summaryrefslogtreecommitdiffstats
path: root/private/utils
diff options
context:
space:
mode:
Diffstat (limited to 'private/utils')
-rw-r--r--private/utils/aclconv/acehelp.cxx431
-rw-r--r--private/utils/aclconv/acehelp.hxx74
-rw-r--r--private/utils/aclconv/aclconv.cxx1938
-rw-r--r--private/utils/aclconv/aclconv.hxx321
-rw-r--r--private/utils/aclconv/aclconv.rc24
-rw-r--r--private/utils/aclconv/aclres.h10
-rw-r--r--private/utils/aclconv/backacc.hxx154
-rw-r--r--private/utils/aclconv/convnode.cxx2421
-rw-r--r--private/utils/aclconv/convnode.hxx248
-rw-r--r--private/utils/aclconv/lmconst.hxx68
-rw-r--r--private/utils/aclconv/logfile.hxx82
-rw-r--r--private/utils/aclconv/makefile6
-rw-r--r--private/utils/aclconv/old_msgs170
-rw-r--r--private/utils/aclconv/sidcache.cxx355
-rw-r--r--private/utils/aclconv/sidcache.hxx116
-rw-r--r--private/utils/aclconv/sources65
-rw-r--r--private/utils/attrib/attrib.cxx800
-rw-r--r--private/utils/attrib/attrib.hxx141
-rw-r--r--private/utils/attrib/attrib.rc11
-rw-r--r--private/utils/attrib/makefile6
-rw-r--r--private/utils/attrib/sources56
-rw-r--r--private/utils/autochk/autochk.cxx870
-rw-r--r--private/utils/autochk/autochk.rc12
-rw-r--r--private/utils/autochk/daytona/makefile6
-rw-r--r--private/utils/autochk/daytona/sources51
-rw-r--r--private/utils/autochk/dirs18
-rw-r--r--private/utils/autoconv/autoconv.cxx772
-rw-r--r--private/utils/autoconv/autoconv.rc13
-rw-r--r--private/utils/autoconv/daytona/makefile6
-rw-r--r--private/utils/autoconv/daytona/sources53
-rw-r--r--private/utils/autoconv/dirs16
-rw-r--r--private/utils/bldtest/utiltest.cmd42
-rw-r--r--private/utils/bldtest/utiltest.out766
-rw-r--r--private/utils/bldtest/utltest1.cmd138
-rw-r--r--private/utils/chcp/chcp.cxx428
-rw-r--r--private/utils/chcp/chcp.hxx90
-rw-r--r--private/utils/chcp/chcp.rc10
-rw-r--r--private/utils/chcp/makefile6
-rw-r--r--private/utils/chcp/sources68
-rw-r--r--private/utils/chcp/t_chcp.c32
-rw-r--r--private/utils/chkdsk/chkdsk.cxx410
-rw-r--r--private/utils/chkdsk/chkdsk.rc10
-rw-r--r--private/utils/chkdsk/makefile6
-rw-r--r--private/utils/chkdsk/sources59
-rw-r--r--private/utils/chkntfs/chkntfs.cxx439
-rw-r--r--private/utils/chkntfs/chkntfs.hxx73
-rw-r--r--private/utils/chkntfs/chkntfs.rc11
-rw-r--r--private/utils/chkntfs/makefile6
-rw-r--r--private/utils/chkntfs/sources82
-rw-r--r--private/utils/comp/comp.cxx1244
-rw-r--r--private/utils/comp/comp.hxx129
-rw-r--r--private/utils/comp/comp.rc10
-rw-r--r--private/utils/comp/makefile6
-rw-r--r--private/utils/comp/sources56
-rw-r--r--private/utils/compact/compact.c1556
-rw-r--r--private/utils/compact/compact.rc13
-rw-r--r--private/utils/compact/makefile6
-rw-r--r--private/utils/compact/makefile.inc4
-rw-r--r--private/utils/compact/msg.mc180
-rw-r--r--private/utils/compact/sdk/compact.rc3
-rw-r--r--private/utils/compact/sdk/makefile24
-rw-r--r--private/utils/compact/sdk/readme.txt24
-rw-r--r--private/utils/compact/sources45
-rw-r--r--private/utils/compact/support.c352
-rw-r--r--private/utils/compact/support.h57
-rw-r--r--private/utils/convert/convert.cxx1307
-rw-r--r--private/utils/convert/convert.hxx136
-rw-r--r--private/utils/convert/convert.rc10
-rw-r--r--private/utils/convert/makefile6
-rw-r--r--private/utils/convert/sources57
-rw-r--r--private/utils/cudbfs/cudbfs.cxx174
-rw-r--r--private/utils/cudbfs/cudbfs.def9
-rw-r--r--private/utils/cudbfs/cudbfs.hxx48
-rw-r--r--private/utils/cudbfs/cudbfs.rc10
-rw-r--r--private/utils/cudbfs/dbfsconv.cxx1812
-rw-r--r--private/utils/cudbfs/dbfsconv.hxx174
-rw-r--r--private/utils/cudbfs/makefile6
-rw-r--r--private/utils/cudbfs/secmap.cxx63
-rw-r--r--private/utils/cudbfs/secmap.hxx47
-rw-r--r--private/utils/cudbfs/sources78
-rw-r--r--private/utils/cudbfs/treemap.cxx219
-rw-r--r--private/utils/cudbfs/treemap.hxx71
-rw-r--r--private/utils/cufat/dirs16
-rw-r--r--private/utils/cufat/inc/convfat.hxx44
-rw-r--r--private/utils/cufat/inc/fatntfs.hxx375
-rw-r--r--private/utils/cufat/inc/fatofs.hxx70
-rw-r--r--private/utils/cufat/src/convfat.cxx589
-rw-r--r--private/utils/cufat/src/cufat.cxx122
-rw-r--r--private/utils/cufat/src/cufat.def8
-rw-r--r--private/utils/cufat/src/cufat.rc10
-rw-r--r--private/utils/cufat/src/fatntfs.cxx2568
-rw-r--r--private/utils/cufat/src/makefile6
-rw-r--r--private/utils/cufat/src/pch.cxx19
-rw-r--r--private/utils/cufat/src/sources76
-rw-r--r--private/utils/cuhpfs/bldnames.cxx468
-rw-r--r--private/utils/cuhpfs/cuhpfs.cxx370
-rw-r--r--private/utils/cuhpfs/cuhpfs.def9
-rw-r--r--private/utils/cuhpfs/cuhpfs.hxx182
-rw-r--r--private/utils/cuhpfs/cuhpfs.rc10
-rw-r--r--private/utils/cuhpfs/cvtdir.cxx1093
-rw-r--r--private/utils/cuhpfs/cvteas.cxx314
-rw-r--r--private/utils/cuhpfs/cvtfnode.cxx266
-rw-r--r--private/utils/cuhpfs/cvthpfs.cxx674
-rw-r--r--private/utils/cuhpfs/getacp.c73
-rw-r--r--private/utils/cuhpfs/makefile6
-rw-r--r--private/utils/cuhpfs/nametab.cxx671
-rw-r--r--private/utils/cuhpfs/nametab.hxx253
-rw-r--r--private/utils/cuhpfs/pch.cxx19
-rw-r--r--private/utils/cuhpfs/sources79
-rw-r--r--private/utils/dblspace/dblspace.cxx2869
-rw-r--r--private/utils/dblspace/dblspace.hxx53
-rw-r--r--private/utils/dblspace/dblspace.rc10
-rw-r--r--private/utils/dblspace/dolist.cxx778
-rw-r--r--private/utils/dblspace/makefile6
-rw-r--r--private/utils/dblspace/sources74
-rw-r--r--private/utils/dirs62
-rw-r--r--private/utils/diskcomp/diskcomp.cxx438
-rw-r--r--private/utils/diskcomp/diskcomp.rc10
-rw-r--r--private/utils/diskcomp/makefile6
-rw-r--r--private/utils/diskcomp/sources64
-rw-r--r--private/utils/diskcopy/diskcopy.cxx209
-rw-r--r--private/utils/diskcopy/diskcopy.rc10
-rw-r--r--private/utils/diskcopy/makefile6
-rw-r--r--private/utils/diskcopy/sources62
-rw-r--r--private/utils/doskey/doskey.cxx763
-rw-r--r--private/utils/doskey/doskey.rc11
-rw-r--r--private/utils/doskey/makefile6
-rw-r--r--private/utils/doskey/sources62
-rw-r--r--private/utils/fc.old/fc.cxx1492
-rw-r--r--private/utils/fc.old/fc.hxx165
-rw-r--r--private/utils/fc.old/makefile6
-rw-r--r--private/utils/fc.old/sources56
-rw-r--r--private/utils/fc/fc.cxx1319
-rw-r--r--private/utils/fc/fc.hxx163
-rw-r--r--private/utils/fc/fc.rc11
-rw-r--r--private/utils/fc/makefile6
-rw-r--r--private/utils/fc/sources58
-rw-r--r--private/utils/fdisk/arrowin.c344
-rw-r--r--private/utils/fdisk/cdrom.c522
-rw-r--r--private/utils/fdisk/commit.c1524
-rw-r--r--private/utils/fdisk/dblspace.c1710
-rw-r--r--private/utils/fdisk/diskman.hlpbin0 -> 14605 bytes
-rw-r--r--private/utils/fdisk/dskmgr.icobin0 -> 766 bytes
-rw-r--r--private/utils/fdisk/fd_nt.c1084
-rw-r--r--private/utils/fdisk/fdconst.h80
-rw-r--r--private/utils/fdisk/fddata.c169
-rw-r--r--private/utils/fdisk/fddlgs.c976
-rw-r--r--private/utils/fdisk/fdengine.c3734
-rw-r--r--private/utils/fdisk/fdft.c1500
-rw-r--r--private/utils/fdisk/fdft.h0
-rw-r--r--private/utils/fdisk/fdglob.h135
-rw-r--r--private/utils/fdisk/fdhelp.c232
-rw-r--r--private/utils/fdisk/fdhelpid.h178
-rw-r--r--private/utils/fdisk/fdinit.c533
-rw-r--r--private/utils/fdisk/fdisk.dlg165
-rw-r--r--private/utils/fdisk/fdisk.h120
-rw-r--r--private/utils/fdisk/fdisk.rc209
-rw-r--r--private/utils/fdisk/fdiskmsg.mc636
-rw-r--r--private/utils/fdisk/fdlistbx.c881
-rw-r--r--private/utils/fdisk/fdmem.c77
-rw-r--r--private/utils/fdisk/fdmisc.c1579
-rw-r--r--private/utils/fdisk/fdprof.c212
-rw-r--r--private/utils/fdisk/fdproto.h1301
-rw-r--r--private/utils/fdisk/fdres.h305
-rw-r--r--private/utils/fdisk/fdstleg.c321
-rw-r--r--private/utils/fdisk/fdtypes.h317
-rw-r--r--private/utils/fdisk/fmifs.c1792
-rw-r--r--private/utils/fdisk/ftreg.c1201
-rw-r--r--private/utils/fdisk/ftreg.dlg23
-rw-r--r--private/utils/fdisk/ftreg.resbin0 -> 758 bytes
-rw-r--r--private/utils/fdisk/ftregres.h4
-rw-r--r--private/utils/fdisk/i386/x86mboot.c33
-rw-r--r--private/utils/fdisk/makefile1
-rw-r--r--private/utils/fdisk/makefile.inc4
-rw-r--r--private/utils/fdisk/network.c206
-rw-r--r--private/utils/fdisk/ntlow.c1087
-rw-r--r--private/utils/fdisk/readme.txt55
-rw-r--r--private/utils/fdisk/rmdisk.bmpbin0 -> 190 bytes
-rw-r--r--private/utils/fdisk/scsi.h85
-rw-r--r--private/utils/fdisk/smdisk.bmpbin0 -> 190 bytes
-rw-r--r--private/utils/fdisk/sources41
-rw-r--r--private/utils/fdisk/windisk.c5549
-rw-r--r--private/utils/find.old/find.cxx659
-rw-r--r--private/utils/find.old/find.hxx101
-rw-r--r--private/utils/find.old/makefile6
-rw-r--r--private/utils/find.old/sources55
-rw-r--r--private/utils/find/find.cxx667
-rw-r--r--private/utils/find/find.hxx101
-rw-r--r--private/utils/find/find.rc11
-rw-r--r--private/utils/find/makefile6
-rw-r--r--private/utils/find/sources56
-rw-r--r--private/utils/findstr/findstr.c2147
-rw-r--r--private/utils/findstr/findstr.rc12
-rw-r--r--private/utils/findstr/fsmsg.mc133
-rw-r--r--private/utils/findstr/makefile6
-rw-r--r--private/utils/findstr/makefile.inc4
-rw-r--r--private/utils/findstr/qmatch.c758
-rw-r--r--private/utils/findstr/recurse.c229
-rw-r--r--private/utils/findstr/sources51
-rw-r--r--private/utils/fmifs/dirs16
-rw-r--r--private/utils/fmifs/inc/chkmsg.hxx81
-rw-r--r--private/utils/fmifs/inc/fmifs.h404
-rw-r--r--private/utils/fmifs/inc/fmifsmsg.hxx120
-rw-r--r--private/utils/fmifs/src/chkdsk.cxx124
-rw-r--r--private/utils/fmifs/src/chkmsg.cxx292
-rw-r--r--private/utils/fmifs/src/diskcopy.cxx72
-rw-r--r--private/utils/fmifs/src/double.cxx819
-rw-r--r--private/utils/fmifs/src/extend.cxx99
-rw-r--r--private/utils/fmifs/src/fmifs.cxx114
-rw-r--r--private/utils/fmifs/src/fmifs.def16
-rw-r--r--private/utils/fmifs/src/fmifs.rc10
-rw-r--r--private/utils/fmifs/src/fmifsmsg.cxx337
-rw-r--r--private/utils/fmifs/src/format.cxx497
-rw-r--r--private/utils/fmifs/src/label.cxx120
-rw-r--r--private/utils/fmifs/src/makefile6
-rw-r--r--private/utils/fmifs/src/makefile.inc12
-rw-r--r--private/utils/fmifs/src/sources76
-rw-r--r--private/utils/format/format.cxx1027
-rw-r--r--private/utils/format/format.rc10
-rw-r--r--private/utils/format/makefile6
-rw-r--r--private/utils/format/makefile.inc12
-rw-r--r--private/utils/format/parse.cxx1346
-rw-r--r--private/utils/format/parse.hxx49
-rw-r--r--private/utils/format/sources62
-rw-r--r--private/utils/help/doshelp.hlp88
-rw-r--r--private/utils/help/help.cxx732
-rw-r--r--private/utils/help/help.hlp115
-rw-r--r--private/utils/help/help.hxx167
-rw-r--r--private/utils/help/help.rc10
-rw-r--r--private/utils/help/makefile6
-rw-r--r--private/utils/help/makefile.inc12
-rw-r--r--private/utils/help/sources58
-rw-r--r--private/utils/ifsutil/dirs16
-rw-r--r--private/utils/ifsutil/inc/autoentr.hxx131
-rw-r--r--private/utils/ifsutil/inc/autoreg.hxx79
-rw-r--r--private/utils/ifsutil/inc/bigint.hxx645
-rw-r--r--private/utils/ifsutil/inc/bootreg.h18
-rw-r--r--private/utils/ifsutil/inc/bpb.hxx209
-rw-r--r--private/utils/ifsutil/inc/cache.hxx146
-rw-r--r--private/utils/ifsutil/inc/cannedsd.hxx153
-rw-r--r--private/utils/ifsutil/inc/dcache.hxx166
-rw-r--r--private/utils/ifsutil/inc/digraph.hxx182
-rw-r--r--private/utils/ifsutil/inc/dossa.hxx713
-rw-r--r--private/utils/ifsutil/inc/drive.hxx1076
-rw-r--r--private/utils/ifsutil/inc/ifssys.hxx245
-rw-r--r--private/utils/ifsutil/inc/ifsutil.hxx36
-rw-r--r--private/utils/ifsutil/inc/intstack.hxx135
-rw-r--r--private/utils/ifsutil/inc/mldcopy.hxx35
-rw-r--r--private/utils/ifsutil/inc/numset.hxx261
-rw-r--r--private/utils/ifsutil/inc/rcache.hxx92
-rw-r--r--private/utils/ifsutil/inc/rwcache.hxx135
-rw-r--r--private/utils/ifsutil/inc/secrun.hxx240
-rw-r--r--private/utils/ifsutil/inc/supera.hxx233
-rw-r--r--private/utils/ifsutil/inc/volume.hxx392
-rw-r--r--private/utils/ifsutil/src/autoentr.cxx128
-rw-r--r--private/utils/ifsutil/src/autoreg.cxx263
-rw-r--r--private/utils/ifsutil/src/bigint.cxx602
-rw-r--r--private/utils/ifsutil/src/bootreg.c145
-rw-r--r--private/utils/ifsutil/src/cache.cxx245
-rw-r--r--private/utils/ifsutil/src/cannedsd.cxx984
-rw-r--r--private/utils/ifsutil/src/dcache.cxx192
-rw-r--r--private/utils/ifsutil/src/digraph.cxx875
-rw-r--r--private/utils/ifsutil/src/drive.cxx2552
-rw-r--r--private/utils/ifsutil/src/ifssys.cxx2178
-rw-r--r--private/utils/ifsutil/src/ifsutil.cxx163
-rw-r--r--private/utils/ifsutil/src/ifsutil.rc10
-rw-r--r--private/utils/ifsutil/src/intstack.cxx265
-rw-r--r--private/utils/ifsutil/src/makefile6
-rw-r--r--private/utils/ifsutil/src/mldcopy.cxx1044
-rw-r--r--private/utils/ifsutil/src/numset.cxx1076
-rw-r--r--private/utils/ifsutil/src/pch.cxx41
-rw-r--r--private/utils/ifsutil/src/rcache.cxx219
-rw-r--r--private/utils/ifsutil/src/rwcache.cxx565
-rw-r--r--private/utils/ifsutil/src/secrun.cxx195
-rw-r--r--private/utils/ifsutil/src/sources105
-rw-r--r--private/utils/ifsutil/src/supera.cxx196
-rw-r--r--private/utils/ifsutil/src/volume.cxx520
-rw-r--r--private/utils/keyb/keyb.cxx913
-rw-r--r--private/utils/keyb/keyb.hxx160
-rw-r--r--private/utils/keyb/keyb.rc10
-rw-r--r--private/utils/keyb/makefile6
-rw-r--r--private/utils/keyb/makefile.inc12
-rw-r--r--private/utils/keyb/sources66
-rw-r--r--private/utils/label/label.cxx558
-rw-r--r--private/utils/label/label.rc10
-rw-r--r--private/utils/label/makefile6
-rw-r--r--private/utils/label/makefile.inc12
-rw-r--r--private/utils/label/sources58
-rw-r--r--private/utils/mep/browser/bsc/bsc.c734
-rw-r--r--private/utils/mep/browser/bsc/bscdump.c114
-rw-r--r--private/utils/mep/browser/bsc/calltree.c213
-rw-r--r--private/utils/mep/browser/bsc/dump.c99
-rw-r--r--private/utils/mep/browser/bsc/filter.c44
-rw-r--r--private/utils/mep/browser/bsc/format.c112
-rw-r--r--private/utils/mep/browser/bsc/listref.c185
-rw-r--r--private/utils/mep/browser/bsc/makefile6
-rw-r--r--private/utils/mep/browser/bsc/outline.c101
-rw-r--r--private/utils/mep/browser/bsc/printf.c114
-rw-r--r--private/utils/mep/browser/bsc/query.c575
-rw-r--r--private/utils/mep/browser/bsc/revtree.c198
-rw-r--r--private/utils/mep/browser/bsc/sources26
-rw-r--r--private/utils/mep/browser/bsc/stats.c96
-rw-r--r--private/utils/mep/browser/bsc/wild.c73
-rw-r--r--private/utils/mep/browser/bscdump/bscdump.c324
-rw-r--r--private/utils/mep/browser/bscdump/bscdump.h15
-rw-r--r--private/utils/mep/browser/bscdump/makefile6
-rw-r--r--private/utils/mep/browser/bscdump/sources21
-rw-r--r--private/utils/mep/browser/bscdump/thunk.c174
-rw-r--r--private/utils/mep/browser/dirs25
-rw-r--r--private/utils/mep/browser/inc/bsc.h228
-rw-r--r--private/utils/mep/browser/inc/bscsup.h106
-rw-r--r--private/utils/mep/browser/inc/hungary.h31
-rw-r--r--private/utils/mep/browser/inc/mbrcache.h7
-rw-r--r--private/utils/mep/browser/inc/sbrbsc.h43
-rw-r--r--private/utils/mep/browser/inc/sbrfdef.h65
-rw-r--r--private/utils/mep/browser/inc/sbrvers.h7
-rw-r--r--private/utils/mep/browser/mbrmake/addtolst.c1004
-rw-r--r--private/utils/mep/browser/mbrmake/casts.h22
-rw-r--r--private/utils/mep/browser/mbrmake/convert.c266
-rw-r--r--private/utils/mep/browser/mbrmake/dcodesbr.c148
-rw-r--r--private/utils/mep/browser/mbrmake/errors.h20
-rw-r--r--private/utils/mep/browser/mbrmake/extern.h83
-rw-r--r--private/utils/mep/browser/mbrmake/getsbrec.c165
-rw-r--r--private/utils/mep/browser/mbrmake/list.c284
-rw-r--r--private/utils/mep/browser/mbrmake/list.h41
-rw-r--r--private/utils/mep/browser/mbrmake/makefile6
-rw-r--r--private/utils/mep/browser/mbrmake/mbrhash.c41
-rw-r--r--private/utils/mep/browser/mbrmake/mbrmake.c756
-rw-r--r--private/utils/mep/browser/mbrmake/mbrmake.h246
-rw-r--r--private/utils/mep/browser/mbrmake/mbrwbsc.c782
-rw-r--r--private/utils/mep/browser/mbrmake/ord.c116
-rw-r--r--private/utils/mep/browser/mbrmake/owner.c76
-rw-r--r--private/utils/mep/browser/mbrmake/profile.h58
-rw-r--r--private/utils/mep/browser/mbrmake/readbsc.c790
-rw-r--r--private/utils/mep/browser/mbrmake/sbrproto.h61
-rw-r--r--private/utils/mep/browser/mbrmake/sbrx.c357
-rw-r--r--private/utils/mep/browser/mbrmake/sources31
-rw-r--r--private/utils/mep/browser/mbrmake/vm.c197
-rw-r--r--private/utils/mep/browser/mbrmake/vm.h67
-rw-r--r--private/utils/mep/dirs26
-rw-r--r--private/utils/mep/extens/dirs32
-rw-r--r--private/utils/mep/extens/exthdr/exthdr.c38
-rw-r--r--private/utils/mep/extens/exthdr/makefile6
-rw-r--r--private/utils/mep/extens/exthdr/makefile.inc2
-rw-r--r--private/utils/mep/extens/exthdr/sources20
-rw-r--r--private/utils/mep/extens/filter/filter.c387
-rw-r--r--private/utils/mep/extens/filter/filter.def7
-rw-r--r--private/utils/mep/extens/filter/filter.rc10
-rw-r--r--private/utils/mep/extens/filter/makefile6
-rw-r--r--private/utils/mep/extens/filter/sources16
-rw-r--r--private/utils/mep/extens/justify/justify.c532
-rw-r--r--private/utils/mep/extens/justify/justify.def7
-rw-r--r--private/utils/mep/extens/justify/justify.rc10
-rw-r--r--private/utils/mep/extens/justify/makefile6
-rw-r--r--private/utils/mep/extens/justify/sources17
-rw-r--r--private/utils/mep/extens/mbrowse/calbak.c436
-rw-r--r--private/utils/mep/extens/mbrowse/makefile6
-rw-r--r--private/utils/mep/extens/mbrowse/mbr.h187
-rw-r--r--private/utils/mep/extens/mbrowse/mbrcore.c197
-rw-r--r--private/utils/mep/extens/mbrowse/mbrdlg.c422
-rw-r--r--private/utils/mep/extens/mbrowse/mbrevt.c58
-rw-r--r--private/utils/mep/extens/mbrowse/mbrfile.c96
-rw-r--r--private/utils/mep/extens/mbrowse/mbrowse.def7
-rw-r--r--private/utils/mep/extens/mbrowse/mbrqry.c432
-rw-r--r--private/utils/mep/extens/mbrowse/mbrutil.c417
-rw-r--r--private/utils/mep/extens/mbrowse/mbrwin.c86
-rw-r--r--private/utils/mep/extens/mbrowse/sources27
-rw-r--r--private/utils/mep/extens/mepparty/makefile6
-rw-r--r--private/utils/mep/extens/mepparty/mepparty.c898
-rw-r--r--private/utils/mep/extens/mepparty/mepparty.def7
-rw-r--r--private/utils/mep/extens/mepparty/mepparty.rc12
-rw-r--r--private/utils/mep/extens/mepparty/sources15
-rw-r--r--private/utils/mep/extens/mhelp/helphck.c40
-rw-r--r--private/utils/mep/extens/mhelp/makefile6
-rw-r--r--private/utils/mep/extens/mhelp/mep.hlpbin0 -> 55080 bytes
-rw-r--r--private/utils/mep/extens/mhelp/mh.h309
-rw-r--r--private/utils/mep/extens/mhelp/mhcore.c781
-rw-r--r--private/utils/mep/extens/mhelp/mhdisp.c434
-rw-r--r--private/utils/mep/extens/mhelp/mhelp.def7
-rw-r--r--private/utils/mep/extens/mhelp/mhelp.rc10
-rw-r--r--private/utils/mep/extens/mhelp/mhevt.c366
-rw-r--r--private/utils/mep/extens/mhelp/mhfile.c344
-rw-r--r--private/utils/mep/extens/mhelp/mhlook.c255
-rw-r--r--private/utils/mep/extens/mhelp/mhutil.c342
-rw-r--r--private/utils/mep/extens/mhelp/mhwin.c140
-rw-r--r--private/utils/mep/extens/mhelp/sources56
-rw-r--r--private/utils/mep/extens/pmatch/makefile6
-rw-r--r--private/utils/mep/extens/pmatch/pmatch.c544
-rw-r--r--private/utils/mep/extens/pmatch/pmatch.def7
-rw-r--r--private/utils/mep/extens/pmatch/pmatch.rc10
-rw-r--r--private/utils/mep/extens/pmatch/sources16
-rw-r--r--private/utils/mep/extens/skel/makefile6
-rw-r--r--private/utils/mep/extens/skel/skel.c101
-rw-r--r--private/utils/mep/extens/skel/skel.def10
-rw-r--r--private/utils/mep/extens/skel/sources14
-rw-r--r--private/utils/mep/extens/tglcase/makefile6
-rw-r--r--private/utils/mep/extens/tglcase/sources16
-rw-r--r--private/utils/mep/extens/tglcase/tglcase.c172
-rw-r--r--private/utils/mep/extens/tglcase/tglcase.def7
-rw-r--r--private/utils/mep/extens/tglcase/tglcase.rc10
-rw-r--r--private/utils/mep/extens/ulcase/makefile6
-rw-r--r--private/utils/mep/extens/ulcase/sources16
-rw-r--r--private/utils/mep/extens/ulcase/ulcase.c166
-rw-r--r--private/utils/mep/extens/ulcase/ulcase.def7
-rw-r--r--private/utils/mep/extens/ulcase/ulcase.rc10
-rw-r--r--private/utils/mep/extens/winclip/makefile6
-rw-r--r--private/utils/mep/extens/winclip/sources21
-rw-r--r--private/utils/mep/extens/winclip/winclip.c830
-rw-r--r--private/utils/mep/extens/winclip/winclip.def7
-rw-r--r--private/utils/mep/extens/winclip/winclip.rc10
-rw-r--r--private/utils/mep/help/dirs24
-rw-r--r--private/utils/mep/help/enginlib/hback.c105
-rw-r--r--private/utils/mep/help/enginlib/hctl.c72
-rw-r--r--private/utils/mep/help/enginlib/hdata.c46
-rw-r--r--private/utils/mep/help/enginlib/help.c1745
-rw-r--r--private/utils/mep/help/enginlib/helpcell.c138
-rw-r--r--private/utils/mep/help/enginlib/helpcnt.c54
-rw-r--r--private/utils/mep/help/enginlib/helpdec.c722
-rw-r--r--private/utils/mep/help/enginlib/helpdll.c190
-rw-r--r--private/utils/mep/help/enginlib/helpif.c308
-rw-r--r--private/utils/mep/help/enginlib/hinfo.c57
-rw-r--r--private/utils/mep/help/enginlib/hline.c139
-rw-r--r--private/utils/mep/help/enginlib/hloc.c146
-rw-r--r--private/utils/mep/help/enginlib/makefile6
-rw-r--r--private/utils/mep/help/enginlib/mshelp.def29
-rw-r--r--private/utils/mep/help/enginlib/mshelp.rc10
-rw-r--r--private/utils/mep/help/enginlib/mshelp1.def29
-rw-r--r--private/utils/mep/help/enginlib/sources35
-rw-r--r--private/utils/mep/help/htest/cons.c2200
-rw-r--r--private/utils/mep/help/htest/cons.h253
-rw-r--r--private/utils/mep/help/htest/htest.c1441
-rw-r--r--private/utils/mep/help/htest/makefile6
-rw-r--r--private/utils/mep/help/htest/sources18
-rw-r--r--private/utils/mep/help/inc/farutil.h30
-rw-r--r--private/utils/mep/help/inc/help.h235
-rw-r--r--private/utils/mep/help/inc/helpfile.h95
-rw-r--r--private/utils/mep/help/inc/helpmake.h195
-rw-r--r--private/utils/mep/help/inc/helpsys.h92
-rw-r--r--private/utils/mep/help/inc/huffman.h8
-rw-r--r--private/utils/mep/help/inc/rtf.h94
-rw-r--r--private/utils/mep/help/inc/vm.h46
-rw-r--r--private/utils/mep/help/inc/zlib.h9
-rw-r--r--private/utils/mep/help/mshelp/help.c1745
-rw-r--r--private/utils/mep/help/mshelp/makefile6
-rw-r--r--private/utils/mep/help/mshelp/mshelp.def29
-rw-r--r--private/utils/mep/help/mshelp/mshelp.rc10
-rw-r--r--private/utils/mep/help/mshelp/mshelp1.def29
-rw-r--r--private/utils/mep/help/mshelp/sources24
-rw-r--r--private/utils/mep/inc/cmds.h117
-rw-r--r--private/utils/mep/inc/console.h262
-rw-r--r--private/utils/mep/inc/ext.h599
-rw-r--r--private/utils/mep/inc/extint.h62
-rw-r--r--private/utils/mep/inc/keyboard.h8
-rw-r--r--private/utils/mep/inc/keys.h4
-rw-r--r--private/utils/mep/inc/menu.h360
-rw-r--r--private/utils/mep/inc/mep.h812
-rw-r--r--private/utils/mep/inc/mepext.h23
-rw-r--r--private/utils/mep/inc/meptype.h590
-rw-r--r--private/utils/mep/inc/mouse.h35
-rw-r--r--private/utils/mep/inc/msg.h63
-rw-r--r--private/utils/mep/inc/version.h4
-rw-r--r--private/utils/mep/src/arg.c929
-rw-r--r--private/utils/mep/src/assign.c846
-rw-r--r--private/utils/mep/src/build.c326
-rw-r--r--private/utils/mep/src/cdelete.c157
-rw-r--r--private/utils/mep/src/cmd.c220
-rw-r--r--private/utils/mep/src/compile.c541
-rw-r--r--private/utils/mep/src/console.c2456
-rw-r--r--private/utils/mep/src/cursor.c861
-rw-r--r--private/utils/mep/src/delete.c126
-rw-r--r--private/utils/mep/src/display.c1055
-rw-r--r--private/utils/mep/src/dline.c325
-rw-r--r--private/utils/mep/src/env.c288
-rw-r--r--private/utils/mep/src/event.c116
-rw-r--r--private/utils/mep/src/file.c895
-rw-r--r--private/utils/mep/src/fileio.c1497
-rw-r--r--private/utils/mep/src/fscan.c168
-rw-r--r--private/utils/mep/src/getstr.c314
-rw-r--r--private/utils/mep/src/graphic.c420
-rw-r--r--private/utils/mep/src/hilite.c610
-rw-r--r--private/utils/mep/src/insert.c72
-rw-r--r--private/utils/mep/src/key.c1087
-rw-r--r--private/utils/mep/src/keyboard.c240
-rw-r--r--private/utils/mep/src/lang.c169
-rw-r--r--private/utils/mep/src/ldelete.c126
-rw-r--r--private/utils/mep/src/linsert.c58
-rw-r--r--private/utils/mep/src/list.c880
-rw-r--r--private/utils/mep/src/load.c880
-rw-r--r--private/utils/mep/src/macro.c465
-rw-r--r--private/utils/mep/src/makefile6
-rw-r--r--private/utils/mep/src/mark.c1496
-rw-r--r--private/utils/mep/src/mep.c417
-rw-r--r--private/utils/mep/src/mep.icobin0 -> 766 bytes
-rw-r--r--private/utils/mep/src/mep.rc12
-rw-r--r--private/utils/mep/src/mepstr.c172
-rw-r--r--private/utils/mep/src/mouse.c283
-rw-r--r--private/utils/mep/src/newline.c51
-rw-r--r--private/utils/mep/src/pbal.c133
-rw-r--r--private/utils/mep/src/pick.c469
-rw-r--r--private/utils/mep/src/record.c509
-rw-r--r--private/utils/mep/src/replace.c569
-rw-r--r--private/utils/mep/src/search.c1126
-rw-r--r--private/utils/mep/src/setfile.c300
-rw-r--r--private/utils/mep/src/show.c302
-rw-r--r--private/utils/mep/src/sources79
-rw-r--r--private/utils/mep/src/statfile.c366
-rw-r--r--private/utils/mep/src/tab.c242
-rw-r--r--private/utils/mep/src/table.c315
-rw-r--r--private/utils/mep/src/textline.c2427
-rw-r--r--private/utils/mep/src/transkey.c442
-rw-r--r--private/utils/mep/src/undo.c984
-rw-r--r--private/utils/mep/src/untab.c330
-rw-r--r--private/utils/mep/src/window.c526
-rw-r--r--private/utils/mep/src/word.c129
-rw-r--r--private/utils/mep/src/z19.c114
-rw-r--r--private/utils/mep/src/zaux.c510
-rw-r--r--private/utils/mep/src/zdebug.c305
-rw-r--r--private/utils/mep/src/zexit.c346
-rw-r--r--private/utils/mep/src/zinit.c1181
-rw-r--r--private/utils/mep/src/zprint.c376
-rw-r--r--private/utils/mep/src/zspawn.c157
-rw-r--r--private/utils/mep/src/zthread.c784
-rw-r--r--private/utils/mep/src/zutil.c378
-rw-r--r--private/utils/mode/argument.cxx2312
-rw-r--r--private/utils/mode/argument.old1518
-rw-r--r--private/utils/mode/com.cxx1208
-rw-r--r--private/utils/mode/com.hxx141
-rw-r--r--private/utils/mode/common.cxx345
-rw-r--r--private/utils/mode/common.hxx68
-rw-r--r--private/utils/mode/cons.cxx460
-rw-r--r--private/utils/mode/cons.hxx90
-rw-r--r--private/utils/mode/lpt.cxx664
-rw-r--r--private/utils/mode/lpt.hxx95
-rw-r--r--private/utils/mode/makefile6
-rw-r--r--private/utils/mode/makefile.inc12
-rw-r--r--private/utils/mode/mode.cxx213
-rw-r--r--private/utils/mode/mode.hxx293
-rw-r--r--private/utils/mode/mode.rc10
-rw-r--r--private/utils/mode/redir.cxx307
-rw-r--r--private/utils/mode/redir.hxx69
-rw-r--r--private/utils/mode/sources71
-rw-r--r--private/utils/mode/support.cxx205
-rw-r--r--private/utils/more/argument.cxx470
-rw-r--r--private/utils/more/makefile6
-rw-r--r--private/utils/more/makefile.inc12
-rw-r--r--private/utils/more/more.cxx877
-rw-r--r--private/utils/more/more.hxx221
-rw-r--r--private/utils/more/more.rc10
-rw-r--r--private/utils/more/pager.cxx823
-rw-r--r--private/utils/more/pager.hxx210
-rw-r--r--private/utils/more/sources65
-rw-r--r--private/utils/ntbackup/dirs23
-rw-r--r--private/utils/ntbackup/exchange/build/alphamk.inc195
-rw-r--r--private/utils/ntbackup/exchange/build/coffbase.txt776
-rw-r--r--private/utils/ntbackup/exchange/build/i386mk.inc247
-rw-r--r--private/utils/ntbackup/exchange/build/inc/common.ver96
-rw-r--r--private/utils/ntbackup/exchange/build/inc/ntddscsi.h229
-rw-r--r--private/utils/ntbackup/exchange/build/inc/ntverp.h47
-rw-r--r--private/utils/ntbackup/exchange/build/inc/pcrt32.h39
-rw-r--r--private/utils/ntbackup/exchange/build/inc/plan32.h14
-rw-r--r--private/utils/ntbackup/exchange/build/inc/port1632.h40
-rw-r--r--private/utils/ntbackup/exchange/build/inc/ptypes32.h62
-rw-r--r--private/utils/ntbackup/exchange/build/inc/pwin32.h305
-rw-r--r--private/utils/ntbackup/exchange/build/inc/uiexport.h132
-rw-r--r--private/utils/ntbackup/exchange/build/inc/warning.h22
-rw-r--r--private/utils/ntbackup/exchange/build/makefile.def2047
-rw-r--r--private/utils/ntbackup/exchange/build/makefile.plt142
-rw-r--r--private/utils/ntbackup/exchange/build/mipsmk.inc218
-rw-r--r--private/utils/ntbackup/exchange/build/ppcmk.inc227
-rw-r--r--private/utils/ntbackup/exchange/inc/edbmsg.h1737
-rw-r--r--private/utils/ntbackup/exchange/inc/jet.h1804
-rw-r--r--private/utils/ntbackup/exchange/inc/jetbcli.h407
-rw-r--r--private/utils/ntbackup/exchange/inc/morpc.h352
-rw-r--r--private/utils/ntbackup/exchange/inc/rpcbak.h225
-rw-r--r--private/utils/ntbackup/exchange/inc/rpcpri.h288
-rw-r--r--private/utils/ntbackup/exchange/inc/rpcpub.h387
-rw-r--r--private/utils/ntbackup/exchange/inc/sadapi.h197
-rw-r--r--private/utils/ntbackup/exchange/readme.txt8
-rw-r--r--private/utils/ntbackup/inc/abort.h30
-rw-r--r--private/utils/ntbackup/inc/add_icon.h36
-rw-r--r--private/utils/ntbackup/inc/adv_rest.h35
-rw-r--r--private/utils/ntbackup/inc/adv_sel.h61
-rw-r--r--private/utils/ntbackup/inc/adv_serv.h53
-rw-r--r--private/utils/ntbackup/inc/afp_fs.h301
-rw-r--r--private/utils/ntbackup/inc/afpdblk.h149
-rw-r--r--private/utils/ntbackup/inc/afplib.h86
-rw-r--r--private/utils/ntbackup/inc/all.h48
-rw-r--r--private/utils/ntbackup/inc/appdefs.h177
-rw-r--r--private/utils/ntbackup/inc/aspi.h7
-rw-r--r--private/utils/ntbackup/inc/backgrnd.h126
-rw-r--r--private/utils/ntbackup/inc/be_debug.h51
-rw-r--r--private/utils/ntbackup/inc/be_init.h108
-rw-r--r--private/utils/ntbackup/inc/be_tfutl.h53
-rw-r--r--private/utils/ntbackup/inc/bec_prv.h31
-rw-r--r--private/utils/ntbackup/inc/beconfig.h598
-rw-r--r--private/utils/ntbackup/inc/bengine.h82
-rw-r--r--private/utils/ntbackup/inc/bitmaps.h200
-rw-r--r--private/utils/ntbackup/inc/bkup.h82
-rw-r--r--private/utils/ntbackup/inc/bsdu.h566
-rw-r--r--private/utils/ntbackup/inc/bsdu_str.h264
-rw-r--r--private/utils/ntbackup/inc/buff_prv.h35
-rw-r--r--private/utils/ntbackup/inc/buffman.h405
-rw-r--r--private/utils/ntbackup/inc/buffnt.h34
-rw-r--r--private/utils/ntbackup/inc/catmaint.h12
-rw-r--r--private/utils/ntbackup/inc/cattape.h47
-rw-r--r--private/utils/ntbackup/inc/cbemon.h125
-rw-r--r--private/utils/ntbackup/inc/channel.h212
-rw-r--r--private/utils/ntbackup/inc/checksum.h27
-rw-r--r--private/utils/ntbackup/inc/cli.h38
-rw-r--r--private/utils/ntbackup/inc/config.h1
-rw-r--r--private/utils/ntbackup/inc/crit_err.h35
-rw-r--r--private/utils/ntbackup/inc/criterr.h91
-rw-r--r--private/utils/ntbackup/inc/ctl3d.h91
-rw-r--r--private/utils/ntbackup/inc/cursors.h38
-rw-r--r--private/utils/ntbackup/inc/d_o_bkup.h80
-rw-r--r--private/utils/ntbackup/inc/d_o_rset.h47
-rw-r--r--private/utils/ntbackup/inc/datetime.h119
-rw-r--r--private/utils/ntbackup/inc/dateutil.h114
-rw-r--r--private/utils/ntbackup/inc/dblkmap.h37
-rw-r--r--private/utils/ntbackup/inc/dblks.h281
-rw-r--r--private/utils/ntbackup/inc/dddefs.h50
-rw-r--r--private/utils/ntbackup/inc/debug.h90
-rw-r--r--private/utils/ntbackup/inc/del_sel.h9
-rw-r--r--private/utils/ntbackup/inc/details.h173
-rw-r--r--private/utils/ntbackup/inc/detdrive.h34
-rw-r--r--private/utils/ntbackup/inc/detnet.h32
-rw-r--r--private/utils/ntbackup/inc/dialmang.h481
-rw-r--r--private/utils/ntbackup/inc/dialogs.h363
-rw-r--r--private/utils/ntbackup/inc/dil.h94
-rw-r--r--private/utils/ntbackup/inc/dilhwd.h55
-rw-r--r--private/utils/ntbackup/inc/dilntprv.h41
-rw-r--r--private/utils/ntbackup/inc/dle.h286
-rw-r--r--private/utils/ntbackup/inc/dle_str.h662
-rw-r--r--private/utils/ntbackup/inc/dlg_ids.h140
-rw-r--r--private/utils/ntbackup/inc/dlm.h469
-rw-r--r--private/utils/ntbackup/inc/dlm_prv.h93
-rw-r--r--private/utils/ntbackup/inc/do_misc.h62
-rw-r--r--private/utils/ntbackup/inc/dos_fs.h279
-rw-r--r--private/utils/ntbackup/inc/doscom.h170
-rw-r--r--private/utils/ntbackup/inc/dosdblk.h74
-rw-r--r--private/utils/ntbackup/inc/drive.h135
-rw-r--r--private/utils/ntbackup/inc/drvinf.h113
-rw-r--r--private/utils/ntbackup/inc/ems.h45
-rw-r--r--private/utils/ntbackup/inc/ems_fs.h471
-rw-r--r--private/utils/ntbackup/inc/ems_jet.h21
-rw-r--r--private/utils/ntbackup/inc/emsdblk.h106
-rw-r--r--private/utils/ntbackup/inc/enc_priv.h67
-rw-r--r--private/utils/ntbackup/inc/enc_pub.h69
-rw-r--r--private/utils/ntbackup/inc/eng_dbug.h110
-rw-r--r--private/utils/ntbackup/inc/eng_err.h116
-rw-r--r--private/utils/ntbackup/inc/eng_fmt.h15
-rw-r--r--private/utils/ntbackup/inc/eng_mq.h13
-rw-r--r--private/utils/ntbackup/inc/eng_msg.h462
-rw-r--r--private/utils/ntbackup/inc/entrydat.h57
-rw-r--r--private/utils/ntbackup/inc/erase.h52
-rw-r--r--private/utils/ntbackup/inc/err_stgs.h11
-rw-r--r--private/utils/ntbackup/inc/error.h31
-rw-r--r--private/utils/ntbackup/inc/esa.h124
-rw-r--r--private/utils/ntbackup/inc/f31proto.h50
-rw-r--r--private/utils/ntbackup/inc/f40proto.h242
-rw-r--r--private/utils/ntbackup/inc/fake_fs.h31
-rw-r--r--private/utils/ntbackup/inc/farlib.h152
-rw-r--r--private/utils/ntbackup/inc/fartypes.h36
-rw-r--r--private/utils/ntbackup/inc/filerepl.h68
-rw-r--r--private/utils/ntbackup/inc/finitfs.h31
-rw-r--r--private/utils/ntbackup/inc/fmteng.h215
-rw-r--r--private/utils/ntbackup/inc/fmtinf.h121
-rw-r--r--private/utils/ntbackup/inc/freplace.h44
-rw-r--r--private/utils/ntbackup/inc/fsstream.h149
-rw-r--r--private/utils/ntbackup/inc/fsys.h798
-rw-r--r--private/utils/ntbackup/inc/fsys_err.h148
-rw-r--r--private/utils/ntbackup/inc/fsys_prv.h240
-rw-r--r--private/utils/ntbackup/inc/fsys_str.h873
-rw-r--r--private/utils/ntbackup/inc/gen_fs.h187
-rw-r--r--private/utils/ntbackup/inc/gendblk.h54
-rw-r--r--private/utils/ntbackup/inc/generr.h72
-rw-r--r--private/utils/ntbackup/inc/genfuncs.h73
-rw-r--r--private/utils/ntbackup/inc/genstat.h44
-rw-r--r--private/utils/ntbackup/inc/get_next.h33
-rw-r--r--private/utils/ntbackup/inc/global.h422
-rw-r--r--private/utils/ntbackup/inc/helpids.h231
-rw-r--r--private/utils/ntbackup/inc/helpmang.h86
-rw-r--r--private/utils/ntbackup/inc/hwcheck.h30
-rw-r--r--private/utils/ntbackup/inc/hwconf.h217
-rw-r--r--private/utils/ntbackup/inc/hwctext.h198
-rw-r--r--private/utils/ntbackup/inc/hwdlg.h79
-rw-r--r--private/utils/ntbackup/inc/iblock.h29
-rw-r--r--private/utils/ntbackup/inc/ibm_scsi.h7
-rw-r--r--private/utils/ntbackup/inc/icons.h62
-rw-r--r--private/utils/ntbackup/inc/image_fs.h165
-rw-r--r--private/utils/ntbackup/inc/imdblk.h56
-rw-r--r--private/utils/ntbackup/inc/install.h148
-rw-r--r--private/utils/ntbackup/inc/int21.h23
-rw-r--r--private/utils/ntbackup/inc/ipx.h125
-rw-r--r--private/utils/ntbackup/inc/islecfg.h7
-rw-r--r--private/utils/ntbackup/inc/job_new.h15
-rw-r--r--private/utils/ntbackup/inc/job_opts.h76
-rw-r--r--private/utils/ntbackup/inc/jobs.h337
-rw-r--r--private/utils/ntbackup/inc/jobsetup.h15
-rw-r--r--private/utils/ntbackup/inc/jobstat.h108
-rw-r--r--private/utils/ntbackup/inc/keys.h37
-rw-r--r--private/utils/ntbackup/inc/launcher.h197
-rw-r--r--private/utils/ntbackup/inc/ld_dvr.h26
-rw-r--r--private/utils/ntbackup/inc/ldialogs.h72
-rw-r--r--private/utils/ntbackup/inc/lis.h94
-rw-r--r--private/utils/ntbackup/inc/log.h335
-rw-r--r--private/utils/ntbackup/inc/loginpw.h35
-rw-r--r--private/utils/ntbackup/inc/loop_prv.h368
-rw-r--r--private/utils/ntbackup/inc/loops.h85
-rw-r--r--private/utils/ntbackup/inc/lp_msg.h183
-rw-r--r--private/utils/ntbackup/inc/lstdres.h116
-rw-r--r--private/utils/ntbackup/inc/ltappswd.h41
-rw-r--r--private/utils/ntbackup/inc/lw_cntl.h43
-rw-r--r--private/utils/ntbackup/inc/lw_data.h116
-rw-r--r--private/utils/ntbackup/inc/lwdefs.h37
-rw-r--r--private/utils/ntbackup/inc/lwprotos.h133
-rw-r--r--private/utils/ntbackup/inc/machine.h43
-rw-r--r--private/utils/ntbackup/inc/mayn31.h512
-rw-r--r--private/utils/ntbackup/inc/mayn40.h463
-rw-r--r--private/utils/ntbackup/inc/mem.h113
-rw-r--r--private/utils/ntbackup/inc/memmang.h125
-rw-r--r--private/utils/ntbackup/inc/menumang.h107
-rw-r--r--private/utils/ntbackup/inc/menus.h141
-rw-r--r--private/utils/ntbackup/inc/message.h16
-rw-r--r--private/utils/ntbackup/inc/minmax.h27
-rw-r--r--private/utils/ntbackup/inc/misc.h27
-rw-r--r--private/utils/ntbackup/inc/ms_qic.h7
-rw-r--r--private/utils/ntbackup/inc/ms_scsi.h7
-rw-r--r--private/utils/ntbackup/inc/msassert.h84
-rw-r--r--private/utils/ntbackup/inc/msg.h30
-rw-r--r--private/utils/ntbackup/inc/msgbox.h88
-rw-r--r--private/utils/ntbackup/inc/msgboxid.h31
-rw-r--r--private/utils/ntbackup/inc/msii.h9
-rw-r--r--private/utils/ntbackup/inc/msinstal.h134
-rw-r--r--private/utils/ntbackup/inc/mslreq.h26
-rw-r--r--private/utils/ntbackup/inc/msmktemp.h10
-rw-r--r--private/utils/ntbackup/inc/mtf.h512
-rw-r--r--private/utils/ntbackup/inc/mui.h154
-rw-r--r--private/utils/ntbackup/inc/muibar.h31
-rw-r--r--private/utils/ntbackup/inc/muiconf.h1376
-rw-r--r--private/utils/ntbackup/inc/muiutil.h136
-rw-r--r--private/utils/ntbackup/inc/nets.h40
-rw-r--r--private/utils/ntbackup/inc/network.h35
-rw-r--r--private/utils/ntbackup/inc/nextset.h37
-rw-r--r--private/utils/ntbackup/inc/nonafp.h179
-rw-r--r--private/utils/ntbackup/inc/nov386.h67
-rw-r--r--private/utils/ntbackup/inc/novcom.h315
-rw-r--r--private/utils/ntbackup/inc/novdblk.h150
-rw-r--r--private/utils/ntbackup/inc/novinit.h60
-rw-r--r--private/utils/ntbackup/inc/nrl.h588
-rw-r--r--private/utils/ntbackup/inc/ntfs_fs.h495
-rw-r--r--private/utils/ntbackup/inc/ntfsdblk.h235
-rw-r--r--private/utils/ntbackup/inc/nw386.h257
-rw-r--r--private/utils/ntbackup/inc/oem.h23
-rw-r--r--private/utils/ntbackup/inc/ombatch.h154
-rw-r--r--private/utils/ntbackup/inc/ombkup.h80
-rw-r--r--private/utils/ntbackup/inc/omevent.h39
-rw-r--r--private/utils/ntbackup/inc/omhelpid.h339
-rw-r--r--private/utils/ntbackup/inc/ommenus.h105
-rw-r--r--private/utils/ntbackup/inc/omrset.h97
-rw-r--r--private/utils/ntbackup/inc/omstring.h1033
-rw-r--r--private/utils/ntbackup/inc/omxchng.h33
-rw-r--r--private/utils/ntbackup/inc/os2_fs.h377
-rw-r--r--private/utils/ntbackup/inc/os2com.h142
-rw-r--r--private/utils/ntbackup/inc/os2dblk.h97
-rw-r--r--private/utils/ntbackup/inc/osinfo.h157
-rw-r--r--private/utils/ntbackup/inc/overwrit.h29
-rw-r--r--private/utils/ntbackup/inc/parstab.h333
-rw-r--r--private/utils/ntbackup/inc/part.h75
-rw-r--r--private/utils/ntbackup/inc/password.h84
-rw-r--r--private/utils/ntbackup/inc/pchstop.h25
-rw-r--r--private/utils/ntbackup/inc/pdtypes.h79
-rw-r--r--private/utils/ntbackup/inc/polldrv.h71
-rw-r--r--private/utils/ntbackup/inc/portdefs.h478
-rw-r--r--private/utils/ntbackup/inc/proddefs.h368
-rw-r--r--private/utils/ntbackup/inc/prtmang.h40
-rw-r--r--private/utils/ntbackup/inc/pwinstal.h33
-rw-r--r--private/utils/ntbackup/inc/qtc.h915
-rw-r--r--private/utils/ntbackup/inc/qtcxface.h37
-rw-r--r--private/utils/ntbackup/inc/queues.h157
-rw-r--r--private/utils/ntbackup/inc/rem_fs.h246
-rw-r--r--private/utils/ntbackup/inc/remdblk.h76
-rw-r--r--private/utils/ntbackup/inc/reqrep.h159
-rw-r--r--private/utils/ntbackup/inc/res_io.h5
-rw-r--r--private/utils/ntbackup/inc/resmang.h130
-rw-r--r--private/utils/ntbackup/inc/resource.h114
-rw-r--r--private/utils/ntbackup/inc/retbuf.h44
-rw-r--r--private/utils/ntbackup/inc/ribmang.h222
-rw-r--r--private/utils/ntbackup/inc/rinitfs.h30
-rw-r--r--private/utils/ntbackup/inc/rm.h101
-rw-r--r--private/utils/ntbackup/inc/rset.h71
-rw-r--r--private/utils/ntbackup/inc/rt_dlg.h69
-rw-r--r--private/utils/ntbackup/inc/save_sel.h35
-rw-r--r--private/utils/ntbackup/inc/sch_opts.h93
-rw-r--r--private/utils/ntbackup/inc/sched.h44
-rw-r--r--private/utils/ntbackup/inc/schedule.h374
-rw-r--r--private/utils/ntbackup/inc/screen.h74
-rw-r--r--private/utils/ntbackup/inc/scriperr.h51
-rw-r--r--private/utils/ntbackup/inc/script.h94
-rw-r--r--private/utils/ntbackup/inc/script_p.h241
-rw-r--r--private/utils/ntbackup/inc/script_s.h94
-rw-r--r--private/utils/ntbackup/inc/set_cat.h41
-rw-r--r--private/utils/ntbackup/inc/set_dbug.h43
-rw-r--r--private/utils/ntbackup/inc/set_log.h40
-rw-r--r--private/utils/ntbackup/inc/set_opts.h32
-rw-r--r--private/utils/ntbackup/inc/set_prt.h32
-rw-r--r--private/utils/ntbackup/inc/set_rest.h38
-rw-r--r--private/utils/ntbackup/inc/setback.h44
-rw-r--r--private/utils/ntbackup/inc/sio.h80
-rw-r--r--private/utils/ntbackup/inc/skipno.h25
-rw-r--r--private/utils/ntbackup/inc/skipopen.h37
-rw-r--r--private/utils/ntbackup/inc/sleep.h29
-rw-r--r--private/utils/ntbackup/inc/smb.h191
-rw-r--r--private/utils/ntbackup/inc/smb_c.h67
-rw-r--r--private/utils/ntbackup/inc/smb_cs.h138
-rw-r--r--private/utils/ntbackup/inc/smb_s.h37
-rw-r--r--private/utils/ntbackup/inc/some.h3
-rw-r--r--private/utils/ntbackup/inc/special.h61
-rw-r--r--private/utils/ntbackup/inc/srvlogin.h39
-rw-r--r--private/utils/ntbackup/inc/ss_gui.h103
-rw-r--r--private/utils/ntbackup/inc/statline.h55
-rw-r--r--private/utils/ntbackup/inc/stats.h299
-rw-r--r--private/utils/ntbackup/inc/status.h43
-rw-r--r--private/utils/ntbackup/inc/std_err.h30
-rw-r--r--private/utils/ntbackup/inc/stdhooks.h48
-rw-r--r--private/utils/ntbackup/inc/stdmacro.h53
-rw-r--r--private/utils/ntbackup/inc/stdmath.h229
-rw-r--r--private/utils/ntbackup/inc/stdstruc.h25
-rw-r--r--private/utils/ntbackup/inc/stdtypes.h351
-rw-r--r--private/utils/ntbackup/inc/stdwcs.h219
-rw-r--r--private/utils/ntbackup/inc/sx.h230
-rw-r--r--private/utils/ntbackup/inc/sxdd.h39
-rw-r--r--private/utils/ntbackup/inc/sxtf.h63
-rw-r--r--private/utils/ntbackup/inc/sypl10.h248
-rw-r--r--private/utils/ntbackup/inc/syplpto.h37
-rw-r--r--private/utils/ntbackup/inc/tape.h107
-rw-r--r--private/utils/ntbackup/inc/tapepswd.h70
-rw-r--r--private/utils/ntbackup/inc/tbe_defs.h124
-rw-r--r--private/utils/ntbackup/inc/tbe_err.h38
-rw-r--r--private/utils/ntbackup/inc/tble_prv.h35
-rw-r--r--private/utils/ntbackup/inc/tdemo.h52
-rw-r--r--private/utils/ntbackup/inc/tension.h30
-rw-r--r--private/utils/ntbackup/inc/text.h45
-rw-r--r--private/utils/ntbackup/inc/tfl_err.h126
-rw-r--r--private/utils/ntbackup/inc/tfldefs.h204
-rw-r--r--private/utils/ntbackup/inc/tflopen.h63
-rw-r--r--private/utils/ntbackup/inc/tflproto.h134
-rw-r--r--private/utils/ntbackup/inc/tflstats.h48
-rw-r--r--private/utils/ntbackup/inc/tflwatch.h60
-rw-r--r--private/utils/ntbackup/inc/tfpoll.h76
-rw-r--r--private/utils/ntbackup/inc/thw.h80
-rw-r--r--private/utils/ntbackup/inc/timers.h66
-rw-r--r--private/utils/ntbackup/inc/tloc.h57
-rw-r--r--private/utils/ntbackup/inc/tpos.h189
-rw-r--r--private/utils/ntbackup/inc/translat.h176
-rw-r--r--private/utils/ntbackup/inc/transprt.h74
-rw-r--r--private/utils/ntbackup/inc/transutl.h69
-rw-r--r--private/utils/ntbackup/inc/tsearch.h44
-rw-r--r--private/utils/ntbackup/inc/unic_io.h883
-rw-r--r--private/utils/ntbackup/inc/use_sel.h30
-rw-r--r--private/utils/ntbackup/inc/vlm.h805
-rw-r--r--private/utils/ntbackup/inc/vlm_find.h344
-rw-r--r--private/utils/ntbackup/inc/vm.h117
-rw-r--r--private/utils/ntbackup/inc/vqueue.h119
-rw-r--r--private/utils/ntbackup/inc/wcs.h63
-rw-r--r--private/utils/ntbackup/inc/win3216.h54
-rw-r--r--private/utils/ntbackup/inc/winmang.h550
-rw-r--r--private/utils/ntbackup/inc/xferblk.h26
-rw-r--r--private/utils/ntbackup/inc/yes_no.h5
-rw-r--r--private/utils/ntbackup/src/3dcheck.bmpbin0 -> 1522 bytes
-rw-r--r--private/utils/ntbackup/src/addbsd.c579
-rw-r--r--private/utils/ntbackup/src/addfse.c633
-rw-r--r--private/utils/ntbackup/src/addlba.c308
-rw-r--r--private/utils/ntbackup/src/atachdle.c237
-rw-r--r--private/utils/ntbackup/src/att_drv.c318
-rw-r--r--private/utils/ntbackup/src/back_dle.c231
-rw-r--r--private/utils/ntbackup/src/back_obj.c847
-rw-r--r--private/utils/ntbackup/src/back_vcb.c240
-rw-r--r--private/utils/ntbackup/src/be_debug.c65
-rw-r--r--private/utils/ntbackup/src/be_dinit.c105
-rw-r--r--private/utils/ntbackup/src/be_init.c232
-rw-r--r--private/utils/ntbackup/src/be_tfutl.c277
-rw-r--r--private/utils/ntbackup/src/bec_init.c360
-rw-r--r--private/utils/ntbackup/src/bec_mem.c514
-rw-r--r--private/utils/ntbackup/src/bec_misc.c320
-rw-r--r--private/utils/ntbackup/src/bitmaps.rc218
-rw-r--r--private/utils/ntbackup/src/bkuevent.mc99
-rw-r--r--private/utils/ntbackup/src/bsdlasto.c290
-rw-r--r--private/utils/ntbackup/src/bsdmatch.c889
-rw-r--r--private/utils/ntbackup/src/bsdsinfo.c417
-rw-r--r--private/utils/ntbackup/src/bsdthw.c93
-rw-r--r--private/utils/ntbackup/src/bset.bmpbin0 -> 310 bytes
-rw-r--r--private/utils/ntbackup/src/bsetpart.bmpbin0 -> 310 bytes
-rw-r--r--private/utils/ntbackup/src/buffman.c942
-rw-r--r--private/utils/ntbackup/src/buffnt.c569
-rw-r--r--private/utils/ntbackup/src/checksum.c269
-rw-r--r--private/utils/ntbackup/src/clearfsl.c136
-rw-r--r--private/utils/ntbackup/src/cli_stub.c72
-rw-r--r--private/utils/ntbackup/src/confmisc.c828
-rw-r--r--private/utils/ntbackup/src/critstub.c65
-rw-r--r--private/utils/ntbackup/src/crptfile.bmpbin0 -> 246 bytes
-rw-r--r--private/utils/ntbackup/src/ctbrkstb.c69
-rw-r--r--private/utils/ntbackup/src/cursors.rc40
-rw-r--r--private/utils/ntbackup/src/d_about.c1200
-rw-r--r--private/utils/ntbackup/src/d_adv_us.c393
-rw-r--r--private/utils/ntbackup/src/d_attach.c332
-rw-r--r--private/utils/ntbackup/src/d_browse.c644
-rw-r--r--private/utils/ntbackup/src/d_ctape.c497
-rw-r--r--private/utils/ntbackup/src/d_date.c145
-rw-r--r--private/utils/ntbackup/src/d_dbug.c329
-rw-r--r--private/utils/ntbackup/src/d_erase.c166
-rw-r--r--private/utils/ntbackup/src/d_o_bkup.c2590
-rw-r--r--private/utils/ntbackup/src/d_o_rset.c2742
-rw-r--r--private/utils/ntbackup/src/d_o_xchg.c732
-rw-r--r--private/utils/ntbackup/src/d_r_path.c240
-rw-r--r--private/utils/ntbackup/src/d_t_pswd.c355
-rw-r--r--private/utils/ntbackup/src/d_v_path.c239
-rw-r--r--private/utils/ntbackup/src/datetime.c383
-rw-r--r--private/utils/ntbackup/src/dateutil.c506
-rw-r--r--private/utils/ntbackup/src/dblksize.c89
-rw-r--r--private/utils/ntbackup/src/ddeproc.c142
-rw-r--r--private/utils/ntbackup/src/debug.c754
-rw-r--r--private/utils/ntbackup/src/debug.icobin0 -> 766 bytes
-rw-r--r--private/utils/ntbackup/src/defchan.c63
-rw-r--r--private/utils/ntbackup/src/defltblk.c167
-rw-r--r--private/utils/ntbackup/src/details.c1756
-rw-r--r--private/utils/ntbackup/src/detfmt.c391
-rw-r--r--private/utils/ntbackup/src/dettpdrv.c205
-rw-r--r--private/utils/ntbackup/src/dialmang.c604
-rw-r--r--private/utils/ntbackup/src/dialogs.rc261
-rw-r--r--private/utils/ntbackup/src/dilntmsc.c1747
-rw-r--r--private/utils/ntbackup/src/dilnttp.c1621
-rw-r--r--private/utils/ntbackup/src/disks.icobin0 -> 766 bytes
-rw-r--r--private/utils/ntbackup/src/dledelet.c84
-rw-r--r--private/utils/ntbackup/src/dleget.c499
-rw-r--r--private/utils/ntbackup/src/dlereset.c153
-rw-r--r--private/utils/ntbackup/src/dleupdat.c180
-rw-r--r--private/utils/ntbackup/src/dlg_util.c295
-rw-r--r--private/utils/ntbackup/src/dlm_draw.c1605
-rw-r--r--private/utils/ntbackup/src/dlm_init.c937
-rw-r--r--private/utils/ntbackup/src/dlm_lbn.c843
-rw-r--r--private/utils/ntbackup/src/dlm_proc.c969
-rw-r--r--private/utils/ntbackup/src/dlm_scrn.c868
-rw-r--r--private/utils/ntbackup/src/dlm_updt.c1014
-rw-r--r--private/utils/ntbackup/src/do_back.c3457
-rw-r--r--private/utils/ntbackup/src/do_cat.c2948
-rw-r--r--private/utils/ntbackup/src/do_del.c638
-rw-r--r--private/utils/ntbackup/src/do_excl.c829
-rw-r--r--private/utils/ntbackup/src/do_ffr.c602
-rw-r--r--private/utils/ntbackup/src/do_misc.c761
-rw-r--r--private/utils/ntbackup/src/do_next.c427
-rw-r--r--private/utils/ntbackup/src/do_rest.c2438
-rw-r--r--private/utils/ntbackup/src/do_tens.c822
-rw-r--r--private/utils/ntbackup/src/do_very.c1859
-rw-r--r--private/utils/ntbackup/src/docproc.c1561
-rw-r--r--private/utils/ntbackup/src/drives.c1771
-rw-r--r--private/utils/ntbackup/src/ems_tab.c138
-rw-r--r--private/utils/ntbackup/src/enc_tab.c77
-rw-r--r--private/utils/ntbackup/src/encrypt.c481
-rw-r--r--private/utils/ntbackup/src/entrpris.icobin0 -> 1078 bytes
-rw-r--r--private/utils/ntbackup/src/eprintf.c174
-rw-r--r--private/utils/ntbackup/src/erase.c617
-rw-r--r--private/utils/ntbackup/src/exe.bmpbin0 -> 246 bytes
-rw-r--r--private/utils/ntbackup/src/file.bmpbin0 -> 246 bytes
-rw-r--r--private/utils/ntbackup/src/files.icobin0 -> 766 bytes
-rw-r--r--private/utils/ntbackup/src/filgetc.c96
-rw-r--r--private/utils/ntbackup/src/floppy1.bmpbin0 -> 438 bytes
-rw-r--r--private/utils/ntbackup/src/floppy2.bmpbin0 -> 438 bytes
-rw-r--r--private/utils/ntbackup/src/floppy3.bmpbin0 -> 438 bytes
-rw-r--r--private/utils/ntbackup/src/floppy4.bmpbin0 -> 438 bytes
-rw-r--r--private/utils/ntbackup/src/fmttab.c581
-rw-r--r--private/utils/ntbackup/src/fol_cm.bmpbin0 -> 214 bytes
-rw-r--r--private/utils/ntbackup/src/fol_cn.bmpbin0 -> 214 bytes
-rw-r--r--private/utils/ntbackup/src/fol_cp.bmpbin0 -> 214 bytes
-rw-r--r--private/utils/ntbackup/src/fol_ocm.bmpbin0 -> 214 bytes
-rw-r--r--private/utils/ntbackup/src/fol_ocn.bmpbin0 -> 214 bytes
-rw-r--r--private/utils/ntbackup/src/fol_ocp.bmpbin0 -> 214 bytes
-rw-r--r--private/utils/ntbackup/src/fold_om.bmpbin0 -> 214 bytes
-rw-r--r--private/utils/ntbackup/src/fold_on.bmpbin0 -> 214 bytes
-rw-r--r--private/utils/ntbackup/src/fold_op.bmpbin0 -> 214 bytes
-rw-r--r--private/utils/ntbackup/src/folder.bmpbin0 -> 214 bytes
-rw-r--r--private/utils/ntbackup/src/folder_m.bmpbin0 -> 214 bytes
-rw-r--r--private/utils/ntbackup/src/folder_p.bmpbin0 -> 214 bytes
-rw-r--r--private/utils/ntbackup/src/font.c282
-rw-r--r--private/utils/ntbackup/src/font.dlg36
-rw-r--r--private/utils/ntbackup/src/freplace.c282
-rw-r--r--private/utils/ntbackup/src/frmproc.c936
-rw-r--r--private/utils/ntbackup/src/fsecopy.c129
-rw-r--r--private/utils/ntbackup/src/func_tab.c25
-rw-r--r--private/utils/ntbackup/src/gen_tab.c137
-rw-r--r--private/utils/ntbackup/src/gendblk.c342
-rw-r--r--private/utils/ntbackup/src/get_vcb.c131
-rw-r--r--private/utils/ntbackup/src/getres.c76
-rw-r--r--private/utils/ntbackup/src/getstrm.c468
-rw-r--r--private/utils/ntbackup/src/ginitfs.c138
-rw-r--r--private/utils/ntbackup/src/global.c539
-rw-r--r--private/utils/ntbackup/src/gmkdblk.c434
-rw-r--r--private/utils/ntbackup/src/gmoddblk.c748
-rw-r--r--private/utils/ntbackup/src/gname.c338
-rw-r--r--private/utils/ntbackup/src/gsize.c181
-rw-r--r--private/utils/ntbackup/src/gtnxtdle.c1032
-rw-r--r--private/utils/ntbackup/src/gtnxttpe.c1021
-rw-r--r--private/utils/ntbackup/src/gui.c1750
-rw-r--r--private/utils/ntbackup/src/hcrpfile.bmpbin0 -> 246 bytes
-rw-r--r--private/utils/ntbackup/src/help.curbin0 -> 326 bytes
-rw-r--r--private/utils/ntbackup/src/helpmang.c1404
-rw-r--r--private/utils/ntbackup/src/hexefile.bmpbin0 -> 246 bytes
-rw-r--r--private/utils/ntbackup/src/hfile.bmpbin0 -> 246 bytes
-rw-r--r--private/utils/ntbackup/src/hslider.curbin0 -> 326 bytes
-rw-r--r--private/utils/ntbackup/src/hwcheck.c258
-rw-r--r--private/utils/ntbackup/src/hwconfnt.c1281
-rw-r--r--private/utils/ntbackup/src/hwctext.rc181
-rw-r--r--private/utils/ntbackup/src/icons.rc85
-rw-r--r--private/utils/ntbackup/src/initfsys.c456
-rw-r--r--private/utils/ntbackup/src/log.c1864
-rw-r--r--private/utils/ntbackup/src/logoproc.c257
-rw-r--r--private/utils/ntbackup/src/lp_tdir.c494
-rw-r--r--private/utils/ntbackup/src/lp_tens.c239
-rw-r--r--private/utils/ntbackup/src/lpbackup.c301
-rw-r--r--private/utils/ntbackup/src/lpdelete.c414
-rw-r--r--private/utils/ntbackup/src/lplist.c443
-rw-r--r--private/utils/ntbackup/src/lprestor.c341
-rw-r--r--private/utils/ntbackup/src/lprintf.c610
-rw-r--r--private/utils/ntbackup/src/lptools.c837
-rw-r--r--private/utils/ntbackup/src/lptpcat.c180
-rw-r--r--private/utils/ntbackup/src/lpverify.c353
-rw-r--r--private/utils/ntbackup/src/ltape.bmpbin0 -> 286 bytes
-rw-r--r--private/utils/ntbackup/src/lw_data.c122
-rw-r--r--private/utils/ntbackup/src/lwtfinf.c147
-rw-r--r--private/utils/ntbackup/src/mach_nt.c38
-rw-r--r--private/utils/ntbackup/src/makecfdb.c88
-rw-r--r--private/utils/ntbackup/src/makefile6
-rw-r--r--private/utils/ntbackup/src/makefile.inc2
-rw-r--r--private/utils/ntbackup/src/makeudb.c66
-rw-r--r--private/utils/ntbackup/src/makevcb.c428
-rw-r--r--private/utils/ntbackup/src/mayn31rd.c1724
-rw-r--r--private/utils/ntbackup/src/mayn40rd.c2431
-rw-r--r--private/utils/ntbackup/src/memang32.c801
-rw-r--r--private/utils/ntbackup/src/memver.c79
-rw-r--r--private/utils/ntbackup/src/menumang.c1546
-rw-r--r--private/utils/ntbackup/src/msgbox.c1304
-rw-r--r--private/utils/ntbackup/src/msgbox.dlg52
-rw-r--r--private/utils/ntbackup/src/msmktemp.c72
-rw-r--r--private/utils/ntbackup/src/mtf10wdb.c1639
-rw-r--r--private/utils/ntbackup/src/mtf10wt.c1678
-rw-r--r--private/utils/ntbackup/src/mui.c1904
-rw-r--r--private/utils/ntbackup/src/muiconf.c1483
-rw-r--r--private/utils/ntbackup/src/muiutil.c1560
-rw-r--r--private/utils/ntbackup/src/myn40otc.c315
-rw-r--r--private/utils/ntbackup/src/nostrad.rc89
-rw-r--r--private/utils/ntbackup/src/nothing.c34
-rw-r--r--private/utils/ntbackup/src/ntbackup.c309
-rw-r--r--private/utils/ntbackup/src/ntfs_tab.c184
-rw-r--r--private/utils/ntbackup/src/ntfslink.c476
-rw-r--r--private/utils/ntbackup/src/ntfsregy.c1330
-rw-r--r--private/utils/ntbackup/src/ntfstemp.c449
-rw-r--r--private/utils/ntbackup/src/ntfsutil.c158
-rw-r--r--private/utils/ntbackup/src/om_blank.bmpbin0 -> 246 bytes
-rw-r--r--private/utils/ntbackup/src/om_dsap.bmpbin0 -> 246 bytes
-rw-r--r--private/utils/ntbackup/src/om_dsas.bmpbin0 -> 246 bytes
-rw-r--r--private/utils/ntbackup/src/om_dsax.bmpbin0 -> 246 bytes
-rw-r--r--private/utils/ntbackup/src/om_entrs.bmpbin0 -> 246 bytes
-rw-r--r--private/utils/ntbackup/src/om_mdbp.bmpbin0 -> 246 bytes
-rw-r--r--private/utils/ntbackup/src/om_mdbs.bmpbin0 -> 246 bytes
-rw-r--r--private/utils/ntbackup/src/om_mdbx.bmpbin0 -> 246 bytes
-rw-r--r--private/utils/ntbackup/src/om_servs.bmpbin0 -> 246 bytes
-rw-r--r--private/utils/ntbackup/src/om_sites.bmpbin0 -> 246 bytes
-rw-r--r--private/utils/ntbackup/src/om_stats.bmpbin0 -> 150 bytes
-rw-r--r--private/utils/ntbackup/src/omabout.dlg49
-rw-r--r--private/utils/ntbackup/src/omacckey.rc34
-rw-r--r--private/utils/ntbackup/src/ombackup.bmpbin0 -> 358 bytes
-rw-r--r--private/utils/ntbackup/src/ombackup.icobin0 -> 766 bytes
-rw-r--r--private/utils/ntbackup/src/ombatch.c1205
-rw-r--r--private/utils/ntbackup/src/ombkup.dlg67
-rw-r--r--private/utils/ntbackup/src/ombrowse.dlg105
-rw-r--r--private/utils/ntbackup/src/omcat.bmpbin0 -> 310 bytes
-rw-r--r--private/utils/ntbackup/src/omcatlog.dlg15
-rw-r--r--private/utils/ntbackup/src/omcdisk.bmpbin0 -> 286 bytes
-rw-r--r--private/utils/ntbackup/src/omcheck.bmpbin0 -> 310 bytes
-rw-r--r--private/utils/ntbackup/src/omeject.bmpbin0 -> 310 bytes
-rw-r--r--private/utils/ntbackup/src/omerase.bmpbin0 -> 310 bytes
-rw-r--r--private/utils/ntbackup/src/omerase.dlg23
-rw-r--r--private/utils/ntbackup/src/omevent.c329
-rw-r--r--private/utils/ntbackup/src/omfdisk.bmpbin0 -> 286 bytes
-rw-r--r--private/utils/ntbackup/src/omfiler.dlg19
-rw-r--r--private/utils/ntbackup/src/omgbacku.bmpbin0 -> 358 bytes
-rw-r--r--private/utils/ntbackup/src/omgcat.bmpbin0 -> 310 bytes
-rw-r--r--private/utils/ntbackup/src/omgcheck.bmpbin0 -> 310 bytes
-rw-r--r--private/utils/ntbackup/src/omgeject.bmpbin0 -> 310 bytes
-rw-r--r--private/utils/ntbackup/src/omgerase.bmpbin0 -> 310 bytes
-rw-r--r--private/utils/ntbackup/src/omgresto.bmpbin0 -> 358 bytes
-rw-r--r--private/utils/ntbackup/src/omgtensi.bmpbin0 -> 310 bytes
-rw-r--r--private/utils/ntbackup/src/omgunche.bmpbin0 -> 310 bytes
-rw-r--r--private/utils/ntbackup/src/omhdisk.bmpbin0 -> 286 bytes
-rw-r--r--private/utils/ntbackup/src/omhwconf.dlg13
-rw-r--r--private/utils/ntbackup/src/ommenus.rc131
-rw-r--r--private/utils/ntbackup/src/ommuibar.c458
-rw-r--r--private/utils/ntbackup/src/omndisk.bmpbin0 -> 286 bytes
-rw-r--r--private/utils/ntbackup/src/omrdisk.bmpbin0 -> 286 bytes
-rw-r--r--private/utils/ntbackup/src/omrestor.bmpbin0 -> 358 bytes
-rw-r--r--private/utils/ntbackup/src/omrset.dlg71
-rw-r--r--private/utils/ntbackup/src/omruntim.dlg82
-rw-r--r--private/utils/ntbackup/src/omselall.bmpbin0 -> 214 bytes
-rw-r--r--private/utils/ntbackup/src/omselnon.bmpbin0 -> 214 bytes
-rw-r--r--private/utils/ntbackup/src/omselpar.bmpbin0 -> 214 bytes
-rw-r--r--private/utils/ntbackup/src/omstring.rc1515
-rw-r--r--private/utils/ntbackup/src/omtensio.bmpbin0 -> 310 bytes
-rw-r--r--private/utils/ntbackup/src/omunchec.bmpbin0 -> 310 bytes
-rw-r--r--private/utils/ntbackup/src/omxchng.dlg52
-rw-r--r--private/utils/ntbackup/src/openbsdu.c109
-rw-r--r--private/utils/ntbackup/src/opensys.c273
-rw-r--r--private/utils/ntbackup/src/otc40msc.c1192
-rw-r--r--private/utils/ntbackup/src/otc40rd.c1058
-rw-r--r--private/utils/ntbackup/src/otc40wt.c1793
-rw-r--r--private/utils/ntbackup/src/parspath.c1104
-rw-r--r--private/utils/ntbackup/src/passdb.c383
-rw-r--r--private/utils/ntbackup/src/password.c813
-rw-r--r--private/utils/ntbackup/src/pdir2.bmpbin0 -> 246 bytes
-rw-r--r--private/utils/ntbackup/src/polldrv.c1124
-rw-r--r--private/utils/ntbackup/src/posatset.c1185
-rw-r--r--private/utils/ntbackup/src/pwxface.c720
-rw-r--r--private/utils/ntbackup/src/qtc_add.c1028
-rw-r--r--private/utils/ntbackup/src/qtc_back.c1884
-rw-r--r--private/utils/ntbackup/src/qtc_bset.c685
-rw-r--r--private/utils/ntbackup/src/qtc_eom.c894
-rw-r--r--private/utils/ntbackup/src/qtc_init.c660
-rw-r--r--private/utils/ntbackup/src/qtc_srch.c3034
-rw-r--r--private/utils/ntbackup/src/qtc_util.c1555
-rw-r--r--private/utils/ntbackup/src/qtcxface.c1173
-rw-r--r--private/utils/ntbackup/src/queues.c914
-rw-r--r--private/utils/ntbackup/src/resmang.c1381
-rw-r--r--private/utils/ntbackup/src/rest_dle.c259
-rw-r--r--private/utils/ntbackup/src/rest_obj.c983
-rw-r--r--private/utils/ntbackup/src/ribproc.c1968
-rw-r--r--private/utils/ntbackup/src/runtime.c2481
-rw-r--r--private/utils/ntbackup/src/savepath.c164
-rw-r--r--private/utils/ntbackup/src/scanbsd.c283
-rw-r--r--private/utils/ntbackup/src/scomplex.c618
-rw-r--r--private/utils/ntbackup/src/sdisk.bmpbin0 -> 310 bytes
-rw-r--r--private/utils/ntbackup/src/set_dbug.dlg43
-rw-r--r--private/utils/ntbackup/src/skipno.c133
-rw-r--r--private/utils/ntbackup/src/skipno.dlg12
-rw-r--r--private/utils/ntbackup/src/skipopen.c235
-rw-r--r--private/utils/ntbackup/src/skipopen.dlg33
-rw-r--r--private/utils/ntbackup/src/sleepwin.c85
-rw-r--r--private/utils/ntbackup/src/sources392
-rw-r--r--private/utils/ntbackup/src/statline.c396
-rw-r--r--private/utils/ntbackup/src/stats.c360
-rw-r--r--private/utils/ntbackup/src/stdmath.c1976
-rw-r--r--private/utils/ntbackup/src/stdwcs.c902
-rw-r--r--private/utils/ntbackup/src/stubfunc.c206
-rw-r--r--private/utils/ntbackup/src/sx.c1239
-rw-r--r--private/utils/ntbackup/src/sypl10rd.c1365
-rw-r--r--private/utils/ntbackup/src/tape2.bmpbin0 -> 246 bytes
-rw-r--r--private/utils/ntbackup/src/tapein2.bmpbin0 -> 246 bytes
-rw-r--r--private/utils/ntbackup/src/tapes2.bmpbin0 -> 310 bytes
-rw-r--r--private/utils/ntbackup/src/tapes3.icobin0 -> 766 bytes
-rw-r--r--private/utils/ntbackup/src/tapesin2.bmpbin0 -> 310 bytes
-rw-r--r--private/utils/ntbackup/src/tattach.c419
-rw-r--r--private/utils/ntbackup/src/tbdpars.c673
-rw-r--r--private/utils/ntbackup/src/tbgetc.c88
-rw-r--r--private/utils/ntbackup/src/tbnextok.c943
-rw-r--r--private/utils/ntbackup/src/tbpdat.c270
-rw-r--r--private/utils/ntbackup/src/tbprocsw.c857
-rw-r--r--private/utils/ntbackup/src/tbrparse.c882
-rw-r--r--private/utils/ntbackup/src/tchgdir.c213
-rw-r--r--private/utils/ntbackup/src/tclose.c569
-rw-r--r--private/utils/ntbackup/src/tcomplet.c260
-rw-r--r--private/utils/ntbackup/src/tcreate.c508
-rw-r--r--private/utils/ntbackup/src/tdelete.c176
-rw-r--r--private/utils/ntbackup/src/tension.dlg11
-rw-r--r--private/utils/ntbackup/src/tfbuffs.c292
-rw-r--r--private/utils/ntbackup/src/tfclose.c229
-rw-r--r--private/utils/ntbackup/src/tfeject.c123
-rw-r--r--private/utils/ntbackup/src/tfinit.c501
-rw-r--r--private/utils/ntbackup/src/tflutils.c1384
-rw-r--r--private/utils/ntbackup/src/tfopen.c394
-rw-r--r--private/utils/ntbackup/src/tfpoll.c1077
-rw-r--r--private/utils/ntbackup/src/tfread.c1656
-rw-r--r--private/utils/ntbackup/src/tfreten.c299
-rw-r--r--private/utils/ntbackup/src/tfrewind.c116
-rw-r--r--private/utils/ntbackup/src/tfstuff.c290
-rw-r--r--private/utils/ntbackup/src/tftpcat.c737
-rw-r--r--private/utils/ntbackup/src/tfwrite.c1487
-rw-r--r--private/utils/ntbackup/src/tgetinfo.c258
-rw-r--r--private/utils/ntbackup/src/tgetnext.c638
-rw-r--r--private/utils/ntbackup/src/tgetpath.c500
-rw-r--r--private/utils/ntbackup/src/tgetspec.c211
-rw-r--r--private/utils/ntbackup/src/timers.c511
-rw-r--r--private/utils/ntbackup/src/tinitfs.c973
-rw-r--r--private/utils/ntbackup/src/tminddb.c178
-rw-r--r--private/utils/ntbackup/src/tmkdblk.c718
-rw-r--r--private/utils/ntbackup/src/tmoddblk.c1174
-rw-r--r--private/utils/ntbackup/src/tname.c185
-rw-r--r--private/utils/ntbackup/src/topen.c1339
-rw-r--r--private/utils/ntbackup/src/tposmisc.c460
-rw-r--r--private/utils/ntbackup/src/tprintf.c139
-rw-r--r--private/utils/ntbackup/src/translat.c1690
-rw-r--r--private/utils/ntbackup/src/transutl.c382
-rw-r--r--private/utils/ntbackup/src/treadobj.c841
-rw-r--r--private/utils/ntbackup/src/tree.icobin0 -> 766 bytes
-rw-r--r--private/utils/ntbackup/src/treefile.icobin0 -> 766 bytes
-rw-r--r--private/utils/ntbackup/src/tseekobj.c143
-rw-r--r--private/utils/ntbackup/src/tsetinfo.c237
-rw-r--r--private/utils/ntbackup/src/tsize.c253
-rw-r--r--private/utils/ntbackup/src/tverinfo.c279
-rw-r--r--private/utils/ntbackup/src/tverobj.c920
-rw-r--r--private/utils/ntbackup/src/twritobj.c676
-rw-r--r--private/utils/ntbackup/src/uadd_dle.c119
-rw-r--r--private/utils/ntbackup/src/unicode.c892
-rw-r--r--private/utils/ntbackup/src/unitinit.c480
-rw-r--r--private/utils/ntbackup/src/version.rc43
-rw-r--r--private/utils/ntbackup/src/very_dle.c270
-rw-r--r--private/utils/ntbackup/src/very_obj.c494
-rw-r--r--private/utils/ntbackup/src/viewproc.c460
-rw-r--r--private/utils/ntbackup/src/vlm_bset.c2797
-rw-r--r--private/utils/ntbackup/src/vlm_cat.c571
-rw-r--r--private/utils/ntbackup/src/vlm_disk.c1180
-rw-r--r--private/utils/ntbackup/src/vlm_file.c3496
-rw-r--r--private/utils/ntbackup/src/vlm_find.c480
-rw-r--r--private/utils/ntbackup/src/vlm_init.c144
-rw-r--r--private/utils/ntbackup/src/vlm_menu.c1041
-rw-r--r--private/utils/ntbackup/src/vlm_poll.c722
-rw-r--r--private/utils/ntbackup/src/vlm_refr.c735
-rw-r--r--private/utils/ntbackup/src/vlm_srch.c1997
-rw-r--r--private/utils/ntbackup/src/vlm_srv.c1897
-rw-r--r--private/utils/ntbackup/src/vlm_strt.c684
-rw-r--r--private/utils/ntbackup/src/vlm_tape.c1382
-rw-r--r--private/utils/ntbackup/src/vlm_tree.c3830
-rw-r--r--private/utils/ntbackup/src/vlm_util.c2162
-rw-r--r--private/utils/ntbackup/src/vlm_xchg.c3630
-rw-r--r--private/utils/ntbackup/src/vmstubs.c109
-rw-r--r--private/utils/ntbackup/src/vset.dlg87
-rw-r--r--private/utils/ntbackup/src/winassrt.c167
-rw-r--r--private/utils/ntbackup/src/winmang.c2061
-rw-r--r--private/utils/ntbackup/src/writescr.c298
-rw-r--r--private/utils/ntbackup/src/xattach.c560
-rw-r--r--private/utils/ntbackup/src/xchgdir.c106
-rw-r--r--private/utils/ntbackup/src/xclose.c153
-rw-r--r--private/utils/ntbackup/src/xcreate.c310
-rw-r--r--private/utils/ntbackup/src/xgetinfo.c51
-rw-r--r--private/utils/ntbackup/src/xgetnext.c86
-rw-r--r--private/utils/ntbackup/src/xgetpath.c189
-rw-r--r--private/utils/ntbackup/src/xinitfs.c1192
-rw-r--r--private/utils/ntbackup/src/xmkdblk.c126
-rw-r--r--private/utils/ntbackup/src/xmoddblk.c618
-rw-r--r--private/utils/ntbackup/src/xname.c160
-rw-r--r--private/utils/ntbackup/src/xopen.c661
-rw-r--r--private/utils/ntbackup/src/xreadobj.c625
-rw-r--r--private/utils/ntbackup/src/xseekobj.c102
-rw-r--r--private/utils/ntbackup/src/xsetinfo.c50
-rw-r--r--private/utils/ntbackup/src/xsize.c185
-rw-r--r--private/utils/ntbackup/src/xverinfo.c50
-rw-r--r--private/utils/ntbackup/src/xverobj.c100
-rw-r--r--private/utils/ntbackup/src/xwritobj.c724
-rw-r--r--private/utils/ntbackup/src/yprintf.c120
-rw-r--r--private/utils/ntbackup/src/zprintf.c111
-rw-r--r--private/utils/ntlib/dirs16
-rw-r--r--private/utils/ntlib/src/boothack.cxx26
-rw-r--r--private/utils/ntlib/src/makefile6
-rw-r--r--private/utils/ntlib/src/makefile.inc326
-rw-r--r--private/utils/ntlib/src/pch.cxx125
-rw-r--r--private/utils/ntlib/src/sources254
-rw-r--r--private/utils/pentbug/i386/sources49
-rw-r--r--private/utils/pentbug/makefile6
-rw-r--r--private/utils/pentbug/makefile.inc4
-rw-r--r--private/utils/pentbug/pbmsg.mc189
-rw-r--r--private/utils/pentbug/pentnt.c694
-rw-r--r--private/utils/pentbug/pentnt.rc12
-rw-r--r--private/utils/pentbug/sources33
-rw-r--r--private/utils/print/makefile6
-rw-r--r--private/utils/print/makefile.inc12
-rw-r--r--private/utils/print/print.cxx413
-rw-r--r--private/utils/print/print.hxx87
-rw-r--r--private/utils/print/print.rc10
-rw-r--r--private/utils/print/sources60
-rw-r--r--private/utils/rdisk/config.c908
-rw-r--r--private/utils/rdisk/dialogs.dlg27
-rw-r--r--private/utils/rdisk/dialogs.h10
-rw-r--r--private/utils/rdisk/diamond.c476
-rw-r--r--private/utils/rdisk/floppyop.c888
-rw-r--r--private/utils/rdisk/format.c347
-rw-r--r--private/utils/rdisk/help.c363
-rw-r--r--private/utils/rdisk/help.h78
-rw-r--r--private/utils/rdisk/i386/rdskboot.asm77
-rw-r--r--private/utils/rdisk/i386/readme17
-rw-r--r--private/utils/rdisk/i386/x.bat2
-rw-r--r--private/utils/rdisk/makefile6
-rw-r--r--private/utils/rdisk/precomp.h14
-rw-r--r--private/utils/rdisk/rdisk.c619
-rw-r--r--private/utils/rdisk/rdisk.h65
-rw-r--r--private/utils/rdisk/rdisk.icobin0 -> 1086 bytes
-rw-r--r--private/utils/rdisk/rdskboot.c8
-rw-r--r--private/utils/rdisk/resource.h70
-rw-r--r--private/utils/rdisk/resource.rc74
-rw-r--r--private/utils/rdisk/sources29
-rw-r--r--private/utils/recover/makefile6
-rw-r--r--private/utils/recover/makefile.inc12
-rw-r--r--private/utils/recover/recover.cxx200
-rw-r--r--private/utils/recover/recover.rc10
-rw-r--r--private/utils/recover/sources57
-rw-r--r--private/utils/regedit/dirs16
-rw-r--r--private/utils/regedit/inc/datavw.hxx207
-rw-r--r--private/utils/regedit/inc/defmsg.h276
-rw-r--r--private/utils/regedit/inc/dialogs.h103
-rw-r--r--private/utils/regedit/inc/editor.hxx183
-rw-r--r--private/utils/regedit/inc/printman.hxx400
-rw-r--r--private/utils/regedit/inc/regdata.hxx346
-rw-r--r--private/utils/regedit/inc/regdesc.hxx1650
-rw-r--r--private/utils/regedit/inc/regedhlp.h91
-rw-r--r--private/utils/regedit/inc/regedir.hxx1445
-rw-r--r--private/utils/regedit/inc/regedit.hxx258
-rw-r--r--private/utils/regedit/inc/regednod.hxx887
-rw-r--r--private/utils/regedit/inc/regedval.hxx389
-rw-r--r--private/utils/regedit/inc/regfdesc.hxx245
-rw-r--r--private/utils/regedit/inc/regiodls.hxx177
-rw-r--r--private/utils/regedit/inc/regiodsc.hxx1694
-rw-r--r--private/utils/regedit/inc/regioreq.hxx308
-rw-r--r--private/utils/regedit/inc/regresls.hxx110
-rw-r--r--private/utils/regedit/inc/regsys.hxx67
-rw-r--r--private/utils/regedit/inc/regwin.hxx263
-rw-r--r--private/utils/regedit/inc/resource.h120
-rw-r--r--private/utils/regedit/inc/treevw.hxx362
-rw-r--r--private/utils/regedit/inc/uapp.hxx184
-rw-r--r--private/utils/regedit/inc/winapp.hxx1005
-rw-r--r--private/utils/regedit/inc/window.hxx78
-rw-r--r--private/utils/regedit/src/bitmap.bmpbin0 -> 4902 bytes
-rw-r--r--private/utils/regedit/src/datavw.cxx1758
-rw-r--r--private/utils/regedit/src/debug.cxx198
-rw-r--r--private/utils/regedit/src/dialogs.dlg322
-rw-r--r--private/utils/regedit/src/editor.cxx2376
-rw-r--r--private/utils/regedit/src/makefile6
-rw-r--r--private/utils/regedit/src/makefile.inc12
-rw-r--r--private/utils/regedit/src/printman.cxx4102
-rw-r--r--private/utils/regedit/src/regdata.cxx3383
-rw-r--r--private/utils/regedit/src/regdesc.cxx538
-rw-r--r--private/utils/regedit/src/regedir.cxx2353
-rw-r--r--private/utils/regedit/src/regedit.hlpbin0 -> 21659 bytes
-rw-r--r--private/utils/regedit/src/regedit.icobin0 -> 766 bytes
-rw-r--r--private/utils/regedit/src/regedit.rc406
-rw-r--r--private/utils/regedit/src/regednod.cxx878
-rw-r--r--private/utils/regedit/src/regedt32.cxx4094
-rw-r--r--private/utils/regedit/src/regedval.cxx637
-rw-r--r--private/utils/regedit/src/regfdesc.cxx399
-rw-r--r--private/utils/regedit/src/regiodls.cxx358
-rw-r--r--private/utils/regedit/src/regiodsc.cxx471
-rw-r--r--private/utils/regedit/src/regioreq.cxx252
-rw-r--r--private/utils/regedit/src/regresls.cxx236
-rw-r--r--private/utils/regedit/src/regsys.cxx156
-rw-r--r--private/utils/regedit/src/regwin.cxx1392
-rw-r--r--private/utils/regedit/src/sources119
-rw-r--r--private/utils/regedit/src/split.curbin0 -> 326 bytes
-rw-r--r--private/utils/regedit/src/treevw.cxx3774
-rw-r--r--private/utils/regedit/src/uapp.cxx173
-rw-r--r--private/utils/regedit/src/winapp.cxx331
-rw-r--r--private/utils/regedit/src/window.cxx56
-rw-r--r--private/utils/replace/argument.cxx422
-rw-r--r--private/utils/replace/makefile6
-rw-r--r--private/utils/replace/makefile.inc12
-rw-r--r--private/utils/replace/replace.cxx948
-rw-r--r--private/utils/replace/replace.hxx289
-rw-r--r--private/utils/replace/replace.rc11
-rw-r--r--private/utils/replace/sources62
-rw-r--r--private/utils/replace/support.cxx156
-rw-r--r--private/utils/restore/dirs25
-rw-r--r--private/utils/restore/inc/queue.h78
-rw-r--r--private/utils/restore/inc/restore.h46
-rw-r--r--private/utils/restore/inc/rtdef.h57
-rw-r--r--private/utils/restore/inc/rtfile.h220
-rw-r--r--private/utils/restore/inc/rtglob.h83
-rw-r--r--private/utils/restore/inc/rtproto.h296
-rw-r--r--private/utils/restore/inc/rttype.h94
-rw-r--r--private/utils/restore/src/exit.c89
-rw-r--r--private/utils/restore/src/filecopy.c736
-rw-r--r--private/utils/restore/src/generic.c536
-rw-r--r--private/utils/restore/src/makefile6
-rw-r--r--private/utils/restore/src/makefile.inc4
-rw-r--r--private/utils/restore/src/match.c841
-rw-r--r--private/utils/restore/src/mbcs.c94
-rw-r--r--private/utils/restore/src/misc.c503
-rw-r--r--private/utils/restore/src/msg.c214
-rw-r--r--private/utils/restore/src/new.c751
-rw-r--r--private/utils/restore/src/old.c527
-rw-r--r--private/utils/restore/src/parse.c787
-rw-r--r--private/utils/restore/src/restore.c481
-rw-r--r--private/utils/restore/src/restore.rc12
-rw-r--r--private/utils/restore/src/rtmsg.mc191
-rw-r--r--private/utils/restore/src/sources36
-rw-r--r--private/utils/sort/makefile6
-rw-r--r--private/utils/sort/makefile.inc12
-rw-r--r--private/utils/sort/sort.cxx315
-rw-r--r--private/utils/sort/sort.hxx66
-rw-r--r--private/utils/sort/sort.rc10
-rw-r--r--private/utils/sort/sources57
-rw-r--r--private/utils/subst/makefile6
-rw-r--r--private/utils/subst/makefile.inc12
-rw-r--r--private/utils/subst/sources54
-rw-r--r--private/utils/subst/subst.cxx401
-rw-r--r--private/utils/subst/subst.hxx23
-rw-r--r--private/utils/subst/subst.rc10
-rw-r--r--private/utils/tree/makefile6
-rw-r--r--private/utils/tree/makefile.inc12
-rw-r--r--private/utils/tree/sources57
-rw-r--r--private/utils/tree/tree.cxx880
-rw-r--r--private/utils/tree/tree.hxx156
-rw-r--r--private/utils/tree/tree.rc10
-rw-r--r--private/utils/ufat/dirs16
-rw-r--r--private/utils/ufat/inc/cluster.hxx178
-rw-r--r--private/utils/ufat/inc/cvf.hxx251
-rw-r--r--private/utils/ufat/inc/cvfexts.hxx294
-rw-r--r--private/utils/ufat/inc/dblentry.hxx68
-rw-r--r--private/utils/ufat/inc/eaheader.hxx229
-rw-r--r--private/utils/ufat/inc/easet.hxx243
-rw-r--r--private/utils/ufat/inc/fat.hxx904
-rw-r--r--private/utils/ufat/inc/fatdbsa.hxx789
-rw-r--r--private/utils/ufat/inc/fatdbvol.hxx97
-rw-r--r--private/utils/ufat/inc/fatdent.hxx1052
-rw-r--r--private/utils/ufat/inc/fatdir.hxx90
-rw-r--r--private/utils/ufat/inc/fatsa.hxx754
-rw-r--r--private/utils/ufat/inc/fatvol.hxx151
-rw-r--r--private/utils/ufat/inc/filedir.hxx213
-rw-r--r--private/utils/ufat/inc/mrcf.h99
-rw-r--r--private/utils/ufat/inc/reloclus.hxx87
-rw-r--r--private/utils/ufat/inc/rfatsa.hxx986
-rw-r--r--private/utils/ufat/inc/rootdir.hxx173
-rw-r--r--private/utils/ufat/inc/ufat.hxx36
-rw-r--r--private/utils/ufat/src/cluster.cxx523
-rw-r--r--private/utils/ufat/src/cvfexts.cxx129
-rw-r--r--private/utils/ufat/src/dblentry.cxx1177
-rw-r--r--private/utils/ufat/src/eaheader.cxx215
-rw-r--r--private/utils/ufat/src/easet.cxx404
-rw-r--r--private/utils/ufat/src/entry.cxx496
-rw-r--r--private/utils/ufat/src/fat.cxx1024
-rw-r--r--private/utils/ufat/src/fatdbsa.cxx1593
-rw-r--r--private/utils/ufat/src/fatdbvol.cxx139
-rw-r--r--private/utils/ufat/src/fatdent.cxx1125
-rw-r--r--private/utils/ufat/src/fatdir.cxx201
-rw-r--r--private/utils/ufat/src/fatsa.cxx866
-rw-r--r--private/utils/ufat/src/fatsachk.cxx3246
-rw-r--r--private/utils/ufat/src/fatsacnv.cxx814
-rw-r--r--private/utils/ufat/src/fatvol.cxx435
-rw-r--r--private/utils/ufat/src/filedir.cxx132
-rw-r--r--private/utils/ufat/src/makefile6
-rw-r--r--private/utils/ufat/src/makefile.inc14
-rw-r--r--private/utils/ufat/src/mrcf.c1726
-rw-r--r--private/utils/ufat/src/pch.cxx36
-rw-r--r--private/utils/ufat/src/reloclus.cxx124
-rw-r--r--private/utils/ufat/src/rfatsa.cxx1789
-rw-r--r--private/utils/ufat/src/rootdir.cxx133
-rw-r--r--private/utils/ufat/src/sources93
-rw-r--r--private/utils/ufat/src/ufat.cxx167
-rw-r--r--private/utils/ufat/src/ufat.def10
-rw-r--r--private/utils/ufat/src/ufat.rc10
-rw-r--r--private/utils/ufat/src/ufatalph.ded9
-rw-r--r--private/utils/ufat/src/ufatmips.ded9
-rw-r--r--private/utils/ufat/src/ufatppc.ded9
-rw-r--r--private/utils/ufat/src/ufatx86.ded9
-rw-r--r--private/utils/uhpfs/dirs16
-rw-r--r--private/utils/uhpfs/hpfsmsgs.txt314
-rw-r--r--private/utils/uhpfs/inc/alsec.hxx209
-rw-r--r--private/utils/uhpfs/inc/badblk.hxx238
-rw-r--r--private/utils/uhpfs/inc/bitmap.hxx363
-rw-r--r--private/utils/uhpfs/inc/bmind.hxx141
-rw-r--r--private/utils/uhpfs/inc/cpinfo.hxx597
-rw-r--r--private/utils/uhpfs/inc/defer.hxx270
-rw-r--r--private/utils/uhpfs/inc/dirblk.hxx474
-rw-r--r--private/utils/uhpfs/inc/dircache.hxx169
-rw-r--r--private/utils/uhpfs/inc/dirmap.hxx147
-rw-r--r--private/utils/uhpfs/inc/dirtree.hxx212
-rw-r--r--private/utils/uhpfs/inc/fnode.hxx461
-rw-r--r--private/utils/uhpfs/inc/hfsecrun.hxx124
-rw-r--r--private/utils/uhpfs/inc/hotfix.hxx216
-rw-r--r--private/utils/uhpfs/inc/hpcensus.hxx420
-rw-r--r--private/utils/uhpfs/inc/hpfsacl.hxx72
-rw-r--r--private/utils/uhpfs/inc/hpfsea.hxx216
-rw-r--r--private/utils/uhpfs/inc/hpfseal.hxx154
-rw-r--r--private/utils/uhpfs/inc/hpfsname.hxx248
-rw-r--r--private/utils/uhpfs/inc/hpfssa.hxx820
-rw-r--r--private/utils/uhpfs/inc/hpfsvol.hxx280
-rw-r--r--private/utils/uhpfs/inc/ods.hxx61
-rw-r--r--private/utils/uhpfs/inc/orphan.hxx442
-rw-r--r--private/utils/uhpfs/inc/sid.hxx78
-rw-r--r--private/utils/uhpfs/inc/spareb.hxx767
-rw-r--r--private/utils/uhpfs/inc/store.hxx248
-rw-r--r--private/utils/uhpfs/inc/superb.hxx536
-rw-r--r--private/utils/uhpfs/inc/uhpfs.hxx90
-rw-r--r--private/utils/uhpfs/inc/verify.hxx35
-rw-r--r--private/utils/uhpfs/src/alsec.cxx922
-rw-r--r--private/utils/uhpfs/src/badblk.cxx795
-rw-r--r--private/utils/uhpfs/src/bitmap.cxx1977
-rw-r--r--private/utils/uhpfs/src/bmind.cxx412
-rw-r--r--private/utils/uhpfs/src/cpinfo.cxx1937
-rw-r--r--private/utils/uhpfs/src/defer.cxx1386
-rw-r--r--private/utils/uhpfs/src/dirblk.cxx1865
-rw-r--r--private/utils/uhpfs/src/dircache.cxx585
-rw-r--r--private/utils/uhpfs/src/dirmap.cxx662
-rw-r--r--private/utils/uhpfs/src/dirtree.cxx2381
-rw-r--r--private/utils/uhpfs/src/entry.cxx610
-rw-r--r--private/utils/uhpfs/src/fnode.cxx1543
-rw-r--r--private/utils/uhpfs/src/hfsecrun.cxx298
-rw-r--r--private/utils/uhpfs/src/hotfix.cxx827
-rw-r--r--private/utils/uhpfs/src/hpcensus.cxx283
-rw-r--r--private/utils/uhpfs/src/hpfsacl.cxx398
-rw-r--r--private/utils/uhpfs/src/hpfschk.cxx814
-rw-r--r--private/utils/uhpfs/src/hpfsea.cxx994
-rw-r--r--private/utils/uhpfs/src/hpfseal.cxx1811
-rw-r--r--private/utils/uhpfs/src/hpfsname.cxx1221
-rw-r--r--private/utils/uhpfs/src/hpfssa.cxx2201
-rw-r--r--private/utils/uhpfs/src/hpfsvol.cxx252
-rw-r--r--private/utils/uhpfs/src/makefile6
-rw-r--r--private/utils/uhpfs/src/makefile.inc14
-rw-r--r--private/utils/uhpfs/src/orphan.cxx1492
-rw-r--r--private/utils/uhpfs/src/pch.cxx50
-rw-r--r--private/utils/uhpfs/src/sid.cxx142
-rw-r--r--private/utils/uhpfs/src/sources98
-rw-r--r--private/utils/uhpfs/src/spareb.cxx530
-rw-r--r--private/utils/uhpfs/src/store.cxx1714
-rw-r--r--private/utils/uhpfs/src/superb.cxx327
-rw-r--r--private/utils/uhpfs/src/uhpfs.cxx202
-rw-r--r--private/utils/uhpfs/src/uhpfs.def10
-rw-r--r--private/utils/uhpfs/src/uhpfs.rc10
-rw-r--r--private/utils/ulib/dirs16
-rw-r--r--private/utils/ulib/inc/achkmsg.hxx164
-rw-r--r--private/utils/ulib/inc/arg.hxx1668
-rw-r--r--private/utils/ulib/inc/array.hxx390
-rw-r--r--private/utils/ulib/inc/arrayit.hxx125
-rw-r--r--private/utils/ulib/inc/basesys.hxx57
-rw-r--r--private/utils/ulib/inc/bitvect.hxx447
-rw-r--r--private/utils/ulib/inc/buffer.hxx183
-rw-r--r--private/utils/ulib/inc/bufstrm.hxx217
-rw-r--r--private/utils/ulib/inc/bytestrm.hxx169
-rw-r--r--private/utils/ulib/inc/clasdesc.hxx183
-rw-r--r--private/utils/ulib/inc/classes.xlsbin0 -> 11546 bytes
-rw-r--r--private/utils/ulib/inc/cmem.hxx66
-rw-r--r--private/utils/ulib/inc/comm.hxx564
-rw-r--r--private/utils/ulib/inc/contain.hxx95
-rw-r--r--private/utils/ulib/inc/cstring.h174
-rw-r--r--private/utils/ulib/inc/dir.hxx150
-rw-r--r--private/utils/ulib/inc/error.hxx392
-rw-r--r--private/utils/ulib/inc/file.hxx127
-rw-r--r--private/utils/ulib/inc/filestrm.hxx208
-rw-r--r--private/utils/ulib/inc/filter.hxx274
-rw-r--r--private/utils/ulib/inc/findleak.hxx47
-rw-r--r--private/utils/ulib/inc/fsnode.hxx1018
-rw-r--r--private/utils/ulib/inc/hmem.hxx152
-rw-r--r--private/utils/ulib/inc/ifsentry.hxx93
-rw-r--r--private/utils/ulib/inc/ifsserv.hxx109
-rw-r--r--private/utils/ulib/inc/iterator.hxx78
-rw-r--r--private/utils/ulib/inc/keyboard.hxx201
-rw-r--r--private/utils/ulib/inc/list.hxx115
-rw-r--r--private/utils/ulib/inc/listit.hxx118
-rw-r--r--private/utils/ulib/inc/machine.hxx77
-rw-r--r--private/utils/ulib/inc/mbstr.hxx434
-rw-r--r--private/utils/ulib/inc/mem.hxx50
-rw-r--r--private/utils/ulib/inc/membmgr.hxx258
-rw-r--r--private/utils/ulib/inc/message.hxx203
-rw-r--r--private/utils/ulib/inc/newdelp.hxx73
-rw-r--r--private/utils/ulib/inc/object.hxx343
-rw-r--r--private/utils/ulib/inc/path.hxx508
-rw-r--r--private/utils/ulib/inc/pipe.hxx121
-rw-r--r--private/utils/ulib/inc/pipestrm.hxx112
-rw-r--r--private/utils/ulib/inc/program.hxx146
-rw-r--r--private/utils/ulib/inc/prtstrm.hxx143
-rw-r--r--private/utils/ulib/inc/screen.hxx484
-rw-r--r--private/utils/ulib/inc/seqcnt.hxx83
-rw-r--r--private/utils/ulib/inc/smsg.hxx173
-rw-r--r--private/utils/ulib/inc/sortcnt.hxx79
-rw-r--r--private/utils/ulib/inc/sortlist.hxx153
-rw-r--r--private/utils/ulib/inc/sortlit.hxx98
-rw-r--r--private/utils/ulib/inc/spackmsg.hxx64
-rw-r--r--private/utils/ulib/inc/stack.hxx233
-rw-r--r--private/utils/ulib/inc/stream.hxx244
-rw-r--r--private/utils/ulib/inc/string.hxx464
-rw-r--r--private/utils/ulib/inc/stringar.hxx83
-rw-r--r--private/utils/ulib/inc/substrng.hxx632
-rw-r--r--private/utils/ulib/inc/system.hxx253
-rw-r--r--private/utils/ulib/inc/timeinfo.hxx631
-rw-r--r--private/utils/ulib/inc/ulib.hxx152
-rw-r--r--private/utils/ulib/inc/ulibcl.hxx40
-rw-r--r--private/utils/ulib/inc/ulibdef.hxx460
-rw-r--r--private/utils/ulib/inc/winnls.old292
-rw-r--r--private/utils/ulib/inc/wstring.hxx1250
-rw-r--r--private/utils/ulib/memtrace/makefile6
-rw-r--r--private/utils/ulib/memtrace/memtrace.c225
-rw-r--r--private/utils/ulib/memtrace/memtrace.def6
-rw-r--r--private/utils/ulib/memtrace/memtrace.h65
-rw-r--r--private/utils/ulib/memtrace/sources37
-rw-r--r--private/utils/ulib/src/achkmsg.cxx550
-rw-r--r--private/utils/ulib/src/arg.cxx2707
-rw-r--r--private/utils/ulib/src/array.cxx760
-rw-r--r--private/utils/ulib/src/arrayit.cxx261
-rw-r--r--private/utils/ulib/src/basesys.cxx249
-rw-r--r--private/utils/ulib/src/bitvect.cxx595
-rw-r--r--private/utils/ulib/src/buffer.cxx457
-rw-r--r--private/utils/ulib/src/bufstrm.cxx1041
-rw-r--r--private/utils/ulib/src/bytestrm.cxx189
-rw-r--r--private/utils/ulib/src/clasdesc.cxx124
-rw-r--r--private/utils/ulib/src/cmem.cxx107
-rw-r--r--private/utils/ulib/src/comm.cxx700
-rw-r--r--private/utils/ulib/src/contain.cxx38
-rw-r--r--private/utils/ulib/src/dir.cxx939
-rw-r--r--private/utils/ulib/src/error.cxx510
-rw-r--r--private/utils/ulib/src/file.cxx251
-rw-r--r--private/utils/ulib/src/filestrm.cxx937
-rw-r--r--private/utils/ulib/src/filter.cxx719
-rw-r--r--private/utils/ulib/src/fsnode.cxx459
-rw-r--r--private/utils/ulib/src/hmem.cxx247
-rw-r--r--private/utils/ulib/src/i386/dosttr.c76
-rw-r--r--private/utils/ulib/src/iterator.cxx63
-rw-r--r--private/utils/ulib/src/keyboard.cxx920
-rw-r--r--private/utils/ulib/src/list.cxx336
-rw-r--r--private/utils/ulib/src/listit.cxx45
-rw-r--r--private/utils/ulib/src/machine.cxx312
-rw-r--r--private/utils/ulib/src/makefile6
-rw-r--r--private/utils/ulib/src/makefile.inc4
-rw-r--r--private/utils/ulib/src/mbstr.cxx597
-rw-r--r--private/utils/ulib/src/mem.cxx8
-rw-r--r--private/utils/ulib/src/membmgr.cxx415
-rw-r--r--private/utils/ulib/src/message.cxx400
-rw-r--r--private/utils/ulib/src/newdel.cxx260
-rw-r--r--private/utils/ulib/src/object.cxx94
-rw-r--r--private/utils/ulib/src/path.cxx1449
-rw-r--r--private/utils/ulib/src/pch.cxx75
-rw-r--r--private/utils/ulib/src/pipe.cxx165
-rw-r--r--private/utils/ulib/src/pipestrm.cxx356
-rw-r--r--private/utils/ulib/src/prnthack.cxx16
-rw-r--r--private/utils/ulib/src/program.cxx453
-rw-r--r--private/utils/ulib/src/prtstrm.cxx392
-rw-r--r--private/utils/ulib/src/rtmsg.dbl387
-rw-r--r--private/utils/ulib/src/rtmsg.mc4851
-rw-r--r--private/utils/ulib/src/screen.cxx1998
-rw-r--r--private/utils/ulib/src/seqcnt.cxx82
-rw-r--r--private/utils/ulib/src/smsg.cxx607
-rw-r--r--private/utils/ulib/src/sortcnt.cxx37
-rw-r--r--private/utils/ulib/src/sortlist.cxx373
-rw-r--r--private/utils/ulib/src/sortlit.cxx316
-rw-r--r--private/utils/ulib/src/sources139
-rw-r--r--private/utils/ulib/src/spackmsg.cxx182
-rw-r--r--private/utils/ulib/src/stream.cxx512
-rw-r--r--private/utils/ulib/src/string.cxx84
-rw-r--r--private/utils/ulib/src/stringar.cxx210
-rw-r--r--private/utils/ulib/src/substrng.cxx1197
-rw-r--r--private/utils/ulib/src/system.cxx1339
-rw-r--r--private/utils/ulib/src/timeinfo.cxx1213
-rw-r--r--private/utils/ulib/src/ulib.cxx681
-rw-r--r--private/utils/ulib/src/ulib.rc10
-rw-r--r--private/utils/ulib/src/usa-ms.msg1588
-rw-r--r--private/utils/ulib/src/winnls.old183
-rw-r--r--private/utils/ulib/src/wstring.cxx1606
-rw-r--r--private/utils/untfs/dirs16
-rw-r--r--private/utils/untfs/inc/attrcol.hxx248
-rw-r--r--private/utils/untfs/inc/attrdef.hxx97
-rw-r--r--private/utils/untfs/inc/attrib.hxx1004
-rw-r--r--private/utils/untfs/inc/attrlist.hxx296
-rw-r--r--private/utils/untfs/inc/attrrec.hxx743
-rw-r--r--private/utils/untfs/inc/badfile.hxx128
-rw-r--r--private/utils/untfs/inc/bitfrs.hxx69
-rw-r--r--private/utils/untfs/inc/bootfile.hxx82
-rw-r--r--private/utils/untfs/inc/clusrun.hxx340
-rw-r--r--private/utils/untfs/inc/extents.hxx361
-rw-r--r--private/utils/untfs/inc/frs.hxx715
-rw-r--r--private/utils/untfs/inc/frsstruc.hxx912
-rw-r--r--private/utils/untfs/inc/fsrtlp.h273
-rw-r--r--private/utils/untfs/inc/hackwc.hxx34
-rw-r--r--private/utils/untfs/inc/indxbuff.hxx378
-rw-r--r--private/utils/untfs/inc/indxroot.hxx366
-rw-r--r--private/utils/untfs/inc/indxtree.hxx686
-rw-r--r--private/utils/untfs/inc/logfile.hxx160
-rw-r--r--private/utils/untfs/inc/mft.hxx487
-rw-r--r--private/utils/untfs/inc/mftfile.hxx265
-rw-r--r--private/utils/untfs/inc/mftref.hxx90
-rw-r--r--private/utils/untfs/inc/ntfsbit.hxx549
-rw-r--r--private/utils/untfs/inc/ntfssa.hxx1010
-rw-r--r--private/utils/untfs/inc/ntfsvol.hxx113
-rw-r--r--private/utils/untfs/inc/sdchk.hxx52
-rw-r--r--private/utils/untfs/inc/untfs.hxx1552
-rw-r--r--private/utils/untfs/inc/upcase.hxx275
-rw-r--r--private/utils/untfs/inc/upfile.hxx86
-rw-r--r--private/utils/untfs/src/attrcol.cxx201
-rw-r--r--private/utils/untfs/src/attrdef.cxx484
-rw-r--r--private/utils/untfs/src/attrib.cxx3533
-rw-r--r--private/utils/untfs/src/attrlist.cxx1952
-rw-r--r--private/utils/untfs/src/attrrec.cxx1465
-rw-r--r--private/utils/untfs/src/badfile.cxx596
-rw-r--r--private/utils/untfs/src/bitfrs.cxx219
-rw-r--r--private/utils/untfs/src/bootfile.cxx352
-rw-r--r--private/utils/untfs/src/clusrun.cxx174
-rw-r--r--private/utils/untfs/src/entry.cxx400
-rw-r--r--private/utils/untfs/src/extents.cxx1789
-rw-r--r--private/utils/untfs/src/format.cxx1402
-rw-r--r--private/utils/untfs/src/frs.cxx5708
-rw-r--r--private/utils/untfs/src/frsstruc.cxx1870
-rw-r--r--private/utils/untfs/src/hackwc.cxx82
-rw-r--r--private/utils/untfs/src/indxbuff.cxx841
-rw-r--r--private/utils/untfs/src/indxchk.cxx3741
-rw-r--r--private/utils/untfs/src/indxroot.cxx639
-rw-r--r--private/utils/untfs/src/indxtree.cxx4016
-rw-r--r--private/utils/untfs/src/largemcb.c2982
-rw-r--r--private/utils/untfs/src/logfile.cxx859
-rw-r--r--private/utils/untfs/src/makefile6
-rw-r--r--private/utils/untfs/src/makefile.inc14
-rw-r--r--private/utils/untfs/src/mft.cxx408
-rw-r--r--private/utils/untfs/src/mftfile.cxx743
-rw-r--r--private/utils/untfs/src/mftref.cxx392
-rw-r--r--private/utils/untfs/src/ntfsbit.cxx688
-rw-r--r--private/utils/untfs/src/ntfschk.cxx6408
-rw-r--r--private/utils/untfs/src/ntfssa.cxx1707
-rw-r--r--private/utils/untfs/src/ntfsvol.cxx527
-rw-r--r--private/utils/untfs/src/pch.cxx50
-rw-r--r--private/utils/untfs/src/sdchk.cxx1752
-rw-r--r--private/utils/untfs/src/sources101
-rw-r--r--private/utils/untfs/src/untfs.cxx175
-rw-r--r--private/utils/untfs/src/untfs.def12
-rw-r--r--private/utils/untfs/src/untfs.rc10
-rw-r--r--private/utils/untfs/src/upcase.cxx469
-rw-r--r--private/utils/untfs/src/upfile.cxx328
-rw-r--r--private/utils/ureg/dirs16
-rw-r--r--private/utils/ureg/inc/registry.hxx677
-rw-r--r--private/utils/ureg/inc/regkey.hxx816
-rw-r--r--private/utils/ureg/inc/regvalue.hxx394
-rw-r--r--private/utils/ureg/src/defalpha.dbg2
-rw-r--r--private/utils/ureg/src/defalpha.fre31
-rw-r--r--private/utils/ureg/src/defi386.dbg2
-rw-r--r--private/utils/ureg/src/defi386.fre32
-rw-r--r--private/utils/ureg/src/defmips.dbg2
-rw-r--r--private/utils/ureg/src/defmips.fre32
-rw-r--r--private/utils/ureg/src/defppc.dbg2
-rw-r--r--private/utils/ureg/src/defppc.fre32
-rw-r--r--private/utils/ureg/src/makefile6
-rw-r--r--private/utils/ureg/src/makefile.inc11
-rw-r--r--private/utils/ureg/src/registry.cxx5757
-rw-r--r--private/utils/ureg/src/regkey.cxx421
-rw-r--r--private/utils/ureg/src/regvalue.cxx358
-rw-r--r--private/utils/ureg/src/sources75
-rw-r--r--private/utils/ureg/src/ureg.cxx125
-rw-r--r--private/utils/ureg/src/ureg.rc10
-rw-r--r--private/utils/windisk/clear/clear.cxx105
-rw-r--r--private/utils/windisk/clear/makefile1
-rw-r--r--private/utils/windisk/clear/sources11
-rw-r--r--private/utils/windisk/controls/bmp.cxx219
-rw-r--r--private/utils/windisk/controls/bmppriv.hxx20
-rw-r--r--private/utils/windisk/controls/box.cxx186
-rw-r--r--private/utils/windisk/controls/boxpriv.hxx20
-rw-r--r--private/utils/windisk/controls/controls.cxx45
-rw-r--r--private/utils/windisk/controls/controls.hxx79
-rw-r--r--private/utils/windisk/controls/headers.hxx28
-rw-r--r--private/utils/windisk/controls/line.cxx159
-rw-r--r--private/utils/windisk/controls/linepriv.hxx20
-rw-r--r--private/utils/windisk/controls/makefile1
-rw-r--r--private/utils/windisk/controls/sources22
-rw-r--r--private/utils/windisk/debug/assert.cxx340
-rw-r--r--private/utils/windisk/debug/debug.h284
-rw-r--r--private/utils/windisk/debug/makefile9
-rw-r--r--private/utils/windisk/debug/sources12
-rw-r--r--private/utils/windisk/dirs33
-rw-r--r--private/utils/windisk/diskinfo/diskinfo.cxx273
-rw-r--r--private/utils/windisk/diskinfo/makefile1
-rw-r--r--private/utils/windisk/diskinfo/sources14
-rw-r--r--private/utils/windisk/doc/adskman.docbin0 -> 44990 bytes
-rw-r--r--private/utils/windisk/doc/adskman2.docbin0 -> 99840 bytes
-rw-r--r--private/utils/windisk/doc/demo.txt112
-rw-r--r--private/utils/windisk/doc/dlls.txt81
-rw-r--r--private/utils/windisk/doc/extend.txt24
-rw-r--r--private/utils/windisk/doc/misc.txt51
-rw-r--r--private/utils/windisk/doc/progmgmt.bmpbin0 -> 166518 bytes
-rw-r--r--private/utils/windisk/doc/select.txt75
-rw-r--r--private/utils/windisk/doc/testing.txt48
-rw-r--r--private/utils/windisk/doc/thecode.txt212
-rw-r--r--private/utils/windisk/doc/todo.txt104
-rw-r--r--private/utils/windisk/doc/wddev.docbin0 -> 53248 bytes
-rw-r--r--private/utils/windisk/doc/why.txt154
-rw-r--r--private/utils/windisk/doc/windisk.pptbin0 -> 13321 bytes
-rw-r--r--private/utils/windisk/hard/chard.cxx265
-rw-r--r--private/utils/windisk/hard/chardmnu.cxx271
-rw-r--r--private/utils/windisk/hard/dialogs.dlg8
-rw-r--r--private/utils/windisk/hard/dialogs.h3
-rw-r--r--private/utils/windisk/hard/global.hxx22
-rw-r--r--private/utils/windisk/hard/hard.cxx199
-rw-r--r--private/utils/windisk/hard/hard.def11
-rw-r--r--private/utils/windisk/hard/hard.hxx103
-rw-r--r--private/utils/windisk/hard/hard.rc28
-rw-r--r--private/utils/windisk/hard/hardmenu.cxx192
-rw-r--r--private/utils/windisk/hard/hardmenu.hxx104
-rw-r--r--private/utils/windisk/hard/headers.hxx19
-rw-r--r--private/utils/windisk/hard/libinit.cxx144
-rw-r--r--private/utils/windisk/hard/makefile1
-rw-r--r--private/utils/windisk/hard/makefile.inc6
-rw-r--r--private/utils/windisk/hard/sources40
-rw-r--r--private/utils/windisk/inc/dacommon.h80
-rw-r--r--private/utils/windisk/readme.txt4
-rw-r--r--private/utils/windisk/src/cdpage.cxx348
-rw-r--r--private/utils/windisk/src/cdpage.hxx76
-rw-r--r--private/utils/windisk/src/cdr.bmpbin0 -> 13918 bytes
-rw-r--r--private/utils/windisk/src/cdrom.cxx955
-rw-r--r--private/utils/windisk/src/cdrom.hxx65
-rw-r--r--private/utils/windisk/src/chkdsk.cxx2050
-rw-r--r--private/utils/windisk/src/chkdsk.hxx27
-rw-r--r--private/utils/windisk/src/cm.cxx888
-rw-r--r--private/utils/windisk/src/cm.hxx37
-rw-r--r--private/utils/windisk/src/commit.cxx1849
-rw-r--r--private/utils/windisk/src/commit.hxx101
-rw-r--r--private/utils/windisk/src/const.h146
-rw-r--r--private/utils/windisk/src/data.cxx288
-rw-r--r--private/utils/windisk/src/dblspace.cxx1662
-rw-r--r--private/utils/windisk/src/dblspace.dlg115
-rw-r--r--private/utils/windisk/src/dblspace.h91
-rw-r--r--private/utils/windisk/src/dblspace.hxx59
-rw-r--r--private/utils/windisk/src/dblspace.resbin0 -> 3092 bytes
-rw-r--r--private/utils/windisk/src/dialogs.dlg126
-rw-r--r--private/utils/windisk/src/dialogs.h263
-rw-r--r--private/utils/windisk/src/dialogs.resbin0 -> 3836 bytes
-rw-r--r--private/utils/windisk/src/dispinfo.cxx126
-rw-r--r--private/utils/windisk/src/dispinfo.hxx65
-rw-r--r--private/utils/windisk/src/dlgs.cxx1372
-rw-r--r--private/utils/windisk/src/dlgs.hxx88
-rw-r--r--private/utils/windisk/src/drives.cxx871
-rw-r--r--private/utils/windisk/src/drives.hxx88
-rw-r--r--private/utils/windisk/src/dskmgr.icobin0 -> 766 bytes
-rw-r--r--private/utils/windisk/src/engine.cxx4086
-rw-r--r--private/utils/windisk/src/engine.hxx311
-rw-r--r--private/utils/windisk/src/extend.cxx636
-rw-r--r--private/utils/windisk/src/extend.hxx87
-rw-r--r--private/utils/windisk/src/fill.cxx867
-rw-r--r--private/utils/windisk/src/fill.hxx24
-rw-r--r--private/utils/windisk/src/fmifs.cxx644
-rw-r--r--private/utils/windisk/src/fmifs.hxx183
-rw-r--r--private/utils/windisk/src/format.cxx65
-rw-r--r--private/utils/windisk/src/format.hxx38
-rw-r--r--private/utils/windisk/src/fs.cxx96
-rw-r--r--private/utils/windisk/src/fs.hxx93
-rw-r--r--private/utils/windisk/src/ft.cxx1685
-rw-r--r--private/utils/windisk/src/ft.hxx67
-rw-r--r--private/utils/windisk/src/ftreg.cxx1329
-rw-r--r--private/utils/windisk/src/ftreg.dlg22
-rw-r--r--private/utils/windisk/src/ftreg.h22
-rw-r--r--private/utils/windisk/src/ftreg.hxx34
-rw-r--r--private/utils/windisk/src/genlpage.cxx726
-rw-r--r--private/utils/windisk/src/genlpage.hxx98
-rw-r--r--private/utils/windisk/src/global.hxx233
-rw-r--r--private/utils/windisk/src/graph.cxx793
-rw-r--r--private/utils/windisk/src/graph.hxx32
-rw-r--r--private/utils/windisk/src/hard.bmpbin0 -> 13918 bytes
-rw-r--r--private/utils/windisk/src/headers.hxx95
-rw-r--r--private/utils/windisk/src/help.cxx312
-rw-r--r--private/utils/windisk/src/help.hxx45
-rw-r--r--private/utils/windisk/src/help2.cxx506
-rw-r--r--private/utils/windisk/src/help2.hxx39
-rw-r--r--private/utils/windisk/src/helpid.h220
-rw-r--r--private/utils/windisk/src/init.cxx949
-rw-r--r--private/utils/windisk/src/init.hxx32
-rw-r--r--private/utils/windisk/src/label.cxx216
-rw-r--r--private/utils/windisk/src/label.hxx22
-rw-r--r--private/utils/windisk/src/listbox.cxx1113
-rw-r--r--private/utils/windisk/src/listbox.hxx85
-rw-r--r--private/utils/windisk/src/log.cxx1289
-rw-r--r--private/utils/windisk/src/makefile1
-rw-r--r--private/utils/windisk/src/makefile.inc24
-rw-r--r--private/utils/windisk/src/mem.cxx92
-rw-r--r--private/utils/windisk/src/mem.hxx38
-rw-r--r--private/utils/windisk/src/menudict.cxx201
-rw-r--r--private/utils/windisk/src/menudict.hxx113
-rw-r--r--private/utils/windisk/src/messages.mc617
-rw-r--r--private/utils/windisk/src/misc.cxx1404
-rw-r--r--private/utils/windisk/src/network.cxx184
-rw-r--r--private/utils/windisk/src/network.hxx33
-rw-r--r--private/utils/windisk/src/nt.cxx1187
-rw-r--r--private/utils/windisk/src/nt.hxx115
-rw-r--r--private/utils/windisk/src/ntlow.cxx1134
-rw-r--r--private/utils/windisk/src/ntlow.hxx134
-rw-r--r--private/utils/windisk/src/oleclass.cxx84
-rw-r--r--private/utils/windisk/src/oleclass.hxx29
-rw-r--r--private/utils/windisk/src/ops.cxx2823
-rw-r--r--private/utils/windisk/src/ops.hxx114
-rw-r--r--private/utils/windisk/src/popup.cxx96
-rw-r--r--private/utils/windisk/src/popup.hxx29
-rw-r--r--private/utils/windisk/src/print.cxx338
-rw-r--r--private/utils/windisk/src/print.hxx23
-rw-r--r--private/utils/windisk/src/profile.cxx598
-rw-r--r--private/utils/windisk/src/profile.hxx32
-rw-r--r--private/utils/windisk/src/proto.hxx468
-rw-r--r--private/utils/windisk/src/ps.cxx205
-rw-r--r--private/utils/windisk/src/ps.hxx22
-rw-r--r--private/utils/windisk/src/rect.cxx310
-rw-r--r--private/utils/windisk/src/rectpriv.hxx50
-rw-r--r--private/utils/windisk/src/resids.h514
-rw-r--r--private/utils/windisk/src/rmdisk.bmpbin0 -> 190 bytes
-rw-r--r--private/utils/windisk/src/scdrom.icobin0 -> 318 bytes
-rw-r--r--private/utils/windisk/src/scsi.h77
-rw-r--r--private/utils/windisk/src/select.cxx1845
-rw-r--r--private/utils/windisk/src/select.hxx108
-rw-r--r--private/utils/windisk/src/shard.icobin0 -> 318 bytes
-rw-r--r--private/utils/windisk/src/smcdrom.bmpbin0 -> 190 bytes
-rw-r--r--private/utils/windisk/src/smdisk.bmpbin0 -> 190 bytes
-rw-r--r--private/utils/windisk/src/sources79
-rw-r--r--private/utils/windisk/src/stleg.cxx534
-rw-r--r--private/utils/windisk/src/stleg.hxx50
-rw-r--r--private/utils/windisk/src/tb.h129
-rw-r--r--private/utils/windisk/src/tbar.cxx701
-rw-r--r--private/utils/windisk/src/tbar.hxx52
-rw-r--r--private/utils/windisk/src/tool16.bmpbin0 -> 1910 bytes
-rw-r--r--private/utils/windisk/src/trffc14.icobin0 -> 766 bytes
-rw-r--r--private/utils/windisk/src/types.hxx489
-rw-r--r--private/utils/windisk/src/unused/startup.cxx166
-rw-r--r--private/utils/windisk/src/unused/startup.hxx27
-rw-r--r--private/utils/windisk/src/unused/time.cxx599
-rw-r--r--private/utils/windisk/src/unused/time.hxx39
-rw-r--r--private/utils/windisk/src/volview.cxx400
-rw-r--r--private/utils/windisk/src/volview.hxx36
-rw-r--r--private/utils/windisk/src/windisk.cxx5753
-rw-r--r--private/utils/windisk/src/windisk.hxx140
-rw-r--r--private/utils/windisk/src/windisk.rc563
-rw-r--r--private/utils/windisk/src/xtra16.bmpbin0 -> 630 bytes
-rw-r--r--private/utils/windisk/types/daexts.idl233
-rw-r--r--private/utils/windisk/types/dahard.idl39
-rw-r--r--private/utils/windisk/types/damenu.idl42
-rw-r--r--private/utils/windisk/types/davol.idl39
-rw-r--r--private/utils/windisk/types/guids.h24
-rw-r--r--private/utils/windisk/types/readme.txt2
-rw-r--r--private/utils/windisk/util/debug.cxx95
-rw-r--r--private/utils/windisk/util/headers.hxx32
-rw-r--r--private/utils/windisk/util/makefile1
-rw-r--r--private/utils/windisk/util/sources17
-rw-r--r--private/utils/windisk/util/util.cxx427
-rw-r--r--private/utils/windisk/util/util.hxx100
-rw-r--r--private/utils/windisk/windisk.mk9
-rw-r--r--private/utils/wizards/addgrpw/exgrp.cpp315
-rw-r--r--private/utils/wizards/addgrpw/exgrp.h60
-rw-r--r--private/utils/wizards/addgrpw/finish.cpp541
-rw-r--r--private/utils/wizards/addgrpw/finish.h57
-rw-r--r--private/utils/wizards/addgrpw/gusers.cpp407
-rw-r--r--private/utils/wizards/addgrpw/gusers.h63
-rw-r--r--private/utils/wizards/addgrpw/lrem.cpp138
-rw-r--r--private/utils/wizards/addgrpw/lrem.h54
-rw-r--r--private/utils/wizards/addgrpw/lusers.cpp632
-rw-r--r--private/utils/wizards/addgrpw/lusers.h72
-rw-r--r--private/utils/wizards/addgrpw/makefile6
-rw-r--r--private/utils/wizards/addgrpw/nettree.cpp578
-rw-r--r--private/utils/wizards/addgrpw/nettree.h94
-rw-r--r--private/utils/wizards/addgrpw/res/endflag.bmpbin0 -> 13678 bytes
-rw-r--r--private/utils/wizards/addgrpw/res/global.bmpbin0 -> 1386 bytes
-rw-r--r--private/utils/wizards/addgrpw/res/group.bmpbin0 -> 328 bytes
-rw-r--r--private/utils/wizards/addgrpw/res/groupb.bmpbin0 -> 13618 bytes
-rw-r--r--private/utils/wizards/addgrpw/res/luser.bmpbin0 -> 328 bytes
-rw-r--r--private/utils/wizards/addgrpw/res/net_tree.bmpbin0 -> 544 bytes
-rw-r--r--private/utils/wizards/addgrpw/res/romaine.icobin0 -> 1078 bytes
-rw-r--r--private/utils/wizards/addgrpw/res/romaine.rc226
-rw-r--r--private/utils/wizards/addgrpw/res/user.bmpbin0 -> 334 bytes
-rw-r--r--private/utils/wizards/addgrpw/res/world.bmpbin0 -> 344 bytes
-rw-r--r--private/utils/wizards/addgrpw/resource.h106
-rw-r--r--private/utils/wizards/addgrpw/romaine.cpp294
-rw-r--r--private/utils/wizards/addgrpw/romaine.h125
-rw-r--r--private/utils/wizards/addgrpw/romaine.rc423
-rw-r--r--private/utils/wizards/addgrpw/sources62
-rw-r--r--private/utils/wizards/addgrpw/stdafx.cpp20
-rw-r--r--private/utils/wizards/addgrpw/stdafx.h39
-rw-r--r--private/utils/wizards/addgrpw/transbmp.cpp175
-rw-r--r--private/utils/wizards/addgrpw/transbmp.h40
-rw-r--r--private/utils/wizards/addgrpw/trstlist.cpp414
-rw-r--r--private/utils/wizards/addgrpw/trstlist.h52
-rw-r--r--private/utils/wizards/addgrpw/type.cpp67
-rw-r--r--private/utils/wizards/addgrpw/type.h50
-rw-r--r--private/utils/wizards/addgrpw/userlist.cpp250
-rw-r--r--private/utils/wizards/addgrpw/userlist.h59
-rw-r--r--private/utils/wizards/addgrpw/welcome.cpp107
-rw-r--r--private/utils/wizards/addgrpw/welcome.h54
-rw-r--r--private/utils/wizards/addgrpw/what.cpp124
-rw-r--r--private/utils/wizards/addgrpw/what.h53
-rw-r--r--private/utils/wizards/addgrpw/where.cpp298
-rw-r--r--private/utils/wizards/addgrpw/where.h56
-rw-r--r--private/utils/wizards/addusrw/accexp.cpp330
-rw-r--r--private/utils/wizards/addusrw/accexp.h102
-rw-r--r--private/utils/wizards/addusrw/dapi.h1322
-rw-r--r--private/utils/wizards/addusrw/exch.cpp177
-rw-r--r--private/utils/wizards/addusrw/exch.h57
-rw-r--r--private/utils/wizards/addusrw/finish.cpp794
-rw-r--r--private/utils/wizards/addusrw/finish.h81
-rw-r--r--private/utils/wizards/addusrw/fpinfo.cpp179
-rw-r--r--private/utils/wizards/addusrw/fpinfo.h65
-rw-r--r--private/utils/wizards/addusrw/fpnwcomm.h307
-rw-r--r--private/utils/wizards/addusrw/ginfo.cpp339
-rw-r--r--private/utils/wizards/addusrw/ginfo.h65
-rw-r--r--private/utils/wizards/addusrw/homedir.cpp245
-rw-r--r--private/utils/wizards/addusrw/homedir.h61
-rw-r--r--private/utils/wizards/addusrw/hours.cpp165
-rw-r--r--private/utils/wizards/addusrw/hours.h93
-rw-r--r--private/utils/wizards/addusrw/hours1.cpp55
-rw-r--r--private/utils/wizards/addusrw/hours1.h50
-rw-r--r--private/utils/wizards/addusrw/limit.cpp276
-rw-r--r--private/utils/wizards/addusrw/limit.h94
-rw-r--r--private/utils/wizards/addusrw/lscript.cpp83
-rw-r--r--private/utils/wizards/addusrw/lscript.h52
-rw-r--r--private/utils/wizards/addusrw/makefile6
-rw-r--r--private/utils/wizards/addusrw/nwlim.cpp312
-rw-r--r--private/utils/wizards/addusrw/nwlim.h92
-rw-r--r--private/utils/wizards/addusrw/nwwks.cpp159
-rw-r--r--private/utils/wizards/addusrw/nwwks.h51
-rw-r--r--private/utils/wizards/addusrw/optdlg.cpp167
-rw-r--r--private/utils/wizards/addusrw/optdlg.h59
-rw-r--r--private/utils/wizards/addusrw/profile.cpp105
-rw-r--r--private/utils/wizards/addusrw/profile.h52
-rw-r--r--private/utils/wizards/addusrw/prsinfo.cpp162
-rw-r--r--private/utils/wizards/addusrw/prsinfo.h54
-rw-r--r--private/utils/wizards/addusrw/pwinfo.cpp207
-rw-r--r--private/utils/wizards/addusrw/pwinfo.h56
-rw-r--r--private/utils/wizards/addusrw/rasperm.cpp155
-rw-r--r--private/utils/wizards/addusrw/rasperm.h58
-rw-r--r--private/utils/wizards/addusrw/res/bitmap1.bmpbin0 -> 13680 bytes
-rw-r--r--private/utils/wizards/addusrw/res/endflag.bmpbin0 -> 13678 bytes
-rw-r--r--private/utils/wizards/addusrw/res/global.bmpbin0 -> 1386 bytes
-rw-r--r--private/utils/wizards/addusrw/res/global_g.bmpbin0 -> 1386 bytes
-rw-r--r--private/utils/wizards/addusrw/res/group.bmpbin0 -> 328 bytes
-rw-r--r--private/utils/wizards/addusrw/res/net_tree.bmpbin0 -> 544 bytes
-rw-r--r--private/utils/wizards/addusrw/res/speckle.icobin0 -> 1078 bytes
-rw-r--r--private/utils/wizards/addusrw/res/speckle.rc226
-rw-r--r--private/utils/wizards/addusrw/res/user.bmpbin0 -> 334 bytes
-rw-r--r--private/utils/wizards/addusrw/res/user_bit.bmpbin0 -> 334 bytes
-rw-r--r--private/utils/wizards/addusrw/res/world.bmpbin0 -> 344 bytes
-rw-r--r--private/utils/wizards/addusrw/resource.h244
-rw-r--r--private/utils/wizards/addusrw/restrct.cpp190
-rw-r--r--private/utils/wizards/addusrw/restrct.h63
-rw-r--r--private/utils/wizards/addusrw/rpcbak.h225
-rw-r--r--private/utils/wizards/addusrw/rpcpub.h387
-rw-r--r--private/utils/wizards/addusrw/sadapi.h197
-rw-r--r--private/utils/wizards/addusrw/sources75
-rw-r--r--private/utils/wizards/addusrw/speckle.cpp262
-rw-r--r--private/utils/wizards/addusrw/speckle.h176
-rw-r--r--private/utils/wizards/addusrw/speckle.rc766
-rw-r--r--private/utils/wizards/addusrw/stdafx.cpp6
-rw-r--r--private/utils/wizards/addusrw/stdafx.h32
-rw-r--r--private/utils/wizards/addusrw/timelist.cpp92
-rw-r--r--private/utils/wizards/addusrw/timelist.h53
-rw-r--r--private/utils/wizards/addusrw/transbmp.cpp175
-rw-r--r--private/utils/wizards/addusrw/transbmp.h42
-rw-r--r--private/utils/wizards/addusrw/trstlist.cpp414
-rw-r--r--private/utils/wizards/addusrw/trstlist.h56
-rw-r--r--private/utils/wizards/addusrw/userlist.cpp216
-rw-r--r--private/utils/wizards/addusrw/userlist.h61
-rw-r--r--private/utils/wizards/addusrw/welcome.cpp576
-rw-r--r--private/utils/wizards/addusrw/welcome.h62
-rw-r--r--private/utils/wizards/addusrw/wizbased.cpp68
-rw-r--r--private/utils/wizards/addusrw/wizbased.h57
-rw-r--r--private/utils/wizards/dirs21
-rw-r--r--private/utils/wizards/hoursctl/hours.cpp90
-rw-r--r--private/utils/wizards/hoursctl/hours.def9
-rw-r--r--private/utils/wizards/hoursctl/hours.h35
-rw-r--r--private/utils/wizards/hoursctl/hours.rc138
-rw-r--r--private/utils/wizards/hoursctl/hours.tlbbin0 -> 2471 bytes
-rw-r--r--private/utils/wizards/hoursctl/hoursctl.bmpbin0 -> 238 bytes
-rw-r--r--private/utils/wizards/hoursctl/hoursctl.cpp1047
-rw-r--r--private/utils/wizards/hoursctl/hoursctl.h118
-rw-r--r--private/utils/wizards/hoursctl/hoursppg.cpp82
-rw-r--r--private/utils/wizards/hoursctl/hoursppg.h42
-rw-r--r--private/utils/wizards/hoursctl/makefile6
-rw-r--r--private/utils/wizards/hoursctl/resource.h27
-rw-r--r--private/utils/wizards/hoursctl/sources50
-rw-r--r--private/utils/wizards/hoursctl/stdafx.cpp18
-rw-r--r--private/utils/wizards/hoursctl/stdafx.h22
-rw-r--r--private/utils/wizards/liccomp/finpic.cpp46
-rw-r--r--private/utils/wizards/liccomp/finpic.h37
-rw-r--r--private/utils/wizards/liccomp/lcwiz.cpp255
-rw-r--r--private/utils/wizards/liccomp/lcwiz.h82
-rw-r--r--private/utils/wizards/liccomp/lcwiz.rc271
-rw-r--r--private/utils/wizards/liccomp/lcwizpgs.cpp1070
-rw-r--r--private/utils/wizards/liccomp/lcwizpgs.h208
-rw-r--r--private/utils/wizards/liccomp/lcwizsht.cpp59
-rw-r--r--private/utils/wizards/liccomp/lcwizsht.h56
-rw-r--r--private/utils/wizards/liccomp/llsapi.h1034
-rw-r--r--private/utils/wizards/liccomp/makefile6
-rw-r--r--private/utils/wizards/liccomp/nettree.cpp595
-rw-r--r--private/utils/wizards/liccomp/nettree.h77
-rw-r--r--private/utils/wizards/liccomp/res/endflag.bmpbin0 -> 13678 bytes
-rw-r--r--private/utils/wizards/liccomp/res/lcwiz.icobin0 -> 1078 bytes
-rw-r--r--private/utils/wizards/liccomp/res/lcwiz.rc213
-rw-r--r--private/utils/wizards/liccomp/res/liccomp.bmpbin0 -> 13678 bytes
-rw-r--r--private/utils/wizards/liccomp/res/net_tree.bmpbin0 -> 478 bytes
-rw-r--r--private/utils/wizards/liccomp/resource.h84
-rw-r--r--private/utils/wizards/liccomp/sources56
-rw-r--r--private/utils/wizards/liccomp/stdafx.cpp6
-rw-r--r--private/utils/wizards/liccomp/stdafx.h27
-rw-r--r--private/utils/wizards/liccomp/transbmp.cpp161
-rw-r--r--private/utils/wizards/liccomp/transbmp.h28
-rw-r--r--private/utils/wizards/shrpub/dirtree.cpp261
-rw-r--r--private/utils/wizards/shrpub/dirtree.h59
-rw-r--r--private/utils/wizards/shrpub/finish.cpp187
-rw-r--r--private/utils/wizards/shrpub/finish.h55
-rw-r--r--private/utils/wizards/shrpub/fpnwapi.h349
-rw-r--r--private/utils/wizards/shrpub/howtoshd.cpp283
-rw-r--r--private/utils/wizards/shrpub/howtoshd.h60
-rw-r--r--private/utils/wizards/shrpub/macfile.h908
-rw-r--r--private/utils/wizards/shrpub/makefile6
-rw-r--r--private/utils/wizards/shrpub/nettree.cpp578
-rw-r--r--private/utils/wizards/shrpub/nettree.h92
-rw-r--r--private/utils/wizards/shrpub/permtype.cpp654
-rw-r--r--private/utils/wizards/shrpub/permtype.h86
-rw-r--r--private/utils/wizards/shrpub/res/bitmap1.bmpbin0 -> 1682 bytes
-rw-r--r--private/utils/wizards/shrpub/res/bitmap3.bmpbin0 -> 1126 bytes
-rw-r--r--private/utils/wizards/shrpub/res/endflag.bmpbin0 -> 13678 bytes
-rw-r--r--private/utils/wizards/shrpub/res/global.bmpbin0 -> 1386 bytes
-rw-r--r--private/utils/wizards/shrpub/res/group.bmpbin0 -> 328 bytes
-rw-r--r--private/utils/wizards/shrpub/res/image_li.bmpbin0 -> 1198 bytes
-rw-r--r--private/utils/wizards/shrpub/res/interac.bmpbin0 -> 328 bytes
-rw-r--r--private/utils/wizards/shrpub/res/net_tree.bmpbin0 -> 564 bytes
-rw-r--r--private/utils/wizards/shrpub/res/network.bmpbin0 -> 292 bytes
-rw-r--r--private/utils/wizards/shrpub/res/server.bmpbin0 -> 246 bytes
-rw-r--r--private/utils/wizards/shrpub/res/shrpub.bmpbin0 -> 16914 bytes
-rw-r--r--private/utils/wizards/shrpub/res/system.bmpbin0 -> 324 bytes
-rw-r--r--private/utils/wizards/shrpub/res/turtle.icobin0 -> 1078 bytes
-rw-r--r--private/utils/wizards/shrpub/res/turtle.rc226
-rw-r--r--private/utils/wizards/shrpub/res/user.bmpbin0 -> 334 bytes
-rw-r--r--private/utils/wizards/shrpub/res/world.bmpbin0 -> 344 bytes
-rw-r--r--private/utils/wizards/shrpub/resource.h279
-rw-r--r--private/utils/wizards/shrpub/shtree.h58
-rw-r--r--private/utils/wizards/shrpub/sources60
-rw-r--r--private/utils/wizards/shrpub/stdafx.cpp19
-rw-r--r--private/utils/wizards/shrpub/stdafx.h38
-rw-r--r--private/utils/wizards/shrpub/transbmp.cpp175
-rw-r--r--private/utils/wizards/shrpub/transbmp.h40
-rw-r--r--private/utils/wizards/shrpub/turtle.cpp995
-rw-r--r--private/utils/wizards/shrpub/turtle.h190
-rw-r--r--private/utils/wizards/shrpub/turtle.rc492
-rw-r--r--private/utils/wizards/shrpub/wait.cpp77
-rw-r--r--private/utils/wizards/shrpub/wait.h48
-rw-r--r--private/utils/wizards/shrpub/welcomed.cpp116
-rw-r--r--private/utils/wizards/shrpub/welcomed.h55
-rw-r--r--private/utils/wizards/shrpub/whattosh.cpp788
-rw-r--r--private/utils/wizards/shrpub/whattosh.h76
-rw-r--r--private/utils/wizards/shrpub/where.cpp274
-rw-r--r--private/utils/wizards/shrpub/where.h56
-rw-r--r--private/utils/wizards/shrpub/wizbased.cpp419
-rw-r--r--private/utils/wizards/shrpub/wizbased.h63
-rw-r--r--private/utils/wizards/wizmgr/listdata.h27
-rw-r--r--private/utils/wizards/wizmgr/makefile6
-rw-r--r--private/utils/wizards/wizmgr/mustard.cpp108
-rw-r--r--private/utils/wizards/wizmgr/mustard.h47
-rw-r--r--private/utils/wizards/wizmgr/mustard.rc208
-rw-r--r--private/utils/wizards/wizmgr/res/bitmap1.bmpbin0 -> 630 bytes
-rw-r--r--private/utils/wizards/wizmgr/res/bitmap2.bmpbin0 -> 1270 bytes
-rw-r--r--private/utils/wizards/wizmgr/res/mustard.icobin0 -> 1078 bytes
-rw-r--r--private/utils/wizards/wizmgr/res/mustard.rc227
-rw-r--r--private/utils/wizards/wizmgr/resource.h59
-rw-r--r--private/utils/wizards/wizmgr/sources42
-rw-r--r--private/utils/wizards/wizmgr/startd.cpp759
-rw-r--r--private/utils/wizards/wizmgr/startd.h95
-rw-r--r--private/utils/wizards/wizmgr/stdafx.cpp20
-rw-r--r--private/utils/wizards/wizmgr/stdafx.h30
-rw-r--r--private/utils/wizards/wizmgr/wizlist.cpp535
-rw-r--r--private/utils/wizards/wizmgr/wizlist.h71
-rw-r--r--private/utils/xcopy/argument.cxx875
-rw-r--r--private/utils/xcopy/makefile6
-rw-r--r--private/utils/xcopy/sources83
-rw-r--r--private/utils/xcopy/support.cxx183
-rw-r--r--private/utils/xcopy/xcopy.cxx2324
-rw-r--r--private/utils/xcopy/xcopy.hxx353
-rw-r--r--private/utils/xcopy/xcopy.rc11
2154 files changed, 758572 insertions, 0 deletions
diff --git a/private/utils/aclconv/acehelp.cxx b/private/utils/aclconv/acehelp.cxx
new file mode 100644
index 000000000..ad7f43363
--- /dev/null
+++ b/private/utils/aclconv/acehelp.cxx
@@ -0,0 +1,431 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ acehelp.hxx
+
+Abstract:
+
+ This module contains definitions for helper routines for
+ manipulating ACE's.
+
+
+Author:
+
+ Bill McJohn (billmc) 09-Feb-1992
+
+Revision History:
+
+
+--*/
+
+extern "C" {
+
+ #include <nt.h>
+ #include <ntrtl.h>
+ #include <nturtl.h>
+ #include <ntseapi.h>
+ #include <windows.h>
+}
+
+
+#include "lmconst.hxx"
+#include "acehelp.hxx"
+
+VOID
+ConvertAccessMasks(
+ IN USHORT LanmanAccess,
+ OUT PACCESS_MASK DirMask,
+ OUT PACCESS_MASK FileMask
+ )
+/*++
+
+Routine Description:
+
+ This method constructs NT Access Masks that correspond to a
+ Lanman 2.x access mask.
+
+Arguments:
+
+ LanmanAccess -- Supplies the Lanman 2.x access mask.
+ DirMask -- Receives the corresponding access mask for
+ a directory object.
+ FileMask -- Receives the corresponding access mask for
+ a file object.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ register ACCESS_MASK DirResult, FileResult;
+
+ if( (LanmanAccess & ~LM_ACCESS_GROUP) == LM_ACCESS_ALL ) {
+
+ // This access mask grants all possible permissions.
+
+ DirResult = GENERIC_ALL;
+ FileResult = GENERIC_ALL;
+
+ } else {
+
+ // Check each of the possible bits.
+
+ DirResult = 0;
+ FileResult = 0;
+
+
+ if( LanmanAccess & LM_ACCESS_READ ) {
+
+ DirResult |= GENERIC_READ;
+ FileResult |= GENERIC_READ;
+ }
+
+ if( LanmanAccess & LM_ACCESS_WRITE ) {
+
+ DirResult |= GENERIC_WRITE;
+ FileResult |= GENERIC_WRITE;
+ }
+
+ if( LanmanAccess & LM_ACCESS_CREATE ) {
+
+ DirResult |= (GENERIC_WRITE | GENERIC_EXECUTE);
+ }
+
+ if( LanmanAccess & LM_ACCESS_EXEC ) {
+
+ DirResult |= GENERIC_EXECUTE;
+ FileResult |= GENERIC_EXECUTE;
+ }
+
+ if( LanmanAccess & LM_ACCESS_DELETE ) {
+
+ DirResult |= DELETE;
+ FileResult |= DELETE;
+ }
+
+ if( LanmanAccess & LM_ACCESS_ATRIB ) {
+
+ DirResult |= FILE_WRITE_ATTRIBUTES;
+ FileResult |= FILE_WRITE_ATTRIBUTES;
+ }
+
+ if( LanmanAccess & LM_ACCESS_PERM ) {
+
+ DirResult |= (WRITE_DAC | WRITE_OWNER);
+ FileResult |= (WRITE_DAC | WRITE_OWNER);
+ }
+ }
+
+ *DirMask = DirResult;
+ *FileMask = FileResult;
+}
+
+VOID
+ConvertAuditBits(
+ IN USHORT LmAuditBits,
+ OUT PACCESS_MASK DirSuccessfulMask,
+ OUT PACCESS_MASK DirFailedMask,
+ OUT PACCESS_MASK FileSuccessfulMask,
+ OUT PACCESS_MASK FileFailedMask
+ )
+/*++
+
+Routine Description:
+
+ This function constructs NT access masks that correspond to
+ Lanman 2.x Audit bitmasks.
+
+Arguments:
+
+ LmAuditBits -- Supplies the Lanman 2.x audit bitmask
+ DirSuccessfulMask -- Receives the corresponding NT access mask
+ for auditing successful directory accesses.
+ DirFailedMask -- Receives the corresponding NT access mask
+ for auditing failed directory accesses.
+ FileSuccessfulMask -- Receives the corresponding NT access mask
+ for auditing successful file accesses.
+ FileFailedMask -- Receives the corresponding NT access mask
+ for auditing failed file accesses.
+Return Value:
+
+ None.
+
+--*/
+{
+ ACCESS_MASK DirFailedResult, DirSuccessfulResult,
+ FileFailedResult, FileSuccessfulResult;
+
+ // If the 'all' bit is set, this conversion is easy:
+
+ if( LmAuditBits & LM_AUDIT_ALL ) {
+
+ *DirSuccessfulMask = GENERIC_ALL;
+ *DirFailedMask = GENERIC_ALL;
+ *FileSuccessfulMask = GENERIC_ALL;
+ *FileFailedMask = GENERIC_ALL;
+
+ return;
+ }
+
+
+ // Compute the audit mask for successful directory access:
+ //
+ DirSuccessfulResult = 0;
+ if( LmAuditBits & LM_AUDIT_S_CREATE ) DirSuccessfulResult |= (FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE);
+ if( LmAuditBits & LM_AUDIT_S_DELETE ) DirSuccessfulResult |= DELETE;
+ if( LmAuditBits & LM_AUDIT_S_ACL ) DirSuccessfulResult |= (WRITE_DAC | WRITE_OWNER);
+
+ // Compute the audit mask for failed directory access:
+ //
+ DirFailedResult = 0;
+ if( LmAuditBits & LM_AUDIT_F_CREATE ) DirFailedResult |= (FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE);
+ if( LmAuditBits & LM_AUDIT_F_DELETE ) DirFailedResult |= DELETE;
+ if( LmAuditBits & LM_AUDIT_F_ACL ) DirFailedResult |= (WRITE_DAC | WRITE_OWNER);
+
+ // Compute the audit mask for successful file access:
+ //
+ FileSuccessfulResult = 0;
+ if( LmAuditBits & LM_AUDIT_S_OPEN ) FileSuccessfulResult |= GENERIC_READ;
+ if( LmAuditBits & LM_AUDIT_S_WRITE ) FileSuccessfulResult |= GENERIC_WRITE;
+ if( LmAuditBits & LM_AUDIT_S_DELETE ) FileSuccessfulResult |= DELETE;
+ if( LmAuditBits & LM_AUDIT_S_ACL ) FileSuccessfulResult |= (WRITE_DAC | WRITE_OWNER);
+
+ // Compute the audit mask for failed file access:
+ //
+ FileFailedResult = 0;
+ if( LmAuditBits & LM_AUDIT_F_OPEN ) FileFailedResult |= GENERIC_READ;
+ if( LmAuditBits & LM_AUDIT_F_WRITE ) FileFailedResult |= GENERIC_WRITE;
+ if( LmAuditBits & LM_AUDIT_F_DELETE ) FileFailedResult |= DELETE;
+ if( LmAuditBits & LM_AUDIT_F_ACL ) FileFailedResult |= (WRITE_DAC | WRITE_OWNER);
+
+
+ // Fill in the return values:
+
+ *DirSuccessfulMask = DirSuccessfulResult;
+ *DirFailedMask = DirFailedResult;
+ *FileSuccessfulMask = FileSuccessfulResult;
+ *FileFailedMask = FileFailedResult;
+
+ return;
+}
+
+
+
+
+BOOLEAN
+CreateAccessAllowedAce(
+ IN OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ IN ACCESS_MASK Access,
+ IN UCHAR InheritFlags,
+ IN PSID Sid,
+ OUT PULONG AceLength
+ )
+/*++
+
+Routine Description:
+
+ This method creates an access-allowed ACE in the supplied buffer.
+
+Arguments:
+
+ Buffer -- Supplies the buffer in which the ACE should be
+ created.
+ BufferLength -- Supplies the length of the buffer.
+ Access -- Supplies the desired Access Mask.
+ InheritFlags -- Supplies the ACE's inherit flags.
+ Sid -- Supplies the ACE's SID.
+ AceLength -- Receives the length of the created ACE.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ PACCESS_ALLOWED_ACE NewAce;
+ ULONG SidLength;
+
+ SidLength = GetLengthSid( Sid );
+
+ *AceLength = sizeof( ACE_HEADER ) +
+ sizeof( ACCESS_MASK ) +
+ SidLength;
+
+ if( *AceLength > BufferLength ) {
+
+ return FALSE;
+ }
+
+
+ NewAce = (PACCESS_ALLOWED_ACE)Buffer;
+
+ NewAce->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
+ NewAce->Header.AceSize = (USHORT)*AceLength;
+ NewAce->Header.AceFlags = InheritFlags;
+
+ NewAce->Mask = Access;
+
+ return( CopySid( SidLength,
+ (PSID)((PBYTE)Buffer + sizeof( ACE_HEADER ) +
+ sizeof( ACCESS_MASK )),
+ Sid ) );
+}
+
+
+
+
+BOOLEAN
+CreateAccessDeniedAce(
+ IN OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ IN ACCESS_MASK Access,
+ IN UCHAR InheritFlags,
+ IN PSID Sid,
+ OUT PULONG AceLength
+ )
+/*++
+
+Routine Description:
+
+ This method creates an access-denied ACE in the supplied buffer.
+ Note that the only sort of access-denied ACE that ACLCONV creates
+ is one which denies all access.
+
+Arguments:
+
+ Buffer -- Supplies the buffer in which the ACE should be
+ created.
+ BufferLength -- Supplies the length of the buffer.
+ Access -- Supplies the desired Access Mask.
+ InheritFlags -- Supplies the ACE's inherit flags.
+ Sid -- Supplies the ACE's SID.
+ AceLength -- Receives the length of the created ACE.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ PACCESS_DENIED_ACE NewAce;
+ ULONG SidLength;
+
+ UNREFERENCED_PARAMETER( Access );
+
+ SidLength = GetLengthSid( Sid );
+
+ *AceLength = sizeof( ACE_HEADER ) +
+ sizeof( ACCESS_MASK ) +
+ SidLength;
+
+ if( *AceLength > BufferLength ) {
+
+ return FALSE;
+ }
+
+
+ NewAce = (PACCESS_DENIED_ACE)Buffer;
+
+ NewAce->Header.AceType = ACCESS_DENIED_ACE_TYPE;
+ NewAce->Header.AceSize = (USHORT)*AceLength;
+ NewAce->Header.AceFlags = InheritFlags;
+
+ NewAce->Mask = GENERIC_ALL;
+
+ return( CopySid( SidLength,
+ (PSID)((PBYTE)Buffer + sizeof( ACE_HEADER ) +
+ sizeof( ACCESS_MASK )),
+ Sid ) );
+}
+
+
+SID_IDENTIFIER_AUTHORITY World = SECURITY_WORLD_SID_AUTHORITY;
+
+BOOLEAN
+CreateSystemAuditAce(
+ IN OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ IN ACCESS_MASK Access,
+ IN UCHAR InheritFlags,
+ IN BOOLEAN AuditFailures,
+ OUT PULONG AceLength
+ )
+/*++
+
+Routine Description:
+
+ This method creates a System Audit ACE in the supplied buffer.
+
+Arguments:
+
+ Buffer -- Supplies the buffer in which the ACE should
+ be created.
+ BufferLength -- Supplies the length of the buffer.
+ Access -- Supplies the access mask that should be audited.
+ InheritFlags -- Supplies the inheritance flags for the ACE.
+ AuditFailures -- Supplies a flag which, if TRUE, indicates that
+ the ACE should be set to audit failed access,
+ rather than successful access.
+ AceLength -- Receives the length of the ACE.
+
+
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ ACLCONV always creates System Audit Aces with the well-known SID WORLD.
+ It has the SID Identifier Authority SECURITY_WORLD_SID_AUTHORITY and
+ no subauthorities.
+
+--*/
+{
+ PSYSTEM_AUDIT_ACE NewAce;
+ ULONG NewAceLength, SidOffset, SidLength;
+ PSID WorldSid;
+
+
+ // See if the supplied buffer is big enough to hold a System
+ // Audit Ace that has an SID with one subauthority. This kind
+ // of ACE consists of an ACE_HEADER followed by an ACCESS_MASK
+ // followed by the SID.
+
+ SidLength = GetSidLengthRequired( 1 );
+
+ SidOffset = sizeof( ACE_HEADER ) + sizeof( ACCESS_MASK );
+
+ NewAceLength = SidOffset + SidLength;
+
+ if( NewAceLength > BufferLength ) {
+
+ return FALSE;
+ }
+
+ // Create the ACE.
+
+ NewAce = (PSYSTEM_AUDIT_ACE)Buffer;
+
+ NewAce->Header.AceType = SYSTEM_AUDIT_ACE_TYPE;
+ NewAce->Header.AceSize = (USHORT)NewAceLength;
+ NewAce->Header.AceFlags = InheritFlags;
+ NewAce->Header.AceFlags |= AuditFailures ? SUCCESSFUL_ACCESS_ACE_FLAG :
+ FAILED_ACCESS_ACE_FLAG;
+
+ NewAce->Mask = Access;
+
+ // WORLD is a well-known SID with one subauthority.
+ //
+ WorldSid = (PSID)((PBYTE)Buffer + SidOffset);
+ InitializeSid( WorldSid, &World, 1 );
+ *GetSidSubAuthority( WorldSid, 0 ) = SECURITY_WORLD_RID;
+
+ *AceLength = NewAceLength;
+ return TRUE;
+}
diff --git a/private/utils/aclconv/acehelp.hxx b/private/utils/aclconv/acehelp.hxx
new file mode 100644
index 000000000..11de8f6d6
--- /dev/null
+++ b/private/utils/aclconv/acehelp.hxx
@@ -0,0 +1,74 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ acehelp.hxx
+
+Abstract:
+
+ This module contains declarations for helper routines for
+ manipulating ACE's.
+
+
+Author:
+
+ Bill McJohn (billmc) 09-Feb-1992
+
+Revision History:
+
+
+--*/
+
+#if !defined ( _ACEHELP_DEFN_ )
+
+#define _ACEHELP_DEFN_
+
+VOID
+ConvertAccessMasks(
+ IN USHORT LanmanAccess,
+ OUT PACCESS_MASK DirMask,
+ OUT PACCESS_MASK FileMask
+ );
+
+VOID
+ConvertAuditBits(
+ IN USHORT LmAuditBits,
+ OUT PACCESS_MASK DirSuccessfulMask,
+ OUT PACCESS_MASK DirFailedMask,
+ OUT PACCESS_MASK FileSuccessfulMask,
+ OUT PACCESS_MASK FileFailedMask
+ );
+
+BOOLEAN
+CreateAccessAllowedAce(
+ IN OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ IN ACCESS_MASK Access,
+ IN UCHAR InheritFlags,
+ IN PSID Sid,
+ OUT PULONG AceLength
+ );
+
+BOOLEAN
+CreateAccessDeniedAce(
+ IN OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ IN ACCESS_MASK Access,
+ IN UCHAR InheritFlags,
+ IN PSID Sid,
+ OUT PULONG AceLength
+ );
+
+BOOLEAN
+CreateSystemAuditAce(
+ IN OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ IN ACCESS_MASK Access,
+ IN UCHAR InheritFlags,
+ IN BOOLEAN AuditFailures,
+ OUT PULONG AceLength
+ );
+
+#endif
diff --git a/private/utils/aclconv/aclconv.cxx b/private/utils/aclconv/aclconv.cxx
new file mode 100644
index 000000000..6438b8ae2
--- /dev/null
+++ b/private/utils/aclconv/aclconv.cxx
@@ -0,0 +1,1938 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ aclconv.cxx
+
+Abstract:
+
+ This module contains function definitions for the ACLCONV class,
+ which implements conversion of Lanman 2.x ACLs into NT ACLs.
+
+Author:
+
+ Bill McJohn (billmc) 29-Jan-1992
+
+Revision History:
+
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+#include "ulibcl.hxx"
+#include "error.hxx"
+#include "array.hxx"
+#include "arrayit.hxx"
+#include "arg.hxx"
+#include "smsg.hxx"
+#include "rtmsg.h"
+#include "wstring.hxx"
+#include "system.hxx"
+#include "aclconv.hxx"
+#include "file.hxx"
+#include "filestrm.hxx"
+
+#include "logfile.hxx"
+
+
+ERRSTACK* perrstk;
+
+BOOLEAN
+QueryFileSystemName(
+ IN PCWSTRING RootName,
+ OUT PDSTRING FileSystemName
+ )
+/*++
+
+Routine Description:
+
+ Determines the name of the file system on the specified volume.
+
+Arguments:
+
+ RootName -- Supplies the name of the volume's root directory.
+ FileSystemName -- Receives the file system name.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ WCHAR NameBuffer[8];
+
+ if( !GetVolumeInformation( RootName->GetWSTR(),
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ NULL,
+ NameBuffer,
+ 8 ) ) {
+
+ return FALSE;
+ }
+
+ return( FileSystemName->Initialize( NameBuffer ) );
+}
+
+
+BOOLEAN
+EnablePrivilege(
+ PWSTR Privilege
+ )
+/*++
+
+Routine Description:
+
+ This routine tries to adjust the priviliege of the current process.
+
+
+Arguments:
+
+ Privilege - String with the name of the privilege to be adjusted.
+
+Return Value:
+
+ Returns TRUE if the privilege could be adjusted.
+ Returns FALSE, otherwise.
+
+
+--*/
+{
+ HANDLE TokenHandle;
+ LUID_AND_ATTRIBUTES LuidAndAttributes;
+
+ TOKEN_PRIVILEGES TokenPrivileges;
+
+
+ if( !OpenProcessToken( GetCurrentProcess(),
+ TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
+ &TokenHandle ) ) {
+ DebugPrint( "OpenProcessToken failed" );
+ return( FALSE );
+ }
+
+
+ if( !LookupPrivilegeValue( NULL,
+ Privilege,
+ &( LuidAndAttributes.Luid ) ) ) {
+ DebugPrintf( "LookupPrivilegeValue failed, Error = %#d \n", GetLastError() );
+ return( FALSE );
+ }
+
+ LuidAndAttributes.Attributes = SE_PRIVILEGE_ENABLED;
+ TokenPrivileges.PrivilegeCount = 1;
+ TokenPrivileges.Privileges[0] = LuidAndAttributes;
+
+ if( !AdjustTokenPrivileges( TokenHandle,
+ FALSE,
+ &TokenPrivileges,
+ 0,
+ NULL,
+ NULL ) ) {
+ DebugPrintf( "AdjustTokenPrivileges failed, Error = %#x \n", GetLastError() );
+ return( FALSE );
+ }
+
+ if( GetLastError() != NO_ERROR ) {
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+INT _CRTAPI1
+main(
+ )
+/*++
+
+Routine Description:
+
+ Entry point for the ACL conversion utility.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ An error level--0 indicates success.
+
+--*/
+{
+ INT ExitCode = 0;
+
+ if( !DEFINE_CLASS_DESCRIPTOR( ACLCONV ) ||
+ !DEFINE_CLASS_DESCRIPTOR( SID_CACHE ) ||
+ !DEFINE_CLASS_DESCRIPTOR( ACL_CONVERT_NODE ) ) {
+
+ return 1;
+ }
+
+ {
+ ACLCONV Aclconv;
+
+ if( Aclconv.Initialize( &ExitCode ) ) {
+
+ if( Aclconv.IsInListMode() ) {
+
+ ExitCode = Aclconv.ListLogFile();
+
+ } else {
+
+ ExitCode = Aclconv.ConvertAcls();
+ }
+ }
+ }
+
+ return ExitCode;
+}
+
+
+DEFINE_CONSTRUCTOR( ACLCONV, PROGRAM );
+
+ACLCONV::~ACLCONV(
+ )
+{
+ Destroy();
+}
+
+VOID
+ACLCONV::Construct(
+ )
+/*++
+
+Routine Description:
+
+ Helper method for object construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _DataFileRevision = DataFileRevisionUnknown;
+
+ _DataFile = NULL;
+ _DataFileStream = NULL;
+ _LogFile = NULL;
+ _LogFileStream = NULL;
+
+ _AclWorkFile = NULL;
+ _AclWorkStream = NULL;
+
+ _NewDrive = NULL;
+
+ _RootNode = NULL;
+ _DriveName = NULL;
+ _DomainName = NULL;
+ _SidLookupTableName = NULL;
+
+}
+
+VOID
+ACLCONV::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Helper function for object destruction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _DataFileRevision = DataFileRevisionUnknown;
+ _NextReadOffset = 0;
+ _BytesRemainingInCurrentGroup = 0;
+
+ DELETE( _DataFile );
+ DELETE( _DataFileStream );
+ DELETE( _LogFile );
+ DELETE( _LogFileStream );
+
+ DELETE( _AclWorkFile );
+ DELETE( _AclWorkStream );
+ DELETE( _NewDrive );
+ DELETE( _RootNode );
+ DELETE( _DriveName );
+ DELETE( _DomainName );
+ DELETE( _SidLookupTableName );
+}
+
+
+
+BOOLEAN
+ACLCONV::Initialize(
+ OUT PINT ExitCode
+ )
+/*++
+
+Routine Description:
+
+ Initialize the ACLCONV object.
+
+Arguments:
+
+ ExitCode -- Receives an error level if this method fails.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ Destroy();
+
+ if( !PROGRAM::Initialize( ) ) {
+
+ Destroy();
+ *ExitCode = 1;
+ return FALSE;
+ }
+
+ return ParseArguments( ExitCode );
+}
+
+
+INT
+ACLCONV::ListLogFile(
+ )
+/*++
+
+Routine Description:
+
+ This method reads a log file produced by a previous run of
+ ACLCONV and displays the errors logged to that file.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ An error level--zero indicates success.
+
+--*/
+{
+ LM_ACCESS_LIST AccessEntries[ MAX_ACCESS_ENTRIES ];
+ ULONG AceConversionCodes[ MAX_ACCESS_ENTRIES ];
+
+ ACLCONV_LOGFILE_HEADER LogFileHeader;
+ DSTRING ResourceName;
+ ULONG AccessEntryCount, BytesRead, ConversionCode, i;
+ INT ExitCode = 0;
+ USHORT AuditInfo;
+
+ // Open the log file and reset the seek pointer to the beginning
+ // of the file.
+ //
+ if( (_LogFile = SYSTEM::QueryFile( &_LogFilePath )) == NULL ||
+ (_LogFileStream = _LogFile->QueryStream( READ_ACCESS )) == NULL ) {
+
+ // Cannot create log file.
+
+ DisplayMessage( MSG_ACLCONV_CANT_OPEN_FILE,
+ ERROR_MESSAGE,
+ "%W",
+ _LogFilePath.GetPathString() );
+ return 1;
+ }
+
+ // Check the log file signature:
+ //
+ if( !_LogFileStream->MovePointerPosition( 0, STREAM_BEGINNING ) ||
+ !_LogFileStream->Read( (PBYTE)&LogFileHeader,
+ sizeof( ACLCONV_LOGFILE_HEADER ),
+ &BytesRead ) ||
+ BytesRead != sizeof( ACLCONV_LOGFILE_HEADER ) ||
+ LogFileHeader.Signature != AclconvLogFileSignature ) {
+
+ DisplayMessage( MSG_ACLCONV_INVALID_LOG_FILE,
+ ERROR_MESSAGE );
+
+ return 1;
+ }
+
+ _NextReadOffset = sizeof( ACLCONV_LOGFILE_HEADER );
+
+ while( ReadNextLogRecord( &ExitCode,
+ &ResourceName,
+ &ConversionCode,
+ &AuditInfo,
+ MAX_ACCESS_ENTRIES,
+ &AccessEntryCount,
+ AccessEntries,
+ AceConversionCodes ) ) {
+
+ // Scan to see if there are any entries to display
+ //
+ if( AccessEntryCount != 0 ) {
+
+ DisplayMessage( MSG_ACLCONV_RESOURCE_NAME,
+ NORMAL_MESSAGE,
+ "%W",
+ &ResourceName );
+
+ for( i = 0; i < AccessEntryCount; i++ ) {
+
+ DisplayAce( (ACL_CONVERT_CODE)ConversionCode,
+ (ACE_CONVERT_CODE)AceConversionCodes[i],
+ AccessEntries + i );
+ }
+ }
+ }
+
+ if( ExitCode ) {
+
+ DisplayMessage( MSG_ACLCONV_LOGFILE_READ_ERROR, ERROR_MESSAGE );
+ }
+
+ return ExitCode;
+}
+
+
+
+NONVIRTUAL
+BOOLEAN
+ACLCONV::DisplayAce(
+ IN ACL_CONVERT_CODE AclConvertCode,
+ IN ACE_CONVERT_CODE AceConvertCode,
+ IN PLM_ACCESS_LIST Ace
+ )
+/*++
+
+Routine Description:
+
+ This method displays the conversion result for a single ACE.
+
+Arguments:
+
+ AclConvertCode -- Supplies the overall conversion code for
+ the resource to which this ACE is attached.
+ AceConvertCode -- Supplies the conversion result for this
+ particular ACE. Note that if the AclConvertCode
+ is not ACL_CONVERT_SUCCESS, it takes priority
+ over AceConvertCode.
+ Ace -- Supplies the ACE in question.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ WCHAR WideNameBuffer[ UNLEN + 1 ];
+ DSTRING Temp;
+ DSTRING Name;
+
+ memset( WideNameBuffer, 0, sizeof( WideNameBuffer ) );
+
+ // Display the user's name. If it's a group, prepend an
+ // asterisk.
+ //
+ if( !MultiByteToWideChar( _SourceCodepage,
+ 0,
+ Ace->acl_ugname,
+ strlen( Ace->acl_ugname ),
+ WideNameBuffer,
+ UNLEN + 1 ) ) {
+
+ DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ return FALSE;
+ }
+
+ if( !Temp.Initialize( WideNameBuffer ) ) {
+
+ DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ return FALSE;
+ }
+
+ if( Ace->acl_access & LM_ACCESS_GROUP ) {
+
+ if( !Name.Initialize( "*" ) ||
+ !Name.Strcat( &Temp ) ) {
+
+ DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ return FALSE;
+ }
+
+ } else {
+
+ if( !Name.Initialize( &Temp ) ) {
+
+ DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ return FALSE;
+ }
+ }
+
+ DisplayMessage( MSG_ACLCONV_USERNAME, NORMAL_MESSAGE, "%W", &Name );
+
+
+ // Display the permissions:
+ //
+ if( (Ace->acl_access & ~LM_ACCESS_GROUP) == 0 ) {
+
+ // This is a no-access ACE.
+ //
+ DisplayMessage( MSG_ACLCONV_NONE_PERM );
+
+ } else {
+
+ // This ACE grants some sort of access--check each type
+ // of access in turn, displaying all we find.
+ //
+ if( Ace->acl_access & LM_ACCESS_READ ) {
+
+ DisplayMessage( MSG_ACLCONV_READ_PERM );
+ }
+
+ if( Ace->acl_access & LM_ACCESS_WRITE ) {
+
+ DisplayMessage( MSG_ACLCONV_WRITE_PERM );
+ }
+
+ if( Ace->acl_access & LM_ACCESS_CREATE ) {
+
+ DisplayMessage( MSG_ACLCONV_CREATE_PERM );
+ }
+
+ if( Ace->acl_access & LM_ACCESS_EXEC ) {
+
+ DisplayMessage( MSG_ACLCONV_EXECUTE_PERM );
+ }
+
+ if( Ace->acl_access & LM_ACCESS_DELETE ) {
+
+ DisplayMessage( MSG_ACLCONV_DELETE_PERM );
+ }
+
+ if( Ace->acl_access & LM_ACCESS_ATRIB ) {
+
+ DisplayMessage( MSG_ACLCONV_ATTR_PERM );
+ }
+
+ if( Ace->acl_access & LM_ACCESS_PERM ) {
+
+ DisplayMessage( MSG_ACLCONV_PERM_PERM );
+ }
+ }
+
+
+ // Display the cause of failure:
+ //
+ if( AclConvertCode != ACL_CONVERT_SUCCESS ) {
+
+ // The failure is associated with the resource.
+ //
+ switch( AclConvertCode ) {
+
+ case ACL_CONVERT_RESOURCE_NOT_FOUND :
+ DisplayMessage( MSG_ACLCONV_FILE_NOT_FOUND );
+ break;
+
+ case ACL_CONVERT_ERROR :
+ default :
+ DisplayMessage( MSG_ACLCONV_ERROR_IN_CONVERSION );
+ break;
+ }
+
+ } else {
+
+ // Display the ACE conversion result.
+ //
+ switch( AceConvertCode ) {
+
+ case ACL_CONVERT_SUCCESS :
+ DisplayMessage( MSG_ACLCONV_ACE_CONVERTED );
+ break;
+
+ case ACE_CONVERT_DROPPED :
+ DisplayMessage( MSG_ACLCONV_ACE_DROPPED );
+ break;
+
+ case ACE_CONVERT_SID_NOT_FOUND :
+ DisplayMessage( MSG_ACLCONV_SID_NOT_FOUND );
+ break;
+
+ case ACE_CONVERT_ERROR :
+ default:
+ DisplayMessage( MSG_ACLCONV_ERROR_IN_CONVERSION );
+ break;
+ }
+ }
+
+
+ return TRUE;
+}
+
+
+NONVIRTUAL
+BOOLEAN
+ACLCONV::ReadNextLogRecord(
+ OUT PINT ExitCode,
+ OUT PWSTRING ResourceString,
+ OUT PULONG ConversionCode,
+ OUT PUSHORT AuditInfo,
+ IN ULONG MaxEntries,
+ OUT PULONG AccessEntryCount,
+ OUT PLM_ACCESS_LIST AccessEntries,
+ OUT PULONG AceConversionCodes
+ )
+/*++
+
+Routine Description:
+
+ This method reads the next log entry from the log file.
+
+Arguments:
+
+ ExitCode -- receives an exit code if an error occurs.
+ ResourceString -- receives the name of the resource
+ ConversionCode -- receives the conversion result for this resource.
+ AuditInfo -- receives the audit information for this resource.
+ MaxEntries -- supplies the maximum number of ACE's that can
+ be written to the output buffers.
+ AccessEntryCount -- receives the number of ACE's written to
+ the output buffers.
+ AccessEntries -- receives the logged ACE's
+ AceConversionCodes -- receives the conversion results for the
+ individual ACE's.
+
+Return Value:
+
+ TRUE upon successful completion (in which case ExitCode may
+ be ignored). FALSE if there are no more entries (in which
+ case ExitCode is zero) or if an error occurs (in which case
+ ExitCode is non-zero).
+
+--*/
+{
+ ACLCONV_LOG_RECORD_HEADER Header;
+ ULONG BytesRead;
+
+ if( _LogFileStream->IsAtEnd() ) {
+
+ // No more entries to read.
+
+ *ExitCode = 0;
+ return FALSE;
+ }
+
+ // Read the log record header
+ //
+ if( !_LogFileStream->Read( (PBYTE)&Header,
+ sizeof( ACLCONV_LOG_RECORD_HEADER ),
+ &BytesRead ) ||
+ BytesRead != sizeof( ACLCONV_LOG_RECORD_HEADER ) ) {
+
+ *ExitCode = 1;
+ return FALSE;
+ }
+
+ *ConversionCode = Header.ConversionResult;
+ *AuditInfo = Header.LmAuditMask;
+ *AccessEntryCount = Header.AccessEntryCount;
+
+ // Make sure that the name is not longer than the maximum
+ // name length (plus room for trailing NULL) and then read
+ // it into the name workspace and use it to initialize the
+ // client's resource name string.
+ //
+ if( Header.ResourceNameLength > MAX_RESOURCE_NAME_LENGTH + 1 ||
+ !_LogFileStream->Read( (PBYTE)_NameBuffer,
+ Header.ResourceNameLength * sizeof( WCHAR ),
+ &BytesRead ) ||
+ BytesRead != Header.ResourceNameLength * sizeof( WCHAR ) ||
+ !ResourceString->Initialize( _NameBuffer ) ) {
+
+ *ExitCode = 1;
+ return FALSE;
+ }
+
+ // Make sure the ACE's and their associated convert codes will
+ // fit in the supplied buffers:
+ //
+ if( Header.AccessEntryCount > MaxEntries ) {
+
+ *ExitCode = 1;
+ return FALSE;
+ }
+
+ // Read the ACE conversion codes and the ACE's themselves:
+ //
+ if( Header.AccessEntryCount != 0 &&
+ ( !_LogFileStream->Read( (PBYTE)AceConversionCodes,
+ Header.AccessEntryCount * sizeof( ULONG ),
+ &BytesRead ) ||
+ BytesRead != Header.AccessEntryCount * sizeof( ULONG ) ) ||
+
+ ( !_LogFileStream->Read( (PBYTE)AccessEntries,
+ Header.AccessEntryCount *
+ sizeof( LM_ACCESS_LIST ),
+ &BytesRead ) ||
+ BytesRead != Header.AccessEntryCount * sizeof( LM_ACCESS_LIST ) ) ) {
+
+ *ExitCode = 1;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+INT
+ACLCONV::ConvertAcls(
+ )
+/*++
+
+Routine Description:
+
+ This method reads the ACL's from the data file into a tree
+ of ACL Convert Nodes, and then converts the ACL's to NT
+ security descriptors and applies them to the files and
+ directories in question.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ An error level--zero indicates success.
+
+--*/
+{
+
+ LM_ACCESS_LIST AccessEntries[MAX_ACCESS_ENTRIES];
+ INHERITANCE_BUFFER Inheritance;
+
+ FSTRING NtfsString;
+ DSTRING FsName;
+ DSTRING CurrentResource;
+ PATH CurrentResourcePath;
+
+ ACLCONV_LOGFILE_HEADER LogfileHeader;
+
+ PARRAY Components = NULL;
+ PARRAY_ITERATOR ComponentIterator = NULL;
+ PACL_CONVERT_NODE CurrentNode, NextNode;
+ PWSTRING CurrentComponent;
+
+ ULONG AccessEntryCount, BytesWritten;
+ USHORT LmAuditInfo;
+
+ INT ExitCode = 0;
+
+ DSTRING AclWorkString;
+
+ // Open aclwork.dat and read the contents into a special
+ // sid cache.
+
+ if (!AclWorkString.Initialize(L"aclwork.dat")) {
+ return 1;
+ }
+ if (!_AclWorkPath.Initialize(&AclWorkString)) {
+ return 1;
+ }
+
+ if (NULL == (_AclWorkFile = SYSTEM::QueryFile(&_AclWorkPath))) {
+
+ // try to open aclwork.dat in the same directory as the
+ // data file.
+
+ if (!_AclWorkPath.Initialize(&_DataFilePath)) {
+ return 1;
+ }
+ if (!_AclWorkPath.SetName(&AclWorkString)) {
+ return 1;
+ }
+
+ _AclWorkFile = SYSTEM::QueryFile(&_AclWorkPath);
+ }
+ if (NULL != _AclWorkFile &&
+ NULL != (_AclWorkStream = _AclWorkFile->QueryStream(READ_ACCESS))) {
+
+ // DisplayMessage( MSG_ACLCONV_USING_ACLWORK, NORMAL_MESSAGE );
+
+ if (!ReadAclWorkSids()) {
+ return 1;
+ }
+ }
+
+ // Open the data file and determine its format (ie. what
+ // revision of BackAcc produced it).
+
+ if( (_DataFile = SYSTEM::QueryFile( &_DataFilePath )) == NULL ||
+ (_DataFileStream = _DataFile->QueryStream( READ_ACCESS )) == NULL ) {
+
+ DisplayMessage( MSG_ACLCONV_CANT_OPEN_FILE,
+ ERROR_MESSAGE,
+ "%W",
+ _DataFilePath.GetPathString() );
+ return 1;
+ }
+
+ // Note that DetermineDataFileRevision sets _DataFileRevision.
+
+ if( !DetermineDataFileRevision( ) ||
+ _DataFileRevision == DataFileRevisionUnknown ) {
+
+ DisplayMessage( MSG_ACLCONV_DATAFILE_BAD_FORMAT,
+ ERROR_MESSAGE,
+ "%W",
+ _DataFilePath.GetPathString() );
+ return 1;
+ }
+
+
+ // Create the log file.
+
+ LogfileHeader.Signature = AclconvLogFileSignature;
+
+ if( (_LogFile = SYSTEM::MakeFile( &_LogFilePath )) == NULL ||
+ (_LogFileStream = _LogFile->QueryStream( WRITE_ACCESS )) == NULL ||
+ !_LogFileStream->Write( (PBYTE)&LogfileHeader,
+ sizeof( ACLCONV_LOGFILE_HEADER ),
+ &BytesWritten ) ||
+ BytesWritten != sizeof( ACLCONV_LOGFILE_HEADER ) ) {
+
+ // Cannot create log file.
+
+ DisplayMessage( MSG_ACLCONV_CANT_OPEN_FILE,
+ ERROR_MESSAGE,
+ "%W",
+ _LogFilePath.GetPathString() );
+ return 1;
+ }
+
+
+ while( ReadNextAcl( &ExitCode,
+ &CurrentResource,
+ MAX_ACCESS_ENTRIES,
+ &AccessEntryCount,
+ (PVOID)AccessEntries,
+ &LmAuditInfo ) ) {
+
+ if( CurrentResource.QueryChCount() == 0 ) {
+
+ // This resource has no name; ignore it.
+ //
+ continue;
+ }
+
+ if( !CurrentResourcePath.Initialize( &CurrentResource ) ) {
+
+ DisplayMessage( MSG_ACLCONV_DATAFILE_ERROR, ERROR_MESSAGE );
+ return 1;
+ }
+
+ // If the user specified a substitute drive, use it.
+ //
+ if( _NewDrive != NULL &&
+ !CurrentResourcePath.SetDevice( _NewDrive ) ) {
+
+ DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ return 1;
+ }
+
+ if( _RootNode == NULL ) {
+
+ // This is the first ACL--create the root of the tree
+ // and determine the name of the drive.
+
+ if( !(_DriveName = CurrentResourcePath.QueryRoot()) ||
+ !(_RootNode = NEW ACL_CONVERT_NODE) ||
+ !_RootNode->Initialize( _DriveName ) ) {
+
+ DELETE( _RootNode );
+ DELETE( _DriveName );
+
+ DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ return 1;
+ }
+ }
+
+ // Fetch the component array for this resource.
+
+ DELETE( ComponentIterator );
+
+ if( Components != NULL ) {
+
+ Components->DeleteAllMembers();
+ }
+
+ DELETE( Components );
+
+ if( !(Components = CurrentResourcePath.QueryComponentArray()) ||
+ !(ComponentIterator = (PARRAY_ITERATOR)
+ Components->QueryIterator()) ) {
+
+ DELETE( ComponentIterator );
+
+ if( Components != NULL ) {
+
+ Components->DeleteAllMembers();
+ }
+
+ DELETE( Components );
+
+ DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ return 1;
+ }
+
+ CurrentNode = _RootNode;
+
+ ComponentIterator->Reset();
+
+ // The first component is the drive & root directory, which
+ // isn't interesting.
+
+ CurrentComponent = (PWSTRING)ComponentIterator->GetNext();
+
+ // Traverse the tree down to the end of the path, creating
+ // new nodes as needed.
+
+ while( (CurrentComponent = (PWSTRING)ComponentIterator->GetNext())
+ != NULL ) {
+
+ if( !(NextNode = CurrentNode->GetChild( CurrentComponent )) &&
+ !(NextNode = CurrentNode->AddChild( CurrentComponent )) ) {
+
+ DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ return 1;
+ }
+
+ CurrentNode = NextNode;
+ }
+
+ // Add the Lanman ACL to the node which represents the end of
+ // the path.
+
+ if( !CurrentNode->AddLanmanAcl( AccessEntryCount,
+ AccessEntries,
+ LmAuditInfo ) ) {
+
+ DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ return 1;
+ }
+ }
+
+
+ if( ExitCode != 0 ) {
+
+ DisplayMessage( MSG_ACLCONV_DATAFILE_ERROR, ERROR_MESSAGE );
+ return 1;
+ }
+
+ // Traverse the tree and convert all the ACE's, propagating
+ // as we go.
+ //
+
+ // Adjust this process' privileges so that it can twiddle
+ // System ACL's.
+ //
+ if( !EnablePrivilege( (LPWSTR)SE_SECURITY_NAME ) ) {
+
+ DisplayMessage( MSG_ACLCONV_CONVERSION_ERROR, ERROR_MESSAGE );
+ ExitCode = 1;
+ }
+
+ if( ExitCode == 0 &&
+ _RootNode != NULL ) {
+
+ // Make sure the target drive is NTFS.
+ //
+ if( !NtfsString.Initialize( (PWSTR)L"NTFS" ) ||
+ !QueryFileSystemName( _RootNode->GetName(), &FsName ) ) {
+
+ DisplayMessage( MSG_ACLCONV_CANT_DETERMINE_FILESYSTEM, ERROR_MESSAGE );
+ ExitCode = 1;
+
+ } else if( FsName.Stricmp( &NtfsString ) != 0 ) {
+
+ DisplayMessage( MSG_ACLCONV_TARGET_NOT_NTFS, ERROR_MESSAGE );
+ ExitCode = 1;
+
+ } else {
+
+ // Set up an empty inheritance buffer to pass
+ // to the root.
+ //
+ Inheritance.RecessiveDeniedAces = NULL;
+ Inheritance.RecessiveAllowedAces = NULL;
+ Inheritance.DominantDeniedAces = NULL;
+ Inheritance.DominantAllowedAces = NULL;
+
+ Inheritance.RecessiveDeniedMaxLength = 0;
+ Inheritance.RecessiveAllowedMaxLength = 0;
+ Inheritance.DominantDeniedMaxLength = 0;
+ Inheritance.DominantAllowedMaxLength = 0;
+
+ Inheritance.RecessiveDeniedLength = 0;
+ Inheritance.RecessiveAllowedLength = 0;
+ Inheritance.DominantDeniedLength = 0;
+ Inheritance.DominantAllowedLength = 0;
+
+ if( !_RootNode->Convert( NULL,
+ &Inheritance,
+ this ) ) {
+
+ DisplayMessage( MSG_ACLCONV_CONVERSION_ERROR, ERROR_MESSAGE );
+ ExitCode = 1;
+ }
+ }
+ }
+
+
+ if( ExitCode == 0 ) {
+
+ DisplayMessage( MSG_ACLCONV_CONVERT_COMPLETE );
+ }
+
+ return ExitCode;
+}
+
+
+BOOLEAN
+ACLCONV::LogConversion(
+ IN PPATH Resource,
+ IN ULONG ConversionCode,
+ IN ULONG LmAuditInfo,
+ IN ULONG AccessEntryCount,
+ IN PCULONG AceConversionCodes,
+ IN PCLM_ACCESS_LIST AccessEntries
+ )
+/*+
+
+Routine Description:
+
+ This method writes information about the conversion of a resource
+ to the log file.
+
+Arguments:
+
+ Resource -- Supplies the path to the resource
+ ConversionCode -- Supplies the conversion result for the
+ resource.
+ LmAuditInfo -- Supplies the Lanman 2.x audit information
+ associated with the resource.
+ AccessEntryCount -- Supplies the number of Lanman 2.x access
+ entries associated with the resource.
+ AceConversionCodes -- Supplies the conversion results of the
+ individual ACE's
+ AccessEntries -- Supplies the Lanman 2.x access control
+ entries.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ ACLCONV_LOG_RECORD_HEADER Header;
+ PCWSTRING PathString;
+
+ ULONG NameLength, BytesWritten;
+
+ DebugPtrAssert( Resource );
+ DebugPtrAssert( _LogFileStream );
+
+ if( (PathString = Resource->GetPathString()) == NULL ||
+ (NameLength = PathString->QueryChCount()) > MAX_RESOURCE_NAME_LENGTH ||
+ !PathString->QueryWSTR( 0,
+ TO_END,
+ _NameBuffer,
+ MAX_RESOURCE_NAME_LENGTH + 1 ) ){
+
+ return FALSE;
+ }
+
+ Header.ResourceNameLength = NameLength + 1;
+ Header.ConversionResult = ConversionCode;
+ Header.LmAuditMask = (USHORT)LmAuditInfo;
+ Header.AccessEntryCount = (USHORT)AccessEntryCount;
+
+ if(!_LogFileStream->Write( (PBYTE)&Header,
+ sizeof( ACLCONV_LOG_RECORD_HEADER ),
+ &BytesWritten ) ||
+ BytesWritten != sizeof( ACLCONV_LOG_RECORD_HEADER ) ||
+ !_LogFileStream->Write( (PBYTE)_NameBuffer,
+ (NameLength + 1) * sizeof( WCHAR ),
+ &BytesWritten ) ||
+ BytesWritten != (NameLength + 1) * sizeof( WCHAR )) {
+
+ DisplayMessage( MSG_ACLCONV_LOGFILE_ERROR, ERROR_MESSAGE );
+ return FALSE;
+ }
+
+ if( AccessEntryCount != 0 &&
+ ( !_LogFileStream->Write( (PBYTE)AceConversionCodes,
+ AccessEntryCount * sizeof(ULONG),
+ &BytesWritten ) ||
+ BytesWritten != AccessEntryCount * sizeof(ULONG) ||
+ !_LogFileStream->Write( (PBYTE)AccessEntries,
+ AccessEntryCount * sizeof( LM_ACCESS_LIST ),
+ &BytesWritten ) ||
+ BytesWritten != AccessEntryCount * sizeof( LM_ACCESS_LIST ) ) ) {
+
+ DisplayMessage( MSG_ACLCONV_LOGFILE_ERROR, ERROR_MESSAGE );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+ACLCONV::ParseArguments(
+ OUT PINT ExitCode
+ )
+/*++
+
+Routine Description:
+
+ This method parses the arguments given to ACLCONV and sets the
+ state of the object appropriately.
+
+ The accepted syntax is:
+
+ ACLCONV [/?] [/V] /DATA:datafile /LOG:logfile
+
+Arguments:
+
+ ExitCode -- Receives an exit code if the method fails.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+ Note that this method will fail, but return an exit-code
+ of zero (success) if the user specifies the /? argument.
+
+--*/
+{
+ ARRAY ArgArray; // Array of arguments
+ ARRAY LexArray; // Array of lexemes
+ ARGUMENT_LEXEMIZER ArgLex; // Argument Lexemizer
+ STRING_ARGUMENT ProgramNameArgument; // Program name argument
+ PATH_ARGUMENT DataFileArgument; // Path to data file
+ PATH_ARGUMENT LogFileArgument; // Path to log file
+ PATH_ARGUMENT DriveArgument; // New drive to use
+ FLAG_ARGUMENT ListArgument; // List flag argument
+ FLAG_ARGUMENT HelpArgument; // Help flag argument
+ STRING_ARGUMENT DomainArgument; // Domain name argument
+ LONG_ARGUMENT CodepageArgument; // Source Codepage argument
+ STRING_ARGUMENT SidLookupArgument; // Filename of lookup table
+ PWSTRING InvalidArg; // Invalid argument catcher
+ DSTRING Backslash; // Backslash
+ DSTRING RootDir; // Root directory of the new drive
+ UINT DriveType;
+
+
+ DebugPtrAssert( ExitCode );
+
+ //
+ // Initialize all the argument parsing machinery.
+ //
+ if( !ArgArray.Initialize( 5, 1 ) ||
+ !LexArray.Initialize( 5, 1 ) ||
+ !ArgLex.Initialize( &LexArray ) ||
+ !HelpArgument.Initialize( "/?" ) ||
+ !ListArgument.Initialize( "/LIST" ) ||
+ !ProgramNameArgument.Initialize( "*" ) ||
+ !DataFileArgument.Initialize( "/DATA:*" ) ||
+ !LogFileArgument.Initialize( "/LOG:*" ) ||
+ !DriveArgument.Initialize( "/NEWDRIVE:*" ) ||
+ !DomainArgument.Initialize( "/DOMAIN:*" ) ||
+ !CodepageArgument.Initialize( "/CODEPAGE:*" ) ||
+ !SidLookupArgument.Initialize( "/SIDLOOKUP:*" ) ) {
+
+ DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+
+ *ExitCode = 1;
+ return FALSE;
+ }
+
+ //
+ // The ACL conversion utility is case-insensitive
+ //
+ ArgLex.SetCaseSensitive( FALSE );
+
+ // Put the arguments into the argument array
+
+ if( !ArgArray.Put( &HelpArgument ) ||
+ !ArgArray.Put( &ListArgument ) ||
+ !ArgArray.Put( &DataFileArgument ) ||
+ !ArgArray.Put( &LogFileArgument ) ||
+ !ArgArray.Put( &DriveArgument ) ||
+ !ArgArray.Put( &DomainArgument ) ||
+ !ArgArray.Put( &CodepageArgument ) ||
+ !ArgArray.Put( &ProgramNameArgument ) ) {
+
+ DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+
+ *ExitCode = 1;
+ return FALSE;
+ }
+
+ //
+ // Lexemize the command line.
+ //
+ if ( !ArgLex.PrepareToParse() ) {
+
+ DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+
+ *ExitCode = 1;
+ return FALSE;
+ }
+
+ //
+ // Parse the arguments.
+ //
+ if( !ArgLex.DoParsing( &ArgArray ) ) {
+
+
+ DisplayMessage( MSG_CONV_INVALID_PARAMETER, ERROR_MESSAGE, "%W", InvalidArg = ArgLex.QueryInvalidArgument() );
+ DELETE( InvalidArg );
+
+ *ExitCode = 1;
+ return FALSE;
+ }
+
+
+ //
+ // If the user requested help, give it.
+ //
+ if( HelpArgument.QueryFlag() ) {
+
+ DisplayMessage( MSG_ACLCONV_USAGE );
+
+ *ExitCode = 0;
+ return FALSE;
+ }
+
+ // The log file must be specified, and either the data
+ // file or the list argument (but not both) must be
+ // provided.
+ //
+ if( !LogFileArgument.IsValueSet() ||
+ ( !DataFileArgument.IsValueSet() &&
+ !ListArgument.IsValueSet() ) ||
+ ( DataFileArgument.IsValueSet() &&
+ ListArgument.IsValueSet() ) ) {
+
+ DisplayMessage( MSG_ACLCONV_USAGE );
+
+ *ExitCode = 1;
+ return FALSE;
+ }
+
+ // If the drive argument has been supplied, record it:
+ //
+ if( DriveArgument.IsValueSet() ) {
+
+ _NewDrive = DriveArgument.GetPath()->QueryDevice();
+
+ if( _NewDrive == NULL ) {
+
+ DisplayMessage( MSG_INVALID_PARAMETER,
+ ERROR_MESSAGE,
+ "%W",
+ DriveArgument.GetPath()->GetPathString() );
+ *ExitCode = 1;
+ return FALSE;
+ }
+
+ // Validate the drive.
+ //
+ if( !RootDir.Initialize( _NewDrive ) ||
+ !Backslash.Initialize( "\\" ) ||
+ !RootDir.Strcat( &Backslash ) ) {
+
+ DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ *ExitCode = 1;
+ return FALSE;
+ }
+
+ DriveType = GetDriveTypeW( RootDir.GetWSTR() );
+
+ switch ( DriveType ) {
+
+ case DRIVE_FIXED:
+ case DRIVE_REMOVABLE:
+
+ // The drive type is acceptable.
+ //
+ break;
+
+ case 0:
+ case 1:
+ case DRIVE_CDROM:
+ case DRIVE_REMOTE:
+ case DRIVE_RAMDISK:
+ default:
+
+ // The drive type is invalid.
+ //
+ DisplayMessage( MSG_ACLCONV_INVALID_DRIVE, ERROR_MESSAGE, "%W", _NewDrive );
+ *ExitCode = 1;
+ return FALSE;
+ }
+ }
+
+ // If a domain name has been specified, remember it:
+ //
+ if( DomainArgument.IsValueSet() ) {
+
+ if( (_DomainName = NEW DSTRING) == NULL ||
+ !_DomainName->Initialize( DomainArgument.GetString() ) ) {
+
+ DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ *ExitCode = 1;
+ return FALSE;
+ }
+ }
+
+ // If a source codepage has been specified, use it; otherwise,
+ // use CP_OEMCP as default.
+ //
+ if( !CodepageArgument.IsValueSet() ) {
+
+ _SourceCodepage = CP_OEMCP;
+
+ } else {
+
+ _SourceCodepage = CodepageArgument.QueryLong();
+
+ if( !IsValidCodePage( _SourceCodepage ) ) {
+
+ DisplayMessage( MSG_ACLCONV_BAD_CODEPAGE, ERROR_MESSAGE );
+ *ExitCode = 1;
+ return FALSE;
+ }
+ }
+
+ if( SidLookupArgument.IsValueSet() ) {
+
+ _SidLookupTableName = SidLookupArgument.GetString()->QueryWSTR();
+ }
+
+ _IsInListMode = ListArgument.IsValueSet();
+
+ if( _IsInListMode ) {
+
+ // In list mode, only the Log File path need be present.
+ //
+ if( !_LogFilePath.Initialize( LogFileArgument.GetPath() ) ) {
+
+ DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ *ExitCode = 1;
+ return FALSE;
+ }
+ } else {
+
+ // The object is not in list mode, so both the Data File
+ // and Log File paths must be present.
+ //
+ if( !_DataFilePath.Initialize( DataFileArgument.GetPath() ) ||
+ !_LogFilePath.Initialize( LogFileArgument.GetPath() ) ) {
+
+ DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ *ExitCode = 1;
+ return FALSE;
+ }
+ }
+
+
+ if( !_SidCache.Initialize( 100 ) ) {
+
+ return FALSE;
+ }
+
+ if (!_AclWorkSids.Initialize(1)) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+
+BOOLEAN
+ACLCONV::DetermineDataFileRevision(
+ )
+/*++
+
+Routine Description:
+
+ This method examines the data file to determine what revision
+ of the Lanman BackAcc utility produced it. It sets the private
+ member variable _DataFileRevision.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion. _DataFileRevision is set
+ appropriately.
+
+--*/
+{
+ CHAR Buffer[RecognitionSize];
+ ULONG BytesRead;
+
+ // If the first four bytes of the file are the LM2.0 backacc signature,
+ // assume the data file was produced by LM2.0 backacc. LM2.1 backacc
+ // data files are recognizable by the string "LM210 BACKACC" at
+ // byte offset 4.
+
+
+ _DataFileRevision = DataFileRevisionUnknown;
+
+ if( _DataFileStream == NULL ||
+ !_DataFileStream->ReadAt( (PBYTE)Buffer,
+ RecognitionSize,
+ 0,
+ STREAM_BEGINNING,
+ &BytesRead ) ||
+ BytesRead != RecognitionSize ) {
+
+ return FALSE;
+ }
+
+
+ if( strncmp( Buffer, (PCHAR)&Lm20BackaccSignature, 4) == 0 ) {
+
+ _DataFileRevision = DataFileRevisionLanman20;
+ return TRUE;
+ }
+
+ if( strncmp( Buffer+Lm21BackaccSignatureOffset,
+ Lm21BackaccSignature,
+ Lm21BackaccSignatureLength ) == 0 ) {
+
+ _DataFileRevision = DataFileRevisionLanman21;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOLEAN
+ACLCONV::UpdateAndQueryCurrentLM21Name(
+ IN ULONG DirectoryLevel,
+ IN PCSTR NewComponent,
+ OUT PWSTRING CurrentName
+ )
+/*++
+
+Routine Description:
+
+ This function updates the current resource name while
+ traversing the LM21 BackAcc data file.
+
+Arguments:
+
+ DirectoryLevel -- Supplies the directory level of the
+ most-recently-encountered component.
+ (0 is the drive, 1 is the root directory,
+ 2 is an element in the root directory, and
+ so forth.)
+ NewComponent -- Supplies the name of the most-recently-
+ encountered component.
+ CurrentName -- Receives the updated current resource name.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ STATIC PDSTRING Components[256];
+ STATIC PDSTRING BackSlash;
+ STATIC ULONG CurrentLevel = 0;
+
+ WCHAR ComponentBuffer[ MAX_RESOURCE_NAME_LENGTH ];
+ ULONG i;
+
+ // If BackSlash hasn't been initialized yet,
+ // initialize it.
+ //
+ if( BackSlash == NULL ) {
+
+ if( (BackSlash = NEW DSTRING) == NULL ||
+ !BackSlash->Initialize( "\\" ) ) {
+
+ return FALSE;
+ }
+ }
+
+ if( DirectoryLevel == 0 ) {
+
+ return( CurrentName->Initialize( "" ) );
+ }
+
+ while( CurrentLevel >= DirectoryLevel ) {
+
+ // Trim off the last component of the path.
+ //
+ CurrentLevel--;
+ DELETE( Components[CurrentLevel] );
+ }
+
+
+ // Now we're ready to add a new component to the end of the
+ // current path.
+ //
+ if( DirectoryLevel != CurrentLevel + 1 ) {
+
+ DebugPrint( "ACLCONV: skipped a level in name tree.\n" );
+ return FALSE;
+ }
+
+ memset( ComponentBuffer, 0, sizeof( ComponentBuffer ) );
+
+ if( (Components[CurrentLevel] = NEW DSTRING) == NULL ||
+ !MultiByteToWideChar( _SourceCodepage,
+ 0,
+ NewComponent,
+ strlen( NewComponent ),
+ ComponentBuffer,
+ MAX_RESOURCE_NAME_LENGTH ) ||
+ !Components[CurrentLevel]->Initialize( ComponentBuffer ) ) {
+
+ return FALSE;
+ }
+
+ CurrentLevel++;
+
+ // Now copy the current path to the output string.
+ //
+ if( !CurrentName->Initialize( "" ) ) {
+
+ return FALSE;
+ }
+
+ for( i = 0; i < CurrentLevel; i++ ) {
+
+ // There's no backslash before the first component (the drive);
+ // if the prefix ends in a backslash, don't add one. Otherwise,
+ // add a backslash.
+ //
+ if( i > 0 &&
+ CurrentName->QueryChAt( CurrentName->QueryChCount() - 1 ) != '\\' &&
+ !CurrentName->Strcat( BackSlash ) ) {
+
+ return FALSE;
+ }
+
+ // Add the next component
+ //
+ if( !CurrentName->Strcat( Components[i] ) ) {
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+ACLCONV::ReadNextAcl(
+ OUT PINT ExitCode,
+ OUT PWSTRING ResourceString,
+ IN ULONG MaxEntries,
+ OUT PULONG AccessEntryCount,
+ OUT PVOID AccessEntries,
+ OUT PUSHORT AuditInfo
+ )
+/*++
+
+Routine Description:
+
+ This method reads the next ACL record from the data file. The
+ ACL record describes the resource and its associated Access Control
+ Entries.
+
+Arguments:
+
+ ExitCode -- Receives an error level if an error occurs.
+ ResourceString -- Receives the name of the resource.
+ MaxEntries -- Supplies the maximum number of entries
+ that will fit in the supplied buffer.
+ AccessEntryCount -- Receives the number of access entries read.
+ AccessEntries -- Receives the access entries.
+ AuditInfo -- Receives the Lanman 2.x audit information
+ for the resource.
+
+
+
+Return Value:
+
+ TRUE upon successful completion. If the end of the file is
+ reached without error, this method returns FALSE, with *ExitCode
+ equal to zero.
+
+--*/
+{
+ CHAR ResourceName[ MAX_RESOURCE_NAME_LENGTH ];
+ WCHAR WideResourceName[ MAX_RESOURCE_NAME_LENGTH ];
+
+ lm20_resource_info ResourceInfo;
+ lm21_aclhdr Lm21Header;
+ lm21_aclrec Lm21AclRec;
+ ULONG BytesRead, TotalBytesRead;
+
+ if( _DataFileStream == NULL ) {
+
+ DebugAbort( "Data stream not set up.\n" );
+ return FALSE;
+ }
+
+
+ switch( _DataFileRevision ) {
+
+ case DataFileRevisionUnknown :
+
+ DebugAbort( "Trying to read from unknown data file revision.\n" );
+ *ExitCode = 1;
+ return FALSE;
+
+ case DataFileRevisionLanman20 :
+
+ if( _NextReadOffset == 0 ) {
+
+ // This is the first read, so we skip over the header
+ // information.
+
+ _NextReadOffset = LM20_BACKACC_HEADER_SIZE +
+ LM20_INDEX_SIZE * LM20_NINDEX;
+
+ }
+
+ if( !_DataFileStream->MovePointerPosition( _NextReadOffset,
+ STREAM_BEGINNING ) ) {
+
+ *ExitCode = 1;
+ return FALSE;
+ }
+
+ if( _DataFileStream->IsAtEnd() ) {
+
+ // No more entries to read.
+
+ *ExitCode = 0;
+ return FALSE;
+ }
+
+ // Read the resource header information.
+
+ if( !_DataFileStream->Read( (PBYTE)&ResourceInfo,
+ LM20_RESOURCE_INFO_HEADER_SIZE,
+ &BytesRead ) ||
+ BytesRead != LM20_RESOURCE_INFO_HEADER_SIZE ) {
+
+ *ExitCode = 1;
+ return FALSE;
+ }
+
+
+ // Read the name and initialize ResourceString
+ //
+ memset( WideResourceName, 0, sizeof( WideResourceName ) );
+
+ if( ResourceInfo.namelen > MAX_RESOURCE_NAME_LENGTH ||
+ !_DataFileStream->Read( (PBYTE)ResourceName,
+ ResourceInfo.namelen,
+ &BytesRead ) ||
+ BytesRead != ResourceInfo.namelen ||
+ !MultiByteToWideChar( _SourceCodepage,
+ 0,
+ ResourceName,
+ strlen( ResourceName ),
+ WideResourceName,
+ MAX_RESOURCE_NAME_LENGTH ) ||
+ !ResourceString->Initialize( WideResourceName ) ) {
+
+ *ExitCode = 1;
+ return FALSE;
+ }
+
+ // Read the access entries
+
+ if( (ULONG)ResourceInfo.acc1_count > MaxEntries ||
+ !_DataFileStream->Read( (PBYTE)AccessEntries,
+ ResourceInfo.acc1_count *
+ LM_ACCESS_LIST_SIZE,
+ &BytesRead ) ||
+ BytesRead != (ULONG)( ResourceInfo.acc1_count * LM_ACCESS_LIST_SIZE ) ) {
+
+ *ExitCode = 1;
+ return FALSE;
+ }
+
+ *AccessEntryCount = ResourceInfo.acc1_count;
+ *AuditInfo = ResourceInfo.acc1_attr;
+
+ _NextReadOffset += LM20_RESOURCE_INFO_HEADER_SIZE +
+ ResourceInfo.namelen +
+ ResourceInfo.acc1_count * LM_ACCESS_LIST_SIZE;
+
+ return TRUE;
+
+ case DataFileRevisionLanman21 :
+
+ while( _NextReadOffset == 0 || _BytesRemainingInCurrentGroup == 0 ) {
+
+ // The current offset is at the beginning of a group. If
+ // this also the end of the file, there are no more records
+ // to read; otherwise, read the header of this group.
+
+ if( !_DataFileStream->MovePointerPosition( _NextReadOffset,
+ STREAM_BEGINNING ) ) {
+
+ *ExitCode = 1;
+ return FALSE;
+ }
+
+ if( _DataFileStream->IsAtEnd() ) {
+
+ // No more entries to read.
+
+ *ExitCode = 0;
+ return FALSE;
+ }
+
+ if( !_DataFileStream->Read( (PBYTE)&Lm21Header,
+ LM21_ACLHDR_SIZE,
+ &BytesRead ) ||
+ BytesRead != LM21_ACLHDR_SIZE ) {
+
+ *ExitCode = 1;
+ return FALSE;
+ }
+
+ _NextReadOffset += LM21_ACLHDR_SIZE;
+ _BytesRemainingInCurrentGroup = Lm21Header.NxtHdr -
+ _NextReadOffset;
+ }
+
+ // Read the ACL Record
+
+ if( !_DataFileStream->Read( (PBYTE)&Lm21AclRec,
+ LM21_ACLREC_SIZE,
+ &BytesRead ) ||
+ BytesRead != LM21_ACLREC_SIZE ) {
+
+ *ExitCode = 1;
+ return FALSE;
+ }
+
+ TotalBytesRead = BytesRead;
+
+ // Read the name and initialize ResourceString
+
+ if( Lm21AclRec.NameBytes > MAX_RESOURCE_NAME_LENGTH ||
+ !_DataFileStream->Read( (PBYTE)ResourceName,
+ Lm21AclRec.NameBytes,
+ &BytesRead ) ||
+ BytesRead != (ULONG)Lm21AclRec.NameBytes ) {
+
+ *ExitCode = 1;
+ return FALSE;
+ }
+
+ if( !UpdateAndQueryCurrentLM21Name( Lm21AclRec.DirLvl,
+ ResourceName,
+ ResourceString ) ) {
+
+ *ExitCode = 1;
+ return FALSE;
+ }
+
+
+ TotalBytesRead += BytesRead;
+
+ // Read the access entries:
+ //
+ if( Lm21AclRec.AclCnt == -1 ) {
+
+ *AccessEntryCount = 0;
+ *AuditInfo = 0;
+
+ } else {
+
+ if( (ULONG)Lm21AclRec.AclCnt > MaxEntries ||
+ !_DataFileStream->Read( (PBYTE)AccessEntries,
+ Lm21AclRec.AclCnt *
+ LM_ACCESS_LIST_SIZE,
+ &BytesRead ) ||
+ BytesRead != (ULONG)( Lm21AclRec.AclCnt * LM_ACCESS_LIST_SIZE ) ) {
+
+ *ExitCode = 1;
+ return FALSE;
+ }
+
+ TotalBytesRead += BytesRead;
+
+ *AccessEntryCount = Lm21AclRec.AclCnt;
+ *AuditInfo = Lm21AclRec.AuditAttrib;
+ }
+
+
+ // Check that this read didn't overflow the current group--if
+ // it did, the file format is not as expected.
+
+ if( TotalBytesRead > _BytesRemainingInCurrentGroup ) {
+
+ *ExitCode = 1;
+ return FALSE;
+ }
+
+ _NextReadOffset += TotalBytesRead;
+ _BytesRemainingInCurrentGroup -= TotalBytesRead;
+
+
+ return TRUE;
+
+ default:
+
+ *ExitCode = 1;
+ return FALSE;
+
+ }
+}
+
+BOOLEAN
+ACLCONV::ReadAclWorkSids(
+ )
+{
+ WORD n_entries;
+ ULONG n_read;
+ ULONG i;
+ USHORT name_len;
+ WCHAR name[64];
+ DSTRING Name;
+ PSID pSid;
+ ULONG sid_len;
+
+ DSTRING Domain;
+
+ if (!Domain.Initialize("UserConv")) {
+ DisplayMessage(MSG_CONV_NO_MEMORY, ERROR_MESSAGE);
+ return FALSE;
+ }
+
+ if (!_AclWorkStream->Read((PUCHAR)&n_entries, sizeof(WORD), &n_read) ||
+ n_read != sizeof(WORD)) {
+ DisplayMessage(MSG_ACLCONV_DATAFILE_BAD_FORMAT, ERROR_MESSAGE,
+ "%W", _AclWorkPath.GetPathString());
+ return FALSE;
+ }
+
+ if (!_AclWorkSids.Initialize(n_entries)) {
+ DisplayMessage(MSG_CONV_NO_MEMORY, ERROR_MESSAGE);
+ return FALSE;
+ }
+
+ //
+ // Read each entry from the aclwork.dat file and add it to this
+ // sid cache.
+ //
+
+ for (i = 0; i < n_entries; ++i) {
+
+ // read the length of the name
+
+ if (!_AclWorkStream->Read((PUCHAR)&name_len, sizeof(name_len),
+ &n_read) || n_read != sizeof(name_len)) {
+
+ DisplayMessage(MSG_ACLCONV_DATAFILE_BAD_FORMAT, ERROR_MESSAGE,
+ "%W", _AclWorkPath.GetPathString());
+
+ return FALSE;
+ }
+
+ // read the name
+
+ if (!_AclWorkStream->Read((PUCHAR)name, name_len, &n_read) ||
+ n_read != name_len) {
+
+ DisplayMessage(MSG_ACLCONV_DATAFILE_BAD_FORMAT, ERROR_MESSAGE,
+ "%W", _AclWorkPath.GetPathString());
+
+ return FALSE;
+ }
+ name[name_len / sizeof(WCHAR)] = UNICODE_NULL;
+
+ if (!Name.Initialize(name)) {
+ DisplayMessage(MSG_CONV_NO_MEMORY, ERROR_MESSAGE);
+ return FALSE;
+ }
+
+ if (!_AclWorkStream->Read((PUCHAR)&sid_len, sizeof(sid_len), &n_read) ||
+ n_read != sizeof(sid_len)) {
+
+ DisplayMessage(MSG_ACLCONV_DATAFILE_BAD_FORMAT, ERROR_MESSAGE,
+ "%W", _AclWorkPath.GetPathString());
+
+ return FALSE;
+ }
+
+ pSid = (PSID)MALLOC(sid_len);
+ if (NULL == pSid) {
+ DisplayMessage(MSG_CONV_NO_MEMORY, ERROR_MESSAGE);
+
+ return FALSE;
+ }
+
+ if (!_AclWorkStream->Read((PUCHAR)pSid, sid_len, &n_read) ||
+ n_read != sid_len) {
+
+ DisplayMessage(MSG_ACLCONV_DATAFILE_BAD_FORMAT, ERROR_MESSAGE,
+ "%W", _AclWorkPath.GetPathString());
+
+ return FALSE;
+ }
+
+ DebugAssert(RtlValidSid(pSid));
+
+ if (!_AclWorkSids.CacheSid( &Domain, &Name, pSid, sid_len)) {
+ DisplayMessage(MSG_CONV_NO_MEMORY, ERROR_MESSAGE);
+ return FALSE;
+ }
+
+ FREE(pSid);
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/aclconv/aclconv.hxx b/private/utils/aclconv/aclconv.hxx
new file mode 100644
index 000000000..2d1d337e4
--- /dev/null
+++ b/private/utils/aclconv/aclconv.hxx
@@ -0,0 +1,321 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ aclconv.hxx
+
+Abstract:
+
+ This module contains declarations for the ACLCONV class, which
+ implements the ACL conversion program.
+
+Author:
+
+ Bill McJohn (billmc) 29-Jan-1992
+
+Revision History:
+
+
+--*/
+
+
+#if !defined (ACLCONV_DEFN)
+
+#define ACLCONV_DEFN
+
+#include "program.hxx"
+#include "path.hxx"
+#include "backacc.hxx"
+#include "convnode.hxx"
+#include "sidcache.hxx"
+
+enum _ACLCONV_DATA_FILE_REVISION {
+
+ DataFileRevisionUnknown,
+ DataFileRevisionLanman20,
+ DataFileRevisionLanman21
+};
+
+DEFINE_TYPE( _ACLCONV_DATA_FILE_REVISION, ACLCONV_DATA_FILE_REVISION );
+
+
+DECLARE_CLASS( FILE_STREAM );
+DECLARE_CLASS( FSN_FILE );
+DECLARE_CLASS( PATH );
+
+DECLARE_CLASS( ACLCONV );
+
+class ACLCONV : public PROGRAM {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( ACLCONV );
+
+ NONVIRTUAL
+ ~ACLCONV(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ OUT PINT ExitCode
+ );
+
+ NONVIRTUAL
+ INT
+ ConvertAcls(
+ );
+
+ NONVIRTUAL
+ INT
+ ListLogFile(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ LogConversion(
+ IN PPATH ResourceName,
+ IN ULONG ConversionCode,
+ IN ULONG LmAuditInfo,
+ IN ULONG AccessEntryCount,
+ IN PCULONG AceConversionCodes,
+ IN PCLM_ACCESS_LIST AccessEntries
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsInListMode(
+ ) CONST;
+
+ NONVIRTUAL
+ PCWSTRING
+ GetDomainName(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QuerySourceCodepage(
+ ) CONST;
+
+ NONVIRTUAL
+ PWSTR
+ GetSidLookupTableName(
+ );
+
+ NONVIRTUAL
+ PSID_CACHE
+ GetSidCache(
+ );
+
+ NONVIRTUAL
+ PSID_CACHE
+ GetAclWorkSids(
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ ACL_CONVERT_CODE
+ ConvertOneAcl(
+ IN LPSTR ResourceName,
+ IN ULONG AccessEntryCount,
+ IN PLM_ACCESS_LIST AccessEntries,
+ IN USHORT AuditInfo
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ParseArguments(
+ OUT PINT ExitCode
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DetermineDataFileRevision(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ReadNextLogRecord(
+ OUT PINT ExitCode,
+ OUT PWSTRING ResourceString,
+ OUT PULONG ConversionCode,
+ OUT PUSHORT AuditInfo,
+ IN ULONG MaxEntries,
+ OUT PULONG AccessEntryCount,
+ OUT PLM_ACCESS_LIST AccessEntries,
+ OUT PULONG AceConversionCodes
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ UpdateAndQueryCurrentLM21Name(
+ IN ULONG DirectoryLevel,
+ IN PCSTR NewComponent,
+ OUT PWSTRING CurrentName
+ );
+
+ BOOLEAN
+ DisplayAce(
+ IN ACL_CONVERT_CODE AclConvertCode,
+ IN ACE_CONVERT_CODE AceConvertCode,
+ IN PLM_ACCESS_LIST Ace
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ReadNextAcl(
+ OUT PINT ExitCode,
+ OUT PWSTRING ResourceString,
+ IN ULONG MaxEntries,
+ OUT PULONG AccessEntryCount,
+ OUT PVOID AccessEntries,
+ OUT PUSHORT AuditInfo
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ReadAclWorkSids(
+ );
+
+ BOOLEAN _IsInListMode;
+ PATH _DataFilePath;
+ PATH _LogFilePath;
+ PWSTRING _NewDrive;
+
+ ACLCONV_DATA_FILE_REVISION _DataFileRevision;
+ ULONG _NextReadOffset;
+ ULONG _BytesRemainingInCurrentGroup; //LM21 only
+
+ PFSN_FILE _DataFile;
+ PFILE_STREAM _DataFileStream;
+ PFSN_FILE _LogFile;
+ PFILE_STREAM _LogFileStream;
+
+ PATH _AclWorkPath;
+ PFSN_FILE _AclWorkFile;
+ PFILE_STREAM _AclWorkStream;
+
+ PACL_CONVERT_NODE _RootNode;
+ PWSTRING _DriveName;
+ PWSTRING _DomainName;
+ ULONG _SourceCodepage;
+
+ SID_CACHE _SidCache;
+ WCHAR _NameBuffer[ MAX_RESOURCE_NAME_LENGTH + 1 ];
+ PWCHAR _SidLookupTableName;
+
+ SID_CACHE _AclWorkSids;
+};
+
+
+INLINE
+BOOLEAN
+ACLCONV::IsInListMode(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method allows the client to determine whether
+ the ACLCONV object is in list mode, ie. that the
+ invoker wishes to list the log file.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the object is in List mode; false if it is not.
+
+--*/
+{
+ return _IsInListMode;
+}
+
+
+INLINE
+PCWSTRING
+ACLCONV::GetDomainName(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the domain name specified on the command line.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the domain name string; NULL if no domain was specified.
+
+--*/
+{
+ return _DomainName;
+}
+
+INLINE
+ULONG
+ACLCONV::QuerySourceCodepage(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the object's source codepage, ie. the
+ codepage associated with the BACKACC data file.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The object's source codepage.
+
+--*/
+{
+ return _SourceCodepage;
+}
+
+INLINE
+PWSTR
+ACLCONV::GetSidLookupTableName(
+ )
+{
+ return _SidLookupTableName;
+}
+
+INLINE
+PSID_CACHE
+ACLCONV::GetSidCache(
+ )
+{
+ return &_SidCache;
+}
+
+INLINE
+PSID_CACHE
+ACLCONV::GetAclWorkSids(
+ )
+{
+ return &_AclWorkSids;
+}
+
+#endif
diff --git a/private/utils/aclconv/aclconv.rc b/private/utils/aclconv/aclconv.rc
new file mode 100644
index 000000000..427d2cd10
--- /dev/null
+++ b/private/utils/aclconv/aclconv.rc
@@ -0,0 +1,24 @@
+#include <windows.h>
+#include <ntverp.h>
+#include "aclres.h"
+
+// Names for the administrator account and administrators group on
+// Lanman 2.x and NT.
+//
+STRINGTABLE BEGIN
+ IDS_ACLCONV_LANMAN_ADMIN_NAME "ADMIN"
+ IDS_ACLCONV_LANMAN_ADMINS_NAME "ADMINS"
+ IDS_ACLCONV_LANMAN_USERS_NAME "USERS"
+ IDS_ACLCONV_LANMAN_GUESTS_NAME "GUESTS"
+ IDS_ACLCONV_NT_ADMIN_NAME "Administrator"
+ IDS_ACLCONV_NT_ADMINS_NAME "Administrators"
+ IDS_ACLCONV_PAGEFILE_NAME "pagefile.sys"
+END
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Access Control List Conversion Utility"
+#define VER_INTERNALNAME_STR "aclconv\0"
+#define VER_ORIGINALFILENAME_STR "ACLCONV.EXE"
+
+#include "common.ver"
diff --git a/private/utils/aclconv/aclres.h b/private/utils/aclconv/aclres.h
new file mode 100644
index 000000000..c1dff11c2
--- /dev/null
+++ b/private/utils/aclconv/aclres.h
@@ -0,0 +1,10 @@
+
+// Strings used by ACLCONV.
+//
+#define IDS_ACLCONV_LANMAN_ADMIN_NAME 1
+#define IDS_ACLCONV_LANMAN_ADMINS_NAME 2
+#define IDS_ACLCONV_NT_ADMIN_NAME 3
+#define IDS_ACLCONV_NT_ADMINS_NAME 4
+#define IDS_ACLCONV_PAGEFILE_NAME 5
+#define IDS_ACLCONV_LANMAN_USERS_NAME 6
+#define IDS_ACLCONV_LANMAN_GUESTS_NAME 7
diff --git a/private/utils/aclconv/backacc.hxx b/private/utils/aclconv/backacc.hxx
new file mode 100644
index 000000000..f6ace432d
--- /dev/null
+++ b/private/utils/aclconv/backacc.hxx
@@ -0,0 +1,154 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ backacc.hxx
+
+Abstract:
+
+ This module contains declarations for structures used in the Lanman
+ Backacc utility data files.
+
+Author:
+
+ Bill McJohn (billmc) 29-Jan-1992
+
+Revision History:
+
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if !defined (BACKACC_FORMAT_DEFN)
+
+#define BACKACC_FORMAT_DEFN
+
+#include "lmconst.hxx"
+
+
+// This constant describes the amount of data that must be read from the
+// file to determine which revision of Backacc produced it. Note that
+// both revisions will produce a file at least this big, so it's safe
+// to read this much.
+
+CONST RecognitionSize = 29;
+
+
+// The Lanman access_list structure, used by both versions of Backacc.
+
+typedef struct _lm_access_list {
+
+ char acl_ugname[UNLEN+1];
+ char agl_ugname_pad_1;
+ USHORT acl_access;
+};
+
+DEFINE_TYPE( _lm_access_list, LM_ACCESS_LIST );
+
+#define LM_ACCESS_LIST_SIZE 24
+
+
+
+// Structure of the Lanman 2.0 BackAcc file:
+//
+// Header structure
+// NINDEX index structures (number used given in header)
+// resource info 0
+// list of access entries for resource 0
+// resource info 1
+// list of access entries for resource 1
+// ...
+//
+
+#define LM20_VOL_LABEL_SIZE 64
+#define LM20_MAX_KEY_LEN 24
+#define LM20_NINDEX 64
+
+
+CONST ULONG Lm20BackaccSignature = 0x08111961;
+
+
+typedef struct _lm20_backacc_header {
+
+ UCHAR back_id[4];
+ UCHAR vol_name[LM20_VOL_LABEL_SIZE + 1];
+ UCHAR nindex[2];
+ UCHAR nentries[2];
+ UCHAR level[2];
+ UCHAR nresource[4];
+};
+
+DEFINE_TYPE( _lm20_backacc_header, lm20_backacc_header );
+
+#define LM20_BACKACC_HEADER_SIZE 79
+
+
+// ACLCONV doesn't use this structure, but since it's part of the
+// data file format, it's here for reference.
+
+typedef struct _lm20_index {
+
+ UCHAR key [LM20_MAX_KEY_LEN];
+ ULONG offset;
+};
+
+#define LM20_INDEX_SIZE 28
+
+// The resource name follows the resource information; the trailing
+// null after the name is included in namelen.
+
+typedef struct _lm20_resource_info {
+
+ USHORT namelen; // Length of name, including trailing null
+ USHORT acc1_attr; // Audit info
+ USHORT acc1_count; // Number of LM_ACCESS_LIST entries which follow
+};
+
+DEFINE_TYPE( _lm20_resource_info, lm20_resource_info );
+
+#define LM20_RESOURCE_INFO_HEADER_SIZE 6
+
+
+// Structure of the LM2.1 backacc file.
+
+
+CONST Lm21BackaccSignatureOffset = 4;
+CONST Lm21BackaccSignatureLength = 13;
+CONST PCHAR Lm21BackaccSignature = "LM210 BACKACC";
+
+typedef struct _lm21_aclhdr {
+
+ LONG NxtHdr;
+ CHAR Version[Lm21BackaccSignatureLength];
+ CHAR Reserved;
+ CHAR VolLbl[12];
+};
+
+DEFINE_TYPE( _lm21_aclhdr, lm21_aclhdr );
+
+#define LM21_ACLHDR_SIZE 30
+
+// This AclRec is immediately followed by the resource name (NameBytes
+// long, including the terminating null.
+
+typedef struct _lm21_aclrec {
+
+ LONG NxtDirEnt;
+ SHORT DirLvl;
+ SHORT RecBytes;
+ SHORT AclCnt;
+ SHORT NameBytes;
+ USHORT FileAttrib;
+ USHORT AuditAttrib;
+};
+
+DEFINE_TYPE( _lm21_aclrec, lm21_aclrec );
+
+#define LM21_ACLREC_SIZE 16
+
+#endif
diff --git a/private/utils/aclconv/convnode.cxx b/private/utils/aclconv/convnode.cxx
new file mode 100644
index 000000000..db89a9184
--- /dev/null
+++ b/private/utils/aclconv/convnode.cxx
@@ -0,0 +1,2421 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ convnode.cxx
+
+Abstract:
+
+ This module contains member function definitions for the
+ ACL_CONVERT_NODE class, which models the nodes in the ACL
+ Conversion tree.
+
+
+Author:
+
+ Bill McJohn (billmc) 09-Feb-1992
+
+Revision History:
+
+
+--*/
+
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+#include "ulibcl.hxx"
+#include "error.hxx"
+#include "wstring.hxx"
+#include "file.hxx"
+#include "filestrm.hxx"
+#include "system.hxx"
+#include "dir.hxx"
+
+#include "convnode.hxx"
+#include "acehelp.hxx"
+
+#include "backacc.hxx"
+#include "logfile.hxx"
+#include "aclconv.hxx"
+#include "aclres.h"
+
+extern "C" {
+#include <stdio.h>
+}
+
+LM_ACCESS_LIST AdminsImplicitAce;
+BOOLEAN AdminsImplicitAceInitialized = FALSE;
+
+BOOLEAN
+CreateImplicitAce(
+ )
+/*++
+
+Routine Description:
+
+ This routine sets up the implicit ACE which grants ADMINS full
+ access to all resources. Under Lanman 2.x, this access is implicit;
+ under NT, it must be explicitly granted.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ CONST ULONG AdminsStringBufferLength = 32;
+ WCHAR AdminsStringBuffer[AdminsStringBufferLength];
+ FSTRING AdminsString;
+
+ if( AdminsImplicitAceInitialized ) {
+
+ return TRUE;
+ }
+
+ memset( &AdminsImplicitAce, 0, sizeof(AdminsImplicitAce) );
+
+ AdminsImplicitAce.agl_ugname_pad_1 = 0;
+ AdminsImplicitAce.acl_access = LM_ACCESS_ALL | LM_ACCESS_GROUP;
+
+ // Fetch the name as a resource and convert it to an eight-bit
+ // string.
+ //
+ if( LoadString( GetModuleHandle(NULL),
+ IDS_ACLCONV_LANMAN_ADMINS_NAME,
+ AdminsStringBuffer,
+ AdminsStringBufferLength ) == 0 ) {
+
+ DebugPrintf( "ACLCONV: LoadString failed--error %d.\n", GetLastError() );
+ return FALSE;
+ }
+
+ if( !AdminsString.Initialize( AdminsStringBuffer ) ||
+ !AdminsString.QuerySTR( 0,
+ TO_END,
+ AdminsImplicitAce.acl_ugname,
+ UNLEN+1 ) ) {
+
+ DebugPrintf( "ACLCONV: can't convert admins string to STR.\n" );
+ return FALSE;
+ }
+
+ AdminsImplicitAceInitialized = TRUE;
+ return TRUE;
+}
+
+
+BOOLEAN
+IsWindowsDir(
+ IN PCPATH ObjectPath
+ )
+/*++
+
+Routine Description:
+
+ This function determines whether the input canonical path is
+ the Windows NT path.
+
+Arguments:
+
+ ObjectPath -- Supplies the path in question.
+
+Return Value:
+
+ TRUE if ObjectPath represents the Windows NT Directory,
+ otherwise FALSE.
+
+--*/
+{
+ STATIC WCHAR DirBuffer[MAX_PATH];
+ STATIC BOOLEAN Initialized = FALSE;
+ FSTRING WindowsDirString;
+
+ if( !Initialized &&
+ GetWindowsDirectory( DirBuffer, MAX_PATH ) == 0 ) {
+
+ return FALSE;
+ }
+
+ Initialized = TRUE;
+
+ if( WindowsDirString.Initialize( DirBuffer ) &&
+ WindowsDirString.Stricmp( ObjectPath->GetPathString() ) == 0 ) {
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOL
+InitializeWellKnownSid(
+ IN ULONG SidId,
+ OUT PSID Sid,
+ IN OUT PULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This function is a worker for MyLookupAccountName. It fills in
+ a SID for one of the well-known users or groups pendant from
+ SECURITY_NT_AUTHORITY. These users and groups are:
+
+ Administrator
+ Guest
+ Administrators
+ Users
+ Guests
+
+Arguments:
+
+ SidId -- Supplies the well-known SID Identifier sub-authority
+ relative to SECURITY_BUILTIN_DOMAIN_RID. This may be:
+
+ DOMAIN_USER_RID_ADMIN
+ DOMAIN_USER_RID_GUEST
+ DOMAIN_ALIAS_RID_ADMINS
+ DOMAIN_ALIAS_RID_USERS
+ DOMAIN_ALIAS_RID_GUESTS
+
+ Sid -- Receives the new SID.
+ Length -- Supplies the length of the buffer; receives the
+ length of the SID. If the buffer is NULL or if
+ the length is not sufficient, *Length is set to
+ the required Length, but the function returns FALSE.
+
+Return Value:
+
+ TRUE upon successful completion. Note that *Length will be
+ set to the required length even if the function fails.
+
+--*/
+{
+ SID_IDENTIFIER_AUTHORITY IdentifierAuthority = SECURITY_NT_AUTHORITY;
+ ULONG LengthRequired;
+ NTSTATUS Status;
+
+ LengthRequired = RtlLengthRequiredSid( 2 );
+
+ if( *Length < LengthRequired ) {
+
+ *Length = LengthRequired;
+ return FALSE;
+ }
+
+ if( Sid != NULL ) {
+
+ Status = RtlInitializeSid( Sid, &IdentifierAuthority, 2 );
+
+ if( !NT_SUCCESS(Status) ) {
+
+ return FALSE;
+ }
+
+ *(RtlSubAuthoritySid( Sid, 0 )) = SECURITY_BUILTIN_DOMAIN_RID;
+ *(RtlSubAuthoritySid( Sid, 1 )) = SidId;
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+ }
+}
+
+BOOL
+AclconvLookupAccountName(
+ IN PACLCONV Aclconv,
+ IN PCWSTRING AccountName,
+ OUT PSID Sid,
+ OUT PULONG SidLength
+ )
+{
+ STATIC BOOLEAN Initialized = FALSE;
+ STATIC PDSTRING AdminString, AdminsString, UsersString,
+ GuestsString, BackSlash, CurrentDomain;
+
+ CONST ULONG StringBufferLength = 64;
+ WCHAR StringBuffer[StringBufferLength];
+
+ CONST DomainBufferLength = 0x80;
+ ULONG FoundDomainNameLength;
+ ULONG CachedSidLength;
+ WCHAR FoundDomainName[0x80];
+ SID_NAME_USE UserType;
+
+ DSTRING QualifiedName;
+ BOOLEAN Result;
+
+ if( !Initialized ) {
+
+ // Initialize the strings for the special names
+ //
+ if( (AdminString = NEW DSTRING) == NULL ||
+ (AdminsString = NEW DSTRING) == NULL ||
+ (UsersString = NEW DSTRING) == NULL ||
+ (GuestsString = NEW DSTRING) == NULL ||
+ (BackSlash = NEW DSTRING) == NULL ||
+ (CurrentDomain = NEW DSTRING) == NULL ) {
+
+
+ return FALSE;
+ }
+
+ if( LoadString( GetModuleHandle(NULL),
+ IDS_ACLCONV_LANMAN_ADMIN_NAME,
+ StringBuffer,
+ StringBufferLength ) == 0 ||
+ !AdminString->Initialize( StringBuffer ) ||
+ LoadString( GetModuleHandle(NULL),
+ IDS_ACLCONV_LANMAN_ADMINS_NAME,
+ StringBuffer,
+ StringBufferLength ) == 0 ||
+ !AdminsString->Initialize( StringBuffer ) ||
+ LoadString( GetModuleHandle(NULL),
+ IDS_ACLCONV_LANMAN_USERS_NAME,
+ StringBuffer,
+ StringBufferLength ) == 0 ||
+ !UsersString->Initialize( StringBuffer ) ||
+ LoadString( GetModuleHandle(NULL),
+ IDS_ACLCONV_LANMAN_GUESTS_NAME,
+ StringBuffer,
+ StringBufferLength ) == 0 ||
+ !GuestsString->Initialize( StringBuffer ) ||
+ !BackSlash->Initialize( "\\" ) ||
+ !CurrentDomain->Initialize( "" ) ) {
+
+ return FALSE;
+ }
+ }
+
+ Initialized = TRUE;
+
+ //
+ // Check for SIDs mapped by userconv.
+ //
+
+ DSTRING UserConvDomain;
+
+ if (!UserConvDomain.Initialize("UserConv")) {
+ return FALSE;
+ }
+
+ if (Aclconv->GetAclWorkSids()->IsNamePresent(&UserConvDomain,
+ AccountName, &CachedSidLength)) {
+
+ DebugAssert(CachedSidLength != 0);
+
+ if ( CachedSidLength > *SidLength ) {
+
+ // The client's buffer is not big enough.
+ //
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ *SidLength = CachedSidLength;
+ return FALSE;
+
+ } else {
+
+ // The name is in the cache and the client's buffer
+ // is big enough. Get it out:
+ //
+ return( Aclconv->GetAclWorkSids()->QueryCachedSid(&UserConvDomain,
+ AccountName,
+ Sid,
+ SidLength ) );
+ }
+ }
+
+ // Check for well-known SID's. Note that ADMIN is not mapped,
+ // since an account ADMIN is created by PORTUAS. (And a good
+ // thing, too, since generating the ADMIN SID would require
+ // accessing the Account Domain.)
+ //
+ if( AccountName->Stricmp( AdminsString ) == 0 ) {
+
+ return InitializeWellKnownSid( DOMAIN_ALIAS_RID_ADMINS, Sid, SidLength );
+ }
+
+ if( AccountName->Stricmp( UsersString ) == 0 ) {
+
+ return InitializeWellKnownSid( DOMAIN_ALIAS_RID_USERS, Sid, SidLength );
+ }
+
+ if( AccountName->Stricmp( GuestsString ) == 0 ) {
+
+ return InitializeWellKnownSid( DOMAIN_ALIAS_RID_GUESTS, Sid, SidLength );
+ }
+
+ // OK, it's not one of the well-known SID's.
+ //
+ // Check the cache:
+ //
+ if( Aclconv->GetSidCache()->IsNamePresent( Aclconv->GetDomainName(),
+ AccountName,
+ &CachedSidLength ) ) {
+
+ if( CachedSidLength == 0 ) {
+
+ // The name is present in the cache without a SID,
+ // which means we've looked for this name before and
+ // not found it.
+ //
+ SetLastError( ERROR_NONE_MAPPED );
+ return FALSE;
+
+ } else if ( CachedSidLength > *SidLength ) {
+
+ // The client's buffer is not big enough.
+ //
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ *SidLength = CachedSidLength;
+ return FALSE;
+
+ } else {
+
+ // The name is in the cache and the client's buffer
+ // is big enough. Get it out:
+ //
+ return( Aclconv->GetSidCache()->QueryCachedSid( Aclconv->GetDomainName(),
+ AccountName,
+ Sid,
+ SidLength ) );
+ }
+ }
+
+
+ // The SID we want isn't in the cache. If the client specified
+ // a domain, then look for the name in that domain. Otherwise,
+ // search the last domain in which a name was found; if that
+ // fails, search the world.
+ //
+ if( Aclconv->GetDomainName() ) {
+
+ if( !QualifiedName.Initialize( Aclconv->GetDomainName() ) ||
+ !QualifiedName.Strcat( BackSlash ) ||
+ !QualifiedName.Strcat( AccountName ) ) {
+
+ return FALSE;
+ }
+
+ FoundDomainNameLength = DomainBufferLength;
+ Result = LookupAccountName( NULL,
+ (PWSTR)QualifiedName.GetWSTR(),
+ Sid,
+ SidLength,
+ FoundDomainName,
+ &FoundDomainNameLength,
+ &UserType );
+
+ if( Result ) {
+
+ // Found the SID. Add the SID to the cache. Since
+ // the specified domain is global to ACLCONV, there's
+ // no need to maintain the current domain.
+ //
+ Aclconv->GetSidCache()->CacheSid( Aclconv->GetDomainName(),
+ AccountName,
+ Sid,
+ *SidLength );
+
+ } else if( GetLastError() == ERROR_NONE_MAPPED ) {
+
+ // There is no such user--record that fact in the cache.
+ //
+ Aclconv->GetSidCache()->CacheSid( Aclconv->GetDomainName(),
+ AccountName,
+ NULL,
+ 0 );
+ }
+
+ } else {
+
+ // Search the current domain, i.e. the last domain in which
+ // a search succeeded.
+ //
+ if( CurrentDomain->QueryChCount() ) {
+
+ // Construct a qualified name based on the current
+ // domain and search that domain.
+ //
+ if( !QualifiedName.Initialize( CurrentDomain ) ||
+ !QualifiedName.Strcat( BackSlash ) ||
+ !QualifiedName.Strcat( AccountName ) ) {
+
+ return FALSE;
+ }
+
+ FoundDomainNameLength = DomainBufferLength;
+ Result = LookupAccountName( NULL,
+ (PWSTR)QualifiedName.GetWSTR(),
+ Sid,
+ SidLength,
+ FoundDomainName,
+ &FoundDomainNameLength,
+ &UserType );
+
+ } else {
+
+ Result = FALSE;
+ SetLastError( ERROR_NONE_MAPPED );
+ }
+
+ if( !Result && GetLastError() == ERROR_NONE_MAPPED ) {
+
+ // This name isn't in the current domain (or there is no
+ // current domain). Do an unqualified search.
+ //
+ FoundDomainNameLength = DomainBufferLength;
+ Result = LookupAccountName( NULL,
+ (PWSTR)AccountName->GetWSTR(),
+ Sid,
+ SidLength,
+ FoundDomainName,
+ &FoundDomainNameLength,
+ &UserType );
+
+ if( !Result && GetLastError() == ERROR_NONE_MAPPED ) {
+
+ // This name does not exist in any trusted domain.
+ // Record that fact in the cache.
+ //
+ Aclconv->GetSidCache()->CacheSid( NULL, AccountName, NULL, 0 );
+ }
+ }
+
+ if( Result ) {
+
+ // This is a match. Record the current domain
+ // and cache the SID.
+ //
+ if( !CurrentDomain->Initialize( FoundDomainName,
+ FoundDomainNameLength ) ) {
+
+ SetLastError( ERROR_OUTOFMEMORY );
+ return FALSE;
+ }
+
+ Aclconv->GetSidCache()->CacheSid( CurrentDomain,
+ AccountName,
+ Sid,
+ *SidLength );
+ }
+ }
+
+ return Result;
+}
+
+
+BOOLEAN
+MapSpecialNames(
+ IN OUT PWSTRING Name,
+ OUT PBOOLEAN IsAdmin
+ )
+/*++
+
+Routine Description:
+
+ This method transforms special OS/2 names (ADMIN, ADMINS)
+ into their corresponding NT names (Administrator, Administrators).
+ Other strings are left unchanged.
+
+Arguments:
+
+ Name -- Supplies the name to map. Receives the result of
+ the transformation.
+ IsAdmin -- Receives TRUE if the name is the administrator account
+ or the administrators group.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ STATIC BOOLEAN Initialized = FALSE;
+ STATIC PWSTRING LmAdminName = NULL,
+ LmAdminsName = NULL,
+ NtAdminName = NULL,
+ NtAdminsName = NULL;
+
+ CONST ULONG StringBufferLength = 64;
+ WCHAR StringBuffer[StringBufferLength];
+
+ if( !Initialized ) {
+
+ if( (LmAdminName = NEW DSTRING) == NULL ||
+ (LmAdminsName = NEW DSTRING) == NULL ||
+ (NtAdminName = NEW DSTRING) == NULL ||
+ (NtAdminsName = NEW DSTRING) == NULL ||
+ LoadString( GetModuleHandle(NULL),
+ IDS_ACLCONV_LANMAN_ADMIN_NAME,
+ StringBuffer,
+ StringBufferLength ) == 0 ||
+ !LmAdminName->Initialize( StringBuffer ) ||
+ LoadString( GetModuleHandle(NULL),
+ IDS_ACLCONV_LANMAN_ADMINS_NAME,
+ StringBuffer,
+ StringBufferLength ) == 0 ||
+ !LmAdminsName->Initialize( StringBuffer ) ||
+ LoadString( GetModuleHandle(NULL),
+ IDS_ACLCONV_NT_ADMIN_NAME,
+ StringBuffer,
+ StringBufferLength ) == 0 ||
+ !NtAdminName->Initialize( StringBuffer ) ||
+ LoadString( GetModuleHandle(NULL),
+ IDS_ACLCONV_NT_ADMINS_NAME,
+ StringBuffer,
+ StringBufferLength ) == 0 ||
+ !NtAdminsName->Initialize( StringBuffer ) ) {
+
+ DELETE( LmAdminName );
+ DELETE( LmAdminsName );
+ DELETE( NtAdminName );
+ DELETE( NtAdminsName );
+ }
+
+ Initialized = TRUE;
+ }
+
+ if( LmAdminName == NULL ) {
+
+ return FALSE;
+ }
+
+ *IsAdmin = FALSE;
+
+ if( Name->Stricmp( LmAdminName ) == 0 ) {
+
+ *IsAdmin = TRUE;
+ return( Name->Initialize( NtAdminName ) );
+
+ } else if( Name->Stricmp( LmAdminsName ) == 0 ) {
+
+ *IsAdmin = TRUE;
+ return( Name->Initialize( NtAdminsName ) );
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+BoilAcl(
+ IN PACL Source,
+ OUT PACL Dest,
+ IN ULONG MaxLength
+ )
+/*++
+
+Routine Description:
+
+ This function boils an ACL down to the mininum size.
+
+Arguments:
+
+ Source -- Supplies a pointer to the source ACL
+ Dest -- Supplies a pointer to the buffer in which the
+ reduced ACL will be constructed.
+ MaxLength -- Supplies the size (in bytes) of the destination buffer.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ ACL_SIZE_INFORMATION AclInfo;
+ ACL_REVISION_INFORMATION AclRevisionInfo;
+
+ PVOID CurrentAce;
+ ULONG CurrentAceIndex, AceSize;
+
+ if( !GetAclInformation( Source,
+ &AclInfo,
+ sizeof( ACL_SIZE_INFORMATION ),
+ AclSizeInformation ) ||
+ !GetAclInformation( Source,
+ &AclRevisionInfo,
+ sizeof( ACL_REVISION_INFORMATION ),
+ AclRevisionInformation ) ) {
+
+ DebugPrintf( "ACLCONV: GetAclInformation failed.\n" );
+ return FALSE;
+ }
+
+
+ // Make sure the ACL fits in the destination buffer.
+ //
+ if( AclInfo.AclBytesInUse > MaxLength ) {
+
+ return FALSE;
+ }
+
+
+ // Initialize the destination to be exactly the right size:
+ //
+ if( !InitializeAcl( Dest,
+ AclInfo.AclBytesInUse,
+ AclRevisionInfo.AclRevision ) ) {
+
+ DebugPrintf( "ACLCONV: InitializeAcl failed.\n" );
+ return FALSE;
+ }
+
+
+ if( AclInfo.AceCount == 0 ) {
+
+ // No ACE's to copy--we're done.
+ //
+ return TRUE;
+ }
+
+
+ // Determine the size of the ACE's in the source ACL:
+ //
+ AceSize = 0;
+
+ for( CurrentAceIndex = 0;
+ CurrentAceIndex < AclInfo.AceCount;
+ CurrentAceIndex++ ) {
+
+ if( !GetAce( Source, CurrentAceIndex, &CurrentAce ) ) {
+
+ DebugPrintf( "ACLCONV: GetAce failed.\n" );
+ return FALSE;
+ }
+
+ AceSize += ((PACE_HEADER)CurrentAce)->AceSize;
+ }
+
+ // Copy the ACE's:
+ //
+ if( !GetAce( Source, 0, &CurrentAce ) ) {
+
+ DebugPrintf( "ACLCONV: GetAce failed.\n" );
+ return FALSE;
+ }
+
+ if( !AddAce( Dest,
+ AclRevisionInfo.AclRevision,
+ 0,
+ CurrentAce,
+ AceSize ) ) {
+
+ DebugPrintf( "ACLCONV: AddAce failed.\n" );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+//
+// Definitions for class-data members.
+//
+
+BYTE ACL_CONVERT_NODE::_SelfRelativeSDBuffer[ SecurityDescriptorBufferSize ];
+BYTE ACL_CONVERT_NODE::_AbsoluteSDBuffer[ SecurityDescriptorBufferSize ];
+BYTE ACL_CONVERT_NODE::_AclWorkBuffer[ AclBufferSize ];
+BYTE ACL_CONVERT_NODE::_DaclBuffer[ AclBufferSize ];
+BYTE ACL_CONVERT_NODE::_SaclBuffer[ AclBufferSize ];
+BYTE ACL_CONVERT_NODE::_SystemAces[ SystemAceBufferSize ];
+
+DEFINE_CONSTRUCTOR( ACL_CONVERT_NODE, OBJECT );
+
+ACL_CONVERT_NODE::~ACL_CONVERT_NODE(
+ )
+/*++
+
+Routine Description:
+
+ This method is the destructor for this class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+VOID
+ACL_CONVERT_NODE::Construct(
+ )
+/*++
+
+Routine Description:
+
+ This method is the helper function for object construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _LanmanAclPresent = FALSE;
+ _AccessEntryCount = 0;
+ _AccessEntries = NULL;
+ _AceConversionResults = NULL;
+ _AuditInfo = 0;
+ _ChildIterator = NULL;
+}
+
+VOID
+ACL_CONVERT_NODE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This method cleans up the object in preparation for destruction
+ or reinitialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _LanmanAclPresent = FALSE;
+ _AccessEntryCount = 0;
+
+ FREE( _AccessEntries );
+ FREE( _AceConversionResults );
+
+ _AuditInfo = 0;
+
+ if( _ChildIterator != NULL ) {
+
+ DELETE( _ChildIterator );
+ _Children.DeleteAllMembers();
+ }
+}
+
+
+
+BOOLEAN
+ACL_CONVERT_NODE::Initialize(
+ IN PCWSTRING ComponentName,
+ IN BOOLEAN IsTransient
+ )
+/*++
+
+Routine Description:
+
+ This method prepares the object for use.
+
+Arguments:
+
+ ComponentName -- Supplies the component name (ie. last component
+ of the path) for this node.
+ IsTransient -- Supplies a flag indicating whether this
+ node is transient. A transient node is
+ created while the parent is being converted,
+ and may be deleted after it has been converted.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This class is reinitializable.
+
+--*/
+{
+ Destroy();
+
+ if( !_Children.Initialize() ||
+ (_ChildIterator = _Children.QueryIterator()) == NULL ||
+ !_ComponentName.Initialize( ComponentName ) ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ _IsTransient = IsTransient;
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+ACL_CONVERT_NODE::AddLanmanAcl(
+ IN ULONG AccessEntryCount,
+ IN PLM_ACCESS_LIST AccessEntries,
+ IN USHORT AuditInfo
+ )
+/*++
+
+Routine Description:
+
+ This method adds a set of Lanman 2.x access entries and audit
+ information to the node.
+
+Arguments:
+
+ AccessEntryCount -- Supplies the number of Lanman 2.x ACE's
+ to add.
+ AccessEntries -- Supplies the Lanman 2.x ACE's.
+ AuditInfo -- Supplies the audit information.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ PLM_ACCESS_LIST NewAccessEntries;
+ PULONG NewConversionResults;
+ ULONG NewAccessEntryCount, i;
+
+ // If the Lanman ACL has no entries and no audit information,
+ // then it can't be set (but the method succeeds).
+ //
+ if( AccessEntryCount == 0 && AuditInfo == 0 ) {
+
+ return TRUE;
+ }
+
+ if( AccessEntryCount != 0 ) {
+
+ NewAccessEntryCount = _AccessEntryCount + AccessEntryCount;
+
+ if( (NewAccessEntries =
+ (PLM_ACCESS_LIST)MALLOC( sizeof(LM_ACCESS_LIST) *
+ NewAccessEntryCount )) ==
+ NULL ||
+ (NewConversionResults =
+ (PULONG)MALLOC(sizeof(ULONG) * NewAccessEntryCount)) == NULL ) {
+
+ FREE( NewAccessEntries );
+ return FALSE;
+ }
+
+ if( _AccessEntryCount != 0 ) {
+
+ DebugPtrAssert( _AccessEntries );
+ DebugPtrAssert( _AceConversionResults );
+
+ memcpy( NewAccessEntries,
+ _AccessEntries,
+ sizeof(LM_ACCESS_LIST) * _AccessEntryCount );
+
+ memcpy( NewConversionResults,
+ _AceConversionResults,
+ sizeof(ULONG) * _AccessEntryCount );
+ }
+
+
+ memcpy( NewAccessEntries + _AccessEntryCount,
+ AccessEntries,
+ sizeof(LM_ACCESS_LIST) * AccessEntryCount );
+
+ for( i = _AccessEntryCount; i < NewAccessEntryCount; i++ ) {
+
+ NewConversionResults[i] = 0;
+ }
+
+ FREE( _AccessEntries );
+ FREE( _AceConversionResults );
+
+ _AccessEntries = NewAccessEntries;
+ _AceConversionResults = NewConversionResults;
+ _AccessEntryCount += AccessEntryCount;
+ }
+
+
+ if( AuditInfo != 0 ) {
+
+ _AuditInfo |= AuditInfo;
+ ConvertAuditBits( _AuditInfo,
+ &_DirSuccessfulAuditMask,
+ &_DirFailedAuditMask,
+ &_FileSuccessfulAuditMask,
+ &_FileFailedAuditMask );
+ }
+
+ _LanmanAclPresent = TRUE;
+
+ return TRUE;
+}
+
+
+
+PACL_CONVERT_NODE
+ACL_CONVERT_NODE::GetChild(
+ IN PCWSTRING SearchName
+ )
+/*++
+
+Routine Description:
+
+ This method searches the child list to find the
+ specified name.
+
+Arguments:
+
+ SearchName -- Supplies the name to find.
+
+Return Value:
+
+ If no child if found with the specified name, this method
+ return NULL. Otherwise, it returns the child with that name.
+
+Notes:
+
+ The child list is maintained in sorted order by Component Name.
+--*/
+{
+ PACL_CONVERT_NODE CurrentChild;
+ LONG CompareResult;
+
+ // Spin backwards through the list of children until I run out
+ // or find one that's less than or equal to the one I want.
+ //
+ _ChildIterator->Reset();
+
+ while( (CurrentChild =
+ (PACL_CONVERT_NODE)_ChildIterator->GetPrevious()) != NULL &&
+ (CompareResult = SearchName->Stricmp( CurrentChild->GetName())) < 0 );
+
+ if( CurrentChild == NULL || CompareResult != 0 ) {
+
+ return NULL;
+
+ } else {
+
+ return CurrentChild;
+ }
+}
+
+
+
+PACL_CONVERT_NODE
+ACL_CONVERT_NODE::AddChild(
+ IN PCWSTRING ChildComponentName,
+ IN BOOLEAN IsTransient
+ )
+/*++
+
+Routine Description:
+
+ This method adds a child node.
+
+Arguments:
+
+ ChildComponentName -- supplies the component name of the new child.
+ IsTransient -- Supplies a flag indicating whether this
+ node is transient. A transient node is
+ created while the parent is being converted,
+ and may be deleted after it has been converted.
+
+
+Return Value:
+
+ A pointer to the newly-created child node, or NULL to indicate
+ failure.
+
+Notes:
+
+ The child list is maintained in sorted order by Component Name.
+
+--*/
+{
+ PACL_CONVERT_NODE NewChild, CurrentChild;
+ LONG CompareResult;
+
+
+ if( (NewChild = NEW ACL_CONVERT_NODE) == NULL ||
+ !NewChild->Initialize( ChildComponentName, IsTransient ) ) {
+
+ DELETE( NewChild );
+ return FALSE;
+ }
+
+ // Spin backwards through the list of children until I run out or
+ // find one that's less than the one I want to add.
+
+ _ChildIterator->Reset();
+
+ while( (CurrentChild =
+ (PACL_CONVERT_NODE)_ChildIterator->GetPrevious()) != NULL &&
+ (CompareResult = ChildComponentName->Stricmp( CurrentChild->GetName())) < 0 );
+
+ // The iterator now points at the member after which I want to
+ // insert the new entry.
+ //
+ _ChildIterator->GetNext();
+
+ if( _Children.Insert( NewChild, _ChildIterator ) ) {
+
+ // Successfully inserted the new child into the list.
+
+ return NewChild;
+
+ } else {
+
+ // Couldn't insert the new child.
+
+ DELETE( NewChild );
+ return NULL;
+ }
+}
+
+BOOLEAN
+ACL_CONVERT_NODE::Convert(
+ IN OUT PPATH CurrentPath,
+ IN OUT PCINHERITANCE_BUFFER Inheritance,
+ IN OUT PACLCONV AclConv
+ )
+/*++
+
+Routine Description:
+
+ This method converts the Lanman 2.x ACL associated with this
+ node into an NT ACL.
+
+Arguments:
+
+ CurrentPath -- Supplies the path of this node's parent. This
+ node adds its own component name to the path,
+ passes it to its children, and then restores
+ it to its original state.
+ A value of NULL indicates that this node
+ is the root of the tree.
+
+ Inheritance -- Supplies the inhertied-aces buffer.
+ AclConv -- Supplies the program object for error logging.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ CONST ULONG PagefileNameBufferLength = 64;
+ WCHAR PagefileNameBuffer[PagefileNameBufferLength];
+
+ INHERITANCE_BUFFER NewInheritance;
+ DSTRING PagefileString;
+
+ PFSN_DIRECTORY DirFsn;
+ PFSN_FILE FileFsn;
+ PACL_CONVERT_NODE CurrentChild;
+
+ PCINHERITANCE_BUFFER InheritanceToUse;
+
+ BOOLEAN IsRoot, IsDir;
+ BOOLEAN NoError = TRUE;
+ BOOLEAN AclToConvert = FALSE;
+
+ // Short-circuit: files or directories named 'pagefile.sys'
+ // are ignored.
+ //
+ if( LoadString( GetModuleHandle(NULL),
+ IDS_ACLCONV_PAGEFILE_NAME,
+ PagefileNameBuffer,
+ PagefileNameBufferLength ) == 0 ) {
+
+ DebugPrintf( "ACLCONV: LoadString failed--error %d.\n", GetLastError() );
+ return FALSE;
+ }
+
+ if( !PagefileString.Initialize( PagefileNameBuffer ) ) {
+
+ DebugPrintf( "ACLCONV: Can't initialize PagefileNameString.\n" );
+ return FALSE;
+ }
+
+ if( PagefileString.Stricmp( &_ComponentName ) == 0 ) {
+
+ return TRUE;
+ }
+
+
+ // This node has an ACL to convert if it has an explicit Lanman
+ // ACL or if it has a non-empty inheritance.
+ //
+ if( _LanmanAclPresent ||
+ Inheritance->RecessiveDeniedLength != 0 ||
+ Inheritance->DominantDeniedLength != 0 ||
+ Inheritance->RecessiveAllowedLength != 0 ||
+ Inheritance->DominantAllowedLength != 0 ) {
+
+ AclToConvert = TRUE;
+ }
+
+ // Add the current component to the path. If this node is the root,
+ // create the path.
+ //
+ if( CurrentPath == NULL ) {
+
+ IsRoot = TRUE;
+
+ if( (CurrentPath = NEW PATH) == NULL ||
+ !CurrentPath->Initialize( &_ComponentName ) ) {
+
+ DebugPrint( "ACLCONV: Cannot initialize path object for root." );
+ return FALSE;
+ }
+
+ } else {
+
+ IsRoot = FALSE;
+
+ if( !CurrentPath->AppendBase( &_ComponentName ) ) {
+
+ DebugPrintf( "ACLCONV: Cannot append to path" );
+ return FALSE;
+ }
+ }
+
+ // Determine whether this node represents a file, a directory, or
+ // a non-existent object.
+
+ if( (DirFsn = SYSTEM::QueryDirectory( CurrentPath )) != NULL ) {
+
+ IsDir = TRUE;
+
+ // Fill in the rest of the children of this node, ie.
+ // those children that do not have an explicit Lanman
+ // ACL. If this node doesn't have an ACL to convert,
+ // don't bother expanding the children, since the
+ // children will only receive an empty inheritance.
+ //
+ if( AclToConvert && !ExpandChildren( DirFsn ) ) {
+
+ if( IsRoot ) {
+
+ DELETE( CurrentPath );
+
+ } else {
+
+ CurrentPath->TruncateBase();
+ }
+
+ return FALSE;
+ }
+
+ DELETE( DirFsn );
+ DirFsn = NULL;
+
+ } else if( (FileFsn = SYSTEM::QueryFile( CurrentPath )) != NULL ) {
+
+ IsDir = FALSE;
+
+ DELETE( FileFsn );
+ FileFsn = NULL;
+
+ } else {
+
+ // This resource does not exist. Note that fact in the
+ // log file and carry on. Note that this node is logged
+ // only if it has an associated Lanman ACL.
+ //
+ if( _LanmanAclPresent &&
+ !AclConv->LogConversion( CurrentPath,
+ ACL_CONVERT_RESOURCE_NOT_FOUND,
+ _AuditInfo,
+ _AccessEntryCount,
+ _AceConversionResults,
+ _AccessEntries ) ) {
+
+ DebugPrint( "ACLCONV--LogConversion failed.\n" );
+ NoError = FALSE;
+ }
+
+ // Clean up the path--delete it if this node allocated it,
+ // otherwise remove the last component.
+
+ if( IsRoot ) {
+
+ DELETE( CurrentPath );
+
+ } else {
+
+ CurrentPath->TruncateBase();
+ }
+
+ return NoError;
+ }
+
+
+ if( _LanmanAclPresent ) {
+
+ // This node has a Lanman 2.x ACL of its own, so it
+ // ignores the ACE's inherited from its parent and
+ // it starts a dynasty of its own.
+ //
+ NoError = QueryInheritance( AclConv, &NewInheritance, IsDir );
+
+ InheritanceToUse = &NewInheritance;
+
+ } else {
+
+ // This node does not have a Lanman 2.x ACL, so it
+ // just uses whatever it inherited from its parent.
+ //
+ InheritanceToUse = Inheritance;
+ }
+
+ // InheritanceToUse now points at the inheritance buffer
+ // with the NT ACE's that I want to attach to this file or
+ // directory and its descendants. Recurse into the children
+ // first, in case the ACE's I put on this object would prevent
+ // me from accessing the children.
+ //
+ if( NoError ) {
+
+ // Recurse into the children:
+
+ _ChildIterator->Reset();
+
+ while( (CurrentChild =
+ (PACL_CONVERT_NODE)_ChildIterator->GetNext()) != NULL &&
+ NoError ) {
+
+ NoError = CurrentChild->Convert( CurrentPath,
+ InheritanceToUse,
+ AclConv );
+ }
+ }
+
+ // Delete the transient children:
+ //
+ _ChildIterator->Reset();
+ CurrentChild = (PACL_CONVERT_NODE)_ChildIterator->GetNext();
+
+ while( CurrentChild != NULL ) {
+
+ if( CurrentChild->IsTransient() ) {
+
+ // This child is transient, and may be deleted.
+ //
+ _Children.Remove( _ChildIterator );
+ DELETE( CurrentChild );
+
+ CurrentChild = (PACL_CONVERT_NODE)_ChildIterator->GetCurrent();
+
+ } else {
+
+ // This child is not transient; keep it and go on
+ // to the next.
+ //
+ CurrentChild = (PACL_CONVERT_NODE)_ChildIterator->GetNext();
+ }
+ }
+
+ // If this object has an ACL to convert, attach the ACE's to
+ // this object.
+ //
+ if( AclToConvert && NoError ) {
+
+ NoError = AddAces( CurrentPath,
+ InheritanceToUse,
+ IsDir,
+ !_LanmanAclPresent );
+
+ if( !NoError &&
+ (GetLastError() == ERROR_FILE_NOT_FOUND ||
+ GetLastError() == ERROR_PATH_NOT_FOUND) ) {
+
+ // We can handle this error--log it.
+ //
+ if( _LanmanAclPresent &&
+ !AclConv->LogConversion( CurrentPath,
+ ACL_CONVERT_RESOURCE_NOT_FOUND,
+ _AuditInfo,
+ _AccessEntryCount,
+ _AceConversionResults,
+ _AccessEntries ) ) {
+
+ DebugPrint( "ACLCONV--LogConversion failed.\n" );
+ NoError = FALSE;
+
+ } else {
+
+ NoError = TRUE;
+ }
+ }
+ }
+
+
+ // Log the results of this conversion, if it didn't error out.
+ // Note that only those resources which have actual (not just
+ // inherited) ACL's are logged.
+
+ if( _LanmanAclPresent && NoError ) {
+
+ NoError = AclConv->LogConversion(CurrentPath,
+ ACL_CONVERT_SUCCESS,
+ _AuditInfo,
+ _AccessEntryCount,
+ _AceConversionResults,
+ _AccessEntries );
+ }
+
+ // Clean up the inheritance buffers:
+ //
+ if( _LanmanAclPresent ) {
+
+ FREE( NewInheritance.RecessiveDeniedAces );
+ FREE( NewInheritance.DominantDeniedAces );
+ FREE( NewInheritance.RecessiveAllowedAces );
+ FREE( NewInheritance.DominantAllowedAces );
+ }
+
+ // Clean up the path--delete it if this node allocated it, otherwise
+ // remove the last component.
+
+ if( IsRoot ) {
+
+ DELETE( CurrentPath );
+
+ } else {
+
+ CurrentPath->TruncateBase();
+ }
+
+
+ return NoError;
+}
+
+// The inheritance scratchpad provides a place to construct
+// and convert ACE's without having to calculate their size
+// in advance.
+//
+BYTE ScratchRecessiveDenied[ AclBufferSize ];
+BYTE ScratchDominantDenied[ AclBufferSize ];
+BYTE ScratchRecessiveAllowed[ AclBufferSize ];
+BYTE ScratchDominantAllowed[ AclBufferSize ];
+
+INHERITANCE_BUFFER InheritanceScratchpad =
+{
+ ScratchRecessiveDenied,
+ AclBufferSize,
+ 0,
+ ScratchDominantDenied,
+ AclBufferSize,
+ 0,
+ ScratchRecessiveAllowed,
+ AclBufferSize,
+ 0,
+ ScratchDominantAllowed,
+ AclBufferSize,
+ 0
+};
+
+
+
+BOOLEAN
+ACL_CONVERT_NODE::QueryInheritance(
+ IN PACLCONV AclConv,
+ IN OUT PINHERITANCE_BUFFER Inheritance,
+ IN BOOLEAN IsDir
+ )
+/*++
+
+Routine Description:
+
+ This method converts the Lanman 2.x ACL associated with
+ this node into a set of NT ACE's.
+
+Arguments:
+
+ AclConv -- Supplies the program object.
+ Inheritance -- Receives the converted ACE information.
+ IsDir -- Supplies a flag indicating whether the
+ node is a directory.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ PVOID RecessiveDenied, DominantDenied, RecessiveAllowed, DominantAllowed;
+ ULONG i;
+
+ // Set up the inheritance in a known state in case of error return.
+ //
+ memset( Inheritance, 0, sizeof( INHERITANCE_BUFFER ) );
+
+
+ if( !_LanmanAclPresent ) {
+
+ // This node does not have a Lanman 2.x ACL, so it
+ // cannot generate an inheritance.
+ //
+ return FALSE;
+ }
+
+ // Clear the scratch pad.
+ //
+ InheritanceScratchpad.RecessiveDeniedLength = 0;
+ InheritanceScratchpad.DominantDeniedLength = 0;
+ InheritanceScratchpad.RecessiveAllowedLength = 0;
+ InheritanceScratchpad.DominantAllowedLength = 0;
+
+ // Convert the Lanman 2.x ACL into the scratchpad. Since
+ // Admins have implicit access to all files in Lanman,
+ // toss in the implicit ACE for good measure.
+ //
+ if( !AdminsImplicitAceInitialized && !CreateImplicitAce() ) {
+
+ return FALSE;
+ }
+
+ ConvertOneAce( AclConv,
+ &InheritanceScratchpad,
+ &AdminsImplicitAce,
+ IsDir );
+
+ for( i = 0; i < _AccessEntryCount; i++ ) {
+
+ _AceConversionResults[i] = ConvertOneAce( AclConv,
+ &InheritanceScratchpad,
+ _AccessEntries + i,
+ IsDir );
+
+ if( _AceConversionResults[i] == ACE_CONVERT_ERROR ) {
+
+ DebugPrint( "ACLCONV: ConvertOneAce failed.\n" );
+ return FALSE;
+ }
+ }
+
+ // Now allocate buffers for the inheritance buffer
+ // under construction.
+ //
+ RecessiveDenied = MALLOC( InheritanceScratchpad.RecessiveDeniedLength );
+ DominantDenied = MALLOC( InheritanceScratchpad.DominantDeniedLength );
+ RecessiveAllowed = MALLOC( InheritanceScratchpad.RecessiveAllowedLength );
+ DominantAllowed = MALLOC( InheritanceScratchpad.DominantAllowedLength );
+
+ if( RecessiveDenied == NULL || DominantDenied == NULL ||
+ RecessiveAllowed == NULL || DominantAllowed == NULL ) {
+
+ FREE( RecessiveDenied );
+ FREE( DominantDenied );
+ FREE( RecessiveAllowed );
+ FREE( DominantAllowed );
+
+ return FALSE;
+ }
+
+ // Copy information into the new buffers and set up the
+ // inheritance buffer for return.
+ //
+ memmove( RecessiveDenied,
+ InheritanceScratchpad.RecessiveDeniedAces,
+ InheritanceScratchpad.RecessiveDeniedLength );
+
+ memmove( DominantDenied,
+ InheritanceScratchpad.DominantDeniedAces,
+ InheritanceScratchpad.DominantDeniedLength );
+
+ memmove( RecessiveAllowed,
+ InheritanceScratchpad.RecessiveAllowedAces,
+ InheritanceScratchpad.RecessiveAllowedLength );
+
+ memmove( DominantAllowed,
+ InheritanceScratchpad.DominantAllowedAces,
+ InheritanceScratchpad.DominantAllowedLength );
+
+ Inheritance->RecessiveDeniedAces = RecessiveDenied;
+ Inheritance->RecessiveDeniedMaxLength = InheritanceScratchpad.RecessiveDeniedLength;
+ Inheritance->RecessiveDeniedLength = InheritanceScratchpad.RecessiveDeniedLength;
+
+ Inheritance->DominantDeniedAces = DominantDenied;
+ Inheritance->DominantDeniedMaxLength = InheritanceScratchpad.DominantDeniedLength;
+ Inheritance->DominantDeniedLength = InheritanceScratchpad.DominantDeniedLength;
+
+ Inheritance->RecessiveAllowedAces = RecessiveAllowed;
+ Inheritance->RecessiveAllowedMaxLength = InheritanceScratchpad.RecessiveAllowedLength;
+ Inheritance->RecessiveAllowedLength = InheritanceScratchpad.RecessiveAllowedLength;
+
+ Inheritance->DominantAllowedAces = DominantAllowed;
+ Inheritance->DominantAllowedMaxLength = InheritanceScratchpad.DominantAllowedLength;
+ Inheritance->DominantAllowedLength = InheritanceScratchpad.DominantAllowedLength;
+
+ return TRUE;
+}
+
+
+ACE_CONVERT_CODE
+ACL_CONVERT_NODE::ConvertOneAce(
+ IN PACLCONV AclConv,
+ IN OUT PINHERITANCE_BUFFER Inheritance,
+ IN PLM_ACCESS_LIST AccessEntry,
+ IN BOOLEAN IsDir
+ )
+/*++
+
+Routine Description:
+
+ This method converts a single Lanman ACE.
+
+Arguments:
+
+ AclConv -- Supplies the program object.
+ Inheritance -- Supplies the buffers for the converted ACE's.
+ This method will add ACE's to this buffer.
+ AccessEntry -- Supplies the Lanman 2.x access entry.
+ IsDir -- Supplies a flag indicating (if TRUE) that
+ this node represents a directory.
+
+Return Value:
+
+ An ACE_CONVERT_CODE indicating the result of this conversion.
+
+--*/
+{
+ CONST SidBufferLength = 128;
+ STATIC BYTE SidBuffer[SidBufferLength];
+
+ WCHAR NameBuffer[ UNLEN + 1 ];
+ DSTRING NameString;
+
+ PSID Sid;
+ ULONG SidLength, OldListLength,
+ NewAceLength, TargetBufferLength;
+ BOOLEAN NoAccess;
+ ACCESS_MASK DirAccessMask, FileAccessMask;
+ ACE_CONVERT_CODE Result;
+ UCHAR InheritBits;
+ PVOID TargetBuffer;
+ BOOLEAN AddFailed = FALSE;
+
+
+ // Set up the name in a UNICODE buffer. If it is a
+ // special name, remap it.
+ //
+ memset( NameBuffer, 0, sizeof( NameBuffer ) );
+
+ if( !MultiByteToWideChar( AclConv->QuerySourceCodepage(),
+ 0,
+ AccessEntry->acl_ugname,
+ strlen( AccessEntry->acl_ugname ),
+ NameBuffer,
+ UNLEN + 1 ) ||
+ !NameString.Initialize( NameBuffer ) ) {
+
+ return ACE_CONVERT_ERROR;
+ }
+
+ // Set NoAccess to TRUE if this is an ACE that grants no
+ // access rights. For individuals, such ACE's become
+ // Accessed-Denied ACE's, for groups they're no-ops.
+
+ NoAccess = ((AccessEntry->acl_access & ~LM_ACCESS_GROUP) == 0);
+
+ if( NoAccess && (AccessEntry->acl_access & LM_ACCESS_GROUP) ) {
+
+ // This is an ACE which grants no permissions to a group--
+ // drop it.
+
+ return ACE_CONVERT_DROPPED;
+ }
+
+
+ // Get the SID for this user.
+ //
+ Sid = (PSID)SidBuffer;
+ SidLength = SidBufferLength;
+
+ if( !AclconvLookupAccountName( AclConv,
+ &NameString,
+ Sid,
+ &SidLength ) ) {
+
+ if( GetLastError() == ERROR_NONE_MAPPED ) {
+
+ return ACE_CONVERT_SID_NOT_FOUND;
+
+ } else {
+
+ return ACE_CONVERT_ERROR;
+ }
+ }
+
+ // Create NT Access Masks that correspond to the Lanman access
+ // mask in this ACE. Note that there are two versions, one for
+ // directories and one for files.
+
+ ConvertAccessMasks( AccessEntry->acl_access,
+ &DirAccessMask,
+ &FileAccessMask );
+
+
+ // Assume the worst:
+
+ Result = ACE_CONVERT_ERROR;
+
+ if( IsDir &&
+ DirAccessMask != FileAccessMask ) {
+
+ // This object is a directory, and this ACE will be inherited
+ // differently by files and subdirectories. Therefore, I need
+ // to create two ACE's--one with the OBJECT_INHERIT_ACE and
+ // INHERIT_ONLY_ACE bits set (to pass on to files), the other
+ // with the CONTAINER_INHERIT_ACE bit set (to pass on to
+ // directories). The former goes on the recessive ACE list,
+ // the latter on the dominant ACE list.
+
+ if( NoAccess ) {
+
+ // This is an access-denied ACE. Save the current length
+ // of the list of recessive access-denied ACE's in case
+ // I have to restore it.
+
+ OldListLength = Inheritance->RecessiveDeniedLength;
+
+ TargetBuffer = (PBYTE)Inheritance->RecessiveDeniedAces +
+ Inheritance->RecessiveDeniedLength;
+
+ TargetBufferLength = Inheritance->RecessiveDeniedMaxLength -
+ Inheritance->RecessiveDeniedLength;
+
+ if( CreateAccessDeniedAce( TargetBuffer,
+ TargetBufferLength,
+ FileAccessMask,
+ OBJECT_INHERIT_ACE | INHERIT_ONLY_ACE,
+ Sid,
+ &NewAceLength ) ) {
+
+ // Successfully added the recessive ACE; update the
+ // length of the recessive list and then add the
+ // dominant ACE.
+
+ Inheritance->RecessiveDeniedLength += NewAceLength;
+
+ TargetBuffer = (PBYTE)Inheritance->DominantDeniedAces +
+ Inheritance->DominantDeniedLength;
+
+ TargetBufferLength =
+ Inheritance->DominantDeniedMaxLength -
+ Inheritance->DominantDeniedLength;
+
+ if( CreateAccessDeniedAce( TargetBuffer,
+ TargetBufferLength,
+ DirAccessMask,
+ CONTAINER_INHERIT_ACE,
+ Sid,
+ &NewAceLength ) ) {
+
+ // Update the length of the dominant list to
+ // include the new ACE.
+
+ Inheritance->DominantDeniedLength += NewAceLength;
+
+ Result = ACE_CONVERT_SUCCESS;
+
+ } else {
+
+ // Couldn't add the dominant ACE--back out the
+ // recessive ACE by restoring the original length
+ // of the recessive list.
+
+ Inheritance->RecessiveDeniedLength = OldListLength;
+ }
+ }
+
+ } else {
+
+ // This is an access-allowed ACE. Save the current length
+ // of the list of recessive access-allowed ACE's in case
+ // I have to restore it.
+ //
+ OldListLength = Inheritance->RecessiveAllowedLength;
+
+ // If the file mask is non-zero, create the corresponding
+ // recessive access-allowed ACE.
+ //
+ if( FileAccessMask != 0 ) {
+
+ TargetBuffer = (PBYTE)Inheritance->RecessiveAllowedAces +
+ Inheritance->RecessiveAllowedLength;
+
+ TargetBufferLength = Inheritance->RecessiveAllowedMaxLength -
+ Inheritance->RecessiveAllowedLength;
+
+ if( CreateAccessAllowedAce( TargetBuffer,
+ TargetBufferLength,
+ FileAccessMask,
+ OBJECT_INHERIT_ACE | INHERIT_ONLY_ACE,
+ Sid,
+ &NewAceLength ) ) {
+
+ // Successfully added the recessive ACE; update the
+ // length of the recessive list
+ //
+ Inheritance->RecessiveAllowedLength += NewAceLength;
+
+ } else {
+
+ AddFailed = TRUE;
+ }
+ }
+
+ if( !AddFailed && DirAccessMask != 0 ) {
+
+ TargetBuffer = (PBYTE)Inheritance->DominantAllowedAces +
+ Inheritance->DominantAllowedLength;
+
+ TargetBufferLength =
+ Inheritance->DominantAllowedMaxLength -
+ Inheritance->DominantAllowedLength;
+
+ if( CreateAccessAllowedAce( TargetBuffer,
+ TargetBufferLength,
+ DirAccessMask,
+ CONTAINER_INHERIT_ACE,
+ Sid,
+ &NewAceLength ) ) {
+
+ // Update the length of the dominant list to
+ // include the new ACE.
+
+ Inheritance->DominantAllowedLength += NewAceLength;
+
+ } else {
+
+ // Couldn't add the dominant ACE--back out the
+ // recessive ACE by restoring the original length
+ // of the recessive list.
+
+ Inheritance->RecessiveAllowedLength = OldListLength;
+ AddFailed = TRUE;
+ }
+ }
+
+ if( !AddFailed ) {
+
+ Result = ACE_CONVERT_SUCCESS;
+ }
+ }
+
+ } else {
+
+ // Either this is object is a file, in which case this ACE will
+ // never be inherited by anything, or inheritance of this ACE
+ // is unaffected by whether the child is a file or directory.
+ // Therefore, I only need to create one ACE. If this object is
+ // a directory, create an ACE with the OBJECT_INHERIT_ACE and
+ // CONTAINER_INHERIT_ACE bits set; if it's a file, create it
+ // with no inherit bits set. The new ACE goes on the appropriate
+ // dominant list (since it applies to the current object as
+ // well as its descendants).
+ //
+ // If this ACE is an ACCESS_ALLOWED ACE that grants no access,
+ // omit it.
+
+ InheritBits = ( IsDir ?
+ (OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE) :
+ 0 );
+
+ if( NoAccess ) {
+
+ // Add an Access Denied ACE to the inherited list of
+ // dominant access denied ACE's.
+
+ TargetBuffer = (PBYTE)Inheritance->DominantDeniedAces +
+ Inheritance->DominantDeniedLength;
+
+ TargetBufferLength = Inheritance->DominantDeniedMaxLength -
+ Inheritance->DominantDeniedLength;
+
+ if( CreateAccessDeniedAce( TargetBuffer,
+ TargetBufferLength,
+ FileAccessMask,
+ InheritBits,
+ Sid,
+ &NewAceLength ) ) {
+
+ // Update the state of the list to show that a new
+ // ACE was successful added.
+
+ Inheritance->DominantDeniedLength += NewAceLength;
+ Result = ACE_CONVERT_SUCCESS;
+ }
+
+ } else if( FileAccessMask == 0 ) {
+
+ // This is an ACCESS_ALLOWED ACE that grants no access--
+ // it can be safely ignored.
+ //
+ Result = ACE_CONVERT_SUCCESS;
+
+ } else {
+
+ // Add an Access Allowed ACE to the inherited list of
+ // dominant access allowed ACE's.
+
+ TargetBuffer = (PBYTE)Inheritance->DominantAllowedAces +
+ Inheritance->DominantAllowedLength;
+
+ TargetBufferLength = Inheritance->DominantAllowedMaxLength -
+ Inheritance->DominantAllowedLength;
+
+ if( CreateAccessAllowedAce( TargetBuffer,
+ TargetBufferLength,
+ FileAccessMask,
+ InheritBits,
+ Sid,
+ &NewAceLength ) ) {
+
+ // Update the state of the list to show that a new ACE
+ // was successfully added.
+
+ Inheritance->DominantAllowedLength += NewAceLength;
+ Result = ACE_CONVERT_SUCCESS;
+ }
+ }
+ }
+
+ return Result;
+}
+
+
+BOOLEAN
+ACL_CONVERT_NODE::AddAces(
+ IN PCPATH ResourceName,
+ IN PCINHERITANCE_BUFFER Inheritance,
+ IN BOOLEAN IsDir,
+ IN BOOLEAN ByDefault
+ )
+/*++
+
+Routine Description:
+
+ This method adds the ACE's in the inheritance buffer to the
+ resource represented by this node.
+
+Arguments:
+
+ ResourceName -- Supplies the path of the resource represented
+ by this node.
+ Inheritance -- Supplies the buffer with ACE's to add.
+ IsDir -- Supplies a flag which indicates, if TRUE,
+ that this resource is a directory.
+ ByDefault -- Supplies a flag which indicates, if TRUE,
+ that the ACE's being added are all inherited.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ SECURITY_DESCRIPTOR AbsoluteSD;
+
+ PCWSTRING PathString;
+ PSECURITY_DESCRIPTOR SelfRelativeSD;
+ PACL NewDacl, NewSacl, BoiledDacl, BoiledSacl;
+
+ SECURITY_INFORMATION RequestedInformation;
+ ACCESS_MASK SuccessfulAuditMask, FailedAuditMask;
+ ULONG SelfRelativeSDLength,
+ SystemAcesLength,
+ NewAceLength;
+ BOOLEAN EditSacl, EditDacl;
+
+ // Check to see if there's actually anything to do:
+ //
+ EditSacl = (_AuditInfo != 0);
+
+ EditDacl = ( Inheritance->DominantDeniedLength != 0 ||
+ Inheritance->DominantAllowedLength != 0 ||
+ (IsDir && Inheritance->RecessiveDeniedLength != 0) ||
+ (IsDir && Inheritance->RecessiveAllowedLength != 0) );
+
+ if( !EditSacl && !EditDacl ) {
+
+ // There's nothing to be done to this resource--short circuit.
+
+ return TRUE;
+ }
+
+ // If this is the Windows NT Directory, silently return.
+ //
+ if( IsWindowsDir( ResourceName ) ) {
+
+ return TRUE;
+ }
+
+ // Get the name of the resource as a WSTR so I can feed
+ // it to the Win32 API.
+
+ if( (PathString = ResourceName->GetPathString()) == NULL ||
+ PathString->QueryChCount() > MAX_RESOURCE_NAME_LENGTH ) {
+
+ DebugPrintf( "ACLCONV: Unable to query path string.\n" );
+ return FALSE;
+ }
+
+
+ RequestedInformation = 0;
+
+ if( EditSacl ) {
+
+ RequestedInformation |= SACL_SECURITY_INFORMATION;
+ }
+
+ if ( EditDacl ) {
+
+
+ RequestedInformation |= DACL_SECURITY_INFORMATION;
+ }
+
+
+ // Get the existing security information for this resource,
+ // in self-relative format.
+
+ // NOTE -- because of the behaviour or GetFileSecurity,
+ // I always request the owner so that I won't get abused in
+ // the case where the file has no ACL. If this is a bug
+ // in the security API, then I can take this owner thing
+ // out when that bug gets fixed.
+ //
+ SelfRelativeSD = (PSECURITY_DESCRIPTOR)_SelfRelativeSDBuffer;
+
+ if( !GetFileSecurity( (PWSTR)PathString->GetWSTR(),
+ RequestedInformation | OWNER_SECURITY_INFORMATION,
+ SelfRelativeSD,
+ SecurityDescriptorBufferSize,
+ &SelfRelativeSDLength ) ||
+ SelfRelativeSDLength > SecurityDescriptorBufferSize ) {
+
+ DebugPrintf( "ACLCONV: GetFileSecurity failed (error %d).\n", GetLastError() );
+ return FALSE;
+ }
+
+ // Create a new security descriptor in Absolute format,
+ // to which a new SACL and/or DACL will be attached as
+ // needed.
+ //
+ if( !InitializeSecurityDescriptor( &AbsoluteSD,
+ SECURITY_DESCRIPTOR_REVISION ) ) {
+
+ DebugPrintf( "ACLCONV: InitializeSecurityDescriptor failed.\n" );
+ return FALSE;
+ }
+
+ if( EditSacl ) {
+
+ // Create a new SACL for this file or directory.
+ //
+ NewSacl = (PACL)_AclWorkBuffer;
+
+ if( !InitializeAcl( NewSacl, AclBufferSize, ACL_REVISION ) ) {
+
+ return FALSE;
+ }
+
+ // Create the appropriate System Audit ACEs for this beast.
+ // First, determine which pair of audit masks to use.
+
+ if( IsDir ) {
+
+ SuccessfulAuditMask = _DirSuccessfulAuditMask;
+ FailedAuditMask = _DirFailedAuditMask;
+
+ } else {
+
+ SuccessfulAuditMask = _FileSuccessfulAuditMask;
+ FailedAuditMask = _FileFailedAuditMask;
+ }
+
+ // Now create the system audit ACE's in the _SystemAces buffer.
+ // (Static to this class).
+ //
+ SystemAcesLength = 0;
+ NewAceLength = 0;
+
+ if( SuccessfulAuditMask != 0 &&
+ !CreateSystemAuditAce( _SystemAces,
+ SystemAceBufferSize,
+ SuccessfulAuditMask,
+ 0,
+ FALSE,
+ &NewAceLength ) ) {
+
+ return FALSE;
+ }
+
+ SystemAcesLength += NewAceLength;
+ NewAceLength = 0;
+
+ if( FailedAuditMask != 0 &&
+ !CreateSystemAuditAce( (PBYTE)_SystemAces + SystemAcesLength,
+ SystemAceBufferSize - SystemAcesLength,
+ FailedAuditMask,
+ 0,
+ TRUE,
+ &NewAceLength ) ) {
+
+ return FALSE;
+ }
+
+ SystemAcesLength += NewAceLength;
+
+ // Add the newly-created system audit aces to the SACL.
+
+ if( SystemAcesLength != 0 &&
+ !AddAce( NewSacl,
+ ACL_REVISION,
+ MAXULONG,
+ _SystemAces,
+ SystemAcesLength ) ) {
+
+ return FALSE;
+ }
+
+ // Boil the SACL down to its minimum size and attach
+ // it to the security descriptor.
+ //
+ BoiledSacl = (PACL)_SaclBuffer;
+
+ if( !BoilAcl( NewSacl, BoiledSacl, AclBufferSize ) ) {
+
+ return FALSE;
+ }
+
+ if( !SetSecurityDescriptorSacl( &AbsoluteSD,
+ TRUE,
+ BoiledSacl,
+ ByDefault ) ) {
+
+ DebugPrintf( "ACLCONV: SetSecurityDescriptorSacl failed (error %d).\n", GetLastError() );
+ return FALSE;
+ }
+ }
+
+ if( EditDacl ) {
+
+ // Create a new DACL for the file or directory.
+ //
+ NewDacl = (PACL)_AclWorkBuffer;
+
+ if( !InitializeAcl( NewDacl, AclBufferSize, ACL_REVISION ) ) {
+
+ DebugPrintf( "ACLCONV: InitializeAcl failed.\n" );
+ return FALSE;
+ }
+
+
+ // Copy in the new Access Denied ACE's...
+ //
+ if( ( IsDir &&
+ Inheritance->RecessiveDeniedLength != 0 &&
+ !AddAce( NewDacl,
+ ACL_REVISION,
+ MAXULONG,
+ Inheritance->RecessiveDeniedAces,
+ Inheritance->RecessiveDeniedLength ) ) ||
+ ( Inheritance->DominantDeniedLength != 0 &&
+ !AddAce( NewDacl,
+ ACL_REVISION,
+ MAXULONG,
+ Inheritance->DominantDeniedAces,
+ Inheritance->DominantDeniedLength ) ) ) {
+
+ DebugPrintf( "ACLCONV: Cannot add access-denied ACE's\n" );
+ return FALSE;
+ }
+
+ // ... and the new Access Allowed ACE's:
+ //
+ if( ( IsDir &&
+ Inheritance->RecessiveAllowedLength != 0 &&
+ !AddAce( NewDacl,
+ ACL_REVISION,
+ MAXULONG,
+ Inheritance->RecessiveAllowedAces,
+ Inheritance->RecessiveAllowedLength ) ) ||
+ ( Inheritance->DominantAllowedLength != 0 &&
+ !AddAce( NewDacl,
+ ACL_REVISION,
+ MAXULONG,
+ Inheritance->DominantAllowedAces,
+ Inheritance->DominantAllowedLength ) ) ) {
+
+ DebugPrintf( "ACLCONV: Cannot add access-allowed ACE's\n" );
+ return FALSE;
+ }
+
+
+ // Boil the DACL down to its minimum size:
+ //
+ BoiledDacl = (PACL)_DaclBuffer;
+
+ if( !BoilAcl( NewDacl, BoiledDacl, AclBufferSize ) ) {
+
+ return FALSE;
+ }
+
+ // Attach the new DACL to the Absolute Security Descriptor.
+ //
+ if( !SetSecurityDescriptorDacl( &AbsoluteSD,
+ TRUE,
+ BoiledDacl,
+ ByDefault ) ) {
+
+ DebugPrintf( "ACLCONV: SetSecurityDescriptorDacl failed (error %d).\n", GetLastError() );
+ return FALSE;
+ }
+ }
+
+ // Save the security descriptor on the file.
+ //
+ if( !SetFileSecurity( (PWSTR)PathString->GetWSTR(),
+ RequestedInformation,
+ &AbsoluteSD ) ) {
+
+ DebugPrintf( "ACLCONV: SetFileSecurity failed (error %d).\n", GetLastError() );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+ACL_CONVERT_NODE::ExpandChildren(
+ PFSN_DIRECTORY DirFsn
+ )
+/*++
+
+Routine Description:
+
+ This method expands the child list to include all children
+ of this directory. Newly-created child nodes are marked
+ as transient.
+
+Arguments:
+
+ DirFsn -- Provides the Directory FSNode object for this
+ node.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ PARRAY FsNodeArray = NULL;
+ PITERATOR Iterator = NULL;
+ PWSTRING ChildName = NULL;
+ PFSNODE ChildFsNode;
+ BOOLEAN NoError = TRUE;
+
+ if( (FsNodeArray = DirFsn->QueryFsnodeArray()) == NULL ) {
+
+ return FALSE;
+ }
+
+ if( (Iterator = FsNodeArray->QueryIterator()) == NULL ) {
+
+ DELETE( FsNodeArray );
+ return FALSE;
+ }
+
+ Iterator->Reset();
+
+ while( NoError && (ChildFsNode = (PFSNODE)Iterator->GetNext()) != NULL ) {
+
+ ChildName = ChildFsNode->QueryName();
+
+ if( ChildName == NULL ) {
+
+ NoError = FALSE;
+ break;
+ }
+
+ // If there is not already a child in the list with
+ // this name, create one and mark it as transient.
+ //
+ if( GetChild( ChildName ) == NULL &&
+ AddChild( ChildName, TRUE ) == NULL ) {
+
+ NoError = FALSE;
+ break;
+ }
+
+ DELETE( ChildName );
+ }
+
+ // Clean up.
+ //
+ DELETE( Iterator );
+
+ FsNodeArray->DeleteAllMembers();
+ DELETE( FsNodeArray );
+ DELETE( ChildName );
+
+ return NoError;
+}
+
+
+
+
+VOID
+ACL_CONVERT_NODE::Dump(
+ IN PPATH ParentPath
+ )
+/*++
+
+Routine Description:
+
+ This method displays the contents of the subtree rooted at
+ this node.
+
+Arguments:
+
+ ParentPath -- Supplies the path of the parent directory. A
+ value of NULL indicates that this is the root
+ of the tree.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PFSN_DIRECTORY DirFsn;
+ PFSN_FILE FileFsn;
+ PCWSTRING PathString;
+ PACL_CONVERT_NODE CurrentChild;
+ ULONG i;
+ PWSTR PathBuffer, pw;
+ CHAR ch;
+ BOOLEAN IsRoot, IsDir, Exists;
+
+
+ if( ParentPath == NULL ) {
+
+ IsRoot = TRUE;
+
+ if( (ParentPath = NEW PATH) == NULL ||
+ !ParentPath->Initialize( &_ComponentName ) ) {
+
+ printf( "*****DUMP ERROR*****\n" );
+ return;
+ }
+
+ } else {
+
+ IsRoot = FALSE;
+
+ if( !ParentPath->AppendBase( &_ComponentName ) ) {
+
+ printf( "*****DUMP ERROR*****\n" );
+ return;
+ }
+ }
+
+ // Determine whether this node represents a file, a directory, or
+ // a non-existent object.
+
+ if( (DirFsn = SYSTEM::QueryDirectory( ParentPath )) != NULL ) {
+
+ Exists = TRUE;
+ IsDir = TRUE;
+ DELETE( DirFsn );
+ DirFsn = NULL;
+
+ } else if( (FileFsn = SYSTEM::QueryFile( ParentPath )) != NULL ) {
+
+ Exists = TRUE;
+ IsDir = FALSE;
+
+ DELETE( FileFsn );
+ FileFsn = NULL;
+
+ } else {
+
+ Exists = FALSE;
+ }
+
+
+ if( (PathString = ParentPath->GetPathString()) == NULL ||
+ (PathBuffer = PathString->QueryWSTR( )) == NULL ) {
+
+ printf( "*****ERROR*****\n" );
+ return;
+ }
+
+ for( pw = PathBuffer; *pw != 0; pw++ ) {
+
+ printf( "%c", *pw );
+ }
+
+ if( !Exists ) {
+
+ printf( " DOES NOT EXIST." );
+
+ } else if ( IsDir ) {
+
+ printf( " (directory)" );
+
+ } else {
+
+ printf( " (file)" );
+ }
+
+ printf( "\n" );
+
+ if( _LanmanAclPresent ) {
+
+ printf( " Audit Info = 0x%x\n", _AuditInfo );
+
+ for( i = 0; i < _AccessEntryCount; i++ ) {
+
+ ch = ( _AccessEntries[i].acl_access & LM_ACCESS_GROUP ) ? '*' : ' ';
+
+ printf( " %c%-20s\n", ch, _AccessEntries[i].acl_ugname );
+ }
+ }
+
+
+ // Spin through the kids.
+
+ _ChildIterator->Reset();
+
+ while( (CurrentChild = (PACL_CONVERT_NODE)_ChildIterator->GetNext()) != NULL ) {
+
+ CurrentChild->Dump( ParentPath );
+ }
+
+ // Clean up this addition to the path.
+
+ if( IsRoot ) {
+
+ DELETE( ParentPath );
+
+ } else {
+
+ ParentPath->TruncateBase();
+ }
+}
diff --git a/private/utils/aclconv/convnode.hxx b/private/utils/aclconv/convnode.hxx
new file mode 100644
index 000000000..d38674c5c
--- /dev/null
+++ b/private/utils/aclconv/convnode.hxx
@@ -0,0 +1,248 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ convnode.hxx
+
+Abstract:
+
+ This module contains declarations for the ACL_CONVERT_NODE class,
+ which models the nodes in the ACL Conversion tree.
+
+ This class is used to handle the conversion of Lanman 2.x ACL's to
+ NT ACL's. It uses a tree structure to bridge the different inheritance
+ schemes. Under Lanman, all ACE's are inherited--thus, applying a new
+ ACE to an existing directory implicitly applies that ACE to all its
+ descendants. Under NT, this is not the case. Thus, it's necessary
+ to create ACEs for all the descendants.
+
+Author:
+
+ Bill McJohn (billmc) 09-Feb-1992
+
+Revision History:
+
+
+--*/
+
+#if !defined (_ACL_CONVERT_NODE_DEFN_)
+
+#define _ACL_CONVERT_NODE_DEFN_
+
+#include "list.hxx"
+#include "listit.hxx"
+#include "string.hxx"
+#include "wstring.hxx"
+
+#include "backacc.hxx"
+#include "logfile.hxx"
+
+typedef struct _INHERITANCE_BUFFER {
+
+ PVOID RecessiveDeniedAces;
+ ULONG RecessiveDeniedMaxLength;
+ ULONG RecessiveDeniedLength;
+ PVOID DominantDeniedAces;
+ ULONG DominantDeniedMaxLength;
+ ULONG DominantDeniedLength;
+ PVOID RecessiveAllowedAces;
+ ULONG RecessiveAllowedMaxLength;
+ ULONG RecessiveAllowedLength;
+ PVOID DominantAllowedAces;
+ ULONG DominantAllowedMaxLength;
+ ULONG DominantAllowedLength;
+};
+
+DEFINE_TYPE( _INHERITANCE_BUFFER, INHERITANCE_BUFFER );
+
+
+CONST SecurityDescriptorBufferSize = 8192;
+CONST AclBufferSize = 8192;
+CONST SystemAceBufferSize = 1024;
+
+
+DECLARE_CLASS( ACL_CONVERT_NODE );
+DECLARE_CLASS( ACLCONV );
+
+class ACL_CONVERT_NODE : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( ACL_CONVERT_NODE );
+
+ VIRTUAL
+ ~ACL_CONVERT_NODE(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PCWSTRING ComponentName,
+ IN BOOLEAN IsTransient DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AddLanmanAcl(
+ IN ULONG AccessEntryCount,
+ IN PLM_ACCESS_LIST AccessEntries,
+ IN USHORT AuditInfo
+ );
+
+ NONVIRTUAL
+ PWSTRING
+ GetName(
+ );
+
+ NONVIRTUAL
+ PACL_CONVERT_NODE
+ GetChild(
+ IN PCWSTRING SearchName
+ );
+
+ NONVIRTUAL
+ PACL_CONVERT_NODE
+ AddChild(
+ IN PCWSTRING ChildComponentName,
+ IN BOOLEAN IsTransient DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Convert(
+ IN OUT PPATH CurrentPath,
+ IN OUT PCINHERITANCE_BUFFER InheritanceBuffer,
+ IN OUT PACLCONV AclConv
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryInheritance(
+ IN PACLCONV AclConv,
+ IN OUT PINHERITANCE_BUFFER Inheritance,
+ IN BOOLEAN IsDir
+ );
+
+ NONVIRTUAL
+ ACE_CONVERT_CODE
+ ConvertOneAce(
+ IN PACLCONV AclConv,
+ IN OUT PINHERITANCE_BUFFER InheritanceBuffer,
+ IN PLM_ACCESS_LIST AccessEntry,
+ IN BOOLEAN IsDir
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AddAces(
+ IN PCPATH ResourceName,
+ IN PCINHERITANCE_BUFFER InheritanceBuffer,
+ IN BOOLEAN IsDir,
+ IN BOOLEAN ByDefault
+ );
+
+ NONVIRTUAL
+ VOID
+ Dump(
+ IN PPATH ParentPath OPTIONAL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsTransient(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ExpandChildren(
+ PFSN_DIRECTORY DirFsn
+ );
+
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct();
+
+ NONVIRTUAL
+ VOID
+ Destroy();
+
+
+ DSTRING _ComponentName;
+
+ BOOLEAN _LanmanAclPresent;
+ BOOLEAN _IsTransient;
+ ULONG _AccessEntryCount;
+ PLM_ACCESS_LIST _AccessEntries;
+ PULONG _AceConversionResults;
+ USHORT _AuditInfo;
+
+ LIST _Children;
+ PITERATOR _ChildIterator;
+
+ ACCESS_MASK _DirSuccessfulAuditMask;
+ ACCESS_MASK _DirFailedAuditMask;
+ ACCESS_MASK _FileSuccessfulAuditMask;
+ ACCESS_MASK _FileFailedAuditMask;
+
+ STATIC BYTE _SelfRelativeSDBuffer[ SecurityDescriptorBufferSize ];
+ STATIC BYTE _AbsoluteSDBuffer[ SecurityDescriptorBufferSize ];
+ STATIC BYTE _AclWorkBuffer[ AclBufferSize ];
+ STATIC BYTE _DaclBuffer[ AclBufferSize ];
+ STATIC BYTE _SaclBuffer[ AclBufferSize ];
+ STATIC BYTE _SystemAces[ SystemAceBufferSize ];
+
+};
+
+INLINE
+PWSTRING
+ACL_CONVERT_NODE::GetName(
+ )
+/*++
+
+Routine Description:
+
+ This method fetches the component name.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the component name.
+
+--*/
+{
+ return( &_ComponentName );
+}
+
+INLINE
+BOOLEAN
+ACL_CONVERT_NODE::IsTransient(
+ )
+/*++
+
+Routine Description:
+
+ This method determines whether the node is transient,
+ ie. should be deleted immediately after conversion.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the node is transient; FALSE if not.
+
+--*/
+{
+ return _IsTransient;
+}
+
+#endif
diff --git a/private/utils/aclconv/lmconst.hxx b/private/utils/aclconv/lmconst.hxx
new file mode 100644
index 000000000..6ecc3075e
--- /dev/null
+++ b/private/utils/aclconv/lmconst.hxx
@@ -0,0 +1,68 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ lmconst.hxx
+
+Abstract:
+
+ This module contains some Lanman 2.x constants needed by
+ the ACL conversion utility.
+
+Author:
+
+ Bill McJohn (billmc) 29-Jan-1992
+
+Revision History:
+
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if !defined( _LMCONST_DEFN_ )
+
+#define _LMCONST_DEFN_
+
+// Manifest constants
+
+#define MAXPATH 260
+#define UNLEN 20
+#define MAX_RESOURCE_NAME_LENGTH 260
+#define MAX_ACCESS_ENTRIES 64
+
+// Lanman Audit bits
+
+#define LM_AUDIT_ALL 0x0001
+#define LM_AUDIT_S_OPEN 0x0010
+#define LM_AUDIT_S_WRITE 0x0020
+#define LM_AUDIT_S_CREATE 0x0020
+#define LM_AUDIT_S_DELETE 0x0040
+#define LM_AUDIT_S_ACL 0x0080
+
+#define LM_AUDIT_F_OPEN 0x0100
+#define LM_AUDIT_F_WRITE 0x0200
+#define LM_AUDIT_F_CREATE 0x0200
+#define LM_AUDIT_F_DELETE 0x0400
+#define LM_AUDIT_F_ACL 0x0800
+
+
+
+// Lanman Access bits:
+
+#define LM_ACCESS_READ 0x1
+#define LM_ACCESS_WRITE 0x2
+#define LM_ACCESS_CREATE 0x4
+#define LM_ACCESS_EXEC 0x8
+#define LM_ACCESS_DELETE 0x10
+#define LM_ACCESS_ATRIB 0x20
+#define LM_ACCESS_PERM 0x40
+#define LM_ACCESS_ALL 0x7f
+#define LM_ACCESS_GROUP 0x8000
+
+
+#endif
diff --git a/private/utils/aclconv/logfile.hxx b/private/utils/aclconv/logfile.hxx
new file mode 100644
index 000000000..e0197c2e1
--- /dev/null
+++ b/private/utils/aclconv/logfile.hxx
@@ -0,0 +1,82 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ logfile.hxx
+
+Abstract:
+
+ This module contains declarations which describe the file format
+ of the log file produced by ACLCONV.
+
+Author:
+
+ Bill McJohn (billmc) 12-Feb-1992
+
+Revision History:
+
+
+--*/
+
+#if !defined( _ACLCONV_LOGFILE_DEFN_ )
+
+#define _ACLCONV_LOGFILE_DEFN_
+
+// Conversion codes. Note that these are stored as ULONGs in
+// the log file.
+
+typedef enum _ACL_CONVERT_CODE {
+
+ ACL_CONVERT_SUCCESS = 0,
+ ACL_CONVERT_RESOURCE_NOT_FOUND = 1,
+ ACL_CONVERT_ERROR = 2
+};
+
+DEFINE_TYPE( _ACL_CONVERT_CODE, ACL_CONVERT_CODE );
+
+typedef enum _ACE_CONVERT_CODE {
+
+ ACE_CONVERT_SUCCESS = 0,
+ ACE_CONVERT_DROPPED = 1,
+ ACE_CONVERT_SID_NOT_FOUND = 2,
+ ACE_CONVERT_ERROR = 3
+};
+
+DEFINE_TYPE( _ACE_CONVERT_CODE, ACE_CONVERT_CODE );
+
+
+// The log file consists of a LOGFILE_HEADER followed by a series
+// of log records.
+
+CONST ULONG AclconvLogFileSignature = 0x38ac534d;
+
+typedef struct _ACLCONV_LOGFILE_HEADER {
+
+ ULONG Signature;
+};
+
+DEFINE_TYPE( _ACLCONV_LOGFILE_HEADER, ACLCONV_LOGFILE_HEADER );
+
+// A log file record has this format:
+//
+// Log Record Header
+// Resource name -- Unicode, NULL-terminated.
+// ACE Conversion codes -- One ULONG for each access entry
+// Lanman access entries
+//
+
+
+typedef struct _ACLCONV_LOG_RECORD_HEADER {
+
+ ULONG ResourceNameLength; // in characters
+ ULONG ConversionResult; // result for this resource
+ USHORT LmAuditMask; // Lanman 2.x audit bits for this resource
+ USHORT AccessEntryCount; // Number of access entries in list.
+};
+
+DEFINE_TYPE( _ACLCONV_LOG_RECORD_HEADER, ACLCONV_LOG_RECORD_HEADER );
+
+
+#endif
diff --git a/private/utils/aclconv/makefile b/private/utils/aclconv/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/aclconv/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/aclconv/old_msgs b/private/utils/aclconv/old_msgs
new file mode 100644
index 000000000..f42329f41
--- /dev/null
+++ b/private/utils/aclconv/old_msgs
@@ -0,0 +1,170 @@
+---------- ULIB\SRC\rtmsg.mc next ----------
+4406,4573d4405
+<
+< ;//----------------------
+< ;//
+< ;// ACLCONV messages
+< ;//
+< ;//----------------------
+<
+< MessageId=30400 SymbolicName=MSG_ACLCONV_USAGE
+< Language=English
+< Converts OS/2 LANMAN SERVER access control lists.
+<
+< ACLCONV /DATA:datafile /LOG:logfile [/NEWDRIVE:n:] [/DOMAIN:domain] [/CODEPAGE:n]
+< ACLCONV /LOG:logfile /LIST [/CODEPAGE:n]
+<
+< /DATA:datafile Specifies an OS/2 Lanman BACKACC data file.
+< /LOG:logfile Specifies the ACLCONV log file.
+< /LIST List the contents of the specified log file.
+< /NEWDRIVE:n: Restore permissions onto drive n: instead of
+< original drive.
+< /DOMAIN:domain Search only the specified domain for account names.
+< /CODEPAGE:n Specifies the Code Page associated with the
+< BACKACC data file.
+<
+< .
+<
+< MessageId=30401 SymbolicName=MSG_ACLCONV_CANT_OPEN_FILE
+< Language=English
+< Cannot open %1.
+<
+< .
+<
+< MessageId=30402 SymbolicName=MSG_ACLCONV_DATAFILE_BAD_FORMAT
+< Language=English
+< Cannot determine LAN Manager 2.x Backacc utility revision of %1.
+<
+< .
+<
+< MessageId=30403 SymbolicName=MSG_ACLCONV_DATAFILE_ERROR
+< Language=English
+< Error encountered reading data file.
+<
+< .
+<
+< MessageId=30404 SymbolicName=MSG_ACLCONV_LOGFILE_ERROR
+< Language=English
+< Error encountered writing log file.
+<
+< .
+<
+< MessageId=30405 SymbolicName=MSG_ACLCONV_CONVERSION_ERROR
+< Language=English
+< Conversion ceased due to error.
+<
+< .
+<
+< MessageId=30406 SymbolicName=MSG_ACLCONV_INVALID_LOG_FILE
+< Language=English
+< Invalid log file format.
+<
+< .
+<
+< MessageId=30407 SymbolicName=MSG_ACLCONV_USERNAME
+< Language=English
+< %1:%0
+< .
+<
+< MessageId=30408 SymbolicName=MSG_ACLCONV_READ_PERM
+< Language=English
+< R%0
+< .
+<
+< MessageId=30409 SymbolicName=MSG_ACLCONV_WRITE_PERM
+< Language=English
+< W%0
+< .
+<
+< MessageId=30410 SymbolicName=MSG_ACLCONV_CREATE_PERM
+< Language=English
+< C%0
+< .
+<
+< MessageId=30411 SymbolicName=MSG_ACLCONV_EXECUTE_PERM
+< Language=English
+< X%0
+< .
+<
+< MessageId=30412 SymbolicName=MSG_ACLCONV_DELETE_PERM
+< Language=English
+< D%0
+< .
+<
+< MessageId=30413 SymbolicName=MSG_ACLCONV_ATTR_PERM
+< Language=English
+< A%0
+< .
+<
+< MessageId=30414 SymbolicName=MSG_ACLCONV_PERM_PERM
+< Language=English
+< P%0
+< .
+<
+< MessageId=30415 SymbolicName=MSG_ACLCONV_NONE_PERM
+< Language=English
+< (none)%0
+< .
+<
+< MessageId=30416 SymbolicName=MSG_ACLCONV_FILE_NOT_FOUND
+< Language=English
+< -- File not found.
+< .
+<
+< MessageId=30417 SymbolicName=MSG_ACLCONV_ACE_DROPPED
+< Language=English
+< -- superfluous access control entry dropped.
+< .
+<
+< MessageId=30418 SymbolicName=MSG_ACLCONV_SID_NOT_FOUND
+< Language=English
+< -- User or group ID not found.
+< .
+<
+< MessageId=30419 SymbolicName=MSG_ACLCONV_ERROR_IN_CONVERSION
+< Language=English
+< -- Error in conversion.
+< .
+<
+< MessageId=30420 SymbolicName=MSG_ACLCONV_ACE_CONVERTED
+< Language=English
+< -- Conversion successful.
+< .
+<
+< MessageId=30421 SymbolicName=MSG_ACLCONV_RESOURCE_NAME
+< Language=English
+< %1
+< .
+<
+< MessageId=30422 SymbolicName=MSG_ACLCONV_CONVERT_COMPLETE
+< Language=English
+< Conversion complete.
+< .
+<
+< MessageId=30423 SymbolicName=MSG_ACLCONV_LOGFILE_READ_ERROR
+< Language=English
+< Error encountered reading log file.
+< .
+<
+< MessageId=30424 SymbolicName=MSG_ACLCONV_INVALID_DRIVE
+< Language=English
+< ACLCONV cannot restore permissions onto drive %1
+< .
+<
+< MessageId=30425 SymbolicName=MSG_ACLCONV_CANT_DETERMINE_FILESYSTEM
+< Language=English
+< ACLCONV cannot determine the file system on target volume.
+< .
+<
+< MessageId=30426 SymbolicName=MSG_ACLCONV_TARGET_NOT_NTFS
+< Language=English
+< The target drive is not formatted for NTFS; ACLCONV can only
+< restore security information to NTFS volumes.
+< .
+<
+< MessageId=30427 SymbolicName=MSG_ACLCONV_BAD_CODEPAGE
+< Language=English
+< The specified codepage is not valid.
+< .
+<
+<
diff --git a/private/utils/aclconv/sidcache.cxx b/private/utils/aclconv/sidcache.cxx
new file mode 100644
index 000000000..ca98d8fa8
--- /dev/null
+++ b/private/utils/aclconv/sidcache.cxx
@@ -0,0 +1,355 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ sidcache.hxx
+
+Abstract:
+
+ This module contains definitions for the SID_CACHE class,
+ which models a simple cache of SID's for ACLCONV.
+
+Author:
+
+ Bill McJohn (billmc) 06-Nov-1993
+
+Revision History:
+
+
+--*/
+
+#include "ulib.hxx"
+#include "sidcache.hxx"
+
+DEFINE_CONSTRUCTOR( SID_CACHE, OBJECT );
+
+SID_CACHE::~SID_CACHE(
+ )
+{
+ Destroy();
+}
+
+VOID
+SID_CACHE::Construct(
+ )
+/*++
+
+Routine Description:
+
+ This method is a helper function for object construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _NumberOfEntries = 0;
+ _NextSlot = 0;
+ _Cache = NULL;
+}
+
+VOID
+SID_CACHE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This method is a helper function for object destruction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG i;
+
+ for( i = 0; i < _NumberOfEntries; i++ ) {
+
+ if( _Cache[i].Sid ) {
+
+ FREE( _Cache[i].Sid );
+ _Cache[i].Sid = NULL;
+ }
+ }
+
+ _NumberOfEntries = 0;
+ _NextSlot = 0;
+ delete[] _Cache;
+}
+
+
+BOOLEAN
+SID_CACHE::Initialize(
+ IN ULONG NumberOfEntries
+ )
+/*++
+
+Routine Description:
+
+ This method initializes the cache--it allocates the array
+ of CACHED_SID's and initializes each one.
+
+Arguments:
+
+ NumberOfEntries -- Supplies the size of the cache.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ ULONG i;
+
+ Destroy();
+
+ if( NumberOfEntries == 0 ) {
+
+ return FALSE;
+ }
+
+ _NumberOfEntries = NumberOfEntries;
+ _NextSlot = 0;
+
+ if( (_Cache = NEW CACHED_SID[NumberOfEntries]) == NULL ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ for( i = 0; i < NumberOfEntries; i++ ) {
+
+ _Cache[i].InUse = FALSE;
+ _Cache[i].Sid = NULL;
+ _Cache[i].SidLength = 0;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+SID_CACHE::IsNamePresent(
+ IN PCWSTRING Domain,
+ IN PCWSTRING Name,
+ OUT PULONG SidLength
+ )
+/*++
+
+Routine Description:
+
+ This method determines whether a particular account name
+ is in the cache.
+
+Arguments:
+
+ Domain -- Supplies the domain to search. May be NULL, indicating
+ that the client will accept a positive match from any
+ domain.
+ Name -- Supplies the account name.
+ SidLength -- Receives the length of the SID for the specified
+ name. A value of 0 indicates that the name has
+ been previously sought and not found.
+
+Return Value:
+
+ TRUE if a match is found.
+
+--*/
+{
+ ULONG Index;
+
+ if( !LocateName( Domain, Name, &Index ) ) {
+
+ return FALSE;
+ }
+
+ *SidLength = _Cache[Index].SidLength;
+ return TRUE;
+}
+
+NONVIRTUAL
+BOOLEAN
+SID_CACHE::QueryCachedSid(
+ IN PCWSTRING Domain,
+ IN PCWSTRING Name,
+ OUT PSID Sid,
+ IN OUT PULONG SidLength
+ )
+/*++
+
+Routine Description:
+
+ This method fetches a SID from the cache.
+
+Arguments:
+
+ Domain -- Supplies the domain to search. May be NULL, indicating
+ that the client will accept a positive match from any
+ domain.
+ Name -- Supplies the account name.
+ Sid -- Receives the SID.
+ SidLength -- Supplies the length in bytes of the client's
+ buffer; receives the length in bytes of the SID.
+ A length of zero means that the name has previously
+ been searched for and not found.
+--*/
+{
+ ULONG Index;
+
+ if( !LocateName( Domain, Name, &Index ) ) {
+
+ return FALSE;
+ }
+
+ if( *SidLength < _Cache[Index].SidLength ) {
+
+ return FALSE;
+ }
+
+ memcpy( Sid, _Cache[Index].Sid, _Cache[Index].SidLength );
+ *SidLength = _Cache[Index].SidLength;
+
+ return TRUE;
+}
+
+
+BOOLEAN
+SID_CACHE::CacheSid(
+ IN PCWSTRING Domain,
+ IN PCWSTRING Name,
+ IN PSID Sid,
+ IN ULONG SidLength
+ )
+/*++
+
+Routine Description:
+
+ This method adds a SID to the cache.
+
+Arguments:
+
+ Domain -- Supplies the domain in which the name was found.
+ May be NULL if the SID is also NULL, to indicate
+ that the specified account name was not found in
+ any trusted domain.
+ Name -- Supplies the name associated with this SID.
+ Sid -- Supplies the SID. A NULL SID indicates that the
+ user does not exist.
+ SidLength -- Supplies the length in bytes of the SID.
+
+--*/
+{
+
+ DebugAssert( _NextSlot < _NumberOfEntries );
+
+ _Cache[_NextSlot].InUse = FALSE;
+
+ if( _Cache[_NextSlot].Sid ) {
+
+ FREE( _Cache[_NextSlot].Sid );
+ _Cache[_NextSlot].Sid = NULL;
+ }
+
+ if( (!Domain && !_Cache[_NextSlot].Domain.Initialize( "" )) ||
+ ( Domain && !_Cache[_NextSlot].Domain.Initialize( Domain )) ||
+ !_Cache[_NextSlot].Name.Initialize( Name ) ) {
+
+ return FALSE;
+ }
+
+ if( !(_Cache[_NextSlot].Sid = (PSID)MALLOC( SidLength )) ) {
+
+ return FALSE;
+ }
+
+ memcpy( _Cache[_NextSlot].Sid, Sid, SidLength );
+
+ _Cache[_NextSlot].SidLength = SidLength;
+ _Cache[_NextSlot].InUse = TRUE;
+
+ _NextSlot++;
+ _NextSlot %= _NumberOfEntries;
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+SID_CACHE::LocateName(
+ IN PCWSTRING Domain,
+ IN PCWSTRING Name,
+ OUT PULONG Index
+ )
+/*++
+
+Routine Description:
+
+ This method locates a name in the cache.
+
+ Note that matching rules are different for positive matches
+ (cache entries with a non-NULL SID) and negative matches
+ (entries with a NULL SID). A negative entry only matches
+ if both the domain and account name are identical, whereas
+ a positive entry also matches if the names are equal and
+ the search domain is the empty string.
+
+Arguments:
+
+ Domain -- Supplies the domain to search. May be NULL, indicating
+ that the client will accept a positive match from any
+ domain.
+ Name -- Supplies the account name to find.
+ Index -- Receives the index of the matching cache entry, if
+ found.
+
+Return Value:
+
+ TRUE if a match is found.
+
+
+
+--*/
+{
+ ULONG i;
+
+ for( i = 0; i < _NumberOfEntries; i++ ) {
+
+ if( _Cache[i].InUse && !_Cache[i].Name.Strcmp( Name ) ) {
+
+ if( (Domain && !_Cache[i].Domain.Strcmp( Domain )) ||
+ (!Domain && _Cache[i].Domain.QueryChCount() == 0) ) {
+
+ // It's an exact match--return it.
+ //
+ *Index = i;
+ return TRUE;
+ }
+
+ // It's not an exact match. If this is a positive
+ // entry (i.e. the SID is non-NULL), and the search
+ // domain is NULL, then this is an acceptable match.
+ //
+ if( _Cache[i].Sid && !Domain ) {
+
+ *Index = i;
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
diff --git a/private/utils/aclconv/sidcache.hxx b/private/utils/aclconv/sidcache.hxx
new file mode 100644
index 000000000..bad355fab
--- /dev/null
+++ b/private/utils/aclconv/sidcache.hxx
@@ -0,0 +1,116 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ sidcache.hxx
+
+Abstract:
+
+ This module contains declarations for the SID_CACHE class,
+ which models a simple cache of SID's for ACLCONV.
+
+Author:
+
+ Bill McJohn (billmc) 06-Nov-1993
+
+Revision History:
+
+
+--*/
+
+#if !defined (_SID_CACHE_DEFN_)
+
+#define _SID_CACHE_DEFN_
+
+#include "string.hxx"
+#include "wstring.hxx"
+
+// a CACHED_SID structure represents one cached SID.
+// Domain -- Domain in which the name was found.
+// Name -- Account name.
+// Sid -- SID found for this name. NULL if
+// the name has not been found previously.
+// SidLength -- Length in bytes of the SID
+//
+typedef struct _CACHED_SID {
+
+ BOOLEAN InUse;
+ DSTRING Domain;
+ DSTRING Name;
+ PSID Sid;
+ ULONG SidLength;
+};
+
+DEFINE_TYPE( _CACHED_SID, CACHED_SID );
+
+DECLARE_CLASS( SID_CACHE );
+
+class SID_CACHE : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( SID_CACHE );
+
+ VIRTUAL
+ ~SID_CACHE(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN ULONG NumberOfEntries
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsNamePresent(
+ IN PCWSTRING Domain OPTIONAL,
+ IN PCWSTRING Name,
+ OUT PULONG SidLength
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryCachedSid(
+ IN PCWSTRING Domain OPTIONAL,
+ IN PCWSTRING Name,
+ OUT PSID Sid,
+ IN OUT PULONG SidLength
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CacheSid(
+ IN PCWSTRING Domain OPTIONAL,
+ IN PCWSTRING Name,
+ IN PSID Sid,
+ IN ULONG SidLength
+ );
+
+ private:
+
+ NONVIRTUAL
+ BOOLEAN
+ LocateName(
+ IN PCWSTRING Domain,
+ IN PCWSTRING Name,
+ OUT PULONG Index
+ );
+
+ NONVIRTUAL
+ VOID
+ Construct();
+
+ NONVIRTUAL
+ VOID
+ Destroy();
+
+ ULONG _NumberOfEntries;
+ ULONG _NextSlot;
+ PCACHED_SID _Cache;
+
+};
+
+#endif // _SID_CACHE_DEFN_
diff --git a/private/utils/aclconv/sources b/private/utils/aclconv/sources
new file mode 100644
index 000000000..915f3e399
--- /dev/null
+++ b/private/utils/aclconv/sources
@@ -0,0 +1,65 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+BLDCRT=1
+
+MAJORCOMP=utils
+MINORCOMP=aclconv
+
+TARGETNAME=aclconv
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=acehelp.cxx \
+ convnode.cxx \
+ sidcache.cxx \
+ aclconv.rc
+
+INCLUDES=..\ulib\inc;\nt\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+CXXFLAGS=+d
+UMLIBS=obj\*\aclconv.lib ..\ulib\src\obj\*\ulib.lib \nt\public\sdk\lib\*\advapi32.lib \
+ \nt\public\sdk\lib\*\user32.lib \nt\public\sdk\lib\*\ntdll.lib
+
+UMTYPE=console
+
+UMAPPL=aclconv
+
+UMRES=obj\*\aclconv.res
diff --git a/private/utils/attrib/attrib.cxx b/private/utils/attrib/attrib.cxx
new file mode 100644
index 000000000..f7df22055
--- /dev/null
+++ b/private/utils/attrib/attrib.cxx
@@ -0,0 +1,800 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ attrib.cxx
+
+Abstract:
+
+ This utility allows the user to change file attributes.
+ It is functionaly compatible with DOS 5 attrib utility.
+
+Author:
+
+ Jaime F. Sasson
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "arg.hxx"
+#include "array.hxx"
+#include "path.hxx"
+#include "wstring.hxx"
+#include "substrng.hxx"
+#include "dir.hxx"
+#include "filter.hxx"
+#include "system.hxx"
+#include "arrayit.hxx"
+#include "stream.hxx"
+#include "smsg.hxx"
+#include "rtmsg.h"
+#include "attrib.hxx"
+
+PSTREAM Get_Standard_Input_Stream();
+PSTREAM Get_Standard_Output_Stream();
+
+
+extern "C" {
+#include <stdio.h>
+}
+
+
+ERRSTACK* perrstk;
+
+DEFINE_CONSTRUCTOR( ATTRIB, PROGRAM );
+
+
+BOOLEAN
+ATTRIB::Initialize(
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes an ATTRIB class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the initialization succeeded.
+
+
+--*/
+
+
+{
+ PWSTRING DynSubDirectory;
+ PWSTRING DynSubFileName;
+
+ ARGUMENT_LEXEMIZER ArgLex;
+ ARRAY LexArray;
+
+ ARRAY ArgumentArray;
+
+ STRING_ARGUMENT ProgramNameArgument;
+// STRING_ARGUMENT FileNameArgument;
+ PCWSTRING FullFileNameString;
+ PATH DirectoryNamePath;
+ PCWSTRING InvalidName;
+ PCWSTRING TempPathString;
+ DSTRING TempPathStringDrive;
+ PATH PathDrive;
+ DSTRING BackSlashString;
+ STRING_ARGUMENT InvalidSwitch;
+ STRING_ARGUMENT InvalidSwitchPlus;
+ STRING_ARGUMENT InvalidSwitchMinus;
+ PWSTRING InvalidArgument;
+ DSTRING InvalidSwitchString;
+ BOOLEAN ActOnDirectory;
+
+
+ _InitialDirectory = NULL;
+ //
+ // Initialize MESSAGE object
+ //
+ _OutStream = Get_Standard_Output_Stream();
+ _Message.Initialize( _OutStream, Get_Standard_Input_Stream() );
+
+ //
+ // Initialize string that contains End-Of-Line characters
+ //
+ if( !_EndOfLineString.Initialize( (LPWSTR)L"\r\n" ) ) {
+ DebugPrint( "_EndOfLineString.Initialize() failed" );
+ return( FALSE );
+ }
+
+
+ //
+ // Parse command line
+ //
+ if ( !LexArray.Initialize( ) ) {
+ DebugPrint( "LexArray.Initialize() failed \n" );
+ return( FALSE );
+ }
+ if ( !ArgLex.Initialize( &LexArray ) ) {
+ DebugPrint( "ArgLex.Initialize() failed \n" );
+ return( FALSE );
+ }
+
+ ArgLex.PutSwitches( "/" );
+ ArgLex.SetCaseSensitive( FALSE );
+ ArgLex.PutStartQuotes( "\"");
+ ArgLex.PutEndQuotes( "\"");
+ ArgLex.PutSeparators( " \t" );
+
+ if( !ArgLex.PrepareToParse() ) {
+ DebugPrint( "ArgLex.PrepareToParse() failed \n" );
+ _Message.Set( MSG_ATTRIB_PARAMETER_NOT_CORRECT );
+ _Message.Display( " " );
+ return( FALSE );
+ }
+
+ if ( !ArgumentArray.Initialize() ) {
+ DebugPrint( "ArgumentArray.Initialize() failed \n" );
+ return( FALSE );
+ }
+ if( !ProgramNameArgument.Initialize("*") ||
+ !_FlagRemoveSystemAttribute.Initialize( "-S" ) ||
+ !_FlagAddSystemAttribute.Initialize( "+S" ) ||
+ !_FlagRemoveHiddenAttribute.Initialize( "-H" ) ||
+ !_FlagAddHiddenAttribute.Initialize( "+H" ) ||
+ !_FlagRemoveReadOnlyAttribute.Initialize( "-R" ) ||
+ !_FlagAddReadOnlyAttribute.Initialize( "+R" ) ||
+ !_FlagRemoveArchiveAttribute.Initialize( "-A" ) ||
+ !_FlagAddArchiveAttribute.Initialize( "+A" ) ||
+ !_FlagRecurseDirectories.Initialize( "/S" ) ||
+ !_FlagDisplayHelp.Initialize( "/?" ) ||
+ !InvalidSwitch.Initialize( "/*" ) ||
+ !InvalidSwitchPlus.Initialize( "+*" ) ||
+ !InvalidSwitchMinus.Initialize( "-*" ) ||
+ !_FileNameArgument.Initialize( "*" ) ) {
+ DebugPrint( "Unable to initialize flag or string arguments \n" );
+ return( FALSE );
+ }
+ if( !ArgumentArray.Put( &ProgramNameArgument ) ||
+ !ArgumentArray.Put( &_FlagRemoveSystemAttribute ) ||
+ !ArgumentArray.Put( &_FlagAddSystemAttribute ) ||
+ !ArgumentArray.Put( &_FlagRemoveHiddenAttribute ) ||
+ !ArgumentArray.Put( &_FlagAddHiddenAttribute ) ||
+ !ArgumentArray.Put( &_FlagRemoveReadOnlyAttribute ) ||
+ !ArgumentArray.Put( &_FlagAddReadOnlyAttribute ) ||
+ !ArgumentArray.Put( &_FlagRemoveArchiveAttribute ) ||
+ !ArgumentArray.Put( &_FlagAddArchiveAttribute ) ||
+ !ArgumentArray.Put( &_FlagRecurseDirectories ) ||
+ !ArgumentArray.Put( &_FlagDisplayHelp ) ||
+ !ArgumentArray.Put( &InvalidSwitch ) ||
+ !ArgumentArray.Put( &InvalidSwitchPlus ) ||
+ !ArgumentArray.Put( &InvalidSwitchMinus ) ||
+ !ArgumentArray.Put( &_FileNameArgument ) ) {
+ DebugPrint( "ArgumentArray.Put() failed \n" );
+ return( FALSE );
+ }
+ if( !ArgLex.DoParsing( &ArgumentArray ) ) {
+ _Message.Set( MSG_ATTRIB_PARAMETER_NOT_CORRECT );
+ _Message.Display( " " );
+ return( FALSE );
+ }
+
+ //
+ // Check the existance of an invalid switch
+ //
+ if( InvalidSwitch.IsValueSet() ||
+ InvalidSwitchPlus.IsValueSet() ||
+ InvalidSwitchMinus.IsValueSet() ) {
+
+ if( InvalidSwitch.IsValueSet() ) {
+ //
+ // The invalid switch starts with '/'
+ //
+ if( !InvalidSwitchString.Initialize( "/" ) ) {
+ DebugPrint( "InvalidSwitchString.Initialize( / ) failed \n" );
+ return( FALSE );
+ }
+ InvalidArgument = InvalidSwitch.GetString();
+ DebugPtrAssert( InvalidArgument );
+ } else if ( InvalidSwitchPlus.IsValueSet() ) {
+ //
+ // The invalid switch starts with '+'
+ //
+ if( !InvalidSwitchString.Initialize( "+" ) ) {
+ DebugPrint( "InvalidSwitchString.Initialize( + ) failed \n" );
+ return( FALSE );
+ }
+ InvalidArgument = InvalidSwitchPlus.GetString();
+ DebugPtrAssert( InvalidArgument );
+ } else {
+ //
+ // The invalid switch starts with '-'
+ //
+ if( !InvalidSwitchString.Initialize( "-" ) ) {
+ DebugPrint( "InvalidSwitchString.Initialize( - ) failed \n" );
+ return( FALSE );
+ }
+ InvalidArgument = InvalidSwitchMinus.GetString();
+ DebugPtrAssert( InvalidArgument );
+ }
+ //
+ // Display the error message followed by the invalid switch
+ //
+ if( !InvalidSwitchString.Strcat( InvalidArgument ) ) {
+ DebugPrint( "InvalidSwitchString.Strcat( InvalidArgument ) failed \n" );
+ return( FALSE );
+ }
+ _Message.Set( MSG_ATTRIB_INVALID_SWITCH );
+ _Message.Display( "%W", &InvalidSwitchString );
+ return( FALSE );
+ }
+
+ //
+ // +S -S or +H -H or +R -R or +A -A are not valid
+ // combination of arguments
+ //
+ if( ( _FlagRemoveSystemAttribute.QueryFlag() &&
+ _FlagAddSystemAttribute.QueryFlag() ) ||
+ ( _FlagRemoveHiddenAttribute.QueryFlag() &&
+ _FlagAddHiddenAttribute.QueryFlag() ) ||
+ ( _FlagRemoveReadOnlyAttribute.QueryFlag() &&
+ _FlagAddReadOnlyAttribute.QueryFlag() ) ||
+ ( _FlagRemoveArchiveAttribute.QueryFlag() &&
+ _FlagAddArchiveAttribute.QueryFlag() ) ) {
+
+ _Message.Set( MSG_ATTRIB_PARAMETER_NOT_CORRECT );
+ _Message.Display( " " );
+ return( FALSE );
+ }
+
+ if( _FlagRemoveSystemAttribute.QueryFlag() ||
+ _FlagAddSystemAttribute.QueryFlag() ||
+ _FlagRemoveHiddenAttribute.QueryFlag() ||
+ _FlagAddHiddenAttribute.QueryFlag() ||
+ _FlagRemoveReadOnlyAttribute.QueryFlag() ||
+ _FlagAddReadOnlyAttribute.QueryFlag() ||
+ _FlagRemoveArchiveAttribute.QueryFlag() ||
+ _FlagAddArchiveAttribute.QueryFlag() ) {
+ _PrintAttribInfo = FALSE;
+ _ResetMask = (FSN_ATTRIBUTE)0xffffffff;
+ if( _FlagRemoveSystemAttribute.QueryFlag() ) {
+ _ResetMask &= ~FSN_ATTRIBUTE_SYSTEM;
+ }
+ if( _FlagRemoveHiddenAttribute.QueryFlag() ) {
+ _ResetMask &= ~FSN_ATTRIBUTE_HIDDEN;
+ }
+ if( _FlagRemoveReadOnlyAttribute.QueryFlag() ) {
+ _ResetMask &= ~FSN_ATTRIBUTE_READONLY;
+ }
+ if( _FlagRemoveArchiveAttribute.QueryFlag() ) {
+ _ResetMask &= ~FSN_ATTRIBUTE_ARCHIVE;
+ }
+
+ _MakeMask = 0;
+ if( _FlagAddSystemAttribute.QueryFlag() ) {
+ _MakeMask |= FSN_ATTRIBUTE_SYSTEM;
+ }
+ if( _FlagAddHiddenAttribute.QueryFlag() ) {
+ _MakeMask |= FSN_ATTRIBUTE_HIDDEN;
+ }
+ if( _FlagAddReadOnlyAttribute.QueryFlag() ) {
+ _MakeMask |= FSN_ATTRIBUTE_READONLY;
+ }
+ if( _FlagAddArchiveAttribute.QueryFlag() ) {
+ _MakeMask |= FSN_ATTRIBUTE_ARCHIVE;
+ }
+ } else {
+ _PrintAttribInfo = TRUE;
+ }
+
+ //
+ // Get filename
+ //
+ if( !_FileNameArgument.IsValueSet() ) {
+ //
+ // User didn't specify file name. Use *.* as default
+ //
+ FullFileNameString = NULL;
+ if( !_FullFileNamePath.Initialize( (LPWSTR)L"*.*", TRUE ) ) {
+ DebugPrint( "_FullFileNamePath.Initialize() failed \n" );
+ return( FALSE );
+ }
+ } else {
+ //
+ // Get name specified in the command line
+ //
+ FullFileNameString = _FileNameArgument.GetPath()->GetPathString();
+ DebugPtrAssert( FullFileNameString );
+ if( !_FullFileNamePath.Initialize( FullFileNameString, TRUE ) ) {
+ DebugPrint( "_FullFileNamePath.Initialize() failed \n" );
+ return( FALSE );
+ }
+ }
+
+ //
+ // Get prefix and verify that it exists
+ //
+ if( ( DynSubDirectory = _FullFileNamePath.QueryPrefix() ) == NULL ) {
+ DebugPrint( "_FullFileNamePath.QueryPrefix() failed \n" );
+ return( FALSE );
+ }
+ if( !DirectoryNamePath.Initialize( DynSubDirectory ) ) {
+ DELETE( DynSubDirectory );
+ DebugPrint( "DirectoryNamePath.Initialize() failed \n" );
+ return( FALSE );
+ }
+ DELETE( DynSubDirectory );
+ //
+ // Have to test if DirectoryNamePath is a drive, and if it is
+ // add \ to it otherwise it won't be able to find a file that is
+ // in the root directory, if the current directory is not the root.
+ //
+ if( DirectoryNamePath.IsDrive() ) {
+ if( !BackSlashString.Initialize( "\\" ) ) {
+ DebugPrint( "BackSlashString.Initialize() failed \n" );
+ return( FALSE );
+ }
+ TempPathString = DirectoryNamePath.GetPathString();
+ DebugPtrAssert( TempPathString );
+ if( !TempPathStringDrive.Initialize( TempPathString ) ) {
+ DebugPrint( "TempPathStringDrive.Initialize() failed \n" );
+ return( FALSE );
+ }
+ TempPathStringDrive.Strcat( &BackSlashString );
+ if( !PathDrive.Initialize( &TempPathStringDrive ) ) {
+ DebugPrint( "PathDrive.Initialize() failed \n" );
+ return( FALSE );
+ }
+ if( !DirectoryNamePath.Initialize( &PathDrive ) ) {
+ DebugPrint( "DirectoryNamePath.Initialize() failed \n" );
+ return( FALSE );
+ }
+ }
+
+ if( ( _InitialDirectory = SYSTEM::QueryDirectory( &DirectoryNamePath ) ) == NULL ) {
+ InvalidName = DirectoryNamePath.GetPathString();
+ DebugPtrAssert( InvalidName );
+ _Message.Set( MSG_ATTRIB_PATH_NOT_FOUND );
+ _Message.Display( "%W", InvalidName );
+ return( FALSE );
+ }
+
+ //
+ // Initialize filter for directories
+ //
+ if( !_FsnFilterDirectory.Initialize() ) {
+ DELETE( _InitialDirectory );
+ DebugPrint( "_FsnFilterDirectory.Initialize() failed \n" );
+ return( FALSE );
+ }
+ if( !_FsnFilterDirectory.SetFileName( "*.*" ) ) {
+ DELETE( _InitialDirectory );
+ DebugPrint( "_FsnFilterDirectory.SetFilename() failed \n" );
+ return( FALSE );
+ }
+ if( !_FsnFilterDirectory.SetAttributes( FSN_ATTRIBUTE_DIRECTORY ) ) {
+ DELETE( _InitialDirectory );
+ DebugPrint( "_FsnFilterDirectory.SetAttributes() failed \n" );
+ return( FALSE );
+ }
+
+ //
+ // Get file name and initialize filter for files
+ //
+ if( ( DynSubFileName = _FullFileNamePath.QueryName() ) == NULL ) {
+ if( _FileNameArgument.IsValueSet() ) {
+ InvalidName = _FileNameArgument.GetPath()->GetPathString();
+ } else {
+ InvalidName = DirectoryNamePath.GetPathString();
+ }
+ DebugPtrAssert( InvalidName );
+
+ _Message.Set( MSG_ATTRIB_FILE_NOT_FOUND );
+ _Message.Display( "%W", InvalidName );
+ DELETE( _InitialDirectory );
+ return( FALSE );
+ }
+
+ //
+ // Determine whether attrib should act on a directory.
+ // It will do so only if the user specify a directory name that does
+ // not contain the characters '*' or '?'.
+ // Also, attrib will not act on directories if the switch /S is specified.
+ //
+ if( ( _FlagRecurseDirectories.QueryFlag() ) ||
+ ( FullFileNameString == NULL ) ||
+ ( FullFileNameString->Strchr( ( WCHAR )'*' ) != INVALID_CHNUM ) ||
+ ( FullFileNameString->Strchr( ( WCHAR )'?' ) != INVALID_CHNUM ) ) {
+ ActOnDirectory = FALSE;
+ } else {
+ ActOnDirectory = TRUE;
+ }
+
+
+ if( !_FsnFilterFile.Initialize() ) {
+ DELETE( _InitialDirectory );
+ DELETE( DynSubFileName );
+ DebugPrint( "FsnFilter.Initialize() failed \n" );
+ return( FALSE );
+ }
+ if( !_FsnFilterFile.SetFileName( DynSubFileName ) ) {
+ DELETE( _InitialDirectory );
+ DELETE( DynSubFileName );
+ DebugPrint( "FsnFilter.SetFilename() failed \n" );
+ return( FALSE );
+ }
+ if( !ActOnDirectory ) {
+ if( !_FsnFilterFile.SetAttributes( 0, 0, FSN_ATTRIBUTE_DIRECTORY ) ) {
+ DELETE( _InitialDirectory );
+ DELETE( DynSubFileName );
+ DebugPrint( "FsnFilter.SetAttributes() failed \n" );
+ return( FALSE );
+ }
+ } else {
+ if( !_FsnFilterFile.SetAttributes( 0, 0, 0 ) ) {
+ DELETE( _InitialDirectory );
+ DELETE( DynSubFileName );
+ DebugPrint( "FsnFilter.SetAttributes() failed \n" );
+ return( FALSE );
+ }
+ }
+ DELETE( DynSubFileName );
+ if( _FlagDisplayHelp.QueryFlag() ) {
+ _Message.Set( MSG_ATTRIB_HELP_MESSAGE );
+ _Message.Display( " " );
+ return( FALSE );
+ }
+
+ _FoundFile = FALSE;
+ LexArray.DeleteAllMembers();
+
+ return( TRUE );
+}
+
+
+
+VOID
+ATTRIB::Terminate(
+ )
+
+/*++
+
+Routine Description:
+
+ Deletes objects created during initialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ if( _InitialDirectory != NULL ) {
+ DELETE( _InitialDirectory );
+ }
+}
+
+
+
+VOID
+ATTRIB::DisplayFileNotFoundMessage(
+ )
+
+/*++
+
+Routine Description:
+
+ Displays a message indicating that no file that meets the file filter
+ criteria was found.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ PCWSTRING FileName;
+
+ if( !_FoundFile ) {
+ if( _FileNameArgument.IsValueSet() ) {
+ FileName = _FileNameArgument.GetPath()->GetPathString();
+ } else {
+ FileName = _FullFileNamePath.GetPathString();
+ }
+ DebugPtrAssert( FileName );
+
+ _Message.Set( MSG_ATTRIB_FILE_NOT_FOUND );
+ _Message.Display( "%W", FileName );
+ }
+}
+
+
+
+VOID
+ATTRIB::DisplayFileAttribute (
+ IN PCFSNODE Fsn
+ )
+
+/*++
+
+Routine Description:
+
+ Displays a filename and its attributes
+
+Arguments:
+
+ Fsn - A pointer to an FSNODE that contains the information
+ about the file.
+
+Return Value:
+
+ None.
+
+--*/
+
+
+{
+// PCWC_STRING pcWcString;
+ PCWSTRING pcWcString;
+
+ WCHAR Buffer[ 12 ];
+ DSTRING String;
+
+ DebugPtrAssert( Fsn );
+ DebugPtrAssert( Fsn->GetPath( ));
+ pcWcString = ( Fsn->GetPath( ))->GetPathString( );
+ DebugPtrAssert( pcWcString );
+
+
+ swprintf( Buffer,
+ ( LPWSTR )L"%lc %lc%lc%lc ",
+ Fsn->IsArchived() ? ( WCHAR )'A' : ( WCHAR )' ',
+ Fsn->IsSystem() ? ( WCHAR )'S' : ( WCHAR )' ',
+ Fsn->IsHidden() ? ( WCHAR )'H' : ( WCHAR )' ',
+ Fsn->IsReadOnly() ? ( WCHAR )'R' : ( WCHAR )' ' );
+
+ if( !String.Initialize( Buffer ) ||
+ !String.Strcat( pcWcString ) ||
+ !String.Strcat( &_EndOfLineString ) ||
+ !_OutStream->WriteString( &String ) ) {
+ DebugPrint( "Unable to display message" );
+ }
+}
+
+
+BOOLEAN
+ATTRIB::ChangeFileAttributes(
+ IN PFSNODE FsnFile
+ )
+
+/*++
+
+Routine Description:
+
+ Changes the file attributes. The attributes will be changed depending
+ on the argumets specified in the command line, and on the current
+ attributes of the file.
+ The algorithm for changing attributes is presented below:
+
+ if( ( -s and -h were specified as arguments ) or
+ ( -s and +h were specified as arguments ) or
+ ( +s and -h were specified as arguments ) or
+ ( +s and +h were specified as arguments ) ) {
+ Change file attributes;
+ } else if ( ( -h and +h were not specified as arguments ) and
+ ( file has hidden attribute ) ) {
+ print( "Not resetting hidden file: <filename> " );
+ } else if ( ( -s and +s were not specified as arguments ) and
+ ( file has system attribute ) ) {
+ print( "Not resetting system file: <filename> " );
+ } else {
+ Change file attributes;
+ }
+
+
+Arguments:
+
+ FsnFile - A pointer to an FSNODE that contains the information
+ about the file.
+
+Return Value:
+
+ BOOLEAN - Returns FALSE if this function fails due to a failure
+ in an API call.
+
+
+--*/
+
+
+{
+// BOOLEAN Result;
+ BOOLEAN Change;
+ DWORD Win32Error;
+
+// PCWC_STRING pcWcString;
+ PCWSTRING pcWcString;
+
+ FSN_ATTRIBUTE Attributes;
+
+ DebugPtrAssert( FsnFile->GetPath( ));
+ pcWcString = ( FsnFile->GetPath( ))->GetPathString( );
+ DebugPtrAssert( pcWcString );
+
+ if( ( ( _FlagAddSystemAttribute.QueryFlag() ||
+ _FlagRemoveSystemAttribute.QueryFlag() ) &&
+ ( _FlagAddHiddenAttribute.QueryFlag() ||
+ _FlagRemoveHiddenAttribute.QueryFlag() ) ) ) {
+ Change = TRUE;
+ } else if( !_FlagAddHiddenAttribute.QueryFlag() &&
+ !_FlagRemoveHiddenAttribute.QueryFlag() &&
+ FsnFile->IsHidden() ) {
+// DebugPtrAssert( FsnFile->GetPath( ));
+// pcWcString = ( FsnFile->GetPath( ))->GetPathString( );
+// DebugPtrAssert( pcWcString );
+ _Message.Set( MSG_ATTRIB_NOT_RESETTING_HIDDEN_FILE );
+ _Message.Display( "%W", pcWcString );
+ Change = FALSE;
+ } else if( !_FlagAddSystemAttribute.QueryFlag() &&
+ !_FlagRemoveSystemAttribute.QueryFlag() &&
+ FsnFile->IsSystem() ) {
+// DebugPtrAssert( FsnFile->GetPath( ));
+// pcWcString = ( FsnFile->GetPath( ))->GetPathString( );
+// DebugPtrAssert( pcWcString );
+ _Message.Set( MSG_ATTRIB_NOT_RESETTING_SYS_FILE );
+ _Message.Display( "%W", pcWcString );
+ Change = FALSE;
+ } else {
+ Change = TRUE;
+ }
+
+// Result = TRUE;
+ if( Change ) {
+ Attributes = FsnFile->QueryAttributes();
+ if( !FsnFile->SetAttributes( ( Attributes & _ResetMask ) | _MakeMask,
+ &Win32Error ) ) {
+ if( Win32Error == ERROR_ACCESS_DENIED ) {
+ _Message.Set( MSG_ATTRIB_ACCESS_DENIED );
+ } else {
+ _Message.Set( MSG_ATTRIB_UNABLE_TO_CHANGE_ATTRIBUTE );
+ }
+ _Message.Display( "%W", pcWcString );
+ DebugPrint( "Unable to change file attribute \n" );
+ return( FALSE );
+ }
+ }
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+ATTRIB::ExamineFiles(
+ IN PFSN_DIRECTORY Directory
+ )
+
+/*++
+
+Routine Description:
+
+ Builds an array of files in the specified directory, and
+ tries to change the attributes of each of these files.
+ Does the same thing in all subdirectories, if the "recurse"
+ flag was specified in the command line.
+
+Arguments:
+
+ Directory - Pointer to an FSN_DIRECTORY that describes the
+ directory to be examined
+
+Return Value:
+
+ Boolean: TRUE if Successful.
+
+--*/
+
+{
+ PARRAY DirectoryArray;
+ PFSN_DIRECTORY FsnDirectory;
+ PARRAY_ITERATOR DirectoryArrayIterator;
+ PARRAY FileArray;
+ PARRAY_ITERATOR FileArrayIterator;
+ PFSNODE FsnFile;
+
+
+ DebugPtrAssert( Directory );
+ //
+ // If /S was specified as argument in the command line, builds
+ // an array of PFSN_DIRECTORY of all sub-directories in the current
+ // directory and examines the files in each sub-directory
+ //
+ if( _FlagRecurseDirectories.QueryFlag() ) {
+ if( ( DirectoryArray = Directory->QueryFsnodeArray( &_FsnFilterDirectory ) ) == NULL ) {
+ DebugPrint( "Directory->QueryFsnodeArray( &_FsnFilterDirectory ) failed \n" );
+ return( FALSE );
+ }
+ if( ( DirectoryArrayIterator =
+ ( PARRAY_ITERATOR )( DirectoryArray->QueryIterator() ) ) == NULL ) {
+ DebugPrint( "DirectoryArray->QueryIterator() failed \n" );
+ return( FALSE );
+ }
+
+ while( ( FsnDirectory = ( PFSN_DIRECTORY )( DirectoryArrayIterator->GetNext( ) ) ) != NULL ) {
+ ExamineFiles( FsnDirectory );
+ DELETE( FsnDirectory );
+ }
+
+ DELETE( DirectoryArrayIterator );
+ DELETE( DirectoryArray );
+ }
+
+ //
+ // Builds an array of FSNODEs of the files tha meet the 'filter'
+ // criteria, and change or display the attributes of these files
+ //
+ if( ( FileArray = Directory->QueryFsnodeArray( &_FsnFilterFile ) ) == NULL ) {
+ DebugPrint( "Directory->QueryFsnodeArray( &_FsnFilterFile ) failed \n" );
+ return( FALSE );
+ }
+ if( ( FileArrayIterator =
+ ( PARRAY_ITERATOR )( FileArray->QueryIterator() ) ) == NULL ) {
+ DebugPrint( "FileArray->QueryIterator() failed \n" );
+ return( FALSE );
+ }
+
+ while( ( FsnFile = ( PFSNODE )( FileArrayIterator->GetNext( ) ) ) != NULL ) {
+ if( _PrintAttribInfo ) {
+ DisplayFileAttribute( FsnFile );
+ } else {
+ ChangeFileAttributes( FsnFile );
+ }
+
+ _FoundFile = TRUE;
+
+ DELETE( FsnFile );
+ }
+ DELETE( FileArrayIterator );
+ DELETE( FileArray );
+ return( TRUE );
+}
+
+
+
+ULONG _CRTAPI1
+main()
+
+{
+ DEFINE_CLASS_DESCRIPTOR( ATTRIB );
+
+ {
+ ATTRIB Attrib;
+
+ perrstk = NEW ERRSTACK;
+
+ if( Attrib.Initialize() ) {
+ Attrib.ExamineFiles( Attrib.GetInitialDirectory() );
+ Attrib.DisplayFileNotFoundMessage();
+ }
+ Attrib.Terminate();
+ DELETE( perrstk );
+ }
+ return( 0 );
+}
diff --git a/private/utils/attrib/attrib.hxx b/private/utils/attrib/attrib.hxx
new file mode 100644
index 000000000..c799a7a36
--- /dev/null
+++ b/private/utils/attrib/attrib.hxx
@@ -0,0 +1,141 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ attrib.hxx
+
+Abstract:
+
+
+Author:
+
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if ! defined( _ATTRIB_ )
+
+#define _ATTRIB_
+
+#include "object.hxx"
+#include "keyboard.hxx"
+#include "program.hxx"
+
+DECLARE_CLASS( TREE );
+
+class ATTRIB : public PROGRAM {
+
+ public:
+
+
+ DECLARE_CONSTRUCTOR( ATTRIB );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ ChangeFileAttributes (
+ IN PFSNODE FsnFile
+ );
+
+
+ NONVIRTUAL
+ VOID
+ DisplayFileAttribute (
+ IN PCFSNODE Fsn
+ );
+
+ NONVIRTUAL
+ VOID
+ DisplayFileNotFoundMessage(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ExamineFiles(
+ IN PFSN_DIRECTORY Directory
+ );
+
+
+ NONVIRTUAL
+ PFSN_DIRECTORY
+ GetInitialDirectory(
+ ) CONST;
+
+
+ NONVIRTUAL
+ VOID
+ Terminate(
+ );
+
+
+ private:
+
+
+ FLAG_ARGUMENT _FlagAddSystemAttribute;
+ FLAG_ARGUMENT _FlagRemoveSystemAttribute;
+ FLAG_ARGUMENT _FlagAddHiddenAttribute;
+ FLAG_ARGUMENT _FlagRemoveHiddenAttribute;
+ FLAG_ARGUMENT _FlagAddReadOnlyAttribute;
+ FLAG_ARGUMENT _FlagRemoveReadOnlyAttribute;
+ FLAG_ARGUMENT _FlagAddArchiveAttribute;
+ FLAG_ARGUMENT _FlagRemoveArchiveAttribute;
+ FLAG_ARGUMENT _FlagRecurseDirectories;
+ FLAG_ARGUMENT _FlagDisplayHelp;
+ PATH_ARGUMENT _FileNameArgument;
+
+ PFSN_DIRECTORY _InitialDirectory;
+
+ FSN_FILTER _FsnFilterDirectory;
+ FSN_FILTER _FsnFilterFile;
+
+ BOOLEAN _PrintAttribInfo;
+ STREAM_MESSAGE _Message;
+ PATH _FullFileNamePath;
+ BOOLEAN _FoundFile;
+
+ FSN_ATTRIBUTE _MakeMask;
+ FSN_ATTRIBUTE _ResetMask;
+ DSTRING _EndOfLineString;
+ PSTREAM _OutStream;
+
+};
+
+
+
+INLINE
+PFSN_DIRECTORY
+ATTRIB::GetInitialDirectory(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PFSN_DIRECTORY
+
+
+--*/
+
+{
+ return( _InitialDirectory );
+}
+
+
+#endif // _ATTRIB_
diff --git a/private/utils/attrib/attrib.rc b/private/utils/attrib/attrib.rc
new file mode 100644
index 000000000..91add4c2c
--- /dev/null
+++ b/private/utils/attrib/attrib.rc
@@ -0,0 +1,11 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Attribute Utility"
+#define VER_INTERNALNAME_STR "attrib\0"
+#define VER_ORIGINALFILENAME_STR "ATTRIB.EXE"
+
+#include "common.ver"
+
diff --git a/private/utils/attrib/makefile b/private/utils/attrib/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/attrib/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/attrib/sources b/private/utils/attrib/sources
new file mode 100644
index 000000000..4969bc210
--- /dev/null
+++ b/private/utils/attrib/sources
@@ -0,0 +1,56 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=utils
+MINORCOMP=attrib
+
+TARGETNAME=attrib
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=attrib.cxx attrib.rc
+
+INCLUDES=..\ulib\inc;\nt\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+UMLIBS= \
+ ..\ulib\src\obj\*\ulib.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+
+UMTYPE=console
diff --git a/private/utils/autochk/autochk.cxx b/private/utils/autochk/autochk.cxx
new file mode 100644
index 000000000..6022bbe0c
--- /dev/null
+++ b/private/utils/autochk/autochk.cxx
@@ -0,0 +1,870 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ autochk.cxx
+
+Abstract:
+
+ This is the main program for the autocheck version of chkdsk.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 31-May-91
+
+--*/
+
+#include "ulib.hxx"
+#include "wstring.hxx"
+#include "fatvol.hxx"
+#include "untfs.hxx"
+#include "ntfsvol.hxx"
+#include "spackmsg.hxx"
+#include "error.hxx"
+#include "ifssys.hxx"
+#include "rtmsg.h"
+#include "rcache.hxx"
+#include "autoreg.hxx"
+
+BOOLEAN
+RegistrySosOption(
+ );
+
+extern "C" BOOLEAN
+InitializeUfat(
+ PVOID DllHandle,
+ ULONG Reason,
+ PCONTEXT Context
+ );
+
+extern "C" BOOLEAN
+InitializeUntfs(
+ PVOID DllHandle,
+ ULONG Reason,
+ PCONTEXT Context
+ );
+
+extern "C" BOOLEAN
+InitializeIfsUtil(
+ PVOID DllHandle,
+ ULONG Reason,
+ PCONTEXT Context
+ );
+
+BOOLEAN
+ExtendNtfsVolume(
+ PCWSTRING DriveName,
+ PMESSAGE Message
+ );
+
+BOOLEAN
+DeregisterAutochk(
+ int argc,
+ char** argv
+ );
+
+BOOLEAN
+QueryNextHardDrive(
+ PWSTRING DriveName,
+ PWSTRING FriendlyDriveName
+ );
+
+int _CRTAPI1
+main(
+ int argc,
+ char** argv,
+ char** envp,
+ ULONG DebugParameter
+ )
+/*++
+
+Routine Description:
+
+ This routine is the main program for autocheck FAT chkdsk.
+
+Arguments:
+
+ argc, argv - Supplies the fully qualified NT path name of the
+ the drive to check.
+
+Return Value:
+
+ 0 - Success.
+ 1 - Failure.
+
+--*/
+{
+ if (!InitializeUlib( NULL, ! DLL_PROCESS_DETACH, NULL ) ||
+ !InitializeIfsUtil(NULL,0,NULL) ||
+ !InitializeUfat(NULL,0,NULL) ||
+ !InitializeUntfs(NULL,0,NULL)) {
+ return 1;
+ }
+ //
+ // The declarations must come after these initialization functions.
+ //
+ DSTRING dos_drive_name;
+ DSTRING drive_name;
+ DSTRING skip_list;
+ PFAT_VOL fatvol = NULL;
+ PNTFS_VOL ntfsvol = NULL;
+ AUTOCHECK_MESSAGE *msg;
+ PVOL_LIODPDRV vol;
+ DSTRING fsname;
+ DSTRING fatname;
+ DSTRING ntfsname;
+ BOOLEAN onlyifdirty = TRUE;
+ BOOLEAN recover = FALSE;
+ BOOLEAN extend = FALSE;
+ BOOLEAN remove_registry = FALSE;
+ PREAD_CACHE read_cache;
+ DSTRING boot_execute_log_file_name;
+ FSTRING boot_ex_temp;
+ HMEM logged_message_mem;
+ ULONG packed_log_length;
+ ULONG ArgOffset = 1;
+ BOOLEAN SetupOutput = FALSE;
+ BOOLEAN SetupSpecialFixLevel = FALSE;
+ ULONG exit_status = 0;
+ BOOLEAN SuppressOutput = TRUE; // dots only by default
+ DSTRING drive_letter;
+ BOOLEAN resize_logfile = FALSE;
+ BOOLEAN all_drives = FALSE;
+ LONG logfile_size = 0;
+
+ if (!drive_letter.Initialize() ||
+ !skip_list.Initialize() ||
+ !drive_name.Initialize()) {
+
+ return 1;
+ }
+
+ // Parse the arguments--the accepted arguments are:
+ //
+ // autochk [/s] [/dx:] [/p] [/r] nt-drive-name
+ // autochk [/dx:] [/p] [/r] [/m] [/l:size] nt-drive-name
+ // autochk [/s] /x dos-drive-name
+ // autochk [/k:drives] *
+ //
+ // /s - setup: no output
+ // /d - the drive letter is x:
+ // /p - check even if not dirty
+ // /r - recover; implies /p
+ // /l - resize log file to <size> kilobytes. May not be combined with
+ // /s because /s explicitly inhibits logfile resizing.
+ // /x - extend volume
+ // /k - a list of drive letters to skip
+ // /m - remove registry entry after running
+ //
+
+ if (argc < 2) {
+
+ // Not enough arguments.
+ return 1;
+ }
+
+ for (ArgOffset = 1; ArgOffset < (ULONG)argc; ++ArgOffset) {
+
+ if ((argv[ArgOffset][0] == '/' || argv[ArgOffset][0] == '-') &&
+ (argv[ArgOffset][1] == 's' || argv[ArgOffset][1] == 'S') &&
+ (argv[ArgOffset][2] == 0) ) {
+ //
+ // Then we're in silent mode
+ //
+ SetupOutput = TRUE;
+ continue;
+ }
+
+ if ((argv[ArgOffset][0] == '/' || argv[ArgOffset][0] == '-') &&
+ (argv[ArgOffset][1] == 'p' || argv[ArgOffset][1] == 'P') &&
+ (argv[ArgOffset][2] == 0) ) {
+
+ // argv[ArgOffset] is the /p parameter, so argv[ArgOffset+1]
+ // must be the drive.
+
+ onlyifdirty = FALSE;
+
+ continue;
+ }
+ if( (argv[ArgOffset][0] == '/' || argv[ArgOffset][0] == '-') &&
+ (argv[ArgOffset][1] == 'r' || argv[ArgOffset][1] == 'R') &&
+ (argv[ArgOffset][2] == 0) ) {
+
+ // Note that /r implies /p.
+ //
+ recover = TRUE;
+ onlyifdirty = FALSE;
+ continue;
+
+ }
+ if( (argv[ArgOffset][0] == '/' || argv[ArgOffset][0] == '-') &&
+ (argv[ArgOffset][1] == 'x' || argv[ArgOffset][1] == 'X') &&
+ (argv[ArgOffset][2] == 0) ) {
+
+ // when the /x parameter is specified, we accept a
+ // DOS name and do a complete check.
+ //
+ onlyifdirty = FALSE;
+ extend = TRUE;
+
+ if( !dos_drive_name.Initialize( argv[ArgOffset + 1] ) ||
+ !IFS_SYSTEM::DosDriveNameToNtDriveName( &dos_drive_name,
+ &drive_name ) ) {
+
+ return 1;
+ }
+ ArgOffset++;
+ continue;
+
+ }
+ if ((argv[ArgOffset][0] == '/' || argv[ArgOffset][0] == '-') &&
+ (argv[ArgOffset][1] == 'd' || argv[ArgOffset][1] == 'D')) {
+
+ //
+ // A parameter of the form "/dX:" indicates that we are checking
+ // the volume whose drive letter is X:.
+ //
+
+ if (!drive_letter.Initialize(&argv[ArgOffset][2])) {
+ return 1;
+ }
+
+ continue;
+
+ }
+ if ((argv[ArgOffset][0] == '/' || argv[ArgOffset][0] == '-') &&
+ (argv[ArgOffset][1] == 'l' || argv[ArgOffset][1] == 'L')) {
+
+ DSTRING number;
+
+ // The /l parameter indicates that we're to resize the log file.
+ // The size should always be specified, and it is in kilobytes.
+ //
+
+ resize_logfile = TRUE;
+
+ if (!number.Initialize(&argv[ArgOffset][3]) ||
+ !number.QueryNumber(&logfile_size) ||
+ logfile_size < 0) {
+ return 1;
+ }
+
+ logfile_size *= 1024;
+
+ continue;
+
+ }
+ if ((argv[ArgOffset][0] == '/' || argv[ArgOffset][0] == '-') &&
+ (argv[ArgOffset][1] == 'k' || argv[ArgOffset][1] == 'K')) {
+
+ // Skip.
+
+ if (!skip_list.Initialize(&argv[ArgOffset][3])) {
+ return 1;
+ }
+
+ continue;
+ }
+ if ((argv[ArgOffset][0] == '/' || argv[ArgOffset][0] == '-') &&
+ (argv[ArgOffset][1] == 'm' || argv[ArgOffset][1] == 'M')) {
+
+ remove_registry = TRUE;
+ continue;
+ }
+
+ if ((argv[ArgOffset][0] != '/' && argv[ArgOffset][0] != '-')) {
+
+ // We've run off the options into the arguments.
+
+ break;
+ }
+ }
+
+ // argv[ArgOffset] is the drive;
+
+ if (NULL != argv[ArgOffset]) {
+ if ('*' == argv[ArgOffset][0]) {
+
+ all_drives = TRUE;
+
+ if (!drive_name.Initialize("")) {
+ return 1;
+ }
+
+ } else {
+
+ all_drives = FALSE;
+
+ if (!drive_name.Initialize(argv[ArgOffset])) {
+ return 1;
+ }
+ }
+ }
+
+ if (!fatname.Initialize("FAT") ||
+ !ntfsname.Initialize("NTFS")) {
+
+ return 1;
+ }
+ //
+ // Determine whether to suppress output or not. If compiled with
+ // DBG==1, print normal output. Otherwise look in the registry to
+ // see if the machine has "SOS" in the NTLOADOPTIONS.
+ //
+#if defined _AUTOCHECK_DBG_
+
+ SuppressOutput = FALSE;
+
+#else /* _AUTOCHECK_DBG */
+
+ if (RegistrySosOption()) {
+ SuppressOutput = FALSE;
+ }
+
+#endif /* _AUTOCHECK_DBG_ */
+
+ //
+ // If this is autochk /r or /l, we've been started from an explicit
+ // registry entry and the dirty bit may not be set. We want to
+ // deliver interesting output regardless.
+ //
+
+ if (recover || resize_logfile) {
+ SuppressOutput = FALSE;
+ }
+
+ if (SetupOutput) {
+ msg = NEW SP_AUTOCHECK_MESSAGE;
+ } else {
+ msg = NEW AUTOCHECK_MESSAGE;
+ }
+
+ if (NULL == msg || !msg->Initialize(SuppressOutput)) {
+ return 1;
+ }
+
+ for (;;) {
+
+ if (all_drives && !QueryNextHardDrive(&drive_name, &drive_letter)) {
+
+ break;
+ }
+ if (skip_list.QueryChCount() > 0 &&
+ INVALID_CHNUM != skip_list.Strchr(*drive_letter.GetWSTR())) {
+
+ // Skip this one.
+
+ continue;
+ }
+
+ if (!IFS_SYSTEM::QueryFileSystemName(&drive_name, &fsname)) {
+ msg->Set( MSG_FS_NOT_DETERMINED );
+ msg->Display( "%W", &drive_name );
+ return 1;
+ }
+ if (recover) {
+ msg->Set(MSG_BLANK_LINE);
+ msg->Display();
+ msg->SetLoggingEnabled();
+
+ } else {
+ if (all_drives) {
+
+ msg->Set(MSG_CHK_RUNNING);
+ msg->Display("%W", &drive_letter);
+ }
+
+ msg->Set(MSG_FILE_SYSTEM_TYPE);
+ msg->Display("%W", &fsname);
+ }
+
+ if (fsname == fatname) {
+
+ if (!(fatvol = NEW FAT_VOL) ||
+ !fatvol->Initialize(&drive_name, msg, TRUE)) {
+ return 1;
+ }
+
+ if ((read_cache = NEW READ_CACHE) &&
+ read_cache->Initialize(fatvol, 75)) {
+
+ fatvol->SetCache(read_cache);
+
+ } else {
+ DELETE(read_cache);
+ }
+
+ vol = fatvol;
+
+ } else if (fsname == ntfsname) {
+
+ if( extend ) {
+
+ // NOTE: this roundabout method is necessary to
+ // convince NTFS to allow us to access the new
+ // sectors on the volume.
+ //
+ if( !ExtendNtfsVolume( &drive_name, msg ) ) {
+
+ return 1;
+ }
+
+ if( !(ntfsvol = NEW NTFS_VOL) ||
+ !ntfsvol->Initialize( &drive_name, msg ) ) {
+
+ return 1;
+ }
+
+ if( !ntfsvol->Lock() ) {
+
+ msg->Set( MSG_CANT_LOCK_THE_DRIVE );
+ msg->Display( "" );
+ }
+
+ } else {
+
+ if (!(ntfsvol = NEW NTFS_VOL) ||
+ !ntfsvol->Initialize(&drive_name, msg, TRUE)) {
+ return 1;
+ }
+
+ if (SetupOutput) {
+
+ //
+ // SetupSpecialFixLevel will be used for NTFS... it means
+ // to refrain from resizing the log file.
+ //
+
+ SetupSpecialFixLevel = TRUE;
+ }
+ }
+
+ // The read cache for NTFS CHKDSK gets set in VerifyAndFix.
+
+ vol = ntfsvol;
+
+ } else {
+ msg->Set( MSG_FS_NOT_SUPPORTED );
+ msg->Display( "%s%W", "AUTOCHK", &fsname );
+ return 1;
+
+ }
+
+ // If the /r, /l, or /m switch was supplied, remove the forcing
+ // entry from the registry before calling Chkdsk, since
+ // Chkdsk may reboot the system if we are checking the
+ // boot partition.
+ //
+
+ if (recover || resize_logfile || remove_registry) {
+
+ DeregisterAutochk( argc, argv );
+ }
+
+ // Invoke chkdsk. Note that if the /r parameter is supplied,
+ // we recover both free and allocated space, but if the /x
+ // parameter is supplied, we only recover free space.
+ //
+
+ if (!vol->ChkDsk(
+ SetupSpecialFixLevel ? SetupSpecial : TotalFix,
+ msg,
+ FALSE,
+ onlyifdirty,
+ recover || extend,
+ recover,
+ resize_logfile,
+ (ULONG)logfile_size,
+ &exit_status,
+ 0 == drive_letter.QueryChCount() ? NULL : &drive_letter)) {
+
+ if (!all_drives) {
+ if (SetupSpecialFixLevel) {
+ return exit_status;
+ } else {
+ return 1;
+ }
+ }
+ }
+
+ DELETE( vol );
+
+
+ // Dump the message retained by the message object into a file.
+ //
+ if( msg->IsLoggingEnabled() &&
+ boot_execute_log_file_name.Initialize( &drive_name ) &&
+ boot_ex_temp.Initialize( L"\\BOOTEX.LOG" ) &&
+ boot_execute_log_file_name.Strcat( &boot_ex_temp ) &&
+ logged_message_mem.Initialize() &&
+ msg->QueryPackedLog( &logged_message_mem, &packed_log_length ) ) {
+
+ IFS_SYSTEM::WriteToFile( &boot_execute_log_file_name,
+ logged_message_mem.GetBuf(),
+ packed_log_length,
+ TRUE );
+ }
+
+ //
+ // If we were checking only a single drive, we're done. Break out
+ // of this loop and go on to the cleanup code.
+ //
+
+ if (!all_drives) {
+
+ break;
+ }
+ }
+
+ // If the /x switch was supplied, remove the
+ // forcing entry from the registry, since Chkdsk
+ // has completed successfully.
+ //
+
+ if (extend) {
+
+ DeregisterAutochk( argc, argv );
+ }
+
+ if (SetupSpecialFixLevel) {
+
+ return exit_status;
+ } else {
+ return 0;
+ }
+}
+
+#define CONTROL_NAME \
+ L"\\Registry\\Machine\\System\\CurrentControlSet\\Control"
+#define VALUE_NAME L"SystemStartOptions"
+#define VALUE_BUFFER_SIZE \
+ (sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 256 * sizeof(WCHAR))
+
+BOOLEAN
+RegistrySosOption(
+ )
+/*++
+
+Routine Description:
+
+ This function examines the registry to determine whether the
+ user's NTLOADOPTIONS boot environment variable contains the string
+ "SOS" or not.
+
+ HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control:SystemStartOptions
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if "SOS" was set. Otherwise FALSE.
+
+--*/
+{
+ NTSTATUS st;
+ UNICODE_STRING uKeyName, uValueName;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE hKey;
+ WCHAR ValueBuf[VALUE_BUFFER_SIZE];
+ PKEY_VALUE_PARTIAL_INFORMATION pKeyValueInfo =
+ (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuf;
+ ULONG ValueLength;
+
+ RtlInitUnicodeString(&uKeyName, CONTROL_NAME);
+ InitializeObjectAttributes(&ObjectAttributes, &uKeyName,
+ OBJ_CASE_INSENSITIVE, NULL, NULL);
+
+ st = NtOpenKey(&hKey, KEY_READ, &ObjectAttributes);
+ if (!NT_SUCCESS(st)) {
+ DebugPrintf("AUTOCHK: can't open control key: 0x%x\n", st);
+ return FALSE;
+ }
+
+ RtlInitUnicodeString(&uValueName, VALUE_NAME);
+
+ st = NtQueryValueKey(hKey, &uValueName, KeyValuePartialInformation,
+ (PVOID)pKeyValueInfo, VALUE_BUFFER_SIZE, &ValueLength);
+
+ ASSERT(ValueLength < VALUE_BUFFER_SIZE);
+
+ NtClose(hKey);
+
+ if (!NT_SUCCESS(st)) {
+ DebugPrintf("AUTOCHK: can't query value key: 0x%x\n", st);
+ return FALSE;
+ }
+
+ // uValue.Buffer = (PVOID)&pKeyValueInfo->Data;
+ // uValue.Length = uValue.MaximumLength = (USHORT)pKeyValueInfo->DataLength;
+
+ if (NULL != wcsstr((PWCHAR)&pKeyValueInfo->Data, L"SOS") ||
+ NULL != wcsstr((PWCHAR)&pKeyValueInfo->Data, L"sos")) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOLEAN
+ExtendNtfsVolume(
+ PCWSTRING DriveName,
+ PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This function changes the count of sectors in sector
+ zero to agree with the drive object. This is useful
+ when extending volume sets. Note that it requires that
+ we be able to lock the volume, and that it should only
+ be called if we know that the drive in question in an
+ NTFS volume. This function also copies the boot sector
+ to the end of the partition, where it's kept as a backup.
+
+Arguments:
+
+ DriveName -- Supplies the name of the volume.
+ Message -- Supplies an output channel for messages.
+
+Return Value:
+
+ TRUE upon completion.
+
+--*/
+{
+ LOG_IO_DP_DRIVE Drive;
+ SECRUN Secrun;
+ HMEM Mem;
+
+ PPACKED_BOOT_SECTOR BootSector;
+
+ if( !Drive.Initialize( DriveName, Message ) ||
+ !Drive.Lock() ||
+ !Mem.Initialize() ||
+ !Secrun.Initialize( &Mem, &Drive, 0, 1 ) ||
+ !Secrun.Read() ) {
+
+ return FALSE;
+ }
+
+ BootSector = (PPACKED_BOOT_SECTOR)Secrun.GetBuf();
+
+ //
+ // We leave an extra sector at the end of the volume to contain
+ // the new replica boot sector.
+ //
+
+ BootSector->NumberSectors.LowPart = Drive.QuerySectors().GetLowPart() - 1;
+ BootSector->NumberSectors.HighPart = Drive.QuerySectors().GetHighPart();
+
+ if (!Secrun.Write()) {
+
+ return FALSE;
+ }
+
+ Secrun.Relocate( Drive.QuerySectors() - 2 );
+
+ if (!Secrun.Write()) {
+
+ DebugPrintf("Error: %x\n", Drive.QueryLastNtStatus());
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+DeregisterAutochk(
+ int argc,
+ char** argv
+ )
+/*++
+
+Routine Description:
+
+ This function removes the registry entry which triggered
+ autochk. It is only called if the /x or /r entry is present.
+
+Arguments:
+
+ argc -- Supplies the number of arguments given to autochk.
+ argv -- supplies the arguments given to autochk.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ DSTRING CommandLineString1,
+ CommandLineString2,
+ CurrentArgString,
+ OneSpace;
+ int i;
+
+ // Reconstruct the command line and remove it from
+ // the registry. First, reconstruct the primary
+ // string, which is "autochk arg1 arg2...".
+ //
+ if( !CommandLineString1.Initialize( "autochk" ) ||
+ !OneSpace.Initialize( " " ) ) {
+
+ return FALSE;
+ }
+
+ for( i = 1; i < argc; i++ ) {
+
+ if( !CurrentArgString.Initialize(argv[i] ) ||
+ !CommandLineString1.Strcat( &OneSpace ) ||
+ !CommandLineString1.Strcat( &CurrentArgString ) ) {
+
+ return FALSE;
+ }
+ }
+
+ // Now construct the secondary string, which is
+ // "autocheck autochk arg1 arg2..."
+ //
+ if( !CommandLineString2.Initialize( "autocheck " ) ||
+ !CommandLineString2.Strcat( &CommandLineString1 ) ) {
+
+ return FALSE;
+ }
+
+ return( AUTOREG::DeleteEntry( &CommandLineString1 ) &&
+ AUTOREG::DeleteEntry( &CommandLineString2 ) );
+
+}
+
+
+BOOLEAN
+QueryNextHardDrive(
+ PWSTRING DriveName,
+ PWSTRING FriendlyDriveName
+ )
+{
+ static BOOLEAN first_time = TRUE;
+ static HANDLE dos_devices_object_dir;
+ static ULONG context = 0;
+
+ WCHAR link_target_buffer[MAXIMUM_FILENAME_LENGTH];
+ POBJECT_DIRECTORY_INFORMATION
+ dir_info;
+ OBJECT_ATTRIBUTES object_attributes;
+ CHAR dir_info_buffer[256];
+ BOOLEAN restart_scan;
+ ULONG length;
+ HANDLE handle;
+ NTSTATUS status;
+
+ UNICODE_STRING link_target;
+ UNICODE_STRING link_type_name;
+ UNICODE_STRING link_target_prefix;
+ UNICODE_STRING u;
+
+ link_target.Buffer = link_target_buffer;
+ dir_info = (POBJECT_DIRECTORY_INFORMATION)dir_info_buffer;
+
+ RtlInitUnicodeString(&link_type_name, L"SymbolicLink");
+ RtlInitUnicodeString(&link_target_prefix, L"\\Device\\Harddisk");
+
+
+ if (first_time) {
+ first_time = FALSE;
+ restart_scan = TRUE;
+
+ RtlInitUnicodeString(&u, L"\\??");
+
+ InitializeObjectAttributes(&object_attributes, &u,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ status = NtOpenDirectoryObject(&dos_devices_object_dir,
+ DIRECTORY_ALL_ACCESS,
+ &object_attributes);
+
+ if (!NT_SUCCESS(status)) {
+
+ DebugPrintf("AUTOCHK: Unable to open %wZ directory - Status == %lx\n",
+ &u, status);
+ return FALSE;
+ }
+
+ } else {
+ restart_scan = FALSE;
+ }
+
+ for (;;) {
+
+ status = NtQueryDirectoryObject(dos_devices_object_dir,
+ (PVOID)dir_info,
+ sizeof(dir_info_buffer),
+ TRUE,
+ restart_scan,
+ &context,
+ &length);
+ restart_scan = FALSE;
+
+ if (!NT_SUCCESS(status)) {
+ return FALSE;
+ }
+
+ if (status == STATUS_NO_MORE_ENTRIES) {
+ return FALSE;
+ }
+
+ if (RtlEqualUnicodeString(&dir_info->TypeName, &link_type_name, TRUE) &&
+ dir_info->Name.Buffer[(dir_info->Name.Length>>1)-1] == L':') {
+
+ InitializeObjectAttributes(&object_attributes,
+ &dir_info->Name,
+ OBJ_CASE_INSENSITIVE,
+ dos_devices_object_dir,
+ NULL);
+
+ status = NtOpenSymbolicLinkObject(&handle,
+ SYMBOLIC_LINK_ALL_ACCESS,
+ &object_attributes);
+
+ if (!NT_SUCCESS(status)) {
+
+ return FALSE;
+ }
+
+ link_target.Length = 0;
+ link_target.MaximumLength = sizeof(link_target_buffer);
+
+ status = NtQuerySymbolicLinkObject(handle,
+ &link_target,
+ NULL);
+ NtClose(handle);
+
+ if (NT_SUCCESS(status) &&
+ RtlPrefixUnicodeString(&link_target_prefix, &link_target, TRUE )) {
+
+ if (!FriendlyDriveName->Initialize(dir_info->Name.Buffer,
+ dir_info->Name.Length / 2)) {
+
+ return FALSE;
+ }
+
+ if (!DriveName->Initialize(link_target.Buffer,
+ link_target.Length / 2)) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+ }
+ }
+
+ //NOTREACHED
+ return FALSE;
+}
diff --git a/private/utils/autochk/autochk.rc b/private/utils/autochk/autochk.rc
new file mode 100644
index 000000000..958a9a215
--- /dev/null
+++ b/private/utils/autochk/autochk.rc
@@ -0,0 +1,12 @@
+#include "..\ntlib\src\rtmsg.rc"
+
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Auto Check Utility"
+#define VER_INTERNALNAME_STR "AutoChk"
+#define VER_ORIGINALFILENAME_STR "AutoChk.Exe"
+
+#include "common.ver"
diff --git a/private/utils/autochk/daytona/makefile b/private/utils/autochk/daytona/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/autochk/daytona/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/autochk/daytona/sources b/private/utils/autochk/daytona/sources
new file mode 100644
index 000000000..8b9f6cac3
--- /dev/null
+++ b/private/utils/autochk/daytona/sources
@@ -0,0 +1,51 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=utils
+MINORCOMP=autochk
+
+TARGETNAME=autochk
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=\
+ ..\autochk.cxx \
+ ..\autochk.rc
+
+INCLUDES=\
+ ..\..\ntlib\src;\
+ ..\..\ulib\inc;\
+ ..\..\ifsutil\inc;\
+ ..\..\ufat\inc;\
+ ..\..\uhpfs\inc;\
+ ..\..\untfs\inc
+
+C_DEFINES=-DCONDITION_HANDLING=1 -D_AUTOCHECK_ -DUNICODE=1
+
+UMLIBS=..\..\ntlib\src\obj\*\ntlib.lib
+
+UMTYPE=nt
+USE_NTDLL=1
diff --git a/private/utils/autochk/dirs b/private/utils/autochk/dirs
new file mode 100644
index 000000000..86bb0ab90
--- /dev/null
+++ b/private/utils/autochk/dirs
@@ -0,0 +1,18 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+!ENDIF
+
+DIRS=
+
+OPTIONAL_DIRS=daytona
diff --git a/private/utils/autoconv/autoconv.cxx b/private/utils/autoconv/autoconv.cxx
new file mode 100644
index 000000000..7be6a6507
--- /dev/null
+++ b/private/utils/autoconv/autoconv.cxx
@@ -0,0 +1,772 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ autoconv.cxx
+
+Abstract:
+
+ This is the main program for the autoconv version of convert.
+
+Author:
+
+ Ramon J. San Andres (ramonsa) 04-Dec-91
+
+--*/
+
+#include "ulib.hxx"
+#include "wstring.hxx"
+#include "achkmsg.hxx"
+#include "spackmsg.hxx"
+#include "error.hxx"
+#include "ifssys.hxx"
+#include "rtmsg.h"
+#include "ifsentry.hxx"
+#include "convfat.hxx"
+#include "fatvol.hxx"
+#include "autoreg.hxx"
+#include "autoentr.hxx"
+#include "arg.hxx"
+#include "rcache.hxx"
+
+#if INCLUDE_OFS==1
+#include "fatofs.hxx"
+#include "initexcp.hxx"
+#endif // INCLUDE_OFS
+
+extern "C" BOOLEAN
+InitializeUfat(
+ PVOID DllHandle,
+ ULONG Reason,
+ PCONTEXT Context
+ );
+
+extern "C" BOOLEAN
+InitializeUntfs(
+ PVOID DllHandle,
+ ULONG Reason,
+ PCONTEXT Context
+ );
+
+extern "C" BOOLEAN
+InitializeIfsUtil(
+ PVOID DllHandle,
+ ULONG Reason,
+ PCONTEXT Context
+ );
+
+
+BOOLEAN
+DeRegister(
+ int argc,
+ char** argv
+ );
+
+BOOLEAN
+SaveMessageLog(
+ IN OUT PMESSAGE Message,
+ IN PCWSTRING DriveName
+ );
+
+BOOLEAN
+FileDelete(
+ IN PCWSTRING DriveName,
+ IN PCWSTRING FileName
+ );
+
+#if INCLUDE_OFS==1
+
+BOOLEAN
+IsRestartFatToOfs( WSTRING const & DriveName,
+ WSTRING const & CurrentFsName,
+ WSTRING const & TargetFileSystem )
+{
+
+ DSTRING OfsName;
+ DSTRING FatName;
+
+
+ if ( !OfsName.Initialize( L"OFS" ) )
+ return FALSE;
+
+ if ( CurrentFsName != OfsName || TargetFileSystem != OfsName )
+ return FALSE;
+
+ PWSTR pwszDriveName = DriveName.QueryWSTR();
+
+ BOOLEAN fIsRestart = IsFatToOfsRestart( pwszDriveName );
+ DELETE( pwszDriveName );
+
+ return fIsRestart;
+}
+
+BOOLEAN
+IsFatToOfs( WSTRING const & CurrentFsName, WSTRING const & TargetFsName )
+{
+ DSTRING FatName;
+ DSTRING OfsName;
+
+ if ( !FatName.Initialize( L"FAT" ) )
+ return FALSE;
+
+ if ( !OfsName.Initialize( L"OFS" ) )
+ return FALSE;
+
+ return 0 == CurrentFsName.Stricmp(&FatName) &&
+ 0 == TargetFsName.Stricmp(&OfsName);
+}
+
+BOOLEAN
+FatToOfs(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ IN BOOLEAN fInSetup,
+ OUT PCONVERT_STATUS Status )
+{
+
+ PWSTR pwszNtDriveName = NtDriveName->QueryWSTR();
+ FAT_OFS_CONVERT_STATUS cnvStatus;
+ BOOLEAN fResult= ConvertFatToOfs(
+ pwszNtDriveName,
+ Message,
+ Verbose,
+ fInSetup,
+ &cnvStatus );
+
+ DELETE( pwszNtDriveName );
+
+ if ( FAT_OFS_CONVERT_SUCCESS == cnvStatus )
+ {
+ *Status = CONVERT_STATUS_CONVERTED;
+ }
+ else
+ {
+ *Status = CONVERT_STATUS_ERROR;
+ }
+
+ return fResult;
+}
+
+#else
+
+BOOLEAN
+IsRestartFatToOfs( WSTRING const & DriveName, WSTRING const & CurrentFsName,
+ WSTRING const & TargetFileSystem )
+{
+ return FALSE;
+}
+
+BOOLEAN
+IsFatToOfs( WSTRING const & CurrentFsName, WSTRING const & TargetFsName )
+{
+ return FALSE;
+}
+
+BOOLEAN
+FatToOfs(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ IN BOOLEAN fInSetup,
+ OUT PCONVERT_STATUS Status )
+{
+ *Status = CONVERT_STATUS_CONVERSION_NOT_AVAILABLE;
+ return FALSE;
+}
+
+#endif // INCLUDE_OFS
+
+int _CRTAPI1
+main(
+ int argc,
+ char** argv,
+ char** envp,
+ ULONG DebugParameter
+ )
+/*++
+
+Routine Description:
+
+ This routine is the main program for AutoConv
+
+Arguments:
+
+ argc, argv - Supplies the fully qualified NT path name of the
+ the drive to check. The syntax of the autoconv
+ command line is:
+
+ AUTOCONV drive-name /FS:target-file-system [/v] [/s] [/o] [/NAMETABLE:filename]
+
+ /v -- verbose output
+ /s -- run from setup
+ /o -- pause before the final reboot (oem setup)
+
+
+Return Value:
+
+ 0 - Success.
+ 1 - Failure.
+
+--*/
+{
+
+#if INCLUDE_OFS==1
+ InitExceptionSystem();
+#endif // INCLUDE_OFS==1
+
+ if (!InitializeUlib( NULL, ! DLL_PROCESS_DETACH, NULL ) ||
+ !InitializeIfsUtil(NULL, ! DLL_PROCESS_DETACH, NULL) ||
+ !InitializeUfat(NULL, ! DLL_PROCESS_DETACH, NULL) ||
+ !InitializeUntfs(NULL, ! DLL_PROCESS_DETACH, NULL)
+ ) {
+ DebugPrintf( "Failed to initialize U* Dlls" );
+ return 1;
+ }
+
+
+ PFAT_VOL FatVolume;
+ DP_DRIVE DpDrive;
+ PAUTOCHECK_MESSAGE message;
+ DSTRING DriveName;
+ DSTRING FileSystemName;
+ DSTRING CurrentFsName;
+ DSTRING FatName;
+ DSTRING NameTableFileName;
+ DSTRING QualifiedName;
+ FSTRING Backslash;
+ BOOLEAN Converted;
+ BOOLEAN Verbose = FALSE;
+ BOOLEAN Error;
+ CONVERT_STATUS Status;
+ BOOLEAN UseNameTable = FALSE;
+ int i;
+ BOOLEAN fInSetup = FALSE;
+ BOOLEAN Pause = FALSE;
+
+ LARGE_INTEGER DelayInterval;
+
+ FSTRING DosDevicesPattern;
+ DSTRING StrippedDriveName;
+ CHNUM position;
+
+ DebugPrintf( "Entering autoconv argc=%ld\n", argc );
+ for ( i = 0; i < argc; i++ )
+ {
+ DebugPrintf(" argv[%d] = %s\n", i, argv[i] );
+ }
+
+ if (!(perrstk = NEW ERRSTACK)) {
+ DebugPrintf( "Failed to create the error stack\n" );
+ return 1;
+ }
+
+ //
+ // Parse the arguments. The accepted arguments are:
+ //
+ // autoconv NtDrive /fs:<filesystem> [/v]
+ //
+
+ if ( argc < 3 ) {
+ return 1;
+ }
+
+ //
+ // First argument is drive
+ //
+ if ( !DriveName.Initialize( argv[1] ) ||
+ !StrippedDriveName.Initialize( argv[1] ) ) {
+ DebugPrintf( "Failed to intialize DriveName \n" );
+ return 1;
+ }
+
+ DosDevicesPattern.Initialize( (LPWSTR)L"\\??\\" );
+ position = StrippedDriveName.Strstr( &DosDevicesPattern );
+ if (position == 0)
+ StrippedDriveName.DeleteChAt(0, DosDevicesPattern.QueryChCount() );
+
+ DebugPrintf("drive name: %ws\n", StrippedDriveName.GetWSTR());
+
+ //
+ // The rest of the arguments are flags.
+ //
+ for( i = 2; i < argc; i++ ) {
+
+ if ( (strlen(argv[i]) >= 5) &&
+ (argv[i][0] == '/' || argv[i][0] == '-') &&
+ (argv[i][1] == 'f' || argv[i][1] == 'F') &&
+ (argv[i][2] == 's' || argv[i][2] == 'S') &&
+ (argv[i][3] == ':') ) {
+
+ if ( 0 != FileSystemName.QueryChCount() ||
+ !FileSystemName.Initialize( &(argv[i][4]) ) )
+ {
+ DebugPrintf( "Failed to initialize FileSystemName \n" );
+ return 1;
+ }
+ }
+
+ if (0 == _stricmp( argv[i], "/V" ) || 0 == _stricmp( argv[i], "-V" )) {
+ Verbose = TRUE;
+ }
+
+ if (0 == _stricmp(argv[i], "/S") || 0 == _stricmp(argv[i], "-S")) {
+ DebugPrintf("Found /s option\n");
+ fInSetup = TRUE;
+ }
+
+ if (0 == _stricmp(argv[i], "/O") || 0 == _stricmp(argv[i], "-O")) {
+ DebugPrintf("Found /o option\n");
+ Pause = TRUE;
+ }
+
+ if( _strnicmp( "/NAMETABLE:", argv[i], strlen("/NAMETABLE:") ) == 0 ||
+ _strnicmp( "-NAMETABLE:", argv[i], strlen("-NAMETABLE:") ) == 0 ) {
+
+ UseNameTable = TRUE;
+ if( !NameTableFileName.Initialize( &argv[i][strlen("-NAMETABLE:")] ) ) {
+
+ return 1;
+ }
+ }
+ }
+
+ if ( 0 == FileSystemName.QueryChCount() )
+ {
+ DebugPrintf( "No FileSystem name specified\n" );
+ return 1;
+ }
+
+ DebugPrintf("AUTOCONV: TargetFileSystem=%ws\n", FileSystemName.GetWSTR() );
+
+ if (fInSetup) {
+ message = NEW SP_AUTOCHECK_MESSAGE;
+ DebugPrintf("Using setup output\n");
+ } else {
+ DebugPrintf("Not using setup output\n");
+ message = NEW AUTOCHECK_MESSAGE;
+ }
+
+ if (NULL == message || !message->Initialize()) {
+ DebugPrintf( "Failed to intitialize message structure\n" );
+ return 1;
+ }
+
+ if (!FatName.Initialize("FAT")) {
+ return 1;
+ }
+
+ // If this is the System Partition of an ARC machine, don't
+ // convert it.
+ //
+ if( IFS_SYSTEM::IsArcSystemPartition( &DriveName, &Error ) ) {
+
+ message->Set( MSG_CONV_ARC_SYSTEM_PARTITION );
+ message->Display( );
+
+ SaveMessageLog( message, &DriveName );
+ DeRegister( argc, argv );
+ return 1;
+ }
+
+
+
+ if (!IFS_SYSTEM::QueryFileSystemName( &DriveName, &CurrentFsName )) {
+
+ message->Set( MSG_FS_NOT_DETERMINED );
+ message->Display( "%W", &StrippedDriveName );
+
+ SaveMessageLog( message, &DriveName );
+ DeRegister( argc, argv );
+ return 1;
+ }
+
+ message->Set( MSG_FILE_SYSTEM_TYPE );
+ message->Display( "%W", &CurrentFsName );
+
+ CurrentFsName.Strupr();
+ FileSystemName.Strupr();
+
+ if ( CurrentFsName == FileSystemName ) {
+
+ int iReturn = 0;
+
+ if ( IsRestartFatToOfs( DriveName, CurrentFsName, FileSystemName ) ) {
+
+ if ( !FatToOfs( &DriveName, message, Verbose, fInSetup, &Status ) ) {
+ iReturn = 1;
+ }
+ }
+ else {
+ //
+ // The drive is already in the desired file system, our
+ // job is done. Delete the name conversion table (if
+ // specified) and take ourselves out of the registry.
+ // Do not save the message log--there's nothing interesting
+ // in it.
+ //
+ // If we're doing oem pre-install (Pause is TRUE) we don't
+ // want to print this "already converted" message.
+ //
+
+ if (!Pause) {
+
+ message->Set( MSG_CONV_ALREADY_CONVERTED );
+ message->Display( "%W%W", &StrippedDriveName, &FileSystemName );
+ }
+
+ if( UseNameTable ) {
+
+ FileDelete( &DriveName, &NameTableFileName );
+ // BUGBUG billmc -- delete the name table file.
+ //
+ }
+ }
+
+ SaveMessageLog( message, &DriveName );
+ DeRegister( argc, argv );
+ return iReturn;
+ }
+
+ // Determine whether the target file-system is enabled
+ // in the registry. If it is not, refuse to convert
+ // the drive.
+ //
+ if( !IFS_SYSTEM::IsFileSystemEnabled( &FileSystemName ) ) {
+
+ message->Set( MSG_CONVERT_FILE_SYSTEM_NOT_ENABLED );
+ message->Display( "%W", &FileSystemName );
+
+ SaveMessageLog( message, &DriveName );
+ DeRegister( argc, argv );
+ return 1;
+ }
+
+ // Since autoconvert will often be put in place by Setup
+ // to run after AutoSetp, delay for 3 seconds to give the
+ // file system time to clean up detritus of deleted files.
+ //
+ DelayInterval = RtlConvertLongToLargeInteger( -30000000 );
+
+ NtDelayExecution( TRUE, &DelayInterval );
+
+ // Open a volume of the appropriate type. The volume is
+ // opened for exclusive write access.
+ //
+ if( CurrentFsName == FatName ) {
+
+ if( !(FatVolume = NEW FAT_VOL) ||
+ !FatVolume->Initialize( &DriveName, message, TRUE ) ||
+ !FatVolume->ChkDsk( TotalFix, message, FALSE, FALSE ) ) {
+
+ message->Set( MSG_CONV_CANNOT_AUTOCHK );
+ message->Display( "%W%W", &StrippedDriveName, &FileSystemName );
+
+ SaveMessageLog( message, &DriveName );
+ DeRegister( argc, argv );
+ return 1;
+ }
+
+ if ( IsFatToOfs( CurrentFsName, FileSystemName ) ) {
+
+ DELETE (FatVolume);
+
+ message->Set( MSG_CONV_CONVERTING );
+ message->Display( "%W%W", &StrippedDriveName, &FileSystemName );
+
+ Converted = FatToOfs( &DriveName,
+ message,
+ Verbose,
+ fInSetup,
+ &Status );
+ }
+ else {
+
+ message->Set( MSG_CONV_CONVERTING );
+ message->Display( "%W%W", &StrippedDriveName, &FileSystemName );
+
+ Converted = ConvertFATVolume( FatVolume,
+ &FileSystemName,
+ message,
+ Verbose,
+ Pause,
+ &Status );
+
+ DELETE( FatVolume );
+ }
+
+ } else {
+
+ message->Set( MSG_FS_NOT_SUPPORTED );
+ message->Display( "%s%W", "AUTOCONV", &CurrentFsName );
+
+ SaveMessageLog( message, &DriveName );
+ DeRegister( argc, argv );
+ return 1;
+ }
+
+
+ if ( Converted ) {
+
+ message->Set( MSG_CONV_CONVERSION_COMPLETE );
+ message->Display();
+
+ } else {
+
+ //
+ // The conversion was not successful. Determine what the problem was
+ // and return the appropriate CONVERT exit code.
+ //
+ switch ( Status ) {
+
+ case CONVERT_STATUS_CONVERTED:
+ //
+ // This is an inconsistent state, Convert should return
+ // TRUE if the conversion was successful!
+ //
+ break;
+
+ case CONVERT_STATUS_INVALID_FILESYSTEM:
+ //
+ // The conversion DLL does not recognize the target file system.
+ //
+ message->Set( MSG_CONV_INVALID_FILESYSTEM );
+ message->Display( "%W", &FileSystemName );
+ break;
+
+ case CONVERT_STATUS_CONVERSION_NOT_AVAILABLE:
+ //
+ // The target file system is valid, but the conversion is not
+ // available.
+ //
+ message->Set( MSG_CONV_CONVERSION_NOT_AVAILABLE );
+ message->Display( "%W", &FileSystemName );
+ break;
+
+ case CONVERT_STATUS_CANNOT_LOCK_DRIVE:
+
+ message->Set( MSG_CONV_CONVERSION_FAILED );
+ message->Display( "%W%W", &StrippedDriveName, &FileSystemName );
+ break;
+
+ case CONVERT_STATUS_ERROR:
+ //
+ // The conversion failed.
+ //
+ message->Set( MSG_CONV_CONVERSION_FAILED );
+ message->Display( "%W%W", &StrippedDriveName, &FileSystemName );
+ break;
+
+ default:
+ //
+ // Invalid status code
+ //
+ message->Set( MSG_CONV_CONVERSION_FAILED );
+ message->Display( "%W%W", &StrippedDriveName, &FileSystemName );
+ break;
+ }
+
+ }
+
+ SaveMessageLog( message, &DriveName );
+ DeRegister( argc, argv );
+
+#if INCLUDE_OFS==1
+ CleanupExceptionSystem();
+#endif // INCLUDE_OFS==1
+
+ return ( Converted ? 0 : 1 );
+}
+
+
+
+
+BOOLEAN
+DeRegister(
+ int argc,
+ char** argv
+ )
+/*++
+
+Routine Description:
+
+ This function removes the registry entry which triggered
+ autoconvert.
+
+Arguments:
+
+ argc -- Supplies the number of arguments given to autoconv
+ argv -- supplies the arguments given to autoconv
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ DSTRING CommandLineString1,
+ CommandLineString2,
+ CurrentArgString,
+ OneSpace;
+
+ int i;
+
+ // Reconstruct the command line and remove it from
+ // the registry. First, reconstruct the primary
+ // string, which is "autoconv arg1 arg2...".
+ //
+ if( !CommandLineString1.Initialize( L"autoconv" ) ||
+ !OneSpace.Initialize( L" " ) ) {
+
+ return FALSE;
+ }
+
+ for( i = 1; i < argc; i++ ) {
+
+ if( !CurrentArgString.Initialize( argv[i] ) ||
+ !CommandLineString1.Strcat( &OneSpace ) ||
+ !CommandLineString1.Strcat( &CurrentArgString ) ) {
+
+ return FALSE;
+ }
+ }
+
+ // Now construct the secondary string, which is
+ // "autocheck arg0 arg1 arg2..."
+ //
+ if( !CommandLineString2.Initialize( "autocheck " ) ||
+ !CommandLineString2.Strcat( &CommandLineString1 ) ) {
+
+ return FALSE;
+ }
+
+ return( AUTOREG::DeleteEntry( &CommandLineString1 ) &&
+ AUTOREG::DeleteEntry( &CommandLineString2 ) );
+
+}
+
+
+BOOLEAN
+SaveMessageLog(
+ IN OUT PMESSAGE Message,
+ IN PCWSTRING DriveName
+ )
+/*++
+
+Routine Description:
+
+ This function writes the logged messages from the supplied
+ message object to the file "BOOTEX.LOG" in the root of the
+ specified drive.
+
+Arguments:
+
+ Message -- Supplies the message object.
+ DriveName -- Supplies the name of the drive.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ DSTRING QualifiedName;
+ FSTRING BootExString;
+ HMEM Mem;
+ ULONG Length;
+
+ if( !Message->IsLoggingEnabled() ) {
+
+ return TRUE;
+ }
+
+ return( QualifiedName.Initialize( DriveName ) &&
+ BootExString.Initialize( L"\\BOOTEX.LOG" ) &&
+ QualifiedName.Strcat( &BootExString ) &&
+ Mem.Initialize() &&
+ Message->QueryPackedLog( &Mem, &Length ) &&
+ IFS_SYSTEM::WriteToFile( &QualifiedName,
+ Mem.GetBuf(),
+ Length,
+ TRUE ) );
+}
+
+BOOLEAN
+FileDelete(
+ IN PCWSTRING DriveName,
+ IN PCWSTRING FileName
+ )
+/*++
+
+Routine Description:
+
+ This function deletes a file. It is used to clean up the
+ name translation table.
+
+Arguments:
+
+ DriveName -- Supplies the drive on which the file resides.
+ FileName -- Supplies the file name. Note that the file
+ should be in the root directory.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ DSTRING QualifiedName;
+ FSTRING Backslash;
+ IO_STATUS_BLOCK IoStatusBlock;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING UnicodeString;
+ FILE_DISPOSITION_INFORMATION DispositionInfo;
+ HANDLE FileHandle;
+ NTSTATUS Status;
+
+ if( !Backslash.Initialize( L"\\" ) ||
+ !QualifiedName.Initialize( DriveName ) ||
+ !QualifiedName.Strcat( &Backslash ) ||
+ !QualifiedName.Strcat( FileName ) ) {
+
+ return FALSE;
+ }
+
+ UnicodeString.Buffer = (PWSTR)QualifiedName.GetWSTR();
+ UnicodeString.Length = (USHORT)( QualifiedName.QueryChCount() * sizeof( WCHAR ) );
+ UnicodeString.MaximumLength = UnicodeString.Length;
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ &UnicodeString,
+ OBJ_CASE_INSENSITIVE,
+ 0,
+ 0 );
+
+ Status = NtOpenFile( &FileHandle,
+ FILE_GENERIC_READ | FILE_GENERIC_WRITE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_DELETE,
+ FILE_NON_DIRECTORY_FILE );
+
+ if( NT_SUCCESS( Status ) ) {
+
+ DispositionInfo.DeleteFile = TRUE;
+
+ Status = NtSetInformationFile( FileHandle,
+ &IoStatusBlock,
+ &DispositionInfo,
+ sizeof( DispositionInfo ),
+ FileDispositionInformation );
+ }
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ return FALSE;
+ }
+
+ NtClose( FileHandle );
+ return TRUE;
+}
diff --git a/private/utils/autoconv/autoconv.rc b/private/utils/autoconv/autoconv.rc
new file mode 100644
index 000000000..1e7a7611d
--- /dev/null
+++ b/private/utils/autoconv/autoconv.rc
@@ -0,0 +1,13 @@
+
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Auto File System Conversion Utility"
+#define VER_INTERNALNAME_STR "autoconv\0"
+#define VER_ORIGINALFILENAME_STR "AUTOCONV.EXE"
+
+#include "common.ver"
+
+1 11 "..\\ntlib\\src\\msg00001.bin"
diff --git a/private/utils/autoconv/daytona/makefile b/private/utils/autoconv/daytona/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/autoconv/daytona/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/autoconv/daytona/sources b/private/utils/autoconv/daytona/sources
new file mode 100644
index 000000000..9783ac5ef
--- /dev/null
+++ b/private/utils/autoconv/daytona/sources
@@ -0,0 +1,53 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=utils
+MINORCOMP=autoconv
+
+TARGETNAME=autoconv
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=\
+ ..\autoconv.cxx \
+ ..\autoconv.rc
+
+INCLUDES=\
+ ..\..\ulib\inc;\
+ ..\..\ifsutil\inc;\
+ ..\..\cufat\inc;\
+ ..\..\cuhpfs;\
+ ..\..\ufat\inc; \
+ ..\..\uhpfs\inc;\
+ ..\..\untfs\inc;\
+ $(BASEDIR)\public\sdk\inc
+
+C_DEFINES=-DCONDITION_HANDLING=1 -D_AUTOCHECK_ -DUNICODE=1
+CXXFLAGS=
+UMLIBS=..\..\ntlib\src\obj\*\ntlib.lib
+
+USE_NTDLL=1
+UMTYPE=nt
diff --git a/private/utils/autoconv/dirs b/private/utils/autoconv/dirs
new file mode 100644
index 000000000..6597fef02
--- /dev/null
+++ b/private/utils/autoconv/dirs
@@ -0,0 +1,16 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+!ENDIF
+
+DIRS=daytona
diff --git a/private/utils/bldtest/utiltest.cmd b/private/utils/bldtest/utiltest.cmd
new file mode 100644
index 000000000..d81128bec
--- /dev/null
+++ b/private/utils/bldtest/utiltest.cmd
@@ -0,0 +1,42 @@
+ @echo off
+ echo.
+ echo. Small DOS5 Utility test V1.0
+ echo. Copyright (C) 1991 Microsoft Corporation
+ echo.
+
+ if "%1"=="" goto usage
+ if "%1"=="-?" goto usage
+
+ copy utiltest.out %1:\utiltest.%1 > NUL
+
+ echo. Test is running...
+ echo.
+
+ call utltest1 %1 > %1:\utiltest.new
+
+ echo.
+ echo. The test is complete. If everything went ok, then
+ echo. the files utiltest.old and utiltest.new should be
+ echo. identical:
+ echo.
+ trans "C\:" "%1\:" %1:\utiltest.%1 > NUL
+ trans "%1\:" "%1\:" %1:\utiltest.new > NUL
+ echo on
+ diff %1:\utiltest.%1 %1:\utiltest.new
+ @echo off
+ echo. -------------------- End -------------------------
+ echo.
+ goto end
+
+:usage
+
+ echo.
+ echo. Runs the small DOS5 utility test scenario.
+ echo.
+ echo. Usage: utiltest DriveLetter
+ echo.
+ echo. Note that DriveLetter must be UPPERCASE!
+ echo.
+ goto end
+
+:end
diff --git a/private/utils/bldtest/utiltest.out b/private/utils/bldtest/utiltest.out
new file mode 100644
index 000000000..9bb5e56a4
--- /dev/null
+++ b/private/utils/bldtest/utiltest.out
@@ -0,0 +1,766 @@
+
+ DOS5 utility test V1.0
+ Copyright (C) 1991 Microsoft Corporation
+
+
+ Preparing test directory...
+
+
+[C:\_UTLTEST]cd SRC
+
+[C:\_UTLTEST\SRC]attrib FILE1
+A C:\_UTLTEST\SRC\FILE1
+
+[C:\_UTLTEST\SRC]attrib +r FILE1
+
+[C:\_UTLTEST\SRC]attrib FILE1
+A R C:\_UTLTEST\SRC\FILE1
+
+[C:\_UTLTEST\SRC]attrib -r FILE1
+
+[C:\_UTLTEST\SRC]attrib /s
+A C:\_UTLTEST\SRC\DELETED\INDEX
+A C:\_UTLTEST\SRC\DELETED\DELETED.001
+A C:\_UTLTEST\SRC\DIR0\DIR1\FILE1
+A C:\_UTLTEST\SRC\DIR0\DIR1\FILE2
+A C:\_UTLTEST\SRC\DIR0\DIR1\FILE3
+A C:\_UTLTEST\SRC\DIR0\FILE1
+A C:\_UTLTEST\SRC\DIR0\FILE2
+A C:\_UTLTEST\SRC\DIR0\FILE3
+A C:\_UTLTEST\SRC\DIR0\FILE4
+A C:\_UTLTEST\SRC\DIR0\FILE5
+A C:\_UTLTEST\SRC\DIR0\FILE6
+A C:\_UTLTEST\SRC\DIR0\FILE7
+A C:\_UTLTEST\SRC\DIR2\DIR1\FILE1
+A C:\_UTLTEST\SRC\DIR2\DIR1\FILE2
+A C:\_UTLTEST\SRC\DIR2\DIR1\FILE3
+A C:\_UTLTEST\SRC\DIR2\FILE1
+A C:\_UTLTEST\SRC\DIR2\FILE2
+A C:\_UTLTEST\SRC\DIR2\FILE3
+A C:\_UTLTEST\SRC\DIR2\FILE4
+A C:\_UTLTEST\SRC\DIR2\FILE5
+A C:\_UTLTEST\SRC\DIR2\FILE6
+A C:\_UTLTEST\SRC\DIR2\FILE7
+A C:\_UTLTEST\SRC\DIR4\DIR1\FILE1
+A C:\_UTLTEST\SRC\DIR4\DIR1\FILE2
+A C:\_UTLTEST\SRC\DIR4\DIR1\FILE3
+A C:\_UTLTEST\SRC\DIR4\FILE1
+A C:\_UTLTEST\SRC\DIR4\FILE2
+A C:\_UTLTEST\SRC\DIR4\FILE3
+A C:\_UTLTEST\SRC\DIR4\FILE4
+A C:\_UTLTEST\SRC\DIR4\FILE5
+A C:\_UTLTEST\SRC\DIR4\FILE6
+A C:\_UTLTEST\SRC\DIR4\FILE7
+A C:\_UTLTEST\SRC\DIR6\DIR1\FILE1
+A C:\_UTLTEST\SRC\DIR6\DIR1\FILE2
+A C:\_UTLTEST\SRC\DIR6\DIR1\FILE3
+A C:\_UTLTEST\SRC\DIR6\FILE1
+A C:\_UTLTEST\SRC\DIR6\FILE2
+A C:\_UTLTEST\SRC\DIR6\FILE3
+A C:\_UTLTEST\SRC\DIR6\FILE4
+A C:\_UTLTEST\SRC\DIR6\FILE5
+A C:\_UTLTEST\SRC\DIR6\FILE6
+A C:\_UTLTEST\SRC\DIR6\FILE7
+A C:\_UTLTEST\SRC\FILE1
+A C:\_UTLTEST\SRC\FILE2
+A C:\_UTLTEST\SRC\FILE3
+A C:\_UTLTEST\SRC\FILE4
+A C:\_UTLTEST\SRC\FILE5
+A C:\_UTLTEST\SRC\FILE6
+A C:\_UTLTEST\SRC\FILE7
+
+[C:\_UTLTEST\SRC]comp FILE1 FILE2 /a /n=20 0<\_UTLTEST\no.txt
+Comparing FILE1 and FILE2...
+Compare error at LINE 1
+file1 =
+file2 =
+Compare error at LINE 1
+file1 =
+file2 =
+Compare error at LINE 1
+file1 =
+file2 =
+Compare error at LINE 1
+file1 =
+file2 =
+Compare error at LINE 1
+file1 =
+file2 =
+Compare error at LINE 1
+file1 =
+file2 =
+Compare error at LINE 1
+file1 =
+file2 =
+Compare error at LINE 1
+file1 =
+file2 =
+Compare error at LINE 1
+file1 =
+file2 =
+Compare error at LINE 1
+file1 =
+file2 =
+10 Mismatches - ending compare
+
+Compare more files (Y/N) ? Compare more files (Y/N) ? Compare more files (Y/N) ? Compare more files (Y/N) ? Name of first file to compare: Unexpected End of File
+
+
+[C:\_UTLTEST\SRC]comp FILE1 FILE1 /d 0<\_UTLTEST\no.txt
+Comparing FILE1 and FILE1...
+Files compare OK
+
+Compare more files (Y/N) ? Compare more files (Y/N) ? Compare more files (Y/N) ? Compare more files (Y/N) ? Name of first file to compare: Unexpected End of File
+
+
+[C:\_UTLTEST\SRC]comp FILE* FILE1 /c /n=1 0<\_UTLTEST\no.txt
+Comparing FILE1 and FILE1...
+Files compare OK
+
+Comparing FILE2 and FILE1...
+Compare error at LINE 1
+file1 = 20
+file2 = 9
+Compare error at LINE 1
+file1 = 20
+file2 = 9
+Compare error at LINE 1
+file1 = 20
+file2 = 9
+Compare error at LINE 1
+file1 = 20
+file2 = 9
+Compare error at LINE 1
+file1 = 20
+file2 = 9
+Compare error at LINE 1
+file1 = 20
+file2 = 9
+Compare error at LINE 1
+file1 = 20
+file2 = 9
+Compare error at LINE 1
+file1 = 20
+file2 = 9
+Compare error at LINE 1
+file1 = 20
+file2 = 9
+Compare error at LINE 1
+file1 = 20
+file2 = 9
+10 Mismatches - ending compare
+
+Comparing FILE3 and FILE1...
+Compare error at LINE 1
+file1 = 48
+file2 = 9
+Compare error at LINE 1
+file1 = 65
+file2 = 9
+Compare error at LINE 1
+file1 = 6C
+file2 = 9
+Compare error at LINE 1
+file1 = 6C
+file2 = 9
+Compare error at LINE 1
+file1 = 6F
+file2 = 9
+Compare error at LINE 1
+file1 = 20
+file2 = 9
+Compare error at LINE 1
+file1 = 57
+file2 = 9
+Compare error at LINE 1
+file1 = 6F
+file2 = 9
+Compare error at LINE 1
+file1 = 72
+file2 = 9
+Compare error at LINE 1
+file1 = 6C
+file2 = 9
+10 Mismatches - ending compare
+
+Comparing FILE4 and FILE1...
+Compare error at LINE 1
+file1 = 48
+file2 = 9
+Compare error at LINE 1
+file1 = 65
+file2 = 9
+Compare error at LINE 1
+file1 = 6C
+file2 = 9
+Compare error at LINE 1
+file1 = 6C
+file2 = 9
+Compare error at LINE 1
+file1 = 6F
+file2 = 9
+Compare error at LINE 1
+file1 = 20
+file2 = 9
+Compare error at LINE 1
+file1 = 57
+file2 = 9
+Compare error at LINE 1
+file1 = 6F
+file2 = 9
+Compare error at LINE 1
+file1 = 72
+file2 = 9
+Compare error at LINE 1
+file1 = 6C
+file2 = 9
+10 Mismatches - ending compare
+
+Comparing FILE5 and FILE1...
+Compare error at LINE 1
+file1 = 48
+file2 = 9
+Compare error at LINE 1
+file1 = 65
+file2 = 9
+Compare error at LINE 1
+file1 = 6C
+file2 = 9
+Compare error at LINE 1
+file1 = 6C
+file2 = 9
+Compare error at LINE 1
+file1 = 6F
+file2 = 9
+Compare error at LINE 1
+file1 = 20
+file2 = 9
+Compare error at LINE 1
+file1 = 57
+file2 = 9
+Compare error at LINE 1
+file1 = 6F
+file2 = 9
+Compare error at LINE 1
+file1 = 72
+file2 = 9
+Compare error at LINE 1
+file1 = 6C
+file2 = 9
+10 Mismatches - ending compare
+
+Comparing FILE6 and FILE1...
+Compare error at LINE 1
+file1 = 48
+file2 = 9
+Compare error at LINE 1
+file1 = 65
+file2 = 9
+Compare error at LINE 1
+file1 = 6C
+file2 = 9
+Compare error at LINE 1
+file1 = 6C
+file2 = 9
+Compare error at LINE 1
+file1 = 6F
+file2 = 9
+Compare error at LINE 1
+file1 = 20
+file2 = 9
+Compare error at LINE 1
+file1 = 57
+file2 = 9
+Compare error at LINE 1
+file1 = 6F
+file2 = 9
+Compare error at LINE 1
+file1 = 72
+file2 = 9
+Compare error at LINE 1
+file1 = 6C
+file2 = 9
+10 Mismatches - ending compare
+
+Comparing FILE7 and FILE1...
+Compare error at LINE 1
+file1 = 48
+file2 = 9
+Compare error at LINE 1
+file1 = 65
+file2 = 9
+Compare error at LINE 1
+file1 = 6C
+file2 = 9
+Compare error at LINE 1
+file1 = 6C
+file2 = 9
+Compare error at LINE 1
+file1 = 6F
+file2 = 9
+Compare error at LINE 1
+file1 = 20
+file2 = 9
+Compare error at LINE 1
+file1 = 57
+file2 = 9
+Compare error at LINE 1
+file1 = 6F
+file2 = 9
+Compare error at LINE 1
+file1 = 72
+file2 = 9
+Compare error at LINE 1
+file1 = 6C
+file2 = 9
+10 Mismatches - ending compare
+
+Compare more files (Y/N) ? Compare more files (Y/N) ? Compare more files (Y/N) ? Compare more files (Y/N) ? Name of first file to compare: Unexpected End of File
+
+
+[C:\_UTLTEST\SRC]fc /a /c /l /n /t /w FILE1 FILE2
+Comparing files FILE1 and FILE2
+
+***** C:\_UTLTEST\SRC\FILE1
+ 11 : //
+ 13 : // Names into NT Path Names.
+***** C:\_UTLTEST\SRC\FILE2
+ 11 : //
+ 13 : // Names into NT Path Names.
+*****
+
+
+***** C:\_UTLTEST\SRC\FILE1
+ 15 :
+ 29 :
+***** C:\_UTLTEST\SRC\FILE2
+ 15 :
+ 29 :
+*****
+
+
+***** C:\_UTLTEST\SRC\FILE1
+ 39 : //
+ 41 : // Names into NT Path Names.
+***** C:\_UTLTEST\SRC\FILE2
+ 39 : //
+ 41 : // Names into NT Path Names.
+*****
+
+
+***** C:\_UTLTEST\SRC\FILE1
+ 43 :
+ 57 :
+***** C:\_UTLTEST\SRC\FILE2
+ 43 :
+ 57 :
+*****
+
+
+***** C:\_UTLTEST\SRC\FILE1
+ 67 : //
+ 69 : // Names into NT Path Names.
+***** C:\_UTLTEST\SRC\FILE2
+ 67 : //
+ 69 : // Names into NT Path Names.
+*****
+
+
+***** C:\_UTLTEST\SRC\FILE1
+ 71 :
+ 85 :
+***** C:\_UTLTEST\SRC\FILE2
+ 71 :
+ 85 :
+*****
+
+
+***** C:\_UTLTEST\SRC\FILE1
+ 95 : //
+ 97 : // Names into NT Path Names.
+***** C:\_UTLTEST\SRC\FILE2
+ 95 : //
+ 97 : // Names into NT Path Names.
+*****
+
+
+***** C:\_UTLTEST\SRC\FILE1
+ 99 :
+ 113 :
+***** C:\_UTLTEST\SRC\FILE2
+ 99 :
+ 113 :
+*****
+
+
+***** C:\_UTLTEST\SRC\FILE1
+ 123 : //
+ 125 : // Names into NT Path Names.
+***** C:\_UTLTEST\SRC\FILE2
+ 123 : //
+ 125 : // Names into NT Path Names.
+*****
+
+
+***** C:\_UTLTEST\SRC\FILE1
+ 127 :
+ 140 : T: = \Device\Tape0
+***** C:\_UTLTEST\SRC\FILE2
+ 127 :
+ 140 : T: = \Baboon\Tape0
+*****
+
+
+
+[C:\_UTLTEST\SRC]find "Device" FILE1
+
+---------- FILE1
+ // The DosDevices contains global definitions for converting DOS style Path
+ [DosDevices]
+ LPT1 = \Device\Parallel0
+ COM1 = \Device\Serial0
+ COM2 = \Device\Serial1
+ PRN = \DosDevices\LPT1
+ AUX = \DosDevices\COM1
+ NUL = \Device\Null
+ PIPE = \Device\NamedPipe
+ MAILSLOT = \Device\MailSlot
+ UNC = \Device\LanmanRedirector
+ A: = \Device\Floppy0
+ B: = \Device\Floppy1
+ T: = \Device\Tape0
+ // The DosDevices contains global definitions for converting DOS style Path
+ [DosDevices]
+ LPT1 = \Device\Parallel0
+ COM1 = \Device\Serial0
+ COM2 = \Device\Serial1
+ PRN = \DosDevices\LPT1
+ AUX = \DosDevices\COM1
+ NUL = \Device\Null
+ PIPE = \Device\NamedPipe
+ MAILSLOT = \Device\MailSlot
+ UNC = \Device\LanmanRedirector
+ A: = \Device\Floppy0
+ B: = \Device\Floppy1
+ T: = \Device\Tape0
+ // The DosDevices contains global definitions for converting DOS style Path
+ [DosDevices]
+ LPT1 = \Device\Parallel0
+ COM1 = \Device\Serial0
+ COM2 = \Device\Serial1
+ PRN = \DosDevices\LPT1
+ AUX = \DosDevices\COM1
+ NUL = \Device\Null
+ PIPE = \Device\NamedPipe
+ MAILSLOT = \Device\MailSlot
+ UNC = \Device\LanmanRedirector
+ A: = \Device\Floppy0
+ B: = \Device\Floppy1
+ T: = \Device\Tape0
+ // The DosDevices contains global definitions for converting DOS style Path
+ [DosDevices]
+ LPT1 = \Device\Parallel0
+ COM1 = \Device\Serial0
+ COM2 = \Device\Serial1
+ PRN = \DosDevices\LPT1
+ AUX = \DosDevices\COM1
+ NUL = \Device\Null
+ PIPE = \Device\NamedPipe
+ MAILSLOT = \Device\MailSlot
+ UNC = \Device\LanmanRedirector
+ A: = \Device\Floppy0
+ B: = \Device\Floppy1
+ T: = \Device\Tape0
+ // The DosDevices contains global definitions for converting DOS style Path
+ [DosDevices]
+ LPT1 = \Device\Parallel0
+ COM1 = \Device\Serial0
+ COM2 = \Device\Serial1
+ PRN = \DosDevices\LPT1
+ AUX = \DosDevices\COM1
+ NUL = \Device\Null
+ PIPE = \Device\NamedPipe
+ MAILSLOT = \Device\MailSlot
+ UNC = \Device\LanmanRedirector
+ A: = \Device\Floppy0
+ B: = \Device\Floppy1
+ T: = \Device\Tape0
+
+[C:\_UTLTEST\SRC]find /c "device" FILE1
+
+---------- FILE1: 0
+
+[C:\_UTLTEST\SRC]sort 0<FILE1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ A: = \Device\Floppy0
+ A: = \Device\Floppy0
+ A: = \Device\Floppy0
+ A: = \Device\Floppy0
+ A: = \Device\Floppy0
+ AUX = \DosDevices\COM1
+ AUX = \DosDevices\COM1
+ AUX = \DosDevices\COM1
+ AUX = \DosDevices\COM1
+ AUX = \DosDevices\COM1
+ B: = \Device\Floppy1
+ B: = \Device\Floppy1
+ B: = \Device\Floppy1
+ B: = \Device\Floppy1
+ B: = \Device\Floppy1
+ COM1 = \Device\Serial0
+ COM1 = \Device\Serial0
+ COM1 = \Device\Serial0
+ COM1 = \Device\Serial0
+ COM1 = \Device\Serial0
+ COM2 = \Device\Serial1
+ COM2 = \Device\Serial1
+ COM2 = \Device\Serial1
+ COM2 = \Device\Serial1
+ COM2 = \Device\Serial1
+ LPT1 = \Device\Parallel0
+ LPT1 = \Device\Parallel0
+ LPT1 = \Device\Parallel0
+ LPT1 = \Device\Parallel0
+ LPT1 = \Device\Parallel0
+ MAILSLOT = \Device\MailSlot
+ MAILSLOT = \Device\MailSlot
+ MAILSLOT = \Device\MailSlot
+ MAILSLOT = \Device\MailSlot
+ MAILSLOT = \Device\MailSlot
+ NUL = \Device\Null
+ NUL = \Device\Null
+ NUL = \Device\Null
+ NUL = \Device\Null
+ NUL = \Device\Null
+ PIPE = \Device\NamedPipe
+ PIPE = \Device\NamedPipe
+ PIPE = \Device\NamedPipe
+ PIPE = \Device\NamedPipe
+ PIPE = \Device\NamedPipe
+ PRN = \DosDevices\LPT1
+ PRN = \DosDevices\LPT1
+ PRN = \DosDevices\LPT1
+ PRN = \DosDevices\LPT1
+ PRN = \DosDevices\LPT1
+ T: = \Device\Tape0
+ T: = \Device\Tape0
+ T: = \Device\Tape0
+ T: = \Device\Tape0
+ T: = \Device\Tape0
+ UNC = \Device\LanmanRedirector
+ UNC = \Device\LanmanRedirector
+ UNC = \Device\LanmanRedirector
+ UNC = \Device\LanmanRedirector
+ UNC = \Device\LanmanRedirector
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ // Names into NT Path Names.
+ // Names into NT Path Names.
+ // Names into NT Path Names.
+ // Names into NT Path Names.
+ // Names into NT Path Names.
+ // The DosDevices contains global definitions for converting DOS style Path
+ // The DosDevices contains global definitions for converting DOS style Path
+ // The DosDevices contains global definitions for converting DOS style Path
+ // The DosDevices contains global definitions for converting DOS style Path
+ // The DosDevices contains global definitions for converting DOS style Path
+ [DosDevices]
+ [DosDevices]
+ [DosDevices]
+ [DosDevices]
+ [DosDevices]
+ AutoCheck = \SystemDisk\Nt\Bin\AutoChk.exe *
+ AutoCheck = \SystemDisk\Nt\Bin\AutoChk.exe *
+ AutoCheck = \SystemDisk\Nt\Bin\AutoChk.exe *
+ AutoCheck = \SystemDisk\Nt\Bin\AutoChk.exe *
+ AutoCheck = \SystemDisk\Nt\Bin\AutoChk.exe *
+ First make sure we check the validity of all hard disks in the system.
+ First make sure we check the validity of all hard disks in the system.
+ First make sure we check the validity of all hard disks in the system.
+ First make sure we check the validity of all hard disks in the system.
+ First make sure we check the validity of all hard disks in the system.
+ kernel and executive.
+ kernel and executive.
+ kernel and executive.
+ kernel and executive.
+ kernel and executive.
+ PagingFile = \SystemDisk\Nt\pagefile.sys 10
+ PagingFile = \SystemDisk\Nt\pagefile.sys 10
+ PagingFile = \SystemDisk\Nt\pagefile.sys 10
+ PagingFile = \SystemDisk\Nt\pagefile.sys 10
+ PagingFile = \SystemDisk\Nt\pagefile.sys 10
+ The Nt section contains global configuration information for the NT
+ The Nt section contains global configuration information for the NT
+ The Nt section contains global configuration information for the NT
+ The Nt section contains global configuration information for the NT
+ The Nt section contains global configuration information for the NT
+
+[C:\_UTLTEST\SRC]tree
+Directory PATH listing for volume RAMONSA_486
+
+Volume Serial Number is 0000-0000
+
+C:.
+ÃÄÄÄDIR0
+³ ÃÄÄÄDIR0
+³ ÃÄÄÄDIR1
+³ ÀÄÄÄDIR2
+ÃÄÄÄDIR1
+ÃÄÄÄDIR2
+³ ÃÄÄÄDIR0
+³ ÃÄÄÄDIR1
+³ ÀÄÄÄDIR2
+ÃÄÄÄDIR4
+³ ÃÄÄÄDIR0
+³ ÃÄÄÄDIR1
+³ ÀÄÄÄDIR2
+ÃÄÄÄDIR6
+³ ÃÄÄÄDIR0
+³ ÃÄÄÄDIR1
+³ ÀÄÄÄDIR2
+ÃÄÄÄDIR3
+ÃÄÄÄDIR5
+ÀÄÄÄDIR7
+
+[C:\_UTLTEST\SRC]cd \_UTLTEST
+
+[C:\_UTLTEST]md Dst
+
+[C:\_UTLTEST]xcopy SRC DST /s
+SRC\FILE1
+SRC\FILE2
+SRC\FILE3
+SRC\FILE4
+SRC\FILE5
+SRC\FILE6
+SRC\FILE7
+SRC\DIR0\FILE1
+SRC\DIR0\FILE2
+SRC\DIR0\FILE3
+SRC\DIR0\FILE4
+SRC\DIR0\FILE5
+SRC\DIR0\FILE6
+SRC\DIR0\FILE7
+SRC\DIR0\DIR1\FILE1
+SRC\DIR0\DIR1\FILE2
+SRC\DIR0\DIR1\FILE3
+SRC\DIR2\FILE1
+SRC\DIR2\FILE2
+SRC\DIR2\FILE3
+SRC\DIR2\FILE4
+SRC\DIR2\FILE5
+SRC\DIR2\FILE6
+SRC\DIR2\FILE7
+SRC\DIR2\DIR1\FILE1
+SRC\DIR2\DIR1\FILE2
+SRC\DIR2\DIR1\FILE3
+SRC\DIR4\FILE1
+SRC\DIR4\FILE2
+SRC\DIR4\FILE3
+SRC\DIR4\FILE4
+SRC\DIR4\FILE5
+SRC\DIR4\FILE6
+SRC\DIR4\FILE7
+SRC\DIR4\DIR1\FILE1
+SRC\DIR4\DIR1\FILE2
+SRC\DIR4\DIR1\FILE3
+SRC\DIR6\FILE1
+SRC\DIR6\FILE2
+SRC\DIR6\FILE3
+SRC\DIR6\FILE4
+SRC\DIR6\FILE5
+SRC\DIR6\FILE6
+SRC\DIR6\FILE7
+SRC\DIR6\DIR1\FILE1
+SRC\DIR6\DIR1\FILE2
+SRC\DIR6\DIR1\FILE3
+47 File(s) copied
+
+[C:\_UTLTEST]xcopy SRC DST /s /e
+SRC\FILE1
+SRC\FILE2
+SRC\FILE3
+SRC\FILE4
+SRC\FILE5
+SRC\FILE6
+SRC\FILE7
+SRC\DIR0\FILE1
+SRC\DIR0\FILE2
+SRC\DIR0\FILE3
+SRC\DIR0\FILE4
+SRC\DIR0\FILE5
+SRC\DIR0\FILE6
+SRC\DIR0\FILE7
+SRC\DIR0\DIR1\FILE1
+SRC\DIR0\DIR1\FILE2
+SRC\DIR0\DIR1\FILE3
+SRC\DIR2\FILE1
+SRC\DIR2\FILE2
+SRC\DIR2\FILE3
+SRC\DIR2\FILE4
+SRC\DIR2\FILE5
+SRC\DIR2\FILE6
+SRC\DIR2\FILE7
+SRC\DIR2\DIR1\FILE1
+SRC\DIR2\DIR1\FILE2
+SRC\DIR2\DIR1\FILE3
+SRC\DIR4\FILE1
+SRC\DIR4\FILE2
+SRC\DIR4\FILE3
+SRC\DIR4\FILE4
+SRC\DIR4\FILE5
+SRC\DIR4\FILE6
+SRC\DIR4\FILE7
+SRC\DIR4\DIR1\FILE1
+SRC\DIR4\DIR1\FILE2
+SRC\DIR4\DIR1\FILE3
+SRC\DIR6\FILE1
+SRC\DIR6\FILE2
+SRC\DIR6\FILE3
+SRC\DIR6\FILE4
+SRC\DIR6\FILE5
+SRC\DIR6\FILE6
+SRC\DIR6\FILE7
+SRC\DIR6\DIR1\FILE1
+SRC\DIR6\DIR1\FILE2
+SRC\DIR6\DIR1\FILE3
+47 File(s) copied
+
+[C:\_UTLTEST]mode 80,50
diff --git a/private/utils/bldtest/utltest1.cmd b/private/utils/bldtest/utltest1.cmd
new file mode 100644
index 000000000..b1294e94f
--- /dev/null
+++ b/private/utils/bldtest/utltest1.cmd
@@ -0,0 +1,138 @@
+ @echo off
+ rem
+ rem DOS5 utility test
+ rem
+
+ set version=1.0
+ set copyright=Copyright (C) 1991 Microsoft Corporation
+ set testdir=\_UTLTEST
+
+ echo.
+ echo. DOS5 utility test V%version%
+ echo. %copyright%
+ echo.
+
+ if "%1"=="-?" goto usage
+
+ cd %1:\
+ %1:
+ delnode /q %testdir%
+ md %testdir%
+ cd %testdir%
+ md SRC
+ cd SRC
+
+ rem
+ rem Prepare all the stuff
+ rem
+
+ echo.
+ echo. Preparing test directory...
+ echo.
+
+ echo. N > %testdir%\No.txt
+ echo. N >> %testdir%\No.txt
+ echo. N >> %testdir%\No.txt
+
+ echo. > FILE1
+ echo. The Nt section contains global configuration information for the NT >> FILE1
+ echo. kernel and executive. >> FILE1
+ echo. >> FILE1
+ echo. >> FILE1
+ echo. First make sure we check the validity of all hard disks in the system. >> FILE1
+ echo. >> FILE1
+ echo. AutoCheck = \SystemDisk\Nt\Bin\AutoChk.exe * >> FILE1
+ echo. PagingFile = \SystemDisk\Nt\pagefile.sys 10 >> FILE1
+ echo. >> FILE1
+ echo. // >> FILE1
+ echo. // The DosDevices contains global definitions for converting DOS style Path >> FILE1
+ echo. // Names into NT Path Names. >> FILE1
+ echo. // >> FILE1
+ echo. >> FILE1
+ echo. [DosDevices] >> FILE1
+ echo. LPT1 = \Device\Parallel0 >> FILE1
+ echo. COM1 = \Device\Serial0 >> FILE1
+ echo. COM2 = \Device\Serial1 >> FILE1
+ echo. PRN = \DosDevices\LPT1 >> FILE1
+ echo. AUX = \DosDevices\COM1 >> FILE1
+ echo. NUL = \Device\Null >> FILE1
+ echo. PIPE = \Device\NamedPipe >> FILE1
+ echo. MAILSLOT = \Device\MailSlot >> FILE1
+ echo. UNC = \Device\LanmanRedirector >> FILE1
+ echo. A: = \Device\Floppy0 >> FILE1
+ echo. B: = \Device\Floppy1 >> FILE1
+ echo. T: = \Device\Tape0 >> FILE1
+ copy FILE1 FILE2 > NUL
+ type FILE2 >> FILE1
+ type FILE2 >> FILE1
+ type FILE2 >> FILE1
+ type FILE2 >> FILE1
+ copy FILE1 FILE2 > NUL
+ trans "Device" "Baboon" FILE2 > NUL
+ echo. Hello World! > FILE3
+ copy FILE3 FILE4 > NUL
+ copy FILE3 FILE5 > NUL
+ copy FILE3 FILE6 > NUL
+ copy FILE3 FILE7 > NUL
+ md DIR0 > NUL
+ md DIR1 > NUL
+ copy FILE* DIR0 > NUL
+ md DIR0\DIR0 > NUL
+ md DIR0\DIR1 > NUL
+ md DIR0\DIR2 > NUL
+ copy FILE3 DIR0\DIR1\FILE1 > NUL
+ copy FILE3 DIR0\DIR1\FILE2 > NUL
+ copy FILE3 DIR0\DIR1\FILE3 > NUL
+ tc DIR0 DIR2 > NUL
+ tc DIR2 DIR4 > NUL
+ tc DIR4 DIR6 > NUL
+ tc DIR1 DIR3 > NUL
+ tc DIR1 DIR5 > NUL
+ tc DIR1 DIR7 > NUL
+
+ cd %testdir%
+
+ rem
+ rem Test the utilitites
+ rem
+
+ @echo on
+
+ cd SRC
+
+ attrib FILE1
+ attrib +r FILE1
+ attrib FILE1
+ attrib -r FILE1
+ attrib /s
+
+ comp FILE1 FILE2 /a /n=20 < %testdir%\no.txt
+ comp FILE1 FILE1 /d < %testdir%\no.txt
+ comp FILE* FILE1 /c /n=1 < %testdir%\no.txt
+
+ fc /a /c /l /n /t /w FILE1 FILE2
+
+ find "Device" FILE1
+ find /c "device" FILE1
+
+ sort < FILE1
+
+ tree
+
+ cd %testdir%
+ md Dst
+ xcopy SRC DST /s
+ xcopy SRC DST /s /e
+
+ mode 80,50
+
+ @echo off
+ @goto end
+
+:usage
+
+ echo. Usage: utiltest
+ echo.
+ goto end
+
+:end
diff --git a/private/utils/chcp/chcp.cxx b/private/utils/chcp/chcp.cxx
new file mode 100644
index 000000000..396bdba2d
--- /dev/null
+++ b/private/utils/chcp/chcp.cxx
@@ -0,0 +1,428 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Chcp
+
+Abstract:
+
+ Chcpo is a DOS5-Compatible codepage utility
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 01-May-1991
+
+Revision History:
+
+--*/
+
+#include "ulib.hxx"
+#include "arg.hxx"
+#include "error.hxx"
+#include "stream.hxx"
+#include "smsg.hxx"
+#include "wstring.hxx"
+#include "rtmsg.h"
+#include "chcp.hxx"
+
+
+
+ERRSTACK *perrstk;
+
+
+
+
+VOID _CRTAPI1
+main (
+ )
+
+/*++
+
+Routine Description:
+
+ Main function of the Chcp utility
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ //
+ // Initialize stuff
+ //
+ DEFINE_CLASS_DESCRIPTOR( CHCP );
+
+ {
+ CHCP Chcp;
+
+ if ( Chcp.Initialize() ) {
+
+ Chcp.Chcp();
+ }
+ }
+}
+
+
+
+DEFINE_CONSTRUCTOR( CHCP, PROGRAM );
+
+
+
+CHCP::~CHCP (
+ )
+
+/*++
+
+Routine Description:
+
+ Destructs a CHCP object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+}
+
+
+
+
+BOOLEAN
+CHCP::Initialize (
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes a CHCP object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if initialized.
+
+Notes:
+
+--*/
+
+{
+ //
+ // Initialize program object
+ //
+ if ( PROGRAM::Initialize( MSG_CHCP_USAGE ) &&
+ _Screen.Initialize( )
+
+ ) {
+
+ _SetCodePage = FALSE;
+ _CodePage = 0;
+
+ return TRUE;
+
+ }
+
+ return FALSE;
+}
+
+
+
+BOOLEAN
+CHCP::Chcp (
+ )
+
+/*++
+
+Routine Description:
+
+ Does the Chcp thing.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE.
+
+Notes:
+
+--*/
+
+{
+ ValidateVersion();
+
+ if ( ParseArguments() ) {
+
+
+ if ( _SetCodePage ) {
+
+ //
+ // Set the code page
+ //
+ if ( !SetCodePage() ) {
+ ExitProgram( EXIT_ERROR );
+ }
+
+ } else {
+
+ //
+ // Display current code page
+ //
+ if ( !DisplayCodePage() ) {
+ ExitProgram( EXIT_ERROR );
+ }
+ }
+
+ ExitProgram( EXIT_NORMAL );
+
+ } else {
+
+ ExitProgram( EXIT_ERROR );
+
+ }
+
+ return TRUE;
+}
+
+
+
+
+BOOLEAN
+CHCP::DisplayCodePage (
+ )
+
+/*++
+
+Routine Description:
+
+ Displays the active code page
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if success, FALSE if syntax error.
+
+Notes:
+
+--*/
+
+{
+
+ DisplayMessage(
+ MSG_CHCP_ACTIVE_CODEPAGE,
+ NORMAL_MESSAGE, "%d",
+ _Screen.QueryCodePage( )
+ );
+
+ return TRUE;
+}
+
+
+BOOLEAN
+CHCP::ParseArguments (
+ )
+
+/*++
+
+Routine Description:
+
+ Parses arguments
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if success, FALSE if syntax error.
+
+Notes:
+
+--*/
+
+{
+
+ ARGUMENT_LEXEMIZER ArgLex;
+ ARRAY LexArray;
+ ARRAY ArgArray;
+
+ STRING_ARGUMENT ProgramNameArgument;
+ LONG_ARGUMENT CodePageArgument;
+ FLAG_ARGUMENT UsageArgument;
+
+
+ if ( !ArgArray.Initialize() ||
+ !LexArray.Initialize() ||
+ !ArgLex.Initialize( &LexArray )
+ ) {
+
+ DisplayMessage( MSG_CHCP_INTERNAL_ERROR, ERROR_MESSAGE );
+ ExitProgram( EXIT_ERROR );
+ }
+
+ if ( !ProgramNameArgument.Initialize( "*" ) ||
+ !UsageArgument.Initialize( "/?" ) ||
+ !CodePageArgument.Initialize( "*" )
+ ) {
+
+ DisplayMessage( MSG_CHCP_INTERNAL_ERROR, ERROR_MESSAGE );
+ ExitProgram( EXIT_ERROR );
+ }
+
+ if ( !ArgArray.Put( &ProgramNameArgument ) ||
+ !ArgArray.Put( &UsageArgument ) ||
+ !ArgArray.Put( &CodePageArgument )
+ ) {
+
+ DisplayMessage( MSG_CHCP_INTERNAL_ERROR, ERROR_MESSAGE );
+ ExitProgram( EXIT_ERROR );
+ }
+
+
+ //
+ // Set up the defaults
+ //
+ ArgLex.PutSwitches( "/" );
+ ArgLex.SetCaseSensitive( FALSE );
+
+
+ if ( !ArgLex.PrepareToParse() ) {
+
+ DisplayMessage( MSG_CHCP_INTERNAL_ERROR, ERROR_MESSAGE );
+ ExitProgram( EXIT_ERROR );
+ }
+
+ if ( !ArgLex.DoParsing( &ArgArray ) ) {
+
+ DisplayMessage( MSG_CHCP_INVALID_PARAMETER, ERROR_MESSAGE, "%W", ArgLex.QueryInvalidArgument() );
+ ExitProgram( EXIT_ERROR );
+
+ }
+
+
+ //
+ // Display Help if requested
+ //
+ if ( UsageArgument.IsValueSet() ) {
+
+ DisplayMessage( MSG_CHCP_USAGE, NORMAL_MESSAGE );
+ ExitProgram( EXIT_NORMAL );
+
+ }
+
+
+ if ( CodePageArgument.IsValueSet() ) {
+
+ _SetCodePage = TRUE;
+ _CodePage = (DWORD)CodePageArgument.QueryLong();
+
+ } else {
+
+ _SetCodePage = FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+CHCP::SetCodePage (
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the active code page
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if success, FALSE if syntax error.
+
+Notes:
+
+--*/
+
+{
+
+#ifdef DBCS
+// MSKK Nov.11.1992 KazuM
+ _Screen.MoveCursorTo(0, 0);
+
+// v-junm - 08/18/93 : Added EraseScreenAndAttribute();
+// _Screen.EraseScreen();
+ _Screen.EraseScreenAndResetAttribute();
+
+#endif
+
+ UINT OldCP = _Screen.QueryCodePage( );
+
+ if ( _Screen.SetCodePage( _CodePage ) ) {
+ if (_Screen.SetOutputCodePage( _CodePage ) ) {
+
+//#ifdef DBCS
+//// MSKK Nov.23.1992 KazuM
+// _Screen.MoveCursorTo(0, 0);
+// _Screen.EraseScreen();
+//#endif
+#ifdef JAPAN // v-junm - 07/22/93
+// Since FormatMessage checks the current TEB's locale, and the Locale for
+// CHCP is initialized when the message class is initialized, the TEB has to
+// be updated after the code page is changed successfully. All other code
+// pages other than JP and US are ignored.
+
+ if ( GetConsoleOutputCP() == 932 )
+ SetThreadLocale(
+ MAKELCID(
+ MAKELANGID( LANG_JAPANESE, SUBLANG_ENGLISH_US ),
+ SORT_DEFAULT
+ )
+ );
+ else
+ SetThreadLocale(
+ MAKELCID(
+ MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ),
+ SORT_DEFAULT
+ )
+ );
+
+#endif // JAPAN
+
+ return DisplayCodePage( );
+ } else {
+ _Screen.SetCodePage( OldCP );
+ }
+ }
+ DisplayMessage( MSG_CHCP_INVALID_CODEPAGE, ERROR_MESSAGE );
+ return FALSE;
+}
+
diff --git a/private/utils/chcp/chcp.hxx b/private/utils/chcp/chcp.hxx
new file mode 100644
index 000000000..5de44e74a
--- /dev/null
+++ b/private/utils/chcp/chcp.hxx
@@ -0,0 +1,90 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Chcp.hxx
+
+Abstract:
+
+ This module contains the definition for the CHCP class, which
+ implements the DOS5-compatible Chcp utility.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 01-May-1990
+
+
+Revision History:
+
+
+--*/
+
+
+#if !defined( _CHCP_ )
+
+#define _CHCP_
+
+//
+// Exit codes
+//
+#define EXIT_NORMAL 0
+#define EXIT_ERROR 1
+
+#include "object.hxx"
+#include "keyboard.hxx"
+#include "program.hxx"
+#include "screen.hxx"
+
+//
+// Forward references
+//
+DECLARE_CLASS( CHCP );
+
+class CHCP : public PROGRAM {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( CHCP );
+
+ NONVIRTUAL
+ ~CHCP (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Chcp (
+ );
+
+ private:
+
+ NONVIRTUAL
+ BOOLEAN
+ DisplayCodePage (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ParseArguments (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetCodePage (
+ );
+
+
+ BOOLEAN _SetCodePage;
+ DWORD _CodePage;
+ SCREEN _Screen;
+
+
+};
+
+#endif // _CHCP_
diff --git a/private/utils/chcp/chcp.rc b/private/utils/chcp/chcp.rc
new file mode 100644
index 000000000..b7adcc332
--- /dev/null
+++ b/private/utils/chcp/chcp.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Change CodePage Utility"
+#define VER_INTERNALNAME_STR "chcp\0"
+#define VER_ORIGINALFILENAME_STR "CHCP.COM"
+
+#include "common.ver"
diff --git a/private/utils/chcp/makefile b/private/utils/chcp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/chcp/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/chcp/sources b/private/utils/chcp/sources
new file mode 100644
index 000000000..31f92a4c4
--- /dev/null
+++ b/private/utils/chcp/sources
@@ -0,0 +1,68 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+BLDCRT=1
+
+MAJORCOMP=utils
+MINORCOMP=chcp
+
+TARGETNAME=chcp
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=chcp.cxx chcp.rc
+
+INCLUDES=..\ulib\inc;\nt\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+CXXFLAGS=+d
+UMLIBS= \
+ ..\ulib\src\obj\*\ulib.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+
+UMTYPE=console
+
+UMAPPL=chcp
+
+UMRES=obj\*\chcp.res
+
+#
+# To build mode.com
+#
+_DOT_COM_FILE=1
diff --git a/private/utils/chcp/t_chcp.c b/private/utils/chcp/t_chcp.c
new file mode 100644
index 000000000..dbb3d13f7
--- /dev/null
+++ b/private/utils/chcp/t_chcp.c
@@ -0,0 +1,32 @@
+#include <stdio.h>
+#include <conio.h>
+
+int cdecl main(int argc, char **argv)
+{
+ int i;
+ int j;
+
+ printf(
+"| |0- |1- |2- |3- |4- |5- |6- |7- |8- |9- |A- |B- |C- |D- |E- |F- |\n");
+ printf(
+"|----+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+\n");
+ for (i = 0; i < 0x10; i++) {
+ printf(
+"| | | | | | | | | | | | | | | | | |\n");
+ printf("| -%.1X |", i);
+ for (j = 0; j < 0x10; j++) {
+ unsigned char ch = (unsigned char)(j * 0x10 + i);
+ if (((7 <= ch) && (ch <= 0xA)) || (ch == 0xD)) {
+ printf(" |");
+ } else {
+ printf(" %.1c |", ch);
+ }
+ }
+ printf("\n");
+ }
+ printf(
+"| | | | | | | | | | | | | | | | | |\n");
+ printf(
+"|____|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|\n");
+ return 0;
+}
diff --git a/private/utils/chkdsk/chkdsk.cxx b/private/utils/chkdsk/chkdsk.cxx
new file mode 100644
index 000000000..8f12ed2be
--- /dev/null
+++ b/private/utils/chkdsk/chkdsk.cxx
@@ -0,0 +1,410 @@
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+
+#include "arg.hxx"
+#include "smsg.hxx"
+#include "rtmsg.h"
+#include "wstring.hxx"
+#include "path.hxx"
+
+#include "system.hxx"
+#include "ifssys.hxx"
+#include "substrng.hxx"
+
+#include "ulibcl.hxx"
+#include "ifsentry.hxx"
+
+#include "keyboard.hxx"
+
+#include "supera.hxx" // for CHKDSK_EXIT_*
+
+int _CRTAPI1
+main(
+ )
+/*++
+
+Routine Description:
+
+ Entry point for chkdsk.exe. This function parses the arguments,
+ determines the appropriate file system (by querying the volume),
+ and invokes the appropriate version of chkdsk.
+
+ The arguments accepted by Chkdsk are:
+
+ /f Fix errors on drive
+ /v Verbose operation
+ drive: drive to check
+ file-name files to check for contiguity
+ (Note that HPFS ignores file-name parameters).
+ /c Check only if dirty bit is set
+
+--*/
+{
+ DSTRING CurrentDirectory;
+ DSTRING FsName;
+ DSTRING LibraryName;
+ DSTRING DosDriveName;
+ DSTRING CurrentDrive;
+ DSTRING NtDriveName;
+ PWSTRING p;
+ HANDLE FsUtilityHandle;
+ DSTRING ChkdskString;
+ DSTRING Colon;
+ CHKDSK_FN Chkdsk = NULL;
+ PWSTRING pwstring;
+ BOOLEAN fix;
+ BOOLEAN resize_logfile;
+ ULONG logfile_size;
+ FSTRING acolon, bcolon;
+ ULONG exit_status;
+
+ ARGUMENT_LEXEMIZER Lexemizer;
+ ARRAY EmptyArray;
+ ARRAY ArgumentArray;
+ FLAG_ARGUMENT ArgumentHelp;
+ FLAG_ARGUMENT ArgumentFix;
+ FLAG_ARGUMENT ArgumentVerbose;
+ FLAG_ARGUMENT ArgumentRecover;
+ FLAG_ARGUMENT ArgumentResize;
+ LONG_ARGUMENT ArgumentResizeLong;
+ STRING_ARGUMENT ArgumentProgramName;
+ PATH_ARGUMENT ArgumentPath;
+
+
+ STREAM_MESSAGE Message;
+ NTSTATUS Status;
+
+
+
+ if( !Message.Initialize( Get_Standard_Output_Stream(),
+ Get_Standard_Input_Stream() ) ) {
+ return CHKDSK_EXIT_COULD_NOT_CHK;
+ }
+
+ // Initialize the colon string in case we need it later:
+
+ if( !Colon.Initialize( ":" ) ) {
+
+ Message.Set( MSG_CHK_NO_MEMORY );
+ Message.Display( "" );
+ return CHKDSK_EXIT_COULD_NOT_CHK;
+ }
+
+
+ // Parse the arguments. First, initialize all the
+ // parsing machinery. Then put the potential arguments
+ // into the argument array,
+
+ if( !ArgumentArray.Initialize( 5, 1 ) ||
+ !EmptyArray.Initialize( 5, 1 ) ||
+ !Lexemizer.Initialize( &EmptyArray ) ||
+ !ArgumentHelp.Initialize( "/?" ) ||
+ !ArgumentFix.Initialize( "/F" ) ||
+ !ArgumentVerbose.Initialize( "/V" ) ||
+ !ArgumentRecover.Initialize( "/R" ) ||
+ !ArgumentResize.Initialize( "/L" ) ||
+ !ArgumentResizeLong.Initialize( "/L:*" ) ||
+ !ArgumentProgramName.Initialize( "*" ) ||
+ !ArgumentPath.Initialize( "*", FALSE ) ) {
+
+ Message.Set( MSG_CHK_NO_MEMORY );
+ Message.Display( "" );
+ return CHKDSK_EXIT_COULD_NOT_CHK;
+ }
+
+ // CHKDSK is not case sensitive.
+
+ Lexemizer.SetCaseSensitive( FALSE );
+
+ if( !ArgumentArray.Put( &ArgumentProgramName ) ||
+ !ArgumentArray.Put( &ArgumentHelp ) ||
+ !ArgumentArray.Put( &ArgumentFix ) ||
+ !ArgumentArray.Put( &ArgumentVerbose ) ||
+ !ArgumentArray.Put( &ArgumentRecover ) ||
+ !ArgumentArray.Put( &ArgumentResize ) ||
+ !ArgumentArray.Put( &ArgumentResizeLong ) ||
+ !ArgumentArray.Put( &ArgumentPath ) ) {
+
+ Message.Set( MSG_CHK_NO_MEMORY );
+ Message.Display( "" );
+ return CHKDSK_EXIT_COULD_NOT_CHK;
+ }
+
+ // Parse. Note that PrepareToParse will, by default, pick
+ // up the command line.
+
+ if( !Lexemizer.PrepareToParse() ) {
+
+ Message.Set( MSG_CHK_NO_MEMORY );
+ Message.Display( "" );
+ return CHKDSK_EXIT_COULD_NOT_CHK;
+ }
+
+
+ // If the parsing failed, display a helpful command line summary.
+
+ if( !Lexemizer.DoParsing( &ArgumentArray ) ) {
+
+ Message.Set(MSG_INVALID_PARAMETER);
+ Message.Display("%W", pwstring = Lexemizer.QueryInvalidArgument());
+ DELETE(pwstring);
+
+ return CHKDSK_EXIT_COULD_NOT_CHK;
+ }
+
+
+ // If the user requested help, give it.
+
+ if( ArgumentHelp.QueryFlag() ) {
+
+ Message.Set( MSG_CHK_USAGE_HEADER );
+ Message.Display( "" );
+ Message.Set( MSG_BLANK_LINE );
+ Message.Display( "" );
+ Message.Set( MSG_CHK_COMMAND_LINE );
+ Message.Display( "" );
+ Message.Set( MSG_BLANK_LINE );
+ Message.Display( "" );
+ Message.Set( MSG_CHK_DRIVE );
+ Message.Display( "" );
+ Message.Set( MSG_CHK_USG_FILENAME );
+ Message.Display( "" );
+ Message.Set( MSG_CHK_F_SWITCH );
+ Message.Display( "" );
+ Message.Set( MSG_CHK_V_SWITCH );
+ Message.Display( "" );
+
+ return CHKDSK_EXIT_COULD_NOT_CHK;
+ }
+
+ if (ArgumentPath.IsValueSet()) {
+ if (!(p = ArgumentPath.GetPath()->QueryDevice())) {
+ Message.Set(MSG_CHK_BAD_DRIVE_PATH_FILENAME);
+ Message.Display( "" );
+ return CHKDSK_EXIT_COULD_NOT_CHK;
+ }
+
+ if (!DosDriveName.Initialize(p) ||
+ !DosDriveName.Strupr()) {
+
+ DELETE(p);
+ return CHKDSK_EXIT_COULD_NOT_CHK;
+ }
+ DELETE(p);
+
+ } else {
+
+ if (!SYSTEM::QueryCurrentDosDriveName(&DosDriveName)) {
+ return CHKDSK_EXIT_COULD_NOT_CHK;
+ }
+ }
+
+ // Make sure that drive is of a correct type.
+
+ switch (SYSTEM::QueryDriveType(&DosDriveName)) {
+
+ case RemoteDrive:
+ Message.Set(MSG_CHK_CANT_NETWORK);
+ Message.Display();
+ return CHKDSK_EXIT_COULD_NOT_CHK;
+
+ case CdRomDrive:
+ Message.Set(MSG_CHK_CANT_CDROM);
+ Message.Display();
+ return CHKDSK_EXIT_COULD_NOT_CHK;
+
+ default:
+ break;
+
+ }
+
+ if (!SYSTEM::QueryCurrentDosDriveName(&CurrentDrive)) {
+ return CHKDSK_EXIT_COULD_NOT_CHK;
+ }
+
+ // /R ==> /F
+
+ fix = ArgumentFix.QueryFlag() || ArgumentRecover.QueryFlag();
+
+ // From here on we want to deal with an NT drive name:
+
+ if (!IFS_SYSTEM::DosDriveNameToNtDriveName(&DosDriveName, &NtDriveName)) {
+ return CHKDSK_EXIT_COULD_NOT_CHK;
+ }
+
+
+ // Determine the type of the file system.
+ // Ask the volume what file system it has. The
+ // IFS utilities for file system xxxx are in Uxxxx.DLL.
+ //
+
+ if (!IFS_SYSTEM::QueryFileSystemName(&NtDriveName,
+ &FsName,
+ &Status )) {
+
+ if( Status == STATUS_ACCESS_DENIED ) {
+
+ Message.Set( MSG_DASD_ACCESS_DENIED );
+ Message.Display( "" );
+
+ } else if( Status != STATUS_SUCCESS ) {
+
+ Message.Set( MSG_CANT_DASD );
+ Message.Display( "" );
+
+ } else {
+
+ Message.Set( MSG_FS_NOT_DETERMINED );
+ Message.Display( "%W", &DosDriveName );
+ }
+
+ return CHKDSK_EXIT_COULD_NOT_CHK;
+ }
+
+ Message.Set( MSG_FILE_SYSTEM_TYPE );
+ Message.Display( "%W", &FsName );
+
+ if( !LibraryName.Initialize( "U" ) ||
+ !LibraryName.Strcat( &FsName ) ||
+ !ChkdskString.Initialize( "Chkdsk" ) ) {
+
+ Message.Set( MSG_CHK_NO_MEMORY );
+ Message.Display( "" );
+ return CHKDSK_EXIT_COULD_NOT_CHK;
+ }
+
+ if (fix && (CurrentDrive == DosDriveName)) {
+
+ Message.Set(MSG_CANT_LOCK_CURRENT_DRIVE);
+ Message.Display();
+
+ acolon.Initialize((PWSTR) L"A:");
+ bcolon.Initialize((PWSTR) L"B:");
+
+ if (!DosDriveName.Stricmp(&acolon) ||
+ !DosDriveName.Stricmp(&bcolon)) {
+
+ return CHKDSK_EXIT_COULD_NOT_CHK;
+ }
+
+ // Fall through so that the lock fails and then the
+ // run autochk on reboot logic kicks in.
+ //
+ }
+
+ // Does the user want to resize the logfile? This is only sensible
+ // for NTFS. If she specified a size of zero, print an error message
+ // because that's a poor choice and will confuse the untfs code,
+ // which assumes that zero means resize to the default size.
+ //
+
+ resize_logfile = ArgumentResize.IsValueSet() || ArgumentResizeLong.IsValueSet();
+
+ if (resize_logfile) {
+
+ DSTRING ntfs_name;
+
+ if (!ntfs_name.Initialize( "ntfs" )) {
+
+ return CHKDSK_EXIT_COULD_NOT_CHK;
+ }
+ if (0 != FsName.Stricmp( &ntfs_name )) {
+
+ Message.Set(MSG_CHK_LOGFILE_NOT_NTFS);
+ Message.Display();
+ return CHKDSK_EXIT_COULD_NOT_CHK;
+ }
+
+ if (ArgumentResizeLong.IsValueSet()) {
+
+ if (ArgumentResizeLong.QueryLong() <= 0) {
+
+ Message.Set(MSG_CHK_WONT_ZERO_LOGFILE);
+ Message.Display();
+ return CHKDSK_EXIT_COULD_NOT_CHK;
+ }
+
+ logfile_size = ArgumentResizeLong.QueryLong() * 1024;
+ } else {
+
+ logfile_size = 0;
+ }
+ }
+
+ if ((Chkdsk =
+ (CHKDSK_FN)SYSTEM::QueryLibraryEntryPoint( &LibraryName,
+ &ChkdskString,
+ &FsUtilityHandle )) !=
+ NULL ) {
+
+ if (fix &&
+ !KEYBOARD::EnableBreakHandling()) {
+ return CHKDSK_EXIT_COULD_NOT_CHK;
+ }
+
+ if (fix) {
+ Chkdsk( &NtDriveName,
+ &Message,
+ fix,
+ ArgumentVerbose.QueryFlag(),
+ FALSE,
+ ArgumentRecover.QueryFlag(),
+ ArgumentPath.IsValueSet() ? ArgumentPath.GetPath() : NULL,
+ FALSE, /* extend */
+ resize_logfile,
+ logfile_size,
+ &exit_status );
+ } else {
+
+//disable C4509 warning about nonstandard ext: SEH + destructor
+#pragma warning(disable:4509)
+
+ __try {
+ Chkdsk( &NtDriveName,
+ &Message,
+ fix,
+ ArgumentVerbose.QueryFlag(),
+ FALSE,
+ ArgumentRecover.QueryFlag(),
+ ArgumentPath.IsValueSet() ? ArgumentPath.GetPath() : NULL,
+ FALSE, /* extend */
+ resize_logfile,
+ logfile_size,
+ &exit_status );
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+
+ // If we get an access violation during read-only mode
+ // CHKDSK then it's because the file system is partying
+ // on the volume while we are.
+
+ Message.Set(MSG_CHK_NTFS_ERRORS_FOUND);
+ Message.Display();
+ exit_status = CHKDSK_EXIT_ERRS_NOT_FIXED;
+ }
+ }
+
+ if (CHKDSK_EXIT_ERRS_FIXED == exit_status && !fix) {
+ exit_status = CHKDSK_EXIT_ERRS_NOT_FIXED;
+ }
+
+ SYSTEM::FreeLibraryHandle( FsUtilityHandle );
+
+ if (fix &&
+ !KEYBOARD::DisableBreakHandling()) {
+
+ return 1;
+ }
+
+ } else {
+
+ Message.Set( MSG_FS_NOT_SUPPORTED );
+ Message.Display( "%s%W", "CHKDSK", &FsName );
+ Message.Set( MSG_BLANK_LINE );
+ Message.Display( "" );
+
+ return CHKDSK_EXIT_COULD_NOT_CHK;
+ }
+
+ return exit_status;
+}
diff --git a/private/utils/chkdsk/chkdsk.rc b/private/utils/chkdsk/chkdsk.rc
new file mode 100644
index 000000000..1e3c19a04
--- /dev/null
+++ b/private/utils/chkdsk/chkdsk.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Check Disk Utility"
+#define VER_INTERNALNAME_STR "chkdsk\0"
+#define VER_ORIGINALFILENAME_STR "CHKDSK.EXE"
+
+#include "common.ver"
diff --git a/private/utils/chkdsk/makefile b/private/utils/chkdsk/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/chkdsk/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/chkdsk/sources b/private/utils/chkdsk/sources
new file mode 100644
index 000000000..ab934694e
--- /dev/null
+++ b/private/utils/chkdsk/sources
@@ -0,0 +1,59 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=utils
+MINORCOMP=chkdsk
+
+TARGETNAME=chkdsk
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=chkdsk.cxx chkdsk.rc
+
+INCLUDES=..\ulib\inc;..\ifsutil\inc;\nt\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+UMLIBS= \
+ ..\ulib\src\obj\*\ulib.lib \
+ ..\ifsutil\src\obj\*\ifsutil.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+
+UMTYPE=console
diff --git a/private/utils/chkntfs/chkntfs.cxx b/private/utils/chkntfs/chkntfs.cxx
new file mode 100644
index 000000000..ee33d60b9
--- /dev/null
+++ b/private/utils/chkntfs/chkntfs.cxx
@@ -0,0 +1,439 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ chkntfs.cxx
+
+
+Abstract:
+
+ This utility allows the users to find the state of the dirty bit
+ on NTFS volumes, to schedule autochk for specific drives, and to
+ mofidy the default autochk action for a drive.
+
+
+ SYNTAX:
+
+ chkntfs drive: [...] -- just display dirty bit state
+ chkntfs /d -- restore default autochk behavior
+ chkntfs /x drive: [...] -- exclude drives from default autochk
+ chkntfs /c drive: [...] -- schedule autochk to run on drives
+
+
+ EXIT:
+
+ 0 -- OK, dirty bit not set on drive or bit not checked
+ 1 -- OK, and dirty bit set on at least one drive
+ 2 -- Error
+
+Author:
+
+ Matthew Bradburn (MattBr) 19-Aug-1996
+
+
+--*/
+
+#include "ulib.hxx"
+#include "arg.hxx"
+#include "array.hxx"
+#include "path.hxx"
+#include "wstring.hxx"
+#include "ifssys.hxx"
+#include "system.hxx"
+#include "arrayit.hxx"
+#include "autoreg.hxx"
+#include "chkntfs.hxx"
+
+
+DEFINE_CONSTRUCTOR(CHKNTFS, PROGRAM);
+
+BOOLEAN
+CHKNTFS::Initialize(
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes an object of class CHKNTFS. Called once when the program
+ starts.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates whether the initialization succeeded.
+
+--*/
+
+{
+ ARGUMENT_LEXEMIZER arg_lex;
+ ARRAY lex_array;
+ ARRAY argument_array;
+ STRING_ARGUMENT program_name_argument;
+
+ FLAG_ARGUMENT flag_restore_default;
+ FLAG_ARGUMENT flag_exclude;
+ FLAG_ARGUMENT flag_schedule_check;
+ FLAG_ARGUMENT flag_invalid;
+ FLAG_ARGUMENT flag_display_help;
+
+
+ PROGRAM::Initialize();
+
+ ExitStatus = 2;
+
+ if (!argument_array.Initialize()) {
+ return FALSE;
+ }
+
+ if (!program_name_argument.Initialize("*") ||
+ !flag_restore_default.Initialize("/D") ||
+ !flag_exclude.Initialize("/X") ||
+ !flag_schedule_check.Initialize("/C") ||
+ !flag_display_help.Initialize("/?") ||
+ !flag_invalid.Initialize("/*") || // close comment */
+ !_drive_arguments.Initialize("*", FALSE, TRUE)) {
+
+ return FALSE;
+ }
+
+ if (!argument_array.Put(&program_name_argument) ||
+ !argument_array.Put(&flag_display_help) ||
+ !argument_array.Put(&flag_restore_default) ||
+ !argument_array.Put(&flag_exclude) ||
+ !argument_array.Put(&flag_schedule_check) ||
+ !argument_array.Put(&flag_invalid) ||
+ !argument_array.Put(&_drive_arguments)) {
+
+ return FALSE;
+ }
+
+ if (!lex_array.Initialize() ||
+ !arg_lex.Initialize(&lex_array)) {
+
+ return FALSE;
+ }
+
+ arg_lex.PutSwitches("/");
+ arg_lex.PutStartQuotes("\"");
+ arg_lex.PutEndQuotes("\"");
+ arg_lex.PutSeparators(" \"\t");
+ arg_lex.SetCaseSensitive(FALSE);
+
+ if (!arg_lex.PrepareToParse()) {
+
+ DisplayMessage(MSG_CHKNTFS_INVALID_FORMAT);
+
+ return FALSE;
+ }
+
+ if (!arg_lex.DoParsing(&argument_array)) {
+
+ if (flag_invalid.QueryFlag()) {
+
+ DisplayMessage(MSG_CHKNTFS_INVALID_SWITCH, NORMAL_MESSAGE,
+ "%W", flag_invalid.GetLexeme());
+
+ } else {
+
+ DisplayMessage(MSG_CHKNTFS_INVALID_FORMAT);
+ }
+
+ return FALSE;
+
+ } else if (_drive_arguments.WildCardExpansionFailed()) {
+
+ DisplayMessage(MSG_CHKNTFS_NO_WILDCARDS);
+ return FALSE;
+ }
+
+ if (flag_invalid.QueryFlag()) {
+
+ DisplayMessage(MSG_CHKNTFS_INVALID_SWITCH);
+ return FALSE;
+ }
+
+ ExitStatus = 0;
+
+ if (flag_display_help.QueryFlag()) {
+
+ DisplayMessage(MSG_CHKNTFS_USAGE);
+ return FALSE;
+ }
+
+ _restore_default = flag_restore_default.QueryFlag();
+ _exclude = flag_exclude.QueryFlag();
+ _schedule_check = flag_schedule_check.QueryFlag();
+
+ if (_restore_default + _exclude + _schedule_check > 1) {
+
+ DisplayMessage(MSG_CHKNTFS_ARGS_CONFLICT);
+ ExitStatus = 2;
+ return FALSE;
+ }
+
+ if (0 == _drive_arguments.QueryPathCount() && !_restore_default) {
+
+ DisplayMessage(MSG_CHKNTFS_REQUIRES_DRIVE);
+ ExitStatus = 2;
+ return FALSE;
+ }
+
+ if (_restore_default && _drive_arguments.QueryPathCount() > 0) {
+
+ DisplayMessage(MSG_CHKNTFS_INVALID_FORMAT);
+ ExitStatus = 2;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+CHKNTFS::CheckNtfs(
+ )
+/*++
+
+Routine Description:
+
+ Look at the arguments specified by the user and do what
+ he wants.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN -- success or failure.
+
+--*/
+{
+ PARRAY drive_array;
+ PARRAY_ITERATOR iterator;
+ PPATH current_drive;
+ PCWSTRING drive_string;
+ DSTRING nt_drive_name;
+ DSTRING fs_name;
+ BOOLEAN is_dirty = 0;
+ DSTRING cmd_line;
+ ULONG old_error_mode;
+ DRIVE_TYPE drive_type;
+
+ nt_drive_name.Initialize();
+
+ if (_restore_default) {
+
+ // Remove previous commands.
+
+ if (!cmd_line.Initialize("autocheck autochk /k:") ||
+ !AUTOREG::DeleteEntry(&cmd_line, TRUE) ||
+ !cmd_line.Initialize("autocheck autochk *") ||
+ !AUTOREG::DeleteEntry(&cmd_line)) {
+
+ return FALSE;
+ }
+ if (!cmd_line.Initialize("autocheck autochk *") ||
+ !AUTOREG::AddEntry(&cmd_line)) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ drive_array = _drive_arguments.GetPathArray();
+ iterator = (PARRAY_ITERATOR)drive_array->QueryIterator();
+
+ //
+ // Run through the arguments here and make sure they're all
+ // valid drive names.
+ //
+
+ while (NULL != (current_drive = (PPATH)iterator->GetNext())) {
+
+ drive_string = current_drive->GetPathString();
+
+ if (!current_drive->IsDrive()) {
+
+ DisplayMessage(MSG_CHKNTFS_BAD_ARG, NORMAL_MESSAGE,
+ "%W", drive_string);
+ return FALSE;
+ }
+
+ old_error_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
+
+ drive_type = SYSTEM::QueryDriveType(drive_string);
+
+ SetErrorMode(old_error_mode);
+
+ switch (drive_type) {
+ case UnknownDrive:
+ DisplayMessage(MSG_CHKNTFS_NONEXISTENT_DRIVE, NORMAL_MESSAGE,
+ "%W", drive_string);
+ return FALSE;
+
+ case RemoteDrive:
+ DisplayMessage(MSG_CHKNTFS_NO_NETWORK, NORMAL_MESSAGE,
+ "%W", drive_string);
+ return FALSE;
+
+ case CdRomDrive:
+ DisplayMessage(MSG_CHKNTFS_NO_CDROM, NORMAL_MESSAGE,
+ "%W", drive_string);
+ return FALSE;
+
+ case RamDiskDrive:
+ DisplayMessage(MSG_CHKNTFS_NO_RAMDISK, NORMAL_MESSAGE,
+ "%W", drive_string);
+ return FALSE;
+
+ default:
+ break;
+ }
+ }
+
+ iterator->Reset();
+
+ if (_exclude) {
+
+ // Remove the previous registry commands, if any.
+
+ if (!cmd_line.Initialize("autocheck autochk *") ||
+ !AUTOREG::DeleteEntry(&cmd_line, TRUE)) {
+ return FALSE;
+ }
+
+ if (!cmd_line.Initialize("autocheck autochk /k:") ||
+ !AUTOREG::DeleteEntry(&cmd_line, TRUE)) {
+ return FALSE;
+ }
+
+ //
+ // Collect a list of drives to be excluded and add them to the
+ // command line
+ //
+
+ while (NULL != (current_drive = (PPATH)iterator->GetNext())) {
+
+ drive_string = current_drive->GetPathString();
+
+ if (!cmd_line.Strcat(drive_string->QueryString(0, 1))) {
+ return FALSE;
+ }
+ }
+
+ DSTRING star;
+
+ if (!star.Initialize(" *") ||
+ !cmd_line.Strcat(&star)) {
+ return FALSE;
+ }
+
+ // Add the new command line.
+
+ return AUTOREG::AddEntry(&cmd_line);
+ }
+
+
+ //
+ // This loop handles the "schedule check" and default actions.
+ //
+
+
+ while (NULL != (current_drive = (PPATH)iterator->GetNext())) {
+
+ drive_string = current_drive->GetPathString();
+
+ if (!IFS_SYSTEM::DosDriveNameToNtDriveName(drive_string,
+ &nt_drive_name)) {
+
+ return FALSE;
+ }
+
+ //
+ // Schedule check: Put a line in the registry like
+ // "autocheck autochck \??\X:" for each command-line argument.
+ //
+
+ if (_schedule_check) {
+
+
+ DSTRING cmd_line;
+
+ if (!cmd_line.Initialize("autocheck autochk /m ") ||
+ !cmd_line.Strcat(&nt_drive_name) ||
+ !AUTOREG::AddEntry(&cmd_line)) {
+
+ return FALSE;
+ }
+
+ ExitStatus = 0;
+
+ continue;
+ }
+
+ //
+ // Default: check to see if the volume is dirty.
+ //
+
+ if (IFS_SYSTEM::QueryFileSystemName(&nt_drive_name, &fs_name, NULL)) {
+
+ DisplayMessage(MSG_FILE_SYSTEM_TYPE, NORMAL_MESSAGE,
+ "%W", &fs_name);
+
+ }
+
+ if (!IFS_SYSTEM::IsVolumeDirty(&nt_drive_name, &is_dirty)) {
+
+ DisplayMessage(MSG_CHKNTFS_CANNOT_CHECK, NORMAL_MESSAGE,
+ "%W", drive_string);
+ return FALSE;
+
+ }
+
+ if (is_dirty) {
+
+ DisplayMessage(MSG_CHKNTFS_DIRTY, NORMAL_MESSAGE,
+ "%W", drive_string);
+
+ ExitStatus = 1;
+
+ } else {
+
+ DisplayMessage(MSG_CHKNTFS_CLEAN, NORMAL_MESSAGE,
+ "%W", drive_string);
+ ExitStatus = ExitStatus > 0 ? ExitStatus : 0;
+ }
+ }
+
+ return TRUE;
+}
+
+VOID _CRTAPI1
+main()
+{
+ DEFINE_CLASS_DESCRIPTOR(CHKNTFS);
+ int r;
+
+ {
+ CHKNTFS ChkNtfs;
+
+ if (!ChkNtfs.Initialize() ||
+ !ChkNtfs.CheckNtfs()) {
+
+ exit(2);
+ }
+
+ r = ChkNtfs.ExitStatus;
+
+ }
+
+ _exit(r);
+}
diff --git a/private/utils/chkntfs/chkntfs.hxx b/private/utils/chkntfs/chkntfs.hxx
new file mode 100644
index 000000000..dbbb8cf6c
--- /dev/null
+++ b/private/utils/chkntfs/chkntfs.hxx
@@ -0,0 +1,73 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ ChkNtfs.hxx
+
+Abstract:
+
+ This module contains the declaration for the CHKNTFS class, which
+ is implements an NTFS volume maintenance utility.
+
+
+Author:
+
+ Matthew Bradburn (mattbr) 19-Aug-1996
+
+Revision History:
+
+--*/
+
+#ifndef _CHKNTFS_HXX_
+#define _CHKNTFS_HXX_
+
+
+#include "object.hxx"
+#include "program.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS(CHKNTFS);
+DECLARE_CLASS(ARGUMENT_LEXEMIZER);
+DECLARE_CLASS(STRING_ARRAY);
+DECLARE_CLASS(ITERATOR);
+
+
+class CHKNTFS : public PROGRAM {
+
+ public:
+
+ DECLARE_CONSTRUCTOR(CHKNTFS);
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CheckNtfs(
+ );
+
+ ULONG ExitStatus; // exit status
+
+ private:
+
+ //
+ // Member data for command-line arguments and options.
+ //
+
+ BOOLEAN _restore_default; // restore default autochk behavior
+ BOOLEAN _exclude; // exclude drives from autochk
+ BOOLEAN _schedule_check; // schedule autochk
+
+ MULTIPLE_PATH_ARGUMENT
+ _drive_arguments;
+
+};
+
+#endif /* _CHKNTFS_HXX */
diff --git a/private/utils/chkntfs/chkntfs.rc b/private/utils/chkntfs/chkntfs.rc
new file mode 100644
index 000000000..1a06f7cad
--- /dev/null
+++ b/private/utils/chkntfs/chkntfs.rc
@@ -0,0 +1,11 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "NTFS Volume Maitenance Utility"
+#define VER_INTERNALNAME_STR "chkntfs\0"
+#define VER_ORIGINALFILENAME_STR "CHKNTFS.EXE"
+
+#include "common.ver"
+
diff --git a/private/utils/chkntfs/makefile b/private/utils/chkntfs/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/chkntfs/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/chkntfs/sources b/private/utils/chkntfs/sources
new file mode 100644
index 000000000..956212493
--- /dev/null
+++ b/private/utils/chkntfs/sources
@@ -0,0 +1,82 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+BLDCRT=1
+
+MAJORCOMP=utils
+MINORCOMP=chkntfs
+
+TARGETNAME=chkntfs
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=chkntfs.cxx \
+ chkntfs.rc
+
+INCLUDES=..\ulib\inc;..\ifsutil\inc
+
+#
+# Debug support.
+#
+# We have 4 levels:
+#
+# 1.- FREE: Non-debug
+# 2.- NTDBG: Debug, no memleak
+# 3.- MEMLEAK: 2 + memleak
+# 4.- STACK_TRACE 3 + stack trace
+#
+#
+# By default, whenever the NTDEBUG symbol is defined, you get level
+# 3. In order to get level 2 you have to define the symbol NOMEMLEAK.
+# In order to get level 4, you have to the file the symbol STACK_TRACE
+#
+# In summary here is how to get each one:
+#
+# 1.- Undefine NTDEBUG
+# 2.- define NTDEBUG, define NOMEMLEAK
+# 3.- define NTDEBUG, undefine NOMEMLEAK
+# 4.- define NTDEBUG, undefine NOMEMLEAK, define STACK_TRACE
+#
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+TARGETLIBS= \
+ ..\ulib\src\obj\*\ulib.lib \
+ ..\ifsutil\src\obj\*\ifsutil.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+
+UMTYPE=console
diff --git a/private/utils/comp/comp.cxx b/private/utils/comp/comp.cxx
new file mode 100644
index 000000000..c523c8c56
--- /dev/null
+++ b/private/utils/comp/comp.cxx
@@ -0,0 +1,1244 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ Comp.cxx
+
+Abstract:
+
+ Compares the contents of two files or sets of files.
+
+ COMP [data1] [data2] [/D] [/A] [/L] [/N=number] [/C]
+
+ data1 Specifies location and name(s) of first file(s) to compare.
+ data2 Specifies location and name(s) of second files to compare.
+ /D Displays differences in decimal format. This is the default
+ setting.
+ /A Displays differences in ASCII characters.
+ /L Displays line numbers for differences.
+ /N=number Compares only the first specified number of lines in each file.
+ /C Disregards case of ASCII letters when comparing files.
+
+ To compare sets of files, use wildcards in data1 and data2 parameters.
+
+Author:
+
+ Barry J. Gilhuly *** W-Barry *** Jun 91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include "ulib.hxx"
+#include "ulibcl.hxx"
+#include "error.hxx"
+#include "arg.hxx"
+#include "array.hxx"
+#include "bytestrm.hxx"
+#include "dir.hxx"
+#include "file.hxx"
+#include "filestrm.hxx"
+#include "filter.hxx"
+#include "iterator.hxx"
+#include "path.hxx"
+#include "rtmsg.h"
+#include "system.hxx"
+#include "smsg.hxx"
+#include "comp.hxx"
+
+
+extern "C" {
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+}
+
+
+ERRSTACK *perrstk;
+STREAM_MESSAGE *psmsg; // Create a pointer to the stream message
+ // class for program output.
+ULONG Errlev; // The current program error level
+PSTREAM Stdout;
+ULONG CompResult;
+
+
+
+//
+// Define a macro to deal with case insensitive comparisons
+//
+#define CASE_SENSITIVE( x ) ( ( _CaseInsensitive ) ? towupper( x ) : x )
+
+VOID
+StripQuotesFromString(
+ IN PWSTRING String
+ )
+/*++
+
+Routine Description:
+
+ This routine removes leading and trailing quote marks (if
+ present) from a quoted string. If the string is not a quoted
+ string, it is left unchanged.
+
+--*/
+{
+ if( String->QueryChCount() >= 2 &&
+ String->QueryChAt( 0 ) == '\"' &&
+ String->QueryChAt( String->QueryChCount() - 1 ) == '\"' ) {
+
+ String->DeleteChAt( String->QueryChCount() - 1 );
+ String->DeleteChAt( 0 );
+ }
+}
+
+DEFINE_CONSTRUCTOR( COMP, PROGRAM );
+
+
+VOID
+COMP::Destruct(
+ )
+/*++
+
+Routine Description:
+
+ Cleans up after finishing with an FC object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ DELETE( perrstk );
+ DELETE( psmsg );
+ if( _InputPath1 != NULL ) {
+ DELETE( _InputPath1 );
+ }
+ if( _InputPath2 != NULL ) {
+ DELETE( _InputPath2 );
+ }
+
+ return;
+}
+
+BOOLEAN
+COMP::Initialize(
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes an FC object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the initialization succeeded.
+
+
+--*/
+
+
+{
+ ARGUMENT_LEXEMIZER ArgLex;
+ ARRAY LexArray;
+ ARRAY ArrayOfArg;
+ PATH_ARGUMENT ProgramName;
+ FLAG_ARGUMENT FlagDecimalFormat;
+ FLAG_ARGUMENT FlagAsciiFormat;
+ FLAG_ARGUMENT FlagLineNumbers;
+ FLAG_ARGUMENT FlagCaseInsensitive;
+ FLAG_ARGUMENT FlagRequestHelp;
+ FLAG_ARGUMENT FlagWrongNumber;
+ LONG_ARGUMENT LongMatchLines;
+ PATH_ARGUMENT InFile1;
+ PATH_ARGUMENT InFile2;
+ STRING_ARGUMENT StringInvalidSwitch;
+ WCHAR WChar;
+ DSTRING InvalidString;
+
+ _Numbered = FALSE;
+ _Limited = FALSE;
+ _InputPath1 = NULL;
+ _InputPath2 = NULL;
+ if( !LexArray.Initialize() ) {
+ DebugPrintf( "LexArray.Initialize() Failed!\n" );
+ Errlev = INTERNAL_ERROR;
+ return( FALSE );
+ }
+ if( !ArgLex.Initialize(&LexArray) ) {
+ DebugPrintf( "ArgLex.Initialize() Failed!\n" );
+ Errlev = INTERNAL_ERROR;
+ return( FALSE );
+ }
+
+ ArgLex.PutSwitches("/");
+ ArgLex.SetCaseSensitive( FALSE );
+ ArgLex.PutMultipleSwitch( "acdl" );
+ ArgLex.PutSeparators( " /\t" );
+ ArgLex.PutStartQuotes( "\"" );
+ ArgLex.PutEndQuotes( "\"" );
+
+ if( !ArgLex.PrepareToParse() ) {
+ DebugPrintf( "ArgLex.PrepareToParse() Failed!\n" );
+ Errlev = INTERNAL_ERROR;
+ return( FALSE );
+ }
+
+ if( !ProgramName.Initialize("*") ||
+ !FlagDecimalFormat.Initialize("/D") ||
+ !FlagAsciiFormat.Initialize("/A") ||
+ !FlagLineNumbers.Initialize("/L") ||
+ !FlagCaseInsensitive.Initialize("/C") ||
+ !FlagWrongNumber.Initialize("/N") ||
+ !LongMatchLines.Initialize("/N=*") ||
+ !FlagRequestHelp.Initialize("/?") ||
+ !StringInvalidSwitch.Initialize("/*") ||
+ !InFile1.Initialize("*") ||
+ !InFile2.Initialize("*") ) {
+
+ DebugPrintf( "Unable to Initialize some or all of the Arguments!\n" );
+ Errlev = INTERNAL_ERROR;
+ return( FALSE );
+ }
+
+
+ if( !ArrayOfArg.Initialize() ) {
+ DebugPrintf( "ArrayOfArg.Initialize() Failed\n" );
+ Errlev = INTERNAL_ERROR;
+ return( FALSE );
+ }
+
+ if( !ArrayOfArg.Put(&ProgramName) ||
+ !ArrayOfArg.Put(&FlagDecimalFormat) ||
+ !ArrayOfArg.Put(&FlagAsciiFormat) ||
+ !ArrayOfArg.Put(&FlagLineNumbers) ||
+ !ArrayOfArg.Put(&FlagCaseInsensitive) ||
+ !ArrayOfArg.Put(&FlagWrongNumber) ||
+ !ArrayOfArg.Put(&LongMatchLines) ||
+ !ArrayOfArg.Put(&FlagRequestHelp) ||
+ !ArrayOfArg.Put(&StringInvalidSwitch) ||
+ !ArrayOfArg.Put(&InFile1) ||
+ !ArrayOfArg.Put(&InFile2) ) {
+
+ DebugPrintf( "ArrayOfArg.Put() Failed!\n" );
+ Errlev = INTERNAL_ERROR;
+ return( FALSE );
+
+ }
+
+
+ if( !ArgLex.DoParsing( &ArrayOfArg ) ||
+ StringInvalidSwitch.IsValueSet() ) {
+
+ if( StringInvalidSwitch.IsValueSet() ) {
+ //
+ // An invalid switch was found...
+ //
+// InvalidString.Initialize( "/" );
+// InvalidString.Strcat( StringInvalidSwitch.GetString() );
+ InvalidString.Initialize( "" );
+ InvalidString.Strcat( StringInvalidSwitch.GetLexeme() );
+ Errlev = INV_SWITCH;
+ psmsg->Set( MSG_COMP_INVALID_SWITCH );
+ psmsg->Display( "%W", &InvalidString );
+ } else {
+ psmsg->Set( MSG_COMP_BAD_COMMAND_LINE );
+ psmsg->Display( "" );
+ Errlev = SYNT_ERR;
+ }
+ return( FALSE );
+ }
+
+ if( FlagWrongNumber.IsValueSet() ) {
+ psmsg->Set( MSG_COMP_NUMERIC_FORMAT );
+ psmsg->Display( "" );
+ }
+
+ // It should now be safe to test the arguments for their values...
+ if( FlagRequestHelp.QueryFlag() ) {
+
+ // Send help message
+ psmsg->Set( MSG_COMP_HELP_MESSAGE );
+ psmsg->Display( "" );
+ return( FALSE );
+ }
+
+ if( InFile1.IsValueSet() ) {
+ StripQuotesFromString( (PWSTRING)InFile1.GetPath()->GetPathString() );
+ if( ( _InputPath1 = NEW PATH ) == NULL ) {
+ psmsg->Set( MSG_COMP_NO_MEMORY );
+ psmsg->Display( "" );
+ Errlev = NO_MEM_AVAIL;
+ return( FALSE );
+ }
+ if( !_InputPath1->Initialize( InFile1.GetPath(), FALSE ) ) {
+ DebugAbort( "Failed to initialize canonicolized version of the path 1\n" );
+ Errlev = INTERNAL_ERROR;
+ return( FALSE );
+ }
+ } else {
+ _InputPath1 = NULL;
+ }
+
+ if( InFile2.IsValueSet() ) {
+ StripQuotesFromString( (PWSTRING)InFile2.GetPath()->GetPathString() );
+ if( ( _InputPath2 = NEW PATH ) == NULL ) {
+ Errlev = NO_MEM_AVAIL;
+ psmsg->Set( MSG_COMP_NO_MEMORY );
+ psmsg->Display( "" );
+ return( FALSE );
+ }
+ if( !_InputPath2->Initialize( InFile2.GetPath(), FALSE ) ) {
+ DebugAbort( "Failed to initialize canonicolized version of the path 2\n" );
+ Errlev = INTERNAL_ERROR;
+ return( FALSE );
+ }
+ } else {
+ _InputPath2 = NULL;
+ }
+
+ //
+ // Set the output mode...
+ //
+ if( FlagAsciiFormat.QueryFlag() ) {
+ _Mode = OUTPUT_ASCII;
+ } else if( FlagDecimalFormat.QueryFlag() ) {
+ _Mode = OUTPUT_DECIMAL;
+ } else {
+ _Mode = OUTPUT_HEX;
+ }
+
+ //
+ // Set the remaining flags...
+ //
+ if( LongMatchLines.IsValueSet() ) {
+ if( ( ( WChar = ( LongMatchLines.GetLexeme()->QueryChAt( 3 ) ) ) == '+' ) ||
+ WChar == '-' ||
+ ( _NumberOfLines = LongMatchLines.QueryLong() ) < 0 ) {
+ Errlev = INV_SWITCH;
+ psmsg->Set( MSG_COMP_BAD_NUMERIC_ARG );
+ psmsg->Display( "%W", LongMatchLines.GetLexeme() );
+ return( FALSE );
+ }
+
+ if ( _NumberOfLines != 0 ) {
+ _Numbered = TRUE;
+ _Limited = TRUE;
+ }
+
+ } else {
+ _Numbered = FlagLineNumbers.QueryFlag();
+ _Limited = FALSE;
+ }
+ _CaseInsensitive = FlagCaseInsensitive.QueryFlag();
+
+
+ if( FlagDecimalFormat.IsValueSet() ||
+ FlagAsciiFormat.IsValueSet() ||
+ FlagLineNumbers.IsValueSet() ||
+ FlagCaseInsensitive.IsValueSet() ||
+ LongMatchLines.IsValueSet() ||
+ ( InFile1.IsValueSet() &&
+ InFile2.IsValueSet() ) ) {
+ _OptionsFound = TRUE;
+ } else {
+ _OptionsFound = FALSE;
+ }
+
+ return( TRUE );
+}
+
+VOID
+COMP::Start(
+ )
+/*++
+
+Routine Description:
+
+ Query missing information from the user and start the comparison
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+
+{
+ DSTRING UserInput;
+ PWSTRING InvalidSwitch;
+ USHORT OptionCount;
+ LONG Number;
+
+ for( ;; ) {
+
+ if( _InputPath1 == NULL ) {
+
+ // Query a path for file 1...
+ psmsg->Set( MSG_COMP_QUERY_FILE1, ERROR_MESSAGE );
+ psmsg->Display( "" );
+ if( !psmsg->QueryStringInput( &UserInput ) ) {
+ psmsg->Set( MSG_COMP_UNEXPECTED_END );
+ psmsg->Display( "" );
+ Errlev = UNEXP_EOF;
+ return;
+ }
+ if( ( _InputPath1 = NEW PATH ) == NULL ) {
+ psmsg->Set( MSG_COMP_NO_MEMORY );
+ psmsg->Display( "" );
+ Errlev = NO_MEM_AVAIL;
+ return;
+ }
+ if( !_InputPath1->Initialize( &UserInput, FALSE ) ) {
+ DebugPrintf( "Unable to initialize the path for file 1\n" );
+ Errlev = INTERNAL_ERROR;
+ return;
+ }
+ }
+ if( _InputPath2 == NULL ) {
+
+ // Query a path for file 2...
+ psmsg->Set( MSG_COMP_QUERY_FILE2, ERROR_MESSAGE );
+ psmsg->Display( "" );
+ if( !psmsg->QueryStringInput( &UserInput ) ) {
+ psmsg->Set( MSG_COMP_UNEXPECTED_END );
+ psmsg->Display( "" );
+ Errlev = UNEXP_EOF;
+ return;
+ }
+ if( ( _InputPath2 = NEW PATH ) == NULL ) {
+ psmsg->Set( MSG_COMP_NO_MEMORY );
+ psmsg->Display( "" );
+ Errlev = NO_MEM_AVAIL;
+ return;
+ }
+ if( !_InputPath2->Initialize( &UserInput, FALSE ) ) {
+ DebugPrintf( "Unable to initialize the path for file 2\n" );
+ Errlev = INTERNAL_ERROR;
+ return;
+ }
+ }
+ if( !_OptionsFound ) {
+
+ //
+ // Query Options from the user...
+ //
+ DSTRING Options;
+ DSTRING Delim;
+ CHNUM CurSwitchStart, NextSwitchStart, Len;
+
+ Delim.Initialize( "/-" );
+ // Query a new list of options from the user
+ for( OptionCount = 0; OptionCount < 5; OptionCount++ ) {
+ psmsg->Set( MSG_COMP_OPTION, ERROR_MESSAGE );
+ psmsg->Display( "" );
+ if( !psmsg->QueryStringInput( &Options ) ) {
+ psmsg->Set( MSG_COMP_UNEXPECTED_END );
+ psmsg->Display( "" );
+ Errlev = UNEXP_EOF;
+ return;
+ }
+ if( Options.QueryChCount() == 0 ) {
+ break;
+ }
+
+ CurSwitchStart = Options.Strcspn( &Delim );
+ if( CurSwitchStart != 0 ) {
+ psmsg->Set( MSG_COMP_BAD_COMMAND_LINE );
+ psmsg->Display( "" );
+ Errlev = SYNT_ERR;
+ return;
+ }
+ for( ;; ) {
+
+ Len = 0;
+ CurSwitchStart++;
+ NextSwitchStart = Options.Strcspn( &Delim, CurSwitchStart );
+
+ switch( towupper( Options.QueryChAt( CurSwitchStart ) ) ) {
+ case 'A':
+ _Mode = OUTPUT_ASCII;
+ CurSwitchStart++;
+ break;
+ case 'D':
+ _Mode = OUTPUT_DECIMAL;
+ CurSwitchStart++;
+ break;
+ case 'C':
+ _CaseInsensitive = TRUE;
+ CurSwitchStart++;
+ break;
+ case 'L':
+ _Numbered = TRUE;
+ CurSwitchStart++;
+ break;
+ case 'N':
+ ++CurSwitchStart;
+ if( Options.QueryChAt( CurSwitchStart ) != '=' ) {
+ psmsg->Set( MSG_COMP_NUMERIC_FORMAT );
+ psmsg->Display( "" );
+ break;
+ }
+ ++CurSwitchStart;
+ if( CurSwitchStart == NextSwitchStart ) {
+ break;
+ }
+ if( NextSwitchStart == INVALID_CHNUM ) {
+ Len = INVALID_CHNUM;
+ } else {
+ Len = NextSwitchStart - CurSwitchStart;
+ }
+ if( !Options.QueryNumber( &Number, CurSwitchStart, Len ) ) {
+ InvalidSwitch = Options.QueryString( CurSwitchStart );
+ psmsg->Set( MSG_COMP_BAD_NUMERIC_ARG );
+ psmsg->Display( "%W", InvalidSwitch );
+ Errlev = BAD_NUMERIC_ARG;
+ DELETE( InvalidSwitch );
+
+ return;
+ }
+ if (Options.QueryNumber( &_NumberOfLines, CurSwitchStart, Len ) ) {
+ _Numbered = TRUE;
+ _Limited = TRUE;
+ }
+ CurSwitchStart += Len;
+ break;
+ default:
+ InvalidSwitch = Options.QueryString( CurSwitchStart - 1 );
+ psmsg->Set( MSG_COMP_INVALID_SWITCH );
+ psmsg->Display( "%W", InvalidSwitch );
+ Errlev = INV_SWITCH;
+ DELETE( InvalidSwitch );
+
+ return;
+ }
+ if( ( CurSwitchStart != NextSwitchStart ) ||
+ ( Len == INVALID_CHNUM ) ) {
+ break;
+ }
+ }
+ }
+ }
+
+ DoCompare();
+
+ //
+ // Check if there are more files to be compared...
+ //
+ psmsg->Set( MSG_COMP_MORE, ERROR_MESSAGE );
+ psmsg->Display( "" );
+ if( !psmsg->IsYesResponse() ) {
+ break;
+ }
+ DELETE( _InputPath1 );
+ DELETE( _InputPath2 );
+ _InputPath1 = NULL;
+ _InputPath2 = NULL;
+ _OptionsFound = NULL;
+ }
+
+ return;
+}
+
+VOID
+COMP::DoCompare(
+ )
+/*++
+
+Routine Description:
+
+ Perform the comparison of the files.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+
+{
+ FSN_FILTER Filter;
+ PARRAY pNodeArray;
+ PITERATOR pIterator;
+ PWSTRING pTmp;
+ PATH File1Path;
+ PFSN_DIRECTORY pDirectory = NULL;
+ PATH CanonPath1; // Canonicolized versions of the user paths
+ PATH CanonPath2;
+ DSTRING WildCardString;
+
+
+ //
+ // Initialize the wildcard string..
+ //
+ WildCardString.Initialize( "" );
+ SYSTEM::QueryResourceString( &WildCardString, MSG_COMP_WILDCARD_STRING, "" );
+
+ // Check to see if the input paths are empty.
+
+ if (_InputPath1->GetPathString()->QueryChCount() == 0) {
+ Errlev = CANT_OPEN_FILE;
+ psmsg->Set( MSG_COMP_UNABLE_TO_OPEN );
+ psmsg->Display( "%W", _InputPath1->GetPathString() );
+ return;
+ }
+
+ if (_InputPath2->GetPathString()->QueryChCount() == 0) {
+ Errlev = CANT_OPEN_FILE;
+ psmsg->Set( MSG_COMP_UNABLE_TO_OPEN );
+ psmsg->Display( "%W", _InputPath2->GetPathString() );
+ return;
+ }
+
+ //
+ // Test if the input paths contain only a directory name. If it
+ // does, append '*.*' to the path so all files in that directory
+ // may be compared.
+ //
+ if( _InputPath1->IsDrive() ||
+ ( !_InputPath1->HasWildCard() &&
+ ( pDirectory = SYSTEM::QueryDirectory( _InputPath1 ) ) != NULL ) ) {
+
+ // The input path corresponds to a directory...
+ _InputPath1->AppendBase( &WildCardString );
+
+ }
+ DELETE( pDirectory );
+ if( _InputPath2->IsDrive() ||
+ ( !_InputPath2->HasWildCard() &&
+ ( pDirectory = SYSTEM::QueryDirectory( _InputPath2 ) ) != NULL ) ) {
+
+ // The input path corresponds to a directory...
+ _InputPath2->AppendBase( &WildCardString );
+
+ }
+ DELETE( pDirectory );
+
+ //
+ // Canonicolize the input paths...
+ //
+ CanonPath1.Initialize( _InputPath1, TRUE );
+ CanonPath2.Initialize( _InputPath2, TRUE );
+
+ //
+ // Test if the first path name contains any wildcards. If it does,
+ // the program must initialize an array of FSN_NODES (for multiple
+ // files...
+ //
+ if( CanonPath1.HasWildCard() ) {
+ PPATH pTmpPath;
+ //
+ // Get a directory based on what the user specified for File 1
+ //
+ if( ( pTmpPath = CanonPath1.QueryFullPath() ) == NULL ) {
+ DebugPrintf( "Unable to grab the Prefix from the input path...\n" );
+ Errlev = INTERNAL_ERROR;
+ return;
+ }
+ pTmpPath->TruncateBase();
+ if( ( pDirectory = SYSTEM::QueryDirectory( pTmpPath, FALSE ) ) != NULL ) {
+ //
+ // Create an FSN_FILTER so we can use the directory to create an
+ // array of FSN_NODES
+ Filter.Initialize();
+
+ pTmp = CanonPath1.QueryName();
+ Filter.SetFileName( pTmp );
+ DELETE( pTmp );
+ Filter.SetAttributes( (FSN_ATTRIBUTE)0, // ALL
+ FSN_ATTRIBUTE_FILES, // ANY
+ FSN_ATTRIBUTE_DIRECTORY ); // NONE
+ pNodeArray = pDirectory->QueryFsnodeArray( &Filter );
+ pIterator = pNodeArray->QueryIterator();
+ DELETE( pDirectory );
+
+ _File1 = (FSN_FILE *)pIterator->GetNext();
+ } else {
+ _File1 = NULL;
+ }
+ DELETE( pTmpPath );
+ } else {
+ _File1 = SYSTEM::QueryFile( &CanonPath1 );
+ }
+
+ if( _File1 == NULL ) {
+ Errlev = CANT_OPEN_FILE;
+ psmsg->Set( MSG_COMP_UNABLE_TO_OPEN );
+ psmsg->Display( "%W", _InputPath1->GetPathString() );
+ return;
+ }
+
+ do {
+
+
+ //
+ // Replace the input path filename with what is to be opened...
+ //
+ pTmp = _File1->GetPath()->QueryName();
+ _InputPath1->SetName( pTmp );
+ DELETE( pTmp );
+
+
+ // Determine if filename 2 contains any wildcards...
+ if( CanonPath2.HasWildCard() ) {
+ // ...if it does, expand them...
+ PPATH pExpanded;
+
+ pExpanded = CanonPath2.QueryWCExpansion( (PATH *)_File1->GetPath() );
+ if( pExpanded == NULL ) {
+ Errlev = COULD_NOT_EXP;
+ psmsg->Set( MSG_COMP_UNABLE_TO_EXPAND );
+ psmsg->Display( "%W%W", _InputPath1->GetPathString(), _InputPath2->GetPathString() );
+ DELETE( _File1 );
+ break;
+ }
+
+ //
+ // Place the expanded name in the input path...
+ //
+ pTmp = pExpanded->QueryName();
+ _InputPath2->SetName( pTmp );
+ DELETE( pTmp );
+
+ psmsg->Set( MSG_COMP_COMPARE_FILES );
+ psmsg->Display( "%W%W", _InputPath1->GetPathString(),
+ _InputPath2->GetPathString()
+ );
+ _File2 = SYSTEM::QueryFile( pExpanded );
+ DELETE( pExpanded );
+
+ } else {
+
+ psmsg->Set( MSG_COMP_COMPARE_FILES );
+ psmsg->Display( "%W%W", _InputPath1->GetPathString(),
+ _InputPath2->GetPathString()
+ );
+ _File2 = SYSTEM::QueryFile( &CanonPath2 );
+
+ }
+
+ if( _File2 == NULL ) {
+ Errlev = CANT_OPEN_FILE;
+ psmsg->Set( MSG_COMP_UNABLE_TO_OPEN );
+ psmsg->Display( "%W", _InputPath2->GetPathString() );
+ DELETE( _File1 );
+ if( !CanonPath1.HasWildCard() ) {
+ break;
+ }
+ continue;
+ }
+
+
+ //
+ // Open the streams...
+ // Initialize _ByteStream1 and _ByteStream2 with BufferSize = 1024, to
+ // improve performance
+ //
+ if( (( _FileStream1 = (FILE_STREAM *)_File1->QueryStream( READ_ACCESS ) ) == NULL) ||
+ !_ByteStream1.Initialize( _FileStream1, 1024 )
+ ) {
+ Errlev = CANT_READ_FILE;
+ psmsg->Set( MSG_COMP_UNABLE_TO_READ );
+ psmsg->Display( "%W", _File1->GetPath()->GetPathString() );
+ DELETE( _File1 );
+ DELETE( _File2 );
+ if( !CanonPath1.HasWildCard() ) {
+ break;
+ }
+ continue;
+ }
+ if( (( _FileStream2 = (FILE_STREAM *)_File2->QueryStream( READ_ACCESS ) ) == NULL ) ||
+ !_ByteStream2.Initialize( _FileStream2, 1024 )
+ ) {
+ Errlev = CANT_READ_FILE;
+ psmsg->Set( MSG_COMP_UNABLE_TO_READ );
+ psmsg->Display( "%W", _File2->GetPath()->GetPathString() );
+ DELETE( _FileStream1 );
+ DELETE( _File1 );
+ DELETE( _File2 );
+ if( !CanonPath1.HasWildCard() ) {
+ break;
+ }
+ continue;
+ }
+
+ BinaryCompare();
+
+ // Close both streams now, since we are done with them...
+ DELETE( _FileStream1 );
+ DELETE( _FileStream2 );
+ DELETE( _File1 );
+ DELETE( _File2 );
+
+ if( !CanonPath1.HasWildCard() ) {
+ break;
+ }
+
+ } while( ( _File1 = (FSN_FILE *)pIterator->GetNext() ) != NULL );
+
+ return;
+}
+
+
+#ifdef DBCS // v-junm - 08/30/93
+
+BOOLEAN
+COMP::CharEqual(
+ PUCHAR c1,
+ PUCHAR c2
+ )
+/*++
+
+Routine Description:
+
+ Checks to see if a PCHAR DBCS or SBCS char is equal or not. For SBCS
+ chars, if the CaseInsensitive flag is set, the characters are converted
+ to uppercase and checked for equality.
+
+Arguments:
+
+ c1 - NULL terminating DBCS/SBCS char *.
+ c2 - NULL terminating DBCS/SBCS char *.
+
+Return Value:
+
+ TRUE - if equal.
+
+Notes:
+
+ The char string sequence is:
+
+ SBCS:
+ c1[0] - char code.
+ c1[1] - 0.
+ DBCS:
+ c1[0] - leadbyte.
+ c1[1] - tailbyte.
+ c1[2] - 0.
+
+--*/
+{
+ if ( (*(c1+1) == 0) && (*(c2+1) == 0 ) )
+ return( CASE_SENSITIVE( *c1 ) == CASE_SENSITIVE( *c2 ) );
+ else
+ return( (*c1 == *c2) && (*(c1+1) == *(c2+1)) );
+}
+
+#endif
+
+VOID
+COMP::BinaryCompare(
+ )
+/*++
+
+Routine Description:
+
+ Does the actual binary compare between the two streams
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+ The binary compare simply does a byte by byte comparison of the two
+ files and reports all differences, as well as the offset into the
+ file... ...no line buffer is required for this comparision...
+
+--*/
+{
+ ULONG FileOffset = 0;
+ ULONG LineCount = 1; // Start the line count at 1...
+ USHORT Differences = 0;
+ BYTE Byte1, Byte2;
+#ifdef DBCS // v-junm - 08/30/93
+ BOOLEAN Lead = 0; // Set when leadbyte is read.
+ UCHAR Byte1W[3], Byte2W[3]; // PCHAR to contain DBCS/SBCS char.
+ ULONG DBCSFileOffset = 0; // When ASCII output and DBCS char,
+ // the offset is where the lead
+ // byte is, not the tail byte.
+#endif
+ STR Message[ 9 ];
+ DSTRING ErrType;
+
+ //
+ // Set up the message string...
+ //
+ Message[ 0 ] = '%';
+ Message[ 1 ] = 'W';
+ if( !_Numbered ) {
+ ErrType.Initialize( "OFFSET" );
+ Message[ 2 ] = '%';
+ Message[ 3 ] = 'X';
+ } else {
+ ErrType.Initialize( "LINE" );
+ Message[ 2 ] = '%';
+ Message[ 3 ] = 'd';
+ }
+ if( _Mode == OUTPUT_HEX ) {
+ Message[ 4 ] = '%';
+ Message[ 5 ] = 'X';
+ Message[ 6 ] = '%';
+ Message[ 7 ] = 'X';
+ } else if( _Mode == OUTPUT_DECIMAL ) {
+ Message[ 4 ] = '%';
+ Message[ 5 ] = 'd';
+ Message[ 6 ] = '%';
+ Message[ 7 ] = 'd';
+ } else {
+#ifdef DBCS // v-junm - 08/30/93
+// This is needed to display DBCS chars. DBCS chars will be handed over
+// as a pointer of chars. In which turns out to go to a call to swprintf in
+// basesys.cxx. You may wonder why a DBCS char is stored as a string, but
+// it works because before the call to swprintf is made, a 'h' is placed before
+// the '%s' and makes a conversion to unicode.
+
+ Message[ 4 ] = '%';
+ Message[ 5 ] = 's';
+ Message[ 6 ] = '%';
+ Message[ 7 ] = 's';
+#else // DBCS
+ Message[ 4 ] = '%';
+ Message[ 5 ] = 'c';
+ Message[ 6 ] = '%';
+ Message[ 7 ] = 'c';
+#endif // DBCS
+ }
+ Message[ 8 ] = 0;
+
+ // Compare the lengths of the files - if they aren't the same and
+ // the number of lines to match hasn't been specified, then return
+ // 'Files are different sizes'.
+ if( !_Limited ) {
+ if( _File1->QuerySize() != _File2->QuerySize() ) {
+ Errlev = DIFFERENT_SIZES;
+ CompResult = FILES_ARE_DIFFERENT;
+ psmsg->Set( MSG_COMP_DIFFERENT_SIZES );
+ psmsg->Display( "" );
+ return;
+ }
+ }
+
+ for( ;; FileOffset++ ) {
+ //if( !_FileStream1->ReadByte( &Byte1 ) ) {
+ if( !_ByteStream1.ReadByte( &Byte1 ) ) {
+ if( !_ByteStream1.IsAtEnd() ) {
+ Errlev = CANT_READ_FILE;
+ psmsg->Set( MSG_COMP_UNABLE_TO_READ );
+ psmsg->Display( "%W", _File1->GetPath()->GetPathString() );
+ return;
+ }
+ //if( !_FileStream2->ReadByte( &Byte2 ) ) {
+ if( !_ByteStream2.ReadByte( &Byte2 ) ) {
+ if( !_ByteStream2.IsAtEnd() ) {
+ Errlev = CANT_READ_FILE;
+ psmsg->Set( MSG_COMP_UNABLE_TO_READ );
+ psmsg->Display( "%W", _File2->GetPath()->GetPathString() );
+ return;
+ }
+ break;
+ } else {
+ Errlev = FILE1_LINES;
+ psmsg->Set( MSG_COMP_FILE1_TOO_SHORT );
+ psmsg->Display( "%d", LineCount-1 );
+ return;
+ }
+ } else {
+ //if( !_FileStream2->ReadByte( &Byte2 ) ) {
+ if( !_ByteStream2.ReadByte( &Byte2 ) ) {
+ if( !_ByteStream2.IsAtEnd() ) {
+ Errlev = CANT_READ_FILE;
+ psmsg->Set( MSG_COMP_UNABLE_TO_READ );
+ psmsg->Display( "%W", _File2->GetPath()->GetPathString() );
+ return;
+ }
+ Errlev = FILE2_LINES;
+ psmsg->Set( MSG_COMP_FILE2_TOO_SHORT );
+ psmsg->Display( "%d", LineCount-1 );
+ return;
+ }
+ }
+
+#ifdef DBCS // v-junm - 08/30/93
+// For hex and decimal display, we don't want to worry about DBCS chars. This
+// is a different spec than DOS/V (Japanese DOS), but it's much cleaner this
+// way. So, we will only worry about DBCS chars when the user asks us to
+// display the difference in characters (/A option). The file offset displayed
+// for DBCS characters is always where the leadbyte is in the file even though
+// only the tailbyte is different.
+
+ DBCSFileOffset = FileOffset;
+
+ //
+ // Only going to worry about DBCS when user is comparing with
+ // ASCII output.
+ //
+ //if ( _Mode == OUTPUT_ASCII ) {
+
+
+ //kksuzuka: #133
+ //We have to worry about DBCS with 'c' option also.
+ if ( (_Mode==OUTPUT_ASCII) || ( _CaseInsensitive ) ) {
+
+ if ( Lead ) {
+
+ //
+ // DBCS leadbyte already found. Setup variables and
+ // fill in tailbyte and null.
+ //
+
+ DBCSFileOffset--;
+ Lead = FALSE;
+ *(Byte1W+1) = Byte1;
+ *(Byte2W+1) = Byte2;
+ *(Byte1W+2) = *(Byte2W+2) = 0;
+
+ }
+ else if ( IsDBCSLeadByte( Byte1 ) || IsDBCSLeadByte( Byte2 ) ) {
+
+ //
+ // Found leadbyte. Set lead flag telling the next time
+ // around that the character is a tailbyte.
+ //
+
+ //
+ // Save the leadbyte. Tailbyte will be filled next time
+ // around(above).
+ //
+
+ *Byte1W = Byte1;
+ *Byte2W = Byte2;
+ Lead = TRUE;
+ continue;
+
+ }
+ else {
+
+ //
+ // SBCS char.
+ //
+
+ *Byte1W = Byte1;
+ *Byte2W = Byte2;
+ *(Byte1W+1) = *(Byte2W+1) = 0;
+ Lead = FALSE;
+ }
+ }
+ else {
+
+ //
+ // Not ASCII output (/a option). Perform original routines.
+ //
+
+ *Byte1W = Byte1;
+ *Byte2W = Byte2;
+ *(Byte1W+1) = *(Byte2W+1) = 0;
+ }
+
+ //
+ // Check to see if chars are equal. If not, display difference.
+ //
+
+ if ( CharEqual( Byte1W, Byte2W ) == FALSE ) {
+
+ psmsg->Set( MSG_COMP_COMPARE_ERROR );
+
+ if ( _Mode == OUTPUT_ASCII ) {
+
+ if ( _Numbered )
+ psmsg->Display( Message, &ErrType,
+ LineCount, Byte1W, Byte2W );
+ else
+ psmsg->Display( Message, &ErrType,
+ DBCSFileOffset, Byte1W, Byte2W );
+
+ }
+ else {
+ if ( _Numbered )
+ psmsg->Display( Message, &ErrType,
+ LineCount, *Byte1W, *Byte2W );
+ //kksuzuka: #133
+ //We have to worry about DBCS with c option also.
+ //else
+ else {
+ if( *Byte1W != *Byte2W ) {
+ psmsg->Display( Message, &ErrType,
+ FileOffset, *Byte1W, *Byte2W );
+ }
+ else {
+ psmsg->Display( Message, &ErrType,
+ FileOffset, *(Byte1W+1), *(Byte2W+1) );
+ }
+ }
+ }
+#else // DBCS
+ // Now compare the bytes...if they are different, report the
+ // difference...
+ if( CASE_SENSITIVE( Byte1 ) != CASE_SENSITIVE( Byte2 ) ) {
+ if( _Numbered ) {
+ psmsg->Set( MSG_COMP_COMPARE_ERROR );
+ psmsg->Display( Message, &ErrType, LineCount, Byte1, Byte2 );
+ } else {
+ psmsg->Set( MSG_COMP_COMPARE_ERROR );
+ psmsg->Display( Message, &ErrType, FileOffset, Byte1, Byte2 );
+ }
+
+#endif // DBCS
+
+ if( ++Differences == MAX_DIFF ) {
+ psmsg->Set( MSG_COMP_TOO_MANY_ERRORS );
+ psmsg->Display( "" );
+ Errlev = TEN_MISM;
+ CompResult = FILES_ARE_DIFFERENT;
+ return;
+ }
+ }
+ //
+ // Use <CR>'s imbedded in File1 to determine the line count. This is
+ // an inexact method (the differing byte may be '/r') but it is good
+ // enough for the purposes of this program.
+ //
+#ifdef DBCS // v-junm - 08/30/93
+ if( *Byte1W == '\r' ) {
+#else // DBCS
+ if( Byte1 == '\r' ) {
+#endif // DBCS
+ LineCount++;
+ }
+ if( _Limited ) {
+ if( LineCount > (ULONG)_NumberOfLines ) {
+ break;
+ }
+ }
+ }
+
+#ifdef DBCS // v-junm - 08/30/93
+// There may be a leadbyte without a tailbyte at the end of the file. Check
+// for it, and process accordingly.
+
+ if ( _Mode == OUTPUT_ASCII && Lead ) {
+
+ //
+ // There is a leadbyte left. Check to see if they are equal and
+ // print difference if not.
+ //
+
+ if ( *Byte2W != *Byte1W ) {
+
+ *(Byte1W+1) = *(Byte2W+1) = 0;
+ Differences++;
+
+ psmsg->Set( MSG_COMP_COMPARE_ERROR );
+ if ( _Numbered )
+ psmsg->Display(Message, &ErrType, LineCount, Byte1W, Byte2W);
+ else
+ psmsg->Display(Message, &ErrType, FileOffset-1, Byte1W, Byte2W);
+ }
+ }
+
+#endif // DBCS
+
+ //
+ // Check if any differences were found in the files
+ //
+ if( !Differences ) {
+ psmsg->Set( MSG_COMP_FILES_OK );
+ psmsg->Display( " " );
+ } else {
+ CompResult = FILES_ARE_DIFFERENT;
+ }
+
+ return;
+}
+
+
+int _CRTAPI1
+main(
+ )
+{
+
+
+ DEFINE_CLASS_DESCRIPTOR( COMP );
+
+
+ {
+ COMP Comp;
+
+ perrstk = NEW ERRSTACK;
+ psmsg = NEW STREAM_MESSAGE;
+
+ Stdout = Get_Standard_Output_Stream();
+
+ // Initialize the stream message for standard input, stdout
+ psmsg->Initialize( Stdout,
+ Get_Standard_Input_Stream(),
+ Get_Standard_Error_Stream() );
+
+ if( !SYSTEM::IsCorrectVersion() ) {
+ DebugPrintf( "Incorrect Version Number...\n" );
+ psmsg->Set( MSG_COMP_INCORRECT_VERSION );
+ psmsg->Display( "" );
+ Comp.Destruct();
+ return( CANNOT_COMPARE_FILES );
+// return( INCORRECT_DOS_VER );
+ }
+
+ // Set the Error level to Zero - No error...
+ Errlev = NO_ERRORS;
+ CompResult = FILES_ARE_EQUAL;
+
+ if( !( Comp.Initialize() ) ) {
+ //
+ // The Command line didn't initialize properly, die nicely
+ // without printing any error messages - Main doesn't know
+ // why the Initialization failed...
+ //
+ // What has to be deleted by hand, or can everything be removed
+ // by the destructor for the FC class?
+ //
+ Comp.Destruct();
+ return( CANNOT_COMPARE_FILES );
+// return( Errlev );
+ }
+
+
+ // Do file comparison stuff...
+ Comp.Start();
+ Comp.Destruct();
+// return( Errlev );
+ if( ( Errlev == NO_ERRORS ) || ( Errlev == TEN_MISM ) || ( Errlev == DIFFERENT_SIZES ) ) {
+ return( CompResult );
+ } else {
+ return( CANNOT_COMPARE_FILES );
+ }
+ }
+}
diff --git a/private/utils/comp/comp.hxx b/private/utils/comp/comp.hxx
new file mode 100644
index 000000000..0421fa23f
--- /dev/null
+++ b/private/utils/comp/comp.hxx
@@ -0,0 +1,129 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ comp.hxx
+
+Abstract:
+
+Author:
+
+ Barry J. Gilhuly
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+
+#if !defined( _BINARY_COMP_ )
+
+#define _BINARY_COMP_
+
+
+//
+// Define an enumerated type for the style of output information - Hex,
+// Decimal, or Ascii
+//
+enum OUTPUT_TYPE {
+ OUTPUT_HEX,
+ OUTPUT_DECIMAL,
+ OUTPUT_ASCII
+};
+
+// Define the maximum number of comparison errors...
+#define MAX_DIFF 10
+
+// Define the various error levels returned by this program
+#define NO_ERRORS 0
+#define NO_MEM_AVAIL 1
+#define CANT_OPEN_FILE 2
+#define CANT_READ_FILE 3
+#define SYNT_ERR 4
+#define BAD_NUMERIC_ARG 5
+#define DIFFERENT_SIZES 16
+#define NEED_DELIM_CHAR 17
+#define COULD_NOT_EXP 20
+#define TEN_MISM 32
+#define INCORRECT_DOS_VER 33
+#define UNEXP_EOF 34
+#define INV_SWITCH 35
+#define FILE1_LINES 36
+#define FILE2_LINES 37
+#define INTERNAL_ERROR 99
+
+#define FILES_ARE_EQUAL 0
+#define FILES_ARE_DIFFERENT 1
+#define CANNOT_COMPARE_FILES 2
+
+#include "object.hxx"
+#include "keyboard.hxx"
+#include "program.hxx"
+
+DECLARE_CLASS( COMP );
+
+class COMP : public PROGRAM {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( COMP );
+
+ NONVIRTUAL
+ VOID
+ Destruct(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ );
+
+ NONVIRTUAL
+ VOID
+ Start(
+ );
+
+ private:
+
+#ifdef DBCS // v-junm - 08/30/93
+
+ BOOLEAN
+ CharEqual(
+ PUCHAR,
+ PUCHAR
+ );
+
+#endif
+
+ NONVIRTUAL
+ VOID
+ DoCompare(
+ );
+
+ NONVIRTUAL
+ VOID
+ BinaryCompare(
+ );
+
+ BOOLEAN _CaseInsensitive; // Case sensitive compare
+ BOOLEAN _Limited; // Compare a limited number of lines
+ BOOLEAN _Numbered; // Number the lines or use byte offsets
+ BOOLEAN _OptionsFound; // Options were present on the command line
+ LONG _NumberOfLines; // The number of lines to compare
+ OUTPUT_TYPE _Mode; // The comparison mode: HEX, DECIMAL, or ASCII
+ PPATH _InputPath1; // The paths requested...
+ PPATH _InputPath2;
+ PFSN_FILE _File1;
+ PFSN_FILE _File2;
+ PFILE_STREAM _FileStream1;
+ PFILE_STREAM _FileStream2;
+ BYTE_STREAM _ByteStream1;
+ BYTE_STREAM _ByteStream2;
+};
+
+
+#endif // _BINARY_COMP_
+
diff --git a/private/utils/comp/comp.rc b/private/utils/comp/comp.rc
new file mode 100644
index 000000000..3e66db08c
--- /dev/null
+++ b/private/utils/comp/comp.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "File Compare Utility"
+#define VER_INTERNALNAME_STR "Comp"
+#define VER_ORIGINALFILENAME_STR "Comp.Exe"
+
+#include "common.ver"
diff --git a/private/utils/comp/makefile b/private/utils/comp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/comp/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/comp/sources b/private/utils/comp/sources
new file mode 100644
index 000000000..10a4164b9
--- /dev/null
+++ b/private/utils/comp/sources
@@ -0,0 +1,56 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=utils
+MINORCOMP=comp
+
+TARGETNAME=comp
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=comp.cxx comp.rc
+
+INCLUDES=..\ulib\inc;\nt\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+TARGETLIBS= \
+ ..\ulib\src\obj\*\ulib.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+
+UMTYPE=console
diff --git a/private/utils/compact/compact.c b/private/utils/compact/compact.c
new file mode 100644
index 000000000..78ca1b792
--- /dev/null
+++ b/private/utils/compact/compact.c
@@ -0,0 +1,1556 @@
+/*++
+
+Copyright (c) 1994-1995 Microsoft Corporation
+
+Module Name:
+
+ Compact.c
+
+Abstract:
+
+ This module implements the double stuff utility for compressed NTFS
+ volumes.
+
+Author:
+
+ Gary Kimura [garyki] 10-Jan-1994
+
+Revision History:
+
+
+--*/
+
+//
+// Include the standard header files.
+//
+
+#define UNICODE
+#define _UNICODE
+
+#include <stdio.h>
+#include <windows.h>
+#include <winioctl.h>
+#include <shellapi.h>
+
+#include "support.h"
+#include "msg.h"
+
+#define lstrchr wcschr
+#define lstricmp _wcsicmp
+#define lstrnicmp _wcsnicmp
+
+//
+// FIRST_COLUMN_WIDTH - When compressing files, the width of the output
+// column which displays the file name
+//
+
+#define FIRST_COLUMN_WIDTH (20)
+
+//
+// Local procedure types
+//
+
+typedef BOOLEAN (*PACTION_ROUTINE) (
+ IN PTCHAR DirectorySpec,
+ IN PTCHAR FileSpec
+ );
+
+typedef VOID (*PFINAL_ACTION_ROUTINE) (
+ );
+
+//
+// Declare global variables to hold the command line information
+//
+
+BOOLEAN DoSubdirectories = FALSE; // recurse
+BOOLEAN IgnoreErrors = FALSE; // keep going despite errs
+BOOLEAN UserSpecifiedFileSpec = FALSE;
+BOOLEAN ForceOperation = FALSE; // compress even if already so
+BOOLEAN Quiet = FALSE; // be less verbose
+BOOLEAN DisplayAllFiles = FALSE; // dsply hidden, system?
+TCHAR StartingDirectory[MAX_PATH]; // parameter to "/s"
+ULONG AttributesNoDisplay = FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN;
+
+//
+// Declere global variables to hold compression statistics
+//
+
+LARGE_INTEGER TotalDirectoryCount;
+LARGE_INTEGER TotalFileCount;
+LARGE_INTEGER TotalCompressedFileCount;
+LARGE_INTEGER TotalUncompressedFileCount;
+
+LARGE_INTEGER TotalFileSize;
+LARGE_INTEGER TotalCompressedSize;
+
+TCHAR Buf[1024]; // for displaying stuff
+
+
+HANDLE
+OpenFileForCompress(
+ IN PTCHAR ptcFile
+ )
+/*++
+
+Routine Description:
+
+ This routine jumps through the hoops necessary to open the file
+ for READ_DATA|WRITE_DATA even if the file has the READONLY
+ attribute set.
+
+Arguments:
+
+ ptcFile - Specifies the file that should be opened.
+
+Return Value:
+
+ A handle open on the file if successfull, INVALID_HANDLE_VALUE
+ otherwise, in which case the caller may use GetLastError() for more
+ info.
+
+--*/
+{
+ BY_HANDLE_FILE_INFORMATION fi;
+ HANDLE hRet;
+ HANDLE h;
+ INT err;
+
+ hRet = CreateFile(
+ ptcFile,
+ FILE_READ_DATA | FILE_WRITE_DATA,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ NULL
+ );
+
+ if (INVALID_HANDLE_VALUE != hRet) {
+ return hRet;
+ }
+
+ if (ERROR_ACCESS_DENIED != GetLastError()) {
+ return INVALID_HANDLE_VALUE;
+ }
+
+ err = GetLastError();
+
+ h = CreateFile(
+ ptcFile,
+ FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ NULL
+ );
+
+ if (INVALID_HANDLE_VALUE == h) {
+ return INVALID_HANDLE_VALUE;
+ }
+
+ if (!GetFileInformationByHandle(h, &fi)) {
+ CloseHandle(h);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ if ((fi.dwFileAttributes & FILE_ATTRIBUTE_READONLY) == 0) {
+
+ // If we couldn't open the file for some reason other than that
+ // the readonly attribute was set, fail.
+
+ SetLastError(err);
+ CloseHandle(h);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ fi.dwFileAttributes &= ~FILE_ATTRIBUTE_READONLY;
+
+ if (!SetFileAttributes(ptcFile, fi.dwFileAttributes)) {
+ CloseHandle(h);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ hRet = CreateFile(
+ ptcFile,
+ FILE_READ_DATA | FILE_WRITE_DATA,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ NULL
+ );
+
+ CloseHandle(h);
+
+ if (INVALID_HANDLE_VALUE == hRet) {
+ return INVALID_HANDLE_VALUE;
+ }
+
+ fi.dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
+
+ if (!SetFileAttributes(ptcFile, fi.dwFileAttributes)) {
+ CloseHandle(hRet);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ return hRet;
+}
+
+//
+// Now do the routines to list the compression state and size of
+// a file and/or directory
+//
+
+BOOLEAN
+DisplayFile (
+ IN PTCHAR FileSpec,
+ IN PWIN32_FIND_DATA FindData
+ )
+{
+ LARGE_INTEGER FileSize;
+ LARGE_INTEGER CompressedSize;
+ TCHAR PrintState;
+
+ ULONG Percentage = 100;
+ double Ratio = 1.0;
+
+ FileSize.LowPart = FindData->nFileSizeLow;
+ FileSize.HighPart = FindData->nFileSizeHigh;
+ PrintState = ' ';
+
+ //
+ // Decide if the file is compressed and if so then
+ // get the compressed file size.
+ //
+
+ if (FindData->dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) {
+
+ CompressedSize.LowPart = GetCompressedFileSize( FileSpec,
+ &CompressedSize.HighPart );
+ PrintState = 'C';
+ TotalCompressedFileCount.QuadPart += 1;
+
+ } else {
+
+ CompressedSize.LowPart = GetCompressedFileSize( FileSpec,
+ &CompressedSize.HighPart );
+
+ if (GetLastError() == 0 &&
+ CompressedSize.QuadPart != 0 &&
+ CompressedSize.QuadPart < FileSize.QuadPart) {
+
+ // File on DblSpace partition.
+
+ PrintState = 'd';
+ TotalCompressedFileCount.QuadPart += 1;
+
+ } else {
+
+ CompressedSize = FileSize;
+ TotalUncompressedFileCount.QuadPart += 1;
+ }
+ }
+
+
+ //
+ // Calculate the compression ratio for this file
+ //
+
+ if (CompressedSize.QuadPart != 0) {
+
+ if (CompressedSize.QuadPart > FileSize.QuadPart) {
+
+ //
+ // The file probably grew between the time we got its size
+ // and the time we got its compressed size. Kludge.
+ //
+
+ FileSize.QuadPart = CompressedSize.QuadPart;
+ }
+
+ Ratio = (double)FileSize.QuadPart / (double)CompressedSize.QuadPart;
+ }
+
+ //
+ // Print out the sizes compression state and file name
+ //
+
+ if (!Quiet &&
+ (DisplayAllFiles ||
+ (0 == (FindData->dwFileAttributes & AttributesNoDisplay)))) {
+
+ FormatFileSize(&FileSize, 9, Buf, FALSE);
+ lstrcat(Buf, TEXT(" : "));
+ FormatFileSize(&CompressedSize, 9, &Buf[lstrlen(Buf)], FALSE);
+
+ swprintf(&Buf[lstrlen(Buf)], TEXT(" = %2.1lf "), Ratio);
+ DisplayMsg(COMPACT_THROW, Buf);
+
+ DisplayMsg(COMPACT_TO_ONE);
+
+ swprintf(Buf, TEXT("%c %s",), PrintState, FindData->cFileName);
+ DisplayMsg(COMPACT_THROW_NL, Buf);
+ }
+
+ //
+ // Increment our running total
+ //
+
+ TotalFileSize.QuadPart += FileSize.QuadPart;
+ TotalCompressedSize.QuadPart += CompressedSize.QuadPart;
+ TotalFileCount.QuadPart += 1;
+
+ return TRUE;
+}
+
+
+BOOLEAN
+DoListAction (
+ IN PTCHAR DirectorySpec,
+ IN PTCHAR FileSpec
+ )
+
+{
+ PTCHAR DirectorySpecEnd;
+
+ //
+ // So that we can keep on appending names to the directory spec
+ // get a pointer to the end of its string
+ //
+
+ DirectorySpecEnd = DirectorySpec + lstrlen(DirectorySpec);
+
+ //
+ // List the compression attribute for the directory
+ //
+
+ {
+ ULONG Attributes;
+
+ if (!Quiet || Quiet) {
+
+ Attributes = GetFileAttributes( DirectorySpec );
+
+ if (0xFFFFFFFF == Attributes) {
+
+ if (!Quiet || !IgnoreErrors) {
+
+ //
+ // Refrain from displaying error only when in quiet
+ // mode *and* we're ignoring errors.
+ //
+
+ DisplayErr(DirectorySpec, GetLastError());
+ }
+
+ if (!IgnoreErrors) {
+ return FALSE;
+ }
+ } else {
+
+ if (Attributes & FILE_ATTRIBUTE_COMPRESSED) {
+ DisplayMsg(COMPACT_LIST_CDIR, DirectorySpec);
+ } else {
+ DisplayMsg(COMPACT_LIST_UDIR, DirectorySpec);
+ }
+ }
+ }
+
+ TotalDirectoryCount.QuadPart += 1;
+ }
+
+ //
+ // Now for every file in the directory that matches the file spec we will
+ // will open the file and list its compression state
+ //
+
+ {
+ HANDLE FindHandle;
+ WIN32_FIND_DATA FindData;
+
+ //
+ // setup the template for findfirst/findnext
+ //
+
+ //
+ // Make sure we don't try any paths that are too long for us
+ // to deal with.
+ //
+
+ if (((DirectorySpecEnd - DirectorySpec) + lstrlen( FileSpec )) <
+ MAX_PATH) {
+
+ lstrcpy( DirectorySpecEnd, FileSpec );
+
+ FindHandle = FindFirstFile( DirectorySpec, &FindData );
+
+ if (INVALID_HANDLE_VALUE != FindHandle) {
+
+ do {
+
+ //
+ // append the found file to the directory spec and open the
+ // file
+ //
+
+ if (0 == lstrcmp(FindData.cFileName, TEXT("..")) ||
+ 0 == lstrcmp(FindData.cFileName, TEXT("."))) {
+ continue;
+ }
+
+ //
+ // Make sure we don't try any paths that are too long for us
+ // to deal with.
+ //
+
+ if ((DirectorySpecEnd - DirectorySpec) +
+ lstrlen( FindData.cFileName ) >= MAX_PATH ) {
+
+ continue;
+ }
+
+ lstrcpy( DirectorySpecEnd, FindData.cFileName );
+
+ //
+ // Now print out the state of the file
+ //
+
+ DisplayFile( DirectorySpec, &FindData );
+
+ } while ( FindNextFile( FindHandle, &FindData ));
+
+ FindClose( FindHandle );
+ }
+ }
+ }
+
+ //
+ // For if we are to do subdirectores then we will look for every
+ // subdirectory and recursively call ourselves to list the subdirectory
+ //
+
+ if (DoSubdirectories) {
+
+ HANDLE FindHandle;
+
+ WIN32_FIND_DATA FindData;
+
+ //
+ // Setup findfirst/findnext to search the entire directory
+ //
+
+ if (((DirectorySpecEnd - DirectorySpec) + lstrlen( TEXT("*") )) <
+ MAX_PATH) {
+
+ lstrcpy( DirectorySpecEnd, TEXT("*") );
+
+ FindHandle = FindFirstFile( DirectorySpec, &FindData );
+
+ if (INVALID_HANDLE_VALUE != FindHandle) {
+
+ do {
+
+ //
+ // Now skip over the . and .. entries otherwise we'll recurse
+ // like mad
+ //
+
+ if (0 == lstrcmp(&FindData.cFileName[0], TEXT(".")) ||
+ 0 == lstrcmp(&FindData.cFileName[0], TEXT(".."))) {
+
+ continue;
+
+ } else {
+
+ //
+ // If the entry is for a directory then we'll tack on the
+ // subdirectory name to the directory spec and recursively
+ // call otherselves
+ //
+
+ if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+
+ //
+ // Make sure we don't try any paths that are too long for us
+ // to deal with.
+ //
+
+ if ((DirectorySpecEnd - DirectorySpec) +
+ lstrlen( TEXT("\\") ) +
+ lstrlen( FindData.cFileName ) >= MAX_PATH ) {
+
+ continue;
+ }
+
+ lstrcpy( DirectorySpecEnd, FindData.cFileName );
+ lstrcat( DirectorySpecEnd, TEXT("\\") );
+
+ if (!DoListAction( DirectorySpec, FileSpec )) {
+
+ return FALSE || IgnoreErrors;
+ }
+ }
+ }
+
+ } while ( FindNextFile( FindHandle, &FindData ));
+
+ FindClose( FindHandle );
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+VOID
+DoFinalListAction (
+ )
+{
+ ULONG TotalPercentage = 100;
+ double f = 1.0;
+
+ TCHAR FileCount[32];
+ TCHAR DirectoryCount[32];
+ TCHAR CompressedFileCount[32];
+ TCHAR UncompressedFileCount[32];
+ TCHAR CompressedSize[32];
+ TCHAR FileSize[32];
+ TCHAR Percentage[10];
+ TCHAR Ratio[8];
+
+ if (TotalCompressedSize.QuadPart != 0) {
+ f = (double)TotalFileSize.QuadPart /
+ (double)TotalCompressedSize.QuadPart;
+ }
+
+ FormatFileSize(&TotalFileCount, 0, FileCount, FALSE);
+ FormatFileSize(&TotalDirectoryCount, 0, DirectoryCount, FALSE);
+ FormatFileSize(&TotalCompressedFileCount, 0, CompressedFileCount, FALSE);
+ FormatFileSize(&TotalUncompressedFileCount, 0, UncompressedFileCount, FALSE);
+ FormatFileSize(&TotalCompressedSize, 0, CompressedSize, TRUE);
+ FormatFileSize(&TotalFileSize, 0, FileSize, TRUE);
+
+ swprintf(Percentage, TEXT("%d"), TotalPercentage);
+ swprintf(Ratio, TEXT("%2.1lf"), f);
+
+ DisplayMsg(COMPACT_LIST_SUMMARY, FileCount, DirectoryCount,
+ CompressedFileCount, UncompressedFileCount,
+ FileSize, CompressedSize,
+ Ratio );
+
+ return;
+}
+
+
+BOOLEAN
+CompressFile (
+ IN HANDLE Handle,
+ IN PTCHAR FileSpec,
+ IN PWIN32_FIND_DATA FindData
+ )
+
+{
+ USHORT State = 1;
+ ULONG Length;
+ ULONG i;
+ BOOLEAN Success;
+ double f = 1.0;
+
+ if ((FindData->dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) &&
+ !ForceOperation) {
+
+ return TRUE;
+ }
+
+ Success = DeviceIoControl(Handle, FSCTL_SET_COMPRESSION, &State,
+ sizeof(USHORT), NULL, 0, &Length, FALSE );
+
+ if (!Success) {
+
+ if (Quiet && IgnoreErrors) {
+ return FALSE || IgnoreErrors;
+ }
+
+ swprintf(Buf, TEXT("%s "), FindData->cFileName);
+ DisplayMsg(COMPACT_THROW, Buf);
+
+ for (i = lstrlen(FindData->cFileName) + 1; i < FIRST_COLUMN_WIDTH; ++i) {
+ swprintf(Buf, TEXT("%c"), ' ');
+ DisplayMsg(COMPACT_THROW, Buf);
+ }
+
+ DisplayMsg(COMPACT_ERR);
+
+ if (!Quiet && !IgnoreErrors) {
+ if (ERROR_INVALID_FUNCTION == GetLastError()) {
+
+ // This error is caused by doing the fsctl on a
+ // non-compressing volume.
+
+ DisplayMsg(COMPACT_WRONG_FILE_SYSTEM, FindData->cFileName);
+
+ } else {
+ DisplayErr(FindData->cFileName, GetLastError());
+ }
+ }
+
+ return FALSE || IgnoreErrors;
+ }
+
+ if (!Quiet &&
+ (DisplayAllFiles ||
+ (0 == (FindData->dwFileAttributes & AttributesNoDisplay)))) {
+ swprintf(Buf, TEXT("%s "), FindData->cFileName);
+ DisplayMsg(COMPACT_THROW, Buf);
+
+ for (i = lstrlen(FindData->cFileName) + 1; i < FIRST_COLUMN_WIDTH; ++i) {
+ swprintf(Buf, TEXT("%c"), ' ');
+ DisplayMsg(COMPACT_THROW, Buf);
+ }
+ }
+
+
+ //
+ // Gather statistics and increment our running total
+ //
+
+ {
+ LARGE_INTEGER FileSize;
+ LARGE_INTEGER CompressedSize;
+ ULONG Percentage = 100;
+
+ FileSize.LowPart = FindData->nFileSizeLow;
+ FileSize.HighPart = FindData->nFileSizeHigh;
+
+ CompressedSize.LowPart = GetCompressedFileSize( FileSpec,
+ &CompressedSize.HighPart );
+
+ //
+ // This statement to prevent confusion from the case where the
+ // compressed file had been 0 size, but has grown since the filesize
+ // was examined.
+ //
+
+ if (0 == FileSize.QuadPart) {
+ CompressedSize.QuadPart = 0;
+ }
+
+ if (CompressedSize.QuadPart != 0) {
+
+ f = (double)FileSize.QuadPart / (double)CompressedSize.QuadPart;
+ }
+
+ //
+ // Print out the sizes compression state and file name
+ //
+
+ if (!Quiet &&
+ (DisplayAllFiles ||
+ (0 == (FindData->dwFileAttributes & AttributesNoDisplay)))) {
+
+ FormatFileSize(&FileSize, 9, Buf, FALSE);
+ lstrcat(Buf, TEXT(" : "));
+ FormatFileSize(&CompressedSize, 9, &Buf[lstrlen(Buf)], FALSE);
+
+ swprintf(&Buf[lstrlen(Buf)], TEXT(" = %2.1lf "), f);
+
+ DisplayMsg(COMPACT_THROW, Buf);
+
+ DisplayMsg(COMPACT_TO_ONE);
+ DisplayMsg(COMPACT_OK);
+ }
+
+ //
+ // Increment our running total
+ //
+
+ TotalFileSize.QuadPart += FileSize.QuadPart;
+ TotalCompressedSize.QuadPart += CompressedSize.QuadPart;
+ TotalFileCount.QuadPart += 1;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+DoCompressAction (
+ IN PTCHAR DirectorySpec,
+ IN PTCHAR FileSpec
+ )
+
+{
+ PTCHAR DirectorySpecEnd;
+
+ //
+ // If the file spec is null then we'll set the compression bit for the
+ // the directory spec and get out.
+ //
+
+ if (lstrlen(FileSpec) == 0) {
+
+ HANDLE FileHandle;
+ USHORT State = 1;
+ ULONG Length;
+
+ FileHandle = OpenFileForCompress(DirectorySpec);
+
+ if (INVALID_HANDLE_VALUE == FileHandle) {
+
+ DisplayErr(DirectorySpec, GetLastError());
+ return FALSE || IgnoreErrors;
+ }
+
+ DisplayMsg(COMPACT_COMPRESS_DIR, DirectorySpec);
+
+ if (!DeviceIoControl(FileHandle, FSCTL_SET_COMPRESSION, &State,
+ sizeof(USHORT), NULL, 0, &Length, FALSE )) {
+
+ if (!Quiet || !IgnoreErrors) {
+ DisplayMsg(COMPACT_ERR);
+ }
+ if (!Quiet && !IgnoreErrors) {
+ DisplayErr(DirectorySpec, GetLastError());
+ }
+ CloseHandle( FileHandle );
+ return FALSE || IgnoreErrors;
+ }
+
+ if (!Quiet) {
+ DisplayMsg(COMPACT_OK);
+ }
+
+ CloseHandle( FileHandle );
+
+ TotalDirectoryCount.QuadPart += 1;
+ TotalFileCount.QuadPart += 1;
+
+ return TRUE;
+ }
+
+ //
+ // So that we can keep on appending names to the directory spec
+ // get a pointer to the end of its string
+ //
+
+ DirectorySpecEnd = DirectorySpec + lstrlen( DirectorySpec );
+
+ //
+ // List the directory that we will be compressing within and say what its
+ // current compress attribute is
+ //
+
+ {
+ ULONG Attributes;
+
+ if (!Quiet || Quiet) {
+
+ Attributes = GetFileAttributes( DirectorySpec );
+
+ if (Attributes & FILE_ATTRIBUTE_COMPRESSED) {
+
+ DisplayMsg(COMPACT_COMPRESS_CDIR, DirectorySpec);
+
+ } else {
+
+ DisplayMsg(COMPACT_COMPRESS_UDIR, DirectorySpec);
+
+ }
+ }
+
+ TotalDirectoryCount.QuadPart += 1;
+ }
+
+ //
+ // Now for every file in the directory that matches the file spec we will
+ // will open the file and compress it
+ //
+
+ {
+ HANDLE FindHandle;
+ HANDLE FileHandle;
+
+ WIN32_FIND_DATA FindData;
+
+ //
+ // setup the template for findfirst/findnext
+ //
+
+ if (((DirectorySpecEnd - DirectorySpec) + lstrlen( FileSpec )) <
+ MAX_PATH) {
+
+ lstrcpy( DirectorySpecEnd, FileSpec );
+
+ FindHandle = FindFirstFile( DirectorySpec, &FindData );
+
+ if (INVALID_HANDLE_VALUE != FindHandle) {
+
+ do {
+
+ //
+ // Now skip over the . and .. entries
+ //
+
+ if (0 == lstrcmp(&FindData.cFileName[0], TEXT(".")) ||
+ 0 == lstrcmp(&FindData.cFileName[0], TEXT(".."))) {
+
+ continue;
+
+ } else {
+
+ //
+ // Make sure we don't try any paths that are too long for us
+ // to deal with.
+ //
+
+ if ( (DirectorySpecEnd - DirectorySpec) +
+ lstrlen( FindData.cFileName ) >= MAX_PATH ) {
+
+ continue;
+ }
+
+ //
+ // append the found file to the directory spec and open
+ // the file
+ //
+
+
+ lstrcpy( DirectorySpecEnd, FindData.cFileName );
+
+ //
+ // Hack hack, kludge kludge. Refrain from compressing
+ // files named "\NTDLR" to help users avoid hosing
+ // themselves.
+ //
+
+ if (IsNtldr(DirectorySpec)) {
+
+ if (!Quiet) {
+ DisplayMsg(COMPACT_SKIPPING, DirectorySpecEnd);
+ }
+
+ continue;
+ }
+
+ FileHandle = OpenFileForCompress(DirectorySpec);
+
+ if (INVALID_HANDLE_VALUE == FileHandle) {
+
+ if (!Quiet || !IgnoreErrors) {
+ DisplayErr(FindData.cFileName, GetLastError());
+ }
+
+ if (!IgnoreErrors) {
+ return FALSE;
+ }
+ continue;
+ }
+
+ //
+ // Now compress the file
+ //
+
+ if (!CompressFile( FileHandle, DirectorySpec, &FindData )) {
+ return FALSE || IgnoreErrors;
+ }
+
+ //
+ // Close the file and go get the next file
+ //
+
+ CloseHandle( FileHandle );
+ }
+
+ } while ( FindNextFile( FindHandle, &FindData ));
+
+ FindClose( FindHandle );
+ }
+ }
+ }
+
+ //
+ // If we are to do subdirectores then we will look for every subdirectory
+ // and recursively call ourselves to list the subdirectory
+ //
+
+ if (DoSubdirectories) {
+
+ HANDLE FindHandle;
+
+ WIN32_FIND_DATA FindData;
+
+ //
+ // Setup findfirst/findnext to search the entire directory
+ //
+
+ if (((DirectorySpecEnd - DirectorySpec) + lstrlen( TEXT("*") )) <
+ MAX_PATH) {
+
+ lstrcpy( DirectorySpecEnd, TEXT("*") );
+
+ FindHandle = FindFirstFile( DirectorySpec, &FindData );
+
+ if (INVALID_HANDLE_VALUE != FindHandle) {
+
+ do {
+
+ //
+ // Now skip over the . and .. entries otherwise we'll recurse
+ // like mad
+ //
+
+ if (0 == lstrcmp(&FindData.cFileName[0], TEXT(".")) ||
+ 0 == lstrcmp(&FindData.cFileName[0], TEXT(".."))) {
+
+ continue;
+
+ } else {
+
+ //
+ // If the entry is for a directory then we'll tack on the
+ // subdirectory name to the directory spec and recursively
+ // call otherselves
+ //
+
+ if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+
+ //
+ // Make sure we don't try any paths that are too long for us
+ // to deal with.
+ //
+
+ if ((DirectorySpecEnd - DirectorySpec) +
+ lstrlen( TEXT("\\") ) +
+ lstrlen( FindData.cFileName ) >= MAX_PATH ) {
+
+ continue;
+ }
+
+ lstrcpy( DirectorySpecEnd, FindData.cFileName );
+ lstrcat( DirectorySpecEnd, TEXT("\\") );
+
+ if (!DoCompressAction( DirectorySpec, FileSpec )) {
+ return FALSE || IgnoreErrors;
+ }
+ }
+ }
+
+ } while ( FindNextFile( FindHandle, &FindData ));
+
+ FindClose( FindHandle );
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+VOID
+DoFinalCompressAction (
+ )
+{
+ ULONG TotalPercentage = 100;
+ double f = 1.0;
+
+ TCHAR FileCount[32];
+ TCHAR DirectoryCount[32];
+ TCHAR CompressedSize[32];
+ TCHAR FileSize[32];
+ TCHAR Percentage[32];
+ TCHAR Ratio[8];
+
+ if (TotalCompressedSize.QuadPart != 0) {
+ f = (double)TotalFileSize.QuadPart /
+ (double)TotalCompressedSize.QuadPart;
+ }
+
+ FormatFileSize(&TotalFileCount, 0, FileCount, FALSE);
+ FormatFileSize(&TotalDirectoryCount, 0, DirectoryCount, FALSE);
+ FormatFileSize(&TotalCompressedSize, 0, CompressedSize, TRUE);
+ FormatFileSize(&TotalFileSize, 0, FileSize, TRUE);
+
+ swprintf(Percentage, TEXT("%d"), TotalPercentage);
+ swprintf(Ratio, TEXT("%2.1f"), f);
+
+ DisplayMsg(COMPACT_COMPRESS_SUMMARY, FileCount, DirectoryCount,
+ FileSize, CompressedSize, Ratio );
+
+}
+
+
+BOOLEAN
+UncompressFile (
+ IN HANDLE Handle,
+ IN PWIN32_FIND_DATA FindData
+ )
+{
+ USHORT State = 0;
+ ULONG Length;
+
+ if (!(FindData->dwFileAttributes & FILE_ATTRIBUTE_COMPRESSED) &&
+ !ForceOperation) {
+
+ return TRUE;
+ }
+
+ if (!DeviceIoControl(Handle, FSCTL_SET_COMPRESSION, &State,
+ sizeof(USHORT), NULL, 0, &Length, FALSE )) {
+
+ if (!Quiet || !IgnoreErrors) {
+
+ swprintf(Buf, TEXT("%s "), FindData->cFileName);
+ DisplayMsg(COMPACT_THROW, Buf);
+
+ DisplayMsg(COMPACT_ERR);
+
+ if (!Quiet && !IgnoreErrors) {
+
+ if (ERROR_INVALID_FUNCTION == GetLastError()) {
+
+ // This error is caused by doing the fsctl on a
+ // non-compressing volume.
+
+ DisplayMsg(COMPACT_WRONG_FILE_SYSTEM, FindData->cFileName);
+
+ } else {
+ DisplayErr(FindData->cFileName, GetLastError());
+ }
+ }
+ }
+ return FALSE || IgnoreErrors;
+ }
+
+ if (!Quiet &&
+ (DisplayAllFiles ||
+ (0 == (FindData->dwFileAttributes & AttributesNoDisplay)))) {
+ swprintf(Buf, TEXT("%s "), FindData->cFileName);
+ DisplayMsg(COMPACT_THROW, Buf);
+
+ DisplayMsg(COMPACT_OK);
+ }
+
+ //
+ // Increment our running total
+ //
+
+ TotalFileCount.QuadPart += 1;
+
+ return TRUE;
+}
+
+BOOLEAN
+DoUncompressAction (
+ IN PTCHAR DirectorySpec,
+ IN PTCHAR FileSpec
+ )
+
+{
+ PTCHAR DirectorySpecEnd;
+
+ //
+ // If the file spec is null then we'll clear the compression bit for the
+ // the directory spec and get out.
+ //
+
+ if (lstrlen(FileSpec) == 0) {
+
+ HANDLE FileHandle;
+ USHORT State = 0;
+ ULONG Length;
+
+ FileHandle = OpenFileForCompress(DirectorySpec);
+
+ if (INVALID_HANDLE_VALUE == FileHandle) {
+
+ if (!Quiet || !IgnoreErrors) {
+ DisplayErr(DirectorySpec, GetLastError());
+ }
+ return FALSE || IgnoreErrors;
+ }
+
+ DisplayMsg(COMPACT_UNCOMPRESS_DIR, DirectorySpec);
+
+ if (!DeviceIoControl(FileHandle, FSCTL_SET_COMPRESSION, &State,
+ sizeof(USHORT), NULL, 0, &Length, FALSE )) {
+
+ if (!Quiet || !IgnoreErrors) {
+ DisplayMsg(COMPACT_ERR);
+
+ }
+ if (!Quiet && !IgnoreErrors) {
+ DisplayErr(DirectorySpec, GetLastError());
+ }
+
+ return FALSE || IgnoreErrors;
+ }
+
+ if (!Quiet) {
+ DisplayMsg(COMPACT_OK);
+ }
+
+ CloseHandle( FileHandle );
+
+ TotalDirectoryCount.QuadPart += 1;
+ TotalFileCount.QuadPart += 1;
+
+ return TRUE;
+ }
+
+ //
+ // So that we can keep on appending names to the directory spec
+ // get a pointer to the end of its string
+ //
+
+ DirectorySpecEnd = DirectorySpec + lstrlen( DirectorySpec );
+
+ //
+ // List the directory that we will be uncompressing within and say what its
+ // current compress attribute is
+ //
+
+ {
+ ULONG Attributes;
+
+ if (!Quiet || Quiet) {
+
+ Attributes = GetFileAttributes( DirectorySpec );
+
+ if (Attributes & FILE_ATTRIBUTE_COMPRESSED) {
+
+ DisplayMsg(COMPACT_UNCOMPRESS_CDIR, DirectorySpec);
+
+ } else {
+
+ DisplayMsg(COMPACT_UNCOMPRESS_UDIR, DirectorySpec);
+ }
+ }
+
+ TotalDirectoryCount.QuadPart += 1;
+ }
+
+ //
+ // Now for every file in the directory that matches the file spec we will
+ // will open the file and uncompress it
+ //
+
+ {
+ HANDLE FindHandle;
+ HANDLE FileHandle;
+
+ WIN32_FIND_DATA FindData;
+
+ //
+ // setup the template for findfirst/findnext
+ //
+
+ if (((DirectorySpecEnd - DirectorySpec) + lstrlen( FileSpec )) <
+ MAX_PATH) {
+
+ lstrcpy( DirectorySpecEnd, FileSpec );
+
+ FindHandle = FindFirstFile( DirectorySpec, &FindData );
+
+ if (INVALID_HANDLE_VALUE != FindHandle) {
+
+ do {
+
+ //
+ // Now skip over the . and .. entries
+ //
+
+ if (0 == lstrcmp(&FindData.cFileName[0], TEXT(".")) ||
+ 0 == lstrcmp(&FindData.cFileName[0], TEXT(".."))) {
+
+ continue;
+
+ } else {
+
+ //
+ // Make sure we don't try any paths that are too long for us
+ // to deal with.
+ //
+
+ if ((DirectorySpecEnd - DirectorySpec) +
+ lstrlen( FindData.cFileName ) >= MAX_PATH ) {
+
+ continue;
+ }
+
+ //
+ // append the found file to the directory spec and open
+ // the file
+ //
+
+ lstrcpy( DirectorySpecEnd, FindData.cFileName );
+
+ FileHandle = OpenFileForCompress(DirectorySpec);
+
+ if (INVALID_HANDLE_VALUE == FileHandle) {
+
+ if (!Quiet || !IgnoreErrors) {
+ DisplayErr(DirectorySpec, GetLastError());
+ }
+
+ if (!IgnoreErrors) {
+ return FALSE;
+ }
+ continue;
+ }
+
+ //
+ // Now compress the file
+ //
+
+ if (!UncompressFile( FileHandle, &FindData )) {
+ return FALSE || IgnoreErrors;
+ }
+
+ //
+ // Close the file and go get the next file
+ //
+
+ CloseHandle( FileHandle );
+ }
+
+ } while ( FindNextFile( FindHandle, &FindData ));
+
+ FindClose( FindHandle );
+ }
+ }
+ }
+
+ //
+ // If we are to do subdirectores then we will look for every subdirectory
+ // and recursively call ourselves to list the subdirectory
+ //
+
+ if (DoSubdirectories) {
+
+ HANDLE FindHandle;
+
+ WIN32_FIND_DATA FindData;
+
+ //
+ // Setup findfirst/findnext to search the entire directory
+ //
+
+ if (((DirectorySpecEnd - DirectorySpec) + lstrlen( TEXT("*") )) <
+ MAX_PATH) {
+
+ lstrcpy( DirectorySpecEnd, TEXT("*") );
+
+ FindHandle = FindFirstFile( DirectorySpec, &FindData );
+ if (INVALID_HANDLE_VALUE != FindHandle) {
+
+ do {
+
+ //
+ // Now skip over the . and .. entries otherwise we'll recurse
+ // like mad
+ //
+
+ if (0 == lstrcmp(&FindData.cFileName[0], TEXT(".")) ||
+ 0 == lstrcmp(&FindData.cFileName[0], TEXT(".."))) {
+
+ continue;
+
+ } else {
+
+ //
+ // If the entry is for a directory then we'll tack on the
+ // subdirectory name to the directory spec and recursively
+ // call otherselves
+ //
+
+ if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+
+ //
+ // Make sure we don't try any paths that are too long for us
+ // to deal with.
+ //
+
+ if ((DirectorySpecEnd - DirectorySpec) +
+ lstrlen( TEXT("\\") ) +
+ lstrlen( FindData.cFileName ) >= MAX_PATH ) {
+
+ continue;
+ }
+
+ lstrcpy( DirectorySpecEnd, FindData.cFileName );
+ lstrcat( DirectorySpecEnd, TEXT("\\") );
+
+ if (!DoUncompressAction( DirectorySpec, FileSpec )) {
+ return FALSE || IgnoreErrors;
+ }
+ }
+ }
+
+ } while ( FindNextFile( FindHandle, &FindData ));
+
+ FindClose( FindHandle );
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+VOID
+DoFinalUncompressAction (
+ )
+
+{
+ TCHAR FileCount[32];
+ TCHAR DirectoryCount[32];
+
+ FormatFileSize(&TotalFileCount, 0, FileCount, FALSE);
+ FormatFileSize(&TotalDirectoryCount, 0, DirectoryCount, FALSE);
+
+ DisplayMsg(COMPACT_UNCOMPRESS_SUMMARY, FileCount, DirectoryCount);
+
+ return;
+}
+
+
+VOID
+__cdecl
+main()
+{
+ PTCHAR *argv;
+ ULONG argc;
+
+ ULONG i;
+
+ PACTION_ROUTINE ActionRoutine = NULL;
+ PFINAL_ACTION_ROUTINE FinalActionRoutine = NULL;
+
+ BOOLEAN UserSpecifiedFileSpec = FALSE;
+
+ TCHAR DirectorySpec[MAX_PATH];
+ TCHAR FileSpec[MAX_PATH];
+ PTCHAR p;
+
+ InitializeIoStreams();
+
+ argv = CommandLineToArgvW(GetCommandLine(), &argc);
+ if (NULL == argv) {
+ DisplayErr(NULL, GetLastError());
+ return;
+ }
+
+ //
+ // Scan through the arguments looking for switches
+ //
+
+ for (i = 1; i < argc; i += 1) {
+
+ if (argv[i][0] == '/') {
+
+ if (0 == lstricmp(argv[i], TEXT("/c"))) {
+
+ if (ActionRoutine != NULL &&
+ ActionRoutine != DoCompressAction) {
+
+ DisplayMsg(COMPACT_USAGE, NULL);
+ return;
+ }
+
+ ActionRoutine = DoCompressAction;
+ FinalActionRoutine = DoFinalCompressAction;
+
+ } else if (0 == lstricmp(argv[i], TEXT("/u"))) {
+
+ if (ActionRoutine != NULL && ActionRoutine != DoListAction) {
+
+ DisplayMsg(COMPACT_USAGE, NULL);
+ return;
+ }
+
+ ActionRoutine = DoUncompressAction;
+ FinalActionRoutine = DoFinalUncompressAction;
+
+ } else if (0 == lstricmp(argv[i], TEXT("/q"))) {
+
+ Quiet = TRUE;
+
+ } else if (0 == lstrnicmp(argv[i], TEXT("/s"), 2)) {
+
+ PTCHAR pch;
+
+ DoSubdirectories = TRUE;
+
+ pch = lstrchr(argv[i], ':');
+ if (NULL != pch) {
+ lstrcpy(StartingDirectory, pch + 1);
+ } else if (2 == lstrlen(argv[i])) {
+
+ // Starting dir is CWD
+
+ GetCurrentDirectory( MAX_PATH, StartingDirectory );
+
+ } else {
+ DisplayMsg(COMPACT_USAGE, NULL);
+ return;
+ }
+
+ } else if (0 == lstricmp(argv[i], TEXT("/i"))) {
+
+ IgnoreErrors = TRUE;
+
+ } else if (0 == lstricmp(argv[i], TEXT("/f"))) {
+
+ ForceOperation = TRUE;
+
+ } else if (0 == lstricmp(argv[i], TEXT("/a"))) {
+
+ DisplayAllFiles = TRUE;
+
+ } else {
+
+ DisplayMsg(COMPACT_USAGE, NULL);
+ return;
+ }
+
+ } else {
+
+ UserSpecifiedFileSpec = TRUE;
+ }
+ }
+
+ //
+ // If the use didn't specify an action then set the default to do a listing
+ //
+
+ if (ActionRoutine == NULL) {
+
+ ActionRoutine = DoListAction;
+ FinalActionRoutine = DoFinalListAction;
+ }
+
+ //
+ // Get our current directoy because the action routines might move us
+ // around
+ //
+
+ if (!DoSubdirectories) {
+ GetCurrentDirectory( MAX_PATH, StartingDirectory );
+ } else if (!SetCurrentDirectory( StartingDirectory )) {
+ DisplayErr(StartingDirectory, GetLastError());
+ return;
+ }
+
+ //
+ // If the user didn't specify a file spec then we'll do just "*"
+ //
+
+ if (!UserSpecifiedFileSpec) {
+
+ (VOID)GetFullPathName( TEXT("*"), MAX_PATH, DirectorySpec, &p );
+
+ lstrcpy( FileSpec, p ); *p = '\0';
+
+ //
+ // Also want to make "compact /c" set the bit for the current
+ // directory.
+ //
+
+ if (ActionRoutine != DoListAction) {
+
+ (VOID)(ActionRoutine)( DirectorySpec, TEXT("") );
+ }
+
+ (VOID)(ActionRoutine)( DirectorySpec, FileSpec );
+
+ } else {
+
+ //
+ // Now scan the arguments again looking for non-switches
+ // and this time do the action, but before calling reset
+ // the current directory so that things work again
+ //
+
+ for (i = 1; i < argc; i += 1) {
+
+ if (argv[i][0] != '/') {
+
+ SetCurrentDirectory( StartingDirectory );
+
+ //
+ // Handle a command with "." as the file argument specially,
+ // since it doesn't make good sense and the results without
+ // this code are surprising.
+ //
+
+ if ('.' == argv[i][0] && '\0' == argv[i][1]) {
+ argv[i] = TEXT("*");
+ GetFullPathName(argv[i], MAX_PATH, DirectorySpec, &p);
+ *p = '\0';
+ p = NULL;
+ } else {
+
+ PWCHAR pwch;
+
+ GetFullPathName(argv[i], MAX_PATH, DirectorySpec, &p);
+
+ //
+ // We want to treat "foobie:xxx" as an invalid drive name,
+ // rather than as a name identifying a stream. If there's
+ // a colon, there should be only a single character before
+ // it.
+ //
+
+ pwch = wcschr(argv[i], ':');
+ if (NULL != pwch && pwch - argv[i] != 1) {
+ DisplayMsg(COMPACT_INVALID_PATH, argv[i]);
+ break;
+ }
+
+ //
+ // GetFullPathName strips trailing dots, but we want
+ // to save them so that "*." will work correctly.
+ //
+
+ if ('.' == argv[i][lstrlen(argv[i]) - 1]) {
+ lstrcat(DirectorySpec, TEXT("."));
+ }
+ }
+
+ if (IsUncRoot(DirectorySpec)) {
+
+ //
+ // If the path is like \\server\share, we append an
+ // additional slash to make things come out right.
+ //
+
+ lstrcat(DirectorySpec, TEXT("\\"));
+ p = NULL;
+ }
+
+
+ if (p != NULL) {
+ lstrcpy( FileSpec, p ); *p = '\0';
+ } else {
+ FileSpec[0] = '\0';
+ }
+
+ if (!(ActionRoutine)( DirectorySpec, FileSpec ) &&
+ !IgnoreErrors) {
+ break;
+ }
+ }
+ }
+ }
+
+ //
+ // Reset our current directory back
+ //
+
+ SetCurrentDirectory( StartingDirectory );
+
+ //
+ // And do the final action routine that will print out the final
+ // statistics of what we've done
+ //
+
+ (FinalActionRoutine)();
+}
diff --git a/private/utils/compact/compact.rc b/private/utils/compact/compact.rc
new file mode 100644
index 000000000..5a0bedf96
--- /dev/null
+++ b/private/utils/compact/compact.rc
@@ -0,0 +1,13 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "File Compress Utility"
+#define VER_INTERNALNAME_STR "compact\0"
+#define VER_ORIGINALFILENAME_STR "COMPACT.EXE"
+
+#include "common.ver"
+
+#include "msg.rc"
+ \ No newline at end of file
diff --git a/private/utils/compact/makefile b/private/utils/compact/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/compact/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/compact/makefile.inc b/private/utils/compact/makefile.inc
new file mode 100644
index 000000000..2623021db
--- /dev/null
+++ b/private/utils/compact/makefile.inc
@@ -0,0 +1,4 @@
+msg.h msg.rc msg00001.bin: msg.mc
+ mc -v msg.mc
+
+$(NTTARGETFILE0): msg.rc msg.h msg00001.bin
diff --git a/private/utils/compact/msg.mc b/private/utils/compact/msg.mc
new file mode 100644
index 000000000..d83e7f493
--- /dev/null
+++ b/private/utils/compact/msg.mc
@@ -0,0 +1,180 @@
+;/*++ BUILD Version: 0001 // Increment this if a change has global effects
+;
+;Copyright (c) 1994-1995 Microsoft Corporation
+;
+;Module Name:
+;
+; msg.h
+;
+;Abstract:
+;
+; This file contains the message definitions for the Win32 Compact
+; utility.
+;
+;Author:
+;
+; Gary Kimura [garyki] 13-Jan-1994
+;
+;Revision History:
+;
+;--*/
+;
+
+MessageId=0001 SymbolicName=COMPACT_OK
+Language=English
+[OK]
+.
+
+MessageId=0002 SymbolicName=COMPACT_ERR
+Language=English
+[ERR]
+.
+
+MessageId=0006 SymbolicName=COMPACT_LIST_CDIR
+Language=English
+
+ Listing %1
+ New files added to this directory will be compressed.
+
+.
+
+MessageId=0007 SymbolicName=COMPACT_LIST_UDIR
+Language=English
+
+ Listing %1
+ New files added to this directory will not be compressed.
+
+.
+
+MessageId=0008 SymbolicName=COMPACT_LIST_SUMMARY
+Language=English
+
+Of %1 files within %2 directories
+%3 are compressed and %4 are not compressed.
+%5 total bytes of data are stored in %6 bytes.
+The compression ratio is %7 to 1.
+
+.
+
+MessageId=0009 SymbolicName=COMPACT_COMPRESS_DIR
+Language=English
+
+ Setting the directory %1 to compress new files %0
+
+.
+
+MessageId=0010 SymbolicName=COMPACT_COMPRESS_CDIR
+Language=English
+
+ Compressing files in %1
+
+.
+
+MessageId=0011 SymbolicName=COMPACT_COMPRESS_UDIR
+Language=English
+
+ Compressing files in %1
+
+.
+
+MessageId=0012 SymbolicName=COMPACT_COMPRESS_SUMMARY
+Language=English
+
+%1 files within %2 directories were compressed.
+%3 total bytes of data are stored in %4 bytes.
+The compression ratio is %5 to 1.
+.
+
+
+MessageId=0013 SymbolicName=COMPACT_UNCOMPRESS_DIR
+Language=English
+
+ Setting the directory %1 not to compress new files %0
+
+.
+
+MessageId=0014 SymbolicName=COMPACT_UNCOMPRESS_CDIR
+Language=English
+
+ Uncompressing files in %1
+
+.
+
+MessageId=0015 SymbolicName=COMPACT_UNCOMPRESS_UDIR
+Language=English
+
+ Uncompressing files in %1
+
+.
+
+MessageId=0016 SymbolicName=COMPACT_UNCOMPRESS_SUMMARY
+Language=English
+
+%1 files within %2 directories were uncompressed.
+
+.
+
+MessageId=0019 SymbolicName=COMPACT_NO_MEMORY
+Language=English
+Out of memory.
+.
+
+MessageId=0020 SymbolicName=COMPACT_SKIPPING
+Language=English
+[Skipping %1]
+.
+
+MessageId=0021 SymbolicName=COMPACT_THROW
+Language=English
+%1%0
+.
+
+MessageId=0022 SymbolicName=COMPACT_THROW_NL
+Language=English
+%1
+.
+
+MessageId=0023 SymbolicName=COMPACT_WRONG_FILE_SYSTEM
+Language=English
+%1: The file system does not support compression.
+.
+
+MessageId=0024 SymbolicName=COMPACT_TO_ONE
+Language=English
+to 1 %0
+.
+
+MessageId=0025 SymbolicName=COMPACT_INVALID_PATH
+Language=English
+Invalid drive specification: %1
+.
+
+MessageId=0050 SymbolicName=COMPACT_USAGE
+Language=English
+Displays or alters the compression of files on NTFS partitions.
+
+COMPACT [/C | /U] [/S[:dir]] [/A] [/I] [/F] [/Q] [filename [...]]
+
+ /C Compresses the specified files. Directories will be marked
+ so that files added afterward will be compressed.
+ /U Uncompresses the specified files. Directories will be marked
+ so that files added afterward will not be compressed.
+ /S Performs the specified operation on files in the given
+ directory and all subdirectories. Default "dir" is the
+ current directory.
+ /A Displays files with the hidden or system attributes. These
+ files are omitted by default.
+ /I Continues performing the specified operation even after errors
+ have occurred. By default, COMPACT stops when an error is
+ encountered.
+ /F Forces the compress operation on all specified files, even
+ those which are already compressed. Already-compressed files
+ are skipped by default.
+ /Q Reports only the most essential information.
+ filename Specifies a pattern, file, or directory.
+
+ Used without parameters, COMPACT displays the compression state of
+ the current directory and any files it contains. You may use multiple
+ filenames and wildcards. You must put spaces between multiple
+ parameters.
+.
diff --git a/private/utils/compact/sdk/compact.rc b/private/utils/compact/sdk/compact.rc
new file mode 100644
index 000000000..a7d628ac0
--- /dev/null
+++ b/private/utils/compact/sdk/compact.rc
@@ -0,0 +1,3 @@
+#include <windows.h>
+
+#include "msg.rc"
diff --git a/private/utils/compact/sdk/makefile b/private/utils/compact/sdk/makefile
new file mode 100644
index 000000000..5455af159
--- /dev/null
+++ b/private/utils/compact/sdk/makefile
@@ -0,0 +1,24 @@
+
+TARGETOS=WINNT
+APPVER=3.51
+
+!include <ntwin32.mak>
+
+all: compact.exe
+
+msg.h msg.rc msg00001.bin: msg.mc
+ mc -v msg.mc
+
+compact.res: compact.rc msg.rc
+ rc -r -fo compact.res compact.rc
+
+compact.obj: compact.c msg.h
+ $(cc) $(cflags) $(cdebug) $(cvars) compact.c
+
+support.obj: support.c
+ $(cc) $(cflags) $(cdebug) $(cvars) support.c
+
+compact.exe: compact.obj support.obj msg.h msg.rc msg00001.bin compact.res
+ $(link) $(ldebug) $(conflags) -out:compact.exe \
+ compact.obj support.obj compact.res \
+ $(conlibs) shell32.lib user32.lib
diff --git a/private/utils/compact/sdk/readme.txt b/private/utils/compact/sdk/readme.txt
new file mode 100644
index 000000000..6cdfc4a27
--- /dev/null
+++ b/private/utils/compact/sdk/readme.txt
@@ -0,0 +1,24 @@
+Display and Alter the Compression of Files or Directories
+
+
+The COMPACT tool compresses files on an NTFS drive.
+
+Usage:
+
+COMPACT [/C | /U] [/S[:dir]] [/A] [/I] [/Q] [filename [...]]
+
+/C Compresses the specified directory or file.
+/U Uncompress the specified directory or file.
+/S Performs the specified operation on matching files in the
+ given directory and all subdirectories. Default "dir" is
+ the current directory.
+/A Do not ignore hidden or system files.
+/I Ignore errors.
+/F Force the operation to compress or uncompress the
+ specified directory or file.
+/Q Be less verbose.
+filename Specifies a pattern, file, or directory.
+
+When used without parameters, COMPACT displays the compression state of the
+current directory. You may use multiple filenames and wildcards.
+
diff --git a/private/utils/compact/sources b/private/utils/compact/sources
new file mode 100644
index 000000000..fa89a00af
--- /dev/null
+++ b/private/utils/compact/sources
@@ -0,0 +1,45 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=sdktools
+MINORCOMP=compact
+
+TARGETNAME=compact
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+SOURCES= \
+ compact.rc \
+ support.c \
+ compact.c \
+ msg.mc
+
+PASS0_HEADERDIR=.
+PASS0_SOURCEDIR=.
+
+UMTYPE=console
+
+UMLIBS= $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\shell32.lib \
+ $(BASEDIR)\public\sdk\lib\*\binmode.obj
diff --git a/private/utils/compact/support.c b/private/utils/compact/support.c
new file mode 100644
index 000000000..ac098fe69
--- /dev/null
+++ b/private/utils/compact/support.c
@@ -0,0 +1,352 @@
+/*++
+
+Copyright (c) 1994-1995 Microsoft Corporation
+
+Module Name:
+
+ Support.c
+
+Abstract:
+
+ Support routines for compact utility
+
+Author:
+
+ Matthew Bradburn [mattbr] 05-Oct-1994
+
+Revision History:
+
+
+--*/
+
+#define UNICODE
+#define _UNICODE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <io.h>
+#include <windows.h>
+#include "support.h"
+#include "msg.h"
+
+
+
+//
+// Declare routines to put out internationalized messages
+//
+
+typedef enum {
+ READ_ACCESS,
+ WRITE_ACCESS
+} STREAMACCESS;
+
+HANDLE
+GetStandardStream(
+ IN HANDLE Handle,
+ IN STREAMACCESS Access
+ );
+
+HANDLE hInput;
+HANDLE hOutput;
+HANDLE hError;
+
+#define STDIN 0
+#define STDOUT 1
+#define STDERR 2
+
+BOOL ConsoleInput;
+BOOL ConsoleOutput;
+BOOL ConsoleError;
+
+int
+FileIsConsole(int fh)
+{
+ unsigned htype;
+ DWORD dwMode;
+ HANDLE hFile;
+
+ hFile = (HANDLE)_get_osfhandle(fh);
+ htype = GetFileType(hFile);
+ htype &= ~FILE_TYPE_REMOTE;
+
+ if (FILE_TYPE_CHAR == htype) {
+
+ switch (fh) {
+ case STDIN:
+ hFile = GetStdHandle(STD_INPUT_HANDLE);
+ break;
+ case STDOUT:
+ hFile = GetStdHandle(STD_OUTPUT_HANDLE);
+ break;
+ case STDERR:
+ hFile = GetStdHandle(STD_ERROR_HANDLE);
+ break;
+ }
+
+ if (GetConsoleMode(hFile, &dwMode)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+
+}
+
+
+VOID
+InitializeIoStreams()
+{
+ hInput = GetStdHandle(STD_INPUT_HANDLE);
+ ConsoleInput = FileIsConsole(STDIN);
+
+ hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
+ ConsoleOutput = FileIsConsole(STDOUT);
+
+ hError = GetStdHandle(STD_ERROR_HANDLE);
+ ConsoleError = FileIsConsole(STDERR);
+}
+
+TCHAR DisplayBuffer[4096];
+CHAR DisplayBuffer2[4096];
+
+VOID
+DisplayMsg(DWORD MsgNum, ... )
+{
+ DWORD len, bytes_written;
+ BOOL success;
+ DWORD status;
+ va_list ap;
+
+ va_start(ap, MsgNum);
+
+ len = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE, NULL, MsgNum, 0,
+ DisplayBuffer, 4096, &ap);
+
+ if (ConsoleOutput) {
+ success = WriteConsole(hOutput, (LPVOID)DisplayBuffer, len,
+ &bytes_written, NULL);
+
+ } else {
+ CharToOem(DisplayBuffer, DisplayBuffer2);
+ success = WriteFile(hOutput, (LPVOID)DisplayBuffer2, len,
+ &bytes_written, NULL);
+ }
+
+ if (!success || bytes_written != len) {
+ status = GetLastError();
+ }
+
+ va_end(ap);
+}
+
+VOID
+DisplayErr(
+ PTCHAR Prefix,
+ DWORD MsgNum,
+ ...
+ )
+{
+ DWORD len, bytes_written;
+ BOOL success;
+ DWORD status;
+ va_list ap;
+ ULONG i;
+
+ va_start(ap, MsgNum);
+
+ if (NULL != Prefix) {
+ lstrcpy(DisplayBuffer, Prefix);
+ lstrcat(DisplayBuffer, TEXT(": "));
+ } else {
+ DisplayBuffer[0] = UNICODE_NULL;
+ }
+
+ i = lstrlen(DisplayBuffer);
+
+ len = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, MsgNum, 0,
+ DisplayBuffer + i, 4096 - i, &ap);
+
+ if (ConsoleError) {
+ success = WriteConsole(hError, (LPVOID)DisplayBuffer, len + i,
+ &bytes_written, NULL);
+
+ } else {
+ CharToOem(DisplayBuffer, DisplayBuffer2);
+ success = WriteFile(hError, (LPVOID)DisplayBuffer2, len + i,
+ &bytes_written, NULL);
+ }
+
+ if (!success) {
+ status = GetLastError();
+ }
+ va_end(ap);
+}
+
+BOOLEAN
+IsNtldr(
+ PTCHAR Path
+ )
+/*++
+
+Routine Description:
+
+ Used to keep the user from compressing \NTLDR (which would prevent
+ the machine from booting).
+
+Arguments:
+
+ Path - the path to examine.
+
+Return Value:
+
+ TRUE - the path looks like \ntldr.
+ FALSE - the path does not look like \ntldr.
+
+--*/
+{
+ PTCHAR pch;
+
+ // try "X:\ntldr"
+
+ if (0 == lstricmp(Path + 2, TEXT("\\ntldr"))) {
+ return TRUE;
+ }
+
+ // try "\\machine\share\ntldr"
+
+ if ('\\' == Path[0] && '\\' != Path[1]) {
+ pch = lstrchr(Path + 2, '\\');
+ if (NULL == pch) {
+ return FALSE;
+ }
+ pch = lstrchr(pch + 1, '\\');
+ if (NULL == pch) {
+ return FALSE;
+ }
+ if (0 == lstricmp(pch, TEXT("\\ntldr"))) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+BOOLEAN
+IsUncRoot(
+ PTCHAR Path
+ )
+/*++
+
+Routine Description:
+
+ Determine whether the given path is of the form \\server\share.
+
+Arguments:
+
+ Path - the path to examine.
+
+Return Value:
+
+ TRUE - the path looks like a unc share name.
+ FALSE - the path does not look like that.
+
+--*/
+{
+ PTCHAR pch;
+
+ if ('\\' != *Path || '\\' != *(Path + 1)) {
+ return FALSE;
+ }
+
+ pch = lstrchr(Path + 2, '\\');
+ if (NULL == pch) {
+ //
+ // There is no slash to seperate server and share.
+ //
+
+ return FALSE;
+ }
+
+ pch = lstrchr(pch + 1, '\\');
+ if (NULL != pch) {
+ //
+ // There are additional component -- no match.
+ //
+
+ return FALSE;
+ }
+
+ if ('\\' == *(Path + lstrlen(Path))) {
+
+ //
+ // The string ends in slash -- it doesn't match.
+ //
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+ULONG
+FormatFileSize(
+ IN PLARGE_INTEGER FileSize,
+ IN DWORD Width,
+ OUT PTCHAR FormattedSize,
+ IN BOOLEAN Commas
+ )
+{
+ TCHAR Buffer[100];
+ PTCHAR s, s1;
+ ULONG DigitIndex, Digit;
+ ULONG Size;
+ LARGE_INTEGER TempSize;
+
+ s = &Buffer[ 99 ];
+ *s = TEXT('\0');
+ DigitIndex = 0;
+ TempSize = *FileSize;
+ while (TempSize.HighPart != 0) {
+ if (TempSize.HighPart != 0) {
+ Digit = (ULONG)(TempSize.QuadPart % 10);
+ TempSize.QuadPart = TempSize.QuadPart / 10;
+ } else {
+ Digit = TempSize.LowPart % 10;
+ TempSize.LowPart = TempSize.LowPart / 10;
+ }
+ *--s = (TCHAR)(TEXT('0') + Digit);
+
+ if ((++DigitIndex % 3) == 0 && Commas) {
+ *--s = TEXT(',');
+ }
+ }
+ Size = TempSize.LowPart;
+ while (Size != 0) {
+ *--s = (TCHAR)(TEXT('0') + (Size % 10));
+ Size = Size / 10;
+
+ if ((++DigitIndex % 3) == 0 && Commas) {
+ *--s = TEXT(',');
+ }
+ }
+
+ if (DigitIndex == 0) {
+ *--s = TEXT('0');
+ } else if (Commas && *s == TEXT(',')) {
+ s += 1;
+ }
+
+ Size = lstrlen( s );
+ if (Width != 0 && Size < Width) {
+ s1 = FormattedSize;
+ while (Width > Size) {
+ Width -= 1;
+ *s1++ = TEXT(' ');
+ }
+ lstrcpy( s1, s );
+ } else {
+ lstrcpy( FormattedSize, s );
+ }
+
+ return lstrlen( FormattedSize );
+}
diff --git a/private/utils/compact/support.h b/private/utils/compact/support.h
new file mode 100644
index 000000000..b257e2258
--- /dev/null
+++ b/private/utils/compact/support.h
@@ -0,0 +1,57 @@
+/*++
+
+Copyright (c) 1994-1995 Microsoft Corporation
+
+Module Name:
+
+ Support.h
+
+Abstract:
+
+ Support routine interfaces
+
+Author:
+
+ Matthew Bradburn [mattbr] 05-Oct-1994
+
+Revision History:
+
+
+--*/
+
+extern VOID
+ArrangeCommandLine(
+ PTCHAR **pargv,
+ int *pargc
+ );
+
+extern BOOLEAN
+IsNtldr(
+ PTCHAR pch
+ );
+
+extern BOOLEAN
+IsUncRoot(
+ PTCHAR pch
+ );
+
+extern VOID
+DisplayMsg(DWORD MsgNum, ... );
+
+extern VOID
+DisplayErr(PTCHAR Prefix, DWORD MsgNum, ... );
+
+extern VOID
+InitializeIoStreams();
+
+#define lstrchr wcschr
+#define lstricmp _wcsicmp
+#define lstrnicmp _wcsnicmp
+
+extern ULONG
+FormatFileSize(
+ IN PLARGE_INTEGER FileSize,
+ IN DWORD Width,
+ OUT PTCHAR FormattedSize,
+ IN BOOLEAN WithCommas
+ );
diff --git a/private/utils/convert/convert.cxx b/private/utils/convert/convert.cxx
new file mode 100644
index 000000000..104eb8dbe
--- /dev/null
+++ b/private/utils/convert/convert.cxx
@@ -0,0 +1,1307 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ convert.cxx
+
+Abstract:
+
+ This module contains the definition of the CONVERT class, which
+ implements the File System Conversion Utility.
+
+Author:
+
+ Ramon J. San Andres (ramonsa) sep-23-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+
+#define _NTAPI_ULIB_
+#include "ulib.hxx"
+#include "ulibcl.hxx"
+#include "error.hxx"
+#include "arg.hxx"
+#include "file.hxx"
+#include "smsg.hxx"
+#include "rtmsg.h"
+#include "wstring.hxx"
+#include "system.hxx"
+#include "autoreg.hxx"
+#include "ifssys.hxx"
+#include "ifsentry.hxx"
+#include "convert.hxx"
+
+extern "C" {
+#include <stdio.h>
+}
+
+#include "fatofs.hxx"
+
+ERRSTACK* perrstk;
+
+
+#define AUTOCHK_PROGRAM_NAME L"AUTOCHK.EXE"
+#define AUTOCONV_PROGRAM_NAME L"AUTOCONV.EXE"
+
+#define AUTOCHK_NAME L"AUTOCHK"
+#define AUTOCONV_NAME L"AUTOCONV"
+
+#define VALUE_NAME_PATH L"PATH"
+#define VALUE_NAME_ARGS L"ARGUMENTS"
+#define VALUE_NAME_FS L"TARGET FILESYSTEM"
+
+//
+// Scheduling status codes
+//
+#define CONV_STATUS_NONE 0
+#define CONV_STATUS_SCHEDULED 1
+
+static WCHAR NameBuffer[16]; // holds cvf name
+
+
+
+INT _CRTAPI1
+main (
+ )
+
+/*++
+
+Routine Description:
+
+ Entry point for the conversion utility.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ One of the CONVERT exit codes.
+
+Notes:
+
+--*/
+
+{
+
+ INT ExitCode = EXIT_ERROR; // Let's be pessimistic
+
+ DEFINE_CLASS_DESCRIPTOR( CONVERT );
+
+ {
+ CONVERT Convert;
+
+ //
+ // Initialize the CONVERT object.
+ //
+ if ( Convert.Initialize( &ExitCode ) ) {
+
+ //
+ // Do the conversion
+ //
+ ExitCode = Convert.Convert();
+ }
+ }
+
+ return ExitCode;
+}
+
+
+
+DEFINE_CONSTRUCTOR( CONVERT, PROGRAM );
+
+
+NONVIRTUAL
+VOID
+CONVERT::Construct (
+ )
+/*++
+
+Routine Description:
+
+ converts a CONVERT object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+{
+ _Autochk = NULL;
+ _Autoconv = NULL;
+}
+
+
+
+NONVIRTUAL
+VOID
+CONVERT::Destroy (
+ )
+/*++
+
+Routine Description:
+
+ Destroys a CONVERT object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+{
+ DELETE( _Autochk );
+ DELETE( _Autoconv );
+}
+
+
+
+
+CONVERT::~CONVERT (
+ )
+
+/*++
+
+Routine Description:
+
+ Destructs a CONVERT object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ Destroy();
+}
+
+
+
+
+BOOLEAN
+CONVERT::Initialize (
+ OUT PINT ExitCode
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes the CONVERT object. Initialization consist of allocating memory
+ for certain object members and argument parsing.
+
+Arguments:
+
+ ExitCode - Supplies pointer to CONVERT exit code.
+
+Return Value:
+
+ BOOLEAN - TRUE if initialization succeeded, FALSE otherwise.
+
+Notes:
+
+--*/
+
+{
+ Destroy();
+
+ //
+ // Initialize program object
+ //
+ if ( PROGRAM::Initialize( MSG_CONV_USAGE ) ) {
+
+ //
+ // Parse the arguments
+ //
+ return ParseArguments( ExitCode );
+ }
+
+ //
+ // Could not initialize the program object.
+ //
+ *ExitCode = EXIT_ERROR;
+ return FALSE;
+}
+
+BOOLEAN IsRestartFatToOfs( WSTRING const & CurrentFsName,
+ WSTRING const & NtDriveName )
+/*++
+
+Routine Description:
+
+ Checks if a FAT->OFS convert is being restarted because of a failure
+ after the Phase1. So, the currrent file system will be OFS but it is not
+ fully converted/
+
+Arguments:
+
+ CurrentFsName - Name of the current file system
+ NtDriveName - NtStyle name of the drive to check.
+
+Return Value:
+
+ BOOLEAN - TRUE if it is a restart of FAT->OFS. FALSE o/w
+
+History:
+
+ Created Srikants August 24, 1995 (WIN95 launch day!!)
+
+Notes:
+
+--*/
+
+{
+
+ DSTRING libraryName;
+ DSTRING entryPoint;
+ HANDLE fsUtilityHandle;
+
+ DSTRING Ofs;
+ Ofs.Initialize("OFS");
+ if ( 0 != Ofs.Stricmp(&CurrentFsName) ) {
+ return FALSE;
+ }
+
+ libraryName.Initialize( FAT_TO_OFS_DLL_NAME );
+ entryPoint.Initialize( FAT_TO_OFS_RESTART_FUNCTION_NAME );
+
+ FAT_OFS_RESTART_FN IsRestartFatOfs;
+
+ IsRestartFatOfs = (FAT_OFS_RESTART_FN)SYSTEM::QueryLibraryEntryPoint(
+ &libraryName, &entryPoint, &fsUtilityHandle );
+
+ if ( NULL == IsRestartFatOfs )
+ {
+ return FALSE;
+ }
+
+ PWSTR pwszNtDriveName = NtDriveName.QueryWSTR();
+ BOOLEAN fResult= IsRestartFatOfs( pwszNtDriveName );
+
+ DELETE( pwszNtDriveName );
+ SYSTEM::FreeLibraryHandle( fsUtilityHandle );
+
+ return fResult;
+}
+
+
+INT
+CONVERT::Convert (
+ )
+/*++
+
+Routine Description:
+
+ Converts the file system in a volume.
+ Depending on the current file system, it loads the appropriate
+ conversion library and calls its conversion entry point.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ INT - One of the CONVERT return codes
+
+Notes:
+
+
+--*/
+{
+ DSTRING CurrentFsName; // Name of current FS in volume
+ DSTRING LibraryName; // Name of library to load
+ DSTRING EntryPoint; // Name of entry point in DLL
+ FSTRING NameTableFnName; // Name of Name-Table construction fn
+ INT ExitCode = EXIT_SUCCESS; // CONVERT exit code
+ CONVERT_STATUS ConvertStatus; // Conversion status
+ NTSTATUS Status; // NT API status
+ HANDLE FsUtilityHandle; // Handle to DLL
+ HANDLE CuDbfsHandle; // Handle to cudbfs.dll
+ CONVERT_FN Convert; // Pointer to entry point in DLL
+ NAMETABLE_FN ConstructNameTable; // Pointer to entry point in DLL
+ CHECKSPACE_FN CheckSpace; // Pointer to entry point in DLL
+ BOOLEAN ConvertDblsHost = TRUE;
+ BOOLEAN Error = FALSE;
+ BOOLEAN Success;
+ BOOLEAN Result;
+
+ // Check to see if this is an ARC System Partition--if it
+ // is, don't convert it.
+ //
+ if( IFS_SYSTEM::IsArcSystemPartition( &_NtDrive, &Error ) ) {
+
+ DisplayMessage( MSG_CONV_ARC_SYSTEM_PARTITION, ERROR_MESSAGE );
+ return EXIT_ERROR;
+ }
+
+ //
+ // Ask the volume what file system it has, and use that name to
+ // figure out what DLL to load.
+ //
+ if ( !IFS_SYSTEM::QueryFileSystemName( &_NtDrive,
+ &CurrentFsName,
+ &Status )) {
+
+ if ( Status == STATUS_ACCESS_DENIED ) {
+ DisplayMessage( MSG_DASD_ACCESS_DENIED, ERROR_MESSAGE );
+ } else {
+ DisplayMessage( MSG_FS_NOT_DETERMINED, ERROR_MESSAGE, "%W", &_DosDrive );
+ }
+
+ return EXIT_ERROR;
+ }
+
+ // If the source and target file system are the same, there's
+ // nothing to do. But if we're uncompressing, that's not true.
+ //
+
+ if (_Restart) {
+ if ( IsRestartFatToOfs( CurrentFsName, _NtDrive ) ) {
+ CurrentFsName.Initialize("FAT");
+ }
+ else {
+ //XXX.mjb: assume that we're restarting from NTFS to OFS.
+ CurrentFsName.Initialize("NTFS");
+ }
+ }
+
+ if( CurrentFsName.Stricmp( &_FsName ) == 0) {
+#ifdef DBLSPACE_ENABLED
+ if (!_Uncompress) {
+#endif // DBLSPACE_ENABLED
+ DisplayMessage( MSG_CONV_ALREADY_CONVERTED, ERROR_MESSAGE, "%W%W",
+ &_DosDrive, &_FsName );
+ return EXIT_ERROR;
+#ifdef DBLSPACE_ENABLED
+ }
+
+ //
+ // We're uncompressing, and we don't need to convert the
+ // host filesystem.
+ //
+
+ ConvertDblsHost = FALSE;
+#endif // DBLSPACE_ENABLED
+ }
+
+ // Make sure that the target file system is enabled in the
+ // registry.
+ //
+ if( !IFS_SYSTEM::IsFileSystemEnabled( &_FsName ) ) {
+
+ DisplayMessage( MSG_FMT_INSTALL_FILE_SYSTEM, NORMAL_MESSAGE, "%W", &_FsName );
+
+ if( _Message.IsYesResponse(TRUE) ) {
+
+ if( IFS_SYSTEM::EnableFileSystem( &_FsName ) ) {
+
+ DisplayMessage( MSG_FMT_FILE_SYSTEM_INSTALLED );
+
+ } else {
+
+ DisplayMessage( MSG_FMT_CANT_INSTALL_FILE_SYSTEM, ERROR_MESSAGE );
+ return EXIT_ERROR;
+ }
+
+ } else {
+
+ return EXIT_ERROR;
+ }
+ }
+
+#ifdef DBLSPACE_ENABLED
+ if (_Uncompress) {
+ //
+ // Make sure the indicated cvf exists before we try to do
+ // anything.
+ //
+
+ DSTRING CvfPath;
+ DSTRING backslash;
+
+ if (!backslash.Initialize("\\")) {
+ DisplayMessage(MSG_CONV_NO_MEMORY, ERROR_MESSAGE);
+ return EXIT_ERROR;
+ }
+ if (!CvfPath.Initialize(&_DosDrive) ||
+ !CvfPath.Strcat(&backslash) ||
+ !CvfPath.Strcat(&_CvfName)) {
+ DisplayMessage(MSG_CONV_NO_MEMORY, ERROR_MESSAGE);
+ return EXIT_ERROR;
+ }
+ if (0xffffffff == GetFileAttributes(CvfPath.GetWSTR())) {
+ if (ERROR_FILE_NOT_FOUND == GetLastError()) {
+ DisplayMessage(MSG_DBLSPACE_NO_SUCH_FILE, ERROR_MESSAGE,
+ "%W", &CvfPath);
+ return EXIT_ERROR;
+ }
+ }
+ }
+#endif // DBLSPACE_ENABLED
+
+ //
+ // Display the current file system type. (Standard in all file system utilities)
+ //
+ DisplayMessage( MSG_FILE_SYSTEM_TYPE, NORMAL_MESSAGE, "%W", &CurrentFsName );
+
+ if (ConvertDblsHost) {
+
+
+#ifdef DBLSPACE_ENABLED
+
+ if (_Uncompress) {
+ if (!LibraryName.Initialize("CNVDBFS") ||
+ !EntryPoint.Initialize("CheckFreeSpaceDBFS")) {
+ return EXIT_ERROR;
+ }
+ if (NULL == (CheckSpace = (CHECKSPACE_FN)SYSTEM::
+ QueryLibraryEntryPoint(&LibraryName, &EntryPoint,
+ &CuDbfsHandle))) {
+ return EXIT_ERROR;
+ }
+
+ Success = CheckSpace(&_NtDrive, &_CvfName, &_Message, _Verbose,
+ _Compress, /* HostIsCompressed */
+ TRUE /* WillConvertHost */
+ );
+
+ SYSTEM::FreeLibraryHandle( CuDbfsHandle );
+
+ if (!Success) {
+ return EXIT_ERROR;
+ }
+ }
+#endif // DBLSPACE_ENABLED
+
+ //
+ // Depending on the current file system, form the name of the conversion
+ // DLL in charge of converting that file system. The name of the
+ // conversion library is the name of the file system prefixed with "CNV"
+ // eg FAT->CNVFAT, HPFS->CNVHPFS
+ //
+ // We also initialize the name of the conversion entry point in the DLL
+ // ("Convert")
+ //
+ if ( !LibraryName.Initialize( "CNV" ) ||
+ !LibraryName.Strcat( &CurrentFsName ) ||
+ !EntryPoint.Initialize( "Convert" ) ||
+ !EntryPoint.Strcat( &CurrentFsName )
+ ) {
+
+ DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ return( EXIT_ERROR );
+ }
+
+
+ //
+ // Get pointer to the conversion entry point and convert the volume.
+ //
+ if (NULL == (Convert = (CONVERT_FN)SYSTEM::QueryLibraryEntryPoint(
+ &LibraryName, &EntryPoint, &FsUtilityHandle ))) {
+ //
+ // There is no conversion DLL for the file system in the volume.
+ //
+ DisplayMessage( MSG_FS_NOT_SUPPORTED, ERROR_MESSAGE, "%s%W",
+ "CONVERT", &CurrentFsName );
+ DisplayMessage( MSG_BLANK_LINE, ERROR_MESSAGE );
+ return EXIT_ERROR;
+ }
+
+ Result = Convert( &_NtDrive,
+ &_FsName,
+ &_Message,
+ _Verbose,
+ FALSE, /* Pause */
+ &ConvertStatus);
+
+ SYSTEM::FreeLibraryHandle( FsUtilityHandle );
+
+ if( Result ) {
+
+#ifdef DBLSPACE_ENABLED
+ if (!_Uncompress) {
+#endif // DBLSPACE_ENABLED
+ //
+ // We're done.
+ //
+
+ DisplayMessage( MSG_CONV_CONVERSION_COMPLETE, NORMAL_MESSAGE );
+ return EXIT_SUCCESS;
+#ifdef DBLSPACE_ENABLED
+ }
+#endif // DBLSPACE_ENABLED
+
+ } else {
+
+ //
+ // The conversion was not successful. Determine what the problem
+ // was and return the appropriate CONVERT exit code.
+ //
+ switch ( ConvertStatus ) {
+
+ case CONVERT_STATUS_CONVERTED:
+ //
+ // This is an inconsistent state, Convert should return
+ // TRUE if the conversion was successful!
+ //
+ DebugPrintf( "CONVERT Error: Conversion failed, but status is success!\n" );
+ DebugAssert( FALSE );
+ ExitCode = EXIT_ERROR;
+ break;
+
+ case CONVERT_STATUS_INVALID_FILESYSTEM:
+ //
+ // The conversion DLL does not recognize the target file system.
+ //
+ DisplayMessage( MSG_CONV_INVALID_FILESYSTEM, ERROR_MESSAGE, "%W", &_FsName );
+ ExitCode = EXIT_UNKNOWN;
+ break;
+
+ case CONVERT_STATUS_CONVERSION_NOT_AVAILABLE:
+ //
+ // The target file system is valid, but the conversion is not
+ // available.
+ //
+ DisplayMessage( MSG_CONV_CONVERSION_NOT_AVAILABLE, ERROR_MESSAGE,
+ "%W%W", &CurrentFsName, &_FsName );
+ ExitCode = EXIT_NOCANDO;
+ break;
+
+ case CONVERT_STATUS_CANNOT_LOCK_DRIVE:
+ //
+ // The drive cannot be locked. We must schedule ChkDsk and AutoConv
+ // to do the job during the next system boot.
+ //
+
+ if( _NameTable.QueryChCount() ) {
+
+ NameTableFnName.Initialize( L"ConstructNameTable" );
+
+ ConstructNameTable = (NAMETABLE_FN)
+ SYSTEM::QueryLibraryEntryPoint( &LibraryName,
+ &NameTableFnName,
+ &FsUtilityHandle );
+
+ if( ConstructNameTable == NULL ) {
+
+ DisplayMessage( MSG_CONV_NAME_TABLE_NOT_SUPPORTED,
+ ERROR_MESSAGE,
+ "%W",
+ &_FsName );
+
+ } else {
+
+ ConstructNameTable( &_NtDrive, &_NameTable, &_Message );
+ }
+ }
+
+ DisplayMessage( MSG_CONVERT_ON_REBOOT_PROMPT, NORMAL_MESSAGE, "%W",
+ &_DosDrive );
+
+ // Note that ScheduleAutoConv reports its success or
+ // failure, so no additional messages are required.
+ //
+ if( _Message.IsYesResponse( FALSE ) &&
+ ScheduleAutoConv() ) {
+
+#ifdef DBLSPACE_ENABLED
+ if (_Uncompress) {
+ DisplayMessage(MSG_DBLCONV_AGAIN, NORMAL_MESSAGE);
+ }
+#endif
+
+ ExitCode = EXIT_SCHEDULED;
+
+ } else {
+
+ ExitCode = EXIT_ERROR;
+ }
+
+ break;
+
+ case CONVERT_STATUS_ERROR:
+ //
+ // The conversion failed.
+ //
+ DisplayMessage( MSG_CONV_CONVERSION_FAILED, ERROR_MESSAGE,
+ "%W%W", &_DosDrive, &_FsName );
+ ExitCode = EXIT_ERROR;
+ break;
+
+ default:
+ //
+ // Invalid status code
+ //
+ DebugPrintf( "CONVERT Error: Convert status code %X invalid!\n",
+ ConvertStatus );
+ DisplayMessage( MSG_CONV_CONVERSION_FAILED, ERROR_MESSAGE,
+ "%W%W", &_DosDrive, &_FsName );
+ ExitCode = EXIT_ERROR;
+ break;
+ }
+
+ return ExitCode;
+ }
+ }
+
+#ifdef DBLSPACE_ENABLED
+ //
+ // Uncompress the cvf named by _CvfName.
+ //
+
+ if (!LibraryName.Initialize("CNVDBFS") ||
+ !EntryPoint.Initialize("CheckFreeSpaceDBFS")) {
+ return EXIT_ERROR;
+ }
+
+ if (_Compress) {
+ //
+ // Indicate that the files we're about to create should
+ // be compressed.
+ //
+
+ if (!IFS_SYSTEM::EnableVolumeCompression(&_NtDrive)) {
+ return EXIT_ERROR;
+ }
+ }
+
+ if (!ConvertDblsHost) {
+
+ if (NULL == (CheckSpace = (CHECKSPACE_FN)SYSTEM::QueryLibraryEntryPoint(
+ &LibraryName, &EntryPoint, &CuDbfsHandle))) {
+ return EXIT_ERROR;
+ }
+
+ Success = CheckSpace(&_NtDrive, &_CvfName, &_Message, _Verbose,
+ FALSE, /* HostIsCompressed */
+ TRUE /* WillConvertHost */
+ );
+
+ SYSTEM::FreeLibraryHandle( CuDbfsHandle );
+
+ if (!Success) {
+ return EXIT_ERROR;
+ }
+ }
+
+ if (!EntryPoint.Initialize("ConvertDBFS")) {
+ return EXIT_ERROR;
+ }
+
+ if (NULL == (Convert = (CONVERT_FN)SYSTEM::QueryLibraryEntryPoint(
+ &LibraryName, &EntryPoint, &CuDbfsHandle))) {
+
+ return EXIT_ERROR;
+ }
+
+ DisplayMessage( MSG_DBLSPACE_UNCOMPRESSING, NORMAL_MESSAGE );
+
+ if (Convert(&_NtDrive, &_CvfName, &_Message, _Verbose,
+ &ConvertStatus)) {
+ ExitCode = EXIT_SUCCESS;
+ } else {
+
+ if (CONVERT_STATUS_INSUFFICIENT_SPACE == ConvertStatus) {
+ DisplayMessage( MSG_DBLCONV_SPACE_EXHAUSTED, ERROR_MESSAGE );
+ }
+
+ ExitCode = EXIT_ERROR;
+ }
+ SYSTEM::FreeLibraryHandle( CuDbfsHandle );
+
+ DisplayMessage( MSG_CONV_CONVERSION_COMPLETE, NORMAL_MESSAGE );
+
+#endif // DBLSPACE_ENABLED
+ return ExitCode;
+
+}
+
+
+PPATH
+CONVERT::FindSystemFile(
+ IN PWSTR FileName
+ )
+
+/*++
+
+Routine Description:
+
+ Makes sure that the given file is in the system directory.
+
+Arguments:
+
+ FileName - Supplies the name of the file to look for.
+
+Return Value:
+
+ PPATH - Path to the file found
+
+--*/
+
+{
+
+
+ DSTRING Name;
+ PPATH Path = NULL;
+ PFSN_FILE File = NULL;
+
+
+ if ( !(Path = SYSTEM::QuerySystemDirectory() ) ) {
+
+ DisplayMessage( MSG_CONV_CANNOT_FIND_SYSTEM_DIR, ERROR_MESSAGE );
+ return FALSE;
+
+ }
+
+ if ( !Name.Initialize( FileName ) ||
+ !Path->AppendBase( &Name ) ) {
+
+ DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ DELETE( Path );
+ return FALSE;
+ }
+
+
+ if ( !(File = SYSTEM::QueryFile( Path )) ) {
+ DisplayMessage( MSG_CONV_CANNOT_FIND_FILE, ERROR_MESSAGE, "%W", Path->GetPathString() );
+ DELETE( Path );
+ return FALSE;
+ }
+
+ DELETE( File );
+
+ return Path;
+}
+
+
+
+
+
+BOOLEAN
+CONVERT::ParseArguments(
+ OUT PINT ExitCode
+ )
+
+/*++
+
+Routine Description:
+
+ Parses the command line and sets the parameters used by the conversion
+ utility.
+
+ The arguments accepted are:
+
+ drive: Drive to convert
+ /fs:fsname File system to convert to
+ /v Verbose mode
+ /uncompress uncompress a cvf after converting
+ /c Compress the resulting filesystem
+ /? Help
+ /NAMETABLE:filename Filename for name translation table.
+
+
+Arguments:
+
+ ExitCode - Supplies pointer to CONVERT exit code
+
+Return Value:
+
+ BOOLEAN - TRUE if arguments were parsed correctly and program can
+ continue.
+ FALSE if the program should exit. ExitCode contains the
+ value with which the program should exit. Note that this
+ does not necessarily means an error (e.g. user requested
+ help).
+
+--*/
+
+{
+
+ DSTRING Colon;
+ UCHAR SequenceNumber;
+
+ DebugPtrAssert( ExitCode );
+
+ //
+ // Parse command line
+ //
+ if ( !Colon.Initialize( (LPWSTR)L":" ) ||
+ !ParseCommandLine( NULL, TRUE ) ) {
+
+ *ExitCode = EXIT_ERROR;
+ return FALSE;
+ }
+
+ //
+ // If the user requested help, give it.
+ //
+ if( _Help ) {
+ DisplayMessage( MSG_CONV_USAGE );
+ *ExitCode = EXIT_SUCCESS;
+ return FALSE;
+ }
+
+
+#ifdef DBLSPACE_ENABLED
+ if (_Compress && !_Uncompress) {
+ //
+ // We don't allow you to specify /c (compress resulting
+ // filesystem) unless the source filesystem has dblspace.
+ //
+
+ DisplayMessage(MSG_CONV_SLASH_C_INVALID, ERROR_MESSAGE);
+ *ExitCode = EXIT_ERROR;
+ return FALSE;
+ }
+#endif // DBLSPACE_ENABLED
+
+ //
+ // If the command line did not specify a drive, we use the
+ // current drive.
+ //
+ if ( _DosDrive.QueryChCount() > 0 ) {
+
+ if ( !_DosDrive.Strcat( &Colon ) ||
+ !_DosDrive.Strupr()) {
+ DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ *ExitCode = EXIT_ERROR;
+ return FALSE;
+ }
+
+ } else {
+
+ if ( !SYSTEM::QueryCurrentDosDriveName( &_DosDrive ) ) {
+
+ DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ *ExitCode = EXIT_ERROR;
+ return FALSE;
+ }
+ }
+
+ //
+ // Make sure that drive is valid and is not remote.
+ //
+ switch ( SYSTEM::QueryDriveType( &_DosDrive ) ) {
+
+ case UnknownDrive:
+ DisplayMessage( MSG_CONV_INVALID_DRIVE, ERROR_MESSAGE, "%W", &_DosDrive );
+ *ExitCode = EXIT_ERROR;
+ return FALSE;
+
+ case RemoteDrive:
+ DisplayMessage( MSG_CONV_CANT_NETWORK, ERROR_MESSAGE );
+ *ExitCode = EXIT_ERROR;
+ return FALSE;
+
+ default:
+ break;
+
+ }
+
+ //
+ // Make sure a target file system was specified. Note that we do not
+ // validate the file system, we accept any string.
+ //
+ if ( _FsName.QueryChCount() == 0 ) {
+ DisplayMessage( MSG_CONV_NO_FILESYSTEM_SPECIFIED, ERROR_MESSAGE );
+ *ExitCode = EXIT_ERROR;
+ return FALSE;
+ }
+
+
+
+ //
+ // Set other object members.
+ //
+ if ( !IFS_SYSTEM::DosDriveNameToNtDriveName( &_DosDrive, &_NtDrive )) {
+ DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ *ExitCode = EXIT_ERROR;
+ return FALSE;
+ }
+
+#ifdef DBLSPACE_ENABLED
+ //
+ // If we're to uncompress a dblspace volume, generate the cvf name.
+ //
+
+ if (_Uncompress) {
+ swprintf(NameBuffer, L"DBLSPACE.%03d", SequenceNumber);
+
+ if (!_CvfName.Initialize(NameBuffer)) {
+ DisplayMessage(MSG_CONV_NO_MEMORY, ERROR_MESSAGE);
+ *ExitCode = EXIT_ERROR;
+ return FALSE;
+ }
+ }
+#endif // DBLSPACE_ENABLED
+
+ *ExitCode = EXIT_SUCCESS;
+ return TRUE;
+}
+
+
+
+BOOLEAN
+CONVERT::ParseCommandLine (
+ IN PCWSTRING CommandLine,
+ IN BOOLEAN Interactive
+ )
+/*++
+
+Routine Description:
+
+ Parses the CONVERT (AUTOCONV) command line.
+
+ The arguments accepted are:
+
+ drive: Drive to convert
+ /fs:fsname File system to convert to
+ /v Verbose mode
+ /uncompress[:sss] Convert from dblspace
+ /c Compress resulting filesystem
+ /? Help
+ /NAMETABLE:filename Filename for name translation table
+
+Arguments:
+
+ CommandLine - Supplies command line to parse
+ Interactive - Supplies Interactive flag
+
+Return Value:
+
+ BOOLEAN - TRUE if arguments were parsed correctly.
+
+--*/
+
+{
+ ARRAY ArgArray; // Array of arguments
+ ARRAY LexArray; // Array of lexemes
+ ARGUMENT_LEXEMIZER ArgLex; // Argument Lexemizer
+ STRING_ARGUMENT DriveArgument; // Drive argument
+ STRING_ARGUMENT ProgramNameArgument; // Program name argument
+ STRING_ARGUMENT FsNameArgument; // Target FS name argument
+ STRING_ARGUMENT NameTableArgument; // Name Table file name
+ FLAG_ARGUMENT HelpArgument; // Help flag argument
+ FLAG_ARGUMENT VerboseArgument; // Verbose flag argument
+ FLAG_ARGUMENT RestartArgument; // Restart (/r) flag argument
+#ifdef DBLSPACE_ENABLED
+ FLAG_ARGUMENT UncompressArgument; // Uncompress flag argument
+ FLAG_ARGUMENT CompressArgument; // Compress flag argument
+ LONG_ARGUMENT UncompressNumberArgument;// Sequence number argument
+#endif // DBLSPACE_ENABLED
+ PWSTRING InvalidArg; // Invalid argument catcher
+ DSTRING Colon; // Colon
+
+
+ //
+ // Initialize all the argument parsing machinery.
+ //
+ if( !Colon.Initialize( ":" ) ||
+ !ArgArray.Initialize( 7, 1 ) ||
+ !LexArray.Initialize( 7, 1 ) ||
+ !ArgLex.Initialize( &LexArray ) ||
+ !DriveArgument.Initialize( "*:" ) ||
+ !HelpArgument.Initialize( "/?" ) ||
+ !RestartArgument.Initialize( "/R" ) ||
+ !VerboseArgument.Initialize( "/V" ) ||
+#ifdef DBLSPACE_ENABLED
+ !CompressArgument.Initialize( "/C" ) ||
+#endif // DBLSPACE_ENABLED
+ !ProgramNameArgument.Initialize( "*" ) ||
+#ifdef DBLSPACE_ENABLED
+ !UncompressArgument.Initialize( "/UNCOMPRESS" ) ||
+ !UncompressNumberArgument.Initialize( "/UNCOMPRESS:*" ) ||
+#endif // DBLSPACE_ENABLED
+ !FsNameArgument.Initialize( "/FS:*" ) ||
+ !NameTableArgument.Initialize( "/NAMETABLE:*" ) ) {
+
+ if ( Interactive ) {
+ DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ }
+ return FALSE;
+ }
+
+ //
+ // The conversion utility is case-insensitive
+ //
+ ArgLex.SetCaseSensitive( FALSE );
+
+ if( !ArgArray.Put( &DriveArgument ) ||
+ !ArgArray.Put( &HelpArgument ) ||
+ !ArgArray.Put( &VerboseArgument ) ||
+ !ArgArray.Put( &RestartArgument ) ||
+#ifdef DBLSPACE_ENABLED
+ !ArgArray.Put( &CompressArgument ) ||
+#endif // DBLSPACE_ENABLED
+ !ArgArray.Put( &ProgramNameArgument ) ||
+#ifdef DBLSPACE_ENABLED
+ !ArgArray.Put( &UncompressArgument ) ||
+ !ArgArray.Put( &UncompressNumberArgument ) ||
+#endif // DBLSPACE_ENABLED
+ !ArgArray.Put( &FsNameArgument ) ||
+ !ArgArray.Put( &NameTableArgument ) ) {
+
+ if ( Interactive ) {
+ DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ }
+ return FALSE;
+ }
+
+ //
+ // Lexemize the command line.
+ //
+ if ( !ArgLex.PrepareToParse( (PWSTRING)CommandLine ) ) {
+
+ if ( Interactive ) {
+ DisplayMessage( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ }
+ return FALSE;
+ }
+
+ //
+ // Parse the arguments.
+ //
+ if( !ArgLex.DoParsing( &ArgArray ) ) {
+
+ if ( Interactive ) {
+ DisplayMessage( MSG_CONV_INVALID_PARAMETER, ERROR_MESSAGE, "%W", InvalidArg = ArgLex.QueryInvalidArgument() );
+ DELETE( InvalidArg );
+ }
+ return FALSE;
+ }
+
+
+ _Help = HelpArgument.QueryFlag();
+ _Verbose = VerboseArgument.QueryFlag();
+ _Restart = RestartArgument.QueryFlag();
+#ifdef DBLSPACE_ENABLED
+ _Compress = CompressArgument.QueryFlag();
+#endif // DBLSPACE_ENABLED
+
+
+ if ( DriveArgument.IsValueSet() ) {
+ if ( !_DosDrive.Initialize( DriveArgument.GetString() ) ) {
+ return FALSE;
+ }
+
+ } else {
+ if ( !_DosDrive.Initialize( L"" ) ) {
+ return FALSE;
+ }
+ }
+
+ if ( FsNameArgument.IsValueSet() ) {
+ if ( !_FsName.Initialize( FsNameArgument.GetString() ) ) {
+ return FALSE;
+ }
+ } else {
+ if ( !_FsName.Initialize( L"" ) ) {
+ return FALSE;
+ }
+ }
+
+ if( NameTableArgument.IsValueSet() ) {
+
+ if( !_NameTable.Initialize( NameTableArgument.GetString() ) ) {
+
+ return FALSE;
+ }
+
+ } else {
+
+ _NameTable.Initialize( L"" );
+ }
+
+#ifdef DBLSPACE_ENABLED
+ _SequenceNumber = 0;
+
+ _Uncompress = FALSE;
+ if (UncompressArgument.IsValueSet()) {
+ _Uncompress = TRUE;
+ }
+ if (UncompressNumberArgument.IsValueSet()) {
+ _SequenceNumber = (UCHAR)UncompressNumberArgument.QueryLong();
+ _Uncompress = TRUE;
+ }
+#endif // DBLSPACE_ENABLED
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+CONVERT::Schedule (
+ )
+
+/*++
+
+Routine Description:
+
+ Schedules AutoConv
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - TRUE if AutoConv successfully scheduled.
+ FALSE otherwise
+
+--*/
+
+{
+ DSTRING CommandLine;
+ DSTRING Space;
+ DSTRING FileSystem;
+ DSTRING NameTableFlag;
+
+ if( !CommandLine.Initialize( (LPWSTR)L"autocheck autoconv " ) ||
+ !Space.Initialize( (LPWSTR)L" " ) ||
+ !FileSystem.Initialize( (LPWSTR)L"/FS:" ) ||
+ !CommandLine.Strcat( &_NtDrive ) ||
+ !CommandLine.Strcat( &Space ) ||
+ !CommandLine.Strcat( &FileSystem ) ||
+ !CommandLine.Strcat( &_FsName ) ) {
+
+ return FALSE;
+ }
+
+ if( _NameTable.QueryChCount() &&
+ ( !CommandLine.Strcat( &Space ) ||
+ !NameTableFlag.Initialize( L"/NAMETABLE:" ) ||
+ !CommandLine.Strcat( &NameTableFlag ) ||
+ !CommandLine.Strcat( &_NameTable ) ) ) {
+
+ return FALSE;
+ }
+
+ return( AUTOREG::AddEntry( &CommandLine ) );
+}
+
+
+
+BOOLEAN
+CONVERT::ScheduleAutoConv(
+ )
+
+/*++
+
+Routine Description:
+
+ Schedules AutoConv to be invoked during boot the next time
+ that the machine reboots.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ BOOLEAN - TRUE if AutoConv successfully scheduled.
+ FALSE otherwise
+
+--*/
+
+{
+ ARRAY EntryArray;
+ PITERATOR Iterator = NULL;
+ BOOLEAN Ok = TRUE;
+
+
+ //
+ // Make sure that Autochk.exe and Autoconv.exe are in the
+ // right place.
+ //
+ if ( !(_Autochk = FindSystemFile( (LPWSTR)AUTOCHK_PROGRAM_NAME )) ||
+ !(_Autoconv = FindSystemFile( (LPWSTR)AUTOCONV_PROGRAM_NAME )) ) {
+
+ return FALSE;
+ }
+
+ // See if this conversion has already been scheduled:
+ //
+ if ( IsAutoConvScheduled( ) ) {
+
+ DisplayMessage( MSG_CONV_ALREADY_SCHEDULED, ERROR_MESSAGE, "%W", &_DosDrive );
+ return TRUE;
+ }
+
+ //
+ // schedule autoconvert
+ //
+ if ( Ok = Schedule( ) ) {
+ DisplayMessage( MSG_CONV_WILL_CONVERT_ON_REBOOT, NORMAL_MESSAGE, "%W", &_DosDrive );
+ } else {
+ DisplayMessage( MSG_CONV_CANNOT_SCHEDULE, ERROR_MESSAGE );
+ }
+
+
+ return Ok;
+}
+
+
+
+BOOLEAN
+CONVERT::IsAutoConvScheduled(
+ )
+/*++
+
+Routine Description:
+
+ Determines if an AutoEntry contains a scheduled AUTOCONV for this
+ drive.
+
+Arguments:
+
+ Entry - AutoEntry to be inspected
+ FileSystem - File system to be converted to,
+
+Return Value:
+
+ BOOLEAN
+
+--*/
+
+{
+ DSTRING CommandLine;
+ DSTRING Space;
+ DSTRING FileSystem;
+
+ return (BOOLEAN)
+ ( CommandLine.Initialize( (LPWSTR)L"autocheck autoconv " ) &&
+ Space.Initialize( (LPWSTR)L" " ) &&
+ FileSystem.Initialize( (LPWSTR)L"/FS:" ) &&
+ CommandLine.Strcat( &_NtDrive ) &&
+ CommandLine.Strcat( &Space ) &&
+ CommandLine.Strcat( &FileSystem ) &&
+ CommandLine.Strcat( &_FsName ) &&
+ AUTOREG::IsEntryPresent( &CommandLine ) );
+
+}
diff --git a/private/utils/convert/convert.hxx b/private/utils/convert/convert.hxx
new file mode 100644
index 000000000..54833aa36
--- /dev/null
+++ b/private/utils/convert/convert.hxx
@@ -0,0 +1,136 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ convert.hxx
+
+Abstract:
+
+ This module contains the declaration of the CONVERT class, which
+ implements the File System Conversion Utility.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 27-Sep-1991
+
+Revision History:
+
+
+--*/
+
+
+#if !defined( _CONVERT_ )
+
+#define _CONVERT_
+
+#include "program.hxx"
+#include "autoentr.hxx"
+#include "autoreg.hxx"
+
+//
+// Convert exit codes
+//
+#define EXIT_SUCCESS 0 // Volume Converted
+#define EXIT_SCHEDULED 1 // Conversion scheduled for next reboot
+#define EXIT_NOCANDO 2 // Specified conversion not available
+#define EXIT_UNKNOWN 3 // Unknown file system
+#define EXIT_ERROR 4 // Conversion error
+
+
+DECLARE_CLASS( STREAM_MESSAGE );
+DECLARE_CLASS( WSTRING );
+DECLARE_CLASS( CONVERT );
+
+
+class CONVERT : public PROGRAM {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( CONVERT );
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ ~CONVERT (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ OUT PINT ExitCode
+ );
+
+ NONVIRTUAL
+ INT
+ Convert (
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Destroy (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsAutoConvScheduled(
+ );
+
+ NONVIRTUAL
+ PPATH
+ FindSystemFile(
+ IN PWSTR FileName
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ParseArguments(
+ OUT PINT ExitCode
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ParseCommandLine (
+ IN PCWSTRING CommandLine,
+ IN BOOLEAN Interactive
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ Schedule (
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ ScheduleAutoConv(
+ );
+
+ DSTRING _DosDrive; // Dos drive name of volume to convert
+ DSTRING _NtDrive; // NT drive name of volume to convert
+ DSTRING _FsName; // Name of target file system
+ DSTRING _NameTable; // Name of file for Name Table
+ BOOLEAN _Verbose; // Verbose flag
+ BOOLEAN _Help; // Help flag
+ BOOLEAN _Restart; // Restart flag
+#ifdef DBLSPACE_ENABLED
+ BOOLEAN _Uncompress;// Set if we're converting a cvf
+ DSTRING _CvfName; // If uncompress, the name of the cvf
+ BOOLEAN _Compress; // Compress resulting filesystem
+ UCHAR _SequenceNumber // sequence number of CVF to uncompress
+
+#endif // DBLSPACE_ENABLED
+
+ PPATH _Autochk; // Path to Autochk
+ PPATH _Autoconv; // Path to Autoconv
+};
+
+
+#endif // _CONVERT_
diff --git a/private/utils/convert/convert.rc b/private/utils/convert/convert.rc
new file mode 100644
index 000000000..e7f36ec99
--- /dev/null
+++ b/private/utils/convert/convert.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "File System Conversion Utility"
+#define VER_INTERNALNAME_STR "convert\0"
+#define VER_ORIGINALFILENAME_STR "CONVERT.EXE"
+
+#include "common.ver"
diff --git a/private/utils/convert/makefile b/private/utils/convert/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/convert/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/convert/sources b/private/utils/convert/sources
new file mode 100644
index 000000000..2abeeba60
--- /dev/null
+++ b/private/utils/convert/sources
@@ -0,0 +1,57 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=utils
+MINORCOMP=convert
+
+TARGETNAME=convert
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=convert.cxx convert.rc
+
+INCLUDES=..\ulib\inc;..\ifsutil\inc;..\cufat\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+UMLIBS= \
+ ..\ulib\src\obj\*\ulib.lib \
+ ..\ifsutil\src\obj\*\ifsutil.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+
+UMTYPE=console
diff --git a/private/utils/cudbfs/cudbfs.cxx b/private/utils/cudbfs/cudbfs.cxx
new file mode 100644
index 000000000..bc365d016
--- /dev/null
+++ b/private/utils/cudbfs/cudbfs.cxx
@@ -0,0 +1,174 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ cudbfs.cxx
+
+Abstract:
+
+ This module contains the declaration of ConvertDBFS, which is
+ the main entry point for this DLL.
+
+Author:
+
+ Matthew Bradburn (mattbr) 24-Nov-1993
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#define _NTAPI_ULIB_
+
+#include "cudbfs.hxx"
+#include "dbfsconv.hxx"
+#include "rtmsg.h"
+
+STATIC BOOLEAN
+DefineClassDescriptors(
+ );
+
+extern "C" BOOLEAN
+InitializeCudbfs(
+ PVOID DllHandle,
+ ULONG Reason,
+ PCONTEXT Context
+ )
+{
+ STATIC BOOLEAN fInit = FALSE;
+
+ if (fInit) {
+ return TRUE;
+ }
+
+ if (DefineClassDescriptors()) {
+ fInit = TRUE;
+ return TRUE;
+ }
+ DbgAbort("Cudbfs init failed.\n");
+ return FALSE;
+}
+
+DECLARE_CLASS(DBFS_CONV);
+
+STATIC BOOLEAN
+DefineClassDescriptors(
+ )
+{
+ if (DEFINE_CLASS_DESCRIPTOR(DBFS_CONV) &&
+ TRUE) {
+ return TRUE;
+ }
+ DbgPrint("Could not init class descriptors.\n");
+ return FALSE;
+}
+
+BOOLEAN FAR APIENTRY
+ConvertDBFS(
+ IN PCWSTRING NtDriveName,
+ IN PCWSTRING HostFileName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ OUT PCONVERT_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ This function converts an HPFS volume to the target file system
+ in-place.
+
+ This function opens and locks the volume, so it is not suitable
+ for use by autoconvert.
+
+Arguments:
+
+ NtDriveName -- Supplies the name of the drive.
+ HostFileName -- The path to the cvf.
+ Message -- Supplies an outlet for messages.
+ Verbose -- Supplies a flag indicating (if TRUE) that
+ conversion should be carried out in verbose mode.
+ Status -- Receives the status of the conversion.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ DBFS_CONV conv;
+ DSTRING HostFilePath;
+ DSTRING backslash;
+
+ if (!backslash.Initialize("\\")) {
+ return FALSE;
+ }
+
+ HostFilePath.Initialize(NtDriveName);
+ HostFilePath.Strcat(&backslash);
+ HostFilePath.Strcat(HostFileName);
+
+ if (!conv.Initialize(NtDriveName, &HostFilePath, Message)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ return conv.Convert(Message, Verbose, Status);
+}
+
+BOOLEAN FAR APIENTRY
+CheckFreeSpaceDBFS(
+ IN PCWSTRING NtDriveName,
+ IN PCWSTRING HostFileName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ IN BOOLEAN HostIsCompressed,
+ IN BOOLEAN WillConvertHost
+ )
+/*++
+
+Routine Description:
+
+ This routine examines the given dblspace cvf and the host
+ volume to determine whether there is enough space available
+ to uncompress the contents of the cvf. Also checks to see
+ if there are file name conflicts or other reasons why the
+ cvf should not be uncompressed.
+
+Arguments:
+
+ NtDriveName -- Supplies the name of the drive.
+ HostFileName -- The path to the cvf.
+ Message -- Supplies an outlet for messages.
+ Verbose -- Supplies a flag indicating (if TRUE) that
+ verbose messages should be printed
+
+Return Value:
+
+ TRUE - the cvf may be uncompressed
+ FALSE - the cvf may not be uncompressed
+
+--*/
+{
+ DBFS_CONV conv;
+ DSTRING HostFilePath;
+ DSTRING backslash;
+
+ if (!backslash.Initialize("\\")) {
+ return FALSE;
+ }
+
+ HostFilePath.Initialize(NtDriveName);
+ HostFilePath.Strcat(&backslash);
+ HostFilePath.Strcat(HostFileName);
+
+ if (!conv.Initialize(NtDriveName, &HostFilePath, Message)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ return conv.CheckFreeSpace(Message, HostIsCompressed, Verbose, WillConvertHost);
+}
diff --git a/private/utils/cudbfs/cudbfs.def b/private/utils/cudbfs/cudbfs.def
new file mode 100644
index 000000000..8ce82bf6b
--- /dev/null
+++ b/private/utils/cudbfs/cudbfs.def
@@ -0,0 +1,9 @@
+LIBRARY CUDBFS
+
+DESCRIPTION File System Conversion Library for DBFS
+
+DATA NONSHARED
+
+EXPORTS
+ ConvertDBFS
+ CheckFreeSpaceDBFS
diff --git a/private/utils/cudbfs/cudbfs.hxx b/private/utils/cudbfs/cudbfs.hxx
new file mode 100644
index 000000000..63f5fd36f
--- /dev/null
+++ b/private/utils/cudbfs/cudbfs.hxx
@@ -0,0 +1,48 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ cudbfs.hxx
+
+Abstract:
+
+ This module contains function prototypes for the DBFS conversion
+ functions.
+
+Author:
+
+ Matthew Bradburn (mattbr) 24-Nov-1993
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include "ulib.hxx"
+#include "message.hxx"
+#include "wstring.hxx"
+#include "ifsentry.hxx"
+
+extern "C"
+BOOLEAN FAR APIENTRY
+ConvertDBFS(
+ IN PCWSTRING NtDriveName,
+ IN PCWSTRING HostFileName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ OUT PCONVERT_STATUS Status
+ );
+
+extern "C"
+BOOLEAN FAR APIENTRY
+CheckFreeSpaceDBFS(
+ IN PCWSTRING NtDriveName,
+ IN PCWSTRING HostFileName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ IN BOOLEAN HostIsCompressed,
+ IN BOOLEAN WillConvertHost
+ );
diff --git a/private/utils/cudbfs/cudbfs.rc b/private/utils/cudbfs/cudbfs.rc
new file mode 100644
index 000000000..0b660f5ea
--- /dev/null
+++ b/private/utils/cudbfs/cudbfs.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "DBFS File System Conversion Utility DLL"
+#define VER_INTERNALNAME_STR "cudbfs\0"
+#define VER_ORIGINALFILENAME_STR "CUDBFS.DLL"
+
+#include "common.ver"
diff --git a/private/utils/cudbfs/dbfsconv.cxx b/private/utils/cudbfs/dbfsconv.cxx
new file mode 100644
index 000000000..3cb297abb
--- /dev/null
+++ b/private/utils/cudbfs/dbfsconv.cxx
@@ -0,0 +1,1812 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ dbfsconv.cxx
+
+Abstract:
+
+ This module contains routines to uncompress doublespace filesystems.
+
+Author:
+
+ Matthew Bradburn (mattbr) 24-Nov-1993
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+#include "dbfsconv.hxx"
+#include "intstack.hxx"
+#include "filedir.hxx"
+#include "rootdir.hxx"
+#include "fatdent.hxx"
+#include "fat.hxx"
+extern "C" {
+#include "mrcf.h"
+#include "rtmsg.h"
+#include <windows.h>
+}
+
+#define SIZE_TO_HOST_CLUSTERS(size) \
+ ((((size + _host_sector_size - 1) / _host_sector_size) \
+ + _new_host_sec_clus - 1) / _new_host_sec_clus)
+
+DEFINE_CONSTRUCTOR(DBFS_CONV, OBJECT);
+
+VOID
+DBFS_CONV::Construct(
+ )
+/*++
+
+Routine Description:
+
+ Constructor for DBFS_CONV.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _fatdbvol = NULL;
+ _fat = NULL;
+ _fatdbsa = NULL;
+ _cvf_name = NULL;
+ _buf = NULL;
+}
+
+BOOLEAN
+DBFS_CONV::Initialize(
+ IN PCWSTRING NtDriveName,
+ IN PCWSTRING HostFileName,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes objects of class DBFS_CONV. If
+ the initialization fails, the caller should print and error
+ message about insufficient memory.
+
+Arguments:
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure.
+
+--*/
+{
+ BOOLEAN need_msg = FALSE;
+ ULONG free_clus, total_clus;
+
+ _cvf_name = HostFileName;
+
+ //
+ // The _cvf_name is something like "\DosDevices\X:\dblspace.000".
+ // We want _win_destdrive to be "X:\".
+
+ _win_destdrive.Initialize(_cvf_name, 12, 3);
+
+ if (NULL == (_fatdbvol = NEW FATDB_VOL)) {
+ return FALSE;
+ }
+
+ if (!_fatdbvol->Initialize(NULL, HostFileName, Message, TRUE)) {
+ return FALSE;
+ }
+
+ _fatdbsa = (PFATDB_SA)_fatdbvol->GetSa();
+ _fat = _fatdbsa->GetFat();
+
+ _fatdbsa->CheckSectorHeapAllocation(CheckOnly, Message, &need_msg);
+
+ if (NULL == (_buf = (PUCHAR)MALLOC(_fatdbsa->QuerySectorsPerCluster() *
+ _fatdbvol->QuerySectorSize()))) {
+ return FALSE;
+ }
+
+ DbgAssert(0 == _fatdbvol->QuerySectors().GetHighPart());
+ if (!_secmap.Initialize(_fatdbvol->QuerySectors().GetLowPart())) {
+ return FALSE;
+ }
+
+ //
+ // Use worst case for number of directories.
+ //
+
+ if (!_parent_map.Initialize(_fatdbsa->QueryClusterCount())) {
+ return FALSE;
+ }
+
+ if (!GetDiskFreeSpace(_win_destdrive.GetWSTR(),
+ &_host_sec_clus, &_host_sector_size, &free_clus, &total_clus)) {
+ return FALSE;
+ }
+ _new_host_sec_clus = _host_sec_clus;
+
+ return TRUE;
+}
+
+BOOLEAN
+DBFS_CONV::Convert(
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ OUT PCONVERT_STATUS Status
+ )
+{
+ CENSUS_REPORT census;
+
+ if (!MapSectorsAndTakeCensus(Message, &census)) {
+ return FALSE;
+ }
+
+ if (!CreateHostDirectoryStructure(Message, Status)) {
+ return FALSE;
+ }
+ if (!ExtractCompressedFiles(Message, Verbose, &census, Status)) {
+ return FALSE;
+ }
+
+ // Destroy the fatdbvol in order to get handles on the cvf closed.
+
+ DELETE(_fatdbvol);
+
+ if (!DeleteCvf(Message)) {
+ *Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+ *Status = CONVERT_STATUS_CONVERTED;
+ return TRUE;
+}
+
+BOOLEAN
+DBFS_CONV::MapSectorsAndTakeCensus(
+ IN OUT PMESSAGE Message,
+ OUT PCENSUS_REPORT Census
+ )
+/*++
+
+Routine Description:
+
+ This routine fills in the _parent_map with pointers from
+ each file and directory to the parent directory, by starting
+ cluster. The cluster 0 indicates that the parent is the root
+ directory.
+
+ Since we're traversing the directory tree anyway, we take the
+ opportunity to calculate how much space will be taken by the
+ uncompressed volume.
+
+Arguments:
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure.
+
+--*/
+{
+ INTSTACK dirs_to_visit;
+ INTSTACK paths_of_dirs_tv;
+ DSTRING backslash;
+ PWSTRING current_path;
+ USHORT current_dir;
+ HMEM hmem;
+ FILEDIR filedir;
+ PFATDIR dir;
+ ULONG i;
+ FAT_DIRENT dirent;
+ USHORT clusters_required;
+ USHORT start_clus;
+ DSTRING filename;
+ DSTRING file_path;
+ PWSTRING new_path;
+
+ // Initialize the parent map.
+
+ DbgAssert(sizeof(PUCHAR) <= sizeof(INT));
+ DbgAssert(sizeof(USHORT) <= sizeof(INT));
+
+ // Initialize the census report
+
+ Census->FileEntriesCount = 0;
+ Census->FileClusters = 0;
+ Census->DirEntriesCount = 0;
+ Census->DirClusters = 0;
+ Census->EaClusters = 0;
+
+ if (!dirs_to_visit.Initialize() || !paths_of_dirs_tv.Initialize()) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!backslash.Initialize("\\")) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (NULL == (current_path = NEW DSTRING) ||
+ !current_path->Initialize(&backslash)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!dirs_to_visit.Push(0) || !paths_of_dirs_tv.Push((INT)current_path)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ for (; dirs_to_visit.QuerySize() > 0; DELETE(current_path)) {
+ current_dir = (USHORT)dirs_to_visit.Look().GetLowPart();
+ dirs_to_visit.Pop();
+ current_path = (PWSTRING)paths_of_dirs_tv.Look().GetLowPart();
+ paths_of_dirs_tv.Pop();
+
+ if (current_dir != 0) {
+ if (!hmem.Initialize() ||
+ !filedir.Initialize(&hmem, _fatdbvol, _fatdbsa, _fat,
+ current_dir) ||
+ !filedir.Read()) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ dir = &filedir;
+ } else {
+ dir = _fatdbsa->GetRootDir();
+ }
+
+ for (i = ((current_dir != 0) ? 2 : 0); ; ++i) {
+ if (!dirent.Initialize(dir->GetDirEntry(i)) ||
+ dirent.IsEndOfDirectory()) {
+ break;
+ }
+ if (dirent.IsErased() || dirent.IsVolumeLabel()) {
+ continue;
+ }
+ if (dirent.IsLongEntry()) {
+ continue;
+ }
+ if (0 == dirent.QueryStartingCluster()) {
+ //
+ // We skip zero-length files for now.
+ //
+ continue;
+ }
+
+ start_clus = dirent.QueryStartingCluster();
+
+ //
+ // The parent map will indicate that the parent of start_clus
+ // is current_dir.
+ //
+
+ _parent_map.SetEntry(start_clus, current_dir);
+
+ //
+ // For each cluster in the cluster chain, map the sectors
+ // for that cluster to the starting cluster in the chain.
+ //
+
+ if (!MapClusterChainSectors(start_clus)) {
+ Message->Set(MSG_DBLCONV_CVF_CORRUPT);
+ Message->Display("");
+ return FALSE;
+ }
+
+
+ if (!dirent.IsDirectory()) {
+ Census->FileClusters += clusters_required;
+ Census->FileEntriesCount++;
+ continue;
+ }
+
+ Census->DirClusters += clusters_required;
+ Census->DirEntriesCount++;
+
+ //
+ // Get the filename of the new directory.
+ //
+
+ dirent.QueryName(&filename);
+
+ if (!file_path.Initialize(current_path)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ if (current_dir != 0) {
+ if (!file_path.Strcat(&backslash)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ }
+ if (!file_path.Strcat(&filename)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (NULL == (new_path = NEW DSTRING) ||
+ !new_path->Initialize(&file_path)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!dirs_to_visit.Push((ULONG)start_clus) ||
+ !paths_of_dirs_tv.Push((ULONG)new_path)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+DBFS_CONV::CheckFreeSpace(
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN HostIsCompressed,
+ IN BOOLEAN Verbose,
+ IN BOOLEAN WillConvertHost
+ )
+/*++
+
+Routine Description:
+
+ This routine calculates whether there's enough space on the
+ host to uncompress the doublespace volume. Prints a message
+ if not. Also checks for file name conflicts.
+
+Arguments:
+
+Return Value:
+
+ TRUE - There is room.
+ FALSE - There is not room.
+
+--*/
+{
+ INTSTACK dirs_to_visit;
+ INTSTACK paths_of_dirs_tv;
+ DSTRING backslash;
+ PWSTRING current_path;
+ USHORT current_dir;
+ HMEM hmem;
+ FILEDIR filedir;
+ PFATDIR dir;
+ ULONG i;
+ FAT_DIRENT dirent;
+ ULONG clusters_required;
+ USHORT start_clus;
+ DSTRING filename;
+ DSTRING file_path;
+ DSTRING host_path;
+ PWSTRING new_path;
+ ULONG host_sec_clus, host_sector_size;
+ ULONG free_clus, total_clus;
+ ULONG attr;
+
+ // Initialize the parent map.
+
+ DbgAssert(sizeof(PUCHAR) <= sizeof(INT));
+ DbgAssert(sizeof(USHORT) <= sizeof(INT));
+
+ if (WillConvertHost) {
+ _new_host_sec_clus = 1;
+ }
+
+ if (!dirs_to_visit.Initialize() || !paths_of_dirs_tv.Initialize()) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!backslash.Initialize("\\")) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (NULL == (current_path = NEW DSTRING) ||
+ !current_path->Initialize(&backslash)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ if (!dirs_to_visit.Push(0) || !paths_of_dirs_tv.Push((INT)current_path)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ clusters_required = 0;
+
+ for (; dirs_to_visit.QuerySize() > 0; DELETE(current_path)) {
+ current_dir = (USHORT)dirs_to_visit.Look().GetLowPart();
+ dirs_to_visit.Pop();
+ current_path = (PWSTRING)paths_of_dirs_tv.Look().GetLowPart();
+ paths_of_dirs_tv.Pop();
+
+ if (current_dir != 0) {
+ if (!hmem.Initialize() ||
+ !filedir.Initialize(&hmem, _fatdbvol, _fatdbsa, _fat,
+ current_dir) ||
+ !filedir.Read()) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ dir = &filedir;
+ } else {
+ dir = _fatdbsa->GetRootDir();
+ }
+
+ for (i = ((current_dir != 0) ? 2 : 0); ; ++i) {
+ if (!dirent.Initialize(dir->GetDirEntry(i)) ||
+ dirent.IsEndOfDirectory()) {
+ break;
+ }
+ if (dirent.IsErased() || dirent.IsVolumeLabel()) {
+ continue;
+ }
+ if (dirent.IsLongEntry()) {
+ continue;
+ }
+
+ dirent.QueryName(&filename);
+
+ clusters_required += SIZE_TO_HOST_CLUSTERS(dirent.QueryFileSize());
+
+ start_clus = dirent.QueryStartingCluster();
+
+ if (!file_path.Initialize(current_path)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ if (current_dir != 0) {
+ if (!file_path.Strcat(&backslash)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ }
+ if (!file_path.Strcat(&filename)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!host_path.Initialize(&_win_destdrive, 0, 2) ||
+ !host_path.Strcat(&file_path)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ //
+ // Check for conflicts between this file in the cvf and
+ // on the host volume.
+
+ attr = GetFileAttributes(host_path.GetWSTR());
+ if (0xffffffff != attr) {
+ if (dirent.IsDirectory()) {
+
+ // The file on the host volume must also be a directory.
+
+ if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
+ Message->Set(MSG_DBLCONV_FILE_CONFLICT);
+ Message->Display("%W", &host_path);
+ return FALSE;
+ }
+ } else {
+
+ // The files conflict.
+
+ Message->Set(MSG_DBLCONV_FILE_CONFLICT);
+ Message->Display("%W", &host_path);
+ return FALSE;
+ }
+ }
+
+ if (!dirent.IsDirectory()) {
+ continue;
+ }
+
+ if (NULL == (new_path = NEW DSTRING) ||
+ !new_path->Initialize(&file_path)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!dirs_to_visit.Push((ULONG)start_clus) ||
+ !paths_of_dirs_tv.Push((ULONG)new_path)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ }
+ }
+
+ //
+ // Add a margin of comfort to the space required. This will
+ // give us room to account for the fact that directories aren't
+ // deleted from the cvf until the very end, and for the FAT and
+ // all the other overhead information stored in the cvf.
+ //
+
+ clusters_required += ULONG(.2 * clusters_required);
+
+ if (HostIsCompressed) {
+ clusters_required *= .7;
+ }
+
+ if (!GetDiskFreeSpace(_win_destdrive.GetWSTR(),
+ &host_sec_clus, &host_sector_size, &free_clus, &total_clus)) {
+ return FALSE;
+ }
+
+ if (clusters_required > free_clus) {
+ Message->Set(MSG_DBLCONV_NOT_ENOUGH_SPACE);
+ Message->Display("%d%d", clusters_required, free_clus);
+ return FALSE;
+ }
+
+ // Destroy the fatdbvol in order to get handles on the cvf closed.
+ // XXX.mjb: this should be done with a proper destructor.
+
+ DELETE(_fatdbvol);
+
+ return TRUE;
+}
+
+BOOLEAN
+DBFS_CONV::CreateHostDirectoryStructure(
+ IN OUT PMESSAGE Message,
+ IN OUT PCONVERT_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ This routine copies the directory structure from the cvf to the
+ host. In the process it creates any zero-length files that may
+ exist.
+
+Arguments:
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure.
+
+--*/
+{
+ INTSTACK dirs_to_visit;
+ INTSTACK paths_of_dirs_tv;
+ DSTRING backslash;
+ PWSTRING current_path;
+ USHORT current_dir;
+ HMEM hmem;
+ FILEDIR filedir;
+ PFATDIR dir;
+ FAT_DIRENT dirent;
+ DSTRING filename;
+ DSTRING file_path;
+ PWSTRING new_path;
+ USHORT start_clus;
+ HANDLE hFile;
+ DSTRING host_path;
+
+ if (!dirs_to_visit.Initialize() || !paths_of_dirs_tv.Initialize()) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!backslash.Initialize("\\")) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (NULL == (current_path = NEW DSTRING) ||
+ !current_path->Initialize(&backslash)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!dirs_to_visit.Push(0) || !paths_of_dirs_tv.Push((INT)current_path)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ for (; dirs_to_visit.QuerySize() > 0; DELETE(current_path)) {
+
+ current_dir = (USHORT)dirs_to_visit.Look().GetLowPart();
+ current_path = (PWSTRING)paths_of_dirs_tv.Look().GetLowPart();
+ dirs_to_visit.Pop();
+ paths_of_dirs_tv.Pop();
+
+ if (current_dir != 0) {
+ if (!hmem.Initialize() ||
+ !filedir.Initialize(&hmem, _fatdbvol, _fatdbsa, _fat,
+ current_dir) ||
+ !filedir.Read()) {
+
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ dir = &filedir;
+ } else {
+ dir = _fatdbsa->GetRootDir();
+ }
+
+ for (ULONG i = ((current_dir != 0) ? 2 : 0); ; ++i) {
+ if (!dirent.Initialize(dir->GetDirEntry(i)) ||
+ dirent.IsEndOfDirectory()) {
+ break;
+ }
+ if (dirent.IsErased() || dirent.IsVolumeLabel()) {
+ continue;
+ }
+ if (dirent.IsLongEntry()) {
+ continue;
+ }
+
+ if (!dirent.IsDirectory() && dirent.QueryFileSize() != 0) {
+ continue;
+ }
+
+ if (!dir->QueryLongName(i, &filename) ||
+ 0 == filename.QueryChCount()) {
+
+ // This directory entry does not have a long name;
+ // use the short name instead.
+ //
+ dirent.QueryName(&filename);
+ }
+
+ if (0 == dirent.QueryStartingCluster()) {
+
+ // Create zero-length files now.
+
+ if (!host_path.Initialize(&_win_destdrive)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ if (!host_path.Strcat(current_path)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ if (current_dir != 0) {
+ if (!host_path.Strcat(&backslash)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ }
+ if (!host_path.Strcat(&filename)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ hFile = CreateFile(host_path.GetWSTR(),
+ GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ dirent.QueryAttributeByte(),
+ NULL
+ );
+ if (INVALID_HANDLE_VALUE == hFile) {
+ Message->Set(MSG_DBLCONV_CANT_CREATE);
+ Message->Display("%W", &host_path);
+ if (ERROR_HANDLE_DISK_FULL == GetLastError() ||
+ ERROR_DISK_FULL == GetLastError()) {
+ *Status = CONVERT_STATUS_INSUFFICIENT_SPACE;
+ } else {
+ *Status = CONVERT_STATUS_ERROR;
+ }
+ return FALSE;
+ }
+ CloseHandle(hFile);
+ continue;
+ }
+ if (!dirent.IsDirectory()) {
+ continue;
+ }
+
+ if (NULL == (new_path = NEW DSTRING) ||
+ !new_path->Initialize(current_path)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ if (current_dir != 0) {
+ if (!new_path->Strcat(&backslash)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ }
+ if (!new_path->Strcat(&filename)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ //
+ // Create this directory on the destination host
+ //
+
+ if (!host_path.Initialize(&_win_destdrive)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ if (!host_path.Strcat(new_path)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!CreateDirectory(host_path.GetWSTR(), NULL)) {
+ if (ERROR_HANDLE_DISK_FULL == GetLastError() ||
+ ERROR_DISK_FULL == GetLastError()) {
+ *Status = CONVERT_STATUS_INSUFFICIENT_SPACE;
+ return FALSE;
+ }
+ }
+
+ //
+ // Push this directory on the stack of directories to
+ // visit.
+ //
+
+ start_clus = dirent.QueryStartingCluster();
+
+ if (!dirs_to_visit.Push((ULONG)start_clus) ||
+ !paths_of_dirs_tv.Push((ULONG)new_path)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+DBFS_CONV::ExtractCompressedFiles(
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ IN PCENSUS_REPORT Census,
+ OUT PCONVERT_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ This routine goes through the cvf from beginning to end,
+ find the file that owns the last used sector, and moves
+ it to the host volume. If the last sector is owned by a
+ directory, it is copied to a different place in the cvf.
+
+Arguments:
+
+ Message - an outlet for messages.
+ Verbose - to be or not to be verbose
+ Census - used to keep track of how many file remain
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure.
+
+--*/
+{
+ USHORT file_starting_cluster;
+ DSTRING file_path;
+ HMEM last_sector_mem;
+ SECRUN last_sector;
+ ULONG last_used_sector;
+ ULONG new_cvf_size;
+ DBFS_FILE_INFO file_info;
+
+ if (!file_path.Initialize()) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ last_used_sector = _secmap.FindLastUsed();
+
+ while (Census->FileEntriesCount > 0) {
+ DbgAssert(0 != last_used_sector);
+ file_starting_cluster = _secmap.QueryEntry(last_used_sector);
+
+ if (!FindPathFromStartingCluster(Message, file_starting_cluster,
+ &file_path, &file_info)) {
+ return FALSE;
+ }
+
+ if (!file_info.fIsDirectory) {
+
+ if (!CopyClusterChainToFile(Message, Verbose,
+ file_starting_cluster, &file_path, &file_info, Status)) {
+ return FALSE;
+ }
+
+ // free file's clusters in cvf, erase entry in cvf dir
+ // clear corresponding entries in _sector_map.
+
+ if (!EraseFile(Message, file_starting_cluster)) {
+ return FALSE;
+ }
+
+ Census->FileEntriesCount--;
+
+ } else {
+ //
+ // assume path names a dir -- copy the last sectors of the
+ // dir elsewhere
+ //
+
+ if (!RelocateClusterChain(Message, Verbose,
+ file_starting_cluster, last_used_sector, Census, Status)) {
+ return FALSE;
+ }
+ }
+
+ last_used_sector = _secmap.FindLastUsed();
+ if (0 == last_used_sector) {
+ return TRUE;
+ }
+
+ new_cvf_size = (last_used_sector + 2) * _fatdbvol->QuerySectorSize();
+
+ _fatdbsa->SetCvfSectorCount(last_used_sector + 1);
+
+
+ //
+ // Write the second Double Space signature in the last
+ // sector of the CVF.
+ //
+
+ if (!last_sector_mem.Initialize() ||
+ !last_sector.Initialize(&last_sector_mem, _fatdbvol,
+ _fatdbvol->QuerySectors() - 1, 1)) {
+
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ memset(last_sector.GetBuf(), 0, _fatdbvol->QuerySectorSize());
+ memcpy(last_sector.GetBuf(), SecondDbSignature, DbSignatureLength);
+
+ if (!_fatdbvol->SetCvfSize(new_cvf_size)) {
+ return FALSE;
+ }
+
+ last_sector.Write();
+ }
+
+ return TRUE;
+}
+
+#undef DeleteFile
+
+BOOLEAN
+DBFS_CONV::DeleteCvf(
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine removes the cvf.
+
+Arguments:
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure.
+
+--*/
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING UnicodeString;
+ FILE_DISPOSITION_INFORMATION DispositionInfo;
+ HANDLE FileHandle;
+ NTSTATUS Status;
+
+ UnicodeString.Buffer = (PWSTR)_cvf_name->GetWSTR();
+ UnicodeString.Length = USHORT(_cvf_name->QueryChCount() * sizeof(WCHAR));
+ UnicodeString.MaximumLength = UnicodeString.Length;
+
+ InitializeObjectAttributes(&ObjectAttributes, &UnicodeString,
+ OBJ_CASE_INSENSITIVE, 0, 0);
+
+ Status = NtOpenFile(&FileHandle,
+ STANDARD_RIGHTS_REQUIRED,
+ &ObjectAttributes, &IoStatusBlock,
+ FILE_SHARE_DELETE,
+ FILE_NON_DIRECTORY_FILE);
+
+ if (!NT_SUCCESS(Status)) {
+ Message->Set(MSG_DASD_ACCESS_DENIED);
+ Message->Display("");
+ return FALSE;
+ }
+
+ DispositionInfo.DeleteFile = TRUE;
+
+ Status = NtSetInformationFile(FileHandle,
+ &IoStatusBlock,
+ &DispositionInfo,
+ sizeof(DispositionInfo),
+ FileDispositionInformation);
+
+ NtClose(FileHandle);
+
+ if (!NT_SUCCESS(Status)) {
+ Message->Set(MSG_DBLSPACE_CANT_DELETE_CVF);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+BOOLEAN
+DBFS_CONV::CopyClusterChainToFile(
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ IN USHORT FirstCluster,
+ IN PWSTRING FilePath,
+ IN PDBFS_FILE_INFO FileInfo,
+ OUT PCONVERT_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ This routine copies the file from the cvf to the host volume,
+ uncompressing in the process.
+
+Arguments:
+
+ Message - an outlet for messages
+ Verbose - to be or not to be verbose
+ FirstCluster - the starting cluster of the file in the cvf.
+ FilePath - the file data's destination
+ FileInfo - file size, attributes etc.
+ Status - return status if failure
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure.
+
+--*/
+{
+ USHORT clus;
+ UCHAR nsec;
+ SECRUN secrun;
+ ULONG lbn;
+ ULONG u;
+ MRCF_DECOMPRESS wkspc;
+ HANDLE hFile;
+ HMEM hmem;
+ BOOLEAN success;
+ DSTRING file_path;
+ ULONG plain_size;
+
+ ULONG sector_size = _fatdbvol->QuerySectorSize();
+ ULONG cluster_size = sector_size * _fatdbsa->QuerySectorsPerCluster();
+
+ if (!file_path.Initialize(&_win_destdrive, 0, 2)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ *Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+ if (!file_path.Strcat(FilePath)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ *Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+ if (Verbose) {
+ Message->Set(MSG_DBLCONV_CREATE_FILE);
+ Message->Display("%W", &file_path);
+ }
+ hFile = CreateFile( file_path.GetWSTR(),
+ GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ FileInfo->bAttributes,
+ NULL
+ );
+
+ if (INVALID_HANDLE_VALUE == hFile) {
+ Message->Set(MSG_DBLCONV_CANT_CREATE);
+ Message->Display("%W", &file_path);
+ *Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+ clus = FirstCluster;
+ for (;;) {
+ lbn = _fatdbsa->QuerySectorFromCluster(clus, &nsec);
+
+ if (!hmem.Initialize() ||
+ !secrun.Initialize(&hmem, _fatdbvol, lbn, nsec)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ if (!secrun.Read()) {
+ Message->Set(MSG_DBLCONV_CVF_CORRUPT);
+ Message->Display("");
+ return FALSE;
+ }
+
+ plain_size = _fatdbsa->QuerySectorsRequiredForPlainData(clus)
+ * sector_size;
+
+ if (_fatdbsa->IsClusterCompressed(clus)) {
+
+ RtlZeroMemory(_buf, cluster_size);
+ RtlZeroMemory(&wkspc, sizeof(wkspc));
+
+ u = MrcfDecompress(_buf, plain_size, (PUCHAR)secrun.GetBuf(),
+ nsec * sector_size, &wkspc);
+
+ if (0 == u) {
+ Message->Set(MSG_DBLCONV_CVF_CORRUPT);
+ Message->Display("");
+ *Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+ success = WriteFile(hFile, _buf,
+ (plain_size > FileInfo->uFileSize) ?
+ FileInfo->uFileSize : plain_size, &u, NULL);
+
+ } else {
+ success = WriteFile(hFile, secrun.GetBuf(),
+ (plain_size > FileInfo->uFileSize) ?
+ FileInfo->uFileSize : plain_size, &u, NULL);
+
+ }
+ if (!success) {
+ *Status = CONVERT_STATUS_INSUFFICIENT_SPACE;
+ return FALSE;
+ }
+
+ FileInfo->uFileSize -= plain_size;
+
+ if (_fat->IsEndOfChain(clus)) {
+ break;
+ }
+ clus = _fat->QueryEntry(clus);
+ if (!_fat->IsInRange(clus)) {
+ Message->Set(MSG_DBLCONV_CVF_CORRUPT);
+ Message->Display("");
+ return FALSE;
+ }
+ }
+
+ //
+ // Set the timestamp on the file.
+ //
+
+ if (!SetFileTime(hFile, NULL, NULL, (PFILETIME)&FileInfo->liTimeStamp)) {
+ DbgPrintf("SetFileTime: %d\n", GetLastError());
+ }
+
+ CloseHandle(hFile);
+ return TRUE;
+}
+
+BOOLEAN
+DBFS_CONV::EraseFile(
+ IN OUT PMESSAGE Message,
+ IN USHORT FirstCluster
+ )
+/*++
+
+Routine Description:
+
+ This routine removes the given file from the cvf.
+
+Arguments:
+
+ FirstCluster - the starting cluster for the file.
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure.
+
+--*/
+{
+ USHORT clus, next;
+ USHORT parent_dir_clus;
+ PFATDIR parent_dir;
+ FILEDIR filedir;
+ FAT_DIRENT dirent;
+ HMEM hmem;
+ ULONG lbn;
+ UCHAR nsec;
+
+ //
+ // remove the file name from the parent directory.
+ //
+
+ parent_dir_clus = _parent_map.QueryEntry(FirstCluster);
+
+ if (parent_dir_clus != 0) {
+ if (!hmem.Initialize() ||
+ !filedir.Initialize(&hmem, _fatdbvol, _fatdbsa, _fat,
+ parent_dir_clus) ||
+ !filedir.Read()) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ parent_dir = &filedir;
+ } else {
+ parent_dir = _fatdbsa->GetRootDir();
+ }
+ for (ULONG i = ((parent_dir_clus != 0) ? 2 : 0); ; i++) {
+ if (!dirent.Initialize(parent_dir->GetDirEntry(i))) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ if (dirent.IsEndOfDirectory()) {
+ Message->Set(MSG_DBLCONV_CVF_CORRUPT);
+ Message->Display("");
+ return FALSE;
+ }
+ if (dirent.IsErased() || dirent.IsVolumeLabel()) {
+ continue;
+ }
+ if (dirent.QueryStartingCluster() == FirstCluster) {
+ dirent.SetErased();
+ break;
+ }
+ }
+
+ if (!WriteDir(parent_dir, parent_dir_clus)) {
+ Message->Set(MSG_DBLCONV_CVF_CORRUPT);
+ Message->Display("");
+ return FALSE;
+ }
+
+
+ //
+ // remove the file from the directory hierarchy map.
+ //
+
+ _parent_map.DeleteEntry(FirstCluster);
+
+ //
+ // Free the cluster chain and file data.
+ //
+
+ clus = FirstCluster;
+ for (;;) {
+
+ lbn = _fatdbsa->QuerySectorFromCluster(clus, &nsec);
+ for (ULONG i = lbn; i < lbn + nsec; ++i) {
+ _secmap.SetEntry(i, MAP_ENTRY_UNUSED);
+ }
+
+ _fatdbsa->FreeClusterData(clus);
+ if (_fat->IsEndOfChain(clus)) {
+ _fat->SetClusterFree(clus);
+ break;
+ }
+
+ next = _fat->QueryEntry(clus);
+ _fat->SetClusterFree(clus);
+
+ if (!_fat->IsInRange(next)) {
+ Message->Set(MSG_DBLCONV_CVF_CORRUPT);
+ Message->Display("");
+ return FALSE;
+ }
+ clus = next;
+ }
+
+ if (!_fat->Write()) {
+ Message->Set(MSG_DBLCONV_CVF_CORRUPT);
+ Message->Display("");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+DBFS_CONV::FindPathFromStartingCluster(
+ IN OUT PMESSAGE Message,
+ IN USHORT StartingCluster,
+ OUT PWSTRING Path,
+ OUT PDBFS_FILE_INFO FileInfo
+ )
+/*++
+
+Routine Description:
+
+ This routine finds the full path of a file from the
+ file's starting cluster by recursively reading parent
+ directories.
+
+Arguments:
+
+ StartingCluster - the file's first cluster
+ Path - the path to the file
+ pbPathNamesFile - set if the path names a file
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure.
+
+--*/
+{
+ FAT_DIRENT dirent;
+ PFATDIR dir;
+ HMEM hmem;
+ FILEDIR filedir;
+ DSTRING filename;
+ DSTRING backslash;
+ INTSTACK dirstack;
+ USHORT clus;
+ USHORT parent;
+
+ if (!dirstack.Initialize()) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ if (!backslash.Initialize("\\")) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ clus = StartingCluster;
+ while (0 != clus) {
+ if (!dirstack.Push(clus)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ clus = _parent_map.QueryEntry(clus);
+ }
+
+ Path->Initialize();
+ clus = 0;
+
+ for (;;) {
+ if (dirstack.QuerySize() == 0) {
+ return TRUE;
+ }
+
+ if (!Path->Strcat(&backslash)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ parent = clus;
+ clus = (USHORT)dirstack.Look().GetLowPart();
+ dirstack.Pop();
+
+ if (parent != 0) {
+ if (!hmem.Initialize() ||
+ !filedir.Initialize(&hmem, _fatdbvol, _fatdbsa, _fat,
+ parent)||
+ !filedir.Read()) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ dir = &filedir;
+ } else {
+ dir = _fatdbsa->GetRootDir();
+ }
+
+ for (ULONG i = ((parent > 0) ? 2 : 0); ; i++) {
+ if (!dirent.Initialize(dir->GetDirEntry(i)) ||
+ dirent.IsEndOfDirectory()) {
+ Message->Set(MSG_DBLCONV_CVF_CORRUPT);
+ Message->Display("");
+ return FALSE;
+ }
+ if (dirent.IsErased() || dirent.IsLongEntry()) {
+ continue;
+ }
+
+ if (dirent.QueryStartingCluster() == clus) {
+ FileInfo->fIsDirectory = dirent.IsDirectory();
+ FileInfo->bAttributes = dirent.QueryAttributeByte();
+ FileInfo->uFileSize = dirent.QueryFileSize();
+ dirent.QueryTimeStamp(&FileInfo->liTimeStamp);
+
+ if (!dir->QueryLongName(i, &filename) ||
+ 0 == filename.QueryChCount()) {
+
+ // This directory entry does not have a long name;
+ // use the short name instead.
+ //
+ dirent.QueryName(&filename);
+ }
+
+ if (!Path->Strcat(&filename)) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ break;
+ }
+ }
+ }
+ //NOTREACHED
+ return TRUE;
+}
+
+BOOLEAN
+DBFS_CONV::RelocateClusterChain(
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ IN USHORT ClusterChain,
+ IN ULONG LastUsedSector,
+ IN OUT PCENSUS_REPORT Census,
+ OUT PCONVERT_STATUS Status
+ )
+{
+ USHORT new_chain;
+ USHORT clus, next, temp_clus;
+ USHORT parent;
+ HMEM hmem;
+ FILEDIR filedir;
+ PFATDIR dir;
+ FAT_DIRENT dirent;
+ ULONG lbn, lbn2;
+ UCHAR nsec;
+ SECRUN secrun;
+ ULONG i;
+
+ //
+ // Find the cluster that points to the last used sector.
+ //
+
+ clus = ClusterChain;
+ while (clus != 0) {
+
+ if (!_fat->IsEndOfChain(clus)) {
+ next = _fat->QueryEntry(clus);
+ } else {
+ next = 0;
+ }
+
+ lbn = _fatdbsa->QuerySectorFromCluster(clus, &nsec);
+
+ if (LastUsedSector >= lbn && LastUsedSector < lbn + nsec) {
+ break;
+ }
+
+ clus = next;
+ }
+ if (clus == 0) {
+ return FALSE;
+ }
+
+ BOOLEAN compressed = _fatdbsa->IsClusterCompressed(clus);
+ UCHAR plain_size = _fatdbsa->QuerySectorsRequiredForPlainData(clus);
+
+ //
+ // Allocate space for the data used by clus
+ //
+
+ for (;;) {
+ temp_clus = _fat->AllocChain(1);
+ if (0 != temp_clus) {
+ break;
+ }
+ if (!FindAndUncompressFile(Message, Verbose, Status)) {
+ return FALSE;
+ }
+ Census->FileEntriesCount--;
+ }
+
+ for (;;) {
+ if (_fatdbsa->AllocateClusterData(temp_clus, nsec, compressed,
+ plain_size)) {
+ lbn2 = _fatdbsa->QuerySectorFromCluster(temp_clus);
+ if (lbn2 < LastUsedSector) {
+ break;
+ }
+
+ //
+ // We succesfully allocated data for the cluster, but
+ // it was too far out in the cvf.
+ //
+
+ _fatdbsa->FreeClusterData(temp_clus);
+ }
+
+ if (!FindAndUncompressFile(Message, Verbose, Status)) {
+ return FALSE;
+ }
+ Census->FileEntriesCount--;
+ continue;
+ }
+
+ //
+ // Copy data from clus to temp_clus
+ //
+
+ if (!secrun.Initialize(&hmem, _fatdbvol, lbn, nsec)) {
+ return FALSE;
+ }
+ if (!secrun.Read()) {
+ return FALSE;
+ }
+ secrun.Relocate(_fatdbsa->QuerySectorFromCluster(temp_clus));
+
+ if (!secrun.Write()) {
+ return FALSE;
+ }
+
+ //
+ // Fiddle with the cluster chain to replace the old cluster with
+ // the new.
+ //
+
+ parent = _parent_map.QueryEntry(ClusterChain);
+
+ if (!ReplaceClusterInChain(ClusterChain, clus, temp_clus, parent,
+ &new_chain)) {
+ return FALSE;
+ }
+
+ if (ClusterChain != new_chain) {
+ //
+ // Change the directory entry to point to the new cluster
+ // chain.
+ //
+
+ if (parent != 0) {
+ if (!hmem.Initialize() ||
+ !filedir.Initialize(&hmem, _fatdbvol, _fatdbsa, _fat, parent) ||
+ !filedir.Read()) {
+ Message->Set(MSG_CONV_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ dir = &filedir;
+ } else {
+ dir = _fatdbsa->GetRootDir();
+ }
+
+ for (ULONG i = ((parent != 0) ? 2 : 0); ; i++) {
+ if (!dirent.Initialize(dir->GetDirEntry(i)) ||
+ dirent.IsEndOfDirectory()) {
+ Message->Set(MSG_DBLCONV_CVF_CORRUPT);
+ Message->Display("");
+ return FALSE;
+ }
+ if (dirent.IsErased() || dirent.IsVolumeLabel()) {
+ continue;
+ }
+ if (dirent.QueryStartingCluster() == ClusterChain) {
+ break;
+ }
+ }
+ dirent.SetStartingCluster(new_chain);
+
+ if (!WriteDir(dir, parent)) {
+ Message->Set(MSG_DBLCONV_CVF_CORRUPT);
+ Message->Display("");
+ return FALSE;
+ }
+ }
+
+ //
+ // Free the data for the old cluster.
+ //
+
+ lbn = _fatdbsa->QuerySectorFromCluster(clus, &nsec);
+ for (i = lbn; i < lbn + nsec; ++i) {
+ _secmap.SetEntry(i, MAP_ENTRY_UNUSED);
+ }
+ _fatdbsa->FreeClusterData(clus);
+
+ if (!_fat->Write()) {
+ return FALSE;
+ }
+
+ //
+ // Modify the sector map to indicate that the sectors in the
+ // new cluster chain are in use.
+ //
+
+ lbn = _fatdbsa->QuerySectorFromCluster(temp_clus, &nsec);
+ for (i = lbn; i < lbn + nsec; ++i) {
+ _secmap.SetEntry(i, new_chain);
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+DBFS_CONV::MapClusterChainSectors(
+ USHORT FirstClus
+ )
+{
+ USHORT clus;
+ ULONG lbn;
+ ULONG i, j;
+ UCHAR nsec;
+ ULONG chain_length;
+
+ chain_length = _fat->QueryLengthOfChain(FirstClus);
+
+ clus = FirstClus;
+ i = 0;
+
+ for (;;) {
+ lbn = _fatdbsa->QuerySectorFromCluster(clus, &nsec);
+
+ for (j = lbn; j < lbn + nsec; ++j) {
+ _secmap.SetEntry(j, FirstClus);
+ }
+
+ if (++i == chain_length) {
+ break;
+ }
+
+ clus = _fat->QueryEntry(clus);
+ }
+ return TRUE;
+}
+
+BOOLEAN
+DBFS_CONV::FindAndUncompressFile(
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ OUT PCONVERT_STATUS Status
+ )
+{
+ ULONG i;
+ USHORT start_clus;
+ DSTRING path;
+ BOOLEAN success;
+ DBFS_FILE_INFO file_info;
+
+ i = 0;
+ for (;;) {
+ while (0 == (start_clus = _secmap.QueryEntry(i))) {
+ ++i;
+ }
+
+ if (!FindPathFromStartingCluster(Message, start_clus,
+ &path, &file_info)) {
+ return FALSE;
+ }
+
+ if (!file_info.fIsDirectory) {
+ break;
+ }
+
+ //
+ // Skip all the adjacent sectors that belong to the
+ // same file.
+ //
+
+ ++i;
+ while (start_clus == _secmap.QueryEntry(i)) {
+ ++i;
+ }
+ }
+
+ success = CopyClusterChainToFile(Message, Verbose, start_clus, &path,
+ &file_info, Status);
+ if (!success) {
+ return FALSE;
+ }
+ success = EraseFile(Message, start_clus);
+ if (!success) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+BOOLEAN
+DBFS_CONV::ReplaceClusterInChain(
+ IN USHORT ClusterChain,
+ IN USHORT Cluster,
+ IN USHORT NewCluster,
+ IN USHORT ParentDir,
+ OUT PUSHORT NewChainHead
+ )
+/*++
+
+Routine Description:
+
+ This routine replaces one cluster in a chain with another cluster.
+ If the cluster being replaces is the head of the chain, this routine
+ also updates the directory entry to point at the correct cluster.
+
+Arguments:
+
+ ClusterChain - the chain in which to make the replacement
+ Cluster - this gets replaces
+ NewCluster - this replaces Cluster
+ NewChainHead - if we replace the head of the chain, this returns
+ the new head (which will be NewCluster).
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ USHORT clus, next;
+
+ if (ClusterChain == Cluster) {
+
+ // replacing the head of the chain.
+
+ *NewChainHead = NewCluster;
+ _fat->SetEntry(NewCluster, _fat->QueryEntry(Cluster));
+
+ //
+ // Delete the entry that tells what the parent of ClusterChain
+ // is.
+ //
+
+ _parent_map.DeleteEntry(ClusterChain);
+
+ //
+ // Modify the parent map so that all the entries that used
+ // to point to ClusterChain now point to the new chain head.
+ //
+
+ _parent_map.ReplaceParent(ClusterChain, NewCluster);
+
+ //
+ // Insert the new child->parent mapping.
+ //
+
+ _parent_map.SetEntry(NewCluster, ParentDir);
+
+ return TRUE;
+ }
+
+ clus = ClusterChain;
+ while (clus != 0) {
+
+ if (!_fat->IsEndOfChain(clus)) {
+ next = _fat->QueryEntry(clus);
+ } else {
+ return FALSE;
+ }
+
+ if (next == Cluster) {
+ _fat->SetEntry(clus, NewCluster);
+ _fat->SetEntry(NewCluster, _fat->QueryEntry(next));
+ break;
+ }
+
+ clus = next;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+DBFS_CONV::WriteDir(
+ PFATDIR Dir,
+ USHORT StartingCluster
+ )
+/*++
+
+Routine Description:
+
+ This routine should be used to write a directory. The problem
+ with calling FATDIR::Write() directly is that is may allocate
+ and free sectors in the sector heap, if the directory changes
+ size on disk. If this happens, it will screw our map of
+ sectors -> file starting cluster. So this routine goes through
+ and clears the mapping, does the write, and then re-establishes
+ a new mapping.
+
+Arguments:
+
+ Dir - the directory we want to write (root is okay)
+ StartingCluster - the first cluster of the dir we want to write
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ USHORT clus;
+ ULONG lbn;
+ UCHAR nsec;
+
+
+ if (0 != StartingCluster) {
+ clus = StartingCluster;
+ for (;;) {
+ lbn = _fatdbsa->QuerySectorFromCluster(clus, &nsec);
+ for (ULONG i = lbn; i < lbn + nsec; ++i) {
+ _secmap.SetEntry(i, MAP_ENTRY_UNUSED);
+ }
+ if (_fat->IsEndOfChain(clus)) {
+ break;
+ }
+ clus = _fat->QueryEntry(clus);
+ }
+ }
+
+ if (!Dir->Write()) {
+ return FALSE;
+ }
+
+ if (0 != StartingCluster) {
+ MapClusterChainSectors(StartingCluster);
+ }
+ return TRUE;
+}
diff --git a/private/utils/cudbfs/dbfsconv.hxx b/private/utils/cudbfs/dbfsconv.hxx
new file mode 100644
index 000000000..9ed0c5c82
--- /dev/null
+++ b/private/utils/cudbfs/dbfsconv.hxx
@@ -0,0 +1,174 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ dbfsconv.hxx
+
+Abstract:
+
+ This module declares routines to uncompress doublespace fileystems.
+
+Author:
+
+ Matthew Bradburn (mattbr) 24-Nov-1993
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if ! defined DBFS_CONV_DEFN
+#define DBFS_CONV_DEFN
+
+#include "ulib.hxx"
+#include "fatdbvol.hxx"
+#include "fatdbsa.hxx"
+#include "secmap.hxx"
+#include "treemap.hxx"
+#include "ifsentry.hxx"
+
+
+typedef struct _DBFS_FILE_INFO {
+ BOOLEAN fIsDirectory; // is the file a directory
+ UCHAR bAttributes; // file attributes
+ ULONG uFileSize; // file size
+ LARGE_INTEGER liTimeStamp; // last mod time
+} DBFS_FILE_INFO, *PDBFS_FILE_INFO;
+
+class DBFS_CONV : OBJECT {
+ public:
+ DECLARE_CONSTRUCTOR(DBFS_CONV);
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PCWSTRING NtDriveName,
+ IN PCWSTRING HostFileName,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Convert(
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ OUT PCONVERT_STATUS Status
+ );
+
+ NONVIRTUAL BOOLEAN
+ CheckFreeSpace(
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN HostIsCompressed,
+ IN BOOLEAN Verbose,
+ IN BOOLEAN WillConvertHost
+ );
+
+
+ private:
+
+ PFATDB_VOL _fatdbvol;
+ PFATDB_SA _fatdbsa;
+ PFAT _fat;
+ SECTOR_MAP _secmap;
+ TREE_MAP _parent_map;
+ ULONG _host_sector_size;
+ ULONG _new_host_sec_clus;
+ ULONG _host_sec_clus;
+ PCWSTRING _cvf_name;
+ DSTRING _win_destdrive;
+ PUCHAR _buf; // decompression workspace
+
+ NONVIRTUAL VOID
+ Construct();
+
+ NONVIRTUAL BOOLEAN
+ MapSectorsAndTakeCensus(
+ IN OUT PMESSAGE Message,
+ OUT PCENSUS_REPORT Census
+ );
+
+ NONVIRTUAL BOOLEAN
+ CreateHostDirectoryStructure(
+ IN OUT PMESSAGE Message,
+ IN OUT PCONVERT_STATUS Status
+ );
+
+ NONVIRTUAL BOOLEAN
+ ExtractCompressedFiles(
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ IN PCENSUS_REPORT Census,
+ OUT PCONVERT_STATUS Status
+ );
+
+ NONVIRTUAL BOOLEAN
+ DeleteCvf(
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL BOOLEAN
+ CopyClusterChainToFile(
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ IN USHORT StartingCluster,
+ IN PWSTRING FilePath,
+ IN PDBFS_FILE_INFO FileInfo,
+ OUT PCONVERT_STATUS Status
+ );
+
+ NONVIRTUAL BOOLEAN
+ EraseFile(
+ IN OUT PMESSAGE Message,
+ IN USHORT FirstCluster
+ );
+
+ NONVIRTUAL BOOLEAN
+ FindPathFromStartingCluster(
+ IN OUT PMESSAGE Message,
+ IN USHORT StartingCluster,
+ OUT PWSTRING Path,
+ OUT PDBFS_FILE_INFO FileInfo
+ );
+
+ NONVIRTUAL BOOLEAN
+ RelocateClusterChain(
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ IN USHORT Cluster,
+ IN ULONG LastUsedSector,
+ IN OUT PCENSUS_REPORT Census,
+ OUT PCONVERT_STATUS Status
+ );
+
+ NONVIRTUAL BOOLEAN
+ MapClusterChainSectors(
+ IN USHORT Cluster
+ );
+
+ NONVIRTUAL BOOLEAN
+ FindAndUncompressFile(
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ OUT PCONVERT_STATUS Status
+ );
+
+ NONVIRTUAL BOOLEAN
+ ReplaceClusterInChain(
+ IN USHORT ClusterChain,
+ IN USHORT Cluster,
+ IN USHORT NewCluster,
+ IN USHORT ParentDir,
+ OUT PUSHORT NewChainHead
+ );
+
+ NONVIRTUAL BOOLEAN
+ WriteDir(
+ IN PFATDIR Dir,
+ IN USHORT StartingCluster
+ );
+};
+
+#endif // DBFS_CONV_DEFN
diff --git a/private/utils/cudbfs/makefile b/private/utils/cudbfs/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/cudbfs/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/cudbfs/secmap.cxx b/private/utils/cudbfs/secmap.cxx
new file mode 100644
index 000000000..c9224b6c0
--- /dev/null
+++ b/private/utils/cudbfs/secmap.cxx
@@ -0,0 +1,63 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ secmap.cxx
+
+Abstract:
+
+ Map a ULONG key to a USHORT value. Used to keep track
+ of the starting cluster for each sector in the sector heap.
+
+Author:
+
+ Matthew Bradburn (mattbr) 01-Dec-1993
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include "secmap.hxx"
+
+BOOLEAN
+SECTOR_MAP::Initialize(ULONG size)
+{
+ _map = (PUSHORT)MALLOC(size * sizeof(USHORT));
+ _size = size;
+
+ memset(_map, 0, size * sizeof(USHORT));
+
+ return TRUE;
+}
+
+VOID
+SECTOR_MAP::SetEntry(ULONG index, USHORT value)
+{
+ DbgAssert(NULL != _map);
+ DbgAssert(index < _size);
+ _map[index] = value;
+}
+
+USHORT
+SECTOR_MAP::QueryEntry(ULONG index)
+{
+ DbgAssert(index < _size);
+ return _map[index];
+}
+
+USHORT
+SECTOR_MAP::FindLastUsed()
+{
+ USHORT i;
+
+ for (i = (USHORT)_size - 1; i > 0; --i) {
+ if (QueryEntry(i) != MAP_ENTRY_UNUSED) {
+ return i;
+ }
+ }
+ return MAP_INVALID_ENTRY;
+}
diff --git a/private/utils/cudbfs/secmap.hxx b/private/utils/cudbfs/secmap.hxx
new file mode 100644
index 000000000..054afa825
--- /dev/null
+++ b/private/utils/cudbfs/secmap.hxx
@@ -0,0 +1,47 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ secmap.hxx
+
+Abstract:
+
+ Maps a ULONG key to a USHORT value. Used to keep track of
+ the starting cluster for each sector in the dbfs sector heap.
+
+Author:
+
+ Matthew Bradburn (mattbr) 01-Dec-1993
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#define MAP_ENTRY_UNUSED 0
+#define MAP_INVALID_ENTRY 0
+
+#include "ulib.hxx"
+
+class SECTOR_MAP {
+public:
+ BOOLEAN
+ Initialize(ULONG size);
+
+ VOID
+ SetEntry(ULONG index, USHORT value);
+
+ USHORT
+ QueryEntry(ULONG index);
+
+ USHORT
+ FindLastUsed();
+
+private:
+
+ PUSHORT _map;
+ ULONG _size;
+};
diff --git a/private/utils/cudbfs/sources b/private/utils/cudbfs/sources
new file mode 100644
index 000000000..c983c6d62
--- /dev/null
+++ b/private/utils/cudbfs/sources
@@ -0,0 +1,78 @@
+
+
+
+
+
+DON'T BUILD CUDBFS
+
+
+
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+BLDCRT=1
+
+MAJORCOMP=utils
+MINORCOMP=cudbfs
+
+TARGETNAME=cudbfs
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+TARGETLIBS= \nt\public\sdk\lib\*\kernel32.lib \
+ ..\ulib\src\obj\*\ulib.lib \
+ ..\ifsutil\src\obj\*\ifsutil.lib \
+ ..\ufat\src\obj\*\ufat.lib
+
+USE_CRTDLL=1
+DLLENTRY=InitializeCudbfs
+
+SOURCES= \
+ cudbfs.cxx \
+ cudbfs.rc \
+ dbfsconv.cxx\
+ secmap.cxx \
+ treemap.cxx
+
+
+INCLUDES=.;..\ufat\inc;..\ulib\inc;..\ifsutil\inc;\nt\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DNOMINMAX -DDBG -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DNOMINMAX -DDBG -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DNOMINMAX -DDBG -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DNOMINMAX -DUNICODE=1
+!ENDIF
+
+UMLIBS=obj\*\cudbfs.lib
+CXXFLAGS=+d
+UMTYPE=console
+UMRES=obj\*\cudbfs.res
+DLLDEF=cudbfs.def
diff --git a/private/utils/cudbfs/treemap.cxx b/private/utils/cudbfs/treemap.cxx
new file mode 100644
index 000000000..1c7290ce1
--- /dev/null
+++ b/private/utils/cudbfs/treemap.cxx
@@ -0,0 +1,219 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ treemap.cxx
+
+Abstract:
+
+Author:
+
+ Matthew Bradburn (mattbr) 01-Dec-1993
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include "treemap.hxx"
+
+BOOLEAN
+TREE_MAP::Initialize(
+ USHORT size
+ )
+/*++
+
+Routine Description:
+
+ This routine ...
+
+Arguments:
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure.
+
+--*/
+{
+ _map = (PTREE_MAP_ENTRY) MALLOC(size * sizeof(TREE_MAP_ENTRY));
+ if (NULL == _map) {
+ return FALSE;
+ }
+ memset(_map, 0, size * sizeof(TREE_MAP_ENTRY));
+ _size = 0;
+ _max_size = size;
+ return TRUE;
+}
+
+VOID
+TREE_MAP::SetEntry(USHORT child, USHORT parent)
+{
+ USHORT i;
+
+ i = QueryEntry(child);
+ if (0 != i) {
+ _map[i].parent = parent;
+ }
+
+ //
+ // There is no such child in the map. Stick it in, making room
+ // if necessary.
+ //
+
+ for (i = 0; i < _size; ++i) {
+ if (_map[i].child > child) {
+ // insert the new entry here
+
+ DbgAssert(_size < _max_size);
+ _size++;
+
+ memmove(&_map[i + 1], &_map[i], (_size - i)*sizeof(TREE_MAP_ENTRY));
+ _map[i].child = child;
+ _map[i].parent = parent;
+
+ return;
+ }
+ }
+
+ // the new entry goes after all the existing entries.
+
+ DbgAssert(_size < _max_size);
+
+ _map[_size].child = child;
+ _map[_size].parent = parent;
+
+ _size++;
+}
+
+USHORT
+TREE_MAP::DeleteEntry(
+ USHORT child
+ )
+/*++
+
+Routine Description:
+
+ This routine deletes the entry that points from the given
+ child to it's parent.
+
+Arguments:
+
+ The child to delete.
+
+Return Value:
+
+ The dead child's parent. 0 is returned if there was no entry
+ for the given child.
+
+--*/
+{
+ USHORT i;
+ USHORT parent;
+
+ for (i = 0; i < _size; ++i) {
+ if (_map[i].child == child) {
+ break;
+ }
+ if (_map[i].child > child) {
+ return 0;
+ }
+ }
+ if (i == _size) {
+ return 0;
+ }
+
+ _size--;
+
+ if (i == _size) {
+ //
+ // Deleting the last entry.
+ //
+ return _map[i].parent;
+ }
+
+ parent = _map[i].parent;
+
+ memmove(&_map[i], &_map[i + 1], (_size - i)*sizeof(TREE_MAP_ENTRY));
+
+ return parent;
+}
+
+
+USHORT
+TREE_MAP::QueryEntry(
+ USHORT child
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine does a binary search for the given child, and returns
+ the corresponding parent.
+
+Arguments:
+
+Return Value:
+
+ 0 - if there is no mapping for the child
+ otherwise - the corresponding parent.
+
+--*/
+{
+ int bottom, top, middle;
+
+ if (0 == _size) {
+ return 0;
+ }
+
+ bottom = 0;
+ top = _size - 1;
+
+ for (;;) {
+ if (bottom > top) {
+ // not found
+ return 0;
+ }
+
+ middle = (bottom + top) / 2;
+
+ if (_map[middle].child < child) {
+ // go to the high side
+
+ bottom = middle + 1;
+ continue;
+ }
+
+ if (_map[middle].child > child) {
+ // go to the low side
+
+ top = middle - 1;
+
+ if (top < 0) {
+ return 0;
+ }
+ continue;
+ }
+
+ // bingo
+ break;
+ }
+
+ return _map[middle].parent;
+}
+
+VOID
+TREE_MAP::ReplaceParent(
+ USHORT OldParent,
+ USHORT NewParent
+ )
+{
+ for (ULONG i = 0; i < _size; ++i) {
+ if (_map[i].parent == OldParent) {
+ _map[i].parent = NewParent;
+ }
+ }
+}
diff --git a/private/utils/cudbfs/treemap.hxx b/private/utils/cudbfs/treemap.hxx
new file mode 100644
index 000000000..2b73a785b
--- /dev/null
+++ b/private/utils/cudbfs/treemap.hxx
@@ -0,0 +1,71 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ treemap.hxx
+
+Abstract:
+
+ Map files to their parent directory, by starting sector number.
+ The entries are packed into an array, sorted. We binary search
+ to find the key.
+
+Author:
+
+ Matthew Bradburn (mattbr) 01-Dec-1993
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include "ulib.hxx"
+
+DECLARE_CLASS(TREE_MAP_ENTRY);
+DECLARE_CLASS(TREE_MAP);
+
+class TREE_MAP_ENTRY {
+public:
+ USHORT child;
+ USHORT parent;
+};
+
+
+class TREE_MAP {
+public:
+
+ BOOLEAN
+ Initialize(
+ USHORT size
+ );
+
+ VOID
+ SetEntry(
+ USHORT child,
+ USHORT parent
+ );
+
+ USHORT
+ QueryEntry(
+ USHORT child
+ ) CONST;
+
+ VOID
+ ReplaceParent(
+ USHORT OldParent,
+ USHORT NewParent
+ );
+
+ USHORT
+ DeleteEntry(
+ USHORT child
+ );
+
+private:
+ TREE_MAP_ENTRY* _map;
+ USHORT _size;
+ USHORT _max_size;
+};
diff --git a/private/utils/cufat/dirs b/private/utils/cufat/dirs
new file mode 100644
index 000000000..c4db5a979
--- /dev/null
+++ b/private/utils/cufat/dirs
@@ -0,0 +1,16 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+!ENDIF
+
+DIRS= src
diff --git a/private/utils/cufat/inc/convfat.hxx b/private/utils/cufat/inc/convfat.hxx
new file mode 100644
index 000000000..a77700fb3
--- /dev/null
+++ b/private/utils/cufat/inc/convfat.hxx
@@ -0,0 +1,44 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ convertfat.hxx
+
+Abstract:
+
+ This module contains the prototype of the ConvertFAT function
+
+Author:
+
+ Ramon J. San Andres (ramonsa) 23-Sep-1991
+
+--*/
+
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( WSTRING );
+DECLARE_CLASS( MESSAGE );
+
+
+BOOLEAN
+FAR APIENTRY
+ConvertFATVolume(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN PCWSTRING TargetFileSystem,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ IN BOOLEAN Pause,
+ OUT PCONVERT_STATUS Status
+ );
+
+extern "C" BOOLEAN
+FAR APIENTRY
+ConvertFAT(
+ IN PCWSTRING NtDriveName,
+ IN PCWSTRING TargetFileSystem,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ IN BOOLEAN Pause,
+ OUT PCONVERT_STATUS Status
+ );
diff --git a/private/utils/cufat/inc/fatntfs.hxx b/private/utils/cufat/inc/fatntfs.hxx
new file mode 100644
index 000000000..f2bf100e8
--- /dev/null
+++ b/private/utils/cufat/inc/fatntfs.hxx
@@ -0,0 +1,375 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ fatntfs.hxx
+
+Abstract:
+
+ This module implements the FAT_NTFS conversion class.
+
+Author:
+
+ Ramon J. San Andres (ramonsa) 23-Sep-1991
+
+--*/
+
+#if !defined( _FAT_NTFS_)
+
+#define _FATNTFS_
+
+//
+// ULIB header files
+//
+#include "volume.hxx"
+#include "ifsentry.hxx"
+
+// IFSUTIL header files
+
+#include "numset.hxx"
+
+//
+// FAT header files
+//
+#include "fat.hxx"
+#include "rfatsa.hxx"
+#include "eaheader.hxx"
+#include "easet.hxx"
+
+//
+// NTFS header files
+//
+#include "untfs.hxx"
+#include "frs.hxx"
+#include "mft.hxx"
+#include "mftfile.hxx"
+#include "mftref.hxx"
+#include "ntfsbit.hxx"
+#include "ntfssa.hxx"
+#include "attrdef.hxx"
+#include "badfile.hxx"
+#include "bootfile.hxx"
+#include "bitfrs.hxx"
+#include "indxtree.hxx"
+#include "upcase.hxx"
+
+
+
+//
+// Length of a buffer containing an file name.
+//
+#define NAMEBUFFERSIZE 255
+
+
+//
+// Forward references
+//
+DECLARE_CLASS( EA_HEADER );
+DECLARE_CLASS( FATDIR );
+DECLARE_CLASS( REAL_FAT_SA );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( MESSAGE );
+DECLARE_CLASS( FAT_NTFS );
+DECLARE_CLASS( NTFS_INDEX_TREE );
+DECLARE_CLASS( NTFS_FILE_RECORD_SEGMENT );
+
+
+class FAT_NTFS : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( FAT_NTFS );
+
+ VIRTUAL
+ ~FAT_NTFS (
+ );
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT PREAL_FAT_SA FatSa,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN BOOLEAN Verbose DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Convert(
+ OUT PCONVERT_STATUS Status,
+ IN BOOLEAN Pause
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Destroy (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CheckSpaceAndCreateHoles (
+ );
+
+ NONVIRTUAL
+ LCN
+ FatClusterToLcn (
+ IN USHORT Cluster
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ConvertDirectory (
+ IN PFATDIR Directory,
+ IN PFAT_DIRENT DirEntry,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT FrsDir
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ConvertDir (
+ IN PFATDIR Directory,
+ IN OUT PNTFS_INDEX_TREE Index,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT FrsDir
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ConvertExtendedAttributes (
+ IN PFAT_DIRENT Dirent,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT Frs
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ConvertExtendedAttributes (
+ IN OUT PNTFS_FILE_RECORD_SEGMENT Frs,
+ IN USHORT EaSetClusterNumber
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ConvertFile (
+ IN PFAT_DIRENT Dirent,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT File
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ConvertFileData (
+ IN PFAT_DIRENT Dirent,
+ IN PNTFS_FILE_RECORD_SEGMENT Frs
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ConvertFileDataNonResident (
+ IN PFAT_DIRENT Dirent,
+ IN PNTFS_FILE_RECORD_SEGMENT Frs
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ConvertFileDataResident (
+ IN PFAT_DIRENT Dirent,
+ IN PNTFS_FILE_RECORD_SEGMENT Frs
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ConvertFileSystem (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ConvertOneExtendedAttribute (
+ IN OUT PNTFS_FILE_RECORD_SEGMENT Frs,
+ IN PEA Ea
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ConvertRoot (
+ IN PFATDIR Directory
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CreateBitmaps (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CreateElementary (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FreeReservedSectors (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ MakeDirectoryFrs (
+ IN PFAT_DIRENT Dirent,
+ IN PNTFS_FILE_RECORD_SEGMENT ParentFrs,
+ OUT PNTFS_FILE_RECORD_SEGMENT FrsDir,
+ OUT PNTFS_INDEX_TREE RootIndex
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryNeededHoles (
+ OUT PINTSTACK HoleStack
+ );
+
+ NONVIRTUAL
+ VOID
+ QuerySectorsNeededForConversion (
+ IN PCENSUS_REPORT Census,
+ IN PBIG_INT SectorsNeeded
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ReserveCluster (
+ IN USHORT Cluster
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CheckGeometryMatch(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ WriteBoot (
+ IN BOOLEAN Pause
+ );
+
+ //
+ // FAT stuff
+ //
+ PREAL_FAT_SA _FatSa; // Fat SuperArea
+ HMEM _EAMemory; // Mem for EAHeader
+ EA_HEADER _EAHeader; // EA header
+ USHORT _EAFileFirstCluster; // EA file starting cluster
+
+ //
+ // NTFS stuff
+ //
+ NTFS_SA _NtfsSa; // NTFS SuperArea
+ ULONG _ClusterFactor; // Cluster factor
+ ULONG _ClustersPerIndexBuffer;// Default clusters per index buffer
+
+ NTFS_BITMAP _ReservedBitmap; // Bitmap of reserved sectors
+ NTFS_BITMAP _VolumeBitmap; // Volume Bitmap
+ NTFS_UPCASE_TABLE _UpcaseTable; // Volume upcase table.
+ NUMBER_SET _BadLcn; // Bad clusters
+ ULONG _LogFileClusters; // Size of Log File
+ NTFS_MFT_FILE _Mft; // Master File Table File
+ DSTRING _RootIndexName; // Root index name
+ ULONG _FrsSize;
+
+ //
+ // Other stuff
+ //
+ PLOG_IO_DP_DRIVE _Drive; // Drive
+ PMESSAGE _Message; // Message
+ CONVERT_STATUS _Status; // Conversion status
+ BOOLEAN _Verbose; // Verbose flag
+ ULONG _NumberOfFiles; // Number of files on disk
+ ULONG _NumberOfDirectories; // Number of dirs on disk
+ LCN _FreeSectorsBefore; // Free sectors before conversion
+ LCN _FreeSectorsAfter; // Free sectors after conversion
+ PFILE_NAME _FileNameBuffer; // Buffer for file name attribute
+
+#if DBG
+ //
+ // Debug stuff
+ //
+ NONVIRTUAL
+ VOID
+ PrintAtLevel (
+ );
+#endif
+
+ ULONG _Level; // Indentation level for verbose output
+
+};
+
+
+
+INLINE
+LCN
+FAT_NTFS::FatClusterToLcn (
+ IN USHORT Cluster
+ )
+
+/*++
+
+Routine Description:
+
+ Converts a FAT cluster to an LCN
+
+Arguments:
+
+ Cluster - Supplies the cluster number
+
+Return Value:
+
+ LCN - The first LCN of the cluster
+
+--*/
+
+{
+ return _FatSa->QueryStartDataLbn() + (Cluster - FirstDiskCluster) * _FatSa->QuerySectorsPerCluster();
+
+}
+
+
+#if DBG
+
+INLINE
+VOID
+FAT_NTFS::PrintAtLevel (
+ )
+
+/*++
+
+Routine Description:
+
+ Prints a certain number of spaces corresponding to the value of
+ _Level. Is used to print the directory structure on the debug
+ terminal in a nice way.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG l = _Level;
+
+ while ( l-- ) {
+ DebugPrintf( " " );
+ }
+}
+
+#endif // DBG
+
+
+#endif // _FAT_NTFS_
diff --git a/private/utils/cufat/inc/fatofs.hxx b/private/utils/cufat/inc/fatofs.hxx
new file mode 100644
index 000000000..aca95603c
--- /dev/null
+++ b/private/utils/cufat/inc/fatofs.hxx
@@ -0,0 +1,70 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ fatofs.hxx
+
+Abstract:
+
+ Export for FAT->OFS Conversion
+
+Author:
+
+ Srikanth Shoroff (srikants) August 22, 1995
+
+Notes:
+
+--*/
+
+#if !defined(__FATOFS_HXX__)
+
+#define __FATOFS_HXX__
+extern "C"
+{
+
+class MESSAGE;
+
+#if !defined(_AUTOCHECK_)
+#define FAT_TO_OFS_DLL_NAME L"OFSUTIL"
+#else
+#define FAT_TO_OFS_DLL_NAME L"AOFSUTIL"
+#endif // _AUTOCHECK
+
+#define FAT_TO_OFS_FUNCTION_NAME L"ConvertFatToOfs"
+#define FAT_TO_OFS_RESTART_FUNCTION_NAME L"IsFatToOfsRestart"
+
+typedef enum _FAT_OFS_CONVERT_STATUS
+{
+ FAT_OFS_CONVERT_SUCCESS = 1,
+ FAT_OFS_CONVERT_FAILED
+} FAT_OFS_CONVERT_STATUS, *PFAT_OFS_CONVERT_STATUS;
+
+BOOLEAN
+FAR APIENTRY
+ConvertFatToOfs(
+ IN PCWSTR pwszNtDriveName,
+ IN OUT MESSAGE * pMessage,
+ IN BOOLEAN fVerbose,
+ IN BOOLEAN fInSetup,
+ OUT PFAT_OFS_CONVERT_STATUS pStatus
+ );
+
+typedef BOOLEAN(FAR APIENTRY * FAT_OFS_CONVERT_FN)( PCWSTR,
+ MESSAGE *,
+ BOOLEAN,
+ BOOLEAN,
+ PFAT_OFS_CONVERT_STATUS );
+
+BOOLEAN
+FAR APIENTRY
+IsFatToOfsRestart(
+ IN PCWSTR pwszNtDriveName
+ );
+
+typedef BOOLEAN(FAR APIENTRY * FAT_OFS_RESTART_FN) ( PCWSTR );
+
+}
+
+#endif // __FATOFS_HXX__
diff --git a/private/utils/cufat/src/convfat.cxx b/private/utils/cufat/src/convfat.cxx
new file mode 100644
index 000000000..24ee48710
--- /dev/null
+++ b/private/utils/cufat/src/convfat.cxx
@@ -0,0 +1,589 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ entry.cxx
+
+Abstract:
+
+ This module contains the Convert entry point for CUFAT.DLL.
+
+Author:
+
+ Ramon San Andres (ramonsa) Sep-19-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#include "ulib.hxx"
+#include "error.hxx"
+#include "drive.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+#include "fatntfs.hxx"
+#include "convfat.hxx"
+#include "rwcache.hxx"
+#include "rfatsa.hxx"
+
+#if !defined(_AUTOCHECK_) && !defined(_SETUP_LOADER_)
+
+#include "fatofs.hxx" // FAT->OFS Conversion
+#include "system.hxx"
+
+#endif // _AUTOCHECK_ || _SETUP_LOADER_
+
+//
+// This file maintains a table that maps file system names to
+// conversion functions. The Convert entry point looks up the
+// target file name system in the table, if found, then it calls
+// the corresponding conversion function. This data-driven scheme
+// makes it easy to add new conversions to the library, since no
+// code has to be changed.
+//
+// The code & data for performing a particular conversion are
+// contained in a class. This avoids name conflicts and lets us
+// have the global data for each conversion localized.
+//
+// Each conversion function will typically just initialize
+// the appropriate conversion object and invoke its conversion
+// method.
+//
+
+
+
+//
+// A FAT_CONVERT_FN is a pointer to a conversion function.
+//
+typedef BOOLEAN(FAR APIENTRY * FAT_CONVERT_FN)( PLOG_IO_DP_DRIVE,
+ PREAL_FAT_SA,
+ PMESSAGE,
+ BOOLEAN,
+ BOOLEAN,
+ PCONVERT_STATUS );
+
+
+
+//
+// Prototypes of conversion functions. Note that all conversion
+// functions must have the same interface since they are all called
+// thru a FAT_CONVERT_FN pointer.
+//
+// Also note that the Drive object passed to the function is
+// LOCKED by the Convert entry point before invoking the function.
+//
+BOOLEAN
+FAR APIENTRY
+ConvertFatToNtfs(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT PREAL_FAT_SA FatSa,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ IN BOOLEAN Pause,
+ OUT PCONVERT_STATUS Status
+ );
+
+
+//
+// The FILESYSTEM_MAP structure is used to map the name of
+// a file system to the function in charge of converting a FAT
+// volume to that particular file system.
+//
+typedef struct _FILESYSTEM_MAP {
+
+ char * FsName; // Name of the file system
+ FAT_CONVERT_FN Function; // Conversion function
+
+} FILESYSTEM_MAP, *PFILESYSTEM_MAP;
+
+// To add a new conversion, create a FAT_CONVERT_FN function
+// for it and add the appropriate entry to the FileSystemMap
+// table.
+//
+// Note that this table contains an entry for every known
+// file system. A NULL entry in the Function field means that
+// the particular conversion is not implemented.
+//
+// This table has to be NULL-terminated.
+//
+FILESYSTEM_MAP FileSystemMap[] = {
+
+ { "NTFS", ConvertFatToNtfs },
+ { "HPFS", NULL },
+ { "FAT", NULL },
+ { "CDFS", NULL },
+ { NULL, NULL }
+};
+
+
+
+BOOLEAN
+FAR APIENTRY
+ConvertFATVolume(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN PCWSTRING TargetFileSystem,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ IN BOOLEAN Pause,
+ OUT PCONVERT_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ This method converts an opened FAT volume to another
+ file system.
+
+Arguments:
+
+ Drive -- Supplies the drive to be converted; note that
+ the drive must already be opened and locked
+ (Convert) or opened for exclusive write access
+ (Autoconvert).
+ TargetFileSyste -- Supplies the name of the file system to which
+ the drive will be converted.
+ Message -- Supplies a channel for messages.
+ Verbose -- Supplies a flag indicating whether convert
+ should run in verbose mode.
+ Pause -- Supplies a flag indicating
+ Status -- Receives the status of the conversion.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ REAL_FAT_SA FatSa; // Fat SuperArea
+ DSTRING FsName; // Filesystem name from table
+ PFILESYSTEM_MAP FsMap; // Maps name->Function
+ PREAD_WRITE_CACHE rwcache;
+
+ DebugPtrAssert( Drive );
+ DebugPtrAssert( TargetFileSystem );
+ DebugPtrAssert( Status );
+
+ // Set up a read-write cache for the volume.
+ //
+ if ((rwcache = NEW READ_WRITE_CACHE) &&
+ rwcache->Initialize(Drive, 75)) {
+
+ Drive->SetCache(rwcache);
+
+ } else {
+
+ DELETE(rwcache);
+ }
+
+
+ //
+ // Find out if the target file system is valid and
+ // if we can convert to it, by looking up the target
+ // file system in the FileSystemMap table.
+ //
+ FsMap = FileSystemMap;
+
+ while ( FsMap->FsName ) {
+
+ //
+ // Initialize FsName to be the name of the file system
+ // in the table entry.
+ //
+ if ( !FsName.Initialize( FsMap->FsName ) ) {
+ Message->Set( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ Message->Display();
+ *Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+ //
+ // If this is the guy we are looking for, we stop searching
+ //
+ if ( *TargetFileSystem == FsName ) {
+
+ break;
+ }
+
+ FsMap++;
+ }
+
+ //
+ // If the target file system is valid, and there is a conversion
+ // for it, lock the drive, initialize the superarea, and
+ // invoke the conversion function.
+ //
+ if ( FsMap->FsName ) {
+
+ if ( FsMap->Function ) {
+
+ if ( FatSa.Initialize( Drive, Message, TRUE ) ||
+ FatSa.Initialize( Drive, Message, FALSE )) {
+
+ if (FatSa.Read( Message )) {
+
+ //
+ // The dive is locked and we have the
+ // FAT superarea. Invoke the conversion
+ // function.
+ //
+
+ return (FsMap->Function)( Drive,
+ &FatSa,
+ Message,
+ Verbose,
+ Pause,
+ Status );
+
+ } else {
+
+ //
+ // Cannot read superarea
+ //
+ *Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+ } else {
+
+ //
+ // Cannot initialize Superarea
+ //
+ *Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+ } else {
+
+ //
+ // The file system is valid, but we don't have a
+ // conversion for it.
+ //
+ *Status = CONVERT_STATUS_CONVERSION_NOT_AVAILABLE;
+ return FALSE;
+ }
+
+ } else {
+
+ //
+ // The file system is not valid
+ //
+ *Status = CONVERT_STATUS_INVALID_FILESYSTEM;
+ return FALSE;
+ }
+
+}
+
+#if !defined(_AUTOCHECK_)
+
+BOOLEAN
+IsTargetOfs(
+ IN PCWSTRING TargetFileSystem )
+{
+ DSTRING Ofs;
+ Ofs.Initialize("OFS");
+
+ return 0 == TargetFileSystem->Stricmp(&Ofs);
+}
+
+BOOLEAN
+IsChkdskOkay(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose
+ )
+{
+ DSTRING libraryName;
+ DSTRING entryPoint;
+ HANDLE fsUtilityHandle;
+
+ libraryName.Initialize( L"UFAT.DLL" );
+ entryPoint.Initialize( L"Chkdsk" );
+ CHKDSK_FN Chkdsk;
+
+ Chkdsk = (CHKDSK_FN)SYSTEM::QueryLibraryEntryPoint(
+ &libraryName, &entryPoint, &fsUtilityHandle );
+
+ if ( NULL == Chkdsk )
+ {
+ //
+ // There is no conversion DLL for the file system in the volume.
+ //
+
+ Message->Set( MSG_FS_NOT_SUPPORTED );
+ Message->Display( "%s%W", "CHKDSK", L"FAT" );
+ Message->Set( MSG_BLANK_LINE );
+ Message->Display( "" );
+
+ return FALSE;
+ }
+
+ ULONG exitStatus;
+
+ Chkdsk( NtDriveName,
+ Message,
+ FALSE, // don't fix - just see if they are consistent
+ Verbose,
+ FALSE, // no recovery
+ FALSE,
+ NULL, // no specific path
+ FALSE, // extend
+ FALSE, // resize logfile
+ 0, // logfile size
+ &exitStatus );
+ SYSTEM::FreeLibraryHandle( fsUtilityHandle );
+
+ if ( CHKDSK_EXIT_SUCCESS != exitStatus )
+ {
+ Message->Set(MSG_CONV_NTFS_CHKDSK);
+ Message->Display();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+ConvertToOfs(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ OUT PCONVERT_STATUS Status
+ )
+{
+ DSTRING libraryName;
+ DSTRING entryPoint;
+ HANDLE fsUtilityHandle;
+
+ libraryName.Initialize( FAT_TO_OFS_DLL_NAME );
+
+ entryPoint.Initialize( FAT_TO_OFS_FUNCTION_NAME );
+
+ FAT_OFS_CONVERT_FN Convert;
+
+ Convert = (FAT_OFS_CONVERT_FN)SYSTEM::QueryLibraryEntryPoint(
+ &libraryName, &entryPoint, &fsUtilityHandle );
+
+ if ( NULL == Convert )
+ {
+ //
+ // There is no conversion DLL for the file system in the volume.
+ //
+ *Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+ PWSTR pwszNtDriveName = NtDriveName->QueryWSTR();
+ FAT_OFS_CONVERT_STATUS cnvStatus;
+ BOOLEAN fResult= Convert( pwszNtDriveName,
+ Message,
+ Verbose,
+ FALSE, // Not in Setup Time
+ &cnvStatus );
+
+ DELETE( pwszNtDriveName );
+ SYSTEM::FreeLibraryHandle( fsUtilityHandle );
+
+ if ( FAT_OFS_CONVERT_SUCCESS == cnvStatus )
+ {
+ *Status = CONVERT_STATUS_CONVERTED;
+ }
+ else
+ {
+ *Status = CONVERT_STATUS_ERROR;
+ }
+
+ return fResult;
+
+}
+
+#endif // _AUTOCHECK_
+
+
+BOOLEAN
+FAR APIENTRY
+ConvertFAT(
+ IN PCWSTRING NtDriveName,
+ IN PCWSTRING TargetFileSystem,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ IN BOOLEAN Pause,
+ OUT PCONVERT_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ Converts a FAT volume to another file system.
+
+Arguments:
+
+ NtDrivName supplies the name of the drive to check
+ TargetFileSystem supplies the name of the target file system
+ Message supplies an outlet for messages
+ Verbose TRUE if should run inv verbose mode
+ Status supplies pointer to convert status code
+
+Return Value:
+
+ BOOLEAN - TRUE if conversion successful
+
+--*/
+{
+ //
+ // If we are converting to OFS, we have to delete the drive before
+ // calling the routine. So, use a pointer instead of a stack object.
+ //
+ LOG_IO_DP_DRIVE * pDrive; // Drive to convert
+
+ DebugPtrAssert( NtDriveName );
+ DebugPtrAssert( TargetFileSystem );
+ DebugPtrAssert( Status );
+
+ pDrive = NEW LOG_IO_DP_DRIVE;
+ if ( NULL == pDrive )
+ {
+ *Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+#if !defined ( _AUTOCHECK_ )
+
+ //
+ // Open the drive and lock it.
+ //
+ if( !pDrive->Initialize( NtDriveName ) ) {
+
+ //
+ // Could not initialize the drive
+ //
+ *Status = CONVERT_STATUS_ERROR;
+ DELETE(pDrive);
+ return FALSE;
+ }
+
+ if( !pDrive->Lock() ) {
+
+ //
+ // Could not lock the volume
+ //
+ *Status = CONVERT_STATUS_CANNOT_LOCK_DRIVE;
+ DELETE(pDrive);
+ return FALSE;
+ }
+
+#else
+
+ // Open the drive for Exclusive Write access.
+ //
+ if( !pDrive->Initialize( NtDriveName, NULL, TRUE ) ) {
+
+ //
+ // Could not initialize the drive
+ //
+ *Status = CONVERT_STATUS_ERROR;
+ DELETE(pDrive);
+ return FALSE;
+ }
+
+#endif
+
+#if !defined ( _AUTOCHECK_ )
+
+ if ( IsTargetOfs( TargetFileSystem ) ) {
+ DELETE (pDrive);
+
+ //
+ // Do a chkdsk before proceeding ahead.
+ //
+ if ( !IsChkdskOkay( NtDriveName, Message, Verbose ) ) {
+ *Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+ else {
+ return ConvertToOfs( NtDriveName, Message, Verbose, Status );
+ }
+ }
+ else
+#endif // !_AUTOCHECK_
+ {
+
+
+ BOOLEAN fResult = ConvertFATVolume( pDrive,
+ TargetFileSystem,
+ Message,
+ Verbose,
+ Pause,
+ Status );
+
+ DELETE( pDrive );
+ return fResult;
+ }
+}
+
+
+BOOLEAN
+FAR APIENTRY
+ConvertFatToNtfs(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT PREAL_FAT_SA FatSa,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ IN BOOLEAN Pause,
+ OUT PCONVERT_STATUS Status
+ )
+
+/*++
+
+Routine Description:
+
+ Converts a FAT volume to NTFS
+
+Arguments:
+
+ Drive supplies pointer to drive
+ FatSa supplies pointer to FAT superarea
+ Message supplies an outlet for messages
+ Verbose TRUE if should run inv verbose mode
+ Status supplies pointer to convert status code
+
+Return Value:
+
+ BOOLEAN - TRUE if conversion successful
+
+Notes:
+
+ The volume is locked on entry. The FAT superarea has
+ been read.
+
+--*/
+
+{
+ FAT_NTFS FatNtfs; // FAT-NTFS conversion object
+
+ DebugPrintf( "CONVERT: Converting FAT volume to NTFS\n");
+
+ //
+ // Initialize the conversion object and invoke its
+ // conversion method.
+ //
+
+ if ( FatNtfs.Initialize( Drive, FatSa, Message, Verbose )) {
+
+ return FatNtfs.Convert( Status, Pause );
+
+ } else {
+
+ //
+ // Could not initialize FAT_NTFS object
+ //
+ *Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+}
diff --git a/private/utils/cufat/src/cufat.cxx b/private/utils/cufat/src/cufat.cxx
new file mode 100644
index 000000000..a89956850
--- /dev/null
+++ b/private/utils/cufat/src/cufat.cxx
@@ -0,0 +1,122 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Cufat.cxx
+
+Abstract:
+
+ This module contains run-time, global support for the
+ FAT Conversion library (CUFAT). This support includes:
+
+ - creation of CLASS_DESCRIPTORs
+ - Global objects
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 23-Sep-1991
+
+Environment:
+
+ User Mode
+
+Notes:
+
+--*/
+
+#include <pch.cxx>
+
+#include "ulib.hxx"
+
+#include "error.hxx"
+
+#if !defined( _AUTOCONV_ )
+
+ ERRSTACK* perrstk;
+
+#endif // _AUTOCONV_
+
+//
+// Local prototypes
+//
+STATIC
+BOOLEAN
+DefineClassDescriptors(
+ );
+
+extern "C" BOOLEAN
+InitializeCufat (
+ PVOID DllHandle,
+ ULONG Reason,
+ PCONTEXT Context
+ );
+
+BOOLEAN
+InitializeCufat (
+ PVOID DllHandle,
+ ULONG Reason,
+ PCONTEXT Context
+ )
+/*++
+
+Routine Description:
+
+ Initialize Cufat by constructing and initializing all
+ global objects. These include:
+
+ - all CLASS_DESCRIPTORs (class_cd)
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if all global objects were succesfully constructed
+ and initialized.
+
+--*/
+
+{
+
+ STATIC BOOLEAN fInit = FALSE;
+
+ if ( fInit ) {
+
+ return( TRUE );
+ }
+
+ if ( DefineClassDescriptors() ) {
+
+ fInit = TRUE;
+ return TRUE;
+
+ } else {
+
+ DebugAbort( "Cufat initialization failed!!!\n" );
+ return( FALSE );
+ }
+}
+
+
+
+DECLARE_CLASS( FAT_NTFS );
+
+
+STATIC
+BOOLEAN
+DefineClassDescriptors(
+ )
+{
+ if ( DEFINE_CLASS_DESCRIPTOR( FAT_NTFS ) &&
+ TRUE ) {
+ return TRUE;
+
+ } else {
+
+ DebugPrint( "Could not initialize class descriptors!");
+ return FALSE;
+ }
+}
diff --git a/private/utils/cufat/src/cufat.def b/private/utils/cufat/src/cufat.def
new file mode 100644
index 000000000..f22ba393d
--- /dev/null
+++ b/private/utils/cufat/src/cufat.def
@@ -0,0 +1,8 @@
+LIBRARY CUFAT
+
+DESCRIPTION File System Conversion Library for FAT
+
+DATA NONSHARED
+
+EXPORTS
+ ConvertFAT
diff --git a/private/utils/cufat/src/cufat.rc b/private/utils/cufat/src/cufat.rc
new file mode 100644
index 000000000..8cb6868b8
--- /dev/null
+++ b/private/utils/cufat/src/cufat.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "FAT File System Conversion Utility DLL"
+#define VER_INTERNALNAME_STR "cnvfat\0"
+#define VER_ORIGINALFILENAME_STR "CNVFAT.DLL"
+
+#include "common.ver"
diff --git a/private/utils/cufat/src/fatntfs.cxx b/private/utils/cufat/src/fatntfs.cxx
new file mode 100644
index 000000000..8c7d6cca1
--- /dev/null
+++ b/private/utils/cufat/src/fatntfs.cxx
@@ -0,0 +1,2568 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ fatntfs.cxx
+
+Abstract:
+
+ This module implements the conversion from FAT to NTFS
+
+Author:
+
+ Ramon J. San Andres (ramonsa) Sep-19-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+
+#include <pch.cxx>
+
+//
+// ULIB include files
+//
+#define _NTAPI_ULIB_
+#include "ulib.hxx"
+#include "array.hxx"
+#include "drive.hxx"
+#include "hmem.hxx"
+#include "wstring.hxx"
+#include "rtmsg.h"
+
+//
+// IFSUTIL include files
+//
+#include "secrun.hxx"
+
+#if defined ( _AUTOCONV_ )
+#include "ifssys.hxx"
+#endif
+
+//
+// CUFAT include files
+//
+#include "fatntfs.hxx"
+
+//
+// UFAT include files
+//
+#include "fatdent.hxx"
+#include "fatdir.hxx"
+#include "filedir.hxx"
+
+//
+// UNTFS include files
+//
+#include "attrib.hxx"
+#include "upfile.hxx"
+#include "logfile.hxx"
+#include "ntfssa.hxx"
+
+//
+// The number of bytes in the copy of the boot sector at sector n/2.
+//
+#define BYTES_IN_EXTRA_BOOT_SECTOR 512
+
+
+//
+// Number of sectors in boot sector
+//
+#define SECTORS_IN_BOOT ((BYTES_IN_BOOT_AREA + _Drive->QuerySectorSize() - 1)/ \
+ _Drive->QuerySectorSize())
+
+#define SECTORS_IN_EXTRA_BOOT ((BYTES_IN_EXTRA_BOOT_SECTOR + _Drive->QuerySectorSize() - 1)/ \
+ _Drive->QuerySectorSize())
+
+
+
+DEFINE_CONSTRUCTOR( FAT_NTFS, OBJECT );
+
+
+
+VOID
+FAT_NTFS::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Constructs a FAT_NTFS object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _FatSa = NULL;
+ _Drive = NULL;
+ _Message = NULL;
+ _FileNameBuffer = NULL;
+}
+
+
+
+VOID
+FAT_NTFS::Destroy (
+ )
+/*++
+
+Routine Description:
+
+ Destroys a FAT_NTFS object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DELETE( _FatSa );
+ DELETE( _Drive );
+ DELETE( _Message );
+ DELETE( _FileNameBuffer );
+}
+
+
+
+
+
+FAT_NTFS::~FAT_NTFS (
+ )
+/*++
+
+Routine Description:
+
+ Destructor for FAT_NTFS.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+}
+
+
+BOOLEAN
+FAT_NTFS::Initialize(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT PREAL_FAT_SA FatSa,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose
+ )
+/*++
+
+Routine Description:
+
+ Initializes a FAT_NTFS object
+
+Arguments:
+
+ FatVol - Supplies the FAT volume
+ Message - Supplies message object
+ Verbose - Supplies verbose flag
+
+Return Value:
+
+ BOOLEAN - TRUE if successfully initialized, FALSE otherwise
+
+--*/
+
+{
+ DebugPtrAssert( Drive );
+ DebugPtrAssert( FatSa );
+ DebugPtrAssert( Message );
+
+ //
+ // Initialize the stuff passed as argument
+ //
+ _FatSa = FatSa;
+ _Drive = Drive;
+ _Message = Message;
+ _Verbose = Verbose;
+
+ // Floppies cannot be converted to NTFS.
+ //
+ if( _Drive->IsFloppy() ) {
+
+ Message->Set(MSG_NTFS_FORMAT_NO_FLOPPIES);
+ Message->Display();
+ return FALSE;
+ }
+
+ // To protect ourselves from disk drivers that cannot
+ // correctly determine the disk geometry, compare the
+ // boot-code-critical values from the existing BPB with
+ // the drive's values. If they don't match, we can't
+ // convert this drive because if it's the system partition,
+ // the system won't boot.
+ //
+ if( !CheckGeometryMatch( ) ) {
+
+ _Message->Set( MSG_CONV_GEOMETRY_MISMATCH );
+ _Message->Display( "%s", "NTFS" );
+ return FALSE;
+ }
+
+ //
+ // FAT clusters are not alligned, so having an NTFS cluster
+ // factor != 1 would make the conversion extremely
+ // complicated.
+ //
+ // Do not change this value unless you rewrite the conversion
+ // code to handle other values!
+ //
+ _ClusterFactor = 1;
+
+ _FrsSize = SMALL_FRS_SIZE;
+
+ // Set the default number of clusters per Index Allocation Buffer
+ // to a useful value.
+ //
+ _ClustersPerIndexBuffer = NTFS_SA::QueryDefaultClustersPerIndexBuffer(
+ _Drive, _ClusterFactor);
+
+ //
+ // _NumberOfFiles and _NumberOfDirectories are used to extend
+ // the MFT when we know how many files there are in the volume.
+ // Unless we do a volume census these values must be zero.
+ //
+ _NumberOfFiles = 0;
+ _NumberOfDirectories = 0;
+
+ // Allocate space for the file name attribute buffer and initialize
+ // the NTFS superarea and the Bad LCN stack.
+ //
+
+ if( (
+
+ _FileNameBuffer =
+ (PFILE_NAME)MALLOC( sizeof(FILE_NAME) +
+ sizeof(WCHAR) * NAMEBUFFERSIZE )) == NULL ||
+ !_RootIndexName.Initialize( FileNameIndexNameData ) ||
+ !_NtfsSa.Initialize( _Drive, _Message ) ||
+ !_BadLcn.Initialize() ) {
+ _Message->Set( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ _Message->Display();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+
+BOOLEAN
+FAT_NTFS::Convert(
+ OUT PCONVERT_STATUS Status,
+ IN BOOLEAN Pause
+ )
+
+/*++
+
+Routine Description:
+
+ Converts a FAT volume to NTFS
+
+Arguments:
+
+ Status - Supplies pointer to conversion status
+
+Return Value:
+
+ BOOLEAN - TRUE if successfully converted, FALSE otherwise
+
+--*/
+
+{
+ BOOLEAN Converted;
+
+ DebugPtrAssert( Status );
+
+#if defined ( _AUTOCONV_ )
+
+ _Message->Set( MSG_CONV_WILL_REBOOT );
+ _Message->Display();
+
+#endif // _AUTOCONV_
+
+ //
+ // The conversion from FAT to NTFS consists of a sequence of well-defined
+ // steps:
+ //
+ // 1.- Create holes (i.e. relocate FAT clusters) for fixed-location
+ // NTFS structures and save FAT.
+ //
+ // 2.- Create NTFS elementary data structures in FAT free space
+ //
+ // 3.- Convert the File system, creating the NTFS file system in
+ // the FAT free space.
+ //
+ // 4.- Mark as free in the NTFS bitmap those NTFS clusters being used
+ // by FAT-specific structures.
+ //
+ // 5.- Write NTFS boot sector
+ //
+ //
+ // Since a crash can occur at any time, we must minimize the chance of
+ // disk corruption. Note that (almost) all writes are to FAT free space,
+ // so a crash will preserve the FAT intact.
+ //
+ // The only times at which we write to non-free space, i.e. the times at
+ // which a crash might cause problems are:
+ //
+ // a.- At the end of step 1, when we overwrite the FAT. The algorithm
+ // for relocating clusters (in UFAT) guarantees that CHKDSK will be
+ // able to fix the disk without any loss of data.
+ //
+ // b.- In step 5, while writting the boot sector. If a crash occurs during
+ // this step, We're out of luck.
+ //
+ //
+ Converted = (BOOLEAN)( //
+ // Create holes for fixed-location structures
+ //
+ CheckSpaceAndCreateHoles( ) &&
+ //
+ // Initialize the bitmaps
+ //
+ CreateBitmaps( ) &&
+ //
+ // Create the NTFS elementary data structures
+ //
+ CreateElementary( ) &&
+ //
+ // Convert the file system
+ //
+ ConvertFileSystem( ) &&
+ //
+ // Mark the reserved sectors as free
+ //
+ FreeReservedSectors( ) &&
+ //
+ // Volume converted, write the boot code
+ //
+ WriteBoot( Pause ) );
+
+ *Status = _Status;
+
+ return Converted;
+}
+
+
+
+
+BOOLEAN
+FAT_NTFS::CheckSpaceAndCreateHoles (
+ )
+
+/*++
+
+Routine Description:
+
+ Determines free space requirements, makes sure that there is
+ enough space for conversion, and makes holes. All this
+ is done in one step so that we only have to traverse the
+ file system once.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ BOOLEAN - TRUE if there is enough space for conversion and
+ the holes are in place.
+ FALSE otherwise
+
+--*/
+
+{
+ INTSTACK HoleStack; // Stack of holes
+ CENSUS_REPORT CensusReport; // Census report
+ PCENSUS_REPORT Census; // Pointer to census report
+ BIG_INT SectorsTotal; // Number of sectors on the volume
+ BIG_INT SectorsFree; // Free sectors on the volume
+ BIG_INT SectorsNeeded; // Sectors needed by conversion
+ BIG_INT KbytesTotal;
+ BIG_INT KbytesFree;
+ BIG_INT KbytesNeeded;
+ BOOLEAN Relocated; // TRUE if relocated sectors
+
+ //
+ // Identify all the "holes" that we need i.e. all those spots
+ // that are used by NTFS structures that need to be at a fixed
+ // location.
+ //
+ //
+ if ( !QueryNeededHoles( &HoleStack ) ) {
+ return FALSE;
+ }
+
+ SectorsTotal = _Drive->QuerySectors();
+ SectorsFree = _FatSa->QueryFreeSectors();
+ // Census = ( SectorsFree > ( SectorsTotal / 2 ) ) ? NULL : &CensusReport;
+ Census = &CensusReport;
+ Relocated = FALSE;
+
+ //
+ // Create the holes and obtain the census if necessary
+ //
+ _Message->Set( MSG_CONV_CHECKING_SPACE );
+ _Message->Display();
+
+ if ( !_FatSa->QueryCensusAndRelocate( Census, &HoleStack, &Relocated )) {
+
+ _Message->Set( MSG_CONV_NO_DISK_SPACE, ERROR_MESSAGE );
+ _Message->Display();
+ _Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+#if defined ( _AUTOCONV_ )
+
+ //
+ // If relocated sectors, then we will be overwritting data that might
+ // be needed by the system. In order to avoid this, we reboot so that
+ // the system will read its stuff from the new locations.
+ //
+ if ( Relocated ) {
+
+ _Drive->FlushCache();
+ IFS_SYSTEM::Reboot();
+ //
+ // If we reach this point, the reboot failed and we should not
+ // continue the conversion.
+ //
+ _Message->Set( MSG_CONV_CANNOT_RELOCATE, ERROR_MESSAGE );
+ _Message->Display();
+ _Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+
+#endif
+
+ //
+ // Determine the number of sectors needed for the conversion
+ //
+ if ( Census ) {
+
+ //
+ // Estimate the number of sectors needed based on the
+ // volume census.
+ //
+ QuerySectorsNeededForConversion( Census, &SectorsNeeded );
+
+ } else {
+
+ //
+ // We'll say that we need half of the disk
+ //
+ SectorsNeeded = SectorsTotal / 2;
+ }
+
+ KbytesTotal = SectorsTotal * _Drive->QuerySectorSize() / 1024;
+ KbytesFree = SectorsFree * _Drive->QuerySectorSize() / 1024;
+ KbytesNeeded = SectorsNeeded * _Drive->QuerySectorSize() / 1024;
+
+ _Message->Set( MSG_CONV_KBYTES_TOTAL );
+ _Message->Display( "%8d", KbytesTotal.GetLowPart() );
+ _Message->Set( MSG_CONV_KBYTES_FREE );
+ _Message->Display( "%8d", KbytesFree.GetLowPart() );
+ _Message->Set( MSG_CONV_KBYTES_NEEDED );
+ _Message->Display( "%8d", KbytesNeeded.GetLowPart() );
+
+
+ if ( SectorsFree < SectorsNeeded ) {
+ //
+ // Not enough disk space for conversion
+ //
+ _Message->Set( MSG_CONV_NO_DISK_SPACE, ERROR_MESSAGE );
+ _Message->Display();
+ _Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+
+ //
+ // The disk has enough disk space.
+ //
+ return TRUE;
+}
+
+
+BOOLEAN
+FAT_NTFS::ConvertRoot (
+ IN PFATDIR Directory
+ )
+
+/*++
+
+Routine Description:
+
+ Converts the FAT root directory and recursively all its
+ subdirectories.
+
+ This is basically the same as the ConvertDirectory method, the
+ differences being:
+
+ 1.- The index for the root has already been created by
+ NTFS_SA::CreateElementaryStructures()
+
+ 2.- No FRS is created
+
+ 3.- ConvertRoot does some extra checkings for
+ EA file (which is at the root level only).
+
+
+Arguments:
+
+ Directory - Supplies root directory.
+
+Return Value:
+
+ BOOLEAN - TRUE if root directory successfully converted
+ FALSE otherwise
+
+--*/
+
+{
+ NTFS_FILE_RECORD_SEGMENT FrsOfRootIndex; // FRS of NTFS root index
+ NTFS_INDEX_TREE RootIndex; // Root index
+ BOOLEAN Converted;
+
+
+ DebugPtrAssert( Directory );
+
+ _Level = 0;
+
+ //
+ // Obtain the NTFS root index
+ //
+ if ( !FrsOfRootIndex.Initialize( ROOT_FILE_NAME_INDEX_NUMBER, &_Mft ) ||
+ !FrsOfRootIndex.Read() ||
+ !RootIndex.Initialize( _Drive,
+ _ClusterFactor,
+ &_VolumeBitmap,
+ FrsOfRootIndex.GetUpcaseTable(),
+ FrsOfRootIndex.QueryMaximumAttributeRecordSize()/2,
+ &FrsOfRootIndex,
+ &_RootIndexName )
+ ) {
+
+ _Message->Set( MSG_CONV_CANNOT_MAKE_INDEX, ERROR_MESSAGE );
+ _Message->Display();
+ _Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+ //
+ // Convert the directory
+ //
+ if ( Converted = ConvertDir( Directory, &RootIndex, &FrsOfRootIndex )) {
+ //
+ // Save the index
+ //
+ if ( !RootIndex.Save( &FrsOfRootIndex ) ||
+ !FrsOfRootIndex.Flush( &_VolumeBitmap ) ) {
+
+ _Message->Set( MSG_CONV_CANNOT_WRITE, ERROR_MESSAGE );
+ _Message->Display();
+ _Status = CONVERT_STATUS_ERROR;
+ Converted = FALSE;
+ }
+ }
+
+ return Converted;
+}
+
+
+
+
+BOOLEAN
+FAT_NTFS::ConvertDirectory (
+ IN PFATDIR Directory,
+ IN PFAT_DIRENT DirEntry,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT FrsDir
+ )
+
+/*++
+
+Routine Description:
+
+ Converts a FAT directory and recursively all its subdirectories
+
+Arguments:
+
+ Directory - Supplies directory to convert
+ DirEntry - Supplies the directory entry of the directory
+ FrsDir - Supplies pointer to FRS of directory
+
+Return Value:
+
+ BOOLEAN - TRUE if directory successfully converted
+ FALSE otherwise
+
+--*/
+
+{
+
+ NTFS_INDEX_TREE Index; // NTFS index
+ BOOLEAN Converted; // FALSE if error
+ ULONG DirSize; // Dir size
+ ULONG SectorsPerFatCluster; // Sectors per cluster
+ USHORT Cluster; // Dir cluster number
+ PFAT Fat; // Pointer to FAT
+ LCN Lcn; // LCN
+
+
+ DebugPtrAssert( Directory );
+ DebugPtrAssert( DirEntry );
+ DebugPtrAssert( FrsDir );
+
+
+ //
+ // Create an index for this directory:
+ //
+ if ( !Index.Initialize( $FILE_NAME,
+ _Drive,
+ _ClusterFactor,
+ &_VolumeBitmap,
+ FrsDir->GetUpcaseTable(),
+ COLLATION_FILE_NAME,
+ // 4, /* clusters per buffer */
+ 4 * _ClusterFactor * _Drive->QuerySectorSize(),
+ /* buffer size */
+ FrsDir->QueryMaximumAttributeRecordSize() /2,
+ &_RootIndexName
+ )
+ ) {
+
+ _Message->Set( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ _Message->Display();
+ _Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+ _Level++;
+
+ //
+ // Convert the directory.
+ //
+ if ( Converted = ConvertDir( Directory, &Index, FrsDir ) ) {
+
+ //
+ // If the directory has extended attributes, convert them.
+ //
+ // Then save the index.
+ //
+ if ( Converted = (BOOLEAN)( !DirEntry->QueryEaHandle() ||
+ ConvertExtendedAttributes( DirEntry, FrsDir ) ) ) {
+
+
+ //
+ // Mark the sectors used by this directory in the reserved
+ // bitmap.
+ //
+ DirSize = DirEntry->QueryFileSize();
+ SectorsPerFatCluster = _FatSa->QuerySectorsPerCluster();
+ Cluster = DirEntry->QueryStartingCluster();
+ Fat = _FatSa->GetFat();
+
+ while ( TRUE ) {
+
+ Lcn = FatClusterToLcn( Cluster );
+
+ _ReservedBitmap.SetAllocated( Lcn, SectorsPerFatCluster );
+
+ if ( Fat->IsEndOfChain( Cluster )) {
+ break;
+ }
+
+ Cluster = Fat->QueryEntry( Cluster );
+ }
+
+
+ //
+ // Save the index for this directory
+ //
+ if ( !( Converted = (Index.Save( FrsDir ) ) ) ) {
+ _Message->Set( MSG_CONV_CANNOT_WRITE, ERROR_MESSAGE );
+ _Message->Display();
+ _Status = CONVERT_STATUS_ERROR;
+ }
+ }
+ }
+
+ _Level--;
+
+ return Converted;
+}
+
+
+
+
+BOOLEAN
+FAT_NTFS::ConvertDir (
+ IN PFATDIR Directory,
+ IN OUT PNTFS_INDEX_TREE Index,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT FrsDir
+ )
+
+/*++
+
+Routine Description:
+
+ Converts a FAT directory and recursively all its subdirectories
+
+Arguments:
+
+
+Return Value:
+
+ BOOLEAN - TRUE if directory successfully converted
+ FALSE otherwise
+
+--*/
+
+{
+
+ FAT_DIRENT Entry; // Directory entry
+ HMEM HMem; // Memory
+ DSTRING DirName; // This dir's name
+ DSTRING LongName; // the associated long name
+ BOOLEAN UseLongName; // make one name attrib
+ STANDARD_INFORMATION StandardInformation;// Std. Info
+ ULONG EntryNumber; // Entry number counter
+ BOOLEAN Converted; // FALSE if error
+ NTFS_FILE_RECORD_SEGMENT Frs; // FRS of each entry
+ VCN FileNumber; // File Number of child.
+ USHORT FrsFlags;
+ PVOID DirEntry;
+ FILEDIR SubDir;
+ BOOLEAN HasLongName;
+
+ Converted = TRUE;
+ EntryNumber = 0;
+
+
+ DebugPtrAssert( Directory );
+ DebugPtrAssert( Index );
+ DebugPtrAssert( FrsDir );
+
+
+ //
+ // Traverse the directory, converting all its entries.
+ //
+ while ( Converted ) {
+
+ //
+ // Get next directory entry
+ //
+ if ( !(DirEntry = Directory->GetDirEntry( EntryNumber ))) {
+ break;
+ }
+ if ( !Entry.Initialize( DirEntry )) {
+ _Message->Set( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ _Message->Display();
+ _Status = CONVERT_STATUS_ERROR;
+ Converted = FALSE;
+ DebugAssert(FALSE);
+ break;
+ }
+
+ //
+ // If end of directory, get out
+ //
+ if ( Entry.IsEndOfDirectory() ) {
+ break;
+ }
+
+ //
+ // Ignore the deleted, the "parent" and the "self" entries, the
+ // volume label and the EA file.
+ //
+ if (( Entry.IsErased() ||
+ Entry.IsDot() ||
+ Entry.IsDotDot() ||
+ Entry.IsVolumeLabel() ||
+ Entry.IsLongEntry() ||
+ (_EAFileFirstCluster != 0 &&
+ Entry.QueryStartingCluster() == _EAFileFirstCluster) ) ) {
+
+ EntryNumber++;
+ continue;
+ }
+
+ // Fill in the standard information for this file or
+ // directory. Note that NTFS stores Universal Time,
+ // whereas FAT stores Local Time, so the time has to
+ // be converted.
+ //
+
+ LARGE_INTEGER FatTime, NtfsTime;
+
+ Entry.QueryLastWriteTime( &FatTime );
+ RtlLocalTimeToSystemTime( &FatTime, &NtfsTime );
+
+ StandardInformation.LastModificationTime = NtfsTime;
+ StandardInformation.LastChangeTime = NtfsTime;
+
+ if (Entry.IsValidCreationTime()) {
+
+ Entry.QueryCreationTime( &FatTime );
+ RtlLocalTimeToSystemTime( &FatTime, &NtfsTime );
+ StandardInformation.CreationTime = NtfsTime;
+ } else {
+
+ StandardInformation.CreationTime = StandardInformation.LastChangeTime;
+ }
+
+ if (Entry.IsValidLastAccessTime()) {
+
+ Entry.QueryLastAccessTime( &FatTime );
+ RtlLocalTimeToSystemTime( &FatTime, &NtfsTime );
+ StandardInformation.LastAccessTime = NtfsTime;
+ } else {
+
+ StandardInformation.LastAccessTime = StandardInformation.LastChangeTime;
+ }
+
+ StandardInformation.FileAttributes = Entry.QueryAttributeByte();
+
+
+ //
+ // Get the WSTR name of the entry and fill in the FILE_NAME
+ // structure for the file name attribute. If this entry
+ // does not have an associated Long File Name, then its
+ // name is both a valid DOS and NTFS name; if there is an
+ // associated Long File Name, then the name is the DOS name
+ // and the long name is the NTFS name.
+ //
+ // If the long name is identical to the short name, ignore
+ // the long name.
+ //
+ Entry.QueryName( &DirName );
+
+ if( !Directory->QueryLongName( EntryNumber, &LongName ) ) {
+
+ DebugPrintf( "CUFAT: QueryLongName failed.\n" );
+ _Status = CONVERT_STATUS_ERROR;
+ Converted = FALSE;
+ break;
+ }
+
+ HasLongName = (LongName.QueryChCount() != 0);
+
+ //
+ // If the long name is only a casewise permutation of the
+ // short name, use the long name as the single ntfs name
+ // attribute.
+ //
+
+ UseLongName = (HasLongName &&
+ 0 == NtfsUpcaseCompare( DirName.GetWSTR(),
+ DirName.QueryChCount(),
+ LongName.GetWSTR(),
+ LongName.QueryChCount(),
+ FrsDir->GetUpcaseTable(),
+ FALSE ));
+
+
+ _FileNameBuffer->ParentDirectory = FrsDir->QuerySegmentReference();
+ _FileNameBuffer->FileNameLength = (unsigned char)DirName.QueryChCount();
+ if (UseLongName) {
+
+ _FileNameBuffer->Flags = FILE_NAME_NTFS | FILE_NAME_DOS;
+
+ if ( !LongName.QueryWSTR( 0, TO_END, NtfsFileNameGetName(_FileNameBuffer), (NAMEBUFFERSIZE * sizeof(WCHAR)) ) ) {
+ _Message->Set( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ _Message->Display();
+ _Status = CONVERT_STATUS_ERROR;
+ Converted = FALSE;
+ DebugAssert(FALSE);
+ break;
+ }
+
+ } else {
+
+ _FileNameBuffer->Flags = HasLongName ?
+ FILE_NAME_DOS :
+ FILE_NAME_NTFS | FILE_NAME_DOS;
+
+ if ( !DirName.QueryWSTR( 0, TO_END, NtfsFileNameGetName(_FileNameBuffer), (NAMEBUFFERSIZE * sizeof(WCHAR)) ) ) {
+ _Message->Set( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ _Message->Display();
+ _Status = CONVERT_STATUS_ERROR;
+ Converted = FALSE;
+ DebugAssert(FALSE);
+ break;
+ }
+ }
+
+ // Allocate and create the FRS for this file or directory,
+ // add its file name, and add an appropriate entry to the
+ // index.
+ //
+ FrsFlags = (Entry.IsDirectory()) ? (USHORT)FILE_FILE_NAME_INDEX_PRESENT : (USHORT)0;
+
+ if ( !_Mft.AllocateFileRecordSegment( &FileNumber, FALSE ) ||
+ !Frs.Initialize( FileNumber, &_Mft ) ||
+ !Frs.Create( &StandardInformation, FrsFlags ) ||
+ !Frs.AddFileNameAttribute( _FileNameBuffer ) ||
+ !Frs.AddSecurityDescriptor( NoAclCannedSd,
+ &_VolumeBitmap ) ||
+ !Index->InsertEntry( NtfsFileNameGetLength( _FileNameBuffer ),
+ _FileNameBuffer,
+ Frs.QuerySegmentReference() ) ) {
+
+ DebugPrint( "Can't create FRS in ConvertDirectory.\n" );
+ Converted = FALSE;
+ break;
+ }
+
+ // If the file has separate long name, add that entry to the FRS
+ // and the index.
+ //
+ if( HasLongName && !UseLongName ) {
+
+
+ _FileNameBuffer->ParentDirectory = FrsDir->QuerySegmentReference();
+ _FileNameBuffer->FileNameLength = (unsigned char)LongName.QueryChCount();
+ _FileNameBuffer->Flags = FILE_NAME_NTFS;
+
+ if ( !LongName.QueryWSTR( 0, TO_END, NtfsFileNameGetName(_FileNameBuffer), (NAMEBUFFERSIZE * sizeof(WCHAR)) ) ) {
+ _Message->Set( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ _Message->Display();
+ _Status = CONVERT_STATUS_ERROR;
+ Converted = FALSE;
+ DebugAssert(FALSE);
+ break;
+ }
+
+ if( !Frs.AddFileNameAttribute( _FileNameBuffer ) ||
+ !Index->InsertEntry( NtfsFileNameGetLength( _FileNameBuffer ),
+ _FileNameBuffer,
+ Frs.QuerySegmentReference() ) ) {
+
+ DebugPrint( "Can't create FRS in ConvertDirectory.\n" );
+ Converted = FALSE;
+ break;
+ }
+ }
+
+ if ( _Verbose ) {
+ STATIC CHAR NameDisplayBuffer[128];
+ ULONG NameStart = _Level * 4;
+ PWSTRING Name;
+
+ Name = (HasLongName ? &LongName : &DirName);
+
+ memset(NameDisplayBuffer, ' ', NameStart);
+ Name->QuerySTR( 0, TO_END, NameDisplayBuffer + NameStart,
+ 128 - Name->QueryChCount() );
+ NameDisplayBuffer[NameStart + Name->QueryChCount()] = 0;
+ _Message->Set( MSG_ONE_STRING );
+ _Message->Display( "%s", NameDisplayBuffer );
+ }
+
+ //
+ // Determine if the entry is a directory or a file, and proccess it
+ // accordingly.
+ //
+ if ( Entry.IsDirectory() ) {
+
+ //
+ // Directory
+ //
+ //
+ // Convert the directory (and all its subdirectories)
+ //
+
+
+ if ( !HMem.Initialize() ||
+ !SubDir.Initialize( &HMem,
+ _Drive,
+ _FatSa,
+ _FatSa->GetFat(),
+ Entry.QueryStartingCluster() ) ) {
+
+ _Message->Set( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ _Message->Display();
+ _Status = CONVERT_STATUS_ERROR;
+ DebugAssert(FALSE);
+ return FALSE;
+ }
+
+ if ( !SubDir.Read() ) {
+ _Message->Set( MSG_CONV_CANNOT_READ, ERROR_MESSAGE );
+ _Message->Display( );
+ _Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+ if ( !ConvertDirectory( &SubDir, &Entry, &Frs ) ||
+ !Frs.Flush( &_VolumeBitmap, Index ) ) {
+
+ _Message->Set( MSG_CONV_CANNOT_CONVERT_DIRECTORY );
+ _Message->Display( "%W", &DirName );
+ Converted = FALSE;
+ break;
+ }
+
+ } else {
+
+ //
+ // File
+ //
+ DebugAssert( !Entry.IsVolumeLabel() );
+ DebugAssert( !Entry.IsLongEntry() );
+ DebugAssert( !_EAFileFirstCluster ||
+ (Entry.QueryStartingCluster() != _EAFileFirstCluster) );
+
+ //
+ // Convert the file.
+ //
+ if ( !ConvertFile( &Entry, &Frs ) ||
+ !Frs.Flush( &_VolumeBitmap, Index ) ) {
+
+ Converted = FALSE;
+ break;
+ }
+ }
+
+ EntryNumber++;
+ }
+
+
+ return Converted;
+}
+
+
+
+
+BOOLEAN
+FAT_NTFS::ConvertExtendedAttributes (
+ IN PFAT_DIRENT Dirent,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT Frs
+ )
+
+/*++
+
+Routine Description:
+
+ Converts the extended attributes of a FAT directory entry.
+
+Arguments:
+
+ Dirent - Supplies the directory entry
+ Frs - Supplies the file's FRS
+
+Return Value:
+
+ BOOLEAN - TRUE if extended attributes converted
+ FALSE otherwise
+
+--*/
+
+{
+ USHORT EaHandle;
+
+ DebugPtrAssert( Dirent );
+ DebugPtrAssert( Frs );
+
+ EaHandle = Dirent->QueryEaHandle();
+
+ //
+ // If this entry has extended attributes, convert them
+ //
+ if ( EaHandle ) {
+
+ //
+ // Make sure that there is an EA file
+ //
+ if ( _EAFileFirstCluster == 0 ) {
+
+ _Message->Set( MSG_CONV_NO_EA_FILE, ERROR_MESSAGE );
+ _Message->Display( );
+ _Status = CONVERT_STATUS_ERROR;
+
+ return FALSE;
+ }
+
+ //
+ // Convert the attributes
+ //
+ return ConvertExtendedAttributes( Frs,
+ EaHandle );
+
+
+ }
+
+ return TRUE;
+}
+
+
+
+
+BOOLEAN
+FAT_NTFS::ConvertExtendedAttributes (
+ IN OUT PNTFS_FILE_RECORD_SEGMENT Frs,
+ IN USHORT EaHandle
+ )
+
+/*++
+
+Routine Description:
+
+ Converts the extended attributes of a FAT directory entry.
+
+Arguments:
+
+ Frs - Supplies the file's FRS
+ Eahandle - Supplies the EA handle
+
+Return Value:
+
+ BOOLEAN - TRUE if extended attributes converted
+ FALSE otherwise
+
+--*/
+
+{
+ EA_INFORMATION EaInformation;
+ NTFS_ATTRIBUTE EaInformationAttribute;
+ NTFS_ATTRIBUTE EaDataAttribute;
+
+ EA_SET EaSet; // Extended attribute set
+ HMEM Mem; // Memory
+ ULONG Index; // EA Index
+ PEA Ea; // Pointer to EA
+ USHORT Cluster; // EA set cluster number
+ PBYTE UnpackedEaList;
+ ULONG PackedEaLength, UnpackedEaLength, PackedListLength,
+ UnpackedListLength, NeedEaCount, TargetOffset;
+
+
+ //
+ // Read in the EA set
+ //
+ Cluster = (_FatSa->GetFat())->QueryNthCluster( _EAFileFirstCluster,
+ _EAHeader.QueryEaSetClusterNumber( EaHandle ));
+
+ if ( !Mem.Initialize() ||
+ !EaSet.Initialize( &Mem,
+ _Drive,
+ _FatSa,
+ _FatSa->GetFat(),
+ Cluster )
+ ) {
+ _Message->Set( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ _Message->Display( );
+ _Status = CONVERT_STATUS_ERROR;
+ DebugAssert(FALSE);
+ return FALSE;
+ }
+
+ if ( !EaSet.Read() ) {
+ _Message->Set( MSG_CONV_CANNOT_READ, ERROR_MESSAGE );
+ _Message->Display( );
+ _Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+ //
+ // Walk the list to determine the packed and unpacked length. The
+ // packed list is simply all the EA's concatenated together, so its
+ // length is the sum of the individual lengths. The unpacked list
+ // consists of a set of entries which in turn consist of a ULONG
+ // and a DWORD-aligned EA, so it length is a bit more complex to
+ // compute.
+ //
+ Index = 0;
+ PackedListLength = 0;
+ UnpackedListLength = 0;
+ NeedEaCount = 0;
+
+ while( (Ea = EaSet.GetEa( Index++ )) != NULL ) {
+
+ PackedEaLength = sizeof( EA ) + Ea->NameSize +
+ *(USHORT UNALIGNED *)Ea->ValueSize;
+
+ UnpackedEaLength = sizeof(ULONG) + DwordAlign( PackedEaLength );
+
+ PackedListLength += PackedEaLength;
+ UnpackedListLength += UnpackedEaLength;
+
+ if( Ea->Flag & NeedFlag ) {
+
+ NeedEaCount += 1;
+ }
+ }
+
+ //
+ // Allocate a buffer to hold the unpacked list.
+ //
+ if( (UnpackedEaList = (PBYTE)MALLOC( (unsigned int)UnpackedListLength )) == NULL ) {
+
+ return FALSE;
+ }
+
+ memset( UnpackedEaList, 0, (unsigned int)UnpackedListLength );
+
+ //
+ // Walk the list again, copying EA's into the packed list buffer.
+ //
+ Index = 0;
+ TargetOffset = 0;
+
+ while( (Ea = EaSet.GetEa( Index++ )) != NULL ) {
+
+ PackedEaLength = sizeof( EA ) + Ea->NameSize +
+ *(USHORT UNALIGNED *)Ea->ValueSize;
+
+ UnpackedEaLength = sizeof(ULONG) + DwordAlign( PackedEaLength );
+
+ memcpy( UnpackedEaList + TargetOffset,
+ &UnpackedEaLength,
+ sizeof( ULONG ) );
+
+ memcpy( UnpackedEaList + TargetOffset + sizeof( ULONG ),
+ Ea,
+ (unsigned int)PackedEaLength );
+
+ TargetOffset += UnpackedEaLength;
+ }
+
+ // Create the EA Information Attribute--fill in the fields of
+ // the EA information structure, put it into a resident attribute
+ // of type $EA_INFORMATION, and insert the attribute into the file.
+ //
+ EaInformation.PackedEaSize = (unsigned short)PackedListLength;
+ EaInformation.NeedEaCount = (unsigned short)NeedEaCount;
+ EaInformation.UnpackedEaSize = UnpackedListLength;
+
+ if( !EaInformationAttribute.Initialize( _Drive,
+ _Mft.QueryClusterFactor(),
+ &EaInformation,
+ sizeof( EA_INFORMATION ),
+ $EA_INFORMATION,
+ NULL,
+ 0 ) ||
+ !EaInformationAttribute.InsertIntoFile( Frs, &_VolumeBitmap ) ) {
+
+ FREE( UnpackedEaList );
+ return FALSE;
+ }
+
+ //
+ // Set up the Ea Data attribute. Start out with it resident; if
+ // it doesn't fit into the FRS, make it nonresident.
+ //
+ if( !EaDataAttribute.Initialize( _Drive,
+ _Mft.QueryClusterFactor(),
+ UnpackedEaList,
+ UnpackedListLength,
+ $EA_DATA,
+ NULL,
+ 0 ) ) {
+
+ DebugPrint( "Cannot initialize resident attribute for EA List.\n" );
+ FREE( UnpackedEaList );
+ return FALSE;
+ }
+
+ if( !EaDataAttribute.InsertIntoFile( Frs, &_VolumeBitmap ) ) {
+
+ // Couldn't insert it in resident form; make it nonresident.
+
+ if( !EaDataAttribute.MakeNonresident( &_VolumeBitmap ) ||
+ !EaDataAttribute.InsertIntoFile( Frs, &_VolumeBitmap ) ) {
+
+ // Can't insert it.
+
+ FREE( UnpackedEaList );
+ return FALSE;
+ }
+ }
+
+
+ //
+ // All the EAs have been converted
+ //
+ FREE( UnpackedEaList );
+ return TRUE;
+}
+
+
+
+BOOLEAN
+FAT_NTFS::ConvertFile (
+ IN PFAT_DIRENT Dirent,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT File
+ )
+
+/*++
+
+Routine Description:
+
+ Converts a file from FAT to NTFS
+
+Arguments:
+
+ Dirent - Supplies the directory entry of the file to convert
+ ParentFrs - Supplies the FRS of the directory which contains this file
+ File - Supplies pointer to FRS of file
+
+Return Value:
+
+ BOOLEAN - TRUE if file successfully converted
+ FALSE otherwise
+
+--*/
+
+{
+ DSTRING FileName; // File name
+
+ DebugPtrAssert( Dirent );
+ DebugPtrAssert( File );
+
+ Dirent->QueryName( &FileName );
+
+ //
+ // Convert the file data and extended attributes.
+ //
+ if ( !ConvertFileData( Dirent, File ) ||
+ !( !Dirent->QueryEaHandle() ||
+ ConvertExtendedAttributes( Dirent, File ))
+ ) {
+
+
+ _Message->Set( MSG_CONV_CANNOT_CONVERT_FILE, ERROR_MESSAGE );
+ _Message->Display( "%W", &FileName );
+ _Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+
+ }
+
+ //
+ // File converted
+ //
+ return TRUE;
+}
+
+
+
+
+BOOLEAN
+FAT_NTFS::ConvertFileData (
+ IN PFAT_DIRENT Dirent,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT Frs
+ )
+
+/*++
+
+Routine Description:
+
+ Converts the file data from FAT to NTFS
+
+Arguments:
+
+ Dirent - Supplies the directory entry of the file to convert
+ Frs - Supplies the FRS for the file
+
+Return Value:
+
+ BOOLEAN - TRUE if file data successfully converted
+ FALSE otherwise
+
+--*/
+
+{
+
+ ULONG FileSize; // File size
+ ULONG SectorsPerFatCluster; // Sectors per cluster
+
+ DebugPtrAssert( Dirent );
+ DebugPtrAssert( Frs );
+
+ //
+ // Get the file size
+ //
+ FileSize = Dirent->QueryFileSize();
+ SectorsPerFatCluster = _FatSa->QuerySectorsPerCluster();
+
+ //
+ // If the data is small enough to fit in the FRS, we make it resident and free
+ // the cluster it occupies, otherwise we reuse its allocation and make it
+ // non-resident.
+ //
+ // Note that we only make the data resident if it is less than one FAT cluster
+ // long.
+ //
+ if ( ( Frs->QueryFreeSpace() > (FileSize + SIZE_OF_RESIDENT_HEADER ) ) &&
+ ( FileSize <= (SectorsPerFatCluster * _Drive->QuerySectorSize( )) )
+ ) {
+
+ return ConvertFileDataResident( Dirent, Frs );
+
+ } else {
+
+ DebugAssert( FileSize > 0 );
+
+ return ConvertFileDataNonResident( Dirent, Frs );
+ }
+}
+
+
+
+
+
+BOOLEAN
+FAT_NTFS::ConvertFileDataNonResident (
+ IN PFAT_DIRENT Dirent,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT Frs
+ )
+
+/*++
+
+Routine Description:
+
+ Converts the file data from FAT to NTFS in nonresident form
+
+Arguments:
+
+ Dirent - Supplies the directory entry of the file to convert
+ Frs - Supplies the FRS for the file
+
+Return Value:
+
+ BOOLEAN - TRUE if file data successfully converted
+ FALSE otherwise
+
+--*/
+
+{
+
+ USHORT Cluster; // File cluster number
+ NTFS_ATTRIBUTE DataAttribute; // File's $DATA attribute
+ NTFS_EXTENT_LIST ExtentList; // NTFS extent list
+ ULONG Length; // Length of extent
+ ULONG FileSize; // File size
+ ULONG SectorsLeft; // Sectors left to convert
+ ULONG SectorsPerCluster; // Sectors per cluster
+ VCN Vcn; // VCN
+ LCN Lcn; // LCN
+ PFAT Fat; // Pointer to FAT
+
+ DebugPtrAssert( Dirent );
+ DebugPtrAssert( Frs );
+
+ //
+ // Get the file size
+ //
+ FileSize = Dirent->QueryFileSize();
+ SectorsPerCluster = _FatSa->QuerySectorsPerCluster();
+
+ DebugAssert( FileSize > 0 );
+
+ //
+ // First we generate an extent list mapping the file's data
+ // allocation. We just add all the clusters in the file as
+ // extents of size SectorsPerCluster. Note that we don't
+ // have to do anything special about consecutive clusters
+ // (the Extent List coallesces them for us).
+ //
+ // If there are unused sectors in the last cluster, we mark
+ // them in the ReservedBitmap.
+ //
+ if ( !ExtentList.Initialize( 0, 0 ) ) {
+ _Message->Set( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ _Message->Display( );
+ _Status = CONVERT_STATUS_ERROR;
+ DebugAssert(FALSE);
+ return FALSE;
+ }
+
+ Cluster = Dirent->QueryStartingCluster();
+ SectorsLeft = (FileSize + _Drive->QuerySectorSize() - 1) /
+ _Drive->QuerySectorSize();
+ Fat = _FatSa->GetFat();
+ Vcn = 0;
+
+ //
+ // Add all the FAT clusters to the NTFS extent list. Note that in the last
+ // cluster we only add those sectors that contain file data, and the rest
+ // will become free after the conversion.
+ //
+ while ( SectorsLeft ) {
+
+ Lcn = FatClusterToLcn( Cluster );
+ Length = min( SectorsLeft, SectorsPerCluster );
+
+ //DebugPrintf( " Extent: Cluster %d Vcn %d Lcn %d Length %d Left %d\n",
+ // Cluster, Vcn.GetLowPart(), Lcn.GetLowPart(), Length,
+ // SectorsLeft );
+
+ if ( !ExtentList.AddExtent( Vcn, Lcn, Length ) ) {
+ _Message->Set( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ _Message->Display( );
+ _Status = CONVERT_STATUS_ERROR;
+ DebugAssert(FALSE);
+ return FALSE;
+ }
+
+ Vcn += Length;
+ SectorsLeft -= Length;
+
+ DebugAssert( ( SectorsLeft > 0 ) || Fat->IsEndOfChain( Cluster ));
+
+ Cluster = Fat->QueryEntry( Cluster );
+ }
+
+ //
+ // Unused sectors in the last cluster are marked in the
+ // ReservedBitmap.
+ //
+ if ( Length < SectorsPerCluster ) {
+
+ _ReservedBitmap.SetAllocated( Lcn+Length,
+ SectorsPerCluster - Length );
+ }
+
+ //
+ // Now put the file data in the $DATA attribute of the file
+ //
+ if ( !DataAttribute.Initialize( _Drive,
+ _ClusterFactor,
+ &ExtentList,
+ FileSize,
+ FileSize,
+ $DATA ) ) {
+
+ _Message->Set( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ _Message->Display( );
+ _Status = CONVERT_STATUS_ERROR;
+ DebugAssert(FALSE);
+ return FALSE;
+ }
+
+ if ( !DataAttribute.InsertIntoFile( Frs, &_VolumeBitmap ) ) {
+
+ _Message->Set( MSG_CONV_CANNOT_CONVERT_DATA, ERROR_MESSAGE );
+ _Message->Display( );
+ _Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+ //
+ // File data converted
+ //
+ return TRUE;
+}
+
+
+
+
+
+BOOLEAN
+FAT_NTFS::ConvertFileDataResident (
+ IN PFAT_DIRENT Dirent,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT Frs
+ )
+
+/*++
+
+Routine Description:
+
+ Converts the file data from FAT to NTFS in resident form
+
+Arguments:
+
+ Dirent - Supplies the directory entry of the file to convert
+ Frs - Supplies the FRS for the file
+
+Return Value:
+
+ BOOLEAN - TRUE if file data successfully converted
+ FALSE otherwise
+
+--*/
+
+{
+
+ HMEM Hmem; // Memory
+ CLUSTER_CHAIN ClusterChain; // File cluster
+ NTFS_ATTRIBUTE DataAttribute; // File's $DATA attribute
+ ULONG FileSize; // File size
+
+ DebugPtrAssert( Dirent );
+ DebugPtrAssert( Frs );
+
+ //
+ // Get the file size
+ //
+ FileSize = Dirent->QueryFileSize();
+
+ if ( FileSize > 0 ) {
+ //
+ // Read the file data.
+ //
+ if ( !Hmem.Initialize() ||
+ !ClusterChain.Initialize( &Hmem,
+ _Drive,
+ _FatSa,
+ _FatSa->GetFat(),
+ Dirent->QueryStartingCluster(), 1 ) ) {
+
+ _Message->Set( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ _Message->Display( );
+ _Status = CONVERT_STATUS_ERROR;
+ DebugAssert(FALSE);
+ return FALSE;
+ }
+
+ if ( !ClusterChain.Read() ) {
+
+ //
+ // We cannot read the file data, possibly because there is a
+ // bad sector on the volume. We will try make the file data
+ // non-resident (that way we don't need to read the data, since
+ // all we do is generate the allocation info). Doing things
+ // this way does not change the state of the drive (i.e. it was
+ // bad before conversion, it is bad after the conversion).
+ //
+ return ConvertFileDataNonResident( Dirent, Frs );
+ }
+ }
+
+ //
+ // Now put the file data in the $DATA attribute of the file
+ //
+ if ( !DataAttribute.Initialize( _Drive,
+ _ClusterFactor,
+ (FileSize > 0) ? ClusterChain.GetBuf() : NULL,
+ FileSize,
+ $DATA ) ) {
+
+ _Message->Set( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ _Message->Display( );
+ _Status = CONVERT_STATUS_ERROR;
+ DebugAssert(FALSE);
+ return FALSE;
+ }
+
+ if ( !DataAttribute.InsertIntoFile( Frs, &_VolumeBitmap ) ) {
+
+ _Message->Set( MSG_CONV_CANNOT_CONVERT_DATA, ERROR_MESSAGE );
+ _Message->Display( );
+ _Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+ //
+ // We can now mark the cluster with the file data in the
+ // ReservedBitmap, so it will be freed after the conversion.
+ //
+ // Note that we cannot mark it free in the VolumeBitmap because
+ // the conversion process must NOT overwrite it (or data may
+ // be lost if the conversion fails!).
+ //
+ if ( FileSize > 0 ) {
+ ReserveCluster( Dirent->QueryStartingCluster() );
+ }
+
+ //
+ // File data converted
+ //
+ return TRUE;
+}
+
+
+
+
+
+BOOLEAN
+FAT_NTFS::ConvertFileSystem(
+ )
+
+/*++
+
+Routine Description:
+
+ Converts the existing FAT file system to NTFS. This is done by
+ traversing the file system tree and converting the FAT structures
+ (i.e. directories, files and EAs).
+
+ The space occupied by FAT-specific files (e.g. the EA file) is marked
+ in the ReservedBitmap so it will be freed up when the conversion is
+ done.
+
+ Note that Operating-System-specific files (e.g. IO.SYS, MSDOS.SYS) are
+ NOT removed by the conversion process. This is a File System conversion,
+ not an Operating System conversion (If this file system conversion is
+ being invoked by an operating system conversion program, then that
+ program is responsible for removing any system files).
+
+Arguments:
+
+ None
+
+Return Value:
+
+ BOOLEAN - TRUE if file system successfully converted
+ FALSE otherwise
+
+--*/
+
+{
+ PFATDIR RootDir; // FAT root directory
+ FAT_DIRENT EAFileDirEnt; // Entry for EA file
+ DSTRING EAFile; // Name of EA file
+ USHORT i; // Cluster index
+ PFAT Fat; // Pointer to FAT
+
+ _Message->Set( MSG_CONV_CONVERTING_FS );
+ _Message->Display();
+
+ //
+ // Get the root directory
+ //
+ RootDir = (PFATDIR)_FatSa->GetRootDir();
+ DebugPtrAssert( RootDir );
+
+ //
+ // Locate the EA file. If it exists then remember its starting cluster
+ // number and initialize the EA header.
+ //
+ // The starting cluster of the EA file is remembered because it is used
+ // later on for identifying the EA file while traversing the root directory.
+ //
+ EAFile.Initialize( "EA DATA. SF" );
+
+ if ( EAFileDirEnt.Initialize( RootDir->SearchForDirEntry( &EAFile )) ) {
+
+ _EAFileFirstCluster = EAFileDirEnt.QueryStartingCluster();
+
+ Fat = _FatSa->GetFat();
+
+ if ( !_EAMemory.Initialize() ||
+ !_EAHeader.Initialize( &_EAMemory,
+ _Drive,
+ _FatSa,
+ Fat,
+ _EAFileFirstCluster ) ||
+
+ !_EAHeader.Read()
+ ) {
+
+ _Message->Set( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ _Message->Display();
+ _Status = CONVERT_STATUS_ERROR;
+ DebugAssert(FALSE);
+ return FALSE;
+ }
+
+ //
+ // Mark all the EA file sectors in the ReservedBitmap, so the
+ // space will me freed up when the conversion is done.
+ //
+ i = _EAFileFirstCluster;
+
+#if DBG
+ if ( _Verbose ) {
+ DebugPrintf( "EA file at cluster %X\n", _EAFileFirstCluster );
+ }
+#endif
+
+ while (TRUE) {
+
+ ReserveCluster( i );
+
+ if ( Fat->IsEndOfChain( i ) ) {
+ break;
+ }
+
+ i = Fat->QueryEntry( i );
+ }
+
+ } else {
+
+#if DBG
+ if ( _Verbose ) {
+ DebugPrintf( "The volume contains no EA file\n" );
+ }
+#endif
+
+ _EAFileFirstCluster = 0;
+
+ }
+
+
+ //
+ // Convert the volume by recursively converting the root directory
+ //
+ return ConvertRoot( RootDir );
+}
+
+
+
+BOOLEAN
+FAT_NTFS::CreateBitmaps(
+ )
+
+/*++
+
+Routine Description:
+
+ Creates the NTFS bitmaps for the volume and the bad block stack.
+
+ Two bitmaps are created:
+
+ _VolumeBitmap - Is the bitmap for the volume. Represents the volume at
+ seemed by NTFS.
+
+ _ReservedBitmap - Contains those NTFS clusters that are marked as "in use"
+ in the _VolumeBitmap during the conversion, but that must
+ be marked as "free" after the conversion. This is
+ required so that the conversion don't try to allocate
+ those clusters. These "reserved" clusters include all
+ the FAT structures that will be thrown away after the
+ conversion.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ BOOLEAN - TRUE if bitmaps and bad block stack created.
+ FALSE otherwise
+
+--*/
+
+{
+ PFAT Fat; // The FAT
+ USHORT Cluster; // Used to traverse FAT
+ LCN Lcn; // Same as Cluster, but in sectors
+ USHORT ClusterCount; // Number of clusters in volume
+ ULONG LcnPerCluster; // Sectors per cluster
+ LCN DataAreaStart; // Start of data area;
+ ULONG LcnCount; // Sector counter
+
+ //
+ // Note that the code assumes that 1 LCN == 1 sector, i.e. that the
+ // cluster factor is 1.
+ //
+ DebugAssert( _ClusterFactor == 1 );
+
+ //
+ // Initialize bitmaps
+ //
+ if (!_VolumeBitmap.Initialize(_Drive->QuerySectors() - 1, FALSE, _Drive,
+ _ClusterFactor) ||
+ !_ReservedBitmap.Initialize(_Drive->QuerySectors() - 1, FALSE, NULL, 0)) {
+
+ _Message->Set( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ _Message->Display();
+ _Status = CONVERT_STATUS_ERROR;
+ DebugAssert(FALSE);
+ return FALSE;
+ }
+
+ //
+ // The boot area must be free (it will become reserved when creating
+ // the elementary NTFS structures).
+ //
+
+ //
+ // The FAT ( From the end of the boot area up to the beginning of
+ // the data area) is reserved but will be freed at the end of the
+ // conversion.
+ //
+ DataAreaStart = _FatSa->QueryStartDataLbn();
+
+ _VolumeBitmap.SetAllocated( SECTORS_IN_BOOT,
+ DataAreaStart - SECTORS_IN_BOOT );
+
+ _ReservedBitmap.SetAllocated( SECTORS_IN_BOOT,
+ DataAreaStart - SECTORS_IN_BOOT );
+
+ //
+ // Allocate the rest of the bitmap according to the FAT
+ //
+ Lcn = DataAreaStart;
+ Cluster = FirstDiskCluster;
+ LcnPerCluster = _FatSa->QuerySectorsPerCluster();
+ ClusterCount = _FatSa->QueryClusterCount() - (USHORT)FirstDiskCluster;
+ Fat = _FatSa->GetFat();
+
+ while ( ClusterCount-- ) {
+
+ //
+ // If the cluster is not free then allocate it if its OK, or
+ // push it onto the bad stack if it is bad.
+ //
+ if ( Fat->IsClusterFree( Cluster ) ) {
+
+ Lcn += LcnPerCluster;
+
+ } else if ( Fat->IsClusterBad( Cluster ) ) {
+
+ LcnCount = LcnPerCluster;
+
+ while ( LcnCount-- ) {
+ _BadLcn.Add( Lcn );
+ Lcn += 1;
+ }
+
+ } else {
+
+ _VolumeBitmap.SetAllocated( Lcn, LcnPerCluster );
+ Lcn += LcnPerCluster;
+ }
+
+ Cluster++;
+ }
+
+ //
+ // Note that SECTORS_IN_BOOT are not really free (will be
+ // allocated later on).
+ //
+ _FreeSectorsBefore = _VolumeBitmap.QueryFreeClusters() - SECTORS_IN_BOOT;
+
+ return TRUE;
+}
+
+
+
+
+BOOLEAN
+FAT_NTFS::CreateElementary(
+ )
+
+/*++
+
+Routine Description:
+
+ Creates the elementary NTFS data structures.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ BOOLEAN - TRUE if elementary NTFS data structures created.
+ FALSE otherwise
+
+--*/
+
+{
+ NTFS_UPCASE_FILE UpcaseFile;
+ NTFS_ATTRIBUTE UpcaseAttribute;
+ NTFS_LOG_FILE LogFile;
+ DSTRING VolumeLabel; // Volume label
+
+ BOOLEAN Error;
+
+ DebugAssert( _VolumeBitmap.IsFree( 0, SECTORS_IN_BOOT ) );
+
+ //
+ // Get the volume label and create the elementary NTFS structures.
+ // Pass in zero for the initial log file size to indicate that
+ // CreateElementaryStructures should decide how big to make it.
+ //
+ if ( !_FatSa->QueryLabel( &VolumeLabel ) ||
+ !_NtfsSa.CreateElementaryStructures( &_VolumeBitmap,
+ _ClusterFactor,
+ _FrsSize,
+ SMALL_INDEX_BUFFER_SIZE,
+ 0,
+ &_BadLcn,
+ _Message,
+ _FatSa->GetBpb(),
+ &VolumeLabel ) ) {
+
+
+ _Message->Set( MSG_CONV_CANNOT_CREATE_ELEMENTARY, ERROR_MESSAGE );
+ _Message->Display();
+ _Status = CONVERT_STATUS_ERROR;
+
+ return FALSE;
+ }
+
+ //
+ // Now that we have the elementary structures, obtain the MFT, which is
+ // used later on during the conversion. Since we don't have an upcase
+ // table yet, pass in NULL for that parameter.
+ //
+ if ( !_Mft.Initialize( _Drive,
+ _NtfsSa.QueryMftStartingLcn(),
+ _ClusterFactor,
+ _FrsSize,
+ _NtfsSa.QueryVolumeSectors(),
+ &_VolumeBitmap,
+ NULL ) ||
+ !_Mft.Read() ) {
+
+ _Message->Set( MSG_CONV_CANNOT_READ, ERROR_MESSAGE );
+ _Message->Display();
+ _Status = CONVERT_STATUS_ERROR;
+
+ return FALSE;
+ }
+
+ // Tell the volume bitmap about the new Mft so it can add any
+ // bad clusters it finds to the bad cluster file.
+
+ _VolumeBitmap.SetMftPointer(_Mft.GetMasterFileTable());
+
+
+ // Get the upcase table.
+ //
+ if( !UpcaseFile.Initialize( _Mft.GetMasterFileTable() ) ||
+ !UpcaseFile.Read() ||
+ !UpcaseFile.QueryAttribute( &UpcaseAttribute, &Error, $DATA ) ||
+ !_UpcaseTable.Initialize( &UpcaseAttribute ) ) {
+
+ DebugPrint( "Can't get the upcase table.\n" );
+ return FALSE;
+ }
+
+ _Mft.SetUpcaseTable( &_UpcaseTable );
+ _Mft.GetMasterFileTable()->SetUpcaseTable( &_UpcaseTable );
+
+
+ //
+ // If we know how many files there are on the volume, extend the
+ // MFT so it is (sort of) contiguous.
+ //
+ if ( (_NumberOfFiles + _NumberOfDirectories) > 0 ) {
+
+ if ( !_Mft.Extend( _NumberOfFiles + _NumberOfDirectories + 20 ) ) {
+
+ DebugPrintf( "Cannot extend MFT by %d segments\n", _NumberOfFiles + _NumberOfDirectories );
+
+ _Message->Set( MSG_CONV_CANNOT_CREATE_ELEMENTARY, ERROR_MESSAGE );
+ _Message->Display();
+ _Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+ }
+
+ // Flush the MFT now, so that it gets first claim to the FRS's
+ // at the beginning of the MFT.
+ //
+ if( !_Mft.Flush() ) {
+
+ DebugPrintf( "CONVERT: Cannot flush the MFT\n" );
+
+ _Message->Set( MSG_CONV_CANNOT_CREATE_ELEMENTARY, ERROR_MESSAGE );
+ _Message->Display();
+ _Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+ // Sanity check: make sure that the log file doesn't have
+ // an attribute list. The file system will die horribly
+ // if Convert creates a log file with external attributes.
+ //
+ if( !LogFile.Initialize( _Mft.GetMasterFileTable() ) ||
+ !LogFile.Read() ||
+ LogFile.IsAttributePresent( $ATTRIBUTE_LIST ) ) {
+
+ _Message->Set( MSG_CONV_VOLUME_TOO_FRAGMENTED );
+ _Message->Display( "" );
+ return FALSE;
+ }
+
+
+ return TRUE;
+}
+
+
+
+
+BOOLEAN
+FAT_NTFS::FreeReservedSectors (
+ )
+
+/*++
+
+Routine Description:
+
+ Frees up those sectors marked as "in use" in the _ReservedBitmap.
+ The _VolumeBitmap is updated and written to disk.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ BOOLEAN - TRUE if sectors freed and _VolumeBitmap written.
+ FALSE otherwise.
+
+--*/
+
+{
+
+ NTFS_BITMAP_FILE BitmapFile; // NTFS bitmap file
+ NTFS_ATTRIBUTE Attribute; // $DATA attribute of bitmap file
+ LCN Lcn; // LCN
+ BOOLEAN Error;
+
+ //
+ // Free the "reserved" clusters
+ //
+ for ( Lcn = 0; Lcn < _Drive->QuerySectors(); Lcn += 1 ) {
+ if ( !_ReservedBitmap.IsFree( Lcn, 1 ) ) {
+ _VolumeBitmap.SetFree( Lcn, 1 );
+ }
+ }
+
+ //
+ // Update the Bitmap file.
+ //
+ if ( !BitmapFile.Initialize( _Mft.GetMasterFileTable() ) ||
+ !BitmapFile.Read() ||
+ !BitmapFile.QueryAttribute( &Attribute, &Error, $DATA )
+ ) {
+
+ _Message->Set( MSG_CONV_CANNOT_READ, ERROR_MESSAGE );
+ _Message->Display();
+ _Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+ //
+ // Update the Bitmap file data attribute (i.e. the volume bitmap)
+ //
+ if ( !_VolumeBitmap.Write( &Attribute, &_VolumeBitmap ) ) {
+ _Message->Set( MSG_CONV_CANNOT_WRITE, ERROR_MESSAGE );
+ _Message->Display();
+ _Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+ _FreeSectorsAfter = _VolumeBitmap.QueryFreeClusters();
+
+#if DBG
+ if ( _Verbose ) {
+ DebugPrintf( "Free sectors before conversion: %d\n", _FreeSectorsBefore.GetLowPart() );
+ DebugPrintf( "Free sectors after conversion: %d\n", _FreeSectorsAfter.GetLowPart() );
+ }
+#endif
+
+ return TRUE;
+}
+
+
+
+
+
+BOOLEAN
+FAT_NTFS::QueryNeededHoles (
+ OUT PINTSTACK Stack
+ )
+
+/*++
+
+Routine Description:
+
+ Determines what holes are required and pushes the hole
+ information in the supplied stack.
+
+Arguments:
+
+ Stack - Supplies the stack where the hole information is
+ passed
+
+Return Value:
+
+ BOOLEAN - TRUE if all hole information is in stack
+ FALSE otherwise
+
+--*/
+
+{
+ BIG_INT HoleStart; // Starting sector of hole
+ BIG_INT HoleSize; // Size of the hole
+ BIG_INT BootSize; // Size of boot code
+ BIG_INT MftSize; // Size of MFT
+ BIG_INT MftReflectionSize; // Size of MFT reflection
+ ULONG sectorsize;
+ USHORT i;
+
+
+ //
+ // Initialize the hole stack
+ //
+
+ if ( !Stack->Initialize() ) {
+ _Message->Set( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ _Message->Display();
+ _Status = CONVERT_STATUS_ERROR;
+ DebugAssert(FALSE);
+ return FALSE;
+ }
+
+ //
+ // The only NTFS structure that needs a fixed location is
+ // the BOOT backup. Push the size and location of this sector
+ // onto the stack.
+ //
+
+ if ( !Stack->Push( 1 ) ||
+ !Stack->Push( _Drive->QuerySectors() - 1 ) ) {
+
+ _Message->Set( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ _Message->Display();
+ _Status = CONVERT_STATUS_ERROR;
+ DebugAssert(FALSE);
+ return FALSE;
+ }
+
+ //
+ // We also want to create a hole big enough for the MFT and
+ // the MFT reflection. These don't need to be in a particular
+ // location, but they have to be contiguous (i.e. occupy a
+ // single "hole").
+ //
+
+ sectorsize = _Drive->QuerySectorSize();
+
+ MftSize = (_FrsSize * FIRST_USER_FILE_NUMBER + (sectorsize - 1)) / sectorsize;
+
+ MftReflectionSize = (_FrsSize * REFLECTED_MFT_SEGMENTS + (sectorsize - 1))
+ / sectorsize;
+
+ HoleSize = MftSize + MftReflectionSize;
+ HoleStart = _Drive->QuerySectors() - 1 - HoleSize;
+
+#if DBG
+ if ( _Verbose ) {
+ DebugPrintf( "Hole required: Sector %X, size %X\n",
+ HoleStart.GetLowPart(), HoleSize.GetLowPart() );
+ }
+#endif
+
+ //
+ // Make sure that the hole lies entirely in the FAT data area. Otherwise
+ // we won't be able to relocate the clusters in the hole.
+ //
+ if ( HoleStart < _FatSa->QueryStartDataLbn() ) {
+ _Message->Set( MSG_CONV_CANNOT_CONVERT_VOLUME, ERROR_MESSAGE );
+ _Message->Display( "%s%s", "NTFS", "FAT" );
+ _Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+ //
+ // Push the hole data in the stack. Size goes first!
+ //
+ if ( !Stack->Push( HoleSize ) ||
+ !Stack->Push( HoleStart ) ) {
+
+ _Message->Set( MSG_CONV_NO_MEMORY, ERROR_MESSAGE );
+ _Message->Display();
+ _Status = CONVERT_STATUS_ERROR;
+ DebugAssert(FALSE);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+
+VOID
+FAT_NTFS::QuerySectorsNeededForConversion (
+ IN PCENSUS_REPORT Census,
+ OUT PBIG_INT SectorsNeeded
+ )
+/*++
+
+Routine Description:
+
+ Determines how many sectors are required for the conversion, given
+ the volume census.
+
+Arguments:
+
+ Census - Supplies the volume census
+ SectorsNeeded - Supplies pointer to number of sectors needed
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ BIG_INT SectorsRequired;
+ BIG_INT BytesInIndices;
+
+ ULONG NtfsClusterSize; // Size of an NTFS cluster
+ ULONG sectorsize;
+
+ CONST AverageBytesPerIndexEntry = 128;
+
+
+#if DBG
+ if ( _Verbose ) {
+ DebugPrintf( "\n" );
+ DebugPrintf( "---- Volume Census Data ----\n" );
+ DebugPrintf( "Number of dirs: %d\n", Census->DirEntriesCount );
+ DebugPrintf( "Number of files: %d\n", Census->FileEntriesCount );
+ DebugPrintf( "Clusters in dirs: %d\n", Census->DirClusters );
+ DebugPrintf( "Clusters in files: %d\n", Census->FileClusters );
+ DebugPrintf( "Clusters in EA file: %d\n", Census->EaClusters );
+ DebugPrintf( "\n\n" );
+ }
+#endif
+
+
+ NtfsClusterSize = _Drive->QuerySectorSize() * _ClusterFactor;
+ _NumberOfFiles = Census->FileEntriesCount;
+ _NumberOfDirectories = Census->DirEntriesCount;
+
+ SectorsRequired =
+ NTFS_SA::QuerySectorsInElementaryStructures( _Drive,
+ _ClusterFactor,
+ _FrsSize,
+ _ClustersPerIndexBuffer,
+ 0 );
+
+
+ //
+ // We will need _ClustersPerFrs clusters for each file or
+ // directory, plus enough index blocks to hold the required
+ // index entries. (Multiply the size of indices by two to
+ // reflect the fact that the average index block will be
+ // half full.)
+ //
+
+ sectorsize = _Drive->QuerySectorSize();
+
+ SectorsRequired += ( _NumberOfFiles + _NumberOfDirectories ) *
+ ((_FrsSize + (sectorsize - 1))/sectorsize);
+
+ BytesInIndices = ( _NumberOfFiles + _NumberOfDirectories ) *
+ AverageBytesPerIndexEntry * 2;
+
+ SectorsRequired += BytesInIndices / _Drive->QuerySectorSize();
+
+ //
+ // Extended attributes
+ //
+ SectorsRequired += Census->EaClusters * _FatSa->QuerySectorsPerCluster();
+
+ //
+ // In case of unreported bad sectors, we reserve 0.1% of the disk
+ //
+ SectorsRequired += _Drive->QuerySectors()/1000;
+
+ // And that's that.
+
+ *SectorsNeeded = SectorsRequired;
+
+}
+
+
+
+
+
+BOOLEAN
+FAT_NTFS::ReserveCluster (
+ IN USHORT Cluster
+ )
+/*++
+
+Routine Description:
+
+ "Reserves" all the sectors in the given clusters. This is done
+ by marking the sectors in the ReservedBitmap.
+
+Arguments:
+
+ Cluster - Supplies cluster whose sectors are to be reserved
+
+Return Value:
+
+ BOOLEAN - TRUE if all sectors in the cluster have been reserved
+ FALSE otherwise
+
+--*/
+
+{
+ LCN Lcn;
+ BIG_INT Clusters;
+
+ DebugAssert( _ClusterFactor == 1 );
+
+ Clusters = ((ULONG)_FatSa->QuerySectorsPerCluster()) / _ClusterFactor;
+
+ if ( Cluster > 0 ) {
+
+ Lcn = FatClusterToLcn( Cluster );
+
+ _ReservedBitmap.SetAllocated( Lcn, Clusters );
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
+NONVIRTUAL
+BOOLEAN
+FAT_NTFS::CheckGeometryMatch(
+ )
+/*++
+
+Routine Description:
+
+ This method checks that the geometry recorded in the
+ Bios Parameter Block agrees with the geometry reported
+ by the driver.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the geometry in the BPB matches that reported
+ by the driver; false if not. Note that the only field
+ which is checked is BytesPerSector.
+
+--*/
+{
+ USHORT SectorSize, SectorsPerTrack, Heads;
+ ULONG HiddenSectors;
+
+ _FatSa->QueryGeometry( &SectorSize,
+ &SectorsPerTrack,
+ &Heads,
+ &HiddenSectors );
+
+ if( SectorSize != _Drive->QuerySectorSize() ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+
+BOOLEAN
+FAT_NTFS::WriteBoot (
+ IN BOOLEAN Pause
+ )
+
+/*++
+
+Routine Description:
+
+ Updates the boot sector and writes any other information (e.g.
+ partition data) so that the volume will be recognized as an NTFS
+ volume.
+
+Arguments:
+
+ Pause - If set, we pause before rebooting the machine
+
+Return Value:
+
+ BOOLEAN - TRUE if boot sector updated
+ FALSE otherwise
+
+--*/
+
+{
+ HMEM BootCodeMem;
+ SECRUN BootCodeSecrun;
+ FSTRING BootLogFileName;
+
+
+ BOOLEAN Done;
+
+ Done = (BOOLEAN)(_Mft.Flush() &&
+ _NtfsSa.Write( _Message ) &&
+ _NtfsSa.WriteRemainingBootCode());
+
+#if defined ( _AUTOCONV_ )
+
+ if ( Done ) {
+
+ //
+ // The volume is no longer FAT. We have to reboot so that the
+ // system recognizes it. Note that before we reboot, we
+ // must flush the drive's cache.
+ //
+ BootLogFileName.Initialize( L"bootex.log" );
+
+ if( _Message->IsLoggingEnabled() &&
+ !NTFS_SA::DumpMessagesToFile( &BootLogFileName,
+ &_Mft,
+ _Message ) ) {
+
+ DebugPrintf( "CONVERT: Error writing messages to BOOTEX.LOG\n" );
+ }
+
+ _Drive->FlushCache();
+
+ //
+ // Unlock the volume and close our handle, to let the filesystem
+ // notice that things have changed.
+ //
+
+ DELETE(_Drive);
+
+ if (Pause) {
+
+ _Message->Set( MSG_CONV_PAUSE_BEFORE_REBOOT );
+ _Message->Display();
+
+ _Message->WaitForUserSignal();
+ }
+
+ //
+ // If we've paused for oem setup, we pass PowerOff = TRUE to
+ // Reboot.
+ //
+
+ IFS_SYSTEM::Reboot( Pause );
+ }
+
+#endif
+
+ return Done;
+}
diff --git a/private/utils/cufat/src/makefile b/private/utils/cufat/src/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/cufat/src/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/cufat/src/pch.cxx b/private/utils/cufat/src/pch.cxx
new file mode 100644
index 000000000..3c6bf9c40
--- /dev/null
+++ b/private/utils/cufat/src/pch.cxx
@@ -0,0 +1,19 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ pch.cxx
+
+Abstract:
+
+ This module is used to pre-compiles cufat headers.
+
+Author:
+
+ Matthew Bradburn (mattbr) 27-Apr-1994
+
+--*/
+
+#define _NTAPI_ULIB_
diff --git a/private/utils/cufat/src/sources b/private/utils/cufat/src/sources
new file mode 100644
index 000000000..4c41301d7
--- /dev/null
+++ b/private/utils/cufat/src/sources
@@ -0,0 +1,76 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=utils
+MINORCOMP=cufat
+
+TARGETNAME=cnvfat
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ ..\..\ulib\src\obj\*\ulib.lib \
+ ..\..\ufat\src\obj\*\ufat.lib \
+ ..\..\untfs\src\obj\*\untfs.lib \
+ ..\..\ifsutil\src\obj\*\ifsutil.lib
+
+USE_CRTDLL=1
+BLDCRT=1
+
+DLLENTRY=InitializeCufat
+
+PRECOMPILED_INCLUDE= pch.cxx
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=convfat.cxx \
+ cufat.cxx \
+ cufat.rc \
+ fatntfs.cxx
+
+INCLUDES=..\inc;..\..\ufat\inc;..\..\untfs\inc;..\..\ulib\inc;..\..\ifsutil\inc;\nt\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+CXXFLAGS=+d
+UMLIBS=obj\*\cufat.lib
+
+UMTYPE=console
+
+UMTEST=
+
+UMRES=obj\*\cufat.res
+
+DLLDEF=cufat.def
diff --git a/private/utils/cuhpfs/bldnames.cxx b/private/utils/cuhpfs/bldnames.cxx
new file mode 100644
index 000000000..3c9ac2d55
--- /dev/null
+++ b/private/utils/cuhpfs/bldnames.cxx
@@ -0,0 +1,468 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ bldnames.cxx
+
+Abstract:
+
+ This module contains the routines which build up the name-translation
+ table.
+
+Author:
+
+ Bill McJohn (billmc) 02-Mar-1994
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+
+#include "wstring.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+
+#include "nametab.hxx"
+
+#include "uhpfs.hxx"
+#include "hpfsvol.hxx"
+#include "hpfssa.hxx"
+#include "superb.hxx"
+#include "cpinfo.hxx"
+#include "fnode.hxx"
+#include "dirblk.hxx"
+
+// Private prototypes:
+//
+BOOLEAN
+NameIsCodepageInvariant(
+ IN USHORT NameLength,
+ IN PSTR Name
+ );
+
+BOOLEAN
+ConstructNameTableFromDirblk(
+ IN OUT PHPFS_VOL HpfsVol,
+ IN OUT PHPFS_SA HpfsSa,
+ IN LBN DirblkLbn,
+ IN OUT PNAME_TABLE NameTable,
+ IN OUT PMESSAGE Message,
+ IN PCWSTRING Path
+ );
+
+BOOLEAN
+ConstructNameTableFromFnode(
+ IN OUT PHPFS_VOL HpfsVol,
+ IN OUT PHPFS_SA HpfsSa,
+ IN LBN FnodeLbn,
+ IN OUT PNAME_TABLE NameTable,
+ IN OUT PMESSAGE Message,
+ IN PCWSTRING Path
+ );
+
+
+
+
+BOOLEAN
+NameIsCodepageInvariant(
+ IN USHORT NameLength,
+ IN PUCHAR Name
+ )
+/*++
+
+Routine Description:
+
+ This function determines whether a name is codepage-invariant,
+ i.e. has no characters greater than 127.
+
+Arguments:
+
+ NameLength -- Supplies the number of bytes in the name.
+ Name -- Supplies the name.
+
+Return Value:
+
+ TRUE if none of the bytes in the name are greater than 127.
+
+--*/
+{
+ USHORT i;
+ PUCHAR puch = (PUCHAR)Name;
+
+ for( i = 0; i < NameLength; i++ ) {
+
+ if( *puch > 127 ) {
+
+ return FALSE;
+ }
+
+ puch++;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+ConstructNameTableFromDirblk(
+ IN OUT PHPFS_VOL HpfsVol,
+ IN OUT PHPFS_SA HpfsSa,
+ IN LBN DirblkLbn,
+ IN OUT PNAME_TABLE NameTable,
+ IN OUT PMESSAGE Message,
+ IN PCWSTRING Path
+ )
+/*++
+
+Routine Description:
+
+ This adds to the Name Table the names in the directory sub-tree
+ rooted at DirblkLbn and all subdirectories.
+
+Arguments:
+
+ HpfsVol -- Supplies the HPFS Volume being converted.
+ HpfsSa -- Supplies the Super Area for the volume.
+ DirblkLbn -- Supplies the LBN for the Dirblk in question.
+ NameTable -- Supplies the name table being constructed.
+ Message -- Supplies an outlet for messages.
+ Path -- Supplies the path for the directory containing
+ this dirblk.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ CONST UnicodeBufferLength = 256;
+ WCHAR UnicodeNameBuffer[UnicodeBufferLength];
+
+ FSTRING Backslash;
+ DSTRING ChildName, ChildPath;
+ DIRBLK Dirblk;
+ PDIRENTD CurrentEntry;
+ ULONG CurrentOffset;
+ ULONG UnicodeNameLength;
+ USHORT CodepageId;
+
+ Backslash.Initialize( L"\\" );
+
+ if( !Dirblk.Initialize( HpfsVol, HpfsSa->GetHotfixList(), DirblkLbn ) ) {
+
+ Message->Set( MSG_CONV_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Dirblk.Read() || !Dirblk.IsDirblk() ) {
+
+ Message->Set( MSG_CONV_HPFS_CORRUPT_VOLUME );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ // Spin through the directory entries in the DIRBLK, converting
+ // their names to Unicode and adding them to the Name Table.
+ // and recursing into child DIRBLK's.
+ //
+ CurrentEntry = Dirblk.GetFirstEntry();
+ CurrentOffset = Dirblk.QueryEntryOffset( CurrentEntry );
+
+ while( TRUE ) {
+
+ if( CurrentOffset + sizeof( USHORT ) > DIRBLK_SIZE ||
+ CurrentOffset + CurrentEntry->cchThisEntry > DIRBLK_SIZE ||
+ CurrentEntry->cchThisEntry == 0 ) {
+
+ Message->Set( MSG_CONV_HPFS_CORRUPT_VOLUME );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ // If this DIRBLK has a child, recurse into it.
+ //
+ if( (CurrentEntry->fFlags & DF_BTP) &&
+ !ConstructNameTableFromDirblk( HpfsVol,
+ HpfsSa,
+ BTP(CurrentEntry),
+ NameTable,
+ Message,
+ Path ) ) {
+
+ return FALSE;
+ }
+
+ if( CurrentEntry->fFlags & DF_END ) {
+
+ break;
+ }
+
+ if( CurrentEntry->fFlags & DF_SPEC ) {
+
+ // Move on to the next entry.
+ //
+ CurrentOffset += CurrentEntry->cchThisEntry;
+ CurrentEntry = NEXT_ENTRY( CurrentEntry );
+ continue;
+ }
+
+ if( CurrentEntry->cchName == 0 ) {
+
+ Message->Set( MSG_CONV_HPFS_CORRUPT_VOLUME );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ // Convert the name of this directory entry and
+ // add it to the name table. Note that it can
+ // be omitted from the name-table if it is
+ // codepage-invariant, but we need the unicode
+ // name to construct the full path.
+ //
+ CodepageId = HpfsSa->GetCasemap()->
+ QueryCodepageId( CurrentEntry->bCodePage );
+
+ UnicodeNameLength =
+ MultiByteToWideChar( CodepageId,
+ MB_PRECOMPOSED,
+ (PCHAR)&CurrentEntry->bName[0],
+ CurrentEntry->cchName,
+ UnicodeNameBuffer,
+ UnicodeBufferLength );
+
+ if( UnicodeNameLength == 0 ) {
+
+ if( Path->QueryChCount() == 0 ) {
+ Message->Set( MSG_CONV_INCONVERTIBLE_NAME_IN_ROOT );
+ Message->Display( "" );
+ } else {
+ Message->Set( MSG_CONV_INCONVERTIBLE_NAME );
+ Message->Display( "%W", Path );
+ }
+ return FALSE;
+ }
+
+ if( !NameIsCodepageInvariant( CurrentEntry->cchName,
+ &CurrentEntry->bName[0] ) ) {
+
+ if( !NameTable->Add( CodepageId,
+ CurrentEntry->cchName,
+ &CurrentEntry->bName[0],
+ (USHORT)UnicodeNameLength,
+ UnicodeNameBuffer ) ) {
+
+ Message->Set( MSG_CONV_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+ }
+
+ // If it's a subdirectory, recurse into it.
+ //
+ if( CurrentEntry->fAttr & ATTR_DIRECTORY ) {
+
+ if( !ChildName.Initialize( UnicodeNameBuffer, UnicodeNameLength ) ||
+ !ChildPath.Initialize( Path ) ||
+ !ChildPath.Strcat( &Backslash ) ||
+ !ChildPath.Strcat( &ChildName ) ) {
+
+ Message->Set( MSG_CONV_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !ConstructNameTableFromFnode( HpfsVol,
+ HpfsSa,
+ CurrentEntry->lbnFnode,
+ NameTable,
+ Message,
+ &ChildPath ) ) {
+
+ return FALSE;
+ }
+ }
+
+ // Move on to the next entry.
+ //
+ CurrentOffset += CurrentEntry->cchThisEntry;
+ CurrentEntry = NEXT_ENTRY( CurrentEntry );
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+ConstructNameTableFromFnode(
+ IN OUT PHPFS_VOL HpfsVol,
+ IN OUT PHPFS_SA HpfsSa,
+ IN LBN FnodeLbn,
+ IN OUT PNAME_TABLE NameTable,
+ IN OUT PMESSAGE Message,
+ IN PCWSTRING Path
+ )
+/*++
+
+Routine Description:
+
+ This adds to the Name Table the names in the directory which has
+ its FNODE at FnodeLbn, and all subdirectories.
+
+Arguments:
+
+Return Value:
+
+ HpfsVol -- Supplies the HPFS Volume being converted.
+ HpfsSa -- Supplies the Super Area for the volume.
+ FnodeLbn -- Supplies the LBN for the FNode in question.
+ Note that this must be a directory FNode.
+ NameTable -- Supplies the name table being constructed.
+ Message -- Supplies an outlet for messages.
+
+--*/
+{
+ FNODE Fnode;
+
+ if( !Fnode.Initialize( HpfsVol, FnodeLbn ) ) {
+
+ Message->Set( MSG_CONV_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Fnode.Read() || !Fnode.IsFnode() ) {
+
+ Message->Set( MSG_CONV_HPFS_CORRUPT_VOLUME );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ return( ConstructNameTableFromDirblk( HpfsVol,
+ HpfsSa,
+ Fnode.QueryRootDirblkLbn(),
+ NameTable,
+ Message,
+ Path ) );
+}
+
+extern "C"
+BOOLEAN
+FAR APIENTRY
+ConstructNameTable(
+ IN PCWSTRING NtDriveName,
+ IN PCWSTRING FileName,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This function creates a MBCS-to-Unicode name translation
+ table for use by Autoconv. This allows Convert to squirrel
+ away Unicode translations for names that Autoconv can't
+ translate for itself.
+
+Arguments:
+
+ NtDriveName -- Supplies the name of the volume for which the
+ name table is to be created.
+ FileName -- Supplies the name of the file in which the name
+ table will be stored. (This file will always
+ be in the root directory of the volume being
+ converted.)
+ Message -- Supplies an outlet for messages.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ HPFS_VOL HpfsVol;
+ PHPFS_SA HpfsSa;
+ NAME_TABLE NameTable;
+ FSTRING BackSlash, RootName;
+ DSTRING QualifiedFileName;
+
+ if( !BackSlash.Initialize( L"\\" ) ||
+ !QualifiedFileName.Initialize( NtDriveName ) ||
+ !QualifiedFileName.Strcat( &BackSlash ) ||
+ !QualifiedFileName.Strcat( FileName ) ) {
+
+ Message->Set( MSG_CONV_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !NameTable.Initialize() ) {
+
+ Message->Set( MSG_CONV_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ // Initialize the HPFS volume object and set up the helpers
+ // (bitmap, codepage and casemap, and hotfix list)
+ //
+ if( !HpfsVol.Initialize( NtDriveName, Message ) ) {
+
+ return FALSE;
+ }
+
+ HpfsSa = HpfsVol.GetHPFSSuperArea();
+
+ if( !HpfsSa->CheckSuperBlockSignatures() ) {
+
+ Message->Set( MSG_CONV_HPFS_NOT_HPFS );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !HpfsSa->IsClean() ) {
+
+ Message->Set( MSG_CONV_HPFS_DIRTY_VOLUME );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( HpfsSa->GetSpare()->QueryHotFixCount() != 0 ||
+ HpfsSa->GetSpare()->IsHotFixesUsed() ) {
+
+ Message->Set( MSG_CONV_HPFS_HOTFIXES_PRESENT );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !HpfsSa->SetupHelpers() ) {
+
+ Message->Set( MSG_CONV_HPFS_CORRUPT_VOLUME );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ Message->Set( MSG_CONV_CONSTRUCTING_NAME_TABLE );
+ Message->Display( "" );
+
+ RootName.Initialize( L"" );
+
+ if( !ConstructNameTableFromFnode( &HpfsVol,
+ HpfsSa,
+ HpfsSa->GetSuper()->QueryRootFnodeLbn(),
+ &NameTable,
+ Message,
+ &RootName ) ||
+ !NameTable.Write( &QualifiedFileName, Message ) ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/cuhpfs/cuhpfs.cxx b/private/utils/cuhpfs/cuhpfs.cxx
new file mode 100644
index 000000000..c1bc3ff66
--- /dev/null
+++ b/private/utils/cuhpfs/cuhpfs.cxx
@@ -0,0 +1,370 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ cvthpfs.cxx
+
+Abstract:
+
+ This module contains the declaration of ConvertHPFS, which is
+ the main entry point for this DLL.
+
+Author:
+
+ Bill McJohn (billmc) 09-Jan-1992
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+
+#include "drive.hxx"
+#include "rwcache.hxx"
+#include "intstack.hxx"
+#include "numset.hxx"
+
+#include "uhpfs.hxx"
+#include "hpfsvol.hxx"
+#include "hpfssa.hxx"
+
+#include "cuhpfs.hxx"
+#include "nametab.hxx"
+
+DECLARE_CLASS( NAME_TABLE );
+DECLARE_CLASS( NAME_LOOKUP_TABLE );
+
+extern "C" BOOLEAN
+InitializeCuhpfs (
+ PVOID DllHandle,
+ ULONG Reason,
+ PCONTEXT Context
+ )
+/*++
+
+Routine Description:
+
+ This function is the initialization entry point for CUHPFS.DLL.
+ At present, it's a null function, but this is where any initialization
+ goes if it's ever needed.
+
+--*/
+{
+ if( !DEFINE_CLASS_DESCRIPTOR( NAME_TABLE ) ||
+ !DEFINE_CLASS_DESCRIPTOR( NAME_LOOKUP_TABLE ) ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+FAR APIENTRY
+ConvertHPFSVolume(
+ IN PHPFS_VOL HpfsVolume,
+ IN PCWSTRING TargetFileSystem,
+ IN PCNAME_LOOKUP_TABLE NameTable,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ OUT PCONVERT_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ This function converts an opened HPFS Volume to a new file system.
+
+Arguments:
+
+ Drive -- Supplies the drive to convert. Note that
+ it the caller must lock the drive (Convert)
+ or open it for exclusive write access
+ (Autoconvert).
+ TargetFileSystem -- Supplies the file system to which the drive
+ will be converted. Note that only "NTFS"
+ is presently supported.
+ Message -- Supplies an outlet for messages.
+ Verbose -- Supplies a flag indicating (if TRUE) that
+ conversion should be carried out in verbose mode.
+ Status -- Receives the status of the conversion.
+
+
+--*/
+{
+ PREAD_WRITE_CACHE RwCache;
+ NUMBER_SET BadSectorSet;
+ DSTRING FatString, HpfsString, NtfsString, CdfsString;
+
+ PHPFS_SA HpfsSuperArea;
+ PLBN BadLbnList;
+
+ ULONG NumberOfBadLbns, ActualNumberOfBadLbns, i;
+ BOOLEAN Result, Corrupt;
+
+
+ // Load in the read write cache.
+
+ if ((RwCache = NEW READ_WRITE_CACHE) &&
+ RwCache->Initialize( HpfsVolume, 75 )) {
+
+ HpfsVolume->SetCache(RwCache);
+ } else {
+ DELETE(RwCache);
+ }
+
+
+
+ // Check that this volume meets the requirements for conversion.
+ // It must be a clean HPFS volume with no hotfixes.
+
+ HpfsSuperArea = HpfsVolume->GetHPFSSuperArea();
+
+ if( !HpfsSuperArea->CheckSuperBlockSignatures() ) {
+
+ Message->Set( MSG_CONV_HPFS_NOT_HPFS );
+ Message->Display( "" );
+
+ *Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+ if( HpfsSuperArea->GetSuper()->QueryVersion() != SUPERB_VERSION ||
+ ( HpfsSuperArea->GetSuper()->QueryFuncVersion() != SUPERB_FVERSION_2 &&
+ HpfsSuperArea->GetSuper()->QueryFuncVersion() != SUPERB_FVERSION_3 ) ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_WRONG_VERSION );
+ Message->Display( "" );
+
+ return FALSE;
+ }
+
+
+ if( !HpfsSuperArea->IsClean() ) {
+
+ Message->Set( MSG_CONV_HPFS_DIRTY_VOLUME );
+ Message->Display( "" );
+
+ *Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+ if( HpfsSuperArea->GetSpare()->QueryHotFixCount() != 0 ||
+ HpfsSuperArea->GetSpare()->IsHotFixesUsed() ) {
+
+ Message->Set( MSG_CONV_HPFS_HOTFIXES_PRESENT );
+ Message->Display( "" );
+
+ *Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+
+ // Fetch the list of bad lbns and bundle them up into an intstack.
+
+ NumberOfBadLbns = HpfsSuperArea->GetSuper()->QueryBadSectors();
+
+ if( (BadLbnList = (PLBN)MALLOC( NumberOfBadLbns * sizeof(LBN) )) ==
+ NULL ) {
+
+ Message->Set( MSG_CONV_NO_MEMORY );
+ Message->Display( "" );
+
+ DebugPrint( "Insufficient memory.\n" );
+ *Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+ if( !HpfsSuperArea->QueryBadLbns( NumberOfBadLbns,
+ BadLbnList,
+ &ActualNumberOfBadLbns ) ) {
+
+ Message->Set( MSG_CONV_HPFS_CORRUPT_VOLUME );
+ Message->Display( "" );
+
+ FREE( BadLbnList );
+ *Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+ if( !BadSectorSet.Initialize() ) {
+
+ Message->Set( MSG_CONV_NO_MEMORY );
+ Message->Display( "" );
+
+ FREE( BadLbnList );
+ *Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+ for( i = 0; i < ActualNumberOfBadLbns; i++ ) {
+
+ if( !BadSectorSet.Add( BadLbnList[i] ) ) {
+
+ Message->Set( MSG_CONV_NO_MEMORY );
+ Message->Display( "" );
+
+ FREE( BadLbnList );
+ *Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+ }
+
+
+ // Tell the HPFS SuperArea to read its codepage information
+
+ if( !HpfsSuperArea->ReadCodepage() ) {
+
+ Message->Set( MSG_CONV_HPFS_CORRUPT_VOLUME );
+ Message->Display( "" );
+
+ FREE( BadLbnList );
+ *Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+
+ // Determine whether the target file system is supported. Set up
+ // a WSTRING for each recognized target file system.
+
+ if( !FatString.Initialize( "FAT" ) ||
+ !HpfsString.Initialize( "HPFS" ) ||
+ !NtfsString.Initialize( "NTFS" ) ||
+ !CdfsString.Initialize( "CDFS" ) ) {
+
+ Message->Set( MSG_CONV_NO_MEMORY );
+ Message->Display( "" );
+
+ FREE( BadLbnList );
+ *Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+ if( *TargetFileSystem == NtfsString ) {
+
+ Result = ConvertToNtfs( HpfsVolume,
+ NameTable,
+ &BadSectorSet,
+ Message,
+ Verbose,
+ &Corrupt );
+
+ *Status = (Result) ? CONVERT_STATUS_CONVERTED : CONVERT_STATUS_ERROR;
+
+ if( !Result && Corrupt ) {
+
+ Message->Set( MSG_CONV_HPFS_CORRUPT_VOLUME );
+ Message->Display( "" );
+ }
+
+ } else if ( *TargetFileSystem == FatString ||
+ *TargetFileSystem == HpfsString ||
+ *TargetFileSystem == CdfsString ) {
+
+ // recognized but unsupported target
+
+ *Status = CONVERT_STATUS_CONVERSION_NOT_AVAILABLE;
+ Result = FALSE;
+
+ } else {
+
+ *Status = CONVERT_STATUS_INVALID_FILESYSTEM;
+ Result = FALSE;
+ }
+
+
+ FREE( BadLbnList );
+ return Result;
+
+}
+
+BOOLEAN
+FAR APIENTRY
+ConvertHPFS(
+ IN PCWSTRING NtDriveName,
+ IN PCWSTRING TargetFileSystem,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ OUT PCONVERT_STATUS Status
+ )
+/*++
+
+Routine Description:
+
+ This function converts an HPFS volume to the target file system
+ in-place.
+
+ This function opens and locks the volume, so it is not suitable
+ for use by autoconvert.
+
+Arguments:
+
+ NtDriveName -- Supplies the name of the drive.
+ TargetFileSystem -- Supplies the file system to which the drive
+ will be converted. Note that only "NTFS"
+ is presently supported.
+ Message -- Supplies an outlet for messages.
+ Verbose -- Supplies a flag indicating (if TRUE) that
+ conversion should be carried out in verbose mode.
+ Status -- Receives the status of the conversion.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ HPFS_VOL HpfsVolume;
+ DP_DRIVE DpDrive;
+
+ // Make sure that the volume does not have a queer sector size.
+
+ if (!DpDrive.Initialize(NtDriveName, Message)) {
+ *Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+ if (DpDrive.QuerySectorSize() != 512) {
+ Message->Set(MSG_CONVERT_UNSUPPORTED_SECTOR_SIZE);
+ Message->Display("%W", TargetFileSystem);
+ *Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+
+ // Initialize and lock the volume.
+
+ if( !HpfsVolume.Initialize( NtDriveName, Message )) {
+
+ *Status = CONVERT_STATUS_ERROR;
+ return FALSE;
+ }
+
+ // Lock the volume for exclusive access.
+
+ if( !HpfsVolume.Lock() ) {
+
+ *Status = CONVERT_STATUS_CANNOT_LOCK_DRIVE;
+ return FALSE;
+ }
+
+ return( ConvertHPFSVolume( &HpfsVolume,
+ TargetFileSystem,
+ NULL,
+ Message,
+ Verbose,
+ Status ) );
+
+}
diff --git a/private/utils/cuhpfs/cuhpfs.def b/private/utils/cuhpfs/cuhpfs.def
new file mode 100644
index 000000000..ed9f9bfe5
--- /dev/null
+++ b/private/utils/cuhpfs/cuhpfs.def
@@ -0,0 +1,9 @@
+LIBRARY CUHPFS
+
+DESCRIPTION File System Conversion Library for HPFS
+
+DATA NONSHARED
+
+EXPORTS
+ ConvertHPFS
+ ConstructNameTable
diff --git a/private/utils/cuhpfs/cuhpfs.hxx b/private/utils/cuhpfs/cuhpfs.hxx
new file mode 100644
index 000000000..5efa7873d
--- /dev/null
+++ b/private/utils/cuhpfs/cuhpfs.hxx
@@ -0,0 +1,182 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ cuhpfs.hxx
+
+Abstract:
+
+ This module contains function prototypes for the HPFS conversion
+ functions.
+
+Author:
+
+ Bill McJohn (billmc) 2-Dec-1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include "untfs.hxx"
+#include "uhpfs.hxx"
+#include "ifsentry.hxx"
+#include "dirblk.hxx"
+
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( HPFS_VOL );
+DECLARE_CLASS( NTFS_BITMAP );
+DECLARE_CLASS( HPFS_MAIN_BITMAP );
+DECLARE_CLASS( HPFS_VOL );
+DECLARE_CLASS( CASEMAP );
+DECLARE_CLASS( NTFS_MFT_FILE );
+DECLARE_CLASS( FNODE );
+DECLARE_CLASS( NTFS_FILE_RECORD_SEGMENT );
+DECLARE_CLASS( DIRBLK );
+DECLARE_CLASS( NTFS_INDEX_TREE );
+DECLARE_CLASS( NUMBER_SET );
+DECLARE_CLASS( NAME_LOOKUP_TABLE );
+
+extern "C" BOOLEAN
+InitializeCuhpfs (
+ PVOID DllHandle,
+ ULONG Reason,
+ PCONTEXT Context
+ );
+
+BOOLEAN
+FAR APIENTRY
+ConvertHPFSVolume(
+ IN OUT PHPFS_VOL Drive,
+ IN PCWSTRING TargetFileSystem,
+ IN PCNAME_LOOKUP_TABLE NameTable OPTIONAL,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ OUT PCONVERT_STATUS Status
+ );
+
+extern "C" BOOLEAN
+FAR APIENTRY
+ConvertHPFS(
+ IN PCWSTRING NtDriveName,
+ IN PCWSTRING TargetFileSystem,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ OUT PCONVERT_STATUS Status
+ );
+
+BOOLEAN
+ConvertToNtfs(
+ IN OUT PHPFS_VOL HpfsVol,
+ IN PCNAME_LOOKUP_TABLE NameTable OPTIONAL,
+ IN PNUMBER_SET BadSectors,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ OUT PBOOLEAN Corrupt
+ );
+
+BOOLEAN
+ConvertFileFnodeToNtfs(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap,
+ IN OUT PNTFS_MFT_FILE Mft,
+ IN OUT PFNODE Fnode,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT TargetFrs,
+ IN ULONG FileSize,
+ IN OUT PBOOLEAN IsCorrupt,
+ IN PCWSTRING FullPath
+ );
+
+
+BOOLEAN
+ConvertDirectoryToNtfs(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN PCNAME_LOOKUP_TABLE NameTable OPTIONAL,
+ IN OUT PMESSAGE Message,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap,
+ IN PCASEMAP Casemap,
+ IN OUT PNTFS_MFT_FILE Mft,
+ IN ULONG ClustersPerIndexBuffer,
+ IN LBN RootDirblkLbn,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT TargetFrs,
+ IN OUT PBOOLEAN IsCorrupt,
+ IN BOOLEAN Verbose,
+ IN OUT PVOID NameBuffer,
+ IN ULONG NameBufferLength,
+ IN OUT PVOID EaBuffer,
+ IN ULONG EaBufferLength,
+ IN ULONG Level,
+ IN PCWSTRING DirectoryPath
+ );
+
+
+BOOLEAN
+ConvertDirentToNtfs(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN PCNAME_LOOKUP_TABLE NameTable OPTIONAL,
+ IN OUT PMESSAGE Message,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap,
+ IN PCASEMAP Casemap,
+ IN OUT PNTFS_MFT_FILE Mft,
+ IN ULONG ClustersPerIndexBuffer,
+ IN PDIRENTD DirectoryEntry,
+ IN OUT PNTFS_INDEX_TREE ParentIndex,
+ IN MFT_SEGMENT_REFERENCE ParentSegmentReference,
+ IN OUT PBOOLEAN IsCorrupt,
+ IN BOOLEAN Verbose,
+ IN OUT PVOID NameBuffer,
+ IN ULONG NameBufferLength,
+ IN OUT PVOID EaBuffer,
+ IN ULONG EaBufferLength,
+ IN ULONG Level,
+ IN PCWSTRING ParentDirectoryPath,
+ IN BOOLEAN ConvertLongNames
+ );
+
+
+BOOLEAN
+ConvertDirblkToNtfs(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN PCNAME_LOOKUP_TABLE NameTable OPTIONAL,
+ IN OUT PMESSAGE Message,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap,
+ IN PCASEMAP Casemap,
+ IN OUT PNTFS_MFT_FILE Mft,
+ IN ULONG ClustersPerIndexBuffer,
+ IN PDIRBLK Dirblk,
+ IN OUT PNTFS_INDEX_TREE NtfsIndex,
+ IN MFT_SEGMENT_REFERENCE IndexSegmentReference,
+ IN OUT PBOOLEAN IsCorrupt,
+ IN BOOLEAN Verbose,
+ IN OUT PVOID NameBuffer,
+ IN ULONG NameBufferLength,
+ IN OUT PVOID EaBuffer,
+ IN ULONG EaBufferLength,
+ IN ULONG Level,
+ IN PCWSTRING DirectoryPath,
+ IN BOOLEAN ConvertLongNames
+ );
+
+BOOLEAN
+ConvertEasToNtfs(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNTFS_MFT_FILE Mft,
+ IN OUT PFNODE Fnode,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT TargetFrs,
+ IN ULONG DirentEaSize,
+ IN ULONG CodepageId,
+ IN OUT PBOOLEAN IsCorrupt,
+ IN OUT PVOID NameBuffer,
+ IN ULONG NameBufferLength,
+ IN OUT PVOID EaBuffer,
+ IN ULONG EaBufferLength
+ );
diff --git a/private/utils/cuhpfs/cuhpfs.rc b/private/utils/cuhpfs/cuhpfs.rc
new file mode 100644
index 000000000..95761f88a
--- /dev/null
+++ b/private/utils/cuhpfs/cuhpfs.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "HPFS File System Conversion Utility DLL"
+#define VER_INTERNALNAME_STR "cuhpfs\0"
+#define VER_ORIGINALFILENAME_STR "CUHPFS.DLL"
+
+#include "common.ver"
diff --git a/private/utils/cuhpfs/cvtdir.cxx b/private/utils/cuhpfs/cvtdir.cxx
new file mode 100644
index 000000000..99e735307
--- /dev/null
+++ b/private/utils/cuhpfs/cvtdir.cxx
@@ -0,0 +1,1093 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ cvtdir.cxx
+
+Abstract:
+
+ This module contains the routines which convert an HPFS directory
+ to NTFS.
+
+
+Author:
+
+ Bill McJohn (billmc) 18-Nov-1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+
+#include "hmem.hxx"
+#include "rtmsg.h"
+
+#include "ifssys.hxx"
+#include "drive.hxx"
+#include "secrun.hxx"
+#include "cannedsd.hxx"
+
+#include "uhpfs.hxx"
+#include "bitmap.hxx"
+#include "dirblk.hxx"
+#include "error.hxx"
+#include "fnode.hxx"
+#include "message.hxx"
+#include "store.hxx"
+#include "cpinfo.hxx"
+
+#include "untfs.hxx"
+#include "attrib.hxx"
+#include "extents.hxx"
+#include "frs.hxx"
+#include "mft.hxx"
+#include "ntfsbit.hxx"
+#include "indxtree.hxx"
+#include "mftfile.hxx"
+
+#include "cuhpfs.hxx"
+#include "nametab.hxx"
+
+extern "C" ULONG
+GetAcp(
+ );
+
+BOOLEAN
+ConvertNameToUnicode(
+ IN ULONG CodepageId,
+ IN PSTR Name,
+ IN ULONG NameLength,
+ IN PWSTR Buffer,
+ IN ULONG BufferLength,
+ OUT PULONG CharsInUnicodeName
+ )
+/*++
+
+Routine Description:
+
+ This function converts the name contained in DirectoryEntry
+ into a unicode name.
+
+Arguments:
+
+ CodepageId -- Supplies the codepage with which the name
+ is associated.
+ Name -- Supplies the name to convert.
+ NameLength -- Supplies the length of the name to convert.
+ Buffer -- Supplies the target buffer for the conversion.
+ BufferLength -- Supplies the length (in bytes) of the
+ target buffer.
+ CharsInUnicodeName -- Receives the number of unicode characters
+ in the converted name.
+
+Return Value:
+
+ TRUE if successful.
+
+--*/
+{
+#ifdef _AUTOCHECK_ // AutoConvert--Windows API not available.
+
+ STATIC ULONG Acp = 0;
+ NTSTATUS Status;
+ PUCHAR puch;
+ ULONG BytesInUnicodeString, i;
+
+ // If we haven't already, fetch the system codepage ID.
+ //
+ if( Acp == 0 ) {
+
+ Acp = GetAcp();
+
+ if( Acp == 0 ) {
+
+ return FALSE;
+ }
+ }
+
+ if( Acp == CodepageId ) {
+
+ // This name is associated with the system codepage,
+ // so we can use the convenient RTL routines.
+ //
+ Status = RtlMultiByteToUnicodeN( Buffer,
+ BufferLength,
+ &BytesInUnicodeString,
+ Name,
+ NameLength );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ return FALSE;
+ }
+
+ *CharsInUnicodeName = BytesInUnicodeString / sizeof( WCHAR );
+ return TRUE;
+ }
+
+ // The name is not associated with the system codepage,
+ // so we have to be sneaky. If the name is codepage-invariant,
+ // we can convert it by just promoting the bytes to words.
+ //
+ puch = (PUCHAR)Name;
+
+ for( i = 0; i < NameLength; i++ ) {
+
+ if( *puch > 127 ) {
+
+ // Name is not codepage-invariant.
+ //
+ return FALSE;
+ }
+
+ Buffer[i] = (WCHAR)(*puch);
+ puch++;
+ }
+
+ *CharsInUnicodeName = NameLength;
+ return TRUE;
+
+#else // _AUTOCHECK_ not defined--use Windows API
+
+ ULONG CharsConverted;
+
+ CharsConverted = MultiByteToWideChar( CodepageId,
+ MB_PRECOMPOSED,
+ Name,
+ NameLength,
+ Buffer,
+ BufferLength );
+
+ if( CharsConverted == 0 ) {
+
+ return FALSE;
+
+ }
+
+ *CharsInUnicodeName = CharsConverted;
+ return TRUE;
+
+#endif
+}
+
+
+BOOLEAN
+ConvertDirectoryToNtfs(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN PCNAME_LOOKUP_TABLE NameTable,
+ IN OUT PMESSAGE Message,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap,
+ IN PCASEMAP Casemap,
+ IN OUT PNTFS_MFT_FILE Mft,
+ IN OUT ULONG ClustersPerIndexBuffer,
+ IN LBN RootDirblkLbn,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT TargetFrs,
+ IN OUT PBOOLEAN IsCorrupt,
+ IN BOOLEAN Verbose,
+ IN OUT PVOID NameBuffer,
+ IN ULONG NameBufferLength,
+ IN OUT PVOID EaBuffer,
+ IN ULONG EaBufferLength,
+ IN ULONG Level,
+ IN PCWSTRING DirectoryPath
+ )
+/*++
+
+Routine Description:
+
+ This method converts an HPFS Directory Fnode to NTFS. It converts
+ every directory entry in the directory, and constructs an NTFS index
+ over $FILE_NAME for the converted entries.
+
+Arguments:
+
+ Drive -- Supplies the drive being converted.
+ Message -- Supplies an outlet for messages.
+ VolumeBitmap -- Supplies the NTFS bitmap for the volume.
+ HpfsOnlyBitmap -- Supplies the bitmap of HPFS-only structures.
+ Casemap -- Supplies the case-mapping table for the
+ HPFS volume.
+ Mft -- Supplies the Master File Table.
+ RootDirblkLbn -- Supplies the LBN of the root dirblk of
+ this directory.
+ TargetFrs -- Supplies the FRS for the directory being
+ converted.
+ IsCorrupt -- Receives TRUE if the volume is found to be
+ corrupt. (Note that it may already be TRUE.)
+ Verbose -- Supplies a flag which indicates (if TRUE) that
+ every file converted should be displayed.
+ NameBuffer -- Supplies a scratch buffer for converting
+ directory entry names.
+ NameBufferLength -- Supplies the length (in bytes) of the file
+ name conversion buffer.
+ EaBuffer -- Supplies a scratch buffer for Extended
+ Attribute conversion.
+ EaBufferLength -- Supplies the length of EaBuffer
+ Level -- Supplies the depth of this directory
+ (root directory is level 0).
+ DirectoryPath -- Supplies the directory path, for display
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This method does not write TargetFrs.
+
+--*/
+{
+ NTFS_INDEX_TREE IndexTree;
+ DIRBLK ChildDirblk;
+ DSTRING FileNameIndexName;
+
+ // Create an index out of whole cloth. It's an index over
+ // $FILE_NAME, and its name is $I3.
+
+ if( !FileNameIndexName.Initialize( FileNameIndexNameData ) ||
+ !IndexTree.Initialize( $FILE_NAME,
+ Drive,
+ Mft->QueryClusterFactor(),
+ VolumeBitmap,
+ TargetFrs->GetUpcaseTable(),
+ COLLATION_FILE_NAME,
+ (UCHAR)ClustersPerIndexBuffer,
+ TargetFrs->QueryMaximumAttributeRecordSize()/2,
+ &FileNameIndexName ) ) {
+
+ return FALSE;
+ }
+
+ // Initialize the root dirblk. Note that Convert assumes that there
+ // are no hotfixes on the volume, so I can pass in NULL for the
+ // hotfix list.
+
+ if( !ChildDirblk.Initialize( Drive, NULL, RootDirblkLbn ) ) {
+
+ return FALSE;
+ }
+
+
+ // Read the dirblk and check that it is really a dirblk. If
+ // it's unreadable or not a dirblk, the volume is corrupt.
+
+ if( !ChildDirblk.Read() || !ChildDirblk.IsDirblk() ) {
+
+ *IsCorrupt = TRUE;
+ return FALSE;
+ }
+
+
+ // Convert the root dirblk. This will recursively convert the
+ // entire directory. Note that it takes two passes; on the
+ // first pass, only short names (ie. names which are both
+ // DOS and NTFS names) are converted; on the second, long
+ // names (names which require a generated short name) are
+ // converted. This prevents collisions between existing
+ // short names and generated short names.
+ //
+ if( !ConvertDirblkToNtfs( Drive,
+ NameTable,
+ Message,
+ VolumeBitmap,
+ HpfsOnlyBitmap,
+ Casemap,
+ Mft,
+ ClustersPerIndexBuffer,
+ &ChildDirblk,
+ &IndexTree,
+ TargetFrs->QuerySegmentReference(),
+ IsCorrupt,
+ Verbose,
+ NameBuffer,
+ NameBufferLength,
+ EaBuffer,
+ EaBufferLength,
+ Level,
+ DirectoryPath,
+ FALSE ) ||
+ !ConvertDirblkToNtfs( Drive,
+ NameTable,
+ Message,
+ VolumeBitmap,
+ HpfsOnlyBitmap,
+ Casemap,
+ Mft,
+ ClustersPerIndexBuffer,
+ &ChildDirblk,
+ &IndexTree,
+ TargetFrs->QuerySegmentReference(),
+ IsCorrupt,
+ Verbose,
+ NameBuffer,
+ NameBufferLength,
+ EaBuffer,
+ EaBufferLength,
+ Level,
+ DirectoryPath,
+ TRUE ) ) {
+
+ return FALSE;
+ }
+
+ // Save the index.
+
+ if( !IndexTree.Save( TargetFrs ) ) {
+
+ DebugPrint( "Couldn't save an index.\n" );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+
+VOID
+DisplayName(
+ IN OUT PMESSAGE Message,
+ IN PBYTE Name,
+ IN ULONG NameLength,
+ IN ULONG Level
+ )
+/*++
+
+Routine Description:
+
+ This method displays a file name. It indents entries under the
+ parent directory, so that the tree structure is evident.
+
+Arguments:
+
+ Message -- Supplies the outlet for messages.
+ Name -- Supplies the name to display.
+ NameLength -- Supplies the length of the name.
+ Level -- Supplies the level of the directory that
+ contains this name (zero is root).
+
+Return Value:
+
+ None.
+
+--*/
+{
+ STATIC CHAR NameDisplayBuffer[512];
+ ULONG NameStart;
+
+ // Insert a number of blanks in the name display buffer to
+ // correctly indent this name under its parent directory.
+
+ NameStart = Level * 4;
+
+ memset( NameDisplayBuffer, ' ', NameStart );
+
+ memcpy( NameDisplayBuffer + NameStart, Name, NameLength );
+
+ NameDisplayBuffer[NameStart + NameLength] = 0;
+
+ Message->Set( MSG_ONE_STRING_NEWLINE );
+ Message->Display( "%s", NameDisplayBuffer );
+}
+
+
+BOOLEAN
+GenerateDosName(
+ IN PFILE_NAME NtfsName,
+ OUT PFILE_NAME DosName,
+ IN ULONG DosNameMaxLength,
+ IN PNTFS_INDEX_TREE ParentIndex
+ )
+/*++
+
+Routine Description:
+
+ This function fills in the DosName with an 8.3 name constructed
+ from the given NtfsName, ensuring that the generated name does not
+ exist in the specified index.
+
+Arguments:
+
+ NtfsName -- Supplies the source name.
+ DosName -- Receives the generated DOS name.
+ DosNameMaxLength -- Supplies the maximum length (in chars) of
+ the file-name portion of the DOS name.
+ ParentIndex -- Supplies the index within which the generated
+ name must be unique.
+
+Return Value:
+
+ TRUE if successful, otherwise FALSE.
+
+--*/
+{
+ CONST ULONG MaximumToTry = 1024;
+
+ GENERATE_NAME_CONTEXT NameContext;
+ MFT_SEGMENT_REFERENCE SegmentReference;
+ UNICODE_STRING NtfsNameString, DosNameString;
+ ULONG i;
+ BOOLEAN Error = FALSE;
+
+ // Fill in the non-name portions of the file name. Note that the
+ // duplicated information will be set up when the FRS is flushed.
+ //
+ memset( DosName, 0, DosNameMaxLength );
+
+ DosName->ParentDirectory = NtfsName->ParentDirectory;
+ DosName->Flags = FILE_NAME_DOS;
+
+
+ memset( &NameContext, 0, sizeof( GENERATE_NAME_CONTEXT ) );
+
+ NtfsNameString.Length = NtfsName->FileNameLength * sizeof( WCHAR );
+ NtfsNameString.MaximumLength = NtfsNameString.Length;
+ NtfsNameString.Buffer = NtfsFileNameGetName( NtfsName );
+
+ DosNameString.Length = 0;
+ DosNameString.MaximumLength = (USHORT)DosNameMaxLength;
+ DosNameString.Buffer = NtfsFileNameGetName( DosName );
+
+ for( i = 0; i < MaximumToTry; i++ ) {
+
+ RtlGenerate8dot3Name( &NtfsNameString, FALSE, &NameContext, &DosNameString );
+
+ DosName->FileNameLength = DosNameString.Length / sizeof( WCHAR );
+
+ if( !ParentIndex->QueryFileReference( NtfsFileNameGetLength(DosName),
+ DosName,
+ 0,
+ &SegmentReference,
+ &Error ) ) {
+
+ // If no error occurred, then there is no matching name
+ // in the index, which means this name is acceptable;
+ // if an error did occur, I want to bail out. Either
+ // way, it's over.
+ //
+ return (!Error);
+ }
+ }
+
+ // Tried a whole lot of different names. None of them worked.
+ //
+ return FALSE;
+}
+
+CONST ULONG ShortNameBufferLength = 256;
+CONST ULONG MaximumDosNameLength = 14;
+BYTE ShortNameBuffer[ShortNameBufferLength];
+
+
+BOOLEAN
+ConvertDirentToNtfs(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN PCNAME_LOOKUP_TABLE NameTable,
+ IN OUT PMESSAGE Message,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap,
+ IN PCASEMAP Casemap,
+ IN OUT PNTFS_MFT_FILE Mft,
+ IN ULONG ClustersPerIndexBuffer,
+ IN PDIRENTD DirectoryEntry,
+ IN OUT PNTFS_INDEX_TREE ParentIndex,
+ IN MFT_SEGMENT_REFERENCE ParentSegmentReference,
+ IN OUT PBOOLEAN IsCorrupt,
+ IN BOOLEAN Verbose,
+ IN OUT PVOID NameBuffer,
+ IN ULONG NameBufferLength,
+ IN OUT PVOID EaBuffer,
+ IN ULONG EaBufferLength,
+ IN ULONG Level,
+ IN PCWSTRING ParentDirectoryPath,
+ IN BOOLEAN ConvertLongNames
+ )
+/*++
+
+Routine Description:
+
+ This function creates an NTFS File Record Segment which corresponds
+ to a given HPFS Directory Entry.
+
+Arguments:
+
+ Drive -- Supplies the drive being converted.
+ Message -- Supplies an outlet for messages.
+ VolumeBitmap -- Supplies the NTFS bitmap for the volume.
+ HpfsOnlyBitmap -- Supplies the bitmap of HPFS-only structures.
+ Casemap -- Supplies the case-mapping table for the
+ HPFS volume.
+ Mft -- Supplies the Master File Table.
+ DirectoryEntry -- Supplies the directory entry.
+ ParentIndex -- Supplies the index into which the converted
+ file or directory's name should be inserted.
+ ParentSegmentReference -- Supplies the segment reference of the File
+ Record Segment that contains the parent
+ index.
+ IsCorrupt -- Receives TRUE if the volume is found to
+ be corrupt.
+ Verbose -- Supplies a flag which indicates (if TRUE)
+ that every file converted should be displayed.
+ NameBuffer -- Supplies a scratch buffer for converting
+ file names.
+ NameBufferLength -- Supplies the length (in bytes) of the file
+ name conversion buffer.
+ EaBuffer -- Supplies a scratch buffer for Extended
+ Attribute conversion.
+ EaBufferLength -- Supplies the length of EaBuffer
+ Level -- Supplies the depth of the directory which
+ contains this dirent. (Root directory is
+ level 0).
+ ParentDirectoryPath -- Supplies the path of the parent directory,
+ for message display.
+ ConvertLongNames -- Supplies a flag which indicates whether
+ this pass is converting long or short names.
+ If the flag is FALSE, this entry is converted
+ only if it is a valid DOS name; if the flag
+ is TRUE, the entry is only converted if it
+ is not a valid DOS name.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ STANDARD_INFORMATION StandardInfo;
+ FNODE Fnode;
+ NTFS_FILE_RECORD_SEGMENT NewFrs;
+ FSTRING Backslash;
+ DSTRING Name, FullPath;
+
+ VCN NewFileNumber;
+ MFT_SEGMENT_REFERENCE SegmentReference;
+ PFILE_NAME FileName = (PFILE_NAME)NameBuffer;
+ PFILE_NAME ShortName = (PFILE_NAME)ShortNameBuffer;
+
+ ULONG CharsInUnicodeName;
+ USHORT UnicodeChars;
+ USHORT FrsFlags;
+ USHORT CodepageId;
+ BOOLEAN result, Error;
+
+ ULONG LegalAttributeBits = FAT_DIRENT_ATTR_READ_ONLY |
+ FAT_DIRENT_ATTR_HIDDEN |
+ FAT_DIRENT_ATTR_SYSTEM |
+ FAT_DIRENT_ATTR_ARCHIVE;
+
+ DebugPtrAssert( Drive );
+ DebugPtrAssert( Message );
+ DebugPtrAssert( VolumeBitmap );
+ DebugPtrAssert( HpfsOnlyBitmap );
+ DebugPtrAssert( Casemap );
+ DebugPtrAssert( Mft );
+ DebugPtrAssert( DirectoryEntry );
+ DebugPtrAssert( ParentIndex );
+ DebugPtrAssert( IsCorrupt );
+ DebugPtrAssert( NameBuffer );
+ DebugPtrAssert( EaBuffer );
+
+ // Set up a FILE_NAME structure for the name. This includes
+ // converting the name to Unicode. Note that the duplicated
+ // information will be updated when the FRS is flushed.
+ //
+ memset( NameBuffer, 0, NameBufferLength );
+ FileName = (PFILE_NAME)NameBuffer;
+
+ CodepageId = Casemap->QueryCodepageId( DirectoryEntry->bCodePage );
+
+ if( !ConvertNameToUnicode(
+ CodepageId,
+ (PSTR)(&DirectoryEntry->bName[0]),
+ DirectoryEntry->cchName,
+ (PWSTR)NtfsFileNameGetName( FileName ),
+ NameBufferLength,
+ &CharsInUnicodeName ) ) {
+
+ // Can't convert this name--look in the name
+ // translation table, if it was supplied.
+ //
+ UnicodeChars = (USHORT)NameBufferLength;
+
+ if( NameTable == NULL ) {
+
+ Message->Set( MSG_CONV_INCONVERTIBLE_NAME );
+ Message->Display( "%W", ParentDirectoryPath );
+ Message->Set( MSG_CONV_USE_NAMETABLE );
+ Message->Display( "" );
+ return FALSE;
+
+ } else if( !NameTable->Lookup( CodepageId,
+ DirectoryEntry->cchName,
+ (PUCHAR)(&DirectoryEntry->bName[0]),
+ &UnicodeChars,
+ (PWCHAR)NtfsFileNameGetName( FileName ) ) ) {
+
+ if( ParentDirectoryPath->QueryChCount() == 0 ) {
+
+ Message->Set( MSG_CONV_INCONVERTIBLE_NAME_IN_ROOT );
+ Message->Display( "" );
+
+ } else {
+
+ Message->Set( MSG_CONV_INCONVERTIBLE_NAME );
+ Message->Display( "%W", ParentDirectoryPath );
+ }
+
+ return FALSE;
+ }
+
+ CharsInUnicodeName = UnicodeChars;
+ }
+
+ FileName->ParentDirectory = ParentSegmentReference;
+ FileName->FileNameLength = (UCHAR)CharsInUnicodeName;
+ FileName->Flags = NTFS_SA::IsDosName(FileName) ?
+ (FILE_NAME_DOS | FILE_NAME_NTFS) :
+ (FILE_NAME_NTFS);
+
+ // Fill in the standard information: Creation Time and Last
+ // Access Time go directly over; Last Modification Time becomes
+ // both Last Change Time and Last Modification Time.
+
+ IFS_SYSTEM::ConvertHpfsTimeToNtfsTime( DirectoryEntry->timCreate,
+ &StandardInfo.CreationTime );
+
+ IFS_SYSTEM::ConvertHpfsTimeToNtfsTime( DirectoryEntry->timLastAccess,
+ &StandardInfo.LastAccessTime );
+
+ IFS_SYSTEM::ConvertHpfsTimeToNtfsTime( DirectoryEntry->timLastMod,
+ &StandardInfo.LastModificationTime );
+
+ IFS_SYSTEM::ConvertHpfsTimeToNtfsTime( DirectoryEntry->timLastMod,
+ &StandardInfo.LastChangeTime );
+
+ StandardInfo.FileAttributes = DirectoryEntry->fAttr & LegalAttributeBits;
+ StandardInfo.MaximumVersions = 0;
+ StandardInfo.VersionNumber = 0;
+
+ // Check that this entry should be converted on this pass:
+ //
+ if( (ConvertLongNames && (FileName->Flags & FILE_NAME_DOS)) ||
+ (!ConvertLongNames && !(FileName->Flags & FILE_NAME_DOS)) ) {
+
+ // This name does not get converted on this pass.
+ //
+ return TRUE;
+ }
+
+ // If Convert is running in verbose mode, display the name.
+ //
+ if( Verbose ) {
+
+ DisplayName( Message,
+ DirectoryEntry->bName,
+ DirectoryEntry->cchName,
+ Level );
+ }
+
+ // Set up the full path for this entry.
+ //
+ if( !Backslash.Initialize( L"\\" ) ||
+ !Name.Initialize( (PWSTR)NtfsFileNameGetName( FileName ),
+ FileName->FileNameLength ) ||
+ !FullPath.Initialize( ParentDirectoryPath ) ||
+ !FullPath.Strcat( &Backslash ) ||
+ !FullPath.Strcat( &Name ) ) {
+
+ Message->Set( MSG_CONV_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ // Initialize and read the entry's FNode. If this sector
+ // is unreadable or not an FNode, then the volume is corrupt.
+
+ if( !Fnode.Initialize( Drive, DirectoryEntry->lbnFnode ) ) {
+
+ DebugPrintf( "CONVERT: can't initialize FNode\n" );
+ return FALSE;
+ }
+
+ if( !Fnode.Read() || !Fnode.IsFnode() ) {
+
+ *IsCorrupt = TRUE;
+ DebugPrintf( "CONVERT: Bad FNode at lbn 0x%x\n", DirectoryEntry->lbnFnode );
+ return FALSE;
+ }
+
+ // Set up a new File Record Segment for the file or directory.
+
+ FrsFlags = 0;
+
+ if( DirectoryEntry->fAttr & ATTR_DIRECTORY ) {
+
+ FrsFlags |= FILE_FILE_NAME_INDEX_PRESENT;
+ }
+
+ if( !Mft->AllocateFileRecordSegment( &NewFileNumber, FALSE ) ||
+ !NewFrs.Initialize( NewFileNumber, Mft ) ||
+ !NewFrs.Create( &StandardInfo, FrsFlags ) ||
+ !NewFrs.AddFileNameAttribute( FileName ) ||
+ !NewFrs.AddSecurityDescriptor( NoAclCannedSd,
+ VolumeBitmap ) ) {
+
+ // Insufficient disk space or insufficient memory.
+
+ DebugPrintf( "CONVERT: ConvertDirectoryEntryToNtfs--can't create FRS.\n" );
+ return FALSE;
+ }
+
+ // Add an entry for the new File Record Segment to the parent
+ // index. Note that the value of the index entry is the entire
+ // FILE_NAME structure (which is the value of the $FILE_NAME
+ // attribute).
+ //
+ if( ParentIndex->QueryFileReference( NtfsFileNameGetLength( FileName ),
+ FileName,
+ 0,
+ &SegmentReference,
+ &Error ) ) {
+
+ // This entry already exists in the index--since duplicates
+ // are not legal under NTFS, the conversion fails. Note that
+ // this condition can arise on a legal HPFS volume, since two
+ // distinct MBCS names can map to the same Unicode name.
+ //
+ Message->Set( MSG_CONV_DUPLICATE_NAME );
+ Message->Display( "%W", ParentDirectoryPath );
+ return FALSE;
+ }
+
+ if( !ParentIndex->InsertEntry( NtfsFileNameGetLength( FileName ),
+ FileName,
+ NewFrs.QuerySegmentReference() ) ) {
+
+ DebugPrintf( "CONVERT: Can't add entry to index\n" );
+ return FALSE;
+ }
+
+ // If the file name is not dos-compatible, generate an
+ // 8.3 name and add it to the index and the FRS.
+ //
+ if( !(FileName->Flags & FILE_NAME_DOS) ) {
+
+ if( !GenerateDosName( FileName,
+ ShortName,
+ MaximumDosNameLength,
+ ParentIndex ) ) {
+
+ DebugPrintf( "HPFS Convert: can't generate a DOS name.\n" );
+ return FALSE;
+ }
+
+ ShortName->Flags = FILE_NAME_DOS;
+
+ if( !ParentIndex->InsertEntry( NtfsFileNameGetLength(ShortName),
+ ShortName,
+ NewFrs.QuerySegmentReference() ) ||
+ !NewFrs.AddFileNameAttribute( ShortName ) ) {
+
+ DebugPrintf( "HPFS Convert: can't add DOS name to FRS.\n" );
+ return FALSE;
+ }
+ }
+
+
+ if( DirectoryEntry->fAttr & ATTR_DIRECTORY ) {
+
+ // This entry represents a directory--convert it.
+
+ result = ConvertDirectoryToNtfs( Drive,
+ NameTable,
+ Message,
+ VolumeBitmap,
+ HpfsOnlyBitmap,
+ Casemap,
+ Mft,
+ ClustersPerIndexBuffer,
+ Fnode.QueryRootDirblkLbn(),
+ &NewFrs,
+ IsCorrupt,
+ Verbose,
+ NameBuffer,
+ NameBufferLength,
+ EaBuffer,
+ EaBufferLength,
+ Level + 1,
+ &FullPath ) ;
+
+ } else {
+
+ // This entry represents a file--convert it.
+
+ result = ConvertFileFnodeToNtfs( Drive,
+ VolumeBitmap,
+ HpfsOnlyBitmap,
+ Mft,
+ &Fnode,
+ &NewFrs,
+ DirectoryEntry->cchFSize,
+ IsCorrupt,
+ &FullPath ) ;
+ }
+
+ if( result ) {
+
+ // Convert the Extended Attributes and write the FRS.
+
+ if( !ConvertEasToNtfs( Drive,
+ VolumeBitmap,
+ Mft,
+ &Fnode,
+ &NewFrs,
+ DirectoryEntry->ulEALen,
+ Casemap->
+ QueryCodepageId(DirectoryEntry->bCodePage),
+ IsCorrupt,
+ NameBuffer,
+ NameBufferLength,
+ EaBuffer,
+ EaBufferLength ) ) {
+
+ DebugPrintf( "Cannot convert EAs in fnode at lbn 0x%x.\n, DirectoryEntry->lbnFnode" );
+ return FALSE;
+ }
+
+ result = NewFrs.Flush( VolumeBitmap, ParentIndex );
+ }
+
+ return result;
+}
+
+
+
+BOOLEAN
+ConvertDirblkToNtfs(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN PCNAME_LOOKUP_TABLE NameTable,
+ IN OUT PMESSAGE Message,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap,
+ IN PCASEMAP Casemap,
+ IN OUT PNTFS_MFT_FILE Mft,
+ IN ULONG ClustersPerIndexBuffer,
+ IN PDIRBLK Dirblk,
+ IN OUT PNTFS_INDEX_TREE NtfsIndex,
+ IN MFT_SEGMENT_REFERENCE IndexSegmentReference,
+ IN OUT PBOOLEAN IsCorrupt,
+ IN BOOLEAN Verbose,
+ IN OUT PVOID NameBuffer,
+ IN ULONG NameBufferLength,
+ IN OUT PVOID EaBuffer,
+ IN ULONG EaBufferLength,
+ IN ULONG Level,
+ IN PCWSTRING DirectoryPath,
+ IN BOOLEAN ConvertLongNames
+ )
+/*++
+
+Routine Description:
+
+ This method converts the entries in an HPFS Dirblk to NTFS.
+ It also recurses into any child dirblks and converts them, too.
+
+
+Arguments:
+
+ Drive -- Supplies the drive being converted.
+ Message -- Supplies an outlet for messages.
+ VolumeBitmap -- Supplies the NTFS bitmap for the volume.
+ HpfsOnlyBitmap -- Supplies the bitmap of HPFS-only structures.
+ Casemap -- Supplies the case-mapping table for the
+ HPFS volume.
+ Mft -- Supplies the Master File Table.
+ NtfsIndex -- Supplies the NTFS index which corresponds
+ to the directory being converted.
+ IndexSegmentReference -- Supplies the segment reference for the
+ File Record Segment which contains the index.
+ IsCorrupt -- Receives TRUE if the volume is found to
+ be corrupt.
+ Verbose -- Supplies a flag which indicates (if TRUE)
+ that every file converted should be displayed.
+ NameBuffer -- Supplies a scratch buffer for converting
+ file names.
+ NameBufferLength -- Supplies the length (in bytes) of the file
+ name conversion buffer.
+ EaBuffer -- Supplies a scratch buffer for Extended
+ Attribute conversion.
+ EaBufferLength -- Supplies the length of EaBuffer
+ Level -- Supplies the depth of the directory which
+ contains this dirblk (root directory
+ is level zero).
+ DirectoryPath -- Supplies the path of this directory.
+ ConvertLongNames -- Supplies a flag which indicates whether
+ to convert entries with long names. If this
+ flag is FALSE, only entries with names
+ that are valid DOS names are converted; if
+ this flag is TRUE, only entries that are
+ not valid DOS names are converted.
+
+
+Return Value:
+
+ TRUE upon successful completion.
+
+
+--*/
+{
+ DIRBLK ChildDirblk;
+
+ PDIRENTD CurrentEntry;
+ ULONG CurrentOffset;
+
+ DebugPtrAssert( Drive );
+ DebugPtrAssert( Message );
+ DebugPtrAssert( VolumeBitmap );
+ DebugPtrAssert( HpfsOnlyBitmap );
+ DebugPtrAssert( Casemap );
+ DebugPtrAssert( Mft );
+ DebugPtrAssert( Dirblk );
+ DebugPtrAssert( NtfsIndex );
+ DebugPtrAssert( IsCorrupt );
+ DebugPtrAssert( NameBuffer );
+ DebugPtrAssert( EaBuffer );
+
+ // Initialize the child dirblk once for all. Note that Convert
+ // requires that the volume have no hotfixes, so I can pass in
+ // NULL for the hotfix list.
+
+ if( !ChildDirblk.Initialize( Drive, NULL, 0 ) ) {
+
+ DebugPrintf( "CONVERT: Can't initialize Dirblk.\n" );
+ return FALSE;
+ }
+
+ // Walk through all the entries in this dirblk, converting as
+ // I go. Note that this loops terminates in the middle, either
+ // by returning FALSE or by breaking.
+
+ CurrentEntry = Dirblk->GetFirstEntry();
+ CurrentOffset = Dirblk->QueryEntryOffset( CurrentEntry );
+
+ while( TRUE ) {
+
+ // Check that the current entry fits in the dirblk. First, check
+ // that this entry's cchThisEntry field fits in the dirblk, and
+ // then check that the entire length of the entry (based on that
+ // field) also fits.
+ //
+ if( CurrentOffset + sizeof(USHORT) > DIRBLK_SIZE ||
+ CurrentOffset + CurrentEntry->cchThisEntry > DIRBLK_SIZE ||
+ CurrentEntry->cchThisEntry == 0 ) {
+
+ // This entry overflows the DIRBLK or has zero length.
+ // In either case, it's corrupt.
+ //
+ DebugPrintf( "Dirblk at lbn 0x%x has no END entry.\n", Dirblk->QueryStartSector() );
+ *IsCorrupt = TRUE;
+ return FALSE;
+ }
+
+ // If the current entry has a B-Tree downpointer, recurse
+ // into the subtree.
+
+ if( CurrentEntry->fFlags & DF_BTP ) {
+
+ // Read the child dirblk--if it's unreadable or not a
+ // dirblk, this volume is corrupt.
+
+ ChildDirblk.Relocate( BTP(CurrentEntry ) );
+
+ if( !ChildDirblk.Read() || !ChildDirblk.IsDirblk() ) {
+
+ // The volume is corrupt.
+
+ DebugPrintf( "CONVERT: Child dirblk is not a dirblk.\n" );
+ *IsCorrupt = TRUE;
+ return FALSE;
+ }
+
+ if( !ConvertDirblkToNtfs(Drive,
+ NameTable,
+ Message,
+ VolumeBitmap,
+ HpfsOnlyBitmap,
+ Casemap,
+ Mft,
+ ClustersPerIndexBuffer,
+ &ChildDirblk,
+ NtfsIndex,
+ IndexSegmentReference,
+ IsCorrupt,
+ Verbose,
+ NameBuffer,
+ NameBufferLength,
+ EaBuffer,
+ EaBufferLength,
+ Level,
+ DirectoryPath,
+ ConvertLongNames ) ) {
+
+ // Couldn't convert the subtree. Give up. Note that
+ // if the child detected corruption, it will have set
+ // *IsCorrupt.
+ //
+ return FALSE;
+ }
+ }
+
+ if( CurrentEntry->fFlags & DF_END ) {
+
+ // End of the road.
+
+ break;
+ }
+
+ // If the current entry isn't the special '..' entry,
+ // convert it.
+
+ if( !(CurrentEntry->fFlags & DF_SPEC) &&
+ !ConvertDirentToNtfs( Drive,
+ NameTable,
+ Message,
+ VolumeBitmap,
+ HpfsOnlyBitmap,
+ Casemap,
+ Mft,
+ ClustersPerIndexBuffer,
+ CurrentEntry,
+ NtfsIndex,
+ IndexSegmentReference,
+ IsCorrupt,
+ Verbose,
+ NameBuffer,
+ NameBufferLength,
+ EaBuffer,
+ EaBufferLength,
+ Level,
+ DirectoryPath,
+ ConvertLongNames ) ) {
+
+ return FALSE;
+ }
+
+ // Move on to the next entry.
+
+ CurrentOffset += CurrentEntry->cchThisEntry;
+ CurrentEntry = NEXT_ENTRY( CurrentEntry );
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/cuhpfs/cvteas.cxx b/private/utils/cuhpfs/cvteas.cxx
new file mode 100644
index 000000000..934581625
--- /dev/null
+++ b/private/utils/cuhpfs/cvteas.cxx
@@ -0,0 +1,314 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ cvteas.cxx
+
+Abstract:
+
+ This module contains the routines to support conversion of HPFS
+ Extended Attributes.
+
+Author:
+
+ Bill McJohn (billmc) 27-Dec-1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+
+#include "hmem.hxx"
+
+#include "ifssys.hxx"
+#include "drive.hxx"
+#include "secrun.hxx"
+
+#include "uhpfs.hxx"
+#include "bitmap.hxx"
+#include "dirblk.hxx"
+#include "error.hxx"
+#include "fnode.hxx"
+#include "message.hxx"
+#include "store.hxx"
+#include "cpinfo.hxx"
+#include "hpfsea.hxx"
+
+#include "untfs.hxx"
+#include "attrib.hxx"
+#include "extents.hxx"
+#include "frs.hxx"
+#include "mft.hxx"
+#include "ntfsbit.hxx"
+#include "indxtree.hxx"
+#include "mftfile.hxx"
+
+#include "cuhpfs.hxx"
+
+BOOLEAN
+ConvertEasToNtfs(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNTFS_MFT_FILE Mft,
+ IN OUT PFNODE Fnode,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT TargetFrs,
+ IN ULONG DirentEaSize,
+ IN ULONG CodepageId,
+ IN OUT PBOOLEAN IsCorrupt,
+ IN OUT PVOID NameBuffer,
+ IN ULONG NameBufferLength,
+ IN OUT PVOID EaBuffer,
+ IN ULONG EaBufferLength
+ )
+/*++
+
+Routine Description:
+
+ This function converts the Extended Attributes associated with an FNode
+ into attributes associated with an NTFS File Record Segment.
+
+Arguments:
+
+ Drive -- Supplies the drive being converted.
+ VolumeBitmap -- Supplies the NTFS bitmap for the volume.
+ Mft -- Supplies the NTFS Master File Table for the volume.
+ Fnode -- Supplies the FNode being converted.
+ TargetFrs -- Supplies the NTFS File Record Segment that will
+ receive the converted attributes.
+ DirentEaSize -- Supplies the size of the Extended Attributes
+ associated with this FNode, according to the
+ parent directory entry.
+ CodepageId -- Supplies the Code Page associated with the parent
+ directory entry. (Note that this is a real code
+ page ID, rather than a volume index).
+ IsCorrupt -- Receives TRUE if the Extended Attribute structures
+ are found to be corrupt.
+ NameBuffer -- Supplies a scratch buffer for name conversion.
+ NameBufferLength -- Supplies the length in bytes of NameBuffer.
+ EaBuffer -- Supplies a scratch buffer for EA conversion.
+ EaBufferLength -- Supplies the length in bytes of EaBuffer.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ EA_INFORMATION EaInformation;
+ NTFS_ATTRIBUTE EaDataAttribute, EaInformationAttribute;
+ NTFS_EXTENT_LIST ExtentList;
+ HPFS_EA CurrentEa;
+ DSTRING AttributeName;
+
+ PBYTE UnpackedListBuffer;
+ ULONG BytesWritten;
+ ULONG PackedListLength, UnpackedListLength, NeedEaCount;
+ ULONG CurrentOffset, TargetOffset, CurrentLength;
+ PBYTE CurrentEaData;
+ USHORT AttributeFlags;
+ ULONG Threshold = 1;
+
+
+ // Get the list of extended attributes from the FNode. Since
+ // Convert assumes that there are no hotfixes on the volume,
+ // pass in NULL for the hotfix parameter.
+
+ if( !Fnode->QueryPackedEaList( EaBuffer,
+ EaBufferLength,
+ &PackedListLength,
+ IsCorrupt,
+ NULL ) ) {
+
+ DebugPrint( "Cannot query packed EA list from FNode.\n" );
+ return FALSE;
+ }
+
+ // If the packed list length is zero, then there's
+ // no work to do.
+
+ if( PackedListLength == 0 ) {
+
+ return TRUE;
+ }
+
+ // Determine the unpacked size of this EA list by traversing the
+ // EA list.
+
+ CurrentOffset = 0;
+ UnpackedListLength = 0;
+ NeedEaCount = 0;
+
+ while( CurrentOffset < PackedListLength ) {
+
+ CurrentEaData = (PBYTE)EaBuffer + CurrentOffset;
+
+ // Initialize the HPFS_EA object with the current Extended
+ // Attribute. For the purpose at hand, the ParentLbn is
+ // unneccessary, so I pass in zero.
+
+ if( !CurrentEa.Initialize( Drive, (PEA_DATA)CurrentEaData, 0 ) ) {
+
+ return FALSE;
+ }
+
+ // Is it a need-ea EA?
+
+ if( CurrentEa.IsNeedEa() ) {
+
+ NeedEaCount += 1;
+ }
+
+ // The unpacked length is increased by a ULONG (for next offset)
+ // plus the length of this EA, plus enough padding to keep it
+ // DWORD aligned.
+
+ UnpackedListLength += sizeof(ULONG) + CurrentEa.QueryLength();
+
+ UnpackedListLength = DwordAlign( UnpackedListLength );
+
+
+ // Move on to the next extended attribute.
+
+ CurrentOffset += CurrentEa.QueryLength();
+ }
+
+
+ // Allocate a buffer to hold the unpacked list length, now that I
+ // know how big it is.
+
+ if( (UnpackedListBuffer = (PBYTE)MALLOC( UnpackedListLength )) == NULL ) {
+
+ return FALSE;
+ }
+
+ memset( UnpackedListBuffer, 0, UnpackedListLength );
+
+ // Traverse the list again, copying the EAs into the packed buffer.
+
+ TargetOffset = 0;
+ CurrentOffset = 0;
+
+ while( CurrentOffset < PackedListLength ) {
+
+ CurrentEaData = (PBYTE)EaBuffer + CurrentOffset;
+
+ // Initialize an EA with the current EA data.
+
+ if( !CurrentEa.Initialize( Drive, (PEA_DATA)CurrentEaData, 0 ) ) {
+
+ FREE( UnpackedListBuffer );
+ return FALSE;
+ }
+
+ // The length of this EA (plus the size of the offset, which
+ // is a ulong) goes at TargetOffset; the value of the EA goes
+ // after this ULONG.
+
+ CurrentLength = DwordAlign( CurrentEa.QueryLength() + sizeof( ULONG ) );
+
+ memcpy( UnpackedListBuffer + TargetOffset,
+ &CurrentLength,
+ sizeof(ULONG) );
+
+ memcpy( UnpackedListBuffer + TargetOffset + sizeof(ULONG),
+ CurrentEaData,
+ CurrentEa.QueryLength() );
+
+ TargetOffset += CurrentLength;
+
+ // Move on to the next extended attribute.
+
+ CurrentOffset += CurrentEa.QueryLength();
+ }
+
+
+ // Create the EA Information Attribute--fill in the fields of
+ // the EA information structure and put it into a resident attribute
+ // of type $EA_INFORMATION.
+
+ EaInformation.PackedEaSize = (USHORT)PackedListLength;
+ EaInformation.NeedEaCount = (USHORT)NeedEaCount;
+ EaInformation.UnpackedEaSize = UnpackedListLength;
+
+
+ if( !EaInformationAttribute.Initialize( Drive,
+ Mft->QueryClusterFactor(),
+ &EaInformation,
+ sizeof( EA_INFORMATION ),
+ $EA_INFORMATION,
+ NULL,
+ 0 ) ) {
+
+ FREE( UnpackedListBuffer );
+ return FALSE;
+ }
+
+
+ // Set up the Ea Data attribute.
+
+ if( UnpackedListLength < Threshold ) {
+
+ // Make the $EA_DATA attribute resident
+
+ if( !EaDataAttribute.Initialize( Drive,
+ Mft->QueryClusterFactor(),
+ UnpackedListBuffer,
+ UnpackedListLength,
+ $EA_DATA,
+ NULL,
+ 0 ) ) {
+
+ DebugPrint( "Cannot initialize resident attribute for EA.\n" );
+ FREE( UnpackedListBuffer );
+ return FALSE;
+ }
+
+
+ } else {
+
+ // Make the $EA_DATA attribute non-resident
+
+ if( !ExtentList.Initialize( 0, 0 ) ||
+ !EaDataAttribute.Initialize( Drive,
+ Mft->QueryClusterFactor(),
+ &ExtentList,
+ 0,
+ 0,
+ $EA_DATA,
+ NULL,
+ 0 ) ||
+ !EaDataAttribute.Write( UnpackedListBuffer,
+ 0,
+ UnpackedListLength,
+ &BytesWritten,
+ VolumeBitmap ) ||
+ BytesWritten != UnpackedListLength ) {
+
+ DebugPrint( "Cannot initialize a non-resident attribute for EA.\n" );
+ FREE( UnpackedListBuffer );
+ return FALSE;
+ }
+
+ }
+
+
+ FREE( UnpackedListBuffer );
+
+ if( !EaDataAttribute.InsertIntoFile( TargetFrs, VolumeBitmap ) ||
+ !EaInformationAttribute.InsertIntoFile( TargetFrs, VolumeBitmap ) ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/cuhpfs/cvtfnode.cxx b/private/utils/cuhpfs/cvtfnode.cxx
new file mode 100644
index 000000000..1196f790f
--- /dev/null
+++ b/private/utils/cuhpfs/cvtfnode.cxx
@@ -0,0 +1,266 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ cvtfnode.cxx
+
+Abstract:
+
+ This module contains the routines to support conversion of an HPFS
+ FNode into an NTFS file.
+
+Author:
+
+ Bill McJohn (billmc) 18-Nov-1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+
+#include "hmem.hxx"
+
+#include "ifssys.hxx"
+#include "drive.hxx"
+#include "secrun.hxx"
+
+#include "uhpfs.hxx"
+#include "bitmap.hxx"
+#include "dirblk.hxx"
+#include "error.hxx"
+#include "fnode.hxx"
+#include "message.hxx"
+#include "store.hxx"
+#include "cpinfo.hxx"
+
+#include "untfs.hxx"
+#include "attrib.hxx"
+#include "extents.hxx"
+#include "frs.hxx"
+#include "mft.hxx"
+#include "ntfsbit.hxx"
+#include "indxtree.hxx"
+#include "mftfile.hxx"
+
+#include "cuhpfs.hxx"
+
+BOOLEAN
+ConvertFileFnodeToNtfs(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap,
+ IN OUT PNTFS_MFT_FILE Mft,
+ IN OUT PFNODE Fnode,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT TargetFrs,
+ IN ULONG FileSize,
+ IN OUT PBOOLEAN IsCorrupt,
+ IN PCWSTRING FullPath
+ )
+/*++
+
+
+Routine Description:
+
+ This method creates a $DATA attribute which corresponds to the
+ storage allocation of the given FNode and inserts that attribute
+ into the target File Record Segment.
+
+Arguments:
+
+ Drive -- Supplies the drive being converted.
+ VolumeBitmap -- Supplies the NTFS bitmap for the volume.
+ HpfsOnlyBitmap -- Supplies the bitmap of HPFS-only structures.
+ Mft -- Supplies the Master File Table.
+ Fnode -- Supplies the FNode being converted.
+ TargetFrs -- Supplies the FRS which will accept the new DATA
+ attribute.
+ FileSize -- Supplies the size of the file (from directory entry).
+ IsCorrupt -- Receives TRUE if the volume is found to be corrupt.
+ (Note that it may already be TRUE
+ FullPath -- Supplies the path for this file.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ If the file's data stream is sufficiently small, it will be
+ incorporated into the File Record Segment as a resident attribute.
+ If this happens, this method will mark the file's allocated sectors
+ in the HpfsOnlyBitmap.
+
+ This method does not write the new File Record Segment--that is the
+ client's responsibility.
+
+--*/
+{
+ NTFS_ATTRIBUTE DataAttribute;
+ NTFS_EXTENT_LIST Extents;
+ SECRUN Secrun;
+ HMEM SecrunBuffer;
+
+ ULONG NumberOfExtents, NumberOfSectors, i;
+ PALLEAF AllocationLeaves;
+ BOOLEAN result;
+
+
+ // Extract the allocation information from the FNode. First,
+ // determine the number of extents associated with the FNode
+ // (using QueryExtents with 0 for max. number and NULL for
+ // output buffer).
+
+ if( !Fnode->QueryExtents( 0, NULL, &NumberOfExtents ) ) {
+
+ return FALSE;
+ }
+
+
+ // Allocate a buffer based on the number of extents it will hold.
+
+ if( (AllocationLeaves =
+ (PALLEAF)MALLOC( NumberOfExtents * sizeof( ALLEAF ) )) ==
+ NULL ) {
+
+ return FALSE;
+ }
+
+
+ // Now go back to the FNode and get the actual list of
+ // allocation leaves.
+
+ if( !Fnode->QueryExtents( NumberOfExtents,
+ AllocationLeaves,
+ &NumberOfExtents ) ) {
+
+ FREE( AllocationLeaves );
+ return FALSE;
+ }
+
+ // Compute the allocated size of the file.
+
+ NumberOfSectors = 0;
+
+ for( i = 0; i < NumberOfExtents; i++ ) {
+
+ NumberOfSectors += AllocationLeaves[i].csecRun;
+ }
+
+
+ // Decide whether the $DATA attribute should be resident or
+ // non-resident. The data attribute can be resident if it
+ // has at most one extent, fits in the base file record segment,
+ // and has a valid length equal to the file length.
+ //
+ if( FileSize == 0 ) {
+
+ // This is an empty file, so it may as well be resident.
+ // I pass a length of zero to NTFS_ATTRIBUTE::Initialize
+ // to indicate that it's an empty attribute.
+
+ if( !DataAttribute.Initialize( Drive,
+ Mft->QueryClusterFactor(),
+ NULL,
+ 0,
+ $DATA ) ) {
+
+ FREE( AllocationLeaves );
+ return FALSE;
+ }
+
+ } else if( NumberOfExtents == 1 &&
+ FileSize == Fnode->QueryValidLength() &&
+ FileSize + SIZE_OF_RESIDENT_HEADER <
+ TargetFrs->QueryFreeSpace() ) {
+
+ // This is a non-empty small file which only has one
+ // extent, so it might fit into the FRS. Start with
+ // it resident; if it doesn't fit, it'll get converted
+ // to nonresident later.
+ //
+ if( !SecrunBuffer.Initialize() ||
+ !Secrun.Initialize( &SecrunBuffer,
+ Drive,
+ AllocationLeaves[0].lbnPhys,
+ AllocationLeaves[0].csecRun ) ||
+ !Secrun.Read() ||
+ !DataAttribute.Initialize( Drive,
+ Mft->QueryClusterFactor(),
+ Secrun.GetBuf(),
+ FileSize,
+ $DATA ) ) {
+ FREE( AllocationLeaves );
+ return FALSE;
+ }
+
+ // The sectors associated with the file are now HPFS-only
+ // structures.
+
+ HpfsOnlyBitmap->SetAllocated(AllocationLeaves[0].lbnPhys,
+ AllocationLeaves[0].csecRun );
+
+ } else {
+
+ // Keep it nonresident. Initialize an extent list and
+ // put the extents from the FNode into that extent list.
+
+ if( !Extents.Initialize( 0, 0 ) ) {
+
+ FREE( AllocationLeaves );
+ return FALSE;
+ }
+
+ for( i = 0; i < NumberOfExtents; i++ ) {
+
+ if( !Extents.AddExtent( AllocationLeaves[i].lbnLog,
+ AllocationLeaves[i].lbnPhys,
+ AllocationLeaves[i].csecRun ) ) {
+
+ FREE( AllocationLeaves );
+ return FALSE;
+ }
+ }
+
+ // Initialize a data attribute with this extent list.
+
+ if( !DataAttribute.Initialize( Drive,
+ Mft->QueryClusterFactor(),
+ &Extents,
+ FileSize,
+ Fnode->QueryValidLength(),
+ $DATA,
+ NULL ) ) {
+
+ FREE( AllocationLeaves );
+ return FALSE;
+ }
+ }
+
+
+ // Jam this data attribute into the File Record Segment.
+
+ result = DataAttribute.InsertIntoFile( TargetFrs, VolumeBitmap );
+
+ if( !result && DataAttribute.IsResident() ) {
+
+ // Couldn't insert a resident attribute--make it nonresident
+ // and try again.
+ //
+ result = DataAttribute.MakeNonresident( VolumeBitmap ) &&
+ DataAttribute.InsertIntoFile( TargetFrs, VolumeBitmap );
+ }
+
+ FREE( AllocationLeaves );
+
+ return result;
+}
diff --git a/private/utils/cuhpfs/cvthpfs.cxx b/private/utils/cuhpfs/cvthpfs.cxx
new file mode 100644
index 000000000..710153036
--- /dev/null
+++ b/private/utils/cuhpfs/cvthpfs.cxx
@@ -0,0 +1,674 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ cvthpfs.cxx
+
+Abstract:
+
+ This module contains the main section of the HPFS-to-NTFS conversion
+ utility.
+
+Author:
+
+ Bill McJohn (billmc) 01-Dec-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "untfs.hxx"
+
+#include "bitmap.hxx"
+#include "error.hxx"
+#include "fnode.hxx"
+#include "hpcensus.hxx"
+#include "hpfsvol.hxx"
+#include "hpfssa.hxx"
+#include "smsg.hxx"
+#include "rtmsg.h"
+#include "wstring.hxx"
+#include "intstack.hxx"
+
+// #include "system.hxx"
+#include "ifssys.hxx"
+#include "ulibcl.hxx"
+
+#include "attrib.hxx"
+#include "bitfrs.hxx"
+#include "logfile.hxx"
+#include "mft.hxx"
+#include "ntfssa.hxx"
+#include "ntfsbit.hxx"
+#include "indxtree.hxx"
+#include "mftfile.hxx"
+#include "upcase.hxx"
+#include "upfile.hxx"
+
+#include "cuhpfs.hxx"
+#include "nametab.hxx"
+
+// Global buffers used for name conversion.
+
+CONST NameBufferLength = 512;
+CHAR NameBuffer[NameBufferLength];
+
+CONST EaBufferLength = 0x10000;
+CHAR EaBuffer[EaBufferLength];
+
+BOOLEAN
+CheckGeometryMatch(
+ IN PHPFS_SA HpfsSuperArea,
+ IN PHPFS_VOL HpfsVol
+ )
+/*++
+
+Routine Description:
+
+ This method checks that the geometry recorded in the
+ Bios Parameter Block agrees with the geometry reported
+ by the driver.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the geometry in the BPB matches that reported
+ by the driver; false if not. The only field that is
+ checked is BytesPerSector.
+
+--*/
+{
+ USHORT SectorSize, SectorsPerTrack, Heads;
+ ULONG HiddenSectors;
+
+ HpfsSuperArea->QueryGeometry( &SectorSize,
+ &SectorsPerTrack,
+ &Heads,
+ &HiddenSectors );
+
+ if( SectorSize != HpfsVol->QuerySectorSize() ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+ConvertToNtfs(
+ IN OUT PHPFS_VOL HpfsVol,
+ IN PCNAME_LOOKUP_TABLE NameTable,
+ IN PNUMBER_SET BadSectors,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ OUT PBOOLEAN Corrupt
+ )
+/*++
+
+Routine Description:
+
+ This function converts the specified HPFS volume into an NTFS
+ volume.
+
+Arguments:
+
+ NtDriveName -- supplies the name of the volume to convert.
+ BadSectors -- supplies the volume's bad sector list.
+ Message -- supplies an outlet for messages.
+ Verbose -- supplies a flag which, if TRUE, indicates that
+ CONVERT should list every file converted.
+ Corrupt -- receives TRUE if conversion fails because the
+ volume was found to be corrupt.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ DIRBLK RootDirblk;
+ FNODE RootFnode;
+ NTFS_SA NtfsSuperArea;
+ HPFS_CENSUS Census;
+ HPFS_MAIN_BITMAP HpfsOnlyBitmap;
+ NTFS_BITMAP NtfsVolumeBitmap;
+ NTFS_UPCASE_TABLE UpcaseTable;
+ NTFS_MFT_FILE Mft;
+ NTFS_BITMAP_FILE BitmapFile;
+ NTFS_LOG_FILE LogFile;
+ NTFS_UPCASE_FILE UpcaseFile;
+ NTFS_FILE_RECORD_SEGMENT RootIndexFile;
+ NTFS_INDEX_TREE RootIndex;
+ NTFS_ATTRIBUTE BitmapAttribute;
+ NTFS_ATTRIBUTE LogfileData;
+ NTFS_ATTRIBUTE UpcaseAttribute;
+ DSTRING LabelString, FileNameIndexName;
+ FSTRING BootLogFileName, RootName;
+ SECRUN NukeSuperblockSecrun;
+ HMEM NukeSuperblockMem;
+
+ PHPFS_SA HpfsSuperArea;
+ PHPFS_BITMAP HpfsVolumeBitmap;
+
+ BIG_INT TotalKilobytes, FreeKilobytes, RequiredKilobytes, BytesInIndices;
+ ULONG NumberOfSectors, i, SectorSize, SectorsInBootArea,
+ SectorsFree, SectorsRequired;
+
+ BOOLEAN Error;
+
+ CONST ULONG ClusterFactor = 1;
+ ULONG ClustersPerFrs = NTFS_SA::QueryDefaultClustersPerFrs(
+ HpfsVol, ClusterFactor);
+ ULONG ClustersPerIndexBuffer = NTFS_SA::QueryDefaultClustersPerIndexBuffer(
+ HpfsVol, ClusterFactor);
+
+
+ CONST AverageBytesPerIndexEntry = 128;
+
+
+
+ // Attributes associated with indices over $FILE_NAME always
+ // have the name $I3.
+ //
+ if( !FileNameIndexName.Initialize( FileNameIndexNameData ) ) {
+
+ return FALSE;
+ }
+
+ HpfsSuperArea = HpfsVol->GetHPFSSuperArea();
+
+ // Assume innocent until proven guilty:
+ //
+ *Corrupt = FALSE;
+
+ // To protect ourselves from disk drivers that cannot
+ // correctly determine the disk geometry, compare the
+ // boot-code-critical values from the existing BPB with
+ // the drive's values. If they don't match, we can't
+ // convert this drive because if it's the system partition,
+ // the system won't boot.
+ //
+ if( !CheckGeometryMatch( HpfsSuperArea, HpfsVol ) ) {
+
+ Message->Set( MSG_CONV_GEOMETRY_MISMATCH );
+ Message->Display( "%s", "NTFS" );
+ return FALSE;
+ }
+
+
+ // Take the census of the HPFS volume.
+ //
+ if( !HpfsOnlyBitmap.Initialize( HpfsVol ) ||
+ !HpfsOnlyBitmap.SetFree( 0, HpfsVol->QuerySectors().GetLowPart() ) ||
+ !Census.Initialize( 1 ) ) {
+
+ DebugPrint( "Can't initialize census stuff.\n" );
+ return FALSE;
+ }
+
+
+ // Add the must-clear sectors:
+
+ if( !Census.AddClearSector( HpfsVol->QuerySectors().GetLowPart()/2 ) ) {
+
+ DebugPrint( "Can't add clear-sector.\n" );
+ return FALSE;
+ }
+
+ Message->Set( MSG_CONV_CHECKING_SPACE );
+ Message->Display();
+
+ if( !HpfsSuperArea->TakeCensusAndClear( &HpfsOnlyBitmap, &Census ) ) {
+
+ DebugPrint( "Census failed.\n" );
+ return FALSE;
+ }
+
+
+ // Set up the NTFS bitmap. I start out with it equivalent to the
+ // HPFS bitmap, so that new NTFS structures will get put down
+ // only in the volume free space. The NTFS volume will have a
+ // clusterfactor of 1.
+
+ if( !NtfsVolumeBitmap.Initialize( HpfsVol->QuerySectors(), FALSE,
+ HpfsVol, 1 )) {
+
+ DebugPrint( "Can't initialize NTFS bitmap.\n" );
+ return FALSE;
+ }
+
+ NumberOfSectors = HpfsVol->QuerySectors().GetLowPart();
+ SectorSize = HpfsVol->QuerySectorSize();
+
+ HpfsVolumeBitmap = HpfsSuperArea->GetBitmap();
+
+ for( i = 0; i < NumberOfSectors; i++ ) {
+
+ if( !HpfsVolumeBitmap->IsFree( i, 1 ) ) {
+
+ NtfsVolumeBitmap.SetAllocated( i, 1 );
+
+ }
+ }
+
+ // Compute free space requirement and see if there's enough.
+ // The amount of free space required is:
+ // The space required by the elementary structures, plus
+ // One FRS for each file or directory, plus
+ // Enough index blocks to hold the required index entries.
+ // (The number of bytes in indices is multiplied by
+ // two to reflect that the average index block will
+ // be half-full.)
+ //
+ SectorsRequired =
+ NTFS_SA::QuerySectorsInElementaryStructures( HpfsVol,
+ ClusterFactor,
+ ClustersPerFrs,
+ ClustersPerIndexBuffer,
+ 0 );
+
+ SectorsRequired += ( Census.QueryNumberOfFiles() +
+ Census.QueryNumberOfDirectories() ) *
+ ClustersPerFrs *
+ ClusterFactor;
+
+ BytesInIndices = ( Census.QueryNumberOfFiles() +
+ Census.QueryNumberOfDirectories() ) *
+ AverageBytesPerIndexEntry * 2;
+
+ SectorsRequired += (BytesInIndices / SectorSize).GetLowPart();
+
+
+ // Note that conversion requires limits us to one
+ // sector per cluster.
+ //
+ SectorsFree = NtfsVolumeBitmap.QueryFreeClusters().GetLowPart();
+
+ // These calculations are broken up into separate statements to
+ // avoid problems with overflow in ULONG arithmetic.
+ //
+ TotalKilobytes = NumberOfSectors;
+ TotalKilobytes = (TotalKilobytes * SectorSize)/1024;
+
+ FreeKilobytes = SectorsFree;
+ FreeKilobytes = (FreeKilobytes * SectorSize)/1024;
+
+ RequiredKilobytes = SectorsRequired;
+ RequiredKilobytes = (RequiredKilobytes * SectorSize)/1024;
+
+ Message->Set( MSG_CONV_KBYTES_TOTAL );
+ Message->Display( "%9d", TotalKilobytes.GetLowPart() );
+
+ Message->Set( MSG_CONV_KBYTES_FREE );
+ Message->Display( "%9d", FreeKilobytes.GetLowPart() );
+
+ Message->Set( MSG_CONV_KBYTES_NEEDED );
+ Message->Display( "%9d", RequiredKilobytes.GetLowPart() );
+
+
+ if( SectorsRequired > SectorsFree ) {
+
+ Message->Set( MSG_CONV_NO_DISK_SPACE );
+ Message->Display();
+
+ return FALSE;
+ }
+
+
+ // Clear the clusters that are allowed to conflict with HPFS-only
+ // structures in the HPFS-only bitmap.
+ //
+ SectorsInBootArea = ( BYTES_IN_BOOT_AREA % SectorSize ) ?
+ ( BYTES_IN_BOOT_AREA / SectorSize + 1 ) :
+ ( BYTES_IN_BOOT_AREA / SectorSize );
+
+ HpfsOnlyBitmap.SetFree( 0, SectorsInBootArea );
+ HpfsOnlyBitmap.SetFree( NumberOfSectors/2, 1 );
+
+
+ // Now I'm ready to create the NTFS super area. It will have
+ // 1 sector per cluster.
+ //
+ if( !NtfsSuperArea.Initialize( HpfsVol, Message ) ) {
+
+ DebugPrint( "Can't initialize NTFS Super Area.\n" );
+ return FALSE;
+ }
+
+ // Get the existing volume label:
+ //
+ if( !HpfsSuperArea->QueryLabel( &LabelString ) ) {
+
+ DebugPrint( "Can't get existing volume label." );
+ return FALSE;
+ }
+
+ Message->Set( MSG_CONV_CONVERTING_FS );
+ Message->Display();
+
+ // Create the file-system elementary structures--ie. all
+ // the system files. Pass in a small number for the log
+ // file size to prevent it from gobbling up the available
+ // contiguous space; patch this up later.
+ //
+ if( !NtfsSuperArea.CreateElementaryStructures( &NtfsVolumeBitmap,
+ ClusterFactor,
+ ClustersPerFrs,
+ ClustersPerIndexBuffer,
+ 0x1000,
+ BadSectors,
+ Message,
+ HpfsSuperArea->GetBpb(),
+ &LabelString ) ) {
+
+ DebugPrint( "CreateElementaryStructures failed.\n" );
+ return FALSE;
+ }
+
+
+ // I now have a valid NTFS volume, except that the boot sectors
+ // have not been written to disk. The bitmap has all existing files,
+ // all HPFS structures, and all NTFS structures marked as in-use.
+
+ // Get a Master File Table object. Note that I don't have an
+ // upcase table yet, so I pass in NULL.
+ //
+ if( !Mft.Initialize( HpfsVol,
+ NtfsSuperArea.QueryMftStartingLcn(),
+ NtfsSuperArea.QueryClusterFactor(),
+ NtfsSuperArea.QueryClustersPerFrs(),
+ NtfsSuperArea.QueryVolumeSectors(),
+ &NtfsVolumeBitmap,
+ NULL ) ||
+ !Mft.Read() ) {
+
+ DebugPrint( "Can't get the MFT I just created.\n" );
+ return FALSE;
+ }
+
+ // Tell the ntfs volume bitmap about the mft so it can use the
+ // bad cluster file to keep track of any bad clusters that are
+ // found.
+
+ NtfsVolumeBitmap.SetMftPointer(Mft.GetMasterFileTable());
+
+ // Get the upcase table.
+ //
+ if( !UpcaseFile.Initialize( Mft.GetMasterFileTable() ) ||
+ !UpcaseFile.Read() ||
+ !UpcaseFile.QueryAttribute( &UpcaseAttribute, &Error, $DATA ) ||
+ !UpcaseTable.Initialize( &UpcaseAttribute ) ) {
+
+ DebugPrint( "Can't get the upcase table.\n" );
+ return FALSE;
+ }
+
+ Mft.SetUpcaseTable( &UpcaseTable );
+ Mft.GetMasterFileTable()->SetUpcaseTable( &UpcaseTable );
+
+
+ // Extend the Master File Table to provide space for all the File
+ // Record Segments I know I'll need. Include some slush, to provide
+ // for files with external attributes (especially the MFT itself).
+ //
+ if( !Mft.Extend( Census.QueryNumberOfFiles() +
+ Census.QueryNumberOfDirectories() +
+ 0x10 ) ) {
+
+ DebugPrint( "CONVERT: Can't create a sufficiently large Master File Table.\n" );
+ return FALSE;
+ }
+
+ // Flush the MFT again, so that it claims the first available
+ // File Record Segments for its overflow (to prevent bootstrap
+ // errors later).
+ //
+ if( !Mft.Flush() ) {
+
+ DebugPrint( "Can't flush the Master File Table.\n" );
+ return FALSE;
+ }
+
+ // Now patch the log file: initialize it, fetch its data attribute
+ // and truncate it to zero, and then create a new data attribute,
+ // passing in zero to tell it to choose a reasonable default.
+ //
+ if( !LogFile.Initialize( Mft.GetMasterFileTable() ) ||
+ !LogFile.Read() ||
+ !LogFile.QueryAttribute( &LogfileData, &Error, $DATA ) ||
+ !LogfileData.Resize( 0, &NtfsVolumeBitmap ) ||
+ !LogFile.CreateDataAttribute( 0, &NtfsVolumeBitmap ) ||
+ !LogFile.Flush( &NtfsVolumeBitmap ) ) {
+
+ DebugPrint( "CONVERT: Can't resize log file.\n" );
+ return FALSE;
+ }
+
+ // Sanity check: make sure that the log file doesn't have
+ // an attribute list. The file system will die horribly
+ // if Convert creates a log file with external attributes.
+ //
+ if( LogFile.IsAttributePresent( $ATTRIBUTE_LIST ) ) {
+
+ Message->Set( MSG_CONV_VOLUME_TOO_FRAGMENTED );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ // Initialize and read the root file name index FRS.
+ //
+ if( !RootIndexFile.Initialize( ROOT_FILE_NAME_INDEX_NUMBER,
+ Mft.GetMasterFileTable() ) ||
+ !RootIndexFile.Read() ||
+ !RootIndex.Initialize( HpfsVol,
+ NtfsSuperArea.QueryClusterFactor(),
+ &NtfsVolumeBitmap,
+ &UpcaseTable,
+ RootIndexFile.
+ QueryMaximumAttributeRecordSize()/2,
+ &RootIndexFile,
+ &FileNameIndexName ) ) {
+
+ DebugPrint( "Can't read/initialize the root file name index.\n" );
+ return FALSE;
+ }
+
+ // Force the HPFS Codepage information into memory:
+
+ if( !HpfsSuperArea->ReadCodepage() ) {
+
+ DebugPrint( "Can't read codepages--volume is corrupt." );
+ return FALSE;
+ }
+
+
+
+ // Get the root Dirblk of the HPFS volume. This Dirblk will
+ // be the key to the entire directory tree.
+
+ if( !RootFnode.Initialize( HpfsVol,
+ HpfsSuperArea->GetSuper()->
+ QueryRootFnodeLbn() ) ) {
+
+ DebugPrint( "Can't initialize root FNode.\n" );
+ return FALSE;
+ }
+
+ if( !RootFnode.Read() || !RootFnode.IsFnode() ) {
+
+ DebugPrint( "Root FNode is not an FNode--volume is corrupt.\n" );
+ return FALSE;
+ }
+
+ if( !RootDirblk.Initialize( HpfsVol,
+ NULL,
+ RootFnode.QueryRootDirblkLbn() ) ) {
+
+ DebugPrint( "Can't initialize root dirblk.\n" );
+ return FALSE;
+ }
+
+ if( !RootDirblk.Read() || !RootDirblk.IsDirblk() ) {
+
+ DebugPrint( "Root dirblk is not a dirblk--volume is corrupt.\n" );
+ return FALSE;
+ }
+
+ // Convert the root dirblk. This will recursively convert the
+ // entire directory tree. Since this is the root directory,
+ // I supply zero for the level. Note that this requires two
+ // passes; the first pass converts short names, while the
+ // second pass converts long names.
+ //
+ RootName.Initialize( L"" );
+
+ if( !ConvertDirblkToNtfs( HpfsVol,
+ NameTable,
+ Message,
+ &NtfsVolumeBitmap,
+ &HpfsOnlyBitmap,
+ HpfsSuperArea->GetCasemap(),
+ &Mft,
+ ClustersPerIndexBuffer,
+ &RootDirblk,
+ &RootIndex,
+ RootIndexFile.QuerySegmentReference(),
+ Corrupt,
+ Verbose,
+ NameBuffer,
+ NameBufferLength,
+ EaBuffer,
+ EaBufferLength,
+ 0,
+ &RootName,
+ FALSE ) ||
+ !ConvertDirblkToNtfs( HpfsVol,
+ NameTable,
+ Message,
+ &NtfsVolumeBitmap,
+ &HpfsOnlyBitmap,
+ HpfsSuperArea->GetCasemap(),
+ &Mft,
+ ClustersPerIndexBuffer,
+ &RootDirblk,
+ &RootIndex,
+ RootIndexFile.QuerySegmentReference(),
+ Corrupt,
+ Verbose,
+ NameBuffer,
+ NameBufferLength,
+ EaBuffer,
+ EaBufferLength,
+ 0,
+ &RootName,
+ TRUE ) ) {
+
+ return FALSE;
+ }
+
+
+ // Save the root file name index
+
+ if( !RootIndex.Save( &RootIndexFile ) ||
+ !RootIndexFile.Write() ) {
+
+ DebugPrint( "Can't save root index.\n" );
+ return FALSE;
+ }
+
+
+
+ // Free the HPFS-only sectors. Any sector which is marked as
+ // in use in the HPFS-only bitmap becomes marked as free in
+ // the NTFS bitmap.
+
+ for( i = 0; i < NumberOfSectors; i++ ) {
+
+ if( !HpfsOnlyBitmap.IsFree( i ) ) {
+
+ NtfsVolumeBitmap.SetFree( i, 1 );
+ }
+ }
+
+
+ // Flush the MFT. Note that this will also update the volume
+ // bitmap and the MFT mirror.
+
+ if( !Mft.Flush() ) {
+
+ DebugPrint( "Can't flush the Master File Table.\n" );
+ return FALSE;
+ }
+
+ // Flush the cache before we write sector zero, just
+ // to be safe.
+ //
+ HpfsVol->FlushCache();
+
+
+ // Write the super area.
+ //
+ if( !NtfsSuperArea.Write() ) {
+
+ DebugPrint( "Failed writing the NTFS superarea!!!\n" );
+ return FALSE;
+ }
+
+ // Write the rest of the boot code:
+ //
+ if( !NtfsSuperArea.WriteRemainingBootCode() ) {
+
+ DebugPrint( "UNTFS: Unable to write boot code.\n" );
+ }
+
+ // Nuke the signatures in sector 16, to make sure nobody
+ // mistakes this for an HPFS volume.
+ //
+ if( NukeSuperblockMem.Initialize() &&
+ NukeSuperblockSecrun.Initialize( &NukeSuperblockMem,
+ HpfsVol,
+ LBN_SUPERB,
+ 1 ) &&
+ NukeSuperblockSecrun.Read() ) {
+
+ memset( NukeSuperblockSecrun.GetBuf(), 0, 8 );
+ NukeSuperblockSecrun.Write();
+ }
+
+
+#if defined( _AUTOCHECK_ )
+
+ // Autoconvert needs to reboot at this point, to force
+ // the new file system to be recognized.
+ //
+ Message->Set( MSG_CONVERT_REBOOT );
+ Message->Display();
+
+ BootLogFileName.Initialize( L"bootex.log" );
+ if( Message->IsLoggingEnabled() &&
+ !NTFS_SA::DumpMessagesToFile( &BootLogFileName, &Mft, Message ) ) {
+
+ DebugPrintf( "CONVERT: Error writing messages to BOOTEX.LOG\n" );
+ }
+
+ HpfsVol->FlushCache();
+ IFS_SYSTEM::Reboot();
+
+#endif
+
+ return TRUE;
+}
diff --git a/private/utils/cuhpfs/getacp.c b/private/utils/cuhpfs/getacp.c
new file mode 100644
index 000000000..1ed1615ac
--- /dev/null
+++ b/private/utils/cuhpfs/getacp.c
@@ -0,0 +1,73 @@
+#include <nt.h>
+#include <ntrtl.h>
+
+#define NLS_CODEPAGE_KEY L"Nls\\Codepage"
+#define NLS_VALUE_ACP L"ACP"
+
+WCHAR AcpStringBuffer[32];
+UNICODE_STRING AcpString = { 0, 32 * sizeof(WCHAR), AcpStringBuffer };
+
+
+RTL_QUERY_REGISTRY_TABLE AcpQueryTable[] = {
+
+ { NULL,
+ RTL_QUERY_REGISTRY_DIRECT,
+ NLS_VALUE_ACP,
+ &AcpString,
+ REG_NONE,
+ 0,
+ 0 },
+
+ { NULL,
+ 0,
+ NULL,
+ NULL,
+ REG_NONE,
+ NULL,
+ 0 }
+};
+
+ULONG
+GetAcp(
+ )
+/*++
+
+Routine Description:
+
+ This function fetches the system Codepage ID from the registry.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The system codepage ID; zero to indicate failure.
+
+--*/
+{
+ NTSTATUS Status;
+ ULONG Acp;
+
+ Status = RtlQueryRegistryValues( RTL_REGISTRY_CONTROL,
+ NLS_CODEPAGE_KEY,
+ AcpQueryTable,
+ NULL,
+ NULL );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ return( 0 );
+ }
+
+ Status = RtlUnicodeStringToInteger( &AcpString,
+ 10,
+ &Acp );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ return( 0 );
+ }
+
+ return Acp;
+}
diff --git a/private/utils/cuhpfs/makefile b/private/utils/cuhpfs/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/cuhpfs/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/cuhpfs/nametab.cxx b/private/utils/cuhpfs/nametab.cxx
new file mode 100644
index 000000000..8ec9fa1db
--- /dev/null
+++ b/private/utils/cuhpfs/nametab.cxx
@@ -0,0 +1,671 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ nametab.hxx
+
+Abstract:
+
+ This module contains definitions for the NAME_TABLE and
+ NAME_LOOKUP_TABLE objects. See the description in nametab.hxx.
+
+Author:
+
+ Bill McJohn (billmc) 02-March-1994
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+
+#include "wstring.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+
+#include "ifssys.hxx"
+#include "bigint.hxx"
+
+#include "nametab.hxx"
+
+extern "C" {
+ #include <ntmmapi.h>
+};
+
+DEFINE_CONSTRUCTOR( NAME_TABLE, OBJECT );
+
+NAME_TABLE::~NAME_TABLE(
+ )
+{
+ Destroy();
+}
+
+VOID
+NAME_TABLE::Construct (
+ )
+{
+ _DataLength = 0;
+ _BufferLength = 0;
+}
+
+VOID
+NAME_TABLE::Destroy(
+ )
+{
+ _DataLength = 0;
+ _BufferLength = 0;
+}
+
+BOOLEAN
+NAME_TABLE::Initialize(
+ )
+{
+ Destroy();
+
+ if( !_Buffer.Initialize() ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+NAME_TABLE::Add(
+ IN USHORT CodepageId,
+ IN USHORT BytesInMbcsName,
+ IN PUCHAR MbcsName,
+ IN USHORT CharsInUnicodeName,
+ IN PWCHAR UnicodeName
+ )
+{
+ ULONG EntryLength, NewDataLength, NewBufferLength;
+ PBYTE CurrentBuffer;
+
+ EntryLength = sizeof(USHORT) +
+ sizeof(USHORT) +
+ sizeof(USHORT) +
+ BytesInMbcsName +
+ CharsInUnicodeName * sizeof(WCHAR);
+
+ NewDataLength = _DataLength + EntryLength;
+
+ if( NewDataLength > _BufferLength ) {
+
+ NewBufferLength = _BufferLength;
+
+ while( NewDataLength > NewBufferLength ) {
+
+ NewBufferLength += 4096;
+ }
+
+ if( !_Buffer.Resize( NewBufferLength ) ) {
+
+ return FALSE;
+ }
+
+ _BufferLength = NewBufferLength;
+ }
+
+ CurrentBuffer = (PBYTE)_Buffer.GetBuf() + _DataLength;
+
+ memcpy( CurrentBuffer, &CodepageId, sizeof(USHORT) );
+ CurrentBuffer += sizeof(USHORT);
+
+ memcpy( CurrentBuffer, &BytesInMbcsName, sizeof(USHORT) );
+ CurrentBuffer += sizeof(USHORT);
+
+ memcpy( CurrentBuffer, &BytesInMbcsName, sizeof(USHORT) );
+ CurrentBuffer += sizeof(USHORT);
+
+ memcpy( CurrentBuffer, MbcsName, BytesInMbcsName );
+ CurrentBuffer += BytesInMbcsName;
+
+ memcpy( CurrentBuffer, UnicodeName, CharsInUnicodeName*sizeof(WCHAR) );
+
+ _DataLength = NewDataLength;
+ return TRUE;
+}
+
+BOOLEAN
+NAME_TABLE::Write(
+ IN PCWSTRING QualifiedFileName,
+ IN OUT PMESSAGE Message
+ )
+{
+ BOOLEAN Result;
+
+ Result = IFS_SYSTEM::WriteToFile( QualifiedFileName,
+ _Buffer.GetBuf(),
+ _DataLength,
+ FALSE );
+
+ if( !Result ) {
+
+ Message->Set( MSG_CONV_CANT_WRITE_NAME_TABLE );
+ Message->Display( "" );
+ }
+
+ return Result;
+}
+
+DEFINE_CONSTRUCTOR( NAME_LOOKUP_TABLE, OBJECT );
+
+NAME_LOOKUP_TABLE::~NAME_LOOKUP_TABLE(
+ )
+{
+ Destroy();
+}
+
+VOID
+NAME_LOOKUP_TABLE::Construct (
+ )
+{
+ ULONG i;
+
+ _FileHandle = 0;
+ _SectionHandle = 0;
+ _DataLength = 0;
+ _Data = NULL;
+ _NodePool = NULL;
+
+ for( i = 0; i < NameLookupHashEntries; i++ ) {
+
+ _Hash[i] = NULL;
+ }
+}
+
+VOID
+NAME_LOOKUP_TABLE::Destroy(
+ )
+{
+ ULONG i;
+
+ if( _Data ) {
+
+ NtUnmapViewOfSection(NtCurrentProcess(), _Data );
+ _Data = NULL;
+ }
+
+ if( _SectionHandle ) {
+
+ NtClose( _SectionHandle );
+ _SectionHandle = 0;
+ }
+
+ if( _FileHandle ) {
+
+ NtClose( _FileHandle );
+ _FileHandle = 0;
+ }
+
+ _DataLength = 0;
+ DELETE( _NodePool );
+
+ for( i = 0; i < NameLookupHashEntries; i++ ) {
+
+ _Hash[i] = NULL;
+ }
+}
+
+BOOLEAN
+NAME_LOOKUP_TABLE::Initialize(
+ IN PCWSTRING QualifiedFileName,
+ IN OUT PMESSAGE Message
+ )
+{
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ IO_STATUS_BLOCK StatusBlock;
+ UNICODE_STRING string;
+ FILE_STANDARD_INFORMATION FileInfo;
+ BIG_INT FileSize;
+ ULONG ViewSize;
+
+ Destroy();
+
+ // Open the file, create a section with that file as its
+ // backing store, and map a view of the section.
+ //
+ string.Buffer = (PWSTR)QualifiedFileName->GetWSTR();
+ string.Length = (USHORT)QualifiedFileName->QueryChCount() * sizeof( WCHAR );
+ string.MaximumLength = string.Length;
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &string,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+ Status = NtOpenFile( &_FileHandle, FILE_GENERIC_READ,
+ &ObjectAttributes, &StatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, 0 );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ _FileHandle = 0;
+ DebugPrintf( "CONVERT: NtOpenFile failed--status = 0x%x.\n", Status );
+ Message->Set( MSG_CONV_CANT_READ_NAME_TABLE );
+ Message->Display( "", QualifiedFileName );
+ Destroy();
+ return FALSE;
+ }
+
+ // Determine the data length:
+ //
+ Status = NtQueryInformationFile( _FileHandle,
+ &StatusBlock,
+ &FileInfo,
+ sizeof(FileInfo),
+ FileStandardInformation );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ DebugPrintf( "CONVERT: NtQueryInformationFile failed--status = 0x%x.\n", Status );
+ Message->Set( MSG_CONV_CANT_READ_NAME_TABLE );
+ Message->Display( "", QualifiedFileName );
+ Destroy();
+ return FALSE;
+ }
+
+ FileSize = FileInfo.EndOfFile;
+ _DataLength = FileSize.GetLowPart();
+
+ if( _DataLength ) {
+
+ // Since the section won't have a name, it doesn't need
+ // any object attributes.
+ //
+ Status = NtCreateSection( &_SectionHandle,
+ SECTION_MAP_READ | SECTION_QUERY,
+ NULL,
+ NULL,
+ PAGE_READONLY,
+ SEC_RESERVE,
+ _FileHandle );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ _SectionHandle = 0;
+ DebugPrintf( "CONVERT: NtCreateSection failed--status = 0x%x.\n", Status );
+ Message->Set( MSG_CONV_CANT_READ_NAME_TABLE );
+ Message->Display( "", QualifiedFileName );
+ Destroy();
+ return FALSE;
+ }
+
+ _Data = NULL;
+ ViewSize = 0;
+ Status = NtMapViewOfSection( _SectionHandle,
+ NtCurrentProcess(),
+ &_Data,
+ 0,
+ 0,
+ NULL,
+ &ViewSize,
+ ViewUnmap,
+ 0,
+ PAGE_READONLY );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ _Data = NULL;
+ DebugPrintf( "CONVERT: NtMapViewOfSection failed--status = 0x%x.\n", Status );
+ Message->Set( MSG_CONV_CANT_READ_NAME_TABLE );
+ Message->Display( "", QualifiedFileName );
+ Destroy();
+ return FALSE;
+ }
+ }
+
+ if( !ConstructHashTable() ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+USHORT
+NAME_LOOKUP_TABLE::ComputeHashValue(
+ USHORT BytesInMbcsName,
+ PUCHAR MbcsName
+ )
+{
+ USHORT Sum, i;
+
+ Sum = 0;
+
+ for( i = 0; i < BytesInMbcsName; i++ ) {
+
+ Sum += *MbcsName++;
+ }
+
+ return Sum % NameLookupHashEntries;
+}
+
+ULONG
+NAME_LOOKUP_TABLE::CountEntries(
+ )
+/*++
+
+Routine Description:
+
+ This function counts the number of entries in the file.
+
+Arguments:
+
+ None.
+
+ReturnValue:
+
+ The number of entries in the file.
+
+--*/
+{
+ PBYTE CurrentEntry;
+ ULONG EntryCount, CurrentOffset;
+ USHORT EntryLength;
+
+ if( _DataLength == 0 ) {
+
+ return 0;
+ }
+
+ CurrentOffset = 0;
+ CurrentEntry = (PBYTE)_Data;
+ EntryCount = 0;
+
+ DebugPtrAssert( CurrentEntry );
+
+ while( CurrentOffset < _DataLength ) {
+
+ // Is the header portion (3 USHORT's) of the entry
+ // valid?
+ //
+ if( CurrentOffset + 3 * sizeof(USHORT) > _DataLength ) {
+
+ break;
+ }
+
+ EntryLength = GetEntryLength( CurrentEntry );
+
+ // Is the entry valid?
+ //
+ if( CurrentOffset + EntryLength > _DataLength ) {
+
+ break;
+ }
+
+ EntryCount++;
+ CurrentOffset += EntryLength;
+ CurrentEntry += EntryLength;
+ }
+
+ return EntryCount;
+}
+
+
+PBYTE
+NAME_LOOKUP_TABLE::FindInHashChain(
+ USHORT Index,
+ USHORT CodepageId,
+ USHORT BytesInMbcsName,
+ PUCHAR MbcsName
+ ) CONST
+/*++
+
+Routine Description:
+
+ This private worker function locates a particular entry in
+ a hash chain.
+
+Arguments:
+
+ Index -- Supplies the index of the hash chain to search.
+ CodepageId -- Supplies the entry's associated codepage.
+ BytesInMbcsName -- Supplies the length (in bytes) of the name.
+ MbcsName -- Supplies the search name.
+
+Return Value:
+
+ A pointer to a matching entry, if one is found; otherwise,
+ NULL.
+
+--*/
+{
+ PLOOKUP_NAME_NODE Node;
+ USHORT CurrentCodepageId, CurrentBytesInMbcsName,
+ CurrentCharsInUnicodeName, MbcsNameOffset,
+ UnicodeNameOffset, EntryLength;
+
+
+ Node = _Hash[Index];
+
+ while( Node != NULL ) {
+
+ UnpackNameTableEntry( Node->Data,
+ &CurrentCodepageId,
+ &CurrentBytesInMbcsName,
+ &CurrentCharsInUnicodeName,
+ &MbcsNameOffset,
+ &UnicodeNameOffset,
+ &EntryLength );
+
+ if( CodepageId == CurrentCodepageId &&
+ BytesInMbcsName == CurrentBytesInMbcsName &&
+ memcmp( MbcsName,
+ Node->Data+MbcsNameOffset,
+ BytesInMbcsName ) == 0 ) {
+
+ return Node->Data;
+ }
+
+ Node = Node->Next;
+ }
+
+ return NULL;
+}
+
+
+VOID
+NAME_LOOKUP_TABLE::AddToHash(
+ PLOOKUP_NAME_NODE Node
+ )
+/*++
+
+Routine Description:
+
+ This method adds a lookup node to the hash table, based on
+ the node's Data field.
+
+Arguments:
+
+ Node -- Supplies the node to be added to the hash table.
+ Its Data field must be initialized.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PBYTE Entry;
+ USHORT CodepageId, BytesInMbcsName, CharsInUnicodeName,
+ MbcsNameOffset, UnicodeNameOffset, EntryLength,
+ Index;
+ PUCHAR MbcsName;
+
+ Entry = Node->Data;
+
+ UnpackNameTableEntry( Entry,
+ &CodepageId,
+ &BytesInMbcsName,
+ &CharsInUnicodeName,
+ &MbcsNameOffset,
+ &UnicodeNameOffset,
+ &EntryLength );
+
+ MbcsName = Entry + MbcsNameOffset;
+ Index = ComputeHashValue( BytesInMbcsName, MbcsName );
+
+ // If this entry is not a duplicate (i.e. if it does not
+ // match some entry already in the chain), add it to the
+ // chain.
+ //
+ if( FindInHashChain( Index,
+ CodepageId,
+ BytesInMbcsName,
+ MbcsName ) == NULL ) {
+
+ Node->Next = _Hash[Index];
+ _Hash[Index] = Node;
+ }
+}
+
+BOOLEAN
+NAME_LOOKUP_TABLE::ConstructHashTable(
+ )
+/*++
+
+Routine Description:
+
+ This method constructs the hash table. It allocates the
+ lookup nodes, and then traverses the data file, adding
+ a node to the hash table for each entry in the file.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ ULONG EntryCount, i;
+ PBYTE CurrentEntry;
+
+ // Count the entries in the data file:
+ //
+ EntryCount = CountEntries();
+
+ if( EntryCount ) {
+
+ _NodePool = NEW LOOKUP_NAME_NODE[EntryCount];
+
+ if( !_NodePool ) {
+
+ return FALSE;
+ }
+
+ for( i = 0; i < EntryCount; i++ ) {
+
+ _NodePool[i].Data = NULL;
+ _NodePool[i].Next = NULL;
+ }
+
+ CurrentEntry = (PBYTE)_Data;
+
+ for( i = 0; i < EntryCount; i++ ) {
+
+ _NodePool[i].Data = CurrentEntry;
+ AddToHash( &_NodePool[i] );
+ CurrentEntry += GetEntryLength( CurrentEntry );;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NAME_LOOKUP_TABLE::Lookup(
+ IN USHORT CodepageId,
+ IN USHORT BytesInMbcsName,
+ IN PUCHAR MbcsName,
+ IN OUT PUSHORT CharsInUnicodeName,
+ OUT PWCHAR UnicodeName
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method looks for a particular name in the table.
+
+Arguments:
+
+ CodepageId -- Supplies the codepage with which the search
+ name is associated.
+ BytesInMbcsName -- Supplies number of bytes in the search name.
+ MbcsName -- Supplies the search name.
+ CharsInUnicodeName -- Supplies the number of characters in the
+ client's buffer; receives the number of characters
+ in the target name (if found).
+ UnicodeName -- Receives the target name, i.e. the Unicode
+ equivalent of the search name.
+
+Return Value:
+
+ TRUE if the search name is found in the table and the user's
+ buffer is large enough to hold it. Otherwise, FALSE.
+
+--*/
+{
+ PBYTE Entry;
+ USHORT CurrentCodepageId, CurrentBytesInMbcsName,
+ CurrentCharsInUnicodeName, MbcsNameOffset,
+ UnicodeNameOffset, EntryLength, Index;
+
+ Index = ComputeHashValue( BytesInMbcsName, MbcsName );
+ Entry = FindInHashChain( Index,
+ CodepageId,
+ BytesInMbcsName,
+ MbcsName );
+
+ if( Entry != NULL ) {
+
+ UnpackNameTableEntry( Entry,
+ &CurrentCodepageId,
+ &CurrentBytesInMbcsName,
+ &CurrentCharsInUnicodeName,
+ &MbcsNameOffset,
+ &UnicodeNameOffset,
+ &EntryLength );
+
+ if( *CharsInUnicodeName < CurrentCharsInUnicodeName ) {
+
+ // Client's buffer is too small.
+ //
+ *CharsInUnicodeName = CurrentCharsInUnicodeName;
+ return FALSE;
+
+ } else {
+
+ *CharsInUnicodeName = CurrentCharsInUnicodeName;
+ memcpy( UnicodeName,
+ Entry + UnicodeNameOffset,
+ CurrentCharsInUnicodeName * sizeof(WCHAR) );
+ return TRUE;
+ }
+
+ } else {
+
+ // Not found.
+ //
+ *CharsInUnicodeName = 0;
+ return FALSE;
+ }
+}
diff --git a/private/utils/cuhpfs/nametab.hxx b/private/utils/cuhpfs/nametab.hxx
new file mode 100644
index 000000000..dc5f51f49
--- /dev/null
+++ b/private/utils/cuhpfs/nametab.hxx
@@ -0,0 +1,253 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ nametab.hxx
+
+Abstract:
+
+ This module contains declarations for the NAME_TABLE and
+ NAME_LOOKUP_TABLE objects. These objects are used to pass
+ information about name translation from Convert to Autoconvert.
+ Convert is able to translate names associated with arbitrary
+ codepages, but it cannot convert volumes which it can't
+ lock; Autoconvert can convert arbitrary volumes, but it
+ can only translate names which are either codepage invariant
+ or associated with the system codepage. The name table
+ objects provide bridge this gap.
+
+ Convert uses the NAME_TABLE object to build up the information
+ about name translation. It then writes this data to a file
+ which Autoconvert reads into a NAME_LOOKUP_TABLE.
+
+ The format of the intermediate file is a series of entries,
+ each of the form:
+
+ USHORT Codepage ID
+ USHORT BytesInMBCSName
+ USHORT CharsInUnicodeName
+ MBCS-Name
+ Unicode-Name
+
+ Note that these entries are themselves packed, and that the
+ entries are packed together. There are no padding bytes, and
+ no guaranteed alignment.
+
+Author:
+
+ Bill McJohn (billmc) 02-March-1994
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if !defined( _NAME_TABLE_DEFN_ )
+
+#define _NAME_TABLE_DEFN_
+
+#include "hmem.hxx"
+
+DECLARE_CLASS( WSTRING );
+DECLARE_CLASS( MESSAGE );
+DECLARE_CLASS( NAME_TABLE );
+DECLARE_CLASS( NAME_LOOKUP_TABLE );
+
+class NAME_TABLE : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( NAME_TABLE );
+
+ VIRTUAL
+ ~NAME_TABLE(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Add(
+ IN USHORT CodepageId,
+ IN USHORT BytesInMbcsName,
+ IN PUCHAR MbcsName,
+ IN USHORT CharsInUnicodeName,
+ IN PWCHAR UnicodeName
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Write(
+ IN PCWSTRING QualifiedFileName,
+ IN OUT PMESSAGE Message
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ HMEM _Buffer;
+ ULONG _DataLength;
+ ULONG _BufferLength;
+
+};
+
+CONST NameLookupHashEntries = 127;
+
+
+typedef struct _LOOKUP_NAME_NODE {
+
+ PBYTE Data;
+ _LOOKUP_NAME_NODE* Next;
+
+} LOOKUP_NAME_NODE, *PLOOKUP_NAME_NODE;
+
+class NAME_LOOKUP_TABLE : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( NAME_LOOKUP_TABLE );
+
+ VIRTUAL
+ ~NAME_LOOKUP_TABLE(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PCWSTRING QualifiedFileName,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Lookup(
+ IN USHORT CodepageId,
+ IN USHORT BytesInMbcsName,
+ IN PUCHAR MbcsName,
+ IN OUT PUSHORT CharsInUnicodeName,
+ OUT PWCHAR UnicodeName
+ ) CONST;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ STATIC
+ USHORT
+ ComputeHashValue(
+ USHORT BytesInMbcsName,
+ PUCHAR MbcsName
+ );
+
+ NONVIRTUAL
+ ULONG
+ CountEntries(
+ );
+
+ NONVIRTUAL
+ PBYTE
+ FindInHashChain(
+ USHORT Index,
+ USHORT CodepageId,
+ USHORT BytesInMbcsName,
+ PUCHAR MbcsName
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ AddToHash(
+ PLOOKUP_NAME_NODE Node
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ConstructHashTable(
+ );
+
+ HANDLE _FileHandle;
+ HANDLE _SectionHandle;
+ PVOID _Data;
+ ULONG _DataLength;
+
+ PLOOKUP_NAME_NODE _Hash[NameLookupHashEntries];
+ PLOOKUP_NAME_NODE _NodePool;
+};
+
+INLINE
+VOID
+UnpackNameTableEntry(
+ IN PBYTE Entry,
+ OUT PUSHORT CodepageId,
+ OUT PUSHORT BytesInMbcsName,
+ OUT PUSHORT CharsInUnicodeName,
+ OUT PUSHORT MbcsNameOffset,
+ OUT PUSHORT UnicodeNameOffset,
+ OUT PUSHORT EntryLength
+ )
+/*++
+
+Routine Description:
+
+ This worker function extracts the codepage ID, MBCS name length,
+ and Unicode name length from a Name Table entry. It is required
+ because the entries are packed, and do not guarantee alignment.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ memcpy( CodepageId, Entry, sizeof(USHORT) );
+ memcpy( BytesInMbcsName, Entry+sizeof(USHORT), sizeof(USHORT) );
+ memcpy( CharsInUnicodeName, Entry+2*sizeof(USHORT), sizeof(USHORT) );
+
+ *MbcsNameOffset = 3 * sizeof(USHORT);
+ *UnicodeNameOffset = *MbcsNameOffset + *BytesInMbcsName;
+
+ *EntryLength = 3 * sizeof(USHORT) +
+ *BytesInMbcsName +
+ *CharsInUnicodeName * sizeof(WCHAR);
+}
+
+INLINE
+USHORT
+GetEntryLength(
+ IN PBYTE Entry
+ )
+{
+ USHORT BytesInMbcsName, CharsInUnicodeName;
+
+ memcpy( &BytesInMbcsName, Entry+sizeof(USHORT), sizeof(USHORT) );
+ memcpy( &CharsInUnicodeName, Entry+2*sizeof(USHORT), sizeof(USHORT) );
+
+ return( 3 * sizeof(USHORT) +
+ BytesInMbcsName +
+ CharsInUnicodeName * sizeof(WCHAR) );
+}
+
+
+#endif
diff --git a/private/utils/cuhpfs/pch.cxx b/private/utils/cuhpfs/pch.cxx
new file mode 100644
index 000000000..6a23ee605
--- /dev/null
+++ b/private/utils/cuhpfs/pch.cxx
@@ -0,0 +1,19 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ pch.cxx
+
+Abstract:
+
+ This module is used to precompile headers for cuhpfs.
+
+Author:
+
+ Matthew Bradburn (mattbr) 01-Feb-1994
+
+--*/
+
+#define _NTAPI_ULIB_
diff --git a/private/utils/cuhpfs/sources b/private/utils/cuhpfs/sources
new file mode 100644
index 000000000..d748f4132
--- /dev/null
+++ b/private/utils/cuhpfs/sources
@@ -0,0 +1,79 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=utils
+MINORCOMP=cuhpfs
+
+TARGETNAME=cuhpfs
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+TARGETLIBS=\nt\public\sdk\lib\*\kernel32.lib \
+ ..\ulib\src\obj\*\ulib.lib \
+ ..\uhpfs\src\obj\*\uhpfs.lib \
+ ..\untfs\src\obj\*\untfs.lib \
+ ..\ifsutil\src\obj\*\ifsutil.lib
+
+USE_CRTDLL=1
+BLDCRT=1
+DLLENTRY=InitializeCuhpfs
+
+PRECOMPILED_INCLUDE= pch.cxx
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=cuhpfs.cxx \
+ cvtfnode.cxx \
+ cvtdir.cxx \
+ cvteas.cxx \
+ cuhpfs.rc \
+ cvthpfs.cxx \
+ nametab.cxx \
+ bldnames.cxx
+
+INCLUDES=.;..\uhpfs\inc;..\untfs\inc;..\ulib\inc;..\ifsutil\inc;\nt\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DUNICODE=1
+!ENDIF
+
+UMLIBS=obj\*\cuhpfs.lib
+
+
+CXXFLAGS=+d
+
+UMTYPE=console
+
+UMRES=obj\*\cuhpfs.res
+
+DLLDEF=cuhpfs.def
diff --git a/private/utils/dblspace/dblspace.cxx b/private/utils/dblspace/dblspace.cxx
new file mode 100644
index 000000000..274b2cd06
--- /dev/null
+++ b/private/utils/dblspace/dblspace.cxx
@@ -0,0 +1,2869 @@
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "arg.hxx"
+#include "array.hxx"
+#include "smsg.hxx"
+#include "rtmsg.h"
+#include "system.hxx"
+#include "ifssys.hxx"
+#include "ulibcl.hxx"
+#include "ifsentry.hxx"
+#include "path.hxx"
+#include "bigint.hxx"
+#include "cvf.hxx"
+#include "drive.hxx"
+#include "dblentry.hxx"
+#include "dblspace.hxx"
+#include "cudbfs.hxx"
+
+extern "C" {
+#include <stdio.h>
+#include <ntdskreg.h>
+}
+
+
+ERRSTACK* perrstk;
+
+
+BOOLEAN
+DosToNtMatch(
+ IN PCWSTRING DosName,
+ IN PCWSTRING NtName
+ )
+/*++
+
+RoutineDescription:
+
+ This function determines whether a certain DOS drive name
+ (i.e. <drive-letter>:) and a certain NT drive name refer
+ to the same device.
+
+Arguments:
+
+ DosName -- Supplies the DOS drive name.
+ NtName -- Supplies the NT drive name.
+
+--*/
+{
+ DSTRING ConvertedName, Canon1, Canon2;
+
+ // Convert the DOS name to an NT name and canonicalize both names.
+ //
+ if( !IFS_SYSTEM::DosDriveNameToNtDriveName( DosName, &ConvertedName ) ||
+ !IFS_SYSTEM::QueryCanonicalNtDriveName( &ConvertedName, &Canon1 ) ||
+ !IFS_SYSTEM::QueryCanonicalNtDriveName( NtName, &Canon2 ) ) {
+
+ return FALSE;
+ }
+
+ // If they canonicalize to the same thing, they're the same;
+ // otherwise, they aren't.
+ //
+ return (Canon1.Stricmp( &Canon2 ) != 0) ? FALSE : TRUE;
+}
+
+
+BOOLEAN
+QueryQualifiedCvfName(
+ IN PCWSTRING DriveName,
+ OUT PWSTRING QualifiedCvfName
+ )
+/*++
+
+Routine Description:
+
+ This function determines the qualified DOS name (i.e.
+ <drive-letter>:DBLSPACE.xxx) of the Compressed Volume
+ File for a DBLSPACE volume.
+
+Arguments:
+
+ DriveName -- Supplies the DOS name of the volume (eg. D:)
+ QualifiedCvfName -- Receives the fully-qualified name of
+ the Compressed Volume File for this volume.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ DSTRING NtName, CanonicalName, HostNtName, CvfName;
+ FSTRING BackSlash, DotHost, HostDosName, DblspaceString;
+ WCHAR DriveLetter;
+ CHNUM position;
+
+ if( !DotHost.Initialize( L".HOST" ) ||
+ !HostDosName.Initialize( L" :" ) ||
+ !BackSlash.Initialize( L"\\" ) ||
+ !DblspaceString.Initialize( L"DBLSPACE" ) ) {
+
+ return FALSE;
+ }
+
+ // Convert the drive name to an NT name and canonicalize it.
+ //
+ if( !IFS_SYSTEM::DosDriveNameToNtDriveName( DriveName, &NtName ) ||
+ !IFS_SYSTEM::QueryCanonicalNtDriveName( &NtName, &CanonicalName ) ) {
+
+ return FALSE;
+ }
+
+ // By convention, the device name of a compressed volume
+ // (i.e. its canonical NT name) has one of two forms:
+ // HostDriveName.CvfName or
+ // HostDriveOriginalName
+ // In the former case, the CvfName is always DBLSPACE.nnn.
+ // The latter form is used for Automounted removable media;
+ // in that instance, the host drive is moved to
+ // HostDriveOriginalName.HOST
+ // and the CVF name is always DBLSPACE.000
+ //
+ position = CanonicalName.Strstr( &DblspaceString );
+
+ if( position == INVALID_CHNUM ||
+ position == 0 ||
+ CanonicalName.QueryChAt( position - 1 ) != '.' ) {
+
+ // The name doesn't have the string "DBLSPACE", so it
+ // must be in the second form.
+ //
+ if( !HostNtName.Initialize( &CanonicalName ) ||
+ !HostNtName.Strcat( &DotHost ) ||
+ !CvfName.Initialize( L"DBLSPACE.000" ) ) {
+
+ return FALSE;
+ }
+
+ } else {
+
+ // The name is in the first form.
+ //
+ if( !HostNtName.Initialize( &CanonicalName, 0, position - 1 ) ||
+ !CvfName.Initialize( &CanonicalName, position, TO_END ) ) {
+
+ return FALSE;
+ }
+ }
+
+ // OK, that produced the HostNtName and the CVF name. Now find
+ // the host's DOS name by iterating through the possiblities:
+ //
+ for( DriveLetter = 'A'; DriveLetter <='Z'; DriveLetter++ ) {
+
+ HostDosName.SetChAt( DriveLetter, 0 );
+
+ if( DosToNtMatch( &HostDosName, &HostNtName ) ) {
+
+ // We've got a winner!
+ //
+ return( QualifiedCvfName->Initialize( &HostDosName ) &&
+ QualifiedCvfName->Strcat( &BackSlash ) &&
+ QualifiedCvfName->Strcat( &CvfName ) );
+ }
+ }
+
+ // Didn't find a match.
+ //
+ return FALSE;
+}
+
+
+BOOLEAN
+MountCompressedDrive(
+ IN PCWSTRING NtHostDriveName,
+ IN PCWSTRING HostFileName,
+ IN PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This function mounts a double-space volume.
+ it does not assign a drive letter.
+
+Arguments:
+
+ NtHostDriveName -- Supplies the NT name of the volume on which
+ the host CVF resides.
+ HostFileName -- Supplies the name of the Compressed Volume File.
+ Message -- Supplies an outlet for messages.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ DP_DRIVE HostDrive;
+
+ DbgPtrAssert( NtHostDriveName );
+ DbgPtrAssert( HostFileName );
+ DbgPtrAssert( Message );
+
+ return( HostDrive.Initialize( NtHostDriveName, Message, TRUE ) &&
+ HostDrive.MountCvf( HostFileName, Message ) );
+}
+
+BOOLEAN
+DriveExists(
+ IN PCWSTRING DriveName
+ )
+/*++
+
+Routine Description:
+
+ This function determines whether a drive name is in use.
+
+Arguments:
+
+ DriveName -- supplies the DOS drive name (e.g. D:)
+
+Return Value:
+
+ TRUE if the drive name is in use; FALSE if it is not in use.
+
+--*/
+{
+ CONST TempBufferLength = 128;
+ WCHAR TempBuffer[TempBufferLength];
+
+ return( (BOOLEAN)QueryDosDevice( DriveName->GetWSTR(),
+ TempBuffer,
+ TempBufferLength ) );
+}
+
+
+BOOLEAN
+FindUnusedDriveLetter(
+ OUT PWSTRING DriveName
+ )
+/*++
+
+Routine Description:
+
+ This function locates an unused drive letter.
+
+Arguments:
+
+ DriveName -- Receives the DOS drive name of an unused
+ drive letter (e.g. D:)
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ CONST TempBufferLength = 128;
+ WCHAR TempBuffer[TempBufferLength];
+ WCHAR NameBuffer[4];
+ int Letter;
+
+ for( Letter = 'C'; Letter <= 'Z'; Letter++ ) {
+
+ swprintf( NameBuffer, L"%c:", Letter );
+
+ if( !QueryDosDevice( NameBuffer,
+ TempBuffer,
+ TempBufferLength ) ) {
+
+ // This one's free
+ //
+ return( DriveName->Initialize( NameBuffer ) );
+ }
+ }
+
+ return FALSE;
+}
+
+BOOLEAN
+RemoveDriveLetter(
+ IN PCWSTRING DosDriveName,
+ IN PMESSAGE Message
+ )
+{
+ CONST CurrentTargetBufferLength = 256;
+ WCHAR CurrentTargetBuffer[CurrentTargetBufferLength];
+ FSTRING CurrentTarget, DblspaceString;
+ CHNUM position;
+
+ // First, check to make sure that the current target
+ // for the specified drive letter ends in '.DBLSPACE.xxx'.
+ //
+ if( !QueryDosDevice( DosDriveName->GetWSTR(),
+ CurrentTargetBuffer,
+ CurrentTargetBufferLength ) ||
+ !CurrentTarget.Initialize( CurrentTargetBuffer ) ||
+ !DblspaceString.Initialize( L"DBLSPACE" ) ) {
+
+ Message->Set( MSG_DBLSPACE_CANT_REMOVE_DRIVE_LETTER );
+ Message->Display( "%W", DosDriveName );
+ return FALSE;
+ }
+
+ position = CurrentTarget.Strstr( &DblspaceString );
+
+ if( position == 0 ||
+ position == INVALID_CHNUM ||
+ CurrentTarget.QueryChAt( position - 1 ) != '.' ) {
+
+ // Don't remove this drive letter--it's reserved
+ // for automount.
+ //
+ return TRUE;
+ }
+
+
+ if( !DefineDosDevice( DDD_REMOVE_DEFINITION,
+ DosDriveName->GetWSTR(),
+ NULL ) ) {
+
+ Message->Set( MSG_DBLSPACE_CANT_REMOVE_DRIVE_LETTER );
+ Message->Display( "%W", DosDriveName );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+AssignDoubleSpaceDriveLetter(
+ IN PCWSTRING DosHostDriveName,
+ IN PCWSTRING HostFileName,
+ IN OUT PWSTRING NewDriveName,
+ IN BOOLEAN ByDefault,
+ IN PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This function establishes a drive letter for a newly-mounted
+ double-space volume.
+
+Arguments:
+
+ DosHostDriveName -- Supplies the name of the host drive
+ HostFileName -- Supplies the name of the Compressed Volume File
+ NewDriveName -- Supplies the name for the new drive; receives
+ the name actually used.
+ ByDefault -- Supplies a flag which indicates that
+ NewDriveName was chosen by default, rather
+ than specified by the user.
+ Message -- Supplies an outlet for messages.
+
+Notes:
+
+ If ByDefault is TRUE, then this function will search for an existing
+ link to the specified device, and use it by preference. If ByDefault
+ if FALSE, then existing links will be suppressed.
+
+--*/
+{
+ CONST BufferLength = 128;
+ WCHAR NameBuffer[BufferLength];
+ DSTRING Dot;
+ FSTRING TargetName;
+ FSTRING SearchName;
+ WCHAR ch;
+
+ DbgPtrAssert( DosHostDriveName );
+ DbgPtrAssert( HostFileName );
+ DbgPtrAssert( NewDriveName );
+ DbgPtrAssert( Message );
+
+ // The device name for the compressed volume is the
+ // concatenation of:
+ // - the device name of the host drive
+ // - "."
+ // - the file name of the Compressed Volume File.
+ //
+ if( !QueryDosDevice( DosHostDriveName->GetWSTR(),
+ NameBuffer,
+ BufferLength ) ) {
+
+ Message->Set( MSG_DBLSPACE_CANT_ASSIGN_DRIVE_LETTER );
+ Message->Display( "%W", NewDriveName );
+ return FALSE;
+ }
+
+ if( !TargetName.Initialize( NameBuffer, BufferLength ) ||
+ !Dot.Initialize( "." ) ||
+ !TargetName.Strcat( &Dot ) ||
+ !TargetName.Strcat( HostFileName ) ) {
+
+ Message->Set( MSG_FMT_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ // Search for existing links:
+ //
+ SearchName.Initialize( L" :" );
+
+ for( ch = 'A'; ch <= 'Z'; ch++ ) {
+
+ SearchName.SetChAt( ch, 0 );
+
+ if( DosToNtMatch( &SearchName, &TargetName ) ) {
+
+ // Found an existing link.
+ //
+ if( ByDefault ) {
+
+ // Since the user did not specify a drive letter
+ // to use, use this one.
+ //
+ return( NewDriveName->Initialize( &SearchName ) );
+
+ } else {
+
+ // The user specified a drive letter to use;
+ // suppress this link.
+ //
+ DefineDosDevice( DDD_REMOVE_DEFINITION,
+ SearchName.GetWSTR(),
+ NULL );
+ }
+ }
+ }
+
+ if( !DefineDosDevice( DDD_RAW_TARGET_PATH,
+ NewDriveName->GetWSTR(),
+ TargetName.GetWSTR() ) ) {
+
+ Message->Set( MSG_DBLSPACE_CANT_ASSIGN_DRIVE_LETTER );
+ Message->Display( "%W", NewDriveName );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+// BUGBUG billmc -- move this into the SYSTEM class.
+//
+BOOLEAN
+QueryDiskFreeSpace(
+ IN PCWSTRING DosDriveName,
+ OUT PULONG SectorsPerCluster,
+ OUT PULONG BytesPerSector,
+ OUT PULONG FreeClusters,
+ OUT PULONG TotalClusters
+ )
+/*++
+
+Description:
+
+ This function determines the amount of space and free
+ space on the specified volume.
+
+Arguments:
+
+ DosDriveName -- supplies the DOS drive name (e.g. D:)
+ Size -- returns the size of the volume, in bytes.
+ FreeSpace -- returns the amount of free space, in bytes.
+
+Return Value:
+
+
+--*/
+{
+ DSTRING RootDir, BackSlash;
+
+ if( !BackSlash.Initialize( "\\" ) ||
+ !RootDir.Initialize( DosDriveName ) ||
+ !RootDir.Strcat( &BackSlash ) ) {
+
+ return FALSE;
+ }
+
+ return( GetDiskFreeSpace( RootDir.GetWSTR(),
+ SectorsPerCluster,
+ BytesPerSector,
+ FreeClusters,
+ TotalClusters ) );
+}
+
+
+ULONG
+BytesFromMegabyteString(
+ IN PCWSTRING String
+ )
+/*++
+
+Routine Description:
+
+ This method extracts a value in bytes from a string which
+ expresses megabytes as a decimal string (either n or n.nnn...).
+
+Arguments:
+
+Return Value:
+
+ Number of bytes corresponding to the string value of megabytes.
+ 0 to indicate failure.
+
+--*/
+{
+ ULONG Whole, Fraction, Scale, N;
+
+ Whole = 0;
+ Fraction = 0;
+
+ swscanf( String->GetWSTR(), (PWSTR)L"%ld.%4ld", &Whole, &Fraction );
+
+ N = Fraction;
+ Scale = 1;
+
+ while( N ) {
+
+ N /= 10;
+ Scale *= 10;
+ }
+
+ // Scale is now the first power of 10 greater than Fraction.
+ //
+ return Whole * 1024L * 1024L + Fraction * 1024L * 1024L / Scale;
+}
+
+
+VOID
+NotSupported(
+ IN PDOUBLE_SPACE_ARGUMENTS Arguments,
+ IN OUT PMESSAGE Message
+ )
+{
+ Message->Set( MSG_DBLSPACE_UNSUPPORTED_OPERATION );
+ Message->Display( "" );
+}
+
+BOOLEAN
+ParseAutomount(
+ IN OUT PMESSAGE Message,
+ IN OUT PDOUBLE_SPACE_ARGUMENTS Arguments
+ )
+/*++
+
+Routine Description:
+
+ This function parses the command line for the AUTOMOUNT
+ operation. It should only be called if the command line
+ includes the /AUTOMOUNT switch.
+
+Arguments:
+
+ Message -- Supplies an outlet for messages.
+ Arguments -- Receives the arguments information. Should be
+ all zeroes on entry.
+
+--*/
+{
+ ARGUMENT_LEXEMIZER Lexemizer;
+ ARRAY EmptyArray;
+ ARRAY ArgumentArray;
+ STRING_ARGUMENT ProgramNameArg;
+ LONG_ARGUMENT AutomountArg;
+ PWSTRING pwstring;
+
+ if( !ArgumentArray.Initialize( 5, 1 ) ||
+ !EmptyArray.Initialize( 5, 1 ) ||
+ !Lexemizer.Initialize( &EmptyArray ) ||
+ !ProgramNameArg.Initialize( "*" ) ||
+ !AutomountArg.Initialize( "/AUTOMOUNT=*" ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ Lexemizer.SetCaseSensitive( FALSE );
+
+ if( !ArgumentArray.Put( &ProgramNameArg ) ||
+ !ArgumentArray.Put( &AutomountArg ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Lexemizer.PrepareToParse() ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Lexemizer.DoParsing( &ArgumentArray ) ) {
+
+ Message->Set(MSG_INVALID_PARAMETER);
+ Message->Display("%W", pwstring = Lexemizer.QueryInvalidArgument());
+ DELETE(pwstring);
+
+ return FALSE;
+ }
+
+ if( AutomountArg.QueryLong() != 0 &&
+ AutomountArg.QueryLong() != 1 ) {
+
+ }
+
+ Arguments->Operation = DBFS_AUTOMOUNT;
+ Arguments->Automount = AutomountArg.QueryLong();
+
+ return TRUE;
+}
+
+BOOLEAN
+ParseCheck(
+ IN OUT PMESSAGE Message,
+ OUT PDOUBLE_SPACE_ARGUMENTS Arguments
+ )
+/*++
+
+Routine Description:
+
+ This function parses the command line for the CHECK
+ operation. It should only be called if the command line
+ includes the /CHECK switch.
+
+Arguments:
+
+ Message -- Supplies an outlet for messages.
+ Arguments -- Receives the arguments information.
+
+--*/
+{
+ ARGUMENT_LEXEMIZER Lexemizer;
+ ARRAY EmptyArray;
+ ARRAY ArgumentArray;
+ STRING_ARGUMENT ProgramNameArg;
+ FLAG_ARGUMENT CheckArg;
+ FLAG_ARGUMENT SlashFArg;
+ FLAG_ARGUMENT SlashVArg;
+ PATH_ARGUMENT DriveArg;
+ PWSTRING pwstring;
+
+ if( !ArgumentArray.Initialize( 4, 1 ) ||
+ !EmptyArray.Initialize( 4, 1 ) ||
+ !Lexemizer.Initialize( &EmptyArray ) ||
+ !ProgramNameArg.Initialize( "*" ) ||
+ !CheckArg.Initialize( "/CHECK" ) ||
+ !SlashFArg.Initialize( "/F" ) ||
+ !SlashVArg.Initialize( "/V" ) ||
+ !DriveArg.Initialize( "*" ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ Lexemizer.SetCaseSensitive( FALSE );
+
+ if( !ArgumentArray.Put( &ProgramNameArg ) ||
+ !ArgumentArray.Put( &CheckArg ) ||
+ !ArgumentArray.Put( &SlashFArg ) ||
+ !ArgumentArray.Put( &SlashVArg ) ||
+ !ArgumentArray.Put( &DriveArg ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Lexemizer.PrepareToParse() ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Lexemizer.DoParsing( &ArgumentArray ) ) {
+
+ Message->Set(MSG_INVALID_PARAMETER);
+ Message->Display("%W", pwstring = Lexemizer.QueryInvalidArgument());
+ DELETE(pwstring);
+
+ return FALSE;
+ }
+
+ // This syntax has been accepted. The drive argument
+ // must be specified.
+ //
+ if( !DriveArg.IsValueSet() ) {
+
+ Message->Set( MSG_DBLSPACE_PARSE_NO_DRIVE );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+
+ // Record the arguments:
+ //
+
+ Arguments->DriveName = DriveArg.GetPath()->QueryDevice();
+ Arguments->Operation = DBFS_CHECK;
+
+ Arguments->VolumeName = DriveArg.GetPath()->QueryFullPathString();
+
+ if( Arguments->VolumeName == NULL ) {
+
+ Message->Set( MSG_DBLSPACE_INVALID_DRIVE );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ Arguments->SlashF = SlashFArg.IsValueSet();
+ Arguments->SlashV = SlashVArg.IsValueSet();
+
+ return TRUE;
+}
+
+BOOLEAN
+ParseCompress(
+ IN OUT PMESSAGE Message,
+ OUT PDOUBLE_SPACE_ARGUMENTS Arguments
+ )
+/*++
+
+Routine Description:
+
+ This function parses the command line for the COMPRESS
+ operation. It should only be called if the command line
+ includes the /COMPRESS switch.
+
+Arguments:
+
+ Message -- Supplies an outlet for messages.
+ Arguments -- Receives the arguments information.
+
+--*/
+{
+ ARGUMENT_LEXEMIZER Lexemizer;
+ ARRAY EmptyArray;
+ ARRAY ArgumentArray;
+ STRING_ARGUMENT ProgramNameArg;
+ FLAG_ARGUMENT CompressArg;
+ FLAG_ARGUMENT SlashFArg;
+ PATH_ARGUMENT DriveArg;
+ PATH_ARGUMENT NewDriveArg;
+ STRING_ARGUMENT ReserveArg;
+ PWSTRING pwstring;
+
+
+ if( !ArgumentArray.Initialize( 5, 1 ) ||
+ !EmptyArray.Initialize( 5, 1 ) ||
+ !Lexemizer.Initialize( &EmptyArray ) ||
+ !ProgramNameArg.Initialize( "*" ) ||
+ !CompressArg.Initialize( "/COMPRESS" ) ||
+ !SlashFArg.Initialize( "/F" ) ||
+ !DriveArg.Initialize( "*" ) ||
+ !NewDriveArg.Initialize( "/NEWDRIVE=*" ) ||
+ !ReserveArg.Initialize( "/RESERVE=*" ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ Lexemizer.SetCaseSensitive( FALSE );
+
+ if( !ArgumentArray.Put( &ProgramNameArg ) ||
+ !ArgumentArray.Put( &CompressArg ) ||
+ !ArgumentArray.Put( &SlashFArg ) ||
+ !ArgumentArray.Put( &DriveArg ) ||
+ !ArgumentArray.Put( &NewDriveArg ) ||
+ !ArgumentArray.Put( &ReserveArg ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Lexemizer.PrepareToParse() ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Lexemizer.DoParsing( &ArgumentArray ) ) {
+
+ Message->Set(MSG_INVALID_PARAMETER);
+ Message->Display("%W", pwstring = Lexemizer.QueryInvalidArgument());
+ DELETE(pwstring);
+
+ return FALSE;
+ }
+
+ NotSupported( Arguments, Message );
+
+ return FALSE;
+
+}
+
+BOOLEAN
+ParseCreate(
+ IN OUT PMESSAGE Message,
+ OUT PDOUBLE_SPACE_ARGUMENTS Arguments
+ )
+/*++
+
+Routine Description:
+
+ This function parses the command line for the CREATE
+ operation. It should only be called if the command line
+ includes the /CREATE switch.
+
+Arguments:
+
+ Message -- Supplies an outlet for messages.
+ Arguments -- Receives the arguments information.
+
+--*/
+{
+ ARGUMENT_LEXEMIZER Lexemizer;
+ ARRAY EmptyArray;
+ ARRAY ArgumentArray;
+ STRING_ARGUMENT ProgramNameArg;
+ FLAG_ARGUMENT CreateArg;
+ PATH_ARGUMENT DriveArg;
+ PATH_ARGUMENT NewDriveArg;
+ STRING_ARGUMENT ReserveArg;
+ STRING_ARGUMENT SizeArg;
+ PWSTRING pwstring;
+
+
+ if( !ArgumentArray.Initialize( 6, 1 ) ||
+ !EmptyArray.Initialize( 6, 1 ) ||
+ !Lexemizer.Initialize( &EmptyArray ) ||
+ !ProgramNameArg.Initialize( "*" ) ||
+ !CreateArg.Initialize( "/CREATE" ) ||
+ !DriveArg.Initialize( "*" ) ||
+ !NewDriveArg.Initialize( "/NEWDRIVE=*" ) ||
+ !SizeArg.Initialize( "/SIZE=*" ) ||
+ !ReserveArg.Initialize( "/RESERVE=*" ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ Lexemizer.SetCaseSensitive( FALSE );
+
+ if( !ArgumentArray.Put( &ProgramNameArg ) ||
+ !ArgumentArray.Put( &CreateArg ) ||
+ !ArgumentArray.Put( &NewDriveArg ) ||
+ !ArgumentArray.Put( &SizeArg ) ||
+ !ArgumentArray.Put( &ReserveArg ) ||
+ !ArgumentArray.Put( &DriveArg ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Lexemizer.PrepareToParse() ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Lexemizer.DoParsing( &ArgumentArray ) ) {
+
+ Message->Set(MSG_INVALID_PARAMETER);
+ Message->Display("%W", pwstring = Lexemizer.QueryInvalidArgument());
+ DELETE(pwstring);
+
+ return FALSE;
+ }
+
+ // This syntax has been accepted. The drive argument
+ // must be specified, and only one of SIZE or RESERVE
+ // may be given.
+ //
+ if( !DriveArg.IsValueSet() ) {
+
+ Message->Set( MSG_DBLSPACE_PARSE_NO_DRIVE );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( SizeArg.IsValueSet() && ReserveArg.IsValueSet() ) {
+
+ Message->Set( MSG_DBLSPACE_INVALID_PARAMETERS );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ // Record the arguments:
+ //
+ Arguments->Operation = DBFS_CREATE;
+
+ Arguments->DriveName = DriveArg.GetPath()->QueryDevice();
+
+ if( Arguments->DriveName == NULL ) {
+
+ Message->Set( MSG_DBLSPACE_INVALID_DRIVE );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( NewDriveArg.IsValueSet() ) {
+
+ Arguments->NewDriveSpecified = TRUE;
+ Arguments->NewDriveName = NewDriveArg.GetPath()->QueryDevice();
+
+ if( Arguments->NewDriveName == NULL ) {
+
+ Message->Set( MSG_DBLSPACE_INVALID_DRIVE );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ // Check to see if the drive is already in use:
+ //
+ if( DriveExists( Arguments->NewDriveName ) ) {
+
+ Message->Set( MSG_DBLSPACE_DRIVE_LETTER_IN_USE );
+ Message->Display( "%W", Arguments->NewDriveName );
+ return FALSE;
+ }
+
+ } else {
+
+ // Get a new drive letter.
+ //
+ Arguments->NewDriveSpecified = FALSE;
+ Arguments->NewDriveName = NEW DSTRING;
+
+ if( Arguments->NewDriveName == NULL ||
+ !FindUnusedDriveLetter( Arguments->NewDriveName ) ) {
+
+ Message->Set( MSG_DBLSPACE_NO_DRIVE_LETTER );
+ Message->Display( "" );
+ return FALSE;
+ }
+ }
+
+ // Reserve and Size
+ //
+ if( ReserveArg.IsValueSet() ) {
+
+ Arguments->Reserve = BytesFromMegabyteString( ReserveArg.GetString() );
+
+ if( Arguments->Reserve == 0 ) {
+
+ Message->Set( MSG_DBLSPACE_INVALID_PARAMETER );
+ Message->Display( "%W", ReserveArg.GetString() );
+ return FALSE;
+ }
+ }
+
+ if( SizeArg.IsValueSet() ) {
+
+ Arguments->Size = BytesFromMegabyteString( SizeArg.GetString() );
+
+ if( Arguments->Size == 0 ) {
+
+ Message->Set( MSG_DBLSPACE_INVALID_PARAMETER );
+ Message->Display( "%W", SizeArg.GetString() );
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+ParseDefragment(
+ IN OUT PMESSAGE Message,
+ OUT PDOUBLE_SPACE_ARGUMENTS Arguments
+ )
+/*++
+
+Routine Description:
+
+ This function parses the command line for the DEFRAGMENT
+ operation. It should only be called if the command line
+ includes the /DEFRAGMENT switch.
+
+Arguments:
+
+ Message -- Supplies an outlet for messages.
+ Arguments -- Receives the arguments information.
+
+--*/
+{
+ NotSupported( Arguments, Message );
+ return FALSE;
+}
+
+BOOLEAN
+ParseDelete(
+ IN OUT PMESSAGE Message,
+ OUT PDOUBLE_SPACE_ARGUMENTS Arguments
+ )
+/*++
+
+Routine Description:
+
+ This function parses the command line for the DELETE
+ operation. It should only be called if the command line
+ includes the /DELETE switch.
+
+Arguments:
+
+ Message -- Supplies an outlet for messages.
+ Arguments -- Receives the arguments information.
+
+--*/
+{
+ ARGUMENT_LEXEMIZER Lexemizer;
+ ARRAY EmptyArray;
+ ARRAY ArgumentArray;
+ STRING_ARGUMENT ProgramNameArg;
+ FLAG_ARGUMENT DeleteArg;
+ PATH_ARGUMENT DriveArg;
+ PWSTRING pwstring;
+
+ if( !ArgumentArray.Initialize( 3, 1 ) ||
+ !EmptyArray.Initialize( 3, 1 ) ||
+ !Lexemizer.Initialize( &EmptyArray ) ||
+ !ProgramNameArg.Initialize( "*" ) ||
+ !DeleteArg.Initialize( "/DELETE" ) ||
+ !DriveArg.Initialize( "*" ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ Lexemizer.SetCaseSensitive( FALSE );
+
+ if( !ArgumentArray.Put( &ProgramNameArg ) ||
+ !ArgumentArray.Put( &DeleteArg ) ||
+ !ArgumentArray.Put( &DriveArg ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Lexemizer.PrepareToParse() ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Lexemizer.DoParsing( &ArgumentArray ) ) {
+
+ Message->Set(MSG_INVALID_PARAMETER);
+ Message->Display("%W", pwstring = Lexemizer.QueryInvalidArgument());
+ DELETE(pwstring);
+
+ return FALSE;
+ }
+
+ if( !DriveArg.IsValueSet() || !DeleteArg.IsValueSet() ) {
+
+ Message->Set( MSG_DBLSPACE_REQUIRED_PARAMETER );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ // This syntax has been accepted.
+ //
+ Arguments->Operation = DBFS_DELETE;
+
+ Arguments->DriveName = DriveArg.GetPath()->QueryDevice();
+
+ if( Arguments->DriveName == NULL ) {
+
+ Message->Set( MSG_DBLSPACE_INVALID_DRIVE );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ return TRUE;
+
+}
+
+BOOLEAN
+ParseFormat(
+ IN OUT PMESSAGE Message,
+ OUT PDOUBLE_SPACE_ARGUMENTS Arguments
+ )
+/*++
+
+Routine Description:
+
+ This function parses the command line for the FORMAT
+ operation. It should only be called if the command line
+ includes the /FORMAT switch.
+
+Arguments:
+
+ Message -- Supplies an outlet for messages.
+ Arguments -- Receives the arguments information.
+
+--*/
+{
+ ARGUMENT_LEXEMIZER Lexemizer;
+ ARRAY EmptyArray;
+ ARRAY ArgumentArray;
+ STRING_ARGUMENT ProgramNameArg;
+ FLAG_ARGUMENT FormatArg;
+ PATH_ARGUMENT DriveArg;
+ PWSTRING pwstring;
+
+ if( !ArgumentArray.Initialize( 3, 1 ) ||
+ !EmptyArray.Initialize( 3, 1 ) ||
+ !Lexemizer.Initialize( &EmptyArray ) ||
+ !ProgramNameArg.Initialize( "*" ) ||
+ !FormatArg.Initialize( "/FORMAT" ) ||
+ !DriveArg.Initialize( "*" ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ Lexemizer.SetCaseSensitive( FALSE );
+
+ if( !ArgumentArray.Put( &ProgramNameArg ) ||
+ !ArgumentArray.Put( &FormatArg ) ||
+ !ArgumentArray.Put( &DriveArg ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Lexemizer.PrepareToParse() ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Lexemizer.DoParsing( &ArgumentArray ) ) {
+
+ Message->Set(MSG_INVALID_PARAMETER);
+ Message->Display("%W", pwstring = Lexemizer.QueryInvalidArgument());
+ DELETE(pwstring);
+
+ return FALSE;
+ }
+
+ if( !DriveArg.IsValueSet() || !FormatArg.IsValueSet() ) {
+
+ Message->Set( MSG_DBLSPACE_REQUIRED_PARAMETER );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ // This syntax has been accepted.
+ //
+ Arguments->Operation = DBFS_FORMAT;
+
+ Arguments->DriveName = DriveArg.GetPath()->QueryDevice();
+
+ if( Arguments->DriveName == NULL ) {
+
+ Message->Set( MSG_DBLSPACE_INVALID_DRIVE );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+ParseHost(
+ IN OUT PMESSAGE Message,
+ OUT PDOUBLE_SPACE_ARGUMENTS Arguments
+ )
+/*++
+
+Routine Description:
+
+ This function parses the command line for the HOST
+ operation. It should only be called if the command line
+ includes the /HOST switch.
+
+Arguments:
+
+ Message -- Supplies an outlet for messages.
+ Arguments -- Receives the arguments information.
+
+--*/
+{
+ NotSupported( Arguments, Message );
+ return FALSE;
+}
+
+BOOLEAN
+ParseInfo(
+ IN OUT PMESSAGE Message,
+ OUT PDOUBLE_SPACE_ARGUMENTS Arguments
+ )
+/*++
+
+Routine Description:
+
+ This function parses the command line for the INFO
+ operation. It should only be called if the command line
+ includes the /INFO switch.
+
+Arguments:
+
+ Message -- Supplies an outlet for messages.
+ Arguments -- Receives the arguments information.
+
+--*/
+{
+ ARGUMENT_LEXEMIZER Lexemizer;
+ ARRAY EmptyArray;
+ ARRAY ArgumentArray;
+ STRING_ARGUMENT ProgramNameArg;
+ FLAG_ARGUMENT InfoArg;
+ PATH_ARGUMENT DriveArg;
+ PWSTRING pwstring;
+
+ if( !ArgumentArray.Initialize( 3, 1 ) ||
+ !EmptyArray.Initialize( 3, 1 ) ||
+ !Lexemizer.Initialize( &EmptyArray ) ||
+ !ProgramNameArg.Initialize( "*" ) ||
+ !InfoArg.Initialize( "/INFO" ) ||
+ !DriveArg.Initialize( "*" ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ Lexemizer.SetCaseSensitive( FALSE );
+
+ if( !ArgumentArray.Put( &ProgramNameArg ) ||
+ !ArgumentArray.Put( &InfoArg ) ||
+ !ArgumentArray.Put( &DriveArg ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Lexemizer.PrepareToParse() ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Lexemizer.DoParsing( &ArgumentArray ) ) {
+
+ Message->Set(MSG_INVALID_PARAMETER);
+ Message->Display("%W", pwstring = Lexemizer.QueryInvalidArgument());
+ DELETE(pwstring);
+
+ return FALSE;
+ }
+
+ // The /INFO flag is optional, but the drive must
+ // be specified.
+ //
+ if( !DriveArg.IsValueSet() ) {
+
+ Message->Set( MSG_DBLSPACE_REQUIRED_PARAMETER );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ // This syntax has been accepted.
+ //
+ Arguments->Operation = DBFS_INFO;
+
+ Arguments->DriveName = DriveArg.GetPath()->QueryDevice();
+
+ if( Arguments->DriveName == NULL ) {
+
+ Message->Set( MSG_DBLSPACE_INVALID_DRIVE );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+ParseList(
+ IN OUT PMESSAGE Message,
+ OUT PDOUBLE_SPACE_ARGUMENTS Arguments
+ )
+/*++
+
+Routine Description:
+
+ This function parses the command line for the LIST
+ operation. It should only be called if the command line
+ includes the /LIST switch.
+
+Arguments:
+
+ Message -- Supplies an outlet for messages.
+ Arguments -- Receives the arguments information.
+
+--*/
+{
+ ARGUMENT_LEXEMIZER Lexemizer;
+ ARRAY EmptyArray;
+ ARRAY ArgumentArray;
+ STRING_ARGUMENT ProgramNameArg;
+ FLAG_ARGUMENT ListArg;
+ PWSTRING pwstring;
+
+ if( !ArgumentArray.Initialize( 2, 1 ) ||
+ !EmptyArray.Initialize( 2, 1 ) ||
+ !Lexemizer.Initialize( &EmptyArray ) ||
+ !ProgramNameArg.Initialize( "*" ) ||
+ !ListArg.Initialize( "/LIST" ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ Lexemizer.SetCaseSensitive( FALSE );
+
+ if( !ArgumentArray.Put( &ProgramNameArg ) ||
+ !ArgumentArray.Put( &ListArg ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Lexemizer.PrepareToParse() ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Lexemizer.DoParsing( &ArgumentArray ) ) {
+
+ Message->Set(MSG_INVALID_PARAMETER);
+ Message->Display("%W", pwstring = Lexemizer.QueryInvalidArgument());
+ DELETE(pwstring);
+
+ return FALSE;
+ }
+
+ // The /LIST flag must be specified.
+ //
+ if( !ListArg.IsValueSet() ) {
+
+ Message->Set( MSG_DBLSPACE_REQUIRED_PARAMETER );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ // This syntax has been accepted.
+ //
+ Arguments->Operation = DBFS_LIST;
+ return TRUE;
+}
+
+BOOLEAN
+ParseMount(
+ IN OUT PMESSAGE Message,
+ OUT PDOUBLE_SPACE_ARGUMENTS Arguments
+ )
+/*++
+
+Routine Description:
+
+ This function parses the command line for the MOUNT
+ operation. It should only be called if the command line
+ includes the /MOUNT switch.
+
+Arguments:
+
+ Message -- Supplies an outlet for messages.
+ Arguments -- Receives the arguments information.
+
+--*/
+{
+ ARGUMENT_LEXEMIZER Lexemizer;
+ ARRAY EmptyArray;
+ ARRAY ArgumentArray;
+ STRING_ARGUMENT ProgramNameArg;
+ FLAG_ARGUMENT MountArg;
+ LONG_ARGUMENT MountNumberArg;
+ PATH_ARGUMENT DriveArg;
+ PATH_ARGUMENT NewDriveArg;
+ PWSTRING pwstring;
+
+ if( !ArgumentArray.Initialize( 6, 1 ) ||
+ !EmptyArray.Initialize( 6, 1 ) ||
+ !Lexemizer.Initialize( &EmptyArray ) ||
+ !ProgramNameArg.Initialize( "*" ) ||
+ !MountArg.Initialize( "/MOUNT" ) ||
+ !MountNumberArg.Initialize( "/MOUNT=*" ) ||
+ !DriveArg.Initialize( "*" ) ||
+ !NewDriveArg.Initialize( "/NEWDRIVE=*" ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ Lexemizer.SetCaseSensitive( FALSE );
+
+ if( !ArgumentArray.Put( &ProgramNameArg ) ||
+ !ArgumentArray.Put( &MountArg ) ||
+ !ArgumentArray.Put( &MountNumberArg ) ||
+ !ArgumentArray.Put( &NewDriveArg ) ||
+ !ArgumentArray.Put( &DriveArg ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Lexemizer.PrepareToParse() ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Lexemizer.DoParsing( &ArgumentArray ) ) {
+
+ Message->Set(MSG_INVALID_PARAMETER);
+ Message->Display("%W", pwstring = Lexemizer.QueryInvalidArgument());
+ DELETE(pwstring);
+
+ return FALSE;
+ }
+
+ // This syntax has been accepted.
+ //
+ Arguments->Operation = DBFS_MOUNT;
+
+ if( DriveArg.IsValueSet() ) {
+
+ Arguments->DriveName = DriveArg.GetPath()->QueryDevice();
+
+ if( Arguments->DriveName == NULL ) {
+
+ Message->Set( MSG_DBLSPACE_INVALID_DRIVE );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ } else {
+
+ // The user did not specify a drive--use the current
+ // drive by default.
+ //
+ if( (Arguments->DriveName = NEW DSTRING) == NULL ||
+ !SYSTEM::QueryCurrentDosDriveName( Arguments->DriveName ) ) {
+
+ Message->Set( MSG_FMT_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+ }
+
+ if( NewDriveArg.IsValueSet() ) {
+
+ Arguments->NewDriveSpecified = TRUE;
+ Arguments->NewDriveName = NewDriveArg.GetPath()->QueryDevice();
+
+ if( Arguments->NewDriveName == NULL ) {
+
+ Message->Set( MSG_DBLSPACE_INVALID_DRIVE );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ // Check to see if the drive is already in use:
+ //
+ if( DriveExists( Arguments->NewDriveName ) ) {
+
+ Message->Set( MSG_DBLSPACE_DRIVE_LETTER_IN_USE );
+ Message->Display( "%W", Arguments->NewDriveName );
+ return FALSE;
+ }
+
+ } else {
+
+ // Get a new drive letter.
+ //
+ Arguments->NewDriveSpecified = FALSE;
+ Arguments->NewDriveName = NEW DSTRING;
+
+ if( Arguments->NewDriveName == NULL ||
+ !FindUnusedDriveLetter( Arguments->NewDriveName ) ) {
+
+ Message->Set( MSG_DBLSPACE_NO_DRIVE_LETTER );
+ Message->Display( "" );
+ return FALSE;
+ }
+ }
+
+ if( MountNumberArg.IsValueSet() ) {
+
+ Arguments->CVFExtension = MountNumberArg.QueryLong();
+
+ } else {
+
+ Arguments->CVFExtension = 0;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+ParseRatio(
+ IN OUT PMESSAGE Message,
+ OUT PDOUBLE_SPACE_ARGUMENTS Arguments
+ )
+/*++
+
+Routine Description:
+
+ This function parses the command line for the RATIO
+ operation. It should only be called if the command line
+ includes the /RATIO switch.
+
+Arguments:
+
+ Message -- Supplies an outlet for messages.
+ Arguments -- Receives the arguments information.
+
+--*/
+{
+ NotSupported( Arguments, Message );
+ return FALSE;
+}
+
+BOOLEAN
+ParseSize(
+ IN OUT PMESSAGE Message,
+ OUT PDOUBLE_SPACE_ARGUMENTS Arguments
+ )
+/*++
+
+Routine Description:
+
+ This function parses the command line for the SIZE
+ operation. It should only be called if the command line
+ includes the /SIZE switch.
+
+Arguments:
+
+ Message -- Supplies an outlet for messages.
+ Arguments -- Receives the arguments information.
+
+--*/
+{
+ NotSupported( Arguments, Message );
+ return FALSE;
+}
+
+BOOLEAN
+ParseUncompress(
+ IN OUT PMESSAGE Message,
+ OUT PDOUBLE_SPACE_ARGUMENTS Arguments
+ )
+/*++
+
+Routine Description:
+
+ This function parses the command line for the UNCOMPRESS
+ operation. It should only be called if the command line
+ includes the /UNCOMPRESS switch.
+
+Arguments:
+
+ Message -- Supplies an outlet for messages.
+ Arguments -- Receives the arguments information.
+
+--*/
+{
+ ARGUMENT_LEXEMIZER Lexemizer;
+ ARRAY EmptyArray;
+ ARRAY ArgumentArray;
+ STRING_ARGUMENT ProgramNameArg;
+ FLAG_ARGUMENT UncompressArg;
+ LONG_ARGUMENT UncompressNumberArg;
+ PATH_ARGUMENT DriveArg;
+ PWSTRING pwstring;
+ FLAG_ARGUMENT SlashVArg;
+
+ if( !ArgumentArray.Initialize( 6, 1 ) ||
+ !EmptyArray.Initialize( 6, 1 ) ||
+ !Lexemizer.Initialize( &EmptyArray ) ||
+ !ProgramNameArg.Initialize( "*" ) ||
+ !UncompressArg.Initialize( "/UNCOMPRESS" ) ||
+ !UncompressNumberArg.Initialize( "/UNCOMPRESS=*" ) ||
+ !SlashVArg.Initialize( "/V" ) ||
+ !DriveArg.Initialize( "*" ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ Lexemizer.SetCaseSensitive( FALSE );
+
+ if( !ArgumentArray.Put( &ProgramNameArg ) ||
+ !ArgumentArray.Put( &UncompressArg ) ||
+ !ArgumentArray.Put( &UncompressNumberArg ) ||
+ !ArgumentArray.Put( &SlashVArg ) ||
+ !ArgumentArray.Put( &DriveArg ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Lexemizer.PrepareToParse() ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Lexemizer.DoParsing( &ArgumentArray ) ) {
+
+ Message->Set(MSG_INVALID_PARAMETER);
+ Message->Display("%W", pwstring = Lexemizer.QueryInvalidArgument());
+ DELETE(pwstring);
+
+ return FALSE;
+ }
+
+ // This syntax has been accepted.
+ //
+ Arguments->Operation = DBFS_UNCOMPRESS;
+
+ if( DriveArg.IsValueSet() ) {
+
+ Arguments->DriveName = DriveArg.GetPath()->QueryDevice();
+
+ if( Arguments->DriveName == NULL ) {
+
+ Message->Set( MSG_DBLSPACE_INVALID_DRIVE );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ } else {
+
+ // The user did not specify a drive--use the current
+ // drive by default.
+ //
+ if( (Arguments->DriveName = NEW DSTRING) == NULL ||
+ !SYSTEM::QueryCurrentDosDriveName( Arguments->DriveName ) ) {
+
+ Message->Set( MSG_FMT_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+ }
+
+ if( UncompressNumberArg.IsValueSet() ) {
+
+ Arguments->CVFExtension = UncompressNumberArg.QueryLong();
+
+ } else {
+
+ Arguments->CVFExtension = 0;
+ }
+
+ Arguments->SlashV = SlashVArg.IsValueSet();
+
+ return TRUE;
+}
+
+BOOLEAN
+ParseUnmount(
+ IN OUT PMESSAGE Message,
+ OUT PDOUBLE_SPACE_ARGUMENTS Arguments
+ )
+/*++
+
+Routine Description:
+
+ This function parses the command line for the UNMOUNT
+ operation. It should only be called if the command line
+ includes the /UNMOUNT switch.
+
+Arguments:
+
+ Message -- Supplies an outlet for messages.
+ Arguments -- Receives the arguments information.
+
+--*/
+{
+ ARGUMENT_LEXEMIZER Lexemizer;
+ ARRAY EmptyArray;
+ ARRAY ArgumentArray;
+ STRING_ARGUMENT ProgramNameArg;
+ FLAG_ARGUMENT UnmountArg;
+ PATH_ARGUMENT DriveArg;
+ PWSTRING pwstring;
+
+ if( !ArgumentArray.Initialize( 3, 1 ) ||
+ !EmptyArray.Initialize( 3, 1 ) ||
+ !Lexemizer.Initialize( &EmptyArray ) ||
+ !ProgramNameArg.Initialize( "*" ) ||
+ !UnmountArg.Initialize( "/UNMOUNT" ) ||
+ !DriveArg.Initialize( "*" ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ Lexemizer.SetCaseSensitive( FALSE );
+
+ if( !ArgumentArray.Put( &ProgramNameArg ) ||
+ !ArgumentArray.Put( &UnmountArg ) ||
+ !ArgumentArray.Put( &DriveArg ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Lexemizer.PrepareToParse() ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Lexemizer.DoParsing( &ArgumentArray ) ) {
+
+ Message->Set(MSG_INVALID_PARAMETER);
+ Message->Display("%W", pwstring = Lexemizer.QueryInvalidArgument());
+ DELETE(pwstring);
+
+ return FALSE;
+ }
+
+ // This syntax has been accepted.
+ //
+ Arguments->Operation = DBFS_UNMOUNT;
+
+ if( DriveArg.IsValueSet() ) {
+
+ Arguments->DriveName = DriveArg.GetPath()->QueryDevice();
+
+ if( Arguments->DriveName == NULL ) {
+
+ Message->Set( MSG_DBLSPACE_INVALID_DRIVE );
+ Message->Display( "" );
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+ParseNoOperation(
+ IN OUT PMESSAGE Message,
+ OUT PDOUBLE_SPACE_ARGUMENTS Arguments
+ )
+/*++
+
+Routine Description:
+
+ This function parses the command line when no operation
+ switch is present.
+
+Arguments:
+
+ Message -- Supplies an outlet for messages.
+ Arguments -- Receives the arguments information.
+
+--*/
+{
+ ARGUMENT_LEXEMIZER Lexemizer;
+ ARRAY EmptyArray;
+ ARRAY ArgumentArray;
+ STRING_ARGUMENT ProgramNameArg;
+ PATH_ARGUMENT DriveArg;
+ PWSTRING pwstring;
+
+ if( !ArgumentArray.Initialize( 5, 1 ) ||
+ !EmptyArray.Initialize( 5, 1 ) ||
+ !Lexemizer.Initialize( &EmptyArray ) ||
+ !ProgramNameArg.Initialize( "*" ) ||
+ !DriveArg.Initialize( "*" ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ Lexemizer.SetCaseSensitive( FALSE );
+
+ if( !ArgumentArray.Put( &ProgramNameArg ) ||
+ !ArgumentArray.Put( &DriveArg ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Lexemizer.PrepareToParse() ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Lexemizer.DoParsing( &ArgumentArray ) ) {
+
+ Message->Set(MSG_INVALID_PARAMETER);
+ Message->Display("%W", pwstring = Lexemizer.QueryInvalidArgument());
+ DELETE(pwstring);
+
+ return FALSE;
+ }
+
+ if( !DriveArg.IsValueSet() ) {
+
+ Arguments->Help = TRUE;
+
+ } else {
+
+ Arguments->Operation = DBFS_INFO;
+ Arguments->DriveName = DriveArg.GetPath()->QueryDevice();
+
+ if( Arguments->DriveName == NULL ) {
+
+ Message->Set( MSG_DBLSPACE_INVALID_DRIVE );
+ Message->Display( "" );
+ return FALSE;
+ }
+ }
+
+
+ return TRUE;
+}
+
+
+BOOLEAN
+ParseArguments(
+ IN OUT PMESSAGE Message,
+ OUT PDOUBLE_SPACE_ARGUMENTS Arguments
+ )
+/*++
+
+Routine Description:
+
+ This function parses the command line and fills in the
+ Arguments buffer.
+
+Arguments:
+
+ Message -- Supplies an outlet for messages.
+ Arguments -- Receives the arguments information.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ ARGUMENT_LEXEMIZER Lexemizer;
+ ARRAY EmptyArray;
+ ARRAY ArgumentArray;
+ LONG_ARGUMENT AutomountArg;
+ FLAG_ARGUMENT CheckArg;
+ FLAG_ARGUMENT CompressArg;
+ FLAG_ARGUMENT CreateArg;
+ FLAG_ARGUMENT DefragmentArg;
+ FLAG_ARGUMENT DeleteArg;
+ FLAG_ARGUMENT FormatArg;
+ STRING_ARGUMENT HostArg;
+ FLAG_ARGUMENT InfoArg;
+ FLAG_ARGUMENT ListArg;
+ FLAG_ARGUMENT MountArg;
+ STRING_ARGUMENT MountExtensionArg;
+ FLAG_ARGUMENT RatioQueryArg;
+ STRING_ARGUMENT RatioSetArg;
+ FLAG_ARGUMENT SizeArg;
+ STRING_ARGUMENT SizeSetArg;
+ FLAG_ARGUMENT UncompressArg;
+ STRING_ARGUMENT UncompressExtensionArg;
+ FLAG_ARGUMENT UnmountArg;
+ FLAG_ARGUMENT HelpArg;
+ STRING_ARGUMENT ProgramNameArg;
+ STRING_ARGUMENT String1, String2, String3, String4;
+ PWSTRING pwstring;
+
+
+ // zero out the arguments structure.
+ //
+ memset( Arguments, 0, sizeof( *Arguments ) );
+ Arguments->Operation = DBFS_NO_OP;
+
+ // parse the arguments to determine which operation has
+ // been requested:
+ //
+ //
+ if( !ArgumentArray.Initialize( 5, 1 ) ||
+ !EmptyArray.Initialize( 5, 1 ) ||
+ !Lexemizer.Initialize( &EmptyArray ) ||
+ !ProgramNameArg.Initialize( "*" ) ||
+ !HelpArg.Initialize( "/?" ) ||
+ !AutomountArg.Initialize( "/AUTOMOUNT=*" ) ||
+ !CheckArg.Initialize( "/CHECK" ) ||
+ !CompressArg.Initialize( "/COMPRESS" ) ||
+ !CreateArg.Initialize( "/CREATE" ) ||
+ !DefragmentArg.Initialize( "/DEFRAGMENT" ) ||
+ !DeleteArg.Initialize( "/DELETE" ) ||
+ !FormatArg.Initialize( "/FORMAT" ) ||
+ !HostArg.Initialize( "/HOST=*" ) ||
+ !InfoArg.Initialize( "/INFO" ) ||
+ !ListArg.Initialize( "/LIST" ) ||
+ !MountArg.Initialize( "/MOUNT" ) ||
+ !MountExtensionArg.Initialize( "/MOUNT=*" ) ||
+ !RatioQueryArg.Initialize( "/RATIO" ) ||
+ !RatioSetArg.Initialize( "/RATIO=*" ) ||
+ !SizeArg.Initialize( "/SIZE" ) ||
+ !SizeSetArg.Initialize( "/SIZE=*" ) ||
+ !UncompressArg.Initialize( "/UNCOMPRESS" ) ||
+ !UncompressExtensionArg.Initialize( "/UNCOMPRESS=*" ) ||
+ !UnmountArg.Initialize( "/UNMOUNT" ) ||
+ !String1.Initialize( "*" ) ||
+ !String2.Initialize( "*" ) ||
+ !String3.Initialize( "*" ) ||
+ !String4.Initialize( "*" ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ Lexemizer.SetCaseSensitive( FALSE );
+
+ if( !ArgumentArray.Put( &ProgramNameArg ) ||
+ !ArgumentArray.Put( &HelpArg ) ||
+ !ArgumentArray.Put( &AutomountArg ) ||
+ !ArgumentArray.Put( &CheckArg ) ||
+ !ArgumentArray.Put( &CompressArg ) ||
+ !ArgumentArray.Put( &CreateArg ) ||
+ !ArgumentArray.Put( &DefragmentArg ) ||
+ !ArgumentArray.Put( &DeleteArg ) ||
+ !ArgumentArray.Put( &FormatArg ) ||
+ !ArgumentArray.Put( &HostArg ) ||
+ !ArgumentArray.Put( &InfoArg ) ||
+ !ArgumentArray.Put( &ListArg ) ||
+ !ArgumentArray.Put( &MountArg ) ||
+ !ArgumentArray.Put( &MountExtensionArg ) ||
+ !ArgumentArray.Put( &RatioQueryArg ) ||
+ !ArgumentArray.Put( &RatioSetArg ) ||
+ !ArgumentArray.Put( &SizeArg ) ||
+ !ArgumentArray.Put( &UncompressArg ) ||
+ !ArgumentArray.Put( &UncompressExtensionArg ) ||
+ !ArgumentArray.Put( &UnmountArg ) ||
+ !ArgumentArray.Put( &String1 ) ||
+ !ArgumentArray.Put( &String2 ) ||
+ !ArgumentArray.Put( &String3 ) ||
+ !ArgumentArray.Put( &String4 ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return( FALSE );
+ }
+
+
+ // Parse. Note that PrepareToParse will, by default, pick
+ // up the command line.
+
+ if( !Lexemizer.PrepareToParse() ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return( FALSE );
+ }
+
+ if( !Lexemizer.DoParsing( &ArgumentArray ) ) {
+
+ Message->Set(MSG_INVALID_PARAMETER);
+ Message->Display("%W", pwstring = Lexemizer.QueryInvalidArgument());
+ DELETE(pwstring);
+
+ return( FALSE );
+ }
+
+ // Check for the help flag.
+ //
+ if( HelpArg.QueryFlag() ) {
+
+ Arguments->Help = TRUE;
+ return TRUE;
+ }
+
+ // Parse the entire command line based on the specified
+ // command:
+ //
+ if( AutomountArg.IsValueSet() ) {
+
+ return ParseAutomount( Message, Arguments );
+ }
+
+ if ( CheckArg.IsValueSet() ) {
+
+ return ParseCheck( Message, Arguments );
+ }
+
+ if( CompressArg.IsValueSet() ) {
+
+ return ParseCompress( Message, Arguments );
+ }
+
+ if( CreateArg.IsValueSet() ) {
+
+ return ParseCreate( Message, Arguments );
+ }
+
+ if( DefragmentArg.IsValueSet() ) {
+
+ return ParseDefragment( Message, Arguments );
+ }
+
+ if( DeleteArg.IsValueSet() ) {
+
+ return ParseDelete( Message, Arguments );
+ }
+
+ if( FormatArg.IsValueSet() ) {
+
+ return ParseFormat( Message, Arguments );
+ }
+
+ if( HostArg.IsValueSet() ) {
+
+ return ParseHost( Message, Arguments );
+ }
+
+ if( InfoArg.IsValueSet() ) {
+
+ return ParseInfo( Message, Arguments );
+ }
+
+ if( ListArg.IsValueSet() ) {
+
+ return ParseList( Message, Arguments );
+ }
+
+ if( MountArg.IsValueSet() || MountExtensionArg.IsValueSet() ) {
+
+ return ParseMount( Message, Arguments );
+ }
+
+ if( RatioQueryArg.IsValueSet() || RatioSetArg.IsValueSet() ) {
+
+ return ParseRatio( Message, Arguments );
+ }
+
+ if( SizeArg.IsValueSet() || SizeSetArg.IsValueSet() ) {
+
+ return ParseSize( Message, Arguments );
+ }
+
+ if( UncompressArg.IsValueSet() || UncompressExtensionArg.IsValueSet() ) {
+
+ return ParseUncompress( Message, Arguments );
+ }
+
+ if( UnmountArg.IsValueSet() ) {
+
+ return ParseUnmount( Message, Arguments );
+ }
+
+ return ParseNoOperation( Message, Arguments );
+}
+
+BOOLEAN
+DoAutomount(
+ IN OUT PDOUBLE_SPACE_ARGUMENTS Arguments,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This function sets or resets the system Automount flag in the
+ registry, which controls whether Dblspace volumes on removable
+ media are automatically mounted.
+
+Arguments:
+
+ Arguments -- Supplies the arguments gathered from the command line.
+ Message -- Supplies an outlet for messages.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ MSGID MsgId;
+ NTSTATUS status;
+ BOOLEAN result;
+
+ status = DiskRegistryDblSpaceRemovable((BOOLEAN)Arguments->Automount);
+
+ result = NT_SUCCESS(status);
+
+ if( result ) {
+
+ MsgId = Arguments->Automount ? MSG_DBLSPACE_AUTOMOUNT_ENABLED :
+ MSG_DBLSPACE_AUTOMOUNT_DISABLED;
+
+ Message->Set( MsgId );
+ Message->Display( "" );
+
+ Message->Set( MSG_BLANK_LINE );
+ Message->Display( "" );
+
+ Message->Set( MSG_DBLSPACE_REBOOT );
+ Message->Display( "" );
+
+ Message->Set( MSG_BLANK_LINE );
+ Message->Display( "" );
+
+ } else {
+
+ MsgId = Arguments->Automount ? MSG_DBLSPACE_AUTOMOUNT_ENABLE_FAILED :
+ MSG_DBLSPACE_AUTOMOUNT_DISABLE_FAILED;
+
+ Message->Set( MsgId );
+ Message->Display( "" );
+ }
+
+ return result;
+}
+
+BOOLEAN
+DoDelete(
+ IN OUT PDOUBLE_SPACE_ARGUMENTS Arguments,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This function deletes a mounted Double Space volume.
+
+Arguments:
+
+ Arguments -- Supplies the arguments gathered from the command line.
+ Message -- Supplies an outlet for messages.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+#if !defined ( _READ_WRITE_DOUBLESPACE_ )
+
+ NotSupported( Arguments, Message );
+ return FALSE;
+
+#else // _READ_WRITE_DOUBLESPACE_
+
+ PLOG_IO_DP_DRIVE Drive;
+ DSTRING NtDriveName;
+ DSTRING FileSystemName;
+ BOOLEAN IsCompressed;
+
+ if( (Drive = NEW LOG_IO_DP_DRIVE) == NULL ) {
+
+ Message->Set( MSG_FMT_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !IFS_SYSTEM::DosDriveNameToNtDriveName( Arguments->DriveName,
+ &NtDriveName ) ) {
+
+ Message->Set( MSG_DBLSPACE_INVALID_DRIVE );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Drive->Initialize( &NtDriveName, Message ) ) {
+
+ return FALSE;
+ }
+
+ if( !Drive->QueryMountedFileSystemName( &FileSystemName, &IsCompressed ) ||
+ !IsCompressed ) {
+
+ Message->Set( MSG_DBLSPACE_NOT_COMPRESSED );
+ Message->Display( "%W", Arguments->DriveName );
+ return FALSE;
+ }
+
+ // Confirm:
+ //
+ Message->Set( MSG_DBLSPACE_CONFIRM_DELETE );
+ Message->Display( "%W", Arguments->DriveName );
+
+ if( !Message->IsYesResponse( FALSE ) ) {
+
+ return TRUE;
+ }
+
+ // Delete the drive object to get rid of its handle.
+ //
+ DELETE( Drive );
+
+ if( !FatDbDelete( &NtDriveName, Message ) ) {
+
+ return FALSE;
+ }
+
+ Message->Set( MSG_DBLSPACE_DELETED );
+ Message->Display( "%W", Arguments->DriveName );
+ return TRUE;
+
+#endif // READ_WRITE_DOUBLESPACE
+}
+
+
+BOOLEAN
+DoUnmount(
+ IN OUT PDOUBLE_SPACE_ARGUMENTS Arguments,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This function performs the Unmount command.
+
+Arguments:
+
+ Arguments -- Supplies the arguments gathered from the command line.
+ Message -- Supplies an outlet for messages.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ FSTRING Backslash;
+ DSTRING DeviceName;
+ DSTRING RootPath;
+ DSTRING QualifiedCvfName;
+ HANDLE DeviceHandle;
+ DWORD FsFlags, BytesReturned;
+ MSGID MsgId;
+ BOOLEAN CvfNameKnown;
+
+ if( !Arguments->DriveName ) {
+
+ Message->Set( MSG_DBLSPACE_CANT_UNMOUNT_CURRENT_DRIVE );
+ Message->Display( );
+ return FALSE;
+ }
+
+ if( !Backslash.Initialize( L"\\" ) ||
+ !RootPath.Initialize( Arguments->DriveName ) ||
+ !RootPath.Strcat( &Backslash ) ||
+ !DeviceName.Initialize( L"\\\\.\\" ) ||
+ !DeviceName.Strcat( Arguments->DriveName ) ) {
+
+ Message->Set( MSG_FMT_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !GetVolumeInformation( RootPath.GetWSTR(),
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ &FsFlags,
+ NULL,
+ 0 ) ||
+ !(FsFlags & FILE_VOLUME_IS_COMPRESSED) ) {
+
+ Message->Set( MSG_DBLSPACE_NOT_COMPRESSED );
+ Message->Display( "%W", Arguments->DriveName );
+ return FALSE;
+ }
+
+ CvfNameKnown = QueryQualifiedCvfName( Arguments->DriveName,
+ &QualifiedCvfName );
+
+ DeviceHandle = CreateFile( DeviceName.GetWSTR(),
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_NO_BUFFERING,
+ NULL );
+
+ if( DeviceHandle == INVALID_HANDLE_VALUE ) {
+
+ MsgId = (GetLastError() == ERROR_ACCESS_DENIED) ?
+ MSG_DASD_ACCESS_DENIED : MSG_CANT_DASD;
+
+ Message->Set( MsgId );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !DeviceIoControl( DeviceHandle,
+ FSCTL_LOCK_VOLUME,
+ NULL, 0, NULL, 0,
+ &BytesReturned, 0 ) ) {
+
+ Message->Set( MSG_CANT_LOCK_THE_DRIVE );
+ Message->Display( "" );
+ CloseHandle( DeviceHandle );
+ return FALSE;
+ }
+
+ if( !DeviceIoControl( DeviceHandle,
+ FSCTL_DISMOUNT_VOLUME,
+ NULL, 0, NULL, 0,
+ &BytesReturned, 0 ) ) {
+
+ Message->Set( MSG_CANT_DISMOUNT );
+ Message->Display( "" );
+ CloseHandle( DeviceHandle );
+ return FALSE;
+ }
+
+ CloseHandle( DeviceHandle );
+
+ Message->Set( MSG_DBLSPACE_UNMOUNTED );
+ Message->Display( "%W", Arguments->DriveName );
+
+ RemoveDriveLetter( Arguments->DriveName, Message );
+
+ if( CvfNameKnown ) {
+
+ // Remove this link from the registry.
+ //
+ DiskRegistryAssignDblSpaceLetter( (PWSTR)QualifiedCvfName.GetWSTR(),
+ (WCHAR)' ' );
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+DoMount(
+ IN OUT PDOUBLE_SPACE_ARGUMENTS Arguments,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This function performs the Mount command.
+
+Arguments:
+
+ Arguments -- Supplies the arguments gathered from the command line.
+ Message -- Supplies an outlet for messages.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ WCHAR NameBuffer[16];
+ FSTRING CvfName;
+ FSTRING BackSlash;
+ DSTRING HostDriveName;
+ DSTRING QualifiedCvfName;
+
+ DbgPtrAssert( Arguments->DriveName );
+ DbgPtrAssert( Arguments->NewDriveName );
+
+ swprintf( NameBuffer, L"DBLSPACE.%03d", Arguments->CVFExtension );
+
+ if( !CvfName.Initialize( NameBuffer ) ) {
+
+ Message->Set( MSG_FMT_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !IFS_SYSTEM::DosDriveNameToNtDriveName( Arguments->DriveName,
+ &HostDriveName ) ) {
+
+ Message->Set( MSG_DBLSPACE_INVALID_DRIVE );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !MountCompressedDrive( &HostDriveName, &CvfName, Message ) ||
+ !AssignDoubleSpaceDriveLetter( Arguments->DriveName,
+ &CvfName,
+ Arguments->NewDriveName,
+ !Arguments->NewDriveSpecified,
+ Message ) ) {
+
+ return FALSE;
+ }
+
+ // Record this mount in the registry, so that it can be
+ // remembered next time the system boots.
+ //
+ if( BackSlash.Initialize( L"\\" ) &&
+ QualifiedCvfName.Initialize( Arguments->DriveName ) &&
+ QualifiedCvfName.Strcat( &BackSlash ) &&
+ QualifiedCvfName.Strcat( &CvfName ) ) {
+
+ DiskRegistryAssignDblSpaceLetter(
+ (PWSTR)QualifiedCvfName.GetWSTR(),
+ Arguments->NewDriveName->QueryChAt( 0 )
+ );
+ }
+
+ Message->Set( MSG_DBLSPACE_MOUNTED );
+ Message->Display( "%W%W", &CvfName, Arguments->NewDriveName );
+
+ return TRUE;
+}
+
+BOOLEAN
+DoCreate(
+ IN OUT PDOUBLE_SPACE_ARGUMENTS Arguments,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This function creates a Double Space volume based on
+ the arguments specified on the command line.
+
+Arguments:
+
+ Arguments -- Supplies the arguments gathered from the command line.
+ Message -- Supplies an outlet for messages.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+#if !defined( _READ_WRITE_DOUBLESPACE_ )
+
+ NotSupported( Arguments, Message );
+ return FALSE;
+
+#else // READ_WRITE_DOUBLESPACE
+
+ DSTRING CreatedName;
+ DSTRING HostDriveName;
+ ULONG Size;
+ BIG_INT AvailableSpace;
+ ULONG BytesPerSector, SectorsPerCluster, FreeClusters, TotalClusters;
+
+ DbgPtrAssert( Arguments->DriveName );
+ DbgPtrAssert( Arguments->NewDriveName );
+
+ if( !IFS_SYSTEM::DosDriveNameToNtDriveName( Arguments->DriveName,
+ &HostDriveName ) ) {
+
+ Message->Set( MSG_DBLSPACE_INVALID_DRIVE );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ // Determine how much space is available on the host
+ // volume:
+ //
+ if( !QueryDiskFreeSpace( Arguments->DriveName,
+ &SectorsPerCluster,
+ &BytesPerSector,
+ &FreeClusters,
+ &TotalClusters ) ) {
+
+ Message->Set( MSG_DBLSPACE_INVALID_DRIVE );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ // Do this calculation in two steps to avoid overflow:
+ //
+ AvailableSpace = FreeClusters;
+ AvailableSpace = AvailableSpace * SectorsPerCluster * BytesPerSector;
+
+ // Subtract from the available space the minimum CVF size
+ // and the FAT Failsafe size (for DOS compatibility)
+ //
+ if( AvailableSpace > CVF_MINIMUM_DISK_SIZE + CVF_FATFAILSAFE ) {
+
+ AvailableSpace -= CVF_MINIMUM_DISK_SIZE + CVF_FATFAILSAFE;
+
+ } else {
+
+ AvailableSpace = 0;
+ }
+
+ if( Arguments->Size != 0 ) {
+
+ Size = Arguments->Size <= AvailableSpace.GetLowPart() ?
+ Arguments->Size : 0;
+
+ } else if( Arguments->Reserve != 0 ) {
+
+ Size = Arguments->Reserve <= AvailableSpace.GetLowPart() ?
+ AvailableSpace.GetLowPart() - Arguments->Reserve : 0;
+
+ } else {
+
+ // Neither Size nor Reserve was specified; use it all.
+ //
+ Size = AvailableSpace.GetLowPart();
+ }
+
+ if( Size < CVF_MINIMUM_DISK_SIZE ) {
+
+ Message->Set( MSG_DBLSPACE_INSUFFICIENT_SPACE_TO_CREATE );
+ Message->Display( "%W", Arguments->DriveName );
+ return FALSE;
+ }
+
+ if( !FatDbCreate( &HostDriveName,
+ NULL,
+ Size,
+ Message,
+ NULL,
+ &CreatedName ) ) {
+
+ Message->Set( MSG_DBLSPACE_VOLUME_NOT_CREATED );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ Message->Set( MSG_DBLSPACE_VOLUME_CREATED );
+ Message->Display( "%W%W", Arguments->DriveName, &CreatedName );
+
+
+ if( !MountCompressedDrive( &HostDriveName, &CreatedName, Message ) ||
+ !AssignDoubleSpaceDriveLetter( Arguments->DriveName,
+ &CreatedName,
+ Arguments->NewDriveName,
+ !Arguments->NewDriveSpecified,
+ Message ) ) {
+
+ return FALSE;
+ }
+
+ Message->Set( MSG_DBLSPACE_MOUNTED );
+ Message->Display( "%W%W", &CreatedName, Arguments->NewDriveName );
+
+ return TRUE;
+
+#endif // READ_WRITE_DOUBLESPACE
+}
+
+BOOLEAN
+DoCheck(
+ IN OUT PDOUBLE_SPACE_ARGUMENTS Arguments,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This function checks a doublespace volume for consistency.
+
+Arguments:
+
+ Arguments -- Supplies the arguments gathered from the command line.
+ Message -- Supplies an outlet for messages.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ DSTRING NtDriveName;
+ DSTRING HostFileName;
+
+ if( !IFS_SYSTEM::DosDriveNameToNtDriveName( Arguments->DriveName,
+ &NtDriveName ) ) {
+ Message->Set( MSG_DBLSPACE_INVALID_DRIVE );
+ Message->Display( "" );
+ return FALSE;
+ }
+ if( !IFS_SYSTEM::DosDriveNameToNtDriveName( Arguments->VolumeName,
+ &HostFileName ) ) {
+ Message->Set( MSG_DBLSPACE_INVALID_DRIVE );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ return FatDbChkdsk(
+ &NtDriveName,
+ Message,
+ Arguments->SlashF, /* Fix */
+ Arguments->SlashV, /* Verbose */
+ FALSE, /* OnlyIfDirty */
+ FALSE, /* Recover */
+ &HostFileName
+ );
+}
+
+BOOLEAN
+DoUncompress(
+ IN OUT PDOUBLE_SPACE_ARGUMENTS Arguments,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine uncompresses a doublespace volume, deleting it
+ in the process.
+
+Arguments:
+
+ Arguments -- Supplies the arguments gathered from the command line.
+ Message -- Supplies an outlet for messages.
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure.
+
+--*/
+{
+ WCHAR NameBuffer[16];
+ FSTRING CvfName;
+ DSTRING HostDriveName;
+ DSTRING HostFilePath;
+ BOOLEAN Success;
+ CONVERT_STATUS Status;
+ HANDLE CuDbfsHandle;
+ DSTRING CvfPath;
+ DSTRING backslash;
+
+ DbgPtrAssert( Arguments->DriveName );
+
+ swprintf( NameBuffer, L"DBLSPACE.%03d", Arguments->CVFExtension );
+
+ if( !CvfName.Initialize( NameBuffer ) ) {
+
+ Message->Set( MSG_FMT_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ //
+ // Ensure that the indicated cvf exists before we try to
+ // do anything to it.
+ //
+
+ if ( !CvfPath.Initialize( Arguments->DriveName )) {
+ Message->Set( MSG_FMT_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+ if ( !backslash.Initialize("\\") ) {
+ Message->Set( MSG_FMT_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+ if ( !CvfPath.Strcat( &backslash )) {
+ Message->Set( MSG_FMT_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+ if ( !CvfPath.Strcat( &CvfName )) {
+ Message->Set( MSG_FMT_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if (0xffffffff == GetFileAttributes(CvfPath.GetWSTR())) {
+ if (ERROR_FILE_NOT_FOUND == GetLastError()) {
+ Message->Set(MSG_DBLSPACE_NO_SUCH_FILE);
+ Message->Display("%W", &CvfPath);
+ return FALSE;
+ }
+ }
+
+ if( !IFS_SYSTEM::DosDriveNameToNtDriveName( Arguments->DriveName,
+ &HostDriveName ) ) {
+
+ Message->Set( MSG_DBLSPACE_INVALID_DRIVE );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ Message->Set( MSG_CONV_CHECKING_SPACE );
+ Message->Display( "" );
+
+ if (!CheckFreeSpaceDBFS(
+ &HostDriveName,
+ &CvfName,
+ Message,
+ Arguments->SlashV,
+ FALSE, /* HostIsCompressed */
+ FALSE /* WillConvertHost */
+ )) {
+ return FALSE;
+ }
+
+ Message->Set( MSG_DBLSPACE_UNCOMPRESSING );
+ Message->Display( "" );
+
+ Success = ConvertDBFS(
+ &HostDriveName,
+ &CvfName,
+ Message,
+ Arguments->SlashV,
+ &Status
+ );
+
+ return Success;
+}
+
+int _CRTAPI1
+main(
+ )
+/*++
+
+Routine Description:
+
+ Entry point for the Double-Space command line utility.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Zero for success.
+
+--*/
+{
+ STREAM_MESSAGE msg;
+ DOUBLE_SPACE_ARGUMENTS Arguments;
+ BOOLEAN Result;
+
+ perrstk = NEW ERRSTACK;
+
+ if (!msg.Initialize(Get_Standard_Output_Stream(),
+ Get_Standard_Input_Stream())) {
+ return 4;
+ }
+
+ if( !ParseArguments( &msg, &Arguments ) ) {
+
+ return 4;
+ }
+
+ if( Arguments.Help ) {
+
+ msg.Set( MSG_DBLSPACE_USAGE );
+ msg.Display( "" );
+ return 0;
+ }
+
+ switch( Arguments.Operation ) {
+
+ case DBFS_NO_OP : msg.Set( MSG_DBLSPACE_USAGE );
+ msg.Display( "" );
+ return 0;
+
+ case DBFS_AUTOMOUNT : Result = DoAutomount( &Arguments, &msg );
+ break;
+
+ case DBFS_CHECK : Result = DoCheck( &Arguments, &msg );
+ break;
+
+ case DBFS_COMPRESS : NotSupported( &Arguments, &msg );
+ Result = FALSE;
+ break;
+
+ case DBFS_CREATE : Result = DoCreate( &Arguments, &msg );
+ break;
+
+ case DBFS_DEFRAGMENT : NotSupported( &Arguments, &msg );
+ Result = FALSE;
+ break;
+
+ case DBFS_DELETE : Result = DoDelete( &Arguments, &msg );
+ break;
+
+ case DBFS_FORMAT : NotSupported( &Arguments, &msg );
+ Result = FALSE;
+ break;
+
+ case DBFS_HOST : NotSupported( &Arguments, &msg );
+ Result = FALSE;
+ break;
+
+ case DBFS_INFO : NotSupported( &Arguments, &msg );
+ Result = FALSE;
+ break;
+
+ case DBFS_LIST : Result = DoList( &Arguments, &msg );
+ break;
+
+ case DBFS_MOUNT : Result = DoMount( &Arguments, &msg );
+ break;
+
+ case DBFS_RATIO : NotSupported( &Arguments, &msg );
+ Result = FALSE;
+ break;
+
+ case DBFS_SIZE : NotSupported( &Arguments, &msg );
+ Result = FALSE;
+ break;
+
+ case DBFS_UNCOMPRESS : Result = DoUncompress( &Arguments, &msg );
+ break;
+
+ case DBFS_UNMOUNT: Result = DoUnmount ( &Arguments, &msg );
+ break;
+
+ default: Result = FALSE;
+
+ }
+
+ if( Result ) {
+
+ return 0;
+
+ } else {
+
+ return 1;
+ }
+}
diff --git a/private/utils/dblspace/dblspace.hxx b/private/utils/dblspace/dblspace.hxx
new file mode 100644
index 000000000..f49b9e167
--- /dev/null
+++ b/private/utils/dblspace/dblspace.hxx
@@ -0,0 +1,53 @@
+
+#include "wstring.hxx"
+#include "message.hxx"
+
+
+typedef enum _DOUBLE_SPACE_OPERATION {
+
+ DBFS_NO_OP,
+ DBFS_AUTOMOUNT,
+ DBFS_CHECK,
+ DBFS_COMPRESS,
+ DBFS_CREATE,
+ DBFS_DEFRAGMENT,
+ DBFS_DELETE,
+ DBFS_FORMAT,
+ DBFS_HOST,
+ DBFS_INFO,
+ DBFS_LIST,
+ DBFS_MOUNT,
+ DBFS_RATIO,
+ DBFS_SIZE,
+ DBFS_UNCOMPRESS,
+ DBFS_UNMOUNT
+
+} DOUBLE_SPACE_OPERATION;
+
+typedef struct _DOUBLE_SPACE_ARGUMENTS {
+
+ DOUBLE_SPACE_OPERATION Operation;
+ ULONG Automount;
+ PWSTRING DriveName;
+ PWSTRING NewDriveName;
+ BOOLEAN NewDriveSpecified;
+ PWSTRING VolumeName;
+ ULONG Reserve;
+ ULONG Size;
+ ULONG CVFExtension;
+ ULONG Ratio1;
+ ULONG Ratio2;
+ BOOLEAN SlashF;
+ BOOLEAN SlashV;
+ BOOLEAN All;
+ BOOLEAN Help;
+
+} DOUBLE_SPACE_ARGUMENTS;
+
+DEFINE_POINTER_AND_REFERENCE_TYPES( DOUBLE_SPACE_ARGUMENTS );
+
+BOOLEAN
+DoList(
+ IN OUT PDOUBLE_SPACE_ARGUMENTS Arguments,
+ IN OUT PMESSAGE Message
+ );
diff --git a/private/utils/dblspace/dblspace.rc b/private/utils/dblspace/dblspace.rc
new file mode 100644
index 000000000..757af7d57
--- /dev/null
+++ b/private/utils/dblspace/dblspace.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Double Space utility"
+#define VER_INTERNALNAME_STR "dblspace\0"
+#define VER_ORIGINALFILENAME_STR "DBLSPACE.EXE"
+
+#include "common.ver"
diff --git a/private/utils/dblspace/dolist.cxx b/private/utils/dblspace/dolist.cxx
new file mode 100644
index 000000000..8cec3b927
--- /dev/null
+++ b/private/utils/dblspace/dolist.cxx
@@ -0,0 +1,778 @@
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "dblspace.hxx"
+#include "wstring.hxx"
+#include "bigint.hxx"
+#include "rtmsg.h"
+
+extern "C" {
+#include "fmifs.h"
+#include <ntdskreg.h>
+}
+
+enum LISTED_DRIVE_TYPE {
+
+ LIST_FLOPPY,
+ LIST_REMOVABLE,
+ LIST_FIXED,
+ LIST_COMPRESSED_FLOPPY,
+ LIST_COMPRESSED_REMOVABLE,
+ LIST_COMPRESSED_FIXED
+};
+
+DECLARE_CLASS( DRIVE_INFORMATION );
+DECLARE_CLASS( PRESENT_DRIVE_INFORMATION );
+
+
+class DRIVE_INFORMATION : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( DRIVE_INFORMATION );
+
+ VIRTUAL
+ ~DRIVE_INFORMATION(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ WCHAR DriveLetter,
+ BOOLEAN IsRemovable
+ );
+
+ VIRTUAL
+ BOOLEAN
+ IsCompressed(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ IsFloppy(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsRemovable(
+ );
+
+ NONVIRTUAL
+ WCHAR
+ QueryDriveLetter(
+ );
+
+ VIRTUAL
+ MSGID
+ QueryMsgId(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ IsPresent(
+ );
+
+ VIRTUAL
+ BIG_INT
+ QueryFreeBytes(
+ );
+
+ VIRTUAL
+ BIG_INT
+ QueryTotalBytes(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ DetermineQualifiedCvfFileName(
+ PDRIVE_INFORMATION *DriveList,
+ ULONG Entries
+ );
+
+ VIRTUAL
+ PWSTRING
+ GetNtName(
+ );
+
+ VIRTUAL
+ PWSTRING
+ GetQualifiedCvfFileName(
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ WCHAR _DriveLetter;
+ BOOLEAN _IsRemovable;
+};
+
+class PRESENT_DRIVE_INFORMATION : public DRIVE_INFORMATION {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( PRESENT_DRIVE_INFORMATION );
+
+ VIRTUAL
+ ~PRESENT_DRIVE_INFORMATION(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ WCHAR DriveLetter,
+ BOOLEAN IsRemovable,
+ BOOLEAN IsFloppy,
+ BOOLEAN IsCompressed,
+ PWSTR NtDriveName,
+ PWSTR HostNtName,
+ PWSTR CvfFileName
+ );
+
+ VIRTUAL
+ BOOLEAN
+ IsCompressed(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ IsFloppy(
+ );
+
+ VIRTUAL
+ MSGID
+ QueryMsgId(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ IsPresent(
+ );
+
+ VIRTUAL
+ BIG_INT
+ QueryFreeBytes(
+ );
+
+ VIRTUAL
+ BIG_INT
+ QueryTotalBytes(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ DetermineQualifiedCvfFileName(
+ PDRIVE_INFORMATION *DriveList,
+ ULONG Entries
+ );
+
+ VIRTUAL
+ PWSTRING
+ GetNtName(
+ );
+
+ VIRTUAL
+ PWSTRING
+ GetQualifiedCvfFileName(
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ DSTRING _NtName;
+ BOOLEAN _IsCompressed;
+ BOOLEAN _IsFloppy;
+ DSTRING _HostDriveNtName;
+ DSTRING _CvfFileName;
+ DSTRING _QualifiedCvfFileName;
+
+ WCHAR _HostDriveLetter;
+
+ BIG_INT _TotalSize;
+ BIG_INT _BytesFree;
+};
+
+
+DEFINE_CONSTRUCTOR( DRIVE_INFORMATION, OBJECT );
+
+DRIVE_INFORMATION::~DRIVE_INFORMATION(
+ )
+{
+ Destroy();
+}
+
+VOID
+DRIVE_INFORMATION::Construct(
+ )
+{
+ _DriveLetter = 0;
+ _IsRemovable = FALSE;
+}
+
+VOID
+DRIVE_INFORMATION::Destroy(
+ )
+{
+ _DriveLetter = 0;
+ _IsRemovable = FALSE;
+}
+
+BOOLEAN
+DRIVE_INFORMATION::Initialize(
+ WCHAR DriveLetter,
+ BOOLEAN IsRemovable
+ )
+{
+ _DriveLetter = DriveLetter;
+ _IsRemovable = IsRemovable;
+
+ return TRUE;
+}
+
+BOOLEAN
+DRIVE_INFORMATION::IsCompressed(
+ )
+{
+ return FALSE;
+}
+
+BOOLEAN
+DRIVE_INFORMATION::IsFloppy(
+ )
+{
+ return FALSE;
+}
+
+BOOLEAN
+DRIVE_INFORMATION::IsRemovable(
+ )
+{
+ return _IsRemovable;
+}
+
+WCHAR
+DRIVE_INFORMATION::QueryDriveLetter(
+ )
+{
+ return _DriveLetter;
+}
+
+MSGID
+DRIVE_INFORMATION::QueryMsgId(
+ )
+{
+ return _IsRemovable ? MSG_DBLSPACE_LIST_REMOVABLE :
+ MSG_DBLSPACE_LIST_FIXED;
+}
+
+BOOLEAN
+DRIVE_INFORMATION::IsPresent(
+ )
+{
+ return FALSE;
+}
+
+BIG_INT
+DRIVE_INFORMATION::QueryFreeBytes(
+ )
+{
+ return 0;
+}
+
+BIG_INT
+DRIVE_INFORMATION::QueryTotalBytes(
+ )
+{
+ return 0;
+}
+
+BOOLEAN
+DRIVE_INFORMATION::DetermineQualifiedCvfFileName(
+ PDRIVE_INFORMATION *DriveList,
+ ULONG Entries
+ )
+{
+ return TRUE;
+}
+
+PWSTRING
+DRIVE_INFORMATION::GetNtName(
+ )
+{
+ return NULL;
+}
+
+PWSTRING
+DRIVE_INFORMATION::GetQualifiedCvfFileName(
+ )
+{
+ return NULL;
+}
+
+
+
+DEFINE_CONSTRUCTOR( PRESENT_DRIVE_INFORMATION, DRIVE_INFORMATION );
+
+
+PRESENT_DRIVE_INFORMATION::~PRESENT_DRIVE_INFORMATION(
+ )
+{
+ Destroy();
+}
+
+VOID
+PRESENT_DRIVE_INFORMATION::Construct(
+ )
+{
+ _IsCompressed = FALSE;
+ _HostDriveLetter = 0;
+ _TotalSize = 0;
+ _BytesFree = 0;
+}
+
+VOID
+PRESENT_DRIVE_INFORMATION::Destroy(
+ )
+{
+ _IsCompressed = FALSE;
+ _HostDriveLetter = 0;
+ _TotalSize = 0;
+ _BytesFree = 0;
+}
+
+
+BOOLEAN
+PRESENT_DRIVE_INFORMATION::Initialize(
+ WCHAR DriveLetter,
+ BOOLEAN IsRemovable,
+ BOOLEAN IsFloppy,
+ BOOLEAN IsCompressed,
+ PWSTR NtDriveName,
+ PWSTR HostNtName,
+ PWSTR CvfFileName
+ )
+{
+ FSTRING RootPath;
+ BIG_INT BigBytesPerSector;
+ ULONG BytesPerSector, SectorsPerCluster, Clusters, FreeClusters;
+
+ Destroy();
+
+ if( !DRIVE_INFORMATION::Initialize( DriveLetter, IsRemovable ) ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ _IsCompressed = IsCompressed;
+ _IsFloppy = IsFloppy;
+
+ if( !_NtName.Initialize( NtDriveName ) ||
+ !_QualifiedCvfFileName.Initialize( "" ) ||
+ (IsCompressed && (!_HostDriveNtName.Initialize( HostNtName ) ||
+ !_CvfFileName.Initialize( CvfFileName ))) ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ // Determine the free space and size
+ //
+ if( !RootPath.Initialize( L"X:\\" ) ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ RootPath.SetChAt( DriveLetter, 0 );
+
+ if( !GetDiskFreeSpace( RootPath.GetWSTR(),
+ &SectorsPerCluster,
+ &BytesPerSector,
+ &FreeClusters,
+ &Clusters ) ) {
+
+ _TotalSize = 0;
+ _BytesFree = 0;
+
+ } else {
+
+ // BigBytesPerSector is used to prevent overflow problems.
+ //
+ BigBytesPerSector = BytesPerSector;
+ _TotalSize = BigBytesPerSector * SectorsPerCluster * Clusters;
+ _BytesFree = BigBytesPerSector * SectorsPerCluster * FreeClusters;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+PRESENT_DRIVE_INFORMATION::IsCompressed(
+ )
+{
+ return _IsCompressed;
+}
+
+BOOLEAN
+PRESENT_DRIVE_INFORMATION::IsFloppy(
+ )
+{
+ return _IsFloppy;
+}
+
+MSGID
+PRESENT_DRIVE_INFORMATION::QueryMsgId(
+ )
+{
+ MSGID MsgId;
+
+ if( IsCompressed() ) {
+
+ if( IsFloppy() ) {
+
+ MsgId = MSG_DBLSPACE_LIST_COMPRESSED_FLOPPY;
+
+ } else if( IsRemovable() ) {
+
+ MsgId = MSG_DBLSPACE_LIST_COMPRESSED_REMOVABLE;
+
+ } else {
+
+ MsgId = MSG_DBLSPACE_LIST_COMPRESSED_FIXED;
+ }
+
+ } else {
+
+ if( IsFloppy() ) {
+
+ MsgId = MSG_DBLSPACE_LIST_FLOPPY;
+
+ } else if( IsRemovable() ) {
+
+ MsgId = MSG_DBLSPACE_LIST_REMOVABLE;
+
+ } else {
+
+ MsgId = MSG_DBLSPACE_LIST_FIXED;
+ }
+ }
+
+ return MsgId;
+}
+
+BOOLEAN
+PRESENT_DRIVE_INFORMATION::IsPresent(
+ )
+{
+ return TRUE;
+}
+
+BIG_INT
+PRESENT_DRIVE_INFORMATION::QueryFreeBytes(
+ )
+{
+ return _BytesFree;
+}
+
+BIG_INT
+PRESENT_DRIVE_INFORMATION::QueryTotalBytes(
+ )
+{
+ return _TotalSize;
+}
+
+BOOLEAN
+PRESENT_DRIVE_INFORMATION::DetermineQualifiedCvfFileName(
+ PDRIVE_INFORMATION *DriveList,
+ ULONG Entries
+ )
+{
+ WCHAR DriveLetter;
+ ULONG i;
+
+ // If the drive is not compressed, there's no need to
+ // determine the host drive's drive letter.
+ //
+ if( !IsCompressed() ) {
+
+ return TRUE;
+ }
+
+ for( i = 0; i < Entries; i++ ) {
+
+ if( DriveList[i] &&
+ DriveList[i]->GetNtName() &&
+ !_HostDriveNtName.Stricmp( DriveList[i]->GetNtName() ) ) {
+
+ // We have a match. Initialize the qualified
+ // CVF file name.
+ //
+ _HostDriveLetter = DriveList[i]->QueryDriveLetter();
+ if( !_QualifiedCvfFileName.Initialize( L"X:\\" ) ||
+ !_QualifiedCvfFileName.Strcat( &_CvfFileName ) ||
+ !_QualifiedCvfFileName.SetChAt( _HostDriveLetter, 0 ) ) {
+
+ _QualifiedCvfFileName.Initialize( "" );
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+ }
+
+ // The host was not found.
+ //
+ return FALSE;
+}
+
+PWSTRING
+PRESENT_DRIVE_INFORMATION::GetNtName(
+ )
+{
+ return &_NtName;
+}
+
+PWSTRING
+PRESENT_DRIVE_INFORMATION::GetQualifiedCvfFileName(
+ )
+{
+ return &_QualifiedCvfFileName;
+}
+
+VOID
+InitializeDriveList(
+ PDRIVE_INFORMATION *DriveList,
+ ULONG Entries
+ )
+{
+ ULONG i;
+
+ for( i = 0; i < Entries; i++ ) {
+
+ DriveList[i] = NULL;
+ }
+}
+
+VOID
+CleanUpDriveList(
+ PDRIVE_INFORMATION *DriveList,
+ ULONG Entries
+ )
+{
+ ULONG i;
+
+ for( i = 0; i < Entries; i++ ) {
+
+ DELETE( DriveList[i] );
+ }
+}
+
+BOOLEAN
+DoList(
+ IN OUT PDOUBLE_SPACE_ARGUMENTS Arguments,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This function displays information about the double-space
+ volumes on the system.
+
+Arguments:
+
+ Arguments -- Supplies the arguments gathered from the command line.
+ Message -- Supplies an outlet for messages.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ DEFINE_CLASS_DESCRIPTOR( DRIVE_INFORMATION );
+ DEFINE_CLASS_DESCRIPTOR( PRESENT_DRIVE_INFORMATION );
+
+ CONST NtDriveNameBufferLength = 256;
+ CONST HostDriveNameBufferLength = 256;
+ CONST CvfFileNameBufferLength = 32;
+
+ WCHAR NtDriveNameBuffer[NtDriveNameBufferLength],
+ HostDriveNameBuffer[HostDriveNameBufferLength],
+ CvfFileNameBuffer[CvfFileNameBufferLength];
+
+ PDRIVE_INFORMATION DriveList[26];
+ PPRESENT_DRIVE_INFORMATION NewDrive;
+ ULONG i, MbFree, DbFree, MbTotal, DbTotal;
+ WCHAR DriveName[4] = { 'X', ':', '\\', 0 };
+ WCHAR DeviceName[3] = { 'X', ':', 0 };
+ WCHAR DriveLetter;
+ DWORD OldErrorMode;
+ BOOLEAN Removable, Error, IsRemovable, IsFloppy, IsCompressed;
+
+ InitializeDriveList( DriveList, 26 );
+
+ // Construct the list of basic drive information: determine
+ // which drive letters are attached to hard drives & floppies
+ // and query information about them.
+ //
+ OldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS );
+
+ for( i = 0; i < 26; i++ ) {
+
+ DriveLetter = (WCHAR)'A' + (WCHAR)i;
+ DriveName[0] = DriveLetter;
+ DeviceName[0] = DriveLetter;
+
+ Removable = FALSE;
+
+ switch( GetDriveType( DriveName ) ) {
+
+ case DRIVE_REMOVABLE:
+
+ Removable = TRUE;
+
+ // Fall through to fixed case.
+
+ case DRIVE_FIXED:
+
+ if( !FmifsQueryDriveInformation( DeviceName,
+ &IsRemovable,
+ &IsFloppy,
+ &IsCompressed,
+ &Error,
+ NtDriveNameBuffer,
+ NtDriveNameBufferLength,
+ CvfFileNameBuffer,
+ CvfFileNameBufferLength,
+ HostDriveNameBuffer,
+ HostDriveNameBufferLength ) ) {
+
+ if( Error ||
+ !(DriveList[i] = NEW DRIVE_INFORMATION) ||
+ !DriveList[i]->Initialize( DriveLetter, Removable ) ) {
+
+ Message->Set( MSG_FMT_NO_MEMORY );
+ Message->Display( "" );
+ CleanUpDriveList( DriveList, 26 );
+ return FALSE;
+ }
+
+ } else {
+
+ if( !(NewDrive = NEW PRESENT_DRIVE_INFORMATION) ||
+ !NewDrive->Initialize( DriveLetter,
+ Removable,
+ IsFloppy,
+ IsCompressed,
+ NtDriveNameBuffer,
+ HostDriveNameBuffer,
+ CvfFileNameBuffer ) ) {
+
+ Message->Set( MSG_FMT_NO_MEMORY );
+ Message->Display( "" );
+ CleanUpDriveList( DriveList, 26 );
+ return FALSE;
+ }
+
+ DriveList[i] = NewDrive;
+ }
+
+ break;
+
+ default:
+
+ DriveList[i] = NULL;
+ break;
+ }
+ }
+
+ SetErrorMode( OldErrorMode );
+
+ // For each compressed volume in the list, find which
+ // drive letter is attached to its host volume.
+ //
+ for( i = 0; i < 26; i++ ) {
+
+ if( DriveList[i] ) {
+
+ DriveList[i]->DetermineQualifiedCvfFileName(
+ DriveList,
+ 26
+ );
+ }
+ }
+
+ // Display the information this function has gathered.
+ //
+ Message->Set( MSG_DBLSPACE_LIST_HEADER );
+ Message->Display( "" );
+
+ for( i = 0; i < 26; i++ ) {
+
+ if( DriveList[i] != NULL ) {
+
+ Message->Set( DriveList[i]->QueryMsgId() );
+ Message->Display( "%c", DriveList[i]->QueryDriveLetter() );
+
+ if( !DriveList[i]->IsPresent() ) {
+
+ Message->Set( DriveList[i]->IsRemovable() ?
+ MSG_DBLSPACE_LIST_NOT_PRESENT_REMOVABLE :
+ MSG_DBLSPACE_LIST_NOT_PRESENT_FIXED );
+ Message->Display( "" );
+
+ } else {
+
+ MbFree = (DriveList[i]->QueryFreeBytes()/(1024*1024)).GetLowPart();
+ DbFree = (DriveList[i]->QueryFreeBytes()%(1024*1024)).GetLowPart();
+ DbFree = DbFree * 100 / (1024*1024);
+
+ MbTotal = (DriveList[i]->QueryTotalBytes()/(1024*1024)).GetLowPart();
+ DbTotal = (DriveList[i]->QueryTotalBytes()%(1024*1024)).GetLowPart();
+ DbTotal = DbTotal * 100 / (1024*1024);
+
+ Message->Set( MSG_DBLSPACE_LIST_DETAIL );
+ Message->Display( "%7d%.2d%7d%.2d%W\n",
+ MbFree, DbFree,
+ MbTotal, DbTotal,
+ DriveList[i]->GetQualifiedCvfFileName() );
+ }
+ }
+ }
+
+ Message->Set( MSG_BLANK_LINE );
+ Message->Display( "" );
+
+ Message->Set( DiskRegistryAutomountCurrentState() ?
+ MSG_DBLSPACE_AUTOMOUNT_STATE_ON :
+ MSG_DBLSPACE_AUTOMOUNT_STATE_OFF );
+ Message->Display( "" );
+
+ Message->Set( MSG_BLANK_LINE );
+ Message->Display( "" );
+
+ // Clean up and exit.
+ //
+ CleanUpDriveList( DriveList, 26 );
+ return TRUE;
+}
diff --git a/private/utils/dblspace/makefile b/private/utils/dblspace/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/dblspace/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/dblspace/sources b/private/utils/dblspace/sources
new file mode 100644
index 000000000..686b1f4dd
--- /dev/null
+++ b/private/utils/dblspace/sources
@@ -0,0 +1,74 @@
+
+
+
+
+
+DON'T BUILD DBLSPACE
+
+
+
+
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+BLDCRT=1
+
+MAJORCOMP=utils
+MINORCOMP=dblspace
+
+TARGETNAME=dblspace
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+SOURCES=dblspace.cxx dolist.cxx dblspace.rc
+
+INCLUDES=..\ulib\inc;..\ifsutil\inc;..\ufat\inc;..\fmifs\inc;$(BASEDIR)\public\sdk\inc;..\cudbfs
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DNOMINMAX -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DNOMINMAX -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DNOMINMAX -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DNOMINMAX -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+CXXFLAGS=+d
+UMLIBS=obj\*\dblspace.lib \
+ ..\ulib\src\obj\*\ulib.lib \
+ ..\ifsutil\src\obj\*\ifsutil.lib \
+ ..\ufat\src\obj\*\ufat.lib \
+ ..\fmifs\src\obj\*\fmifs.lib \
+ ..\cudbfs\obj\*\cudbfs.lib \
+ $(BASEDIR)\public\sdk\lib\*\diskreg.lib
+
+UMTYPE=console
+UMAPPL=dblspace
+
+UMRES=obj\*\dblspace.res
diff --git a/private/utils/dirs b/private/utils/dirs
new file mode 100644
index 000000000..d28c71eb4
--- /dev/null
+++ b/private/utils/dirs
@@ -0,0 +1,62 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+!ENDIF
+
+DIRS= ntlib \
+ ulib \
+ ureg \
+ mep \
+ ifsutil \
+ fmifs \
+ ufat \
+ untfs \
+ cufat \
+ attrib \
+ autochk \
+ autoconv \
+ chcp \
+ chkdsk \
+ chkntfs \
+ comp \
+ convert \
+ diskcomp \
+ diskcopy \
+ doskey \
+ fc \
+ find \
+ findstr \
+ keyb \
+ help \
+ label \
+ format \
+ mode \
+ more \
+ pentbug \
+ print \
+ rdisk \
+ recover \
+ regedit \
+ replace \
+ restore \
+ sort \
+ subst \
+ tree \
+ compact \
+ xcopy \
+ windisk \
+ wizards
+
+OPTIONAL_DIRS=ntbackup \
+ \
+ qcdbg
diff --git a/private/utils/diskcomp/diskcomp.cxx b/private/utils/diskcomp/diskcomp.cxx
new file mode 100644
index 000000000..c744dcd58
--- /dev/null
+++ b/private/utils/diskcomp/diskcomp.cxx
@@ -0,0 +1,438 @@
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "arg.hxx"
+#include "array.hxx"
+#include "smsg.hxx"
+#include "rtmsg.h"
+#include "wstring.hxx"
+#include "system.hxx"
+#include "ifssys.hxx"
+#include "supera.hxx"
+#include "hmem.hxx"
+#include "cmem.hxx"
+#include "ulibcl.hxx"
+
+ERRSTACK* perrstk;
+
+
+INT
+DiskComp(
+ IN PCWSTRING SrcNtDriveName,
+ IN PCWSTRING DstNtDriveName,
+ IN PCWSTRING SrcDosDriveName,
+ IN PCWSTRING DstDosDriveName,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine copies on floppy diskette to another floppy diskette.
+
+Arguments:
+
+ SrcNtDriveName - Supplies the NT style drive name for the source.
+ DstNtDriveName - Supplies the NT style drive name for the destination.
+ SrcDosDriveName - Supplies the DOS style drive name for the source.
+ DstDosDriveName - Supplies the DOS style drive name for the destination.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ 0 - The disks are the same.
+ 1 - The disks are different.
+ 3 - A hard error occurred.
+ 4 - An initialization error occurred.
+
+--*/
+{
+ LOG_IO_DP_DRIVE src_drive;
+ LOG_IO_DP_DRIVE dst_drive;
+ HMEM src_hmem;
+ HMEM dst_hmem;
+ CONT_MEM src_cmem;
+ PVOID mem_ptr;
+ SECRUN src_secrun;
+ SECRUN dst_secrun;
+ SECTORCOUNT sec_per_track;
+ ULONG total_tracks;
+ ULONG grab; // number of tracks to grab at once.
+ ULONG sector_size;
+ BOOLEAN one_drive;
+ ULONG src_top; // src track pointer -- next read
+ ULONG dst_top; // dst track pointer -- next write
+ PCHAR dst_pchar;
+ PCHAR src_pchar;
+ ULONG i;
+ BOOLEAN the_same;
+ ULONG heads;
+ DSTRING fsname;
+
+ one_drive = (*SrcDosDriveName == *DstDosDriveName);
+
+ Message->Set(MSG_DCOMP_INSERT_FIRST);
+ Message->Display("%W", SrcDosDriveName);
+
+ if (!one_drive) {
+ Message->Set(MSG_DCOMP_INSERT_SECOND);
+ Message->Display("%W", DstDosDriveName);
+ }
+
+ Message->Set(MSG_PRESS_ENTER_WHEN_READY);
+ Message->Display();
+ Message->WaitForUserSignal();
+
+ if (!src_drive.Initialize(SrcNtDriveName)) {
+
+ // Verify that we can access the source drive:
+
+ if (src_drive.QueryLastNtStatus() == STATUS_ACCESS_DENIED) {
+ Message->Set(MSG_DASD_ACCESS_DENIED);
+ Message->Display();
+ return 4;
+ }
+
+ Message->Set(MSG_DCOMP_FIRST_DISK_BAD);
+ Message->Display();
+ return 3;
+ }
+
+ if (!src_drive.IsFloppy()) {
+ Message->Set(MSG_DCOPY_INVALID_DRIVE);
+ Message->Display();
+ return 4;
+ }
+
+ if (src_drive.QueryMediaType() == Unknown) {
+ Message->Set(MSG_DCOMP_FIRST_DISK_BAD);
+ Message->Display();
+ return 3;
+ }
+
+ Message->Set(MSG_DCOMP_COMPARING);
+ Message->Display("%d%d%d", src_drive.QueryCylinders().GetLowPart(),
+ src_drive.QuerySectorsPerTrack(),
+ src_drive.QueryHeads());
+
+ sec_per_track = src_drive.QuerySectorsPerTrack();
+ sector_size = src_drive.QuerySectorSize();
+ total_tracks = src_drive.QueryTracks().GetLowPart();
+ heads = src_drive.QueryHeads();
+
+ DebugAssert(src_drive.QuerySectors().GetHighPart() == 0);
+
+ src_top = 0;
+
+ if (!dst_hmem.Initialize()) {
+ return 4;
+ }
+
+ the_same = TRUE;
+
+ for (dst_top = 0; dst_top < total_tracks; dst_top++) {
+
+ if (src_top == dst_top) {
+
+ if (src_top && one_drive) {
+ Message->Set(MSG_DCOMP_INSERT_FIRST);
+ Message->Display("%W", SrcDosDriveName);
+ Message->Set(MSG_PRESS_ENTER_WHEN_READY);
+ Message->Display();
+ Message->WaitForUserSignal();
+ }
+
+
+ // Allocate memory for read.
+
+ for (grab = total_tracks - src_top;
+ !src_hmem.Initialize() ||
+ !(mem_ptr = src_hmem.Acquire(grab*sector_size*sec_per_track,
+ src_drive.QueryAlignmentMask()));
+ grab /= 2) {
+
+ if (grab < 2) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return 4;
+ }
+ }
+
+ if (!src_cmem.Initialize(mem_ptr, grab*sector_size*sec_per_track)) {
+ return 4;
+ }
+
+
+ // Read the source, track by track.
+
+ for (i = 0; i < grab; i++) {
+ if (!src_secrun.Initialize(&src_cmem, &src_drive,
+ src_top*sec_per_track,
+ sec_per_track)) {
+ return 4;
+ }
+
+ if (!src_secrun.Read()) {
+
+ if (src_drive.QueryLastNtStatus() == STATUS_NO_MEDIA_IN_DEVICE ||
+ src_drive.QueryLastNtStatus() == STATUS_UNRECOGNIZED_MEDIA) {
+ return 3;
+ }
+
+ Message->Set(MSG_DCOPY_READ_ERROR);
+ Message->Display("%W%d%d", SrcDosDriveName,
+ src_top%heads, src_top/heads);
+ the_same = FALSE;
+ }
+ src_top++;
+ }
+
+ if (!src_cmem.Initialize(mem_ptr, grab*sector_size*sec_per_track)) {
+ return 4;
+ }
+
+ if (one_drive) {
+ Message->Set(MSG_DCOMP_INSERT_SECOND);
+ Message->Display("%W", DstDosDriveName);
+ Message->Set(MSG_PRESS_ENTER_WHEN_READY);
+ Message->Display();
+ Message->WaitForUserSignal();
+ }
+
+ if (!dst_top) {
+
+ if (!dst_drive.Initialize(DstNtDriveName)) {
+
+ // verify that we can access the destination drive:
+
+ if (dst_drive.QueryLastNtStatus() == STATUS_ACCESS_DENIED) {
+
+ Message->Set(MSG_DASD_ACCESS_DENIED);
+ Message->Display( "" );
+ return 4;
+ }
+
+ Message->Set(MSG_DCOMP_SECOND_DISK_BAD);
+ Message->Display();
+ return 3;
+ }
+
+ if (dst_drive.QueryMediaType() != src_drive.QueryMediaType()) {
+ Message->Set(MSG_DCOMP_NOT_COMPATIBLE);
+ Message->Display();
+ return 4;
+ }
+ }
+ }
+
+ if (!dst_secrun.Initialize(&dst_hmem, &dst_drive,
+ dst_top*sec_per_track, sec_per_track)) {
+ return 4;
+ }
+
+ if (dst_secrun.Read()) {
+ src_pchar = (PCHAR) src_cmem.Acquire(sector_size*sec_per_track);
+ dst_pchar = (PCHAR) dst_secrun.GetBuf();
+
+ if (!dst_top) {
+ if ((src_pchar[0x26] == 0x28 || src_pchar[0x26] == 0x29) &&
+ (dst_pchar[0x26] == 0x28 || dst_pchar[0x26] == 0x29)) {
+ memcpy(src_pchar + 0x27, dst_pchar + 0x27, sizeof(ULONG));
+ }
+ }
+
+ if (memcmp(src_pchar, dst_pchar, (UINT) (sector_size*sec_per_track))) {
+ Message->Set(MSG_DCOMP_COMPARE_ERROR);
+ Message->Display("%d%d", dst_top%heads, dst_top/heads);
+ the_same = FALSE;
+ }
+
+ } else {
+
+ if (dst_drive.QueryLastNtStatus() == STATUS_NO_MEDIA_IN_DEVICE ||
+ dst_drive.QueryLastNtStatus() == STATUS_UNRECOGNIZED_MEDIA) {
+ return 3;
+ }
+
+ Message->Set(MSG_DCOPY_READ_ERROR);
+ Message->Display("%W%d%d", DstDosDriveName,
+ dst_top%heads, dst_top/heads);
+ the_same = FALSE;
+ }
+ }
+
+ if (the_same) {
+ Message->Set(MSG_DCOMP_OK);
+ Message->Display();
+ }
+
+ return the_same ? 0 : 1;
+}
+
+
+INT _CRTAPI1
+main(
+ )
+/*++
+
+Routine Description:
+
+ Main program for DISKCOMP.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ 0 - The disks are the same.
+ 1 - The disks are different.
+ 3 - Fatal hard error.
+ 4 - Initialization error.
+
+--*/
+{
+ STREAM_MESSAGE msg;
+ PMESSAGE message;
+ ARGUMENT_LEXEMIZER arglex;
+ ARRAY lex_array;
+ ARRAY arg_array;
+ STRING_ARGUMENT progname;
+ STRING_ARGUMENT drive_arg1;
+ STRING_ARGUMENT drive_arg2;
+ FLAG_ARGUMENT slashv;
+ FLAG_ARGUMENT helparg;
+ DSTRING dossource;
+ DSTRING dosdest;
+ DSTRING ntsource;
+ DSTRING ntdest;
+ PWSTRING pwstring;
+ DSTRING colon;
+ INT result;
+
+ if (!(perrstk = new ERRSTACK)) {
+ return 4;
+ }
+
+ if (!msg.Initialize(Get_Standard_Output_Stream(),
+ Get_Standard_Input_Stream())) {
+ return 4;
+ }
+
+ message = &msg;
+
+ if (!lex_array.Initialize() || !arg_array.Initialize()) {
+ return 4;
+ }
+
+ if (!arglex.Initialize(&lex_array)) {
+ return 4;
+ }
+
+ arglex.SetCaseSensitive(FALSE);
+
+ if (!arglex.PrepareToParse()) {
+ return 4;
+ }
+
+ if (!progname.Initialize("*") ||
+ !drive_arg1.Initialize("*:") ||
+ !drive_arg2.Initialize("*:") ||
+ !helparg.Initialize("/?")) {
+ return 4;
+ }
+
+ if (!arg_array.Put(&progname) ||
+ !arg_array.Put(&drive_arg1) ||
+ !arg_array.Put(&drive_arg2) ||
+ !arg_array.Put(&helparg)) {
+ return 4;
+ }
+
+ if (!arglex.DoParsing(&arg_array)) {
+ message->Set(MSG_INVALID_PARAMETER);
+ message->Display("%W", pwstring = arglex.QueryInvalidArgument());
+ DELETE(pwstring);
+ return 4;
+ }
+
+ if (helparg.QueryFlag()) {
+ message->Set(MSG_DCOMP_INFO);
+ message->Display();
+ message->Set(MSG_DCOMP_USAGE);
+ message->Display();
+ return 0;
+ }
+
+ if (!colon.Initialize(":")) {
+ return 4;
+ }
+
+ if (drive_arg1.IsValueSet()) {
+ if (!dossource.Initialize(drive_arg1.GetString()) ||
+ !dossource.Strcat(&colon) ||
+ !dossource.Strupr()) {
+ return 4;
+ }
+ } else {
+ if (!SYSTEM::QueryCurrentDosDriveName(&dossource)) {
+ return 4;
+ }
+ }
+
+ if (drive_arg2.IsValueSet()) {
+ if (!dosdest.Initialize(drive_arg2.GetString()) ||
+ !dosdest.Strcat(&colon) ||
+ !dosdest.Strupr()) {
+ return 4;
+ }
+ } else {
+ if (!SYSTEM::QueryCurrentDosDriveName(&dosdest)) {
+ return 4;
+ }
+ }
+
+ if (SYSTEM::QueryDriveType(&dossource) != RemovableDrive) {
+ message->Set(MSG_DCOPY_INVALID_DRIVE);
+ message->Display();
+ return 4;
+ }
+
+ if (SYSTEM::QueryDriveType(&dosdest) != RemovableDrive) {
+ message->Set(MSG_DCOPY_INVALID_DRIVE);
+ message->Display();
+ return 4;
+ }
+
+ if (!IFS_SYSTEM::DosDriveNameToNtDriveName(&dossource, &ntsource)) {
+ message->Set(MSG_DCOPY_INVALID_DRIVE);
+ message->Display();
+ return 4;
+ }
+
+ if (!IFS_SYSTEM::DosDriveNameToNtDriveName(&dosdest, &ntdest)) {
+ message->Set(MSG_DCOPY_INVALID_DRIVE);
+ message->Display();
+ return 4;
+ }
+
+ for (;;) {
+
+ result = DiskComp(&ntsource, &ntdest, &dossource, &dosdest, message);
+
+ if (result > 1) {
+ message->Set(MSG_DCOMP_ENDED);
+ message->Display();
+ }
+
+ message->Set(MSG_DCOMP_ANOTHER);
+ message->Display();
+
+ if (!message->IsYesResponse(FALSE)) {
+ break;
+ }
+ }
+
+ return result;
+}
diff --git a/private/utils/diskcomp/diskcomp.rc b/private/utils/diskcomp/diskcomp.rc
new file mode 100644
index 000000000..3e1a3f170
--- /dev/null
+++ b/private/utils/diskcomp/diskcomp.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Disk Comparison Utility"
+#define VER_INTERNALNAME_STR "diskcomp\0"
+#define VER_ORIGINALFILENAME_STR "DISKCOMP.COM"
+
+#include "common.ver"
diff --git a/private/utils/diskcomp/makefile b/private/utils/diskcomp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/diskcomp/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/diskcomp/sources b/private/utils/diskcomp/sources
new file mode 100644
index 000000000..52728391b
--- /dev/null
+++ b/private/utils/diskcomp/sources
@@ -0,0 +1,64 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+BLDCRT=1
+
+MAJORCOMP=utils
+MINORCOMP=diskcomp
+
+TARGETNAME=diskcomp
+TARGETPATH=obj
+TARGETTYPE=UMAPPL_NOLIB
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=diskcomp.cxx diskcomp.rc
+
+INCLUDES=..\ulib\inc;..\ifsutil\inc;\nt\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+CXXFLAGS=+d
+UMLIBS= \
+ ..\ulib\src\obj\*\ulib.lib \
+ ..\ifsutil\src\obj\*\ifsutil.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+
+UMTYPE=console
+UMAPPL=diskcomp
+UMAPPLEXT=.com
+
+UMRES=obj\*\diskcomp.res
diff --git a/private/utils/diskcopy/diskcopy.cxx b/private/utils/diskcopy/diskcopy.cxx
new file mode 100644
index 000000000..28d0c29f9
--- /dev/null
+++ b/private/utils/diskcopy/diskcopy.cxx
@@ -0,0 +1,209 @@
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "arg.hxx"
+#include "array.hxx"
+#include "smsg.hxx"
+#include "rtmsg.h"
+#include "wstring.hxx"
+#include "system.hxx"
+#include "ifssys.hxx"
+#include "supera.hxx"
+#include "hmem.hxx"
+#include "cmem.hxx"
+#include "ulibcl.hxx"
+#include "mldcopy.hxx"
+
+ERRSTACK* perrstk;
+
+INT _CRTAPI1
+main(
+ )
+/*++
+
+Routine Description:
+
+ Main program for DISKCOPY.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ 0 - Copy was successful.
+ 1 - A nonfatal read/write error occured.
+ 3 - Fatal hard error.
+ 4 - Initialization error.
+
+--*/
+{
+ STREAM_MESSAGE msg;
+ PMESSAGE message;
+ ARGUMENT_LEXEMIZER arglex;
+ ARRAY lex_array;
+ ARRAY arg_array;
+ STRING_ARGUMENT progname;
+ STRING_ARGUMENT drive_arg1;
+ STRING_ARGUMENT drive_arg2;
+ FLAG_ARGUMENT slashv;
+ FLAG_ARGUMENT helparg;
+ FLAG_ARGUMENT genvalue;
+ DSTRING dossource;
+ DSTRING dosdest;
+ DSTRING ntsource;
+ DSTRING ntdest;
+ DSTRING currentdrive;
+ PWSTRING pwstring;
+ DSTRING colon;
+ INT result;
+
+ if (!(perrstk = new ERRSTACK)) {
+ return 4;
+ }
+
+ if (!msg.Initialize(Get_Standard_Output_Stream(),
+ Get_Standard_Input_Stream())) {
+ return 4;
+ }
+
+ message = &msg;
+
+ if (!lex_array.Initialize() || !arg_array.Initialize()) {
+ return 4;
+ }
+
+ if (!arglex.Initialize(&lex_array)) {
+ return 4;
+ }
+
+ arglex.SetCaseSensitive(FALSE);
+
+ if (!arglex.PrepareToParse()) {
+ return 4;
+ }
+
+ if (!progname.Initialize("*") ||
+ !drive_arg1.Initialize("*:") ||
+ !drive_arg2.Initialize("*:") ||
+ !slashv.Initialize("/v") ||
+ !helparg.Initialize("/?") ||
+ !genvalue.Initialize("/machinetoken")) {
+ return 4;
+ }
+
+ if (!arg_array.Put(&progname) ||
+ !arg_array.Put(&drive_arg1) ||
+ !arg_array.Put(&drive_arg2) ||
+ !arg_array.Put(&slashv) ||
+ !arg_array.Put(&helparg) ||
+ !arg_array.Put(&genvalue)) {
+ return 4;
+ }
+
+ if (!arglex.DoParsing(&arg_array)) {
+ message->Set(MSG_INVALID_PARAMETER);
+ message->Display("%W", pwstring = arglex.QueryInvalidArgument());
+ DELETE(pwstring);
+ return 4;
+ }
+
+ if (genvalue.QueryFlag()) {
+ message->Set(MSG_ONE_STRING_NEWLINE);
+ message->Display("%X", QueryMachineUniqueToken());
+ return 0;
+ }
+
+ if (helparg.QueryFlag()) {
+ message->Set(MSG_DCOPY_INFO);
+ message->Display();
+ message->Set(MSG_DCOPY_USAGE);
+ message->Display();
+ message->Set(MSG_DCOPY_SLASH_V);
+ message->Display();
+ message->Set(MSG_DCOPY_INFO_2);
+ message->Display();
+ return 0;
+ }
+
+ if (!colon.Initialize(":")) {
+ return 4;
+ }
+
+ if (drive_arg1.IsValueSet()) {
+ if (!dossource.Initialize(drive_arg1.GetString()) ||
+ !dossource.Strcat(&colon) ||
+ !dossource.Strupr()) {
+ return 4;
+ }
+ } else {
+ if (!SYSTEM::QueryCurrentDosDriveName(&dossource)) {
+ return 4;
+ }
+ }
+
+ if (drive_arg2.IsValueSet()) {
+ if (!dosdest.Initialize(drive_arg2.GetString()) ||
+ !dosdest.Strcat(&colon) ||
+ !dosdest.Strupr()) {
+ return 4;
+ }
+ } else {
+ if (!SYSTEM::QueryCurrentDosDriveName(&dosdest)) {
+ return 4;
+ }
+ }
+
+ if (SYSTEM::QueryDriveType(&dossource) != RemovableDrive) {
+ message->Set(MSG_DCOPY_INVALID_DRIVE);
+ message->Display();
+ return 4;
+ }
+
+ if (SYSTEM::QueryDriveType(&dosdest) != RemovableDrive) {
+ message->Set(MSG_DCOPY_INVALID_DRIVE);
+ message->Display();
+ return 4;
+ }
+
+ if (!SYSTEM::QueryCurrentDosDriveName(&currentdrive) ||
+ currentdrive == dosdest) {
+
+ message->Set(MSG_CANT_LOCK_CURRENT_DRIVE);
+ message->Display();
+ return 4;
+ }
+
+ if (!IFS_SYSTEM::DosDriveNameToNtDriveName(&dossource, &ntsource)) {
+ message->Set(MSG_DCOPY_INVALID_DRIVE);
+ message->Display();
+ return 4;
+ }
+
+ if (!IFS_SYSTEM::DosDriveNameToNtDriveName(&dosdest, &ntdest)) {
+ message->Set(MSG_DCOPY_INVALID_DRIVE);
+ message->Display();
+ return 4;
+ }
+
+ for (;;) {
+
+ result = DiskCopyMainLoop(&ntsource, &ntdest, &dossource, &dosdest,
+ slashv.QueryFlag(), message);
+
+ if (result > 1) {
+ message->Set(MSG_DCOPY_ENDED);
+ message->Display();
+ }
+
+ message->Set(MSG_DCOPY_ANOTHER);
+ message->Display();
+
+ if (!message->IsYesResponse(FALSE)) {
+ break;
+ }
+ }
+
+ return result;
+}
diff --git a/private/utils/diskcopy/diskcopy.rc b/private/utils/diskcopy/diskcopy.rc
new file mode 100644
index 000000000..75d74f644
--- /dev/null
+++ b/private/utils/diskcopy/diskcopy.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Disk Copy Utility"
+#define VER_INTERNALNAME_STR "diskcopy\0"
+#define VER_ORIGINALFILENAME_STR "DISKCOPY.COM"
+
+#include "common.ver"
diff --git a/private/utils/diskcopy/makefile b/private/utils/diskcopy/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/diskcopy/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/diskcopy/sources b/private/utils/diskcopy/sources
new file mode 100644
index 000000000..ff5584c14
--- /dev/null
+++ b/private/utils/diskcopy/sources
@@ -0,0 +1,62 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+BLDCRT=1
+
+MAJORCOMP=utils
+MINORCOMP=diskcopy
+
+TARGETNAME=diskcopy
+TARGETPATH=obj
+TARGETTYPE=UMAPPL_NOLIB
+
+SOURCES=diskcopy.cxx diskcopy.rc
+
+INCLUDES=..\ulib\inc;..\ifsutil\inc;\nt\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+CXXFLAGS=+d
+UMLIBS= \
+ ..\ulib\src\obj\*\ulib.lib \
+ ..\ifsutil\src\obj\*\ifsutil.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+
+UMTYPE=console
+UMAPPL=diskcopy
+UMAPPLEXT=.com
+
+UMRES=obj\*\diskcopy.res
diff --git a/private/utils/doskey/doskey.cxx b/private/utils/doskey/doskey.cxx
new file mode 100644
index 000000000..17f048769
--- /dev/null
+++ b/private/utils/doskey/doskey.cxx
@@ -0,0 +1,763 @@
+#include "ulib.hxx"
+#include "error.hxx"
+
+#include "arg.hxx"
+#include "smsg.hxx"
+#include "rtmsg.h"
+#include "wstring.hxx"
+#include "path.hxx"
+#include "filestrm.hxx"
+#include "system.hxx"
+#include "file.hxx"
+
+#include "ulibcl.hxx"
+
+extern "C" {
+#include "conapi.h"
+#include <ctype.h>
+#ifdef DBCS // isspace patch
+// isspace() causes access violation when x is Unicode char
+// that is not included in ASCII charset.
+#define isspace(x) ( (x) == ' ' ) ? TRUE : FALSE
+#endif // DBCS
+};
+
+ERRSTACK* perrstk;
+
+VOID
+StripQuotesFromString(
+ IN PWSTRING String
+ )
+/*++
+
+Routine Description:
+
+ This routine removes leading and trailing quote marks (if
+ present) from a quoted string. If the string is not a quoted
+ string, it is left unchanged.
+
+--*/
+{
+ if( String->QueryChCount() >= 2 &&
+ String->QueryChAt( 0 ) == '\"' &&
+ String->QueryChAt( String->QueryChCount() - 1 ) == '\"' ) {
+
+ String->DeleteChAt( String->QueryChCount() - 1 );
+ String->DeleteChAt( 0 );
+ }
+}
+
+
+BOOLEAN
+DisplayPackedString(
+ IN PCWSTR PackedStrings,
+ IN ULONG PackedStringsLength,
+ IN BOOLEAN IndentStrings,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine outputs the given strings. One line per string.
+
+Arguments:
+
+ PackedStrings - Supplies the null-separated strings to output.
+ PackedStringsLength - Supplies the number of characters in the strings.
+ NumIndentSpaces - Supplies whether or not to indent the strings.
+ Message - Supplies the outlet for the strings.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ DSTRING display_string;
+ DSTRING raw_string;
+ ULONG i;
+ PCWSTR p;
+
+ p = PackedStrings;
+
+ for (i = 0; i < PackedStringsLength; i++) {
+
+ if (i > 0 && p[i - 1]) {
+ continue;
+ }
+
+ if (IndentStrings) {
+
+ if (!display_string.Initialize(" ")) {
+ return FALSE;
+ }
+ } else {
+
+ if (!display_string.Initialize("")) {
+ return FALSE;
+ }
+ }
+
+
+ if (!raw_string.Initialize(&p[i]) ||
+ !display_string.Strcat(&raw_string)) {
+
+ return FALSE;
+ }
+
+ Message->Set(MSG_ONE_STRING_NEWLINE);
+ Message->Display("%W", &display_string);
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+QuerySourceAndTarget(
+ IN PCWSTRING MacroLine,
+ OUT PWSTR* Source,
+ OUT PWSTR* Target
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the sources and target string from the given macro line
+ by isolating the '=' and then making sure that the source is a single token.
+
+Arguments:
+
+ MacroLine - Supplies the macro.
+ Source - Returns the source part of the macro.
+ Target - Returns the target part of the macro.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ LONG src_start, src_end, dst_start;
+ ULONG i, n;
+ WCHAR w;
+
+ *Source = NULL;
+ *Target = NULL;
+
+ i = 0;
+ n = MacroLine->QueryChCount();
+
+ for (; i < n; i++) {
+ w = MacroLine->QueryChAt(i);
+ if (!isspace(w)) {
+ break;
+ }
+ }
+
+ src_start = i;
+
+ for (; i < n; i++) {
+ w = MacroLine->QueryChAt(i);
+ if (isspace(w) || w == '=') {
+ break;
+ }
+ }
+
+ src_end = i;
+
+ if (src_start == src_end) {
+ return FALSE;
+ }
+
+ for (; i < n; i++) {
+ w = MacroLine->QueryChAt(i);
+ if (!isspace(w)) {
+ break;
+ }
+ }
+
+ if (w != '=') {
+ return FALSE;
+ }
+
+ i++;
+
+ for (; i < n; i++) {
+ w = MacroLine->QueryChAt(i);
+ if (!isspace(w)) {
+ break;
+ }
+ }
+
+ dst_start = i;
+
+ *Source = MacroLine->QueryWSTR(src_start, src_end - src_start);
+ *Target = MacroLine->QueryWSTR(dst_start);
+
+ if (!*Source || !*Target) {
+ DELETE(*Source);
+ DELETE(*Target);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+DisplayMacros(
+ IN PWSTR TargetExe,
+ IN BOOLEAN IndentString,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine displays the macros for the given exe.
+
+Arguments:
+
+ TargetExe - Supplies the exe for which to display the macros.
+ IndentStrings - Supplies whether or not to indent the macro strings.
+ Message - Supplies an outlet for the macro strings.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG buffer_length = 0;
+ PWSTR buffer;
+
+ buffer_length = GetConsoleAliasesLength(TargetExe);
+ if (!(buffer = (PWCHAR) MALLOC(buffer_length + 1))) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (buffer_length) {
+ buffer_length = GetConsoleAliases(buffer, buffer_length, TargetExe);
+ }
+
+ if (!DisplayPackedString(buffer, buffer_length/sizeof(WCHAR),
+ IndentString, Message)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ FREE(buffer);
+
+ return TRUE;
+}
+
+
+BOOLEAN
+DisplayAllMacros(
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine displays all of the macros for all of the exes which have macros
+ defined for them.
+
+Arguments:
+
+ Message - Supplies an outlet for the macros.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PWSTR exes_buffer;
+ ULONG exes_length;
+ ULONG i;
+ DSTRING exe_name;
+ DSTRING display_name;
+
+ exes_length = GetConsoleAliasExesLength();
+ if (!(exes_buffer = (PWSTR) MALLOC(exes_length + 1))) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (exes_length) {
+ exes_length = GetConsoleAliasExes(exes_buffer, exes_length);
+ }
+
+ exes_length /= sizeof(WCHAR);
+
+ for (i = 0; i < exes_length; i++) {
+
+ if (i > 0 && exes_buffer[i - 1]) {
+ continue;
+ }
+
+ if (!exe_name.Initialize(&exes_buffer[i]) ||
+ !display_name.Initialize("[") ||
+ !display_name.Strcat(&exe_name) ||
+ !exe_name.Initialize("]") ||
+ !display_name.Strcat(&exe_name)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ Message->Set(MSG_ONE_STRING_NEWLINE);
+ Message->Display("%W", &display_name);
+
+ if (!DisplayMacros(&exes_buffer[i], TRUE, Message)) {
+ return FALSE;
+ }
+
+ Message->Set(MSG_BLANK_LINE);
+ Message->Display();
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+ReadInMacrosFromFile(
+ IN PPATH FilePath,
+ IN PWSTR TargetExe,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine reads in the macros in the given file. The file must have the same
+ format as the output from DOSKEY /macros or DOSKEY /macros:all.
+
+Arguments:
+
+ FilePath - Supplies the file with the macros.
+ TargetExe - Supplies the exe for which the unclaimed macros are.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PFSN_FILE file;
+ PFILE_STREAM file_stream;
+ DSTRING line;
+ PWSTR target_exe;
+ DSTRING target_string;
+ PWSTR source, target;
+
+ if (!(file = SYSTEM::QueryFile(FilePath)) ||
+ !(file_stream = file->QueryStream(READ_ACCESS))) {
+
+ DELETE(file);
+
+ Message->Set(MSG_ATTRIB_FILE_NOT_FOUND);
+ Message->Display("%W", FilePath->GetPathString());
+ return FALSE;
+ }
+
+
+ // Set up the target exe.
+
+ if (!line.Initialize("") ||
+ !target_string.Initialize(TargetExe) ||
+ !(target_exe = target_string.QueryWSTR())) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ while (!file_stream->IsAtEnd() && file_stream->ReadLine(&line)) {
+
+ // First see if the current line will define a new exe name.
+
+ if (!line.QueryChCount()) {
+ continue;
+ }
+
+ if (line.QueryChAt(0) == '[' &&
+ line.Strchr(']') != INVALID_CHNUM &&
+ line.Strchr(']') > 1) {
+
+ DELETE(target_exe);
+ if (!target_string.Initialize(&line, 1, line.Strchr(']') - 1) ||
+ !(target_exe = target_string.QueryWSTR())) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ continue;
+ }
+
+
+ if (!QuerySourceAndTarget(&line, &source, &target) ||
+ !AddConsoleAlias(source, *target ? target : NULL, target_exe)) {
+
+ Message->Set(MSG_DOSKEY_INVALID_MACRO_DEFINITION);
+ Message->Display();
+
+ continue;
+ }
+ }
+
+ DELETE(file_stream);
+ DELETE(file);
+
+ return TRUE;
+}
+
+int _CRTAPI1
+main(
+ )
+/*++
+
+Routine Description:
+
+ This routine provides equivalent functionality to DOS 5's DOSKEY utility.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ 0 - Success.
+ 1 - Failure.
+
+--*/
+{
+ STREAM_MESSAGE msg;
+ ARGUMENT_LEXEMIZER arglex;
+ ARRAY lex_array;
+ ARRAY arg_array;
+ STRING_ARGUMENT progname;
+ FLAG_ARGUMENT help;
+ FLAG_ARGUMENT reinstall;
+ LONG_ARGUMENT bufsize;
+ LONG_ARGUMENT listsize;
+ STRING_ARGUMENT m_plus;
+ FLAG_ARGUMENT m;
+ STRING_ARGUMENT macros_plus;
+ FLAG_ARGUMENT macros;
+ FLAG_ARGUMENT history;
+ FLAG_ARGUMENT h;
+ FLAG_ARGUMENT insert;
+ FLAG_ARGUMENT overstrike;
+ STRING_ARGUMENT exename;
+ PATH_ARGUMENT filename;
+ REST_OF_LINE_ARGUMENT macro;
+ PWSTRING pwstring;
+ PWSTR target_exe;
+ PWSTR source, target;
+ PWSTR buffer;
+ ULONG buffer_length;
+ DSTRING all_string;
+
+
+ // Initialize the error stack and the stream message object.
+
+ if (!(perrstk = NEW ERRSTACK) ||
+ !msg.Initialize(Get_Standard_Output_Stream(),
+ Get_Standard_Input_Stream())) {
+
+ return 1;
+ }
+
+
+ // Initialize the parsing machinery.
+
+ if (!lex_array.Initialize() ||
+ !arg_array.Initialize() ||
+ !arglex.Initialize(&lex_array)) {
+
+ return 1;
+ }
+
+ arglex.SetCaseSensitive(FALSE);
+ arglex.PutStartQuotes( "\"" );
+ arglex.PutEndQuotes( "\"" );
+ arglex.PutSeparators( " \t" );
+
+
+ // Tokenize the command line.
+
+ if (!arglex.PrepareToParse()) {
+
+ return 1;
+ }
+
+
+ // Initialize the argument patterns to be accepted.
+
+ if (!progname.Initialize("*") ||
+ !help.Initialize("/?") ||
+ !reinstall.Initialize("/reinstall") ||
+ !bufsize.Initialize("/bufsize=*") ||
+ !listsize.Initialize("/listsize=*") ||
+ !macros_plus.Initialize("/macros:*") ||
+ !m_plus.Initialize("/m:*") ||
+ !macros.Initialize("/macros") ||
+ !m.Initialize("/m") ||
+ !history.Initialize("/history") ||
+ !h.Initialize("/h") ||
+ !insert.Initialize("/insert") ||
+ !overstrike.Initialize("/overstrike") ||
+ !exename.Initialize("/exename=*") ||
+ !filename.Initialize("/macrofile=*") ||
+ !macro.Initialize()) {
+
+ return 1;
+ }
+
+
+ // Feed the arguments into the argument array.
+
+ if (!arg_array.Put(&progname) ||
+ !arg_array.Put(&help) ||
+ !arg_array.Put(&reinstall) ||
+ !arg_array.Put(&bufsize) ||
+ !arg_array.Put(&listsize) ||
+ !arg_array.Put(&macros_plus) ||
+ !arg_array.Put(&m_plus) ||
+ !arg_array.Put(&macros) ||
+ !arg_array.Put(&m) ||
+ !arg_array.Put(&history) ||
+ !arg_array.Put(&h) ||
+ !arg_array.Put(&insert) ||
+ !arg_array.Put(&overstrike) ||
+ !arg_array.Put(&exename) ||
+ !arg_array.Put(&filename) ||
+ !arg_array.Put(&macro)) {
+
+ return 1;
+ }
+
+
+ // Parse the command line.
+
+ if (!arglex.DoParsing(&arg_array)) {
+
+ msg.Set(MSG_INVALID_PARAMETER);
+ msg.Display("%W", pwstring = arglex.QueryInvalidArgument());
+ DELETE(pwstring);
+ return 1;
+ }
+
+
+ // Interpret the command line.
+
+ if (bufsize.IsValueSet()) {
+
+ msg.Set(MSG_DOSKEY_CANT_DO_BUFSIZE);
+ msg.Display();
+ }
+
+
+ if (help.QueryFlag()) {
+
+ msg.Set(MSG_DOSKEY_HELP);
+ msg.Display();
+ return 0;
+ }
+
+
+ if ((m.QueryFlag() || macros.QueryFlag()) &&
+ (macros_plus.IsValueSet() || m_plus.IsValueSet()) ||
+ (macros_plus.IsValueSet() && m_plus.IsValueSet())) {
+
+ msg.Set(MSG_INCOMPATIBLE_PARAMETERS);
+ msg.Display();
+ return 1;
+ }
+
+
+ // Compute the target exe name.
+
+ if (exename.IsValueSet()) {
+
+ StripQuotesFromString( (PWSTRING)exename.GetString() );
+ if (!(target_exe = exename.GetString()->QueryWSTR())) {
+ return 1;
+ }
+
+ } else {
+
+ target_exe = (PWSTR) L"cmd.exe";
+ }
+
+
+ // Interpret reinstall switch.
+
+ if (reinstall.QueryFlag()) {
+
+ ExpungeConsoleCommandHistory(target_exe);
+ }
+
+
+ // Interpret list size switch.
+
+ if (listsize.IsValueSet()) {
+ if (!SetConsoleNumberOfCommands(listsize.QueryLong(), target_exe)) {
+ msg.Set(MSG_DOSKEY_CANT_SIZE_LIST);
+ msg.Display();
+ return 1;
+ }
+ }
+
+
+ // Interpret insert and overstrike switches.
+
+ if (insert.QueryFlag()) {
+ SetConsoleCommandHistoryMode(0);
+ }
+
+ if (overstrike.QueryFlag()) {
+ SetConsoleCommandHistoryMode(CONSOLE_OVERSTRIKE);
+ }
+
+
+ // Interpret the macro if any.
+
+ if (macro.IsValueSet()) {
+
+ if (!QuerySourceAndTarget(macro.GetRestOfLine(), &source, &target) ||
+ !AddConsoleAlias(source, *target ? target : NULL, target_exe)) {
+
+ msg.Set(MSG_DOSKEY_INVALID_MACRO_DEFINITION);
+ msg.Display();
+ }
+
+ DELETE(source);
+ DELETE(target);
+ }
+
+
+ // Suck the stuff out from the file if provided.
+
+ if (filename.IsValueSet()) {
+
+ StripQuotesFromString((PWSTRING)filename.GetPath()->GetPathString());
+ if (!ReadInMacrosFromFile(filename.GetPath(), target_exe, &msg)) {
+ return 1;
+ }
+ }
+
+
+ // Print out history buffer.
+
+ if (history.QueryFlag() || h.QueryFlag()) {
+
+ buffer_length = GetConsoleCommandHistoryLength(target_exe);
+ if (!(buffer = (PWSTR) MALLOC(buffer_length))) {
+ msg.Set(MSG_CHK_NO_MEMORY);
+ msg.Display();
+ return 1;
+ }
+
+ if (buffer_length) {
+ buffer_length = GetConsoleCommandHistory(buffer,
+ buffer_length,
+ target_exe);
+ }
+
+ if (!DisplayPackedString(buffer, buffer_length/sizeof(WCHAR),
+ FALSE, &msg)) {
+
+ msg.Set(MSG_CHK_NO_MEMORY);
+ msg.Display();
+ return 1;
+ }
+
+ FREE(buffer);
+ }
+
+
+ // Echo macros for target_exe.
+
+ if (macros.QueryFlag() || m.QueryFlag()) {
+ if (!DisplayMacros(target_exe, FALSE, &msg)) {
+ return 1;
+ }
+ }
+
+
+ // Echo macros for specific exe.
+
+ if (macros_plus.IsValueSet()) {
+
+ StripQuotesFromString(macros_plus.GetString());
+ if (!all_string.Initialize("all")) {
+ return 1;
+ }
+
+ if (!macros_plus.GetString()->Stricmp(&all_string)) {
+
+ if (!DisplayAllMacros(&msg)) {
+ return 1;
+ }
+
+ } else {
+
+ target_exe = macros_plus.GetString()->QueryWSTR();
+
+ if (!DisplayMacros(target_exe, FALSE, &msg)) {
+ return 1;
+ }
+
+ DELETE(target_exe);
+ }
+ }
+
+
+ // Echo macros for specific exe.
+
+ if (m_plus.IsValueSet()) {
+
+ StripQuotesFromString(m_plus.GetString());
+ if (!all_string.Initialize("all")) {
+ return 1;
+ }
+
+ if (!m_plus.GetString()->Stricmp(&all_string)) {
+
+ if (!DisplayAllMacros(&msg)) {
+ return 1;
+ }
+
+ } else {
+
+ target_exe = m_plus.GetString()->QueryWSTR();
+
+ if (!DisplayMacros(target_exe, FALSE, &msg)) {
+ return 1;
+ }
+
+ DELETE(target_exe);
+ }
+ }
+
+ return 0;
+}
diff --git a/private/utils/doskey/doskey.rc b/private/utils/doskey/doskey.rc
new file mode 100644
index 000000000..cbd2c399f
--- /dev/null
+++ b/private/utils/doskey/doskey.rc
@@ -0,0 +1,11 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Keyboard History Utility"
+#define VER_INTERNALNAME_STR "doskey\0"
+#define VER_ORIGINALFILENAME_STR "DOSKEY.EXE"
+
+#include "common.ver"
+
diff --git a/private/utils/doskey/makefile b/private/utils/doskey/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/doskey/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/doskey/sources b/private/utils/doskey/sources
new file mode 100644
index 000000000..588217b7d
--- /dev/null
+++ b/private/utils/doskey/sources
@@ -0,0 +1,62 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+BLDCRT=1
+
+MAJORCOMP=utils
+MINORCOMP=doskey
+
+TARGETNAME=doskey
+TARGETPATH=obj
+TARGETTYPE=UMAPPL_NOLIB
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=doskey.cxx doskey.rc
+
+INCLUDES=..\ulib\inc;\nt\public\sdk\inc;\nt\private\windows\inc;
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+
+CXXFLAGS=+d
+UMLIBS=..\ulib\src\obj\*\ulib.lib \nt\public\sdk\lib\*\ntdll.lib
+
+UMTYPE=console
+
+UMAPPL=doskey
+
+UMRES=obj\*\doskey.res
diff --git a/private/utils/fc.old/fc.cxx b/private/utils/fc.old/fc.cxx
new file mode 100644
index 000000000..76eb48ea6
--- /dev/null
+++ b/private/utils/fc.old/fc.cxx
@@ -0,0 +1,1492 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ fc.cxx
+
+Abstract:
+
+ Compares two files or sets of files and displays the differences between
+ them.
+
+ FC [/A] [/C] [/L] [/LBn] [/N] [/T] [/W] [/nnnn] [drive1:][path1]filename1
+ [drive2:][path2]filename2
+ FC /B [drive1:][path1]filename1 [drive2:][path2]filename2
+
+ /A Displays only first and last lines for each set of differences.
+ /B Performs a binary comparison.
+ /C Disregards the case of letters.
+ /L Compares files as ASCII text.
+ /LBn Sets the maximum consecutive mismatches to the specified number of
+ lines.
+ /N Displays the line numbers on an ASCII comparison.
+ /T Does not expand tabs to spaces.
+ /W Compresses white space (tabs and spaces) for comparison.
+ /nnnn Specifies the number of consecutive lines that must match after a
+ mismatch.
+
+Author:
+
+ Barry J. Gilhuly *** W-Barry *** May 91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include "ulib.hxx"
+#include "ulibcl.hxx"
+#include "error.hxx"
+#include "arg.hxx"
+#include "array.hxx"
+#include "dir.hxx"
+#include "file.hxx"
+#include "filestrm.hxx"
+#include "filter.hxx"
+#include "iterator.hxx"
+#include "path.hxx"
+#include "rtmsg.h"
+#include "system.hxx"
+#include "smsg.hxx"
+#include "fc.hxx"
+
+
+extern "C" {
+#include <stdio.h>
+#include <string.h>
+}
+
+
+ERRSTACK *perrstk;
+STREAM_MESSAGE *psmsg; // Create a pointer to the stream message
+ // class for program output.
+
+DEFINE_CONSTRUCTOR( FC, PROGRAM );
+
+
+VOID
+FC::Destruct(
+ )
+/*++
+
+Routine Description:
+
+ Cleans up after finishing with an FC object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ DELETE( perrstk );
+ DELETE( psmsg );
+
+ DELETE( _InputPath1 );
+ DELETE( _InputPath2 );
+
+ return;
+}
+
+
+
+BOOLEAN
+FC::Initialize(
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes an FC object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the initialization succeeded.
+
+
+--*/
+
+
+{
+ ARGUMENT_LEXEMIZER ArgLex;
+ ARRAY LexArray;
+ ARRAY ArrayOfArg;
+
+ PATH_ARGUMENT ProgramName;
+ FLAG_ARGUMENT FlagAbbreviate;
+ FLAG_ARGUMENT FlagAsciiCompare;
+ FLAG_ARGUMENT FlagBinaryCompare;
+ FLAG_ARGUMENT FlagCaseInsensitive;
+ FLAG_ARGUMENT FlagCompression;
+ FLAG_ARGUMENT FlagExpansion;
+ FLAG_ARGUMENT FlagLineNumber;
+ FLAG_ARGUMENT FlagRequestHelp;
+
+ PATH_ARGUMENT InFile1;
+ PATH_ARGUMENT InFile2;
+
+ PCPATH TmpPath;
+ WSTRING TmpString1;
+ WSTRING TmpString2;
+ PCWSTRING AuxString;
+
+
+ _InputPath1 = NULL;
+ _InputPath2 = NULL;
+
+ //
+ // Set the default mode to ASCII
+ //
+ _Mode = FALSE;
+
+ if( !LexArray.Initialize() ) {
+ DbgAbort( "LexArray.Initialize() Failed!\n" );
+ return( FALSE );
+ }
+ if( !ArgLex.Initialize(&LexArray) ) {
+ DbgAbort( "ArgLex.Initialize() Failed!\n" );
+ return( FALSE );
+ }
+
+ // Allow only the '/' as a valid switch
+ ArgLex.PutSwitches("/");
+ ArgLex.SetCaseSensitive( FALSE );
+
+ if( !ArgLex.PrepareToParse() ) {
+ DbgAbort( "ArgLex.PrepareToParse() Failed!\n" );
+ return( FALSE );
+ }
+
+ if( !ProgramName.Initialize("*") ||
+ !FlagAbbreviate.Initialize("/A") ||
+ !FlagAsciiCompare.Initialize("/L") ||
+ !FlagBinaryCompare.Initialize("/B") ||
+ !FlagCaseInsensitive.Initialize("/C") ||
+ !FlagCompression.Initialize("/W") ||
+ !FlagExpansion.Initialize("/T") ||
+ !FlagLineNumber.Initialize("/N") ||
+ !FlagRequestHelp.Initialize("/?") ||
+ !_LongBufferSize.Initialize("/LB#") ||
+ !_LongMatch.Initialize("/*") ||
+ !InFile1.Initialize("*") ||
+ !InFile2.Initialize("*") ) {
+
+ DbgAbort( "Unable to Initialize some or all of the Arguments!\n" );
+ return( FALSE );
+ }
+
+
+ if( !ArrayOfArg.Initialize() ) {
+ DbgAbort( "ArrayOfArg.Initialize() Failed\n" );
+ return( FALSE );
+ }
+
+ if( !ArrayOfArg.Put(&ProgramName) ||
+ !ArrayOfArg.Put(&FlagAbbreviate) ||
+ !ArrayOfArg.Put(&FlagAsciiCompare) ||
+ !ArrayOfArg.Put(&FlagBinaryCompare) ||
+ !ArrayOfArg.Put(&FlagCaseInsensitive) ||
+ !ArrayOfArg.Put(&FlagCompression) ||
+ !ArrayOfArg.Put(&FlagExpansion) ||
+ !ArrayOfArg.Put(&FlagLineNumber) ||
+ !ArrayOfArg.Put(&FlagRequestHelp) ||
+ !ArrayOfArg.Put(&_LongBufferSize) ||
+ !ArrayOfArg.Put(&_LongMatch) ||
+ !ArrayOfArg.Put(&InFile1) ||
+ !ArrayOfArg.Put(&InFile2) ) {
+
+ DbgAbort( "ArrayOfArg.Put() Failed!\n" );
+ return( FALSE );
+
+ }
+
+
+ if( !( ArgLex.DoParsing( &ArrayOfArg ) ) ) {
+ // For each incorrect command line parameter, FC displays the
+ // following message:
+ //
+ // FC: Invalid Switch
+ //
+ // It does *not* die if a parameter is unrecognized...(Dos does...)
+ //
+ psmsg->Set( MSG_FC_INVALID_SWITCH );
+ psmsg->Display( "" );
+
+ return( FALSE );
+ }
+
+
+
+ // It should now be safe to test the arguments for their values...
+ if( FlagRequestHelp.QueryFlag() ) {
+
+ // Send help message
+ psmsg->Set( MSG_FC_HELP_MESSAGE );
+ psmsg->Display( "" );
+
+ return( FALSE );
+ }
+
+ if( FlagBinaryCompare.QueryFlag() &&
+ ( FlagAsciiCompare.QueryFlag() || FlagLineNumber.QueryFlag() ) ) {
+
+ psmsg->Set( MSG_FC_INCOMPATIBLE_SWITCHES );
+ psmsg->Display( "" );
+
+ return( FALSE );
+ }
+
+ if( !InFile1.IsValueSet() ||
+ !InFile2.IsValueSet() ) {
+
+ psmsg->Set( MSG_FC_INSUFFICIENT_FILES );
+ psmsg->Display( "" );
+
+ return( FALSE );
+ }
+
+ //
+ // Convert paths to upper case
+ //
+ TmpPath = InFile1.GetPath();
+ DbgPtrAssert( TmpPath );
+ AuxString = TmpPath->GetPathString();
+ DbgPtrAssert( AuxString );
+ if( !TmpString1.Initialize( AuxString ) ){
+ DbgAbort( "TmpString1.Initialize() failed \n" );
+ return( FALSE );
+ }
+ TmpString1.Strupr();
+
+ TmpPath = InFile2.GetPath();
+ DbgPtrAssert( TmpPath );
+ AuxString = TmpPath->GetPathString();
+ DbgPtrAssert( AuxString );
+ if( !TmpString2.Initialize( AuxString ) ) {
+ DbgAbort( "TmpString2.Initialize() failed \n" );
+ return( FALSE );
+ }
+ TmpString2.Strupr();
+
+
+ //
+ // Initialize _InputPath1 and _InputPAth2
+ //
+ if( ( _InputPath1 = NEW PATH ) == NULL ) {
+ DbgAbort( "Unable to allocate memory for string storage\n" );
+ return( FALSE );
+ }
+/*
+ if( !_InputPath1->Initialize( InFile1.GetPath(), FALSE ) ) {
+ DbgAbort( "Failed to initialize canonicolized version of the path 1\n" );
+ return( FALSE );
+ }
+*/
+ if( !_InputPath1->Initialize( &TmpString1, FALSE ) ) {
+ DbgAbort( "Failed to initialize canonicolized version of the path 1\n" );
+ return( FALSE );
+ }
+ if( ( _InputPath2 = NEW PATH ) == NULL ) {
+ DbgAbort( "Unable to allocate memory for string storage\n" );
+ return( FALSE );
+ }
+/*
+ if( !_InputPath2->Initialize( InFile2.GetPath(), FALSE ) ) {
+ DbgAbort( "Failed to initialize canonicolized version of the path 1\n" );
+ return( FALSE );
+ }
+*/
+ if( !_InputPath2->Initialize( &TmpString2, FALSE ) ) {
+ DbgAbort( "Failed to initialize canonicolized version of the path 1\n" );
+ return( FALSE );
+ }
+
+ if( !FlagBinaryCompare.QueryFlag() &&
+ !FlagAsciiCompare.QueryFlag() ) {
+
+ PWSTRING pString;
+ PSUB_STRING pExtention;
+ USHORT idx;
+
+ if( ( pExtention = _InputPath1->QueryExt() ) != NULL ) {
+
+ pString = NEW WSTRING;
+ idx = 0;
+ while( Extentions[ idx ] != NULL ) {
+ pString->Initialize( Extentions[ idx ] );
+ if( !pString->Stricmp( pExtention ) ) {
+ _Mode = TRUE;
+ break;
+ }
+ idx++;
+ }
+ DELETE( pString );
+ DELETE( pExtention );
+ }
+
+ } else if( FlagBinaryCompare.QueryFlag() ) {
+ _Mode = TRUE;
+ }
+
+ //
+ // Retrieve the values of the rest of the flags...
+ //
+ _Abbreviate = FlagAbbreviate.QueryFlag();
+ _CaseInsensitive = FlagCaseInsensitive.QueryFlag();
+ _Compression = FlagCompression.QueryFlag();
+ _Expansion = FlagExpansion.QueryFlag();
+ _LineNumber = FlagLineNumber.QueryFlag();
+
+
+ return( TRUE );
+}
+
+
+
+VOID
+FC::DoCompare(
+ )
+/*++
+
+Routine Description:
+
+ Perform the comparison of the files.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+
+{
+ FSN_FILTER Filter;
+ PARRAY pNodeArray = NULL;
+ PITERATOR pIterator = NULL;
+ PDYNAMIC_SUB_STRING pTmp = NULL;
+ PFSN_DIRECTORY pDirectory = NULL;
+ PATH CanonPath1;
+ PATH CanonPath2;
+ PPATH AuxPath1;
+ PPATH AuxPath2;
+ PDYNAMIC_SUB_STRING Name;
+ PDYNAMIC_SUB_STRING Prefix;
+
+
+ CanonPath1.Initialize( _InputPath1, TRUE );
+ CanonPath2.Initialize( _InputPath2, TRUE );
+
+ //
+ // Test if the first path name contains any wildcards. If it does,
+ // the program must initialize an array of FSN_NODES (for multiple
+ // files...
+ //
+ if( CanonPath1.HasWildCard() ) {
+ PPATH pTmpPath;
+ //
+ // Get a directory based on what the user specified for File 1
+ //
+ if( ( pTmpPath = CanonPath1.QueryFullPath() ) == NULL ) {
+ DbgAbort( "Unable to grab the Prefix from the input path...\n" );
+ return;
+ }
+ pTmpPath->TruncateBase();
+ if( ( pDirectory = SYSTEM::QueryDirectory( pTmpPath ) ) != NULL ) {
+ //
+ // Create an FSN_FILTER so we can use the directory to create an
+ // array of FSN_NODES
+ Filter.Initialize();
+
+ pTmp = CanonPath1.QueryName();
+ Filter.SetFileName( pTmp );
+ DELETE( pTmp );
+ Filter.SetAttributes( (FSN_ATTRIBUTE)0, // ALL
+ FSN_ATTRIBUTE_FILES, // ANY
+ FSN_ATTRIBUTE_DIRECTORY ); // NONE
+ pNodeArray = pDirectory->QueryFsnodeArray( &Filter );
+ pIterator = pNodeArray->QueryIterator();
+ DELETE( pDirectory );
+
+ _File1 = (FSN_FILE *)pIterator->GetNext();
+ } else {
+ _File1 = NULL;
+ }
+ DELETE( pTmpPath );
+ } else {
+ _File1 = SYSTEM::QueryFile( &CanonPath1 );
+ }
+
+ if( _File1 == NULL ) {
+ psmsg->Set( MSG_FC_FILES_NOT_FOUND );
+ psmsg->Display( "%W", _InputPath1->GetPathString() );
+ DELETE( pIterator );
+ DELETE( pNodeArray);
+ return;
+ }
+
+ do {
+
+ //
+ // Replace the input path filename with what is to be opened...
+ //
+ pTmp = _File1->GetPath()->QueryName();
+ _InputPath1->SetName( pTmp );
+ DELETE( pTmp );
+
+
+ // Determine if filename 2 contains any wildcards...
+ if( CanonPath2.HasWildCard() ) {
+ // ...if it does, expand them...
+ PPATH pExpanded;
+
+ pExpanded = CanonPath2.QueryWCExpansion( (PATH *)_File1->GetPath() );
+ if( pExpanded == NULL ) {
+ psmsg->Set( MSG_FC_CANT_EXPAND_TO_MATCH );
+ psmsg->Display( "%W%W", _InputPath1->GetPathString(), _InputPath2->GetPathString() );
+ DELETE( _File1 );
+ DELETE( pIterator );
+ DELETE( pNodeArray);
+ return;
+ }
+
+ //
+ // Place the expanded name in the input path...
+ //
+ pTmp = pExpanded->QueryName();
+ _InputPath2->SetName( pTmp );
+ DELETE( pTmp );
+
+ psmsg->Set( MSG_FC_COMPARING_FILES );
+ psmsg->Display( "%W%W", _InputPath1->GetPathString(),
+ _InputPath2->GetPathString() );
+ _File2 = SYSTEM::QueryFile( pExpanded );
+ DELETE( pExpanded );
+ } else {
+ psmsg->Set( MSG_FC_COMPARING_FILES );
+ psmsg->Display( "%W%W", _InputPath1->GetPathString(),
+ _InputPath2->GetPathString()
+ );
+ _File2 = SYSTEM::QueryFile( &CanonPath2 );
+ }
+
+ if( _File2 == NULL ) {
+ psmsg->Set( MSG_FC_UNABLE_TO_OPEN );
+ psmsg->Display( "%W", _InputPath2->GetPathString() );
+ DELETE( _File1 );
+ if( !CanonPath1.HasWildCard() ) {
+ break;
+ }
+ continue;
+ }
+
+
+ //
+ // Open the streams...
+ //
+ if( ( _FileStream1 = (FILE_STREAM *)_File1->QueryStream( READ_ACCESS ) ) == NULL ) {
+ psmsg->Set( MSG_FC_CANT_CREATE_STREAM );
+ psmsg->Display( "%W", _InputPath1->GetPathString() );
+ DELETE( _File1 );
+ DELETE( _File2 );
+ if( !CanonPath1.HasWildCard() ) {
+ break;
+ }
+ continue;
+ }
+ if( ( _FileStream2 = (FILE_STREAM *)_File2->QueryStream( READ_ACCESS ) ) == NULL ) {
+ psmsg->Set( MSG_FC_CANT_CREATE_STREAM );
+ psmsg->Display( "%W", _InputPath2->GetPathString() );
+ DELETE( _FileStream1 );
+ DELETE( _File1 );
+ DELETE( _File2 );
+ if( !CanonPath1.HasWildCard() ) {
+ break;
+ }
+ continue;
+ }
+
+ //
+ // Prepare the strings that contain the file names.
+ // These strings will be used by Dump()
+ //
+
+ AuxPath1 = NEW( PATH );
+ DbgPtrAssert( AuxPath1 );
+ Prefix = _InputPath1->QueryPrefix();
+ if( Prefix != NULL ) {
+ if( !AuxPath1->Initialize( Prefix ) ) {
+ DbgAbort( "AuxPath1->Initialize( Prefix ) failed \n" );
+ DELETE( AuxPath1 );
+ DELETE( Prefix );
+ return;
+ }
+ Name = _File1->QueryName();
+ DbgPtrAssert( Name );
+ if( !AuxPath1->AppendBase( Name ) ) {
+ DbgAbort( "AuxPath1->AppendBase() failed \n" );
+ DELETE( AuxPath1 );
+ DELETE( Name );
+ return;
+ }
+ } else {
+ Name = _File1->QueryName();
+ DbgPtrAssert( Name );
+ if( !AuxPath1->Initialize( Name ) ) {
+ DbgAbort( "AuxPath1->Initialize( Name ) failed \n" );
+ DELETE( AuxPath1 );
+ DELETE( Name );
+ return;
+ }
+ }
+ DELETE( Name );
+ DELETE( Prefix );
+ _FileName1 = AuxPath1->GetPathString();
+ DbgPtrAssert( _FileName1 );
+
+ AuxPath2 = NEW( PATH );
+ DbgPtrAssert( AuxPath2 );
+ Prefix = _InputPath2->QueryPrefix();
+ if( Prefix != NULL ) {
+ if( !AuxPath2->Initialize( Prefix ) ) {
+ DbgAbort( "AuxPath2->Initialize( Prefix ) failed \n" );
+ DELETE( AuxPath2 );
+ DELETE( Prefix );
+ return;
+ }
+ Name = _File2->QueryName();
+ DbgPtrAssert( Name );
+ if( !AuxPath2->AppendBase( Name ) ) {
+ DbgAbort( "AuxPath2->AppendBase() failed \n" );
+ DELETE( AuxPath2 );
+ DELETE( Name );
+ return;
+ }
+ } else {
+ Name = _File2->QueryName();
+ DbgPtrAssert( Name );
+ if( !AuxPath2->Initialize( Name ) ) {
+ DbgAbort( "AuxPath2->Initialize( Name ) failed \n" );
+ DELETE( AuxPath2 );
+ DELETE( Name );
+ return;
+ }
+ }
+ DELETE( Name );
+ DELETE( Prefix );
+ _FileName2 = AuxPath2->GetPathString();
+ DbgPtrAssert( _FileName2 );
+
+
+ // Do comparison of data...
+ if( !_Mode ) {
+ DoAsciiCompare();
+ } else {
+ DoBinaryCompare();
+ }
+
+ DELETE( AuxPath1 );
+ DELETE( AuxPath2 );
+
+ // Close both streams now, since we are done with them...
+ DELETE( _FileStream1 );
+ DELETE( _FileStream2 );
+ DELETE( _File1 );
+ DELETE( _File2 );
+
+ if( !CanonPath1.HasWildCard() ) {
+ break;
+ }
+
+ } while( ( _File1 = (FSN_FILE *)pIterator->GetNext() ) != NULL );
+
+ DELETE( pIterator );
+ DELETE( pNodeArray);
+
+ return;
+}
+
+
+VOID
+FC::DoAsciiCompare(
+ )
+/*++
+
+Routine Description:
+
+ Does the actual ascii based comparison between the ascii based files
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+{
+
+ ARRAY LineBuffer1, LineBuffer2;
+ ULONG LineNum1, LineNum2;
+ ULONG SyncLen, BufSize;
+ ULONG Src, Dest;
+ BOOLEAN fBuffDiff, fSync, fSame;
+
+ ULONG Index;
+ ULONG Count;
+
+ ULONG xc, yc, xp, yp;
+ BOOLEAN EndBuffer1;
+ BOOLEAN EndBuffer2;
+ ULONG Count1;
+ ULONG Count2;
+ ULONG RealSyncLen;
+
+ ARRAY EmptyStringArray1;
+ ARRAY EmptyStringArray2;
+
+ //
+ // Set the current line number of each buffer to 0
+ //
+ LineNum1 = LineNum2 = 0;
+
+ //
+ // Set the value for the number of lines required to consider the
+ // files back in sync...
+ //
+ SyncLen =
+ _LongMatch.IsValueSet() ? _LongMatch.QueryLong() : DEFAULT_MATCH;
+ //
+ // Initialize the buffer size
+ //
+ BufSize =
+ _LongBufferSize.IsValueSet() ? _LongBufferSize.QueryLong() : DEFAULT_LINE_BUFFER;
+
+ //
+ // For compatibility purpose, display that no differences were found
+ //
+ if( BufSize == 0 ) {
+ psmsg->Set( MSG_FC_NO_DIFFERENCES );
+ psmsg->Display( " " );
+ return;
+ }
+
+ //
+ // Initialize arrays of empty strings
+ //
+
+ if( !EmptyStringArray1.Initialize( BufSize, 0 ) ||
+ !EmptyStringArray2.Initialize( BufSize, 0 )) {
+ DbgAbort( "Unable to initialize EmptyStringArrays" );
+ return;
+ }
+
+ if( !FillEmptyStringArray( &EmptyStringArray1 ) ) {
+ DbgAbort( "Unable to fill EmptyStringArray1" );
+ return;
+ }
+ if( !FillEmptyStringArray( &EmptyStringArray2 ) ) {
+ DbgAbort( "Unable to fill EmptyStringArray2" );
+ return;
+ }
+
+ //
+ // Initialize the array of lines
+ //
+ if( !LineBuffer1.Initialize( BufSize, 0 ) ||
+ !LineBuffer2.Initialize( BufSize, 0 ) ) {
+ DbgAbort( "Unable to initialize line buffers!" );
+ return;
+ }
+ //
+ // Assume initially that the files are equal
+ //
+ fSame = TRUE;
+
+ for(;;) {
+ //
+ // Fill the buffers
+ //
+ LineNum1 += FillBuf( &LineBuffer1, _FileStream1, &EmptyStringArray1 );
+ LineNum2 += FillBuf( &LineBuffer2, _FileStream2, &EmptyStringArray2 );
+ if( ( LineBuffer1.QueryMemberCount() == 0 ) &&
+ ( LineBuffer2.QueryMemberCount() == 0 ) ) {
+ //
+ // Buffers are empty and there are no more lines to read
+ // from the files.
+ //
+ if( fSame ){
+ //
+ // If no difference was found between the two files,
+ // display message indicating that the files are equal
+ //
+ psmsg->Set( MSG_FC_NO_DIFFERENCES );
+ psmsg->Display( " " );
+ }
+ return;
+ }
+
+ //
+ // At least one of the buffers is not empty.
+ // Assume that the contents of the two buffers are equal, and find
+ // out the position in the buffer where the difference start.
+ //
+ fBuffDiff = FALSE;
+ Count = min( LineBuffer1.QueryMemberCount(), LineBuffer2.QueryMemberCount() );
+ for( Index = 0; Index < Count; Index++ ) {
+ if( !CompareArraySeg( &LineBuffer1, Index, &LineBuffer2, Index, 1 ) ) {
+ fSame = FALSE; // Files are not equal
+ fBuffDiff = TRUE; // Buffers are not equal
+ break;
+ }
+ }
+ if( fBuffDiff ) {
+ //
+ // if a difference was found, adjust 'Count', so that the last
+ // line that matches is kept in the buffer.
+ // No adjustment is made if the buffers are the same, so that
+ // all lines are removed from the buffer
+ // (Is this correct? Dos has the same behavior)
+ //
+ //
+ Index = ( Index )? ( Index-1 ) : 0;
+ }
+
+ //
+ // Remove the first (index+1) lines from the buffers
+ //
+ ShiftArray( &LineBuffer1, Index, &EmptyStringArray1 );
+ ShiftArray( &LineBuffer2, Index, &EmptyStringArray2 );
+
+ //
+ // If both buffers are empty, try to refill them
+ //
+ if( ( LineBuffer1.QueryMemberCount() == 0 ) &&
+ ( LineBuffer2.QueryMemberCount() == 0 ) ) {
+ continue;
+ }
+
+ //
+ // If at least one of the buffers is not empty try to refill
+ // fill the buffers
+ //
+ LineNum1 += FillBuf( &LineBuffer1, _FileStream1, &EmptyStringArray1 );
+ LineNum2 += FillBuf( &LineBuffer2, _FileStream2, &EmptyStringArray2 );
+
+
+ //
+ // Attempt to synchronize the two buffers
+ //
+
+ EndBuffer1 = FALSE;
+ EndBuffer2 = FALSE;
+ xc = 1; // The first element in each buffer are either
+ xp = 1; // different (and don't need to be compared ), or
+ yc = 1; // are the last elements that match before the
+ yp = 1; // differeces (and don't need to be compared either
+ // For this reason we start the indeces with '1'
+ // instead of '0'
+ fSync = FALSE;
+ Count1 = LineBuffer1.QueryMemberCount();
+ Count2 = LineBuffer2.QueryMemberCount();
+
+ while( !fSync ) {
+ RealSyncLen = min( Count1 - xc, Count2 - yp );
+ RealSyncLen = min( RealSyncLen, SyncLen );
+ if( CompareArraySeg( &LineBuffer1, xc, &LineBuffer2, yp, RealSyncLen ) ){
+ //
+ // Dump differences
+ //
+ Dump( &LineBuffer1, xc + 1, LineNum1, TRUE );
+ Dump( &LineBuffer2, yp + 1, LineNum2, FALSE );
+ psmsg->Set( MSG_FC_DUMP_END );
+ psmsg->Display( " " );
+
+ //
+ // Remove elements
+ //
+ ShiftArray( &LineBuffer1, xc, &EmptyStringArray1 );
+ ShiftArray( &LineBuffer2, yp, &EmptyStringArray2 );
+ fSync = TRUE;
+ }
+ if( !fSync ) {
+ RealSyncLen = min( Count1 - xp, Count2 - yc );
+ RealSyncLen = min( RealSyncLen, SyncLen );
+ if( CompareArraySeg( &LineBuffer1, xp, &LineBuffer2, yc, RealSyncLen ) ){
+ //
+ // Dump differences
+ //
+ Dump( &LineBuffer1, xp + 1, LineNum1, TRUE );
+ Dump( &LineBuffer2, yc + 1, LineNum2, FALSE );
+ psmsg->Set( MSG_FC_DUMP_END );
+ psmsg->Display( " " );
+
+ //
+ // Remove elements
+ //
+ ShiftArray( &LineBuffer1, xp, &EmptyStringArray1 );
+ ShiftArray( &LineBuffer2, yc, &EmptyStringArray2 );
+
+ fSync = TRUE;
+ }
+ }
+ if( !fSync ) {
+ //
+ // Adjust indexes
+ //
+ if( ++xp > xc ) {
+ xp = 1;
+ if( ++xc >= Count1 ) {
+ xc = Count1;
+ EndBuffer1 = TRUE;
+ }
+ }
+ if( ++yp > yc ) {
+ yp = 1;
+ if( ++yc >= Count2 ) {
+ yc = Count2;
+ EndBuffer2 = TRUE;
+ }
+ }
+ if( EndBuffer1 && EndBuffer2 ) {
+ if( ( LineBuffer1.QueryMemberCount() >= LineBuffer1.QueryCapacity() ) ||
+ ( LineBuffer2.QueryMemberCount() >= LineBuffer2.QueryCapacity() ) ) {
+
+ psmsg->Set( MSG_FC_RESYNC_FAILED );
+ psmsg->Display( " " );
+ }
+ //
+ // Dump buffers
+ //
+ Dump( &LineBuffer1, Count1, LineNum1, TRUE );
+ Dump( &LineBuffer2, Count2, LineNum2, FALSE );
+ psmsg->Set( MSG_FC_DUMP_END );
+ psmsg->Display( " " );
+
+ //
+ // Remove elements from buffer
+ //
+ ShiftArray( &LineBuffer1, Count1, &EmptyStringArray1 );
+ ShiftArray( &LineBuffer2, Count2, &EmptyStringArray2 );
+ return;
+ }
+
+ }
+ } // while( !fSync ) loop
+ } // for(;;) loop
+}
+
+
+
+
+
+
+
+
+
+
+VOID
+FC::DoBinaryCompare(
+ )
+/*++
+
+Routine Description:
+
+ Does the actual binary compare between the two streams
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+ The binary compare simply does a byte by byte comparison of the two
+ files and reports all differences, as well as the offset into the
+ file... ...no line buffer is required for this comparision...
+
+--*/
+{
+ ULONG FileOffset = 0;
+ BYTE Byte1, Byte2;
+ STR Buffer[OFFSET_WIDTH+1]; // A buffer to store the characters from the converted offset...
+ WSTRING ZeroString;
+ BOOLEAN fDiff;
+
+ fDiff = FALSE;
+ for( ;; FileOffset++ ) {
+ if( !_FileStream1->ReadByte( &Byte1 ) ) {
+ // Assume EOF of File 1
+ if( !_FileStream2->ReadByte( &Byte2 ) ) {
+ // Assume EOF of File 2
+ break;
+ } else {
+ fDiff = TRUE;
+ psmsg->Set( MSG_FC_FILES_DIFFERENT_LENGTH );
+ psmsg->Display( "%W%W", ( _File2->GetPath() )->GetPathString(),
+ ( _File1->GetPath() )->GetPathString() );
+ break;
+ }
+ } else {
+ if( !_FileStream2->ReadByte( &Byte2 ) ) {
+ // Assume EOF of File 2
+ fDiff = TRUE;
+ psmsg->Set( MSG_FC_FILES_DIFFERENT_LENGTH );
+ psmsg->Display( "%W%W", ( _File1->GetPath() )->GetPathString(),
+ ( _File2->GetPath() )->GetPathString() );
+ break;
+ }
+ }
+
+ // Now compare the bytes...if they are different, report the
+ // difference...
+ if( Byte1 != Byte2 ) {
+ fDiff = TRUE;
+ // Convert the current offset to a hex string...max length will be 8 chars...
+ sprintf( Buffer, "%08lx %02x %02x", FileOffset, Byte1, Byte2 );
+ ZeroString.Initialize( Buffer );
+
+ psmsg->Set( MSG_FC_DATA );
+ psmsg->Display( "%W", &ZeroString );
+ }
+ }
+ //
+ // Check if any differences were found in the files
+ //
+ if( !fDiff ) {
+ psmsg->Set( MSG_FC_NO_DIFFERENCES );
+ psmsg->Display( " " );
+ }
+
+ return;
+}
+
+
+ULONG
+FC::FillBuf(
+ PARRAY pArray,
+ PFILE_STREAM pStream,
+ PARRAY EmptyStringArray
+ )
+/*++
+
+Routine Description:
+
+ Attempts to fill an array of strings to capacity (therefore, a
+ non-growing array) from the given stream.
+
+Arguments:
+
+ pArray - A pointer to the array to be filled.
+ pStream - A pointer to the stream which is to be read.
+ EmptyStringArray - Pointer to the an array that contains empty strings.
+
+Return Value:
+
+ The number of lines read from the stream.
+
+Notes:
+
+--*/
+{
+
+ WSTRING Delim;
+ PWSTRING String;
+ WSTRING Spaces;
+ WCHAR Wchar;
+ ULONG Count = 0;
+ CHNUM idx;
+
+ Delim.Initialize( "\n\r" );
+ Spaces.Initialize( " " ); // BUGBUG - If TABSTOP changes,
+ // the length of this string must
+ // change as well
+
+ while( pArray->QueryMemberCount() < pArray->QueryCapacity() ) {
+ if( pStream->IsAtEnd() ) {
+ break;
+ }
+/*
+ if( ( String = NEW WSTRING ) == NULL ) {
+ DbgAbort( "String = NEW WSTRING failed!\n" );
+ }
+ if( !String->Initialize( "" ) ) {
+ DbgAbort( "String->Initialize() failed!" );
+ }
+*/
+
+ String = ( PWSTRING )EmptyStringArray->RemoveAt( 0 );
+ DbgPtrAssert( String );
+
+ if( !pStream->ReadLine( String ) ) {
+ DbgAbort( "Unable to read line but file isn't empty...\n" );
+ }
+
+ if( !_Expansion ) {
+ //
+ // Expand tabs to space characters...
+ //
+ Wchar = '\t'; // the tab character...
+ idx = 0;
+ while( ( idx = String->Strchr( Wchar, idx ) ) != INVALID_CHNUM ) {
+ String->Replace( &Spaces, idx, 1, 0, TABSTOP - ( idx % TABSTOP ) );
+ }
+ }
+ pArray->Put( String );
+ Count++;
+ }
+
+ return( Count );
+}
+
+
+BOOLEAN
+FC::CompareArraySeg(
+ PARRAY pArrayX,
+ ULONG idxX,
+ PARRAY pArrayY,
+ ULONG idxY,
+ ULONG Len
+ )
+/*++
+
+Routine Description:
+
+ Compares two arrays of strings from a specified index for a specified
+ number of elements.
+
+Arguments:
+
+ pArrayX - the first array to compare.
+ idxX - the index into array X where the compare starts.
+ pArrayY - the second array to compare.
+ idxY - the index into array Y where the compare starts.
+ Len - the number of elements of the arrays to compare.
+
+Return Value:
+
+ TRUE if the array segments are the same.
+
+Notes:
+
+ This compare function uses flags from the FC:: class to qualify which
+ method it uses to do the actual comparison.
+
+--*/
+{
+ PWSTRING StrX;
+ PWSTRING StrY;
+ WSTRING Delim;
+ CHNUM BeginX, EndX, BeginY, EndY;
+
+ if( ( Len == 0 ) ||
+ ( ( idxX + Len ) > pArrayX->QueryMemberCount() ) ||
+ ( ( idxY + Len ) > pArrayY->QueryMemberCount() ) ) {
+ return( FALSE );
+ }
+ while( Len > 0 ) {
+ StrX = (WSTRING *)pArrayX->GetAt( idxX );
+ StrY = (WSTRING *)pArrayY->GetAt( idxY );
+ if( !_Compression ) {
+ // If whitespace isn't being ignored, then the length of the
+ // strings will instantly tell whether they are different...
+ if( StrX->QueryChCount() != StrY->QueryChCount() ) {
+ return( FALSE );
+ }
+ if( _CaseInsensitive ) {
+ if( StrX->StringCompare( StrY, CF_IGNORECASE ) ) {
+ return( FALSE );
+ }
+ } else {
+ if( StrX->StringCompare( StrY, 0 ) ) {
+ return( FALSE );
+ }
+ }
+ } else {
+ Delim.Initialize( " \n\r\t" );
+ PSUB_STRING SubStrX;
+ PSUB_STRING SubStrY;
+
+ EndX = EndY = 0;
+
+ for(;;) {
+ if( EndX != INVALID_CHNUM ) {
+ BeginX = StrX->Strspn( &Delim, EndX );
+ } else {
+ BeginX = INVALID_CHNUM;
+ }
+ if( EndY != INVALID_CHNUM ) {
+ BeginY = StrY->Strspn( &Delim, EndY );
+ } else {
+ BeginY = INVALID_CHNUM;
+ }
+ if( BeginX == INVALID_CHNUM ) {
+ if( BeginY == INVALID_CHNUM ) {
+ break;
+ } else {
+ return( FALSE );
+ }
+ } else {
+ if( BeginY == INVALID_CHNUM ) {
+ return( FALSE );
+ }
+ }
+ EndX = StrX->Strcspn( &Delim, BeginX );
+ EndY = StrY->Strcspn( &Delim, BeginY );
+
+ if( EndX == INVALID_CHNUM ) {
+ SubStrX = StrX->QuerySubString( BeginX );
+ } else {
+ SubStrX = StrX->QuerySubString( BeginX, EndX - BeginX );
+ }
+ if( EndY == INVALID_CHNUM ) {
+ SubStrY = StrY->QuerySubString( BeginY );
+ } else {
+ SubStrY = StrY->QuerySubString( BeginY, EndY - BeginY );
+ }
+ if( SubStrX->QueryChCount() != SubStrY->QueryChCount() ) {
+ DELETE( SubStrX );
+ DELETE( SubStrY );
+ return( FALSE );
+ }
+ if( _CaseInsensitive ) {
+ if( SubStrX->Stricmp( SubStrY ) ) {
+ DELETE( SubStrX );
+ DELETE( SubStrY );
+ return( FALSE );
+ }
+ } else {
+ if( SubStrX->Strcmp( SubStrY ) ) {
+ DELETE( SubStrX );
+ DELETE( SubStrY );
+ return( FALSE );
+ }
+ }
+ DELETE( SubStrX );
+ DELETE( SubStrY );
+ }
+ }
+ Len--;
+ idxX++;
+ idxY++;
+ }
+ return( TRUE );
+}
+
+
+BOOLEAN
+FC::ShiftArray(
+ PARRAY pArray,
+ ULONG idx,
+ PARRAY EmptyStringArray
+ )
+/*++
+
+Routine Description:
+
+ Remove idx elements from the array, starting with the the first
+ element. The remaining elements in the array are moved to the
+ begining of the array.
+
+
+Arguments:
+
+ pArray - the array on which the ripple copy is carried out.
+ idx - number of elements to remove
+ EmptyStringArray - Pointer to the array that will store the strings
+ removed from pArray.
+
+Return Value:
+
+ TRUE if the passed index is less or equal than the number of members
+ in the array.
+
+Notes:
+
+--*/
+{
+ PWSTRING pTmp;
+ ULONG Count;
+
+
+ //
+ // Check the bounds on the index...
+ //
+ if( idx > pArray->QueryMemberCount() ) {
+ DbgAbort( "Invalid index idx \n" );
+ return( FALSE );
+ }
+ if( idx == 0) {
+ return( TRUE );
+ }
+ //
+ // Remove the first 'idx' elements from the array.
+ // After each element is removed, the remaining ones are automatically
+ // shifted to the top (RemoveAt() does it).
+ //
+ for( Count = 0; Count < idx; Count++ ) {
+ pTmp = (WSTRING *)pArray->RemoveAt( 0 );
+ DbgPtrAssert( pTmp );
+ EmptyStringArray->Put( pTmp );
+
+// DELETE( pTmp );
+
+ }
+ return( TRUE );
+}
+
+
+VOID
+FC::Dump(
+ PARRAY pArray,
+ ULONG idx,
+ ULONG LineCount,
+ BOOLEAN fFileIndicator
+ )
+/*++
+
+Routine Description:
+
+ Display the contents of an array to the screen using the message
+ class (and the global pointer to the message class for stdin/stdout).
+ It displays 'idx' elements of the array, starting at position 0.
+
+Arguments:
+
+ pArray - A pointer to the array that is to be dumped.
+ idx - Numbers of elements to be displayed.
+ LineCount - The current line count.
+ fFileIndicator - Indicates which file owns the array - TRUE is File 1.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+{
+ USHORT i;
+
+ // Correct the line count for output...
+ LineCount -= pArray->QueryMemberCount();
+
+ psmsg->Set( MSG_FC_OUTPUT_FILENAME );
+ if( fFileIndicator ) {
+// psmsg->Display( "%W", ( _File1->GetPath() )->GetPathString() );
+ psmsg->Display( "%W", _FileName1 );
+ } else {
+// psmsg->Display( "%W", ( _File2->GetPath() )->GetPathString() );
+ psmsg->Display( "%W", _FileName2 );
+ }
+ if( idx == 0 ) {
+ return;
+ }
+
+
+ if( _Abbreviate && ( idx > 2 ) ) {
+ //
+ // The output is abbreviated and there are more than two elements
+ // in the array.
+ //
+ // Print the first element
+ //
+ PrintSequenceOfLines( pArray, 0, 0, LineCount );
+
+ //
+ // Print the '...'
+ //
+ if( _LineNumber ) {
+ //
+ // print the shifted ...
+ //
+ psmsg->Set( MSG_FC_ABBREVIATE_SYMBOL_SHIFTED );
+ psmsg->Display( " " );
+
+ } else {
+ //
+ // print the non-shifted ...
+ //
+ psmsg->Set( MSG_FC_ABBREVIATE_SYMBOL );
+ psmsg->Display( " " );
+
+ }
+ LineCount += idx - 1; // Correct the linecount for the skipped lines
+ // Print the last element
+ //
+ PrintSequenceOfLines( pArray, idx, idx, LineCount );
+ } else {
+ //
+ // Print the first 'idx' elements in the array
+ //
+ PrintSequenceOfLines( pArray, 0, idx-1, LineCount );
+ }
+}
+
+
+
+VOID
+FC::PrintSequenceOfLines(
+ PARRAY pArray,
+ ULONG Start,
+ ULONG End,
+ ULONG LineCount
+ )
+
+/*++
+
+Routine Description:
+
+ Display the contents of an array to the screen using the message
+ class (and the global pointer to the message class for stdin/stdout).
+
+
+Arguments:
+
+ pArray - A pointer to the array that is to be dumped.
+ Start - Index of the first element to be displayed.
+ End - Index of the last element to be displayed.
+ LineCount - The line count of the first element to be displayed.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ ULONG i;
+
+ if( Start > End ) {
+ DbgAbort( "Invalid values for Start and End \n" );
+ return;
+ }
+ for( i = Start; i <= End; i++ ) {
+ if( _LineNumber ) {
+ LineCount;
+ psmsg->Set( MSG_FC_NUMBERED_DATA );
+ psmsg->Display( "%5d %W", LineCount, (PWSTRING)pArray->GetAt( i ) );
+ } else {
+ psmsg->Set( MSG_FC_DATA );
+ psmsg->Display( "%W", (PWSTRING)pArray->GetAt( i ) );
+ }
+ }
+}
+
+
+BOOLEAN
+FC::FillEmptyStringArray(
+ PARRAY Array
+ )
+
+/*++
+
+Routine Description:
+
+ Fill an array with WSTRINGS initialized with "".
+ It assumes that the array is empty and that it was previously initialized.
+
+
+Arguments:
+
+ Array - A pointer to an empty and initialized array.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+Notes:
+
+--*/
+
+{
+ PWSTRING String;
+
+
+ while( Array->QueryMemberCount() < Array->QueryCapacity() ) {
+ if( ( String = NEW WSTRING ) == NULL ) {
+ DbgAbort( "String = NEW WSTRING failed!\n" );
+ }
+ if( !String->Initialize( "" ) ) {
+ DbgAbort( "String->Initialize() failed!" );
+ return( FALSE );
+ }
+ Array->Put( String );
+ }
+ return( TRUE );
+}
+
+
+
+
+
+
+main(
+ )
+{
+
+ DEFINE_CLASS_DESCRIPTOR( FC );
+
+
+ {
+ FC Fc;
+
+ perrstk = NEW ERRSTACK;
+ psmsg = NEW STREAM_MESSAGE;
+
+ // Initialize the stream message for standard input, stdout
+ psmsg->Initialize( Get_Standard_Output_Stream(),
+ Get_Standard_Input_Stream() );
+
+ if( !SYSTEM::IsCorrectVersion() ) {
+ psmsg->Set( MSG_FC_INCORRECT_VERSION );
+ psmsg->Display( "" );
+ Fc.Destruct();
+ return( 0 );
+ }
+ if( !( Fc.Initialize() ) ) {
+ //
+ // The Command line didn't initialize properly, die nicely
+ // without printing any error messages - Main doesn't know
+ // why the Initialization failed...
+ //
+ // What has to be deleted by hand, or can everything be removed
+ // by the destructor for the FC class?
+ //
+ Fc.Destruct();
+ return( 1 );
+ }
+
+
+ // Do file comparison stuff...
+ Fc.DoCompare();
+ Fc.Destruct();
+ return( 0 );
+ }
+}
diff --git a/private/utils/fc.old/fc.hxx b/private/utils/fc.old/fc.hxx
new file mode 100644
index 000000000..7f83923da
--- /dev/null
+++ b/private/utils/fc.old/fc.hxx
@@ -0,0 +1,165 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ fc.hxx
+
+Abstract:
+
+Author:
+
+ Barry J. Gilhuly
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+
+#if !defined( _FILE_COMPARE_ )
+
+#define _FILE_COMPARE_
+
+
+#define DEFAULT_LINE_BUFFER 100 // Size of line buffer...
+#define DEFAULT_MATCH 2 // Number of lines to be equal before files in sinc
+
+//
+// OFFSET_WIDTH is used for binary comparisons and refers to the width
+// used to print the offset into the files where they differ (8 chars)
+// followed by a space (1 char) followed by the byte in the first file
+// (2 chars) followed by a space (1 char) followed by the byte in the
+// second file (2 chars), for a total of...
+//
+
+#define OFFSET_WIDTH 14
+#define TABSTOP 8 // The tab stop width - don't change this field unless the Spaces string
+ // is changed as well.
+
+#define FORCENONZERO( v, d ) ( ( v ) ? v : d )
+
+STR *Extentions[] = { "EXE",
+ "OBJ",
+ "LIB",
+ "COM",
+ "BIN",
+ "SYS",
+ NULL
+ };
+
+#include "object.hxx"
+#include "keyboard.hxx"
+#include "program.hxx"
+
+DECLARE_CLASS( FC );
+
+class FC : public PROGRAM {
+
+ public:
+
+
+ DECLARE_CONSTRUCTOR( FC );
+
+
+ NONVIRTUAL
+ VOID
+ Destruct(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ );
+
+ NONVIRTUAL
+ VOID
+ DoCompare(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FillEmptyStringArray(
+ IN OUT PARRAY Array
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ DoAsciiCompare(
+ );
+
+ NONVIRTUAL
+ VOID
+ DoBinaryCompare(
+ );
+
+ NONVIRTUAL
+ ULONG
+ FillBuf(
+ PARRAY pArray,
+ PFILE_STREAM pStream,
+ PARRAY EmptyStringArray
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CompareArraySeg(
+ PARRAY pArrayX,
+ ULONG idxX,
+ PARRAY pArrayY,
+ ULONG idxY,
+ ULONG Len
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ShiftArray(
+ PARRAY pArray,
+ ULONG idx,
+ PARRAY EmptyStringArray
+ );
+
+ NONVIRTUAL
+ VOID
+ Dump(
+ PARRAY pArray,
+ ULONG idx,
+ ULONG LineCount,
+ BOOLEAN fFileIndicator
+ );
+
+ NONVIRTUAL
+ VOID
+ PrintSequenceOfLines(
+ PARRAY pArray,
+ ULONG Start,
+ ULONG End,
+ ULONG LineCount
+ );
+
+ LONG_ARGUMENT _LongBufferSize;
+ LONG_ARGUMENT _LongMatch;
+
+ // Other variables - non arguments
+ BOOLEAN _Abbreviate;
+ BOOLEAN _CaseInsensitive;
+ BOOLEAN _Compression;
+ BOOLEAN _Expansion;
+ BOOLEAN _LineNumber;
+ BOOLEAN _Mode;
+ PPATH _InputPath1;
+ PPATH _InputPath2;
+ PFSN_FILE _File1;
+ PFSN_FILE _File2;
+ PFILE_STREAM _FileStream1;
+ PFILE_STREAM _FileStream2;
+ PCWSTRING _FileName1;
+ PCWSTRING _FileName2;
+};
+
+
+#endif // _FILE_COMPARE_
diff --git a/private/utils/fc.old/makefile b/private/utils/fc.old/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/fc.old/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/fc.old/sources b/private/utils/fc.old/sources
new file mode 100644
index 000000000..fe7d24d6a
--- /dev/null
+++ b/private/utils/fc.old/sources
@@ -0,0 +1,56 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=utils
+MINORCOMP=fc
+
+TARGETNAME=fc
+TARGETPATH=obj
+TARGETTYPE=UMAPPL_NOLIB
+
+SOURCES=
+
+INCLUDES=..\ulib\inc;\nt\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DNOMINMAX -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DNOMINMAX -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DNOMINMAX -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DNOMINMAX -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+CXXFLAGS=+d
+UMLIBS=..\ulib\src\obj\*\ulib.lib
+
+
+UMTYPE=console
+
+UMAPPL=fc
diff --git a/private/utils/fc/fc.cxx b/private/utils/fc/fc.cxx
new file mode 100644
index 000000000..391683d36
--- /dev/null
+++ b/private/utils/fc/fc.cxx
@@ -0,0 +1,1319 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ FC
+
+Abstract:
+
+ FC is a DOS-5 compatible file comparison utility
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 01-May-1991
+
+Notes:
+
+ This FC is a port of the DOS5 FC code. It has been slightly modified
+ to use some of the ULIB functionality (e.g. argument parsing), however
+ it does not make full use of the ULIB functionality (e.g. it uses
+ stdio.h functions for file handling).
+
+
+
+Revision History:
+
+--*/
+
+
+/****************************************************************************
+ File Compare
+
+ Fcom compares two files in either a line-by-line mode or in a strict
+ BYTE-by-BYTE mode.
+
+ The BYTE-by-BYTE mode is simple; merely read both files and print the
+ offsets where they differ and the contents.
+
+ The line compare mode attempts to isolate differences in ranges of lines.
+ Two buffers of lines are read and compared. No hashing of lines needs
+ to be done; hashing only speedily tells you when things are different,
+ not the same. Most files run through this are expected to be largely
+ the same. Thus, hashing buys nothing.
+
+
+***********************************************************************
+The algorithm that immediately follows does not work. There is an error
+somewhere in the range of lines 11 on. An alternative explanation follows.
+ KGS
+************************************************************************
+
+ [0] Fill buffers
+ [1] If both buffers are empty then
+ [1.1] Done
+ [2] Adjust buffers so 1st differing lines are at top.
+ [3] If buffers are empty then
+ [3.1] Goto [0]
+
+ This is the difficult part. We assume that there is a sequence of inserts,
+ deletes and replacements that will bring the buffers back into alignment.
+
+ [4] xd = yd = FALSE
+ [5] xc = yc = 1
+ [6] xp = yp = 1
+ [7] If buffer1[xc] and buffer2[yp] begin a "sync" range then
+ [7.1] Output lines 1 through xc-1 in buffer 1
+ [7.2] Output lines 1 through yp-1 in buffer 2
+ [7.3] Adjust buffer 1 so line xc is at beginning
+ [7.4] Adjust buffer 2 so line yp is at beginning
+ [7.5] Goto [0]
+ [8] If buffer1[xp] and buffer2[yc] begin a "sync" range then
+ [8.1] Output lines 1 through xp-1 in buffer 1
+ [8.2] Output lines 1 through yc-1 in buffer 2
+ [8.3] Adjust buffer 1 so line xp is at beginning
+ [8.4] Adjust buffer 2 so line yc is at beginning
+ [8.5] Goto [0]
+ [9] xp = xp + 1
+ [10] if xp > xc then
+ [10.1] xp = 1
+ [10.2] xc = xc + 1
+ [10.3] if xc > number of lines in buffer 1 then
+ [10.4] xc = number of lines
+ [10.5] xd = TRUE
+ [11] if yp > yc then
+ [11.1] yp = 1
+ [11.2] yc = yc + 1
+ [11.3] if yc > number of lines in buffer 2 then
+ [11.4] yc = number of lines
+ [11.5] yd = TRUE
+ [12] if not xd or not yd then
+ [12.1] goto [6]
+
+ At this point there is no possible match between the buffers. For
+ simplicity, we punt.
+
+ [13] Display error message.
+
+EXPLANATION 2
+
+ This is a variation of the Largest Common Subsequence problem. A
+ detailed explanation of this can be found on p 189 of Data Structures
+ and Algorithms by Aho Hopcroft and Ulman.
+
+ FC maintains two buffers within which it tries to find the Largest Common
+ Subsequence (The largest common subsequence is simply the pattern in
+ buffer1 that yields the most matches with the pattern in buffer2, or the
+ pattern in buffer2 that yields the most matches with the pattern in buffer1)
+
+ FC makes a simplifying assumption that the contents of one buffer can be
+ converted to the contents of the other buffer by deleting the lines that are
+ different between the two buffers.
+
+ Two indices into each buffer are maintained:
+
+ xc, yc == point to the last line that has been scanned up to now
+
+ xp, yp == point to the first line that has not been exhaustively
+ compared to lines 0 - #c in the other buffer.
+
+ FC now makes a second simplifying assumption:
+ It is unnecessary to do any calculations on lines that are equal.
+
+ Hence FC scans File1 and File two line by line until a difference is
+ encountered.
+
+ When a difference is encountered the two buffers are filled such that
+ the line containing the first difference heads the buffer. The following
+ exhaustive search algorithm is applied to find the first "sync" occurance.
+ (The below is simplified to use == for comparison. In practice more than
+ one line needs to match for a "sync" to be established).
+
+ FOR xc,yc = 1; xc,yx <= sizeof( BUFFERS ); xc++, yc++
+
+ FOR xp,yp = 1; xp,yp <= xc,yc; xp++, yp++
+
+ IF ( BUFFER1[xp] == BUFFER2[yc] )
+
+ Then the range of lines BUFFER1[ 1 ... xp ] and
+ BUFFER2[ 1 ... yc ] need to be deleted for the
+ two files to be equal. Therefore DISPLAY these
+ ranges, and begin scanning both files starting at
+ the matching lines.
+ FI
+
+ IF ( BUFFER1[yp] == BUFFER2[xc] )
+
+ Then the range of lines BUFFER2[ 1 ... yp ] and
+ BUFFER1[ 1 ... xc ] need to be deleted for the
+ two files to be equal. Therefore DISPLAY these
+ ranges, and begin scanning both files starting at
+ the matching lines.
+ FI
+ FOREND
+ FOREND
+
+ If a match is not found within the buffers, the message "RESYNC FAILED"
+ is issued and further comparison is aborted since there is no valid way
+ to find further matching lines.
+
+END EXPLANATION 2
+
+ Certain flags may be set to modify the behavior of the comparison:
+
+ -a abbreviated output. Rather than displaying all of the modified
+ ranges, just display the beginning, ... and the ending difference
+ -b compare the files in binary (or BYTE-by-BYTE) mode. This mode is
+ default on .EXE, .OBJ, .LIB, .COM, .BIN, and .SYS files
+ -c ignore case on compare (cmp = strcmpi instead of strcmp)
+ -l compare files in line-by-line mode
+ -lb n set the size of the internal line buffer to n lines from default
+ of 100
+ -u Files to be compared are UNICODE text files
+ -w ignore blank lines and white space (ignore len 0, use strcmps)
+ -t do not untabify (use fgets instead of fgetl)
+ -n output the line number also
+ -NNNN set the number of lines to resynchronize to n which defaults
+ to 2. Failure to have this value set correctly can result in
+ odd output:
+ file1: file2:
+ abcdefg abcdefg
+ aaaaaaa aaaaaab
+ aaaaaaa aaaaaaa
+ aaaaaaa aaaaaaa
+ abcdefg abcdefg
+
+ with default sync of 2 yields: with sync => 3 yields:
+
+ *****f1 *****f1
+ abcdefg abcdefg
+ aaaaaaa aaaaaaa
+ *****f2 aaaaaaa
+ abcdefg *****f2
+ aaaaaab abcdefg
+ aaaaaaa aaaaaab
+ aaaaaaa
+ *****f1
+ aaaaaaa
+ aaaaaaa
+ abcdefg
+ *****f2
+ aaaaaaa
+ abcdefg
+
+WARNING:
+ This program makes use of GOTO's and hence is not as straightforward
+ as it could be! CAVEAT PROGRAMMER.
+****************************************************************************/
+
+
+#include "ulib.hxx"
+#include "fc.hxx"
+#include "arg.hxx"
+#include "array.hxx"
+#include "arrayit.hxx"
+#include "bytestrm.hxx"
+#include "dir.hxx"
+#include "file.hxx"
+#include "filestrm.hxx"
+#include "filter.hxx"
+#include "mbstr.hxx"
+#include "system.hxx"
+#include "wstring.hxx"
+
+#include <malloc.h>
+#include <process.h>
+#include <stdlib.h>
+#include <math.h>
+
+
+/**************************************************************************/
+/* main */
+/**************************************************************************/
+
+INT _CRTAPI1
+main (
+ )
+{
+ DEFINE_CLASS_DESCRIPTOR( FC );
+
+ {
+ FC Fc;
+
+ if ( Fc.Initialize() ) {
+
+ return Fc.Fcmain();
+ }
+ }
+
+ return FAILURE;
+}
+
+
+
+
+CHAR *ExtBin[] = { "EXE", "OBJ", "LIB",
+ "COM", "BIN", "SYS", NULL };
+
+
+
+
+DEFINE_CONSTRUCTOR( FC, PROGRAM );
+
+
+FC::~FC () {
+}
+
+
+
+BOOLEAN FC::Initialize() {
+
+
+ if ( PROGRAM::Initialize() ) {
+
+ ValidateVersion();
+
+ ctSync = -1; // number of lines required to sync
+ cLine = -1; // number of lines in internal buffs
+
+ fAbbrev = FALSE; // abbreviated output
+ fBinary = FALSE; // binary comparison
+ fLine = FALSE; // line comparison
+ fNumb = FALSE; // display line numbers
+ fCase = TRUE; // case is significant
+ fIgnore = FALSE; // ignore spaces and blank lines
+
+#ifdef DEBUG
+ fDebug = FALSE;
+#endif
+
+ fExpandTabs = TRUE;
+ // funcRead = (int (*)(char *,int,FILE *))fgetl;
+
+ extBin = (CHAR **)ExtBin;
+
+ return ParseArguments();
+ }
+
+ return FALSE;
+}
+
+
+
+
+
+BOOLEAN
+FC::ParseArguments(
+ )
+{
+
+ ARGUMENT_LEXEMIZER ArgLex;
+ ARRAY LexArray;
+ ARRAY ArrayOfArg;
+
+ PATH_ARGUMENT ProgramName;
+ FLAG_ARGUMENT FlagAbbreviate;
+ FLAG_ARGUMENT FlagAsciiCompare;
+ FLAG_ARGUMENT FlagBinaryCompare;
+ FLAG_ARGUMENT FlagCaseInsensitive;
+ FLAG_ARGUMENT FlagCompression;
+ FLAG_ARGUMENT FlagExpansion;
+ FLAG_ARGUMENT FlagLineNumber;
+ FLAG_ARGUMENT FlagRequestHelp;
+ FLAG_ARGUMENT FlagUnicode;
+ LONG_ARGUMENT LongBufferSize;
+#ifdef DEBUG
+ FLAG_ARGUMENT FlagDebug;
+#endif
+ STRING_ARGUMENT LongMatch;
+ PATH_ARGUMENT InFile1;
+ PATH_ARGUMENT InFile2;
+
+ LONG Long;
+ INT i;
+
+
+ if( !LexArray.Initialize() ) {
+ DebugAbort( "LexArray.Initialize() Failed!\n" );
+ return( FALSE );
+ }
+ if( !ArgLex.Initialize(&LexArray) ) {
+ DebugAbort( "ArgLex.Initialize() Failed!\n" );
+ return( FALSE );
+ }
+
+ // Allow only the '/' as a valid switch
+ ArgLex.PutSwitches("/");
+ ArgLex.SetCaseSensitive( FALSE );
+
+ ArgLex.PutStartQuotes("\"");
+ ArgLex.PutEndQuotes("\"");
+ ArgLex.PutSeparators(" \t");
+
+ if( !ArgLex.PrepareToParse() ) {
+ DebugAbort( "ArgLex.PrepareToParse() Failed!\n" );
+ return( FALSE );
+ }
+
+ if( !ProgramName.Initialize("*") ||
+ !FlagAbbreviate.Initialize("/A") ||
+ !FlagAsciiCompare.Initialize("/L") ||
+ !FlagBinaryCompare.Initialize("/B") ||
+ !FlagCaseInsensitive.Initialize("/C") ||
+ !FlagCompression.Initialize("/W") ||
+ !FlagExpansion.Initialize("/T") ||
+ !FlagLineNumber.Initialize("/N") ||
+ !FlagRequestHelp.Initialize("/?") ||
+ !FlagUnicode.Initialize("/U") ||
+#ifdef DEBUG
+ !FlagDebug.Initialize("/D") ||
+#endif
+ !LongBufferSize.Initialize("/LB#") ||
+ !LongMatch.Initialize("/*") ||
+ !InFile1.Initialize("*") ||
+ !InFile2.Initialize("*") ) {
+
+ DebugAbort( "Unable to Initialize some or all of the Arguments!\n" );
+ return( FALSE );
+ }
+
+
+ if( !ArrayOfArg.Initialize() ) {
+ DebugAbort( "ArrayOfArg.Initialize() Failed\n" );
+ return( FALSE );
+ }
+
+ if( !ArrayOfArg.Put(&ProgramName) ||
+ !ArrayOfArg.Put(&FlagAbbreviate) ||
+ !ArrayOfArg.Put(&FlagAsciiCompare) ||
+ !ArrayOfArg.Put(&FlagBinaryCompare) ||
+ !ArrayOfArg.Put(&FlagCaseInsensitive) ||
+ !ArrayOfArg.Put(&FlagCompression) ||
+ !ArrayOfArg.Put(&FlagExpansion) ||
+ !ArrayOfArg.Put(&FlagLineNumber) ||
+ !ArrayOfArg.Put(&FlagRequestHelp) ||
+ !ArrayOfArg.Put(&FlagUnicode) ||
+#ifdef DEBUG
+ !ArrayOfArg.Put(&FlagDebug) ||
+#endif
+ !ArrayOfArg.Put(&LongBufferSize) ||
+ !ArrayOfArg.Put(&LongMatch) ||
+ !ArrayOfArg.Put(&InFile1) ||
+ !ArrayOfArg.Put(&InFile2) ) {
+
+ DebugAbort( "ArrayOfArg.Put() Failed!\n" );
+ return( FALSE );
+ }
+
+
+ if( !( ArgLex.DoParsing( &ArrayOfArg ) ) ) {
+ // For each incorrect command line parameter, FC displays the
+ // following message:
+ //
+ // FC: Invalid Switch
+ //
+ // It does *not* die if a parameter is unrecognized...(Dos does...)
+ //
+ DisplayMessage( MSG_FC_INVALID_SWITCH, ERROR_MESSAGE, "" );
+ // return( FALSE );
+ }
+
+
+
+ //
+ // It should now be safe to test the arguments for their values...
+ //
+ if( FlagRequestHelp.QueryFlag() ) {
+ DisplayMessage( MSG_FC_HELP_MESSAGE, NORMAL_MESSAGE, "" );
+ return( FALSE );
+ }
+
+ if( FlagBinaryCompare.QueryFlag() &&
+ ( FlagAsciiCompare.QueryFlag() || FlagLineNumber.QueryFlag() ) ) {
+
+ DisplayMessage( MSG_FC_INCOMPATIBLE_SWITCHES, ERROR_MESSAGE, "" );
+ return( FALSE );
+ }
+
+ if( !InFile1.IsValueSet() ||
+ !InFile2.IsValueSet() ) {
+ DisplayMessage( MSG_FC_INSUFFICIENT_FILES, ERROR_MESSAGE, "" );
+ return( FALSE );
+ }
+
+
+ //
+ // Convert filenames to upper case
+ //
+ _File1.Initialize( InFile1.GetPath() );
+ _File2.Initialize( InFile2.GetPath() );
+
+ ((PWSTRING)_File1.GetPathString())->Strupr();
+ ((PWSTRING)_File2.GetPathString())->Strupr();
+
+
+ fUnicode = FlagUnicode.QueryFlag();
+ fAbbrev = FlagAbbreviate.QueryFlag();
+ fCase = !FlagCaseInsensitive.QueryFlag();
+ fIgnore = FlagCompression.QueryFlag();
+ fNumb = FlagLineNumber.QueryFlag();
+ fBinary = FlagBinaryCompare.QueryFlag();
+
+ if ( FlagExpansion.QueryFlag() ) {
+ fExpandTabs = FALSE;
+ //funcRead = (int (*)(char *,int,FILE *))fgets;
+ }
+
+#ifdef DEBUG
+ fDebug = FlagDebug.QueryFlag();
+#endif
+
+
+ if ( LongBufferSize.IsValueSet() ) {
+ cLine = (INT)LongBufferSize.QueryLong();
+ fLine = TRUE;
+ } else {
+ cLine = 100;
+ }
+
+ if ( LongMatch.IsValueSet() ) {
+ if ( LongMatch.GetString()->QueryNumber( &Long ) ) {
+ ctSync = (INT)Long;
+ fLine = TRUE;
+ } else {
+
+ DisplayMessage( MSG_FC_INVALID_SWITCH, ERROR_MESSAGE, "" );
+ ctSync = 2;
+ }
+ } else {
+ ctSync = 2;
+ }
+
+ if (!fBinary && !fLine) {
+
+ DSTRING ExtBin;
+ PWSTRING Ext = _File1.QueryExt();
+
+ if ( Ext ) {
+ for (i=0; extBin[i]; i++) {
+ ExtBin.Initialize( extBin[i] );
+ if ( !ExtBin.Stricmp( Ext ) ) {
+ fBinary = TRUE;
+ break;
+ }
+ }
+
+ DELETE( Ext );
+ }
+
+ if (!fBinary) {
+ fLine = TRUE;
+ }
+ }
+
+ if (!fUnicode) {
+ if (fIgnore) {
+ if (fCase) {
+ fCmp = MBSTR::Strcmps;
+ } else {
+ fCmp = MBSTR::Strcmpis;
+ }
+ } else {
+
+ if (fCase) {
+ fCmp = MBSTR::Strcmp;
+ } else {
+ fCmp = MBSTR::Stricmp;
+ }
+ }
+ } else {
+ if (fIgnore) {
+ if (fCase) {
+ fCmp_U = WSTRING::Strcmps;
+ } else {
+ fCmp_U = WSTRING::Strcmpis;
+ }
+ } else {
+
+ if (fCase) {
+ fCmp_U = WSTRING::Strcmp;
+ } else {
+ fCmp_U = WSTRING::Stricmp;
+ }
+ }
+ }
+
+ return( TRUE );
+
+}
+
+
+
+
+
+INT
+FC::Fcmain
+ (
+ )
+{
+ ParseFileNames();
+
+ return SUCCESS;
+}
+
+
+
+
+/**************************************************************************/
+/* BinaryCompare */
+/**************************************************************************/
+
+int FC::BinaryCompare (char *f1, char *f2)
+{
+
+ DSTRING FileStr;
+ PATH FileName;
+ PFSN_FILE File1 = NULL;
+ PFSN_FILE File2 = NULL;
+ PFILE_STREAM Stream1 = NULL;
+ PFILE_STREAM Stream2 = NULL;;
+ BYTE_STREAM Bs1;
+ BYTE_STREAM Bs2;
+ BYTE c1, c2;
+ DWORD pos;
+ BOOLEAN fSame;
+ char buffer[128];
+ int Result = 0;
+
+
+ if ( !FileStr.Initialize( f1 ) ||
+ !FileName.Initialize( &FileStr ) ||
+ !(File1 = SYSTEM::QueryFile( &FileName )) ||
+ !(Stream1 = File1->QueryStream( READ_ACCESS )) ||
+ !Bs1.Initialize( Stream1 )
+ ) {
+
+ DisplayMessage( MSG_FC_UNABLE_TO_OPEN, ERROR_MESSAGE, "%s", f1 );
+ Result = 1;
+ DELETE( Stream2 );
+ DELETE( File2 );
+ DELETE( Stream1 );
+ DELETE( File1 );
+ return Result;
+ // goto Exit;
+ }
+
+ if ( !FileStr.Initialize( f2 ) ||
+ !FileName.Initialize( &FileStr ) ||
+ !(File2 = SYSTEM::QueryFile( &FileName )) ||
+ !(Stream2 = File2->QueryStream( READ_ACCESS )) ||
+ !Bs2.Initialize( Stream2 )
+ ) {
+
+ DisplayMessage( MSG_FC_UNABLE_TO_OPEN, ERROR_MESSAGE, "%s", f2 );
+ Result = 1;
+ DELETE( Stream2 );
+ DELETE( File2 );
+ DELETE( Stream1 );
+ DELETE( File1 );
+ return Result;
+ // goto Exit;
+ }
+
+ fSame = TRUE;
+ pos = 0L;
+
+ while ( TRUE ) {
+
+ if ( Bs1.ReadByte( &c1 ) ) {
+
+ if ( Bs2.ReadByte( &c2 ) ) {
+
+ if (c1 != c2) {
+
+ fSame = FALSE;
+ sprintf( buffer, "%08lX: %02X %02X", pos, c1, c2 );
+ DisplayMessage( MSG_FC_DATA, NORMAL_MESSAGE, "%s", buffer );
+ // DisplayMessage( MSG_FC_HEX_OUT, NORMAL_MESSAGE, "%08lX %02X %02X", pos, c1, c2 );
+ }
+
+ } else {
+
+ DisplayMessage( MSG_FC_FILES_DIFFERENT_LENGTH, NORMAL_MESSAGE, "%s%s", f1, f2 );
+ Result = 1;
+ DELETE( Stream2 );
+ DELETE( File2 );
+ DELETE( Stream1 );
+ DELETE( File1 );
+ return Result;
+ // goto Exit;
+
+ }
+
+ } else {
+
+ if ( Bs2.ReadByte( &c2 ) ) {
+
+ DisplayMessage( MSG_FC_FILES_DIFFERENT_LENGTH, NORMAL_MESSAGE, "%s%s", f2, f1 );
+ Result = 1;
+ DELETE( Stream2 );
+ DELETE( File2 );
+ DELETE( Stream1 );
+ DELETE( File1 );
+ return Result;
+ //goto Exit;
+
+ } else {
+
+ if (fSame) {
+ DisplayMessage( MSG_FC_NO_DIFFERENCES, NORMAL_MESSAGE );
+ }
+
+ Result = 0;
+ DELETE( Stream2 );
+ DELETE( File2 );
+ DELETE( Stream1 );
+ DELETE( File1 );
+ return Result;
+ // goto Exit;
+
+ }
+ }
+
+ pos++;
+ }
+
+// Exit:
+
+ DELETE( Stream2 );
+ DELETE( File2 );
+ DELETE( Stream1 );
+ DELETE( File1 );
+ return Result;
+}
+
+
+/**************************************************************************/
+/* Compare a range of lines. */
+/**************************************************************************/
+
+BOOLEAN FC::compare (int l1, register int s1, int l2, register int s2, int ct)
+{
+#ifdef DEBUG
+ if (fDebug)
+ DebugPrintf ("compare (%d, %d, %d, %d, %d)\n", l1, s1, l2, s2, ct);
+#endif
+
+ if (ct <= 0 || s1+ct > l1 || s2+ct > l2)
+ return (FALSE);
+
+ while (ct--)
+ {
+
+#ifdef DEBUG
+ if (fDebug)
+ DebugPrintf ("'%s' == '%s'? ", buffer1[s1].text, buffer2[s2].text);
+#endif
+ if(!fUnicode) {
+ if ((*fCmp)(buffer1[s1++].text, buffer2[s2++].text)) {
+
+#ifdef DEBUG
+ if (fDebug)
+ DebugPrintf ("No\n");
+#endif
+ return (FALSE);
+ }
+ } else {
+ if ((*fCmp_U)(buffer1[s1++].wtext, buffer2[s2++].wtext)) {
+
+#ifdef DEBUG
+ if (fDebug)
+ DebugPrintf ("No\n");
+#endif
+ return (FALSE);
+ }
+ }
+ }
+
+#ifdef DEBUG
+ if (fDebug)
+ DebugPrintf ("Yes\n");
+#endif
+
+ return (TRUE);
+}
+
+
+/**************************************************************************/
+/* LineCompare */
+/**************************************************************************/
+
+
+void FC::LineCompare (char *f1, char *f2)
+{
+
+ DSTRING FileStr;
+ PATH FileName;
+ PFSN_FILE File1 = NULL;
+ PFSN_FILE File2 = NULL;
+ PFILE_STREAM Stream1 = NULL;
+ PFILE_STREAM Stream2 = NULL;;
+
+
+ buffer1 = buffer2 = NULL;
+
+ if ( !FileStr.Initialize( f1 ) ||
+ !FileName.Initialize( &FileStr ) ||
+ !(File1 = SYSTEM::QueryFile( &FileName )) ||
+ !(Stream1 = File1->QueryStream( READ_ACCESS ))
+ ) {
+
+ DisplayMessage( MSG_FC_UNABLE_TO_OPEN, ERROR_MESSAGE, "%s", f1 );
+ FREE(buffer1);
+ FREE(buffer2);
+ DELETE(Stream2);
+ DELETE(File2);
+ DELETE(Stream1);
+ DELETE(File1);
+ return;
+ //goto Exit;
+ }
+
+ if ( !FileStr.Initialize( f2 ) ||
+ !FileName.Initialize( &FileStr ) ||
+ !(File2 = SYSTEM::QueryFile( &FileName )) ||
+ !(Stream2 = File2->QueryStream( READ_ACCESS ))
+ ) {
+
+ DisplayMessage( MSG_FC_UNABLE_TO_OPEN, ERROR_MESSAGE, "%s", f2 );
+ FREE(buffer1);
+ FREE(buffer2);
+ DELETE(Stream2);
+ DELETE(File2);
+ DELETE(Stream1);
+ DELETE(File1);
+ return;
+ //goto Exit;
+ }
+
+
+ if ( (buffer1 = (struct lineType *)MALLOC(cLine * (sizeof *buffer1))) == NULL ||
+ (buffer2 = (struct lineType *)MALLOC(cLine * (sizeof *buffer1))) == NULL) {
+
+ DisplayMessage( MSG_FC_OUT_OF_MEMORY, ERROR_MESSAGE );
+ FREE(buffer1);
+ FREE(buffer2);
+ DELETE(Stream2);
+ DELETE(File2);
+ DELETE(Stream1);
+ DELETE(File1);
+ return;
+ //goto Exit;
+ }
+
+ RealLineCompare( f1, f2, Stream1, Stream2 );
+
+// Exit:
+ FREE(buffer1);
+ FREE(buffer2);
+ DELETE(Stream2);
+ DELETE(File2);
+ DELETE(Stream1);
+ DELETE(File1);
+
+
+}
+
+void FC::RealLineCompare (char *f1, char *f2, PSTREAM Stream1, PSTREAM Stream2 )
+{
+
+ int l1, l2, i, xp, yp, xc, yc;
+ BOOLEAN xd, yd, fSame;
+ int line1, line2;
+
+
+ fSame = TRUE;
+ l1 = l2 = 0;
+ line1 = line2 = 0;
+
+l0:
+
+#ifdef DEBUG
+ if (fDebug) {
+ DebugPrintf ("At scan beginning\n");
+ }
+#endif
+
+ l1 += xfill (buffer1+l1, Stream1, cLine-l1, &line1);
+ l2 += xfill (buffer2+l2, Stream2, cLine-l2, &line2);
+
+ if (l1 == 0 && l2 == 0) {
+
+ if (fSame) {
+ DisplayMessage( MSG_FC_NO_DIFFERENCES, NORMAL_MESSAGE );
+ }
+ return;
+ }
+
+ xc = min (l1, l2);
+
+ for (i=0; i < xc; i++) {
+
+ if (!compare (l1, i, l2, i, 1)) {
+ break;
+ }
+ }
+
+ if (i != xc) {
+// i = max (i-1, 0);
+ i = ( i-1 > 0 )? ( i-1 ) : 0;
+ }
+
+ l1 = adjust (buffer1, l1, i);
+ l2 = adjust (buffer2, l2, i);
+
+ if (l1 == 0 && l2 == 0) {
+ goto l0;
+ }
+
+ l1 += xfill (buffer1+l1, Stream1, cLine-l1, &line1);
+ l2 += xfill (buffer2+l2, Stream2, cLine-l2, &line2);
+
+#ifdef DEBUG
+ if (fDebug) {
+ DebugPrintf ("buffers are adjusted, %d, %d remain\n", l1, l2);
+ }
+#endif
+
+ xd = yd = FALSE;
+ xc = yc = 1;
+ xp = yp = 1;
+
+l6:
+
+#ifdef DEBUG
+ if (fDebug) {
+ DebugPrintf ("Trying resync %d,%d %d,%d\n", xc, xp, yc, yp);
+ }
+#endif
+
+ i = min (l1-xc,l2-yp);
+ i = min (i, ctSync);
+
+ if (compare (l1, xc, l2, yp, i)) {
+
+ fSame = FALSE;
+ DisplayMessage( MSG_FC_OUTPUT_FILENAME, NORMAL_MESSAGE, "%s", f1 );
+ dump (buffer1, 0, xc);
+ DisplayMessage( MSG_FC_OUTPUT_FILENAME, NORMAL_MESSAGE, "%s", f2 );
+ dump (buffer2, 0, yp);
+ DisplayMessage( MSG_FC_DUMP_END, NORMAL_MESSAGE );
+
+ l1 = adjust (buffer1, l1, xc);
+ l2 = adjust (buffer2, l2, yp);
+
+ goto l0;
+ }
+
+ i = min (l1-xp, l2-yc);
+ i = min (i, ctSync);
+
+ if (compare (l1, xp, l2, yc, i)) {
+
+ fSame = FALSE;
+ DisplayMessage( MSG_FC_OUTPUT_FILENAME, NORMAL_MESSAGE, "%s", f1 );
+ dump (buffer1, 0, xp);
+ DisplayMessage( MSG_FC_OUTPUT_FILENAME, NORMAL_MESSAGE, "%s", f2 );
+ dump (buffer2, 0, yc);
+ DisplayMessage( MSG_FC_DUMP_END, NORMAL_MESSAGE );
+
+ l1 = adjust (buffer1, l1, xp);
+ l2 = adjust (buffer2, l2, yc);
+
+ goto l0;
+ }
+
+ if (++xp > xc) {
+
+ xp = 1;
+ if (++xc >= l1) {
+
+ xc = l1;
+ xd = TRUE;
+ }
+ }
+
+ if (++yp > yc) {
+
+ yp = 1;
+ if (++yc >= l2) {
+
+ yc = l2;
+ yd = TRUE;
+ }
+ }
+
+ if (!xd || !yd) {
+ goto l6;
+ }
+
+ fSame = FALSE;
+
+ if (l1 >= cLine || l2 >= cLine) {
+ DisplayMessage( MSG_FC_RESYNC_FAILED, NORMAL_MESSAGE );
+ }
+
+ DisplayMessage( MSG_FC_OUTPUT_FILENAME, NORMAL_MESSAGE, "%s", f1 );
+ dump (buffer1, 0, l1-1);
+ DisplayMessage( MSG_FC_OUTPUT_FILENAME, NORMAL_MESSAGE, "%s", f2 );
+ dump (buffer2, 0, l2-1);
+ DisplayMessage( MSG_FC_DUMP_END, NORMAL_MESSAGE );
+
+ return;
+}
+
+
+/**************************************************************************/
+/* Return number of lines read in. */
+/**************************************************************************/
+
+FC::xfill (struct lineType *pl, PSTREAM Stream, int ct, int *plnum)
+{
+ int i;
+ DWORD StrSize;
+
+#ifdef DEBUG
+ if (fDebug)
+ DebugPrintf ("xfill (%04x, %04x)\n", pl, fh);
+#endif
+
+ i = 0;
+
+ if (!fUnicode) {
+ while ( ct-- && !Stream->IsAtEnd() && Stream->ReadMbLine( pl->text, MAXLINESIZE, &StrSize, fExpandTabs, 8 ) ) {
+
+ if (fIgnore && !MBSTR::Strcmps(pl->text, "")) {
+
+ pl->text[0] = 0;
+ ++*plnum;
+ }
+
+ if (strlen (pl->text) != 0 || !fIgnore)
+ {
+ pl->line = ++*plnum;
+ pl++;
+ i++;
+ }
+ }
+ } else {
+ while( ct-- && !Stream->IsAtEnd() && Stream->ReadWLine( pl->wtext,MAXLINESIZE, &StrSize, fExpandTabs, 8 ) ) {
+ //while( ct-- && !Stream->IsAtEnd() && Stream->ReadLine( &_String , TRUE )) {
+
+ //_String.QueryWSTR(0,TO_END,pl->wtext,MAXLINESIZE,TRUE);
+
+ if (fIgnore && !WSTRING::Strcmps((PWSTR)pl->wtext, (PWSTR)L"")) {
+
+ pl->wtext[0] = 0;
+ ++*plnum;
+ }
+
+ if (wcslen (pl->wtext) != 0 || !fIgnore)
+ {
+ pl->line = ++*plnum;
+ pl++;
+ i++;
+ }
+ }
+ }
+
+#ifdef DEBUG
+ if (fDebug)
+ DebugPrintf ("xfill returns %d\n", i);
+#endif
+
+ return (i);
+
+#if 0
+
+ while (ct-- && (*funcRead) (pl->text, MAXLINESIZE, fh) != NULL)
+ {
+ if (funcRead == ( int (*) (char *,int, FILE *))fgets)
+ pl->text[strlen(pl->text)-1] = 0;
+ if (fIgnore && !MBSTR::Strcmps(pl->text, ""))
+ {
+ pl->text[0] = 0;
+ ++*plnum;
+ }
+ if (strlen (pl->text) != 0 || !fIgnore)
+ {
+ pl->line = ++*plnum;
+ pl++;
+ i++;
+ }
+ }
+
+#ifdef DEBUG
+ if (fDebug)
+ DebugPrintf ("xfill returns %d\n", i);
+#endif
+
+ return (i);
+
+# endif
+
+}
+
+
+/**************************************************************************/
+/* Adjust returns number of lines in buffer. */
+/**************************************************************************/
+
+FC::adjust (struct lineType *pl, int ml, int lt)
+{
+#ifdef DEBUG
+ if (fDebug)
+ DebugPrintf ("adjust (%04x, %d, %d) = ", pl, ml, lt);
+ if (fDebug)
+ DebugPrintf ("%d\n", ml-lt);
+#endif
+
+ if (ml <= lt)
+ return (0);
+
+#ifdef DEBUG
+ if (fDebug)
+ DebugPrintf ("move (%04x, %04x, %04x)\n", &pl[lt], &pl[0], sizeof (*pl)*(ml-lt));
+#endif
+
+ // Move((char *)&pl[lt], (char *)&pl[0], sizeof (*pl)*(ml-lt));
+ memmove( (char *)&pl[0], (char *)&pl[lt], sizeof (*pl)*(ml-lt) );
+ return ml-lt;
+}
+
+
+/**************************************************************************/
+/* dump */
+/* dump outputs a range of lines. */
+/* */
+/* INPUTS */
+/* pl pointer to current lineType structure */
+/* start starting line number */
+/* end ending line number */
+/* */
+/* CALLS */
+/* pline, printf */
+/**************************************************************************/
+
+void FC::dump (struct lineType *pl, int start, int end)
+{
+ if (fAbbrev && end-start > 2)
+ {
+ pline (pl+start);
+ DisplayMessage( MSG_FC_ABBREVIATE_SYMBOL, NORMAL_MESSAGE );
+ pline (pl+end);
+ }
+ else
+ {
+ while (start <= end)
+ pline (pl+start++);
+ }
+}
+
+
+/**************************************************************************/
+/* PrintLINE */
+/* pline prints a single line of output. If the /n flag */
+/* has been specified, the line number of the printed text is added. */
+/* */
+/* Inputs */
+/* pl pointer to current lineType structure */
+/* fNumb TRUE if /n specified */
+/**************************************************************************/
+
+void FC::pline (struct lineType *pl)
+{
+ if (!fUnicode) {
+ if (fNumb)
+ DisplayMessage( MSG_FC_NUMBERED_DATA, NORMAL_MESSAGE, "%5d%s",
+ pl->line, pl->text );
+ else
+ DisplayMessage( MSG_FC_DATA, NORMAL_MESSAGE, "%s", pl->text );
+ } else {
+ FSTRING f;
+ if (fNumb)
+ DisplayMessage( MSG_FC_NUMBERED_DATA, NORMAL_MESSAGE, "%5d%W",
+ pl->line, f.Initialize(pl->wtext) );
+ else
+ DisplayMessage( MSG_FC_DATA, NORMAL_MESSAGE, "%W",
+ f.Initialize(pl->wtext) );
+ }
+}
+
+
+/*********************************************************************/
+/* Routine: ParseFileNames */
+/* */
+/* Function: Parses the two given filenames and then compares the */
+/* appropriate filenames. This routine handles wildcard */
+/* characters in both filenames. */
+/*********************************************************************/
+
+void FC::ParseFileNames()
+{
+ PATH File1;
+ PATH File2;
+ FSN_FILTER Filter;
+ PWSTRING Name;
+ PARRAY NodeArray;
+ PITERATOR Iterator;
+ PFSN_DIRECTORY Dir;
+ PFSNODE File;
+ PPATH ExpandedPath;
+ PATH TmpPath;
+
+ File1.Initialize( &_File1 );
+ File2.Initialize( &_File2 );
+
+ Filter.Initialize();
+ if (!(Name = File1.QueryName())) {
+ DisplayMessage( MSG_FC_UNABLE_TO_OPEN, ERROR_MESSAGE, "%W", File1.GetPathString() );
+ return;
+ }
+ Filter.SetFileName( Name );
+ DELETE( Name );
+ Filter.SetAttributes( (FSN_ATTRIBUTE)0, // ALL
+ FSN_ATTRIBUTE_FILES, // ANY
+ FSN_ATTRIBUTE_DIRECTORY ); // NONE
+
+
+ TmpPath.Initialize( &File1, TRUE );
+ TmpPath.TruncateBase();
+
+ if ( !( Dir = SYSTEM::QueryDirectory( &TmpPath ) ) ||
+ !(NodeArray = Dir->QueryFsnodeArray( &Filter )) ||
+ !(Iterator = NodeArray->QueryIterator()) ||
+ !(File = (PFSNODE)Iterator->GetNext())
+ ) {
+ DisplayMessage( MSG_FC_UNABLE_TO_OPEN, ERROR_MESSAGE, "%W", File1.GetPathString() );
+ return;
+ }
+
+ Iterator->Reset();
+
+ while ( File = (PFSNODE)Iterator->GetNext() ) {
+
+ PWSTRING Name1;
+ PWSTRING Name2;
+
+ if (!(Name1 = File->QueryName())) {
+ DisplayMessage( MSG_FC_UNABLE_TO_OPEN, ERROR_MESSAGE, "%W", File->GetPath()->GetPathString() );
+ return;
+ }
+
+ if ( _File2.HasWildCard() ) {
+
+ if ( !(ExpandedPath = _File2.QueryWCExpansion( (PPATH)File->GetPath() ))) {
+
+ if (!(Name2 = _File2.QueryName())) {
+ DisplayMessage( MSG_FC_UNABLE_TO_OPEN, ERROR_MESSAGE, "%W", _File2.GetPathString() );
+ return;
+ }
+
+ DisplayMessage( MSG_FC_CANT_EXPAND_TO_MATCH, ERROR_MESSAGE, "%W%W", Name1, Name2 );
+ DELETE( Name2 );
+ DELETE( Name1 );
+ DELETE( Iterator );
+ DELETE( NodeArray );
+ DELETE( Dir );
+ return;
+ }
+
+ } else {
+
+ if ( !(ExpandedPath = NEW PATH) ||
+ !ExpandedPath->Initialize( &_File2 ) ) {
+
+ DisplayMessage( MSG_FC_OUT_OF_MEMORY, ERROR_MESSAGE );
+ DELETE( Name1 );
+ DELETE( Iterator );
+ DELETE( NodeArray );
+ DELETE( Dir );
+ return;
+
+ }
+ }
+
+ if (!(Name2 = ExpandedPath->QueryName())) {
+ DisplayMessage( MSG_FC_UNABLE_TO_OPEN, ERROR_MESSAGE, "%W", ExpandedPath->GetPathString() );
+ return;
+ }
+ File1.SetName( Name1 );
+ File2.SetName( Name2 );
+
+ comp( File1.GetPathString()->QuerySTR(), File2.GetPathString()->QuerySTR() );
+
+ DELETE( Name2 );
+ DELETE( Name1 );
+ DELETE( ExpandedPath );
+
+ }
+
+ DELETE( Iterator );
+ NodeArray->DeleteAllMembers();
+ DELETE( NodeArray );
+ DELETE( Dir );
+
+}
+
+
+
+
+/*********************************************************************/
+/* Routine: comp */
+/* */
+/* Function: Compares the two files. */
+/*********************************************************************/
+
+void FC::comp(char *file1, char *file2)
+{
+ DisplayMessage( MSG_FC_COMPARING_FILES, NORMAL_MESSAGE, "%s%s", file1, file2 );
+ if (fBinary)
+ BinaryCompare (file1, file2);
+ else {
+ LineCompare (file1, file2);
+ }
+
+}
+
+
+/* returns line from file (no CRLFs); returns NULL if EOF */
+FC::fgetl ( char *buf, int len, FILE *fh)
+{
+ register int c;
+ register char *p;
+
+ /* remember NUL at end */
+ len--;
+ p = buf;
+ while (len) {
+ c = getc (fh);
+ if (c == EOF || c == '\n')
+ break;
+#if MSDOS
+ if (c != '\r')
+#endif
+ if (c != '\t') {
+ *p++ = (char)c;
+ len--;
+ }
+ else {
+ c = min (8 - ((p-buf) & 0x0007), len);
+ memset(p, ' ', c);
+ p += c;
+ len -= c;
+ }
+ }
+ *p = 0;
+ return ! ( (c == EOF) && (p == buf) );
+}
diff --git a/private/utils/fc/fc.hxx b/private/utils/fc/fc.hxx
new file mode 100644
index 000000000..da2b7c3cd
--- /dev/null
+++ b/private/utils/fc/fc.hxx
@@ -0,0 +1,163 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ fc.hxx
+
+Abstract:
+
+ This module contains the definition for the FC class, which
+ implements the DOS5-compatible FC utility.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 01-May-1990
+
+
+Revision History:
+
+
+--*/
+
+
+#if !defined( _FC_ )
+
+#define _FC_
+
+#include "object.hxx"
+#include "program.hxx"
+#include "path.hxx"
+#include "wstring.hxx"
+
+
+extern "C" {
+ #include <stdio.h>
+}
+
+
+//
+// Define DEBUG for debug support
+//
+// #define DEBUG
+
+
+//
+// Maximum file name size
+//
+#define MAXFNAME 80
+
+
+//
+// Maximum line size
+//
+#define MAXLINESIZE 128
+
+
+//
+// Exit codes
+//
+#define FAILURE -1
+#define SUCCESS 0
+#define FILES_NOT_FOUND 6
+#define COULD_NOT_EXP 21
+
+
+
+typedef struct lineType {
+ INT line; // line number
+union {
+ CHAR text[MAXLINESIZE]; // body of line
+ WCHAR wtext[MAXLINESIZE]; // body of line
+ };
+} LINETYPE, *PLINETYPE;
+
+
+DECLARE_CLASS( STREAM );
+DECLARE_CLASS( FC );
+
+class FC : public PROGRAM {
+
+
+ public:
+
+ DECLARE_CONSTRUCTOR( FC );
+
+ NONVIRTUAL
+ ~FC (
+ );
+
+ INT Fcmain ();
+ BOOLEAN Initialize();
+ BOOLEAN ParseArguments();
+ int BinaryCompare(char *f1,char *f2);
+ BOOLEAN compare(int l1,int s1,int l2,int s2,int ct);
+ void LineCompare(char *f1,char *f2);
+ void RealLineCompare(char *f1,char *f2, PSTREAM Stream1, PSTREAM Stream2);
+ int xfill(struct lineType *pl,PSTREAM Stream,int ct,int *plnum);
+ int adjust(struct lineType *pl,int ml,int lt);
+ void dump(struct lineType *pl,int start,int end);
+ void pline(struct lineType *pl);
+ void ParseFileNames();
+ void comp(char *, char *);
+
+ static char *strbscan (char *p, char *s);
+ static char *strbskip (char *p, char *s);
+
+ static int fgetl(char *buf,int len, FILE *fh);
+
+ static int extention (char *src, char *dst);
+ static int filename (char *src, char *dst);
+
+ private:
+
+ int ctSync; /* number of lines required to sync */
+ int cLine ; /* number of lines in internal buffs */
+
+ BOOLEAN fUnicode; /* UNICODE text file compare */
+ BOOLEAN fAbbrev ; /* abbreviated output */
+ BOOLEAN fBinary ; /* binary comparison */
+ BOOLEAN fLine ; /* line comparison */
+ BOOLEAN fNumb ; /* display line numbers */
+ BOOLEAN fCase ; /* case is significant */
+ BOOLEAN fIgnore ; /* ignore spaces and blank lines */
+ BOOLEAN fExpandTabs;
+
+#ifdef DEBUG
+ BOOLEAN fDebug ;
+#endif
+
+ int (*funcRead) (char *buf,int len,FILE *fh); /* function to use to read lines */
+ INT (*fCmp) (IN PSTR, IN PSTR); /* function to use to compare lines */
+ INT (*fCmp_U) (IN PWSTR, IN PWSTR); /* function to use to compare lines */
+
+ struct lineType *buffer1;
+ struct lineType *buffer2;
+
+ CHAR line[MAXLINESIZE]; /* single line buffer */
+
+ CHAR **extBin;
+
+ PATH _File1;
+ PATH _File2;
+
+};
+
+
+INLINE
+char *FC::strbscan (char *p, char *s)
+{
+ return p + strcspn(p,s);
+}
+
+
+INLINE
+char *FC::strbskip (char *p, char *s)
+{
+ return p + strspn(p,s);
+}
+
+
+
+#endif //FC
diff --git a/private/utils/fc/fc.rc b/private/utils/fc/fc.rc
new file mode 100644
index 000000000..fca03ee29
--- /dev/null
+++ b/private/utils/fc/fc.rc
@@ -0,0 +1,11 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "DOS 5 File Compare Utility"
+#define VER_INTERNALNAME_STR "fc\0"
+#define VER_ORIGINALFILENAME_STR "FC.EXE"
+
+#include "common.ver"
+
diff --git a/private/utils/fc/makefile b/private/utils/fc/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/fc/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/fc/sources b/private/utils/fc/sources
new file mode 100644
index 000000000..40e35b6af
--- /dev/null
+++ b/private/utils/fc/sources
@@ -0,0 +1,58 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+BLDCRT=1
+
+MAJORCOMP=utils
+MINORCOMP=fc
+
+TARGETNAME=fc
+TARGETPATH=obj
+TARGETTYPE=UMAPPL_NOLIB
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=fc.cxx fc.rc
+
+INCLUDES=..\ulib\inc;\nt\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+CXXFLAGS=+d
+UMLIBS=..\ulib\src\obj\*\ulib.lib \nt\public\sdk\lib\*\ntdll.lib
+UMTYPE=console
+UMAPPL=fc
+UMRES=obj\*\fc.res
diff --git a/private/utils/fdisk/arrowin.c b/private/utils/fdisk/arrowin.c
new file mode 100644
index 000000000..cf8d7cfb6
--- /dev/null
+++ b/private/utils/fdisk/arrowin.c
@@ -0,0 +1,344 @@
+/** FILE: arrowin.c ******** Module Header ********************************
+ *
+ * Control panel arrow window class routines. This file contains the
+ * window procedure and utility functions for managing the "cpArrow"
+ * window class/spinner control for use by Control Panel applet dialogs.
+ *
+ * History:
+ * 15:30 on Thur 25 Apr 1991 -by- Steve Cathcart [stevecat]
+ * Took base code from Win 3.1 source
+ *
+ * Copyright (C) 1990-1991 Microsoft Corporation
+ *
+ *************************************************************************/
+//==========================================================================
+// Include files
+//==========================================================================
+// C Runtime
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+// Windows SDK
+/* cut out unnec stuff from windows.h */
+#define NOCLIPBOARD
+#define NOMETAFILE
+#define NOREGION
+#define NOSYSCOMMANDS
+#define NOATOM
+#define NOGDICAPMASKS
+
+#include <windows.h>
+
+//==========================================================================
+// Local Definitions
+//==========================================================================
+#define SHIFT_TO_DOUBLE 1
+#define DOUBLECLICK 0
+#define PRESSINVERT 1
+#define POINTSPERARROW 3
+#define ARROWXAXIS 15
+#define ARROWYAXIS 15
+
+
+//==========================================================================
+// External Declarations
+//==========================================================================
+extern HANDLE hModule;
+
+
+//==========================================================================
+// Local Data Declarations
+//==========================================================================
+#if 0
+POINT Arrow[11] = { 16, 1, 2, 14, 12, 14, 12, 20, 2, 20, 16, 33,
+ 29, 20, 20, 20, 20, 14, 29, 14/*, 16,1*/};
+#endif
+
+#if 0
+POINT ArrowUp[7] = {5, 2, 8, 5, 6, 5, 6, 7, 4, 7, 4, 5, 2, 5};
+
+POINT ArrowDown[7] = { 4, 10, 6, 10, 6, 12, 8, 12, 5, 15, 2, 12, 4, 12};
+
+#endif
+
+POINT ArrowUp[POINTSPERARROW] = {7, 1, 3, 5, 11, 5};
+
+POINT ArrowDown[POINTSPERARROW] = {7, 13, 3, 9, 11, 9};
+
+BOOL bRight;
+RECT rUp, rDown;
+LPRECT lpUpDown;
+FARPROC lpArrowProc;
+HANDLE hParent;
+
+//==========================================================================
+// Local Function Prototypes
+//==========================================================================
+
+
+//==========================================================================
+// Functions
+//==========================================================================
+
+WORD UpOrDown()
+{
+ LONG l;
+ WORD retval;
+ POINT pt;
+
+ l = GetMessagePos();
+
+ pt.y = (int) HIWORD(l);
+ pt.x = (int) LOWORD(l);
+
+ if (PtInRect((LPRECT) &rUp, pt))
+ retval = SB_LINEUP;
+ else if (PtInRect((LPRECT) &rDown, pt))
+ retval = SB_LINEDOWN;
+ else
+ retval = (WORD)-1; /* -1, because SB_LINEUP == 0 */
+ return(retval);
+}
+
+
+WORD ArrowTimerProc(hWnd, wMsg, nID, dwTime)
+HANDLE hWnd;
+WORD wMsg;
+short nID;
+DWORD dwTime;
+{
+ WORD wScroll;
+
+ if ((wScroll = UpOrDown()) != -1)
+ {
+ if (bRight == WM_RBUTTONDOWN)
+ wScroll += SB_PAGEUP - SB_LINEUP;
+// [stevecat] - changed WM_VSCROLL message parameter ordering for WIN32
+ SendMessage(hParent, WM_VSCROLL, MAKELONG(wScroll,
+ GetWindowLong(hWnd, GWL_ID)), (LONG) hWnd);
+ }
+/* Don't need to call KillTimer(), because SetTimer will reset the right one */
+ SetTimer(hWnd, nID, 50, (TIMERPROC)lpArrowProc);
+ return(0);
+#if 0
+ wMsg = wMsg;
+ dwTime = dwTime;
+#endif
+}
+
+
+#if PRESSINVERT
+void InvertArrow(HANDLE hArrow, WORD wScroll)
+{
+ HDC hDC;
+
+ lpUpDown = (wScroll == SB_LINEUP) ? &rUp : &rDown;
+ hDC = GetDC(hArrow);
+ ScreenToClient(hArrow, (LPPOINT) &(lpUpDown->left));
+ ScreenToClient(hArrow, (LPPOINT) &(lpUpDown->right));
+ InvertRect(hDC, lpUpDown);
+ ClientToScreen(hArrow, (LPPOINT) &(lpUpDown->left));
+ ClientToScreen(hArrow, (LPPOINT) &(lpUpDown->right));
+ ReleaseDC(hArrow, hDC);
+ ValidateRect(hArrow, lpUpDown);
+ return;
+}
+
+
+#endif
+
+LONG ArrowControlProc(HWND hArrow, UINT message, UINT wParam, LONG lParam)
+{
+ PAINTSTRUCT ps;
+ RECT rArrow;
+ HBRUSH hbr;
+ short fUpDownOut;
+ WORD wScroll;
+ POINT tPoint;
+ SIZE tSize;
+
+ switch (message)
+ {
+/*
+ case WM_CREATE:
+ break;
+
+ case WM_DESTROY:
+ break;
+*/
+
+ case WM_MOUSEMOVE:
+ if (!bRight) /* If not captured, don't worry about it */
+ break;
+
+ if (lpUpDown == &rUp)
+ fUpDownOut = SB_LINEUP;
+ else if (lpUpDown == &rDown)
+ fUpDownOut = SB_LINEDOWN;
+ else
+ fUpDownOut = -1;
+
+ switch (wScroll = UpOrDown())
+ {
+ case SB_LINEUP:
+ if (fUpDownOut == SB_LINEDOWN)
+ InvertArrow(hArrow, SB_LINEDOWN);
+ if (fUpDownOut != SB_LINEUP)
+ InvertArrow(hArrow, wScroll);
+ break;
+
+ case SB_LINEDOWN:
+ if (fUpDownOut == SB_LINEUP)
+ InvertArrow(hArrow, SB_LINEUP);
+ if (fUpDownOut != SB_LINEDOWN)
+ InvertArrow(hArrow, wScroll);
+ break;
+
+ default:
+ if (lpUpDown)
+ {
+ InvertArrow(hArrow, fUpDownOut);
+ lpUpDown = 0;
+ }
+ }
+ break;
+
+ case WM_RBUTTONDOWN:
+ case WM_LBUTTONDOWN:
+ if (bRight)
+ break;
+ bRight = message;
+ SetCapture(hArrow);
+ hParent = GetParent(hArrow);
+ GetWindowRect(hArrow, (LPRECT) &rUp);
+ CopyRect((LPRECT) &rDown, (LPRECT) &rUp);
+ rUp.bottom = (rUp.top + rUp.bottom) / 2;
+ rDown.top = rUp.bottom + 1;
+ wScroll = UpOrDown();
+#if PRESSINVERT
+ InvertArrow(hArrow, wScroll);
+#endif
+#if SHIFT_TO_DOUBLE
+ if (wParam & MK_SHIFT)
+ {
+ if (message != WM_RBUTTONDOWN)
+ goto ShiftLClick;
+ else
+ goto ShiftRClick;
+ }
+#endif
+ if (message == WM_RBUTTONDOWN)
+ wScroll += SB_PAGEUP - SB_LINEUP;
+// [stevecat] - changed WM_VSCROLL message parameter ordering for WIN32
+ SendMessage(hParent, WM_VSCROLL, MAKELONG(wScroll,
+ GetWindowLong(hArrow, GWL_ID)), (LONG) hArrow);
+ lpArrowProc = MakeProcInstance((FARPROC) ArrowTimerProc, hModule);
+ SetTimer(hArrow, GetWindowLong(hArrow, GWL_ID), 200, (TIMERPROC)lpArrowProc);
+ break;
+
+ case WM_LBUTTONUP:
+ case WM_RBUTTONUP:
+ if ((UINT) (bRight - WM_LBUTTONDOWN + WM_LBUTTONUP) == message)
+ {
+ bRight = 0;
+ ReleaseCapture();
+#if PRESSINVERT
+ if (lpUpDown)
+ InvertArrow(hArrow, (WORD)((lpUpDown == &rUp) ? SB_LINEUP : SB_LINEDOWN));
+#endif
+ if (lpArrowProc)
+ {
+// [stevecat] - changed WM_VSCROLL message parameter ordering for WIN32
+ SendMessage(hParent, WM_VSCROLL, MAKELONG(SB_ENDSCROLL,
+ GetWindowLong(hArrow, GWL_ID)), (LONG) hArrow);
+ KillTimer(hArrow, GetWindowLong(hArrow, GWL_ID));
+ FreeProcInstance(lpArrowProc);
+ ReleaseCapture();
+ lpArrowProc = 0;
+ }
+ }
+ break;
+
+ case WM_LBUTTONDBLCLK:
+ShiftLClick:
+ wScroll = UpOrDown() + (WORD) (SB_TOP - SB_LINEUP);
+// [stevecat] - changed WM_VSCROLL message parameter ordering for WIN32
+ SendMessage(hParent, WM_VSCROLL, MAKELONG(wScroll,
+ GetWindowLong(hArrow, GWL_ID)), (LONG) hArrow);
+ SendMessage(hParent, WM_VSCROLL, MAKELONG(wScroll,
+ GetWindowLong(hArrow, GWL_ID)), (LONG) hArrow);
+ break;
+
+ case WM_RBUTTONDBLCLK:
+ShiftRClick:
+ wScroll = UpOrDown() + (WORD) (SB_THUMBPOSITION - SB_LINEUP);
+// [stevecat] - changed WM_VSCROLL message parameter ordering for WIN32
+ SendMessage(hParent, WM_VSCROLL, MAKELONG(wScroll,
+ GetWindowLong(hArrow, GWL_ID)), (LONG) hArrow);
+ SendMessage(hParent, WM_VSCROLL, MAKELONG(wScroll,
+ GetWindowLong(hArrow, GWL_ID)), (LONG) hArrow);
+/*
+ hDC = GetDC(hArrow);
+ InvertRect(hDC, (LPRECT) &rArrow);
+ ReleaseDC(hArrow, hDC);
+ ValidateRect(hArrow, (LPRECT) &rArrow);
+*/
+ break;
+
+ case WM_PAINT:
+ BeginPaint(hArrow, &ps);
+ GetClientRect(hArrow, (LPRECT) &rArrow);
+ if (hbr = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)))
+ {
+ FillRect(ps.hdc, (LPRECT) &rArrow, hbr);
+ DeleteObject(hbr);
+ }
+ hbr = SelectObject(ps.hdc, GetStockObject(BLACK_BRUSH));
+ SetTextColor(ps.hdc, GetSysColor(COLOR_WINDOWFRAME));
+ SetMapMode(ps.hdc, MM_ANISOTROPIC);
+
+ SetViewportOrgEx(ps.hdc, rArrow.left, rArrow.top, &tPoint);
+ SetViewportExtEx(ps.hdc, rArrow.right - rArrow.left,
+ rArrow.bottom - rArrow.top, &tSize);
+ SetWindowOrgEx(ps.hdc, 0, 0, &tPoint);
+ SetWindowExtEx(ps.hdc, ARROWXAXIS, ARROWYAXIS, &tSize);
+ MoveToEx(ps.hdc, 0, (ARROWYAXIS / 2), &tPoint);
+ LineTo(ps.hdc, ARROWXAXIS, (ARROWYAXIS / 2));
+/*
+ Polygon(ps.hdc, (LPPOINT) Arrow, 10);
+*/
+ Polygon(ps.hdc, (LPPOINT) ArrowUp, POINTSPERARROW);
+ Polygon(ps.hdc, (LPPOINT) ArrowDown, POINTSPERARROW);
+ SelectObject(ps.hdc, hbr);
+ EndPaint(hArrow, &ps);
+ break;
+
+ default:
+ return(DefWindowProc(hArrow, message, wParam, lParam));
+ break;
+ }
+ return(0L);
+}
+
+
+BOOL RegisterArrowClass (HANDLE hModule)
+{
+ WNDCLASS wcArrow;
+
+ wcArrow.lpszClassName = "cpArrow";
+ wcArrow.hInstance = hModule;
+ wcArrow.lpfnWndProc = ArrowControlProc;
+ wcArrow.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wcArrow.hIcon = NULL;
+ wcArrow.lpszMenuName = NULL;
+ wcArrow.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
+ wcArrow.style = CS_HREDRAW | CS_VREDRAW;
+#if DOUBLECLICK
+ wcArrow.style |= CS_DBLCLKS;
+#endif
+ wcArrow.cbClsExtra = 0;
+ wcArrow.cbWndExtra = 0;
+
+ return(RegisterClass((LPWNDCLASS) &wcArrow));
+}
diff --git a/private/utils/fdisk/cdrom.c b/private/utils/fdisk/cdrom.c
new file mode 100644
index 000000000..d98d94b0d
--- /dev/null
+++ b/private/utils/fdisk/cdrom.c
@@ -0,0 +1,522 @@
+
+/*++
+
+Copyright (c) 1993-1994 Microsoft Corporation
+
+Module Name:
+
+ cdrom.c
+
+Abstract:
+
+ This module contains the set of routines that display and control the
+ drive letters for CdRom devices.
+
+Author:
+
+ Bob Rinne (bobri) 12/9/93
+
+Environment:
+
+ User process.
+
+Notes:
+
+Revision History:
+
+--*/
+
+#include "fdisk.h"
+#include "shellapi.h"
+#include <string.h>
+#include <stdio.h>
+#include <wchar.h>
+#include <malloc.h>
+
+PCDROM_DESCRIPTOR CdRomChainBase = NULL;
+PCDROM_DESCRIPTOR CdRomChainLast = NULL;
+PCDROM_DESCRIPTOR CdRomChanged = NULL;
+
+static BOOLEAN CdRomFirstCall = TRUE;
+static TCHAR SourcePathLetter = (TCHAR) '\0';
+static TCHAR SourcePathKeyName[80];
+static TCHAR SourcePathValueName[30];
+
+VOID
+CdRomAddDevice(
+ IN PWSTR NtName,
+ IN WCHAR DriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ Build a cdrom description structure for this and fill it in.
+
+Arguments:
+
+ NtName - The unicode name for the device.
+ DriveLetter - The DosDevice name.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PCDROM_DESCRIPTOR cdrom;
+ PWCHAR cp;
+ LONG error;
+ HKEY keyHandle;
+ DWORD valueType;
+ ULONG size;
+ TCHAR *string;
+
+ if (CdRomFirstCall) {
+ CdRomFirstCall = FALSE;
+
+ // Get the registry path and value name.
+
+ LoadString(hModule,
+ IDS_SOURCE_PATH,
+ SourcePathKeyName,
+ sizeof(SourcePathKeyName)/sizeof(TCHAR));
+ LoadString(hModule,
+ IDS_SOURCE_PATH_NAME,
+ SourcePathValueName,
+ sizeof(SourcePathValueName)/sizeof(TCHAR));
+
+ error = RegOpenKey(HKEY_LOCAL_MACHINE,
+ SourcePathKeyName,
+ &keyHandle);
+ if (error == NO_ERROR) {
+ error = RegQueryValueEx(keyHandle,
+ SourcePathValueName,
+ NULL,
+ &valueType,
+ (PUCHAR)NULL,
+ &size);
+
+ if (error == NO_ERROR) {
+ string = (PUCHAR) LocalAlloc(LMEM_FIXED, size);
+ if (string) {
+ error = RegQueryValueEx(keyHandle,
+ SourcePathValueName,
+ NULL,
+ &valueType,
+ string,
+ &size);
+ if (error == NO_ERROR) {
+ SourcePathLetter = *string;
+ }
+ }
+ LocalFree(string);
+ }
+ RegCloseKey(keyHandle);
+ }
+ }
+
+ cdrom = (PCDROM_DESCRIPTOR) malloc(sizeof(CDROM_DESCRIPTOR));
+ if (cdrom) {
+ cdrom->DeviceName = (PWSTR) malloc((wcslen(NtName)+1)*sizeof(WCHAR));
+ if (cdrom->DeviceName) {
+ wcscpy(cdrom->DeviceName, NtName);
+ cp = cdrom->DeviceName;
+ while (*cp) {
+ if (iswdigit(*cp)) {
+ break;
+ }
+ cp++;
+ }
+
+ if (*cp) {
+ cdrom->DeviceNumber = wcstoul(cp, (WCHAR) 0, 10);
+ }
+ cdrom->DriveLetter = DriveLetter;
+ cdrom->Next = NULL;
+ cdrom->NewDriveLetter = (WCHAR) 0;
+ if (CdRomChainBase) {
+ CdRomChainLast->Next = cdrom;
+ } else {
+ AllowCdRom = TRUE;
+ CdRomChainBase = cdrom;
+ }
+ CdRomChainLast = cdrom;
+ } else {
+ free(cdrom);
+ }
+ }
+}
+
+
+INT
+CdRomDlgProc(
+ IN HWND hDlg,
+ IN UINT wMsg,
+ IN DWORD wParam,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Handle the dialog for CD-ROMS
+
+Arguments:
+
+ Standard Windows dialog procedure
+
+Return Value:
+
+ TRUE if something was deleted.
+ FALSE otherwise.
+
+--*/
+
+{
+ HWND hwndCombo;
+ DWORD selection;
+ DWORD index;
+ CHAR driveLetter;
+ TCHAR string[40];
+ PCDROM_DESCRIPTOR cdrom;
+ static PCDROM_DESCRIPTOR currentCdrom;
+ static CHAR currentSelectionLetter;
+
+ switch (wMsg) {
+ case WM_INITDIALOG:
+
+ // Store all device strings into the selection area.
+
+ hwndCombo = GetDlgItem(hDlg, IDC_CDROM_NAMES);
+ cdrom = currentCdrom = CdRomChainBase;
+ currentSelectionLetter = (CHAR) cdrom->DriveLetter;
+ while (cdrom) {
+ sprintf(string, "CdRom%d", cdrom->DeviceNumber);
+ SendMessage(hwndCombo, CB_ADDSTRING, 0, (LONG)string);
+ cdrom = cdrom->Next;
+ }
+ SendMessage(hwndCombo, CB_SETCURSEL, 0, 0);
+
+ // Update the drive letter selections.
+
+ selection = index = 0;
+ hwndCombo = GetDlgItem(hDlg, IDC_DRIVELET_COMBOBOX);
+ string[1] = TEXT(':');
+ string[2] = 0;
+ for (driveLetter = 'C'; driveLetter <= 'Z'; driveLetter++) {
+ if ((DriveLetterIsAvailable((CHAR)driveLetter)) ||
+ (driveLetter == currentSelectionLetter)) {
+ *string = driveLetter;
+ SendMessage(hwndCombo, CB_ADDSTRING, 0, (LONG)string);
+ if (driveLetter == currentSelectionLetter) {
+ selection = index;
+ }
+ index++;
+ }
+ }
+
+ // set the current selection to the appropriate index
+
+ SendMessage(hwndCombo, CB_SETCURSEL, selection, 0);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (wParam) {
+
+ case FD_IDHELP:
+ DialogHelp(HC_DM_DLG_CDROM);
+ break;
+
+ case IDCANCEL:
+
+ EndDialog(hDlg, FALSE);
+ break;
+
+ case IDOK:
+
+ // User has selected the drive letter and wants the mount to occur.
+
+ hwndCombo = GetDlgItem(hDlg, IDC_DRIVELET_COMBOBOX);
+ selection = SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
+ SendMessage(hwndCombo,
+ CB_GETLBTEXT,
+ selection,
+ (LONG)string);
+ currentCdrom->NewDriveLetter = (WCHAR) string[0];
+ CdRomChanged = currentCdrom;
+ EndDialog(hDlg, TRUE);
+ break;
+
+ default:
+
+ if (HIWORD(wParam) == LBN_SELCHANGE) {
+ TCHAR *cp;
+
+ if (LOWORD(wParam) != IDC_CDROM_NAMES) {
+ break;
+ }
+
+ // The state of something in the dialog changed.
+
+ hwndCombo = GetDlgItem(hDlg, IDC_CDROM_NAMES);
+ selection = SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
+ SendMessage(hwndCombo,
+ CB_GETLBTEXT,
+ selection,
+ (LONG)string);
+
+ // The format of the string returned is "cdrom#". Parse the
+ // value of # in order to find the selection.
+
+ cp = string;
+ while (*cp) {
+ cp++;
+ }
+ cp--;
+ while ((*cp >= (TCHAR) '0') && (*cp <= (TCHAR) '9')) {
+ cp--;
+ }
+ cp++;
+
+ selection = 0;
+ while (*cp) {
+ selection = (selection * 10) + (*cp - (TCHAR) '0');
+ cp++;
+ }
+
+ // Find the matching device name.
+
+ for (cdrom = CdRomChainBase; cdrom; cdrom = cdrom->Next) {
+
+ if (selection == cdrom->DeviceNumber) {
+
+ // found the match
+
+ currentSelectionLetter = (CHAR) cdrom->DriveLetter;
+ currentCdrom = cdrom;
+ break;
+ }
+ }
+
+ // The only thing that is important is to track the cdrom
+ // device name selected and update the drive letter list.
+
+ selection = index = 0;
+ hwndCombo = GetDlgItem(hDlg, IDC_DRIVELET_COMBOBOX);
+ SendMessage(hwndCombo, CB_RESETCONTENT, 0, 0);
+ string[1] = TEXT(':');
+ string[2] = 0;
+ for (driveLetter = 'C'; driveLetter <= 'Z'; driveLetter++) {
+ if ((DriveLetterIsAvailable((CHAR)driveLetter)) ||
+ (driveLetter == currentSelectionLetter)) {
+ *string = driveLetter;
+ SendMessage(hwndCombo, CB_ADDSTRING, 0, (LONG)string);
+ if (driveLetter == currentSelectionLetter) {
+ selection = index;
+ }
+ index++;
+ }
+ }
+
+ // set the current selection to the appropriate index
+
+ SendMessage(hwndCombo, CB_SETCURSEL, selection, 0);
+ }
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+
+VOID
+CdRom(
+ IN HWND Dialog,
+ IN PVOID Param
+ )
+
+/*++
+
+Routine Description:
+
+ Start the CdRom dialogs.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ BOOLEAN result = 0;
+ DWORD action,
+ ec;
+ TCHAR name[40];
+ TCHAR letter[10];
+ PWSTR linkTarget;
+ OBJECT_ATTRIBUTES oa;
+ WCHAR dosName[20];
+ HANDLE handle;
+ NTSTATUS status;
+ IO_STATUS_BLOCK statusBlock;
+ ANSI_STRING ansiName;
+ UNICODE_STRING unicodeName;
+ UINT errorMode;
+
+ result = DialogBoxParam(hModule,
+ MAKEINTRESOURCE(IDD_CDROM),
+ Dialog,
+ (DLGPROC) CdRomDlgProc,
+ (ULONG) NULL);
+ if (result) {
+
+ action = ConfirmationDialog(MSG_DRIVE_RENAME_WARNING, MB_ICONQUESTION | MB_YESNOCANCEL);
+
+ if (!action) {
+ return;
+ }
+
+ // Attempt to open and lock the cdrom.
+
+ sprintf(name, "\\Device\\CdRom%d", CdRomChanged->DeviceNumber);
+
+ RtlInitAnsiString(&ansiName, name);
+ status = RtlAnsiStringToUnicodeString(&unicodeName, &ansiName, TRUE);
+
+ if (!NT_SUCCESS(status)) {
+ ErrorDialog(MSG_CDROM_LETTER_ERROR);
+ return;
+ }
+
+ memset(&oa, 0, sizeof(OBJECT_ATTRIBUTES));
+ oa.Length = sizeof(OBJECT_ATTRIBUTES);
+ oa.ObjectName = &unicodeName;
+ oa.Attributes = OBJ_CASE_INSENSITIVE;
+
+ errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+ status = NtOpenFile(&handle,
+ SYNCHRONIZE | FILE_READ_DATA,
+ &oa,
+ &statusBlock,
+ FILE_SHARE_READ,
+ FILE_SYNCHRONOUS_IO_ALERT);
+ RtlFreeUnicodeString(&unicodeName);
+ SetErrorMode(errorMode);
+
+ if (!NT_SUCCESS(status)) {
+ ErrorDialog(MSG_CANNOT_LOCK_CDROM);
+ return;
+ }
+
+ // Lock the drive to insure that no other access is occurring
+ // to the volume. This is done via the "Low" routine for
+ // convenience
+
+ status = LowLockDrive(handle);
+
+ if (!NT_SUCCESS(status)) {
+ LowCloseDisk(handle);
+ ErrorDialog(MSG_CANNOT_LOCK_CDROM);
+ return;
+ }
+
+ // Before attempting to move the name, see if the letter
+ // is currently in use - could be a new network connection
+ // or a partition that is scheduled for deletion.
+
+ wsprintfW(dosName, L"\\DosDevices\\%wc:", (WCHAR) CdRomChanged->NewDriveLetter);
+ ec = GetDriveLetterLinkTarget(dosName, &linkTarget);
+ if (ec == NO_ERROR) {
+
+ // Something is using this letter.
+
+ LowCloseDisk(handle);
+ ErrorDialog(MSG_CANNOT_MOVE_CDROM);
+ return;
+ }
+
+ // remove existing definition - if this fails don't continue.
+
+ sprintf(letter, "%c:", (UCHAR) CdRomChanged->DriveLetter);
+ if (!DefineDosDevice(DDD_REMOVE_DEFINITION, (LPCTSTR) letter, (LPCTSTR) NULL)) {
+ LowCloseDisk(handle);
+ ErrorDialog(MSG_CDROM_LETTER_ERROR);
+ return;
+ }
+ status = DiskRegistryAssignCdRomLetter(CdRomChanged->DeviceName,
+ CdRomChanged->NewDriveLetter);
+ MarkDriveLetterFree((UCHAR)CdRomChanged->DriveLetter);
+
+ // See if this was the device used to install NT
+
+ if (SourcePathLetter) {
+ if (SourcePathLetter == CdRomChanged->DriveLetter) {
+ LONG error;
+ HKEY keyHandle;
+ DWORD valueType;
+ ULONG size;
+ TCHAR *string;
+
+
+ // Update the source path
+
+ error = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ SourcePathKeyName,
+ 0,
+ KEY_ALL_ACCESS,
+ &keyHandle);
+ if (error == NO_ERROR) {
+ error = RegQueryValueEx(keyHandle,
+ SourcePathValueName,
+ NULL,
+ &valueType,
+ (PUCHAR)NULL,
+ &size);
+
+ if (error == NO_ERROR) {
+ string = (PUCHAR) LocalAlloc(LMEM_FIXED, size);
+ if (string) {
+ error = RegQueryValueEx(keyHandle,
+ SourcePathValueName,
+ NULL,
+ &valueType,
+ string,
+ &size);
+ if (error == NO_ERROR) {
+ *string = SourcePathLetter = (UCHAR) CdRomChanged->NewDriveLetter;
+ RegSetValueEx(keyHandle,
+ SourcePathValueName,
+ 0,
+ REG_SZ,
+ string,
+ size);
+ }
+ }
+ LocalFree(string);
+ }
+ RegCloseKey(keyHandle);
+ }
+ }
+ }
+
+ // set up new device letter - name is already set up
+
+ sprintf(letter, "%c:", (UCHAR) CdRomChanged->NewDriveLetter);
+ if (DefineDosDevice(DDD_RAW_TARGET_PATH, (LPCTSTR) letter, (LPCTSTR) name)) {
+ CdRomChanged->DriveLetter = CdRomChanged->NewDriveLetter;
+ MarkDriveLetterUsed((UCHAR)CdRomChanged->DriveLetter);
+ } else {
+ RegistryChanged = TRUE;
+ }
+ LowCloseDisk(handle);
+ }
+}
diff --git a/private/utils/fdisk/commit.c b/private/utils/fdisk/commit.c
new file mode 100644
index 000000000..82a5235b0
--- /dev/null
+++ b/private/utils/fdisk/commit.c
@@ -0,0 +1,1524 @@
+
+/*++
+
+Copyright (c) 1993-1994 Microsoft Corporation
+
+Module Name:
+
+ commit.c
+
+Abstract:
+
+ This module contains the set of routines that support the commitment
+ of changes to disk without rebooting.
+
+Author:
+
+ Bob Rinne (bobri) 11/15/93
+
+Environment:
+
+ User process.
+
+Notes:
+
+Revision History:
+
+--*/
+
+#include "fdisk.h"
+#include "shellapi.h"
+#include <winbase.h>
+#include <string.h>
+#include <stdio.h>
+#include <malloc.h>
+#include "scsi.h"
+#include <ntddcdrm.h>
+#include <ntddscsi.h>
+
+// Lock list chain head for deleted partitions.
+
+PDRIVE_LOCKLIST DriveLockListHead = NULL;
+
+// Commit flag for case where a partition is deleted that has not drive letter
+
+extern BOOLEAN CommitDueToDelete;
+extern BOOLEAN CommitDueToMirror;
+extern BOOLEAN CommitDueToExtended;
+extern ULONG UpdateMbrOnDisk;
+
+extern HWND InitDlg;
+
+// List head for new drive letter assignment on commit.
+
+typedef struct _ASSIGN_LIST {
+ struct _ASSIGN_LIST *Next;
+ ULONG DiskNumber;
+ BOOLEAN MoveLetter;
+ UCHAR OriginalLetter;
+ UCHAR DriveLetter;
+} ASSIGN_LIST, *PASSIGN_LIST;
+
+PASSIGN_LIST AssignDriveLetterListHead = NULL;
+
+VOID
+CommitToAssignLetterList(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN BOOL MoveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ Remember this region for assigning a drive letter to it upon
+ commit.
+
+Arguments:
+
+ RegionDescriptor - the region to watch
+ MoveLetter - indicate that the region letter is already
+ assigned to a different partition, therefore
+ it must be "moved".
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PASSIGN_LIST newListEntry;
+ PPERSISTENT_REGION_DATA regionData;
+
+ newListEntry = (PASSIGN_LIST) Malloc(sizeof(ASSIGN_LIST));
+
+ if (newListEntry) {
+
+ // Save this region
+
+ regionData = PERSISTENT_DATA(RegionDescriptor);
+ newListEntry->OriginalLetter =
+ newListEntry->DriveLetter = regionData->DriveLetter;
+ newListEntry->DiskNumber = RegionDescriptor->Disk;
+ newListEntry->MoveLetter = MoveLetter;
+
+ // place it at the front of the chain.
+
+ newListEntry->Next = AssignDriveLetterListHead;
+ AssignDriveLetterListHead = newListEntry;
+ }
+}
+
+VOID
+CommitAssignLetterList(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Walk the assign drive letter list and make all drive letter assignments
+ expected. The regions data structures are moved around, so no pointer
+ can be maintained to look at them. To determine the partition number
+ for a new partition in this list, the Disks[] structure must be searched
+ to find a match on the partition for the drive letter. Then the partition
+ number will be known.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PREGION_DESCRIPTOR regionDescriptor;
+ PPERSISTENT_REGION_DATA regionData;
+ PDISKSTATE diskp;
+ PASSIGN_LIST assignList,
+ prevEntry;
+ TCHAR newName[4];
+ WCHAR targetPath[100];
+ LONG partitionNumber;
+ ULONG index;
+
+ assignList = AssignDriveLetterListHead;
+ while (assignList) {
+
+ if ((assignList->DriveLetter != NO_DRIVE_LETTER_YET) && (assignList->DriveLetter != NO_DRIVE_LETTER_EVER)) {
+
+ diskp = Disks[assignList->DiskNumber];
+ partitionNumber = 0;
+ for (index = 0; index < diskp->RegionCount; index++) {
+
+ regionDescriptor = &diskp->RegionArray[index];
+
+ if (DmSignificantRegion(regionDescriptor)) {
+
+ // If the region has a drive letter, use the drive letter
+ // to get the info via the Windows API. Otherwise we'll
+ // have to use the NT API.
+
+ regionData = PERSISTENT_DATA(regionDescriptor);
+
+ if (regionData) {
+ if (regionData->DriveLetter == assignList->DriveLetter) {
+ partitionNumber = regionDescriptor->Reserved->Partition->PartitionNumber;
+ regionDescriptor->PartitionNumber = partitionNumber;
+ break;
+ }
+ }
+ }
+ }
+
+ if (partitionNumber) {
+ HANDLE handle;
+ ULONG status;
+
+ // set up the new NT path.
+
+ wsprintf((LPTSTR) targetPath,
+ "%s\\Partition%d",
+ GetDiskName(assignList->DiskNumber),
+ partitionNumber);
+
+ // Set up the DOS name.
+
+ newName[1] = (TCHAR)':';
+ newName[2] = 0;
+
+ if (assignList->MoveLetter) {
+
+ // The letter must be removed before it
+ // can be assigned.
+
+ newName[0] = (TCHAR)assignList->OriginalLetter;
+ NetworkRemoveShare((LPCTSTR) newName);
+ DefineDosDevice(DDD_REMOVE_DEFINITION, (LPCTSTR) newName, (LPCTSTR) NULL);
+ newName[0] = (TCHAR)assignList->DriveLetter;
+
+ } else {
+ newName[0] = (TCHAR)assignList->DriveLetter;
+ }
+
+ // Assign the name - don't worry about errors for now.
+
+ DefineDosDevice(DDD_RAW_TARGET_PATH, (LPCTSTR) newName, (LPCTSTR) targetPath);
+ NetworkShare((LPCTSTR) newName);
+
+ // Some of the file systems do not actually dismount
+ // when requested. Instead, they set a verification
+ // bit in the device object. Due to dynamic partitioning
+ // this bit may get cleared by the process of the
+ // repartitioning and the file system will then
+ // assume it is still mounted on a new access.
+ // To get around this problem, new drive letters
+ // are always locked and dismounted on creation.
+
+ status = LowOpenDriveLetter(assignList->DriveLetter,
+ &handle);
+
+ if (NT_SUCCESS(status)) {
+
+ // Lock the drive to insure that no other access is occurring
+ // to the volume.
+
+ status = LowLockDrive(handle);
+
+ if (NT_SUCCESS(status)) {
+ LowUnlockDrive(handle);
+ }
+ LowCloseDisk(handle);
+ }
+
+ } else {
+ ErrorDialog(MSG_INTERNAL_LETTER_ASSIGN_ERROR);
+ }
+ }
+
+ prevEntry = assignList;
+ assignList = assignList->Next;
+ Free(prevEntry);
+ }
+ AssignDriveLetterListHead = NULL;
+}
+
+LONG
+CommitInternalLockDriveLetter(
+ IN PDRIVE_LOCKLIST LockListEntry
+ )
+
+/*++
+
+Routine Description:
+
+ Support routine to perform the locking of a drive letter based on
+ the locklist entry given.
+
+Arguments:
+
+ LockListEntry - The information about what to lock.
+
+Return Values:
+
+ zero - success
+ non-zero failure
+
+--*/
+
+{
+ ULONG status;
+
+ // Lock the disk and save the handle.
+
+ status = LowOpenDriveLetter(LockListEntry->DriveLetter,
+ &LockListEntry->LockHandle);
+
+ if (!NT_SUCCESS(status)) {
+ return 1;
+ }
+
+
+ // Lock the drive to insure that no other access is occurring
+ // to the volume.
+
+ status = LowLockDrive(LockListEntry->LockHandle);
+
+ if (!NT_SUCCESS(status)) {
+ LowCloseDisk(LockListEntry->LockHandle);
+ return 1;
+ }
+
+ LockListEntry->CurrentlyLocked = TRUE;
+ return 0;
+}
+
+LONG
+CommitToLockList(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN BOOL RemoveDriveLetter,
+ IN BOOL LockNow,
+ IN BOOL FailOk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds the given drive into the lock list for processing
+ when a commit occurs. If the LockNow flag is set it indicates that
+ the drive letter is to be immediately locked if it is to go in the
+ lock letter list. If this locking fails an error is returned.
+
+Arguments:
+
+ RegionDescriptor - the region for the drive to lock.
+ RemoveDriveLetter - remove the letter when performing the unlock.
+ LockNow - If the letter is inserted in the list - lock it now.
+ FailOk - It is ok to fail the lock - used for disabled FT sets.
+
+Return Values:
+
+ non-zero - failure to add to list.
+
+--*/
+
+{
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(RegionDescriptor);
+ PDRIVE_LOCKLIST lockListEntry;
+ UCHAR driveLetter;
+ ULONG diskNumber;
+
+ if (!regionData) {
+
+ // without region data there is no need to be on the lock list.
+
+ return 0;
+ }
+
+ // See if this drive letter is already in the lock list.
+
+ driveLetter = regionData->DriveLetter;
+
+ if ((driveLetter == NO_DRIVE_LETTER_YET) || (driveLetter == NO_DRIVE_LETTER_EVER)) {
+
+ // There is no drive letter to lock.
+
+ CommitDueToDelete = RemoveDriveLetter;
+ return 0;
+ }
+
+ if (!regionData->VolumeExists) {
+ PASSIGN_LIST assignList,
+ prevEntry;
+
+ // This item has never been created so no need to put it in the
+ // lock list. But it does need to be removed from the assign
+ // letter list.
+
+ prevEntry = NULL;
+ assignList = AssignDriveLetterListHead;
+ while (assignList) {
+
+ // If a match is found remove it from the list.
+
+ if (assignList->DriveLetter == driveLetter) {
+ if (prevEntry) {
+ prevEntry->Next = assignList->Next;
+ } else {
+ AssignDriveLetterListHead = assignList->Next;
+ }
+
+ Free(assignList);
+ assignList = NULL;
+ } else {
+
+ prevEntry = assignList;
+ assignList = assignList->Next;
+ }
+ }
+ return 0;
+ }
+
+ diskNumber = RegionDescriptor->Disk;
+ lockListEntry = DriveLockListHead;
+ while (lockListEntry) {
+ if (lockListEntry->DriveLetter == driveLetter) {
+
+ // Already in the list -- update when to lock and unlock
+
+ if (diskNumber < lockListEntry->LockOnDiskNumber) {
+ lockListEntry->LockOnDiskNumber = diskNumber;
+ }
+
+ if (diskNumber > lockListEntry->UnlockOnDiskNumber) {
+ lockListEntry->UnlockOnDiskNumber = diskNumber;
+ }
+
+ // Already in the lock list and information for locking set up.
+ // Check to see if this should be a LockNow request.
+
+ if (LockNow) {
+ if (!lockListEntry->CurrentlyLocked) {
+
+ // Need to perform the lock.
+
+ if (CommitInternalLockDriveLetter(lockListEntry)) {
+
+ // Leave the element in the list
+
+ return 1;
+ }
+ }
+ }
+ return 0;
+
+ }
+ lockListEntry = lockListEntry->Next;
+ }
+
+ lockListEntry = (PDRIVE_LOCKLIST) Malloc(sizeof(DRIVE_LOCKLIST));
+
+ if (!lockListEntry) {
+ return 1;
+ }
+
+ // set up the lock list entry.
+
+ lockListEntry->LockHandle = NULL;
+ lockListEntry->PartitionNumber = RegionDescriptor->PartitionNumber;
+ lockListEntry->DriveLetter = driveLetter;
+ lockListEntry->RemoveOnUnlock = RemoveDriveLetter;
+ lockListEntry->CurrentlyLocked = FALSE;
+ lockListEntry->FailOk = FailOk;
+ lockListEntry->DiskNumber = lockListEntry->UnlockOnDiskNumber =
+ lockListEntry->LockOnDiskNumber = diskNumber;
+
+ if (LockNow) {
+ if (CommitInternalLockDriveLetter(lockListEntry)) {
+
+ // Do not add this to the list.
+
+ Free(lockListEntry);
+ return 1;
+ }
+ }
+
+ // place it at the front of the chain.
+
+ lockListEntry->Next = DriveLockListHead;
+ DriveLockListHead = lockListEntry;
+ return 0;
+}
+
+LONG
+CommitLockVolumes(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will go through any drive letters inserted in the lock list
+ for the given disk number and attempt to lock the volumes. Currently,
+ this routine locks all of the drives letters in the lock list when
+ called the first time (i.e. when Disk == 0).
+
+Arguments:
+
+ Disk - the index into the disk table.
+
+Return Values:
+
+ non-zero - failure to lock the items in the list.
+
+--*/
+
+{
+ PDRIVE_LOCKLIST lockListEntry;
+
+ if (Disk) {
+ return 0;
+ }
+
+
+ for (lockListEntry = DriveLockListHead; lockListEntry; lockListEntry = lockListEntry->Next) {
+
+ // Lock the disk. Return on any failure if that is the
+ // requested action for the entry. It is the responsibility
+ // of the caller to release any successful locks.
+
+ if (!lockListEntry->CurrentlyLocked) {
+ if (CommitInternalLockDriveLetter(lockListEntry)) {
+ if (!lockListEntry->FailOk) {
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+LONG
+CommitUnlockVolumes(
+ IN ULONG Disk,
+ IN BOOLEAN FreeList
+ )
+
+/*++
+
+Routine Description:
+
+ Go through and unlock any locked volumes in the locked list for the
+ given disk. Currently this routine waits until the last disk has
+ been processed, then unlocks all disks.
+
+Arguments:
+
+ Disk - the index into the disk table.
+ FreeList - Clean up the list as unlocks are performed or don't
+
+Return Values:
+
+ non-zero - failure to lock the items in the list.
+
+--*/
+
+{
+ PDRIVE_LOCKLIST lockListEntry,
+ previousLockListEntry;
+ TCHAR name[4];
+
+ if (Disk != GetDiskCount()) {
+ return 0;
+ }
+
+ lockListEntry = DriveLockListHead;
+ if (FreeList) {
+ DriveLockListHead = NULL;
+ }
+ while (lockListEntry) {
+
+ // Unlock the disk.
+
+ if (lockListEntry->CurrentlyLocked) {
+
+ if (FreeList && lockListEntry->RemoveOnUnlock) {
+
+ // set up the new dos name and NT path.
+
+ name[0] = (TCHAR)lockListEntry->DriveLetter;
+ name[1] = (TCHAR)':';
+ name[2] = 0;
+
+ NetworkRemoveShare((LPCTSTR) name);
+ if (!DefineDosDevice(DDD_REMOVE_DEFINITION, (LPCTSTR) name, (LPCTSTR) NULL)) {
+
+ // could not remove name!!?
+
+ }
+ }
+ LowUnlockDrive(lockListEntry->LockHandle);
+ LowCloseDisk(lockListEntry->LockHandle);
+ }
+
+ // Move to the next entry. If requested free this entry.
+
+ previousLockListEntry = lockListEntry;
+ lockListEntry = lockListEntry->Next;
+ if (FreeList) {
+ Free(previousLockListEntry);
+ }
+ }
+ return 0;
+}
+
+LETTER_ASSIGNMENT_RESULT
+CommitDriveLetter(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN CHAR OldDrive,
+ IN CHAR NewDrive
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will update the drive letter information in the registry and
+ (if the update works) it will attempt to move the current drive letter
+ to the new one via DefineDosDevice()
+
+Arguments:
+
+ RegionDescriptor - the region that should get the letter.
+ NewDrive - the new drive letter for the volume.
+
+Return Value:
+
+ 0 - the assignment failed.
+ 1 - if the assigning of the letter occurred interactively.
+ 2 - must reboot to do the letter.
+
+--*/
+
+{
+ PPERSISTENT_REGION_DATA regionData;
+ PDRIVE_LOCKLIST lockListEntry;
+ PASSIGN_LIST assignList;
+ HANDLE handle;
+ TCHAR newName[4];
+ WCHAR targetPath[100];
+ int doIt;
+ STATUS_CODE status = ERROR_SEVERITY_ERROR;
+ LETTER_ASSIGNMENT_RESULT result = Failure;
+
+ regionData = PERSISTENT_DATA(RegionDescriptor);
+
+ // check the assign letter list for a match.
+ // If the letter is there, then just update the list
+ // otherwise continue on with the action.
+
+ assignList = AssignDriveLetterListHead;
+ while (assignList) {
+
+ if (assignList->DriveLetter == (UCHAR)OldDrive) {
+ assignList->DriveLetter = (UCHAR)NewDrive;
+ return Complete;
+ }
+ assignList = assignList->Next;
+ }
+
+ // Search to see if the drive is currently locked.
+
+ for (lockListEntry = DriveLockListHead;
+ lockListEntry;
+ lockListEntry = lockListEntry->Next) {
+
+ if ((lockListEntry->DiskNumber == RegionDescriptor->Disk) &&
+ (lockListEntry->PartitionNumber == RegionDescriptor->PartitionNumber)) {
+
+ if (lockListEntry->CurrentlyLocked) {
+ status = 0;
+ }
+
+ // found the match no need to continue searching.
+
+ break;
+ }
+ }
+
+ if (!NT_SUCCESS(status)) {
+
+ // See if the drive can be locked.
+
+ status = LowOpenPartition(GetDiskName(RegionDescriptor->Disk),
+ RegionDescriptor->PartitionNumber,
+ &handle);
+
+ if (!NT_SUCCESS(status)) {
+ return Failure;
+ }
+
+ // Lock the drive to insure that no other access is occurring
+ // to the volume.
+
+ status = LowLockDrive(handle);
+
+ if (!NT_SUCCESS(status)) {
+
+ if (IsPagefileOnDrive(OldDrive)) {
+
+ ErrorDialog(MSG_CANNOT_LOCK_PAGEFILE);
+ } else {
+
+ ErrorDialog(MSG_CANNOT_LOCK_TRY_AGAIN);
+ }
+ doIt = ConfirmationDialog(MSG_SCHEDULE_REBOOT, MB_ICONQUESTION | MB_YESNO);
+
+ LowCloseDisk(handle);
+ if (doIt == IDYES) {
+ RegistryChanged = TRUE;
+ RestartRequired = TRUE;
+ return MustReboot;
+ }
+ return Failure;
+ }
+ } else {
+
+ // This drive was found in the lock list and is already
+ // in the locked state. It is safe to continue with
+ // the drive letter assignment.
+
+ }
+
+ doIt = ConfirmationDialog(MSG_DRIVE_RENAME_WARNING, MB_ICONQUESTION | MB_YESNOCANCEL);
+
+ if (doIt != IDYES) {
+
+ LowUnlockDrive(handle);
+ LowCloseDisk(handle);
+ return Failure;
+ }
+
+ // Update the registry first. This way if something goes wrong
+ // the new letter will arrive on reboot.
+
+ if (!DiskRegistryAssignDriveLetter(Disks[RegionDescriptor->Disk]->Signature,
+ FdGetExactOffset(RegionDescriptor),
+ FdGetExactSize(RegionDescriptor, FALSE),
+ (UCHAR)((NewDrive == NO_DRIVE_LETTER_EVER) ? (UCHAR)' ' : (UCHAR)NewDrive))) {
+
+ // Registry update failed.
+
+ return Failure;
+ }
+
+ // It is safe to change the drive letter. First, remove the
+ // existing letter.
+
+ newName[0] = (TCHAR)OldDrive;
+ newName[1] = (TCHAR)':';
+ newName[2] = 0;
+
+ NetworkRemoveShare((LPCTSTR) newName);
+ if (!DefineDosDevice(DDD_REMOVE_DEFINITION, (LPCTSTR) newName, (LPCTSTR) NULL)) {
+
+ LowUnlockDrive(handle);
+ LowCloseDisk(handle);
+ RegistryChanged = TRUE;
+ return Failure;
+ }
+
+ if (NewDrive != NO_DRIVE_LETTER_EVER) {
+
+ // set up the new dos name and NT path.
+
+ newName[0] = (TCHAR)NewDrive;
+ newName[1] = (TCHAR)':';
+ newName[2] = 0;
+
+ wsprintf((LPTSTR) targetPath,
+ "%s\\Partition%d",
+ GetDiskName(RegionDescriptor->Disk),
+ RegionDescriptor->PartitionNumber);
+
+ if (DefineDosDevice(DDD_RAW_TARGET_PATH, (LPCTSTR) newName, (LPCTSTR) targetPath)) {
+ result = Complete;
+ } else {
+ RegistryChanged = TRUE;
+ }
+ NetworkShare((LPCTSTR) newName);
+ } else {
+ result = Complete;
+ }
+
+ // Force the file system to dismount
+
+ LowUnlockDrive(handle);
+ LowCloseDisk(handle);
+ return result;
+}
+
+VOID
+CommitUpdateRegionStructures(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called ONLY after a successful commit of a new partitioning
+ scheme for the system. Its is responsible for walking through the
+ region arrays for each of the disks and updating the regions to indicate
+ their transition from being "desired" to being actually committed
+ to disk
+
+Arguments:
+
+ None
+
+Return Values:
+
+ None
+
+--*/
+
+{
+ PDISKSTATE diskState;
+ PREGION_DESCRIPTOR regionDescriptor;
+ PPERSISTENT_REGION_DATA regionData;
+ ULONG regionNumber,
+ diskNumber;
+
+ // search through all disks in the system.
+
+ for (diskNumber = 0, diskState = Disks[0]; diskNumber < DiskCount; diskState = Disks[++diskNumber]) {
+
+ // Look at every region array entry and update the values
+ // to indicate that this region now exists.
+
+ for (regionNumber = 0; regionNumber < diskState->RegionCount; regionNumber++) {
+
+ regionDescriptor = &diskState->RegionArray[regionNumber];
+ if (regionDescriptor->Reserved) {
+ if (regionDescriptor->Reserved->Partition) {
+ regionDescriptor->Reserved->Partition->CommitMirrorBreakNeeded = FALSE;
+ }
+ }
+ regionData = PERSISTENT_DATA(regionDescriptor);
+ if ((regionData) && (!regionData->VolumeExists)) {
+
+ // By definition and assumption of this routine,
+ // this region has just been committed to disk.
+
+ regionData->VolumeExists = TRUE;
+
+ if (regionData->TypeName) {
+ Free(regionData->TypeName);
+ }
+ regionData->TypeName = Malloc((lstrlenW(wszUnformatted)+1)*sizeof(WCHAR));
+ lstrcpyW(regionData->TypeName, wszUnformatted);
+ }
+ }
+ }
+}
+
+VOID
+CommitAllChanges(
+ IN PVOID Param
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will go through all of the region descriptors and commit
+ any changes that have occurred to disk. Then it "re-initializes"
+ Disk Administrator and start the display/work process over again.
+
+Arguments:
+
+ Param - undefined for now
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ DWORD action,
+ errorCode;
+ ULONG diskCount,
+ temp;
+ BOOL profileWritten,
+ changesMade,
+ mustReboot,
+ configureFt;
+
+ SetCursor(hcurWait);
+ diskCount = GetDiskCount();
+
+ // Determine whether any disks have been changed, and whether
+ // the system must be rebooted. The system must be rebooted
+ // if the registry has changed, if any non-removable disk has
+ // changed, or if any removable disk that was not originally
+ // unpartitioned has changed.
+
+ changesMade = configureFt = FALSE;
+ mustReboot = RestartRequired;
+
+ for (temp=0; temp<diskCount; temp++) {
+ if (HavePartitionsBeenChanged(temp)) {
+
+ changesMade = TRUE;
+ break;
+ }
+ }
+
+ profileWritten = FALSE;
+
+ // Determine if the commit can be done without a reboot.
+ // If FT is in the system then it must be notified to
+ // reconfigure if a reboot is not performed. If it is
+ // not in the system, but the new disk information requires
+ // it, then a reboot must be forced.
+
+ if (FtInstalled()) {
+ configureFt = TRUE;
+ }
+ if (NewConfigurationRequiresFt()) {
+ if (!configureFt) {
+
+ // The FT driver is not loaded currently.
+
+ mustReboot = TRUE;
+ } else {
+
+ // If the system is going to be rebooted, don't
+ // have FT reconfigure prior to shutdown.
+
+ if (mustReboot) {
+ configureFt = FALSE;
+ }
+ }
+ }
+
+ if (RegistryChanged | changesMade | RestartRequired) {
+
+ if (RestartRequired) {
+ action = IDYES;
+ } else {
+ action = ConfirmationDialog(MSG_CONFIRM_EXIT, MB_ICONQUESTION | MB_YESNOCANCEL);
+ }
+
+ if (action == IDYES) {
+ errorCode = CommitLockVolumes(0);
+ if (errorCode) {
+
+ // could not lock all volumes
+
+ SetCursor(hcurNormal);
+ ErrorDialog(MSG_CANNOT_LOCK_FOR_COMMIT);
+ CommitUnlockVolumes(diskCount, FALSE);
+ return;
+ }
+
+ if (mustReboot) {
+
+ SetCursor(hcurNormal);
+ if (RestartRequired) {
+ action = IDYES;
+ } else {
+ action = ConfirmationDialog(MSG_REQUIRE_REBOOT, MB_ICONQUESTION | MB_YESNO);
+ }
+
+ if (action != IDYES) {
+
+ CommitUnlockVolumes(diskCount, FALSE);
+ return;
+ }
+ }
+
+ SetCursor(hcurWait);
+ errorCode = CommitChanges();
+ CommitUnlockVolumes(diskCount, TRUE);
+ SetCursor(hcurNormal);
+
+ if (errorCode != NO_ERROR) {
+ ErrorDialog(MSG_BAD_CONFIG_SET);
+ PostQuitMessage(0);
+ } else {
+ ULONG OldBootPartitionNumber,
+ NewBootPartitionNumber;
+ CHAR OldNumberString[8],
+ NewNumberString[8];
+ DWORD MsgCode;
+
+ // Update the configuration registry
+
+ errorCode = SaveFt();
+
+ // Check if FTDISK drive should reconfigure.
+
+ if (configureFt) {
+
+ // Issue device control to ftdisk driver to reconfigure.
+
+ FtConfigure();
+ }
+
+ // Register autochk to fix up file systems
+ // in newly extended volume sets, if necessary
+
+ if (RegisterFileSystemExtend()) {
+ mustReboot = TRUE;
+ }
+
+ // Determine if the FT driver must be enabled.
+
+ if (DiskRegistryRequiresFt() == TRUE) {
+ if (!FtInstalled()) {
+ mustReboot = TRUE;
+ }
+ DiskRegistryEnableFt();
+ } else {
+ DiskRegistryDisableFt();
+ }
+
+ if (errorCode == NO_ERROR) {
+ InfoDialog(MSG_OK_COMMIT);
+ } else {
+ ErrorDialog(MSG_BAD_CONFIG_SET);
+ }
+
+ // Has the partition number of the boot
+ // partition changed?
+
+ if (BootPartitionNumberChanged( &OldBootPartitionNumber,&NewBootPartitionNumber)) {
+#if i386
+ MsgCode = MSG_BOOT_PARTITION_CHANGED_X86;
+#else
+ MsgCode = MSG_BOOT_PARTITION_CHANGED_ARC;
+#endif
+ sprintf(OldNumberString, "%d", OldBootPartitionNumber);
+ sprintf(NewNumberString, "%d", NewBootPartitionNumber);
+ InfoDialog(MsgCode, OldNumberString, NewNumberString);
+ }
+
+ ClearCommittedDiskInformation();
+
+ if (UpdateMbrOnDisk) {
+
+ UpdateMasterBootCode(UpdateMbrOnDisk);
+ UpdateMbrOnDisk = 0;
+ }
+
+ // Reboot if necessary.
+
+ if (mustReboot) {
+
+ SetCursor(hcurWait);
+ Sleep(5000);
+ SetCursor(hcurNormal);
+ FdShutdownTheSystem();
+ profileWritten = TRUE;
+ }
+ CommitAssignLetterList();
+ CommitUpdateRegionStructures();
+ RegistryChanged = FALSE;
+ CommitDueToDelete = CommitDueToMirror = FALSE;
+ TotalRedrawAndRepaint();
+ AdjustMenuAndStatus();
+ }
+ } else if (action == IDCANCEL) {
+ return; // don't exit
+ } else {
+ FDASSERT(action == IDNO);
+ }
+ }
+}
+
+VOID
+FtConfigure(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine calls the FTDISK driver to ask it to reconfigure as changes
+ have been made in the registry.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ OBJECT_ATTRIBUTES objectAttributes;
+ STRING ntFtName;
+ IO_STATUS_BLOCK statusBlock;
+ UNICODE_STRING unicodeDeviceName;
+ NTSTATUS status;
+ HANDLE handle;
+
+ // Open ft control object.
+
+ RtlInitString(&ntFtName,
+ "\\Device\\FtControl");
+ RtlAnsiStringToUnicodeString(&unicodeDeviceName,
+ &ntFtName,
+ TRUE);
+ InitializeObjectAttributes(&objectAttributes,
+ &unicodeDeviceName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ status = DmOpenFile(&handle,
+ SYNCHRONIZE | FILE_ANY_ACCESS,
+ &objectAttributes,
+ &statusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT );
+ RtlFreeUnicodeString(&unicodeDeviceName);
+
+ if (!NT_SUCCESS(status)) {
+ return;
+ }
+
+ // Issue device control to reconfigure FT.
+
+ NtDeviceIoControlFile(handle,
+ NULL,
+ NULL,
+ NULL,
+ &statusBlock,
+ FT_CONFIGURE,
+ NULL,
+ 0L,
+ NULL,
+ 0L);
+
+ DmClose(handle);
+ return;
+}
+
+BOOL
+CommitAllowed(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Determine if it is ok to perform a commit.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ TRUE if it is ok to commit and there is something to commit
+ FALSE otherwise
+
+--*/
+
+{
+ if (DriveLockListHead ||
+ AssignDriveLetterListHead ||
+ CommitDueToDelete ||
+ CommitDueToMirror ||
+ CommitDueToExtended) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+VOID
+RescanDevices(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs all actions necessary to dynamically rescan
+ device buses (i.e. SCSI) and get the appropriate driver support loaded.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PSCSI_ADAPTER_BUS_INFO adapterInfo;
+ PSCSI_BUS_DATA busData;
+ PSCSI_INQUIRY_DATA inquiryData;
+ TCHAR physicalName[32];
+ TCHAR driveName[32];
+ BYTE driveBuffer[32];
+ BYTE physicalBuffer[32];
+ HANDLE volumeHandle;
+ STRING string;
+ UNICODE_STRING unicodeString;
+ UNICODE_STRING physicalString;
+ OBJECT_ATTRIBUTES objectAttributes;
+ NTSTATUS ntStatus;
+ IO_STATUS_BLOCK statusBlock;
+ BOOLEAN diskFound,
+ cdromFound;
+ ULONG bytesTransferred,
+ i,
+ j,
+ deviceNumber,
+ currentPort,
+ numberOfPorts,
+ percentComplete,
+ portNumber;
+
+ diskFound = FALSE;
+ cdromFound = FALSE;
+
+ // Determine how many buses there are
+
+ portNumber = numberOfPorts = percentComplete = 0;
+ while (TRUE) {
+
+ memset(driveBuffer, 0, sizeof(driveBuffer));
+ sprintf(driveBuffer, "\\\\.\\Scsi%d:", portNumber);
+
+ // Open the SCSI port with the DOS name.
+
+ volumeHandle = CreateFile(driveBuffer,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ 0);
+
+ if (volumeHandle == INVALID_HANDLE_VALUE) {
+ break;
+ }
+
+ CloseHandle(volumeHandle);
+ numberOfPorts++;
+ portNumber++;
+ }
+
+ currentPort = 1;
+ portNumber = 0;
+
+ // Perform the scsi bus rescan.
+
+ while (TRUE) {
+
+ memset(driveBuffer, 0, sizeof(driveBuffer));
+ sprintf(driveBuffer, "\\\\.\\Scsi%d:", portNumber);
+
+ // Open the SCSI port with the DOS name.
+
+ volumeHandle = CreateFile(driveBuffer,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ 0);
+
+ if (volumeHandle == INVALID_HANDLE_VALUE) {
+ break;
+ }
+
+ // Issue rescan device control.
+
+ if (!DeviceIoControl(volumeHandle,
+ IOCTL_SCSI_RESCAN_BUS,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &bytesTransferred,
+ NULL)) {
+
+ CloseHandle(volumeHandle);
+ break;
+ }
+
+ percentComplete = (currentPort * 100) / numberOfPorts;
+
+ if (percentComplete < 100) {
+ PostMessage(InitDlg,
+ WM_USER,
+ percentComplete,
+ 0);
+ }
+
+ currentPort++;
+
+ // Get a big chuck of memory to store the SCSI bus data.
+
+ adapterInfo = malloc(0x4000);
+
+ if (adapterInfo == NULL) {
+ CloseHandle(volumeHandle);
+ goto finish;
+ }
+
+ // Issue device control to get configuration information.
+
+ if (!DeviceIoControl(volumeHandle,
+ IOCTL_SCSI_GET_INQUIRY_DATA,
+ NULL,
+ 0,
+ adapterInfo,
+ 0x4000,
+ &bytesTransferred,
+ NULL)) {
+
+ CloseHandle(volumeHandle);
+ goto finish;
+ }
+
+
+ for (i = 0; i < adapterInfo->NumberOfBuses; i++) {
+
+ busData = &adapterInfo->BusData[i];
+ inquiryData =
+ (PSCSI_INQUIRY_DATA)((PUCHAR)adapterInfo + busData->InquiryDataOffset);
+
+ for (j = 0; j < busData->NumberOfLogicalUnits; j++) {
+
+ // Check if device is claimed.
+
+ if (!inquiryData->DeviceClaimed) {
+
+ // Determine the perpherial type.
+
+ switch (inquiryData->InquiryData[0] & 0x1f) {
+ case DIRECT_ACCESS_DEVICE:
+ diskFound = TRUE;
+ break;
+
+ case READ_ONLY_DIRECT_ACCESS_DEVICE:
+ cdromFound = TRUE;
+ break;
+
+ case OPTICAL_DEVICE:
+ diskFound = TRUE;
+ break;
+ }
+ }
+
+ // Get next device data.
+
+ inquiryData =
+ (PSCSI_INQUIRY_DATA)((PUCHAR)adapterInfo + inquiryData->NextInquiryDataOffset);
+ }
+ }
+
+ free(adapterInfo);
+ CloseHandle(volumeHandle);
+
+ portNumber++;
+ }
+
+ if (diskFound) {
+
+ // Send IOCTL_DISK_FIND_NEW_DEVICES commands to each existing disk.
+
+ deviceNumber = 0;
+ while (TRUE) {
+
+ memset(driveBuffer, 0, sizeof(driveBuffer));
+ sprintf(driveBuffer, "\\Device\\Harddisk%d\\Partition0", deviceNumber);
+
+ RtlInitString(&string, driveBuffer);
+ ntStatus = RtlAnsiStringToUnicodeString(&unicodeString,
+ &string,
+ TRUE);
+ if (!NT_SUCCESS(ntStatus)) {
+ break;
+ }
+ InitializeObjectAttributes(&objectAttributes,
+ &unicodeString,
+ 0,
+ NULL,
+ NULL);
+ ntStatus = DmOpenFile(&volumeHandle,
+ FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE,
+ &objectAttributes,
+ &statusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT);
+
+ if (!NT_SUCCESS(ntStatus)) {
+ RtlFreeUnicodeString(&unicodeString);
+ break;
+ }
+
+ // Issue find device device control.
+
+ if (!DeviceIoControl(volumeHandle,
+ IOCTL_DISK_FIND_NEW_DEVICES,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &bytesTransferred,
+ NULL)) {
+
+ }
+ DmClose(volumeHandle);
+
+ // see if the physicaldrive# symbolic link is present
+
+ sprintf(physicalBuffer, "\\DosDevices\\PhysicalDrive%d", deviceNumber);
+ deviceNumber++;
+
+ RtlInitString(&string, physicalBuffer);
+ ntStatus = RtlAnsiStringToUnicodeString(&physicalString,
+ &string,
+ TRUE);
+ if (!NT_SUCCESS(ntStatus)) {
+ continue;
+ }
+ InitializeObjectAttributes(&objectAttributes,
+ &physicalString,
+ 0,
+ NULL,
+ NULL);
+ ntStatus = DmOpenFile(&volumeHandle,
+ FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE,
+ &objectAttributes,
+ &statusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT);
+
+ if (!NT_SUCCESS(ntStatus)) {
+ ULONG index;
+ ULONG dest;
+
+ // Name is not there - create it. This copying
+ // is done in case this code should ever become
+ // unicode and the types for the two strings would
+ // actually be different.
+ //
+ // Copy only the portion of the physical name
+ // that is in the \dosdevices\ directory
+
+ for (dest = 0, index = 12; TRUE; index++, dest++) {
+
+ physicalName[dest] = (TCHAR)physicalBuffer[index];
+ if (!physicalName[dest]) {
+ break;
+ }
+ }
+
+ // Copy all of the NT namespace name.
+
+ for (index = 0; TRUE; index++) {
+
+ driveName[index] = (TCHAR) driveBuffer[index];
+ if (!driveName[index]) {
+ break;
+ }
+ }
+
+ DefineDosDevice(DDD_RAW_TARGET_PATH,
+ (LPCTSTR) physicalName,
+ (LPCTSTR) driveName);
+
+ } else {
+ DmClose(volumeHandle);
+ }
+
+ // free allocated memory for unicode string.
+
+ RtlFreeUnicodeString(&unicodeString);
+ RtlFreeUnicodeString(&physicalString);
+ }
+ }
+
+ if (cdromFound) {
+
+ // Send IOCTL_CDROM_FIND_NEW_DEVICES commands to each existing cdrom.
+
+ deviceNumber = 0;
+ while (TRUE) {
+
+ memset(driveBuffer, 0, sizeof(driveBuffer));
+ sprintf(driveBuffer, "\\Device\\Cdrom%d", deviceNumber);
+ RtlInitString(&string, driveBuffer);
+
+ ntStatus = RtlAnsiStringToUnicodeString(&unicodeString,
+ &string,
+ TRUE);
+
+ if (!NT_SUCCESS(ntStatus)) {
+ break;
+ }
+
+ InitializeObjectAttributes(&objectAttributes,
+ &unicodeString,
+ 0,
+ NULL,
+ NULL);
+
+ ntStatus = DmOpenFile(&volumeHandle,
+ FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE,
+ &objectAttributes,
+ &statusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT);
+
+ if (!NT_SUCCESS(ntStatus)) {
+ break;
+ }
+
+ // Issue find device device control.
+
+ if (!DeviceIoControl(volumeHandle,
+ IOCTL_CDROM_FIND_NEW_DEVICES,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &bytesTransferred,
+ NULL)) {
+ }
+
+ CloseHandle(volumeHandle);
+ deviceNumber++;
+ }
+ }
+finish:
+ PostMessage(InitDlg,
+ WM_USER,
+ 100,
+ 0);
+ return;
+}
diff --git a/private/utils/fdisk/dblspace.c b/private/utils/fdisk/dblspace.c
new file mode 100644
index 000000000..a24a9529d
--- /dev/null
+++ b/private/utils/fdisk/dblspace.c
@@ -0,0 +1,1710 @@
+
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ dblspace.c
+
+Abstract:
+
+ This module contains the set of routines that deal with double space
+ dialogs and support.
+
+Author:
+
+ Bob Rinne (bobri) 11/15/93
+
+Environment:
+
+ User process.
+
+Notes:
+
+Revision History:
+
+--*/
+
+#include "fdisk.h"
+#include "fmifs.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <wchar.h>
+#include <string.h>
+
+#ifdef DOUBLE_SPACE_SUPPORT_INCLUDED
+
+PREGION_DESCRIPTOR RegionForDblSpaceVolume;
+
+ULONG DblSpaceThresholdSizes[] = { 10, 40, 100, (ULONG) -1 };
+
+#define NUMBER_PARSEFORMAT_ITEMS 4
+char *DblSpaceIniFileName = "%c:\\dblspace.ini";
+char *DblSpaceWildCardFileName = "%c:\\dblspace.*";
+char *DblSpaceParseFormat = "%s %s %d %d";
+
+// All double space structures are chained into the base chain
+// this allows for ease in initialization to determine which are
+// mounted. This chain is only used for initialization.
+
+PDBLSPACE_DESCRIPTOR DblChainBase = NULL;
+PDBLSPACE_DESCRIPTOR DblChainLast = NULL;
+
+extern BOOLEAN DoubleSpaceSupported;
+
+#define DblSpaceMountDrive(REGDESC, DBLSPACE) \
+ DblSpaceChangeState(REGDESC, DBLSPACE, TRUE)
+#define DblSpaceDismountDrive(REGDESC, DBLSPACE) \
+ DblSpaceChangeState(REGDESC, DBLSPACE, FALSE)
+
+VOID
+DblSpaceUpdateIniFile(
+ IN PREGION_DESCRIPTOR RegionDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is left around in case this code must update DOS
+ based .ini files. Currently it does nothing.
+
+Arguments:
+
+ The region with the double space volumes.
+
+Return Value
+
+ None
+
+--*/
+
+{
+}
+
+ULONG
+DblSpaceChangeState(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN PDBLSPACE_DESCRIPTOR DblSpacePtr,
+ IN BOOL Mount
+ )
+
+/*++
+
+Routine Description:
+
+ Based on the value of Mount, either mount the volume or
+ dismount the Double Space volume
+
+Arguments:
+
+ RegionDescriptor - The region containing the double space volume
+ DriveLetter - The drive letter of the double space volume involved.
+ Mount - TRUE == perform a mount function
+ FALSE == dismount the volume
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(RegionDescriptor);
+ WCHAR dblSpaceUniqueName[32];
+ ULONG index;
+ ULONG result = 0;
+
+ SetCursor(hcurWait);
+
+ if (Mount) {
+
+ // Call fmifs mount routine.
+
+ result = FmIfsMountDblspace(DblSpacePtr->FileName,
+ regionData->DriveLetter,
+ DblSpacePtr->NewDriveLetter);
+
+ } else {
+
+ // Call fmifs dismount routine.
+
+ result = FmIfsDismountDblspace(DblSpacePtr->DriveLetter);
+ }
+
+ if (!result) {
+ DblSpacePtr->Mounted = Mount;
+ if (Mount) {
+ DblSpacePtr->DriveLetter = DblSpacePtr->NewDriveLetter;
+ MarkDriveLetterUsed(DblSpacePtr->DriveLetter);
+ } else {
+ TCHAR name[4];
+
+ // remove the drive letter.
+
+ name[0] = (TCHAR)DblSpacePtr->DriveLetter;
+ name[1] = (TCHAR)':';
+ name[2] = 0;
+
+ DefineDosDevice(DDD_REMOVE_DEFINITION, (LPCTSTR) name, (LPCTSTR) NULL);
+
+ // Now update the internal structures.
+
+ MarkDriveLetterFree(DblSpacePtr->DriveLetter);
+ DblSpacePtr->DriveLetter = ' ';
+ }
+
+ if (!IsDiskRemovable[RegionDescriptor->Disk]) {
+
+ dblSpaceUniqueName[0] = (WCHAR) regionData->DriveLetter;
+ dblSpaceUniqueName[1] = (WCHAR) ':';
+ dblSpaceUniqueName[2] = (WCHAR) '\\';
+
+ index = 0;
+ while (dblSpaceUniqueName[index + 3] = DblSpacePtr->FileName[index]) {
+ index++;
+ }
+
+ result = DiskRegistryAssignDblSpaceLetter(dblSpaceUniqueName,
+ (WCHAR) DblSpacePtr->DriveLetter);
+ }
+ }
+ SetCursor(hcurNormal);
+ return result;
+}
+
+PDBLSPACE_DESCRIPTOR
+DblSpaceCreateInternalStructure(
+ IN CHAR DriveLetter,
+ IN ULONG Size,
+ IN PCHAR Name,
+ IN BOOLEAN ChainIt
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs the internal data structure that represents a
+ double space volume.
+
+Arguments:
+
+ DriveLetter - drive letter for new internal structure
+ Size - size of the actual volume
+ Name - name of the containing double space file (i.e. dblspace.xxx)
+
+Return Value:
+
+ Pointer to the new structure if created.
+ NULL if it couldn't be created.
+
+--*/
+
+{
+ PDBLSPACE_DESCRIPTOR dblSpace;
+
+ dblSpace = malloc(sizeof(DBLSPACE_DESCRIPTOR));
+ if (dblSpace) {
+ if (DriveLetter != ' ') {
+ MarkDriveLetterUsed(DriveLetter);
+ }
+ dblSpace->DriveLetter = DriveLetter;
+ dblSpace->DriveLetterEOS = 0;
+ dblSpace->NewDriveLetter = 0;
+ dblSpace->NewDriveLetterEOS = 0;
+ dblSpace->ChangeDriveLetter = FALSE;
+ dblSpace->Next = dblSpace->DblChainNext = NULL;
+ dblSpace->Mounted = FALSE;
+ dblSpace->ChangeMountState = FALSE;
+ dblSpace->AllocatedSize = Size;
+ dblSpace->FileName = malloc(strlen(Name) + 4);
+ if (dblSpace->FileName) {
+
+ // Copy the name.
+
+ strcpy(dblSpace->FileName, Name);
+ if (ChainIt) {
+ if (DblChainBase) {
+ DblChainLast->DblChainNext = dblSpace;
+ } else {
+ DblChainBase = dblSpace;
+ }
+ DblChainLast = dblSpace;
+ }
+ } else {
+
+ // no memory - free what is allocated and give up.
+
+ free(dblSpace);
+ dblSpace = NULL;
+ }
+ }
+ return dblSpace;
+}
+
+#define MAX_IFS_NAME_LENGTH 200
+VOID
+DblSpaceDetermineMounted(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine walks through all of the system drive letters to see
+ if any are mounted double space volumes. If a mounted double space
+ volume is located it updates the state of that volume in the internal
+ data structures for the double space volumes.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PDBLSPACE_DESCRIPTOR dblSpace;
+ ULONG index;
+ WCHAR driveLetter[4],
+ ntDriveName[MAX_IFS_NAME_LENGTH],
+ cvfName[MAX_IFS_NAME_LENGTH],
+ hostDriveName[MAX_IFS_NAME_LENGTH],
+ compareName[MAX_IFS_NAME_LENGTH];
+ UINT errorMode;
+ BOOLEAN removable,
+ floppy,
+ compressed,
+ error;
+
+ driveLetter[1] = (WCHAR) ':';
+ driveLetter[2] = 0;
+
+ errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+ for (driveLetter[0] = (WCHAR) 'C'; driveLetter[0] < (WCHAR) 'Z'; driveLetter[0]++) {
+
+ if (DriveLetterIsAvailable((CHAR)driveLetter[0])) {
+
+ // No sense calling this stuff for something that doesn't exist
+
+ continue;
+ }
+
+ compressed = FALSE;
+ if (FmIfsQueryInformation(&driveLetter[0],
+ &removable,
+ &floppy,
+ &compressed,
+ &error,
+ &ntDriveName[0],
+ MAX_IFS_NAME_LENGTH,
+ &cvfName[0],
+ MAX_IFS_NAME_LENGTH,
+ &hostDriveName[0],
+ MAX_IFS_NAME_LENGTH)) {
+ // call worked, see if it is a double space volume
+
+ if (compressed) {
+
+ // now need to find this volume in the chain and
+ // update it mounted state.
+
+ for (dblSpace = DblChainBase;
+ dblSpace;
+ dblSpace = dblSpace->DblChainNext) {
+
+ for (index = 0;
+ compareName[index] = (WCHAR) dblSpace->FileName[index];
+ index++) {
+ // Everything in for loop
+ }
+
+ if (!wcscmp(compareName, cvfName)) {
+
+ // found a match.
+
+ dblSpace->Mounted = TRUE;
+ dblSpace->DriveLetter = (UCHAR) driveLetter[0];
+ }
+ }
+ }
+ }
+ }
+ SetErrorMode(errorMode);
+}
+
+VOID
+DblSpaceInitialize(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine goes through the disk table and searches for FAT format
+ partitions. When one is found, it checks for the presense of DoubleSpace
+ volumes and initializes the DoubleSpace support structures inside
+ Disk Administrator.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PDISKSTATE diskState;
+ PREGION_DESCRIPTOR regionDesc;
+ PPERSISTENT_REGION_DATA regionData;
+ PDBLSPACE_DESCRIPTOR dblSpace,
+ prevDblSpace;
+ FILE *dblSpaceIniFile,
+ *dblSpaceFile;
+ CHAR driveLetter[10];
+ CHAR fileName[50];
+ ULONG size,
+ mounted;
+ int items;
+ unsigned diskIndex,
+ regionIndex;
+
+ for (diskIndex = 0; diskIndex < DiskCount; diskIndex++) {
+
+ diskState = Disks[diskIndex];
+ regionDesc = diskState->RegionArray;
+ for (regionIndex = 0; regionIndex < diskState->RegionCount; regionIndex++) {
+
+ regionData = PERSISTENT_DATA(&regionDesc[regionIndex]);
+
+ // region may be free or something that isn't recognized by NT
+
+ if (!regionData) {
+ continue;
+ }
+
+ // region may not be formatted yet.
+
+ if (!regionData->TypeName) {
+ continue;
+ }
+
+ // Double space volumes are only allowed on FAT non-FT partitions.
+
+ if (regionData->FtObject) {
+ continue;
+ }
+
+ if (wcscmp(regionData->TypeName, L"FAT") == 0) {
+ WIN32_FIND_DATA findInformation;
+ HANDLE findHandle;
+
+ // it is possible to have a double space volume here.
+ // Search the root directory of the driver for files with
+ // the name "dblspace.xxx". These are potentially dblspace
+ // volumes.
+
+ prevDblSpace = NULL;
+ sprintf(fileName, DblSpaceWildCardFileName, regionData->DriveLetter);
+ findHandle = FindFirstFile(fileName, &findInformation);
+ while (findHandle != INVALID_HANDLE_VALUE) {
+ char *cp;
+ int i;
+ int save;
+
+ // There is at least one dblspace volume. Insure that
+ // the name is of the proper form.
+
+ save = TRUE;
+ cp = &findInformation.cFileName[0];
+
+ while (*cp) {
+ if (*cp == '.') {
+ break;
+ }
+ cp++;
+ }
+
+ if (*cp != '.') {
+
+ // not a proper dblspace volume name.
+
+ save = FALSE;
+ } else {
+
+ cp++;
+
+ for (i = 0; i < 3; i++, cp++) {
+ if ((*cp < '0') || (*cp > '9')) {
+ break;
+ }
+ }
+
+ if (i != 3) {
+
+ // not a proper dblspace volume name.
+
+ save = FALSE;
+ }
+ }
+
+ if (save) {
+
+ // save the information and search for more.
+
+ dblSpace =
+ DblSpaceCreateInternalStructure(' ',
+ ((findInformation.nFileSizeHigh << 16) |
+ (findInformation.nFileSizeLow)
+ / (1024 * 1024)),
+ &findInformation.cFileName[0],
+ TRUE);
+ if (dblSpace) {
+
+ // Assume volume is not mounted.
+
+ dblSpace->Mounted = FALSE;
+ dblSpace->ChangeMountState = FALSE;
+
+ // Chain in this description.
+
+ if (prevDblSpace) {
+ prevDblSpace->Next = dblSpace;
+ } else {
+ regionData->DblSpace = dblSpace;
+ }
+
+ // Keep the pointer to this one for the chain.
+
+ prevDblSpace = dblSpace;
+ } else {
+
+ // no memory
+
+ break;
+ }
+ }
+
+ if (!FindNextFile(findHandle, &findInformation)) {
+
+ // Technically this should double check and call
+ // GetLastError to see that it is ERROR_NO_MORE_FILES
+ // but this code doesn't do that.
+
+ FindClose(findHandle);
+
+ // Get out of the search loop.
+
+ findHandle = INVALID_HANDLE_VALUE;
+ }
+ }
+ }
+ }
+ }
+
+ // Now that all volumes have been located determine which volumes
+ // are mounted by chasing down the drive letters.
+
+ LoadIfsDll();
+ DblSpaceDetermineMounted();
+}
+
+PDBLSPACE_DESCRIPTOR
+DblSpaceGetNextVolume(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN PDBLSPACE_DESCRIPTOR DblSpace
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will check the RegionDescriptor to walk the DoubleSpace volume chain
+ located from the persistent data.
+
+Arguments:
+
+ RegionDescriptor - pointer to the region on the disk that is to be searched for
+ a DoubleSpace volume.
+
+ DblSpace - pointer to the last DoubleSpace volume located on the region.
+
+Return Value:
+
+ pointer to the next DoubleSpace volume if found
+ NULL if no volume found.
+
+--*/
+
+{
+ PPERSISTENT_REGION_DATA regionData;
+
+ // If a previous DoubleSpace location was past, simply walk the chain to the next.
+
+ if (DblSpace) {
+ return DblSpace->Next;
+ }
+
+ // no previous DoubleSpace location, just get the first one and return it.
+ // Could get a NULL RegionDescriptor. If so, return NULL.
+
+ if (RegionDescriptor) {
+ regionData = PERSISTENT_DATA(RegionDescriptor);
+ if (!regionData) {
+ return NULL;
+ }
+ } else {
+ return NULL;
+ }
+ return regionData->DblSpace;
+}
+
+VOID
+DblSpaceLinkNewVolume(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN PDBLSPACE_DESCRIPTOR DblSpace
+ )
+
+/*++
+
+Routine Description:
+
+ Chain the new double space volume on the list of double space volumes
+ for the region.
+
+Arguments:
+
+ RegionDescriptor - the region the double space volume has been added to.
+ DblSpace - the new volume internal data structure.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(RegionDescriptor);
+ PDBLSPACE_DESCRIPTOR prevDblSpace;
+
+ // if this is the first one, chain it first
+
+ if (!regionData->DblSpace) {
+ regionData->DblSpace = DblSpace;
+ return;
+ }
+
+ for (prevDblSpace = regionData->DblSpace;
+ prevDblSpace->Next;
+ prevDblSpace = prevDblSpace->Next) {
+
+ // all the work is in the for
+ }
+
+ // found the last one. Add the new one to the chain
+
+ prevDblSpace->Next = DblSpace;
+}
+
+BOOL
+DblSpaceVolumeExists(
+ IN PREGION_DESCRIPTOR RegionDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ Indicate to the caller if the input region contains a DoubleSpace volume.
+
+Arguments:
+
+ RegionDescriptor - a pointer to the region in question.
+
+Return Value:
+
+ TRUE if this region contains DoubleSpace volume(s).
+ FALSE if not
+
+--*/
+
+{
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(RegionDescriptor);
+
+ if (regionData) {
+ return(regionData->DblSpace ? TRUE : FALSE);
+ }
+ return FALSE;
+}
+
+BOOL
+DblSpaceDismountedVolumeExists(
+ IN PREGION_DESCRIPTOR RegionDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ Indicate to the caller if the input region contains a DoubleSpace volume
+ that is not mounted.
+
+Arguments:
+
+ RegionDescriptor - a pointer to the region in question.
+
+Return Value:
+
+ TRUE if this region contains DoubleSpace volume(s).
+ FALSE if not
+
+--*/
+
+{
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(RegionDescriptor);
+ PDBLSPACE_DESCRIPTOR dblSpace;
+
+ if (regionData) {
+ if (dblSpace = regionData->DblSpace) {
+ while (dblSpace) {
+ if (!dblSpace->Mounted) {
+ return TRUE;
+ }
+ dblSpace = dblSpace->Next;
+ }
+ }
+ }
+ return FALSE;
+}
+
+PDBLSPACE_DESCRIPTOR
+DblSpaceFindVolume(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN PCHAR Name
+ )
+
+/*++
+
+Routine Description:
+
+ Given a region and a name, locate the double space data structure.
+
+Arguments:
+
+ RegionDescriptor - the region to search
+ Name - the filename wanted.
+
+Return Value:
+
+ A pointer to a double space descriptor if found.
+ NULL if not found.
+
+--*/
+
+{
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(RegionDescriptor);
+ PDBLSPACE_DESCRIPTOR dblSpace = NULL;
+ PCHAR string[50];
+
+ if (regionData) {
+ for (dblSpace = regionData->DblSpace; dblSpace; dblSpace = dblSpace->Next) {
+ if (strcmp(Name, dblSpace->FileName) == 0) {
+
+ // found the desired double space volume
+
+ break;
+ }
+ }
+ }
+ return dblSpace;
+}
+
+
+BOOL
+DblSpaceDetermineUniqueFileName(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN PUCHAR FileName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will search the actual partition to determine what
+ valid double space file name to use (i.e. dblspace.xxx where xxx
+ is a unique number).
+
+Arguments:
+
+ RegionDescriptor - the region to search and determine what double space
+ file names are in use.
+ FileName - a pointer to a character buffer for the name.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ DWORD uniqueNumber = 0;
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(RegionDescriptor);
+ PDBLSPACE_DESCRIPTOR dblSpace;
+
+ do {
+ sprintf(FileName, "dblspace.%03d", uniqueNumber++);
+ if (uniqueNumber > 999) {
+ return FALSE;
+ }
+ } while (DblSpaceFindVolume(RegionDescriptor, FileName));
+ return TRUE;
+}
+
+VOID
+DblSpaceRemoveVolume(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN UCHAR DriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ Find the drive letter provided and unlink it from the chain.
+ Currently this also removes the volume for the scaffolding file.
+
+Arguments:
+
+ RegionDescriptor - region containing the double space volume.
+ DriveLetter - the drive letter to remove.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(RegionDescriptor);
+ PDBLSPACE_DESCRIPTOR dblSpace,
+ prevDblSpace = NULL;
+
+ // Clean up the internal structures.
+
+ if (regionData) {
+ for (dblSpace = regionData->DblSpace; dblSpace; dblSpace = dblSpace->Next) {
+ if (dblSpace->DriveLetter == DriveLetter) {
+
+ // This is the one to delete
+
+ if (prevDblSpace) {
+ prevDblSpace->Next = dblSpace->Next;
+ } else {
+ regionData->DblSpace = dblSpace->Next;
+ }
+ free(dblSpace);
+ break;
+ }
+ prevDblSpace = dblSpace;
+ }
+ }
+}
+
+
+INT
+CreateDblSpaceDlgProc(
+ IN HWND hDlg,
+ IN UINT wMsg,
+ IN WPARAM wParam,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ This routine manages the dialog for the creation of a new double
+ space volume.
+
+Arguments:
+
+ hDlg - the dialog box handle.
+ wMsg - the message.
+ wParam - the windows parameter.
+ lParam - depends on message type.
+
+Return Value:
+
+ TRUE is returned back through windows if the create is successful
+ FALSE otherwise
+
+--*/
+{
+ PREGION_DESCRIPTOR regionDescriptor = &SingleSel->RegionArray[SingleSelIndex];
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(regionDescriptor);
+ PDBLSPACE_DESCRIPTOR dblSpace;
+ static FORMAT_PARAMS formatParams; // this is passed to other threads
+ // it cannot be located on the stack
+ static HWND hwndCombo;
+ static DWORD sizeMB = 0,
+ maxSizeMB = 600,
+ minSizeMB = 10;
+ TCHAR outputString[50],
+ driveLetterString[4], // big enough for "x:" string.
+ sizeString[20], // must be big enough for an 8.3 name
+ letter;
+ FILE *dblspaceIniFile;
+ DWORD compressedSize,
+ selection;
+ BOOL validNumber;
+ CHAR fileName[50];
+
+ switch (wMsg) {
+ case WM_INITDIALOG:
+
+ // limit the size of string that may be entered for the label
+
+ hwndCombo = GetDlgItem(hDlg, IDC_NAME);
+ SendMessage(hwndCombo, EM_LIMITTEXT, 11, 0);
+
+ // set up to watch all characters that go thru the size dialog
+ // to allow only decimal numbers.
+
+ hwndCombo = GetDlgItem(hDlg, IDC_DBLSPACE_SIZE);
+ OldSizeDlgProc = (WNDPROC) SetWindowLong(hwndCombo,
+ GWL_WNDPROC,
+ (LONG)&SizeDlgProc);
+
+ // Add each available drive letter to the list of available
+ // drive letters and set the default letter to the first available.
+
+ hwndCombo = GetDlgItem(hDlg, IDC_DRIVELET_COMBOBOX);
+ driveLetterString[1] = TEXT(':');
+ driveLetterString[2] = 0;
+ for (letter='C'; letter <= 'Z'; letter++) {
+ if (DriveLetterIsAvailable((CHAR)letter)) {
+ *driveLetterString = letter;
+ SendMessage(hwndCombo, CB_ADDSTRING, 0, (LONG)driveLetterString);
+ }
+ }
+ SendMessage(hwndCombo,CB_SETCURSEL,0,0);
+
+ // Setup the min/max values and the size box.
+
+ wsprintf(outputString, TEXT("%u"), 0);
+ SetDlgItemText(hDlg, IDC_DBLSPACE_SIZE, outputString);
+ wsprintf(outputString, TEXT("%u"), minSizeMB);
+ SetDlgItemText(hDlg, IDC_MINMAX_MIN, outputString);
+ wsprintf(outputString, TEXT("%u"), maxSizeMB);
+ SetDlgItemText(hDlg, IDC_MINMAX_MAX, outputString);
+ CenterDialog(hDlg);
+ return TRUE;
+
+ case WM_VSCROLL:
+ {
+ switch (LOWORD(wParam)) {
+ case SB_LINEDOWN:
+ case SB_LINEUP:
+
+ // user is pressing one of the scroll buttons.
+
+ sizeMB = GetDlgItemInt(hDlg, IDC_DBLSPACE_SIZE, &validNumber, FALSE);
+ if (sizeMB < minSizeMB) {
+ sizeMB = minSizeMB + 1;
+ }
+
+ if (sizeMB > maxSizeMB) {
+ sizeMB = maxSizeMB - 1;
+ }
+
+ if (((sizeMB > minSizeMB) && (LOWORD(wParam) == SB_LINEDOWN))
+ || ((sizeMB < maxSizeMB) && (LOWORD(wParam) == SB_LINEUP ))) {
+ if (sizeMB > maxSizeMB) {
+ sizeMB = maxSizeMB;
+ } else if (LOWORD(wParam) == SB_LINEUP) {
+ sizeMB++;
+ } else {
+ sizeMB--;
+ }
+ SetDlgItemInt(hDlg, IDC_DBLSPACE_SIZE, sizeMB, FALSE);
+ SendDlgItemMessage(hDlg, IDC_DBLSPACE_SIZE, EM_SETSEL, 0, -1);
+#if 0
+ compressedSize = sizeMB * 2;
+ wsprintf(outputString, TEXT("%u"), compressedSize);
+ SetDlgItemText(hDlg, IDC_DBLSPACE_COMPRESSED, outputString);
+#endif
+ } else {
+ Beep(500,100);
+ }
+ }
+ break;
+ }
+
+ case WM_COMMAND:
+ switch (wParam) {
+ case FD_IDHELP:
+ break;
+
+ case IDCANCEL:
+
+ EndDialog(hDlg, FALSE);
+ break;
+
+ case IDOK:
+
+ // can only do this if the fmifs dll supports double space.
+
+ if (!DoubleSpaceSupported) {
+
+ // could not load the dll
+
+ ErrorDialog(MSG_CANT_LOAD_FMIFS);
+ EndDialog(hDlg, FALSE);
+ break;
+ }
+
+ // Get the current size for this volume.
+
+ sizeMB = GetDlgItemInt(hDlg, IDC_DBLSPACE_SIZE, &validNumber, FALSE);
+ if (!validNumber || !sizeMB || (sizeMB > maxSizeMB) || (sizeMB < minSizeMB)) {
+ ErrorDialog(MSG_INVALID_SIZE);
+ EndDialog(hDlg, FALSE);
+ break;
+ }
+
+ // Get the currently selected item in the listbox for drive letter
+
+ selection = SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
+ SendMessage(hwndCombo, CB_GETLBTEXT, selection, (LONG)driveLetterString);
+
+ formatParams.RegionDescriptor = regionDescriptor;
+ formatParams.RegionData = regionData;
+ formatParams.FileSystem = NULL;
+ formatParams.DblspaceFileName = NULL;
+ formatParams.QuickFormat = formatParams.Cancel = FALSE;
+ formatParams.DoubleSpace = TRUE;
+ formatParams.TotalSpace = 0;
+ formatParams.SpaceAvailable = sizeMB;
+ formatParams.NewLetter = driveLetterString[0];
+
+ // get the label
+
+ formatParams.Label = (PUCHAR) malloc(100);
+ GetDlgItemText(hDlg, IDC_NAME, (LPTSTR)formatParams.Label, 100);
+
+ DialogBoxParam(hModule,
+ MAKEINTRESOURCE(IDD_DBLSPACE_CANCEL),
+ hwndFrame,
+ (DLGPROC) CancelDlgProc,
+ (ULONG) &formatParams);
+ if (formatParams.Result) {
+
+ // the format failed.
+
+ ErrorDialog(formatParams.Result);
+ EndDialog(hDlg, FALSE);
+ } else {
+ ULONG index;
+ TCHAR message[300],
+ msgProto[300],
+ title[200];
+
+ // save the name
+
+ if (formatParams.DblspaceFileName) {
+ for (index = 0;
+ message[index] = (TCHAR) formatParams.DblspaceFileName[index];
+ index++) {
+ }
+ } else {
+ sprintf(message, "DIDNTWORK");
+ }
+ free(formatParams.DblspaceFileName);
+
+ dblSpace = DblSpaceCreateInternalStructure(*driveLetterString,
+ sizeMB,
+ message,
+ FALSE);
+ if (dblSpace) {
+ DblSpaceLinkNewVolume(regionDescriptor, dblSpace);
+ MarkDriveLetterUsed(dblSpace->DriveLetter);
+ dblSpace->Mounted = TRUE;
+ }
+
+ LoadString(hModule,
+ IDS_DBLSPACECOMPLETE,
+ title,
+ sizeof(title)/sizeof(TCHAR));
+ LoadString(hModule,
+ IDS_FORMATSTATS,
+ msgProto,
+ sizeof(msgProto)/sizeof(TCHAR));
+ wsprintf(message,
+ msgProto,
+ formatParams.TotalSpace,
+ formatParams.SpaceAvailable);
+ MessageBox(GetActiveWindow(),
+ message,
+ title,
+ MB_ICONINFORMATION | MB_OK);
+
+ EndDialog(hDlg, TRUE);
+ }
+
+ break;
+
+ default:
+
+ if (HIWORD(wParam) == EN_CHANGE) {
+
+ // The size value has changed. Update the compressed
+ // size value displayed to the user.
+
+ sizeMB = GetDlgItemInt(hDlg, IDC_DBLSPACE_SIZE, &validNumber, FALSE);
+ if (!validNumber) {
+ sizeMB = 0;
+ }
+
+ }
+ break;
+ }
+ break;
+
+ case WM_DESTROY:
+
+ // restore original subclass to window.
+
+ hwndCombo = GetDlgItem(hDlg, IDC_DBLSPACE_SIZE);
+ SetWindowLong(hwndCombo, GWL_WNDPROC, (LONG) OldSizeDlgProc);
+ break;
+
+ case WM_PAINT:
+
+ // This may be dead code that really isn't needed.
+
+ sizeMB = GetDlgItemInt(hDlg, IDC_DBLSPACE_SIZE, &validNumber, FALSE);
+ if (!validNumber || !sizeMB || (sizeMB > maxSizeMB) || (sizeMB < minSizeMB)) {
+ return FALSE;
+ }
+
+ SetDlgItemInt(hDlg, IDC_DBLSPACE_SIZE, sizeMB, FALSE);
+ SendDlgItemMessage(hDlg, IDC_DBLSPACE_SIZE, EM_SETSEL, 0, -1);
+ break;
+ }
+ return FALSE;
+}
+
+VOID
+DblSpaceDelete(
+ IN PDBLSPACE_DESCRIPTOR DblSpace
+ )
+
+/*++
+
+Routine Description:
+
+ Start the dialog box for the deletion of a double space volume.
+
+Arguments:
+
+ Param - not currently used.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PREGION_DESCRIPTOR regionDescriptor = &SingleSel->RegionArray[SingleSelIndex];
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(regionDescriptor);
+
+ if (ConfirmationDialog(MSG_CONFIRM_DBLSPACE_DELETE, MB_ICONQUESTION | MB_YESNOCANCEL) == IDYES) {
+
+ // Delete the drive from view
+
+ DblSpaceRemoveVolume(regionDescriptor, DblSpace->DriveLetter);
+ DblSpaceUpdateIniFile(regionDescriptor);
+ DrawDiskBar(SingleSel);
+ ForceLBRedraw();
+ }
+}
+
+BOOLEAN
+DblSpaceCreate(
+ IN HWND Dialog,
+ IN PVOID Param
+ )
+
+/*++
+
+Routine Description:
+
+ Start the dialog box for the creation of a double space volume.
+
+Arguments:
+
+ Param - not currently used.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ BOOLEAN result = 0;
+
+ result = DialogBoxParam(hModule,
+ MAKEINTRESOURCE(IDD_DBLSPACE_CREATE),
+ Dialog,
+ (DLGPROC) CreateDblSpaceDlgProc,
+ (ULONG) NULL);
+ if (result) {
+ DrawDiskBar(SingleSel);
+ ForceLBRedraw();
+ }
+ return result;
+}
+
+INT
+DblSpaceMountDlgProc(
+ IN HWND hDlg,
+ IN UINT wMsg,
+ IN DWORD wParam,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Handle the dialog for double space.
+
+Arguments:
+
+ Standard Windows dialog procedure.
+
+Return Value:
+
+ TRUE if something was deleted.
+ FALSE otherwise.
+
+--*/
+
+{
+ static PDBLSPACE_DESCRIPTOR dblSpace;
+ HWND hwndCombo;
+ DWORD selection;
+ CHAR driveLetter;
+ TCHAR driveLetterString[20];
+
+ switch (wMsg) {
+ case WM_INITDIALOG:
+
+ dblSpace = (PDBLSPACE_DESCRIPTOR) lParam;
+
+ // Update the drive letter selections.
+
+ hwndCombo = GetDlgItem(hDlg, IDC_DRIVELET_COMBOBOX);
+
+ // Add all other available letters. Keep track of current
+ // letters offset to set the cursor correctly
+
+ driveLetterString[1] = TEXT(':');
+ driveLetterString[2] = 0;
+ for (driveLetter = 'C'; driveLetter <= 'Z'; driveLetter++) {
+ if (DriveLetterIsAvailable((CHAR)driveLetter) ||
+ (driveLetter == dblSpace->DriveLetter)) {
+
+ *driveLetterString = driveLetter;
+ SendMessage(hwndCombo, CB_ADDSTRING, 0, (LONG)driveLetterString);
+ }
+ }
+
+ // set the current selection to the appropriate index
+
+ SendMessage(hwndCombo, CB_SETCURSEL, 0, 0);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (wParam) {
+
+ case FD_IDHELP:
+
+ DialogHelp(HC_DM_DLG_DOUBLESPACE_MOUNT);
+ break;
+
+ case IDCANCEL:
+
+ EndDialog(hDlg, FALSE);
+ break;
+
+ case IDOK:
+
+ // User has selected the drive letter and wants the mount to occur.
+
+ hwndCombo = GetDlgItem(hDlg, IDC_DRIVELET_COMBOBOX);
+ selection = SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
+ SendMessage(hwndCombo,
+ CB_GETLBTEXT,
+ selection,
+ (LONG)driveLetterString);
+ dblSpace->NewDriveLetter = (UCHAR) driveLetterString[0];
+ EndDialog(hDlg, TRUE);
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+VOID
+DblSpaceSetDialogState(
+ IN HWND hDlg,
+ IN PDBLSPACE_DESCRIPTOR DblSpace
+ )
+
+/*++
+
+Routine Description:
+
+ Given a double space volume this routine will update the buttons
+ in the dialog box to reflect they meaning.
+
+Arguments:
+
+ hDlg - dialog handle
+ DblSpace - The double space volume selection for determining dialog state.
+
+Return Value
+
+ None
+
+--*/
+
+{
+ TCHAR outputString[200];
+
+ if (DblSpace->Mounted) {
+
+ LoadString(hModule,
+ IDS_DBLSPACE_MOUNTED,
+ outputString,
+ sizeof(outputString)/sizeof(TCHAR));
+ SetDlgItemText(hDlg, IDC_MOUNT_STATE, outputString);
+ LoadString(hModule,
+ IDS_DISMOUNT,
+ outputString,
+ sizeof(outputString)/sizeof(TCHAR));
+ SetDlgItemText(hDlg, ID_MOUNT_OR_DISMOUNT, outputString);
+
+ outputString[1] = TEXT(':');
+ outputString[2] = 0;
+ outputString[0] = DblSpace->DriveLetter;
+ SetDlgItemText(hDlg, IDC_DBLSPACE_LETTER, outputString);
+ } else {
+ LoadString(hModule,
+ IDS_DBLSPACE_DISMOUNTED,
+ outputString,
+ sizeof(outputString)/sizeof(TCHAR));
+ SetDlgItemText(hDlg, IDC_MOUNT_STATE, outputString);
+ LoadString(hModule,
+ IDS_MOUNT,
+ outputString,
+ sizeof(outputString)/sizeof(TCHAR));
+ SetDlgItemText(hDlg, ID_MOUNT_OR_DISMOUNT, outputString);
+
+ outputString[1] = TEXT(' ');
+ outputString[2] = 0;
+ outputString[0] = TEXT(' ');
+ SetDlgItemText(hDlg, IDC_DBLSPACE_LETTER, outputString);
+ }
+}
+
+INT
+DblSpaceDlgProc(
+ IN HWND hDlg,
+ IN UINT wMsg,
+ IN DWORD wParam,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Handle the dialog for double space.
+
+Arguments:
+
+Return Value:
+
+ TRUE if something was deleted.
+ FALSE otherwise.
+
+--*/
+
+{
+ static HWND hwndCombo,
+ mountButtonHwnd,
+ deleteButtonHwnd;
+ static PREGION_DESCRIPTOR regionDescriptor;
+ static PPERSISTENT_REGION_DATA regionData;
+ static PDBLSPACE_DESCRIPTOR firstDblSpace;
+ CHAR driveLetter;
+ PDBLSPACE_DESCRIPTOR dblSpace;
+ TCHAR outputString[200];
+ DWORD selection;
+ BOOLEAN result;
+ ULONG errorMessage;
+ DRAWITEMSTRUCT drawItem;
+
+ switch (wMsg) {
+ case WM_INITDIALOG:
+
+ regionDescriptor = &SingleSel->RegionArray[SingleSelIndex];
+ regionData = PERSISTENT_DATA(regionDescriptor);
+
+ hwndCombo = GetDlgItem(hDlg, IDC_DBLSPACE_VOLUME);
+ mountButtonHwnd = GetDlgItem(hDlg, ID_MOUNT_OR_DISMOUNT);
+ deleteButtonHwnd = GetDlgItem(hDlg, IDDELETE);
+
+ // place all double space file names in the selection
+ // box and remember the first name.
+
+ firstDblSpace = dblSpace = DblSpaceGetNextVolume(regionDescriptor, NULL);
+ for (; dblSpace;
+ dblSpace = DblSpaceGetNextVolume(regionDescriptor, dblSpace)) {
+ wsprintf(outputString, TEXT("%s"), dblSpace->FileName);
+ SendMessage(hwndCombo, CB_ADDSTRING, 0, (LONG)outputString);
+ }
+ SendMessage(hwndCombo, CB_SETCURSEL, 0, 0);
+
+ // add the drive letter
+
+ if (firstDblSpace) {
+
+ // update the allocated size.
+
+ wsprintf(outputString, TEXT("%u"), firstDblSpace->AllocatedSize);
+ SetDlgItemText(hDlg, IDC_DBLSPACE_ALLOCATED, outputString);
+
+ // update mount state
+
+ DblSpaceSetDialogState(hDlg, firstDblSpace);
+ EnableWindow(mountButtonHwnd, TRUE);
+ EnableWindow(deleteButtonHwnd, TRUE);
+ } else {
+
+ // update the Mount/Dismount button to say mount and grey it
+
+ LoadString(hModule,
+ IDS_MOUNT,
+ outputString,
+ sizeof(outputString)/sizeof(TCHAR));
+ SetDlgItemText(hDlg, ID_MOUNT_OR_DISMOUNT, outputString);
+ EnableWindow(mountButtonHwnd, FALSE);
+ EnableWindow(deleteButtonHwnd, FALSE);
+ }
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (wParam) {
+
+ case FD_IDHELP:
+
+ DialogHelp(HC_DM_DLG_DOUBLESPACE);
+ break;
+
+ case IDCANCEL:
+
+ // Run the dblspace change and forget about any changes.
+
+ for (dblSpace = firstDblSpace;
+ dblSpace;
+ dblSpace = DblSpaceGetNextVolume(regionDescriptor, dblSpace)) {
+ dblSpace->ChangeMountState = FALSE;
+ dblSpace->NewDriveLetter = 0;
+ }
+ EndDialog(hDlg, FALSE);
+ break;
+
+ case IDOK:
+
+ EndDialog(hDlg, TRUE);
+ break;
+
+ case IDADD:
+
+ DblSpaceCreate(hDlg, NULL);
+ break;
+
+ case IDDELETE:
+
+ hwndCombo = GetDlgItem(hDlg, IDC_DBLSPACE_VOLUME);
+ selection = SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
+ SendMessage(hwndCombo,
+ CB_GETLBTEXT,
+ selection,
+ (LONG)outputString);
+
+ // relate the name to a double space volume
+
+ dblSpace = DblSpaceFindVolume(regionDescriptor, (PCHAR)outputString);
+ if (!dblSpace) {
+ break;
+ }
+
+ DblSpaceDelete(dblSpace);
+ break;
+
+ case ID_MOUNT_OR_DISMOUNT:
+
+ // The state of something in the dialog changed.
+ // Determine which double space volume is involved.
+
+ hwndCombo = GetDlgItem(hDlg, IDC_DBLSPACE_VOLUME);
+ selection = SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
+ SendMessage(hwndCombo,
+ CB_GETLBTEXT,
+ selection,
+ (LONG)outputString);
+
+ // relate the name to a double space volume
+
+ dblSpace = DblSpaceFindVolume(regionDescriptor, (PCHAR)outputString);
+ if (!dblSpace) {
+ break;
+ }
+
+ if (dblSpace->Mounted) {
+
+ // dismount the volume
+
+ errorMessage = DblSpaceDismountDrive(regionDescriptor,
+ dblSpace);
+
+ if (errorMessage) {
+ ErrorDialog(errorMessage);
+ } else {
+
+ // Update the dialog
+
+ DblSpaceSetDialogState(hDlg, dblSpace);
+ DblSpaceUpdateIniFile(regionDescriptor);
+ }
+
+ } else {
+
+ // mount the volume unless the user cancels out
+
+ result = DialogBoxParam(hModule,
+ MAKEINTRESOURCE(IDD_DBLSPACE_DRIVELET),
+ hwndFrame,
+ (DLGPROC) DblSpaceMountDlgProc,
+ (ULONG) dblSpace);
+ if (result) {
+
+ errorMessage = DblSpaceMountDrive(regionDescriptor, dblSpace);
+
+ if (errorMessage) {
+ ErrorDialog(errorMessage);
+ } else {
+
+ // Update the dialog
+
+ DblSpaceSetDialogState(hDlg, dblSpace);
+ DblSpaceUpdateIniFile(regionDescriptor);
+ }
+ }
+ }
+ DrawDiskBar(SingleSel);
+ ForceLBRedraw();
+ break;
+
+ default:
+
+ // The state of something in the dialog changed.
+ // Determine which double space volume is involved.
+
+ hwndCombo = GetDlgItem(hDlg, IDC_DBLSPACE_VOLUME);
+ selection = SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
+ SendMessage(hwndCombo,
+ CB_GETLBTEXT,
+ selection,
+ (LONG)outputString);
+
+ // relate the name to a double space volume
+
+ dblSpace = DblSpaceFindVolume(regionDescriptor, (PCHAR)outputString);
+ if (!dblSpace) {
+
+ // update the Mount/Dismount button to say mount and grey it
+
+ LoadString(hModule,
+ IDS_MOUNT,
+ outputString,
+ sizeof(outputString)/sizeof(TCHAR));
+ SetDlgItemText(hDlg, ID_MOUNT_OR_DISMOUNT, outputString);
+ EnableWindow(mountButtonHwnd, FALSE);
+ EnableWindow(deleteButtonHwnd, FALSE);
+ break;
+ } else {
+ EnableWindow(mountButtonHwnd, TRUE);
+ EnableWindow(deleteButtonHwnd, TRUE);
+ }
+ if (HIWORD(wParam) == LBN_SELCHANGE) {
+
+ // update the allocated/compressed size items
+
+ wsprintf(outputString, TEXT("%u"), dblSpace->AllocatedSize);
+ SetDlgItemText(hDlg, IDC_DBLSPACE_ALLOCATED, outputString);
+#if 0
+ wsprintf(outputString, TEXT("%u"), dblSpace->AllocatedSize * 2);
+ SetDlgItemText(hDlg, IDC_DBLSPACE_COMPRESSED, outputString);
+ wsprintf(outputString, TEXT("%u.%u"), 2, 0);
+ SetDlgItemText(hDlg, IDC_DBLSPACE_RATIO, outputString);
+#endif
+
+ // update mount state
+
+ DblSpaceSetDialogState(hDlg, dblSpace);
+ }
+
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+VOID
+DblSpace(
+ IN HWND Dialog,
+ IN PVOID Param
+ )
+
+/*++
+
+Routine Description:
+
+ Start the dialog box for double space.
+
+Arguments:
+
+ Param - not currently used.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ BOOLEAN result;
+
+ if (IsFullDoubleSpace) {
+ result = DialogBoxParam(hModule,
+ MAKEINTRESOURCE(IDD_DBLSPACE_FULL),
+ Dialog,
+ (DLGPROC) DblSpaceDlgProc,
+ (ULONG) NULL);
+
+ } else {
+ result = DialogBoxParam(hModule,
+ MAKEINTRESOURCE(IDD_DBLSPACE),
+ Dialog,
+ (DLGPROC) DblSpaceDlgProc,
+ (ULONG) NULL);
+ }
+ if (result) {
+ DrawDiskBar(SingleSel);
+ ForceLBRedraw();
+ }
+}
+#else
+
+// STUBS for easy removal of DoubleSpace support.
+
+BOOL
+DblSpaceVolumeExists(
+ IN PREGION_DESCRIPTOR RegionDescriptor
+ )
+{
+ return FALSE;
+}
+
+BOOL
+DblSpaceDismountedVolumeExists(
+ IN PREGION_DESCRIPTOR RegionDescriptor
+ )
+{
+ return FALSE;
+}
+
+BOOLEAN
+DblSpaceCreate(
+ IN HWND Dialog,
+ IN PVOID Param
+ )
+{
+ return FALSE;
+}
+
+VOID
+DblSpaceDelete(
+ IN PVOID Param
+ )
+{
+}
+
+VOID
+DblSpaceMount(
+ IN PVOID Param
+ )
+{
+}
+
+VOID
+DblSpaceDismount(
+ IN PVOID Param
+ )
+{
+}
+
+VOID
+DblSpaceInitialize(
+ VOID
+ )
+{
+}
+
+VOID
+DblSpace(
+ IN HWND Dialog,
+ IN PVOID Param
+ )
+{
+}
+
+PDBLSPACE_DESCRIPTOR
+DblSpaceGetNextVolume(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN PDBLSPACE_DESCRIPTOR DblSpace
+ )
+{
+ return NULL;
+}
+
+#endif
diff --git a/private/utils/fdisk/diskman.hlp b/private/utils/fdisk/diskman.hlp
new file mode 100644
index 000000000..1916d428f
--- /dev/null
+++ b/private/utils/fdisk/diskman.hlp
Binary files differ
diff --git a/private/utils/fdisk/dskmgr.ico b/private/utils/fdisk/dskmgr.ico
new file mode 100644
index 000000000..f0fa6bfe5
--- /dev/null
+++ b/private/utils/fdisk/dskmgr.ico
Binary files differ
diff --git a/private/utils/fdisk/fd_nt.c b/private/utils/fdisk/fd_nt.c
new file mode 100644
index 000000000..4d439d414
--- /dev/null
+++ b/private/utils/fdisk/fd_nt.c
@@ -0,0 +1,1084 @@
+/*++
+
+Copyright (c) 1991-1994 Microsoft Corporation
+
+Module Name:
+
+ fd_nt.c
+
+Abstract:
+
+ This module wraps fdisk engine functions. This is done
+ to avoid having files that include both the full windows
+ and the full nt include file sets.
+
+ Functions that manipulate engine structures (REGIONs, for example)
+ are also placed here.
+
+ This file is targeted at NT, not Windows.
+
+Author:
+
+ Ted Miller (tedm) 5-Dec-1991
+
+Revision History:
+
+ Misc cleanup (BobRi) 22-Jan-1994
+
+--*/
+
+#include "fdisk.h"
+#include <string.h>
+#include <stdio.h>
+
+// These partition ID's are for systems recognized by WINDISK,
+// even though they don't appear in ntdddisk.h.
+
+#define PARTITION_OS2_BOOT 0xa
+#define PARTITION_EISA 0x12
+
+
+WCHAR UnicodeSysIdName[100];
+BYTE StringBuffer[100];
+
+// Pagefile support structures.
+
+typedef struct _PAGEFILE_LOCATION {
+ struct _PAGEFILE_LOCATION *Next;
+ CHAR DriveLetter;
+} PAGEFILE_LOCATION, *PPAGEFILE_LOCATION;
+
+PPAGEFILE_LOCATION PagefileHead = NULL;
+
+// For some reason the file systems don't like being accessed shortly after
+// a format or lock event.
+
+#define SLEEP_TIME (1000*2) // 2 seconds
+
+
+PWSTR
+GetWideSysIDName(
+ IN UCHAR SysID
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ ANSI_STRING ansiString;
+ UNICODE_STRING unicodeString;
+ DWORD stringId;
+
+ // Get the name, which is a byte-string.
+
+ switch (SysID) {
+
+ case PARTITION_ENTRY_UNUSED:
+ stringId = IDS_PARTITION_FREE;
+ break;
+
+ case PARTITION_XENIX_1:
+ stringId = IDS_PARTITION_XENIX1;
+ break;
+
+ case PARTITION_XENIX_2:
+ stringId = IDS_PARTITION_XENIX2;
+ break;
+
+ case PARTITION_OS2_BOOT:
+ stringId = IDS_PARTITION_OS2_BOOT;
+ break;
+
+ case PARTITION_EISA:
+ stringId = IDS_PARTITION_EISA;
+ break;
+
+ case PARTITION_UNIX:
+ stringId = IDS_PARTITION_UNIX;
+ break;
+
+ case PARTITION_PREP:
+#ifdef _PPC_
+ stringId = IDS_PARTITION_POWERPC;
+#else
+
+ // If not on a PPC platform, assume this is Eisa related
+
+ stringId = IDS_PARTITION_EISA;
+#endif
+ break;
+
+ default:
+ stringId = IDS_UNKNOWN;
+ break;
+ }
+
+ LoadString(hModule, stringId, StringBuffer, sizeof(StringBuffer));
+ RtlInitAnsiString(&ansiString, StringBuffer);
+
+ //
+ // Convert to Unicode
+ //
+
+ unicodeString.Buffer = UnicodeSysIdName;
+ unicodeString.MaximumLength = sizeof(UnicodeSysIdName);
+ RtlAnsiStringToUnicodeString(&unicodeString, &ansiString, FALSE);
+ return UnicodeSysIdName;
+}
+
+
+ULONG
+MyDiskRegistryGet(
+ OUT PDISK_REGISTRY *DiskRegistry
+ )
+
+/*++
+
+Routine Description:
+
+ Allocate memory for the size of the disk registry, obtain
+ the registry contents (if any) and return the pointer to the
+ allocated memory.
+
+Arguments:
+
+ A pointer to a disk registry pointer.
+
+Return Value:
+
+ status indicating success or failure.
+
+--*/
+
+{
+ ULONG length;
+ PDISK_REGISTRY diskRegistry;
+ NTSTATUS status;
+
+
+ while (((status = DiskRegistryGet(NULL, &length)) == STATUS_NO_MEMORY)
+ || (status == STATUS_INSUFFICIENT_RESOURCES))
+ {
+ ConfirmOutOfMemory();
+ }
+
+ if (!NT_SUCCESS(status)) {
+ return EC(status);
+ }
+
+ diskRegistry = Malloc(length);
+
+ while (((status = DiskRegistryGet(diskRegistry, &length)) == STATUS_NO_MEMORY)
+ || (status == STATUS_INSUFFICIENT_RESOURCES))
+ {
+ ConfirmOutOfMemory();
+ }
+
+ if (NT_SUCCESS(status)) {
+
+ LOG_DISK_REGISTRY("MyDiskRegistryGet", diskRegistry);
+ *DiskRegistry = diskRegistry;
+ }
+ return EC(status);
+}
+
+
+ULONG
+FormDiskSignature(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Return a ULONG disk signature. This is derived from the current
+ system time.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ A 32-bit signature
+
+--*/
+
+{
+ LARGE_INTEGER time;
+ static ULONG baseSignature = 0;
+
+ if (!baseSignature) {
+
+ NtQuerySystemTime(&time);
+ time.QuadPart = time.QuadPart >> 16;
+ baseSignature = time.LowPart;
+ }
+ return baseSignature++;
+}
+
+
+BOOLEAN
+GetVolumeSizeMB(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ OUT PULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ Given a disk and a partition, query the "volume" to get its size.
+ By performing the query on the 1st partition of a potential FT set,
+ the total size of the set will be returned. If the partition isn't
+ an FT set, it will work too.
+
+Arguments:
+
+ Disk - the disk number
+ Partition - the partition number
+ Size - the size of the "volume"
+
+Return Value:
+
+ TRUE - a size was returned.
+ FALSE - something failed in getting the size.
+
+--*/
+
+{
+ BOOLEAN retValue = FALSE;
+ IO_STATUS_BLOCK statusBlock;
+ HANDLE handle;
+ STATUS_CODE sc;
+ PARTITION_INFORMATION partitionInfo;
+ LARGE_INTEGER partitionLength;
+
+ *Size = 0;
+ sc = LowOpenPartition(GetDiskName(Disk), Partition, &handle);
+ if (sc == OK_STATUS) {
+
+ sc = NtDeviceIoControlFile(handle,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ IOCTL_DISK_GET_PARTITION_INFO,
+ NULL,
+ 0,
+ &partitionInfo,
+ sizeof(PARTITION_INFORMATION));
+
+ if (sc == OK_STATUS) {
+
+ // Convert to MB
+
+ partitionLength.QuadPart = partitionInfo.PartitionLength.QuadPart >> 20;
+ *Size = partitionLength.LowPart;
+ retValue = TRUE;
+ }
+ LowCloseDisk(handle);
+ }
+ return retValue;
+}
+
+
+ULONG
+GetVolumeTypeAndSize(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ OUT PWSTR *Label,
+ OUT PWSTR *Type,
+ OUT PULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ Given a disk and partition number, determine its size, label and file
+ system type. This routine will allocate the space for label and file
+ system type. It is the responsibility of the caller to free this memory.
+
+Arguments:
+
+ Disk - the disk number
+ Partition - the partition number
+ Label - a pointer to a pointer for a WCHAR string to contain the label
+ Type - a pointer to a pointer for a WCHAR string to contain the file system
+ type.
+ Size - a pointer to a ULONG for the size of the disk in KB.
+
+Return Value:
+
+ OK_STATUS - everything was performed.
+ !OK_STATUS - the error code that was returned in the process of performing
+ this work.
+
+--*/
+
+{
+ IO_STATUS_BLOCK statusBlock;
+ HANDLE handle;
+ unsigned char buffer[256];
+ PWSTR label,
+ name;
+ ULONG length;
+ DISK_GEOMETRY diskGeometry;
+ STATUS_CODE sc;
+ BOOLEAN firstTime = TRUE;
+ PFILE_FS_VOLUME_INFORMATION labelInfo = (PFILE_FS_VOLUME_INFORMATION)buffer;
+ PFILE_FS_ATTRIBUTE_INFORMATION info = (PFILE_FS_ATTRIBUTE_INFORMATION)buffer;
+
+ while (1) {
+ sc = LowOpenPartition(GetDiskName(Disk), Partition, &handle);
+ if (sc == OK_STATUS) {
+
+ sc = NtQueryVolumeInformationFile(handle,
+ &statusBlock,
+ buffer,
+ sizeof(buffer),
+ FileFsVolumeInformation);
+ if (sc == OK_STATUS) {
+
+ length = labelInfo->VolumeLabelLength;
+ labelInfo->VolumeLabel[length/sizeof(WCHAR)] = 0;
+ length = (length+1) * sizeof(WCHAR);
+
+ label = Malloc(length);
+ RtlMoveMemory(label, labelInfo->VolumeLabel, length);
+ } else {
+
+ label = Malloc(sizeof(WCHAR));
+ *label = 0;
+ }
+ *Label = label;
+
+ if (sc == OK_STATUS) {
+ sc = NtQueryVolumeInformationFile(handle,
+ &statusBlock,
+ buffer,
+ sizeof(buffer),
+ FileFsAttributeInformation);
+ if (sc == OK_STATUS) {
+
+ length = info->FileSystemNameLength;
+ info->FileSystemName[length/sizeof(WCHAR)] = 0;
+ length = (length+1)*sizeof(WCHAR);
+ name = Malloc(length);
+ RtlMoveMemory(name, info->FileSystemName, length);
+ } else {
+
+ name = Malloc(sizeof(WCHAR));
+ *name = 0;
+ }
+ *Type = name;
+ }
+
+ if (sc == OK_STATUS) {
+ sc = NtDeviceIoControlFile(handle,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ IOCTL_DISK_GET_DRIVE_GEOMETRY,
+ NULL,
+ 0,
+ (PVOID)&diskGeometry,
+ sizeof(diskGeometry));
+ if (NT_SUCCESS(sc)) {
+ LARGE_INTEGER sizeInBytes;
+ ULONG cylinderBytes;
+
+ cylinderBytes = diskGeometry.TracksPerCylinder *
+ diskGeometry.SectorsPerTrack *
+ diskGeometry.BytesPerSector;
+
+ sizeInBytes.QuadPart = diskGeometry.Cylinders.QuadPart * cylinderBytes;
+
+ // Now convert everything to KB
+
+ sizeInBytes.QuadPart = sizeInBytes.QuadPart >> 10;
+ *Size = (ULONG) sizeInBytes.LowPart;
+ }
+ }
+ DmClose(handle);
+ sc = OK_STATUS;
+ break;
+ } else {
+ if (firstTime) {
+ firstTime = FALSE;
+ } else {
+ break;
+ }
+ Sleep(SLEEP_TIME);
+ }
+ }
+
+ return EC(sc);
+}
+
+ULONG
+GetVolumeLabel(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ OUT PWSTR *Label
+ )
+
+/*++
+
+Routine Description:
+
+ Given a disk number and a partition number return the volume label (if
+ any).
+
+Arguments:
+
+ Disk - the disk number
+ Partition - the partition number
+ Label - a pointer to a pointer for a WCHAR string to contain the label
+
+Return Value:
+
+ OK_STATUS - everything was performed.
+ !OK_STATUS - the error code that was returned in the process of performing
+ this work.
+--*/
+
+{
+ IO_STATUS_BLOCK statusBlock;
+ HANDLE handle;
+ unsigned char buffer[256];
+ PWSTR label;
+ ULONG length;
+ STATUS_CODE sc;
+ BOOLEAN firstTime = TRUE;
+ PFILE_FS_VOLUME_INFORMATION labelInfo = (PFILE_FS_VOLUME_INFORMATION)buffer;
+
+ while (1) {
+ sc = LowOpenPartition(GetDiskName(Disk), Partition, &handle);
+ if (sc == OK_STATUS) {
+
+ sc = NtQueryVolumeInformationFile(handle,
+ &statusBlock,
+ buffer,
+ sizeof(buffer),
+ FileFsVolumeInformation);
+ DmClose(handle);
+ if (sc == OK_STATUS) {
+
+ length = labelInfo->VolumeLabelLength;
+ labelInfo->VolumeLabel[length/sizeof(WCHAR)] = 0;
+ length = (length+1) * sizeof(WCHAR);
+
+ label = Malloc(length);
+ RtlMoveMemory(label, labelInfo->VolumeLabel, length);
+ } else {
+
+ label = Malloc(sizeof(WCHAR));
+ sc = OK_STATUS;
+ *label = 0;
+ }
+ *Label = label;
+ break;
+ } else {
+ if (firstTime) {
+ firstTime = FALSE;
+ } else {
+ *Label = NULL;
+ break;
+ }
+ Sleep(SLEEP_TIME);
+ }
+ }
+ return EC(sc);
+}
+
+
+ULONG
+GetTypeName(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ OUT PWSTR *Name
+ )
+
+/*++
+
+Routine Description:
+
+ Given a disk number and partition number return the file system type
+ string.
+
+Arguments:
+
+ Disk - the disk number
+ Partition - the partition number
+ Name - a pointer to a pointer for a WCHAR string to contain the file system
+ type.
+
+Return Value:
+
+ OK_STATUS - everything was performed.
+ !OK_STATUS - the error code that was returned in the process of performing
+ this work.
+--*/
+
+{
+ PWSTR name;
+ STATUS_CODE sc;
+ HANDLE handle;
+ unsigned char buffer[256];
+ IO_STATUS_BLOCK statusBlock;
+ ULONG length;
+ BOOLEAN firstTime = TRUE;
+ PFILE_FS_ATTRIBUTE_INFORMATION info = (PFILE_FS_ATTRIBUTE_INFORMATION)buffer;
+
+ // For some reason, the file systems believe they are locked or need
+ // to be verified after formats and the like. Therefore this is attempted
+ // twice before it actually gives up.
+
+ while (1) {
+ sc = LowOpenPartition(GetDiskName(Disk), Partition, &handle);
+
+ if (sc == OK_STATUS) {
+ sc = NtQueryVolumeInformationFile(handle,
+ &statusBlock,
+ buffer,
+ sizeof(buffer),
+ FileFsAttributeInformation);
+ DmClose(handle);
+ if (sc == OK_STATUS) {
+
+ length = info->FileSystemNameLength;
+ info->FileSystemName[length/sizeof(WCHAR)] = 0;
+ length = (length+1)*sizeof(WCHAR);
+ name = Malloc(length);
+ RtlMoveMemory(name, info->FileSystemName, length);
+ } else {
+
+ name = Malloc(sizeof(WCHAR));
+ *name = 0;
+ sc = OK_STATUS;
+ }
+ *Name = name;
+ break;
+ } else {
+ if (firstTime) {
+ firstTime = FALSE;
+ } else {
+ break;
+ }
+ Sleep(SLEEP_TIME);
+ }
+ }
+
+ return EC(sc);
+}
+
+
+BOOLEAN
+IsRemovable(
+ IN ULONG DiskNumber
+ )
+
+/*++
+
+Routine Description:
+
+ This function determines whether the specified physical
+ disk is removable.
+
+Arguments:
+
+ DiskNumber -- The Physical Disk Number of the disk in question.
+
+Return Value:
+
+ TRUE if the disk is removable.
+
+--*/
+
+{
+ STATUS_CODE sc;
+ NTSTATUS status;
+ HANDLE handle;
+ DISK_GEOMETRY diskGeometry;
+ IO_STATUS_BLOCK statusBlock;
+ PCHAR name;
+
+ name = GetDiskName(DiskNumber);
+ sc = LowOpenDisk(name, &handle);
+
+ if (sc == OK_STATUS) {
+ status = NtDeviceIoControlFile(handle,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ IOCTL_DISK_GET_DRIVE_GEOMETRY,
+ NULL,
+ 0,
+ (PVOID)&diskGeometry,
+ sizeof(diskGeometry));
+ LowCloseDisk(handle);
+ if (NT_SUCCESS(status)) {
+ if (diskGeometry.MediaType == RemovableMedia) {
+ char ntDeviceName[100];
+
+ // Do a dismount/force mount sequence to make sure
+ // the media hasn't changed since last mount.
+ // Dismount partition 1 by lock/unlock/close.
+
+ sprintf(ntDeviceName, "%s\\Partition1", name);
+ status= LowOpenNtName(ntDeviceName, &handle);
+ if (NT_SUCCESS(status)) {
+
+ LowLockDrive(handle);
+ LowUnlockDrive(handle);
+ LowCloseDisk(handle);
+
+ // Now force the mount by opening the device with a '\'
+ // This is done on partition 1 of the device.
+
+ sprintf(ntDeviceName, "%s\\Partition1\\", name);
+ status= LowOpenNtName(ntDeviceName, &handle);
+ if (NT_SUCCESS(status)) {
+ LowCloseDisk(handle);
+ }
+ }
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+
+ULONG
+GetDriveLetterLinkTarget(
+ IN PWSTR SourceNameStr,
+ OUT PWSTR *LinkTarget
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ static WCHAR targetNameBuffer[50];
+ UNICODE_STRING sourceName,
+ targetName;
+ NTSTATUS status;
+ OBJECT_ATTRIBUTES attributes;
+ HANDLE handle;
+
+
+ RtlInitUnicodeString(&sourceName, SourceNameStr);
+ InitializeObjectAttributes(&attributes, &sourceName, OBJ_CASE_INSENSITIVE, NULL, NULL);
+ status = NtOpenSymbolicLinkObject(&handle, READ_CONTROL | SYMBOLIC_LINK_QUERY, &attributes);
+
+ if (NT_SUCCESS(status)) {
+
+ RtlZeroMemory(targetNameBuffer, 50 * sizeof(WCHAR));
+ targetName.Buffer = targetNameBuffer;
+ targetName.MaximumLength = sizeof(targetNameBuffer);
+ status = NtQuerySymbolicLinkObject(handle, &targetName, NULL);
+ NtClose(handle);
+ }
+
+ if (NT_SUCCESS(status)) {
+ *LinkTarget = targetName.Buffer;
+ } else {
+ *LinkTarget = NULL;
+ }
+
+ return EC(status);
+}
+
+
+#include "bootmbr.h"
+
+#if X86BOOTCODE_SIZE < MBOOT_CODE_SIZE
+#error Something is wrong with the boot code (it's too small)!
+#endif
+
+
+ULONG
+MasterBootCode(
+ IN ULONG Disk,
+ IN ULONG Signature,
+ IN BOOLEAN SetBootCode,
+ IN BOOLEAN SetSignature
+ )
+
+/*++
+
+Routine Description:
+
+ If the zero sector of the disk does not have a valid MBR
+ signature (i.e. AA55), update it such that it has a valid
+ MBR and fill in the disk signature and bootcode in the
+ process.
+
+Arguments:
+
+ Disk - the disk ordinal to be affected
+ SetSignature - if TRUE update the disk signature
+ Signature - the disk signature for the update
+
+Return Value:
+
+ status
+
+--*/
+
+{
+ HANDLE handle;
+ STATUS_CODE status;
+ PUCHAR unalignedSectorBuffer,
+ sectorBuffer;
+ ULONG bps,
+ dummy,
+ i;
+ BOOLEAN writeIt;
+ PCHAR diskName = GetDiskName(Disk);
+
+#ifndef max
+#define max(a,b) ((a > b) ? a : b)
+#endif
+
+ if (SetBootCode) {
+ writeIt = FALSE;
+
+ // allocate sector buffer
+
+ status = LowGetDriveGeometry(diskName, &dummy, &bps, &dummy, &dummy);
+ if (status != OK_STATUS) {
+ return EC(status);
+ }
+ if (bps < 512) {
+ bps = 512;
+ }
+ unalignedSectorBuffer = Malloc(2*bps);
+ sectorBuffer = (PUCHAR)(((ULONG)unalignedSectorBuffer+bps) & ~(bps-1));
+
+ // open entire disk (partition 0)
+
+ if ((status = LowOpenDisk(diskName, &handle)) != OK_STATUS) {
+ return EC(status);
+ }
+
+ // read (at least) first 512 bytes
+
+ status = LowReadSectors(handle, bps, 0, 1, sectorBuffer);
+ if (status == OK_STATUS) {
+
+ if ((sectorBuffer[MBOOT_SIG_OFFSET+0] != MBOOT_SIG1)
+ || (sectorBuffer[MBOOT_SIG_OFFSET+1] != MBOOT_SIG2)) {
+
+ // xfer boot code into sectorBuffer
+
+ for (i=0; i<MBOOT_CODE_SIZE; i++) {
+ sectorBuffer[i] = x86BootCode[i];
+ }
+
+ // wipe partition table
+
+ for (i=MBOOT_CODE_SIZE; i<MBOOT_SIG_OFFSET; i++) {
+ sectorBuffer[i] = 0;
+ }
+
+ // set the signature
+
+ sectorBuffer[MBOOT_SIG_OFFSET+0] = MBOOT_SIG1;
+ sectorBuffer[MBOOT_SIG_OFFSET+1] = MBOOT_SIG2;
+
+ writeIt = TRUE;
+ }
+
+ if (writeIt) {
+ status = LowWriteSectors(handle, bps, 0, 1, sectorBuffer);
+ }
+ }
+
+ LowCloseDisk(handle);
+ Free(unalignedSectorBuffer);
+ }
+
+ if (SetSignature) {
+ PDRIVE_LAYOUT_INFORMATION layout;
+
+ // Use the IOCTL to set the signature. This code really does
+ // not know where the MBR exists. (ezDrive extensions).
+
+ status = LowGetDiskLayout(diskName, &layout);
+
+ if (status == OK_STATUS) {
+ layout->Signature = Signature;
+ LowSetDiskLayout(diskName, layout);
+ }
+ }
+
+ return EC(status);
+}
+
+
+ULONG
+UpdateMasterBootCode(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine updates the zero sector of the disk to insure that boot
+ code is present.
+
+Arguments:
+
+ Disk - the disk number onto which to put the boot code.
+
+Return Value:
+
+ status
+
+--*/
+
+{
+ HANDLE handle;
+ STATUS_CODE status;
+ PUCHAR unalignedSectorBuffer,
+ sectorBuffer;
+ ULONG bps,
+ dummy,
+ i;
+ PCHAR diskName = GetDiskName(Disk);
+
+#ifndef max
+#define max(a,b) ((a > b) ? a : b)
+#endif
+
+ // allocate sector buffer
+
+ status = LowGetDriveGeometry(diskName, &dummy, &bps, &dummy, &dummy);
+ if (status != OK_STATUS) {
+ return EC(status);
+ }
+ if (bps < 512) {
+ bps = 512;
+ }
+ unalignedSectorBuffer = Malloc(2*bps);
+ sectorBuffer = (PUCHAR)(((ULONG)unalignedSectorBuffer+bps) & ~(bps-1));
+
+ // open entire disk (partition 0)
+
+ if ((status = LowOpenDisk(diskName, &handle)) != OK_STATUS) {
+ return EC(status);
+ }
+
+ // read (at least) first 512 bytes
+
+ status = LowReadSectors(handle, bps, 0, 1, sectorBuffer);
+ if (status == OK_STATUS) {
+
+
+ // xfer boot code into sectorBuffer. This avoids changing the
+ // disk signature and the partition table information.
+
+ for (i=0; i<MBOOT_CODE_SIZE; i++) {
+ sectorBuffer[i] = x86BootCode[i];
+ }
+
+ status = LowWriteSectors(handle, bps, 0, 1, sectorBuffer);
+ }
+
+ LowCloseDisk(handle);
+
+ // free the sector buffer
+
+ Free(unalignedSectorBuffer);
+ return EC(status);
+}
+
+
+#if i386
+
+VOID
+MakePartitionActive(
+ IN PREGION_DESCRIPTOR DiskRegionArray,
+ IN ULONG RegionCount,
+ IN ULONG RegionIndex
+ )
+
+/*++
+
+Routine Description:
+
+ Update the information in the internal structures to indicate
+ that the specified partition is active.
+
+Arguments:
+
+ DiskRegionArray
+ RegionCount
+ RegionIndex
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ unsigned i;
+
+ for (i=0; i<RegionCount; i++) {
+ if (DiskRegionArray[i].RegionType == REGION_PRIMARY) {
+ DiskRegionArray[i].Active = FALSE;
+ SetPartitionActiveFlag(&DiskRegionArray[i], FALSE);
+ }
+ }
+ DiskRegionArray[RegionIndex].Active = (BOOLEAN)0x80;
+ SetPartitionActiveFlag(&DiskRegionArray[RegionIndex], 0x80);
+}
+
+#endif
+
+VOID
+LoadExistingPageFileInfo(
+ IN VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine finds all pagefiles in the system and updates the internal
+ structures.
+
+Arguments:
+
+ None
+
+Return Values:
+
+ None
+
+--*/
+
+{
+ NTSTATUS status;
+ SYSTEM_INFO sysInfo;
+ UCHAR genericBuffer[0x10000];
+ PSYSTEM_PAGEFILE_INFORMATION pageFileInfo;
+ ANSI_STRING ansiPageFileName;
+ PPAGEFILE_LOCATION pageFileListEntry;
+ PCHAR p;
+
+ GetSystemInfo(&sysInfo);
+
+ status = NtQuerySystemInformation(SystemPageFileInformation,
+ genericBuffer,
+ sizeof(genericBuffer),
+ NULL);
+ if (!NT_SUCCESS(status)) {
+
+ // It's possible that this call will fail if the
+ // the system is running without ANY paging files.
+
+ return;
+ }
+
+ pageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION) genericBuffer;
+
+ for (;;) {
+
+ RtlUnicodeStringToAnsiString(&ansiPageFileName,
+ &pageFileInfo->PageFileName,
+ TRUE);
+
+ // Since the format of the pagefile name generally
+ // looks something like "\DosDevices\h:\pagefile.sys",
+ // just use the first character before the colon
+ // and assume that's the drive letter.
+
+ p = strchr(_strlwr(ansiPageFileName.Buffer), ':');
+
+ if ((p-- != NULL) && (*p >= 'a') && (*p <= 'z')) {
+
+ pageFileListEntry = Malloc(sizeof(PAGEFILE_LOCATION));
+ if (pageFileListEntry) {
+ if (PagefileHead) {
+ pageFileListEntry->Next = PagefileHead;
+ } else {
+ PagefileHead = pageFileListEntry;
+ pageFileListEntry->Next = NULL;
+ }
+ pageFileListEntry->DriveLetter = *p;
+ }
+
+ }
+
+ RtlFreeAnsiString(&ansiPageFileName);
+
+ if (pageFileInfo->NextEntryOffset == 0) {
+ break;
+ }
+
+ pageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION)((PCHAR) pageFileInfo
+ + pageFileInfo->NextEntryOffset);
+ }
+}
+
+BOOLEAN
+IsPagefileOnDrive(
+ CHAR DriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ Walk the page file list and determine if the drive letter given has
+ a paging file. NOTE: The assumption is that drive letters that
+ contain paging files can never get changed during the execution of
+ Disk Administrator. Therefore this list is never updated, but
+ can be used during the execution of Disk Administrator.
+
+Arguments:
+
+ DriveLetter - the drive in question.
+
+Return Value:
+
+ TRUE if this drive contains a page file.
+
+--*/
+
+{
+ PPAGEFILE_LOCATION pageFileListEntry = PagefileHead;
+
+ while (pageFileListEntry) {
+ if (pageFileListEntry->DriveLetter == DriveLetter) {
+ return TRUE;
+ }
+ pageFileListEntry = pageFileListEntry->Next;
+ }
+ return FALSE;
+}
diff --git a/private/utils/fdisk/fdconst.h b/private/utils/fdisk/fdconst.h
new file mode 100644
index 000000000..35fac882e
--- /dev/null
+++ b/private/utils/fdisk/fdconst.h
@@ -0,0 +1,80 @@
+#define SYSID_FT 0x80
+
+
+
+#define LEGEND_STRING_COUNT 5
+
+#define STATUS_TEXT_SIZE 250
+
+#define NUM_AVAILABLE_COLORS 16
+#define NUM_AVAILABLE_HATCHES 5
+
+
+// brushes for drawing rectangles
+
+#define BRUSH_USEDPRIMARY 0
+#define BRUSH_USEDLOGICAL 1
+#define BRUSH_STRIPESET 2
+#define BRUSH_MIRROR 3
+#define BRUSH_VOLUMESET 4
+#define BRUSH_ARRAY_SIZE LEGEND_STRING_COUNT
+
+// see AvailableHatches[] in fddata.c
+#define DEFAULT_HATCH_USEDPRIMARY 4
+#define DEFAULT_HATCH_USEDLOGICAL 4
+#define DEFAULT_HATCH_STRIPESET 4
+#define DEFAULT_HATCH_MIRROR 4
+#define DEFAULT_HATCH_VOLUMESET 4
+
+// see AvailableColors[] in fddata.c
+#define DEFAULT_COLOR_USEDPRIMARY 9
+#define DEFAULT_COLOR_USEDLOGICAL 15
+#define DEFAULT_COLOR_STRIPESET 14
+#define DEFAULT_COLOR_MIRROR 5
+#define DEFAULT_COLOR_VOLUMESET 10
+
+
+#define MESSAGE_BUFFER_SIZE 4096
+
+#define ID_LISTBOX 0xcac
+
+
+// thickness of the border indicating selection of a region
+
+#define SELECTION_THICKNESS 2
+
+
+//
+// define constants for use with drive letter assignments.
+// use arbitrary symbols that won't ever be drive letters themselves.
+
+#define NO_DRIVE_LETTER_YET '#'
+#define NO_DRIVE_LETTER_EVER '%'
+
+
+
+
+// notification codes
+
+#define RN_CLICKED 213
+
+// window messages
+
+#define RM_SELECT WM_USER
+
+// window extra
+
+#define RECTCONTROL_WNDEXTRA 2
+#define GWW_SELECTED 0
+
+
+// custom windows message for F1 key
+
+#define WM_F1DOWN (WM_USER + 0x17a)
+
+
+
+#define MBOOT_CODE_SIZE 0x1b8
+#define MBOOT_SIG_OFFSET 0x1fe
+#define MBOOT_SIG1 0x55
+#define MBOOT_SIG2 0xaa
diff --git a/private/utils/fdisk/fddata.c b/private/utils/fdisk/fddata.c
new file mode 100644
index 000000000..32f54a68b
--- /dev/null
+++ b/private/utils/fdisk/fddata.c
@@ -0,0 +1,169 @@
+#include "fdisk.h"
+
+
+HANDLE hModule;
+
+// IsDiskRemovable is an array of BOOLEANs each of which indicates
+// whether the corresponding physical disk is removable.
+
+PBOOLEAN IsDiskRemovable = NULL;
+
+// RemovableDiskReservedDriveLetters is an array of CHARs which
+// shows the reserved drive letter for each disk if that disk is
+// removable.
+
+PCHAR RemovableDiskReservedDriveLetters;
+
+// This will be an array of pointers to DISKSTATE structures, indexed
+// by disk number.
+
+PDISKSTATE *Disks;
+
+// BootDiskNumber is the number of the disk on which the boot partition
+// (ie. the disk with the WinNt files) resides. BootPartitionNumber is
+// the original partition number of this partition.
+
+ULONG BootDiskNumber;
+ULONG BootPartitionNumber;
+
+
+// window handles
+
+HANDLE hwndFrame,
+ hwndList;
+
+// GDI objects
+
+HBITMAP hBitmapSmallDisk;
+HBITMAP hBitmapRemovableDisk;
+HDC hDC;
+HFONT hFontGraph,
+ hFontGraphBold;
+HBRUSH Brushes[BRUSH_ARRAY_SIZE];
+HBRUSH hBrushFreeLogical,
+ hBrushFreePrimary;
+HPEN hPenNull,
+ hPenThinSolid;
+HCURSOR hcurWait,
+ hcurNormal;
+
+
+// initial stuff for the disk graphs, used when there is
+// no info in win.ini.
+
+int BrushHatches[BRUSH_ARRAY_SIZE] = { DEFAULT_HATCH_USEDPRIMARY,
+ DEFAULT_HATCH_USEDLOGICAL,
+ DEFAULT_HATCH_STRIPESET,
+ DEFAULT_HATCH_MIRROR,
+ DEFAULT_HATCH_VOLUMESET
+ };
+
+int BrushColors[BRUSH_ARRAY_SIZE] = { DEFAULT_COLOR_USEDPRIMARY,
+ DEFAULT_COLOR_USEDLOGICAL,
+ DEFAULT_COLOR_STRIPESET,
+ DEFAULT_COLOR_MIRROR,
+ DEFAULT_COLOR_VOLUMESET
+ };
+
+// colors and patterns available for the disk graphs
+
+COLORREF AvailableColors[NUM_AVAILABLE_COLORS] = { RGB(0,0,0), // black
+ RGB(128,128,128), // dark gray
+ RGB(192,192,192), // light gray
+ RGB(255,255,255), // white
+ RGB(128,128,0), // dark yellow
+ RGB(128,0,128), // violet
+ RGB(128,0,0), // dark red
+ RGB(0,128,128), // dark cyan
+ RGB(0,128,0), // dark green
+ RGB(0,0,128), // dark blue
+ RGB(255,255,0), // yellow
+ RGB(255,0,255), // light violet
+ RGB(255,0,0), // red
+ RGB(0,255,255), // cyan
+ RGB(0,255,0), // green
+ RGB(0,0,255) // blue
+ };
+
+int AvailableHatches[NUM_AVAILABLE_HATCHES] = { 2,3,4,5,6 };
+
+
+// positions for various items in a disk graph
+
+DWORD GraphWidth,
+ GraphHeight;
+DWORD BarTopYOffset,
+ BarBottomYOffset,
+ BarHeight;
+DWORD dxDriveLetterStatusArea;
+DWORD dxBarTextMargin,
+ dyBarTextLine;
+DWORD dxSmallDisk,
+ dySmallDisk,
+ xSmallDisk,
+ ySmallDisk;
+DWORD dxRemovableDisk,
+ dyRemovableDisk,
+ xRemovableDisk,
+ yRemovableDisk;
+DWORD BarLeftX,
+ BarWidth;
+
+
+// if a single disk region is selected, these vars describe the selection.
+
+PDISKSTATE SingleSel;
+DWORD SingleSelIndex;
+
+// name of help file
+
+PTCHAR HelpFile;
+TCHAR WinHelpFile[] = TEXT("windisk.hlp");
+TCHAR LanmanHelpFile[] = TEXT("windiska.hlp");
+
+
+// number of hard disks attached to the system
+
+unsigned DiskCount = 0;
+
+// class name for frame window
+
+TCHAR szFrame[] = TEXT("fdFrame");
+
+// "Disk %u"
+
+LPTSTR DiskN;
+
+PWSTR wszUnformatted,
+ wszNewUnformatted,
+ wszUnknown;
+
+// If the following is TRUE, the registry needs to be updated and the user will
+// be prompted to save changed just as if he had made changes to any partitions.
+
+BOOL RegistryChanged = FALSE;
+
+// Restart required to make changes work.
+
+BOOL RestartRequired = FALSE;
+
+
+// If the following is TRUE, the main window will pass WM_ENTERIDLE
+// messages on to the child dialog box; this will trigger the
+// configuration search.
+
+BOOL ConfigurationSearchIdleTrigger = FALSE;
+
+// This flag indicates whether this is a Server
+// or just regular Windows NT Workstation.
+
+BOOL IsLanmanNt = FALSE;
+
+// This flag indicates whether double space volume creation
+// and deletion is allowed.
+
+BOOL IsFullDoubleSpace = FALSE;
+
+// Cdrom is present in the system.
+
+ULONG AllowCdRom = FALSE;
diff --git a/private/utils/fdisk/fddlgs.c b/private/utils/fdisk/fddlgs.c
new file mode 100644
index 000000000..a7412cbfc
--- /dev/null
+++ b/private/utils/fdisk/fddlgs.c
@@ -0,0 +1,976 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ fddlgs.c
+
+Abstract:
+
+ Dialog routines and dialog support subroutines.
+
+Author:
+
+ Ted Miller (tedm) 7-Jan-1992
+
+--*/
+
+#include "fdisk.h"
+
+// used in color dialog to indicate what the user has chosen for
+// the various graph element types
+
+DWORD SelectedColor[LEGEND_STRING_COUNT];
+DWORD SelectedHatch[LEGEND_STRING_COUNT];
+
+// used in color dialog, contains element (ie, partition, logical volume,
+// etc) we're selecting for (ie, which item is diaplyed in static text of
+// combo box).
+
+DWORD CurrentElement;
+
+// handle of active color dialogs box. Used by rectangle custom control.
+
+HWND hDlgColor;
+
+BOOL
+InitColorDlg(
+ IN HWND hdlg
+ );
+
+VOID
+CenterDialog(
+ HWND hwnd
+ )
+
+/*++
+
+Routine Description:
+
+ Centers a dialog relative to the app's main window
+
+Arguments:
+
+ hwnd - window handle of dialog to center
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ RECT rcFrame,
+ rcWindow;
+ LONG x,
+ y,
+ w,
+ h;
+ POINT point;
+ LONG sx = GetSystemMetrics(SM_CXSCREEN),
+ sy = GetSystemMetrics(SM_CYSCREEN);
+
+ point.x = point.y = 0;
+ ClientToScreen(hwndFrame,&point);
+ GetWindowRect (hwnd ,&rcWindow);
+ GetClientRect (hwndFrame,&rcFrame );
+
+ w = rcWindow.right - rcWindow.left + 1;
+ h = rcWindow.bottom - rcWindow.top + 1;
+ x = point.x + ((rcFrame.right - rcFrame.left + 1 - w) / 2);
+ y = point.y + ((rcFrame.bottom - rcFrame.top + 1 - h) / 2);
+
+ if (x + w > sx) {
+ x = sx - w;
+ } else if (x < 0) {
+ x = 0;
+ }
+ if (y + h > sy) {
+ y = sy - h;
+ } else if (y < 0) {
+ y = 0;
+ }
+
+ MoveWindow(hwnd,x,y,w,h,FALSE);
+}
+
+BOOL
+MinMaxDlgProc(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN DWORD wParam,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Dialog procedure for the enter size dialog box. This dialog
+ allows the user to enter a size for a partition, or use
+ spin controls (a tiny scroll bar) to select the size.
+ Possible outcomes are cancel or OK. In the latter case the
+ EndDialog code is the size. In the former it is 0.
+
+Arguments:
+
+ hwnd - window handle of dialog box
+
+ msg - message #
+
+ wParam - msg specific data
+
+ lParam - msg specific data
+
+Return Value:
+
+ msg dependent
+
+--*/
+
+{
+ TCHAR outputString[MESSAGE_BUFFER_SIZE];
+ PMINMAXDLG_PARAMS params;
+ BOOL validNumber;
+ DWORD sizeMB;
+ static DWORD minSizeMB,
+ maxSizeMB,
+ helpContextId;
+
+ switch (msg) {
+
+ case WM_INITDIALOG:
+
+ CenterDialog(hwnd);
+ params = (PMINMAXDLG_PARAMS)lParam;
+ // set up caption
+
+ LoadString(hModule, params->CaptionStringID, outputString, sizeof(outputString)/sizeof(TCHAR));
+ SetWindowText(hwnd, outputString);
+
+ // set up minimum/maximum text
+
+ LoadString(hModule, params->MinimumStringID, outputString, sizeof(outputString)/sizeof(TCHAR));
+ SetDlgItemText(hwnd, IDC_MINMAX_MINLABEL, outputString);
+ LoadString(hModule, params->MaximumStringID, outputString, sizeof(outputString)/sizeof(TCHAR));
+ SetDlgItemText(hwnd, IDC_MINMAX_MAXLABEL, outputString);
+ LoadString(hModule, params->SizeStringID, outputString, sizeof(outputString)/sizeof(TCHAR));
+ SetDlgItemText(hwnd, IDC_MINMAX_SIZLABEL, outputString);
+
+ minSizeMB = params->MinSizeMB;
+ maxSizeMB = params->MaxSizeMB;
+ helpContextId = params->HelpContextId;
+
+ wsprintf(outputString, TEXT("%u"), minSizeMB);
+ SetDlgItemText(hwnd, IDC_MINMAX_MIN, outputString);
+ wsprintf(outputString, TEXT("%u"), maxSizeMB);
+ SetDlgItemText(hwnd, IDC_MINMAX_MAX, outputString);
+
+ // also put the size in the edit control and select the text
+
+ wsprintf(outputString, TEXT("%u"), maxSizeMB);
+ SetDlgItemText(hwnd, IDC_MINMAX_SIZE, outputString);
+ SendDlgItemMessage(hwnd, IDC_MINMAX_SIZE, EM_SETSEL, 0, -1);
+ SetFocus(GetDlgItem(hwnd, IDC_MINMAX_SIZE));
+ return FALSE; // indicate focus set to a control
+
+ case WM_VSCROLL:
+
+ switch (LOWORD(wParam)) {
+ case SB_LINEDOWN:
+ case SB_LINEUP:
+ sizeMB = GetDlgItemInt(hwnd, IDC_MINMAX_SIZE, &validNumber, FALSE);
+ if (!validNumber) {
+ Beep(500,100);
+ } else {
+ if (((sizeMB > minSizeMB) && (LOWORD(wParam) == SB_LINEDOWN))
+ || ((sizeMB < maxSizeMB) && (LOWORD(wParam) == SB_LINEUP )))
+ {
+ if (sizeMB > maxSizeMB) {
+ sizeMB = maxSizeMB;
+ } else if (LOWORD(wParam) == SB_LINEUP) {
+ sizeMB++;
+ } else {
+ sizeMB--;
+ }
+ wsprintf(outputString, TEXT("%u"), sizeMB);
+ SetDlgItemText(hwnd, IDC_MINMAX_SIZE, outputString);
+ SendDlgItemMessage(hwnd, IDC_MINMAX_SIZE, EM_SETSEL, 0, -1);
+ } else {
+ Beep(500,100);
+ }
+ }
+ }
+ break;
+
+ case WM_COMMAND:
+
+ switch (LOWORD(wParam)) {
+
+ case IDOK:
+
+ sizeMB = GetDlgItemInt(hwnd, IDC_MINMAX_SIZE, &validNumber, FALSE);
+ if (!validNumber || !sizeMB || (sizeMB > maxSizeMB) || (sizeMB < minSizeMB)) {
+ ErrorDialog(MSG_INVALID_SIZE);
+ } else {
+ EndDialog(hwnd, sizeMB);
+ }
+ break;
+
+ case IDCANCEL:
+
+ EndDialog(hwnd, 0);
+ break;
+
+ case FD_IDHELP:
+
+ DialogHelp(helpContextId);
+ break;
+
+ default:
+
+ return FALSE;
+ }
+ break;
+
+ default:
+
+ return FALSE;
+ }
+ return TRUE;
+}
+
+BOOL
+DriveLetterDlgProc(
+ IN HWND hdlg,
+ IN DWORD msg,
+ IN DWORD wParam,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Dialog for allowing the user to select a drive letter for a
+ partition, logical drive, volume set, or stripe set.
+
+ The EndDialog codes are as follows:
+
+ 0 - user cancelled
+ NO_DRIVE_LETTER_EVER - user opted not to assign a drive letter
+ other - the drive letter chosen by the user
+
+Arguments:
+
+ hdlg - window handle of dialog box
+
+ msg - message #
+
+ wParam - msg specific data
+
+ lParam - msg specific data
+
+Return Value:
+
+ msg dependent
+
+--*/
+
+{
+ static HWND hwndCombo;
+ static DWORD currentSelection;
+ TCHAR driveLetter;
+ TCHAR driveLetterString[3];
+ DWORD defRadioButton,
+ selection;
+ PREGION_DESCRIPTOR regionDescriptor;
+ PFT_OBJECT ftObject;
+ TCHAR description[256];
+
+ switch (msg) {
+
+ case WM_INITDIALOG:
+
+ // lParam points to the region descriptor
+
+ regionDescriptor = (PREGION_DESCRIPTOR)lParam;
+ FDASSERT(DmSignificantRegion(regionDescriptor));
+
+ hwndCombo = GetDlgItem(hdlg,IDC_DRIVELET_COMBOBOX);
+ CenterDialog(hdlg);
+
+ // Add each available drive letter to the list of available
+ // drive letters.
+
+ driveLetterString[1] = TEXT(':');
+ driveLetterString[2] = 0;
+ for (driveLetter='C'; driveLetter <= 'Z'; driveLetter++) {
+ if (DriveLetterIsAvailable((CHAR)driveLetter)) {
+ *driveLetterString = driveLetter;
+ SendMessage(hwndCombo, CB_ADDSTRING, 0, (LONG)driveLetterString);
+ }
+ }
+
+ // Format the description of the partition.
+
+ if (ftObject = GET_FT_OBJECT(regionDescriptor)) {
+
+ TCHAR descr[256];
+ DWORD resid = 0;
+
+ // Ft. Description is something like "Stripe set with parity #0"
+
+ switch (ftObject->Set->Type) {
+ case Mirror:
+ resid = IDS_DLGCAP_MIRROR;
+ break;
+ case Stripe:
+ resid = IDS_STATUS_STRIPESET;
+ break;
+ case StripeWithParity:
+ resid = IDS_DLGCAP_PARITY;
+ break;
+ case VolumeSet:
+ resid = IDS_STATUS_VOLUMESET;
+ break;
+ default:
+ FDASSERT(FALSE);
+ }
+
+ LoadString(hModule, resid, descr, sizeof(descr)/sizeof(TCHAR));
+ wsprintf(description, descr, ftObject->Set->Ordinal);
+
+ } else {
+
+ // Non-ft. Description is something like '500 MB Unformatted
+ // logical drive on disk 3' or '400 MB HPFS partition on disk 4'
+
+ LPTSTR args[4];
+ TCHAR sizeStr[20],
+ partTypeStr[100],
+ diskNoStr[10],
+ typeName[150];
+ TCHAR formatString[256];
+
+ args[0] = sizeStr;
+ args[1] = typeName;
+ args[2] = partTypeStr;
+ args[3] = diskNoStr;
+
+ wsprintf(sizeStr, "%u", regionDescriptor->SizeMB);
+ wsprintf(typeName, "%ws", PERSISTENT_DATA(regionDescriptor)->TypeName);
+ LoadString(hModule, regionDescriptor->RegionType == REGION_LOGICAL ? IDS_LOGICALVOLUME : IDS_PARTITION, partTypeStr, sizeof(partTypeStr)/sizeof(TCHAR));
+ wsprintf(diskNoStr, "%u", regionDescriptor->Disk);
+
+ LoadString(hModule, IDS_DRIVELET_DESCR, formatString, sizeof(formatString)/sizeof(TCHAR));
+ FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
+ formatString,
+ 0,
+ 0,
+ description,
+ sizeof(description),
+ (va_list *)args);
+ }
+
+ SetWindowText(GetDlgItem(hdlg, IDC_DRIVELET_DESCR), description);
+ driveLetter = (TCHAR)PERSISTENT_DATA(regionDescriptor)->DriveLetter;
+
+ if ((driveLetter != NO_DRIVE_LETTER_YET) && (driveLetter != NO_DRIVE_LETTER_EVER)) {
+
+ DWORD itemIndex;
+
+ // There is a default drive letter. Place it on the list,
+ // check the correct radio button, and set the correct default
+ // in the combo box.
+
+ driveLetterString[0] = (TCHAR)driveLetter;
+ itemIndex = SendMessage(hwndCombo, CB_ADDSTRING, 0, (LONG)driveLetterString);
+ SendMessage(hwndCombo, CB_SETCURSEL, itemIndex, 0);
+ defRadioButton = IDC_DRIVELET_RBASSIGN;
+ SetFocus(hwndCombo);
+ currentSelection = itemIndex;
+
+ } else {
+
+ // Default is no drive letter. Disable the combo box. Select
+ // the correct radio button.
+
+ EnableWindow(hwndCombo, FALSE);
+ defRadioButton = IDC_DRIVELET_RBNOASSIGN;
+ SendMessage(hwndCombo, CB_SETCURSEL, (DWORD)(-1), 0);
+ SetFocus(GetDlgItem(hdlg, IDC_DRIVELET_RBNOASSIGN));
+ currentSelection = 0;
+ }
+
+ CheckRadioButton(hdlg, IDC_DRIVELET_RBASSIGN, IDC_DRIVELET_RBNOASSIGN, defRadioButton);
+ return FALSE; // focus set to control
+
+ case WM_COMMAND:
+
+ switch (LOWORD(wParam)) {
+
+ case IDOK:
+
+ // If the 'no letter' button is checked, return NO_DRIVE_LETTER_EVER
+
+ if (IsDlgButtonChecked(hdlg, IDC_DRIVELET_RBNOASSIGN)) {
+ EndDialog(hdlg, NO_DRIVE_LETTER_EVER);
+ break;
+ }
+
+ // Otherwise, get the currently selected item in the listbox.
+
+ selection = SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
+ SendMessage(hwndCombo, CB_GETLBTEXT, selection, (LONG)driveLetterString);
+ EndDialog(hdlg,(int)(unsigned)(*driveLetterString));
+ break;
+
+ case IDCANCEL:
+
+ EndDialog(hdlg, 0);
+ break;
+
+ case FD_IDHELP:
+
+ DialogHelp(HC_DM_DLG_DRIVELETTER);
+ break;
+
+ case IDC_DRIVELET_RBASSIGN:
+
+ if (HIWORD(wParam) == BN_CLICKED) {
+ EnableWindow(hwndCombo, TRUE);
+ SendMessage(hwndCombo, CB_SETCURSEL, currentSelection, 0);
+ SetFocus(hwndCombo);
+ }
+ break;
+
+ case IDC_DRIVELET_RBNOASSIGN:
+
+ if (HIWORD(wParam) == BN_CLICKED) {
+ currentSelection = SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
+ SendMessage(hwndCombo, CB_SETCURSEL, (DWORD)-1, 0);
+ EnableWindow(hwndCombo, FALSE);
+ }
+ break;
+
+ default:
+
+ return FALSE;
+ }
+ break;
+
+ default:
+
+ return FALSE;
+ }
+ return TRUE;
+}
+
+BOOL
+DisplayOptionsDlgProc(
+ IN HWND hdlg,
+ IN UINT msg,
+ IN DWORD wParam,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Dialog procedure for display options. Currently the only display option
+ is to alter the graph type (proportional/equal) on each disk.
+
+ For this dialog, lParam on creation must point to a buffer into which
+ this dialog procedure will place the user's new choices for the graph
+ display type for each disk.
+
+Arguments:
+
+ hdlg - window handle of dialog box
+
+ msg - message #
+
+ wParam - msg specific data
+
+ lParam - msg specific data
+
+Return Value:
+
+ msg dependent
+
+--*/
+
+{
+ static PBAR_TYPE newBarTypes;
+ static HWND hwndCombo;
+ DWORD selection;
+ DWORD i;
+
+ switch (msg) {
+
+ case WM_INITDIALOG:
+
+ CenterDialog(hdlg);
+ newBarTypes = (PBAR_TYPE)lParam;
+ hwndCombo = GetDlgItem(hdlg, IDC_DISK_COMBOBOX);
+
+ // Add each disk to the combo box.
+
+ for (i=0; i<DiskCount; i++) {
+
+ TCHAR str[10];
+
+ wsprintf(str,TEXT("%u"),i);
+ SendMessage(hwndCombo, CB_ADDSTRING, 0, (DWORD)str);
+ }
+
+ // select the zeroth item in the combobox
+ SendMessage(hwndCombo, CB_SETCURSEL, 0, 0);
+ SendMessage(hdlg,
+ WM_COMMAND,
+ MAKELONG(IDC_DISK_COMBOBOX,CBN_SELCHANGE),
+ 0);
+ break;
+
+ case WM_COMMAND:
+
+ switch (LOWORD(wParam)) {
+
+ case IDOK:
+ EndDialog(hdlg, IDOK);
+ break;
+
+ case IDCANCEL:
+ EndDialog(hdlg, IDCANCEL);
+ break;
+
+ case FD_IDHELP:
+ DialogHelp(HC_DM_DLG_DISPLAYOPTION);
+ break;
+
+ case IDC_DISK_COMBOBOX:
+
+ if (HIWORD(wParam) == CBN_SELCHANGE) {
+
+ int rb = 0;
+
+ // Selection in the combobox has changed; update the radio buttons
+
+ selection = SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
+
+ switch (newBarTypes[selection]) {
+ case BarProportional:
+ rb = IDC_RBPROPORTIONAL;
+ break;
+ case BarEqual:
+ rb = IDC_RBEQUAL;
+ break;
+ case BarAuto:
+ rb = IDC_RBAUTO;
+ break;
+ default:
+ FDASSERT(0);
+ }
+
+ CheckRadioButton(hdlg, IDC_RBPROPORTIONAL, IDC_RBAUTO, rb);
+ }
+ break;
+
+ case IDC_RESETALL:
+
+ if (HIWORD(wParam) == BN_CLICKED) {
+ for (i=0; i<DiskCount; i++) {
+ newBarTypes[i] = BarAuto;
+ }
+ CheckRadioButton(hdlg, IDC_RBPROPORTIONAL, IDC_RBAUTO, IDC_RBAUTO);
+ }
+ break;
+
+ case IDC_RBPROPORTIONAL:
+
+ if (HIWORD(wParam) == BN_CLICKED) {
+ selection = SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
+ newBarTypes[selection] = BarProportional;
+ }
+ break;
+
+ case IDC_RBEQUAL:
+
+ if (HIWORD(wParam) == BN_CLICKED) {
+ selection = SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
+ newBarTypes[selection] = BarEqual;
+ }
+ break;
+
+ case IDC_RBAUTO:
+
+ if (HIWORD(wParam) == BN_CLICKED) {
+ selection = SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
+ newBarTypes[selection] = BarAuto;
+ }
+ break;
+
+ default:
+ return FALSE;
+ }
+ break;
+
+ default:
+
+ return FALSE;
+ }
+ return TRUE;
+}
+
+BOOL
+ColorDlgProc(
+ IN HWND hdlg,
+ IN DWORD msg,
+ IN DWORD wParam,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Dialog for the select colors/patterns dialog box. Note that this dialog
+ uses a rectangle custom control, defined below.
+
+Arguments:
+
+ hwnd - window handle of dialog box
+
+ msg - message #
+
+ wParam - msg specific data
+
+ lParam - msg specific data
+
+Return Value:
+
+ msg dependent
+
+--*/
+
+{
+ unsigned i;
+
+ switch (msg) {
+
+ case WM_INITDIALOG:
+
+ #if BRUSH_ARRAY_SIZE != LEGEND_STRING_COUNT
+ #error legend label array and brush array are out of sync
+ #endif
+
+ if (!InitColorDlg(hdlg)) {
+ EndDialog(hdlg, -1);
+ }
+ break;
+
+ case WM_COMMAND:
+
+ switch (LOWORD(wParam)) {
+
+ case IDOK:
+
+ for (i=0; i<LEGEND_STRING_COUNT; i++) {
+ SelectedColor[i] -= IDC_COLOR1;
+ SelectedHatch[i] -= IDC_PATTERN1;
+ }
+ EndDialog(hdlg, IDOK);
+ break;
+
+ case IDCANCEL:
+ EndDialog(hdlg, IDCANCEL);
+ break;
+
+ case FD_IDHELP:
+ DialogHelp(HC_DM_COLORSANDPATTERNS);
+ break;
+
+ case IDC_COLORDLGCOMBO:
+ switch (HIWORD(wParam)) {
+ case CBN_SELCHANGE:
+ // deselect previous color
+ SendMessage(GetDlgItem(hdlg, SelectedColor[CurrentElement]),
+ RM_SELECT,
+ FALSE,
+ 0);
+ // deselect previous pattern
+ SendMessage(GetDlgItem(hdlg, SelectedHatch[CurrentElement]),
+ RM_SELECT,
+ FALSE,
+ 0);
+ CurrentElement = SendMessage((HWND)lParam, CB_GETCURSEL, 0, 0);
+ SendMessage(hdlg, WM_COMMAND, MAKELONG(SelectedColor[CurrentElement], 0), 0);
+ SendMessage(hdlg, WM_COMMAND, MAKELONG(SelectedHatch[CurrentElement], 0), 0);
+ break;
+ default:
+ return FALSE;
+ }
+ break;
+
+ case IDC_COLOR1:
+ case IDC_COLOR2:
+ case IDC_COLOR3:
+ case IDC_COLOR4:
+ case IDC_COLOR5:
+ case IDC_COLOR6:
+ case IDC_COLOR7:
+ case IDC_COLOR8:
+ case IDC_COLOR9:
+ case IDC_COLOR10:
+ case IDC_COLOR11:
+ case IDC_COLOR12:
+ case IDC_COLOR13:
+ case IDC_COLOR14:
+ case IDC_COLOR15:
+ case IDC_COLOR16:
+ // deselect previous color
+
+ SendMessage(GetDlgItem(hdlg, SelectedColor[CurrentElement]),
+ RM_SELECT,
+ FALSE,
+ 0);
+ SendMessage(GetDlgItem(hdlg, LOWORD(wParam)),
+ RM_SELECT,
+ TRUE,
+ 0);
+ SelectedColor[CurrentElement] = LOWORD(wParam);
+
+ // now force patterns to be redrawn in selected color
+
+ for (i=IDC_PATTERN1; i<=IDC_PATTERN5; i++) {
+ InvalidateRect(GetDlgItem(hdlg, i), NULL, FALSE);
+ }
+ break;
+
+ case IDC_PATTERN1:
+ case IDC_PATTERN2:
+ case IDC_PATTERN3:
+ case IDC_PATTERN4:
+ case IDC_PATTERN5:
+ // deselect previous pattern
+ SendMessage(GetDlgItem(hdlg, SelectedHatch[CurrentElement]),
+ RM_SELECT,
+ FALSE,
+ 0);
+ SendMessage(GetDlgItem(hdlg, LOWORD(wParam)),
+ RM_SELECT,
+ TRUE,
+ 0);
+ SelectedHatch[CurrentElement] = LOWORD(wParam);
+ break;
+ }
+ break;
+
+ default:
+ return FALSE;
+ }
+ return TRUE;
+}
+
+BOOL
+InitColorDlg(
+ IN HWND hdlg
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the color selection dialog.
+
+Arguments:
+
+ hdlg - the dialog handle.
+
+Return Value:
+
+ TRUE - successfully set up the dialog.
+
+--*/
+
+{
+ unsigned i;
+ LONG ec;
+ HWND hwndCombo = GetDlgItem(hdlg, IDC_COLORDLGCOMBO);
+
+ hDlgColor = hdlg;
+
+ CenterDialog(hdlg);
+
+ for (i=0; i<LEGEND_STRING_COUNT; i++) {
+ ec = SendMessage(hwndCombo, CB_ADDSTRING, 0, (LONG)LegendLabels[i]);
+ if ((ec == CB_ERR) || (ec == CB_ERRSPACE)) {
+ return FALSE;
+ }
+ SelectedColor[i] = IDC_COLOR1 + BrushColors[i];
+ SelectedHatch[i] = IDC_PATTERN1 + BrushHatches[i];
+ }
+ SendMessage(hwndCombo, CB_SETCURSEL, CurrentElement=0, 0);
+ SendMessage(hdlg, WM_COMMAND, MAKELONG(GetDlgCtrlID(hwndCombo), CBN_SELCHANGE), (LONG)hwndCombo);
+ return TRUE;
+}
+
+LONG
+RectWndProc(
+ IN HWND hwnd,
+ IN DWORD msg,
+ IN DWORD wParam,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ This is a pre-process routine for all access to the disk
+ bar display region of the WinDisk interface.
+
+Arguments:
+
+ hwnd - the dialog handle
+ msg - the windows message for the dialog
+ wParam/lParam - windows dialog parameters.
+
+Return Value:
+
+ Standard dialog requirements.
+
+--*/
+
+{
+ LONG res = 1;
+ PAINTSTRUCT ps;
+ RECT rc;
+ int CtlID;
+ HBRUSH hbr,
+ hbrT;
+ DWORD style;
+
+ switch (msg) {
+
+ case WM_CREATE:
+
+ FDASSERT(GetWindowLong(hwnd, GWL_STYLE) & (RS_PATTERN | RS_COLOR));
+ SetWindowWord(hwnd, GWW_SELECTED, FALSE);
+ break;
+
+ case WM_LBUTTONDOWN:
+
+ SetFocus(hwnd);
+ break;
+
+ case WM_SETFOCUS:
+
+ SendMessage(GetParent(hwnd), WM_COMMAND, MAKELONG(GetDlgCtrlID(hwnd), RN_CLICKED), (LONG)hwnd);
+ break;
+
+ case WM_PAINT:
+
+ GetClientRect(hwnd, &rc);
+ CtlID = GetDlgCtrlID(hwnd);
+ BeginPaint(hwnd, &ps);
+
+ hbr = CreateSolidBrush(GetWindowWord(hwnd, GWW_SELECTED)
+ ? (~GetSysColor(COLOR_WINDOW)) & 0xffffff
+ : GetSysColor(COLOR_WINDOW));
+ hbrT = SelectObject(ps.hdc,hbr);
+ SelectObject(ps.hdc, hPenNull);
+ Rectangle(ps.hdc, rc.left, rc.top, rc.right, rc.bottom);
+
+ if (hbrT) {
+ SelectObject(ps.hdc, hbrT);
+ }
+ DeleteObject(hbr);
+
+ InflateRect(&rc, -2, -2);
+ rc.right--;
+ rc.bottom--;
+
+ if (GetWindowLong(hwnd, GWL_STYLE) & RS_COLOR) {
+ hbr = CreateSolidBrush(AvailableColors[CtlID-IDC_COLOR1]);
+ } else {
+ hbr = CreateHatchBrush(AvailableHatches[CtlID-IDC_PATTERN1], AvailableColors[SelectedColor[SendMessage(GetDlgItem(hDlgColor, IDC_COLORDLGCOMBO), CB_GETCURSEL, 0, 0)]-IDC_COLOR1]);
+ }
+
+ hbrT = SelectObject(ps.hdc, hbr);
+ SelectObject(ps.hdc, hPenThinSolid);
+ Rectangle(ps.hdc, rc.left, rc.top, rc.right, rc.bottom);
+
+ if (hbrT) {
+ SelectObject(ps.hdc, hbrT);
+ }
+
+ DeleteObject(hbr);
+
+ EndPaint(hwnd, &ps);
+ break;
+
+ case RM_SELECT:
+
+ // wParam = TRUE/FALSE for selected/not selected
+
+ if (GetWindowWord(hwnd, GWW_SELECTED) != (WORD)wParam) {
+
+ SetWindowWord(hwnd, GWW_SELECTED, (WORD)wParam);
+ InvalidateRect(hwnd, NULL, FALSE);
+
+ // make keyboard interface work correctly
+
+ style = (DWORD)GetWindowLong(hwnd, GWL_STYLE);
+ style = wParam ? style | WS_TABSTOP : style & ~WS_TABSTOP;
+ SetWindowLong(hwnd, GWL_STYLE, (LONG)style);
+ }
+
+ break;
+
+ default:
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+ return res;
+}
+
+VOID
+InitRectControl(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Register the windows class for the selection control.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ WNDCLASS wc;
+
+ wc.style = 0;
+ wc.lpfnWndProc = (WNDPROC)RectWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = RECTCONTROL_WNDEXTRA;
+ wc.hInstance = hModule;
+ wc.hIcon = NULL;
+ wc.hCursor = NULL;
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = TEXT(RECTCONTROL);
+
+ RegisterClass(&wc);
+}
diff --git a/private/utils/fdisk/fdengine.c b/private/utils/fdisk/fdengine.c
new file mode 100644
index 000000000..8aaa91564
--- /dev/null
+++ b/private/utils/fdisk/fdengine.c
@@ -0,0 +1,3734 @@
+/*++
+
+Copyright (c) 1991-1994 Microsoft Corporation
+
+Module Name:
+
+ fdengine.c
+
+Abstract:
+
+ This module contains the disk partitioning engine. The code
+ in this module can be compiled for either the NT platform
+ or the ARC platform (-DARC).
+
+Author:
+
+ Ted Miller (tedm) Nov-1991
+
+Revision History:
+
+ Bob Rinne (bobri) Feb-1994
+ Moved as actual part of Disk Administrator enlistment instead of being
+ copied from ArcInst. This is due to dynamic partition changes. Removed
+ string table that made this an internationalized file.
+
+--*/
+
+#include "fdisk.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+// Attached disk devices.
+
+ULONG CountOfDisks;
+PCHAR *DiskNames;
+
+// Information about attached disks.
+
+DISKGEOM *DiskGeometryArray;
+
+PPARTITION *PrimaryPartitions,
+ *LogicalVolumes;
+
+// A 'signature' is a unique 4-byte value immediately preceeding the
+// partition table in the MBR.
+
+PULONG Signatures;
+
+// Array keeping track of whether each disk is off line.
+
+PBOOLEAN OffLine;
+
+// Keeps track of whether changes have been requested
+// to each disk's partition structure.
+
+BOOLEAN *ChangesRequested;
+BOOLEAN *ChangesCommitted;
+
+
+// Value used to indicate that the partition entry has changed but in a non-
+// destructive way (ie, made active/inactive).
+
+#define CHANGED_DONT_ZAP ((BOOLEAN)(5))
+
+// forward declarations
+
+
+STATUS_CODE
+OpenDisks(
+ VOID
+ );
+
+VOID
+CloseDisks(
+ VOID
+ );
+
+STATUS_CODE
+GetGeometry(
+ VOID
+ );
+
+BOOLEAN
+CheckIfDiskIsOffLine(
+ IN ULONG Disk
+ );
+
+STATUS_CODE
+InitializePartitionLists(
+ VOID
+ );
+
+STATUS_CODE
+GetRegions(
+ IN ULONG Disk,
+ IN PPARTITION p,
+ IN BOOLEAN WantUsedRegions,
+ IN BOOLEAN WantFreeRegions,
+ IN BOOLEAN WantLogicalRegions,
+ OUT PREGION_DESCRIPTOR *Region,
+ OUT ULONG *RegionCount,
+ IN REGION_TYPE RegionType
+ );
+
+BOOLEAN
+AddRegionEntry(
+ IN OUT PREGION_DESCRIPTOR *Regions,
+ IN OUT ULONG *RegionCount,
+ IN ULONG SizeMB,
+ IN REGION_TYPE RegionType,
+ IN PPARTITION Partition,
+ IN LARGE_INTEGER AlignedRegionOffset,
+ IN LARGE_INTEGER AlignedRegionSize
+ );
+
+VOID
+AddPartitionToLinkedList(
+ IN PARTITION **Head,
+ IN PARTITION *p
+ );
+
+BOOLEAN
+IsInLinkedList(
+ IN PPARTITION p,
+ IN PPARTITION List
+ );
+
+BOOLEAN
+IsInLogicalList(
+ IN ULONG Disk,
+ IN PPARTITION p
+ );
+
+BOOLEAN
+IsInPartitionList(
+ IN ULONG Disk,
+ IN PPARTITION p
+ );
+
+LARGE_INTEGER
+AlignTowardsDiskStart(
+ IN ULONG Disk,
+ IN LARGE_INTEGER Offset
+ );
+
+LARGE_INTEGER
+AlignTowardsDiskEnd(
+ IN ULONG Disk,
+ IN LARGE_INTEGER Offset
+ );
+
+VOID
+FreeLinkedPartitionList(
+ IN PARTITION **q
+ );
+
+VOID
+MergeFreePartitions(
+ IN PPARTITION p
+ );
+
+VOID
+FreePartitionInfoLinkedLists(
+ IN PARTITION **ListHeadArray
+ );
+
+LARGE_INTEGER
+DiskLengthBytes(
+ IN ULONG Disk
+ );
+
+PPARTITION
+AllocatePartitionStructure(
+ IN ULONG Disk,
+ IN LARGE_INTEGER Offset,
+ IN LARGE_INTEGER Length,
+ IN UCHAR SysID,
+ IN BOOLEAN Update,
+ IN BOOLEAN Active,
+ IN BOOLEAN Recognized
+ );
+
+STATUS_CODE
+LowFreeFdiskPathList(
+ IN OUT PCHAR* PathList,
+ IN ULONG ListLength
+ );
+
+STATUS_CODE
+LowQueryFdiskPathList(
+ OUT PCHAR **PathList,
+ OUT PULONG ListLength
+ );
+
+
+STATUS_CODE
+FdiskInitialize(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the partitioning engine, including allocating
+ arrays, determining attached disk devices, and reading their
+ partition tables.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+ STATUS_CODE status;
+ ULONG i;
+
+
+ if ((status = LowQueryFdiskPathList(&DiskNames, &CountOfDisks)) != OK_STATUS) {
+ return status;
+ }
+
+ DiskGeometryArray = NULL;
+ PrimaryPartitions = NULL;
+ LogicalVolumes = NULL;
+
+ if (((DiskGeometryArray = AllocateMemory(CountOfDisks * sizeof(DISKGEOM ))) == NULL)
+ || ((ChangesRequested = AllocateMemory(CountOfDisks * sizeof(BOOLEAN ))) == NULL)
+ || ((ChangesCommitted = AllocateMemory(CountOfDisks * sizeof(BOOLEAN ))) == NULL)
+ || ((PrimaryPartitions = AllocateMemory(CountOfDisks * sizeof(PPARTITION))) == NULL)
+ || ((Signatures = AllocateMemory(CountOfDisks * sizeof(ULONG ))) == NULL)
+ || ((OffLine = AllocateMemory(CountOfDisks * sizeof(BOOLEAN ))) == NULL)
+ || ((LogicalVolumes = AllocateMemory(CountOfDisks * sizeof(PPARTITION))) == NULL))
+ {
+ RETURN_OUT_OF_MEMORY;
+ }
+
+ for (i=0; i<CountOfDisks; i++) {
+ PrimaryPartitions[i] = NULL;
+ LogicalVolumes[i] = NULL;
+ ChangesRequested[i] = FALSE;
+ ChangesCommitted[i] = FALSE;
+ OffLine[i] = CheckIfDiskIsOffLine(i);
+ }
+
+ if (((status = GetGeometry() ) != OK_STATUS)
+ || ((status = InitializePartitionLists()) != OK_STATUS)) {
+ return status;
+ }
+
+ return OK_STATUS;
+}
+
+
+VOID
+FdiskCleanUp(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deallocates storage used by the partitioning engine.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LowFreeFdiskPathList(DiskNames, CountOfDisks);
+
+ if (DiskGeometryArray != NULL) {
+ FreeMemory(DiskGeometryArray);
+ }
+ if (PrimaryPartitions != NULL) {
+ FreePartitionInfoLinkedLists(PrimaryPartitions);
+ FreeMemory(PrimaryPartitions);
+ }
+ if (LogicalVolumes != NULL) {
+ FreePartitionInfoLinkedLists(LogicalVolumes);
+ FreeMemory(LogicalVolumes);
+ }
+ if (ChangesRequested != NULL) {
+ FreeMemory(ChangesRequested);
+ }
+ if (ChangesCommitted != NULL) {
+ FreeMemory(ChangesCommitted);
+ }
+ if (OffLine != NULL) {
+ FreeMemory(OffLine);
+ }
+ if (Signatures != NULL) {
+ FreeMemory(Signatures);
+ }
+}
+
+
+BOOLEAN
+CheckIfDiskIsOffLine(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ Determine whether a disk is off-line by attempting to open it.
+ If this is diskman, also attempt to read from it.
+
+Arguments:
+
+ Disk - supplies number of the disk to check
+
+Return Value:
+
+ TRUE if disk is off-line, FALSE is disk is on-line.
+
+--*/
+
+{
+ HANDLE_T handle;
+ UINT errorMode;
+ BOOLEAN isOffLine = TRUE;
+
+ errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+ if (LowOpenDisk(GetDiskName(Disk), &handle) == OK_STATUS) {
+
+ ULONG dummy,
+ bps;
+ PVOID unalignedBuffer,
+ buffer;
+
+ // The open might succeed even if the disk is off line. So to be
+ // sure, read the first sector from the disk.
+
+ if (NT_SUCCESS(LowGetDriveGeometry(GetDiskName(Disk), &dummy, &bps, &dummy, &dummy))) {
+
+ unalignedBuffer = Malloc(2*bps);
+ buffer = (PVOID)(((ULONG)unalignedBuffer+bps) & ~(bps-1));
+
+ if (NT_SUCCESS(LowReadSectors(handle,bps,0,1,buffer))) {
+ isOffLine = FALSE;
+ }
+
+ Free(unalignedBuffer);
+ } else {
+
+ // It is possible this is a removable drive.
+
+ if (IsRemovable(Disk)) {
+ isOffLine = FALSE;
+ }
+ }
+ LowCloseDisk(handle);
+ }
+ SetErrorMode(errorMode);
+
+ return isOffLine;
+}
+
+
+STATUS_CODE
+GetGeometry(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines disk geometry for each disk device.
+ Disk geometry includes heads, sectors per track, cylinder count,
+ and bytes per sector. It also includes bytes per track and
+ bytes per cylinder, which are calculated from the other values
+ for the convenience of the rest of this module.
+
+ Geometry information is placed in the DiskGeometryArray global variable.
+
+ Geometry information is undefined for an off-line disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+ ULONG i;
+ STATUS_CODE status;
+ ULONG TotalSectorCount,
+ SectorSize,
+ SectorsPerTrack,
+ Heads;
+
+ for (i=0; i<CountOfDisks; i++) {
+
+ if (OffLine[i]) {
+ continue;
+ }
+
+ if ((status = LowGetDriveGeometry(DiskNames[i],&TotalSectorCount,&SectorSize,&SectorsPerTrack,&Heads)) != OK_STATUS) {
+ return(status);
+ }
+
+ DiskGeometryArray[i].BytesPerSector = SectorSize;
+ DiskGeometryArray[i].SectorsPerTrack = SectorsPerTrack;
+ DiskGeometryArray[i].Heads = Heads;
+ DiskGeometryArray[i].Cylinders.QuadPart = (TotalSectorCount / (SectorsPerTrack * Heads));
+ DiskGeometryArray[i].BytesPerTrack = SectorsPerTrack * SectorSize;
+ DiskGeometryArray[i].BytesPerCylinder = SectorsPerTrack * SectorSize * Heads;
+ }
+ return(OK_STATUS);
+}
+
+
+#if i386
+VOID
+SetPartitionActiveFlag(
+ IN PREGION_DESCRIPTOR Region,
+ IN UCHAR value
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ PPARTITION p = ((PREGION_DATA)Region->Reserved)->Partition;
+
+ if((UCHAR)p->Active != value) {
+
+ //
+ // Unfortuneately, the Update flag becomes the RewritePartition flag
+ // at commit time. This causes us to zap the boot sector. To avoid
+ // this, we use a spacial non-boolean value that can be checked for
+ // at commit time and that will cause us NOT to zap the bootsector
+ // even though RewritePartition will be TRUE.
+ //
+
+ p->Active = value;
+ if(!p->Update) {
+ p->Update = CHANGED_DONT_ZAP;
+ }
+ ChangesRequested[p->Disk] = TRUE;
+ }
+}
+#endif
+
+
+VOID
+DetermineCreateSizeAndOffset(
+ IN PREGION_DESCRIPTOR Region,
+ IN LARGE_INTEGER MinimumSize,
+ IN ULONG CreationSizeMB,
+ IN REGION_TYPE Type,
+ OUT PLARGE_INTEGER CreationStart,
+ OUT PLARGE_INTEGER CreationSize
+ )
+
+/*++
+
+Routine Description:
+
+ Determine the actual offset and size of the partition, given the
+ size in megabytes.
+
+Arguments:
+
+ Region - a region descriptor returned by GetDiskRegions(). Must
+ be an unused region.
+
+ MinimumSize - if non-0, this is the minimum size that the partition
+ or logical drive can be.
+
+ CreationSizeMB - If MinimumSize is 0, size of partition to create, in MB.
+
+ Type - REGION_PRIMARY, REGION_EXTENDED, or REGION_LOGICAL, for
+ creating a primary partition, extended partition, or
+ logical volume, respectively.
+
+ CreationStart - receives the offset where the partition should be placed.
+
+ CreationSize - receives the exact size for the partition.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREGION_DATA createData = Region->Reserved;
+ ULONG bpc = DiskGeometryArray[Region->Disk].BytesPerCylinder;
+ ULONG bpt = DiskGeometryArray[Region->Disk].BytesPerTrack;
+ LARGE_INTEGER cSize,
+ cStart,
+ mod;
+
+ //
+ // If we are creating a partition at offset 0, adjust the aligned region
+ // offset and the aligned region size, because no partition can actually
+ // start at offset 0.
+ //
+
+ if (!createData->AlignedRegionOffset.QuadPart) {
+
+ LARGE_INTEGER delta;
+
+ if (Type == REGION_EXTENDED) {
+ delta.QuadPart = bpc;
+ } else {
+ delta.QuadPart = bpt;
+ }
+
+ createData->AlignedRegionOffset = delta;
+ createData->AlignedRegionSize.QuadPart -= delta.QuadPart;
+ }
+
+ cStart = createData->AlignedRegionOffset;
+ if (!MinimumSize.QuadPart) {
+ cSize.QuadPart = UInt32x32To64(CreationSizeMB, ONE_MEG);
+ } else {
+ cSize = MinimumSize;
+ if (Type == REGION_LOGICAL) {
+ cSize.QuadPart += bpt;
+ }
+ }
+
+ //
+ // Decide whether to align the ending cylinder up or down.
+ // If the offset of end of the partition is more than half way into the
+ // final cylinder, align towrds the disk end. Otherwise align toward
+ // the disk start.
+ //
+
+ mod.QuadPart = (cStart.QuadPart + cSize.QuadPart) % bpc;
+ if (mod.QuadPart) {
+
+ if ((MinimumSize.QuadPart) || (mod.QuadPart > (bpc/2))) {
+ cSize.QuadPart += ((LONGLONG)bpc - mod.QuadPart);
+ } else {
+ cSize.QuadPart -= mod.QuadPart; // snap downwards to cyl boundary
+ }
+ }
+
+ if (cSize.QuadPart > createData->AlignedRegionSize.QuadPart) {
+
+ //
+ // Space available in the free space isn't large enough to accomodate
+ // the request; just use the entire free space.
+ //
+
+ cSize = createData->AlignedRegionSize;
+ }
+
+ *CreationStart = cStart;
+ *CreationSize = cSize;
+}
+
+
+STATUS_CODE
+CreatePartitionEx(
+ IN PREGION_DESCRIPTOR Region,
+ IN LARGE_INTEGER MinimumSize,
+ IN ULONG CreationSizeMB,
+ IN REGION_TYPE Type,
+ IN UCHAR SysId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a partition from a free region on the disk. The
+ partition is always created at the beginning of the free space, and any
+ left over space at the end is kept on the free space list.
+
+Arguments:
+
+ Region - a region descriptor returned by GetDiskRegions(). Must
+ be an unused region.
+
+ CreationSizeMB - size of partition to create, in MB.
+
+ Type - REGION_PRIMARY, REGION_EXTENDED, or REGION_LOGICAL, for
+ creating a primary partition, extended pasrtition, or
+ logical volume, respectively.
+
+ SysId - system ID byte to be assigned to the partition
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+ PPARTITION p1,
+ p2,
+ p3;
+ PREGION_DATA createData = Region->Reserved;
+ LARGE_INTEGER creationStart,
+ creationSize,
+ leftOver,
+ offset,
+ length;
+ PPARTITION *partitionList;
+
+ DetermineCreateSizeAndOffset(Region,
+ MinimumSize,
+ CreationSizeMB,
+ Type,
+ &creationStart,
+ &creationSize);
+
+ // now we've got the start and size of the partition to be created.
+ // If there's left-over at the beginning of the free space (after
+ // alignment), make a new PARTITION structure.
+
+ p1 = NULL;
+ offset = createData->Partition->Offset;
+ length = createData->Partition->Length;
+ leftOver.QuadPart = creationStart.QuadPart - offset.QuadPart;
+
+ if (leftOver.QuadPart > 0) {
+
+ p1 = AllocatePartitionStructure(Region->Disk,
+ createData->Partition->Offset,
+ leftOver,
+ SYSID_UNUSED,
+ FALSE,
+ FALSE,
+ FALSE);
+ if (p1 == NULL) {
+ RETURN_OUT_OF_MEMORY;
+ }
+ }
+
+ // make a new partition structure for space being left free as
+ // a result of this creation.
+
+ p2 = NULL;
+ leftOver.QuadPart = (offset.QuadPart + length.QuadPart) -
+ (creationStart.QuadPart + creationSize.QuadPart);
+
+ if (leftOver.QuadPart) {
+ LARGE_INTEGER temp;
+
+ temp.QuadPart = creationStart.QuadPart + creationSize.QuadPart;
+ p2 = AllocatePartitionStructure(Region->Disk,
+ temp,
+ leftOver,
+ SYSID_UNUSED,
+ FALSE,
+ FALSE,
+ FALSE);
+ if (p2 == NULL) {
+ RETURN_OUT_OF_MEMORY;
+ }
+ }
+
+ // adjust the free partition's fields.
+
+ createData->Partition->Offset = creationStart;
+ createData->Partition->Length = creationSize;
+ createData->Partition->SysID = SysId;
+ createData->Partition->Update = TRUE;
+ createData->Partition->Recognized = TRUE;
+
+ // if we just created an extended partition, show the whole thing
+ // as one free logical region.
+
+ if (Type == REGION_EXTENDED) {
+
+ p3 = AllocatePartitionStructure(Region->Disk,
+ creationStart,
+ creationSize,
+ SYSID_UNUSED,
+ FALSE,
+ FALSE,
+ FALSE);
+ if (p3 == NULL) {
+ RETURN_OUT_OF_MEMORY;
+ }
+ AddPartitionToLinkedList(&LogicalVolumes[Region->Disk], p3);
+ }
+
+ partitionList = (Type == REGION_LOGICAL)
+ ? &LogicalVolumes[Region->Disk]
+ : &PrimaryPartitions[Region->Disk];
+
+ if (p1) {
+ AddPartitionToLinkedList(partitionList, p1);
+ }
+ if (p2) {
+ AddPartitionToLinkedList(partitionList, p2);
+ }
+
+ MergeFreePartitions(*partitionList);
+ ChangesRequested[Region->Disk] = TRUE;
+ return(OK_STATUS);
+}
+
+
+STATUS_CODE
+CreatePartition(
+ IN PREGION_DESCRIPTOR Region,
+ IN ULONG CreationSizeMB,
+ IN REGION_TYPE Type
+ )
+/*++
+
+Routine Description:
+
+ Create a partition.
+
+Arguments:
+
+ Region - A region descriptor pointer.
+ CreationSizeMB - the size for the new region.
+ Type - the type of region being created.
+
+Return Value:
+
+ OK_STATUS or error code
+
+--*/
+
+{
+ LARGE_INTEGER zero;
+
+ zero.QuadPart = 0;
+ return CreatePartitionEx(Region,
+ zero,
+ CreationSizeMB,
+ Type,
+ (UCHAR)((Type == REGION_EXTENDED) ? SYSID_EXTENDED
+ : SYSID_BIGFAT));
+}
+
+
+STATUS_CODE
+DeletePartition(
+ IN PREGION_DESCRIPTOR Region
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deletes a partition, returning its space to the
+ free space on the disk. If deleting the extended partition,
+ all logical volumes within it are also deleted.
+
+Arguments:
+
+ Region - a region descriptor returned by GetDiskRegions(). Must
+ be a used region.
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+ PREGION_DATA RegionData = Region->Reserved;
+ PPARTITION *PartitionList;
+
+ if(IsExtended(Region->SysID)) {
+
+ // Deleting extended partition. Also delete all logical volumes.
+
+ FreeLinkedPartitionList(&LogicalVolumes[Region->Disk]);
+ }
+
+ RegionData->Partition->SysID = SYSID_UNUSED;
+ RegionData->Partition->Update = TRUE;
+ RegionData->Partition->Active = FALSE;
+ RegionData->Partition->OriginalPartitionNumber = 0;
+
+ PartitionList = (Region->RegionType == REGION_LOGICAL)
+ ? &LogicalVolumes[Region->Disk]
+ : &PrimaryPartitions[Region->Disk];
+
+ MergeFreePartitions(*PartitionList);
+ ChangesRequested[Region->Disk] = TRUE;
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+GetDiskRegions(
+ IN ULONG Disk,
+ IN BOOLEAN WantUsedRegions,
+ IN BOOLEAN WantFreeRegions,
+ IN BOOLEAN WantPrimaryRegions,
+ IN BOOLEAN WantLogicalRegions,
+ OUT PREGION_DESCRIPTOR *Region,
+ OUT ULONG *RegionCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns an array of region descriptors to the caller.
+ A region desscriptor describes a space on the disk, either used
+ or free. The caller can control which type of regions are returned.
+
+ The caller must free the returned array via FreeRegionArray().
+
+Arguments:
+
+ Disk - index of disk whose regions are to be returned
+
+ WantUsedRegions - whether to return used disk regions
+
+ WantFreeRegions - whether to return free disk regions
+
+ WantPrimaryRegions - whether to return regions not in the
+ extended partition
+
+ WantLogicalRegions - whether to return regions within the
+ extended partition
+
+ Region - where to put a pointer to the array of regions
+
+ RegionCount - where to put the number of items in the returned
+ Region array
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+ *Region = AllocateMemory(0);
+ *RegionCount = 0;
+
+ if (WantPrimaryRegions) {
+ return GetRegions(Disk,
+ PrimaryPartitions[Disk],
+ WantUsedRegions,
+ WantFreeRegions,
+ WantLogicalRegions,
+ Region,
+ RegionCount,
+ REGION_PRIMARY);
+ } else if (WantLogicalRegions) {
+ return GetRegions(Disk,
+ LogicalVolumes[Disk],
+ WantUsedRegions,
+ WantFreeRegions,
+ FALSE,
+ Region,
+ RegionCount,
+ REGION_LOGICAL);
+ }
+ return OK_STATUS;
+}
+
+
+// workers for GetDiskRegions
+
+STATUS_CODE
+GetRegions(
+ IN ULONG Disk,
+ IN PPARTITION p,
+ IN BOOLEAN WantUsedRegions,
+ IN BOOLEAN WantFreeRegions,
+ IN BOOLEAN WantLogicalRegions,
+ OUT PREGION_DESCRIPTOR *Region,
+ OUT ULONG *RegionCount,
+ IN REGION_TYPE RegionType
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ STATUS_CODE status;
+ LARGE_INTEGER alignedOffset,
+ alignedSize,
+ temp;
+ ULONG sizeMB;
+
+ while (p) {
+
+ if (p->SysID == SYSID_UNUSED) {
+
+ if (WantFreeRegions) {
+
+ alignedOffset = AlignTowardsDiskEnd(p->Disk,p->Offset);
+ temp.QuadPart = p->Offset.QuadPart + p->Length.QuadPart;
+ temp = AlignTowardsDiskStart(p->Disk, temp);
+ alignedSize.QuadPart = temp.QuadPart - alignedOffset.QuadPart;
+ sizeMB = SIZEMB(alignedSize);
+
+ // Show the space free if it is greater than 1 meg, AND
+ // it is not a space starting at the beginning of the disk
+ // and of length <= 1 cylinder.
+ // This prevents the user from seeing the first cylinder
+ // of the disk as free (could otherwise happen with an
+ // extended partition starting on cylinder 1 and cylinders
+ // of 1 megabyte or larger).
+
+ if ((alignedSize.QuadPart > 0) && sizeMB &&
+ ((p->Offset.QuadPart) ||
+ (p->Length.QuadPart > (DiskGeometryArray[p->Disk].BytesPerCylinder)))) {
+ if (!AddRegionEntry(Region,
+ RegionCount,
+ sizeMB,
+ RegionType,
+ p,
+ alignedOffset,
+ alignedSize)) {
+ RETURN_OUT_OF_MEMORY;
+ }
+ }
+ }
+ } else {
+
+ if (WantUsedRegions) {
+
+ alignedOffset = p->Offset;
+ alignedSize = p->Length;
+ sizeMB = SIZEMB(alignedSize);
+
+ if (!AddRegionEntry(Region,
+ RegionCount,
+ sizeMB,
+ RegionType,
+ p,
+ alignedOffset,
+ alignedSize)) {
+ RETURN_OUT_OF_MEMORY;
+ }
+ }
+
+ if (IsExtended(p->SysID) && WantLogicalRegions) {
+ status = GetRegions(Disk,
+ LogicalVolumes[Disk],
+ WantUsedRegions,
+ WantFreeRegions,
+ FALSE,
+ Region,
+ RegionCount,
+ REGION_LOGICAL);
+ if (status != OK_STATUS) {
+ return status;
+ }
+ }
+ }
+ p = p->Next;
+ }
+ return OK_STATUS;
+}
+
+
+BOOLEAN
+AddRegionEntry(
+ OUT PREGION_DESCRIPTOR *Regions,
+ OUT ULONG *RegionCount,
+ IN ULONG SizeMB,
+ IN REGION_TYPE RegionType,
+ IN PPARTITION Partition,
+ IN LARGE_INTEGER AlignedRegionOffset,
+ IN LARGE_INTEGER AlignedRegionSize
+ )
+
+/*++
+
+Routine Description:
+
+ Allocate space for the region descriptor and copy the provided data.
+
+Arguments:
+
+ Regions - return the pointer to the new region
+ RegionCount - number of regions on the disk so far
+ SizeMB - size of the region
+ RegionType - type of the region
+ Partition - partition structure with other related information
+ AlignedRegionOffset - region starting location
+ AlignedRegionSize - region size.
+
+Return Value:
+
+ TRUE - The region was added successfully
+ FALSE - it wasn't
+
+--*/
+
+{
+ PREGION_DESCRIPTOR regionDescriptor;
+ PREGION_DATA regionData;
+
+ regionDescriptor = ReallocateMemory(*Regions,(((*RegionCount) + 1) * sizeof(REGION_DESCRIPTOR)) + 20);
+ if (regionDescriptor == NULL) {
+ return FALSE;
+ } else {
+ *Regions = regionDescriptor;
+ (*RegionCount)++;
+ }
+
+ regionDescriptor = &(*Regions)[(*RegionCount)-1];
+
+ if (!(regionDescriptor->Reserved = AllocateMemory(sizeof(REGION_DATA)))) {
+ return FALSE;
+ }
+
+ regionDescriptor->Disk = Partition->Disk;
+ regionDescriptor->SysID = Partition->SysID;
+ regionDescriptor->SizeMB = SizeMB;
+ regionDescriptor->Active = Partition->Active;
+ regionDescriptor->Recognized = Partition->Recognized;
+ regionDescriptor->PartitionNumber = Partition->PartitionNumber;
+ regionDescriptor->OriginalPartitionNumber = Partition->OriginalPartitionNumber;
+ regionDescriptor->RegionType = RegionType;
+ regionDescriptor->PersistentData = Partition->PersistentData;
+
+ regionData = regionDescriptor->Reserved;
+
+ regionData->Partition = Partition;
+ regionData->AlignedRegionOffset = AlignedRegionOffset;
+ regionData->AlignedRegionSize = AlignedRegionSize;
+
+ return TRUE;
+}
+
+
+VOID
+FreeRegionArray(
+ IN PREGION_DESCRIPTOR Region,
+ IN ULONG RegionCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees a region array returned by GetDiskRegions().
+
+Arguments:
+
+ Region - pointer to the array of regions to be freed
+
+ RegionCount - number of items in the Region array
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG i;
+
+ for (i = 0; i < RegionCount; i++) {
+
+ if (Region[i].Reserved) {
+ FreeMemory(Region[i].Reserved);
+ }
+ }
+ FreeMemory(Region);
+}
+
+
+VOID
+AddPartitionToLinkedList(
+ IN OUT PARTITION **Head,
+ IN PARTITION *p
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds a PARTITION structure to a doubly-linked
+ list, sorted by the Offset field in ascending order.
+
+Arguments:
+
+ Head - pointer to pointer to first element in list
+ p - pointer to item to be added to list
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PARTITION *cur,
+ *prev;
+
+ if ((cur = *Head) == NULL) {
+ *Head = p;
+ return;
+ }
+
+ if (p->Offset.QuadPart < cur->Offset.QuadPart) {
+ p->Next = cur;
+ cur->Prev = p;
+ *Head = p;
+ return;
+ }
+
+ prev = *Head;
+ cur = cur->Next;
+
+ while (cur) {
+ if (p->Offset.QuadPart < cur->Offset.QuadPart) {
+
+ p->Next = cur;
+ p->Prev = prev;
+ prev->Next = p;
+ cur->Prev = p;
+ return;
+ }
+ prev = cur;
+ cur = cur->Next;
+ }
+
+ prev->Next = p;
+ p->Prev = prev;
+ return;
+}
+
+
+BOOLEAN
+IsInLinkedList(
+ IN PPARTITION p,
+ IN PPARTITION List
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether a PARTITION element is in
+ a given linked list of PARTITION elements.
+
+Arguments:
+
+ p - pointer to element to be checked for
+ List - first element in list to be scanned
+
+Return Value:
+
+ true if p found in List, false otherwise
+
+--*/
+
+{
+ while (List) {
+ if (p == List) {
+ return TRUE;
+ }
+ List = List->Next;
+ }
+ return FALSE;
+}
+
+
+BOOLEAN
+IsInLogicalList(
+ IN ULONG Disk,
+ IN PPARTITION p
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether a PARTITION element is in
+ the logical volume list for a given disk.
+
+Arguments:
+
+ Disk - index of disk to be checked
+ p - pointer to element to be checked for
+
+Return Value:
+
+ true if p found in Disk's logical volume list, false otherwise
+
+--*/
+
+{
+ return IsInLinkedList(p, LogicalVolumes[Disk]);
+}
+
+
+BOOLEAN
+IsInPartitionList(
+ IN ULONG Disk,
+ IN PPARTITION p
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether a PARTITION element is in
+ the primary partition list for a given disk.
+
+Arguments:
+
+ Disk - index of disk to be checked
+ p - pointer to element to be checked for
+
+Return Value:
+
+ true if p found in Disk's primary partition list, false otherwise
+
+--*/
+
+{
+ return IsInLinkedList(p, PrimaryPartitions[Disk]);
+}
+
+
+VOID
+MergeFreePartitions(
+ IN PPARTITION p
+ )
+
+/*++
+
+Routine Description:
+
+ This routine merges adjacent free space elements in the
+ given linked list of PARTITION elements. It is designed
+ to be called after adding or deleting a partition.
+
+Arguments:
+
+ p - pointer to first item in list whose free elements are to
+ be merged.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PPARTITION next;
+
+ while (p && p->Next) {
+
+ if ((p->SysID == SYSID_UNUSED) && (p->Next->SysID == SYSID_UNUSED)) {
+
+ next = p->Next;
+ p->Length.QuadPart = (next->Offset.QuadPart + next->Length.QuadPart) - p->Offset.QuadPart;
+
+ if (p->Next = next->Next) {
+ next->Next->Prev = p;
+ }
+
+ FreeMemory(next);
+
+ } else {
+ p = p->Next;
+ }
+ }
+}
+
+
+PPARTITION
+FindPartitionElement(
+ IN ULONG Disk,
+ IN ULONG Partition
+ )
+
+/*++
+
+Routine Description:
+
+ This routine locates a PARTITION element for a disk/partition
+ number pair. The partition number is the number that the
+ system assigns to the partition.
+
+Arguments:
+
+ Disk - index of relevent disk
+
+ Partition - partition number of partition to find
+
+Return Value:
+
+ pointer to PARTITION element, or NULL if not found.
+
+--*/
+
+{
+ PPARTITION p;
+
+ p = PrimaryPartitions[Disk];
+ while (p) {
+ if ((p->SysID != SYSID_UNUSED) && !IsExtended(p->SysID) && (p->PartitionNumber == Partition)) {
+ return p;
+ }
+ p = p->Next;
+ }
+ p = LogicalVolumes[Disk];
+ while (p) {
+ if ((p->SysID != SYSID_UNUSED) && (p->PartitionNumber == Partition)) {
+ return p;
+ }
+ p = p->Next;
+ }
+ return NULL;
+}
+
+
+VOID
+SetSysID(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ IN UCHAR SysID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the system id of the given partition
+ on the given disk.
+
+Arguments:
+
+ Disk - index of relevent disk
+
+ Partition - partition number of relevent partition
+
+ SysID - new system ID for Partition on Disk
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PPARTITION p = FindPartitionElement(Disk,Partition);
+
+ if (p) {
+ p->SysID = SysID;
+ if (!p->Update) {
+ p->Update = CHANGED_DONT_ZAP;
+ }
+ ChangesRequested[p->Disk] = TRUE;
+ }
+}
+
+
+VOID
+SetSysID2(
+ IN PREGION_DESCRIPTOR Region,
+ IN UCHAR SysID
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ PPARTITION p = ((PREGION_DATA)(Region->Reserved))->Partition;
+
+ p->SysID = SysID;
+ if (!p->Update) {
+ p->Update = CHANGED_DONT_ZAP;
+ }
+ ChangesRequested[p->Disk] = TRUE;
+}
+
+
+VOID
+FreeLinkedPartitionList(
+ IN OUT PPARTITION *q
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees a linked list of PARTITION elements. The head
+ pointer is set to NULL.
+
+Arguments:
+
+ p - pointer to pointer to first element of list to free.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PARTITION *n;
+ PARTITION *p = *q;
+
+ while(p) {
+ n = p->Next;
+ FreeMemory(p);
+ p = n;
+ }
+ *q = NULL;
+}
+
+
+VOID
+FreePartitionInfoLinkedLists(
+ IN PPARTITION *ListHeadArray
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees the linked lists of PARTITION elements
+ for each disk.
+
+Arguments:
+
+ ListHeadArray - pointer to array of pointers to first elements of
+ PARTITION element lists.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG i;
+
+ for (i = 0; i < CountOfDisks; i++) {
+
+ FreeLinkedPartitionList(&ListHeadArray[i]);
+ }
+}
+
+
+PPARTITION
+AllocatePartitionStructure(
+ IN ULONG Disk,
+ IN LARGE_INTEGER Offset,
+ IN LARGE_INTEGER Length,
+ IN UCHAR SysID,
+ IN BOOLEAN Update,
+ IN BOOLEAN Active,
+ IN BOOLEAN Recognized
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates space for, and initializes a PARTITION
+ structure.
+
+Arguments:
+
+ Disk - index of disk, one of whose regions the new PARTITION
+ strucure describes.
+ Offset - byte offset of region on the disk
+ Length - length in bytes of the region
+ SysID - system id of region, of SYSID_UNUSED of this PARTITION
+ is actually a free space.
+ Update - whether this PARTITION is dirty, ie, has changed and needs
+ to be written to disk.
+ Active - flag for the BootIndicator field in a partition table entry,
+ indicates to the x86 master boot program which partition
+ is active.
+ Recognized - whether the partition is a type recognized by NT
+
+Return Value:
+
+ NULL if allocation failed, or new initialized PARTITION strucure.
+
+--*/
+
+{
+ PPARTITION p = AllocateMemory(sizeof(PARTITION));
+
+ if (p) {
+ p->Next = NULL;
+ p->Prev = NULL;
+ p->Offset = Offset;
+ p->Length = Length;
+ p->Disk = Disk;
+ p->Update = Update;
+ p->Active = Active;
+ p->Recognized = Recognized;
+ p->SysID = SysID;
+ p->OriginalPartitionNumber = 0;
+ p->PartitionNumber = 0;
+ p->PersistentData = 0;
+ p->CommitMirrorBreakNeeded = FALSE;
+ }
+ return(p);
+}
+
+
+STATUS_CODE
+InitializeFreeSpace(
+ IN ULONG Disk,
+ IN PPARTITION *PartitionList, // list the free space goes in
+ IN LARGE_INTEGER StartOffset,
+ IN LARGE_INTEGER Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines all the free spaces within a given area
+ on a disk, allocates PARTITION structures to describe them,
+ and adds these structures to the relevent partition list
+ (primary partitions or logical volumes).
+
+ No rounding or alignment is performed here. Spaces of even one
+ byte will be counted and inserted in the partition list.
+
+Arguments:
+
+ Disk - index of disk whose free spaces are being sought.
+
+ PartitionList - pointer to first element on PARTITION list that
+ the free spaces will go in.
+
+ StartOffset - start offset of area on disk to consider (ie, 0 for
+ primary spaces or the first byte of the extended
+ partition for logical spaces).
+
+ Length - length of area on disk to consider (ie, size of disk
+ for primary spaces or size of extended partition for
+ logical spaces).
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+ PPARTITION p = *PartitionList,
+ q;
+ LARGE_INTEGER start,
+ size;
+
+ start = StartOffset;
+ while (p) {
+
+ size.QuadPart = p->Offset.QuadPart - start.QuadPart;
+ if (size.QuadPart > 0) {
+ if (!(q = AllocatePartitionStructure(Disk,
+ start,
+ size,
+ SYSID_UNUSED,
+ FALSE,
+ FALSE,
+ FALSE))) {
+ RETURN_OUT_OF_MEMORY;
+ }
+
+ AddPartitionToLinkedList(PartitionList, q);
+ }
+
+ start.QuadPart = p->Offset.QuadPart + p->Length.QuadPart;
+ p = p->Next;
+ }
+
+ size.QuadPart = (StartOffset.QuadPart + Length.QuadPart) - start.QuadPart;
+ if (size.QuadPart > 0) {
+
+ if (!(q = AllocatePartitionStructure(Disk,
+ start,
+ size,
+ SYSID_UNUSED,
+ FALSE,
+ FALSE,
+ FALSE))) {
+ RETURN_OUT_OF_MEMORY;
+ }
+
+ AddPartitionToLinkedList(PartitionList, q);
+ }
+
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+InitializeLogicalVolumeList(
+ IN ULONG Disk,
+ IN PDRIVE_LAYOUT_INFORMATION DriveLayout
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates the logical volume linked list of
+ PARTITION structures for the given disk.
+
+Arguments:
+
+ Disk - index of disk
+
+ DriveLayout - pointer to structure describing the raw partition
+ layout of the disk.
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+ PPARTITION p,
+ q;
+ ULONG i,
+ j;
+ PPARTITION_INFORMATION d;
+ LARGE_INTEGER HiddenBytes;
+ ULONG BytesPerSector = DiskGeometryArray[Disk].BytesPerSector;
+
+ FreeLinkedPartitionList(&LogicalVolumes[Disk]);
+
+ p = PrimaryPartitions[Disk];
+ while (p) {
+ if (IsExtended(p->SysID)) {
+ break;
+ }
+ p = p->Next;
+ }
+
+ if (p) {
+ for (i=ENTRIES_PER_BOOTSECTOR; i<DriveLayout->PartitionCount; i+=ENTRIES_PER_BOOTSECTOR) {
+
+ for (j=i; j<i+ENTRIES_PER_BOOTSECTOR; j++) {
+
+ d = &DriveLayout->PartitionEntry[j];
+
+ if ((d->PartitionType != SYSID_UNUSED) && (d->PartitionType != SYSID_EXTENDED)) {
+ LARGE_INTEGER t1,
+ t2;
+
+ HiddenBytes.QuadPart = (LONGLONG)d->HiddenSectors * (LONGLONG)BytesPerSector;
+
+ t1.QuadPart = d->StartingOffset.QuadPart - HiddenBytes.QuadPart;
+ t2.QuadPart = d->PartitionLength.QuadPart + HiddenBytes.QuadPart;
+ if (!(q = AllocatePartitionStructure(Disk,
+ t1,
+ t2,
+ d->PartitionType,
+ FALSE,
+ d->BootIndicator,
+ d->RecognizedPartition))) {
+ RETURN_OUT_OF_MEMORY;
+ }
+
+ q->PartitionNumber =
+ q->OriginalPartitionNumber = d->PartitionNumber;
+ AddPartitionToLinkedList(&LogicalVolumes[Disk],q);
+
+ break;
+ }
+ }
+ }
+ return InitializeFreeSpace(Disk,
+ &LogicalVolumes[Disk],
+ p->Offset,
+ p->Length);
+ }
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+InitializePrimaryPartitionList(
+ IN ULONG Disk,
+ IN PDRIVE_LAYOUT_INFORMATION DriveLayout
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates the primary partition linked list of
+ PARTITION structures for the given disk.
+
+Arguments:
+
+ Disk - index of disk
+
+ DriveLayout - pointer to structure describing the raw partition
+ layout of the disk.
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+ LARGE_INTEGER zero;
+ ULONG i;
+ PPARTITION p;
+ PPARTITION_INFORMATION d;
+
+ zero.QuadPart = 0;
+ FreeLinkedPartitionList(&PrimaryPartitions[Disk]);
+
+ if (DriveLayout->PartitionCount >= ENTRIES_PER_BOOTSECTOR) {
+
+ for (i=0; i<ENTRIES_PER_BOOTSECTOR; i++) {
+
+ d = &DriveLayout->PartitionEntry[i];
+
+ if (d->PartitionType != SYSID_UNUSED) {
+
+ if (!(p = AllocatePartitionStructure(Disk,
+ d->StartingOffset,
+ d->PartitionLength,
+ d->PartitionType,
+ FALSE,
+ d->BootIndicator,
+ d->RecognizedPartition))) {
+ RETURN_OUT_OF_MEMORY;
+ }
+
+ p->PartitionNumber =
+ p->OriginalPartitionNumber = IsExtended(p->SysID)
+ ? 0
+ : d->PartitionNumber;
+
+ AddPartitionToLinkedList(&PrimaryPartitions[Disk],p);
+ }
+ }
+ }
+ return InitializeFreeSpace(Disk,
+ &PrimaryPartitions[Disk],
+ zero,
+ DiskLengthBytes(Disk));
+}
+
+
+VOID
+ReconcilePartitionNumbers(
+ ULONG Disk,
+ PDRIVE_LAYOUT_INFORMATION DriveLayout
+ )
+
+/*++
+
+Routine Description:
+
+ With dynamic partitioning, the partitions on the disk will no longer
+ follow sequencial numbering schemes. It will be possible for a disk
+ to have a partition #1 that is the last partition on the disk and a
+ partition #3 that is the first. This routine runs through the NT
+ namespace for harddisks to resolve this inconsistency.
+
+ This routine has the problem that it will not locate partitions that
+ are part of an FT set because the partition information for these
+ partitions will be modified to reflect the size of the set, not the
+ size of the partition.
+
+Arguments:
+
+ Disk - the disk number
+ DriveLayout - the partitioning information
+
+Return Value:
+
+ None
+
+--*/
+
+{
+#define BUFFERSIZE 1024
+ NTSTATUS status;
+ IO_STATUS_BLOCK statusBlock;
+ HANDLE directoryHandle,
+ partitionHandle;
+ CLONG continueProcessing;
+ ULONG context = 0,
+ returnedLength,
+ index;
+ POBJECT_DIRECTORY_INFORMATION dirInfo;
+ PARTITION_INFORMATION partitionInfo;
+ PPARTITION_INFORMATION partitionInfoPtr;
+ OBJECT_ATTRIBUTES attributes;
+ UNICODE_STRING unicodeString;
+ ANSI_STRING ansiName;
+ PUCHAR deviceName;
+ PUCHAR buffer;
+
+ deviceName = Malloc(100);
+ if (!deviceName) {
+ return;
+ }
+
+ buffer = Malloc(BUFFERSIZE);
+ if (!buffer) {
+ Free(deviceName);
+ return;
+ }
+
+ sprintf(deviceName, "\\Device\\Harddisk%d", Disk);
+ RtlInitAnsiString(&ansiName, deviceName);
+ status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiName, TRUE);
+
+ if (!NT_SUCCESS(status)) {
+ Free(deviceName);
+ Free(buffer);
+ return;
+ }
+ InitializeObjectAttributes(&attributes,
+ &unicodeString,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ status = NtOpenDirectoryObject(&directoryHandle,
+ DIRECTORY_QUERY,
+ &attributes);
+ if (!NT_SUCCESS(status)) {
+
+ Free(deviceName);
+ Free(buffer);
+ return;
+ }
+
+ // Query the entire directory in one sweep
+
+ continueProcessing = 1;
+ while (continueProcessing) {
+ RtlZeroMemory(buffer, BUFFERSIZE);
+ status = NtQueryDirectoryObject(directoryHandle,
+ buffer,
+ BUFFERSIZE,
+ FALSE,
+ FALSE,
+ &context,
+ &returnedLength);
+
+ // Check the status of the operation.
+
+ if (!NT_SUCCESS(status)) {
+ if (status != STATUS_NO_MORE_FILES) {
+ break;
+ }
+ continueProcessing = 0;
+ }
+
+ // For every record in the buffer check for partition name
+
+
+ for (dirInfo = (POBJECT_DIRECTORY_INFORMATION) buffer;
+ TRUE;
+ dirInfo = (POBJECT_DIRECTORY_INFORMATION) (((PUCHAR) dirInfo) +
+ sizeof(OBJECT_DIRECTORY_INFORMATION))) {
+
+ // Check if there is another record. If there isn't, then get out
+ // of the loop now
+
+ if (dirInfo->Name.Length == 0) {
+ break;
+ }
+
+ // compare the name to see if it is a Partition
+
+ if (!_wcsnicmp(dirInfo->Name.Buffer, L"Partition", 9)) {
+ UCHAR digits[3];
+ ULONG partitionNumber;
+
+ // Located a partition. This restricts the # of partitions
+ // to 99.
+
+ digits[0] = (UCHAR) dirInfo->Name.Buffer[9];
+ digits[1] = (UCHAR) dirInfo->Name.Buffer[10];
+ digits[2] = 0;
+ partitionNumber = atoi(digits);
+
+ if (partitionNumber <= 0) {
+
+ // less than zero is really an error...
+ // partition zero is always the same.
+
+ continue;
+ }
+
+ // Have a numbered partition -- match it to the drive layout
+
+ status = LowOpenPartition(deviceName, partitionNumber, &partitionHandle);
+ if (!NT_SUCCESS(status)) {
+
+ // If it cannot be opened perhaps it isn't really a partition
+
+ continue;
+ }
+
+ status = NtDeviceIoControlFile(partitionHandle,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ IOCTL_DISK_GET_PARTITION_INFO,
+ NULL,
+ 0,
+ &partitionInfo,
+ sizeof(PARTITION_INFORMATION));
+
+ if (!NT_SUCCESS(status)) {
+ LowCloseDisk(partitionHandle);
+ continue;
+ }
+
+ // match partition information with drive layout.
+
+ for (index = 0; index < DriveLayout->PartitionCount; index++) {
+
+ partitionInfoPtr = &DriveLayout->PartitionEntry[index];
+ if ((partitionInfoPtr->StartingOffset.QuadPart == partitionInfo.StartingOffset.QuadPart) &&
+ (partitionInfoPtr->PartitionLength.QuadPart == partitionInfo.PartitionLength.QuadPart)) {
+
+ // This is a match.
+
+ partitionInfoPtr->PartitionNumber = partitionNumber;
+ break;
+ }
+ }
+ LowCloseDisk(partitionHandle);
+ }
+
+ }
+ }
+
+ // Now close the directory object
+
+ Free(deviceName);
+ Free(buffer);
+ (VOID) NtClose(directoryHandle);
+ return;
+}
+
+
+VOID
+CheckForOldDrivers(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines if an old release 3.1 drive is in the
+ system. If so, it calculates the partition number for each region
+ on a disk. For a used region, the partition number is the number
+ that the system will assign to the partition. All partitions
+ (except the extended partition) are numbered first starting at 1,
+ and then all logical volumes in the extended partition.
+ For a free region, the partition number is the number that the
+ system WOULD assign to the partition if the space were to be
+ converted to a partition and all other regions on the disk were
+ left as is.
+
+ The partition numbers are stored in the PARTITION elements.
+
+Arguments:
+
+ Disk - index of disk whose partitions are to be renumbered.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PPARTITION p = PrimaryPartitions[Disk];
+ ULONG n = 1;
+
+ while (p) {
+ if (p->SysID != SYSID_UNUSED) {
+ if ((!IsExtended(p->SysID)) && (IsRecognizedPartition(p->SysID))) {
+
+ // If there is already a partition number, nothing need be
+ // done here.
+
+ if (p->PartitionNumber) {
+ return;
+ } else {
+ RestartRequired = TRUE;
+ }
+ p->PartitionNumber = n;
+ if (p->SysID != SYSID_UNUSED) {
+ n++;
+ }
+ }
+ }
+ p = p->Next;
+ }
+ p = LogicalVolumes[Disk];
+ while (p) {
+ if (p->SysID != SYSID_UNUSED) {
+ if (p->PartitionNumber) {
+ return;
+ } else {
+ RestartRequired = TRUE;
+ }
+ p->PartitionNumber = n;
+ n++;
+ }
+ p = p->Next;
+ }
+}
+
+
+STATUS_CODE
+InitializePartitionLists(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the PARTITION_INFO array returned for each disk
+ by the OS. A linked list of PARTITION structures is layered on top
+ of each array; the net result is a sorted list that covers an entire
+ disk, because free spaces are also factored in as 'dummy' partitions.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+ STATUS_CODE status;
+ ULONG disk;
+ PDRIVE_LAYOUT_INFORMATION driveLayout;
+
+ for (disk = 0; disk < CountOfDisks; disk++) {
+
+ if (OffLine[disk]) {
+ continue;
+ }
+
+ if ((status = LowGetDiskLayout(DiskNames[disk], &driveLayout)) != OK_STATUS) {
+ return status;
+ }
+
+ // ReconcilePartitionNumbers(disk, driveLayout);
+
+ if ((status = InitializePrimaryPartitionList(disk, driveLayout)) == OK_STATUS) {
+ status = InitializeLogicalVolumeList(disk, driveLayout);
+ }
+ if (status != OK_STATUS) {
+ FreeMemory(driveLayout);
+ return status;
+ }
+
+ Signatures[disk] = driveLayout->Signature;
+ FreeMemory(driveLayout);
+ CheckForOldDrivers(disk);
+ }
+ return OK_STATUS;
+}
+
+
+LARGE_INTEGER
+DiskLengthBytes(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines the disk length in bytes. This value
+ is calculated from the disk geometry information.
+
+Arguments:
+
+ Disk - index of disk whose size is desired
+
+Return Value:
+
+ Size of Disk.
+
+--*/
+
+{
+ LARGE_INTEGER result;
+
+ result.QuadPart = DiskGeometryArray[Disk].Cylinders.QuadPart *
+ DiskGeometryArray[Disk].BytesPerCylinder;
+ return result;
+}
+
+
+ULONG
+SIZEMB(
+ IN LARGE_INTEGER ByteCount
+ )
+
+/*++
+
+Routine Description:
+
+ Calculate the size in megabytes of a given byte count. The value is
+ properly rounded (ie, not merely truncated).
+
+ This function replaces a macro of the same name that was truncating
+ instead of rounding.
+
+Arguments:
+
+ ByteCount - supplies number of bytes
+
+Return Value:
+
+ Size in MB equivalent to ByteCount.
+
+--*/
+
+{
+ ULONG Remainder;
+ ULONG SizeMB;
+
+ SizeMB = RtlExtendedLargeIntegerDivide(ByteCount,
+ ONE_MEG,
+ &Remainder).LowPart;
+
+ if (Remainder >= ONE_MEG/2) {
+ SizeMB++;
+ }
+
+ return SizeMB;
+}
+
+
+ULONG
+DiskSizeMB(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines the disk length in megabytes. The returned
+ value is rounded down after division by 1024*1024.
+
+Arguments:
+
+ Disk - index of disk whose size is desired
+
+Return Value:
+
+ Size of Disk.
+
+--*/
+
+{
+ return SIZEMB(DiskLengthBytes(Disk));
+}
+
+
+LARGE_INTEGER
+AlignTowardsDiskStart(
+ IN ULONG Disk,
+ IN LARGE_INTEGER Offset
+ )
+
+/*++
+
+Routine Description:
+
+ This routine snaps a byte offset to a cylinder boundary, towards
+ the start of the disk.
+
+Arguments:
+
+ Disk - index of disk whose offset is to be snapped
+ Offset - byte offset to be aligned (snapped to cylinder boundary)
+
+Return Value:
+
+ Aligned offset.
+
+--*/
+
+{
+ LARGE_INTEGER mod;
+ LARGE_INTEGER result;
+
+ mod.QuadPart = Offset.QuadPart % DiskGeometryArray[Disk].BytesPerCylinder;
+ result.QuadPart = Offset.QuadPart - mod.QuadPart;
+ return result;
+}
+
+
+LARGE_INTEGER
+AlignTowardsDiskEnd(
+ IN ULONG Disk,
+ IN LARGE_INTEGER Offset
+ )
+
+/*++
+
+Routine Description:
+
+ This routine snaps a byte offset to a cylinder boundary, towards
+ the end of the disk.
+
+Arguments:
+
+ Disk - index of disk whose offset is to be snapped
+ Offset - byte offset to be aligned (snapped to cylinder boundary)
+
+Return Value:
+
+ Aligned offset.
+
+--*/
+
+{
+ LARGE_INTEGER mod,
+ temp;
+
+ mod.QuadPart = Offset.QuadPart % DiskGeometryArray[Disk].BytesPerCylinder;
+ if (mod.QuadPart) {
+
+ temp.QuadPart = Offset.QuadPart + DiskGeometryArray[Disk].BytesPerCylinder;
+ Offset = AlignTowardsDiskStart(Disk, temp);
+ }
+ return Offset;
+}
+
+
+BOOLEAN
+IsExtended(
+ IN UCHAR SysID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether a given system id is for an
+ extended type (ie, link) entry.
+
+Arguments:
+
+ SysID - system id to be tested.
+
+Return Value:
+
+ true/false based on whether SysID is for an extended type.
+
+--*/
+
+{
+ return (BOOLEAN)(SysID == SYSID_EXTENDED);
+}
+
+
+STATUS_CODE
+IsAnyCreationAllowed(
+ IN ULONG Disk,
+ IN BOOLEAN AllowMultiplePrimaries,
+ OUT PBOOLEAN AnyAllowed,
+ OUT PBOOLEAN PrimaryAllowed,
+ OUT PBOOLEAN ExtendedAllowed,
+ OUT PBOOLEAN LogicalAllowed
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether any partition may be created on a
+ given disk, based on three sub-queries -- whether creation is allowed
+ of a primary partition, an extended partition, or a logical volume.
+
+Arguments:
+
+ Disk - index of disk to check
+ AllowMultiplePrimaries - whether to allow multiple primary partitions
+ AnyAllowed - returns whether any creation is allowed
+ PrimaryAllowed - returns whether creation of a primary partition
+ is allowed
+ ExtendedAllowed - returns whether creation of an extended partition
+ is allowed
+ Logical Allowed - returns whether creation of a logical volume is allowed.
+
+Return Value:
+
+ OK_STATUS or error code
+
+--*/
+
+{
+ STATUS_CODE status;
+
+ if ((status = IsCreationOfPrimaryAllowed(Disk,AllowMultiplePrimaries,PrimaryAllowed)) != OK_STATUS) {
+ return status;
+ }
+ if ((status = IsCreationOfExtendedAllowed(Disk,ExtendedAllowed)) != OK_STATUS) {
+ return status;
+ }
+ if ((status = IsCreationOfLogicalAllowed(Disk,LogicalAllowed)) != OK_STATUS) {
+ return status;
+ }
+ *AnyAllowed = (BOOLEAN)(*PrimaryAllowed || *ExtendedAllowed || *LogicalAllowed);
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+IsCreationOfPrimaryAllowed(
+ IN ULONG Disk,
+ IN BOOLEAN AllowMultiplePrimaries,
+ OUT BOOLEAN *Allowed
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether creation of a primary partition is
+ allowed. This is true when there is a free entry in the MBR and
+ there is free primary space on the disk. If multiple primaries
+ are not allowed, then there must also not exist any primary partitions
+ in order for a primary creation to be allowed.
+
+Arguments:
+
+ Disk - index of disk to check
+ AllowMultiplePrimaries - whether existnace of primary partition
+ disallows creation of a primary partition
+ Allowed - returns whether creation of a primary partition
+ is allowed
+
+Return Value:
+
+ OK_STATUS or error code
+
+--*/
+
+{
+ PREGION_DESCRIPTOR Regions;
+ ULONG RegionCount;
+ ULONG UsedCount,
+ RecogCount,
+ i;
+ STATUS_CODE status;
+ BOOLEAN FreeSpace = FALSE;
+
+ status = GetPrimaryDiskRegions(Disk, &Regions, &RegionCount);
+ if (status != OK_STATUS) {
+ return status;
+ }
+
+ for (UsedCount = RecogCount = i = 0; i<RegionCount; i++) {
+ if (Regions[i].SysID == SYSID_UNUSED) {
+ FreeSpace = TRUE;
+ } else {
+ UsedCount++;
+ if (!IsExtended(Regions[i].SysID) && Regions[i].Recognized) {
+ RecogCount++;
+ }
+ }
+ }
+
+ if ((UsedCount < ENTRIES_PER_BOOTSECTOR)
+ && FreeSpace
+ && (!RecogCount || AllowMultiplePrimaries)) {
+ *Allowed = TRUE;
+ } else {
+ *Allowed = FALSE;
+ }
+
+ FreeRegionArray(Regions, RegionCount);
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+IsCreationOfExtendedAllowed(
+ IN ULONG Disk,
+ OUT BOOLEAN *Allowed
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether creation of an extended partition is
+ allowed. This is true when there is a free entry in the MBR,
+ there is free primary space on the disk, and there is no existing
+ extended partition.
+
+Arguments:
+
+ Disk - index of disk to check
+
+ Allowed - returns whether creation of an extended partition
+ is allowed
+
+Return Value:
+
+ OK_STATUS or error code
+
+--*/
+
+{
+ PREGION_DESCRIPTOR Regions;
+ ULONG RegionCount;
+ ULONG UsedCount,
+ FreeCount,
+ i;
+ STATUS_CODE status;
+
+ status = GetPrimaryDiskRegions(Disk,&Regions,&RegionCount);
+ if (status != OK_STATUS) {
+ return status;
+ }
+
+ for (UsedCount = FreeCount = i = 0; i<RegionCount; i++) {
+ if (Regions[i].SysID == SYSID_UNUSED) {
+
+ // BUGBUG should adjust the size here and see if it's non0 first
+ // (ie, take into account that the extended partition can't
+ // start on cyl 0).
+
+ FreeCount++;
+ } else {
+ UsedCount++;
+ if (IsExtended(Regions[i].SysID)) {
+ FreeRegionArray(Regions,RegionCount);
+ *Allowed = FALSE;
+ return OK_STATUS;
+ }
+ }
+ }
+ *Allowed = (BOOLEAN)((UsedCount < ENTRIES_PER_BOOTSECTOR) && FreeCount);
+ FreeRegionArray(Regions,RegionCount);
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+IsCreationOfLogicalAllowed(
+ IN ULONG Disk,
+ OUT BOOLEAN *Allowed
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether creation of a logical volume is
+ allowed. This is true when there is an extended partition and
+ free space within it.
+
+Arguments:
+
+ Disk - index of disk to check
+
+ Allowed - returns whether creation of a logical volume is allowed
+
+Return Value:
+
+ OK_STATUS or error code
+
+--*/
+
+{
+ PREGION_DESCRIPTOR Regions;
+ ULONG RegionCount;
+ ULONG i;
+ STATUS_CODE status;
+ BOOLEAN ExtendedExists;
+
+ *Allowed = FALSE;
+
+ status = DoesExtendedExist(Disk,&ExtendedExists);
+ if (status != OK_STATUS) {
+ return status;
+ }
+ if (!ExtendedExists) {
+ return OK_STATUS;
+ }
+
+ status = GetLogicalDiskRegions(Disk,&Regions,&RegionCount);
+ if (status != OK_STATUS) {
+ return status;
+ }
+
+ for (i = 0; i<RegionCount; i++) {
+ if (Regions[i].SysID == SYSID_UNUSED) {
+ *Allowed = TRUE;
+ break;
+ }
+ }
+ FreeRegionArray(Regions,RegionCount);
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+DoesAnyPartitionExist(
+ IN ULONG Disk,
+ OUT PBOOLEAN AnyExists,
+ OUT PBOOLEAN PrimaryExists,
+ OUT PBOOLEAN ExtendedExists,
+ OUT PBOOLEAN LogicalExists
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether any partition exists on a given disk.
+ This is based on three sub queries: whether there are any primary or
+ extended partitions, or logical volumes on the disk.
+
+Arguments:
+
+ Disk - index of disk to check
+ AnyExists - returns whether any partitions exist on Disk
+ PrimaryExists - returns whether any primary partitions exist on Disk
+ ExtendedExists - returns whether there is an extended partition on Disk
+ LogicalExists - returns whether any logical volumes exist on Disk
+
+Return Value:
+
+ OK_STATUS or error code
+
+--*/
+
+{
+ STATUS_CODE status;
+
+ if ((status = DoesAnyPrimaryExist(Disk,PrimaryExists )) != OK_STATUS) {
+ return status;
+ }
+ if ((status = DoesExtendedExist (Disk,ExtendedExists)) != OK_STATUS) {
+ return status;
+ }
+ if ((status = DoesAnyLogicalExist(Disk,LogicalExists )) != OK_STATUS) {
+ return status;
+ }
+ *AnyExists = (BOOLEAN)(*PrimaryExists || *ExtendedExists || *LogicalExists);
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+DoesAnyPrimaryExist(
+ IN ULONG Disk,
+ OUT BOOLEAN *Exists
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether any non-extended primary partition exists
+ on a given disk.
+
+Arguments:
+
+ Disk - index of disk to check
+ Exists - returns whether any primary partitions exist on Disk
+
+Return Value:
+
+ OK_STATUS or error code
+
+--*/
+
+{
+ PREGION_DESCRIPTOR Regions;
+ ULONG RegionCount,
+ i;
+ STATUS_CODE status;
+
+ status = GetUsedPrimaryDiskRegions(Disk,&Regions,&RegionCount);
+ if (status != OK_STATUS) {
+ return status;
+ }
+
+ *Exists = FALSE;
+
+ for (i=0; i<RegionCount; i++) {
+ if (!IsExtended(Regions[i].SysID)) {
+ *Exists = TRUE;
+ break;
+ }
+ }
+ FreeRegionArray(Regions,RegionCount);
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+DoesExtendedExist(
+ IN ULONG Disk,
+ OUT BOOLEAN *Exists
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether an extended partition exists
+ on a given disk.
+
+Arguments:
+
+ Disk - index of disk to check
+ Exists - returns whether an extended partition exists on Disk
+
+Return Value:
+
+ OK_STATUS or error code
+
+--*/
+
+{
+ PREGION_DESCRIPTOR Regions;
+ ULONG RegionCount,
+ i;
+ STATUS_CODE status;
+
+ status = GetUsedPrimaryDiskRegions(Disk,&Regions,&RegionCount);
+ if (status != OK_STATUS) {
+ return status;
+ }
+
+ *Exists = FALSE;
+
+ for (i=0; i<RegionCount; i++) {
+ if (IsExtended(Regions[i].SysID)) {
+ *Exists = TRUE;
+ break;
+ }
+ }
+ FreeRegionArray(Regions,RegionCount);
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+DoesAnyLogicalExist(
+ IN ULONG Disk,
+ OUT BOOLEAN *Exists
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether any logical volumes exist
+ on a given disk.
+
+Arguments:
+
+ Disk - index of disk to check
+ Exists - returns whether any logical volumes exist on Disk
+
+Return Value:
+
+ OK_STATUS or error code
+
+--*/
+
+{
+ PREGION_DESCRIPTOR Regions;
+ ULONG RegionCount;
+ STATUS_CODE status;
+
+ status = GetUsedLogicalDiskRegions(Disk,&Regions,&RegionCount);
+ if (status != OK_STATUS) {
+ return status;
+ }
+
+ *Exists = (BOOLEAN)(RegionCount != 0);
+ FreeRegionArray(Regions,RegionCount);
+ return OK_STATUS;
+}
+
+
+ULONG
+GetDiskCount(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the number of attached partitionable disk
+ devices. The returned value is one greater than the maximum index
+ allowed for Disk parameters to partitioning engine routines.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Count of disks.
+
+--*/
+
+{
+ return CountOfDisks;
+}
+
+
+PCHAR
+GetDiskName(
+ ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the system name for the disk device whose
+ index is given.
+
+Arguments:
+
+ Disk - index of disk whose name is desired.
+
+Return Value:
+
+ System name for the disk device. The caller must not attempt to
+ free this buffer or modify it.
+
+--*/
+
+{
+ return DiskNames[Disk];
+}
+
+
+// worker routines for WriteDriveLayout
+
+VOID
+UnusedEntryFill(
+ IN PPARTITION_INFORMATION pinfo,
+ IN ULONG EntryCount
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize a partition information structure.
+
+Arguments:
+
+ pinfo - the partition information structure to fill in.
+ EntryCount - the number of entries in the structure to fill.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG i;
+ LARGE_INTEGER zero;
+
+ zero.QuadPart = 0;
+ for (i = 0; i < EntryCount; i++) {
+
+ pinfo[i].StartingOffset = zero;
+ pinfo[i].PartitionLength = zero;
+ pinfo[i].HiddenSectors = 0;
+ pinfo[i].PartitionType = SYSID_UNUSED;
+ pinfo[i].BootIndicator = FALSE;
+ pinfo[i].RewritePartition = TRUE;
+ }
+}
+
+
+LARGE_INTEGER
+MakeBootRec(
+ ULONG Disk,
+ PPARTITION_INFORMATION pInfo,
+ PPARTITION pLogical,
+ PPARTITION pNextLogical
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ Disk - the disk number
+ pinfo - the partition information for the disk.
+ pLogical
+ pNextLogical
+
+Return Value:
+
+ The starting offset.
+
+--*/
+
+{
+ ULONG entry = 0;
+ LARGE_INTEGER bytesPerTrack;
+ LARGE_INTEGER sectorsPerTrack;
+ LARGE_INTEGER startingOffset;
+
+ bytesPerTrack.QuadPart = DiskGeometryArray[Disk].BytesPerTrack;
+ sectorsPerTrack.QuadPart = DiskGeometryArray[Disk].SectorsPerTrack;
+ startingOffset.QuadPart = 0;
+
+ if (pLogical) {
+
+ pInfo[entry].StartingOffset.QuadPart = pLogical->Offset.QuadPart + bytesPerTrack.QuadPart;
+ pInfo[entry].PartitionLength.QuadPart = pLogical->Length.QuadPart - bytesPerTrack.QuadPart;
+ pInfo[entry].HiddenSectors = sectorsPerTrack.LowPart;
+ pInfo[entry].RewritePartition = pLogical->Update;
+ pInfo[entry].BootIndicator = pLogical->Active;
+ pInfo[entry].PartitionType = pLogical->SysID;
+
+ if(pInfo[entry].RewritePartition) {
+ startingOffset = pInfo[entry].StartingOffset;
+ }
+
+ entry++;
+ }
+
+ if (pNextLogical) {
+
+ pInfo[entry].StartingOffset = pNextLogical->Offset;
+ pInfo[entry].PartitionLength = pNextLogical->Length;
+ pInfo[entry].HiddenSectors = 0;
+ pInfo[entry].RewritePartition = TRUE;
+ pInfo[entry].BootIndicator = FALSE;
+ pInfo[entry].PartitionType = SYSID_EXTENDED;
+
+ entry++;
+ }
+
+ UnusedEntryFill(pInfo + entry, ENTRIES_PER_BOOTSECTOR - entry);
+ return startingOffset;
+}
+
+
+STATUS_CODE
+ZapSector(
+ ULONG Disk,
+ LARGE_INTEGER Offset
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes zeros into a sector at a given offset. This is
+ used to clear out a new partition's filesystem boot record, so that
+ no previous filesystem appears in a new partition; or to clear out the
+ first EBR in the extended partition if there are to be no logical vols.
+
+Arguments:
+
+ Disk - disk to write to
+
+ Offset - byte offset to a newly created partition on Disk
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+ ULONG sectorSize = DiskGeometryArray[Disk].BytesPerSector;
+ ULONG i;
+ PCHAR sectorBuffer,
+ alignedSectorBuffer;
+ STATUS_CODE status;
+ HANDLE_T handle;
+ LARGE_INTEGER temp;
+
+ if ((sectorBuffer = AllocateMemory(2*sectorSize)) == NULL) {
+ RETURN_OUT_OF_MEMORY;
+ }
+
+ alignedSectorBuffer = (PCHAR)(((ULONG)sectorBuffer+sectorSize) & ~(sectorSize-1));
+
+ for (i=0; i<sectorSize; alignedSectorBuffer[i++] = 0);
+
+ if ((status = LowOpenDisk(GetDiskName(Disk),&handle)) != OK_STATUS) {
+ FreeMemory(sectorBuffer);
+ return status;
+ }
+
+ temp.QuadPart = Offset.QuadPart / sectorSize;
+ status = LowWriteSectors(handle,
+ sectorSize,
+ temp.LowPart,
+ 1,
+ alignedSectorBuffer);
+ LowCloseDisk(handle);
+
+ // Now to make sure the file system really did a dismount,
+ // force a mount/verify of the partition. This avoids a
+ // problem where HPFS doesn't dismount when asked, but instead
+ // marks the volume for verify.
+
+ if ((status = LowOpenDisk(GetDiskName(Disk), &handle)) == OK_STATUS) {
+ LowCloseDisk(handle);
+ }
+
+ FreeMemory(sectorBuffer);
+ return status;
+}
+
+
+STATUS_CODE
+WriteDriveLayout(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes the current partition layout for a given disk
+ out to disk. The high-level PARTITION lists are transformed into
+ a DRIVE_LAYOUT_INFORMATION structure before being passed down
+ to the low-level partition table writing routine.
+
+Arguments:
+
+ Disk - index of disk whose on-disk partition structure is to be updated.
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+#define MAX_DISKS 250
+ PDRIVE_LAYOUT_INFORMATION driveLayout;
+ PPARTITION_INFORMATION pinfo;
+ ULONG entryCount;
+ ULONG sectorSize;
+ STATUS_CODE status;
+ LARGE_INTEGER startingOffset,
+ extendedStartingOffset;
+ PPARTITION nextPartition,
+ partition,
+ partitionHash[MAX_DISKS];
+
+ extendedStartingOffset.QuadPart = 0;
+ memset(partitionHash, 0, sizeof(partitionHash));
+
+ // allocate a huge buffer now to avoid complicated dynamic
+ // reallocation schemes later.
+
+ if (!(driveLayout = AllocateMemory((MAX_DISKS + 1) * sizeof(PARTITION_INFORMATION)))) {
+ RETURN_OUT_OF_MEMORY;
+ }
+
+ pinfo = &driveLayout->PartitionEntry[0];
+
+ // first do the mbr.
+
+ entryCount = 0;
+ partition = PrimaryPartitions[Disk];
+ sectorSize = DiskGeometryArray[Disk].BytesPerSector;
+
+ while (partition) {
+
+ if (partition->SysID != SYSID_UNUSED) {
+
+ if (IsExtended(partition->SysID)) {
+ extendedStartingOffset = partition->Offset;
+ } else {
+ partitionHash[entryCount] = partition;
+ }
+
+ pinfo[entryCount].StartingOffset = partition->Offset;
+ pinfo[entryCount].PartitionLength = partition->Length;
+ pinfo[entryCount].PartitionType = partition->SysID;
+ pinfo[entryCount].BootIndicator = partition->Active;
+ pinfo[entryCount].RewritePartition = partition->Update;
+ pinfo[entryCount].HiddenSectors = (ULONG) (partition->Offset.QuadPart / sectorSize);
+
+ // if we're creating this partition, clear out the
+ // filesystem boot sector.
+
+ if (pinfo[entryCount].RewritePartition
+ && (partition->Update != CHANGED_DONT_ZAP)
+ && !IsExtended(pinfo[entryCount].PartitionType)) {
+ status = ZapSector(Disk,pinfo[entryCount].StartingOffset);
+ if (status != OK_STATUS) {
+ FreeMemory(driveLayout);
+ return status;
+ }
+ }
+
+ entryCount++;
+ }
+ partition = partition->Next;
+ }
+
+ // fill the remainder of the MBR with unused entries.
+ // NOTE that there will thus always be an MBR even if there
+ // are no partitions defined.
+
+ UnusedEntryFill(pinfo+entryCount, ENTRIES_PER_BOOTSECTOR - entryCount);
+ entryCount = ENTRIES_PER_BOOTSECTOR;
+
+ // now handle the logical volumes.
+ // first check to see whether we need a dummy EBR at the beginning
+ // of the extended partition. This is the case when there is
+ // free space at the beginning of the extended partition.
+#if 0
+ // Also handle the case where we are creating an empty extended
+ // partition -- need to zap the first sector to eliminate any residue
+ // that might start an EBR chain.
+#else
+ // BUGBUG 4/24/92 tedm: Currently the io subsystem returns an error
+ // status (status_bad_master_boot_record) if any mbr or ebr is bad.
+ // Zeroing the first sector of the extended partition therefore causes
+ // the whole disk to be seen as empty. So create a blank, but valid,
+ // EBR in the 'empty extended partition' case. Code is in the 'else'
+ // part of the #if 0, below.
+#endif
+
+ if ((partition = LogicalVolumes[Disk]) && (partition->SysID == SYSID_UNUSED)) {
+ if (partition->Next) {
+
+ partitionHash[entryCount] = partition;
+ MakeBootRec(Disk, pinfo+entryCount, NULL, partition->Next);
+ entryCount += ENTRIES_PER_BOOTSECTOR;
+ partition = partition->Next;
+ } else {
+
+#if 0
+ status = ZapSector(Disk, extendedStartingOffset);
+ if (status != OK_STATUS) {
+ FreeMemory(driveLayout);
+ return status;
+ }
+#else
+ MakeBootRec(Disk, pinfo+entryCount, NULL, NULL);
+ entryCount += ENTRIES_PER_BOOTSECTOR;
+#endif
+ }
+ }
+
+ while (partition) {
+ if (partition->SysID != SYSID_UNUSED) {
+
+ // find the next logical volume.
+
+ nextPartition = partition->Next;
+ while (nextPartition) {
+ if (nextPartition->SysID != SYSID_UNUSED) {
+ break;
+ }
+ nextPartition = nextPartition->Next;
+ }
+
+ partitionHash[entryCount] = partition;
+ startingOffset = MakeBootRec(Disk, pinfo+entryCount, partition, nextPartition);
+
+ // if we're creating a volume, clear out its filesystem
+ // boot sector so it starts out fresh.
+
+ if ((startingOffset.QuadPart) && (partition->Update != CHANGED_DONT_ZAP)) {
+ status = ZapSector(Disk,startingOffset);
+ if (status != OK_STATUS) {
+ FreeMemory(driveLayout);
+ return status;
+ }
+ }
+
+ entryCount += ENTRIES_PER_BOOTSECTOR;
+ }
+ partition = partition->Next;
+ }
+
+ driveLayout->PartitionCount = entryCount;
+ driveLayout->Signature = Signatures[Disk];
+ status = LowSetDiskLayout(DiskNames[Disk], driveLayout);
+
+ if (NT_SUCCESS(status)) {
+
+ // Update the partition numbers in the region structures.
+
+ // ReconcilePartitionNumbers(Disk, driveLayout);
+
+ for (entryCount = 0; entryCount < MAX_DISKS; entryCount++) {
+ if (partition = partitionHash[entryCount]) {
+ if (partition->Update) {
+ pinfo = &driveLayout->PartitionEntry[entryCount];
+ partition->PartitionNumber = pinfo->PartitionNumber;
+ }
+ }
+ }
+ }
+
+ FreeMemory(driveLayout);
+ return status;
+}
+
+
+STATUS_CODE
+CommitPartitionChanges(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the entry point for updating the on-disk partition
+ structures of a disk. The disk is only written to if the partition
+ structure has been changed by adding or deleting partitions.
+
+Arguments:
+
+ Disk - index of disk whose on-disk partition structure is to be updated.
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+ PPARTITION p;
+ STATUS_CODE status;
+
+ if (!HavePartitionsBeenChanged(Disk)) {
+ return OK_STATUS;
+ }
+
+ if ((status = WriteDriveLayout(Disk)) != OK_STATUS) {
+ return status;
+ }
+
+ // BUGBUG for ARC and NT MIPS, update NVRAM vars so partitions are right.
+ // Do that here, before partition numbers are reassigned.
+
+ p = PrimaryPartitions[Disk];
+ while (p) {
+ p->Update = FALSE;
+ p->OriginalPartitionNumber = p->PartitionNumber;
+ p = p->Next;
+ }
+ p = LogicalVolumes[Disk];
+ while (p) {
+ p->Update = FALSE;
+ p->OriginalPartitionNumber = p->PartitionNumber;
+ p = p->Next;
+ }
+
+ ChangesRequested[Disk] = FALSE;
+ ChangesCommitted[Disk] = TRUE;
+ return OK_STATUS;
+}
+
+
+BOOLEAN
+IsRegionCommitted(
+ PREGION_DESCRIPTOR RegionDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ Given a region descriptor, return TRUE if it actually exists on disk,
+ FALSE otherwise.
+
+Arguments:
+
+ RegionDescriptor - the region to check
+
+Return Value:
+
+ TRUE - if the region actually exists on disk
+ FALSE otherwise.
+
+--*/
+
+{
+ PPERSISTENT_REGION_DATA regionData;
+
+ regionData = PERSISTENT_DATA(RegionDescriptor);
+ if (!regionData) {
+ return FALSE;
+ }
+ return regionData->VolumeExists;
+}
+
+
+BOOLEAN
+HavePartitionsBeenChanged(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns TRUE if the given disk's partition structures
+ have been modified by adding or deleting partitions, since the
+ on-disk structures were last written by a call to CommitPartitionChanges
+ (or first read).
+
+Arguments:
+
+ Disk - index of disk to check
+
+Return Value:
+
+ true if Disk's partition structure has changed.
+
+--*/
+
+{
+ return ChangesRequested[Disk];
+}
+
+
+BOOLEAN
+ChangeCommittedOnDisk(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will inform the caller if a change was actually committed
+ to the disk given.
+
+Arguments:
+
+ Disk - index of disk to check
+
+Return Value:
+
+ TRUE if disk was changed
+ FALSE otherwise.
+
+--*/
+
+{
+ return ChangesCommitted[Disk];
+}
+
+
+VOID
+ClearCommittedDiskInformation(
+ )
+
+/*++
+
+Routine Description:
+
+ Clear all knowledge about any changes that have occurred to the
+ disks.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG i;
+
+ for (i=0; i<CountOfDisks; i++) {
+ ChangesCommitted[i] = FALSE;
+ }
+}
+
+
+VOID
+FdMarkDiskDirty(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ Remember that this disk has had some partitioning changes.
+
+Arguments:
+
+ Disk - the disk number
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ChangesRequested[Disk] = TRUE;
+}
+
+
+VOID
+FdSetPersistentData(
+ IN PREGION_DESCRIPTOR Region,
+ IN ULONG Data
+ )
+
+/*++
+
+Routine Description:
+
+ Set the persistent data area for the specified region.
+
+Arguments:
+
+ Region - the region for which the persistent data is to be set
+ Data - the persistent data for the region.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ((PREGION_DATA)(Region->Reserved))->Partition->PersistentData =
+ (PPERSISTENT_REGION_DATA) Data;
+}
+
+
+ULONG
+FdGetMinimumSizeMB(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ Return the minimum size for a partition on a given disk.
+
+ This is the rounded size of one cylinder or 1, whichever is greater.
+
+Arguments:
+
+ Region - region describing the partition to check.
+
+Return Value:
+
+ Actual offset
+
+--*/
+
+{
+ LARGE_INTEGER temp;
+
+ temp.QuadPart = DiskGeometryArray[Disk].BytesPerCylinder;
+ return max(SIZEMB(temp), 1);
+}
+
+
+ULONG
+FdGetMaximumSizeMB(
+ IN PREGION_DESCRIPTOR Region,
+ IN REGION_TYPE CreationType
+ )
+
+/*++
+
+Routine Description:
+
+ Given a region of disk determine how much of it may be used to
+ create the specified partition type. This code take into consideration
+ the many alignment restrictions imposed by early DOS software versions.
+
+Arguments:
+
+ Region - The affected region
+ CreationType - What is being created
+ (extended partition/primary partition)
+
+Return Value:
+
+ The maximum size that a partition of the specified type can be
+ to fit within the space available in the region.
+
+--*/
+
+{
+ PREGION_DATA createData = Region->Reserved;
+ LARGE_INTEGER maxSize;
+
+ maxSize = createData->AlignedRegionSize;
+ if (!(createData->AlignedRegionOffset.QuadPart)) {
+ ULONG delta;
+
+ delta = (CreationType == REGION_EXTENDED)
+ ? DiskGeometryArray[Region->Disk].BytesPerCylinder
+ : DiskGeometryArray[Region->Disk].BytesPerTrack;
+
+ maxSize.QuadPart -= delta;
+ }
+
+ return SIZEMB(maxSize);
+}
+
+
+LARGE_INTEGER
+FdGetExactSize(
+ IN PREGION_DESCRIPTOR Region,
+ IN BOOLEAN ForExtended
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ PREGION_DATA regionData = Region->Reserved;
+ LARGE_INTEGER largeSize = regionData->AlignedRegionSize;
+ LARGE_INTEGER bytesPerTrack;
+ LARGE_INTEGER bytesPerCylinder;
+
+ bytesPerTrack.QuadPart = DiskGeometryArray[Region->Disk].BytesPerTrack;
+ bytesPerCylinder.QuadPart = DiskGeometryArray[Region->Disk].BytesPerCylinder;
+
+ if (Region->RegionType == REGION_LOGICAL) {
+
+ //
+ // The region is within the extended partition. It doesn't matter
+ // whether it's free space or used -- in either case, we need to
+ // account for the reserved EBR track.
+ //
+
+ largeSize.QuadPart -= bytesPerTrack.QuadPart;
+
+ } else if (Region->SysID == SYSID_UNUSED) {
+
+ //
+ // The region is unused space not inside the extended partition.
+ // We must know whether the caller will put a primary or extended
+ // partition there -- a primary partition can use all the space, but
+ // a logical volume in the extended partition won't include the first
+ // track. If the free space starts at offset 0 on the disk, a special
+ // calculation must be used to move the start of the partition to
+ // skip a track for a primary or a cylinder and a track for an
+ // extended+logical.
+ //
+
+ if ((!regionData->AlignedRegionOffset.QuadPart) || ForExtended) {
+ largeSize.QuadPart -= bytesPerTrack.QuadPart;
+ }
+
+ if ((!regionData->AlignedRegionOffset.QuadPart) && ForExtended) {
+ largeSize.QuadPart -= bytesPerCylinder.QuadPart;
+ }
+ }
+
+ return largeSize;
+}
+
+
+LARGE_INTEGER
+FdGetExactOffset(
+ IN PREGION_DESCRIPTOR Region
+ )
+
+/*++
+
+Routine Description:
+
+ Determine where a given partition _actually_ starts, which may be
+ different than where is appears because of EBR reserved tracks, etc.
+
+ NOTE: This routine is not meant to operate on unused regions or
+ extended partitions. In these cases, it just returns the apparant offset.
+
+Arguments:
+
+ Region - region describing the partition to check.
+
+Return Value:
+
+ Actual offset
+
+--*/
+
+{
+ LARGE_INTEGER offset = ((PREGION_DATA)(Region->Reserved))->Partition->Offset;
+
+ if ((Region->SysID != SYSID_UNUSED) && (Region->RegionType == REGION_LOGICAL)) {
+
+ //
+ // The region is a logical volume.
+ // Account for the reserved EBR track.
+ //
+
+ offset.QuadPart += DiskGeometryArray[Region->Disk].BytesPerTrack;
+ }
+
+ return offset;
+}
+
+
+BOOLEAN
+FdCrosses1024Cylinder(
+ IN PREGION_DESCRIPTOR Region,
+ IN ULONG CreationSizeMB,
+ IN REGION_TYPE RegionType
+ )
+
+/*++
+
+Routine Description:
+
+ Determine whether a used region corsses the 1024th cylinder, or whether
+ a partition created within a free space will cross the 1024th cylinder.
+
+Arguments:
+
+ Region - region describing the partition to check.
+ CreationSizeMB - if the Region is for a free space, this is the size of
+ the partition to be checked.
+ RegionType - one of REGION_PRIMARY, REGION_EXTENDED, or REGION_LOGICAL
+
+Return Value:
+
+ TRUE if the end cylinder >= 1024.
+
+--*/
+
+{
+ LARGE_INTEGER start,
+ size,
+ end,
+ zero;
+
+ if (Region->SysID == SYSID_UNUSED) {
+
+ // Determine the exact size and offset of the partition, according
+ // to how CreatePartitionEx() will do it.
+
+ zero.QuadPart = 0;
+ DetermineCreateSizeAndOffset(Region,
+ zero,
+ CreationSizeMB,
+ RegionType,
+ &start,
+ &size);
+ } else {
+
+ start = ((PREGION_DATA)(Region->Reserved))->Partition->Offset;
+ size = ((PREGION_DATA)(Region->Reserved))->Partition->Length;
+ }
+
+ end.QuadPart = (start.QuadPart + size.QuadPart) - 1;
+
+ // End is the last byte in the partition. Divide by the number of
+ // bytes in a cylinder and see whether the result is > 1023.
+
+ end.QuadPart = end.QuadPart / DiskGeometryArray[Region->Disk].BytesPerCylinder;
+ return (end.QuadPart > 1023);
+}
+
+
+BOOLEAN
+IsDiskOffLine(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ return OffLine[Disk];
+}
+
+ULONG
+FdGetDiskSignature(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ return Signatures[Disk];
+}
+
+VOID
+FdSetDiskSignature(
+ IN ULONG Disk,
+ IN ULONG Signature
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ Signatures[Disk] = Signature;
+}
+
+BOOLEAN
+SignatureIsUniqueToSystem(
+ IN ULONG Disk,
+ IN ULONG Signature
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ ULONG index;
+
+ for (index = 0; index < Disk; index++) {
+ if (Signatures[index] == Signature) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
diff --git a/private/utils/fdisk/fdft.c b/private/utils/fdisk/fdft.c
new file mode 100644
index 000000000..5eed40346
--- /dev/null
+++ b/private/utils/fdisk/fdft.c
@@ -0,0 +1,1500 @@
+
+/*++
+
+Copyright (c) 1991-1993 Microsoft Corporation
+
+Module Name:
+
+ fdft.c
+
+Abstract:
+
+ This module contains FT support routines for Disk Administrator
+
+Author:
+
+ Edward (Ted) Miller (TedM) 11/15/91
+
+Environment:
+
+ User process.
+
+Notes:
+
+Revision History:
+
+ 11-Nov-93 (bobri) minor changes - mostly cosmetic.
+
+--*/
+
+#include "fdisk.h"
+#include <string.h>
+
+
+// This variable heads a linked list of ft object sets.
+
+PFT_OBJECT_SET FtObjects = NULL;
+
+// Array of pointers to registry disk descriptors that we
+// remember, ie, save for later use when a disk is not physically
+// present on the machine.
+
+PDISK_DESCRIPTION *RememberedDisks;
+ULONG RememberedDiskCount;
+
+
+
+ULONG
+FdpDetermineDiskDescriptionSize(
+ PDISKSTATE DiskState
+ );
+
+ULONG
+FdpConstructDiskDescription(
+ IN PDISKSTATE DiskState,
+ OUT PDISK_DESCRIPTION DiskDescription
+ );
+
+VOID
+FdpRememberDisk(
+ IN PDISK_DESCRIPTION DiskDescription
+ );
+
+VOID
+FdpInitializeMirrors(
+ VOID
+ );
+
+#define MAX_FT_SET_TYPES 4
+ULONG OrdinalToAllocate[MAX_FT_SET_TYPES] = {0, 0, 0, 0};
+
+VOID
+MaintainOrdinalTables(
+ IN FT_TYPE FtType,
+ IN ULONG Ordinal
+ )
+
+/*++
+
+Routine Description:
+
+ Maintain the minimum and maximum Ordinal value recorded.
+
+Arguments:
+
+ FtType - the type of the FT set.
+ Ordinal - the in use FtGroup (or ordinal) number
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ if (Ordinal > OrdinalToAllocate[FtType]) {
+ OrdinalToAllocate[FtType] = Ordinal;
+ }
+}
+
+DWORD
+FdftNextOrdinal(
+ IN FT_TYPE FtType
+ )
+
+/*++
+
+Routine Description:
+
+ Allocate a number that will uniquely identify the FT set
+ from other sets of the same type. This number must be unique
+ from any given or used by FT sets of the same type due to
+ requirements of FT dynamic partitioning.
+
+Arguments:
+
+ FtType - The type of the FT set.
+
+Return Value:
+
+ The FtGroup number -- called an "ordinal" in the internal
+ structures.
+
+--*/
+
+{
+ DWORD ord;
+ PFT_OBJECT_SET pftset;
+ BOOL looping;
+
+ // The Ordinal value is going to be used as an FtGroup number
+ // FtGroups are USHORTs so don't wrap on the Ordinal. Try
+ // to keep the next ordinal in the largest opening range, that
+ // is if the minimum found is > half way through a USHORT, start
+ // the ordinals over at zero.
+
+ if (OrdinalToAllocate[FtType] > 0x7FFE) {
+ OrdinalToAllocate[FtType] = 0;
+ }
+
+ ord = OrdinalToAllocate[FtType];
+ ord++;
+
+ do {
+ looping = FALSE;
+ pftset = FtObjects;
+ while (pftset) {
+ if ((pftset->Type == FtType) && (pftset->Ordinal == ord)) {
+ ord++;
+ looping = TRUE;
+ break;
+ }
+ pftset = pftset->Next;
+ }
+ } while (looping);
+
+ OrdinalToAllocate[FtType] = (ord + 1);
+ return ord;
+}
+
+
+VOID
+FdftCreateFtObjectSet(
+ IN FT_TYPE FtType,
+ IN PREGION_DESCRIPTOR *Regions,
+ IN DWORD RegionCount,
+ IN FT_SET_STATUS Status
+ )
+
+/*++
+
+Routine Description:
+
+ Create the FT set structures for the give collection of
+ region pointers.
+
+Arguments:
+
+ FtType
+ Regions
+ RegionCount
+ Status
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ DWORD Ord;
+ PFT_OBJECT_SET FtSet;
+ PFT_OBJECT FtObject;
+
+
+ FtSet = Malloc(sizeof(FT_OBJECT_SET));
+
+ // Figure out an ordinal for the new object set.
+
+ FtSet->Ordinal = FdftNextOrdinal(FtType);
+ FtSet->Type = FtType;
+ FtSet->Members = NULL;
+ FtSet->Member0 = NULL;
+ FtSet->Status = Status;
+
+ // Link the new object set into the list.
+
+ FtSet->Next = FtObjects;
+ FtObjects = FtSet;
+
+ // For each region in the set, associate the ft info with it.
+
+ for (Ord=0; Ord<RegionCount; Ord++) {
+
+ FtObject = Malloc(sizeof(FT_OBJECT));
+
+ // If this is a creation of a stripe set with parity, then
+ // we must mark the 0th item 'Initializing' instead of 'Healthy'.
+
+ if ((Ord == 0)
+ && (FtType == StripeWithParity)
+ && (Status == FtSetNewNeedsInitialization)) {
+ FtObject->State = Initializing;
+ } else {
+ FtObject->State = Healthy;
+ }
+
+ if (!Ord) {
+ FtSet->Member0 = FtObject;
+ }
+
+ FtObject->Set = FtSet;
+ FtObject->MemberIndex = Ord;
+ FtObject->Next = FtSet->Members;
+ FtSet->Members = FtObject;
+
+ SET_FT_OBJECT(Regions[Ord],FtObject);
+ }
+}
+
+BOOL
+FdftUpdateFtObjectSet(
+ IN PFT_OBJECT_SET FtSet,
+ IN FT_SET_STATUS SetState
+ )
+
+/*++
+
+Routine Description:
+
+ Given an FT set, go back to the registry information and
+ update the state of the members with the state in the registry.
+
+ NOTE: The following condition may exist. It is possible for
+ the FtDisk driver to return that the set is in an initializing
+ or regenerating state and not have this fact reflected in the
+ registry. This can happen when the system has crashed and
+ on restart the FtDisk driver started the regeneration of the
+ check data (parity).
+
+Arguments:
+
+ FtSet - the set to update.
+
+Return Value:
+
+ TRUE if the set state provided has a strong likelyhood of being correct
+ FALSE if the NOTE condition above is occuring.
+
+--*/
+
+{
+ BOOLEAN allHealthy = TRUE;
+ PFT_OBJECT ftObject;
+ PDISK_REGISTRY diskRegistry;
+ PDISK_PARTITION partition;
+ PDISK_DESCRIPTION diskDescription;
+ DWORD ec;
+ ULONG diskIndex,
+ partitionIndex;
+
+ ec = MyDiskRegistryGet(&diskRegistry);
+ if (ec != NO_ERROR) {
+
+ // No registry information.
+
+ return TRUE;
+ }
+
+ diskDescription = diskRegistry->Disks;
+ for (diskIndex=0; diskIndex<diskRegistry->NumberOfDisks; diskIndex++) {
+
+ for (partitionIndex=0; partitionIndex<diskDescription->NumberOfPartitions; partitionIndex++) {
+
+ partition = &diskDescription->Partitions[partitionIndex];
+ if ((partition->FtType == FtSet->Type) && (partition->FtGroup == (USHORT) FtSet->Ordinal)) {
+
+ // Have a match for a partition within this set.
+ // Find the region descriptor for this partition and
+ // update its state accordingly.
+
+ for (ftObject = FtSet->Members; ftObject; ftObject = ftObject->Next) {
+
+ if (ftObject->MemberIndex == (ULONG) partition->FtMember) {
+ ftObject->State = partition->FtState;
+ break;
+ }
+
+ if (partition->FtState != Healthy) {
+ allHealthy = FALSE;
+ }
+ }
+ }
+ }
+ diskDescription = (PDISK_DESCRIPTION)&diskDescription->Partitions[diskDescription->NumberOfPartitions];
+ }
+
+ Free(diskRegistry);
+ if ((allHealthy) && (SetState != FtSetHealthy)) {
+
+ // This is a condition where the system must be
+ // updating the check data for redundant sets.
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+VOID
+FdftDeleteFtObjectSet(
+ IN PFT_OBJECT_SET FtSet,
+ IN BOOL OffLineDisksOnly
+ )
+
+/*++
+
+Routine Description:
+
+ Delete an ft set, or rather its internal representation as a linked
+ list of ft member structures.
+
+Arguments:
+
+ FtSet - supplies pointer to ft set structure for set to delete.
+
+ OffLineDisksOnly - if TRUE, then do not delete the set but instead
+ scan remembered disks for members of the set and remove such members.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PFT_OBJECT ftObject = FtSet->Members;
+ PFT_OBJECT next;
+ PFT_OBJECT_SET ftSetTemp;
+ PDISK_DESCRIPTION diskDescription;
+ PDISK_PARTITION diskPartition;
+ ULONG partitionCount,
+ size,
+ i,
+ j;
+
+ // Locate any members of the ft set on remembered disks and
+ // remove the entries for such partitions.
+
+ for (i=0; i<RememberedDiskCount; i++) {
+
+ diskDescription = RememberedDisks[i];
+ partitionCount = diskDescription->NumberOfPartitions;
+
+ for (j=0; j<partitionCount; j++) {
+
+ diskPartition = &diskDescription->Partitions[j];
+
+ if ((diskPartition->FtType == FtSet->Type)
+ && (diskPartition->FtGroup == (USHORT)FtSet->Ordinal)) {
+
+ // Found a member of the ft set being deleted on a
+ // remembered disk. Remove the partition from the
+ // remembered disk.
+
+ RtlMoveMemory( diskPartition,
+ diskPartition+1,
+ (partitionCount - j - 1) * sizeof(DISK_PARTITION)
+ );
+
+ partitionCount--;
+ j--;
+ }
+ }
+
+ if (partitionCount != diskDescription->NumberOfPartitions) {
+
+ diskDescription->NumberOfPartitions = (USHORT)partitionCount;
+
+ size = sizeof(DISK_DESCRIPTION);
+ if (partitionCount > 1) {
+ size += (partitionCount - 1) * sizeof(DISK_PARTITION);
+ }
+ RememberedDisks[i] = Realloc(RememberedDisks[i], size);
+ }
+ }
+
+ if (OffLineDisksOnly) {
+ return;
+ }
+
+ // First, free all members of the set
+
+ while (ftObject) {
+ next = ftObject->Next;
+ Free(ftObject);
+ ftObject = next;
+ }
+
+ // now, remove the set from the linked list of sets.
+
+ if (FtObjects == FtSet) {
+ FtObjects = FtSet->Next;
+ } else {
+ ftSetTemp = FtObjects;
+ while (1) {
+ FDASSERT(ftSetTemp);
+ if (ftSetTemp == NULL) {
+ break;
+ }
+ if (ftSetTemp->Next == FtSet) {
+ ftSetTemp->Next = FtSet->Next;
+ break;
+ }
+ ftSetTemp = ftSetTemp->Next;
+ }
+ }
+ Free(FtSet);
+}
+
+VOID
+FdftExtendFtObjectSet(
+ IN OUT PFT_OBJECT_SET FtSet,
+ IN OUT PREGION_DESCRIPTOR* Regions,
+ IN DWORD RegionCount
+ )
+/*++
+
+Routine Description:
+
+ This function adds regions to an existing FT-set.
+
+Arguments:
+
+ FtSet -- Supplies the set to extend.
+ Regions -- Supplies the regions to add to the set. Note
+ that these regions are updated with the FT
+ information.
+ RegionCount -- Supplies the number of regions to add.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PFT_OBJECT FtObject;
+ DWORD i, StartingIndex;
+
+ // Determine the starting member index for the new regions.
+ // It is the greatest of the existing member indices plus one.
+
+ StartingIndex = 0;
+
+ for( FtObject = FtSet->Members; FtObject; FtObject = FtObject->Next ) {
+
+ if( FtObject->MemberIndex > StartingIndex ) {
+
+ StartingIndex = FtObject->MemberIndex;
+ }
+ }
+
+ StartingIndex++;
+
+
+ // Associate the ft-set's information with each of the
+ // new regions.
+
+ for( i = 0; i < RegionCount; i++ ) {
+
+ FtObject = Malloc( sizeof(FT_OBJECT) );
+
+ FtObject->Set = FtSet;
+ FtObject->MemberIndex = StartingIndex + i;
+ FtObject->Next = FtSet->Members;
+ FtObject->State = Healthy;
+ FtSet->Members = FtObject;
+
+ SET_FT_OBJECT(Regions[i],FtObject);
+ }
+
+ FtSet->Status = FtSetExtended;
+}
+
+
+PULONG DiskHadRegistryEntry;
+
+ULONG
+ActualPartitionCount(
+ IN PDISKSTATE DiskState
+ )
+
+/*++
+
+Routine Description:
+
+ Given a disk, this routine counts the number of partitions on it.
+ The number of partitions is the number of regions that appear in
+ the NT name space (ie, the maximum value of <x> in
+ \device\harddiskn\partition<x>).
+
+Arguments:
+
+ DiskState - descriptor for the disk in question.
+
+Return Value:
+
+ Partition count (may be 0).
+
+--*/
+
+{
+ ULONG i,PartitionCount=0;
+ PREGION_DESCRIPTOR region;
+
+ for(i=0; i<DiskState->RegionCount; i++) {
+ region = &DiskState->RegionArray[i];
+ if((region->SysID != SYSID_UNUSED) &&
+ !IsExtended(region->SysID) &&
+ IsRecognizedPartition(region->SysID)) {
+
+ PartitionCount++;
+ }
+ }
+ return(PartitionCount);
+}
+
+
+PDISKSTATE
+LookUpDiskBySignature(
+ IN ULONG Signature
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will look through the disk descriptors created by the
+ fdisk back end looking for a disk with a particular signature.
+
+Arguments:
+
+ Signature - signature of disk to locate
+
+Return Value:
+
+ Pointer to disk descriptor or NULL if no disk with the given signature
+ was found.
+
+--*/
+
+{
+ ULONG disk;
+ PDISKSTATE ds;
+
+ for(disk=0; disk<DiskCount; disk++) {
+ ds = Disks[disk];
+ if(ds->Signature == Signature) {
+ return(ds);
+ }
+ }
+ return(NULL);
+}
+
+
+PREGION_DESCRIPTOR
+LookUpPartition(
+ IN PDISKSTATE DiskState,
+ IN LARGE_INTEGER Offset,
+ IN LARGE_INTEGER Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will look through a region descriptor array for a
+ partition with a particular length and starting offset.
+
+Arguments:
+
+ DiskState - disk on which to locate the partition
+ Offset - offset of partition on the disk to find
+ Length - size of the partition to find
+
+Return Value:
+
+ Pointer to region descriptor or NULL if no such partition on that disk
+
+--*/
+
+{
+ ULONG regionIndex,
+ maxRegion = DiskState->RegionCount;
+ PREGION_DESCRIPTOR regionDescriptor;
+ LARGE_INTEGER offset,
+ length;
+
+ for (regionIndex=0; regionIndex<maxRegion; regionIndex++) {
+
+ regionDescriptor = &DiskState->RegionArray[regionIndex];
+
+ if ((regionDescriptor->SysID != SYSID_UNUSED) && !IsExtended(regionDescriptor->SysID)) {
+
+ offset = FdGetExactOffset(regionDescriptor);
+ length = FdGetExactSize(regionDescriptor, FALSE);
+
+ if ((offset.LowPart == Offset.LowPart )
+ && (offset.HighPart == Offset.HighPart)
+ && (length.LowPart == Length.LowPart)
+ && (length.HighPart == Length.HighPart)) {
+ return regionDescriptor;
+ }
+ }
+ }
+ return NULL;
+}
+
+
+VOID
+AddObjectToSet(
+ IN PFT_OBJECT FtObjectToAdd,
+ IN FT_TYPE FtType,
+ IN USHORT FtGroup
+ )
+
+/*++
+
+Routine Description:
+
+ Find the FtSet for that this object belongs to and insert
+ it into the chain of members. If the set cannot be found
+ in the existing collection of sets, create a new one.
+
+Arguments:
+
+ FtObjectToAdd - the object point to be added.
+ FtType - the type of the FT set.
+ FtGroup - group for this object.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PFT_OBJECT_SET ftSet = FtObjects;
+
+ while (ftSet) {
+
+ if ((ftSet->Type == FtType) && (ftSet->Ordinal == FtGroup)) {
+ break;
+ }
+ ftSet = ftSet->Next;
+ }
+
+ if (!ftSet) {
+
+ // There is no such existing ft set. Create one.
+
+ ftSet = Malloc(sizeof(FT_OBJECT_SET));
+
+ ftSet->Status = FtSetHealthy;
+ ftSet->Type = FtType;
+ ftSet->Ordinal = FtGroup;
+ ftSet->Members = NULL;
+ ftSet->Next = FtObjects;
+ ftSet->Member0 = NULL;
+ ftSet->NumberOfMembers = 0;
+ FtObjects = ftSet;
+ }
+
+ FDASSERT(ftSet);
+
+ FtObjectToAdd->Next = ftSet->Members;
+ ftSet->Members = FtObjectToAdd;
+ ftSet->NumberOfMembers++;
+ FtObjectToAdd->Set = ftSet;
+
+ if (FtObjectToAdd->MemberIndex == 0) {
+ ftSet->Member0 = FtObjectToAdd;
+ }
+
+ if (FtType == StripeWithParity || FtType == Mirror) {
+
+ // Update the set's state based on the state of the new member:
+
+ switch (FtObjectToAdd->State) {
+
+ case Healthy:
+
+ // Doesn't change state of set.
+
+ break;
+
+ case Regenerating:
+ ftSet->Status = (ftSet->Status == FtSetHealthy ||
+ ftSet->Status == FtSetRegenerating)
+ ? FtSetRegenerating
+ : FtSetBroken;
+ break;
+
+ case Initializing:
+ ftSet->Status = (ftSet->Status == FtSetHealthy ||
+ ftSet->Status == FtSetInitializing)
+ ? FtSetInitializing
+ : FtSetBroken;
+ break;
+
+ default:
+
+ // If only one member is bad, the set is recoverable;
+ // otherwise, it's broken.
+
+ ftSet->Status = (ftSet->Status == FtSetHealthy)
+ ? FtSetRecoverable
+ : FtSetDisabled;
+ break;
+ }
+ }
+}
+
+
+ULONG
+InitializeFt(
+ IN BOOL DiskSignaturesCreated
+ )
+
+/*++
+
+Routine Description:
+
+ Search the disk registry information to construct the FT
+ relationships in the system.
+
+Arguments:
+
+ DiskSignaturesCreated - boolean to indicate that new disks
+ were located in the system.
+
+Return Value:
+
+ An error code if the disk registry could not be obtained.
+
+--*/
+
+{
+ ULONG disk,
+ partitionIndex,
+ partitionCount;
+ PDISK_REGISTRY diskRegistry;
+ PDISK_PARTITION partition;
+ PDISK_DESCRIPTION diskDescription;
+ PDISKSTATE diskState;
+ PREGION_DESCRIPTOR regionDescriptor;
+ DWORD ec;
+ BOOL configDiskChanged = FALSE,
+ configMissingDisk = FALSE,
+ configExtraDisk = FALSE;
+ PFT_OBJECT ftObject;
+ BOOL anyDisksOffLine;
+ TCHAR name[100];
+
+
+ RememberedDisks = Malloc(0);
+ RememberedDiskCount = 0;
+
+ ec = MyDiskRegistryGet(&diskRegistry);
+ if (ec != NO_ERROR) {
+
+ FDLOG((0,"InitializeFt: Error %u from MyDiskRegistryGet\n",ec));
+
+ return ec;
+ }
+
+ DiskHadRegistryEntry = Malloc(DiskCount * sizeof(ULONG));
+ memset(DiskHadRegistryEntry,0,DiskCount * sizeof(ULONG));
+
+ diskDescription = diskRegistry->Disks;
+
+ for (disk = 0; disk < diskRegistry->NumberOfDisks; disk++) {
+
+ // For the disk described in the registry, look up the
+ // corresponding actual disk found by the fdisk init code.
+
+ diskState = LookUpDiskBySignature(diskDescription->Signature);
+
+ if (diskState) {
+
+ FDLOG((2,
+ "InitializeFt: disk w/ signature %08lx is disk #%u\n",
+ diskDescription->Signature,
+ diskState->Disk));
+
+ DiskHadRegistryEntry[diskState->Disk]++;
+
+ partitionCount = ActualPartitionCount(diskState);
+
+ if (partitionCount != diskDescription->NumberOfPartitions) {
+
+ FDLOG((1,"InitializeFt: partition counts for disk %08lx don't match:\n", diskState->Signature));
+ FDLOG((1," Count from actual disk: %u\n",partitionCount));
+ FDLOG((1," Count from registry : %u\n",diskDescription->NumberOfPartitions));
+
+ configDiskChanged = TRUE;
+ }
+ } else {
+
+ // there's an entry in the registry that does not have a
+ // real disk to match. Remember this disk; if it has any
+ // FT partitions, we also want to display a message telling
+ // the user that something's missing.
+
+ FDLOG((1,"InitializeFt: Entry for disk w/ signature %08lx has no matching real disk\n", diskDescription->Signature));
+
+ for (partitionIndex = 0; partitionIndex < diskDescription->NumberOfPartitions; partitionIndex++) {
+
+ partition = &diskDescription->Partitions[partitionIndex];
+ if (partition->FtType != NotAnFtMember) {
+
+ // This disk has an FT partition, so Windisk will
+ // want to tell the user that some disks are missing.
+
+ configMissingDisk = TRUE;
+ break;
+ }
+ }
+
+ FdpRememberDisk(diskDescription);
+ }
+
+ for (partitionIndex = 0; partitionIndex < diskDescription->NumberOfPartitions; partitionIndex++) {
+
+ partition = &diskDescription->Partitions[partitionIndex];
+ regionDescriptor = NULL;
+
+ if (diskState) {
+ regionDescriptor = LookUpPartition(diskState,
+ partition->StartingOffset,
+ partition->Length);
+ }
+
+ // At this point one of three conditions exists.
+ //
+ // 1. There is no disk related to this registry information
+ // diskState == NULL && regionDescriptor == NULL
+ // 2. There is a disk, but no partition related to this information
+ // diskState != NULL && regionDescriptor == NULL
+ // 3. There is a disk and a partition related to this information
+ // diskState != NULL && regionDescriptor != NULL
+ //
+ // In any of these conditions, if the registry entry is part
+ // of an FT set and FT object must be created.
+ //
+ // that corresponds to a partition's entry in the
+ // disk registry database.
+
+ if (partition->FtType != NotAnFtMember) {
+ ftObject = Malloc(sizeof(FT_OBJECT));
+ ftObject->Next = NULL;
+ ftObject->Set = NULL;
+ ftObject->MemberIndex = partition->FtMember;
+ ftObject->State = partition->FtState;
+
+ // if a partition was actually found there will be a
+ // regionDescriptor that needs to be updated.
+
+ if (regionDescriptor && regionDescriptor->PersistentData) {
+ FT_SET_STATUS setState;
+ ULONG numberOfMembers;
+
+ SET_FT_OBJECT(regionDescriptor, ftObject);
+
+ // Before the drive letter is moved into the region
+ // data, be certain that the FT volume exists at this
+ // drive letter.
+
+ LowFtVolumeStatusByLetter(partition->DriveLetter,
+ &setState,
+ &numberOfMembers);
+
+ // If the numberOfMembers gets set to 1 then
+ // this letter is not the letter for the FT set,
+ // but rather a default letter assigned because the
+ // FT sets letter could not be assigned.
+
+ if (numberOfMembers > 1) {
+ PERSISTENT_DATA(regionDescriptor)->DriveLetter = partition->DriveLetter;
+ }
+ } else {
+
+ // There is no region for this partition
+ // so update the set state.
+
+ ftObject->State = Orphaned;
+ }
+
+ // Now place the ft object in the correct set,
+ // creating the set if necessary.
+
+ AddObjectToSet(ftObject, partition->FtType, partition->FtGroup);
+ MaintainOrdinalTables(partition->FtType, (ULONG) partition->FtGroup);
+ }
+ }
+
+ diskDescription = (PDISK_DESCRIPTION)&diskDescription->Partitions[diskDescription->NumberOfPartitions];
+ }
+ Free(diskRegistry);
+
+ // Check to see if every disk found by the fdisk back end has a
+ // corresponding registry entry.
+
+ for (disk = 0; disk < DiskCount; disk++) {
+
+ if (Disks[disk]->OffLine) {
+ continue;
+ }
+
+ if ((!DiskHadRegistryEntry[disk]) && (!IsRemovable(disk))) {
+
+ // a real disk does not have a matching registry entry.
+
+ FDLOG((1,"InitializeFt: Disk %u does not have a registry entry (disk sig = %08lx)\n",disk,Disks[disk]->Signature));
+ configExtraDisk = TRUE;
+ }
+ }
+
+ // Determine whether any disks are off line
+
+ anyDisksOffLine = FALSE;
+ for (disk = 0; disk < DiskCount; disk++) {
+ if (Disks[disk]->OffLine) {
+ anyDisksOffLine = TRUE;
+ break;
+ }
+ }
+
+ if (configMissingDisk || anyDisksOffLine) {
+ WarningDialog(MSG_CONFIG_MISSING_DISK);
+ }
+ if (configDiskChanged) {
+ RegistryChanged = TRUE;
+ WarningDialog(MSG_CONFIG_DISK_CHANGED);
+ }
+ if (configExtraDisk || DiskSignaturesCreated) {
+
+ BOOL BadConfigSet = FALSE;
+
+ WarningDialog(MSG_CONFIG_EXTRA_DISK);
+
+ // Update ft signature on each disk for which a new signature
+ // was created. and update registry for each disk with
+ // DiskHadRegistryEntry[Disk] == 0.
+
+ for (disk = 0; disk < DiskCount; disk++) {
+ BOOL b1 = TRUE,
+ b2 = TRUE;
+
+ if (Disks[disk]->OffLine) {
+ continue;
+ }
+
+ wsprintf(name, DiskN, disk);
+ if (Disks[disk]->SigWasCreated) {
+ if (ConfirmationDialog(MSG_NO_SIGNATURE, MB_ICONEXCLAMATION | MB_YESNO, name) == IDYES) {
+ b1 = (MasterBootCode(disk, Disks[disk]->Signature, TRUE, TRUE) == NO_ERROR);
+ } else {
+ Disks[disk]->OffLine = TRUE;
+ continue;
+ }
+ }
+
+ if (!DiskHadRegistryEntry[disk]) {
+ ULONG size;
+
+ size = FdpDetermineDiskDescriptionSize(Disks[disk]);
+
+ diskDescription = Malloc(size);
+ FdpConstructDiskDescription(Disks[disk], diskDescription);
+
+ FDLOG((2,"InitializeFt: Adding new disk %08lx to registry.\n", diskDescription->Signature));
+ LOG_ONE_DISK_REGISTRY_DISK_ENTRY("InitializeFt", diskDescription);
+
+ b2 = (EC(DiskRegistryAddNewDisk(diskDescription)) == NO_ERROR);
+ Free(diskDescription);
+ }
+
+ if (!(b1 && b2)) {
+ BadConfigSet = TRUE;
+ }
+ }
+
+ if (BadConfigSet) {
+ ErrorDialog(MSG_BAD_CONFIG_SET);
+ }
+ }
+
+ return NO_ERROR;
+}
+
+BOOLEAN
+NewConfigurationRequiresFt(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Search the diskstate and region arrays to determine if a single
+ FtDisk element (i.e. stripe, stripe set with parity, mirror or
+ volume set) is contained in the configuration.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ TRUE if the new configuration requires the FtDisk driver.
+ FALSE otherwise.
+
+--*/
+
+{
+ ULONG disk,
+ region;
+ PDISKSTATE diskState;
+ PREGION_DESCRIPTOR regionDescriptor;
+
+ // Look at all disks in the system.
+
+ for (disk = 0; disk < DiskCount; disk++) {
+
+ diskState = Disks[disk];
+ if (diskState->OffLine || IsDiskRemovable[disk]) {
+ continue;
+ }
+
+ // Check each region on the disk.
+
+ for (region = 0; region < diskState->RegionCount; region++) {
+
+ regionDescriptor = &diskState->RegionArray[region];
+ if ((regionDescriptor->SysID != SYSID_UNUSED) && !IsExtended(regionDescriptor->SysID) && IsRecognizedPartition(regionDescriptor->SysID)) {
+
+ // If a single region has an FT Object, then FT
+ // is required and the search may be stopped.
+
+ if (GET_FT_OBJECT(regionDescriptor)) {
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ // no FtObject was found.
+
+ return FALSE;
+}
+
+ULONG
+SaveFt(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine walks all of the internal structures and creates
+ the interface structure for the DiskRegistry interface.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ success/failure code. NO_ERROR is success.
+
+--*/
+
+{
+ ULONG i;
+ ULONG disk,
+ partition;
+ ULONG size;
+ PDISK_REGISTRY diskRegistry;
+ PDISK_DESCRIPTION diskDescription;
+ PBYTE start,
+ end;
+ DWORD ec;
+ ULONG offLineDiskCount;
+ ULONG removableDiskCount;
+
+ // First count partitions and disks so we can allocate a structure
+ // of the correct size.
+
+ size = sizeof(DISK_REGISTRY) - sizeof(DISK_DESCRIPTION);
+ offLineDiskCount = 0;
+ removableDiskCount = 0;
+
+ for (i=0; i<DiskCount; i++) {
+
+ if (Disks[i]->OffLine) {
+ offLineDiskCount++;
+ } else if (IsDiskRemovable[i]) {
+ removableDiskCount++;
+ } else {
+ size += FdpDetermineDiskDescriptionSize(Disks[i]);
+ }
+ }
+
+ // Account for remembered disks.
+
+ size += RememberedDiskCount * sizeof(DISK_DESCRIPTION);
+ for (i=0; i<RememberedDiskCount; i++) {
+ if (RememberedDisks[i]->NumberOfPartitions > 1) {
+ size += (RememberedDisks[i]->NumberOfPartitions - 1) * sizeof(DISK_PARTITION);
+ }
+ }
+
+ diskRegistry = Malloc(size);
+ diskRegistry->NumberOfDisks = (USHORT)( DiskCount
+ + RememberedDiskCount
+ - offLineDiskCount
+ - removableDiskCount);
+ diskRegistry->ReservedShort = 0;
+ diskDescription = diskRegistry->Disks;
+ for (disk=0; disk<DiskCount; disk++) {
+
+ if (Disks[disk]->OffLine || IsDiskRemovable[disk]) {
+ continue;
+ }
+
+ partition = FdpConstructDiskDescription(Disks[disk], diskDescription);
+
+ diskDescription = (PDISK_DESCRIPTION)&diskDescription->Partitions[partition];
+ }
+
+ // Toss in remembered disks.
+
+ for (i=0; i<RememberedDiskCount; i++) {
+
+ // Compute the beginning and end of this remembered disk's
+ // Disk Description:
+
+ partition = RememberedDisks[i]->NumberOfPartitions;
+ start = (PBYTE)RememberedDisks[i];
+ end = (PBYTE)&(RememberedDisks[i]->Partitions[partition]);
+
+ RtlMoveMemory(diskDescription, RememberedDisks[i], end - start);
+ diskDescription = (PDISK_DESCRIPTION)&diskDescription->Partitions[partition];
+ }
+
+ LOG_DISK_REGISTRY("SaveFt", diskRegistry);
+
+ ec = EC(DiskRegistrySet(diskRegistry));
+ Free(diskRegistry);
+
+ if (ec == NO_ERROR) {
+ FdpInitializeMirrors();
+ }
+
+ return(ec);
+}
+
+
+ULONG
+FdpDetermineDiskDescriptionSize(
+ PDISKSTATE DiskState
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes a pointer to a disk and determines how much
+ memory is needed to contain the description of the disk by
+ counting the number of partitions on the disk and multiplying
+ the appropriate counts by the appropriate size of the structures.
+
+Arguments:
+
+ DiskState - the disk in question.
+
+Return Value:
+
+ The memory size needed to contain all of the information on the disk.
+
+--*/
+
+{
+ ULONG partitionCount;
+ ULONG size;
+
+ if (DiskState->OffLine) {
+ return(0);
+ }
+
+ size = sizeof(DISK_DESCRIPTION);
+ partitionCount = ActualPartitionCount(DiskState);
+ size += (partitionCount ? partitionCount-1 : 0) * sizeof(DISK_PARTITION);
+
+ return(size);
+}
+
+
+ULONG
+FdpConstructDiskDescription(
+ IN PDISKSTATE DiskState,
+ OUT PDISK_DESCRIPTION DiskDescription
+ )
+
+/*++
+
+Routine Description:
+
+ Given a disk state pointer as input, construct the FtRegistry
+ structure to describe the partitions on the disk.
+
+Arguments:
+
+ DiskState - the disk for which to construct the information
+ DiskDescription - the memory location where the registry
+ structure is to be created.
+
+Return Value:
+
+ The number of partitions described in the DiskDescription.
+
+--*/
+
+{
+ PDISKSTATE ds = DiskState;
+ ULONG partition,
+ region;
+ PREGION_DESCRIPTOR regionDescriptor;
+ PDISK_PARTITION diskPartition;
+ CHAR driveLetter;
+ BOOLEAN assignDriveLetter;
+ PFT_OBJECT ftObject;
+ PFT_OBJECT_SET ftSet;
+
+ partition = 0;
+
+ for (region=0; region<ds->RegionCount; region++) {
+
+ regionDescriptor = &ds->RegionArray[region];
+
+ if ((regionDescriptor->SysID != SYSID_UNUSED) && !IsExtended(regionDescriptor->SysID) && IsRecognizedPartition(regionDescriptor->SysID)) {
+
+ diskPartition = &DiskDescription->Partitions[partition++];
+
+ diskPartition->StartingOffset = FdGetExactOffset(regionDescriptor);
+ diskPartition->Length = FdGetExactSize(regionDescriptor, FALSE);
+ diskPartition->LogicalNumber = (USHORT)regionDescriptor->PartitionNumber;
+
+ switch (driveLetter = PERSISTENT_DATA(regionDescriptor)->DriveLetter) {
+ case NO_DRIVE_LETTER_YET:
+ assignDriveLetter = TRUE;
+ driveLetter = 0;
+ break;
+ case NO_DRIVE_LETTER_EVER:
+ assignDriveLetter = FALSE;
+ driveLetter = 0;
+ break;
+ default:
+ assignDriveLetter = TRUE;
+ break;
+ }
+
+ diskPartition->DriveLetter = driveLetter;
+ diskPartition->FtLength.LowPart = 0;
+ diskPartition->FtLength.HighPart = 0;
+ diskPartition->ReservedTwoLongs[0] = 0;
+ diskPartition->ReservedTwoLongs[1] = 0;
+ diskPartition->Modified = TRUE;
+
+ if (ftObject = GET_FT_OBJECT(regionDescriptor)) {
+ PREGION_DESCRIPTOR tmpDescriptor;
+
+ ftSet = ftObject->Set;
+
+ tmpDescriptor = LocateRegionForFtObject(ftSet->Member0);
+
+ // Only update status if member zero is present.
+ // otherwise the status is know to be Orphaned or
+ // needs regeneration.
+#if 0
+
+// need to do something here, but currently this does not work.
+
+ if (tmpDescriptor) {
+ ULONG numberOfMembers;
+ FT_SET_STATUS setState;
+ STATUS_CODE status;
+
+ // If the partition number is zero, then this set
+ // has not been committed to the disk yet. Only
+ // update status for existing sets.
+
+ if ((tmpDescriptor->PartitionNumber) &&
+ (ftSet->Status != FtSetNew) &&
+ (ftSet->Status != FtSetNewNeedsInitialization)) {
+ status = LowFtVolumeStatus(tmpDescriptor->Disk,
+ tmpDescriptor->PartitionNumber,
+ &setState,
+ &numberOfMembers);
+ if (status == OK_STATUS) {
+ if (ftSet->Status != setState) {
+
+ // Problem here - the FT driver has
+ // updated the status of the set after
+ // windisk last got the status. Need
+ // to restart the process of building
+ // the FT information after updating
+ // the set to the new state.
+
+ FdftUpdateFtObjectSet(ftSet, setState);
+
+ // now recurse and start over
+
+ status =
+ FdpConstructDiskDescription(DiskState,
+ DiskDescription);
+ return status;
+ }
+ }
+ }
+ }
+#endif
+ diskPartition->FtState = ftObject->State;
+ diskPartition->FtType = ftSet->Type;
+ diskPartition->FtGroup = (USHORT)ftSet->Ordinal;
+ diskPartition->FtMember = (USHORT)ftObject->MemberIndex;
+ if (assignDriveLetter && (ftObject == ftObject->Set->Member0)) {
+ diskPartition->AssignDriveLetter = TRUE;
+ } else {
+ diskPartition->AssignDriveLetter = FALSE;
+ }
+
+ } else {
+
+ diskPartition->FtState = Healthy;
+ diskPartition->FtType = NotAnFtMember;
+ diskPartition->FtGroup = (USHORT)(-1);
+ diskPartition->FtMember = 0;
+ diskPartition->AssignDriveLetter = assignDriveLetter;
+ }
+ }
+ }
+
+ DiskDescription->NumberOfPartitions = (USHORT)partition;
+ DiskDescription->Signature = ds->Signature;
+ DiskDescription->ReservedShort = 0;
+ return(partition);
+}
+
+
+VOID
+FdpRememberDisk(
+ IN PDISK_DESCRIPTION DiskDescription
+ )
+
+/*++
+
+Routine Description:
+
+ Make a copy of a registry disk description structure for later use.
+
+Arguments:
+
+ DiskDescription - supplies pointer to the registry descriptor for
+ the disk in question.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDISK_DESCRIPTION diskDescription;
+ ULONG Size;
+
+ // Only bother remembering disks with at least one partition.
+
+ if (DiskDescription->NumberOfPartitions == 0) {
+
+ return;
+ }
+
+ // Compute the size of the structure
+
+ Size = sizeof(DISK_DESCRIPTION);
+ if (DiskDescription->NumberOfPartitions > 1) {
+ Size += (DiskDescription->NumberOfPartitions - 1) * sizeof(DISK_PARTITION);
+ }
+
+ diskDescription = Malloc(Size);
+ RtlMoveMemory(diskDescription, DiskDescription, Size);
+
+ RememberedDisks = Realloc(RememberedDisks,
+ (RememberedDiskCount + 1) * sizeof(PDISK_DESCRIPTION));
+ RememberedDisks[RememberedDiskCount++] = diskDescription;
+
+ FDLOG((2,
+ "FdpRememberDisk: remembered disk %08lx, remembered count = %u\n",
+ diskDescription->Signature,
+ RememberedDiskCount));
+}
+
+
+VOID
+FdpInitializeMirrors(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ For each existing partition that was mirrored by the user during this Disk Manager
+ session, call the FT driver to register initialization of the mirror (ie, cause
+ the primary to be copied to the secondary). Perform a similar initialization for
+ each stripe set with parity created by the user.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PFT_OBJECT_SET ftSet;
+ PFT_OBJECT ftMember;
+
+ // Look through the list of FT sets for mirrored pairs and parity stripes
+
+ for (ftSet = FtObjects; ftSet; ftSet = ftSet->Next) {
+
+ // If the set needs initialization, or was recovered,
+ // call the FT driver.
+
+ switch (ftSet->Status) {
+
+ case FtSetNewNeedsInitialization:
+
+ DiskRegistryInitializeSet((USHORT)ftSet->Type,
+ (USHORT)ftSet->Ordinal);
+ ftSet->Status = FtSetInitializing;
+ break;
+
+ case FtSetRecovered:
+
+ // Find the member that needs to be addressed.
+
+ for (ftMember=ftSet->Members; ftMember; ftMember=ftMember->Next) {
+ if (ftMember->State == Regenerating) {
+ break;
+ }
+ }
+
+ DiskRegistryRegenerateSet((USHORT)ftSet->Type,
+ (USHORT)ftSet->Ordinal,
+ (USHORT)ftMember->MemberIndex);
+ ftSet->Status = FtSetRegenerating;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
diff --git a/private/utils/fdisk/fdft.h b/private/utils/fdisk/fdft.h
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/private/utils/fdisk/fdft.h
diff --git a/private/utils/fdisk/fdglob.h b/private/utils/fdisk/fdglob.h
new file mode 100644
index 000000000..489b72be6
--- /dev/null
+++ b/private/utils/fdisk/fdglob.h
@@ -0,0 +1,135 @@
+/*++
+
+Copyright (c) 1990-1993 Microsoft Corporation
+
+Module Name:
+
+ fdglob.h
+
+Abstract:
+
+ Global data
+
+Author:
+
+ Ted Miller (tedm) 7-Jan-1992
+
+Revisions:
+
+ 11-Nov-93 (bobri) double space and commit support.
+
+--*/
+
+// from fddata.c
+
+extern HANDLE hModule;
+extern PBOOLEAN IsDiskRemovable;
+extern PCHAR RemovableDiskReservedDriveLetters;
+extern PDISKSTATE *Disks;
+extern ULONG BootDiskNumber;
+extern ULONG BootPartitionNumber;
+extern HANDLE hwndFrame,
+ hwndList;
+
+extern HBITMAP hBitmapSmallDisk;
+extern HBITMAP hBitmapRemovableDisk;
+extern HDC hDC;
+extern HFONT hFontGraph,
+ hFontGraphBold;
+extern HBRUSH Brushes[BRUSH_ARRAY_SIZE];
+extern HBRUSH hBrushFreeLogical,
+ hBrushFreePrimary;
+extern HPEN hPenNull,
+ hPenThinSolid;
+extern HCURSOR hcurWait,
+ hcurNormal;
+
+extern int BrushHatches[BRUSH_ARRAY_SIZE];
+extern int BrushColors[BRUSH_ARRAY_SIZE];
+
+extern COLORREF AvailableColors[NUM_AVAILABLE_COLORS];
+extern int AvailableHatches[NUM_AVAILABLE_HATCHES];
+
+extern DWORD GraphWidth,
+ GraphHeight;
+extern DWORD BarTopYOffset,
+ BarBottomYOffset,
+ BarHeight;
+extern DWORD dxDriveLetterStatusArea;
+extern DWORD dxBarTextMargin,
+ dyBarTextLine;
+extern DWORD dxSmallDisk,
+ dySmallDisk,
+ xSmallDisk,
+ ySmallDisk;
+extern DWORD dxRemovableDisk,
+ dyRemovableDisk,
+ xRemovableDisk,
+ yRemovableDisk;
+extern DWORD BarLeftX,BarWidth;
+
+extern PDISKSTATE SingleSel;
+extern DWORD SingleSelIndex;
+
+extern TCHAR WinHelpFile[];
+extern TCHAR LanmanHelpFile[];
+extern PTCHAR HelpFile;
+
+extern unsigned DiskCount;
+
+extern TCHAR szFrame[];
+extern LPTSTR DiskN;
+extern PWSTR wszUnformatted,
+ wszNewUnformatted,
+ wszUnknown;
+
+extern BOOL RegistryChanged;
+extern BOOL RestartRequired;
+
+extern BOOL ConfigurationSearchIdleTrigger;
+extern BOOL IsLanmanNt;
+extern BOOL IsFullDoubleSpace;
+
+// from fdstleg.c
+
+extern HFONT hFontStatus,
+ hFontLegend;
+extern DWORD dyLegend,
+ wLegendItem;
+extern DWORD dyStatus,
+ dyBorder;
+extern TCHAR *LegendLabels[LEGEND_STRING_COUNT];
+extern BOOL StatusBar,
+ Legend;
+extern TCHAR StatusTextStat[STATUS_TEXT_SIZE];
+extern TCHAR StatusTextSize[STATUS_TEXT_SIZE];
+extern WCHAR StatusTextDrlt[3];
+extern WCHAR StatusTextType[STATUS_TEXT_SIZE];
+extern WCHAR StatusTextVoll[STATUS_TEXT_SIZE];
+
+// from fdlistbx.c
+
+extern DWORD LBCursorListBoxItem,
+ LBCursorRegion;
+
+// from fdprof.c
+
+extern int ProfileWindowX,
+ ProfileWindowY,
+ ProfileWindowW,
+ ProfileWindowH;
+extern BOOL ProfileIsMaximized,
+ ProfileIsIconic;
+
+// from fddlgs.c
+
+extern DWORD SelectedColor[LEGEND_STRING_COUNT];
+extern DWORD SelectedHatch[LEGEND_STRING_COUNT];
+
+// from fdft.c
+
+extern PFT_OBJECT_SET FtObjects;
+
+// For CdRoms
+
+extern ULONG AllowCdRom;
diff --git a/private/utils/fdisk/fdhelp.c b/private/utils/fdisk/fdhelp.c
new file mode 100644
index 000000000..626871bdb
--- /dev/null
+++ b/private/utils/fdisk/fdhelp.c
@@ -0,0 +1,232 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ fdhelp.c
+
+Abstract:
+
+ Routines to support context-sensitive help in the disk manager.
+
+Author:
+
+ Ted Miller (tedm) 18-March-1992
+
+Revision History:
+
+--*/
+
+
+#include "fdisk.h"
+
+
+//
+// Define macro to convert between a menu id and its corresponding
+// context-sensitive help id, in a switch statement.
+//
+
+#define MENUID_TO_HELPID(name) case IDM_##name : \
+ HelpContext = HC_DM_MENU_##name; \
+ break;
+
+
+//
+// Current help context
+//
+
+DWORD HelpContext = (DWORD)(-1);
+
+
+//
+// Handle to windows hook for F1 key
+//
+HHOOK hHook;
+
+
+
+DWORD
+HookProc(
+ IN int nCode,
+ IN UINT wParam,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Hook proc to detect F1 key presses.
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ PMSG pmsg = (PMSG)lParam;
+
+ if(nCode < 0) {
+ return(CallNextHookEx(hHook,nCode,wParam,lParam));
+ }
+
+ if(((nCode == MSGF_DIALOGBOX) || (nCode == MSGF_MENU))
+ && (pmsg->message == WM_KEYDOWN)
+ && (LOWORD(pmsg->wParam) == VK_F1))
+ {
+ PostMessage(hwndFrame,WM_F1DOWN,nCode,0);
+ return(TRUE);
+ }
+
+ return(FALSE);
+}
+
+
+
+VOID
+Help(
+ IN LONG Code
+ )
+
+/*++
+
+Routine Description:
+
+ Display context-sensitive help.
+
+Arguments:
+
+ Code - supplies type of message (MSGF_DIALOGBOX, MSGF_MENU, etc).
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(Code);
+
+ if(HelpContext != -1) {
+ WinHelp(hwndFrame,HelpFile,HELP_CONTEXT,HelpContext);
+ DrawMenuBar(hwndFrame);
+ }
+}
+
+VOID
+DialogHelp(
+ IN DWORD HelpId
+ )
+/*++
+
+Routine Description:
+
+ Display help on a specific item.
+
+Arguments:
+
+ HelpId -- Supplies the help item to display.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ WinHelp(hwndFrame,HelpFile,HELP_CONTEXT,HelpId);
+ DrawMenuBar(hwndFrame);
+}
+
+VOID
+SetMenuItemHelpContext(
+ IN LONG wParam,
+ IN DWORD lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Routine to set help context based on which menu item is currently
+ selected.
+
+Arguments:
+
+ wParam,lParam - params to window proc in WM_MENUSELECT case
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if(HIWORD(lParam) == 0) { // menu closed
+
+ HelpContext = (DWORD)(-1);
+
+ } else if (HIWORD(wParam) & MF_POPUP) { // popup selected
+
+ HelpContext = (DWORD)(-1);
+
+ } else { // regular old menu item
+ switch(LOWORD(wParam)) {
+
+ MENUID_TO_HELPID(PARTITIONCREATE)
+ MENUID_TO_HELPID(PARTITIONCREATEEX)
+ MENUID_TO_HELPID(PARTITIONDELETE)
+#if i386
+ MENUID_TO_HELPID(PARTITIONACTIVE)
+#else
+ MENUID_TO_HELPID(SECURESYSTEM)
+#endif
+ MENUID_TO_HELPID(PARTITIONLETTER)
+ MENUID_TO_HELPID(PARTITIONEXIT)
+
+ MENUID_TO_HELPID(CONFIGMIGRATE)
+ MENUID_TO_HELPID(CONFIGSAVE)
+ MENUID_TO_HELPID(CONFIGRESTORE)
+
+ MENUID_TO_HELPID(FTESTABLISHMIRROR)
+ MENUID_TO_HELPID(FTBREAKMIRROR)
+ MENUID_TO_HELPID(FTCREATESTRIPE)
+ MENUID_TO_HELPID(FTCREATEPSTRIPE)
+ MENUID_TO_HELPID(FTCREATEVOLUMESET)
+ MENUID_TO_HELPID(FTEXTENDVOLUMESET)
+ MENUID_TO_HELPID(FTRECOVERSTRIPE)
+
+ MENUID_TO_HELPID(OPTIONSSTATUS)
+ MENUID_TO_HELPID(OPTIONSLEGEND)
+ MENUID_TO_HELPID(OPTIONSCOLORS)
+ MENUID_TO_HELPID(OPTIONSDISPLAY)
+
+ MENUID_TO_HELPID(HELPCONTENTS)
+ MENUID_TO_HELPID(HELPSEARCH)
+ MENUID_TO_HELPID(HELPHELP)
+ MENUID_TO_HELPID(HELPABOUT)
+
+ default:
+ HelpContext = (DWORD)(-1);
+ }
+ }
+}
+
+
+VOID
+InitHelp(
+ VOID
+ )
+{
+ hHook = SetWindowsHookEx(WH_MSGFILTER,(HOOKPROC)HookProc,NULL,GetCurrentThreadId());
+}
+
+
+VOID
+TermHelp(
+ VOID
+ )
+{
+ UnhookWindowsHookEx(hHook);
+}
diff --git a/private/utils/fdisk/fdhelpid.h b/private/utils/fdisk/fdhelpid.h
new file mode 100644
index 000000000..c22507a29
--- /dev/null
+++ b/private/utils/fdisk/fdhelpid.h
@@ -0,0 +1,178 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ fdhelpid.h
+
+Abstract:
+
+ Context ids for context-sensitive help for the disk manager
+
+Author:
+
+ Ted Miller (tedm) 18-March-1992
+
+Revision History:
+
+--*/
+
+
+//
+// All ids in this file start with HC_DM, as in "Help Context for Disk Manager"
+//
+
+//
+// Menu items. In the form HC_DM_MENU_xxx, where xxx matches the name used
+// in the resource file (fdisk.rc) for the menu item (of the form IDM_xxx).
+//
+
+//
+// The partition menu
+//
+
+#define HC_DM_MENU_PARTITIONCREATE 110
+#define HC_DM_MENU_PARTITIONCREATEEX 111
+#define HC_DM_MENU_PARTITIONDELETE 112
+#define HC_DM_MENU_FTCREATEVOLUMESET 113
+#define HC_DM_MENU_FTEXTENDVOLUMESET 114
+#define HC_DM_MENU_FTCREATESTRIPE 115
+#if i386
+#define HC_DM_MENU_PARTITIONACTIVE 116
+#endif
+#define HC_DM_MENU_PARTITIONLETTER 117 // really in tools menu
+#define HC_DM_MENU_PARTITIONEXIT 118
+#define HC_DM_MENU_SECURESYSTEM 119
+#define HC_DM_MENU_COMMIT 120
+
+//
+// The configuration menu
+//
+
+#define HC_DM_MENU_CONFIGMIGRATE 210
+#define HC_DM_MENU_CONFIGSAVE 211
+#define HC_DM_MENU_CONFIGRESTORE 212
+#define HC_DM_MENU_CONFIG 213
+
+//
+// The fault tolerance menu
+//
+
+#define HC_DM_MENU_FTESTABLISHMIRROR 310
+#define HC_DM_MENU_FTBREAKMIRROR 311
+#define HC_DM_MENU_FTCREATEPSTRIPE 312
+#define HC_DM_MENU_FTRECOVERSTRIPE 313
+
+//
+// The tools menu
+//
+
+#define HC_DM_MENU_AUTOMOUNT 610
+#define HC_DM_MENU_DBLSPACE 611
+#define HC_DM_MENU_CDROM 612
+#define HC_DM_MENU_FORMAT 613
+#define HC_DM_MENU_LABEL 614
+
+//
+// The options menu
+//
+
+#define HC_DM_MENU_OPTIONSSTATUS 410
+#define HC_DM_MENU_OPTIONSLEGEND 411
+#define HC_DM_MENU_OPTIONSCOLORS 412
+#define HC_DM_MENU_OPTIONSDISPLAY 413
+
+//
+// The help menu
+//
+
+#define HC_DM_MENU_HELPCONTENTS 510
+#define HC_DM_MENU_HELPSEARCH 511
+#define HC_DM_MENU_HELPHELP 512
+#define HC_DM_MENU_HELPABOUT 513
+
+
+//
+// The system menu
+//
+
+#define HC_DM_SYSMENU_RESTORE 910
+#define HC_DM_SYSMENU_MOVE 911
+#define HC_DM_SYSMENU_SIZE 912
+#define HC_DM_SYSMENU_MINIMIZE 913
+#define HC_DM_SYSMENU_MAXIMIZE 914
+#define HC_DM_SYSMENU_CLOSE 915
+#define HC_DM_SYSMENU_SWITCHTO 916
+
+//
+// Dialog boxes. In the form HC_DM_DLG_xxx, where xxx is some reasonably
+// descriptive name for the dialog.
+//
+//
+// These dialog boxes do not have help buttons:
+//
+// - About
+// - Searching for Previous Installation
+// - Confirmation dialogs
+
+//
+// Min/Max dialogs for creating various items
+//
+
+#define HC_DM_DLG_CREATEPRIMARY 1010
+#define HC_DM_DLG_CREATEEXTENDED 1011
+#define HC_DM_DLG_CREATELOGICAL 1012
+#define HC_DM_DLG_CREATEVOLUMESET 1013
+#define HC_DM_DLG_EXTENDVOLUMESET 1014
+#define HC_DM_DLG_CREATESTRIPESET 1015
+#define HC_DM_DLG_CREATEPARITYSTRIPE 1016
+
+//
+// Dialog for assigning drive letters
+//
+
+#define HC_DM_DLG_DRIVELETTER 1020
+
+//
+// Dialog for determining display sizing
+//
+
+#define HC_DM_DLG_DISPLAYOPTION 1030
+
+//
+// Configuration migration dialog to select previous installation
+//
+
+#define HC_DM_DLG_SELECTINSTALLATION 1040
+
+//
+// Colors and patterns dialog
+//
+
+#define HC_DM_COLORSANDPATTERNS 1050
+
+//
+// DoubleSpace dialog
+//
+
+#define HC_DM_DLG_DOUBLESPACE 1060
+#define HC_DM_DLG_DOUBLESPACE_MOUNT 1061
+
+//
+// Format dialog
+//
+
+#define HC_DM_DLG_FORMAT 1070
+
+//
+// Label dialog
+//
+
+#define HC_DM_DLG_LABEL 1080
+
+//
+// CdRom dialog
+//
+
+#define HC_DM_DLG_CDROM 1090
diff --git a/private/utils/fdisk/fdinit.c b/private/utils/fdisk/fdinit.c
new file mode 100644
index 000000000..0862505de
--- /dev/null
+++ b/private/utils/fdisk/fdinit.c
@@ -0,0 +1,533 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ fdinit.c
+
+Abstract:
+
+ Code for initializing the fdisk application.
+
+Author:
+
+ Ted Miller (tedm) 7-Jan-1992
+
+--*/
+
+#include "fdisk.h"
+
+HWND InitDlg;
+BOOLEAN StartedAsIcon = FALSE;
+BOOLEAN InitDlgComplete = FALSE;
+
+BOOL
+InitializeApp(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the fdisk app. This includes registering
+ the frame window class and creating the frame window.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ boolean value indicating success or failure.
+
+--*/
+
+{
+ WNDCLASS wc;
+ TCHAR szTitle[80];
+ DWORD ec;
+ HDC hdcScreen = GetDC(NULL);
+ TEXTMETRIC tm;
+ BITMAP bitmap;
+ HFONT hfontT;
+ unsigned i;
+
+ ReadProfile();
+
+ // Load cursors
+
+ hcurWait = LoadCursor(NULL, MAKEINTRESOURCE(IDC_WAIT));
+ hcurNormal = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
+
+ // fonts
+
+#ifdef JAPAN
+ hFontGraph = CreateFont(GetHeightFromPoints(10), 0,
+ 0, 0, 400, FALSE, FALSE, FALSE, SHIFTJIS_CHARSET,
+ OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+ DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
+ TEXT("System")
+ );
+#else
+ hFontGraph = CreateFont(GetHeightFromPoints(8), 0,
+ 0, 0, 400, FALSE, FALSE, FALSE, ANSI_CHARSET,
+ OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+ DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
+ TEXT("Helv"));
+#endif
+
+ hFontLegend = hFontGraph;
+ hFontStatus = hFontGraph;
+
+#ifdef JAPAN
+ hFontGraphBold = CreateFont(GetHeightFromPoints(10), 0,
+ 0, 0, 700, FALSE, FALSE, FALSE,
+ SHIFTJIS_CHARSET, OUT_DEFAULT_PRECIS,
+ CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
+ VARIABLE_PITCH | FF_SWISS, TEXT("System")
+ );
+#else
+ hFontGraphBold = CreateFont(GetHeightFromPoints(8), 0,
+ 0, 0, 700, FALSE, FALSE, FALSE, ANSI_CHARSET,
+ OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
+ DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
+ TEXT("Helv"));
+#endif
+
+ hfontT = SelectObject(hdcScreen, hFontGraph);
+ GetTextMetrics(hdcScreen, &tm);
+ if (hfontT) {
+ SelectObject(hdcScreen, hfontT);
+ }
+
+ hPenNull = CreatePen(PS_NULL, 0, 0);
+ hPenThinSolid = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
+
+ GraphWidth = (DWORD)GetSystemMetrics(SM_CXSCREEN);
+ GraphHeight = 25 * tm.tmHeight / 4; // 6.25 x font height
+
+ // set up the legend off-screen bitmap
+
+ wLegendItem = GetSystemMetrics(SM_CXHTHUMB);
+ dyLegend = 2 * wLegendItem; // 7*wLegendItem/2 for a double-height legend
+
+ ReleaseDC(NULL, hdcScreen);
+
+ dyBorder = GetSystemMetrics(SM_CYBORDER);
+ dyStatus = tm.tmHeight + tm.tmExternalLeading + 7 * dyBorder;
+
+ // set up brushes
+
+ for (i=0; i<BRUSH_ARRAY_SIZE; i++) {
+ Brushes[i] = CreateHatchBrush(AvailableHatches[BrushHatches[i]], AvailableColors[BrushColors[i]]);
+ }
+
+ hBrushFreeLogical = CreateHatchBrush(HS_FDIAGONAL, RGB(128, 128, 128));
+ hBrushFreePrimary = CreateHatchBrush(HS_BDIAGONAL, RGB(128, 128, 128));
+
+ // load legend strings
+
+ for (i=IDS_LEGEND_FIRST; i<=IDS_LEGEND_LAST; i++) {
+ if (!(LegendLabels[i-IDS_LEGEND_FIRST] = LoadAString(i))) {
+ return FALSE;
+ }
+ }
+
+ if (((wszUnformatted = LoadWString(IDS_UNFORMATTED)) == NULL)
+ || ((wszNewUnformatted = LoadWString(IDS_NEW_UNFORMATTED)) == NULL)
+ || ((wszUnknown = LoadWString(IDS_UNKNOWN )) == NULL)) {
+ return FALSE;
+ }
+
+ // register the frame class
+
+ wc.style = CS_OWNDC | CS_VREDRAW;
+ wc.lpfnWndProc = MyFrameWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = hModule;
+ wc.hIcon = LoadIcon(hModule, MAKEINTRESOURCE(IDFDISK));
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = GetStockObject(LTGRAY_BRUSH);
+ wc.lpszMenuName = MAKEINTRESOURCE(IDFDISK);
+ wc.lpszClassName = szFrame;
+
+ if (!RegisterClass(&wc)) {
+ return FALSE;
+ }
+
+ if (!RegisterArrowClass(hModule)) {
+ return FALSE;
+ }
+
+ LoadString(hModule, IDS_APPNAME, szTitle, sizeof(szTitle)/sizeof(TCHAR));
+
+ // create the frame window. Note that this also creates the listbox.
+
+ hwndFrame = CreateWindow(szFrame,
+ szTitle,
+ WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
+ ProfileWindowX,
+ ProfileWindowY,
+ ProfileWindowW,
+ ProfileWindowH,
+ NULL,
+ NULL,
+ hModule,
+ NULL);
+ if (!hwndFrame) {
+ return FALSE;
+ }
+
+ if (!hwndList) {
+ DestroyWindow(hwndFrame);
+ return FALSE;
+ }
+
+ hDC = GetDC(hwndFrame);
+ BarTopYOffset = tm.tmHeight;
+ BarHeight = 21 * tm.tmHeight / 4;
+ BarBottomYOffset = BarTopYOffset + BarHeight;
+ dxBarTextMargin = 5*tm.tmAveCharWidth/4;
+ dyBarTextLine = tm.tmHeight;
+
+ dxDriveLetterStatusArea = 5 * tm.tmAveCharWidth / 2;
+
+ hBitmapSmallDisk = LoadBitmap(hModule, MAKEINTRESOURCE(IDB_SMALLDISK));
+ GetObject(hBitmapSmallDisk, sizeof(BITMAP), &bitmap);
+ dxSmallDisk = bitmap.bmWidth;
+ dySmallDisk = bitmap.bmHeight;
+ xSmallDisk = dxSmallDisk / 2;
+ ySmallDisk = BarTopYOffset + (2*dyBarTextLine) - dySmallDisk - tm.tmDescent;
+
+ hBitmapRemovableDisk = LoadBitmap(hModule, MAKEINTRESOURCE(IDB_REMOVABLE));
+ GetObject(hBitmapRemovableDisk, sizeof(BITMAP), &bitmap);
+ dxRemovableDisk = bitmap.bmWidth;
+ dyRemovableDisk = bitmap.bmHeight;
+ xRemovableDisk = dxRemovableDisk / 2;
+ yRemovableDisk = BarTopYOffset + (2*dyBarTextLine) - dyRemovableDisk - tm.tmDescent;
+
+
+ BarLeftX = 7 * dxSmallDisk;
+ BarWidth = GraphWidth - BarLeftX - (5 * tm.tmAveCharWidth);
+
+ DiskN = LoadAString(IDS_DISKN);
+
+ if ((ec = InitializeListBox(hwndList)) != NO_ERROR) {
+ DestroyWindow(hwndList);
+ DestroyWindow(hwndFrame);
+ return FALSE;
+ }
+
+ // initial list box selection cursor (don't allow to fall on
+ // extended partition).
+ LBCursorListBoxItem = 0;
+ ResetLBCursorRegion();
+
+ ShowWindow(hwndFrame,
+ ProfileIsIconic ? SW_SHOWMINIMIZED
+ : ProfileIsMaximized ? SW_SHOWMAXIMIZED : SW_SHOWDEFAULT);
+ UpdateWindow(hwndFrame);
+ return TRUE;
+}
+
+VOID
+CreateDiskState(
+ OUT PDISKSTATE *DiskState,
+ IN DWORD Disk,
+ OUT PBOOL SignatureCreated
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is designed to be called once, at initialization time,
+ per disk. It creates and initializes a disk state -- which includes
+ creating a memory DC and compatible bitmap for drawing the disk's
+ graph, and getting some information that is static in nature about
+ the disk (ie, its total size.)
+
+Arguments:
+
+ DiskState - structure whose fields are to be intialized
+
+ Disk - number of disk
+
+ SignatureCreated - received boolean indicating whether an FT signature was created for
+ the disk.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ HDC hDCMem;
+ PDISKSTATE pDiskState = Malloc(sizeof(DISKSTATE));
+
+
+ *DiskState = pDiskState;
+
+ pDiskState->LeftRight = Malloc(0);
+ pDiskState->Selected = Malloc(0);
+
+ pDiskState->Disk = Disk;
+
+ // create a memory DC for drawing the bar off-screen,
+ // and the correct bitmap
+
+#if 0
+ pDiskState->hDCMem = NULL;
+ pDiskState->hbmMem = NULL;
+ hDCMem = CreateCompatibleDC(hDC);
+#else
+ pDiskState->hDCMem = hDCMem = CreateCompatibleDC(hDC);
+ pDiskState->hbmMem = CreateCompatibleBitmap(hDC, GraphWidth, GraphHeight);
+#endif
+ SelectObject(hDCMem,pDiskState->hbmMem);
+
+
+ pDiskState->RegionArray = NULL;
+ pDiskState->RegionCount = 0;
+ pDiskState->BarType = BarAuto;
+ pDiskState->OffLine = IsDiskOffLine(Disk);
+
+ if (pDiskState->OffLine) {
+
+ pDiskState->SigWasCreated = FALSE;
+ pDiskState->Signature = 0;
+ pDiskState->DiskSizeMB = 0;
+ FDLOG((1, "CreateDiskState: Disk %u is off-line\n", Disk));
+ } else {
+
+ pDiskState->DiskSizeMB = DiskSizeMB(Disk);
+ if (pDiskState->Signature = FdGetDiskSignature(Disk)) {
+
+ if (SignatureIsUniqueToSystem(Disk, pDiskState->Signature)) {
+ pDiskState->SigWasCreated = FALSE;
+ FDLOG((2,
+ "CreateDiskState: Found signature %08lx on disk %u\n",
+ pDiskState->Signature,
+ Disk));
+ } else {
+ goto createSignature;
+ }
+ } else {
+
+createSignature:
+ pDiskState->Signature = FormDiskSignature();
+ FdSetDiskSignature(Disk, pDiskState->Signature);
+ pDiskState->SigWasCreated = TRUE;
+ FDLOG((1,
+ "CreateDiskState: No signature on disk %u; created signature %08lx\n",
+ Disk,
+ pDiskState->Signature));
+ }
+ }
+
+ *SignatureCreated = (BOOL)pDiskState->SigWasCreated;
+}
+
+BOOL
+InitializationDlgProc(
+ IN HWND hDlg,
+ IN UINT uMsg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ standard Windows dialog procedure
+
+Return Values:
+
+ standard Windows dialog procedure
+
+--*/
+
+{
+ static DWORD percentDrawn;
+ static RECT rectGG; // GasGauge rectangle
+ static BOOL captionIsLoaded;
+ static PFORMAT_PARAMS formatParams;
+ TCHAR title[100],
+ templateString[100];
+
+ switch (uMsg) {
+ case WM_INITDIALOG: {
+ HWND hwndGauge = GetDlgItem(hDlg, IDC_GASGAUGE);
+
+ InitDlg = hDlg;
+ percentDrawn = 0;
+ StartedAsIcon = IsIconic(hDlg);
+
+ // Get the coordinates of the gas gauge static control rectangle,
+ // and convert them to dialog client area coordinates
+
+ GetClientRect(hwndGauge, &rectGG);
+ ClientToScreen(hwndGauge, (LPPOINT)&rectGG.left);
+ ClientToScreen(hwndGauge, (LPPOINT)&rectGG.right);
+ ScreenToClient(hDlg, (LPPOINT)&rectGG.left);
+ ScreenToClient(hDlg, (LPPOINT)&rectGG.right);
+ return TRUE;
+ }
+
+ case WM_PAINT: {
+ INT width = rectGG.right - rectGG.left;
+ INT height = rectGG.bottom - rectGG.top;
+ INT nDivideRects;
+ HDC hDC;
+ PAINTSTRUCT ps;
+ TCHAR buffer[10];
+ SIZE size;
+ INT xText,
+ yText,
+ byteCount;
+ RECT rectDone,
+ rectLeftToDo;
+
+ hDC = BeginPaint(hDlg, &ps);
+ byteCount = wsprintf(buffer, TEXT("%3d%%"), percentDrawn);
+ GetTextExtentPoint(hDC, buffer, lstrlen(buffer), &size);
+ xText = rectGG.left + (width - size.cx) / 2;
+ yText = rectGG.top + (height - size.cy) / 2;
+
+ // Paint in the "done so far" rectangle of the gas
+ // gauge with blue background and white text
+
+ nDivideRects = (width * percentDrawn) / 100;
+ SetRect(&rectDone,
+ rectGG.left,
+ rectGG.top,
+ rectGG.left + nDivideRects,
+ rectGG.bottom);
+
+ SetTextColor(hDC, RGB(255, 255, 255));
+ SetBkColor(hDC, RGB(0, 0, 255));
+ ExtTextOut(hDC,
+ xText,
+ yText,
+ ETO_CLIPPED | ETO_OPAQUE,
+ &rectDone,
+ buffer,
+ byteCount/sizeof(TCHAR),
+ NULL);
+
+ // Paint in the "still left to do" rectangle of the gas
+ // gauge with white background and blue text
+
+ SetRect(&rectLeftToDo,
+ rectGG.left + nDivideRects,
+ rectGG.top,
+ rectGG.right,
+ rectGG.bottom);
+ SetBkColor(hDC, RGB(255, 255, 255));
+ SetTextColor(hDC, RGB(0, 0, 255));
+ ExtTextOut(hDC,
+ xText,
+ yText,
+ ETO_CLIPPED | ETO_OPAQUE,
+ &rectLeftToDo,
+ buffer,
+ byteCount/sizeof(TCHAR),
+ NULL);
+ EndPaint(hDlg, &ps);
+
+ if (percentDrawn == 100) {
+ InitDlgComplete = TRUE;
+ }
+ return TRUE;
+ }
+
+ case WM_USER:
+ percentDrawn = (INT)wParam;
+ InvalidateRect(hDlg, &rectGG, TRUE);
+ UpdateWindow(hDlg);
+ return TRUE;
+
+ case (WM_USER + 1):
+ EndDialog(hDlg, FALSE);
+ return TRUE;
+
+ default:
+
+ return FALSE;
+ }
+}
+
+VOID
+InitializationMessageThread(
+ PVOID ThreadParameter
+ )
+
+/*++
+
+Routine Description:
+
+ This is the entry for the initialization message thread. It creates
+ a dialog that simply tells the user to be patient.
+
+Arguments:
+
+ ThreadParameter - not used.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ DialogBoxParam(hModule,
+ MAKEINTRESOURCE(IDD_INITIALIZING),
+ hwndFrame,
+ (DLGPROC) InitializationDlgProc,
+ (ULONG) NULL);
+ InitDlg = (HWND) 0;
+ ExitThread(0L);
+}
+
+VOID
+DisplayInitializationMessage(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Create a 2nd thread to display an initialization message.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ HANDLE threadHandle;
+ DWORD threadId;
+
+ threadHandle = CreateThread(NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE) InitializationMessageThread,
+ (LPVOID) NULL,
+ (DWORD) 0,
+ (LPDWORD) &threadId);
+ if (!threadHandle) {
+ CloseHandle(threadHandle);
+ }
+}
diff --git a/private/utils/fdisk/fdisk.dlg b/private/utils/fdisk/fdisk.dlg
new file mode 100644
index 000000000..4129b33c8
--- /dev/null
+++ b/private/utils/fdisk/fdisk.dlg
@@ -0,0 +1,165 @@
+// 'about' dialog box
+
+IDD_ABOUT DIALOG LOADONCALL MOVEABLE DISCARDABLE 25,23,184,78
+FONT 8,"MS Shell Dlg"
+CAPTION "About Disk Administrator"
+STYLE WS_BORDER | DS_MODALFRAME | WS_CAPTION | WS_DLGFRAME | WS_POPUP | WS_SYSMENU
+BEGIN
+ CONTROL "Microsoft Windows NT",-1,"static",SS_CENTER | WS_GROUP | WS_CHILD,0,5 ,184,8
+ CONTROL "Disk Administrator",-1,"static",SS_CENTER | WS_GROUP | WS_CHILD,0,15,184,8
+ CONTROL "Version VERSION" ,-1,"Static",SS_CENTER | WS_GROUP | WS_CHILD,0,34,184,8
+ CONTROL "Copyright \251 1991 Microsoft Corp.",-1,"static",SS_CENTER | WS_GROUP | WS_CHILD,0,47,184,9
+ CONTROL "&OK",IDOK,"button",BS_DEFPUSHBUTTON | WS_GROUP | WS_TABSTOP | WS_CHILD,76,60,32,14
+ CONTROL IDFDISK,-1,"static",SS_ICON | WS_CHILD,25,14,16,21
+END
+
+IDD_MINMAX DIALOG LOADONCALL MOVEABLE DISCARDABLE 98, 82, 204, 131
+FONT 8,"MS Shell Dlg"
+CAPTION ""
+STYLE WS_BORDER | DS_MODALFRAME | WS_CAPTION | WS_DLGFRAME | WS_POPUP | WS_SYSMENU
+BEGIN
+ LTEXT "" ,IDC_MINMAX_MINLABEL,10 ,18 ,136,8
+ LTEXT "" ,IDC_MINMAX_MAXLABEL,10 ,30 ,136,8
+ LTEXT "" ,IDC_MINMAX_SIZLABEL,10 ,54 ,136,8
+ LTEXT "MB" ,-1 ,185,18 ,11 ,8
+ LTEXT "MB" ,-1 ,185,30 ,11 ,8
+ LTEXT "MB" ,-1 ,185,54 ,11 ,8
+ RTEXT "" ,IDC_MINMAX_MIN ,148,18 ,32 ,8
+ RTEXT "" ,IDC_MINMAX_MAX ,148,30 ,32 ,8
+ EDITTEXT IDC_MINMAX_SIZE ,150,52 ,25 ,12,ES_AUTOHSCROLL
+ CONTROL "",IDC_MINMAX_SCROLL,"cpArrow",WS_CHILD | WS_BORDER | WS_GROUP,174,52,7,12
+ PUSHBUTTON "&OK" ,IDOK ,26 ,111,40 ,14, WS_TABSTOP | WS_GROUP
+ PUSHBUTTON "Cancel",IDCANCEL ,82 ,111,40 ,14
+ PUSHBUTTON "&Help" ,FD_IDHELP ,138,111,40 ,14
+END
+
+IDD_DRIVELET DIALOG 6, 18, 180, 124
+FONT 8, "MS Shell Dlg"
+STYLE WS_BORDER | DS_MODALFRAME | WS_CAPTION | WS_DLGFRAME | WS_POPUP | WS_SYSMENU
+CAPTION "Assign Drive Letter"
+BEGIN
+ LTEXT "", IDC_DRIVELET_DESCR, 14, 12, 152, 16
+ GROUPBOX "",-1,19,30,142,58
+ AUTORADIOBUTTON "&Assign drive letter", IDC_DRIVELET_RBASSIGN, 36, 46, 70, 10
+ AUTORADIOBUTTON "Do &not assign a drive letter", IDC_DRIVELET_RBNOASSIGN, 36, 64, 100, 10
+ COMBOBOX IDC_DRIVELET_COMBOBOX, 109, 46, 22, 51, CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ DEFPUSHBUTTON "OK" ,IDOK , 15 , 101, 40, 17
+ PUSHBUTTON "Cancel",IDCANCEL, 70 , 101, 40, 17
+ PUSHBUTTON "&Help" ,FD_IDHELP , 125, 101, 40, 17
+END
+
+IDD_PARTITIONLABEL DIALOG 20, 20, 161, 63
+FONT 8 "MS Shell Dlg"
+STYLE WS_BORDER | DS_MODALFRAME | WS_CAPTION | WS_DLGFRAME | WS_POPUP | WS_SYSMENU
+CAPTION "Label Volume"
+BEGIN
+ CONTROL "&Label:", IDC_TEXT, "static", SS_LEFTNOWORDWRAP | WS_CHILD, 5, 15, 30, 10
+ CONTROL "", IDC_NAME, "edit", ES_LEFT | WS_BORDER | WS_TABSTOP | WS_CHILD | ES_AUTOHSCROLL, 5, 26, 100, 12
+ CONTROL "&OK", IDOK, "button", BS_DEFPUSHBUTTON | WS_TABSTOP | WS_CHILD, 115, 6, 40, 14
+ CONTROL "Cancel", IDCANCEL, "button", BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD, 115, 23, 40, 14
+ CONTROL "&Help", FD_IDHELP, "button", BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD, 115, 43, 40, 14
+END
+
+IDD_PARTITIONFORMAT DIALOG 11, 28, 183, 65
+FONT 8, "MS Shell Dlg"
+STYLE WS_BORDER | DS_MODALFRAME | WS_CAPTION | WS_DLGFRAME | WS_POPUP | WS_SYSMENU
+CAPTION "Format"
+BEGIN
+ CONTROL "&OK", IDOK, "button", BS_DEFPUSHBUTTON | WS_TABSTOP | WS_CHILD, 140, 6, 40, 14
+ CONTROL "Cancel", IDCANCEL, "button", BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD, 140, 23, 40, 14
+ CONTROL "&Help", FD_IDHELP, "button", BS_PUSHBUTTON | WS_TABSTOP | WS_CHILD, 140, 43, 40, 14
+ LTEXT "&File System:", -1, 5, 7, 49, 10
+ CONTROL "", IDC_FSTYPE, "combobox", CBS_DROPDOWNLIST | WS_TABSTOP | WS_VSCROLL | WS_CHILD, 55, 4, 65, 40
+ LTEXT "&Label:", -1, 11, 30, 39, 10
+ CONTROL "", IDC_NAME, "edit", ES_LEFT | WS_BORDER | WS_TABSTOP | WS_CHILD, 40, 28, 63, 12
+ CONTROL "&Quick Format", IDC_VERIFY, "button", BS_CHECKBOX | BS_AUTOCHECKBOX | WS_TABSTOP | WS_CHILD, 11, 48, 90, 12
+END
+
+IDD_FORMATCANCEL DIALOG 7, 18, 160, 65
+STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Formatting"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CTEXT "", IDC_TEXT, 15, 36, 131, 8
+ CONTROL "", IDC_GASGAUGE, "Static", SS_BLACKFRAME, 15, 10, 131, 22
+ DEFPUSHBUTTON "Cancel", IDCANCEL, 60, 45, 40, 14
+END
+
+IDD_CDROM DIALOG 11, 28, 180, 110
+FONT 8, "MS Shell Dlg"
+STYLE WS_BORDER | DS_MODALFRAME | WS_CAPTION | WS_DLGFRAME | WS_POPUP | WS_SYSMENU
+CAPTION "CD-ROM Drive Letters"
+BEGIN
+ LTEXT "&Device Names", -1, 10, 15, 90, 8
+ COMBOBOX IDC_CDROM_NAMES, 10, 25, 100, 45, CBS_SIMPLE | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Drive &Letter", -1, 115, 15, 50, 8
+ COMBOBOX IDC_DRIVELET_COMBOBOX, 115, 25, 22, 51, CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ DEFPUSHBUTTON "&Change" ,IDOK , 15 , 80, 40, 17
+ PUSHBUTTON "Cancel" ,IDCANCEL, 70 , 80, 40, 17
+ PUSHBUTTON "&Help" ,FD_IDHELP , 125, 80, 40, 17
+END
+
+IDD_COLORS DIALOG 6, 32, 329, 131
+STYLE WS_BORDER | DS_MODALFRAME | WS_CAPTION | WS_DLGFRAME | WS_POPUP | WS_SYSMENU
+CAPTION "Colors and Patterns"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Color &and pattern for:",-1,10,8,229,8
+ COMBOBOX IDC_COLORDLGCOMBO,10,20,309,44,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ GROUPBOX "&Colors",-1,10,39,106,80,WS_GROUP
+ CONTROL "", IDC_COLOR1 , RECTCONTROL, RS_COLOR, 27, 55, 15, 11
+ CONTROL "", IDC_COLOR2 , RECTCONTROL, RS_COLOR, 27, 69, 15, 11
+ CONTROL "", IDC_COLOR3 , RECTCONTROL, RS_COLOR, 27, 83, 15, 11
+ CONTROL "", IDC_COLOR4 , RECTCONTROL, RS_COLOR, 27, 97, 15, 11
+ CONTROL "", IDC_COLOR5 , RECTCONTROL, RS_COLOR, 46, 55, 15, 11
+ CONTROL "", IDC_COLOR6 , RECTCONTROL, RS_COLOR, 46, 69, 15, 11
+ CONTROL "", IDC_COLOR7 , RECTCONTROL, RS_COLOR, 46, 83, 15, 11
+ CONTROL "", IDC_COLOR8 , RECTCONTROL, RS_COLOR, 46, 97, 15, 11
+ CONTROL "", IDC_COLOR9 , RECTCONTROL, RS_COLOR, 65, 55, 15, 11
+ CONTROL "", IDC_COLOR10, RECTCONTROL, RS_COLOR, 65, 69, 15, 11
+ CONTROL "", IDC_COLOR11, RECTCONTROL, RS_COLOR, 65, 83, 15, 11
+ CONTROL "", IDC_COLOR12, RECTCONTROL, RS_COLOR, 65, 97, 15, 11
+ CONTROL "", IDC_COLOR13, RECTCONTROL, RS_COLOR, 84, 55, 15, 11
+ CONTROL "", IDC_COLOR14, RECTCONTROL, RS_COLOR, 84, 69, 15, 11
+ CONTROL "", IDC_COLOR15, RECTCONTROL, RS_COLOR, 84, 83, 15, 11
+ CONTROL "", IDC_COLOR16, RECTCONTROL, RS_COLOR, 84, 97, 15, 11
+ GROUPBOX "&Patterns",-1,127,39,94,80,WS_GROUP
+ CONTROL "", IDC_PATTERN1,RECTCONTROL, RS_PATTERN, 142, 55, 27, 15
+ CONTROL "", IDC_PATTERN2,RECTCONTROL, RS_PATTERN, 142, 74, 27, 15
+ CONTROL "", IDC_PATTERN3,RECTCONTROL, RS_PATTERN, 142, 93, 27, 15
+ CONTROL "", IDC_PATTERN4,RECTCONTROL, RS_PATTERN, 179, 55, 27, 15
+ CONTROL "", IDC_PATTERN5,RECTCONTROL, RS_PATTERN, 179, 74, 27, 15
+ DEFPUSHBUTTON "&OK" , IDOK , 272, 43, 44, 18, WS_TABSTOP | WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, 272, 70, 44, 18, WS_TABSTOP
+ PUSHBUTTON "&Help" , FD_IDHELP , 272, 97, 44, 18, WS_TABSTOP
+END
+
+
+IDD_DISPLAYOPTIONS DIALOG 6, 18, 211, 130
+STYLE WS_BORDER | DS_MODALFRAME | WS_CAPTION | WS_DLGFRAME | WS_POPUP | WS_SYSMENU
+CAPTION "Region Display Options"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "",-1,10,12,191,83
+ LTEXT "For &disk",-1,18,29,29,8
+ COMBOBOX IDC_DISK_COMBOBOX,47,27,24,40,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP | WS_GROUP
+ PUSHBUTTON "&Reset All",IDC_RESETALL,146,25,48,16,WS_TABSTOP | WS_GROUP
+ AUTORADIOBUTTON "Size regions based on &actual size",IDC_RBPROPORTIONAL,18,49,158,10, WS_GROUP | WS_TABSTOP
+ AUTORADIOBUTTON "Size all regions &equally",IDC_RBEQUAL,18,61,158,10
+ AUTORADIOBUTTON "&Let Disk Administrator decide how to size regions",IDC_RBAUTO,18,73,173,10
+ DEFPUSHBUTTON "&OK" ,IDOK ,29 ,110,40,14, WS_TABSTOP | WS_GROUP
+ PUSHBUTTON "Cancel",IDCANCEL,85 ,110,40,14, WS_TABSTOP
+ PUSHBUTTON "&Help" ,FD_IDHELP ,141,110,40,14, WS_TABSTOP
+END
+
+IDD_INITIALIZING DIALOG 7, 18, 160, 45
+STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Disk Administrator is initializing"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CTEXT "", IDC_TEXT, 15, 36, 131, 8
+ CONTROL "", IDC_GASGAUGE, "Static", SS_BLACKFRAME, 15, 10, 131, 22
+END
+
+
+#include "ftreg.dlg"
diff --git a/private/utils/fdisk/fdisk.h b/private/utils/fdisk/fdisk.h
new file mode 100644
index 000000000..2ffa163fd
--- /dev/null
+++ b/private/utils/fdisk/fdisk.h
@@ -0,0 +1,120 @@
+
+/*++
+
+Copyright (c) 1991-1994 Microsoft Corporation
+
+Module Name:
+
+ fdisk.h
+
+Abstract:
+
+ Central include file for Disk Administrator
+
+Author:
+
+ Edward (Ted) Miller (TedM) 11/15/91
+
+Environment:
+
+ User process.
+
+Notes:
+
+Revision History:
+
+ 11-Nov-93 (bobri) added doublespace and commit support.
+ 2-Feb-94 (bobri) removed ArcInst dependency in build.
+
+--*/
+
+//#define UNICODE
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <ntdddisk.h>
+#include <ntdskreg.h>
+#include <ntddft.h>
+
+//
+// These defines are for virtualized types in partitp.h, low.h,
+// fdengine.c, etc.
+//
+#define STATUS_CODE NTSTATUS
+#define OK_STATUS STATUS_SUCCESS
+#define RETURN_OUT_OF_MEMORY return(STATUS_NO_MEMORY);
+#define HANDLE_T HANDLE
+#define HANDLE_PT PHANDLE
+#define AllocateMemory Malloc
+#define ReallocateMemory Realloc
+#define FreeMemory Free
+
+#include <windows.h>
+
+#include <stdarg.h>
+
+#include "fdtypes.h"
+#include "fdproto.h"
+#include "fdconst.h"
+#include "fdglob.h"
+#include "fdres.h"
+#include "fdiskmsg.h"
+#include "fdhelpid.h"
+
+
+#define PERSISTENT_DATA(region) ((PPERSISTENT_REGION_DATA)((region)->PersistentData))
+
+#define GET_FT_OBJECT(region) ((region)->PersistentData ? PERSISTENT_DATA(region)->FtObject : NULL)
+#define SET_FT_OBJECT(region,o) (PERSISTENT_DATA(region)->FtObject = o)
+
+
+#define EC(x) RtlNtStatusToDosError(x)
+
+// assertion checking, logging
+
+#if DBG
+
+#define FDASSERT(expr) if(!(expr)) FdiskAssertFailedRoutine(#expr,__FILE__,__LINE__);
+#define FDLOG(X) FdLog X
+
+VOID
+FdLog(
+ IN int Level,
+ IN PCHAR FormatString,
+ ...
+ );
+
+VOID
+LOG_DISK_REGISTRY(
+ IN PCHAR RoutineName,
+ IN PDISK_REGISTRY DiskRegistry
+ );
+
+VOID
+LOG_ONE_DISK_REGISTRY_DISK_ENTRY(
+ IN PCHAR RoutineName OPTIONAL,
+ IN PDISK_DESCRIPTION DiskDescription
+ );
+
+VOID
+LOG_DRIVE_LAYOUT(
+ IN PDRIVE_LAYOUT_INFORMATION DriveLayout
+ );
+
+VOID
+InitLogging(
+ VOID
+ );
+
+extern PVOID LogFile;
+
+#else
+
+#define FDASSERT(expr)
+#define FDLOG(X)
+#define LOG_DISK_REGISTRY(x,y)
+#define LOG_ONE_DISK_REGISTRY_DISK_ENTRY(x,y)
+#define LOG_DRIVE_LAYOUT(x)
+
+#endif
diff --git a/private/utils/fdisk/fdisk.rc b/private/utils/fdisk/fdisk.rc
new file mode 100644
index 000000000..4b6bc8284
--- /dev/null
+++ b/private/utils/fdisk/fdisk.rc
@@ -0,0 +1,209 @@
+#include <windows.h>
+#include "fdres.h"
+
+
+// icons
+
+IDFDISK ICON dskmgr.ico // main icon
+IDB_SMALLDISK BITMAP smdisk.bmp // small disk
+IDB_REMOVABLE BITMAP rmdisk.bmp // removable disk
+
+// string table
+
+STRINGTABLE BEGIN
+ IDS_APPNAME "Disk Administrator"
+ IDS_MULTIPLEITEMS "Multiple items selected"
+ IDS_FREESPACE "Free space"
+ IDS_PARTITION "Partition"
+ IDS_LOGICALVOLUME "Logical drive"
+ IDS_DISKN "Disk %u"
+ IDS_CONFIRM "Confirm"
+ IDS_NOT_IN_APP_MSG_FILE "Could not find message %u in the application message file"
+ IDS_NOT_IN_SYS_MSG_FILE "Could not find message %u in the system message file"
+ IDS_UNFORMATTED "Unformatted"
+ IDS_NEW_UNFORMATTED "New unformatted"
+ IDS_UNKNOWN "Unknown"
+ IDS_STRIPESET "Stripe set"
+ IDS_VOLUMESET "Volume set"
+ IDS_EXTENDEDPARTITION "Empty extended partition"
+ IDS_FREEEXT "Free space in extended partition"
+ IDS_DRIVELET_DESCR "%1 MB %2 %3 on disk %4"
+ IDS_HEALTHY "HEALTHY"
+ IDS_BROKEN "BROKEN"
+ IDS_RECOVERABLE "RECOVERABLE"
+ IDS_INITIALIZING "INITIALIZING"
+ IDS_REGENERATING "REGENERATING"
+ IDS_REGENERATED "REGENERATED"
+ IDS_NEW "NEW"
+ IDS_OFFLINE "OFF-LINE"
+ IDS_DISABLED "DISABLED"
+ IDS_INIT_FAILED "Initialization Failed"
+ IDS_INSERT_DISK "Insert Disk"
+ IDS_MEGABYTES_ABBREV "MB"
+ IDS_NO_CONFIG_INFO "Configuration information not available"
+
+#if i386
+ IDS_ACTIVEPARTITION "Active partition"
+#endif
+ IDS_CRTPART_CAPTION_P "Create Primary Partition"
+ IDS_CRTPART_CAPTION_E "Create Extended Partition"
+ IDS_CRTPART_CAPTION_L "Create Logical Drive"
+ IDS_CRTPART_MIN_P "Minimum size for the partition is"
+ IDS_CRTPART_MAX_P "Maximum size for the partition is"
+ IDS_CRTPART_MIN_L "Minimum size for the logical drive is"
+ IDS_CRTPART_MAX_L "Maximum size for the logical drive is"
+ IDS_CRTPART_SIZE_P "Create partition of size"
+ IDS_CRTPART_SIZE_L "Create logical drive of size"
+
+ IDS_CRTPSTRP_CAPTION "Create Stripe Set With Parity"
+ IDS_CRTSTRP_CAPTION "Create Stripe Set"
+ IDS_CRTSTRP_MIN "Minimum total size for the stripe set is"
+ IDS_CRTSTRP_MAX "Maximum total size for the stripe set is"
+ IDS_CRTSTRP_SIZE "Create stripe set of total size"
+
+ IDS_CRTVSET_CAPTION "Create Volume Set"
+ IDS_EXPVSET_CAPTION "Extend Volume Set"
+ IDS_CRTVSET_MIN "Minimum total size for the volume set is"
+ IDS_CRTVSET_MAX "Maximum total size for the volume set is"
+ IDS_CRTVSET_SIZE "Create volume set of total size"
+
+ IDS_STATUS_STRIPESET "Stripe set #%u"
+ IDS_STATUS_PARITY "Stripe set with parity #%u [%ws]"
+ IDS_DLGCAP_PARITY "Stripe set with parity #%u"
+ IDS_STATUS_VOLUMESET "Volume set #%u"
+ IDS_STATUS_MIRROR "Mirror set #%u [%ws]"
+ IDS_DLGCAP_MIRROR "Mirror set #%u"
+
+ // Note: these must be in same order as BRUSH_xxx constants in fdisk.h
+
+ IDS_LEGEND_PRIMARY "Primary partition"
+ IDS_LEGEND_LOGICAL "Logical drive"
+ IDS_LEGEND_STRIPESET "Stripe set"
+ IDS_LEGEND_MIRROR "Mirror set"
+ IDS_LEGEND_VOLUMESET "Volume set"
+
+ IDS_PARTITION_FREE "Free Space"
+ IDS_PARTITION_XENIX1 "XENIX1"
+ IDS_PARTITION_XENIX2 "XENIX2"
+ IDS_PARTITION_OS2_BOOT "OS/2 Boot Manager"
+ IDS_PARTITION_EISA "EISA Utilities"
+ IDS_PARTITION_UNIX "Unix"
+ IDS_PARTITION_POWERPC "PowerPC Boot"
+
+ // Double space support strings
+
+ IDS_DBLSPACE_DELETE "Delete DoubleSpace Volume"
+ IDS_DBLSPACE_MOUNTED "DoubleSpace Volume currently mounted as drive"
+ IDS_DBLSPACE_DISMOUNTED "DoubleSpace Volume is dismounted"
+ IDS_WITH_DBLSPACE "with DoubleSpace Volumes"
+ IDS_MOUNT "Mount"
+ IDS_DISMOUNT "Dismount"
+ IDS_CREATING_DBLSPACE "Creating DoubleSpace volume..."
+ IDS_DBLSPACECOMPLETE "Creation of DoubleSpace volume is complete"
+
+ // format support strings
+
+ IDS_QUICK_FORMAT "Quick Formatting..."
+ IDS_PERCENTCOMPLETE "Percent Complete"
+ IDS_FORMATSTATS "%ld KB total disk space\n%ld KB available on disk"
+ IDS_FORMATCOMPLETE "Format Complete"
+ IDS_FORMAT_TITLE "Formatting %c:"
+ IDS_LABEL_TITLE "Label for Volume %c:"
+ IDS_SOURCE_PATH "Software\\Microsoft\\Windows NT\\CurrentVersion"
+ IDS_SOURCE_PATH_NAME "SourcePath"
+END
+
+
+// frame window menu
+
+IDFDISK MENU BEGIN
+ POPUP "&Partition"
+ BEGIN
+ MENUITEM "&Create..." ,IDM_PARTITIONCREATE , GRAYED
+ MENUITEM "Create &Extended..." ,IDM_PARTITIONCREATEEX, GRAYED
+ MENUITEM "&Delete" ,IDM_PARTITIONDELETE , GRAYED
+ MENUITEM SEPARATOR
+ MENUITEM "Create &Volume Set..." ,IDM_FTCREATEVOLUMESET, GRAYED
+ MENUITEM "Ex&tend Volume Set..." ,IDM_FTEXTENDVOLUMESET, GRAYED
+ MENUITEM SEPARATOR
+ MENUITEM "Create &Stripe Set..." ,IDM_FTCREATESTRIPE , GRAYED
+#if i386
+ MENUITEM SEPARATOR
+ MENUITEM "Mark &Active" ,IDM_PARTITIONACTIVE , GRAYED
+#else
+ MENUITEM SEPARATOR
+ MENUITEM "Sec&ure System Partition",IDM_SECURESYSTEM
+#endif
+ MENUITEM SEPARATOR
+ POPUP "Confi&guration"
+ BEGIN
+ MENUITEM "&Save..." ,IDM_CONFIGSAVE
+ MENUITEM "&Restore..." ,IDM_CONFIGRESTORE
+ MENUITEM "Sear&ch..." ,IDM_CONFIGMIGRATE
+ END
+ MENUITEM SEPARATOR
+ MENUITEM "C&ommit Changes Now..." ,IDM_COMMIT , GRAYED
+ MENUITEM "E&xit" ,IDM_PARTITIONEXIT
+ END
+ POPUP "&Fault Tolerance"
+ BEGIN
+ MENUITEM "Establish &Mirror" ,IDM_FTESTABLISHMIRROR, GRAYED
+ MENUITEM "&Break Mirror..." ,IDM_FTBREAKMIRROR , GRAYED
+ MENUITEM SEPARATOR
+ MENUITEM "Create Stripe Set with &Parity...",IDM_FTCREATEPSTRIPE , GRAYED
+ MENUITEM "&Regenerate" ,IDM_FTRECOVERSTRIPE , GRAYED
+ END
+ POPUP "&Tools"
+ BEGIN
+ MENUITEM "&Format..." ,IDM_PARTITIONFORMAT , GRAYED
+ MENUITEM "&Label..." ,IDM_PARTITIONLABEL , GRAYED
+ MENUITEM "Dri&ve Letter..." ,IDM_PARTITIONLETTER , GRAYED
+#ifdef DOUBLE_SPACE_SUPPORT_INCLUDED
+ MENUITEM SEPARATOR
+ MENUITEM "&DoubleSpace Volumes...",IDM_DBLSPACE , GRAYED
+ MENUITEM "&Automount DoubleSpace Floppies",IDM_AUTOMOUNT
+#endif
+ MENUITEM SEPARATOR
+ MENUITEM "&CD-ROM Drive Letters..." ,IDM_CDROM , GRAYED
+ END
+ POPUP "&Options"
+ BEGIN
+ MENUITEM "&Status Bar" ,IDM_OPTIONSSTATUS
+ MENUITEM "&Legend" ,IDM_OPTIONSLEGEND
+ MENUITEM SEPARATOR
+ MENUITEM "&Colors and Patterns...",IDM_OPTIONSCOLORS
+ MENUITEM "&Region Display..." ,IDM_OPTIONSDISPLAY
+ END
+ POPUP "&Help"
+ BEGIN
+ MENUITEM "&Contents" ,IDM_HELPCONTENTS
+ MENUITEM "&Search for Help on..." ,IDM_HELPSEARCH
+ MENUITEM "&How to Use Help" ,IDM_HELPHELP
+ MENUITEM SEPARATOR
+ MENUITEM "&About Disk Administrator..." ,IDM_HELPABOUT
+ END
+#if DBG && DEVL
+ POPUP "DEBUG"
+ BEGIN
+ MENUITEM "Allow delete all partitions",IDM_DEBUGALLOWDELETES
+ END
+#endif
+END
+
+MainAcc ACCELERATORS PRELOAD DISCARDABLE
+BEGIN
+ VK_F1, IDM_HELP, VIRTKEY
+END
+
+#include "fdisk.dlg"
+#include "fdiskmsg.rc"
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Disk Partitioning Utility"
+#define VER_INTERNALNAME_STR "fdisk\0"
+#define VER_ORIGINALFILENAME_STR "WINDISK.EXE"
+
+#include "common.ver"
diff --git a/private/utils/fdisk/fdiskmsg.mc b/private/utils/fdisk/fdiskmsg.mc
new file mode 100644
index 000000000..879280728
--- /dev/null
+++ b/private/utils/fdisk/fdiskmsg.mc
@@ -0,0 +1,636 @@
+;/*++
+;
+;Copyright (c) 1991 Microsoft Corporation
+;
+;Module Name:
+;
+; fdiskmsg.h
+;
+;Abstract:
+;
+; This file contains the message definitions for Win32 fdisk.
+;
+;Author:
+;
+; Ted Miller (tedm) 5-Dec-1991
+;
+;Revision History:
+;
+;Notes:
+;
+; This file is generated from fdiskmsg.mc
+;
+;--*/
+;
+;#ifndef _FDISKMSG_
+;#define _FDISKMSG_
+;
+;
+
+MessageID=9000 SymbolicName=MSG_FIRST_FDISK_MSG
+Language=English
+.
+
+MessageID=9001 SymbolicName=MSG_CANT_CREATE_WINDOWS
+Language=English
+Disk Administrator was unable to create its windows.
+Click OK to exit.
+.
+
+MessageID=9002 SymbolicName=MSG_NO_DISKS
+Language=English
+Disk Administrator has determined that there are no fixed disks attached to the system, or all such disks are off-line. Click OK to exit.
+.
+
+MessageID=9003 SymbolicName=MSG_ACCESS_DENIED
+Language=English
+Access is denied. You must be logged on with Administrative privilege to run Disk Administrator.
+.
+
+MessageID=9004 SymbolicName=MSG_CONFIRM_DELETE
+Language=English
+All data in the partition or logical drive will be lost!
+
+Are you sure you want to delete the chosen partition or logical drive?
+.
+
+MessageID=9005 SymbolicName=MSG_CREATE_NOT_COMPAT
+Language=English
+This operation will result in a disk whose partition scheme may not be compatible with MS-DOS. Some partitions may not be accessible if the disk is used with MS-DOS in the future.
+
+Do you want to continue and create the partition anyway?
+.
+
+MessageID=9006 SymbolicName=MSG_INVALID_SIZE
+Language=English
+Invalid size.
+.
+
+MessageID=9007 SymbolicName=MSG_ALREADY_RUNNING
+Language=English
+Disk Administrator is already running.
+.
+
+MessageID=9008 SymbolicName=MSG_CONFIRM_EXIT
+Language=English
+Changes have been made to your disk configuration.
+
+Do you want to save the changes?
+.
+
+MessageID=9009 SymbolicName=MSG_OUT_OF_MEMORY
+Language=English
+Disk Administrator has run out of memory.
+Select Cancel to exit Disk Administrator, or try closing other applications to free memory and then select Retry.
+If you exit, all changes will be lost.
+.
+
+MessageID=9010 SymbolicName=MSG_OK_COMMIT
+Language=English
+Disks were updated successfully.
+
+It is recommended that you update the emergency repair configuration information and create a new Emergency Repair Disk. You can do this with the system utility RDISK.EXE.
+.
+
+MessageID=9011 SymbolicName=MSG_CANT_DELETE_WINNT
+Language=English
+Disk Administrator cannot delete the partition containing Windows NT system files.
+.
+
+MessageID=9012 SymbolicName=MSG_HELP_ERROR
+Language=English
+Could not invoke help application.
+.
+
+MessageID=9013 SymbolicName=MSG_NO_AVAIL_LETTER
+Language=English
+All available drive letters are already assigned.
+
+You will not be able to access the %1 from Windows NT unless you rearrange drive letter usage.
+
+Do you want to continue and create the %1 anyway?
+.
+
+MessageID=9014 SymbolicName=MSG_BAD_CONFIG_SET
+Language=English
+An error occurred while updating disk configuration.
+
+Drive letter and fault tolerance information may be lost and/or some partitions may be inaccessible.
+.
+
+MessageID=9015 SymbolicName=MSG_CONFIG_MISSING_DISK
+Language=English
+Disk Administrator has determined that one or more disks have been removed from your computer since Disk Administrator was last run, or that one or more disks are off-line.
+
+Configuration information about the missing disk(s) will be retained.
+.
+
+MessageID=9016 SymbolicName=MSG_CONFIG_EXTRA_DISK
+Language=English
+Disk Administrator has determined that this is the first time Disk Administrator has been run, or that one or more disks have been added to your computer since Disk Administrator was last run.
+
+System configuration will now be updated.
+.
+
+MessageID=9017 SymbolicName=MSG_CONFIG_DISK_CHANGED
+Language=English
+Disk Administrator has determined that the configuration of one of more disks has been altered since Disk Administrator was last run.
+
+System configuration will be automatically updated to reflect these changes when you next opt to save changes when exiting Disk Administrator.
+.
+
+MessageID=9018 SymbolicName=MSG_ALL_DRIVE_LETTERS_USED
+Language=English
+All drive letters are already assigned.
+.
+
+MessageID=9019 SymbolicName=MSG_PART_TABLE_FULL
+Language=English
+No more primary partitions can be created on the disk. A disk cannot hold more than four partitions (including the extended partition but not including logical drives).
+.
+
+MessageID=9020 SymbolicName=MSG_EXTENDED_ALREADY_EXISTS
+Language=English
+An extended partition already exists on the disk.
+.
+
+MessageID=9021 SymbolicName=MSG_NO_OTHER_NTS
+Language=English
+No other Windows NT installations were found.
+.
+
+MessageID=9022 SymbolicName=MSG_CONFIRM_MIGRATE_CONFIG
+Language=English
+Warning: This operation will overwrite your disk configuration information with the configuration from a different installation of Windows NT.
+Currently defined drive letters, volume sets, stripe sets, parity stripes, and mirrors may be lost depending on the disk configuration associated with the Windows NT installation you select.
+
+No partitions will be created or deleted by this operation, but any changes you have made during this session of Disk Administrator will be lost.
+
+Do you want to search for other installations of Windows NT?
+.
+
+MessageID=9023 SymbolicName=MSG_CONFIRM_RESTORE_CONFIG
+Language=English
+Warning: This operation will overwrite your disk configuration information
+with a previously saved configuration.
+Currently defined drive letters, volume sets, stripe sets, parity stripes,
+and mirrors may be lost depending on the previously saved disk configuration.
+
+No partitions will be created or deleted by this operation,
+but any changes you have made during this session of Disk Administrator
+will be lost.
+
+Do you want to continue with the restoration?
+.
+
+MessageID=9024 SymbolicName=MSG_INSERT_REGSAVEDISK
+Language=English
+Please insert a disk onto which you have previously saved disk configuration information, into drive A:.
+
+Press OK when the disk is in the drive.
+.
+
+MessageID=9025 SymbolicName=MSG_INSERT_REGSAVEDISK2
+Language=English
+This operation will save configuration information about currently defined drive letters, volume sets, stripe sets, stripe sets with parity, and mirrors sets.
+The saved configuration information will be placed on a floppy disk.
+
+Please insert a formatted disk into drive A:. Press OK when the disk is in the drive.
+.
+
+MessageID=9026 SymbolicName=MSG_CONFIG_SAVED_OK
+Language=English
+Disk configuration information was saved successfully.
+.
+
+MessageID=9027 SymbolicName=MSG_ABSOLUTELY_SURE
+Language=English
+Current disk configuration information will be overwritten! Are you absolutely sure you want to continue?
+.
+
+
+MessageID=9028 SymbolicName=MSG_NO_SIGNATURE
+Language=English
+No signature found on %1. Writing a signature is a safe operation and will not affect your ability to access this disk from other operating systems, such as DOS.
+
+If you choose not to write a signature, the disk will be marked OFF-LINE and be inaccessable to the Windows NT Disk Administrator program.
+
+Do you want to write a signature on %1 so that Disk Administrator can access the drive?
+.
+
+MessageID=9029 SymbolicName=MSG_SCHEDULE_REBOOT
+Language=English
+This drive letter assignment can be performed if you wish to restart your computer.
+Click YES to schedule this change for system restart upon exiting this application.
+
+Note, responding with YES to this question means a commit of the changes requested will occur on exiting this application.
+.
+
+MessageID=9030 SymbolicName=MSG_TOO_BIG_FOR_FAT
+Language=English
+This volume cannot be formatted to the FAT file system. FAT can only support volumes up to 4GB in size.
+.
+
+MessageID=9031 SymbolicName=MSG_NO_DISK_INFO
+Language=English
+The configuration selected does not contain any disk configuration information. No change will be made to the current configuration.
+.
+
+MessageID=9032 SymbolicName=MSG_DISK_INFO_BUSY
+Language=English
+The configuration selected is currently open by another application. Close the other accesses to this file and try again.
+.
+
+;#if i386
+
+MessageID=9100 SymbolicName=MSG_DISK0_ACTIVE
+Language=English
+The requested partition has been marked active. When you reboot your computer the operating system on that partition will be started.
+.
+
+MessageID=9101 SymbolicName=MSG_PRI_1024_CYL
+Language=English
+The partition created may not be accessible from other operating systems
+such as MS-DOS because the start or end cylinder value is too large.
+
+Do you want to create the partition anyway?
+.
+
+MessageID=9102 SymbolicName=MSG_EXT_1024_CYL
+Language=English
+Logical drives created within the extended partition created will not be
+accessible from other operating systems such as MS-DOS because the start
+or end cylinder value is too large.
+
+Do you want to create the extended partition anyway?
+.
+
+MessageID=9103 SymbolicName=MSG_LOG_1024_CYL
+Language=English
+The logical drive created will not be accessible from other operating systems
+such as MS-DOS because the extended partition start or end cylinder value is too large.
+
+Do you want to create the logical drive anyway?
+.
+
+MessageID=9104 SymbolicName=MSG_CANT_DELETE_ACTIVE0
+Language=English
+Disk Administrator cannot delete the active partition on disk 0.
+.
+
+MessageID=9105 SymbolicName=MSG_CANT_EXTEND_ACTIVE0
+Language=English
+Disk Administrator cannot convert the active partition on disk 0 into a volume set.
+.
+
+;#endif
+
+MessageID=9106 SymbolicName=MSG_CANT_DELETE_INITIALIZING_SET
+Language=English
+Disk Administrator cannot delete an FT set while it is initializing or regenerating.
+.
+
+MessageID=9107 SymbolicName=MSG_CANT_BREAK_INITIALIZING_SET
+Language=English
+Disk Administrator cannot break a Mirror set while it is initializing.
+.
+
+MessageID=9108 SymbolicName=MSG_CANT_REGEN_INITIALIZING_SET
+Language=English
+Disk Administrator cannot regenerate a Stripe set with Parity while it is initializing or regenerating.
+.
+
+MessageID=9109 SymbolicName=MSG_MIRROR_OF_BOOT
+Language=English
+This will be a Mirror set of the system boot partition. Please refer to the Windows NT Server Concepts and Planning Guide for information on how to create a Fault Tolerant boot floppy disk.
+.
+
+MessageID=9200 SymbolicName=MSG_CONFIRM_DEL_STRP
+Language=English
+All data in the stripe set will be lost!
+
+Are you sure you want to delete the selected stripe set?
+.
+
+MessageID=9201 SymbolicName=MSG_CRTSTRP_FULL
+Language=English
+The disk containing one of the free spaces you have chosen is not able to accept any more partitions.
+.
+
+MessageID=9202 SymbolicName=MSG_CRTMIRROR_BADFREE
+Language=English
+The free space you have chosen is not large enough to contain a mirror of the partition you have chosen.
+.
+
+MessageID=9203 SymbolicName=MSG_CONFIRM_BRK_MIRROR
+Language=English
+This will end mirroring and create two independent partitions.
+
+Are you sure you want to break the selected mirror?
+.
+
+MessageID=9204 SymbolicName=MSG_CONFIRM_DEL_VSET
+Language=English
+All data in the volume set will be lost!
+
+Are you sure you want to delete the selected volume set?
+.
+
+MessageId=9205 SymbolicName=MSG_CANT_INIT_FT
+Language=English
+Disk Administrator was unable to configure the Fault Tolerance Device.
+Mirrors and stripe sets with parity will not be initialized or regenerated.
+.
+
+MessageId=9207 SymbolicName=MSG_NOT_LARGE_ENOUGH_FOR_STRIPE
+Language=English
+The free space you have chosen is not large enough to contain an element in the stripe set you have chosen for regeneration.
+.
+
+MessageID=9497 SymbolicName=MSG_CHANGED_BOOT_PARTITION_X86
+Language=English
+This change will modify the partition number of the partition which contains your Windows NT system files.
+The old partition number was %1; the new partition number is %2.
+Edit BOOT.INI to reflect this change before shutting the system down.
+.
+
+MessageID=9498 SymbolicName=MSG_CHANGED_BOOT_PARTITION_ARC
+Language=English
+This change will modify the partition number of the partition which contains your Windows NT system files.
+The old partition number was %1; the new partition number is %2.
+.
+
+MessageId=9499 SymbolicName=MSG_REQUIRE_REBOOT
+Language = English
+The changes requested will require you to restart your computer. Click YES to continue with the changes and restart the computer.
+.
+
+MessageId=9500 SymbolicName=MSG_MUST_REBOOT
+Language=English
+Changes have been made which require you to restart your computer. Click OK to initiate system shutdown.
+.
+
+MessageId=9501 SymbolicName=MSG_COULDNT_REBOOT
+Language=English
+Disk Administrator was unable to restart your computer. To ensure the integrity of your disks and data, you should initiate system shutdown from the Program Manager. Click OK to exit Disk Administrator.
+.
+
+MessageId=9051 SymbolicName=MSG_CONFIRM_SHUTDOWN_FOR_MIRROR
+Language=English
+The mirror set cannot be locked. To break this mirror relationship the system must be restarted. This restart of the system will occur on exiting Disk Administrator.
+
+Do you wish to continue with this operation?
+.
+
+MessageId=9052 SymbolicName=MSG_EXTEND_VOLSET_MUST_BE_NTFS
+Language=English
+The volume set is not formatted to NTFS; only NTFS volume sets can be extended.
+.
+
+MessageId=9053 SymbolicName=MSG_CONFIRM_BRKANDDEL_MIRROR
+Language=English
+All data in the mirror will be lost!
+
+Are you sure you want to break the selected mirror and delete its component partitions?
+.
+
+MessageID=9054 SymbolicName=MSG_CANT_EXTEND_WINNT
+Language=English
+Disk Administrator cannot extend the partition containing Windows NT system files.
+.
+
+MessageID=9055 SymbolicName=MSG_CONFIRM_PROTECT_SYSTEM
+Language=English
+Are you sure you want to restrict access to the System Partition to System Administrators?
+
+Performing this operation will require a restart of the system.
+.
+
+MessageID=9056 SymbolicName=MSG_CONFIRM_UNPROTECT_SYSTEM
+Language=English
+Are you sure you want to allow all users access to the System Partition?
+
+Performing this operation will require a restart of the system.
+.
+
+MessageID=9057 SymbolicName=MSG_CANT_PROTECT_SYSTEM
+Language=English
+Disk Administrator cannot mark the System Partition secure.
+.
+
+MessageID=9058 SymbolicName=MSG_CANT_UNPROTECT_SYSTEM
+Language=English
+Disk Administrator cannot mark the System Partition as non-secure.
+.
+
+MessageID=9059 SymbolicName=MSG_NO_REMOVABLE_IN_STRIPE
+Language=English
+Stripe sets cannot include partitions on removable media.
+.
+
+MessageID=9060 SymbolicName=MSG_NO_REMOVABLE_IN_VOLUMESET
+Language=English
+Volume sets cannot include partitions on removable media.
+.
+
+
+MessageID=9061 SymbolicName=MSG_NO_REMOVABLE_IN_MIRROR
+Language=English
+Mirror pairs cannot include partitions on removable media.
+.
+
+MessageID=9062 SymbolicName=MSG_CANT_ASSIGN_LETTER_TO_REMOVABLE
+Language=English
+Disk Administrator cannot assign drive letters to partitions on removable media.
+.
+
+MessageID=9063 SymbolicName=MSG_NO_EXTENDED_ON_REMOVABLE
+Language=English
+Disk Administrator cannot create extended partitions on removable media.
+.
+
+MessageID=9064 SymbolicName=MSG_ONLY_ONE_PARTITION_ON_REMOVABLE
+Language=English
+Disk Administrator can only create one partition on a removable disk.
+.
+
+MessageID=9065 SymbolicName=MSG_REMOVABLE_PARTITION_NOT_FULL_SIZE
+Language=English
+Disk Administrator can only create one partition on a removable disk.
+Therefore, if you create a partition which does not use the entire disk,
+you will not be able to use the remaining free space.
+
+Are you sure you want to create this partition?
+.
+
+MessageID=9066 SymbolicName=MSG_BOOT_PARTITION_CHANGED_X86
+Language=English
+The partition number of the partition which contains your Windows NT system files has changed.
+The old partition number was %1; the new partition number is %2.
+Edit BOOT.INI to reflect this change before shutting the system down.
+.
+
+MessageID=9067 SymbolicName=MSG_BOOT_PARTITION_CHANGED_ARC
+Language=English
+The partition number of the partition which contains your Windows NT system files has changed.
+The old partition number was %1; the new partition number is %2.
+.
+
+MessageID=9068 SymbolicName=MSG_CANT_FORMAT_WINNT
+Language=English
+Disk Administrator cannot format a volume containing Windows NT system files.
+.
+
+MessageID=9069 SymbolicName=MSG_CANT_LOAD_FMIFS
+Language=English
+Disk Administrator cannot locate fmifs.dll to perform this action.
+.
+
+MessageID=9070 SymbolicName=MSG_CANT_FORMAT_NO_LETTER
+Language=English
+Disk Administrator cannot format a volume that is not assigned a drive letter.
+.
+
+MessageID=9071 SymbolicName=MSG_CONFIRM_FORMAT
+Language=English
+Warning: This operation will overwrite the data contained on this volume.
+Are you sure you wish to continue with this operation?
+.
+
+MessageID=9073 SymbolicName=MSG_COULDNT_CREATE_THREAD
+Language=English
+Disk Administrator could not create a thread to perform this operation.
+.
+
+MessageID=9074 SymbolicName=MSG_INCOMPATIBLE_FILE_SYSTEM
+Language=English
+The volume selected cannot be formatted in this manner.
+.
+
+MessageID=9075 SymbolicName=MSG_FORMAT_ACCESS_DENIED
+Language=English
+Access denied.
+.
+
+MessageID=9076 SymbolicName=MSG_WRITE_PROTECTED
+Language=English
+The volume selected is write protected.
+.
+
+MessageID=9077 SymbolicName=MSG_FORMAT_CANT_LOCK
+Language=English
+The volume selected cannot be locked for format.
+.
+
+MessageID=9078 SymbolicName=MSG_BAD_LABEL
+Language=English
+The label given is inappropriate for this volume.
+.
+
+MessageID=9079 SymbolicName=MSG_INCOMPATIBLE_MEDIA
+Language=English
+The media selected cannot support the file system selected.
+.
+
+MessageID=9080 SymbolicName=MSG_CANT_QUICK_FORMAT
+Language=English
+Quick format is not allowed on this volume.
+.
+
+MessageID=9081 SymbolicName=MSG_IO_ERROR
+Language=English
+An operation failed while attempting to format the volume.
+.
+
+MessageID=9082 SymbolicName=MSG_FORMAT_CANCELLED
+Language=English
+The format operation was cancelled.
+.
+
+MessageID=9896 SymbolicName=MSG_MUST_COMMIT_BREAK
+Language=English
+You have selected a partition that is still a member of a mirror set. Breaking the mirror set relationship does not actually happen until you quit Disk Administrator or choose the Commit Changes Now command.
+
+Please do one or the other of these actions and then delete the partition.
+.
+
+MessageID=9897 SymbolicName=MSG_CANNOT_LOCK_PAGEFILE
+Language=English
+The drive letter cannot be changed because a Windows NT paging file is located on this drive.
+
+Relocate the paging file using the control panel system option.
+.
+
+MessageID=9898 SymbolicName=MSG_CDROM_LETTER_ERROR
+Language=English
+An error occurred attempting to change the CdROM drive letter.
+
+The drive letter has not been changed.
+.
+
+MessageID=9899 SymbolicName=MSG_CANNOT_LOCK_CDROM
+Language=English
+The CdROM cannot be locked for exclusive use.
+
+Please check to see if some applications are currently accessing the drive. If so, close them and try again.
+.
+
+MessageID=9900 SymbolicName=MSG_CANNOT_LOCK_TRY_AGAIN
+Language=English
+The drive cannot be locked for exclusive use.
+
+Please check to see if some applications are currently accessing the drive. If so, close them and try again.
+.
+
+MessageID=9901 SymbolicName=MSG_VOLUME_CHANGED
+Language=English
+The removable media has changed. Insure the proper media is in the drive and perform the operation again.
+.
+
+MessageID=9902 SymbolicName=MSG_CANCEL_EXIT
+Language=English
+exit due to cancel return.
+.
+
+MessageID=9903 SymbolicName=MSG_CANNOT_MOVE_CDROM
+Language=English
+The new drive letter for the CdRom is still in use. Commit current Disk Administrator changes, verify network drive letter assignments and try again.
+.
+
+MessageID=9904 SymbolicName=MSG_NOT_COMMITTED
+Language=English
+The requested partitions and/or volumes have not been committed to disk. Retry this operation after committing this change.
+.
+
+MessageID=9909 SymbolicName=MSG_DRIVE_RENAME_WARNING
+Language=English
+This new drive letter assignment will happen immediately.
+
+Do you wish to continue?
+.
+
+MessageID=9910 SymbolicName=MSG_NO_COMMIT
+Language=English
+Not all of the affected disks can be changed without restarting the Windows NT system.
+.
+
+MessageID=9911 SymbolicName=MSG_CANT_BREAK_WHILE_INITIALIZING
+Language=English
+The mirror set cannot be broken at this time.
+.
+
+MessageID=9912 SymbolicName=MSG_INTERNAL_LETTER_ASSIGN_ERROR
+Language=English
+An internal error occurred and some drive letters could not be assigned.
+.
+
+MessageID=9913 SymbolicName=MSG_CANNOT_LOCK_FOR_COMMIT
+Language=English
+Disk Administrator could not lock all of the volumes affected by the changes selected. Please exit any applications holding references to the affected volumes and try again.
+.
+
+MessageID=9914 SymbolicName=MSG_ERROR_DURING_COMMIT
+Language=English
+Disk Administrator encountered an unknown error while making the requested changes. Some of the requested actions may not have occurred.
+.
+;#endif // _FDISKMSG_
diff --git a/private/utils/fdisk/fdlistbx.c b/private/utils/fdisk/fdlistbx.c
new file mode 100644
index 000000000..27ef39b61
--- /dev/null
+++ b/private/utils/fdisk/fdlistbx.c
@@ -0,0 +1,881 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ fdlistbx.c
+
+Abstract:
+
+ Routines for handling the subclassed owner-draw listbox used by NT fdisk
+ to display the state of attached disks.
+
+Author:
+
+ Ted Miller (tedm) 7-Jan-1992
+
+--*/
+
+#include "fdisk.h"
+
+// constants used when listbox or its focus rectangle is
+// scrolled/moved.
+
+#define DIR_NONE 0
+#define DIR_UP 1
+#define DIR_DN 2
+
+// original window procedure for our subclassed listbox
+
+WNDPROC OldListBoxProc;
+
+// item which has focus
+
+DWORD LBCursorListBoxItem,LBCursorRegion;
+
+BOOL LBCursorOn = FALSE;
+
+VOID
+ToggleLBCursor(
+ IN HDC hdc
+ );
+
+VOID
+ToggleRegion(
+ IN PDISKSTATE DiskState,
+ IN DWORD RegionIndex,
+ IN HDC hdc
+ );
+
+LONG
+ListBoxSubProc(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN DWORD wParam,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the window procedure used for our subclassed listbox.
+ We subclass the listbox so that we can handle keyboard input processing.
+ All other messages are passed through to the original listbox procedure.
+
+ Significant keys are arrows, pageup/dn, tab, space, return, home, and end.
+ Control may be used to modify space and return.
+ Shift may be used to modify tab.
+
+Arguments:
+
+ hwnd - window handle of listbox
+
+ msg - message #
+
+ wParam - user param # 1
+
+ lParam - user param # 2
+
+Return Value:
+
+ see below
+
+--*/
+
+{
+ int focusDir = DIR_NONE;
+ USHORT vKey;
+ DWORD maxRegion;
+ PDISKSTATE diskState;
+ LONG topItem,
+ bottomWholeItem,
+ visibleItems;
+ RECT rc;
+
+ switch (msg) {
+
+ case WM_CHAR:
+
+ break;
+
+ case WM_KEYDOWN:
+
+ switch (vKey = LOWORD(wParam)) {
+ case VK_LEFT:
+ case VK_RIGHT:
+ case VK_UP:
+ case VK_DOWN:
+
+ ToggleLBCursor(NULL);
+ switch (vKey) {
+ case VK_LEFT:
+ LBCursorRegion = LBCursorRegion ? LBCursorRegion-1 : 0;
+ break;
+ case VK_RIGHT:
+ maxRegion = Disks[LBCursorListBoxItem]->RegionCount - 1;
+ if (LBCursorRegion < maxRegion) {
+ LBCursorRegion++;
+ }
+ break;
+ case VK_UP:
+ if (LBCursorListBoxItem) {
+ LBCursorListBoxItem--;
+ LBCursorRegion = 0;
+ focusDir = DIR_UP;
+ }
+ break;
+ case VK_DOWN:
+ if (LBCursorListBoxItem < DiskCount-1) {
+ LBCursorListBoxItem++;
+ LBCursorRegion = 0;
+ focusDir = DIR_DN;
+ }
+ break;
+ }
+
+ // don't allow list box cursor to fall on extended partition
+
+ diskState = Disks[LBCursorListBoxItem];
+ maxRegion = diskState->RegionCount - 1;
+ if (IsExtended(diskState->RegionArray[LBCursorRegion].SysID)) {
+ if (LBCursorRegion && ((vKey == VK_LEFT) || (LBCursorRegion == maxRegion))) {
+ LBCursorRegion--;
+ } else {
+ LBCursorRegion++;
+ }
+ }
+
+ ToggleLBCursor(NULL);
+ break;
+
+ case VK_TAB:
+
+ ToggleLBCursor(NULL);
+
+ if (GetKeyState(VK_SHIFT) & ~1) { // shift-tab
+ LBCursorListBoxItem--;
+ focusDir = DIR_UP;
+ } else {
+ LBCursorListBoxItem++;
+ focusDir = DIR_DN;
+ }
+ if (LBCursorListBoxItem == (DWORD)(-1)) {
+ LBCursorListBoxItem = DiskCount-1;
+ focusDir = DIR_DN;
+ } else if (LBCursorListBoxItem == DiskCount) {
+ LBCursorListBoxItem = 0;
+ focusDir = DIR_UP;
+ }
+ ResetLBCursorRegion();
+
+ ToggleLBCursor(NULL);
+ break;
+
+ case VK_HOME:
+ case VK_END:
+
+ ToggleLBCursor(NULL);
+ topItem = (vKey == VK_HOME) ? 0 : DiskCount-1;
+ SendMessage(hwndList, LB_SETTOPINDEX, (DWORD)topItem, 0);
+ LBCursorListBoxItem = topItem;
+ ResetLBCursorRegion();
+ ToggleLBCursor(NULL);
+ break;
+
+ case VK_PRIOR:
+ case VK_NEXT:
+
+ ToggleLBCursor(NULL);
+ topItem = SendMessage(hwndList, LB_GETTOPINDEX, 0, 0);
+ GetClientRect(hwndList,&rc);
+ visibleItems = (rc.bottom - rc.top) / GraphHeight;
+ if (!visibleItems) {
+ visibleItems = 1;
+ }
+ topItem = (vKey == VK_PRIOR)
+ ? max(topItem - visibleItems, 0)
+ : min(topItem + visibleItems, (LONG)DiskCount-1);
+ SendMessage(hwndList, LB_SETTOPINDEX, (DWORD)topItem, 0);
+ LBCursorListBoxItem = SendMessage(hwndList, LB_GETTOPINDEX, 0, 0);
+ ResetLBCursorRegion();
+ ToggleLBCursor(NULL);
+ break;
+
+
+ case VK_RETURN:
+ case VK_SPACE:
+
+ // Select the region that currently has the list box selection cursor.
+
+ if (!Disks[LBCursorListBoxItem]->OffLine) {
+
+ Selection(GetKeyState(VK_CONTROL) & ~1, // strip toggle bit
+ Disks[LBCursorListBoxItem],
+ LBCursorRegion);
+ }
+ break;
+ }
+
+ // now scroll the newly focused item into view if necessary
+
+ switch (focusDir) {
+ case DIR_UP:
+ if (LBCursorListBoxItem < (DWORD)SendMessage(hwndList, LB_GETTOPINDEX, 0, 0)) {
+ SendMessage(hwndList, LB_SETTOPINDEX, LBCursorListBoxItem, 0);
+ }
+ break;
+ case DIR_DN:
+ GetClientRect(hwndList, &rc);
+ topItem = SendMessage(hwndList, LB_GETTOPINDEX, 0, 0);
+ bottomWholeItem = topItem + ((rc.bottom - rc.top) / GraphHeight) - 1;
+ if (bottomWholeItem < topItem) {
+ bottomWholeItem = topItem;
+ }
+ if ((DWORD)bottomWholeItem > DiskCount-1) {
+ bottomWholeItem = DiskCount-1;
+ }
+ if (LBCursorListBoxItem > (DWORD)bottomWholeItem) {
+ SendMessage(hwndList,
+ LB_SETTOPINDEX,
+ topItem + LBCursorListBoxItem - bottomWholeItem,
+ 0);
+ }
+ break;
+ }
+ break;
+
+ default:
+ return CallWindowProc(OldListBoxProc, hwnd, msg, wParam, lParam);
+ }
+ return 0;
+}
+
+VOID
+SubclassListBox(
+ IN HWND hwnd
+ )
+{
+ OldListBoxProc = (WNDPROC)GetWindowLong(hwnd, GWL_WNDPROC);
+ SetWindowLong(hwnd, GWL_WNDPROC, (LONG)ListBoxSubProc);
+
+ // There is a scantily documented 'feature' of a listbox wherein it will
+ // use its parent's DC. This means that drawing is not always clipped to
+ // the client area of the listbox. Seeing as we're subclassing listboxes
+ // anyway, take care of this here.
+
+ SetClassLong(hwnd, GCL_STYLE, GetClassLong(hwnd, GCL_STYLE) & ~CS_PARENTDC);
+}
+
+VOID
+DeselectSelectedRegions(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine visually unselects all selected regions. The selection
+ state is also updated in the master disk structures.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DWORD i,
+ j;
+ PDISKSTATE diskState;
+
+ for (i=0; i<DiskCount; i++) {
+ diskState = Disks[i];
+ for (j=0; j<diskState->RegionCount; j++) {
+ if (diskState->Selected[j]) {
+ diskState->Selected[j] = FALSE;
+ ToggleRegion(diskState, j, NULL);
+ }
+ }
+ }
+}
+
+VOID
+Selection(
+ IN BOOL MultipleSel,
+ IN PDISKSTATE DiskState,
+ IN DWORD RegionIndex
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles a user selection of a disk region. It is called
+ directly for a keyboard selection or indirectly for a mouse selection.
+ If not a multiple selection, all selected regions are deselected.
+ The focus rectangle is moved to the selected region, which is then
+ visually selected.
+
+Arguments:
+
+ MultipleSel - whether the user has made a multiple selection
+ (ie, control-clicked).
+
+ DiskState - master disk structure for disk containing selected region
+
+ RegionIndex - index of selected region on the disk
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PFT_OBJECT ftObject,
+ ftObj;
+ PFT_OBJECT_SET ftSet;
+ ULONG disk,
+ r;
+
+ if (!MultipleSel) {
+
+ // need to deselect all selected regions first.
+
+ DeselectSelectedRegions();
+ }
+
+ // remove the list box selection cursor from its previous region
+
+ ToggleLBCursor(NULL);
+
+ // The selected region might be part of an ft object set. If it is,
+ // scan each region in each disk and select each item in the set.
+
+ if (ftObject = GET_FT_OBJECT(&DiskState->RegionArray[RegionIndex])) {
+
+ ftSet = ftObject->Set;
+ for (disk=0; disk<DiskCount; disk++) {
+ PDISKSTATE diskState = Disks[disk];
+
+ for (r=0; r<diskState->RegionCount; r++) {
+ PREGION_DESCRIPTOR regionDescriptor = &diskState->RegionArray[r];
+
+ if (DmSignificantRegion(regionDescriptor)) {
+
+ if (ftObj = GET_FT_OBJECT(regionDescriptor)) {
+
+ if (ftObj->Set == ftSet) {
+
+ diskState->Selected[r] = (BOOLEAN)(!diskState->Selected[r]);
+ ToggleRegion(diskState, r, NULL);
+ }
+ }
+ }
+ }
+ }
+ } else {
+ DiskState->Selected[RegionIndex] = (BOOLEAN)(!DiskState->Selected[RegionIndex]);
+ ToggleRegion(DiskState, RegionIndex, NULL);
+ }
+
+ LBCursorListBoxItem = DiskState->Disk;
+ LBCursorRegion = RegionIndex;
+ ToggleLBCursor(NULL);
+ AdjustMenuAndStatus();
+}
+
+VOID
+MouseSelection(
+ IN BOOL MultipleSel,
+ IN OUT PPOINT Point
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the user clicks in the list box. It determines
+ which disk region the user has clicked on before calling the common
+ selection subroutine.
+
+Arguments:
+
+ MultipleSel - whether the user has made a multiple selection
+ (ie, control-clicked).
+
+ point - screen coords of the click
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDISKSTATE diskState;
+ DWORD selectedItem;
+ DWORD x,
+ y;
+ DWORD i;
+ RECT rc;
+ BOOL valid;
+
+ if ((selectedItem = SendMessage(hwndList, LB_GETCURSEL, 0, 0)) == LB_ERR) {
+ return;
+ }
+
+ // user has clicked on a list box item.
+
+ diskState = Disks[selectedItem];
+
+ // Ignore clicks on off-line disks.
+
+ if (diskState->OffLine) {
+ return;
+ }
+
+ ScreenToClient(hwndList, Point);
+
+ x = Point->x;
+ y = Point->y;
+ GetClientRect(hwndList,&rc);
+
+ // first make sure that the click was within a bar and not in space
+ // between two bars
+
+ for (valid=FALSE, i=rc.top; i<=(DWORD)rc.bottom; i+=GraphHeight) {
+ if ((y >= i+BarTopYOffset) && (y <= i+BarBottomYOffset)) {
+ valid = TRUE;
+ break;
+ }
+ }
+ if (!valid) {
+ return;
+ }
+
+ // determine which region he has clicked on
+
+ for (i=0; i<diskState->RegionCount; i++) {
+ if ((x >= (unsigned)diskState->LeftRight[i].Left) && (x <= (unsigned)diskState->LeftRight[i].Right)) {
+ break;
+ }
+ }
+ if (i == diskState->RegionCount) {
+ return; // region not found. Ignore the click.
+ }
+
+ Selection(MultipleSel, diskState, i);
+}
+
+LONG
+CalcBarTop(
+ DWORD Bar
+ )
+
+/*++
+
+Routine Description:
+
+ This routine calculates the current top y coord of a given bar.
+ The value is in listbox client coords.
+
+Arguments:
+
+ Bar - # of bar whose position is desired
+
+Return Value:
+
+ Y-coord, or -1 if bar is not visible.
+
+--*/
+
+{
+ LONG barDelta = (LONG)Bar - SendMessage(hwndList, LB_GETTOPINDEX, 0, 0);
+ LONG pos = -1;
+ RECT rc;
+
+ if (barDelta >= 0) { // BUGBUG check bottom too
+ GetClientRect(hwndList,&rc);
+ pos = rc.top + (barDelta * GraphHeight);
+ }
+ return pos;
+}
+
+VOID
+ResetLBCursorRegion(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine resets the list box focus cursor to the 0th (leftmost)
+ region on the current disk. If the 0th region is the extended
+ partition, focus is set to the first logical volume or free space
+ with the extended partition instead.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDISKSTATE diskState = Disks[LBCursorListBoxItem];
+ unsigned i;
+
+ LBCursorRegion = 0;
+ if (IsExtended(diskState->RegionArray[LBCursorRegion].SysID)) {
+ for (i=0; i<diskState->RegionCount; i++) {
+ if (diskState->RegionArray[i].RegionType == REGION_LOGICAL) {
+ LBCursorRegion = i;
+ return;
+ }
+ }
+ FDASSERT(0);
+ }
+}
+
+VOID
+ToggleLBCursor(
+ IN HDC hdc
+ )
+
+/*++
+
+Routine Description:
+
+ This routine visually toggles the focus state of the disk region
+ described by the LBCursorListBoxItem and LBCursorRegion globals.
+
+Arguments:
+
+ hdc - If non-NULL, device context to use for drawing. If NULL,
+ we'll first get a DC via GetDC().
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDISKSTATE lBCursorDisk = Disks[LBCursorListBoxItem];
+ LONG barTop = CalcBarTop(LBCursorListBoxItem);
+ RECT rc;
+ HDC hdcActual;
+
+ if (barTop != -1) {
+
+ hdcActual = hdc ? hdc : GetDC(hwndList);
+
+ LBCursorOn = !LBCursorOn;
+
+ rc.left = lBCursorDisk->LeftRight[LBCursorRegion].Left;
+ rc.right = lBCursorDisk->LeftRight[LBCursorRegion].Right + 1;
+ rc.top = barTop + BarTopYOffset;
+ rc.bottom = barTop + BarBottomYOffset;
+
+ FrameRect(hdcActual,
+ &rc,
+ GetStockObject(LBCursorOn ? WHITE_BRUSH : BLACK_BRUSH));
+
+ if (LBCursorOn) {
+
+ // BUGBUG really want a dotted line.
+ DrawFocusRect(hdcActual, &rc);
+ }
+
+ if (!hdc) {
+ ReleaseDC(hwndList, hdcActual);
+ }
+ }
+}
+
+VOID
+ForceLBRedraw(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine forces redraw of the listbox by invalidating its
+ entire client area.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ InvalidateRect(hwndList,NULL,FALSE);
+ UpdateWindow(hwndList);
+}
+
+VOID
+ToggleRegion(
+ IN PDISKSTATE DiskState,
+ IN DWORD RegionIndex,
+ IN HDC hdc
+ )
+
+/*++
+
+Routine Description:
+
+ This routine visually toggles the selection state of a given disk region.
+
+Arguments:
+
+ DiskState - master structure for disk containing region to select
+
+ RegionIndex - which region on the disk to toggle
+
+ hdc - if non-NULL, device context to use for drawing. If NULL, we'll
+ first get a device context via GetDC().
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLEFTRIGHT leftRight = &DiskState->LeftRight[RegionIndex];
+ LONG barTop = CalcBarTop(DiskState->Disk); // BUGBUG disk# as lb index#
+ BOOL selected = (BOOL)DiskState->Selected[RegionIndex];
+ HBRUSH hbr = GetStockObject(BLACK_BRUSH);
+ HDC hdcActual;
+ RECT rc;
+ int i;
+
+ if (barTop != -1) {
+
+ hdcActual = hdc ? hdc : GetDC(hwndList);
+
+ rc.left = leftRight->Left + 1;
+ rc.right = leftRight->Right;
+ rc.top = barTop + BarTopYOffset + 1;
+ rc.bottom = barTop + BarBottomYOffset - 1;
+
+ if (selected) {
+
+ for (i=0; i<SELECTION_THICKNESS; i++) {
+ FrameRect(hdcActual, &rc, hbr);
+ InflateRect(&rc, -1, -1);
+ }
+
+ } else {
+
+ // Blt the region from the off-screen bitmap onto the
+ // screen. But first exclude the center of the region
+ // from the clip region so we only blt the necessary bits.
+ // This sppeds up selections noticably.
+
+ InflateRect(&rc, -SELECTION_THICKNESS, -SELECTION_THICKNESS);
+ ExcludeClipRect(hdcActual, rc.left, rc.top, rc.right, rc.bottom);
+ BitBlt(hdcActual,
+ leftRight->Left,
+ barTop + BarTopYOffset,
+ leftRight->Right - leftRight->Left,
+ barTop + BarBottomYOffset,
+ DiskState->hDCMem,
+ leftRight->Left,
+ BarTopYOffset,
+ SRCCOPY);
+ }
+
+ if (!hdc) {
+ ReleaseDC(hwndList, hdcActual);
+ }
+ }
+}
+
+DWORD
+InitializeListBox(
+ IN HWND hwndListBox
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets up the list box. This includes creating disk state
+ structures, drawing the graphs for each disk off screen, and adding the
+ disks to the list box.
+
+ It also includes determining the initial volume labels and type names
+ for all significant partitions.
+
+Arguments:
+
+ hwndListBox - handle of the list box that will hold the disk graphs
+
+Return Value:
+
+ Windows error code (esp. out of memory)
+
+--*/
+
+{
+ PPERSISTENT_REGION_DATA regionData;
+ TCHAR windowsDir[MAX_PATH];
+ unsigned i;
+ PDISKSTATE diskState;
+ DWORD ec;
+ ULONG r;
+ BOOL diskSignaturesCreated,
+ temp;
+
+ // First, create the array that will hold the diskstates,
+ // the IsDiskRemovable array and the RemovableDiskReservedDriveLetters
+ // array.
+
+ Disks = Malloc(DiskCount * sizeof(PDISKSTATE));
+ IsDiskRemovable = (PBOOLEAN)Malloc(DiskCount * sizeof(BOOLEAN));
+ RemovableDiskReservedDriveLetters = (PCHAR)Malloc(DiskCount * sizeof(CHAR));
+
+ // Determine which disks are removable and which are unpartitioned.
+
+ for (i=0; i<DiskCount; i++) {
+
+ IsDiskRemovable[i] = IsRemovable( i );
+ }
+
+ // next, create all disk states
+
+ FDASSERT(DiskCount);
+ diskSignaturesCreated = FALSE;
+ for (i=0; i<DiskCount; i++) {
+
+ // first create the disk state structure
+
+ CreateDiskState(&diskState, i, &temp);
+ diskSignaturesCreated = diskSignaturesCreated || temp;
+
+ Disks[i] = diskState;
+
+ // next determine the state of the disk's partitioning scheme
+
+ DeterminePartitioningState(diskState);
+
+ // Next create a blank logical disk structure for each region.
+
+ for (r=0; r<diskState->RegionCount; r++) {
+ if (DmSignificantRegion(&diskState->RegionArray[r])) {
+ regionData = Malloc(sizeof(PERSISTENT_REGION_DATA));
+ DmInitPersistentRegionData(regionData, NULL, NULL, NULL, NO_DRIVE_LETTER_YET);
+ regionData->VolumeExists = TRUE;
+ } else {
+ regionData = NULL;
+ }
+ DmSetPersistentRegionData(&diskState->RegionArray[r], regionData);
+ }
+
+ // add the item to the listbox
+
+ while (((ec = SendMessage(hwndListBox, LB_ADDSTRING, 0, 0)) == LB_ERR) || (ec == LB_ERRSPACE)) {
+ ConfirmOutOfMemory();
+ }
+ }
+
+ // Read the configuration registry
+
+ if ((ec = InitializeFt(diskSignaturesCreated)) != NO_ERROR) {
+ ErrorDialog(ec);
+ return ec;
+ }
+
+ // Determine drive letter mappings
+
+ InitializeDriveLetterInfo();
+
+ // Determine volume labels and type names.
+
+ InitVolumeLabelsAndTypeNames();
+
+ // Determine which disk is the boot disk.
+
+ if (GetWindowsDirectory(windowsDir, sizeof(windowsDir)/sizeof(TCHAR)) < 2 ||
+ windowsDir[1] != TEXT(':')) {
+
+ BootDiskNumber = (ULONG)-1;
+ BootPartitionNumber = (ULONG)-1;
+ } else {
+ BootDiskNumber = GetDiskNumberFromDriveLetter((CHAR)windowsDir[0]);
+ BootPartitionNumber = GetPartitionNumberFromDriveLetter((CHAR)windowsDir[0]);
+ }
+
+ // Locate and create data structures for any DoubleSpace volumes
+
+ DblSpaceInitialize();
+
+ for (i=0; i<DiskCount; i++) {
+
+ DrawDiskBar(Disks[i]);
+ }
+
+ return NO_ERROR;
+}
+
+VOID
+WMDrawItem(
+ IN PDRAWITEMSTRUCT pDrawItem
+ )
+{
+ DWORD temp;
+ PDISKSTATE pDiskState;
+
+ if ((pDrawItem->itemID != (DWORD)(-1))
+ && (pDrawItem->itemAction == ODA_DRAWENTIRE)) {
+ pDiskState = Disks[pDrawItem->itemID];
+
+ // blt the disk's bar from the off-screen bitmap to the screen
+
+ BitBlt(pDrawItem->hDC,
+ pDrawItem->rcItem.left,
+ pDrawItem->rcItem.top,
+ pDrawItem->rcItem.right - pDrawItem->rcItem.left + 1,
+ pDrawItem->rcItem.bottom - pDrawItem->rcItem.top + 1,
+ pDiskState->hDCMem,
+ 0,
+ 0,
+ SRCCOPY);
+
+ // if we just overwrote the focus cursor, redraw it
+
+ if (pDrawItem->itemID == LBCursorListBoxItem) {
+ LBCursorOn = FALSE;
+ ToggleLBCursor(pDrawItem->hDC);
+ }
+
+ // select any items selected in this bar
+
+ for (temp=0; temp<pDiskState->RegionCount; temp++) {
+ if (pDiskState->Selected[temp]) {
+ ToggleRegion(pDiskState, temp, pDrawItem->hDC);
+ }
+ }
+ }
+}
diff --git a/private/utils/fdisk/fdmem.c b/private/utils/fdisk/fdmem.c
new file mode 100644
index 000000000..e370da50b
--- /dev/null
+++ b/private/utils/fdisk/fdmem.c
@@ -0,0 +1,77 @@
+#include "fdisk.h"
+#include <malloc.h>
+#include <process.h>
+
+
+
+PVOID
+Malloc(
+ IN ULONG Size
+ )
+{
+ PVOID p;
+
+ while((p = malloc(Size)) == NULL) {
+ ConfirmOutOfMemory();
+ }
+ return(p);
+}
+
+
+PVOID
+Realloc(
+ IN PVOID Block,
+ IN ULONG NewSize
+ )
+{
+ PVOID p;
+
+ if(NewSize) {
+ while((p = realloc(Block,NewSize)) == NULL) {
+ ConfirmOutOfMemory();
+ }
+ } else {
+
+ //
+ // realloc with a size of 0 is the same as free,
+ // so special case that here.
+ //
+
+ free(Block);
+ while((p = malloc(0)) == NULL) {
+ ConfirmOutOfMemory();
+ }
+ }
+ return(p);
+}
+
+
+VOID
+Free(
+ IN PVOID Block
+ )
+{
+ free(Block);
+}
+
+
+
+VOID
+ConfirmOutOfMemory(
+ VOID
+ )
+{
+ va_list arglist =
+#ifdef _ALPHA_
+ {0}; // Alpha defines va_list as a struct. Init as such.
+#else
+ NULL;
+#endif
+
+ if(CommonDialog(MSG_OUT_OF_MEMORY,
+ NULL,
+ MB_ICONHAND | MB_RETRYCANCEL | MB_SYSTEMMODAL,
+ arglist) != IDRETRY) {
+ exit(1);
+ }
+}
diff --git a/private/utils/fdisk/fdmisc.c b/private/utils/fdisk/fdmisc.c
new file mode 100644
index 000000000..dbee3c1a5
--- /dev/null
+++ b/private/utils/fdisk/fdmisc.c
@@ -0,0 +1,1579 @@
+/*++
+
+Copyright (c) 1990-1993 Microsoft Corporation
+
+Module Name:
+
+ fdmisc.c
+
+Abstract:
+
+ Miscellaneous routines for NT fdisk.
+
+Author:
+
+ Ted Miller (tedm) 7-Jan-1992
+
+Modifications:
+
+ 13-Dec-1993 (bobri) CdRom initialization support.
+
+--*/
+
+
+#include "fdisk.h"
+#include <process.h>
+
+extern HWND InitDlg;
+extern BOOLEAN StartedAsIcon;
+
+BOOL
+AllDisksOffLine(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Determine whether all hard disks are off line.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if all disks off-line, false otherwise.
+
+--*/
+
+{
+ ULONG i;
+
+ FDASSERT(DiskCount);
+
+ for (i=0; i<DiskCount; i++) {
+ if (!IsDiskOffLine(i)) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+
+VOID
+FdShutdownTheSystem(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to update the caller privilege, then shutdown the
+ Windows NT system. If it fails it prints a warning dialog. If it
+ succeeds then it doesn't return to the caller.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ NTSTATUS Status;
+ BOOLEAN PreviousPriv;
+
+ InfoDialog(MSG_MUST_REBOOT);
+ SetCursor(hcurWait);
+ WriteProfile();
+
+ // Enable shutdown privilege
+
+ Status = RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,
+ TRUE,
+ FALSE,
+ &PreviousPriv);
+
+#if DBG
+ if (Status) {
+ DbgPrint("DISKMAN: Status %lx attempting to enable shutdown privilege\n",Status);
+ }
+#endif
+
+ Sleep(3000);
+ if (!ExitWindowsEx(EWX_REBOOT,(DWORD)(-1))) {
+ WarningDialog(MSG_COULDNT_REBOOT);
+ }
+}
+
+
+LPTSTR
+LoadAString(
+ IN DWORD StringID
+ )
+
+/*++
+
+Routine Description:
+
+ Loads a string from the resource file and allocates a buffer of exactly
+ the right size to hold it.
+
+Arguments:
+
+ StringID - resource ID of string to load
+
+Return Value:
+
+ pointer to buffer. If string is not found, the first
+ (and only) char in the returned buffer will be 0.
+
+--*/
+
+{
+ TCHAR text[500];
+ LPTSTR buffer;
+
+ text[0] = 0;
+ LoadString(hModule, StringID, text, sizeof(text)/sizeof(TCHAR));
+ buffer = Malloc((lstrlen(text)+1)*sizeof(TCHAR));
+ lstrcpy(buffer, text);
+ return buffer;
+}
+
+
+PWSTR
+LoadWString(
+ IN DWORD StringID
+ )
+
+/*++
+
+Routine Description:
+
+ Loads a wide-char string from the resource file and allocates a
+ buffer of exactly the right size to hold it.
+
+Arguments:
+
+ StringID - resource ID of string to load
+
+Return Value:
+
+ pointer to buffer. If string is not found, the first
+ (and only) char in the returned buffer will be 0.
+
+--*/
+
+{
+ WCHAR text[500];
+ PWSTR buffer;
+
+ text[0] = 0;
+ LoadStringW(hModule, StringID, text, sizeof(text)/sizeof(WCHAR));
+ buffer = Malloc((lstrlenW(text)+1)*sizeof(WCHAR));
+ lstrcpyW(buffer, text);
+ return buffer;
+}
+
+
+int
+GetHeightFromPoints(
+ IN int Points
+ )
+
+/*++
+
+Routine Description:
+
+ This routine calculates the height of a font given a point value.
+ The calculation is based on 72 points per inch and the display's
+ pixels/inch device capability.
+
+Arguments:
+
+ Points - number of points
+
+Return Value:
+
+ pixel count (negative and therefore suitable for passing to
+ CreateFont())
+
+--*/
+
+{
+ HDC hdc = GetDC(NULL);
+ int height = MulDiv(-Points, GetDeviceCaps(hdc, LOGPIXELSY), 72);
+
+ ReleaseDC(NULL, hdc);
+ return height;
+}
+
+
+VOID
+UnicodeHack(
+ IN PCHAR Source,
+ OUT LPTSTR Dest
+ )
+
+/*++
+
+Routine Description:
+
+ Given a non-Unicode ASCII string, this routine will either convert it
+ to Unicode or copy it, depending on the current definition of TCHAR.
+ The 'conversion' is a simple hack that casts to TCHAR.
+
+Arguments:
+
+ Source - source (ansi ascii) string
+ Dest - destination string or wide string
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ int i;
+ int j = lstrlen(Source);
+
+ for (i=0; i<=j; i++) {
+ Dest[i] = (TCHAR)(UCHAR)Source[i];
+ }
+}
+
+
+VOID
+_RetreiveAndFormatMessage(
+ IN DWORD Msg,
+ OUT LPTSTR Buffer,
+ IN DWORD BufferSize,
+ IN va_list arglist
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ DWORD x;
+ TCHAR text[500];
+
+ // get message from system or app msg file.
+
+ x = FormatMessage( Msg >= MSG_FIRST_FDISK_MSG
+ ? FORMAT_MESSAGE_FROM_HMODULE
+ : FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ Msg,
+ 0,
+ Buffer,
+ BufferSize,
+ &arglist);
+
+ if (!x) { // couldn't find message
+
+ LoadString(hModule,
+ Msg >= MSG_FIRST_FDISK_MSG ? IDS_NOT_IN_APP_MSG_FILE : IDS_NOT_IN_SYS_MSG_FILE,
+ text,
+ sizeof(text)/sizeof(TCHAR));
+
+ wsprintf(Buffer, text, Msg);
+ }
+}
+
+
+DWORD
+CommonDialog(
+ IN DWORD MsgCode,
+ IN LPTSTR Caption,
+ IN DWORD Flags,
+ IN va_list arglist
+ )
+
+/*++
+
+Routine Description:
+
+ Simple dialog routine to get dialogs out of the resource
+ for the program and run them as a message box.
+
+Arguments:
+
+ MsgCode - dialog message code
+ Caption - message box caption
+ Flags - standard message box flags
+ arglist - list to be given when pulling the message text
+
+Return Value:
+
+ The MessageBox() return value
+
+--*/
+
+{
+ TCHAR MsgBuf[MESSAGE_BUFFER_SIZE];
+
+ if (!StartedAsIcon) {
+// Flags |= MB_SETFOREGROUND;
+ }
+
+ if (InitDlg) {
+
+ PostMessage(InitDlg,
+ (WM_USER + 1),
+ 0,
+ 0);
+ InitDlg = (HWND) 0;
+ }
+ _RetreiveAndFormatMessage(MsgCode, MsgBuf, sizeof(MsgBuf), arglist);
+ return MessageBox(GetActiveWindow(), MsgBuf, Caption, Flags);
+}
+
+
+VOID
+ErrorDialog(
+ IN DWORD ErrorCode,
+ ...
+ )
+
+/*++
+
+-Routine Description:
+
+ This routine retreives a message from the app or system message file
+ and displays it in a message box.
+
+Arguments:
+
+ ErrorCode - number of message
+
+ ... - strings for insertion into message
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ va_list arglist;
+
+ va_start(arglist, ErrorCode);
+ CommonDialog(ErrorCode, NULL, MB_ICONHAND | MB_OK | MB_SYSTEMMODAL, arglist);
+ va_end(arglist);
+}
+
+
+
+
+VOID
+WarningDialog(
+ IN DWORD MsgCode,
+ ...
+ )
+
+/*++
+
+Routine Description:
+
+ This routine retreives a message from the app or system message file
+ and displays it in a message box.
+
+Arguments:
+
+ MsgCode - number of message
+
+ ... - strings for insertion into message
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ TCHAR Caption[100];
+ va_list arglist;
+
+ va_start(arglist, MsgCode);
+ LoadString(hModule, IDS_APPNAME, Caption, sizeof(Caption)/sizeof(TCHAR));
+ CommonDialog(MsgCode, Caption, MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL, arglist);
+ va_end(arglist);
+}
+
+
+DWORD
+ConfirmationDialog(
+ IN DWORD MsgCode,
+ IN DWORD Flags,
+ ...
+ )
+
+/*++
+
+Routine Description:
+
+ Support for a simple confirmation dialog
+
+Arguments:
+
+ MsgCode - resource code for message
+ Flags - dialog flags
+
+Return Value:
+
+ Result from the CommonDialog() performed.
+
+--*/
+
+{
+ TCHAR Caption[100];
+ DWORD x;
+ va_list arglist;
+
+ va_start(arglist, Flags);
+ LoadString(hModule, IDS_CONFIRM, Caption, sizeof(Caption)/sizeof(TCHAR));
+ x = CommonDialog(MsgCode, Caption, Flags | MB_TASKMODAL, arglist);
+ va_end(arglist);
+ return x;
+}
+
+
+VOID
+InfoDialog(
+ IN DWORD MsgCode,
+ ...
+ )
+
+/*++
+
+Routine Description:
+
+ This routine retreives a message from the app or system message file
+ and displays it in a message box.
+
+Arguments:
+
+ MsgCode - number of message
+
+ ... - strings for insertion into message
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ TCHAR Caption[100];
+ va_list arglist;
+
+ va_start(arglist, MsgCode);
+ LoadString(hModule, IDS_APPNAME, Caption, sizeof(Caption)/sizeof(TCHAR));
+ CommonDialog(MsgCode, Caption, MB_ICONINFORMATION | MB_OK | MB_TASKMODAL, arglist);
+ va_end(arglist);
+}
+
+PREGION_DESCRIPTOR
+LocateRegionForFtObject(
+ IN PFT_OBJECT FtObject
+ )
+
+/*++
+
+Routine Description:
+
+ Given an FtObject, find the associated region descriptor
+
+Arguments:
+
+ FtObject - the ft object to search for.
+
+Return Value:
+
+ NULL - no descriptor found
+ !NULL - a pointer to the region descriptor for the FT object
+
+++*/
+
+{
+ PDISKSTATE diskState;
+ PREGION_DESCRIPTOR regionDescriptor;
+ DWORD disk,
+ region;
+ PPERSISTENT_REGION_DATA regionData;
+
+ for (disk = 0; disk < DiskCount; disk++) {
+
+ diskState = Disks[disk];
+
+ for (region = 0; region < diskState->RegionCount; region++) {
+
+ regionDescriptor = &diskState->RegionArray[region];
+ regionData = PERSISTENT_DATA(regionDescriptor);
+
+ if (regionData) {
+ if (regionData->FtObject == FtObject) {
+ return regionDescriptor;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+VOID
+InitVolumeLabelsAndTypeNames(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Determine the volume label and type name for each significant
+ (non-extended, non-free, recognized) partition.
+
+ Assumes that persistent data has already been set up, and drive letters
+ determined.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DWORD disk,
+ region;
+ PDISKSTATE ds;
+ PREGION_DESCRIPTOR rd;
+ PPERSISTENT_REGION_DATA regionData;
+ WCHAR diskName[4];
+ WCHAR volumeLabel[100];
+ WCHAR typeName[100];
+ UINT errorMode;
+
+ lstrcpyW(diskName, L"x:\\");
+
+ for (disk=0; disk<DiskCount; disk++) {
+
+ ds = Disks[disk];
+
+ for (region=0; region<ds->RegionCount; region++) {
+
+ rd = &ds->RegionArray[region];
+
+ if (DmSignificantRegion(rd)) {
+
+ // If the region has a drive letter, use the drive letter
+ // to get the info via the Windows API. Otherwise we'll
+ // have to use the NT API.
+
+ regionData = PERSISTENT_DATA(rd);
+
+ if (!regionData) {
+ continue;
+ }
+
+ if ((regionData->DriveLetter == NO_DRIVE_LETTER_YET)
+ || (regionData->DriveLetter == NO_DRIVE_LETTER_EVER)) {
+ PWSTR tempLabel,
+ tempName;
+
+ // No drive letter. Use NT API.
+ // If this is an FT set use the zero member disk for the
+ // call so all members get the right type and label
+
+ if (regionData->FtObject) {
+ PFT_OBJECT searchFtObject;
+
+ // Want to get rd pointing to the zeroth member
+
+ searchFtObject = regionData->FtObject->Set->Member0;
+
+ // Now search regions for this match
+
+ rd = LocateRegionForFtObject(searchFtObject);
+
+ if (!rd) {
+ continue;
+ }
+ }
+
+ if (GetVolumeLabel(rd->Disk, rd->PartitionNumber, &tempLabel) == NO_ERROR) {
+ lstrcpyW(volumeLabel, tempLabel);
+ Free(tempLabel);
+ } else {
+ *volumeLabel = 0;
+ }
+
+ if (GetTypeName(rd->Disk, rd->PartitionNumber, &tempName) == NO_ERROR) {
+ lstrcpyW(typeName, tempName);
+ Free(tempName);
+ } else {
+ lstrcpyW(typeName, wszUnknown);
+ }
+
+ } else {
+
+ // Use Windows API.
+
+ diskName[0] = (WCHAR)(UCHAR)regionData->DriveLetter;
+
+ errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+ if (!GetVolumeInformationW(diskName, volumeLabel, sizeof(volumeLabel)/2, NULL, NULL, NULL, typeName, sizeof(typeName)/2)) {
+ lstrcpyW(typeName, wszUnknown);
+ *volumeLabel = 0;
+ }
+ SetErrorMode(errorMode);
+ }
+
+ if (!lstrcmpiW(typeName, L"raw")) {
+ lstrcpyW(typeName, wszUnknown);
+ }
+
+ regionData->TypeName = Malloc((lstrlenW(typeName) + 1) * sizeof(WCHAR));
+ regionData->VolumeLabel = Malloc((lstrlenW(volumeLabel) + 1) * sizeof(WCHAR));
+
+ lstrcpyW(regionData->TypeName, typeName);
+ lstrcpyW(regionData->VolumeLabel, volumeLabel);
+ }
+ }
+ }
+}
+
+
+VOID
+DetermineRegionInfo(
+ IN PREGION_DESCRIPTOR Region,
+ OUT PWSTR *TypeName,
+ OUT PWSTR *VolumeLabel,
+ OUT PWCH DriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ For a given region, fetch the persistent data, appropriately modified
+ depending on whether the region is used or free, recognized, etc.
+
+Arguments:
+
+ Region - supplies a pointer to the region whose data is to be fetched.
+
+ TypeName - receives a pointer to the type name. If the region is
+ unrecognized, the type is determined based on the system id of
+ the partition.
+
+ VolumeLabel - receives a pointer to the volume label. If the region is
+ free space or unrecognized, the volume label is "".
+
+ DriveLetter - receices the drive letter. If the region is free space
+ or unrecognized, the drive letter is ' ' (space).
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PWSTR typeName,
+ volumeLabel;
+ WCHAR driveLetter;
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(Region);
+
+ if (DmSignificantRegion(Region)) {
+
+ typeName = regionData->TypeName;
+ volumeLabel = regionData->VolumeLabel;
+ driveLetter = (WCHAR)(UCHAR)regionData->DriveLetter;
+ if ((driveLetter == NO_DRIVE_LETTER_YET) || (driveLetter == NO_DRIVE_LETTER_EVER)) {
+ driveLetter = L' ';
+ }
+ } else {
+ typeName = GetWideSysIDName(Region->SysID);
+ volumeLabel = L"";
+ driveLetter = L' ';
+ }
+
+ *TypeName = typeName;
+ *VolumeLabel = volumeLabel;
+ *DriveLetter = driveLetter;
+}
+
+
+PREGION_DESCRIPTOR
+RegionFromFtObject(
+ IN PFT_OBJECT FtObject
+ )
+
+/*++
+
+Routine Description:
+
+ Given an ft object, determine which region it belongs to. The algorithm
+ is brute force -- look at each region on each disk until a match is found.
+
+Arguments:
+
+ FtObject - ft member whose region is to be located.
+
+Return Value:
+
+ pointer to region descriptor
+
+--*/
+
+{
+ PREGION_DESCRIPTOR reg;
+ DWORD region,
+ disk;
+ PDISKSTATE ds;
+
+ for (disk=0; disk<DiskCount; disk++) {
+
+ ds = Disks[disk];
+
+ for (region=0; region<ds->RegionCount; region++) {
+
+ reg = &ds->RegionArray[region];
+
+ if (DmSignificantRegion(reg) && (GET_FT_OBJECT(reg) == FtObject)) {
+
+ return reg;
+ }
+ }
+ }
+ return NULL;
+}
+
+
+//
+// For each drive letter, these arrays hold the disk and partition number
+// the the drive letter is linked to.
+//
+
+#define M1 ((unsigned)(-1))
+
+unsigned
+DriveLetterDiskNumbers[26] = { M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,
+ M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,M1
+ },
+
+DriveLetterPartitionNumbers[24] = { M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,
+ M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,M1,M1
+ };
+
+#undef M1
+
+//
+// Drive letter usage map. Bit n set means that drive letter 'C'+n is in use.
+//
+
+ULONG DriveLetterUsageMap = 0;
+
+#define DRIVELETTERBIT(letter) (1 << (unsigned)((UCHAR)letter-(UCHAR)'C'))
+
+#define SetDriveLetterUsed(letter) DriveLetterUsageMap |= DRIVELETTERBIT(letter)
+#define SetDriveLetterFree(letter) DriveLetterUsageMap &= (~DRIVELETTERBIT(letter))
+#define IsDriveLetterUsed(letter) (DriveLetterUsageMap & DRIVELETTERBIT(letter))
+
+
+CHAR
+GetAvailableDriveLetter(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Scan the drive letter usage bitmap and return the next available
+ drive letter. May also mark the drivee letter used.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The next available drive letter, or 0 if all are used.
+
+--*/
+
+{
+ CHAR driveLetter;
+
+ FDASSERT(!(DriveLetterUsageMap & 0xff000000));
+ for (driveLetter = 'C'; driveLetter <= 'Z'; driveLetter++) {
+ if (!IsDriveLetterUsed(driveLetter)) {
+ return driveLetter;
+ }
+ }
+ return 0;
+}
+
+
+VOID
+MarkDriveLetterUsed(
+ IN CHAR DriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ Given an ASCII drive letter, mark it in the usage map as being used.
+
+Arguments:
+
+ DriveLetter - the letter to mark
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ FDASSERT(!(DriveLetterUsageMap & 0xff000000));
+ if ((DriveLetter != NO_DRIVE_LETTER_YET) && (DriveLetter != NO_DRIVE_LETTER_EVER)) {
+ SetDriveLetterUsed(DriveLetter);
+ }
+}
+
+VOID
+MarkDriveLetterFree(
+ IN CHAR DriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ Given a drive letter, remove it from the usage map, thereby making it available
+ for reuse.
+
+Arguments:
+
+ Drive Letter - the letter to free
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ FDASSERT(!(DriveLetterUsageMap & 0xff000000));
+ if ((DriveLetter != NO_DRIVE_LETTER_YET) && (DriveLetter != NO_DRIVE_LETTER_EVER)) {
+ SetDriveLetterFree(DriveLetter);
+ }
+}
+
+BOOL
+DriveLetterIsAvailable(
+ IN CHAR DriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ Determine if the drive letter given is available for use.
+
+Arguments:
+
+ DriveLetter - the letter to check in the usage map
+
+Return Value:
+
+ TRUE if it is free and can be used.
+ FALSE if it is currently in use.
+
+--*/
+
+{
+ FDASSERT(!(DriveLetterUsageMap & 0xff000000));
+ FDASSERT((DriveLetter != NO_DRIVE_LETTER_YET) && (DriveLetter != NO_DRIVE_LETTER_EVER));
+ return !IsDriveLetterUsed(DriveLetter);
+}
+
+BOOL
+AllDriveLettersAreUsed(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Determine if all possible drive letters are in use.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ TRUE if all letters are in use - FALSE otherwise
+
+--*/
+
+{
+ FDASSERT(!(DriveLetterUsageMap & 0xff000000));
+ return(DriveLetterUsageMap == 0x00ffffff);
+}
+
+ULONG
+GetDiskNumberFromDriveLetter(
+ IN CHAR DriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ Given a drive letter return the disk number that contains the partition
+ that is the drive letter.
+
+Arguments:
+
+ DriveLetter - the drive letter to check.
+
+Return Value:
+
+ -1 if the letter is invalid.
+ The disk number for the drive letter if it is valid.
+
+--*/
+
+{
+ DriveLetter = toupper( DriveLetter );
+
+ if (DriveLetter >= 'C' && DriveLetter <= 'Z') {
+ return DriveLetterDiskNumbers[ DriveLetter - 'C' ];
+ } else {
+ return (ULONG)(-1);
+ }
+}
+
+ULONG
+GetPartitionNumberFromDriveLetter(
+ IN CHAR DriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ Given a drive letter return the numeric value for the partition that
+ the letter is associated with.
+
+Arguments:
+
+ DriveLetter - the letter in question.
+
+Return Value:
+
+ -1 if letter is invalid
+ Partition number for partition that is the drive letter
+
+--*/
+
+{
+ DriveLetter = toupper( DriveLetter );
+
+ if (DriveLetter >= 'C' && DriveLetter <= 'Z') {
+ return DriveLetterPartitionNumbers[ DriveLetter - 'C' ];
+ } else {
+ return (ULONG)(-1);
+ }
+}
+
+
+CHAR
+LocateDriveLetterFromDiskAndPartition(
+ IN ULONG Disk,
+ IN ULONG Partition
+ )
+
+/*++
+
+Routine Description:
+
+ Given a disk and partition number return the drive letter assigned to it.
+
+Arguments:
+
+ Disk - the disk index
+ Partition - the partition index
+
+Return Value:
+
+ The drive letter for the specific partition or
+ NO_DRIVE_LETTER_YET if it is not assigned a letter.
+
+--*/
+
+{
+ unsigned i;
+
+ for (i=0; i<24; i++) {
+
+ if (Disk == DriveLetterDiskNumbers[i] &&
+ Partition == DriveLetterPartitionNumbers[i]) {
+
+ return((CHAR)(i+(unsigned)(UCHAR)'C'));
+ }
+ }
+ return NO_DRIVE_LETTER_YET;
+}
+
+CHAR
+LocateDriveLetter(
+ IN PREGION_DESCRIPTOR Region
+ )
+
+/*++
+
+Routine Description:
+
+ Return the drive letter associated to a region.
+
+Arguments:
+
+ Region - the region wanted.
+
+Return Value:
+
+ The drive letter or NO_DRIVE_LETTER_YET
+
+--*/
+
+{
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(Region);
+
+ if (regionData) {
+ if (regionData->FtObject) {
+ if (regionData->DriveLetter) {
+ return regionData->DriveLetter;
+ }
+ }
+ }
+
+ return LocateDriveLetterFromDiskAndPartition(Region->Disk,
+ Region->OriginalPartitionNumber);
+}
+
+
+#define IsDigitW(digit) (((digit) >= L'0') && ((digit) <= L'9'))
+
+VOID
+InitializeDriveLetterInfo(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Initialze all of the external support structures for drive letter maintainence.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ WCHAR DriveLetterW;
+ CHAR DriveLetter = '\0';
+ PWSTR LinkTarget;
+ WCHAR DosDevicesName[sizeof(L"\\DosDevices\\A:")];
+ int DiskNo,
+ PartNo;
+ PWSTR Pattern,
+ String;
+ DWORD x,
+ ec;
+ PFT_OBJECT FtObject;
+ PFT_OBJECT_SET FtSet;
+ PREGION_DESCRIPTOR Region;
+
+ // Construct list of drives with pagefiles
+
+ LoadExistingPageFileInfo();
+
+ // Initialize network information.
+
+ NetworkInitialize();
+
+ // For each drive letter c-z, query the symbolic link.
+
+ for (DriveLetterW=L'C'; DriveLetterW<=L'Z'; DriveLetterW++) {
+
+ wsprintfW(DosDevicesName, L"%ws%wc:", L"\\DosDevices\\", DriveLetterW);
+
+ if ((ec = GetDriveLetterLinkTarget(DosDevicesName, &LinkTarget)) == NO_ERROR) {
+
+ // Check if it is a Cdrom
+
+ if (_wcsnicmp(LinkTarget, L"\\Device\\CdRom", 13) == 0) {
+
+ // Save the information on this CdRom away
+
+ CdRomAddDevice(LinkTarget, DriveLetterW);
+ }
+
+ // The drive letter is used because it is linked to something,
+ // even if we can't figure out what. So mark it used here.
+
+ SetDriveLetterUsed(DriveLetterW);
+ CharUpperW(LinkTarget);
+ Pattern = L"\\DEVICE\\HARDDISK";
+ String = LinkTarget;
+
+ // Attempt to match the '\device\harddisk' part
+
+ for (x=0; x < (sizeof(L"\\DEVICE\\HARDDISK") / sizeof(WCHAR)) - 1; x++) {
+ if (*Pattern++ != *String++) {
+ goto next_letter;
+ }
+ }
+
+ // Now get the hard disk #
+
+ if (!IsDigitW(*String)) {
+ continue;
+ }
+
+ DiskNo = 0;
+ while (IsDigitW(*String)) {
+ DiskNo = (DiskNo * 10) + (*String - L'0');
+ *String++;
+ }
+
+ // Attempt to match the '\partition' part
+
+ Pattern = L"\\PARTITION";
+ for (x=0; x < (sizeof(L"\\PARTITION") / sizeof(WCHAR)) - 1; x++) {
+ if (*Pattern++ != *String++) {
+ goto next_letter;
+ }
+ }
+
+ // Now get the partition #, which cannot be 0
+
+ PartNo = 0;
+ while (IsDigitW(*String)) {
+ PartNo = (PartNo * 10) + (*String - L'0');
+ *String++;
+ }
+
+ if (!PartNo) {
+ continue;
+ }
+
+ // Make sure there is nothing left in the link target's name
+
+ if (*String) {
+ continue;
+ }
+
+ // We understand the link target. Store the disk and partition.
+
+ DriveLetterDiskNumbers[DriveLetterW-L'C'] = DiskNo;
+ DriveLetterPartitionNumbers[DriveLetterW-L'C'] = PartNo;
+ } else {
+ if (ec == ERROR_ACCESS_DENIED) {
+ ErrorDialog(MSG_ACCESS_DENIED);
+
+ // BUGBUG When system and workstation manager are the same
+ // thing, then we'd never have gotten here. We can't just
+ // send a WM_DESTROY message to hwndFrame because we're not
+ // in the message loop here -- we end up doing a bunch of
+ // processing before the quit message is pulled our of the
+ // queue. So just exit.
+
+ SendMessage(hwndFrame,WM_DESTROY,0,0);
+ exit(1);
+ }
+ }
+ next_letter:
+ {}
+ }
+
+ // Now for each non-ft, significant region on each disk, figure out its
+ // drive letter.
+
+ for (x=0; x<DiskCount; x++) {
+
+ PDISKSTATE ds = Disks[x];
+ unsigned reg;
+
+ for (reg=0; reg<ds->RegionCount; reg++) {
+
+ PREGION_DESCRIPTOR region = &ds->RegionArray[reg];
+
+ if (DmSignificantRegion(region)) {
+
+ // Handle drive letters for FT sets specially.
+
+ if (!GET_FT_OBJECT(region)) {
+ PERSISTENT_DATA(region)->DriveLetter = LocateDriveLetter(region);
+ }
+ }
+ }
+
+ // If this is a removable disk, record the reserved drive
+ // letter for that disk.
+
+ if (IsDiskRemovable[x]) {
+ RemovableDiskReservedDriveLetters[x] = LocateDriveLetterFromDiskAndPartition(x, 1);
+ } else {
+ RemovableDiskReservedDriveLetters[x] = NO_DRIVE_LETTER_YET;
+ }
+ }
+
+ // Now handle ft sets. For each set, loop through the objects twice.
+ // On the first pass, figure out which object actually is linked to the
+ // drive letter. On the second pass, assign the drive letter found to
+ // each of the objects in the set.
+
+ for (FtSet = FtObjects; FtSet; FtSet = FtSet->Next) {
+
+ for (FtObject = FtSet->Members; FtObject; FtObject = FtObject->Next) {
+
+ Region = RegionFromFtObject(FtObject);
+
+ if (Region) {
+ if ((DriveLetter = LocateDriveLetter(Region)) != NO_DRIVE_LETTER_YET) {
+ break;
+ }
+ }
+ }
+
+ for (FtObject = FtSet->Members; FtObject; FtObject = FtObject->Next) {
+
+ Region = RegionFromFtObject(FtObject);
+
+ if (Region) {
+ PERSISTENT_DATA(Region)->DriveLetter = DriveLetter;
+ }
+ }
+ }
+}
+
+
+#if DBG
+
+VOID
+FdiskAssertFailedRoutine(
+ IN char *Expression,
+ IN char *FileName,
+ IN int LineNumber
+ )
+
+/*++
+
+Routine Description:
+
+ Routine that is called when an assertion fails in the debug version.
+ Throw up a list box giving appriopriate information and terminate
+ the program.
+
+Arguments:
+
+ Source - source (ansi ascii) string
+ Dest - destination string or wide string
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ char text[500];
+
+ wsprintf(text,
+ "Line #%u in File '%s'\n[%s]\n\nClick OK to exit.",
+ LineNumber,
+ FileName,
+ Expression
+ );
+
+ MessageBoxA(NULL,text,"Assertion Failure",MB_TASKMODAL | MB_OK);
+ exit(1);
+}
+
+
+#include <stdio.h>
+
+PVOID LogFile;
+int LoggingLevel = 1000;
+
+
+VOID
+InitLogging(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Open the log file for debug logging.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ LogFile = (PVOID)fopen("c:\\fdisk.log","wt");
+ if(LogFile == NULL) {
+ MessageBox(GetActiveWindow(),"Can't open log file; logging turned off","DEBUG",MB_SYSTEMMODAL|MB_OK);
+ LoggingLevel = -1;
+ }
+}
+
+
+VOID
+FdLog(
+ IN int Level,
+ IN PCHAR FormatString,
+ ...
+ )
+
+/*++
+
+Routine Description:
+
+ Write a line into the log file for debugging.
+
+Arguments:
+
+ Debug level and "printf" like argument string.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ va_list arglist;
+
+ if(Level <= LoggingLevel) {
+
+ va_start(arglist,FormatString);
+
+ if(vfprintf((FILE *)LogFile,FormatString,arglist) < 0) {
+ LoggingLevel = -1;
+ MessageBox(GetActiveWindow(),"Error writing to log file; logging turned off","DEBUG",MB_SYSTEMMODAL|MB_OK);
+ fclose((FILE *)LogFile);
+ } else {
+ fflush((FILE *)LogFile);
+ }
+
+ va_end(arglist);
+ }
+}
+
+
+VOID
+LOG_DISK_REGISTRY(
+ IN PCHAR RoutineName,
+ IN PDISK_REGISTRY DiskRegistry
+ )
+
+/*++
+
+Routine Description:
+
+ Log what was in the disk registry into the debugging log file.
+
+Arguments:
+
+ RoutineName - calling routines name
+ DiskRegistry - registry information for disks
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG i;
+ PDISK_DESCRIPTION diskDesc;
+
+ FDLOG((2,"%s: %u disks; registry info follows:\n",RoutineName,DiskRegistry->NumberOfDisks));
+
+ diskDesc = DiskRegistry->Disks;
+
+ for(i=0; i<DiskRegistry->NumberOfDisks; i++) {
+ LOG_ONE_DISK_REGISTRY_DISK_ENTRY(NULL,diskDesc);
+ diskDesc = (PDISK_DESCRIPTION)&diskDesc->Partitions[diskDesc->NumberOfPartitions];
+ }
+}
+
+
+VOID
+LOG_ONE_DISK_REGISTRY_DISK_ENTRY(
+ IN PCHAR RoutineName OPTIONAL,
+ IN PDISK_DESCRIPTION DiskDescription
+ )
+
+/*++
+
+Routine Description:
+
+ This routine walks through the partition information from
+ the registry for a single disk and writes lines in the
+ debugging log file.
+
+Arguments:
+
+ RoutineName - the name of the calling routine
+ DiskDescription - the disk description portion of the registry
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ USHORT j;
+ PDISK_PARTITION partDesc;
+ PDISK_DESCRIPTION diskDesc = DiskDescription;
+
+ if(ARGUMENT_PRESENT(RoutineName)) {
+ FDLOG((2,"%s: disk registry entry follows:\n",RoutineName));
+ }
+
+ FDLOG((2," Disk signature : %08lx\n",diskDesc->Signature));
+ FDLOG((2," Partition count: %u\n",diskDesc->NumberOfPartitions));
+ if(diskDesc->NumberOfPartitions) {
+ FDLOG((2," # Dr FtTyp FtGrp FtMem Start Length\n"));
+ }
+
+ for(j=0; j<diskDesc->NumberOfPartitions; j++) {
+
+ CHAR dr1,dr2;
+
+ partDesc = &diskDesc->Partitions[j];
+
+ if(partDesc->AssignDriveLetter) {
+
+ if(partDesc->DriveLetter) {
+ dr1 = partDesc->DriveLetter;
+ dr2 = ':';
+ } else {
+ dr1 = dr2 = ' ';
+ }
+
+ } else {
+ dr1 = 'n';
+ dr2 = 'o';
+ }
+
+ FDLOG((2,
+ " %02u %c%c %-5u %-5u %-5u %08lx:%08lx %08lx:%08lx\n",
+ partDesc->LogicalNumber,
+ dr1,dr2,
+ partDesc->FtType,
+ partDesc->FtGroup,
+ partDesc->FtMember,
+ partDesc->StartingOffset.HighPart,
+ partDesc->StartingOffset.LowPart,
+ partDesc->Length.HighPart,
+ partDesc->Length.LowPart
+ ));
+ }
+}
+
+
+VOID
+LOG_DRIVE_LAYOUT(
+ IN PDRIVE_LAYOUT_INFORMATION DriveLayout
+ )
+
+/*++
+
+Routine Description:
+
+ Write the drive layout into the debugging log file.
+
+Arguments:
+
+ DriveLayout - the layout to write
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG i;
+
+ FDLOG((2," Disk signature : %08lx\n",DriveLayout->Signature));
+ FDLOG((2," Partition count: %u\n",DriveLayout->PartitionCount));
+
+ for(i=0; i<DriveLayout->PartitionCount; i++) {
+
+ if(!i) {
+ FDLOG((2," ID Active Recog Start Size Hidden\n"));
+ }
+
+ FDLOG((2,
+ " %02x %s %s %08lx:%08lx %08lx:%08lx %08lx\n",
+ DriveLayout->PartitionEntry[i].PartitionType,
+ DriveLayout->PartitionEntry[i].BootIndicator ? "yes" : "no ",
+ DriveLayout->PartitionEntry[i].RecognizedPartition ? "yes" : "no ",
+ DriveLayout->PartitionEntry[i].StartingOffset.HighPart,
+ DriveLayout->PartitionEntry[i].StartingOffset.LowPart,
+ DriveLayout->PartitionEntry[i].PartitionLength.HighPart,
+ DriveLayout->PartitionEntry[i].PartitionLength.LowPart,
+ DriveLayout->PartitionEntry[i].HiddenSectors
+ ));
+ }
+
+}
+
+#endif
diff --git a/private/utils/fdisk/fdprof.c b/private/utils/fdisk/fdprof.c
new file mode 100644
index 000000000..c31876b5a
--- /dev/null
+++ b/private/utils/fdisk/fdprof.c
@@ -0,0 +1,212 @@
+#include "fdisk.h"
+#include <stdio.h>
+
+
+int ProfileWindowX,
+ ProfileWindowY,
+ ProfileWindowW,
+ ProfileWindowH;
+
+BOOL ProfileIsMaximized,ProfileIsIconic;
+
+#ifdef JAPAN
+//Don't use IDS_APPNAME as registry key,
+//because it is also used window's caption and it was localized.
+CHAR SectionName[] = "Disk Administrator";
+#else
+CHAR SectionName[80];
+#endif
+
+CHAR szWindowPosition[] = "WindowPosition";
+CHAR szWindowMaximized[] = "WindowMaximized";
+CHAR szWindowIconic[] = "WindowIconic";
+CHAR szWindowPosFormatString[] = "%d,%d,%d,%d";
+CHAR szStatusBar[] = "StatusBar";
+CHAR szLegend[] = "Legend";
+CHAR szElementN[] = "Element %u Color/Pattern";
+
+
+VOID
+WriteProfile(
+ VOID
+ )
+{
+ CHAR SectionLocation[128], SectionMapping[128];
+ HKEY Key1, Key2;
+ RECT rc;
+ CHAR text[100],text2[100];
+ int i;
+ DWORD Disposition;
+ LONG Err;
+
+
+#ifdef JAPAN
+//Don't use IDS_APPNAME as registry key,
+//because it is also used window's caption and it was localized.
+#else
+ LoadStringA(hModule,IDS_APPNAME,SectionName,sizeof(SectionName));
+#endif
+
+ // Make sure that the appropriate registry keys exits:
+ //
+ // windisk.ini key:
+ //
+ Err = RegCreateKeyExA( HKEY_LOCAL_MACHINE,
+ "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\IniFileMapping\\windisk.ini",
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_WRITE,
+ NULL,
+ &Key1,
+ &Disposition );
+
+ if( Err != ERROR_SUCCESS ) {
+
+ return;
+ }
+
+ if( Disposition == REG_CREATED_NEW_KEY ) {
+
+ // We need to set up the registry keys for the INI mapping.
+ // First, create the Disk Administrator value on the windisk.ini
+ // key, which indicates the location of the key which maps
+ // the Disk Administrator section.
+ //
+ strcpy( SectionLocation, "Software\\Microsoft\\" );
+ strcat( SectionLocation, SectionName );
+
+ strcpy( SectionMapping, "USR:" );
+ strcat( SectionMapping, SectionLocation );
+
+ Err = RegSetValueEx( Key1,
+ SectionName,
+ 0,
+ REG_SZ,
+ SectionMapping,
+ strlen( SectionMapping ) + 1 );
+
+ if( Err != ERROR_SUCCESS ) {
+
+ RegCloseKey( Key1 );
+ return;
+ }
+
+ // Now create the key to which the section mapping points:
+ //
+ Err = RegCreateKeyEx( HKEY_CURRENT_USER,
+ SectionLocation,
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_WRITE,
+ NULL,
+ &Key2,
+ &Disposition );
+
+ RegCloseKey( Key2 );
+ }
+
+ RegCloseKey( Key1 );
+
+
+ // OK, the registry location is set up. Write the initialization
+ // information.
+ //
+
+ // write window position
+
+ GetWindowRect(hwndFrame,&rc);
+ wsprintf(text,
+ szWindowPosFormatString,
+ ProfileWindowX,
+ ProfileWindowY,
+ ProfileWindowW,
+ ProfileWindowH
+ );
+ WritePrivateProfileStringA(SectionName,szWindowPosition,text,"windisk.ini");
+ wsprintf(text,"%u",IsZoomed(hwndFrame));
+ WritePrivateProfileStringA(SectionName,szWindowMaximized,text,"windisk.ini");
+ wsprintf(text,"%u",IsIconic(hwndFrame));
+ WritePrivateProfileStringA(SectionName,szWindowIconic,text,"windisk.ini");
+
+ // status bar and legend stuff
+
+ wsprintf(text,
+ "%u",
+ StatusBar
+ );
+ WritePrivateProfileStringA(SectionName,szStatusBar,text,"windisk.ini");
+
+ wsprintf(text,
+ "%u",
+ Legend
+ );
+ WritePrivateProfileStringA(SectionName,szLegend,text,"windisk.ini");
+
+ // disk graph colors/patterns
+
+ for(i=0; i<LEGEND_STRING_COUNT; i++) {
+ wsprintf(text2,szElementN,i);
+ wsprintf(text,"%u/%u",BrushColors[i],BrushHatches[i]);
+ WritePrivateProfileStringA(SectionName,text2,text,"windisk.ini");
+ }
+}
+
+
+VOID
+ReadProfile(
+ VOID
+ )
+{
+ CHAR text[100],text2[100];
+ int i;
+
+#ifdef JAPAN
+//Don't use IDS_APPNAME as registry key,
+//because it is also used window's caption and it was localized.
+#else
+ LoadStringA(hModule,IDS_APPNAME,SectionName,sizeof(SectionName));
+#endif
+
+ // get the window position data
+
+ ProfileIsMaximized = GetPrivateProfileIntA(SectionName,szWindowMaximized,0,"windisk.ini");
+ ProfileIsIconic = GetPrivateProfileIntA(SectionName,szWindowIconic ,0,"windisk.ini");
+
+ *text = 0;
+ if(GetPrivateProfileStringA(SectionName,szWindowPosition,"",text,sizeof(text),"windisk.ini")
+ && *text)
+ {
+ sscanf(text,
+ szWindowPosFormatString,
+ &ProfileWindowX,
+ &ProfileWindowY,
+ &ProfileWindowW,
+ &ProfileWindowH
+ );
+ } else {
+ ProfileWindowX = CW_USEDEFAULT;
+ ProfileWindowY = 0;
+ ProfileWindowW = CW_USEDEFAULT;
+ ProfileWindowH = 0;
+ }
+
+ // status bar and legend stuff
+
+ StatusBar = GetPrivateProfileIntA(SectionName,szStatusBar,1,"windisk.ini");
+ Legend = GetPrivateProfileIntA(SectionName,szLegend ,1,"windisk.ini");
+
+ // disk graph colors/patterns
+
+ for(i=0; i<LEGEND_STRING_COUNT; i++) {
+ wsprintf(text2,szElementN,i);
+ *text = 0;
+ if(GetPrivateProfileStringA(SectionName,text2,"",text,sizeof(text),"windisk.ini") && *text) {
+ sscanf(text,"%u/%u",&BrushColors[i],&BrushHatches[i]);
+ if( BrushHatches[i] >= NUM_AVAILABLE_HATCHES ) {
+ BrushHatches[i] = NUM_AVAILABLE_HATCHES - 1;
+ }
+ }
+ }
+}
diff --git a/private/utils/fdisk/fdproto.h b/private/utils/fdisk/fdproto.h
new file mode 100644
index 000000000..5a1fb7e94
--- /dev/null
+++ b/private/utils/fdisk/fdproto.h
@@ -0,0 +1,1301 @@
+/*++
+
+Copyright (c) 1990-1994 Microsoft Corporation
+
+Module Name:
+
+ fdproto.h
+
+Abstract:
+
+ Function prototypes.
+
+Author:
+
+ Ted Miller (tedm) 7-Jan-1992
+
+Revision:
+
+ Bob Rinne (bobri) 2-Feb-1994
+ Moved definitions from ArcInst here to get rid of dependency with
+ that source project.
+
+--*/
+
+// stuff in fdengine.c
+
+BOOLEAN
+SignatureIsUniqueToSystem(
+ IN ULONG Disk,
+ IN ULONG Signature
+ );
+
+VOID
+FdSetDiskSignature(
+ IN ULONG Disk,
+ IN ULONG Signature
+ );
+
+ULONG
+FdGetDiskSignature(
+ IN ULONG Disk
+ );
+
+BOOLEAN
+IsDiskOffLine(
+ IN ULONG Disk
+ );
+
+BOOLEAN
+IsRegionCommitted(
+ PREGION_DESCRIPTOR RegionDescriptor
+ );
+
+BOOLEAN
+ChangeCommittedOnDisk(
+ IN ULONG Disk
+ );
+
+VOID
+ClearCommittedDiskInformation(
+ );
+
+// stuff in fdisk.c
+
+LONG
+MyFrameWndProc(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN UINT wParam,
+ IN LONG lParam
+ );
+
+VOID
+DeterminePartitioningState(
+ IN OUT PDISKSTATE DiskState
+ );
+
+VOID
+DrawDiskBar(
+ IN PDISKSTATE DiskState
+ );
+
+VOID
+AdjustMenuAndStatus(
+ VOID
+ );
+
+// stuff in fdinit.c
+
+BOOL
+InitializeApp(
+ VOID
+ );
+
+VOID
+CreateDiskState(
+ OUT PDISKSTATE *DiskState,
+ IN DWORD Disk,
+ OUT PBOOL SignatureCreated
+ );
+
+#if DBG && DEVL
+
+VOID
+StartThread2(
+ VOID
+ );
+
+#endif
+
+VOID
+DisplayInitializationMessage(
+ VOID
+ );
+
+// stuff in fdlistbx.c
+
+VOID
+Selection(
+ IN BOOL MultipleSel,
+ IN PDISKSTATE DiskState,
+ IN DWORD region
+ );
+
+VOID
+MouseSelection(
+ IN BOOL MultipleSel,
+ IN OUT PPOINT point
+ );
+
+VOID
+SubclassListBox(
+ IN HWND hwnd
+ );
+
+DWORD
+InitializeListBox(
+ IN HWND hwndListBox
+ );
+
+VOID
+ResetLBCursorRegion(
+ VOID
+ );
+
+VOID
+WMDrawItem(
+ IN PDRAWITEMSTRUCT pDrawItem
+ );
+
+VOID
+ForceLBRedraw(
+ VOID
+ );
+
+
+// stuff in fdmisc.c
+
+BOOL
+AllDisksOffLine(
+ VOID
+ );
+
+VOID
+FdShutdownTheSystem(
+ VOID
+ );
+
+LPTSTR
+LoadAString(
+ IN DWORD StringID
+ );
+
+PWSTR
+LoadWString(
+ IN DWORD StringID
+ );
+
+int
+GetHeightFromPoints(
+ IN int Points
+ );
+
+VOID
+UnicodeHack(
+ IN PCHAR Source,
+ OUT LPTSTR Dest
+ );
+
+VOID
+TotalRedrawAndRepaint(
+ VOID
+ );
+
+DWORD
+CommonDialog(
+ IN DWORD MsgCode,
+ IN LPTSTR Caption,
+ IN DWORD Flags,
+ IN va_list arglist
+ );
+
+VOID
+ErrorDialog(
+ IN DWORD ErrorCode,
+ ...
+ );
+
+VOID
+WarningDialog(
+ IN DWORD MsgCode,
+ ...
+ );
+
+DWORD
+ConfirmationDialog(
+ IN DWORD MsgCode,
+ IN DWORD Flags,
+ ...
+ );
+
+VOID
+InfoDialog(
+ IN DWORD MsgCode,
+ ...
+ );
+
+VOID
+InitVolumeLabelsAndTypeNames(
+ VOID
+ );
+
+VOID
+DetermineRegionInfo(
+ IN PREGION_DESCRIPTOR Region,
+ OUT PWSTR *TypeName,
+ OUT PWSTR *VolumeLabel,
+ OUT PWCH DriveLetter
+ );
+
+VOID
+InitializeDriveLetterInfo(
+ VOID
+ );
+
+CHAR
+GetAvailableDriveLetter(
+ VOID
+ );
+
+VOID
+MarkDriveLetterUsed(
+ IN CHAR DriveLetter
+ );
+
+VOID
+MarkDriveLetterFree(
+ IN CHAR DriveLetter
+ );
+
+BOOL
+DriveLetterIsAvailable(
+ IN CHAR DriveLetter
+ );
+
+BOOL
+AllDriveLettersAreUsed(
+ VOID
+ );
+
+ULONG
+GetDiskNumberFromDriveLetter(
+ IN CHAR DriveLetter
+ );
+
+ULONG
+GetPartitionNumberFromDriveLetter(
+ IN CHAR DriveLetter
+ );
+
+PREGION_DESCRIPTOR
+LocateRegionForFtObject(
+ IN PFT_OBJECT FtObject
+ );
+
+#if DBG
+
+VOID
+FdiskAssertFailedRoutine(
+ IN char *Expression,
+ IN char *FileName,
+ IN int LineNumber
+ );
+
+#endif
+
+
+// stuff in fddlgs.c
+
+VOID
+CenterDialog(
+ HWND hwnd
+ );
+
+VOID
+SubclassListBox(
+ IN HWND hwnd
+ );
+
+BOOL
+MinMaxDlgProc(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN DWORD wParam,
+ IN LONG lParam
+ );
+
+BOOL
+DriveLetterDlgProc(
+ IN HWND hdlg,
+ IN DWORD msg,
+ IN DWORD wParam,
+ IN LONG lParam
+ );
+
+BOOL
+ColorDlgProc(
+ IN HWND hdlg,
+ IN DWORD msg,
+ IN DWORD wParam,
+ IN LONG lParam
+ );
+
+BOOL
+DisplayOptionsDlgProc(
+ IN HWND hdlg,
+ IN UINT msg,
+ IN DWORD wParam,
+ IN LONG lParam
+ );
+
+VOID
+InitRectControl(
+ VOID
+ );
+
+
+// Format and label support routines - dmfmifs.c
+
+VOID
+FormatPartition(
+ PREGION_DESCRIPTOR RegionDescriptor
+ );
+
+VOID
+LabelPartition(
+ PREGION_DESCRIPTOR RegionDescriptor
+ );
+
+INT
+FormatDlgProc(
+ IN HWND hDlg,
+ IN UINT wMsg,
+ IN WPARAM wParam,
+ IN LONG lParam
+ );
+
+INT
+LabelDlgProc(
+ IN HWND hDlg,
+ IN UINT wMsg,
+ IN WPARAM wParam,
+ IN LONG lParam
+ );
+
+BOOL
+CancelDlgProc(
+ IN HWND hDlg,
+ IN UINT wMsg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+VOID
+UnloadIfsDll(
+ VOID
+ );
+
+// stuff in fdmem.c
+
+PVOID
+Malloc(
+ IN ULONG Size
+ );
+
+PVOID
+Realloc(
+ IN PVOID Block,
+ IN ULONG NewSize
+ );
+
+VOID
+Free(
+ IN PVOID Block
+ );
+
+VOID
+ConfirmOutOfMemory(
+ VOID
+ );
+
+
+// stuff in fdstleg.c
+
+VOID
+UpdateStatusBarDisplay(
+ VOID
+ );
+
+VOID
+ClearStatusArea(
+ VOID
+ );
+
+VOID
+DrawLegend(
+ IN HDC hdc,
+ IN PRECT rc
+ );
+
+VOID
+DrawStatusAreaItem(
+ IN PRECT rc,
+ IN HDC hdc,
+ IN LPTSTR Text,
+ IN BOOL Unicode
+ );
+
+
+// stuff in fdprof.c
+
+VOID
+WriteProfile(
+ VOID
+ );
+
+VOID
+ReadProfile(
+ VOID
+ );
+
+
+// stuff in fdft.c
+
+ULONG
+InitializeFt(
+ IN BOOL DiskSignaturesCreated
+ );
+
+ULONG
+SaveFt(
+ VOID
+ );
+
+VOID
+FdftCreateFtObjectSet(
+ IN FT_TYPE FtType,
+ IN PREGION_DESCRIPTOR *Regions,
+ IN DWORD RegionCount,
+ IN FT_SET_STATUS Status
+ );
+
+BOOL
+FdftUpdateFtObjectSet(
+ IN PFT_OBJECT_SET FtSet,
+ IN FT_SET_STATUS SetState
+ );
+
+VOID
+FdftDeleteFtObjectSet(
+ IN PFT_OBJECT_SET FtSet,
+ IN BOOL OffLineDisksOnly
+ );
+
+BOOLEAN
+NewConfigurationRequiresFt(
+ VOID
+ );
+
+VOID
+FdftExtendFtObjectSet(
+ IN OUT PFT_OBJECT_SET FtSet,
+ IN OUT PREGION_DESCRIPTOR* Regions,
+ IN DWORD RegionCount
+ );
+
+DWORD
+FdftNextOrdinal(
+ IN FT_TYPE FtType
+ );
+
+// commit.c
+
+VOID
+FtConfigure(
+ VOID
+ );
+
+VOID
+CommitAssignLetterList(
+ VOID
+ );
+
+VOID
+CommitToAssignLetterList(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN BOOL MoveLetter
+ );
+
+VOID
+CommitAllChanges(
+ IN PVOID Param
+ );
+
+VOID
+CommitDeleteLockLetter(
+ IN CHAR DriveLetter
+ );
+
+BOOL
+CommitAllowed(
+ VOID
+ );
+
+
+VOID
+RescanDevices(
+ VOID
+ );
+
+// Commit interface routines.
+
+LETTER_ASSIGNMENT_RESULT
+CommitDriveLetter(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN CHAR OldDrive,
+ IN CHAR NewDrive
+ );
+
+LONG
+CommitToLockList(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN BOOL RemoveDriveLetter,
+ IN BOOL LockNow,
+ IN BOOL FailOk
+ );
+
+LONG
+CommitLockVolumes(
+ IN ULONG Disk
+ );
+
+LONG
+CommitUnlockVolumes(
+ IN ULONG Disk,
+ IN BOOLEAN FreeList
+ );
+
+VOID
+CommitUpdateRegionStructures(
+ VOID
+ );
+
+// windisk.c
+
+INT
+SizeDlgProc(
+ IN HWND hDlg,
+ IN UINT wMsg,
+ IN WPARAM wParam,
+ IN LONG lParam
+ );
+
+extern WNDPROC OldSizeDlgProc;
+
+DWORD
+CommitChanges(
+ VOID
+ );
+
+BOOLEAN
+BootPartitionNumberChanged(
+ PULONG OldNumber,
+ PULONG NewNumber
+ );
+
+DWORD
+DeletionIsAllowed(
+ IN PREGION_DESCRIPTOR Region
+ );
+
+BOOL
+RegisterFileSystemExtend(
+ VOID
+ );
+
+// stuff in fd_nt.c
+
+BOOLEAN
+IsPagefileOnDrive(
+ CHAR DriveLetter
+ );
+
+VOID
+LoadExistingPageFileInfo(
+ IN VOID
+ );
+
+BOOLEAN
+GetVolumeSizeMB(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ OUT PULONG Size
+ );
+
+ULONG
+GetVolumeTypeAndSize(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ OUT PWSTR *Label,
+ OUT PWSTR *Type,
+ OUT PULONG Size
+ );
+
+PWSTR
+GetWideSysIDName(
+ IN UCHAR SysID
+ );
+
+ULONG
+MyDiskRegistryGet(
+ OUT PDISK_REGISTRY *DiskRegistry
+ );
+
+ULONG
+MasterBootCode(
+ IN ULONG Disk,
+ IN ULONG Signature,
+ IN BOOLEAN SetBootCode,
+ IN BOOLEAN SetSignature
+ );
+
+ULONG
+UpdateMasterBootCode(
+ IN ULONG Disk
+ );
+
+ULONG
+FormDiskSignature(
+ VOID
+ );
+
+ULONG
+GetVolumeLabel(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ OUT PWSTR *Label
+ );
+
+ULONG
+GetTypeName(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ OUT PWSTR *Name
+ );
+
+BOOLEAN
+IsRemovable(
+ IN ULONG DiskNumber
+ );
+
+ULONG
+GetDriveLetterLinkTarget(
+ IN PWSTR SourceNameStr,
+ OUT PWSTR *LinkTarget
+ );
+
+#if i386
+VOID
+MakePartitionActive(
+ IN PREGION_DESCRIPTOR DiskRegionArray,
+ IN ULONG RegionCount,
+ IN ULONG RegionIndex
+ );
+#endif
+
+
+// stuff in arrowin.c
+
+BOOL
+RegisterArrowClass(
+ IN HANDLE hModule
+ );
+
+
+// stuff in fdhelp.c
+
+VOID
+InitHelp(
+ VOID
+ );
+
+VOID
+TermHelp(
+ VOID
+ );
+
+VOID
+Help(
+ IN LONG Code
+ );
+
+VOID
+DialogHelp(
+ IN DWORD HelpId
+ );
+
+VOID
+SetMenuItemHelpContext(
+ IN LONG wParam,
+ IN DWORD lParam
+ );
+
+
+// stuff in ftreg.c
+
+BOOL
+DoMigratePreviousFtConfig(
+ VOID
+ );
+
+BOOL
+DoRestoreFtConfig(
+ VOID
+ );
+
+VOID
+DoSaveFtConfig(
+ VOID
+ );
+
+
+// Double Space support routines.
+
+BOOL
+DblSpaceVolumeExists(
+ IN PREGION_DESCRIPTOR RegionDescriptor
+ );
+
+BOOL
+DblSpaceDismountedVolumeExists(
+ IN PREGION_DESCRIPTOR RegionDescriptor
+ );
+
+BOOLEAN
+DblSpaceCreate(
+ IN HWND Dialog,
+ IN PVOID Param
+ );
+
+VOID
+DblSpaceDelete(
+ IN PVOID Param
+ );
+
+VOID
+DblSpaceMount(
+ IN PVOID Param
+ );
+
+VOID
+DblSpaceDismount(
+ IN PVOID Param
+ );
+
+VOID
+DblSpaceInitialize(
+ VOID
+ );
+
+VOID
+DblSpace(
+ IN HWND Dialog,
+ IN PVOID Param
+ );
+
+PDBLSPACE_DESCRIPTOR
+DblSpaceGetNextVolume(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN PDBLSPACE_DESCRIPTOR DblSpace
+ );
+
+// FmIfs interface routines
+
+BOOL
+LoadIfsDll(
+ VOID
+ );
+
+BOOL
+FmIfsDismountDblspace(
+ IN CHAR DriveLetter
+ );
+
+BOOL
+FmIfsMountDblspace(
+ IN PCHAR FileName,
+ IN CHAR HostDrive,
+ IN CHAR NewDrive
+ );
+
+BOOLEAN
+FmIfsQueryInformation(
+ IN PWSTR DosDriveName,
+ OUT PBOOLEAN IsRemovable,
+ OUT PBOOLEAN IsFloppy,
+ OUT PBOOLEAN IsCompressed,
+ OUT PBOOLEAN Error,
+ OUT PWSTR NtDriveName,
+ IN ULONG MaxNtDriveNameLength,
+ OUT PWSTR CvfFileName,
+ IN ULONG MaxCvfFileNameLength,
+ OUT PWSTR HostDriveName,
+ IN ULONG MaxHostDriveNameLength
+ );
+
+
+// Cdrom interface routines.
+
+VOID
+CdRom(
+ IN HWND Dialog,
+ IN PVOID Param
+ );
+
+VOID
+CdRomAddDevice(
+ IN PWSTR NtName,
+ IN WCHAR DriveLetter
+ );
+
+//
+// Macros
+//
+
+//
+// BOOLEAN
+// DmSignificantRegion(
+// IN PREGION_DESCRIPTOR Region
+// );
+//
+
+#define DmSignificantRegion(Region) (((Region)->SysID != SYSID_UNUSED) \
+ && (!IsExtended((Region)->SysID)) \
+ && (IsRecognizedPartition((Region)->SysID)))
+
+//
+// VOID
+// DmSetPersistentRegionData(
+// IN PPERSISTENT_REGION_DATA RegionData
+// );
+//
+
+#define DmSetPersistentRegionData(Region,RegionData) \
+ FdSetPersistentData((Region),(ULONG)RegionData); \
+ (Region)->PersistentData = RegionData
+
+
+//
+// VOID
+// DmInitPersistentRegionData(
+// OUT PPERSISTENT_REGION_DATA RegionData,
+// IN PFT_OBJECT ftObject,
+// IN PWSTR volumeLabel,
+// IN PWSTR typeName,
+// IN CHAR driveLetter,
+// );
+//
+
+#define DmInitPersistentRegionData(RegionData,ftObject,volumeLabel,typeName,driveLetter) \
+ RegionData->DblSpace = NULL; \
+ RegionData->FtObject = ftObject; \
+ RegionData->VolumeLabel = volumeLabel; \
+ RegionData->TypeName = typeName; \
+ RegionData->VolumeExists = FALSE; \
+ RegionData->DriveLetter = driveLetter
+
+// ntlow definitions
+
+STATUS_CODE
+LowOpenNtName(
+ IN PCHAR Name,
+ IN HANDLE_PT Handle
+ );
+
+STATUS_CODE
+LowOpenDisk(
+ IN PCHAR DevicePath,
+ OUT HANDLE_PT DiskId
+ );
+
+STATUS_CODE
+LowOpenPartition(
+ IN PCHAR DevicePath,
+ IN ULONG Partition,
+ OUT HANDLE_PT Handle
+ );
+
+STATUS_CODE
+LowOpenDriveLetter(
+ IN CHAR DriveLetter,
+ IN HANDLE_PT Handle
+ );
+
+STATUS_CODE
+LowCloseDisk(
+ IN HANDLE_T DiskId
+ );
+
+STATUS_CODE
+LowGetDriveGeometry(
+ IN PCHAR DevicePath,
+ OUT PULONG TotalSectorCount,
+ OUT PULONG SectorSize,
+ OUT PULONG SectorsPerTrack,
+ OUT PULONG Heads
+ );
+
+STATUS_CODE
+LowGetPartitionGeometry(
+ IN PCHAR PartitionPath,
+ OUT PULONG TotalSectorCount,
+ OUT PULONG SectorSize,
+ OUT PULONG SectorsPerTrack,
+ OUT PULONG Heads
+ );
+
+STATUS_CODE
+LowReadSectors(
+ IN HANDLE_T VolumeId,
+ IN ULONG SectorSize,
+ IN ULONG StartingSector,
+ IN ULONG NumberOfSectors,
+ OUT PVOID Buffer
+ );
+
+STATUS_CODE
+LowWriteSectors(
+ IN HANDLE_T VolumeId,
+ IN ULONG SectorSize,
+ IN ULONG StartingSector,
+ IN ULONG NumberOfSectors,
+ IN PVOID Buffer
+ );
+
+STATUS_CODE
+LowLockDrive(
+ IN HANDLE_T DiskId
+ );
+
+STATUS_CODE
+LowUnlockDrive(
+ IN HANDLE_T DiskId
+ );
+
+STATUS_CODE
+LowFtVolumeStatus(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ IN PFT_SET_STATUS FtStatus,
+ IN PULONG NumberOfMembers
+ );
+
+STATUS_CODE
+LowFtVolumeStatusByLetter(
+ IN CHAR DriveLetter,
+ IN PFT_SET_STATUS FtStatus,
+ IN PULONG NumberOfMembers
+ );
+
+STATUS_CODE
+LowSetDiskLayout(
+ IN PCHAR Path,
+ IN PDRIVE_LAYOUT_INFORMATION DriveLayout
+ );
+
+STATUS_CODE
+LowGetDiskLayout(
+ IN PCHAR Path,
+ OUT PDRIVE_LAYOUT_INFORMATION *DriveLayout
+ );
+
+// Partition engine definitions
+
+ULONG
+GetDiskCount(
+ VOID
+ );
+
+PCHAR
+GetDiskName(
+ ULONG Disk
+ );
+
+ULONG
+DiskSizeMB(
+ IN ULONG Disk
+ );
+
+STATUS_CODE
+GetDiskRegions(
+ IN ULONG Disk,
+ IN BOOLEAN WantUsedRegions,
+ IN BOOLEAN WantFreeRegions,
+ IN BOOLEAN WantPrimaryRegions,
+ IN BOOLEAN WantLogicalRegions,
+ OUT PREGION_DESCRIPTOR *Region,
+ OUT ULONG *RegionCount
+ );
+
+#define GetAllDiskRegions(disk,regions,count) \
+ GetDiskRegions(disk,TRUE,TRUE,TRUE,TRUE,regions,count)
+
+#define GetFreeDiskRegions(disk,regions,count) \
+ GetDiskRegions(disk,FALSE,TRUE,TRUE,TRUE,regions,count)
+
+#define GetUsedDiskRegions(disk,regions,count) \
+ GetDiskRegions(disk,TRUE,FALSE,TRUE,TRUE,regions,count)
+
+#define GetPrimaryDiskRegions(disk,regions,count) \
+ GetDiskRegions(disk,TRUE,TRUE,TRUE,FALSE,regions,count)
+
+#define GetLogicalDiskRegions(disk,regions,count) \
+ GetDiskRegions(disk,TRUE,TRUE,FALSE,TRUE,regions,count)
+
+#define GetUsedPrimaryDiskRegions(disk,regions,count) \
+ GetDiskRegions(disk,TRUE,FALSE,TRUE,FALSE,regions,count)
+
+#define GetUsedLogicalDiskRegions(disk,regions,count) \
+ GetDiskRegions(disk,TRUE,FALSE,FALSE,TRUE,regions,count)
+
+#define GetFreePrimaryDiskRegions(disk,regions,count) \
+ GetDiskRegions(disk,FALSE,TRUE,TRUE,FALSE,regions,count)
+
+#define GetFreeLogicalDiskRegions(disk,regions,count) \
+ GetDiskRegions(disk,FALSE,TRUE,FALSE,TRUE,regions,count)
+
+VOID
+FreeRegionArray(
+ IN PREGION_DESCRIPTOR Region,
+ IN ULONG RegionCount
+ );
+
+STATUS_CODE
+IsAnyCreationAllowed(
+ IN ULONG Disk,
+ IN BOOLEAN AllowMultiplePrimaries,
+ OUT PBOOLEAN AnyAllowed,
+ OUT PBOOLEAN PrimaryAllowed,
+ OUT PBOOLEAN ExtendedAllowed,
+ OUT PBOOLEAN LogicalAllowed
+ );
+
+STATUS_CODE
+IsCreationOfPrimaryAllowed(
+ IN ULONG Disk,
+ IN BOOLEAN AllowMultiplePrimaries,
+ OUT PBOOLEAN Allowed
+ );
+
+STATUS_CODE
+IsCreationOfExtendedAllowed(
+ IN ULONG Disk,
+ OUT PBOOLEAN Allowed
+ );
+
+STATUS_CODE
+IsCreationOfLogicalAllowed(
+ IN ULONG Disk,
+ OUT PBOOLEAN Allowed
+ );
+
+STATUS_CODE
+DoesAnyPartitionExist(
+ IN ULONG Disk,
+ OUT PBOOLEAN AnyExists,
+ OUT PBOOLEAN PrimaryExists,
+ OUT PBOOLEAN ExtendedExists,
+ OUT PBOOLEAN LogicalExists
+ );
+
+STATUS_CODE
+DoesAnyPrimaryExist(
+ IN ULONG Disk,
+ OUT PBOOLEAN Exists
+ );
+
+STATUS_CODE
+DoesExtendedExist(
+ IN ULONG Disk,
+ OUT PBOOLEAN Exists
+ );
+
+STATUS_CODE
+DoesAnyLogicalExist(
+ IN ULONG Disk,
+ OUT PBOOLEAN Exists
+ );
+
+BOOLEAN
+IsExtended(
+ IN UCHAR SysID
+ );
+
+VOID
+SetPartitionActiveFlag(
+ IN PREGION_DESCRIPTOR Region,
+ IN UCHAR value
+ );
+
+STATUS_CODE
+CreatePartition(
+ IN PREGION_DESCRIPTOR Region,
+ IN ULONG CreationSizeMB,
+ IN REGION_TYPE Type
+ );
+
+STATUS_CODE
+CreatePartitionEx(
+ IN PREGION_DESCRIPTOR Region,
+ IN LARGE_INTEGER MinimumSize,
+ IN ULONG CreationSizeMB,
+ IN REGION_TYPE Type,
+ IN UCHAR SysId
+ );
+
+STATUS_CODE
+DeletePartition(
+ IN PREGION_DESCRIPTOR Region
+ );
+
+ULONG
+GetHiddenSectorCount(
+ ULONG Disk,
+ ULONG Partition
+ );
+
+VOID
+SetSysID(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ IN UCHAR SysID
+ );
+
+VOID
+SetSysID2(
+ IN PREGION_DESCRIPTOR Region,
+ IN UCHAR SysID
+ );
+
+PCHAR
+GetSysIDName(
+ UCHAR SysID
+ );
+
+STATUS_CODE
+CommitPartitionChanges(
+ IN ULONG Disk
+ );
+
+BOOLEAN
+HavePartitionsBeenChanged(
+ IN ULONG Disk
+ );
+
+VOID
+FdMarkDiskDirty(
+ IN ULONG Disk
+ );
+
+VOID
+FdSetPersistentData(
+ IN PREGION_DESCRIPTOR Region,
+ IN ULONG Data
+ );
+
+ULONG
+FdGetMinimumSizeMB(
+ IN ULONG Disk
+ );
+
+ULONG
+FdGetMaximumSizeMB(
+ IN PREGION_DESCRIPTOR Region,
+ IN REGION_TYPE CreationType
+ );
+
+LARGE_INTEGER
+FdGetExactSize(
+ IN PREGION_DESCRIPTOR Region,
+ IN BOOLEAN ForExtended
+ );
+
+LARGE_INTEGER
+FdGetExactOffset(
+ IN PREGION_DESCRIPTOR Region
+ );
+
+BOOLEAN
+FdCrosses1024Cylinder(
+ IN PREGION_DESCRIPTOR Region,
+ IN ULONG CreationSizeMB,
+ IN REGION_TYPE RegionType
+ );
+
+ULONG
+FdGetDiskSignature(
+ IN ULONG Disk
+ );
+
+VOID
+FdSetDiskSignature(
+ IN ULONG Disk,
+ IN ULONG Signature
+ );
+
+BOOLEAN
+IsDiskOffLine(
+ IN ULONG Disk
+ );
+
+
+STATUS_CODE
+FdiskInitialize(
+ VOID
+ );
+
+VOID
+FdiskCleanUp(
+ VOID
+ );
+
+VOID
+ConfigureSystemPartitions(
+ VOID
+ );
+
+
+VOID
+ConfigureOSPartitions(
+ VOID
+ );
+
+// Network support function definitions. stuff from network.c
+
+VOID
+NetworkRemoveShare(
+ IN LPCTSTR DriveLetter
+ );
+
+VOID
+NetworkShare(
+ IN LPCTSTR DriveLetter
+ );
+
+VOID
+NetworkInitialize(
+ );
+
+// Debugging support for opens
+
+#ifdef DBG
+
+NTSTATUS
+DmOpenFile(
+ OUT PHANDLE FileHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ IN ULONG ShareAccess,
+ IN ULONG OpenOptions
+ );
+
+NTSTATUS
+DmClose(
+ IN HANDLE Handle
+ );
+#else
+#define DmOpenFile NtOpenFile
+#define DmClose NtClose
+#endif
diff --git a/private/utils/fdisk/fdres.h b/private/utils/fdisk/fdres.h
new file mode 100644
index 000000000..16c8c9fe5
--- /dev/null
+++ b/private/utils/fdisk/fdres.h
@@ -0,0 +1,305 @@
+
+/*++
+
+Copyright (c) 1991-1994 Microsoft Corporation
+
+Module Name:
+
+ fdres.h
+
+Abstract:
+
+ Central include file for Disk Administrator
+
+Author:
+
+ Edward (Ted) Miller (TedM) 11/15/91
+
+Environment:
+
+ User process.
+
+Notes:
+
+Revision History:
+
+ 11-Nov-93 (bobri) added doublespace and commit support.
+
+--*/
+
+// If double space is included this define should turn it on in the sources
+//#define DOUBLE_SPACE_SUPPORT_INCLUDED 1
+
+#define IDFDISK 1
+
+#define IDB_SMALLDISK 100
+#define IDB_REMOVABLE 101
+
+
+// dialogs
+
+#define IDD_ABOUT 200
+#define IDD_MINMAX 201
+#define IDD_COLORS 202
+#define IDD_DRIVELET 203
+#define IDD_DISPLAYOPTIONS 204
+#define IDD_DBLSPACE_CREATE 205
+#define IDD_DBLSPACE_DELETE 206
+#define IDD_DBLSPACE_MOUNT 207
+#define IDD_DBLSPACE_DISMOUNT 208
+#define IDD_DBLSPACE 209
+#define IDD_PARTITIONFORMAT 210
+#define IDD_PARTITIONLABEL 211
+#define IDD_DBLSPACE_DRIVELET 212
+#define IDD_FORMATCANCEL 213
+#define IDD_DBLSPACE_CANCEL 214
+#define IDD_DBLSPACE_FULL 215
+#define IDD_CDROM 216
+#define IDD_INITIALIZING 217
+
+// menu IDs
+
+#define IDM_PARTITIONCREATE 1000
+#define IDM_PARTITIONCREATEEX 1001
+#define IDM_PARTITIONDELETE 1002
+#if i386
+#define IDM_PARTITIONACTIVE 1003
+#endif
+#define IDM_PARTITIONLETTER 1004
+#define IDM_PARTITIONEXIT 1005
+#define IDM_SECURESYSTEM 1006
+#define IDM_PARTITIONFORMAT 1007
+#define IDM_PARTITIONLABEL 1008
+
+#define IDM_CONFIGMIGRATE 2000
+#define IDM_CONFIGSAVE 2001
+#define IDM_CONFIGRESTORE 2002
+
+#define IDM_FTESTABLISHMIRROR 3000
+#define IDM_FTBREAKMIRROR 3001
+#define IDM_FTCREATESTRIPE 3002
+#define IDM_FTCREATEVOLUMESET 3004
+#define IDM_FTRECOVERSTRIPE 3006
+#define IDM_FTCREATEPSTRIPE 3007
+#define IDM_FTEXTENDVOLUMESET 3009
+
+#define IDM_DBLSPACE 3100
+#define IDM_AUTOMOUNT 3101
+#define IDM_CDROM 3102
+
+#define IDM_OPTIONSSTATUS 4000
+#define IDM_OPTIONSLEGEND 4001
+#define IDM_OPTIONSCOLORS 4002
+#define IDM_OPTIONSDISPLAY 4003
+
+#define IDM_COMMIT 4100
+
+#define IDM_HELPCONTENTS 5000
+#define IDM_HELPSEARCH 5001
+#define IDM_HELPHELP 5002
+#define IDM_HELPABOUT 5003
+
+#if DBG && DEVL
+#define IDM_DEBUGALLOWDELETES 10001
+#endif
+
+// accelerator keys
+
+#define IDM_HELP 6000
+
+//controls
+
+#define IDC_MINMAX_MINLABEL 100
+#define IDC_MINMAX_MAXLABEL 101
+#define IDC_MINMAX_SIZLABEL 102
+#define IDC_MINMAX_MIN 103
+#define IDC_MINMAX_MAX 104
+#define IDC_MINMAX_SIZE 105
+#define IDC_MINMAX_SCROLL 106
+#define IDC_DBLSPACE_LETTER 107
+#define IDC_DBLSPACE_LETTER_INDICATOR 108
+#define IDC_DBLSPACE_ALLOCATED 100
+#define IDC_DBLSPACE_COMPRESSED 110
+#define IDC_DBLSPACE_SIZE 111
+#define IDC_DBLSPACE_VOLUME 112
+#define IDC_DBLSPACE_RATIO 113
+#define IDC_MOUNT_STATE 114
+
+#define IDC_TEXT 200
+#define IDC_NAME 201
+#define IDC_VERIFY 202
+#define IDC_FSTYPE 203
+#define IDC_PROGRESS 204
+#define IDC_GASGAUGE 205
+#define IDC_HIDE 206
+
+#define IDC_COLOR1 501
+#define IDC_COLOR2 502
+#define IDC_COLOR3 503
+#define IDC_COLOR4 504
+#define IDC_COLOR5 505
+#define IDC_COLOR6 506
+#define IDC_COLOR7 507
+#define IDC_COLOR8 508
+#define IDC_COLOR9 509
+#define IDC_COLOR10 510
+#define IDC_COLOR11 511
+#define IDC_COLOR12 512
+#define IDC_COLOR13 513
+#define IDC_COLOR14 514
+#define IDC_COLOR15 515
+#define IDC_COLOR16 516
+
+#define IDC_PATTERN1 601
+#define IDC_PATTERN2 602
+#define IDC_PATTERN3 603
+#define IDC_PATTERN4 604
+#define IDC_PATTERN5 605
+
+#define IDC_COLORDLGCOMBO 100
+
+#define IDC_DRIVELET_RBASSIGN 700
+#define IDC_DRIVELET_RBNOASSIGN 701
+#define IDC_DRIVELET_DESCR 702
+#define IDC_DRIVELET_COMBOBOX 703
+#define IDC_CDROM_NAMES 704
+
+#define IDC_DISK_COMBOBOX 100
+#define IDC_RESETALL 101
+#define IDC_RBPROPORTIONAL 200
+#define IDC_RBEQUAL 201
+#define IDC_RBAUTO 202
+
+
+// buttons
+
+#define FD_IDHELP 22
+#define IDADD 23
+#define IDDELETE 24
+#define ID_MOUNT_OR_DISMOUNT 25
+
+// strings
+
+#define IDS_APPNAME 1
+#define IDS_MULTIPLEITEMS 2
+#define IDS_FREESPACE 3
+#define IDS_PARTITION 4
+#define IDS_LOGICALVOLUME 5
+#define IDS_DISKN 6
+#define IDS_CONFIRM 7
+#define IDS_NOT_IN_APP_MSG_FILE 8
+#define IDS_NOT_IN_SYS_MSG_FILE 9
+#define IDS_UNFORMATTED 10
+#define IDS_UNKNOWN 11
+#define IDS_STRIPESET 12
+#define IDS_VOLUMESET 13
+#define IDS_EXTENDEDPARTITION 14
+#define IDS_FREEEXT 15
+#define IDS_DRIVELET_DESCR 16
+#define IDS_HEALTHY 17
+#define IDS_BROKEN 18
+#define IDS_RECOVERABLE 19
+#define IDS_REGENERATED 20
+#define IDS_NEW 21
+#define IDS_OFFLINE 22
+#define IDS_INSERT_DISK 23
+#define IDS_MEGABYTES_ABBREV 24
+#define IDS_INITIALIZING 25
+#define IDS_REGENERATING 26
+#define IDS_NO_CONFIG_INFO 27
+#define IDS_NEW_UNFORMATTED 28
+#define IDS_DISABLED 29
+#define IDS_INIT_FAILED 70
+
+#define IDS_CRTPART_CAPTION_P 30
+#define IDS_CRTPART_CAPTION_E 31
+#define IDS_CRTPART_CAPTION_L 32
+#define IDS_CRTPART_MIN_P 33
+#define IDS_CRTPART_MAX_P 34
+#define IDS_CRTPART_MIN_L 35
+#define IDS_CRTPART_MAX_L 36
+#define IDS_CRTPART_SIZE_P 37
+#define IDS_CRTPART_SIZE_L 38
+
+#define IDS_CRTSTRP_CAPTION 39
+#define IDS_CRTSTRP_MIN 40
+#define IDS_CRTSTRP_MAX 41
+#define IDS_CRTSTRP_SIZE 42
+
+#define IDS_CRTVSET_CAPTION 43
+#define IDS_EXPVSET_CAPTION 44
+#define IDS_CRTVSET_MIN 45
+#define IDS_CRTVSET_MAX 46
+#define IDS_CRTVSET_SIZE 47
+
+#define IDS_STATUS_STRIPESET 48
+#define IDS_STATUS_PARITY 49
+#define IDS_STATUS_VOLUMESET 50
+#define IDS_STATUS_MIRROR 51
+
+#define IDS_CRTPSTRP_CAPTION 52
+
+#define IDS_DLGCAP_PARITY 53
+#define IDS_DLGCAP_MIRROR 54
+
+// these must be contigous, and kept in sync with BRUSH_xxx constants
+
+#define IDS_LEGEND_PRIMARY 100
+#define IDS_LEGEND_LOGICAL 101
+#define IDS_LEGEND_STRIPESET 102
+#define IDS_LEGEND_MIRROR 103
+#define IDS_LEGEND_VOLUMESET 104
+#define IDS_LEGEND_LAST IDS_LEGEND_VOLUMESET
+#define IDS_LEGEND_FIRST IDS_LEGEND_PRIMARY
+
+
+// These are the strings for system-names other than those which are
+// meaningful to NT.
+
+#define IDS_PARTITION_FREE 120
+#define IDS_PARTITION_XENIX1 121
+#define IDS_PARTITION_XENIX2 122
+#define IDS_PARTITION_OS2_BOOT 123
+#define IDS_PARTITION_EISA 124
+#define IDS_PARTITION_UNIX 125
+#define IDS_PARTITION_POWERPC 126
+
+
+// Double space support strings
+
+#define IDS_DBLSPACE_DELETE 150
+#define IDS_WITH_DBLSPACE 151
+#define IDS_DBLSPACE_MOUNTED 152
+#define IDS_DBLSPACE_DISMOUNTED 153
+#define IDS_MOUNT 154
+#define IDS_DISMOUNT 155
+#define IDS_CREATING_DBLSPACE 156
+#define IDS_DBLSPACECOMPLETE 157
+
+// format strings.
+
+#define IDS_QUICK_FORMAT 170
+#define IDS_PERCENTCOMPLETE 171
+#define IDS_FORMATSTATS 172
+#define IDS_FORMATCOMPLETE 173
+#define IDS_FORMAT_TITLE 174
+#define IDS_LABEL_TITLE 175
+
+// Registry paths.
+
+#define IDS_SOURCE_PATH 180
+#define IDS_SOURCE_PATH_NAME 181
+
+#if i386
+#define IDS_ACTIVEPARTITION 200
+#endif
+
+
+// name of rectangle custom control class
+
+#define RECTCONTROL "RectControl"
+
+// rectangle control styles
+
+#define RS_PATTERN 0x00000001
+#define RS_COLOR 0x00000002
diff --git a/private/utils/fdisk/fdstleg.c b/private/utils/fdisk/fdstleg.c
new file mode 100644
index 000000000..dc5772416
--- /dev/null
+++ b/private/utils/fdisk/fdstleg.c
@@ -0,0 +1,321 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ fdstleg.c
+
+Abstract:
+
+ Routines to support the status bar and legend displays.
+
+Author:
+
+ Ted Miller (tedm) 7-Jan-1992
+
+--*/
+
+
+#include "fdisk.h"
+
+
+HFONT hFontStatus,hFontLegend;
+
+DWORD dyLegend,wLegendItem;
+DWORD dyStatus,dyBorder;
+
+
+// text for status area
+
+TCHAR StatusTextStat[STATUS_TEXT_SIZE];
+TCHAR StatusTextSize[STATUS_TEXT_SIZE];
+
+WCHAR StatusTextDrlt[3];
+
+WCHAR StatusTextType[STATUS_TEXT_SIZE];
+WCHAR StatusTextVoll[STATUS_TEXT_SIZE];
+
+TCHAR *LegendLabels[LEGEND_STRING_COUNT];
+
+
+// whether status bar and legend are currently shown
+
+BOOL StatusBar = TRUE,
+ Legend = TRUE;
+
+
+
+VOID
+UpdateStatusBarDisplay(
+ VOID
+ )
+{
+ RECT rc;
+
+ if(StatusBar) {
+ GetClientRect(hwndFrame,&rc);
+ rc.top = rc.bottom - dyStatus;
+ InvalidateRect(hwndFrame,&rc,FALSE);
+ }
+}
+
+
+VOID
+ClearStatusArea(
+ VOID
+ )
+{
+ StatusTextStat[0] = StatusTextSize[0] = 0;
+ StatusTextVoll[0] = StatusTextType[0] = 0;
+ StatusTextDrlt[0] = 0;
+ UpdateStatusBarDisplay();
+}
+
+
+VOID
+DrawLegend(
+ IN HDC hdc,
+ IN PRECT rc
+ )
+
+/*++
+
+Routine Description:
+
+ This routine draws the legend onto the given device context. The legend
+ lists the brush styles used to indicate various region types in the
+ disk graphs.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DWORD i,
+ left,
+ delta = GraphWidth / BRUSH_ARRAY_SIZE;
+ HBRUSH hBrush;
+ RECT rc1,rc2;
+ HFONT hfontOld;
+ SIZE size;
+ DWORD dx;
+ COLORREF OldTextColor,OldBkColor;
+
+ rc1 = *rc;
+ rc2 = *rc;
+
+ // first draw the background.
+
+ hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
+ rc1.right = rc1.left + GetSystemMetrics(SM_CXSCREEN); // erase it all
+ FillRect(hdc,&rc1,hBrush);
+ DeleteObject(hBrush);
+
+ // now draw the nice container
+
+ rc2.left += 8 * dyBorder;
+ rc2.right -= 8 * dyBorder;
+ DrawStatusAreaItem(&rc2,hdc,NULL,FALSE);
+
+ // now draw the legend items
+
+ SelectObject(hdc,hPenThinSolid);
+
+ left = rc2.left + (wLegendItem / 2);
+ SetBkColor(hdc,GetSysColor(COLOR_BTNFACE));
+ hfontOld = SelectObject(hdc,hFontLegend);
+
+ OldTextColor = SetTextColor(hdc,GetSysColor(COLOR_BTNTEXT));
+ SetBkMode(hdc,OPAQUE);
+
+ for(i=0; i<BRUSH_ARRAY_SIZE; i++) {
+
+ hBrush = SelectObject(hdc,Brushes[i]);
+
+ OldBkColor = SetBkColor(hdc,RGB(255,255,255));
+
+ Rectangle(hdc,
+ left,
+ rc->top + (wLegendItem / 2),
+ left + wLegendItem,
+ rc->top + (3 * wLegendItem / 2)
+ );
+
+ SetBkColor(hdc,OldBkColor);
+
+ // BUGBUG unicode lstrlen?
+ GetTextExtentPoint(hdc,LegendLabels[i],lstrlen(LegendLabels[i]),&size);
+ dx = (DWORD)size.cx;
+ TextOut(hdc,
+ left + (3*wLegendItem/2),
+ rc->top + (wLegendItem / 2) + ((wLegendItem-size.cy)/2),
+ LegendLabels[i],
+ lstrlen(LegendLabels[i])
+ );
+#if 0
+ SelectObject(hdc,Brushes[++i]);
+
+ OldBkColor = SetBkColor(hdc,RGB(255,255,255));
+
+ Rectangle(hdc,
+ left,
+ rc->top + (2 * wLegendItem),
+ left + wLegendItem,
+ rc->top + (3 * wLegendItem)
+ );
+
+ SetBkColor(hdc,OldBkColor);
+
+ GetTextExtentPoint(hdc,LegendLabels[i],lstrlen(LegendLabels[i]),&size);
+ TextOut(hdc,
+ left + (3*wLegendItem/2),
+ rc->top + (2 * wLegendItem) + ((wLegendItem-size.cy)/2),
+ LegendLabels[i],
+ lstrlen(LegendLabels[i])
+ );
+
+ if((DWORD)size.cx > dx) {
+ dx = (DWORD)size.cx;
+ }
+#endif
+ left += dx + (5*wLegendItem/2);
+
+ if(hBrush) {
+ SelectObject(hdc,hBrush);
+ }
+ }
+ if(hfontOld) {
+ SelectObject(hdc,hfontOld);
+ }
+ SetTextColor(hdc,OldTextColor);
+}
+
+
+
+VOID
+DrawStatusAreaItem(
+ IN PRECT rc,
+ IN HDC hdc,
+ IN LPTSTR Text,
+ IN BOOL Unicode
+ )
+
+/*++
+
+Routine Description:
+
+ This routine draws a status area item into a given dc. This
+ includes drawing the nice shaded button-like container, and
+ then drawing text within it.
+
+Arguments:
+
+ rc - rectangle describing the status area item
+
+ hdc - device context into which to draw
+
+ Text - optional parameter that if present represents text to
+ be placed in the item.
+
+ Unicode - if TRUE, Text points to a wide character string regardless
+ of the type of LPTSTR
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ HBRUSH hBrush;
+ RECT rcx;
+
+
+ // the shadow
+
+ if(hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW))) {
+
+ // left edge
+
+ rcx.left = rc->left;
+ rcx.right = rc->left + dyBorder;
+ rcx.top = rc->top + (2*dyBorder);
+ rcx.bottom = rc->bottom - (2*dyBorder);
+ FillRect(hdc,&rcx,hBrush);
+
+ // top edge
+
+ rcx.right = rc->right;
+ rcx.bottom = rcx.top + dyBorder;
+ FillRect(hdc,&rcx,hBrush);
+
+ DeleteObject(hBrush);
+ }
+
+ // the highlight
+
+ if(hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNHIGHLIGHT))) {
+
+ // right edge
+
+ rcx.left = rc->right - dyBorder;
+ rcx.right = rc->right;
+ rcx.top = rc->top + (2*dyBorder);
+ rcx.bottom = rc->bottom - (2*dyBorder);
+ FillRect(hdc,&rcx,hBrush);
+
+ // top edge
+
+ rcx.left = rc->left;
+ rcx.right = rc->right;
+ rcx.top = rc->bottom - (3*dyBorder);
+ rcx.bottom = rcx.top + dyBorder;
+ FillRect(hdc,&rcx,hBrush);
+
+ DeleteObject(hBrush);
+ }
+
+ if(Text) {
+
+ // draw the text
+
+ SetTextColor(hdc,GetSysColor(COLOR_BTNTEXT));
+ SetBkColor(hdc,GetSysColor(COLOR_BTNFACE));
+
+ rcx.top = rc->top + (3*dyBorder);
+ rcx.bottom = rc->bottom - (3*dyBorder);
+ rcx.left = rc->left + dyBorder;
+ rcx.right = rc->right - dyBorder;
+
+ if(Unicode && (sizeof(TCHAR) != sizeof(WCHAR))) {
+
+ ExtTextOutW(hdc,
+ rcx.left+(2*dyBorder),
+ rcx.top,
+ ETO_OPAQUE | ETO_CLIPPED,
+ &rcx,
+ (PWSTR)Text,
+ lstrlenW((PWSTR)Text),
+ NULL
+ );
+
+ } else {
+ ExtTextOut(hdc,
+ rcx.left+(2*dyBorder),
+ rcx.top,
+ ETO_OPAQUE | ETO_CLIPPED,
+ &rcx,
+ Text,
+ lstrlen(Text),
+ NULL
+ );
+ }
+ }
+}
diff --git a/private/utils/fdisk/fdtypes.h b/private/utils/fdisk/fdtypes.h
new file mode 100644
index 000000000..f59bc111d
--- /dev/null
+++ b/private/utils/fdisk/fdtypes.h
@@ -0,0 +1,317 @@
+/*++
+
+Copyright (c) 1990-1994 Microsoft Corporation
+
+Module Name:
+
+ fdtypes.h
+
+Abstract:
+
+ Support types definitions for Disk Administrator
+
+Author:
+
+ Ted Miller (tedm) 7-Jan-1992
+
+Revisions:
+
+ 11-Nov-93 (bobri) double space and commit support.
+ 2-Feb-94 (bobri) moved ArcInst data items into this file.
+
+--*/
+
+// Partition data items
+
+typedef enum { REGION_PRIMARY,
+ REGION_EXTENDED,
+ REGION_LOGICAL
+ } REGION_TYPE;
+
+enum {
+ SYSID_UNUSED = 0,
+ SYSID_EXTENDED = 5,
+ SYSID_BIGFAT = 6,
+ SYSID_IFS = 7
+ };
+
+// These structures are used in doubly-linked per disk lists that
+// describe the layout of the disk.
+//
+// Free spaces are indicated by entries with a SysID of 0 (note that
+// these entries don't actually appear anywhere on-disk!)
+//
+// The partition number is the number the system will assign to
+// the partition in naming it. For free spaces, this is the number
+// that the system WOULD assign to it if it was a partition.
+// The number is good only for one transaction (create or delete),
+// after which partitions must be renumbered.
+
+struct _PERSISTENT_REGION_DATA;
+typedef struct _PARTITION {
+ struct _PARTITION *Next;
+ struct _PARTITION *Prev;
+ struct _PERSISTENT_REGION_DATA *PersistentData;
+ LARGE_INTEGER Offset;
+ LARGE_INTEGER Length;
+ ULONG Disk;
+ ULONG OriginalPartitionNumber;
+ ULONG PartitionNumber;
+ BOOLEAN Update;
+ BOOLEAN Active;
+ BOOLEAN Recognized;
+ UCHAR SysID;
+ BOOLEAN CommitMirrorBreakNeeded;
+} PARTITION,*PPARTITION;
+
+typedef struct _REGION_DATA {
+ PPARTITION Partition;
+ LARGE_INTEGER AlignedRegionOffset;
+ LARGE_INTEGER AlignedRegionSize;
+} REGION_DATA,*PREGION_DATA;
+
+// structure that describes an ft object (mirror, stripe component, etc).
+
+struct _FT_OBJECT_SET;
+typedef struct _FT_OBJECT {
+ struct _FT_OBJECT *Next;
+ struct _FT_OBJECT_SET *Set;
+ ULONG MemberIndex;
+ FT_PARTITION_STATE State;
+} FT_OBJECT, *PFT_OBJECT;
+
+// DoubleSpace support structure. This is tagged off of the persistent data for
+// each region.
+
+typedef struct _DBLSPACE_DESCRIPTOR {
+ struct _DBLSPACE_DESCRIPTOR *Next;
+ struct _DBLSPACE_DESCRIPTOR *DblChainNext;
+ ULONG AllocatedSize;
+ PCHAR FileName;
+ UCHAR DriveLetter;
+ CHAR DriveLetterEOS;
+ BOOLEAN Mounted;
+ BOOLEAN ChangeMountState;
+ UCHAR NewDriveLetter;
+ CHAR NewDriveLetterEOS;
+ BOOLEAN ChangeDriveLetter;
+} DBLSPACE_DESCRIPTOR, *PDBLSPACE_DESCRIPTOR;
+
+// Define the structure that is associated with each non-extended, recognized
+// partition. This structure is associated with the partition, and persists
+// across region array free/get from the back end. It is used for logical
+// and ft information.
+
+typedef struct _PERSISTENT_REGION_DATA {
+ PFT_OBJECT FtObject;
+ PDBLSPACE_DESCRIPTOR DblSpace;
+ PWSTR VolumeLabel;
+ PWSTR TypeName;
+ CHAR DriveLetter;
+ BOOLEAN VolumeExists;
+} PERSISTENT_REGION_DATA, *PPERSISTENT_REGION_DATA;
+
+typedef struct _REGION_DESCRIPTOR {
+ PPERSISTENT_REGION_DATA PersistentData;
+ PREGION_DATA Reserved;
+ ULONG Disk;
+ ULONG PartitionNumber;
+ ULONG OriginalPartitionNumber;
+ ULONG SizeMB;
+ REGION_TYPE RegionType;
+ BOOLEAN Active;
+ BOOLEAN Recognized;
+ UCHAR SysID;
+} REGION_DESCRIPTOR,*PREGION_DESCRIPTOR;
+
+// params for the MinMax dialog -- used at WM_INITDIALOG time
+
+typedef struct _MINMAXDLG_PARAMS {
+ DWORD CaptionStringID;
+ DWORD MinimumStringID;
+ DWORD MaximumStringID;
+ DWORD SizeStringID;
+ DWORD MinSizeMB;
+ DWORD MaxSizeMB;
+ DWORD HelpContextId;
+} MINMAXDLG_PARAMS,*PMINMAXDLG_PARAMS;
+
+typedef struct _FORMAT_PARAMS {
+ PREGION_DESCRIPTOR RegionDescriptor;
+ PVOID RegionData;
+ BOOL QuickFormat;
+ BOOL Cancel;
+ BOOL DoubleSpace;
+ UCHAR NewLetter;
+ PUCHAR Label;
+ PUCHAR FileSystem;
+ PWSTR DblspaceFileName;
+ HWND DialogHwnd;
+ DWORD Result;
+ ULONG TotalSpace;
+ ULONG SpaceAvailable;
+ ULONG ThreadIsDone;
+} FORMAT_PARAMS, *PFORMAT_PARAMS;
+
+typedef struct _LABEL_PARAMS {
+ PREGION_DESCRIPTOR RegionDescriptor;
+ LPTSTR NewLabel;
+} LABEL_PARAMS, *PLABEL_PARAMS;
+
+typedef struct _LEFTRIGHT {
+ LONG Left;
+ LONG Right;
+} LEFTRIGHT, *PLEFTRIGHT;
+
+
+//
+// Types of views that can be used for a disk bar.
+// Proportional means that the amount of space taken up in the bar is
+// directly proportional to the size of the partition or free space
+// Equal means that all free spaces and partitions are sized equally on
+// screen regardless of their actual size
+
+typedef enum _BAR_TYPE {
+ BarProportional,
+ BarEqual,
+ BarAuto
+} BAR_TYPE, *PBAR_TYPE;
+
+// One of these structures is associated with each item in the
+// listbox. The structure is the crux of the implementation.
+
+typedef struct _DISKSTATE {
+ DWORD Disk; // number of disk
+ DWORD DiskSizeMB; // size in MB of disk
+ PREGION_DESCRIPTOR RegionArray; // region array for disk
+ DWORD RegionCount; // # items in region array
+ PBOOLEAN Selected; // whether each region is selected
+ PLEFTRIGHT LeftRight; // left/right coords of boxes in graph
+ DWORD BoxCount; // # boxes in this disk's graph
+ BOOLEAN CreateAny; // any creations allowed on disk
+ BOOLEAN CreatePrimary; // allowed to create primary partition
+ BOOLEAN CreateExtended; // allowed to create extended partition
+ BOOLEAN CreateLogical; // allowed to create logical volume
+ BOOLEAN ExistAny; // any partitions/logicals exist
+ BOOLEAN ExistPrimary; // primary partition(s) exist
+ BOOLEAN ExistExtended; // extended partition exists
+ BOOLEAN ExistLogical; // logical volume(s) exist
+ HDC hDCMem; // for off-screen drawing
+ HBITMAP hbmMem; // for offscreen bitmap
+ ULONG Signature; // unique disk registry index
+ BAR_TYPE BarType; // how to display the disk's bar
+ BOOLEAN SigWasCreated; // whether we had to make up a sig
+ BOOLEAN OffLine; // FALSE if disk is accessible.
+} DISKSTATE, *PDISKSTATE;
+
+// Enum for the states in which an ft set can be.
+
+typedef enum _FT_SET_STATUS {
+ FtSetHealthy,
+ FtSetBroken,
+ FtSetRecoverable,
+ FtSetRecovered,
+ FtSetNew,
+ FtSetNewNeedsInitialization,
+ FtSetExtended,
+ FtSetInitializing,
+ FtSetRegenerating,
+ FtSetInitializationFailed,
+ FtSetDisabled
+} FT_SET_STATUS, *PFT_SET_STATUS;
+
+// structure that describes an ft object set (ie, mirrored pair, stripe set).
+
+typedef struct _FT_OBJECT_SET {
+ struct _FT_OBJECT_SET *Next;
+ FT_TYPE Type;
+ ULONG Ordinal;
+ PFT_OBJECT Members;
+ PFT_OBJECT Member0;
+ FT_SET_STATUS Status;
+ ULONG NumberOfMembers;
+} FT_OBJECT_SET, *PFT_OBJECT_SET;
+
+typedef struct _DBLSPACE_PARAMS {
+ DWORD CaptionStringID;
+ PVOID RegionDescriptor;
+ PPERSISTENT_REGION_DATA RegionData;
+ PDBLSPACE_DESCRIPTOR DblSpace;
+} DBLSPACE_PARAMS, *PDBLSPACE_PARAMS;
+
+// CdRom support structures.
+
+typedef struct _CDROM_DESCRIPTOR {
+ struct _CDROM_DESCRIPTOR *Next;
+ PWSTR DeviceName;
+ ULONG DeviceNumber;
+ WCHAR DriveLetter;
+ WCHAR NewDriveLetter;
+} CDROM_DESCRIPTOR, *PCDROM_DESCRIPTOR;
+
+// Commit support structures
+
+typedef struct _DRIVE_LOCKLIST {
+ struct _DRIVE_LOCKLIST *Next;
+ HANDLE LockHandle;
+ ULONG DiskNumber;
+ ULONG PartitionNumber;
+ ULONG LockOnDiskNumber;
+ ULONG UnlockOnDiskNumber;
+ UCHAR DriveLetter;
+ BOOLEAN RemoveOnUnlock;
+ BOOLEAN FailOk;
+ BOOLEAN CurrentlyLocked;
+} DRIVE_LOCKLIST, *PDRIVE_LOCKLIST;
+
+// Commit support enum for drive letter assignment
+
+typedef enum _LETTER_ASSIGNMENT_RESULT {
+ Failure = 0,
+ Complete,
+ MustReboot
+} LETTER_ASSIGNMENT_RESULT;
+
+// Items below used to be in fdenginp.h -- have been moved here to
+// remove dependency on ArcInst project.
+
+#define LOWPART(x) ((x).LowPart)
+
+#define ONE_MEG (1024*1024)
+
+ULONG
+SIZEMB(
+ IN LARGE_INTEGER ByteCount
+ );
+
+#define ENTRIES_PER_BOOTSECTOR 4
+
+// This structure is used to hold the information returned by the
+// get drive geometry call.
+
+typedef struct _DISKGEOM {
+ LARGE_INTEGER Cylinders;
+ ULONG Heads;
+ ULONG SectorsPerTrack;
+ ULONG BytesPerSector;
+ // These two are not part of drive geometry info, but calculated from it.
+ ULONG BytesPerCylinder;
+ ULONG BytesPerTrack;
+} DISKGEOM,*PDISKGEOM;
+
+
+
+#if DBG
+
+#include <process.h>
+char _ASRTFAILEDSTR_[256];
+#define ASRT(x) if(!(x)) { sprintf( _ASRTFAILEDSTR_, \
+ "file %s\nline %u", \
+ __FILE__,__LINE__ \
+ ); \
+ MessageBoxA(NULL,_ASRTFAILEDSTR_,"Assertion Failure",0); \
+ exit(1); \
+ }
+
+#endif
+
diff --git a/private/utils/fdisk/fmifs.c b/private/utils/fdisk/fmifs.c
new file mode 100644
index 000000000..4bc8f8ac9
--- /dev/null
+++ b/private/utils/fdisk/fmifs.c
@@ -0,0 +1,1792 @@
+
+/*++
+
+Copyright (c) 1993-1994 Microsoft Corporation
+
+Module Name:
+
+ fmifs.c
+
+Abstract:
+
+ This module contains the set of routines that work with the fmifs.dll
+
+Author:
+
+ Bob Rinne (bobri) 11/15/93
+
+Environment:
+
+ User process.
+
+Notes:
+
+Revision History:
+
+--*/
+
+#include "fdisk.h"
+#include "shellapi.h"
+#include "fmifs.h"
+#include <string.h>
+#include <stdio.h>
+
+//
+// defines unique to this module
+//
+
+#define FS_CANCELUPDATE (WM_USER + 0)
+#define FS_FINISHED (WM_USER + 1)
+
+BOOLEAN
+FmIfsCallback(
+ IN FMIFS_PACKET_TYPE PacketType,
+ IN DWORD PacketLength,
+ IN PVOID PacketData
+ );
+
+//
+// Externals needed for IFS Dll support (format and label)
+//
+
+HINSTANCE IfsDllHandle = NULL;
+PFMIFS_FORMAT_ROUTINE FormatRoutine = NULL;
+PFMIFS_SETLABEL_ROUTINE LabelRoutine = NULL;
+
+#ifdef DOUBLE_SPACE_SUPPORT_INCLUDED
+PFMIFS_DOUBLESPACE_CREATE_ROUTINE DblSpaceCreateRoutine = NULL;
+PFMIFS_DOUBLESPACE_MOUNT_ROUTINE DblSpaceMountRoutine = NULL;
+PFMIFS_DOUBLESPACE_DELETE_ROUTINE DblSpaceDeleteRoutine = NULL;
+PFMIFS_DOUBLESPACE_DISMOUNT_ROUTINE DblSpaceDismountRoutine = NULL;
+PFMIFS_DOUBLESPACE_QUERY_INFO_ROUTINE DblSpaceQueryInfoRoutine = NULL;
+
+BOOLEAN DoubleSpaceSupported = TRUE;
+#endif
+
+// HACK HACK - clean this up if it works.
+
+#define SELECTED_REGION(i) (SelectedDS[i]->RegionArray[SelectedRG[i]])
+#define MaxMembersInFtSet 32
+extern DWORD SelectionCount;
+extern PDISKSTATE SelectedDS[MaxMembersInFtSet];
+extern ULONG SelectedRG[MaxMembersInFtSet];
+
+VOID
+setUnicode(
+ char *astring,
+ WCHAR *wstring
+ )
+/*++
+
+Routine Description:
+
+ Convert an ansii string to Unicode. Internal routine to fmifs module.
+
+Arguments:
+
+ astring - ansii string to convert to Unicode
+ wstring - resulting string location
+
+Return Value:
+
+ None
+
+--*/
+{
+
+ int len = lstrlen(astring)+1;
+
+ MultiByteToWideChar( CP_ACP, 0, astring, len, wstring, len );
+}
+
+BOOL
+LoadIfsDll(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will determine if the IFS Dll needs to be loaded. If
+ so, it will load it and locate the format and label routines in the
+ dll.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ TRUE if Dll is loaded and the routines needed have been found
+ FALSE if something fails
+
+--*/
+
+{
+ if (FormatRoutine) {
+
+ // Library is already loaded and the routines needed
+ // have been located.
+
+ return TRUE;
+ }
+
+ IfsDllHandle = LoadLibrary(TEXT("fmifs.dll"));
+ if (IfsDllHandle == (HANDLE)NULL) {
+
+ // FMIFS not available.
+
+ return FALSE;
+ }
+
+ // Library is loaded. Locate the two routines needed by
+ // Disk Administrator.
+
+ FormatRoutine = (PVOID)GetProcAddress(IfsDllHandle, "Format");
+ LabelRoutine = (PVOID)GetProcAddress(IfsDllHandle, "SetLabel");
+ if (!FormatRoutine || !LabelRoutine) {
+
+ // something didn't get found so shut down all accesses
+ // to the library by insuring FormatRoutine is NULL
+
+ FreeLibrary(IfsDllHandle);
+ FormatRoutine = NULL;
+ return FALSE;
+ }
+
+#ifdef DOUBLE_SPACE_SUPPORT_INCLUDED
+ DblSpaceMountRoutine = (PVOID)GetProcAddress(IfsDllHandle, "DoubleSpaceMount");
+ DblSpaceDismountRoutine = (PVOID)GetProcAddress(IfsDllHandle, "DoubleSpaceDismount");
+ DblSpaceCreateRoutine = (PVOID)GetProcAddress(IfsDllHandle, "DoubleSpaceCreate");
+ DblSpaceDeleteRoutine = (PVOID)GetProcAddress(IfsDllHandle, "DoubleSpaceDelete");
+ DblSpaceQueryInfoRoutine = (PVOID)GetProcAddress(IfsDllHandle, "FmifsQueryDriveInformation");
+
+ if (!DblSpaceMountRoutine || !DblSpaceDismountRoutine || !DblSpaceQueryInfoRoutine) {
+
+ // didn't get all of the DoubleSpace support routines
+ // Allow format and label, just don't do DoubleSpace
+
+ DoubleSpaceSupported = FALSE;
+ }
+
+ if (DblSpaceCreateRoutine && DblSpaceDeleteRoutine) {
+
+ // Everything is there for read/write double space support.
+ // This will change certain dialogs to allow creation and
+ // deletion of double space volumes.
+
+ IsFullDoubleSpace = TRUE;
+ }
+#endif
+ return TRUE;
+}
+
+VOID
+UnloadIfsDll(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will free the FmIfs DLL if it was loaded.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ if (FormatRoutine) {
+ FreeLibrary(IfsDllHandle);
+ FormatRoutine = NULL;
+ IfsDllHandle = NULL;
+ LabelRoutine = NULL;
+#ifdef DOUBLE_SPACE_SUPPORT_INCLUDED
+ DblSpaceDismountRoutine = NULL;
+ DblSpaceMountRoutine = NULL;
+ DblSpaceCreateRoutine = NULL;
+ DblSpaceDeleteRoutine = NULL;
+#endif
+ }
+}
+
+PFORMAT_PARAMS ParamsForCallBack = NULL;
+
+BOOLEAN
+FmIfsCallback(
+ IN FMIFS_PACKET_TYPE PacketType,
+ IN DWORD PacketLength,
+ IN PVOID PacketData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine gets callbacks from fmifs.dll regarding
+ progress and status of the ongoing format or doublespace
+ create. It runs in the same thread as the format or create,
+ which is a separate thread from the "cancel" button. If
+ the user hits "cancel", this routine notices on the next
+ callback and cancels the format or double space create.
+
+Arguments:
+
+ [PacketType] -- an fmifs packet type
+ [PacketLength] -- length of the packet data
+ [PacketData] -- data associated with the packet
+
+Return Value:
+
+ TRUE if the fmifs activity should continue, FALSE if the
+ activity should halt immediately. Thus, we return FALSE if
+ the user has hit "cancel" and we wish fmifs to clean up and
+ return from the Format() entrypoint call.
+
+--*/
+
+{
+ PFORMAT_PARAMS formatParams = ParamsForCallBack;
+ HWND hDlg = formatParams->DialogHwnd;
+
+ // Quit if told to do so..
+
+ if (formatParams->Cancel) {
+ formatParams->Result = MSG_FORMAT_CANCELLED;
+ return FALSE;
+ }
+
+ switch (PacketType) {
+ case FmIfsPercentCompleted:
+
+ PostMessage(hDlg,
+ FS_CANCELUPDATE,
+ ((PFMIFS_PERCENT_COMPLETE_INFORMATION)PacketData)->PercentCompleted,
+ 0);
+ break;
+
+ case FmIfsFormatReport:
+
+ formatParams->TotalSpace = ((PFMIFS_FORMAT_REPORT_INFORMATION)PacketData)->KiloBytesTotalDiskSpace;
+ formatParams->SpaceAvailable = ((PFMIFS_FORMAT_REPORT_INFORMATION)PacketData)->KiloBytesAvailable;
+ break;
+
+ case FmIfsIncompatibleFileSystem:
+
+ formatParams->Result = MSG_INCOMPATIBLE_FILE_SYSTEM;
+ break;
+
+ case FmIfsInsertDisk:
+
+ break;
+
+ case FmIfsFormattingDestination:
+
+ break;
+
+ case FmIfsIncompatibleMedia:
+
+ formatParams->Result = MSG_INCOMPATIBLE_MEDIA;
+ break;
+
+ case FmIfsAccessDenied:
+
+ formatParams->Result = MSG_FORMAT_ACCESS_DENIED;
+ break;
+
+ case FmIfsMediaWriteProtected:
+
+ formatParams->Result = MSG_WRITE_PROTECTED;
+ break;
+
+ case FmIfsCantLock:
+
+ formatParams->Result = MSG_FORMAT_CANT_LOCK;
+ break;
+
+ case FmIfsBadLabel:
+
+ formatParams->Result = MSG_BAD_LABEL;
+ break;
+
+ case FmIfsCantQuickFormat:
+
+ formatParams->Result = MSG_CANT_QUICK_FORMAT;
+ break;
+
+ case FmIfsIoError:
+
+ formatParams->Result = MSG_IO_ERROR;
+ break;
+
+ case FmIfsFinished:
+
+ PostMessage(hDlg,
+ FS_FINISHED,
+ 0,
+ 0);
+ return FALSE;
+ break;
+
+#ifdef DOUBLE_SPACE_SUPPORT_INCLUDED
+ case FmIfsDblspaceCreateFailed:
+ formatParams->Result = MSG_CANT_CREATE_DBLSPACE;
+ break;
+
+ case FmIfsDblspaceMountFailed:
+ formatParams->Result = MSG_CANT_MOUNT_DBLSPACE;
+ break;
+
+ case FmIfsDblspaceDriveLetterFailed:
+ formatParams->Result = MSG_DBLSPACE_LETTER_FAILED;
+ break;
+
+ case FmIfsDblspaceCreated:
+
+ // Save the name of the double space file.
+
+ if (formatParams->DblspaceFileName = (PWSTR) Malloc(PacketLength)) {
+ memcpy(formatParams->DblspaceFileName, PacketData, PacketLength);
+ }
+ break;
+
+ case FmIfsDblspaceMounted:
+ break;
+#endif
+ default:
+ break;
+ }
+
+ return (formatParams->Result) ? FALSE : TRUE;
+}
+
+#ifdef DOUBLE_SPACE_SUPPORT_INCLUDED
+ULONG MountDismountResult;
+#define MOUNT_DISMOUNT_SUCCESS 0
+
+BOOLEAN
+FmIfsMountDismountCallback(
+ IN FMIFS_PACKET_TYPE PacketType,
+ IN DWORD PacketLength,
+ IN PVOID PacketData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine gets callbacks from fmifs.dll regarding
+ progress and status of the ongoing format or doublespace
+
+Arguments:
+
+ [PacketType] -- an fmifs packet type
+ [PacketLength] -- length of the packet data
+ [PacketData] -- data associated with the packet
+
+Return Value:
+
+ TRUE if the fmifs activity should continue, FALSE if the
+ activity should halt immediately. Thus, we return FALSE if
+ the user has hit "cancel" and we wish fmifs to clean up and
+ return from the Format() entrypoint call.
+
+--*/
+
+{
+ switch (PacketType) {
+ case FmIfsDblspaceMounted:
+ MountDismountResult = MOUNT_DISMOUNT_SUCCESS;
+ break;
+ }
+ return TRUE;
+}
+#endif
+
+VOID
+FormatVolume(
+ IN PVOID ThreadParameter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine converts the strings in the formatParams structure
+ and calls the fmifs routines to perform the format.
+
+ It assumes it is called by a separate thread and will exit the
+ thread on completion of the format.
+
+Arguments:
+
+ ThreadParameter - a pointer to the FORMAT_PARAMS structure
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PFORMAT_PARAMS formatParams = (PFORMAT_PARAMS) ThreadParameter;
+ PPERSISTENT_REGION_DATA regionData;
+ DWORD index;
+ WCHAR unicodeLabel[100],
+ unicodeFsType[20],
+ driveLetter[4];
+
+ // The fmifs interface doesn't allow for a context parameter
+ // therefore the formatparams must be passed through an external.
+
+ ParamsForCallBack = formatParams;
+
+ // set up a unicode drive letter.
+
+ regionData = (PPERSISTENT_REGION_DATA) formatParams->RegionData;
+ driveLetter[1] = L':';
+ driveLetter[2] = 0;
+ driveLetter[0] = (WCHAR) regionData->DriveLetter;
+
+ // convert label to unicode
+
+ setUnicode(formatParams->Label,
+ unicodeLabel);
+
+ // convert filesystem type to unicode
+
+ for (index = 0;
+ unicodeFsType[index] = (WCHAR)(formatParams->FileSystem[index]);
+ index++) {
+ // operation done in for loop
+ }
+
+ (*FormatRoutine)(driveLetter,
+ FmMediaUnknown,
+ unicodeFsType,
+ unicodeLabel,
+ (BOOLEAN)formatParams->QuickFormat,
+ &FmIfsCallback);
+
+ // Set the synchronization event to inform the windisk thread
+ // that this is complete and all handles have been closed.
+
+ formatParams->ThreadIsDone = 1;
+ ExitThread(0L);
+}
+
+#ifdef DOUBLE_SPACE_SUPPORT_INCLUDED
+VOID
+FmIfsCreateDblspace(
+ IN PVOID ThreadParameter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine converts the strings in the formatParams structure
+ and calls the fmifs routines to perform the double space create.
+
+ It assumes it is called by a separate thread and will exit the
+ thread on completion of the create.
+
+Arguments:
+
+ ThreadParameter - a pointer to the FORMAT_PARAMS structure
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PFORMAT_PARAMS formatParams = (PFORMAT_PARAMS) ThreadParameter;
+ PPERSISTENT_REGION_DATA regionData;
+ DWORD index;
+ UCHAR letter;
+ WCHAR unicodeLabel[100],
+ newDriveLetter[4],
+ driveLetter[4];
+
+ // The fmifs interface doesn't allow for a context parameter
+ // therefore the formatparams must be passed through an external.
+
+ ParamsForCallBack = formatParams;
+
+ // set up a unicode drive letter.
+
+ regionData = (PPERSISTENT_REGION_DATA) formatParams->RegionData;
+ driveLetter[1] = L':';
+ driveLetter[2] = 0;
+ driveLetter[0] = (WCHAR) regionData->DriveLetter;
+
+ // set up the new letter
+
+ newDriveLetter[1] = L':';
+ newDriveLetter[2] = 0;
+
+ // Choose the first available. This should come from the dialog
+ // newDriveLetter[0] = (WCHAR) formatParams->NewLetter;
+
+ for (letter='C'; letter <= 'Z'; letter++) {
+ if (DriveLetterIsAvailable((CHAR)letter)) {
+ newDriveLetter[0] = (WCHAR) letter;
+ break;
+ }
+ }
+
+ // convert label to unicode
+
+ setUnicode(formatParams->Label,
+ unicodeLabel);
+
+ (*DblSpaceCreateRoutine)(driveLetter,
+ formatParams->SpaceAvailable * 1024 * 1024,
+ unicodeLabel,
+ newDriveLetter,
+ &FmIfsCallback);
+ ExitThread(0L);
+}
+
+BOOL
+FmIfsDismountDblspace(
+ IN CHAR DriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ Convert the name provided into unicode and call the
+ FmIfs support routine.
+
+Arguments:
+
+ DriveLetter - the drive letter to dismount.
+
+Return Value:
+
+ TRUE - it worked.
+
+--*/
+
+{
+ WCHAR unicodeLetter[4];
+ ULONG index;
+
+ unicodeLetter[0] = (WCHAR) DriveLetter;
+ unicodeLetter[1] = (WCHAR) ':';
+ unicodeLetter[2] = 0;
+
+ // The only way to communicate with the fmifs callback
+ // is through global externals.
+
+ MountDismountResult = MSG_CANT_DISMOUNT_DBLSPACE;
+
+ (*DblSpaceDismountRoutine)(unicodeLetter, &FmIfsMountDismountCallback);
+
+ return MountDismountResult;
+}
+
+BOOL
+FmIfsMountDblspace(
+ IN PCHAR FileName,
+ IN CHAR HostDrive,
+ IN CHAR NewDrive
+ )
+
+/*++
+
+Routine Description:
+
+ Convert the arguments into unicode characters and
+ call the FmIfs support routine to mount the double
+ space volume.
+
+Arguments:
+
+ FileName - ASCII file name (i.e. dblspace.xxx)
+ HostDrive - Drive drive letter containing double space volume
+ NewDrive - Drive letter to be assigned to the volume
+
+Return Value:
+
+ TRUE it worked.
+
+--*/
+
+{
+ WCHAR wideFileName[40];
+ WCHAR wideHostDrive[4];
+ WCHAR wideNewDrive[4];
+ ULONG index;
+
+ // convert the double space file name.
+
+ for (index = 0; wideFileName[index] = (WCHAR) FileName[index]; index++) {
+ // all work done in for expression
+ }
+
+ // convert the drive names.
+
+ wideNewDrive[1] = wideHostDrive[1] = (WCHAR) ':';
+ wideNewDrive[2] = wideHostDrive[2] = 0;
+
+ wideNewDrive[0] = (WCHAR) NewDrive;
+ wideHostDrive[0] = (WCHAR) HostDrive;
+
+ // The only way to communicate with the fmifs callback
+ // is through global externals.
+
+ MountDismountResult = MSG_CANT_MOUNT_DBLSPACE;
+
+ (*DblSpaceMountRoutine)(wideHostDrive,
+ wideFileName,
+ wideNewDrive,
+ &FmIfsMountDismountCallback);
+ return MountDismountResult;
+}
+
+BOOLEAN
+FmIfsQueryInformation(
+ IN PWSTR DosDriveName,
+ OUT PBOOLEAN IsRemovable,
+ OUT PBOOLEAN IsFloppy,
+ OUT PBOOLEAN IsCompressed,
+ OUT PBOOLEAN Error,
+ OUT PWSTR NtDriveName,
+ IN ULONG MaxNtDriveNameLength,
+ OUT PWSTR CvfFileName,
+ IN ULONG MaxCvfFileNameLength,
+ OUT PWSTR HostDriveName,
+ IN ULONG MaxHostDriveNameLength
+ )
+
+/*++
+
+Routine Description:
+
+ Call through the pointer to the routine in the fmifs dll.
+
+Arguments:
+
+ Same as the Fmifs routine in the DLL.
+
+Return Value:
+
+--*/
+
+{
+ if (!DblSpaceQueryInfoRoutine) {
+ return FALSE;
+ }
+ return (*DblSpaceQueryInfoRoutine)(DosDriveName,
+ IsRemovable,
+ IsFloppy,
+ IsCompressed,
+ Error,
+ NtDriveName,
+ MaxNtDriveNameLength,
+ CvfFileName,
+ MaxCvfFileNameLength,
+ HostDriveName,
+ MaxHostDriveNameLength);
+}
+#endif
+
+BOOL
+CancelDlgProc(
+ IN HWND hDlg,
+ IN UINT uMsg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Dialog procedure for the modeless progress & cancel dialog
+ Two main purposes here:
+ 1. if the user chooses CANCEL we set bCancel to TRUE
+ which will end the PeekMessage background processing loop
+ 2. handle the private FS_CANCELUPDATE message and draw
+ a "gas gauge" indication of how far the background job
+ has progressed
+
+Arguments:
+
+ standard Windows dialog procedure
+
+Return Values:
+
+ standard Windows dialog procedure
+
+--*/
+
+{
+ static DWORD percentDrawn;
+ static RECT rectGG; // GasGauge rectangle
+ static BOOL captionIsLoaded;
+ static PFORMAT_PARAMS formatParams;
+ TCHAR title[100],
+ templateString[100];
+
+ switch (uMsg) {
+ case WM_INITDIALOG: {
+ PPERSISTENT_REGION_DATA regionData;
+ HANDLE threadHandle;
+ DWORD threadId;
+ HWND hwndGauge = GetDlgItem(hDlg, IDC_GASGAUGE);
+
+ // set up the dialog handle in the parameter block so the
+ // call back routine can communicate with this routine
+ // and initialize static variables.
+
+ formatParams = (PFORMAT_PARAMS) lParam;
+ formatParams->DialogHwnd = hDlg;
+ regionData = (PPERSISTENT_REGION_DATA) formatParams->RegionData;
+ percentDrawn = 0;
+ captionIsLoaded = FALSE;
+
+ // Set the caption string.
+
+ LoadString(hModule, IDS_FORMAT_TITLE, templateString, sizeof(templateString)/sizeof(TCHAR));
+ wsprintf(title,
+ templateString,
+ regionData->DriveLetter);
+ SetWindowText(hDlg, title);
+
+#ifdef DOUBLE_SPACE_SUPPORT_INCLUDED
+ if (formatParams->DoubleSpace) {
+
+ // start the double space create thread
+
+ threadHandle = CreateThread(NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE) FmIfsCreateDblspace,
+ (LPVOID) formatParams,
+ (DWORD) 0,
+ (LPDWORD) &threadId);
+ } else {
+#endif
+
+ // start the format thread
+
+ threadHandle = CreateThread(NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE) FormatVolume,
+ (LPVOID) formatParams,
+ (DWORD) 0,
+ (LPDWORD) &threadId);
+#ifdef DOUBLE_SPACE_SUPPORT_INCLUDED
+ }
+#endif
+ if (!threadHandle) {
+ // can't do it now.
+
+ formatParams->Result = MSG_COULDNT_CREATE_THREAD;
+ EndDialog(hDlg, FALSE);
+ return TRUE;
+ }
+
+ // no need to keep the handle around.
+
+ CloseHandle(threadHandle);
+
+ // Get the coordinates of the gas gauge static control rectangle,
+ // and convert them to dialog client area coordinates
+
+ GetClientRect(hwndGauge, &rectGG);
+ ClientToScreen(hwndGauge, (LPPOINT)&rectGG.left);
+ ClientToScreen(hwndGauge, (LPPOINT)&rectGG.right);
+ ScreenToClient(hDlg, (LPPOINT)&rectGG.left);
+ ScreenToClient(hDlg, (LPPOINT)&rectGG.right);
+ return TRUE;
+ }
+
+ case WM_COMMAND:
+
+ switch (wParam) {
+ case IDCANCEL:
+
+ formatParams->Result = MSG_FORMAT_CANCELLED;
+ formatParams->Cancel = TRUE;
+ EndDialog(hDlg, FALSE);
+ }
+ return TRUE;
+
+ case WM_PAINT: {
+ INT width = rectGG.right - rectGG.left;
+ INT height = rectGG.bottom - rectGG.top;
+ INT nDivideRects;
+ HDC hDC;
+ PAINTSTRUCT ps;
+ TCHAR buffer[100];
+ SIZE size;
+ INT xText,
+ yText,
+ byteCount;
+ RECT rectDone,
+ rectLeftToDo;
+
+ // The gas gauge is drawn by drawing a text string stating
+ // what percentage of the job is done into the middle of
+ // the gas gauge rectangle, and by separating that rectangle
+ // into two parts: rectDone (the left part, filled in blue)
+ // and rectLeftToDo(the right part, filled in white).
+ // nDivideRects is the x coordinate that divides these two rects.
+ //
+ // The text in the blue rectangle is drawn white, and vice versa
+ // This is easy to do with ExtTextOut()!
+
+ hDC = BeginPaint(hDlg, &ps);
+
+ // If formatting quick, set this display
+
+ if (!captionIsLoaded) {
+ UINT resourceId = IDS_PERCENTCOMPLETE;
+
+ if (formatParams->QuickFormat) {
+ resourceId = IDS_QUICK_FORMAT;
+ }
+#ifdef DOUBLE_SPACE_SUPPORT_INCLUDED
+ if (formatParams->DoubleSpace) {
+ resourceId = IDS_CREATING_DBLSPACE;
+ }
+#endif
+ LoadString(hModule,
+ resourceId,
+ buffer,
+ sizeof(buffer)/sizeof(TCHAR));
+ if (!formatParams->QuickFormat) {
+ SetDlgItemText(hDlg, IDC_TEXT, buffer);
+ }
+ captionIsLoaded = TRUE;
+ }
+
+ if (formatParams->QuickFormat) {
+ nDivideRects = 0;
+ byteCount = lstrlen(buffer);
+ } else {
+ byteCount = wsprintf(buffer, TEXT("%3d%%"), percentDrawn);
+ nDivideRects = (width * percentDrawn) / 100;
+ }
+
+ GetTextExtentPoint(hDC, buffer, lstrlen(buffer), &size);
+ xText = rectGG.left + (width - size.cx) / 2;
+ yText = rectGG.top + (height - size.cy) / 2;
+
+
+ // Paint in the "done so far" rectangle of the gas
+ // gauge with blue background and white text
+
+ SetRect(&rectDone,
+ rectGG.left,
+ rectGG.top,
+ rectGG.left + nDivideRects,
+ rectGG.bottom);
+
+ SetTextColor(hDC, RGB(255, 255, 255));
+ SetBkColor(hDC, RGB(0, 0, 255));
+
+ ExtTextOut(hDC,
+ xText,
+ yText,
+ ETO_CLIPPED | ETO_OPAQUE,
+ &rectDone,
+ buffer,
+ byteCount/sizeof(TCHAR),
+ NULL);
+
+ // Paint in the "still left to do" rectangle of the gas
+ // gauge with white background and blue text
+
+ SetRect(&rectLeftToDo,
+ rectGG.left + nDivideRects,
+ rectGG.top,
+ rectGG.right,
+ rectGG.bottom);
+ SetTextColor(hDC, RGB(0, 0, 255));
+ SetBkColor(hDC, RGB(255, 255, 255));
+
+ ExtTextOut(hDC,
+ xText,
+ yText,
+ ETO_CLIPPED | ETO_OPAQUE,
+ &rectLeftToDo,
+ buffer,
+ byteCount/sizeof(TCHAR),
+ NULL);
+ EndPaint(hDlg, &ps);
+ return TRUE;
+ }
+
+ case FS_CANCELUPDATE:
+
+ // wParam = % completed
+
+ percentDrawn = (INT)wParam;
+ InvalidateRect(hDlg, &rectGG, TRUE);
+ UpdateWindow(hDlg);
+ return TRUE;
+
+ case FS_FINISHED:
+
+ EndDialog(hDlg, TRUE);
+ return TRUE;
+
+ default:
+
+ return FALSE;
+ }
+}
+
+INT
+LabelDlgProc(
+ IN HWND hDlg,
+ IN UINT wMsg,
+ IN WPARAM wParam,
+ IN LONG lParam)
+
+/*++
+
+Routine Description:
+
+ This routine manages the label dialog.
+ Upon completion of the dialog it will end the dialog with a result of
+ TRUE to indicate that all is set up for the label operation. FALSE if
+ the label operation has been cancelled by the user.
+
+Arguments:
+
+ Standard Windows dialog procedure.
+
+Return Value:
+
+ Standard Windows dialog procedure.
+
+--*/
+
+{
+ static PLABEL_PARAMS labelParams;
+ static PREGION_DESCRIPTOR regionDescriptor;
+ static PPERSISTENT_REGION_DATA regionData;
+ char text[100];
+ TCHAR uniText[100];
+ int labelSize;
+ TCHAR title[100],
+ templateString[100];
+
+ switch (wMsg) {
+ case WM_INITDIALOG:
+
+ labelParams = (PLABEL_PARAMS) lParam;
+ regionDescriptor = labelParams->RegionDescriptor;
+ regionData = PERSISTENT_DATA(regionDescriptor);
+
+ // Set the caption string.
+ //
+ LoadString(hModule, IDS_LABEL_TITLE, templateString, sizeof(templateString)/sizeof(TCHAR));
+ wsprintf(title,
+ templateString,
+ regionData->DriveLetter);
+ SetWindowText(hDlg, title);
+
+ // Convert the volume label into the proper type for windows.
+
+ wsprintf(text, "%ws", regionData->VolumeLabel);
+ UnicodeHack(text, uniText);
+ SetDlgItemText(hDlg, IDC_NAME, uniText);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (wParam) {
+
+ case FD_IDHELP:
+
+ DialogHelp(HC_DM_DLG_LABEL);
+ break;
+
+ case IDCANCEL:
+
+ EndDialog(hDlg, FALSE);
+ break;
+
+ case IDOK:
+
+ labelSize = GetDlgItemText(hDlg, IDC_NAME, text, 100);
+ UnicodeHack(text, labelParams->NewLabel);
+ EndDialog(hDlg, TRUE);
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+#define NUM_FSTYPES 2
+#define MAX_FSTYPENAME_SIZE 6
+
+// HPFS is not supported -- therefore commented out.
+
+TCHAR *FsTypes[NUM_FSTYPES + 1] = { "NTFS",
+ /* "HPFS", */
+ "FAT" };
+WCHAR *UnicodeFsTypes[NUM_FSTYPES] = { L"NTFS",
+ /* L"HPFS", */
+ L"FAT" };
+
+INT
+FormatDlgProc(
+ IN HWND hDlg,
+ IN UINT wMsg,
+ IN WPARAM wParam,
+ IN LONG lParam)
+
+/*++
+
+Routine Description:
+
+ This routine manages the format dialog. Upon completion it ends the
+ dialog with a result value of TRUE to indicate that the format operation
+ is to take place. FALSE is the result if the user cancels out of the
+ dialog.
+
+Arguments:
+
+ Standard Windows dialog procedure.
+
+Return Value:
+
+ Standard Windows dialog procedure.
+
+--*/
+
+{
+ static HWND hwndCombo;
+ static PFORMAT_PARAMS formatParams;
+ static PREGION_DESCRIPTOR regionDescriptor;
+ static PPERSISTENT_REGION_DATA regionData;
+ char text[40];
+ TCHAR uniText[40];
+ INT i;
+ DWORD selection;
+ BOOL quickFormat = FALSE;
+ HWND hwndButton;
+ TCHAR title[100],
+ templateString[100];
+
+ UNREFERENCED_PARAMETER(lParam);
+
+ switch (wMsg) {
+ case WM_INITDIALOG: {
+ PWSTR typeName = NULL,
+ volumeLabel = NULL;
+ WCHAR driveLetter = L' ';
+
+ // since the format params are static reset the quick format boolean.
+
+ formatParams = (PFORMAT_PARAMS) lParam;
+ formatParams->QuickFormat = FALSE;
+
+ // get format params, set static values and
+ // get information about the volume
+
+ hwndCombo = GetDlgItem(hDlg, IDC_FSTYPE);
+ regionDescriptor = formatParams->RegionDescriptor;
+ DetermineRegionInfo(regionDescriptor,
+ &typeName,
+ &volumeLabel,
+ &driveLetter);
+ regionData = PERSISTENT_DATA(regionDescriptor);
+
+ // Set the caption string.
+
+ LoadString(hModule, IDS_FORMAT_TITLE, templateString, sizeof(templateString)/sizeof(TCHAR));
+ wsprintf(title,
+ templateString,
+ regionData->DriveLetter);
+ SetWindowText(hDlg, title);
+
+ // Convert the volume label into the proper type for windows
+ // and set default values.
+
+ wsprintf(text, "%ws", regionData->VolumeLabel);
+ UnicodeHack(text, uniText);
+ SetDlgItemText(hDlg, IDC_NAME, uniText);
+ CheckDlgButton(hDlg, IDC_VERIFY, quickFormat);
+ SendDlgItemMessage(hDlg, IDOK, EM_SETSEL, 0, -1);
+
+ // If this volume is a mirror or stripe with parity,
+ // disable Quick Format.
+
+ if (regionData->FtObject != NULL &&
+ (regionData->FtObject->Set->Type == Mirror ||
+ regionData->FtObject->Set->Type == StripeWithParity)) {
+
+ hwndButton = GetDlgItem(hDlg, IDC_VERIFY);
+
+ if (hwndButton != NULL) {
+
+ EnableWindow(hwndButton, FALSE);
+ }
+ }
+
+ selection = 0;
+ if (IsDiskRemovable[regionDescriptor->Disk]) {
+
+ // If removable, start from the bottom of the list so FAT is first.
+ // Load the available File system types.
+
+ for (i = NUM_FSTYPES - 1; i >= 0; i--) {
+
+ // Fill the drop down list.
+
+ SendMessage(hwndCombo, CB_ADDSTRING, 0, (LONG)FsTypes[i]);
+ }
+
+ } else {
+
+ // Load the available File system types.
+
+ for (i = 0; i < NUM_FSTYPES; i++) {
+
+ // While filling in the drop down, determine which FS
+ // this volume is already formated for and make it the
+ // default (if not found, NTFS is the default).
+
+ if (wcscmp(typeName, UnicodeFsTypes[i]) == 0) {
+ selection = i;
+ }
+
+ // set the FS type into the dialog.
+
+ SendMessage(hwndCombo, CB_ADDSTRING, 0, (LONG)FsTypes[i]);
+ }
+ }
+
+ SendMessage(hwndCombo, CB_SETCURSEL, selection, 0);
+ return TRUE;
+ break;
+ }
+
+ case WM_COMMAND:
+
+ switch (wParam) {
+
+ case FD_IDHELP:
+
+ DialogHelp(HC_DM_DLG_FORMAT);
+ break;
+
+ case IDCANCEL:
+
+ EndDialog(hDlg, FALSE);
+ break;
+
+ case IDOK: {
+ int labelSize;
+
+ // pull the parameters from the dialog
+ // and return with success.
+
+ selection = SendMessage(hwndCombo, CB_GETCURSEL, 0, 0);
+ SendMessage(hwndCombo,
+ CB_GETLBTEXT,
+ selection,
+ (LONG)formatParams->FileSystem);
+ labelSize = GetDlgItemText(hDlg,
+ IDC_NAME,
+ (LPTSTR) formatParams->Label,
+ 100);
+ if (IsDlgButtonChecked(hDlg, IDC_VERIFY)) {
+ formatParams->QuickFormat = TRUE;
+ }
+ EndDialog(hDlg, TRUE);
+ break;
+ }
+
+ default:
+
+ return FALSE;
+ }
+
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+VOID
+FormatPartition(
+ PREGION_DESCRIPTOR RegionDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ Insure the IFS Dll is loaded and start the dialog for format
+ of a volume.
+
+Arguments:
+
+ RegionDescriptor - The region to format.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ static FORMAT_PARAMS formatParams; // this is passed to other threads
+ // it cannot be located on the stack
+ PPERSISTENT_REGION_DATA regionData;
+ int doFormat;
+ ULONG diskSize;
+ PWSTR tempName,
+ tempLabel,
+ typeName;
+ TCHAR label[100],
+ fileSystem[10],
+ message[300],
+ msgProto[300],
+ title[200];
+
+ // Make sure format of this partition is allowed. It is not allowed
+ // if it is the boot partition (or sys partition on x86).
+
+ if ((DeletionIsAllowed(RegionDescriptor)) != NO_ERROR) {
+ ErrorDialog(MSG_CANT_FORMAT_WINNT);
+ return;
+ }
+
+ // must have a drive letter
+
+ regionData = PERSISTENT_DATA(RegionDescriptor);
+ if (!regionData->DriveLetter) {
+ ErrorDialog(MSG_CANT_FORMAT_NO_LETTER);
+ return;
+ }
+
+ // can only do this is the dll is loaded.
+
+ if (!LoadIfsDll()) {
+
+ // could not load the dll
+
+ ErrorDialog(MSG_CANT_LOAD_FMIFS);
+ return;
+ }
+
+ // set up the parameters and get the information from the user.
+
+ formatParams.RegionDescriptor = RegionDescriptor;
+ formatParams.Result = 0;
+ formatParams.RegionData = regionData;
+ formatParams.Label = (PUCHAR) label;
+ formatParams.FileSystem = (PUCHAR) fileSystem;
+ formatParams.QuickFormat = formatParams.Cancel =
+ formatParams.DoubleSpace = FALSE;
+ formatParams.TotalSpace = formatParams.SpaceAvailable = 0;
+ doFormat = DialogBoxParam(hModule,
+ MAKEINTRESOURCE(IDD_PARTITIONFORMAT),
+ hwndFrame,
+ (DLGPROC) FormatDlgProc,
+ (ULONG) &formatParams);
+ if (doFormat) {
+
+ // do an are you sure message.
+
+ doFormat = ConfirmationDialog(MSG_CONFIRM_FORMAT,
+ MB_ICONQUESTION | MB_YESNO);
+ if (doFormat == IDYES) {
+
+ if (IsDiskRemovable[RegionDescriptor->Disk]) {
+ PWSTR typeName,
+ volumeLabel;
+ BOOLEAN volumeChanged = FALSE;
+
+ if (!RegionDescriptor->PartitionNumber) {
+
+ // TODO: something has changed where the code gets to this
+ // point with an incorrect partition number - This happens
+ // when a partition is deleted and added to removable media.
+ // For removable media the partition number is always 1.
+
+ RegionDescriptor->PartitionNumber = 1;
+ }
+ if (GetVolumeTypeAndSize(RegionDescriptor->Disk,
+ RegionDescriptor->PartitionNumber,
+ &volumeLabel,
+ &typeName,
+ &diskSize) == OK_STATUS) {
+
+ // Verify that this is still the same device.
+
+ if (typeName) {
+ if (!lstrcmpiW(typeName, L"raw")) {
+ Free(typeName);
+ typeName = Malloc((wcslen(wszUnknown) * sizeof(WCHAR)) + sizeof(WCHAR));
+ lstrcpyW(typeName, wszUnknown);
+ }
+ } else {
+ typeName = Malloc((wcslen(wszUnknown) * sizeof(WCHAR)) + sizeof(WCHAR));
+ lstrcpyW(typeName, wszUnknown);
+ }
+ if (regionData) {
+ if (regionData->VolumeLabel) {
+ if (wcscmp(regionData->VolumeLabel, volumeLabel)) {
+ volumeChanged = TRUE;
+ }
+ }
+ if (regionData->TypeName) {
+
+ // It is possible the region has no type
+ // or is of type "Unformatted".
+ // This says it is ok to format.
+
+ if (*regionData->TypeName) {
+
+ if (wcscmp(regionData->TypeName, wszUnformatted)) {
+
+ // It has a type and it isn't
+ // unformatted - see if it is
+ // the same as before.
+
+ if (wcscmp(regionData->TypeName, typeName)) {
+ volumeChanged = TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ if (Disks[RegionDescriptor->Disk]->DiskSizeMB != (diskSize/1024)) {
+ volumeChanged = TRUE;
+ }
+ if (volumeChanged) {
+
+ ErrorDialog(MSG_VOLUME_CHANGED);
+
+ // since the user was told the volume changed,
+ // update the display.
+
+ SetCursor(hcurWait);
+ if (GetVolumeTypeAndSize(RegionDescriptor->Disk,
+ RegionDescriptor->PartitionNumber,
+ &tempLabel,
+ &tempName,
+ &diskSize) == OK_STATUS) {
+ Free(typeName);
+ typeName = tempName;
+ Free(volumeLabel);
+ volumeLabel = tempLabel;
+ }
+ if (regionData->VolumeLabel) {
+ Free(regionData->VolumeLabel);
+ }
+ regionData->VolumeLabel = volumeLabel;
+ if (regionData->TypeName) {
+ Free(regionData->TypeName);
+ }
+ regionData->TypeName = typeName;
+ SetCursor(hcurNormal);
+ TotalRedrawAndRepaint();
+ return;
+ } else {
+ if (volumeLabel) {
+ Free(volumeLabel);
+ }
+ if (typeName) {
+ Free(typeName);
+ }
+ }
+ }
+ }
+
+ // Insure the partition is not to big if the requested format
+ // is FAT.
+
+ if (!strcmpi(formatParams.FileSystem, "FAT")) {
+
+ if (GetVolumeSizeMB(RegionDescriptor->Disk,
+ RegionDescriptor->PartitionNumber,
+ &diskSize)) {
+ if (diskSize > (4*1024)) {
+ ErrorDialog(MSG_TOO_BIG_FOR_FAT);
+ TotalRedrawAndRepaint();
+ return;
+ }
+ } else {
+
+ // Just try the format anyway.
+
+ }
+ }
+
+ // Initialize synchronization event to know when the
+ // format thread is really complete.
+
+ formatParams.ThreadIsDone = 0;
+
+ // user still wants to format.
+
+ DialogBoxParam(hModule,
+ MAKEINTRESOURCE(IDD_FORMATCANCEL),
+ hwndFrame,
+ (DLGPROC) CancelDlgProc,
+ (ULONG) &formatParams);
+ if (formatParams.Result) {
+
+ // the format failed.
+
+ ErrorDialog(formatParams.Result);
+ } else {
+
+ LoadString(hModule,
+ IDS_FORMATCOMPLETE,
+ title,
+ sizeof(title)/sizeof(TCHAR));
+ LoadString(hModule,
+ IDS_FORMATSTATS,
+ msgProto,
+ sizeof(msgProto)/sizeof(TCHAR));
+ wsprintf(message,
+ msgProto,
+ formatParams.TotalSpace,
+ formatParams.SpaceAvailable);
+ MessageBox(GetActiveWindow(),
+ message,
+ title,
+ MB_ICONINFORMATION | MB_OK);
+
+ }
+
+ // Synchronize with the format thread just in case
+ // the user did a cancel and the format thread is
+ // still buzy verifying 50MB or some such thing.
+ // Rather than use an event this is a polling loop.
+
+ SetCursor(hcurWait);
+ while (!formatParams.ThreadIsDone) {
+ Sleep(1000);
+ }
+ SetCursor(hcurNormal);
+
+ // If the format was successful, update the volume
+ // information in the data structures.
+
+ if (!formatParams.Result) {
+
+ // get the new label and FsType regardless of success of the
+ // format (i.e. user cancel may have occurred, so this stuff
+ // is not what it used to be even if the format failed.
+
+ {
+ // force mount by filesystem. This is done with the
+ // extra \ on the end of the path. This must be done
+ // in order to get the FS type. Otherwise the filesystem
+ // recognisor may allow the open without actually getting
+ // the file system involved.
+
+ char ntDeviceName[100];
+ STATUS_CODE sc;
+ HANDLE_T handle;
+
+ sprintf(ntDeviceName, "\\DosDevices\\%c:\\", regionData->DriveLetter);
+ sc = LowOpenNtName(ntDeviceName, &handle);
+ if (sc == OK_STATUS) {
+ LowCloseDisk(handle);
+ }
+ }
+ typeName = NULL;
+ GetTypeName(RegionDescriptor->Disk, RegionDescriptor->PartitionNumber, &typeName);
+
+ if (!typeName) {
+
+ // Failed to get the type after a cancel. This means
+ // GetTypeName() could not open the volume for some reason.
+ // This has been seen on Alpha's and x86 with large
+ // hardware raid devices. Exiting and starting
+ // over will get an FS type. For now, don't change the
+ // data structures.
+
+ TotalRedrawAndRepaint();
+ return;
+ }
+
+ tempLabel = NULL;
+ if (GetVolumeLabel(RegionDescriptor->Disk, RegionDescriptor->PartitionNumber, &tempLabel) == NO_ERROR) {
+
+ if (tempLabel) {
+ Free(regionData->VolumeLabel);
+ regionData->VolumeLabel = Malloc((lstrlenW(tempLabel) + 1) * sizeof(WCHAR));
+ lstrcpyW(regionData->VolumeLabel, tempLabel);
+ }
+ } else {
+ *regionData->VolumeLabel = 0;
+ }
+
+ // update the type name.
+
+ if (regionData->TypeName) {
+ Free(regionData->TypeName);
+ regionData->TypeName = typeName;
+ }
+
+ // update the file system type information for all
+ // components of this region (i.e. fix up FT structures if
+ // it is an FT item). This is done via knowledge about multiple
+ // selections as opposed to walking through the FtObject list.
+
+ if (SelectionCount > 1) {
+ PPERSISTENT_REGION_DATA passedRegionData;
+ ULONG index;
+
+ // Need to update all involved.
+
+ passedRegionData = regionData;
+
+ for (index = 0; index < SelectionCount; index++) {
+ RegionDescriptor = &SELECTED_REGION(index);
+ regionData = PERSISTENT_DATA(RegionDescriptor);
+
+ if (regionData == passedRegionData) {
+ continue;
+ }
+
+ if (regionData->VolumeLabel) {
+ Free(regionData->VolumeLabel);
+ regionData->VolumeLabel = NULL;
+ }
+ if (tempLabel) {
+ regionData->VolumeLabel = Malloc((lstrlenW(tempLabel) + 1) * sizeof(WCHAR));
+ lstrcpyW(regionData->VolumeLabel, tempLabel);
+ }
+
+ if (regionData->TypeName) {
+ Free(regionData->TypeName);
+ }
+ regionData->TypeName = Malloc((lstrlenW(passedRegionData->TypeName) + 1) * sizeof(WCHAR));
+ lstrcpyW(regionData->TypeName, passedRegionData->TypeName);
+ }
+ }
+
+ if (tempLabel) {
+ Free(tempLabel);
+ }
+ }
+
+ // force screen update.
+
+ TotalRedrawAndRepaint();
+ }
+ }
+}
+
+VOID
+LabelPartition(
+ PREGION_DESCRIPTOR RegionDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ Insure the IFS Dll is loaded and start the dialog for label
+ of a volume.
+
+Arguments:
+
+ RegionDescriptor - the region for the label.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ int doLabel;
+ DWORD ec;
+ TCHAR label[100];
+ WCHAR unicodeLabel[100];
+ LABEL_PARAMS labelParams;
+ WCHAR driveLetter[4];
+ PWSTR tmpLabel;
+ PPERSISTENT_REGION_DATA regionData;
+
+ if (!LoadIfsDll()) {
+
+ // could not load the Dll
+
+ ErrorDialog(MSG_CANT_LOAD_FMIFS);
+ return;
+ }
+ labelParams.RegionDescriptor = RegionDescriptor;
+ labelParams.NewLabel = (LPTSTR)label;
+ doLabel = DialogBoxParam(hModule,
+ MAKEINTRESOURCE(IDD_PARTITIONLABEL),
+ hwndFrame,
+ (DLGPROC) LabelDlgProc,
+ (ULONG) &labelParams);
+ if (doLabel) {
+
+ regionData = PERSISTENT_DATA(RegionDescriptor);
+
+ if (IsDiskRemovable[RegionDescriptor->Disk]) {
+ PWSTR typeName,
+ volumeLabel;
+ ULONG diskSize;
+ BOOLEAN volumeChanged = FALSE;
+
+ if (GetVolumeTypeAndSize(RegionDescriptor->Disk,
+ RegionDescriptor->PartitionNumber,
+ &volumeLabel,
+ &typeName,
+ &diskSize) == OK_STATUS) {
+ // Verify that this is still the same device.
+
+ if (regionData) {
+ if (regionData->VolumeLabel) {
+ if (wcscmp(regionData->VolumeLabel, volumeLabel)) {
+ volumeChanged = TRUE;
+ }
+ }
+ if (regionData->TypeName) {
+ if (wcscmp(regionData->TypeName, typeName)) {
+ volumeChanged = TRUE;
+ }
+ }
+ }
+
+ if (Disks[RegionDescriptor->Disk]->DiskSizeMB != (diskSize/1024)) {
+ volumeChanged = TRUE;
+ }
+
+ if (volumeChanged) {
+ PWSTR tempName,
+ tempLabel;
+
+ ErrorDialog(MSG_VOLUME_CHANGED);
+
+ // since the user was told the volume changed,
+ // update the display.
+
+ SetCursor(hcurWait);
+ if (GetVolumeTypeAndSize(RegionDescriptor->Disk,
+ RegionDescriptor->PartitionNumber,
+ &tempLabel,
+ &tempName,
+ &diskSize) == OK_STATUS) {
+ Free(typeName);
+ typeName = tempName;
+ Free(volumeLabel);
+ volumeLabel = tempLabel;
+ }
+ if (regionData->VolumeLabel) {
+ Free(regionData->VolumeLabel);
+ }
+ regionData->VolumeLabel = volumeLabel;
+ if (regionData->TypeName) {
+ Free(regionData->TypeName);
+ }
+ regionData->TypeName = typeName;
+ SetCursor(hcurNormal);
+ TotalRedrawAndRepaint();
+ return;
+ } else {
+ Free(volumeLabel);
+ Free(typeName);
+ }
+ }
+ }
+ driveLetter[1] = L':';
+ driveLetter[2] = 0;
+ driveLetter[0] = (WCHAR)regionData->DriveLetter;
+
+ // convert to unicode - use variable doLabel as an index.
+
+ setUnicode(label,
+ unicodeLabel);
+
+ // perform the label.
+
+ SetCursor(hcurWait);
+ (*LabelRoutine)(driveLetter, unicodeLabel);
+
+ ec = GetLastError();
+
+ if (ec != NO_ERROR) {
+ SetCursor(hcurNormal);
+ ErrorDialog(ec);
+ SetCursor(hcurWait);
+ }
+
+ // get the new label to be certain it took and update
+ // the internal structures.
+
+ if (GetVolumeLabel(RegionDescriptor->Disk, RegionDescriptor->PartitionNumber, &tmpLabel) == NO_ERROR) {
+ Free(regionData->VolumeLabel);
+ regionData->VolumeLabel = Malloc((lstrlenW(tmpLabel) + 1) * sizeof(WCHAR));
+ lstrcpyW(regionData->VolumeLabel, tmpLabel);
+ } else {
+ *regionData->VolumeLabel = 0;
+ }
+
+ // update the label for all
+ // components of this region (i.e. fix up FT structures if
+ // it is an FT item). This is done via knowledge about multiple
+ // selections as opposed to walking through the FtObject list.
+
+ if (SelectionCount > 1) {
+ PPERSISTENT_REGION_DATA passedRegionData;
+ ULONG index;
+
+ // Need to update all involved.
+
+ passedRegionData = regionData;
+
+ for (index = 0; index < SelectionCount; index++) {
+ RegionDescriptor = &SELECTED_REGION(index);
+ regionData = PERSISTENT_DATA(RegionDescriptor);
+
+ if (regionData == passedRegionData) {
+ continue;
+ }
+
+ if (regionData->VolumeLabel) {
+ Free(regionData->VolumeLabel);
+ regionData->VolumeLabel = NULL;
+ }
+ if (tmpLabel) {
+ regionData->VolumeLabel = Malloc((lstrlenW(tmpLabel) + 1) * sizeof(WCHAR));
+ lstrcpyW(regionData->VolumeLabel, tmpLabel);
+ } else {
+ *regionData->VolumeLabel = 0;
+ }
+ }
+ }
+ if (tmpLabel) {
+ Free(tmpLabel);
+ }
+ SetCursor(hcurNormal);
+
+ // force screen update.
+
+ TotalRedrawAndRepaint();
+ }
+}
diff --git a/private/utils/fdisk/ftreg.c b/private/utils/fdisk/ftreg.c
new file mode 100644
index 000000000..86ee9a20d
--- /dev/null
+++ b/private/utils/fdisk/ftreg.c
@@ -0,0 +1,1201 @@
+
+/*++
+
+Copyright (c) 1991-1994 Microsoft Corporation
+
+Module Name:
+
+ ftreg.c
+
+Abstract:
+
+ This module contains the routines for Disk Administrator that deal
+ with registry manipulation
+
+Author:
+
+ Edward (Ted) Miller (TedM) 11/15/91
+
+Environment:
+
+ User process.
+
+Notes:
+
+Revision History:
+
+ 1-Feb-94 (bobri) Clean up and handle missing floppy disk on registry
+ save/restore.
+
+--*/
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <windows.h>
+
+#include "fdisk.h"
+#include "ftregres.h"
+
+
+
+// attempt to avoid conflict
+
+#define TEMP_KEY_NAME TEXT("xzss3___$$Temp$Hive$$___")
+
+#define DISK_KEY_NAME TEXT("DISK")
+#define DISK_VALUE_NAME TEXT("Information")
+
+
+LONG
+FdpLoadHiveIntoRegistry(
+ IN LPTSTR HiveFilename
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes the contents of a given hive file into the registry,
+ rooted at a temporary key in HKEY_LOCAL_MACHINE.
+
+Arguments:
+
+ HiveFilename - supplies filename of the hive to be loaded into
+ the registry
+
+Return Value:
+
+ Windows error code.
+
+--*/
+
+{
+ NTSTATUS Status;
+ BOOLEAN OldPrivState;
+ LONG Err;
+
+ // Attempt to get restore privilege
+
+ Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE,
+ TRUE,
+ FALSE,
+ &OldPrivState);
+ if (!NT_SUCCESS(Status)) {
+ return RtlNtStatusToDosError(Status);
+ }
+
+ // Load the hive into our registry
+
+ Err = RegLoadKey(HKEY_LOCAL_MACHINE,TEMP_KEY_NAME,HiveFilename);
+
+ // Restore old privilege if necessary
+
+ if (!OldPrivState) {
+
+ RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE,
+ FALSE,
+ FALSE,
+ &OldPrivState);
+ }
+
+ return Err;
+}
+
+
+LONG
+FdpUnloadHiveFromRegistry(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes a tree (previously loaded with
+ FdpLoadHiveIntoRegistry) from the temporary key in HKEY_LOCAL_MACHINE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Windows error code.
+
+--*/
+
+{
+ NTSTATUS Status;
+ BOOLEAN OldPrivState;
+ LONG Err;
+
+ // Attempt to get restore privilege
+
+ Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE,
+ TRUE,
+ FALSE,
+ &OldPrivState);
+ if (!NT_SUCCESS(Status)) {
+ return RtlNtStatusToDosError(Status);
+ }
+
+ // Unload the hive from our registry
+
+ Err = RegUnLoadKey(HKEY_LOCAL_MACHINE,TEMP_KEY_NAME);
+
+ // Restore old privilege if necessary
+
+ if (!OldPrivState) {
+
+ RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE,
+ FALSE,
+ FALSE,
+ &OldPrivState);
+ }
+
+ return Err;
+}
+
+
+LONG
+FdpGetDiskInfoFromKey(
+ IN LPTSTR RootKeyName,
+ OUT PVOID *DiskInfo,
+ OUT PULONG DiskInfoSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine pulls the binary blob containing disk ft, drive letter,
+ and layout information out of a given registry key.
+
+ The info is found in HKEY_LOCAL_MACHINE,<RootKeyName>\DISK:Information.
+
+Arguments:
+
+ RootKeyName - name of the subkey of HKEY_LOCAL_MACHINE that is to
+ contain the DISK key.
+
+ DiskInfo - receives a pointer to a buffer containing the disk info.
+
+ DiskInfoSize - receives size of the disk buffer.
+
+Return Value:
+
+ Windows error code. If NO_ERROR, DiskInfo and DiskInfoSize are
+ filled in, and it is the caller's responsibility to free the buffer
+ when it is finished (via LocalFree()).
+
+--*/
+
+{
+ LONG Err;
+ HKEY hkeyDisk;
+ ULONG BufferSize;
+ ULONG ValueType;
+ PVOID Buffer;
+ LPTSTR DiskKeyName;
+
+ // Form the name of the DISK key
+
+ DiskKeyName = (LPTSTR)LocalAlloc( LMEM_FIXED,
+ ( lstrlen(RootKeyName)
+ + lstrlen(DISK_KEY_NAME)
+ + 2 // the \ and nul
+ )
+ * sizeof(TCHAR)
+ );
+
+ if (DiskKeyName == NULL) {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ lstrcpy(DiskKeyName,RootKeyName);
+ lstrcat(DiskKeyName,TEXT("\\"));
+ lstrcat(DiskKeyName,DISK_KEY_NAME);
+
+ // Open the DISK key.
+
+ Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ DiskKeyName,
+ REG_OPTION_RESERVED,
+ KEY_READ,
+ &hkeyDisk);
+
+ if (Err != NO_ERROR) {
+ goto CleanUp2;
+ }
+
+ // Determine how large we need the buffer to be
+
+ Err = RegQueryValueEx(hkeyDisk,
+ DISK_VALUE_NAME,
+ NULL,
+ &ValueType,
+ NULL,
+ &BufferSize);
+
+ if ((Err != NO_ERROR) && (Err != ERROR_MORE_DATA)) {
+ goto CleanUp1;
+ }
+
+ // Allocate a buffer of appropriate size
+
+ Buffer = (PVOID)LocalAlloc(LMEM_FIXED,BufferSize);
+ if (Buffer == NULL) {
+ Err = ERROR_NOT_ENOUGH_MEMORY;
+ goto CleanUp1;
+ }
+
+ // Query the data
+
+ Err = RegQueryValueEx(hkeyDisk,
+ DISK_VALUE_NAME,
+ NULL,
+ &ValueType,
+ Buffer,
+ &BufferSize);
+
+ if (Err != NO_ERROR) {
+ LocalFree(Buffer);
+ goto CleanUp1;
+ }
+
+ *DiskInfo = Buffer;
+ *DiskInfoSize = BufferSize;
+
+ CleanUp1:
+
+ RegCloseKey(hkeyDisk);
+
+ CleanUp2:
+
+ LocalFree(DiskKeyName);
+
+ return Err;
+}
+
+
+LONG
+FdpGetDiskInfoFromHive(
+ IN PCHAR HiveFilename,
+ OUT PVOID *DiskInfo,
+ OUT PULONG DiskInfoSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine pulls the binary blob containing disk ft, drive letter,
+ and layout information out of a given registry hive, which must be
+ a file in an alternate NT tree (ie, can't be an active hive).
+
+ The info is found in \DISK:Information within the hive.
+
+Arguments:
+
+ HiveFilename - supplies filename of hive
+
+ DiskInfo - receives a pointer to a buffer containing the disk info.
+
+ DiskInfoSize - receives size of the disk buffer.
+
+Return Value:
+
+ Windows error code. If NO_ERROR, DiskInfo and DiskInfoSize are
+ filled in, and it is the caller's responsibility to free the buffer
+ when it is finished (via LocalFree()).
+
+--*/
+
+{
+ ULONG windowsError;
+
+ windowsError = FdpLoadHiveIntoRegistry(HiveFilename);
+ if (windowsError == NO_ERROR) {
+ windowsError = FdpGetDiskInfoFromKey(TEMP_KEY_NAME,DiskInfo,DiskInfoSize);
+ FdpUnloadHiveFromRegistry();
+ }
+
+ return windowsError;
+}
+
+
+LONG
+FdTransferOldDiskInfoToRegistry(
+ IN PCHAR HiveFilename
+ )
+
+/*++
+
+Routine Description:
+
+ This routine transfers disk configuration from a given hive file
+ (which should be an inactive system hive) to the current registry.
+
+Arguments:
+
+ HiveFilename - supplies filename of source hive
+
+Return Value:
+
+ Windows error code.
+
+--*/
+
+{
+ LONG windowsError;
+ PVOID diskInfo;
+ ULONG diskInfoSize;
+ HKEY hkeyDisk;
+
+
+ // Load up the hive and pull the disk info from it.
+
+ windowsError = FdpGetDiskInfoFromHive(HiveFilename,&diskInfo,&diskInfoSize);
+ if (windowsError != NO_ERROR) {
+ return windowsError;
+ }
+
+ // Propogate the disk info into the current registry.
+ //
+ // Start by opening HKEY_LOCAL_MACHINE,System\DISK
+
+ windowsError = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("System\\") DISK_KEY_NAME,
+ REG_OPTION_RESERVED,
+ KEY_WRITE,
+ &hkeyDisk);
+
+ if (windowsError != NO_ERROR) {
+ LocalFree(diskInfo);
+ return windowsError;
+ }
+
+ // Set the Information value in the DISK key.
+
+ windowsError = RegSetValueEx(hkeyDisk,
+ DISK_VALUE_NAME,
+ 0,
+ REG_BINARY,
+ diskInfo,
+ diskInfoSize);
+ RegCloseKey(hkeyDisk);
+ LocalFree(diskInfo);
+ return windowsError;
+}
+
+
+typedef struct _STRING_LIST_NODE {
+ struct _STRING_LIST_NODE *Next;
+ LPTSTR String;
+} STRING_LIST_NODE, *PSTRING_LIST_NODE;
+
+PSTRING_LIST_NODE FoundDirectoryList;
+ULONG FoundDirectoryCount;
+
+TCHAR Pattern[MAX_PATH+1];
+WIN32_FIND_DATA FindData;
+OFSTRUCT OfStruct;
+HWND hwndStatus;
+BOOLEAN ScanDrive[26];
+BOOLEAN UserCancelled;
+
+
+typedef
+BOOL
+(*PFOUND_HIVE_ROUTINE)(
+ IN LPTSTR Directory
+ );
+
+VOID
+ProcessPendingMessages(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Preprocess messages.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ MSG msg;
+
+ while (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
+ DispatchMessage(&msg);
+ }
+}
+
+
+
+PUCHAR ConfigRegistryPath = "\\system32\\config\\system";
+BOOL
+FdpSearchTreeForSystemHives(
+ IN LPTSTR CurrentDirectory,
+ IN PFOUND_HIVE_ROUTINE FoundHiveRoutine,
+ IN HWND hdlg
+ )
+
+/*++
+
+Routine Description:
+
+ Search an entire directory tree for system and system.alt hive files.
+ When found, call a callback function with the directory in which
+ system32\config\system[.alt] was found, and the full path of the hive
+ file.
+
+ The root directory is not included in the search.
+
+ The top-level call to this function should have a current directory
+ like "C:." (ie, no slash for the root directory).
+
+Arguments:
+
+ CurrentDirectory - supplies current directory search path
+
+Return Value:
+
+ FALSE if error (callback function returned FALSE when we found an entry).
+
+--*/
+
+{
+ HANDLE findHandle;
+ TCHAR newDirectory[MAX_PATH+1];
+ BOOL found = FALSE;
+
+ // Iterate through the current directory, looking for subdirectories.
+
+ lstrcpy(Pattern, CurrentDirectory);
+ lstrcat(Pattern, "\\*");
+ findHandle = FindFirstFile(Pattern, &FindData);
+
+ if (findHandle != INVALID_HANDLE_VALUE) {
+
+ do {
+
+ ProcessPendingMessages();
+ if (UserCancelled) {
+ return FALSE;
+ }
+
+ // If the current match is not a directory then skip it.
+
+ if (!(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ || !lstrcmp(FindData.cFileName,TEXT("."))
+ || !lstrcmp(FindData.cFileName,TEXT(".."))) {
+ continue;
+ }
+
+ found = FALSE;
+
+ // Form the name of the file we are looking for
+ // [<currentdirectory>\<match>\system32\config\system]
+
+ lstrcpy(Pattern, CurrentDirectory);
+ lstrcat(Pattern, "\\");
+ lstrcat(Pattern, FindData. cFileName);
+
+ lstrcpy(newDirectory, Pattern);
+
+ // Don't decend into the directory unless the path to the
+ // hive.alt name is within MAX_PATH length.
+
+ if ((ULONG)(lstrlen(newDirectory) / sizeof(TCHAR)) < (MAX_PATH - strlen(ConfigRegistryPath) - 4)) {
+
+ SetDlgItemText(hdlg, IDC_SIMPLE_TEXT_LINE, newDirectory);
+
+ lstrcat(Pattern, TEXT(ConfigRegistryPath));
+
+ if (OpenFile(Pattern, &OfStruct, OF_EXIST) != (HFILE)(-1)) {
+ found = TRUE;
+ }
+
+ // Also check for a system.alt file there
+
+ lstrcat(Pattern,TEXT(".alt"));
+
+ if (OpenFile(Pattern, &OfStruct, OF_EXIST) != (HFILE)(-1)) {
+ found = TRUE;
+ }
+
+ if (found) {
+ if (!FoundHiveRoutine(newDirectory)) {
+ return FALSE;
+ }
+ }
+
+ // Descend into the directory we just found
+
+ if (!FdpSearchTreeForSystemHives(newDirectory, FoundHiveRoutine, hdlg)) {
+ return FALSE;
+ }
+ }
+
+ } while (FindNextFile(findHandle,&FindData));
+
+ FindClose(findHandle);
+ }
+
+ return TRUE;
+}
+
+
+BOOL
+FdpFoundHiveCallback(
+ IN PCHAR Directory
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a directory containing a system hive
+ has been located. If all goes well (allocate memory and the like)
+ this routine will save the directory name in a list for later use.
+ NOTE: No checks are made on the directory name being greater in
+ length than MAX_PATH. It is the responsibility of the caller to
+ insure that this is true.
+
+Arguments:
+
+ Directory - the pointer to the character string for the directory
+ where a hive has been located.
+
+Return Value:
+
+ TRUE - did something with it.
+ FALSE - did not save the directory.
+
+--*/
+
+{
+ TCHAR windowsDir[MAX_PATH+1];
+ PSTRING_LIST_NODE dirItem;
+ LPTSTR p;
+
+ // If this is the current windows directory, skip it.
+
+ GetWindowsDirectory(windowsDir, sizeof(windowsDir)/sizeof(TCHAR));
+
+ if (!lstrcmpi(Directory, windowsDir)) {
+ return TRUE;
+ }
+
+ // Save the directory information away
+
+ dirItem = (PSTRING_LIST_NODE)LocalAlloc(LMEM_FIXED|LMEM_ZEROINIT, sizeof(STRING_LIST_NODE));
+ if (dirItem == NULL) {
+ return FALSE;
+ }
+
+ p = (LPTSTR)LocalAlloc(LMEM_FIXED,(lstrlen(Directory)+1) * sizeof(TCHAR));
+ if (p == NULL) {
+ LocalFree(dirItem);
+ return FALSE;
+ }
+
+ dirItem->String = p;
+ lstrcpy(p, Directory);
+
+ // Update the global chain of found directories.
+
+ dirItem->Next = FoundDirectoryList;
+ FoundDirectoryList = dirItem;
+ FoundDirectoryCount++;
+ return TRUE;
+}
+
+
+VOID
+FdpFreeDirectoryList(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Go through the list of directories containing system hives and
+ free the entries.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PSTRING_LIST_NODE n,
+ p = FoundDirectoryList;
+
+ while (p) {
+ n = p->Next;
+ if (p->String) {
+ LocalFree(p->String);
+ }
+ LocalFree(p);
+ p = n;
+ }
+
+ FoundDirectoryCount = 0;
+ FoundDirectoryList = NULL;
+}
+
+
+BOOL
+FdpScanningDirsDlgProc(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN DWORD wParam,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Display the "scanning" dialog, then when the IDLE message arrives
+ process all drive letters and search for system hives.
+
+Arguments:
+
+ Windows dialog proc
+
+Return Value:
+
+ Windows dialog proc
+
+--*/
+
+{
+ TCHAR LetterColon[3];
+ TCHAR Letter;
+
+ switch (msg) {
+
+ case WM_INITDIALOG:
+
+ CenterDialog(hwnd);
+ break;
+
+ case WM_ENTERIDLE:
+
+ // Sent to us by the main window after the dialog is displayed.
+ // Perform the search here.
+
+ ConfigurationSearchIdleTrigger = FALSE;
+
+ UserCancelled = FALSE;
+
+ lstrcpy(LetterColon,TEXT("?:"));
+ for (Letter = TEXT('A'); Letter <= TEXT('Z'); Letter++) {
+
+ if (!ScanDrive[Letter-TEXT('A')]) {
+ continue;
+ }
+
+ LetterColon[0] = Letter;
+
+ if (!FdpSearchTreeForSystemHives(LetterColon, FdpFoundHiveCallback, hwnd)) {
+ EndDialog(hwnd,IDCANCEL);
+ return TRUE;
+ }
+
+ }
+
+ EndDialog(hwnd,IDOK);
+ break;
+
+ case WM_COMMAND:
+
+ switch (LOWORD(wParam)) {
+
+ case IDCANCEL:
+
+ UserCancelled = TRUE;
+ break;
+
+ default:
+
+ return FALSE;
+ }
+ break;
+
+ default:
+
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+BOOL
+FdpSelectDirDlgProc(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN DWORD wParam,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Using the list of directories containing system hives, display the
+ selections to the user and save the selected item if the user so
+ chooses.
+
+Arguments:
+
+ Windows dialog proc.
+
+Return Value:
+
+ Windows dialog proc.
+
+--*/
+
+{
+ PSTRING_LIST_NODE Str;
+ LONG i;
+ static HANDLE ListBoxHandle;
+
+ switch (msg) {
+
+ case WM_INITDIALOG:
+
+ CenterDialog(hwnd);
+
+ // Add each item in the directory list to the listbox
+
+ ListBoxHandle = GetDlgItem(hwnd,IDC_LISTBOX);
+
+ for (Str = FoundDirectoryList; Str; Str = Str->Next) {
+
+ i = SendMessage(ListBoxHandle,LB_ADDSTRING ,0,(LONG)Str->String);
+ SendMessage(ListBoxHandle,LB_SETITEMDATA,i,(LONG)Str );
+ }
+
+ // select the zeroth item
+
+ SendMessage(ListBoxHandle,LB_SETCURSEL,0,0);
+
+ break;
+
+ case WM_COMMAND:
+
+ switch (LOWORD(wParam)) {
+
+ case IDOK:
+
+ // Get the index of the current list box selection and the
+ // pointer to the string node associated with it.
+
+ i = SendMessage(ListBoxHandle,LB_GETCURSEL,0,0);
+ EndDialog(hwnd,SendMessage(ListBoxHandle,LB_GETITEMDATA,i,0));
+ break;
+
+ case IDCANCEL:
+
+ EndDialog(hwnd,(int)NULL);
+ break;
+
+ default:
+
+ return FALSE;
+ }
+ break;
+
+ default:
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOL
+DoMigratePreviousFtConfig(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Allow the user to move the disk config info from a different Windows NT
+ installation into the current registry.
+
+ For each fixed disk volume, scan it for system hives and present the
+ results to the user so he can select the installation to migrate.
+
+ Then load the system hive from that instllation (system.alt if the system
+ hive is corrupt, etc) and transfer the DISK:Information binary blob.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE if error or user cancelled, TRUE if info was migrated and reboot
+ is required.
+
+--*/
+
+{
+ LONG windowsError;
+ TCHAR letter;
+ TCHAR letterColon[4];
+ PSTRING_LIST_NODE stringNode;
+
+ // Tell the user what this will do and prompt for confirmation
+
+ if (ConfirmationDialog(MSG_CONFIRM_MIGRATE_CONFIG, MB_ICONEXCLAMATION | MB_YESNO) != IDYES) {
+ return FALSE;
+ }
+
+ ProcessPendingMessages();
+
+ // Figure out which drives are relevent
+
+ SetCursor(hcurWait);
+
+ RtlZeroMemory(ScanDrive,sizeof(ScanDrive));
+ lstrcpy(letterColon,TEXT("?:\\"));
+ for (letter=TEXT('A'); letter<=TEXT('Z'); letter++) {
+
+ letterColon[0] = letter;
+
+ if (GetDriveType(letterColon) == DRIVE_FIXED) {
+
+ ScanDrive[letter-TEXT('A')] = TRUE;
+ }
+ }
+
+ SetCursor(hcurNormal);
+
+ // Create a window that will list the directories being scanned, to
+ // keep the user entertained.
+
+ ConfigurationSearchIdleTrigger = TRUE;
+
+ windowsError = DialogBox(hModule,
+ MAKEINTRESOURCE(IDD_SIMPLETEXT),
+ hwndFrame,
+ (DLGPROC)FdpScanningDirsDlgProc);
+
+ if (windowsError == IDCANCEL) {
+ FdpFreeDirectoryList();
+ return FALSE;
+ }
+
+ ProcessPendingMessages();
+
+ if (!FoundDirectoryCount) {
+
+ InfoDialog(MSG_NO_OTHER_NTS);
+ return FALSE;
+ }
+
+ // Display a dialog box that allows the user to select one of the
+ // directories we found.
+
+ stringNode = (PSTRING_LIST_NODE)DialogBox(hModule,
+ MAKEINTRESOURCE(IDD_SELDIR),
+ hwndFrame,
+ (DLGPROC)FdpSelectDirDlgProc);
+
+ if (stringNode == NULL) {
+ FdpFreeDirectoryList();
+ return FALSE;
+ }
+
+ // User made a selection. One last confirmation.
+
+ if (ConfirmationDialog(MSG_ABSOLUTELY_SURE,MB_ICONEXCLAMATION | MB_YESNO) != IDYES) {
+ FdpFreeDirectoryList();
+ return FALSE;
+ }
+
+ ProcessPendingMessages();
+
+ SetCursor(hcurWait);
+
+ lstrcpy(Pattern,stringNode->String);
+ lstrcat(Pattern,TEXT(ConfigRegistryPath));
+
+ windowsError = FdTransferOldDiskInfoToRegistry(Pattern);
+ if (windowsError != NO_ERROR) {
+ lstrcat(Pattern,TEXT(".alt"));
+ windowsError = FdTransferOldDiskInfoToRegistry(Pattern);
+ }
+ FdpFreeDirectoryList();
+ SetCursor(hcurNormal);
+
+ if (windowsError != NO_ERROR) {
+
+ if (windowsError == ERROR_FILE_NOT_FOUND) {
+ ErrorDialog(MSG_NO_DISK_INFO);
+ } else if (windowsError == ERROR_SHARING_VIOLATION) {
+ ErrorDialog(MSG_DISK_INFO_BUSY);
+ } else {
+ ErrorDialog(windowsError);
+ }
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+
+BOOL
+DoRestoreFtConfig(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Restore previously saved disk configuration information into the
+ active registry.
+
+ The saved config info will come from a floppy that the user is
+ prompted to insert.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE if error or user cancelled, TRUE if info was restored and reboot
+ is required.
+
+--*/
+
+{
+ LONG Err;
+ TCHAR caption[256];
+ UINT errorMode;
+ va_list arglist =
+#ifdef _ALPHA_ // Alpha defines va_list as a struct. Init as such
+ {0};
+#else
+ NULL;
+#endif
+
+
+ // Get confirmation
+
+ if (ConfirmationDialog(MSG_CONFIRM_RESTORE_CONFIG, MB_ICONEXCLAMATION | MB_YESNO) != IDYES) {
+ return FALSE;
+ }
+
+ // Get the diskette into A:.
+
+ errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+ LoadString(hModule,IDS_INSERT_DISK,caption,sizeof(caption)/sizeof(TCHAR));
+ if (CommonDialog(MSG_INSERT_REGSAVEDISK,caption,MB_OKCANCEL | MB_TASKMODAL, arglist) != IDOK) {
+ return FALSE;
+ }
+
+ ProcessPendingMessages();
+ SetCursor(hcurWait);
+
+ // If there is no file called SYSTEM on a:\, it appears that the registry
+ // creates one and then keeps it open. To avoid this, check to see
+ // whether there is one first.
+
+ if (OpenFile(TEXT("A:\\SYSTEM"),&OfStruct,OF_EXIST) == (HFILE)(-1)) {
+ Err = ERROR_FILE_NOT_FOUND;
+ } else {
+ Err = FdTransferOldDiskInfoToRegistry(TEXT("A:\\SYSTEM"));
+ }
+
+ SetErrorMode(errorMode);
+ SetCursor(hcurNormal);
+
+ if (Err != NO_ERROR) {
+ ErrorDialog(Err);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+VOID
+DoSaveFtConfig(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Allow the user to update the registry save diskette with the currently
+ defined disk configuration. The saved info excludes any changes made
+ during this session of disk manager.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LONG Err,
+ ErrAlt;
+ LPTSTR SystemHiveName = TEXT("a:\\system");
+ HKEY hkey;
+ TCHAR caption[256];
+ DWORD disposition;
+ UINT errorMode;
+ va_list arglist =
+#ifdef _ALPHA_
+ {0}; // Alpha defines va_list as a struct. Init as such.
+#else
+ NULL;
+#endif
+
+ // Get a diskette into A:.
+
+ LoadString(hModule,
+ IDS_INSERT_DISK,
+ caption,
+ sizeof(caption)/sizeof(TCHAR));
+ if (CommonDialog(MSG_INSERT_REGSAVEDISK2,caption,MB_OKCANCEL | MB_TASKMODAL, arglist) != IDOK) {
+ return;
+ }
+
+ // Decide what to do based on the presence of a a:\system. If that file
+ // is present, just update the DISK entry in it. If it is not present,
+ // then blast out the entire system hive.
+
+ errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+ ProcessPendingMessages();
+ SetCursor(hcurWait);
+
+ if (OpenFile(SystemHiveName,&OfStruct,OF_EXIST) == (HFILE)(-1)) {
+
+ BOOLEAN OldPrivState;
+ NTSTATUS Status;
+
+ // Blast the entire system hive out to the floppy.
+ // Start by attempting to get backup privilege.
+
+ Status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE,
+ TRUE,
+ FALSE,
+ &OldPrivState);
+
+ Err = RtlNtStatusToDosError(Status);
+ if (Err == NO_ERROR) {
+
+ Err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("system"),
+ REG_OPTION_RESERVED,
+ KEY_READ,
+ &hkey);
+
+ if (Err == NO_ERROR) {
+
+ Err = RegSaveKey(hkey,SystemHiveName,NULL);
+ RegCloseKey(hkey);
+ }
+
+ if (!OldPrivState) {
+ RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE,FALSE,FALSE,&OldPrivState);
+ }
+ }
+ } else {
+
+ PVOID DiskInfo;
+ ULONG DiskInfoSize;
+
+ // Load up the saved system hive
+
+ Err = FdpLoadHiveIntoRegistry(SystemHiveName);
+ if (Err == NO_ERROR) {
+
+ // Get the current DISK information
+
+ Err = FdpGetDiskInfoFromKey(TEXT("system"),&DiskInfo,&DiskInfoSize);
+ if (Err == NO_ERROR) {
+
+ // Place the current disk information into the saved hive
+
+ Err = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
+ TEMP_KEY_NAME TEXT("\\") DISK_KEY_NAME,
+ 0,
+ "Disk and fault tolerance information.",
+ REG_OPTION_NON_VOLATILE,
+ KEY_WRITE,
+ NULL,
+ &hkey,
+ &disposition );
+
+ if (Err == NO_ERROR) {
+
+ Err = RegSetValueEx(hkey,
+ DISK_VALUE_NAME,
+ REG_OPTION_RESERVED,
+ REG_BINARY,
+ DiskInfo,
+ DiskInfoSize);
+
+ RegFlushKey(hkey);
+ RegCloseKey(hkey);
+ }
+
+ LocalFree(DiskInfo);
+ }
+
+ ErrAlt = FdpUnloadHiveFromRegistry();
+
+ if (Err == NO_ERROR && ErrAlt != NO_ERROR) {
+
+ Err = ErrAlt;
+ }
+ }
+ }
+
+ SetCursor(hcurNormal);
+ SetErrorMode(errorMode);
+
+ if (Err == NO_ERROR) {
+ InfoDialog(MSG_CONFIG_SAVED_OK);
+ } else {
+ ErrorDialog(Err);
+ }
+
+ return;
+}
diff --git a/private/utils/fdisk/ftreg.dlg b/private/utils/fdisk/ftreg.dlg
new file mode 100644
index 000000000..e4ff1655d
--- /dev/null
+++ b/private/utils/fdisk/ftreg.dlg
@@ -0,0 +1,23 @@
+#include "ftregres.h"
+
+IDD_SELDIR DIALOG 6, 18, 154, 127
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Get Previous Disk Configuration"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LISTBOX IDC_LISTBOX, 16, 28, 122, 66, LBS_SORT | WS_VSCROLL |
+ WS_TABSTOP
+ LTEXT "Select a Windows NT installation:", 102, 10, 10, 118, 8
+ PUSHBUTTON "OK", IDOK, 29, 107, 40, 14
+ PUSHBUTTON "Cancel", IDCANCEL, 85, 107, 40, 14
+END
+
+IDD_SIMPLETEXT DIALOG 6, 18, 270, 54
+STYLE WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CAPTION
+CAPTION "Searching for Windows NT Installations"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "",
+ IDC_SIMPLE_TEXT_LINE, 10, 10, 250, 8
+ DEFPUSHBUTTON "Cancel", IDCANCEL, 114, 31, 40, 14, WS_GROUP
+END
diff --git a/private/utils/fdisk/ftreg.res b/private/utils/fdisk/ftreg.res
new file mode 100644
index 000000000..4153e6402
--- /dev/null
+++ b/private/utils/fdisk/ftreg.res
Binary files differ
diff --git a/private/utils/fdisk/ftregres.h b/private/utils/fdisk/ftregres.h
new file mode 100644
index 000000000..af24b29de
--- /dev/null
+++ b/private/utils/fdisk/ftregres.h
@@ -0,0 +1,4 @@
+#define IDC_LISTBOX 101
+#define IDD_SELDIR 100
+#define IDC_SIMPLE_TEXT_LINE 201
+#define IDD_SIMPLETEXT 300
diff --git a/private/utils/fdisk/i386/x86mboot.c b/private/utils/fdisk/i386/x86mboot.c
new file mode 100644
index 000000000..d80048170
--- /dev/null
+++ b/private/utils/fdisk/i386/x86mboot.c
@@ -0,0 +1,33 @@
+#define X86BOOTCODE_SIZE 446
+
+
+unsigned char x86BootCode[] = {
+250,51,192,142,208,188,0,124,139,244,80,7,80,31,251,252,
+191,0,6,185,0,1,242,165,234,29,6,0,0,190,190,7,
+179,4,128,60,128,116,14,128,60,0,117,28,131,198,16,254,
+203,117,239,205,24,139,20,139,76,2,139,238,131,198,16,254,
+203,116,26,128,60,0,116,244,190,139,6,172,60,0,116,11,
+86,187,7,0,180,14,205,16,94,235,240,235,254,191,5,0,
+187,0,124,184,1,2,87,205,19,95,115,12,51,192,205,19,
+79,117,237,190,163,6,235,211,190,194,6,191,254,125,129,61,
+85,170,117,199,139,245,234,0,124,0,0,73,110,118,97,108,
+105,100,32,112,97,114,116,105,116,105,111,110,32,116,97,98,
+108,101,0,69,114,114,111,114,32,108,111,97,100,105,110,103,
+32,111,112,101,114,97,116,105,110,103,32,115,121,115,116,101,
+109,0,77,105,115,115,105,110,103,32,111,112,101,114,97,116,
+105,110,103,32,115,121,115,116,101,109,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0
+};
diff --git a/private/utils/fdisk/makefile b/private/utils/fdisk/makefile
new file mode 100644
index 000000000..5acbbd24c
--- /dev/null
+++ b/private/utils/fdisk/makefile
@@ -0,0 +1 @@
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/fdisk/makefile.inc b/private/utils/fdisk/makefile.inc
new file mode 100644
index 000000000..80377e046
--- /dev/null
+++ b/private/utils/fdisk/makefile.inc
@@ -0,0 +1,4 @@
+fdiskmsg.h fdiskmsg.rc msg00001.bin: fdiskmsg.mc
+ mc -v fdiskmsg.mc
+
+obj\$(TARGET_DIRECTORY)\fdisk.res: fdisk.dlg fdiskmsg.rc ftreg.dlg
diff --git a/private/utils/fdisk/network.c b/private/utils/fdisk/network.c
new file mode 100644
index 000000000..e4003591e
--- /dev/null
+++ b/private/utils/fdisk/network.c
@@ -0,0 +1,206 @@
+
+/*++
+
+Copyright (c) 1993-1994 Microsoft Corporation
+
+Module Name:
+
+ network.c
+
+Abstract:
+
+ This module contains the set of routines that support updating network
+ drive shares when adding and deleting drive letters.
+
+Author:
+
+ Bob Rinne (bobri) 12/26/94
+
+Environment:
+
+ User process.
+
+Notes:
+
+Revision History:
+
+--*/
+
+#include "fdisk.h"
+#include "shellapi.h"
+#include <winbase.h>
+#include <string.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <lm.h>
+
+// Data area to hold the permissions that are to be assigned to the
+// administrative shares C$, D$, etc. This is obtained during initialization
+// and not changed, just used when a new administrator share needes to
+// be made.
+
+LPBYTE ShareInformationBuffer;
+
+// Only perform network actions if this value is true. This value
+// is set if the initialization of this module completes successfully.
+
+BOOLEAN NetworkEnabled;
+
+
+VOID
+NetworkInitialize(
+ )
+
+/*++
+
+Routine Description:
+
+ Intialize the permissions constants for any new administrator
+ driver letter shares.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ WCHAR shareName[4];
+ NET_API_STATUS status;
+ PSHARE_INFO_502 info;
+ LPTSTR string;
+
+ shareName[1] = (WCHAR) '$';
+ shareName[2] = (WCHAR) 0;
+
+ for (shareName[0] = (WCHAR) 'C'; shareName[0] <= (WCHAR) 'Z'; shareName[0]++) {
+
+ // Since windisk is still built as a non-unicode application,
+ // the parameter "shareName" must be unicode, but the prototype
+ // specifies that it is a (char *). Do the typecast to remove
+ // warnings.
+
+ status = NetShareGetInfo(NULL,
+ (char *) shareName,
+ 502,
+ &ShareInformationBuffer);
+ if (status == NERR_Success) {
+
+ // Update the remarks and password to be NULL.
+
+ info = (PSHARE_INFO_502) ShareInformationBuffer;
+ string = info->shi502_remark;
+ if (string) {
+ *string = (TCHAR) 0;
+ }
+ string = info->shi502_passwd;
+ if (string) {
+ *string = (TCHAR) 0;
+ }
+
+ // Network shares are to be updated.
+
+ NetworkEnabled = TRUE;
+ return;
+ }
+ }
+
+ // Can't find any network shares - do not attempt updates
+ // of administrator shares.
+
+ NetworkEnabled = FALSE;
+}
+
+VOID
+NetworkShare(
+ IN LPCTSTR DriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ Given a drive letter, construct the default administrator share
+ for the letter. This is the C$, D$, etc share for the drive.
+
+Arguments:
+
+ DriveLetter - the drive letter to share.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ NET_API_STATUS status;
+ PSHARE_INFO_502 info;
+ LPTSTR string;
+
+ if (NetworkEnabled) {
+ info = (PSHARE_INFO_502) ShareInformationBuffer;
+
+ // Set up the new network name.
+
+ string = info->shi502_netname;
+ *string = *DriveLetter;
+
+ // Set up the path. All that need be added is the drive letter
+ // the rest of the path (":\") is already in the structure.
+
+ string = info->shi502_path;
+ *string = *DriveLetter;
+
+ status = NetShareAdd(NULL,
+ 502,
+ ShareInformationBuffer,
+ NULL);
+ }
+}
+
+
+VOID
+NetworkRemoveShare(
+ IN LPCTSTR DriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ Remove the administrator share for the given letter.
+
+Arguments:
+
+ DriveLetter - the drive letter to share.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ NET_API_STATUS status;
+ WCHAR shareName[4];
+
+ if (NetworkEnabled) {
+ shareName[0] = (WCHAR) *DriveLetter;
+ shareName[1] = (WCHAR) '$';
+ shareName[2] = (WCHAR) 0;
+
+ // Since windisk is still built as a non-unicode application,
+ // the parameter "shareName" must be unicode, but the prototype
+ // specifies that it is a (char *). Do the typecast to remove
+ // warnings.
+
+ status = NetShareDel(NULL,
+ (char *) shareName,
+ 0);
+ }
+}
diff --git a/private/utils/fdisk/ntlow.c b/private/utils/fdisk/ntlow.c
new file mode 100644
index 000000000..29ef6f01b
--- /dev/null
+++ b/private/utils/fdisk/ntlow.c
@@ -0,0 +1,1087 @@
+/*++
+
+Copyright (c) 1991-1994 Microsoft Corporation
+
+Module Name:
+
+ ntlow.c
+
+Abstract:
+
+ This file contains the low-level I/O routines, implemented
+ to run on NT.
+
+Author:
+
+ Ted Miller (tedm) 8-Nov-1991
+
+Revision History:
+
+ Bob Rinne (bobri) 2-Feb-1994
+ Dynamic partitioning changes.
+
+--*/
+
+
+#include "fdisk.h"
+#include <stdio.h>
+#include <string.h>
+
+
+STATUS_CODE
+LowQueryFdiskPathList(
+ OUT PCHAR **PathList,
+ OUT PULONG ListLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines how many drives are present in the
+ system and returns a list of Ascii strings for the names of
+ each of the drives found.
+
+ When a drive is located, a check is made to insure that the
+ associated DosName for the physical drive is also present in
+ the system.
+
+Arguments:
+
+ PathList - pointer to a pointer for the list
+ ListLength - the number of entries returned in the list
+
+Return Value:
+
+ Error status if there is a problem.
+
+--*/
+
+{
+ HANDLE dummyHandle;
+ STATUS_CODE status;
+ ULONG count = 0;
+ ULONG i;
+ char buffer[100];
+ PCHAR *pathArray;
+
+ while (1) {
+
+ sprintf(buffer, "\\device\\harddisk%u", count);
+ status = LowOpenDisk(buffer, &dummyHandle);
+
+ // Only STATUS_OBJECT_PATH_NOT_FOUND can terminate the count.
+
+ if (NT_SUCCESS(status)) {
+ char dosNameBuffer[80];
+
+ LowCloseDisk(dummyHandle);
+
+ // Insure that the physicaldrive name is present
+
+ sprintf(dosNameBuffer, "\\dosdevices\\PhysicalDrive%u", count);
+ status = LowOpenNtName(dosNameBuffer, &dummyHandle);
+ if (NT_SUCCESS(status)) {
+ LowCloseDisk(dummyHandle);
+ } else {
+
+ // Not there, create it.
+
+ sprintf(buffer, "\\device\\harddisk%u\\Partition0", count);
+ DefineDosDevice(DDD_RAW_TARGET_PATH, (LPCTSTR) dosNameBuffer, (LPCTSTR) buffer);
+ }
+ } else if (status == STATUS_OBJECT_PATH_NOT_FOUND) {
+
+ break;
+ } else if (status == STATUS_ACCESS_DENIED) {
+
+ return status;
+ }
+ count++;
+ }
+
+ pathArray = Malloc(count * sizeof(PCHAR));
+
+ for (i=0; i<count; i++) {
+
+ sprintf(buffer, "\\device\\harddisk%u", i);
+ pathArray[i] = Malloc(lstrlenA(buffer)+1);
+ strcpy(pathArray[i], buffer);
+ }
+
+ *PathList = pathArray;
+ *ListLength = count;
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+LowFreeFdiskPathList(
+ IN OUT PCHAR* PathList,
+ IN ULONG ListLength
+ )
+
+/*++
+
+Routine Description:
+
+ Walk the provided list up to its length and free the memory
+ allocated. Upon completion, free the memory for the list
+ itself.
+
+Arguments:
+
+ PathList - pointer to base of path list
+ ListLength - number of entries in the list
+
+Return Value:
+
+ Always OK_STATUS
+
+--*/
+
+{
+ ULONG i;
+
+ for (i=0; i<ListLength; i++) {
+ FreeMemory(PathList[i]);
+ }
+ FreeMemory(PathList);
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+LowOpenNtName(
+ IN PCHAR Name,
+ IN HANDLE_PT Handle
+ )
+
+/*++
+
+Routine Description:
+
+ This is an internal "Low" routine to handle open requests.
+
+Arguments:
+
+ Name - pointer to the NT name for the open.
+ Handle - pointer for the handle returned.
+
+Return Value:
+
+ NT status
+
+--*/
+
+{
+ OBJECT_ATTRIBUTES oa;
+ NTSTATUS status;
+ IO_STATUS_BLOCK statusBlock;
+ ANSI_STRING ansiName;
+ UNICODE_STRING unicodeName;
+
+ RtlInitAnsiString(&ansiName, Name);
+ status = RtlAnsiStringToUnicodeString(&unicodeName, &ansiName, TRUE);
+
+ if (!NT_SUCCESS(status)) {
+ return status;
+ }
+
+ memset(&oa, 0, sizeof(OBJECT_ATTRIBUTES));
+ oa.Length = sizeof(OBJECT_ATTRIBUTES);
+ oa.ObjectName = &unicodeName;
+ oa.Attributes = OBJ_CASE_INSENSITIVE;
+
+ status = DmOpenFile(Handle,
+ SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
+ &oa,
+ &statusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT);
+
+
+ if (!NT_SUCCESS(status)) {
+
+ FDLOG((1,"LowOpen: 1st open failed with 0x%x\n", status));
+
+ // try a 2nd time to get around an FS glitch or a test
+ // bug where this doesn't work on an attempt to delete a
+ // partition
+
+ Sleep(500);
+ status = DmOpenFile(Handle,
+ SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
+ &oa,
+ &statusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT);
+ FDLOG((1,"LowOpen: 2nd open 0x%x\n", status));
+ }
+ RtlFreeUnicodeString(&unicodeName);
+ return status;
+}
+
+
+STATUS_CODE
+LowOpenDriveLetter(
+ IN CHAR DriveLetter,
+ IN HANDLE_PT Handle
+ )
+
+/*++
+
+Routine Description:
+
+ Given a drive letter, open it and return a handle.
+
+Arguments:
+
+ DriveLetter - the letter to open
+ Handle - a pointer to a handle
+
+Return Value:
+
+ NT status
+
+--*/
+
+{
+ char ntDeviceName[100];
+
+ sprintf(ntDeviceName,
+ "\\DosDevices\\%c:",
+ DriveLetter);
+ return LowOpenNtName(ntDeviceName, Handle);
+}
+
+
+STATUS_CODE
+LowOpenPartition(
+ IN PCHAR DevicePath,
+ IN ULONG Partition,
+ OUT HANDLE_PT Handle
+ )
+
+/*++
+
+Routine Description:
+
+ Construct the NT device name for the Partition value given
+ and perform the NT APIs to open the device.
+
+Arguments:
+
+ DevicePath - the string to the device without the partition
+ portion of the name. This is constructed using
+ the Partition value passed
+ Partition - the partion desired
+ Handle - pointer to a handle pointer for the result
+
+Return Value:
+
+ NT status
+
+--*/
+
+{
+ char ntDeviceName[100];
+
+ sprintf(ntDeviceName,
+ "%s\\partition%u",
+ DevicePath,
+ Partition);
+ return LowOpenNtName(ntDeviceName, Handle);
+}
+
+
+STATUS_CODE
+LowOpenDisk(
+ IN PCHAR DevicePath,
+ OUT HANDLE_PT DiskId
+ )
+
+/*++
+
+Routine Description:
+
+ Perform the NT actions to open a device.
+
+Arguments:
+
+ DevicePath - Ascii device name
+ DiskId - pointer to a handle pointer for the returned
+ handle value
+
+Return Value:
+
+ NT status
+
+--*/
+
+{
+ return(LowOpenPartition(DevicePath, 0, DiskId));
+}
+
+
+STATUS_CODE
+LowCloseDisk(
+ IN HANDLE_T DiskId
+ )
+
+/*++
+
+Routine Description:
+
+ Close a disk handle.
+
+Arguments:
+
+ DiskId - the actual NT handle
+
+Return Value:
+
+ NT status
+
+--*/
+
+{
+ return(DmClose(DiskId));
+}
+
+
+STATUS_CODE
+LowLockDrive(
+ IN HANDLE_T DiskId
+ )
+
+/*++
+
+Routine Description:
+
+ Perform the NT API to cause a volume to be locked.
+ This is a File System device control.
+
+Arguments:
+
+ DiskId - the actual NT handle to the drive
+
+Return Value:
+
+ NT status
+
+--*/
+
+{
+ NTSTATUS status;
+ IO_STATUS_BLOCK statusBlock;
+
+ status = NtFsControlFile(DiskId,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ FSCTL_LOCK_VOLUME,
+ NULL,
+ 0,
+ NULL,
+ 0);
+
+ if (!NT_SUCCESS(status)) {
+ FDLOG((1, "LowLock: failed with 0x%x\n", status));
+ }
+ return status;
+}
+
+
+STATUS_CODE
+LowUnlockDrive(
+ IN HANDLE_T DiskId
+ )
+
+/*++
+
+Routine Description:
+
+ Perform the NT API to cause a volume to be unlocked.
+ This is a File System device control.
+
+Arguments:
+
+ DiskId - the actual NT handle to the drive
+
+Return Value:
+
+ NT status
+
+--*/
+
+{
+ NTSTATUS status;
+ IO_STATUS_BLOCK statusBlock;
+
+ status = NtFsControlFile(DiskId,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ FSCTL_DISMOUNT_VOLUME,
+ NULL,
+ 0,
+ NULL,
+ 0);
+ status = NtFsControlFile(DiskId,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ FSCTL_UNLOCK_VOLUME,
+ NULL,
+ 0,
+ NULL,
+ 0);
+ return status;
+}
+
+
+STATUS_CODE
+LowGetDriveGeometry(
+ IN PCHAR Path,
+ OUT PULONG TotalSectorCount,
+ OUT PULONG SectorSize,
+ OUT PULONG SectorsPerTrack,
+ OUT PULONG Heads
+ )
+
+/*++
+
+Routine Description:
+
+ Routine collects information concerning the geometry
+ of a specific drive.
+
+Arguments:
+
+ Path - Ascii path name to get to disk object
+ this is not a full path, but rather
+ a path without the Partition indicator
+ \device\harddiskX
+ TotalSectorCount- pointer to ULONG for result
+ SectorSize - pointer to ULONG for result
+ SectorsPerTrack - pointer to ULONG for result
+ Heads - pointer to ULONG for result
+
+Return Value:
+
+ NT status
+
+--*/
+
+{
+ IO_STATUS_BLOCK statusBlock;
+ DISK_GEOMETRY diskGeometry;
+ STATUS_CODE status;
+ HANDLE handle;
+
+ if ((status = LowOpenDisk(Path, &handle)) != OK_STATUS) {
+ return status;
+ }
+
+ status = NtDeviceIoControlFile(handle,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ IOCTL_DISK_GET_DRIVE_GEOMETRY,
+ NULL,
+ 0,
+ &diskGeometry,
+ sizeof(DISK_GEOMETRY));
+ if (!NT_SUCCESS(status)) {
+ return (STATUS_CODE)status;
+ }
+ LowCloseDisk(handle);
+
+ *SectorSize = diskGeometry.BytesPerSector;
+ *SectorsPerTrack = diskGeometry.SectorsPerTrack;
+ *Heads = diskGeometry.TracksPerCylinder;
+ *TotalSectorCount = (RtlExtendedIntegerMultiply(diskGeometry.Cylinders,
+ *SectorsPerTrack * *Heads)).LowPart;
+ return(OK_STATUS);
+}
+
+
+STATUS_CODE
+LowGetDiskLayout(
+ IN PCHAR Path,
+ OUT PDRIVE_LAYOUT_INFORMATION *DriveLayout
+ )
+
+/*++
+
+Routine Description:
+
+ Perform the necessary NT API calls to get the drive
+ layout from the disk and return it in a memory buffer
+ allocated by this routine.
+
+Arguments:
+
+ Path - Ascii path name to get to disk object
+ this is not a full path, but rather
+ a path without the Partition indicator
+ \device\harddiskX
+
+ DriveLayout - pointer to pointer for the drive layout result
+
+Return Value:
+
+ NT status
+
+--*/
+
+{
+ PDRIVE_LAYOUT_INFORMATION layout;
+ IO_STATUS_BLOCK statusBlock;
+ STATUS_CODE status;
+ ULONG bufferSize;
+ HANDLE handle;
+
+ bufferSize = sizeof(DRIVE_LAYOUT_INFORMATION)
+ + (500 * sizeof(PARTITION_INFORMATION));
+
+ if ((layout = AllocateMemory(bufferSize)) == NULL) {
+ RETURN_OUT_OF_MEMORY;
+ }
+
+ if ((status = LowOpenDisk(Path, &handle)) != OK_STATUS) {
+ FreeMemory(layout);
+ return status;
+ }
+
+ status = NtDeviceIoControlFile(handle,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ IOCTL_DISK_GET_DRIVE_LAYOUT,
+ NULL,
+ 0,
+ layout,
+ bufferSize);
+ LowCloseDisk(handle);
+
+ if (!NT_SUCCESS(status)) {
+ if (status == STATUS_BAD_MASTER_BOOT_RECORD) {
+
+ FDLOG((1,"LowGetDiskLayout: Disk device %s has bad MBR\n",Path));
+
+ // Zero the drive layout information for the fdengine to process.
+
+ RtlZeroMemory(layout, bufferSize);
+ } else {
+ FDLOG((0,"LowGetDiskLayout: Status %lx getting layout for disk device %s\n",status,Path));
+ FreeMemory(layout);
+ return status;
+ }
+ } else {
+
+ FDLOG((2,"LowGetDiskLayout: layout received from ioctl for %s follows:\n",Path));
+ LOG_DRIVE_LAYOUT(layout);
+ }
+
+ // Check to insure that the drive supports dynamic partitioning.
+
+ *DriveLayout = layout;
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+LowSetDiskLayout(
+ IN PCHAR Path,
+ IN PDRIVE_LAYOUT_INFORMATION DriveLayout
+ )
+
+/*++
+
+Routine Description:
+
+ Perform the NT API actions of opening Partition0 for
+ the specified drive and setting the drive layout.
+
+Arguments:
+
+ Path - Ascii path name to get to disk object
+ this is not a full path, but rather
+ a path without the Partition indicator
+ \device\harddiskX
+
+ DriveLayout - new layout to set
+
+Return Value:
+
+ NT status
+
+--*/
+
+{
+ IO_STATUS_BLOCK statusBlock;
+ STATUS_CODE status;
+ HANDLE handle;
+ ULONG bufferSize;
+
+ if ((status = LowOpenDisk(Path, &handle)) != OK_STATUS) {
+
+ return status;
+ } else {
+
+ FDLOG((2, "LowSetDiskLayout: calling ioctl for %s, layout follows:\n", Path));
+ LOG_DRIVE_LAYOUT(DriveLayout);
+ }
+
+ bufferSize = sizeof(DRIVE_LAYOUT_INFORMATION)
+ + ( (DriveLayout->PartitionCount - 1)
+ * sizeof(PARTITION_INFORMATION));
+ status = NtDeviceIoControlFile(handle,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ IOCTL_DISK_SET_DRIVE_LAYOUT,
+ DriveLayout,
+ bufferSize,
+ DriveLayout,
+ bufferSize);
+ LowCloseDisk(handle);
+ return status;
+}
+
+
+STATUS_CODE
+LowWriteSectors(
+ IN HANDLE_T VolumeId,
+ IN ULONG SectorSize,
+ IN ULONG StartingSector,
+ IN ULONG NumberOfSectors,
+ IN PVOID Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ Routine to write to a volume handle. This routine
+ insulates the NT issues concerning the call from the
+ caller.
+
+Arguments:
+
+ VolumeId - actually the NT handle.
+ SectorSize - used to calculate starting byte offset for I/O
+ StartingSector - starting sector for write.
+ NumberOfSectors - size of I/O in sectors
+ Buffer - the location for the data
+
+Return Value:
+
+ Standard NT status values
+
+--*/
+
+{
+ IO_STATUS_BLOCK statusBlock;
+ LARGE_INTEGER byteOffset;
+
+ byteOffset = RtlExtendedIntegerMultiply(RtlConvertUlongToLargeInteger(StartingSector), (LONG)SectorSize);
+
+ statusBlock.Status = 0;
+ statusBlock.Information = 0;
+ return(NtWriteFile(VolumeId,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ Buffer,
+ NumberOfSectors * SectorSize,
+ &byteOffset,
+ NULL));
+}
+
+
+STATUS_CODE
+LowReadSectors(
+ IN HANDLE_T VolumeId,
+ IN ULONG SectorSize,
+ IN ULONG StartingSector,
+ IN ULONG NumberOfSectors,
+ IN PVOID Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ Routine to read from a volume handle. This routine
+ insulates the NT issues concerning the call from the
+ caller.
+
+Arguments:
+
+ VolumeId - actually the NT handle.
+ SectorSize - used to calculate starting byte offset for I/O
+ StartingSector - starting sector for write.
+ NumberOfSectors - size of I/O in sectors
+ Buffer - the location for the data
+
+Return Value:
+
+ Standard NT status values
+
+--*/
+
+{
+ IO_STATUS_BLOCK statusBlock;
+ LARGE_INTEGER byteOffset;
+
+ byteOffset = RtlExtendedIntegerMultiply(RtlConvertUlongToLargeInteger(StartingSector), (LONG)SectorSize);
+
+ statusBlock.Status = 0;
+ statusBlock.Information = 0;
+ return(NtReadFile(VolumeId,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ Buffer,
+ NumberOfSectors * SectorSize,
+ &byteOffset,
+ NULL));
+}
+
+
+STATUS_CODE
+LowFtVolumeStatus(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ IN PFT_SET_STATUS FtStatus,
+ IN PULONG NumberOfMembers
+ )
+
+/*++
+
+Routine Description:
+
+ Open the requested partition and query the FT state.
+
+Arguments:
+
+ DriveLetter - the letter for the current state
+ FtState - a pointer to a location to return state
+ NumberOfMembers - a pointer to a ULONG for number of members
+ in the FT set.
+
+Return Value:
+
+ Standard NT status values
+
+--*/
+
+{
+ HANDLE handle;
+ STATUS_CODE status;
+ IO_STATUS_BLOCK statusBlock;
+ FT_SET_INFORMATION setInfo;
+
+ status = LowOpenPartition(GetDiskName(Disk),
+ Partition,
+ &handle);
+
+ if (status == OK_STATUS) {
+
+ status = NtDeviceIoControlFile(handle,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ FT_QUERY_SET_STATE,
+ NULL,
+ 0,
+ &setInfo,
+ sizeof(setInfo));
+ LowCloseDisk(handle);
+
+ if (status == OK_STATUS) {
+ switch (setInfo.SetState) {
+ case FtStateOk:
+ *FtStatus = FtSetHealthy;
+ break;
+
+ case FtHasOrphan:
+ switch (setInfo.Type) {
+ case Mirror:
+ *FtStatus = FtSetBroken;
+ break;
+ case StripeWithParity:
+ *FtStatus = FtSetRecoverable;
+ break;
+ }
+ break;
+
+ case FtRegenerating:
+ *FtStatus = FtSetRegenerating;
+ break;
+
+ case FtCheckParity:
+ *FtStatus = FtSetInitializationFailed;
+ break;
+
+ case FtInitializing:
+ *FtStatus = FtSetInitializing;
+ break;
+
+ case FtDisabled:
+
+ // This will never happen.
+
+ *FtStatus = FtSetDisabled;
+ break;
+
+ case FtNoCheckData:
+ default:
+
+ // BUGBUG: there is no mapping here.
+
+ *FtStatus = FtSetHealthy;
+ break;
+ }
+ *NumberOfMembers = setInfo.NumberOfMembers;
+ }
+ } else {
+
+ // If the FT set could not be opened, then it must be
+ // disabled if the return code is "No such device".
+
+ if (status == 0xc000000e) {
+ *FtStatus = FtSetDisabled;
+ status = OK_STATUS;
+ }
+ }
+
+ // Always update the state to the caller.
+
+ return status;
+}
+
+
+STATUS_CODE
+LowFtVolumeStatusByLetter(
+ IN CHAR DriveLetter,
+ IN PFT_SET_STATUS FtStatus,
+ IN PULONG NumberOfMembers
+ )
+
+/*++
+
+Routine Description:
+
+ Open the requested drive letter and query the FT state.
+
+Arguments:
+
+ DriveLetter - the letter for the current state
+ FtState - a pointer to a location to return state
+ NumberOfMembers - a pointer to a ULONG for number of members
+ in the FT set.
+
+Return Value:
+
+ Standard NT status values
+
+--*/
+
+{
+ HANDLE handle;
+ STATUS_CODE status;
+ IO_STATUS_BLOCK statusBlock;
+ FT_SET_INFORMATION setInfo;
+
+ *NumberOfMembers = 1;
+ status = LowOpenDriveLetter(DriveLetter,
+ &handle);
+
+ if (status == OK_STATUS) {
+
+ status = NtDeviceIoControlFile(handle,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ FT_QUERY_SET_STATE,
+ NULL,
+ 0,
+ &setInfo,
+ sizeof(setInfo));
+ LowCloseDisk(handle);
+
+ if (status == OK_STATUS) {
+ switch (setInfo.SetState) {
+ case FtStateOk:
+ *FtStatus = FtSetHealthy;
+ break;
+
+ case FtHasOrphan:
+ switch (setInfo.Type) {
+ case Mirror:
+ *FtStatus = FtSetBroken;
+ break;
+ case StripeWithParity:
+ *FtStatus = FtSetRecoverable;
+ break;
+ }
+ break;
+
+ case FtRegenerating:
+ *FtStatus = FtSetRegenerating;
+ break;
+
+ case FtCheckParity:
+ *FtStatus = FtSetInitializationFailed;
+ break;
+
+ case FtInitializing:
+ *FtStatus = FtSetInitializing;
+ break;
+
+ case FtDisabled:
+
+ // This will never happen.
+
+ *FtStatus = FtSetDisabled;
+ break;
+
+ case FtNoCheckData:
+ default:
+
+ // BUGBUG: there is no mapping here.
+
+ *FtStatus = FtSetHealthy;
+ break;
+ }
+ *NumberOfMembers = setInfo.NumberOfMembers;
+ }
+ } else {
+
+ // If the FT set could not be opened, then it must be
+ // disabled if the return code is "No such device".
+
+ if (status == 0xc000000e) {
+ *FtStatus = FtSetDisabled;
+ status = OK_STATUS;
+ }
+ }
+
+ // Always update the state to the caller.
+
+ return status;
+}
+
+
+
+#define NUMBER_OF_HANDLES_TRACKED 500
+HANDLE OpenHandleArray[NUMBER_OF_HANDLES_TRACKED];
+BOOLEAN DmFirstTime = TRUE;
+ULONG HandleHighWaterMark = 0;
+
+NTSTATUS
+DmOpenFile(
+ OUT PHANDLE FileHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ IN ULONG ShareAccess,
+ IN ULONG OpenOptions
+ )
+
+/*++
+
+Routine Description:
+
+ A debugging aid to track open and closes of partitions.
+
+Arguments:
+
+ Same as for NtOpenFile()
+
+Return Value:
+
+ Same as for NtOpenFile()
+
+--*/
+
+{
+ ULONG index;
+ NTSTATUS status;
+
+ if (DmFirstTime) {
+ DmFirstTime = FALSE;
+ for (index = 0; index < NUMBER_OF_HANDLES_TRACKED; index++) {
+ OpenHandleArray[index] = (HANDLE) 0;
+ }
+ }
+
+ status = NtOpenFile(FileHandle,
+ DesiredAccess,
+ ObjectAttributes,
+ IoStatusBlock,
+ ShareAccess,
+ OpenOptions);
+ if (NT_SUCCESS(status)) {
+ for (index = 0; index < NUMBER_OF_HANDLES_TRACKED; index++) {
+ if (OpenHandleArray[index] == (HANDLE) 0) {
+ OpenHandleArray[index] = *FileHandle;
+
+ if (index > HandleHighWaterMark) {
+ HandleHighWaterMark = index;
+ }
+ break;
+ }
+ }
+ }
+ return status;
+}
+
+
+NTSTATUS
+DmClose(
+ IN HANDLE Handle
+ )
+
+/*++
+
+Routine Description:
+
+ A debugging aid for tracking open and closes
+
+Arguments:
+
+ Same as for NtClose()
+
+Return Value:
+
+ Same as for NtClose()
+
+--*/
+
+{
+ ULONG index;
+
+ for (index = 0; index < NUMBER_OF_HANDLES_TRACKED; index++) {
+ if (OpenHandleArray[index] == Handle) {
+ OpenHandleArray[index] = (HANDLE) 0;
+ break;
+ }
+ }
+
+ return NtClose(Handle);
+}
diff --git a/private/utils/fdisk/readme.txt b/private/utils/fdisk/readme.txt
new file mode 100644
index 000000000..51ec453e3
--- /dev/null
+++ b/private/utils/fdisk/readme.txt
@@ -0,0 +1,55 @@
+
+
+ Building NT fdisk's boot code
+ -----------------------------
+
+
+ The master boot code is contained in the file x86mboot.c, which is
+#include'd into fd_nt.c. The boot code is in the form of an array
+(named x86BootCode) of unsigned chars, which is refered to by code in
+fd_nt.c when fdisk needs to lay boot code on the disk.
+
+ The x86mboot.c file is generated by different means depending on the
+compilation host (ie, whether you're building on x86 or MIPS).
+
+
+The following applies to x86 ONLY:
+----------------------------------
+
+ The master boot code is built from the x86mboot.asm and x86mboot.msg
+files in i386 by running masm386 over these files to produce x86mboot.obj.
+
+Then link_60 is run over x86mboot.obj to produce x86mboot.com. The boot code
+is at offset 1280 in this file (1280 = 600h-100h. 600h is where the boot
+code is assembled, and 100h is where a .com file is loaded by DOS.) It is
+of length 0x1be (512 byte sector - 64-byte partition table - signature word).
+
+The tool bin2c.exe (in sdktoosl) is run over x86mboot.com to generate
+i386\x86mboot.c.
+
+
+The following applies to MIPS ONLY:
+-----------------------------------
+
+ On MIPS, the best we can do is check in the 'finished' product of the
+x86 process, namely x86mboot.c, into the mips directory (we cannot run
+masm386 or link_60 on MIPS!). If, however, the i386\x86mboot.asm or .msg
+files are newer than mips\x86mboot.c, then that means that someone changed
+the boot code but did not check in the .c file to mips\x86mboot.c. So we
+generate an error message.
+
+The correct action when receiving this error message is to go to an x86
+machine, bget or build the i386\x86mboot.c file, and check that file
+into mips\x86mboot.c. Then sync on the MIPS machine.
+
+
+
+
+
+
+ Our build process generates a -I parameter to the compiler based on
+the compilation environement (ie, -Imips\ or -Ii386\). This allows fdisk
+to simply '#include "x86mboot.c"' and get either the generated file on x86
+or the file under source control for MIPS. This way we maintain at least
+a semblance of the correct dependencies should the x86mboot.msg file be
+translated, etc.
diff --git a/private/utils/fdisk/rmdisk.bmp b/private/utils/fdisk/rmdisk.bmp
new file mode 100644
index 000000000..7dd7d57fb
--- /dev/null
+++ b/private/utils/fdisk/rmdisk.bmp
Binary files differ
diff --git a/private/utils/fdisk/scsi.h b/private/utils/fdisk/scsi.h
new file mode 100644
index 000000000..fc3f6c861
--- /dev/null
+++ b/private/utils/fdisk/scsi.h
@@ -0,0 +1,85 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ scsi.h
+
+Abstract:
+
+ This is a subset of the header file for SCSI definitions that is
+ located in the kernel tree.
+
+Authors:
+
+ Mike Glass (mglass)
+
+Revision History:
+
+--*/
+
+//
+// Inquiry buffer structure. This is the data returned from the target
+// after it receives an inquiry.
+//
+// This structure may be extended by the number of bytes specified
+// in the field AdditionalLength. The defined size constant only
+// includes fields through ProductRevisionLevel.
+//
+// The NT SCSI drivers are only interested in the first 36 bytes of data.
+//
+
+#define INQUIRYDATABUFFERSIZE 36
+
+typedef struct _INQUIRYDATA {
+ UCHAR DeviceType : 5;
+ UCHAR DeviceTypeQualifier : 3;
+ UCHAR DeviceTypeModifier : 7;
+ UCHAR RemovableMedia : 1;
+ UCHAR Versions;
+ UCHAR ResponseDataFormat;
+ UCHAR AdditionalLength;
+ UCHAR Reserved[2];
+ UCHAR SoftReset : 1;
+ UCHAR CommandQueue : 1;
+ UCHAR Reserved2 : 1;
+ UCHAR LinkedCommands : 1;
+ UCHAR Synchronous : 1;
+ UCHAR Wide16Bit : 1;
+ UCHAR Wide32Bit : 1;
+ UCHAR RelativeAddressing : 1;
+ UCHAR VendorId[8];
+ UCHAR ProductId[16];
+ UCHAR ProductRevisionLevel[4];
+ UCHAR VendorSpecific[20];
+ UCHAR Reserved3[40];
+} INQUIRYDATA, *PINQUIRYDATA;
+
+//
+// Inquiry defines. Used to interpret data returned from target as result
+// of inquiry command.
+//
+// DeviceType field
+//
+
+#define DIRECT_ACCESS_DEVICE 0x00 // disks
+#define SEQUENTIAL_ACCESS_DEVICE 0x01 // tapes
+#define PRINTER_DEVICE 0x02 // printers
+#define PROCESSOR_DEVICE 0x03 // scanners, printers, etc
+#define WRITE_ONCE_READ_MULTIPLE_DEVICE 0x04 // worms
+#define READ_ONLY_DIRECT_ACCESS_DEVICE 0x05 // cdroms
+#define SCANNER_DEVICE 0x06 // scanners
+#define OPTICAL_DEVICE 0x07 // optical disks
+#define MEDIUM_CHANGER 0x08 // jukebox
+#define COMMUNICATION_DEVICE 0x09 // network
+#define LOGICAL_UNIT_NOT_PRESENT_DEVICE 0x7F
+#define DEVICE_QUALIFIER_NOT_SUPPORTED 0x03
+
+//
+// DeviceTypeQualifier field
+//
+
+#define DEVICE_CONNECTED 0x00
+
+
diff --git a/private/utils/fdisk/smdisk.bmp b/private/utils/fdisk/smdisk.bmp
new file mode 100644
index 000000000..db2c6b252
--- /dev/null
+++ b/private/utils/fdisk/smdisk.bmp
Binary files differ
diff --git a/private/utils/fdisk/sources b/private/utils/fdisk/sources
new file mode 100644
index 000000000..5ee801f12
--- /dev/null
+++ b/private/utils/fdisk/sources
@@ -0,0 +1,41 @@
+MAJORCOMP=utils
+MINORCOMP=windisk
+
+TARGETNAME=windisk
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+SOURCES= \
+ windisk.c \
+ fdmisc.c \
+ fddlgs.c \
+ fddata.c \
+ fd_nt.c \
+ fdengine.c \
+ fdinit.c \
+ fdmem.c \
+ fdlistbx.c \
+ fdprof.c \
+ fdstleg.c \
+ fdft.c \
+ fdhelp.c \
+ ntlow.c \
+ arrowin.c \
+ ftreg.c \
+ dblspace.c \
+ fmifs.c \
+ commit.c \
+ cdrom.c \
+ network.c \
+ fdisk.rc
+
+INCLUDES=..\fmifs\inc
+
+UMTYPE=windows
+MSC_WARNING_LEVEL=/W3 /WX
+UMLIBS=$(BASEDIR)\public\sdk\lib\*\diskreg.lib \
+ $(BASEDIR)\public\sdk\lib\*\shell32.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\netapi32.lib
+
+NTTARGETFILE0=fdiskmsg.h fdiskmsg.rc
diff --git a/private/utils/fdisk/windisk.c b/private/utils/fdisk/windisk.c
new file mode 100644
index 000000000..fb819db62
--- /dev/null
+++ b/private/utils/fdisk/windisk.c
@@ -0,0 +1,5549 @@
+
+/*++
+
+Copyright (c) 1991-1994 Microsoft Corporation
+
+Module Name:
+
+ windisk.c
+
+Abstract:
+
+ This module contains the main dialog and support routines for
+ Disk Administrator.
+
+Author:
+
+ Edward (Ted) Miller (TedM) 11/15/91
+
+Environment:
+
+ User process.
+
+Notes:
+
+Revision History:
+
+ 11-Nov-93 (bobri) added doublespace and commit support.
+
+--*/
+
+#include "fdisk.h"
+#include "shellapi.h"
+#include <string.h>
+#include <stdio.h>
+
+#if DBG && DEVL
+
+// stuff used in debug version
+
+BOOL AllowAllDeletes = FALSE; // whether to allow deleting boot/sys parts
+
+#endif
+
+// External from fdinit.
+
+extern HWND InitDlg;
+extern BOOLEAN InitDlgComplete;
+extern BOOLEAN StartedAsIcon;
+HANDLE hAccelerator;
+
+// This is the maximum number of members that WinDisk will support
+// in an FT Set.
+
+#define MaxMembersInFtSet 32
+
+// The following vars keep track of the currently selected regions.
+
+DWORD SelectionCount = 0;
+PDISKSTATE SelectedDS[MaxMembersInFtSet];
+ULONG SelectedRG[MaxMembersInFtSet];
+
+#define SELECTED_REGION(i) (SelectedDS[i]->RegionArray[SelectedRG[i]])
+
+FT_TYPE FtSelectionType;
+
+// This variable tracks whether the system partition is secure.
+
+BOOL SystemPartitionIsSecure = FALSE;
+
+// Deleted a partition with no drive letter
+
+BOOLEAN CommitDueToDelete = FALSE;
+BOOLEAN CommitDueToMirror = FALSE;
+BOOLEAN CommitDueToExtended = FALSE;
+
+// If a mirror is made of the boot partition, this will become
+// non-zero and indicate which disk should get some boot code in
+// the MBR.
+
+ULONG UpdateMbrOnDisk = 0;
+
+#ifdef DOUBLE_SPACE_SUPPORT_INCLUDED
+
+// If FmIfs.dll doesn't have double space routines this
+// flag will reflect that fact.
+
+extern BOOLEAN DoubleSpaceSupported;
+BOOLEAN DoubleSpaceAutomount;
+#endif
+
+
+VOID
+FrameCommandHandler(
+ IN HWND hwnd,
+ IN DWORD wParam,
+ IN LONG lParam
+ );
+
+DWORD
+SetUpMenu(
+ IN PDISKSTATE *SinglySelectedDisk,
+ IN DWORD *SinglySelectedRegion
+ );
+
+BOOL
+AssignDriveLetter(
+ IN BOOL WarnIfNoLetter,
+ IN DWORD StringId,
+ OUT PCHAR DriveLetter
+ );
+
+VOID
+AdjustOptionsMenu(
+ VOID
+ );
+
+ULONG
+PartitionCount(
+ IN ULONG Disk
+ );
+
+VOID
+CheckForBootNumberChange(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ Determine if the disk that has just changed is the boot disk.
+ If so, determine if the boot partition number changed. If it
+ did, warn the user.
+
+Arguments:
+
+ RegionDescriptor - the region that has just changed.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG newPart;
+ CHAR oldNumberString[8],
+ newNumberString[8];
+ DWORD msgCode;
+
+ if (Disk == BootDiskNumber) {
+
+ // Pass a pointer to Disk even though this is just to get the
+ // old partition number back.
+
+ if (BootPartitionNumberChanged(&Disk, &newPart)) {
+#if i386
+ msgCode = MSG_CHANGED_BOOT_PARTITION_X86;
+#else
+ msgCode = MSG_CHANGED_BOOT_PARTITION_ARC;
+#endif
+ sprintf(oldNumberString, "%d", Disk);
+ sprintf(newNumberString, "%d", newPart);
+ InfoDialog(msgCode, oldNumberString, newNumberString);
+ }
+ }
+}
+
+
+BOOL
+IsSystemPartitionSecure(
+ )
+
+/*++
+
+Routine Description:
+
+ This routine knows where to go in the Registry to determine
+ if the system partition for this boot is to be protected from
+ modification.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ TRUE if the system partition is secure
+ FALSE otherwise.
+
+--*/
+
+{
+ LONG ec;
+ HKEY hkey;
+ DWORD type;
+ DWORD size;
+ ULONG value;
+
+ value = FALSE;
+
+ ec = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("System\\CurrentControlSet\\Control\\Lsa"),
+ 0,
+ KEY_QUERY_VALUE,
+ &hkey);
+
+ if (ec == NO_ERROR) {
+
+ size = sizeof(ULONG);
+ ec = RegQueryValueExA(hkey,
+ TEXT("Protect System Partition"),
+ NULL,
+ &type,
+ (PBYTE)&value,
+ &size);
+
+ if ((ec != NO_ERROR) || (type != REG_DWORD)) {
+ value = FALSE;
+ }
+ RegCloseKey(hkey);
+ }
+ return value;
+}
+
+VOID _CRTAPI1
+main(
+ IN int argc,
+ IN char *argv[],
+ IN char *envp[]
+ )
+
+/*++
+
+Routine Description:
+
+ This is were control is given to Disk Administrator when it
+ is started. This routine initializes the application and
+ contains the control loop for getting and processing Windows
+ messages.
+
+Arguments:
+
+ Standard "main" entry
+
+Return Value:
+
+ Standard "main" entry
+
+--*/
+
+{
+ MSG msg;
+ NTSTATUS status;
+ HANDLE mutex;
+
+ hModule = GetModuleHandle(NULL);
+
+ mutex = CreateMutex(NULL,FALSE,"Disk Administrator Is Running");
+
+ if (mutex == NULL) {
+ // An error (like out of memory) has occurred.
+ return;
+ }
+
+ // Make sure we are the only process with a handle to our named mutex.
+
+ if (GetLastError() == ERROR_ALREADY_EXISTS) {
+ CloseHandle(mutex);
+ InfoDialog(MSG_ALREADY_RUNNING);
+ return;
+ } else {
+ DisplayInitializationMessage();
+ }
+
+ // Determine whether this is LanmanNt or Windows NT by looking at
+ // HKEY_LOCAL_MACHINE,System\CurrentControlSet\Control\ProductOptions.
+ // If the ProductType value therein is "LanmanNt" then this is LanmanNt.
+
+ {
+ LONG ec;
+ HKEY hkey;
+ DWORD type;
+ DWORD size;
+ UCHAR buf[100];
+
+ IsLanmanNt = FALSE;
+
+#if DBG
+ // The code below will allow users to run WinDisk in Lanman
+ // mode on WinNt. It should never be enabled in a released
+ // build, but is very useful for internal users.
+
+ if (argc >= 2 && !_stricmp(argv[1], "-p:lanman")) {
+ IsLanmanNt = TRUE;
+ }
+#endif
+ ec = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("System\\CurrentControlSet\\Control\\ProductOptions"),
+ 0,
+ KEY_QUERY_VALUE,
+ &hkey);
+
+ if (ec == NO_ERROR) {
+
+ size = sizeof(buf);
+ ec = RegQueryValueExA(hkey,
+ TEXT("ProductType"),
+ NULL,
+ &type,
+ buf,
+ &size);
+
+ if ((ec == NO_ERROR) && (type == REG_SZ)) {
+
+ if (!lstrcmpiA(buf,"lanmannt")) {
+ IsLanmanNt = TRUE;
+ }
+ if (!lstrcmpiA(buf,"servernt")) {
+ IsLanmanNt = TRUE;
+ }
+ }
+
+ RegCloseKey(hkey);
+ }
+ }
+
+ // Set the Help file name to the file appropriate to
+ // the product.
+
+ HelpFile = IsLanmanNt ? LanmanHelpFile : WinHelpFile;
+
+ // Determine whether the system partition is protected:
+
+ SystemPartitionIsSecure = IsSystemPartitionSecure();
+
+ try {
+
+#if DBG
+ InitLogging();
+#endif
+
+ // Insure that all drives are present before looking.
+
+ RescanDevices();
+
+ if (!NT_SUCCESS(status = FdiskInitialize())) {
+ ErrorDialog(status == STATUS_ACCESS_DENIED ? MSG_ACCESS_DENIED : EC(status));
+ goto xx1;
+ }
+
+ if (((DiskCount = GetDiskCount()) == 0) || AllDisksOffLine()) {
+ ErrorDialog(MSG_NO_DISKS);
+ goto xx2;
+ }
+
+ if (!InitializeApp()) {
+ ErrorDialog(MSG_CANT_CREATE_WINDOWS);
+ goto xx2;
+ }
+
+ InitRectControl();
+
+ SetUpMenu(&SingleSel,&SingleSelIndex);
+ AdjustOptionsMenu();
+
+ InitHelp();
+ hAccelerator = LoadAccelerators(hModule, TEXT("MainAcc"));
+
+ if (InitDlg) {
+
+ PostMessage(InitDlg,
+ (WM_USER + 1),
+ 0,
+ 0);
+ InitDlg = (HWND) 0;
+ }
+ while (GetMessage(&msg,NULL,0,0)) {
+ if (!TranslateAccelerator(hwndFrame, hAccelerator, &msg)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ TermHelp();
+ UnloadIfsDll();
+
+ xx2:
+
+ FdiskCleanUp();
+
+ xx1:
+
+ ;
+
+ } finally {
+
+ // Destroy the mutex.
+
+ CloseHandle(mutex);
+ }
+}
+
+LONG
+MyFrameWndProc(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN UINT wParam,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ This is the window handler for the main display of Disk Administrator.
+
+Arguments:
+
+ Standard window handler procedure
+
+Return Value:
+
+ Standard window handler procedure
+
+--*/
+
+{
+ static BOOLEAN oneTime = TRUE;
+ PMEASUREITEMSTRUCT pMeasureItem;
+ DWORD ec;
+ DWORD action;
+ DWORD temp;
+ RECT rc;
+ BOOL profileWritten,
+ changesMade,
+ mustReboot,
+ configureFt;
+ HMENU hMenu;
+
+ switch (msg) {
+ case WM_CREATE:
+
+ // create the listbox
+
+ if (!StartedAsIcon) {
+ StartedAsIcon = IsIconic(hwnd);
+ }
+ GetClientRect(hwnd,&rc);
+#if 1
+ hwndList = CreateWindow(TEXT("listbox"),
+ NULL,
+ WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_VISIBLE | LBS_NOTIFY |
+ LBS_NOINTEGRALHEIGHT | LBS_OWNERDRAWFIXED,
+ 0,
+ dyLegend,
+ rc.right - rc.left,
+ rc.bottom - rc.top - (StatusBar ? dyStatus : 0) - (Legend ? dyLegend : 0),
+ hwnd,
+ (HMENU)ID_LISTBOX,
+ hModule,
+ NULL);
+#else
+ hwndList = CreateWindow(TEXT("listbox"),
+ NULL,
+ WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_VISIBLE | LBS_NOTIFY |
+ LBS_NOINTEGRALHEIGHT | LBS_OWNERDRAWFIXED,
+ 0,
+ dyLegend,
+ CW_USEDEFAULT,
+ CW_USEDEFAULT,
+ hwnd,
+ (HMENU)ID_LISTBOX,
+ hModule,
+ NULL);
+#endif
+ if (hwndList) {
+
+ SetFocus(hwndList);
+
+ // subclass the listbox so we can handle keyboard
+ // input our way.
+
+ SubclassListBox(hwndList);
+ }
+
+ // If we are not running the LanmanNt version of
+ // Windisk, remove the Fault-Tolerance menu item.
+
+ if (!IsLanmanNt && (hMenu = GetMenu( hwnd )) != NULL ) {
+
+ DeleteMenu( hMenu, 1, MF_BYPOSITION );
+ DrawMenuBar( hwnd );
+ }
+
+ StatusTextDrlt[0] = 0;
+ StatusTextStat[0] = StatusTextSize[0] = 0;
+ StatusTextType[0] = StatusTextVoll[0] = 0;
+ break;
+
+ case WM_SETFOCUS:
+
+ SetFocus(hwndList);
+ break;
+
+ case WM_WININICHANGE:
+
+ if ((lParam == (LONG)NULL) || !lstrcmpi((LPTSTR)lParam,TEXT("colors"))) {
+ TotalRedrawAndRepaint();
+ InvalidateRect(hwnd,NULL,FALSE);
+ }
+ break;
+
+ case WM_SIZE:
+
+ // resize the listbox
+
+ GetClientRect(hwnd,&rc);
+#if 0
+ temp = rc.right - rc.left;
+
+ if (GraphWidth != temp) {
+
+ GraphWidth = temp;
+ BarWidth = GraphWidth - dxBarTextMargin;
+ }
+#endif
+ MoveWindow(hwndList,
+ rc.left,
+ rc.top,
+ rc.right - rc.left,
+ rc.bottom - rc.top - (StatusBar ? dyStatus : 0) - (Legend ? dyLegend : 0),
+ TRUE);
+
+ // invalidate status/legend area so that the clipping
+ // rectangle is right for redraws
+
+ rc.top = rc.bottom;
+
+ if (StatusBar) {
+ rc.top -= dyStatus;
+ }
+ if (Legend) {
+ rc.top -= dyLegend;
+ }
+ if (rc.top != rc.bottom) {
+ InvalidateRect(hwnd,&rc,FALSE);
+ }
+
+ // FALL THROUGH
+
+ case WM_MOVE:
+
+ // if not iconic or minimized, save new position for profile
+
+ if (!IsZoomed(hwndFrame) && !IsIconic(hwndFrame)) {
+ GetWindowRect(hwndFrame,&rc);
+ ProfileWindowX = rc.left;
+ ProfileWindowY = rc.top;
+ ProfileWindowW = rc.right - rc.left;
+ ProfileWindowH = rc.bottom - rc.top;
+ }
+ break;
+
+ case WM_ENTERIDLE:
+
+ if (ConfigurationSearchIdleTrigger == TRUE && wParam == MSGF_DIALOGBOX) {
+
+ PostMessage((HWND)lParam,WM_ENTERIDLE,wParam,lParam);
+
+ } else {
+
+ // If we're coming from a dialog box and the F1 key is down,
+ // kick the dialog box and make it spit out help.
+
+ if ((wParam == MSGF_DIALOGBOX) &&
+ (GetKeyState(VK_F1) & 0x8000) &&
+ GetDlgItem((HANDLE) lParam, FD_IDHELP)) {
+
+ PostMessage((HANDLE) lParam, WM_COMMAND, FD_IDHELP, 0L);
+ }
+ }
+
+ return 1; // indicate we did not process the message
+
+ case WM_PAINT:
+
+#if 1
+ if ((!IsIconic(hwnd)) && !(InitDlg && StartedAsIcon)) {
+#else
+ if (!StartedAsIcon) {
+#endif
+ HDC hdcTemp,hdcScr;
+ HBITMAP hbmTemp;
+ PAINTSTRUCT ps;
+ HBRUSH hBrush;
+ HFONT hFontOld;
+ RECT rcTemp,rcTemp2;
+ DWORD ClientRight;
+
+ BeginPaint(hwnd,&ps);
+ hdcScr = ps.hdc;
+
+ GetClientRect(hwnd,&rc);
+
+ rcTemp2 = rc;
+ ClientRight = rc.right;
+ rc.top = rc.bottom - dyStatus + dyBorder;
+
+ if (StatusBar) {
+
+ hdcTemp = CreateCompatibleDC(hdcScr);
+ hbmTemp = CreateCompatibleBitmap(hdcScr,rc.right-rc.left+1,rc.bottom-rc.top+1);
+ SelectObject(hdcTemp,hbmTemp);
+
+ // adjust position for off-screen bitmap
+
+ rcTemp = rc;
+ rc.bottom -= rc.top;
+ rc.top = 0;
+
+ hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
+ if (hBrush) {
+ FillRect(hdcTemp,&rc,hBrush);
+ DeleteObject(hBrush);
+ }
+
+ // draw the status bar at the bottom of the window
+
+ hFontOld = SelectObject(hdcTemp,hFontStatus);
+
+ // Status text
+ rc.left = 8 * dyBorder;
+ rc.right = 2 * GraphWidth / 5;
+ DrawStatusAreaItem(&rc,hdcTemp,StatusTextStat,FALSE);
+
+ // size
+ rc.left = rc.right + (8*dyBorder);
+ rc.right = rc.left + (GraphWidth / 9);
+ DrawStatusAreaItem(&rc,hdcTemp,StatusTextSize,FALSE);
+
+ // type
+ rc.left = rc.right + (8*dyBorder);
+ rc.right = rc.left + (GraphWidth / 5);
+ DrawStatusAreaItem(&rc,hdcTemp,(LPTSTR)StatusTextType,TRUE);
+
+ // drive letter
+ rc.left = rc.right + (8*dyBorder);
+ rc.right = rc.left + (8*dyBorder) + dxDriveLetterStatusArea;
+ DrawStatusAreaItem(&rc,hdcTemp,(LPTSTR)StatusTextDrlt,TRUE);
+
+ // vol label
+ rc.left = rc.right + (8*dyBorder);
+ rc.right = GraphWidth - (8*dyBorder);
+ DrawStatusAreaItem(&rc,hdcTemp,(LPTSTR)StatusTextVoll,TRUE);
+
+ BitBlt(hdcScr,
+ rcTemp.left,
+ rcTemp.top,
+ rcTemp.right-rcTemp.left+1,
+ rcTemp.bottom-rcTemp.top+1,
+ hdcTemp,
+ 0,
+ 0,
+ SRCCOPY);
+
+ if (hFontOld) {
+ SelectObject(hdcTemp,hFontOld);
+ }
+ DeleteObject(hbmTemp);
+ DeleteDC(hdcTemp);
+ } else {
+ rcTemp = rcTemp2;
+ rcTemp.top = rcTemp.bottom;
+ }
+
+ if (Legend) {
+
+ // draw the legend onto the screen
+
+ if (StatusBar) {
+ rcTemp2.bottom -= dyStatus;
+ }
+ rcTemp2.top = rcTemp2.bottom - dyLegend + (2*dyBorder);
+ if (StatusBar) {
+ rcTemp2.top += dyBorder;
+ }
+ rcTemp2.right = GraphWidth;
+ DrawLegend(hdcScr,&rcTemp2);
+ }
+
+ // dark line across top of status/legend area
+
+ if (hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNTEXT))) {
+
+ if (StatusBar || Legend) {
+ rcTemp.bottom = rcTemp.top;
+ if (Legend) {
+ rcTemp.bottom -= dyLegend - 1;
+ rcTemp.top -= dyLegend - 1;
+ }
+ rcTemp.top -= dyBorder;
+ FillRect(hdcScr,&rcTemp,hBrush);
+ }
+ DeleteObject(hBrush);
+ }
+
+ EndPaint(hwnd,&ps);
+
+ }
+ if (InitDlg) {
+
+ if (InitDlgComplete) {
+ PostMessage(InitDlg,
+ (WM_USER + 1),
+ 0,
+ 0);
+ InitDlg = (HWND) 0;
+ }
+
+ }
+ if (oneTime) {
+ if (!StartedAsIcon) {
+ SetForegroundWindow(hwnd);
+ }
+ oneTime = FALSE;
+ }
+ break;
+
+ case WM_COMMAND:
+
+ FrameCommandHandler(hwnd,wParam,lParam);
+ break;
+
+ case WM_MEASUREITEM:
+
+ pMeasureItem = (PMEASUREITEMSTRUCT)lParam;
+ pMeasureItem->itemHeight = GraphHeight;
+ break;
+
+ case WM_DRAWITEM:
+
+ WMDrawItem((PDRAWITEMSTRUCT)lParam);
+ break;
+
+ case WM_CTLCOLORLISTBOX:
+
+ if (lParam == (LONG)hwndList) {
+ return (LONG)GetStockObject(LTGRAY_BRUSH);
+ } else {
+ return DefWindowProc(hwnd,msg,wParam,lParam);
+ }
+
+ case WM_CLOSE:
+
+ // Determine whether any disks have been changed, and whether
+ // the system must be rebooted. The system must be rebooted
+ // if the registry has changed, if any non-removable disk has
+ // changed, or if any removable disk that was not originally
+ // unpartitioned has changed.
+
+ changesMade = FALSE;
+ configureFt = FALSE;
+ mustReboot = RestartRequired;
+
+ for (temp=0; temp<DiskCount; temp++) {
+ if (HavePartitionsBeenChanged(temp)) {
+
+ changesMade = TRUE;
+ break;
+ }
+ }
+
+ profileWritten = FALSE;
+
+ // Determine if the commit can be done without a reboot.
+ // If FT is in the system then it must be notified to
+ // reconfigure if a reboot is not performed. If it is
+ // not in the system, but the new disk information requires
+ // it, then a reboot must be forced.
+
+ if (FtInstalled()) {
+ configureFt = TRUE;
+ }
+ if (NewConfigurationRequiresFt()) {
+ if (!configureFt) {
+
+ // The FT driver is not loaded currently.
+
+ mustReboot = TRUE;
+ } else {
+
+ // If the system is going to be rebooted, don't
+ // have FT reconfigure prior to shutdown.
+
+ if (mustReboot) {
+ configureFt = FALSE;
+ }
+ }
+ }
+
+ if (RegistryChanged | changesMade | RestartRequired) {
+ if (RestartRequired) {
+ action = IDYES;
+ } else {
+ action = ConfirmationDialog(MSG_CONFIRM_EXIT, MB_ICONQUESTION | MB_YESNOCANCEL);
+ }
+
+ if (action == IDYES) {
+ ec = CommitLockVolumes(0);
+ if (ec) {
+
+ // could not lock all volumes
+
+ ErrorDialog(MSG_CANNOT_LOCK_FOR_COMMIT);
+ CommitUnlockVolumes(DiskCount, FALSE);
+ break;
+ }
+ if (mustReboot) {
+ if (RestartRequired) {
+ action = IDYES;
+ } else {
+ action = ConfirmationDialog(MSG_REQUIRE_REBOOT, MB_ICONQUESTION | MB_YESNO);
+ }
+
+ if (action != IDYES) {
+
+ CommitUnlockVolumes(DiskCount, FALSE);
+ break;
+ }
+ }
+
+ SetCursor(hcurWait);
+ ec = CommitChanges();
+ SetCursor(hcurNormal);
+
+ CommitUnlockVolumes(DiskCount, TRUE);
+ if (ec != NO_ERROR) {
+ ErrorDialog(MSG_BAD_CONFIG_SET);
+ } else {
+ ULONG oldBootPartitionNumber,
+ newBootPartitionNumber;
+ CHAR oldNumberString[8],
+ newNumberString[8];
+ DWORD msgCode;
+
+ // Update the configuration registry
+
+ ec = SaveFt();
+ if (configureFt) {
+
+ // Issue device control to ftdisk driver to reconfigure.
+
+ FtConfigure();
+ }
+
+ // Register autochk to fix up file systems
+ // in newly extended volume sets, if necessary
+
+ if (RegisterFileSystemExtend()) {
+ mustReboot = TRUE;
+ }
+
+ // Determine if the FT driver must be enabled.
+
+ if (DiskRegistryRequiresFt() == TRUE) {
+ if (!FtInstalled()) {
+ mustReboot = TRUE;
+ }
+ DiskRegistryEnableFt();
+ } else {
+ DiskRegistryDisableFt();
+ }
+
+ if (ec == NO_ERROR) {
+ InfoDialog(MSG_OK_COMMIT);
+ } else {
+ ErrorDialog(MSG_BAD_CONFIG_SET);
+ }
+
+ // Has the partition number of the boot
+ // partition changed?
+
+ if (BootPartitionNumberChanged(&oldBootPartitionNumber, &newBootPartitionNumber)) {
+#if i386
+ msgCode = MSG_BOOT_PARTITION_CHANGED_X86;
+#else
+ msgCode = MSG_BOOT_PARTITION_CHANGED_ARC;
+#endif
+ sprintf(oldNumberString, "%d", oldBootPartitionNumber);
+ sprintf(newNumberString, "%d", newBootPartitionNumber);
+ InfoDialog(msgCode, oldNumberString, newNumberString);
+ }
+
+ ClearCommittedDiskInformation();
+
+ if (UpdateMbrOnDisk) {
+
+ UpdateMasterBootCode(UpdateMbrOnDisk);
+ UpdateMbrOnDisk = 0;
+ }
+
+ // Reboot if necessary.
+
+ if (mustReboot) {
+
+ SetCursor(hcurWait);
+ Sleep(5000);
+ SetCursor(hcurNormal);
+ FdShutdownTheSystem();
+ profileWritten = TRUE;
+ }
+ CommitDueToDelete = CommitDueToMirror = FALSE;
+ CommitAssignLetterList();
+ }
+ } else if (action == IDCANCEL) {
+ return 0; // don't exit
+ } else {
+ FDASSERT(action == IDNO);
+ }
+ }
+
+ if (!profileWritten) {
+ WriteProfile();
+ }
+ DestroyWindow(hwnd);
+ break;
+
+ case WM_DESTROY:
+
+ // BUGBUG clean up here -- release dc's, free DiskStates, etc.
+
+ WinHelp(hwndFrame,HelpFile,HELP_QUIT,0);
+ PostQuitMessage(0);
+ break;
+
+ case WM_MENUSELECT:
+
+ SetMenuItemHelpContext(wParam,lParam);
+ break;
+
+ case WM_F1DOWN:
+
+ Help(wParam);
+ break;
+
+ default:
+
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+ return 0;
+}
+
+#if i386
+
+VOID
+SetUpMenui386(
+ HMENU hMenu,
+ DWORD SelectionCount
+ )
+
+/*++
+
+Routine Description:
+
+ X86 SPECIFIC
+
+ This routine understands the X86 specific feature of
+ "Active Partition". It determines if the "set partition
+ active" menu item should be enabled.
+
+Arguments:
+
+ hMenu - menu handle
+ SelectionCount - number of items currently selected.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ BOOL allowActive = FALSE;
+ PREGION_DESCRIPTOR regionDescriptor;
+
+ if ((SelectionCount == 1) && (FtSelectionType == -1)) {
+
+ regionDescriptor = &SingleSel->RegionArray[SingleSelIndex];
+
+ // allow it to be made active if
+ // - it is not free space
+ // - it is a primary partition
+ // - it is on disk 0
+ // - it is not already active
+ // - it is not part of an ft set
+
+ if ((regionDescriptor->SysID != SYSID_UNUSED)
+ && (regionDescriptor->RegionType == REGION_PRIMARY)
+ && !regionDescriptor->Active
+ && (GET_FT_OBJECT(regionDescriptor) == NULL)) {
+ allowActive = TRUE;
+ }
+ }
+
+ EnableMenuItem(hMenu,
+ IDM_PARTITIONACTIVE,
+ allowActive ? MF_ENABLED : MF_GRAYED);
+}
+
+#endif
+
+DWORD
+SetUpMenu(
+ IN PDISKSTATE *SinglySelectedDisk,
+ IN DWORD *SinglySelectedRegion
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets up the menu bar based on the state of the app and
+ the disks.
+
+ If multiple items are selected, allow neither create nor delete.
+ If a single partition is selected, allow delete.
+ If a single free space is selected, allow create.
+ If the free space is the only free space in the extended partitions,
+ also allow delete. (This is how to delete the extended partition).
+
+Arguments:
+
+ SinglySelectedDisk -- if there is only one selected item, the PDISKSTATE
+ pointed to by this paramater will get a pointer
+ to the selected region's disk structure. If there are
+ multiple selected items (or none), then the value
+ will be set to NULL.
+
+ SinglySelectedRegion -- if there is only one selected item, the DWORD
+ pointed to by this paramater will get the selected
+ region #. Otherwise the DWORD gets -1.
+
+Return Value:
+
+ Count of selected regions.
+
+--*/
+
+{
+ BOOL allowCreate = FALSE,
+ allowCreateEx = FALSE,
+ allowDelete = FALSE,
+ allowFormat = FALSE,
+ allowLabel = FALSE,
+ allowBreakMirror = FALSE,
+ allowCreateMirror = FALSE,
+ allowCreateStripe = FALSE,
+ allowCreateVolumeSet = FALSE,
+ allowExtendVolumeSet = FALSE,
+ allowCreatePStripe = FALSE,
+ allowDriveLetter = FALSE,
+ allowRecoverParity = FALSE,
+ ftSetSelected = FALSE,
+ nonFtItemSelected = FALSE,
+ multipleItemsSelected = FALSE,
+ volumeSetAndFreeSpaceSelected = FALSE,
+ onDifferentDisks,
+ possibleRecover;
+ BOOL allowCommit = CommitAllowed();
+ WCHAR driveLetter = L' ';
+ PWSTR typeName = NULL,
+ volumeLabel = NULL;
+ PDISKSTATE diskState,
+ selDiskState = NULL;
+ DWORD i,
+ j,
+ selectedRegion = 0;
+ ULONG ordinal = 0,
+ selectedFreeSpaces = 0,
+ freeSpaceIndex = 0,
+ componentsInFtSet = 0,
+ selectedNonFtPartitions = 0;
+ HMENU hMenu = GetMenu(hwndFrame);
+ FT_TYPE type = (FT_TYPE) 0;
+ PULONG diskSeenCounts;
+ PFT_OBJECT_SET ftSet = NULL;
+ PFT_OBJECT ftObject = NULL;
+ PREGION_DESCRIPTOR regionDescriptor;
+ PPERSISTENT_REGION_DATA regionData;
+
+ diskSeenCounts = Malloc(DiskCount * sizeof(ULONG));
+ RtlZeroMemory(diskSeenCounts,DiskCount * sizeof(ULONG));
+
+ SelectionCount = 0;
+ for (i=0; i<DiskCount; i++) {
+ diskState = Disks[i];
+ for (j=0; j<diskState->RegionCount; j++) {
+ if (diskState->Selected[j]) {
+ selDiskState = diskState;
+ selectedRegion = j;
+ SelectionCount++;
+ if (SelectionCount <= MaxMembersInFtSet) {
+ SelectedDS[SelectionCount-1] = diskState;
+ SelectedRG[SelectionCount-1] = j;
+ }
+ diskSeenCounts[diskState->Disk]++;
+ if (ftObject = GET_FT_OBJECT(&diskState->RegionArray[j])) {
+ ftSet = ftObject->Set;
+ if (componentsInFtSet == 0) {
+ ordinal = ftSet->Ordinal;
+ type = ftSet->Type;
+ ftSetSelected = TRUE;
+ componentsInFtSet = 1;
+ } else if ((ftSet->Ordinal == ordinal) && (ftSet->Type == type)) {
+ componentsInFtSet++;
+ } else {
+ ftSetSelected = FALSE;
+ }
+ } else {
+
+ nonFtItemSelected = TRUE;
+
+ if (IsRecognizedPartition(diskState->RegionArray[j].SysID) ) {
+ selectedNonFtPartitions += 1;
+ }
+ }
+ }
+ }
+ }
+
+ // Determine the number of free-space regions selected:
+
+ selectedFreeSpaces = 0;
+ for (i=0; i<SelectionCount && i < MaxMembersInFtSet; i++) {
+ if (SELECTED_REGION(i).SysID == SYSID_UNUSED) {
+ freeSpaceIndex = i;
+ selectedFreeSpaces++;
+ }
+ }
+
+ FtSelectionType = -1;
+ possibleRecover = FALSE;
+ if (nonFtItemSelected && ftSetSelected) {
+
+ // Both FT and Non-FT items have been selected. First,
+ // check to see if a volume set and free space have been
+ // selected; then reset the state to indicate that the
+ // selection does not consists of a mix of FT and non-FT
+ // objects.
+
+ if (type == VolumeSet && selectedFreeSpaces + componentsInFtSet == SelectionCount ) {
+
+ volumeSetAndFreeSpaceSelected = TRUE;
+ }
+
+ possibleRecover = TRUE;
+ ftSetSelected = FALSE;
+ nonFtItemSelected = FALSE;
+ multipleItemsSelected = TRUE;
+ }
+
+ if ((SelectionCount == 1) && !ftSetSelected) {
+
+ *SinglySelectedDisk = selDiskState;
+ *SinglySelectedRegion = selectedRegion;
+
+ regionDescriptor = &selDiskState->RegionArray[selectedRegion];
+
+ if (regionDescriptor->SysID == SYSID_UNUSED) {
+
+ // Free region. Always allow create; let DoCreate() sort out
+ // details about whether partition table is full, etc.
+
+ allowCreate = TRUE;
+
+ if (regionDescriptor->RegionType == REGION_PRIMARY) {
+ allowCreateEx = TRUE;
+ }
+
+ // special case -- allow deletion of the extended partition if
+ // there are no logicals in it.
+
+ if ((regionDescriptor->RegionType == REGION_LOGICAL)
+ && selDiskState->ExistExtended
+ && !selDiskState->ExistLogical) {
+ FDASSERT(regionDescriptor->SysID == SYSID_UNUSED);
+ allowDelete = TRUE;
+ }
+ } else {
+
+ // used region. Delete always allowed.
+
+ allowDelete = TRUE;
+ regionData = (PPERSISTENT_REGION_DATA)(PERSISTENT_DATA(regionDescriptor));
+
+ if (regionData) {
+ if (regionData->VolumeExists) {
+ if ((regionData->DriveLetter != NO_DRIVE_LETTER_YET) && (regionData->DriveLetter != NO_DRIVE_LETTER_EVER)) {
+ allowFormat = TRUE;
+ }
+ }
+ }
+
+ // If the region is recognized, then also allow drive letter
+ // manipulation.
+
+ if (IsRecognizedPartition(regionDescriptor->SysID)) {
+
+ allowDriveLetter = TRUE;
+
+ // DblSpace volumes are allowed on non-FT, FAT volumes only
+
+ DetermineRegionInfo(regionDescriptor,
+ &typeName,
+ &volumeLabel,
+ &driveLetter);
+
+ if ((driveLetter != NO_DRIVE_LETTER_YET) && (driveLetter != NO_DRIVE_LETTER_EVER)) {
+ if (wcscmp(typeName, L"FAT") == 0) {
+ allowLabel = allowFormat;
+#ifdef DOUBLE_SPACE_SUPPORT_INCLUDED
+ allowDblSpace = allowFormat;
+#endif
+
+ // Force the dll in now to know if Double Space
+ // support is offerred by the dll.
+
+ LoadIfsDll();
+ }
+
+ if ((wcscmp(typeName, L"NTFS") == 0) ||
+ (wcscmp(typeName, L"HPFS") == 0)) {
+ allowLabel = allowFormat;
+ }
+ }
+ }
+ }
+ } else {
+
+ if (SelectionCount) {
+
+ *SinglySelectedDisk = NULL;
+ *SinglySelectedRegion = (DWORD)(-1);
+
+ // Multiple regions are selected. This might be an existing ft set,
+ // a set of regions that allow creation of an ft set, or just plain
+ // old multiple items.
+ //
+ // First deal with a selected ft set.
+
+ if (ftSetSelected) {
+
+ regionDescriptor = &SELECTED_REGION(0);
+ regionData = (PPERSISTENT_REGION_DATA)(PERSISTENT_DATA(regionDescriptor));
+
+ // RDR - should locate member zero of the set since it
+ // may not be committed yet.
+
+ if (regionData) {
+ if (regionData->VolumeExists) {
+ if ((regionData->DriveLetter != NO_DRIVE_LETTER_YET) && (regionData->DriveLetter != NO_DRIVE_LETTER_EVER)) {
+
+ // Now check for special cases on FT sets
+
+ ftObject = regionData->FtObject;
+ if (ftObject) {
+ ftSet = ftObject->Set;
+ if (ftSet) {
+ FT_SET_STATUS setState = ftSet->Status;
+ ULONG numberOfMembers;
+
+ LowFtVolumeStatus(regionDescriptor->Disk,
+ regionDescriptor->PartitionNumber,
+ &setState,
+ &numberOfMembers);
+
+ if ((ftSet->Status != FtSetDisabled) &&
+ (setState != FtSetDisabled)) {
+ allowFormat = TRUE;
+ }
+ }
+ }
+ }
+
+ if (regionData->TypeName) {
+ typeName = regionData->TypeName;
+ } else {
+
+ typeName = NULL;
+ DetermineRegionInfo(regionDescriptor,
+ &typeName,
+ &volumeLabel,
+ &driveLetter);
+ if (!typeName) {
+
+ if (SelectionCount > 1) {
+
+ // it is an FT set - try the next member.
+
+ regionDescriptor = &SELECTED_REGION(1);
+ DetermineRegionInfo(regionDescriptor,
+ &typeName,
+ &volumeLabel,
+ &driveLetter);
+ regionDescriptor = &SELECTED_REGION(0);
+ }
+ }
+
+ }
+
+ if (typeName) {
+ if ((wcscmp(typeName, L"NTFS") == 0) ||
+ (wcscmp(typeName, L"HPFS") == 0) ||
+ (wcscmp(typeName, L"FAT") == 0)) {
+
+ allowLabel = allowFormat;
+ }
+ }
+ }
+ }
+
+ // Allow the correct type of ft-related delete.
+
+ switch (type) {
+
+ case Mirror:
+ allowBreakMirror = TRUE;
+ allowDelete = TRUE;
+ break;
+ case StripeWithParity:
+
+ if ((SelectionCount == ftSet->NumberOfMembers) &&
+ (ftSet->Status == FtSetRecoverable)) {
+ allowRecoverParity = TRUE;
+ }
+ allowDelete = TRUE;
+ break;
+ case Stripe:
+ case VolumeSet:
+ allowDelete = TRUE;
+ break;
+ default:
+ FDASSERT(FALSE);
+ }
+
+ FtSelectionType = type;
+
+ if (type == StripeWithParity) {
+
+ // If the set is disabled. Do not allow drive
+ // letter changes - This is done because there are
+ // conditions whereby the drive letter code will
+ // access violate if this is done.
+
+ if (ftSet->Status != FtSetDisabled) {
+
+ // Must have either member 0 or member 1 for access
+
+ for (ftObject = ftSet->Members; ftObject; ftObject = ftObject->Next) {
+ if ((ftObject->MemberIndex == 0) ||
+ (ftObject->MemberIndex == 1)) {
+ allowDriveLetter = TRUE;
+ break;
+ }
+ }
+
+ // if the drive letter cannot be done, then no live
+ // action can be done.
+
+ if (!allowDriveLetter) {
+
+ ftSet->Status = FtSetDisabled;
+ allowFormat = FALSE;
+ allowLabel = FALSE;
+ }
+ }
+ } else {
+ allowDriveLetter = TRUE;
+ }
+
+ } else {
+
+ // Next figure out whether some sort of ft object set could
+ // be created out of the selected regions.
+
+ if (SelectionCount <= MaxMembersInFtSet) {
+
+ // Determine whether the selected regions are all on
+ // different disks.
+
+ onDifferentDisks = TRUE;
+ for (i=0; i<DiskCount; i++) {
+ if (diskSeenCounts[i] > 1) {
+ onDifferentDisks = FALSE;
+ break;
+ }
+ }
+
+ // Check for allowing mirror creation. User must have selected
+ // two regions -- one a recognized partition, the other a free space.
+
+ if (onDifferentDisks && (SelectionCount == 2)
+ &&((SELECTED_REGION(0).SysID == SYSID_UNUSED) != (SELECTED_REGION(1).SysID == SYSID_UNUSED))
+ &&( IsRecognizedPartition(SELECTED_REGION(0).SysID) ||
+ IsRecognizedPartition(SELECTED_REGION(1).SysID))
+ &&!GET_FT_OBJECT(&(SELECTED_REGION(0)))
+ &&!GET_FT_OBJECT(&(SELECTED_REGION(1))))
+ {
+ allowCreateMirror = TRUE;
+ }
+
+ // Check for allowing volume set or stripe set
+
+ if (selectedFreeSpaces == SelectionCount) {
+ allowCreateVolumeSet = TRUE;
+ if (onDifferentDisks) {
+ allowCreateStripe = TRUE;
+ if (selectedFreeSpaces > 2) {
+ allowCreatePStripe = TRUE;
+ }
+ }
+ }
+
+ // Check for allowing volume set expansion. If
+ // the selected regions consist of one volume set
+ // and free space, then that volume set can be
+ // extended. If the selection consists of one
+ // recognized non-FT partition and free space,
+ // then we can convert those regions into a
+ // volume set.
+
+ if (volumeSetAndFreeSpaceSelected ||
+ (SelectionCount > 1 &&
+ selectedFreeSpaces == SelectionCount - 1 &&
+ selectedNonFtPartitions == 1) ) {
+
+ allowExtendVolumeSet = TRUE;
+ }
+
+ // Check for allowing non-in-place FT recover
+
+ if ((SelectionCount > 1)
+ && (selectedFreeSpaces == 1)
+ && possibleRecover
+ && (type == StripeWithParity)
+ && (ftSet->Status == FtSetRecoverable)) {
+ BOOL OrphanOnSameDiskAsFreeSpace = FALSE;
+
+ if (!onDifferentDisks) {
+
+ // Determine whether the orphan is on the same
+ // disk as the free space. First find the orphan.
+
+ for (i=0; i<SelectionCount; i++) {
+
+ PREGION_DESCRIPTOR reg = &SELECTED_REGION(i);
+
+ if ((i != freeSpaceIndex)
+ && (GET_FT_OBJECT(reg)->State == Orphaned))
+ {
+ if (SELECTED_REGION(freeSpaceIndex).Disk == reg->Disk) {
+ OrphanOnSameDiskAsFreeSpace = TRUE;
+ }
+ break;
+ }
+ }
+ }
+
+ if (onDifferentDisks || OrphanOnSameDiskAsFreeSpace) {
+ allowRecoverParity = TRUE;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ EnableMenuItem(hMenu,
+ IDM_PARTITIONCREATE,
+ allowCreate ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem(hMenu,
+ IDM_PARTITIONCREATEEX,
+ allowCreateEx ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem(hMenu,
+ IDM_PARTITIONDELETE,
+ allowDelete ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem(hMenu,
+ IDM_PARTITIONFORMAT,
+ allowFormat ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem(hMenu,
+ IDM_PARTITIONLABEL,
+ allowLabel ? MF_ENABLED : MF_GRAYED);
+
+#ifdef DOUBLE_SPACE_SUPPORT_INCLUDED
+ EnableMenuItem(hMenu,
+ IDM_DBLSPACE,
+ (allowDblSpace & DoubleSpaceSupported) ? MF_ENABLED : MF_GRAYED);
+
+ if (DoubleSpaceAutomount = DiskRegistryAutomountCurrentState()) {
+ CheckMenuItem(hMenu, IDM_AUTOMOUNT, MF_BYCOMMAND | MF_CHECKED);
+ }
+
+ EnableMenuItem(hMenu,
+ IDM_AUTOMOUNT,
+ MF_ENABLED);
+#endif
+ EnableMenuItem(hMenu,
+ IDM_CDROM,
+ AllowCdRom ? MF_ENABLED : MF_GRAYED);
+#if i386
+ SetUpMenui386(hMenu,SelectionCount);
+#else
+ EnableMenuItem(hMenu,
+ IDM_SECURESYSTEM,
+ MF_ENABLED);
+
+ CheckMenuItem(hMenu,
+ IDM_SECURESYSTEM,
+ SystemPartitionIsSecure ? MF_CHECKED : MF_UNCHECKED);
+
+#endif
+
+ EnableMenuItem(hMenu,
+ IDM_FTBREAKMIRROR,
+ allowBreakMirror ? MF_ENABLED : MF_GRAYED);
+ EnableMenuItem(hMenu,
+ IDM_FTESTABLISHMIRROR,
+ IsLanmanNt &&
+ allowCreateMirror ? MF_ENABLED : MF_GRAYED);
+ EnableMenuItem(hMenu,
+ IDM_FTCREATESTRIPE,
+ allowCreateStripe ? MF_ENABLED : MF_GRAYED);
+ EnableMenuItem(hMenu,
+ IDM_FTCREATEPSTRIPE,
+ allowCreatePStripe ? MF_ENABLED : MF_GRAYED);
+ EnableMenuItem(hMenu,
+ IDM_FTCREATEVOLUMESET,
+ allowCreateVolumeSet ? MF_ENABLED : MF_GRAYED);
+ EnableMenuItem(hMenu,
+ IDM_FTEXTENDVOLUMESET,
+ allowExtendVolumeSet ? MF_ENABLED : MF_GRAYED);
+ EnableMenuItem(hMenu,
+ IDM_PARTITIONLETTER,
+ allowDriveLetter ? MF_ENABLED : MF_GRAYED);
+ EnableMenuItem(hMenu,
+ IDM_FTRECOVERSTRIPE,
+ IsLanmanNt &&
+ allowRecoverParity ? MF_ENABLED : MF_GRAYED);
+
+ // If the registry has change allow commit.
+
+ if (RegistryChanged) {
+ allowCommit = TRUE;
+ }
+ EnableMenuItem(hMenu,
+ IDM_COMMIT,
+ allowCommit ? MF_ENABLED : MF_GRAYED);
+ return SelectionCount;
+}
+
+VOID
+CompleteSingleRegionOperation(
+ IN PDISKSTATE DiskState
+ )
+
+/*++
+
+Routine Description:
+
+ Redraw the disk bar for the DiskState given and cause the
+ display to refresh.
+
+Arguments:
+
+ DiskState - the disk involved.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ RECT rc;
+ signed displayOffset;
+
+ EnableMenuItem(GetMenu(hwndFrame), IDM_CONFIGSAVE, MF_GRAYED);
+ DeterminePartitioningState(DiskState);
+ DrawDiskBar(DiskState);
+ SetUpMenu(&SingleSel, &SingleSelIndex);
+
+ // BUGBUG use of disk# as offset in listbox
+
+ displayOffset = (signed)DiskState->Disk
+ - (signed)SendMessage(hwndList, LB_GETTOPINDEX, 0, 0);
+
+ if (displayOffset > 0) { // otherwise it's not visible
+
+ // make a thin rectangle to force update
+
+ rc.left = BarLeftX + 5;
+ rc.right = rc.left + 5;
+ rc.top = (displayOffset * GraphHeight) + BarTopYOffset;
+ rc.bottom = rc.top + 5;
+ InvalidateRect(hwndList, &rc, FALSE);
+ }
+
+ ClearStatusArea();
+ ResetLBCursorRegion();
+ ForceLBRedraw();
+}
+
+VOID
+TotalRedrawAndRepaint(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Invalidate the display and cause all disk bars to be redrawn.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ unsigned i;
+
+ for (i=0; i<DiskCount; i++) {
+ DrawDiskBar(Disks[i]);
+ }
+ ForceLBRedraw();
+}
+
+
+VOID
+CompleteMultiRegionOperation(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will cause the display to be updated
+ after a multi-region action has been completed.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ unsigned i;
+
+ EnableMenuItem(GetMenu(hwndFrame), IDM_CONFIGSAVE, MF_GRAYED);
+
+ for (i=0; i<DiskCount; i++) {
+ DeterminePartitioningState(Disks[i]);
+ }
+
+ TotalRedrawAndRepaint();
+ SetUpMenu(&SingleSel, &SingleSelIndex);
+ ClearStatusArea();
+ ResetLBCursorRegion();
+}
+
+PPERSISTENT_REGION_DATA
+DmAllocatePersistentData(
+ IN PWSTR VolumeLabel,
+ IN PWSTR TypeName,
+ IN CHAR DriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ Allocate a structure to hold persistent region data. Fill in the volume
+ label, type name, and drive letter. The volume label and type name are
+ duplicated.
+
+Arguments:
+
+ VolumeLabel - volume label to be stored in the the persistent data.
+ The string will be duplicated first and a pointer to the duplicate
+ copy is what is stored in the persistent data. May be NULL.
+
+ TypeName - name of type of region, ie unformatted, FAT, etc. May be NULL.
+
+ DriveLetter - drive letter to be stored in persistent data
+
+Return Value:
+
+ pointer to newly allocated persistent data structure. The structure
+ may be freed via DmFreePersistentData(), below.
+
+--*/
+
+{
+ PPERSISTENT_REGION_DATA regionData = NULL;
+ PWSTR volumeLabel = NULL,
+ typeName = NULL;
+
+ if (VolumeLabel) {
+ volumeLabel = Malloc((lstrlenW(VolumeLabel)+1)*sizeof(WCHAR));
+ lstrcpyW(volumeLabel,VolumeLabel);
+ }
+
+ if (TypeName) {
+ typeName = Malloc((lstrlenW(TypeName)+1)*sizeof(WCHAR));
+ lstrcpyW(typeName,TypeName);
+ }
+
+ regionData = Malloc(sizeof(PERSISTENT_REGION_DATA));
+ DmInitPersistentRegionData(regionData, NULL, volumeLabel, typeName, DriveLetter);
+ return regionData;
+}
+
+VOID
+DmFreePersistentData(
+ IN OUT PPERSISTENT_REGION_DATA RegionData
+ )
+
+/*++
+
+Routine Description:
+
+ Free a persistent data structure and storage used for volume label
+ and type name (does not free ft objects).
+
+Arguments:
+
+ RegionData - structure to be freed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if (RegionData->VolumeLabel) {
+ Free(RegionData->VolumeLabel);
+ }
+ if (RegionData->TypeName) {
+ Free(RegionData->TypeName);
+ }
+ Free(RegionData);
+}
+
+VOID
+DoCreate(
+ IN DWORD CreationType // REGION_EXTENDED or REGION_PRIMARY
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a new partition.
+
+Arguments:
+
+ CreationType - indicator of partition type (extended or primary).
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PREGION_DESCRIPTOR regionDescriptor = &SingleSel->RegionArray[SingleSelIndex];
+ ULONG diskNumber = regionDescriptor->Disk;
+ MINMAXDLG_PARAMS dlgParams;
+ DWORD creationSize;
+ DWORD ec;
+ PPERSISTENT_REGION_DATA regionData;
+ BOOLEAN isRemovable;
+ CHAR driveLetter;
+
+
+ FDASSERT(SingleSel);
+ FDASSERT(regionDescriptor->SysID == SYSID_UNUSED);
+
+ // WinDisk can only create a single partition on a removable
+ // disk--no extended partitions and only one primary.
+
+ isRemovable = IsDiskRemovable[diskNumber];
+
+ if (isRemovable) {
+
+ if (CreationType == REGION_EXTENDED) {
+
+ ErrorDialog(MSG_NO_EXTENDED_ON_REMOVABLE);
+ return;
+ }
+
+ if (Disks[diskNumber]->ExistAny) {
+
+ ErrorDialog(MSG_ONLY_ONE_PARTITION_ON_REMOVABLE);
+ return;
+ }
+ }
+
+ // Make sure the partition table is not full, and that we are allowed to
+ // create the type of partition to be created.
+
+ if (regionDescriptor->RegionType == REGION_PRIMARY) {
+
+ if (!SingleSel->CreatePrimary) {
+ ErrorDialog(MSG_PART_TABLE_FULL);
+ return;
+ }
+
+ if ((CreationType == REGION_EXTENDED) && !SingleSel->CreateExtended) {
+ ErrorDialog(MSG_EXTENDED_ALREADY_EXISTS);
+ return;
+ }
+ }
+
+ // If not creating an extended partition, allocate a drive letter.
+ // If no drive letter is available, warn the user and allow him to cancel.
+ // If the new partition is on a removable disk, use the reserved
+ // drive letter for that removable disk.
+
+ if (CreationType != REGION_EXTENDED) {
+
+ CreationType = regionDescriptor->RegionType; // primary or logical
+
+ if (isRemovable) {
+
+ driveLetter = RemovableDiskReservedDriveLetters[diskNumber];
+
+ } else {
+
+ if (!AssignDriveLetter(TRUE, CreationType == REGION_LOGICAL ? IDS_LOGICALVOLUME : IDS_PARTITION, &driveLetter)) {
+ return;
+ }
+ }
+ } else {
+ CommitDueToExtended = TRUE;
+ }
+
+#if i386
+ // if the user is creating a primary partition and there are already
+ // primary partitions, warn him that the scheme he will create may
+ // not be DOS compatible.
+
+ if ((CreationType == REGION_PRIMARY) && SingleSel->ExistPrimary) {
+
+ if (ConfirmationDialog(MSG_CREATE_NOT_COMPAT, MB_ICONQUESTION | MB_YESNO) != IDYES) {
+ return;
+ }
+ }
+#endif
+
+ // now get the size.
+
+ dlgParams.MinSizeMB = FdGetMinimumSizeMB(diskNumber);
+ dlgParams.MaxSizeMB = FdGetMaximumSizeMB(regionDescriptor, CreationType);
+
+ switch (CreationType) {
+ case REGION_PRIMARY:
+ dlgParams.CaptionStringID = IDS_CRTPART_CAPTION_P;
+ dlgParams.MinimumStringID = IDS_CRTPART_MIN_P;
+ dlgParams.MaximumStringID = IDS_CRTPART_MAX_P;
+ dlgParams.SizeStringID = IDS_CRTPART_SIZE_P;
+ dlgParams.HelpContextId = HC_DM_DLG_CREATEPRIMARY;
+ break;
+
+ case REGION_EXTENDED:
+ dlgParams.CaptionStringID = IDS_CRTPART_CAPTION_E;
+ dlgParams.MinimumStringID = IDS_CRTPART_MIN_P;
+ dlgParams.MaximumStringID = IDS_CRTPART_MAX_P;
+ dlgParams.SizeStringID = IDS_CRTPART_SIZE_P;
+ dlgParams.HelpContextId = HC_DM_DLG_CREATEEXTENDED;
+ break;
+
+ case REGION_LOGICAL:
+ dlgParams.CaptionStringID = IDS_CRTPART_CAPTION_L;
+ dlgParams.MinimumStringID = IDS_CRTPART_MIN_L;
+ dlgParams.MaximumStringID = IDS_CRTPART_MAX_L;
+ dlgParams.SizeStringID = IDS_CRTPART_SIZE_L;
+ dlgParams.HelpContextId = HC_DM_DLG_CREATELOGICAL;
+ break;
+
+ default:
+ FDASSERT(FALSE);
+ }
+
+ creationSize = DialogBoxParam(hModule,
+ MAKEINTRESOURCE(IDD_MINMAX),
+ hwndFrame,
+ (DLGPROC)MinMaxDlgProc,
+ (LONG)&dlgParams);
+
+ if (!creationSize) { // user cancelled
+ return;
+ }
+
+ // Since the WinDisk can only create one partition on a removable
+ // disk, if the user requests a size smaller than the maximum
+ // on a removable disk, prompt to confirm:
+
+ if (isRemovable && creationSize != FdGetMaximumSizeMB(regionDescriptor, CreationType)) {
+
+ if (ConfirmationDialog(MSG_REMOVABLE_PARTITION_NOT_FULL_SIZE,MB_ICONQUESTION | MB_YESNO) != IDYES) {
+ return;
+ }
+ }
+
+#if i386
+
+ // See whether the partition will cross over the 1024 cylinder boundary
+ // and warn the user if it will.
+ //
+ // If the extended partition crosses the boundary and the user is creating
+ // a logical drive, warn him even though the logical drive itself may not
+ // cross the boundary -- he still won't be able to access it.
+
+ {
+ DWORD i,
+ msgId = (DWORD)(-1);
+
+ if (CreationType == REGION_LOGICAL) {
+
+ PREGION_DESCRIPTOR extReg;
+
+ //
+ // Find the extended partition
+ //
+
+ for (i=0; i<Disks[diskNumber]->RegionCount; i++) {
+
+ extReg = &Disks[diskNumber]->RegionArray[i];
+
+ if (IsExtended(extReg->SysID)) {
+ break;
+ }
+ extReg = NULL;
+ }
+
+ FDASSERT(extReg);
+ if (extReg && FdCrosses1024Cylinder(extReg, 0, REGION_LOGICAL)) {
+ msgId = MSG_LOG_1024_CYL;
+ }
+
+ } else {
+ if (FdCrosses1024Cylinder(regionDescriptor, creationSize, CreationType)) {
+ msgId = (CreationType == REGION_PRIMARY) ? MSG_PRI_1024_CYL : MSG_EXT_1024_CYL;
+ }
+ }
+
+ if ((msgId != (ULONG)(-1)) && (ConfirmationDialog(msgId, MB_ICONQUESTION | MB_YESNO) != IDYES)) {
+ return;
+ }
+ }
+
+#endif
+
+ // If not creating an extended partition, we need to create a new
+ // persistent region data structure to associate with the new
+ // partition.
+
+ if (CreationType == REGION_EXTENDED) {
+ regionData = NULL;
+ } else {
+ regionData = DmAllocatePersistentData(L"", wszNewUnformatted, driveLetter);
+ }
+
+ SetCursor(hcurWait);
+
+ ec = CreatePartition(regionDescriptor,
+ creationSize,
+ CreationType);
+ if (ec != NO_ERROR) {
+ SetCursor(hcurNormal);
+ ErrorDialog(ec);
+ }
+
+ DmSetPersistentRegionData(regionDescriptor, regionData);
+ if (CreationType != REGION_EXTENDED) {
+ if (!isRemovable) {
+ MarkDriveLetterUsed(driveLetter);
+ CommitToAssignLetterList(regionDescriptor, FALSE);
+ }
+ }
+
+ // this clears all selections on the disk
+
+ CompleteSingleRegionOperation(SingleSel);
+ SetCursor(hcurNormal);
+}
+
+VOID
+DoDelete(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Using the global selection information, delete the partition.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PREGION_DESCRIPTOR regionDescriptor = &SingleSel->RegionArray[SingleSelIndex];
+ ULONG diskNumber = regionDescriptor->Disk;
+ DWORD actualIndex = SingleSelIndex;
+ DWORD i,
+ ec;
+ PPERSISTENT_REGION_DATA regionData;
+ BOOL deletingExtended;
+
+ FDASSERT(SingleSel);
+
+ // if deleting a free space in the extended partition, then delete the
+ // extended partition itself.
+
+ if ((regionDescriptor->RegionType == REGION_LOGICAL) && !SingleSel->ExistLogical) {
+
+ FDASSERT(SingleSel->ExistExtended);
+
+ // find the extended partition
+
+ for (i=0; i<SingleSel->RegionCount; i++) {
+ if (IsExtended(SingleSel->RegionArray[i].SysID)) {
+ actualIndex = i;
+ break;
+ }
+ }
+
+ deletingExtended = TRUE;
+ FDASSERT(actualIndex != SingleSelIndex);
+
+ } else {
+
+ deletingExtended = FALSE;
+
+ // Make sure deletion of this partition is allowed. It is not allowed
+ // if it is the boot partition (or sys partition on x86).
+
+ if ((ec = DeletionIsAllowed(&SingleSel->RegionArray[actualIndex])) != NO_ERROR) {
+ ErrorDialog(ec);
+ return;
+ }
+ }
+
+ // If this is a partition that will become the result of a
+ // mirror break, insure that the break has occurred. Otherwise
+ // this delete will have bad results.
+
+ regionDescriptor = &SingleSel->RegionArray[actualIndex];
+ if (regionDescriptor->Reserved) {
+ if (regionDescriptor->Reserved->Partition) {
+ if (regionDescriptor->Reserved->Partition->CommitMirrorBreakNeeded) {
+ ErrorDialog(MSG_MUST_COMMIT_BREAK);
+ return;
+ }
+ }
+ }
+
+ if (!deletingExtended && (ConfirmationDialog(MSG_CONFIRM_DELETE, MB_ICONQUESTION | MB_YESNO) != IDYES)) {
+ return;
+ }
+
+ // actualIndex is the thing to delete.
+
+ FDASSERT(regionDescriptor->SysID != SYSID_UNUSED);
+ regionData = PERSISTENT_DATA(regionDescriptor);
+
+ if (regionData) {
+
+ // Remember drive letter if there is one in order to lock it for delete.
+
+ if (CommitToLockList(regionDescriptor, !IsDiskRemovable[diskNumber], TRUE, FALSE)) {
+
+ // Could not lock exclusively - do not allow delete.
+
+ if (IsPagefileOnDrive(regionData->DriveLetter)) {
+ ErrorDialog(MSG_CANNOT_LOCK_PAGEFILE);
+ return;
+ } else {
+ if (CommitToLockList(regionDescriptor, !IsDiskRemovable[diskNumber], TRUE, FALSE)) {
+ FDLOG((1,"DoDelete: Couldn't lock 2 times - popup shown\n"));
+ ErrorDialog(MSG_CANNOT_LOCK_TRY_AGAIN);
+ return;
+ }
+ }
+ }
+ } else {
+
+ // Deleting an extended partition - enable commit.
+
+ CommitDueToDelete = TRUE;
+ }
+
+ SetCursor(hcurWait);
+
+ // Perform the "delete" of internal structures.
+
+ ec = DeletePartition(regionDescriptor);
+
+ if (ec != NO_ERROR) {
+ SetCursor(hcurNormal);
+ ErrorDialog(ec);
+ }
+
+ if (regionData) {
+
+ // Make the letter available for reuse.
+
+ if (!IsDiskRemovable[diskNumber]) {
+ MarkDriveLetterFree(regionData->DriveLetter);
+ }
+
+ // Free the persistent data associated with the region.
+
+ DmFreePersistentData(regionData);
+ DmSetPersistentRegionData(regionDescriptor,NULL);
+ }
+
+ // this clears all selections on the disk
+
+ CompleteSingleRegionOperation(SingleSel);
+ SetCursor(hcurNormal);
+}
+
+#if i386
+VOID
+DoMakeActive(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets that active partition bit on for the selected partition.
+ This code is x86 specific.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ SetCursor(hcurWait);
+
+ FDASSERT(SingleSel);
+ FDASSERT(!SingleSel->RegionArray[SingleSelIndex].Active);
+ FDASSERT(SingleSel->RegionArray[SingleSelIndex].RegionType == REGION_PRIMARY);
+ FDASSERT(SingleSel->RegionArray[SingleSelIndex].SysID != SYSID_UNUSED);
+
+ MakePartitionActive(SingleSel->RegionArray,
+ SingleSel->RegionCount,
+ SingleSelIndex);
+
+ SetCursor(hcurNormal);
+ InfoDialog(MSG_DISK0_ACTIVE);
+ SetCursor(hcurWait);
+ CompleteSingleRegionOperation(SingleSel);
+ SetCursor(hcurNormal);
+}
+#endif
+
+VOID
+DoProtectSystemPartition(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function toggles the state of the system partition security:
+ if the system partition is secure, it makes it non-secure; if the
+ system partition is not secure, it makes it secure.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ LONG ec;
+ HKEY hkey;
+ DWORD value;
+ DWORD MessageId;
+
+ SetCursor(hcurWait);
+ MessageId = SystemPartitionIsSecure ? MSG_CONFIRM_UNPROTECT_SYSTEM :
+ MSG_CONFIRM_PROTECT_SYSTEM;
+
+ if (ConfirmationDialog(MessageId, MB_ICONEXCLAMATION | MB_YESNO) != IDYES) {
+ return;
+ }
+
+ ec = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("System\\CurrentControlSet\\Control\\Lsa"),
+ 0,
+ KEY_SET_VALUE,
+ &hkey);
+
+ if (ec != ERROR_SUCCESS) {
+
+ MessageId = SystemPartitionIsSecure ? MSG_CANT_UNPROTECT_SYSTEM :
+ MSG_CANT_PROTECT_SYSTEM;
+ ErrorDialog(MessageId);
+ return;
+ }
+
+ // If the system partition is currently secure, change it
+ // to not secure; if it is not secure, make it secure.
+
+ value = SystemPartitionIsSecure ? 0 : 1;
+
+ ec = RegSetValueEx(hkey,
+ TEXT("Protect System Partition"),
+ 0,
+ REG_DWORD,
+ (PBYTE)&value,
+ sizeof(DWORD));
+ RegCloseKey(hkey);
+
+ if (ec != ERROR_SUCCESS) {
+
+ MessageId = SystemPartitionIsSecure ? MSG_CANT_UNPROTECT_SYSTEM :
+ MSG_CANT_PROTECT_SYSTEM;
+ ErrorDialog(MessageId);
+ return;
+ }
+
+ SystemPartitionIsSecure = !SystemPartitionIsSecure;
+
+ SetUpMenu(&SingleSel,&SingleSelIndex);
+ RestartRequired = TRUE;
+ SetCursor(hcurNormal);
+}
+
+
+VOID
+DoEstablishMirror(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Using the global selection values, this routine will associate
+ freespace with an existing partition in order to construct a
+ mirror.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ LARGE_INTEGER partitionSize,
+ freeSpaceSize;
+ DWORD i,
+ part,
+ free = 0;
+ PREGION_DESCRIPTOR regionDescriptor,
+ freeSpace = NULL,
+ existingPartition = NULL;
+ PREGION_DESCRIPTOR regionArray[MaxMembersInFtSet];
+ UCHAR newSysID;
+ PPERSISTENT_REGION_DATA regionData;
+ HMENU hMenu = GetMenu(hwndFrame);
+
+ FDASSERT(SelectionCount == 2);
+
+ // Make sure that the mirror pair does not include any
+ // partitions on removable media.
+
+ for (i=0; i<SelectionCount; i++) {
+
+ if (IsDiskRemovable[SELECTED_REGION(i).Disk]) {
+
+ ErrorDialog(MSG_NO_REMOVABLE_IN_MIRROR);
+ return;
+ }
+ }
+
+ for (i=0; i<2; i++) {
+ regionDescriptor = &SELECTED_REGION(i);
+ if (regionDescriptor->SysID == SYSID_UNUSED) {
+ free = i;
+ freeSpace = regionDescriptor;
+ } else {
+ part = i;
+ existingPartition = regionDescriptor;
+ }
+ }
+
+ FDASSERT((freeSpace != NULL) && (existingPartition != NULL));
+
+ // Make sure that we are allowed to create a partition in the free space.
+
+ if (!( ((freeSpace->RegionType == REGION_LOGICAL) && SelectedDS[free]->CreateLogical)
+ || ((freeSpace->RegionType == REGION_PRIMARY) && SelectedDS[free]->CreatePrimary))) {
+ ErrorDialog(MSG_CRTSTRP_FULL);
+ return;
+ }
+
+ // Make sure that the free space is large enough to hold a mirror of
+ // the existing partition. Do this by getting the EXACT size of
+ // the existing partition and the free space.
+
+ partitionSize = FdGetExactSize(existingPartition, FALSE);
+ freeSpaceSize = FdGetExactSize(freeSpace, FALSE);
+
+ if (freeSpaceSize.QuadPart < partitionSize.QuadPart) {
+ ErrorDialog(MSG_CRTMIRROR_BADFREE);
+ return;
+ }
+
+ if (BootDiskNumber != (ULONG)-1) {
+
+ // If the disk number and original partition number of this
+ // region match the recorded disk number and partition number
+ // of the boot partition warn the user about mirroring the boot
+ // drive.
+
+ if (existingPartition->Disk == BootDiskNumber &&
+ existingPartition->OriginalPartitionNumber == BootPartitionNumber) {
+
+ WarningDialog(MSG_MIRROR_OF_BOOT);
+
+ // Set up to write the boot code to the MBR of the mirror.
+
+ UpdateMbrOnDisk = freeSpace->Disk;
+ }
+ }
+
+ SetCursor(hcurWait);
+ regionData = DmAllocatePersistentData(PERSISTENT_DATA(existingPartition)->VolumeLabel,
+ PERSISTENT_DATA(existingPartition)->TypeName,
+ PERSISTENT_DATA(existingPartition)->DriveLetter);
+
+ // Finally, create the new partition.
+
+ newSysID = (UCHAR)(existingPartition->SysID | (UCHAR)SYSID_FT);
+ CreatePartitionEx(freeSpace,
+ partitionSize,
+ 0,
+ freeSpace->RegionType,
+ newSysID);
+ DmSetPersistentRegionData(freeSpace, regionData);
+
+ // Set the partition type of the existing partition.
+
+ SetSysID2(existingPartition, newSysID);
+ regionArray[0] = existingPartition;
+ regionArray[1] = freeSpace;
+
+ FdftCreateFtObjectSet(Mirror,
+ regionArray,
+ 2,
+ FtSetNewNeedsInitialization);
+
+ CompleteMultiRegionOperation();
+ SetCursor(hcurNormal);
+ CommitDueToMirror = TRUE;
+ EnableMenuItem(hMenu,
+ IDM_COMMIT,
+ MF_ENABLED);
+}
+
+VOID
+DoBreakMirror(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Using the global selection variables, this routine will break
+ the mirror relationship and modify their region descriptors to
+ describe two non-ft partitions giving either the primary member
+ of the mirror the drive letter for the mirror, or the only healthy
+ member of the mirror the drive letter. The remaining "new" partition
+ will receive the next available drive letter.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ DWORD i;
+ PFT_OBJECT_SET ftSet;
+ PFT_OBJECT ftObject0,
+ ftObject1;
+ PREGION_DESCRIPTOR regionDescriptor;
+ PPERSISTENT_REGION_DATA regionData;
+ ULONG newDriveLetterRegion;
+ CHAR driveLetter;
+ HMENU hMenu = GetMenu(hwndFrame);
+
+ FDASSERT((SelectionCount) == 1 || (SelectionCount == 2));
+
+ ftObject0 = GET_FT_OBJECT(&SELECTED_REGION(0));
+ if (SelectionCount == 2) {
+ ftObject1 = GET_FT_OBJECT(&SELECTED_REGION(1));
+ } else {
+ ftObject1 = NULL;
+ }
+ ftSet = ftObject0->Set;
+
+ // Determine if the action is allowed.
+
+ switch (ftSet->Status) {
+
+ case FtSetInitializing:
+ case FtSetRegenerating:
+
+ ErrorDialog(MSG_CANT_BREAK_INITIALIZING_SET);
+ return;
+ break;
+
+ default:
+ break;
+ }
+
+ if (ConfirmationDialog(MSG_CONFIRM_BRK_MIRROR,MB_ICONQUESTION | MB_YESNO) != IDYES) {
+ return;
+ }
+
+ SetCursor(hcurWait);
+
+ // Figure out which region gets the new drive letter. A complication is
+ // that selection 0 is not necessarily member 0.
+ //
+ // If there is only one selection, then only one part of the mirror set
+ // is present -- no new drive letters are assigned.
+ // Otherwise, if one of the members is orphaned, it gets the new
+ // drive letter. Else the secondary member gets the new drive letter.
+
+ if (SelectionCount == 2) {
+
+ if (ftObject0->State == Orphaned) {
+
+ newDriveLetterRegion = 0;
+ } else {
+
+ if (ftObject1->State == Orphaned) {
+
+ newDriveLetterRegion = 1;
+ } else {
+
+ // Neither member is orphaned; determine which is
+ // member 0 and give the other one the new drive letter.
+
+ if (ftObject0->MemberIndex) { // secondary member ?
+
+ newDriveLetterRegion = 0;
+ } else {
+
+ newDriveLetterRegion = 1;
+ }
+ }
+ }
+ } else {
+
+ // The one remaining member could be the shadow.
+ // The drive letter must move to locate this partition
+
+ regionDescriptor = &SELECTED_REGION(0);
+ regionData = PERSISTENT_DATA(regionDescriptor);
+ if (!regionData->FtObject->MemberIndex) {
+
+ // The shadow has become the valid partition.
+ // move the current letter there.
+
+ CommitToAssignLetterList(regionDescriptor, TRUE);
+ }
+ newDriveLetterRegion = (ULONG)(-1);
+ }
+
+ // if newDriveLetterRegion is -1 this will still work and
+ // select the 0 selected region.
+
+ if (CommitToLockList(&SELECTED_REGION(newDriveLetterRegion ? 0 : 1), FALSE, TRUE, FALSE)) {
+ if (ConfirmationDialog(MSG_CONFIRM_SHUTDOWN_FOR_MIRROR, MB_ICONQUESTION | MB_YESNO) != IDYES) {
+ return;
+ }
+ RestartRequired = TRUE;
+ }
+
+ if (newDriveLetterRegion != (ULONG)(-1)) {
+ if (AssignDriveLetter(FALSE, 0, &driveLetter)) {
+
+ // Got a valid drive letter
+
+ MarkDriveLetterUsed(driveLetter);
+ } else {
+
+ // didn't get a letter. Instead the magic value
+ // for no drive letter assigned has been returned
+
+ }
+
+ regionDescriptor = &SELECTED_REGION(newDriveLetterRegion);
+ regionData = PERSISTENT_DATA(regionDescriptor);
+ regionData->DriveLetter = driveLetter;
+ CommitToAssignLetterList(regionDescriptor, FALSE);
+ if (!regionData->FtObject->MemberIndex) {
+
+ // The shadow has become the valid partition.
+ // move the current letter there.
+
+ CommitToAssignLetterList(&SELECTED_REGION(newDriveLetterRegion ? 0 : 1), TRUE);
+ }
+
+ } else {
+ regionDescriptor = &SELECTED_REGION(0);
+ regionData = PERSISTENT_DATA(regionDescriptor);
+ if (regionData->FtObject->MemberIndex) {
+
+ // The shadow is all that is left.
+
+ CommitToAssignLetterList(regionDescriptor, TRUE);
+ }
+ }
+
+ FdftDeleteFtObjectSet(ftSet, FALSE);
+
+ for (i=0; i<SelectionCount; i++) {
+
+ regionDescriptor = &SELECTED_REGION(i);
+ if (regionDescriptor->Reserved) {
+ if (regionDescriptor->Reserved->Partition) {
+ regionDescriptor->Reserved->Partition->CommitMirrorBreakNeeded = TRUE;
+ }
+ }
+ SET_FT_OBJECT(regionDescriptor, 0);
+ SetSysID2(regionDescriptor, (UCHAR)(regionDescriptor->SysID & ~VALID_NTFT));
+ }
+
+ CompleteMultiRegionOperation();
+ SetCursor(hcurNormal);
+ CommitDueToMirror = TRUE;
+ EnableMenuItem(hMenu,
+ IDM_COMMIT,
+ MF_ENABLED);
+}
+
+VOID
+DoBreakAndDeleteMirror(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will delete the mirror relationship information
+ and the member partitions of the mirror.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PFT_OBJECT_SET ftSet;
+ DWORD i;
+ PREGION_DESCRIPTOR regionDescriptor;
+ CHAR driveLetter = '\0';
+
+ FDASSERT( SelectionCount == 1 || SelectionCount == 2 );
+
+ // Attempt to lock this before continuing.
+
+ regionDescriptor = &SELECTED_REGION(0);
+ if (CommitToLockList(regionDescriptor, TRUE, TRUE, FALSE)) {
+
+ // Could not lock the volume - do not allow delete.
+
+ ErrorDialog(MSG_CANNOT_LOCK_TRY_AGAIN);
+ return;
+ }
+
+ ftSet = (GET_FT_OBJECT(regionDescriptor))->Set;
+
+ // Determine if the action is allowed.
+
+ switch (ftSet->Status) {
+
+ case FtSetInitializing:
+ case FtSetRegenerating:
+
+ ErrorDialog(MSG_CANT_DELETE_INITIALIZING_SET);
+ return;
+ break;
+
+ default:
+ break;
+ }
+
+ if (ConfirmationDialog(MSG_CONFIRM_BRKANDDEL_MIRROR, MB_ICONQUESTION | MB_YESNO) != IDYES) {
+ return;
+ }
+
+ SetCursor(hcurWait);
+ FdftDeleteFtObjectSet(ftSet, FALSE);
+ for (i = 0; i < SelectionCount; i++) {
+
+ regionDescriptor = &SELECTED_REGION(i);
+
+ if (i) {
+ FDASSERT(PERSISTENT_DATA(regionDescriptor)->DriveLetter == driveLetter);
+ } else {
+ driveLetter = PERSISTENT_DATA(regionDescriptor)->DriveLetter;
+ }
+
+ // Free the pieces of the set.
+
+ DmFreePersistentData(PERSISTENT_DATA(regionDescriptor));
+ DmSetPersistentRegionData(regionDescriptor, NULL);
+ DeletePartition(regionDescriptor);
+ }
+
+ MarkDriveLetterFree(driveLetter);
+
+ // Remember drive letter if there is one in order to lock it for delete.
+
+ CompleteMultiRegionOperation();
+ SetCursor(hcurNormal);
+}
+
+VOID
+DoCreateStripe(
+ IN BOOL Parity
+ )
+
+/*++
+
+Routine Description:
+
+ This routine starts the dialog with the user to determine
+ the parameters of the creation of a stripe or stripe set
+ with parity. Based on the user response it creates the
+ internal structures necessary for the creation of a stripe
+ or stripe set with parity.
+
+ The regions involved in the stripe creation are located via
+ the global parameters for multiple selections.
+
+Arguments:
+
+ Parity - boolean to indicate the presence of parity in the stripe.
+
+Return Value
+
+ None
+
+--*/
+
+{
+ MINMAXDLG_PARAMS params;
+ DWORD smallestSize = (DWORD)(-1);
+ DWORD creationSize;
+ unsigned i;
+ PREGION_DESCRIPTOR regionDescriptor,
+ regionArray[MaxMembersInFtSet];
+ PPERSISTENT_REGION_DATA regionData;
+ CHAR DriveLetter;
+
+
+ // Make sure that the volume set does not include any
+ // partitions on removable media.
+
+ for (i=0; i<SelectionCount; i++) {
+
+ if (IsDiskRemovable[SELECTED_REGION(i).Disk]) {
+
+ ErrorDialog(MSG_NO_REMOVABLE_IN_STRIPE);
+ return;
+ }
+ }
+
+ // Scan the disks to determine the maximum size, which is
+ // the size of the smallest partition times the number of
+ // partitions.
+
+ for (i=0; i<SelectionCount; i++) {
+ FDASSERT(SELECTED_REGION(i).SysID == SYSID_UNUSED);
+ if (SELECTED_REGION(i).SizeMB < smallestSize) {
+ smallestSize = SELECTED_REGION(i).SizeMB;
+ }
+ }
+
+ // Figure out a drive letter.
+
+ if (!AssignDriveLetter(TRUE, IDS_STRIPESET, &DriveLetter)) {
+ return;
+ }
+
+ params.CaptionStringID = Parity ? IDS_CRTPSTRP_CAPTION : IDS_CRTSTRP_CAPTION;
+ params.MinimumStringID = IDS_CRTSTRP_MIN;
+ params.MaximumStringID = IDS_CRTSTRP_MAX;
+ params.SizeStringID = IDS_CRTSTRP_SIZE;
+ params.MinSizeMB = SelectionCount;
+ params.MaxSizeMB = smallestSize * SelectionCount;
+ if (Parity) {
+ params.HelpContextId = HC_DM_DLG_CREATEPARITYSTRIPE;
+ } else {
+ params.HelpContextId = HC_DM_DLG_CREATESTRIPESET;
+ }
+
+ creationSize = DialogBoxParam(hModule,
+ MAKEINTRESOURCE(IDD_MINMAX),
+ hwndFrame,
+ (DLGPROC)MinMaxDlgProc,
+ (LONG)&params);
+
+ if (!creationSize) { // user cancelled
+ return;
+ }
+
+ // Determine how large we have to make each member of the stripe set.
+
+ creationSize = (creationSize / SelectionCount);
+ FDASSERT(creationSize <= smallestSize);
+ if (creationSize % SelectionCount) {
+ creationSize++; // round up.
+ }
+
+ SetCursor(hcurWait);
+
+ // Make sure we are allowed to create all the partitions
+
+ for (i=0; i<SelectionCount; i++) {
+ regionDescriptor = &SELECTED_REGION(i);
+ FDASSERT(regionDescriptor->RegionType != REGION_EXTENDED);
+
+ if (!( ((regionDescriptor->RegionType == REGION_LOGICAL) && SelectedDS[i]->CreateLogical)
+ || ((regionDescriptor->RegionType == REGION_PRIMARY) && SelectedDS[i]->CreatePrimary))) {
+ SetCursor(hcurNormal);
+ ErrorDialog(MSG_CRTSTRP_FULL);
+ return;
+ }
+
+ }
+
+ // Now actually perform the creation.
+
+ for (i=0; i<SelectionCount; i++) {
+
+ regionDescriptor = &SELECTED_REGION(i);
+
+ CreatePartitionEx(regionDescriptor,
+ RtlConvertLongToLargeInteger(0L),
+ creationSize,
+ regionDescriptor->RegionType,
+ (UCHAR)(SYSID_BIGFAT | SYSID_FT));
+
+ // Finish setting up the FT set
+
+ regionData = DmAllocatePersistentData(L"", wszNewUnformatted, DriveLetter);
+ DmSetPersistentRegionData(regionDescriptor, regionData);
+ regionArray[i] = regionDescriptor;
+ }
+
+ // The zeroth element is the one to assign the drive letter to.
+
+ CommitToAssignLetterList(&SELECTED_REGION(0), FALSE);
+
+ FdftCreateFtObjectSet(Parity ? StripeWithParity : Stripe,
+ regionArray,
+ SelectionCount,
+ Parity ? FtSetNewNeedsInitialization : FtSetNew);
+ MarkDriveLetterUsed(DriveLetter);
+ CompleteMultiRegionOperation();
+ SetCursor(hcurNormal);
+}
+
+
+VOID
+DoDeleteStripeOrVolumeSet(
+ IN DWORD ConfirmationMsg
+ )
+
+/*++
+
+Routine Description:
+
+ Common code for the deletion of a stripe or volume set.
+ This routine will display a message giving the user a 2nd
+ chance to change their mind, then based on the answer perform
+ the work of deleting the item. This consists of removing
+ the region descriptors (and related information) from the
+ collection of Disk structures.
+
+Arguments:
+
+ ConfirmationMsg - text for comfirming what is being deleted.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ DWORD i;
+ PFT_OBJECT_SET ftSet;
+ PFT_OBJECT ftObject;
+ PREGION_DESCRIPTOR regionDescriptor;
+ FT_SET_STATUS setState;
+ ULONG numberOfMembers;
+ CHAR driveLetter = '\0';
+ BOOL setIsHealthy = TRUE;
+
+ regionDescriptor = &SELECTED_REGION(0);
+
+ // Determine if the action is allowed.
+
+ ftObject = GET_FT_OBJECT(regionDescriptor);
+ ftSet = ftObject->Set;
+
+ LowFtVolumeStatus(regionDescriptor->Disk,
+ regionDescriptor->PartitionNumber,
+ &setState,
+ &numberOfMembers);
+
+ if (ftSet->Status != setState) {
+ ftSet->Status = setState;
+ }
+
+ switch (ftSet->Status) {
+ case FtSetDisabled:
+ setIsHealthy = FALSE;
+ break;
+
+ case FtSetInitializing:
+ case FtSetRegenerating:
+
+ ErrorDialog(MSG_CANT_DELETE_INITIALIZING_SET);
+ return;
+ break;
+
+ default:
+ break;
+ }
+
+ // Attempt to lock this before continuing.
+
+ if (CommitToLockList(regionDescriptor, TRUE, setIsHealthy, TRUE)) {
+
+ // Could not lock the volume - try again, the file systems appear
+ // to be confused.
+
+ if (CommitToLockList(regionDescriptor, TRUE, setIsHealthy, TRUE)) {
+
+ // Don't allow the delete.
+
+ ErrorDialog(MSG_CANNOT_LOCK_TRY_AGAIN);
+ return;
+ }
+ }
+
+ if (ConfirmationDialog(ConfirmationMsg,MB_ICONQUESTION | MB_YESNO) != IDYES) {
+ return;
+ }
+
+ // Delete all partitions that are part of the stripe set
+
+ SetCursor(hcurWait);
+ FdftDeleteFtObjectSet(ftSet,FALSE);
+
+ for (i=0; i<SelectionCount; i++) {
+ ULONG diskNumber;
+
+ regionDescriptor = &SELECTED_REGION(i);
+
+ if (i) {
+ FDASSERT(PERSISTENT_DATA(regionDescriptor)->DriveLetter == driveLetter);
+ } else {
+ driveLetter = PERSISTENT_DATA(regionDescriptor)->DriveLetter;
+ }
+
+ diskNumber = regionDescriptor->Disk;
+ DmFreePersistentData(PERSISTENT_DATA(regionDescriptor));
+ DmSetPersistentRegionData(regionDescriptor, NULL);
+ DeletePartition(regionDescriptor);
+ }
+
+ // Mark the drive letter that was being used by the stripe or volume
+ // set free.
+
+ MarkDriveLetterFree(driveLetter);
+
+ // Remember drive letter if there is one in order to lock it for delete.
+
+ CompleteMultiRegionOperation();
+ SetCursor(hcurNormal);
+}
+
+
+VOID
+DoDeleteStripe(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Routine is called to delete a stripe. It calls a general
+ routine for stripe and volume set deletion.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ DoDeleteStripeOrVolumeSet(MSG_CONFIRM_DEL_STRP);
+}
+
+
+VOID
+DoCreateVolumeSet(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine uses the global selection information to collect
+ a group of freespace regions on the disks and organize them into
+ a volume set.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ MINMAXDLG_PARAMS params;
+ DWORD creationSize,
+ size,
+ maxTotalSize=0,
+ totalSizeUsed;
+ DWORD sizes[MaxMembersInFtSet];
+ PULONG primarySpacesToUseOnDisk;
+ CHAR driveLetter;
+ unsigned i;
+ PREGION_DESCRIPTOR regionDescriptor,
+ regionArray[MaxMembersInFtSet];
+ PPERSISTENT_REGION_DATA regionData;
+
+ // Make sure that the volume set does not include any
+ // partitions on removable media.
+
+ for (i=0; i<SelectionCount; i++) {
+
+ if (IsDiskRemovable[SELECTED_REGION(i).Disk]) {
+
+ ErrorDialog(MSG_NO_REMOVABLE_IN_VOLUMESET);
+ return;
+ }
+ }
+
+ for (i=0; i<SelectionCount; i++) {
+ FDASSERT(SELECTED_REGION(i).SysID == SYSID_UNUSED);
+ size = SELECTED_REGION(i).SizeMB;
+ sizes[i] = size;
+ maxTotalSize += size;
+ }
+
+ // Figure out a drive letter.
+
+ if (!AssignDriveLetter(TRUE, IDS_VOLUMESET, &driveLetter)) {
+ return;
+ }
+
+ params.CaptionStringID = IDS_CRTVSET_CAPTION;
+ params.MinimumStringID = IDS_CRTVSET_MIN;
+ params.MaximumStringID = IDS_CRTVSET_MAX;
+ params.SizeStringID = IDS_CRTVSET_SIZE;
+ params.MinSizeMB = SelectionCount;
+ params.MaxSizeMB = maxTotalSize;
+ params.HelpContextId = HC_DM_DLG_CREATEVOLUMESET;
+
+ creationSize = DialogBoxParam(hModule,
+ MAKEINTRESOURCE(IDD_MINMAX),
+ hwndFrame,
+ (DLGPROC)MinMaxDlgProc,
+ (LONG)&params);
+
+ if (!creationSize) { // user cancelled
+ return;
+ }
+
+ // Determine how large we have to make each member of the volume set.
+ // The percentage of each free space that will be used is the ratio
+ // of the total space he chose to the total free space.
+ //
+ // Example: 2 75 meg free spaces for a total set size of 150 MB.
+ // User chooses a set size of 100 MB. Use 50 MB of each space.
+
+ totalSizeUsed = 0;
+
+ for (i=0; i<SelectionCount; i++) {
+ sizes[i] = sizes[i] * creationSize / maxTotalSize;
+ if ((sizes[i] * creationSize) % maxTotalSize) {
+ sizes[i]++;
+ }
+
+ if (sizes[i] == 0) {
+ sizes[i]++;
+ }
+
+ totalSizeUsed += sizes[i];
+ }
+
+ // Make sure that the total amount used is not greater than the
+ // maximum amount available. Note that this loop is certain
+ // to terminate because maxTotalSize >= SelectionCount; if
+ // each of the sizes goes down to one, we will exit the loop
+
+ while (totalSizeUsed > maxTotalSize) {
+
+ for (i=0; (i<SelectionCount) && (totalSizeUsed > maxTotalSize); i++) {
+
+ if (sizes[i] > 1) {
+
+ sizes[i]--;
+ totalSizeUsed--;
+ }
+ }
+ }
+
+ SetCursor(hcurWait);
+
+ // Make sure that we are allowed to create a partition in the space.
+ // This is tricky because a volume set could contain more than one
+ // primary partition on a disk -- which means that if we're not careful
+ // we could create a disk with more than 4 primary partitions!
+
+ primarySpacesToUseOnDisk = Malloc(DiskCount * sizeof(ULONG));
+ RtlZeroMemory(primarySpacesToUseOnDisk, DiskCount * sizeof(ULONG));
+
+ for (i=0; i<SelectionCount; i++) {
+ regionDescriptor = &SELECTED_REGION(i);
+ FDASSERT(regionDescriptor->RegionType != REGION_EXTENDED);
+
+ if (regionDescriptor->RegionType == REGION_PRIMARY) {
+ primarySpacesToUseOnDisk[SelectedDS[i]->Disk]++;
+ }
+
+ if (!( ((regionDescriptor->RegionType == REGION_LOGICAL) && SelectedDS[i]->CreateLogical)
+ || ((regionDescriptor->RegionType == REGION_PRIMARY) && SelectedDS[i]->CreatePrimary)))
+ {
+ SetCursor(hcurNormal);
+ Free(primarySpacesToUseOnDisk);
+ ErrorDialog(MSG_CRTSTRP_FULL);
+ return;
+ }
+ }
+
+ // Look through the array we built to see whether we are supposed to use
+ // more than one primary partition on a given disk. For each such disk,
+ // make sure that we can actually create that many primary partitions.
+
+ for (i=0; i<DiskCount; i++) {
+
+ // If there are not enough primary partition slots, fail.
+
+ if ((primarySpacesToUseOnDisk[i] > 1)
+ && (4 - PartitionCount(i) < primarySpacesToUseOnDisk[i]))
+ {
+ SetCursor(hcurNormal);
+ Free(primarySpacesToUseOnDisk);
+ ErrorDialog(MSG_CRTSTRP_FULL);
+ return;
+ }
+ }
+
+ Free(primarySpacesToUseOnDisk);
+
+ // Now actually perform the creation.
+
+ for (i=0; i<SelectionCount; i++) {
+
+ regionDescriptor = &SELECTED_REGION(i);
+ FDASSERT(regionDescriptor->RegionType != REGION_EXTENDED);
+
+ CreatePartitionEx(regionDescriptor,
+ RtlConvertLongToLargeInteger(0L),
+ sizes[i],
+ regionDescriptor->RegionType,
+ (UCHAR)(SYSID_BIGFAT | SYSID_FT));
+
+ regionData = DmAllocatePersistentData(L"", wszNewUnformatted, driveLetter);
+ DmSetPersistentRegionData(regionDescriptor, regionData);
+ regionArray[i] = regionDescriptor;
+ }
+
+ // The zeroth element is the one to assign the drive letter to.
+
+ FdftCreateFtObjectSet(VolumeSet, regionArray, SelectionCount, FtSetNew);
+ MarkDriveLetterUsed(driveLetter);
+ CommitToAssignLetterList(&SELECTED_REGION(0), FALSE);
+ CompleteMultiRegionOperation();
+ SetCursor(hcurNormal);
+}
+
+
+VOID
+DoExtendVolumeSet(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine uses the global selection item information to
+ add additional freespace to an existing volume set or partition.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ MINMAXDLG_PARAMS params;
+ DWORD currentSize = 0,
+ freeSize = 0,
+ maxTotalSize = 0,
+ newSize = 0,
+ totalFreeSpaceUsed,
+ freeSpaceUsed,
+ Size;
+ DWORD Sizes[MaxMembersInFtSet];
+ ULONG nonFtPartitions = 0,
+ numberOfFreeRegions = 0;
+ PULONG primarySpacesToUseOnDisk;
+ WCHAR driveLetter = L' ';
+ PWSTR typeName = NULL,
+ volumeLabel = NULL;
+ PREGION_DESCRIPTOR regionDescriptor;
+ PREGION_DESCRIPTOR newRegions[MaxMembersInFtSet];
+ PREGION_DESCRIPTOR convertedRegion;
+ PFT_OBJECT_SET ftSet = NULL;
+ PPERSISTENT_REGION_DATA regionData;
+ unsigned i;
+ DWORD ec;
+
+
+ // Make sure that the volume set does not include any
+ // partitions on removable media.
+
+ for (i=0; i<SelectionCount; i++) {
+
+ if (IsDiskRemovable[SELECTED_REGION(i).Disk]) {
+
+ ErrorDialog(MSG_NO_REMOVABLE_IN_VOLUMESET);
+ return;
+ }
+ }
+
+
+ // First, determine the current size of the volume set,
+ // it's file system type and associated drive letter,
+ // and the size of the selected free space
+
+ for (i = 0; i < SelectionCount; i++) {
+
+ regionDescriptor = &(SELECTED_REGION(i));
+
+ Size = regionDescriptor->SizeMB;
+ Sizes[i] = Size;
+ maxTotalSize += Size;
+
+ if (regionDescriptor->SysID == SYSID_UNUSED) {
+
+ // This region is a chunk of free space; include it
+ // in the free space tallies.
+
+ newRegions[numberOfFreeRegions] = regionDescriptor;
+ Sizes[numberOfFreeRegions] = Size;
+
+ numberOfFreeRegions++;
+ freeSize += Size;
+
+ } else if (GET_FT_OBJECT(regionDescriptor)) {
+
+ // This is an element of an existing volume set.
+
+ currentSize += Size;
+
+ if ( ftSet == NULL ) {
+
+ DetermineRegionInfo(regionDescriptor,
+ &typeName,
+ &volumeLabel,
+ &driveLetter);
+ ftSet = GET_FT_OBJECT(regionDescriptor)->Set;
+ }
+
+ } else {
+
+ // This is a non-FT partition.
+
+ nonFtPartitions++;
+ DetermineRegionInfo(regionDescriptor,
+ &typeName,
+ &volumeLabel,
+ &driveLetter);
+ currentSize = Size;
+ convertedRegion = regionDescriptor;
+ }
+ }
+
+ // Check for consistency: the selection must have either a volume
+ // set or a partition, but not both, and cannot have more than
+ // one non-FT partition.
+
+ if (nonFtPartitions > 1 ||
+ (ftSet != NULL && nonFtPartitions != 0) ||
+ (ftSet == NULL && nonFtPartitions == 0)) {
+
+ return;
+ }
+
+
+ if (nonFtPartitions != 0 &&
+ (ec = DeletionIsAllowed(convertedRegion)) != NO_ERROR) {
+
+ // If the error-message is delete-specific, remap it.
+ //
+ switch( ec ) {
+#if i386
+ case MSG_CANT_DELETE_ACTIVE0: ec = MSG_CANT_EXTEND_ACTIVE0;
+ break;
+#endif
+ case MSG_CANT_DELETE_WINNT: ec = MSG_CANT_EXTEND_WINNT;
+ break;
+ default: break;
+ }
+
+ ErrorDialog(ec);
+ return;
+ }
+
+ if (wcscmp(typeName, L"NTFS") != 0) {
+
+ ErrorDialog(MSG_EXTEND_VOLSET_MUST_BE_NTFS);
+ return;
+ }
+
+
+ params.CaptionStringID = IDS_EXPVSET_CAPTION;
+ params.MinimumStringID = IDS_CRTVSET_MIN;
+ params.MaximumStringID = IDS_CRTVSET_MAX;
+ params.SizeStringID = IDS_CRTVSET_SIZE;
+ params.MinSizeMB = currentSize + numberOfFreeRegions;
+ params.MaxSizeMB = maxTotalSize;
+ params.HelpContextId = HC_DM_DLG_EXTENDVOLUMESET;
+
+ newSize = DialogBoxParam(hModule,
+ MAKEINTRESOURCE(IDD_MINMAX),
+ hwndFrame,
+ (DLGPROC)MinMaxDlgProc,
+ (LONG)&params);
+
+ if (!newSize) { // user cancelled
+ return;
+ }
+
+ // Determine how large to make each new member of the volume
+ // set. The percentage of free space to use is the ratio of
+ // the amount by which the volume set will grow to the total
+ // free space.
+
+ freeSpaceUsed = newSize - currentSize;
+ totalFreeSpaceUsed = 0;
+
+ for ( i = 0; i < numberOfFreeRegions; i++ ) {
+
+ Sizes[i] = Sizes[i] * freeSpaceUsed / freeSize;
+ if ((Sizes[i] * freeSpaceUsed) % freeSize) {
+ Sizes[i]++;
+ }
+
+ if (Sizes[i] == 0) {
+ Sizes[i]++;
+ }
+
+ totalFreeSpaceUsed += Sizes[i];
+ }
+
+ // Make sure that the total amount of free space used is not
+ // greater than the amount available. Note that this loop is
+ // certain to terminate because the amount of free space used
+ // is >= the number of free regions, so this loop will exit
+ // if one megabyte is used in each free region (the degenerate
+ // case).
+
+ while (totalFreeSpaceUsed > freeSize) {
+
+ for (i = 0;
+ (i < numberOfFreeRegions) && (totalFreeSpaceUsed > freeSize);
+ i++) {
+
+ if ( Sizes[i] > 1 ) {
+
+ Sizes[i]--;
+ totalFreeSpaceUsed--;
+ }
+ }
+ }
+
+ SetCursor(hcurWait);
+
+ // Make sure that we are allowed to create a partition in the space.
+ //
+ // This is tricky because a volume set could contain more than one
+ // primary partition on a disk -- which means that if we're not careful
+ // we could create a disk with more than 4 primary partitions!
+
+ primarySpacesToUseOnDisk = Malloc(DiskCount * sizeof(ULONG));
+ RtlZeroMemory(primarySpacesToUseOnDisk, DiskCount * sizeof(ULONG));
+
+ for (i=0; i<SelectionCount; i++) {
+ regionDescriptor = &SELECTED_REGION(i);
+
+ if (regionDescriptor->SysID == SYSID_UNUSED) {
+
+ FDASSERT(regionDescriptor->RegionType != REGION_EXTENDED);
+
+ if (regionDescriptor->RegionType == REGION_PRIMARY) {
+ primarySpacesToUseOnDisk[SelectedDS[i]->Disk]++;
+ }
+
+ if (!( ((regionDescriptor->RegionType == REGION_LOGICAL) && SelectedDS[i]->CreateLogical)
+ || ((regionDescriptor->RegionType == REGION_PRIMARY) && SelectedDS[i]->CreatePrimary))) {
+ SetCursor(hcurNormal);
+ Free(primarySpacesToUseOnDisk);
+ ErrorDialog(MSG_CRTSTRP_FULL);
+ return;
+ }
+ }
+ }
+
+ // Look through the array we built to see whether we are supposed to use
+ // more than one primary partition on a given disk. For each such disk,
+ // make sure that we can actually create that many primary partitions.
+
+ for (i=0; i<DiskCount; i++) {
+
+ // If there are not enough primary partition slots, fail.
+
+ if ((primarySpacesToUseOnDisk[i] > 1)
+ && (4 - PartitionCount(i) < primarySpacesToUseOnDisk[i])) {
+ SetCursor(hcurNormal);
+ Free(primarySpacesToUseOnDisk);
+ ErrorDialog(MSG_CRTSTRP_FULL);
+ return;
+ }
+ }
+
+ // Now actually perform the creation.
+
+ for (i=0; i<numberOfFreeRegions; i++) {
+
+ regionDescriptor = newRegions[i];
+ FDASSERT(regionDescriptor->RegionType != REGION_EXTENDED);
+
+ CreatePartitionEx(regionDescriptor,
+ RtlConvertLongToLargeInteger(0L),
+ Sizes[i],
+ regionDescriptor->RegionType,
+ (UCHAR)(SYSID_IFS | SYSID_FT));
+ regionData = DmAllocatePersistentData(volumeLabel, typeName, (CHAR)driveLetter);
+ DmSetPersistentRegionData(regionDescriptor, regionData);
+ }
+
+ if (nonFtPartitions != 0) {
+
+ // Create the volume set so we can extend it
+
+ FdftCreateFtObjectSet(VolumeSet, &convertedRegion, 1, FtSetExtended);
+ ftSet = GET_FT_OBJECT(convertedRegion)->Set;
+
+ // Set the converted region's partition System Id to indicate
+ // that it is now part of a volume set.
+
+ SetSysID2(convertedRegion, (UCHAR)(convertedRegion->SysID | SYSID_FT));
+ }
+
+ FdftExtendFtObjectSet(ftSet, newRegions, numberOfFreeRegions);
+ CompleteMultiRegionOperation();
+ SetCursor(hcurNormal);
+}
+
+VOID
+DoDeleteVolumeSet(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Routine is called to delete a volume set. It calls a general
+ routine for stripe and volume set deletion.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ DoDeleteStripeOrVolumeSet(MSG_CONFIRM_DEL_VSET);
+}
+
+extern ULONG OrdinalToAllocate[];
+
+VOID
+DoRecoverStripe(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Using the global selection information this routine will
+ set up a stripe with parity such that a problem member is
+ regenerated. This new member may either be the problem member
+ (i.e. regeneration is "in place") or new free space on a
+ different disk.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PREGION_DESCRIPTOR freeSpace = NULL;
+ PREGION_DESCRIPTOR unhealthy = NULL;
+ ULONG freeSpaceI = 0;
+ ULONG i;
+ PREGION_DESCRIPTOR regionArray[MaxMembersInFtSet];
+ LARGE_INTEGER minimumSize;
+ PFT_OBJECT ftObject;
+
+ // Initialize minimumSize to the maximum possible positive value
+
+ minimumSize.HighPart = 0x7FFFFFFF;
+ minimumSize.LowPart = 0xFFFFFFFF;
+
+ if ((!IsRegionCommitted(&SELECTED_REGION(0))) &&
+ (!IsRegionCommitted(&SELECTED_REGION(1)))) {
+ ErrorDialog(MSG_NOT_COMMITTED);
+ return;
+ }
+
+ FDASSERT(SelectionCount > 1);
+ FDASSERT(SelectionCount <= MaxMembersInFtSet);
+
+ SetCursor(hcurWait);
+
+ // Determine the exact size of the smallest member of the stripe set.
+ // If the user is regenerating using an additional free space, this
+ // will be the size requirement for the free space.
+ // Also find the free space (if any).
+ // If there is no free space, then we're doing an 'in-place' recover
+ // (ie regnerating into the unhealthy member). If there is a free space,
+ // make sure we are allowed to create a partition or logical drive in it.
+
+ for (i=0; i<SelectionCount; i++) {
+
+ regionArray[i] = &SELECTED_REGION(i);
+
+ FDASSERT(!IsExtended(regionArray[i]->SysID));
+
+ if (regionArray[i]->SysID == SYSID_UNUSED) {
+
+ PDISKSTATE ds;
+
+ FDASSERT(freeSpace == NULL);
+
+ freeSpace = regionArray[i];
+ freeSpaceI = i;
+
+ // Make sure we are allowed to create a partition or logical
+ // drive in the selected free space.
+
+ ds = SelectedDS[freeSpaceI];
+
+ if (!( ((freeSpace->RegionType == REGION_LOGICAL) && ds->CreateLogical)
+ || ((freeSpace->RegionType == REGION_PRIMARY) && ds->CreatePrimary))) {
+ SetCursor(hcurNormal);
+ ErrorDialog(MSG_CRTSTRP_FULL);
+ return;
+ }
+ } else {
+
+ LARGE_INTEGER largeTemp;
+
+ largeTemp = FdGetExactSize(regionArray[i], FALSE);
+ if (largeTemp.QuadPart < minimumSize.QuadPart) {
+ minimumSize = largeTemp;
+ }
+
+ if (GET_FT_OBJECT(regionArray[i])->State != Healthy) {
+ FDASSERT(unhealthy == NULL);
+ unhealthy = regionArray[i];
+ }
+ }
+ }
+
+ // If there is a free space, place it at item 0 of the regionArray
+ // to simplify processing later.
+
+ if (freeSpace) {
+ PREGION_DESCRIPTOR tempRegion = regionArray[0];
+
+ regionArray[0] = regionArray[freeSpaceI];
+ regionArray[freeSpaceI] = tempRegion;
+ i = 1;
+ } else {
+ i = 0;
+ }
+
+ // Get a pointer to the FT object for the broken member. Can't do this
+ // in the loop above because the broken member might be on an off-line
+ // disk.
+
+ for (ftObject=GET_FT_OBJECT(regionArray[i])->Set->Members; ftObject; ftObject = ftObject->Next) {
+ if (ftObject->State != Healthy) {
+ break;
+ }
+ }
+ FDASSERT(ftObject);
+
+ // Determine if the action is allowed.
+
+ if (ftObject->Set) {
+ switch (ftObject->Set->Status) {
+
+ case FtSetInitializing:
+ case FtSetRegenerating:
+
+ ErrorDialog(MSG_CANT_REGEN_INITIALIZING_SET);
+ return;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // Must lock the volume to perform this operation.
+
+ if (CommitToLockList(regionArray[i], FALSE, TRUE, FALSE)) {
+
+ // Could not lock the volume - try again, the file systems appear
+ // to be confused.
+
+ if (CommitToLockList(regionArray[i], FALSE, TRUE, FALSE)) {
+
+ // Don't allow the delete.
+
+ ErrorDialog(MSG_CANNOT_LOCK_TRY_AGAIN);
+ return;
+ }
+ }
+
+ if (freeSpace) {
+
+ LARGE_INTEGER temp;
+ PPERSISTENT_REGION_DATA regionData,
+ regionDataTemp;
+
+ // Make sure the free space region is large enough.
+
+ temp = FdGetExactSize(freeSpace, FALSE);
+ if (temp.QuadPart < minimumSize.QuadPart) {
+ SetCursor(hcurNormal);
+ ErrorDialog(MSG_NOT_LARGE_ENOUGH_FOR_STRIPE);
+ return;
+ }
+
+ // Create the new partition.
+
+ CreatePartitionEx(freeSpace,
+ minimumSize,
+ 0,
+ freeSpace->RegionType,
+ regionArray[1]->SysID);
+
+ // Set up the new partition's persistent data
+
+ regionDataTemp = PERSISTENT_DATA(regionArray[1]);
+ regionData = DmAllocatePersistentData(regionDataTemp->VolumeLabel,
+ regionDataTemp->TypeName,
+ regionDataTemp->DriveLetter);
+ regionData->FtObject = ftObject;
+ DmSetPersistentRegionData(freeSpace, regionData);
+
+ // Check to see if member zero of the set changed and
+ // the drive letter needs to move.
+
+ if (!ftObject->MemberIndex) {
+
+ // This is member zero. Move the drive letter to the
+ // new region descriptor.
+
+ CommitToAssignLetterList(freeSpace, TRUE);
+ }
+
+ // If the unhealthy member is on-line, delete it.
+ // Otherwise remove it from the off-line disk.
+
+ if (unhealthy) {
+ DmFreePersistentData(PERSISTENT_DATA(unhealthy));
+ DmSetPersistentRegionData(unhealthy, NULL);
+ DeletePartition(unhealthy);
+ }
+
+ // Remove any offline disks - this doesn't really
+ // delete the set.
+
+ FdftDeleteFtObjectSet(ftObject->Set, TRUE);
+ }
+
+ ftObject->Set->Ordinal = FdftNextOrdinal(StripeWithParity);
+ ftObject->State = Regenerating;
+ ftObject->Set->Status = FtSetRecovered;
+ RegistryChanged = TRUE;
+ CompleteMultiRegionOperation();
+ SetCursor(hcurNormal);
+}
+
+VOID
+AdjustOptionsMenu(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine updates the options menu (i.e. maintains
+ the state of the menu items for whether the status bar
+ or legend are displayed).
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ RECT rc;
+
+ CheckMenuItem(GetMenu(hwndFrame),
+ IDM_OPTIONSSTATUS,
+ MF_BYCOMMAND | (StatusBar ? MF_CHECKED : MF_UNCHECKED));
+ CheckMenuItem(GetMenu(hwndFrame),
+ IDM_OPTIONSLEGEND,
+ MF_BYCOMMAND | (Legend ? MF_CHECKED : MF_UNCHECKED));
+ GetClientRect(hwndFrame, &rc);
+ SendMessage(hwndFrame, WM_SIZE, SIZENORMAL, MAKELONG(rc.right, rc.bottom));
+ InvalidateRect(hwndFrame, NULL, TRUE);
+}
+
+VOID
+FrameCommandHandler(
+ IN HWND hwnd,
+ IN DWORD wParam,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles WM_COMMAND messages for the frame window.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DWORD i,
+ pos;
+ DWORD HelpFlag;
+ POINT point;
+
+ switch (LOWORD(wParam)) {
+
+ case IDM_PARTITIONCREATE:
+
+ DoCreate(REGION_PRIMARY);
+ break;
+
+ case IDM_PARTITIONCREATEEX:
+
+ DoCreate(REGION_EXTENDED);
+ break;
+
+ case IDM_PARTITIONDELETE:
+
+ switch (FtSelectionType) {
+
+ case Mirror:
+
+ DoBreakAndDeleteMirror();
+ break;
+
+ case Stripe:
+ case StripeWithParity:
+ DoDeleteStripe();
+ break;
+
+ case VolumeSet:
+ DoDeleteVolumeSet();
+ break;
+
+ default:
+ DoDelete();
+ break;
+ }
+
+ break;
+
+#if i386
+
+ case IDM_PARTITIONACTIVE:
+
+ DoMakeActive();
+ break;
+#endif
+
+ case IDM_SECURESYSTEM:
+
+ DoProtectSystemPartition();
+ break;
+
+ case IDM_PARTITIONLETTER:
+ {
+ int driveLetterIn,
+ driveLetterOut;
+ PREGION_DESCRIPTOR regionDescriptor;
+ PPERSISTENT_REGION_DATA regionData;
+ PFT_OBJECT ftObject;
+ ULONG index;
+
+ regionDescriptor = &SELECTED_REGION(0);
+ FDASSERT(regionDescriptor);
+ regionData = PERSISTENT_DATA(regionDescriptor);
+ FDASSERT(regionData);
+
+ if (ftObject = regionData->FtObject) {
+
+ // Must find the zero member of this set for the
+ // drive letter assignment. Search all of the selected
+ // regions
+
+ index = 0;
+ while (ftObject->MemberIndex) {
+
+ // search the next selected item if there is one
+
+ index++;
+ if (index >= SelectionCount) {
+ ftObject = NULL;
+ break;
+ }
+ regionDescriptor = &SELECTED_REGION(index);
+ FDASSERT(regionDescriptor);
+ regionData = PERSISTENT_DATA(regionDescriptor);
+ FDASSERT(regionData);
+ ftObject = regionData->FtObject;
+
+ // must have an FtObject to continue
+
+ if (!ftObject) {
+ break;
+ }
+ }
+
+ if (!ftObject) {
+
+ // This is really an internal error.
+ }
+
+ // regionDescriptor locates the zero element now.
+ }
+ driveLetterIn = (int)(UCHAR)regionData->DriveLetter;
+
+ if (IsDiskRemovable[regionDescriptor->Disk]) {
+ ErrorDialog(MSG_CANT_ASSIGN_LETTER_TO_REMOVABLE);
+ } else if (AllDriveLettersAreUsed() && ((driveLetterIn == NO_DRIVE_LETTER_YET) || (driveLetterIn == NO_DRIVE_LETTER_EVER))) {
+ ErrorDialog(MSG_ALL_DRIVE_LETTERS_USED);
+ } else {
+ driveLetterOut = DialogBoxParam(hModule,
+ MAKEINTRESOURCE(IDD_DRIVELET),
+ hwndFrame,
+ (DLGPROC)DriveLetterDlgProc,
+ (LONG)regionDescriptor);
+ if (driveLetterOut) {
+ LETTER_ASSIGNMENT_RESULT result;
+
+ if ((driveLetterIn == NO_DRIVE_LETTER_YET) || (driveLetterIn == NO_DRIVE_LETTER_EVER)) {
+
+ // Must insure that driveLetterIn maps to same things
+ // as is returned by the dialog when the user selects
+ // no letter.
+
+ driveLetterIn = NO_DRIVE_LETTER_EVER;
+ }
+ if (driveLetterOut != driveLetterIn) {
+ if (result = CommitDriveLetter(regionDescriptor, (CHAR) driveLetterIn, (CHAR)driveLetterOut)) {
+
+ // The following would be more rigorously correct:
+ // if non-ft, just set regionData->DriveLetter. If
+ // ft, scan all regions on all disks for members of
+ // ft set and set their drive letter fields.
+ //
+ // The below is probably correct, though.
+
+ for (i=0; i<SelectionCount; i++) {
+ PERSISTENT_DATA(&SELECTED_REGION(i))->DriveLetter = (CHAR)driveLetterOut;
+ }
+
+ // Don't allow the letter that is actually in use
+ // and will only change on a reboot to cycle back
+ // into the free list.
+
+ if (result != MustReboot) {
+
+ // Mark old letter free, new one used.
+
+ MarkDriveLetterFree((CHAR)driveLetterIn);
+ }
+ MarkDriveLetterUsed((CHAR)driveLetterOut);
+
+ // force status area and all disk bars to be redrawn
+
+ if (SelectionCount > 1) {
+ CompleteMultiRegionOperation();
+ } else {
+ CompleteSingleRegionOperation(SingleSel);
+ }
+ EnableMenuItem(GetMenu(hwndFrame), IDM_CONFIGSAVE, MF_GRAYED);
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ case IDM_PARTITIONFORMAT: {
+ PREGION_DESCRIPTOR regionDescriptor;
+
+ regionDescriptor = &SELECTED_REGION(0);
+ FDASSERT(regionDescriptor);
+ FormatPartition(regionDescriptor);
+ break;
+ }
+
+ case IDM_PARTITIONLABEL: {
+ PREGION_DESCRIPTOR regionDescriptor;
+
+ regionDescriptor = &SELECTED_REGION(0);
+ FDASSERT(regionDescriptor);
+ LabelPartition(regionDescriptor);
+ break;
+ }
+
+ case IDM_PARTITIONEXIT:
+
+ SendMessage(hwndFrame,WM_CLOSE,0,0);
+ break;
+
+ case IDM_CONFIGMIGRATE:
+
+ if (DoMigratePreviousFtConfig()) {
+
+ // Determine if the FT driver must be enabled.
+
+ SetCursor(hcurWait);
+ Sleep(2000);
+ if (DiskRegistryRequiresFt() == TRUE) {
+ DiskRegistryEnableFt();
+ } else {
+ DiskRegistryDisableFt();
+ }
+
+ // wait four seconds before shutdown
+
+ Sleep(4000);
+ SetCursor(hcurNormal);
+ FdShutdownTheSystem();
+ }
+ break;
+
+ case IDM_CONFIGSAVE:
+
+ DoSaveFtConfig();
+ break;
+
+ case IDM_CONFIGRESTORE:
+
+ if (DoRestoreFtConfig()) {
+
+ // Determine if the FT driver must be enabled.
+
+ if (DiskRegistryRequiresFt() == TRUE) {
+ DiskRegistryEnableFt();
+ } else {
+ DiskRegistryDisableFt();
+ }
+
+ // wait five seconds before shutdown
+
+ SetCursor(hcurWait);
+ Sleep(5000);
+ SetCursor(hcurNormal);
+ FdShutdownTheSystem();
+ }
+ break;
+
+ case IDM_FTESTABLISHMIRROR:
+
+ DoEstablishMirror();
+ break;
+
+ case IDM_FTBREAKMIRROR:
+
+ DoBreakMirror();
+ break;
+
+ case IDM_FTCREATESTRIPE:
+
+ DoCreateStripe(FALSE);
+ break;
+
+ case IDM_FTCREATEPSTRIPE:
+
+ DoCreateStripe(TRUE);
+ break;
+
+ case IDM_FTCREATEVOLUMESET:
+
+ DoCreateVolumeSet();
+ break;
+
+ case IDM_FTEXTENDVOLUMESET:
+
+ DoExtendVolumeSet();
+ break;
+
+ case IDM_FTRECOVERSTRIPE:
+
+ DoRecoverStripe();
+ break;
+
+#ifdef DOUBLE_SPACE_SUPPORT_INCLUDED
+ case IDM_DBLSPACE:
+ DblSpace(hwndFrame, NULL);
+ break;
+
+ case IDM_AUTOMOUNT: {
+ HMENU hMenu;
+
+ if (DoubleSpaceAutomount) {
+ DoubleSpaceAutomount = FALSE;
+ } else {
+ DoubleSpaceAutomount = TRUE;
+ }
+ DiskRegistryDblSpaceRemovable(DoubleSpaceAutomount);
+ hMenu = GetMenu(hwndFrame);
+ CheckMenuItem(hMenu,
+ IDM_AUTOMOUNT,
+ (DoubleSpaceAutomount) ? MF_CHECKED : MF_UNCHECKED);
+ break;
+ }
+#endif
+
+ case IDM_CDROM:
+ CdRom(hwndFrame, NULL);
+ break;
+
+ case IDM_COMMIT:
+ CommitAllChanges(NULL);
+ EnableMenuItem(GetMenu(hwndFrame), IDM_CONFIGSAVE, MF_ENABLED);
+ break;
+
+ case IDM_OPTIONSSTATUS:
+
+ StatusBar = !StatusBar;
+ AdjustOptionsMenu();
+ break;
+
+ case IDM_OPTIONSLEGEND:
+
+ Legend = !Legend;
+ AdjustOptionsMenu();
+ break;
+
+ case IDM_OPTIONSCOLORS:
+
+ switch(DialogBox(hModule, MAKEINTRESOURCE(IDD_COLORS), hwnd, (DLGPROC)ColorDlgProc)) {
+ case IDOK:
+ for (i=0; i<BRUSH_ARRAY_SIZE; i++) {
+ DeleteObject(Brushes[i]);
+ Brushes[i] = CreateHatchBrush(AvailableHatches[BrushHatches[i] = SelectedHatch[i]],
+ AvailableColors[BrushColors[i] = SelectedColor[i]]);
+ }
+ SetCursor(hcurWait);
+ TotalRedrawAndRepaint();
+ if (Legend) {
+ InvalidateRect(hwndFrame, NULL, FALSE);
+ }
+ SetCursor(hcurNormal);
+ break;
+
+ case IDCANCEL:
+ break;
+
+ case -1:
+ ErrorDialog(ERROR_NOT_ENOUGH_MEMORY);
+ break;
+
+ default:
+ FDASSERT(0);
+ }
+ break;
+
+ case IDM_OPTIONSDISPLAY: {
+
+ PBAR_TYPE newBarTypes = Malloc(DiskCount * sizeof(BAR_TYPE));
+
+ for (i=0; i<DiskCount; i++) {
+ newBarTypes[i] = Disks[i]->BarType;
+ }
+
+ switch (DialogBoxParam(hModule,
+ MAKEINTRESOURCE(IDD_DISPLAYOPTIONS),
+ hwnd,
+ (DLGPROC)DisplayOptionsDlgProc,
+ (DWORD)newBarTypes)) {
+ case IDOK:
+ SetCursor(hcurWait);
+ for (i=0; i<DiskCount; i++) {
+ Disks[i]->BarType = newBarTypes[i];
+ }
+ TotalRedrawAndRepaint();
+ SetCursor(hcurNormal);
+ break;
+
+ case IDCANCEL:
+ break;
+
+ default:
+ FDASSERT(0);
+ }
+
+ Free(newBarTypes);
+ break;
+ }
+
+ case IDM_HELPCONTENTS:
+ case IDM_HELP:
+
+ HelpFlag = HELP_INDEX;
+ goto CallWinHelp;
+ break;
+
+ case IDM_HELPSEARCH:
+
+ HelpFlag = HELP_PARTIALKEY;
+ goto CallWinHelp;
+ break;
+
+ case IDM_HELPHELP:
+
+ HelpFlag = HELP_HELPONHELP;
+ goto CallWinHelp;
+ break;
+
+ case IDM_HELPABOUT: {
+ TCHAR title[100];
+
+ LoadString(hModule, IDS_APPNAME, title, sizeof(title)/sizeof(TCHAR));
+ ShellAbout(hwndFrame, title, NULL, (HICON)GetClassLong(hwndFrame, GCL_HICON));
+ break;
+ }
+
+#if DBG && DEVL
+
+ case IDM_DEBUGALLOWDELETES:
+
+ AllowAllDeletes = !AllowAllDeletes;
+ CheckMenuItem(GetMenu(hwndFrame),
+ IDM_DEBUGALLOWDELETES,
+ AllowAllDeletes ? MF_CHECKED : MF_UNCHECKED);
+ break;
+
+#endif
+
+ case ID_LISTBOX:
+
+ switch (HIWORD(wParam)) {
+ case LBN_SELCHANGE:
+ point.x = LOWORD(pos = GetMessagePos());
+ point.y = HIWORD(pos);
+ MouseSelection(GetKeyState(VK_CONTROL) & ~1, // strip toggle bit
+ &point);
+ return;
+ default:
+ DefWindowProc(hwnd, WM_COMMAND, wParam, lParam);
+ return;
+ }
+ break;
+
+ default:
+
+ DefWindowProc(hwnd, WM_COMMAND, wParam, lParam);
+ }
+ return;
+
+CallWinHelp:
+
+ if (!WinHelp(hwndFrame, HelpFile, HelpFlag, (LONG)"")) {
+ WarningDialog(MSG_HELP_ERROR);
+ }
+}
+
+DWORD
+DeletionIsAllowed(
+ IN PREGION_DESCRIPTOR Region
+ )
+
+/*++
+
+Routine Description:
+
+ This routine makes sure deletion of the partition is allowed. We do not
+ allow the user to delete the Windows NT boot partition or the active
+ partition on disk 0 (x86 only).
+
+ Note that this routine is also used to determine whether an existing
+ single-partition volume can be extended into a volume set, since the
+ criteria are the same.
+
+Arguments:
+
+ Region - points to region descriptor for the region which the user would
+ like to delete.
+
+Return Value:
+
+ NO_ERROR if deletion is allowed; error number for message to display
+ if not.
+
+--*/
+
+{
+ ULONG ec;
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(Region);
+
+ FDASSERT(!IsExtended(Region->SysID)); // can't be extended partition
+ FDASSERT(Region->SysID != SYSID_UNUSED); // can't be free space
+
+#if DBG && DEVL
+ if (AllowAllDeletes) {
+ return NO_ERROR;
+ }
+#endif
+
+ // if this is not an original region, deletion is allowed.
+
+ if (!Region->OriginalPartitionNumber) {
+ return NO_ERROR;
+ }
+
+ // if there is no persistent data for this region, allow deletion.
+
+ if (regionData == NULL) {
+ return NO_ERROR;
+ }
+
+ ec = NO_ERROR;
+
+ // Determine the Windows NT drive by determining the windows directory
+ // and pulling out the first letter.
+
+ if (BootDiskNumber != (ULONG)-1) {
+
+ // If the disk number and original partition number of this
+ // region match the recorded disk number and partition number
+ // of the boot partition, don't allow deletion.
+
+ if (Region->Disk == BootDiskNumber &&
+ Region->OriginalPartitionNumber == BootPartitionNumber) {
+
+ ec = MSG_CANT_DELETE_WINNT;
+ }
+ }
+
+#if i386
+ if (ec == NO_ERROR) {
+ if (!Region->Disk && Region->Active) {
+ ec = MSG_CANT_DELETE_ACTIVE0;
+ }
+ }
+#endif
+
+ return ec;
+}
+
+
+BOOLEAN
+BootPartitionNumberChanged(
+ PULONG OldNumber,
+ PULONG NewNumber
+ )
+
+/*++
+
+Routine Description
+
+ This function determines whether the partition number of
+ the boot partition has changed during this invocation of
+ Windisk. With dynamic partitioning enabled, the work of
+ this routine increases. This routine must guess what the
+ partition numbers will be when the system is rebooted to
+ determine if the partition number for the boot partition
+ has changed. It does this via the following algorithm:
+
+ 1. Count all primary partitions - These get numbers first
+ starting from 1.
+
+ 2. Count all logical drives - These get numbers second starting
+ from the count of primary partitions plus 1.
+
+ The partition numbers located in the region structures cannot
+ be assumed to be valid. This work must be done from the
+ region array located in the disk state structure for the
+ disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the boot partition's partition number has changed.
+
+--*/
+
+{
+ PDISKSTATE bootDisk;
+ PREGION_DESCRIPTOR regionDescriptor,
+ bootDescriptor = NULL;
+ ULONG i,
+ partitionNumber = 0;
+
+ if (BootDiskNumber == (ULONG)(-1) || BootDiskNumber > DiskCount) {
+
+ // Can't tell--assume it hasn't.
+
+ return FALSE;
+ }
+
+ if (!ChangeCommittedOnDisk(BootDiskNumber)) {
+
+ // disk wasn't changed - no possibility for a problem.
+
+ return FALSE;
+ }
+
+ bootDisk = Disks[BootDiskNumber];
+
+ // Find the region descriptor for the boot partition
+
+ for (i = 0; i < bootDisk->RegionCount; i++) {
+ regionDescriptor = &bootDisk->RegionArray[i];
+ if (regionDescriptor->OriginalPartitionNumber == BootPartitionNumber) {
+ bootDescriptor = regionDescriptor;
+ break;
+ }
+ }
+
+ if (!bootDescriptor) {
+
+ // Can't find boot partition - assume no change
+
+ return FALSE;
+ }
+
+ // No go through the region descriptors and count the partition
+ // numbers as they will be counted during system boot.
+ //
+ // If the boot region is located determine if the partition
+ // number changed.
+
+ for (i = 0; i < bootDisk->RegionCount; i++) {
+
+ regionDescriptor = &bootDisk->RegionArray[i];
+ if ((regionDescriptor->RegionType == REGION_PRIMARY) &&
+ (!IsExtended(regionDescriptor->SysID) &&
+ (regionDescriptor->SysID != SYSID_UNUSED))) {
+ partitionNumber++;
+ if (regionDescriptor == bootDescriptor) {
+ if (partitionNumber != regionDescriptor->OriginalPartitionNumber) {
+ *OldNumber = regionDescriptor->OriginalPartitionNumber;
+ *NewNumber = partitionNumber;
+ return TRUE;
+ } else {
+
+ // Numbers match, no problem.
+
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ // Check the logical drives as well.
+
+ for (i = 0; i < bootDisk->RegionCount; i++) {
+ regionDescriptor = &bootDisk->RegionArray[i];
+
+ if (regionDescriptor->RegionType == REGION_LOGICAL) {
+ partitionNumber++;
+ if (regionDescriptor == bootDescriptor) {
+ if (partitionNumber != regionDescriptor->OriginalPartitionNumber) {
+ *OldNumber = regionDescriptor->OriginalPartitionNumber;
+ *NewNumber = partitionNumber;
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+DWORD
+CommitChanges(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine updates the disks to reflect changes made by the user
+ the partitioning scheme, or to stamp signatures on disks.
+
+ If the partitioning scheme on a disk has changed at all, a check will
+ first be made for a valid signature on the mbr in sector 0. If the
+ signature is not valid, x86 boot code will be written to the sector.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Windows error code.
+
+--*/
+
+{
+ unsigned i;
+ DWORD ec,
+ rc = NO_ERROR;
+
+ for (i=0; i<DiskCount; i++) {
+
+ if (HavePartitionsBeenChanged(i)) {
+ ec = MasterBootCode(i, 0, TRUE, FALSE);
+
+ // MasterBootCode has already translated the NT error
+ // status into a Windows error status.
+
+ if (rc == NO_ERROR) {
+ rc = ec; // save first non-success return code
+ }
+ ec = CommitPartitionChanges(i);
+
+ // CommitPartitionChanges returns a native NT error, it
+ // must be translated before it can be saved.
+
+ if (ec != NO_ERROR) {
+ ec = RtlNtStatusToDosError(ec);
+ }
+ if (rc == NO_ERROR) { // save first non-success return code
+ rc = ec;
+ }
+ }
+ }
+ if (rc != NO_ERROR) {
+
+ // If CommitPartitionChanges returns an error, it will be
+ // an NT status, which needs to be converted to a DOS status.
+
+ if (rc == ERROR_MR_MID_NOT_FOUND) {
+ ErrorDialog(MSG_ERROR_DURING_COMMIT);
+ } else {
+ ErrorDialog(rc);
+ }
+ }
+
+ return rc;
+}
+
+BOOL
+AssignDriveLetter(
+ IN BOOL WarnIfNoLetter,
+ IN DWORD StringId,
+ OUT PCHAR DriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ Determine the next available drive letter. If no drive letters are
+ available, optionally warn the user and allow him to cancel the
+ operation.
+
+Arguments:
+
+ WarnIfNoLetter - whether to warn the user if no drive letters are
+ available and allow him to cancel the operation.
+
+ StringId - resource containing the name of the object being created
+ that will need a drive letter (ie, partition, logical drive, stripe
+ set, volume set).
+
+ DriveLetter - receives the drive letter to assign, or NO_DRIVE_LETTER_YET
+ if no more left.
+
+Return Value:
+
+ If there were no more drive letters, returns TRUE if the user wants
+ to create anyway, FALSE if he canceled. If there were drive letters
+ available, the return value is undefined.
+
+--*/
+
+{
+ CHAR driveLetter;
+ TCHAR name[256];
+
+ driveLetter = GetAvailableDriveLetter();
+ if (WarnIfNoLetter && !driveLetter) {
+ LoadString(hModule, StringId, name, sizeof(name)/sizeof(TCHAR));
+ if (ConfirmationDialog(MSG_NO_AVAIL_LETTER, MB_ICONQUESTION | MB_YESNO, name) != IDYES) {
+ return FALSE;
+ }
+ }
+ if (!driveLetter) {
+ driveLetter = NO_DRIVE_LETTER_YET;
+ }
+ *DriveLetter = driveLetter;
+ return TRUE;
+}
+
+VOID
+DeterminePartitioningState(
+ IN OUT PDISKSTATE DiskState
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines the disk's partitioning state (ie, what types
+ of partitions exist and may be created), filling out a DISKSTATE
+ structure with the info. It also allocates the array for the
+ left/right position pairs for each region's on-screen square.
+
+Arguments:
+
+ DiskState - the CreateXXX and ExistXXX fields will be filled in for the
+ disk in the Disk field
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DWORD i;
+
+ // If there's an existing region array there, free it.
+
+ if (DiskState->RegionArray) {
+ FreeRegionArray(DiskState->RegionArray, DiskState->RegionCount);
+ }
+
+ // get the region array for the disk in question
+
+ GetAllDiskRegions(DiskState->Disk,
+ &DiskState->RegionArray,
+ &DiskState->RegionCount);
+
+ // Allocate the array for the left/right coords for the graph.
+ // This may overallocate by one square (for extended partition).
+
+ DiskState->LeftRight = Realloc(DiskState->LeftRight,
+ DiskState->RegionCount * sizeof(LEFTRIGHT));
+ DiskState->Selected = Realloc(DiskState->Selected,
+ DiskState->RegionCount * sizeof(BOOLEAN));
+
+ for (i=0; i<DiskState->RegionCount; i++) {
+ DiskState->Selected[i] = FALSE;
+ }
+
+ // figure out whether various creations are allowed
+
+ IsAnyCreationAllowed(DiskState->Disk,
+ TRUE,
+ &DiskState->CreateAny,
+ &DiskState->CreatePrimary,
+ &DiskState->CreateExtended,
+ &DiskState->CreateLogical);
+
+ // figure out whether various partition types exist
+
+ DoesAnyPartitionExist(DiskState->Disk,
+ &DiskState->ExistAny,
+ &DiskState->ExistPrimary,
+ &DiskState->ExistExtended,
+ &DiskState->ExistLogical);
+}
+
+VOID
+DrawDiskBar(
+ IN PDISKSTATE DiskState
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will draw the disk bar into the window.
+
+Arguments:
+
+ DiskState - current disk to draw.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PREGION_DESCRIPTOR regionDescriptor;
+ PDISKSTATE diskState;
+ LONGLONG temp1,
+ temp2;
+ HDC hDCMem = DiskState->hDCMem;
+ DWORD leftAdjust = BarLeftX,
+ xDiskText,
+ cx = 0,
+ brushIndex = 0;
+ HPEN hpenT;
+ char text[100],
+ textBold[5];
+ TCHAR uniText[100],
+ uniTextBold[5],
+ mbBuffer[16];
+ RECT rc;
+ HFONT hfontT;
+ COLORREF previousColor;
+ HBRUSH hbr;
+ BOOL isFree,
+ isLogical;
+ HDC hdcTemp;
+ HBITMAP hbmOld;
+ PWSTR typeName,
+ volumeLabel;
+ WCHAR driveLetter;
+ BAR_TYPE barType;
+ ULONG diskSize,
+ largestDiskSize;
+ unsigned i;
+
+ // If this is a removable. Update to whatever its current
+ // information may be.
+
+ if (IsDiskRemovable[DiskState->Disk]) {
+ PPERSISTENT_REGION_DATA regionData;
+
+ // Update the information on this disk.
+
+ regionDescriptor = &DiskState->RegionArray[0];
+ regionData = PERSISTENT_DATA(regionDescriptor);
+
+ if (GetVolumeTypeAndSize(DiskState->Disk,
+ regionDescriptor->PartitionNumber,
+ &volumeLabel,
+ &typeName,
+ &diskSize)) {
+
+ // Update the values for the removable.
+
+ if (regionData) {
+
+ // Always want RAW file systems to display as "Unknown"
+
+ if (!lstrcmpiW(typeName, L"raw")) {
+ Free(typeName);
+ typeName = Malloc((wcslen(wszUnknown) * sizeof(WCHAR)) + sizeof(WCHAR));
+ lstrcpyW(typeName, wszUnknown);
+ }
+ if (regionData->VolumeLabel) {
+ Free(regionData->VolumeLabel);
+ }
+ regionData->VolumeLabel = volumeLabel;
+ if (regionData->TypeName) {
+ Free(regionData->TypeName);
+ }
+ regionData->TypeName = typeName;
+ }
+
+ DiskState->DiskSizeMB = diskSize;
+ }
+ }
+
+ // figure out largest disk's size
+
+ for (largestDiskSize = i = 0, diskState = Disks[0];
+ i < DiskCount;
+ diskState = Disks[++i]) {
+
+ if (diskState->DiskSizeMB > largestDiskSize) {
+ largestDiskSize = diskState->DiskSizeMB;
+ }
+ }
+
+ // erase the graph background
+
+ rc.left = rc.top = 0;
+ rc.right = GraphWidth + 1;
+ rc.bottom = GraphHeight + 1;
+ FillRect(hDCMem, &rc, GetStockObject(LTGRAY_BRUSH));
+
+ hpenT = SelectObject(hDCMem,hPenThinSolid);
+
+ // Draw the disk info area: small disk bitmap, some text, and a
+ // line across the top.
+ //
+ // First draw the bitmap.
+
+ hdcTemp = CreateCompatibleDC(hDCMem);
+ if (IsDiskRemovable[DiskState->Disk]) {
+ hbmOld = SelectObject(hdcTemp, hBitmapRemovableDisk);
+ BitBlt(hDCMem,
+ xRemovableDisk,
+ yRemovableDisk,
+ dxRemovableDisk,
+ dyRemovableDisk,
+ hdcTemp,
+ 0,
+ 0,
+ SRCCOPY);
+ } else {
+ hbmOld = SelectObject(hdcTemp, hBitmapSmallDisk);
+ BitBlt(hDCMem,
+ xSmallDisk,
+ ySmallDisk,
+ dxSmallDisk,
+ dySmallDisk,
+ hdcTemp,
+ 0,
+ 0,
+ SRCCOPY);
+ }
+
+ if (hbmOld) {
+ SelectObject(hdcTemp, hbmOld);
+ }
+ DeleteDC(hdcTemp);
+
+ // Now draw the line.
+
+ if (IsDiskRemovable[DiskState->Disk]) {
+ MoveToEx(hDCMem, xRemovableDisk, BarTopYOffset, NULL);
+ LineTo(hDCMem, BarLeftX - xRemovableDisk, BarTopYOffset);
+ xDiskText = 2 * dxRemovableDisk;
+ } else {
+ MoveToEx(hDCMem, xSmallDisk, BarTopYOffset, NULL);
+ LineTo(hDCMem, BarLeftX - xSmallDisk, BarTopYOffset);
+ xDiskText = 2 * dxSmallDisk;
+ }
+
+ // Now draw the text.
+
+ hfontT = SelectObject(hDCMem, hFontGraphBold);
+ SetTextColor(hDCMem, RGB(0, 0, 0));
+ SetBkColor(hDCMem, RGB(192, 192, 192));
+ wsprintf(uniText, DiskN, DiskState->Disk);
+ TextOut(hDCMem,
+ xDiskText,
+ BarTopYOffset + dyBarTextLine,
+ uniText,
+ lstrlen(uniText));
+
+ SelectObject(hDCMem, hFontGraph);
+ if (DiskState->OffLine) {
+ LoadString(hModule, IDS_OFFLINE, uniText, sizeof(uniText)/sizeof(TCHAR));
+ } else {
+ LoadString(hModule, IDS_MEGABYTES_ABBREV, mbBuffer, sizeof(mbBuffer)/sizeof(TCHAR));
+ wsprintf(uniText, TEXT("%u %s"), DiskState->DiskSizeMB, mbBuffer);
+ }
+
+ TextOut(hDCMem,
+ xDiskText,
+ BarTopYOffset + (4*dyBarTextLine),
+ uniText,
+ lstrlen(uniText));
+
+ if (DiskState->OffLine) {
+
+ SelectObject(hDCMem, GetStockObject(LTGRAY_BRUSH));
+ Rectangle(hDCMem,
+ BarLeftX,
+ BarTopYOffset,
+ BarLeftX + BarWidth,
+ BarBottomYOffset);
+ LoadString(hModule, IDS_NO_CONFIG_INFO, uniText, sizeof(uniText)/sizeof(TCHAR));
+ TextOut(hDCMem,
+ BarLeftX + dxBarTextMargin,
+ BarTopYOffset + (4*dyBarTextLine),
+ uniText,
+ lstrlen(uniText));
+ } else {
+
+ // Account for extreme differences in largest to smallest disk
+ // by insuring that a disk is always 1/4 the size of the
+ // largest disk.
+
+ diskSize = DiskState->DiskSizeMB;
+ if (diskSize < largestDiskSize / 4) {
+ diskSize = largestDiskSize / 4;
+ }
+#if 0
+ // manage the horizontal size of the list box in order
+ // to get a scroll bar. Perhaps this only needs to be done
+ // once. BUGBUG: This will cause a horizontal scroll bar
+ // that works correctly, but the region selection code is
+ // not prepared for this, so selection of regions doesn't
+ // operate correctly.
+
+ largestExtent = (WPARAM)(BarWidth + BarLeftX + 2);
+ SendMessage(hwndList, LB_SETHORIZONTALEXTENT, largestExtent, 0);
+#endif
+ // If user wants WinDisk to decide which type of view to use, do that
+ // here. We'll use a proportional view unless any single region would
+ // have a width less than the size of a drive letter.
+
+ if ((barType = DiskState->BarType) == BarAuto) {
+ ULONG regionSize;
+
+ barType = BarProportional;
+
+ for (i=0; i<DiskState->RegionCount; i++) {
+
+ regionDescriptor = &DiskState->RegionArray[i];
+
+ if (IsExtended(regionDescriptor->SysID)) {
+ continue;
+ }
+
+ temp1 = UInt32x32To64(BarWidth, diskSize);
+ temp1 *= regionDescriptor->SizeMB;
+ temp2 = UInt32x32To64(largestDiskSize, DiskState->DiskSizeMB);
+ regionSize = (ULONG) (temp1 / temp2);
+
+ if (regionSize < 12*SELECTION_THICKNESS) {
+ barType = BarEqual;
+ break;
+ }
+ }
+ }
+
+ if (barType == BarEqual) {
+
+ temp1 = UInt32x32To64(BarWidth, diskSize);
+ temp2 = UInt32x32To64((DiskState->RegionCount -
+ (DiskState->ExistExtended ? 1 : 0)), largestDiskSize);
+ cx = (ULONG) (temp1 / temp2);
+ }
+
+ for (i=0; i<DiskState->RegionCount; i++) {
+ PFT_OBJECT ftObject = NULL;
+
+ regionDescriptor = &DiskState->RegionArray[i];
+ if (!IsExtended(regionDescriptor->SysID)) {
+
+ if (barType == BarProportional) {
+
+ temp1 = UInt32x32To64(BarWidth, diskSize);
+ temp1 *= regionDescriptor->SizeMB;
+ temp2 = UInt32x32To64(largestDiskSize, DiskState->DiskSizeMB);
+ cx = (ULONG) (temp1 / temp2);
+ }
+
+ isFree = (regionDescriptor->SysID == SYSID_UNUSED);
+ isLogical = (regionDescriptor->RegionType == REGION_LOGICAL);
+
+ if (!isFree) {
+
+ // If we've got a mirror or stripe set, use special colors.
+
+ ftObject = GET_FT_OBJECT(regionDescriptor);
+ switch(ftObject ? ftObject->Set->Type : -1) {
+ case Mirror:
+ brushIndex = BRUSH_MIRROR;
+ break;
+ case Stripe:
+ case StripeWithParity:
+ brushIndex = BRUSH_STRIPESET;
+ break;
+ case VolumeSet:
+ brushIndex = BRUSH_VOLUMESET;
+ break;
+ default:
+ brushIndex = isLogical ? BRUSH_USEDLOGICAL : BRUSH_USEDPRIMARY;
+ } // end the switch
+ }
+
+ previousColor = SetBkColor(hDCMem, RGB(255, 255, 255));
+ SetBkMode(hDCMem, OPAQUE);
+
+ if (isFree) {
+
+ // Free space -- cross hatch the whole block.
+
+ hbr = SelectObject(hDCMem,isLogical ? hBrushFreeLogical : hBrushFreePrimary);
+ Rectangle(hDCMem,
+ leftAdjust,
+ BarTopYOffset,
+ leftAdjust + cx,
+ BarBottomYOffset);
+ } else {
+
+ // Used space -- make most of the block white except for
+ // a small strip at the top, which gets an identifying color.
+ // If the partition is not recognized, leave it all white.
+
+ hbr = SelectObject(hDCMem, GetStockObject(WHITE_BRUSH));
+ Rectangle(hDCMem, leftAdjust, BarTopYOffset, leftAdjust + cx, BarBottomYOffset);
+
+ if (IsRecognizedPartition(regionDescriptor->SysID)) {
+ SelectObject(hDCMem, Brushes[brushIndex]);
+ Rectangle(hDCMem,
+ leftAdjust,
+ BarTopYOffset,
+ leftAdjust + cx,
+ BarTopYOffset + (4 * dyBarTextLine / 5) + 1);
+ }
+ }
+
+ if (hbr) {
+ SelectObject(hDCMem, hbr);
+ }
+
+ DiskState->LeftRight[i].Left = leftAdjust;
+ DiskState->LeftRight[i].Right = leftAdjust + cx - 1;
+
+ // Figure out the type name (ie, unformatted, fat, etc) and
+ // volume label.
+
+ typeName = NULL;
+ volumeLabel = NULL;
+ DetermineRegionInfo(regionDescriptor, &typeName, &volumeLabel, &driveLetter);
+ LoadString(hModule, IDS_MEGABYTES_ABBREV, mbBuffer, sizeof(mbBuffer)/sizeof(TCHAR));
+
+ if (!typeName) {
+ typeName = wszUnknown;
+ }
+ if (!volumeLabel) {
+ volumeLabel = L"";
+ }
+ wsprintf(text,
+ "\n%ws\n%ws\n%u %s",
+ volumeLabel,
+ typeName,
+ regionDescriptor->SizeMB,
+ mbBuffer);
+
+ *textBold = 0;
+ if (driveLetter != L' ') {
+ wsprintf(textBold, "%wc:", driveLetter);
+ }
+
+ UnicodeHack(text, uniText);
+ UnicodeHack(textBold, uniTextBold);
+
+ // output the text
+
+ rc.left = leftAdjust + dxBarTextMargin;
+ rc.right = leftAdjust + cx - dxBarTextMargin;
+ rc.top = BarTopYOffset + dyBarTextLine;
+ rc.bottom = BarBottomYOffset;
+
+ SetBkMode(hDCMem, TRANSPARENT);
+ SelectObject(hDCMem, hFontGraphBold);
+
+ // If this is an unhealthy ft set member, draw the text in red.
+
+ if (!isFree && ftObject
+ && (ftObject->State != Healthy)
+ && (ftObject->State != Initializing)) {
+ SetTextColor(hDCMem, RGB(192, 0, 0));
+ } else {
+ SetTextColor(hDCMem, RGB(0, 0, 0));
+ }
+
+ DrawText(hDCMem, uniTextBold, -1, &rc, DT_LEFT | DT_NOPREFIX);
+ SelectObject(hDCMem, hFontGraph);
+ DrawText(hDCMem, uniText, -1, &rc, DT_LEFT | DT_NOPREFIX);
+#if i386
+ // if this guy is active make a mark in the upper left
+ // corner of his rectangle.
+
+ if ((regionDescriptor->SysID != SYSID_UNUSED)
+ && (regionDescriptor->Disk == 0)
+ && (regionDescriptor->RegionType == REGION_PRIMARY)
+ && regionDescriptor->Active) {
+ TextOut(hDCMem,
+ leftAdjust + dxBarTextMargin,
+ BarTopYOffset + 2,
+ TEXT("*"),
+ 1);
+ }
+#endif
+#ifdef DOUBLE_SPACE_SUPPORT_INCLUDED
+ // Check for DoubleSpace volumes and update display accordingly
+
+ dblSpaceIndex = 0;
+ dblSpace = NULL;
+ while (dblSpace = DblSpaceGetNextVolume(regionDescriptor, dblSpace)) {
+
+ if (dblSpace->Mounted) {
+ SetTextColor(hDCMem, RGB(192,0,0));
+ } else {
+ SetTextColor(hDCMem, RGB(0,0,0));
+ }
+ wsprintf(uniText,
+ TEXT("%c: %s"),
+ dblSpace->DriveLetter,
+ dblSpace->FileName);
+ rc.left = leftAdjust + dxBarTextMargin + 60;
+ rc.right = leftAdjust + cx - dxBarTextMargin;
+ rc.top = BarTopYOffset + dyBarTextLine + (dblSpaceIndex * 15);
+ rc.bottom = BarBottomYOffset;
+ DrawText(hDCMem, uniText, -1, &rc, DT_LEFT | DT_NOPREFIX);
+ dblSpaceIndex++;
+ }
+#endif
+ SetBkColor(hDCMem, previousColor);
+ leftAdjust += cx - 1;
+ } else {
+ DiskState->LeftRight[i].Left = DiskState->LeftRight[i].Right = 0;
+ }
+ }
+ }
+
+ SelectObject(hDCMem, hpenT);
+ SelectObject(hDCMem, hfontT);
+}
+
+VOID
+AdjustMenuAndStatus(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine updates the information in the Status bar
+ if something is selected and if the status bar is to be
+ displayed.
+
+Arguments"
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ TCHAR mbBuffer[16],
+ statusBarPartitionString[200],
+ dblSpaceString[200];
+ DWORD selectionCount,
+ msg,
+ regionIndex;
+ PDISKSTATE diskState;
+ PWSTR volumeLabel,
+ typeName;
+ WCHAR driveLetter;
+
+
+ switch (selectionCount = SetUpMenu(&SingleSel,&SingleSelIndex)) {
+
+ case 0:
+
+ StatusTextDrlt[0] = 0;
+ StatusTextSize[0] = StatusTextStat[0] = 0;
+ StatusTextVoll[0] = StatusTextType[0] = 0;
+ break;
+
+ case 1:
+
+ // Might be part of a partial FT set.
+
+ if (FtSelectionType != -1) {
+ goto FtSet;
+ }
+
+ diskState = SingleSel;
+ regionIndex = SingleSelIndex;
+
+ DetermineRegionInfo(&diskState->RegionArray[regionIndex],
+ &typeName,
+ &volumeLabel,
+ &driveLetter);
+ lstrcpyW(StatusTextType,typeName);
+ lstrcpyW(StatusTextVoll,volumeLabel);
+
+ if (diskState->RegionArray[regionIndex].SysID == SYSID_UNUSED) {
+ if (diskState->RegionArray[regionIndex].RegionType == REGION_LOGICAL) {
+ if (diskState->ExistLogical) {
+ msg = IDS_FREEEXT;
+ } else {
+ msg = IDS_EXTENDEDPARTITION;
+ }
+ } else {
+ msg = IDS_FREESPACE;
+ }
+ driveLetter = L' ';
+ StatusTextType[0] = 0;
+ } else {
+ msg = (diskState->RegionArray[regionIndex].RegionType == REGION_LOGICAL)
+ ? IDS_LOGICALVOLUME
+ : IDS_PARTITION;
+
+#if i386
+ if ((msg == IDS_PARTITION) && (diskState->Disk == 0) && diskState->RegionArray[regionIndex].Active) {
+ msg = IDS_ACTIVEPARTITION;
+ }
+#endif
+ }
+ LoadString(hModule, msg, statusBarPartitionString, STATUS_TEXT_SIZE/sizeof(StatusTextStat[0]));
+ if (DblSpaceVolumeExists(&diskState->RegionArray[regionIndex])) {
+ LoadString(hModule, IDS_WITH_DBLSPACE, dblSpaceString, STATUS_TEXT_SIZE/sizeof(StatusTextStat[0]));
+ } else {
+ dblSpaceString[0] = dblSpaceString[1] = 0;
+ }
+ wsprintf(StatusTextStat,
+ "%s %s",
+ statusBarPartitionString,
+ dblSpaceString);
+ LoadString(hModule, IDS_MEGABYTES_ABBREV, mbBuffer, sizeof(mbBuffer)/sizeof(TCHAR));
+ wsprintf(StatusTextSize,
+ "%u %s",
+ diskState->RegionArray[regionIndex].SizeMB,
+ mbBuffer);
+
+ StatusTextDrlt[0] = driveLetter;
+ StatusTextDrlt[1] = (WCHAR)((driveLetter == L' ') ? 0 : L':');
+ break;
+
+ default:
+ FtSet:
+
+ // Might be an ft set, might be multiple items
+
+ if (FtSelectionType == -1) {
+ LoadString(hModule, IDS_MULTIPLEITEMS, StatusTextStat, STATUS_TEXT_SIZE/sizeof(StatusTextStat[0]));
+ StatusTextDrlt[0] = 0;
+ StatusTextSize[0] = 0;
+ StatusTextType[0] = StatusTextVoll[0] = 0;
+ } else {
+ PREGION_DESCRIPTOR regionDescriptor;
+ DWORD resid = 0,
+ i;
+ DWORD Size = 0;
+ TCHAR textbuf[STATUS_TEXT_SIZE];
+ PFT_OBJECT_SET ftSet;
+ PFT_OBJECT ftObject;
+ FT_SET_STATUS setState;
+ ULONG numberOfMembers;
+ WCHAR ftstat[65];
+ STATUS_CODE status;
+
+ typeName = NULL;
+ DetermineRegionInfo(&SELECTED_REGION(0),
+ &typeName,
+ &volumeLabel,
+ &driveLetter);
+ if (!typeName) {
+ if (SelectionCount > 1) {
+ DetermineRegionInfo(&SELECTED_REGION(0),
+ &typeName,
+ &volumeLabel,
+ &driveLetter);
+ }
+ }
+ if (!typeName) {
+ typeName = wszUnknown;
+ volumeLabel = L"";
+ }
+ lstrcpyW(StatusTextType, typeName);
+ lstrcpyW(StatusTextVoll, volumeLabel);
+
+ switch (FtSelectionType) {
+ case Mirror:
+ resid = IDS_STATUS_MIRROR;
+ Size = SELECTED_REGION(0).SizeMB;
+ break;
+ case Stripe:
+ resid = IDS_STATUS_STRIPESET;
+ goto CalcSize;
+ case StripeWithParity:
+ resid = IDS_STATUS_PARITY;
+ goto CalcSize;
+ case VolumeSet:
+ resid = IDS_STATUS_VOLUMESET;
+ goto CalcSize;
+CalcSize:
+ for (i=0; i<selectionCount; i++) {
+ Size += SELECTED_REGION(i).SizeMB;
+ }
+ break;
+ default:
+ FDASSERT(FALSE);
+ }
+
+ ftObject = GET_FT_OBJECT(&SELECTED_REGION(0));
+ ftSet = ftObject->Set;
+
+ if (FtSelectionType != VolumeSet) {
+ regionDescriptor = LocateRegionForFtObject(ftSet->Member0);
+
+ if (!regionDescriptor) {
+
+ // The zeroth member is off line
+
+ ftObject = ftSet->Members;
+ while (ftObject) {
+
+ // Find member 1
+
+ if (ftObject->MemberIndex == 1) {
+ regionDescriptor = LocateRegionForFtObject(ftObject);
+ break;
+ }
+ ftObject = ftObject->Next;
+ }
+ }
+
+ // If the partition number is zero, then this set has
+ // not been committed to the disk yet.
+
+ if ((regionDescriptor) && (regionDescriptor->PartitionNumber)) {
+ status = LowFtVolumeStatus(regionDescriptor->Disk,
+ regionDescriptor->PartitionNumber,
+ &setState,
+ &numberOfMembers);
+ if (status == OK_STATUS) {
+ if ((ftSet->Status != FtSetNewNeedsInitialization) &&
+ (ftSet->Status != FtSetNew)) {
+
+ if (ftSet->Status != setState) {
+ PFT_OBJECT tempFtObjectPtr;
+
+ ftSet->Status = setState;
+
+ // Determine if each object should be updated.
+
+ switch (setState) {
+ case FtSetHealthy:
+
+ // Each object in the set should have
+ // the partition state updated. Determine
+ // the value for the update and walk
+ // the chain to perform the update.
+
+ for (tempFtObjectPtr = ftSet->Members;
+ tempFtObjectPtr;
+ tempFtObjectPtr = tempFtObjectPtr->Next) {
+ tempFtObjectPtr->State = Healthy;
+ }
+ TotalRedrawAndRepaint();
+ break;
+
+ case FtSetInitializing:
+ case FtSetRegenerating:
+ case FtSetDisabled:
+
+ FdftUpdateFtObjectSet(ftSet, setState);
+ TotalRedrawAndRepaint();
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ LoadString(hModule, resid, textbuf, sizeof(textbuf)/sizeof(TCHAR));
+
+ switch (resid) {
+ case IDS_STATUS_STRIPESET:
+ case IDS_STATUS_VOLUMESET:
+ wsprintf(StatusTextStat, textbuf, ftSet->Ordinal);
+ break;
+ case IDS_STATUS_PARITY:
+ case IDS_STATUS_MIRROR:
+ switch(ftSet->Status) {
+ case FtSetHealthy:
+ resid = IDS_HEALTHY;
+ break;
+ case FtSetNew:
+ case FtSetNewNeedsInitialization:
+ resid = IDS_NEW;
+ break;
+ case FtSetBroken:
+ resid = IDS_BROKEN;
+ break;
+ case FtSetRecoverable:
+ resid = IDS_RECOVERABLE;
+ break;
+ case FtSetRecovered:
+ resid = IDS_REGENERATED;
+ break;
+ case FtSetInitializing:
+ resid = IDS_INITIALIZING;
+ break;
+ case FtSetRegenerating:
+ resid = IDS_REGENERATING;
+ break;
+ case FtSetDisabled:
+ resid = IDS_DISABLED;
+ break;
+ case FtSetInitializationFailed:
+ resid = IDS_INIT_FAILED;
+ break;
+ default:
+ FDASSERT(FALSE);
+ }
+ LoadStringW(hModule, resid, ftstat, sizeof(ftstat)/sizeof(WCHAR));
+ wsprintf(StatusTextStat, textbuf, ftSet->Ordinal,ftstat);
+ break;
+ default:
+ FDASSERT(FALSE);
+ }
+
+ LoadString(hModule, IDS_MEGABYTES_ABBREV, mbBuffer, sizeof(mbBuffer)/sizeof(TCHAR));
+ wsprintf(StatusTextSize, "%u %s", Size, mbBuffer);
+
+ StatusTextDrlt[0] = driveLetter;
+ StatusTextDrlt[1] = (WCHAR)((driveLetter == L' ') ? 0 : L':');
+ }
+ }
+ UpdateStatusBarDisplay();
+}
+
+ULONG
+PartitionCount(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ Given a disk index, this routine calculates the number of partitions the
+ disk contains.
+
+Arguments:
+
+ Disk - This disk index for the count.
+
+Return Value:
+
+ The number of partitions on the disk
+
+--*/
+
+{
+ unsigned i;
+ ULONG partitions = 0;
+ PREGION_DESCRIPTOR regionDescriptor;
+
+ for (i=0; i<Disks[Disk]->RegionCount; i++) {
+
+ regionDescriptor = &Disks[Disk]->RegionArray[i];
+
+ if ((regionDescriptor->RegionType != REGION_LOGICAL) && (regionDescriptor->SysID != SYSID_UNUSED)) {
+ partitions++;
+ }
+ }
+
+ return partitions;
+}
+
+
+BOOL
+RegisterFileSystemExtend(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function adds registry entries to extend the file
+ system structures in volume sets that have been extended.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ non-zero if there was a file system that was extended.
+
+--*/
+{
+ BYTE buf[1024];
+ PSTR template = "autochk /x ";
+ CHAR extendedDrives[26];
+ PDISKSTATE diskState;
+ PREGION_DESCRIPTOR regionDescriptor;
+ PFT_OBJECT ftObject;
+ DWORD cExt = 0,
+ i,
+ j,
+ valueType,
+ size,
+ templateLength;
+ HKEY hkey;
+ LONG ec;
+
+ // Traverse the disks to find any volume sets that
+ // have been extended.
+
+ for (i = 0; i < DiskCount; i++) {
+
+ diskState = Disks[i];
+ for (j = 0; j < diskState->RegionCount; j++) {
+
+ regionDescriptor = &diskState->RegionArray[j];
+ if ((ftObject = GET_FT_OBJECT(regionDescriptor)) != NULL
+ && ftObject->MemberIndex == 0
+ && ftObject->Set->Type == VolumeSet
+ && ftObject->Set->Status == FtSetExtended) {
+
+ extendedDrives[cExt++] = PERSISTENT_DATA(regionDescriptor)->DriveLetter;
+ }
+ }
+ }
+
+ if (cExt) {
+
+ // Fetch the BootExecute value of the Session Manager key.
+
+ ec = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("System\\CurrentControlSet\\Control\\Session Manager"),
+ 0,
+ KEY_QUERY_VALUE | KEY_SET_VALUE,
+ &hkey);
+
+ if (ec != NO_ERROR) {
+ return 0;
+ }
+
+ size = sizeof(buf);
+ ec = RegQueryValueExA(hkey,
+ TEXT("BootExecute"),
+ NULL,
+ &valueType,
+ buf,
+ &size);
+
+ if (ec != NO_ERROR || valueType != REG_MULTI_SZ) {
+ return 0;
+ }
+
+ // Decrement size to get rid of the extra trailing null
+
+ if (size) {
+ size--;
+ }
+
+ templateLength = strlen(template);
+
+ for (i = 0; i < cExt; i++) {
+
+ // Add an entry for this drive to the BootExecute value.
+
+ strncpy(buf+size, template, templateLength);
+ size += templateLength;
+
+ buf[size++] = extendedDrives[i];
+ buf[size++] = ':';
+ buf[size++] = 0;
+ }
+
+ // Add an additional trailing null at the end
+
+ buf[size++] = 0;
+
+ // Save the value.
+
+ ec = RegSetValueExA(hkey,
+ TEXT("BootExecute"),
+ 0,
+ REG_MULTI_SZ,
+ buf,
+ size);
+
+ RegCloseKey( hkey );
+ if (ec != NO_ERROR) {
+ return 0;
+ }
+ return 1;
+ }
+ return 0;
+}
diff --git a/private/utils/find.old/find.cxx b/private/utils/find.old/find.cxx
new file mode 100644
index 000000000..ff847b462
--- /dev/null
+++ b/private/utils/find.old/find.cxx
@@ -0,0 +1,659 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ find.cxx
+
+Abstract:
+
+ This utility allows the user to search for strings in a file
+ It is functionaly compatible with DOS 5 find utility.
+
+ SYNTAX (Command line)
+
+ FIND [/?][/V][/C][/N][/I] "string" [[d:][path]filename[.ext]...]
+
+ where:
+
+ /? - Display this help
+ /V - Display all lines NOT containing the string
+ /C - Display only a count of lines containing string
+ /N - Display number of line containing string
+ /I - Ignore case
+
+ UTILITY FUNCTION:
+
+ Searches the specified file(s) looking for the string the user
+ entered from the command line. If file name(s) are specifeied,
+ those names are displayed, and if the string is found, then the
+ entire line containing that string will be displayed. Optional
+ parameters modify that behavior and are described above. String
+ arguments have to be enclosed in double quotes. (Two double quotes
+ if a double quote is to be included). Only one string argument is
+ presently allowed. The maximum line size is determined by buffer
+ size. Bigger lines will bomb the program. If no file name is given
+ then it will asssume the input is coming from the standard Input.
+ No errors are reported when reading from standard Input.
+
+
+ EXIT:
+ The program returns errorlevel:
+ 0 - OK, and some matches
+ 1 -
+ 2 - Some Error
+
+
+Author:
+
+ Bruce Wilson (w-wilson) 08-May-1991
+
+Environment:
+
+ ULIB, User Mode
+
+Revision History:
+
+ 08-May-1991 w-wilson
+
+ created
+
+--*/
+
+#include "ulib.hxx"
+#include "ulibcl.hxx"
+#include "error.hxx"
+#include "arg.hxx"
+#include "array.hxx"
+#include "path.hxx"
+#include "wstring.hxx"
+#include "substrng.hxx"
+#include "filestrm.hxx"
+#include "file.hxx"
+#include "system.hxx"
+#include "arrayit.hxx"
+#include "smsg.hxx"
+#include "rtmsg.h"
+#include "find.hxx"
+
+
+extern "C" {
+#include <stdio.h>
+#include <string.h>
+}
+
+#define MAX_LINE_LEN 1024
+
+
+ERRSTACK* perrstk;
+static STR TmpBuf[MAX_LINE_LEN];
+
+DEFINE_CONSTRUCTOR( FIND, PROGRAM );
+
+
+BOOLEAN
+FIND::Initialize(
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes an FIND class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the initialization succeeded.
+
+
+--*/
+
+
+{
+ ARGUMENT_LEXEMIZER ArgLex;
+ ARRAY LexArray;
+
+ ARRAY ArgumentArray;
+
+ STRING_ARGUMENT ProgramNameArgument;
+ FLAG_ARGUMENT FlagCaseInsensitive;
+ FLAG_ARGUMENT FlagNegativeSearch;
+ FLAG_ARGUMENT FlagCountLines;
+ FLAG_ARGUMENT FlagDisplayNumbers;
+ FLAG_ARGUMENT FlagDisplayHelp;
+ FLAG_ARGUMENT FlagInvalid;
+ STRING_ARGUMENT StringPattern;
+
+ PROGRAM::Initialize();
+
+ _ErrorLevel = 0;
+
+ if( !SYSTEM::IsCorrectVersion() ) {
+ DisplayMessage(MSG_FIND_INCORRECT_VERSION);
+ // BUGBUG: (w-wilson) this seems stupid - shouldn't it be 1 or 2??
+ _ErrorLevel = 0;
+ return(FALSE);
+ }
+
+ //
+ // - init the array that will contain the command-line args
+ //
+ if ( !ArgumentArray.Initialize() ) {
+ DbgAbort( "ArgumentArray.Initialize() failed \n" );
+ }
+
+ //
+ // - init the individual arguments
+ //
+ if( !ProgramNameArgument.Initialize("*")
+ || !FlagCaseInsensitive.Initialize( "/I" )
+ || !FlagNegativeSearch.Initialize( "/V" )
+ || !FlagCountLines.Initialize( "/C" )
+ || !FlagDisplayNumbers.Initialize( "/N" )
+ || !FlagDisplayHelp.Initialize( "/?" )
+ || !FlagInvalid.Initialize( "/*" )
+ || !StringPattern.Initialize( "\"*\"" )
+ || !_PathArguments.Initialize( "*", FALSE, TRUE ) ) {
+
+ DbgAbort( "Unable to initialize flag or string arguments \n" );
+ }
+
+ //
+ // - put the arguments in the array
+ //
+ if( !ArgumentArray.Put( &ProgramNameArgument )
+ || !ArgumentArray.Put( &FlagCaseInsensitive )
+ || !ArgumentArray.Put( &FlagNegativeSearch )
+ || !ArgumentArray.Put( &FlagCountLines )
+ || !ArgumentArray.Put( &FlagDisplayNumbers )
+ || !ArgumentArray.Put( &FlagDisplayHelp )
+ || !ArgumentArray.Put( &FlagInvalid )
+ || !ArgumentArray.Put( &StringPattern )
+ || !ArgumentArray.Put( &_PathArguments ) ) {
+
+ DbgAbort( "ArgumentArray.Put() failed \n" );
+ }
+ //
+ // - init the lexemizer
+ //
+ if ( !LexArray.Initialize() ) {
+ DbgAbort( "LexArray.Initialize() failed \n" );
+ }
+ if ( !ArgLex.Initialize( &LexArray ) ) {
+ DbgAbort( "ArgLex.Initialize() failed \n" );
+ }
+
+ //
+ // - set up the defaults
+ //
+ ArgLex.PutSwitches( "/" );
+ ArgLex.PutStartQuotes( "\"" );
+ ArgLex.PutEndQuotes( "\"" );
+ ArgLex.PutSeparators( " \"" );
+ ArgLex.SetCaseSensitive( FALSE );
+ if( !ArgLex.PrepareToParse() ) {
+
+ //
+ // invalid format
+ //
+ DisplayMessage(MSG_FIND_INVALID_FORMAT);
+
+ _ErrorLevel = 2;
+ return( FALSE );
+ }
+
+
+ //
+ // - now parse the command line. The args in the array will be set
+ // if they are found on the command line.
+ //
+ if( !ArgLex.DoParsing( &ArgumentArray ) ) {
+ if( FlagInvalid.QueryFlag() ) {
+ //
+ // invalid switch
+ //
+ DisplayMessage(MSG_FIND_INVALID_SWITCH);
+
+ } else {
+ //
+ // invalid format
+ //
+ DisplayMessage(MSG_FIND_INVALID_FORMAT);
+ }
+ _ErrorLevel = 2;
+ return( FALSE );
+ } else if ( _PathArguments.WildCardExpansionFailed() ) {
+
+ //
+ // No files matched
+ //
+ DisplayMessage(MSG_FIND_FILE_NOT_FOUND, ERROR_MESSAGE, "%W", _PathArguments.GetLexemeThatFailed() );
+
+ _ErrorLevel = 2;
+ return( FALSE );
+
+ } else {
+
+// DbgPrint( "\nargs parsed ok\n" );
+ }
+
+ if( FlagInvalid.QueryFlag() ) {
+ //
+ // invalid switch
+ //
+ DisplayMessage(MSG_FIND_INVALID_SWITCH, ERROR_MESSAGE );
+ _ErrorLevel = 2;
+ return( FALSE );
+ }
+
+ //
+ // - now do semantic checking/processing
+ // - if they ask for help, do it right away and return
+ // - set flags
+ //
+ if( FlagDisplayHelp.QueryFlag() ) {
+ DisplayMessage(MSG_FIND_USAGE);
+ _ErrorLevel = 0;
+ return( FALSE );
+ }
+
+ if( !StringPattern.IsValueSet() ) {
+ DisplayMessage(MSG_FIND_INVALID_FORMAT);
+ _ErrorLevel = 2;
+ return( FALSE );
+ } else {
+ //
+ // - keep a copy of the pattern string
+ //
+
+ DbgAssert(StringPattern.GetString());
+ _PatternString = *StringPattern.GetString();
+
+ _PatternString.QuerySTR( 0, TO_END, TmpBuf, sizeof( TmpBuf ));
+// DbgPrint("pattern is ");
+// DbgPrint(TmpBuf);
+// DbgPrint("\n");
+ }
+
+ _CaseSensitive = (BOOLEAN)!FlagCaseInsensitive.QueryFlag();
+
+ _LinesContainingPattern = (BOOLEAN)!FlagNegativeSearch.QueryFlag();
+
+ _OutputLines = (BOOLEAN)!FlagCountLines.QueryFlag();
+
+ _OutputLineNumbers = (BOOLEAN)FlagDisplayNumbers.QueryFlag();
+
+ DbgAssert(sprintf(TmpBuf,
+ "flags:caseSens %1d, +veSrch %1d, outLines %1d, line#'s %1d\n",
+ _CaseSensitive, _LinesContainingPattern, _OutputLines,
+ _OutputLineNumbers) > 0);
+// DbgPrint(TmpBuf);
+
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+FIND::IsDos5CompatibleFileName(
+ IN PCPATH Path
+ )
+/*++
+
+Routine Description:
+
+ Parses the path string and returns FALSE if DOS5 would reject
+ the path.
+
+Arguments:
+
+ Path - Supplies the path
+
+Return Value:
+
+ BOOLEAN - Returns FALSE if DOS5 would reject the path,
+ TRUE otherwise
+
+--*/
+
+{
+
+ PWSTRING String;
+
+ DbgPtrAssert( Path );
+
+ String = (PWSTRING)Path->GetPathString();
+
+ DbgPtrAssert( String );
+
+ if ( String->QueryChCount() > 0 ) {
+
+ if ( String->QueryChAt(0) == '\"' ) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+
+}
+
+
+
+ULONG
+FIND::SearchStream(
+ PSTREAM StreamToSearch
+ )
+
+/*++
+
+Routine Description:
+
+ Does the search on an open file_stream.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Number of lines found/not found.
+
+
+--*/
+
+{
+ ULONG LineCount;
+ ULONG FoundCount;
+ CHNUM PatternLen;
+ CHNUM PositionInLine;
+ CHNUM LastPosInLine;
+ WSTRING CurrentLine;
+ WSTRING Delim;
+ USHORT CompareFlags;
+ WCHAR Wchar;
+ BOOLEAN Found;
+
+ LineCount = FoundCount = 0;
+ PatternLen = _PatternString.QueryChCount();
+ if( !Delim.Initialize( "\r\n" ) ) {
+ DbgAbort( "Delim.Initialize() failed \n" );
+ }
+ if( !CurrentLine.Initialize("") ) {
+ DbgAbort( "CurrentLine.Initialize() failed \n" );
+ }
+ CompareFlags = (_CaseSensitive) ? 0 : CF_IGNORECASE;
+
+ //
+ // - for each line from stream
+ // - do strstr to see if pattern string is in line
+ // - if -ve search and not in line || +ve search and in line
+ // - output line and number or inc counter appropriately
+ //
+// DbgPrint("searching stream\n");
+ while( !StreamToSearch->IsAtEnd() ) {
+
+ //
+ // BUGBUG: the following can be replaced with ReadLine() when
+ // it's ready
+ //
+ //if( !StreamToSearch->ReadString(&CurrentLine, &Delim) ) {
+ // DbgAbort( "ReadString() failed \n" );
+ //}
+ //if( !StreamToSearch->IsAtEnd() ) {
+ // if( !StreamToSearch->ReadChar( &Wchar ) ) {
+ // DbgAbort( "ReadChar() failed \n" );
+ // }
+ // if( Wchar == ( WCHAR )'\r' ) {
+ // if( !StreamToSearch->IsAtEnd() ) {
+ // if( !StreamToSearch->ReadChar( &Wchar ) ) {
+ // DbgAbort( "ReadChar() failed \n" );
+ // }
+ // }
+ // }
+ //}
+
+ if ( !StreamToSearch->ReadLine( &CurrentLine ) ) {
+ DbgAbort( "ReadLine failed\n" );
+ }
+
+ LineCount++;
+// DbgPrint(".");
+
+ //
+ // - look for pattern string in the current line
+ // - note: a 0-length pattern ("") never matches a line.
+ // A 0-length pattern can produce output with the /v
+ // switch.
+ // - start at the end (saves a var)
+ //
+
+ Found = FALSE;
+
+ if( PatternLen && CurrentLine.QueryChCount() >= PatternLen ) {
+
+ LastPosInLine = CurrentLine.QueryChCount() - PatternLen;
+
+ for( PositionInLine = 0;
+ PositionInLine <= LastPosInLine; PositionInLine++ ) {
+
+ if( CurrentLine.StringCompare(PositionInLine, PatternLen,
+ &_PatternString, 0, PatternLen,
+ CompareFlags) == 0 ) {
+ //
+ // found a match so exit loop
+ //
+ Found = TRUE;
+ break;
+ }
+ }
+ }
+
+ //
+ // - if either (search is +ve and found a match)
+ // or (search is -ve and no match found)
+ // then print line/line number based on options
+ //
+ if( (_LinesContainingPattern && Found)
+ || (!_LinesContainingPattern && !Found) ) {
+
+ FoundCount++;
+ if( _OutputLines ) {
+ if( _OutputLineNumbers ) {
+ DisplayMessage( MSG_FIND_LINE_AND_NUMBER, NORMAL_MESSAGE, "%d%W", LineCount, &CurrentLine);
+ } else {
+ DisplayMessage( MSG_FIND_LINEONLY, NORMAL_MESSAGE, "%W", &CurrentLine);
+ }
+ }
+ }
+ }
+// DbgPrint("\n");
+ return(FoundCount);
+}
+
+
+
+VOID
+FIND::SearchFiles(
+ )
+
+/*++
+
+Routine Description:
+
+ Does the search on the files specified on the command line.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+// STR nameBuf[ MAX_PATH ];
+ PARRAY PathArray;
+ PARRAY_ITERATOR PIterator;
+ PPATH CurrentPath;
+ PFSN_FILE CurrentFSNode = NULL;
+ PFSN_DIRECTORY CurrentFSDir;
+ PFILE_STREAM CurrentFile = NULL;
+ WSTRING CurrentPathString;
+ ULONG LinesFound;
+
+
+ if( !_PathArguments.IsValueSet() ) {
+// DbgPrint( "no paths specified\n" );
+ } else {
+// DbgPrint( "paths specified\n" );
+ }
+
+ //
+ // - if 0 paths on cmdline then open stdin
+ // - if more than one path set OutputName flag
+ //
+ if( (_PathArguments.QueryPathCount() == 0) ) {
+// DbgPrint("PathCount == 0 so searching stdin\n");
+ // use stdin
+ LinesFound = SearchStream( Get_Standard_Input_Stream() );
+ if( !_OutputLines ) {
+ DisplayMessage(MSG_FIND_COUNT, NORMAL_MESSAGE, "%d", LinesFound);
+ }
+ return;
+ }
+
+ PathArray = _PathArguments.GetPathArray();
+ PIterator = (PARRAY_ITERATOR)PathArray->QueryIterator();
+
+ //
+ // - for each path specified on the command line
+ // - open a stream for the path
+ // - print filename if supposed to
+ // - call SearchStream
+ //
+ while( (CurrentPath = (PPATH)PIterator->GetNext()) != NULL ) {
+ CurrentPathString.Initialize( CurrentPath->GetPathString() );
+ CurrentPathString.Strupr();
+
+// ->QuerySTR( 0, TO_END, nameBuf, sizeof(nameBuf));
+// DbgAssert(sprintf(TmpBuf, "path is <%s>\n", nameBuf) > 0);
+// DbgPrint(TmpBuf);
+
+ // if the system object can return a FSN_DIRECTORY for this
+ // path then the user is trying to 'find' on a dir so print
+ // access denied and skip this file
+
+ if( CurrentFSDir = SYSTEM::QueryDirectory(CurrentPath) ) {
+
+ if (CurrentPath->IsDrive()) {
+
+ DisplayMessage(MSG_FIND_FILE_NOT_FOUND, ERROR_MESSAGE, "%W", &CurrentPathString);
+
+ } else {
+
+ DisplayMessage( MSG_ACCESS_DENIED, ERROR_MESSAGE, "%W", &CurrentPathString);
+
+ }
+
+ DELETE( CurrentFSDir );
+ continue;
+ }
+
+
+ if( !(CurrentFSNode = SYSTEM::QueryFile(CurrentPath)) ||
+ !(CurrentFile = CurrentFSNode->QueryStream(READ_ACCESS)) ) {
+
+ //
+ // If the file name is "", DOS5 prints an invalid parameter
+ // format message. There is no clean way to filter this
+ // kind of stuff in the ULIB library, so we will have to
+ // parse the path ourselves.
+ //
+ if ( IsDos5CompatibleFileName( CurrentPath ) ) {
+ DisplayMessage(MSG_FIND_FILE_NOT_FOUND, ERROR_MESSAGE, "%W", &CurrentPathString);
+ } else {
+ DisplayMessage(MSG_FIND_INVALID_FORMAT, ERROR_MESSAGE );
+ break;
+ }
+ DELETE( CurrentFile );
+ DELETE( CurrentFSNode );
+ CurrentFile = NULL;
+ CurrentFSNode = NULL;
+ continue;
+ }
+
+
+ if( _OutputLines ) {
+ DisplayMessage( MSG_FIND_BANNER, NORMAL_MESSAGE, "%W", &CurrentPathString);
+ }
+
+ LinesFound = SearchStream( CurrentFile );
+
+ if( !_OutputLines ) {
+ DisplayMessage(MSG_FIND_COUNT_BANNER, NORMAL_MESSAGE, "%W%d", &CurrentPathString, LinesFound);
+ }
+
+ DELETE( CurrentFSNode );
+ DELETE( CurrentFile );
+ CurrentFSNode = NULL;
+ CurrentFile = NULL;
+ }
+
+ return;
+}
+
+
+
+VOID
+FIND::Terminate(
+ )
+
+/*++
+
+Routine Description:
+
+ Deletes objects created during initialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ exit(_ErrorLevel);
+}
+
+
+
+VOID
+main()
+
+{
+ DEFINE_CLASS_DESCRIPTOR( FIND );
+
+ {
+ FIND Find;
+
+ perrstk = NEW ERRSTACK;
+
+ if( Find.Initialize() ) {
+ // DbgPrint("done init\n" );
+ Find.SearchFiles();
+ }
+ Find.Terminate();
+ }
+}
diff --git a/private/utils/find.old/find.hxx b/private/utils/find.old/find.hxx
new file mode 100644
index 000000000..28d0fcdb8
--- /dev/null
+++ b/private/utils/find.old/find.hxx
@@ -0,0 +1,101 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ find.hxx
+
+Abstract:
+
+
+Author:
+
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if ! defined( _FIND_ )
+
+#define _FIND_
+
+#include "object.hxx"
+#include "keyboard.hxx"
+#include "program.hxx"
+
+DECLARE_CLASS( FIND );
+
+class FIND : public PROGRAM {
+
+ public:
+
+
+ DECLARE_CONSTRUCTOR( FIND );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsDos5CompatibleFileName(
+ IN PCPATH Path
+ );
+
+ NONVIRTUAL
+ VOID
+ Terminate(
+ );
+
+
+ NONVIRTUAL
+ VOID
+ SearchFiles(
+ );
+
+
+ private:
+
+ NONVIRTUAL
+ ULONG
+ SearchStream(
+ PSTREAM StreamToSearch
+ );
+
+
+ //
+ // TRUE = do a case-sensitive matching
+ //
+ BOOLEAN _CaseSensitive;
+
+ //
+ // TRUE = output lines that contain the pattern
+ //
+ BOOLEAN _LinesContainingPattern;
+
+ //
+ // TRUE = output the lines that match/don't match
+ // FALSE = count the lines that match/don't match
+ //
+ BOOLEAN _OutputLines;
+
+ //
+ // TRUE = output line numbers if lines are being output
+ //
+ BOOLEAN _OutputLineNumbers;
+
+ WSTRING _PatternString;
+
+ MULTIPLE_PATH_ARGUMENT _PathArguments;
+
+ STREAM_MESSAGE _Message;
+ ULONG _ErrorLevel;
+
+};
+
+
+#endif // _FIND_
diff --git a/private/utils/find.old/makefile b/private/utils/find.old/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/find.old/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/find.old/sources b/private/utils/find.old/sources
new file mode 100644
index 000000000..447e7a22b
--- /dev/null
+++ b/private/utils/find.old/sources
@@ -0,0 +1,55 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=utils
+MINORCOMP=find
+
+TARGETNAME=find
+TARGETPATH=obj
+TARGETTYPE=UMAPPL_NOLIB
+
+SOURCES=
+
+INCLUDES=..\ulib\inc;\nt\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DNOMINMAX -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DNOMINMAX -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DNOMINMAX -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DNOMINMAX -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+CXXFLAGS=+d
+UMLIBS=..\ulib\src\obj\*\ulib.lib
+
+UMTYPE=console
+
+UMAPPL=find
diff --git a/private/utils/find/find.cxx b/private/utils/find/find.cxx
new file mode 100644
index 000000000..0af152c27
--- /dev/null
+++ b/private/utils/find/find.cxx
@@ -0,0 +1,667 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ find.cxx
+
+Abstract:
+
+ This utility allows the user to search for strings in a file
+ It is functionaly compatible with DOS 5 find utility.
+
+ SYNTAX (Command line)
+
+ FIND [/?][/V][/C][/N][/I] "string" [[d:][path]filename[.ext]...]
+
+ where:
+
+ /? - Display this help
+ /V - Display all lines NOT containing the string
+ /C - Display only a count of lines containing string
+ /N - Display number of line containing string
+ /I - Ignore case
+
+ UTILITY FUNCTION:
+
+ Searches the specified file(s) looking for the string the user
+ entered from the command line. If file name(s) are specifeied,
+ those names are displayed, and if the string is found, then the
+ entire line containing that string will be displayed. Optional
+ parameters modify that behavior and are described above. String
+ arguments have to be enclosed in double quotes. (Two double quotes
+ if a double quote is to be included). Only one string argument is
+ presently allowed. The maximum line size is determined by buffer
+ size. Bigger lines will bomb the program. If no file name is given
+ then it will asssume the input is coming from the standard Input.
+ No errors are reported when reading from standard Input.
+
+
+ EXIT:
+ The program returns errorlevel:
+ 0 - OK, and some matches
+ 1 -
+ 2 - Some Error
+
+
+Author:
+
+ Bruce Wilson (w-wilson) 08-May-1991
+
+Environment:
+
+ ULIB, User Mode
+
+Revision History:
+
+ 08-May-1991 w-wilson
+
+ created
+
+--*/
+
+#include "ulib.hxx"
+#include "ulibcl.hxx"
+#include "error.hxx"
+#include "arg.hxx"
+#include "array.hxx"
+#include "mbstr.hxx"
+#include "path.hxx"
+#include "wstring.hxx"
+#include "substrng.hxx"
+#include "filestrm.hxx"
+#include "file.hxx"
+#include "system.hxx"
+#include "arrayit.hxx"
+#include "smsg.hxx"
+#include "rtmsg.h"
+#include "find.hxx"
+#include "dir.hxx"
+
+extern "C" {
+ #include <stdio.h>
+ #include <string.h>
+}
+
+#define MAX_LINE_LEN 1024
+
+
+ERRSTACK* perrstk;
+static STR TmpBuf[MAX_LINE_LEN];
+
+DEFINE_CONSTRUCTOR( FIND, PROGRAM );
+
+
+BOOLEAN
+FIND::Initialize(
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes an FIND class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the initialization succeeded.
+
+
+--*/
+
+
+{
+ ARGUMENT_LEXEMIZER ArgLex;
+ ARRAY LexArray;
+
+ ARRAY ArgumentArray;
+
+ STRING_ARGUMENT ProgramNameArgument;
+ FLAG_ARGUMENT FlagCaseInsensitive;
+ FLAG_ARGUMENT FlagNegativeSearch;
+ FLAG_ARGUMENT FlagCountLines;
+ FLAG_ARGUMENT FlagDisplayNumbers;
+ FLAG_ARGUMENT FlagDisplayHelp;
+ FLAG_ARGUMENT FlagInvalid;
+ STRING_ARGUMENT StringPattern;
+
+ PROGRAM::Initialize();
+
+ // An Error Level return of 1 indicates that no match was
+ // found; a return of 0 indicates that a match was found.
+ // Set it at 1 until a match is found.
+ //
+ _ErrorLevel = 1;
+
+ if( !SYSTEM::IsCorrectVersion() ) {
+ DisplayMessage(MSG_FIND_INCORRECT_VERSION);
+ _ErrorLevel = 2;
+ return(FALSE);
+ }
+
+ //
+ // - init the array that will contain the command-line args
+ //
+ if ( !ArgumentArray.Initialize() ) {
+ DebugAbort( "ArgumentArray.Initialize() failed \n" );
+ }
+
+ //
+ // - init the individual arguments
+ //
+ if( !ProgramNameArgument.Initialize("*")
+ || !FlagCaseInsensitive.Initialize( "/I" )
+ || !FlagNegativeSearch.Initialize( "/V" )
+ || !FlagCountLines.Initialize( "/C" )
+ || !FlagDisplayNumbers.Initialize( "/N" )
+ || !FlagDisplayHelp.Initialize( "/?" )
+ || !FlagInvalid.Initialize( "/*" ) // comment */
+ || !StringPattern.Initialize( "\"*\"" )
+ || !_PathArguments.Initialize( "*", FALSE, TRUE ) ) {
+
+ DebugAbort( "Unable to initialize flag or string arguments \n" );
+ }
+
+ //
+ // - put the arguments in the array
+ //
+ if( !ArgumentArray.Put( &ProgramNameArgument )
+ || !ArgumentArray.Put( &FlagCaseInsensitive )
+ || !ArgumentArray.Put( &FlagNegativeSearch )
+ || !ArgumentArray.Put( &FlagCountLines )
+ || !ArgumentArray.Put( &FlagDisplayNumbers )
+ || !ArgumentArray.Put( &FlagDisplayHelp )
+ || !ArgumentArray.Put( &FlagInvalid )
+ || !ArgumentArray.Put( &StringPattern )
+ || !ArgumentArray.Put( &_PathArguments ) ) {
+
+ DebugAbort( "ArgumentArray.Put() failed \n" );
+ }
+ //
+ // - init the lexemizer
+ //
+ if ( !LexArray.Initialize() ) {
+ DebugAbort( "LexArray.Initialize() failed \n" );
+ }
+ if ( !ArgLex.Initialize( &LexArray ) ) {
+ DebugAbort( "ArgLex.Initialize() failed \n" );
+ }
+
+ //
+ // - set up the defaults
+ //
+ ArgLex.PutSwitches( "/" );
+ ArgLex.PutStartQuotes( "\"" );
+ ArgLex.PutEndQuotes( "\"" );
+ ArgLex.PutSeparators( " \"\t" );
+ ArgLex.SetCaseSensitive( FALSE );
+ if( !ArgLex.PrepareToParse() ) {
+
+ //
+ // invalid format
+ //
+ DisplayMessage(MSG_FIND_INVALID_FORMAT);
+
+ _ErrorLevel = 2;
+ return( FALSE );
+ }
+
+
+ //
+ // - now parse the command line. The args in the array will be set
+ // if they are found on the command line.
+ //
+ if( !ArgLex.DoParsing( &ArgumentArray ) ) {
+ if( FlagInvalid.QueryFlag() ) {
+ //
+ // invalid switch
+ //
+ DisplayMessage(MSG_FIND_INVALID_SWITCH);
+
+ } else {
+ //
+ // invalid format
+ //
+ DisplayMessage(MSG_FIND_INVALID_FORMAT);
+ }
+ _ErrorLevel = 2;
+ return( FALSE );
+ } else if ( _PathArguments.WildCardExpansionFailed() ) {
+
+ //
+ // No files matched
+ //
+ DisplayMessage(MSG_FIND_FILE_NOT_FOUND, ERROR_MESSAGE, "%W", _PathArguments.GetLexemeThatFailed() );
+
+ _ErrorLevel = 2;
+ return( FALSE );
+
+ } else {
+
+// DebugPrint( "\nargs parsed ok\n" );
+ }
+
+ if( FlagInvalid.QueryFlag() ) {
+ //
+ // invalid switch
+ //
+ DisplayMessage(MSG_FIND_INVALID_SWITCH, ERROR_MESSAGE );
+ _ErrorLevel = 2;
+ return( FALSE );
+ }
+
+ //
+ // - now do semantic checking/processing
+ // - if they ask for help, do it right away and return
+ // - set flags
+ //
+ if( FlagDisplayHelp.QueryFlag() ) {
+ DisplayMessage(MSG_FIND_USAGE);
+ _ErrorLevel = 0;
+ return( FALSE );
+ }
+
+ if( !StringPattern.IsValueSet() ) {
+ DisplayMessage(MSG_FIND_INVALID_FORMAT);
+ _ErrorLevel = 2;
+ return( FALSE );
+ } else {
+ //
+ // - keep a copy of the pattern string
+ //
+
+ DebugAssert(StringPattern.GetString());
+ _PatternString.Initialize(StringPattern.GetString());
+
+// _PatternString.QuerySTR( 0, TO_END, TmpBuf, sizeof( TmpBuf ));
+// DebugPrint("pattern is ");
+// DebugPrint(TmpBuf);
+// DebugPrint("\n");
+ }
+
+ _CaseSensitive = (BOOLEAN)!FlagCaseInsensitive.QueryFlag();
+
+ _LinesContainingPattern = (BOOLEAN)!FlagNegativeSearch.QueryFlag();
+
+ _OutputLines = (BOOLEAN)!FlagCountLines.QueryFlag();
+
+ _OutputLineNumbers = (BOOLEAN)FlagDisplayNumbers.QueryFlag();
+
+ DebugAssert(sprintf(TmpBuf,
+ "flags:caseSens %1d, +veSrch %1d, outLines %1d, line#'s %1d\n",
+ _CaseSensitive, _LinesContainingPattern, _OutputLines,
+ _OutputLineNumbers) > 0);
+// DebugPrint(TmpBuf);
+
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+FIND::IsDos5CompatibleFileName(
+ IN PCPATH Path
+ )
+/*++
+
+Routine Description:
+
+ Parses the path string and returns FALSE if DOS5 would reject
+ the path.
+
+Arguments:
+
+ Path - Supplies the path
+
+Return Value:
+
+ BOOLEAN - Returns FALSE if DOS5 would reject the path,
+ TRUE otherwise
+
+--*/
+
+{
+
+ PWSTRING String;
+
+ DebugPtrAssert( Path );
+
+ String = (PWSTRING)Path->GetPathString();
+
+ DebugPtrAssert( String );
+
+ if ( String->QueryChCount() > 0 ) {
+
+ if ( String->QueryChAt(0) == '\"' ) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+
+}
+
+
+
+ULONG
+FIND::SearchStream(
+ PSTREAM StreamToSearch
+ )
+
+/*++
+
+Routine Description:
+
+ Does the search on an open file_stream.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Number of lines found/not found.
+
+
+--*/
+
+{
+
+ ULONG LineCount;
+ ULONG FoundCount;
+ DWORD PatternLen;
+ DWORD LineLen;
+ DWORD LastPosInLine;
+ BOOLEAN Found;
+ WCHAR c;
+ PWSTR pLine;
+ PWSTR p;
+ WCHAR CurrentLine[MAX_LINE_LEN];
+ WCHAR PatternString[MAX_LINE_LEN];
+ DSTRING dstring;
+ DSTRING _String;
+
+
+
+ LineCount = FoundCount = 0;
+ PatternLen = _PatternString.QueryChCount() ;
+ _PatternString.QueryWSTR(0,TO_END,PatternString,MAX_LINE_LEN,TRUE);
+
+ if ( !_String.Initialize() ) {
+ DebugAbort( "memory alloc failed\n" );
+ }
+
+
+ //
+ // - for each line from stream
+ // - do strstr to see if pattern string is in line
+ // - if -ve search and not in line || +ve search and in line
+ // - output line and number or inc counter appropriately
+ //
+ while( !StreamToSearch->IsAtEnd() ) {
+
+
+ if ( !StreamToSearch->ReadLine( &_String)) {
+ DebugAbort( "ReadLine failed\n" );
+ }
+ _String.QueryWSTR(0,TO_END,CurrentLine,MAX_LINE_LEN,TRUE);
+ LineLen = min ( MAX_LINE_LEN - 1, _String.QueryChCount());
+
+ LineCount++;
+
+ //
+ // - look for pattern string in the current line
+ // - note: a 0-length pattern ("") never matches a line.
+ // A 0-length pattern can produce output with the /v
+ // switch.
+ // - start at the end (saves a var)
+ //
+
+ Found = FALSE;
+
+ // fprintf(stderr, "\n\n%8d>> '%s'\n\n", LineLen, CurrentLine );
+ if ( PatternLen && LineLen >= PatternLen ) {
+ FSTRING TempLine;
+
+ TempLine.Initialize(CurrentLine);
+ if ( _CaseSensitive ) {
+
+ Found = (TempLine.Strstr( &_PatternString ) != INVALID_CHNUM);
+
+ } else {
+
+ pLine = CurrentLine;
+ LastPosInLine = LineLen - PatternLen + 1;
+
+ while ( LastPosInLine-- && !Found ) {
+
+ p = pLine+PatternLen;
+ c = *p;
+ *p = 0;
+
+ Found = !WSTRING::Stricmp(pLine++,PatternString);
+
+ *p = c;
+
+ }
+ }
+ }
+
+ //
+ // - if either (search is +ve and found a match)
+ // or (search is -ve and no match found)
+ // then print line/line number based on options
+ //
+ if( (_LinesContainingPattern && Found)
+ || (!_LinesContainingPattern && !Found) ) {
+
+ FoundCount++;
+ if( _OutputLines ) {
+ dstring.Initialize(CurrentLine);
+ if( _OutputLineNumbers ) {
+ DisplayMessage( MSG_FIND_LINE_AND_NUMBER, NORMAL_MESSAGE, "%d%W", LineCount, &dstring);
+ } else {
+ DisplayMessage( MSG_FIND_LINEONLY, NORMAL_MESSAGE, "%W", &dstring);
+ }
+ }
+ }
+ }
+
+ if (FoundCount) {
+
+ // Set _ErrorLevel to zero to indicate that at least
+ // one match has been found.
+ //
+ _ErrorLevel = 0;
+ }
+ return(FoundCount);
+}
+
+
+
+VOID
+FIND::SearchFiles(
+ )
+
+/*++
+
+Routine Description:
+
+ Does the search on the files specified on the command line.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+// STR nameBuf[ MAX_PATH ];
+ PARRAY PathArray;
+ PARRAY_ITERATOR PIterator;
+ PPATH CurrentPath;
+ PFSN_FILE CurrentFSNode = NULL;
+ PFSN_DIRECTORY CurrentFSDir;
+ PFILE_STREAM CurrentFile = NULL;
+ DSTRING CurrentPathString;
+ ULONG LinesFound;
+
+
+
+ if( !_PathArguments.IsValueSet() ) {
+// DebugPrint( "no paths specified\n" );
+ } else {
+// DebugPrint( "paths specified\n" );
+ }
+
+ //
+ // - if 0 paths on cmdline then open stdin
+ // - if more than one path set OutputName flag
+ //
+ if( (_PathArguments.QueryPathCount() == 0) ) {
+// DebugPrint("PathCount == 0 so searching stdin\n");
+ // use stdin
+ LinesFound = SearchStream( Get_Standard_Input_Stream() );
+ if( !_OutputLines ) {
+ DisplayMessage(MSG_FIND_COUNT, NORMAL_MESSAGE, "%d", LinesFound);
+ }
+ return;
+ }
+
+ PathArray = _PathArguments.GetPathArray();
+ PIterator = (PARRAY_ITERATOR)PathArray->QueryIterator();
+
+ //
+ // - for each path specified on the command line
+ // - open a stream for the path
+ // - print filename if supposed to
+ // - call SearchStream
+ //
+ while( (CurrentPath = (PPATH)PIterator->GetNext()) != NULL ) {
+ CurrentPathString.Initialize( CurrentPath->GetPathString() );
+ CurrentPathString.Strupr();
+
+// ->QuerySTR( 0, TO_END, nameBuf, sizeof(nameBuf));
+// DebugAssert(sprintf(TmpBuf, "path is <%s>\n", nameBuf) > 0);
+// DebugPrint(TmpBuf);
+
+ // if the system object can return a FSN_DIRECTORY for this
+ // path then the user is trying to 'find' on a dir so print
+ // access denied and skip this file
+
+ if( CurrentFSDir = SYSTEM::QueryDirectory(CurrentPath) ) {
+
+ if (CurrentPath->IsDrive()) {
+
+ DisplayMessage(MSG_FIND_FILE_NOT_FOUND, ERROR_MESSAGE, "%W", &CurrentPathString);
+
+ } else {
+
+ DisplayMessage( MSG_ACCESS_DENIED, ERROR_MESSAGE, "%W", &CurrentPathString);
+
+ }
+
+ DELETE( CurrentFSDir );
+ continue;
+ }
+
+
+ if( !(CurrentFSNode = SYSTEM::QueryFile(CurrentPath)) ||
+ !(CurrentFile = CurrentFSNode->QueryStream(READ_ACCESS)) ) {
+
+ //
+ // If the file name is "", DOS5 prints an invalid parameter
+ // format message. There is no clean way to filter this
+ // kind of stuff in the ULIB library, so we will have to
+ // parse the path ourselves.
+ //
+ if ( IsDos5CompatibleFileName( CurrentPath ) ) {
+ DisplayMessage(MSG_FIND_FILE_NOT_FOUND, ERROR_MESSAGE, "%W", &CurrentPathString);
+ } else {
+ DisplayMessage(MSG_FIND_INVALID_FORMAT, ERROR_MESSAGE );
+ break;
+ }
+ DELETE( CurrentFile );
+ DELETE( CurrentFSNode );
+ CurrentFile = NULL;
+ CurrentFSNode = NULL;
+ continue;
+ }
+
+
+ if( _OutputLines ) {
+ DisplayMessage( MSG_FIND_BANNER, NORMAL_MESSAGE, "%W", &CurrentPathString);
+ }
+
+ LinesFound = SearchStream( CurrentFile );
+
+ if( !_OutputLines ) {
+ DisplayMessage(MSG_FIND_COUNT_BANNER, NORMAL_MESSAGE, "%W%d", &CurrentPathString, LinesFound);
+ }
+
+ DELETE( CurrentFSNode );
+ DELETE( CurrentFile );
+ CurrentFSNode = NULL;
+ CurrentFile = NULL;
+ }
+
+ return;
+}
+
+
+
+VOID
+FIND::Terminate(
+ )
+
+/*++
+
+Routine Description:
+
+ Deletes objects created during initialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ exit(_ErrorLevel);
+}
+
+
+
+VOID _CRTAPI1
+main()
+
+{
+ DEFINE_CLASS_DESCRIPTOR( FIND );
+
+ {
+ FIND Find;
+
+ perrstk = NEW ERRSTACK;
+
+ if( Find.Initialize() ) {
+ // DebugPrint("done init\n" );
+ Find.SearchFiles();
+ }
+ Find.Terminate();
+ }
+}
diff --git a/private/utils/find/find.hxx b/private/utils/find/find.hxx
new file mode 100644
index 000000000..c4868ff2b
--- /dev/null
+++ b/private/utils/find/find.hxx
@@ -0,0 +1,101 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ find.hxx
+
+Abstract:
+
+
+Author:
+
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if ! defined( _FIND_ )
+
+#define _FIND_
+
+#include "object.hxx"
+#include "keyboard.hxx"
+#include "program.hxx"
+
+DECLARE_CLASS( FIND );
+
+class FIND : public PROGRAM {
+
+ public:
+
+
+ DECLARE_CONSTRUCTOR( FIND );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsDos5CompatibleFileName(
+ IN PCPATH Path
+ );
+
+ NONVIRTUAL
+ VOID
+ Terminate(
+ );
+
+
+ NONVIRTUAL
+ VOID
+ SearchFiles(
+ );
+
+
+ private:
+
+ NONVIRTUAL
+ ULONG
+ SearchStream(
+ PSTREAM StreamToSearch
+ );
+
+
+ //
+ // TRUE = do a case-sensitive matching
+ //
+ BOOLEAN _CaseSensitive;
+
+ //
+ // TRUE = output lines that contain the pattern
+ //
+ BOOLEAN _LinesContainingPattern;
+
+ //
+ // TRUE = output the lines that match/don't match
+ // FALSE = count the lines that match/don't match
+ //
+ BOOLEAN _OutputLines;
+
+ //
+ // TRUE = output line numbers if lines are being output
+ //
+ BOOLEAN _OutputLineNumbers;
+
+ DSTRING _PatternString;
+
+ MULTIPLE_PATH_ARGUMENT _PathArguments;
+
+ STREAM_MESSAGE _Message;
+ ULONG _ErrorLevel;
+
+};
+
+
+#endif // _FIND_
diff --git a/private/utils/find/find.rc b/private/utils/find/find.rc
new file mode 100644
index 000000000..a5b45f386
--- /dev/null
+++ b/private/utils/find/find.rc
@@ -0,0 +1,11 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Find String (grep) Utility"
+#define VER_INTERNALNAME_STR "find\0"
+#define VER_ORIGINALFILENAME_STR "FIND.EXE"
+
+#include "common.ver"
+
diff --git a/private/utils/find/makefile b/private/utils/find/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/find/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/find/sources b/private/utils/find/sources
new file mode 100644
index 000000000..4ce335d21
--- /dev/null
+++ b/private/utils/find/sources
@@ -0,0 +1,56 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+BLDCRT=1
+
+MAJORCOMP=utils
+MINORCOMP=find
+
+TARGETNAME=find
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+SOURCES=find.cxx find.rc
+
+INCLUDES=..\ulib\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+TARGETLIBS= \
+ ..\ulib\src\obj\*\ulib.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+
+UMTYPE=console
diff --git a/private/utils/findstr/findstr.c b/private/utils/findstr/findstr.c
new file mode 100644
index 000000000..d7aa5c096
--- /dev/null
+++ b/private/utils/findstr/findstr.c
@@ -0,0 +1,2147 @@
+// FINDSTR (used to be QGREP), June 1992
+//
+// Modification History:
+//
+// Aug 1990 PeteS Created.
+// 1990 DaveGi Ported to Cruiser
+// 31-Oct-1990 W-Barry Removed the #ifdef M_I386 'cause this
+// code will never see 16bit again.
+// June 1992 t-petes Added recursive file search in subdirs.
+// Used file mapping instead of multi-thread.
+// Disabled internal switches.
+// Internatioanlized display messages.
+// Made switches case-insensitive.
+// 05/08/93 v-junm Added Japanese search support.
+// 06/03/93 v-junm Added Bilingual Message support>
+
+
+/* About FILEMAP support:
+ * The file mapping object is used to speed up string searches. The new
+ * file mapping method is coded as #ifdef-#else-#endif to show the
+ * changes needed to be made. The old code(non-filemapping) has a read
+ * buffer like this:
+ *
+ * filbuf[] = {.....................................}
+ * ^ ^
+ * BegPtr EndPtr
+ *
+ * This means there are some spare space before BegPtr and after EndPtr
+ * for the search algorithm to work its way. The old code also
+ * occasionally modifies filbuf[](like filbuf[i] = '\n';).
+ *
+ * The new code(filemapping) must avoid doing all of the above because
+ * there are no spare space before BegPtr or after EndPtr when mapping
+ * view of the file which is opened as read-only.
+ */
+
+#include <stdio.h>
+#include <time.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <io.h>
+#include <windows.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include <stdarg.h>
+#include "fsmsg.h"
+
+#define FILBUFLEN (SECTORLEN*2)
+
+#define FILNAMLEN 80 // File name length
+#define ISCOT 0x0002 // Handle is console output
+#define LG2SECLEN 10 // Log base two of sector length
+#define LNOLEN 12 // Maximum line number length
+#define MAXSTRLEN 128 // Maximum search string length
+#define OUTBUFLEN (SECTORLEN*2) // Output buffer length
+#define PATHLEN (MAX_PATH+2) // Path buffer length
+#define SECTORLEN (1 << LG2SECLEN) // Sector length
+#define STKLEN 512 // Stack length in bytes
+#define TRTABLEN 256 // Translation table length
+#define s_text(x) (((char *)(x)) - ((x)->s_must)) // Text field access macro
+#define EOS ('\r') // End of string
+
+
+// Bit flag definitions
+
+#define SHOWNAME 0x01 // Print filename
+#define NAMEONLY 0x02 // Print filename only
+#define LINENOS 0x04 // Print line numbers
+#define BEGLINE 0x08 // Match at beginning of line
+#define ENDLINE 0x10 // Match at end of line
+#define DEBUG 0x20 // Print debugging output
+#define TIMER 0x40 // Time execution
+#define SEEKOFF 0x80 // Print seek offsets
+#define PRINTABLE_ONLY 0x100 // Skip files with non-printable characters
+
+
+// Type definitions
+
+typedef struct stringnode {
+ struct stringnode *s_alt; // List of alternates
+ struct stringnode *s_suf; // List of suffixes
+ int s_must; // Length of portion that must match
+}
+ STRINGNODE; // String node
+
+typedef ULONG CBIO; // I/O byte count
+typedef ULONG PARM; // Generic parameter
+
+typedef CBIO *PCBIO; // Pointer to I/O byte count
+typedef PARM *PPARM; // Pointer to generic parameter
+
+
+// Global data
+
+char *BaseByteAddress = NULL; // File mapping base address
+BOOL bStdIn = FALSE; // Std-input file flag
+
+#ifdef DBCS // v-junm - 05/06/93
+// Global flag. If TRUE, then current console code page is JP. Otherwise
+// set to FALSE.
+
+BOOL IsJPCP;
+
+#endif // DBCS
+
+char filbuf[FILBUFLEN*2L + 12];
+char outbuf[OUTBUFLEN*2];
+char td1[TRTABLEN] = { 0 };
+unsigned cchmin = (unsigned)(-1); // Minimum string length
+unsigned chmax = 0; // Maximum character
+unsigned chmin = (unsigned)(-1); // Minimum character
+char transtab[TRTABLEN] = { 0 };
+STRINGNODE *stringlist[TRTABLEN/2];
+int casesen = 1; // Assume case-sensitivity
+long cbfile; // Number of bytes in file
+static int clists = 1; // One is first available index
+int filbuflen = FILBUFLEN; // File buffer length
+int flags; // Flags
+unsigned lineno; // Current line number
+char *program; // Program name
+int status = 1; // Assume failure
+int strcnt = 0; // String count
+char target[MAXSTRLEN]; // Last string added
+int targetlen; // Length of last string added
+unsigned waste; // Wasted storage in heap
+
+int arrc; // I/O return code for DOSREAD
+char asyncio; // Asynchronous I/O flag
+int awrc = TRUE; // I/O return code for DOSWRITE
+char *bufptr[] = { filbuf + 4, filbuf + FILBUFLEN + 8 };
+CBIO cbread; // Bytes read by DOSREAD
+CBIO cbwrite; // Bytes written by DOSWRITE
+char *obuf[] = { outbuf, outbuf + OUTBUFLEN };
+int ocnt[] = { OUTBUFLEN, OUTBUFLEN };
+int oi = 0; // Output buffer index
+char *optr[] = { outbuf, outbuf + OUTBUFLEN };
+char pmode; // Protected mode flag
+
+
+// External functions and forward references
+
+void printmessage(FILE *fp, DWORD messagegID, ...);
+ // Message display function for internationalization
+
+int filematch(char *pszfile,char **ppszpat,int cpat);
+
+#ifdef DBCS // v-junm - 05/06/93
+// Function to check if a certain location in a string is the second byte
+// of a DBCS character.
+int IsTailByte( unsigned const char *, const int );
+int _mbsnicmp( const unsigned char *, const unsigned char *, int, BOOL * );
+unsigned char *_mbslwr( unsigned char * );
+char *_mbsrchr( const char *, int );
+#endif // DBCS
+
+void addexpr( char *, int ); // See QMATCH.C
+void addstring( char *, int ); // See below
+int countlines( char *, char * );
+char *findexpr( unsigned char *, char *); // See QMATCH.C
+char *findlist( unsigned char *, char * );
+char *findone( unsigned char *buffer, char *bufend );
+void flush1buf( void ); // See below
+void flush1nobuf( void ); // See below
+int grepbuffer( char *, char *, char * ); // See below
+int isexpr( unsigned char *, int ); // See QMATCH.C
+void matchstrings( char *, char *, int, int *, int * );
+int preveol( char * );
+int strncspn( char *, char *, int );
+int strnspn( char *, char *, int );
+char *strnupr( char *pch, int cch );
+void write1buf( char *, int ); // See below
+void (*addstr)( char *, int ) = NULL;
+char *(*find)( unsigned char *, char * ) = NULL;
+void (*flush1)( void ) = flush1buf;
+int (*grep)( char *, char *, char * ) = grepbuffer;
+void (*write1)( char *, int ) = write1buf;
+void write1nobuf( char *, int );
+
+int
+has_wild_cards(
+ char* p
+ )
+{
+ if (!p)
+ return 0;
+
+ for (; *p; p++) {
+ if (*p == '?' || *p == '*') {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
+void
+error(
+ DWORD messageID
+ )
+{
+ printmessage(stderr, messageID, program);
+ // Print message
+ exit(2); // Die
+}
+
+
+char *
+alloc(
+ unsigned size
+ )
+{
+ char *cp; // Char pointer
+
+ if((cp = (char *) malloc(size)) == NULL) { // If allocation fails
+ printmessage(stderr, MSG_FINDSTR_OUT_OF_MEMORY, program);
+ // Write error message
+ exit(2); // Die
+ }
+ return(cp); // Return pointer to buffer
+}
+
+
+void
+freenode(
+ STRINGNODE *x
+ )
+{
+ register STRINGNODE *y; // Pointer to next node in list
+
+ while(x != NULL) { // While not at end of list
+ if(x->s_suf != NULL)
+ freenode(x->s_suf); // Free suffix list if not end
+ else
+ --strcnt; // Else decrement string count
+ y = x; // Save pointer
+ x = x->s_alt; // Move down the list
+ free((char *)((int) s_text(y) & ~3));
+ // Free the node
+ }
+}
+
+
+STRINGNODE *
+newnode(
+ char *s,
+ int n
+ )
+{
+ register STRINGNODE *newNode; // Pointer to new node
+ char *t; // String pointer
+ int d; // rounds to a dword boundary
+
+ d = n & 3 ? 4 - (n & 3) : 0; // offset to next dword past n
+ t = alloc(sizeof(STRINGNODE) + n + d);
+ // Allocate string node
+ t += d; // END of string word-aligned
+ strncpy(t,s,n); // Copy string text
+ newNode = (STRINGNODE *)(t + n); // Set pointer to node
+ newNode->s_alt = NULL; // No alternates yet
+ newNode->s_suf = NULL; // No suffixes yet
+ newNode->s_must = n; // Set string length
+ return(newNode); // Return pointer to new node
+}
+
+
+STRINGNODE *
+reallocnode(
+ STRINGNODE *node,
+ char *s,
+ int n
+ )
+{
+ register char *cp; // Char pointer
+
+ assert(n <= node->s_must); // Node must not grow
+ waste += (unsigned)(node->s_must - n);
+ // Add in wasted space
+ assert(sizeof(char *) == sizeof(int));
+ // Optimizer should eliminate this
+ cp = (char *)((int) s_text(node) & ~3);
+ // Point to start of text
+ node->s_must = n; // Set new length
+ if(n & 3)
+ cp += 4 - (n & 3); // Adjust non dword-aligned string
+ memmove(cp,s,n); // Copy new text
+ cp += n; // Skip over new text
+ memmove(cp,node,sizeof(STRINGNODE));// Copy the node
+ return((STRINGNODE *) cp); // Return pointer to moved node
+}
+
+
+/*** maketd1 - add entry for TD1 shift table
+ *
+ * This function fills in the TD1 table for the given
+ * search string. The idea is adapted from Daniel M.
+ * Sunday's QuickSearch algorithm as described in an
+ * article in the August 1990 issue of "Communications
+ * of the ACM". As described, the algorithm is suitable
+ * for single-string searches. The idea to extend it for
+ * multiple search strings is mine and is described below.
+ *
+ * Think of searching for a match as shifting the search
+ * pattern p of length n over the source text s until the
+ * search pattern is aligned with matching text or until
+ * the end of the source text is reached.
+ *
+ * At any point when we find a mismatch, we know
+ * we will shift our pattern to the right in the
+ * source text at least one position. Thus,
+ * whenever we find a mismatch, we know the character
+ * s[n] will figure in our next attempt to match.
+ *
+ * For some character c, TD1[c] is the 1-based index
+ * from right to left of the first occurrence of c
+ * in p. Put another way, it is the count of places
+ * to shift p to the right on s so that the rightmost
+ * c in p is aligned with s[n]. If p does not contain
+ * c, then TD1[c] = n + 1, meaning we shift p to align
+ * p[0] with s[n + 1] and try our next match there.
+ *
+ * Computing TD1 for a single string is easy:
+ *
+ * memset(TD1,n + 1,sizeof TD1);
+ * for (i = 0; i < n; ++i) {
+ * TD1[p[i]] = n - i;
+ * }
+ *
+ * Generalizing this computation to a case where there
+ * are multiple strings of differing lengths is trickier.
+ * The key is to generate a TD1 that is as conservative
+ * as necessary, meaning that no shift value can be larger
+ * than one plus the length of the shortest string for
+ * which you are looking. The other key is to realize
+ * that you must treat each string as though it were only
+ * as long as the shortest string. This is best illustrated
+ * with an example. Consider the following two strings:
+ *
+ * DYNAMIC PROCEDURE
+ * 7654321 927614321
+ *
+ * The numbers under each letter indicate the values of the
+ * TD1 entries if we computed the array for each string
+ * separately. Taking the union of these two sets, and taking
+ * the smallest value where there are conflicts would yield
+ * the following TD1:
+ *
+ * DYNAMICPODURE
+ * 7654321974321
+ *
+ * Note that TD1['P'] equals 9; since n, the length of our
+ * shortest string is 7, we know we should not have any
+ * shift value larger than 8. If we clamp our shift values
+ * to this value, then we get
+ *
+ * DYNAMICPODURE
+ * 7654321874321
+ *
+ * Already, this looks fishy, but let's try it out on
+ * s = "DYNAMPROCEDURE". We know we should match on
+ * the trailing procedure, but watch:
+ *
+ * DYNAMPROCEDURE
+ * ^^^^^^^|
+ *
+ * Since DYNAMPR doesn't match one of our search strings,
+ * we look at TD1[s[n]] == TD1['O'] == 7. Applying this
+ * shift, we get
+ *
+ * DYNAMPROCEDURE
+ * ^^^^^^^
+ *
+ * As you can see, by shifting 7, we have gone too far, and
+ * we miss our match. When computing TD1 for "PROCEDURE",
+ * we must take only the first 7 characters, "PROCEDU".
+ * Any trailing characters can be ignored (!) since they
+ * have no effect on matching the first 7 characters of
+ * the string. Our modified TD1 then becomes
+ *
+ * DYNAMICPODURE
+ * 7654321752163
+ *
+ * When applied to s, we get TD1[s[n]] == TD1['O'] == 5,
+ * leaving us with
+ *
+ * DYNAMPROCEDURE
+ * ^^^^^^^
+ * which is just where we need to be to match on "PROCEDURE".
+ *
+ * Going to this algorithm has speeded qgrep up on multi-string
+ * searches from 20-30%. The all-C version with this algorithm
+ * became as fast or faster than the C+ASM version of the old
+ * algorithm. Thank you, Daniel Sunday, for your inspiration!
+ *
+ * Note: if we are case-insensitive, then we expect the input
+ * string to be upper-cased on entry to this routine.
+ *
+ * Pete Stewart, August 14, 1990.
+ */
+
+void
+maketd1(
+ unsigned char *pch,
+ unsigned cch,
+ unsigned cchstart
+ )
+{
+ unsigned ch; // Character
+ unsigned i; // String index
+
+ if ((cch += cchstart) > cchmin)
+ cch = cchmin; // Use smaller count
+ for (i = cchstart; i < cch; ++i) { // Examine each char left to right
+ ch = *pch++; // Get the character
+ for (;;) { // Loop to set up entries
+ if (ch < chmin)
+ chmin = ch; // Remember if smallest
+ if (ch > chmax)
+ chmax = ch; // Remember if largest
+ if (cchmin - i < (unsigned) td1[ch])
+ td1[ch] = (unsigned char)(cchmin - i);
+ // Set value if smaller than previous
+ if (casesen || !isascii(ch) || !isupper(ch))
+ break; // Exit loop if done
+ ch = _tolower(ch); // Force to lower case
+ }
+ }
+}
+
+static int
+newstring(
+ unsigned char *s,
+ int n
+ )
+{
+ register STRINGNODE *cur; // Current string
+ register STRINGNODE **pprev; // Pointer to previous link
+ STRINGNODE *newNode; // New string
+ int i; // Index
+ int j; // Count
+ int k; // Count
+
+ if ( (unsigned)n < cchmin)
+ cchmin = n; // Remember length of shortest string
+ if((i = transtab[*s]) == 0) { // If no existing list
+
+ // We have to start a new list
+
+ if((i = clists++) >= TRTABLEN/2)
+ error(MSG_FINDSTR_TOO_MANY_STRING_LISTS); //"Too many string lists");
+ // Die if too many string lists
+ stringlist[i] = NULL; // Initialize
+ transtab[*s] = (char) i; // Set pointer to new list
+ if(!casesen && isalpha(*s))
+ transtab[*s ^ '\040'] = (char) i; // Set pointer for other case
+ }
+ else
+ if(stringlist[i] == NULL)
+ return(0); // Check for existing 1-byte string
+ if(--n == 0) { // If 1-byte string
+ freenode(stringlist[i]); // Free any existing stuff
+ stringlist[i] = NULL; // No record here
+ ++strcnt; // We have a new string
+ return(1); // String added
+ }
+ ++s; // Skip first char
+ pprev = stringlist + i; // Get pointer to link
+ cur = *pprev; // Get pointer to node
+ while(cur != NULL) { // Loop to traverse match tree
+ i = (n > cur->s_must)? cur->s_must: n;
+ // Find minimum of string lengths
+ matchstrings((char *)s, s_text(cur), i, &j, &k);
+ // Compare the strings
+ if(j == 0) { // If complete mismatch
+ if(k < 0)
+ break; // Break if insertion point found
+ pprev = &(cur->s_alt); // Get pointer to alternate link
+ cur = *pprev; // Follow the link
+ } else if(i == j) { // Else if strings matched
+ if(i == n) { // If new is prefix of current
+ cur = *pprev = reallocnode(cur,s_text(cur),n);
+ // Shorten text of node
+ if(cur->s_suf != NULL) { // If there are suffixes
+ freenode(cur->s_suf);
+ // Suffixes no longer needed
+ cur->s_suf = NULL;
+ ++strcnt; // Account for this string
+ }
+ return(1); // String added
+ }
+ pprev = &(cur->s_suf); // Get pointer to suffix link
+ if((cur = *pprev) == NULL) return(0);
+ // Done if current is prefix of new
+ s += i; // Skip matched portion
+ n -= i;
+ } else { // Else partial match
+
+ // We must split an existing node.
+ // This is the trickiest case.
+
+ newNode = newnode(s_text(cur) + j,cur->s_must - j);
+ // Unmatched part of current string
+ cur = *pprev = reallocnode(cur,s_text(cur),j);
+ // Set length to matched portion
+ newNode->s_suf = cur->s_suf; // Current string's suffixes
+ if(k < 0) { // If new preceded current
+ cur->s_suf = newnode((char *)s + j,n - j);
+ // FIrst suffix is new string
+ cur->s_suf->s_alt = newNode;// Alternate is part of current
+ } else { // Else new followed current
+ newNode->s_alt = newnode((char *)(s + j), n - j);
+ // Unmatched new string is alternate
+ cur->s_suf = newNode; // New suffix list
+ }
+ ++strcnt; // One more string
+ return(1); // String added
+ }
+ }
+ *pprev = newnode((char *)s, n); // Set pointer to new node
+ (*pprev)->s_alt = cur; // Attach alternates
+ ++strcnt; // One more string
+ return(1); // String added
+}
+
+
+void
+addstring(
+ char *s,
+ int n
+ )
+{
+ int endline; // Match-at-end-of-line flag
+ register char *pch; // Char pointer
+
+ endline = flags & ENDLINE; // Initialize flag
+ pch = target; // Initialize pointer
+ while(n-- > 0) { // While not at end of string
+ switch(*pch = *s++) { // Switch on character
+ case '\\': // Escape
+ if(n > 0 && !isalnum(*s)) { // If next character "special"
+ --n; // Decrement counter
+ *pch = *s++; // Copy next character
+ }
+ ++pch; // Increment pointer
+ break;
+
+ default: // All others
+ ++pch; // Increment pointer
+ break;
+ }
+ }
+ if(endline)
+ *pch++ = EOS; // Add end character if needed
+ targetlen = pch - target; // Compute target string length
+ if (!casesen)
+ strnupr(target,targetlen); // Force to upper case if necessary
+ newstring((unsigned char *)target, targetlen); // Add string
+ }
+
+
+int
+addstrings(
+ char *buffer,
+ char *bufend,
+ char *seplist
+ )
+{
+ int len; // String length
+ char tmpbuf[MAXSTRLEN+2];
+
+ while(buffer < bufend) { // While buffer not empty
+ len = strnspn(buffer,seplist,bufend - buffer);
+ // Count leading separators
+ if((buffer += len) >= bufend) {
+ break; // Skip leading separators
+ }
+ len = strncspn(buffer,seplist,bufend - buffer);
+ // Get length of search string
+ if(addstr == NULL) {
+ addstr = isexpr( (unsigned char *) buffer, len ) ? addexpr : addstring;
+ // Select search string type
+ }
+
+ if (len >= MAXSTRLEN)
+ error(MSG_FINDSTR_SEARCH_STRING_TOO_LONG);
+
+ memcpy(tmpbuf, buffer, len);
+ tmpbuf[len] = '\n';
+
+ if( addstr == addexpr || (flags & BEGLINE) ||
+ findlist((unsigned char *)tmpbuf, tmpbuf + len + 1) == NULL) {
+ // If no match within string
+ (*addstr)(buffer,len); // Add string to list
+ }
+
+ buffer += len; // Skip the string
+ }
+ return(0); // Keep looking
+}
+
+
+int
+enumlist(
+ STRINGNODE *node,
+ int cchprev
+ )
+{
+ int strcnt; // String count
+
+ strcnt = 0; // Initialize
+ while(node != NULL) { // While not at end of list
+ maketd1((unsigned char *)s_text(node), node->s_must, cchprev);
+ // Make TD1 entries
+
+#if DBG
+ if (flags & DEBUG) { // If verbose output wanted
+ int i; // Counter
+
+
+ for(i = 0; i < cchprev; ++i)
+ fputc(' ', stderr); // Indent line
+ fwrite(s_text(node), sizeof(char), node->s_must, stderr);
+ // Write this portion
+ fprintf(stderr,"\n"); // Newline
+ }
+#endif
+
+ strcnt += (node->s_suf != NULL) ?
+ enumlist(node->s_suf,cchprev + node->s_must): 1;
+ // Recurse to do suffixes
+ node = node->s_alt; // Do next alternate in list
+ }
+ return(strcnt? strcnt: 1); // Return string count
+}
+
+int
+enumstrings()
+{
+ char ch; // Character
+ int i; // Index
+ int strcnt; // String count
+
+ strcnt = 0; // Initialize
+ for(i = 0; i < TRTABLEN; ++i) { // Loop through translation table
+ if (casesen || !isascii(i) || !islower(i)) {
+ // If case sensitive or not lower
+ if(transtab[i] == 0)
+ continue; // Skip null entries
+ ch = (char) i; // Get character
+ maketd1((unsigned char *)&ch, 1, 0); // Make TD1 entry
+
+#if DBG
+ if (flags & DEBUG)
+ fprintf(stderr,"%c\n",i); // Print the first byte
+#endif
+
+ strcnt += enumlist(stringlist[transtab[i]],1);
+ // Enumerate the list
+ }
+ }
+ return(strcnt); // Return string count
+}
+
+
+HANDLE
+openfile(
+ char *name
+ )
+{
+ HANDLE fd;
+ DWORD attr;
+
+ attr = GetFileAttributes(name);
+
+ if(attr != (DWORD) -1 && (attr & FILE_ATTRIBUTE_DIRECTORY))
+ return (HANDLE)-1;
+
+ if((fd = CreateFile(name,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL)) == (HANDLE)-1) {
+
+ printmessage(stderr, MSG_FINDSTR_CANNOT_OPEN_FILE, program,name);
+ }
+ return( fd ); // Return file descriptor
+}
+
+
+
+void
+startread(
+ HANDLE fd,
+ char *buffer,
+ int buflen
+ )
+{
+ if(bStdIn)
+ arrc = ReadFile(fd,(PVOID)buffer,buflen, &cbread, NULL);
+}
+
+
+
+int
+finishread()
+{
+ return(arrc ? cbread : -1); // Return number of bytes read
+}
+
+
+
+void
+startwrite( HANDLE fd, char *buffer, int buflen)
+{
+ awrc = WriteFile(fd,(PVOID)buffer,buflen, &cbwrite, NULL);
+ return;
+}
+
+
+int
+finishwrite()
+{
+ return(awrc ? cbwrite : -1); // Return number of bytes written
+}
+
+
+
+void
+write1nobuf(
+ char *buffer,
+ int buflen
+ )
+{
+ CBIO cb; // Count of bytes written
+
+ if(!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),(PVOID)buffer,buflen, &cb, NULL)
+ || (cb != (CBIO)buflen))
+ {
+ error(MSG_FINDSTR_WRITE_ERROR); // Die if write fails
+ }
+}
+
+
+void
+write1buf(
+ char *buffer,
+ int buflen
+ )
+{
+ register int cb; // Byte count
+
+ while(buflen > 0) { // While bytes remain
+ if(!awrc) { // If previous write failed
+ printmessage(stderr, MSG_FINDSTR_WRITE_ERROR, program); // Print error message
+ exit(2); // Die
+ }
+ if((cb = ocnt[oi]) == 0) { // If buffer full
+ startwrite( GetStdHandle( STD_OUTPUT_HANDLE ), obuf[oi], OUTBUFLEN );
+ // Write the buffer
+ ocnt[oi] = OUTBUFLEN; // Reset count and pointer
+ optr[oi] = obuf[oi];
+ oi ^= 1; // Switch buffers
+ cb = ocnt[oi]; // Get space remaining
+ }
+ if(cb > buflen)
+ cb = buflen; // Get minimum
+ memmove(optr[oi],buffer,cb); // Copy bytes to buffer
+ ocnt[oi] -= cb; // Update buffer length and pointers
+ optr[oi] += cb;
+ buflen -= cb;
+ buffer += cb;
+ }
+}
+
+
+void
+flush1nobuf(
+ void
+ )
+{
+ ;
+}
+
+
+void
+flush1buf(
+ void
+ )
+{
+ register int cb; // Byte count
+
+ if((cb = OUTBUFLEN - ocnt[oi]) > 0) { // If buffer not empty
+ startwrite( GetStdHandle( STD_OUTPUT_HANDLE ), obuf[oi], cb ); // Start write
+ if(finishwrite() != cb) { // If write failed
+ printmessage(stderr, MSG_FINDSTR_WRITE_ERROR, program); // Print error message
+ exit(2); // Die
+ }
+ }
+}
+
+
+int
+grepbuffer(
+ char *startbuf,
+ char *endbuf,
+ char *name
+ )
+{
+ char *cp; // Buffer pointer
+ char *lastmatch; // Last matching line
+ int linelen; // Line length
+ int namlen = 0; // Length of name
+ char lnobuf[LNOLEN]; // Line number buffer
+ char nambuf[PATHLEN]; // Name buffer
+
+ cp = startbuf; // Initialize to start of buffer
+ lastmatch = cp; // No previous match yet
+ while((cp = (*find)((unsigned char *)cp, endbuf)) != NULL) {
+ // While matches are found
+ --cp; // Back up to previous character
+
+ // Take care of '\n' as an artificial newline before line 1.
+ if((flags & BEGLINE) && (bStdIn || cp >= BaseByteAddress) && *cp != '\n' ) {
+ // If begin line conditions not met
+ cp += strncspn(cp,"\n",endbuf - cp) + 1;
+ // Skip line
+ continue; // Keep looking
+ }
+ status = 0; // Match found
+ if(flags & NAMEONLY)
+ return(1); // Return if filename only wanted
+ cp -= preveol(cp) - 1; // Point at start of line
+ if(flags & SHOWNAME) { // If name wanted
+ if(namlen == 0) { // If name not formatted yet
+ namlen = sprintf(nambuf,"%s:",name);
+ // Format name if not done already
+ }
+ (*write1)(nambuf,namlen); // Show name
+ }
+ if(flags & LINENOS) { // If line number wanted
+ lineno += countlines(lastmatch,cp);
+ // Count lines since last match
+ (*write1)(lnobuf,sprintf(lnobuf,"%u:",lineno));
+ // Print line number
+ lastmatch = cp; // New last match
+ }
+ if(flags & SEEKOFF) { // If seek offset wanted
+ (*write1)(lnobuf,sprintf(lnobuf,"%lu:",
+ cbfile + (long)(cp - startbuf)));
+ // Print seek offset
+ }
+ linelen = strncspn(cp,"\n",endbuf - cp) + 1;
+ // Calculate line length
+ if (linelen > endbuf - cp) {
+ linelen = endbuf - cp;
+ }
+ (*write1)(cp,linelen); // Print the line
+ cp += linelen; // Skip the line
+ }
+ if(flags & LINENOS)
+ lineno += countlines(lastmatch,endbuf);
+ // Count remaining lines in buffer
+ return(0); // Keep searching
+}
+
+
+void
+showv(
+ char *name,
+ char *startbuf,
+ char *lastmatch,
+ char *thismatch
+ )
+{
+ register int linelen;
+ int namlen = 0; // Length of name
+ char lnobuf[LNOLEN]; // Line number buffer
+ char nambuf[PATHLEN];// Name buffer
+
+ if(flags & (SHOWNAME | LINENOS | SEEKOFF)) {
+ while(lastmatch < thismatch) {
+ if(flags & SHOWNAME) { // If name wanted
+ if(namlen == 0) { // If name not formatted yet
+ namlen = sprintf(nambuf,"%s:",name);
+ // Format name if not done already
+ }
+ (*write1)(nambuf,namlen);
+ // Write the name
+ }
+ if(flags & LINENOS) // If line numbers wanted
+ {
+ (*write1)(lnobuf,sprintf(lnobuf,"%u:",lineno++));
+ // Print the line number
+ }
+ if(flags & SEEKOFF) { // If seek offsets wanted
+ (*write1)(lnobuf,sprintf(lnobuf,"%lu:",
+ cbfile + (long)(lastmatch - startbuf)));
+ // Print the line number
+ }
+ linelen = strncspn(lastmatch,"\n",thismatch - lastmatch);
+ // If there's room for the '\n' then suck it in. Otherwise
+ // the buffer doesn't have a '\n' within the range here.
+ if (linelen < thismatch - lastmatch) {
+ linelen++;
+ }
+ (*write1)(lastmatch,linelen);
+ lastmatch += linelen;
+ }
+ }
+ else
+ (*write1)(lastmatch,thismatch - lastmatch);
+}
+
+
+int
+grepvbuffer(
+ char *startbuf,
+ char *endbuf,
+ char *name
+ )
+{
+ char *cp; // Buffer pointer
+ char *lastmatch; // Pointer to line after last match
+
+ cp = startbuf; // Initialize to start of buffer
+ lastmatch = cp;
+ while((cp = (*find)((unsigned char *)cp, endbuf)) != NULL) {
+ --cp; // Back up to previous character
+
+ // Take care of '\n' as an artificial newline before line 1.
+ if((flags & BEGLINE) && (bStdIn || cp >= BaseByteAddress) && *cp != '\n') {
+ // If begin line conditions not met
+ cp += strncspn(cp,"\n",endbuf - cp) + 1;
+ // Skip line
+ continue; // Keep looking
+ }
+ cp -= preveol(cp) - 1; // Point at start of line
+ if(cp > lastmatch) { // If we have lines without matches
+ status = 0; // Lines without matches found
+ if(flags & NAMEONLY) return(1);
+ // Skip rest of file if NAMEONLY
+ showv(name,startbuf,lastmatch,cp);
+ // Show from last match to this
+ }
+ cp += strncspn(cp,"\n",endbuf - cp) + 1;
+ // Skip over line with match
+ lastmatch = cp; // New "last" match
+ ++lineno; // Increment line count
+ }
+ if(endbuf > lastmatch) { // If we have lines without matches
+ status = 0; // Lines without matches found
+ if(flags & NAMEONLY)
+ return(1); // Skip rest of file if NAMEONLY
+ showv(name,startbuf,lastmatch,endbuf);
+ // Show buffer tail
+ }
+ return(0); // Keep searching file
+}
+
+
+void
+qgrep(
+ int (*grep)( char *, char *, char * ),
+ char *name,
+ HANDLE fd
+ )
+{
+ register int cb; // Byte count
+ char *cp; // Buffer pointer
+ char *endbuf; // End of buffer
+ int taillen; // Length of buffer tail
+ int bufi; // Buffer index
+ HANDLE MapHandle; // File mapping handle
+ BOOL grep_result;
+
+ cbfile = 0L; // File empty so far
+ lineno = 1; // File starts on line 1
+ taillen = 0; // No buffer tail yet
+ bufi = 0; // Initialize buffer index
+ cp = bufptr[0]; // Initialize to start of buffer
+
+ bStdIn = (fd == GetStdHandle(STD_INPUT_HANDLE));
+
+ // If fd is not std-input, use file mapping object method.
+
+ if(!bStdIn) {
+ if((((cbread = (CBIO)GetFileSize(fd, NULL)) == -1) && (GetLastError() != NO_ERROR)) ||
+ (cbread == 0)
+ )
+ return; // skip the file
+
+ MapHandle = CreateFileMapping(fd,
+ NULL,
+ PAGE_READONLY,
+ 0L,
+ 0L,
+ NULL);
+ if (MapHandle == NULL) {
+ CloseHandle(fd);
+ printmessage(stderr, MSG_FINDSTR_CANNOT_CREATE_FILE_MAPPING, program);
+ exit(2);
+ }
+
+ BaseByteAddress = (char *) MapViewOfFile(MapHandle,
+ FILE_MAP_READ,
+ 0L,
+ 0L,
+ 0);
+ CloseHandle(MapHandle);
+ if (BaseByteAddress == NULL) {
+ CloseHandle(fd);
+ printmessage(stderr, MSG_FINDSTR_CANNOT_MAP_VIEW, program);
+ exit(2);
+ }
+
+ cp = bufptr[0] = BaseByteAddress;
+ arrc = TRUE;
+ } else {
+ // Reset buffer pointers since they might have been changed.
+ cp = bufptr[0] = filbuf + 4;
+
+ arrc = ReadFile(fd, (PVOID)cp, filbuflen, &cbread, NULL);
+ }
+
+ if (flags & PRINTABLE_ONLY) {
+ char *s;
+ unsigned long n;
+
+ s = cp;
+ n = cbread;
+ while (--n) {
+ if (*s < ' ') {
+
+ // If not backspace, tab, CR, LF, FF or Ctrl-Z then not a printable character.
+
+ if (strchr("\b\t\v\r\n\f\032", *s) == NULL) {
+ goto skipfile;
+ }
+ }
+
+ s += 1;
+ }
+ }
+
+ // Note: if FILEMAP && !bStdIn, 'while' is executed once(taillen is 0).
+ while((cb = finishread()) + taillen > 0) {
+ // While search incomplete
+
+ if(bStdIn) {
+ if(cb == 0) { // If buffer tail is all that's left
+ *cp++ = '\r'; // Add end of line sequence
+ *cp++ = '\n';
+ endbuf = cp; // Note end of buffer
+ taillen = 0; // Set tail length to zero
+
+ } else { // Else start next read
+
+ taillen = preveol(cp + cb - 1); // Find length of partial line
+ endbuf = cp + cb - taillen; // Get pointer to end of buffer
+ cp = bufptr[bufi ^ 1]; // Pointer to other buffer
+ memmove(cp,endbuf,taillen); // Copy tail to head of other buffer
+ cp += taillen; // Skip over tail
+ startread(fd,cp,(filbuflen - taillen) & (~0 << LG2SECLEN));
+ // Start next read
+ }
+ } else {
+ endbuf = cp + cb - taillen; // Get pointer to end of buffer
+
+ // Cause 'while' to terminate(since no next read is needed.)
+ cbread = 0;
+ arrc = TRUE;
+ }
+
+ __try {
+ grep_result = (*grep)(bufptr[bufi],endbuf,name);
+ } __except( GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR ) {
+ printmessage(stderr, MSG_FINDSTR_READ_ERROR, program, name);
+ break;
+ }
+
+ if(grep_result) { // If rest of file can be skipped
+ (*write1)(name,strlen(name));
+ // Write file name
+ (*write1)("\r\n",2); // Write newline sequence
+
+ if(!bStdIn) {
+ if(BaseByteAddress != NULL)
+ UnmapViewOfFile(BaseByteAddress);
+ }
+
+ return; // Skip rest of file
+ }
+
+ cbfile += (long)(endbuf - bufptr[bufi]);
+ // Increment count of bytes in file
+ bufi ^= 1; // Switch buffers
+ }
+
+skipfile:
+ if(!bStdIn) {
+ if(BaseByteAddress != NULL)
+ UnmapViewOfFile(BaseByteAddress);
+ }
+}
+
+
+char *
+rmpath(
+ char *name
+ )
+{
+ char *cp; // Char pointer
+
+ if(name[0] != '\0' && name[1] == ':')
+ name += 2; // Skip drive spec if any
+ cp = name; // Point to start
+ while(*name != '\0') { // While not at end
+ ++name; // Skip to next character
+ if(name[-1] == '/' || name[-1] == '\\') cp = name;
+ // Point past path separator
+ }
+ return(cp); // Return pointer to name
+}
+
+
+void
+prepend_path(
+ char* file_name,
+ char* path
+ )
+{
+ int path_len;
+ char* last;
+
+ // First figure out how much of the path to take.
+ // Check for the last occurance of '\' if there is one.
+
+#ifdef DBCS // v-junm - 06/25/93
+// DBCS tailbytes can contain '\' character. Use MBCS function.
+ last = _mbsrchr(path, '\\');
+#else
+ last = strrchr(path, '\\');
+#endif // DBCS
+ if (last) {
+ path_len = last - path + 1;
+ } else if (path[1] == ':') {
+ path_len = 2;
+ } else {
+ path_len = 0;
+ }
+
+ memmove(file_name + path_len, file_name, strlen(file_name) + 1);
+ memmove(file_name, path, path_len);
+}
+
+
+void
+ConvertAppToOem(
+ unsigned argc,
+ char* argv[]
+ )
+/*++
+
+Routine Description:
+
+ Converts the command line from ANSI to OEM, and force the app
+ to use OEM APIs
+
+Arguments:
+
+ argc - Standard C argument count.
+
+ argv - Standard C argument strings.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ unsigned i;
+
+ for( i=0; i<argc; i++ ) {
+ CharToOem( argv[i], argv[i] );
+ }
+ SetFileApisToOEM();
+}
+
+
+int _CRTAPI1
+main(
+ int argc,
+ char **argv
+ )
+{
+ char *cp;
+
+ HANDLE fd;
+
+ FILE *fi;
+ int fsubdirs; // Search subdirectories
+ int i;
+ int j;
+ char *inpfile = NULL;
+ char *strfile = NULL;
+ unsigned long tstart; // Start time
+ char filnam[MAX_PATH];
+ WIN32_FIND_DATA find_data;
+ HANDLE find_handle;
+
+ ConvertAppToOem( argc, argv );
+ tstart = clock(); // Get start time
+
+#ifdef DBCS // v-junm - 06/03/93
+// Set TEB's language ID to correspond to the console output code page. This
+// will ensure the correct language message is displayed when FormatMessage is
+// called.
+// All non-JP code page will assume US LangId.
+
+ if ( (IsJPCP = GetConsoleOutputCP()) == 932 ) {
+ SetThreadLocale(
+ MAKELCID(
+ MAKELANGID( LANG_JAPANESE, SUBLANG_ENGLISH_US ),
+ SORT_DEFAULT
+ )
+ );
+ } else {
+ SetThreadLocale(
+ MAKELCID(
+ MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ),
+ SORT_DEFAULT
+ )
+ );
+ }
+ //
+ // Set Global CP variable IsJPCP.
+ // if JP code page then TRUE
+ // else false.
+ //
+ IsJPCP = ( IsJPCP == 932 ) ? TRUE : FALSE;
+
+#endif // JAPAN
+
+ asyncio = pmode = 1; // Do asynchronous I/O
+
+ // program = rmpath(argv[0]); // Set program name
+ program ="FINDSTR";
+
+ memset(td1, 1, TRTABLEN); // Set up TD1 for startup
+ flags = 0;
+
+ _setmode(_fileno(stdout), O_BINARY); // No linefeed translation on output
+ _setmode(_fileno(stderr), O_BINARY); // No linefeed translation on output
+
+ fsubdirs = 0;
+
+#if DBG
+#define VALID_SWITCHES "?BbEeIiLlMmNnOoPpRrSsVvXxtd"
+#else
+#define VALID_SWITCHES "?BbEeIiLlMmNnOoPpRrSsVvXx"
+#endif
+
+ for(i = 1; i < argc && (argv[i][0] == '/' || argv[i][0] == '-'); ++i) {
+ if(argv[i][1] == '\0' || strchr(VALID_SWITCHES, argv[i][1]) == NULL)
+ break; // Break if unrecognized switch
+
+ for(cp = &argv[i][1]; *cp != '\0'; ++cp) {
+ switch(*cp) {
+ case '?':
+ printmessage(stdout, MSG_FINDSTR_USAGE, NULL); // Verbose usage message
+ exit(0);
+
+ case 'b':
+ case 'B':
+ flags |= BEGLINE;
+ break;
+
+ case 'e':
+ case 'E':
+ flags |= ENDLINE;
+ break;
+
+ case 'i':
+ case 'I':
+ casesen = 0; // case-insensitive search
+ break;
+
+ case 'l':
+ case 'L':
+ addstr = addstring; // Treat strings literally
+ break;
+
+ case 'm':
+ case 'M':
+ flags |= NAMEONLY;
+ break;
+
+ case 'n':
+ case 'N':
+ flags |= LINENOS;
+ break;
+
+ case 'o':
+ case 'O':
+ flags |= SEEKOFF;
+ break;
+
+ case 'p':
+ case 'P':
+ flags |= PRINTABLE_ONLY;
+ break;
+
+ case 'r':
+ case 'R':
+ addstr = addexpr; // Add expression to list
+ break;
+
+ case 's':
+ case 'S':
+ fsubdirs = 1;
+ break;
+
+ case 'v':
+ case 'V':
+ grep = grepvbuffer;
+ break;
+
+ case 'x':
+ case 'X':
+ flags |= BEGLINE | ENDLINE;
+ break;
+
+#if DBG
+ case 'd':
+ flags |= DEBUG;
+ break;
+
+ case 't':
+ flags |= TIMER;
+ break;
+#endif
+
+ default:
+ {
+ char tmp[3];
+ tmp[0]='/';
+ tmp[1]=*cp;
+ tmp[2]='\0';
+ printmessage(stderr, MSG_FINDSTR_SWITCH_IGNORED, program, tmp);
+ }
+ break;
+ }
+ }
+ } // for( i=1; )
+
+ // Deal with form /C:string, etc.
+ for(; i < argc && (argv[i][0] == '/' || argv[i][0] == '-'); ++i) {
+ if(argv[i][2] == ':') { // Expect /C:, /G:, or /F:
+ switch(argv[i][1]) {
+ case 'c':
+ case 'C': // Explicit string (no separators)
+ if(argv[i][3] == '\0') {
+ printmessage(stderr, MSG_FINDSTR_ARGUMENT_MISSING, program, argv[i][1]);
+ exit(2);
+ // Argument missing
+ }
+ cp = &argv[i][3]; // Point to string
+ addstrings( cp, cp + strlen(cp), "" );
+ // Add string "as is"
+ continue;
+
+ case 'g':
+ case 'G': // Patterns in file
+ case 'f':
+ case 'F': // Names of files to search in file
+ if (argv[i][3] == '\0') {
+ printmessage(stderr, MSG_FINDSTR_ARGUMENT_MISSING, program, argv[i][1]);
+ exit(2);
+ // Argument missing
+ }
+ if(argv[i][1] == 'f' || argv[i][1] == 'F')
+ inpfile = &argv[i][3];
+ else
+ strfile = &argv[i][3];
+ continue;
+ } // switch
+ }
+
+ printmessage(stderr, MSG_FINDSTR_SWITCH_IGNORED, program, argv[i]);
+ }
+
+ if(i == argc && strcnt == 0 && strfile == NULL)
+ error(MSG_FINDSTR_BAD_COMMAND_LINE);
+
+ bufptr[0][-1] = bufptr[1][-1] = '\n'; // Mark beginnings with newline
+
+// Note: 4-Dec-90 w-barry Since there currently exists no method to query a
+// handle with the Win32 api (no equivalent to
+// DosQueryHType() ), the following piece of code
+// replaces the commented section.
+
+ if(_isatty(_fileno(stdout))) { // If stdout is a device
+ write1 = write1nobuf; // Use unbuffered output
+ flush1 = flush1nobuf;
+ }
+
+// /*
+// * Check type of handle for std. out.
+// */
+// if(DosQueryHType(fileno(stdout),(PPARM) &j,(PPARM) &fd) != NO_ERROR)
+// {
+// error("Standard output bad handle");
+// }
+// // Die if error
+// if(j != 0 && (fd & ISCOT)) // If handle is console output
+//#else
+// filbuf[3] = '\n'; // Mark beginning with newline
+// if(isatty(fileno(stdout))) // If stdout is a device
+//#endif
+// {
+// write1 = write1nobuf; // Use unbuffered output
+// flush1 = flush1nobuf;
+// }
+
+
+ if(strfile != NULL) { // If strings from file
+ if((strcmp(strfile,"/") != 0) && (strcmp(strfile,"-") != 0)) {
+ // If strings not from std. input
+
+ if( ( fd = CreateFile( strfile,
+ GENERIC_READ,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL ) ) == (HANDLE)-1 )
+ { // If open fails
+ printmessage(stderr, MSG_FINDSTR_CANNOT_READ_STRINGS, program, strfile);
+ exit(2); // Die
+ }
+ }else {
+ fd = GetStdHandle( STD_INPUT_HANDLE ); // Else use std. input
+ }
+ qgrep( addstrings, "\r\n", fd );// Do the work
+ if( fd != GetStdHandle( STD_INPUT_HANDLE ) ) {
+ CloseHandle( fd ); // Close strings file
+ }
+ } else if(strcnt == 0) { // Else if strings on command line
+ cp = argv[i++]; // Set pointer to strings
+ addstrings(cp,cp + strlen(cp)," \t");
+ // Add strings to list
+ }
+
+ if(strcnt == 0)
+ error(MSG_FINDSTR_NO_SEARCH_STRINGS); // Die if no strings
+
+ if(addstr != addexpr) { // If not using expressions
+ memset(td1,cchmin + 1,TRTABLEN);// Initialize table
+ find = findlist; // Assume finding many
+ if ((j = enumstrings()) != strcnt) {
+ printmessage(stderr, MSG_FINDSTR_STRING_COUNT_ERROR, j, strcnt);
+ }
+
+ // Enumerate strings and verify count
+
+#if DBG
+ if(flags & DEBUG) { // If debugging output wanted
+ fprintf(stderr,"%u bytes wasted in heap\n",waste);
+ // Print storage waste
+ assert(chmin <= chmax); // Must have some entries
+ fprintf(stderr, "chmin = %u, chmax = %u, cchmin = %u\n",chmin,chmax,cchmin);
+ // Print range info
+ for (j = (int)chmin; j <= (int)chmax; ++j) {
+ // Loop to print TD1 table
+ if( td1[j] <= (char)cchmin ) { // If not maximum shift
+ if (isascii(j) && isprint(j))
+ fprintf(stderr,"'%c'=%2u ",j,td1[j]); // Show literally if printable
+ else
+ fprintf(stderr,"\\%02x=%2u ",j,td1[j]); // Else show hex value
+ }
+ }
+ fprintf(stderr,"\n");
+ }
+#endif
+
+ if(strcnt == 1 && casesen)
+ find = findone; // Find one case-sensitive string
+ } else if(find == NULL) {
+ find = findexpr; // Else find expressions
+ }
+
+ if(inpfile != NULL) { // If file list from file
+ flags |= SHOWNAME; // Always show name of file
+ if((strcmp(inpfile,"/") != 0) && (strcmp(inpfile,"-") != 0)) {
+ if((fi = fopen(inpfile,"r")) == NULL) {
+ // If open fails
+ printmessage(stderr, MSG_FINDSTR_CANNOT_READ_FILE_LIST, program, inpfile);
+ exit(2); // Error exit
+ }
+ } else
+ fi = stdin; // Else read file list from stdin
+
+ while(fgets(filnam,FILNAMLEN,fi) != NULL) {
+ // While there are names
+ filnam[strcspn(filnam,"\r\n")] = '\0'; // Null-terminate the name
+ if((fd = openfile(filnam)) == (HANDLE)-1) {
+ continue; // Skip file if it cannot be opened
+ }
+ qgrep(grep,filnam,fd); // Do the work
+ CloseHandle( fd );
+ }
+
+ if(fi != stdin)
+ fclose(fi); // Close the list file
+ } else if(i == argc) {
+ flags &= ~(NAMEONLY | SHOWNAME);
+ qgrep( grep, NULL, GetStdHandle( STD_INPUT_HANDLE ) );
+ }
+
+ if(argc > i + 1 || fsubdirs || has_wild_cards(argv[i]))
+ flags |= SHOWNAME;
+
+
+ if (fsubdirs && argc > i) { // If directory search wanted
+ while (filematch(filnam,argv + i,argc - i) >= 0) {
+#ifdef DBCS // v-junm - 06/25/93 - DBCS chars can have upper case alphabets in 2nd byte.
+ _mbslwr((unsigned char *)filnam);
+#else
+ _strlwr(filnam);
+#endif
+ if((fd = openfile(filnam)) == (HANDLE)-1) {
+ continue;
+ }
+
+ qgrep(grep,filnam,fd);
+ CloseHandle( fd );
+ }
+ } else { // Else search files specified
+ for(; i < argc; ++i) {
+#ifdef DBCS // v-junm - 06/25/93 - DBCS chars can have upper case alphabets in 2nd byte.
+ _mbslwr((unsigned char *) argv[i]);
+#else
+ _strlwr(argv[i]);
+#endif // DBCS
+ find_handle = FindFirstFile(argv[i], &find_data);
+ if (find_handle == INVALID_HANDLE_VALUE) {
+ printmessage(stderr, MSG_FINDSTR_CANNOT_OPEN_FILE, program, argv[i]);
+ continue;
+ }
+
+ do {
+
+#ifdef DBCS // v-junm - 06/25/93 - DBCS chars can have upper case alphabets in 2nd byte.
+ _mbslwr((unsigned char *)find_data.cFileName);
+#else
+ _strlwr(find_data.cFileName);
+#endif // DBCS
+ prepend_path(find_data.cFileName, argv[i]);
+ fd = openfile(find_data.cFileName);
+
+ if (fd != INVALID_HANDLE_VALUE) {
+ qgrep(grep,find_data.cFileName,fd);
+ CloseHandle( fd );
+ }
+ } while (FindNextFile(find_handle, &find_data));
+ }
+ }
+
+ (*flush1)();
+
+#if DBG
+ if( flags & TIMER ) { // If timing wanted
+ unsigned long tend;
+
+ tend = clock();
+ tstart = tend - tstart; // Get time in milliseconds
+ fprintf(stderr,"%lu.%03lu seconds\n", ( tstart / CLK_TCK ), ( tstart % CLK_TCK ) );
+ // Print total elapsed time
+ }
+#endif
+
+ return( status );
+} // main
+
+
+char * findsub( unsigned char *, char * );
+char * findsubi( unsigned char *, char * );
+
+char * (*flworker[])(unsigned char *, char *) = { // Table of workers
+ findsubi,
+ findsub
+};
+
+
+char *
+strnupr(
+ char *pch,
+ int cch
+ )
+{
+#ifdef DBCS // v-junm - 05/06/93 - Change check from beginning so we can skip 2nd byte of DBCS characters.
+ int max = cch;
+ for ( cch = 0; cch < max; cch++ ) {
+#else
+ while (cch-- > 0) { // Convert string to upper case
+#endif // DBCS
+ if (isascii(pch[cch]))
+ pch[cch] = (char)toupper(pch[cch]);
+#ifdef DBCS // v-junm - 05/06/93 - Skip over 2nd byte of DBCS character.
+ else
+ if ( IsJPCP && IsDBCSLeadByte(pch[cch]))
+ cch++;
+#endif // DBCS
+ }
+ return(pch);
+}
+
+
+/*
+ * This is an implementation of the QuickSearch algorith described
+ * by Daniel M. Sunday in the August 1990 issue of CACM. The TD1
+ * table is computed before this routine is called.
+ */
+
+char *
+findone(
+ unsigned char *buffer,
+ char *bufend
+ )
+{
+#ifdef DBCS // v-junm - 05/06/93 - Need starting position of string for checking 2nd bytes of DBCS characters.
+ unsigned char *bufferhead = buffer;
+#endif // DBCS
+
+ if((bufend -= targetlen - 1) <= (char *) buffer)
+ return((char *) 0); // Fail if buffer too small
+
+ while (buffer < (unsigned char *) bufend) { // While space remains
+ int cch; // Character count
+ register char *pch1; // Char pointer
+ register char *pch2; // Char pointer
+
+ pch1 = target; // Point at pattern
+ pch2 = (char *) buffer; // Point at buffer
+
+#ifdef DBCS // v-junm - 05/06/93 - If buffer points to the 2nd byte of a DBCS character, skip to next compare position.
+ if ( !IsTailByte( bufferhead, buffer - bufferhead ) ) {
+#endif // DBCS
+ for (cch = targetlen; cch > 0; --cch) {
+ // Loop to try match
+ if (*pch1++ != *pch2++)
+ break; // Exit loop on mismatch
+ }
+ if (cch == 0)
+ return((char *)buffer); // Return pointer to match
+#ifdef DBCS // v-junm - 05/06/93
+ }
+#endif // DBCS
+
+ if(buffer + 1 < (unsigned char *) bufend) // Make sure buffer[targetlen] is valid.
+ buffer += ((unsigned char)td1[buffer[targetlen]]); // Skip ahead
+ else
+ break;
+ }
+ return((char *) 0); // No match
+}
+
+
+int
+preveol(
+ char *s
+ )
+{
+ register char *cp; // Char pointer
+
+ cp = s + 1; // Initialize pointer
+
+ if(!bStdIn) {
+ while((--cp >= BaseByteAddress) && (*cp != '\n'))
+ ; // Find previous end-of-line
+ } else {
+ while(*--cp != '\n') ; // Find previous end-of-line
+ }
+
+ return(s - cp); // Return distance to match
+}
+
+
+int
+countlines(
+ char *start,
+ char *finish
+ )
+{
+ register int count; // Line count
+
+ for(count = 0; start < finish; ) {
+ // Loop to count lines
+ if(*start++ == '\n')
+ ++count; // Increment count if linefeed found
+ }
+ return(count); // Return count
+}
+
+
+
+char *
+findlist(
+ unsigned char *buffer,
+ char *bufend
+ )
+{
+ char *match; // Pointer to matching string
+
+ // Avoid writting to bufend. bufend[-1] is something(such as '\n') that is not
+ // part of search and will cause the search to stop.
+
+ match = (*flworker[casesen])(buffer, bufend); // Call worker
+
+ return(match); // Return matching string
+}
+
+
+char *
+findsub(
+ unsigned char *buffer,
+ char *bufend
+ )
+{
+ register char *cp; // Char pointer
+ STRINGNODE *s; // String node pointer
+ int i; // Index
+#ifdef DBCS // v-junm - 05/06/93 - // Keep head of buffer for checking if a certain offset is the 2nd byte of a DBCS character.
+ unsigned char *bufhead = buffer;
+#endif // DBCS
+
+ if ((bufend -= cchmin - 1) < (char *) buffer)
+ return((char *) 0); // Compute effective buffer length
+
+ while(buffer < (unsigned char *) bufend) { // Loop to find match
+#ifdef DBCS // v-junm - 05/06/93
+// Search cannot start at the second byte of a DBCS character, so check for it
+// and skip it if it is a second byte.
+ if((i = transtab[*buffer]) != 0 &&
+ !IsTailByte( bufhead, buffer-bufhead ) ) {
+#else
+ if((i = transtab[*buffer]) != 0) {
+#endif // DBCS
+ // If valid first character
+ if((s = stringlist[i]) == 0) {
+ return((char *)buffer); // Check for 1-byte match
+ }
+
+ for(cp = (char *) buffer + 1; ; ) { // Loop to search list
+
+ if((i = memcmp(cp,s_text(s),s->s_must)) == 0) {
+ // If portions match
+ cp += s->s_must; // Skip matching portion
+ if((s = s->s_suf) == 0)
+ return((char *)buffer); // Return match if end of list
+ continue; // Else continue
+ }
+
+ if(i < 0 || (s = s->s_alt) == 0) {
+ break; // Break if not in this list
+ }
+ }
+ }
+
+ if(buffer + 1 < (unsigned char *) bufend) // Make sure buffer[cchmin] is valid.
+ buffer += ((unsigned char)td1[buffer[cchmin]]); // Shift as much as possible
+ else
+ break;
+ }
+ return((char *) 0); // No match
+}
+
+
+char *
+findsubi(
+ unsigned char *buffer,
+ char *bufend
+ )
+{
+ register char *cp; // Char pointer
+ STRINGNODE *s; // String node pointer
+ int i; // Index
+#ifdef DBCS // v-junm - 05/06/93
+// Keep head of buffer for checking if a certain offset is the 2nd byte of
+// a DBCS character.
+ unsigned char *bufhead = buffer;
+#endif DBCS
+
+ if ((bufend -= cchmin - 1) < (char *) buffer)
+ return((char *) 0); // Compute effective buffer length
+
+ while(buffer < (unsigned char *) bufend) { // Loop to find match
+#ifdef DBCS // v-junm - 05/06/93
+// Search cannot start at the second byte of a DBCS character, so check for it
+// and skip it if it is a second byte.
+ if((i = transtab[*buffer]) != 0 &&
+ !IsTailByte( bufhead, buffer-bufhead ) ) {
+ // If valid first character
+ BOOL LeadByte; // Flag to check if 1st char is leadbyte.
+#else
+ if((i = transtab[*buffer]) != 0) { // If valid first character
+#endif // DBCS
+
+ if((s = stringlist[i]) == 0)
+ return((char *) buffer); // Check for 1-byte match
+
+#ifdef DBCS // v-junm - 05/06/93
+// Same leadbytes with tailbytes such as 0x41 and 0x61 will become the same
+// character, so become aware of it and use the multibyte function.
+
+ //
+ // Check if first byte is a leadbyte character.
+ //
+
+ LeadByte = (*buffer == (unsigned char)(*(s_text(s)-1)));
+
+ for(cp = (char *) buffer + 1; ; ) { // Loop to search list
+ if((i = _mbsnicmp((unsigned char *)cp, (unsigned char *) s_text(s), s->s_must, &LeadByte)) == 0) {
+#else
+ for(cp = (char *) buffer + 1; ; ) { // Loop to search list
+ if((i = memicmp(cp,s_text(s),s->s_must)) == 0) {
+#endif // DBCS
+ // If portions match
+ cp += s->s_must; // Skip matching portion
+ if((s = s->s_suf) == 0)
+ return((char *) buffer); // Return match if end of list
+ continue; // And continue
+ }
+ if(i < 0 || (s = s->s_alt) == 0)
+ break; // Break if not in this list
+ }
+ }
+
+ if(buffer + 1 < (unsigned char *) bufend) // Make sure buffer[cchmin] is valid.
+ buffer += ((unsigned char)td1[buffer[cchmin]]); // Shift as much as possible
+ else
+ break;
+ }
+ return((char *) 0); // No match
+}
+
+
+int
+strnspn(
+ char *s,
+ char *t,
+ int n
+ )
+{
+ register char *s1; // String pointer
+ register char *t1; // String pointer
+
+ for(s1 = s; n-- != 0; ++s1) { // While not at end of s
+ for(t1 = t; *t1 != '\0'; ++t1) { // While not at end of t
+ if(*s1 == *t1)
+ break; // Break if match found
+ }
+ if(*t1 == '\0')
+ break; // Break if no match found
+ }
+ return(s1 - s); // Return length
+}
+
+
+int
+strncspn(
+ char *s,
+ char *t,
+ int n
+ )
+{
+ register char *s1; // String pointer
+ register char *t1; // String pointer
+
+ for(s1 = s; n-- != 0; ++s1) { // While not at end of s
+ for(t1 = t; *t1 != '\0'; ++t1) { // While not at end of t
+ if(*s1 == *t1)
+ return(s1 - s); // Return if match found
+ }
+ }
+ return(s1 - s); // Return length
+}
+
+
+void
+matchstrings(
+ char *s1,
+ char *s2,
+ int len,
+ int *nmatched,
+ int *leg
+ )
+{
+ register char *cp; // Char pointer
+ register int (_CRTAPI1 *cmp)(const char*,const char*, size_t); // Comparison function pointer
+
+ cmp = casesen ? strncmp: _strnicmp; // Set pointer
+ if((*leg = (*cmp)(s1,s2,len)) != 0) { // If strings don't match
+ for(cp = s1; (*cmp)(cp,s2++,1) == 0; ++cp)
+ ;
+ // Find mismatch
+ *nmatched = cp - s1; // Return number matched
+ }
+ else *nmatched = len; // Else all matched
+}
+
+
+
+void
+printmessage (
+ FILE* fp,
+ DWORD messageID,
+ ...
+ )
+{
+ char messagebuffer[4096];
+ va_list ap;
+
+ va_start(ap, messageID);
+
+ FormatMessage(FORMAT_MESSAGE_FROM_HMODULE, NULL, messageID, 0, messagebuffer, 4095, &ap);
+
+ fprintf(fp, messagebuffer);
+
+ va_end(ap);
+}
+
+#ifdef DBCS // v-junm - 05/06/93
+
+int
+IsTailByte(
+ unsigned const char *text,
+ const int offset
+ )
+
+/*
+ Description:
+
+ This routine checks to see if the byte at the offset location is a
+ tail byte of a DBCS character. The offset is calculated such that the
+ first location has a value of 0.
+
+ Argument:
+
+ text - Points to a MBCS text string.
+
+ offset - zero base offset to check character is a tailbyte of a DBCS
+ character.
+
+ Returns:
+
+ TRUE - offset position is a tailbyte character.
+
+ FALSE - otherwise.
+
+ Modifications:
+
+ v-junm: 05/06/93 - Original.
+*/
+
+{
+ int i = offset;
+
+ if ( !IsJPCP )
+ return( FALSE );
+
+ for ( ; i; i-- )
+ if ( !IsDBCSLeadByte ( text[i-1] ) )
+ break;
+
+ return( ( offset - i ) % 2 );
+}
+
+char *
+_mbsrchr(
+ const char *string,
+ int c
+ )
+
+/*
+ Description:
+
+ This function is a DBCS enabled version of the STRRCHR function
+ included in the MS C/C++ library. What DBCS enabled means is that
+ the SBCS character 'c' is found in a MBCS string 'string'. 'c' is
+ a SBCS character that cannot be contained in the tailbyte of a DBCS
+ character.
+
+ Argument:
+
+ string - Points to a MBCS text string.
+
+ offset - Character to find in string.
+
+ Returns:
+
+ Returns a pointer to the last occurance of c in string, or a NULL
+ pointer if c is not found.
+
+ Modifications:
+
+ v-junm: 05/06/93 - Original.
+*/
+
+{
+ register int i = strlen( string );
+
+ for (; i >= 0; i-- ) {
+ if ( ( *(string + i) == (char)c ) && !IsTailByte( (unsigned char *) string, i ) )
+ return( (char*)(string + i) );
+ }
+ return ( NULL );
+}
+
+
+unsigned char *
+_mbslwr(
+ unsigned char *s
+ )
+
+/*
+ Description:
+
+ This function is a DBCS aware version of the strlwr function
+ included in the MS C/C++ library. SBCS alphabets contained in
+ the tailbyte of a DBCS character is not affected in the conversion.
+
+ Argument:
+
+ s - String to converted to lower case.
+
+ Returns:
+
+ Returns a string that was converted to lower case.
+
+ Modifications:
+
+ v-junm: 05/06/93 - Original.
+*/
+
+{
+ //
+ // If NonJP code page, use original routine.
+ //
+ if ( !IsJPCP )
+ return( (unsigned char *) _strlwr( (char *) s ) );
+
+ //
+ // While not end of string convert to lower case.
+ //
+ for( ; *s; s++ ) {
+
+ //
+ // if Leadbyte and next character is not NULL
+ // skip tailbyte
+ // else if uppercase character
+ // convert it to lowercase
+ //
+ if ( IsDBCSLeadByte( *s ) && *(s+1) )
+ s++;
+ else if ( *s >= 0x41 && *s <= 0x5a )
+ *s = *s + 0x20;
+ }
+ return( s );
+}
+
+int
+_mbsnicmp(
+ const unsigned char *s1,
+ const unsigned char *s2,
+ int n,
+ BOOL *TailByte
+ )
+
+/*
+ Description:
+
+ This is similar to a DBCS aware version of the memicmp function
+ contained in the MS C/C++ library. The only difference is that
+ an additional parameter is passed which indicates if the first
+ character is a tailbyte of a DBCS character.
+
+ Argument:
+
+ s1 - string 1 to compare.
+
+ s2 - string 2 to compare.
+
+ n - maximum number of bytes to compare.
+
+ TailByte - flag to indicate first character in s1 and s2 is a tailbyte
+ of a DBCS character.
+
+ Returns:
+
+ RetVal < 0 - s1 < s2
+
+ RetVal = 0 - s1 == s2
+
+ RetVal > 0 - s1 > s2
+
+ Modifications:
+
+ v-junm: 05/06/93 - Original.
+*/
+
+{
+ BOOL tail = *TailByte;
+
+ *TailByte = FALSE;
+
+ for( ; n; n--, s1++, s2++ ) {
+
+ if ( *s1 == *s2 ) {
+
+ if ( tail == FALSE && IsDBCSLeadByte( *s1 ) )
+ tail = TRUE;
+ else
+ tail = FALSE;
+
+ continue;
+
+ }
+ else if ( !tail ) {
+
+ if ( tolower( *s1 ) == tolower( *s2 ) )
+ continue;
+
+ }
+
+ return( *s1 - *s2 );
+ }
+ return( 0 );
+}
+
+#endif // DBCS
+
diff --git a/private/utils/findstr/findstr.rc b/private/utils/findstr/findstr.rc
new file mode 100644
index 000000000..9f2cdcdf0
--- /dev/null
+++ b/private/utils/findstr/findstr.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Find String (QGREP) Utility"
+#define VER_INTERNALNAME_STR "findstr\0"
+#define VER_ORIGINALFILENAME_STR "FINDSTR.EXE"
+
+#include "common.ver"
+
+#include "fsmsg.rc"
diff --git a/private/utils/findstr/fsmsg.mc b/private/utils/findstr/fsmsg.mc
new file mode 100644
index 000000000..474b18a01
--- /dev/null
+++ b/private/utils/findstr/fsmsg.mc
@@ -0,0 +1,133 @@
+;/*++
+;
+;Copyright (c) 1992 Microsoft Corporation
+;
+;Module Name:
+;
+; fsmsg.mc (will create fsmsg.h when compiled)
+;
+;Abstract:
+;
+; This file contains the FINDSTR messages.
+;
+;Author:
+;
+; Peter Sun (t-petes) 18-June-1992
+;
+;Revision History:
+;
+;--*/
+
+
+MessageId=1 SymbolicName=MSG_FINDSTR_BAD_COMMAND_LINE
+Language=English
+%1: Bad command line
+.
+
+MessageId=2 SymbolicName=MSG_FINDSTR_OUT_OF_MEMORY
+Language=English
+%1: Out of memory
+.
+
+MessageId=3 SymbolicName=MSG_FINDSTR_USAGE
+Language=English
+Searches for strings in files.
+
+FINDSTR [/B] [/E] [/L] [/R] [/S] [/I] [/X] [/V] [/N] [/M] [/O] [/F:file]
+ [/C:string] [/G:file] [strings] [[drive:][path]filename[ ...]]
+
+ /B Matches pattern if at the beginning of a line.
+ /E Matches pattern if at the end of a line.
+ /L Uses search strings literally.
+ /R Uses search strings as regular expressions.
+ /S Searches for matching files in the current directory and all
+ subdirectories.
+ /I Specifies that the search is not to be case-sensitive.
+ /X Prints lines that match exactly.
+ /V Prints only lines that do not contain a match.
+ /N Prints the line number before each line that matches.
+ /M Prints only the filename if a file contains a match.
+ /O Prints character offset before each matching line.
+ /P Skip files with non-printable characters
+ /F:file Reads file list from the specified file(/ stands for console).
+ /C:string Uses specified string as a literal search string.
+ /G:file Gets search strings from the specified file(/ stands for console).
+ strings Text to be searched for.
+ [drive:][path]filename
+ Specifies a file or files to search.
+
+Use spaces to separate multiple search strings unless the argument is prefixed
+with /C. For example, 'FINDSTR "hello there" x.y' searches for "hello" or
+"there" in file x.y. 'FINDSTR /C:"hello there" x.y' searches for
+"hello there" in file x.y.
+
+For information on FINDSTR regular expressions refer to the online Command
+Reference.
+.
+
+MessageId=4 SymbolicName=MSG_FINDSTR_CANNOT_OPEN_FILE
+Language=English
+%1: Cannot open %2
+.
+
+MessageId=5 SymbolicName=MSG_FINDSTR_WRITE_ERROR
+Language=English
+%1: Write error
+.
+
+MessageId=6 SymbolicName=MSG_FINDSTR_SWITCH_IGNORED
+Language=English
+%1: %2 ignored
+.
+
+MessageId=7 SymbolicName=MSG_FINDSTR_CANNOT_READ_STRINGS
+Language=English
+%1: Cannot read strings from %2
+.
+
+MessageId=8 SymbolicName=MSG_FINDSTR_STRING_COUNT_ERROR
+Language=English
+String count error: (%1 does not equal %2)
+.
+
+MessageId=9 SymbolicName=MSG_FINDSTR_CANNOT_READ_FILE_LIST
+Language=English
+%1: Cannot read file list from %2
+.
+
+MessageId=10 SymbolicName=MSG_FINDSTR_TOO_MANY_STRING_LISTS
+Language=English
+Too many string lists
+.
+
+MessageId=11 SymbolicName=MSG_FINDSTR_ARGUMENT_MISSING
+Language=English
+%1: Argument missing after /%2!c!
+.
+
+MessageId=12 SymbolicName=MSG_FINDSTR_NO_SEARCH_STRINGS
+Language=English
+%1: No search strings
+.
+
+MessageId=13 SymbolicName=MSG_FINDSTR_CANNOT_CREATE_FILE_MAPPING
+Language=English
+%1: Read file failed. (Cannot create file mapping.)
+.
+
+MessageId=14 SymbolicName=MSG_FINDSTR_CANNOT_MAP_VIEW
+Language=English
+%1: Read file failed. (Cannot map view of file.)
+.
+
+MessageId=15 SymbolicName=MSG_FINDSTR_READ_ERROR
+Language=English
+%1: Error reading file %2.
+.
+
+MessageId=16 SymbolicName=MSG_FINDSTR_SEARCH_STRING_TOO_LONG
+Language=English
+%1: Search string too long.
+.
+
+ \ No newline at end of file
diff --git a/private/utils/findstr/makefile b/private/utils/findstr/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/findstr/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/findstr/makefile.inc b/private/utils/findstr/makefile.inc
new file mode 100644
index 000000000..70cff653f
--- /dev/null
+++ b/private/utils/findstr/makefile.inc
@@ -0,0 +1,4 @@
+fsmsg.rc: msg00001.bin
+
+fsmsg.h msg00001.bin: fsmsg.mc
+ mc -v -h .\ fsmsg.mc
diff --git a/private/utils/findstr/qmatch.c b/private/utils/findstr/qmatch.c
new file mode 100644
index 000000000..fb96eb62b
--- /dev/null
+++ b/private/utils/findstr/qmatch.c
@@ -0,0 +1,758 @@
+// static char *SCCSID = "@(#)qmatch.c 13.7 90/08/13";
+
+
+#include <stdio.h>
+#include <ctype.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <windows.h>
+#include <stdarg.h>
+#include "fsmsg.h"
+
+
+#define ASCLEN 128 // Number of ascii characters
+#define BUFLEN 256 // Temporary buffer length
+#define EOS ('\r') // End of string character
+#define EOS2 ('\n') // Alternate End of string character
+#define PATMAX 512 // Maximum parsed pattern length
+
+#define BEGLINE 0x08 // Match at beginning of line
+#define DEBUG 0x20 // Print debugging output
+#define ENDLINE 0x10 // Match at end of line
+
+#define T_END 0 // End of expression
+#define T_STRING 1 // String to match
+#define T_SINGLE 2 // Single character to match
+#define T_CLASS 3 // Class to match
+#define T_ANY 4 // Match any character
+#define T_STAR 5 // *-expr
+
+
+typedef struct exprnode {
+ struct exprnode *ex_next; // Next node in list
+ unsigned char *ex_pattern; // Pointer to pattern to match
+} EXPR; // Expression node
+
+
+static int clists = 1; // One is first available index
+static int toklen[] = { // Table of token lengths
+ 32767, // T_END: invalid
+ 32767, // T_STRING: invalid
+ 2, // T_SINGLE
+ ASCLEN/8+1, // T_CLASS
+ 1, // T_ANY
+ 32767 // T_STAR: invalid
+};
+
+static int (_CRTAPI1 *ncmp)(const char *,const char *,size_t);
+ // String comparison pointer
+
+
+extern int casesen; // Case-sensitivity flag
+extern char *(*find)(unsigned char *, char *); // Pointer to search function
+extern int flags; // Flags
+extern int strcnt; // String count
+extern char transtab[]; // Translation table
+EXPR *stringlist[ASCLEN];
+ // String table
+
+
+void addexpr( char *, int ); // Add expression
+extern char *alloc(unsigned); // User-defined heap allocator
+unsigned char *simpleprefix(); // Match simple prefix
+char *strnupr( char *pch, int cch );
+void printmessage(FILE *fp, DWORD messagegid, ...);
+ // Message display function for internationalization(findstr.c)
+
+unsigned char *
+simpleprefix(
+ unsigned char *s, // String pointer
+ unsigned char **pp // Pointer to pattern pointer
+ )
+{
+ register unsigned char *p; // Simple pattern pointer
+ register int c; // Single character
+
+ p = *pp; // Initialize
+ while(*p != T_END && *p != T_STAR) { // While not at end of pattern
+ switch(*p++) { // Switch on token type
+ case T_STRING: // String to compare
+ if((*ncmp)((char *)s, (char *)p + 1, *p) != 0)
+ return(NULL);
+ // Fail if mismatch found
+ s += *p; // Skip matched portion
+ p += *p + 1; // Skip to next token
+ break;
+
+ case T_SINGLE: // Single character
+ c = *s++; // Get character
+ if(!casesen)
+ c = toupper(c);
+ // Map to upper case if necessary
+ if(c != (int)*p++)
+ return(NULL);
+ // Fail if mismatch found
+ break;
+
+ case T_CLASS: // Class of characters
+ if(!isascii(*s) || !(p[*s >> 3] & (1 << (*s & 7))))
+ return(NULL); // Failure if bit not set
+ p += ASCLEN/8; // Skip bit vector
+ ++s; // Skip character
+ break;
+
+ case T_ANY: // Any character
+
+ if(*s == EOS || *s == EOS2)
+ return(NULL); // Match all but end of string
+ ++s;
+ break;
+ }
+ }
+ *pp = p; // Update pointer
+ return(s); // Pattern is prefix of s
+}
+
+
+int
+match(
+ unsigned char *s, // String to match
+ unsigned char *p // Pattern to match against
+ )
+{
+ register unsigned char *q; // Temporary pointer
+ unsigned char *r; // Temporary pointer
+ register int c; // Character
+
+ if(*p != T_END && *p != T_STAR && (s = simpleprefix(s,&p)) == NULL)
+ return(0); // Failure if prefix mismatch
+ if(*p++ == T_END)
+ return(1); // Match if end of pattern
+ q = r = p; // Point to repeated token
+ r += toklen[*q]; // Skip repeated token
+ switch(*q++) { // Switch on token type
+ case T_ANY: // Any character
+ while(match(s,r) == 0) { // While match not found
+ if(*s == EOS || *s == EOS2)
+ return(0); // Match all but end of string
+ ++s;
+ }
+ return(1); // Success
+
+ case T_SINGLE: // Single character
+ while(match(s,r) == 0) { // While match not found
+ c = *s++; // Get character
+ if(!casesen)
+ c = toupper(c); // Map to upper case if necessary
+ if((unsigned char) c != *q)
+ return(0); // Fail if mismatch found
+ }
+ return(1); // Success
+
+ case T_CLASS: // Class of characters
+ while(match(s,r) == 0) { // While match not found
+ if(!isascii(*s) || !(q[*s >> 3] & (1 << (*s & 7))))
+ return(0); // Fail if bit not set
+ ++s; // Else skip character
+ }
+ return(1); // Success
+ }
+ return(0); // Return failure
+}
+
+
+int
+exprmatch(
+ char *s, // String
+ char *p // Pattern
+ )
+{
+ ncmp = strncmp; // Assume case-sensitive
+ if(!casesen) {
+ ncmp = _strnicmp;
+ } // Be case-insensitive if flag set
+
+ // See if pattern matches string
+ return(match((unsigned char *)s, (unsigned char *)p));
+}
+
+
+void
+bitset(
+ char *bitvec, // Bit vector
+ int first, // First character
+ int last, // Last character
+ int bitval // Bit value (0 or 1)
+ )
+{
+ int bitno; // Bit number
+
+ bitvec += first >> 3; // Point at first byte
+ bitno = first & 7; // Calculate first bit number
+ while(first <= last) { // Loop to set bits
+ if(bitno == 0 && first + 8 <= last) {
+ // If we have a whole byte's worth
+ *bitvec++ = (char)(bitval? '\xFF': '\0');
+ // Set the bits
+ first += 8; // Increment the counter
+ continue; // Next iteration
+ }
+ *bitvec=(char)(*bitvec & (unsigned char)(~(1 << bitno))) | (unsigned char)(bitval << bitno);
+ // Set the appropriate bit
+ if(++bitno == 8) { // If we wrap into next byte
+ ++bitvec; // Increment pointer
+ bitno = 0; // Reset bit index
+ }
+ ++first; // Increment bit index
+ }
+}
+
+
+unsigned char *
+exprparse(
+ unsigned char *p // Raw pattern
+ )
+{
+ register char *cp; // Char pointer
+ unsigned char *cp2; // Char pointer
+ int i; // Counter/index
+ int j; // Counter/index
+ int m; // Counter/index
+ int n; // Counter/index
+ int bitval; // Bit value
+ char buffer[PATMAX]; // Temporary buffer
+
+ if(!casesen)
+ strnupr((char *)p, strlen((char *)p)); // Force pattern to upper case
+ cp = buffer; // Initialize pointer
+ if(*p == '^')
+ *cp++ = *p++; // Copy leading caret if any
+ while(*p != '\0') { // While not end of pattern
+ i = -2; // Initialize
+ for(n = 0;;) { // Loop to delimit ordinary string
+ n += strcspn((char *)(p + n),".\\[*");// Look for a special character
+ if(p[n] != '\\')
+ break; // Break if not backslash
+ i = n; // Remember where backslash is
+ if(p[++n] == '\0')
+ return(NULL); // Cannot be at very end
+ ++n; // Skip escaped character
+ }
+ if(p[n] == '*') { // If we found a *-expr.
+ if(n-- == 0)
+ return(NULL); // Illegal first character
+ if(i == n - 1)
+ n = i; // Escaped single-char. *-expr.
+ }
+ if(n > 0) { // If we have string or single
+ if(n == 1 || (n == 2 && *p == '\\')) {
+ // If single character
+ *cp++ = T_SINGLE; // Set type
+ if(*p == '\\')
+ ++p; // Skip escape if any
+ *cp++ = *p++; // Copy single character
+ } else { // Else we have a string
+ *cp++ = T_STRING; // Set type
+ cp2 = (unsigned char *)cp++; // Save pointer to length byte
+ while(n-- > 0) { // While bytes to copy remain
+ if(*p == '\\') { // If escape found
+ ++p; // Skip escape
+ --n; // Adjust length
+ }
+ *cp++ = *p++; // Copy character
+ }
+ *cp2 = (unsigned char)((cp - (char *)cp2) - 1);
+ // Set string length
+ }
+ }
+ if(*p == '\0')
+ break; // Break if end of pattern
+ if(*p == '.') { // If matching any
+ if(*++p == '*') { // If star follows any
+ ++p; // Skip star, too
+ *cp++ = T_STAR; // Insert prefix ahead of token
+ }
+ *cp++ = T_ANY; // Match any character
+ continue; // Next iteration
+ }
+ if(*p == '[') { // If character class
+ if(*++p == '\0')
+ return(NULL);
+ // Skip '['
+ *cp++ = T_CLASS; // Set type
+ memset(cp,'\0',ASCLEN/8); // Clear the vector
+ bitval = 1; // Assume we're setting bits
+ if(*p == '^') { // If inverted class
+ ++p; // Skip '^'
+ memset(cp,'\xFF',ASCLEN/8);
+ // Set all bits
+ bitset(cp,EOS,EOS,0); // All except end-of-string
+ bitset(cp,'\n','\n',0); // And linefeed!
+ bitval = 0; // Now we're clearing bits
+ }
+
+ while(*p != ']') { // Loop to find ']'
+ if(*p == '\0')
+ return(NULL); // Check for malformed string
+ if(*p == '\\') { // If escape found
+ if(*++p == '\0')
+ return(NULL); // Skip escape
+ }
+ i = *p++; // Get first character in range
+ if(*p == '-' && p[1] != '\0' && p[1] != ']') {
+ // If range found
+ ++p; // Skip hyphen
+ if(*p == '\\' && p[1] != '\0')
+ ++p; // Skip escape character
+ j = *p++; // Get end of range
+ } else
+ j = i; // Else just one character
+ bitset(cp,i,j,bitval); // Set bits in vector
+ if(!casesen) { // If ignoring case
+ m = (i < 'A')? 'A': i;
+ // m = max(i,'A')
+ n = (j > 'Z')? 'Z': j;
+ // n = min(j,'Z')
+ if(m <= n)
+ bitset(cp,_tolower(m),_tolower(n),bitval);
+ // Whack corresponding lower case
+ m = (i < 'a')? 'a': i;
+ // m = max(i,'a')
+ n = (j > 'z')? 'z': j;
+ // n = min(j,'z')
+ if(m <= n)
+ bitset(cp,_toupper(m),_toupper(n),bitval);
+ // Whack corresponding upper case
+ }
+ }
+
+ if(*++p == '*') { // If repeated class
+ memmove(cp,cp - 1,ASCLEN/8 + 1);
+ // Move vector forward 1 byte
+ cp[-1] = T_STAR; // Insert prefix
+ ++cp; // Skip to start of vector
+ ++p; // Skip star
+ }
+ cp += ASCLEN/8; // Skip over vector
+ continue; // Next iteration
+ }
+ *cp++ = T_STAR; // Repeated single character
+ *cp++ = T_SINGLE;
+ if(*p == '\\')
+ ++p; // Skip escape if any
+ *cp++ = *p++; // Copy the character
+ assert(*p == '*'); // Validate assumption
+ ++p; // Skip the star
+ }
+ *cp++ = T_END; // Mark end of parsed expression
+ cp2 = (unsigned char *)alloc(cp - buffer); // Allocate buffer
+ memmove(cp2, buffer,cp - buffer); // Copy expression to buffer
+ return(cp2); // Return buffer pointer
+}
+
+
+int
+istoken(
+ unsigned char *s, // String
+ int n // Length
+ )
+{
+ if(n >= 2 && s[0] == '\\' && s[1] == '<')
+ return(1); // Token if starts with '\<'
+
+ while(n-- > 0) { // Loop to find end of string
+ if(*s++ == '\\') { // If escape found
+ if(--n == 0 && *s == '>')
+ return(1); // Token if ends with '\>'
+ ++s; // Skip escaped character
+ }
+ }
+ return(0); // Not a token
+}
+
+
+int
+isexpr(
+ unsigned char *s, // String
+ int n // Length
+ )
+{
+ unsigned char *cp; // Char pointer
+ int status; // Return status
+ char buffer[BUFLEN]; // Temporary buffer
+
+ if(istoken(s, n))
+ return(1); // Tokens are exprs
+ memmove(buffer,s,n); // Copy string to buffer
+ buffer[n] = '\0'; // Null-terminate string
+ if (*buffer && buffer[n - 1] == '$')
+ return(1);
+ if((s = exprparse((unsigned char *)buffer)) == NULL)
+ return(0); // Not an expression if parse fails
+ status = 1; // Assume we have an expression
+ if(*s != '^' && *s != T_END) { // If no caret and not empty
+ status = 0; // Assume not an expression
+ cp = s; // Initialize
+ do { // Loop to find special tokens
+ switch(*cp++) { // Switch on token type
+ case T_STAR: // Repeat prefix
+ case T_CLASS: // Character class
+ case T_ANY: // Any character
+ ++status; // This is an expression
+ break;
+
+ case T_SINGLE: // Single character
+ ++cp; // Skip character
+ break;
+
+ case T_STRING: // String
+ cp += *cp + 1; // Skip string
+ break;
+ }
+ }
+ while(!status && *cp != T_END)
+ ; // Do while not at end of expression
+ }
+ free(s); // Free expression
+ return(status); // Return status
+}
+
+
+#ifdef gone // for DEBUG
+
+void
+exprprint(
+ unsigned char *p, // Pointer to expression
+ FILE *fo // File pointer
+ )
+{
+ int bit; // Bit value
+ int count; // Count of characters in string
+ int first; // First character in range
+ int last; // Last character in range
+ int star; // Repeat prefix flag
+
+ if(*p == '^')
+ fputc(*p++,fo); // Print leading caret
+
+ while(*p != T_END) { // While not at end of expression
+ star = 0; // Assume no prefix
+ if(*p == T_STAR) { // If repeat prefix found
+ ++star; // Set flag
+ ++p; // Skip prefix
+ }
+ switch(*p++) { // Switch on token type
+ case T_END: // End of expression
+ case T_STAR: // Repeat prefix
+ fprintf(stderr,"Internal error: exprprint\n");
+ // Not valid
+ exit(2); // Die abnormal death
+
+ case T_STRING: // String
+ count = *p++; // Get string length
+ goto common; // Forgive me, Djikstra!
+
+ case T_SINGLE: // Single character
+ count = 1; // Only one character
+common:
+ while(count-- > 0) { // While bytes remain
+ if(*p == EOS || *p == EOS2) {
+ // If end-of-string found
+ ++p; // Skip character
+ fputc('$',fo); // Emit special marker
+ continue; // Next iteration
+ }
+ if(strchr("*.[\\$",*p) != NULL)
+ fputc('\\',fo); // Emit escape if needed
+
+ fputc(*p++,fo); // Emit the character
+ }
+ break;
+
+ case T_ANY: // Match any
+ fputc('.',fo); // Emit dot
+ break;
+
+ case T_CLASS:
+ first = -1; // Initialize
+ fputc('[',fo); // Open braces
+ for(count = ' '; count <= '~'; ++count) {
+ // Loop through printable characters
+ if((bit = p[count >> 3] & (1 << (count & 7))) != 0) {
+ // If bit is set
+ if(first == -1)
+ first = count;
+ // Set first bit
+ last = count; // Set last bit
+ }
+ if((!bit || count == '~') && first != -1) {
+ // If range to print
+ if(strchr("\\]-",first) != NULL)
+ fputc('\\',fo); // Emit escape if needed
+ fputc(first,fo); // Print first character in range
+ if(last != first) { // If we have a range
+
+ if(last > first + 1)
+ fputc('-',fo); // Emit hyphen if needed
+
+ if(strchr("\\]-",last) != NULL)
+ fputc('\\',fo); // Emit escape if needed
+
+ fputc(last,fo);
+ // Print last character in range
+ }
+ first = -1; // Range printed
+ }
+ }
+ fputc(']',fo); // Close braces
+ p += ASCLEN/8; // Skip bit vector
+ break;
+ }
+ if(star)
+ fputc('*',fo); // Print star if needed
+ }
+ fputc('\n',fo); // Print newline
+}
+
+#endif
+
+
+char *
+get1stcharset(
+ unsigned char *e, // Pointer to expression
+ char *bitvec // Pointer to bit vector
+ )
+{
+ unsigned char *cp; // Char pointer
+ int i; // Index/counter
+ int star; // Repeat prefix flag
+
+ if(*e == '^')
+ ++e; // Skip leading caret if any
+ memset(bitvec,'\0',ASCLEN/8); // Clear bit vector
+ cp = e; // Initialize
+ while(*e != T_END) { // Loop to process leading *-expr.s
+ star = 0; // Assume no repeat prefix
+ if(*e == T_STAR) { // If repeat prefix found
+ ++star; // Set flag
+ ++e; // Skip repeat prefix
+ }
+ switch(*e++) { // Switch on token type
+ case T_END: // End of expression
+ case T_STAR: // Repeat prefix
+
+ assert(0); // Not valid
+ exit(2); // Die abnormal death
+
+ case T_STRING: // String
+ if(star || *e++ == '\0') { // If repeat prefix or zero count
+ assert(0); // Not valid
+ exit(2); // Die abnormal death
+ }
+ // Drop through
+
+ case T_SINGLE: // Single character
+ bitset(bitvec,*e,*e,1); // Set the bit
+ ++e; // Skip the character
+ break;
+
+ case T_ANY: // Match any
+ memset(bitvec,'\xFF',ASCLEN/8);
+ // Set all the bits
+ bitset(bitvec,EOS,EOS,0); // Except end-of-string
+ bitset(bitvec,'\n','\n',0); // And linefeed!
+ break;
+
+ case T_CLASS:
+ for(i = 0; i < ASCLEN/8; ++i)
+ bitvec[i] |= *e++; // Or in all the bits
+ break;
+ }
+ if(!star)
+ break; // Break if not repeated
+ cp = e; // Update pointer
+ }
+ return((char *)cp); // Point to 1st non-repeated expr.
+}
+
+
+char *
+findall(
+ unsigned char *buffer, // Buffer in which to search
+ char *bufend // End of buffer
+ )
+{
+ return(buffer < (unsigned char *) bufend ? (char *) buffer : NULL); // Fail only on empty buffer
+}
+
+
+void
+addtoken(
+ char *e, // Raw token expression
+ int n // Length of expression
+ )
+{
+ static char achpref[] = "^";// Prefix
+ static char achprefsuf[] = "[^A-Za-z0-9_]";
+ // Prefix/suffix
+ static char achsuf[] = "$"; // Suffix
+ char buffer[BUFLEN]; // Temporary buffer
+
+ assert(n >= 2); // Must have at least two characters
+ if(e[0] == '\\' && e[1] == '<') { // If begin token
+ if(!(flags & BEGLINE)) { // If not matching at beginning only
+ memcpy(buffer,achprefsuf,sizeof achprefsuf - 1);
+ // Copy first prefix
+ memcpy(buffer + sizeof achprefsuf - 1,e + 2,n - 2);
+ // Attach expression
+ addexpr(buffer,n + sizeof achprefsuf - 3);
+ // Add expression
+ }
+ memcpy(buffer,achpref,sizeof achpref - 1);
+ // Copy second prefix
+ memcpy(buffer + sizeof achpref - 1,e + 2,n - 2);
+ // Attach expression
+ addexpr(buffer,n + sizeof achpref - 3);
+ // Add expression
+ return; // Done
+ }
+ assert(e[n-2] == '\\' && e[n - 1] == '>');
+ // Must be end token
+ if(!(flags & ENDLINE)) { // If not matching at end only
+ memcpy(buffer,e,n - 2); // Copy expression
+ memcpy(buffer + n - 2,achprefsuf,sizeof achprefsuf - 1);
+ // Attach first suffix
+ addexpr(buffer,n + sizeof achprefsuf - 3);
+ // Add expression
+ }
+ memcpy(buffer,e,n - 2); // Copy expression
+ memcpy(buffer + n - 2,achsuf,sizeof achsuf - 1);
+ // Attach second suffix
+ addexpr(buffer,n + sizeof achsuf - 3);
+ // Add expression
+}
+
+
+void
+addexpr(
+ char *e, // Expression to add
+ int n // Length of expression
+ )
+{
+ EXPR *expr; // Expression node pointer
+ int i; // Index
+ int j; // Index
+ int locflags; // Local copy of flags
+ char bitvec[ASCLEN/8];
+ // First char. bit vector
+ char buffer[BUFLEN]; // Temporary buffer
+
+ if(find == findall)
+ return; // Return if matching everything
+ if(istoken((unsigned char *)e, n)) { // If expr is token
+ addtoken(e,n); // Convert and add tokens
+ return; // Done
+ }
+ locflags = flags; // Initialize local copy
+ if(*e == '^') locflags |= BEGLINE; // Set flag if match must begin line
+ j = -2; // Assume no escapes in string
+ for(i = 0; i < n - 1; ++i) { // Loop to find last escape
+ if(e[i] == '\\') j = i++; // Save index of last escape
+ }
+ if(n > 0 && e[n-1] == '$' && j != n-2) {
+ // If expr. ends in unescaped '$'
+ --n; // Skip dollar sign
+ locflags |= ENDLINE; // Match must be at end
+ }
+ strncpy(buffer,e,n); // Copy pattern to buffer
+ if(locflags & ENDLINE)
+ buffer[n++] = EOS; // Add end character if needed
+ buffer[n] = '\0'; // Null-terminate string
+ if((e = (char *)exprparse((unsigned char *)buffer)) == NULL)
+ return; // Return if invalid expression
+ ++strcnt; // Increment string count
+ if(!(locflags & BEGLINE)) { // If match needn't be at beginning
+ e = get1stcharset((unsigned char *)e, bitvec); // Remove leading *-expr.s
+ }
+
+ // E now points to a buffer containing a preprocessed expression.
+ // We need to find the set of allowable first characters and make
+ // the appropriate entries in the string node table.
+
+ if(*get1stcharset((unsigned char *)e, bitvec) == T_END) {
+ // If expression will match anything
+ find = findall; // Match everything
+ return; // All done
+ }
+
+ for(j = 0; j < ASCLEN; ++j) { // Loop to examine bit vector
+ if(bitvec[j >> 3] & (1 << (j & 7))) { // If the bit is set
+ expr = (EXPR *) alloc(sizeof(EXPR)); // Allocate record
+ expr->ex_pattern = (unsigned char *)e; // Point it at pattern
+ if((i = transtab[j]) == 0) { // If no existing list
+ if((i = clists++) >= ASCLEN) { // If too many string lists
+
+ printmessage(stderr,MSG_FINDSTR_TOO_MANY_STRING_LISTS,NULL);
+ // Error message
+ exit(2); // Die
+ }
+ stringlist[i] = NULL; // Initialize
+ transtab[j] = (char) i; // Set pointer to new list
+ if(!casesen && isalpha(j))
+ transtab[j ^ 0x20] = (char) i; // Set pointer for other case
+ }
+ expr->ex_next = stringlist[i]; // Link new record into table
+ stringlist[i] = expr;
+ }
+ }
+
+ // if(locflags & DEBUG) exprprint(e,stderr);
+ // Print the expression if debugging
+}
+
+
+char *
+findexpr(
+ unsigned char *buffer, // Buffer in which to search
+ char *bufend // End of buffer
+ )
+{
+ EXPR *expr; // Expression list pointer
+ unsigned char *pattern; // Pattern
+ int i; // Index
+ unsigned char *bufbegin;
+ int b;
+
+ bufbegin = buffer;
+
+ while(buffer < (unsigned char *)bufend) { // Loop to find match
+ if((i = transtab[*buffer++]) == 0)
+ continue; // Continue if not valid 1st char
+ if((expr = (EXPR *) stringlist[i]) == NULL) {
+ // If null pointer
+ assert(0);
+ exit(2); // Die
+ }
+ --buffer; // Back up to first character
+ while(expr != NULL) { // Loop to find match
+ pattern = expr->ex_pattern; // Point to pattern
+ expr = expr->ex_next; // Point to next record
+ if(pattern[0] == '^') { // If match begin line
+ ++pattern; // Skip caret
+ if(buffer > bufbegin && buffer[-1] != '\n') continue;
+ // Don't bother if not at beginning
+ }
+ __try {
+ b = exprmatch((char *)buffer, (char *)pattern);
+ } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION) {
+ b = 0;
+ }
+ if (b) {
+ return((char *)buffer);
+ }
+ }
+ ++buffer; // Skip first character
+ }
+ return(NULL); // No match
+}
diff --git a/private/utils/findstr/recurse.c b/private/utils/findstr/recurse.c
new file mode 100644
index 000000000..1611d0e17
--- /dev/null
+++ b/private/utils/findstr/recurse.c
@@ -0,0 +1,229 @@
+// recurse.c
+
+#include <ctype.h>
+#include <direct.h>
+#include <malloc.h>
+#include <string.h>
+#include <windows.h>
+#include <assert.h>
+
+typedef struct patarray_s {
+ HANDLE hfind; // handle for FindFirstFile/FindNextFile
+ BOOLEAN find_next_file; // TRUE if FindNextFile is to be called
+ BOOLEAN IsDir; // TRUE if current found file is a dir
+ char szfile[MAX_PATH];// Name of file/dir found
+} patarray_t;
+
+typedef struct dirstack_s {
+ struct dirstack_s *next; // Next element in stack
+ struct dirstack_s *prev; // Previous element in stack
+ HANDLE hfind;
+ patarray_t *ppatarray; // pointer to an array of pattern records
+ char szdir[1]; // Directory name
+} dirstack_t; // Directory stack
+
+#define FA_ATTR(x) ((x).dwFileAttributes)
+#define FA_CCHNAME(x) MAX_PATH
+#define FA_NAME(x) ((x).cFileName)
+#define FA_ALL (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
+ FILE_ATTRIBUTE_SYSTEM)
+#define FA_DIR FILE_ATTRIBUTE_DIRECTORY
+
+static dirstack_t *pdircur = NULL; // Current directory pointer
+
+void
+makename(
+ char *pszfile,
+ char *pszname
+ )
+{
+ dirstack_t *pdir; // Directory stack pointer
+
+ *pszfile = '\0'; // Start with null string
+ pdir = pdircur; // Point at last entry
+ if (pdir->next != pdircur) { // If not only entry
+ do {
+ pdir = pdir->next; // Advance to next subdirectory
+ strcat(pszfile,pdir->szdir);// Add the subdirectory
+ } while (pdir != pdircur); // Do until current directory
+ }
+ strcat(pszfile,pszname);
+}
+
+
+int
+filematch(
+ char *pszfile,
+ char **ppszpat,
+ int cpat
+ )
+{
+ WIN32_FIND_DATA fi, fi2;
+ BOOL b;
+ int i;
+ dirstack_t *pdir;
+ patarray_t *pPatFind;
+
+ assert(INVALID_HANDLE_VALUE != NULL);
+
+ if (pdircur == NULL) {
+
+ // If stack empty
+ if ((pdircur = (dirstack_t *) malloc(sizeof(dirstack_t))) == NULL)
+ return(-1); // Fail if allocation fails
+
+ if ((pdircur->ppatarray =
+ (patarray_t *) malloc(sizeof(patarray_t)*cpat)) == NULL) {
+ free(pdircur);
+ return(-1);
+ }
+ pdircur->szdir[0] = '\0'; // Root has no name
+ pdircur->hfind = INVALID_HANDLE_VALUE; // No search handle yet
+ pdircur->next = pdircur->prev = pdircur; // Entry points to self
+ for (i=0; i<cpat; i++) {
+ pdircur->ppatarray[i].hfind = INVALID_HANDLE_VALUE;
+ pdircur->ppatarray[i].szfile[0] = '\0';
+ }
+ }
+
+ while (pdircur != NULL) {
+ // While directories remain
+
+ b = TRUE;
+
+ if (pdircur->hfind == INVALID_HANDLE_VALUE) {
+ // If no handle yet
+
+ makename(pszfile,"*.*"); // Make search name
+
+ pdircur->hfind = FindFirstFile((LPSTR) pszfile,
+ (LPWIN32_FIND_DATA) &fi); // Find first matching entry
+ } else
+
+ b = FindNextFile(pdircur->hfind,
+ (LPWIN32_FIND_DATA) &fi); // Else find next matching entry
+
+ if (b == FALSE || pdircur->hfind == INVALID_HANDLE_VALUE) {
+ // If search fails
+
+ if (pdircur->hfind != INVALID_HANDLE_VALUE)
+ FindClose(pdircur->hfind);
+ pdir = pdircur; // Point at record to delete
+ if ((pdircur = pdir->prev) != pdir) {
+ // If no parent directory
+
+ pdircur->next = pdir->next; // Delete record from list
+ pdir->next->prev = pdircur;
+ } else
+ pdircur = NULL; // Else cause search to stop
+
+ pPatFind = pdir->ppatarray;
+ for (i=0; i<cpat; i++) {
+ if (pPatFind[i].hfind != NULL &&
+ pPatFind[i].hfind != INVALID_HANDLE_VALUE)
+ FindClose(pPatFind[i].hfind);
+ }
+ free(pdir->ppatarray);
+ free(pdir); // Free the record
+ continue; // Top of loop
+ }
+
+
+ if (FA_ATTR(fi) & FA_DIR) {
+ // If subdirectory found
+
+ if (strcmp(FA_NAME(fi),".") != 0 && strcmp(FA_NAME(fi),"..") != 0 &&
+ (pdir = (dirstack_t *) malloc(sizeof(dirstack_t)+FA_CCHNAME(fi)+1)) != NULL)
+ {
+ if ((pdir->ppatarray =
+ (patarray_t *) malloc(sizeof(patarray_t)*cpat)) == NULL) {
+ free(pdir);
+ continue;
+ }
+ // If not "." nor ".." and alloc okay
+
+ strcpy(pdir->szdir,FA_NAME(fi)); // Copy name to buffer
+ strcat(pdir->szdir,"\\"); // Add trailing backslash
+ pdir->hfind = INVALID_HANDLE_VALUE; // No search handle yet
+ pdir->next = pdircur->next; // Insert entry in linked list
+ pdir->prev = pdircur;
+ for (i=0; i<cpat; i++) {
+ pdir->ppatarray[i].hfind = INVALID_HANDLE_VALUE;
+ pdir->ppatarray[i].szfile[0] = '\0';
+ }
+ pdircur->next = pdir;
+ pdir->next->prev = pdir;
+ pdircur = pdir; // Make new entry current
+ }
+ continue; // Top of loop
+ }
+
+ pPatFind = pdircur->ppatarray;
+ for (i = cpat; i-- > 0; ) {
+ // Loop to see if we care
+ b = (pPatFind[i].hfind != NULL);
+ for (;;) {
+ if (pPatFind[i].hfind == INVALID_HANDLE_VALUE) {
+ makename(pszfile, ppszpat[i]);
+ pPatFind[i].hfind = FindFirstFile(pszfile, &fi2);
+ b = (pPatFind[i].hfind != INVALID_HANDLE_VALUE);
+ pPatFind[i].find_next_file = FALSE;
+ if (b) {
+ strcpy(pPatFind[i].szfile, FA_NAME(fi2));
+ pPatFind[i].IsDir = (BOOLEAN)(FA_ATTR(fi2) & FA_DIR);
+ }
+ } else if (pPatFind[i].find_next_file) {
+ b = FindNextFile(pPatFind[i].hfind, &fi2);
+ pPatFind[i].find_next_file = FALSE;
+ if (b) {
+ strcpy(pPatFind[i].szfile, FA_NAME(fi2));
+ pPatFind[i].IsDir = (BOOLEAN)(FA_ATTR(fi2) & FA_DIR);
+ }
+ }
+ if (b) {
+ if (pPatFind[i].IsDir) {
+ pPatFind[i].find_next_file = TRUE;
+ } else
+ break; // found a file to do matching
+ } else {
+ if (pPatFind[i].hfind != NULL &&
+ pPatFind[i].hfind != INVALID_HANDLE_VALUE) {
+ FindClose(pPatFind[i].hfind);
+ pPatFind[i].hfind = NULL;
+ }
+ pPatFind[i].find_next_file = FALSE;
+ break; // exhausted all entries
+ }
+ } // for
+
+ if (b) {
+ if (strcmp(FA_NAME(fi), pPatFind[i].szfile) == 0) {
+ pPatFind[i].find_next_file = TRUE;
+ makename(pszfile, FA_NAME(fi));
+ return 1;
+ }
+ }
+ }
+ }
+ return(-1); // No match found
+}
+
+
+
+#ifdef TEST
+#include <process.h>
+#include <stdio.h>
+
+void
+main(
+ int carg,
+ char **ppszarg
+ )
+{
+ char szfile[MAX_PATH]; // if OS2: CCHPATHMAX];
+
+ while (filematch(szfile,ppszarg,carg) >= 0)
+ printf("%s\n",szfile);
+ exit(0);
+}
+#endif
diff --git a/private/utils/findstr/sources b/private/utils/findstr/sources
new file mode 100644
index 000000000..91061a0f5
--- /dev/null
+++ b/private/utils/findstr/sources
@@ -0,0 +1,51 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=utils
+MINORCOMP=findstr
+
+USE_CRTDLL=1
+C_DEFINES = $(C_DEFINES) -DDBCS=1
+
+TARGETNAME=findstr
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+SOURCES=qmatch.c \
+ recurse.c \
+ findstr.c \
+ findstr.rc \
+ fsmsg.mc
+
+UMTYPE=console
+
+PASS0_HEADERDIR=.
+PASS0_SOURCEDIR=.
+MC_FLAGS=-v
+
+USECXX_FLAG=/Tp
+
+TARGETLIBS= \
+ $(BASEDIR)\public\sdk\lib\*\binmode.obj \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib
diff --git a/private/utils/fmifs/dirs b/private/utils/fmifs/dirs
new file mode 100644
index 000000000..c4db5a979
--- /dev/null
+++ b/private/utils/fmifs/dirs
@@ -0,0 +1,16 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+!ENDIF
+
+DIRS= src
diff --git a/private/utils/fmifs/inc/chkmsg.hxx b/private/utils/fmifs/inc/chkmsg.hxx
new file mode 100644
index 000000000..666d66246
--- /dev/null
+++ b/private/utils/fmifs/inc/chkmsg.hxx
@@ -0,0 +1,81 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ chkmsg.hxx
+
+Abstract:
+
+ This class is an implementation of the MESSAGE class which uses
+ an FMIFS callback function as its means of communicating results.
+ This is used only for the CHKDSK functionality, and overrides the
+ DisplayV method of the FMIFS_MESSAGE class.
+
+Author:
+
+ Bruce Forstall (brucefo) 13-Jul-93
+
+--*/
+
+#if !defined( _FMIFS_CHKMSG_DEFN_ )
+
+#define _FMIFS_CHKMSG_DEFN_
+
+#define UNINITIALIZED_BOOLEAN 2
+
+#include "fmifsmsg.hxx"
+
+DECLARE_CLASS( FMIFS_CHKMSG );
+
+class FMIFS_CHKMSG : public FMIFS_MESSAGE {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( FMIFS_CHKMSG );
+
+ VIRTUAL
+ ~FMIFS_CHKMSG(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Initialize(
+ IN FMIFS_CALLBACK CallBack
+ );
+
+ VIRTUAL
+ BOOLEAN
+ DisplayV(
+ IN PCSTR Format,
+ IN va_list VarPointer
+ );
+
+ VIRTUAL
+ BOOLEAN
+ IsYesResponse(
+ IN BOOLEAN Default
+ );
+
+ VIRTUAL
+ PMESSAGE
+ Dup(
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ BOOL _lastyesnoquery;
+};
+
+#endif // _FMIFS_CHKMSG_DEFN_
diff --git a/private/utils/fmifs/inc/fmifs.h b/private/utils/fmifs/inc/fmifs.h
new file mode 100644
index 000000000..77c452a84
--- /dev/null
+++ b/private/utils/fmifs/inc/fmifs.h
@@ -0,0 +1,404 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ fmifs.h
+
+Abstract:
+
+ This header file contains the specification of the interface
+ between the file manager and fmifs.dll for the purposes of
+ accomplishing IFS functions.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 6-Mar-92
+
+--*/
+
+#if !defined( _FMIFS_DEFN_ )
+
+#define _FMIFS_DEFN_
+
+
+//
+// These are the defines for 'PacketType'.
+//
+
+typedef enum _FMIFS_PACKET_TYPE {
+ FmIfsPercentCompleted,
+ FmIfsFormatReport,
+ FmIfsInsertDisk,
+ FmIfsIncompatibleFileSystem,
+ FmIfsFormattingDestination,
+ FmIfsIncompatibleMedia,
+ FmIfsAccessDenied,
+ FmIfsMediaWriteProtected,
+ FmIfsCantLock,
+ FmIfsCantQuickFormat,
+ FmIfsIoError,
+ FmIfsFinished,
+ FmIfsBadLabel,
+#if defined( DBLSPACE_ENABLED )
+ FmIfsDblspaceCreateFailed,
+ FmIfsDblspaceMountFailed,
+ FmIfsDblspaceDriveLetterFailed,
+ FmIfsDblspaceCreated,
+ FmIfsDblspaceMounted,
+#endif // DBLSPACE_ENABLED
+ FmIfsCheckOnReboot,
+ FmIfsTextMessage,
+ FmIfsHiddenStatus
+} FMIFS_PACKET_TYPE, *PFMIFS_PACKET_TYPE;
+
+typedef struct _FMIFS_PERCENT_COMPLETE_INFORMATION {
+ ULONG PercentCompleted;
+} FMIFS_PERCENT_COMPLETE_INFORMATION, *PFMIFS_PERCENT_COMPLETE_INFORMATION;
+
+typedef struct _FMIFS_FORMAT_REPORT_INFORMATION {
+ ULONG KiloBytesTotalDiskSpace;
+ ULONG KiloBytesAvailable;
+} FMIFS_FORMAT_REPORT_INFORMATION, *PFMIFS_FORMAT_REPORT_INFORMATION;
+
+// The packet for FmIfsDblspaceCreated is a Unicode string
+// giving the name of the Compressed Volume File; it is not
+// necessarily zero-terminated.
+//
+
+#define DISK_TYPE_GENERIC 0
+#define DISK_TYPE_SOURCE 1
+#define DISK_TYPE_TARGET 2
+#define DISK_TYPE_SOURCE_AND_TARGET 3
+
+typedef struct _FMIFS_INSERT_DISK_INFORMATION {
+ ULONG DiskType;
+} FMIFS_INSERT_DISK_INFORMATION, *PFMIFS_INSERT_DISK_INFORMATION;
+
+typedef struct _FMIFS_IO_ERROR_INFORMATION {
+ ULONG DiskType;
+ ULONG Head;
+ ULONG Track;
+} FMIFS_IO_ERROR_INFORMATION, *PFMIFS_IO_ERROR_INFORMATION;
+
+typedef struct _FMIFS_FINISHED_INFORMATION {
+ BOOLEAN Success;
+} FMIFS_FINISHED_INFORMATION, *PFMIFS_FINISHED_INFORMATION;
+
+typedef struct _FMIFS_CHECKONREBOOT_INFORMATION {
+ OUT BOOLEAN QueryResult; // TRUE for "yes", FALSE for "no"
+} FMIFS_CHECKONREBOOT_INFORMATION, *PFMIFS_CHECKONREBOOT_INFORMATION;
+
+typedef enum _TEXT_MESSAGE_TYPE {
+ MESSAGE_TYPE_PROGRESS,
+ MESSAGE_TYPE_RESULTS,
+ MESSAGE_TYPE_FINAL
+} TEXT_MESSAGE_TYPE, *PTEXT_MESSAGE_TYPE;
+
+typedef struct _FMIFS_TEXT_MESSAGE {
+ IN TEXT_MESSAGE_TYPE MessageType;
+ IN PSTR Message;
+} FMIFS_TEXT_MESSAGE, *PFMIFS_TEXT_MESSAGE;
+
+
+
+
+//
+// This is a list of supported floppy media types for format.
+//
+
+typedef enum _FMIFS_MEDIA_TYPE {
+ FmMediaUnknown,
+ FmMediaF5_160_512, // 5.25", 160KB, 512 bytes/sector
+ FmMediaF5_180_512, // 5.25", 180KB, 512 bytes/sector
+ FmMediaF5_320_512, // 5.25", 320KB, 512 bytes/sector
+ FmMediaF5_320_1024, // 5.25", 320KB, 1024 bytes/sector
+ FmMediaF5_360_512, // 5.25", 360KB, 512 bytes/sector
+ FmMediaF3_720_512, // 3.5", 720KB, 512 bytes/sector
+ FmMediaF5_1Pt2_512, // 5.25", 1.2MB, 512 bytes/sector
+ FmMediaF3_1Pt44_512, // 3.5", 1.44MB, 512 bytes/sector
+ FmMediaF3_2Pt88_512, // 3.5", 2.88MB, 512 bytes/sector
+ FmMediaF3_20Pt8_512, // 3.5", 20.8MB, 512 bytes/sector
+ FmMediaRemovable, // Removable media other than floppy
+ FmMediaFixed,
+ FmMediaF3_120M_512 // 3.5", 120M Floppy
+} FMIFS_MEDIA_TYPE, *PFMIFS_MEDIA_TYPE;
+
+
+//
+// Function types/interfaces.
+//
+
+typedef BOOLEAN
+(*FMIFS_CALLBACK)(
+ IN FMIFS_PACKET_TYPE PacketType,
+ IN ULONG PacketLength,
+ IN PVOID PacketData
+ );
+
+typedef
+VOID
+(*PFMIFS_FORMAT_ROUTINE)(
+ IN PWSTR DriveName,
+ IN FMIFS_MEDIA_TYPE MediaType,
+ IN PWSTR FileSystemName,
+ IN PWSTR Label,
+ IN BOOLEAN Quick,
+ IN FMIFS_CALLBACK Callback
+ );
+
+typedef
+VOID
+(*PFMIFS_FORMATEX_ROUTINE)(
+ IN PWSTR DriveName,
+ IN FMIFS_MEDIA_TYPE MediaType,
+ IN PWSTR FileSystemName,
+ IN PWSTR Label,
+ IN BOOLEAN Quick,
+ IN ULONG ClusterSize,
+ IN FMIFS_CALLBACK Callback
+ );
+
+typedef
+BOOLEAN
+(*PFMIFS_ENABLECOMP_ROUTINE)(
+ IN PWSTR DriveName,
+ IN USHORT CompressionFormat
+ );
+
+
+typedef
+VOID
+(*PFMIFS_CHKDSK_ROUTINE)(
+ IN PWSTR DriveName,
+ IN PWSTR FileSystemName,
+ IN BOOLEAN Fix,
+ IN BOOLEAN Verbose,
+ IN BOOLEAN OnlyIfDirty,
+ IN BOOLEAN Recover,
+ IN PWSTR PathToCheck,
+ IN BOOLEAN Extend,
+ IN FMIFS_CALLBACK Callback
+ );
+
+typedef
+VOID
+(*PFMIFS_EXTEND_ROUTINE)(
+ IN PWSTR DriveName,
+ IN BOOLEAN Verify,
+ IN FMIFS_CALLBACK Callback
+ );
+
+
+typedef
+VOID
+(*PFMIFS_DISKCOPY_ROUTINE)(
+ IN PWSTR SourceDrive,
+ IN PWSTR DestDrive,
+ IN BOOLEAN Verify,
+ IN FMIFS_CALLBACK Callback
+ );
+
+typedef
+BOOLEAN
+(*PFMIFS_SETLABEL_ROUTINE)(
+ IN PWSTR DriveName,
+ IN PWSTR Label
+ );
+
+typedef
+BOOLEAN
+(*PFMIFS_QSUPMEDIA_ROUTINE)(
+ IN PWSTR DriveName,
+ OUT PFMIFS_MEDIA_TYPE MediaTypeArray OPTIONAL,
+ IN ULONG NumberOfArrayEntries,
+ OUT PULONG NumberOfMediaTypes
+ );
+
+
+typedef
+VOID
+(*PFMIFS_DOUBLESPACE_CREATE_ROUTINE)(
+ IN PWSTR HostDriveName,
+ IN ULONG Size,
+ IN PWSTR Label,
+ IN PWSTR NewDriveName,
+ IN FMIFS_CALLBACK Callback
+ );
+
+#if defined( DBLSPACE_ENABLED )
+typedef
+VOID
+(*PFMIFS_DOUBLESPACE_DELETE_ROUTINE)(
+ IN PWSTR DblspaceDriveName,
+ IN FMIFS_CALLBACK Callback
+ );
+
+typedef
+VOID
+(*PFMIFS_DOUBLESPACE_MOUNT_ROUTINE)(
+ IN PWSTR HostDriveName,
+ IN PWSTR CvfName,
+ IN PWSTR NewDriveName,
+ IN FMIFS_CALLBACK Callback
+ );
+
+typedef
+VOID
+(*PFMIFS_DOUBLESPACE_DISMOUNT_ROUTINE)(
+ IN PWSTR DblspaceDriveName,
+ IN FMIFS_CALLBACK Callback
+ );
+
+typedef
+BOOLEAN
+(*PFMIFS_DOUBLESPACE_QUERY_INFO_ROUTINE)(
+ IN PWSTR DosDriveName,
+ OUT PBOOLEAN IsRemovable,
+ OUT PBOOLEAN IsFloppy,
+ OUT PBOOLEAN IsCompressed,
+ OUT PBOOLEAN Error,
+ OUT PWSTR NtDriveName,
+ IN ULONG MaxNtDriveNameLength,
+ OUT PWSTR CvfFileName,
+ IN ULONG MaxCvfFileNameLength,
+ OUT PWSTR HostDriveName,
+ IN ULONG MaxHostDriveNameLength
+ );
+
+typedef
+BOOLEAN
+(*PFMIFS_DOUBLESPACE_SET_AUTMOUNT_ROUTINE)(
+ IN BOOLEAN EnableAutomount
+ );
+
+#endif // DBLSPACE_ENABLED
+
+
+VOID
+Format(
+ IN PWSTR DriveName,
+ IN FMIFS_MEDIA_TYPE MediaType,
+ IN PWSTR FileSystemName,
+ IN PWSTR Label,
+ IN BOOLEAN Quick,
+ IN FMIFS_CALLBACK Callback
+ );
+
+VOID
+FormatEx(
+ IN PWSTR DriveName,
+ IN FMIFS_MEDIA_TYPE MediaType,
+ IN PWSTR FileSystemName,
+ IN PWSTR Label,
+ IN BOOLEAN Quick,
+ IN ULONG ClusterSize,
+ IN FMIFS_CALLBACK Callback
+ );
+
+BOOLEAN
+EnableVolumeCompression(
+ IN PWSTR DriveName,
+ IN USHORT CompressionFormat
+ );
+
+VOID
+Chkdsk(
+ IN PWSTR DriveName,
+ IN PWSTR FileSystemName,
+ IN BOOLEAN Fix,
+ IN BOOLEAN Verbose,
+ IN BOOLEAN OnlyIfDirty,
+ IN BOOLEAN Recover,
+ IN PWSTR PathToCheck,
+ IN BOOLEAN Extend,
+ IN FMIFS_CALLBACK Callback
+ );
+
+VOID
+Extend(
+ IN PWSTR DriveName,
+ IN BOOLEAN Verify,
+ IN FMIFS_CALLBACK Callback
+ );
+
+VOID
+DiskCopy(
+ IN PWSTR SourceDrive,
+ IN PWSTR DestDrive,
+ IN BOOLEAN Verify,
+ IN FMIFS_CALLBACK Callback
+ );
+
+BOOLEAN
+SetLabel(
+ IN PWSTR DriveName,
+ IN PWSTR Label
+ );
+
+BOOLEAN
+QuerySupportedMedia(
+ IN PWSTR DriveName,
+ OUT PFMIFS_MEDIA_TYPE MediaTypeArray OPTIONAL,
+ IN ULONG NumberOfArrayEntries,
+ OUT PULONG NumberOfMediaTypes
+ );
+
+VOID
+DoubleSpaceCreate(
+ IN PWSTR HostDriveName,
+ IN ULONG Size,
+ IN PWSTR Label,
+ IN PWSTR NewDriveName,
+ IN FMIFS_CALLBACK Callback
+ );
+
+#if defined( DBLSPACE_ENABLED )
+
+VOID
+DoubleSpaceDelete(
+ IN PWSTR DblspaceDriveName,
+ IN FMIFS_CALLBACK Callback
+ );
+
+VOID
+DoubleSpaceMount(
+ IN PWSTR HostDriveName,
+ IN PWSTR CvfName,
+ IN PWSTR NewDriveName,
+ IN FMIFS_CALLBACK Callback
+ );
+
+VOID
+DoubleSpaceDismount(
+ IN PWSTR DblspaceDriveName,
+ IN FMIFS_CALLBACK Callback
+ );
+
+// Miscellaneous prototypes:
+//
+BOOLEAN
+FmifsQueryDriveInformation(
+ IN PWSTR DosDriveName,
+ OUT PBOOLEAN IsRemovable,
+ OUT PBOOLEAN IsFloppy,
+ OUT PBOOLEAN IsCompressed,
+ OUT PBOOLEAN Error,
+ OUT PWSTR NtDriveName,
+ IN ULONG MaxNtDriveNameLength,
+ OUT PWSTR CvfFileName,
+ IN ULONG MaxCvfFileNameLength,
+ OUT PWSTR HostDriveName,
+ IN ULONG MaxHostDriveNameLength
+ );
+
+BOOLEAN
+FmifsSetAutomount(
+ IN BOOLEAN EnableAutomount
+ );
+
+#endif
+
+
+#endif // _FMIFS_DEFN_
diff --git a/private/utils/fmifs/inc/fmifsmsg.hxx b/private/utils/fmifs/inc/fmifsmsg.hxx
new file mode 100644
index 000000000..629cbaa76
--- /dev/null
+++ b/private/utils/fmifs/inc/fmifsmsg.hxx
@@ -0,0 +1,120 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ fmifsmsg.hxx
+
+Abstract:
+
+ This class is an implementation of the MESSAGE class which uses
+ an FMIFS callback function as its means of communicating results.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 9-Mar-92
+
+--*/
+
+#if !defined( _FMIFS_MESSAGE_DEFN_ )
+
+#define _FMIFS_MESSAGE_DEFN_
+
+#include "message.hxx"
+#include "fmifs.h"
+
+DECLARE_CLASS( FMIFS_MESSAGE );
+
+class FMIFS_MESSAGE : public MESSAGE {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( FMIFS_MESSAGE );
+
+ VIRTUAL
+ ~FMIFS_MESSAGE(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Initialize(
+ IN FMIFS_CALLBACK CallBack
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Set(
+ IN MSGID MsgId,
+ IN MESSAGE_TYPE MessageType DEFAULT NORMAL_MESSAGE,
+ IN ULONG MessageVisual DEFAULT NORMAL_VISUAL
+ );
+
+ VIRTUAL
+ BOOLEAN
+ DisplayV(
+ IN PCSTR Format,
+ IN va_list VarPointer
+ );
+
+ VIRTUAL
+ PMESSAGE
+ Dup(
+ );
+
+ protected:
+
+ MSGID _msgid;
+ MESSAGE_TYPE _msgtype;
+ ULONG _msgvisual;
+ FMIFS_CALLBACK _callback;
+ ULONG _kilobytes_total_disk_space;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+};
+
+
+INLINE
+BOOLEAN
+FMIFS_MESSAGE::Set(
+ IN MSGID MsgId,
+ IN MESSAGE_TYPE MessageType,
+ IN ULONG MessageVisual
+ )
+/*++
+
+Routine Description:
+
+ This routine sets up the class to display the message with the 'MsgId'
+ resource identifier.
+
+Arguments:
+
+ MsgId - Supplies the resource message id.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ _msgid = MsgId;
+ _msgtype = MessageType;
+ _msgvisual = MessageVisual;
+ return TRUE;
+}
+
+
+#endif // _FMIFS_MESSAGE_DEFN_
diff --git a/private/utils/fmifs/src/chkdsk.cxx b/private/utils/fmifs/src/chkdsk.cxx
new file mode 100644
index 000000000..59f9f67bf
--- /dev/null
+++ b/private/utils/fmifs/src/chkdsk.cxx
@@ -0,0 +1,124 @@
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+extern "C" {
+#include "fmifs.h"
+};
+#include "fmifsmsg.hxx"
+#include "chkmsg.hxx"
+#include "ifssys.hxx"
+#include "wstring.hxx"
+#include "ifsentry.hxx"
+#include "system.hxx"
+#include "drive.hxx"
+
+
+VOID
+Chkdsk(
+ IN PWSTR DriveName,
+ IN PWSTR FileSystemName,
+ IN BOOLEAN Fix,
+ IN BOOLEAN Verbose,
+ IN BOOLEAN OnlyIfDirty,
+ IN BOOLEAN Recover,
+ IN PWSTR PathToCheck,
+ IN BOOLEAN Extend,
+ IN FMIFS_CALLBACK Callback
+ )
+
+/*++
+
+Routine Description:
+
+ This routine loads and calls the correct DLL to chkdsk the
+ given volume.
+
+ This is is for either GUI or text mode.
+
+Arguments:
+
+ DriveName - Supplies the DOS style drive name.
+ FileSystemName - Supplies the file system name (e.g., FAT) of the volume
+ Fix - Whether or not to fix detected consistency problems
+ Verbose - Whether to print every filename (this is a stupid
+ option for chkdsk!)
+ OnlyIfDirty - Whether to check consistency only if the volume is dirty
+ Recover - Whether to perform a full sector read test
+ PathToCheck - Supplies a path to check for fragmentation
+ Extend - Whether the volume is being extended
+ Callback - Supplies the necessary call back for
+ communication with the client
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ FMIFS_CHKMSG message;
+ DSTRING chkdsk_string;
+ DSTRING library_name;
+ DSTRING file_system_name;
+ CHKDSK_FN chkdsk_function;
+ HANDLE dll_handle;
+ DSTRING ntdrivename;
+ BOOLEAN result;
+ DSTRING dosdrivename;
+ FMIFS_FINISHED_INFORMATION finished_info;
+ DWORD OldErrorMode;
+ PATH check_path;
+ ULONG chkdsk_result;
+
+ // Initialize the message object with the callback function.
+ // Load the file system DLL.
+ // Compute the NT style drive name.
+
+ if (!message.Initialize(Callback) ||
+ !chkdsk_string.Initialize("Chkdsk") ||
+ !library_name.Initialize("U") ||
+ !file_system_name.Initialize(FileSystemName) ||
+ !library_name.Strcat(&file_system_name) ||
+ !(chkdsk_function = (CHKDSK_FN)
+ SYSTEM::QueryLibraryEntryPoint(&library_name,
+ &chkdsk_string,
+ &dll_handle)) ||
+ !dosdrivename.Initialize(DriveName) ||
+ (NULL != PathToCheck && !check_path.Initialize(PathToCheck)) ||
+ !IFS_SYSTEM::DosDriveNameToNtDriveName(&dosdrivename, &ntdrivename))
+ {
+ finished_info.Success = FALSE;
+ Callback(FmIfsFinished,
+ sizeof(FMIFS_FINISHED_INFORMATION),
+ &finished_info);
+ return;
+ }
+
+ // Disable hard-error popups.
+ OldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS );
+
+ // Call chkdsk.
+
+ result = chkdsk_function(&ntdrivename,
+ &message,
+ Fix,
+ Verbose,
+ OnlyIfDirty,
+ Recover,
+ (NULL == PathToCheck) ? NULL : &check_path,
+ Extend,
+ FALSE,
+ 0,
+ &chkdsk_result);
+
+ // Enable hard-error popups.
+ SetErrorMode( OldErrorMode );
+
+ SYSTEM::FreeLibraryHandle(dll_handle);
+
+ finished_info.Success = (0 == result) ? TRUE : FALSE;
+ Callback(FmIfsFinished,
+ sizeof(FMIFS_FINISHED_INFORMATION),
+ &finished_info);
+}
+
diff --git a/private/utils/fmifs/src/chkmsg.cxx b/private/utils/fmifs/src/chkmsg.cxx
new file mode 100644
index 000000000..bb9d099e8
--- /dev/null
+++ b/private/utils/fmifs/src/chkmsg.cxx
@@ -0,0 +1,292 @@
+#include "ulib.hxx"
+#include "system.hxx"
+#include "chkmsg.hxx"
+#include "rtmsg.h"
+
+
+#define MAX_CHKDSK_MESSAGE_LENGTH 400
+
+
+DEFINE_CONSTRUCTOR(FMIFS_CHKMSG, FMIFS_MESSAGE);
+
+
+FMIFS_CHKMSG::~FMIFS_CHKMSG(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for FMIFS_CHKMSG.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+FMIFS_CHKMSG::Construct(
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the object to a default initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+}
+
+
+VOID
+FMIFS_CHKMSG::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the object to a default initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+}
+
+
+
+BOOLEAN
+FMIFS_CHKMSG::Initialize(
+ IN FMIFS_CALLBACK CallBack
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the class to a valid initial state.
+
+Arguments:
+
+ CallBack - Supplies the callback to the file manager.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ Destroy();
+ _callback = CallBack;
+ _lastyesnoquery = UNINITIALIZED_BOOLEAN;
+ return _callback ? TRUE : FALSE;
+}
+
+
+
+
+BOOLEAN
+FMIFS_CHKMSG::DisplayV(
+ IN PCSTR Format,
+ IN va_list VarPointer
+ )
+/*++
+
+Routine Description:
+
+ This routine displays the message with the specified parameters.
+
+ The format string supports all printf options.
+
+Arguments:
+
+ Format - Supplies a printf style format string.
+ VarPointer - Supplies a varargs pointer to the arguments.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ BOOLEAN r = TRUE;
+ DSTRING string;
+ STR sz[MAX_CHKDSK_MESSAGE_LENGTH];
+ FMIFS_PERCENT_COMPLETE_INFORMATION percent_info;
+ FMIFS_CHECKONREBOOT_INFORMATION reboot_info;
+ FMIFS_TEXT_MESSAGE textMsg;
+
+ if (! (_msgvisual & GUI_MESSAGE) )
+ {
+ return TRUE;
+ }
+
+ switch (_msgid)
+ {
+ case MSG_PERCENT_COMPLETE:
+ {
+ percent_info.PercentCompleted = va_arg(VarPointer, ULONG);
+ r = _callback(FmIfsPercentCompleted,
+ sizeof(FMIFS_PERCENT_COMPLETE_INFORMATION),
+ &percent_info);
+ break;
+ }
+
+ case MSG_CHKDSK_ON_REBOOT_PROMPT:
+ {
+ reboot_info.QueryResult = UNINITIALIZED_BOOLEAN;
+ r = _callback(FmIfsCheckOnReboot,
+ sizeof(FMIFS_CHECKONREBOOT_INFORMATION),
+ &reboot_info);
+
+ _lastyesnoquery = reboot_info.QueryResult;
+
+ break;
+ }
+
+ default:
+ {
+ if (!SYSTEM::QueryResourceStringV(
+ &string,
+ _msgid,
+ Format,
+ VarPointer))
+ {
+ return FALSE;
+ }
+
+ string.QuerySTR(0,TO_END,sz,MAX_CHKDSK_MESSAGE_LENGTH);
+ textMsg.Message = sz;
+
+ switch (_msgid)
+ {
+ case MSG_CHKDSK_CANNOT_SCHEDULE:
+ case MSG_CHKDSK_SCHEDULED:
+ case MSG_CHK_NTFS_ERRORS_FOUND:
+ {
+ textMsg.MessageType = MESSAGE_TYPE_FINAL;
+
+ break;
+ }
+
+ default:
+ {
+ switch (_msgtype)
+ {
+ case PROGRESS_MESSAGE:
+ textMsg.MessageType = MESSAGE_TYPE_PROGRESS;
+ break;
+
+ default:
+ textMsg.MessageType = MESSAGE_TYPE_RESULTS;
+ break;
+ }
+
+ break;
+ }
+ }
+
+ r = _callback(
+ FmIfsTextMessage,
+ sizeof(FMIFS_TEXT_MESSAGE),
+ &textMsg);
+
+ break;
+ }
+ }
+
+ return r;
+}
+
+
+BOOLEAN
+FMIFS_CHKMSG::IsYesResponse(
+ IN BOOLEAN Default
+ )
+/*++
+
+Routine Description:
+
+ This routine returns returns the value loaded from the user during
+ the previous DisplayV() with a query message, or the default
+ if no response (which currently isn't possible...)
+
+Arguments:
+
+ Default - Supplies the default answer
+
+Return Value:
+
+ FALSE - A "no" response.
+ TRUE - A "yes" response.
+
+--*/
+{
+ DebugPrintf(
+ "FMIFS_CHKMSG::IsYesResponse: _lastyesnoquery == %d\n",
+ _lastyesnoquery);
+
+ return (UNINITIALIZED_BOOLEAN == _lastyesnoquery)
+ ? Default
+ : _lastyesnoquery
+ ;
+}
+
+
+
+
+PMESSAGE
+FMIFS_CHKMSG::Dup(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a new MESSAGE of the same type.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to a new MESSAGE object.
+
+--*/
+{
+ PFMIFS_CHKMSG p;
+
+ if (!(p = NEW FMIFS_CHKMSG)) {
+ return NULL;
+ }
+
+ if (!p->Initialize(_callback)) {
+ DELETE(p);
+ return NULL;
+ }
+
+ return p;
+}
diff --git a/private/utils/fmifs/src/diskcopy.cxx b/private/utils/fmifs/src/diskcopy.cxx
new file mode 100644
index 000000000..5ed092fc3
--- /dev/null
+++ b/private/utils/fmifs/src/diskcopy.cxx
@@ -0,0 +1,72 @@
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+extern "C" {
+#include "fmifs.h"
+};
+#include "fmifsmsg.hxx"
+#include "ifssys.hxx"
+#include "wstring.hxx"
+#include "mldcopy.hxx"
+
+
+VOID
+DiskCopy(
+ IN PWSTR SourceDrive,
+ IN PWSTR DestDrive,
+ IN BOOLEAN Verify,
+ IN FMIFS_CALLBACK Callback
+ )
+/*++
+
+Routine Description:
+
+ This routine copies the contents of the floppy in the
+ source drive to the floppy in the destination drive.
+
+Arguments:
+
+ SourceDrive - Supplies the dos style name of the source drive.
+ DestDrive - Supplies the dos style name of the destination drive.
+ Verify - Supplies whether or not writes should be verified.
+ Callback - Supplies the file manager call back function.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ FMIFS_MESSAGE message;
+ DSTRING src_dos_name, dst_dos_name;
+ DSTRING src_nt_name, dst_nt_name;
+ INT r;
+ FMIFS_FINISHED_INFORMATION finished_info;
+
+ if (!message.Initialize(Callback) ||
+ !src_dos_name.Initialize(SourceDrive) ||
+ !dst_dos_name.Initialize(DestDrive) ||
+ !IFS_SYSTEM::DosDriveNameToNtDriveName(&src_dos_name, &src_nt_name) ||
+ !IFS_SYSTEM::DosDriveNameToNtDriveName(&dst_dos_name, &dst_nt_name)) {
+
+ finished_info.Success = FALSE;
+ Callback(FmIfsFinished,
+ sizeof(FMIFS_FINISHED_INFORMATION),
+ &finished_info);
+ return;
+ }
+
+ r = DiskCopyMainLoop(&src_nt_name,
+ &dst_nt_name,
+ &src_dos_name,
+ &dst_dos_name,
+ Verify,
+ &message,
+ &message);
+
+ finished_info.Success = (r <= 1) ? TRUE : FALSE;
+ Callback(FmIfsFinished,
+ sizeof(FMIFS_FINISHED_INFORMATION),
+ &finished_info);
+}
diff --git a/private/utils/fmifs/src/double.cxx b/private/utils/fmifs/src/double.cxx
new file mode 100644
index 000000000..52be20a22
--- /dev/null
+++ b/private/utils/fmifs/src/double.cxx
@@ -0,0 +1,819 @@
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+extern "C" {
+#include "fmifs.h"
+#include "ntdskreg.h"
+};
+#include "fmifsmsg.hxx"
+#include "ifssys.hxx"
+#include "wstring.hxx"
+#include "ifsentry.hxx"
+#include "system.hxx"
+#include "dblentry.hxx"
+#include "drive.hxx"
+#include "rtmsg.h"
+
+BOOLEAN
+FmifsQueryDriveInformation(
+ IN PWSTR DosDriveName,
+ OUT PBOOLEAN IsRemovable,
+ OUT PBOOLEAN IsFloppy,
+ OUT PBOOLEAN IsCompressed,
+ OUT PBOOLEAN Error,
+ OUT PWSTR NtDriveName,
+ IN ULONG MaxNtDriveNameLength,
+ OUT PWSTR CvfFileName,
+ IN ULONG MaxCvfFileNameLength,
+ OUT PWSTR HostDriveName,
+ IN ULONG MaxHostDriveNameLength
+ )
+{
+ DSTRING DosName, DriveName, RootName,
+ NtName, CanonicalNtName,
+ HostName, CvfName;
+ FSTRING DblspaceString, DotHostString, Backslash;
+ DISK_GEOMETRY Geometry;
+ CHNUM position;
+ DWORD FsFlags, BytesReturned;
+ HANDLE DeviceHandle;
+
+ // The Drive Name passed to CreateFile is \\.\\n:
+ //
+ if( !DosName.Initialize( DosDriveName ) ||
+ !DblspaceString.Initialize( L"DBLSPACE" ) ||
+ !DriveName.Initialize( L"\\\\.\\" ) ||
+ !DriveName.Strcat( &DosName ) ||
+ !Backslash.Initialize( L"\\" ) ||
+ !RootName.Initialize( &DosName ) ||
+ !RootName.Strcat( &Backslash ) ) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ // Convert the name to an NT name.
+ //
+ if( !IFS_SYSTEM::DosDriveNameToNtDriveName( &DosName,
+ &NtName ) ) {
+ // This drive does not exist.
+ //
+ *Error = FALSE;
+ return TRUE;
+ }
+
+ // Canonicalize the NT name.
+ //
+ if( !IFS_SYSTEM::QueryCanonicalNtDriveName( &NtName,
+ &CanonicalNtName ) ) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ // Open the device using WIN32 API.
+ //
+ DeviceHandle = CreateFile( DriveName.GetWSTR(),
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_NO_BUFFERING,
+ NULL );
+
+ if( DeviceHandle == INVALID_HANDLE_VALUE ) {
+
+ // This drive doesn't exist, or I can't open it.
+ //
+ DbgPrintf( "Device not opened--Error %d\n", GetLastError() );
+ *Error = FALSE;
+ return FALSE;
+ }
+
+ if( !GetVolumeInformation( RootName.GetWSTR(),
+ NULL, 0, NULL, NULL,
+ &FsFlags,
+ NULL, 0 ) ||
+ !DeviceIoControl( DeviceHandle, IOCTL_DISK_GET_DRIVE_GEOMETRY,
+ NULL, 0,
+ &Geometry, sizeof( Geometry ),
+ &BytesReturned, 0 ) ) {
+
+ // The drive is not available.
+ //
+ CloseHandle( DeviceHandle );
+ *Error = FALSE;
+ return FALSE;
+ }
+
+ CloseHandle( DeviceHandle );
+
+ *IsCompressed = (FsFlags & FILE_VOLUME_IS_COMPRESSED) ? TRUE : FALSE;
+ *IsRemovable = (Geometry.MediaType != Unknown) &&
+ (Geometry.MediaType != FixedMedia);
+ *IsFloppy = (Geometry.MediaType != Unknown) &&
+ (Geometry.MediaType != RemovableMedia) &&
+ (Geometry.MediaType != FixedMedia);
+
+ // Copy the canonical name to the user's buffer (if requested).
+ //
+ if( NtDriveName &&
+ !CanonicalNtName.QueryWSTR( 0, TO_END, NtDriveName,
+ MaxNtDriveNameLength ) ) {
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ if( !*IsCompressed ) {
+
+ // This is not a compressed volume, so we're done.
+ //
+ return TRUE;
+ }
+
+ // The volume is compressed. By convention, its device name
+ // (i.e. the canonical NT name) has one of two forms:
+ // HostDriveName.CvfName or
+ // HostDriveOriginalName
+ // In the former case, the CvfName is always DBLSPACE.nnn.
+ // The latter form is used for Automounted removable media;
+ // in that instance, the host drive is moved to
+ // HostDriveOriginalName.HOST
+ //
+ position = CanonicalNtName.Strstr( &DblspaceString );
+
+ if( position == INVALID_CHNUM ||
+ position == 0 ||
+ CanonicalNtName.QueryChAt( position - 1 ) != '.' ) {
+
+ // The name doesn't have the string "DBLSPACE", so it
+ // must be in the second form.
+ //
+ if( !DotHostString.Initialize( L".HOST" ) ||
+ !HostName.Initialize( &CanonicalNtName ) ||
+ !HostName.Strcat( &DotHostString ) ||
+ !CvfName.Initialize( L"DBLSPACE.000" ) ) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ } else {
+
+ // The name is in the first form.
+ //
+ if( !HostName.Initialize( &CanonicalNtName, 0, position - 1 ) ||
+ !CvfName.Initialize( &CanonicalNtName, position, TO_END ) ) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+ }
+
+ // Copy the host drive name and the CVF file name to the
+ // client's buffers.
+ //
+ if( !HostName.QueryWSTR( 0, TO_END, HostDriveName,
+ MaxHostDriveNameLength ) ||
+ !CvfName.QueryWSTR( 0, TO_END, CvfFileName,
+ MaxCvfFileNameLength ) ) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+MountCompressedDrive(
+ IN PCWSTRING DosHostDriveName,
+ IN PCWSTRING HostFileName,
+ IN PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This function mounts a double-space volume.
+ it does not assign a drive letter.
+
+Arguments:
+
+ DosHostDriveName -- Supplies the DOS name of the volume on which
+ the host CVF resides.
+ HostFileName -- Supplies the name of the Compressed Volume File.
+ Message -- Supplies an outlet for messages.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ DSTRING NtDriveName;
+ DP_DRIVE HostDrive;
+
+ DbgPtrAssert( DosHostDriveName );
+ DbgPtrAssert( HostFileName );
+ DbgPtrAssert( Message );
+
+
+ return( IFS_SYSTEM::DosDriveNameToNtDriveName( DosHostDriveName,
+ &NtDriveName ) &&
+ HostDrive.Initialize( &NtDriveName, Message, TRUE ) &&
+ HostDrive.MountCvf( HostFileName, Message ) );
+}
+
+BOOLEAN
+AssignDoubleSpaceDriveLetter(
+ IN PCWSTRING DosHostDriveName,
+ IN PCWSTRING HostFileName,
+ IN PCWSTRING NewDriveName,
+ IN PMESSAGE Message
+ )
+/*++
+--*/
+{
+ CONST BufferLength = 128;
+ WCHAR NameBuffer[BufferLength];
+ DSTRING Dot;
+ FSTRING TargetName;
+
+ DbgPtrAssert( DosHostDriveName );
+ DbgPtrAssert( HostFileName );
+ DbgPtrAssert( NewDriveName );
+ DbgPtrAssert( Message );
+
+ // The device name for the compressed volume is the
+ // concatenation of:
+ // - the device name of the host drive
+ // - "."
+ // - the file name of the Compressed Volume File.
+ //
+ if( !QueryDosDevice( DosHostDriveName->GetWSTR(),
+ NameBuffer,
+ BufferLength ) ) {
+
+ Message->Set( MSG_DBLSPACE_CANT_ASSIGN_DRIVE_LETTER );
+ Message->Display( "%W", NewDriveName );
+ return FALSE;
+ }
+
+ if( !TargetName.Initialize( NameBuffer, BufferLength ) ||
+ !Dot.Initialize( "." ) ||
+ !TargetName.Strcat( &Dot ) ||
+ !TargetName.Strcat( HostFileName ) ) {
+
+ Message->Set( MSG_DBLSPACE_CANT_ASSIGN_DRIVE_LETTER );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !DefineDosDevice( DDD_RAW_TARGET_PATH,
+ NewDriveName->GetWSTR(),
+ TargetName.GetWSTR() ) ) {
+
+ Message->Set( MSG_DBLSPACE_CANT_ASSIGN_DRIVE_LETTER );
+ Message->Display( "%W", NewDriveName );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+#if !defined ( _READ_WRITE_DOUBLESPACE_ )
+VOID
+DoubleSpaceCreate(
+ IN PWSTR HostDriveName,
+ IN ULONG Size,
+ IN PWSTR Label,
+ IN PWSTR NewDriveName,
+ IN FMIFS_CALLBACK Callback
+ )
+{
+ FMIFS_MESSAGE message;
+ FMIFS_FINISHED_INFORMATION finished_info;
+ DSTRING HostDriveNameString,
+ HostNtDriveNameString,
+ NewDriveNameString,
+ LabelString,
+ CreatedName;
+ BOOLEAN result;
+
+ if( !message.Initialize( Callback ) ||
+ !HostDriveNameString.Initialize( HostDriveName ) ||
+ !IFS_SYSTEM::DosDriveNameToNtDriveName( &HostDriveNameString,
+ &HostNtDriveNameString ) ||
+ ( Label && !LabelString.Initialize( Label )) ||
+ (!Label && !LabelString.Initialize( "" )) ||
+ !NewDriveNameString.Initialize( NewDriveName ) ) {
+
+ finished_info.Success = FALSE;
+ Callback(FmIfsFinished,
+ sizeof(FMIFS_FINISHED_INFORMATION),
+ &finished_info);
+ return;
+ }
+
+ result = FatDbCreate( &HostNtDriveNameString,
+ NULL,
+ Size,
+ &message,
+ &LabelString,
+ &CreatedName );
+
+ if( !result ) {
+
+ message.Set( MSG_DBLSPACE_VOLUME_NOT_CREATED );
+ message.Display( "" );
+ finished_info.Success = result;
+ Callback(FmIfsFinished,
+ sizeof(FMIFS_FINISHED_INFORMATION),
+ &finished_info);
+ return;
+ }
+
+ message.Set( MSG_DBLSPACE_VOLUME_CREATED );
+ message.Display( "%W%W", &HostDriveNameString, &CreatedName );
+
+ result = MountCompressedDrive( &HostDriveNameString,
+ &CreatedName,
+ &message ) &&
+ AssignDoubleSpaceDriveLetter( &HostDriveNameString,
+ &CreatedName,
+ &NewDriveNameString,
+ &message );
+
+ if( result ) {
+
+ message.Set( MSG_DBLSPACE_MOUNTED );
+ message.Display( "%W%W", &CreatedName, &NewDriveNameString );
+ }
+
+ finished_info.Success = result;
+ Callback(FmIfsFinished,
+ sizeof(FMIFS_FINISHED_INFORMATION),
+ &finished_info);
+}
+
+VOID
+DoubleSpaceDelete(
+ IN PWSTR DblspaceDriveName,
+ IN FMIFS_CALLBACK Callback
+ )
+{
+ FMIFS_MESSAGE message;
+ FMIFS_FINISHED_INFORMATION finished_info;
+ DSTRING DriveNameString;
+ BOOLEAN result;
+
+ if( !message.Initialize( Callback ) ||
+ !DriveNameString.Initialize( DblspaceDriveName ) ) {
+
+ finished_info.Success = FALSE;
+ Callback(FmIfsFinished,
+ sizeof(FMIFS_FINISHED_INFORMATION),
+ &finished_info);
+ return;
+ }
+
+ result = FatDbDelete( &DriveNameString,
+ &message );
+
+ finished_info.Success = result;
+ Callback(FmIfsFinished,
+ sizeof(FMIFS_FINISHED_INFORMATION),
+ &finished_info);
+}
+#endif
+
+
+VOID
+DoubleSpaceMount(
+ IN PWSTR HostDriveName,
+ IN PWSTR CvfName,
+ IN PWSTR NewDriveName,
+ IN FMIFS_CALLBACK Callback
+ )
+{
+ FMIFS_MESSAGE message;
+ FMIFS_FINISHED_INFORMATION finished_info;
+ DSTRING HostDriveNameString,
+ CvfNameString,
+ NewDriveNameString;
+ BOOLEAN result;
+
+ if( !message.Initialize( Callback ) ||
+ !HostDriveNameString.Initialize( HostDriveName ) ||
+ !CvfNameString.Initialize( CvfName ) ||
+ !NewDriveNameString.Initialize( NewDriveName ) ) {
+
+ finished_info.Success = FALSE;
+ Callback(FmIfsFinished,
+ sizeof(FMIFS_FINISHED_INFORMATION),
+ &finished_info);
+ return;
+ }
+
+ result = MountCompressedDrive( &HostDriveNameString,
+ &CvfNameString,
+ &message ) &&
+ AssignDoubleSpaceDriveLetter( &HostDriveNameString,
+ &CvfNameString,
+ &NewDriveNameString,
+ &message );
+
+ if( result ) {
+
+ message.Set( MSG_DBLSPACE_MOUNTED );
+ message.Display( "%W%W", &CvfNameString, &NewDriveNameString );
+ }
+
+ finished_info.Success = result;
+ Callback(FmIfsFinished,
+ sizeof(FMIFS_FINISHED_INFORMATION),
+ &finished_info);
+}
+
+VOID
+DoubleSpaceDismount(
+ IN PWSTR DblspaceDriveName,
+ IN FMIFS_CALLBACK Callback
+ )
+{
+ FSTRING Backslash;
+ DSTRING DriveName;
+ DSTRING DeviceName;
+ DSTRING RootPath;
+ HANDLE DeviceHandle;
+ DWORD FsFlags, BytesReturned;
+
+ if( !DriveName.Initialize( DblspaceDriveName ) ||
+ !Backslash.Initialize( L"\\" ) ||
+ !RootPath.Initialize( &DriveName ) ||
+ !RootPath.Strcat( &Backslash ) ||
+ !DeviceName.Initialize( L"\\\\.\\" ) ||
+ !DeviceName.Strcat( &DriveName ) ) {
+
+ Callback(FmIfsDblspaceMountFailed, 0, NULL);
+ return;
+ }
+
+ if( !GetVolumeInformation( RootPath.GetWSTR(),
+ NULL,
+ 0,
+ NULL,
+ NULL,
+ &FsFlags,
+ NULL,
+ 0 ) ||
+ !(FsFlags & FILE_VOLUME_IS_COMPRESSED) ) {
+
+ Callback(FmIfsDblspaceMountFailed, 0, NULL);
+ return;
+ }
+
+ DeviceHandle = CreateFile( DeviceName.GetWSTR(),
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_NO_BUFFERING,
+ NULL );
+
+ if( DeviceHandle == INVALID_HANDLE_VALUE ) {
+
+ Callback(FmIfsDblspaceMountFailed, 0, NULL);
+ return;
+ }
+
+ if( !DeviceIoControl( DeviceHandle,
+ FSCTL_LOCK_VOLUME,
+ NULL, 0, NULL, 0,
+ &BytesReturned, 0 ) ) {
+
+ Callback(FmIfsCantLock, 0, NULL);
+ CloseHandle( DeviceHandle );
+ return;
+ }
+
+ if( !DeviceIoControl( DeviceHandle,
+ FSCTL_DISMOUNT_VOLUME,
+ NULL, 0, NULL, 0,
+ &BytesReturned, 0 ) ) {
+
+ Callback(FmIfsDblspaceMountFailed, 0, NULL);
+ CloseHandle( DeviceHandle );
+ return;
+ }
+
+ CloseHandle( DeviceHandle );
+
+ Callback(FmIfsDblspaceMounted, 0, NULL);
+ return;
+
+}
+
+
+BOOLEAN
+DosToNtMatch(
+ IN PCWSTRING DosName,
+ IN PCWSTRING NtName
+ )
+/*++
+
+RoutineDescription:
+
+ This function determines whether a certain DOS drive name
+ (i.e. <drive-letter>:) and a certain NT drive name refer
+ to the same device.
+
+Arguments:
+
+ DosName -- Supplies the DOS drive name.
+ NtName -- Supplies the NT drive name.
+
+--*/
+{
+ DSTRING ConvertedName, Canon1, Canon2;
+
+ // Convert the DOS name to an NT name and canonicalize both names.
+ //
+ if( !IFS_SYSTEM::DosDriveNameToNtDriveName( DosName, &ConvertedName ) ||
+ !IFS_SYSTEM::QueryCanonicalNtDriveName( &ConvertedName, &Canon1 ) ||
+ !IFS_SYSTEM::QueryCanonicalNtDriveName( NtName, &Canon2 ) ) {
+
+ return FALSE;
+ }
+
+ // If they canonicalize to the same thing, they're the same;
+ // otherwise, they aren't.
+ //
+ return (Canon1.Stricmp( &Canon2 ) != 0) ? FALSE : TRUE;
+}
+
+BOOLEAN
+DriveLetterInUse(
+ IN WCHAR Letter
+ )
+/*++
+
+Routine Description:
+
+ This function determines whether the specified letter is
+ in use as a Dos drive letter.
+
+Arguments:
+
+ Letter -- Supplies the drive letter in question.
+
+Return Value:
+
+ TRUE if this drive letter is in use (i.e. if QueryDosDevice
+ succeeds).
+
+--*/
+{
+ CONST TempBufferLength = 128;
+ WCHAR TempBuffer[TempBufferLength];
+ PWCHAR DriveName = L" :";
+
+ DriveName[0] = Letter;
+
+ return( (BOOLEAN)QueryDosDevice( DriveName,
+ TempBuffer,
+ TempBufferLength ) );
+}
+
+BOOLEAN
+QueryAssociatedHostName(
+ IN WCHAR ch,
+ OUT PWSTRING HostNtName
+ )
+/*++
+
+Routine Description:
+
+ This function determines the Double-Space Host name
+ associated with the specified drive letter.
+
+Arguments:
+
+ ch -- Supplies the drive letter for a removable
+ drive (which may be a double-space volume).
+ HostNtName -- Receives the host name (devicename.host)
+ associated with the specified drive letter.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ FSTRING DosName, DotHost, DotDblspace;
+ DSTRING NtName, CanonicalName, BaseName;
+ CHNUM position;
+
+ DotHost.Initialize( L".HOST" );
+ DotDblspace.Initialize( L".DBLSPACE" );
+
+ DosName.Initialize( L" :" );
+ DosName.SetChAt( ch, 0 );
+
+ // Fetch the canonical NT name for this drive. If it
+ // ends in .HOST, return it directly; if it ends in
+ // .DBLSPACE.xxx, truncate that portion and append .HOST;
+ // otherwise, just append .HOST.
+ //
+ if( !IFS_SYSTEM::DosDriveNameToNtDriveName( &DosName, &NtName ) ||
+ !IFS_SYSTEM::QueryCanonicalNtDriveName( &NtName, &CanonicalName ) ) {
+
+ return FALSE;
+ }
+
+ position = CanonicalName.Strstr( &DotHost );
+
+ if( position != INVALID_CHNUM ) {
+
+ // This name has .HOST in it, so it's already a
+ // host name.
+ //
+ return( HostNtName->Initialize( &CanonicalName ) );
+ }
+
+ position = CanonicalName.Strstr( &DotDblspace );
+
+ if( position == INVALID_CHNUM ) {
+
+ // This name contains neither .HOST nor .DBLSPACE,
+ // so it's a base name.
+ //
+ if( !BaseName.Initialize( &CanonicalName ) ) {
+
+ return FALSE;
+ }
+
+ } else {
+
+ // This name ends in .DBLSPACE.xxx--the base name is
+ // everything before the .DBLSPACE.
+ //
+ if( !BaseName.Initialize( &CanonicalName, 0, position ) ) {
+
+ return FALSE;
+ }
+ }
+
+ return( HostNtName->Initialize( &BaseName ) &&
+ HostNtName->Strcat( &DotHost ) );
+}
+
+BOOLEAN
+FmifsEnableAutomount(
+ )
+/*++
+
+Routine Description:
+
+ This function enables automatic mounting of Double Space volumes
+ on removable media (floppies and removable disks). It twiddles
+ the registry to enable automount and makes sure that a drive
+ letter is defined to serve as a host for each removable media.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ DSTRING HostNtName;
+ FSTRING DosName;
+ PWCHAR RootName = L" :\\";
+ PWCHAR DriveName = L" :";
+ WCHAR ch, NextAvailableLetter;
+ BOOLEAN LinkFound;
+ NTSTATUS status;
+
+ NextAvailableLetter = 'C';
+ DosName.Initialize( L" :" );
+
+ // Set up the host drive letters.
+ //
+ for( ch = 'A'; ch <= 'Z'; ch++ ) {
+
+ RootName[0] = ch;
+
+ if( GetDriveType( RootName ) == DRIVE_REMOVABLE ) {
+
+ // Construct the host-device name.
+ //
+ if( !QueryAssociatedHostName( ch, &HostNtName ) ) {
+
+ // Can't generate the associated host name--
+ // don't worry about it.
+ //
+ continue;
+ }
+
+ // If no link exists for this host name, create one.
+ //
+ LinkFound = FALSE;
+
+ for( ch = 'C'; !LinkFound && ch <= 'Z'; ch++ ) {
+
+ DosName.SetChAt( ch, 0 );
+
+ if( DosToNtMatch( &DosName, &HostNtName ) ) {
+
+ LinkFound = TRUE;
+ }
+ }
+
+ if( !LinkFound ) {
+
+ // Create a link for this host name. First,
+ // choose a letter.
+ //
+ while( DriveLetterInUse( NextAvailableLetter ) &&
+ NextAvailableLetter <= 'Z' ) {
+
+ NextAvailableLetter++;
+ }
+
+ if( NextAvailableLetter > 'Z' ) {
+
+ // No more letters--stop assigning.
+ //
+ break;
+ }
+
+ DosName.SetChAt( NextAvailableLetter, 0 );
+
+ DefineDosDevice( DDD_RAW_TARGET_PATH,
+ DosName.GetWSTR(),
+ HostNtName.GetWSTR() );
+ }
+ }
+ }
+
+ // Now twiddle the registry to turn on Double-Space AUTOMOUNT.
+ //
+ status = DiskRegistryDblSpaceRemovable( 1 );
+
+ return( NT_SUCCESS(status) );
+}
+
+BOOLEAN
+FmifsDisableAutomount(
+ )
+/*++
+
+Routine Description:
+
+ This function disables automatic mounting of Double Space volumes
+ on removable media (floppies and removable disks).
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ //PWCHAR RootName = L" :\\";
+ //WCHAR ch;
+ NTSTATUS status;
+
+ // Spin through the drives looking for names ending in .HOST.
+ // If the drive is not present, or if I can lock it, remove
+ // the drive letter assignment.
+ //
+ //for( ch = 'A'; ch <= 'Z'; ch++ ) {
+ //
+ // RootName[0] = ch;
+ // if( GetDriveType( RootName ) == DRIVE_REMOVABLE ) {
+ //
+ // }
+ //}
+
+ status = DiskRegistryDblSpaceRemovable( 0 );
+ return( NT_SUCCESS(status) );
+}
+
+
+BOOLEAN
+FmifsSetAutomount(
+ IN BOOLEAN EnableAutomount
+ )
+{
+ return EnableAutomount ? FmifsEnableAutomount() : FmifsDisableAutomount();
+}
diff --git a/private/utils/fmifs/src/extend.cxx b/private/utils/fmifs/src/extend.cxx
new file mode 100644
index 000000000..1badc1afc
--- /dev/null
+++ b/private/utils/fmifs/src/extend.cxx
@@ -0,0 +1,99 @@
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+extern "C" {
+#include "fmifs.h"
+};
+#include "fmifsmsg.hxx"
+#include "ifssys.hxx"
+#include "wstring.hxx"
+#include "ifsentry.hxx"
+#include "system.hxx"
+#include "drive.hxx"
+
+
+VOID
+Extend(
+ IN PWSTR DriveName,
+ IN BOOLEAN Verify,
+ IN FMIFS_CALLBACK Callback
+ )
+
+/*++
+
+Routine Description:
+
+ This routine loads and calls the correct DLL to extend the
+ given volume. Currently only NTFS can do this.
+
+ This is is for either GUI or text mode.
+
+Arguments:
+
+ DriveName - Supplies the DOS style drive name.
+ Verify - Whether or not to verify the extended space
+ Callback - Supplies the necessary call back for
+ communication with the client
+
+Return Value:
+
+ None.
+
+--*/
+{
+ FMIFS_MESSAGE message;
+ DSTRING extend_string;
+ DSTRING library_name;
+ DSTRING file_system_name;
+ EXTEND_FN extend_function;
+ HANDLE dll_handle;
+ DSTRING ntdrivename;
+ BOOLEAN result;
+ DSTRING dosdrivename;
+ FMIFS_FINISHED_INFORMATION finished_info;
+ DWORD OldErrorMode;
+
+ // Initialize the message object with the callback function.
+ // Load the file system DLL.
+ // Compute the NT style drive name.
+
+ if (!message.Initialize(Callback) ||
+ !extend_string.Initialize("Extend") ||
+ !library_name.Initialize("U") ||
+ !file_system_name.Initialize("NTFS") ||
+ !library_name.Strcat(&file_system_name) ||
+ !(extend_function = (EXTEND_FN)
+ SYSTEM::QueryLibraryEntryPoint(&library_name,
+ &extend_string,
+ &dll_handle)) ||
+ !dosdrivename.Initialize(DriveName) ||
+ !IFS_SYSTEM::DosDriveNameToNtDriveName(&dosdrivename, &ntdrivename))
+ {
+ finished_info.Success = FALSE;
+ Callback(FmIfsFinished,
+ sizeof(FMIFS_FINISHED_INFORMATION),
+ &finished_info);
+ return;
+ }
+
+ // Disable hard-error popups.
+ OldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS );
+
+ // Call chkdsk.
+
+ result = extend_function(&ntdrivename,
+ &message,
+ Verify
+ );
+
+ // Enable hard-error popups.
+ SetErrorMode( OldErrorMode );
+
+ SYSTEM::FreeLibraryHandle(dll_handle);
+
+ finished_info.Success = (0 == result) ? TRUE : FALSE;
+ Callback(FmIfsFinished,
+ sizeof(FMIFS_FINISHED_INFORMATION),
+ &finished_info);
+}
+
diff --git a/private/utils/fmifs/src/fmifs.cxx b/private/utils/fmifs/src/fmifs.cxx
new file mode 100644
index 000000000..7e8846435
--- /dev/null
+++ b/private/utils/fmifs/src/fmifs.cxx
@@ -0,0 +1,114 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ fmifs.cxx
+
+Abstract:
+
+ This module contains run-time, global support for the
+ FM IFS Utilities library (FMIFS). This support includes:
+
+ - creation of CLASS_DESCRIPTORs
+ - Global objects
+
+Author:
+
+ Norbert P. Kusters (norbertk) 30-May-1991
+
+Environment:
+
+ User Mode
+
+Notes:
+
+--*/
+
+#include "ulib.hxx"
+
+
+// Local prototypes
+
+STATIC
+BOOLEAN
+DefineClassDescriptors(
+ );
+
+extern "C" BOOLEAN
+InitializeFmIfs (
+ IN PVOID DllHandle,
+ IN ULONG Reason,
+ IN PCONTEXT Context
+ );
+
+BOOLEAN
+InitializeFmIfs (
+ IN PVOID DllHandle,
+ IN ULONG Reason,
+ IN PCONTEXT Context
+ )
+/*++
+
+Routine Description:
+
+ Initialize FmIfs by constructing and initializing all
+ global objects. These include:
+
+ - all CLASS_DESCRIPTORs (class_cd)
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if all global objects were succesfully constructed
+ and initialized.
+
+--*/
+
+{
+
+ STATIC BOOLEAN fInit = FALSE;
+
+ if ( fInit ) {
+
+ return( TRUE );
+ }
+
+ if ( DefineClassDescriptors() ) {
+
+ fInit = TRUE;
+ return TRUE;
+
+ } else {
+
+ DebugAbort( "FmIfs initialization failed!!!\n" );
+ return( FALSE );
+ }
+}
+
+
+
+DECLARE_CLASS( FMIFS_MESSAGE );
+DECLARE_CLASS( FMIFS_CHKMSG );
+
+STATIC
+BOOLEAN
+DefineClassDescriptors(
+ )
+{
+ if( DEFINE_CLASS_DESCRIPTOR( FMIFS_MESSAGE )
+ && DEFINE_CLASS_DESCRIPTOR( FMIFS_CHKMSG )
+ ) {
+
+ return TRUE;
+
+ } else {
+
+ DebugPrint( "Could not initialize class descriptors!");
+ return FALSE;
+ }
+}
diff --git a/private/utils/fmifs/src/fmifs.def b/private/utils/fmifs/src/fmifs.def
new file mode 100644
index 000000000..e8b41b8e4
--- /dev/null
+++ b/private/utils/fmifs/src/fmifs.def
@@ -0,0 +1,16 @@
+LIBRARY FMIFS
+
+DESCRIPTION File System Utilities for the file manager
+
+DATA NONSHARED
+
+EXPORTS
+ Format
+ Chkdsk
+ SetLabel
+ QuerySupportedMedia
+ InitializeFmIfs
+ DiskCopy
+ FormatEx
+ EnableVolumeCompression
+ Extend
diff --git a/private/utils/fmifs/src/fmifs.rc b/private/utils/fmifs/src/fmifs.rc
new file mode 100644
index 000000000..08dac43b1
--- /dev/null
+++ b/private/utils/fmifs/src/fmifs.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "FM IFS Utility DLL"
+#define VER_INTERNALNAME_STR "fmifs\0"
+#define VER_ORIGINALFILENAME_STR "FMIFS.DLL"
+
+#include "common.ver"
diff --git a/private/utils/fmifs/src/fmifsmsg.cxx b/private/utils/fmifs/src/fmifsmsg.cxx
new file mode 100644
index 000000000..74d8eb515
--- /dev/null
+++ b/private/utils/fmifs/src/fmifsmsg.cxx
@@ -0,0 +1,337 @@
+#include "ulib.hxx"
+#include "fmifsmsg.hxx"
+#include "rtmsg.h"
+
+
+DEFINE_CONSTRUCTOR(FMIFS_MESSAGE, MESSAGE);
+
+
+FMIFS_MESSAGE::~FMIFS_MESSAGE(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for FMIFS_MESSAGE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+FMIFS_MESSAGE::Construct(
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the object to a default initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _msgid = 0;
+ _callback = NULL;
+ _kilobytes_total_disk_space = 0;
+}
+
+
+VOID
+FMIFS_MESSAGE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the object to a default initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _msgid = 0;
+ _callback = NULL;
+ _kilobytes_total_disk_space = 0;
+}
+
+
+BOOLEAN
+FMIFS_MESSAGE::Initialize(
+ IN FMIFS_CALLBACK CallBack
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the class to a valid initial state.
+
+Arguments:
+
+ CallBack - Supplies the callback to the file manager.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ Destroy();
+ _callback = CallBack;
+ return _callback ? TRUE : FALSE;
+}
+
+
+BOOLEAN
+FMIFS_MESSAGE::DisplayV(
+ IN PCSTR Format,
+ IN va_list VarPointer
+ )
+/*++
+
+Routine Description:
+
+ This routine displays the message with the specified parameters.
+
+ The format string supports all printf options.
+
+Arguments:
+
+ Format - Supplies a printf style format string.
+ VarPointer - Supplies a varargs pointer to the arguments.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ FMIFS_PERCENT_COMPLETE_INFORMATION percent_info;
+ FMIFS_FORMAT_REPORT_INFORMATION fmt_report;
+ FMIFS_INSERT_DISK_INFORMATION insert_info;
+ FMIFS_IO_ERROR_INFORMATION io_error_info;
+ BOOLEAN r = TRUE;
+ PWSTRING drive_name, file_name;
+
+
+ switch (_msgid) {
+
+ case MSG_PERCENT_COMPLETE:
+ percent_info.PercentCompleted = va_arg(VarPointer, ULONG);
+ r = _callback(FmIfsPercentCompleted,
+ sizeof(FMIFS_PERCENT_COMPLETE_INFORMATION),
+ &percent_info);
+ break;
+
+ case MSG_DCOPY_INSERT_TARGET:
+ insert_info.DiskType = DISK_TYPE_TARGET;
+ r = _callback(FmIfsInsertDisk,
+ sizeof(FMIFS_INSERT_DISK_INFORMATION),
+ &insert_info);
+ break;
+
+ case MSG_DCOPY_INSERT_SOURCE:
+ insert_info.DiskType = DISK_TYPE_SOURCE;
+ r = _callback(FmIfsInsertDisk,
+ sizeof(FMIFS_INSERT_DISK_INFORMATION),
+ &insert_info);
+ break;
+
+ case MSG_DCOPY_INSERT_SOURCE_AND_TARGET:
+ insert_info.DiskType = DISK_TYPE_SOURCE_AND_TARGET;
+ r = _callback(FmIfsInsertDisk,
+ sizeof(FMIFS_INSERT_DISK_INFORMATION),
+ &insert_info);
+ break;
+
+ case MSG_DCOPY_FORMATTING_WHILE_COPYING:
+ r = _callback(FmIfsFormattingDestination, 0, NULL);
+ break;
+
+ case MSG_DCOPY_BAD_DEST:
+ r = _callback(FmIfsIncompatibleMedia, 0, NULL);
+ break;
+
+#if 1
+ case MSG_DCOPY_NON_COMPAT_DISKS:
+ r = _callback(FmIfsIncompatibleMedia, 0, NULL);
+ break;
+#else
+ // MSG_DCOPY_BAD_DEST may need to call a different FmIfs....
+ case MSG_DCOPY_NON_COMPAT_DISKS:
+ // pop a dialog and ask for retry or cancel
+ // TRUE signals CANCEL selected instead of RETRY
+ break;
+#endif
+
+
+ case MSG_TOTAL_DISK_SPACE:
+ _kilobytes_total_disk_space = va_arg(VarPointer, ULONG)/1024;
+ break;
+
+ case MSG_AVAILABLE_DISK_SPACE:
+ fmt_report.KiloBytesTotalDiskSpace = _kilobytes_total_disk_space;
+ fmt_report.KiloBytesAvailable = va_arg(VarPointer, ULONG)/1024;
+ r = _callback(FmIfsFormatReport,
+ sizeof(FMIFS_FORMAT_REPORT_INFORMATION),
+ &fmt_report);
+ break;
+
+ case MSG_TOTAL_KILOBYTES:
+ case MSG_CHK_NTFS_TOTAL_DISK_SPACE:
+ _kilobytes_total_disk_space = va_arg(VarPointer, ULONG);
+ break;
+
+ case MSG_AVAILABLE_KILOBYTES:
+ case MSG_CHK_NTFS_AVAILABLE_SPACE:
+ fmt_report.KiloBytesTotalDiskSpace = _kilobytes_total_disk_space;
+ fmt_report.KiloBytesAvailable = va_arg(VarPointer, ULONG);
+ r = _callback(FmIfsFormatReport,
+ sizeof(FMIFS_FORMAT_REPORT_INFORMATION),
+ &fmt_report);
+ break;
+
+ case MSG_DCOPY_WRITE_ERROR:
+ case MSG_DCOPY_READ_ERROR:
+ io_error_info.DiskType = (_msgid == MSG_DCOPY_READ_ERROR) ?
+ DISK_TYPE_SOURCE : DISK_TYPE_TARGET;
+ va_arg(VarPointer, PVOID);
+ io_error_info.Head = va_arg(VarPointer, ULONG);
+ io_error_info.Track = va_arg(VarPointer, ULONG);
+ r = _callback(FmIfsIoError,
+ sizeof(FMIFS_IO_ERROR_INFORMATION),
+ &io_error_info);
+ break;
+
+ case MSG_CANT_LOCK_THE_DRIVE:
+ r = _callback(FmIfsCantLock, 0, NULL);
+ break;
+
+ case MSG_CANT_UNLOCK_THE_DRIVE:
+ // similiar to FmIfsCantLock
+ break;
+
+ case MSG_DCOPY_NO_MEDIA_IN_DEVICE:
+ // pop a dialog and ask for retry or cancel
+ // TRUE signals CANCEL selected instead of RETRY
+ break;
+
+ case MSG_DCOPY_UNRECOGNIZED_MEDIA:
+ // pop a dialog and ask for retry or cancel
+ // TRUE signals CANCEL selected instead of RETRY
+ break;
+
+ case MSG_DASD_ACCESS_DENIED:
+ r = _callback(FmIfsAccessDenied, 0, NULL);
+ break;
+
+ case MSG_CANT_QUICKFMT:
+ r = _callback(FmIfsCantQuickFormat, 0, NULL);
+ break;
+
+ case MSG_FMT_WRITE_PROTECTED_MEDIA:
+ r = _callback(FmIfsMediaWriteProtected, 0, NULL);
+ break;
+
+ case MSG_INVALID_LABEL_CHARACTERS:
+ r = _callback(FmIfsBadLabel, 0, NULL);
+ break;
+
+ case MSG_HIDDEN_STATUS:
+ r = _callback(FmIfsHiddenStatus, 0, NULL);
+ break;
+
+#if defined ( DBLSPACE_ENABLED )
+ case MSG_DBLSPACE_VOLUME_NOT_CREATED:
+ r = _callback(FmIfsDblspaceCreateFailed, 0, NULL);
+ break;
+
+ case MSG_DBLSPACE_CANT_MOUNT:
+ r = _callback(FmIfsDblspaceMountFailed, 0, NULL);
+ break;
+
+ case MSG_DBLSPACE_CANT_ASSIGN_DRIVE_LETTER:
+ r = _callback(FmIfsDblspaceDriveLetterFailed, 0, NULL);
+ break;
+
+ case MSG_DBLSPACE_VOLUME_CREATED:
+ // Both arguments to this message are PWSTRING's;
+ // the first is the drive, the second is the
+ // Compressed Volume File name.
+ //
+ drive_name = va_arg( VarPointer, PWSTRING );
+ file_name = va_arg( VarPointer, PWSTRING );
+ r = _callback(FmIfsDblspaceCreated,
+ file_name->QueryChCount() * sizeof(WCHAR),
+ (PVOID)file_name->GetWSTR() );
+ break;
+
+ case MSG_DBLSPACE_MOUNTED:
+ r = _callback(FmIfsDblspaceMounted, 0, NULL);
+ break;
+#endif // DBLSPACE_ENABLED
+
+ default:
+ break;
+ }
+
+ return r;
+}
+
+
+PMESSAGE
+FMIFS_MESSAGE::Dup(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a new MESSAGE of the same type.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to a new MESSAGE object.
+
+--*/
+{
+ PFMIFS_MESSAGE p;
+
+ if (!(p = NEW FMIFS_MESSAGE)) {
+ return NULL;
+ }
+
+ if (!p->Initialize(_callback)) {
+ DELETE(p);
+ return NULL;
+ }
+
+ return p;
+}
diff --git a/private/utils/fmifs/src/format.cxx b/private/utils/fmifs/src/format.cxx
new file mode 100644
index 000000000..ee28d457b
--- /dev/null
+++ b/private/utils/fmifs/src/format.cxx
@@ -0,0 +1,497 @@
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+extern "C" {
+#include "fmifs.h"
+};
+#include "fmifsmsg.hxx"
+#include "ifssys.hxx"
+#include "wstring.hxx"
+#include "ifsentry.hxx"
+#include "system.hxx"
+#include "drive.hxx"
+
+
+MEDIA_TYPE
+ComputeNtMediaType(
+ IN FMIFS_MEDIA_TYPE MediaType
+ )
+/*++
+
+Routine Description:
+
+ This routine translates the FMIFS media type to the NT media type.
+
+Arguments:
+
+ MediaType - Supplies the FMIFS media type.
+
+Return Value:
+
+ The NT media type corresponding to the input.
+
+--*/
+{
+ MEDIA_TYPE media_type;
+
+ switch (MediaType) {
+ case FmMediaFixed:
+ media_type = FixedMedia;
+ break;
+ case FmMediaRemovable:
+ media_type = RemovableMedia;
+ break;
+ case FmMediaF5_1Pt2_512:
+ media_type = F5_1Pt2_512;
+ break;
+ case FmMediaF5_360_512:
+ media_type = F5_360_512;
+ break;
+ case FmMediaF5_320_512:
+ media_type = F5_320_512;
+ break;
+ case FmMediaF5_320_1024:
+ media_type = F5_320_1024;
+ break;
+ case FmMediaF5_180_512:
+ media_type = F5_180_512;
+ break;
+ case FmMediaF5_160_512:
+ media_type = F5_160_512;
+ break;
+ case FmMediaF3_2Pt88_512:
+ media_type = F3_2Pt88_512;
+ break;
+ case FmMediaF3_1Pt44_512:
+ media_type = F3_1Pt44_512;
+ break;
+ case FmMediaF3_720_512:
+ media_type = F3_720_512;
+ break;
+ case FmMediaF3_20Pt8_512:
+ media_type = F3_20Pt8_512;
+ break;
+ case FmMediaF3_120M_512:
+ media_type = F3_120M_512;
+ break;
+ case FmMediaUnknown:
+ default:
+ media_type = Unknown;
+ break;
+ }
+
+ return media_type;
+}
+
+
+FMIFS_MEDIA_TYPE
+ComputeFmMediaType(
+ IN MEDIA_TYPE MediaType
+ )
+/*++
+
+Routine Description:
+
+ This routine translates the NT media type to the FMIFS media type.
+
+Arguments:
+
+ MediaType - Supplies the NT media type.
+
+Return Value:
+
+ The FMIFS media type corresponding to the input.
+
+--*/
+{
+ FMIFS_MEDIA_TYPE media_type;
+
+ switch (MediaType) {
+ case FixedMedia:
+ media_type = FmMediaFixed;
+ break;
+ case RemovableMedia:
+ media_type = FmMediaRemovable;
+ break;
+ case F5_1Pt2_512:
+ media_type = FmMediaF5_1Pt2_512;
+ break;
+ case F5_360_512:
+ media_type = FmMediaF5_360_512;
+ break;
+ case F5_320_512:
+ media_type = FmMediaF5_320_512;
+ break;
+ case F5_320_1024:
+ media_type = FmMediaF5_320_1024;
+ break;
+ case F5_180_512:
+ media_type = FmMediaF5_180_512;
+ break;
+ case F5_160_512:
+ media_type = FmMediaF5_160_512;
+ break;
+ case F3_2Pt88_512:
+ media_type = FmMediaF3_2Pt88_512;
+ break;
+ case F3_1Pt44_512:
+ media_type = FmMediaF3_1Pt44_512;
+ break;
+ case F3_720_512:
+ media_type = FmMediaF3_720_512;
+ break;
+ case F3_20Pt8_512:
+ media_type = FmMediaF3_20Pt8_512;
+ break;
+ case F3_120M_512:
+ media_type = FmMediaF3_120M_512;
+ break;
+ case Unknown:
+ default:
+ media_type = FmMediaUnknown;
+ break;
+ }
+
+ return media_type;
+}
+
+
+VOID
+Format(
+ IN PWSTR DriveName,
+ IN FMIFS_MEDIA_TYPE MediaType,
+ IN PWSTR FileSystemName,
+ IN PWSTR Label,
+ IN BOOLEAN Quick,
+ IN FMIFS_CALLBACK Callback
+ )
+/*++
+
+Routine Description:
+
+ This routine loads and calls the correct DLL to format the
+ given volume.
+
+Arguments:
+
+ DriveName - Supplies the DOS style drive name.
+ MediaType - Supplies the media type.
+ FileSystemName - Supplies the file system type to format to.
+ Label - Supplies a new label for the volume.
+ Quick - Supplies whether or not to perform a quick
+ format.
+ Callback - Supplies the necessary call back for
+ communication with the file manager.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ FMIFS_MESSAGE message;
+ DSTRING format_string;
+ DSTRING library_name;
+ DSTRING file_system_name;
+ FORMAT_FN format_function;
+ HANDLE dll_handle;
+ DSTRING ntdrivename;
+ BOOLEAN result;
+ DSTRING label_string;
+ DSTRING dosdrivename;
+ FMIFS_FINISHED_INFORMATION finished_info;
+ DWORD OldErrorMode;
+
+ // Initialize the message object with the callback function.
+ // Load the file system DLL.
+ // Compute the NT style drive name.
+
+ if (!message.Initialize(Callback) ||
+ !format_string.Initialize("Format") ||
+ !library_name.Initialize("U") ||
+ !file_system_name.Initialize(FileSystemName) ||
+ !library_name.Strcat(&file_system_name) ||
+ !(format_function = (FORMAT_FN)
+ SYSTEM::QueryLibraryEntryPoint(&library_name,
+ &format_string,
+ &dll_handle)) ||
+ !dosdrivename.Initialize(DriveName) ||
+ !label_string.Initialize(Label) ||
+ !IFS_SYSTEM::DosDriveNameToNtDriveName(&dosdrivename, &ntdrivename)) {
+
+ finished_info.Success = FALSE;
+ Callback(FmIfsFinished,
+ sizeof(FMIFS_FINISHED_INFORMATION),
+ &finished_info);
+ return;
+ }
+
+ // Disable hard-error popups.
+ OldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS );
+
+ // Call format.
+
+ result = format_function(&ntdrivename,
+ &message,
+ Quick,
+ ComputeNtMediaType(MediaType),
+ &label_string, 0);
+
+ // Enable hard-error popups.
+ SetErrorMode( OldErrorMode );
+
+ SYSTEM::FreeLibraryHandle(dll_handle);
+
+ finished_info.Success = result;
+ Callback(FmIfsFinished,
+ sizeof(FMIFS_FINISHED_INFORMATION),
+ &finished_info);
+}
+
+
+VOID
+FormatEx(
+ IN PWSTR DriveName,
+ IN FMIFS_MEDIA_TYPE MediaType,
+ IN PWSTR FileSystemName,
+ IN PWSTR Label,
+ IN BOOLEAN Quick,
+ IN DWORD ClusterSize,
+ IN FMIFS_CALLBACK Callback
+ )
+/*++
+
+Routine Description:
+
+ This routine loads and calls the correct DLL to format the
+ given volume.
+
+Arguments:
+
+ DriveName - Supplies the DOS style drive name.
+ MediaType - Supplies the media type.
+ FileSystemName - Supplies the file system type to format to.
+ Label - Supplies a new label for the volume.
+ Quick - Supplies whether or not to perform a quick
+ format.
+ ClusterSize - Size of volume cluster in bytes.
+ Callback - Supplies the necessary call back for
+ communication with the file manager.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ FMIFS_MESSAGE message;
+ DSTRING format_string;
+ DSTRING library_name;
+ DSTRING file_system_name;
+ FORMAT_FN format_function;
+ HANDLE dll_handle;
+ DSTRING ntdrivename;
+ BOOLEAN result;
+ DSTRING label_string;
+ DSTRING dosdrivename;
+ FMIFS_FINISHED_INFORMATION finished_info;
+ DWORD OldErrorMode;
+
+ // Initialize the message object with the callback function.
+ // Load the file system DLL.
+ // Compute the NT style drive name.
+
+ if (!message.Initialize(Callback) ||
+ !format_string.Initialize("Format") ||
+ !library_name.Initialize("U") ||
+ !file_system_name.Initialize(FileSystemName) ||
+ !library_name.Strcat(&file_system_name) ||
+ !(format_function = (FORMAT_FN)
+ SYSTEM::QueryLibraryEntryPoint(&library_name,
+ &format_string,
+ &dll_handle)) ||
+ !dosdrivename.Initialize(DriveName) ||
+ !label_string.Initialize(Label) ||
+ !IFS_SYSTEM::DosDriveNameToNtDriveName(&dosdrivename, &ntdrivename)) {
+
+ finished_info.Success = FALSE;
+ Callback(FmIfsFinished,
+ sizeof(FMIFS_FINISHED_INFORMATION),
+ &finished_info);
+ return;
+ }
+
+ // Disable hard-error popups.
+ OldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS );
+
+ // Call format.
+
+ result = format_function(&ntdrivename,
+ &message,
+ Quick,
+ ComputeNtMediaType(MediaType),
+ &label_string, ClusterSize);
+
+ // Enable hard-error popups.
+ SetErrorMode( OldErrorMode );
+
+ SYSTEM::FreeLibraryHandle(dll_handle);
+
+ finished_info.Success = result;
+ Callback(FmIfsFinished,
+ sizeof(FMIFS_FINISHED_INFORMATION),
+ &finished_info);
+}
+
+
+BOOLEAN
+EnableVolumeCompression(
+ IN PWSTR DriveName,
+ IN USHORT CompressionFormat
+ )
+/*++
+
+Routine Description:
+
+ This sets the compression attribute on the root directory of an NTFS volume.
+ Note that the compression state of any files already contained on the
+ volume is not affected.
+
+Arguments:
+
+ DriveName - Supplies the drive name.
+ Expects a string like "C:\".
+
+ CompressionFormat - COMPRESSION_FORMAT_NONE = Uncompressed.
+ COMPRESSION_FORMAT_DEFAULT = Default compression.
+ COMPRESSION_FORMAT_LZNT1 = Use LZNT1 compression format.
+ (as defined in NTRTL.H)
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ HANDLE hFile;
+ BOOLEAN bStatus = FALSE;
+
+ //
+ // Don't even try if no drive name provided.
+ //
+ if (DriveName[0])
+ {
+ //
+ // Try to open the root directory - READ_DATA | WRITE_DATA.
+ //
+ if ((hFile = CreateFile(DriveName,
+ FILE_READ_DATA | FILE_WRITE_DATA,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS,
+ NULL )) != INVALID_HANDLE_VALUE)
+ {
+ ULONG Length = 0;
+
+ if (DeviceIoControl( hFile,
+ FSCTL_SET_COMPRESSION,
+ &CompressionFormat,
+ sizeof(CompressionFormat),
+ NULL,
+ 0,
+ &Length,
+ NULL))
+ {
+ //
+ // Successfully set compression on root directory.
+ //
+ bStatus = TRUE;
+ }
+ CloseHandle(hFile);
+ }
+ }
+ return bStatus;
+}
+
+BOOLEAN
+QuerySupportedMedia(
+ IN PWSTR DriveName,
+ OUT PFMIFS_MEDIA_TYPE MediaTypeArray,
+ IN ULONG NumberOfArrayEntries,
+ OUT PULONG NumberOfMediaTypes
+ )
+/*++
+
+Routine Description:
+
+ This routine computes a list of the supported media types for
+ the given drive.
+
+ If NULL is passed for the array then 'NumberOfMediaTypes'
+ is filled in with the correct number.
+
+Arguments:
+
+ DriveName - Supplies the drive name.
+ MediaTypeArray - Returns the supported media types.
+ NumberOfArrayEntries - Supplies the number of entries in
+ 'MediaTypeArray'.
+ NumberOfMediaTypes - Returns the number of media types
+ returned in the media type array.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ DSTRING dosdrivename, ntdrivename;
+ DP_DRIVE dpdrive;
+ PCDRTYPE nt_media_types;
+ INT num_types;
+ ULONG i, j;
+ FMIFS_MEDIA_TYPE tmp;
+
+ if (!dosdrivename.Initialize(DriveName) ||
+ !IFS_SYSTEM::DosDriveNameToNtDriveName(&dosdrivename, &ntdrivename)) {
+
+ return FALSE;
+ }
+
+ if (!dpdrive.Initialize(&ntdrivename)) {
+ SetLastError(RtlNtStatusToDosError(dpdrive.QueryLastNtStatus()));
+ return FALSE;
+ }
+
+ if (!(nt_media_types = dpdrive.GetSupportedList(&num_types))) {
+ return FALSE;
+ }
+
+ if (!MediaTypeArray) {
+ *NumberOfMediaTypes = num_types;
+ return TRUE;
+ }
+
+ *NumberOfMediaTypes = min(NumberOfArrayEntries, (ULONG)num_types);
+
+ for (i = 0; i < *NumberOfMediaTypes; i++) {
+ MediaTypeArray[i] = ComputeFmMediaType(nt_media_types[i].MediaType);
+ }
+
+ for (i = 0; i < *NumberOfMediaTypes; i++) {
+ for (j = 0; j < *NumberOfMediaTypes - 1; j++) {
+ if (MediaTypeArray[j] < MediaTypeArray[j + 1]) {
+ tmp = MediaTypeArray[j];
+ MediaTypeArray[j] = MediaTypeArray[j + 1];
+ MediaTypeArray[j + 1] = tmp;
+ }
+ }
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/fmifs/src/label.cxx b/private/utils/fmifs/src/label.cxx
new file mode 100644
index 000000000..4b6c542aa
--- /dev/null
+++ b/private/utils/fmifs/src/label.cxx
@@ -0,0 +1,120 @@
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+extern "C" {
+#include "fmifs.h"
+};
+#include "ifssys.hxx"
+#include "wstring.hxx"
+
+BOOLEAN
+SetLabel(
+ IN PWSTR DriveName,
+ IN PWSTR Label
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the label on the given drive.
+
+Arguments:
+
+ DriveName - Supplies the drive name on which to place the
+ label.
+ Label - Supplies the label.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ CONST length = sizeof(FILE_FS_LABEL_INFORMATION) + MAX_PATH*sizeof(WCHAR);
+
+ DSTRING dosdrivename, ntdrivename;
+ UNICODE_STRING string;
+ OBJECT_ATTRIBUTES oa;
+ IO_STATUS_BLOCK status_block;
+ HANDLE handle;
+ DSTRING label;
+ PFILE_FS_LABEL_INFORMATION info;
+ STR info_buf[length];
+ NTSTATUS nts;
+ BOOLEAN result;
+ DWORD error;
+
+ if (!dosdrivename.Initialize(DriveName) ||
+ !IFS_SYSTEM::DosDriveNameToNtDriveName(&dosdrivename, &ntdrivename)) {
+
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+
+ if (!(string.Buffer = ntdrivename.QueryWSTR())) {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+
+ string.Length = (USHORT) (ntdrivename.QueryChCount()*sizeof(WCHAR));
+ string.MaximumLength = string.Length;
+
+ InitializeObjectAttributes( &oa, &string, OBJ_CASE_INSENSITIVE, 0, 0 );
+
+ nts = NtOpenFile(&handle,
+ SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
+ &oa, &status_block,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT | FILE_WRITE_THROUGH);
+
+ if (!NT_SUCCESS(nts)) {
+
+ DELETE(string.Buffer);
+ SetLastError(RtlNtStatusToDosError(nts));
+ return FALSE;
+ }
+
+ DELETE(string.Buffer);
+
+ if (!label.Initialize(Label)) {
+
+ NtClose(handle);
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+
+ info = (PFILE_FS_LABEL_INFORMATION) info_buf;
+
+
+ label.QueryWSTR(0, TO_END, info->VolumeLabel, length - sizeof(ULONG));
+
+ info->VolumeLabelLength = label.QueryChCount()*sizeof(WCHAR);
+
+ nts = NtSetVolumeInformationFile(
+ handle, &status_block, info, length, FileFsLabelInformation);
+
+ if (!NT_SUCCESS(nts)) {
+
+ result = FALSE;
+ error = RtlNtStatusToDosError(nts);
+
+ // Remap ERROR_LABEL_TOO_LONG, since its message text is
+ // misleading.
+ //
+ if( error == ERROR_LABEL_TOO_LONG ) {
+
+ error = ERROR_INVALID_NAME;
+ }
+
+ SetLastError(error);
+
+ } else {
+
+ result = TRUE;
+ }
+
+ NtClose(handle);
+
+ return result;
+}
diff --git a/private/utils/fmifs/src/makefile b/private/utils/fmifs/src/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/fmifs/src/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/fmifs/src/makefile.inc b/private/utils/fmifs/src/makefile.inc
new file mode 100644
index 000000000..6c93eb38d
--- /dev/null
+++ b/private/utils/fmifs/src/makefile.inc
@@ -0,0 +1,12 @@
+{}.cxx{obj\i386\}.obj:
+ $(386_COMPILER) -Fo$@ $(MAKEDIR)\$(<F)
+
+{}.cxx{obj\mips\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClMips $< " $(C_COMPILER) "
+ @$(C_COMPILER) -Fo$@ $(MAKEDIR)\$<
+
+{}.cxx{obj\alpha\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClAlpha $< " $(ALPHA_COMPILER) "
+ @$(ALPHA_COMPILER) -Fo$@ $(MAKEDIR)\$<
diff --git a/private/utils/fmifs/src/sources b/private/utils/fmifs/src/sources
new file mode 100644
index 000000000..9eebbd58b
--- /dev/null
+++ b/private/utils/fmifs/src/sources
@@ -0,0 +1,76 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+BLDCRT=1
+
+MAJORCOMP=utils
+MINORCOMP=fmifs
+
+TARGETNAME=fmifs
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+
+TARGETLIBS=\nt\public\sdk\lib\*\kernel32.lib \
+ ..\..\ulib\src\obj\*\ulib.lib \
+ ..\..\ifsutil\src\obj\*\ifsutil.lib \
+ ..\..\ufat\src\obj\*\ufat.lib
+
+USE_CRTDLL=1
+
+DLLENTRY=InitializeFmIfs
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=fmifsmsg.cxx \
+ format.cxx \
+ label.cxx \
+ diskcopy.cxx \
+ fmifs.rc \
+ fmifs.cxx \
+ chkdsk.cxx \
+ chkmsg.cxx \
+ extend.cxx
+
+
+INCLUDES=..\inc;..\..\ulib\inc;..\..\ifsutil\inc;..\..\ufat\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+CXXFLAGS=+d
+UMLIBS=obj\*\fmifs.lib
+UMTYPE=windows
+UMRES=obj\*\fmifs.res
+DLLDEF=fmifs.def
diff --git a/private/utils/format/format.cxx b/private/utils/format/format.cxx
new file mode 100644
index 000000000..b6a4666e5
--- /dev/null
+++ b/private/utils/format/format.cxx
@@ -0,0 +1,1027 @@
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+#if defined(JAPAN) && defined(_X86_)
+#include "machine.hxx"
+#endif // defined(JAPAN) && defiend(_X86_)
+#include "error.hxx"
+#include "drive.hxx"
+#include "arg.hxx"
+#include "array.hxx"
+#include "smsg.hxx"
+#include "rtmsg.h"
+#include "system.hxx"
+#include "ifssys.hxx"
+#include "ulibcl.hxx"
+#include "ifsentry.hxx"
+#include "path.hxx"
+#include "parse.hxx"
+
+extern "C" {
+ #include "nturtl.h"
+}
+
+ERRSTACK* perrstk;
+
+VOID
+DisplayFormatUsage(
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine outputs usage information on format.
+
+Arguments:
+
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Message->Set(MSG_FORMAT_INFO);
+ Message->Display("");
+ Message->Set(MSG_FORMAT_COMMAND_LINE_1);
+ Message->Display("");
+ Message->Set(MSG_FORMAT_COMMAND_LINE_2);
+ Message->Display("");
+#if !defined(_PC98_)
+ Message->Set(MSG_FORMAT_COMMAND_LINE_3);
+ Message->Display("");
+#endif // !_PC98_
+ Message->Set(MSG_FORMAT_COMMAND_LINE_4);
+ Message->Display("");
+ Message->Set(MSG_FORMAT_SLASH_V);
+ Message->Display("");
+ Message->Set(MSG_FORMAT_SLASH_Q);
+ Message->Display("");
+ Message->Set(MSG_FORMAT_SLASH_C);
+ Message->Display("");
+ Message->Set(MSG_FORMAT_SLASH_F);
+ Message->Display("");
+ Message->Set(MSG_FORMAT_SUPPORTED_SIZES);
+ Message->Display("");
+ Message->Set(MSG_FORMAT_SLASH_T);
+ Message->Display("");
+ Message->Set(MSG_FORMAT_SLASH_N);
+ Message->Display("");
+#if !defined(_PC98_)
+ Message->Set(MSG_FORMAT_SLASH_1);
+ Message->Display("");
+ Message->Set(MSG_FORMAT_SLASH_4);
+ Message->Display("");
+ Message->Set(MSG_FORMAT_SLASH_8);
+ Message->Display("");
+#endif // !_PC98_
+}
+
+
+BOOLEAN
+DetermineMediaType(
+ OUT PMEDIA_TYPE MediaType,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Request160,
+ IN BOOLEAN Request180,
+ IN BOOLEAN Request320,
+ IN BOOLEAN Request360,
+ IN BOOLEAN Request720,
+ IN BOOLEAN Request1200,
+ IN BOOLEAN Request1440,
+ IN BOOLEAN Request2880,
+ IN BOOLEAN Request20800
+#if defined(JAPAN) && defined(_X86_)
+// FMR Jul.12.1994 SFT KMR
+// Add Request640 on to the parmeter of DetermineMediaType()
+ ,
+#if defined(_PC98_)
+//'94.09.05 Hirata
+ IN BOOLEAN Request256,
+#endif // _PC98_
+
+ IN BOOLEAN Request640,
+
+// Add Request1232 on to the parmeter of DetermineMediaType()
+ IN BOOLEAN Request1232
+#endif // JAPAN && _X86_
+ )
+/*++
+
+Routine Description:
+
+ This routine determines the media type to format to.
+
+Arguments:
+
+ MediaType - Supplies the current media type and returns
+ a new media type.
+ Message - Supplies an outlet for messages.
+ Request160 - Supplies whether or not the user wished to format 160.
+ Request180 - Supplies whether or not the user wished to format 180.
+ Request320 - Supplies whether or not the user wished to format 320.
+ Request360 - Supplies whether or not the user wished to format 360.
+ Request720 - Supplies whether or not the user wished to format 720.
+ Request1200 - Supplies whether or not the user wished to format 1200.
+ Request1440 - Supplies whether or not the user wished to format 1440.
+ Request2880 - Supplies whether or not the user wished to format 2880.
+ Request20800 - Supplies whether or not the use wished to format 20800.
+#if defined(JAPAN) && defined(_X86_)
+#if defined(_PC98_)
+ Request256 - Supplies whether or not the user wished to format 256. --NEC--
+#endif // _PC98_
+// FMR Jul.12.1994 SFT KMR
+// Add Request640 on to the parmeter of DetermineMediaType()
+ Request640 - Supplies whether or not the user wished to format 640.
+// Add Request1232 on to the parmeter of DetermineMediaType()
+ Request1232 - Supplies whether or not the user wished to format 1232.
+#endif // JAPAN && _X86_
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ INT sum;
+
+ // First, normalize all of the booleans.
+
+ if (Request160) {
+ Request160 = 1;
+ *MediaType = F5_160_512;
+ }
+
+ if (Request180) {
+ Request180 = 1;
+ *MediaType = F5_180_512;
+ }
+
+ if (Request320) {
+ Request320 = 1;
+ *MediaType = F5_320_512;
+ }
+
+ if (Request360) {
+ Request360 = 1;
+ *MediaType = F5_360_512;
+ }
+
+#if defined(JAPAN) && defined(_X86_) && defined(_PC98_)
+ // NEC98 '94.09.22 NES
+ if (IsPC98_N()){
+ if (Request256) {
+ Request256 = 1;
+ *MediaType = F8_256_128;
+ }
+ }
+ // end NEC98 '94.09.22 NES
+#endif // _PC98_
+ if (Request720) {
+ Request720 = 1;
+ *MediaType = F3_720_512;
+ }
+
+ if (Request1200) {
+ Request1200 = 1;
+ *MediaType = F5_1Pt2_512;
+ }
+
+ if (Request1440) {
+ Request1440 = 1;
+ *MediaType = F3_1Pt44_512;
+ }
+
+ if (Request2880) {
+ Request2880 = 1;
+ *MediaType = F3_2Pt88_512;
+ }
+
+ if (Request20800) {
+ Request20800 = 1;
+ *MediaType = F3_20Pt8_512;
+ }
+#if defined(JAPAN) && (_X86_)
+// FMR Jul.12.1994 SFT KMR
+// Add the media_type_set_up_process when the 640KB format
+ if (Request640) {
+ Request640 = 1;
+ *MediaType = F5_640_512;
+ }
+
+// Add the media_type_set_up_process when the 2HD format
+ if (Request1232) {
+ Request1232 = 1;
+ *MediaType = F5_1Pt23_1024;
+ }
+#endif // JAPAN && _X86_
+
+ sum = Request160 +
+ Request180 +
+ Request320 +
+ Request360 +
+ Request720 +
+ Request1200 +
+ Request1440 +
+ Request2880 +
+ Request20800;
+#if defined(JAPAN) && defined(_X86_) && defined(_PC98_)
+ // NEC98 '94.09.22 NES
+ //*****1994/09/05 Hirata ********************************
+ // 256KB support
+ if (IsPC98_N()){
+ sum += Request256;
+ }
+#endif // _PC98_
+
+#if defined(JAPAN) && defined(_X86_)
+// FMR Jul.12.1994 SFT KMR
+// 640KB support
+// 1232KB support
+ sum += Request640 +
+ Request1232;
+#endif // JAPAN && _X86_
+
+ if (sum > 1) {
+
+ Message->Set(MSG_INCOMPATIBLE_PARAMETERS);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (sum == 0) {
+ *MediaType = Unknown;
+ }
+
+ return TRUE;
+}
+
+int _CRTAPI1
+main(
+ )
+/*++
+
+Routine Description:
+
+ This routine is the main procedure for format. This routine
+ parses the arguments, determines the appropriate file system,
+ and invokes the appropriate version of format.
+
+ The arguments accepted by format are:
+
+ /fs:fs - specifies file system to install on volume
+ /v:label - specifies a volume label.
+ /q - specifies a "quick" format.
+ /c - the file system is compressed.
+ /f:size - specifies the size of the floppy disk to format
+ /t - specifies the number of tracks per disk side
+ /n - specifies the number of sectors per track
+ /1 - formats a single side of a floppy
+ /4 - formats a 360K floppy in a high density drive
+ /8 - formats eight sectors per track
+ /backup - refrain from prompting the user
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ 0 - Success.
+ 1 - Failure.
+
+--*/
+{
+ STREAM_MESSAGE msg;
+ PMESSAGE message;
+ MEDIA_TYPE media_type, cmd_line_media_type;
+ DSTRING dosdrivename;
+ DSTRING arg_fsname;
+ DSTRING arg_label;
+ BOOLEAN label_spec;
+ BOOLEAN quick_format;
+ BOOLEAN compressed;
+ BOOLEAN force_mode;
+ INT errorlevel;
+ DSTRING ntdrivename;
+ DSTRING fsname;
+ DSTRING currentdrive;
+ DSTRING driveletter;
+ DSTRING raw_str;
+ DSTRING fat_str;
+ DSTRING ofs_str;
+ DSTRING ntfs_str;
+ DSTRING hpfs_str;
+ PWSTRING old_volume_label = NULL;
+ PATH dos_drive_path;
+ VOL_SERIAL_NUMBER old_serial;
+ DSTRING user_old_label;
+ DSTRING null_string;
+ BOOLEAN do_format;
+ BOOLEAN do_floppy_return;
+ DSTRING LibSuffix;
+ DSTRING LibraryName;
+ HANDLE FsUtilityHandle = NULL;
+ DSTRING FormatString;
+ FORMAT_FN Format = NULL;
+ DRIVE_TYPE drive_type;
+ BIG_INT bigint;
+ NTSTATUS Status;
+ DWORD OldErrorMode;
+ ULONG cluster_size;
+ BOOLEAN no_prompts;
+#if defined(JAPAN) && defined(_X86_)
+// FMR Jul.14.1994 SFT KMR
+// Add the value to use the process to judge for 5inci or 3.5inch
+
+ PCDRTYPE nt_media_types;
+ INT num_types;
+ MEDIA_TYPE alt_media_type;
+ INT i;
+ // FMR Oct.07.1994 SFT YAM
+ // Add the flag check whether unformat-disk.
+ INT Unknown_flag = FALSE;
+
+ InitializeMachineData();
+#endif
+
+ perrstk = NEW ERRSTACK;
+
+ if (!msg.Initialize(Get_Standard_Output_Stream(),
+ Get_Standard_Input_Stream())) {
+ return 4;
+ }
+
+ if( !null_string.Initialize( "" ) ) {
+ return 4;
+ }
+
+ if (!ParseArguments(&msg, &cmd_line_media_type, &dosdrivename,
+ &arg_label, &label_spec, &arg_fsname, &quick_format,
+ &force_mode, &cluster_size, &compressed, &no_prompts,
+ &errorlevel )) {
+
+ return errorlevel;
+ }
+
+ message = &msg;
+
+ if (!hpfs_str.Initialize("HPFS")) {
+ return 4;
+ }
+
+ if (arg_fsname == hpfs_str) {
+ message->Set(MSG_HPFS_NO_FORMAT);
+ message->Display("");
+ return 1;
+ }
+
+ // Disable popups while we determine the drive type.
+ OldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS );
+
+ drive_type = SYSTEM::QueryDriveType(&dosdrivename);
+
+ // Re-enable harderror popups.
+ SetErrorMode( OldErrorMode );
+
+ switch (drive_type) {
+ case UnknownDrive:
+ message->Set(MSG_NONEXISTENT_DRIVE);
+ message->Display("");
+ return 1;
+
+ case RemoteDrive:
+ message->Set(MSG_FORMAT_NO_NETWORK);
+ message->Display("");
+ return 1;
+
+ case CdRomDrive:
+ message->Set(MSG_FORMAT_NO_CDROM);
+ message->Display("");
+ return 1;
+
+ case RamDiskDrive:
+ message->Set(MSG_FORMAT_NO_RAMDISK);
+ message->Display("");
+ return 1;
+
+ default:
+ break;
+
+ }
+
+ if (!SYSTEM::QueryCurrentDosDriveName(&currentdrive) ||
+ currentdrive == dosdrivename) {
+
+ message->Set(MSG_CANT_LOCK_CURRENT_DRIVE);
+ message->Display();
+ return 1;
+ }
+
+ if (!IFS_SYSTEM::DosDriveNameToNtDriveName(&dosdrivename, &ntdrivename)) {
+ return 4;
+ }
+
+ if (!driveletter.Initialize(&dosdrivename, 0,
+ dosdrivename.QueryChCount() - 1)) {
+ return 4;
+ }
+
+
+ if (!raw_str.Initialize("RAW") ||
+ !fat_str.Initialize("FAT") ||
+ !ofs_str.Initialize("OFS") ||
+ !ntfs_str.Initialize("NTFS")) {
+
+ return 4;
+ }
+
+ for (;;) {
+
+ DP_DRIVE dpdrive;
+
+ // ------------------------------------
+ // Figure out if the drive is a floppy.
+ // ------------------------------------
+
+ if (drive_type == FixedDrive && cmd_line_media_type != Unknown) {
+ message->Set(MSG_INCOMPATIBLE_PARAMETERS_FOR_FIXED);
+ message->Display("");
+ return 1;
+ }
+
+ if (drive_type == RemovableDrive && !no_prompts) {
+ message->Set(MSG_INSERT_DISK);
+ message->Display("%W", &driveletter);
+ message->Set(MSG_PRESS_ENTER_WHEN_READY);
+ message->Display("");
+ message->WaitForUserSignal();
+ }
+
+
+
+
+ // -----------------------
+ // Now get the media type.
+ // -----------------------
+
+ // Disable hard-error popups while we initialize the drive.
+ // Otherwise, we'll may get the 'unformatted medium' popup,
+ // which doesn't make a lot of sense.
+
+ OldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS );
+
+ if (!dpdrive.Initialize(&ntdrivename, message)) {
+ // Re-enable hard-error popups
+ SetErrorMode( OldErrorMode );
+
+ return 4;
+ }
+
+#if defined(JAPAN) && defined(_X86_)
+// FMR Oct.07.1994 SFT YAM
+// Add the check whether unformat-disk.
+ if(dpdrive.QueryMediaType()==Unknown) {
+ Unknown_flag = TRUE;
+ }
+
+// FMR Jul.14.1994 SFT KMR
+// Add the process to judge for 5inch or 3.5inch
+// FMR is surport 3.5/5 inch disk drive. System default 2HD.
+// Return 3.5 or 5inch type media. driver used.
+// Search drive list on media type.
+
+#if defined(_PC98_)
+ if (IsFMR_N() || IsPC98_N()) {
+#endif // _PC98_
+ if (!(nt_media_types = dpdrive.GetSupportedList(&num_types))) {
+ return 4;
+ }
+ for (i = 0; i < num_types; i++) {
+ if ( nt_media_types[i].MediaType == cmd_line_media_type) break;
+ }
+ if (i == num_types) {
+ switch(cmd_line_media_type) {
+ case F5_1Pt23_1024:
+ alt_media_type = F3_1Pt23_1024;
+ break;
+ case F3_1Pt23_1024:
+ alt_media_type = F5_1Pt23_1024;
+ break;
+ case F5_1Pt2_512:
+ alt_media_type = F3_1Pt2_512;
+ break;
+ case F3_1Pt2_512:
+ alt_media_type = F5_1Pt2_512;
+ break;
+ case F3_720_512:
+ alt_media_type = F5_720_512;
+ break;
+ case F5_720_512:
+ alt_media_type = F3_720_512;
+ break;
+ case F5_640_512:
+ alt_media_type = F3_640_512;
+ break;
+ case F3_640_512:
+ alt_media_type = F5_640_512;
+ break;
+ default:
+ break;
+ }
+ for (i = 0; i < num_types; i++) {
+ if ( nt_media_types[i].MediaType == alt_media_type){
+ cmd_line_media_type = alt_media_type;
+ break;
+ }
+ }
+ }
+#if defined(_PC98_)
+ }
+#endif // _PC98_
+#endif // JAPAN && _X86_
+
+ // Re-enable hard-error popups
+ SetErrorMode( OldErrorMode );
+
+ if (cmd_line_media_type == Unknown) {
+ media_type = dpdrive.QueryMediaType();
+ } else {
+ media_type = cmd_line_media_type;
+ }
+
+ if (media_type == Unknown) {
+
+ media_type = dpdrive.QueryRecommendedMediaType();
+
+ if (media_type == Unknown) {
+ // This should never happen.
+ DebugPrint("No media types supported by this device.\n");
+ return 4;
+ }
+ }
+
+ do_floppy_return = dpdrive.IsFloppy();
+
+ // Disable hard error popups. This will prevent the file system
+ // from throwing up the popup that says 'unformatted medium'.
+
+ OldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS );
+
+ if (!IFS_SYSTEM::QueryFileSystemName(&ntdrivename, &fsname, &Status)) {
+
+ if( Status == STATUS_ACCESS_DENIED ) {
+
+ message->Set( MSG_DASD_ACCESS_DENIED );
+ message->Display( "" );
+
+ } else {
+
+ message->Set( MSG_FS_NOT_DETERMINED );
+ message->Display( "%W", &dosdrivename );
+ }
+
+ // Re-enable hard error popups.
+ SetErrorMode( OldErrorMode );
+
+ return 1;
+ }
+
+ // Re-enable hard error popups.
+ SetErrorMode( OldErrorMode );
+
+ if (!fsname.Strupr()) {
+ message->Set(MSG_FS_NOT_DETERMINED);
+ message->Display("%W", &dosdrivename);
+ return 4;
+ }
+
+ message->Set(MSG_FILE_SYSTEM_TYPE);
+ message->Display("%W", &fsname);
+
+ //
+ // If compression is requested, make sure we can compress the
+ // indicated file system type (or the current filesystem type,
+ // if the user didn't specify one). Compression is not supported
+ // for 64k-cluster NTFS volumes.
+ //
+
+ if (compressed) {
+ if (0 != ntfs_str.Stricmp( 0 != arg_fsname.QueryChCount() ?
+ &arg_fsname : &fsname )) {
+
+ message->Set(MSG_COMPRESSION_NOT_AVAILABLE);
+ message->Display("%W", 0 != arg_fsname.QueryChCount() ?
+ &arg_fsname : &fsname );
+ return 1;
+ }
+ if (cluster_size > 4096) {
+ message->Set(MSG_CANNOT_COMPRESS_HUGE_CLUSTERS);
+ message->Display();
+ return 1;
+ }
+ }
+
+ //
+ // Determine which IFS library to load. The IFS
+ // utilities for file system xxxx reside in Uxxxx.DLL.
+ // If the use specified the file system with the /FS:
+ // parameter, use that file system; otherwise, take
+ // whatever's already on the disk (returned from
+ // SYSTEM::QueryFileSystemName).
+ //
+
+ if( !LibraryName.Initialize( "U" ) ) {
+
+ return 4;
+ }
+
+ if (!LibSuffix.Initialize(arg_fsname.QueryChCount() ?
+ &arg_fsname : &fsname) ||
+ !LibSuffix.Strupr()) {
+ return 4;
+ }
+
+ if (fsname != LibSuffix) {
+ message->Set(MSG_NEW_FILE_SYSTEM_TYPE);
+ message->Display("%W", &LibSuffix);
+ } else if (fsname == raw_str) {
+ if (dpdrive.IsFloppy()) {
+ if (!LibSuffix.Initialize(&fat_str)) {
+ return 4;
+ }
+ message->Set(MSG_NEW_FILE_SYSTEM_TYPE);
+ message->Display("%W", &LibSuffix);
+ } else {
+ message->Set(MSG_FORMAT_PLEASE_USE_FS_SWITCH);
+ message->Display("");
+ return 1;
+ }
+ }
+
+ if( !LibraryName.Strcat( &LibSuffix ) ) {
+
+ return 4;
+ }
+
+ if( !FormatString.Initialize( "Format" ) ) {
+
+ return 4;
+ }
+
+ if( (Format =
+ (FORMAT_FN)SYSTEM::QueryLibraryEntryPoint( &LibraryName,
+ &FormatString,
+ &FsUtilityHandle )) ==
+ NULL ) {
+
+ message->Set( MSG_FS_NOT_SUPPORTED );
+ message->Display( "%s%W", "FORMAT", &LibSuffix );
+ message->Set( MSG_BLANK_LINE );
+ message->Display( "" );
+ return 1;
+ }
+
+
+ if (drive_type != RemovableDrive) {
+
+ // If the volume has a label, prompt the user for it.
+ // Note that if we can't get the label, we'll treat it
+ // as without a label (since we have to handle unformatted
+ // volumes).
+
+ OldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS );
+
+ if( !force_mode &&
+ dos_drive_path.Initialize( &dosdrivename) &&
+ (old_volume_label =
+ SYSTEM::QueryVolumeLabel( &dos_drive_path,
+ &old_serial )) != NULL &&
+ old_volume_label->Stricmp( &null_string ) != 0 ) {
+
+ // This fixed drive has a label. To give the user
+ // a bit more protection, prompt for the old label:
+
+ message->Set( MSG_ENTER_CURRENT_LABEL );
+ message->Display( "%W", &driveletter );
+ message->QueryStringInput( &user_old_label );
+
+ if( old_volume_label->Stricmp( &user_old_label ) != 0 ) {
+
+ // Re-enable hard error popups.
+ SetErrorMode( OldErrorMode );
+
+ message->Set( MSG_WRONG_CURRENT_LABEL );
+ message->Display( "" );
+
+ DELETE( old_volume_label );
+
+ return 1;
+ }
+ }
+
+ // Re-enable hard error popups.
+ SetErrorMode( OldErrorMode );
+
+ DELETE( old_volume_label );
+ old_volume_label = NULL;
+
+ if (!force_mode) {
+ message->Set(MSG_WARNING_FORMAT);
+ message->Display("%W", &driveletter);
+ if (!message->IsYesResponse(FALSE)) {
+ return 5;
+ }
+ }
+ }
+
+
+
+ // ------------------------------------
+ // Print the formatting <size> message.
+ // ------------------------------------
+
+ do_format = (BOOLEAN) (media_type != dpdrive.QueryMediaType());
+
+ switch (media_type) {
+ case F5_160_512:
+ case F5_180_512:
+ case F5_320_512:
+ case F5_360_512:
+#if defined(JAPAN) && defined(_X86_) && defined(_PC98_)
+ //*****1993/08/03 haga***********************************
+ case F8_256_128:
+#endif // _PC98_
+ case F3_720_512:
+#if defined (JAPAN) && defined(_X86_)
+// FMR Jul.12.1994 SFT KMR
+// Modify the process to be display
+// when formating 640KB and 5inch's 720KB disk
+ case F5_640_512:
+ case F3_640_512:
+ case F5_720_512:
+#endif
+ if (quick_format) {
+ message->Set(MSG_QUICKFORMATTING_KB);
+ } else if (do_format) {
+ message->Set(MSG_FORMATTING_KB);
+ } else {
+ message->Set(MSG_VERIFYING_KB);
+ }
+ break;
+
+ case F5_1Pt2_512:
+ case F3_1Pt44_512:
+ case F3_2Pt88_512:
+ case F3_20Pt8_512:
+#if defined(JAPAN) && defined(_X86_)
+// FMR Jul.12.1994 SFT KMR
+// Modify the process to be display
+// when formating 1.20/1.23MB disk
+ case F3_1Pt2_512:
+ case F5_1Pt23_1024:
+ case F3_1Pt23_1024:
+#endif // JAPAN && _X86_
+ if (quick_format) {
+ message->Set(MSG_QUICKFORMATTING_DOT_MB);
+ } else if (do_format) {
+ message->Set(MSG_FORMATTING_DOT_MB);
+ } else {
+ message->Set(MSG_VERIFYING_DOT_MB);
+ }
+ break;
+
+ case RemovableMedia:
+ case FixedMedia:
+ case F3_120M_512:
+#if defined(JAPAN) && defined(_X86_) && defined(_PC98_)
+ case F3_128Mb_512: //***1993/08/03 haga 3.5"MO***
+#endif // _PC98_
+ if (quick_format) {
+ message->Set(MSG_QUICKFORMATTING_MB);
+ } else if (do_format) {
+ message->Set(MSG_FORMATTING_MB);
+ } else {
+ message->Set(MSG_VERIFYING_MB);
+ }
+ break;
+
+ case F5_320_1024:
+ case Unknown:
+ // This can't happen.
+ return 4;
+ }
+
+ switch (media_type) {
+ case F5_160_512:
+ message->Display("%d", 160);
+ break;
+
+ case F5_180_512:
+ message->Display("%d", 180);
+ break;
+
+ case F5_320_512:
+ message->Display("%d", 320);
+ break;
+
+ case F5_360_512:
+ message->Display("%d", 360);
+ break;
+
+#if defined(JAPAN) && defined(_X86_) && defined(_PC98_)
+ //*****1993/09/05 Hirata ********************************
+ case F8_256_128:
+ message->Display("%d", 256);
+ break;
+#endif // _PC98_
+ case F3_720_512:
+#if defined(JAPAN) && defined(_X86_)
+// FMR Jul.12.1994 SFT KMR
+ case F5_720_512:
+#endif
+ message->Display("%d", 720);
+ break;
+
+ case F5_1Pt2_512:
+#if defined(JAPAN) && defined(_X86_)
+// FMR Jul.12.1994 SFT KMR
+ case F3_1Pt2_512:
+#endif // JAPAN && _X86_
+ message->Display("%d%d", 1, 2);
+ break;
+
+ case F3_1Pt44_512:
+ message->Display("%d%d", 1, 44);
+ break;
+
+ case F3_2Pt88_512:
+ message->Display("%d%d", 2, 88);
+ break;
+
+ case F3_20Pt8_512:
+ message->Display("%d%d", 20, 8);
+ break;
+
+ case RemovableMedia:
+ case FixedMedia:
+ case F3_120M_512:
+#if defined(JAPAN) && defined(_X86_) && defined(_PC98_)
+ case F3_128Mb_512: //***1993/08/03 haga 3.5"MO***
+#endif // _PC98_
+ bigint = dpdrive.QuerySectors()*
+ dpdrive.QuerySectorSize()/
+ 1048576;
+
+ DebugAssert(bigint.GetHighPart() == 0);
+
+ message->Display("%d", bigint.GetLowPart());
+ break;
+
+ case F5_320_1024:
+ case Unknown:
+ // This can't happen.
+ return 4;
+#if defined(JAPAN) && defined(_X86_)
+// FMR Jul.12.1994 SFT KMR
+// Modify the process to be display when formating 640KB disk
+// Modify the process to be display when formating 5inch's 720KB disk
+// Modify the process to be display when formating 3.5inch's 2HC disk
+// Modify the process to be display when formating 2HD disk
+ case F5_640_512:
+ case F3_640_512:
+ message->Display("%d", 640);
+ break;
+
+ case F5_1Pt23_1024:
+ case F3_1Pt23_1024:
+#if defined(_PC98_)
+ // ***** 94.09.04 Hirata *****
+ if (IsPC98_N()){
+ message->Display("%d%d", 1, 25);
+ }
+ else{
+ message->Display("%d%d", 1, 23);
+ }
+ break;
+#else // !_PC98_
+ message->Display("%d%d", 1, 23);
+ break;
+#endif // _PC98_
+#endif // JAPAN && _X86_
+ }
+
+#if defined (JAPAN) && defined (_X86_)
+// FMR Oct.07.1994 SFT YAM
+// If the sector-size when the last format differ from next format,
+// initialize a hard one-byte of disk.
+// at this time,if next formated disk is unformat-disk,
+// this process is undone.
+
+ ULONG old_sec_size;
+ ULONG new_sec_size;
+ UCHAR rw_buff[2048];
+ LOG_IO_DP_DRIVE *LDpDrive = NEW LOG_IO_DP_DRIVE;
+
+
+ if(drive_type == RemovableDrive && !no_prompts) {
+ if(Unknown_flag == FALSE) {
+ old_sec_size = dpdrive.QuerySectorSize();
+
+ if(cmd_line_media_type == F5_1Pt23_1024 || cmd_line_media_type == F3_1Pt23_1024) {
+ new_sec_size = 1024;
+ }
+ else {
+ new_sec_size = 512;
+ }
+
+ if(new_sec_size != old_sec_size) {
+ LDpDrive->Initialize(&ntdrivename,message,TRUE);
+ LDpDrive->Read(0,1,&rw_buff);
+ rw_buff[0] = 0;
+ LDpDrive->Write(0,1,&rw_buff);
+ }
+ }
+ }
+ else {
+ if (IsFMR_N()) {
+ if(LibSuffix.Stricmp(&fsname)) {
+ LDpDrive->Initialize(&ntdrivename,message,TRUE);
+ LDpDrive->Read(0,1,&rw_buff);
+ rw_buff[0] = 0;
+ LDpDrive->Write(0,1,&rw_buff);
+ }
+ }
+ }
+ DELETE( LDpDrive );
+
+#endif // JAPAN && _X86_
+
+ // Disable hard-error popups.
+ OldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS );
+
+ if( !Format( &ntdrivename,
+ message,
+ quick_format,
+ media_type,
+ label_spec ? &arg_label : NULL,
+ cluster_size
+ ) ) {
+
+ // Enable hard-error popups.
+ SetErrorMode( OldErrorMode );
+
+ SYSTEM::FreeLibraryHandle( FsUtilityHandle );
+ return 4;
+ }
+
+ // Enable hard-error popups.
+ SetErrorMode( OldErrorMode );
+
+
+ SYSTEM::FreeLibraryHandle( FsUtilityHandle );
+
+
+ if (do_floppy_return && !no_prompts) {
+ message->Set(quick_format ? MSG_QUICKFMT_ANOTHER : MSG_FORMAT_ANOTHER);
+ message->Display("");
+ if (!message->IsYesResponse(FALSE)) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+
+ // Make sure that the file system is installed.
+
+ if (!do_floppy_return &&
+ !IFS_SYSTEM::IsFileSystemEnabled(&LibSuffix)) {
+
+ message->Set(MSG_FMT_INSTALL_FILE_SYSTEM);
+ message->Display("%W", &LibSuffix);
+ if (message->IsYesResponse(TRUE)) {
+ if (!IFS_SYSTEM::EnableFileSystem(&LibSuffix)) {
+ message->Set(MSG_FMT_CANT_INSTALL_FILE_SYSTEM);
+ message->Display();
+ return 1;
+ }
+
+ message->Set(MSG_FMT_FILE_SYSTEM_INSTALLED);
+ message->Display();
+ }
+ }
+
+ if (compressed && !IFS_SYSTEM::EnableVolumeCompression(&ntdrivename)) {
+ message->Set(MSG_CANNOT_ENABLE_COMPRESSION);
+ message->Display();
+
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/private/utils/format/format.rc b/private/utils/format/format.rc
new file mode 100644
index 000000000..a6ed927d3
--- /dev/null
+++ b/private/utils/format/format.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Disk Format Utility"
+#define VER_INTERNALNAME_STR "format\0"
+#define VER_ORIGINALFILENAME_STR "format.com"
+
+#include "common.ver"
diff --git a/private/utils/format/makefile b/private/utils/format/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/format/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/format/makefile.inc b/private/utils/format/makefile.inc
new file mode 100644
index 000000000..6c93eb38d
--- /dev/null
+++ b/private/utils/format/makefile.inc
@@ -0,0 +1,12 @@
+{}.cxx{obj\i386\}.obj:
+ $(386_COMPILER) -Fo$@ $(MAKEDIR)\$(<F)
+
+{}.cxx{obj\mips\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClMips $< " $(C_COMPILER) "
+ @$(C_COMPILER) -Fo$@ $(MAKEDIR)\$<
+
+{}.cxx{obj\alpha\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClAlpha $< " $(ALPHA_COMPILER) "
+ @$(ALPHA_COMPILER) -Fo$@ $(MAKEDIR)\$<
diff --git a/private/utils/format/parse.cxx b/private/utils/format/parse.cxx
new file mode 100644
index 000000000..e208a8a93
--- /dev/null
+++ b/private/utils/format/parse.cxx
@@ -0,0 +1,1346 @@
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+#if defined(JAPAN) && defined(_X86_)
+#include "machine.hxx"
+#endif // JAPAN && _X86_
+#include "error.hxx"
+#include "drive.hxx"
+#include "arg.hxx"
+#include "array.hxx"
+#include "smsg.hxx"
+#include "rtmsg.h"
+#include "system.hxx"
+#include "ifssys.hxx"
+#include "ulibcl.hxx"
+#include "ifsentry.hxx"
+#include "path.hxx"
+#include "parse.hxx"
+
+extern "C" {
+ #include "nturtl.h"
+}
+
+
+BOOLEAN
+ParseArguments(
+ IN OUT PMESSAGE Message,
+ OUT PMEDIA_TYPE MediaType,
+ OUT PWSTRING DosDriveName,
+ OUT PWSTRING Label,
+ OUT PBOOLEAN IsLabelSpeced,
+ OUT PWSTRING FileSystemName,
+ OUT PBOOLEAN QuickFormat,
+ OUT PBOOLEAN ForceMode,
+ OUT PULONG ClusterSize,
+ OUT PBOOLEAN Compress,
+ OUT PBOOLEAN NoPrompts,
+ OUT PINT ErrorLevel
+ )
+{
+ PWSTRING pwstring;
+ BOOLEAN req160;
+ BOOLEAN req180;
+ BOOLEAN req320;
+ BOOLEAN req360;
+#if defined(JAPAN) && defined(_X86_) && defined(_PC98_)
+//*******1994/09/05 Hirata 640 delete **********************
+ BOOLEAN req256;
+#endif // _PC98_
+ BOOLEAN req720;
+ BOOLEAN req1200;
+ BOOLEAN req1440;
+ BOOLEAN req2880;
+ BOOLEAN req20800;
+#if defined(JAPAN) && defined(_X86_)
+// FMR Jul.12.1994 SFT KMR
+// Add the 640KB_check on to the ParseArguments()
+ BOOLEAN req640;
+
+// Add the 2HD_check on to the ParseArguments()
+ BOOLEAN req1232;
+#endif
+ DSTRING tmp_string;
+ ULONG v;
+
+ ARGUMENT_LEXEMIZER arglex;
+ ARRAY lex_array;
+ ARRAY arg_array;
+ PSTRING_ARGUMENT progname = NULL;
+ PFLAG_ARGUMENT dummyv = NULL;
+ PFLAG_ARGUMENT dummyu = NULL;
+ PSTRING_ARGUMENT drive = NULL;
+ PFLAG_ARGUMENT quick = NULL;
+ PFLAG_ARGUMENT compress = NULL;
+ PFLAG_ARGUMENT force = NULL;
+ PFLAG_ARGUMENT null_label = NULL;
+ PSTRING_ARGUMENT label = NULL;
+ PFLAG_ARGUMENT f160 = NULL;
+ PFLAG_ARGUMENT f160k = NULL;
+ PFLAG_ARGUMENT f160kb = NULL;
+ PFLAG_ARGUMENT f180 = NULL;
+ PFLAG_ARGUMENT f180k = NULL;
+ PFLAG_ARGUMENT f180kb = NULL;
+ PFLAG_ARGUMENT f320 = NULL;
+ PFLAG_ARGUMENT f320k = NULL;
+ PFLAG_ARGUMENT f320kb = NULL;
+ PFLAG_ARGUMENT f360 = NULL;
+ PFLAG_ARGUMENT f360k = NULL;
+ PFLAG_ARGUMENT f360kb = NULL;
+#if defined(JAPAN) && defined(_X86_) && defined(_PC98_)
+//*******1993/09/05 Hirata*******************************
+ PFLAG_ARGUMENT f256 = NULL;
+ PFLAG_ARGUMENT f256k = NULL;
+ PFLAG_ARGUMENT f256kb = NULL;
+#endif // _PC98_
+ PFLAG_ARGUMENT f720 = NULL;
+ PFLAG_ARGUMENT f720k = NULL;
+ PFLAG_ARGUMENT f720kb = NULL;
+ PFLAG_ARGUMENT f1200 = NULL;
+ PFLAG_ARGUMENT f1200k = NULL;
+ PFLAG_ARGUMENT f1200kb = NULL;
+ PFLAG_ARGUMENT f12 = NULL;
+ PFLAG_ARGUMENT f12m = NULL;
+ PFLAG_ARGUMENT f12mb = NULL;
+#if defined(JAPAN) && defined(_X86_) && defined(_PC98_)
+//*******1993/08/03 haga*********************************
+ PFLAG_ARGUMENT f1250 = NULL;
+ PFLAG_ARGUMENT f1250k = NULL;
+ PFLAG_ARGUMENT f1250kb = NULL;
+ PFLAG_ARGUMENT f125 = NULL;
+ PFLAG_ARGUMENT f125m = NULL;
+ PFLAG_ARGUMENT f125mb = NULL;
+ PFLAG_ARGUMENT f1 = NULL;
+ PFLAG_ARGUMENT f1m = NULL;
+ PFLAG_ARGUMENT f1mb = NULL;
+#endif // _PC98_
+ PFLAG_ARGUMENT f1440 = NULL;
+ PFLAG_ARGUMENT f1440k = NULL;
+ PFLAG_ARGUMENT f1440kb = NULL;
+ PFLAG_ARGUMENT f144 = NULL;
+ PFLAG_ARGUMENT f144m = NULL;
+ PFLAG_ARGUMENT f144mb = NULL;
+ PFLAG_ARGUMENT f2880 = NULL;
+ PFLAG_ARGUMENT f2880k = NULL;
+ PFLAG_ARGUMENT f2880kb = NULL;
+ PFLAG_ARGUMENT f288 = NULL;
+ PFLAG_ARGUMENT f288m = NULL;
+ PFLAG_ARGUMENT f288mb = NULL;
+ PFLAG_ARGUMENT f208 = NULL;
+ PFLAG_ARGUMENT f208m = NULL;
+ PFLAG_ARGUMENT f208mb = NULL;
+#if defined(JAPAN) && defined(_X86_)
+// FMR Jul.12.1994 SFT KMR
+// Add the 640KB_check on to the ParseArguments()
+ PFLAG_ARGUMENT f640 = NULL;
+ PFLAG_ARGUMENT f640k = NULL;
+ PFLAG_ARGUMENT f640kb = NULL;
+
+// Add the 2HD_check on to the ParseArguments()
+ PFLAG_ARGUMENT f1232 = NULL;
+ PFLAG_ARGUMENT f1232k = NULL;
+ PFLAG_ARGUMENT f1232kb = NULL;
+
+// Add the 2HD_check on to the ParseArguments()
+ PFLAG_ARGUMENT f123 = NULL;
+ PFLAG_ARGUMENT f123m = NULL;
+ PFLAG_ARGUMENT f123mb = NULL;
+#endif
+ PFLAG_ARGUMENT cs512 = NULL;
+ PFLAG_ARGUMENT cs1024 = NULL;
+ PFLAG_ARGUMENT cs2048 = NULL;
+ PFLAG_ARGUMENT cs4096 = NULL;
+ PFLAG_ARGUMENT cs8192 = NULL;
+ PFLAG_ARGUMENT cs16k = NULL;
+ PFLAG_ARGUMENT cs32k = NULL;
+ PFLAG_ARGUMENT cs64k = NULL;
+ PFLAG_ARGUMENT cs128k = NULL;
+ PFLAG_ARGUMENT cs256k = NULL;
+ PFLAG_ARGUMENT one = NULL;
+ PFLAG_ARGUMENT four = NULL;
+ PFLAG_ARGUMENT eight = NULL;
+ PLONG_ARGUMENT secpertrack = NULL;
+ PLONG_ARGUMENT numtracks = NULL;
+ PSTRING_ARGUMENT arg_fs_name = NULL;
+ PFLAG_ARGUMENT helparg = NULL;
+ PFLAG_ARGUMENT no_prompts = NULL;
+
+
+ DebugAssert(Message);
+ DebugAssert(MediaType);
+ DebugAssert(DosDriveName);
+ DebugAssert(Label);
+ DebugAssert(FileSystemName);
+ DebugAssert(QuickFormat);
+ DebugAssert(ErrorLevel);
+ DebugAssert(NoPrompts);
+
+
+#if defined(JAPAN) && defined(_X86_)
+// FMR Jul.13.1994 SFT KMR
+// FMR is surpport 640KB&2HD, non surpport 2D Media.
+// NT format is compatible for DOS format.
+ if( IsFMR_N() ) {
+ if (!(progname = NEW STRING_ARGUMENT) ||
+ !(dummyv = NEW FLAG_ARGUMENT) ||
+ !(dummyu = NEW FLAG_ARGUMENT) ||
+ !(drive = NEW STRING_ARGUMENT) ||
+ !(quick = NEW FLAG_ARGUMENT) ||
+ !(compress = NEW FLAG_ARGUMENT) ||
+ !(force = NEW FLAG_ARGUMENT) ||
+ !(null_label = NEW FLAG_ARGUMENT) ||
+ !(no_prompts = NEW FLAG_ARGUMENT) ||
+ !(label = NEW STRING_ARGUMENT) ||
+// Delete the /F:160,180,320 and 360 process from the ParseArguments()
+// !(f160 = NEW FLAG_ARGUMENT) ||
+// !(f160k = NEW FLAG_ARGUMENT) ||
+// !(f160kb = NEW FLAG_ARGUMENT) ||
+// !(f180 = NEW FLAG_ARGUMENT) ||
+// !(f180k = NEW FLAG_ARGUMENT) ||
+// !(f180kb = NEW FLAG_ARGUMENT) ||
+// !(f320 = NEW FLAG_ARGUMENT) ||
+// !(f320k = NEW FLAG_ARGUMENT) ||
+// !(f320kb = NEW FLAG_ARGUMENT) ||
+// !(f360 = NEW FLAG_ARGUMENT) ||
+// !(f360k = NEW FLAG_ARGUMENT) ||
+// !(f360kb = NEW FLAG_ARGUMENT) ||
+// Add the 640KB_check on to the ParseArguments()
+ !(f640 = NEW FLAG_ARGUMENT) ||
+ !(f640k = NEW FLAG_ARGUMENT) ||
+ !(f640kb = NEW FLAG_ARGUMENT) ||
+ !(f720 = NEW FLAG_ARGUMENT) ||
+ !(f720k = NEW FLAG_ARGUMENT) ||
+ !(f720kb = NEW FLAG_ARGUMENT) ||
+ !(f1200 = NEW FLAG_ARGUMENT) ||
+ !(f1200k = NEW FLAG_ARGUMENT) ||
+ !(f1200kb = NEW FLAG_ARGUMENT) ||
+// Add the 2HD_check on to the ParseArguments()
+ !(f1232 = NEW FLAG_ARGUMENT) ||
+ !(f1232k = NEW FLAG_ARGUMENT) ||
+ !(f1232kb = NEW FLAG_ARGUMENT) ||
+ !(f12 = NEW FLAG_ARGUMENT) ||
+ !(f12m = NEW FLAG_ARGUMENT) ||
+ !(f12mb = NEW FLAG_ARGUMENT) ||
+// Add the 2HD_check on to the ParseArguments()
+ !(f123 = NEW FLAG_ARGUMENT) ||
+ !(f123m = NEW FLAG_ARGUMENT) ||
+ !(f123mb = NEW FLAG_ARGUMENT) ||
+ !(f1440 = NEW FLAG_ARGUMENT) ||
+ !(f1440k = NEW FLAG_ARGUMENT) ||
+ !(f1440kb = NEW FLAG_ARGUMENT) ||
+ !(f144 = NEW FLAG_ARGUMENT) ||
+ !(f144m = NEW FLAG_ARGUMENT) ||
+ !(f144mb = NEW FLAG_ARGUMENT) ||
+ !(f2880 = NEW FLAG_ARGUMENT) ||
+ !(f2880k = NEW FLAG_ARGUMENT) ||
+ !(f2880kb = NEW FLAG_ARGUMENT) ||
+ !(f288 = NEW FLAG_ARGUMENT) ||
+ !(f288m = NEW FLAG_ARGUMENT) ||
+ !(f288mb = NEW FLAG_ARGUMENT) ||
+ !(f208 = NEW FLAG_ARGUMENT)) {
+
+ *ErrorLevel = 4;
+ return FALSE;
+ }
+ }
+ else
+#endif
+#if defined(JAPAN) && defined(_X86_) && defined(_PC98_)
+//*******1993/08/03 haga*********************************
+ if(IsPC98_N()){
+ if (!(progname = NEW STRING_ARGUMENT) ||
+ !(dummyv = NEW FLAG_ARGUMENT) ||
+ !(dummyu = NEW FLAG_ARGUMENT) ||
+ !(drive = NEW STRING_ARGUMENT) ||
+ !(quick = NEW FLAG_ARGUMENT) ||
+ !(compress = NEW FLAG_ARGUMENT) ||
+ !(force = NEW FLAG_ARGUMENT) ||
+ !(null_label = NEW FLAG_ARGUMENT) ||
+ !(no_prompts = NEW FLAG_ARGUMENT) ||
+ !(label = NEW STRING_ARGUMENT) ||
+ !(f160 = NEW FLAG_ARGUMENT) ||
+ !(f160k = NEW FLAG_ARGUMENT) ||
+ !(f160kb = NEW FLAG_ARGUMENT) ||
+ !(f180 = NEW FLAG_ARGUMENT) ||
+ !(f180k = NEW FLAG_ARGUMENT) ||
+ !(f180kb = NEW FLAG_ARGUMENT) ||
+ !(f256 = NEW FLAG_ARGUMENT) ||
+ !(f256k = NEW FLAG_ARGUMENT) ||
+ !(f256kb = NEW FLAG_ARGUMENT) ||
+ !(f320 = NEW FLAG_ARGUMENT) ||
+ !(f320k = NEW FLAG_ARGUMENT) ||
+ !(f320kb = NEW FLAG_ARGUMENT) ||
+ !(f360 = NEW FLAG_ARGUMENT) ||
+ !(f360k = NEW FLAG_ARGUMENT) ||
+ !(f360kb = NEW FLAG_ARGUMENT) ||
+ !(f640 = NEW FLAG_ARGUMENT) ||
+ !(f640k = NEW FLAG_ARGUMENT) ||
+ !(f640kb = NEW FLAG_ARGUMENT) ||
+ !(f1232 = NEW FLAG_ARGUMENT) ||
+ !(f1232k = NEW FLAG_ARGUMENT) ||
+ !(f1232kb = NEW FLAG_ARGUMENT) ||
+ !(f123 = NEW FLAG_ARGUMENT) ||
+ !(f123m = NEW FLAG_ARGUMENT) ||
+ !(f123mb = NEW FLAG_ARGUMENT) ||
+ !(f720 = NEW FLAG_ARGUMENT) ||
+ !(f720k = NEW FLAG_ARGUMENT) ||
+ !(f720kb = NEW FLAG_ARGUMENT) ||
+ !(f1200 = NEW FLAG_ARGUMENT) ||
+ !(f1200k = NEW FLAG_ARGUMENT) ||
+ !(f1200kb = NEW FLAG_ARGUMENT) ||
+ !(f12 = NEW FLAG_ARGUMENT) ||
+ !(f12m = NEW FLAG_ARGUMENT) ||
+ !(f12mb = NEW FLAG_ARGUMENT) ||
+ !(f1250 = NEW FLAG_ARGUMENT) ||
+ !(f1250k = NEW FLAG_ARGUMENT) ||
+ !(f1250kb = NEW FLAG_ARGUMENT) ||
+ !(f125 = NEW FLAG_ARGUMENT) ||
+ !(f125m = NEW FLAG_ARGUMENT) ||
+ !(f125mb = NEW FLAG_ARGUMENT) ||
+ !(f1 = NEW FLAG_ARGUMENT) ||
+ !(f1m = NEW FLAG_ARGUMENT) ||
+ !(f1mb = NEW FLAG_ARGUMENT) ||
+ !(f1440 = NEW FLAG_ARGUMENT) ||
+ !(f1440k = NEW FLAG_ARGUMENT) ||
+ !(f1440kb = NEW FLAG_ARGUMENT) ||
+ !(f144 = NEW FLAG_ARGUMENT) ||
+ !(f144m = NEW FLAG_ARGUMENT) ||
+ !(f144mb = NEW FLAG_ARGUMENT) ||
+ !(f2880 = NEW FLAG_ARGUMENT) ||
+ !(f2880k = NEW FLAG_ARGUMENT) ||
+ !(f2880kb = NEW FLAG_ARGUMENT) ||
+ !(f288 = NEW FLAG_ARGUMENT) ||
+ !(f288m = NEW FLAG_ARGUMENT) ||
+ !(f288mb = NEW FLAG_ARGUMENT) ||
+ !(f208 = NEW FLAG_ARGUMENT)) {
+
+ *ErrorLevel = 4;
+ return FALSE;
+ }
+ }else
+#endif // _PC98_
+ if (!(progname = NEW STRING_ARGUMENT) ||
+ !(dummyv = NEW FLAG_ARGUMENT) ||
+ !(dummyu = NEW FLAG_ARGUMENT) ||
+ !(drive = NEW STRING_ARGUMENT) ||
+ !(quick = NEW FLAG_ARGUMENT) ||
+ !(compress = NEW FLAG_ARGUMENT) ||
+ !(force = NEW FLAG_ARGUMENT) ||
+ !(null_label = NEW FLAG_ARGUMENT) ||
+ !(no_prompts = NEW FLAG_ARGUMENT) ||
+ !(label = NEW STRING_ARGUMENT) ||
+ !(f160 = NEW FLAG_ARGUMENT) ||
+ !(f160k = NEW FLAG_ARGUMENT) ||
+ !(f160kb = NEW FLAG_ARGUMENT) ||
+ !(f180 = NEW FLAG_ARGUMENT) ||
+ !(f180k = NEW FLAG_ARGUMENT) ||
+ !(f180kb = NEW FLAG_ARGUMENT) ||
+ !(f320 = NEW FLAG_ARGUMENT) ||
+ !(f320k = NEW FLAG_ARGUMENT) ||
+ !(f320kb = NEW FLAG_ARGUMENT) ||
+ !(f360 = NEW FLAG_ARGUMENT) ||
+ !(f360k = NEW FLAG_ARGUMENT) ||
+ !(f360kb = NEW FLAG_ARGUMENT) ||
+#if defined(JAPAN) && defined(_X86_)
+// FMR Jul.13.1994 SFT KMR
+// FMR is surpport 640KB&2HD, non surpport 2D Media.
+// NT format is compatible for DOS format.
+ !(f640 = NEW FLAG_ARGUMENT) ||
+ !(f640k = NEW FLAG_ARGUMENT) ||
+ !(f640kb = NEW FLAG_ARGUMENT) ||
+ !(f1232 = NEW FLAG_ARGUMENT) ||
+ !(f1232k = NEW FLAG_ARGUMENT) ||
+ !(f1232kb = NEW FLAG_ARGUMENT) ||
+ !(f123 = NEW FLAG_ARGUMENT) ||
+ !(f123m = NEW FLAG_ARGUMENT) ||
+ !(f123mb = NEW FLAG_ARGUMENT) ||
+#endif
+ !(f720 = NEW FLAG_ARGUMENT) ||
+ !(f720k = NEW FLAG_ARGUMENT) ||
+ !(f720kb = NEW FLAG_ARGUMENT) ||
+ !(f1200 = NEW FLAG_ARGUMENT) ||
+ !(f1200k = NEW FLAG_ARGUMENT) ||
+ !(f1200kb = NEW FLAG_ARGUMENT) ||
+ !(f12 = NEW FLAG_ARGUMENT) ||
+ !(f12m = NEW FLAG_ARGUMENT) ||
+ !(f12mb = NEW FLAG_ARGUMENT) ||
+ !(f1440 = NEW FLAG_ARGUMENT) ||
+ !(f1440k = NEW FLAG_ARGUMENT) ||
+ !(f1440kb = NEW FLAG_ARGUMENT) ||
+ !(f144 = NEW FLAG_ARGUMENT) ||
+ !(f144m = NEW FLAG_ARGUMENT) ||
+ !(f144mb = NEW FLAG_ARGUMENT) ||
+ !(f2880 = NEW FLAG_ARGUMENT) ||
+ !(f2880k = NEW FLAG_ARGUMENT) ||
+ !(f2880kb = NEW FLAG_ARGUMENT) ||
+ !(f288 = NEW FLAG_ARGUMENT) ||
+ !(f288m = NEW FLAG_ARGUMENT) ||
+ !(f288mb = NEW FLAG_ARGUMENT) ||
+ !(f208 = NEW FLAG_ARGUMENT)) {
+
+ *ErrorLevel = 4;
+ return FALSE;
+ }
+
+
+ if (!lex_array.Initialize() ||
+ !arg_array.Initialize() ||
+ !arglex.Initialize(&lex_array)) {
+
+ *ErrorLevel = 4;
+ return FALSE;
+ }
+
+ arglex.SetCaseSensitive(FALSE);
+
+ if (!arglex.PrepareToParse()) {
+
+ *ErrorLevel = 4;
+ return FALSE;
+ }
+
+
+
+ if (!(f208m = NEW FLAG_ARGUMENT) ||
+ !(f208mb = NEW FLAG_ARGUMENT) ||
+ !(cs512 = NEW FLAG_ARGUMENT) ||
+ !(cs1024 = NEW FLAG_ARGUMENT) ||
+ !(cs2048 = NEW FLAG_ARGUMENT) ||
+ !(cs4096 = NEW FLAG_ARGUMENT) ||
+ !(cs8192 = NEW FLAG_ARGUMENT) ||
+ !(cs16k = NEW FLAG_ARGUMENT) ||
+ !(cs32k = NEW FLAG_ARGUMENT) ||
+ !(cs64k = NEW FLAG_ARGUMENT) ||
+ !(cs128k = NEW FLAG_ARGUMENT) ||
+ !(cs256k = NEW FLAG_ARGUMENT) ||
+ !(one = NEW FLAG_ARGUMENT) ||
+ !(four = NEW FLAG_ARGUMENT) ||
+ !(eight = NEW FLAG_ARGUMENT) ||
+ !(secpertrack = NEW LONG_ARGUMENT) ||
+ !(numtracks = NEW LONG_ARGUMENT) ||
+ !(arg_fs_name = NEW STRING_ARGUMENT) ||
+ !(helparg = NEW FLAG_ARGUMENT)) {
+
+ *ErrorLevel = 4;
+ return FALSE;
+ }
+
+
+ if (!lex_array.Initialize() ||
+ !arg_array.Initialize() ||
+ !arglex.Initialize(&lex_array)) {
+
+ *ErrorLevel = 4;
+ return FALSE;
+ }
+
+ arglex.SetCaseSensitive(FALSE);
+
+ if (!arglex.PrepareToParse()) {
+
+ *ErrorLevel = 4;
+ return FALSE;
+ }
+
+
+#if defined(JAPAN) && defined(_X86_)
+// FMR Jul.13.1994 SFT KMR
+// FMR is surpport 640KB&2HD, non surpport 2D Media.
+// NT format is compatible for DOS format.
+ if ( IsFMR_N() ) {
+ if (!progname->Initialize("*") ||
+ !dummyv->Initialize("/v") ||
+ !dummyu->Initialize("/u") ||
+ !drive->Initialize("*:") ||
+ !quick->Initialize("/q") ||
+ !compress->Initialize("/c") ||
+ !force->Initialize("/force") ||
+ !null_label->Initialize("/v:\"\"") ||
+ !label->Initialize("/v:*") ||
+ !no_prompts->Initialize("/backup") ||
+// FMR Delete the /F:160,180,320 and 360 process from the ParseArguments()
+// !f160->Initialize("/f:160") ||
+// !f160k->Initialize("/f:160K") ||
+// !f160kb->Initialize("/f:160KB") ||
+// !f180->Initialize("/f:180") ||
+// !f180k->Initialize("/f:180K") ||
+// !f180kb->Initialize("/f:180KB") ||
+// !f320->Initialize("/f:320") ||
+// !f320k->Initialize("/f:320K") ||
+// !f320kb->Initialize("/f:320KB") ||
+// !f360->Initialize("/f:360") ||
+// !f360k->Initialize("/f:360K") ||
+// !f360kb->Initialize("/f:360KB") ||
+// Add the 640KB_check on to the ParseArguments()
+ !f640->Initialize("/f:640") ||
+ !f640k->Initialize("/f:640K") ||
+ !f640kb->Initialize("/f:640KB") ||
+ !f720->Initialize("/f:720") ||
+ !f720k->Initialize("/f:720K") ||
+ !f720kb->Initialize("/f:720KB") ||
+ !f1200->Initialize("/f:1200") ||
+ !f1200k->Initialize("/f:1200K") ||
+ !f1200kb->Initialize("/f:1200KB") ||
+// Add the 2HD_check on to the ParseArguments()
+ !f1232->Initialize("/f:1232") ||
+ !f1232k->Initialize("/f:1232K") ||
+ !f1232kb->Initialize("/f:1232KB") ||
+ !f12->Initialize("/f:1.2") ||
+ !f12m->Initialize("/f:1.2M") ||
+ !f12mb->Initialize("/f:1.2MB") ||
+// Add the 2HD_check on to the ParseArguments()
+ !f123->Initialize("/f:1.23") ||
+ !f123m->Initialize("/f:1.23M") ||
+ !f123mb->Initialize("/f:1.23MB") ||
+ !f1440->Initialize("/f:1440") ||
+ !f1440k->Initialize("/f:1440K") ||
+ !f1440kb->Initialize("/f:1440KB") ||
+ !f144->Initialize("/f:1.44") ||
+ !f144m->Initialize("/f:1.44M") ||
+ !f144mb->Initialize("/f:1.44MB") ||
+ !f2880->Initialize("/f:2880") ||
+ !f2880k->Initialize("/f:2880K") ||
+ !f2880kb->Initialize("/f:2880KB") ||
+ !f288->Initialize("/f:2.88") ||
+ !f288m->Initialize("/f:2.88M") ||
+ !f288mb->Initialize("/f:2.88MB") ||
+ !f208->Initialize("/f:20.8") ||
+ !f208m->Initialize("/f:20.8M") ||
+ !f208mb->Initialize("/f:20.8MB") ||
+ !cs512->Initialize("/a:512") ||
+ !cs1024->Initialize("/a:1024") ||
+ !cs2048->Initialize("/a:2048") ||
+ !cs4096->Initialize("/a:4096") ||
+ !cs8192->Initialize("/a:8192") ||
+ !cs16k->Initialize("/a:16k") ||
+ !cs32k->Initialize("/a:32k") ||
+ !cs64k->Initialize("/a:64k") ||
+ !cs128k->Initialize("/a:128k") ||
+ !cs256k->Initialize("/a:256k") ||
+ !one->Initialize("/1") ||
+ !four->Initialize("/4") ||
+ !eight->Initialize("/8") ||
+ !secpertrack->Initialize("/n:*") ||
+ !numtracks->Initialize("/t:*") ||
+ !arg_fs_name->Initialize("/fs:*") ||
+ !helparg->Initialize("/?")) {
+
+ *ErrorLevel = 4;
+ return FALSE;
+ }
+ }
+ else
+#endif
+#if defined(JAPAN) && defined(_X86_) && defined(_PC98_)
+//*******1993/08/03 haga*********************************
+ if(IsPC98_N()){
+ if (!progname->Initialize("*") ||
+ !dummyv->Initialize("/v") ||
+ !dummyu->Initialize("/u") ||
+ !drive->Initialize("*:") ||
+ !quick->Initialize("/q") ||
+ !compress->Initialize("/c") ||
+ !force->Initialize("/force") ||
+ !null_label->Initialize("/v:\"\"") ||
+ !label->Initialize("/v:*") ||
+ !no_prompts->Initialize("/backup") ||
+ !f160->Initialize("/f:160") ||
+ !f160k->Initialize("/f:160K") ||
+ !f160kb->Initialize("/f:160KB") ||
+ !f180->Initialize("/f:180") ||
+ !f180k->Initialize("/f:180K") ||
+ !f180kb->Initialize("/f:180KB") ||
+ !f256->Initialize("/f:256") ||
+ !f256k->Initialize("/f:256K") ||
+ !f256kb->Initialize("/f:256KB") ||
+ !f320->Initialize("/f:320") ||
+ !f320k->Initialize("/f:320K") ||
+ !f320kb->Initialize("/f:320KB") ||
+ !f360->Initialize("/f:360") ||
+ !f360k->Initialize("/f:360K") ||
+ !f360kb->Initialize("/f:360KB") ||
+ !f640->Initialize("/f:640") ||
+ !f640k->Initialize("/f:640K") ||
+ !f640kb->Initialize("/f:640KB") ||
+ !f720->Initialize("/f:720") ||
+ !f720k->Initialize("/f:720K") ||
+ !f720kb->Initialize("/f:720KB") ||
+ !f1200->Initialize("/f:1200") ||
+ !f1200k->Initialize("/f:1200K") ||
+ !f1200kb->Initialize("/f:1200KB") ||
+ !f12->Initialize("/f:1.2") ||
+ !f12m->Initialize("/f:1.2M") ||
+ !f12mb->Initialize("/f:1.2MB") ||
+ !f1250->Initialize("/f:1250") ||
+ !f1250k->Initialize("/f:1250K") ||
+ !f1250kb->Initialize("/f:1250KB") ||
+ !f125->Initialize("/f:1.25") ||
+ !f125m->Initialize("/f:1.25M") ||
+ !f125mb->Initialize("/f:1.25MB") ||
+ !f1->Initialize("/f:1") ||
+ !f1m->Initialize("/f:1M") ||
+ !f1mb->Initialize("/f:1MB") ||
+ !f1440->Initialize("/f:1440") ||
+ !f1440k->Initialize("/f:1440K") ||
+ !f1440kb->Initialize("/f:1440KB") ||
+ !f144->Initialize("/f:1.44") ||
+ !f144m->Initialize("/f:1.44M") ||
+ !f144mb->Initialize("/f:1.44MB") ||
+ !f2880->Initialize("/f:2880") ||
+ !f2880k->Initialize("/f:2880K") ||
+ !f2880kb->Initialize("/f:2880KB") ||
+ !f288->Initialize("/f:2.88") ||
+ !f288m->Initialize("/f:2.88M") ||
+ !f288mb->Initialize("/f:2.88MB") ||
+ !f208->Initialize("/f:20.8") ||
+ !f208m->Initialize("/f:20.8M") ||
+ !f208mb->Initialize("/f:20.8MB") ||
+ !cs512->Initialize("/a:512") ||
+ !cs1024->Initialize("/a:1024") ||
+ !cs2048->Initialize("/a:2048") ||
+ !cs4096->Initialize("/a:4096") ||
+ !cs8192->Initialize("/a:8192") ||
+ !cs16k->Initialize("/a:16k") ||
+ !cs32k->Initialize("/a:32k") ||
+ !cs64k->Initialize("/a:64k") ||
+ !cs128k->Initialize("/a:128k") ||
+ !cs256k->Initialize("/a:256k") ||
+ !one->Initialize("/1") ||
+ !four->Initialize("/4") ||
+ !eight->Initialize("/8") ||
+ !secpertrack->Initialize("/n:*") ||
+ !numtracks->Initialize("/t:*") ||
+ !arg_fs_name->Initialize("/fs:*") ||
+ !helparg->Initialize("/?")) {
+
+ *ErrorLevel = 4;
+ return FALSE;
+ }
+ }else
+#endif // _PC98_
+ if (!progname->Initialize("*") ||
+ !dummyv->Initialize("/v") ||
+ !dummyu->Initialize("/u") ||
+ !drive->Initialize("*:") ||
+ !quick->Initialize("/q") ||
+ !compress->Initialize("/c") ||
+ !force->Initialize("/force") ||
+ !null_label->Initialize("/v:\"\"") ||
+ !label->Initialize("/v:*") ||
+ !no_prompts->Initialize("/backup") ||
+ !f160->Initialize("/f:160") ||
+ !f160k->Initialize("/f:160K") ||
+ !f160kb->Initialize("/f:160KB") ||
+ !f180->Initialize("/f:180") ||
+ !f180k->Initialize("/f:180K") ||
+ !f180kb->Initialize("/f:180KB") ||
+ !f320->Initialize("/f:320") ||
+ !f320k->Initialize("/f:320K") ||
+ !f320kb->Initialize("/f:320KB") ||
+ !f360->Initialize("/f:360") ||
+ !f360k->Initialize("/f:360K") ||
+ !f360kb->Initialize("/f:360KB") ||
+#if defined(JAPAN) && defined(_X86_)
+// FMR Jul.13.1994 SFT KMR
+// FMR is surpport 640KB&2HD, non surpport 2D Media.
+// NT format is compatible for DOS format.
+ !f640->Initialize("/f:640") ||
+ !f640k->Initialize("/f:640K") ||
+ !f640kb->Initialize("/f:640KB") ||
+ !f1232->Initialize("/f:1232") ||
+ !f1232k->Initialize("/f:1232K") ||
+ !f1232kb->Initialize("/f:1232KB") ||
+ !f123->Initialize("/f:1.23") ||
+ !f123m->Initialize("/f:1.23M") ||
+ !f123mb->Initialize("/f:1.23MB") ||
+#endif
+ !f720->Initialize("/f:720") ||
+ !f720k->Initialize("/f:720K") ||
+ !f720kb->Initialize("/f:720KB") ||
+ !f1200->Initialize("/f:1200") ||
+ !f1200k->Initialize("/f:1200K") ||
+ !f1200kb->Initialize("/f:1200KB") ||
+ !f12->Initialize("/f:1.2") ||
+ !f12m->Initialize("/f:1.2M") ||
+ !f12mb->Initialize("/f:1.2MB") ||
+ !f1440->Initialize("/f:1440") ||
+ !f1440k->Initialize("/f:1440K") ||
+ !f1440kb->Initialize("/f:1440KB") ||
+ !f144->Initialize("/f:1.44") ||
+ !f144m->Initialize("/f:1.44M") ||
+ !f144mb->Initialize("/f:1.44MB") ||
+ !f2880->Initialize("/f:2880") ||
+ !f2880k->Initialize("/f:2880K") ||
+ !f2880kb->Initialize("/f:2880KB") ||
+ !f288->Initialize("/f:2.88") ||
+ !f288m->Initialize("/f:2.88M") ||
+ !f288mb->Initialize("/f:2.88MB") ||
+ !f208->Initialize("/f:20.8") ||
+ !f208m->Initialize("/f:20.8M") ||
+ !f208mb->Initialize("/f:20.8MB") ||
+ !cs512->Initialize("/a:512") ||
+ !cs1024->Initialize("/a:1024") ||
+ !cs2048->Initialize("/a:2048") ||
+ !cs4096->Initialize("/a:4096") ||
+ !cs8192->Initialize("/a:8192") ||
+ !cs16k->Initialize("/a:16k") ||
+ !cs32k->Initialize("/a:32k") ||
+ !cs64k->Initialize("/a:64k") ||
+ !cs128k->Initialize("/a:128k") ||
+ !cs256k->Initialize("/a:256k") ||
+ !one->Initialize("/1") ||
+ !four->Initialize("/4") ||
+ !eight->Initialize("/8") ||
+ !secpertrack->Initialize("/n:*") ||
+ !numtracks->Initialize("/t:*") ||
+ !arg_fs_name->Initialize("/fs:*") ||
+ !helparg->Initialize("/?")) {
+
+ *ErrorLevel = 4;
+ return FALSE;
+ }
+
+#if defined(JAPAN) && defined(_X86_)
+// FMR Jul.13.1994 SFT KMR
+// NT format is compatible for DOS format.
+ if ( IsFMR_N() ) {
+ if (!arg_array.Put(progname) ||
+ !arg_array.Put(dummyv) ||
+ !arg_array.Put(dummyu) ||
+ !arg_array.Put(drive) ||
+ !arg_array.Put(quick) ||
+ !arg_array.Put(compress) ||
+ !arg_array.Put(force) ||
+ !arg_array.Put(null_label) ||
+ !arg_array.Put(label) ||
+ !arg_array.Put(no_prompts) ||
+// Delete the /F:160,180,320 and 360 process from the ParseArguments()
+// !arg_array.Put(f160) ||
+// !arg_array.Put(f160k) ||
+// !arg_array.Put(f160kb) ||
+// !arg_array.Put(f180) ||
+// !arg_array.Put(f180k) ||
+// !arg_array.Put(f180kb) ||
+// !arg_array.Put(f320) ||
+// !arg_array.Put(f320k) ||
+// !arg_array.Put(f320kb) ||
+// !arg_array.Put(f360) ||
+// !arg_array.Put(f360k) ||
+// !arg_array.Put(f360kb) ||
+// Add the 640KB_check on to the ParseArguments()
+ !arg_array.Put(f640) ||
+ !arg_array.Put(f640k) ||
+ !arg_array.Put(f640kb) ||
+ !arg_array.Put(f720) ||
+ !arg_array.Put(f720k) ||
+ !arg_array.Put(f720kb) ||
+ !arg_array.Put(f1200) ||
+ !arg_array.Put(f1200k) ||
+ !arg_array.Put(f1200kb) ||
+ !arg_array.Put(f12) ||
+ !arg_array.Put(f12m) ||
+ !arg_array.Put(f12mb) ||
+// Add the 2HD_check on to the ParseArguments()
+ !arg_array.Put(f1232) ||
+ !arg_array.Put(f1232k) ||
+ !arg_array.Put(f1232kb) ||
+ !arg_array.Put(f123) ||
+ !arg_array.Put(f123m) ||
+ !arg_array.Put(f123mb) ||
+// Add the 2HD_check on to the ParseArguments()
+ !arg_array.Put(f1440) ||
+ !arg_array.Put(f1440k) ||
+ !arg_array.Put(f1440kb) ||
+ !arg_array.Put(f144) ||
+ !arg_array.Put(f144m) ||
+ !arg_array.Put(f144mb) ||
+ !arg_array.Put(f2880) ||
+ !arg_array.Put(f2880k) ||
+ !arg_array.Put(f2880kb) ||
+ !arg_array.Put(f288) ||
+ !arg_array.Put(f288m) ||
+ !arg_array.Put(f288mb) ||
+ !arg_array.Put(f208) ||
+ !arg_array.Put(f208m) ||
+ !arg_array.Put(f208mb) ||
+ !arg_array.Put(cs512) ||
+ !arg_array.Put(cs1024) ||
+ !arg_array.Put(cs2048) ||
+ !arg_array.Put(cs4096) ||
+ !arg_array.Put(cs8192) ||
+ !arg_array.Put(cs16k) ||
+ !arg_array.Put(cs32k) ||
+ !arg_array.Put(cs64k) ||
+ !arg_array.Put(cs128k) ||
+ !arg_array.Put(cs256k) ||
+ !arg_array.Put(one) ||
+ !arg_array.Put(four) ||
+ !arg_array.Put(eight) ||
+ !arg_array.Put(secpertrack) ||
+ !arg_array.Put(numtracks) ||
+ !arg_array.Put(arg_fs_name) ||
+ !arg_array.Put(helparg)) {
+
+ *ErrorLevel = 4;
+ return FALSE;
+ }
+ }
+ else
+#endif
+#if defined(JAPAN) && defined(_X86_) && defined(_PC98_)
+ if(IsPC98_N()) {
+ if (!arg_array.Put(progname) ||
+ !arg_array.Put(dummyv) ||
+ !arg_array.Put(dummyu) ||
+ !arg_array.Put(drive) ||
+ !arg_array.Put(quick) ||
+ !arg_array.Put(compress) ||
+ !arg_array.Put(force) ||
+ !arg_array.Put(null_label) ||
+ !arg_array.Put(label) ||
+ !arg_array.Put(no_prompts) ||
+ !arg_array.Put(f160) ||
+ !arg_array.Put(f160k) ||
+ !arg_array.Put(f160kb) ||
+ !arg_array.Put(f180) ||
+ !arg_array.Put(f180k) ||
+ !arg_array.Put(f180kb) ||
+ !arg_array.Put(f256) ||
+ !arg_array.Put(f256k) ||
+ !arg_array.Put(f256kb) ||
+ !arg_array.Put(f320) ||
+ !arg_array.Put(f320k) ||
+ !arg_array.Put(f320kb) ||
+ !arg_array.Put(f360) ||
+ !arg_array.Put(f360k) ||
+ !arg_array.Put(f360kb) ||
+ !arg_array.Put(f640) ||
+ !arg_array.Put(f640k) ||
+ !arg_array.Put(f640kb) ||
+ !arg_array.Put(f1232) ||
+ !arg_array.Put(f1232k) ||
+ !arg_array.Put(f1232kb) ||
+ !arg_array.Put(f123) ||
+ !arg_array.Put(f123m) ||
+ !arg_array.Put(f123mb) ||
+ !arg_array.Put(f720) ||
+ !arg_array.Put(f720k) ||
+ !arg_array.Put(f720kb) ||
+ !arg_array.Put(f1200) ||
+ !arg_array.Put(f1200k) ||
+ !arg_array.Put(f1200kb) ||
+ !arg_array.Put(f12) ||
+ !arg_array.Put(f12m) ||
+ !arg_array.Put(f12mb) ||
+ !arg_array.Put(f1250) ||
+ !arg_array.Put(f1250k) ||
+ !arg_array.Put(f1250kb) ||
+ !arg_array.Put(f125) ||
+ !arg_array.Put(f125m) ||
+ !arg_array.Put(f125mb) ||
+ !arg_array.Put(f1) ||
+ !arg_array.Put(f1m) ||
+ !arg_array.Put(f1mb) ||
+ !arg_array.Put(f1440) ||
+ !arg_array.Put(f1440k) ||
+ !arg_array.Put(f1440kb) ||
+ !arg_array.Put(f144) ||
+ !arg_array.Put(f144m) ||
+ !arg_array.Put(f144mb) ||
+ !arg_array.Put(f2880) ||
+ !arg_array.Put(f2880k) ||
+ !arg_array.Put(f2880kb) ||
+ !arg_array.Put(f288) ||
+ !arg_array.Put(f288m) ||
+ !arg_array.Put(f288mb) ||
+ !arg_array.Put(f208) ||
+ !arg_array.Put(f208m) ||
+ !arg_array.Put(f208mb) ||
+ !arg_array.Put(cs512) ||
+ !arg_array.Put(cs1024) ||
+ !arg_array.Put(cs2048) ||
+ !arg_array.Put(cs4096) ||
+ !arg_array.Put(cs8192) ||
+ !arg_array.Put(cs16k) ||
+ !arg_array.Put(cs32k) ||
+ !arg_array.Put(cs64k) ||
+ !arg_array.Put(cs128k) ||
+ !arg_array.Put(cs256k) ||
+ !arg_array.Put(one) ||
+ !arg_array.Put(four) ||
+ !arg_array.Put(eight) ||
+ !arg_array.Put(secpertrack) ||
+ !arg_array.Put(numtracks) ||
+ !arg_array.Put(arg_fs_name) ||
+ !arg_array.Put(helparg)) {
+
+ *ErrorLevel = 4;
+ return FALSE;
+ }
+ } else
+#endif // _PC98_
+ if (!arg_array.Put(progname) ||
+ !arg_array.Put(dummyv) ||
+ !arg_array.Put(dummyu) ||
+ !arg_array.Put(drive) ||
+ !arg_array.Put(quick) ||
+ !arg_array.Put(compress) ||
+ !arg_array.Put(force) ||
+ !arg_array.Put(null_label) ||
+ !arg_array.Put(label) ||
+ !arg_array.Put(no_prompts) ||
+ !arg_array.Put(f160) ||
+ !arg_array.Put(f160k) ||
+ !arg_array.Put(f160kb) ||
+ !arg_array.Put(f180) ||
+ !arg_array.Put(f180k) ||
+ !arg_array.Put(f180kb) ||
+ !arg_array.Put(f320) ||
+ !arg_array.Put(f320k) ||
+ !arg_array.Put(f320kb) ||
+ !arg_array.Put(f360) ||
+ !arg_array.Put(f360k) ||
+ !arg_array.Put(f360kb) ||
+#if defined(JAPAN) && defined(_X86_)
+// FMR Jul.13.1994 SFT KMR
+// NT format is compatible for DOS format.
+// Add the 640KB_check on to the ParseArguments()
+ !arg_array.Put(f640) ||
+ !arg_array.Put(f640k) ||
+ !arg_array.Put(f640kb) ||
+ !arg_array.Put(f1232) ||
+ !arg_array.Put(f1232k) ||
+ !arg_array.Put(f1232kb) ||
+ !arg_array.Put(f123) ||
+ !arg_array.Put(f123m) ||
+ !arg_array.Put(f123mb) ||
+#endif // JAPAN && _X86_
+ !arg_array.Put(f720) ||
+ !arg_array.Put(f720k) ||
+ !arg_array.Put(f720kb) ||
+ !arg_array.Put(f1200) ||
+ !arg_array.Put(f1200k) ||
+ !arg_array.Put(f1200kb) ||
+ !arg_array.Put(f12) ||
+ !arg_array.Put(f12m) ||
+ !arg_array.Put(f12mb) ||
+ !arg_array.Put(f1440) ||
+ !arg_array.Put(f1440k) ||
+ !arg_array.Put(f1440kb) ||
+ !arg_array.Put(f144) ||
+ !arg_array.Put(f144m) ||
+ !arg_array.Put(f144mb) ||
+ !arg_array.Put(f2880) ||
+ !arg_array.Put(f2880k) ||
+ !arg_array.Put(f2880kb) ||
+ !arg_array.Put(f288) ||
+ !arg_array.Put(f288m) ||
+ !arg_array.Put(f288mb) ||
+ !arg_array.Put(f208) ||
+ !arg_array.Put(f208m) ||
+ !arg_array.Put(f208mb) ||
+ !arg_array.Put(cs512) ||
+ !arg_array.Put(cs1024) ||
+ !arg_array.Put(cs2048) ||
+ !arg_array.Put(cs4096) ||
+ !arg_array.Put(cs8192) ||
+ !arg_array.Put(cs16k) ||
+ !arg_array.Put(cs32k) ||
+ !arg_array.Put(cs64k) ||
+ !arg_array.Put(cs128k) ||
+ !arg_array.Put(cs256k) ||
+ !arg_array.Put(one) ||
+ !arg_array.Put(four) ||
+ !arg_array.Put(eight) ||
+ !arg_array.Put(secpertrack) ||
+ !arg_array.Put(numtracks) ||
+ !arg_array.Put(arg_fs_name) ||
+ !arg_array.Put(helparg)) {
+
+ *ErrorLevel = 4;
+ return FALSE;
+ }
+
+
+
+ if (!arglex.DoParsing(&arg_array)) {
+
+ Message->Set(MSG_INVALID_PARAMETER);
+ Message->Display("%W", pwstring = arglex.QueryInvalidArgument());
+ DELETE(pwstring);
+ arg_array.DeleteAllMembers();
+
+ *ErrorLevel = 4;
+ return FALSE;
+ }
+
+ if (helparg->QueryFlag()) {
+
+ DisplayFormatUsage(Message);
+ arg_array.DeleteAllMembers();
+
+ *ErrorLevel = 0;
+ return FALSE;
+ }
+
+
+ if (!drive->IsValueSet()) {
+
+ Message->Set(MSG_REQUIRED_PARAMETER);
+ Message->Display("");
+ arg_array.DeleteAllMembers();
+
+ *ErrorLevel = 1;
+ return FALSE;
+ }
+
+ if (!DosDriveName->Initialize(drive->GetString()) ||
+ !tmp_string.Initialize(":") ||
+ !DosDriveName->Strcat(&tmp_string) ||
+ !DosDriveName->Strupr()) {
+
+ *ErrorLevel = 1;
+ arg_array.DeleteAllMembers();
+ return FALSE;
+ }
+
+ if (label->IsValueSet() && null_label->QueryFlag()) {
+
+ Message->Set(MSG_INVALID_PARAMETER);
+ Message->Display("%s", "/v:\"\"");
+
+ *ErrorLevel = 4;
+ arg_array.DeleteAllMembers();
+ return FALSE;
+ }
+
+ *IsLabelSpeced = label->IsValueSet() || null_label->QueryFlag();
+
+ if (label->IsValueSet()) {
+
+ if (!Label->Initialize(label->GetString())) {
+
+ *ErrorLevel = 4;
+ arg_array.DeleteAllMembers();
+ return FALSE;
+ }
+
+ } else {
+
+ if (!Label->Initialize("")) {
+
+ *ErrorLevel = 4;
+ arg_array.DeleteAllMembers();
+ return FALSE;
+ }
+ }
+
+
+ if (arg_fs_name->IsValueSet()) {
+
+ if (!FileSystemName->Initialize(arg_fs_name->GetString()) ||
+ !FileSystemName->Strupr()) {
+
+ *ErrorLevel = 4;
+ arg_array.DeleteAllMembers();
+ return FALSE;
+ }
+
+ } else {
+
+ if (!FileSystemName->Initialize("")) {
+
+ *ErrorLevel = 4;
+ arg_array.DeleteAllMembers();
+ return FALSE;
+ }
+
+ }
+
+
+ *NoPrompts = no_prompts->QueryFlag();
+ *QuickFormat = quick->QueryFlag();
+ *ForceMode = force->QueryFlag();
+
+ *Compress = compress->QueryFlag();
+
+ if (label->IsValueSet()) {
+ if (eight->QueryFlag()) {
+
+ Message->Set(MSG_NO_LABEL_WITH_8);
+ Message->Display("");
+
+ *ErrorLevel = 1;
+ arg_array.DeleteAllMembers();
+ return FALSE;
+ }
+ }
+
+ v = 0;
+ *ClusterSize = 0;
+
+ if (cs512->QueryFlag()) {
+ *ClusterSize = 512;
+ v++;
+ }
+
+ if (cs1024->QueryFlag()) {
+ *ClusterSize = 1024;
+ v++;
+ }
+
+ if (cs2048->QueryFlag()) {
+ *ClusterSize = 2048;
+ v++;
+ }
+
+ if (cs4096->QueryFlag()) {
+ *ClusterSize = 4096;
+ v++;
+ }
+
+ if (cs8192->QueryFlag()) {
+ *ClusterSize = 8192;
+ v++;
+ }
+
+ if (cs16k->QueryFlag()) {
+ *ClusterSize = 16*1024;
+ v++;
+ }
+
+ if (cs32k->QueryFlag()) {
+ *ClusterSize = 32*1024;
+ v++;
+ }
+
+ if (cs64k->QueryFlag()) {
+ *ClusterSize = 64*1024;
+ v++;
+ }
+
+ if (cs128k->QueryFlag()) {
+ *ClusterSize = 128*1024;
+ v++;
+ }
+
+ if (cs256k->QueryFlag()) {
+ *ClusterSize = 256*1024;
+ v++;
+ }
+
+ if (v > 1) {
+ Message->Set(MSG_INCOMPATIBLE_PARAMETERS);
+ Message->Display();
+
+ *ErrorLevel = 4;
+ arg_array.DeleteAllMembers();
+ return FALSE;
+ }
+
+
+ // -----------------------
+ // Compute the media type.
+ // -----------------------
+
+#if defined(JAPAN) && defined(_X86_)
+// FMR Jul.13.1994 SFT KMR
+// When /T:80 and /N:8, modify the process to be 640KB's
+// Delete the /F:160,180,320 and 360 process from the ParseArguments()
+// Not surported media 2D.
+// NT format is compatible for DOS format.
+ if ( IsFMR_N() ) {
+ req160 = FALSE;
+ req180 = FALSE;
+ req320 = FALSE;
+ req360 = FALSE;
+ }
+ else {
+#endif // JAPAN && _X86_
+ req160 = f160->QueryFlag() || f160k->QueryFlag() || f160kb->QueryFlag();
+ req180 = f180->QueryFlag() || f180k->QueryFlag() || f180kb->QueryFlag();
+ req320 = f320->QueryFlag() || f320k->QueryFlag() || f320kb->QueryFlag();
+ req360 = f360->QueryFlag() || f360k->QueryFlag() || f360kb->QueryFlag();
+#if defined(JAPAN) && defined(_X86_) && defined(_PC98_)
+//*******1993/08/03 haga*********************************
+ req256 = f256->QueryFlag() || f256k->QueryFlag() || f256kb->QueryFlag();
+#endif // _PC98_
+#if defined(JAPAN) && defined(_X86_)
+ }
+#endif // JAPAN && _X86_
+ req720 = f720->QueryFlag() || f720k->QueryFlag() || f720kb->QueryFlag();
+ req1200 = f1200->QueryFlag() || f1200k->QueryFlag() || f1200kb->QueryFlag() ||
+ f12->QueryFlag() || f12m->QueryFlag() || f12mb->QueryFlag();
+ req1440 = f1440->QueryFlag() || f1440k->QueryFlag() || f1440kb->QueryFlag() ||
+ f144->QueryFlag() || f144m->QueryFlag() || f144mb->QueryFlag();
+ req2880 = f2880->QueryFlag() || f2880k->QueryFlag() || f2880kb->QueryFlag() ||
+ f288->QueryFlag() || f288m->QueryFlag() || f288mb->QueryFlag();
+ req20800 = f208->QueryFlag() || f208m->QueryFlag() || f208mb->QueryFlag();
+#if defined(JAPAN) && defined(_X86_)
+// FMR Jul.12.1994 SFT KMR
+// Add the 640KB_check on to the ParseArguments()
+ req640 = f640->QueryFlag() || f640k->QueryFlag() || f640kb->QueryFlag();
+#if defined(_PC98_)
+//*******1993/08/03 haga*********************************
+ req1232 = f1250->QueryFlag() || f1250k->QueryFlag() || f1250kb->QueryFlag() ||
+ f125->QueryFlag() || f125m->QueryFlag() || f125mb->QueryFlag() ||
+ f1->QueryFlag() || f1m->QueryFlag() || f1mb->QueryFlag();
+#else // !_PC98_
+ req1232 = f1232->QueryFlag() || f1232k->QueryFlag() || f1232kb->QueryFlag() ||
+ f123->QueryFlag() || f123m->QueryFlag() || f123mb->QueryFlag();
+#endif // _PC98_
+#endif // JAPAN && _X86_
+
+
+
+ if (one->QueryFlag() && four->QueryFlag() && !eight->QueryFlag()) {
+
+ req180 = TRUE;
+
+ } else if (one->QueryFlag() && !four->QueryFlag() && eight->QueryFlag()) {
+
+ req160 = TRUE;
+
+ } else if (!one->QueryFlag() && four->QueryFlag() && !eight->QueryFlag()) {
+
+ req360 = TRUE;
+
+ } else if (!one->QueryFlag() && !four->QueryFlag() && eight->QueryFlag()) {
+
+ req320 = TRUE;
+
+ } else if (!one->QueryFlag() && !four->QueryFlag() && !eight->QueryFlag()) {
+ } else {
+ Message->Set(MSG_INCOMPATIBLE_PARAMETERS);
+ Message->Display("");
+ *ErrorLevel = 1;
+ arg_array.DeleteAllMembers();
+ return FALSE;
+ }
+
+ if (secpertrack->IsValueSet() && numtracks->IsValueSet()) {
+ if (secpertrack->QueryLong() == 8) {
+ if (numtracks->QueryLong() == 40) {
+
+ req320 = TRUE;
+
+#if defined(JAPAN) && defined(_X86_)
+// FMR Jul.12.1994 SFT KMR
+// When /T:77 and /N:8, modify the process to be 1.2MB's
+ }
+ else if ( numtracks->QueryLong() == 77) {
+ req1232 = TRUE;
+ }
+
+// FMR Jul.12.1994 SFT KMR
+// When /T:80 and /N:8, modify the process to be 640KB's
+ else if ( numtracks->QueryLong() == 80 ) {
+ req640 = TRUE;
+#endif
+ } else {
+ Message->Set(MSG_INCOMPATIBLE_PARAMETERS);
+ Message->Display("");
+ *ErrorLevel = 1;
+ arg_array.DeleteAllMembers();
+ return FALSE;
+ }
+ } else if (secpertrack->QueryLong() == 9) {
+ if (numtracks->QueryLong() == 40) {
+
+ req360 = TRUE;
+
+ } else if (numtracks->QueryLong() == 80) {
+
+ req720 = TRUE;
+
+ } else {
+ Message->Set(MSG_INCOMPATIBLE_PARAMETERS);
+ Message->Display("");
+ *ErrorLevel = 1;
+ arg_array.DeleteAllMembers();
+ return FALSE;
+ }
+ } else if (secpertrack->QueryLong() == 15) {
+ if (numtracks->QueryLong() == 80) {
+
+ req1200 = TRUE;
+
+ } else {
+ Message->Set(MSG_INCOMPATIBLE_PARAMETERS);
+ Message->Display("");
+ *ErrorLevel = 1;
+ arg_array.DeleteAllMembers();
+ return FALSE;
+ }
+ } else if (secpertrack->QueryLong() == 18) {
+ if (numtracks->QueryLong() == 80) {
+
+ req1440 = TRUE;
+
+ } else {
+ Message->Set(MSG_INCOMPATIBLE_PARAMETERS);
+ Message->Display("");
+ *ErrorLevel = 1;
+ arg_array.DeleteAllMembers();
+ return FALSE;
+ }
+ } else if (secpertrack->QueryLong() == 36) {
+ if (numtracks->QueryLong() == 80) {
+
+ req2880 = TRUE;
+
+ } else {
+ Message->Set(MSG_INCOMPATIBLE_PARAMETERS);
+ Message->Display("");
+ *ErrorLevel = 1;
+ arg_array.DeleteAllMembers();
+ return FALSE;
+ }
+#if defined(JAPAN) && defined(_X86_) && defined(_PC98_)
+// NEC98 '94.09.22 NES
+ } else if(IsPC98_N() && (secpertrack->QueryLong() == 26)) {
+ req256 = TRUE;
+ } else {
+#else // !_PC98_
+ } else {
+#endif // _PC98_
+ Message->Set(MSG_INCOMPATIBLE_PARAMETERS);
+ Message->Display("");
+ *ErrorLevel = 1;
+ arg_array.DeleteAllMembers();
+ return FALSE;
+ }
+ } else if (secpertrack->IsValueSet() || numtracks->IsValueSet()) {
+ Message->Set(MSG_NEED_BOTH_T_AND_N);
+ Message->Display("");
+ *ErrorLevel = 1;
+ arg_array.DeleteAllMembers();
+ return FALSE;
+ }
+
+ if (!DetermineMediaType(MediaType, Message, req160, req180, req320,
+ req360, req720, req1200, req1440, req2880,
+ req20800
+#if defined(JAPAN) && defined(_X86_)
+// FMR Jul.13.1994 SFT KMR
+// Add the 2HD and the 640KB_check on to the ParseArguments()
+ ,
+#if defined(_PC98_)
+// ***** 94.09.05 Hirata *****
+ req256,
+#endif // _PC98_
+ req640, req1232
+#endif // JAPAN && _X86_
+ )
+ ) {
+
+ *ErrorLevel = 1;
+ arg_array.DeleteAllMembers();
+ return FALSE;
+ }
+
+ // If the media type was specified then it's gotten by now.
+
+ arg_array.DeleteAllMembers();
+ return TRUE;
+}
diff --git a/private/utils/format/parse.hxx b/private/utils/format/parse.hxx
new file mode 100644
index 000000000..865c3df00
--- /dev/null
+++ b/private/utils/format/parse.hxx
@@ -0,0 +1,49 @@
+VOID
+DisplayFormatUsage(
+ IN OUT PMESSAGE Message
+ );
+
+
+BOOLEAN
+DetermineMediaType(
+ OUT PMEDIA_TYPE MediaType,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Request160,
+ IN BOOLEAN Request180,
+ IN BOOLEAN Request320,
+ IN BOOLEAN Request360,
+ IN BOOLEAN Request720,
+ IN BOOLEAN Request1200,
+ IN BOOLEAN Request1440,
+ IN BOOLEAN Request2880,
+ IN BOOLEAN Request20800
+#if defined (JAPAN) && defined (_X86_)
+// FMR Jul.12.1994 SFT KMR
+// Add the Request640 on to the parmeter of the DetermineMediaType()
+ ,
+#if defined(_PC98_)
+ IN BOOLEAN Request256,
+#endif // _PC98_
+ IN BOOLEAN Request640,
+// Add the Request1232 on to the parmeter of the DetermineMediaType()
+ IN BOOLEAN Request1232
+#endif // JAPAN && _X86_
+ );
+
+
+
+BOOLEAN
+ParseArguments(
+ IN OUT PMESSAGE Message,
+ OUT PMEDIA_TYPE MediaType,
+ OUT PWSTRING DosDriveName,
+ OUT PWSTRING Label,
+ OUT PBOOLEAN IsLabelSpeced,
+ OUT PWSTRING FileSystemName,
+ OUT PBOOLEAN QuickFormat,
+ OUT PBOOLEAN ForceMode,
+ OUT PULONG ClusterSize,
+ OUT PBOOLEAN Compress,
+ OUT PBOOLEAN NoPrompts,
+ OUT PINT ErrorLevel
+ );
diff --git a/private/utils/format/sources b/private/utils/format/sources
new file mode 100644
index 000000000..e90989cd7
--- /dev/null
+++ b/private/utils/format/sources
@@ -0,0 +1,62 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=utils
+MINORCOMP=format
+
+TARGETNAME=format
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=parse.cxx format.cxx format.rc
+
+INCLUDES=..\ulib\inc;..\ifsutil\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+UMLIBS= \
+ obj\*\format.lib \
+ ..\ulib\src\obj\*\ulib.lib \
+ ..\ifsutil\src\obj\*\ifsutil.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+
+UMTYPE=console
+UMAPPL=format
+UMAPPLEXT=.com
+
+UMRES=obj\*\format.res
diff --git a/private/utils/help/doshelp.hlp b/private/utils/help/doshelp.hlp
new file mode 100644
index 000000000..5440ee01d
--- /dev/null
+++ b/private/utils/help/doshelp.hlp
@@ -0,0 +1,88 @@
+@ Copyright (C) 1990-1991 Microsoft Corp. All rights reserved.
+@ This is the DOS general help file. It contains a brief
+@ description of each command supported by the DOS help command.
+@ Type HELP with no arguments to display the text in this file.
+@ Lines beginning with @ are comments, and are ignored by HELP.
+@ This file may be modified to add new commands. If the HELP command-name
+@ form is to be used, any new commands should support the /? parameter.
+@ New commands should start in the first column. Any extra lines needed
+@ for a command description should be preceded by white space. Commands
+@ must be added in alphabetical order.
+ASSOC Displays or modifies file extension associations
+AT Schedules commands and programs to run on a computer.
+ATTRIB Displays or changes file attributes.
+BREAK Sets or clears extended CTRL+C checking.
+CACLS Displays or modifies access control lists (ACLs) of files.
+CALL Calls one batch program from another.
+CD Displays the name of or changes the current directory.
+CHCP Displays or sets the active code page number.
+CHDIR Displays the name of or changes the current directory.
+CHKDSK Checks a disk and displays a status report.
+CLS Clears the screen.
+CMD Starts a new instance of the Windows NT command interpreter.
+COLOR Sets the default console foreground and background colors.
+COMP Compares the contents of two files or sets of files.
+COMPACT Displays or alters the compression of files on NTFS partitions.
+CONVERT Converts FAT volumes to NTFS. You cannot convert the
+ current drive.
+COPY Copies one or more files to another location.
+DATE Displays or sets the date.
+DEL Deletes one or more files.
+DIR Displays a list of files and subdirectories in a directory.
+DISKCOMP Compares the contents of two floppy disks.
+DISKCOPY Copies the contents of one floppy disk to another.
+DOSKEY Edits command lines, recalls Windows NT commands, and creates macros.
+ECHO Displays messages, or turns command echoing on or off.
+ENDLOCAL Ends localization of environment changes in a batch file.
+ERASE Deletes one or more files.
+EXIT Quits the CMD.EXE program (command interpreter).
+FC Compares two files or sets of files, and displays the differences
+ between them.
+FIND Searches for a text string in a file or files.
+FINDSTR Searches for strings in files.
+FOR Runs a specified command for each file in a set of files.
+FORMAT Formats a disk for use with Windows NT.
+FTYPE Displays or modifies file types used in file extension associations.
+GOTO Directs the Windows NT command interpreter to a labeled line in a
+ batch program.
+GRAFTABL Enables Windows NT to display an extended character set in graphics
+ mode.
+HELP Provides Help information for Windows NT commands.
+IF Performs conditional processing in batch programs.
+KEYB Configures a keyboard for a specific language.
+LABEL Creates, changes, or deletes the volume label of a disk.
+MD Creates a directory.
+MKDIR Creates a directory.
+MODE Configures a system device.
+MORE Displays output one screen at a time.
+MOVE Moves one or more files from one directory to another directory on
+ the same drive.
+PATH Displays or sets a search path for executable files.
+PAUSE Suspends processing of a batch file and displays a message.
+POPD Restores the previous value of the current directory saved by PUSHD.
+PRINT Prints a text file.
+PROMPT Changes the Windows NT command prompt.
+PUSHD Saves the current directory then changes it.
+RD Removes a directory.
+RECOVER Recovers readable information from a bad or defective disk.
+REM Records comments (remarks) in batch files or CONFIG.SYS.
+REN Renames a file or files.
+RENAME Renames a file or files.
+REPLACE Replaces files.
+RESTORE Restores files that were backed up by using the BACKUP command.
+RMDIR Removes a directory.
+SET Displays, sets, or removes Windows NT environment variables.
+SETLOCAL Begins localization of environment changes in a batch file.
+SHIFT Shifts the position of replaceable parameters in batch files.
+SORT Sorts input.
+START Starts a separate window to run a specified program or command.
+SUBST Associates a path with a drive letter.
+TIME Displays or sets the system time.
+TITLE Sets the window title for a CMD.EXE session.
+TREE Graphically displays the directory structure of a drive or path.
+TYPE Displays the contents of a text file.
+VER Displays the Windows NT version.
+VERIFY Tells Windows NT whether to verify that your files are written
+ correctly to a disk.
+VOL Displays a disk volume label and serial number.
+XCOPY Copies files and directory trees.
diff --git a/private/utils/help/help.cxx b/private/utils/help/help.cxx
new file mode 100644
index 000000000..c35c1d3f2
--- /dev/null
+++ b/private/utils/help/help.cxx
@@ -0,0 +1,732 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ Help.cxx
+
+Abstract:
+
+
+Author:
+
+ Barry J. Gilhuly *** W-Barry *** May 91
+
+Environment:
+
+ ULIB, User Mode
+
+Notes:
+
+ This program calls Win32 API's to modify the STDIN and STDOUT handles as
+ well as to spawn processes and create a pipe.
+
+--*/
+
+#include "ulib.hxx"
+#include "ulibcl.hxx"
+#include "error.hxx"
+#include "arg.hxx"
+#include "array.hxx"
+#include "dir.hxx"
+#include "file.hxx"
+#include "filestrm.hxx"
+#include "filter.hxx"
+#include "iterator.hxx"
+#include "keyboard.hxx"
+#include "path.hxx"
+#include "pipe.hxx"
+#include "rtmsg.h"
+#include "screen.hxx"
+#include "system.hxx"
+#include "smsg.hxx"
+#include "help.hxx"
+
+
+extern "C" {
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+}
+
+
+ERRSTACK *perrstk;
+STREAM_MESSAGE *psmsg; // Create a pointer to the stream message
+ // class for program output.
+USHORT Errlev; // The current program error level
+
+DEFINE_CONSTRUCTOR( HELP, PROGRAM );
+
+
+VOID
+HELP::Destruct(
+ )
+/*++
+
+Routine Description:
+
+ Cleans up after finishing with an FC object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ DELETE( perrstk );
+ DELETE( psmsg );
+
+ return;
+}
+
+BOOLEAN
+HELP::Initialize(
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes an FC object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the initialization succeeded.
+
+
+--*/
+
+
+{
+ ARGUMENT_LEXEMIZER ArgLex;
+ ARRAY LexArray;
+ ARRAY ArrayOfArg;
+
+ PATH_ARGUMENT ProgramName;
+ FLAG_ARGUMENT FlagRequestHelp;
+ DSTRING CommentString;
+
+ if( !LexArray.Initialize() ) {
+ KdPrint(( "LexArray.Initialize() Failed!\n" ));
+ }
+ if( !ArgLex.Initialize(&LexArray) ) {
+ KdPrint(( "ArgLex.Initialize() Failed!\n" ));
+ }
+
+ // Allow only the '/' as a valid switch
+ ArgLex.PutSwitches("/");
+ ArgLex.SetCaseSensitive( FALSE );
+
+ if( !ArgLex.PrepareToParse() ) {
+ KdPrint(( "ArgLex.PrepareToParse() Failed!\n" ));
+ }
+
+ if( !ProgramName.Initialize("*") ||
+ !FlagRequestHelp.Initialize("/?") ||
+ !_FileName.Initialize("*") ) {
+
+ KdPrint(( "Unable to Initialize some or all of the Arguments!\n" ));
+ return( FALSE );
+ }
+
+
+ if( !ArrayOfArg.Initialize() ) {
+ KdPrint(( "ArrayOfArg.Initialize() Failed\n" ));
+ }
+
+ if( !ArrayOfArg.Put(&ProgramName) ||
+ !ArrayOfArg.Put(&FlagRequestHelp) ||
+ !ArrayOfArg.Put(&_FileName) ) {
+
+ KdPrint(( "ArrayOfArg.Put() Failed!\n" ));
+
+ }
+
+
+ if( !( ArgLex.DoParsing( &ArrayOfArg ) ) ) {
+/*
+ * Ignore (for now) any unrecognized switches on the command line since
+ * that is what the Dos version does... However, it become advisable for
+ * HELP to advise the user that there were too many parameters on the
+ * command line... If this ever comes to pass, the TOO_MANY_PARAMETERS
+ * message must be added to the resource file.
+ *
+ PWSTRING InvalidArg;
+
+ KdPrint(( "HELP: invalid Switch(s)\n" ));
+ InvalidArg = ArgLex.QueryInvalidArgument();
+
+ psmsg->Set( MSG_HELP_TOO_MANY_PARAMETERS );
+ psmsg->Display( "%W", InvalidArg );
+
+ DELETE( InvalidArg );
+ return( FALSE );
+ *
+ */
+ }
+
+
+ // It should now be safe to test the arguments for their values...
+ if( FlagRequestHelp.QueryFlag() ) {
+
+ // Send help message
+ KdPrint(( "Help....\n" ));
+ psmsg->Set( MSG_HELP_HELP_MESSAGE );
+ psmsg->Display( "" );
+
+ return( FALSE );
+ }
+
+ //
+ // Set up the comment character
+ //
+ CommentString.Initialize( "" );
+ SYSTEM::QueryResourceString( &CommentString, MSG_HELP_HELP_COMMENT, "" );
+ _CommentChar = CommentString.QueryChAt( 0 );
+
+ LexArray.DeleteAllMembers();
+
+ return( TRUE );
+}
+
+VOID
+HELP::GetHelp(
+ )
+/*++
+
+Routine Description:
+
+ Decide which type of help to provide to the user.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+ There are two cases when the program gets here: Either the command
+ line was completely empty and the user therefore wants the entire
+ help file to be output, or help has been requested for as single
+ command.
+
+--*/
+{
+ PPATH pHelpPath;
+ DSTRING HelpName;
+ PFSN_FILE pHelpFile;
+
+ // Find the help file...
+ SYSTEM::QueryResourceString( &HelpName, MSG_HELP_HELP_FILE_NAME, "" );
+
+ if( ( pHelpPath = SYSTEM::SearchPath( &HelpName ) ) == NULL ) {
+ // Output unable to find helpfile...
+ KdPrint(( "Unable to find helpfile...\n" ));
+ psmsg->Set( MSG_HELP_HELP_FILE_NOT_FOUND );
+ psmsg->Display( "" );
+ Errlev = HELP_ERROR;
+ return;
+ }
+
+ // Get a file node to the Help file and open a stream...
+ if( ( pHelpFile = SYSTEM::QueryFile( pHelpPath ) ) == NULL ) {
+ KdPrint(( "Unable to create FSN_NODE for helpfile\n" ));
+ psmsg->Set( MSG_HELP_HELP_FILE_ERROR );
+ psmsg->Display( "" );
+ DELETE( pHelpPath );
+ Errlev = HELP_ERROR;
+ return;
+ }
+ DELETE( pHelpPath );
+
+ if( ( _HelpStream = pHelpFile->QueryStream( READ_ACCESS ) ) == NULL ) {
+ KdPrint(( "Unable to open stream to help file...\n" ));
+ psmsg->Set( MSG_HELP_HELP_FILE_ERROR );
+ psmsg->Display( "" );
+ DELETE( pHelpFile );
+ Errlev = HELP_ERROR;
+ return;
+ }
+
+ // Test if there is a command...
+ if( _FileName.IsValueSet() ) {
+ PrintCmd();
+ } else {
+ PrintList();
+ }
+
+ DELETE( pHelpFile );
+ DELETE( _HelpStream );
+
+ return;
+}
+
+VOID
+HELP::PrintCmd(
+ )
+/*++
+
+Routine Description:
+
+ Search the help file for the command - if its there, exec it, otherwise
+ print an error message and return.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ BOOLEAN flag;
+ CHNUM CmdLen;
+ LONG result;
+ PWSTRING String;
+ DSTRING CmdStr;
+ DSTRING Command;
+ LPWSTR pCmd;
+ STR ApiCommand[ MAX_PATH ];
+ STARTUPINFO StartupInfo;
+ PROCESS_INFORMATION ProcessInfo;
+ BOOLEAN dot_com = FALSE;
+
+ DSTRING CmdCommand;
+ DSTRING ExternalCommand;
+ DSTRING DotComExtension;
+ FSTRING fstring;
+
+ //
+ // Initialize the strings to be used...
+ //
+ CmdStr.Initialize( "" );
+ Command.Initialize( _FileName.GetString() );
+ CmdLen = Command.QueryChCount();
+
+ // Test if the command is on the list...(recognized)
+ flag = FALSE;
+ while( !_HelpStream->IsAtEnd() ) {
+
+ if( ( String = NEW DSTRING ) == NULL ) {
+ KdPrint(( "Unable to create string for QueryLine()\n" ));
+ return;
+ }
+ String->Initialize( "" );
+
+
+ // Help file is ANSI.
+ WSTRING::SetAnsiConversions();
+ if( !_HelpStream->ReadLine( String ) ) {
+ KdPrint(( "Unable to read line but file isn't empty...\n" ));
+ }
+ WSTRING::SetOemConversions();
+
+ if( !isspace( String->QueryChAt( 0 ) ) ) { // if a command starts this line...
+ result = String->Stricmp( &Command, 0, CmdLen, 0, CmdLen );
+ if( !result ) {
+ flag = TRUE;
+ break;
+ }
+ if( result > 0 ) {
+ break; // We've passed it...
+ }
+ }
+ DELETE( String );
+
+ }
+ DELETE( String );
+
+ if( !flag ) {
+ KdPrint(( "Help not available for this subject\n" ));
+ psmsg->Set( MSG_HELP_HELP_UNAVAILABLE );
+ psmsg->Display( "%W", &Command );
+ Errlev = NO_HELP_FOUND;
+ return;
+ }
+
+ //
+ // Set up the StartupInfo block...
+ //
+ memset(&StartupInfo, 0, sizeof( STARTUPINFO ) );
+ StartupInfo.cb = sizeof( STARTUPINFO );
+
+ //
+ // The command has now been recognized - if it is internal, exec
+ // it with Cmd.exe, otherwise, just attempt to exec it...
+ //
+ if( IsInternal( &Command ) ) {
+
+ // Exec with Cmd.exe
+ SYSTEM::QueryResourceString( &CmdStr, MSG_HELP_EXECUTE_WITH_CMD, "%W", _FileName.GetString() );
+ pCmd = CmdStr.QueryWSTR();
+ flag = CreateProcess( NULL,
+ pCmd,
+ NULL,
+ NULL,
+ TRUE,
+ 0,
+ NULL,
+ NULL,
+ &StartupInfo,
+ &ProcessInfo
+ );
+
+ } else {
+
+ if( !ExternalCommand.Initialize( _FileName.GetString() ) ) {
+ KdPrint(( "ExternalCommand.Initialize() failed \n" ));
+ return;
+ }
+ //
+ // Find out if we have to add '.COM' to the command to be
+ // be executed
+ //
+ if( IsExternalDotComCommand( &ExternalCommand ) ) {
+ //
+ // Append '.COM' to the command
+ //
+ if( !DotComExtension.Initialize( ".COM" ) ) {
+ KdPrint(( "DotComExtension.Initialize() failed \n" ));
+ return;
+ }
+ ExternalCommand.Strcat( &DotComExtension );
+ dot_com = TRUE;
+ }
+
+ for (;;) {
+
+ //
+ // Exec just the command...
+ SYSTEM::QueryResourceString( &CmdStr, MSG_HELP_EXECUTE_WITHOUT_CMD, "%W", &ExternalCommand );
+ pCmd = CmdStr.QueryWSTR();
+ flag = CreateProcess( NULL,
+ pCmd,
+ NULL,
+ NULL,
+ TRUE,
+ 0,
+ NULL,
+ NULL,
+ &StartupInfo,
+ &ProcessInfo
+ );
+
+ // If this command wasn't an "official" dot_com but the
+ // CreateProcess failed then try the create process again
+ // with the .COM extension. We do this so that apps that
+ // add stuff to the DOSHELP file won't be disappointed just
+ // because they end in COM.
+
+ if (!flag && !dot_com) {
+
+ ExternalCommand.Strcat(fstring.Initialize((PWSTR) L".COM"));
+ dot_com = TRUE;
+
+ } else {
+ break;
+ }
+ }
+ }
+ FREE( pCmd );
+
+ if( !flag ) {
+ // Failed to create the process...
+ KdPrint(( " Unable to run the exe...\n" ));
+ psmsg->Set( MSG_HELP_HELP_UNAVAILABLE );
+ psmsg->Display( "%W", &Command );
+ Errlev = NO_HELP_FOUND;
+ return;
+ }
+
+ // Wait for the process to complete...
+ WaitForSingleObject( ProcessInfo.hProcess, (DWORD)-1 );
+
+ return;
+}
+
+VOID
+HELP::PrintList(
+ )
+/*++
+
+Routine Description:
+
+ Search the help file for the command - if its there, exec it, otherwise
+ print an error message and return.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ BOOLEAN StatusOk; // status value
+ PKEYBOARD InStream;
+ PSCREEN OutStream;
+ PWSTRING String;
+ SCREEN Screen;
+ USHORT idx;
+ USHORT ScrRows;
+
+ //
+ // Get a pointer to the input stream, so we can tell when a character
+ // is typed.
+ //
+ if( !( InStream = KEYBOARD::Cast( Get_Standard_Input_Stream() ) ) ) {
+ KdPrint(( "Unable to flush keyboard - skipping more...\n" ));
+ }
+
+ //
+ // Check if the Stdout is a Screen Object. If it isn't, then we don't
+ // want to pause or print the general help message....
+ //
+ OutStream = SCREEN::Cast( Get_Standard_Output_Stream() );
+
+
+ //
+ // Initialize the screen object and get the number of rows. The number
+ // of cols is inconsequential.
+ //
+ Screen.Initialize();
+ Screen.QueryScreenSize( &ScrRows, &idx );
+
+
+ for( ;; ) {
+
+ if( OutStream ) {
+ //
+ // Output the general message string...
+ //
+ psmsg->Set( MSG_HELP_GENERAL_HELP );
+ psmsg->Display( "" );
+ }
+
+ for( idx = ScrRows - USED_ROWS; idx; ) {
+
+ //
+ // Read a line from the file and write it to the stream...
+ //
+
+
+ if( _HelpStream->IsAtEnd() ) {
+
+ //
+ // End of the HELP file...
+ //
+ return;
+ }
+
+ if( ( String = NEW DSTRING ) == NULL ) {
+ KdPrint(( "Unable to create string for QueryLine()\n" ));
+ return;
+ }
+ String->Initialize( "" );
+
+
+ // The help file contains ANSI strings.
+
+ WSTRING::SetAnsiConversions();
+
+ if( !_HelpStream->ReadLine( String ) ) {
+ KdPrint(( "Unable to read line but file isn't empty...\n" ));
+ }
+
+ WSTRING::SetOemConversions();
+
+ //
+ // Print the latest line, if it isn't a comment... (preceded by '@')
+ //
+ if( String->QueryChAt( 0 ) != _CommentChar ) {
+
+ psmsg->Set( MSG_HELP_HELP_FILE_DATA );
+ psmsg->Display( "%W", String );
+
+ //
+ // Used a line - decrement the count
+ //
+ idx--;
+
+ }
+ DELETE( String );
+
+ }
+ //
+ // If we are able, or if we need to, wait for any response from
+ // the keyboard...
+ //
+ if( OutStream && InStream ) {
+
+ //
+ // Output the '--- MORE ---' string...
+ //
+ psmsg->Set( MSG_HELP_MORE );
+ psmsg->Display( "" );
+
+ InStream->Flush(); // Kill any keys waiting in the buffer
+ while( InStream->IsKeyAvailable( &StatusOk ) && !StatusOk ) {
+ ;
+ }
+ InStream->Flush(); // remove keys waiting in the buffer
+ }
+ }
+}
+
+BOOLEAN
+HELP::IsInternal(
+ PWSTRING pCmdString
+ )
+/*++
+
+Routine Description:
+
+ Initializes an FC object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the initialization succeeded.
+
+
+--*/
+{
+ PWSTRING pString;
+ USHORT idx;
+ LONG result;
+
+ pString = NEW DSTRING;
+ idx = 0;
+ while( Internal_Commands[ idx ] != NULL ) {
+ pString->Initialize( Internal_Commands[ idx ] );
+ result = pString->Stricmp( pCmdString );
+ if( !result ) {
+ DELETE( pString );
+ return( TRUE );
+ }
+ if( result > 0 ) { // The Compare has returned that the command
+ // string is lexically greater then the current
+ // value - therefore, since the list is alphabetic
+ // the command won't be found.
+ DELETE( pString );
+ return( FALSE );
+ }
+ idx++;
+ }
+ DELETE( pString );
+
+ return( FALSE );
+}
+
+BOOLEAN
+HELP::IsExternalDotComCommand(
+ PWSTRING pCmdString
+ )
+/*++
+
+Routine Description:
+
+ Determines if pCmdString refers to an external utility whose name
+ has .com extension
+
+Arguments:
+
+ pCmdString - Pointer to a WSTRING that contains the utility name
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if pCmdString refers to an external utility
+ that whose name has .com extension.
+ Returns FALSE otherwise.
+
+
+--*/
+{
+ PWSTRING pString;
+ USHORT idx;
+ LONG result;
+
+ pString = NEW DSTRING;
+ idx = 0;
+ while( ExternalDotComCommands[ idx ] != NULL ) {
+ pString->Initialize( ExternalDotComCommands[ idx ] );
+ result = pString->Stricmp( pCmdString );
+ if( !result ) {
+ DELETE( pString );
+ return( TRUE );
+ }
+ if( result > 0 ) { // The Compare has returned that the command
+ // string is lexically greater then the current
+ // value - therefore, since the list is alphabetic
+ // the command won't be found.
+ DELETE( pString );
+ return( FALSE );
+ }
+ idx++;
+ }
+ DELETE( pString );
+
+ return( FALSE );
+}
+
+int _CRTAPI1
+main(
+ )
+{
+ DEFINE_CLASS_DESCRIPTOR( HELP );
+
+ {
+ HELP Help;
+
+ perrstk = NEW ERRSTACK;
+ psmsg = NEW STREAM_MESSAGE;
+ Errlev = NO_ERRORS;
+
+ psmsg->Initialize( Get_Standard_Output_Stream(),
+ Get_Standard_Input_Stream() );
+
+ if( !SYSTEM::IsCorrectVersion() ) {
+ KdPrint(( "Incorrect Version Number...\n" ));
+ psmsg->Set( MSG_HELP_INCORRECT_VERSION );
+ psmsg->Display( "" );
+ Help.Destruct();
+ return( NO_ERRORS );
+ }
+ if( !( Help.Initialize() ) ) {
+ //
+ // The Command line didn't initialize properly, die nicely
+ // without printing any error messages - Main doesn't know
+ // why the Initialization failed...
+ //
+ Help.Destruct();
+ return( NO_ERRORS );
+ }
+
+ // Do file comparison stuff...
+ Help.GetHelp();
+ Help.Destruct();
+ return( Errlev );
+ }
+}
diff --git a/private/utils/help/help.hlp b/private/utils/help/help.hlp
new file mode 100644
index 000000000..31603bd54
--- /dev/null
+++ b/private/utils/help/help.hlp
@@ -0,0 +1,115 @@
+@ Copyright (C) 1990-1991 Microsoft Corp. All rights reserved.
+@ This is the DOS general help file. It contains a brief
+@ description of each command supported by the DOS help command.
+@ Type HELP with no arguments to display the text in this file.
+@ Lines beginning with @ are comments, and are ignored by HELP.
+@ This file may be modified to add new commands. If the HELP command-name
+@ form is to be used, any new commands should support the /? parameter.
+@ New commands should start in the first column. Any extra lines needed
+@ for a command description should be preceded by white space. Commands
+@ must be added in alphabetical order.
+@APPEND Allows programs to open data files in specified directories as if
+@ they were in the current directory.
+@ASSIGN Redirects requests for disk operations on one drive to a different
+@ drive.
+AT Schedules commands and programs to run on a computer.
+ATTRIB Displays or changes file attributes.
+@BACKUP Backs up one or more files from one disk to another.
+BREAK Sets or clears extended CTRL+C checking.
+CALL Calls one batch program from another.
+CD Displays the name of or changes the current directory.
+CHCP Displays or sets the active code page number.
+CHDIR Displays the name of or changes the current directory.
+CHKDSK Checks a disk and displays a status report.
+CLS Clears the screen.
+CMD Starts a new instance of the Windows NT command interpreter.
+COMP Compares the contents of two files or sets of files.
+CONVERT Converts FAT volumes to NTFS. You cannot convert the
+ current drive.
+COPY Copies one or more files to another location.
+@CTTY Changes the terminal device used to control your system.
+DATE Displays or sets the date.
+@DEBUG Runs Debug, a program testing and editing tool.
+DEL Deletes one or more files.
+DIR Displays a list of files and subdirectories in a directory.
+DISKCOMP Compares the contents of two floppy disks.
+DISKCOPY Copies the contents of one floppy disk to another.
+DOSKEY Edits command lines, recalls Windows NT commands, and creates macros.
+@DOSSHELL Starts Windows NT Shell.
+ECHO Displays messages, or turns command echoing on or off.
+@EDIT Starts Windows NT Editor, which creates and changes ASCII files.
+@EDLIN Starts Edlin, a line-oriented text editor.
+@EMM386 Turns on or off EMM386 expanded memory support.
+ENDLOCAL Ends localization of environment changes in a batch file.
+ERASE Deletes one or more files.
+@EXE2BIN Converts .EXE (executable) files to binary format.
+EXIT Quits the CMD.EXE program (command interpreter).
+@EXPAND Expands one or more compressed files.
+@FASTOPEN Decreases the amount of time needed to open frequently used files
+@ and directories.
+FC Compares two files or sets of files, and displays the differences
+ between them.
+@FDISK Configures a hard disk for use with Windows NT.
+FIND Searches for a text string in a file or files.
+FINDSTR Searches for strings in files.
+FOR Runs a specified command for each file in a set of files.
+FORMAT Formats a disk for use with Windows NT.
+GOTO Directs the Windows NT command interpreter to a labeled line in a
+ batch program.
+GRAFTABL Enables Windows NT to display an extended character set in graphics
+ mode.
+@GRAPHICS Loads a program that can print graphics.
+HELP Provides Help information for Windows NT commands.
+IF Performs conditional processing in batch programs.
+@JOIN Joins a disk drive to a directory on another drive.
+KEYB Configures a keyboard for a specific language.
+LABEL Creates, changes, or deletes the volume label of a disk.
+@LH Loads a program into the upper memory area.
+@LOADFIX Loads a program above the first 64K of memory, and runs the program.
+@LOADHIGH Loads a program into the upper memory area.
+MD Creates a directory.
+@MEM Displays the amount of used and free memory in your system.
+@MIRROR Records information about one or more disks.
+MKDIR Creates a directory.
+MODE Configures a system device.
+MORE Displays output one screen at a time.
+MOVE Moves one or more files from one directory to another directory on
+ the same drive.
+@NLSFUNC Loads country-specific information.
+PATH Displays or sets a search path for executable files.
+PAUSE Suspends processing of a batch file and displays a message.
+POPD Restores the previous value of the current directory saved by PUSHD.
+PRINT Prints a text file.
+PROMPT Changes the Windows NT command prompt.
+PUSHD Saves the current directory then changes it.
+@QBASIC Starts the Windows NT QBasic programming environment.
+RD Removes a directory.
+RECOVER Recovers readable information from a bad or defective disk.
+REM Records comments (remarks) in batch files or CONFIG.SYS.
+REN Renames a file or files.
+RENAME Renames a file or files.
+REPLACE Replaces files.
+RESTORE Restores files that were backed up by using the BACKUP command.
+RMDIR Removes a directory.
+SET Displays, sets, or removes Windows NT environment variables.
+SETLOCAL Begins localization of environment changes in a batch file.
+@SETVER Sets the version number that Windows NT reports to a program.
+@SHARE Installs file-sharing and locking capabilities on your hard disk.
+SHIFT Shifts the position of replaceable parameters in batch files.
+SORT Sorts input.
+START Starts a separate window to run a specified program or command.
+SUBST Associates a path with a drive letter.
+@SYS Copies Windows NT system files and command interpreter to a disk you
+@ specify.
+TIME Displays or sets the system time.
+TITLE Sets the window title for a CMD.EXE session.
+TREE Graphically displays the directory structure of a drive or path.
+TYPE Displays the contents of a text file.
+@UNDELETE Recovers files which have been deleted.
+@UNFORMAT Restores a disk erased by the FORMAT command or restructured by the
+@ RECOVER command.
+VER Displays the Windows NT version.
+VERIFY Tells Windows NT whether to verify that your files are written
+ correctly to a disk.
+VOL Displays a disk volume label and serial number.
+XCOPY Copies files and directory trees.
diff --git a/private/utils/help/help.hxx b/private/utils/help/help.hxx
new file mode 100644
index 000000000..51dd179ea
--- /dev/null
+++ b/private/utils/help/help.hxx
@@ -0,0 +1,167 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ help.hxx
+
+Abstract:
+
+Author:
+
+ Barry J. Gilhuly
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+
+#if !defined( _HELP_ )
+
+#define _HELP_
+
+//
+// Define the possible error codes
+//
+#define NO_ERRORS 0
+#define HELP_ERROR 2
+#define NO_HELP_FOUND 3
+#define USED_ROWS 3
+
+
+STR *Internal_Commands[] = {
+ "ASSOC",
+ "BREAK",
+ "CALL",
+ "CD",
+ "CHDIR",
+ "CLS",
+ "COLOR",
+ "COPY",
+ "DATE",
+ "DEL",
+ "DIR",
+ "ECHO",
+ "ENDLOCAL",
+ "ERASE",
+ "EXIT",
+ "FOR",
+ "FTYPE",
+ "GOTO",
+ "IF",
+ "MD",
+ "MKDIR",
+ "MOVE",
+ "PATH",
+ "PAUSE",
+ "POPD",
+ "PROMPT",
+ "PUSHD",
+ "RD",
+ "REM",
+ "REN",
+ "RENAME",
+ "RMDIR",
+ "SET",
+ "SETLOCAL",
+ "SHIFT",
+ "START",
+ "TIME",
+ "TITLE",
+ "TYPE",
+ "VER",
+ "VERIFY",
+ "VOL",
+ NULL
+};
+
+//
+// jaimes - 10/15/91
+// The array below contains the name of external utilities that have .com
+// extension. We have to add the .com extension after the utility name
+// before we invoke cmd, otherwise cmd will look for <utility>.exe, and it
+// won't find it.
+//
+STR *ExternalDotComCommands[] = {
+ "CHCP",
+ "DISKCOMP",
+ "DISKCOPY",
+ "FORMAT",
+ "GRAFTABL",
+ "KEYB",
+ "MODE",
+ "MORE",
+ "TREE",
+ NULL
+};
+
+
+
+#include "object.hxx"
+#include "keyboard.hxx"
+#include "program.hxx"
+
+DECLARE_CLASS( HELP );
+
+class HELP : public PROGRAM {
+
+ public:
+
+
+ DECLARE_CONSTRUCTOR( HELP );
+
+ NONVIRTUAL
+ VOID
+ Destruct(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ );
+
+ NONVIRTUAL
+ VOID
+ GetHelp(
+ );
+
+ private:
+
+ NONVIRTUAL
+ BOOLEAN
+ FindHelpFile(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsInternal(
+ PWSTRING pCmdString
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsExternalDotComCommand(
+ PWSTRING pCmdString
+ );
+
+ NONVIRTUAL
+ VOID
+ PrintCmd(
+ );
+
+ NONVIRTUAL
+ VOID
+ PrintList(
+ );
+
+ PFILE_STREAM _HelpStream;
+ STRING_ARGUMENT _FileName;
+ WCHAR _CommentChar;
+
+};
+
+
+#endif // _HELP_
diff --git a/private/utils/help/help.rc b/private/utils/help/help.rc
new file mode 100644
index 000000000..b89914788
--- /dev/null
+++ b/private/utils/help/help.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Command Line Help Utility"
+#define VER_INTERNALNAME_STR "Help"
+#define VER_ORIGINALFILENAME_STR "Help.Exe"
+
+#include "common.ver"
diff --git a/private/utils/help/makefile b/private/utils/help/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/help/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/help/makefile.inc b/private/utils/help/makefile.inc
new file mode 100644
index 000000000..6c93eb38d
--- /dev/null
+++ b/private/utils/help/makefile.inc
@@ -0,0 +1,12 @@
+{}.cxx{obj\i386\}.obj:
+ $(386_COMPILER) -Fo$@ $(MAKEDIR)\$(<F)
+
+{}.cxx{obj\mips\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClMips $< " $(C_COMPILER) "
+ @$(C_COMPILER) -Fo$@ $(MAKEDIR)\$<
+
+{}.cxx{obj\alpha\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClAlpha $< " $(ALPHA_COMPILER) "
+ @$(ALPHA_COMPILER) -Fo$@ $(MAKEDIR)\$<
diff --git a/private/utils/help/sources b/private/utils/help/sources
new file mode 100644
index 000000000..aa2c35616
--- /dev/null
+++ b/private/utils/help/sources
@@ -0,0 +1,58 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+BLDCRT=1
+
+MAJORCOMP=utils
+MINORCOMP=help
+
+TARGETNAME=help
+TARGETPATH=obj
+TARGETTYPE=UMAPPL_NOLIB
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=help.cxx help.rc
+
+INCLUDES=..\ulib\inc;\nt\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+CXXFLAGS=+d
+UMLIBS=..\ulib\src\obj\*\ulib.lib \nt\public\sdk\lib\*\ntdll.lib
+UMTYPE=console
+UMAPPL=help
+UMRES=obj\*\help.res
diff --git a/private/utils/ifsutil/dirs b/private/utils/ifsutil/dirs
new file mode 100644
index 000000000..c4db5a979
--- /dev/null
+++ b/private/utils/ifsutil/dirs
@@ -0,0 +1,16 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+!ENDIF
+
+DIRS= src
diff --git a/private/utils/ifsutil/inc/autoentr.hxx b/private/utils/ifsutil/inc/autoentr.hxx
new file mode 100644
index 000000000..1be4b6b7e
--- /dev/null
+++ b/private/utils/ifsutil/inc/autoentr.hxx
@@ -0,0 +1,131 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ autoentr.hxx
+
+Abstract:
+
+ This module contains the declaration of the AUTOENTRY class.
+
+ The AUTOENTRY class models an entry in the registry used to
+ execute a program at boot time.
+
+Author:
+
+ Ramon J. San Andres (ramonsa) 11 Mar 1991
+
+Environment:
+
+ Ulib, User Mode
+
+
+--*/
+
+
+#if !defined( _AUTOENTRY_ )
+
+#define _AUTOENTRY_
+
+#include "wstring.hxx"
+
+DECLARE_CLASS( AUTOENTRY );
+
+
+class AUTOENTRY : public OBJECT {
+
+
+ public:
+
+ DECLARE_CONSTRUCTOR( AUTOENTRY );
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ VIRTUAL
+ ~AUTOENTRY(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ IN PCWSTRING EntryName,
+ IN PCWSTRING CommandLine
+ );
+
+ NONVIRTUAL
+ PCWSTRING
+ GetCommandLine (
+ );
+
+ NONVIRTUAL
+ PCWSTRING
+ GetEntryName (
+ );
+ private:
+
+ NONVIRTUAL
+ VOID
+ Destroy (
+ );
+
+ DSTRING _EntryName;
+ DSTRING _CommandLine;
+
+};
+
+
+INLINE
+PCWSTRING
+AUTOENTRY::GetCommandLine (
+ )
+/*++
+
+Routine Description:
+
+ Gets the command line
+
+Arguments:
+
+ None
+
+Return Value:
+
+ The command line
+
+--*/
+{
+ return &_CommandLine;
+}
+
+
+
+INLINE
+PCWSTRING
+AUTOENTRY::GetEntryName (
+ )
+/*++
+
+Routine Description:
+
+ Gets the command line
+
+Arguments:
+
+ None
+
+Return Value:
+
+ The command line
+
+--*/
+{
+ return &_EntryName;
+}
+
+
+#endif // _AUTOENTRY_
diff --git a/private/utils/ifsutil/inc/autoreg.hxx b/private/utils/ifsutil/inc/autoreg.hxx
new file mode 100644
index 000000000..230932c09
--- /dev/null
+++ b/private/utils/ifsutil/inc/autoreg.hxx
@@ -0,0 +1,79 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ autoreg.hxx
+
+Abstract:
+
+ This module contains the declaration of the AUTOREG class.
+
+ The AUTOREG class contains methods for the registration and
+ de-registration of those programs that are to be executed at
+ boot time.
+
+Author:
+
+ Ramon J. San Andres (ramonsa) 11 Mar 1991
+
+Environment:
+
+ Ulib, User Mode
+
+
+--*/
+
+
+#if !defined( _AUTOREG_ )
+
+#define _AUTOREG_
+
+#include "ulib.hxx"
+#include "wstring.hxx"
+
+
+#if defined ( _AUTOCHECK_ )
+#define IFSUTIL_EXPORT
+#elif defined ( _IFSUTIL_MEMBER_ )
+#define IFSUTIL_EXPORT __declspec(dllexport)
+#else
+#define IFSUTIL_EXPORT __declspec(dllimport)
+#endif
+
+
+DECLARE_CLASS( AUTOREG );
+
+
+class AUTOREG : public OBJECT {
+
+
+ public:
+
+ STATIC
+ IFSUTIL_EXPORT
+ BOOLEAN
+ AddEntry (
+ IN PCWSTRING CommandLine
+ );
+
+ STATIC
+ IFSUTIL_EXPORT
+ BOOLEAN
+ DeleteEntry (
+ IN PCWSTRING LineToMatch,
+ IN BOOLEAN PrefixOnly DEFAULT FALSE
+ );
+
+ STATIC
+ IFSUTIL_EXPORT
+ BOOLEAN
+ IsEntryPresent (
+ IN PCWSTRING LineToMatch
+ );
+
+};
+
+
+#endif // _AUTOREG_
diff --git a/private/utils/ifsutil/inc/bigint.hxx b/private/utils/ifsutil/inc/bigint.hxx
new file mode 100644
index 000000000..d12c2bbb9
--- /dev/null
+++ b/private/utils/ifsutil/inc/bigint.hxx
@@ -0,0 +1,645 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ bigint.hxx
+
+Abstract:
+
+ The BIG_INT class models a 64 bit signed integer.
+
+ This class is meant to be light and will occupy only 64 bits of space.
+ It should be manipulated exactly as an INT would be.
+
+ There will be no constructor or destructor. A BIG_INT will be
+ uninitialized until a value is assigned to it.
+
+ This implementation of BIG_INT uses the NT LARGE_INTEGER structure.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 8-Jul-91
+
+--*/
+
+
+#if !defined(BIG_INT_DEFN)
+
+#define BIG_INT_DEFN
+
+#include <ulib.hxx>
+
+#if defined ( _AUTOCHECK_ )
+#define IFSUTIL_EXPORT
+#elif defined ( _IFSUTIL_MEMBER_ )
+#define IFSUTIL_EXPORT __declspec(dllexport)
+#else
+#define IFSUTIL_EXPORT __declspec(dllimport)
+#endif
+
+
+
+DEFINE_POINTER_AND_REFERENCE_TYPES( LARGE_INTEGER );
+
+DECLARE_CLASS( BIG_INT );
+
+class BIG_INT {
+
+ public:
+
+ NONVIRTUAL
+ BIG_INT(
+ );
+
+ NONVIRTUAL
+ BIG_INT(
+ IN RCINT LowPart
+ );
+
+ NONVIRTUAL
+ BIG_INT(
+ IN RCUINT LowPart
+ );
+
+ NONVIRTUAL
+ BIG_INT(
+ IN RCSLONG LowPart
+ );
+
+ NONVIRTUAL
+ BIG_INT(
+ IN RCULONG LowPart
+ );
+
+ NONVIRTUAL
+ BIG_INT(
+ IN RCLARGE_INTEGER LargeInteger
+ );
+
+ NONVIRTUAL
+ VOID
+ operator=(
+ IN RCINT LowPart
+ );
+
+ NONVIRTUAL
+ VOID
+ operator=(
+ IN RCUINT LowPart
+ );
+
+ NONVIRTUAL
+ VOID
+ operator=(
+ IN RCSLONG LowPart
+ );
+
+ NONVIRTUAL
+ VOID
+ operator=(
+ IN RCULONG LowPart
+ );
+
+ NONVIRTUAL
+ VOID
+ operator=(
+ IN RCLARGE_INTEGER LargeInteger
+ );
+
+ NONVIRTUAL
+ VOID
+ Set(
+ IN RCULONG LowPart,
+ IN RCSLONG HighPart
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ VOID
+ Set(
+ IN UCHAR ByteCount,
+ IN PCUCHAR CompressedInteger
+ );
+
+ NONVIRTUAL
+ RCULONG
+ GetLowPart(
+ ) CONST;
+
+ NONVIRTUAL
+ RCSLONG
+ GetHighPart(
+ ) CONST;
+
+ NONVIRTUAL
+ RCLARGE_INTEGER
+ GetLargeInteger(
+ ) CONST;
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ VOID
+ QueryCompressedInteger(
+ OUT PUCHAR ByteCount,
+ OUT PUCHAR CompressedInteger
+ ) CONST;
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ VOID
+ operator+=(
+ IN RCBIG_INT BigInt
+ );
+
+ NONVIRTUAL
+ BIG_INT
+ operator-(
+ ) CONST;
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ VOID
+ operator-=(
+ IN RCBIG_INT BigInt
+ );
+
+ FRIEND
+ IFSUTIL_EXPORT
+ BIG_INT
+ operator+(
+ IN RCBIG_INT Left,
+ IN RCBIG_INT Right
+ );
+
+ FRIEND
+ IFSUTIL_EXPORT
+ BIG_INT
+ operator-(
+ IN RCBIG_INT Left,
+ IN RCBIG_INT Right
+ );
+
+ FRIEND
+ IFSUTIL_EXPORT
+ BIG_INT
+ operator*(
+ IN RCBIG_INT Left,
+ IN RCSLONG Right
+ );
+
+ FRIEND
+ IFSUTIL_EXPORT
+ BIG_INT
+ operator*(
+ IN RCSLONG Left,
+ IN RCBIG_INT Right
+ );
+
+ FRIEND
+ IFSUTIL_EXPORT
+ BIG_INT
+ operator/(
+ IN RCBIG_INT Left,
+ IN RCBIG_INT Right
+ );
+
+ FRIEND
+ IFSUTIL_EXPORT
+ BIG_INT
+ operator%(
+ IN RCBIG_INT Left,
+ IN RCBIG_INT Right
+ );
+
+ FRIEND
+ IFSUTIL_EXPORT
+ BOOLEAN
+ operator==(
+ IN RCBIG_INT Left,
+ IN RCBIG_INT Right
+ );
+
+ FRIEND
+ IFSUTIL_EXPORT
+ BOOLEAN
+ operator!=(
+ IN RCBIG_INT Left,
+ IN RCBIG_INT Right
+ );
+
+ FRIEND
+ IFSUTIL_EXPORT
+ BOOLEAN
+ operator<(
+ IN RCBIG_INT Left,
+ IN RCBIG_INT Right
+ );
+
+ FRIEND
+ IFSUTIL_EXPORT
+ BOOLEAN
+ operator<=(
+ IN RCBIG_INT Left,
+ IN RCBIG_INT Right
+ );
+
+ FRIEND
+ IFSUTIL_EXPORT
+ BOOLEAN
+ operator>(
+ IN RCBIG_INT Left,
+ IN RCBIG_INT Right
+ );
+
+ FRIEND
+ IFSUTIL_EXPORT
+ BOOLEAN
+ operator>=(
+ IN RCBIG_INT Left,
+ IN RCBIG_INT Right
+ );
+
+ private:
+
+ LARGE_INTEGER x;
+
+};
+
+
+INLINE
+BIG_INT::BIG_INT(
+ )
+/*++
+
+Routine Description:
+
+ Constructor for BIG_INT.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+}
+
+
+INLINE
+VOID
+BIG_INT::operator=(
+ IN RCINT LowPart
+ )
+/*++
+
+Routine Description:
+
+ This routine copies an INT into a BIG_INT.
+
+Arguments:
+
+ LowPart - Supplies an integer.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ x.LowPart = (ULONG) ((SLONG) LowPart);
+ x.HighPart = (LowPart >= 0) ? 0 : -1;
+}
+
+
+INLINE
+VOID
+BIG_INT::operator=(
+ IN RCUINT LowPart
+ )
+/*++
+
+Routine Description:
+
+ This routine copies a UINT into a BIG_INT.
+
+Arguments:
+
+ LowPart - Supplies an unsigned integer.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ x.LowPart = LowPart;
+ x.HighPart = 0;
+}
+
+
+INLINE
+VOID
+BIG_INT::operator=(
+ IN RCSLONG LowPart
+ )
+/*++
+
+Routine Description:
+
+ This routine copies a LONG into a BIG_INT.
+
+Arguments:
+
+ LowPart - Supplies a long integer.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ x.LowPart = (ULONG) LowPart;
+ x.HighPart = (LowPart >= 0) ? 0 : -1;
+}
+
+
+INLINE
+VOID
+BIG_INT::operator=(
+ IN RCULONG LowPart
+ )
+/*++
+
+Routine Description:
+
+ This routine copies a ULONG into a BIG_INT.
+
+Arguments:
+
+ LowPart - Supplies an unsigned long integer.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ x.LowPart = LowPart;
+ x.HighPart = 0;
+}
+
+INLINE
+VOID
+BIG_INT::operator=(
+ IN RCLARGE_INTEGER LargeInteger
+ )
+/*++
+
+Routine Description:
+
+ This routine copies a LARGE_INTEGER into a BIG_INT.
+
+Arguments:
+
+ LargeInteger -- supplies a large integer
+
+Return Value:
+
+ None.
+
+--*/
+{
+ x = LargeInteger;
+}
+
+
+INLINE
+BIG_INT::BIG_INT(
+ IN RCINT LowPart
+ )
+/*++
+
+Routine Description:
+
+ Constructor for BIG_INT.
+
+Arguments:
+
+ LowPart - Supplies an integer.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ *this = LowPart;
+}
+
+
+INLINE
+BIG_INT::BIG_INT(
+ IN RCUINT LowPart
+ )
+/*++
+
+Routine Description:
+
+ Constructor for BIG_INT.
+
+Arguments:
+
+ LowPart - Supplies an unsigned integer.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ *this = LowPart;
+}
+
+
+INLINE
+BIG_INT::BIG_INT(
+ IN RCSLONG LowPart
+ )
+/*++
+
+Routine Description:
+
+ Constructor for BIG_INT.
+
+Arguments:
+
+ LowPart - Supplies a long integer.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ *this = LowPart;
+}
+
+
+INLINE
+BIG_INT::BIG_INT(
+ IN RCULONG LowPart
+ )
+/*++
+
+Routine Description:
+
+ Constructor for BIG_INT.
+
+Arguments:
+
+ LowPart - Supplies an unsigned long integer.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ *this = LowPart;
+}
+
+INLINE
+BIG_INT::BIG_INT(
+ IN RCLARGE_INTEGER LargeInteger
+ )
+/*++
+
+Routine Description:
+
+ Constructor for BIG_INT to permit initialization with a LARGE_INTEGER
+
+Arguments:
+
+ LargeInteger -- supplies a large integer.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ *this = LargeInteger;
+}
+
+
+INLINE
+VOID
+BIG_INT::Set(
+ IN RCULONG LowPart,
+ IN RCSLONG HighPart
+ )
+/*++
+
+Routine Description:
+
+ This routine sets a BIG_INT to an initial value.
+
+Arguments:
+
+ LowPart - Supplies the low part of the BIG_INT.
+ HighPart - Supplies the high part of the BIG_INT.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ x.LowPart = LowPart;
+ x.HighPart = HighPart;
+}
+
+
+INLINE
+RCULONG
+BIG_INT::GetLowPart(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the low part of the BIG_INT.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The low part of the BIG_INT.
+
+--*/
+{
+ return x.LowPart;
+}
+
+
+// Note: billmc -- this could probably return an RCLONG, for
+// greater efficiency, but that generates warnings.
+
+INLINE
+RCSLONG
+BIG_INT::GetHighPart(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the high part of the BIG_INT.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The high part of the BIG_INT.
+
+--*/
+{
+ return x.HighPart;
+}
+
+
+INLINE
+RCLARGE_INTEGER
+BIG_INT::GetLargeInteger(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the large integer embedded in the BIG_INT.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The large-integer value of the BIG_INT.
+
+--*/
+{
+ return x;
+}
+
+
+
+
+#endif // BIG_INT_DEFN
diff --git a/private/utils/ifsutil/inc/bootreg.h b/private/utils/ifsutil/inc/bootreg.h
new file mode 100644
index 000000000..199d2d94f
--- /dev/null
+++ b/private/utils/ifsutil/inc/bootreg.h
@@ -0,0 +1,18 @@
+#include <nt.h>
+#include <ntrtl.h>
+
+ULONG
+CharsInMultiString(
+ IN PWSTR pw
+ );
+
+BOOLEAN
+QueryAutocheckEntries(
+ OUT PVOID Buffer,
+ IN ULONG BufferSize
+ );
+
+BOOLEAN
+SaveAutocheckEntries(
+ IN PVOID Value
+ );
diff --git a/private/utils/ifsutil/inc/bpb.hxx b/private/utils/ifsutil/inc/bpb.hxx
new file mode 100644
index 000000000..8a37bc838
--- /dev/null
+++ b/private/utils/ifsutil/inc/bpb.hxx
@@ -0,0 +1,209 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ bpb.hxx
+
+Abstract:
+
+ This module contains the declarations for packed and
+ unpacked Bios Parameter Block
+
+Author:
+
+ Bill McJohn [BillMc] 24-September-1993
+
+Revision History:
+
+--*/
+
+#if !defined( _IFSUTIL_BPB_DEFN_ )
+#define _IFSUTIL_BPB_DEFN_
+
+#define cOEM 8
+#define cLABEL 11
+#define cSYSID 8
+
+typedef struct _PACKED_BIOS_PARAMETER_BLOCK {
+ UCHAR BytesPerSector[2]; // offset = 0x000
+ UCHAR SectorsPerCluster[1]; // offset = 0x002
+ UCHAR ReservedSectors[2]; // offset = 0x003
+ UCHAR Fats[1]; // offset = 0x005
+ UCHAR RootEntries[2]; // offset = 0x006
+ UCHAR Sectors[2]; // offset = 0x008
+ UCHAR Media[1]; // offset = 0x00A
+ UCHAR SectorsPerFat[2]; // offset = 0x00B
+ UCHAR SectorsPerTrack[2]; // offset = 0x00D
+ UCHAR Heads[2]; // offset = 0x00F
+ UCHAR HiddenSectors[4]; // offset = 0x011
+ UCHAR LargeSectors[4]; // offset = 0x015
+} PACKED_BIOS_PARAMETER_BLOCK; // sizeof = 0x019
+typedef PACKED_BIOS_PARAMETER_BLOCK *PPACKED_BIOS_PARAMETER_BLOCK;
+
+typedef struct BIOS_PARAMETER_BLOCK {
+ USHORT BytesPerSector;
+ UCHAR SectorsPerCluster;
+ USHORT ReservedSectors;
+ UCHAR Fats;
+ USHORT RootEntries;
+ USHORT Sectors;
+ UCHAR Media;
+ USHORT SectorsPerFat;
+ USHORT SectorsPerTrack;
+ USHORT Heads;
+ ULONG HiddenSectors;
+ ULONG LargeSectors;
+} BIOS_PARAMETER_BLOCK;
+typedef BIOS_PARAMETER_BLOCK *PBIOS_PARAMETER_BLOCK;
+
+#if !defined( _UCHAR_DEFINED_ )
+
+#define _UCHAR_DEFINED_
+
+//
+// The following types and macros are used to help unpack the packed and
+// misaligned fields found in the Bios parameter block
+//
+typedef union _UCHAR1 {
+ UCHAR Uchar[1];
+ UCHAR ForceAlignment;
+} UCHAR1, *PUCHAR1;
+
+typedef union _UCHAR2 {
+ UCHAR Uchar[2];
+ USHORT ForceAlignment;
+} UCHAR2, *PUCHAR2;
+
+typedef union _UCHAR4 {
+ UCHAR Uchar[4];
+ ULONG ForceAlignment;
+} UCHAR4, *PUCHAR4;
+
+#define CopyUchar1(Dst,Src) { \
+ *((UCHAR1 *)(Dst)) = *((UNALIGNED UCHAR1 *)(Src)); \
+}
+
+#define CopyUchar2(Dst,Src) { \
+ *((UCHAR2 *)(Dst)) = *((UNALIGNED UCHAR2 *)(Src)); \
+}
+
+#define CopyU2char(Dst,Src) { \
+ *((UNALIGNED UCHAR2 *)(Dst)) = *((UCHAR2 *)(Src)); \
+}
+
+#define CopyUchar4(Dst,Src) { \
+ *((UCHAR4 *)(Dst)) = *((UNALIGNED UCHAR4 *)(Src)); \
+}
+
+#define CopyU4char(Dst, Src) { \
+ *((UNALIGNED UCHAR4 *)(Dst)) = *((UCHAR4 *)(Src)); \
+}
+
+#endif // _UCHAR_DEFINED_
+
+//
+// This macro takes a Packed BPB and fills in its Unpacked equivalent
+//
+#define UnpackBios(Bios,Pbios) { \
+ CopyUchar2(&((Bios)->BytesPerSector), (Pbios)->BytesPerSector ); \
+ CopyUchar1(&((Bios)->SectorsPerCluster), (Pbios)->SectorsPerCluster); \
+ CopyUchar2(&((Bios)->ReservedSectors), (Pbios)->ReservedSectors ); \
+ CopyUchar1(&((Bios)->Fats), (Pbios)->Fats ); \
+ CopyUchar2(&((Bios)->RootEntries), (Pbios)->RootEntries ); \
+ CopyUchar2(&((Bios)->Sectors), (Pbios)->Sectors ); \
+ CopyUchar1(&((Bios)->Media), (Pbios)->Media ); \
+ CopyUchar2(&((Bios)->SectorsPerFat), (Pbios)->SectorsPerFat ); \
+ CopyUchar2(&((Bios)->SectorsPerTrack), (Pbios)->SectorsPerTrack ); \
+ CopyUchar2(&((Bios)->Heads), (Pbios)->Heads ); \
+ CopyUchar4(&((Bios)->HiddenSectors), (Pbios)->HiddenSectors ); \
+ CopyUchar4(&((Bios)->LargeSectors), (Pbios)->LargeSectors ); \
+}
+
+
+//
+// This macro takes an Unpacked BPB and fills in its Packed equivalent
+//
+#define PackBios(Bios,Pbios) { \
+ CopyU2char((Pbios)->BytesPerSector, &((Bios)->BytesPerSector) ); \
+ CopyUchar1((Pbios)->SectorsPerCluster, &((Bios)->SectorsPerCluster)); \
+ CopyU2char((Pbios)->ReservedSectors, &((Bios)->ReservedSectors) ); \
+ CopyUchar1((Pbios)->Fats, &((Bios)->Fats) ); \
+ CopyU2char((Pbios)->RootEntries, &((Bios)->RootEntries) ); \
+ CopyU2char((Pbios)->Sectors, &((Bios)->Sectors) ); \
+ CopyUchar1((Pbios)->Media, &((Bios)->Media) ); \
+ CopyU2char((Pbios)->SectorsPerFat, &((Bios)->SectorsPerFat) ); \
+ CopyU2char((Pbios)->SectorsPerTrack, &((Bios)->SectorsPerTrack) ); \
+ CopyU2char((Pbios)->Heads, &((Bios)->Heads) ); \
+ CopyU4char((Pbios)->HiddenSectors, &((Bios)->HiddenSectors) ); \
+ CopyU4char((Pbios)->LargeSectors, &((Bios)->LargeSectors) ); \
+}
+
+//
+// And now, an extended BPB:
+//
+typedef struct _PACKED_EXTENDED_BIOS_PARAMETER_BLOCK {
+ UCHAR IntelNearJumpCommand[1];
+ UCHAR BootStrapJumpOffset[2];
+ UCHAR OemData[cOEM];
+
+ PACKED_BIOS_PARAMETER_BLOCK Bpb;
+ UCHAR PhysicalDrive[1]; // 0 = removable, 80h = fixed
+ UCHAR CurrentHead[1]; // used for dirty partition info
+ UCHAR Signature[1]; // boot signature
+ UCHAR SerialNumber[4]; // volume serial number
+ UCHAR Label[cLABEL]; // volume label, padded with spaces
+ UCHAR SystemIdText[cSYSID]; // system ID, (e.g. FAT or HPFS)
+ UCHAR StartBootCode; // first byte of boot code
+
+} PACKED_EXTENDED_BIOS_PARAMETER_BLOCK, *PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK;
+
+typedef struct _EXTENDED_BIOS_PARAMETER_BLOCK {
+ UCHAR IntelNearJumpCommand;
+ USHORT BootStrapJumpOffset;
+ UCHAR OemData[cOEM];
+
+ BIOS_PARAMETER_BLOCK Bpb;
+ UCHAR PhysicalDrive;
+ UCHAR CurrentHead;
+ UCHAR Signature;
+ ULONG SerialNumber;
+ UCHAR Label[11];
+ UCHAR SystemIdText[8];
+
+} EXTENDED_BIOS_PARAMETER_BLOCK, *PEXTENDED_BIOS_PARAMETER_BLOCK;
+
+//
+// This macro unpacks a Packed Extended BPB.
+//
+#define UnpackExtendedBios( Bios, Pbios ) { \
+ CopyUchar1( &((Bios)->IntelNearJumpCommand), (Pbios)->IntelNearJumpCommand ); \
+ CopyUchar2( &((Bios)->BootStrapJumpOffset), (Pbios)->BootStrapJumpOffset ); \
+ memcpy( (Bios)->OemData, (Pbios)->OemData, cOEM ); \
+ UnpackBios( &((Bios)->Bpb), &((Pbios)->Bpb)); \
+ CopyUchar1( &((Bios)->PhysicalDrive), (Pbios)->PhysicalDrive ); \
+ CopyUchar1( &((Bios)->CurrentHead), (Pbios)->CurrentHead ); \
+ CopyUchar1( &((Bios)->Signature), (Pbios)->Signature ) \
+ CopyUchar4( &((Bios)->SerialNumber), (Pbios)->SerialNumber ); \
+ memcpy( (Bios)->Label, (Pbios)->Label, cLABEL ); \
+ memcpy( (Bios)->SystemIdText, (Pbios)->SystemIdText, cSYSID ); \
+}
+
+//
+// This macro packs a Packed Extended BPB.
+//
+#define PackExtendedBios( Bios, Pbios ) { \
+ PackBios( &((Bios)->Bpb), &((Pbios)->Bpb)); \
+ CopyUchar1( (Pbios)->IntelNearJumpCommand, &((Bios)->IntelNearJumpCommand) ); \
+ CopyU2char( (Pbios)->BootStrapJumpOffset, &((Bios)->BootStrapJumpOffset) ); \
+ memcpy( (Pbios)->OemData, (Bios)->OemData, cOEM ); \
+ CopyUchar1( (Pbios)->PhysicalDrive, &((Bios)->PhysicalDrive )); \
+ CopyUchar1( (Pbios)->CurrentHead, &((Bios)->CurrentHead )); \
+ CopyUchar1( (Pbios)->Signature, &((Bios)->Signature)); \
+ CopyU4char( (Pbios)->SerialNumber, &((Bios)->SerialNumber )); \
+ memcpy( (Pbios)->Label, (Bios)->Label, cLABEL ); \
+ memcpy( (Pbios)->SystemIdText, (Bios)->SystemIdText, cSYSID ); \
+}
+
+#endif
diff --git a/private/utils/ifsutil/inc/cache.hxx b/private/utils/ifsutil/inc/cache.hxx
new file mode 100644
index 000000000..295cddda7
--- /dev/null
+++ b/private/utils/ifsutil/inc/cache.hxx
@@ -0,0 +1,146 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ cache.hxx
+
+Abstract:
+
+ This class models a cache of equal sized blocks.
+
+Author:
+
+ Norbert Kusters (norbertk) 1-Nov-91
+
+--*/
+
+
+#if !defined(_CACHE_DEFN_)
+
+#define _CACHE_DEFN_
+
+
+#include "bigint.hxx"
+
+
+DECLARE_CLASS(CACHE);
+
+
+class CACHE : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( CACHE );
+
+ VIRTUAL
+ ~CACHE(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN ULONG BlockSize,
+ IN ULONG MaximumNumberOfBlocks
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Read(
+ IN BIG_INT BlockNumber,
+ OUT PVOID Buffer
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ AddBlock(
+ IN BIG_INT BlockNumber,
+ IN PCVOID Buffer
+ );
+
+ NONVIRTUAL
+ VOID
+ Empty(
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryMaxNumBlocks(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QueryBlockSize(
+ ) CONST;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ PVOID* _buffer;
+ PBIG_INT _block_number;
+ ULONG _num_blocks;
+ ULONG _block_size;
+ ULONG _next_add;
+
+};
+
+
+INLINE
+ULONG
+CACHE::QueryMaxNumBlocks(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the number of cache blocks used by this object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The maximum number of cache blocks.
+
+--*/
+{
+ return _num_blocks;
+}
+
+
+INLINE
+ULONG
+CACHE::QueryBlockSize(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the number of bytes per block.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of bytes per block.
+
+--*/
+{
+ return _block_size;
+}
+
+
+#endif // _CACHE_DEFN_
diff --git a/private/utils/ifsutil/inc/cannedsd.hxx b/private/utils/ifsutil/inc/cannedsd.hxx
new file mode 100644
index 000000000..232660e17
--- /dev/null
+++ b/private/utils/ifsutil/inc/cannedsd.hxx
@@ -0,0 +1,153 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ cannedsd.hxx
+
+Abstract:
+
+ This module contains declarations for the CANNED_SECURITY
+ class, which is a repository for the canned Security Descriptors
+ used by the utilities.
+
+ Initializing an object of this type generates the canned
+ security descriptors used by the utilities, which can
+ then be gotten from the object.
+
+ These security descriptors are all in the self-relative
+ format.
+
+Author:
+
+ Bill McJohn (billmc) 04-March-1992
+
+--*/
+
+#if ! defined ( _CANNED_SECURITY_DEFN )
+
+#define _CANNED_SECURITY_DEFN
+
+
+#if defined ( _AUTOCHECK_ )
+#define IFSUTIL_EXPORT
+#elif defined ( _IFSUTIL_MEMBER_ )
+#define IFSUTIL_EXPORT __declspec(dllexport)
+#else
+#define IFSUTIL_EXPORT __declspec(dllimport)
+#endif
+
+
+
+// The IFS utilities use the following kinds of canned Security Descriptors:
+//
+// NoAccess -- No one is granted any access (empty ACL).
+// NoAcl -- The file has no ACL.
+// ReadOnly -- System and Admins can read the file.
+// ReadWrite -- System and Admins can read and write the file.
+// Edit -- System and Admins can read and write the file,
+// and can also change its permissions.
+//
+typedef enum _CANNED_SECURITY_TYPE {
+
+ NoAccessCannedSd,
+ NoAclCannedSd,
+ ReadCannedSd,
+ WriteCannedSd,
+ EditCannedSd
+};
+
+// These security descriptors need the SID's for System and Administrators.
+//
+
+//#define WELL_KNOWN_NAME_SYSTEM L"System"
+//#define WELL_KNOWN_NAME_ADMINS L"Administrators"
+
+#define WELL_KNOWN_NAME_SYSTEM L"SYSTEM"
+#define WELL_KNOWN_NAME_ADMINS L"ADMINS"
+
+
+
+DEFINE_TYPE( _CANNED_SECURITY_TYPE, CANNED_SECURITY_TYPE );
+
+
+class CANNED_SECURITY : public OBJECT {
+
+ public:
+
+ IFSUTIL_EXPORT
+ DECLARE_CONSTRUCTOR( CANNED_SECURITY );
+
+ IFSUTIL_EXPORT
+ ~CANNED_SECURITY(
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Initialize(
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ PVOID
+ GetCannedSecurityDescriptor(
+ IN CANNED_SECURITY_TYPE Type,
+ OUT PULONG SecurityDescriptorLength
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ STATIC
+ BOOLEAN
+ QuerySystemSid(
+ OUT PSID NewSid,
+ IN OUT PULONG Length
+ );
+
+ STATIC
+ BOOLEAN
+ QueryAdminsSid(
+ OUT PSID NewSid,
+ IN OUT PULONG Length
+ );
+
+ STATIC
+ PVOID
+ GenerateCannedSd(
+ IN BOOLEAN DaclPresent,
+ IN ACCESS_MASK GrantedAccess,
+ IN PSID AdminsSid,
+ IN PSID SystemSid,
+ IN HANDLE TokenHandle,
+ OUT PULONG Length
+ );
+
+ STATIC
+ BOOLEAN
+ GenerateCannedAcl(
+ IN PACL AclBuffer,
+ IN ULONG BufferLength,
+ IN ACCESS_MASK GrantedAccess,
+ IN PSID AdminsSid,
+ IN PSID SystemSid
+ );
+
+ ULONG _NoAccessLength, _NoAclLength, _ReadLength,
+ _WriteLength, _EditLength;
+ PVOID _NoAccessSd, _NoAclSd, _ReadSd, _WriteSd, _EditSd;
+};
+
+
+#endif
diff --git a/private/utils/ifsutil/inc/dcache.hxx b/private/utils/ifsutil/inc/dcache.hxx
new file mode 100644
index 000000000..f7ead408d
--- /dev/null
+++ b/private/utils/ifsutil/inc/dcache.hxx
@@ -0,0 +1,166 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ dcache.hxx
+
+Abstract:
+
+ This class models a general cache for reading and writing.
+ The actual implementation of this base class is to not have
+ any cache at all.
+
+Author:
+
+ Norbert Kusters (norbertk) 23-Apr-92
+
+--*/
+
+
+#if !defined(_DRIVE_CACHE_DEFN_)
+
+#define _DRIVE_CACHE_DEFN_
+
+
+#include "bigint.hxx"
+#include "drive.hxx"
+
+
+DECLARE_CLASS(DRIVE_CACHE);
+
+
+class DRIVE_CACHE : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( DRIVE_CACHE );
+
+ VIRTUAL
+ ~DRIVE_CACHE(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN OUT PIO_DP_DRIVE Drive
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Read(
+ IN BIG_INT StartingSector,
+ IN SECTORCOUNT NumberOfSectors,
+ OUT PVOID Buffer
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Write(
+ IN BIG_INT StartingSector,
+ IN SECTORCOUNT NumberOfSectors,
+ IN PVOID Buffer
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Flush(
+ );
+
+ protected:
+
+ NONVIRTUAL
+ BOOLEAN
+ HardRead(
+ IN BIG_INT StartingSector,
+ IN SECTORCOUNT NumberOfSectors,
+ OUT PVOID Buffer
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ HardWrite(
+ IN BIG_INT StartingSector,
+ IN SECTORCOUNT NumberOfSectors,
+ IN PVOID Buffer
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ PIO_DP_DRIVE _drive;
+
+};
+
+
+INLINE
+BOOLEAN
+DRIVE_CACHE::HardRead(
+ IN BIG_INT StartingSector,
+ IN SECTORCOUNT NumberOfSectors,
+ OUT PVOID Buffer
+ )
+/*++
+
+Routine Description:
+
+ This routine reads the requested sectors directly from the disk.
+
+Arguments:
+
+ StartingSector - Supplies the first sector to be read.
+ NumberOfSectors - Supplies the number of sectors to be read.
+ Buffer - Supplies the buffer to read the run of sectors to.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ return DRIVE_CACHE::Read(StartingSector, NumberOfSectors, Buffer);
+}
+
+
+INLINE
+BOOLEAN
+DRIVE_CACHE::HardWrite(
+ IN BIG_INT StartingSector,
+ IN SECTORCOUNT NumberOfSectors,
+ IN PVOID Buffer
+ )
+/*++
+
+Routine Description:
+
+ This routine writes the requested sectors directly to the disk.
+
+Arguments:
+
+ StartingSector - Supplies the first sector to be written.
+ NumberOfSectors - Supplies the number of sectors to be written.
+ Buffer - Supplies the buffer to write the run of sectors from.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ return DRIVE_CACHE::Write(StartingSector, NumberOfSectors, Buffer);
+}
+
+
+#endif // _DRIVE_CACHE_DEFN_
diff --git a/private/utils/ifsutil/inc/digraph.hxx b/private/utils/ifsutil/inc/digraph.hxx
new file mode 100644
index 000000000..768b2f605
--- /dev/null
+++ b/private/utils/ifsutil/inc/digraph.hxx
@@ -0,0 +1,182 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ digraph.hxx
+
+Abstract:
+
+ This class implements a directed graph.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 17-Mar-92
+
+--*/
+
+#if !defined(DIGRAPH_DEFN)
+
+#define DIGRAPH_DEFN
+
+#include "membmgr.hxx"
+
+#if defined ( _AUTOCHECK_ )
+#define IFSUTIL_EXPORT
+#elif defined ( _IFSUTIL_MEMBER_ )
+#define IFSUTIL_EXPORT __declspec(dllexport)
+#else
+#define IFSUTIL_EXPORT __declspec(dllimport)
+#endif
+
+
+DECLARE_CLASS( NUMBER_SET );
+DECLARE_CLASS( BITVECTOR );
+DECLARE_CLASS( INTSTACK );
+DECLARE_CLASS( CONTAINER );
+
+DECLARE_CLASS( DIGRAPH_EDGE );
+
+class DIGRAPH_EDGE : public OBJECT {
+
+ public:
+
+ IFSUTIL_EXPORT
+ DECLARE_CONSTRUCTOR( DIGRAPH_EDGE );
+
+ ULONG Parent;
+ ULONG Child;
+};
+
+
+struct CHILD_ENTRY {
+ CHILD_ENTRY* Next;
+ ULONG Child; // first child described this node
+ ULONG ChildBits[1]; // 0 bit is same as "Child"
+};
+DEFINE_POINTER_TYPES(CHILD_ENTRY);
+
+#define BITS_PER_CHILD_ENTRY (32) // 1 * (bits per ulong)
+
+struct PARENT_ENTRY {
+ PARENT_ENTRY* Next;
+ ULONG Parent;
+ RTL_GENERIC_TABLE Children;
+};
+DEFINE_POINTER_TYPES(PARENT_ENTRY);
+
+
+DECLARE_CLASS( DIGRAPH );
+
+class DIGRAPH : public OBJECT {
+
+ public:
+
+ IFSUTIL_EXPORT
+ DECLARE_CONSTRUCTOR( DIGRAPH );
+
+ IFSUTIL_EXPORT
+ VIRTUAL
+ ~DIGRAPH(
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Initialize(
+ IN ULONG NumberOfNodes
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ AddEdge(
+ IN ULONG Parent,
+ IN ULONG Child
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ RemoveEdge(
+ IN ULONG Parent,
+ IN ULONG Child
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryNumChildren(
+ IN ULONG Parent
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QueryNumParents(
+ IN ULONG Child
+ ) CONST;
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ QueryChildren(
+ IN ULONG Parent,
+ OUT PNUMBER_SET Children
+ ) CONST;
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ QueryParents(
+ IN ULONG Child,
+ OUT PNUMBER_SET Parents
+ ) CONST;
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ QueryParentsWithChildren(
+ OUT PNUMBER_SET Parents,
+ IN ULONG MinimumNumberOfChildren DEFAULT 1
+ ) CONST;
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ EliminateCycles(
+ IN OUT PCONTAINER RemovedEdges
+ );
+
+ private:
+
+ NONVIRTUAL
+ PPARENT_ENTRY
+ GetParentEntry(
+ IN ULONG Parent
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ DescendDigraph(
+ IN ULONG CurrentNode,
+ IN OUT PBITVECTOR Visited,
+ IN OUT PINTSTACK Ancestors,
+ IN OUT PCONTAINER RemovedEdges
+ );
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ PPARENT_ENTRY* _parent_head;
+ ULONG _num_nodes;
+ MEM_BLOCK_MGR _parent_mgr;
+
+};
+
+#endif // DIGRAPH_DEFN
diff --git a/private/utils/ifsutil/inc/dossa.hxx b/private/utils/ifsutil/inc/dossa.hxx
new file mode 100644
index 000000000..ce0870f3d
--- /dev/null
+++ b/private/utils/ifsutil/inc/dossa.hxx
@@ -0,0 +1,713 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ dossa.hxx
+
+Abstract:
+
+ This class models the root of an HPFS or FAT file system.
+
+Author:
+
+ Mark Shavlik (marks) 27-Mar-90
+ Norbert Kusters (norbertk) 25-July-91
+
+Notes:
+
+ The super sector contains data that is common to both FAT and HPFS
+ file system. This data is stored at LBN 0 on such volumes. This
+ data maps a number of things defined by the data structures below.
+
+--*/
+
+#if !defined(DOSSA_DEFN)
+
+#define DOSSA_DEFN
+
+
+#include "supera.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( DOS_SUPERAREA );
+DECLARE_CLASS( WSTRING );
+
+
+
+#define sigBOOTSTRAP (UCHAR)0x29 // boot strap signature
+
+// if any of these values change make sure alignment is not problem,
+// see the alignment tables below for more information.
+#define cOEM 8 // 8 bytes of OEM data
+#define cLABEL 11 // number of bytes in the label
+#define cSYSID 8 // number of bytes in SYS ID
+
+enum PHYSTYPE { // ptype
+ PHYS_REMOVABLE, // physical drive is removable
+ PHYS_FIXED = 0x80 // physical drive is fixed
+};
+
+// The structures below are the aligned version of the above structures.
+// Conversions between the two types is done by the Pack and UnPack methods.
+// Any access to sector 0 data must be done via these aligned types.
+
+//
+// Define the Packed and Unpacked BIOS Parameter Block
+//
+
+// Unaligned Sector 0
+typedef struct UNALIGNED_SECTOR_ZERO {
+ UCHAR IntelNearJumpCommand[1]; // Intel Jump command
+ UCHAR BootStrapJumpOffset[2]; // offset of boot strap code
+ UCHAR OemData[cOEM]; // OEM data
+ UCHAR BytesPerSector[2]; // BPB
+ UCHAR SectorsPerCluster[1]; //
+ UCHAR ReservedSectors[2]; //
+ UCHAR Fats[1]; //
+ UCHAR RootEntries[2]; //
+ UCHAR Sectors[2]; //
+ UCHAR Media[1]; //
+ UCHAR SectorsPerFat[2]; //
+ UCHAR SectorsPerTrack[2]; //
+ UCHAR Heads[2]; //
+ UCHAR HiddenSectors[4]; //
+ UCHAR LargeSectors[4]; //
+ UCHAR PhysicalDrive[1]; // 0 = removable, 80h = fixed
+ UCHAR CurrentHead[1]; // not used by fs utils
+ UCHAR Signature[1]; // boot signature
+ UCHAR SerialNumber[4]; // serial number
+ UCHAR Label[cLABEL]; // volume label, aligned padded
+ UCHAR SystemIdText[cSYSID]; // system ID, FAT for example
+ UCHAR StartBootCode; // First byte of boot code
+} *PUNALIGNED_SECTOR_ZERO;
+
+// Aligned Sector 0
+typedef struct ALIGNED_SECTOR_ZERO {
+ UCHAR IntelNearJumpCommand; // Intel Jump command
+ USHORT BootStrapJumpOffset; // offset of boot strap code
+ UCHAR OemData[cOEM]; // OEM data
+ USHORT BytesPerSector;
+ UCHAR SectorsPerCluster;
+ USHORT ReservedSectors;
+ UCHAR Fats;
+ USHORT RootEntries;
+ USHORT SectorCount_16bits; // 16 bit count
+ UCHAR MediaByte;
+ USHORT SectorsPerFat;
+ USHORT SectorsPerTrack;
+ USHORT Heads;
+ ULONG HiddenSectors;
+ ULONG SectorCount_32bits; // 32 bit count
+ UCHAR PhysicalDrive; // 0 = removable, 80h = fixed
+ UCHAR CurrentHead; // not used by fs utils
+ UCHAR Signature; // boot signature
+ ULONG SerialNumber; // serial number
+ UCHAR Label[cLABEL]; // volume label, aligned padded
+ UCHAR SystemIdText[cSYSID]; // system ID
+} *PALIGNED_SECTOR_ZERO;
+
+//
+// The following types and macros are used to help unpack the packed and
+// misaligned fields found in the Bios parameter block
+//
+#if !defined( _UCHAR_DEFINED_ )
+
+#define _UCHAR_DEFINED_
+
+// This code is taken directly from the NT HPFS code
+
+typedef union _UCHAR1 {
+ UCHAR Uchar[1];
+ UCHAR ForceAlignment;
+} UCHAR1, *PUCHAR1;
+
+typedef union _UCHAR2 {
+ UCHAR Uchar[2];
+ USHORT ForceAlignment;
+} UCHAR2, *PUCHAR2;
+
+typedef union _UCHAR4 {
+ UCHAR Uchar[4];
+ ULONG ForceAlignment;
+} UCHAR4, *PUCHAR4;
+
+//
+// This macro copies an unaligned src byte to an aligned dst byte
+//
+
+#define CopyUchar1(Dst,Src) { \
+ ((PUCHAR1)(Dst))->Uchar[0] = ((PUCHAR1)(Src))->Uchar[0]; \
+ }
+
+//
+// This macro copies an unaligned src word to an aligned dst word
+//
+
+#define CopyUchar2(Dst,Src) { \
+ ((PUCHAR2)(Dst))->Uchar[0] = ((PUCHAR2)(Src))->Uchar[0]; \
+ ((PUCHAR2)(Dst))->Uchar[1] = ((PUCHAR2)(Src))->Uchar[1]; \
+ }
+
+//
+// This macro copies an unaligned src longword to an aligned dsr longword
+//
+
+#define CopyUchar4(Dst,Src) { \
+ ((PUCHAR4)(Dst))->Uchar[0] = ((PUCHAR4)(Src))->Uchar[0]; \
+ ((PUCHAR4)(Dst))->Uchar[1] = ((PUCHAR4)(Src))->Uchar[1]; \
+ ((PUCHAR4)(Dst))->Uchar[2] = ((PUCHAR4)(Src))->Uchar[2]; \
+ ((PUCHAR4)(Dst))->Uchar[3] = ((PUCHAR4)(Src))->Uchar[3]; \
+ }
+
+#endif // _UCHAR_DEFINED_
+
+//
+// This macro Uncopies an unaligned src byte to an aligned dst byte
+//
+
+#define UnCopyUchar1(Dst,Src) { \
+ ((PUCHAR1)(Src))->Uchar[0] = ((PUCHAR1)(Dst))->Uchar[0]; \
+ }
+
+//
+// This macro Uncopies an unaligned src word to an aligned dst word
+//
+
+#define UnCopyUchar2(Dst,Src) { \
+ ((PUCHAR2)(Src))->Uchar[0] = ((PUCHAR2)(Dst))->Uchar[0]; \
+ ((PUCHAR2)(Src))->Uchar[1] = ((PUCHAR2)(Dst))->Uchar[1]; \
+ }
+
+//
+// This macro Uncopies an unaligned src longword to an aligned dst longword
+//
+
+#define UnCopyUchar4(Dst,Src) { \
+ ((PUCHAR4)(Src))->Uchar[0] = ((PUCHAR4)(Dst))->Uchar[0]; \
+ ((PUCHAR4)(Src))->Uchar[1] = ((PUCHAR4)(Dst))->Uchar[1]; \
+ ((PUCHAR4)(Src))->Uchar[2] = ((PUCHAR4)(Dst))->Uchar[2]; \
+ ((PUCHAR4)(Src))->Uchar[3] = ((PUCHAR4)(Dst))->Uchar[3]; \
+ }
+
+// the text for the oem data field
+#define OEMTEXT "MSDOS5.0"
+#define OEMTEXTLENGTH 8
+
+
+class DOS_SUPERAREA : public SUPERAREA {
+
+ public:
+
+ VIRTUAL
+ ~DOS_SUPERAREA(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Read(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Write(
+ );
+
+ VIRTUAL
+ PVOID
+ GetBuf(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Create(
+ IN PCNUMBER_SET BadSectors,
+ IN OUT PMESSAGE Message,
+ IN PCWSTRING Label DEFAULT NULL,
+ IN ULONG ClusterSize DEFAULT 0
+ ) PURE;
+
+ VIRTUAL
+ BOOLEAN
+ VerifyAndFix(
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose DEFAULT FALSE,
+ IN BOOLEAN OnlyIfDirty DEFAULT FALSE,
+ IN BOOLEAN RecoverFree DEFAULT FALSE,
+ IN BOOLEAN RecoverAlloc DEFAULT FALSE
+ ) PURE;
+
+ VIRTUAL
+ BOOLEAN
+ RecoverFile(
+ IN PCWSTRING FullPathFileName,
+ IN OUT PMESSAGE Message
+ ) PURE;
+
+ NONVIRTUAL
+ PALIGNED_SECTOR_ZERO
+ GetSectorZero(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsFormatted(
+ ) CONST;
+
+ VIRTUAL
+ PARTITION_SYSTEM_ID
+ QuerySystemId(
+ ) CONST PURE;
+
+ NONVIRTUAL
+ SECTORCOUNT
+ QuerySectors(
+ ) CONST;
+
+ VIRTUAL
+ SECTORCOUNT
+ QueryFreeSectors(
+ ) CONST PURE;
+
+ NONVIRTUAL
+ VOLID
+ SetVolId(
+ IN VOLID VolId
+ );
+
+ NONVIRTUAL
+ VOLID
+ QueryVolId(
+ ) CONST;
+
+ NONVIRTUAL
+ VOLID
+ CreateVolId(
+ );
+
+ NONVIRTUAL
+ UCHAR
+ QueryMediaByte(
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ QueryLabel(
+ OUT PWSTRING Label
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ SetLabel(
+ IN PCWSTRING NewLabel
+ );
+
+ STATIC
+ BOOLEAN
+ IsValidString(
+ IN PCWSTRING String
+ );
+
+ protected:
+
+ DECLARE_CONSTRUCTOR( DOS_SUPERAREA );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN SECTORCOUNT NumberOfSectors,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CreateBootSector(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ VerifyBootSector(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ SetBpb(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PackSectorZero(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ UnPackSectorZero(
+ );
+
+ ALIGNED_SECTOR_ZERO _sector_zero;
+
+ private:
+
+ PUCHAR _sector_sig; // sector signature
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ ULONG
+ QuerySecMeg(
+ IN ULONG MegaBytes
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ SetOemData(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetBootCode(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetBootSignature(
+ IN UCHAR Signature DEFAULT sigBOOTSTRAP
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetSignature(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetPhysicalDriveType(
+ IN PHYSTYPE PhysType
+ );
+
+};
+
+
+INLINE
+BOOLEAN
+DOS_SUPERAREA::Read(
+ )
+/*++
+
+Routine Description:
+
+ This routine calls SECRUN's read routine and then unpacks the
+ sectorzero data into a local structure.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ return SECRUN::Read() && UnPackSectorZero();
+}
+
+
+INLINE
+BOOLEAN
+DOS_SUPERAREA::Write(
+ )
+/*++
+
+Routine Description:
+
+ This routine packs the sector zero structure in the SECRUN and then
+ calls SECRUN's write routine.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ return PackSectorZero() && SECRUN::Write();
+}
+
+
+INLINE
+PVOID
+DOS_SUPERAREA::GetBuf(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the beginning of the read/write
+ buffer.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to a read/write buffer.
+
+--*/
+{
+ return PackSectorZero() ? SECRUN::GetBuf() : NULL;
+}
+
+
+INLINE
+PALIGNED_SECTOR_ZERO
+DOS_SUPERAREA::GetSectorZero(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the unpacked version of sector zero.
+ The values modified here will take effect on disk after a write.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to an unpacked sector zero.
+
+--*/
+{
+ return &_sector_zero;
+}
+
+
+INLINE
+SECTORCOUNT
+DOS_SUPERAREA::QuerySectors(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of sectors on the volume according
+ to the file system.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of sectors on the volume according to the file system.
+
+--*/
+{
+ return _sector_zero.SectorCount_16bits ? _sector_zero.SectorCount_16bits :
+ _sector_zero.SectorCount_32bits;
+}
+
+
+INLINE
+VOLID
+DOS_SUPERAREA::SetVolId(
+ IN VOLID VolId
+ )
+/*++
+
+Routine Description:
+
+ This routine puts the volume ID into the super area's data.
+
+Arguments:
+
+ VolId - The new volume ID.
+
+Return Value:
+
+ The volume ID that was put.
+
+--*/
+{
+ return _sector_zero.SerialNumber = VolId;
+}
+
+
+INLINE
+VOLID
+DOS_SUPERAREA::CreateVolId(
+ )
+/*++
+
+Routine Description:
+
+ This routine puts a new volume identifier in the super area.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The volume id that was created.
+
+--*/
+{
+ return SetVolId(ComputeVolId());
+}
+
+
+INLINE
+ULONG
+DOS_SUPERAREA::QuerySecMeg(
+ IN ULONG MegaBytes
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of sectors contained in 'MegaBytes'
+ megabytes.
+
+Arguments:
+
+ MegaBytes - Supplies the number of megabytes.
+
+Return Value:
+
+ The number of sectors contained in 'MegaBytes' megabytes.
+
+--*/
+{
+ return ( (MegaBytes<<20) / _drive->QuerySectorSize());
+}
+
+
+INLINE
+BOOLEAN
+DOS_SUPERAREA::SetOemData(
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the OEM data in the super area.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ memcpy( (void*)_sector_zero.OemData, (void*)OEMTEXT, OEMTEXTLENGTH);
+ return TRUE;
+}
+
+
+INLINE
+BOOLEAN
+DOS_SUPERAREA::SetBootSignature(
+ IN UCHAR Signature
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the boot signature in the super area.
+
+Arguments:
+
+ Signature - Supplies the character to set the signature to.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ _sector_zero.Signature = Signature;
+ return TRUE;
+}
+
+
+INLINE
+VOLID
+DOS_SUPERAREA::QueryVolId(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine fetches the volume ID from the super area's data.
+ This routine will return 0 if volume serial numbers are not
+ supported by the partition.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The volume ID residing in the super area.
+
+--*/
+{
+ return (_sector_zero.Signature == 0x28 || _sector_zero.Signature == 0x29) ?
+ _sector_zero.SerialNumber : 0;
+}
+
+
+INLINE
+UCHAR
+DOS_SUPERAREA::QueryMediaByte(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine fetches the media byte from the super area's data.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The media byte residing in the super area.
+
+--*/
+{
+ return _sector_zero.MediaByte;
+}
+
+
+#endif // DOSSA_DEFN
diff --git a/private/utils/ifsutil/inc/drive.hxx b/private/utils/ifsutil/inc/drive.hxx
new file mode 100644
index 000000000..56ecc613c
--- /dev/null
+++ b/private/utils/ifsutil/inc/drive.hxx
@@ -0,0 +1,1076 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ drive.hxx
+
+Abstract:
+
+ The drive class hierarchy models the concept of a drive in various
+ stages. It looks like this:
+
+ DRIVE
+ DP_DRIVE
+ IO_DP_DRIVE
+ LOG_IO_DP_DRIVE
+ PHYS_IO_DP_DRIVE
+
+ DRIVE
+ -----
+
+ DRIVE implements a container for the drive path which is recognizable
+ by the file system. 'Initialize' takes the path as an argument so
+ that it can be later queried with 'GetNtDriveName'.
+
+
+ DP_DRIVE
+ --------
+
+ DP_DRIVE (Drive Parameters) implements queries for the geometry of the
+ drive. 'Initiliaze' queries the information from the drive. What
+ is returned is the default drive geometry for the drive. The user
+ may ask by means of 'IsSupported' if the physical device will support
+ another MEDIA_TYPE.
+
+ A protected member function called 'SetMediaType' allows the a derived
+ class to set the MEDIA_TYPE to another media type which is supported
+ by the device. This method is protected because only a low-level
+ format will actually change the media type.
+
+
+ IO_DP_DRIVE
+ -----------
+
+ IO_DP_DRIVE implements the reading a writting of sectors as well
+ as 'Lock', 'Unlock', and 'Dismount'. The 'FormatVerifyFloppy' method
+ does a low-level format. A version of this method allows the user
+ to specify a new MEDIA_TYPE for the media.
+
+
+ LOG_IO_DP_DRIVE and PHYS_IO_DP_DRIVE
+ ------------------------------------
+
+ LOG_IO_DP_DRIVE models logical drive. PHYS_IO_DP_DRIVE models a
+ physical drive. Currently both implementations just initialize
+ an IO_DP_DRIVE. The difference is in the drive path specified.
+ Some drive paths are to logical drives and others are to physical
+ drives.
+
+
+Author:
+
+ Mark Shavlik (marks) Jun-90
+ Norbert P. Kusters (norbertk) 22-Feb-91
+
+--*/
+
+
+#if ! defined( DRIVE_DEFN )
+
+#define DRIVE_DEFN
+
+
+#include "wstring.hxx"
+#include "bigint.hxx"
+
+#if defined ( _AUTOCHECK_ )
+#define IFSUTIL_EXPORT
+#elif defined ( _IFSUTIL_MEMBER_ )
+#define IFSUTIL_EXPORT __declspec(dllexport)
+#else
+#define IFSUTIL_EXPORT __declspec(dllimport)
+#endif
+
+
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( DRIVE );
+DECLARE_CLASS( DP_DRIVE );
+DECLARE_CLASS( IO_DP_DRIVE );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( PHYS_IO_DP_DRIVE );
+DECLARE_CLASS( NUMBER_SET );
+DECLARE_CLASS( MESSAGE );
+DECLARE_CLASS( DRIVE_CACHE );
+
+#if !defined _PARTITION_SYSTEM_ID_DEFINED_
+#define _PARTITION_SYSTEM_ID_DEFINED_
+enum PARTITION_SYSTEM_ID {
+ SYSID_NONE = 0,
+ SYSID_FAT12BIT = 1,
+ SYSID_FAT16BIT = 4,
+ SYSID_FAT32MEG = 6,
+ SYSID_IFS = 7,
+ SYSID_EXTENDED = 5
+};
+#endif
+
+DEFINE_TYPE( ULONG, SECTORCOUNT ); // count of sectors
+DEFINE_TYPE( ULONG, LBN ); // Logical buffer number
+
+DEFINE_POINTER_AND_REFERENCE_TYPES( MEDIA_TYPE );
+DEFINE_POINTER_AND_REFERENCE_TYPES( DISK_GEOMETRY );
+
+struct _DRTYPE {
+ MEDIA_TYPE MediaType;
+ ULONG SectorSize;
+ BIG_INT Sectors; // w/o hidden sectors.
+ BIG_INT HiddenSectors;
+ SECTORCOUNT SectorsPerTrack;
+ ULONG Heads;
+};
+
+// Hosted volumes always have certain values fixed. Define
+// those values here:
+//
+CONST MEDIA_TYPE HostedDriveMediaType = FixedMedia;
+CONST ULONG HostedDriveSectorSize = 512;
+CONST BIG_INT HostedDriveHiddenSectors = 0;
+CONST SECTORCOUNT HostedDriveSectorsPerTrack = 0x11;
+CONST SECTORCOUNT HostedDriveHeads = 6;
+
+DEFINE_TYPE( struct _DRTYPE, DRTYPE );
+
+
+class DRIVE : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR(DRIVE);
+
+ VIRTUAL
+ ~DRIVE(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ PCWSTRING
+ GetNtDriveName(
+ ) CONST;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ DSTRING _name;
+
+};
+
+
+INLINE
+PCWSTRING
+DRIVE::GetNtDriveName(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns a pointer string containing the NT drive name.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to a string containing the NT drive name.
+
+--*/
+{
+ return &_name;
+}
+
+
+class DP_DRIVE : public DRIVE {
+
+ public:
+
+ IFSUTIL_EXPORT
+ DECLARE_CONSTRUCTOR(DP_DRIVE);
+
+ VIRTUAL
+ IFSUTIL_EXPORT
+ ~DP_DRIVE(
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Initialize(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN BOOLEAN IsTransient DEFAULT FALSE,
+ IN BOOLEAN ExclusiveWrite DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Initialize(
+ IN PCWSTRING NtDriveName,
+ IN PCWSTRING HostFileName,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN BOOLEAN IsTransient DEFAULT FALSE,
+ IN BOOLEAN ExclusiveWrite DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ MEDIA_TYPE
+ QueryMediaType(
+ ) CONST;
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ UCHAR
+ QueryMediaByte(
+ ) CONST;
+
+ VIRTUAL
+ IFSUTIL_EXPORT
+ ULONG
+ QuerySectorSize(
+ ) CONST;
+
+ VIRTUAL
+ IFSUTIL_EXPORT
+ BIG_INT
+ QuerySectors(
+ ) CONST;
+
+ NONVIRTUAL
+ BIG_INT
+ QueryHiddenSectors(
+ ) CONST;
+
+ NONVIRTUAL
+ SECTORCOUNT
+ QuerySectorsPerTrack(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QueryHeads(
+ ) CONST;
+
+ NONVIRTUAL
+ BIG_INT
+ QueryTracks(
+ ) CONST;
+
+ NONVIRTUAL
+ BIG_INT
+ QueryCylinders(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsRemovable(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsFloppy(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsSuperFloppy(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsFixed(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsSupported(
+ IN MEDIA_TYPE MediaType
+ ) CONST;
+
+ NONVIRTUAL
+ PCDRTYPE
+ GetSupportedList(
+ OUT PINT NumSupported
+ ) CONST;
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ MEDIA_TYPE
+ QueryRecommendedMediaType(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QueryAlignmentMask(
+ ) CONST;
+
+ NONVIRTUAL
+ NTSTATUS
+ QueryLastNtStatus(
+ ) CONST;
+
+ NONVIRTUAL
+ HANDLE
+ GetVolumeFileHandle(
+ ) CONST;
+
+#if defined ( DBLSPACE_ENABLED )
+ NONVIRTUAL
+ BOOLEAN
+ QueryMountedFileSystemName(
+ OUT PWSTRING FileSystemName,
+ OUT PBOOLEAN IsCompressed
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ MountCvf(
+ IN PCWSTRING CvfName,
+ IN PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetCvfSize(
+ IN ULONG Size
+ );
+#endif // DBLSPACE_ENABLED
+
+
+ protected:
+
+ NONVIRTUAL
+ BOOLEAN
+ SetMediaType(
+ IN MEDIA_TYPE MediaType DEFAULT Unknown
+ );
+
+
+ // On a normal drive, _handle is a handle to the drive
+ // and _alternate_drive is zero. On a hosted drive,
+ // however, _handle is a handle to the file which
+ // contains the volume and _alternate_handle is a handle
+ // to the volume itself.
+ //
+ // When the drive object opens a hosted volume, it must
+ // first make the host file non-readonly. It caches the
+ // old attributes of the file so that it can reset them.
+ //
+ HANDLE _handle;
+ HANDLE _alternate_handle;
+ BOOLEAN _hosted_drive;
+ ULONG _old_attributes;
+ NTSTATUS _last_status;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ STATIC
+ NTSTATUS
+ OpenDrive(
+ IN PCWSTRING NtDriveName,
+ IN ACCESS_MASK DesiredAccess,
+ IN BOOLEAN ExclusiveWrite,
+ OUT PHANDLE Handle,
+ OUT PULONG Alignment,
+ IN OUT PMESSAGE Message
+ );
+
+ STATIC
+ VOID
+ DiskGeometryToDriveType(
+ IN PCDISK_GEOMETRY DiskGeometry,
+ OUT PDRTYPE DriveType
+ );
+
+ STATIC
+ VOID
+ DiskGeometryToDriveType(
+ IN PCDISK_GEOMETRY DiskGeometry,
+ IN BIG_INT NumSectors,
+ IN BIG_INT NumHiddenSectors,
+ OUT PDRTYPE DriveType
+ );
+
+ DRTYPE _actual;
+ PDRTYPE _supported_list;
+ INT _num_supported;
+ ULONG _alignment_mask;
+ BOOLEAN _super_floppy;
+
+};
+
+
+INLINE
+MEDIA_TYPE
+DP_DRIVE::QueryMediaType(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the media type.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The media type.
+
+--*/
+{
+ return _actual.MediaType;
+}
+
+
+INLINE
+BIG_INT
+DP_DRIVE::QueryHiddenSectors(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of hidden sectors.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of hidden sectors.
+
+--*/
+{
+ return _actual.HiddenSectors;
+}
+
+
+INLINE
+SECTORCOUNT
+DP_DRIVE::QuerySectorsPerTrack(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of sectors per track.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of sectors per track.
+
+--*/
+{
+ return _actual.SectorsPerTrack;
+}
+
+
+INLINE
+ULONG
+DP_DRIVE::QueryHeads(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of heads.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of heads.
+
+--*/
+{
+ return _actual.Heads;
+}
+
+
+INLINE
+BIG_INT
+DP_DRIVE::QueryTracks(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of tracks on the disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of tracks on the disk.
+
+--*/
+{
+ return (_actual.Sectors + _actual.HiddenSectors)/_actual.SectorsPerTrack;
+}
+
+
+INLINE
+BIG_INT
+DP_DRIVE::QueryCylinders(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of cylinders on the disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of cylinders on the disk.
+
+--*/
+{
+ return QueryTracks()/_actual.Heads;
+}
+
+
+INLINE
+BOOLEAN
+DP_DRIVE::IsRemovable(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes whether or not the disk is removable.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - The disk is not removable.
+ TRUE - The disk is removable.
+
+--*/
+{
+ return _actual.MediaType != FixedMedia;
+}
+
+
+INLINE
+BOOLEAN
+DP_DRIVE::IsFloppy(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes whether or not the disk is a floppy disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - The disk is not a floppy disk.
+ TRUE - The disk is a floppy disk.
+
+--*/
+{
+ return IsRemovable() && _actual.MediaType != RemovableMedia;
+}
+
+INLINE
+BOOLEAN
+DP_DRIVE::IsSuperFloppy(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine tells whether the media is non-floppy unpartitioned
+ removable media.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - The disk is not a floppy disk.
+ TRUE - The disk is a floppy disk.
+
+--*/
+{
+ return _super_floppy;
+}
+
+
+INLINE
+BOOLEAN
+DP_DRIVE::IsFixed(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes whether or not the disk is a fixed disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - The disk is not a fixed disk.
+ TRUE - The disk is a fixed disk.
+
+--*/
+{
+ return _actual.MediaType == FixedMedia;
+}
+
+
+INLINE
+PCDRTYPE
+DP_DRIVE::GetSupportedList(
+ OUT PINT NumSupported
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns a list of the supported media types by the device.
+
+Arguments:
+
+ NumSupported - Returns the number of elements in the list.
+
+Return Value:
+
+ A list of the supported media types by the device.
+
+--*/
+{
+ *NumSupported = _num_supported;
+ return _supported_list;
+}
+
+
+INLINE
+ULONG
+DP_DRIVE::QueryAlignmentMask(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the memory alignment requirement for the drive.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The memory alignment requirement for the drive in the form of a mask.
+
+--*/
+{
+ return _alignment_mask;
+}
+
+
+INLINE
+NTSTATUS
+DP_DRIVE::QueryLastNtStatus(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the last NT status value.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The last NT status value.
+
+--*/
+{
+ return _last_status;
+}
+
+
+class IO_DP_DRIVE : public DP_DRIVE {
+
+ FRIEND class DRIVE_CACHE;
+
+ public:
+
+ VIRTUAL
+ ~IO_DP_DRIVE(
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Read(
+ IN BIG_INT StartingSector,
+ IN SECTORCOUNT NumberOfSectors,
+ OUT PVOID Buffer
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Write(
+ IN BIG_INT StartingSector,
+ IN SECTORCOUNT NumberOfSectors,
+ IN PVOID Buffer
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Verify(
+ IN BIG_INT StartingSector,
+ IN BIG_INT NumberOfSectors
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Verify(
+ IN BIG_INT StartingSector,
+ IN BIG_INT NumberOfSectors,
+ IN OUT PNUMBER_SET BadSectors
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Lock(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Unlock(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ForceDirty(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FormatVerifyFloppy(
+ IN MEDIA_TYPE MediaType DEFAULT Unknown,
+ IN OUT PNUMBER_SET BadSectors DEFAULT NULL,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN BOOLEAN IsDmfFormat DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ VOID
+ SetCache(
+ IN OUT PDRIVE_CACHE Cache
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ FlushCache(
+ );
+
+ // Note that the following three methods, provided to
+ // support SimBad, are _not_ in ifsutil.dll.
+
+ NONVIRTUAL
+ BOOLEAN
+ EnableBadSectorSimulation(
+ IN BOOLEAN Enable
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SimulateBadSectors(
+ IN BOOLEAN Add,
+ IN ULONG Count,
+ IN PLBN SectorArray,
+ IN NTSTATUS Status,
+ IN ULONG AccessType
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QuerySimulatedBadSectors(
+ OUT PULONG Count,
+ IN ULONG MaximumLbnsInBuffer,
+ OUT PLBN SectorArray,
+ OUT PULONG AccessTypeArray
+ );
+
+
+ protected:
+
+ DECLARE_CONSTRUCTOR(IO_DP_DRIVE);
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN BOOLEAN ExclusiveWrite DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PCWSTRING NtDriveName,
+ IN PCWSTRING HostFileName,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN BOOLEAN ExclusiveWrite DEFAULT FALSE
+ );
+
+ private:
+
+ BOOLEAN _is_locked;
+ BOOLEAN _is_exclusive_write;
+ PDRIVE_CACHE _cache;
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ VerifyWithRead(
+ IN BIG_INT StartingSector,
+ IN BIG_INT NumberOfSectors
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ HardRead(
+ IN BIG_INT StartingSector,
+ IN SECTORCOUNT NumberOfSectors,
+ OUT PVOID Buffer
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ HardWrite(
+ IN BIG_INT StartingSector,
+ IN SECTORCOUNT NumberOfSectors,
+ IN PVOID Buffer
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Dismount(
+ );
+
+};
+
+
+class LOG_IO_DP_DRIVE : public IO_DP_DRIVE {
+
+ public:
+
+ IFSUTIL_EXPORT
+ DECLARE_CONSTRUCTOR(LOG_IO_DP_DRIVE);
+
+ VIRTUAL
+ IFSUTIL_EXPORT
+ ~LOG_IO_DP_DRIVE(
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Initialize(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN BOOLEAN ExclusiveWrite DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ SetSystemId(
+ IN PARTITION_SYSTEM_ID SystemId
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Initialize(
+ IN PCWSTRING NtDriveName,
+ IN PCWSTRING HostFileName,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN BOOLEAN ExclusiveWrite DEFAULT FALSE
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+};
+
+
+INLINE
+VOID
+LOG_IO_DP_DRIVE::Construct(
+ )
+/*++
+
+Routine Description:
+
+ Constructor for LOG_IO_DP_DRIVE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+}
+
+
+class PHYS_IO_DP_DRIVE : public IO_DP_DRIVE {
+
+ public:
+
+ DECLARE_CONSTRUCTOR(PHYS_IO_DP_DRIVE);
+
+ VIRTUAL
+ ~PHYS_IO_DP_DRIVE(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN BOOLEAN ExclusiveWrite DEFAULT FALSE
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+};
+
+
+INLINE
+VOID
+PHYS_IO_DP_DRIVE::Construct(
+ )
+/*++
+
+Routine Description:
+
+ Constructor for PHYS_IO_DP_DRIVE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+}
+
+INLINE
+HANDLE
+DP_DRIVE::GetVolumeFileHandle(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine is a hack for NTFS->OFS convert... it returns the
+ handle open on the ntfs volume-file.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The handle.
+
+--*/
+{
+ return _handle;
+}
+
+#endif // DRIVE_DEFN
diff --git a/private/utils/ifsutil/inc/ifssys.hxx b/private/utils/ifsutil/inc/ifssys.hxx
new file mode 100644
index 000000000..75ec856a9
--- /dev/null
+++ b/private/utils/ifsutil/inc/ifssys.hxx
@@ -0,0 +1,245 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ifssys.hxx
+
+Abstract:
+
+ This module contains the definition for the IFS_SYSTEM class.
+ The IFS_SYSTEM class is an abstract class which offers an
+ interface for communicating with the underlying operating system
+ on specific IFS issues.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 03-Sep-1991
+
+--*/
+
+#if ! defined( _IFS_SYSTEM_ )
+
+#define _IFS_SYSTEM_
+
+#if defined ( _AUTOCHECK_ )
+#define IFSUTIL_EXPORT
+#elif defined ( _IFSUTIL_MEMBER_ )
+#define IFSUTIL_EXPORT __declspec(dllexport)
+#else
+#define IFSUTIL_EXPORT __declspec(dllimport)
+#endif
+
+
+DECLARE_CLASS( CANNED_SECURITY );
+DECLARE_CLASS( WSTRING );
+DECLARE_CLASS( WSTRING );
+DECLARE_CLASS( BIG_INT );
+DECLARE_CLASS( IFS_SYSTEM );
+
+class IFS_SYSTEM {
+
+ public:
+
+ STATIC
+ IFSUTIL_EXPORT
+ BOOLEAN
+ QueryFileSystemName(
+ IN PCWSTRING NtDriveName,
+ OUT PWSTRING FileSystemName,
+ OUT PNTSTATUS ErrorCode DEFAULT NULL
+ );
+
+ STATIC
+ IFSUTIL_EXPORT
+ BOOLEAN
+ DosDriveNameToNtDriveName(
+ IN PCWSTRING DosDriveName,
+ OUT PWSTRING NtDriveName
+ );
+
+ STATIC
+ IFSUTIL_EXPORT
+ BOOLEAN
+ QueryFreeDiskSpace(
+ IN PCWSTRING DosDriveName,
+ OUT PBIG_INT BytesFree
+ );
+
+ STATIC
+ IFSUTIL_EXPORT
+ VOID
+ QueryHpfsTime(
+ OUT PULONG HpfsTime
+ );
+
+ STATIC
+ IFSUTIL_EXPORT
+ VOID
+ QueryNtfsTime(
+ OUT PLARGE_INTEGER NtfsTime
+ );
+
+ STATIC
+ VOID
+ ConvertNtfsTimeToHpfsTime(
+ IN LARGE_INTEGER NtfsTime,
+ OUT PULONG HpfsTime
+ );
+
+ STATIC
+ IFSUTIL_EXPORT
+ VOID
+ ConvertHpfsTimeToNtfsTime(
+ IN ULONG HpfsTime,
+ OUT PLARGE_INTEGER NtfsTime
+ );
+
+ STATIC
+ VOID
+ Reboot(
+ IN BOOLEAN PowerOff DEFAULT FALSE
+ );
+
+ STATIC
+ IFSUTIL_EXPORT
+ PCANNED_SECURITY
+ GetCannedSecurity(
+ );
+
+ STATIC
+ IFSUTIL_EXPORT
+ BOOLEAN
+ EnableFileSystem(
+ IN PCWSTRING FileSystemName
+ );
+
+ STATIC
+ IFSUTIL_EXPORT
+ BOOLEAN
+ IsFileSystemEnabled(
+ IN PCWSTRING FileSystemName,
+ OUT PBOOLEAN Error DEFAULT NULL
+ );
+
+ STATIC
+ IFSUTIL_EXPORT
+ ULONG
+ QueryPageSize(
+ );
+
+ STATIC
+ IFSUTIL_EXPORT
+ BOOLEAN
+ QueryCanonicalNtDriveName(
+ IN PCWSTRING NtDriveName,
+ OUT PWSTRING CanonicalNtDriveName
+ );
+
+ STATIC
+ BOOLEAN
+ QueryNtSystemDriveName(
+ OUT PWSTRING NtSystemDriveName
+ );
+
+ STATIC
+ BOOLEAN
+ QuerySystemEnvironmentVariableValue(
+ IN PWSTRING VariableName,
+ IN ULONG ValueBufferLength,
+ OUT PVOID ValueBuffer,
+ OUT PUSHORT ValueLength
+ );
+
+ STATIC
+ IFSUTIL_EXPORT
+ BOOLEAN
+ IsArcSystemPartition(
+ IN PCWSTRING NtDriveName,
+ OUT PBOOLEAN Error
+ );
+
+ STATIC
+ BOOLEAN
+ IsThisFat(
+ IN BIG_INT Sectors,
+ IN PVOID BootSectorData
+ );
+
+ STATIC
+ BOOLEAN
+ IsThisHpfs(
+ IN BIG_INT Sectors,
+ IN PVOID BootSectorData,
+ IN PULONG SuperBlock,
+ IN PULONG SpareBlock
+ );
+
+ STATIC
+ IFSUTIL_EXPORT
+ BOOLEAN
+ IsThisNtfs(
+ IN BIG_INT Sectors,
+ IN ULONG SectorSize,
+ IN PVOID BootSectorData
+ );
+
+ STATIC
+ IFSUTIL_EXPORT
+ BOOLEAN
+ FileSetAttributes(
+ IN PCWSTRING FileName,
+ IN ULONG NewFileAttributes,
+ OUT PULONG OldAttributes
+ );
+
+ STATIC
+ BOOLEAN
+ FileSetAttributes(
+ IN HANDLE FileHandle,
+ IN ULONG NewFileAttributes,
+ OUT PULONG OldAttributes
+ );
+
+ STATIC
+ IFSUTIL_EXPORT
+ BOOLEAN
+ WriteToFile(
+ IN PCWSTRING QualifiedFileName,
+ IN PVOID Data,
+ IN ULONG DataLength,
+ IN BOOLEAN Append
+ );
+
+ STATIC
+ IFSUTIL_EXPORT
+ BOOLEAN
+ EnableVolumeCompression(
+ IN PCWSTRING NtDriveName
+ );
+
+ STATIC
+ IFSUTIL_EXPORT
+ BOOLEAN
+ CheckValidSecurityDescriptor(
+ IN ULONG Length,
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor
+ );
+
+ STATIC
+ IFSUTIL_EXPORT
+ BOOLEAN
+ IsVolumeDirty(
+ IN PWSTRING NtDriveName,
+ OUT PBOOLEAN Result
+ );
+
+ private:
+
+ STATIC PCANNED_SECURITY _CannedSecurity;
+
+};
+
+
+#endif // _IFS_SYSTEM_
diff --git a/private/utils/ifsutil/inc/ifsutil.hxx b/private/utils/ifsutil/inc/ifsutil.hxx
new file mode 100644
index 000000000..399c2224a
--- /dev/null
+++ b/private/utils/ifsutil/inc/ifsutil.hxx
@@ -0,0 +1,36 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ifsutil.hxx
+
+Author:
+
+ Rafael Lisitsa (RafaelL) 23-Mar-1995
+
+
+--*/
+
+
+#if !defined ( _IFSUTIL_INCLUDED_ )
+
+#define _IFSUTIL_INCLUDED_
+
+
+// Set up the IFSUTIL_EXPORT macro for exporting from IFSUTIL (if the
+// source file is a member of IFSUTIL) or importing from IFSUTIL (if
+// the source file is a client of IFSUTIL).
+//
+#if defined ( _AUTOCHECK_ )
+#define IFSUTIL_EXPORT
+#elif defined ( _IFSUTIL_MEMBER_ )
+#define IFSUTIL_EXPORT __declspec(dllexport)
+#else
+#define IFSUTIL_EXPORT __declspec(dllimport)
+#endif
+
+
+#endif // _IFSUTIL_INCLUDED_
+
diff --git a/private/utils/ifsutil/inc/intstack.hxx b/private/utils/ifsutil/inc/intstack.hxx
new file mode 100644
index 000000000..6ac36a969
--- /dev/null
+++ b/private/utils/ifsutil/inc/intstack.hxx
@@ -0,0 +1,135 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ intstack.hxx
+
+Abstract:
+
+ This class implements a linked list integer stack.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 28-Dec-90
+
+--*/
+
+#if !defined(INTSTACK_DEFN)
+
+#define INTSTACK_DEFN
+
+#include "bigint.hxx"
+
+#if defined ( _AUTOCHECK_ )
+#define IFSUTIL_EXPORT
+#elif defined ( _IFSUTIL_MEMBER_ )
+#define IFSUTIL_EXPORT __declspec(dllexport)
+#else
+#define IFSUTIL_EXPORT __declspec(dllimport)
+#endif
+
+
+DECLARE_CLASS( INTSTACK );
+
+DEFINE_TYPE( struct _INTNODE, INTNODE );
+
+struct _INTNODE {
+ PINTNODE Next;
+ BIG_INT Data;
+};
+
+class INTSTACK : public OBJECT {
+
+ public:
+
+ IFSUTIL_EXPORT
+ DECLARE_CONSTRUCTOR( INTSTACK );
+
+ VIRTUAL
+ IFSUTIL_EXPORT
+ ~INTSTACK(
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Initialize(
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Push(
+ IN BIG_INT Data
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ VOID
+ Pop(
+ IN ULONG HowMany DEFAULT 1
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BIG_INT
+ Look(
+ IN ULONG Index DEFAULT 0
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QuerySize(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsMember(
+ IN BIG_INT Data
+ ) CONST;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ PINTNODE _stack;
+ ULONG _size;
+
+};
+
+
+INLINE
+ULONG
+INTSTACK::QuerySize(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of elements in the stack.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of elements in the stack.
+
+--*/
+{
+ return _size;
+}
+
+
+#endif // INTSTACK_DEFN
diff --git a/private/utils/ifsutil/inc/mldcopy.hxx b/private/utils/ifsutil/inc/mldcopy.hxx
new file mode 100644
index 000000000..3dc552f6c
--- /dev/null
+++ b/private/utils/ifsutil/inc/mldcopy.hxx
@@ -0,0 +1,35 @@
+#if !defined( _DISK_COPY_MAIN_DEFN_ )
+
+#define _DISK_COPY_MAIN_DEFN_
+
+#if defined ( _AUTOCHECK_ )
+#define IFSUTIL_EXPORT
+#elif defined ( _IFSUTIL_MEMBER_ )
+#define IFSUTIL_EXPORT __declspec(dllexport)
+#else
+#define IFSUTIL_EXPORT __declspec(dllimport)
+#endif
+
+
+DECLARE_CLASS(WSTRING);
+DECLARE_CLASS(MESSAGE);
+
+IFSUTIL_EXPORT
+INT
+DiskCopyMainLoop(
+ IN PCWSTRING SrcNtDriveName,
+ IN PCWSTRING DstNtDriveName,
+ IN PCWSTRING SrcDosDriveName,
+ IN PCWSTRING DstDosDriveName,
+ IN BOOLEAN Verify,
+ IN OUT PMESSAGE Message,
+ IN OUT PMESSAGE PercentMessage DEFAULT NULL
+ );
+
+
+IFSUTIL_EXPORT
+ULONG
+QueryMachineUniqueToken(
+ );
+
+#endif // _DISK_COPY_MAIN_DEFN_
diff --git a/private/utils/ifsutil/inc/numset.hxx b/private/utils/ifsutil/inc/numset.hxx
new file mode 100644
index 000000000..27ecb2adb
--- /dev/null
+++ b/private/utils/ifsutil/inc/numset.hxx
@@ -0,0 +1,261 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ numset.hxx
+
+Abstract:
+
+ This class implements a sparse number set. The number are
+ stored in ascending order.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 10-Jan-91
+
+--*/
+
+#if !defined(NUMBER_SET_DEFN)
+
+#define NUMBER_SET_DEFN
+
+#include "bigint.hxx"
+#include "list.hxx"
+
+#if defined ( _AUTOCHECK_ )
+#define IFSUTIL_EXPORT
+#elif defined ( _IFSUTIL_MEMBER_ )
+#define IFSUTIL_EXPORT __declspec(dllexport)
+#else
+#define IFSUTIL_EXPORT __declspec(dllimport)
+#endif
+
+
+DECLARE_CLASS( NUMBER_SET );
+
+class NUMBER_EXTENT : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( NUMBER_EXTENT );
+
+ BIG_INT Start;
+ BIG_INT Length;
+
+};
+
+
+DEFINE_POINTER_TYPES(NUMBER_EXTENT);
+
+class NUMBER_SET : public OBJECT {
+
+ public:
+
+ IFSUTIL_EXPORT
+ DECLARE_CONSTRUCTOR( NUMBER_SET );
+
+ VIRTUAL
+ IFSUTIL_EXPORT
+ ~NUMBER_SET(
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Initialize(
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Add(
+ IN BIG_INT Number
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ AddStart(
+ IN BIG_INT Number
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ AddNext(
+ IN BIG_INT Number
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Add(
+ IN BIG_INT Start,
+ IN BIG_INT Length
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Add(
+ IN PCNUMBER_SET NumberSet
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ CheckAndAdd(
+ IN BIG_INT Number,
+ OUT PBOOLEAN Duplicate
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Remove(
+ IN BIG_INT Number
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ RemoveAll(
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ CheckAndRemove(
+ IN BIG_INT Number,
+ OUT PBOOLEAN DoesExists
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Remove(
+ IN BIG_INT Start,
+ IN BIG_INT Length
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Remove(
+ IN PCNUMBER_SET NumberSet
+ );
+
+ NONVIRTUAL
+ BIG_INT
+ QueryCardinality(
+ ) CONST;
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BIG_INT
+ QueryNumber(
+ IN BIG_INT Index
+ ) CONST;
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ DoesIntersectSet(
+ IN BIG_INT Start,
+ IN BIG_INT Length
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QueryNumDisjointRanges(
+ ) CONST;
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ VOID
+ QueryDisjointRange(
+ IN ULONG Index,
+ OUT PBIG_INT Start,
+ OUT PBIG_INT Length
+ ) CONST;
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ QueryContainingRange(
+ IN BIG_INT Number,
+ OUT PBIG_INT Start,
+ OUT PBIG_INT Length
+ ) CONST;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ LIST _list;
+ BIG_INT _card;
+ PITERATOR _iterator;
+
+};
+
+
+INLINE
+BIG_INT
+NUMBER_SET::QueryCardinality(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of elements in the set.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of elements in the set.
+
+--*/
+{
+ return _card;
+}
+
+
+INLINE
+ULONG
+NUMBER_SET::QueryNumDisjointRanges(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of disjoint ranges contained
+ in this number set.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of disjoint ranges contained in this number set.
+
+--*/
+{
+ return _list.QueryMemberCount();
+}
+
+
+#endif // NUMBER_SET_DEFN
diff --git a/private/utils/ifsutil/inc/rcache.hxx b/private/utils/ifsutil/inc/rcache.hxx
new file mode 100644
index 000000000..cdc41bc27
--- /dev/null
+++ b/private/utils/ifsutil/inc/rcache.hxx
@@ -0,0 +1,92 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ rcache.hxx
+
+Abstract:
+
+ This class models a read cache of equal sized blocks.
+
+Author:
+
+ Norbert Kusters (norbertk) 23-Apr-92
+
+--*/
+
+
+#if !defined(_READ_CACHE_DEFN_)
+
+#define _READ_CACHE_DEFN_
+
+
+#include "dcache.hxx"
+#include "cache.hxx"
+
+#if defined ( _AUTOCHECK_ )
+#define IFSUTIL_EXPORT
+#elif defined ( _IFSUTIL_MEMBER_ )
+#define IFSUTIL_EXPORT __declspec(dllexport)
+#else
+#define IFSUTIL_EXPORT __declspec(dllimport)
+#endif
+
+
+DECLARE_CLASS(READ_CACHE);
+
+
+class READ_CACHE : public DRIVE_CACHE {
+
+ public:
+
+ IFSUTIL_EXPORT
+ DECLARE_CONSTRUCTOR( READ_CACHE );
+
+ VIRTUAL
+ ~READ_CACHE(
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Initialize(
+ IN OUT PIO_DP_DRIVE Drive,
+ IN ULONG NumberOfCacheBlocks
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Read(
+ IN BIG_INT StartingSector,
+ IN SECTORCOUNT NumberOfSectors,
+ OUT PVOID Buffer
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Write(
+ IN BIG_INT StartingSector,
+ IN SECTORCOUNT NumberOfSectors,
+ IN PVOID Buffer
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ CACHE _cache;
+
+};
+
+
+#endif // _READ_CACHE_DEFN_
diff --git a/private/utils/ifsutil/inc/rwcache.hxx b/private/utils/ifsutil/inc/rwcache.hxx
new file mode 100644
index 000000000..1d4f82247
--- /dev/null
+++ b/private/utils/ifsutil/inc/rwcache.hxx
@@ -0,0 +1,135 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ rwcache.hxx
+
+Abstract:
+
+ This class implements a read write cache.
+
+Author:
+
+ Norbert Kusters (norbertk) 23-Apr-92
+
+--*/
+
+
+#if !defined(_READ_WRITE_CACHE_DEFN_)
+
+#define _READ_WRITE_CACHE_DEFN_
+
+#include "dcache.hxx"
+#include "hmem.hxx"
+#include "numset.hxx"
+
+#if defined ( _AUTOCHECK_ )
+#define IFSUTIL_EXPORT
+#elif defined ( _IFSUTIL_MEMBER_ )
+#define IFSUTIL_EXPORT __declspec(dllexport)
+#else
+#define IFSUTIL_EXPORT __declspec(dllimport)
+#endif
+
+
+struct RW_CACHE_BLOCK {
+ BOOLEAN InUse;
+ BOOLEAN IsDirty;
+ ULONG Age;
+ BIG_INT SectorNumber;
+ HMEM SectorBuffer;
+};
+DEFINE_POINTER_TYPES(RW_CACHE_BLOCK);
+
+
+DECLARE_CLASS(READ_WRITE_CACHE);
+
+class READ_WRITE_CACHE : public DRIVE_CACHE {
+
+ public:
+
+ IFSUTIL_EXPORT
+ DECLARE_CONSTRUCTOR( READ_WRITE_CACHE );
+
+ VIRTUAL
+ ~READ_WRITE_CACHE(
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Initialize(
+ IN OUT PIO_DP_DRIVE Drive,
+ IN ULONG NumberOfCacheBlocks
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Read(
+ IN BIG_INT StartingSector,
+ IN SECTORCOUNT NumberOfSectors,
+ OUT PVOID Buffer
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Write(
+ IN BIG_INT StartingSector,
+ IN SECTORCOUNT NumberOfSectors,
+ IN PVOID Buffer
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Flush(
+ );
+
+ private:
+
+ NONVIRTUAL
+ PRW_CACHE_BLOCK
+ GetSectorCacheBlock(
+ IN BIG_INT SectorNumber
+ );
+
+ NONVIRTUAL
+ PRW_CACHE_BLOCK
+ GetNextAvailbleCacheBlock(
+ );
+
+ NONVIRTUAL
+ VOID
+ FlushThisCacheBlock(
+ IN OUT PRW_CACHE_BLOCK Block
+ );
+
+ NONVIRTUAL
+ VOID
+ FlushJustThisCacheBlock(
+ IN OUT PRW_CACHE_BLOCK Block
+ );
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NUMBER_SET _sectors_cached;
+ PRW_CACHE_BLOCK* _cache_blocks;
+ ULONG _num_blocks;
+ HMEM _write_buffer;
+ ULONG _sector_size;
+ BOOLEAN _error_occurred;
+ ULONG _next_age;
+
+};
+
+
+#endif
diff --git a/private/utils/ifsutil/inc/secrun.hxx b/private/utils/ifsutil/inc/secrun.hxx
new file mode 100644
index 000000000..9731536d0
--- /dev/null
+++ b/private/utils/ifsutil/inc/secrun.hxx
@@ -0,0 +1,240 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ secrun.hxx
+
+Abstract:
+
+ This class models a run of sectors. It is able to read in a run of
+ sectors into memory and write a run of sectors in memory onto disk.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 26-Nov-90
+
+--*/
+
+#if !defined(SECRUN_DEFN)
+
+#define SECRUN_DEFN
+
+#include "drive.hxx"
+#include "mem.hxx"
+
+#if defined ( _AUTOCHECK_ )
+#define IFSUTIL_EXPORT
+#elif defined ( _IFSUTIL_MEMBER_ )
+#define IFSUTIL_EXPORT __declspec(dllexport)
+#else
+#define IFSUTIL_EXPORT __declspec(dllimport)
+#endif
+
+
+DECLARE_CLASS( SECRUN );
+
+class SECRUN : public OBJECT {
+
+ public:
+
+ IFSUTIL_EXPORT
+ DECLARE_CONSTRUCTOR( SECRUN );
+
+ VIRTUAL
+ IFSUTIL_EXPORT
+ ~SECRUN(
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PIO_DP_DRIVE Drive,
+ IN BIG_INT StartSector,
+ IN SECTORCOUNT NumSectors
+ );
+
+ NONVIRTUAL
+ VOID
+ Relocate(
+ IN BIG_INT NewStartSector
+ );
+
+ VIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Read(
+ );
+
+ VIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Write(
+ );
+
+ NONVIRTUAL
+ PVOID
+ GetBuf(
+ );
+
+ NONVIRTUAL
+ BIG_INT
+ QueryStartSector(
+ ) CONST;
+
+ NONVIRTUAL
+ LBN
+ QueryStartLbn(
+ ) CONST;
+
+ NONVIRTUAL
+ SECTORCOUNT
+ QueryLength(
+ ) CONST;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ PVOID _buf;
+ PIO_DP_DRIVE _drive;
+ BIG_INT _start_sector;
+ SECTORCOUNT _num_sectors;
+
+};
+
+INLINE
+VOID
+SECRUN::Relocate(
+ IN BIG_INT NewStartSector
+ )
+/*++
+
+Routine Description:
+
+ This routine relocates the secrun.
+
+Arguments:
+
+ NewStartSector - Supplies the new starting sector.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _start_sector = NewStartSector;
+}
+
+
+INLINE
+PVOID
+SECRUN::GetBuf(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the beginning of the read/write
+ buffer.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to a read/write buffer.
+
+--*/
+{
+ return _buf;
+}
+
+
+INLINE
+BIG_INT
+SECRUN::QueryStartSector(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the starting sector number for the run of sectors.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The starting sector number for the run of sectors.
+
+--*/
+{
+ return _start_sector;
+}
+
+
+INLINE
+LBN
+SECRUN::QueryStartLbn(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the starting LBN for the run of sectors.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The starting LBN for the run of sectors.
+
+--*/
+{
+ DebugAssert(_start_sector.GetHighPart() == 0);
+ return _start_sector.GetLowPart();
+}
+
+
+INLINE
+SECTORCOUNT
+SECRUN::QueryLength(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of sectors in this sector run.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of sectors in this sector run.
+
+--*/
+{
+ return _num_sectors;
+}
+
+
+#endif // SECRUN_DEFN
diff --git a/private/utils/ifsutil/inc/supera.hxx b/private/utils/ifsutil/inc/supera.hxx
new file mode 100644
index 000000000..c1c25c585
--- /dev/null
+++ b/private/utils/ifsutil/inc/supera.hxx
@@ -0,0 +1,233 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ supera.hxx
+
+Abstract:
+
+ This class models the root of a file system. This abstract class is
+ currently the base class of an HPFS and a FAT super area.
+
+Author:
+
+ Norbert Kusters (norbertk) 25-July-91
+
+--*/
+
+#if !defined(SUPERA_DEFN)
+
+#define SUPERA_DEFN
+
+
+#include "secrun.hxx"
+#include "volume.hxx"
+
+#if defined ( _AUTOCHECK_ )
+#define IFSUTIL_EXPORT
+#elif defined ( _IFSUTIL_MEMBER_ )
+#define IFSUTIL_EXPORT __declspec(dllexport)
+#else
+#define IFSUTIL_EXPORT __declspec(dllimport)
+#endif
+
+
+enum PHYSTYPE { // ptype
+ PHYS_REMOVABLE, // physical drive is removable
+ PHYS_FIXED = 0x80 // physical drive is fixed
+};
+
+//
+// These symbols are used by Chkdsk functions to return an appropriate
+// exit status to the chkdsk program.
+//
+
+#define CHKDSK_EXIT_SUCCESS 0
+#define CHKDSK_EXIT_ERRS_FIXED 1
+#define CHKDSK_EXIT_MINOR_ERRS 2 // whether or not "/f"
+#define CHKDSK_EXIT_COULD_NOT_CHK 3
+#define CHKDSK_EXIT_ERRS_NOT_FIXED 3
+#define CHKDSK_EXIT_COULD_NOT_FIX 3
+
+
+DECLARE_CLASS( SUPERAREA );
+DECLARE_CLASS( NUMBER_SET );
+DECLARE_CLASS( MESSAGE );
+DECLARE_CLASS( WSTRING );
+
+
+class SUPERAREA : public SECRUN {
+
+ public:
+
+ VIRTUAL
+ IFSUTIL_EXPORT
+ ~SUPERAREA(
+ );
+
+ VIRTUAL
+ PVOID
+ GetBuf(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Create(
+ IN PCNUMBER_SET BadSectors,
+ IN OUT PMESSAGE Message,
+ IN PCWSTRING Label DEFAULT NULL,
+ IN ULONG ClusterSize DEFAULT 0,
+ IN ULONG VirtualSize DEFAULT 0
+ ) PURE;
+
+ VIRTUAL
+ BOOLEAN
+ VerifyAndFix(
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose DEFAULT FALSE,
+ IN BOOLEAN OnlyIfDirty DEFAULT FALSE,
+ IN BOOLEAN RecoverFree DEFAULT FALSE,
+ IN BOOLEAN RecoverAlloc DEFAULT FALSE,
+ IN BOOLEAN ResizeLogFile DEFAULT FALSE,
+ IN ULONG LogFileSize DEFAULT 0,
+ OUT PULONG ExitStatus DEFAULT NULL,
+ IN PCWSTRING DriveLetter DEFAULT NULL
+ ) PURE;
+
+ VIRTUAL
+ BOOLEAN
+ RecoverFile(
+ IN PCWSTRING FullPathFileName,
+ IN OUT PMESSAGE Message
+ ) PURE;
+
+ VIRTUAL
+ PARTITION_SYSTEM_ID
+ QuerySystemId(
+ ) CONST PURE;
+
+ STATIC
+ IFSUTIL_EXPORT
+ VOLID
+ ComputeVolId(
+ IN VOLID Seed DEFAULT 0
+ );
+
+ protected:
+
+ IFSUTIL_EXPORT
+ DECLARE_CONSTRUCTOR( SUPERAREA );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN SECTORCOUNT NumberOfSectors,
+ IN OUT PMESSAGE Message
+ );
+
+#if !defined( _SETUP_LOADER_ )
+
+ NONVIRTUAL
+ BOOLEAN
+ SetSystemId(
+ );
+
+#endif // _SETUP_LOADER_
+
+ PLOG_IO_DP_DRIVE _drive;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+};
+
+
+INLINE
+PVOID
+SUPERAREA::GetBuf(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the beginning of the read/write
+ buffer.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to a read/write buffer.
+
+--*/
+{
+ return SECRUN::GetBuf();
+}
+
+
+#if !defined( _SETUP_LOADER_ )
+
+INLINE
+BOOLEAN
+SUPERAREA::SetSystemId(
+ )
+/*++
+
+Routine Description:
+
+ Set the current volume's file system sub-type.
+
+ The volume stores the file system type on disk with a
+ strong bias to the FAT. However, this may not continue
+ in the future so a common interface to this type is supported.
+
+ The current on disk file system subtypes are:
+
+ UNKNOWN, no format done yet
+ 12 bit fat
+ 16 bit fat on a < 32M volume
+ 16 bit fat on a >= 32M volume
+ IFS
+
+ OS/2 2.0 does not support this interface so we must set the
+ information via the MBR, NT will provide an ioctl to set this
+ information.
+
+ This information MUST be maintained to stay disk compatable.
+
+ This activity should only be done by format so this is
+ a protected method.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ return _drive->SetSystemId(QuerySystemId());
+}
+
+#endif // _SETUP_LOADER_
+#endif // SUPERA_DEFN
diff --git a/private/utils/ifsutil/inc/volume.hxx b/private/utils/ifsutil/inc/volume.hxx
new file mode 100644
index 000000000..412da598d
--- /dev/null
+++ b/private/utils/ifsutil/inc/volume.hxx
@@ -0,0 +1,392 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ volume.hxx
+
+Abstract:
+
+ Provides volume methods.
+
+Author:
+
+ Mark Shavlik (marks) 13-Feb-90
+ Norbert P. Kusters (norbertk) 22-Feb-91
+
+--*/
+
+#if !defined (VOL_LOG_IO_DP_DRIVE_DEFN)
+
+#define VOL_LOG_IO_DP_DRIVE_DEFN
+
+#if !defined( _SETUP_LOADER_ )
+
+#include "drive.hxx"
+#include "numset.hxx"
+
+#if defined ( _AUTOCHECK_ )
+#define IFSUTIL_EXPORT
+#elif defined ( _IFSUTIL_MEMBER_ )
+#define IFSUTIL_EXPORT __declspec(dllexport)
+#else
+#define IFSUTIL_EXPORT __declspec(dllimport)
+#endif
+
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( HMEM );
+DECLARE_CLASS( MESSAGE );
+DECLARE_CLASS( SUPERAREA );
+DECLARE_CLASS( VOL_LIODPDRV );
+DECLARE_CLASS( WSTRING );
+DECLARE_CLASS( WSTRING );
+
+// This number describes the minimum number of bytes in a boot sector.
+#define BYTES_PER_BOOT_SECTOR 512
+
+
+typedef ULONG VOLID;
+
+#define MAXVOLNAME 11
+
+enum FIX_LEVEL {
+ CheckOnly,
+ TotalFix,
+ SetupSpecial
+};
+
+class VOL_LIODPDRV : public LOG_IO_DP_DRIVE {
+
+ public:
+
+ VIRTUAL
+ IFSUTIL_EXPORT
+ ~VOL_LIODPDRV(
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Format(
+ IN PCWSTRING Label DEFAULT NULL,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN ULONG ClusterSize DEFAULT 0,
+ IN ULONG VirtualSectors DEFAULT 0
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ ChkDsk(
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN BOOLEAN Verbose DEFAULT FALSE,
+ IN BOOLEAN OnlyIfDirty DEFAULT FALSE,
+ IN BOOLEAN RecoverFree DEFAULT FALSE,
+ IN BOOLEAN RecoverAlloc DEFAULT FALSE,
+ IN BOOLEAN ResizeLogfile DEFAULT FALSE,
+ IN ULONG DesiredLogfileSize DEFAULT 0,
+ OUT PULONG ExitStatus DEFAULT NULL,
+ IN PCWSTRING DriveLetter DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Recover(
+ IN PCWSTRING FileName,
+ IN OUT PMESSAGE Message DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ PSUPERAREA
+ GetSa(
+ );
+
+ VIRTUAL
+ PVOL_LIODPDRV
+ QueryDupVolume(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN BOOLEAN ExclusiveWrite DEFAULT FALSE,
+ IN BOOLEAN FormatMedia DEFAULT FALSE,
+ IN MEDIA_TYPE MediaType DEFAULT Unknown
+ ) CONST PURE;
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ ForceAutochk(
+ IN BOOLEAN Recover,
+ IN BOOLEAN ResizeLogfile,
+ IN ULONG DesiredLogfileSize,
+ IN PCWSTRING Name
+ );
+
+
+ protected:
+
+ IFSUTIL_EXPORT
+ DECLARE_CONSTRUCTOR( VOL_LIODPDRV );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Initialize(
+ IN PCWSTRING NtDriveName,
+ IN PSUPERAREA SuperArea,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN BOOLEAN ExclusiveWrite DEFAULT FALSE,
+ IN BOOLEAN FormatMedia DEFAULT FALSE,
+ IN MEDIA_TYPE MediaType DEFAULT Unknown
+ );
+
+ NONVIRTUAL
+ IFSUTIL_EXPORT
+ BOOLEAN
+ Initialize(
+ IN PCWSTRING NtDriveName,
+ IN PCWSTRING HostFileName,
+ IN PSUPERAREA SuperArea,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN BOOLEAN ExclusiveWrite DEFAULT FALSE
+ );
+
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ SECTORCOUNT
+ ReadABunch(
+ IN OUT PHMEM HeapMem,
+ IN LBN StartLbn,
+ IN SECTORCOUNT NumSectors,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN PCWSTRING SrcDosDriveName DEFAULT NULL
+ );
+
+ PSUPERAREA _sa;
+ NUMBER_SET _bad_sectors;
+};
+
+
+INLINE
+PSUPERAREA
+VOL_LIODPDRV::GetSa(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the current super area.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the current super area.
+
+--*/
+{
+ return _sa;
+}
+
+#else // _SETUP_LOADER_ is defined
+
+#include "drive.hxx"
+#include "intstack.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( HMEM );
+DECLARE_CLASS( MESSAGE );
+DECLARE_CLASS( SUPERAREA );
+DECLARE_CLASS( VOL_LIODPDRV );
+DECLARE_CLASS( WSTRING );
+DECLARE_CLASS( WSTRING );
+
+
+typedef ULONG VOLID;
+
+#define MAXVOLNAME 11
+
+enum FIX_LEVEL {
+ CheckOnly,
+ TotalFix
+};
+
+// This number describes the minimum number of bytes in a boot sector.
+#define BYTES_PER_BOOT_SECTOR 512
+
+class VOL_LIODPDRV : public LOG_IO_DP_DRIVE {
+
+ public:
+
+ VIRTUAL
+ ~VOL_LIODPDRV(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ChkDsk(
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN BOOLEAN Verbose DEFAULT FALSE,
+ IN BOOLEAN OnlyIfDirty DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ PSUPERAREA
+ GetSa(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ IsHpfs(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ IsNtfs(
+ );
+
+ VIRTUAL
+ ARC_STATUS
+ MarkDirty(
+ ) PURE;
+
+ VIRTUAL
+ ARC_STATUS
+ Flush(
+ IN BOOLEAN JustHandle
+ ) PURE;
+
+ protected:
+
+ DECLARE_CONSTRUCTOR( VOL_LIODPDRV );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN ULONG DeviceId,
+ IN OUT PSUPERAREA SuperArea
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ SECTORCOUNT
+ ReadABunch(
+ IN OUT PHMEM HeapMem,
+ IN LBN StartLbn,
+ IN SECTORCOUNT NumSectors,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN PCWSTRING SrcDosDriveName DEFAULT NULL
+ );
+
+ PSUPERAREA _sa;
+ INTSTACK _bad_sectors;
+};
+
+
+INLINE
+PSUPERAREA
+VOL_LIODPDRV::GetSa(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the current super area.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the current super area.
+
+--*/
+{
+ return _sa;
+}
+
+INLINE
+BOOLEAN
+VOL_LIODPDRV::IsHpfs(
+ )
+/*++
+
+Routine Description:
+
+ This method determines whether the volume is HPFS.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if this volume is an HPFS volume.
+
+--*/
+{
+ return FALSE;
+}
+
+INLINE
+BOOLEAN
+VOL_LIODPDRV::IsNtfs(
+ )
+/*++
+
+Routine Description:
+
+ This method determines whether the volume is NTFS.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if this volume is an NTFS volume.
+
+--*/
+{
+ return FALSE;
+}
+
+#endif
+
+#endif
diff --git a/private/utils/ifsutil/src/autoentr.cxx b/private/utils/ifsutil/src/autoentr.cxx
new file mode 100644
index 000000000..0ce8feb40
--- /dev/null
+++ b/private/utils/ifsutil/src/autoentr.cxx
@@ -0,0 +1,128 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ autoentr
+
+Abstract:
+
+ This module contains the definition of the AUTOENTR class.
+
+Author:
+
+ Ramon J. San Andres (ramonsa) 11 Mar 1991
+
+Environment:
+
+ Ulib, User Mode
+
+
+--*/
+
+#include <pch.cxx>
+
+#include "ulib.hxx"
+#include "autoentr.hxx"
+
+DEFINE_CONSTRUCTOR( AUTOENTRY, OBJECT );
+
+
+
+AUTOENTRY::~AUTOENTRY (
+ )
+/*++
+
+Routine Description:
+
+ Destructor for AUTOENTRY
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+
+
+VOID
+AUTOENTRY::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Constructor for AUTOENTRY
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+}
+
+
+
+
+VOID
+AUTOENTRY::Destroy (
+ )
+/*++
+
+Routine Description:
+
+ Destroys an AUTOENTRY object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+}
+
+
+
+BOOLEAN
+AUTOENTRY::Initialize (
+ IN PCWSTRING EntryName,
+ IN PCWSTRING CommandLine
+ )
+/*++
+
+Routine Description:
+
+ Initializes an AUTOENTRY object
+
+Arguments:
+
+ None
+
+Return Value:
+
+ BOOLEAN - TRUE if success
+
+--*/
+{
+ return ( _EntryName.Initialize( EntryName ) &&
+ _CommandLine.Initialize( CommandLine ) );
+}
diff --git a/private/utils/ifsutil/src/autoreg.cxx b/private/utils/ifsutil/src/autoreg.cxx
new file mode 100644
index 000000000..ee7d35aad
--- /dev/null
+++ b/private/utils/ifsutil/src/autoreg.cxx
@@ -0,0 +1,263 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ autoreg
+
+Abstract:
+
+ This module contains the definition of the AUTOREG class.
+
+ The AUTOREG class contains methods for the registration and
+ de-registration of those programs that are to be executed at
+ boot time.
+
+Author:
+
+ Ramon J. San Andres (ramonsa) 11 Mar 1991
+
+Environment:
+
+ Ulib, User Mode
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _IFSUTIL_MEMBER_
+
+#include "ulib.hxx"
+#include "ifsutil.hxx"
+
+#include "autoreg.hxx"
+#include "autoentr.hxx"
+
+
+extern "C" {
+ #include <stdio.h>
+ #include "bootreg.h"
+}
+
+CONST BootExecuteBufferSize = 0x2000;
+
+STATIC BYTE BootExecuteBuffer[BootExecuteBufferSize];
+
+IFSUTIL_EXPORT
+BOOLEAN
+AUTOREG::AddEntry (
+ IN PCWSTRING CommandLine
+ )
+{
+ PWCHAR BootExecuteValue = (PWCHAR)BootExecuteBuffer;
+ ULONG CharsInValue, NewCharCount;
+
+
+ // Fetch the existing autocheck entries.
+ //
+ if( !QueryAutocheckEntries( BootExecuteValue,
+ BootExecuteBufferSize ) ) {
+
+ return FALSE;
+ }
+
+ // Determine if the new entry fits in our buffer. The
+ // new size will be the chars in the existing value
+ // plus the length of the new string plus a terminating
+ // null for the new string plus a terminating null for
+ // the multi-string value.
+ //
+ CharsInValue = CharsInMultiString( BootExecuteValue );
+
+ NewCharCount = CharsInValue + CommandLine->QueryChCount() + 2;
+
+ if( NewCharCount * sizeof( WCHAR ) > BootExecuteBufferSize ) {
+
+ // Not enough room.
+ //
+ return FALSE;
+ }
+
+
+ // Add the new entry to the buffer and add a terminating null
+ // for the multi-string:
+ //
+ if( !CommandLine->QueryWSTR( 0,
+ TO_END,
+ BootExecuteValue + CharsInValue,
+ BootExecuteBufferSize/sizeof(WCHAR) -
+ CharsInValue ) ) {
+
+ // Couldn't get the WSTR.
+ //
+ return FALSE;
+ }
+
+ BootExecuteValue[ NewCharCount - 1 ] = 0;
+
+
+ // Write the value back into the registry:
+ //
+ return( SaveAutocheckEntries( BootExecuteValue ) );
+}
+
+BOOLEAN
+AUTOREG::DeleteEntry (
+ IN PCWSTRING LineToMatch,
+ IN BOOLEAN PrefixOnly
+ )
+/*++
+
+Routine Description:
+
+ This method removes an Autocheck entry.
+
+Arguments:
+
+ LineToMatch -- Supplies a pattern for the entry to delete.
+ All lines which match this pattern will be
+ deleted.
+
+ PrefixOnly -- LineToMatch specifies a prefix, and all lines
+ beginning with that prefix are deleted.
+
+Return Value:
+
+ TRUE upon successful completion. Note that this function
+ will return TRUE if no matching entry is found, or if a
+ matching entry is found and removed.
+
+Notes:
+
+ Since the utilities only assume responsibility for removing
+ entries which we created in the first place, we can place
+ very tight constraints on the matching pattern. In particular,
+ we can require an exact match (except for case).
+
+--*/
+{
+ DSTRING CurrentString;
+ PWCHAR BootExecuteValue = (PWCHAR)BootExecuteBuffer;
+ PWCHAR pw;
+
+ // Fetch the existing entries:
+ //
+ if( !QueryAutocheckEntries( BootExecuteValue,
+ BootExecuteBufferSize ) ) {
+
+ return FALSE;
+ }
+
+ // Spin through the entries looking for matches:
+ //
+ pw = BootExecuteValue;
+
+ while( *pw ) {
+
+ if( !CurrentString.Initialize( pw ) ) {
+
+ return FALSE;
+ }
+
+ if( CurrentString.Stricmp( LineToMatch ) == 0 ||
+ (PrefixOnly && CurrentString.Stricmp( LineToMatch,
+ 0, LineToMatch->QueryChCount(),
+ 0, LineToMatch->QueryChCount()) == 0)) {
+
+ // This line is a match--delete it. We simply expunge
+ // the current string plus its terminating null by
+ // shifting the data beyond that point down.
+ //
+ memmove( pw,
+ pw + CurrentString.QueryChCount() + 1,
+ BootExecuteBufferSize - (pw - BootExecuteValue) * sizeof(WCHAR) );
+
+ } else {
+
+ // This line is not a match. Advance to the next.
+ // Note that this will bump over the terminating
+ // null for this component string, which is what
+ // we want.
+ //
+ while( *pw++ );
+ }
+ }
+
+ return( SaveAutocheckEntries( BootExecuteValue ) );
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+AUTOREG::IsEntryPresent (
+ IN PCWSTRING LineToMatch
+ )
+/*++
+
+Routine Description:
+
+ This method determines whether a proposed entry for the
+ autocheck list is already in the registry.
+
+Arguments:
+
+ LineToMatch -- Supplies a pattern for proposed entry.
+
+Return Value:
+
+ TRUE if a matching entry exists.
+
+Notes:
+
+ Since the utilities only assume responsibility for removing
+ entries which we created in the first place, we can place
+ very tight constraints on the matching pattern. In particular,
+ we can require an exact match (except for case).
+
+--*/
+{
+ DSTRING CurrentString;
+ PWCHAR BootExecuteValue = (PWCHAR)BootExecuteBuffer;
+ PWCHAR pw;
+
+ // Fetch the existing entries:
+ //
+ if( !QueryAutocheckEntries( BootExecuteValue,
+ BootExecuteBufferSize ) ) {
+
+ return FALSE;
+ }
+
+ // Spin through the entries looking for matches:
+ //
+ pw = BootExecuteValue;
+
+ while( *pw ) {
+
+ if( !CurrentString.Initialize( pw ) ) {
+
+ return FALSE;
+ }
+
+ if( CurrentString.Stricmp( LineToMatch ) == 0 ) {
+
+ // This line is a match.
+ //
+ return TRUE;
+
+ } else {
+
+ // This line is not a match. Advance to the next.
+ // Note that this will bump over the terminating
+ // null for this component string, which is what
+ // we want.
+ //
+ while( *pw++ );
+ }
+ }
+
+ return FALSE;
+}
diff --git a/private/utils/ifsutil/src/bigint.cxx b/private/utils/ifsutil/src/bigint.cxx
new file mode 100644
index 000000000..27096e5ed
--- /dev/null
+++ b/private/utils/ifsutil/src/bigint.cxx
@@ -0,0 +1,602 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _IFSUTIL_MEMBER_
+
+#include "ulib.hxx"
+#include "ifsutil.hxx"
+
+#include "bigint.hxx"
+
+
+IFSUTIL_EXPORT
+VOID
+BIG_INT::Set(
+ IN UCHAR ByteCount,
+ IN PCUCHAR CompressedInteger
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the big_int with the given compressed integer.
+
+Arguments:
+
+ ByteCount - Supplies the number of bytes in the compressed
+ integer.
+ CompressedInteger - Supplies the compressed integer.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ // If the number is completely compressed then we'll say that the
+ // number is zero. QueryCompressed should always return at least
+ // one byte though.
+
+ if (ByteCount == 0) {
+ x.LowPart = 0;
+ x.HighPart = 0;
+ return;
+ }
+
+
+ // First fill the integer with -1 if it's negative or 0 if it's
+ // positive.
+
+ if (CompressedInteger[ByteCount - 1] >= 0x80) {
+
+ x.LowPart = (ULONG) -1;
+ x.HighPart = -1;
+
+ } else {
+
+ x.LowPart = 0;
+ x.HighPart = 0;
+ }
+
+
+ // Now copy over the integer.
+
+ DebugAssert( ByteCount <= 8 );
+
+ memcpy( &x, CompressedInteger, ByteCount );
+}
+
+
+IFSUTIL_EXPORT
+VOID
+BIG_INT::QueryCompressedInteger(
+ OUT PUCHAR ByteCount,
+ OUT PUCHAR CompressedInteger
+ ) CONST
+/*++
+
+Routine Descrtiption:
+
+ This routine returns a compressed form of the integer.
+
+Arguments:
+
+ ByteCount - Returns the number of bytes in the compressed
+ integer.
+ CompressedInteger - Returns a 'little endian' string of bytes
+ representing a signed 'ByteCount' byte integer
+ into this supplied buffer.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ INT i;
+ PUCHAR p;
+
+ DebugAssert(ByteCount);
+ DebugAssert(CompressedInteger);
+
+ // First copy over the whole thing then determine the number
+ // of bytes that you have to keep.
+
+ memcpy(CompressedInteger, &x, sizeof(LARGE_INTEGER));
+
+
+ p = CompressedInteger;
+
+
+ // First check to see whether the number is positive or negative.
+
+ if (p[7] >= 0x80) { // high byte is negative.
+
+ for (i = 7; i >= 0 && p[i] == 0xFF; i--) {
+ }
+
+ if (i < 0) {
+ *ByteCount = 1;
+ return;
+ }
+
+ if (p[i] < 0x80) { // high byte is non-negative.
+ i++;
+ }
+
+ } else { // high byte is non-negative.
+
+ for (i = 7; i >= 0 && p[i] == 0; i--) {
+ }
+
+ if (i < 0) {
+ *ByteCount = 1;
+ return;
+ }
+
+ if (p[i] >= 0x80) { // high byte is negative.
+ i++;
+ }
+
+ }
+
+
+ // Now 'i' marks the position of the last character that you
+ // have to keep.
+
+ *ByteCount = (UCHAR) (i + 1);
+}
+
+
+
+IFSUTIL_EXPORT
+VOID
+BIG_INT::operator+=(
+ IN RCBIG_INT BigInt
+ )
+/*++
+
+Routine Description:
+
+ This routine adds another BIG_INT to this one.
+
+Arguments:
+
+ BigInt - Supplies the BIG_INT to add to the current BIG_INT.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if (x.LowPart > ((ULONG) -1) - BigInt.GetLowPart()) {
+ x.HighPart++;
+ }
+ x.LowPart += BigInt.GetLowPart();
+ x.HighPart += BigInt.GetHighPart();
+}
+
+
+
+BIG_INT
+BIG_INT::operator-(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the negation of the current BIG_INT.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The negation of the current BIG_INT.
+
+--*/
+{
+ BIG_INT r;
+
+ r.Set(~x.LowPart + 1, (x.LowPart ? ~x.HighPart : -x.HighPart));
+
+ return r;
+}
+
+
+
+IFSUTIL_EXPORT
+VOID
+BIG_INT::operator-=(
+ IN RCBIG_INT BigInt
+ )
+/*++
+
+Routine Description:
+
+ This routine subtracts a BIG_INT from this one.
+
+Arguments:
+
+ BigInt - Supplies a BIG_INT to subtract from the current BIG_INT.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ *this += -BigInt;
+}
+
+
+
+IFSUTIL_EXPORT
+BIG_INT
+operator+(
+ IN RCBIG_INT Left,
+ IN RCBIG_INT Right
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the sum of two BIG_INTs.
+
+Arguments:
+
+ Left - Supplies the left argument.
+ Right - Supplies the right argument.
+
+Return Value:
+
+ The sum of Left and Right.
+
+--*/
+{
+ BIG_INT r;
+
+ r = Left;
+ r += Right;
+ return r;
+}
+
+
+
+IFSUTIL_EXPORT
+BIG_INT
+operator-(
+ IN RCBIG_INT Left,
+ IN RCBIG_INT Right
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the difference of two BIG_INTs.
+
+Arguments:
+
+ Left - Supplies the left argument.
+ Right - Supplies the right argument.
+
+Return Value:
+
+ The difference between Left and Right.
+
+--*/
+{
+ BIG_INT r;
+
+ r = Left;
+ r -= Right;
+ return r;
+}
+
+
+
+IFSUTIL_EXPORT
+BIG_INT
+operator*(
+ IN RCBIG_INT Left,
+ IN RCSLONG Right
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the product of a BIG_INT and a LONG.
+
+Arguments:
+
+ Left - Supplies the left argument.
+ Right - Supplies the right argument.
+
+Return Value:
+
+ The product of Left and Right.
+
+--*/
+{
+ return RtlExtendedIntegerMultiply(Left.x, Right);
+}
+
+
+
+IFSUTIL_EXPORT
+BIG_INT
+operator*(
+ IN RCSLONG Left,
+ IN RCBIG_INT Right
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the product of a BIG_INT and a LONG.
+
+Arguments:
+
+ Left - Supplies the left argument.
+ Right - Supplies the right argument.
+
+Return Value:
+
+ The product of Left and Right.
+
+--*/
+{
+ return Right*Left;
+}
+
+
+
+IFSUTIL_EXPORT
+BIG_INT
+operator/(
+ IN RCBIG_INT Left,
+ IN RCBIG_INT Right
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the quotient of two BIG_INTs.
+
+Arguments:
+
+ Left - Supplies the left argument.
+ Right - Supplies the right argument.
+
+Return Value:
+
+ The quotient of Left and Right.
+
+--*/
+{
+ return RtlLargeIntegerDivide(Left.x, Right.x, NULL);
+}
+
+
+
+IFSUTIL_EXPORT
+BIG_INT
+operator%(
+ IN RCBIG_INT Left,
+ IN RCBIG_INT Right
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the modulus of two BIG_INTs.
+
+Arguments:
+
+ Left - Supplies the left argument.
+ Right - Supplies the right argument.
+
+Return Value:
+
+ The modulus of Left and Right.
+
+--*/
+{
+ LARGE_INTEGER r;
+
+ RtlLargeIntegerDivide(Left.x, Right.x, &r);
+ return r;
+}
+
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+operator<(
+ IN RCBIG_INT Left,
+ IN RCBIG_INT Right
+ )
+/*++
+
+Routine Description:
+
+ This routine compares two BIG_INTs.
+
+Arguments:
+
+ Left - Supplies the left argument.
+ Right - Supplies the right argument.
+
+Return Value:
+
+ FALSE - Left is not less than Right.
+ TRUE - Left is less than Right.
+
+--*/
+{
+ if (Left.x.HighPart == Right.x.HighPart) {
+ return Left.x.LowPart < Right.x.LowPart;
+ } else {
+ return Left.x.HighPart < Right.x.HighPart;
+ }
+}
+
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+operator<=(
+ IN RCBIG_INT Left,
+ IN RCBIG_INT Right
+ )
+/*++
+
+Routine Description:
+
+ This routine compares two BIG_INTs.
+
+Arguments:
+
+ Left - Supplies the left argument.
+ Right - Supplies the right argument.
+
+Return Value:
+
+ FALSE - Left is not less than or equal to Right.
+ TRUE - Left is less than or equal to Right.
+
+--*/
+{
+ if (Left.x.HighPart == Right.x.HighPart) {
+ return Left.x.LowPart <= Right.x.LowPart;
+ } else {
+ return Left.x.HighPart < Right.x.HighPart;
+ }
+}
+
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+operator>(
+ IN RCBIG_INT Left,
+ IN RCBIG_INT Right
+ )
+/*++
+
+Routine Description:
+
+ This routine compares two BIG_INTs.
+
+Arguments:
+
+ Left - Supplies the left argument.
+ Right - Supplies the right argument.
+
+Return Value:
+
+ FALSE - Left is not greater than Right.
+ TRUE - Left is greater than Right.
+
+--*/
+{
+ if (Left.x.HighPart == Right.x.HighPart) {
+ return Left.x.LowPart > Right.x.LowPart;
+ } else {
+ return Left.x.HighPart > Right.x.HighPart;
+ }
+}
+
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+operator>=(
+ IN RCBIG_INT Left,
+ IN RCBIG_INT Right
+ )
+/*++
+
+Routine Description:
+
+ This routine compares two BIG_INTs.
+
+Arguments:
+
+ Left - Supplies the left argument.
+ Right - Supplies the right argument.
+
+Return Value:
+
+ FALSE - Left is not greater than or equal to Right.
+ TRUE - Left is greater than or equal to Right.
+
+--*/
+{
+ if (Left.x.HighPart == Right.x.HighPart) {
+ return Left.x.LowPart >= Right.x.LowPart;
+ } else {
+ return Left.x.HighPart > Right.x.HighPart;
+ }
+}
+
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+operator==(
+ IN RCBIG_INT Left,
+ IN RCBIG_INT Right
+ )
+/*++
+
+Routine Description:
+
+ This routine compares two BIG_INTs for equality.
+
+Arguments:
+
+ Left - Supplies the left argument.
+ Right - Supplies the right argument.
+
+Return Value:
+
+ FALSE - Left is not equal to Right.
+ TRUE - Left is equal to Right.
+
+--*/
+{
+ return Left.x.LowPart == Right.x.LowPart &&
+ Left.x.HighPart == Right.x.HighPart;
+}
+
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+operator!=(
+ IN RCBIG_INT Left,
+ IN RCBIG_INT Right
+ )
+/*++
+
+Routine Description:
+
+ This routine compares two BIG_INTs for equality.
+
+Arguments:
+
+ Left - Supplies the left argument.
+ Right - Supplies the right argument.
+
+Return Value:
+
+ FALSE - Left is equal to Right.
+ TRUE - Left is not equal to Right.
+
+--*/
+{
+ return !(Left == Right);
+}
diff --git a/private/utils/ifsutil/src/bootreg.c b/private/utils/ifsutil/src/bootreg.c
new file mode 100644
index 000000000..b43cbb49b
--- /dev/null
+++ b/private/utils/ifsutil/src/bootreg.c
@@ -0,0 +1,145 @@
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <stdio.h>
+#include "bootreg.h"
+
+#define SESSION_MANAGER_KEY L"Session Manager"
+#define BOOT_EXECUTE_VALUE L"BootExecute"
+#define NEW_ENTRY L"autocheck new entry"
+
+
+ULONG
+CharsInMultiString(
+ IN PWSTR pw
+ )
+/*++
+
+Routine Description:
+
+ This computes the number of characters in a multi-string. Note
+ that this includes the terminating nulls of the component strings
+ but not the terminating null of the multi-string itself.
+
+Arguments:
+
+ pw -- Supplies a pointer to the multi-string.
+
+Return Value:
+
+ the number of characters in the multi-string.
+
+--*/
+{
+ ULONG Length = 0;
+
+ while( *pw ) {
+
+ while( *pw++ ) {
+
+ Length++;
+ }
+
+ Length++;
+ }
+
+
+ return Length;
+}
+
+
+BOOLEAN
+QueryAutocheckEntries(
+ OUT PVOID Buffer,
+ IN ULONG BufferSize
+ )
+/*++
+
+Routine Description:
+
+ This function fetches the BootExecute value of the Session
+ Manager key.
+
+Arguments:
+
+ Buffer -- Supplies a buffer into which the value
+ will be written.
+ BufferSize -- Supplies the size of the client's buffer.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ UNICODE_STRING OutputString;
+ RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+ NTSTATUS Status;
+
+ // Set up the query table:
+ //
+ OutputString.Length = 0;
+ OutputString.MaximumLength = (USHORT)BufferSize;
+ OutputString.Buffer = (PWSTR)Buffer;
+
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND;
+ QueryTable[0].Name = BOOT_EXECUTE_VALUE;
+ QueryTable[0].EntryContext = &OutputString;
+ QueryTable[0].DefaultType = REG_NONE;
+ QueryTable[0].DefaultData = 0;
+ QueryTable[0].DefaultLength = 0;
+
+ QueryTable[1].QueryRoutine = NULL;
+ QueryTable[1].Flags = 0;
+ QueryTable[1].Name = NULL;
+ QueryTable[1].EntryContext = NULL;
+ QueryTable[1].DefaultType = REG_NONE;
+ QueryTable[1].DefaultData = NULL;
+ QueryTable[1].DefaultLength = 0;
+
+ Status = RtlQueryRegistryValues( RTL_REGISTRY_CONTROL,
+ SESSION_MANAGER_KEY,
+ QueryTable,
+ NULL,
+ NULL );
+
+ return( NT_SUCCESS( Status ) );
+}
+
+
+BOOLEAN
+SaveAutocheckEntries(
+ IN PVOID Value
+ )
+/*++
+
+Routine Description:
+
+ This function writes the BootExecute value of the Session
+ Manager key.
+
+Arguments:
+
+ Value -- Supplies the value (as a MULTI_STRING)
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ NTSTATUS Status;
+ ULONG Length;
+
+ Length = ( CharsInMultiString( Value ) + 1 ) * sizeof( WCHAR );
+
+ Status = RtlWriteRegistryValue( RTL_REGISTRY_CONTROL,
+ SESSION_MANAGER_KEY,
+ BOOT_EXECUTE_VALUE,
+ REG_MULTI_SZ,
+ Value,
+ Length );
+
+ return( NT_SUCCESS( Status ) );
+}
diff --git a/private/utils/ifsutil/src/cache.cxx b/private/utils/ifsutil/src/cache.cxx
new file mode 100644
index 000000000..6a46437a5
--- /dev/null
+++ b/private/utils/ifsutil/src/cache.cxx
@@ -0,0 +1,245 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+#include "cache.hxx"
+
+
+DEFINE_CONSTRUCTOR( CACHE, OBJECT );
+
+
+CACHE::~CACHE(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for CACHE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+CACHE::Construct(
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes this class to a default initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _buffer = NULL;
+ _block_number = NULL;
+ _num_blocks = 0;
+ _block_size = 0;
+ _next_add = 0;
+}
+
+
+VOID
+CACHE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns this object to its initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG i;
+
+ for (i = 0; i < _num_blocks; i++) {
+ FREE(_buffer[i]);
+ }
+ DELETE(_buffer);
+
+ DELETE(_block_number);
+
+ _num_blocks = 0;
+ _block_size = 0;
+ _next_add = 0;
+}
+
+
+BOOLEAN
+CACHE::Initialize(
+ IN ULONG BlockSize,
+ IN ULONG MaximumNumberOfBlocks
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes this object to a valid initial state.
+
+Arguments:
+
+ BlockSize - Supplies the size of the cache blocks.
+ MaximumNumberOfBlocks - Supplies the maximum number of cache blocks.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG i;
+
+ Destroy();
+
+ _num_blocks = MaximumNumberOfBlocks;
+ _block_size = BlockSize;
+
+ if (!(_buffer = NEW PVOID[_num_blocks]) ||
+ !(_block_number = NEW BIG_INT[_num_blocks])) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ for (i = 0; i < _num_blocks; i++) {
+
+ _buffer[i] = NULL;
+ _block_number[i] = -1;
+ }
+
+ for (i = 0; i < _num_blocks; i++) {
+
+ if (!(_buffer[i] = MALLOC((UINT) _block_size))) {
+
+ Destroy();
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+CACHE::Read(
+ IN BIG_INT BlockNumber,
+ OUT PVOID Buffer
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine searches the cache for the requested block and
+ copies it to the buffer if it is available. If the block is
+ not available then this routine will return FALSE.
+
+Arguments:
+
+ BlockNumber - Supplies the number of the block requested.
+ Buffer - Returns the buffer for the block requested.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG i;
+
+ for (i = 0; i < _num_blocks; i++) {
+
+ if (BlockNumber == _block_number[i]) {
+
+ memcpy(Buffer, _buffer[i], (UINT) _block_size);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+VOID
+CACHE::AddBlock(
+ IN BIG_INT BlockNumber,
+ IN PCVOID Buffer
+ )
+/*++
+
+Routine Description:
+
+ This routine adds a new block to the cache. This will remove the
+ oldest existing block out of the cache.
+
+Arguments:
+
+ BlockNumber - Supplies the block number of the new block.
+ Buffer - Supplies the buffer for the new block.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ memcpy(_buffer[_next_add], Buffer, (UINT) _block_size);
+ _block_number[_next_add] = BlockNumber;
+ _next_add = (_next_add + 1) % _num_blocks;
+}
+
+
+VOID
+CACHE::Empty(
+ )
+/*++
+
+Routine Description:
+
+ This routine eliminates all of the blocks from the cache.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG i;
+
+ for (i = 0; i < _num_blocks; i++) {
+
+ _block_number[i] = -1;
+ }
+}
diff --git a/private/utils/ifsutil/src/cannedsd.cxx b/private/utils/ifsutil/src/cannedsd.cxx
new file mode 100644
index 000000000..b432664b5
--- /dev/null
+++ b/private/utils/ifsutil/src/cannedsd.cxx
@@ -0,0 +1,984 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ cannedsd.cxx
+
+Abstract:
+
+ This module contains member function definitions for the
+ CANNED_SECURITY class, which is a repository for the canned
+ Security Descriptors used by the utilities.
+
+ Initializing an object of this type generates the canned
+ security descriptors used by the utilities, which can
+ then be gotten from the object.
+
+ These security descriptors are all in the self-relative
+ format.
+
+ Note that this class uses the NT Api and RTL routines, rather
+ than the Win32 API, since it needs to be available to AutoChk
+ and AutoConvert.
+
+Author:
+
+ Bill McJohn (billmc) 04-March-1992
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _IFSUTIL_MEMBER_
+
+#include "ulib.hxx"
+#include "ifsutil.hxx"
+
+#include "error.hxx"
+#include "ntrtl.h"
+#include "nturtl.h"
+
+#include "cannedsd.hxx"
+
+// This generic mapping array is copied from ntos\io\ioinit.c.
+//
+GENERIC_MAPPING IopFileMapping = {
+
+ STANDARD_RIGHTS_READ |
+ FILE_READ_DATA | FILE_READ_ATTRIBUTES | FILE_READ_EA | SYNCHRONIZE,
+ STANDARD_RIGHTS_WRITE |
+ FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_APPEND_DATA | SYNCHRONIZE,
+ STANDARD_RIGHTS_EXECUTE |
+ SYNCHRONIZE | FILE_READ_ATTRIBUTES | FILE_EXECUTE,
+ FILE_ALL_ACCESS
+};
+
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( CANNED_SECURITY, OBJECT, IFSUTIL_EXPORT );
+
+IFSUTIL_EXPORT
+CANNED_SECURITY::~CANNED_SECURITY(
+ )
+{
+ Destroy();
+}
+
+VOID
+CANNED_SECURITY::Construct(
+ )
+/*++
+
+Routine Description:
+
+ This method is the helper function for object construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _NoAccessLength = 0;
+ _NoAclLength = 0;
+ _ReadLength = 0;
+ _WriteLength = 0;
+ _EditLength = 0;
+
+ _NoAccessSd = NULL;
+ _NoAclSd = NULL;
+ _ReadSd = NULL;
+ _WriteSd = NULL;
+ _EditSd = NULL;
+}
+
+VOID
+CANNED_SECURITY::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This method cleans up the object in preparation for destruction
+ or reinitialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+#if !defined( _SETUP_LOADER_ )
+ _NoAccessLength = 0;
+ _NoAclLength = 0;
+ _ReadLength = 0;
+ _WriteLength = 0;
+ _EditLength = 0;
+
+ // Since the canned security descriptors are ultimately
+ // generated by RtlNewSecurityObject, they have to be
+ // freed using RtlFreeHeap.
+ //
+ if( _NoAccessSd != NULL ) {
+
+ RtlFreeHeap( RtlProcessHeap(), 0, _NoAccessSd );
+ _NoAccessSd = NULL;
+ }
+
+ if( _NoAclSd != NULL ) {
+
+ RtlFreeHeap( RtlProcessHeap(), 0, _NoAclSd );
+ _NoAclSd = NULL;
+ }
+
+ if( _ReadSd != NULL ) {
+
+ RtlFreeHeap( RtlProcessHeap(), 0, _ReadSd );
+ _ReadSd = NULL;
+ }
+
+ if( _WriteSd != NULL ) {
+
+ RtlFreeHeap( RtlProcessHeap(), 0, _WriteSd );
+ _WriteSd = NULL;
+ }
+
+ if( _EditSd != NULL ) {
+
+ RtlFreeHeap( RtlProcessHeap(), 0, _EditSd );
+ _EditSd = NULL;
+ }
+#endif // _SETUP_LOADER_
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+CANNED_SECURITY::Initialize(
+ )
+/*++
+
+Routine Description:
+
+ This method initializes the object. It builds the canned
+ security descriptors, puts them into self-relative form,
+ and squirrels them away for later use.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+#if defined( _SETUP_LOADER_ )
+
+ // Canned security descriptors are not available in
+ // the setup loader environment.
+ //
+ return FALSE;
+
+#else
+
+ CONST SidBufferLength = 512;
+ PSID SystemSid = NULL;
+ PSID AdminsSid = NULL;
+ ULONG AdminsSidBufferLength, SystemSidBufferLength;
+ NTSTATUS Status;
+ HANDLE TokenHandle;
+
+ Destroy();
+
+ // Get the SID's for Admins and System.
+ //
+ SystemSidBufferLength = SidBufferLength;
+ AdminsSidBufferLength = SidBufferLength;
+
+ if( (SystemSid = (PSID)MALLOC( SystemSidBufferLength )) == NULL ||
+ !QuerySystemSid( SystemSid, &SystemSidBufferLength ) ||
+ (AdminsSid = (PSID)MALLOC( AdminsSidBufferLength )) == NULL ||
+ !QueryAdminsSid( AdminsSid, &AdminsSidBufferLength ) ) {
+
+ FREE( SystemSid );
+ FREE( AdminsSid );
+ Destroy();
+ return FALSE;
+ }
+
+ // Get a handle to the token for the current process:
+ //
+ Status = NtOpenProcessToken( NtCurrentProcess(),
+ TOKEN_QUERY,
+ &TokenHandle );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ DebugPrintf( "IFSUTIL: NtOpenProcessToken failed: status = 0x%x\n", Status );
+ FREE( SystemSid );
+ FREE( AdminsSid );
+ Destroy();
+ return FALSE ;
+ }
+
+ // Generate the canned security descriptors. All but _NoAclSd
+ // have a discretionary ACL, so pass in TRUE for the DaclPresent
+ // parameter for all but that exception.
+ //
+ _NoAccessSd = GenerateCannedSd( TRUE,
+ 0,
+ AdminsSid,
+ SystemSid,
+ TokenHandle,
+ &_NoAccessLength );
+
+ _NoAclSd = GenerateCannedSd( FALSE,
+ 0,
+ AdminsSid,
+ SystemSid,
+ TokenHandle,
+ &_NoAclLength );
+
+ _ReadSd = GenerateCannedSd( TRUE,
+ GENERIC_READ,
+ AdminsSid,
+ SystemSid,
+ TokenHandle,
+ &_ReadLength );
+
+ _WriteSd = GenerateCannedSd( TRUE,
+ GENERIC_READ | GENERIC_WRITE,
+ AdminsSid,
+ SystemSid,
+ TokenHandle,
+ &_WriteLength );
+
+ _EditSd = GenerateCannedSd( TRUE,
+ GENERIC_ALL,
+ AdminsSid,
+ SystemSid,
+ TokenHandle,
+ &_EditLength );
+
+ // We're done with the SID's for Admins and System, and with
+ // the token for the current process.
+ //
+ FREE( SystemSid );
+ FREE( AdminsSid );
+ NtClose( TokenHandle );
+
+ // Make sure that all the canned security descriptors were
+ // successful generated.
+ //
+ if( _NoAccessSd == NULL ||
+ _NoAclSd == NULL ||
+ _ReadSd == NULL ||
+ _WriteSd == NULL ||
+ _EditSd == NULL ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ return TRUE;
+
+#endif // _SETUP_LOADER_
+}
+
+
+IFSUTIL_EXPORT
+PVOID
+CANNED_SECURITY::GetCannedSecurityDescriptor(
+ IN CANNED_SECURITY_TYPE Type,
+ OUT PULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This method fetches one of the canned security descriptors.
+
+Arguments:
+
+ Type -- Supplies a code indicating which security
+ descriptor to get.
+ Length -- Receives the length (in bytes) of the security
+ descriptor.
+
+Return Value:
+
+ A pointer to the canned security descriptor. (A return value
+ of NULL indicates that an error has occurred.)
+
+--*/
+{
+ DebugPtrAssert( Length );
+
+ switch( Type ) {
+
+ case NoAccessCannedSd : *Length = _NoAccessLength;
+ return _NoAccessSd;
+
+ case NoAclCannedSd : *Length = _NoAclLength;
+ return _NoAclSd;
+
+ case ReadCannedSd : *Length = _ReadLength;
+ return _ReadSd;
+
+ case WriteCannedSd : *Length = _WriteLength;
+ return _WriteSd;
+
+ case EditCannedSd : *Length = _EditLength;
+ return _EditSd;
+
+ default : *Length = 0;
+ return NULL;
+ }
+}
+
+#if !defined( _SETUP_LOADER_ )
+
+BOOLEAN
+QueryWorldSid(
+ OUT PSID NewSid,
+ IN OUT PULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This functions fetches the SID for WORLD.
+
+Arguments:
+
+ NewSid -- Supplies buffer in which the SID will be created.
+ Length -- Supplies the length of the buffer; receives the
+ length of the actual SID.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ SID_IDENTIFIER_AUTHORITY IdentifierAuthority = SECURITY_WORLD_SID_AUTHORITY;
+ ULONG LengthNeeded;
+ NTSTATUS Status;
+
+ // WORLD is a well-known SID with one subauthority. Make sure
+ // that the buffer is big enough:
+ //
+ LengthNeeded = RtlLengthRequiredSid( 1 );
+
+ if( *Length < LengthNeeded ) {
+
+ return FALSE;
+ }
+
+ *Length = LengthNeeded;
+
+ // Initialize the SID and fill in the subauthority:
+ //
+ Status = RtlInitializeSid( NewSid,
+ &IdentifierAuthority,
+ 1 );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ DebugPrintf( "IFSUTIL: RtlInitializeSid failed--status 0x%x\n", Status );
+ return FALSE;
+ }
+
+ *(RtlSubAuthoritySid( NewSid, 0 )) = SECURITY_WORLD_RID;
+
+ return TRUE;
+}
+
+NTSTATUS
+AddInheritableAccessAllowedAce(
+ IN OUT PACL Acl,
+ IN ULONG AceRevision,
+ IN ACCESS_MASK AccessMask,
+ IN PSID Sid
+ )
+/*++
+
+Routine Description:
+
+ This routine adds an ACCESS_ALLOWED ACE to an ACL. This is
+ expected to be a common form of ACL modification. The inheritance
+ flags are set so that this ACE will apply to the current item
+ and will be propagated to child containers and objects.
+
+Arguments:
+
+ Acl - Supplies the Acl being modified
+
+ AceRevision - Supplies the Acl/Ace revision of the ACE being added
+
+ AccessMask - The mask of accesses to be granted to the specified SID.
+
+ Sid - Pointer to the SID being granted access.
+
+
+Return Value:
+
+ STATUS_SUCCESS - The ACE was successfully added.
+ anything else - The ACE was not successfully added.
+
+--*/
+{
+ PACCESS_ALLOWED_ACE NewAce;
+ ULONG AceSize;
+ NTSTATUS Status;
+
+ AceSize = (USHORT)(sizeof(ACE_HEADER) +
+ sizeof(ACCESS_MASK) +
+ RtlLengthSid(Sid));
+
+ NewAce = (PACCESS_ALLOWED_ACE)MALLOC( AceSize );
+
+ if( NewAce == NULL ) {
+
+ return STATUS_NO_MEMORY;
+ }
+
+ NewAce->Header.AceFlags = OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
+ NewAce->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
+ NewAce->Header.AceSize = (USHORT)AceSize;
+ NewAce->Mask = AccessMask;
+ RtlCopySid( RtlLengthSid(Sid), (PSID)(&NewAce->SidStart), Sid );
+
+ Status = RtlAddAce( Acl, AceRevision, MAXULONG, NewAce, AceSize );
+
+ FREE( NewAce );
+
+ return Status;
+}
+
+
+BOOLEAN
+GenerateWorldAcl(
+ OUT PACL AclBuffer,
+ IN ULONG BufferLength
+ )
+/*++
+
+Routine Description:
+
+ This function creates an ACL that grants full access to all
+ the world.
+
+Arguments:
+
+ AclBuffer -- Supplies the buffer in which the ACL
+ will be created.
+ BufferLength -- Supplies the length of the buffer
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ CONST WorldSidBufferLength = 64;
+ BYTE WorldSidBuffer[WorldSidBufferLength];
+
+ ULONG WorldSidLength = WorldSidBufferLength;
+ PSID WorldSid = (PSID)WorldSidBuffer;
+
+ if( !QueryWorldSid( WorldSid, &WorldSidLength ) ) {
+
+ return FALSE;
+ }
+
+ ACL_SIZE_INFORMATION AclSizeInfo;
+ PACL NewAcl;
+ NTSTATUS Status;
+
+ // This is rather complicated, since we want to use the minimum
+ // space for this ACL, but have to give it the buffer size in
+ // advance. To deal with this problem, we build the ACL up
+ // twice. The first time, we initialize it with the entire
+ // buffer. Once it's complete, we can ask it how big it really
+ // is, and rebuild it with the correct size.
+ //
+ NewAcl = (PACL)AclBuffer;
+ Status = RtlCreateAcl( NewAcl, BufferLength, ACL_REVISION );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ DebugPrintf( "IFSUTIL: RtlCreateAcl failed--status 0x%x.\n", Status );
+ return FALSE;
+ }
+
+ // This ACL always has one ACE, which grants the world full
+ // access:
+ //
+ Status = AddInheritableAccessAllowedAce( NewAcl,
+ ACL_REVISION,
+ GENERIC_ALL,
+ WorldSid );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ DebugPrintf( "IFSUTIL: RtlAddAccessAllowedAce failed--status 0x%x.\n", Status );
+ return FALSE;
+ }
+
+
+ // Now determine the size of this ACL:
+ //
+ RtlQueryInformationAcl( NewAcl,
+ &AclSizeInfo,
+ sizeof( ACL_SIZE_INFORMATION ),
+ AclSizeInformation );
+
+ // Now reinitialize and rebuild the ACL with the correct size:
+ //
+ Status = RtlCreateAcl( NewAcl, AclSizeInfo.AclBytesInUse, ACL_REVISION );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ DebugPrintf( "IFSUTIL: RtlCreateAcl failed--status 0x%x.\n", Status );
+ return FALSE;
+ }
+
+ Status = AddInheritableAccessAllowedAce( NewAcl,
+ ACL_REVISION,
+ GENERIC_ALL,
+ WorldSid );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ DebugPrintf( "IFSUTIL: RtlAddAccessAllowedAce failed--status 0x%x.\n", Status );
+ return FALSE;
+ }
+
+
+ return TRUE;
+}
+
+
+BOOLEAN
+CANNED_SECURITY::QuerySystemSid(
+ OUT PSID NewSid,
+ IN OUT PULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This method fetches the SID for the SYSTEM account.
+
+Arguments:
+
+ NewSid -- Supplies the buffer in which the SID will be created.
+ Length -- Supplies the length of the buffer; receives the length
+ of the actual SID.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ SID_IDENTIFIER_AUTHORITY IdentifierAuthority = SECURITY_NT_AUTHORITY;
+ ULONG LengthNeeded;
+ NTSTATUS Status;
+
+ // System is a well-known SID with one subauthority. Make sure
+ // that the buffer is big enough:
+ //
+ LengthNeeded = RtlLengthRequiredSid( 1 );
+
+ if( *Length < LengthNeeded ) {
+
+ return FALSE;
+ }
+
+ *Length = LengthNeeded;
+
+ // Initialize the SID and fill in the subauthority:
+ //
+ Status = RtlInitializeSid( NewSid,
+ &IdentifierAuthority,
+ 1 );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ DebugPrintf( "IFSUTIL: RtlInitializeSid failed--status 0x%x\n", Status );
+ return FALSE;
+ }
+
+ *(RtlSubAuthoritySid( NewSid, 0 )) = SECURITY_LOCAL_SYSTEM_RID;
+
+ return TRUE;
+}
+
+
+BOOLEAN
+CANNED_SECURITY::QueryAdminsSid(
+ OUT PSID NewSid,
+ IN OUT PULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This method fetches the SID for the WORKSTATION ADMINISTRATORS
+ alias.
+
+Arguments:
+
+ NewSid -- Supplies the buffer in which the SID will be created.
+ Length -- Supplies the length of the buffer; receives the length
+ of the actual SID.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ SID_IDENTIFIER_AUTHORITY IdentifierAuthority = SECURITY_NT_AUTHORITY;
+ ULONG LengthNeeded;
+ NTSTATUS Status;
+
+ // Admins is a well-known SID with two subauthorities. Make sure
+ // that the buffer is big enough:
+ //
+ LengthNeeded = RtlLengthRequiredSid( 2 );
+
+ if( *Length < LengthNeeded ) {
+
+ return FALSE;
+ }
+
+ *Length = LengthNeeded;
+
+ // Initialize the SID and fill in the two subauthorities:
+ //
+ Status = RtlInitializeSid( NewSid,
+ &IdentifierAuthority,
+ 2 );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ DebugPrintf( "IFSUTIL: RtlInitializeSid failed--status 0x%x\n", Status );
+ return FALSE;
+ }
+
+ *(RtlSubAuthoritySid( NewSid, 0 )) = SECURITY_BUILTIN_DOMAIN_RID;
+ *(RtlSubAuthoritySid( NewSid, 1 )) = DOMAIN_ALIAS_RID_ADMINS;
+
+ return TRUE;
+}
+
+
+
+PVOID
+CANNED_SECURITY::GenerateCannedSd(
+ IN BOOLEAN DaclPresent,
+ IN ACCESS_MASK GrantedAccess,
+ IN PSID AdminsSid,
+ IN PSID SystemSid,
+ IN HANDLE TokenHandle,
+ OUT PULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This method generates a self-relative Security Descriptor
+ which grants the specified access to System and Administrators.
+
+Arguments:
+
+ DaclPresent -- Supplies a flag that indicates whether this
+ Security Descriptor will have a discretionary
+ ACL. If this flag is FALSE, the GrantedAccess
+ parameter is ignored.
+ GrantedAccess -- Supplies the access that System and Administrators
+ will have to the file protected by this Security
+ Descriptor. A value of zero indicates that no
+ aces are to be created.
+ AdminsSid -- Supplies the SID for Administrators.
+ SystemSid -- Supplies the SID for System.
+ Length -- Receives the length of the Security Descriptor.
+
+Return Value:
+
+ A pointer to the generated Security Descriptor. NULL indicates
+ failure.
+
+--*/
+{
+ CONST CannedAclBufferLength = 2048;
+ STATIC BYTE CannedAclBuffer[CannedAclBufferLength];
+
+ SECURITY_DESCRIPTOR AbsoluteSd;
+ PSECURITY_DESCRIPTOR SelfRelativeSd;
+ NTSTATUS Status;
+
+ // Create an absolute Security Descriptor.
+ //
+ Status = RtlCreateSecurityDescriptor( &AbsoluteSd,
+ SECURITY_DESCRIPTOR_REVISION );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ DebugPrintf( "RtlCreateSecurityDescriptor failed--status 0x%x.\n", Status );
+ return NULL;
+ }
+
+ // The owner and group is ADMINS.
+ //
+ Status = RtlSetOwnerSecurityDescriptor( &AbsoluteSd,
+ AdminsSid,
+ TRUE );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ DebugPrintf( "IFSUTIL: RtlSetOwnerSecurityDescriptor failed--status 0x%x\n", Status );
+ return NULL;
+ }
+
+ Status = RtlSetGroupSecurityDescriptor( &AbsoluteSd,
+ AdminsSid,
+ TRUE );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ DebugPrintf( "IFSUTIL: RtlSetGroupSecurityDescriptor failed--status 0x%x\n", Status );
+ return NULL;
+ }
+
+ if( DaclPresent ) {
+
+ // The client wants to put a discretionary ACL on this
+ // security descriptor.
+ //
+ if( !GenerateCannedAcl( (PACL)CannedAclBuffer,
+ CannedAclBufferLength,
+ GrantedAccess,
+ AdminsSid,
+ SystemSid ) ) {
+
+ return NULL;
+ }
+
+ // Attach the new ACL to the Security Descriptor. Pass in
+ // TRUE for DaclPresent (since that's what we're setting)
+ // and for DaclDefaulted (since these canned Security
+ // Descriptors are defaults).
+ //
+ Status = RtlSetDaclSecurityDescriptor( &AbsoluteSd,
+ TRUE,
+ (PACL)CannedAclBuffer,
+ TRUE );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ DebugPrintf( "RtlSetDaclSecurityDescriptor failed--status 0x%x.\n", Status );
+ return NULL;
+ }
+
+ } else {
+
+ // The client has not specified a discretionary ACL, so
+ // we'll create an ACL that grants full access to all
+ // the world.
+ //
+ if( !GenerateWorldAcl( (PACL)CannedAclBuffer,
+ CannedAclBufferLength ) ){
+
+ return NULL;
+ }
+
+
+ // Attach the new ACL to the Security Descriptor. Pass in
+ // TRUE for DaclPresent (since that's what we're setting)
+ // and for DaclDefaulted (since these canned Security
+ // Descriptors are defaults).
+ //
+ Status = RtlSetDaclSecurityDescriptor( &AbsoluteSd,
+ TRUE,
+ (PACL)CannedAclBuffer,
+ TRUE );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ DebugPrintf( "RtlSetDaclSecurityDescriptor failed--status 0x%x.\n", Status );
+ return NULL;
+ }
+ }
+
+ // Now call RtlNewSecurityObject to massage this security
+ // descriptor into a self-relative security descriptor
+ // that canned be slammed onto files.
+ //
+ Status = RtlNewSecurityObject( NULL,
+ &AbsoluteSd,
+ &SelfRelativeSd,
+ FALSE,
+ TokenHandle,
+ &IopFileMapping );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ DebugPrintf( "IFSUTIL: RtlNewSecurityObject failed--status = 0x%x\n", Status );
+ return NULL;
+ }
+
+ // Make sure the returned security descriptor is valid:
+ //
+ if( !RtlValidSecurityDescriptor( SelfRelativeSd ) ) {
+
+ DebugPrint( "IFSUTIL: RtlNewSecurityObject did not return a valid security descriptor.\n" );
+
+ RtlFreeHeap( RtlProcessHeap(), 0, SelfRelativeSd );
+ return NULL;
+ }
+
+ *Length = RtlLengthSecurityDescriptor( SelfRelativeSd );
+ return SelfRelativeSd;
+}
+
+
+BOOLEAN
+CANNED_SECURITY::GenerateCannedAcl(
+ IN PACL AclBuffer,
+ IN ULONG BufferLength,
+ IN ACCESS_MASK GrantedAccess,
+ IN PSID AdminsSid,
+ IN PSID SystemSid
+ )
+/*++
+
+Routine Description:
+
+ This method builds up an ACL in the supplied buffer.
+
+Arguments:
+
+ AclBuffer -- Supplies the buffer in which to build the ACL.
+ BufferLength -- Supplies the length of the buffer (in bytes).
+ GrantedAccess -- Supplies the access the ACL will grant to
+ SYSTEM and ADMINS.
+ AdminsSid -- Supplies the SID for administrators.
+ SystemSid -- Supplies the SID for SYSTEM.
+
+--*/
+{
+ ACL_SIZE_INFORMATION AclSizeInfo;
+ PACL NewAcl;
+ NTSTATUS Status;
+
+ // This is rather complicated, since we want to use the minimum
+ // space for this ACL, but have to give it the buffer size in
+ // advance. To deal with this problem, we build the ACL up
+ // twice. The first time, we initialize it with the entire
+ // buffer. Once it's complete, we can ask it how big it really
+ // is, and rebuild it with the correct size.
+ //
+ NewAcl = (PACL)AclBuffer;
+ Status = RtlCreateAcl( NewAcl, BufferLength, ACL_REVISION );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ DebugPrintf( "IFSUTIL: RtlCreateAcl failed--status 0x%x.\n", Status );
+ return FALSE;
+ }
+
+ if( GrantedAccess != 0 ) {
+
+ // The client wants an ACL that grants certain access
+ // rights to System and Administrators.
+ //
+ Status = RtlAddAccessAllowedAce( NewAcl,
+ ACL_REVISION,
+ GrantedAccess,
+ SystemSid );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ DebugPrintf( "IFSUTIL: RtlAddAccessAllowedAce failed--status 0x%x.\n", Status );
+ return FALSE;
+ }
+
+ Status = RtlAddAccessAllowedAce( NewAcl,
+ ACL_REVISION,
+ GrantedAccess,
+ AdminsSid );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ DebugPrintf( "IFSUTIL: RtlAddAccessAllowedAce failed--status 0x%x.\n", Status );
+ return FALSE;
+ }
+ }
+
+ // Now determine the size of this ACL:
+ //
+ RtlQueryInformationAcl( NewAcl,
+ &AclSizeInfo,
+ sizeof( ACL_SIZE_INFORMATION ),
+ AclSizeInformation );
+
+ // Now reinitialize and rebuild the ACL with the correct size:
+ //
+ Status = RtlCreateAcl( NewAcl, AclSizeInfo.AclBytesInUse, ACL_REVISION );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ DebugPrintf( "IFSUTIL: RtlCreateAcl failed--status 0x%x.\n", Status );
+ return FALSE;
+ }
+
+ if( GrantedAccess != 0 ) {
+
+ // The client wants an ACL that grants certain access
+ // rights to System and Administrators.
+ //
+ Status = RtlAddAccessAllowedAce( NewAcl,
+ ACL_REVISION,
+ GrantedAccess,
+ SystemSid );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ DebugPrintf( "IFSUTIL: RtlAddAccessAllowedAce failed--status 0x%x.\n", Status );
+ return FALSE;
+ }
+
+ Status = RtlAddAccessAllowedAce( NewAcl,
+ ACL_REVISION,
+ GrantedAccess,
+ AdminsSid );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ DebugPrintf( "IFSUTIL: RtlAddAccessAllowedAce failed--status 0x%x.\n", Status );
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+#endif // _SETUP_LOADER_
diff --git a/private/utils/ifsutil/src/dcache.cxx b/private/utils/ifsutil/src/dcache.cxx
new file mode 100644
index 000000000..daec992c3
--- /dev/null
+++ b/private/utils/ifsutil/src/dcache.cxx
@@ -0,0 +1,192 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+#include "dcache.hxx"
+
+
+DEFINE_CONSTRUCTOR( DRIVE_CACHE, OBJECT );
+
+
+DRIVE_CACHE::~DRIVE_CACHE(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for DRIVE_CACHE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+DRIVE_CACHE::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Contructor for DRIVE_CACHE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _drive = NULL;
+}
+
+
+VOID
+DRIVE_CACHE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for DRIVE_CACHE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _drive = NULL;
+}
+
+
+BOOLEAN
+DRIVE_CACHE::Initialize(
+ IN OUT PIO_DP_DRIVE Drive
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes a DRIVE_CACHE object.
+
+Arguments:
+
+ Drive - Supplies the drive to cache for.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ DebugAssert(Drive);
+
+ Destroy();
+ _drive = Drive;
+ return TRUE;
+}
+
+
+BOOLEAN
+DRIVE_CACHE::Read(
+ IN BIG_INT StartingSector,
+ IN SECTORCOUNT NumberOfSectors,
+ OUT PVOID Buffer
+ )
+/*++
+
+Routine Description:
+
+ This routine reads the requested sectors directly from the disk.
+
+Arguments:
+
+ StartingSector - Supplies the first sector to be read.
+ NumberOfSectors - Supplies the number of sectors to be read.
+ Buffer - Supplies the buffer to read the run of sectors to.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ DebugAssert(_drive);
+ return _drive->HardRead(StartingSector, NumberOfSectors, Buffer);
+}
+
+
+BOOLEAN
+DRIVE_CACHE::Write(
+ IN BIG_INT StartingSector,
+ IN SECTORCOUNT NumberOfSectors,
+ IN PVOID Buffer
+ )
+/*++
+
+Routine Description:
+
+ This routine writes the requested sectors directly to the disk.
+
+Arguments:
+
+ StartingSector - Supplies the first sector to be written.
+ NumberOfSectors - Supplies the number of sectors to be written.
+ Buffer - Supplies the buffer to write the run of sectors from.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ DebugAssert(_drive);
+ return _drive->HardWrite(StartingSector, NumberOfSectors, Buffer);
+}
+
+
+BOOLEAN
+DRIVE_CACHE::Flush(
+ )
+/*++
+
+Routine Description:
+
+ This routine flushes all dirty cache blocks to disk. This routine
+ returns FALSE if there has ever been an write error since the last
+ flush.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ return TRUE;
+}
diff --git a/private/utils/ifsutil/src/digraph.cxx b/private/utils/ifsutil/src/digraph.cxx
new file mode 100644
index 000000000..acd2e70f5
--- /dev/null
+++ b/private/utils/ifsutil/src/digraph.cxx
@@ -0,0 +1,875 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ digraph.cxx
+
+Abstract:
+
+ This module implements the Directed Graph class.
+
+Author:
+
+ Matthew Bradburn (mattbr) 11-Nov-1994
+
+Remarks:
+
+ The class is implemented as a mapping from parent to child.
+ There is a hash table of parents, with a linked-list of parent nodes
+ from each hash table bucket... each parent node then holds a pointer
+ to a tree of child nodes which share an edge with that parent. In an
+ attempt to save memory, each child node actually has a starting value
+ and a bitmap which describes the possible children immediately following
+ that starting value.
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _IFSUTIL_MEMBER_
+
+#include "ulib.hxx"
+#include "ifsutil.hxx"
+
+#include "digraph.hxx"
+#include "numset.hxx"
+#include "bitvect.hxx"
+#include "list.hxx"
+#include "intstack.hxx"
+
+
+CONST NumHeads = 1024;
+
+DEFINE_EXPORTED_CONSTRUCTOR( DIGRAPH, OBJECT, IFSUTIL_EXPORT );
+
+DEFINE_EXPORTED_CONSTRUCTOR( DIGRAPH_EDGE, OBJECT, IFSUTIL_EXPORT );
+
+VOID
+DIGRAPH::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Constructor for DIGRAPH.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _parent_head = NULL;
+ _num_nodes = 0;
+}
+
+
+VOID
+DIGRAPH::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the DIGRAPH to its initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DELETE(_parent_head);
+ _num_nodes = 0;
+}
+
+
+IFSUTIL_EXPORT
+DIGRAPH::~DIGRAPH(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for DIGRAPH.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+DIGRAPH::Initialize(
+ IN ULONG NumberOfNodes
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes this class to an empty directed graph.
+
+Arguments:
+
+ NumberOfNodes - Supplies the number of nodes in the graph.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ Destroy();
+
+ _num_nodes = NumberOfNodes;
+
+ if (!(_parent_head = NEW PPARENT_ENTRY[NumHeads]) ||
+ !_parent_mgr.Initialize(sizeof(PARENT_ENTRY))) {
+
+ return FALSE;
+ }
+
+ memset(_parent_head, 0, sizeof(PPARENT_ENTRY)*NumHeads);
+
+ return TRUE;
+}
+
+RTL_GENERIC_COMPARE_RESULTS
+GenericChildCompare(
+ RTL_GENERIC_TABLE *Table,
+ PVOID First,
+ PVOID Second
+ )
+/*++
+
+Routine Description:
+
+ This routine is required for use by the Generic Table package.
+ In this case it will be used only to find the node containing
+ a particular child, and the caller will search the bits in that
+ node after that.
+
+
+--*/
+{
+ PCHILD_ENTRY FirstChild = PCHILD_ENTRY(First);
+ PCHILD_ENTRY SecondChild = PCHILD_ENTRY(Second);
+
+ if (FirstChild->Child < SecondChild->Child) {
+ return GenericLessThan;
+ }
+ if (FirstChild->Child > SecondChild->Child) {
+ return GenericGreaterThan;
+ }
+ return GenericEqual;
+}
+
+PVOID
+NTAPI
+GenericChildAllocate(
+ RTL_GENERIC_TABLE *Table,
+ CLONG ByteSize
+ )
+{
+ // return MALLOC(ByteSize);
+
+ return NEW BYTE[ByteSize];
+}
+
+VOID
+NTAPI
+GenericChildDeallocate(
+ RTL_GENERIC_TABLE *Table,
+ PVOID Buffer
+ )
+{
+ // FREE(Buffer);
+
+ delete[] Buffer;
+}
+
+PPARENT_ENTRY
+DIGRAPH::GetParentEntry(
+ IN ULONG Parent
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine searches for the requested parent entry and returns it if
+ it is found.
+
+Arguments:
+
+ Parent - Supplies the number of the parent.
+
+Return Value:
+
+ A pointer to the requested parent entry or NULL.
+
+--*/
+{
+ PPARENT_ENTRY r;
+
+ for (r = _parent_head[Parent%NumHeads]; NULL != r; r = r->Next) {
+ if (r->Parent == Parent) {
+ break;
+ }
+ }
+
+ return r;
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+DIGRAPH::AddEdge(
+ IN ULONG Parent,
+ IN ULONG Child
+ )
+/*++
+
+Routine Description:
+
+ This routine adds an edge to the digraph.
+
+Arguments:
+
+ Parent - Supplies the source node of the edge.
+ Child - Supplies the destination node of the edge.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ DebugAssert(Parent < _num_nodes);
+ DebugAssert(Child < _num_nodes);
+
+ PPARENT_ENTRY parent_entry;
+ CHILD_ENTRY new_child;
+ PCHILD_ENTRY pChild;
+ RTL_BITMAP bitmap_hdr;
+
+ memset(&new_child, 0, sizeof(new_child));
+
+ //
+ // Figure out which node we're looking for by rounding Child down
+ // to the appropriate alignment.
+ //
+
+ new_child.Child = Child & ~(BITS_PER_CHILD_ENTRY - 1);
+
+ DebugAssert(new_child.Child <= Child);
+ DebugAssert(new_child.Child + BITS_PER_CHILD_ENTRY >= Child);
+
+ if (!(parent_entry = GetParentEntry(Parent))) {
+ if (!(parent_entry = (PPARENT_ENTRY) _parent_mgr.Alloc())) {
+ return FALSE;
+ }
+
+ parent_entry->Next = _parent_head[Parent%NumHeads];
+ parent_entry->Parent = Parent;
+
+ RtlInitializeGenericTable(
+ &parent_entry->Children,
+ GenericChildCompare,
+ GenericChildAllocate,
+ GenericChildDeallocate,
+ 0
+ );
+
+ _parent_head[Parent%NumHeads] = parent_entry;
+ }
+
+ pChild = (PCHILD_ENTRY)RtlInsertElementGenericTable(
+ &parent_entry->Children,
+ &new_child,
+ sizeof(new_child),
+ NULL
+ );
+ if (NULL == pChild) {
+ return FALSE;
+ }
+
+ RtlInitializeBitMap(&bitmap_hdr, pChild->ChildBits, BITS_PER_CHILD_ENTRY);
+
+ RtlSetBits(&bitmap_hdr, Child - new_child.Child, 1);
+
+ return TRUE;
+}
+
+
+BOOLEAN
+DIGRAPH::RemoveEdge(
+ IN ULONG Parent,
+ IN ULONG Child
+ )
+/*++
+
+Routine Description:
+
+ This routine removes an edge from the digraph.
+
+Arguments:
+
+ Parent - Supplies the source node of the edge.
+ Child - Supplies the destination node of the edge.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ DebugAssert(Parent < _num_nodes);
+ DebugAssert(Child < _num_nodes);
+
+ PPARENT_ENTRY parent_entry;
+ CHILD_ENTRY curr;
+ PCHILD_ENTRY pChild;
+ RTL_BITMAP bitmap_hdr;
+
+ curr.Child = Child & ~(BITS_PER_CHILD_ENTRY - 1);
+
+ if (!(parent_entry = GetParentEntry(Parent))) {
+ return TRUE;
+ }
+
+ pChild = (PCHILD_ENTRY)RtlLookupElementGenericTable(
+ &parent_entry->Children,
+ &curr);
+ if (NULL == pChild) {
+ return TRUE;
+ }
+
+ RtlInitializeBitMap(&bitmap_hdr, pChild->ChildBits, BITS_PER_CHILD_ENTRY);
+
+ RtlClearBits(&bitmap_hdr, Child - curr.Child, 1);
+
+ //
+ // Now if the entire bitmap for this node is clear, we'll delete
+ // the node itself.
+ //
+
+ if ((ULONG)-1 == RtlFindSetBits(&bitmap_hdr, 1, 0)) {
+ RtlDeleteElementGenericTable(&parent_entry->Children, &curr);
+ }
+
+ return TRUE;
+}
+
+
+ULONG
+DIGRAPH::QueryNumChildren(
+ IN ULONG Parent
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of children that belong to the
+ given parent.
+
+Arguments:
+
+ Parent - Supplies the parent node.
+
+Return Value:
+
+ The number of children pointed to by the parent.
+
+--*/
+{
+ PPARENT_ENTRY parent_entry;
+ RTL_BITMAP bitmap_hdr;
+ PVOID restart_key;
+ PVOID ptr;
+ ULONG r;
+
+ if (!(parent_entry = GetParentEntry(Parent))) {
+ return 0;
+ }
+
+ //
+ // Need to enuerate through all the children and count the bits in
+ // each bitmap.
+ //
+
+ r = 0;
+ restart_key = NULL;
+
+ for (ptr = RtlEnumerateGenericTableWithoutSplaying(
+ &parent_entry->Children, &restart_key);
+ ptr != NULL;
+ ptr = RtlEnumerateGenericTableWithoutSplaying(
+ &parent_entry->Children, &restart_key)) {
+
+ RtlInitializeBitMap(&bitmap_hdr, PCHILD_ENTRY(ptr)->ChildBits,
+ BITS_PER_CHILD_ENTRY);
+
+ r += RtlNumberOfSetBits(&bitmap_hdr);
+ }
+
+ return r;
+}
+
+
+ULONG
+DIGRAPH::QueryNumParents(
+ IN ULONG Child
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of parents that belong to the
+ given child.
+
+Arguments:
+
+ Child - Supplies the child node.
+
+Return Value:
+
+ The number of parents that point to the child.
+
+--*/
+{
+ ULONG i, r;
+ PPARENT_ENTRY currp;
+ CHILD_ENTRY curr;
+ RTL_BITMAP bitmap_hdr;
+ PCHILD_ENTRY pChild;
+
+ curr.Child = Child & ~(BITS_PER_CHILD_ENTRY - 1);
+
+ r = 0;
+ for (i = 0; i < NumHeads; i++) {
+ for (currp = _parent_head[i]; currp; currp = currp->Next) {
+
+ //
+ // Increment <r> if the child tree contains <Child>.
+ //
+
+ pChild = (PCHILD_ENTRY)RtlLookupElementGenericTable(
+ &currp->Children, &curr);
+ if (NULL == pChild) {
+ continue;
+ }
+
+ RtlInitializeBitMap(&bitmap_hdr, pChild->ChildBits,
+ BITS_PER_CHILD_ENTRY);
+
+ if (RtlCheckBit(&bitmap_hdr, Child - curr.Child)) {
+ r++;
+ }
+ }
+ }
+
+ return r;
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+DIGRAPH::QueryChildren(
+ IN ULONG Parent,
+ OUT PNUMBER_SET Children
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the children of the given parent.
+
+Arguments:
+
+ Parent - Supplies the parent.
+ Children - Return the children.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PPARENT_ENTRY parent_entry;
+ RTL_BITMAP bitmap_hdr;
+ PVOID restart_key;
+ PVOID ptr;
+ ULONG i;
+
+ if (!Children->Initialize()) {
+ return FALSE;
+ }
+
+ if (!(parent_entry = GetParentEntry(Parent))) {
+ return TRUE;
+ }
+
+ restart_key = NULL;
+ for (ptr = RtlEnumerateGenericTableWithoutSplaying(
+ &parent_entry->Children, &restart_key);
+ ptr != NULL;
+ ptr = RtlEnumerateGenericTableWithoutSplaying(
+ &parent_entry->Children, &restart_key)) {
+
+ //
+ // Add a child for each set bit in this node.
+ //
+
+ RtlInitializeBitMap(&bitmap_hdr, PCHILD_ENTRY(ptr)->ChildBits,
+ BITS_PER_CHILD_ENTRY);
+
+ for (i = 0; i < BITS_PER_CHILD_ENTRY; ++i) {
+
+ if (RtlCheckBit(&bitmap_hdr, i)) {
+
+ if (!Children->Add(PCHILD_ENTRY(ptr)->Child + i)) {
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+DIGRAPH::QueryParents(
+ IN ULONG Child,
+ OUT PNUMBER_SET Parents
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the parents of the given child.
+
+Arguments:
+
+ Child - Supplies the child.
+ Parents - Return the parents.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG i;
+ PPARENT_ENTRY currp;
+ CHILD_ENTRY curr;
+ PCHILD_ENTRY pChild;
+ RTL_BITMAP bitmap_hdr;
+
+ curr.Child = Child & ~(BITS_PER_CHILD_ENTRY - 1);
+
+ if (!Parents->Initialize()) {
+ return FALSE;
+ }
+
+ for (i = 0; i < NumHeads; i++) {
+ for (currp = _parent_head[i]; currp; currp = currp->Next) {
+
+ pChild = (PCHILD_ENTRY)RtlLookupElementGenericTable(
+ &currp->Children, &curr);
+ if (NULL == pChild) {
+ continue;
+ }
+
+ RtlInitializeBitMap(&bitmap_hdr, pChild->ChildBits,
+ BITS_PER_CHILD_ENTRY);
+
+ if (RtlCheckBit(&bitmap_hdr, Child - curr.Child)) {
+
+ if (!Parents->Add(currp->Parent)) {
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+DIGRAPH::QueryParentsWithChildren(
+ OUT PNUMBER_SET Parents,
+ IN ULONG MinimumNumberOfChildren
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns a list of all digraph nodes with out degree
+ greater than or equal to the given minimum.
+
+Arguments:
+
+ Parents - Returns a list of parents.
+ MinimumNumberOfChildren - Supplies the minimum number of children
+ that a parent must have to qualify for
+ the list.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG i;
+ PPARENT_ENTRY currp;
+ ULONG count;
+ RTL_BITMAP bitmap_hdr;
+ PVOID ptr;
+ PVOID restart_key;
+
+ if (!Parents->Initialize()) {
+ return FALSE;
+ }
+
+ if (!MinimumNumberOfChildren) {
+ return Parents->Add(0, _num_nodes);
+ }
+
+ for (i = 0; i < NumHeads; i++) {
+ for (currp = _parent_head[i]; currp; currp = currp->Next) {
+
+ //
+ // Need to enumerate nodes of the tree and count bits in
+ // each node.
+ //
+
+ restart_key = NULL;
+ count = 0;
+
+ for (ptr = RtlEnumerateGenericTableWithoutSplaying(
+ &currp->Children, &restart_key);
+ ptr != NULL;
+ ptr = RtlEnumerateGenericTableWithoutSplaying(
+ &currp->Children, &restart_key)) {
+
+ RtlInitializeBitMap(&bitmap_hdr, PCHILD_ENTRY(ptr)->ChildBits,
+ BITS_PER_CHILD_ENTRY);
+
+ count += RtlNumberOfSetBits(&bitmap_hdr);
+
+ if (count >= MinimumNumberOfChildren) {
+ break;
+ }
+ }
+
+ if (count >= MinimumNumberOfChildren) {
+ if (!Parents->Add(currp->Parent)) {
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+DIGRAPH::EliminateCycles(
+ IN OUT PCONTAINER RemovedEdges
+ )
+/*++
+
+Routine Description:
+
+ This routine eliminates cycles from the digraph and then returns
+ the edges that had to be removed.
+
+Arguments:
+
+ RemovedEdges - Returns the edges removed from the digraph.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ BITVECTOR visited;
+ ULONG i;
+ INTSTACK ancestors;
+
+ if (!visited.Initialize(_num_nodes) || !ancestors.Initialize()) {
+ return FALSE;
+ }
+
+ for (i = 0; i < _num_nodes; i++) {
+
+ if (!visited.IsBitSet(i) &&
+ !DescendDigraph(i, &visited, &ancestors, RemovedEdges)) {
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+DIGRAPH::DescendDigraph(
+ IN ULONG CurrentNode,
+ IN OUT PBITVECTOR Visited,
+ IN OUT PINTSTACK Ancestors,
+ IN OUT PCONTAINER RemovedEdges
+ )
+/*++
+
+Routine Description:
+
+ This routine does a depth first search on the digraph.
+
+Arguments:
+
+ CurrentNode - Supplies the current node being evaluated.
+ Visited - Supplies a list of nodes which have been visited.
+ Ancestors - Supplies a stack of direct ancestors.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PPARENT_ENTRY parent_entry;
+ PNUMBER_SET nodes_to_delete;
+ ULONG i, set_card, child_node;
+ PDIGRAPH_EDGE p;
+ RTL_BITMAP bitmap_hdr;
+ PVOID restart_key;
+ PVOID ptr;
+
+ Visited->SetBit(CurrentNode);
+ if (!Ancestors->Push(CurrentNode)) {
+ return FALSE;
+ }
+
+ nodes_to_delete = NULL;
+
+ if (NULL != (parent_entry = GetParentEntry(CurrentNode))) {
+
+ // traverse list
+
+ restart_key = NULL;
+ for (ptr = RtlEnumerateGenericTableWithoutSplaying(
+ &parent_entry->Children, &restart_key);
+ ptr != NULL;
+ ptr = RtlEnumerateGenericTableWithoutSplaying(
+ &parent_entry->Children, &restart_key)) {
+
+ for (i = 0; i < BITS_PER_CHILD_ENTRY; ++i) {
+
+ RtlInitializeBitMap(&bitmap_hdr, PCHILD_ENTRY(ptr)->ChildBits,
+ BITS_PER_CHILD_ENTRY);
+
+ if (0 == RtlCheckBit(&bitmap_hdr, i)) {
+ continue;
+ }
+
+ //
+ // Child + i is a child of this parent.
+ //
+
+
+ if (Visited->IsBitSet(PCHILD_ENTRY(ptr)->Child + i)) {
+
+ // Check for cycle.
+
+ if (Ancestors->IsMember(PCHILD_ENTRY(ptr)->Child + i)) {
+
+ // Cycle detected.
+
+ if (!nodes_to_delete) {
+ if (!(nodes_to_delete = NEW NUMBER_SET) ||
+ !nodes_to_delete->Initialize()) {
+
+ return FALSE;
+ }
+ }
+
+ if (!nodes_to_delete->Add(PCHILD_ENTRY(ptr)->Child + i)) {
+ return FALSE;
+ }
+ }
+
+ } else if (!DescendDigraph(PCHILD_ENTRY(ptr)->Child + i, Visited,
+ Ancestors, RemovedEdges)) {
+
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ if (nodes_to_delete) {
+
+ set_card = nodes_to_delete->QueryCardinality().GetLowPart();
+
+ for (i = 0; i < set_card; i++) {
+
+ child_node = nodes_to_delete->QueryNumber(i).GetLowPart();
+
+ if (!RemoveEdge(CurrentNode, child_node)) {
+ return FALSE;
+ }
+
+ if (!(p = NEW DIGRAPH_EDGE)) {
+ return FALSE;
+ }
+
+ p->Parent = CurrentNode;
+ p->Child = child_node;
+
+ if (!RemovedEdges->Put(p)) {
+ return FALSE;
+ }
+ }
+ }
+
+ Ancestors->Pop();
+
+ return TRUE;
+}
diff --git a/private/utils/ifsutil/src/drive.cxx b/private/utils/ifsutil/src/drive.cxx
new file mode 100644
index 000000000..ec6ffd572
--- /dev/null
+++ b/private/utils/ifsutil/src/drive.cxx
@@ -0,0 +1,2552 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _IFSUTIL_MEMBER_
+
+#include "ulib.hxx"
+#include "ifsutil.hxx"
+
+#include "error.hxx"
+#include "drive.hxx"
+#include "rtmsg.h"
+#include "message.hxx"
+#include "numset.hxx"
+#include "dcache.hxx"
+#include "hmem.hxx"
+#include "ifssys.hxx"
+
+extern "C" {
+#include <stdio.h>
+};
+
+
+// Don't lock down more that 64K for IO.
+CONST MaxIoSize = 65536;
+
+// This buffer used when reading back after write
+char ScratchIoBuf[MaxIoSize + 16];
+
+DEFINE_CONSTRUCTOR( DRIVE, OBJECT );
+
+VOID
+DRIVE::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Contructor for DRIVE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ // unreferenced parameters
+ (void)(this);
+}
+
+
+DRIVE::~DRIVE(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for DRIVE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+BOOLEAN
+DRIVE::Initialize(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes a drive object.
+
+Arguments:
+
+ NtDriveName - Supplies an NT style drive name.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ Destroy();
+
+ if (!NtDriveName) {
+ Destroy();
+ return FALSE;
+ }
+
+ if (!_name.Initialize(NtDriveName)) {
+ Destroy();
+ Message ? Message->Set(MSG_FMT_NO_MEMORY) : 1;
+ Message ? Message->Display("") : 1;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+VOID
+DRIVE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a DRIVE object to its initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ // unreferenced parameters
+ (void)(this);
+}
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( DP_DRIVE, DRIVE, IFSUTIL_EXPORT );
+
+VOID
+DP_DRIVE::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Constructor for DP_DRIVE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ memset(&_actual, 0, sizeof(DRTYPE));
+ _supported_list = NULL;
+ _num_supported = 0;
+ _alignment_mask = 0;
+ _last_status = 0;
+ _handle = 0;
+ _alternate_handle = 0;
+ _hosted_drive = FALSE;
+ _super_floppy = FALSE;
+}
+
+
+IFSUTIL_EXPORT
+DP_DRIVE::~DP_DRIVE(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for DP_DRIVE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+NTSTATUS
+DP_DRIVE::OpenDrive(
+ IN PCWSTRING NtDriveName,
+ IN ACCESS_MASK DesiredAccess,
+ IN BOOLEAN ExclusiveWrite,
+ OUT PHANDLE Handle,
+ OUT PULONG Alignment,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This method is a worker function for the Initialize methods,
+ to open a volume and determine its alignment requirement.
+
+Arguments:
+
+ NtDriveName - Supplies the name of the drive.
+ DesiredAccess - Supplies the access the client desires to the volume.
+ ExclusiveWrite - Supplies a flag indicating whether the client
+ wishes to exclude other write handles.
+ Handle - Receives the handle to the opened volume.
+ Alignment - Receives the alignment requirement for the volume.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+
+--*/
+{
+ UNICODE_STRING string;
+ OBJECT_ATTRIBUTES oa;
+ IO_STATUS_BLOCK status_block;
+ FILE_ALIGNMENT_INFORMATION alignment_info;
+ MSGID MessageId;
+ NTSTATUS Status;
+
+
+ string.Length = (USHORT) NtDriveName->QueryChCount() * sizeof(WCHAR);
+ string.MaximumLength = string.Length;
+ string.Buffer = (PWSTR)NtDriveName->GetWSTR();
+
+ InitializeObjectAttributes( &oa,
+ &string,
+ OBJ_CASE_INSENSITIVE,
+ 0,
+ 0 );
+
+ Status = NtOpenFile(Handle,
+ DesiredAccess,
+ &oa, &status_block,
+ FILE_SHARE_READ |
+ (ExclusiveWrite ? 0 : FILE_SHARE_WRITE),
+ FILE_SYNCHRONOUS_IO_ALERT);
+
+ if (!NT_SUCCESS(Status)) {
+
+ MessageId = ( Status == STATUS_ACCESS_DENIED ) ?
+ MSG_DASD_ACCESS_DENIED :
+ MSG_CANT_DASD;
+
+ Message ? Message->Set( MessageId ) : 1;
+ Message ? Message->Display("") : 1;
+ return Status;
+ }
+
+
+ // Query the disk alignment information.
+
+ Status = NtQueryInformationFile(*Handle,
+ &status_block,
+ &alignment_info,
+ sizeof(FILE_ALIGNMENT_INFORMATION),
+ FileAlignmentInformation);
+
+ if (!NT_SUCCESS(Status)) {
+
+ MessageId = (Status == STATUS_DEVICE_BUSY ||
+ Status == STATUS_DEVICE_NOT_READY ) ?
+ MSG_DEVICE_BUSY :
+ MSG_BAD_IOCTL;
+
+ Message ? Message->Set(MessageId) : 1;
+ Message ? Message->Display("") : 1;
+ return Status;
+ }
+
+ *Alignment = alignment_info.AlignmentRequirement;
+
+ //
+ // Set the ALLOW_EXTENDED_DASD_IO flag for the file handle,
+ // which ntfs format and chkdsk depend on to write the backup
+ // boot sector. We ignore the return code from this, but we
+ // could go either way.
+ //
+
+ (VOID)NtFsControlFile( *Handle,
+ 0, NULL, NULL,
+ &status_block,
+ FSCTL_ALLOW_EXTENDED_DASD_IO,
+ NULL, 0, NULL, 0);
+
+ return Status;
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+DP_DRIVE::Initialize(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN IsTransient,
+ IN BOOLEAN ExclusiveWrite
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes a DP_DRIVE object based on the supplied drive
+ path.
+
+Arguments:
+
+ NtDriveName - Supplies the drive path.
+ Message - Supplies an outlet for messages.
+ IsTransient - Supplies whether or not to keep the handle to the
+ drive open beyond this method.
+ ExclusiveWrite - Supplies whether or not to open the drive for
+ exclusive write.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ CONST NumMediaTypes = 20;
+
+ IO_STATUS_BLOCK status_block;
+ DISK_GEOMETRY disk_geometry;
+ DISK_GEOMETRY media_types[NumMediaTypes];
+ INT i;
+ PARTITION_INFORMATION partition_info;
+ BOOLEAN partition;
+ MSGID MessageId;
+
+ Destroy();
+
+ if (!DRIVE::Initialize(NtDriveName, Message)) {
+ Destroy();
+ return FALSE;
+ }
+
+ _last_status = OpenDrive( NtDriveName,
+ SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
+ ExclusiveWrite,
+ &_handle,
+ &_alignment_mask,
+ Message );
+
+ if(!NT_SUCCESS(_last_status)) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ // Record that this is not a hosted volume:
+ //
+ _hosted_drive = FALSE;
+
+
+ // Query the disk geometry.
+
+ _last_status = NtDeviceIoControlFile(_handle, 0, NULL, NULL,
+ &status_block,
+ IOCTL_DISK_GET_DRIVE_GEOMETRY,
+ NULL, 0, &disk_geometry,
+ sizeof(DISK_GEOMETRY));
+
+ if (!NT_SUCCESS(_last_status)) {
+ if ((_last_status == STATUS_UNSUCCESSFUL) ||
+ (_last_status == STATUS_UNRECOGNIZED_MEDIA)) {
+ disk_geometry.MediaType = Unknown;
+ } else {
+ Destroy();
+ switch( _last_status ) {
+
+ case STATUS_NO_MEDIA_IN_DEVICE:
+ MessageId = MSG_CANT_DASD;
+ break;
+
+ case STATUS_DEVICE_BUSY:
+ case STATUS_DEVICE_NOT_READY:
+ MessageId = MSG_DEVICE_BUSY;
+ break;
+
+ default:
+ MessageId = MSG_BAD_IOCTL;
+ break;
+ }
+
+ Message ? Message->Set(MessageId) : 1;
+ Message ? Message->Display("") : 1;
+
+ return FALSE;
+ }
+ }
+
+ if (disk_geometry.MediaType == Unknown) {
+ memset(&disk_geometry, 0, sizeof(DISK_GEOMETRY));
+ disk_geometry.MediaType = Unknown;
+ }
+
+ partition = FALSE;
+
+ // Try to read the partition entry.
+
+ if (disk_geometry.MediaType == FixedMedia ||
+ disk_geometry.MediaType == RemovableMedia) {
+
+ _last_status = NtDeviceIoControlFile(_handle, 0, NULL, NULL,
+ &status_block,
+ IOCTL_DISK_GET_PARTITION_INFO,
+ NULL, 0, &partition_info,
+ sizeof(PARTITION_INFORMATION));
+
+ partition = (BOOLEAN) NT_SUCCESS(_last_status);
+
+ if (!NT_SUCCESS(_last_status) &&
+ _last_status != STATUS_INVALID_DEVICE_REQUEST) {
+
+ Destroy();
+ Message ? Message->Set(MSG_READ_PARTITION_TABLE) : 1;
+ Message ? Message->Display("") : 1;
+ return FALSE;
+ }
+
+ }
+
+
+ // Store the information in the class.
+
+ if (partition) {
+
+ DiskGeometryToDriveType(&disk_geometry,
+ partition_info.PartitionLength/
+ disk_geometry.BytesPerSector,
+ partition_info.HiddenSectors,
+ &_actual);
+
+ } else {
+
+ DiskGeometryToDriveType(&disk_geometry, &_actual);
+
+ if (IsFloppy()) {
+
+ _last_status = NtDeviceIoControlFile(_handle, 0, NULL, NULL,
+ &status_block,
+ IOCTL_DISK_GET_MEDIA_TYPES,
+ NULL, 0, media_types,
+ NumMediaTypes*
+ sizeof(DISK_GEOMETRY));
+
+ if (!NT_SUCCESS(_last_status)) {
+ Destroy();
+ Message ? Message->Set(MSG_BAD_IOCTL) : 1;
+ Message ? Message->Display("") : 1;
+ return FALSE;
+ }
+
+ _num_supported = (INT) (status_block.Information/
+ sizeof(DISK_GEOMETRY));
+
+ if (!_num_supported) {
+ Destroy();
+ Message ? Message->Set(MSG_BAD_IOCTL) : 1;
+ Message ? Message->Display("") : 1;
+ return FALSE;
+ }
+
+ if (!(_supported_list = NEW DRTYPE[_num_supported])) {
+ Destroy();
+ Message ? Message->Set(MSG_FMT_NO_MEMORY) : 1;
+ Message ? Message->Display("") : 1;
+ return FALSE;
+ }
+
+ for (i = 0; i < _num_supported; i++) {
+ DiskGeometryToDriveType(&media_types[i], &_supported_list[i]);
+ }
+ }
+ }
+
+ if (!_num_supported) {
+ _num_supported = 1;
+
+ if (!(_supported_list = NEW DRTYPE)) {
+ Destroy();
+ Message ? Message->Set(MSG_FMT_NO_MEMORY) : 1;
+ Message ? Message->Display("") : 1;
+ return FALSE;
+ }
+
+ _supported_list[0] = _actual;
+ }
+
+ //
+ // Determine whether the media is a super-floppy; non-floppy
+ // removable media which is not partitioned. Such media will
+ // have but a single partition, normal media will have at least 4.
+ //
+
+ if (disk_geometry.MediaType == RemovableMedia) {
+
+ CONST INT EntriesPerBootRecord = 4;
+ CONST INT MaxLogicalVolumes = 23;
+ CONST INT Length = sizeof(DRIVE_LAYOUT_INFORMATION) +
+ EntriesPerBootRecord * (MaxLogicalVolumes + 1) *
+ sizeof(PARTITION_INFORMATION);
+
+ UCHAR buf[Length];
+
+ DRIVE_LAYOUT_INFORMATION *layout_info = (DRIVE_LAYOUT_INFORMATION *)buf;
+
+ _last_status = NtDeviceIoControlFile(_handle, 0, NULL, NULL,
+ &status_block,
+ IOCTL_DISK_GET_DRIVE_LAYOUT,
+ NULL, 0, layout_info,
+ Length);
+
+ if (!NT_SUCCESS(_last_status)) {
+ Destroy();
+ Message ? Message->Set(MSG_BAD_IOCTL) : 1;
+ Message ? Message->Display("") : 1;
+ return FALSE;
+ }
+
+ if (layout_info->PartitionCount < 4) {
+
+ _super_floppy = TRUE;
+ }
+ }
+
+ if (!IsTransient) {
+ NtClose(_handle);
+ _handle = 0;
+ }
+
+ return TRUE;
+}
+
+IFSUTIL_EXPORT
+BOOLEAN
+DP_DRIVE::Initialize(
+ IN PCWSTRING NtDriveName,
+ IN PCWSTRING HostFileName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN IsTransient,
+ IN BOOLEAN ExclusiveWrite
+ )
+/*++
+
+Routine Description:
+
+ This method initializes a hosted drive, i.e. a volume which
+ is implemented as a file on another volume. Instead of opening
+ this file by its actual name, we open it by the host file name,
+ to prevent interactions with the file system.
+
+Arguments:
+
+ NtDriveName - Supplies the NT name of the drive itself.
+ HostFileName - Supplies the fully qualified name of the file
+ which contains this drive.
+ Message - Supplies an outlet for messages.
+ IsTransient - Supplies whether or not to keep the handle to the
+ drive open beyond this method.
+ ExclusiveWrite - Supplies whether or not to open the drive for
+ exclusive write.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ FILE_STANDARD_INFORMATION FileStandardInfo;
+ IO_STATUS_BLOCK StatusBlock;
+ BIG_INT Sectors, FileSize;
+ ULONG AlignmentMask, ExtraUlong;
+
+
+ Destroy();
+
+ if( !DRIVE::Initialize(HostFileName, Message)) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ _hosted_drive = TRUE;
+
+ // First, make the host file not-readonly.
+ //
+ if( !IFS_SYSTEM::FileSetAttributes( HostFileName,
+ FILE_ATTRIBUTE_NORMAL,
+ &_old_attributes ) ) {
+
+ Message ? Message->Set( MSG_CANT_DASD ) : 1;
+ Message ? Message->Display( "" ) : 1;
+ Destroy();
+ return FALSE;
+ }
+
+ _last_status = OpenDrive( HostFileName,
+ SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA |
+ FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
+ ExclusiveWrite,
+ &_handle,
+ &_alignment_mask,
+ Message );
+
+ if( !NT_SUCCESS( _last_status ) ) {
+
+ IFS_SYSTEM::FileSetAttributes( HostFileName,
+ _old_attributes,
+ &ExtraUlong );
+
+ Destroy();
+ return FALSE;
+ }
+
+ if( NtDriveName ) {
+
+ _last_status = OpenDrive( NtDriveName,
+ SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
+ ExclusiveWrite,
+ &_alternate_handle,
+ &AlignmentMask,
+ Message );
+ }
+
+ // Fill in the drive type information. Everything except the
+ // Sectors field is fixed by default. The number of Sectors
+ // on the drive is determined from the host file's size.
+ //
+ _actual.MediaType = HostedDriveMediaType;
+ _actual.SectorSize = HostedDriveSectorSize;
+ _actual.HiddenSectors = HostedDriveHiddenSectors;
+ _actual.SectorsPerTrack = HostedDriveSectorsPerTrack;
+ _actual.Heads = HostedDriveHeads;
+
+ _last_status = NtQueryInformationFile( _handle,
+ &StatusBlock,
+ &FileStandardInfo,
+ sizeof( FileStandardInfo ),
+ FileStandardInformation );
+
+ if( !NT_SUCCESS( _last_status ) ) {
+
+ Destroy();
+ Message ? Message->Set( MSG_DISK_TOO_LARGE_TO_FORMAT ) : 1;
+ Message ? Message->Display ( "" ) : 1;
+ return FALSE;
+ }
+
+ FileSize = FileStandardInfo.EndOfFile;
+ Sectors = FileSize / _actual.SectorSize;
+
+ if( Sectors.GetHighPart() != 0 ) {
+
+ Destroy();
+ Message ? Message->Set( MSG_BAD_IOCTL ) : 1;
+ Message ? Message->Display ( "" ) : 1;
+ return FALSE;
+ }
+
+ _actual.Sectors = Sectors.GetLargeInteger();
+
+
+ // This drive has only one supported drive type
+ //
+ _num_supported = 1;
+
+ if (!(_supported_list = NEW DRTYPE)) {
+ Destroy();
+ Message ? Message->Set(MSG_FMT_NO_MEMORY) : 1;
+ Message ? Message->Display("") : 1;
+ return FALSE;
+ }
+
+ _supported_list[0] = _actual;
+
+ // If this was a transient open, clean it up.
+ //
+ if (!IsTransient) {
+
+ IFS_SYSTEM::FileSetAttributes( _handle, _old_attributes, &ExtraUlong );
+ NtClose(_handle);
+ _alternate_handle ? NtClose(_alternate_handle) : 1;
+ _handle = 0;
+ _alternate_handle = 0;
+ }
+
+ return TRUE;
+}
+
+
+IFSUTIL_EXPORT
+ULONG
+DP_DRIVE::QuerySectorSize(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of bytes per sector.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of bytes per sector.
+
+--*/
+{
+ return _actual.SectorSize;
+}
+
+
+IFSUTIL_EXPORT
+BIG_INT
+DP_DRIVE::QuerySectors(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number sectors on the disk. This does not
+ include the hidden sectors.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of sectors on the disk.
+
+--*/
+{
+ return _actual.Sectors;
+}
+
+
+IFSUTIL_EXPORT
+UCHAR
+DP_DRIVE::QueryMediaByte(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the media byte used by the FAT and HPFS file
+ systems to represent the current media type.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The media byte for the drive.
+
+--*/
+{
+ switch (_actual.MediaType) {
+ case F5_1Pt2_512: // 5.25", 1.2MB, 512 bytes/sector
+ return 0xF9;
+
+ case F3_1Pt44_512: // 3.5", 1.44MB, 512 bytes/sector
+ return 0xF0;
+
+ case F3_2Pt88_512: // 3.5", 2.88MB, 512 bytes/sector
+ return 0xF0;
+
+ case F3_120M_512: // 3.5", 120MB, 512 bytes/sector
+ return 0xF0;
+
+ case F3_20Pt8_512: // 3.5", 20.8MB, 512 bytes/sector
+ return 0xF9;
+
+ case F3_720_512: // 3.5", 720KB, 512 bytes/sector
+ return 0xF9;
+
+ case F5_360_512: // 5.25", 360KB, 512 bytes/sector
+ return 0xFD;
+
+ case F5_320_512: // 5.25", 320KB, 512 bytes/sector
+ return 0xFF;
+
+ case F5_180_512: // 5.25", 180KB, 512 bytes/sector
+ return 0xFC;
+
+ case F5_160_512: // 5.25", 160KB, 512 bytes/sector
+ return 0xFE;
+
+ case RemovableMedia:// Removable media other than floppy
+ return 0xF8; // There is no better choice than this.
+
+ case FixedMedia: // Fixed hard disk media
+ return 0xF8;
+
+ case F5_320_1024:
+ case Unknown:
+ break;
+
+ }
+
+ return 0;
+}
+
+
+VOID
+DP_DRIVE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a DP_DRIVE to its initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG ExtraUlong;
+
+ memset(&_actual, 0, sizeof(DRTYPE));
+ DELETE(_supported_list);
+ _num_supported = 0;
+ _alignment_mask = 0;
+
+ if (_hosted_drive) {
+
+ IFS_SYSTEM::FileSetAttributes( _handle, _old_attributes, &ExtraUlong );
+ }
+
+ if (_alternate_handle) {
+
+ NtClose(_alternate_handle);
+ _alternate_handle = 0;
+ }
+
+ if (_handle) {
+
+ NtClose(_handle);
+ _handle = 0;
+ }
+
+ _hosted_drive = FALSE;
+}
+
+
+BOOLEAN
+DP_DRIVE::IsSupported(
+ IN MEDIA_TYPE MediaType
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes whether or not the supplied media type is supported
+ by the drive.
+
+Arguments:
+
+ MediaType - Supplies the media type.
+
+Return Value:
+
+ FALSE - The media type is not supported by the drive.
+ TRUE - The media type is supported by the drive.
+
+--*/
+{
+ INT i;
+
+ for (i = 0; i < _num_supported; i++) {
+ if (MediaType == _supported_list[i].MediaType) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+IFSUTIL_EXPORT
+MEDIA_TYPE
+DP_DRIVE::QueryRecommendedMediaType(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the recommended media type for
+ drive. This media type is independant of any existing
+ media type for the drive. It is solely based on the
+ list of recommended media types for the drive.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The recommended media type for the drive.
+
+--*/
+{
+ INT i;
+ MEDIA_TYPE media_type;
+ SECTORCOUNT sectors;
+
+ media_type = Unknown;
+ sectors = 0;
+ for (i = 0; i < _num_supported; i++) {
+
+ // Special case 1.44. If a drive supports it then
+ // that should be the recommended media type.
+
+ if (_supported_list[i].MediaType == F3_1Pt44_512) {
+ media_type = _supported_list[i].MediaType;
+ break;
+ }
+
+ if (_supported_list[i].Sectors > sectors) {
+ media_type = _supported_list[i].MediaType;
+ }
+ }
+
+ return media_type;
+}
+
+#if defined ( DBLSPACE_ENABLED )
+BOOLEAN
+DP_DRIVE::QueryMountedFileSystemName(
+ OUT PWSTRING FileSystemName,
+ OUT PBOOLEAN IsCompressed
+ )
+/*++
+
+Routine Description:
+
+ This method returns the name of the file system
+ which has mounted this volume.
+
+Arguments:
+
+ FileSystemName - Receives the name of the file system
+ which has mounted this volume.
+ IsCompressed - Receives TRUE if the volume is compressed,
+ FALSE if it's not compressed or if the
+ method fails.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ CONST buffer_length = 64;
+ BYTE buffer[buffer_length];
+ PFILE_FS_ATTRIBUTE_INFORMATION fs_info;
+ IO_STATUS_BLOCK status_block;
+ NTSTATUS status;
+
+ DebugPtrAssert( FileSystemName );
+ DebugPtrAssert( IsCompressed );
+
+ *IsCompressed = FALSE;
+
+ fs_info = (PFILE_FS_ATTRIBUTE_INFORMATION) buffer;
+
+ status = NtQueryVolumeInformationFile( (_alternate_handle != 0) ?
+ _alternate_handle : _handle,
+ &status_block,
+ fs_info,
+ buffer_length,
+ FileFsAttributeInformation );
+
+ if( !NT_SUCCESS( status ) || fs_info->FileSystemNameLength == 0 ) {
+
+ return FALSE;
+ }
+
+ *IsCompressed =
+ (fs_info->FileSystemAttributes & FILE_VOLUME_IS_COMPRESSED) ?
+ TRUE : FALSE;
+
+ return( FileSystemName->Initialize( fs_info->FileSystemName,
+ fs_info->FileSystemNameLength ) );
+}
+
+BOOLEAN
+DP_DRIVE::MountCvf(
+ IN PCWSTRING CvfName,
+ IN PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This method mounts a file on the drive as a Double Space volume.
+
+Arguments:
+
+ CvfName -- Supplies the name of the Compressed Volume File.
+ Message -- Supplies an outlet for messages.
+
+Return Value:
+
+ TRUE upon successful completion
+
+--*/
+{
+ CONST MountBufferSize = 64;
+ IO_STATUS_BLOCK status_block;
+ BYTE MountBuffer[MountBufferSize];
+ PFILE_MOUNT_DBLS_BUFFER MountInfo;
+
+ MountInfo = (PFILE_MOUNT_DBLS_BUFFER)MountBuffer;
+
+ if( _hosted_drive ||
+ !CvfName->QueryWSTR( 0,
+ TO_END,
+ MountInfo->CvfName,
+ MountBufferSize - sizeof(ULONG),
+ TRUE ) ) {
+
+ Message->Set( MSG_DBLSPACE_CANT_MOUNT );
+ Message->Display( "%W", CvfName );
+ return FALSE;
+ }
+
+ MountInfo->CvfNameLength = CvfName->QueryChCount() * sizeof(WCHAR);
+
+ _last_status = NtFsControlFile( _handle,
+ 0, NULL, NULL,
+ &status_block,
+ FSCTL_MOUNT_DBLS_VOLUME,
+ MountBuffer,
+ sizeof( MountBuffer ),
+ NULL, 0 );
+
+ if( !NT_SUCCESS( _last_status ) ) {
+
+ Message->Set( MSG_DBLSPACE_CANT_MOUNT );
+ Message->Display( "%W", CvfName );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+DP_DRIVE::SetCvfSize(
+ IN ULONG Size
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the size of the cvf. Used to grow or
+ shrink the cvf while converted filesystems from or to
+ dblspace. The caller is responsible for placing the
+ proper signature at the end of the last sector in the cvf.
+
+Arguments:
+
+ Size - desired size, in bytes, of the entire cvf.
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure.
+
+--*/
+{
+ IO_STATUS_BLOCK status_block;
+ FILE_ALLOCATION_INFORMATION allocation;
+
+ allocation.AllocationSize.HighPart = 0;
+ allocation.AllocationSize.LowPart = Size;
+
+ _last_status = NtSetInformationFile(_handle,
+ &status_block,
+ &allocation,
+ sizeof(allocation),
+ FileAllocationInformation
+ );
+ if (!NT_SUCCESS(_last_status)) {
+ return FALSE;
+ }
+
+ DebugAssert(Size % _actual.SectorSize == 0);
+
+ _actual.Sectors = Size / _actual.SectorSize;
+
+ return TRUE;
+}
+#endif // DBLSPACE_ENABLED
+
+BOOLEAN
+DP_DRIVE::SetMediaType(
+ IN MEDIA_TYPE MediaType
+ )
+/*++
+
+Routine Description:
+
+ This routine alters the media type of the drive. If 'MediaType' is
+ 'Unknown' and the current media type for the drive is also 'Unknown'
+ then this routine selects the highest density supported by the
+ driver. If the current media type is known then this function
+ will have no effect if 'MediaType' is 'Unknown'.
+
+Arguments:
+
+ MediaType - Supplies the new media type for the drive.
+
+Return Value:
+
+ FALSE - The proposed media type is not supported by the drive.
+ TRUE - Success.
+
+--*/
+{
+ INT i;
+
+ if (MediaType == Unknown) {
+ if (_actual.MediaType != Unknown) {
+ return TRUE;
+ } else if (!_num_supported) {
+ return FALSE;
+ }
+
+ for (i = 0; i < _num_supported; i++) {
+ if (_supported_list[i].Sectors > QuerySectors()) {
+ _actual = _supported_list[i];
+ }
+ }
+
+ return TRUE;
+ }
+
+ for (i = 0; i < _num_supported; i++) {
+ if (_supported_list[i].MediaType == MediaType) {
+ _actual = _supported_list[i];
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+VOID
+DP_DRIVE::DiskGeometryToDriveType(
+ IN PCDISK_GEOMETRY DiskGeometry,
+ OUT PDRTYPE DriveType
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the drive type given the disk geometry.
+
+Arguments:
+
+ DiskGeometry - Supplies the disk geometry for the drive.
+ DriveType - Returns the drive type for the drive.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ DriveType->MediaType = DiskGeometry->MediaType;
+ DriveType->SectorSize = DiskGeometry->BytesPerSector;
+ DriveType->Sectors = DiskGeometry->Cylinders*
+ DiskGeometry->TracksPerCylinder*
+ DiskGeometry->SectorsPerTrack;
+ DriveType->HiddenSectors = 0;
+ DriveType->SectorsPerTrack = DiskGeometry->SectorsPerTrack;
+ DriveType->Heads = DiskGeometry->TracksPerCylinder;
+}
+
+
+VOID
+DP_DRIVE::DiskGeometryToDriveType(
+ IN PCDISK_GEOMETRY DiskGeometry,
+ IN BIG_INT NumSectors,
+ IN BIG_INT NumHiddenSectors,
+ OUT PDRTYPE DriveType
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the drive type given the disk geometry.
+
+Arguments:
+
+ DiskGeometry - Supplies the disk geometry for the drive.
+ NumSectors - Supplies the total number of non-hidden sectors on
+ the disk.
+ NumHiddenSectors - Supplies the number of hidden sectors on the disk.
+ DriveType - Returns the drive type for the drive.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ DriveType->MediaType = DiskGeometry->MediaType;
+ DriveType->SectorSize = DiskGeometry->BytesPerSector;
+ DriveType->Sectors = NumSectors;
+ DriveType->HiddenSectors = NumHiddenSectors;
+ DriveType->SectorsPerTrack = DiskGeometry->SectorsPerTrack;
+ DriveType->Heads = DiskGeometry->TracksPerCylinder;
+}
+
+
+DEFINE_CONSTRUCTOR( IO_DP_DRIVE, DP_DRIVE );
+
+VOID
+IO_DP_DRIVE::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Constructor for IO_DP_DRIVE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _is_locked = FALSE;
+ _is_exclusive_write = FALSE;
+ _cache = NULL;
+}
+
+
+VOID
+IO_DP_DRIVE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns an IO_DP_DRIVE object to its initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DELETE(_cache);
+
+ if (_is_exclusive_write) {
+ Dismount();
+ _is_exclusive_write = FALSE;
+ }
+
+ if (_is_locked) {
+ Unlock();
+ _is_locked = FALSE;
+ }
+}
+
+
+IO_DP_DRIVE::~IO_DP_DRIVE(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for IO_DP_DRIVE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+BOOLEAN
+IO_DP_DRIVE::Initialize(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN ExclusiveWrite
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes an IO_DP_DRIVE object.
+
+Arguments:
+
+ NtDriveName - Supplies the drive path.
+ Message - Supplies an outlet for messages.
+ ExclusiveWrite - Supplies whether or not to open the drive for
+ exclusive write.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ Destroy();
+
+ if (!DP_DRIVE::Initialize(NtDriveName, Message, TRUE, ExclusiveWrite)) {
+ Destroy();
+ return FALSE;
+ }
+
+ _is_exclusive_write = ExclusiveWrite;
+
+ if (!(_cache = NEW DRIVE_CACHE) ||
+ !_cache->Initialize(this)) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+IO_DP_DRIVE::Initialize(
+ IN PCWSTRING NtDriveName,
+ IN PCWSTRING HostFileName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN ExclusiveWrite
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes an IO_DP_DRIVE object for a hosted
+ drive, i.e. one which is implemented as a file on another
+ volume.
+
+Arguments:
+
+ NtDriveName - Supplies the drive path.
+ HostFileName - Supplies the fully qualified name of the host file.
+ Message - Supplies an outlet for messages.
+ ExclusiveWrite - Supplies whether or not to open the drive for
+ exclusive write.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ Destroy();
+
+ if( !DP_DRIVE::Initialize(NtDriveName,
+ HostFileName,
+ Message,
+ TRUE,
+ ExclusiveWrite)) {
+ Destroy();
+ return FALSE;
+ }
+
+ _is_exclusive_write = ExclusiveWrite;
+
+ if (!(_cache = NEW DRIVE_CACHE) ||
+ !_cache->Initialize(this)) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+IFSUTIL_EXPORT
+BOOLEAN
+IO_DP_DRIVE::Read(
+ IN BIG_INT StartingSector,
+ IN SECTORCOUNT NumberOfSectors,
+ OUT PVOID Buffer
+ )
+/*++
+
+Routine Description:
+
+ This routine reads a run of sectors into the buffer pointed to by
+ 'Buffer'.
+
+Arguments:
+
+ StartingSector - Supplies the first sector to be read.
+ NumberOfSectors - Supplies the number of sectors to be read.
+ Buffer - Supplies a buffer to read the run of sectors into.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ DebugAssert(_cache);
+ return _cache->Read(StartingSector, NumberOfSectors, Buffer);
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+IO_DP_DRIVE::Write(
+ BIG_INT StartingSector,
+ SECTORCOUNT NumberOfSectors,
+ PVOID Buffer
+ )
+/*++
+
+Routine Description:
+
+ This routine writes a run of sectors onto the disk from the buffer pointed
+ to by 'Buffer'. Writing is only permitted if 'Lock' was called.
+
+Arguments:
+
+ StartingSector - Supplies the first sector to be written.
+ NumberOfSectors - Supplies the number of sectors to be written.
+ Buffer - Supplies the buffer to write the run of sectors from.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ DebugAssert(_cache);
+ return _cache->Write(StartingSector, NumberOfSectors, Buffer);
+}
+
+
+IFSUTIL_EXPORT
+VOID
+IO_DP_DRIVE::SetCache(
+ IN OUT PDRIVE_CACHE Cache
+ )
+/*++
+
+Routine Description:
+
+ This routine relaces the current cache with the one supplied.
+ The object then takes ownership of this cache and it will be
+ deleted by the object.
+
+Arguments:
+
+ Cache - Supplies the new cache to install.
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure.
+
+--*/
+{
+ DebugAssert(Cache);
+ DELETE(_cache);
+ _cache = Cache;
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+IO_DP_DRIVE::FlushCache(
+ )
+/*++
+
+Routine Description:
+
+ This routine flushes the cache and report returns whether any
+ IO error occurred during the life of the cache.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Some IO errors have occured during the life of the cache.
+ TRUE - Success.
+
+--*/
+{
+ DebugAssert(_cache);
+ return _cache->Flush();
+}
+
+
+BOOLEAN
+IO_DP_DRIVE::HardRead(
+ IN BIG_INT StartingSector,
+ IN SECTORCOUNT NumberOfSectors,
+ OUT PVOID Buffer
+ )
+/*++
+
+Routine Description:
+
+ This routine reads a run of sectors into the buffer pointed to by
+ 'Buffer'.
+
+Arguments:
+
+ StartingSector - Supplies the first sector to be read.
+ NumberOfSectors - Supplies the number of sectors to be read.
+ Buffer - Supplies a buffer to read the run of sectors into.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG sector_size;
+ ULONG buffer_size;
+ IO_STATUS_BLOCK status_block;
+ BIG_INT secptr;
+ BIG_INT endofrange;
+ SECTORCOUNT increment;
+ PCHAR bufptr;
+ BIG_INT byte_offset;
+ BIG_INT tmp;
+ LARGE_INTEGER l;
+
+ DebugAssert(!(((ULONG) Buffer) & QueryAlignmentMask()));
+
+ sector_size = QuerySectorSize();
+ endofrange = StartingSector + NumberOfSectors;
+ increment = MaxIoSize/sector_size;
+
+ bufptr = (PCHAR) Buffer;
+ for (secptr = StartingSector; secptr < endofrange; secptr += increment) {
+
+ byte_offset = secptr*sector_size;
+
+ if (secptr + increment > endofrange) {
+ tmp = endofrange - secptr;
+ DebugAssert(tmp.GetHighPart() == 0);
+ buffer_size = sector_size*tmp.GetLowPart();
+ } else {
+ buffer_size = sector_size*increment;
+ }
+
+ l = byte_offset.GetLargeInteger();
+
+ _last_status = NtReadFile(_handle, 0, NULL, NULL, &status_block,
+ bufptr, buffer_size, &l, NULL);
+
+ if (_last_status == STATUS_NO_MEMORY) {
+ increment /= 2;
+ secptr -= increment;
+ continue;
+ }
+
+ if (NT_ERROR(_last_status) || status_block.Information != buffer_size) {
+ return FALSE;
+ }
+
+ bufptr += buffer_size;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+IO_DP_DRIVE::HardWrite(
+ BIG_INT StartingSector,
+ SECTORCOUNT NumberOfSectors,
+ PVOID Buffer
+ )
+/*++
+
+Routine Description:
+
+ This routine writes a run of sectors onto the disk from the buffer pointed
+ to by 'Buffer'. Writing is only permitted if 'Lock' was called.
+
+ MJB: After writing each chunk, we read it back to make sure the write
+ really succeeded.
+
+Arguments:
+
+ StartingSector - Supplies the first sector to be written.
+ NumberOfSectors - Supplies the number of sectors to be written.
+ Buffer - Supplies the buffer to write the run of sectors from.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG sector_size;
+ ULONG buffer_size;
+ IO_STATUS_BLOCK status_block;
+ BIG_INT secptr;
+ BIG_INT endofrange;
+ SECTORCOUNT increment;
+ PCHAR bufptr;
+ PCHAR scratch_ptr;
+ BIG_INT byte_offset;
+ BIG_INT tmp;
+ LARGE_INTEGER l;
+
+ DebugAssert(!(((ULONG) Buffer) & QueryAlignmentMask()));
+
+ if (! ULONG((ScratchIoBuf)) & QueryAlignmentMask()) {
+ scratch_ptr = ScratchIoBuf;
+ } else {
+ scratch_ptr = (PCHAR)((ULONG) ((PCHAR)ScratchIoBuf +
+ QueryAlignmentMask()) & (~QueryAlignmentMask()));
+ }
+ DebugAssert(!(((ULONG) scratch_ptr) & QueryAlignmentMask()));
+
+ sector_size = QuerySectorSize();
+ endofrange = StartingSector + NumberOfSectors;
+ increment = MaxIoSize/sector_size;
+
+ bufptr = (PCHAR) Buffer;
+ for (secptr = StartingSector; secptr < endofrange; secptr += increment) {
+
+ byte_offset = secptr*sector_size;
+
+ if (secptr + increment > endofrange) {
+ tmp = endofrange - secptr;
+ DebugAssert(tmp.GetHighPart() == 0);
+ buffer_size = sector_size*tmp.GetLowPart();
+ } else {
+ buffer_size = sector_size*increment;
+ }
+
+ l = byte_offset.GetLargeInteger();
+
+ _last_status = NtWriteFile(_handle, 0, NULL, NULL, &status_block,
+ bufptr, buffer_size, &l, NULL);
+
+ if (_last_status == STATUS_NO_MEMORY) {
+ increment /= 2;
+ secptr -= increment;
+ continue;
+ }
+
+ if (NT_ERROR(_last_status) || status_block.Information != buffer_size) {
+
+ return FALSE;
+ }
+
+ DebugAssert(buffer_size <= MaxIoSize);
+
+ _last_status = NtReadFile(_handle, 0, NULL, NULL, &status_block,
+ scratch_ptr, buffer_size, &l, NULL);
+
+ if (NT_ERROR(_last_status) || status_block.Information != buffer_size) {
+ return FALSE;
+ }
+
+ if (0 != memcmp(scratch_ptr, bufptr, buffer_size)) {
+ return FALSE;
+ }
+
+ bufptr += buffer_size;
+ }
+
+ return TRUE;
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+IO_DP_DRIVE::Verify(
+ IN BIG_INT StartingSector,
+ IN BIG_INT NumberOfSectors
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies a run of sectors on the disk.
+
+Arguments:
+
+ StartingSector - Supplies the first sector of the run to verify.
+ NumberOfSectors - Supplies the number of sectors in the run to verify.
+
+Return Value:
+
+ FALSE - Some of the sectors in the run are bad.
+ TRUE - All of the sectors in the run are good.
+
+--*/
+{
+ VERIFY_INFORMATION verify_info;
+ IO_STATUS_BLOCK status_block;
+ BIG_INT starting_offset;
+ BIG_INT verify_size;
+
+ DebugAssert(QuerySectorSize());
+
+ if (IsFloppy() || !_is_exclusive_write) {
+ return VerifyWithRead(StartingSector, NumberOfSectors);
+ }
+
+ starting_offset = StartingSector*QuerySectorSize();
+ verify_size = NumberOfSectors*QuerySectorSize();
+
+ verify_info.StartingOffset = starting_offset.GetLargeInteger();
+
+ // Note: norbertk Verify IOCTL is destined to go to a BIG_INT length.
+ DebugAssert(verify_size.GetHighPart() == 0);
+ verify_info.Length = verify_size.GetLowPart();
+
+ _last_status = NtDeviceIoControlFile(_handle, 0, NULL, NULL,
+ &status_block, IOCTL_DISK_VERIFY,
+ &verify_info,
+ sizeof(VERIFY_INFORMATION),
+ NULL, 0);
+
+ return (BOOLEAN) NT_SUCCESS(_last_status);
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+IO_DP_DRIVE::Verify(
+ IN BIG_INT StartingSector,
+ IN BIG_INT NumberOfSectors,
+ IN OUT PNUMBER_SET BadSectors
+ )
+/*++
+
+Routine Description:
+
+ This routine computes which sectors in the given range are bad
+ and adds these bad sectors to the bad sectors list.
+
+Arguments:
+
+ StartingSector - Supplies the starting sector.
+ NumberOfSectors - Supplies the number of sectors.
+ BadSectors - Supplies the bad sectors list.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ CONST MaxSectorsInVerify = 512;
+
+ ULONG MaxDiskHits;
+ BIG_INT half;
+ PBIG_INT starts;
+ PBIG_INT run_lengths;
+ ULONG i, n;
+ BIG_INT num_sectors;
+
+ if (NumberOfSectors == 0) {
+ return TRUE;
+ }
+
+ // Allow 20 retries so that a single bad sector in this region
+ // will be found accurately.
+
+ MaxDiskHits = (20 + NumberOfSectors/MaxSectorsInVerify + 1).GetLowPart();
+
+ if (!(starts = NEW BIG_INT[MaxDiskHits]) ||
+ !(run_lengths = NEW BIG_INT[MaxDiskHits])) {
+
+ DELETE(starts);
+ DELETE(run_lengths);
+ return FALSE;
+ }
+
+ num_sectors = NumberOfSectors;
+ for (i = 0; num_sectors > 0; i++) {
+ starts[i] = StartingSector + i*MaxSectorsInVerify;
+ if (MaxSectorsInVerify > num_sectors) {
+ run_lengths[i] = num_sectors;
+ } else {
+ run_lengths[i] = MaxSectorsInVerify;
+ }
+ num_sectors -= run_lengths[i];
+ }
+
+ n = i;
+
+ for (i = 0; i < n; i++) {
+
+ if (!Verify(starts[i], run_lengths[i])) {
+
+ if (n + 2 > MaxDiskHits) {
+
+ if (!BadSectors->Add(starts[i], run_lengths[i])) {
+ DELETE(starts);
+ DELETE(run_lengths);
+ return FALSE;
+ }
+
+ } else {
+
+ if (run_lengths[i] == 1) {
+
+ if (!BadSectors->Add(starts[i])) {
+ DELETE(starts);
+ DELETE(run_lengths);
+ return FALSE;
+ }
+
+ } else {
+
+ half = run_lengths[i]/2;
+
+ starts[n] = starts[i];
+ run_lengths[n] = half;
+ starts[n + 1] = starts[i] + half;
+ run_lengths[n + 1] = run_lengths[i] - half;
+
+ n += 2;
+ }
+ }
+ }
+ }
+
+
+ DELETE(starts);
+ DELETE(run_lengths);
+
+ return TRUE;
+}
+
+
+BOOLEAN
+IO_DP_DRIVE::VerifyWithRead(
+ IN BIG_INT StartingSector,
+ IN BIG_INT NumberOfSectors
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies the usability of the given range of sectors
+ using read.
+
+Arguments:
+
+ StartingSector - Supplies the starting sector of the verify.
+ Number OfSectors - Supplies the number of sectors to verify.
+
+Return Value:
+
+ FALSE - At least one of the sectors in the given range was unreadable.
+ TRUE - All of the sectors in the given range are readable.
+
+--*/
+{
+ HMEM hmem;
+ ULONG grab;
+ BIG_INT i;
+
+ if (!hmem.Initialize() ||
+ !hmem.Acquire(MaxIoSize, QueryAlignmentMask())) {
+
+ return FALSE;
+ }
+
+ grab = MaxIoSize/QuerySectorSize();
+ for (i = 0; i < NumberOfSectors; i += grab) {
+
+ if (NumberOfSectors - i < grab) {
+ grab = (NumberOfSectors - i).GetLowPart();
+ }
+
+ if (!HardRead(StartingSector + i, grab, hmem.GetBuf())) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+IO_DP_DRIVE::Lock(
+ )
+/*++
+
+Routine Description:
+
+ This routine locks the drive. If the drive is already locked then
+ this routine will do nothing.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ IO_STATUS_BLOCK status_block;
+
+ if (_is_locked) {
+ return TRUE;
+ }
+
+ if (_hosted_drive && _alternate_handle == 0) {
+
+ // This is a hosted volume which is not mounted as
+ // a drive--locking succeeds.
+ //
+ _is_locked = TRUE;
+ _is_exclusive_write = TRUE;
+ return TRUE;
+ }
+
+ _last_status = NtFsControlFile( (_alternate_handle != 0) ?
+ _alternate_handle : _handle,
+ 0, NULL, NULL,
+ &status_block,
+ FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0);
+
+ _is_locked = (BOOLEAN) NT_SUCCESS(_last_status);
+
+ if (_is_locked) {
+ _is_exclusive_write = TRUE;
+ }
+
+ return _is_locked;
+}
+
+
+BOOLEAN
+IO_DP_DRIVE::ForceDirty(
+ )
+/*++
+
+Routine Description:
+
+ This routine forces the volume to be dirty, so that autochk will
+ run next time the system reboots.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ IO_STATUS_BLOCK status_block;
+
+ _last_status = NtFsControlFile((_alternate_handle != 0) ?
+ _alternate_handle : _handle,
+ 0, NULL, NULL,
+ &status_block,
+ FSCTL_MARK_VOLUME_DIRTY,
+ NULL, 0, NULL, 0);
+
+ return ((BOOLEAN) NT_SUCCESS(_last_status));
+}
+
+
+BOOLEAN
+IO_DP_DRIVE::Unlock(
+ )
+/*++
+
+Routine Description:
+
+ This routine unlocks the drive.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ IO_STATUS_BLOCK status_block;
+
+ if (_hosted_drive && _alternate_handle == 0 ) {
+
+ return TRUE;
+ }
+
+ return NT_SUCCESS(NtFsControlFile((_alternate_handle != 0) ?
+ _alternate_handle : _handle,
+ 0, NULL, NULL,
+ &status_block,
+ FSCTL_UNLOCK_VOLUME,
+ NULL, 0, NULL, 0));
+}
+
+
+BOOLEAN
+IO_DP_DRIVE::Dismount(
+ )
+/*++
+
+Routine Description:
+
+ This routine dismounts the drive.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ IO_STATUS_BLOCK status_block;
+
+ if( _hosted_drive && _alternate_handle == 0 ) {
+
+ return TRUE;
+ }
+
+ if( !NT_SUCCESS(NtFsControlFile((_alternate_handle != 0) ?
+ _alternate_handle : _handle,
+ 0, NULL, NULL,
+ &status_block,
+ FSCTL_DISMOUNT_VOLUME,
+ NULL, 0, NULL, 0)) ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+IO_DP_DRIVE::FormatVerifyFloppy(
+ IN MEDIA_TYPE MediaType,
+ IN OUT PNUMBER_SET BadSectors,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN IsDmfFormat
+ )
+/*++
+
+Routine Description:
+
+ This routine low level formats an entire floppy disk to the media
+ type specified. If no MediaType is specified then a logical one will
+ be selected.
+
+Arguments:
+
+ MediaType - Supplies an optional media type to format to.
+ BadSectors - Returns a list of bad sectors on the disk.
+ Message - Supplies a message object to route messages to.
+ IsDmfFormat - Supplies whether or not to perform a DMF type format.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ IO_STATUS_BLOCK status_block;
+ CONST format_parameters_size = sizeof(FORMAT_EX_PARAMETERS) + 20*sizeof(USHORT);
+ CHAR format_parameters_buffer[format_parameters_size];
+ PFORMAT_EX_PARAMETERS format_parameters;
+ PBAD_TRACK_NUMBER bad;
+ ULONG num_bad, j;
+ ULONG i;
+ ULONG cyl;
+ ULONG percent;
+ ULONG sec_per_track;
+ ULONG sec_per_cyl;
+ HMEM hmem;
+ MSGID MessageId;
+ USHORT swap_buffer[3];
+
+ // We don't make sure that the volume is locked here because
+ // it's not strictly necessary and 'diskcopy' will format
+ // floppies without locking them.
+
+ if (!SetMediaType(MediaType) ||
+ (IsDmfFormat && QueryMediaType() != F3_1Pt44_512)) {
+
+ Message ? Message->Set(MSG_NOT_SUPPORTED_BY_DRIVE) : 1;
+ Message ? Message->Display("") : 1;
+ return FALSE;
+ }
+
+ format_parameters = (PFORMAT_EX_PARAMETERS) format_parameters_buffer;
+ format_parameters->MediaType = QueryMediaType();
+ format_parameters->StartHeadNumber = 0;
+ format_parameters->EndHeadNumber = QueryHeads() - 1;
+
+ if (IsDmfFormat) {
+ sec_per_track = 21;
+ format_parameters->FormatGapLength = 8;
+ format_parameters->SectorsPerTrack = (USHORT) sec_per_track;
+ format_parameters->SectorNumber[0] = 12;
+ format_parameters->SectorNumber[1] = 2;
+ format_parameters->SectorNumber[2] = 13;
+ format_parameters->SectorNumber[3] = 3;
+ format_parameters->SectorNumber[4] = 14;
+ format_parameters->SectorNumber[5] = 4;
+ format_parameters->SectorNumber[6] = 15;
+ format_parameters->SectorNumber[7] = 5;
+ format_parameters->SectorNumber[8] = 16;
+ format_parameters->SectorNumber[9] = 6;
+ format_parameters->SectorNumber[10] = 17;
+ format_parameters->SectorNumber[11] = 7;
+ format_parameters->SectorNumber[12] = 18;
+ format_parameters->SectorNumber[13] = 8;
+ format_parameters->SectorNumber[14] = 19;
+ format_parameters->SectorNumber[15] = 9;
+ format_parameters->SectorNumber[16] = 20;
+ format_parameters->SectorNumber[17] = 10;
+ format_parameters->SectorNumber[18] = 21;
+ format_parameters->SectorNumber[19] = 11;
+ format_parameters->SectorNumber[20] = 1;
+ } else {
+ sec_per_track = QuerySectorsPerTrack();
+ }
+ sec_per_cyl = sec_per_track*QueryHeads();
+
+ DebugAssert(QueryCylinders().GetHighPart() == 0);
+ cyl = QueryCylinders().GetLowPart();
+ num_bad = QueryHeads();
+ if (num_bad == 0 || cyl == 0) {
+ return FALSE;
+ }
+
+ if (!(bad = NEW BAD_TRACK_NUMBER[num_bad])) {
+ Message ? Message->Set(MSG_FMT_NO_MEMORY) : 1;
+ Message ? Message->Display("") : 1;
+ return FALSE;
+ }
+
+ if (!hmem.Acquire(sec_per_cyl*QuerySectorSize(), QueryAlignmentMask())) {
+ Message ? Message->Set(MSG_FMT_NO_MEMORY) : 1;
+ Message ? Message->Display("") : 1;
+ return FALSE;
+ }
+
+
+ Message ? Message->Set(MSG_PERCENT_COMPLETE) : 1;
+ Message ? Message->Display("%d", 0) : 1;
+
+ percent = 0;
+ for (i = 0; i < cyl; i++) {
+
+ format_parameters->StartCylinderNumber = i;
+ format_parameters->EndCylinderNumber = i;
+
+ if (IsDmfFormat) {
+ _last_status = NtDeviceIoControlFile(_handle, 0, NULL, NULL,
+ &status_block,
+ IOCTL_DISK_FORMAT_TRACKS_EX,
+ format_parameters,
+ format_parameters_size,
+ bad, num_bad*
+ sizeof(BAD_TRACK_NUMBER));
+
+ // Skew the next cylinder by 3 sectors from this one.
+
+ RtlMoveMemory(swap_buffer,
+ &format_parameters->SectorNumber[18],
+ 3*sizeof(USHORT));
+ RtlMoveMemory(&format_parameters->SectorNumber[3],
+ &format_parameters->SectorNumber[0],
+ 18*sizeof(USHORT));
+ RtlMoveMemory(&format_parameters->SectorNumber[0],
+ swap_buffer,
+ 3*sizeof(USHORT));
+
+ } else {
+ _last_status = NtDeviceIoControlFile(_handle, 0, NULL, NULL,
+ &status_block,
+ IOCTL_DISK_FORMAT_TRACKS,
+ format_parameters,
+ sizeof(FORMAT_PARAMETERS),
+ bad, num_bad*
+ sizeof(BAD_TRACK_NUMBER));
+ }
+
+ if (!NT_SUCCESS(_last_status)) {
+ DELETE(bad);
+
+ switch( _last_status ) {
+
+ case STATUS_MEDIA_WRITE_PROTECTED:
+ MessageId = MSG_FMT_WRITE_PROTECTED_MEDIA ;
+ break;
+
+ case STATUS_DEVICE_BUSY:
+ case STATUS_DEVICE_NOT_READY:
+ MessageId = MSG_DEVICE_BUSY;
+ break;
+
+ default:
+ MessageId = MSG_BAD_IOCTL;
+ break;
+ }
+
+ Message ? Message->Set(MessageId) : 1;
+ Message ? Message->Display("") : 1;
+ return FALSE;
+ }
+
+
+ // Verify the sectors.
+
+ if (BadSectors) {
+
+ if (!Read(i*sec_per_cyl, sec_per_cyl, hmem.GetBuf())) {
+
+ // If this is the first track then crap out.
+ // A disk with a bad cylinder 0 is not
+ // worth continuing on.
+ //
+ // As of 7/29/94, formatting 2.88 floppies to 1.44
+ // doesn't work on Alphas; if we can't format to
+ // 1.44 and 2.88 is supported, try 2.88.
+ //
+ if (i == 0) {
+
+ if( !IsDmfFormat &&
+ QueryMediaType() == F3_1Pt44_512 &&
+ SetMediaType(F3_2Pt88_512) ) {
+
+ return( FormatVerifyFloppy( F3_2Pt88_512,
+ BadSectors,
+ Message,
+ IsDmfFormat ) );
+
+ } else {
+
+ Message ? Message->Set(MSG_UNUSABLE_DISK) : 1;
+ Message ? Message->Display() : 1;
+ return FALSE;
+ }
+ }
+
+ for (j = 0; j < sec_per_cyl; j++) {
+ if (!Read(i*sec_per_cyl + j, 1, hmem.GetBuf())) {
+ if (!BadSectors->Add(i*sec_per_cyl + j)) {
+ return FALSE;
+ }
+ }
+ }
+ }
+ }
+
+ if ((i + 1)*100/cyl > percent) {
+ percent = (i + 1)*100/cyl;
+ if (percent > 100) {
+ percent = 100;
+ }
+
+ // This check for success on the message object
+ // has to be there for FMIFS to implement CANCEL.
+
+ if (Message && !Message->Display("%d", percent)) {
+ DELETE(bad);
+ return FALSE;
+ }
+ }
+ }
+
+ DELETE(bad);
+
+ return TRUE;
+}
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( LOG_IO_DP_DRIVE, IO_DP_DRIVE, IFSUTIL_EXPORT );
+
+
+IFSUTIL_EXPORT
+LOG_IO_DP_DRIVE::~LOG_IO_DP_DRIVE(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for LOG_IO_DP_DRIVE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+LOG_IO_DP_DRIVE::Initialize(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN ExclusiveWrite
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes a LOG_IO_DP_DRIVE object.
+
+Arguments:
+
+ NtDriveName - Supplies the path of the drive object.
+ Message - Supplies an outlet for messages.
+ ExclusiveWrite - Supplies whether or not to open the drive for
+ exclusive write.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ return IO_DP_DRIVE::Initialize(NtDriveName, Message, ExclusiveWrite);
+}
+
+IFSUTIL_EXPORT
+BOOLEAN
+LOG_IO_DP_DRIVE::Initialize(
+ IN PCWSTRING NtDriveName,
+ IN PCWSTRING HostFileName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN ExclusiveWrite
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes a LOG_IO_DP_DRIVE object for a hosted
+ drive, i.e. one which is implemented as a file on another volume.
+
+
+Arguments:
+
+ NtDriveName - Supplies the path of the drive object.
+ HostFileName - Supplies the fully qualified name of the host file.
+ Message - Supplies an outlet for messages.
+ ExclusiveWrite - Supplies whether or not to open the drive for
+ exclusive write.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ return IO_DP_DRIVE::Initialize(NtDriveName,
+ HostFileName,
+ Message,
+ ExclusiveWrite);
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+LOG_IO_DP_DRIVE::SetSystemId(
+ IN PARTITION_SYSTEM_ID SystemId
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the system identifier (or partition type) in the
+ hidden sectors of a logical volume on a fixed disk.
+
+Arguments:
+
+ SystemId - Supplies the system id to write in the partition entry.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ IO_STATUS_BLOCK status_block;
+ SET_PARTITION_INFORMATION partition_info;
+
+ //
+ // This operation is unnecessary on floppies, super-floppies, and
+ // hosted volumes.
+ //
+
+ if (IsFloppy() || IsSuperFloppy() || _hosted_drive) {
+ return TRUE;
+ }
+
+ if( SystemId == SYSID_NONE ) {
+
+ // Note: billmc -- we should never set it to zero!
+
+ DebugPrint( "Skip setting the partition type to zero.\n" );
+ return TRUE;
+ }
+
+ partition_info.PartitionType = (UCHAR)SystemId;
+
+ _last_status = NtDeviceIoControlFile(_handle, 0, NULL, NULL,
+ &status_block,
+ IOCTL_DISK_SET_PARTITION_INFO,
+ &partition_info,
+ sizeof(SET_PARTITION_INFORMATION),
+ NULL, 0);
+
+ return NT_SUCCESS(_last_status) ||
+ _last_status == STATUS_INVALID_DEVICE_REQUEST;
+}
+
+
+DEFINE_CONSTRUCTOR( PHYS_IO_DP_DRIVE, IO_DP_DRIVE );
+
+PHYS_IO_DP_DRIVE::~PHYS_IO_DP_DRIVE(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for PHYS_IO_DP_DRIVE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+}
+
+
+BOOLEAN
+PHYS_IO_DP_DRIVE::Initialize(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN ExclusiveWrite
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes a PHYS_IO_DP_DRIVE object.
+
+Arguments:
+
+ NtDriveName - Supplies the path of the drive object.
+ Message - Supplies an outlet for messages.
+ ExclusiveWrite - Supplies whether or not to open the drive for
+ exclusive write.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ return IO_DP_DRIVE::Initialize(NtDriveName, Message, ExclusiveWrite);
+}
diff --git a/private/utils/ifsutil/src/ifssys.cxx b/private/utils/ifsutil/src/ifssys.cxx
new file mode 100644
index 000000000..bb24a458d
--- /dev/null
+++ b/private/utils/ifsutil/src/ifssys.cxx
@@ -0,0 +1,2178 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _IFSUTIL_MEMBER_
+
+#include "ulib.hxx"
+#include "ifsutil.hxx"
+
+#include "ifssys.hxx"
+#include "bigint.hxx"
+#include "wstring.hxx"
+#include "cannedsd.hxx"
+#include "drive.hxx"
+#include "secrun.hxx"
+#include "hmem.hxx"
+#include "bpb.hxx"
+#include "volume.hxx"
+
+
+BOOLEAN
+IFS_SYSTEM::IsThisFat(
+ IN BIG_INT Sectors,
+ IN PVOID BootSectorData
+ )
+/*++
+
+Routine Description:
+
+ This routine determines if the given boot sector is a FAT
+ boot sector.
+
+Arguments:
+
+ Sectors - Supplies the number of sectors on this drive.
+ BootSector - Supplies the boot sector data.
+
+Return Value:
+
+ FALSE - This is not a FAT boot sector.
+ TRUE - This is a FAT boot sector.
+
+--*/
+{
+ PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK BootSector =
+ (PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK)BootSectorData;
+ BOOLEAN r;
+ USHORT bytes_per_sector, reserved_sectors, root_entries, sectors;
+ USHORT sectors_per_fat;
+ ULONG large_sectors;
+
+ r = TRUE;
+
+ memcpy(&bytes_per_sector, BootSector->Bpb.BytesPerSector, sizeof(USHORT));
+ memcpy(&reserved_sectors, BootSector->Bpb.ReservedSectors, sizeof(USHORT));
+ memcpy(&root_entries, BootSector->Bpb.RootEntries, sizeof(USHORT));
+ memcpy(&sectors, BootSector->Bpb.Sectors, sizeof(USHORT));
+ memcpy(&large_sectors, BootSector->Bpb.LargeSectors, sizeof(ULONG));
+ memcpy(&sectors_per_fat, BootSector->Bpb.SectorsPerFat, sizeof(USHORT));
+
+
+ if (BootSector->IntelNearJumpCommand[0] != 0xeb &&
+ BootSector->IntelNearJumpCommand[0] != 0xe9) {
+
+ r = FALSE;
+
+ } else if ((bytes_per_sector != 128) &&
+ (bytes_per_sector != 256) &&
+ (bytes_per_sector != 512) &&
+ (bytes_per_sector != 1024) &&
+ (bytes_per_sector != 2048) &&
+ (bytes_per_sector != 4096)) {
+
+ r = FALSE;
+
+ } else if ((BootSector->Bpb.SectorsPerCluster[0] != 1) &&
+ (BootSector->Bpb.SectorsPerCluster[0] != 2) &&
+ (BootSector->Bpb.SectorsPerCluster[0] != 4) &&
+ (BootSector->Bpb.SectorsPerCluster[0] != 8) &&
+ (BootSector->Bpb.SectorsPerCluster[0] != 16) &&
+ (BootSector->Bpb.SectorsPerCluster[0] != 32) &&
+ (BootSector->Bpb.SectorsPerCluster[0] != 64) &&
+ (BootSector->Bpb.SectorsPerCluster[0] != 128)) {
+
+ r = FALSE;
+
+ } else if (reserved_sectors == 0) {
+
+ r = FALSE;
+
+ } else if (BootSector->Bpb.Fats[0] == 0) {
+
+ r = FALSE;
+
+ } else if (root_entries == 0) {
+
+ r = FALSE;
+
+ } else if (Sectors.GetHighPart() != 0) {
+
+ r = FALSE;
+
+ } else if (sectors != 0 && sectors > Sectors.GetLowPart()) {
+
+ r = FALSE;
+
+ } else if (sectors == 0 && large_sectors > Sectors.GetLowPart()) {
+
+ r = FALSE;
+
+ } else if (sectors == 0 && large_sectors == 0) {
+
+ r = FALSE;
+
+ } else if (sectors_per_fat == 0) {
+
+ r = FALSE;
+
+ }
+
+ return r;
+}
+
+
+BOOLEAN
+IFS_SYSTEM::IsThisHpfs(
+ IN BIG_INT Sectors,
+ IN PVOID BootSectorData,
+ IN PULONG SuperBlock,
+ IN PULONG SpareBlock
+ )
+/*++
+
+Routine Description:
+
+ This routine determines whether or not the given structures
+ are part of an HPFS file system.
+
+Arguments:
+
+ Sectors - Supplies the number of sectors on the volume.
+ BootSector - Supplies the unaligned boot sector.
+ SuperBlock - Supplies the super block.
+ SpareBlock - Supplies the spare block.
+
+Return Value:
+
+ FALSE - The given structures are not part on an HPFS volume.
+ TRUE - The given structures are part of an HPFS volume.
+
+--*/
+{
+ PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK BootSector =
+ (PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK)BootSectorData;
+ BOOLEAN r;
+ USHORT bytes_per_sector, sectors;
+ ULONG large_sectors;
+
+ r = TRUE;
+
+ memcpy(&bytes_per_sector, BootSector->Bpb.BytesPerSector, sizeof(USHORT));
+ memcpy(&sectors, BootSector->Bpb.Sectors, sizeof(USHORT));
+ memcpy(&large_sectors, BootSector->Bpb.LargeSectors, sizeof(ULONG));
+
+ if ((BootSector->IntelNearJumpCommand[0] != 0xeb &&
+ BootSector->IntelNearJumpCommand[0] != 0xe9) ||
+ bytes_per_sector != 512 ||
+ ((PUCHAR) BootSector)[510] != 0x55 ||
+ ((PUCHAR) BootSector)[511] != 0xaa ||
+ BootSector->Bpb.Fats[0] != 0 ||
+ (sectors == 0 && large_sectors == 0) ||
+ (sectors != 0 && large_sectors != 0) ||
+ (sectors > Sectors.GetLowPart()) ||
+ (large_sectors > Sectors.GetLowPart()) ||
+ Sectors.GetHighPart() != 0) {
+
+ r = FALSE;
+
+ } else if (SuperBlock[0] != 0xF995E849 ||
+ SuperBlock[1] != 0xFA53E9C5 ||
+ SpareBlock[0] != 0xf9911849 ||
+ SpareBlock[1] != 0xfa5229c5) {
+
+ r = FALSE;
+
+ }
+
+ return r;
+}
+
+#if !defined _AUTOCHK_ && !defined _AUTOCONV_
+
+typedef struct _PACKED_BOOT_SECTOR {
+ UCHAR Jump[3]; // offset = 0x000
+ UCHAR Oem[8]; // offset = 0x003
+ PACKED_BIOS_PARAMETER_BLOCK PackedBpb; // offset = 0x00B
+ UCHAR Unused[4]; // offset = 0x024
+ LARGE_INTEGER NumberSectors; // offset = 0x028
+ LARGE_INTEGER MftStartLcn; // offset = 0x030
+ LARGE_INTEGER Mft2StartLcn; // offset = 0x038
+ CHAR ClustersPerFileRecordSegment; // offset = 0x040
+ UCHAR Unused1[3]; // offset = 0x041
+ CHAR DefaultClustersPerIndexAllocationBuffer; // offset = 0x044
+ UCHAR Unused2[3]; // offset = 0x047
+ LARGE_INTEGER SerialNumber; // offset = 0x048
+ ULONG Checksum; // offset = 0x050
+ UCHAR BootStrap[0x200-0x054]; // offset = 0x054
+} PACKED_BOOT_SECTOR; // sizeof = 0x200
+typedef PACKED_BOOT_SECTOR *PPACKED_BOOT_SECTOR;
+
+#endif // _AUTOCHK_ && _AUTOCONV_
+
+IFSUTIL_EXPORT
+BOOLEAN
+IFS_SYSTEM::IsThisNtfs(
+ IN BIG_INT Sectors,
+ IN ULONG SectorSize,
+ IN PVOID BootSectorData
+ )
+/*++
+
+Routine Description:
+
+ This routine determines whether or not the given structure
+ is part of an NTFS partition.
+
+Arguments:
+
+ Sectors - Supplies the number of sectors on the drive.
+ SectorSize - Supplies the number of bytes per sector.
+ BootSector - Supplies an unaligned boot sector.
+
+Return Value:
+
+ FALSE - The supplied boot sector is not part of an NTFS
+ TRUE - The supplied boot sector is part of an NTFS volume.
+
+--*/
+{
+ PPACKED_BOOT_SECTOR BootSector = (PPACKED_BOOT_SECTOR)BootSectorData;
+ BOOLEAN r;
+ ULONG checksum;
+ PULONG l;
+ USHORT reserved_sectors, root_entries, sectors, sectors_per_fat;
+ USHORT bytes_per_sector;
+ ULONG large_sectors;
+
+ memcpy(&reserved_sectors, BootSector->PackedBpb.ReservedSectors, sizeof(USHORT));
+ memcpy(&root_entries, BootSector->PackedBpb.RootEntries, sizeof(USHORT));
+ memcpy(&sectors, BootSector->PackedBpb.Sectors, sizeof(USHORT));
+ memcpy(&sectors_per_fat, BootSector->PackedBpb.SectorsPerFat, sizeof(USHORT));
+ memcpy(&bytes_per_sector, BootSector->PackedBpb.BytesPerSector, sizeof(USHORT));
+ memcpy(&large_sectors, BootSector->PackedBpb.LargeSectors, sizeof(ULONG));
+
+
+ r = TRUE;
+
+ checksum = 0;
+ for (l = (PULONG) BootSector; l < (PULONG) &BootSector->Checksum; l++) {
+ checksum += *l;
+ }
+
+ if (BootSector->Oem[0] != 'N' ||
+ BootSector->Oem[1] != 'T' ||
+ BootSector->Oem[2] != 'F' ||
+ BootSector->Oem[3] != 'S' ||
+ BootSector->Oem[4] != ' ' ||
+ BootSector->Oem[5] != ' ' ||
+ BootSector->Oem[6] != ' ' ||
+ BootSector->Oem[7] != ' ' ||
+ // BootSector->Checksum != checksum ||
+ bytes_per_sector != SectorSize) {
+
+ r = FALSE;
+
+ } else if ((BootSector->PackedBpb.SectorsPerCluster[0] != 0x1) &&
+ (BootSector->PackedBpb.SectorsPerCluster[0] != 0x2) &&
+ (BootSector->PackedBpb.SectorsPerCluster[0] != 0x4) &&
+ (BootSector->PackedBpb.SectorsPerCluster[0] != 0x8) &&
+ (BootSector->PackedBpb.SectorsPerCluster[0] != 0x10) &&
+ (BootSector->PackedBpb.SectorsPerCluster[0] != 0x20) &&
+ (BootSector->PackedBpb.SectorsPerCluster[0] != 0x40) &&
+ (BootSector->PackedBpb.SectorsPerCluster[0] != 0x80)) {
+
+ r = FALSE;
+
+ } else if (reserved_sectors != 0 ||
+ BootSector->PackedBpb.Fats[0] != 0 ||
+ root_entries != 0 ||
+ sectors != 0 ||
+ sectors_per_fat != 0 ||
+ large_sectors != 0 ||
+ BootSector->NumberSectors > Sectors ||
+ BootSector->MftStartLcn >= Sectors ||
+ BootSector->Mft2StartLcn >= Sectors) {
+
+ r = FALSE;
+ }
+
+ if (!r) {
+ return r;
+ }
+
+ if (BootSector->ClustersPerFileRecordSegment < 0) {
+
+ LONG temp = LONG(BootSector->ClustersPerFileRecordSegment);
+
+ temp = 2 << -temp;
+
+ if (temp < 512) {
+ return FALSE;
+ }
+ } else if ((BootSector->ClustersPerFileRecordSegment != 0x1) &&
+ (BootSector->ClustersPerFileRecordSegment != 0x2) &&
+ (BootSector->ClustersPerFileRecordSegment != 0x4) &&
+ (BootSector->ClustersPerFileRecordSegment != 0x8) &&
+ (BootSector->ClustersPerFileRecordSegment != 0x10) &&
+ (BootSector->ClustersPerFileRecordSegment != 0x20) &&
+ (BootSector->ClustersPerFileRecordSegment != 0x40) &&
+ (BootSector->ClustersPerFileRecordSegment != 0x80)) {
+
+ return FALSE;
+ }
+
+ if (BootSector->DefaultClustersPerIndexAllocationBuffer < 0) {
+
+ LONG temp = LONG(BootSector->DefaultClustersPerIndexAllocationBuffer);
+
+ temp = 2 << -temp;
+
+ if (temp < 512) {
+ return FALSE;
+ }
+ } else if ((BootSector->DefaultClustersPerIndexAllocationBuffer != 0x1) &&
+ (BootSector->DefaultClustersPerIndexAllocationBuffer != 0x2) &&
+ (BootSector->DefaultClustersPerIndexAllocationBuffer != 0x4) &&
+ (BootSector->DefaultClustersPerIndexAllocationBuffer != 0x8) &&
+ (BootSector->DefaultClustersPerIndexAllocationBuffer != 0x10) &&
+ (BootSector->DefaultClustersPerIndexAllocationBuffer != 0x20) &&
+ (BootSector->DefaultClustersPerIndexAllocationBuffer != 0x40) &&
+ (BootSector->DefaultClustersPerIndexAllocationBuffer != 0x80)) {
+
+ r = FALSE;
+ }
+
+ return r;
+}
+
+#define BOOTBLKSECTORS 4
+typedef int DSKPACKEDBOOTSECT;
+
+BOOLEAN
+IsThisOfs(
+ IN LOG_IO_DP_DRIVE * Drive,
+ IN DSKPACKEDBOOTSECT * PackedBootSect
+ )
+{
+ return(FALSE);
+}
+
+#if !defined( _SETUP_LOADER_ )
+
+IFSUTIL_EXPORT
+BOOLEAN
+IFS_SYSTEM::QueryFileSystemName(
+ IN PCWSTRING NtDriveName,
+ OUT PWSTRING FileSystemName,
+ OUT PNTSTATUS ErrorCode
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the file system name for the drive specified.
+
+Arguments:
+
+ NtDriveName - Supplies an NT style drive name.
+ FileSystemName - Returns the file system name for the drive.
+ ErrorCode - Receives an error code (if the method fails).
+ Note that this may be NULL, in which case the
+ exact error is not reported.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ LOG_IO_DP_DRIVE drive;
+ HMEM bootsec_hmem;
+ SECRUN bootsec;
+ HMEM super_hmem;
+ SECRUN super;
+ HMEM spare_hmem;
+ SECRUN spare;
+ BOOLEAN could_be_fat;
+ BOOLEAN could_be_hpfs;
+ BOOLEAN could_be_ntfs;
+ BOOLEAN could_be_ofs;
+ ULONG num_boot_sectors;
+ BOOLEAN first_read_failed = FALSE;
+
+ if (ErrorCode) {
+ *ErrorCode = 0;
+ }
+
+ if (!drive.Initialize(NtDriveName)) {
+ if (ErrorCode) {
+ *ErrorCode = drive.QueryLastNtStatus();
+ }
+ return FALSE;
+ }
+
+ could_be_fat = could_be_hpfs = could_be_ntfs = could_be_ofs = TRUE;
+
+
+ if (drive.QueryMediaType() == Unknown) {
+ return FileSystemName->Initialize("RAW");
+ }
+
+ num_boot_sectors = max(1, BYTES_PER_BOOT_SECTOR/drive.QuerySectorSize());
+
+ if (!bootsec_hmem.Initialize() ||
+ !bootsec.Initialize(&bootsec_hmem, &drive, 0, num_boot_sectors)) {
+
+ return FileSystemName->Initialize("RAW");
+ }
+
+ if (!bootsec.Read()) {
+
+ could_be_fat = could_be_hpfs = FALSE;
+ first_read_failed = TRUE;
+
+ bootsec.Relocate(drive.QuerySectors());
+
+ if (!bootsec.Read()) {
+
+ bootsec.Relocate(drive.QuerySectors()/2);
+
+ if (!bootsec.Read()) {
+
+ could_be_ntfs = FALSE;
+ }
+ }
+ }
+
+ if (could_be_ntfs &&
+ IsThisNtfs(drive.QuerySectors(),
+ drive.QuerySectorSize(),
+ (PPACKED_BOOT_SECTOR) bootsec.GetBuf())) {
+
+ return FileSystemName->Initialize("NTFS");
+ }
+
+ if (first_read_failed) {
+
+ bootsec.Relocate(BOOTBLKSECTORS);
+
+ if (!bootsec.Read()) {
+ could_be_ofs = FALSE;
+ }
+ }
+
+ // Check if it is ofs
+
+ if (could_be_ofs &&
+ IsThisOfs(&drive, (DSKPACKEDBOOTSECT *) bootsec.GetBuf())) {
+
+ return FileSystemName->Initialize("OFS");
+ }
+
+ if (could_be_hpfs) {
+ if (!super_hmem.Initialize() ||
+ !super.Initialize(&super_hmem, &drive,
+ 16*num_boot_sectors, num_boot_sectors) ||
+ !super.Read() ||
+ !spare_hmem.Initialize() ||
+ !spare.Initialize(&spare_hmem, &drive,
+ 17*num_boot_sectors, num_boot_sectors) ||
+ !spare.Read()) {
+
+ could_be_hpfs = FALSE;
+ }
+ }
+
+ if (could_be_hpfs &&
+ IsThisHpfs(drive.QuerySectors(),
+ (PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK)bootsec.GetBuf(),
+ (PULONG) super.GetBuf(),
+ (PULONG) spare.GetBuf())) {
+
+ return FileSystemName->Initialize("HPFS");
+ }
+
+ if (could_be_fat &&
+ IsThisFat(drive.QuerySectors(),
+ (PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK)bootsec.GetBuf())) {
+
+ return FileSystemName->Initialize("FAT");
+ }
+
+ return FileSystemName->Initialize("RAW");
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+IFS_SYSTEM::DosDriveNameToNtDriveName(
+ IN PCWSTRING DosDriveName,
+ OUT PWSTRING NtDriveName
+ )
+/*++
+
+Routine Description:
+
+ This routine converts a dos style drive name to an NT style drive
+ name.
+
+Arguments:
+
+ DosDriveName - Supplies the dos style drive name.
+ NtDriveName - Supplies the nt style drive name.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ UNICODE_STRING string;
+ WSTR buffer[80];
+ CHNUM l;
+ PWSTR Wstr;
+
+ Wstr = DosDriveName->QueryWSTR(0, TO_END, buffer, 80);
+
+ if (!Wstr) {
+ return FALSE;
+ }
+
+ l = DosDriveName->QueryChCount() + 1;
+
+ buffer[l - 1] = '\\';
+ buffer[l] = 0;
+
+ if (!RtlDosPathNameToNtPathName_U(buffer, &string, NULL, NULL)) {
+ return FALSE;
+ }
+
+ string.Buffer[string.Length/sizeof(WSTR) - 1] = 0;
+
+ return NtDriveName->Initialize(string.Buffer);
+}
+
+VOID
+IFS_SYSTEM::Reboot (
+ IN BOOLEAN PowerOff
+ )
+/*++
+
+Routine Description:
+
+ Reboots the machine
+
+Arguments:
+
+ PowerOff -- if TRUE, we will ask the system to shut down and
+ power off.
+
+Return Value:
+
+ Only returns in case of error.
+
+--*/
+{
+
+#if defined ( _AUTOCHECK_ )
+
+ CONST PrivilegeBufferSize = 32;
+ CHAR PrivilegeBuffer[PrivilegeBufferSize];
+ NTSTATUS Status;
+ HANDLE TokenHandle;
+
+ PTOKEN_PRIVILEGES TokenPrivileges = (PTOKEN_PRIVILEGES)PrivilegeBuffer;
+
+ Status = NtOpenProcessToken( NtCurrentProcess(),
+ TOKEN_ADJUST_PRIVILEGES,
+ &TokenHandle );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ return;
+ }
+
+ memset( TokenPrivileges, 0, PrivilegeBufferSize );
+
+ TokenPrivileges->PrivilegeCount = 1;
+ TokenPrivileges->Privileges[0].Luid = RtlConvertUlongToLuid( SE_SHUTDOWN_PRIVILEGE );
+ TokenPrivileges->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+ Status = NtAdjustPrivilegesToken( TokenHandle,
+ FALSE,
+ TokenPrivileges,
+ 0,
+ NULL,
+ NULL );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ NtClose( TokenHandle );
+ return;
+ }
+
+ Status = NtShutdownSystem( PowerOff ? ShutdownPowerOff: ShutdownReboot );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ NtClose( TokenHandle );
+ return;
+ }
+
+#endif
+
+}
+
+PCANNED_SECURITY IFS_SYSTEM::_CannedSecurity = NULL;
+
+IFSUTIL_EXPORT
+PCANNED_SECURITY
+IFS_SYSTEM::GetCannedSecurity(
+ )
+/*++
+
+Routine Description:
+
+ This method fetches the canned security object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the canned security object; NULL to indicate
+ failure.
+
+--*/
+{
+ STATIC Initialized = FALSE;
+
+ if( !Initialized ) {
+
+ // The canned security information has not yet been
+ // generated; allocate and initialize a canned security
+ // object. Note that if initialization fails, DELETE
+ // will set _CannedSecurity back to NULL.
+ //
+ _CannedSecurity = NEW CANNED_SECURITY;
+
+ if( _CannedSecurity == NULL ||
+ !_CannedSecurity->Initialize() ) {
+
+ DebugPrint( "IFSUTIL: cannot initialize canned security.\n" );
+ DELETE( _CannedSecurity );
+ }
+
+ Initialized = TRUE;
+ }
+
+ return _CannedSecurity;
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+IFS_SYSTEM::QueryFreeDiskSpace(
+ IN PCWSTRING DosDriveName,
+ OUT PBIG_INT BytesFree
+ )
+/*++
+
+Routine Description:
+
+ Returns the amount of free space in a volume (in bytes).
+
+Arguments:
+
+ DosDrivename - Supplies the DOS name of the drive
+ BytesFree - Supplies the BIG_INT in which the result
+ is returned.
+
+Return Value:
+
+ BOOLEAN - TRUE if the amount of free space was obtained.
+
+--*/
+{
+ BOOLEAN Ok = FALSE;
+
+#if !defined( _AUTOCHECK_ )
+
+ WCHAR Buffer[MAX_PATH];
+ LPWSTR Drive;
+ BIG_INT TmpBigInt;
+
+ DWORD SectorsPerCluster;
+ DWORD BytesPerSector;
+ DWORD NumberOfFreeClusters;
+ DWORD TotalNumberOfClusters;
+
+ DebugPtrAssert( DosDriveName );
+
+ Drive = DosDriveName->QueryWSTR( 0, TO_END, Buffer, MAX_PATH );
+
+ if ( Drive ) {
+
+ if ( GetDiskFreeSpace( Drive,
+ &SectorsPerCluster,
+ &BytesPerSector,
+ &NumberOfFreeClusters,
+ &TotalNumberOfClusters
+ ) ) {
+
+ // Use a temporary big_int so that the following happens in
+ // large integer arithmetic.
+
+ TmpBigInt = BytesPerSector;
+ *BytesFree = TmpBigInt * SectorsPerCluster * NumberOfFreeClusters;
+
+ Ok = TRUE;
+ }
+ }
+
+#endif
+
+ return Ok;
+}
+
+
+BOOLEAN
+QueryDriverName(
+ IN PCWSTRING FileSystemName,
+ OUT PWSTRING DriverName
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the driver name corresponding to the
+ given file system name.
+
+Arguments:
+
+ FileSystemName - Supplies the name of the file system.
+ DriverName - Returns the name of the corresponding driver.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ DSTRING fat_name, hpfs_name;
+
+ if (!fat_name.Initialize("FAT") || !hpfs_name.Initialize("HPFS")) {
+ return FALSE;
+ }
+
+ if (!FileSystemName->Stricmp(&fat_name)) {
+ return DriverName->Initialize("FASTFAT");
+ } else if (!FileSystemName->Stricmp(&hpfs_name)) {
+ return DriverName->Initialize("PINBALL");
+ }
+
+ return DriverName->Initialize(FileSystemName);
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+IFS_SYSTEM::EnableFileSystem(
+ IN PCWSTRING FileSystemName
+ )
+/*++
+
+Routine Description:
+
+ This routine will simply return TRUE because file systems are
+ enabled automatically due to a recent IO system change.
+ Formerly, this routine used to enable the file system in
+ the registry.
+
+Arguments:
+
+ FileSystemName - Supplies the name of the file system to enable.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(FileSystemName);
+
+ return TRUE;
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+IFS_SYSTEM::IsFileSystemEnabled(
+ IN PCWSTRING FileSystemName,
+ OUT PBOOLEAN Error
+ )
+/*++
+
+Routine Description:
+
+ This routine will always return TRUE now that the IO
+ system will automatically load file systems when needed.
+ Formerly, this method used to examine the registry
+ for this information.
+
+Argument:
+
+ FileSystemName - Supplies the name of the file system.
+ Error - Returns whether or not an error occurred.
+
+Return Value:
+
+ FALSE - The file system is not enabled.
+ TRUE - The file system is enabled.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(FileSystemName);
+
+ if (Error) {
+ *Error = FALSE;
+ }
+
+ return TRUE;
+}
+
+
+#endif // _SETUP_LOADER_
+
+
+IFSUTIL_EXPORT
+VOID
+IFS_SYSTEM::QueryHpfsTime(
+ OUT PULONG HpfsTime
+ )
+/*++
+
+Routine Description:
+
+ This method returns the current time in a format useful
+ to HPFS (seconds since 1970).
+
+Arguments:
+
+ HpfsTime -- receives the current time in HPFS format.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ LARGE_INTEGER NtfsTime;
+
+ QueryNtfsTime( &NtfsTime );
+ ConvertNtfsTimeToHpfsTime( NtfsTime, HpfsTime );
+}
+
+
+IFSUTIL_EXPORT
+VOID
+IFS_SYSTEM::QueryNtfsTime(
+ OUT PLARGE_INTEGER NtfsTime
+ )
+/*++
+
+Routine Description:
+
+ This method returns the current time in NTFS (ie. NT) format.
+
+Arguments
+
+ NtfsTime -- receives the current time in NTFS format.
+
+Return Value:
+
+ None.
+
+--*/
+{
+#if !defined( _SETUP_LOADER_ )
+
+ NtQuerySystemTime( NtfsTime );
+
+#else
+
+ TIME_FIELDS TimeFields;
+
+ SpGetTimeFields( &TimeFields );
+ RtlTimeFieldsToTime( &TimeFields, NtfsTime );
+
+#endif // _SETUP_LOADER_
+}
+
+
+IFSUTIL_EXPORT
+VOID
+IFS_SYSTEM::ConvertHpfsTimeToNtfsTime(
+ IN ULONG HpfsTime,
+ OUT PLARGE_INTEGER NtfsTime
+ )
+/*++
+
+Routine Description:
+
+ This method converts a time value in HPFS format into NTFS format.
+ Note that HPFS Time is Local Time, but NTFS Time is Universal Time.
+
+Arguments:
+
+ NtfsTime -- Supplies the time in NTFS format.
+ HpfsTime -- Receives the time in HPFS format.
+
+Return Value:
+
+ None.
+
+--*/
+{
+#if !defined( _SETUP_LOADER_ )
+
+ LARGE_INTEGER LocalTime;
+
+ RtlSecondsSince1970ToTime ( HpfsTime, &LocalTime );
+ RtlLocalTimeToSystemTime( &LocalTime, NtfsTime );
+
+#else
+
+ // In the setup-loader environment, Local-to-Universal time
+ // conversion is not available, so we blow it off.
+ //
+ RtlSecondsSince1970ToTime( HpfsTime, NtfsTime );
+
+#endif // _SETUP_LOADER_
+}
+
+
+VOID
+IFS_SYSTEM::ConvertNtfsTimeToHpfsTime(
+ IN LARGE_INTEGER NtfsTime,
+ OUT PULONG HpfsTime
+ )
+/*++
+
+Routine Description:
+
+ This method converts a time value in NTFS (ie. NT) format into
+ HPFS format. Note that HPFS Time is Local Time, but NTFS Time
+ is Universal Time.
+
+Arguments:
+
+ HpfsTime -- Supplies the time in HPFS format.
+ NtfsTime -- Receives the time in NTFS format.
+
+Return Value:
+
+ None.
+
+--*/
+{
+#if !defined( _SETUP_LOADER_ )
+
+ LARGE_INTEGER LocalTime;
+
+ RtlSystemTimeToLocalTime( &NtfsTime, &LocalTime );
+ RtlTimeToSecondsSince1970 ( &LocalTime, HpfsTime );
+
+#else
+
+ // In the setup-loader environment, Universal-to-Local time
+ // conversion is not available, so we blow it off.
+ //
+ RtlTimeToSecondsSince1970 ( &NtfsTime, HpfsTime );
+
+#endif
+}
+
+
+IFSUTIL_EXPORT
+ULONG
+IFS_SYSTEM::QueryPageSize(
+ )
+/*++
+
+Routine Description:
+
+ This method determines the page size of the system.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The system page size. A return value of 0 indicates error.
+
+--*/
+{
+#if !defined( _SETUP_LOADER_ )
+
+ SYSTEM_BASIC_INFORMATION BasicInfoBuffer;
+ NTSTATUS Status;
+
+ Status = NtQuerySystemInformation( SystemBasicInformation,
+ &BasicInfoBuffer,
+ sizeof( BasicInfoBuffer ),
+ NULL );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ return 0;
+
+ } else {
+
+ return BasicInfoBuffer.PageSize;
+ }
+
+#else
+
+ // The setup loader environment assumes a page size of 4K.
+ //
+ return 0x1000;
+
+#endif // _SETUP_LOADER_
+}
+
+
+#if !defined( _SETUP_LOADER_ )
+
+CONST MaxNtNameLength = 260;
+
+IFSUTIL_EXPORT
+BOOLEAN
+IFS_SYSTEM::QueryCanonicalNtDriveName(
+ IN PCWSTRING NtDriveName,
+ OUT PWSTRING CanonicalNtDriveName
+ )
+/*++
+
+Routine Description:
+
+ This routine follows the given NT drive name through all
+ of the links until it hits the end of the link chain.
+ The element at the end of the chain is the "canonical"
+ form.
+
+Arguments:
+
+ NtDriveName - Supplies the NT drive name to canonicalize.
+ CanonicalNtDriveName - Returns the canoncal form of the given drive
+ name.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ UNICODE_STRING source, target;
+ PUNICODE_STRING psource, ptarget, tmp;
+ NTSTATUS status;
+ OBJECT_ATTRIBUTES oa;
+ HANDLE handle;
+ WSTR buffer[MaxNtNameLength];
+
+ RtlInitUnicodeString(&source, NtDriveName->GetWSTR());
+ psource = &source;
+ ptarget = &target;
+
+ for (;;) {
+
+ InitializeObjectAttributes(&oa, psource, OBJ_CASE_INSENSITIVE,
+ NULL, NULL);
+
+ status = NtOpenSymbolicLinkObject(&handle,
+ READ_CONTROL | SYMBOLIC_LINK_QUERY,
+ &oa);
+
+ if (!NT_SUCCESS(status)) {
+ ptarget = psource;
+ break;
+ }
+
+ ptarget->Buffer = buffer;
+ ptarget->MaximumLength = MaxNtNameLength*sizeof(WCHAR);
+ status = NtQuerySymbolicLinkObject(handle, ptarget, NULL);
+ NtClose(handle);
+
+ if (!NT_SUCCESS(status)) {
+ ptarget = psource;
+ break;
+ }
+
+ tmp = psource;
+ psource = ptarget;
+ ptarget = tmp;
+ }
+
+ if (!CanonicalNtDriveName->Initialize(ptarget->Buffer,
+ ptarget->Length/sizeof(WCHAR))) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+IFS_SYSTEM::QueryNtSystemDriveName(
+ OUT PWSTRING NtSystemDriveName
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the NT device name for the partition
+ which contains the NT system files (ie. ntoskrnl.exe).
+
+Arguments:
+
+ NtSystemDriveName - Returns the NT drive name for the partition
+ on which ntoskrnl.exe resides.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ WSTR buffer[MaxNtNameLength];
+ UNICODE_STRING source, target;
+ FSTRING dos_name;
+ NTSTATUS status;
+
+ RtlInitUnicodeString(&source, (PWSTR) L"%SystemRoot%");
+
+ target.Buffer = buffer;
+ target.MaximumLength = MaxNtNameLength*sizeof(WCHAR);
+
+ status = RtlExpandEnvironmentStrings_U(NULL, &source, &target, NULL);
+
+ if (!NT_SUCCESS(status) ||
+ target.Length/sizeof(WCHAR) < 2 ||
+ target.Buffer[1] != ':') {
+
+ return FALSE;
+ }
+
+ target.Buffer[2] = 0;
+ dos_name.Initialize(target.Buffer);
+
+ return DosDriveNameToNtDriveName(&dos_name, NtSystemDriveName);
+}
+
+BOOLEAN
+IFS_SYSTEM::QuerySystemEnvironmentVariableValue(
+ IN PWSTRING VariableName,
+ IN ULONG ValueBufferLength,
+ OUT PVOID ValueBuffer,
+ OUT PUSHORT ValueLength
+ )
+/*++
+
+Routine Description:
+
+ This method fetches the value of an NT System Variable. (Note
+ that this is a set of variables distinct from the Windows
+ environment variables.)
+
+Arguments:
+
+ VariableName
+ ValueBufferLength -- Supplies the length (in bytes) of the
+ buffer supplied to hold the output value.
+ ValueBuffer -- Receives the UNICODE value of the
+ environment variable.
+ ValueLength -- Receives the length (in bytes) of the
+ value.
+
+Return Value:
+
+ TRUE if the method was able to query the value of the specified
+ environment variable.
+
+--*/
+{
+ UNICODE_STRING Name;
+ NTSTATUS Status;
+ BOOLEAN WasEnabled;
+
+ Name.Buffer = (PWSTR)VariableName->GetWSTR();
+ Name.Length = (USHORT)VariableName->QueryChCount() * sizeof(WCHAR);
+ Name.MaximumLength = Name.Length;
+
+ // Adjust the privileges so we can access system variables:
+ //
+ Status = RtlAdjustPrivilege( SE_SYSTEM_ENVIRONMENT_PRIVILEGE,
+ TRUE,
+ FALSE,
+ &WasEnabled );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ DebugPrintf( "IFSUTIL: Could not adjust privileges (Status 0x%x).\n", Status );
+ return FALSE;
+ }
+
+ Status = NtQuerySystemEnvironmentValue( &Name,
+ (PWSTR)ValueBuffer,
+ (USHORT)ValueBufferLength,
+ ValueLength );
+
+ // Set the privilege back:
+ //
+ RtlAdjustPrivilege( SE_SYSTEM_PROFILE_PRIVILEGE,
+ WasEnabled,
+ FALSE,
+ &WasEnabled );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ DebugPrintf( "IFSUTIL: Couldn't query system variable--status 0x%x\n", Status );
+ return FALSE;
+
+ } else {
+
+ return TRUE;
+ }
+}
+
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+IFS_SYSTEM::IsArcSystemPartition(
+ IN PCWSTRING NtDriveName,
+ OUT PBOOLEAN Error
+ )
+/*++
+
+Routine Description:
+
+ This routine determines whether the specified drive
+ appears in the list of System Partitions in the ARC
+ boot selections.
+
+Arguments:
+
+ NtDriveName -- Supplies the name
+ Error -- Receives TRUE if the method encountered an
+ error.
+
+Return Value:
+
+ TRUE if the specified volume is a System Partition for a
+ system boot selection.
+
+Notes:
+
+ The System Partitions is the volume from which the system
+ loads OSLOADER.EXE and HAL.DLL. The system partitions
+ for the various boot selections are listed in the system
+ environment variable SYSTEMPARTITION. The value of this
+ variable is a list of ARC names delimited by semicolons.
+
+--*/
+{
+#if defined( i386 )
+
+ *Error = FALSE;
+ return FALSE;
+
+#else
+
+ CONST ULONG ValueBufferSize = 512;
+ BYTE SystemPartitionValue[ValueBufferSize];
+ DSTRING SearchName, CurrentNameString, CurrentCanonicalName, VariableName,
+ ZeroString, ArcPrefixString;
+ PWSTR CurrentName, CurrentChar;
+ ULONG RemainingLength, CurrentNameLength, i;
+ USHORT ValueLength = 0;
+
+ DebugPtrAssert( NtDriveName );
+ DebugPtrAssert( Error );
+
+ // Assume innocent until...
+ //
+ *Error = FALSE;
+
+ // Initialize the helper strings:
+ //
+ if( !ZeroString.Initialize( "0" ) ||
+ !ArcPrefixString.Initialize( "\\ArcName\\" ) ) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ // Canonicalize the search name:
+ //
+ if( !QueryCanonicalNtDriveName( NtDriveName, &SearchName ) ) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ // Fetch the value of the system environment variable
+ // SystemPartition.
+ //
+ if( !VariableName.Initialize( "SystemPartition" ) ||
+ !QuerySystemEnvironmentVariableValue( &VariableName,
+ ValueBufferSize,
+ SystemPartitionValue,
+ &ValueLength ) ) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ // Step through the list of partition names in the
+ // value of the SystemPartition variable. For each
+ // partition name, canonicalize it and compare it to
+ // the search name.
+ //
+ RemainingLength = ValueLength/sizeof(WCHAR);
+ CurrentChar = (PWSTR)SystemPartitionValue;
+
+ while( RemainingLength ) {
+
+ // Determine the length of the current name:
+ //
+ CurrentName = CurrentChar;
+ CurrentNameLength = 0;
+
+ while( RemainingLength && *CurrentChar != ';' ) {
+
+ CurrentNameLength++;
+ RemainingLength--;
+ CurrentChar++;
+ }
+
+ if( CurrentNameLength != 0 ) {
+
+ // Initialize a DSTRING for the current name
+ // and canonicalize it for comparison with the
+ // (canonicalized) search name.
+ //
+ if( !CurrentNameString.Initialize( CurrentName,
+ CurrentNameLength ) ) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ // Now normalize the current ARC name--prepend it
+ // with \ArcName\ and replace any occurrence of
+ // "()" with "(0)".
+ //
+ if( !CurrentNameString.InsertString( 0, &ArcPrefixString ) ) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ // Find the first occurrence of '(':
+ //
+ i = CurrentNameString.Strchr( '(', 0 );
+
+ while( i != INVALID_CHNUM ) {
+
+ i++;
+
+ if( CurrentNameString.QueryChAt( i ) == ')' &&
+ !CurrentNameString.InsertString( i, &ZeroString ) ) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ // Find the next occurrence of '(':
+ //
+ i = CurrentNameString.Strchr( '(', i );
+ }
+
+ // CurrentNameString is now a symbolic link to an ARC
+ // System Partition. Canonicalize this name in the
+ // NT name space and compare it to the (previously
+ // canonicalized) search name.
+ //
+ if( !QueryCanonicalNtDriveName( &CurrentNameString,
+ &CurrentCanonicalName ) ) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ if( SearchName.Stricmp( &CurrentCanonicalName ) == 0 ) {
+
+ // Found a match--the search name is an ARC System
+ // Partition.
+ //
+ return TRUE;
+ }
+
+ }
+
+ // If RemainingLength is non-zero, then CurrentChar is
+ // pointing at a semicolon delimiter. Step over it
+ // to the next name.
+ //
+ if( RemainingLength ) {
+
+ RemainingLength--;
+ CurrentChar++;
+ }
+ }
+
+ // No match was found--this name is not an ARC System Partition.
+ //
+ return FALSE;
+#endif // i386
+}
+
+
+BOOLEAN
+IFS_SYSTEM::FileSetAttributes(
+ IN HANDLE FileHandle,
+ IN ULONG NewAttributes,
+ OUT PULONG OldAttributes
+ )
+/*++
+
+Routine Description:
+
+ This method changes the attributes (read-only, system, hidden,
+ archive) on a file.
+
+Arguments:
+
+ FileHandle -- Supplies the handle of the target file.
+ NewAttributes -- Supplies the new attributes for the file.
+ OldAttributes -- Receives the existing file attributes.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatusBlock;
+ FILE_BASIC_INFORMATION BasicInfo;
+
+ Status = NtQueryInformationFile( FileHandle,
+ &IoStatusBlock,
+ &BasicInfo,
+ sizeof(BasicInfo),
+ FileBasicInformation
+ );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ return FALSE;
+ }
+
+ *OldAttributes = BasicInfo.FileAttributes;
+
+ BasicInfo.FileAttributes = NewAttributes;
+
+ Status = NtSetInformationFile( FileHandle,
+ &IoStatusBlock,
+ &BasicInfo,
+ sizeof(BasicInfo),
+ FileBasicInformation
+ );
+
+ return( NT_SUCCESS( Status ) );
+}
+
+IFSUTIL_EXPORT
+BOOLEAN
+IFS_SYSTEM::FileSetAttributes(
+ IN PCWSTRING FileName,
+ IN ULONG NewAttributes,
+ OUT PULONG OldAttributes
+ )
+/*++
+
+Routine Description:
+
+ This method changes the attributes (read-only, system, hidden,
+ archive) on a file.
+
+Arguments:
+
+ FileName -- Supplies the name of the target file.
+ NewAttributes -- Supplies the new attributes for the file.
+ OldAttributes -- Receives the existing file attributes.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES Obja;
+ HANDLE Handle;
+ UNICODE_STRING string;
+ IO_STATUS_BLOCK IoStatusBlock;
+ BOOLEAN Result;
+
+ string.Buffer = (PWSTR)FileName->GetWSTR();
+ string.Length = (USHORT)FileName->QueryChCount() * sizeof( WCHAR );
+ string.MaximumLength = string.Length;
+
+ InitializeObjectAttributes(
+ &Obja,
+ &string,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+ Status = NtOpenFile(
+ &Handle,
+ FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
+ &Obja,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT
+ );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ return FALSE;
+ }
+
+ Result = FileSetAttributes( Handle, NewAttributes, OldAttributes );
+
+ NtClose( Handle );
+
+ return Result;
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+IFS_SYSTEM::WriteToFile(
+ IN PCWSTRING QualifiedFileName,
+ IN PVOID Data,
+ IN ULONG DataLength,
+ IN BOOLEAN Append
+ )
+/*++
+
+Routine Description:
+
+ This method appends the given data to the specified file
+ using the NT-native file-system API. If the file does not
+ exist, it is created.
+
+Arguments:
+
+ QualifiedFileName -- Supplies the fully-qualified file name.
+ Data -- Supplies the data to be written to the file.
+ DataLength -- Supplies the length of data in bytes.
+ Append -- Supplies a flag indicating that new data
+ should be appended to the file, rather than
+ overwriting it.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES Obja;
+ HANDLE Handle;
+ UNICODE_STRING string;
+ IO_STATUS_BLOCK StatusBlock;
+ LARGE_INTEGER FileOffset;
+
+ if( Append && DataLength == 0 ) {
+
+ return TRUE;
+ }
+
+ string.Buffer = (PWSTR)QualifiedFileName->GetWSTR();
+ string.Length = (USHORT)QualifiedFileName->QueryChCount() * sizeof( WCHAR );
+ string.MaximumLength = string.Length;
+
+ InitializeObjectAttributes(
+ &Obja,
+ &string,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+ // If we're appending to the file, open; if that fails, create
+ // it. If we're not appending, just create it.
+ //
+ if( Append ) {
+
+ Status = NtOpenFile(
+ &Handle,
+ FILE_GENERIC_READ | FILE_GENERIC_WRITE,
+ &Obja,
+ &StatusBlock,
+ FILE_SHARE_READ,
+ 0
+ );
+ }
+
+ if( !Append ||
+ Status == STATUS_NO_SUCH_FILE ||
+ Status == STATUS_OBJECT_NAME_NOT_FOUND ) {
+
+ Status = NtCreateFile( &Handle,
+ FILE_GENERIC_READ | FILE_GENERIC_WRITE,
+ &Obja,
+ &StatusBlock,
+ NULL, // No pre-allocation
+ FILE_ATTRIBUTE_NORMAL,
+ 0, // No sharing.
+ FILE_OVERWRITE_IF,
+ FILE_NON_DIRECTORY_FILE,
+ NULL, // No EA's
+ 0 );
+ }
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ // Can't open or create the file.
+ //
+ DebugPrintf( "IFSUTIL: Error opening/creating file--status 0x%x\n", Status );
+ return FALSE;
+ }
+
+ FileOffset = RtlConvertLongToLargeInteger( FILE_WRITE_TO_END_OF_FILE );
+
+ Status = NtWriteFile( Handle,
+ 0, NULL, NULL,
+ &StatusBlock,
+ Data,
+ DataLength,
+ &FileOffset,
+ NULL );
+
+ NtClose( Handle );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ DebugPrintf( "IFSUTIL: NtWriteFile failed with status 0x%s\n", Status );
+ return FALSE;
+
+ } else {
+
+ return TRUE;
+ }
+}
+
+IFSUTIL_EXPORT
+BOOLEAN
+IFS_SYSTEM::EnableVolumeCompression(
+ IN PCWSTRING NtDriveName
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the bit on the root directory of the given
+ volume so that files added to the volume will be compressed.
+
+Arguments:
+
+ NtDriveName -- the name of the volume
+
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES Obja;
+ HANDLE Handle;
+ UNICODE_STRING string;
+ IO_STATUS_BLOCK IoStatusBlock;
+ USHORT State = 1;
+ DSTRING FileName;
+ DSTRING backslash;
+
+ if (!backslash.Initialize("\\") ||
+ !FileName.Initialize(NtDriveName) ||
+ !FileName.Strcat(&backslash)) {
+ return FALSE;
+ }
+
+ string.Buffer = (PWSTR)FileName.GetWSTR();
+ string.Length = (USHORT)FileName.QueryChCount() * sizeof( WCHAR );
+ string.MaximumLength = string.Length;
+
+ InitializeObjectAttributes(
+ &Obja,
+ &string,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+ Status = NtOpenFile(
+ &Handle,
+ FILE_READ_DATA|FILE_WRITE_DATA|SYNCHRONIZE,
+ &Obja,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT
+ );
+
+ if (!NT_SUCCESS(Status)) {
+ return FALSE;
+ }
+
+ Status = NtFsControlFile(
+ Handle,
+ NULL, /* Event */
+ NULL, /* ApcRoutine */
+ NULL, /* ApcContext */
+ &IoStatusBlock,
+ FSCTL_SET_COMPRESSION,
+ (PVOID)&State, /* InputBuffer */
+ sizeof(State), /* InputBufferLength */
+ NULL, /* OutputBuffer */
+ 0 /* OutputBufferLength */
+ );
+
+ NtClose(Handle);
+
+ if (!NT_SUCCESS(Status)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+typedef struct _KNOWN_ACE {
+ ACE_HEADER Header;
+ ACCESS_MASK Mask;
+ ULONG SidStart;
+} KNOWN_ACE, *PKNOWN_ACE;
+
+#define LongAlign(Ptr) ( \
+ (PVOID)((((ULONG)(Ptr)) + 3) & 0xfffffffc) \
+ )
+
+#define LongAligned( ptr ) (LongAlign((ptr)) == ((PVOID)(ptr)))
+
+IFSUTIL_EXPORT
+BOOLEAN
+IFS_SYSTEM::CheckValidSecurityDescriptor(
+ IN ULONG Length,
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor
+ )
+/*++
+
+Routine Description:
+
+ Validates a security descriptor for structural correctness.
+
+Arguments:
+
+ Length - Length in bytes of passed Security Descriptor.
+
+ SecurityDescriptor - Points to the Security Descriptor (in kernel memory) to be
+ validatated.
+
+Return Value:
+
+ TRUE - The passed security descriptor is correctly structured
+ FALSE - The passed security descriptor is badly formed
+
+--*/
+{
+ PISECURITY_DESCRIPTOR ISecurityDescriptor = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
+ PISID OwnerSid;
+ PISID GroupSid;
+ PACE_HEADER Ace;
+ PISID Sid;
+ PACL Dacl;
+ PACL Sacl;
+ ULONG i;
+
+ if (Length < sizeof(SECURITY_DESCRIPTOR)) {
+ return(FALSE);
+ }
+
+ //
+ // Check the revision information.
+ //
+
+ if (ISecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
+ return(FALSE);
+ }
+
+ //
+ // Make sure the passed SecurityDescriptor is in self-relative form
+ //
+
+ if (!(ISecurityDescriptor->Control & SE_SELF_RELATIVE)) {
+ return(FALSE);
+ }
+
+ //
+ // Check the owner. A valid SecurityDescriptor must have an owner.
+ // It must also be long aligned.
+ //
+
+ if (ISecurityDescriptor->Owner == NULL || !LongAligned(ISecurityDescriptor->Owner) ||
+ (ULONG)((PCHAR)(ISecurityDescriptor->Owner)+sizeof(SID)) > Length) {
+
+ return(FALSE);
+ }
+
+ //
+ // It is safe to reference the owner's SubAuthorityCount, compute the
+ // expected length of the SID
+ //
+
+ OwnerSid = (PISID)RtlOffsetToPointer( ISecurityDescriptor, ISecurityDescriptor->Owner );
+
+ if (OwnerSid->Revision != SID_REVISION) {
+ return(FALSE);
+ }
+
+ if (OwnerSid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) {
+ return(FALSE);
+ }
+
+ if ((ULONG)((PCHAR)ISecurityDescriptor->Owner+RtlLengthSid(OwnerSid)) > Length) {
+ return(FALSE);
+ }
+
+ //
+ // The owner appears to be a structurally valid SID that lies within
+ // the bounds of the security descriptor. Do the same for the Group
+ // if there is one.
+ //
+
+ if (ISecurityDescriptor->Group != NULL) {
+
+ //
+ // Check alignment
+ //
+
+ if (!LongAligned(ISecurityDescriptor->Group)) {
+ return(FALSE);
+ }
+
+ if ((ULONG)((PCHAR)(ISecurityDescriptor->Group)+sizeof(SID)) > Length) {
+ return(FALSE);
+ }
+
+ //
+ // It is safe to reference the Group's SubAuthorityCount, compute the
+ // expected length of the SID
+ //
+
+ GroupSid = (PISID)RtlOffsetToPointer( ISecurityDescriptor, ISecurityDescriptor->Group );
+
+ if (GroupSid->Revision != SID_REVISION) {
+ return(FALSE);
+ }
+
+ if (GroupSid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) {
+ return(FALSE);
+ }
+
+ if ((ULONG)((PCHAR)ISecurityDescriptor->Group+RtlLengthSid(GroupSid)) > Length) {
+ return(FALSE);
+ }
+ }
+
+ //
+ // Validate the DACL. A structurally valid SecurityDescriptor may not necessarily
+ // have a DACL.
+ //
+
+ if (ISecurityDescriptor->Dacl != NULL) {
+
+ //
+ // Check alignment
+ //
+
+ if (!LongAligned(ISecurityDescriptor->Dacl)) {
+ return(FALSE);
+ }
+
+ //
+ // Make sure the DACL structure is within the bounds of the security descriptor.
+ //
+
+ if ((ULONG)((PCHAR)(ISecurityDescriptor->Dacl)+sizeof(ACL)) > Length) {
+ return(FALSE);
+ }
+
+ Dacl = (PACL)RtlOffsetToPointer( ISecurityDescriptor, ISecurityDescriptor->Dacl );
+
+ if (Dacl->AclRevision != ACL_REVISION) {
+ return(FALSE);
+ }
+
+ if (!LongAligned(Dacl->AclSize)) {
+ return(FALSE);
+ }
+
+ if ((ULONG)((PUCHAR)ISecurityDescriptor->Dacl + Dacl->AclSize) > Length) {
+ return(FALSE);
+ }
+
+ //
+ // Validate all of the ACEs.
+ //
+
+ Ace = (PACE_HEADER)((PVOID)((PUCHAR)(Dacl) + sizeof(ACL)));
+
+ for (i = 0; i < Dacl->AceCount; i++) {
+
+ //
+ // Check to make sure we haven't overrun the Acl buffer
+ // with our ace pointer.
+ //
+
+ if ((PVOID)Ace >= (PVOID)((PUCHAR)Dacl + Dacl->AclSize)) {
+ return(FALSE);
+ }
+
+ //
+ // The ACE fits into the ACL, if this is a known type of ACE,
+ // make sure the SID is within the bounds of the ACE
+ //
+
+ if (Ace->AceType == ACCESS_ALLOWED_ACE_TYPE || Ace->AceType == ACCESS_DENIED_ACE_TYPE) {
+
+ if (!LongAligned(Ace->AceSize)) {
+ return(FALSE);
+ }
+
+ if (Ace->AceSize < sizeof(KNOWN_ACE) - sizeof(ULONG) + sizeof(SID)) {
+ return(FALSE);
+ }
+
+ //
+ // It's now safe to reference the parts of the SID structure, though
+ // not the SID itself.
+ //
+
+ Sid = (PISID) & (((PKNOWN_ACE)Ace)->SidStart);
+
+ if (Sid->Revision != SID_REVISION) {
+ return(FALSE);
+ }
+
+ if (Sid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) {
+ return(FALSE);
+ }
+
+ //
+ // RtlLengthSid computes the size of the SID based on the subauthority count,
+ // so it is safe to use even though we don't know that the body of the SID
+ // is safe to reference.
+ //
+
+ if (Ace->AceSize < sizeof(KNOWN_ACE) - sizeof(ULONG) + RtlLengthSid( Sid )) {
+ return(FALSE);
+ }
+ }
+
+ //
+ // And move Ace to the next ace position
+ //
+
+ Ace = (PACE_HEADER)((PVOID)((PUCHAR)(Ace) +
+ ((PACE_HEADER)(Ace))->AceSize));
+ }
+ }
+
+ //
+ // Validate the SACL. A structurally valid SecurityDescriptor may not
+ // have a SACL.
+ //
+
+ if (ISecurityDescriptor->Sacl != NULL) {
+
+ //
+ // Check alignment
+ //
+
+ if (!LongAligned(ISecurityDescriptor->Sacl)) {
+ return(FALSE);
+ }
+
+ if ((ULONG)((PCHAR)(ISecurityDescriptor->Sacl)+sizeof(ACL)) > Length) {
+ return(FALSE);
+ }
+
+ Sacl = (PACL)RtlOffsetToPointer( ISecurityDescriptor, ISecurityDescriptor->Sacl );
+
+ if (!LongAligned(Sacl->AclSize)) {
+ return(FALSE);
+ }
+
+ if (Sacl->AclRevision != ACL_REVISION) {
+ return(FALSE);
+ }
+
+ if ((ULONG)((PUCHAR)ISecurityDescriptor->Sacl + Sacl->AclSize) > Length) {
+ return(FALSE);
+ }
+
+ //
+ // Validate all of the ACEs.
+ //
+
+ Ace = (PACE_HEADER)((PVOID)((PUCHAR)(Sacl) + sizeof(ACL)));
+
+ for (i = 0; i < Sacl->AceCount; i++) {
+
+ //
+ // Check to make sure we haven't overrun the Acl buffer
+ // with our ace pointer.
+ //
+
+ if ((PVOID)Ace >= (PVOID)((PUCHAR)Sacl + Sacl->AclSize)) {
+ return(FALSE);
+ }
+
+ //
+ // The ACE fits into the ACL, if this is a known type of ACE,
+ // make sure the SID is within the bounds of the ACE
+ //
+
+ if (Ace->AceType == SYSTEM_AUDIT_ACE_TYPE || Ace->AceType == SYSTEM_ALARM_ACE_TYPE) {
+
+ if (!LongAligned(Ace->AceSize)) {
+ return(FALSE);
+ }
+
+ if (Ace->AceSize < sizeof(KNOWN_ACE) - sizeof(ULONG) + sizeof(SID)) {
+ return(FALSE);
+ }
+
+ Sid = (PISID) & ((PKNOWN_ACE)Ace)->SidStart;
+
+ if (Sid->Revision != SID_REVISION) {
+ return(FALSE);
+ }
+
+ if (Sid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) {
+ return(FALSE);
+ }
+
+ if (Ace->AceSize < sizeof(KNOWN_ACE) - sizeof(ULONG) + RtlLengthSid( Sid )) {
+ return(FALSE);
+ }
+ }
+
+ //
+ // And move Ace to the next ace position
+ //
+
+ Ace = (PACE_HEADER)((PVOID)((PUCHAR)(Ace) +
+ ((PACE_HEADER)(Ace))->AceSize));
+ }
+ }
+
+ return(TRUE);
+}
+
+IFSUTIL_EXPORT
+BOOLEAN
+IFS_SYSTEM::IsVolumeDirty(
+ IN PWSTRING NtDriveName,
+ OUT PBOOLEAN Result
+ )
+/*++
+
+Routine Description:
+
+ This routine opens the given nt drive and sends down
+ FSCTL_IS_VOLUME_DIRTY to determine the state of that volume's
+ dirty bit.
+
+Arguments:
+
+ NtDriveName -- supplies the volume in question
+ Result -- returns the state of the dirty bit
+
+Return Value:
+
+ FALSE -- the dirty bit could not be queried
+ TRUE -- success
+
+--*/
+{
+ UNICODE_STRING u;
+ OBJECT_ATTRIBUTES obj;
+ NTSTATUS status;
+ IO_STATUS_BLOCK iosb;
+ HANDLE h;
+ ULONG r;
+
+ u.Length = (USHORT)NtDriveName->QueryChCount() * sizeof(WCHAR);
+ u.MaximumLength = u.Length;
+ u.Buffer = (PWSTR)NtDriveName->GetWSTR();
+
+ InitializeObjectAttributes(&obj, &u, OBJ_CASE_INSENSITIVE, 0, 0);
+
+ status = NtOpenFile(&h,
+ SYNCHRONIZE | FILE_READ_DATA,
+ &obj,
+ &iosb,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT);
+
+ if (!NT_SUCCESS(status)) {
+
+ return FALSE;
+ }
+
+ status = NtFsControlFile(h, NULL, NULL, NULL,
+ &iosb,
+ FSCTL_IS_VOLUME_DIRTY,
+ NULL, 0,
+ &r, sizeof(r));
+
+ if (!NT_SUCCESS(status)) {
+
+ return FALSE;
+ }
+
+ *Result = (BOOLEAN)r;
+
+ return TRUE;
+}
+
+#endif // _SETUP_LOADER_
diff --git a/private/utils/ifsutil/src/ifsutil.cxx b/private/utils/ifsutil/src/ifsutil.cxx
new file mode 100644
index 000000000..69e8c6f35
--- /dev/null
+++ b/private/utils/ifsutil/src/ifsutil.cxx
@@ -0,0 +1,163 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ifsutil.cxx
+
+Abstract:
+
+ This module contains run-time, global support for the
+ IFS Utilities library (IFSUTIL). This support includes:
+
+ - creation of CLASS_DESCRIPTORs
+ - Global objects
+
+Author:
+
+ Bill McJohn (billmc) 30-May-1991
+
+Environment:
+
+ User Mode
+
+Notes:
+
+--*/
+
+#include <pch.cxx>
+
+#define _IFSUTIL_MEMBER_
+
+#include "ulib.hxx"
+#include "ifsutil.hxx"
+
+#include "error.hxx"
+
+#if !defined( _AUTOCHECK_ )
+
+ERRSTACK* perrstk;
+
+#endif // _AUTOCHECK_
+
+
+// Local prototypes
+
+STATIC
+BOOLEAN
+DefineClassDescriptors(
+ );
+
+extern "C"
+IFSUTIL_EXPORT
+BOOLEAN
+InitializeIfsUtil (
+ PVOID DllHandle,
+ ULONG Reason,
+ PCONTEXT Context
+ );
+
+IFSUTIL_EXPORT
+BOOLEAN
+InitializeIfsUtil (
+ PVOID DllHandle,
+ ULONG Reason,
+ PCONTEXT Context
+ )
+/*++
+
+Routine Description:
+
+ Initialize Ufat by constructing and initializing all
+ global objects. These include:
+
+ - all CLASS_DESCRIPTORs (class_cd)
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if all global objects were succesfully constructed
+ and initialized.
+
+--*/
+
+{
+
+ STATIC BOOLEAN fInit = FALSE;
+
+ if ( fInit ) {
+
+ return( TRUE );
+ }
+
+ if ( DefineClassDescriptors() ) {
+
+ fInit = TRUE;
+ return TRUE;
+
+ } else {
+
+ DebugAbort( "IfsUtil initialization failed!!!\n" );
+ return( FALSE );
+ }
+}
+
+
+DECLARE_CLASS( AUTOENTRY );
+DECLARE_CLASS( CACHE );
+DECLARE_CLASS( CANNED_SECURITY );
+DECLARE_CLASS( DIGRAPH );
+DECLARE_CLASS( DIGRAPH_EDGE );
+DECLARE_CLASS( DRIVE );
+DECLARE_CLASS( DP_DRIVE );
+DECLARE_CLASS( INTSTACK );
+DECLARE_CLASS( IO_DP_DRIVE );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( NUMBER_EXTENT );
+DECLARE_CLASS( NUMBER_SET );
+DECLARE_CLASS( PHYS_IO_DP_DRIVE );
+DECLARE_CLASS( SECRUN );
+DECLARE_CLASS( SUPERAREA );
+DECLARE_CLASS( VOL_LIODPDRV );
+DECLARE_CLASS( DRIVE_CACHE );
+DECLARE_CLASS( READ_CACHE );
+DECLARE_CLASS( READ_WRITE_CACHE );
+
+
+STATIC
+BOOLEAN
+DefineClassDescriptors(
+ )
+{
+ if( DEFINE_CLASS_DESCRIPTOR( AUTOENTRY ) &&
+ DEFINE_CLASS_DESCRIPTOR( CACHE ) &&
+ DEFINE_CLASS_DESCRIPTOR( CANNED_SECURITY ) &&
+ DEFINE_CLASS_DESCRIPTOR( DIGRAPH ) &&
+ DEFINE_CLASS_DESCRIPTOR( DIGRAPH_EDGE ) &&
+ DEFINE_CLASS_DESCRIPTOR( DRIVE ) &&
+ DEFINE_CLASS_DESCRIPTOR( DP_DRIVE ) &&
+ DEFINE_CLASS_DESCRIPTOR( IO_DP_DRIVE ) &&
+ DEFINE_CLASS_DESCRIPTOR( LOG_IO_DP_DRIVE ) &&
+ DEFINE_CLASS_DESCRIPTOR( PHYS_IO_DP_DRIVE ) &&
+ DEFINE_CLASS_DESCRIPTOR( SECRUN ) &&
+ DEFINE_CLASS_DESCRIPTOR( SUPERAREA ) &&
+ DEFINE_CLASS_DESCRIPTOR( NUMBER_EXTENT ) &&
+ DEFINE_CLASS_DESCRIPTOR( NUMBER_SET ) &&
+ DEFINE_CLASS_DESCRIPTOR( INTSTACK ) &&
+ DEFINE_CLASS_DESCRIPTOR( READ_CACHE ) &&
+ DEFINE_CLASS_DESCRIPTOR( READ_WRITE_CACHE ) &&
+ DEFINE_CLASS_DESCRIPTOR( DRIVE_CACHE ) &&
+ DEFINE_CLASS_DESCRIPTOR( VOL_LIODPDRV ) ) {
+
+ return TRUE;
+
+ } else {
+
+ DebugPrint( "Could not initialize class descriptors!");
+ return FALSE;
+ }
+}
diff --git a/private/utils/ifsutil/src/ifsutil.rc b/private/utils/ifsutil/src/ifsutil.rc
new file mode 100644
index 000000000..1d6078507
--- /dev/null
+++ b/private/utils/ifsutil/src/ifsutil.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "IFS Utility DLL"
+#define VER_INTERNALNAME_STR "IFSUtil"
+#define VER_ORIGINALFILENAME_STR "IFSUtil.DLL"
+
+#include "common.ver"
diff --git a/private/utils/ifsutil/src/intstack.cxx b/private/utils/ifsutil/src/intstack.cxx
new file mode 100644
index 000000000..df71c9683
--- /dev/null
+++ b/private/utils/ifsutil/src/intstack.cxx
@@ -0,0 +1,265 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _IFSUTIL_MEMBER_
+
+#include "ulib.hxx"
+#include "ifsutil.hxx"
+
+#include "error.hxx"
+#include "intstack.hxx"
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( INTSTACK, OBJECT, IFSUTIL_EXPORT );
+
+VOID
+INTSTACK::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Constructor for INTSTACK.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _stack = NULL;
+ _size = 0;
+}
+
+
+IFSUTIL_EXPORT
+INTSTACK::~INTSTACK(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for INTSTACK.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+INTSTACK::Initialize(
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the stack for new input.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ Destroy();
+ return TRUE;
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+INTSTACK::Push(
+ IN BIG_INT Data
+ )
+/*++
+
+Routine Description:
+
+ This routine pushes 'Data' on the stack.
+
+Arguments:
+
+ Data - Supplies the integer to push on the stack.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PINTNODE p;
+
+ p = _stack;
+ if (!(_stack = NEW INTNODE)) {
+ _stack = p;
+ return FALSE;
+ }
+
+ _stack->Next = p;
+ _stack->Data = Data;
+ _size++;
+
+ return TRUE;
+}
+
+
+IFSUTIL_EXPORT
+VOID
+INTSTACK::Pop(
+ IN ULONG HowMany
+ )
+/*++
+
+Routine Description:
+
+ This routine attempts to remove 'HowMany' elements from the top of
+ the stack. If there are not that many to remove then all that
+ can be removed, will be removed and FALSE will be returned.
+
+Arguments:
+
+ HowMany - Supplies the number of elements to remove from the top of the
+ stack.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PINTNODE p;
+
+ for (; HowMany; HowMany--) {
+
+ DebugAssert(_stack);
+
+ p = _stack->Next;
+ DELETE( _stack );
+ _stack = p;
+ _size--;
+ }
+}
+
+
+IFSUTIL_EXPORT
+BIG_INT
+INTSTACK::Look(
+ IN ULONG Index
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the 'Index'th element of the stack. Index 0 denotes
+ the top of the stack. Index 1 denotes one element from the top of the
+ stack and so on. If the stack is smaller than the element requested then
+ this routine will return 0. This is not a limitation since 'QuerySize'
+ will return the depth of the stack.
+
+Arguments:
+
+ Index - Supplies the index of the data requested.
+
+Return Value:
+
+ The value of the stack element at position 'Index' or 0.
+
+--*/
+{
+ PINTNODE p;
+
+ p = _stack;
+ for (; Index; Index--) {
+ p = p ? p->Next : NULL;
+ }
+
+ if (!p) {
+ return 0;
+ }
+
+ return p->Data;
+}
+
+
+BOOLEAN
+INTSTACK::IsMember(
+ IN BIG_INT Data
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine searches the stack to see if there is an element equal
+ to 'Data'. It returns TRUE if there is.
+
+Arguments:
+
+ Data - Supplies the element to search for.
+
+Return Value:
+
+ FALSE - 'Data' is not an element of the stack.
+ TRUE - 'Data' is an element of the stack.
+
+--*/
+{
+ PINTNODE p;
+
+ for (p = _stack; p; p = p->Next) {
+ if (Data == p->Data) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+VOID
+INTSTACK::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the INTSTACK to its initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PINTNODE p;
+
+ while (_stack) {
+ p = _stack->Next;
+ DELETE( _stack );
+ _stack = p;
+ }
+ _size = 0;
+}
diff --git a/private/utils/ifsutil/src/makefile b/private/utils/ifsutil/src/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/ifsutil/src/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/ifsutil/src/mldcopy.cxx b/private/utils/ifsutil/src/mldcopy.cxx
new file mode 100644
index 000000000..4e7842cd4
--- /dev/null
+++ b/private/utils/ifsutil/src/mldcopy.cxx
@@ -0,0 +1,1044 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _IFSUTIL_MEMBER_
+
+extern "C" {
+#include "ntlsa.h"
+#include "..\..\..\lsa\crypt\engine\md4.h"
+}
+
+#include "ulib.hxx"
+#include "ifsutil.hxx"
+
+#include "ifssys.hxx"
+#include "wstring.hxx"
+#include "drive.hxx"
+#include "mldcopy.hxx"
+#include "rtmsg.h"
+#include "supera.hxx"
+#include "hmem.hxx"
+#include "cmem.hxx"
+#include "message.hxx"
+
+
+#define JIMS_BIG_NUMBER 718315
+#define RegPath TEXT("System\\CurrentControlSet\\Control\\ComputerName\\ActiveComputerName")
+#define RegVal TEXT("ComputerName")
+#define DmfPath TEXT("System\\CurrentControlSet\\Control\\Windows")
+#define DmfVal TEXT("DmfEnabled")
+
+#define MAX_DISK_SIZE_ALLOWED (3) // in Megabytes
+
+BOOLEAN
+GetWidget(
+ OUT PSID *Sid,
+ OUT PULONG SidLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine retrieves the sid of this machine's account
+ domain and returns it in memory allocated with MALLOC.
+ If this machine is a server in a domain, then this SID will
+ be domain's SID.
+
+
+Arguments:
+
+ Sid - receives a pointer to the returned SID.
+
+ SidLength - Receives the length (in bytes) of the returned SID.
+
+
+Return Value:
+
+ TRUE - The SID was allocated and returned.
+
+ FALSE - Some error prevented the SID from being returned.
+
+--*/
+
+{
+ NTSTATUS
+ Status;
+
+ OBJECT_ATTRIBUTES
+ ObjectAttributes;
+
+ LSA_HANDLE
+ PolicyHandle;
+
+ POLICY_ACCOUNT_DOMAIN_INFO
+ *DomainInfo = NULL;
+
+ PSID
+ ReturnSid;
+
+ BOOLEAN
+ ReturnStatus = FALSE;
+
+
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ NULL, // No name
+ 0, // No attributes
+ 0, // No root handle
+ NULL // No SecurityDescriptor
+ );
+
+ Status = LsaOpenPolicy( NULL, // Local System
+ &ObjectAttributes,
+ POLICY_VIEW_LOCAL_INFORMATION,
+ &PolicyHandle
+ );
+
+ if (NT_SUCCESS(Status)) {
+
+ Status = LsaQueryInformationPolicy(
+ PolicyHandle,
+ PolicyAccountDomainInformation,
+ (PVOID*) &DomainInfo
+ );
+
+ if (NT_SUCCESS(Status)) {
+
+ ASSERT(DomainInfo != NULL);
+
+ //
+ // Allocate the return buffer
+ //
+
+ (*SidLength) = RtlLengthSid( DomainInfo->DomainSid );
+ ReturnSid = MALLOC(*SidLength);
+
+ if (ReturnSid != NULL) {
+
+ //
+ // Copy the sid
+ //
+
+ RtlMoveMemory( ReturnSid, DomainInfo->DomainSid, (*SidLength) );
+ (*Sid) = ReturnSid;
+ ReturnStatus = TRUE;
+ }
+
+
+ LsaFreeMemory( DomainInfo );
+ }
+
+ Status = LsaClose( PolicyHandle );
+ ASSERT(NT_SUCCESS(Status));
+ }
+
+ return(ReturnStatus);
+}
+
+
+IFSUTIL_EXPORT
+ULONG
+QueryMachineUniqueToken(
+ )
+/*++
+
+Routine Description:
+
+ This routine will compute a unique 32-bit value for this machine.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ 0 - Failure.
+ A 32-bit value unique for this machine.
+
+--*/
+{
+ HKEY hKey;
+ int err;
+ WCHAR szMN[64];
+ DWORD dwType;
+ DWORD cbMN = 64 * sizeof(WCHAR);
+ MD4_CTX MD4Context;
+ DWORD Final;
+ DWORD * pDigest;
+ PSID sid;
+ ULONG sidLength;
+
+ err = RegOpenKey(HKEY_LOCAL_MACHINE, RegPath, &hKey);
+ if (err) {
+ return 0;
+ }
+
+ err = RegQueryValueEx(hKey, RegVal, NULL, &dwType, (PBYTE) szMN, &cbMN);
+ if (err) {
+ return 0;
+ }
+
+ RegCloseKey(hKey);
+
+ if (!GetWidget(&sid, &sidLength)) {
+ return 0;
+ }
+
+ MD4Init(&MD4Context);
+
+ MD4Update(&MD4Context, (PBYTE) szMN, cbMN);
+ MD4Update(&MD4Context, (PBYTE) sid, sidLength);
+
+ MD4Final(&MD4Context);
+ pDigest = (DWORD *) MD4Context.digest;
+
+ Final = pDigest[0] ^ pDigest[1] ^ pDigest[2] ^ pDigest[3];
+
+ FREE(sid);
+
+ return Final;
+}
+
+
+BOOLEAN
+TestTokenForAdmin(
+ )
+/*++
+
+Routine Description:
+
+ This routine checks if the current process token represents an admin
+ user.
+
+ Code taken from Winlogon.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - The current process does not represent an administrator.
+ TRUE - The current process represents an administrator.
+
+--*/
+{
+ NTSTATUS Status;
+ ULONG InfoLength;
+ PTOKEN_GROUPS TokenGroupList;
+ ULONG GroupIndex;
+ BOOL FoundAdmin;
+ HANDLE Token;
+ PSID gAdminSid;
+ SID_IDENTIFIER_AUTHORITY gSystemSidAuthority = SECURITY_NT_AUTHORITY;
+
+ Status = RtlAllocateAndInitializeSid(
+ &gSystemSidAuthority,
+ 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS,
+ 0, 0, 0, 0, 0, 0,
+ &gAdminSid
+ );
+
+ if (!NT_SUCCESS(Status)) {
+ return(FALSE);
+ }
+
+ Status = NtOpenProcessToken( NtCurrentProcess(), TOKEN_QUERY, &Token );
+
+ if (!NT_SUCCESS(Status)) {
+ return(FALSE);
+ }
+
+ //
+ // Get a list of groups in the token
+ //
+
+ Status = NtQueryInformationToken(
+ Token, // Handle
+ TokenGroups, // TokenInformationClass
+ NULL, // TokenInformation
+ 0, // TokenInformationLength
+ &InfoLength // ReturnLength
+ );
+
+ if ((Status != STATUS_SUCCESS) && (Status != STATUS_BUFFER_TOO_SMALL)) {
+
+ NtClose(Token);
+ return(FALSE);
+ }
+
+
+ TokenGroupList = (PTOKEN_GROUPS) MALLOC(InfoLength);
+
+ if (TokenGroupList == NULL) {
+ NtClose(Token);
+ return(FALSE);
+ }
+
+ Status = NtQueryInformationToken(
+ Token, // Handle
+ TokenGroups, // TokenInformationClass
+ TokenGroupList, // TokenInformation
+ InfoLength, // TokenInformationLength
+ &InfoLength // ReturnLength
+ );
+
+ if (!NT_SUCCESS(Status)) {
+ FREE(TokenGroupList);
+ NtClose(Token);
+ return(FALSE);
+ }
+
+
+ //
+ // Search group list for admin alias
+ //
+
+ FoundAdmin = FALSE;
+
+ for (GroupIndex=0; GroupIndex < TokenGroupList->GroupCount; GroupIndex++ ) {
+
+ if (RtlEqualSid(TokenGroupList->Groups[GroupIndex].Sid, gAdminSid)) {
+ FoundAdmin = TRUE;
+ break;
+ }
+ }
+
+ //
+ // Tidy up
+ //
+
+ FREE(TokenGroupList);
+
+ NtClose(Token);
+
+ return(FoundAdmin);
+}
+
+
+IFSUTIL_EXPORT
+INT
+DiskCopyMainLoop(
+ IN PCWSTRING SrcNtDriveName,
+ IN PCWSTRING DstNtDriveName,
+ IN PCWSTRING SrcDosDriveName,
+ IN PCWSTRING DstDosDriveName,
+ IN BOOLEAN Verify,
+ IN OUT PMESSAGE Message,
+ IN OUT PMESSAGE PercentMessage
+ )
+/*++
+
+Routine Description:
+
+ This routine copies on floppy diskette to another floppy diskette.
+
+Arguments:
+
+ SrcNtDriveName - Supplies the NT style drive name for the source.
+ DstNtDriveName - Supplies the NT style drive name for the destination.
+ SrcDosDriveName - Supplies the DOS style drive name for the source.
+ DstDosDriveName - Supplies the DOS style drive name for the destination.
+ Message - Supplies an outlet for messages.
+ PercentMessage - Supplies an outlet for percent complete messages.
+
+Return Value:
+
+ 0 - Success.
+ 1 - Io error occured.
+ > 1 - Error.
+
+--*/
+{
+ PLOG_IO_DP_DRIVE src_drive = NULL;
+ LOG_IO_DP_DRIVE dst_drive;
+ HMEM src_hmem;
+ HMEM dst_hmem;
+ CONT_MEM src_cmem;
+ PVOID mem_ptr;
+ SECRUN src_secrun;
+ SECRUN dst_secrun;
+ SECTORCOUNT sec_per_track;
+ ULONG total_tracks;
+ ULONG grab; // number of tracks to grab at once.
+ ULONG sector_size;
+ BOOLEAN one_drive;
+ ULONG src_top; // src track pointer -- next read
+ ULONG dst_top; // dst track pointer -- next write
+ ULONG src_volume_id, volume_id;
+ PCHAR pchar;
+ ULONG i;
+ PUSHORT pus;
+ ULONG heads;
+ DSTRING fsname;
+ BOOLEAN io_error;
+ ULONG percent_complete, newp;
+ DWORD OldErrorMode;
+ BOOLEAN dmf;
+ UCHAR saved_char;
+ BOOLEAN cancel;
+ BOOLEAN done = FALSE;
+ MSGID msg;
+ BIG_INT src_drive_Sectors;
+ BIG_INT src_drive_Tracks;
+ MEDIA_TYPE src_drive_MediaType;
+
+ one_drive = (*SrcDosDriveName == *DstDosDriveName);
+
+ if (!one_drive) {
+ Message->Set(MSG_DCOPY_INSERT_SOURCE_AND_TARGET);
+ Message->Display("%W%W", SrcDosDriveName, DstDosDriveName);
+ } else {
+ Message->Set(MSG_DCOPY_INSERT_SOURCE);
+ Message->Display("%W", SrcDosDriveName);
+ }
+
+ Message->Set(MSG_PRESS_ENTER_WHEN_READY);
+ Message->Display();
+ Message->WaitForUserSignal();
+
+
+ if (!(src_drive = NEW LOG_IO_DP_DRIVE) ||
+ !src_drive->Initialize(SrcNtDriveName)) {
+
+ // Verify that we can access the source drive:
+
+ if (src_drive->QueryLastNtStatus() == STATUS_ACCESS_DENIED) {
+ Message->Set(MSG_DASD_ACCESS_DENIED);
+ Message->Display();
+ DELETE(src_drive);
+ return 4;
+ }
+
+ Message->Set(MSG_DCOPY_BAD_SOURCE);
+ Message->Display();
+ DELETE(src_drive);
+ return 3;
+ }
+
+ if (!src_drive->IsFloppy()) {
+ Message->Set(MSG_DCOPY_INVALID_DRIVE);
+ Message->Display();
+ DELETE(src_drive);
+ return 4;
+ }
+
+ DebugPrintf("Try to lock source drive\n");
+ if (!src_drive->Lock()) {
+ Message->Set(MSG_CANT_LOCK_THE_DRIVE);
+ Message->Display("");
+ DELETE(src_drive);
+ return 3;
+ }
+ src_drive_Sectors = src_drive->QuerySectors();
+ src_drive_MediaType = src_drive->QueryMediaType();
+ src_drive_Tracks = src_drive->QueryTracks();
+
+ if (src_drive->QueryMediaType() == Unknown) {
+ Message->Set(MSG_DCOPY_BAD_SOURCE);
+ Message->Display();
+ DELETE(src_drive);
+ return 3;
+ }
+
+ if (src_drive->QueryMediaType() == F3_1Pt44_512 &&
+ src_drive->QuerySectorsPerTrack() != 18) {
+
+ if (!src_hmem.Initialize() ||
+ !src_secrun.Initialize(&src_hmem, src_drive, 0, 1) ||
+ !src_secrun.Read()) {
+
+ Message->Set(MSG_DCOPY_BAD_SOURCE);
+ Message->Display();
+ DELETE(src_drive);
+ return 3;
+ }
+
+ if (src_drive->QuerySectorsPerTrack() != 21 ||
+ memcmp(((PUCHAR) src_secrun.GetBuf()) + 3, "MSDMF3.2", 8)) {
+
+ Message->Set(MSG_DCOPY_UNRECOGNIZED_FORMAT);
+ Message->Display();
+ DELETE(src_drive);
+ return 3;
+ }
+
+
+ {
+ HKEY hKey;
+ int err;
+ DWORD dwType;
+ DWORD JimsBigNumber, machineToken;
+ MD4_CTX MD4Context;
+ DWORD Final;
+ DWORD * pDigest;
+ DWORD regFinal;
+ DWORD regFinalSize = sizeof(DWORD);
+
+ JimsBigNumber = JIMS_BIG_NUMBER;
+
+ machineToken = QueryMachineUniqueToken();
+
+ MD4Init(&MD4Context);
+
+ MD4Update(&MD4Context, (PBYTE) &machineToken, sizeof(DWORD));
+ MD4Update(&MD4Context, (PBYTE) &JimsBigNumber, sizeof(DWORD));
+
+ MD4Final(&MD4Context);
+ pDigest = (DWORD *) MD4Context.digest;
+
+ Final = pDigest[0] ^ pDigest[1] ^ pDigest[2] ^ pDigest[3];
+
+
+ //
+ // Reserve the upper two bits for VERSIONing.
+ // This is version 0.0
+ //
+
+ Final &= 0x3FFFFFFF;
+
+
+ err = RegOpenKey(HKEY_LOCAL_MACHINE, DmfPath, &hKey);
+ if (err) {
+ Message->Set(MSG_DCOPY_UNRECOGNIZED_FORMAT);
+ Message->Display();
+ DELETE(src_drive);
+ return 3;
+ }
+
+ err = RegQueryValueEx(hKey, DmfVal, NULL, &dwType, (PBYTE) &regFinal,
+ &regFinalSize);
+ if (err || regFinalSize != sizeof(DWORD)) {
+ Message->Set(MSG_DCOPY_UNRECOGNIZED_FORMAT);
+ Message->Display();
+ DELETE(src_drive);
+ return 3;
+ }
+
+ RegCloseKey(hKey);
+
+ if (regFinal != Final) {
+ Message->Set(MSG_DCOPY_UNRECOGNIZED_FORMAT);
+ Message->Display();
+ DELETE(src_drive);
+ return 3;
+ }
+ }
+
+
+ dmf = TRUE;
+ Verify = TRUE;
+
+ if (!TestTokenForAdmin()) {
+ Message->Set(MSG_DCOPY_NOT_ADMINISTRATOR);
+ Message->Display();
+ DELETE(src_drive);
+ return 3;
+ }
+
+ if (src_drive->IsSupported(F3_2Pt88_512)) {
+ Message->Set(MSG_FMT_DMF_NOT_SUPPORTED_ON_288_DRIVES);
+ Message->Display();
+ DELETE(src_drive);
+ return 3;
+ }
+
+ } else {
+ dmf = FALSE;
+ }
+
+ // If there is more than one drive then open the second
+ // one right away to determine if it's compatible or not.
+
+ if (!one_drive) {
+
+ // Disable popups while we determine the drive type.
+ OldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS );
+
+ if (!dst_drive.Initialize(DstNtDriveName)) {
+
+ // Restore the error mode.
+ SetErrorMode( OldErrorMode );
+
+ // Verify that we can access the destination drive:
+
+ if (dst_drive.QueryLastNtStatus() == STATUS_ACCESS_DENIED) {
+ Message->Set(MSG_DASD_ACCESS_DENIED);
+ Message->Display();
+ DELETE(src_drive);
+ return 4;
+ }
+
+ Message->Set(MSG_DCOPY_BAD_DEST);
+ Message->Display();
+ DELETE(src_drive);
+ return 3;
+ }
+
+ // Restore the error mode.
+ SetErrorMode( OldErrorMode );
+
+ DebugPrintf("Try to lock destination drive\n");
+ if (!dst_drive.Lock()) {
+ Message->Set(MSG_CANT_LOCK_THE_DRIVE);
+ Message->Display("");
+ DELETE(src_drive);
+ return 4;
+ }
+
+ // Make sure that the destination floppy will support the same media
+ // as the source floppy.
+
+ if (!dst_drive.IsSupported(src_drive->QueryMediaType())) {
+ Message->Set(MSG_DCOPY_BAD_DEST);
+ Message->Display();
+ DELETE(src_drive);
+ return 4;
+ }
+ }
+
+ sec_per_track = src_drive->QuerySectorsPerTrack();
+ sector_size = src_drive->QuerySectorSize();
+ total_tracks = src_drive->QueryTracks().GetLowPart();
+ heads = src_drive->QueryHeads();
+
+ if (total_tracks*sec_per_track*sector_size >
+ MAX_DISK_SIZE_ALLOWED*1024*1024) {
+ Message->Set(MSG_DCOPY_DISK_TOO_LARGE);
+ Message->Display("%d", MAX_DISK_SIZE_ALLOWED);
+ DELETE(src_drive);
+ return 3;
+ }
+
+ Message->Set(MSG_DCOPY_COPYING);
+ Message->Display("%d%d%d", src_drive->QueryCylinders().GetLowPart(),
+ sec_per_track,
+ heads);
+
+ DebugAssert(src_drive->QuerySectors().GetHighPart() == 0);
+
+ if (!dst_hmem.Initialize()) {
+ DELETE(src_drive);
+ return 4;
+ }
+
+ io_error = FALSE;
+
+ percent_complete = 0;
+ if (PercentMessage) {
+ PercentMessage->Set(MSG_PERCENT_COMPLETE);
+ if (!PercentMessage->Display("%d", 0)) {
+ DELETE(src_drive);
+ return 4;
+ }
+ }
+
+ for (src_top = dst_top = 0; dst_top < total_tracks; dst_top++) {
+
+ if (src_top == dst_top) {
+
+ if (src_top && one_drive) {
+
+ // Gets here because diskcopy is doing multiple passes
+
+ ASSERT(FALSE); // shouldn't get here anymore
+
+ DebugPrintf("Try to unlock destination drive\n");
+ if (!dst_drive.Unlock()) {
+ Message->Set(MSG_CANT_UNLOCK_THE_DRIVE);
+ Message->Display("");
+ DELETE(src_drive);
+ return 3;
+ }
+
+ Message->Set(MSG_DCOPY_INSERT_SOURCE);
+ Message->Display("%W", SrcDosDriveName);
+ Message->Set(MSG_PRESS_ENTER_WHEN_READY);
+ Message->Display();
+ Message->WaitForUserSignal();
+
+ DebugPrintf("Try to lock source drive\n");
+ if (!src_drive->Lock()) {
+ Message->Set(MSG_CANT_LOCK_THE_DRIVE);
+ Message->Display("");
+ DELETE(src_drive);
+ return 3;
+ }
+ }
+
+
+ // Allocate memory for read.
+ for (grab = total_tracks - src_top;
+ !src_hmem.Initialize() ||
+ !(mem_ptr = src_hmem.Acquire(grab*sector_size*sec_per_track,
+ src_drive->QueryAlignmentMask()));
+ grab /= 2) {
+
+// if (grab < 2) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ DELETE(src_drive);
+ return 4;
+// }
+ }
+
+ if (!src_cmem.Initialize(mem_ptr, grab*sector_size*sec_per_track)) {
+ DELETE(src_drive);
+ return 4;
+ }
+
+
+ // Read the source, track by track.
+
+ for (i = 0; i < grab; i++) {
+ if (!src_secrun.Initialize(&src_cmem, src_drive,
+ src_top*sec_per_track,
+ sec_per_track)) {
+ DELETE(src_drive);
+ return 4;
+ }
+
+ ReadAgain:
+
+ if (!src_secrun.Read()) {
+
+ if (src_drive->QueryLastNtStatus() == STATUS_NO_MEDIA_IN_DEVICE ||
+ src_drive->QueryLastNtStatus() == STATUS_UNRECOGNIZED_MEDIA) {
+ if (src_drive->QueryLastNtStatus() == STATUS_NO_MEDIA_IN_DEVICE)
+ msg = MSG_DCOPY_NO_MEDIA_IN_DEVICE;
+ else
+ msg = MSG_DCOPY_UNRECOGNIZED_MEDIA;
+ Message->Set(msg, NORMAL_MESSAGE, GUI_MESSAGE);
+ cancel = Message->Display("%W", SrcDosDriveName);
+ if (!cancel) // if not cancel that means the user want to retry
+ goto ReadAgain;
+ DELETE(src_drive);
+ return 3;
+ }
+
+ Message->Set(MSG_DCOPY_READ_ERROR);
+ Message->Display("%W%d%d", SrcDosDriveName,
+ src_top%heads, src_top/heads);
+ io_error = TRUE;
+ }
+
+ src_top++;
+
+ newp = (100*(src_top + dst_top)/
+ (2*src_drive->QueryTracks())).GetLowPart();
+ if (newp != percent_complete && PercentMessage) {
+ PercentMessage->Set(MSG_PERCENT_COMPLETE);
+ if (!PercentMessage->Display("%d", newp)) {
+ DELETE(src_drive);
+ return 4;
+ }
+ }
+ percent_complete = newp;
+ }
+
+ if (!src_cmem.Initialize(mem_ptr, grab*sector_size*sec_per_track)) {
+ DELETE(src_drive);
+ return 4;
+ }
+
+ if (one_drive) {
+
+ DebugPrintf("Try to unlock source drive\n");
+ if (!src_drive->Unlock()) {
+ Message->Set(MSG_CANT_UNLOCK_THE_DRIVE);
+ Message->Display("");
+ DELETE(src_drive);
+ return 4;
+ } else {
+ DELETE(src_drive);
+ src_drive = NULL;
+ }
+
+ Message->Set(MSG_DCOPY_INSERT_TARGET);
+ Message->Display("%W", DstDosDriveName);
+ Message->Set(MSG_PRESS_ENTER_WHEN_READY);
+ Message->Display();
+ Message->WaitForUserSignal();
+
+ if (dst_top) DebugPrintf("Try to lock destination drive\n");
+ if (dst_top && !dst_drive.Lock()) {
+ Message->Set(MSG_CANT_LOCK_THE_DRIVE);
+ Message->Display("");
+ DELETE(src_drive);
+ return 3;
+ }
+
+ }
+
+ if (!dst_top) { // first time
+
+ DstInitializeAgain:
+
+ // Disable popups while we determine the drive type.
+ OldErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS );
+
+ if (!dst_drive.Initialize(DstNtDriveName)) {
+
+ // Restore the error mode.
+ SetErrorMode( OldErrorMode );
+
+ // Verify that we can access the destination drive:
+
+ if (dst_drive.QueryLastNtStatus() == STATUS_ACCESS_DENIED) {
+ Message->Set(MSG_DASD_ACCESS_DENIED);
+ Message->Display();
+ DELETE(src_drive);
+ return 4;
+ }
+
+ if (dst_drive.QueryLastNtStatus() == STATUS_NO_MEDIA_IN_DEVICE ||
+ dst_drive.QueryLastNtStatus() == STATUS_UNRECOGNIZED_MEDIA) {
+ if (dst_drive.QueryLastNtStatus() == STATUS_NO_MEDIA_IN_DEVICE)
+ msg = MSG_DCOPY_NO_MEDIA_IN_DEVICE;
+ else
+ msg = MSG_DCOPY_UNRECOGNIZED_MEDIA;
+ Message->Set(msg, NORMAL_MESSAGE, GUI_MESSAGE);
+ cancel = Message->Display("%W", DstDosDriveName);
+ if (!cancel) // if not cancel that means the user want to retry
+ goto DstInitializeAgain;
+ }
+
+ Message->Set(MSG_DCOPY_BAD_DEST);
+ Message->Display();
+ DELETE(src_drive);
+ return 3;
+ }
+
+ // Restore the error mode.
+ SetErrorMode( OldErrorMode );
+
+ // Only try to lock the drive if the source disk has
+ // a serial number. Don't lock if the source and
+ // destination drive name are the same (since they
+ // may have the same serial number).
+ // If the target is DMF, don't write protect it until
+ // we're done with it.
+
+ if (dmf) {
+ saved_char = ((PUCHAR) mem_ptr)[3];
+ ((PUCHAR) mem_ptr)[3] = 'X';
+ }
+
+ if (((PUCHAR) mem_ptr)[0x26] == 0x28 ||
+ ((PUCHAR) mem_ptr)[0x26] == 0x29) {
+
+ memcpy(&src_volume_id, (PCHAR) mem_ptr + 0x27,
+ sizeof(ULONG));
+ } else {
+ src_volume_id = 0;
+ }
+
+ DebugPrintf("Try to lock destination drive\n");
+ if (!dst_drive.Lock()) {
+ Message->Set(MSG_CANT_LOCK_THE_DRIVE);
+ Message->Display("");
+ DELETE(src_drive);
+ return 3;
+ }
+
+ // Only format the target if it isn't formatted.
+ // If it is formatted then it must be of the same
+ // media type.
+
+ if (dst_drive.QueryMediaType() == Unknown ||
+ (dst_drive.QueryMediaType() == src_drive_MediaType &&
+ (dmf || dst_drive.QuerySectors() != src_drive_Sectors))) {
+
+ if (!dst_drive.IsSupported(src_drive_MediaType)) {
+ Message->Set(MSG_DCOPY_BAD_DEST);
+ Message->Display();
+ DELETE(src_drive);
+ return 4;
+ }
+
+ Message->Set(MSG_DCOPY_FORMATTING_WHILE_COPYING);
+ Message->Display();
+
+ if (!dst_drive.FormatVerifyFloppy(
+ src_drive_MediaType, NULL, NULL, dmf)) {
+
+ Message->Set(MSG_DCOPY_BAD_DEST);
+ Message->Display("");
+ DELETE(src_drive);
+ return 3;
+ }
+ } else if (dst_drive.QueryMediaType() !=
+ src_drive_MediaType) {
+
+ dst_drive.Unlock();
+ Message->Set(MSG_DCOPY_NON_COMPAT_DISKS);
+ cancel = Message->Display();
+ if (!cancel)
+ goto DstInitializeAgain;
+ DELETE(src_drive);
+ return 4;
+ }
+ }
+ }
+
+ FinalWrite:
+
+ if (!dst_secrun.Initialize(&src_cmem, &dst_drive,
+ dst_top*sec_per_track, sec_per_track)) {
+ DELETE(src_drive);
+ return 4;
+ }
+
+ if (!dst_top && !done) {
+ if (src_volume_id) {
+
+ while (!(volume_id = SUPERAREA::ComputeVolId())) {
+ }
+
+ pchar = (PCHAR) dst_secrun.GetBuf();
+ memcpy(pchar + 0x27, &volume_id, sizeof(ULONG));
+ }
+ continue;
+ }
+
+ WriteAgain:
+
+ if (!dst_secrun.Write()) {
+
+ if (dst_drive.QueryLastNtStatus() == STATUS_MEDIA_WRITE_PROTECTED ||
+ dst_drive.QueryLastNtStatus() == STATUS_NO_MEDIA_IN_DEVICE ||
+ dst_drive.QueryLastNtStatus() == STATUS_UNRECOGNIZED_MEDIA) {
+ if (dst_drive.QueryLastNtStatus() == STATUS_NO_MEDIA_IN_DEVICE)
+ msg = MSG_DCOPY_NO_MEDIA_IN_DEVICE;
+ else if (dst_drive.QueryLastNtStatus() == STATUS_UNRECOGNIZED_MEDIA)
+ msg = MSG_DCOPY_UNRECOGNIZED_MEDIA;
+ else {
+ msg = MSG_DCOPY_MEDIA_WRITE_PROTECTED;
+ // Assuming this is the first write. That means the user has
+ // to either unprotect the disk or put in a different disk.
+ // If the user puts in a different disk, we will have to start
+ // over again. That's why we should unlock first.
+ dst_drive.Unlock();
+ }
+ Message->Set(msg, NORMAL_MESSAGE, GUI_MESSAGE);
+ cancel = Message->Display("%W", DstDosDriveName);
+ if (!cancel) // if not cancel that means the user want to retry
+ if (msg == MSG_DCOPY_MEDIA_WRITE_PROTECTED) {
+ if (!src_cmem.Initialize(mem_ptr, grab*sector_size*sec_per_track)) {
+ DELETE(src_drive);
+ return 4;
+ }
+ done = FALSE;
+ dst_top = 0;
+ goto DstInitializeAgain;
+ } else
+ goto WriteAgain;
+ DELETE(src_drive);
+ return 3;
+ }
+
+ Message->Set(MSG_DCOPY_WRITE_ERROR);
+ Message->Display("%W%d%d", DstDosDriveName,
+ dst_top%heads, dst_top/heads);
+
+ io_error = TRUE;
+
+ } else if (Verify) {
+ pchar = (PCHAR) dst_secrun.GetBuf();
+
+ if (!dst_secrun.Initialize(&dst_hmem, &dst_drive,
+ dst_top*sec_per_track, sec_per_track)) {
+ DELETE(src_drive);
+ return 4;
+ }
+
+ VerifyReadAgain:
+
+ if (!dst_secrun.Read() ||
+ memcmp(dst_secrun.GetBuf(), pchar,
+ (UINT) (sec_per_track*sector_size))) {
+
+ if (dst_drive.QueryLastNtStatus() == STATUS_NO_MEDIA_IN_DEVICE ||
+ dst_drive.QueryLastNtStatus() == STATUS_UNRECOGNIZED_MEDIA) {
+ if (dst_drive.QueryLastNtStatus() == STATUS_NO_MEDIA_IN_DEVICE)
+ msg = MSG_DCOPY_NO_MEDIA_IN_DEVICE;
+ else
+ msg = MSG_DCOPY_UNRECOGNIZED_MEDIA;
+ Message->Set(msg, NORMAL_MESSAGE, GUI_MESSAGE);
+ cancel = Message->Display("%W", DstDosDriveName);
+ if (!cancel) // if not cancel that means the user want to retry
+ goto VerifyReadAgain;
+ DELETE(src_drive);
+ return 3;
+ }
+
+ Message->Set(MSG_DCOPY_WRITE_ERROR);
+ Message->Display("%W%d%d", DstDosDriveName,
+ dst_top%heads, dst_top/heads);
+
+ io_error = TRUE;
+ }
+ }
+
+ if (dst_top == total_tracks-1) {
+ dst_top = 0;
+ done = TRUE;
+ if (!src_cmem.Initialize(mem_ptr, grab*sector_size*sec_per_track)) {
+ DELETE(src_drive);
+ return 4;
+ }
+ goto FinalWrite;
+ }
+
+ if (done)
+ dst_top = total_tracks;
+
+ newp = (100*(src_top + dst_top-1)/
+ (2*src_drive_Tracks)).GetLowPart();
+ if (newp != percent_complete && PercentMessage) {
+ PercentMessage->Set(MSG_PERCENT_COMPLETE);
+ if (!PercentMessage->Display("%d", newp)) {
+ DELETE(src_drive);
+ return 4;
+ }
+ }
+ percent_complete = newp;
+ }
+
+ DELETE(src_drive);
+
+ // If this is DMF then write-protect the target floppy.
+
+ if (dmf) {
+ if (!dst_hmem.Initialize() ||
+ !dst_secrun.Initialize(&dst_hmem, &dst_drive, 0, 1) ||
+ !dst_secrun.Read() ||
+ (((PUCHAR) dst_secrun.GetBuf())[3] = saved_char) != saved_char ||
+ !dst_secrun.Write()) {
+
+ Message->Set(MSG_DCOPY_WRITE_ERROR);
+ Message->Display("%W%d%d", DstDosDriveName, 0, 0);
+ io_error = TRUE;
+ }
+ }
+
+ if (src_volume_id) {
+ pus = (PUSHORT) &volume_id;
+ Message->Set(MSG_VOLUME_SERIAL_NUMBER);
+ Message->Display("%04X%04X", pus[1], pus[0]);
+ }
+
+ // In that we didn't lock the
+ // volume previously. We need to do this so
+ // that the file system will do a verify and
+ // thus be able to see the new label if any.
+ // We shouldn't fail if we can't do this though.
+
+ DebugPrintf("Try to lock destination drive\n");
+ dst_drive.Lock();
+
+ return io_error ? 1 : 0;
+}
diff --git a/private/utils/ifsutil/src/numset.cxx b/private/utils/ifsutil/src/numset.cxx
new file mode 100644
index 000000000..fbd66fddb
--- /dev/null
+++ b/private/utils/ifsutil/src/numset.cxx
@@ -0,0 +1,1076 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _IFSUTIL_MEMBER_
+
+#include "ulib.hxx"
+#include "ifsutil.hxx"
+
+#include "numset.hxx"
+#include "iterator.hxx"
+
+DEFINE_EXPORTED_CONSTRUCTOR( NUMBER_SET, OBJECT, IFSUTIL_EXPORT );
+
+DEFINE_CONSTRUCTOR( NUMBER_EXTENT, OBJECT );
+
+VOID
+NUMBER_SET::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Constructor for NUMBER_SET.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _card = 0;
+ _iterator = NULL;
+}
+
+
+VOID
+NUMBER_SET::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the NUMBER_SET to its initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _list.DeleteAllMembers();
+ _card = 0;
+ DELETE(_iterator);
+}
+
+
+IFSUTIL_EXPORT
+NUMBER_SET::~NUMBER_SET(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for NUMBER_SET.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+NUMBER_SET::Initialize(
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the stack for new input.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ Destroy();
+
+ if (!_list.Initialize() ||
+ !(_iterator = _list.QueryIterator())) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+IFSUTIL_EXPORT
+BOOLEAN
+NUMBER_SET::Add(
+ IN BIG_INT Number
+ )
+/*++
+
+Routine Description:
+
+ This routine adds 'Number' to the set.
+
+Arguments:
+
+ Number - Supplies the number to add to the set.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PNUMBER_EXTENT p, pn;
+ PNUMBER_EXTENT new_extent;
+ BIG_INT next;
+
+ DebugAssert(_iterator);
+
+ _iterator->Reset();
+ while (p = (PNUMBER_EXTENT) _iterator->GetPrevious()) {
+ if (p->Start <= Number) {
+ break;
+ }
+ }
+
+ if (p) {
+
+ next = p->Start + p->Length;
+
+ if (Number < next) {
+ return TRUE;
+ }
+
+ if (Number == next) {
+
+ p->Length += 1;
+ _card += 1;
+
+ if (pn = (PNUMBER_EXTENT) _iterator->GetNext()) {
+
+ if (pn->Start == Number + 1) {
+
+ p->Length += pn->Length;
+ pn = (PNUMBER_EXTENT) _list.Remove(_iterator);
+ DELETE(pn);
+ }
+ }
+
+ return TRUE;
+ }
+ }
+
+ if (p = (PNUMBER_EXTENT) _iterator->GetNext()) {
+
+ if (Number + 1 == p->Start) {
+
+ p->Start = Number;
+ p->Length += 1;
+ _card += 1;
+ return TRUE;
+ }
+ }
+
+ if (!(new_extent = NEW NUMBER_EXTENT)) {
+ return FALSE;
+ }
+
+ new_extent->Start = Number;
+ new_extent->Length = 1;
+
+ if (!_list.Insert(new_extent, _iterator)) {
+ DELETE(new_extent);
+ return FALSE;
+ }
+
+ _card += 1;
+
+ return TRUE;
+}
+
+IFSUTIL_EXPORT
+BOOLEAN
+NUMBER_SET::AddStart(
+ IN BIG_INT Number
+ )
+/*++
+
+Routine Description:
+
+ This routine adds 'Number' to the set. Call this routine once before calling
+ AddNext.
+
+ NOTE: Do not insert other calls of this class in between AddStart and AddNext.
+
+Arguments:
+
+ Number - Supplies the number to add to the set.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PNUMBER_EXTENT p, pn;
+ PNUMBER_EXTENT new_extent;
+ BIG_INT next;
+
+ DebugAssert(_iterator);
+
+ _iterator->Reset();
+ p = (PNUMBER_EXTENT) _iterator->GetPrevious();
+
+ while (p != NULL) {
+ if (p->Start <= Number) {
+ next = p->Start + p->Length;
+
+ // if within range, then done
+ if (Number < next)
+ return TRUE;
+
+ // if passed the range by 1, try to expand the range to include it
+ if (Number == next) {
+ p->Length += 1;
+ _card += 1;
+ // see if the next range can be merged with the expanded range
+ if (pn = (PNUMBER_EXTENT) _iterator->GetNext()) {
+ if (pn->Start == Number + 1) {
+ p->Length += pn->Length;
+ pn = (PNUMBER_EXTENT) _list.Remove(_iterator);
+ DELETE(pn);
+ }
+ }
+ p = (PNUMBER_EXTENT)_iterator->GetPrevious();
+ return TRUE;
+ }
+
+ // if less than the next range by 1, try to expand the range to
+ // include it. There won't be a merge as there must be more than
+ // one hole in between the two ranges
+ if (p = (PNUMBER_EXTENT) _iterator->GetNext()) {
+ if (p->Start <= Number)
+ continue;
+ if ((Number+1) == p->Start) {
+ p->Start = Number;
+ p->Length += 1;
+ _card += 1;
+ return TRUE;
+ }
+ }
+ break;
+ } else {
+ // search backwards
+ p = (PNUMBER_EXTENT) _iterator->GetPrevious();
+ if (p == NULL) {
+ p = (PNUMBER_EXTENT) _iterator->GetNext();
+ DebugAssert(p);
+ if (p && ((Number+1) == p->Start)) {
+ p->Start = Number;
+ p->Length += 1;
+ _card += 1;
+ return TRUE;
+ }
+ break;
+ }
+ }
+ }
+
+ if (!(new_extent = NEW NUMBER_EXTENT)) {
+ return FALSE;
+ }
+
+ new_extent->Start = Number;
+ new_extent->Length = 1;
+
+ if (!_list.Insert(new_extent, _iterator)) {
+ DELETE(new_extent);
+ return FALSE;
+ }
+
+ _card += 1;
+
+ p = (PNUMBER_EXTENT) _iterator->GetPrevious();
+
+ return TRUE;
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+NUMBER_SET::AddNext(
+ IN BIG_INT Number
+ )
+/*++
+
+Routine Description:
+
+ This routine adds 'Number' to the set. Call this routine after calling
+ AddStart once. This routine differs from Add ni the sense that it searches
+ through each of the subset from where it last added instead of starting
+ backwards like Add does.
+
+ NOTE: Do not insert any other call of this class in between two AddNext calls.
+
+Arguments:
+
+ Number - Supplies the number to add to the set.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PNUMBER_EXTENT p, pn;
+ PNUMBER_EXTENT new_extent;
+ BIG_INT next;
+
+ DebugAssert(_iterator);
+
+ if (!(p = (PNUMBER_EXTENT) _iterator->GetCurrent())) {
+ _iterator->Reset();
+ p = (PNUMBER_EXTENT) _iterator->GetPrevious();
+ }
+
+ while (p != NULL) {
+ if (p->Start <= Number) {
+ next = p->Start + p->Length;
+
+ // if within range, then done
+ if (Number < next)
+ return TRUE;
+
+ // if passed the range by 1, try to expand the range to include it
+ if (Number == next) {
+ p->Length += 1;
+ _card += 1;
+ // see if the next range can be merged with the expanded range
+ if (pn = (PNUMBER_EXTENT) _iterator->GetNext()) {
+ if (pn->Start == Number + 1) {
+ p->Length += pn->Length;
+ pn = (PNUMBER_EXTENT) _list.Remove(_iterator);
+ DELETE(pn);
+ }
+ }
+ p = (PNUMBER_EXTENT)_iterator->GetPrevious();
+ return TRUE;
+ }
+
+ // if less than the next range by 1, try to expand the range to
+ // include it. There won't be a merge as there must be more than
+ // one hole in between the two ranges
+ if (p = (PNUMBER_EXTENT) _iterator->GetNext()) {
+ if (p->Start <= Number)
+ continue;
+ if ((Number+1) == p->Start) {
+ p->Start = Number;
+ p->Length += 1;
+ _card += 1;
+ return TRUE;
+ }
+ }
+ break;
+ } else {
+ // search backwards
+ p = (PNUMBER_EXTENT) _iterator->GetPrevious();
+ if (p == NULL) {
+ p = (PNUMBER_EXTENT) _iterator->GetNext();
+ DebugAssert(p);
+ if (p && ((Number+1) == p->Start)) {
+ p->Start = Number;
+ p->Length += 1;
+ _card += 1;
+ return TRUE;
+ }
+ break;
+ }
+ }
+ }
+
+ if (!(new_extent = NEW NUMBER_EXTENT)) {
+ return FALSE;
+ }
+
+ new_extent->Start = Number;
+ new_extent->Length = 1;
+
+ if (!_list.Insert(new_extent, _iterator)) {
+ DELETE(new_extent);
+ return FALSE;
+ }
+
+ _card += 1;
+
+ p = (PNUMBER_EXTENT) _iterator->GetPrevious();
+
+ return TRUE;
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+NUMBER_SET::Add(
+ IN BIG_INT Start,
+ IN BIG_INT Length
+ )
+/*++
+
+Routine Description:
+
+ This routine adds the range of numbers to the set.
+
+Arguments:
+
+ Start - Supplies the first number to add to the set.
+ Length - Supplies the length of the run to add.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ BIG_INT i, sup;
+ BOOLEAN r;
+
+ sup = Start + Length;
+
+ r = TRUE;
+ for (i = Start; i < sup; i += 1) {
+ r = Add(i) && r;
+ }
+
+ return r;
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+NUMBER_SET::Add(
+ IN PCNUMBER_SET NumberSet
+ )
+/*++
+
+Routine Description:
+
+ This routine adds all of the elements in the given number set to
+ this one.
+
+Arguments:
+
+ NumberSet - Supplies the numbers to add.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG i, n;
+ BIG_INT s, l;
+
+ n = NumberSet->QueryNumDisjointRanges();
+
+ for (i = 0; i < n; i++) {
+
+ NumberSet->QueryDisjointRange(i, &s, &l);
+
+ if (!Add(s, l)) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+IFSUTIL_EXPORT
+BOOLEAN
+NUMBER_SET::CheckAndAdd(
+ IN BIG_INT Number,
+ OUT PBOOLEAN Duplicate
+ )
+/*++
+
+Routine Description:
+
+ This routine adds 'Number' to the set.
+
+Arguments:
+
+ Number - Supplies the number to add to the set.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PNUMBER_EXTENT p, pn;
+ PNUMBER_EXTENT new_extent;
+ BIG_INT next;
+
+ DebugAssert(_iterator);
+ DebugAssert(Duplicate);
+
+ *Duplicate = FALSE;
+
+ _iterator->Reset();
+ while (p = (PNUMBER_EXTENT) _iterator->GetPrevious()) {
+ if (p->Start <= Number) {
+ break;
+ }
+ }
+
+ if (p) {
+
+ next = p->Start + p->Length;
+
+ if (Number < next) {
+ *Duplicate = TRUE;
+ return TRUE;
+ }
+
+ if (Number == next) {
+
+ p->Length += 1;
+ _card += 1;
+
+ if (pn = (PNUMBER_EXTENT) _iterator->GetNext()) {
+
+ if (pn->Start == Number + 1) {
+
+ p->Length += pn->Length;
+ pn = (PNUMBER_EXTENT) _list.Remove(_iterator);
+ DELETE(pn);
+ }
+ }
+
+ return TRUE;
+ }
+ }
+
+ if (p = (PNUMBER_EXTENT) _iterator->GetNext()) {
+
+ if (Number + 1 == p->Start) {
+
+ p->Start = Number;
+ p->Length += 1;
+ _card += 1;
+ return TRUE;
+ }
+ }
+
+ if (!(new_extent = NEW NUMBER_EXTENT)) {
+ return FALSE;
+ }
+
+ new_extent->Start = Number;
+ new_extent->Length = 1;
+
+ if (!_list.Insert(new_extent, _iterator)) {
+ DELETE(new_extent);
+ return FALSE;
+ }
+
+ _card += 1;
+
+ return TRUE;
+}
+
+IFSUTIL_EXPORT
+BOOLEAN
+NUMBER_SET::Remove(
+ IN BIG_INT Number
+ )
+/*++
+
+Routine Description:
+
+ This routine removes a number from the number set.
+
+Arguments:
+
+ Number - Supplies the number to remove.
+
+Routine Description:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PNUMBER_EXTENT p;
+ PNUMBER_EXTENT new_extent;
+ BIG_INT next, new_length;
+
+ DebugAssert(_iterator);
+
+ _iterator->Reset();
+ while (p = (PNUMBER_EXTENT) _iterator->GetNext()) {
+ if (p->Start > Number) {
+ break;
+ }
+ }
+
+ if (p = (PNUMBER_EXTENT) _iterator->GetPrevious()) {
+
+ next = p->Start + p->Length;
+
+ if (p->Start == Number) {
+ p->Start += 1;
+ p->Length -= 1;
+ _card -= 1;
+
+ if (p->Length == 0) {
+ p = (PNUMBER_EXTENT) _list.Remove(_iterator);
+ DELETE(p);
+ }
+
+ return TRUE;
+ }
+
+ if (Number + 1 == next) {
+ p->Length -= 1;
+ _card -= 1;
+ return TRUE;
+ }
+
+ if (Number < next) {
+
+ if (!(new_extent = NEW NUMBER_EXTENT)) {
+ return FALSE;
+ }
+
+ _iterator->GetNext();
+
+ if (!_list.Insert(new_extent, _iterator)) {
+ DELETE(new_extent);
+ return FALSE;
+ }
+
+ new_length = Number - p->Start;
+
+ new_extent->Start = Number + 1;
+ new_extent->Length = p->Length - 1 - new_length;
+
+ p->Length = new_length;
+
+ _card -= 1;
+ }
+ }
+
+ return TRUE;
+}
+
+IFSUTIL_EXPORT
+BOOLEAN
+NUMBER_SET::RemoveAll(
+ )
+{
+ PNUMBER_EXTENT p;
+
+ DebugAssert(_iterator);
+
+ _iterator->Reset();
+ if ((p = (PNUMBER_EXTENT) _iterator->GetNext()))
+ do {
+ p = (PNUMBER_EXTENT) _list.Remove(_iterator);
+ DELETE(p);
+ } while ((p=(PNUMBER_EXTENT)_iterator->GetCurrent()));
+ _card = 0;
+ return TRUE;
+}
+
+IFSUTIL_EXPORT
+BOOLEAN
+NUMBER_SET::CheckAndRemove(
+ IN BIG_INT Number,
+ OUT PBOOLEAN DoesExists
+ )
+/*++
+
+Routine Description:
+
+ This routine removes a number from the number set.
+
+Arguments:
+
+ Number - Supplies the number to remove.
+ DoesExists - TRUE if Number was found in the set
+
+Routine Description:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PNUMBER_EXTENT p;
+ PNUMBER_EXTENT new_extent;
+ BIG_INT next, new_length;
+
+ DebugAssert(_iterator);
+ DebugAssert(DoesExists);
+
+ *DoesExists = FALSE;
+
+ _iterator->Reset();
+ while (p = (PNUMBER_EXTENT) _iterator->GetNext()) {
+ if (p->Start > Number) {
+ break;
+ }
+ }
+
+ if (p = (PNUMBER_EXTENT) _iterator->GetPrevious()) {
+
+ next = p->Start + p->Length;
+
+ if (p->Start == Number) {
+ p->Start += 1;
+ p->Length -= 1;
+ _card -= 1;
+ *DoesExists = TRUE;
+
+ if (p->Length == 0) {
+ p = (PNUMBER_EXTENT) _list.Remove(_iterator);
+ DELETE(p);
+ }
+
+ return TRUE;
+ }
+
+ if (Number + 1 == next) {
+ p->Length -= 1;
+ _card -= 1;
+ *DoesExists = TRUE;
+ return TRUE;
+ }
+
+ if (Number < next) {
+
+ if (!(new_extent = NEW NUMBER_EXTENT)) {
+ return FALSE;
+ }
+
+ _iterator->GetNext();
+
+ if (!_list.Insert(new_extent, _iterator)) {
+ DELETE(new_extent);
+ return FALSE;
+ }
+
+ new_length = Number - p->Start;
+
+ new_extent->Start = Number + 1;
+ new_extent->Length = p->Length - 1 - new_length;
+
+ p->Length = new_length;
+
+ _card -= 1;
+ *DoesExists = TRUE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+NUMBER_SET::Remove(
+ IN BIG_INT Start,
+ IN BIG_INT Length
+ )
+/*++
+
+Routine Description:
+
+ This routine removes the given range from the number set.
+
+Arguments:
+
+ Start - Supplies the beginning of the range.
+ Length - Supplies the length of the range.
+
+Routine Description:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ BIG_INT i, sup;
+ BOOLEAN r;
+
+ sup = Start + Length;
+
+ r = TRUE;
+ for (i = Start; i < sup; i += 1) {
+ r = Remove(i) && r;
+ }
+
+ return r;
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+NUMBER_SET::Remove(
+ IN PCNUMBER_SET NumberSet
+ )
+/*++
+
+Routine Description:
+
+ This routine removes all of the elements in the given number set from
+ this one.
+
+Arguments:
+
+ NumberSet - Supplies the numbers to remove.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG i, n;
+ BIG_INT s, l;
+
+ n = NumberSet->QueryNumDisjointRanges();
+ for (i = 0; i < n; i++) {
+
+ NumberSet->QueryDisjointRange(i, &s, &l);
+
+ if (!Remove(s, l)) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+IFSUTIL_EXPORT
+BIG_INT
+NUMBER_SET::QueryNumber(
+ IN BIG_INT Index
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the Nth number contained in this set.
+
+Arguments:
+
+ Index - Supplies a zero-based index into the ordered set.
+
+Return Value:
+
+ The Nth number in this set.
+
+--*/
+{
+ PNUMBER_EXTENT p;
+ BIG_INT r;
+ BIG_INT count;
+
+ DebugAssert(Index < _card);
+
+ _iterator->Reset();
+ count = 0;
+ while (p = (PNUMBER_EXTENT) _iterator->GetNext()) {
+
+ count += p->Length;
+
+ if (count > Index) {
+ break;
+ }
+ }
+
+ DebugAssert(p);
+
+ return p->Start + Index - (count - p->Length);
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+NUMBER_SET::DoesIntersectSet(
+ IN BIG_INT Start,
+ IN BIG_INT Length
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes whether or not the range specified intersects
+ the current number set. This routine will return FALSE if the
+ intersection is empty, TRUE otherwise.
+
+Arguments:
+
+ Start - Supplies the start of the range.
+ Length - Supplies the length of the range.
+
+Return Value:
+
+ FALSE - The specified range does not intersect the number set.
+ TRUE - The specified range makes a non-empty intersection with
+ the number set.
+
+--*/
+{
+ PNUMBER_EXTENT p;
+ BIG_INT pnext, next;
+
+ DebugAssert(_iterator);
+
+ if (Length == 0) {
+ return FALSE;
+ }
+
+ next = Start + Length;
+
+ _iterator->Reset();
+ while (p = (PNUMBER_EXTENT) _iterator->GetNext()) {
+
+ pnext = p->Start + p->Length;
+
+ if (Start >= p->Start) {
+
+ if (Start < pnext) {
+ return TRUE;
+ }
+ } else {
+
+ if (next > p->Start) {
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+
+IFSUTIL_EXPORT
+VOID
+NUMBER_SET::QueryDisjointRange(
+ IN ULONG Index,
+ OUT PBIG_INT Start,
+ OUT PBIG_INT Length
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the 'Index'th disjoint range. (This is zero
+ based).
+
+Arguments:
+
+ Index - Supplies the index of the disjoint range.
+ Start - Returns the start of the disjoint range.
+ Length - Returns the length of the disjoint range.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG i;
+ PNUMBER_EXTENT p;
+
+ DebugAssert(_iterator);
+
+ _iterator->Reset();
+ for (i = 0; i <= Index; i++) {
+ p = (PNUMBER_EXTENT) _iterator->GetNext();
+ }
+
+ DebugAssert(p);
+ DebugAssert(Start);
+ DebugAssert(Length);
+
+ *Start = p->Start;
+ *Length = p->Length;
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+NUMBER_SET::QueryContainingRange(
+ IN BIG_INT Number,
+ OUT PBIG_INT Start,
+ OUT PBIG_INT Length
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the range that contains the given number.
+
+Arguments:
+
+ Number - Supplies the number.
+ Start - Returns the start of the range.
+ Length - Returns the length of the range.
+
+Return Value:
+
+ FALSE - The given number was not in the set.
+ TRUE - Success.
+
+--*/
+{
+ PNUMBER_EXTENT p;
+
+ DebugAssert(_iterator);
+
+ _iterator->Reset();
+ while (p = (PNUMBER_EXTENT) _iterator->GetPrevious()) {
+ if (p->Start <= Number) {
+ break;
+ }
+ }
+
+ if (!p || Number >= p->Start + p->Length) {
+ return FALSE;
+ }
+
+ *Start = p->Start;
+ *Length = p->Length;
+
+ return TRUE;
+}
diff --git a/private/utils/ifsutil/src/pch.cxx b/private/utils/ifsutil/src/pch.cxx
new file mode 100644
index 000000000..dfb9e083a
--- /dev/null
+++ b/private/utils/ifsutil/src/pch.cxx
@@ -0,0 +1,41 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ pch.cxx
+
+Abstract:
+
+ This module implements
+
+Author:
+
+ Matthew Bradburn (mattbr) 27-Apr-1994
+
+--*/
+
+#define _NTAPI_ULIB_
+#define _IFSUTIL_MEMBER_
+
+#include "ulib.hxx"
+#include "ifsutil.hxx"
+#include "autoentr.hxx"
+#include "autoreg.hxx"
+#include "bigint.hxx"
+#include "bpb.hxx"
+#include "cache.hxx"
+#include "cannedsd.hxx"
+#include "dcache.hxx"
+#include "digraph.hxx"
+#include "drive.hxx"
+#include "ifssys.hxx"
+#include "intstack.hxx"
+#include "mldcopy.hxx"
+#include "numset.hxx"
+#include "rcache.hxx"
+#include "rwcache.hxx"
+#include "secrun.hxx"
+#include "supera.hxx"
+#include "volume.hxx"
diff --git a/private/utils/ifsutil/src/rcache.cxx b/private/utils/ifsutil/src/rcache.cxx
new file mode 100644
index 000000000..9846e65f4
--- /dev/null
+++ b/private/utils/ifsutil/src/rcache.cxx
@@ -0,0 +1,219 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _IFSUTIL_MEMBER_
+
+#include "ulib.hxx"
+#include "ifsutil.hxx"
+
+#include "rcache.hxx"
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( READ_CACHE, DRIVE_CACHE, IFSUTIL_EXPORT );
+
+
+READ_CACHE::~READ_CACHE(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for READ_CACHE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+READ_CACHE::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Contructor for READ_CACHE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+}
+
+
+VOID
+READ_CACHE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for READ_CACHE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+READ_CACHE::Initialize(
+ IN OUT PIO_DP_DRIVE Drive,
+ IN ULONG NumberOfCacheBlocks
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes a READ_CACHE object.
+
+Arguments:
+
+ Drive - Supplies the drive to cache for.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ Destroy();
+
+ if (!DRIVE_CACHE::Initialize(Drive)) {
+ Destroy();
+ return FALSE;
+ }
+
+ if (!_cache.Initialize(Drive->QuerySectorSize(),
+ NumberOfCacheBlocks)) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+READ_CACHE::Read(
+ IN BIG_INT StartingSector,
+ IN SECTORCOUNT NumberOfSectors,
+ OUT PVOID Buffer
+ )
+/*++
+
+Routine Description:
+
+ This routine reads the requested sectors.
+
+Arguments:
+
+ StartingSector - Supplies the first sector to be read.
+ NumberOfSectors - Supplies the number of sectors to be read.
+ Buffer - Supplies the buffer to read the run of sectors to.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG i, j;
+ ULONG sector_size;
+ PCHAR buf;
+
+ // Bypass the cache for large reads.
+
+ if (NumberOfSectors > _cache.QueryMaxNumBlocks()) {
+ return HardRead(StartingSector, NumberOfSectors, Buffer);
+ }
+
+ sector_size = _cache.QueryBlockSize();
+ buf = (PCHAR) Buffer;
+
+ for (i = 0; i < NumberOfSectors; i++) {
+
+ for (j = i; j < NumberOfSectors; j++) {
+
+ if (_cache.Read(StartingSector + j, &buf[j*sector_size])) {
+
+ break;
+ }
+ }
+
+
+ // Now do a hard read on everything from i to j and add these
+ // blocks to the cache.
+
+ if (j - i) {
+
+ if (!HardRead(StartingSector + i, j - i, &buf[i*sector_size])) {
+
+ return FALSE;
+ }
+
+ for (; i < j; i++) {
+
+ _cache.AddBlock(StartingSector + i, &buf[i*sector_size]);
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+READ_CACHE::Write(
+ IN BIG_INT StartingSector,
+ IN SECTORCOUNT NumberOfSectors,
+ IN PVOID Buffer
+ )
+/*++
+
+Routine Description:
+
+ This routine writes the requested sectors directly to the disk.
+
+Arguments:
+
+ StartingSector - Supplies the first sector to be written.
+ NumberOfSectors - Supplies the number of sectors to be written.
+ Buffer - Supplies the buffer to write the run of sectors from.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ _cache.Empty();
+ return HardWrite(StartingSector, NumberOfSectors, Buffer);
+}
diff --git a/private/utils/ifsutil/src/rwcache.cxx b/private/utils/ifsutil/src/rwcache.cxx
new file mode 100644
index 000000000..79326f91b
--- /dev/null
+++ b/private/utils/ifsutil/src/rwcache.cxx
@@ -0,0 +1,565 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _IFSUTIL_MEMBER_
+
+#include "ulib.hxx"
+#include "ifsutil.hxx"
+
+#include "rwcache.hxx"
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( READ_WRITE_CACHE, DRIVE_CACHE, IFSUTIL_EXPORT );
+
+
+READ_WRITE_CACHE::~READ_WRITE_CACHE(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for READ_WRITE_CACHE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+READ_WRITE_CACHE::Construct(
+ )
+/*++
+
+Routine Description:
+
+ Contructor for READ_WRITE_CACHE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _cache_blocks = NULL;
+ _num_blocks = 0;
+ _sector_size = 0;
+ _error_occurred = FALSE;
+ _next_age = 0;
+}
+
+
+VOID
+READ_WRITE_CACHE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for READ_WRITE_CACHE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG i;
+
+ Flush();
+
+ for (i = 0; i < _num_blocks; i++) {
+ DELETE(_cache_blocks[i]);
+ }
+ DELETE(_cache_blocks);
+
+ _num_blocks = 0;
+ _sector_size = 0;
+ _error_occurred = FALSE;
+ _next_age = 0;
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+READ_WRITE_CACHE::Initialize(
+ IN OUT PIO_DP_DRIVE Drive,
+ IN ULONG NumberOfCacheBlocks
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes a READ_WRITE_CACHE object.
+
+Arguments:
+
+ Drive - Supplies the drive to cache for.
+ NumberOfCacheBlocks - Supplies the number of cache blocks.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG i;
+
+ Destroy();
+
+ _num_blocks = NumberOfCacheBlocks;
+ _sector_size = Drive->QuerySectorSize();
+ _error_occurred = FALSE;
+ _next_age = 1;
+
+ if (!DRIVE_CACHE::Initialize(Drive) ||
+ !_sectors_cached.Initialize() ||
+ !(_cache_blocks = NEW PRW_CACHE_BLOCK[_num_blocks]) ||
+ !_write_buffer.Initialize() ||
+ !_write_buffer.Acquire(NumberOfCacheBlocks*_sector_size,
+ Drive->QueryAlignmentMask())) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ for (i = 0; i < _num_blocks; i++) {
+
+ if (!(_cache_blocks[i] = NEW RW_CACHE_BLOCK) ||
+ !_cache_blocks[i]->SectorBuffer.Initialize() ||
+ !_cache_blocks[i]->SectorBuffer.Acquire(_sector_size)) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ _cache_blocks[i]->InUse = FALSE;
+ _cache_blocks[i]->IsDirty = FALSE;
+ _cache_blocks[i]->Age = 0;
+ _cache_blocks[i]->SectorNumber = 0;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+READ_WRITE_CACHE::Read(
+ IN BIG_INT StartingSector,
+ IN SECTORCOUNT NumberOfSectors,
+ OUT PVOID Buffer
+ )
+/*++
+
+Routine Description:
+
+ This routine reads the requested sectors.
+
+Arguments:
+
+ StartingSector - Supplies the first sector to be read.
+ NumberOfSectors - Supplies the number of sectors to be read.
+ Buffer - Supplies the buffer to read the run of sectors to.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG i, j;
+ PRW_CACHE_BLOCK p;
+ PCHAR pchar;
+
+ pchar = (PCHAR) Buffer;
+
+ // First check to see if the whole thing can come from the cache.
+
+ for (i = 0; i < NumberOfSectors; i++) {
+
+ if (!(p = GetSectorCacheBlock(StartingSector + i))) {
+ break;
+ }
+
+ p->Age = _next_age++;
+ memcpy(&pchar[i*_sector_size], p->SectorBuffer.GetBuf(), _sector_size);
+ }
+
+ if (i == NumberOfSectors) {
+ return TRUE;
+ }
+
+
+ // Not all of it was available so we first read the whole thing in from
+ // disk and then modify that with any dirty cache blocks.
+
+ if (!HardRead(StartingSector + i, NumberOfSectors - i,
+ &pchar[i*_sector_size])) {
+
+ return FALSE;
+ }
+
+ // First, spin through the sectors just read to determine
+ // if any are dirty in the cache; if a sector is present
+ // and dirty, copy it from the cache block to the client
+ // buffer.
+ //
+ for (j = i; j < NumberOfSectors; j++) {
+
+ if (p = GetSectorCacheBlock(StartingSector + j)) {
+
+ // The sector is in the cache. Update its timestamp;
+ // if it's dirty, copy the data from the cache block
+ // into the client buffer.
+ //
+ p->Age = _next_age++;
+ if (p->IsDirty) {
+ memcpy(&pchar[j*_sector_size], p->SectorBuffer.GetBuf(), _sector_size);
+ }
+ }
+ }
+
+ // Now spin through them again, copying the read data that
+ // isn't already in the cache into the cache. Note that this
+ // loop must be kept separate from the loop above to prevent
+ // dirty cache blocks associated with this read from getting
+ // preempted.
+ //
+ for (j = i; j < NumberOfSectors; j++) {
+
+ if (!GetSectorCacheBlock(StartingSector + j)) {
+
+ // The sector is not already in the cache--grab a
+ // cache block and stuff this sector's data into it
+ //
+ if (p = GetNextAvailbleCacheBlock()) {
+
+ if (p->InUse) {
+ if (p->IsDirty) {
+ FlushThisCacheBlock(p);
+ }
+
+ _sectors_cached.Remove(p->SectorNumber);
+ }
+
+ p->InUse = TRUE;
+ p->IsDirty = FALSE;
+ p->Age = _next_age++;
+ p->SectorNumber = StartingSector + j;
+ memcpy(p->SectorBuffer.GetBuf(), &pchar[j*_sector_size], _sector_size);
+
+ _sectors_cached.Add(p->SectorNumber);
+
+ } else {
+ DebugAbort("This can't happen!");
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+READ_WRITE_CACHE::Write(
+ IN BIG_INT StartingSector,
+ IN SECTORCOUNT NumberOfSectors,
+ IN PVOID Buffer
+ )
+/*++
+
+Routine Description:
+
+ This routine writes the requested sectors directly to the disk.
+
+Arguments:
+
+ StartingSector - Supplies the first sector to be written.
+ NumberOfSectors - Supplies the number of sectors to be written.
+ Buffer - Supplies the buffer to write the run of sectors from.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG i;
+ PRW_CACHE_BLOCK p;
+ PCHAR pchar;
+
+ pchar = (PCHAR) Buffer;
+
+ for (i = 0; i < NumberOfSectors; i++) {
+
+ if (!(p = GetSectorCacheBlock(StartingSector + i))) {
+
+ p = GetNextAvailbleCacheBlock();
+ // DebugAssert(p);
+
+ if (p->InUse) {
+ if (p->IsDirty) {
+ FlushThisCacheBlock(p);
+ }
+
+ _sectors_cached.Remove(p->SectorNumber);
+ }
+
+ p->InUse = TRUE;
+ p->SectorNumber = StartingSector + i;
+ _sectors_cached.Add(p->SectorNumber);
+ }
+
+ p->IsDirty = TRUE;
+ p->Age = _next_age++;
+ memcpy(p->SectorBuffer.GetBuf(), &pchar[i*_sector_size], _sector_size);
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+READ_WRITE_CACHE::Flush(
+ )
+/*++
+
+Routine Description:
+
+ This routine flushes all dirty cache blocks to disk. This routine
+ returns FALSE if there has ever been an write error since the last
+ flush.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG i;
+
+ i = 0;
+ while (i < _num_blocks) {
+ if (_cache_blocks[i]->InUse && _cache_blocks[i]->IsDirty) {
+ FlushThisCacheBlock(_cache_blocks[i]);
+ i = 0;
+ continue;
+ }
+ i++;
+ }
+
+ return !_error_occurred;
+}
+
+
+PRW_CACHE_BLOCK
+READ_WRITE_CACHE::GetSectorCacheBlock(
+ IN BIG_INT SectorNumber
+ )
+/*++
+
+Routine Description:
+
+ This routine searches the cache block list and return the block corresponding
+ to the given sector. If no such block exists then this routine returns NULL.
+
+Arguments:
+
+ SectorNumber - Supplies the sector searched for.
+
+Return Value:
+
+ The cache block for the given sector or NULL.
+
+--*/
+{
+ ULONG i;
+ PRW_CACHE_BLOCK p;
+
+ for (i = 0; i < _num_blocks; i++) {
+ p = _cache_blocks[i];
+ if (p->InUse && p->SectorNumber == SectorNumber) {
+ break;
+ }
+ }
+
+ return i < _num_blocks ? p : NULL;
+}
+
+
+PRW_CACHE_BLOCK
+READ_WRITE_CACHE::GetNextAvailbleCacheBlock(
+ )
+/*++
+
+Routine Description:
+
+ This routine searches the cache block list and return the next available
+ one. This routine will return either the oldest cache block or one that
+ is not in use.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The next available cache block.
+
+--*/
+{
+ ULONG i;
+ PRW_CACHE_BLOCK p;
+ ULONG oldest;
+
+
+ oldest = (ULONG) -1;
+ for (i = 0; i < _num_blocks; i++) {
+ p = _cache_blocks[i];
+
+ if (!p->InUse) {
+ return p;
+ }
+
+ if (p->Age < oldest) {
+ oldest = p->Age;
+ }
+ }
+
+ for (i = 0; i < _num_blocks; i++) {
+ p = _cache_blocks[i];
+ if (p->Age == oldest) {
+ break;
+ }
+ }
+
+ // DebugAssert(p);
+
+ return p;
+}
+
+
+VOID
+READ_WRITE_CACHE::FlushThisCacheBlock(
+ IN OUT PRW_CACHE_BLOCK Block
+ )
+/*++
+
+Routine Description:
+
+ This routine flushes the given block along with all of its adjacent
+ neighbours. All of these cache blocks are then marked clean.
+
+Arguments:
+
+ Block - Supplies a pointer to the cache block to flush.
+
+Return Value:
+
+ None.
+
+Notes:
+
+ Because we don't check return values from the NUMBER_SET calls, we can't
+ depend on this structure being valid. If it is not then only the given
+ block will be flushed.
+
+--*/
+{
+ ULONG i, n;
+ BIG_INT start, length;
+ PCHAR flush_buffer;
+ PRW_CACHE_BLOCK p;
+
+ // First figure out which group to flush.
+
+ n = _sectors_cached.QueryNumDisjointRanges();
+ for (i = 0; i < n; i++) {
+
+ _sectors_cached.QueryDisjointRange(i, &start, &length);
+
+ if (Block->SectorNumber >= start && Block->SectorNumber < start + length) {
+ break;
+ }
+ }
+
+ if (i == n) {
+ // This shouldn't happen so just flush this single one out.
+
+ FlushJustThisCacheBlock(Block);
+ return;
+ }
+
+ flush_buffer = (PCHAR) _write_buffer.GetBuf();
+
+ for (i = 0; i < length.GetLowPart(); i++) {
+
+ if (!(p = GetSectorCacheBlock(start + i))) {
+
+ // This shouldn't happen so just flush this single one out plus
+ // the stuff that so far has been marked clean.
+
+ if (i > 0) {
+ _error_occurred = !HardWrite(start, i, flush_buffer) || _error_occurred;
+ }
+
+ FlushJustThisCacheBlock(Block);
+ return;
+ }
+
+ p->IsDirty = FALSE;
+ memcpy(&flush_buffer[i*_sector_size], p->SectorBuffer.GetBuf(), _sector_size);
+ }
+
+ _error_occurred = !HardWrite(start, i, flush_buffer) || _error_occurred;
+}
+
+
+VOID
+READ_WRITE_CACHE::FlushJustThisCacheBlock(
+ IN OUT PRW_CACHE_BLOCK Block
+ )
+/*++
+
+Routine Description:
+
+ This routine flushes just the given block.
+
+Arguments:
+
+ Block - Supplies a pointer to the cache block to flush.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Block->IsDirty = FALSE;
+ memcpy(_write_buffer.GetBuf(), Block->SectorBuffer.GetBuf(), _sector_size);
+ _error_occurred = !HardWrite(Block->SectorNumber, 1, _write_buffer.GetBuf()) || _error_occurred;
+}
diff --git a/private/utils/ifsutil/src/secrun.cxx b/private/utils/ifsutil/src/secrun.cxx
new file mode 100644
index 000000000..a46a6e514
--- /dev/null
+++ b/private/utils/ifsutil/src/secrun.cxx
@@ -0,0 +1,195 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _IFSUTIL_MEMBER_
+
+#include "ulib.hxx"
+#include "ifsutil.hxx"
+
+#include "error.hxx"
+#include "secrun.hxx"
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( SECRUN, OBJECT, IFSUTIL_EXPORT );
+
+
+VOID
+SECRUN::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Constructor for class SECRUN. This function initializes the
+ member variables to "dummy" states. The member function 'Init'
+ must be called to make this class "work".
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _buf = NULL;
+ _drive = NULL;
+ _start_sector = 0;
+ _num_sectors = 0;
+}
+
+
+VOID
+SECRUN::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine puts the object back into its initial and empty state.
+ It is not necessary to call this function between calls to 'Init'
+ as Init will call this function automatically.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _buf = NULL;
+ _drive = NULL;
+ _start_sector = 0;
+ _num_sectors = 0;
+}
+
+
+IFSUTIL_EXPORT
+SECRUN::~SECRUN(
+ )
+/*++
+
+Routine Description:
+
+ Destructor of sector run object. Returns references.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+SECRUN::Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PIO_DP_DRIVE Drive,
+ IN BIG_INT StartSector,
+ IN SECTORCOUNT NumSectors
+ )
+/*++
+
+Routine Description:
+
+ This member function initializes the class so that reads and writes
+ may take place.
+
+Arguments:
+
+ Mem - Supplies means by which to acquire sufficient memory.
+ Drive - Supplies drive interface.
+ StartSector - Supplies starting LBN.
+ NumSector - Supplies the number of LBNs.
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure.
+
+--*/
+{
+ ULONG size;
+
+ Destroy();
+
+ DebugAssert(Drive);
+ DebugAssert(Mem);
+
+ _drive = Drive;
+ _start_sector = StartSector;
+ _num_sectors = NumSectors;
+ size = _num_sectors*_drive->QuerySectorSize();
+ _buf = Mem->Acquire(size, _drive->QueryAlignmentMask());
+
+ if (!size || !_buf) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+SECRUN::Read(
+ )
+/*++
+
+Routine Description:
+
+ This member function reads the sectors on disk into memory.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure.
+
+--*/
+{
+ DebugAssert(_buf);
+ return _drive->Read(_start_sector, _num_sectors, _buf);
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+SECRUN::Write(
+ )
+/*++
+
+Routine Description:
+
+ This member function writes onto the disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure.
+
+--*/
+{
+ DebugAssert(_buf);
+ return _drive->Write(_start_sector, _num_sectors, _buf);
+}
diff --git a/private/utils/ifsutil/src/sources b/private/utils/ifsutil/src/sources
new file mode 100644
index 000000000..df1c8e8d2
--- /dev/null
+++ b/private/utils/ifsutil/src/sources
@@ -0,0 +1,105 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+BLDCRT=1
+
+MAJORCOMP=utils
+MINORCOMP=ifsutil
+
+TARGETNAME=ifsutil
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ ..\..\ulib\src\obj\*\ulib.lib \
+ $(BASEDIR)\private\lsa\crypt\engine\obj\*\engine.lib \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+
+USE_CRTDLL=1
+
+DLLENTRY=InitializeIfsUtil
+
+# The following is stuff so people do not have to enlisted in ofs to build the loader.
+!IF EXIST($(BASEDIR)\private\ofs\h\ofsdisk.h)
+OFS_INCLUDE=;$(BASEDIR)\private\ofs\h
+OFS_DEFINE=-DINCLUDE_OFS
+!ELSEIF EXIST($(BASEDIR)\private\ofs.pri\h\ofsdisk.h)
+OFS_INCLUDE=;$(BASEDIR)\private\ofs.pri\h
+OFS_DEFINE=-DINCLUDE_OFS
+!ENDIF
+
+PRECOMPILED_INCLUDE= pch.cxx
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=autoentr.cxx \
+ autoreg.cxx \
+ bigint.cxx \
+ bootreg.c \
+ cache.cxx \
+ cannedsd.cxx \
+ dcache.cxx \
+ digraph.cxx \
+ drive.cxx \
+ ifssys.cxx \
+ ifsutil.cxx \
+ intstack.cxx \
+ mldcopy.cxx \
+ numset.cxx \
+ rcache.cxx \
+ rwcache.cxx \
+ secrun.cxx \
+ supera.cxx \
+ volume.cxx \
+ ifsutil.rc
+
+
+INCLUDES=..\inc;..\..\ulib\inc;..\..\..\ntos\inc$(OFS_INCLUDE)
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1 -DSTRICT=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1 -DSTRICT=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1 -DSTRICT=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1 -DSTRICT=1
+!ENDIF # NTDEBUG
+
+C_DEFINES=$(C_DEFINES) $(OFS_DEFINE)
+CXXFLAGS=+d
+UMLIBS=obj\*\ifsutil.lib
+
+UMTYPE=console
+
+UMTEST=
+
+UMRES=obj\*\ifsutil.res
+
+DLLDEF=
diff --git a/private/utils/ifsutil/src/supera.cxx b/private/utils/ifsutil/src/supera.cxx
new file mode 100644
index 000000000..2c256320b
--- /dev/null
+++ b/private/utils/ifsutil/src/supera.cxx
@@ -0,0 +1,196 @@
+#include <pch.cxx>
+
+#if i386
+//
+// Temporarily disable optimizations until cl386 Drop 077 is fixed.
+//
+#pragma optimize("",off)
+#endif
+
+#define _NTAPI_ULIB_
+#define _IFSUTIL_MEMBER_
+
+#include "ulib.hxx"
+#include "ifsutil.hxx"
+
+#include "supera.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+#include "ifssys.hxx"
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( SUPERAREA, SECRUN, IFSUTIL_EXPORT );
+
+IFSUTIL_EXPORT
+SUPERAREA::~SUPERAREA(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for SUPERAREA.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+SUPERAREA::Construct(
+ )
+/*++
+
+Routine Description:
+
+ Constructor for SUPERAREA.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _drive = NULL;
+}
+
+
+VOID
+SUPERAREA::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the object to its initial state freeing up
+ any memory in the process.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _drive = NULL;
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+SUPERAREA::Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN SECTORCOUNT NumberOfSectors,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the SUPERAREA for the given drive.
+
+Arguments:
+
+ Mem - Supplies necessary memory for the underlying sector run.
+ Drive - Supplies the drive where the superarea resides.
+ NumberOfSectors - Supplies the number of sectors in the superarea.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ Destroy();
+
+ DebugAssert(Mem);
+ DebugAssert(Drive);
+ DebugAssert(NumberOfSectors);
+
+ if (!SECRUN::Initialize(Mem, Drive, 0, NumberOfSectors)) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ _drive = Drive;
+
+ return TRUE;
+}
+
+
+IFSUTIL_EXPORT
+VOLID
+SUPERAREA::ComputeVolId(
+ IN VOLID Seed
+ )
+/*++
+
+Routine Description:
+
+ This routine computes a new and unique volume identifier.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A unique volume id.
+
+--*/
+{
+ VOLID volid;
+ PUCHAR p;
+ INT i;
+ LARGE_INTEGER NtfsTime;
+
+ if (Seed) {
+ volid = Seed;
+ } else {
+ volid = 0;
+ }
+
+ do {
+
+ if (!volid) {
+ IFS_SYSTEM::QueryNtfsTime( &NtfsTime );
+ if (NtfsTime.LowPart) {
+ volid = (VOLID) NtfsTime.LowPart;
+ } else {
+ volid = (VOLID) NtfsTime.HighPart;
+ }
+
+ if (volid == 0) { // This should never happen.
+ volid = 0x11111111;
+ }
+ }
+
+ p = (PUCHAR) &volid;
+ for (i = 0; i < sizeof(VOLID); i++) {
+ volid += *p++;
+ volid = (volid >> 2) + (volid << 30);
+ }
+
+ } while (!volid);
+
+ return volid;
+}
diff --git a/private/utils/ifsutil/src/volume.cxx b/private/utils/ifsutil/src/volume.cxx
new file mode 100644
index 000000000..b86e4dfc2
--- /dev/null
+++ b/private/utils/ifsutil/src/volume.cxx
@@ -0,0 +1,520 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _IFSUTIL_MEMBER_
+
+#include "ulib.hxx"
+#include "ifsutil.hxx"
+
+#include "error.hxx"
+#include "volume.hxx"
+#include "supera.hxx"
+#include "hmem.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+#include "autoreg.hxx"
+
+#ifndef _AUTOCHECK_
+#include <stdio.h>
+#endif // _AUTOCHECK_
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( VOL_LIODPDRV, LOG_IO_DP_DRIVE, IFSUTIL_EXPORT );
+
+VOID
+VOL_LIODPDRV::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Constructor for VOL_LIODPDRV.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _sa = NULL;
+}
+
+IFSUTIL_EXPORT
+VOL_LIODPDRV::~VOL_LIODPDRV(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for VOL_LIODPDRV.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+VOL_LIODPDRV::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a VOL_LIODPDRV to its initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _sa = NULL;
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+VOL_LIODPDRV::Initialize(
+ IN PCWSTRING NtDriveName,
+ IN PSUPERAREA SuperArea,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN ExclusiveWrite,
+ IN BOOLEAN FormatMedia,
+ IN MEDIA_TYPE MediaType
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes a VOL_LIODPDRV to a valid state.
+
+Arguments:
+
+ NtDriveName - Supplies the drive path for the volume.
+ SuperArea - Supplies the superarea for the volume.
+ Message - Supplies an outlet for messages.
+ ExclusiveWrite - Supplies whether or not the drive should be
+ opened for exclusive write.
+ FormatMedia - Supplies whether or not to format the media.
+ MediaType - Supplies the type of media to format to.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ CONST MaxSectorsInVerify = 512;
+
+ BIG_INT chunk;
+ BIG_INT amount_to_verify;
+ BIG_INT i;
+ BIG_INT sectors;
+ ULONG percent;
+
+ Destroy();
+
+ DebugAssert(NtDriveName);
+ DebugAssert(SuperArea);
+
+ if (!LOG_IO_DP_DRIVE::Initialize(NtDriveName, Message, ExclusiveWrite)) {
+ return FALSE;
+ }
+
+ if (!_bad_sectors.Initialize()) {
+ return FALSE;
+ }
+
+ _sa = SuperArea;
+
+ if (QueryMediaType() == Unknown && MediaType == Unknown) {
+ Message ? Message->Set(MSG_DISK_NOT_FORMATTED) : 1;
+ Message ? Message->Display("") : 1;
+ return FALSE;
+ }
+
+ if (!FormatMedia &&
+ (QueryMediaType() == Unknown ||
+ (MediaType != Unknown && MediaType != QueryMediaType()))) {
+ Message ? Message->Set(MSG_CANT_QUICKFMT) : 1;
+ Message ? Message->Display("") : 1;
+ if (Message ? Message->IsYesResponse(FALSE) : FALSE) {
+ FormatMedia = TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+
+ if (FormatMedia) {
+ if (!Lock()) {
+ Message ? Message->Set(MSG_CANT_LOCK_THE_DRIVE) : 1;
+ Message ? Message->Display("") : 1;
+ return FALSE;
+ }
+
+ //
+ // We make a weird exception here for the Compaq 120MB floppy,
+ // because it wants to be formatted as if it were a hard disk.
+ //
+
+ if (IsFloppy() && MediaType != F3_120M_512) {
+
+ if (!FormatVerifyFloppy(MediaType, &_bad_sectors, Message)) {
+ return FALSE;
+ }
+ } else {
+ sectors = QuerySectors();
+ chunk = min( sectors/20 + 1, MaxSectorsInVerify );
+
+ Message ? Message->Set(MSG_PERCENT_COMPLETE) : 1;
+
+ percent = 0;
+ if (Message && !Message->Display("%d", percent)) {
+ return FALSE;
+ }
+
+ for (i = 0; i < sectors; i += chunk) {
+
+ if (i*100/sectors > percent) {
+ percent = ((i*100)/sectors).GetLowPart();
+ if (Message && !Message->Display("%d", percent)) {
+ return FALSE;
+ }
+ }
+
+ amount_to_verify = min(chunk, sectors - i);
+
+ if (!Verify(i, amount_to_verify, &_bad_sectors)) {
+ Message ? Message->Set(MSG_CHK_NO_MEMORY) : 1;
+ Message ? Message->Display() : 1;
+ return FALSE;
+ }
+ }
+
+ if (Message && !Message->Display("%d", 100)) {
+ return FALSE;
+ }
+ }
+ }
+
+
+ if (QuerySectors() == 0) {
+ DebugAbort("Sectors is 0");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+IFSUTIL_EXPORT
+BOOLEAN
+VOL_LIODPDRV::Initialize(
+ IN PCWSTRING NtDriveName,
+ IN PCWSTRING HostFileName,
+ IN PSUPERAREA SuperArea,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN ExclusiveWrite
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes a VOL_LIODPDRV for a hosted
+ volume, i.e. one that is implemented as a file on
+ another volume.
+
+Arguments:
+
+ NtDriveName - Supplies the drive path for the volume.
+ HostFileName - Supplies the drive name for the host file.
+ SuperArea - Supplies the superarea for the volume.
+ Message - Supplies an outlet for messages.
+ ExclusiveWrite - Supplies whether or not the drive should be
+ opened for exclusive write.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ Destroy();
+
+ DebugAssert(HostFileName);
+ DebugAssert(SuperArea);
+
+ if (!LOG_IO_DP_DRIVE::Initialize(NtDriveName,
+ HostFileName,
+ Message,
+ ExclusiveWrite)) {
+
+ return FALSE;
+ }
+
+ if (!_bad_sectors.Initialize()) {
+ return FALSE;
+ }
+
+ _sa = SuperArea;
+
+ return TRUE;
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+VOL_LIODPDRV::Format(
+ IN PCWSTRING Label,
+ IN OUT PMESSAGE Message,
+ IN ULONG ClusterSize,
+ IN ULONG VirtualSectors
+ )
+/*++
+
+Routine Description:
+
+ This routine formats a volume.
+
+Arguments:
+
+ Label - Supplies an optional label for the volume.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ MESSAGE msg;
+
+ if (!Message) {
+ Message = &msg;
+ }
+
+ if (!_sa) {
+ return FALSE;
+ }
+
+ if (!Lock()) {
+ Message->Set(MSG_CANT_LOCK_THE_DRIVE);
+ Message->Display("");
+ return FALSE;
+ }
+
+ return _sa->Create(&_bad_sectors,
+ Message, Label,
+ ClusterSize,
+ VirtualSectors);
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+VOL_LIODPDRV::ChkDsk(
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ IN BOOLEAN OnlyIfDirty,
+ IN BOOLEAN RecoverFree,
+ IN BOOLEAN RecoverAlloc,
+ IN BOOLEAN ResizeLogFile,
+ IN ULONG DesiredLogFileSize,
+ OUT PULONG ExitStatus,
+ IN PCWSTRING DriveLetter
+ )
+/*++
+
+Routine Description:
+
+ This routine checks the integrity of the file system on the volume.
+ If there are any problems, this routine will attempt to fix them
+ to the degree specified in 'FixLevel'.
+
+Arguments:
+
+ FixLevel - Supplies the level to which the volume should be fixed.
+ Message - Supplies an outlet for messages.
+ Verbose - Supplies whether or not to be verbose.
+ OnlyIfDirty - Supplies whether the drive should be checked only if
+ it is dirty (TRUE) or unconditionally (FALSE).
+ Recover - Supplies whether or not to verify all sectors on the
+ volume.
+ ResizeLogFile - Tells whether to resize the ntfs logfile.
+ DesiredLogFileSize - Tells what logfile size the user wants.
+ ExitStatus - Returns and indication of how the chkdsk went.
+ DriveLetter - For autochk, tells which drive letter we're checking.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ MESSAGE msg;
+ ULONG exit_status;
+
+ if (!Message) {
+ Message = &msg;
+ }
+
+ if (NULL == ExitStatus) {
+ ExitStatus = &exit_status;
+ }
+
+ if (!_sa) {
+ return FALSE;
+ }
+
+ return _sa->VerifyAndFix(FixLevel, Message, Verbose, OnlyIfDirty,
+ RecoverFree, RecoverAlloc,
+ ResizeLogFile, DesiredLogFileSize,
+ ExitStatus,
+ DriveLetter);
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+VOL_LIODPDRV::Recover(
+ IN PCWSTRING FullPathFileName,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine searches the named file for bad allocation units.
+ It removes these allocation units from the file and marks them
+ as bad in the file system.
+
+Arguments:
+
+ FullPathFileName - Supplies the name of the file to recover.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ MESSAGE msg;
+
+ if (!Message) {
+ Message = &msg;
+ }
+
+ if (!_sa) {
+ return FALSE;
+ }
+
+ return _sa->RecoverFile(FullPathFileName, Message);
+}
+
+
+IFSUTIL_EXPORT
+BOOLEAN
+VOL_LIODPDRV::ForceAutochk(
+ IN BOOLEAN Recover,
+ IN BOOLEAN ResizeLogFile,
+ IN ULONG LogFileSize,
+ IN PCWSTRING Name
+ )
+/*++
+
+Routine Description:
+
+ This method schedules Autochk to be run at next boot. If the client
+ has not requested bad sector detection or logfile resizing, this
+ scheduling is done simply by marking the volume dirty. If bad sector
+ detection or logfile resizing has been requested, the appropriate entry
+ is put into the registry to force autochk to run.
+
+Arguments:
+
+ Recover -- Supplies a flag which indicates whether the client
+ wants to perform bad sector recovery on free space
+ and user files.
+ ResizeLogFile -- Tells whether the user wants to resize the ntfs log file.
+ LogFileSize -- If resizing, tells the desired size in bytes.
+ Name -- Supplies the volume's NT name.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ DSTRING CommandLine;
+
+ if (!Recover && !ResizeLogFile) {
+
+ // The client has not asked for autochk /r or /l, so it suffices
+ // to mark the volume dirty.
+ //
+
+ return ForceDirty();
+ }
+
+ // The caller wants to do tricky stuff, so we'll have to schedule an
+ // explicit autocheck.
+ //
+
+ if (!CommandLine.Initialize( "autocheck autochk " )) {
+ return FALSE;
+ }
+
+ if (Recover) {
+
+ DSTRING R_Option;
+
+ if (!R_Option.Initialize( "/r " ) ||
+ !CommandLine.Strcat( &R_Option )) {
+
+ return FALSE;
+ }
+ }
+
+#ifndef _AUTOCHECK_
+// Not allowed to call sprintf from autochk; don't need this there code anyway.
+
+ if (ResizeLogFile) {
+
+ DSTRING L_Option;
+ CHAR buf[20];
+
+ sprintf(buf, "/l:%d ", LogFileSize / 1024);
+
+ if (!L_Option.Initialize( buf ) ||
+ !CommandLine.Strcat( &L_Option )) {
+
+ return FALSE;
+ }
+ }
+#endif // _AUTOCHECK_
+
+ return CommandLine.Strcat( Name ) &&
+ AUTOREG::AddEntry( &CommandLine );
+}
diff --git a/private/utils/keyb/keyb.cxx b/private/utils/keyb/keyb.cxx
new file mode 100644
index 000000000..9c3a070a2
--- /dev/null
+++ b/private/utils/keyb/keyb.cxx
@@ -0,0 +1,913 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Keyb
+
+Abstract:
+
+ Keyb is a DOS5-Compatible keyboard preparation utility
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 01-May-1991
+
+Revision History:
+
+--*/
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "stream.hxx"
+#include "screen.hxx"
+#include "smsg.hxx"
+#include "rtmsg.h"
+#include "keyb.hxx"
+
+#include <winuser.h>
+
+extern "C" {
+#include <stdio.h>
+}
+
+
+ERRSTACK *perrstk;
+
+
+
+VOID _CRTAPI1
+main (
+ )
+
+/*++
+
+Routine Description:
+
+ Main function of the Keyb utility
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ //
+ // Initialize stuff
+ //
+ DEFINE_CLASS_DESCRIPTOR( KEYB );
+
+ {
+ KEYB Keyb;
+
+ Keyb.Initialize();
+
+ Keyb.ConfigureKeyboard();
+
+ }
+}
+
+
+
+DEFINE_CONSTRUCTOR( KEYB, PROGRAM );
+
+
+
+KEYB::~KEYB (
+ )
+
+/*++
+
+Routine Description:
+
+ Destructs a KEYB object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+}
+
+
+
+
+BOOLEAN
+KEYB::Initialize (
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes a KEYB object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE.
+
+Notes:
+
+--*/
+
+{
+ //
+ // Initialize program object
+ //
+ PROGRAM::Initialize( MSG_KEYB_USAGE );
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+KEYB::ConfigureKeyboard (
+ )
+
+/*++
+
+Routine Description:
+
+ Configures the keyboard
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE.
+
+Notes:
+
+--*/
+
+{
+
+ DWORD KeyboardCode;
+ HKL Hkl;
+ DSTRING Code;
+ SCREEN Screen;
+ char CharBuffer[MAX_PATH];
+ WCHAR WCharBuffer[MAX_PATH];
+
+ if ( !Screen.Initialize() ) {
+
+ DisplayMessage( MSG_INSUFFICIENT_MEMORY, ERROR_MESSAGE );
+ return FALSE;
+ }
+
+ if ( ParseArguments() ) {
+
+
+ if ( !_SetKeyboardCode && !_SetCodePage && !_SetKeyboardId ) {
+
+ //
+ // Display current status
+ //
+ DisplayCurrentKeyboardCode( );
+ DisplayMessage( MSG_KEYB_CON_CODE_PAGE, NORMAL_MESSAGE, "%d", Screen.QueryCodePage( ) );
+
+ } else {
+
+ //
+ // Set keyboard and/or codepage
+ //
+ if ( _SetKeyboardCode ) {
+
+ //
+ // Get keyboard code
+ //
+ KeyboardCode = GetKeyboardCode();
+
+ //
+ // Set keyboard layer
+ //
+ //
+ // The keyboard code is a number, but the API takes a
+ // wide character string, so we have to do some funky
+ // stuff to do the conversion.
+ //
+ sprintf( CharBuffer, "%8.8X", KeyboardCode );
+ Code.Initialize( CharBuffer );
+ Code.QueryWSTR( 0, TO_END, WCharBuffer, MAX_PATH );
+
+ Hkl = LoadKeyboardLayout( WCharBuffer, KLF_ACTIVATE | KLF_UNLOADPREVIOUS);
+
+ if ( Hkl == 0 || Hkl == INVALID_HANDLE_VALUE ) {
+
+ DisplayMessage( MSG_KEYB_INVALID_CODE, ERROR_MESSAGE );
+ ExitProgram( EXIT_SYNTAXERROR );
+ }
+ }
+
+ if ( _SetCodePage ) {
+
+ if ( Screen.SetCodePage( _CodePage ) &&
+ Screen.SetOutputCodePage( _CodePage ) ) {
+
+ DisplayMessage( MSG_KEYB_CON_CODE_PAGE, NORMAL_MESSAGE, "%d", Screen.QueryCodePage( ) );
+
+ } else {
+
+ DisplayMessage( MSG_KEYB_INVALID_CODE_PAGE, ERROR_MESSAGE );
+ return FALSE;
+ }
+ }
+ }
+
+ ExitProgram( EXIT_NORMAL );
+
+ } else {
+
+ ExitProgram( EXIT_SYNTAXERROR );
+
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+LookupKeyboardCode(
+ IN PWSTR LangIdString,
+ OUT PWSTRING KeyboardString
+ )
+/*++
+
+Routine Description:
+
+ This method looks up the keyboard code string for the specified
+ Language ID string.
+
+Arguments:
+
+ LangIdString -- Supplies the language ID as a string representing
+ a hexadecimal number.
+ KeyboardString -- Receives the two-letter keyboard code string
+ which corresponds to the given language ID.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ HKEY Key;
+ BYTE Data[32];
+ DWORD DataLength, DataType;
+ BOOLEAN Result;
+
+ DataLength = 32;
+
+ if( RegOpenKey( HKEY_LOCAL_MACHINE,
+ KEYBOARD_LAYOUT_KEY_NAME,
+ &Key ) != ERROR_SUCCESS ) {
+
+ return FALSE;
+ }
+
+ Result = RegQueryValueEx( Key,
+ LangIdString,
+ NULL,
+ &DataType,
+ Data,
+ &DataLength ) == ERROR_SUCCESS &&
+ DataType == REG_SZ &&
+ KeyboardString->Initialize( (PCWSTR)Data );
+
+ RegCloseKey( Key );
+
+ return Result;
+
+}
+
+DWORD
+LookupLanguageId(
+ IN PCWSTR KeyboardString,
+ IN PCWSTR KbdId,
+ OUT PDWORD LanguageId
+ )
+/*++
+
+Routine Description:
+
+ This method looks up the Language ID for the specified keyboard
+ code string.
+
+Arguments:
+
+ KeyboardString -- Supplies the two-letter keyboard string.
+ LangId -- Receives the language ID corresponding to
+ the specified keyboard code.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ HKEY Key;
+ HKEY KeyIds;
+ WCHAR Value[REG_VALUE_LEN];
+ BYTE Data[REG_DATA_LEN];
+ PWCHAR p;
+ DWORD ValueLength, DataLength, DataType;
+ ULONG i;
+ DWORD ErrorMsg;
+
+
+ if( RegOpenKey( HKEY_LOCAL_MACHINE,
+ KEYBOARD_LAYOUT_KEY_NAME,
+ &Key ) != ERROR_SUCCESS ) {
+
+ return MSG_KEYB_BAD_REGISTRY;
+ }
+
+ if( ( KbdId != NULL ) &&
+ ( RegOpenKey( HKEY_LOCAL_MACHINE,
+ KEYBOARD_LAYOUT_KEY_IDS,
+ &KeyIds ) != ERROR_SUCCESS ) ) {
+ RegCloseKey( Key );
+ return MSG_KEYB_BAD_REGISTRY;
+ }
+
+ ErrorMsg = MSG_KEYB_INVALID_CODE;
+
+ // Iterate through the values until one is found which has
+ // the keyboard string for its value.
+ //
+ for( i = 0, DataLength = REG_DATA_LEN, ValueLength = REG_VALUE_LEN;
+ RegEnumValue( Key, i, Value, &ValueLength, NULL, &DataType,
+ Data, &DataLength ) == ERROR_SUCCESS;
+ i++, DataLength = REG_DATA_LEN, ValueLength = REG_VALUE_LEN ) {
+
+ if( DataType == REG_SZ &&
+ _wcsicmp( KeyboardString, (PCWSTR)Data ) == 0 ) {
+
+ // It's a match. The value name is a string which
+ // represents the Language ID as a hexadecimal number.
+ // If there is a _KeyboardId, make sure it matches.
+ //
+ if( KbdId != NULL ) {
+
+ DataLength = REG_DATA_LEN;
+ if( ( RegQueryValueEx( KeyIds,
+ Value,
+ NULL, &DataType,
+ Data, &DataLength ) == ERROR_SUCCESS ) &&
+ (DataType == REG_SZ) ) {
+
+ // Value is found, does data match KbdId ?
+ //
+ if( wcscmp(KbdId, (PCWSTR)Data ) == 0 ) {
+ // If it doesn't match, continue enumerating to find
+ // another match with KeyboardString
+ goto Match;
+ }
+ }
+ ErrorMsg = MSG_KEYB_INVALID_ID;
+ continue;
+ }
+
+Match:
+ // Its the match we want - convert it to a DWORD and return it.
+ ErrorMsg = 0;
+ p = Value;
+ *LanguageId = 0;
+
+ while ( *p ) {
+ *LanguageId *= 0x10;
+ if ( *p >= '0' && *p <= '9' ) {
+ *LanguageId += *p - '0';
+ } else {
+ *LanguageId += *p - 'A' + 0xA;
+ }
+ p++;
+ }
+
+ break;
+ }
+ }
+
+ if( KbdId != NULL ) {
+ RegCloseKey( KeyIds );
+ }
+ RegCloseKey( Key );
+ return ErrorMsg;
+}
+
+
+
+
+VOID
+KEYB::DisplayCurrentKeyboardCode (
+ )
+
+/*++
+
+Routine Description:
+
+ Displays the current keyboard code
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ DSTRING KeyboardString;
+
+ WCHAR Buffer[12];
+ PWCHAR p;
+ DWORD LangId;
+ BYTE Lang;
+ BYTE Sublang;
+
+
+ if ( !GetKeyboardLayoutName( Buffer ) ) {
+
+ DebugAssert( FALSE );
+
+ } else {
+
+ // The keyboard API returns a string representing a hexadecimal
+ // number. This string is a value-name on the keyboard-layout
+ // registry key; the content of that value is the two-letter
+ // keyboard ID string.
+ //
+ if( LookupKeyboardCode( Buffer, &KeyboardString ) ) {
+
+ DisplayMessage( MSG_KEYB_KEYBOARD_CODE, NORMAL_MESSAGE, "%W", &KeyboardString );
+
+ } else {
+
+ // This language code is not in the registry. Convert
+ // the string to a number, break it into language and
+ // sublanguage, and display that information.
+ //
+ p = Buffer;
+ LangId = 0;
+
+ while ( *p ) {
+ LangId *= 0x10;
+ if ( *p >= '0' && *p <= '9' ) {
+ LangId += *p - '0';
+ } else {
+ LangId += *p - 'A' + 0xA;
+ }
+ p++;
+ }
+
+ Lang = PRIMARYLANGID( LangId );
+ Sublang = SUBLANGID( LangId );
+
+ DisplayMessage( MSG_KEYB_KEYBOARD_LAYOUT, NORMAL_MESSAGE, "%d%d", Lang, Sublang );
+ }
+ }
+}
+
+
+
+BOOLEAN
+KEYB::ParseArguments (
+ )
+
+/*++
+
+Routine Description:
+
+ Parses arguments
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if success, FALSE if syntax error.
+
+Notes:
+
+--*/
+
+{
+
+ DSTRING Line;
+ DSTRING Blanks;
+ CHNUM Pos;
+
+ _SetKeyboardCode = FALSE;
+ _SetCodePage = FALSE;
+ _SetKeyboardId = FALSE;
+
+ if ( !Line.Initialize( GetCommandLine() ) ||
+ !Blanks.Initialize( " \t" )
+ ) {
+ return FALSE;
+ }
+
+ Pos = Line.Strcspn( &Blanks );
+
+ //DisplayToken( "Program name", Line, Len );
+
+ SkipBlanks( &Line, &Pos );
+
+ return KeyboardCode( &Line, Pos );
+}
+
+
+BOOLEAN
+KEYB::KeyboardCode(
+ IN PWSTRING Line,
+ IN CHNUM Pos
+ )
+{
+ CHNUM Len;
+ DSTRING Delimiters;
+
+ if ( !Delimiters.Initialize( " ," ) ) {
+ return FALSE;
+ }
+
+ switch ( Line->QueryChAt( Pos ) ) {
+
+ case INVALID_CHAR:
+ return TRUE;
+
+ case '/':
+ return Switches( Line, Pos );
+
+ case ',':
+ Pos++;
+ SkipBlanks( Line, &Pos );
+ return CodePage( Line, Pos );
+
+ default:
+
+ Len = Line->Strcspn( &Delimiters, Pos );
+
+ if ( Len == INVALID_CHNUM ) {
+ Len = Line->QueryChCount();
+ }
+
+ Len-=Pos;
+
+ if ( !_KeyboardCode.Initialize( Line, Pos, Len ) ) {
+ return FALSE;
+ }
+
+ _KeyboardCode.Strupr();
+
+ _SetKeyboardCode = TRUE;
+
+ Pos += Len;
+ SkipBlanks( Line, &Pos );
+
+ switch( Line->QueryChAt( Pos ) ) {
+
+ case INVALID_CHAR:
+ return TRUE;
+
+ case ',':
+ Pos++;
+ return CodePage( Line, Pos );
+
+ case '/':
+ return Switches( Line, Pos );
+
+ default:
+ return ParseError( MSG_KEYB_INVALID_PARAMETER, Line, Pos );
+ }
+ }
+}
+
+
+BOOLEAN
+KEYB::CodePage(
+ IN PWSTRING Line,
+ IN CHNUM Pos
+ )
+{
+ CHNUM Len;
+ DSTRING Delimiters;
+
+ if ( !Delimiters.Initialize( " ," ) ) {
+ return FALSE;
+ }
+
+
+ switch( Line->QueryChAt( Pos ) ) {
+
+ case INVALID_CHAR:
+ return TRUE;
+
+ case '/':
+ return Switches( Line, Pos );
+
+ case ',':
+ Pos++;
+ SkipBlanks( Line, &Pos );
+ return FileName( Line, Pos );
+
+ default:
+ Len = Line->Strcspn( &Delimiters, Pos );
+
+ if ( Len == INVALID_CHNUM ) {
+ Len = Line->QueryChCount();
+ }
+
+ Len-=Pos;
+
+ if ( !Line->QueryNumber( &_CodePage, Pos, Len ) ) {
+ return ParseError( MSG_KEYB_INVALID_PARAMETER, Line, Pos );
+ }
+
+ _SetCodePage = TRUE;
+
+ Pos += Len;
+ SkipBlanks( Line, &Pos );
+
+ switch( Line->QueryChAt( Pos ) ) {
+
+ case INVALID_CHAR:
+ return TRUE;
+
+ case ',':
+ Pos++;
+ return FileName( Line, Pos );
+
+ case '/':
+ return Switches( Line, Pos );
+
+ default:
+ return ParseError( MSG_KEYB_INVALID_PARAMETER, Line, Pos );
+
+ }
+ }
+}
+
+
+BOOLEAN
+KEYB::FileName(
+ IN PWSTRING Line,
+ IN CHNUM Pos
+ )
+{
+ CHNUM Len;
+
+ DSTRING Delimiters;
+
+ if ( !Delimiters.Initialize( " /" ) ) {
+ return FALSE;
+ }
+
+ switch( Line->QueryChAt( Pos ) ) {
+
+ case INVALID_CHAR:
+ return TRUE;
+
+ case '/':
+ return Switches( Line, Pos );
+
+ default:
+ Len = Line->Strcspn( &Delimiters, Pos );
+ if ( Len == INVALID_CHNUM ) {
+ Len = Line->QueryChCount();
+ }
+
+ Len-=Pos;
+
+ //DisplayToken( "File Name", Line, Len );
+ Pos += Len;
+ SkipBlanks( Line, &Pos );
+ return Switches( Line, Pos );
+ }
+}
+
+
+BOOLEAN
+KEYB::Switches(
+ IN PWSTRING Line,
+ IN CHNUM Pos
+ )
+{
+
+ WCHAR Char;
+
+ Char = Line->QueryChAt( Pos );
+
+ if ( Char == INVALID_CHAR ) {
+ return TRUE;
+ } else if ( Char != '/' ) {
+ return ParseError( MSG_KEYB_INVALID_PARAMETER, Line, Pos );
+ }
+
+ Pos++;
+
+ switch( Line->QueryChAt( Pos ) ) {
+
+ case '?':
+ Usage();
+
+ case 'e':
+ case 'E':
+ return Enhanced( Line, Pos );
+
+ case 'i':
+ case 'I':
+ return KeyboardId( Line, Pos );
+
+ default:
+ return ParseError( MSG_KEYB_INVALID_SWITCH, Line, Pos-1 );
+ }
+}
+
+
+BOOLEAN
+KEYB::Enhanced(
+ IN PWSTRING Line,
+ IN CHNUM Pos
+ )
+{
+ DSTRING Delimiters;
+ CHNUM Len;
+
+ if ( !Delimiters.Initialize( " \t" ) ) {
+ return FALSE;
+ }
+
+ Len = Line->Strcspn( &Delimiters, Pos);
+
+ if ( Len != INVALID_CHNUM && Len != Pos+1 ) {
+ return ParseError( MSG_KEYB_INVALID_SWITCH, Line, Pos-1);
+ }
+
+ Pos++;
+ SkipBlanks( Line, &Pos );
+
+ switch ( Line->QueryChAt( Pos ) ) {
+
+ case INVALID_CHAR:
+ return FALSE;
+
+ case '/':
+ Pos++;
+ switch ( Line->QueryChAt( Pos ) ) {
+
+ case 'i':
+ case 'I':
+ return KeyboardId( Line, Pos );
+
+ default:
+ return ParseError( MSG_KEYB_INVALID_SWITCH, Line, Pos-1 );
+ }
+
+ default:
+ return ParseError( MSG_KEYB_INVALID_SWITCH, Line, Pos );
+
+ }
+}
+
+
+BOOLEAN
+KEYB::KeyboardId(
+ IN PWSTRING Line,
+ IN CHNUM Pos
+ )
+{
+
+ CHNUM Len;
+ DSTRING Delimiters;
+
+ if ( !Delimiters.Initialize( " \t" ) ) {
+ return FALSE;
+ }
+
+
+ Len = Line->Strcspn( &Delimiters, Pos );
+ if ( Len == INVALID_CHNUM ) {
+ Len = Line->QueryChCount();
+ }
+
+ if ( ( Line->QueryChAt( Pos+1)=='d' || Line->QueryChAt(Pos+1)=='D' ) &&
+ ( Line->QueryChAt( Pos+2)==':' ) ) {
+
+ if ( !_KeyboardId.Initialize( Line, Pos+3, Len-3 ) ) {
+ return ParseError( MSG_KEYB_INVALID_SWITCH, Line, Pos );
+ }
+
+ _SetKeyboardId = TRUE;
+
+ Pos += Len;
+ SkipBlanks( Line, &Pos );
+ if ( Line->QueryChAt( Pos ) == INVALID_CHAR ) {
+ return TRUE;
+ }
+
+ return ParseError( MSG_KEYB_INVALID_SWITCH, Line, Pos );
+
+ } else {
+ return ParseError( MSG_KEYB_INVALID_SWITCH, Line, Pos );
+ }
+
+}
+
+
+
+
+BOOLEAN
+KEYB::ParseError(
+ IN DWORD MessageId,
+ IN PWSTRING Line,
+ IN CHNUM Pos
+ )
+{
+ DSTRING Error;
+
+ Error.Initialize( Line, Pos );
+
+ DisplayMessage( MessageId, ERROR_MESSAGE, "%W", &Error );
+ ExitProgram( EXIT_SYNTAXERROR );
+
+ return FALSE;
+}
+
+
+
+VOID
+KEYB::SkipBlanks(
+ IN PWSTRING Line,
+ IN PCHNUM Pos
+ )
+{
+
+ DSTRING Delimiters;
+ CHNUM Len;
+ CHNUM NewPos = *Pos;
+
+ if ( Line->QueryChAt( NewPos ) == INVALID_CHAR ) {
+ return;
+ }
+
+ if ( !Delimiters.Initialize( " \t" ) ) {
+ return;
+ }
+
+ Len = Line->Strspn( &Delimiters, NewPos );
+
+ if ( Len == INVALID_CHNUM ) {
+ NewPos = Line->QueryChCount();
+ } else {
+ NewPos = Len;
+ }
+
+ *Pos = NewPos;
+}
+
+
+DWORD
+KEYB::GetKeyboardCode (
+ )
+{
+ DWORD LanguageId;
+ DWORD ErrMsg = MSG_KEYB_INVALID_CODE;
+
+ if ( _KeyboardCode.QueryChCount() != 0 ) {
+ ErrMsg = LookupLanguageId( _KeyboardCode.GetWSTR(), _KeyboardId.GetWSTR(), &LanguageId );
+ if ( ErrMsg == 0 ) {
+ return LanguageId;
+ }
+ }
+
+ DisplayMessage( ErrMsg, ERROR_MESSAGE );
+ ExitProgram( EXIT_SYNTAXERROR );
+ return 0;
+}
diff --git a/private/utils/keyb/keyb.hxx b/private/utils/keyb/keyb.hxx
new file mode 100644
index 000000000..98b92da37
--- /dev/null
+++ b/private/utils/keyb/keyb.hxx
@@ -0,0 +1,160 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Keyb.hxx
+
+Abstract:
+
+ This module contains the definition for the KEYB class, which
+ implements the DOS5-compatible Keyb utility.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 01-May-1990
+
+
+Revision History:
+
+
+--*/
+
+
+#if !defined( _KEYB_ )
+
+#define _KEYB_
+
+//
+// Exit codes
+//
+#define EXIT_NORMAL 0
+#define EXIT_SYNTAXERROR 1
+#define EXIT_BADFILE 2
+#define EXIT_CONERROR 4
+#define EXIT_MISCERROR 5
+
+#define REG_DATA_LEN 32
+#define REG_VALUE_LEN 16
+
+#include "object.hxx"
+#include "keyboard.hxx"
+#include "program.hxx"
+
+#define KEYBOARD_LAYOUT_KEY_NAME L"System\\CurrentControlSet\\Control\\Keyboard Layout\\DosKeybCodes"
+#define KEYBOARD_LAYOUT_KEY_IDS L"System\\CurrentControlSet\\Control\\Keyboard Layout\\DosKeybIDs"
+
+//
+// Forward references
+//
+DECLARE_CLASS( KEYB );
+
+class KEYB : public PROGRAM {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( KEYB );
+
+ NONVIRTUAL
+ ~KEYB (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ConfigureKeyboard (
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ DisplayCurrentKeyboardCode(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ParseArguments (
+ );
+
+ NONVIRTUAL
+ DWORD
+ GetKeyboardCode(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ KeyboardCode(
+ IN PWSTRING Line,
+ IN CHNUM Pos
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CodePage(
+ IN PWSTRING Line,
+ IN CHNUM Pos
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FileName(
+ IN PWSTRING Line,
+ IN CHNUM Pos
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Switches(
+ IN PWSTRING Line,
+ IN CHNUM Pos
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Enhanced(
+ IN PWSTRING Line,
+ IN CHNUM Pos
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ KeyboardId(
+ IN PWSTRING Line,
+ IN CHNUM Pos
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ParseError(
+ IN DWORD MsgId,
+ IN PWSTRING Line,
+ IN CHNUM Pos
+ );
+
+ NONVIRTUAL
+ VOID
+ SkipBlanks(
+ IN PWSTRING Line,
+ IN PCHNUM Pos
+ );
+
+
+ DSTRING _KeyboardCode;
+ LONG _CodePage;
+ DSTRING _KeyboardId;
+
+ BOOLEAN _SetKeyboardCode;
+ BOOLEAN _SetCodePage;
+ BOOLEAN _SetKeyboardId;
+
+
+
+};
+
+#endif // _KEYB_
diff --git a/private/utils/keyb/keyb.rc b/private/utils/keyb/keyb.rc
new file mode 100644
index 000000000..51fcd0ec4
--- /dev/null
+++ b/private/utils/keyb/keyb.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Keyboard Utility"
+#define VER_INTERNALNAME_STR "keyb\0"
+#define VER_ORIGINALFILENAME_STR "KEYB.COM"
+
+#include "common.ver"
diff --git a/private/utils/keyb/makefile b/private/utils/keyb/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/keyb/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/keyb/makefile.inc b/private/utils/keyb/makefile.inc
new file mode 100644
index 000000000..6c93eb38d
--- /dev/null
+++ b/private/utils/keyb/makefile.inc
@@ -0,0 +1,12 @@
+{}.cxx{obj\i386\}.obj:
+ $(386_COMPILER) -Fo$@ $(MAKEDIR)\$(<F)
+
+{}.cxx{obj\mips\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClMips $< " $(C_COMPILER) "
+ @$(C_COMPILER) -Fo$@ $(MAKEDIR)\$<
+
+{}.cxx{obj\alpha\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClAlpha $< " $(ALPHA_COMPILER) "
+ @$(ALPHA_COMPILER) -Fo$@ $(MAKEDIR)\$<
diff --git a/private/utils/keyb/sources b/private/utils/keyb/sources
new file mode 100644
index 000000000..4cbc38525
--- /dev/null
+++ b/private/utils/keyb/sources
@@ -0,0 +1,66 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=utils
+MINORCOMP=keyb
+
+TARGETNAME=keyb
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=keyb.cxx keyb.rc
+
+INCLUDES=..\ulib\inc;\nt\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+UMLIBS= \
+ ..\ulib\src\obj\*\ulib.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+
+UMTYPE=console
+
+UMAPPL=keyb
+
+UMRES=obj\*\keyb.res
+
+#
+# To build keyb.com
+#
+_DOT_COM_FILE=1
diff --git a/private/utils/label/label.cxx b/private/utils/label/label.cxx
new file mode 100644
index 000000000..da37a2d45
--- /dev/null
+++ b/private/utils/label/label.cxx
@@ -0,0 +1,558 @@
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+#include "arg.hxx"
+#include "array.hxx"
+#include "smsg.hxx"
+#include "rtmsg.h"
+#include "wstring.hxx"
+#include "path.hxx"
+#include "substrng.hxx"
+#include "system.hxx"
+#include "ifssys.hxx"
+#include "ulibcl.hxx"
+
+extern "C" {
+ #include "ntioapi.h"
+}
+
+CONST MaxLabelLength = 1024;
+
+VOID
+DisplayLabelUsage(
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine displays the usage for the dos 5 label program.
+
+Arguments:
+
+ Message - Supplies an outlet for the messages.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Message->Set(MSG_LBL_INFO);
+ Message->Display("");
+ Message->Set(MSG_LBL_USAGE);
+ Message->Display("");
+}
+
+
+BOOLEAN
+OpenDrive(
+ IN PCWSTRING Drive,
+ OUT PHANDLE Handle,
+ OUT PNTSTATUS Status
+ )
+/*++
+
+Routine Description:
+
+ This routine opens an NT handle to for the given dos drive name.
+
+Arguments:
+
+ Drive - Supplies a dos drive name.
+ Handle - Returns an NT handle to the drive.
+ Status - Receives the status code if the function returns FALSE
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ DSTRING ntdrive;
+ UNICODE_STRING string;
+ OBJECT_ATTRIBUTES oa;
+ IO_STATUS_BLOCK status_block;
+
+ if (!IFS_SYSTEM::DosDriveNameToNtDriveName(Drive, &ntdrive)) {
+
+ *Status = STATUS_NO_MEMORY;
+ return FALSE;
+ }
+
+ if (!(string.Buffer = ntdrive.QueryWSTR())) {
+
+ *Status = STATUS_NO_MEMORY;
+ return FALSE;
+ }
+
+ string.Length = (USHORT) (ntdrive.QueryChCount()*sizeof(WCHAR));
+ string.MaximumLength = string.Length;
+
+ InitializeObjectAttributes( &oa,
+ &string,
+ OBJ_CASE_INSENSITIVE,
+ 0,
+ 0 );
+
+ *Status = NtOpenFile(Handle,
+ SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
+ &oa, &status_block,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT | FILE_WRITE_THROUGH);
+
+ return (BOOLEAN) NT_SUCCESS(*Status);
+}
+
+
+BOOLEAN
+OpenReadOnlyDrive(
+ IN PCWSTRING Drive,
+ OUT PHANDLE Handle
+ )
+/*++
+
+Routine Description:
+
+ This routine opens an NT handle to for the given dos drive name.
+
+Arguments:
+
+ Drive - Supplies a dos drive name.
+ Handle - Returns an NT handle to the drive.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ DSTRING ntdrive;
+ UNICODE_STRING string;
+ OBJECT_ATTRIBUTES oa;
+ IO_STATUS_BLOCK status_block;
+ DSTRING backslash;
+ NTSTATUS Status;
+
+
+ if (!IFS_SYSTEM::DosDriveNameToNtDriveName(Drive, &ntdrive) ||
+ !backslash.Initialize("\\") ||
+ !ntdrive.Strcat(&backslash)) {
+
+ return FALSE;
+ }
+
+ if (!(string.Buffer = ntdrive.QueryWSTR())) {
+
+ return FALSE;
+ }
+
+ string.Length = (USHORT) (ntdrive.QueryChCount()*sizeof(WCHAR));
+ string.MaximumLength = string.Length;
+
+ InitializeObjectAttributes( &oa,
+ &string,
+ OBJ_CASE_INSENSITIVE,
+ 0,
+ 0 );
+
+ Status = NtOpenFile(Handle,
+ SYNCHRONIZE | FILE_READ_DATA,
+ &oa, &status_block,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT);
+
+ return (BOOLEAN) NT_SUCCESS(Status);
+}
+
+
+BOOLEAN
+GetLabelInput(
+ IN PCWSTRING Drive,
+ OUT PBOOLEAN LabelExists,
+ OUT PWSTRING Label,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine prints the current label, if any, and the current serial
+ number. Then a new label is queried from the user.
+
+Arguments:
+
+ Drive - The dos style drive name.
+ LabelExists - Returns whether or not a label currently exists on
+ the volume.
+ Label - Returns the inputted label.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ CONST length = sizeof(FILE_FS_VOLUME_INFORMATION) + MaxLabelLength;
+ CONST max_fsname = 40;
+
+ // The buffer for FileFsVolumeInformation must be quadword-aligned.
+
+ LONGLONG info_buf[length/sizeof(LONGLONG) + 1];
+ PFILE_FS_VOLUME_INFORMATION info;
+
+ IO_STATUS_BLOCK status_block;
+ PUSHORT p;
+ DSTRING driveletter;
+ DSTRING current_label;
+ HANDLE Handle;
+ WCHAR file_system[max_fsname];
+ MSGID label_prompt_msg;
+ DSTRING root_dir;
+ DSTRING slash;
+ PWSTR proot_dir;
+ DSTRING fsname;
+ DSTRING ntfs;
+
+ if (!OpenReadOnlyDrive(Drive, &Handle)) {
+
+ Message->Set(MSG_INCOMPATIBLE_PARAMETERS);
+ Message->Display();
+ return FALSE;
+ }
+
+
+ info = (PFILE_FS_VOLUME_INFORMATION) info_buf;
+
+ if (!NT_SUCCESS(NtQueryVolumeInformationFile(Handle, &status_block,
+ info, length, FileFsVolumeInformation))) {
+
+ NtClose(Handle);
+ return FALSE;
+ }
+
+ NtClose(Handle);
+
+ info->VolumeLabel[info->VolumeLabelLength/sizeof(WCHAR)] = 0;
+
+ if (!current_label.Initialize(info->VolumeLabel)) {
+ return FALSE;
+ }
+
+ if (Drive->QueryChCount() == 2 && Drive->QueryChAt(1) == ':') {
+ if (!driveletter.Initialize(Drive, 0, Drive->QueryChCount() - 1)) {
+ return FALSE;
+ }
+ } else {
+ if (!driveletter.Initialize(Drive)) {
+ return FALSE;
+ }
+ }
+
+ if (info->VolumeLabelLength) {
+ Message->Set(MSG_LBL_THE_LABEL);
+ Message->Display("%W%W", &driveletter, &current_label);
+ *LabelExists = TRUE;
+ } else {
+ Message->Set(MSG_LBL_NO_LABEL);
+ Message->Display("%W", &driveletter);
+ *LabelExists = FALSE;
+ }
+
+ p = (PUSHORT) &info->VolumeSerialNumber;
+
+ if (p[1] || p[0]) {
+ Message->Set(MSG_VOLUME_SERIAL_NUMBER);
+ Message->Display("%04X%04X", p[1], p[0]);
+ }
+
+ // Figure out which label prompt message to use.
+
+ label_prompt_msg = MSG_VOLUME_LABEL_PROMPT;
+
+ if (slash.Initialize("\\") &&
+ root_dir.Initialize(Drive) &&
+ root_dir.Strcat(&slash) &&
+ ntfs.Initialize("NTFS") &&
+ (proot_dir = root_dir.QueryWSTR())) {
+
+ if (GetVolumeInformation(proot_dir, NULL, 0, NULL, NULL,
+ NULL, file_system, max_fsname) &&
+ fsname.Initialize(file_system) &&
+ !fsname.Stricmp(&ntfs)) {
+
+ label_prompt_msg = MSG_VOLUME_LABEL_NO_MAX;
+ }
+
+ DELETE(proot_dir);
+ }
+
+ Message->Set(label_prompt_msg, ERROR_MESSAGE);
+ Message->Display();
+
+ return Message->QueryStringInput(Label);
+}
+
+
+BOOLEAN
+SetLabel(
+ IN PCWSTRING Drive,
+ IN PCWSTRING Label,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the supplied label on the supplied drive.
+
+Arguments:
+
+ Drive - Supplies the dos drive name.
+ Label - Supplies a label.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ CONST length = sizeof(FILE_FS_LABEL_INFORMATION) + MaxLabelLength;
+
+ PFILE_FS_LABEL_INFORMATION info;
+ STR info_buf[length];
+ IO_STATUS_BLOCK status_block;
+ NTSTATUS nts;
+ DSTRING uppercase_label;
+ HANDLE Handle;
+ NTSTATUS status;
+
+
+ if (!OpenDrive(Drive, &Handle, &status)) {
+
+ if( status == STATUS_ACCESS_DENIED ) {
+
+ Message->Set(MSG_DASD_ACCESS_DENIED);
+ Message->Display("");
+
+ } else {
+
+ Message->Set(MSG_INCOMPATIBLE_PARAMETERS);
+ Message->Display("");
+ }
+
+ return 1;
+ }
+
+
+ if (!uppercase_label.Initialize(Label)) {
+ return FALSE;
+ }
+
+ info = (PFILE_FS_LABEL_INFORMATION) info_buf;
+
+ if (!uppercase_label.QueryWSTR(0, TO_END, info->VolumeLabel,
+ (length - sizeof(ULONG))/sizeof(WCHAR))) {
+
+ Message->Set(MSG_INCOMPATIBLE_PARAMETERS);
+ Message->Display();
+ return FALSE;
+ }
+
+ info->VolumeLabelLength = uppercase_label.QueryChCount()*sizeof(WCHAR);
+
+ nts = NtSetVolumeInformationFile(Handle, &status_block, info,
+ length, FileFsLabelInformation);
+
+ if (!NT_SUCCESS(nts)) {
+
+ if ( nts == STATUS_ACCESS_DENIED ) {
+
+ Message->Set(MSG_DASD_ACCESS_DENIED);
+ Message->Display();
+
+ } else if ( nts == STATUS_INVALID_VOLUME_LABEL ) {
+
+ Message->Set(MSG_INVALID_LABEL);
+ Message->Display();
+
+ } else if ( nts == STATUS_NOT_SUPPORTED ||
+ nts == STATUS_INVALID_DEVICE_REQUEST ) {
+
+ Message->Set(MSG_LBL_NOT_SUPPORTED);
+ Message->Display();
+
+ } else if ( nts == STATUS_DISK_FULL ) {
+
+ Message->Set(MSG_INSUFFICIENT_DISK_SPACE);
+ Message->Display();
+
+ } else {
+
+ Message->Set(MSG_INCOMPATIBLE_PARAMETERS);
+ Message->Display();
+ }
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+INT _CRTAPI1
+main(
+ )
+/*++
+
+Routine Description:
+
+ This routine emulates the dos 5 label command for NT.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ 1 - An error occured.
+ 0 - Success.
+
+--*/
+{
+ STREAM_MESSAGE msg;
+ ARGUMENT_LEXEMIZER arglex;
+ ARRAY lex_array;
+ ARRAY arg_array;
+ STRING_ARGUMENT progname;
+ STRING_ARGUMENT drive_arg;
+ REST_OF_LINE_ARGUMENT label_arg;
+ FLAG_ARGUMENT help_arg;
+ DSTRING label_string;
+ DSTRING drive_string;
+ BOOLEAN label_exists;
+ PATH label_path;
+ PWSTRING p;
+ FSTRING colon;
+
+ if (!msg.Initialize(Get_Standard_Output_Stream(),
+ Get_Standard_Input_Stream(),
+ Get_Standard_Error_Stream())) {
+ return 1;
+ }
+
+ if (!lex_array.Initialize() || !arg_array.Initialize()) {
+ return 1;
+ }
+
+ if (!arglex.Initialize(&lex_array)) {
+ return 1;
+ }
+
+ arglex.SetCaseSensitive(FALSE);
+
+ if (!arglex.PrepareToParse()) {
+ return 1;
+ }
+
+ if (!progname.Initialize("*") ||
+ !help_arg.Initialize("/?") ||
+ !drive_arg.Initialize("*:") ||
+ !label_arg.Initialize()) {
+ return 1;
+ }
+
+ if (!arg_array.Put(&progname) ||
+ !arg_array.Put(&drive_arg) ||
+ !arg_array.Put(&help_arg) ||
+ !arg_array.Put(&label_arg)) {
+ return 1;
+ }
+
+ if (!arglex.DoParsing(&arg_array)) {
+ msg.Set(MSG_INVALID_PARAMETER);
+ msg.Display("%W", p = arglex.QueryInvalidArgument());
+ return 1;
+ }
+
+ if (help_arg.QueryFlag()) {
+ DisplayLabelUsage(&msg);
+ return 0;
+ }
+
+
+ if (drive_arg.IsValueSet()) {
+ if (!drive_string.Initialize(drive_arg.GetString()) ||
+ !drive_string.Strcat(colon.Initialize((PWSTR) L":"))) {
+
+ return 1;
+ }
+ } else {
+
+ if (!SYSTEM::QueryCurrentDosDriveName(&drive_string)) {
+ return 1;
+ }
+ }
+
+
+ if (label_arg.IsValueSet()) {
+
+ if (!label_path.Initialize(label_arg.GetRestOfLine())) {
+ return 1;
+ }
+
+ if (p = label_path.QueryDevice()) {
+ if (drive_arg.IsValueSet()) {
+ msg.Set(MSG_INVALID_PARAMETER);
+ msg.Display("%W", label_arg.GetRestOfLine());
+ return 1;
+ }
+
+ if (!drive_string.Initialize(p)) {
+ return 1;
+ }
+
+ DELETE(p);
+ }
+
+ if (p = label_path.QueryDirsAndName()) {
+ if (!label_string.Initialize(p)) {
+ return 1;
+ }
+ DELETE(p);
+ } else {
+ if (!label_string.Initialize("")) {
+ return 1;
+ }
+ }
+ }
+
+
+ if (!label_string.QueryChCount()) {
+
+ if (!GetLabelInput(&drive_string, &label_exists,
+ &label_string, &msg)) {
+ return 1;
+ }
+ }
+
+ if (!label_string.QueryChCount()) {
+ if (label_exists) {
+ msg.Set(MSG_LBL_DELETE_LABEL);
+ msg.Display("");
+ if (!msg.IsYesResponse(FALSE)) {
+ return 0;
+ }
+ } else {
+ return 0;
+ }
+ }
+
+ return SetLabel(&drive_string, &label_string, &msg) ? 0 : 1;
+}
diff --git a/private/utils/label/label.rc b/private/utils/label/label.rc
new file mode 100644
index 000000000..e72982120
--- /dev/null
+++ b/private/utils/label/label.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Disk Label Utility"
+#define VER_INTERNALNAME_STR "Label"
+#define VER_ORIGINALFILENAME_STR "Label.Exe"
+
+#include "common.ver"
diff --git a/private/utils/label/makefile b/private/utils/label/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/label/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/label/makefile.inc b/private/utils/label/makefile.inc
new file mode 100644
index 000000000..6c93eb38d
--- /dev/null
+++ b/private/utils/label/makefile.inc
@@ -0,0 +1,12 @@
+{}.cxx{obj\i386\}.obj:
+ $(386_COMPILER) -Fo$@ $(MAKEDIR)\$(<F)
+
+{}.cxx{obj\mips\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClMips $< " $(C_COMPILER) "
+ @$(C_COMPILER) -Fo$@ $(MAKEDIR)\$<
+
+{}.cxx{obj\alpha\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClAlpha $< " $(ALPHA_COMPILER) "
+ @$(ALPHA_COMPILER) -Fo$@ $(MAKEDIR)\$<
diff --git a/private/utils/label/sources b/private/utils/label/sources
new file mode 100644
index 000000000..c3b31c7a5
--- /dev/null
+++ b/private/utils/label/sources
@@ -0,0 +1,58 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+BLDCRT=1
+
+MAJORCOMP=utils
+MINORCOMP=label
+
+TARGETNAME=label
+TARGETPATH=obj
+TARGETTYPE=UMAPPL_NOLIB
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=label.cxx label.rc
+
+INCLUDES=..\ulib\inc;..\ifsutil\inc;\nt\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+CXXFLAGS=+d
+UMLIBS=..\ulib\src\obj\*\ulib.lib ..\ifsutil\src\obj\*\ifsutil.lib \nt\public\sdk\lib\*\ntdll.lib
+UMTYPE=console
+UMAPPL=label
+UMRES=obj\*\label.res
diff --git a/private/utils/mep/browser/bsc/bsc.c b/private/utils/mep/browser/bsc/bsc.c
new file mode 100644
index 000000000..b611e591a
--- /dev/null
+++ b/private/utils/mep/browser/bsc/bsc.c
@@ -0,0 +1,734 @@
+//
+// bsc.c -- manage queries on the database
+//
+// Copyright <C> 1988, Microsoft Corporation
+//
+// Revision History:
+//
+//
+
+#include <stdio.h>
+#include <io.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stddef.h>
+#define LINT_ARGS
+#if defined(OS2)
+#define INCL_NOCOMMON
+#define INCL_DOSPROCESS
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSFILEMGR
+#define INCL_DOSERRORS
+#define INCL_DOSMISC
+#include <os2.h>
+#include <dos.h>
+#else
+#include <windows.h>
+#endif
+
+
+
+#include "hungary.h"
+#include "mbrcache.h"
+#include "version.h"
+#include "sbrbsc.h"
+#include "bsc.h"
+
+#define LISTALLOC 50 // Browser max list size
+
+// static data
+
+static FILEHANDLE fhBSC = (FILEHANDLE)(-1); // .BSC file handle
+
+static BYTE fCase; // TRUE for case compare
+static BYTE MaxSymLen; // longest symbol length
+static WORD ModCnt; // count of modules
+
+static ISYM Unknown; // UNKNOWN symbol index
+
+static WORD ModSymCnt; // count of modsyms
+static WORD SymCnt; // count of symbols
+static WORD PropCnt; // count of properties
+static DWORD RefCnt; // count of references
+static WORD DefCnt; // count of definitions
+static WORD CalCnt; // count of calls
+static WORD CbyCnt; // count of called bys
+static WORD lastAtomPage; // last atom page #
+static WORD lastAtomCnt; // last atom page size
+
+static WORD cbModSymCnt; // size of list of modsyms
+static WORD cbSymCnt; // size of list of symbols
+static WORD cbPropCnt; // size of list of properties
+static WORD cbRefCnt; // size of list of references
+static WORD cbDefCnt; // size of list of definitions
+static WORD cbCalCnt; // size of list of calls
+static WORD cbCbyCnt; // size of list of called bys
+
+static WORD MaxModSymCnt; // max list of modsyms
+static WORD MaxSymCnt; // max list of symbols
+static WORD MaxPropCnt; // max list of properties
+static WORD MaxRefCnt; // max list of references
+static WORD MaxDefCnt; // max list of references
+static WORD MaxCalCnt; // max list of calls
+static WORD MaxCbyCnt; // max list of called bys
+
+static DWORD lbModSymList; // modsym list file start
+static DWORD lbSymList; // symbol list file start
+static DWORD lbPropList; // property list file start
+static DWORD lbRefList; // reference list file start
+static DWORD lbDefList; // def'n list file start
+static DWORD lbCalList; // calls list file start
+static DWORD lbCbyList; // call bys list file start
+static DWORD lbSbrList; // sbr list file start
+static DWORD lbAtomCache; // atom cache file start
+
+static WORD CurModSymPage = 0; // Current page of modsyms
+static WORD CurSymPage = 0; // Current page of symbols
+static WORD CurPropPage = 0; // Current page of properties
+static WORD CurRefPage = 0; // Current page of references
+static WORD CurDefPage = 0; // Current page of definitions
+static WORD CurCalPage = 0; // Current page of calls
+static WORD CurCbyPage = 0; // Current page of called bys
+
+static LSZ lszBSCName = NULL; // name of .bsc file
+
+static MODLIST far *pfModList = NULL; // module list cache start
+static MODSYMLIST far *pfModSymList = NULL; // modsym list cache start
+static SYMLIST far *pfSymList = NULL; // symbol list cache start
+static PROPLIST far *pfPropList = NULL; // property list cache start
+static REFLIST far *pfRefList = NULL; // reference list cache start
+static REFLIST far *pfDefList = NULL; // def'n list cache start
+static USELIST far *pfCalList = NULL; // calls list cache start
+static USELIST far *pfCbyList = NULL; // call bys list cache start
+
+static WORD AtomPageTblMac = 0; // last cache page used
+static CACHEPAGE AtomPageTbl[MAXATOMPAGETBL]; // Atom Cache table
+
+#define bMOD(imod) (pfModList[imod])
+#define bMODSYM(isym) (pfModSymList[isym])
+#define bSYM(isym) (pfSymList[isym])
+#define bPROP(iprop) (pfPropList[iprop])
+
+#define bREF(iref) (pfRefList[iref])
+#define bDEF(idef) (pfDefList[idef])
+
+#define bCAL(iuse) (pfCalList[iuse])
+#define bCBY(iuse) (pfCbyList[iuse])
+#define bUSE(iuse) (pfCalList[iuse])
+#define bUBY(iuse) (pfCbyList[iuse])
+
+// prototypes
+//
+
+#define BSCIn(v) ReadBSC(&v, sizeof(v));
+
+static VOID GetBSC (DWORD lpos, LPV lpv, WORD cb);
+static VOID ReadBSC(LPV lpv, WORD cb);
+static WORD SwapPAGE (DWORD, LPV, WORD, WORD, WORD *, DWORD);
+static LPCH GetAtomCache (WORD);
+
+static VOID
+ReadBSC(LPV lpv, WORD cb)
+// read a block of data from the BSC file
+//
+{
+ if (BSCRead(fhBSC, lpv, cb) != cb)
+ ReadError(lszBSCName);
+}
+
+static VOID
+GetBSC(DWORD lpos, LPV lpv, WORD cb)
+// Read a block of the specified size from the specified position
+//
+{
+#if defined (OS2)
+ if (BSCSeek(fhBSC, lpos, SEEK_SET) == -1)
+#else
+ if (BSCSeek(fhBSC, lpos, FILE_BEGIN) == -1)
+ SeekError(lszBSCName);
+#endif
+
+ if (BSCRead(fhBSC, lpv, cb) != cb)
+ ReadError(lszBSCName);
+}
+
+static WORD
+SwapPAGE (DWORD lbuflist, LPV pfTABLE, WORD tblsiz,
+/* */ WORD lstsiz, WORD * pcurpage, DWORD idx)
+//
+//
+// SwapPAGE - Swap in the table page for the table pfTABLE[idx]
+// and return the table's new index in the page.
+{
+ WORD page;
+ WORD newidx;
+
+ page = (WORD)(idx / lstsiz);
+ newidx = (WORD)(idx % lstsiz);
+
+ if (page == *pcurpage)
+ return newidx;
+
+ GetBSC(lbuflist+((long)tblsiz*(long)page), pfTABLE, tblsiz);
+
+ *pcurpage = page;
+ return newidx;
+}
+
+static WORD
+ModSymPAGE (IMOD imod)
+// Swap in the ModSym page for ModSym[imod]
+// return the ModSym's index in the page.
+//
+{
+ return SwapPAGE (lbModSymList, pfModSymList,
+ cbModSymCnt, MaxModSymCnt, &CurModSymPage, (IDX)imod);
+}
+
+static WORD
+SymPAGE (ISYM isym)
+// Swap in the Symbol page for symbol[isym]
+// return the Symbol's index in the page.
+//
+{
+ return SwapPAGE (lbSymList, pfSymList,
+ cbSymCnt, MaxSymCnt, &CurSymPage, (IDX)isym);
+}
+
+static WORD
+PropPAGE (IINST iinst)
+// Swap in the Property page for Property[idx]
+// return the Property's index in the page.
+//
+{
+ return SwapPAGE (lbPropList, pfPropList,
+ cbPropCnt, MaxPropCnt, &CurPropPage, (IDX)iinst);
+}
+
+static WORD
+RefPAGE (IREF iref)
+// Swap in the Reference page for Reference[idx]
+// return the Reference's index in the page.
+//
+{
+ return SwapPAGE (lbRefList, pfRefList,
+ cbRefCnt, MaxRefCnt, &CurRefPage, (IDX)iref);
+}
+
+static WORD
+DefPAGE (IDEF idef)
+// Swap in the Deference page for Definition[idef]
+// return the Definitions index in the page.
+//
+{
+ return SwapPAGE (lbDefList, pfDefList,
+ cbDefCnt, MaxDefCnt, &CurDefPage, (IDX)idef);
+}
+
+static WORD
+CalPAGE (IUSE iuse)
+// Swap in the Usage page for Usage[iuse] (cal/cby)
+// and return the Usage's index in the page.
+//
+{
+ return SwapPAGE (lbCalList, pfCalList,
+ cbCalCnt, MaxCalCnt, &CurCalPage, (IDX)iuse);
+}
+
+static WORD
+CbyPAGE (IUSE iuse)
+// Swap in the Usage page for Usage[iuse] (cal/cby)
+// and return the Usage's index in the page.
+//
+{
+ return SwapPAGE (lbCbyList, pfCbyList,
+ cbCbyCnt, MaxCbyCnt, &CurCbyPage, (IDX)iuse);
+}
+
+static LPCH
+GetAtomCache (WORD Page)
+// load the requested page into the cache
+//
+{
+ register WORD ipg;
+ WORD pagesize;
+ LPCH pfAtomCsave;
+
+ for (ipg = 0; ipg < AtomPageTblMac; ipg++) {
+ if (AtomPageTbl[ipg].uPage == Page)
+ return AtomPageTbl[ipg].pfAtomCache;
+ }
+
+ if (ipg != MAXATOMPAGETBL) {
+ if (AtomPageTbl[ipg].pfAtomCache ||
+ (AtomPageTbl[ipg].pfAtomCache = LpvAllocCb(ATOMALLOC)))
+ AtomPageTblMac++;
+ }
+
+ pfAtomCsave = AtomPageTbl[AtomPageTblMac-1].pfAtomCache;
+
+ for (ipg = AtomPageTblMac-1; ipg; ipg--)
+ AtomPageTbl[ipg] = AtomPageTbl[ipg-1]; // move up
+
+ AtomPageTbl[0].pfAtomCache = pfAtomCsave;
+ AtomPageTbl[0].uPage = Page;
+
+ if (Page == lastAtomPage)
+ pagesize = lastAtomCnt;
+ else
+ pagesize = ATOMALLOC;
+
+ GetBSC(lbAtomCache+ATOMALLOC*(long)Page,
+ AtomPageTbl[0].pfAtomCache, pagesize);
+
+ return AtomPageTbl[0].pfAtomCache;
+}
+
+LSZ BSC_API
+LszNameFrSym (ISYM isym)
+// Swap in the Atom page for the symbol isym
+// return the atom's address in the page.
+//
+{
+ SYMLIST sym;
+
+ sym = bSYM(isym);
+ return GetAtomCache (sym.Page) + sym.Atom;
+}
+
+LSZ BSC_API
+LszNameFrMod (IMOD imod)
+// Swap in the Atom page for the module isym
+// return the atom's address in the page.
+//
+{
+ return LszNameFrSym(bMOD(imod).ModName);
+}
+
+int BSC_API
+CaseCmp(LSZ lsz1, LSZ lsz2)
+//
+// think of lsz1 and lsz2 being in a list of things that are sorted
+// case insensitively and then case sensitively within that. This is
+// the case for browser symbols
+//
+// return -1, 0, or 1 if lsz1 before, at, or after lsz2 in the list
+//
+{
+ int ret;
+
+ // do case insensitive compare
+ ret = _stricmp(lsz1, lsz2);
+
+ // if this is good enough then use it, or if we are only doing
+ // a case insensitive search then this is good enough
+
+ if (ret || !fCase) return ret;
+
+ // if we must, do the case sensitive compare
+
+ return strcmp(lsz1, lsz2);
+}
+
+
+ISYM BSC_API
+IsymFrLsz (LSZ lszReqd)
+// find the symbol with the specifed name
+//
+{
+ ISYM Lo, Hi, Mid;
+ int Cmp;
+ LSZ lszCur;
+
+ Lo = 0;
+ Hi = (ISYM)(SymCnt - 1);
+
+ while (Lo <= Hi) {
+ Mid = (ISYM)((Hi + Lo) / 2);
+
+ lszCur = LszNameFrSym (Mid);
+ Cmp = CaseCmp (lszReqd, lszCur);
+
+ if (Cmp == 0)
+ return Mid;
+
+ if (Cmp < 0)
+ Hi = (ISYM)(Mid - 1);
+ else
+ Lo = (ISYM)(Mid + 1);
+ }
+ return isymNil;
+}
+
+IMOD BSC_API
+ImodFrLsz (LSZ lszReqd)
+// find the module with the specifed name
+//
+{
+ IMOD imod;
+
+ for (imod = 0; imod < ModCnt; imod++) {
+ if (_stricmp (lszReqd, LszNameFrSym (bMOD(imod).ModName)) == 0)
+ return imod;
+ }
+
+ return imodNil;
+}
+
+ISYM BSC_API
+IsymMac()
+// return the biggest isym in this database
+//
+{
+ return SymCnt;
+}
+
+IMOD BSC_API
+ImodMac()
+// return the biggest imod in this database
+//
+{
+ return ModCnt;
+}
+
+IINST BSC_API
+IinstMac()
+// return the biggest iinst in this database
+//
+{
+ return PropCnt;
+}
+
+VOID BSC_API
+MsRangeOfMod(IMOD imod, IMS *pimsFirst, IMS *pimsLast)
+// fill in the module information
+//
+{
+ *pimsFirst = imod ? bMOD(imod-1).mSymEnd : 0;
+ *pimsLast = bMOD(imod).mSymEnd;
+}
+
+IINST BSC_API
+IinstOfIms(IMS ims)
+// give the instance (PROP) index of the modsym
+//
+{
+ return bMODSYM(ims).ModSymProp;
+}
+
+VOID BSC_API
+InstRangeOfSym(ISYM isym, IINST *piinstFirst, IINST *piinstLast)
+// fill in the range of inst values for this symbol
+//
+{
+ *piinstFirst = isym ? bSYM(isym-1).PropEnd:0;
+ *piinstLast = bSYM(isym).PropEnd;
+}
+
+VOID BSC_API
+InstInfo(IINST iinst, ISYM *pisymInst, TYP *pTyp, ATR *pAtr)
+// get the information that qualifies this instance
+//
+{
+ *pisymInst = bPROP(iinst).PropName;
+ *pAtr = bPROP(iinst).PropAttr & 0x3ff;
+ *pTyp = (bPROP(iinst).PropAttr >> 11) & 0x1f;
+}
+
+VOID BSC_API
+RefRangeOfInst(IINST iinst, IREF *pirefFirst, IREF *pirefLast)
+// fill in the reference ranges from the inst
+//
+{
+ *pirefFirst = iinst ? bPROP(iinst-1).RefEnd : 0;
+ *pirefLast = bPROP(iinst).RefEnd;
+}
+
+VOID BSC_API
+DefRangeOfInst(IINST iinst, IDEF *pidefFirst, IDEF *pidefLast)
+// fill in the definition ranges from the inst
+//
+{
+ *pidefFirst = iinst ? bPROP(iinst-1).DefEnd : 0;
+ *pidefLast = bPROP(iinst).DefEnd;
+}
+
+VOID BSC_API
+UseRangeOfInst(IINST iinst, IUSE *piuseFirst, IUSE *piuseLast)
+// fill in the use ranges from the inst
+//
+{
+ *piuseFirst = iinst ? bPROP(iinst-1).CalEnd : 0;
+ *piuseLast = bPROP(iinst).CalEnd;
+}
+
+VOID BSC_API
+UbyRangeOfInst(IINST iinst, IUBY *piubyFirst, IUBY *piubyLast)
+// fill in the used by ranges from the inst
+//
+{
+ *piubyFirst = iinst ? bPROP(iinst-1).CbyEnd : 0;
+ *piubyLast = bPROP(iinst).CbyEnd;
+}
+
+VOID BSC_API
+UseInfo(IUSE iuse, IINST *piinst, WORD *pcnt)
+// fill in the information about this things which an inst uses
+//
+{
+ *piinst = bUSE(iuse).UseProp;
+ *pcnt = bUSE(iuse).UseCnt;
+}
+
+VOID BSC_API
+UbyInfo(IUBY iuby, IINST *piinst, WORD *pcnt)
+// fill in the information about this things which an inst is used by
+//
+{
+ *piinst = bUBY(iuby).UseProp;
+ *pcnt = bUBY(iuby).UseCnt;
+}
+
+VOID BSC_API
+RefInfo(IREF iref, LSZ *plszName, WORD *pline)
+// fill in the information about this reference
+//
+{
+ *pline = bREF(iref).RefLin;
+ *plszName = LszNameFrSym(bREF(iref).RefNam);
+}
+
+VOID BSC_API
+DefInfo(IDEF idef, LSZ *plszName, WORD *pline)
+// fill in the information about this definition
+//
+{
+ *pline = bDEF(idef).RefLin;
+ *plszName = LszNameFrSym(bDEF(idef).RefNam);
+}
+
+VOID BSC_API
+CloseBSC()
+// close database and free as much memory as possible
+//
+{
+ int i;
+
+ // close file if open
+
+ if (fhBSC != (FILEHANDLE)(-1)) {
+ BSCClose (fhBSC);
+ fhBSC = (FILEHANDLE)(-1);
+ }
+
+ // free any memory we may have allocated
+
+ if (pfModList) { FreeLpv (pfModList); pfModList = NULL; }
+ if (pfModSymList) { FreeLpv (pfModSymList); pfModSymList = NULL; }
+ if (pfSymList) { FreeLpv (pfSymList); pfSymList = NULL; }
+ if (pfPropList) { FreeLpv (pfPropList); pfPropList = NULL; }
+ if (pfRefList) { FreeLpv (pfRefList); pfRefList = NULL; }
+ if (pfDefList) { FreeLpv (pfDefList); pfDefList = NULL; }
+ if (pfCalList) { FreeLpv (pfCalList); pfCalList = NULL; }
+ if (pfCbyList) { FreeLpv (pfCbyList); pfCbyList = NULL; }
+
+ for (i=0; i < MAXATOMPAGETBL; i++) {
+ if (AtomPageTbl[i].pfAtomCache) {
+ FreeLpv (AtomPageTbl[i].pfAtomCache); // dispose Atom Cache
+ AtomPageTbl[i].pfAtomCache = NULL;
+ }
+ }
+}
+
+BOOL BSC_API
+FOpenBSC (LSZ lszName)
+// Open the specified data base.
+// Allocate buffers for cache areas
+// Initialize the data cache from the data base.
+//
+// Return TRUE iff successful, FALSE if database can't be read
+//
+{
+ WORD pagesize;
+
+ BYTE MajorVer; // .bsc version (major)
+ BYTE MinorVer; // .bsc version (minor)
+ BYTE UpdatVer; // .bsc version (updat)
+
+ WORD MaxModCnt; // max list of modules
+ WORD cbModCnt; // size of list of modules
+ DWORD lbModList; // module list file start
+
+ int i;
+
+ #define ABORT_OPEN CloseBSC(); return FALSE;
+
+ lszBSCName = lszName;
+
+#if defined (OS2)
+ fhBSC = BSCOpen(lszBSCName, O_BINARY|O_RDONLY);
+#else
+ fhBSC = BSCOpen(lszBSCName, GENERIC_READ);
+#endif
+
+ // if the .bsc file doesn't exist then we don't do any work
+ // this is the cold compile case
+ //
+
+ if (fhBSC == (FILEHANDLE)(-1)) {ABORT_OPEN;}
+
+ // read and check BSC version (major, minor and update)
+
+ BSCIn(MajorVer);
+ BSCIn(MinorVer);
+ BSCIn(UpdatVer);
+
+ BSCPrintf("Browser Data Base: %s ver %d.%d.%d\n\n",
+ lszBSCName, MajorVer, MinorVer, UpdatVer);
+
+ if ((MajorVer != BSC_MAJ) ||
+ (MinorVer != BSC_MIN) ||
+ (UpdatVer != BSC_UPD)) {
+
+ CloseBSC();
+ BadBSCVer(lszBSCName);
+ return FALSE;
+ }
+
+ // read Case sense switch, max symbol length and Unknown module id
+
+ BSCIn(fCase);
+ BSCIn(MaxSymLen);
+ BSCIn(Unknown);
+
+ // this will make the formatting look more reasonable if there are
+ // only very short names in the database
+
+ if (MaxSymLen < 8 ) MaxSymLen = 8;
+
+ // read counts (sizes) of each data area
+
+ BSCIn(ModCnt);
+ BSCIn(ModSymCnt);
+ BSCIn(SymCnt);
+ BSCIn(PropCnt);
+ BSCIn(RefCnt);
+ BSCIn(DefCnt);
+ BSCIn(CalCnt);
+ BSCIn(CbyCnt);
+ BSCIn(lastAtomPage);
+ BSCIn(lastAtomCnt);
+
+ // read BSC data area offsets
+
+ BSCIn(lbModList);
+ BSCIn(lbModSymList);
+ BSCIn(lbSymList);
+ BSCIn(lbPropList);
+ BSCIn(lbRefList);
+ BSCIn(lbDefList);
+ BSCIn(lbCalList);
+ BSCIn(lbCbyList);
+ BSCIn(lbAtomCache);
+ BSCIn(lbSbrList);
+
+ // determine data cache area sizes
+
+ #define MIN(a,b) ((a)>(b) ? (b) : (a))
+
+ MaxModCnt = ModCnt; // max list of modules
+ MaxModSymCnt = ModSymCnt; // max list of modsyms
+ MaxSymCnt = SymCnt+ModCnt; // max list of symbols
+ MaxPropCnt = PropCnt; // max list of props
+ MaxRefCnt = RefCnt; // max list of refs
+ MaxDefCnt = DefCnt; // max list of defs
+ MaxCalCnt = CalCnt; // max list of cals
+ MaxCbyCnt = CbyCnt; // max list of cbys
+
+ cbModCnt = sizeof(MODLIST) * MaxModCnt; // size of mods list
+ cbModSymCnt = sizeof(MODSYMLIST) * MaxModSymCnt; // size of modsyms list
+ cbSymCnt = sizeof(SYMLIST) * MaxSymCnt; // size of syms list
+ cbPropCnt = sizeof(PROPLIST) * MaxPropCnt; // size of props list
+ cbRefCnt = sizeof(REFLIST) * MaxRefCnt; // size of refs list
+ cbDefCnt = sizeof(REFLIST) * MaxDefCnt; // size of defs list
+ cbCalCnt = sizeof(USELIST) * MaxCalCnt; // size of cals list
+ cbCbyCnt = sizeof(USELIST) * MaxCbyCnt; // size of cbys list
+
+ // Allocate buffers for each of the object types
+
+ if (!(pfModList = LpvAllocCb(cbModCnt))) { ABORT_OPEN; }
+ if (!(pfModSymList = LpvAllocCb(cbModSymCnt))) { ABORT_OPEN; }
+ if (!(pfSymList = LpvAllocCb(cbSymCnt))) { ABORT_OPEN; }
+ if (!(pfPropList = LpvAllocCb(cbPropCnt))) { ABORT_OPEN; }
+ if (!(pfRefList = LpvAllocCb(cbRefCnt))) { ABORT_OPEN; }
+ if (!(pfDefList = LpvAllocCb(cbDefCnt))) { ABORT_OPEN; }
+ if (!(pfCalList = LpvAllocCb(cbCalCnt))) { ABORT_OPEN; }
+ if (!(pfCbyList = LpvAllocCb(cbCbyCnt))) { ABORT_OPEN; }
+
+ // read data areas
+
+ if (lastAtomPage == 0)
+ pagesize = lastAtomCnt;
+ else
+ pagesize = ATOMALLOC;
+
+ // clear out the atom cache
+ // we must be able to allocate at least one page
+
+ AtomPageTblMac = 0;
+
+ for (i=0; i < MAXATOMPAGETBL; i++)
+ AtomPageTbl[i].pfAtomCache = NULL;
+
+ AtomPageTbl[0].uPage = 65535;
+ AtomPageTbl[0].pfAtomCache = LpvAllocCb(pagesize);
+ if (!AtomPageTbl[0].pfAtomCache) { ABORT_OPEN; }
+
+
+ GetBSC(lbModList, pfModList, cbModCnt); // Init Mod cache
+ GetBSC(lbModSymList, pfModSymList, cbModSymCnt); // Init ModSym cache
+ GetBSC(lbSymList, pfSymList, cbSymCnt); // Init Sym cache
+ GetBSC(lbPropList, pfPropList, cbPropCnt); // Init Prop cache
+ GetBSC(lbRefList, pfRefList, cbRefCnt); // Init Ref cache
+ GetBSC(lbDefList, pfDefList, cbDefCnt); // Init Def cache
+ GetBSC(lbCalList, pfCalList, cbCalCnt); // Init Cal cache
+ GetBSC(lbCbyList, pfCbyList, cbCbyCnt); // Init Cby cache
+
+ // current page for all database items is now page zero
+
+ CurModSymPage = 0;
+ CurSymPage = 0;
+ CurPropPage = 0;
+ CurRefPage = 0;
+ CurDefPage = 0;
+ CurCalPage = 0;
+ CurCbyPage = 0;
+
+ GetAtomCache (0); // Init Atom cache
+
+ return TRUE;
+}
+
+WORD BSC_API
+BSCMaxSymLen()
+// return the length of the largest symbol in the database
+//
+{
+ return MaxSymLen;
+}
+
+BOOL BSC_API
+FCaseBSC()
+// is this database built with a case sensitive language?
+//
+{
+ return fCase;
+}
+
+VOID BSC_API
+SetCaseBSC(BOOL fNewCase)
+// set case sensitivity of database
+//
+{
+ fCase = (BYTE)!!fNewCase;
+}
diff --git a/private/utils/mep/browser/bsc/bscdump.c b/private/utils/mep/browser/bsc/bscdump.c
new file mode 100644
index 000000000..e4d1ea317
--- /dev/null
+++ b/private/utils/mep/browser/bsc/bscdump.c
@@ -0,0 +1,114 @@
+
+//
+//
+// DumpBSC - Dump Source Data Base.
+// Walk the symbol tree dumping stuff.
+//
+#include <string.h>
+#include <stdio.h>
+#if defined(OS2)
+#define INCL_NOCOMMON
+#define INCL_DOSPROCESS
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSFILEMGR
+#define INCL_DOSERRORS
+#define INCL_DOSMISC
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include <dos.h>
+
+#include "hungary.h"
+#include "bsc.h"
+#include "bscsup.h"
+
+VOID BSC_API
+DumpBSC()
+// Dump the contents of the .BSC file to the Output Function
+//
+{
+ IMOD imod, imodMac;
+ IMS ims, imsMac;
+ ISYM isym, isymMac, isymT;
+ IINST iinst, iinstMac, iinstT;
+ IDEF idef, idefMac;
+ IREF iref, irefMac;
+ IUSE iuse, iuseMac;
+ IUBY iuby, iubyMac;
+ WORD wLine, cnt;
+ LSZ lsz;
+
+ imodMac = ImodMac();
+
+ BSCPrintf("Modules:\n\n");
+
+ for (imod = 0; imod < imodMac; imod++) {
+ BSCPrintf("%s\n", LszNameFrMod(imod));
+
+ MsRangeOfMod(imod, &ims, &imsMac);
+
+ for ( ;ims < imsMac; ims++) {
+ BSCPrintf("\t contains ");
+ DumpInst(IinstOfIms(ims));
+ BSCPrintf("\n");
+ }
+ }
+
+ isymMac = IsymMac();
+
+ BSCPrintf("\nSymbols:\n\n");
+
+ for (isym = 0; isym < isymMac; isym++) {
+
+ InstRangeOfSym(isym, &iinst, &iinstMac);
+
+ for ( ;iinst < iinstMac; iinst++) {
+ TYP typ;
+ ATR atr;
+
+ DumpInst(iinst);
+ BSCPrintf("\n");
+
+ InstInfo(iinst, &isymT, &typ, &atr);
+
+ if (isym != isymT)
+ BSCPrintf("\t ERROR instance points back to wrong symbol!\n");
+
+ DefRangeOfInst(iinst, &idef, &idefMac);
+ for (; idef < idefMac; idef++) {
+ DefInfo(idef, &lsz, &wLine);
+ BSCPrintf ("\t def'd %s(%d)\n", lsz, wLine);
+ }
+
+ RefRangeOfInst(iinst, &iref, &irefMac);
+ for (; iref < irefMac; iref++) {
+ RefInfo(iref, &lsz, &wLine);
+ BSCPrintf ("\t ref'd %s(%d)\n", lsz, wLine);
+ }
+
+ UseRangeOfInst(iinst, &iuse, &iuseMac);
+ for (; iuse < iuseMac; iuse++) {
+ BSCPrintf ("\t uses ");
+
+ UseInfo(iuse, &iinstT, &cnt);
+ DumpInst(iinstT);
+ if (cnt > 1) BSCPrintf("[%d]", cnt);
+ BSCPrintf ("\n");
+ }
+
+ UbyRangeOfInst(iinst, &iuby, &iubyMac);
+ for (; iuby < iubyMac; iuby++) {
+ BSCPrintf ("\t used-by ");
+
+ UbyInfo(iuby, &iinstT, &cnt);
+ DumpInst(iinstT);
+ if (cnt > 1) BSCPrintf("[%d]", cnt);
+ BSCPrintf ("\n");
+ }
+
+ BSCPrintf("\n");
+ }
+ }
+}
diff --git a/private/utils/mep/browser/bsc/calltree.c b/private/utils/mep/browser/bsc/calltree.c
new file mode 100644
index 000000000..e26f07b2f
--- /dev/null
+++ b/private/utils/mep/browser/bsc/calltree.c
@@ -0,0 +1,213 @@
+//
+// calltree.c
+//
+// two routines for printing out ascii call tree's
+//
+#include <stdio.h>
+#include <string.h>
+#if defined(OS2)
+#define INCL_NOCOMMON
+#define INCL_DOSPROCESS
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSFILEMGR
+#define INCL_DOSERRORS
+#define INCL_DOSMISC
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include <dos.h>
+
+
+#include "hungary.h"
+#include "bsc.h"
+#include "bscsup.h"
+
+// forward declarations
+static BOOL FUsedInst(IINST iinst);
+static VOID dCallTree(IINST iinst, WORD cuse);
+
+
+// static variables
+static BYTE *UseBits = NULL;
+static WORD cNest = 0;
+
+VOID BSC_API
+CallTreeInst (IINST iinst)
+// emit the call tree starting from the given inst
+//
+{
+ WORD iinstMac;
+ int igrp;
+
+ iinstMac = IinstMac();
+
+ // allocate memory for bit array
+ UseBits = LpvAllocCb((WORD)(iinstMac/8 + 1));
+
+ // no memory -- no call tree
+ if (!UseBits) return;
+
+ igrp = iinstMac/8+1;
+
+ while (--igrp>=0)
+ UseBits[igrp] = 0;
+
+ cNest = 0;
+
+ dCallTree(iinst, 1);
+
+ FreeLpv(UseBits);
+}
+
+
+static VOID
+dCallTree (IINST iinst, WORD cuse)
+// emit the call tree starting from the given inst
+//
+// there are many block variables to keep the stack to a minimum...
+{
+ {
+ ISYM isym;
+
+ {
+ TYP typ;
+ ATR atr;
+
+ InstInfo(iinst, &isym, &typ, &atr);
+
+ if (typ > INST_TYP_LABEL)
+ return;
+ }
+
+
+ {
+ WORD i;
+ cNest++;
+ for (i = cNest; i; i--) BSCPrintf ("| ");
+ }
+
+ if (cuse > 1)
+ BSCPrintf ("%s[%d]", LszNameFrSym (isym), cuse);
+ else
+ BSCPrintf ("%s", LszNameFrSym (isym));
+ }
+
+ {
+ IDEF idef, idefMac;
+ LSZ lsz;
+ WORD w;
+
+ DefRangeOfInst(iinst, &idef, &idefMac);
+ DefInfo(idef, &lsz, &w);
+
+ if (strcmp("<Unknown>", lsz) == 0) {
+ BSCPrintf ("?\n");
+ cNest--;
+ return;
+ }
+ }
+
+ if (FUsedInst(iinst)) {
+ BSCPrintf ("...\n");
+ cNest--;
+ return;
+ }
+
+ BSCPrintf ("\n");
+
+ {
+ IUSE iuse, iuseMac;
+ IINST iinstUse;
+
+ UseRangeOfInst(iinst, &iuse, &iuseMac);
+
+ for (; iuse < iuseMac; iuse++) {
+ UseInfo(iuse, &iinstUse, &cuse);
+ dCallTree (iinstUse, cuse);
+ }
+ }
+
+ cNest--;
+}
+
+BOOL BSC_API
+FCallTreeLsz(LSZ lszName)
+// print out a call tree based on the given name
+//
+{
+ IMOD imod;
+ ISYM isym;
+
+ cNest = 0;
+
+ if (!lszName)
+ return FALSE;
+
+ {
+ IINST iinstMac;
+ int igrp;
+
+ iinstMac = IinstMac();
+
+ // allocate memory for bit array
+ UseBits = LpvAllocCb((WORD)(iinstMac/8 + 1));
+
+ // no memory -- no call tree
+ if (!UseBits) return FALSE;
+
+ igrp = iinstMac/8+1;
+
+ while (--igrp >= 0)
+ UseBits[igrp] = 0;
+ }
+
+ if ((imod = ImodFrLsz (lszName)) != imodNil) {
+ IMS ims, imsMac;
+
+ MsRangeOfMod(imod, &ims, &imsMac);
+
+ BSCPrintf ("%s\n", LszNameFrMod (imod));
+
+ for ( ; ims < imsMac ; ims++)
+ dCallTree (IinstOfIms(ims), 1);
+
+ FreeLpv(UseBits);
+ return TRUE;
+ }
+
+ if ((isym = IsymFrLsz (lszName)) != isymNil) {
+ IINST iinst, iinstMac;
+
+ BSCPrintf ("%s\n", LszNameFrSym (isym));
+
+ InstRangeOfSym(isym, &iinst, &iinstMac);
+
+ for (; iinst < iinstMac; iinst++)
+ dCallTree (iinst, 1);
+
+ FreeLpv(UseBits);
+ return TRUE;
+ }
+
+ FreeLpv(UseBits);
+ return FALSE;
+}
+
+static BOOL
+FUsedInst(IINST iinst)
+// return the status bit for this iinst and set it true
+//
+{
+ WORD igrp;
+ BOOL fOut;
+ WORD mask;
+
+ igrp = iinst / 8;
+ mask = (1 << (iinst % 8));
+
+ fOut = !!(UseBits[igrp] & mask);
+ UseBits[igrp] |= mask;
+ return fOut;
+}
diff --git a/private/utils/mep/browser/bsc/dump.c b/private/utils/mep/browser/bsc/dump.c
new file mode 100644
index 000000000..b87f1da29
--- /dev/null
+++ b/private/utils/mep/browser/bsc/dump.c
@@ -0,0 +1,99 @@
+
+//
+// support for instance dumping
+//
+#include <string.h>
+#include <stdio.h>
+#if defined(OS2)
+#define INCL_NOCOMMON
+#define INCL_DOSPROCESS
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSFILEMGR
+#define INCL_DOSERRORS
+#define INCL_DOSMISC
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include <dos.h>
+
+#include "hungary.h"
+#include "bsc.h"
+#include "bscsup.h"
+
+char *ptyptab[] = {
+ "undef", // SBR_TYP_UNKNOWN
+ "function", // SBR_TYP_FUNCTION
+ "label", // SBR_TYP_LABEL
+ "parameter", // SBR_TYP_PARAMETER
+ "variable", // SBR_TYP_VARIABLE
+ "constant", // SBR_TYP_CONSTANT
+ "macro", // SBR_TYP_MACRO
+ "typedef", // SBR_TYP_TYPEDEF
+ "strucnam", // SBR_TYP_STRUCNAM
+ "enumnam", // SBR_TYP_ENUMNAM
+ "enummem", // SBR_TYP_ENUMMEM
+ "unionnam", // SBR_TYP_UNIONNAM
+ "segment", // SBR_TYP_SEGMENT
+ "group", // SBR_TYP_GROUP
+ "program" // SBR_TYP_PROGRAM
+};
+
+#define C_ATR 11
+
+char *patrtab[] = {
+ "local", // SBR_ATR_LOCAL
+ "static", // SBR_ATR_STATIC
+ "shared", // SBR_ATR_SHARED
+ "near", // SBR_ATR_NEAR
+ "common", // SBR_ATR_COMMON
+ "decl_only", // SBR_ATR_DECL_ONLY
+ "public", // SBR_ATR_PUBLIC
+ "named", // SBR_ATR_NAMED
+ "module", // SBR_ATR_MODULE
+ "?", "?" // reserved for expansion
+};
+
+VOID BSC_API
+DumpInst(IINST iinst)
+// dump a single instance
+{
+ ISYM isym;
+ WORD i;
+ LSZ lsz;
+ WORD len;
+ TYP typ;
+ ATR atr;
+
+ len = BSCMaxSymLen();
+
+ InstInfo(iinst, &isym, &typ, &atr);
+
+ lsz = LszNameFrSym(isym);
+
+ BSCPrintf("%s", lsz);
+
+ for (i = strlen(lsz); i < len; i++)
+ BSCPrintf(" ");
+
+ BSCPrintf(" (%s", ptyptab[typ]);
+
+ for (i=0; i < C_ATR; i++)
+ if (atr & (1<<i)) BSCPrintf (":%s", patrtab[i]);
+
+ BSCPrintf(")");
+}
+
+LSZ BSC_API
+LszTypInst(IINST iinst)
+// return the type string of a single inst
+//
+{
+ ISYM isym;
+ TYP typ;
+ ATR atr;
+
+ InstInfo(iinst, &isym, &typ, &atr);
+ return ptyptab[typ];
+}
diff --git a/private/utils/mep/browser/bsc/filter.c b/private/utils/mep/browser/bsc/filter.c
new file mode 100644
index 000000000..5f01c7b1a
--- /dev/null
+++ b/private/utils/mep/browser/bsc/filter.c
@@ -0,0 +1,44 @@
+
+// filter.c
+//
+#include <string.h>
+#if defined(OS2)
+#define INCL_NOCOMMON
+#define INCL_DOSPROCESS
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSFILEMGR
+#define INCL_DOSERRORS
+#define INCL_DOSMISC
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include <dos.h>
+
+#include "hungary.h"
+#include "bsc.h"
+#include "bscsup.h"
+
+BOOL BSC_API
+FInstFilter (IINST iinst, MBF mbf)
+// return true if the given inst has the required properties
+//
+{
+ ISYM isym;
+ TYP typ;
+ ATR atr;
+
+ InstInfo(iinst, &isym, &typ, &atr);
+
+ if (typ <= INST_TYP_LABEL)
+ return !!(mbf & mbfFuncs);
+
+ if (typ <= INST_TYP_VARIABLE || typ >= INST_TYP_SEGMENT)
+ return !!(mbf & mbfVars);
+
+ if (typ <= INST_TYP_MACRO)
+ return !!(mbf & mbfMacros);
+
+ return !!(mbf & mbfTypes);
+}
diff --git a/private/utils/mep/browser/bsc/format.c b/private/utils/mep/browser/bsc/format.c
new file mode 100644
index 000000000..d29228723
--- /dev/null
+++ b/private/utils/mep/browser/bsc/format.c
@@ -0,0 +1,112 @@
+//
+// format.c
+//
+// simple minded printf replacement
+//
+// only supports %s and %d but it is *small*
+//
+#include <string.h>
+#if defined(OS2)
+#define INCL_NOCOMMON
+#define INCL_DOSPROCESS
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSFILEMGR
+#define INCL_DOSERRORS
+#define INCL_DOSMISC
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include <dos.h>
+
+#include "hungary.h"
+#include "bsc.h"
+#include "bscsup.h"
+
+VOID static near pascal _ultoa(DWORD, LSZ);
+
+VOID BSC_API
+BSCFormat(LPCH lpchOut, LSZ lszFormat, va_list va)
+// format to lpchOut as specified byh format
+//
+// this is a very simple minded formatter
+{
+ LPCH lpch;
+ WORD i;
+ DWORD l;
+
+ lpch = lpchOut;
+
+ while (*lszFormat) {
+ if (*lszFormat == '%') {
+ switch (lszFormat[1]) {
+
+ case '%':
+ *lpch++ = '%';
+ break;
+
+ case 's':
+ strcpy(lpch, va_arg(va, LSZ));
+ lpch += strlen(lpch);
+ break;
+
+ case 'd':
+ i = va_arg(va, WORD);
+ _ultoa((DWORD)i, lpch);
+ lpch += strlen(lpch);
+ break;
+
+ case 'l':
+ l = va_arg(va, DWORD);
+ _ultoa(l, lpch);
+ lpch += strlen(lpch);
+ break;
+
+ default:
+ lpch[0] = '%';
+ lpch[1] = lszFormat[1];
+ lpch += 2;
+ break;
+ }
+ lszFormat += 2;
+ }
+ else
+ *lpch++ = *lszFormat++;
+ }
+ *lpch = 0;
+}
+
+VOID BSC_API
+BSCSprintf(LPCH lpchOut, LSZ lszFormat, ...)
+// sprintf replacement
+//
+{
+ va_list va;
+
+ va_start(va, lszFormat);
+
+ BSCFormat(lpchOut, lszFormat, va);
+}
+
+static DWORD pow10[8] = {
+ 10L, 100L, 1000L, 10000L,
+ 100000L , 1000000L, 10000000L, 100000000L
+ };
+
+VOID static near pascal
+_ultoa(DWORD dw, LSZ lsz)
+{
+ int log;
+
+ for (log = 0; log < 8; log++)
+ if (dw < pow10[log])
+ break;
+
+ lsz[++log] = 0;
+
+ while (--log >= 0) {
+ lsz[log] = (char)(((int)(dw%10)) + '0');
+ dw/=10;
+ }
+}
diff --git a/private/utils/mep/browser/bsc/listref.c b/private/utils/mep/browser/bsc/listref.c
new file mode 100644
index 000000000..c5327c99e
--- /dev/null
+++ b/private/utils/mep/browser/bsc/listref.c
@@ -0,0 +1,185 @@
+// listref.c
+//
+// list database references
+//
+#include <string.h>
+#if defined(OS2)
+#define INCL_NOCOMMON
+#define INCL_DOSPROCESS
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSFILEMGR
+#define INCL_DOSERRORS
+#define INCL_DOSMISC
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include <dos.h>
+
+#include "hungary.h"
+#include "bsc.h"
+#include "bscsup.h"
+
+#include <stdlib.h>
+
+// forward references
+//
+static VOID ListRefSym (ISYM isym, MBF mbf);
+static VOID ListRefUse (IINST iinst, WORD icol, WORD cuse);
+static VOID PutLine(VOID);
+static VOID ListRefTitle(LSZ lszType, LSZ lszUsers, MBF mbf);
+
+// static variables
+//
+static WORD MaxSymLen;
+static LPCH bufg;
+
+
+BOOL BSC_API
+ListRefs (MBF mbfReqd)
+// scan the database for items which would match the requirements
+// and emit their uses and used by lists
+//
+{
+ static char szFunction[] = "FUNCTION";
+ static char szVariable[] = "VARIABLE";
+ static char szType[] = "TYPE";
+ static char szMacro[] = "MACRO";
+ static char szCalledBy[] = "CALLED BY LIST";
+ static char szUsedBy[] = "USED BY LIST";
+
+ bufg = LpvAllocCb(1024);
+
+ // no memory.. no reference list
+ if (!bufg) return FALSE;
+
+ MaxSymLen = BSCMaxSymLen();
+
+ if (mbfReqd & mbfFuncs) ListRefTitle(szFunction, szCalledBy, mbfFuncs);
+ if (mbfReqd & mbfVars) ListRefTitle(szVariable, szUsedBy, mbfVars);
+ if (mbfReqd & mbfMacros) ListRefTitle(szMacro, szUsedBy, mbfMacros);
+ if (mbfReqd & mbfTypes) ListRefTitle(szType, szUsedBy, mbfTypes);
+
+ FreeLpv(bufg);
+ return TRUE;
+}
+
+static VOID
+ListRefTitle(LSZ lszType, LSZ lszUsers, MBF mbf)
+// format a title
+//
+{
+ WORD i,l;
+ ISYM isym, isymMac;
+
+ isymMac = IsymMac();
+
+ // format titles
+ //
+
+ strcpy (bufg, lszType);
+ for (i=strlen(bufg); i < MaxSymLen+5; i++) bufg[i] = ' ';
+ strcpy (bufg+i, lszUsers);
+ PutLine();
+
+ // underscore titles
+ //
+ l = strlen(lszType);
+ for (i=0; i<l; i++) bufg[i] = '-';
+ for (; i < MaxSymLen+5; i++) bufg[i] = ' ';
+ l = i + strlen(lszUsers);
+ for (; i<l; i++) bufg[i] = '-';
+ bufg[i] = 0;
+ PutLine();
+
+ for (isym = 0; isym < isymMac; isym++)
+ ListRefSym (isym, mbf);
+
+ strcpy (bufg, " ");
+ PutLine();
+}
+
+static VOID
+ListRefSym (ISYM isym, MBF mbf)
+// list all the references associated with this symbol
+{
+ IINST iinst, iinstMac, iinstUby;
+ IUBY iuby, iubyMac;
+ WORD csym;
+ WORD icol = MaxSymLen+5;
+ WORD maxcol = 80 / (MaxSymLen+5)-1;
+ WORD cnt;
+
+ InstRangeOfSym(isym, &iinst, &iinstMac);
+
+ for ( ;iinst < iinstMac ; iinst++) {
+
+ if (!FInstFilter (iinst, mbf))
+ continue;
+
+ csym = 0;
+ strcpy (bufg, " ");
+ strcat (bufg, LszNameFrSym(isym));
+ strcat (bufg, ": ");
+
+ UbyRangeOfInst(iinst, &iuby, &iubyMac);
+
+ for ( ;iuby < iubyMac; iuby++) {
+ if (++csym > maxcol) {
+ csym = 1;
+ PutLine();
+ }
+
+ UbyInfo(iuby, &iinstUby, &cnt);
+ ListRefUse (iinstUby, (WORD)(csym*icol), cnt);
+ }
+ }
+ if (bufg[0]) PutLine();
+}
+
+static VOID
+ListRefUse (IINST iinst, WORD icol, WORD cuse)
+// dump information about the given prop in the location provided
+//
+{
+ WORD i, len;
+ ISYM isym;
+ BOOL fVar;
+ TYP typ;
+ ATR atr;
+ LSZ lsz;
+
+ InstInfo(iinst, &isym, &typ, &atr);
+
+ fVar = (typ > INST_TYP_LABEL);
+
+ len = strlen(bufg);
+
+ lsz = LszNameFrSym(isym);
+
+ for (i=len; i<icol; i++) bufg[i] = ' ';
+
+ bufg[icol] = 0;
+
+ if (fVar) {
+ if (cuse > 1)
+ BSCSprintf(bufg+icol, "(%s)[%d] ", lsz, cuse);
+ else
+ BSCSprintf(bufg+icol, "(%s) ", lsz);
+ }
+ else {
+ if (cuse > 1)
+ BSCSprintf(bufg+icol, "%s[%d] ", lsz, cuse);
+ else
+ BSCSprintf(bufg+icol, "%s ", lsz);
+ }
+}
+
+static VOID
+PutLine()
+// write out a single line from the buffer
+{
+ BSCPrintf("%s\n", bufg);
+ *bufg = 0;
+}
diff --git a/private/utils/mep/browser/bsc/makefile b/private/utils/mep/browser/bsc/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/mep/browser/bsc/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/mep/browser/bsc/outline.c b/private/utils/mep/browser/bsc/outline.c
new file mode 100644
index 000000000..097489bda
--- /dev/null
+++ b/private/utils/mep/browser/bsc/outline.c
@@ -0,0 +1,101 @@
+//
+// outline.c
+//
+// these are the file outline routines
+//
+//
+#include <string.h>
+#if defined(OS2)
+#define INCL_NOCOMMON
+#define INCL_DOSPROCESS
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSFILEMGR
+#define INCL_DOSERRORS
+#define INCL_DOSMISC
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include <dos.h>
+
+#include "hungary.h"
+#include "bsc.h"
+#include "bscsup.h"
+
+// forward ref
+
+VOID BSC_API
+OutlineMod(IMOD imod, MBF mbf)
+// print the outline for this module
+//
+{
+ IMS ims, imsMac;
+ IINST iinst;
+
+ BSCPrintf("\n%s\n", LszNameFrMod(imod));
+
+ MsRangeOfMod(imod, &ims, &imsMac);
+ for ( ;ims < imsMac; ims++) {
+ iinst = IinstOfIms(ims);
+
+ if (FInstFilter (iinst, mbf)) {
+ BSCPrintf(" ");
+ DumpInst(iinst);
+ BSCPrintf("\n");
+ }
+ }
+}
+
+BOOL BSC_API
+FOutlineModuleLsz (LSZ lszName, MBF mbf)
+// generate an outline for all files matching the given name/pattern
+// showing only those items which match the required attribute
+//
+{
+ IMOD imod, imodMac;
+ BOOL fRet = FALSE;
+
+ if (!lszName)
+ return FALSE;
+
+ imodMac = ImodMac();
+
+ // we match base names only
+
+ lszName = LszBaseName(lszName);
+ for (imod = 0; imod < imodMac; imod++) {
+ if (FWildMatch(lszName, LszBaseName(LszNameFrMod(imod)))) {
+ OutlineMod (imod, mbf);
+ fRet = TRUE;
+ }
+ }
+
+ return fRet;
+}
+
+LSZ BSC_API
+LszBaseName (LSZ lsz)
+// return the base name part of a path
+//
+{
+ LSZ lszBase;
+
+ // check for empty string
+
+ if (!lsz || !lsz[0]) return lsz;
+
+ // remove drive
+
+ if (lsz[1] == ':') lsz += 2;
+
+ // remove up to trailing backslash
+
+ if (lszBase = strrchr(lsz, '\\')) lsz = lszBase+1;
+
+ // then remove up to trailing slash
+
+ if (lszBase = strrchr(lsz, '/')) lsz = lszBase+1;
+
+ return lsz;
+}
diff --git a/private/utils/mep/browser/bsc/printf.c b/private/utils/mep/browser/bsc/printf.c
new file mode 100644
index 000000000..4ed12bd8b
--- /dev/null
+++ b/private/utils/mep/browser/bsc/printf.c
@@ -0,0 +1,114 @@
+
+//
+// printf.c
+//
+// simple minded printf replacement
+//
+// only supports %s and %d but it is *small*
+//
+#include <string.h>
+#include <io.h>
+#include <stdlib.h>
+#if defined(OS2)
+#define INCL_NOCOMMON
+#define INCL_DOSPROCESS
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSFILEMGR
+#define INCL_DOSERRORS
+#define INCL_DOSMISC
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include <dos.h>
+
+#include "hungary.h"
+#include "bsc.h"
+#include "bscsup.h"
+
+static char lpchBuf[1024];
+static LPCH lpchPos = NULL;
+
+VOID BSC_API
+BSCPrintf(LSZ lszFormat, ...)
+// printf replacement
+//
+{
+ va_list va;
+ LPCH lpch;
+ char ch;
+
+ if (!lpchPos) {
+ lpchPos = lpchBuf;
+ }
+
+ va_start(va, lszFormat);
+
+ BSCFormat(lpchPos, lszFormat, va);
+
+ // write out a line at a time
+ //
+ for (;;) {
+ lpch = strchr(lpchPos, '\n');
+ if (!lpch) {
+ lpchPos += strlen(lpchPos);
+ return;
+ }
+
+ ch = *++lpch;
+ *lpch = 0;
+ BSCOutput(lpchBuf);
+ *lpch = ch;
+ strcpy(lpchBuf, lpch);
+ if (!ch)
+ lpchPos = lpchBuf;
+ else
+ lpchPos = lpchBuf + strlen(lpchBuf);
+ }
+}
+
+#ifdef DEBUG
+
+static char lpchDBuf[256];
+static LPCH lpchDPos = NULL;
+
+VOID BSC_API
+BSCDebug(LSZ lszFormat, ...)
+// printf clone for debug output
+//
+{
+ va_list va;
+ LPCH lpch;
+ char ch;
+
+ if (!lpchDPos) {
+ lpchDPos = lpchDBuf;
+ }
+
+ va_start(va, lszFormat);
+
+ BSCFormat(lpchDPos, lszFormat, va);
+
+ // write out a line at a time
+ //
+ for (;;) {
+ lpch = strchr(lpchDPos, '\n');
+ if (!lpch) {
+ lpchDPos += strlen(lpchDPos);
+ return;
+ }
+
+ ch = *++lpch;
+ *lpch = 0;
+ BSCDebugOut(lpchDBuf);
+ *lpch = ch;
+ strcpy(lpchDBuf, lpch);
+ if (!ch)
+ lpchDPos = lpchDBuf;
+ else
+ lpchDPos = lpchDBuf + strlen(lpchDBuf);
+ }
+}
+
+#endif
diff --git a/private/utils/mep/browser/bsc/query.c b/private/utils/mep/browser/bsc/query.c
new file mode 100644
index 000000000..329f22e31
--- /dev/null
+++ b/private/utils/mep/browser/bsc/query.c
@@ -0,0 +1,575 @@
+//
+// query.c
+//
+// perform database queries
+//
+#include <stddef.h>
+#include <string.h>
+#if defined(OS2)
+#define INCL_NOCOMMON
+#define INCL_DOSPROCESS
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSFILEMGR
+#define INCL_DOSERRORS
+#define INCL_DOSMISC
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include <dos.h>
+
+#include "hungary.h"
+#include "bsc.h"
+#include "bscsup.h"
+
+// these keep track of the current query, they are globally visible so
+// that users can see how the query is progressing
+//
+// you may not write on these
+
+IDX far idxQyStart;
+IDX far idxQyCur;
+IDX far idxQyMac;
+
+// this is auxilliary information about the current bob which some
+// queries may choose to make available
+//
+
+static BOOL fWorking;
+static LSZ lszModLast = NULL; // for removing duplicate modules
+
+// prototypes for the query worker functions
+//
+
+static BOB BobQyFiles(VOID);
+static BOB BobQySymbols (VOID);
+static BOB BobQyContains (VOID);
+static BOB BobQyCalls (VOID);
+static BOB BobQyCalledBy (VOID);
+static BOB BobQyUses (VOID);
+static BOB BobQyUsedBy (VOID);
+static BOB BobQyUsedIn (VOID);
+static BOB BobQyDefinedIn(VOID);
+static BOB BobQyRefs(VOID);
+static BOB BobQyDefs(VOID);
+
+// current bob worker function
+static BOB (*bobFn)(VOID) = NULL;
+
+BOOL BSC_API
+InitBSCQuery (QY qy, BOB bob)
+// do the request query on the given bob
+//
+{
+ fWorking = FALSE;
+
+ if (lszModLast == NULL)
+ lszModLast = LpvAllocCb(1024); // REVIEW -- how much to alloc? [rm]
+
+ // no memory -- no query
+ if (lszModLast == NULL)
+ return FALSE;
+
+ strcpy(lszModLast, "");
+
+ switch (qy) {
+
+ case qyFiles:
+ bobFn = BobQyFiles;
+ idxQyStart = (IDX)0;
+ idxQyMac = (IDX)ImodMac();
+ break;
+
+ case qySymbols:
+ bobFn = BobQySymbols;
+ idxQyStart = (IDX)0;
+ idxQyMac = (IDX)IinstMac();
+ break;
+
+ case qyContains:
+ {
+ IMS ims, imsMac;
+
+ bobFn = BobQyContains;
+
+ if (ClsOfBob(bob) != clsMod) return FALSE;
+ MsRangeOfMod(ImodFrBob(bob), &ims, &imsMac);
+
+ idxQyStart = (IDX)ims;
+ idxQyMac = (IDX)imsMac;
+
+ break;
+ }
+
+ case qyCalls:
+ {
+ IUSE iuse, iuseMac;
+
+ bobFn = BobQyCalls;
+ if (ClsOfBob(bob) != clsInst) return FALSE;
+ UseRangeOfInst(IinstFrBob(bob), &iuse, &iuseMac);
+
+ idxQyStart = (IDX)iuse;
+ idxQyMac = (IDX)iuseMac;
+
+ break;
+ }
+
+ case qyUses:
+ {
+ IUSE iuse, iuseMac;
+
+ bobFn = BobQyUses;
+ if (ClsOfBob(bob) != clsInst) return FALSE;
+ UseRangeOfInst(IinstFrBob(bob), &iuse, &iuseMac);
+
+ idxQyStart = (IDX)iuse;
+ idxQyMac = (IDX)iuseMac;
+
+ break;
+ }
+
+ case qyCalledBy:
+ {
+ IUBY iuby, iubyMac;
+
+ bobFn = BobQyCalledBy;
+ if (ClsOfBob(bob) != clsInst) return FALSE;
+ UbyRangeOfInst(IinstFrBob(bob), &iuby, &iubyMac);
+
+ idxQyStart = (IDX)iuby;
+ idxQyMac = (IDX)iubyMac;
+
+ break;
+ }
+
+ case qyUsedBy:
+ {
+ IUBY iuby, iubyMac;
+
+ bobFn = BobQyUsedBy;
+ if (ClsOfBob(bob) != clsInst) return FALSE;
+ UbyRangeOfInst(IinstFrBob(bob), &iuby, &iubyMac);
+
+ idxQyStart = (IDX)iuby;
+ idxQyMac = (IDX)iubyMac;
+
+ break;
+ }
+
+ case qyUsedIn:
+ {
+ IREF iref, irefMac;
+
+ bobFn = BobQyUsedIn;
+ if (ClsOfBob(bob) != clsInst) return FALSE;
+ RefRangeOfInst(IinstFrBob(bob), &iref, &irefMac);
+
+ idxQyStart = (IDX)iref;
+ idxQyMac = (IDX)irefMac;
+
+ break;
+ }
+
+ case qyDefinedIn:
+ {
+ IDEF idef, idefMac;
+
+ bobFn = BobQyDefinedIn;
+ if (ClsOfBob(bob) != clsInst) return FALSE;
+ DefRangeOfInst(IinstFrBob(bob), &idef, &idefMac);
+
+ idxQyStart = (IDX)idef;
+ idxQyMac = (IDX)idefMac;
+
+ break;
+ }
+
+ case qyRefs:
+ {
+ IINST iinst, iinstMac;
+
+ bobFn = BobQyRefs;
+
+ switch (ClsOfBob(bob)) {
+
+ default:
+ return FALSE;
+
+ case clsSym:
+ InstRangeOfSym(IsymFrBob(bob), &iinst, &iinstMac);
+
+ idxQyStart = (IDX)iinst;
+ idxQyMac = (IDX)iinstMac;
+ break;
+
+ case clsInst:
+ idxQyStart = (IDX)IinstFrBob(bob);
+ idxQyMac = idxQyStart+1;
+ break;
+ }
+
+ break;
+ }
+
+ case qyDefs:
+ {
+ IINST iinst, iinstMac;
+
+ bobFn = BobQyDefs;
+
+ switch (ClsOfBob(bob)) {
+
+ default:
+ return FALSE;
+
+ case clsSym:
+ InstRangeOfSym(IsymFrBob(bob), &iinst, &iinstMac);
+
+ idxQyStart = (IDX)iinst;
+ idxQyMac = (IDX)iinstMac;
+ break;
+
+ case clsInst:
+ idxQyStart = (IDX)IinstFrBob(bob);
+ idxQyMac = idxQyStart+1;
+ break;
+ }
+
+ break;
+ }
+ }
+
+ idxQyCur = idxQyStart;
+ return TRUE;
+}
+
+BOB BSC_API
+BobNext()
+// return the next Bob in the query
+{
+ if (idxQyCur < idxQyMac && bobFn != NULL)
+ return (*bobFn)();
+
+ return bobNil;
+}
+
+static BOB
+BobQyFiles()
+// return the next File in a file query
+//
+{
+ BOB bob;
+
+ while (idxQyCur < idxQyMac) {
+ IMS ims1, ims2;
+
+ MsRangeOfMod((IMOD)idxQyCur, &ims1, &ims2);
+ if (ims1 != ims2) {
+ bob = BobFrClsIdx(clsMod, idxQyCur);
+ idxQyCur++;
+ return bob;
+ }
+ else
+ idxQyCur++;
+ }
+ return bobNil;
+}
+
+static BOB
+BobQySymbols ()
+// get the next symbol in a symbol query
+//
+{
+ BOB bob;
+
+ bob = BobFrClsIdx(clsInst, idxQyCur);
+ idxQyCur++;
+ return bob;
+}
+
+static BOB
+BobQyContains ()
+// get the next symbol in a contains query
+//
+{
+ BOB bob;
+
+ bob = BobFrClsIdx(clsInst, IinstOfIms((IMS)idxQyCur));
+ idxQyCur++;
+ return bob;
+}
+
+static BOB
+BobQyCalls ()
+// get the next symbol which query focus calls
+//
+{
+ WORD cuse;
+ IINST iinst;
+ ISYM isym;
+ TYP typ;
+ ATR atr;
+ BOB bob;
+
+ for (; idxQyCur < idxQyMac; idxQyCur++) {
+
+ UseInfo((IUSE)idxQyCur, &iinst, &cuse);
+ InstInfo(iinst, &isym, &typ, &atr);
+
+ if (typ > INST_TYP_LABEL)
+ continue;
+
+ bob = BobFrClsIdx(clsInst, iinst);
+ idxQyCur++;
+ return bob;
+ }
+ return bobNil;
+}
+
+static BOB
+BobQyCalledBy ()
+// get the next symbol which query focus is called by
+//
+{
+ WORD cuse;
+ IINST iinst;
+ ISYM isym;
+ TYP typ;
+ ATR atr;
+ BOB bob;
+
+ for (; idxQyCur < idxQyMac; idxQyCur++) {
+
+ UbyInfo((IUBY)idxQyCur, &iinst, &cuse);
+ InstInfo(iinst, &isym, &typ, &atr);
+
+ if (typ > INST_TYP_LABEL)
+ continue;
+
+ bob = BobFrClsIdx(clsInst, iinst);
+ idxQyCur++;
+ return bob;
+ }
+ return bobNil;
+}
+
+static BOB
+BobQyUses ()
+// get the next symbol which query focus calls
+//
+{
+ WORD cuse;
+ IINST iinst;
+ BOB bob;
+
+ UseInfo((IUSE)idxQyCur, &iinst, &cuse);
+ bob = BobFrClsIdx(clsInst, iinst);
+ idxQyCur++;
+ return bob;
+}
+
+static BOB
+BobQyUsedBy ()
+// get the next symbol which query focus calls
+//
+{
+ WORD cuse;
+ IINST iinst;
+ BOB bob;
+
+ UbyInfo((IUBY)idxQyCur, &iinst, &cuse);
+ bob = BobFrClsIdx(clsInst, iinst);
+ idxQyCur++;
+ return bob;
+}
+
+static BOB
+BobQyUsedIn ()
+// get the next module which query focus is used in
+//
+{
+ WORD wLine;
+ BOB bob;
+ LSZ lszMod;
+
+ for ( ; idxQyCur < idxQyMac ; idxQyCur++) {
+ RefInfo((IREF)idxQyCur, &lszMod, &wLine);
+
+ if (strcmp(lszMod, lszModLast) == 0)
+ continue;
+
+ strcpy(lszModLast, lszMod);
+
+ bob = BobFrClsIdx(clsMod, ImodFrLsz(lszMod));
+ idxQyCur++;
+ return bob;
+ }
+ return bobNil;
+}
+
+static BOB
+BobQyDefinedIn ()
+// get the next module which query focus is defined in
+//
+{
+ WORD wLine;
+ LSZ lszMod;
+ BOB bob;
+
+ for ( ; idxQyCur < idxQyMac ; idxQyCur++) {
+ DefInfo((IDEF)idxQyCur, &lszMod, &wLine);
+
+ if (strcmp(lszMod, lszModLast) == 0)
+ continue;
+
+ strcpy(lszModLast, lszMod);
+
+ bob = BobFrClsIdx(clsMod, ImodFrLsz(lszMod));
+ idxQyCur++;
+ return bob;
+ }
+ return bobNil;
+}
+
+LSZ BSC_API
+LszNameFrBob(BOB bob)
+// return the name of the given bob
+//
+{
+ switch (ClsOfBob(bob)) {
+
+ case clsMod:
+ return LszNameFrMod(ImodFrBob(bob));
+
+ case clsSym:
+ return LszNameFrSym(IsymFrBob(bob));
+
+ case clsInst:
+ {
+ ISYM isym;
+ TYP typ;
+ ATR atr;
+
+ InstInfo(IinstFrBob(bob), &isym, &typ, &atr);
+ return LszNameFrSym(isym);
+ }
+
+ case clsRef:
+ {
+ LSZ lsz;
+ WORD wLine;
+
+ RefInfo(IrefFrBob(bob), &lsz, &wLine);
+ return lsz;
+ }
+
+ case clsDef:
+ {
+ LSZ lsz;
+ WORD wLine;
+
+ DefInfo(IdefFrBob(bob), &lsz, &wLine);
+ return lsz;
+ }
+
+ default:
+ return "?";
+ }
+}
+
+BOB BSC_API
+BobFrName(LSZ lszName)
+// return the best bob we can find from the given name
+//
+{
+ ISYM isym;
+ IMOD imod, imodMac;
+ IINST iinst, iinstMac;
+
+ if ((isym = IsymFrLsz(lszName)) != isymNil) {
+ InstRangeOfSym(isym, &iinst, &iinstMac);
+ return BobFrClsIdx(clsInst, iinst);
+ }
+
+ if ((imod = ImodFrLsz(lszName)) != imodNil) {
+ return BobFrClsIdx(clsMod, imod);
+ }
+
+ imodMac = ImodMac();
+
+ // no exact match -- try short names
+ lszName = LszBaseName(lszName);
+ for (imod = 0; imod < imodMac; imod++)
+ if (_stricmp(lszName, LszBaseName(LszNameFrMod(imod))) == 0)
+ return BobFrClsIdx(clsMod, imod);
+
+ return bobNil;
+}
+
+static BOB
+BobQyRefs()
+// return the next File in a file query
+//
+{
+ BOB bob;
+ static IREF iref, irefMac;
+
+ for (;;) {
+ if (!fWorking) {
+ for ( ; idxQyCur < idxQyMac ; idxQyCur++) {
+
+ RefRangeOfInst((IINST)idxQyCur, &iref, &irefMac);
+ if (iref != irefMac)
+ break;
+ }
+ if (idxQyCur >= idxQyMac)
+ return bobNil;
+
+ fWorking = TRUE;
+ }
+
+ if (iref < irefMac) {
+ bob = BobFrClsIdx(clsRef, iref);
+ iref++;
+ return bob;
+ }
+
+ idxQyCur++;
+ fWorking = FALSE;
+ }
+}
+
+static BOB
+BobQyDefs()
+// return the next File in a file query
+//
+{
+ BOB bob;
+ static IDEF idef, idefMac;
+
+ for (;;) {
+ if (!fWorking) {
+ for ( ; idxQyCur < idxQyMac ; idxQyCur++) {
+
+ DefRangeOfInst((IINST)idxQyCur, &idef, &idefMac);
+ if (idef != idefMac)
+ break;
+ }
+ if (idxQyCur >= idxQyMac)
+ return bobNil;
+
+ fWorking = TRUE;
+ }
+
+ if (idef < idefMac) {
+ bob = BobFrClsIdx(clsDef, idef);
+ idef++;
+ return bob;
+ }
+
+ idxQyCur++;
+ fWorking = FALSE;
+ }
+}
diff --git a/private/utils/mep/browser/bsc/revtree.c b/private/utils/mep/browser/bsc/revtree.c
new file mode 100644
index 000000000..45d801553
--- /dev/null
+++ b/private/utils/mep/browser/bsc/revtree.c
@@ -0,0 +1,198 @@
+//
+// revtree.c
+//
+// two routines for printing out ascii reverse call tree's
+//
+#include <stdio.h>
+#include <string.h>
+#if defined(OS2)
+#define INCL_NOCOMMON
+#define INCL_DOSPROCESS
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSFILEMGR
+#define INCL_DOSERRORS
+#define INCL_DOSMISC
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include <dos.h>
+
+
+#include "hungary.h"
+#include "bsc.h"
+#include "bscsup.h"
+
+// forward declarations
+static BOOL FUsedInst(IINST iinst);
+static VOID dRevTree(IINST iinst, WORD cuby);
+
+
+// static variables
+static BYTE *UbyBits = NULL;
+static WORD cNest = 0;
+
+VOID BSC_API
+RevTreeInst (IINST iinst)
+// emit the call tree starting from the given inst
+//
+{
+ WORD iinstMac;
+ int igrp;
+
+ iinstMac = IinstMac();
+
+ // allocate memory for bit array
+ UbyBits = LpvAllocCb((WORD)(iinstMac/8 + 1));
+
+ // no memory -- no call tree
+ if (!UbyBits) return;
+
+ igrp = iinstMac/8+1;
+
+ while (--igrp>=0)
+ UbyBits[igrp] = 0;
+
+ cNest = 0;
+
+ dRevTree(iinst, 1);
+
+ FreeLpv(UbyBits);
+}
+
+
+static VOID
+dRevTree (IINST iinst, WORD cuby)
+// emit the call tree starting from the given inst
+//
+// there are many block variables to keep the stack to a minimum...
+{
+ {
+ ISYM isym;
+
+ {
+ ATR atr;
+ TYP typ;
+
+ InstInfo(iinst, &isym, &typ, &atr);
+
+ if (typ > INST_TYP_LABEL)
+ return;
+ }
+
+
+ {
+ WORD i;
+ cNest++;
+ for (i = cNest; i; i--) BSCPrintf ("| ");
+ }
+
+ if (cuby > 1)
+ BSCPrintf ("%s[%d]", LszNameFrSym (isym), cuby);
+ else
+ BSCPrintf ("%s", LszNameFrSym (isym));
+ }
+
+ if (FUsedInst(iinst)) {
+ BSCPrintf ("...\n");
+ cNest--;
+ return;
+ }
+
+ BSCPrintf ("\n");
+
+ {
+ IUBY iuby, iubyMac;
+ IINST iinstUby;
+
+ UbyRangeOfInst(iinst, &iuby, &iubyMac);
+
+ for (; iuby < iubyMac; iuby++) {
+ UbyInfo(iuby, &iinstUby, &cuby);
+ dRevTree (iinstUby, cuby);
+ }
+ }
+
+ cNest--;
+}
+
+BOOL BSC_API
+FRevTreeLsz(LSZ lszName)
+// print out a call tree based on the given name
+//
+{
+ IMOD imod;
+ ISYM isym;
+
+ cNest = 0;
+
+ if (!lszName)
+ return FALSE;
+
+ {
+ IINST iinstMac;
+ int igrp;
+
+ iinstMac = IinstMac();
+
+ // allocate memory for bit array
+ UbyBits = LpvAllocCb((WORD)(iinstMac/8 + 1));
+
+ // no memory -- no call tree
+ if (!UbyBits) return FALSE;
+
+ igrp = iinstMac/8+1;
+
+ while (--igrp >= 0)
+ UbyBits[igrp] = 0;
+ }
+
+ if ((imod = ImodFrLsz (lszName)) != imodNil) {
+ IMS ims, imsMac;
+
+ MsRangeOfMod(imod, &ims, &imsMac);
+
+ BSCPrintf ("%s\n", LszNameFrMod (imod));
+
+ for ( ; ims < imsMac ; ims++)
+ dRevTree (IinstOfIms(ims), 1);
+
+ FreeLpv(UbyBits);
+ return TRUE;
+ }
+
+ if ((isym = IsymFrLsz (lszName)) != isymNil) {
+ IINST iinst, iinstMac;
+
+ BSCPrintf ("%s\n", LszNameFrSym (isym));
+
+ InstRangeOfSym(isym, &iinst, &iinstMac);
+
+ for (; iinst < iinstMac; iinst++)
+ dRevTree (iinst, 1);
+
+ FreeLpv(UbyBits);
+ return TRUE;
+ }
+
+ FreeLpv(UbyBits);
+ return FALSE;
+}
+
+static BOOL
+FUsedInst(IINST iinst)
+// return the status bit for this iinst and set it true
+//
+{
+ WORD igrp;
+ BOOL fOut;
+ WORD mask;
+
+ igrp = iinst / 8;
+ mask = (1 << (iinst % 8));
+
+ fOut = !!(UbyBits[igrp] & mask);
+ UbyBits[igrp] |= mask;
+ return fOut;
+}
diff --git a/private/utils/mep/browser/bsc/sources b/private/utils/mep/browser/bsc/sources
new file mode 100644
index 000000000..81ae33220
--- /dev/null
+++ b/private/utils/mep/browser/bsc/sources
@@ -0,0 +1,26 @@
+MAJORCOMP=sdktools
+MINORCOMP=bsc
+
+TARGETNAME=bsc
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+INCLUDES=.;..\inc;..\..\ztools\inc
+
+SOURCES= bsc.c \
+ bscdump.c \
+ calltree.c \
+ dump.c \
+ filter.c \
+ format.c \
+ listref.c \
+ outline.c \
+ printf.c \
+ query.c \
+ revtree.c \
+ stats.c \
+ wild.c
+
+
+C_DEFINES=-D_OS2_20_=0 -DNO_EXT_KEYS -Dpascal= -Dfar= -DNOLANMAN -DNT
+UMTYPE=console
diff --git a/private/utils/mep/browser/bsc/stats.c b/private/utils/mep/browser/bsc/stats.c
new file mode 100644
index 000000000..81e2f4267
--- /dev/null
+++ b/private/utils/mep/browser/bsc/stats.c
@@ -0,0 +1,96 @@
+
+//
+// stats.c dump statistics about the database
+//
+#include <string.h>
+#include <stdio.h>
+#if defined(OS2)
+#define INCL_NOCOMMON
+#define INCL_DOSPROCESS
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSFILEMGR
+#define INCL_DOSERRORS
+#define INCL_DOSMISC
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include <dos.h>
+
+#include "hungary.h"
+#include "bsc.h"
+#include "bscsup.h"
+
+VOID BSC_API
+StatsBSC()
+// Dump statistics about the BSC using the output function
+//
+{
+ IMOD imod, imodMac;
+ IMS ims, imsMac;
+ ISYM isym, isymMac, isymT;
+ IINST iinst, iinstMac;
+ IDEF idef, idefMac;
+ IREF iref, irefMac;
+ IUSE iuse, iuseMac;
+ IUBY iuby, iubyMac;
+ TYP typ;
+ ATR atr;
+
+ isymMac = IsymMac();
+ imodMac = ImodMac();
+ MsRangeOfMod((IMOD)(imodMac-1), &ims, &imsMac);
+ InstRangeOfSym((ISYM)(isymMac-1), &iinst, &iinstMac);
+ RefRangeOfInst((IINST)(iinstMac-1), &iref, &irefMac);
+ DefRangeOfInst((IINST)(iinstMac-1), &idef, &idefMac);
+ UseRangeOfInst((IINST)(iinstMac-1), &iuse, &iuseMac);
+ UbyRangeOfInst((IINST)(iinstMac-1), &iuby, &iubyMac);
+
+ BSCPrintf("Totals\n------\n");
+ BSCPrintf("MOD : %d\n", imodMac);
+ BSCPrintf("MODSYM : %d\n", imsMac);
+ BSCPrintf("SYM : %d\n", isymMac);
+ BSCPrintf("INST : %d\n", iinstMac);
+ BSCPrintf("REF : %l\n", irefMac);
+ BSCPrintf("DEF : %d\n", idefMac);
+ BSCPrintf("USE : %d\n", iuseMac);
+ BSCPrintf("UBY : %d\n", iubyMac);
+
+ BSCPrintf("\n\nDetail\n\n");
+
+ for (imod = 0; imod < imodMac; imod++) {
+ MsRangeOfMod(imod, &ims, &imsMac);
+ BSCPrintf("%s Modsyms:%d\n", LszNameFrMod(imod), imsMac-ims);
+ }
+
+ isymMac = IsymMac();
+
+ for (isym = 0; isym < isymMac; isym++) {
+
+ InstRangeOfSym(isym, &iinst, &iinstMac);
+
+ for ( ;iinst < iinstMac; iinst++) {
+
+ DumpInst(iinst);
+ BSCPrintf(" ");
+
+ InstInfo(iinst, &isymT, &typ, &atr);
+
+ if (isym != isymT)
+ BSCPrintf("\t ERROR instance points back to wrong symbol!\n");
+
+ DefRangeOfInst(iinst, &idef, &idefMac);
+ BSCPrintf ("DEF %d ", idefMac-idef);
+
+ RefRangeOfInst(iinst, &iref, &irefMac);
+ BSCPrintf ("REF %d ", irefMac-iref);
+
+ UseRangeOfInst(iinst, &iuse, &iuseMac);
+ BSCPrintf ("USE %d ", iuseMac-iuse);
+
+ UbyRangeOfInst(iinst, &iuby, &iubyMac);
+ BSCPrintf ("UBY %d\n", iubyMac-iuby);
+ }
+ }
+}
diff --git a/private/utils/mep/browser/bsc/wild.c b/private/utils/mep/browser/bsc/wild.c
new file mode 100644
index 000000000..f07409541
--- /dev/null
+++ b/private/utils/mep/browser/bsc/wild.c
@@ -0,0 +1,73 @@
+// wild.c
+//
+// wildcard file matching
+//
+//
+#include <string.h>
+#if defined(OS2)
+#define INCL_NOCOMMON
+#define INCL_DOSPROCESS
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSFILEMGR
+#define INCL_DOSERRORS
+#define INCL_DOSMISC
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include <dos.h>
+
+#include "hungary.h"
+#include "bsc.h"
+
+BOOL BSC_API
+FWildMatch(LSZ pchPat, LSZ pchText)
+// return TRUE if pchText matchs pchPat in the dos wildcard sense
+//
+// REVIEW for 1.2 file name support
+//
+{
+ for (;;) {
+ switch (*pchPat) {
+ case '\0':
+ return *pchText == '\0';
+
+ case '.':
+ pchPat++;
+ switch (*pchText) {
+ case '.':
+ pchText++;
+ break;
+
+ case '\0':
+ break;
+
+ default:
+ return FALSE;
+ }
+ break;
+
+ case '*':
+ pchPat++;
+ while (*pchText != '\0' && *pchText != '.')
+ pchText++;
+ while (*pchPat != '\0' && *pchPat != '.')
+ pchPat++;
+ break;
+
+ case '?':
+ pchPat++;
+ if (*pchText != '\0' && *pchText != '.')
+ pchText++;
+ break;
+
+ default:
+ if (*pchText != *pchPat)
+ return FALSE;
+ pchPat++;
+ pchText++;
+ break;
+ }
+ }
+}
diff --git a/private/utils/mep/browser/bscdump/bscdump.c b/private/utils/mep/browser/bscdump/bscdump.c
new file mode 100644
index 000000000..82ffa3104
--- /dev/null
+++ b/private/utils/mep/browser/bscdump/bscdump.c
@@ -0,0 +1,324 @@
+/*
+ * BSCdump - Browser Data Base (.BSC) Dumper
+ * (C) 1988 By Microsoft
+ *
+ *
+ */
+#include <stdio.h>
+#include <string.h>
+#define LINT_ARGS
+#if defined(OS2)
+#define INCL_NOCOMMON
+#define INCL_DOSPROCESS
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSFILEMGR
+#define INCL_DOSERRORS
+#define INCL_DOSMISC
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include <dos.h>
+
+
+#include "bscdump.h"
+#include "version.h"
+#include "hungary.h"
+#include "bsc.h"
+#include "bscsup.h"
+#include "sbrvers.h"
+
+// this is gross but I don't know where these are supposed to come from
+//
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#if defined (DEBUG)
+char fDEBUG = FALSE;
+#endif
+
+char *psymbol = NULL;
+char *OutlineFileName = NULL;
+char far * fname;
+
+extern char *strdup();
+
+void DumpRefsLsz(LSZ);
+void DumpDefsLsz(LSZ);
+void ListRdds(MBF);
+
+main (argc, argv)
+int argc;
+char *argv[];
+{
+ unsigned char Cont;
+ unsigned char fCalltree = FALSE;
+ unsigned char fSymRefs = FALSE;
+ unsigned char fSymDefs = FALSE;
+ unsigned char fRevtree = FALSE;
+ unsigned char fDumpStats = FALSE;
+ unsigned char fRedundant = FALSE;
+ MBF mbf = mbfNil, mbfRef = mbfNil, mbfRdd = mbfNil;
+
+ char *s;
+ --argc;
+ ++argv;
+ while (argc && ((**argv == '-') || (**argv == '-'))) {
+ Cont = TRUE;
+ while (Cont && *++*argv)
+ switch (**argv) {
+ case 'o':
+ s = *argv+1;
+ while (*s) {
+ switch (*s) {
+ case 'F': mbf |= mbfFuncs; break;
+ case 'M': mbf |= mbfMacros; break;
+ case 'V': mbf |= mbfVars; break;
+ case 'T': mbf |= mbfTypes; break;
+ }
+ s++;
+ }
+
+ if (mbf == mbfNil) mbf = mbfAll;
+ if (--argc == 0)
+ Usage();
+ OutlineFileName = *++argv;
+ Cont = FALSE;
+ break;
+
+ case 'l':
+ s = *argv+1;
+ while (*s) {
+ switch (*s) {
+ case 'F': mbfRef |= mbfFuncs; break;
+ case 'M': mbfRef |= mbfMacros; break;
+ case 'V': mbfRef |= mbfVars; break;
+ case 'T': mbfRef |= mbfTypes; break;
+ }
+ s++;
+ }
+
+ if (mbfRef == mbfNil) mbfRef = mbfAll;
+ Cont = FALSE;
+ break;
+
+ case 'u':
+ s = *argv+1;
+ while (*s) {
+ switch (*s) {
+ case 'F': mbfRdd |= mbfFuncs; break;
+ case 'M': mbfRdd |= mbfMacros; break;
+ case 'V': mbfRdd |= mbfVars; break;
+ case 'T': mbfRdd |= mbfTypes; break;
+ }
+ s++;
+ }
+
+ if (mbfRdd == mbfNil) mbfRdd = mbfAll;
+ Cont = FALSE;
+ break;
+
+ case 't':
+ if (--argc == 0) Usage();
+ psymbol = *++argv;
+ fCalltree = TRUE;
+ Cont = FALSE;
+ break;
+
+ case 'r':
+ if (--argc == 0) Usage();
+ psymbol = *++argv;
+ fSymRefs = TRUE;
+ Cont = FALSE;
+ break;
+
+ case 'd':
+ if (--argc == 0) Usage();
+ psymbol = *++argv;
+ fSymDefs = TRUE;
+ Cont = FALSE;
+ break;
+
+ case 'b':
+ if (--argc == 0) Usage();
+ psymbol = *++argv;
+ fRevtree = TRUE;
+ Cont = FALSE;
+ break;
+
+ case 's':
+ fDumpStats = TRUE;
+ break;
+
+ default:
+ Usage();
+ break;
+ }
+ --argc;
+ ++argv;
+ }
+
+ if (argc < 1) {
+ Usage();
+ }
+
+ fname = strdup(*argv++);
+
+ if (!FOpenBSC(fname)) {
+ BSCPrintf("BSCdump: cannot open database %s\n", fname);
+ exit(4);
+ }
+
+ if (fDumpStats)
+ StatsBSC();
+ else if (fCalltree)
+ FCallTreeLsz(psymbol);
+ else if (fSymRefs)
+ DumpRefsLsz(psymbol);
+ else if (fSymDefs)
+ DumpDefsLsz(psymbol);
+ else if (fRevtree)
+ FRevTreeLsz(psymbol);
+ else if (OutlineFileName)
+ FOutlineModuleLsz(OutlineFileName, mbf);
+ else if (mbfRef)
+ ListRefs(mbfRef);
+ else if (mbfRdd)
+ ListRdds(mbfRdd);
+ else
+ DumpBSC();
+
+ CloseBSC();
+
+ free (fname);
+}
+
+Usage()
+{
+ BSCPrintf("Microsoft (R) BSCdump Utility ");
+ BSCPrintf(VERS(rmj, rmm, rup));
+ BSCPrintf(CPYRIGHT);
+
+ BSCPrintf("Usage: bscdump [options] file.bsc\n\n");
+ BSCPrintf(" -o[FVMT] <file> outline\n");
+ BSCPrintf(" -l[FVMT] List References\n");
+ BSCPrintf(" -u[FVMT] List Redundant definitions\n");
+ BSCPrintf(" -t <sym> Calltree <sym>\n");
+ BSCPrintf(" -b <sym> Backwards Calltree <sym>\n");
+ BSCPrintf(" -s Emit BSC stats\n");
+ BSCPrintf(" -r <sym> List all references to symbol\n");
+ BSCPrintf(" -d <sym> List all definitions of symbol\n");
+ exit(1);
+}
+
+void DumpDefsLsz(LSZ lszSym)
+{
+ ISYM isym;
+ IINST iinst, iinstMac;
+ IDEF idef, idefMac;
+ LSZ lsz;
+ WORD line;
+
+ isym = IsymFrLsz(lszSym);
+
+ if (isym == isymNil) {
+ BSCPrintf("unknown symbol %s\n", lszSym);
+ return;
+ }
+
+ InstRangeOfSym(isym, &iinst, &iinstMac);
+
+ for (;iinst < iinstMac; iinst++) {
+
+ DefRangeOfInst(iinst, &idef, &idefMac);
+
+ for ( ; idef < idefMac; idef++) {
+ DefInfo(idef, &lsz, &line);
+ BSCPrintf("%s %d\n", lsz, line);
+ }
+ }
+
+}
+
+void DumpRefsLsz(LSZ lszSym)
+{
+ ISYM isym;
+ IINST iinst, iinstMac;
+ IREF iref, irefMac;
+ LSZ lsz;
+ WORD line;
+
+ isym = IsymFrLsz(lszSym);
+
+ if (isym == isymNil) {
+ BSCPrintf("unknown symbol %s\n", lszSym);
+ return;
+ }
+
+ InstRangeOfSym(isym, &iinst, &iinstMac);
+
+ for (;iinst < iinstMac; iinst++) {
+
+ RefRangeOfInst(iinst, &iref, &irefMac);
+
+ for ( ; iref < irefMac; iref++) {
+ RefInfo(iref, &lsz, &line);
+ BSCPrintf("%s %d\n", lsz, line);
+ }
+ }
+
+}
+
+void ListRdds(MBF mbf)
+{
+ ISYM isym, isymMac, isymname;
+ IINST iinst, iinstMac;
+ IUBY iubyFirst, iubyLast;
+ LSZ lszsymname;
+ TYP iinsttyp;
+ ATR iinstattr;
+
+ isymMac = IsymMac();
+
+ for (isym = 0 ; isym < isymMac ; isym++)
+ {
+ lszsymname = LszNameFrSym(isym);
+ InstRangeOfSym(isym,&iinst,&iinstMac);
+
+ for ( ; iinst < iinstMac ; iinst++)
+ {
+ UbyRangeOfInst(iinst,&iubyFirst,&iubyLast);
+
+ if (iubyFirst == iubyLast)
+ {
+ InstInfo(iinst,&isymname, &iinsttyp, &iinstattr);
+
+ // iinstattr &= INST_TYPMASK;
+
+ if (iinsttyp <= INST_TYP_LABEL && !!(mbf & mbfFuncs))
+
+ BSCPrintf("Function not called : %s\n",lszsymname);
+
+ else if
+ ((iinsttyp <= INST_TYP_VARIABLE ||
+ iinsttyp >= INST_TYP_SEGMENT ) && !!(mbf & mbfVars))
+
+ BSCPrintf("Variable not used : %s\n",lszsymname);
+
+ else if
+ (iinsttyp <= INST_TYP_MACRO && !!(mbf & mbfMacros))
+
+ BSCPrintf("Macro not referenced : %s\n",lszsymname);
+
+ else if (!!(mbf & mbfTypes))
+
+ BSCPrintf("Type not referenced : %s\n",lszsymname);
+
+ }
+ }
+ }
+}
diff --git a/private/utils/mep/browser/bscdump/bscdump.h b/private/utils/mep/browser/bscdump/bscdump.h
new file mode 100644
index 000000000..da2c4f157
--- /dev/null
+++ b/private/utils/mep/browser/bscdump/bscdump.h
@@ -0,0 +1,15 @@
+/*** bscdump.h
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+*
+* 28-Jul-1989 dw Removed extraneous defs of TRUE, FALSE
+* 05-Jul-1989 mt Added the option to list redundant symbols
+*
+*************************************************************************/
+#define BUFLEN 251
+#define EXTERNAL near
+
+typedef char flagType;
+typedef char buffer[BUFLEN];
diff --git a/private/utils/mep/browser/bscdump/makefile b/private/utils/mep/browser/bscdump/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/mep/browser/bscdump/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/mep/browser/bscdump/sources b/private/utils/mep/browser/bscdump/sources
new file mode 100644
index 000000000..ef27a5200
--- /dev/null
+++ b/private/utils/mep/browser/bscdump/sources
@@ -0,0 +1,21 @@
+MAJORCOMP=sdktools
+MINORCOMP=bscdump
+
+TARGETNAME=bscdump
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+
+INCLUDES=.;..\inc;\nt\private\sdktools\ztools\inc
+
+SOURCES= thunk.c
+
+
+
+UMAPPL=bscdump
+
+
+
+C_DEFINES=-D_OS2_20_=0 -DNO_EXT_KEYS -Dpascal= -Dfar= -DNOLANMAN -DNT
+UMTYPE=console
+UMLIBS= obj\*\bscdump.lib ..\bsc\obj\*\bsc.lib \nt\private\sdktools\ztools\src\obj\*\ztools.lib
diff --git a/private/utils/mep/browser/bscdump/thunk.c b/private/utils/mep/browser/bscdump/thunk.c
new file mode 100644
index 000000000..eb16cd3a4
--- /dev/null
+++ b/private/utils/mep/browser/bscdump/thunk.c
@@ -0,0 +1,174 @@
+// calback.c
+//
+// these are the default callbacks for the library
+//
+#include <string.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <io.h>
+#if defined(OS2)
+#define INCL_NOCOMMON
+#define INCL_DOSPROCESS
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSFILEMGR
+#define INCL_DOSERRORS
+#define INCL_DOSMISC
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include <dos.h>
+
+#include "hungary.h"
+#include "bsc.h"
+
+typedef char bscbuf[2048];
+
+// you must define the following callbacks for the library to use
+
+LPV BSC_API LpvAllocCb(WORD cb)
+// allocate a block of memory
+//
+{
+ return malloc(cb);
+}
+
+VOID BSC_API FreeLpv(LPV lpv)
+// free a block of memory
+//
+{
+ free(lpv);
+}
+
+VOID BSC_API SeekError(LSZ lszFileName) // do not return!
+// error handling
+//
+{
+ BSCPrintf("BSC Library: Error seeking in file '%s'\n", lszFileName);
+ exit(1);
+}
+
+VOID BSC_API ReadError(LSZ lszFileName) // do not return!
+// error handling
+//
+{
+ BSCPrintf("BSC Library: Error reading in file '%s'\n", lszFileName);
+ exit(1);
+}
+
+VOID BSC_API BadBSCVer(LSZ lszFileName) // do not return!
+// error handling
+//
+{
+ BSCPrintf("BSC Library: '%s' not in current .bsc format\n", lszFileName);
+ exit(1);
+}
+
+FILEHANDLE BSC_API
+BSCOpen(LSZ lszFileName, FILEMODE mode)
+// open the specified file
+//
+{
+#if defined (OS2)
+ bscbuf b;
+ strcpy(b, lszFileName);
+ return open(b, mode);
+#else
+ return OpenFile( lszFileName, mode, FALSE, FILE_SHARE_READ);
+#endif
+
+}
+
+int BSC_API
+BSCRead(FILEHANDLE handle, LPCH lpchBuf, WORD cb)
+// read in the specified number of bytes
+//
+{
+#if defined (OS2)
+ bscbuf b;
+
+ while (cb > sizeof(b)) {
+ if (read(handle, b, sizeof(b)) == -1) return -1;
+ memcpy(lpchBuf, b, sizeof(b));
+ cb -= sizeof(b);
+ lpchBuf += sizeof(b);
+ }
+
+ if (read(handle, b, cb) == -1) return -1;
+ memcpy(lpchBuf, b, cb);
+ return cb;
+#else
+ return ReadFile(handle, lpchBuf, cb);
+#endif
+
+}
+
+int BSC_API
+BSCClose(FILEHANDLE handle)
+// close the specified handle
+//
+{
+#if defined (OS2)
+ return close(handle);
+#else
+ return !CloseHandle( handle );
+#endif
+
+}
+
+int BSC_API
+BSCSeek(FILEHANDLE handle, long lPos, FILEMODE mode)
+// seek on the specified handle
+//
+{
+#if defined (OS2)
+ if (lseek(handle, lPos, mode) == -1)
+ return -1;
+ else
+ return 0;
+#else
+ if (SetFilePointer( handle, lPos, 0L, mode) == -1) {
+ return -1;
+ } else {
+ return 0;
+ }
+#endif
+
+}
+
+VOID BSC_API
+BSCOutput(LSZ lsz)
+// write the given string to the standard output
+//
+{
+ bscbuf b;
+ int cb;
+
+ cb = strlen(lsz);
+
+ while (cb > sizeof(b)) {
+ memcpy(b, lsz, sizeof(b));
+
+ if (write(1, b, sizeof(b)) == -1) return;
+
+ cb -= sizeof(b);
+ lsz += sizeof(b);
+ }
+
+ memcpy(b, lsz, cb);
+ write(1, b, cb);
+ return;
+}
+
+#ifdef DEBUG
+VOID BSC_API
+BSCDebugOut(LSZ lsz)
+// ignore debug output by default
+//
+{
+ // unreferenced lsz
+ lsz = NULL;
+}
+#endif
diff --git a/private/utils/mep/browser/dirs b/private/utils/mep/browser/dirs
new file mode 100644
index 000000000..52fcdbe99
--- /dev/null
+++ b/private/utils/mep/browser/dirs
@@ -0,0 +1,25 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+
+!ENDIF
+
+DIRS=bsc \
+ mbrmake
+
+OPTIONAL_DIRS=
diff --git a/private/utils/mep/browser/inc/bsc.h b/private/utils/mep/browser/inc/bsc.h
new file mode 100644
index 000000000..6286baabd
--- /dev/null
+++ b/private/utils/mep/browser/inc/bsc.h
@@ -0,0 +1,228 @@
+
+// bsc.h
+//
+
+#include <stdarg.h>
+
+#define BSC_API far
+
+#if defined (OS2)
+typedef int FILEHANDLE;
+typedef int FILEMODE;
+#else
+typedef HANDLE FILEHANDLE;
+typedef DWORD FILEMODE;
+#endif
+
+//////////////////////////////////////////////////////////////////////
+// you must define the following callbacks for the library to use
+// to avoid dependancy on the C standard io library. If you don't
+// define these then you accept the defaults which call C runtime
+//
+
+// malloc and free workalikes
+
+LPV BSC_API LpvAllocCb(WORD cb);
+VOID BSC_API FreeLpv(LPV lpv);
+
+// open, read, close, seek workalikes
+
+FILEHANDLE BSC_API BSCOpen(LSZ lszFileName, FILEMODE mode);
+int BSC_API BSCRead(FILEHANDLE handle, LPCH lpchBuf, WORD cb);
+int BSC_API BSCSeek(FILEHANDLE handle, long lPos, FILEMODE mode);
+int BSC_API BSCClose(FILEHANDLE handle);
+
+
+// ascii text output routine
+
+VOID BSC_API BSCOutput(LSZ lsz);
+
+#ifdef DEBUG
+VOID BSC_API BSCDebugOut(LSZ lsz);
+VOID BSC_API BSCDebug(LSZ lszFormat, ...);
+#endif
+
+// error handling routines
+//
+VOID BSC_API SeekError(LSZ lszFileName); // (may choose to not return)
+VOID BSC_API ReadError(LSZ lszFileName); // (may choose to not return)
+VOID BSC_API BadBSCVer(LSZ lszFileName); // (may choose to not return)
+
+// end of callbacks
+//
+///////////////////////////////////////////////////////////////////////
+
+// an IDX is guaranteed to be big enough to hold any of the
+// database index types, i.e. it is a generic index
+
+typedef DWORD IDX;
+
+#define idxNil 0xffffffffL
+#define isymNil 0xffffL
+#define imodNil 0xffffL
+
+// definition and prototypes for use with the bsc library
+//
+typedef WORD IMOD;
+typedef WORD IMS;
+typedef WORD ISYM;
+typedef WORD IINST;
+typedef DWORD IREF;
+typedef WORD IDEF;
+typedef WORD IUSE;
+typedef WORD IUBY;
+typedef WORD TYP;
+typedef WORD ATR;
+
+// Open the specified data base.
+// Return TRUE iff successful, FALSE if database can't be read
+//
+BOOL BSC_API FOpenBSC (LSZ lszName);
+
+// close database and free as much memory as possible
+//
+VOID BSC_API CloseBSC(VOID);
+
+// return the length of the largest symbol in the database
+//
+WORD BSC_API BSCMaxSymLen(VOID);
+
+// is this database built with a case sensitive language?
+//
+BOOL BSC_API FCaseBSC(VOID);
+
+// override the case sensitivity of the database, symbol lookups become
+// case (in)sensistive as specified
+//
+VOID BSC_API SetCaseBSC(BOOL fCaseSensitive);
+
+// do a case insenstive compare qualified by a case sensitive compare
+// if fCase is true -- this is the order of symbols in the symbol list
+int BSC_API CaseCmp(LSZ lsz1, LSZ lsz2);
+
+// return the name of the given symbol
+//
+LSZ BSC_API LszNameFrSym (ISYM isym);
+
+// return the name of the given module
+//
+LSZ BSC_API LszNameFrMod (IMOD imod);
+
+// return the imod with the given name -- imodNil if none
+//
+IMOD BSC_API ImodFrLsz(LSZ lszModName);
+
+// return the isym with the given name -- isymNil if none
+//
+ISYM BSC_API IsymFrLsz(LSZ lszSymName);
+
+// return the biggest isym in this database, isyms run from 0 to this value - 1
+//
+ISYM BSC_API IsymMac(VOID);
+
+// return the biggest imod in this database, imods run from 0 to this value - 1
+//
+IMOD BSC_API ImodMac(VOID);
+
+// return the biggest iinst in this database, iinsts run from 0 to the value -1
+IINST BSC_API IinstMac(VOID);
+
+// fill in the range of MS items valid for this module
+//
+VOID BSC_API MsRangeOfMod(IMOD imod, IMS far *pimsFirst, IMS far *pimsLast);
+
+// give the instance index of the module symbol (MS)
+//
+IINST BSC_API IinstOfIms(IMS ims);
+
+// fill in the range of inst values for this symbol
+//
+VOID BSC_API InstRangeOfSym(ISYM isym, IINST far *piinstFirst, IINST far *piinstLast);
+
+// get the information that qualifies this instance
+//
+VOID BSC_API InstInfo(IINST iinst, ISYM far *pisymInst, TYP far *typ, ATR far *atr);
+
+// fill in the reference ranges from the inst
+//
+VOID BSC_API RefRangeOfInst(IINST iinst, IREF far *pirefFirst, IREF far *pirefLast);
+
+// fill in the definition ranges from the inst
+//
+VOID BSC_API DefRangeOfInst(IINST iinst, IDEF far *pidefFirst, IDEF far *pidefLast);
+
+// fill in the use ranges from the inst
+//
+VOID BSC_API UseRangeOfInst(IINST iinst, IUSE far *piuseFirst, IUSE far *piuseLast);
+
+// fill in the used by ranges from the inst
+//
+VOID BSC_API UbyRangeOfInst(IINST iinst, IUBY far *piubyFirst, IUBY far *piubyLast);
+
+// fill in the information about this things which an inst uses
+//
+VOID BSC_API UseInfo(IUSE iuse, IINST far *piinst, WORD far *pcnt);
+
+// fill in the information about this things which an inst is used by
+//
+VOID BSC_API UbyInfo(IUBY iuby, IINST far *piinst, WORD far *pcnt);
+
+// fill in the information about this reference
+//
+VOID BSC_API RefInfo(IREF iref, LSZ far *plszName, WORD far *pline);
+
+// fill in the information about this definition
+//
+VOID BSC_API DefInfo(IDEF idef, LSZ far *plszName, WORD far *pline);
+
+// these are the bit values for the InstInfo() TYP and ATR types
+//
+//
+
+// this is the type part of the field, it describes what sort of object
+// we are talking about. Note the values are sequential -- the item will
+// be exactly one of these things
+//
+
+#define INST_TYP_FUNCTION 0x01
+#define INST_TYP_LABEL 0x02
+#define INST_TYP_PARAMETER 0x03
+#define INST_TYP_VARIABLE 0x04
+#define INST_TYP_CONSTANT 0x05
+#define INST_TYP_MACRO 0x06
+#define INST_TYP_TYPEDEF 0x07
+#define INST_TYP_STRUCNAM 0x08
+#define INST_TYP_ENUMNAM 0x09
+#define INST_TYP_ENUMMEM 0x0A
+#define INST_TYP_UNIONNAM 0x0B
+#define INST_TYP_SEGMENT 0x0C
+#define INST_TYP_GROUP 0x0D
+
+// this is the attribute part of the field, it describes the storage
+// class and/or scope of the instance. Any combination of the bits
+// might be set by some language compiler, but there are some combinations
+// that done make sense.
+
+#define INST_ATR_LOCAL 0x001
+#define INST_ATR_STATIC 0x002
+#define INST_ATR_SHARED 0x004
+#define INST_ATR_NEAR 0x008
+#define INST_ATR_COMMON 0x010
+#define INST_ATR_DECL_ONLY 0x020
+#define INST_ATR_PUBLIC 0x040
+#define INST_ATR_NAMED 0x080
+#define INST_ATR_MODULE 0x100
+
+// simple minded printf replacements, only %d, %s supported -- SMALL
+
+VOID BSC_API BSCFormat(LPCH lpchOut, LSZ lszFormat, va_list va);
+VOID BSC_API BSCSprintf(LPCH lpchOut, LSZ lszFormat, ...);
+VOID BSC_API BSCPrintf(LSZ lszFormat, ...);
+
+
+// rjsa 10/22/90
+// Some runtime library functions are broken, so intrinsics have
+// to be used.
+// BUGBUG
+//#pragma intrinsic (memset, memcpy, memcmp)
+//#pragma intrinsic (strset, strcpy, strcmp, strcat, strlen)
diff --git a/private/utils/mep/browser/inc/bscsup.h b/private/utils/mep/browser/inc/bscsup.h
new file mode 100644
index 000000000..10f6cca24
--- /dev/null
+++ b/private/utils/mep/browser/inc/bscsup.h
@@ -0,0 +1,106 @@
+
+// bscsup.h
+//
+// BSC high level support functions
+//
+
+VOID BSC_API StatsBSC(VOID); // ascii dump of bsc statistics
+VOID BSC_API DumpBSC(VOID); // ascii dump of the .bsc file
+VOID BSC_API DumpInst(IINST iinst); // ascii dump of single inst (name + flags)
+LSZ BSC_API LszTypInst(IINST iinst); // ascii version of iinst type
+
+VOID BSC_API CallTreeInst (IINST iinst); // call tree from given inst
+BOOL BSC_API FCallTreeLsz(LSZ lszName); // call tree from given name
+
+VOID BSC_API RevTreeInst (IINST iinst); // reverse call tree from given inst
+BOOL BSC_API FRevTreeLsz(LSZ lszName); // reverse call tree from given name
+
+// Browse OBject
+
+typedef DWORD BOB;
+
+#define bobNil 0L
+
+typedef WORD CLS;
+
+#define clsMod 1
+#define clsInst 2
+#define clsRef 3
+#define clsDef 4
+#define clsUse 5
+#define clsUby 6
+#define clsSym 7
+
+#define BobFrClsIdx(cls, idx) ((((long)(cls)) << 24) | (idx))
+#define ClsOfBob(bob) (CLS)((bob) >> 24)
+
+#define ImodFrBob(bob) ((IMOD)(bob))
+#define IinstFrBob(bob) ((IINST)(bob))
+#define IrefFrBob(bob) ((IREF)((bob) & 0xffffffL))
+#define IdefFrBob(bob) ((IDEF)(bob))
+#define IuseFrBob(bob) ((IUSE)(bob))
+#define IubyFrBob(bob) ((IUBY)(bob))
+#define IsymFrBob(bob) ((ISYM)(bob))
+
+#define BobFrMod(x) (BobFrClsIdx(clsMod, (x)))
+#define BobFrSym(x) (BobFrClsIdx(clsSym, (x)))
+#define BobFrInst(x) (BobFrClsIdx(clsInst, (x)))
+#define BobFrRef(x) (BobFrClsIdx(clsDef, (x)))
+#define BobFrDef(x) (BobFrClsIdx(clsRef, (x)))
+#define BobFrUse(x) (BobFrClsIdx(clsUse, (x)))
+#define BobFrUby(x) (BobFrClsIdx(clsUby, (x)))
+
+// these are the query types
+//
+typedef enum _qy_ {
+ qyFiles, qySymbols, qyContains,
+ qyCalls, qyCalledBy, qyUses, qyUsedBy,
+ qyUsedIn, qyDefinedIn,
+ qyDefs, qyRefs
+} QY;
+
+// these are visible so that you can see how the query is progressing
+// you may not write on these -- these values may or may not have anything
+// to do with any database indices
+//
+
+extern IDX far idxQyStart;
+extern IDX far idxQyCur;
+extern IDX far idxQyMac;
+
+BOOL BSC_API InitBSCQuery (QY qy, BOB bob);
+BOB BSC_API BobNext(VOID);
+
+LSZ BSC_API LszNameFrBob(BOB bob);
+BOB BSC_API BobFrName(LSZ lsz);
+
+// these are the instance types you can filter on
+// they are called MBF's for historical reasons which are not clear to me
+//
+
+typedef WORD MBF;
+
+// these may be or'd together
+
+#define mbfNil 0
+#define mbfVars 1
+#define mbfFuncs 2
+#define mbfMacros 4
+#define mbfTypes 8
+#define mbfAll 15
+
+BOOL BSC_API FInstFilter (IINST iinst, MBF mbf);
+
+// show outline for the given files (by imod, or by Pattern)
+//
+VOID BSC_API OutlineMod(IMOD imod, MBF mbfReqd);
+BOOL BSC_API FOutlineModuleLsz (LSZ lszPattern, MBF mbfReqd);
+LSZ BSC_API LszBaseName(LSZ lsz);
+
+// list references for all symbols meeting the mbf requirement
+//
+BOOL BSC_API ListRefs (MBF mbfReqd);
+
+// DOS style wildcard matching
+//
+BOOL BSC_API FWildMatch(LSZ lszPat, LSZ lszText);
diff --git a/private/utils/mep/browser/inc/hungary.h b/private/utils/mep/browser/inc/hungary.h
new file mode 100644
index 000000000..0535ea6b0
--- /dev/null
+++ b/private/utils/mep/browser/inc/hungary.h
@@ -0,0 +1,31 @@
+// instant hungarian
+
+// base types
+//
+
+// #define FAR far
+// #define NEAR near
+
+// #define TRUE 1
+// #define FALSE 0
+
+// typedef void VOID;
+// typedef unsigned char BYTE;
+// typedef unsigned short WORD;
+// typedef int INT;
+// typedef unsigned long DWORD;
+// typedef long LONG;
+// typedef unsigned short BOOL;
+
+//typedef USHORT WORD;
+//typedef ULONG DWORD;
+
+// pointer types
+//
+typedef char NEAR * SZ;
+typedef char FAR * LSZ;
+typedef void FAR * LPV;
+typedef BYTE FAR * LPB;
+//typedef char FAR * LPCH;
+
+#define API NEAR pascal
diff --git a/private/utils/mep/browser/inc/mbrcache.h b/private/utils/mep/browser/inc/mbrcache.h
new file mode 100644
index 000000000..c0ae3b600
--- /dev/null
+++ b/private/utils/mep/browser/inc/mbrcache.h
@@ -0,0 +1,7 @@
+#define MAXATOMPAGETBL 32 /* # of Cache Pages */
+#define ATOMALLOC 512 /* Atom Cache page size */
+
+typedef struct pgetlb {
+ unsigned uPage; /* Cache page */
+ char far * pfAtomCache; /* Atom Cache loc */
+ } CACHEPAGE;
diff --git a/private/utils/mep/browser/inc/sbrbsc.h b/private/utils/mep/browser/inc/sbrbsc.h
new file mode 100644
index 000000000..26714fab7
--- /dev/null
+++ b/private/utils/mep/browser/inc/sbrbsc.h
@@ -0,0 +1,43 @@
+#define BSC_MAJ 1
+#define BSC_MIN 0
+#define BSC_UPD 4
+
+#pragma pack(1)
+
+typedef struct {
+ WORD ModName; // module name symbol index */
+ WORD mSymEnd; // last ModSym index */
+} MODLIST;
+
+typedef struct {
+ WORD ModSymProp; // sym 1st property index */
+} MODSYMLIST;
+
+typedef struct {
+ WORD PropEnd; // last Property index */
+ WORD Atom; // Atom cache sym idx */
+ WORD Page; // Atom cache sym page */
+} SYMLIST;
+
+typedef struct {
+ WORD PropName; // owner name symbol index
+ WORD PropAttr; // Property attribute
+ WORD DefEnd; // last Definition index
+ DWORD RefEnd; // last Reference index
+ WORD CalEnd; // last Calls/uses index
+ WORD CbyEnd; // last Calld/used index
+} PROPLIST;
+
+typedef struct {
+ WORD RefNam; // file name symbol index
+ WORD RefLin; // reference line number
+ WORD isbr; // sbr file this item is found in
+} REFLIST;
+
+typedef struct {
+ WORD UseProp; // symbol called/used (by)
+ BYTE UseCnt; // symbol called/used (by) cnt
+ WORD isbr; // sbr file this item is found in
+} USELIST;
+
+#pragma pack()
diff --git a/private/utils/mep/browser/inc/sbrfdef.h b/private/utils/mep/browser/inc/sbrfdef.h
new file mode 100644
index 000000000..a9ec4be0d
--- /dev/null
+++ b/private/utils/mep/browser/inc/sbrfdef.h
@@ -0,0 +1,65 @@
+// sdbfdef.h Source Browser .SBR file definitions
+
+#define S_EOF 255
+
+#define SBR_L_UNDEF 0 // Undefined
+#define SBR_L_BASIC 1 // Basic
+#define SBR_L_C 2 // C
+#define SBR_L_FORTRAN 3 // Fortran
+#define SBR_L_MASM 4 // MASM
+#define SBR_L_PASCAL 5 // Pascal
+#define SBR_L_COBOL 6 // Cobol
+
+#define SBR_REC_HEADER 0x00 // Header
+#define SBR_REC_MODULE 0x01 // Module definition
+#define SBR_REC_LINDEF 0x02 // Line Number
+#define SBR_REC_SYMDEF 0x03 // Symbol Definition
+#define SBR_REC_SYMREFUSE 0x04 // Symbol Reference
+#define SBR_REC_SYMREFSET 0x05 // Symbol Ref and assign
+#define SBR_REC_MACROBEG 0x06 // Macro Start
+#define SBR_REC_MACROEND 0x07 // Macro End
+#define SBR_REC_BLKBEG 0x08 // Block Start
+#define SBR_REC_BLKEND 0x09 // Block End
+#define SBR_REC_MODEND 0x0A // Module End
+#define SBR_REC_OWNER 0x0B // Set owner of current block
+
+
+// Column information is no longer supported in PWB 1.00 (ignored if present)
+
+#define SBR_REC_NOCOLUMN 1 // Missing column default 1
+
+#define SBR_TYPBITS 5
+#define SBR_TYPSHIFT 11
+#define SBR_TYPMASK (0x1f << SBR_TYPSHIFT)
+
+#define SBR_TYP_FUNCTION (0x01 << SBR_TYPSHIFT)
+#define SBR_TYP_LABEL (0x02 << SBR_TYPSHIFT)
+#define SBR_TYP_PARAMETER (0x03 << SBR_TYPSHIFT)
+#define SBR_TYP_VARIABLE (0x04 << SBR_TYPSHIFT)
+#define SBR_TYP_CONSTANT (0x05 << SBR_TYPSHIFT)
+#define SBR_TYP_MACRO (0x06 << SBR_TYPSHIFT)
+#define SBR_TYP_TYPEDEF (0x07 << SBR_TYPSHIFT)
+#define SBR_TYP_STRUCNAM (0x08 << SBR_TYPSHIFT)
+#define SBR_TYP_ENUMNAM (0x09 << SBR_TYPSHIFT)
+#define SBR_TYP_ENUMMEM (0x0A << SBR_TYPSHIFT)
+#define SBR_TYP_UNIONNAM (0x0B << SBR_TYPSHIFT)
+#define SBR_TYP_SEGMENT (0x0C << SBR_TYPSHIFT)
+#define SBR_TYP_GROUP (0x0D << SBR_TYPSHIFT)
+#define SBR_TYP_PROGRAM (0x0E << SBR_TYPSHIFT)
+
+#define SBR_ATRBITS 11
+#define SBR_ATRSHIFT 0
+#define SBR_ATRMASK (0x3ff << SBR_ATRSHIFT)
+
+#define SBR_ATR_LOCAL (0x001 << SBR_ATRSHIFT)
+#define SBR_ATR_STATIC (0x002 << SBR_ATRSHIFT)
+#define SBR_ATR_SHARED (0x004 << SBR_ATRSHIFT)
+#define SBR_ATR_NEAR (0x008 << SBR_ATRSHIFT)
+#define SBR_ATR_COMMON (0x010 << SBR_ATRSHIFT)
+#define SBR_ATR_DECL_ONLY (0x020 << SBR_ATRSHIFT)
+#define SBR_ATR_PUBLIC (0x040 << SBR_ATRSHIFT)
+#define SBR_ATR_NAMED (0x080 << SBR_ATRSHIFT)
+#define SBR_ATR_MODULE (0x100 << SBR_ATRSHIFT)
+
+#define SBR_VER_MAJOR 1 /* Major version */
+#define SBR_VER_MINOR 1 /* Minor version */
diff --git a/private/utils/mep/browser/inc/sbrvers.h b/private/utils/mep/browser/inc/sbrvers.h
new file mode 100644
index 000000000..d1718353d
--- /dev/null
+++ b/private/utils/mep/browser/inc/sbrvers.h
@@ -0,0 +1,7 @@
+/*
+ * use double macro level to force rup to be turned into string representation
+ */
+#define VERS(x,y,z) VERS2(x,y,z)
+#define VERS2(x,y,z) " Version " #x "." #y "." #z
+
+#define CPYRIGHT "\nCopyright (c) Microsoft Corp 1990. All rights reserved.\n\n"
diff --git a/private/utils/mep/browser/mbrmake/addtolst.c b/private/utils/mep/browser/mbrmake/addtolst.c
new file mode 100644
index 000000000..056bb7a89
--- /dev/null
+++ b/private/utils/mep/browser/mbrmake/addtolst.c
@@ -0,0 +1,1004 @@
+//
+// ADDTOLST.C - Add each record from the .SBR file to the approprate list.
+//
+
+#define LINT_ARGS
+
+#include "sbrfdef.h"
+#include "mbrmake.h"
+#include <ctype.h>
+
+// local types
+
+typedef struct _mstk {
+ struct _mstk FAR *pmstkPrev; // next module stack entry
+ VA vaCurMod; // saved current module
+ BOOL fDupMod; // saved dup module flag
+ BOOL fExclMod; // saved exclude module flag
+} MSTK, FAR * PMSTK;
+
+typedef struct _bstk {
+ struct _bstk FAR *pbstkPrev; // next block stack entry
+ VA vaOwnerProp; // saved current owner
+} BSTK, FAR * PBSTK;
+
+// static variables
+
+BOOL near fDupSym = FALSE; // TRUE if adding duplicate atom
+BOOL near cMacroDepth = 0; // depth of MACROBEG records
+WORD near ModCnt; // count of modules
+WORD near isbrCur; // current SBR file index
+
+VA near vaUnknownSym = vaNil; // Unknown symbol
+VA near vaUnknownMod = vaNil; // Unknown module
+
+static VA near vaOwnerProp = vaNil; // ptr to current procedure
+static BOOL near fDupMod = FALSE; // duplicate module
+static BOOL near fExclMod = FALSE; // exclude this module
+static BOOL near fFirstMod = TRUE; // this is 1st module of file
+
+static PMSTK pmstkRoot; // root of module stack
+static PBSTK pbstkRoot; // root of block stack
+
+// forward references
+
+static BOOL FSkipMacro(void);
+static VOID PushMstk(VOID);
+static VOID PushBstk(VOID);
+static VOID PopMstk(VOID);
+static VOID PopBstk(VOID);
+static VOID CheckStacksEmpty(VOID);
+
+VOID
+SBRCorrupt (char *psz)
+// sbr file corrupt -- print message
+//
+{
+
+#ifdef DEBUG
+ printf("Info = %s\n", psz);
+#else
+ // to make /W3 happy
+ psz;
+#endif
+
+ Error(ERR_SBR_CORRUPT, lszFName);
+}
+
+static VOID
+PushMstk (VOID)
+// stack the current module context -- occurs before SBR_REC_MODULE
+//
+{
+ PMSTK pmstk;
+
+ pmstk = LpvAllocCb(sizeof(*pmstk));
+
+ pmstk->vaCurMod = vaCurMod; // current module
+ pmstk->fDupMod = fDupMod; // dup module
+ pmstk->fExclMod = fExclMod; // exclude module
+ pmstk->pmstkPrev = pmstkRoot; // make stack links
+ pmstkRoot = pmstk; // root <- new
+}
+
+static VOID
+PushBstk (VOID)
+// stack the current block context -- occurs before SBR_REC_BLKBEG
+//
+{
+ PBSTK pbstk;
+
+ pbstk = LpvAllocCb(sizeof(*pbstk));
+
+ pbstk->vaOwnerProp = vaOwnerProp; // current owner
+ pbstk->pbstkPrev = pbstkRoot; // make stack links
+ pbstkRoot = pbstk; // root <- new
+}
+
+static VOID
+PopMstk (VOID)
+// restore previous module context -- occurs on SBR_REC_MODEND
+//
+{
+ PMSTK pmstk;
+
+ if (pmstkRoot == NULL) {
+#ifdef DEBUG
+ SBRCorrupt("Module stack empty but MODEND was found");
+#else
+ SBRCorrupt("");
+#endif
+ }
+
+ vaCurMod = pmstkRoot->vaCurMod; // get previous current module
+ fDupMod = pmstkRoot->fDupMod; // get previous dup mod flag
+ fExclMod = pmstkRoot->fExclMod; // get previous excl mod flag
+
+ pmstk = pmstkRoot;
+ pmstkRoot = pmstkRoot->pmstkPrev;
+
+ FreeLpv(pmstk);
+}
+
+static VOID
+PopBstk (VOID)
+// restore previous block context -- occurs on SBR_REC_BLKEND
+//
+{
+ PBSTK pbstk;
+
+ if (pbstkRoot == NULL) {
+#ifdef DEBUG
+ SBRCorrupt("Block stack empty but BLKEND was found");
+#else
+ SBRCorrupt("");
+#endif
+ }
+
+ vaOwnerProp = pbstkRoot->vaOwnerProp; // get previous current proc
+
+ pbstk = pbstkRoot;
+ pbstkRoot = pbstkRoot->pbstkPrev;
+
+ FreeLpv(pbstk);
+}
+
+static VOID
+CheckStacksEmpty(VOID)
+// check to make sure that both stacks are empty at the .sbr file EOF
+//
+{
+ if (pmstkRoot != NULL) {
+#ifdef DEBUG
+ SBRCorrupt("Module stack not empty at EOF");
+#else
+ SBRCorrupt("");
+#endif
+ }
+
+ if (pbstkRoot != NULL) {
+#ifdef DEBUG
+ SBRCorrupt("Block stack not empty at EOF");
+#else
+ SBRCorrupt("");
+#endif
+ }
+}
+
+BOOL
+FInExcList (LSZ lszName)
+// Is the module name in the exclude file list?
+//
+{
+ EXCLINK FAR * px;
+ LSZ lszAbs;
+
+ if (OptEs && !fFirstMod) {
+ if (lszName[0] == '\0') return FALSE;
+
+ if (lszName[0] == '/' || lszName[0] == '\\') return TRUE;
+ if (lszName[1] == ':' && lszName[2] == '/') return TRUE;
+ if (lszName[1] == ':' && lszName[2] == '\\') return TRUE;
+ }
+
+ px = pExcludeFileList;
+
+ // this name is relative to the path given in the header file
+ lszAbs = ToAbsPath(lszName, r_cwd);
+
+ while (px) {
+ if ((FWildMatch (px->pxfname, lszAbs)))
+ return TRUE;
+ px = px->xnext;
+ }
+ return FALSE;
+}
+
+static BOOL
+FSkipMacro()
+// return TRUE if this record should be skipped given that we are inside
+// of a macro definition (i.e cMacroDepth is known to be non-zero)
+//
+{
+ if (!OptEm)
+ return FALSE;
+
+ if ((r_rectyp == SBR_REC_BLKBEG) ||
+ (r_rectyp == SBR_REC_BLKEND) ||
+ (r_rectyp == SBR_REC_MACROEND))
+ return FALSE;
+
+ return TRUE;
+}
+
+VOID
+InstallSBR()
+// Read the next .sbr file and add all the defs/refs/cals/cbys etc to
+// the various lists
+//
+{
+ WORD nlen;
+
+ VA vaCurSym; // current symbol
+ VA vaProp; // current property
+ VA vaOrd; // current property temp
+
+ BOOL fSymSet = FALSE; // TRUE if symbol set reference
+
+ r_lineno = 0;
+
+ fExclMod = FALSE;
+ fFirstMod = TRUE; // we haven't seen the first MODULE record yet
+
+ vaUnknownSym = MbrAddAtom ("<Unknown>", TRUE); // unknown module name
+
+ if (vaUnknownMod == vaNil) {
+
+ vaUnknownMod = VaAllocGrpCb(grpMod, sizeof(MOD));
+
+ vaCurMod = vaUnknownMod;
+
+ gMOD(vaCurMod).csyms = 0;
+ cMOD.vaNameSym = vaUnknownSym;
+ pMOD(vaCurMod);
+
+ gSYM(vaUnknownSym).vaFirstProp = vaCurMod; // store pointer back to MOD
+ pSYM(vaUnknownSym);
+ ModCnt++;
+ }
+ else
+ fDupMod = (vaUnknownMod != 0);
+
+ vaCurMod = vaUnknownMod;
+
+ if (vaRootMod == vaNil)
+ vaRootMod = vaCurMod;
+
+ while (GetSBRRec() != S_EOF) {
+
+ #ifdef DEBUG
+ if (OptD & 1) DecodeSBR ();
+ #endif
+
+ if (cMacroDepth != 0) // skip SYMBOLS in macros if true
+ if (FSkipMacro ())
+ continue;
+
+ if (fExclMod) {
+ if ((r_rectyp == SBR_REC_MODULE) ||
+ (r_rectyp == SBR_REC_SYMDEF) ||
+ (r_rectyp == SBR_REC_MODEND)) {
+ ;
+ }
+ else
+ continue;
+ }
+
+ switch(r_rectyp) {
+
+ case SBR_REC_MODULE:
+ PushMstk (); // save state
+
+ r_lineno = 0; // reset line no.
+
+ fDupMod = FALSE; // go to a known state
+ fExclMod = FALSE;
+
+ if (fExclMod = FInExcList (r_bname)) {
+ #ifdef DEBUG
+ if (OptD & 256)
+ printf (" module excluded = %s\n", r_bname);
+ #endif
+ vaCurMod = vaUnknownMod;
+ }
+ else if ((vaCurMod = VaSearchModule (r_bname)) != vaNil) {
+ if (gMOD(vaCurMod).csyms == 0) {
+ fDupMod = TRUE;
+ #ifdef DEBUG
+ if (OptD & 256)
+ printf (" module redef = %s\n", r_bname);
+ #endif
+ }
+ else {
+ cMOD.csyms = 0;
+ pMOD(vaCurMod);
+
+ #ifdef DEBUG
+ if (OptD & 256)
+ printf (" module subst = %s\n", r_bname);
+ #endif
+ }
+ }
+ else {
+ SetVMClient(VM_ADD_MOD);
+ ModCnt++;
+ vaCurMod = VaAllocGrpCb(grpMod, sizeof(MOD));
+ gMOD(vaCurMod);
+ cMOD.vaFirstModSym = vaNil;
+ cMOD.csyms = 0;
+ cMOD.vaNameSym =
+ MbrAddAtom (ToCanonPath(r_bname, r_cwd, c_cwd), TRUE);
+ cMOD.vaNextMod = vaRootMod;
+ pMOD(vaCurMod);
+
+ vaRootMod = vaCurMod;
+
+ gSYM(cMOD.vaNameSym).vaFirstProp = vaCurMod; // ptr to MOD
+ pSYM(cMOD.vaNameSym);
+
+ SetVMClient(VM_MISC);
+ }
+
+ fFirstMod = FALSE;
+ break;
+
+ case SBR_REC_LINDEF:
+ break;
+
+ case SBR_REC_SYMDEF:
+
+ // if module is being excluded then just make the ord and prop entry
+ // in case it is referred to later.
+
+ // REVIEW For FORTRAN if ordinal is already defined
+ // REVIEW then this is a refined definition -- we
+ // REVIEW override the old definition with the new
+ // REVIEW one at this time -Rico
+
+ nlen = strlen (r_bname);
+ if (nlen > MaxSymLen) MaxSymLen = (BYTE)nlen;
+
+ vaCurSym = MbrAddAtom (r_bname, FALSE);
+ vaOrd = VaOrdAdd (); // add sym ord to ord list
+ gORD(vaOrd).vaOrdProp = VaPropAddToSym(vaCurSym);
+ pORD(vaOrd);
+
+ break;
+
+ case SBR_REC_OWNER:
+ if (!(vaProp = VaOrdFind(r_ordinal))) {
+ // emit error message in case of forward reference
+ // try to continue
+ //
+ #ifdef DEBUG
+ if (OptD & 4)
+ printf ("mbrmake: Owner Forward Reference(%d)\n",
+ r_ordinal);
+ #endif
+ break;
+ }
+ vaOwnerProp = vaProp;
+ break;
+
+ case SBR_REC_SYMREFSET:
+ fSymSet = TRUE;
+ // fall through
+
+ case SBR_REC_SYMREFUSE:
+
+ if (!(vaProp = VaOrdFind(r_ordinal))) {
+ // emit error message in case of forward reference
+ // try to continue
+ //
+ #ifdef DEBUG
+ if (OptD & 4)
+ printf ("mbrmake: Forward Reference(%d)\n", r_ordinal);
+ #endif
+ break;
+ }
+
+ AddRefProp (vaProp);
+ break;
+
+ case SBR_REC_BLKBEG:
+ PushBstk(); // save state
+ break;
+
+ case SBR_REC_MACROBEG:
+ cMacroDepth++;
+ break;
+
+ case SBR_REC_MACROEND:
+ cMacroDepth--;
+ break;
+
+ case SBR_REC_BLKEND:
+ PopBstk();
+ break;
+
+ case SBR_REC_MODEND:
+ PopMstk();
+ break;
+
+ default:
+ SBRCorrupt ("unknown rec type");
+ Fatal ();
+ break;
+
+ }
+ }
+
+ CheckStacksEmpty();
+}
+
+VOID
+AddCalProp(VA vaCurProp)
+// Add a symbol reference to the calling procedure's Calls/Uses list.
+//
+{
+ CAL cal;
+
+ SetVMClient(VM_SEARCH_CAL);
+
+ ENM_LIST (gPROP(vaOwnerProp).vaCalList, CAL) // proc call list
+
+ if (cCAL.vaCalProp == vaCurProp) {
+ cCAL.isbr = isbrCur;
+ cCAL.calcnt++; // multiple calls
+ ENM_PUT(CAL);
+ return;
+ }
+
+ ENM_END
+
+ cal.isbr = isbrCur;
+ cal.vaCalProp = vaCurProp; // symbol called or used
+ cal.calcnt = 1;
+
+ SetVMClient(VM_ADD_CAL);
+
+ VaAddList(&cPROP.vaCalList, &cal, sizeof(cal), grpCal);
+
+ pPROP(vaOwnerProp);
+
+ SetVMClient(VM_MISC);
+
+#ifdef DEBUG
+ if (OptD & 8) {
+ printf("New CAL for: ");
+ DebugDumpProp(vaOwnerProp);
+ }
+#endif
+}
+
+VOID
+AddCbyProp(VA vaCurProp)
+// Add a symbol reference to it's property Called/Used by list.
+//
+{
+ CBY cby;
+
+ SetVMClient(VM_SEARCH_CBY);
+
+ ENM_LIST (gPROP(vaCurProp).vaCbyList, CBY) // prop called/used by list
+
+ if (cCBY.vaCbyProp == vaOwnerProp) {
+ cCBY.isbr = isbrCur;
+ cCBY.cbycnt++;
+ ENM_PUT(CBY);
+ return;
+ }
+
+ ENM_END
+
+ cby.isbr = isbrCur;
+ cby.vaCbyProp = vaOwnerProp; // symbol we are called or used by
+ cby.cbycnt = 1;
+
+ SetVMClient(VM_ADD_CBY);
+
+ VaAddList(&cPROP.vaCbyList, &cby, sizeof(cby), grpCby);
+
+ pPROP(vaCurProp);
+
+ SetVMClient(VM_MISC);
+
+#ifdef DEBUG
+ if (OptD & 8) {
+ printf("New CBY for: ");
+ DebugDumpProp(vaCurProp);
+ }
+#endif
+}
+
+VOID
+AddRefProp(VA vaCurProp)
+// Add a symbol reference to it's property reference list.
+//
+{
+ VA vaRef, vaFileSym;
+
+ SetVMClient(VM_SEARCH_REF);
+
+ vaFileSym = gMOD(vaCurMod).vaNameSym;
+
+ gPROP(vaCurProp);
+
+ if (fDupMod) {
+ // try looking at the hint for this PROP if there is one, if there
+ // isn't then we're stuck -- we must search the whole REF list
+ //
+
+ if (vaRef = cPROP.vaHintRef) {
+ gREF(vaRef);
+
+ if (cREF.reflin == r_lineno) {
+ cREF.isbr = isbrCur;
+ pREF(vaRef);
+ SetVMClient(VM_MISC);
+ return;
+ }
+
+ vaRef = VaFrVp(cREF.vpNextRef);
+ if (vaRef) {
+ gREF(vaRef);
+ if (cREF.reflin == r_lineno) {
+ cREF.isbr = isbrCur;
+ pREF(vaRef);
+ cPROP.vaHintRef = vaRef;
+ pPROP(vaCurProp);
+ SetVMClient(VM_MISC);
+ return;
+ }
+ }
+ }
+
+ vaRef = VaFrVp(cPROP.vpFirstRef);
+
+ while (vaRef) {
+ gREF(vaRef);
+ if ((VaFrVp(cREF.vpFileSym) == vaFileSym) && // ignore multiple
+ (cREF.reflin == r_lineno)) { // references to same file & line
+ cREF.isbr = isbrCur;
+ pREF(vaRef);
+ cPROP.vaHintRef = vaRef;
+ pPROP(vaCurProp);
+ SetVMClient(VM_MISC);
+ return;
+ }
+ vaRef = VaFrVp(cREF.vpNextRef);
+ }
+ }
+ else {
+ if (vaRef = VaFrVp(cPROP.vpLastRef)) {
+ gREF(vaRef);
+ if (cREF.reflin == r_lineno &&
+ vaFileSym == VaFrVp(cREF.vpFileSym)) {
+ SetVMClient(VM_MISC);
+ return;
+ }
+ }
+ }
+
+ SetVMClient(VM_ADD_REF);
+
+ vaRef = VaAllocGrpCb(grpRef, sizeof(REF));
+
+ gREF(vaRef);
+ cREF.isbr = isbrCur;
+ cREF.reflin = r_lineno;
+
+ MkVpVa(cREF.vpFileSym, vaFileSym);
+
+ pREF(vaRef);
+
+ gPROP(vaCurProp);
+
+ AddTail (Ref, REF);
+
+ cPROP.cref++; // count references
+ cPROP.vaHintRef = vaRef;
+
+ pPROP(vaCurProp);
+
+#ifdef DEBUG
+ if (OptD & 8) {
+ printf("New REF for: ");
+ DebugDumpProp(vaCurProp);
+ }
+#endif
+
+ SetVMClient(VM_MISC);
+
+ if (vaOwnerProp) {
+ AddCbyProp (vaCurProp); // add to called/used by
+ AddCalProp (vaCurProp); // add to call/uses
+ }
+}
+
+VOID
+AddDefProp(VA vaCurProp)
+// Add a symbol definition to it's property definition list.
+// -Set vaOwnerProp if symbol is an internal function.
+{
+ DEF def;
+ VA vaFileSym;
+
+#if 0
+
+ // if current symbol is FUNCTION and formally declared
+ // (block stack not empty), then remember it.
+ // Subsequent symbols are called by or used by this function.
+ //
+ // this is going away when all compilers support SBR_REC_OWNER
+
+ if ((r_attrib & SBR_TYPMASK) == SBR_TYP_FUNCTION)
+ if (pfblkstack != NULL && !(r_attrib & SBR_ATR_DECL_ONLY))
+ vaOwnerProp = vaCurProp;
+#endif
+
+ vaFileSym = gMOD(vaCurMod).vaNameSym;
+
+ ENM_LIST (gPROP(vaCurProp).vaDefList, DEF) // proc def list
+
+ if ((cDEF.vaFileSym == vaFileSym) && // ignore multiple
+ (cDEF.deflin == r_lineno)) { // references to same file & line
+ cDEF.isbr = isbrCur;
+ ENM_PUT(DEF);
+ SetVMClient(VM_MISC);
+ return;
+ }
+
+ ENM_END
+
+ def.isbr = isbrCur;
+ def.deflin = r_lineno;
+ def.vaFileSym = vaFileSym;
+
+ SetVMClient(VM_ADD_DEF);
+
+ gPROP(vaCurProp);
+
+ VaAddList(&cPROP.vaDefList, &def, sizeof(def), grpDef);
+
+ pPROP(vaCurProp);
+
+ SetVMClient(VM_MISC);
+
+#ifdef DEBUG
+ if (OptD & 8) {
+ printf("New DEF for: ");
+ DebugDumpProp(vaCurProp);
+ }
+#endif
+
+ // don't count the definitions of the current proc as uses
+
+ if (vaOwnerProp && vaCurProp != vaOwnerProp) {
+ AddCbyProp (vaCurProp); // add to called/used by
+ AddCalProp (vaCurProp); // add to call/uses
+ }
+}
+
+
+VA
+VaPropBestOfSym(VA vaSym)
+//
+// Returns property pointer if:
+// 1). symbol is already defined,
+// 2). attributes match (except for possibly ATR_DECL_ONLY)
+//
+// Idea is to recognize the definition of an external.
+//
+{
+ VA vaProp;
+ WORD sattr;
+
+ SetVMClient(VM_SEARCH_PROP);
+
+ vaProp = gSYM(vaSym).vaFirstProp;
+
+ while (vaProp) {
+ sattr = gPROP(vaProp).sattr;
+
+ if ((r_attrib & (~SBR_ATR_DECL_ONLY))
+ == (sattr & (~SBR_ATR_DECL_ONLY))) {
+ SetVMClient(VM_MISC);
+ return (vaProp);
+ }
+
+ vaProp = cPROP.vaNextProp;
+ }
+
+ SetVMClient(VM_MISC);
+
+ return vaNil;
+}
+
+VA
+VaPropAddToSym(VA vaCurSym)
+// Add a property node for the given symbol.
+//
+{
+ char fDupProp = FALSE;
+ VA vaCurProp;
+
+ if (vaCurProp = VaPropBestOfSym (vaCurSym)) {
+ if ( (cPROP.sattr & SBR_ATR_DECL_ONLY) &&
+ !(r_attrib & SBR_ATR_DECL_ONLY)) {
+ cPROP.sattr = r_attrib;
+ pPROP(vaCurProp);
+ }
+ fDupProp = TRUE;
+ }
+ else {
+ SetVMClient(VM_ADD_PROP);
+
+ vaCurProp = VaAllocGrpCb(grpProp, sizeof(PROP));
+ gPROP(vaCurProp);
+ cPROP.vaNameSym = vaCurSym;
+ cPROP.sattr = r_attrib;
+
+ if (gSYM(vaCurSym).vaFirstProp)
+ cPROP.vaNextProp = cSYM.vaFirstProp;
+
+ pPROP(vaCurProp);
+
+ cSYM.vaFirstProp = vaCurProp;
+ cSYM.cprop++;
+ pSYM(vaCurSym);
+
+ SetVMClient(VM_MISC);
+ }
+
+ if (!fExclMod) {
+ if (r_attrib & SBR_ATR_DECL_ONLY)
+ AddRefProp (vaCurProp); // treat extern as ref
+ else
+ AddDefProp (vaCurProp); // define others
+ }
+
+ return (vaCurProp);
+}
+
+VOID
+BldModSymList ()
+// Build each module's symbol list
+//
+{
+ WORD i;
+ VA vaMod, vaModSym, vaSym, vaProp;
+
+ SetVMClient(VM_BUILD_MODSYM);
+
+ // zero out module symbol counts
+ vaMod = vaRootMod;
+ while (vaMod) {
+ gMOD(vaMod);
+ cMOD.csyms = 0;
+ pMOD(vaMod);
+ vaMod = cMOD.vaNextMod;
+ }
+
+ for (i=0; i < cSymbolsMac; i++) {
+ vaSym = rgvaSymSorted[i];
+
+ if (!vaSym) continue;
+
+ vaProp = gSYM(vaSym).vaFirstProp;
+
+ while (vaProp) {
+ ENM_LIST(gPROP(vaProp).vaDefList, DEF)
+
+ vaMod = vaRootMod; // look at defs for each mod */
+ while (vaMod) {
+ if (cDEF.vaFileSym == gMOD(vaMod).vaNameSym) {
+
+ if (cMOD.vaLastModSym &&
+ gMODSYM(cMOD.vaLastModSym).vaFirstProp == vaProp)
+ goto break2; // duplicate
+
+ // belongs to this mod
+ cMOD.csyms++;
+
+ vaModSym = VaAllocGrpCb(grpModSym, sizeof(MODSYM));
+ gMODSYM(vaModSym);
+ cMODSYM.vaFirstProp = vaProp;
+ cMODSYM.vaNextModSym = 0;
+ pMODSYM(vaModSym);
+
+ if (!cMOD.vaFirstModSym)
+ cMOD.vaFirstModSym = cMOD.vaLastModSym = vaModSym;
+ else {
+ gMODSYM(cMOD.vaLastModSym).vaNextModSym = vaModSym;
+ pMODSYM(cMOD.vaLastModSym);
+ cMOD.vaLastModSym = vaModSym;
+ }
+ pMOD(vaMod);
+ break;
+ }
+ vaMod = cMOD.vaNextMod;
+ }
+ break2: ; // duplicate Modsyms will cause goto here
+ ENM_END
+
+ vaProp = cPROP.vaNextProp;
+ }
+ }
+
+ SetVMClient(VM_MISC);
+}
+
+VOID
+CleanUp()
+// 1. Remove symbols that have no references.
+// 2. Remove symbols that have only references
+// 3. Connect used symbols with no definition to <Unknown>
+//
+{
+ WORD i;
+ VA vaSym, vaProp, vaPropNext, vaPropPrev = vaNil;
+ DEF def;
+ BOOL fDelete;
+
+ #define FExternAttr(attr) (!!(attr & SBR_ATR_DECL_ONLY))
+ #define FFunctionAttr(attr) ((attr & SBR_TYPMASK) == SBR_TYP_FUNCTION)
+
+ def.vaFileSym = vaUnknownSym;
+ def.deflin = 0;
+ def.isbr = 0xffff;
+
+ SetVMClient(VM_CLEAN_REFS);
+
+ for (i=0; i < cSymbolsMac; i++) {
+ vaSym = rgvaSymSorted[i];
+
+ vaPropPrev = vaNil;
+
+ vaProp = gSYM(vaSym).vaFirstProp;
+
+ while (vaProp) {
+ vaPropNext = gPROP(vaProp).vaNextProp;
+ fDelete = FALSE;
+
+ // figure out what to delete here
+
+ // if the symbol is used by anyone or uses anyone we must keep it
+ // regardless of all other considerations
+ //
+ if (((!cPROP.vaCalList) && (!cPROP.vaCbyList)) && (
+ // at this point we know there are only refs & defs
+
+ // if it is totally unreferenced & undefined it can go
+ (cPROP.cref == 0 && (!cPROP.vaDefList))
+ ||
+ // if we're allowed to remove "useless" symbols then we try
+ ((!OptIu) &&
+ // if there are only prototypes we can delete it
+ (((!cPROP.vaDefList) && FExternAttr(cPROP.sattr))
+ ||
+ // or if it is unreferenced and is not a function
+ (cPROP.cref == 0 && (!FFunctionAttr(cPROP.sattr))))))) {
+ fDelete = TRUE; // nuke it
+ }
+ else if (!cPROP.vaDefList) {
+
+ // if we couldn't get rid of the thing, and there are no
+ // definitions for it then we must make a fake definition
+ // in the <Unknown> file. This will happen (in particular)
+ // for library functions that are called by someone
+ //
+ // library functions that are not called would fall under
+ // the case of a symbol with only prototypes above
+
+ VaAddList(&cPROP.vaDefList, &def, sizeof(def), grpDef);
+ pPROP(vaProp);
+
+ #ifdef DEBUG
+ if (OptD & 32)
+ printf ("PROP unknown: %s\n", GetAtomStr (vaSym));
+ #endif
+ }
+
+ if (fDelete) {
+ #ifdef DEBUG
+ if (OptD & 32)
+ printf ("PROP deleted: %s\n", GetAtomStr (vaSym));
+ #endif
+
+ cSYM.cprop--;
+
+ if (vaPropPrev == vaNil) {
+ cSYM.vaFirstProp = vaPropNext;
+ }
+ else {
+ gPROP(vaPropPrev);
+ cPROP.vaNextProp = vaPropNext;
+ pPROP(vaPropPrev);
+ }
+
+ pSYM(vaSym);
+ }
+ else
+ vaPropPrev = vaProp; // prev = current
+
+ vaProp = vaPropNext;
+ }
+
+ if (!cSYM.cprop) {
+ #ifdef DEBUG
+ if (OptD & 32)
+ printf ("SYM deleted: %s\n", GetAtomStr (vaSym));
+ #endif
+ rgvaSymSorted[i] = vaNil;
+ }
+ }
+
+ SetVMClient(VM_MISC);
+}
+
+BOOL
+FWildMatch(char *pchPat, char *pchText)
+// return TRUE if pchText matchs pchPat in the dos wildcard sense
+//
+// REVIEW FWildMatch for 1.2 file name support
+//
+{
+ char chText, chPat;
+
+ for (;;) {
+ switch (*pchPat) {
+
+ case '\0':
+ return *pchText == '\0';
+
+ case '/':
+ case '\\':
+ if (*pchText != '/' && *pchText != '\\')
+ return FALSE;
+
+ pchText++;
+ pchPat++;
+ break;
+
+ case '.':
+ pchPat++;
+ switch (*pchText) {
+
+ case '.':
+ pchText++;
+ break;
+
+ case '\0': case '/': case '\\':
+ break;
+
+ default:
+ return FALSE;
+ }
+ break;
+
+ case '*':
+ pchText += strcspn(pchText, ":./\\");
+ pchPat += strcspn(pchPat, ":./\\");
+ break;
+
+ case '?':
+ pchPat++;
+ switch (*pchText) {
+
+ case '\0': case '.': case '/': case '\\':
+ break;
+
+ default:
+ pchText++;
+ break;
+ }
+
+ break;
+
+ default:
+ chText = *pchText;
+ chPat = *pchPat;
+
+ if (islower(chText)) chText = (char)toupper(chText);
+ if (islower(chPat)) chPat = (char)toupper(chPat);
+
+ if (chText != chPat)
+ return FALSE;
+
+ pchPat++;
+ pchText++;
+ break;
+ }
+ }
+}
diff --git a/private/utils/mep/browser/mbrmake/casts.h b/private/utils/mep/browser/mbrmake/casts.h
new file mode 100644
index 000000000..1d55b9e29
--- /dev/null
+++ b/private/utils/mep/browser/mbrmake/casts.h
@@ -0,0 +1,22 @@
+/* casts.h - define useful casts for calling DOS 5 API routines
+**
+*/
+
+#define FALSE 0
+#define TRUE 1
+
+typedef unsigned char byte;
+typedef unsigned int word;
+typedef unsigned long dword;
+
+typedef char * NPC;
+typedef int * NPI;
+typedef long * NPL;
+typedef unsigned int * NPU;
+typedef unsigned long * NPUL;
+
+typedef char far * FPC;
+typedef int far * FPI;
+typedef long far * FPL;
+typedef unsigned int far * FPU;
+typedef unsigned long far * FPUL;
diff --git a/private/utils/mep/browser/mbrmake/convert.c b/private/utils/mep/browser/mbrmake/convert.c
new file mode 100644
index 000000000..917c2e8a8
--- /dev/null
+++ b/private/utils/mep/browser/mbrmake/convert.c
@@ -0,0 +1,266 @@
+// filename conversion/canonicalization facility
+//
+
+#include "mbrmake.h"
+#include <string.h>
+#include <ctype.h>
+
+LSZ ToCanonPath(LSZ lszPath, LSZ lszCwd, LSZ lszCanon);
+VOID ToRelativePath(LSZ lszPath, LSZ lszCwd);
+VOID ToBackSlashes(LSZ lsz);
+
+#ifdef STANDALONE
+
+#include <stdio.h>
+main()
+{
+ static char s[PATH_BUF];
+ static char canon[PATH_BUF];
+ static char cwd[PATH_BUF];
+
+ getcwd(cwd, PATH_BUF);
+ printf("Current Dir is %s\n", cwd);
+ printf("Canonical path?\n");
+ gets(canon);
+ while (gets(s)) {
+ printf("%s\n", ToCanonPath(s, cwd, canon));
+ }
+}
+
+#endif
+
+LSZ
+ToCanonPath(LSZ lszPath, LSZ lszCwd, LSZ lszCanon)
+// canonicalize the given path
+//
+{
+ LSZ p;
+ static char buf[PATH_BUF];
+
+ strcpy(buf, lszPath);
+
+ ToBackSlashes(buf);
+
+ if (buf[0] == 0 || buf[0] == '\\' || buf[0] == '<')
+ return buf;
+
+ if (buf[1] == ':') {
+ // different drive is assumed invariant
+ if (buf[0] != lszCwd[0] || '\\' == buf[2])
+ return buf;
+
+ strcpy(buf, lszCwd);
+ strcat(buf, "/");
+ strcat(buf, lszPath+2);
+ }
+ else {
+ strcpy(buf, lszCwd);
+ strcat(buf, "/");
+ strcat(buf, lszPath);
+ }
+
+ ToBackSlashes(buf);
+
+ p = buf;
+ for (;;) {
+ p = strchr(p, '\\');
+ if (!p) {
+ ToRelativePath(buf, lszCanon);
+ return buf;
+ }
+
+ switch (p[1]) {
+
+ case '\0':
+ *p = 0;
+ ToRelativePath(buf, lszCanon);
+ return buf;
+
+ case '\\':
+ strcpy(p, p+1);
+ break;
+
+ case '.':
+
+ if (p[2] == '\\' || p[2] == 0) {
+ strcpy(p, p+2);
+ break;
+ }
+ if (p[2] == '.' && (p[3] == '\\' || p[3] == 0)) {
+ LSZ s;
+
+ s = p;
+
+ while (--s >= buf) {
+ if (*s == '\\') {
+ strcpy(s+1,p+3);
+ p = s;
+ break;
+ }
+ }
+
+ if (s < buf)
+ p++;
+ }
+ break;
+
+ default:
+ p++;
+ }
+ }
+}
+
+VOID
+ToRelativePath(LSZ lszPath, LSZ lszCwd)
+// convert absolute path to relative
+//
+{
+ WORD ich, ichOK;
+ int c1, c2;
+ char buf[PATH_BUF];
+
+ ich = ichOK = 0;
+
+ for (ich = 0; lszPath[ich] && lszCwd[ich]; ich++) {
+
+ c1 = lszPath[ich];
+ c2 = lszCwd[ich];
+
+ if (c1 == c2) {
+ if (c1 == '\\') ichOK = ich+1;
+ continue;
+ }
+
+ if (isupper(c1) && islower(c2) && tolower(c1) == c2)
+ continue;
+
+ if (isupper(c2) && islower(c1) && tolower(c2) == c1)
+ continue;
+
+ break;
+ }
+
+ if (ich == 0) // not on the same drive, we can't do the conversion
+ return;
+
+ if (lszCwd[ich] == 0 && lszPath[ich] == '\\') {
+ ichOK = ich+1;
+ c2 = 0;
+ }
+ else {
+ c2 = 1;
+ c1 = ichOK;
+ for (c1 = ichOK; lszCwd[c1]; c1++)
+ if (lszCwd[c1] == '\\')
+ c2++;
+ }
+
+ buf[0] = 0;
+ for (c1 = 0; c1 < c2; c1++)
+ strcat(buf, "..\\");
+
+ strcat(buf, lszPath+ichOK);
+ strcpy(lszPath, buf);
+}
+
+LSZ
+ToAbsPath(LSZ lszPath, LSZ lszCwd)
+// canonicalize the given path
+//
+{
+ LSZ p;
+ static char buf[PATH_BUF];
+
+ strcpy(buf, lszPath);
+
+ ToBackSlashes(buf);
+
+ if (buf[0] == '<')
+ return buf;
+
+ if (buf[0] == 0) {
+ strcpy(buf, lszCwd);
+ ToBackSlashes(lszCwd);
+ return buf;
+ }
+
+ if (buf[0] == '\\') {
+ buf[0] = lszCwd[0];
+ buf[1] = ':';
+ strcpy(buf+2, lszPath);
+ ToBackSlashes(buf);
+ return buf;
+ }
+
+ if (buf[1] == ':') {
+ // different drive is assumed invariant
+ if (buf[0] != lszCwd[0] || buf[2] == '\\')
+ return buf;
+
+ strcpy(buf, lszCwd);
+ strcat(buf, "/");
+ strcat(buf, lszPath+2);
+ }
+ else {
+ strcpy(buf, lszCwd);
+ strcat(buf, "/");
+ strcat(buf, lszPath);
+ }
+
+ ToBackSlashes(buf);
+
+ p = buf;
+ for (;;) {
+ p = strchr(p, '\\');
+ if (!p) return buf;
+
+ switch (p[1]) {
+
+ case '\0':
+ *p = 0;
+ return buf;
+
+ case '\\':
+ strcpy(p, p+1);
+ break;
+
+ case '.':
+
+ if (p[2] == '\\' || p[2] == 0) {
+ strcpy(p, p+2);
+ break;
+ }
+ if (p[2] == '.' && (p[3] == '\\' || p[3] == 0)) {
+ LSZ s;
+
+ s = p;
+
+ while (--s >= buf) {
+ if (*s == '\\') {
+ strcpy(s+1,p+3);
+ p = s;
+ break;
+ }
+ }
+
+ if (s < buf)
+ p++;
+ }
+ break;
+
+ default:
+ p++;
+ }
+ }
+}
+
+VOID
+ToBackSlashes(LSZ lsz)
+// convert forward slashes to backslashes
+//
+{
+ while (*lsz) {
+ if (*lsz == '/') *lsz = '\\';
+ lsz ++;
+ }
+}
diff --git a/private/utils/mep/browser/mbrmake/dcodesbr.c b/private/utils/mep/browser/mbrmake/dcodesbr.c
new file mode 100644
index 000000000..eff86b6ab
--- /dev/null
+++ b/private/utils/mep/browser/mbrmake/dcodesbr.c
@@ -0,0 +1,148 @@
+//
+//
+// DCODESBR.C - dumps a human readable version of the current .sbr file
+// record from the r_... variables
+//
+//
+
+#include "sbrfdef.h"
+#include "mbrmake.h"
+
+char * near prectab[] = {
+ "HEADER", // SBR_REC_HEADER
+ "MODULE", // SBR_REC_MODULE
+ "LINDEF", // SBR_REC_LINDEF
+ "SYMDEF", // SBR_REC_SYMDEF
+ "SYMREFUSE", // SBR_REC_SYMREFUSE
+ "SYMREFSET", // SBR_REC_SYMREFSET
+ "MACROBEG", // SBR_REC_MACROBEG
+ "MACROEND", // SBR_REC_MACROEND
+ "BLKBEG", // SBR_REC_BLKBEG
+ "BLKEND", // SBR_REC_BLDEND
+ "MODEND", // SBR_REC_MODEND
+ "OWNER" // SBR_REC_OWNER
+};
+
+char * near plangtab[] = {
+ "UNDEF", // SBR_L_UNDEF
+ "BASIC", // SBR_L_BASIC
+ "C", // SBR_L_C
+ "FORTRAN", // SBR_L_FORTRAN
+ "MASM", // SBR_L_MASM
+ "PASCAL", // SBR_L_PASCAL
+ "COBOL" // SBR_L_COBOL
+};
+
+char * near ptyptab[] = {
+ "UNDEF", // SBR_TYP_UNKNOWN
+ "FUNCTION", // SBR_TYP_FUNCTION
+ "LABEL", // SBR_TYP_LABEL
+ "PARAMETER", // SBR_TYP_PARAMETER
+ "VARIABLE", // SBR_TYP_VARIABLE
+ "CONSTANT", // SBR_TYP_CONSTANT
+ "MACRO", // SBR_TYP_MACRO
+ "TYPEDEF", // SBR_TYP_TYPEDEF
+ "STRUCNAM", // SBR_TYP_STRUCNAM
+ "ENUMNAM", // SBR_TYP_ENUMNAM
+ "ENUMMEM", // SBR_TYP_ENUMMEM
+ "UNIONNAM", // SBR_TYP_UNIONNAM
+ "SEGMENT", // SBR_TYP_SEGMENT
+ "GROUP", // SBR_TYP_GROUP
+ "PROGRAM" // SBR_TYP_PROGRAM
+};
+
+char * near patrtab[] = {
+ "LOCAL", // SBR_ATR_LOCAL
+ "STATIC", // SBR_ATR_STATIC
+ "SHARED", // SBR_ATR_SHARED
+ "NEAR", // SBR_ATR_NEAR
+ "COMMON", // SBR_ATR_COMMON
+ "DECL_ONLY", // SBR_ATR_DECL_ONLY
+ "PUBLIC", // SBR_ATR_PUBLIC
+ "NAMED", // SBR_ATR_NAMED
+ "MODULE", // SBR_ATR_MODULE
+ "?", "?" // reserved for expansion
+};
+
+VOID
+DecodeSBR ()
+{
+ int i;
+ static indent;
+
+ switch(r_rectyp) {
+ case SBR_REC_MACROEND:
+ case SBR_REC_BLKEND:
+ case SBR_REC_MODEND:
+ indent--;
+ break;
+
+ case SBR_REC_HEADER:
+ case SBR_REC_MODULE:
+ case SBR_REC_LINDEF:
+ case SBR_REC_SYMDEF:
+ case SBR_REC_SYMREFUSE:
+ case SBR_REC_SYMREFSET:
+ case SBR_REC_MACROBEG:
+ case SBR_REC_BLKBEG:
+ case SBR_REC_OWNER:
+ break;
+
+ default:
+ fprintf(streamOut, "invalid record type %0xh", r_rectyp);
+ SBRCorrupt("");
+ return;
+ }
+
+ for (i = indent; i; i--)
+ fprintf (streamOut, " ");
+
+ fprintf (streamOut, "%s: (", prectab[r_rectyp]);
+
+ switch(r_rectyp) {
+
+ case SBR_REC_HEADER:
+ fprintf (streamOut, "%1d:%1d (%s) %1d)",
+ r_majv, r_minv, plangtab[r_lang], r_fcol);
+ fprintf (streamOut, " in %s", r_cwd);
+ break;
+
+ case SBR_REC_MODULE:
+ fprintf (streamOut, "%s", r_bname);
+ indent++;
+ break;
+
+ case SBR_REC_LINDEF:
+ fprintf (streamOut, "%d", r_lineno);
+ break;
+
+ case SBR_REC_SYMDEF:
+ {
+ WORD attr, type;
+
+ type = (r_attrib & SBR_TYPMASK) >> SBR_TYPSHIFT;
+ attr = (r_attrib & SBR_ATRMASK) >> SBR_ATRSHIFT;
+
+ fprintf (streamOut, "%s", ptyptab[type]);
+
+ for (i = 0 ; i < SBR_ATRBITS; i++)
+ if (attr & (1 << i))
+ fprintf (streamOut, "|%s", patrtab[i]);
+
+ fprintf (streamOut, " o:%d %s", r_ordinal, r_bname);
+ }
+ break;
+
+ case SBR_REC_SYMREFUSE:
+ case SBR_REC_SYMREFSET:
+ case SBR_REC_OWNER:
+ fprintf (streamOut, "o:%d", r_ordinal);
+ break;
+
+ case SBR_REC_MACROBEG:
+ case SBR_REC_BLKBEG:
+ indent++;
+ break;
+ }
+ fprintf (streamOut, ")\n");
+}
diff --git a/private/utils/mep/browser/mbrmake/errors.h b/private/utils/mep/browser/mbrmake/errors.h
new file mode 100644
index 000000000..e684211d4
--- /dev/null
+++ b/private/utils/mep/browser/mbrmake/errors.h
@@ -0,0 +1,20 @@
+
+#define WARN_UNKNOWN_WARNING 0
+#define WARN_OPTION_IGNORED 1
+#define WARN_SBR_TRUNC 2
+
+#define ERR_UNKNOWN_ERROR 0
+#define ERR_UNKNOWN_OPTION 1
+#define ERR_MISSING_OPTION 2
+#define ERR_WRITE_FAILED 3
+#define ERR_SEEK_FAILED 4
+#define ERR_READ_FAILED 5
+#define ERR_OPEN_FAILED 6
+#define ERR_TEMP_FAILED 7
+#define ERR_DELETE_FAILED 8
+#define ERR_OUT_OF_MEMORY 9
+#define ERR_SBR_CORRUPT 10
+#define ERR_BAD_RESPONSE 11
+#define ERR_CAPACITY_EXCEEDED 12
+#define ERR_NO_INCREMENTAL 13
+#define ERR_ALL_SBR_TRUNC 14
diff --git a/private/utils/mep/browser/mbrmake/extern.h b/private/utils/mep/browser/mbrmake/extern.h
new file mode 100644
index 000000000..44fe56cbe
--- /dev/null
+++ b/private/utils/mep/browser/mbrmake/extern.h
@@ -0,0 +1,83 @@
+
+// pointers to resident pages of virtual memory of the given object type
+
+extern MOD FAR * near modRes;
+extern MODSYM FAR * near modsymRes;
+extern SYM FAR * near symRes;
+extern PROP FAR * near propRes;
+extern DEF FAR * near defRes;
+extern REF FAR * near refRes;
+extern CAL FAR * near calRes;
+extern CBY FAR * near cbyRes;
+extern ORD FAR * near ordRes;
+extern SBR FAR * near sbrRes;
+extern char FAR * near textRes;
+extern OCR FAR * near ocrRes;
+
+// global variables for communication with getsbrec.c
+
+extern BYTE near r_rectyp; // current record type
+extern BYTE near r_fcol; // read column #'s
+extern BYTE near r_majv; // major version #
+extern BYTE near r_minv; // minor version #
+extern BYTE near r_lang; // current language
+extern WORD near r_lineno; // current line number
+extern WORD near r_ordinal; // symbol ordinal
+extern WORD near r_attrib; // symbol attribute
+extern char near r_bname[]; // symbol or filename
+extern char near r_cwd[]; // current working directory
+extern BYTE near r_rectyp; // current record type
+extern BYTE near r_fcol; // read column #'s
+extern WORD near r_lineno; // current line number
+extern WORD near r_ordinal; // symbol ordinal
+extern WORD near r_attrib; // symbol attribute
+extern char near r_bname[]; // symbol or filename
+extern char near r_cwd[]; // this .sbr files current dir
+extern char near c_cwd[]; // pwbrmake's actual current dir
+
+// option variables
+
+extern BOOL near OptEm; // TRUE = exclude macro bodies
+extern BOOL near OptEs; // TRUE = exclude system files
+extern BOOL near OptIu; // TRUE = exclude unused syms
+extern BOOL near OptV; // Verbose switch
+#if DEBUG
+extern WORD near OptD; // debug bits
+#endif
+
+// others that I haven't classified yet
+
+extern BYTE near MaxSymLen; // longest symbol len
+extern VA near vaSymHash[]; // symbol list
+extern LPEXCL near pExcludeFileList; // exclude file list
+extern LSZ near lszFName; // name of current .sbr file
+extern FILE * near streamOut; // .bsc output stream
+extern int near fhCur; // file handle for the current .sbr file
+extern LSZ near prectab[]; // record types table
+extern LSZ near plangtab[]; // language types table
+extern LSZ near ptyptab[]; // prop types table
+extern LSZ near patrtab[]; // prop attributes table
+extern WORD near isbrCur; // current SBR file index
+extern FILE * near OutFile; // .BSC file handle
+extern WORD near ModCnt; // count of modules
+extern WORD near SbrCnt; // count of sbr files
+extern BYTE near fCase; // TRUE for case compare
+extern BYTE near MaxSymLen; // longest symbol len
+extern BOOL near fOutputBroken; // TRUE while database is incomplete
+extern VA near vaUnknownSym; // ptr to 'UNKNOWN' Symbol
+extern VA near vaUnknownMod; // unknown module
+extern BOOL near fDupSym; // TRUE if adding duplicate atom
+extern VA near vaRootMod; // Module list
+extern VA near rgVaSym[]; // Symbol list
+extern FILE * near streamCur; // Current .sbr handle
+extern LSZ near OutputFileName; // Output file name
+extern VA FAR * near rgvaSymSorted;
+extern VA near vaRootMod;
+extern VA near vaCurMod;
+extern VA near vaCurSym;
+extern VA near vaRootOrd;
+extern VA near vaRootSbr;
+extern WORD near cAtomsMac;
+extern WORD near cModulesMac;
+extern WORD near cSymbolsMac;
+extern LSZ near lszFName; // current .sbr file name
diff --git a/private/utils/mep/browser/mbrmake/getsbrec.c b/private/utils/mep/browser/mbrmake/getsbrec.c
new file mode 100644
index 000000000..6fed1778e
--- /dev/null
+++ b/private/utils/mep/browser/mbrmake/getsbrec.c
@@ -0,0 +1,165 @@
+//
+//
+// GETSBREC.C - Reads records from the .SBR file and stores the fields
+// in the appropriate r_.. buffers.
+//
+
+#include "sbrfdef.h"
+#include "..\mbrmake\mbrmake.h"
+
+// globals for communicating with clients
+
+BYTE near r_rectyp; // current record type
+BYTE near r_majv; // major version num
+BYTE near r_minv; // minor version num
+BYTE near r_lang; // source language
+BYTE near r_fcol; // read column #'s
+WORD near r_lineno; // current line number
+BYTE near r_column = 0; // def/ref column num
+WORD near r_ordinal; // symbol ordinal
+WORD near r_attrib; // symbol attribute
+char near r_bname[PATH_BUF]; // symbol or filename
+char near r_cwd[PATH_BUF]; // .sbr file working directory
+
+int near fhCur; // Current input handle
+
+#pragma intrinsic(memcpy)
+#pragma intrinsic(strcpy)
+#pragma intrinsic(strlen)
+
+#define MY_BUF_SIZE 16384
+
+static char sbrBuf[MY_BUF_SIZE + 1];
+static char *pchBuf;
+static int cchBuf;
+
+#define GetByte(X) \
+{ \
+ if (!cchBuf) { \
+ cchBuf = read(fhCur, sbrBuf, MY_BUF_SIZE); \
+ sbrBuf[cchBuf] = 0; \
+ pchBuf = sbrBuf; \
+ \
+ if (cchBuf == 0) \
+ SBRCorrupt("premature EOF"); \
+ } \
+ \
+ cchBuf--; \
+ (X) = (unsigned char)*pchBuf++; \
+}
+
+#define GetWord(X) \
+{ \
+ \
+ GetByte(((char *)&(X))[0]); \
+ GetByte(((char *)&(X))[1]); \
+}
+
+void
+GetStr(char *buf)
+// get null terminated string from current .sbr file
+//
+{
+ register int l;
+
+ for (;;) {
+ // there is always a NULL after the real buffer
+ l = strlen(pchBuf);
+
+ if (l++ < cchBuf) {
+ strcpy(buf, pchBuf);
+ cchBuf -= l;
+ pchBuf += l;
+ return;
+ }
+
+ memcpy(buf, pchBuf, cchBuf);
+ buf += cchBuf;
+
+ cchBuf = read(fhCur, sbrBuf, MY_BUF_SIZE);
+ sbrBuf[cchBuf] = 0;
+ pchBuf = sbrBuf;
+
+ if (cchBuf == 0)
+ SBRCorrupt("premature EOF");
+ }
+}
+
+BYTE
+GetSBRRec()
+// read the next record from the current .sbr file
+//
+{
+ static fFoundHeader;
+ BYTE col;
+
+ // read rectype, check for EOF as we go
+
+
+ if (!cchBuf) {
+ cchBuf = read(fhCur, sbrBuf, MY_BUF_SIZE);
+ sbrBuf[cchBuf] = 0;
+ pchBuf = sbrBuf;
+
+ if (cchBuf == 0) {
+ fFoundHeader = 0; // this is in case we are reinitialized
+ return S_EOF;
+ }
+ }
+
+ cchBuf--;
+ r_rectyp = (unsigned char)*pchBuf++;
+
+ switch(r_rectyp) {
+ case SBR_REC_HEADER:
+ if (fFoundHeader)
+ SBRCorrupt("Multiple Headers");
+
+ fFoundHeader = 1;
+ GetByte(r_majv);
+ GetByte(r_minv);
+ GetByte(r_lang);
+ GetByte(r_fcol);
+
+ if (r_majv != 1 || r_minv != 1)
+ break;
+
+ GetStr (r_cwd);
+ break;
+
+ case SBR_REC_MODULE:
+ GetStr (r_bname);
+ break;
+
+ case SBR_REC_LINDEF:
+ GetWord (r_lineno);
+ if (r_lineno)
+ r_lineno--;
+ break;
+
+ case SBR_REC_SYMDEF:
+ GetWord (r_attrib);
+ GetWord (r_ordinal);
+ if (r_fcol) GetByte (col);
+ GetStr (r_bname);
+ break;
+
+ case SBR_REC_OWNER:
+ GetWord (r_ordinal);
+ break;
+
+ case SBR_REC_SYMREFUSE:
+ case SBR_REC_SYMREFSET:
+ GetWord (r_ordinal);
+ if (r_fcol) GetByte (col);
+ break;
+
+ case SBR_REC_MACROBEG:
+ case SBR_REC_MACROEND:
+ case SBR_REC_BLKBEG:
+ case SBR_REC_BLKEND:
+ case SBR_REC_MODEND:
+ break;
+ }
+ return (r_rectyp);
+}
diff --git a/private/utils/mep/browser/mbrmake/list.c b/private/utils/mep/browser/mbrmake/list.c
new file mode 100644
index 000000000..a2b634904
--- /dev/null
+++ b/private/utils/mep/browser/mbrmake/list.c
@@ -0,0 +1,284 @@
+// list.c
+//
+// a VM growable array package
+
+#include "mbrmake.h"
+
+typedef struct _list {
+ WORD cItems;
+} SLIST;
+
+typedef struct _biglist {
+ WORD cItems;
+ VA vaNext;
+} BLIST;
+
+typedef union _mixlist {
+ SLIST sml;
+ BLIST big;
+} GLIST;
+
+// this are the two VM lock numbers for the list package
+//
+#define LIST_LOCK 10
+#define LIST_LOCK2 11
+
+// Beware! For the system to work properly this number must
+// be small enough that the VM free lists won't overflow
+// i.e. C_ITEMS_MAX * sizeof(biggest_thing_stored) <= C_FREE_LIST_MAX
+//
+#define C_ITEMS_MAX 16
+
+#pragma intrinsic(memcpy)
+
+#define cBlock 1
+
+VA
+VaAddList(VA far *pvaList, LPV lpvData, WORD cbData, WORD grp)
+// add the given item to the list; create if necessary
+// return the virtual address of the most recently added item
+//
+{
+ VA vaListNew;
+ VA vaDirtyOnExit = vaNil;
+
+ WORD cbBlock, cItems, cAlloc;
+
+ GLIST far *lpList, *lpListNew;
+
+#ifdef SWAP_INFO
+ iVMGrp = grp;
+#endif
+
+#if cBlock != 1
+ if (cBlock == 0) cBlock = C_ITEMS_MAX;
+#endif
+
+top: // for tail recursion...
+
+ // current list is empty -- create a new list with one thing in it
+
+ if (*pvaList == vaNil) {
+ if (cBlock == C_ITEMS_MAX) {
+ *pvaList = VaAllocGrpCb(grp, cbData*cBlock + sizeof(BLIST));
+ lpList = LpvFromVa(*pvaList, LIST_LOCK);
+ lpList->big.vaNext = vaNil;
+ lpList->big.cItems = 1;
+ memcpy(((LPCH)lpList) + sizeof(BLIST), lpvData, cbData);
+ if (vaDirtyOnExit) {
+ DirtyVa(vaDirtyOnExit);
+ UnlockW(LIST_LOCK+1);
+ }
+ DirtyVa(*pvaList);
+ UnlockW(LIST_LOCK);
+ return (PBYTE)*pvaList + sizeof(BLIST);
+ }
+ else {
+ *pvaList = VaAllocGrpCb(grp, cbData*cBlock + sizeof(SLIST));
+ lpList = LpvFromVa(*pvaList, LIST_LOCK);
+ lpList->sml.cItems = 1;
+ memcpy(((LPCH)lpList) + sizeof(SLIST), lpvData, cbData);
+ if (vaDirtyOnExit) {
+ DirtyVa(vaDirtyOnExit);
+ UnlockW(LIST_LOCK+1);
+ }
+ DirtyVa(*pvaList);
+ UnlockW(LIST_LOCK);
+ return (PBYTE)*pvaList + sizeof(SLIST);
+ }
+ }
+
+ lpList = LpvFromVa(*pvaList, LIST_LOCK);
+ cItems = lpList->sml.cItems;
+
+ // if current list has extension blocks, recursively add to the
+ // tail of this list
+
+ if (cItems >= C_ITEMS_MAX) {
+ vaDirtyOnExit = *pvaList;
+ lpList->big.cItems++;
+ DirtyVa(*pvaList);
+ LpvFromVa(*pvaList, LIST_LOCK+1); // lock in mem so address stays good
+ pvaList = &lpList->big.vaNext;
+ UnlockW(LIST_LOCK);
+ goto top;
+ }
+
+ cbBlock = cItems * cbData;
+ cAlloc = cItems % cBlock;
+ cAlloc = cItems - cAlloc + ( cAlloc ? cBlock : 0 );
+
+ // do we need to reallocate? If not do a fast insert
+ //
+ if (cItems < cAlloc) {
+ if (cAlloc >= C_ITEMS_MAX) {
+ memcpy(((LPCH)lpList) + cbBlock + sizeof(BLIST), lpvData, cbData);
+ lpList->big.cItems++;
+ DirtyVa(*pvaList);
+ UnlockW(LIST_LOCK);
+ return (PBYTE)*pvaList + cbBlock + sizeof(BLIST);
+ }
+ else {
+ memcpy(((LPCH)lpList) + cbBlock + sizeof(SLIST), lpvData, cbData);
+ lpList->sml.cItems++;
+ DirtyVa(*pvaList);
+ UnlockW(LIST_LOCK);
+ return (PBYTE)*pvaList + cbBlock + sizeof(SLIST);
+ }
+ }
+
+ // test if the next block will fit without turning the current list into
+ // a chained list... allocate a new block & copy the old data
+
+ if (cItems + cBlock < C_ITEMS_MAX) {
+ vaListNew = VaAllocGrpCb(grp, cbBlock + cbData*cBlock + sizeof(SLIST));
+ lpListNew = LpvFromVa(vaListNew, 0);
+ memcpy((LPCH)lpListNew, lpList, cbBlock + sizeof(SLIST));
+ memcpy((LPCH)lpListNew + cbBlock + sizeof(SLIST), lpvData, cbData);
+ lpListNew->sml.cItems++;
+ DirtyVa(vaListNew);
+ FreeGrpVa(grp, *pvaList, cbBlock + sizeof(SLIST));
+ *pvaList = vaListNew;
+ if (vaDirtyOnExit) {
+ DirtyVa(vaDirtyOnExit);
+ UnlockW(LIST_LOCK+1);
+ }
+ UnlockW(LIST_LOCK);
+ return (PBYTE)vaListNew + cbBlock + sizeof(SLIST);
+ }
+
+ // this is the last item that will go into this block,
+ // allocate a new block c/w link field & copy the old data
+ // set the link field to 0 for now
+
+#if cBlock != 1
+ cBlock = C_ITEMS_MAX - cItems;
+#endif
+
+ vaListNew = VaAllocGrpCb(grp, cbBlock + cbData*cBlock + sizeof(BLIST));
+ lpListNew = LpvFromVa(vaListNew, 0);
+ memcpy(lpListNew + 1 , ((SLIST FAR *)lpList) + 1, cbBlock);
+ memcpy(((LPCH)lpListNew) + cbBlock + sizeof(BLIST), lpvData, cbData);
+ lpListNew->big.cItems = lpList->sml.cItems + 1;
+ lpListNew->big.vaNext = vaNil;
+ DirtyVa(vaListNew);
+ FreeGrpVa(grp, *pvaList, cbBlock + sizeof(SLIST));
+ *pvaList = vaListNew;
+ if (vaDirtyOnExit) {
+ DirtyVa(vaDirtyOnExit);
+ UnlockW(LIST_LOCK+1);
+ }
+ UnlockW(LIST_LOCK);
+ return (PBYTE)vaListNew + cbBlock + sizeof(BLIST);
+}
+
+WORD
+CItemsList(VA vaList)
+// return total number of items in array
+//
+{
+ if (vaList == vaNil)
+ return 0;
+
+#ifdef SWAP_INFO
+ iVMGrp = grpList;
+#endif
+
+ return ((SLIST FAR *)LpvFromVa(vaList, 0))->cItems;
+}
+
+// to use the following iterator say something like
+//
+// vaPropList = cSYM.vaPropList;
+// while (cprop = CItemsIterate(&vaProps, &vaPropList, cBlock)) {
+// gPROP(vaProps);
+// for (;--cprop >= 0; cPROP++) {
+// cPROP.etc = ;
+//
+// }
+// }
+//
+//
+// The ENM_LIST, ENM_END, ENM_BREAK macros "do the right thing" with
+// these lists.
+//
+
+WORD
+CItemsIterate(VA FAR *vaData, VA FAR *vaNext)
+// give number of elements in current block and pointer to next block
+//
+{
+ GLIST FAR *lpgList;
+ WORD cItems, cAlloc;
+
+ if (*vaNext == vaNil)
+ return 0;
+
+#ifdef SWAP_INFO
+ iVMGrp = grpList;
+#endif
+
+#if cBlock != 1
+ if (cBlock == 0) cBlock = C_ITEMS_MAX;
+#endif
+
+ lpgList = LpvFromVa(*vaNext, 0);
+
+ cItems = lpgList->sml.cItems;
+
+ if (cItems >= C_ITEMS_MAX) {
+ *vaData = (PBYTE)*vaNext + sizeof(BLIST);
+ *vaNext = lpgList->big.vaNext;
+ return C_ITEMS_MAX;
+ }
+
+ if (cBlock == 0)
+ cAlloc = C_ITEMS_MAX;
+ else {
+ cAlloc = cItems % cBlock;
+ cAlloc = cItems - cAlloc + ( cAlloc ? cBlock : 0 );
+ }
+
+ if (cAlloc >= C_ITEMS_MAX)
+ *vaData = (PBYTE)*vaNext + sizeof(BLIST);
+ else
+ *vaData = (PBYTE)*vaNext + sizeof(SLIST);
+
+ *vaNext = 0;
+ return cItems;
+}
+
+VOID
+FreeList(VA vaList, WORD cbData)
+// free up all the memory associated with this list
+//
+{
+ (PBYTE)vaList + cbData;
+ printf("FreeList is currently not working\n");
+
+#if 0
+
+ GLIST FAR * lpgList;
+ VA vaNextList;
+
+
+ if (vaList == vaNil)
+ return;
+
+top: // tail recursion
+
+ lpgList = LpvFromVa(vaList, 0);
+
+ if (lpgList->sml.cItems >= C_ITEMS_MAX) {
+
+ vaNextList = lpgList->big.vaNext;
+ FreeVa(vaList, C_ITEMS_MAX * cbData + sizeof(BLIST));
+
+ vaList = vaNextList;
+ goto top; // tail recursion
+ }
+
+ FreeVa(vaList, lpgList->sml.cItems * cbData + sizeof(SLIST));
+ return;
+#endif
+}
diff --git a/private/utils/mep/browser/mbrmake/list.h b/private/utils/mep/browser/mbrmake/list.h
new file mode 100644
index 000000000..ceee6a9c0
--- /dev/null
+++ b/private/utils/mep/browser/mbrmake/list.h
@@ -0,0 +1,41 @@
+// list.h
+//
+// a VM growable array package
+
+VA VaAddList(VA far *vaList, LPV lpvData, WORD cbData, WORD grp);
+WORD CItemsList(VA vaList);
+WORD CItemsIterate(VA FAR *vaData, VA FAR *vaNext);
+
+
+#define ENM_LIST(start, type) \
+{ \
+ VA va##type##list = (start); \
+ VA va##type##s; \
+ int cnt##type, idx##type; \
+ while (cnt##type = CItemsIterate(&va##type##s, &va##type##list)) {\
+ g##type(va##type##s); \
+ for (idx##type = 0; idx##type < cnt##type; idx##type++, (&c##type)++) {
+
+#define ENM_END } } }
+
+#define ENM_PUT(type) DirtyVa(va##type##s)
+
+#define ENM_VA(type) (va##type##s + sizeof(c##type)*idx##type)
+
+#define ENM_BREAK(type) va##type##list = 0; break;
+
+
+//
+// example use of ENM_LIST
+//
+//
+
+// ENM_LIST (vaPropList, PROP) {
+//
+// ... some things using CPROP (like below) ..
+//
+// printf("%s\n", GetAtomStr(cPROP.vaNameSym));
+//
+// ... other things using cPROP...
+//
+// } ENM_END
diff --git a/private/utils/mep/browser/mbrmake/makefile b/private/utils/mep/browser/mbrmake/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/mep/browser/mbrmake/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/mep/browser/mbrmake/mbrhash.c b/private/utils/mep/browser/mbrmake/mbrhash.c
new file mode 100644
index 000000000..269322941
--- /dev/null
+++ b/private/utils/mep/browser/mbrmake/mbrhash.c
@@ -0,0 +1,41 @@
+#include "mbrmake.h"
+WORD HashAtomStr (char *pStr) {
+
+ WORD hash = 0;
+ while (*pStr)
+ hash += (hash << 5) + *pStr++;
+
+ return (hash % (MAXSYMPTRTBLSIZ-1));
+}
+
+#if rjsa
+HashAtomStr PROC NEAR USES DS SI, npsz:DWORD
+ xor ax,ax ; (ax) = byte-extended-to-word
+ mov cx,ax ; (cx) = hash
+ mov dx,ax ; (dx) = high part for later div
+ cld
+ lds si,npsz ; (si) = pointer to string
+ align 4
+hfs1: lodsb ; get next byte
+ or al,al ; are we at end of string?
+ jz hfs2 ; yes, compute div and we're done
+ mov bx,cx
+ shl bx,1
+ shl bx,1
+ shl bx,1
+ shl bx,1
+ shl bx,1
+ add cx,bx ; (newcx) = (oldcx) + (oldcx) << 5
+ add cx,ax ; (cx) += (cx) << 5 + (ax)
+ jmp hfs1
+
+hfs2: mov ax,4094 ; magic divider
+ xchg ax,cx ; (dx:ax) = number, (cx) = dividend
+ div cx
+ mov ax,dx
+ ret
+HashAtomStr ENDP
+
+end
+
+#endif
diff --git a/private/utils/mep/browser/mbrmake/mbrmake.c b/private/utils/mep/browser/mbrmake/mbrmake.c
new file mode 100644
index 000000000..170ecb695
--- /dev/null
+++ b/private/utils/mep/browser/mbrmake/mbrmake.c
@@ -0,0 +1,756 @@
+//
+// mbrmake - Source Browser Source Data Base builder
+// (C) 1988 By Microsoft
+//
+// 29-Aug-1989 dw Minor fixes to aid in C 6 conversion
+//
+//
+
+#define LINT_ARGS
+
+// rjsa #include <signal.h>
+#include <process.h>
+#include <direct.h>
+#include <stdlib.h>
+
+// get version.h from mb
+
+#include "..\..\inc\version.h"
+
+#include "sbrvers.h"
+#include "sbrfdef.h"
+#include "mbrmake.h"
+
+#include <sys\types.h>
+#include <sys\stat.h>
+#include <tools.h>
+
+// this fixes the bogosity in config.h that gets included by tools.h
+// it will set DEBUG = 0 for a non-debug version...
+//
+// -rm
+
+#ifdef DEBUG
+#if DEBUG == 0
+#undef DEBUG
+#endif
+#endif
+
+static VOID TruncateSBR(char *lszName);
+static VOID ProcessSBR(char *lszName);
+static VOID MarkNewSBR(char *lszName);
+
+#ifdef DEBUG
+WORD near OptD = 0;
+#endif
+
+FILE * near streamOut = stdout;
+
+BOOL near OptEs = FALSE; // exclude system files
+BOOL near OptEm = FALSE; // exclude macro expansions
+BOOL near OptIu = FALSE; // include unreference symbols
+BOOL near OptV = FALSE; // verbose output
+BOOL near OptN = FALSE; // no incremental behaviour
+
+char near c_cwd[PATH_BUF]; // current working directory
+char near patbuf[PATH_BUF];
+
+MOD FAR * near modRes; // VM cache
+MODSYM FAR * near modsymRes;
+SYM FAR * near symRes;
+PROP FAR * near propRes;
+DEF FAR * near defRes;
+REF FAR * near refRes;
+CAL FAR * near calRes;
+CBY FAR * near cbyRes;
+ORD FAR * near ordRes;
+SBR FAR * near sbrRes;
+char FAR * near textRes;
+OCR FAR * near ocrRes;
+
+BYTE near fCase = FALSE; // TRUE for case compare
+BYTE near MaxSymLen = 0; // longest symbol len
+
+LSZ near lszFName; // Current input file
+
+LSZ near OutputFileName = NULL; // output file name
+FILE * near OutFile; // output file handle
+BOOL near fOutputBroken = FALSE; // we have dirtied the database
+
+VA near vaRootMod = vaNil; // module list
+VA near vaCurMod = vaNil; // current module
+
+VA near rgVaSym[MAXSYMPTRTBLSIZ]; // symbol list array
+
+EXCLINK FAR * near pExcludeFileList = NULL; // exclude file list
+
+struct mlist {
+ int erno;
+ char *text;
+};
+
+struct mlist WarnMsg[] = {
+ 4500, "UNKNOWN WARNING\n\tContact Microsoft Product Support Services",
+ 4501, "ignoring unknown option '%s'",
+ 4502, "truncated .SBR file '%s' not in database",
+};
+
+struct mlist ErrorMsg[] = {
+ 1500, "UNKNOWN ERROR\n\tContact Microsoft Product Support Services",
+ 1501, "unknown character '%c' in option '%s'",
+ 1502, "incomplete specification for option '%s'",
+ 1503, "cannot write to file '%s'",
+ 1504, "cannot position in file '%s'",
+ 1505, "cannot read from file '%s'",
+ 1506, "cannot open file '%s'",
+ 1507, "cannot open temporary file '%s'",
+ 1508, "cannot delete temporary file '%s'",
+ 1509, "out of heap space",
+ 1510, "corrupt .SBR file '%s'",
+ 1511, "invalid response file specification",
+ 1512, "database capacity exceeded",
+ 1513, "nonincremental update requires all .SBR files",
+ 1514, "all .SBR files truncated and not in database",
+};
+
+VOID
+Error (int imsg, char *parg)
+// print error number and message
+//
+{
+ printf ("mbrmake: error U%d : ",ErrorMsg[imsg].erno);
+ printf (ErrorMsg[imsg].text, parg);
+ printf ("\n");
+ Fatal();
+}
+
+VOID
+Error2 (int imsg, char achar, char *parg)
+// print error number and message with argument
+//
+{
+ printf ("mbrmake: error U%d : ",ErrorMsg[imsg].erno);
+ printf (ErrorMsg[imsg].text, achar, parg);
+ printf ("\n");
+ Fatal();
+}
+
+VOID
+Warning (int imsg, char *parg)
+// print warning number and message
+//
+{
+ printf ("mbrmake: warning U%d : ",WarnMsg[imsg].erno);
+ printf (WarnMsg[imsg].text, parg);
+ printf ("\n");
+}
+
+VOID
+Fatal ()
+// fatal error, attempt to shut down and exit
+// if we already tried to shut down -- just abort without doing anything
+{
+ static BOOL fTwice;
+ if (!fTwice) {
+ fTwice = TRUE;
+ if (fOutputBroken) {
+ if (OutFile) fclose(OutFile);
+ if (OutputFileName != NULL) unlink(OutputFileName);
+ }
+ CloseVM();
+ }
+ exit(4);
+}
+
+VOID
+sigint ()
+{
+ // signal(SIGBREAK, sigint);
+ // signal(SIGINT, sigint);
+ Fatal ();
+}
+
+LSZ
+LszDup(LSZ lsz)
+// like strdup only using LpvAllocCb to get the memory
+//
+{
+ LSZ lszDup;
+
+ lszDup = LpvAllocCb(strlen(lsz)+1);
+ strcpy(lszDup, lsz);
+ return lszDup;
+}
+
+LSZ
+LszDupNewExt(LSZ pname, LSZ pext)
+// duplicate the given filename changing the extension to be the given
+//
+{
+ int i, len, elen;
+ LSZ lsz;
+
+ len = strlen(pname);
+ elen = strlen(pext);
+
+ // I know this looks like I should be doing a runtime call but nothing
+ // does quite what I want here and I know that C6 will make great
+ // code for this loop [rm]
+
+ // find the first '.' starting from the back
+
+ for (i=len; --i >= 0; )
+ if (pname[i] == '.')
+ break;
+
+
+ // check to make sure we've got a real base name and not just all extension
+ //
+
+ if (i > 0) {
+ // replace the extension with what's in pext
+
+ lsz = LpvAllocCb(i + 1 + elen + 1); // base + dot + ext + nul
+ memcpy(lsz, pname, i+1);
+ strcpy(lsz+i+1, pext);
+ }
+ else {
+ // just stick the extension on the end...
+
+ lsz = LpvAllocCb(len + 1 + elen + 1); // fullname + dot + ext + nul
+ strcpy(lsz, pname);
+ strcat(lsz, ".");
+ strcat(lsz, pext);
+ }
+
+ return lsz;
+}
+
+VOID
+AddExcludeFileList(LSZ pname)
+// add the specifed filename to the exclusion list
+//
+{
+ EXCLINK FAR *pexc;
+
+ pexc = (EXCLINK FAR *)LpvAllocCb(sizeof(EXCLINK));
+ pexc->pxfname = LszDup(ToAbsPath(pname, c_cwd));
+
+ if (pExcludeFileList == NULL)
+ pexc->xnext = NULL;
+ else
+ pexc->xnext = pExcludeFileList;
+
+ pExcludeFileList = pexc;
+}
+
+BOOL
+FValidHeader()
+// Read in the header of a .sbr file -- return TRUE if it is valid
+//
+{
+ // test if this is a truncated (i.e. already installed) .sbr file
+ //
+ if (GetSBRRec() == S_EOF)
+ return FALSE;
+
+ if (r_rectyp != SBR_REC_HEADER)
+ SBRCorrupt("header not correct record type");
+
+ if (r_lang == SBR_L_C)
+ fCase = TRUE;
+
+ if (r_majv != 1 || r_minv != 1)
+ SBRCorrupt("incompatible .sbr format\n");
+
+ #ifdef DEBUG
+ if (OptD & 1) DecodeSBR();
+ #endif
+
+ return TRUE;
+}
+
+#ifdef PROFILE
+
+// profile prototypes and typedefs
+
+#include "casts.h"
+#include "profile.h"
+
+#endif
+
+VOID _CRTAPI1
+main (argc, argv)
+int argc;
+char *argv[];
+{
+ int i;
+ char *parg;
+ long lArgPosn;
+
+#ifdef PROFILE
+ PROFINIT(PT_USER|PT_USEKP, (FPC)NULL);
+ PROFCLEAR(PT_USER);
+ PROFON(PT_USER);
+#endif
+
+ // signal(SIGBREAK, sigint);
+ // signal(SIGINT, sigint);
+
+ printf("Microsoft (R) mbrmake Utility ");
+ printf(VERS(rmj, rmm, rup));
+ printf(CPYRIGHT);
+
+ if (argc == 1) Usage();
+
+ getcwd(c_cwd, sizeof(c_cwd));
+ ToBackSlashes(c_cwd);
+
+ parg = ParseArgs(argc, argv);
+
+ if (!parg)
+ Usage();
+
+ InitVM();
+
+ for (i=0; i < MAXSYMPTRTBLSIZ; i++) // init symbol lists
+ rgVaSym[i] = vaNil;
+
+ lArgPosn = GetArgPosn();
+
+ do {
+ ToBackSlashes(parg);
+
+ if (forfile(parg, A_ALL, MarkNewSBR, NULL) == 0)
+ Error(ERR_OPEN_FAILED, parg);
+ }
+ while (parg = NextArg());
+
+ if (!OptN && FOpenBSC(OutputFileName)) {
+ InstallBSC();
+ CloseBSC();
+ }
+ else
+ NumberSBR();
+
+ SetArgPosn(lArgPosn);
+ parg = NextArg();
+
+ do {
+ if (forfile(parg, A_ALL, ProcessSBR, NULL) == 0)
+ Error(ERR_OPEN_FAILED, parg);
+ }
+ while (parg = NextArg());
+
+ // this sort must happen before all the other calls below as they
+ // use the sorted version of the list and not the raw symbols
+
+ SortAtoms(); // create a sorted version of the atoms
+
+#ifdef DEBUG
+ if (OptD & 128) DebugDump();
+#endif
+
+ CleanUp (); // General cleaning
+
+#ifdef DEBUG
+ if (OptD & 16) DebugDump();
+#endif
+
+ WriteBSC (OutputFileName); // write .bsc Source Data Base
+
+#ifdef PROFILE
+ PROFOFF(PT_USER);
+ PROFDUMP(PT_USER, (FPC)"mbrmake.pro");
+ PROFFREE(PT_USER);
+#endif
+
+ if (!OptN) {
+ // truncate the .sbr files now
+ SetArgPosn(lArgPosn);
+ parg = NextArg();
+
+ do {
+ if (forfile(parg, A_ALL, TruncateSBR, NULL) == 0)
+ Error(ERR_OPEN_FAILED, parg);
+ }
+ while (parg = NextArg());
+
+ // touch the .bsc file so it has a date later than all the .sbrs
+
+ {
+ FILE *fh;
+ int buf = 0;
+
+ if (!(fh = fopen(OutputFileName, "ab"))) {
+ Error(ERR_OPEN_FAILED, OutputFileName);
+ }
+ if (fwrite(&buf, 1, 1, fh)==0) {
+ Error(ERR_WRITE_FAILED, OutputFileName);
+ }
+
+ fclose(fh);
+ }
+ }
+
+ CloseVM();
+ exit (0);
+}
+
+static VOID
+ProcessSBR(char *lszName)
+// process one .sbr file with the given name
+//
+{
+
+ lszFName = LszDup(lszName);
+ if ((fhCur = open(lszFName, O_BINARY|O_RDONLY)) == -1) {
+ Error(ERR_OPEN_FAILED, lszFName);
+ }
+
+ isbrCur = gSBR(VaSbrFrName(lszFName)).isbr;
+
+ if (OptV)
+ printf("Processing: %s ..\n", lszFName);
+
+ if (!FValidHeader()) {
+ FreeLpv (lszFName);
+ close(fhCur);
+ return;
+ }
+
+ // Add .SBR data to lists
+ InstallSBR ();
+
+ FreeOrdList (); // free ordinal aliases
+ close(fhCur);
+
+ FreeLpv (lszFName);
+}
+
+static VOID
+TruncateSBR(char *lszName)
+// once the .sbr file is used -- truncate it
+//
+{
+ int fh;
+
+ if (unlink(lszName) == -1) {
+ Error(ERR_OPEN_FAILED, lszFName);
+ }
+
+ if ((fh = open(lszName, O_CREAT|O_BINARY, S_IREAD|S_IWRITE)) == -1) {
+ Error(ERR_OPEN_FAILED, lszFName);
+ }
+
+ close(fh);
+}
+
+VOID
+Usage()
+{
+#ifdef DEBUG
+ printf("usage: mbrmake [-Emu] [-Ei ...] [-vd] [-help] [-o <.BSC>] [@<file>] <.sbr>...\n\n");
+#else
+ printf("usage: mbrmake [-Emu] [-Ei ...] [-v] [-help] [-o <.BSC>] [@<file>] <.sbr>...\n\n");
+#endif
+ printf(" @<file> Get arguments from specified file\n");
+ printf(" /E... Exclude:\n");
+ printf(" s system files\n");
+ printf(" i <file> named include file <file>\n");
+ printf(" i ( <files> ) named include file list <files>\n");
+ printf(" m macro expanded symbols\n");
+ printf(" /I... Include:\n");
+ printf(" u unreferenced symbols\n");
+ printf(" /o <file> output source database name\n");
+ printf(" /n no incremental (full builds, .sbr's preserved)\n");
+ printf(" /v verbose output\n");
+ printf(" /help Quick Help\n");
+#ifdef DEBUG
+ printf(" /d show debugging information\n");
+ printf(" 1 sbrdump .sbr files as they come in\n");
+ printf(" 2 show every duplicate MbrAddAtom\n");
+ printf(" 4 emit warning on forward referenced ordinal\n");
+ printf(" 8 show prop data as new items are added\n");
+ printf(" 16 bscdump database after cleanup\n");
+ printf(" 32 emit information about what cleanup is doing\n");
+ printf(" 64 emit list of sorted modules after sorting\n");
+ printf(" 128 bscdump database before cleanup\n");
+ printf(" 256 give info about duplicate/excluded modules\n");
+#endif
+ exit(1);
+}
+
+FILE *fileResp;
+int cargs;
+char ** vargs;
+int iarg = 1;
+long lFilePosnLast;
+
+LONG
+GetArgPosn()
+// save the current position on the command line
+//
+{
+ if (fileResp)
+ return lFilePosnLast;
+ else
+ return (LONG)iarg - 1;
+}
+
+VOID
+SetArgPosn(LONG lArgPosn)
+// restore the command line parsing position
+//
+{
+ if (fileResp) {
+ fseek(fileResp, lArgPosn, SEEK_SET);
+ iarg = 0;
+ }
+ else
+ iarg = (int)lArgPosn;
+}
+
+char *
+NextArg()
+// get the next argument from the response file or the command line
+//
+{
+ static char buf[PATH_BUF];
+ char *pch;
+ int c;
+ BOOL fQuote = FALSE;
+
+ if (iarg >= cargs)
+ return NULL;
+
+ if (fileResp) {
+ pch = buf;
+
+ lFilePosnLast = ftell(fileResp);
+
+ for (;;) {
+ c = getc(fileResp);
+ switch (c) {
+
+ case '"':
+ if (fQuote) {
+ *pch = '\0';
+ return buf;
+ }
+ else {
+ fQuote = TRUE;
+ continue;
+ }
+
+ case EOF:
+ iarg = cargs;
+ if (pch == buf)
+ return NULL;
+
+ *pch = '\0';
+ return buf;
+
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\f':
+ case '\n':
+ if (fQuote)
+ goto quoted;
+
+ if (pch == buf)
+ continue;
+
+ *pch = '\0';
+ return buf;
+
+ default:
+ quoted:
+ if (pch < buf + sizeof(buf) - 1)
+ *pch++ = (char)c;
+ break;
+ }
+ }
+ }
+ else
+ return vargs[iarg++];
+}
+
+char *
+ParseArgs(int argc, char **argv)
+// parse the command line or response file
+//
+{
+ char *respName;
+ char *pchWord;
+ int len;
+
+ cargs = argc;
+ vargs = argv;
+
+ for (;;) {
+ pchWord = NextArg();
+
+ if (pchWord == NULL)
+ return pchWord;
+
+ if (pchWord[0] == '@') {
+
+ if (fileResp)
+ Error(ERR_BAD_RESPONSE, "");
+ else if (pchWord[1])
+ respName = pchWord+1;
+ else if (!(respName = NextArg()))
+ Error(ERR_BAD_RESPONSE, "");
+
+ fileResp = fopen(respName, "r");
+
+ if (!fileResp)
+ Error(ERR_OPEN_FAILED, respName);
+
+ cargs++;
+
+ continue;
+ }
+
+ if (pchWord[0] != '-' && pchWord[0] != '/')
+ return pchWord;
+
+ switch (pchWord[1]) {
+
+ case 'n':
+ OptN = TRUE;
+ break;
+
+ case 'o':
+ if (pchWord[2])
+ pchWord += 2;
+ else if (!(pchWord = NextArg()))
+ Usage();
+
+ OutputFileName = LszDupNewExt (pchWord, "bsc");
+ break;
+
+ #ifdef DEBUG
+ case 'd':
+ OptD = 1;
+ if (pchWord[2]) OptD = atoi(pchWord+2);
+ break;
+ #endif
+
+ case 'E':
+ switch (pchWord[2]) {
+
+ case 0:
+ Error (ERR_MISSING_OPTION, pchWord);
+ break;
+
+ case 'm':
+ OptEm = TRUE;
+ break;
+
+ case 's':
+ OptEs = TRUE;
+ break;
+
+ default:
+ Error2 (ERR_UNKNOWN_OPTION, pchWord[2], pchWord);
+ break;
+
+ case 'i':
+ if (pchWord[3])
+ pchWord += 3;
+ else
+ pchWord = NextArg();
+
+ if (!pchWord)
+ Error (ERR_MISSING_OPTION, "-Ei");
+
+ if (pchWord[0] != '(') {
+ AddExcludeFileList(pchWord);
+ break;
+ }
+
+ if (pchWord[1])
+ pchWord++;
+ else
+ pchWord = NextArg();
+
+ for ( ;pchWord != NULL; pchWord = NextArg()) {
+ len = strlen(pchWord);
+ if (pchWord[len-1] != ')') {
+ AddExcludeFileList(pchWord);
+ }
+ else if (len > 1) {
+ pchWord[len-1] = 0;
+ AddExcludeFileList(pchWord);
+ break;
+ }
+ else
+ break;
+ }
+ if (pchWord == NULL)
+ Error (ERR_MISSING_OPTION, "-Ei (...");
+ }
+ break;
+
+ case 'I':
+ switch (pchWord[2]) {
+ case 'u':
+ OptIu = TRUE;
+ break;
+
+ default:
+ Error2 (ERR_UNKNOWN_OPTION, pchWord[2], pchWord);
+ break;
+ }
+ break;
+
+ case 'H':
+ case 'h':
+ if ((strcmpi (pchWord+1, "help")) == 0) {
+ if (spawnlp (P_WAIT, "qh", "-u", "mbrmake.exe", NULL))
+ Usage();
+ exit (0);
+ }
+ break;
+
+ case 'v':
+ OptV = TRUE;
+ break;
+
+ default:
+ Warning (WARN_OPTION_IGNORED, pchWord);
+ break;
+ }
+ }
+}
+
+
+static VOID
+MarkNewSBR(char *lszName)
+// mark the specified SBR file as requiring update
+//
+{
+ int fh;
+ char ch;
+
+ if (!OutputFileName)
+ OutputFileName = LszDupNewExt (lszName, "bsc");
+
+ if ((fh = open(lszName, O_BINARY|O_RDONLY)) == -1) {
+ Error(ERR_OPEN_FAILED, lszFName);
+ }
+
+ // if the file has non zero length then it is being updated -- else
+ // it is just a stub that will not affect the database this time around
+ //
+ if (read(fh, &ch, 1) != 1)
+ VaSbrAdd(SBR_NEW, lszName); // to remain in .bsc
+ else
+ VaSbrAdd(SBR_NEW|SBR_UPDATE, lszName); // to be re-installed in .bsc
+
+ close (fh);
+}
+
diff --git a/private/utils/mep/browser/mbrmake/mbrmake.h b/private/utils/mep/browser/mbrmake/mbrmake.h
new file mode 100644
index 000000000..904ee8dfb
--- /dev/null
+++ b/private/utils/mep/browser/mbrmake/mbrmake.h
@@ -0,0 +1,246 @@
+#define MAXSYMPTRTBLSIZ 4095 // max symbol pointer table size
+#define PATH_BUF 512 // path buffer size
+
+
+#include <io.h>
+#include <fcntl.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <string.h>
+
+#if defined (OS2)
+#define INCL_NOCOMMON
+#define INCL_DOSPROCESS
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSFILEMGR
+#define INCL_DOSERRORS
+#define INCL_DOSMISC
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+
+#include "hungary.h"
+#include "vm.h"
+#include "list.h"
+#include "errors.h"
+
+
+
+// rjsa 10/22/90
+// Some runtime library functions are broken, so intrinsics have
+// to be used.
+// BUGBUG
+//#pragma intrinsic (memset, memcpy, memcmp)
+//#pragma intrinsic (strset, strcpy, strcmp, strcat, strlen)
+
+#ifndef LINT_PROTO
+#include "sbrproto.h"
+#endif
+
+#pragma pack(1)
+
+#if rjsa
+extern void far * cdecl _fmalloc(unsigned int);
+extern void cdecl _ffree(void far *);
+extern char * cdecl getenv(const char *);
+extern char * cdecl mktemp(char *);
+extern char * cdecl strdup(const char *);
+#endif
+
+// typedef char flagType;
+
+typedef struct {
+ VA vaNextMod; // next module
+ VA vaNameSym; // name Symbol
+ VA vaFirstModSym; // first ModSym for this file
+ VA vaLastModSym; // last ModSym for this file
+ WORD csyms; // symbol count
+} MOD;
+
+typedef struct {
+ VA vaNextModSym; // next symbol
+ VA vaFirstProp; // first prop entry for this symbol
+} MODSYM;
+
+typedef struct {
+ VA vaNextSym; // next symbol
+ VA vaFirstProp; // first prop entry for this symbol
+ VA vaNameText; // the text of this symbol
+ WORD cprop; // Property count
+ WORD isym; // this symbol index
+} SYM;
+
+typedef struct {
+ VA vaNextProp; // next property
+ WORD iprp; // this property index
+ WORD sattr; // attribute
+ WORD cref;
+ VA vaNameSym; // symbol name ptr
+ VA vaDefList; // def chain
+ VP vpFirstRef; // ref head
+ VP vpLastRef; // ref tail
+ VA vaCalList; // cal chain
+ VA vaCbyList; // cby chain
+ VA vaHintRef; // last ref we found by searching
+} PROP;
+
+typedef struct {
+ VA vaFileSym; // file name Symbol ptr
+ WORD deflin; // def line #
+ WORD isbr; // sbr file owning this DEF
+} DEF;
+
+typedef struct {
+ VP vpNextRef; // next ref in list
+ VP vpFileSym; // file name Symbol ptr
+ WORD reflin; // ref line #
+ WORD isbr; // sbr file owning this REF
+} REF;
+
+typedef struct {
+ VA vaCalProp; // prop called/used
+ WORD calcnt; // times called
+ WORD isbr; // sbr file owning this CAL
+} CAL;
+
+typedef struct {
+ VA vaCbyProp; // prop calling/using
+ WORD cbycnt; // times calling/using
+ WORD isbr; // sbr file owning this CBY
+} CBY;
+
+typedef struct {
+ VA vaNextOrd; // next ord
+ VA vaOrdProp; // prop item alias goes to
+ WORD aliasord; // ordinal
+} ORD;
+
+typedef struct {
+ VA vaNextSbr; // next sbr
+ WORD isbr; // index for this SBR file
+ BOOL fUpdate; // is this SBR file being updated?
+ char szName[1]; // name
+} SBR;
+
+typedef struct {
+ VA vaOcrProp; // prop occurring
+ WORD isbr; // SBR file it occurs in
+} OCR;
+
+typedef struct exclink {
+ struct exclink FAR *xnext; // next exclusion
+ LPCH pxfname; // exclude file name
+} EXCLINK, FAR *LPEXCL;
+
+#include "extern.h"
+
+// macros to 'g'et an item of the specified type from VM space
+
+#ifdef SWAP_INFO
+
+#define gMOD(va) (*(iVMGrp = grpMod, modRes = LpvFromVa(va,1)))
+#define gMODSYM(va) (*(iVMGrp = grpModSym, modsymRes = LpvFromVa(va,2)))
+#define gSYM(va) (*(iVMGrp = grpSym, symRes = LpvFromVa(va,3)))
+#define gPROP(va) (*(iVMGrp = grpProp, propRes = LpvFromVa(va,4)))
+#define gDEF(va) (*(iVMGrp = grpDef, defRes = LpvFromVa(va,5)))
+#define gREF(va) (*(iVMGrp = grpRef, refRes = LpvFromVa(va,6)))
+#define gCAL(va) (*(iVMGrp = grpCal, calRes = LpvFromVa(va,7)))
+#define gCBY(va) (*(iVMGrp = grpCby, cbyRes = LpvFromVa(va,8)))
+#define gORD(va) (*(iVMGrp = grpOrd, ordRes = LpvFromVa(va,9)))
+#define gSBR(va) (*(iVMGrp = grpSbr, sbrRes = LpvFromVa(va,13)))
+#define gTEXT(va) ((iVMGrp = grpText, textRes = LpvFromVa(va,12)))
+#define gOCR(va) (*(iVMGrp = grpOcr, ocrRes = LpvFromVa(va,14)))
+
+#else
+
+#define gMOD(va) (*(modRes = LpvFromVa(va,1)))
+#define gMODSYM(va) (*(modsymRes = LpvFromVa(va,2)))
+#define gSYM(va) (*(symRes = LpvFromVa(va,3)))
+#define gPROP(va) (*(propRes = LpvFromVa(va,4)))
+#define gDEF(va) (*(defRes = LpvFromVa(va,5)))
+#define gREF(va) (*(refRes = LpvFromVa(va,6)))
+#define gCAL(va) (*(calRes = LpvFromVa(va,7)))
+#define gCBY(va) (*(cbyRes = LpvFromVa(va,8)))
+#define gORD(va) (*(ordRes = LpvFromVa(va,9)))
+#define gSBR(va) (*(sbrRes = LpvFromVa(va,13)))
+#define gTEXT(va) ((textRes = LpvFromVa(va,12)))
+#define gOCR(va) (*(ocrRes = LpvFromVa(va,14)))
+
+#endif
+
+// macros to 'p'ut an item of the specified type to VM space
+
+#define pMOD(va) DirtyVa(va)
+#define pMODSYM(va) DirtyVa(va)
+#define pSYM(va) DirtyVa(va)
+#define pPROP(va) DirtyVa(va)
+#define pDEF(va) DirtyVa(va)
+#define pREF(va) DirtyVa(va)
+#define pCAL(va) DirtyVa(va)
+#define pCBY(va) DirtyVa(va)
+#define pORD(va) DirtyVa(va)
+#define pSBR(va) DirtyVa(va)
+#define pTEXT(va) DirtyVa(va)
+#define pOCR(va) DirtyVa(va)
+
+// these macros allow access to the 'c'urrent visible item
+
+#define cMOD (*modRes)
+#define cMODSYM (*modsymRes)
+#define cSYM (*symRes)
+#define cPROP (*propRes)
+#define cDEF (*defRes)
+#define cREF (*refRes)
+#define cCAL (*calRes)
+#define cCBY (*cbyRes)
+#define cORD (*ordRes)
+#define cSBR (*sbrRes)
+#define cTEXT (textRes)
+#define cOCR (*ocrRes)
+
+#define grpSym 0
+#define grpMod 1
+#define grpOrd 2
+#define grpProp 3
+#define grpModSym 4
+#define grpDef 5
+#define grpRef 6
+#define grpCal 7
+#define grpCby 8
+#define grpList 9
+#define grpText 10
+#define grpSbr 11
+#define grpOcr 12
+
+#define SBR_OLD (1<<0) // this .sbr file used to exist
+#define SBR_NEW (1<<1) // this .sbr file currently exists
+#define SBR_UPDATE (1<<2) // this .sbr file is to be updated
+
+//
+// this is used to add items to the tail of the lists in a property group
+//
+// things being added type m
+// ------------------ ---- ---
+// Refs Ref REF
+// Defs Def DEF
+// Calls/Uses Cal CAL
+// Called by/Used By Cby CBY
+//
+
+#define AddTail(type, m) \
+{ \
+ VP vpT; \
+ VA vaT; \
+ MkVpVa(vpT, va##type); \
+ vaT = VaFrVp(cPROP.vpLast##type); \
+ if (vaT) { \
+ g##m(vaT).vpNext##type = vpT; \
+ p##m(vaT); \
+ } \
+ else { \
+ cPROP.vpFirst##type = vpT; \
+ } \
+ cPROP.vpLast##type = vpT; \
+}
diff --git a/private/utils/mep/browser/mbrmake/mbrwbsc.c b/private/utils/mep/browser/mbrmake/mbrwbsc.c
new file mode 100644
index 000000000..a63e6a520
--- /dev/null
+++ b/private/utils/mep/browser/mbrmake/mbrwbsc.c
@@ -0,0 +1,782 @@
+//
+//
+// mbRWBSC.C - Write .BSC Source Data Base file from various lists.
+//
+//
+
+#define LINT_ARGS
+
+#include <stdlib.h>
+#include <search.h>
+#include <ctype.h>
+
+#include "sbrfdef.h"
+#include "mbrmake.h"
+#include "sbrbsc.h"
+#include "mbrcache.h"
+
+// prototypes
+//
+
+static void pascal WriteBSCHeader (void);
+static void pascal WriteAtoms (void);
+static void pascal WriteMods (void);
+static void pascal WriteModSyms (void);
+static void pascal WriteSyms (void);
+static void pascal WriteProps (void);
+static void pascal WriteRefs (void);
+static void pascal WriteDefs (void);
+static void pascal WriteCals (void);
+static void pascal WriteCbys (void);
+static void pascal WriteSbrInfo (void);
+static void pascal IndexTree (void);
+static void pascal BSCWrite (LPV lpv, WORD cch);
+static void pascal BSCWriteLsz (LSZ lsz);
+
+//
+
+#define BSCOut(v) BSCWrite(&(v), sizeof(v))
+
+static WORD CntAtomPage; // count of Atom pages
+static WORD AtomCnt = 0;
+
+static WORD unknownModName; // UNKNOWN module idx
+
+static WORD ModSymCnt = 0; // count of modsyms
+static WORD SymCnt = 0; // count of symbols
+static WORD PropCnt = 0; // count of props
+static DWORD RefCnt = 0; // count of refs
+static WORD DefCnt = 0; // count of defs
+static WORD CbyCnt = 0; // count of use half of above
+static WORD CalCnt = 0; // count of used by half of above
+
+static DWORD lbModList; // offset to Module list
+static DWORD lbModSymList; // offset to ModSym list
+static DWORD lbSymList; // offset to Symbol list
+static DWORD lbPropList; // offset to Property list
+static DWORD lbRefList; // offset to Reference list
+static DWORD lbDefList; // offset to Definition list
+static DWORD lbCalList; // offset to Call/used list
+static DWORD lbCbyList; // offset to Call/used list
+static DWORD lbAtomCache; // offset to Sym Atom cache
+static DWORD lbSbrList; // offset to Sbr file names
+
+extern char far *GetAtomCache (WORD);
+
+void
+WriteBSC (char *OutputFileName)
+// Write .BSC Source Data Base
+//
+{
+ OutFile = fopen(OutputFileName, "wb");
+ if (OutFile == NULL) {
+ Error(ERR_OPEN_FAILED, OutputFileName);
+ }
+
+ //
+ // no backing out from here -- if we fail we must delete the database
+ //
+
+ fOutputBroken = TRUE;
+
+ WriteBSCHeader(); // save space for header
+
+ WriteAtoms(); // sort and write atom cache
+
+ IndexTree(); // xlate pointers to indices
+
+ BldModSymList(); // Build module symbol list
+
+ SetVMClient(VM_EMIT_TREE);
+
+ unknownModName = gSYM(vaUnknownSym).isym; // record UNKNOWN index
+
+ WriteMods(); // output modules
+ WriteModSyms(); // output module symbol lists
+ WriteSyms(); // output all symbols
+ WriteProps(); // output all prop headers
+ WriteRefs(); // output all refs
+ WriteDefs(); // output all defs
+ WriteCals(); // output all uses/calls
+ WriteCbys(); // output all UBY/CBY
+ WriteSbrInfo(); // output the SBR file names
+
+ if (fseek(OutFile, 0L, SEEK_SET)) // Beginning of file
+ SeekError (OutputFileName);
+
+ WriteBSCHeader (); // output .BSC header
+
+ fclose(OutFile);
+
+ //
+ // we're all done --- it's a keeper!
+ //
+
+ fOutputBroken = FALSE;
+
+ SetVMClient(VM_MISC);
+
+ if (OptV) {
+ printf ("%u\tModules\n", ModCnt);
+ printf ("%u\tSymbols\n", SymCnt);
+ printf ("%u\tDefinitions\n", DefCnt);
+ printf ("%u\tReferences\n", RefCnt);
+ printf ("%u\tCalls/Uses\n", CalCnt);
+ printf ("%u\tCalled by/Used by\n", CbyCnt);
+#ifdef DEBUG
+ printf ("\n");
+ printf ("%u\tTotal ModSyms\n", ModSymCnt);
+ printf ("%u\tTotal Properties\n", PropCnt);
+ printf ("%u\tLast Atom page \n", AtomCnt);
+ printf ("\n");
+ printf ("%lu\tBase of AtomCache\n", lbAtomCache);
+ printf ("%lu\tBase of ModList\n", lbModList);
+ printf ("%lu\tBase of ModSymList\n", lbModSymList);
+ printf ("%lu\tBase of SymList\n", lbSymList);
+ printf ("%lu\tBase of PropList\n", lbPropList);
+ printf ("%lu\tBase of RefList\n", lbRefList);
+ printf ("%lu\tBase of DefList\n", lbDefList);
+ printf ("%lu\tBase of CalList\n", lbCalList);
+ printf ("%lu\tBase of CbyList\n", lbCbyList);
+#endif
+ }
+}
+
+static void pascal
+WriteBSCHeader ()
+// Write .BSC header, counts, and table offsets.
+//
+{
+ BYTE ver; // version num
+
+ // output BSC version (major and minor)
+
+ ver = BSC_MAJ;
+ BSCOut(ver); // major ver
+
+ ver = BSC_MIN;
+ BSCOut(ver); // minor ver
+
+ ver = BSC_UPD;
+ BSCOut(ver); // update ver
+
+ BSCOut(fCase); // case sensitive
+ BSCOut(MaxSymLen); // biggest symbol allowed
+
+ BSCOut(unknownModName); // UNKNOWN idx
+
+ // output counts (sizes) of each data area
+
+ BSCOut(ModCnt);
+ BSCOut(ModSymCnt);
+ BSCOut(SymCnt);
+ BSCOut(PropCnt);
+ BSCOut(RefCnt);
+ BSCOut(DefCnt);
+ BSCOut(CalCnt);
+ BSCOut(CbyCnt);
+
+ // last page #
+
+ BSCOut(CntAtomPage);
+
+ // last page size
+
+ BSCOut(AtomCnt);
+
+ // output BSC data area offsets
+
+ BSCOut(lbModList);
+ BSCOut(lbModSymList);
+ BSCOut(lbSymList);
+ BSCOut(lbPropList);
+ BSCOut(lbRefList);
+ BSCOut(lbDefList);
+ BSCOut(lbCalList);
+ BSCOut(lbCbyList);
+ BSCOut(lbAtomCache);
+ BSCOut(lbSbrList);
+}
+
+static void pascal
+WriteAtoms ()
+// Write a sorted version of the symbol Atom Cache to the .BSC file by walking
+// the sorted symbol subscript array
+//
+{
+ WORD i;
+ int Atomlen;
+ LPCH lpchAtoms;
+ LSZ lszAtom;
+
+ VA vaSym;
+
+ SetVMClient(VM_EMIT_ATOMS);
+
+ lpchAtoms = LpvAllocCb(ATOMALLOC);
+
+ lbAtomCache = ftell(OutFile); // offset to text of symbols
+
+ for (i=0; i < cAtomsMac; i++) {
+ vaSym = rgvaSymSorted[i];
+ if (vaSym == vaNil) continue;
+
+ gSYM(vaSym);
+ lszAtom = gTEXT(cSYM.vaNameText);
+
+ Atomlen = strlen(lszAtom);
+
+ // write Atom page if not enough room
+ //
+ if (Atomlen + AtomCnt + 1 > ATOMALLOC) {
+ if (AtomCnt < ATOMALLOC)
+ memset(lpchAtoms + AtomCnt, 0, ATOMALLOC - AtomCnt);
+
+ if ((fwrite (lpchAtoms, ATOMALLOC, 1, OutFile)) != 1)
+ WriteError (OutputFileName);
+
+ CntAtomPage++;
+ AtomCnt = 0;
+ }
+
+ strcpy(lpchAtoms + AtomCnt, lszAtom); // copy Atom
+
+ cSYM.vaNameText = (PVOID)(((long)CntAtomPage << 16) | (AtomCnt));
+
+ pSYM(vaSym);
+
+ AtomCnt += Atomlen + 1;
+
+ // force to even value
+ if (AtomCnt & 1) lpchAtoms[AtomCnt++] = 0;
+ }
+
+ // write last Atom page
+ //
+ if (AtomCnt)
+ if ((fwrite (lpchAtoms, AtomCnt, 1, OutFile)) != 1)
+ WriteError (OutputFileName);
+
+ // free all the memory for the atom cache, we no longer need it
+
+ fflush (OutFile);
+
+ FreeLpv(lpchAtoms);
+
+ SetVMClient(VM_MISC);
+}
+
+static void pascal
+WriteMods()
+// write out the list of modules
+//
+// compute the MODSYM indices as we do this
+//
+{
+ MODLIST bmod;
+ VA vaMod;
+ WORD i;
+
+ ModSymCnt = 0;
+ lbModList = ftell(OutFile); // offset to Module list
+
+ for (i = cSymbolsMac; i < cAtomsMac; i++) {
+ gSYM(rgvaSymSorted[i]);
+ vaMod = cSYM.vaFirstProp; // points back to module, honest!
+ gMOD(vaMod);
+
+ bmod.ModName = gSYM(cMOD.vaNameSym).isym; // module name idx
+ ModSymCnt += cMOD.csyms;
+ bmod.mSymEnd = ModSymCnt; // last ModSym idx +1
+ BSCOut(bmod);
+ }
+}
+
+static void pascal
+WriteModSyms()
+// write out the list of modsyms
+//
+{
+ MODSYMLIST bmodsym;
+ VA vaMod, vaModSym;
+ WORD i;
+
+ lbModSymList = ftell(OutFile); // offset to ModSym list
+
+ for (i = cSymbolsMac; i < cAtomsMac; i++) {
+ gSYM(rgvaSymSorted[i]);
+ vaMod = cSYM.vaFirstProp; // points back to module, honest!
+ gMOD(vaMod);
+
+ vaModSym = cMOD.vaFirstModSym;
+ while (vaModSym) {
+ gMODSYM(vaModSym);
+
+ // Symbol Property idx
+ bmodsym.ModSymProp = gPROP(cMODSYM.vaFirstProp).iprp;
+
+ BSCOut(bmodsym);
+
+ vaModSym = cMODSYM.vaNextModSym;
+ }
+ }
+}
+
+static void pascal
+WriteSyms()
+// write out the list of SYMs
+//
+{
+ SYMLIST bsym;
+ VA vaSym;
+ WORD i;
+
+ lbSymList = ftell(OutFile); // offset to Symbol list
+
+ PropCnt = 0;
+ for (i=0; i < cAtomsMac; i++) {
+ vaSym = rgvaSymSorted[i];
+ if (vaSym == vaNil) continue;
+
+ gSYM(vaSym);
+
+ PropCnt += cSYM.cprop;
+
+ bsym.PropEnd = PropCnt; // last Prop idx +1
+ bsym.Atom = (WORD)((long)cSYM.vaNameText & 0xffff); // Atom cache offset
+ bsym.Page = (WORD)((long)cSYM.vaNameText >> 16); // Atom cache page
+
+ BSCOut(bsym);
+ }
+}
+
+static void pascal
+WriteProps ()
+// write out the list of PROPS to the database
+//
+// the number of definitions (DefCnt), references (RefCnt),
+// calls (CalCnt) and called-by (CbyCnt) items are computed at this time
+//
+// Each PROP is assigned numbers for its associated objects
+//
+{
+ PROPLIST bprop;
+ VA vaSym, vaProp;
+ WORD i;
+
+ lbPropList = ftell(OutFile); // offset to Property list
+
+ DefCnt = 0;
+ RefCnt = 0L;
+ CalCnt = 0;
+ CbyCnt = 0;
+
+ for (i=0; i < cSymbolsMac; i++) {
+ vaSym = rgvaSymSorted[i];
+ if (vaSym == vaNil) continue;
+
+ vaProp = gSYM(vaSym).vaFirstProp;
+
+ while (vaProp) {
+ gPROP(vaProp);
+ gSYM(cPROP.vaNameSym);
+
+ bprop.PropName = cSYM.isym; // Symbol idx
+ bprop.PropAttr = cPROP.sattr; // Property Attribute
+
+ DefCnt += CItemsList(cPROP.vaDefList);
+
+ bprop.DefEnd = DefCnt; // last Definition idx +1
+
+ RefCnt += cPROP.cref;
+
+ bprop.RefEnd = RefCnt; // last Reference idx +1
+
+ CalCnt += CItemsList(cPROP.vaCalList);
+
+ bprop.CalEnd = CalCnt; // last Calls/uses idx +1
+
+ CbyCnt += CItemsList(cPROP.vaCbyList);
+
+ bprop.CbyEnd = CbyCnt; // last Called by/used by idx +1
+
+ BSCOut(bprop);
+
+ vaProp = cPROP.vaNextProp;
+ }
+ }
+}
+
+static void pascal
+WriteRefs()
+// write out the list of references
+//
+{
+ REFLIST bref;
+ VA vaSym, vaProp, vaRef;
+ WORD i;
+
+ lbRefList = ftell(OutFile); // offset to Reference list
+
+ for (i=0; i < cSymbolsMac; i++) {
+ vaSym = rgvaSymSorted[i];
+ if (vaSym == vaNil) continue;
+
+ vaProp = gSYM(vaSym).vaFirstProp;
+
+ while (vaProp) {
+ gPROP(vaProp);
+
+ vaRef = VaFrVp(cPROP.vpFirstRef);
+ while (vaRef) {
+ gREF(vaRef);
+
+ gSYM(VaFrVp(cREF.vpFileSym));
+
+ bref.RefNam = cSYM.isym; // Symbol idx
+ bref.RefLin = cREF.reflin; // Symbol lin
+ bref.isbr = cREF.isbr; // owner
+
+ BSCOut(bref);
+
+ vaRef = VaFrVp(cREF.vpNextRef);
+ }
+
+ vaProp = cPROP.vaNextProp;
+ }
+ }
+}
+
+static void pascal
+WriteDefs()
+// write out the list of defintions
+//
+{
+ REFLIST bdef;
+ WORD i;
+ VA vaProp, vaSym;
+
+ lbDefList = ftell(OutFile); // offset to Definition list
+
+ for (i=0; i < cSymbolsMac; i++) {
+ vaSym = rgvaSymSorted[i];
+ if (vaSym == vaNil) continue;
+
+ vaProp = gSYM(vaSym).vaFirstProp;
+
+ while (vaProp) {
+ gPROP(vaProp);
+
+ ENM_LIST (cPROP.vaDefList, DEF)
+
+ gSYM(cDEF.vaFileSym);
+
+ bdef.RefNam = cSYM.isym; // Symbol idx
+ bdef.RefLin = cDEF.deflin; // Symbol lin
+ bdef.isbr = cDEF.isbr; // owner
+
+ BSCOut(bdef);
+
+ ENM_END
+
+ vaProp = cPROP.vaNextProp;
+ }
+ }
+}
+
+static void pascal
+WriteCals()
+// write out the list of uses (CALs) items
+//
+{
+ USELIST buse;
+ PROP prop;
+ VA vaSym, vaProp;
+ WORD i;
+
+ lbCalList = ftell(OutFile); // offset to CAL list
+
+ for (i=0; i < cSymbolsMac; i++) {
+ vaSym = rgvaSymSorted[i];
+ if (vaSym == vaNil) continue;
+
+ vaProp = gSYM(vaSym).vaFirstProp;
+
+ while (vaProp) {
+ prop = gPROP(vaProp);
+
+ ENM_LIST(prop.vaCalList, CAL)
+
+ gPROP(cCAL.vaCalProp);
+
+ buse.UseProp = cPROP.iprp; // property idx
+ buse.UseCnt = (BYTE) cCAL.calcnt; // use count
+ buse.isbr = cCAL.isbr; // owner
+
+ BSCOut(buse);
+
+ ENM_END
+
+ vaProp = prop.vaNextProp;
+ }
+ }
+ BSCOut(buse); // Pad
+}
+
+static void pascal
+WriteCbys()
+// write out the list of used-by (CBY) items
+//
+{
+ USELIST buse;
+ PROP prop;
+ VA vaSym, vaProp;
+ WORD i;
+
+ lbCbyList = ftell(OutFile); // offset to CBY list
+
+ for (i=0; i < cSymbolsMac; i++) {
+ vaSym = rgvaSymSorted[i];
+ if (vaSym == vaNil) continue;
+
+ vaProp = gSYM(vaSym).vaFirstProp;
+
+ while (vaProp) {
+ prop = gPROP(vaProp);
+
+ ENM_LIST(prop.vaCbyList, CBY)
+
+ gPROP(cCBY.vaCbyProp);
+
+ buse.UseProp = cPROP.iprp; // property idx
+ buse.UseCnt = (BYTE) cCBY.cbycnt; // use count
+ buse.isbr = cCBY.isbr; // owner
+
+ BSCOut(buse);
+
+ ENM_END
+
+ vaProp = prop.vaNextProp;
+ }
+ }
+ BSCOut(buse); // Pad
+}
+
+static void pascal
+WriteSbrInfo()
+// write out the names of the .sbr files in the correct order
+//
+{
+ VA vaSbr;
+ WORD isbr;
+ VA *rgVaSbr;
+
+ lbSbrList = ftell(OutFile);
+
+ rgVaSbr = (VA *)LpvAllocCb(SbrCnt * (WORD)sizeof(VA));
+
+ for (isbr = 0; isbr < SbrCnt; isbr++)
+ rgVaSbr[isbr] = vaNil;
+
+ vaSbr = vaRootSbr;
+ while (vaSbr) {
+ gSBR(vaSbr);
+ if (cSBR.isbr != -1)
+ rgVaSbr[cSBR.isbr] = vaSbr;
+
+ vaSbr = cSBR.vaNextSbr;
+ }
+
+ for (isbr = 0; isbr < SbrCnt; isbr++) {
+ if (rgVaSbr[isbr] != vaNil) {
+ gSBR(rgVaSbr[isbr]);
+ BSCWriteLsz(cSBR.szName);
+ }
+ }
+ BSCWriteLsz("");
+}
+
+static void pascal
+IndexTree ()
+// Walk all the list of all symbols and index each prop as we find it
+// at this point we also count the total number of defs + refs to
+// make sure that we can actually create this database
+//
+{
+ VA vaSym, vaProp;
+ DWORD cdefs = 0;
+ DWORD crefs = 0;
+ DWORD ccals = 0;
+ DWORD ccbys = 0;
+ WORD i;
+
+ SetVMClient(VM_INDEX_TREE);
+
+ SymCnt = 0;
+ PropCnt = 0;
+
+ for (i=0; i < cAtomsMac; i++) {
+ vaSym = rgvaSymSorted[i];
+ if (vaSym == vaNil) continue;
+
+ gSYM(vaSym);
+ cSYM.isym = SymCnt++; // Symbol index
+ pSYM(vaSym);
+
+ // the vaFirstProp field is used for something else in module symbols
+ if (cSYM.cprop)
+ vaProp = cSYM.vaFirstProp;
+ else
+ vaProp = vaNil;
+
+ while (vaProp) {
+ gPROP(vaProp);
+
+ cPROP.iprp = PropCnt++; // Property index
+
+ cdefs += CItemsList(cPROP.vaDefList);
+ crefs += cPROP.cref;
+ ccals += CItemsList(cPROP.vaCalList);
+ ccbys += CItemsList(cPROP.vaCbyList);
+
+ pPROP(vaProp);
+
+ vaProp = cPROP.vaNextProp;
+ }
+ }
+ SymCnt -= ModCnt; // Subtract module names
+
+ if (cdefs > 0xffffL ||
+ crefs > 0xffffffL ||
+ ccals > 0xffffL ||
+ ccbys > 0xffffL) {
+ if (OptV) {
+ printf ("%u\tModules\n", ModCnt);
+ printf ("%u\tSymbols\n", SymCnt);
+ printf ("%lu\tDefinitions\n", cdefs);
+ printf ("%lu\tReferences\n", crefs);
+ printf ("%lu\tCalls/Uses\n", ccals);
+ printf ("%lu\tCalled by/Used by\n", ccbys);
+ }
+ Error(ERR_CAPACITY_EXCEEDED, "");
+ }
+
+ SetVMClient(VM_MISC);
+}
+
+static void pascal
+BSCWrite(LPV lpv, WORD cch)
+// write block to the .bsc file
+//
+{
+ if (fwrite(lpv, cch, 1, OutFile) != 1)
+ WriteError (OutputFileName);
+}
+
+static void pascal
+BSCWriteLsz(LSZ lsz)
+// write a null terminated string to the BSC file
+//
+{
+ BSCWrite(lsz, (WORD)(strlen(lsz)+1));
+}
+
+
+#ifdef DEBUG
+
+void
+DebugDump()
+{
+ VA vaMod, vaProp, vaSym;
+ WORD i;
+
+ vaMod = vaRootMod;
+ printf("Modules:\n");
+ while (vaMod) {
+ gMOD(vaMod);
+ printf ("\t%s\n", GetAtomStr (cMOD.vaNameSym));
+ vaMod = cMOD.vaNextMod;
+ }
+ printf ("\nAll Symbols:\n");
+
+ for (i=0; i < cAtomsMac; i++) {
+ vaSym = rgvaSymSorted[i];
+ if (vaSym == vaNil) continue;
+
+ gSYM(vaSym);
+
+ // the vaFirstProp field is used for something else in module symbols
+ if (cSYM.cprop)
+ vaProp = cSYM.vaFirstProp;
+ else
+ vaProp = vaNil;
+
+ while (vaProp) {
+ gPROP(vaProp);
+
+ DebugDumpProp(vaProp);
+
+ vaProp = gPROP(vaProp).vaNextProp;
+ }
+ }
+}
+
+void
+DebugDumpProp(VA vaProp)
+{
+ PROP prop;
+ VA vaRef;
+
+ gPROP(vaProp);
+ prop = cPROP;
+
+ printf ("%s ", GetAtomStr (prop.vaNameSym));
+ printf ("\t\t[%d %d %d %d]\n",
+ CItemsList(prop.vaDefList),
+ prop.cref,
+ CItemsList(prop.vaCalList),
+ CItemsList(prop.vaCbyList)
+ );
+
+ ENM_LIST(prop.vaDefList, DEF)
+
+ printf ("\tdefined in %s(%d) <%d>\n",
+ GetAtomStr (cDEF.vaFileSym),
+ cDEF.deflin,
+ cDEF.isbr
+ );
+ ENM_END
+
+ vaRef = VaFrVp(prop.vpFirstRef);
+ while (vaRef) {
+ gREF(vaRef);
+
+ printf ("\trefer'd in %s(%d) <%d>\n",
+ GetAtomStr ( VaFrVp(cREF.vpFileSym) ),
+ cREF.reflin,
+ cREF.isbr
+ );
+
+ vaRef = VaFrVp(cREF.vpNextRef);
+ }
+
+ ENM_LIST(prop.vaCalList, CAL)
+
+ printf ("\tcalls/uses %s[%d] <%d>\n",
+ GetAtomStr (gPROP(cCAL.vaCalProp).vaNameSym),
+ cCAL.calcnt,
+ cCAL.isbr
+ );
+ ENM_END
+
+ ENM_LIST(prop.vaCbyList, CBY)
+
+ printf ("\tc-by/u-by %s[%d] <%d>\n",
+ GetAtomStr (gPROP(cCBY.vaCbyProp).vaNameSym),
+ cCBY.cbycnt,
+ cCBY.isbr
+ );
+ ENM_END
+
+}
+#endif
diff --git a/private/utils/mep/browser/mbrmake/ord.c b/private/utils/mep/browser/mbrmake/ord.c
new file mode 100644
index 000000000..ea0d8c44d
--- /dev/null
+++ b/private/utils/mep/browser/mbrmake/ord.c
@@ -0,0 +1,116 @@
+//
+// ORD.C - Keep track of ordinals in the current .sbr file
+//
+//
+
+#include "mbrmake.h"
+
+static WORD near cOrdFree; // number of free ords in this block
+static VA near vaOrdNext; // the next free ord
+static VA near vaOrdBase; // the first ord in this block
+static VA near vaOrdRoot; // the first ord block
+
+// ordinals may be sparse so they are hashed
+//
+// number of hash buckets
+
+#define PORD_MAX 512
+#define HASH_ORD(ord) ((ord)&511)
+
+static VA near rgvaOrd[PORD_MAX]; // array of linked-lists
+
+// allocation blocking (ORD_BLOCK objects per alloc)
+#define ORD_BLOCK 128
+
+VOID
+FreeOrdList()
+// free the ordinal alias list
+//
+{
+ int i;
+
+ // clean the hash table
+ for (i=0; i<PORD_MAX; i++)
+ rgvaOrd[i] = vaNil;
+
+ vaOrdBase = vaOrdRoot;
+ vaOrdNext = (PBYTE)vaOrdRoot + sizeof(ORD);
+ cOrdFree = ORD_BLOCK - 1;
+}
+
+
+VA
+VaOrdFind (WORD ord)
+// search for the specified ord, return the corresponding PROP entry
+// return vaNil if not found
+//
+{
+ VA vaOrd;
+
+ SetVMClient(VM_SEARCH_ORD);
+
+ vaOrd = rgvaOrd[HASH_ORD(ord)];
+
+ while (vaOrd) {
+ if (ord == gORD(vaOrd).aliasord) {
+ SetVMClient(VM_MISC);
+ return(cORD.vaOrdProp);
+ }
+ else
+ vaOrd = cORD.vaNextOrd;
+ }
+
+ SetVMClient(VM_MISC);
+ return(vaNil);
+}
+
+VA
+VaOrdAdd()
+// Add the symbol ordinal to the alias list.
+//
+{
+ VA vaOrdNew;
+
+ SetVMClient(VM_ADD_ORD);
+
+ if (cOrdFree--) {
+ vaOrdNew = vaOrdNext;
+ vaOrdNext = (PBYTE)vaOrdNext + sizeof(ORD);
+ }
+ else if (vaOrdBase && gORD(vaOrdBase).vaNextOrd) {
+ // if there is an old allocated block that we can re-use, then do so
+ vaOrdBase = cORD.vaNextOrd;
+ vaOrdNew = (PBYTE)vaOrdBase + sizeof(ORD);
+ vaOrdNext = (PBYTE)vaOrdNew + sizeof(ORD);
+ cOrdFree = ORD_BLOCK - 2;
+ }
+ else {
+
+ // allocate a new block -- keep a backwards pointer in this block
+
+ vaOrdNew = VaAllocGrpCb(grpOrd, sizeof(ORD) * ORD_BLOCK);
+
+ if (!vaOrdRoot)
+ vaOrdRoot = vaOrdNew;
+
+ if (vaOrdBase) {
+ gORD(vaOrdBase);
+ cORD.vaNextOrd = vaOrdNew;
+ pORD(vaOrdBase);
+ }
+
+ vaOrdBase = vaOrdNew;
+ (PBYTE)vaOrdNew += sizeof(ORD);
+ vaOrdNext = (PBYTE)vaOrdNew + sizeof(ORD);
+ cOrdFree = ORD_BLOCK - 2;
+ }
+
+ gORD(vaOrdNew).aliasord = r_ordinal;
+ cORD.vaNextOrd = rgvaOrd[HASH_ORD(r_ordinal)];
+ rgvaOrd[HASH_ORD(r_ordinal)] = vaOrdNew;
+ pORD(vaOrdNew);
+
+ SetVMClient(VM_MISC);
+
+ return(vaOrdNew);
+}
diff --git a/private/utils/mep/browser/mbrmake/owner.c b/private/utils/mep/browser/mbrmake/owner.c
new file mode 100644
index 000000000..e3107640f
--- /dev/null
+++ b/private/utils/mep/browser/mbrmake/owner.c
@@ -0,0 +1,76 @@
+//
+// owner.c : this code manipulates the SBR records for keeping track of
+// what SBR file owns a particular DEF/REF
+//
+
+#include "mbrmake.h"
+
+VA near vaRootSbr; // head of SBR list
+VA near vaTailSbr; // tail of SBR list
+WORD near SbrCnt; // count of sbr files
+
+VA
+VaSbrAdd(WORD fUpdate, LSZ lszName)
+// add a new sbr entry to the list -- we promise that cSBR will be the
+// setup for the newly added vaSbr
+//
+{
+ WORD cb;
+ VA vaSbr;
+
+ vaSbr = vaRootSbr;
+
+ while (vaSbr) {
+ gSBR(vaSbr);
+ if (strcmpi(cSBR.szName, lszName) == 0) {
+ cSBR.fUpdate |= fUpdate;
+ pSBR(vaSbr);
+ return vaSbr;
+ }
+ vaSbr = cSBR.vaNextSbr;
+ }
+
+ cb = strlen(lszName);
+
+ vaSbr = VaAllocGrpCb(grpSbr, sizeof(SBR) + cb);
+
+ gSBR(vaSbr);
+ cSBR.vaNextSbr = vaNil;
+ cSBR.fUpdate |= fUpdate;
+ cSBR.isbr = -1;
+ strcpy(cSBR.szName, lszName);
+ pSBR(vaSbr);
+
+
+ if (vaTailSbr) {
+ gSBR(vaTailSbr);
+ cSBR.vaNextSbr = vaSbr;
+ pSBR(vaTailSbr);
+ }
+ else
+ vaRootSbr = vaSbr;
+ vaTailSbr = vaSbr;
+
+ gSBR(vaSbr);
+
+ SbrCnt++;
+ return vaSbr;
+}
+
+VA
+VaSbrFrName(LSZ lszName)
+// find the .sbr entry matching the given name
+//
+{
+ VA vaSbr;
+
+ vaSbr = vaRootSbr;
+
+ while (vaSbr) {
+ gSBR(vaSbr);
+ if (strcmp(cSBR.szName, lszName) == 0)
+ return vaSbr;
+ vaSbr = cSBR.vaNextSbr;
+ }
+ return vaNil;
+}
diff --git a/private/utils/mep/browser/mbrmake/profile.h b/private/utils/mep/browser/mbrmake/profile.h
new file mode 100644
index 000000000..b58ed84a6
--- /dev/null
+++ b/private/utils/mep/browser/mbrmake/profile.h
@@ -0,0 +1,58 @@
+/* profile.h - definitions for profile.dll */
+
+extern word far pascal PROFCLEAR (int);
+extern word far pascal PROFDUMP (int,FPC);
+extern word far pascal PROFFREE (int);
+extern word far pascal PROFINIT (int,FPC);
+extern word far pascal PROFOFF (int);
+extern word far pascal PROFON (int);
+
+#define PROF_SHIFT 2 /* Power of 2 profile granularity */
+
+#define MOD_NAME_SIZE 10 /* size of module name */
+
+/* Profile flags */
+#define PT_SYSTEM 0 /* select system profiling */
+#define PT_USER 1 /* select user profiling */
+
+#define PT_USEDD 2 /* tell PROFON to call profile DD */
+#define PT_USEKP 4 /* Do kernel-support profiling */
+#define PT_VERBOSE 8 /* Also collect detail kernel tics */
+#define PT_NODD 0 /* tell PROFON not to call profile DD */
+
+
+/* Profiling SCOPE
+* ---------------
+* PT_SYSTEM
+* Profile the ENTIRE system;
+* Exists for the use of tools like PSET, which gather data on
+* system behavior. Avoids need to write/modify test programs.
+*
+* PT_USER (i.e., PT_SYSTEM not specified)
+* Profile ONLY in the context of the calling process;
+* Exists to gather data on an individual program and those parts of
+* the system exercised by that program.
+*
+* Profiling Configuration
+* -----------------------
+* PT_USEDD
+* Call PROFILE device driver, if installed, on every timer tick.
+* Used by Presentation Manager "attributed" profiling, in
+* particular. Allows for arbitrary actions at "profile" time.
+*
+* PT_USEKP
+* Cause kernel to record profiling information;
+* These are the 4-byte granularity tick counts kept for each
+* code segment of interest. Making this optional allows one to
+* do PT_USEDD profiling without taking the memory hit of Kernel
+* Profiling.
+*
+* PT_VERBOSE
+* Collect detailed tick counts on KERNEL code segments;
+* Works only if PT_USEKP also specified. Generally useful
+* only for kernel programmers tuning the kernel.
+*
+*
+* The above flags can be used in any combination, with the exception
+* that PT_VERBOSE is allowed only if PT_USEKP is also specified.
+*/
diff --git a/private/utils/mep/browser/mbrmake/readbsc.c b/private/utils/mep/browser/mbrmake/readbsc.c
new file mode 100644
index 000000000..6cdd08eec
--- /dev/null
+++ b/private/utils/mep/browser/mbrmake/readbsc.c
@@ -0,0 +1,790 @@
+//
+// readbsc.c -- read in a .BSC file and install in mbrmake's vm space
+//
+// Copyright <C> 1988, Microsoft Corporation
+//
+// Revision History:
+//
+// 13-Aug-1989 rm Extracted from mbrapi.c
+//
+
+#define LINT_ARGS
+
+#include "mbrmake.h"
+
+#include <stddef.h>
+
+#include "mbrcache.h"
+
+#include "sbrfdef.h" // sbr attributes
+#include "sbrbsc.h"
+
+typedef struct _sbrinfo {
+ WORD fUpdate;
+ WORD isbr;
+} SI, far *LPSI; // sbr info
+
+#define LISTALLOC 50 // Browser max list size
+
+typedef WORD IDX;
+
+// these will be initialized by the reading of the .bsc file
+//
+// fCase; TRUE for case compare
+// MaxSymLen; longest symbol length
+// ModCnt; count of modules
+// SbrCnt; count of sbr files
+// vaUnknownSym; unknown symbol
+// vaUnknownMod; unknown module
+//
+
+// static data
+
+static BOOL fIncremental; // update will be incremental
+static BOOL fFoundSBR; // at least .sbr file matched
+
+static int fhBSC = 0; // .BSC file handle
+
+static IDX Unknown; // UNKNOWN symbol index
+
+static WORD ModSymCnt; // count of modsyms
+static WORD SymCnt; // count of symbols
+static WORD PropCnt; // count of properties
+static DWORD RefCnt; // count of references
+static WORD DefCnt; // count of definitions
+static WORD CalCnt; // count of calls
+static WORD CbyCnt; // count of called bys
+static WORD lastAtomPage; // last atom page #
+static WORD lastAtomCnt; // last atom page size
+
+static WORD cbModSymCnt; // size of list of modsyms
+static WORD cbSymCnt; // size of list of symbols
+static WORD cbPropCnt; // size of list of properties
+static WORD cbRefCnt; // size of list of references
+static WORD cbDefCnt; // size of list of definitions
+static WORD cbCalCnt; // size of list of calls
+static WORD cbCbyCnt; // size of list of called bys
+
+static WORD MaxModSymCnt; // max list of modsyms
+static WORD MaxSymCnt; // max list of symbols
+static WORD MaxPropCnt; // max list of properties
+static WORD MaxRefCnt; // max list of references
+static WORD MaxDefCnt; // max list of definitions
+static WORD MaxCalCnt; // max list of calls
+static WORD MaxCbyCnt; // max list of called bys
+
+static DWORD lbModSymList; // modsym list file start
+static DWORD lbSymList; // symbol list file start
+static DWORD lbPropList; // property list file start
+static DWORD lbRefList; // reference list file start
+static DWORD lbDefList; // defintion list file start
+static DWORD lbCalList; // call list file start
+static DWORD lbCbyList; // called by list file start
+static DWORD lbSbrList; // sbr list file start
+static DWORD lbAtomCache; // atom cache file start
+
+static WORD CurModSymPage = 0; // Current page of modsyms
+static WORD CurSymPage = 0; // Current page of symbols
+static WORD CurPropPage = 0; // Current page of properties
+static WORD CurRefPage = 0; // Current page of references
+static WORD CurDefPage = 0; // Current page of defintions
+static WORD CurCalPage = 0; // Current page of calls
+static WORD CurCbyPage = 0; // Current page of called bys
+
+static LSZ lszBSCName = NULL; // name of .bsc file
+
+static MODLIST far *pfModList; // module list cache start
+static MODSYMLIST far *pfModSymList; // modsym list cache start
+static SYMLIST far *pfSymList; // symbol list cache start
+static PROPLIST far *pfPropList; // property list cache start
+static REFLIST far *pfRefList; // reference list cache start
+static REFLIST far *pfDefList; // def'n list cache start
+static USELIST far *pfCalList; // calls list cache start
+static USELIST far *pfCbyList; // call bys list cache start
+
+static WORD AtomPageTblMac; // last cache page used
+static CACHEPAGE AtomPageTbl[MAXATOMPAGETBL]; // Atom Cache table
+
+#define bMOD(imod) (pfModList[imod])
+#define bMODSYM(isym) (pfModSymList[ModSymPAGE(isym)])
+#define bSYM(isym) (pfSymList[SymPAGE(isym)])
+#define bPROP(iprop) (pfPropList[PropPAGE(iprop)])
+
+#define bREF(iref) (pfRefList[RefPAGE(iref)])
+#define bDEF(idef) (pfDefList[DefPAGE(idef)])
+
+#define bCAL(iuse) (pfCalList[CalPAGE(iuse)])
+#define bCBY(iuse) (pfCbyList[CbyPAGE(iuse)])
+#define bUSE(iuse) (pfCalList[CalPAGE(iuse)])
+#define bUBY(iuse) (pfCbyList[CbyPAGE(iuse)])
+
+#define BSCIn(v) ReadBSC(&v, sizeof(v))
+
+// prototypes
+//
+
+static VOID GetBSCLsz(LSZ lsz);
+static VOID GetBSC (DWORD lpos, LPV lpv, WORD cb);
+static VOID ReadBSC(LPV lpv, WORD cb);
+static IDX SwapPAGE (DWORD, LPV, WORD, WORD, WORD *, DWORD);
+static LPCH GetAtomCache (WORD);
+static WORD ModSymPAGE(WORD idx);
+static WORD SymPAGE(WORD idx);
+static WORD PropPAGE(WORD idx);
+static WORD RefPAGE(DWORD idx);
+static WORD DefPAGE(WORD idx);
+static WORD CalPAGE(WORD idx);
+static WORD CbyPAGE(WORD idx);
+static LSZ LszNameFrIsym(WORD isym);
+static LPSI LpsiCreate(VOID);
+
+static VOID
+GetBSCLsz(LSZ lsz)
+// read a null terminated string from the current position in the BSC file
+//
+{
+ for (;;) {
+ if (read(fhBSC, lsz, 1) != 1)
+ ReadError(lszBSCName);
+ if (*lsz++ == 0) return;
+ }
+}
+
+static VOID
+ReadBSC(LPV lpv, WORD cb)
+// read a block of data from the BSC file
+//
+// the requested number of bytes MUST be present
+//
+{
+ if (read(fhBSC, lpv, cb) != (int)cb)
+ ReadError(lszBSCName);
+}
+
+static VOID
+GetBSC(DWORD lpos, LPV lpv, WORD cb)
+// Read a block of the specified size from the specified position
+//
+// we have to be tolerant of EOF here because the swapper might ask
+// for a whole block when only block when only part of a block is actually
+// is actually present
+//
+{
+ if (lseek(fhBSC, lpos, SEEK_SET) == -1)
+ SeekError(lszBSCName);
+
+ if (read(fhBSC, lpv, cb) == -1)
+ ReadError(lszBSCName);
+}
+
+static IDX
+SwapPAGE (DWORD lbuflist, LPV pfTABLE, WORD tblsiz,
+/* */ WORD lstsiz, WORD * pcurpage, DWORD idx)
+// SwapPAGE - Swap in the table page for the table pfTABLE[idx]
+// and return the table's new index in the page.
+{
+ WORD page;
+ IDX newidx;
+
+ page = (WORD)(idx / lstsiz);
+ newidx = (WORD)(idx % lstsiz);
+
+ if (page == *pcurpage)
+ return newidx;
+
+ GetBSC(lbuflist+((long)tblsiz*(long)page), pfTABLE, tblsiz);
+
+ *pcurpage = page;
+ return newidx;
+}
+
+static IDX
+ModSymPAGE (IDX idx)
+// Swap in the ModSym page for ModSym[idx]
+// return the ModSym's index in the page.
+//
+{
+ return SwapPAGE (lbModSymList, pfModSymList,
+ cbModSymCnt, MaxModSymCnt, &CurModSymPage, (DWORD)idx);
+}
+
+static IDX
+SymPAGE (IDX idx)
+// Swap in the Symbol page for symbol[idx]
+// return the Symbol's index in the page.
+//
+{
+ return SwapPAGE (lbSymList, pfSymList,
+ cbSymCnt, MaxSymCnt, &CurSymPage, (DWORD)idx);
+}
+
+static IDX
+PropPAGE (IDX idx)
+// Swap in the Property page for Property[idx]
+// return the Property's index in the page.
+//
+{
+ return SwapPAGE (lbPropList, pfPropList,
+ cbPropCnt, MaxPropCnt, &CurPropPage, (DWORD)idx);
+}
+
+static IDX
+RefPAGE (DWORD idx)
+// Swap in the Reference page for Reference[idx] (ref/def)
+// return the Reference's index in the page.
+//
+{
+ return SwapPAGE (lbRefList, pfRefList,
+ cbRefCnt, MaxRefCnt, &CurRefPage, idx);
+}
+
+static IDX
+DefPAGE (IDX idx)
+// Swap in the Reference page for Defintions[idx] (ref/def)
+// return the Reference's index in the page.
+//
+{
+ return SwapPAGE (lbDefList, pfDefList,
+ cbDefCnt, MaxDefCnt, &CurDefPage, (DWORD)idx);
+}
+
+static IDX
+CalPAGE (IDX idx)
+// Swap in the Usage page for Usage[idx] (cal/cby)
+// and return the Usage's index in the page.
+//
+{
+ return SwapPAGE (lbCalList, pfCalList,
+ cbCalCnt, MaxCalCnt, &CurCalPage, (DWORD)idx);
+}
+
+static IDX
+CbyPAGE (IDX idx)
+// Swap in the Usage page for Usage[idx] (cal/cby)
+// and return the Usage's index in the page.
+//
+{
+ return SwapPAGE (lbCbyList, pfCbyList,
+ cbCbyCnt, MaxCbyCnt, &CurCbyPage, (DWORD)idx);
+}
+
+static LPCH
+GetAtomCache (WORD Page)
+// load the requested page into the cache
+//
+{
+ WORD ipg;
+ WORD pagesize;
+ LPCH pfAtomCsave;
+
+ for (ipg = 0; ipg < AtomPageTblMac; ipg++) {
+ if (AtomPageTbl[ipg].uPage == Page)
+ return AtomPageTbl[ipg].pfAtomCache;
+ }
+ if (ipg == AtomPageTblMac && ipg != MAXATOMPAGETBL)
+ AtomPageTblMac++;
+
+ pfAtomCsave = AtomPageTbl[MAXATOMPAGETBL-1].pfAtomCache;
+ for (ipg = MAXATOMPAGETBL-1; ipg; ipg--)
+ AtomPageTbl[ipg] = AtomPageTbl[ipg-1]; // move up
+
+ AtomPageTbl[0].pfAtomCache = pfAtomCsave;
+ AtomPageTbl[0].uPage = Page;
+
+ if (Page == lastAtomPage)
+ pagesize = lastAtomCnt;
+ else
+ pagesize = ATOMALLOC;
+
+ GetBSC(lbAtomCache+ATOMALLOC*(long)Page,
+ AtomPageTbl[0].pfAtomCache, pagesize);
+
+ return AtomPageTbl[0].pfAtomCache;
+}
+
+static LSZ
+LszNameFrIsym (IDX isym)
+// Swap in the Atom page for the symbol isym
+// return the atom's address in the page.
+//
+{
+ SYMLIST sym;
+
+ sym = bSYM(isym);
+ return GetAtomCache (sym.Page) + sym.Atom;
+}
+
+VOID
+CloseBSC()
+// close database and free as much memory as possible
+// return TRUE iff successful.
+//
+{
+ int i;
+
+ if (fhBSC) { // if open then close, & free memory
+
+ FreeLpv (pfModList); // module table
+ FreeLpv (pfModSymList); // modsym table
+ FreeLpv (pfSymList); // symbol table
+ FreeLpv (pfPropList); // property table
+ FreeLpv (pfRefList); // reference table
+ FreeLpv (pfDefList); // definition table
+ FreeLpv (pfCalList); // call table
+ FreeLpv (pfCbyList); // called by table
+
+ for (i=0; i < MAXATOMPAGETBL; i++)
+ FreeLpv (AtomPageTbl[i].pfAtomCache); // dispose Atom Cache
+
+ close (fhBSC);
+ }
+}
+
+
+BOOL
+FOpenBSC (LSZ lszName)
+// Open the specified data base.
+// Allocate buffers for cache areas
+// Initialize the data cache from the data base.
+//
+// Return TRUE iff successful, FALSE if database can't be read
+//
+{
+ int i;
+ WORD pagesize;
+
+ BYTE MajorVer; // .bsc version (major)
+ BYTE MinorVer; // .bsc version (minor)
+ BYTE UpdatVer; // .bsc version (updat)
+
+ WORD MaxModCnt; // max list of modules
+ WORD cbModCnt; // size of list of modules
+ DWORD lbModList; // module list file start
+
+ lszBSCName = lszName;
+
+ fhBSC = open(lszBSCName, O_BINARY|O_RDONLY);
+
+ // if the .bsc file doesn't exist then we don't do any work
+ // this is the cold compile case
+ //
+
+ if (fhBSC == -1)
+ return FALSE;
+
+ // read and check BSC version (major, minor and update)
+
+ BSCIn(MajorVer);
+ BSCIn(MinorVer);
+ BSCIn(UpdatVer);
+
+#ifdef DEBUG
+ printf("Browser Data Base: %s ver %d.%d.%d\n\n",
+ lszBSCName, MajorVer, MinorVer, UpdatVer);
+#endif
+
+ if ((MajorVer != BSC_MAJ) ||
+ (MinorVer != BSC_MIN) ||
+ (UpdatVer != BSC_UPD))
+ return FALSE;
+
+
+ // we will be attempting an incremental update
+
+ fIncremental = TRUE;
+
+ // read Case sense switch, max symbol length and Unknown module id
+
+ BSCIn(fCase);
+ BSCIn(MaxSymLen);
+ BSCIn(Unknown);
+
+ // read counts (sizes) of each data area
+
+ BSCIn(ModCnt);
+ BSCIn(ModSymCnt);
+ BSCIn(SymCnt);
+ BSCIn(PropCnt);
+ BSCIn(RefCnt);
+ BSCIn(DefCnt);
+ BSCIn(CalCnt);
+ BSCIn(CbyCnt);
+ BSCIn(lastAtomPage);
+ BSCIn(lastAtomCnt);
+
+ // read BSC data area offsets
+
+ BSCIn(lbModList);
+ BSCIn(lbModSymList);
+ BSCIn(lbSymList);
+ BSCIn(lbPropList);
+ BSCIn(lbRefList);
+ BSCIn(lbDefList);
+ BSCIn(lbCalList);
+ BSCIn(lbCbyList);
+ BSCIn(lbAtomCache);
+ BSCIn(lbSbrList);
+
+ // determine data cache area sizes
+
+ #define MIN(a,b) ((a)>(b) ? (b) : (a))
+
+ MaxModCnt = ModCnt; // max list of modules
+ MaxModSymCnt = MIN(ModSymCnt , LISTALLOC); // max list of modsyms
+ MaxSymCnt = MIN(SymCnt+ModCnt, LISTALLOC); // max list of symbols
+ MaxPropCnt = MIN(PropCnt , LISTALLOC); // max list of props
+ MaxRefCnt = (WORD)MIN(RefCnt, (long)LISTALLOC); // max list of refs
+ MaxDefCnt = MIN(DefCnt , LISTALLOC); // max list of defs
+ MaxCalCnt = MIN(CalCnt , LISTALLOC); // max list of cals
+ MaxCbyCnt = MIN(CbyCnt , LISTALLOC); // max list of cbys
+
+ cbModCnt = sizeof (MODLIST) * MaxModCnt; // size of mods list
+ cbModSymCnt = sizeof (MODSYMLIST) * MaxModSymCnt; // size of modsyms list
+ cbSymCnt = sizeof (SYMLIST) * MaxSymCnt; // size of syms list
+ cbPropCnt = sizeof (PROPLIST) * MaxPropCnt; // size of props list
+ cbRefCnt = sizeof (REFLIST) * MaxRefCnt; // size of refs list
+ cbDefCnt = sizeof (REFLIST) * MaxDefCnt; // size of defs list
+ cbCalCnt = sizeof (USELIST) * MaxCalCnt; // size of cals list
+ cbCbyCnt = sizeof (USELIST) * MaxCbyCnt; // size of cbys list
+
+ // Allocate data cache
+
+ pfModList = LpvAllocCb(cbModCnt);
+ pfModSymList = LpvAllocCb(cbModSymCnt);
+ pfSymList = LpvAllocCb(cbSymCnt);
+ pfPropList = LpvAllocCb(cbPropCnt);
+ pfRefList = LpvAllocCb(cbRefCnt);
+ pfDefList = LpvAllocCb(cbDefCnt);
+ pfCalList = LpvAllocCb(cbCalCnt);
+ pfCbyList = LpvAllocCb(cbCbyCnt);
+
+ for (i=0; i < MAXATOMPAGETBL; i++) {
+ AtomPageTbl[i].uPage = 0;
+ AtomPageTbl[i].pfAtomCache = LpvAllocCb(ATOMALLOC);
+ }
+ AtomPageTblMac = 0; // last cache page used
+ AtomPageTbl[0].uPage = 65535;
+
+ // read data areas
+
+ if (lastAtomPage == 0)
+ pagesize = lastAtomCnt;
+ else
+ pagesize = ATOMALLOC;
+
+ GetBSC(lbModList, pfModList, cbModCnt); // Init Mod cache
+ GetBSC(lbModSymList, pfModSymList, cbModSymCnt); // Init ModSym cache
+ GetBSC(lbSymList, pfSymList, cbSymCnt); // Init Sym cache
+ GetBSC(lbPropList, pfPropList, cbPropCnt); // Init Prop cache
+ GetBSC(lbRefList, pfRefList, cbRefCnt); // Init Ref cache
+ GetBSC(lbDefList, pfDefList, cbDefCnt); // Init Def cache
+ GetBSC(lbCalList, pfCalList, cbCalCnt); // Init Cal cache
+ GetBSC(lbCbyList, pfCbyList, cbCbyCnt); // Init Cby cache
+
+ GetAtomCache (0); // Init Atom cache
+
+ return TRUE;
+}
+
+VOID
+InstallBSC()
+// Install the currently open BSC into the mbrmake lists
+//
+{
+ IDX iprop, imod, isym, idef, ical, icby, isbr, iFirstFileSym;
+ VA vaSym, vaProp, vaRef, vaFileSym, vaMod;
+ DWORD iref;
+
+ PROPLIST prop, prop0;
+ MODLIST mod;
+
+ DEF def;
+ CAL cal;
+ CBY cby;
+ VA *rgVaProp; // preallocated array of PROPs
+ VA *rgVaFileSym; // cached SYMs for the filenames
+ BYTE *rgFModUsed; // is this module used?
+
+ SI *mpIsbrSi;
+
+ rgVaProp = (VA *)LpvAllocCb(PropCnt * sizeof(VA));
+ rgVaFileSym = (VA *)LpvAllocCb(ModCnt * sizeof(VA));
+ rgFModUsed = (BYTE *)LpvAllocCb(ModCnt * sizeof(BYTE));
+
+ // make the SBR info for this BSC file
+ mpIsbrSi = LpsiCreate();
+
+ // this relies on the fact that all the SYMs for the files are together
+ // (they're after all the SYMs for the variables)
+ iFirstFileSym = bMOD(0).ModName;
+
+ for (iprop = 0; iprop < PropCnt; iprop++)
+ rgVaProp[iprop] = VaAllocGrpCb(grpProp, sizeof(PROP));
+
+ for (imod = 0; imod < ModCnt; imod++) {
+ mod = bMOD(imod);
+
+ vaCurMod = VaAllocGrpCb(grpMod, sizeof(MOD));
+
+ gMOD(vaCurMod);
+ cMOD.vaFirstModSym = vaNil;
+ cMOD.csyms = 0;
+ cMOD.vaNameSym = MbrAddAtom (LszNameFrIsym (mod.ModName), TRUE);
+ cMOD.vaNextMod = vaRootMod;
+ pMOD(vaCurMod);
+
+ rgVaFileSym[imod] = cMOD.vaNameSym;
+ rgFModUsed[imod] = 0;
+
+ vaRootMod = vaCurMod;
+
+ if (Unknown == mod.ModName) {
+ vaUnknownSym = cMOD.vaNameSym;
+ vaUnknownMod = vaCurMod;
+ }
+
+ gSYM(cMOD.vaNameSym).vaFirstProp = vaCurMod; // store ptr to MOD
+ pSYM(cMOD.vaNameSym);
+ }
+
+ for (isym = 0; isym < SymCnt; isym++) {
+
+ vaSym = MbrAddAtom(LszNameFrIsym(isym), FALSE);
+
+ iprop = isym ? bSYM((IDX)(isym-1)).PropEnd : 0;
+ for (; iprop < bSYM(isym).PropEnd; iprop++) {
+
+ prop = bPROP(iprop);
+
+ if (iprop)
+ prop0 = bPROP((IDX)(iprop-1));
+ else {
+ prop0.DefEnd = 0L;
+ prop0.RefEnd = 0;
+ prop0.CalEnd = 0;
+ prop0.CbyEnd = 0;
+ }
+
+ // the properties were preallocated
+ vaProp = rgVaProp[iprop];
+
+ gSYM(vaSym);
+ if (cSYM.vaFirstProp == vaNil)
+ cSYM.vaFirstProp = vaProp;
+ else
+ cPROP.vaNextProp = vaProp;
+
+ cSYM.cprop++;
+ pSYM(vaSym);
+
+ gPROP(vaProp);
+ cPROP.vaNameSym = vaSym;
+ cPROP.sattr = prop.PropAttr;
+
+
+#ifdef DEBUG
+if (isym != prop.PropName)
+ printf("\t ERROR property points back to wrong symbol!\n"); // DEBUG
+#endif
+
+ for (idef = prop0.DefEnd; idef < prop.DefEnd; idef++) {
+ isbr = bDEF(idef).isbr;
+
+ // this SBR file is being updated -- ignore incoming info
+ if (isbr == 0xffff || mpIsbrSi[isbr].fUpdate) continue;
+
+ imod = bDEF(idef).RefNam - iFirstFileSym;
+ def.isbr = mpIsbrSi[isbr].isbr;
+ def.deflin = bDEF(idef).RefLin;
+ def.vaFileSym = rgVaFileSym[imod];
+
+ rgFModUsed[imod] = 1;
+
+ VaAddList(&cPROP.vaDefList, &def, sizeof(def), grpDef);
+ }
+
+ for (iref = prop0.RefEnd; iref < prop.RefEnd; iref++) {
+ isbr = bREF(iref).isbr;
+
+ // this SBR file is being updated -- ignore incoming info
+ if (mpIsbrSi[isbr].fUpdate) continue;
+
+ vaRef = VaAllocGrpCb(grpRef, sizeof(REF));
+
+ gREF(vaRef);
+ imod = bREF(iref).RefNam - iFirstFileSym;
+ cREF.isbr = mpIsbrSi[isbr].isbr;
+ cREF.reflin = bREF(iref).RefLin;
+ vaFileSym = rgVaFileSym[imod];
+
+ rgFModUsed[imod] = 1;
+
+ MkVpVa(cREF.vpFileSym, vaFileSym);
+
+ pREF(vaRef);
+
+ AddTail (Ref, REF);
+
+ cPROP.cref++; // count references
+ }
+
+ for (ical = prop0.CalEnd; ical < prop.CalEnd; ical++) {
+ isbr = bCAL(ical).isbr;
+
+ // this SBR file is being updated -- ignore incoming info
+ if (mpIsbrSi[isbr].fUpdate) continue;
+
+ cal.isbr = mpIsbrSi[isbr].isbr;
+ cal.vaCalProp = rgVaProp[bCAL(ical).UseProp];
+ cal.calcnt = bCAL(ical).UseCnt;
+
+ VaAddList(&cPROP.vaCalList, &cal, sizeof(cal), grpCal);
+ }
+
+ for (icby = prop0.CbyEnd; icby < prop.CbyEnd; icby++) {
+ isbr = bCBY(icby).isbr;
+
+ // this SBR file is being updated -- ignore incoming info
+ if (mpIsbrSi[isbr].fUpdate) continue;
+
+ cby.isbr = mpIsbrSi[isbr].isbr;
+ cby.vaCbyProp = rgVaProp[bCBY(icby).UseProp];
+ cby.cbycnt = bCBY(icby).UseCnt;
+
+ VaAddList(&cPROP.vaCbyList, &cby, sizeof(cby), grpCby);
+ }
+
+ pPROP(vaProp);
+ }
+ }
+
+ for (imod = 0; imod < ModCnt; imod++) {
+ vaMod = gSYM(rgVaFileSym[imod]).vaFirstProp;
+ gMOD(vaMod);
+ if (rgFModUsed[imod] == 0) {
+ cMOD.csyms = 1; // mark this MOD as empty
+ pMOD(vaMod);
+ }
+ }
+
+ FreeLpv(mpIsbrSi);
+ FreeLpv(rgFModUsed);
+ FreeLpv(rgVaFileSym);
+ FreeLpv(rgVaProp);
+}
+
+static LPSI
+LpsiCreate()
+// create the SBR info records for this .BSC file
+//
+{
+ SI FAR *mpIsbrSi;
+ LSZ lszSbrName;
+ VA vaSbr;
+ WORD isbr, isbr2;
+ WORD fUpdate;
+
+ // add the files that are current in the database to the list of .SBR files
+ //
+ lszSbrName = LpvAllocCb(PATH_BUF);
+ lseek(fhBSC, lbSbrList, SEEK_SET);
+ for (isbr = 0;;isbr++) {
+ GetBSCLsz(lszSbrName);
+ if (*lszSbrName == '\0')
+ break;
+
+ vaSbr = VaSbrAdd(SBR_OLD, lszSbrName);
+
+ cSBR.isbr = isbr;
+ pSBR(vaSbr);
+ }
+ FreeLpv(lszSbrName);
+
+ mpIsbrSi = LpvAllocCb(SbrCnt * sizeof(SI));
+
+ // allocate and fill in the new table with the base numbers
+ // mark files that are staying and those that are going away
+ // number any new sbr files that we find while doing this.
+
+ vaSbr = vaRootSbr;
+ while (vaSbr) {
+ gSBR(vaSbr);
+
+ if (cSBR.isbr == (WORD)-1) {
+ cSBR.isbr = isbr++;
+ pSBR(vaSbr);
+ }
+
+ if (cSBR.fUpdate == SBR_NEW)
+ Warning(WARN_SBR_TRUNC, cSBR.szName);
+ else if (cSBR.fUpdate & SBR_NEW)
+ fFoundSBR = TRUE;
+
+ mpIsbrSi[cSBR.isbr].fUpdate = cSBR.fUpdate;
+
+ vaSbr = cSBR.vaNextSbr;
+ }
+
+ if (!fFoundSBR) {
+ // all SBR files were not in the database and were truncated. ERROR!
+ Error(ERR_ALL_SBR_TRUNC, "");
+ }
+
+ isbr2 = 0;
+ for (isbr = 0; isbr < SbrCnt; isbr++) {
+ fUpdate = mpIsbrSi[isbr].fUpdate;
+
+ if (fUpdate & SBR_NEW)
+ mpIsbrSi[isbr].isbr = isbr2++;
+ else
+ mpIsbrSi[isbr].isbr = (WORD)-1;
+
+ if ((fUpdate & SBR_UPDATE) ||
+ (fUpdate & SBR_OLD) && (~fUpdate & SBR_NEW))
+ mpIsbrSi[isbr].fUpdate = TRUE;
+ else
+ mpIsbrSi[isbr].fUpdate = FALSE;
+
+ }
+
+ return mpIsbrSi;
+}
+
+VOID
+NumberSBR()
+// stub version of LpsiCreate --- call this if FOpenBSC fails to just
+// assign new numbers to all the .sbr files that are in the list
+//
+{
+ VA vaSbr;
+ WORD isbr;
+
+ // number new sbr files
+
+ vaSbr = vaRootSbr;
+ isbr = 0;
+ while (vaSbr) {
+ gSBR(vaSbr);
+
+ #ifdef DEBUG
+ if (cSBR.isbr != (WORD)-1) {
+ printf("Non initialized SBR file encountered\n"); //DEBUG
+ }
+ #endif
+
+ // if this file is truncated then and there is no
+ // old version of the file then emit a warning about the file
+ // and then an error stating that we are not in incremental mode
+
+ if (cSBR.fUpdate == SBR_NEW) {
+ Warning(WARN_SBR_TRUNC, cSBR.szName);
+ Error(ERR_NO_INCREMENTAL, "");
+ }
+
+ cSBR.isbr = isbr++;
+
+ pSBR(vaSbr);
+
+ vaSbr = cSBR.vaNextSbr;
+ }
+}
diff --git a/private/utils/mep/browser/mbrmake/sbrproto.h b/private/utils/mep/browser/mbrmake/sbrproto.h
new file mode 100644
index 000000000..bdeb8c1f6
--- /dev/null
+++ b/private/utils/mep/browser/mbrmake/sbrproto.h
@@ -0,0 +1,61 @@
+void SBRCorrupt(char *psz);
+void FreeOrdList(void);
+PVOID VaOrdFind(unsigned short ord);
+PVOID VaOrdAdd(void);
+BOOL FInExcList (LSZ lszName);
+void InstallSBR(void);
+void AddCalProp(VA vaCurProp);
+void AddCbyProp(VA vaCurProp);
+void AddRefProp(VA vaCurProp);
+void AddDefProp(VA vaCurProp);
+VA VaPropBestOfSym(VA vaSym);
+VA VaPropAddToSym(VA vaCurSym);
+void BldModSymList(void);
+void CleanUp(void);
+BOOL FWildMatch(char *pchPat, char *pchText);
+void Error(int imsg,char *parg);
+void Error2(int imsg,char achar,char *parg);
+void Warning(int imsg,char *parg);
+void Fatal(void);
+void sigint(void);
+char far *LszDup(char far *lsz);
+char far *LszDupNewExt(char far *pname,char far *pext);
+void AddExcludeFileList(char far *pname);
+BOOL FValidHeader(void);
+void _CRTAPI1 main(int argc,char * *argv);
+void Usage(void);
+long GetArgPosn(void);
+void SetArgPosn(long lArgPosn);
+char *NextArg(void);
+char *ParseArgs(int argc,char * *argv);
+void WriteBSC(char *OutputFileName);
+void DebugDump(void);
+void DebugDumpProp(VA vaProp);
+void SeekError(char *pfilenm);
+void ReadError(char *pfilenm);
+void WriteError(char *pfilenm);
+void FindTmp(char *pbuf);
+char *MakTmpFileName(char *pext);
+char far *LszBaseName(char far *lsz);
+VA VaSearchModule(char *p);
+VA VaSearchModuleExact(char *p);
+VA VaSearchSymbol(char *pStr);
+char far *GetAtomStr(VA vaSym);
+PVOID MbrAddAtom(char *pStr,char fFILENM);
+void SortAtoms(void);
+int _CRTAPI1 CmpSym(VA *sym1, VA *sym2);
+void CloseBSC(void);
+BOOL FOpenBSC (LSZ lszName);
+void InstallBSC(void);
+void NumberSBR(void);
+VA VaSbrAdd(unsigned short fUpdate,char far *lszName);
+VA VaSbrFrName(char far *lszName);
+char far *ToCanonPath(char far *lszPath,char far *lszCwd,char far *lszCanon);
+void ToRelativePath(char far *lszPath,char far *lszCwd);
+char far *ToAbsPath(char far *lszPath,char far *lszCwd);
+void ToBackSlashes(char far *lsz);
+void GetStr(char *buf);
+unsigned char GetSBRRec(void);
+void DecodeSBR(void);
+// rjsa forfile (char far * pat, void (*rtn)(char far *));
+
diff --git a/private/utils/mep/browser/mbrmake/sbrx.c b/private/utils/mep/browser/mbrmake/sbrx.c
new file mode 100644
index 000000000..a2b670389
--- /dev/null
+++ b/private/utils/mep/browser/mbrmake/sbrx.c
@@ -0,0 +1,357 @@
+#define LINT_ARGS
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <search.h>
+#include <sys\types.h>
+#include <sys\stat.h>
+
+#include "mbrmake.h"
+
+#define LONGESTPATH 128
+
+#define SLASH "\\"
+#define SLASHCHAR '\\'
+#define XSLASHCHAR '/'
+
+WORD near cAtomsMac; // total number of atoms
+WORD near cModulesMac; // total number of modules
+WORD near cSymbolsMac; // total number of symbols
+
+static char *tmpl = "XXXXXX";
+
+extern WORD HashAtomStr (char *);
+
+// rjsa LPCH GetAtomStr (VA vaSym);
+
+void
+SeekError (char *pfilenm)
+// couldn't seek to position ... emit error message
+//
+{
+ Error(ERR_SEEK_FAILED, pfilenm);
+}
+
+void
+ReadError (char *pfilenm)
+// couldn't read from file... emit error message
+//
+{
+ Error(ERR_READ_FAILED, pfilenm);
+}
+
+void
+WriteError (char *pfilenm)
+// couldn't write to file ... emit error message
+//
+{
+ Error(ERR_WRITE_FAILED, pfilenm);
+}
+
+void
+FindTmp (char *pbuf) /* copy TMP path to pbuf if exists */
+//
+//
+{
+ char ebuf[LONGESTPATH];
+ char *env = ebuf;
+
+ *pbuf = '\0';
+ *env = '\0';
+
+// if (!(env = getenv("TMP")))
+ if (!(env = getenvOem("TMP")))
+ return; /* no path, return */
+
+// env = strncpy(ebuf, env, LONGESTPATH-1);
+ strncpy(ebuf, env, LONGESTPATH-1);
+ free( env );
+ env = ebuf;
+ ebuf[LONGESTPATH-1] = '\0';
+
+ if (!( env = ebuf ) )
+ return;
+
+ env = ebuf + strcspn(ebuf, ";");
+ if (*env == ';')
+ *env = '\0';
+
+ if (env != ebuf) {
+ env--;
+ if (*env != SLASHCHAR
+ && *env != XSLASHCHAR)
+ strcat(ebuf, SLASH);
+ }
+ strcpy (pbuf, ebuf);
+}
+
+
+char *
+MakTmpFileName (char *pext)
+// Create a temporary file with the extension supplied.
+// returns a pointer to the file name on the heap.
+//
+{
+ char ptmpnam[96];
+ char btmpl[7];
+ char *p;
+
+ strcpy (btmpl, tmpl);
+ p = mktemp(btmpl);
+ FindTmp (ptmpnam);
+ strcat (ptmpnam, p);
+ free (p);
+ strcat (ptmpnam, pext); /* /tmp/xxxxxx.ext file */
+ return (LszDup(ptmpnam));
+}
+
+LSZ
+LszBaseName (LSZ lsz)
+// return the base name part of a path
+//
+{
+ LPCH lpch;
+
+ lpch = strrchr(lsz, '\\');
+ if (lpch) return lpch+1;
+ if (lsz[1] == ':')
+ return lsz+2;
+
+ return lsz;
+}
+
+VA
+VaSearchModule (char *p)
+// search for the named module in the module list
+//
+{
+ VA vaMod;
+ LSZ lsz, lszBase;
+ char buf[PATH_BUF];
+
+ strcpy(buf, ToAbsPath(p, r_cwd));
+ lszBase = LszBaseName(buf);
+
+ SetVMClient(VM_SEARCH_MOD);
+
+ vaMod = vaRootMod;
+
+ while (vaMod) {
+ gMOD(vaMod);
+
+ lsz = GetAtomStr(cMOD.vaNameSym);
+
+ if (strcmpi(LszBaseName(lsz), lszBase) == 0 &&
+ strcmpi(buf,ToAbsPath(lsz, c_cwd)) == 0) {
+ SetVMClient(VM_MISC);
+ return (vaMod);
+ }
+ vaMod = cMOD.vaNextMod;
+ }
+ SetVMClient(VM_MISC);
+ return vaNil;
+}
+
+VA
+VaSearchModuleExact (char *p)
+// search for the named module in the module list -- EXACT match only
+//
+{
+ VA vaMod;
+
+ SetVMClient(VM_SEARCH_MOD);
+
+ vaMod = vaRootMod;
+
+ while (vaMod) {
+ gMOD(vaMod);
+
+ if (strcmp(p,GetAtomStr(cMOD.vaNameSym)) == 0) {
+ SetVMClient(VM_MISC);
+ return (vaMod);
+ }
+ vaMod = cMOD.vaNextMod;
+ }
+ SetVMClient(VM_MISC);
+ return vaNil;
+}
+
+VA
+VaSearchSymbol (char *pStr)
+// search for the named symbol (not a module!)
+//
+{
+ WORD hashid;
+ VA vaRootSym, vaSym;
+ LSZ lszAtom;
+
+ SetVMClient(VM_SEARCH_SYM);
+
+ vaRootSym = rgVaSym[hashid = HashAtomStr (pStr)];
+
+ if (vaRootSym) {
+ vaSym = vaRootSym;
+ while (vaSym) {
+
+ gSYM(vaSym);
+ lszAtom = gTEXT(cSYM.vaNameText);
+
+ if (strcmp (pStr, lszAtom) == 0) {
+ SetVMClient(VM_MISC);
+ return (vaSym); // Duplicate entry
+ }
+
+ vaSym = cSYM.vaNextSym; // current = next
+ }
+ }
+
+ SetVMClient(VM_MISC);
+ return vaNil;
+}
+
+LPCH
+GetAtomStr (VA vaSym)
+// Swap in the Atom page for the symbol chain entry pSym
+// Return the atom's address in the page.
+//
+{
+ gSYM(vaSym);
+ return gTEXT(cSYM.vaNameText);
+}
+
+VA
+MbrAddAtom (char *pStr, char fFILENM)
+// create a new symbol with the given name
+//
+{
+ WORD hashid;
+ VA vaSym, vaSymRoot, vaText;
+
+ if (!fFILENM)
+ vaSymRoot = rgVaSym[hashid = HashAtomStr (pStr)];
+ else
+ vaSymRoot = rgVaSym[hashid = MAXSYMPTRTBLSIZ - 1];
+
+ SetVMClient(VM_SEARCH_SYM);
+
+ if (vaSymRoot) {
+ vaSym = vaSymRoot;
+ while (vaSym) {
+ gSYM(vaSym);
+
+ if (!strcmp (pStr, GetAtomStr(vaSym))) {
+ #if defined (DEBUG)
+ if (OptD & 2)
+ printf("MbrAddAtom: duplicate (%s)\n", pStr);
+ #endif
+ SetVMClient(VM_SEARCH_SYM);
+ return (vaSym); // Duplicate entry
+ }
+
+ vaSym = cSYM.vaNextSym; // current = next
+ }
+ }
+
+ // we are now going to have to add the symbol
+
+
+ if (fFILENM) {
+ SetVMClient(VM_ADD_MOD);
+ cModulesMac++;
+ }
+ else {
+ SetVMClient(VM_ADD_SYM);
+ cSymbolsMac++;
+ }
+
+ cAtomsMac++;
+
+ vaSym = VaAllocGrpCb(grpSym, sizeof(SYM));
+ vaText = VaAllocGrpCb(grpText, strlen(pStr) + 1);
+
+ gSYM(vaSym);
+ cSYM.vaNameText = vaText;
+ cSYM.vaNextSym = rgVaSym[hashid];
+ pSYM(vaSym);
+
+ rgVaSym[hashid] = vaSym;
+
+ strcpy(gTEXT(vaText), pStr);
+
+ pTEXT(vaText);
+
+ SetVMClient(VM_MISC);
+
+ return (vaSym);
+}
+
+VA FAR * near rgvaSymSorted;
+
+// rjsa int CmpSym(VA FAR *lhsym1, VA FAR *lhsym2);
+
+void
+SortAtoms ()
+// create the "subscript sort" array pointers rgvaSymSorted
+//
+{
+ VA vaSym;
+ char buf[PATH_BUF];
+ WORD i, iSym;
+
+ SetVMClient(VM_SORT_ATOMS);
+
+ rgvaSymSorted = (VA FAR *)LpvAllocCb(cAtomsMac * sizeof(VA));
+
+ iSym = 0;
+ for (i=0; i < MAXSYMPTRTBLSIZ; i++) {
+ vaSym = rgVaSym[i];
+ while (vaSym) {
+ gSYM(vaSym);
+ rgvaSymSorted[iSym] = cSYM.vaNameText;
+ vaSym = cSYM.vaNextSym;
+ iSym++;
+ }
+ }
+
+ // sort symbols
+ qsort(rgvaSymSorted, cSymbolsMac, sizeof(VA), CmpSym);
+
+ // the files are in the last hash bucket so they went to the
+ // end of this array we just made -- we sort them separately
+
+ // sort files
+ qsort(rgvaSymSorted + cSymbolsMac, cModulesMac, sizeof(VA), CmpSym);
+
+ // convert the Page/Atom values back to virtual symbol addresses
+ for (i=0; i < cSymbolsMac; i++) {
+ strcpy(buf, gTEXT(rgvaSymSorted[i]));
+ rgvaSymSorted[i] = VaSearchSymbol(buf);
+ }
+
+ for (; i < cAtomsMac; i++) {
+ strcpy(buf, gTEXT(rgvaSymSorted[i]));
+#ifdef DEBUG
+ if (OptD & 64) printf("Module: %s\n", buf);
+#endif
+ rgvaSymSorted[i] = (VaSearchModuleExact(buf), cMOD.vaNameSym);
+ }
+}
+
+int _CRTAPI1
+CmpSym (VA FAR *sym1, VA FAR *sym2)
+// compare two symbols given their pointers
+//
+{
+ register char far *lpch1, *lpch2;
+ register int cmp;
+
+ lpch1 = gTEXT(*sym1); // LRU will not page out lpch1
+ lpch2 = gTEXT(*sym2);
+
+ cmp = strcmpi(lpch1, lpch2);
+
+ if (cmp) return cmp;
+
+ return strcmp(lpch1, lpch2);
+}
+
diff --git a/private/utils/mep/browser/mbrmake/sources b/private/utils/mep/browser/mbrmake/sources
new file mode 100644
index 000000000..0d8a80c53
--- /dev/null
+++ b/private/utils/mep/browser/mbrmake/sources
@@ -0,0 +1,31 @@
+MAJORCOMP=sdktools
+MINORCOMP=mbrmake
+
+TARGETNAME=mbrmake
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+INCLUDES=.;..\inc;\nt\private\sdktools\ztools\inc
+
+SOURCES= addtolst.c \
+ convert.c \
+ dcodesbr.c \
+ getsbrec.c \
+ list.c \
+ mbrhash.c \
+ ord.c \
+ owner.c \
+ mbrwbsc.c \
+ readbsc.c \
+ sbrx.c \
+ vm.c
+
+UMAPPL=mbrmake
+
+
+C_DEFINES=-D_OS2_20_=0 -DNO_EXT_KEYS -Dpascal= -Dfar= -DNOLANMAN -DNT
+UMTYPE=console
+UMLIBS= obj\*\mbrmake.lib \
+ ..\bsc\obj\*\bsc.lib \
+ \nt\private\sdktools\ztools\src\obj\*\ztools.lib \
+ \nt\public\sdk\lib\*\user32.lib
diff --git a/private/utils/mep/browser/mbrmake/vm.c b/private/utils/mep/browser/mbrmake/vm.c
new file mode 100644
index 000000000..9c8e0bef5
--- /dev/null
+++ b/private/utils/mep/browser/mbrmake/vm.c
@@ -0,0 +1,197 @@
+// vm.c
+//
+// simple minded virtual memory implemenation
+
+// there is no code to do the OS2 version...
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <io.h>
+#include <sys\types.h>
+#include <sys\stat.h>
+#include <malloc.h>
+#include <string.h>
+#if defined(OS2)
+#define INCL_NOCOMMON
+#define INCL_DOSPROCESS
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSFILEMGR
+#define INCL_DOSERRORS
+#define INCL_DOSMISC
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+
+#include "hungary.h"
+#include "vm.h"
+#include "sbrproto.h"
+#include "errors.h"
+
+#define CB_PAGE_SIZE 2048 // 4k pages
+#define C_LOCKS_MAX 16 // up to 16 pages may be locked in ram
+#define C_PAGES_MAX 8192 // up to 4k pages resident
+#define C_FREE_LIST_MAX 256 // keep free lists for items up to 256 bytes
+#define GRP_MAX 16 // max number of memory groups
+
+typedef WORD VPG; // virtual page number
+typedef VA far *LPVA; // far pointer to VA
+
+// virtual address arithmetic
+//
+// #define VpgOfVa(va) ((WORD)((va>>12)))
+
+// this is really the same as the above but it assumes that the high byte
+// of the long is all zero's and it is optimized for our C compiler
+
+#define VpgOfVa(va) ((((WORD)((BYTE)(va>>16)))<<4)|\
+ (((BYTE)(((WORD)va)>>8))>>4))
+
+#define OfsOfVa(va) ((WORD)((va) & 0x07ff))
+#define VaBaseOfVpg(vpg) (((DWORD)(vpg)) << 12)
+
+// phsyical page header
+typedef struct _pg {
+ BYTE fDirty; // needs to be written out
+ BYTE cLocks; // this page is locked
+ VPG vpg; // what is the virtual page number of this page
+ struct _pg FAR *lppgNext; // LRU ordering next
+ struct _pg FAR *lppgPrev; // and prev
+} PG;
+
+typedef PG FAR * LPPG;
+
+typedef struct _mem {
+ VA vaFree;
+ WORD cbFree;
+ VA mpCbVa[C_FREE_LIST_MAX];
+#ifdef SWAP_INFO
+ WORD cPages;
+#endif
+} MGI; // Memory Group Info
+
+static MGI mpGrpMgi[GRP_MAX];
+
+// translation table -- map virtual page number to physical page address
+static LPPG mpVpgLppg[C_PAGES_MAX];
+
+// head and tail pointers for LRU
+//
+static LPPG near lppgHead;
+static LPPG near lppgTail;
+
+// nil page pointer
+//
+#define lppgNil 0
+
+// points to the start of linked lists of free blocks
+//
+static VA mpCbVa[C_FREE_LIST_MAX];
+
+// these pages are locked in memory
+//
+static LPPG near rgLppgLocked[C_LOCKS_MAX];
+
+// number of pages we have given out
+static VPG near vpgMac;
+
+// number of physical pages we have resident
+static WORD near cPages;
+
+// should we keep trying to allocate memory
+static BOOL near fTryMemory = TRUE;
+
+// the file handle for the backing store
+static int near fhVM;
+
+// the name of the file for the backing store
+static LSZ near lszVM;
+
+#ifdef ASSERT
+
+#define Assert(x, sz) { if (!(x)) AssertionFailed(sz); }
+
+VOID
+AssertionFailed(LSZ lsz)
+// something went wrong...
+//
+{
+ printf("assertion failure:%s\n", lsz);
+ Fatal();
+}
+
+#else
+
+#define Assert(x, y)
+
+#endif
+
+
+LPV VM_API
+LpvAllocCb(ULONG cb)
+// allocate a block of far memory, if _fmalloc fails, the free some of
+// the memory we were using for the VM cache
+//
+{
+ LPV lpv;
+
+ if (!(lpv = calloc(cb,1))) {
+ Error(ERR_OUT_OF_MEMORY, "");
+ }
+ return lpv;
+}
+
+
+VA VM_API
+VaAllocGrpCb(WORD grp, ULONG cb)
+// allocate cb bytes from the requested memory group
+//
+{
+ VA vaNew;
+ MGI FAR *lpMgi;
+ LPV lpv;
+
+ lpMgi = &mpGrpMgi[grp];
+
+ Assert(grp < GRP_MAX, "Memory Group out of range");
+
+ if (cb < C_FREE_LIST_MAX && (vaNew = lpMgi->mpCbVa[cb])) {
+ lpv = LpvFromVa(vaNew, 0);
+ lpMgi->mpCbVa[cb] = *(LPVA)lpv;
+ memset(lpv, 0, cb);
+ DirtyVa(vaNew);
+ return vaNew;
+ }
+
+ if (cb < mpGrpMgi[grp].cbFree) {
+ vaNew = mpGrpMgi[grp].vaFree;
+ (PBYTE)mpGrpMgi[grp].vaFree += cb;
+ mpGrpMgi[grp].cbFree -= cb;
+ }
+ else {
+ vaNew = VaAllocCb(CB_PAGE_SIZE - sizeof(PG));
+ mpGrpMgi[grp].vaFree = (PBYTE)vaNew + cb;
+ mpGrpMgi[grp].cbFree = CB_PAGE_SIZE - cb - sizeof(PG);
+ }
+
+ return vaNew;
+}
+
+VOID VM_API
+FreeGrpVa(WORD grp, VA va, ULONG cb)
+// put this block on the free list for blocks of that size
+// we don't remember how big the blocks were so the caller has
+// provide that info
+//
+{
+ MGI FAR *lpMgi;
+
+ lpMgi = &mpGrpMgi[grp];
+
+ if (cb < C_FREE_LIST_MAX && cb >= 4 ) {
+ *(LPVA)LpvFromVa(va, 0) = lpMgi->mpCbVa[cb];
+ DirtyVa(va);
+ lpMgi->mpCbVa[cb] = va;
+ }
+}
diff --git a/private/utils/mep/browser/mbrmake/vm.h b/private/utils/mep/browser/mbrmake/vm.h
new file mode 100644
index 000000000..730ff627c
--- /dev/null
+++ b/private/utils/mep/browser/mbrmake/vm.h
@@ -0,0 +1,67 @@
+//
+// simple minded virtual memory system headers
+//
+
+typedef PVOID VA;
+
+#define vaNil 0
+
+#define VM_API pascal
+
+
+#define InitVM()
+#define CloseVM()
+#define FreeVa(va,cb) (free((LPV)va))
+#define VaAllocCb(cb) ((VA)LpvAllocCb(cb))
+#define LpvFromVa(va, wLock) (LPV)(va)
+#define DirtyVa(va)
+#define UnlockW(w)
+#define FreeLpv(lpv) (free(lpv))
+
+typedef VA VP;
+
+#define MkVpVa(vp, va) ((vp) = (VP)va)
+#define VaFrVp(vp) ((VA)(vp))
+
+
+LPV VM_API LpvAllocCb(ULONG cb);
+VA VM_API VaAllocGrpCb(WORD grp, ULONG cb);
+VOID VM_API FreeGrpVa(WORD grp, VA va, ULONG cb);
+
+#ifdef SWAP_INFO
+
+#define VM_MISC 0
+#define VM_SEARCH_DEF 1
+#define VM_ADD_DEF 2
+#define VM_SEARCH_REF 3
+#define VM_ADD_REF 4
+#define VM_SEARCH_CAL 5
+#define VM_ADD_CAL 6
+#define VM_SEARCH_CBY 7
+#define VM_ADD_CBY 8
+#define VM_SEARCH_ORD 9
+#define VM_ADD_ORD 10
+#define VM_SEARCH_PROP 11
+#define VM_ADD_PROP 12
+#define VM_SEARCH_SYM 13
+#define VM_ADD_SYM 14
+#define VM_SEARCH_MOD 15
+#define VM_ADD_MOD 16
+#define VM_SORT_ATOMS 17
+#define VM_FIX_UNDEFS 18
+#define VM_CLEAN_REFS 19
+#define VM_INDEX_TREE 20
+#define VM_BUILD_MODSYM 21
+#define VM_EMIT_ATOMS 22
+#define VM_EMIT_TREE 23
+
+extern WORD near iVMClient;
+extern WORD near iVMGrp;
+
+#define SetVMClient(x) (iVMClient = (x))
+
+#else
+
+#define SetVMClient(x)
+
+#endif
diff --git a/private/utils/mep/dirs b/private/utils/mep/dirs
new file mode 100644
index 000000000..b9e13963f
--- /dev/null
+++ b/private/utils/mep/dirs
@@ -0,0 +1,26 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+
+!ENDIF
+
+DIRS=help \
+ extens \
+ src
+
+OPTIONAL_DIRS=
diff --git a/private/utils/mep/extens/dirs b/private/utils/mep/extens/dirs
new file mode 100644
index 000000000..308b99084
--- /dev/null
+++ b/private/utils/mep/extens/dirs
@@ -0,0 +1,32 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+
+!ENDIF
+
+DIRS=exthdr \
+ mhelp \
+ filter \
+ justify \
+ mepparty \
+ pmatch \
+ tglcase \
+ ulcase \
+ winclip
+
+OPTIONAL_DIRS=
diff --git a/private/utils/mep/extens/exthdr/exthdr.c b/private/utils/mep/extens/exthdr/exthdr.c
new file mode 100644
index 000000000..dbd26fe98
--- /dev/null
+++ b/private/utils/mep/extens/exthdr/exthdr.c
@@ -0,0 +1,38 @@
+#include <ext.h>
+#include <stddef.h>
+
+#define offsetof(s,m) (size_t)&(((s *)0)->m)
+
+int __acrtused = 1;
+
+
+
+/***
+
+ The data below must match the structure in ..\ext.h
+
+ Think VERY carefully before you ever change any of this. We
+ currently support using extensions written for previous versions
+ of the editor without recompiling. This means that just about
+ ANY change to this data, or it's initialization will break that.
+
+ When adding a new import, consider appending to the table rather
+ than replacing one currently in the table.
+***/
+
+extern struct cmdDesc cmdTable;
+extern struct swiDesc swiTable;
+
+EXTTAB ModInfo =
+ { VERSION,
+ sizeof (struct CallBack),
+ &cmdTable,
+ &swiTable,
+ { NULL }};
+
+void
+EntryPoint (
+ ) {
+
+ WhenLoaded( );
+}
diff --git a/private/utils/mep/extens/exthdr/makefile b/private/utils/mep/extens/exthdr/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/mep/extens/exthdr/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/mep/extens/exthdr/makefile.inc b/private/utils/mep/extens/exthdr/makefile.inc
new file mode 100644
index 000000000..a3f28eb8d
--- /dev/null
+++ b/private/utils/mep/extens/exthdr/makefile.inc
@@ -0,0 +1,2 @@
+\nt\public\sdk\inc\ext.h: ..\..\inc\ext.h
+ copy ..\..\inc\ext.h \nt\public\sdk\inc\ext.h
diff --git a/private/utils/mep/extens/exthdr/sources b/private/utils/mep/extens/exthdr/sources
new file mode 100644
index 000000000..94b05e378
--- /dev/null
+++ b/private/utils/mep/extens/exthdr/sources
@@ -0,0 +1,20 @@
+MAJORCOMP=utils
+MINORCOMP=mep
+
+TARGETNAME=exthdr
+TARGETPATH=\nt\public\sdk\lib
+TARGETTYPE=LIBRARY
+
+INCLUDES=.;..\..\inc;\nt\private\sdktools\ztools\inc
+
+
+SOURCES= exthdr.c
+
+
+C_DEFINES=-DNO_EXT_KEYS -DNOLANMAN -DNT
+UMTYPE=console
+UMTEST=
+UMLIBS=\nt\public\sdk\lib\*\exthdr.lib
+
+
+NTTARGETFILE0=\nt\public\sdk\inc\ext.h
diff --git a/private/utils/mep/extens/filter/filter.c b/private/utils/mep/extens/filter/filter.c
new file mode 100644
index 000000000..f993d0bdb
--- /dev/null
+++ b/private/utils/mep/extens/filter/filter.c
@@ -0,0 +1,387 @@
+/*** filter.c - Microsoft Editor Filter Extension
+*
+* Purpose:
+* Provides a new editting function, filter, which replaces its argument with
+* the the argument run through an arbitrary operating system filter program.
+*
+* Modifications
+* 12-Sep-1988 mz Made WhenLoaded match declaration
+*
+*************************************************************************/
+#define EXT_ID " filter ver 1.01 "##__DATE__##" "##__TIME__
+
+#include <stdlib.h> /* min macro definition */
+#include <string.h> /* prototypes for string fcns */
+#include "ext.h"
+
+
+//
+// Prototypes
+//
+flagType pascal DoSpawn (char *);
+void pascal id (char *);
+void pascal EXTERNAL SetFilter (char far *);
+
+
+//
+// Global data
+//
+PFILE pFileFilt = 0; /* handle for filterfile*/
+char *szNameFilt = "<filter-file>"; /* name of filter file */
+char *szTemp1 = "filter1.tmp"; /* name of 1st temp file*/
+char *szTemp2 = "filter2.tmp"; /* name of 2nd temp file*/
+char filtcmd[BUFLEN] = ""; /* filter command itself*/
+
+
+
+
+/*** filter - Editor filter extension function
+*
+* Purpose:
+* Replace seleted text with that text run through an arbitrary filter
+*
+* NOARG - Filter entire current line
+* NULLARG - Filter current line, from cursor to end of line
+* LINEARG - Filter range of lines
+* BOXARG - Filter characters with the selected box
+*
+* NUMARG - Converted to LINEARG before extension is called.
+* MARKARG - Converted to Appropriate ARG form above before extension is
+* called.
+*
+* STREAMARG - Treated as BOXARG
+*
+* TEXTARG - Set new filter command
+*
+* Input:
+* Editor Standard Function Parameters
+*
+* Output:
+* Returns TRUE on success, file updated, else FALSE.
+*
+*************************************************************************/
+flagType pascal EXTERNAL
+filter (
+ unsigned int argData, /* keystroke invoked with */
+ ARG far *pArg, /* argument data */
+ flagType fMeta /* indicates preceded by meta */
+ )
+{
+ char buf[BUFLEN]; /* buffer for lines */
+ int cbLineMax; /* max lein length in filtered */
+ LINE cLines; /* count of lines in file */
+ LINE iLineCur; /* line being read */
+ PFILE pFile; /* file handle of current file */
+
+ //
+ // Unreferenced parameters
+ //
+ (void)argData;
+ (void)fMeta;
+
+ //
+ // Identify ourselves, get a handle to the current file and discard the
+ // contents of the filter file.
+ //
+ id ("");
+ pFile = FileNameToHandle ("", "");
+ DelFile (pFileFilt);
+
+ //
+ // Step 1, based on the argument type, copy the selected region into the
+ // (upper left most position of) filter-file.
+ //
+ // Note that TEXTARG is a special case that allows the user to change the name
+ // of the filter command to be used.
+ //
+ switch (pArg->argType) {
+ case NOARG: /* filter entire line */
+ CopyLine (pFile,
+ pFileFilt,
+ pArg->arg.noarg.y,
+ pArg->arg.noarg.y,
+ (LINE) 0);
+ break;
+
+ case NULLARG: /* filter to EOL */
+ CopyStream (pFile,
+ pFileFilt,
+ pArg->arg.nullarg.x,
+ pArg->arg.nullarg.y,
+ 255,
+ pArg->arg.nullarg.y,
+ (COL) 0,
+ (LINE) 0);
+ break;
+
+ case LINEARG: /* filter line range */
+ CopyLine (pFile,
+ pFileFilt,
+ pArg->arg.linearg.yStart,
+ pArg->arg.linearg.yEnd,
+ (LINE) 0);
+ break;
+
+ case BOXARG: /* filter box */
+ CopyBox (pFile,
+ pFileFilt,
+ pArg->arg.boxarg.xLeft,
+ pArg->arg.boxarg.yTop,
+ pArg->arg.boxarg.xRight,
+ pArg->arg.boxarg.yBottom,
+ (COL) 0,
+ (LINE) 0);
+ break;
+
+ case TEXTARG:
+ SetFilter (pArg->arg.textarg.pText);
+ return 1;
+ }
+
+ //
+ // Step 2, write the selected text to disk
+ //
+ if (!FileWrite (szTemp1, pFileFilt)) {
+ id ("** Error writing temporary file **");
+ return 0;
+ }
+
+ //
+ // Step 3, create the command to be executed:
+ // user specified filter command + " " + tempname 1 + " >" + tempname 2
+ // Then perform the filter operation on that file, creating a second temp file.
+ //
+ strcpy (buf,filtcmd);
+ strcat (buf," ");
+ strcat (buf,szTemp1);
+ strcat (buf," >");
+ strcat (buf,szTemp2);
+
+ if (!DoSpawn (buf)) {
+ id ("** Error executing filter **");
+ return 0;
+ }
+
+ //
+ // Step 4, delete the contents of the filter-file, and replace it by reading
+ // in the contents of that second temp file.
+ //
+ DelFile (pFileFilt);
+
+ if (!FileRead (szTemp2, pFileFilt)) {
+ id ("Error reading temporary file **");
+ return 0;
+ }
+
+ //
+ // Step 5, calculate the maximum width of the data we got back from the
+ // filter. Then, based again on the type of region selected by the user,
+ // DISCARD the users select region, and copy in the contents of the filter
+ // file in an equivelant type.
+ //
+ cLines = FileLength (pFileFilt);
+ cbLineMax = 0;
+ for (iLineCur = 0; iLineCur < cLines; iLineCur++) {
+ cbLineMax = max (cbLineMax, GetLine (iLineCur, buf, pFileFilt));
+ }
+
+ switch (pArg->argType) {
+ case NOARG: /* filter entire line */
+ DelLine (pFile,
+ pArg->arg.noarg.y,
+ pArg->arg.noarg.y);
+ CopyLine (pFileFilt,
+ pFile,
+ (LINE) 0,
+ (LINE) 0,
+ pArg->arg.noarg.y);
+ break;
+
+ case NULLARG: /* filter to EOL */
+ DelStream (pFile,
+ pArg->arg.nullarg.x,
+ pArg->arg.nullarg.y,
+ 255,
+ pArg->arg.nullarg.y);
+ CopyStream (pFileFilt,
+ pFile,
+ (COL) 0,
+ (LINE) 0,
+ cbLineMax,
+ (LINE) 0,
+ pArg->arg.nullarg.x,
+ pArg->arg.nullarg.y);
+ break;
+
+ case LINEARG: /* filter line range */
+ DelLine (pFile,
+ pArg->arg.linearg.yStart,
+ pArg->arg.linearg.yEnd);
+ CopyLine (pFileFilt,
+ pFile,
+ (LINE) 0,
+ cLines-1,
+ pArg->arg.linearg.yStart);
+ break;
+
+ case BOXARG: /* filter box */
+ DelBox (pFile,
+ pArg->arg.boxarg.xLeft,
+ pArg->arg.boxarg.yTop,
+ pArg->arg.boxarg.xRight,
+ pArg->arg.boxarg.yBottom);
+ CopyBox (pFileFilt,
+ pFile,
+ (COL) 0,
+ (LINE) 0,
+ cbLineMax-1,
+ cLines-1,
+ pArg->arg.boxarg.xLeft,
+ pArg->arg.boxarg.yTop);
+ break;
+ }
+
+ //
+ // Clean-up: delete the temporary files we've created
+ //
+ strcpy (buf, "DEL ");
+ strcat (buf, szTemp1);
+ DoSpawn (buf);
+ strcpy (buf+4, szTemp2);
+ DoSpawn (buf);
+
+ return 1;
+}
+
+
+
+/*** DoSpawn - Execute an OS/2 or DOS command
+*
+* Purpose:
+* Send the passed strign to OS/2 or DOS for execution.
+*
+* Input:
+* szCmd = Command to be executed
+*
+* Output:
+* Returns TRUE if successfull, else FALSE.
+*
+*************************************************************************/
+flagType pascal
+DoSpawn (
+ char *szCmd
+ )
+{
+ char cmd[BUFLEN];
+
+ strcpy (cmd, "arg \"");
+ strcat (cmd, szCmd);
+ strcat (cmd, "\" shell");
+ return fExecute (cmd);
+
+}
+
+
+
+
+
+/*** SetFilter - Set filter command to be used
+*
+* Purpose:
+* Save the passed string paramater as the filter command to be used by the
+* filter function. Called either because the "filtcmd:" switch has been
+* set, or because the filter command recieved a TEXTARG.
+*
+* Input:
+* szCmd = Pointer to asciiz filter command
+*
+* Output:
+* Returns nothing. Command saved
+*
+*************************************************************************/
+void pascal EXTERNAL
+SetFilter (
+ char far *szCmd
+ )
+{
+ strcpy (filtcmd,szCmd);
+}
+
+
+
+
+/*** WhenLoaded - Extension Initialization
+*
+* Purpose:
+* Executed when extension gets loaded. Identify self, create <filter-file>,
+* and assign default keystroke.
+*
+* Input:
+* none
+*
+* Output:
+* Returns nothing. Initializes various data.
+*
+*************************************************************************/
+void EXTERNAL
+WhenLoaded (
+ void
+ )
+{
+
+ pFileFilt = FileNameToHandle (szNameFilt,szNameFilt);
+ if (!pFileFilt) {
+ pFileFilt = AddFile(szNameFilt);
+ FileRead (szNameFilt, pFileFilt);
+ }
+ SetKey ("filter", "alt+f");
+ id ("text filter extension:");
+
+}
+
+
+
+/*** id - identify extension
+*
+* Purpose:
+* identify ourselves, along with any passed informative message.
+*
+* Input:
+* pszMsg = Pointer to asciiz message, to which the extension name
+* and version are appended prior to display.
+*
+* Output:
+* Returns nothing. Message displayed.
+*
+*************************************************************************/
+void pascal id (
+ char *pszFcn /* function name */
+ )
+{
+ char buf[BUFLEN]; /* message buffer */
+
+ strcpy (buf,pszFcn);
+ strcat (buf,EXT_ID);
+ DoMessage (buf);
+}
+
+
+
+
+
+//
+// Switch communication table to the editor
+//
+struct swiDesc swiTable[] = {
+ {"filtcmd", (PIF)(long)(void far *)SetFilter, SWI_SPECIAL},
+ {0, 0, 0}
+ };
+
+
+//
+// Command communiation table to the editor
+//
+struct cmdDesc cmdTable[] = {
+ {"filter",(funcCmd) filter,0, KEEPMETA | NOARG | BOXARG | NULLARG | LINEARG | MARKARG | NUMARG | TEXTARG | MODIFIES},
+ {0, 0, 0}
+ };
diff --git a/private/utils/mep/extens/filter/filter.def b/private/utils/mep/extens/filter/filter.def
new file mode 100644
index 000000000..297dd72da
--- /dev/null
+++ b/private/utils/mep/extens/filter/filter.def
@@ -0,0 +1,7 @@
+LIBRARY FILTER
+
+DESCRIPTION 'MEP extension'
+
+EXPORTS
+ EntryPoint
+ ModInfo
diff --git a/private/utils/mep/extens/filter/filter.rc b/private/utils/mep/extens/filter/filter.rc
new file mode 100644
index 000000000..36c69d65a
--- /dev/null
+++ b/private/utils/mep/extens/filter/filter.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Filter Utility for MEP"
+#define VER_INTERNALNAME_STR "filter"
+#define VER_ORIGINALNAME_STR "FILTER.DLL"
+
+#include "common.ver"
diff --git a/private/utils/mep/extens/filter/makefile b/private/utils/mep/extens/filter/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/mep/extens/filter/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/mep/extens/filter/sources b/private/utils/mep/extens/filter/sources
new file mode 100644
index 000000000..ba1957e23
--- /dev/null
+++ b/private/utils/mep/extens/filter/sources
@@ -0,0 +1,16 @@
+MAJORCOMP=utils
+MINORCOMP=mep
+
+TARGETNAME=filter
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+LINKLIBS=$(BASEDIR)\public\sdk\lib\*\exthdr.lib
+
+INCLUDES=.;..\..\inc;$(BASEDIR)\private\sdktools\ztools\inc
+
+SOURCES= filter.c filter.rc
+
+C_DEFINES=-D_OS2_20_=0 -DNO_EXT_KEYS -DEXTERNAL= -DEXPORT= -Dpascal= -Dfar= -DNOLANMAN -DNT
+UMTYPE=console
+
+UMRES=obj\*\filter.res
diff --git a/private/utils/mep/extens/justify/justify.c b/private/utils/mep/extens/justify/justify.c
new file mode 100644
index 000000000..4bf82ab24
--- /dev/null
+++ b/private/utils/mep/extens/justify/justify.c
@@ -0,0 +1,532 @@
+#define EXT_ID "justify ver 2.02 "##__DATE__##" "##__TIME__
+/*
+** Justify Z extension
+**
+** History:
+** 12-Sep-1988 mz Made WhenLoaded match declaration
+** 01-Sep-1988 Corrected hang when flush-justifying a line with no
+** spaces.
+** 14-Aug-1988 Corrected right-justification on non-column-1 based
+** lines. Corrected justification over multiple
+** paragraphs.
+** 30-Mar-1988 Extracted from "myext".
+**
+*/
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ext.h"
+
+#ifndef TRUE
+#define TRUE -1
+#define FALSE 0
+#endif
+
+void pascal near DumpLine (char far *, PFILE, COL, COL, LINE, char far *, int);
+int pascal near NextLine (char far *, PFILE, LINE, LINE far *, int far *);
+flagType pascal near isterm (char);
+void pascal near _stat (char *);
+
+#ifdef DEBUG
+void pascal near debend (flagType);
+void pascal near debhex (long);
+void pascal near debmsg (char far *);
+#else
+#define debend(x)
+#define debhex(x)
+#define debmsg(x)
+#endif
+
+flagType just2space = TRUE;
+int justwidth = 79;
+
+/*************************************************************************
+**
+** justify
+** justify paragraph(s)
+**
+** NOARG: Justify between columns 0 and 78, from the current line to
+** blank line.
+** NULLARG: Justify between current column and 78, from the current line to
+** blank line.
+** LINEARG: Justify between current column and 78, the specified lines.
+** "STREAMARG": Justify between specified columns from current line to blank.
+** (handled by boxarg)
+** BOXARG: justify between specified columns the specified rows
+** TEXTARG: Justify between columns 0 and 78, from the current line to
+** blank line, prepending each resulting line with the textarg.
+*/
+flagType pascal EXTERNAL
+justify (
+ CMDDATA argData,
+ ARG far *pArg,
+ flagType fMeta
+ )
+{
+int cbLine; /* length of line just read */
+char inbuf[512]; /* input buffer */
+PFILE pFile; /* file handle */
+char far *pText; /* pointer to prepending text */
+COL x1; /* justify to left column */
+COL x2; /* justify to right columne */
+LINE y1; /* start line */
+LINE y2; /* end line */
+LINE yOut; /* output line */
+
+ //
+ // Unreferenced parameters
+ //
+ (void)argData;
+
+_stat(EXT_ID);
+switch (pArg->argType) {
+
+ case NOARG: /* justify paragraph */
+ x1 = 0; /* between cols 0... */
+ x2 = justwidth; /* ...and 79 */
+ y1 = pArg->arg.noarg.y; /* current line... */
+ y2 = -1; /* ...to blank line*/
+ pText = 0; /* there is no text */
+ break;
+
+ case NULLARG: /* justify indented */
+ x1 = pArg->arg.nullarg.x; /* between cur col... */
+ x2 = justwidth; /* ...and 79 */
+ y1 = pArg->arg.nullarg.y; /* current line... */
+ y2 = -1; /* ...to blank line*/
+ pText = 0; /* there is no text */
+ break;
+
+ case LINEARG: /* justify line range */
+ x1 = 0; /* between cols 0... */
+ x2 = justwidth; /* ...and 79 */
+ y1 = pArg->arg.linearg.yStart; /* and range of lines */
+ y2 = pArg->arg.linearg.yEnd;
+ pText = 0; /* there is no text */
+ break;
+
+ case BOXARG: /* justify box */
+ x1 = pArg->arg.boxarg.xLeft; /* from left corner... */
+ x2 = pArg->arg.boxarg.xRight; /* ...to right */
+ y1 = pArg->arg.boxarg.yTop; /* from top... */
+ y2 = pArg->arg.boxarg.yBottom; /* ...to bottom */
+ pText = 0; /* there is no text */
+ break;
+
+ case TEXTARG: /* justify & prepend */
+ x1 = 0; /* between 0... */
+ x2 = justwidth; /* ...and 79 */
+ y1 = pArg->arg.textarg.y; /* current line... */
+ y2 = -1; /* ...to blank line */
+ pText = pArg->arg.textarg.pText; /* there IS text */
+ break;
+ }
+pFile = FileNameToHandle ("", "");
+
+if (y1 == y2) /* if same line, then */
+ y2 = -1; /* just to blank line */
+if (x1 == x2) /* if same column */
+ x2 = justwidth; /* then just to default */
+if (x2 < x1) { /* if bas-ackwards */
+ x1 = 0; /* revert to default */
+ x2 = justwidth;
+ }
+
+/*
+** while we can get data within the specified limits, format each new line
+** and output back to the file.
+*/
+inbuf[0] = 0;
+yOut = y1;
+while (NextLine(inbuf,pFile,y1,&y2,&cbLine)) {
+/*
+** if the line was blank, NextLine returned TRUE becase we're formating a
+** range of text. This means we've reached the end of one paragraph. We dump
+** the text collected so far (if any), and then a blank line.
+*/
+ if (cbLine == 0) {
+ if (inbuf[0]) {
+ DumpLine(inbuf,pFile,x1,x2,yOut++,pText,0);
+ y1++;
+ if (y2 != (LINE)-1)
+ y2++;
+ }
+ DumpLine("",pFile,x1,x2,yOut++,pText,0);/* dump blank line */
+ y1++;
+ if (y2 != (LINE)-1)
+ y2++;
+ }
+ else
+/*
+** inbuf contains the data collected so far for output. Output one newly
+** formated line at a time until the contents of inbuf are narrower than
+** our output columns.
+*/
+ while ((COL)strlen(inbuf) > (x2-x1)) { /* while data to output */
+ DumpLine(inbuf,pFile,x1,x2,yOut++,pText,fMeta);
+ y1++; /* line moves with insert*/
+ if (y2 != (LINE)-1)
+ y2++;
+ }
+ }
+/*
+** Dump any partial last line. Then if we were formatting to a blank line,
+** dump out one of those too.;
+*/
+if (inbuf[0])
+ DumpLine (inbuf,pFile,x1,x2,yOut++,pText,0); /* dump last line */
+if (y2 == -1)
+ DumpLine (NULL,pFile,x1,x2,yOut++,pText,0); /* dump blank line */
+
+return TRUE;
+
+/* end justify */}
+
+/*** NextLine - Get next line from file
+*
+* Get next line from file, remove leading and trailing spaces, and append
+* it to the input buffer. Each line is deleted from the file as it is
+* read in. This means that the target terminator, (*py2), is decremented
+* by one for each line read in.
+*
+* Input:
+* pBuf = pointer to input buffer
+* pFile = file pointer
+* y1 = line # to read
+* py2 = pointer to line # to stop at (updated)
+* pcbLine = pointer to place to put the count of bytes read
+*
+* Output:
+* Returns TRUE on a line being read & more reformatting should occurr.
+*
+*************************************************************************/
+int pascal near NextLine (
+char far *pBuf, /* input buffer */
+PFILE pFile, /* file pointer */
+LINE y1, /* line # to read */
+LINE far *py2, /* line # to stop at */
+int far *pcbLine /* loc to place bytes read*/
+) {
+flagType fRet = TRUE;
+char far *pT; /* working pointer */
+char workbuf[512]; /* working buffer */
+
+
+*pcbLine = 0;
+workbuf[0] = 0;
+/*
+** If asked for line that is not in file, we're done.
+*/
+if (y1 >= FileLength(pFile))
+ return FALSE;
+/*
+** if current line past range, (and range is not "-1"), then we're done.
+*/
+if ((*py2 != (LINE)-1) && (y1 > *py2))
+ return FALSE;
+/*
+** Get the next line in the file & remove it.
+*/
+*pcbLine = GetLine(y1, workbuf, pFile);
+DelLine(pFile, y1, y1);
+if (*py2 == 0)
+ fRet = FALSE;
+else if (*py2 != (LINE)-1)
+ (*py2)--;
+/*
+** If the line is blank, and the range is "-1", we're done.
+*/
+if (!*pcbLine && (*py2 == -1))
+ return FALSE;
+
+/*
+** strip leading spaces in newly input line
+*/
+pT = workbuf; /* point into line */
+while (*pT == ' ')
+ pT++; /* skip leading spaces */
+/*
+** If existing buffer is non-empty, append a space & set pointer to end
+*/
+if (strlen(pBuf)) { /* if non-null string */
+ pBuf += strlen(pBuf); /* point to null */
+ *pBuf++ = ' '; /* append space */
+ if (isterm(*(pBuf-2))) /* if sentence term... */
+ *pBuf++ = ' '; /* append another */
+ }
+/*
+** append new line, but compress multiple spaces into one
+*/
+while (*pT) { /* copy line over */
+ if (isterm(*pT)) /* if sentence term... */
+ if (*(pT+1) == ' ') { /* ...space */
+ *pBuf++ = *pT++; /* copy period */
+ *pBuf++ = *pT; /* copy space */
+ }
+ if ((*pBuf++ = *pT++) == ' ' ) /* copy a char */
+ while (*pT == ' ') pT++; /* skip multiple spaces */
+ }
+if (*(pBuf-1) == ' ') /* if a trailing space */
+ pBuf--; /* remove it */
+*pBuf = 0;
+
+return fRet;
+/* end NextLine */}
+
+/*** DumpLine - Dump one line of text to the file
+*
+* Dump one line of text to the file. Prepend any required text or spaces,
+* and perform word break/cut at right hand column.
+*
+* Input:
+* pBuf = Pointer to the buffer containing data to output. If NULL, pText
+* will not be prepended to output text.
+* pFile
+* x1
+* x2
+* yOut
+* pText
+* fFlush
+*
+* Output:
+* Returns .....
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+void pascal near DumpLine (
+char far *pBuf, /* data to output */
+PFILE pFile, /* file to output to */
+COL x1, /* left-hand column */
+COL x2, /* right-hand column */
+LINE yOut, /* line to output to */
+char far *pText, /* text to prepend */
+int fFlush /* flush both sides */
+) {
+int i;
+char far *pT;
+char far *pT2;
+char workbuf[512]; /* working buffer */
+char flushbuf[512]; /* working buffer */
+char fSpace; /* space seen flag */
+
+/*
+** Start by prepending any text, and then filling out to the left hand column
+** to justify to.
+*/
+workbuf[0] = 0; /* start with null */
+if (pText && pBuf)
+ strcpy(workbuf,pText); /* if starting with text*/
+i = strlen(workbuf); /* length of line-so-far*/
+while (i++ < x1)
+ strcat(workbuf," "); /* fill out with spaces */
+
+/*
+** Append the data to be output, and then starting at the right column, scan
+** back for a space to break at. If one is not found before the left hand
+** column, then break at the right hand column. Copy any line left over back
+** to the passed in buffer
+*/
+if (pBuf) {
+ strcat(workbuf,pBuf); /* get total line */
+ *pBuf = 0; /* empty input buffer */
+ }
+if ((COL)strlen(workbuf) > x2) { /* if we need to cut */
+ pT = &workbuf[x2]; /* point at potential cut*/
+ while ((pT > (char far *)&workbuf[0]) && (*pT != ' ')) pT--; /* back up to space*/
+ if (pT <= (char far *)&workbuf[x1]) { /* if none found in range*/
+ if (pBuf)
+ strcpy(pBuf,&workbuf[x2]); /* copy remainder of line*/
+ workbuf[x2] = 0; /* and terminate this one*/
+ }
+ else {
+ while (*++pT == ' '); /* Skip leading spaces */
+ if (pBuf)
+ strcpy(pBuf,pT); /* copy remainder of line*/
+ *pT = 0; /* and terminate this one*/
+ }
+ }
+/*
+** This code is invoked when the user wants to justify both right and left
+** sides of his text. We determine how many spaces we need to add, and scan
+** through and add one space to each run of spaces until we've added enough
+*/
+if (fFlush) { /* right & left justify?*/
+ if ((LONG) (pT = workbuf + strlen(workbuf) - 1) > 0)
+ while (*pT == ' ')
+ *pT-- = 0;
+ if (strchr(workbuf,' ')) {
+ while ((i = x2 - strlen(workbuf)) > 0) {/* count of spaces to add */
+ strcpy(flushbuf,workbuf); /* start with unmodified*/
+ pT = workbuf + x1;
+ pT2 = flushbuf + x1; /* skip fixed part */
+ fSpace = FALSE; /* assume no spaces */
+ while (*pT) { /* while data to copy */
+ if ((*pT == ' ') && i) { /* time to insert a space*/
+ fSpace = TRUE; /* we've seen a space */
+ *pT2++ = ' ';
+ i--;
+ while (*pT == ' ')
+ *pT2++ = *pT++; /* copy run of spaces */
+ }
+ if (*pT)
+ *pT2++ = *pT++; /* copy line */
+ else if (!fSpace)
+ break; /* no embedded spaces */
+ }
+ *pT2 = 0;
+ strcpy(workbuf,flushbuf); /* copy back */
+ if (!fSpace)
+ break;
+ }
+ }
+ }
+
+CopyLine ((PFILE) NULL, pFile, yOut, yOut, yOut); /* create new line */
+PutLine (yOut, workbuf, pFile); /* output line */
+
+/* end DumpLine */}
+
+/*************************************************************************
+**
+** isterm
+** returns true/false based on the character being a sentence terminator:
+** one of '.', '?', '!'. Also, always returns false if just2space is off.
+*/
+flagType pascal near isterm(
+char c /* character to test */
+)
+{
+return (flagType)(just2space && ((c == '.') || (c == '!') || (c == '?')));
+/* end isterm */}
+
+
+/*
+** switch communication table to Z
+*/
+struct swiDesc swiTable[] = {
+ { "just2space", toPIF(just2space), SWI_BOOLEAN },
+ { "justwidth", toPIF(justwidth), SWI_NUMERIC | RADIX10 },
+ {0, 0, 0}
+ };
+
+/*
+** command communication table to Z
+*/
+struct cmdDesc cmdTable[] = {
+ { "justify", justify, 0, MODIFIES | NOARG | NULLARG | LINEARG | BOXARG | TEXTARG },
+ {0, 0, 0}
+ };
+
+/*
+** WhenLoaded
+** Executed when these extensions get loaded. Identify self & assign keys.
+*/
+void EXTERNAL WhenLoaded () {
+PSWI pwidth;
+
+_stat(EXT_ID);
+SetKey ("justify","alt+b");
+
+if (pwidth = FindSwitch("rmargin"))
+ justwidth = *pwidth->act.ival;
+}
+
+/*************************************************************************
+**
+** stat - display status line message
+**
+** Purpose:
+** Places extension name and message on the status line
+**
+** Entry:
+** pszFcn - Pointer to string to be prepended.
+**
+** Exit:
+** none
+**
+** Exceptions:
+** none
+**
+*/
+void pascal near _stat (
+char *pszFcn /* function name */
+) {
+buffer buf; /* message buffer */
+
+strcpy(buf,"justify: "); /* start with name */
+#ifdef DEBUG
+if (strlen(pszFcn) > 71) {
+ pszFcn+= strlen(pszFcn) - 68;
+ strcat (buf, "...");
+ }
+#endif
+strcat(buf,pszFcn); /* append message */
+DoMessage (buf); /* display */
+/* end stat */}
+
+#ifdef DEBUG
+buffer debstring = {0};
+extern int delay; /* message delay */
+
+/*** debhex - output long in hex
+*
+* Display the value of a long in hex
+*
+* Input:
+* lval = long value
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void pascal near debhex (
+long lval
+) {
+char lbuf[10];
+
+_ultoa (lval, lbuf, 16);
+debmsg (lbuf);
+/* end debhex */}
+
+/*** debmsg - piece together debug message
+*
+* Outputs a the cummulative message formed by successive calls.
+*
+* Input:
+* psz = pointer to message part
+*
+* Output:
+* Returns nothing
+*************************************************************************/
+void pascal near debmsg (
+char far *psz
+) {
+_stat (strcat (debstring, psz));
+/* end debmsg */}
+
+/*** debend - terminates message accumulation & pauses
+*
+* Terminates the message accumulation, displays the final message, and
+* pauses, either for the pause time, or for a keystroke.
+*
+* Input:
+* fWait = TRUE => wait for a keystroke
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void pascal near debend (
+flagType fWait
+) {
+if (fWait) {
+ _stat (strcat (debstring, " Press a key..."));
+ ReadChar ();
+ }
+debstring[0] = 0;
+/* end debend */}
+#endif
diff --git a/private/utils/mep/extens/justify/justify.def b/private/utils/mep/extens/justify/justify.def
new file mode 100644
index 000000000..feea774bc
--- /dev/null
+++ b/private/utils/mep/extens/justify/justify.def
@@ -0,0 +1,7 @@
+LIBRARY JUSTIFY
+
+DESCRIPTION 'MEP extension'
+
+EXPORTS
+ EntryPoint
+ ModInfo
diff --git a/private/utils/mep/extens/justify/justify.rc b/private/utils/mep/extens/justify/justify.rc
new file mode 100644
index 000000000..f82db772d
--- /dev/null
+++ b/private/utils/mep/extens/justify/justify.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Justify Utility for MEP"
+#define VER_INTERNALNAME_STR "justify"
+#define VER_ORIGINALNAME_STR "JUSTIFY.DLL"
+
+#include "common.ver"
diff --git a/private/utils/mep/extens/justify/makefile b/private/utils/mep/extens/justify/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/mep/extens/justify/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/mep/extens/justify/sources b/private/utils/mep/extens/justify/sources
new file mode 100644
index 000000000..21fc39058
--- /dev/null
+++ b/private/utils/mep/extens/justify/sources
@@ -0,0 +1,17 @@
+MAJORCOMP=utils
+MINORCOMP=mep
+
+TARGETNAME=justify
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+LINKLIBS=\nt\public\sdk\lib\*\exthdr.lib
+
+INCLUDES=.;..\..\inc;\nt\private\sdktools\ztools\inc
+
+SOURCES= justify.c justify.rc
+
+C_DEFINES=-D_OS2_20_=0 -DNO_EXT_KEYS -Dpascal= -Dfar= -DEXTERNAL= -DEXPORT= -DNOLANMAN -DNT
+UMTYPE=console
+
+UMRES=obj\*\justify.res
+ \ No newline at end of file
diff --git a/private/utils/mep/extens/mbrowse/calbak.c b/private/utils/mep/extens/mbrowse/calbak.c
new file mode 100644
index 000000000..51579eae9
--- /dev/null
+++ b/private/utils/mep/extens/mbrowse/calbak.c
@@ -0,0 +1,436 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ calbak.c
+
+Abstract:
+
+ Callback functions needed by the bsc library.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 06-Nov-1990
+
+
+Revision History:
+
+
+--*/
+
+/**************************************************************************/
+
+#include "stdlib.h"
+#include "mbr.h"
+
+
+typedef char bscbuf[2048];
+
+/**************************************************************************/
+
+LPV
+BSC_API
+LpvAllocCb (
+ IN WORD cb
+ )
+/*++
+
+Routine Description:
+
+ Allocates block of memory.
+
+Arguments:
+
+ cb - Supplies size of block.
+
+Return Value:
+
+ Pointer to block of memory of size cb, or NULL
+
+--*/
+
+{
+ return (LPV)malloc(cb);
+}
+
+
+
+/**************************************************************************/
+
+VOID
+BSC_API
+FreeLpv (
+ IN LPV lpv
+ )
+/*++
+
+Routine Description:
+
+ Frees a block of memory.
+
+Arguments:
+
+ lpv - Suplies a pointer to the block of memory to free.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ free(lpv);
+}
+
+
+
+/**************************************************************************/
+
+VOID
+BSC_API
+SeekError (
+ IN LSZ lszFileName
+ )
+/*++
+
+Routine Description:
+
+ Error handling for seek operations.
+
+Arguments:
+
+ lszFileName - Supplies the name of the file.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ errstat(MBRERR_BSC_SEEK_ERROR, lszFileName);
+}
+
+
+
+/**************************************************************************/
+
+VOID
+BSC_API
+ReadError (
+ IN LSZ lszFileName
+ )
+/*++
+
+Routine Description:
+
+ Error handling for read operations.
+
+Arguments:
+
+ lszFileName - Supplies the name of the file.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ errstat(MBRERR_BSC_READ_ERROR, lszFileName);
+}
+
+
+
+/**************************************************************************/
+
+VOID
+BSC_API
+BadBSCVer (
+ IN LSZ lszFileName
+ )
+/*++
+
+Routine Description:
+
+ Error handling for bad version number.
+
+Arguments:
+
+ lszFileName - Supplies the name of the file.
+ .
+ .
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ errstat(MBRERR_BAD_BSC_VERSION, lszFileName);
+}
+
+
+
+/**************************************************************************/
+
+FILEHANDLE
+BSC_API
+BSCOpen (
+ IN LSZ lszFileName,
+ IN FILEMODE mode
+ )
+/*++
+
+Routine Description:
+
+ Opens a file.
+
+Arguments:
+
+ lszFileName - Supplies the name of the file.
+ mode - Supplies the mode with which to open the file.
+
+Return Value:
+
+ File handle for the opened file. -1 if error.
+
+--*/
+
+{
+#if defined (OS2)
+ bscbuf b;
+
+ strcpy(b, lszFileName);
+ return open(b, mode);
+#else
+ return CreateFile( lszFileName, mode, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+#endif
+}
+
+
+
+/**************************************************************************/
+
+int
+BSC_API
+BSCRead (
+ IN FILEHANDLE handle,
+ OUT LPCH lpchBuf,
+ IN WORD cb
+ )
+/*++
+
+Routine Description:
+
+ Reads in the specified number of bytes.
+
+Arguments:
+
+ handle - Supplies the file handle.
+ lpchBuf - Supplies pointer to buffer.
+ cb - Supplies number of bytes to read.
+
+Return Value:
+
+ Number of bytes read
+
+--*/
+
+{
+#if defined (OS2)
+ bscbuf b;
+
+ while (cb > sizeof(b)) {
+ if (read(handle, b, sizeof(b)) == -1) {
+ return -1;
+ }
+ memcpy(lpchBuf, b, sizeof(b));
+ cb -= sizeof(b);
+ lpchBuf += sizeof(b);
+ }
+
+ if (read(handle, b, cb) == -1) {
+ return -1;
+ }
+ memcpy(lpchBuf, b, cb);
+ return cb;
+#else
+ DWORD BytesRead;
+ if ( !ReadFile(handle, lpchBuf, cb, &BytesRead, NULL) ) {
+ return -1;
+ } else {
+ return BytesRead;
+ }
+#endif
+}
+
+
+
+/**************************************************************************/
+
+int
+BSC_API
+BSCClose (
+ IN FILEHANDLE handle
+ )
+/*++
+
+Routine Description:
+
+ Closes a handle.
+
+Arguments:
+
+ handle - Supplies the handle to be closed.
+
+Return Value:
+
+ 0 if the file was successfully closed, -! if error.
+
+--*/
+
+{
+#if defined (OS2)
+ return close(handle);
+#else
+ return !CloseHandle( handle );
+#endif
+}
+
+
+
+/**************************************************************************/
+
+int
+BSC_API
+BSCSeek (
+ FILEHANDLE handle,
+ long lPos,
+ FILEMODE mode
+ )
+/*++
+
+Routine Description:
+
+ Seek (change file pointer).
+
+Arguments:
+
+ handle - Supplies the file handle.
+ lPos - Supplies the offset from the position specified by mode.
+ mode - Supplies the initial position. Must be one of the SEEK_*
+ values of the lseek C library function.
+
+
+Return Value:
+
+ 0 if successful, -1 if error.
+
+--*/
+
+{
+#if defined (OS2)
+ if (lseek(handle, lPos, mode) == -1) {
+ return -1;
+ } else {
+ return 0;
+ }
+#else
+ if (SetFilePointer( handle, lPos, 0L, mode) == -1) {
+ return -1;
+ } else {
+ return 0;
+ }
+#endif
+}
+
+
+
+
+/**************************************************************************/
+
+VOID
+BSC_API
+BSCOutput (
+ IN LSZ lsz
+ )
+/*++
+
+Routine Description:
+
+ Outputs a given string.
+
+Arguments:
+
+ lsz - Supplies the string to be output.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ // PWND pWinCur;
+ // winContents wc;
+ USHORT len; // Length of string
+ PBYTE p;
+ PFILE pFile; // Current file
+
+
+ pFile = FileNameToHandle("", NULL);
+
+ //GetEditorObject (RQ_WIN_HANDLE, 0, &pWinCur);
+ //GetEditorObject (RQ_WIN_CONTENTS | 0xff, pWinCur, &wc);
+
+ len = strlen(lsz);
+
+ while (len) {
+ //
+ // We output the string one line at a time.
+ //
+ p = lsz;
+
+ while (len--) {
+ if (*lsz != '\n') {
+ lsz++;
+ } else {
+ *lsz++ = '\00';
+ break;
+ }
+ }
+
+ // if ((wc.pFile == pBrowse) && BscInUse) {
+ if ((pFile == pBrowse) && BscInUse) {
+ //
+ // Display in Browser window
+ //
+ PutLine(BrowseLine++, p, pBrowse);
+ } else {
+ //
+ // Display in status line
+ //
+ errstat(p,NULL);
+ }
+ }
+}
+
+
+
+/**************************************************************************/
+
+#ifdef DEBUG
+VOID BSC_API
+BSCDebugOut(LSZ lsz)
+// ignore debug output by default
+//
+{
+ // unreferenced lsz
+ lsz = NULL;
+}
+#endif
+
diff --git a/private/utils/mep/extens/mbrowse/makefile b/private/utils/mep/extens/mbrowse/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/mep/extens/mbrowse/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/mep/extens/mbrowse/mbr.h b/private/utils/mep/extens/mbrowse/mbr.h
new file mode 100644
index 000000000..07f63e89f
--- /dev/null
+++ b/private/utils/mep/extens/mbrowse/mbr.h
@@ -0,0 +1,187 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ mbr.h
+
+Abstract:
+
+ Common include file for the MS Editor browser extension.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 06-Nov-1990
+
+
+Revision History:
+
+
+--*/
+
+
+#ifndef EXTINT
+#include "ext.h" /* mep extension include file */
+#include <string.h>
+
+#if defined (OS2)
+#define INCL_DOSPROCESS
+#define INCL_DOSMODULEMGR
+#define INCL_DOSFILEMGR
+#define INCL_DOSMISC
+#include <os2.h> /* os2 system calls */
+#else
+#include <windows.h>
+#endif
+#endif
+
+#include <hungary.h>
+#include <bsc.h>
+#include <bscsup.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <tools.h>
+
+
+
+// rjsa 10/22/90
+// Some runtime library functions are broken, so intrinsics have
+// to be used.
+//
+#pragma intrinsic (memset, memcpy, memcmp)
+//#pragma intrinsic (strset, strcpy, strcmp, strcat, strlen)
+
+
+// typedef char buffer[BUFLEN];
+typedef int DEFREF;
+
+
+#define Q_DEFINITION 1
+#define Q_REFERENCE 2
+
+#define CMND_NONE 0
+#define CMND_LISTREF 1
+#define CMND_OUTLINE 2
+#define CMND_CALLTREE 3
+
+#define CALLTREE_FORWARD 0
+#define CALLTREE_BACKWARD 1
+
+
+
+/////////////////////////////////////////////////////////////////////////
+//
+// Global Data
+//
+
+// Bsc info.
+//
+flagType BscInUse; /* BSC database selected flag */
+buffer BscName; /* BSC database name */
+MBF BscMbf; /* Last BSC MBF switch */
+int BscCalltreeDir; /* Calltree direction switch */
+int BscCmnd; /* Last command performed */
+buffer BscArg; /* Last argument used */
+
+// Windows
+//
+PFILE pBrowse; /* Browse PFILE */
+LINE BrowseLine; /* Current line within file */
+
+// results of procArgs.
+//
+int cArg; /* number of <args> hit */
+rn rnArg; /* range of argument */
+char *pArgText; /* ptr to any single line text */
+char *pArgWord; /* ptr to context-sens word */
+PFILE pFileCur; /* file handle of user file */
+
+
+// colors
+//
+int hlColor; /* normal: white on black */
+int blColor; /* bold: high white on black */
+int itColor; /* italics: high green on black */
+int ulColor; /* underline: high red on black */
+int wrColor; /* warning: black on white */
+
+// misc.
+//
+buffer buf; /* utility buffer */
+
+
+
+/////////////////////////////////////////////////////////////////////////
+//
+// Prototypes of global functions
+//
+
+
+// mbrdlg.c
+//
+flagType pascal EXTERNAL mBRdoSetBsc (USHORT argData, ARG far *pArg, flagType fMeta);
+flagType pascal EXTERNAL mBRdoNext (USHORT argData, ARG far *pArg, flagType fMeta);
+flagType pascal EXTERNAL mBRdoPrev (USHORT argData, ARG far *pArg, flagType fMeta);
+flagType pascal EXTERNAL mBRdoDef (USHORT argData, ARG far *pArg, flagType fMeta);
+flagType pascal EXTERNAL mBRdoRef (USHORT argData, ARG far *pArg, flagType fMeta);
+flagType pascal EXTERNAL mBRdoLstRef (USHORT argData, ARG far *pArg, flagType fMeta);
+flagType pascal EXTERNAL mBRdoOutlin (USHORT argData, ARG far *pArg, flagType fMeta);
+flagType pascal EXTERNAL mBRdoCalTre (USHORT argData, ARG far *pArg, flagType fMeta);
+
+
+// mbrevt.c
+//
+void pascal mbrevtinit (void);
+
+
+
+// mbrutil.c
+//
+int pascal procArgs (ARG far * pArg);
+void pascal GrabWord (void);
+flagType pascal wordSepar (CHAR c);
+flagType pascal errstat (char *sz1,char *sz2 );
+void pascal stat (char * pszFcn);
+int far pascal SetMatchCriteria (char far *pTxt );
+int far pascal SetCalltreeDirection (char far *pTxt );
+MBF pascal GetMbf (PBYTE pTxt);
+
+
+// mbrfile.c
+//
+flagType pascal OpenDataBase (char * Path);
+void pascal CloseDataBase (void);
+
+
+// mbrwin.c
+//
+void pascal OpenBrowse (void );
+
+// mbrqry.c
+//
+void pascal InitDefRef(DEFREF QueryType, char *Symbol );
+void GotoDefRef(void );
+void pascal MoveToSymbol(LINE Line, char *Buf, char *Symbol);
+void NextDefRef(void );
+void PrevDefRef(void );
+BOOL InstanceTypeMatches(IINST Iinst);
+
+
+/////////////////////////////////////////////////////////////////////////
+//
+// Messages
+//
+#define MBRERR_CANNOT_OPEN_BSC "Cannot open bsc database"
+#define MBRERR_BAD_BSC_VERSION "Bad version database"
+#define MBRERR_BSC_SEEK_ERROR "BSC Library: Error seeking in file"
+#define MBRERR_BSC_READ_ERROR "BSC Library: Error reading in file"
+#define MBRERR_NOSUCHFILE "Cannot find file"
+#define MBRERR_LAST_DEF "That is the last definition"
+#define MBRERR_LAST_REF "That is the last reference"
+#define MBRERR_FIRST_DEF "No previous definition"
+#define MBRERR_FIRST_REF "No previous reference"
+#define MBRERR_NOT_MODULE "Not a module name:"
+// #define MBRERR_CTDIR_INV "Valid switch values are: F(orward) B(ackward)"
+// #define MBRERR_MATCH_INV "Valid switch values are combinations of: T F M V"
+
diff --git a/private/utils/mep/extens/mbrowse/mbrcore.c b/private/utils/mep/extens/mbrowse/mbrcore.c
new file mode 100644
index 000000000..dc2650152
--- /dev/null
+++ b/private/utils/mep/extens/mbrowse/mbrcore.c
@@ -0,0 +1,197 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ mbrcore.c
+
+Abstract:
+
+ Initialization for the MS Editor browser extension.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 06-Nov-1990
+
+
+Revision History:
+
+
+--*/
+
+#include "mbr.h" /* help extension include file */
+#include "version.h" /* version file */
+
+
+
+//
+// Use double macro level to force rup to be turned into string
+// representation.
+//
+#define VER(x,y,z) VER2(x,y,z)
+#define VER2(x,y,z) "Microsoft Editor Browser Version v1.02."###z##" - "##__DATE__" "##__TIME__
+#define ID VER(rmj,rmm,rup)
+
+
+
+//
+// Initialization of Global data in mbr.h that needs it.
+//
+buffer BscName = {'\00'};
+MBF BscMbf = mbfAll;
+int BscCmnd = CMND_NONE;
+buffer BscArg = {'\00'};
+int BscCalltreeDir = CALLTREE_FORWARD;
+flagType BscInUse = FALSE;
+
+
+
+
+//
+// Initial macro assignments
+//
+char *assignments[] = {
+ "mbrowsesetbsc:alt+b" ,
+ "mbrowselistref:alt+l" ,
+ "mbrowsecalltree:alt+t" ,
+ "mbrowseoutline:alt+o" ,
+ "mbrowsegotodef:alt+d" ,
+ "mbrowsegotoref:alt+r" ,
+ "mbrowsenext:ctrl+num+" ,
+ "mbrowseprev:ctrl+num-" ,
+ NULL
+ };
+
+
+//
+// Switch communication table to MEP
+//
+// Switch Description
+// ------ -----------
+//
+// mbrmatch Set match criteria for references.
+//
+// Values accepted:
+// String combination of: 'T' (Type)
+// 'F' (Function)
+// 'V' (Variable)
+// 'M' (Macro)
+//
+// mbrdir Set Calltree direction.
+//
+// Values accepted:
+// One of: 'F' (Forward)
+// 'B' (Backward)
+//
+struct swiDesc swiTable[] = {
+ {"mbrmatch", SetMatchCriteria, SWI_SPECIAL},
+ {"mbrdir", SetCalltreeDirection, SWI_SPECIAL},
+ {0, 0, 0}
+};
+
+
+
+//
+// Command communication table to MEP
+//
+//
+// Command Description
+// ------- -----------
+//
+// mbrowsenext Display next Definition/Reference
+// mbrowseprev Display previous Definition/Reference
+// mbrowsesetbsc Open BSC database
+// mbrowsegotodef Display first Definition
+// mbrowsegotoref Display first reference
+// mbrowselistref List all references in database
+// mbrowseoutline Display outline
+// mbrowsecalltree Display calltree
+//
+//
+struct cmdDesc cmdTable[] = {
+ { "mbrowsenext", mBRdoNext, 0, NOARG },
+ { "mbrowseprev", mBRdoPrev, 0, NOARG },
+ { "mbrowsesetbsc", mBRdoSetBsc, 0, NOARG | BOXARG | STREAMARG | TEXTARG },
+ { "mbrowsegotodef", mBRdoDef, 0, NOARG | BOXARG | STREAMARG | TEXTARG },
+ { "mbrowsegotoref", mBRdoRef, 0, NOARG | BOXARG | STREAMARG | TEXTARG },
+ { "mbrowselistref", mBRdoLstRef, 0, NOARG | BOXARG | STREAMARG | TEXTARG },
+ { "mbrowseoutline", mBRdoOutlin, 0, NOARG | BOXARG | STREAMARG | TEXTARG },
+ { "mbrowsecalltree",mBRdoCalTre, 0, NOARG | BOXARG | STREAMARG | TEXTARG },
+ {0, 0, 0, 0}
+};
+
+
+
+
+
+void
+EXTERNAL
+WhenLoaded (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Called by MEP when extension is loaded.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+ {
+ char **pAsg;
+ static char *szBrowseName = "<mbrowse>";
+ PSWI fgcolor;
+ int ref;
+
+ DoMessage (ID); /* display signon */
+
+ // Make default key assignments, & create default macros.
+ //
+ strcpy (buf, "arg \"");
+ for (pAsg = assignments; *pAsg; pAsg++) {
+ strcpy (buf+5, *pAsg);
+ strcat (buf, "\" assign");
+ fExecute (buf);
+ }
+
+ // Set up the colors that we will use.
+ //
+ if (fgcolor = FindSwitch("fgcolor")) {
+ hlColor = *fgcolor->act.ival;
+ blColor |= hlColor & 0xf0;
+ itColor |= hlColor & 0xf0;
+ ulColor |= hlColor & 0xf0;
+ wrColor |= (hlColor & 0x70) >> 8;
+ }
+
+ //
+ // create the pseudo file we'll be using for browser.
+ //
+ if (pBrowse = FileNameToHandle(szBrowseName,NULL))
+ DelFile (pBrowse);
+ else {
+ pBrowse = AddFile (szBrowseName);
+ FileRead (szBrowseName, pBrowse);
+ }
+
+ //
+ // Increment the file's reference count so it can't be discarded
+ //
+ GetEditorObject (RQ_FILE_REFCNT | 0xff, pBrowse, &ref);
+ ref++;
+ SetEditorObject (RQ_FILE_REFCNT | 0xff, pBrowse, &ref);
+
+ //
+ // Initialize event stuff
+ //
+ mbrevtinit ();
+}
diff --git a/private/utils/mep/extens/mbrowse/mbrdlg.c b/private/utils/mep/extens/mbrowse/mbrdlg.c
new file mode 100644
index 000000000..cb131c43c
--- /dev/null
+++ b/private/utils/mep/extens/mbrowse/mbrdlg.c
@@ -0,0 +1,422 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ mbrdlg.c
+
+Abstract:
+
+ Top-level functions that implement the commands supported by the
+ MS Editor browser extension.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 06-Nov-1990
+
+
+Revision History:
+
+
+--*/
+
+
+#include "mbr.h"
+
+
+
+/**************************************************************************/
+
+flagType
+pascal
+EXTERNAL
+mBRdoSetBsc (
+ IN USHORT argData,
+ IN ARG far *pArg,
+ IN flagType fMeta
+ )
+/*++
+
+Routine Description:
+
+ Opens a browser database.
+
+Arguments:
+
+ Standard arguments for MEP Editing functions
+
+Return Value:
+
+ FALSE if error, TRUE otherwise
+
+--*/
+
+{
+ PBYTE pName;
+ procArgs(pArg);
+ pName = pArgText ? pArgText : BscName;
+
+ if (pName) {
+ if (! OpenDataBase(pName)) {
+ return errstat(MBRERR_CANNOT_OPEN_BSC, pName);
+ }
+ strcpy(BscName, pName);
+ BscArg[0] = '\0';
+ BscCmnd = CMND_NONE;
+ }
+ return TRUE;
+}
+
+
+
+/**************************************************************************/
+
+flagType
+pascal
+EXTERNAL
+mBRdoNext (
+ IN USHORT argData,
+ IN ARG far *pArg,
+ IN flagType fMeta
+ )
+/*++
+
+Routine Description:
+
+ Displays next reference or definition.
+
+Arguments:
+
+ Standard arguments for MEP editing functions
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ NextDefRef();
+ return TRUE;
+}
+
+
+
+/**************************************************************************/
+
+flagType
+pascal
+EXTERNAL
+mBRdoPrev (
+ IN USHORT argData,
+ IN ARG far *pArg,
+ IN flagType fMeta
+ )
+/*++
+
+Routine Description:
+
+ Displays previous reference or definition.
+
+Arguments:
+
+ Standard arguments for MEP editing functions
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ PrevDefRef();
+ return TRUE;
+}
+
+
+
+/**************************************************************************/
+
+flagType
+pascal
+EXTERNAL
+mBRdoDef (
+ IN USHORT argData,
+ IN ARG far *pArg,
+ IN flagType fMeta
+ )
+/*++
+
+Routine Description:
+
+ Displays first definition of a symbol.
+
+Arguments:
+
+ Standard arguments for MEP editing functions
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ procArgs(pArg);
+
+ if (BscInUse && pArgText) {
+ InitDefRef(Q_DEFINITION, pArgText);
+ NextDefRef();
+ }
+ return TRUE;
+}
+
+
+
+/**************************************************************************/
+
+flagType
+pascal
+EXTERNAL
+mBRdoRef (
+ IN USHORT argData,
+ IN ARG far *pArg,
+ IN flagType fMeta
+ )
+/*++
+
+Routine Description:
+
+ Displays first reference of a symbol.
+
+Arguments:
+
+ Standard arguments for MEP editing functions
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ procArgs(pArg);
+
+ if (BscInUse && pArgText) {
+ InitDefRef(Q_REFERENCE, pArgText);
+ NextDefRef();
+ }
+ return TRUE;
+}
+
+
+
+/**************************************************************************/
+
+flagType
+pascal
+EXTERNAL
+mBRdoLstRef (
+ IN USHORT argData,
+ IN ARG far *pArg,
+ IN flagType fMeta
+ )
+/*++
+
+Routine Description:
+
+ List all references in database matching an MBF criteria.
+
+Arguments:
+
+ Standard arguments for MEP editing functions
+
+Return Value:
+
+ TRUE
+
+--*/
+{
+ MBF mbfReqd;
+
+ // The matching criteria may be specified as an argument.
+ //
+ procArgs(pArg);
+ if (procArgs(pArg) != NOARG) {
+ mbfReqd = GetMbf(pArgText);
+ }
+
+ if (BscInUse) {
+ if ((BscCmnd == CMND_LISTREF) && (mbfReqd == mbfNil)) {
+ //
+ // Pseudofile already has the information we want
+ //
+ ShowBrowse();
+ } else {
+ //
+ // Generate list
+ //
+ OpenBrowse();
+ if (mbfReqd == mbfNil) {
+ mbfReqd = BscMbf;
+ } else {
+ BscMbf = mbfReqd; // Matching criteria becomes default
+ }
+ ListRefs(mbfReqd);
+ BscCmnd = CMND_LISTREF;
+ BscArg[0] = '\0';
+ }
+ MoveCur(0,0);
+ }
+ return TRUE;
+}
+
+
+
+/**************************************************************************/
+
+flagType
+pascal
+EXTERNAL
+mBRdoOutlin (
+ IN USHORT argData,
+ IN ARG far *pArg,
+ IN flagType fMeta
+ )
+/*++
+
+Routine Description:
+
+ Generate outline of a module.
+
+Arguments:
+
+ Standard arguments for MEP editing functions.
+
+Return Value:
+
+ FALSE if symbol is not a module,
+ TRUE otherwise.
+
+--*/
+
+{
+
+ PFILE pCurFile;
+
+ procArgs(pArg);
+
+ if (BscInUse) {
+ if ((BscCmnd == CMND_OUTLINE) && (!strcmp(pArgText, BscArg))) {
+ //
+ // pseudofile already has the information we want
+ //
+ ShowBrowse();
+ MoveCur(0,0);
+ } else if (pArgText) {
+ //
+ // Make sure that the the symbol is a valid module
+ //
+ if (ImodFrLsz(pArgText) == imodNil) {
+ return errstat(MBRERR_NOT_MODULE, pArgText);
+ } else {
+ pCurFile = FileNameToHandle("", NULL);
+ OpenBrowse();
+ if (FOutlineModuleLsz(pArgText,BscMbf)) {
+ //
+ // Function worked, set command state.
+ //
+ BscCmnd = CMND_OUTLINE;
+ strcpy(BscArg, pArgText);
+ MoveCur(0,0);
+ } else {
+ //
+ // Function failed, restore previous file and reset
+ // command state.
+ //
+ pFileToTop(pCurFile);
+ BscCmnd = CMND_NONE;
+ BscArg[0] = '\0';
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+
+
+/**************************************************************************/
+
+flagType
+pascal
+EXTERNAL
+mBRdoCalTre (
+ IN USHORT argData,
+ IN ARG far *pArg,
+ IN flagType fMeta
+ )
+/*++
+
+Routine Description:
+
+ Displays calltree of a symbol.
+
+Arguments:
+
+ Standard arguments for MEP editing functions.
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+
+ PFILE pCurFile;
+ BOOL FunctionWorked;
+
+ procArgs(pArg);
+
+ if (BscInUse) {
+ if ((BscCmnd == CMND_CALLTREE) && (!strcmp(pArgText, BscArg))) {
+ //
+ // pseudofile already has the information we want.
+ //
+ ShowBrowse();
+ MoveCur(0,0);
+ } else if (pArgText) {
+ pCurFile = FileNameToHandle("", NULL);
+ OpenBrowse();
+ //
+ // Generate the tree forward or backward depending on
+ // the value of the direction switch.
+ //
+ if (BscCalltreeDir == CALLTREE_FORWARD) {
+ FunctionWorked = FCallTreeLsz(pArgText);
+ } else {
+ FunctionWorked = FRevTreeLsz(pArgText);
+ }
+
+ if (FunctionWorked) {
+ //
+ // Function worked, set command state.
+ //
+ BscCmnd = CMND_CALLTREE;
+ strcpy(BscArg, pArgText);
+ MoveCur(0,0);
+ } else {
+ //
+ // Function failed, restore previous file and
+ // reset command state.
+ //
+ pFileToTop(pCurFile);
+ BscCmnd = CMND_NONE;
+ BscArg[0] = '\00';
+ }
+ }
+ }
+ return TRUE;
+}
diff --git a/private/utils/mep/extens/mbrowse/mbrevt.c b/private/utils/mep/extens/mbrowse/mbrevt.c
new file mode 100644
index 000000000..8a048bfd0
--- /dev/null
+++ b/private/utils/mep/extens/mbrowse/mbrevt.c
@@ -0,0 +1,58 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ mbrevt.c
+
+Abstract:
+
+ Event handling code for the MS Editor browser extension.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 06-Nov-1990
+
+
+Notes:
+
+ Currently there is no event handler in this extension.
+
+Revision History:
+
+
+--*/
+
+
+
+
+
+#include "mbr.h"
+
+
+
+void
+pascal
+near
+mbrevtinit (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Initialization of event handling code.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+}
diff --git a/private/utils/mep/extens/mbrowse/mbrfile.c b/private/utils/mep/extens/mbrowse/mbrfile.c
new file mode 100644
index 000000000..2f9481666
--- /dev/null
+++ b/private/utils/mep/extens/mbrowse/mbrfile.c
@@ -0,0 +1,96 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ mbrfile.c
+
+Abstract:
+
+ BSC database file Opening and closing code for the MS Editor
+ browser extension.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 06-Nov-1990
+
+
+Revision History:
+
+
+--*/
+
+
+
+#include "mbr.h"
+#include <fcntl.h>
+
+
+
+/**************************************************************************/
+
+flagType
+pascal
+OpenDataBase (
+ IN char * Path
+ )
+/*++
+
+Routine Description:
+
+ Opens a BSC database.
+
+Arguments:
+
+ Path - Name of file containing database
+
+Return Value:
+
+ TRUE if database opened successfully, FALSE otherwise.
+
+--*/
+
+{
+
+ if (BscInUse) {
+ CloseBSC();
+ }
+ if (!FOpenBSC(Path)) {
+ BscInUse = FALSE;
+ } else {
+ BscInUse = TRUE;
+ }
+
+ return BscInUse;
+}
+
+
+
+/**************************************************************************/
+
+void
+pascal
+CloseDataBase (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Closes current BSC database.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CloseBSC();
+ BscInUse = FALSE;
+}
diff --git a/private/utils/mep/extens/mbrowse/mbrowse.def b/private/utils/mep/extens/mbrowse/mbrowse.def
new file mode 100644
index 000000000..a87e122e4
--- /dev/null
+++ b/private/utils/mep/extens/mbrowse/mbrowse.def
@@ -0,0 +1,7 @@
+LIBRARY MBROWSE
+
+DESCRIPTION 'MEP extension'
+
+EXPORTS
+ EntryPoint
+ ModInfo
diff --git a/private/utils/mep/extens/mbrowse/mbrqry.c b/private/utils/mep/extens/mbrowse/mbrqry.c
new file mode 100644
index 000000000..013f3b668
--- /dev/null
+++ b/private/utils/mep/extens/mbrowse/mbrqry.c
@@ -0,0 +1,432 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ mbrqry.c
+
+Abstract:
+
+ This file contains the functions that perform the queries to the
+ database. These functions are called by the top-level functions
+ which implement the browser commands (see mbrdlg.c).
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 07-Nov-1990
+
+
+Revision History:
+
+
+--*/
+
+
+#include "mbr.h"
+
+
+// INST_MATCHES_CRITERIA
+//
+// This macro is used to find out if an instance matches the
+// current MBF criteria.
+//
+#define INST_MATCHES_CRITERIA(Iinst) FInstFilter(Iinst, BscMbf)
+
+
+
+//
+// Static variables reflect the current state of
+// Definition/Reference queries.
+//
+static IREF LastiRef; // Last reference index
+static IREF iRefMin, iRefMax; // Current reference index range
+
+static IDEF LastiDef; // Last definition index
+static IDEF iDefMin, iDefMax; // Current definition index range
+
+static IINST LastIinst; // Last instance index
+static IINST IinstMin, IinstMax; // Current instance index range
+
+static DEFREF LastQueryType; // last query type:
+ // Q_DEFINITION or
+ // Q_REFERENCE
+
+static buffer LastSymbol; // Last symbol queried.
+
+
+
+
+/**************************************************************************/
+
+void
+pascal
+InitDefRef(
+ IN DEFREF QueryType,
+ IN char *Symbol
+ )
+/*++
+
+Routine Description:
+
+ Initializes the query state, this must be done before querying for
+ the first definition/reference of a symbol.
+
+ After calling this function, the first definition/reference must be
+ obtained by calling the NextDefRef function.
+
+Arguments:
+
+ QueryType - Type of query (Q_DEFINITION or Q_REFERENCE).
+ Symbol - Symbol name.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ISYM Isym;
+
+ LastQueryType = QueryType;
+ strcpy(LastSymbol, Symbol);
+
+ Isym = IsymFrLsz(Symbol);
+
+ InstRangeOfSym(Isym, &IinstMin, &IinstMax);
+
+ LastIinst = IinstMin;
+
+ if (QueryType == Q_DEFINITION) {
+ DefRangeOfInst(LastIinst, &iDefMin, &iDefMax);
+ LastiDef = iDefMin - 1;
+ } else {
+ RefRangeOfInst(LastIinst, &iRefMin, &iRefMax);
+ LastiRef = iRefMin - 1;
+ }
+}
+
+
+
+/**************************************************************************/
+
+void
+GotoDefRef (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Makes the file containing the current definition/reference the
+ current file and positions the cursor in the line where the
+ definition/reference takes place.
+
+ The state of the query (current instance and definition/reference
+ indexes) must be set before calling this function.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ char *pName = NULL;
+ WORD Line = 0;
+ PFILE pFile;
+ char szFullName[MAX_PATH];
+
+
+ szFullName[0] = '\0';
+ if (LastQueryType == Q_DEFINITION) {
+ DefInfo(LastiDef, &pName, &Line);
+ } else {
+ RefInfo(LastiRef, &pName, &Line);
+ }
+
+ if (BscInUse && pName) {
+
+ if (rootpath(pName, szFullName)) {
+ strcpy(szFullName, pName);
+ }
+
+ pFile = FileNameToHandle(szFullName,NULL);
+
+ if (!pFile) {
+ pFile = AddFile(szFullName);
+ if (!FileRead(szFullName, pFile)) {
+ RemoveFile(pFile);
+ pFile = NULL;
+ }
+ }
+
+ if (!pFile) {
+ errstat(MBRERR_NOSUCHFILE, szFullName);
+ return;
+ }
+ pFileToTop(pFile);
+ MoveCur(0,Line);
+ GetLine(Line, buf, pFile);
+ MoveToSymbol(Line, buf, LastSymbol);
+ }
+}
+
+
+
+/**************************************************************************/
+
+void
+pascal
+MoveToSymbol(
+ IN LINE Line,
+ IN char *Buf,
+ IN char *Symbol
+ )
+/*++
+
+Routine Description:
+
+ Moves the cursor to the first occurance of a symbol within
+ a line. It is case-sensitive.
+
+Arguments:
+
+ Line - Line number
+ Buf - Contents of the line
+ Symbol - Symbol to look for.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ // First Symbol within Buf
+ //
+ char *p = Buf;
+ char *q = Symbol;
+ char *Mark;
+
+ while (*p) {
+ //
+ // Look for first character
+ //
+ if (*p == *q) {
+ Mark = p;
+ //
+ // compare rest
+ //
+ while (*p && *q && *p == *q) {
+ p++;
+ q++;
+ }
+ if (*q) {
+ q = Symbol;
+ p = Mark+1;
+ } else {
+ break;
+ }
+ } else {
+ p++;
+ }
+ }
+
+ if (!*q) {
+ MoveCur((COL)(Mark-Buf), Line);
+ }
+}
+
+
+
+/**************************************************************************/
+
+void
+NextDefRef (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Displays next definition or reference of a symbol.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ IINST Iinst;
+
+
+ // For locating the next def/ref we do the following:
+ //
+ // 1.- If the def/ref index is within the current range, we just
+ // increment it.
+ // 2.- Otherwise we look for the next instance that matches the
+ // MBF criteria, and set the def/ref index to the min value of
+ // the def/ref range for that instance.
+ // 3.- If no next instance is found, we display an error message
+ //
+
+ if (LastQueryType == Q_DEFINITION) {
+ if (LastiDef == iDefMax-1) {
+
+ Iinst = LastIinst;
+
+ do {
+ LastIinst++;
+ } while ((LastIinst < IinstMax) &&
+ (!INST_MATCHES_CRITERIA(LastIinst)));
+
+ if (LastIinst == IinstMax ) {
+ LastIinst = Iinst;
+ errstat(MBRERR_LAST_DEF, "");
+ return;
+ } else {
+ DefRangeOfInst(LastIinst, &iDefMin, &iDefMax);
+ LastiDef = iDefMin;
+ }
+
+ } else {
+ LastiDef++;
+ }
+ } else {
+ if (LastiRef == iRefMax-1) {
+
+ Iinst = LastIinst;
+
+ do {
+ LastIinst++;
+ } while ((LastIinst < IinstMax) &&
+ (!INST_MATCHES_CRITERIA(LastIinst)));
+
+ if (LastIinst == IinstMax) {
+ LastIinst = Iinst;
+ errstat(MBRERR_LAST_REF, "");
+ return;
+ } else {
+ RefRangeOfInst(LastIinst, &iRefMin, &iRefMax);
+ LastiRef = iRefMin;
+ }
+ } else {
+ LastiRef++;
+ }
+ }
+ GotoDefRef();
+}
+
+
+
+/**************************************************************************/
+
+void
+PrevDefRef (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Displays the previous definition or reference of a symbol.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ IINST Iinst;
+ BOOL Match;
+
+ // For locating the previous def/ref we do the following:
+ //
+ // 1.- if the def/ref index is within the current range, we
+ // just decrement it.
+ // 2.- Otherwise we look for the most previous instance that
+ // matches the MBF criteria, and set the def/ref index to
+ // the maximum value within the def/ref range for that
+ // instance.
+ // 3.- If not such instance exist, we display an error message.
+ //
+
+ if (LastQueryType == Q_DEFINITION) {
+ if (LastiDef == iDefMin) {
+
+ if (LastIinst == IinstMin) {
+ errstat(MBRERR_FIRST_DEF, "");
+ return;
+ }
+
+ Iinst = LastIinst;
+
+ do {
+ Iinst--;
+ } while ((LastIinst > IinstMin) &&
+ (!(Match = INST_MATCHES_CRITERIA(LastIinst))));
+
+ if (!Match) {
+ LastIinst = Iinst;
+ errstat(MBRERR_FIRST_DEF, "");
+ return;
+ } else {
+ DefRangeOfInst(LastIinst, &iDefMin, &iDefMax);
+ LastiDef = iDefMax - 1;
+ }
+
+ } else {
+ LastiDef--;
+ }
+ } else {
+ if (LastiRef == iRefMin) {
+
+ if (LastIinst == IinstMin) {
+ errstat(MBRERR_FIRST_REF, "");
+ return;
+ }
+
+ Iinst = LastIinst;
+
+ do {
+ Iinst--;
+ } while ((LastIinst > IinstMin) &&
+ (!(Match = INST_MATCHES_CRITERIA(LastIinst))));
+
+ if (!Match) {
+ LastIinst = Iinst;
+ errstat(MBRERR_FIRST_REF, "");
+ return;
+ } else {
+ RefRangeOfInst(LastIinst, &iRefMin, &iRefMax);
+ LastiRef = iRefMax - 1;
+ }
+
+ } else {
+ LastiRef--;
+ }
+ }
+ GotoDefRef();
+}
+
diff --git a/private/utils/mep/extens/mbrowse/mbrutil.c b/private/utils/mep/extens/mbrowse/mbrutil.c
new file mode 100644
index 000000000..59dd8b674
--- /dev/null
+++ b/private/utils/mep/extens/mbrowse/mbrutil.c
@@ -0,0 +1,417 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ mbrutil.c
+
+Abstract:
+
+ This file contains miscelaneous functions used in the browser extension.
+ These functions include argument processing, message displaying,
+ setting of switches, etc.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 06-Nov-1990
+
+
+Revision History:
+
+
+--*/
+
+
+#include "mbr.h"
+
+
+
+
+/**************************************************************************/
+
+int
+pascal
+procArgs (
+ IN ARG far * pArg
+ )
+/*++
+
+Routine Description:
+
+ Decodes arguments passed into extension into commonly used
+ variables.
+
+Arguments:
+
+ pArg - Supplies a pointer to the arguments.
+
+Return Value:
+
+ The type of the argument.
+
+--*/
+
+{
+
+ buf[0] = 0;
+ cArg = 0;
+ pArgWord = 0;
+ pArgText = 0;
+ rnArg.flFirst.col = rnArg.flLast.col = 0;
+ rnArg.flFirst.lin = rnArg.flLast.lin = 0;
+
+ pFileCur = FileNameToHandle ("", ""); /* get current file handle */
+
+ switch (pArg->argType) {
+ case NOARG: /* <function> only, no arg */
+ cArg = pArg->arg.nullarg.cArg; /* get <arg> count */
+ GrabWord (); /* get argtext and argword */
+ break;
+
+ case NULLARG: /* <arg><function> */
+ cArg = pArg->arg.nullarg.cArg; /* get <arg> count */
+ GrabWord (); /* get argtext and argword */
+ break;
+
+ case STREAMARG: /* <arg>line movement<function> */
+ cArg = pArg->arg.streamarg.cArg;/* get <arg> count */
+ rnArg.flFirst.col = pArg->arg.streamarg.xStart;
+ rnArg.flLast.col = pArg->arg.streamarg.xEnd;
+ rnArg.flFirst.lin = pArg->arg.streamarg.yStart;
+ if (GetLine(rnArg.flFirst.lin, buf, pFileCur) > rnArg.flFirst.col) {
+ pArgText = &buf[rnArg.flFirst.col]; /* point at word */
+ buf[rnArg.flLast.col] = 0; /* terminate string */
+ }
+ break;
+
+ case TEXTARG: /* <arg> text <function> */
+ cArg = pArg->arg.textarg.cArg; /* get <arg> count */
+ pArgText = pArg->arg.textarg.pText;
+ break;
+ }
+ return pArg->argType;
+}
+
+
+
+/**************************************************************************/
+
+void
+pascal
+GrabWord (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Grabs the word underneath the cursor.
+ Upon exit, pArgText points to the word
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ pArgText = pArgWord = 0;
+ pFileCur = FileNameToHandle ("", ""); // get current file handle
+ GetTextCursor (&rnArg.flFirst.col, &rnArg.flFirst.lin);
+ if (GetLine(rnArg.flFirst.lin, buf, pFileCur)) {
+ //
+ // get line
+ //
+ pArgText = &buf[rnArg.flFirst.col]; // point at word
+ while (!wordSepar((int)*pArgText)) {
+ //
+ // Search for end
+ //
+ pArgText++;
+ }
+ *pArgText = 0; // and terminate
+
+ pArgWord = pArgText = &buf[rnArg.flFirst.col]; // point at word
+ while ((pArgWord > &buf[0]) && !wordSepar ((int)*(pArgWord-1))) {
+ pArgWord--;
+ }
+ }
+}
+
+
+
+/**************************************************************************/
+
+flagType
+pascal
+wordSepar (
+ IN CHAR c
+)
+/*++
+
+Routine Description:
+
+ Find out if character is a word separator.
+
+ A word separator is anything not in the [a-z, A-Z, 0-9] set.
+
+Arguments:
+
+ c - Supplies the character.
+
+Return Value:
+
+ TRUE if c is a word separator, FALSE otherwise
+
+--*/
+
+{
+
+ if (((c >= 'a') && (c <= 'z')) ||
+ ((c >= 'A') && (c <= 'Z')) ||
+ ((c >= '0') && (c <= '9'))) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+
+
+/**************************************************************************/
+
+flagType
+pascal
+errstat (
+ IN char *sz1,
+ IN char *sz2
+ )
+/*++
+
+Routine Description:
+
+ Concatenates two strings and displays them on the status line.
+
+Arguments:
+
+ sz1 - Supplies a pointer to the first string
+ sz2 - Supplies a pointer to the second string.
+
+Return Value:
+
+ FALSE
+
+--*/
+
+{
+
+ buffer buf;
+ strcpy (buf, sz1);
+ if (sz2) {
+ strcat (buf, " ");
+ strcat (buf, sz2);
+ }
+ _stat (buf);
+ return FALSE;
+}
+
+
+
+/**************************************************************************/
+
+void
+pascal
+_stat (
+ IN char * pszFcn
+ )
+/*++
+
+Routine Description:
+
+ Displays extension name and message on the status line
+
+Arguments:
+
+ pszFcn - Message to display
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ buffer buf; /* message buffer */
+
+ strcpy(buf,"mbrowse: "); /* start with name */
+ if (strlen(pszFcn) > 72) {
+ pszFcn+= strlen(pszFcn) - 69;
+ strcat (buf, "...");
+ }
+ strcat(buf,pszFcn); /* append message */
+ DoMessage (buf); /* display */
+}
+
+
+
+/**************************************************************************/
+
+int
+far
+pascal
+SetMatchCriteria (
+ IN char far *pTxt
+ )
+/*++
+
+Routine Description:
+
+ Sets the mbrmatch switch.
+ Creates an MBF mask from the given string and sets the BscMbf variable.
+
+Arguments:
+
+ pTxt - Supplies the string containing the new default
+ match criteria.
+
+Return Value:
+
+ TRUE if string contains a valid value.
+ FALSE otherwise
+
+--*/
+
+{
+ MBF mbfReqd;
+
+ mbfReqd = GetMbf(pTxt);
+
+ if (mbfReqd != mbfNil) {
+ BscMbf = mbfReqd;
+ } else {
+ return FALSE;
+ }
+ BscCmnd = CMND_NONE; // reset command state
+ return TRUE;
+}
+
+
+
+/**************************************************************************/
+
+int
+far
+pascal
+SetCalltreeDirection (
+ IN char far *pTxt
+ )
+/*++
+
+Routine Description:
+
+ Sets the mbrdir switch.
+ Sets the BscCalltreeDir variable to CALLTREE_FORWARD or
+ CALLTREE_BACKWARD, depending on the first character of the
+ string supplied.
+
+ The given string must start with either 'F' or 'B'.
+
+Arguments:
+
+ pTxt - Supplies the string containing the new default
+ direction.
+
+Return Value:
+
+ TRUE if the string contains a valid value,
+ FALSE otherwise.
+
+--*/
+
+{
+ switch(*pTxt) {
+
+ case 'f':
+ case 'F':
+ BscCalltreeDir = CALLTREE_FORWARD;
+ break;
+
+ case 'b':
+ case 'B':
+ BscCalltreeDir = CALLTREE_BACKWARD;
+ break;
+
+ default:
+ return FALSE;
+ break;
+ }
+ BscCmnd = CMND_NONE; // Reset command state
+ return TRUE;
+}
+
+
+
+/**************************************************************************/
+
+MBF
+pascal
+GetMbf(
+ IN PBYTE pTxt
+ )
+/*++
+
+Routine Description:
+
+ Creates an MBF mask from a given string.
+ The string is parsed for the characters 'T', 'V', 'F', and 'M'.
+
+Arguments:
+
+ pTxt - Supplies a pointer to string
+
+Return Value:
+
+ MBF mask generated from string
+
+--*/
+
+{
+
+ MBF mbfReqd = mbfNil;
+
+ if (pTxt) {
+ while (*pTxt) {
+ switch(*pTxt++) {
+ case 'f':
+ case 'F':
+ mbfReqd |= mbfFuncs;
+ break;
+
+ case 'v':
+ case 'V':
+ mbfReqd |= mbfVars;
+ break;
+
+ case 'm':
+ case 'M':
+ mbfReqd |= mbfMacros;
+ break;
+
+ case 't':
+ case 'T':
+ mbfReqd |= mbfTypes;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ return mbfReqd;
+}
diff --git a/private/utils/mep/extens/mbrowse/mbrwin.c b/private/utils/mep/extens/mbrowse/mbrwin.c
new file mode 100644
index 000000000..76a5a2ec6
--- /dev/null
+++ b/private/utils/mep/extens/mbrowse/mbrwin.c
@@ -0,0 +1,86 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ mbrwin.c
+
+Abstract:
+
+ Functions dealing with opening and displaying the browse window.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 06-Nov-1990
+
+
+Revision History:
+
+
+--*/
+
+#include "mbr.h"
+
+
+
+/**************************************************************************/
+
+void
+pascal
+OpenBrowse (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Opens a window on the browser file, empties it and makes it current
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ DelFile (pBrowse);
+ pFileToTop (pBrowse);
+ BrowseLine = 0;
+}
+
+
+
+/**************************************************************************/
+
+void
+pascal
+ShowBrowse (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Makes the browser file current.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ pFileToTop (pBrowse);
+ BrowseLine = 0;
+}
diff --git a/private/utils/mep/extens/mbrowse/sources b/private/utils/mep/extens/mbrowse/sources
new file mode 100644
index 000000000..04790bd12
--- /dev/null
+++ b/private/utils/mep/extens/mbrowse/sources
@@ -0,0 +1,27 @@
+MAJORCOMP=utils
+MINORCOMP=mep
+
+TARGETNAME=mbrowse
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+LINKLIBS=\nt\public\sdk\lib\*\exthdr.lib
+TARGETLIBS=\nt\private\sdktools\ztools\src\obj\*\ztools.lib \
+ ..\..\browser\bsc\obj\*\bsc.lib \
+ \nt\public\sdk\lib\*\kernel32.lib
+
+INCLUDES=.;..\..\inc;..\..\browser\inc;\nt\private\sdktools\ztools\inc
+
+SOURCES= mbrcore.c \
+ mbrdlg.c \
+ mbrevt.c \
+ mbrutil.c \
+ mbrfile.c \
+ mbrwin.c \
+ mbrqry.c \
+ calbak.c
+
+
+C_DEFINES=-D_OS2_20_=0 -DNO_EXT_KEYS -Dpascal= -Dfar= -DNOLANMAN -DNT
+UMTYPE=console
+USE_CRTDLL=1
+ \ No newline at end of file
diff --git a/private/utils/mep/extens/mepparty/makefile b/private/utils/mep/extens/mepparty/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/mep/extens/mepparty/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/mep/extens/mepparty/mepparty.c b/private/utils/mep/extens/mepparty/mepparty.c
new file mode 100644
index 000000000..86d791850
--- /dev/null
+++ b/private/utils/mep/extens/mepparty/mepparty.c
@@ -0,0 +1,898 @@
+/*
+** MEP Party extension
+**
+** History:
+** 17-Oct-1991 Ported to NT
+**
+*/
+
+#define _CTYPE_DISABLE_MACROS
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ext.h"
+#include <winuserp.h>
+
+#ifndef TRUE
+#define TRUE -1
+#define FALSE 0
+#endif
+
+flagType iconizeOnExit = TRUE;
+
+flagType pascal DoCaseLine(
+ PFILE CurFile,
+ LINE y,
+ COL x,
+ COL maxX,
+ flagType LowerCase
+ )
+{
+ flagType Modified;
+ int cb;
+ char buf[ BUFLEN ], *s;
+
+ cb = GetLine( y, buf, CurFile );
+ s = &buf[ x ];
+ if (maxX != 0) {
+ if (maxX - x < cb) {
+ cb = maxX - x + 1;
+ }
+ }
+ else {
+ cb -= x;
+ }
+
+ Modified = FALSE;
+ while (cb--) {
+ if (LowerCase) {
+ if (*s >= 'A' && *s <= 'Z') {
+ *s -= 'A' - 'a';
+ Modified = TRUE;
+ }
+ }
+ else {
+ if (*s >= 'a' && *s <= 'z') {
+ *s += 'A' - 'a';
+ Modified = TRUE;
+ }
+ }
+
+ s++;
+ }
+
+ if (Modified) {
+ PutLine( y, buf, CurFile );
+ }
+
+ return( TRUE );
+}
+
+
+flagType pascal EXTERNAL
+Case(
+ CMDDATA argData,
+ ARG far *pArg,
+ flagType fMeta
+ )
+{
+ int i;
+ PFILE CurFile;
+
+ CurFile = FileNameToHandle("",NULL);
+ switch( pArg->argType ) {
+ case NOARG:
+ return( DoCaseLine( CurFile, pArg->arg.noarg.y, 0, 0, fMeta ) );
+ break;
+
+ case NULLARG:
+ return( DoCaseLine( CurFile,
+ pArg->arg.nullarg.y,
+ pArg->arg.nullarg.x,
+ 0,
+ fMeta
+ )
+ );
+ break;
+
+ case LINEARG:
+ for (i=pArg->arg.linearg.yStart; i<=pArg->arg.linearg.yEnd; i++) {
+ if (!DoCaseLine( CurFile, (LINE)i, 0, 0, fMeta )) {
+ return( FALSE );
+ }
+ }
+
+ return( TRUE );
+ break;
+
+ case BOXARG:
+ for (i=pArg->arg.boxarg.yTop; i<=pArg->arg.boxarg.yBottom; i++) {
+ if (!DoCaseLine( CurFile,
+ (LINE)i,
+ pArg->arg.boxarg.xLeft,
+ pArg->arg.boxarg.xRight,
+ fMeta
+ )
+ ) {
+ return( FALSE );
+ }
+ }
+
+ return( TRUE );
+ break;
+
+ default:
+ BadArg();
+ return( FALSE );
+ }
+
+ argData;
+}
+
+int CountMsgFiles;
+int MsgFileIndex;
+HANDLE MsgFiles[ 2 ];
+int MsgFileOffsetIndex;
+LONG MsgFileOffsets[ 3 ];
+
+char
+GetHexDigit(
+ ULONG value,
+ int index
+ )
+{
+ int digit;
+
+ if (index < 4) {
+ index <<= 2;
+ digit = (int)((value >> index) & 0xF);
+ }
+ else {
+ digit = 0;
+ }
+ if (digit <= 9) {
+ return( (char)(digit+'0') );
+ }
+ else {
+ return( (char)((digit-10)+'A') );
+ }
+}
+
+void
+MyFormatMessage(
+ char *buf,
+ char *msg,
+ long value1,
+ long value2
+ );
+
+void
+MyFormatMessage(
+ char *buf,
+ char *msg,
+ long value1,
+ long value2
+ )
+{
+ char c, *src, *dst;
+ long value;
+
+ src = msg;
+ dst = buf;
+ while (c = *src++) {
+ if (c == '%' && src[1] == 'x') {
+ if (*src == '1') {
+ value = value1;
+ }
+ else {
+ value = value2;
+ }
+
+ *dst++ = GetHexDigit( value, 3 );
+ *dst++ = GetHexDigit( value, 2 );
+ *dst++ = GetHexDigit( value, 1 );
+ *dst++ = GetHexDigit( value, 0 );
+ src++;
+ src++;
+ }
+ else {
+ *dst++ = c;
+ }
+ }
+
+ *dst = '\0';
+ DoMessage( buf );
+}
+
+flagType pascal EXTERNAL
+ShowBuildMessage(
+ CMDDATA argData,
+ ARG far *pArg,
+ flagType fMeta
+ )
+{
+ int i, BytesRead, BytesScanned, linenum;
+ ULONG NewOffset;
+ char LineBuffer[ 256 ], *s, *s1;
+
+ if (!fMeta && CountMsgFiles == 0) {
+ MsgFileIndex = 0;
+ MsgFiles[ MsgFileIndex ] = CreateFile( "build.wrn",
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL
+ );
+ if (MsgFiles[ MsgFileIndex ] != INVALID_HANDLE_VALUE) {
+ CountMsgFiles++;
+ MsgFileIndex++;
+ }
+
+ MsgFiles[ MsgFileIndex ] = CreateFile( "build.err",
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL
+ );
+ if (MsgFiles[ MsgFileIndex ] != INVALID_HANDLE_VALUE) {
+ CountMsgFiles++;
+ MsgFileIndex++;
+ }
+
+ MsgFileIndex = 0;
+ MsgFileOffsetIndex = 0;
+ MsgFileOffsets[ 0 ] = 0L;
+ MsgFileOffsets[ 1 ] = 0L;
+ MsgFileOffsets[ 2 ] = 0L;
+ }
+ else
+ if (fMeta && CountMsgFiles != 0) {
+ for (i=0; i<CountMsgFiles; i++) {
+ CloseHandle( MsgFiles[ i ] );
+ }
+
+ CountMsgFiles = 0;
+ return( TRUE );
+ }
+
+ if (CountMsgFiles == 0) {
+ DoMessage( "No BUILD.WRN or BUILD.ERR message file." );
+ return( FALSE );
+ }
+
+ switch( pArg->argType ) {
+ case NULLARG:
+ if (MsgFileOffsetIndex-- == 0) {
+ MsgFileOffsetIndex = 2;
+ }
+ //
+ // fall through
+ //
+
+ case NOARG:
+retrymsgfile:
+ NewOffset = SetFilePointer( MsgFiles[ MsgFileIndex ],
+ MsgFileOffsets[ MsgFileOffsetIndex ],
+ NULL,
+ FILE_BEGIN
+ );
+ if (NewOffset == -1) {
+ MyFormatMessage( LineBuffer,
+ "SetFilePointer( %1x ) failed - rc == %2x",
+ MsgFileOffsets[ MsgFileOffsetIndex ],
+ GetLastError()
+ );
+ DoMessage( LineBuffer );
+ return( FALSE );
+ }
+
+ if (!ReadFile( MsgFiles[ MsgFileIndex ],
+ LineBuffer,
+ sizeof( LineBuffer ),
+ ( LPDWORD )&BytesRead,
+ NULL
+ )
+ ) {
+ MyFormatMessage( LineBuffer,
+ "ReadFile( %1x ) failed - rc == %2x",
+ (ULONG)BytesRead,
+ GetLastError()
+ );
+ DoMessage( LineBuffer );
+ return( FALSE );
+ }
+
+ s = LineBuffer;
+ BytesScanned = 0;
+ while (BytesScanned < BytesRead) {
+ BytesScanned++;
+ if (*s == '\n') {
+ *s = '\0';
+ break;
+ }
+ else
+ if (*s == '\r' && s[1] == '\n') {
+ *s = '\0';
+ BytesScanned++;
+ break;
+ }
+ else {
+ s++;
+ }
+ }
+
+ if (BytesScanned == 0) {
+ if (++MsgFileIndex == CountMsgFiles) {
+ for (i=0; i<CountMsgFiles; i++) {
+ CloseHandle( MsgFiles[ i ] );
+ }
+
+ CountMsgFiles = 0;
+ DoMessage( "no more BUILD messages" );
+ return( FALSE );
+ }
+ else {
+ MsgFileOffsetIndex = 0;
+ MsgFileOffsets[ 0 ] = 0L;
+ MsgFileOffsets[ 1 ] = 0L;
+ MsgFileOffsets[ 2 ] = 0L;
+ goto retrymsgfile;
+ }
+ }
+ else {
+ NewOffset = MsgFileOffsets[ MsgFileOffsetIndex ];
+
+ if (++MsgFileOffsetIndex == 3) {
+ MsgFileOffsetIndex = 0;
+ }
+
+ MsgFileOffsets[ MsgFileOffsetIndex ] = NewOffset + BytesScanned;
+ }
+
+ s = LineBuffer;
+ while (*s) {
+ if (*s == '(') {
+ *s++ = '\0';
+ s1 = s;
+ while (*s && isdigit( *s )) {
+ s++;
+ }
+ *s++ = '\0';
+ linenum = atoi( s1 );
+ while (*s) {
+ if (*s++ == ':') {
+ fChangeFile( FALSE, LineBuffer );
+ MoveCur( 0, (LINE)(linenum-1) );
+ fExecute( "begline" );
+ DoMessage( s+1 );
+ return( TRUE );
+ }
+ }
+ }
+ else {
+ s++;
+ }
+ }
+ goto retrymsgfile;
+
+ default:
+ BadArg();
+ return( FALSE );
+ }
+
+ return( TRUE );
+
+ argData;
+}
+
+char ErrorText[ 64 ],
+ Arguments[ 64 + MAX_PATH ],
+ PathName[ MAX_PATH ];
+
+flagType pascal EXTERNAL
+SlmOut(
+ CMDDATA argData,
+ ARG far *pArg,
+ flagType fMeta
+ )
+{
+ PFILE CurFile;
+ STARTUPINFO StartupInfo;
+ PROCESS_INFORMATION ProcessInformation;
+ DWORD ExitCode;
+ char *FileName;
+ DWORD FileFlags;
+
+ CurFile = FileNameToHandle( (char far *)"", (char far *)NULL );
+ FileFlags = 0;
+ GetEditorObject( 0xFF | RQ_FILE_FLAGS, CurFile, (PVOID)&FileFlags );
+ GetEditorObject( 0xFF | RQ_FILE_NAME, CurFile, (PVOID)PathName );
+
+ FileName = PathName + strlen( PathName );
+ while (FileName > PathName) {
+ if (*--FileName == '\\') {
+ *FileName++ = '\0';
+ break;
+ }
+ }
+
+ if (FileName > PathName) {
+ if (fMeta) {
+ strcpy( Arguments, "in -i " );
+ }
+ else {
+ strcpy( Arguments, "out -z " );
+ }
+
+ strcat( Arguments, FileName );
+ DoMessage( Arguments );
+
+ memset( &StartupInfo, 0, sizeof( StartupInfo ) );
+ StartupInfo.cb = sizeof(StartupInfo);
+
+ if (CreateProcess( NULL,
+ Arguments,
+ NULL,
+ NULL,
+ FALSE,
+ 0,
+ NULL,
+ PathName,
+ &StartupInfo,
+ &ProcessInformation
+ )
+ ) {
+ WaitForSingleObject( ProcessInformation.hProcess, (DWORD)-1 );
+ if (!GetExitCodeProcess( ProcessInformation.hProcess, &ExitCode )) {
+ ExitCode = 1;
+ }
+ CloseHandle( ProcessInformation.hProcess );
+ CloseHandle( ProcessInformation.hThread );
+ }
+ else {
+ ExitCode = 1;
+ }
+
+ if (ExitCode == 0) {
+ if (!fMeta && FileFlags & DIRTY) {
+ FileFlags &= ~(REFRESH|READONLY);
+ SetEditorObject( 0xFF | RQ_FILE_FLAGS, CurFile, (PVOID)&FileFlags );
+ GetEditorObject( 0xFF | RQ_FILE_NAME, CurFile, (PVOID)PathName );
+ fChangeFile( FALSE, PathName );
+ FileFlags = 0;
+ GetEditorObject( 0xFF | RQ_FILE_FLAGS, CurFile, (PVOID)&FileFlags );
+ if (FileFlags & DIRTY) {
+ DoMessage( "Modified file has been checked out." );
+ }
+ else {
+ DoMessage( "Current file has been checked out." );
+ }
+ }
+ else {
+ fExecute( "refresh" );
+ if (fMeta) {
+ DoMessage( "Changes to current file discarded. No longer checked out." );
+ }
+ else {
+ DoMessage( "Current file has been checked out." );
+ }
+ }
+
+ return( TRUE );
+ }
+ else {
+ return( FALSE );
+ }
+ }
+ else {
+ DoMessage( "Unable to change current directory" );
+ return( FALSE );
+ }
+
+ argData;
+ pArg;
+ fMeta;
+}
+
+
+EVT evtIdle;
+HANDLE Thread;
+DWORD ThreadId;
+
+HANDLE EditorStartEvent;
+HANDLE EditorStopEvent;
+HANDLE EditorSharedMemory;
+LPSTR EditorMemoryPointer;
+HWND hPrevWindow = (HWND)-1;
+PFILE pMailFile;
+LPSTR lpCmdLine = NULL;
+char CommandLineBuffer[ 256 ];
+
+
+flagType
+CheckForCmdLine( VOID )
+{
+ LPSTR s;
+ PFILE pCurFile;
+ int fFileFlags;
+ flagType fMailFile;
+
+ if (lpCmdLine) {
+ s = lpCmdLine;
+ lpCmdLine = NULL;
+
+ while (*s == ' ')
+ s++;
+
+ fMailFile = FALSE;
+ if (*s) {
+ if (*s == '/' || *s == '-')
+ if (*++s == 't' || *s == 'T')
+ if (*++s == ' ') {
+ s++;
+ fMailFile = TRUE;
+ }
+
+ if (fChangeFile( TRUE, s ) && fMailFile) {
+ pCurFile = FileNameToHandle( "", NULL );
+ fFileFlags = 0;
+ GetEditorObject( 0xFF | RQ_FILE_FLAGS, pCurFile,
+ (PVOID)&fFileFlags );
+ fFileFlags |= TEMP;
+ SetEditorObject( 0xFF | RQ_FILE_FLAGS, pCurFile,
+ (PVOID)&fFileFlags );
+ fExecute( "entermail" );
+ pMailFile = pCurFile;
+ }
+ }
+ }
+
+ return( FALSE ); // We never handle a character
+}
+
+
+HWND
+GetWindowHandleOfEditor( void );
+
+void
+WaitForStartEvent( void );
+
+void SwitchToProgram( HWND hwnd );
+
+void
+SwitchToTaskManager( void );
+
+flagType pascal EXTERNAL
+StartExt(
+ CMDDATA argData,
+ ARG far *pArg,
+ flagType fMeta
+ )
+{
+ PFILE pCurFile;
+ int fFileFlags;
+ CHAR szFileName[ 256 ];
+
+ if (!fMeta || pMailFile) {
+ pCurFile = FileNameToHandle( "", NULL );
+ fFileFlags = 0;
+ GetEditorObject( 0xFF | RQ_FILE_FLAGS, pCurFile, (PVOID)&fFileFlags );
+ if (fFileFlags & DIRTY)
+ FileWrite( "", pCurFile );
+
+ if (pMailFile) {
+ RemoveFile( pMailFile );
+ pMailFile = NULL;
+ }
+ }
+
+ if (hPrevWindow) {
+ if (hPrevWindow != (HWND)-1) {
+ SetEvent( EditorStopEvent );
+ SwitchToProgram( hPrevWindow );
+ }
+
+ hPrevWindow = NULL;
+ }
+ else {
+ SwitchToTaskManager();
+ }
+
+#if 0
+ //
+ // Wait for this window to enter foreground again.
+ //
+
+ WaitForSingleObject( EditorStartEvent, (DWORD)-1 );
+
+ fExecute( "cancel" );
+ fExecute( "setwindow" );
+ pCurFile = FileNameToHandle( "", NULL );
+ pFileToTop( pCurFile );
+ szFileName[ 0 ] = '\0';
+ GetEditorObject( 0xFF | RQ_FILE_NAME, pCurFile, (PVOID)szFileName );
+ if (szFileName[ 0 ] != '\0') {
+ fChangeFile( TRUE, szFileName );
+ }
+
+ return( CheckForCmdLine() );
+
+#else
+ fExecute( "savetmpfile" );
+
+ return TRUE;
+
+#endif
+
+ argData;
+ pArg;
+}
+
+
+HWND
+GetWindowHandleOfEditor( void )
+{
+ HWND hwnd;
+
+ hwnd = GetWindow( GetDesktopWindow(), GW_CHILD );
+ while (hwnd) {
+ /*
+ * Only look at visible, non-owned, Top Level Windows.
+ */
+ if (IsWindowVisible( hwnd ) && !GetWindow( hwnd, GW_OWNER )) {
+ break;
+ }
+
+ hwnd = GetWindow( hwnd, GW_HWNDNEXT );
+ }
+
+
+ return hwnd;
+}
+
+
+void
+SwitchToProgram(
+ HWND hwnd
+ )
+{
+ HWND hwndSelf;
+ HWND hwndFoo;
+
+ hwndSelf = GetWindowHandleOfEditor();
+ if (hwndSelf && iconizeOnExit) {
+ ShowWindow( hwndSelf, SW_MINIMIZE );
+ }
+
+ //
+ // Temporary hack to make SetForegroundWindow work from a console
+ // window - create an invisible window, make it the foreground
+ // window and then make the window we want the foreground window.
+ // After that destroy the temporary window.
+ //
+
+ hwndFoo = CreateWindow( "button", "baz", 0, 0, 0, 0, 0,
+ NULL, NULL, NULL, NULL
+ );
+
+ SetForegroundWindow( hwndFoo );
+
+ SetForegroundWindow( hwnd );
+ ShowWindow( hwnd, SW_RESTORE);
+
+ DestroyWindow( hwndFoo );
+}
+
+void
+SwitchToTaskManager( void )
+{
+ HWND hwnd;
+ wchar_t szTitle[ 256 ];
+
+ /*
+ * Search the window list for task manager window.
+ */
+ hwnd = GetWindow( GetDesktopWindow(), GW_CHILD );
+ while (hwnd) {
+ /*
+ * Only look at non-visible, non-owned, Top Level Windows.
+ */
+ if (!IsWindowVisible( hwnd ) && !GetWindow( hwnd, GW_OWNER )) {
+ //
+ // Use internal call to get current Window title that does NOT
+ // use SendMessage to query the title from the window procedure
+ // but instead returns the most recent title displayed.
+ //
+
+ InternalGetWindowText( hwnd,
+ (LPWSTR)szTitle,
+ sizeof( szTitle )
+ );
+ if (!_wcsicmp( L"Task List", szTitle )) {
+ SwitchToProgram( hwnd );
+ break;
+ }
+ }
+
+ hwnd = GetWindow( hwnd, GW_HWNDNEXT );
+ }
+
+ return;
+}
+
+
+void
+WaitForStartEvent( void )
+{
+ LPSTR lpName, lpValue, lpNewCmdLine, lpEditorMem;
+
+ WaitForSingleObject( EditorStartEvent, (DWORD)-1 );
+
+ lpEditorMem = EditorMemoryPointer;
+
+ hPrevWindow = *(HWND *)lpEditorMem;
+ lpEditorMem += sizeof( hPrevWindow );
+
+ pMailFile = NULL;
+
+ SetCurrentDirectory( lpEditorMem );
+ while( *lpEditorMem++ ) {
+ }
+
+ lpNewCmdLine = CommandLineBuffer;
+ while( *lpNewCmdLine++ = *lpEditorMem++ ) {
+ }
+
+ while (*lpEditorMem) {
+ lpName = lpEditorMem;
+ while (*lpEditorMem) {
+ if (*lpEditorMem++ == '=') {
+ lpValue = lpEditorMem;
+ lpValue[ -1 ] = '\0';
+ while (*lpEditorMem++) {
+ }
+ SetEnvironmentVariableA( lpName, lpValue );
+ lpValue[ -1 ] = '=';
+ break;
+ }
+ }
+ }
+
+ lpCmdLine = CommandLineBuffer;
+
+ return;
+}
+
+
+flagType pascal EXPORT MyIdleEvent( EVTargs far *pArgs )
+{
+ return( CheckForCmdLine() );
+
+ pArgs;
+}
+
+
+DWORD
+EnvThread(
+ PVOID Parameter
+ );
+
+flagType
+StartExtLoaded( void );
+
+flagType
+StartExtLoaded ()
+{
+ EditorStartEvent = CreateEvent( NULL, FALSE, FALSE, "EditorStartEvent" );
+ if (EditorStartEvent == NULL) {
+ DoMessage( "Create of EditorStartEvent failed" );
+ return FALSE;
+ }
+
+ EditorStopEvent = CreateEvent( NULL, FALSE, FALSE, "EditorStopEvent" );
+ if (EditorStopEvent == NULL) {
+ DoMessage( "Create of EditorStopEvent failed" );
+ CloseHandle( EditorStartEvent );
+ return FALSE;
+ }
+
+ EditorSharedMemory = CreateFileMapping( INVALID_HANDLE_VALUE,
+ NULL,
+ PAGE_READWRITE,
+ 0,
+ 8192,
+ "EditorSharedMemory"
+ );
+ if (EditorSharedMemory == NULL) {
+ DoMessage( "Create of EditorStartMemory failed" );
+ CloseHandle( EditorStopEvent );
+ CloseHandle( EditorStartEvent );
+ return FALSE;
+ }
+
+ EditorMemoryPointer = MapViewOfFile( EditorSharedMemory,
+ FILE_MAP_READ | FILE_MAP_WRITE,
+ 0,
+ 0,
+ 8192
+ );
+ if (EditorMemoryPointer == NULL) {
+ DoMessage( "MapView of EditorStartMemory failed" );
+ CloseHandle( EditorStopEvent );
+ CloseHandle( EditorStartEvent );
+ CloseHandle( EditorSharedMemory );
+ return FALSE;
+ }
+
+ hPrevWindow = (HWND)-1;
+
+ evtIdle.evtType = EVT_RAWKEY;
+ evtIdle.func = MyIdleEvent;
+ evtIdle.focus = NULL;
+ RegisterEvent( (EVT far *)&evtIdle );
+
+ Thread = CreateThread( NULL,
+ 8192,
+ (LPTHREAD_START_ROUTINE)EnvThread,
+ 0,
+ 0,
+ &ThreadId
+ );
+
+ if (Thread == NULL) {
+ DoMessage( "Can't start environment thread" );
+ UnmapViewOfFile( EditorMemoryPointer );
+ CloseHandle( EditorSharedMemory );
+ CloseHandle( EditorStopEvent );
+ CloseHandle( EditorStartEvent );
+ return FALSE;
+ }
+
+ if (!SetThreadPriority( Thread, THREAD_PRIORITY_ABOVE_NORMAL )) {
+ DoMessage( "Can't set priority of environment thread" );
+ }
+
+ return TRUE;
+}
+
+DWORD
+EnvThread(
+ PVOID Parameter
+ )
+{
+ while( TRUE ) {
+ WaitForStartEvent();
+ }
+
+ Parameter;
+ return 0;
+}
+
+
+struct swiDesc swiTable[] = {
+ { "iconizeonexit", toPIF(iconizeOnExit), SWI_BOOLEAN },
+ {0, 0, 0},
+ {0, 0, 0},
+ {0, 0, 0}
+};
+
+struct cmdDesc cmdTable[] = {
+ {"startext", StartExt, 0, NOARG },
+ { "MapCase", Case, 0, NOARG | NULLARG | LINEARG | BOXARG | NUMARG },
+ { "BuildMessage", ShowBuildMessage, 0, NOARG | NULLARG | TEXTARG },
+ { "SlmOut", SlmOut, 0, NOARG | NULLARG | TEXTARG },
+ { NULL, (funcCmd)NULL, 0, 0 }
+};
+
+void EXTERNAL WhenLoaded(void)
+{
+ if (StartExtLoaded()) {
+ CountMsgFiles = 0;
+ DoMessage("MEPPARTY extensions loaded.");
+ }
+}
diff --git a/private/utils/mep/extens/mepparty/mepparty.def b/private/utils/mep/extens/mepparty/mepparty.def
new file mode 100644
index 000000000..69718d0ae
--- /dev/null
+++ b/private/utils/mep/extens/mepparty/mepparty.def
@@ -0,0 +1,7 @@
+LIBRARY MEPPARTY
+
+DESCRIPTION 'MEP extension'
+
+EXPORTS
+ EntryPoint
+ ModInfo
diff --git a/private/utils/mep/extens/mepparty/mepparty.rc b/private/utils/mep/extens/mepparty/mepparty.rc
new file mode 100644
index 000000000..87d62f3e0
--- /dev/null
+++ b/private/utils/mep/extens/mepparty/mepparty.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Microsoft\256 MEP Extensions"
+
+#define VER_INTERNALNAME_STR "mepparty.dll"
+#define VER_ORIGINALFILENAME_STR "mepparty.dll"
+
+#include <common.ver>
+
diff --git a/private/utils/mep/extens/mepparty/sources b/private/utils/mep/extens/mepparty/sources
new file mode 100644
index 000000000..e59b612ba
--- /dev/null
+++ b/private/utils/mep/extens/mepparty/sources
@@ -0,0 +1,15 @@
+MAJORCOMP=utils
+MINORCOMP=mep
+
+TARGETNAME=mepparty
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+LINKLIBS=\nt\public\sdk\lib\*\exthdr.lib
+TARGETLIBS=\nt\public\sdk\lib\*\kernel32.lib \nt\public\sdk\lib\*\user32p.lib
+
+INCLUDES=.;..\..\inc;\nt\private\sdktools\ztools\inc;\nt\private\windows\inc
+
+SOURCES= mepparty.c mepparty.rc
+
+C_DEFINES=-D_OS2_20_=0 -DNO_EXT_KEYS -DEXTERNAL= -DEXPORT= -Dpascal= -Dfar= -DNOLANMAN -DNT
+UMTYPE=console
diff --git a/private/utils/mep/extens/mhelp/helphck.c b/private/utils/mep/extens/mhelp/helphck.c
new file mode 100644
index 000000000..a6d8e1382
--- /dev/null
+++ b/private/utils/mep/extens/mhelp/helphck.c
@@ -0,0 +1,40 @@
+#if defined(HELP_HACK)
+
+//
+// This file is used instead of exthdr.c for the hacked version of
+// the help extension that is linked directly to MEP instead of being
+// a DLL.
+//
+// This file defines the 2 extension entry points (ModInfo and EntryPoint)
+// but does not define the editor function wrappers. Since the hacked help
+// extension is linked directly to MEP, having the wrappers would mean
+// re-defining the existing functions, besides, we can call the editor
+// functions directly.
+//
+
+#include <ext.h>
+#include <stddef.h>
+
+#define offsetof(s,m) (size_t)&(((s *)0)->m)
+
+extern struct cmdDesc HelpcmdTable;
+extern struct swiDesc HelpswiTable;
+
+EXTTAB ModInfo =
+ { VERSION,
+ sizeof (struct CallBack),
+ &HelpcmdTable,
+ &HelpswiTable,
+ { NULL }};
+
+
+void
+EntryPoint (
+ ) {
+
+ WhenLoaded( );
+}
+
+
+
+#endif
diff --git a/private/utils/mep/extens/mhelp/makefile b/private/utils/mep/extens/mhelp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/mep/extens/mhelp/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/mep/extens/mhelp/mep.hlp b/private/utils/mep/extens/mhelp/mep.hlp
new file mode 100644
index 000000000..95b9db582
--- /dev/null
+++ b/private/utils/mep/extens/mhelp/mep.hlp
Binary files differ
diff --git a/private/utils/mep/extens/mhelp/mh.h b/private/utils/mep/extens/mhelp/mh.h
new file mode 100644
index 000000000..8e306e63c
--- /dev/null
+++ b/private/utils/mep/extens/mhelp/mh.h
@@ -0,0 +1,309 @@
+/*** mh.h - common include file for the MS Editor help extension
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+* 24-Feb-1989 ln Increase max open help files to 20
+* 13-Jan-1989 ln PWIN->PWND
+* 09-Dec-1988 ln Changes for Dialog help
+* 28-Sep-1988 ln Correct GrabWord return value
+* 13-Sep-1988 Make EVTargs param a pointer
+* [] 17-May-1988 Created
+*
+*************************************************************************/
+
+#ifndef EXTINT
+
+
+#include "ext.h" /* z extension include file */
+#include <stdio.h>
+#include <windows.h>
+
+#if defined (DEBUG )
+ #define ORGDBG DEBUG
+#else
+ #undef ORGDBG
+#endif
+
+#if defined (_INCLUDE_TOOLS_ )
+ #define _FLAGTYPE_DEFINED_
+ #include "tools.h"
+ #if defined (ORGDBG)
+ #define DEBUG ORGDBG
+ #else
+ #undef DEBUG
+ #endif
+#else
+ struct findType {
+ unsigned type; /* type of object being searched */
+ HANDLE dir_handle; /* Dir search handle for FindNext */
+ WIN32_FIND_DATA fbuf; /* Aligned structure for Cruiser and NT */
+ };
+#endif
+
+#endif // EXTINT
+
+#include "help.h" /* help system include file */
+
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+
+#define MAXFILES 20 /* max open helpfiles */
+#define MAXEXT 10 /* max default search extensions*/
+
+#if defined(PWB)
+#define CLISTMAX 20 /* max number of duplicates */
+#endif
+
+#define WIN_MIN 5 /* min number of lines in window*/
+
+//
+// Editor color indexes
+//
+#define C_BOLD USERCOLORMIN
+#define C_ITALICS (1 + C_BOLD)
+#define C_UNDERLINE (1 + C_ITALICS)
+#define C_WARNING (1 + C_UNDERLINE)
+#define C_NORM (1 + C_WARNING)
+
+
+//
+// Info we keep for every helpfile
+//
+typedef struct {
+ nc ncInit; /* initial context */
+ uchar exts[MAXEXT][4]; /* extensions */
+ } helpfile;
+
+
+//
+// Forward Declarations of help extension routines
+//
+void pascal near appTitle (char far *, nc);
+uchar pascal near atrmap (ushort);
+flagType pascal EXTERNAL CloseWin (EVTargs far *);
+flagType pascal near closehelp (char *);
+flagType pascal near errstat (char *, char *);
+flagType pascal near fContextCommand (char *);
+flagType pascal near fDisplayNc (nc, flagType, flagType, flagType);
+flagType pascal near fReadNc (nc);
+flagType pascal near fHelpCmd (char *, flagType, flagType);
+PWND pascal near FindHelpWin (flagType);
+void pascal near GrabWord (void);
+flagType pascal EXTERNAL IdleProc (EVTargs far *);
+flagType pascal EXTERNAL keyevent (EVTargs far *);
+flagType pascal EXTERNAL LooseFocus (EVTargs far *);
+void pascal near mhcwinit (void);
+void pascal near mhevtinit (void);
+nc pascal near ncSearch (uchar far *, uchar far *, nc, flagType, flagType);
+void pascal near opendefault (void);
+void pascal near openhelp (char *, struct findType*, void*);
+PWND pascal near OpenWin (ushort);
+void pascal near PlaceColor (int, COL, COL);
+int pascal near procArgs (ARG far *);
+void pascal near ProcessKeys (void);
+void pascal near procExt(int, char *);
+flagType pascal EXTERNAL prochelpfiles (char *);
+void pascal near stat (char *);
+flagType pascal near wordSepar (int);
+char far * pascal near xrefCopy (char far *, char far *);
+
+
+#if defined(PWB)
+nc pascal near ncChoose (char far *);
+#endif
+
+#ifdef DEBUG
+void pascal near debend (flagType);
+void pascal near debhex (long);
+void pascal near debmsg (char far *);
+/*
+ * assertion support
+ *
+ * assert - assertion macro. We define our own, because if we abort we need
+ * to be able to shut down cleanly (or at least die trying). This
+ * version also saves us some code over the C library one.
+ *
+ * asserte - version of assert that always executes the expression, regardless
+ * of debug state.
+ */
+void pascal near _mhassertexit (char *, char *, int);
+#define assert(exp) { \
+ if (!(exp)) \
+ _mhassertexit (#exp, __FILE__, __LINE__); \
+ }
+#define asserte(exp) assert(exp)
+#else
+#define debend(x)
+#define debhex(x)
+#define debmsg(x)
+#define assert(exp)
+#define asserte(exp) ((exp) != 0)
+#endif
+
+
+//
+// Global Data
+//
+// results of procArgs.
+//
+extern int cArg; /* number of <args> hit */
+extern rn rnArg; /* range of argument */
+extern char *pArgText; /* ptr to any single line text */
+extern char *pArgWord; /* ptr to context-sens word */
+extern PFILE pFileCur; /* file handle of user file */
+//
+// Global State
+//
+extern flagType fInOpen; /* TRUE=> currently opening win */
+extern flagType fInPopUp; /* TRUE=> currently in popup */
+extern flagType fSplit; /* TRUE=> window was split open */
+extern flagType fCreateWindow; /* TRUE=> create window */
+
+extern buffer fnCur; /* Current file being editted */
+extern char *fnExtCur; /* ptr to it's extension */
+
+extern int ifileCur; /* Current index into files */
+extern nc ncCur; /* most recently accessed */
+extern nc ncInitLast; /* ncInit of most recent topic */
+extern nc ncInitLastFile; /* ncInit of most recent, our files*/
+extern nc ncLast; /* most recently displayed topic*/
+extern PFILE pHelp; /* help PFILE */
+extern PWND pWinHelp; /* handle to window w/ help in */
+extern PWND pWinUser; /* User's most recent window */
+extern buffer szLastFound; /* last context string found */
+//
+// Global Misc
+//
+extern buffer buf; /* utility buffer */
+extern helpfile files[MAXFILES]; /* help file structs */
+helpinfo hInfoCur; /* information on the help file */
+extern uchar far *pTopic; /* mem for topic */
+extern fl flIdle; /* last position of idle check */
+//
+// Multiple search list
+//
+extern flagType fList; /* TRUE=> search for and list dups*/
+#if defined(PWB)
+extern nc rgncList[CLISTMAX]; /* list of found nc's */
+extern int cList; /* number of entries */
+#endif
+
+
+extern flagType ExtensionLoaded;
+
+
+//
+// colors
+//
+extern int hlColor; /* normal: white on black */
+extern int blColor; /* bold: high white on black */
+extern int itColor; /* italics: high green on black */
+extern int ulColor; /* underline: high red on black */
+extern int wrColor; /* warning: black on white */
+#if defined(PWB)
+extern uchar far *rgsa; /* pointer to color table */
+#endif
+//
+// Debugging
+//
+#ifdef DEBUG
+extern int delay; /* message delay */
+#endif
+
+//
+// The extension accesses the entry points in the engine thru a table
+// which is initialize by DosGetProcAddr.
+//
+typedef void pascal (*void_F) (void);
+typedef int pascal (*int_F) (void);
+typedef ushort pascal (*ushort_F) (void);
+typedef f pascal (*f_F) (void);
+typedef char * pascal (*pchar_F) (void);
+typedef nc pascal (*nc_F) (void);
+typedef mh pascal (*mh_F) (void);
+
+
+
+#if defined( HELP_HACK )
+
+#else
+
+#define HelpcLines ((int pascal (*)(PB)) (pHelpEntry[P_HelpcLines ]))
+#define HelpClose ((void pascal (*)(nc)) (pHelpEntry[P_HelpClose ]))
+#define HelpCtl ((void pascal (*)(PB, f)) (pHelpEntry[P_HelpCtl ]))
+#define HelpDecomp ((f pascal (*)(PB, PB, nc)) (pHelpEntry[P_HelpDecomp ]))
+#define HelpGetCells ((int pascal (*)(int, int, char *, pb, uchar *)) (pHelpEntry[P_HelpGetCells ]))
+#define HelpGetInfo ((int pascal (*)(nc, helpinfo *, int)) (pHelpEntry[P_HelpGetInfo ]))
+#define HelpGetLine ((ushort pascal (*)(ushort, ushort, uchar *, PB)) (pHelpEntry[P_HelpGetLine ]))
+#define HelpGetLineAttr ((ushort pascal (*)(ushort, int, lineattr *, PB)) (pHelpEntry[P_HelpGetLineAttr]))
+#define HelpHlNext ((f pascal (*)(int, PB, hotspot *)) (pHelpEntry[P_HelpHlNext ]))
+#define HelpLook ((ushort pascal (*)(nc, PB)) (pHelpEntry[P_HelpLook ]))
+#define HelpNc ((nc pascal (*)(char *, nc)) (pHelpEntry[P_HelpNc ]))
+#define HelpNcBack ((nc pascal (*)(void)) (pHelpEntry[P_HelpNcBack ]))
+#define HelpNcCb ((ushort pascal (*)(nc)) (pHelpEntry[P_HelpNcCb ]))
+#define HelpNcCmp ((nc pascal (*)(char *, nc, f (pascal *)(uchar *, uchar *, ushort, f, f) ) (pHelpEntry[P_HelpNcCmp ]))
+#define HelpNcNext ((nc pascal (*)(nc)) (pHelpEntry[P_HelpNcNext ]))
+#define HelpNcPrev ((nc pascal (*)(nc)) (pHelpEntry[P_HelpNcPrev ]))
+#define HelpNcRecord ((void pascal (*)(nc)) (pHelpEntry[P_HelpNcRecord ]))
+#define HelpNcUniq ((nc pascal (*)(nc)) (pHelpEntry[P_HelpNcUniq ]))
+#define HelpOpen ((nc pascal (*)(char *)) (pHelpEntry[P_HelpOpen ]))
+#define HelpShrink ((void pascal (*)(void)) (pHelpEntry[P_HelpShrink ]))
+#define HelpSzContext ((f pascal (*)(uchar *, nc))(pHelpEntry[P_HelpSzContext ]))
+#define HelpXRef ((char * pascal (*)(PB, hotspot *)) (pHelpEntry[P_HelpXRef ]))
+//#define LoadFdb ((f_F) (pHelpEntry[P_LoadFdb ]))
+//#define LoadPortion ((mh_F) (pHelpEntry[P_LoadPortion ]))
+
+#endif // HELP_HACK
+
+
+// Some functions return an error code in the nc structure
+// (yuck!)
+//
+#define ISERROR(x) (((x).mh == 0L) && ((x).cn <= HELPERR_MAX))
+
+
+enum {
+ P_HelpcLines,
+ P_HelpClose,
+ P_HelpCtl,
+ P_HelpDecomp,
+ P_HelpGetCells,
+ P_HelpGetInfo,
+ P_HelpGetLine,
+ P_HelpGetLineAttr,
+ P_HelpHlNext,
+ P_HelpLook,
+ P_HelpNc,
+ P_HelpNcBack,
+ P_HelpNcCb,
+ P_HelpNcCmp,
+ P_HelpNcNext,
+ P_HelpNcPrev,
+ P_HelpNcRecord,
+ P_HelpNcUniq,
+ P_HelpOpen,
+ P_HelpShrink,
+ P_HelpSzContext,
+ P_HelpXRef,
+ P_LoadFdb,
+ P_LoadPortion,
+ LASTENTRYPOINT
+ } ENTRYPOINTS;
+
+#define NUM_ENTRYPOINTS (LASTENTRYPOINT - P_HelpcLines)
+
+//
+// Name of the help engine
+//
+#define HELPDLL_NAME "MSHELP.DLL"
+#define HELPDLL_BASE "mshelp"
+
+typedef nc pascal (*PHF) (void);
+
+HANDLE hModule;
+PHF pHelpEntry[NUM_ENTRYPOINTS];
diff --git a/private/utils/mep/extens/mhelp/mhcore.c b/private/utils/mep/extens/mhelp/mhcore.c
new file mode 100644
index 000000000..5e6ca2f89
--- /dev/null
+++ b/private/utils/mep/extens/mhelp/mhcore.c
@@ -0,0 +1,781 @@
+/*** mhcore - help extension for the Microsoft Editor
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* This file contains the core, top-level entrypoints for the help extension.
+*
+* Revision History (most recent first):
+*
+* 16-Apr-1989 ln Increment ref count for psuedo file.
+* 12-Mar-1989 ln Various modifications for multiple context lookup.
+* 21-Feb-1989 ln Ensure that fPopUp initialized.
+* 14-Feb-1989 ln Enable BOXSTR
+* 26-Jan-1989 ln Correct key assignments
+* 13-Jan-1989 ln PWIN->PWND
+* 01-Dec-1988 ln Cleanup & dialog help
+* 03-Oct-1988 ln Change xref lookup to call HelpNc first (for xref in same
+* file), then SearchHelp (possibly in other files).
+* 28-Sep-1988 ln Changes for CW color and event support
+* 14-Sep-1988 ln Change event arg definition.
+* 12-Sep-1988 mz Made WhenLoaded match declaration
+* 31-Aug-1988 Added additional checks for null pointers
+* 01-Aug-1988 Add editor exit event, and detection of hot-keys which
+* aren't.
+* 28-Jul-1988 Change to "h." conventions.
+* 12-Jul-1988 Reverse SHIFT+F1 and F1.
+* 16-May-1988 Split out from mehelp.c
+* 18-Feb-1988 Made to work, in protect mode
+* 15-Dec-1987 Created, as test harness for the help engine.
+*
+*************************************************************************/
+#include <string.h> /* string functions */
+#include <malloc.h>
+#ifdef DEBUG
+#include <stdlib.h> /* for ltoa def */
+#endif
+
+#include "mh.h" /* help extension include file */
+#include "version.h" /* version file */
+
+
+/*
+ * use double macro level to force rup to be turned into string representation
+ */
+#define VER(x,y,z) VER2(x,y,z)
+#if defined(PWB)
+#define VER2(x,y,z) "Microsoft Editor Help Version v"###x##"."###y##"."###z##" - "##__DATE__" "##__TIME__
+#else
+#define VER2(x,y,z) "Microsoft Editor Help Version v1.02."###z##" - "##__DATE__" "##__TIME__
+#endif
+
+#define EXT_ID VER(rmj,rmm,rup)
+
+
+/*************************************************************************
+**
+** Initialization of Global data in MH.H that needs it.
+*/
+helpfile files[MAXFILES] = {{{0}}}; /* help file structs */
+flagType fInOpen = FALSE; /* TRUE=> currently opening win */
+#if defined(PWB)
+flagType fList = TRUE; /* TRUE=> search for and list dups*/
+#else
+flagType fList = FALSE; /* TRUE=> search for and list dups*/
+#endif
+flagType fPopUp = FALSE; /* current item is popup */
+flagType fCreateWindow = TRUE; /* create window? */
+int ifileCur = 0; /* Current index into files */
+nc ncCur = {0,0}; /* most recently accessed */
+nc ncLast = {0,0}; /* last topic displayed */
+PWND pWinHelp = 0; /* handle to window w/ help in */
+uchar far *pTopic = 0; /* mem for topic */
+uchar far *pTopicC = 0; /* mem for compressed topic */
+fl flIdle = {-1, -1}; /* last position of idle check */
+
+int hlColor = 0x07; /* normal: white on black */
+int blColor = 0x0f; /* bold: high white on black */
+int itColor = 0x0a; /* italics: high green on black */
+int ulColor = 0x0c; /* underline: high red on black */
+int wrColor = 0x70; /* warning: black on white */
+
+#ifdef DEBUG
+int delay = 0; /* message delay */
+#endif
+
+int cArg; /* number of <args> hit */
+flagType fInPopUp; /* TRUE=> currently in popup */
+flagType fSplit; /* TRUE=> window was split open */
+buffer fnCur; /* Current file being editted */
+char * fnExtCur; /* ptr to it's extension */
+buffer buf;
+nc ncInitLast; /* ncInit of most recent topic */
+nc ncInitLastFile; /* ncInit of most recent, our files*/
+char * pArgText; /* ptr to any single line text */
+char * pArgWord; /* ptr to context-sens word */
+PFILE pFileCur; /* file handle of user file */
+rn rnArg; /* range of argument */
+PFILE pHelp; /* help PFILE */
+PWND pWinUser; /* User's most recent window */
+buffer szLastFound; /* last context string found */
+
+flagType ExtensionLoaded = TRUE;
+
+/*
+** assignments
+** table of strings of macro definitions & key assignments
+*/
+char *assignments[] = {
+
+#if !defined(PWB)
+ "mhcontext:=arg mhelp.mhelp",
+ "mhback:=meta mhelp.mhelpnext",
+
+ "mhcontext:F1",
+ "mhelp.mhelp:shift+F1",
+ "mhelp.mhelpnext:ctrl+F1",
+ "mhback:alt+F1",
+ "mhelp.sethelp:alt+s",
+#else
+ "pwbhelpcontext:=arg pwbhelp.pwbhelp",
+ "pwbhelpback:=meta pwbhelp.pwbhelpnext",
+ "pwbhelpindex:=arg \\\"h.index\\\" pwbhelp.pwbhelp",
+ "pwbhelpcontents:=arg \\\"h.contents\\\" pwbhelp.pwbhelp",
+ "pwbhelpagain:=arg pwbhelp.pwbhelpnext",
+
+ "pwbhelpcontext:F1",
+ "pwbhelp.pwbhelp:shift+F1",
+ "pwbhelp.pwbhelpnext:ctrl+F1",
+ "pwbhelpback:alt+F1",
+ "pwbhelp.sethelp:shift+ctrl+s",
+#endif
+ NULL
+ };
+
+#if defined (OS2)
+char * szEntryName[NUM_ENTRYPOINTS] = {
+ "_HelpcLines",
+ "_HelpClose",
+ "_HelpCtl",
+ "_HelpDecomp",
+ "_HelpGetCells",
+ "_HelpGetInfo",
+ "_HelpGetLine",
+ "_HelpGetLineAttr",
+ "_HelpHlNext",
+ "_HelpLook",
+ "_HelpNc",
+ "_HelpNcBack",
+ "_HelpNcCb",
+ "_HelpNcCmp",
+ "_HelpNcNext",
+ "_HelpNcPrev",
+ "_HelpNcRecord",
+ "_HelpNcUniq",
+ "_HelpOpen",
+ "_HelpShrink",
+ "_HelpSzContext",
+ "_HelpXRef",
+ "_LoadFdb",
+ "_LoadPortion",
+ };
+#else
+char * szEntryName[NUM_ENTRYPOINTS] = {
+ "HelpcLines",
+ "HelpClose",
+ "HelpCtl",
+ "HelpDecomp",
+ "HelpGetCells",
+ "HelpGetInfo",
+ "HelpGetLine",
+ "HelpGetLineAttr",
+ "HelpHlNext",
+ "HelpLook",
+ "HelpNc",
+ "HelpNcBack",
+ "HelpNcCb",
+ "HelpNcCmp",
+ "HelpNcNext",
+ "HelpNcPrev",
+ "HelpNcRecord",
+ "HelpNcUniq",
+ "HelpOpen",
+ "HelpShrink",
+ "HelpSzContext",
+ "HelpXRef",
+ "LoadFdb",
+ "LoadPortion",
+ };
+#endif
+
+flagType LoadEngineDll(void);
+flagType pascal EXTERNAL mhelp (unsigned int argData, ARG far *pArg, flagType fMeta );
+flagType pascal EXTERNAL mhelpnext (unsigned int argData, ARG far *pArg, flagType fMeta );
+flagType pascal EXTERNAL sethelp (unsigned int argData, ARG far *pArg, flagType fMeta );
+
+
+
+
+/*** WhenLoaded - Routine called by Z when the extension is loaded
+*
+* This routine is called when Z loads the extension. We identify ourselves
+* and assign the default keystroke.
+*
+* Entry:
+* None
+*
+* Exit:
+* None
+*
+* Exceptions:
+* None
+*
+*************************************************************************/
+void EXTERNAL WhenLoaded () {
+ char **pAsg;
+ static char *szHelpName = "<mhelp>";
+#if !defined(PWB)
+ PSWI fgcolor;
+#endif
+ int ref; // reference count
+
+#if 0
+ //
+ // BUGBUG Delete when proved superfluous.
+ //
+ // Initialize global variables
+ //
+
+ cArg = 0;
+ pArgText = NULL;
+ pArgWord = NULL;
+ pFileCur = NULL;
+ fInOpen = FALSE;
+ fInPopUp = FALSE;
+ fSplit = FALSE;
+ fCreateWindow = FALSE;
+ fnExtCur = NULL;
+ ifileCur = 0;
+ pHelp = NULL;
+ pWinHelp = NULL;
+ pWinUser = NULL;
+ pTopic = NULL;
+ fList = FALSE;
+#endif
+
+ if (!LoadEngineDll() ) {
+ DoMessage( "mhelp: Cannot load help engine" );
+ ExtensionLoaded = FALSE;
+ return;
+ }
+
+ DoMessage (EXT_ID); /* display signon */
+ /*
+ ** Make default key assignments, & create default macros.
+ */
+ strcpy (buf, "arg \"");
+ for (pAsg = assignments; *pAsg; pAsg++) {
+ strcpy (buf+5, *pAsg);
+ strcat (buf, "\" assign");
+ fExecute (buf);
+ }
+ /*
+ ** CW: Init CW specifics & set up the colors that we will use.
+ */
+#if defined(PWB)
+ mhcwinit ();
+
+ hlColor = rgsa[FGCOLOR*2 +1];
+ blColor |= hlColor & 0xf0;
+ itColor |= hlColor & 0xf0;
+ ulColor |= hlColor & 0xf0;
+ wrColor |= (hlColor & 0x70) >> 8;
+
+ fInPopUp = FALSE;
+#else
+ /*
+ * make semi-intellgent guesses on users colors.
+ */
+ if (fgcolor = FindSwitch("fgcolor")) {
+ hlColor = *fgcolor->act.ival;
+ blColor |= hlColor & 0xf0;
+ itColor |= hlColor & 0xf0;
+ ulColor |= hlColor & 0xf0;
+ wrColor |= (hlColor & 0x70) >> 8;
+ }
+#endif
+ /*
+ * create the psuedo file we'll be using for on-line help.
+ */
+ if (pHelp = FileNameToHandle(szHelpName,NULL)) {
+ DelFile (pHelp);
+ } else {
+ pHelp = AddFile (szHelpName);
+ FileRead (szHelpName, pHelp);
+ }
+ //
+ // Increment the file's reference count so it can't be discarded
+ //
+ GetEditorObject (RQ_FILE_REFCNT | 0xff, pHelp, &ref);
+ ref++;
+ SetEditorObject (RQ_FILE_REFCNT | 0xff, pHelp, &ref);
+
+ mhevtinit ();
+
+}
+
+
+/*****************************************************************
+ *
+ * LoadEngineDll
+ *
+ * Loads the help engine and initialize the table of function
+ * pointers to the engine's entry points (pHelpEntry).
+ *
+ * Entry:
+ * none
+ *
+ * Exit:
+ * none
+ *
+ *******************************************************************/
+
+flagType
+LoadEngineDll (
+ void
+ ) {
+
+#if defined (OS2)
+ USHORT rc;
+#endif
+ CHAR szFullName[256];
+ CHAR szErrorName[256];
+ USHORT i;
+
+
+
+ // Initialize pointers to NULL in case something goes wrong.
+
+ for (i=0; i<LASTENTRYPOINT; i++) {
+ pHelpEntry[i] = 0;
+ }
+
+ strcpy(szFullName, HELPDLL_BASE);
+ strcpy(szErrorName, HELPDLL_NAME);
+
+#if defined (OS2)
+ rc = DosLoadModule(szErrorName,
+ 256,
+ szFullName,
+ &hModule);
+
+ for (i=0; i<LASTENTRYPOINT; i++) {
+ rc = DosQueryProcAddr(hModule,
+ 0,
+ szEntryName[i],
+ (PFN *)&(pHelpEntry[i]));
+ }
+#else
+
+
+ hModule = LoadLibrary(szFullName);
+ if ( !hModule ) {
+ return FALSE;
+ }
+ for (i=0; i<LASTENTRYPOINT; i++) {
+ pHelpEntry[i] = (PHF)GetProcAddress(hModule, szEntryName[i]);
+ }
+
+ return TRUE;
+
+#endif // OS2
+
+}
+
+
+
+
+/*** mhelp - editor help function
+*
+* main entry point for editor help functions.
+*
+* NOARG: - Get help on "Default"; change focus to help window.
+* META NOARG - prompt for keystroke and get help on that function; change
+* focus to help window.
+* NULLARG: - Get help on word at cursor position; change focus to help
+* window.
+* STREAMARG: - Get help on text argument; change focus to help window.
+* TEXTARG: - Get help on typed in word; change focus to help window.
+*
+* Entry:
+* Standard Z extension
+*
+* Exit:
+* Returns TRUE on successfull ability to get help on selected topic.
+*
+* Exceptions:
+* None
+*
+*************************************************************************/
+flagType pascal EXTERNAL mhelp (
+ unsigned int argData, /* keystroke invoked with */
+ ARG far *pArg, /* argument data */
+ flagType fMeta /* indicates preceded by meta */
+ ) {
+
+ buffer tbuf; /* buf to put ctxt string into */
+ char *pText = NULL; /* pointer to the lookup text */
+ COL Col; /* Current cursor position */
+ LINE Line;
+ flagType RetVal; /* Return Value */
+
+ UNREFERENCED_PARAMETER( argData );
+
+ if ( !ExtensionLoaded ) {
+ return FALSE;
+ }
+
+ GetTextCursor(&Col, &Line);
+
+ switch (procArgs (pArg)) {
+
+ //
+ // null arg: context sensitive help. First, is we're looking at a help
+ // topic, check for any cross references that apply to the current location.
+ // If none do, then if a word was found when processing args, look that up.
+ //
+ case NULLARG:
+ //
+ // context-sensitive
+ //
+ if ((pFileCur == pHelp) && (pTopic)) {
+ //
+ // hot spot definition
+ //
+ hotspot hsCur;
+
+ hsCur.line = (ushort)(rnArg.flFirst.lin+1);
+ hsCur.col = (ushort)rnArg.flFirst.col+(ushort)1;
+ if (pText = HelpXRef(pTopic, &hsCur)) {
+ debmsg ("Xref=>");
+ debmsg (pText);
+ break;
+ }
+ }
+
+ if (pArgText) {
+ if (*pArgText && (pText = pArgWord)) {
+ debmsg ("Ctxt=>");
+ debmsg (pText);
+ break;
+ }
+ }
+
+ //
+ // for stream and textarg types, the argument, if any, is that entered of
+ // highlighted by the user.
+ //
+ case STREAMARG: /* context sensitive */
+ case TEXTARG: /* user entered context */
+ if (pArgText) {
+ if (*pArgText) {
+ pText = pArgText;
+ }
+ }
+
+ case NOARG: /* default context */
+ //
+ // meta: prompt user for keystroke, get the name of the function assigned
+ // to whatever he presses, and display help on that.
+ //
+ if (fMeta) {
+ stat("Press Keystroke:");
+ pText = ReadCmd()->name;
+ }
+ break;
+ }
+
+ //
+ // If after everything above we still have no text, then use the default
+ // context.
+ //
+ if (pText == NULL) {
+ //
+ // Default context
+ //
+ pText = "h.default";
+ }
+
+ debmsg (" Looking up:");
+ debmsg (pText);
+ debend (TRUE);
+
+ RetVal = fHelpCmd ( xrefCopy(tbuf,pText) /* command */
+ , (flagType)(pArg->argType != NOARG) /* change focus?*/
+ , FALSE /* not pop-up */
+ );
+
+
+
+ return RetVal;
+}
+
+
+
+
+
+/*** mhelpnext - editor help traversal function
+*
+* Handles next and previous help access.
+*
+* mhelpnext - next physical
+* arg mhelpnext - next ocurrance
+* meta mhelpnext - previous viewed
+*
+* Entry:
+* Standard Z extension
+*
+* Exit:
+* Returns TRUE on successfull ability to get help on selected topic.
+*
+* Exceptions:
+* None
+*
+*************************************************************************/
+flagType pascal EXTERNAL mhelpnext (
+ unsigned int argData, /* keystroke invoked with */
+ ARG far *pArg, /* argument data */
+ flagType fMeta /* indicates preceded by meta */
+ ) {
+
+
+ UNREFERENCED_PARAMETER( argData );
+
+ //
+ // Ensure that help files are open, and then process the arguments and a few
+ // other init type things
+ //
+ procArgs (pArg);
+
+ //
+ // if there was no help context to start with, then we can't go either way,
+ // so inform the user
+ //
+ if (!ncLast.mh && !ncLast.cn) {
+ return errstat("No previously viewed help", NULL);
+ }
+
+ if (fMeta) {
+ //
+ // meta: attempt to get the most recently viewed help context. If a help
+ // window is currently up, then if the one we just found is the same as that
+ // in the window, go back once more. If no back trace, then say so.
+ //
+ ncCur = HelpNcBack();
+ if (FindHelpWin(FALSE)) {
+ if ((ncCur.mh == ncLast.mh) &&
+ (ncCur.cn == ncLast.cn)) {
+ ncCur = HelpNcBack();
+ }
+ }
+
+ if ((ncCur.mh == 0) && (ncCur.cn == 0)) {
+ return errstat ("No more backtrace", NULL);
+ }
+
+ } else if (pArg->arg.nullarg.cArg) {
+ //
+ // not meta, and args. Try to look again
+ //
+ ncCur = ncSearch ( szLastFound /* search for last string again */
+ , NULL /* no extension restriction */
+ , ncInitLastFile /* file where we found it last */
+ , TRUE /* skip all until then */
+ , FALSE /* don;t look at all files */
+ );
+ } else {
+ //
+ // not meta, no args, Just get the next help context.
+ //
+ ncCur = HelpNcNext(ncLast);
+ }
+
+ if (!ncCur.mh && !ncCur.cn) {
+ return FALSE;
+ }
+
+ return fDisplayNc ( ncCur /* nc to display */
+ , TRUE /* add to backtrace list */
+ , TRUE /* keep focus in current win */
+ , FALSE); /* Not as a pop-up, though */
+
+}
+
+
+
+
+
+/*** sethelp - editor help file list manipulation
+*
+* Function which allows the user to add to, delete from or examine the
+* list of help files used by the extension
+*
+* Input:
+* Standard editing function.
+*
+* Output:
+* Returns TRUE if file succefully added or deleted, or the list displayed.
+*
+*************************************************************************/
+flagType pascal EXTERNAL sethelp (
+ unsigned int argData, /* keystroke invoked with */
+ ARG far *pArg, /* argument data */
+ flagType fMeta /* indicates preceded by meta */
+) {
+
+ int i = 0;
+ int j;
+ int iHelpNew; /* file table index */
+ nc ncNext; /* nc for next file */
+ char *pT; /* temp pointer */
+ EVTargs dummy;
+ int fFile; /* file's flags */
+
+
+ UNREFERENCED_PARAMETER( argData );
+
+ procArgs(pArg);
+
+ if ( !pArgText ) {
+ return FALSE;
+ }
+
+
+ //
+ // The special request to <sethelp> to "?" displays a list of all open
+ // help files.
+ //
+ // We do this by first clearing the help psudeo file and ensuring that the
+ // topic text is also gone. Then for each file we output the help engine's
+ // physical filename, along with any extensions that the user associated
+ // with it. We also walk the list of appended files, and print the original
+ // filename and helpfile title for each.
+ //
+ // We walk the list in the same way that it is searched, so that the
+ // displayed list also reflects the default search order.
+ //
+ if ( pArgText && (*(ushort UNALIGNED *)pArgText == (ushort)'?') ) {
+
+ fInOpen = TRUE;
+ CloseWin (&dummy);
+ fInOpen = FALSE;
+
+ OpenWin (0);
+
+ //
+ // Ensure that the help pseudo file is marked readonly, and clean
+ //
+ GetEditorObject (RQ_FILE_FLAGS | 0xff, pHelp, &fFile);
+ fFile |= READONLY;
+ fFile &= ~DIRTY;
+ SetEditorObject (RQ_FILE_FLAGS | 0xff, pHelp, &fFile);
+
+ SetEditorObject (RQ_WIN_CUR | 0xff, pWinHelp, 0);
+
+ // asserte(pFileToTop (pHelp)); /* display psuedo file */
+ MoveCur((COL)0,(LINE)0); /* and go to upper left */
+
+ DelFile (pHelp);
+ if (pTopic) {
+ free(pTopic);
+ pTopic = NULL;
+ }
+ iHelpNew = ifileCur;
+
+ do {
+
+ ncNext = files[iHelpNew].ncInit;
+
+ while (ncNext.mh && ncNext.cn && !HelpGetInfo (ncNext, &hInfoCur, sizeof(hInfoCur))) {
+
+ if ((ncNext.mh == files[iHelpNew].ncInit.mh) &&
+ (ncNext.cn == files[iHelpNew].ncInit.cn)) {
+
+ memset (buf, ' ', 20);
+ buf[20] = 0;
+ strncpy (buf, FNAME(&hInfoCur), strlen(FNAME(&hInfoCur)));
+ pT = &buf[20];
+
+ for (j=0; j<MAXEXT; j++) {
+ if (files[iHelpNew].exts[j][0]) {
+ buf[19] = '>';
+ strcat (pT," .");
+ strcat (pT,files[iHelpNew].exts[j]);
+ }
+ }
+
+ PutLine((LINE)i++,buf,pHelp);
+ }
+
+ memset (buf, ' ', 15);
+ strncpy (&buf[2], HFNAME(&hInfoCur), strlen(HFNAME(&hInfoCur)));
+ strcpy (&buf[15], ": ");
+ appTitle (buf, ncNext);
+ PutLine((LINE)i++,buf,pHelp);
+ ncNext = NCLINK(&hInfoCur);
+ }
+
+ iHelpNew += iHelpNew ? -1 : MAXFILES-1;
+
+ } while (iHelpNew != ifileCur);
+
+#ifdef DEBUG
+ PutLine((LINE)i++," ",pHelp);
+ strcpy(buf,"ncLast: 0x");
+ strcat(buf,_ltoa(ncLast,&buf[128],16));
+ PutLine((LINE)i++,buf,pHelp);
+ strcpy(buf,"ncCur: 0x");
+ strcat(buf,_ltoa(ncCur,&buf[128],16));
+ PutLine((LINE)i++,buf,pHelp);
+#endif
+
+ DoMessage (NULL);
+
+ return TRUE;
+ }
+
+
+ //
+ // Not a special request, just the user adding or removing a file from the
+ // list of files to search.
+ //
+ if (fMeta)
+ return closehelp(pArgText);
+ {
+ flagType Status;
+ openhelp(pArgText, NULL, &Status);
+ return Status;
+ }
+
+}
+
+
+
+
+
+/*************************************************************************
+**
+** Z communication tables
+**
+** switch communication table to Z
+*/
+struct swiDesc swiTable[] = {
+ {"helpfiles", prochelpfiles, SWI_SPECIAL },
+ {"helpwindow", toPIF(fCreateWindow), SWI_BOOLEAN },
+#if defined(PWB)
+ {"helplist", toPIF(fList), SWI_BOOLEAN },
+#endif
+ {"helpcolor", toPIF(hlColor), SWI_NUMERIC | RADIX16 },
+ {"helpboldcolor", toPIF(blColor), SWI_NUMERIC | RADIX16 },
+ {"helpitalcolor", toPIF(itColor), SWI_NUMERIC | RADIX16 },
+ {"helpundrcolor", toPIF(ulColor), SWI_NUMERIC | RADIX16 },
+ {"helpwarncolor", toPIF(wrColor), SWI_NUMERIC | RADIX16 },
+#ifdef DEBUG
+ {"helpdelay", toPIF(delay), SWI_NUMERIC | RADIX10 },
+#endif
+ {0, 0, 0}
+ };
+
+/*
+** command communication table to Z
+*/
+struct cmdDesc cmdTable[] = {
+#if defined(PWB)
+ { "pwbhelpnext", mhelpnext, 0, NOARG | NULLARG },
+ { "pwbhelp", mhelp, 0, NOARG | NULLARG | STREAMARG | TEXTARG | BOXSTR},
+#else
+ { "mhelpnext", (funcCmd)mhelpnext, 0, NOARG | NULLARG },
+ { "mhelp", (funcCmd)mhelp, 0, NOARG | NULLARG | STREAMARG | TEXTARG | BOXSTR},
+#endif
+ { "sethelp", (funcCmd)sethelp, 0, NULLARG | STREAMARG | TEXTARG | BOXSTR},
+ {0, 0, 0}
+ };
diff --git a/private/utils/mep/extens/mhelp/mhdisp.c b/private/utils/mep/extens/mhelp/mhdisp.c
new file mode 100644
index 000000000..32cd15804
--- /dev/null
+++ b/private/utils/mep/extens/mhelp/mhdisp.c
@@ -0,0 +1,434 @@
+/*** mhdisp - help extension display code
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* This module contains routines dealing with the display of help information.
+*
+* Revision History (most recent first):
+*
+* 12-Mar-1989 ln Moved some to mhlook
+* 15-Feb-1989 ln Restore to correct current window on close of a
+* split window.
+* 26-Jan-1989 ln Turn help in dialog back on. (M200 #295)
+* 13-Jan-1989 ln PWIN->PWND
+* 09-Jan-1989 ln Popup boxes only in CW
+* 01-Dec-1988 ln Cleanup & dialog help
+* 28-Sep-1988 ln Update for CW
+* 22-Sep-1988 ln MessageBox ==> DoMessageBox
+* 02-Sep-1988 ln Make all data inited. Remove GP fault in debug vers.
+* 05-Aug-1988 ln Rewrote process keys.
+* [] 16-May-1988 LN Split off of mehelp.c
+*
+*************************************************************************/
+#include <stdlib.h> /* min macro */
+#include <string.h> /* string functions */
+
+#include "mh.h" /* help extension include file */
+
+/*** fDisplayNc - Display topic text for the context number passed in
+*
+* Input:
+* ncCur = context number
+* frecord, = TRUE => record for backtrace
+* fStay = TRUE => keep focus in current window, else move focus to
+* newly opened help window.
+* fWantPopUp = TRUE => display as popup window. (Ignored in non-CW)
+*
+* Exit:
+* returns TRUE on success.
+*
+*************************************************************************/
+flagType pascal near fDisplayNc (
+ nc ncCur,
+ flagType frecord,
+ flagType fStay,
+ flagType fWantPopUp
+) {
+ ushort cLines = 0; /* # of lines in window */
+ EVTargs dummy;
+ int fFile; /* file's flags */
+ hotspot hsCur; /* hot spot definition */
+ LINE iHelpLine = 0; /* next help line to read/disp */
+ PSWI pHeight; /* ptr to heigth switch */
+ winContents wc; /* description of win contents */
+ BOOL fDisp = FALSE; /* True when Displayed */
+
+
+ UNREFERENCED_PARAMETER( fWantPopUp );
+
+ if (fReadNc(ncCur)) {
+ debmsg ("Displaying nc:[");
+ debhex (ncCur.cn);
+ debmsg ("]");
+ /*
+ ** Set up some data....
+ **
+ ** - Invalidate the most recent cursor position for highlighting
+ ** - Get pointer to editor's height switch
+ ** - Set up current colors
+ */
+ flIdle.lin = -1;
+ pHeight = FindSwitch ("height");
+#if defined(PWB)
+ rgsa[C_NORM*2 + 1] = (uchar)hlColor;
+ rgsa[C_BOLD*2 + 1] = (uchar)blColor;
+ rgsa[C_ITALICS*2 + 1] = (uchar)itColor;
+ rgsa[C_UNDERLINE*2 + 1] = (uchar)ulColor;
+ rgsa[C_WARNING*2 + 1] = (uchar)wrColor;
+#else
+ SetEditorObject (RQ_COLOR | C_NORM, 0, &hlColor);
+ SetEditorObject (RQ_COLOR | C_BOLD, 0, &blColor);
+ SetEditorObject (RQ_COLOR | C_ITALICS, 0, &itColor);
+ SetEditorObject (RQ_COLOR | C_UNDERLINE,0, &ulColor);
+ SetEditorObject (RQ_COLOR | C_WARNING, 0, &wrColor);
+ /*
+ ** If help window was found, close it, so that we can create it with the
+ ** correct new size.
+ */
+ fInOpen = TRUE;
+ CloseWin (&dummy);
+ fInOpen = FALSE;
+#endif
+ /*
+ ** Set the ncLast, the most recently viewed context, to what we are about to
+ ** bring up. If recording, save it in the backtrace as well.
+ */
+ ncLast = ncCur;
+ if (frecord) {
+ HelpNcRecord(ncLast);
+ }
+ if (!HelpGetInfo (ncLast, &hInfoCur, sizeof(hInfoCur))) {
+ ncInitLast = NCINIT(&hInfoCur);
+ } else {
+ ncInitLast.mh = (mh)0;
+ ncInitLast.cn = 0;
+ }
+ /*
+ ** Read through the text, looking for any control lines that we want to
+ ** respond to. Stop as soon as we discover a non-control line. We currently
+ ** respond to:
+ **
+ ** :lnn where nn is the suggested size of the window.
+ */
+ ((topichdr *)pTopic)->linChar = 0xff;
+ while (HelpGetLine((ushort)++iHelpLine, BUFLEN, buf, pTopic)) {
+ if (buf[0] != ':') {
+ break;
+ }
+ switch (buf[1]) {
+ case 'l':
+ cLines = (USHORT)(atoi (&buf[2]));
+ default:
+ break;
+ }
+ }
+ ((topichdr *)pTopic)->linChar = ((topichdr *)pTopic)->appChar;
+ /*
+ ** Open the window on the help psuedo file. Read the lines one at a time
+ ** from the help text, update any embedded key assignements, and put the
+ ** line and color into the pseudo file.
+ */
+#if defined(PWB)
+ if (!(fInPopUp || fWantPopUp))
+#endif
+ OpenWin (cLines);
+#if defined(PWB)
+ else
+ DelFile (pHelp);
+#endif
+ debend (TRUE);
+ iHelpLine = 0;
+ while (HelpGetLine((ushort)iHelpLine+(ushort)1, (ushort)BUFLEN, (uchar far *)buf, pTopic)) {
+ if ( buf[0] == ':' ) {
+
+ switch (buf[1]) {
+
+ case 'x':
+ return FALSE;
+
+ case 'c':
+ case 'y':
+ case 'f':
+ case 'z':
+ case 'm':
+ case 'i':
+ case 'p':
+ case 'e':
+ case 'g':
+ case 'r':
+ case 'n':
+ iHelpLine++;
+ continue;
+
+ default:
+ break;
+
+ }
+ }
+
+ ProcessKeys();
+ PutLine(iHelpLine,buf,pHelp);
+ PlaceColor ((int)iHelpLine++, 0, 0);
+ /*
+ ** This is a speed hack to display help as soon as we get a screen full.
+ ** "Looks" faster.
+ */
+ if (pHeight) {
+ if (iHelpLine == *(pHeight->act.ival)) {
+ Display ();
+ fDisp = TRUE;
+ }
+ }
+ }
+ if (!fDisp) {
+ Display();
+ fDisp = TRUE;
+ }
+
+ /*
+ ** Ensure that the help psuedo file is marked readonly, and clean
+ */
+ GetEditorObject (RQ_FILE_FLAGS | 0xff, pHelp, &fFile);
+ fFile |= READONLY;
+ fFile &= ~DIRTY;
+ SetEditorObject (RQ_FILE_FLAGS | 0xff, pHelp, &fFile);
+ /*
+ ** Search for the first hotspot in the text which lies within the current
+ ** window, and place the cursor there.
+ */
+ GetEditorObject (RQ_WIN_CONTENTS, 0, &wc);
+ hsCur.line = 1;
+ hsCur.col = 1;
+ MoveCur((COL)0,(LINE)0);
+ if (HelpHlNext(0,pTopic,&hsCur)) {
+ if (hsCur.line <= wc.arcWin.ayBottom - wc.arcWin.ayTop) {
+ MoveCur((COL)hsCur.col-1,(LINE)hsCur.line-1);
+ }
+ }
+ /*
+ ** If we're supposed to stay in the previous window, then change currancy
+ ** to there. Clear the status line, and we're done!
+ */
+#if defined(PWB)
+ if (fWantPopUp) {
+ if (!fInPopUp) {
+ fInPopUp = TRUE;
+ PopUpBox (pHelp,"Help");
+ fInPopUp = FALSE;
+ }
+ }
+ else
+#endif
+ SetEditorObject (RQ_WIN_CUR | 0xff, fStay ? pWinUser : pWinHelp, 0);
+ DoMessage (NULL);
+ Display();
+ return TRUE;
+ }
+
+ return errstat("Error Displaying Help",NULL);
+
+}
+
+/*** fReadNc - Read and decompress help topic
+*
+* Reads and decompresses the help topic associated with the given nc.
+* Allocaets memory as appropriate to read it in.
+*
+* Input:
+* ncCur - nc of help topic to read in
+*
+* Output:
+* Returns TRUE on successfull read in
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+flagType pascal near fReadNc (
+nc ncCur
+) {
+int cbExp; /* size of compressed topic */
+flagType fRet = FALSE; /* return value */
+uchar far *pTopicC; /* mem for compressed topic */
+
+if (ncCur.mh && ncCur.cn) {
+/*
+** Determine the memory required for the compressed topic text, and allocate
+** that. Read in the compressed topic, and get the uncompressed size.
+** Allocate that memory, and decompress. Once decompressed, discard the
+** compressed topic.
+*/
+ if (cbExp = HelpNcCb(ncCur)) {
+ debmsg (" sized,");
+ if (pTopicC = malloc((long)cbExp)) {
+ if (cbExp = HelpLook(ncCur,pTopicC)) {
+ debmsg ("read,");
+ if (pTopic) {
+ free (pTopic);
+ pTopic = NULL;
+ }
+ if (pTopic = malloc((long)cbExp)) {
+ if (!HelpDecomp(pTopicC,pTopic,ncCur)) {
+ fRet = TRUE;
+ debmsg ("decomped");
+ }
+ }
+ }
+ free(pTopicC);
+ pTopicC = NULL;
+ }
+ }
+ }
+return fRet;
+
+/* end fReadNc */}
+
+/*** PlaceColor - Put color into help screen line
+*
+* Purpose:
+*
+* Input:
+* i = line number to be worked on
+* xStart,xEnd = Column range to be highlighted (one based, inclusive)
+*
+* Globals:
+* pTopic = Pointer to topic buffer
+*
+* Output:
+* Returns nothing
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+void pascal near PlaceColor (
+ int line, /* line number to do */
+ COL xStart, /* starting highlight column */
+ COL xEnd /* ending highlight column */
+) {
+
+ buffer bufL; /* local buffer */
+ ushort cbExp; /* size of color info */
+ COL column = 1;
+ struct lineAttr *pbT; /* byte lineattr pointer */
+ lineattr *pwT; /* word lineattr pointer */
+
+ /*
+ ** Convert our internal color indecies into editor color indecies.
+ */
+ cbExp = HelpGetLineAttr ((ushort)line+(ushort)1, (ushort)BUFLEN, (lineattr far *)buf, pTopic) / sizeof(lineattr);
+ pbT = (struct lineAttr *)bufL;
+ pwT = (lineattr *)buf;
+ while (cbExp-- > 0) {
+ pbT->attr = atrmap (pwT->attr);
+ column += (pbT->len = (uchar)pwT->cb);
+ pbT++;
+ pwT++;
+ }
+
+ PutColor ((LINE)line, (struct lineAttr far *)bufL, pHelp);
+ if (xEnd != xStart) {
+ SetColor (pHelp, line, xStart-1, xEnd-xStart+1, C_WARNING);
+ }
+}
+
+/*** atrmap - map attributes in file to editor attributes
+*
+* Purpose:
+*
+* Input:
+* fileAtr = attribute word from the help file
+*
+* Output:
+* Returns attribute byte for editor.
+*
+*************************************************************************/
+uchar pascal near atrmap (
+ushort fileAtr
+) {
+if (fileAtr == 0x7)
+ return C_WARNING;
+else if (fileAtr & A_BOLD)
+ return C_BOLD;
+else if (fileAtr & A_ITALICS)
+ return C_ITALICS;
+else if (fileAtr & A_UNDERLINE)
+ return C_UNDERLINE;
+else
+ return C_NORM;
+/* end atrmap */}
+
+/*** ProcessKeys - replace embedded function names with current keys.
+*
+* Replaces ocurrances of <<function name>> in the text with the most recent
+* keystroke currently assigned to that function. ("<<" and ">>" here are
+* actually single graphic characters 174 and 175).
+*
+* If there is a space preceding the trailing ">>", the field is space filled
+* to that width. Else, the length of the keystroke text is used.
+*
+* Input:
+* None.
+*
+* Global:
+* Operates on buf.
+*
+* Output:
+* Returns nothing. Updates buf.
+*
+*************************************************************************/
+void pascal near ProcessKeys() {
+char *pKeyBuf;
+char *pKeyCur;
+char *pKeyEnd; /* ptr to end of magic field */
+char *pKeyFill; /* position to fill to */
+char *pKeyStart; /* ptr to start of magic field */
+buffer keybuf;
+
+pKeyStart = &buf[0];
+/*
+** look for magic character to signal replacement. If found, begin replacement
+** process.
+*/
+while (pKeyStart = strchr (pKeyStart,174)) {
+/*
+** Search for the terminating magic character. If found, examine the character
+** immediate prior to see if it was a space, and record the "fill to this
+** position" place. Copy the remainder of the line to a holding buffer.
+*/
+ if (pKeyFill = pKeyEnd = strchr(pKeyStart,175)) {
+ if (*(pKeyEnd-1) != ' ')
+ pKeyFill = 0;
+ strcpy (keybuf, pKeyEnd+1);
+ do
+ *pKeyEnd-- = 0;
+ while ((*pKeyEnd == ' ') && (pKeyEnd > pKeyStart));
+ }
+/*
+** replace the function name in the line with a list of the keys assigned to
+** it. Search the string placed there for the last keystroke in the space
+** seperated "and" list (which represents the most recent assignment), and
+** then copy that down to the begining of the string.
+*/
+ NameToKeys(pKeyStart+1,pKeyStart);
+ pKeyCur = pKeyStart-1;
+ do pKeyBuf = pKeyCur+1;
+ while (pKeyCur = strchr (pKeyBuf,' '));
+ if (pKeyBuf != pKeyStart)
+ strcpy (pKeyStart, pKeyBuf);
+ pKeyStart = strchr(pKeyStart,0);
+/*
+** If we are requested to space fill out the field, and our current position
+** is prior to the fill position, then add spaces. Finally, append the
+** remainder of the line back on.
+*/
+ if (pKeyFill) {
+ while (pKeyStart <= pKeyFill)
+ *pKeyStart++ = ' ';
+ pKeyStart = pKeyFill + 1;
+ }
+ strcpy (pKeyStart, keybuf);
+ }
+/* End ProcessKeys */}
diff --git a/private/utils/mep/extens/mhelp/mhelp.def b/private/utils/mep/extens/mhelp/mhelp.def
new file mode 100644
index 000000000..b59faec1e
--- /dev/null
+++ b/private/utils/mep/extens/mhelp/mhelp.def
@@ -0,0 +1,7 @@
+LIBRARY MHELP
+
+DESCRIPTION 'MEP extension'
+
+EXPORTS
+ EntryPoint
+ ModInfo
diff --git a/private/utils/mep/extens/mhelp/mhelp.rc b/private/utils/mep/extens/mhelp/mhelp.rc
new file mode 100644
index 000000000..6e63c9f9e
--- /dev/null
+++ b/private/utils/mep/extens/mhelp/mhelp.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Mep Help Utility Library"
+#define VER_INTERNALNAME_STR "mhelp"
+#define VER_ORIGINALNAME_STR "MHELP.DLL"
+
+#include "common.ver"
diff --git a/private/utils/mep/extens/mhelp/mhevt.c b/private/utils/mep/extens/mhelp/mhevt.c
new file mode 100644
index 000000000..4188e00fe
--- /dev/null
+++ b/private/utils/mep/extens/mhelp/mhevt.c
@@ -0,0 +1,366 @@
+/*** mhevt - help extension event handling code
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* This file contains the code called by the edit in response to events
+*
+* Revision History (most recent first):
+*
+* 30-Mar-1989 ln Fudge with keyevent to react corectly to what we want.
+* 23-Mar-1989 ln Created. Extracted from mhcore & others
+*
+*************************************************************************/
+#include <string.h> /* string functions */
+#include <malloc.h>
+#include "mh.h" /* help extension include file */
+
+/*************************************************************************
+*
+* static data
+*/
+static EVT EVThlp = { /* keyboard event definition */
+ EVT_KEY,
+ keyevent,
+ 0,
+ 0,
+ 0 /* ALL keys */
+ };
+static EVT EVTcan = { /* cancel event definition */
+ EVT_CANCEL,
+ CloseWin,
+ 0,
+ 0,
+ 0
+ };
+static EVT EVTxit = { /* exit event definition */
+ EVT_EXIT,
+ CloseWin,
+ 0,
+ 0,
+ 0
+ };
+static EVT EVTidl = { /* idle event definition */
+ EVT_IDLE,
+ IdleProc,
+ 0,
+ 0,
+ 0
+ };
+static EVT EVTfcs = { /* focus loss event definition */
+ EVT_LOSEFOCUS,
+ LooseFocus,
+ 0,
+ 0,
+ 0
+ };
+
+/*** mhevtinit - init editor event handling
+*
+* Input:
+* none
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void pascal near mhevtinit (void) {
+
+EVTidl.focus = EVThlp.focus = pHelp;
+RegisterEvent(&EVThlp); /* register help key event */
+RegisterEvent(&EVTcan); /* register help cancel event */
+RegisterEvent(&EVTidl); /* register help idle event */
+RegisterEvent(&EVTxit); /* register help exit event */
+RegisterEvent(&EVTfcs); /* register help focus event */
+
+/* end mhevtinit */}
+
+/*** keyevent - called by editor whenever a key is pressed in a help window
+*
+* When called we know that pHelp is being displayed, and was current.
+* Process the key pressed by the user. Keys handled:
+*
+* TAB - move forward to next hot spot
+* BACK-TAB - move backward to next hot spot
+* lc Alpha - move forward to next hot spot whose text begins with alpha
+* uc Alpha - move backward to next hot spot whose text begins with alpha
+* Enter - execute cross reference, if we're on one
+* Space - execute cross reference, if we're on one
+*
+* Input:
+* parg = pointer to event arguments
+*
+* Output:
+* If the key pressed is one we recognize return TRUE, else we return FALSE
+* and let the editor process the key.
+*
+*************************************************************************/
+flagType pascal EXTERNAL keyevent (
+ EVTargs far *parg
+ ) {
+
+ uchar c; /* character hit */
+ int fDir; /* direction flag */
+ f fWrapped = FALSE; /* wrapped arounf flag */
+ hotspot hsCur; /* hot spot definition */
+ char *pText = NULL;
+ COL x;
+ LINE y;
+
+ c = parg->arg.key.KeyData.Ascii;
+
+ //
+ // if there is no topic, no sense doing anything
+ //
+ if (pTopic == 0) {
+ if ( ((c <= 'z') && (c >= 'a')) ||
+ ((c <= 'Z') && (c >= 'A')) ||
+ (c == 0x09) ) {
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ //
+ // start by getting this info, in case it is used later.
+ //
+ GetTextCursor(&x, &y);
+ hsCur.line = (ushort)++y;
+ hsCur.col = (ushort)++x;
+
+ //
+ // If he hit return or space, look for a cross reference at the current loc.
+ // If there is one, process it.
+ //
+ if ((c == 0x0d) || (c == ' ')) {
+ if (pText = HelpXRef (pTopic, &hsCur)) {
+#ifdef DEBUG
+ debmsg ("Xref: ");
+ if (*pText) {
+ debmsg (pText);
+ } else {
+ debmsg ("@Local 0x");
+ debhex ((long)*(ushort far *)(pText+1));
+ }
+ debend (TRUE);
+#endif
+ if (!fHelpCmd ( pText /* command/help to look up */
+ , FALSE /* change focus to help window */
+ , FALSE /* not pop-up */
+ )) {
+ errstat ("Cannot Process Cross Reference", NULL);
+ }
+ }
+ Display(); // Show CUrsor Position
+ return TRUE;
+ }
+
+ if ( parg->arg.key.KeyData.Flags & (FLAG_CTRL | FLAG_ALT) ) {
+ return FALSE;
+ }
+
+ //
+ // Maneuvering keys:
+ // TAB: Move to next hot spot
+ // SHIFT+TAB Move to previous hot spot
+ // lcase alpha Move to next hot spot beginning with alpha
+ // ucase alpha Move to previous hot spot beginning with alpha
+ //
+ if ((c <= 'z') && (c >= 'a')) {
+ fDir = (int)c-0x20;
+ } else if ((c <= 'Z') && (c >= 'A')) {
+ fDir = -(int)c;
+ } else if (c == 0x09) {
+ if (parg->arg.key.KeyData.Flags & FLAG_SHIFT) {
+ fDir = -1;
+ } else {
+ fDir = 0;
+ }
+ } else {
+ return FALSE;
+ }
+
+ //
+ // loop looking for the next cross reference that either follows or precedes
+ // the current cursor position. Ensure that we do NOT end up on the same xref
+ // we are currently on. If we've reached the end/beginning of the topic, wrap
+ // around to the begining/end. Ensure we do this only ONCE, in case there are
+ // NO cross references at all.
+ //
+ while (TRUE) {
+
+ if (HelpHlNext(fDir,pTopic,&hsCur)) {
+
+ MoveCur((COL)hsCur.col-1,(LINE)hsCur.line-1);
+ IdleProc(parg);
+ Display();
+
+ if (fWrapped || ((LINE)hsCur.line != y)) {
+ break;
+ }
+
+ if ((fDir < 0) && ((COL)hsCur.ecol >= x)) {
+ hsCur.col--;
+ } else if ((fDir >= 0) && ((COL)hsCur.col <= x)) {
+ hsCur.col = (ushort)(hsCur.ecol+1);
+ } else {
+ break;
+ }
+ } else {
+ if (fWrapped++) {
+ break;
+ }
+ hsCur.col = 1;
+ hsCur.line = (fDir < 0) ? (ushort)FileLength(pHelp) : (ushort)1;
+ }
+ }
+
+ return TRUE;
+}
+
+/*** IdleProc - Idle event processor
+*
+* Purpose:
+*
+* Input:
+* Editor event args passed, but ignored.
+*
+* Output:
+* Returns .....
+*
+*************************************************************************/
+flagType pascal EXTERNAL IdleProc (
+ EVTargs far *arg
+ ) {
+
+ hotspot hsCur; /* hot spot definition */
+ fl flCur; /* current cursor location */
+
+ UNREFERENCED_PARAMETER( arg );
+
+ /*
+ ** if there is no topic, no sense doing anything
+ */
+ if (pTopic) {
+ /*
+ ** If the cursor position has changed since the last idle call...
+ */
+ GetTextCursor(&flCur.col, &flCur.lin);
+ if ((flCur.col != flIdle.col) || (flCur.lin != flIdle.lin)) {
+ /*
+ ** restore the color to the previous line, and check for a cross reference at
+ ** the current position. If there is one, change it's colors.
+ */
+ if (flIdle.lin != -1)
+ PlaceColor (flIdle.lin, 0, 0);
+
+ hsCur.line = (ushort)(flCur.lin+1);
+ hsCur.col = (ushort)(flCur.col+1);
+
+ if (HelpXRef (pTopic, &hsCur))
+ SetColor (pHelp, flCur.lin, hsCur.col-1, hsCur.ecol-hsCur.col+1, C_WARNING);
+
+ flIdle = flCur;
+ }
+ }
+ Display();
+ return FALSE;
+}
+
+/*** LooseFocus - called when help file looses focus
+*
+* This is called each time a file looses focus. If the help file is no
+* longer displayed, we clear it from memory and deallocate any associated
+* help text.
+*
+* Input:
+* e - ignored
+*
+* Output:
+* Returns TRUE.
+*
+*************************************************************************/
+flagType pascal EXTERNAL LooseFocus (
+EVTargs far *e
+) {
+
+UNREFERENCED_PARAMETER( e );
+
+if (!fInPopUp && pTopic && !fInOpen) {
+/*
+** Look for a window that has the help file in it. If found, we're done.
+*/
+ if (FindHelpWin (FALSE))
+ return FALSE;
+/*
+** There is no help window currently displayed, deallocate any topic text
+** we have lying around.
+*/
+ if (pTopic) {
+ free (pTopic);
+ pTopic = NULL;
+ }
+/*
+** If there is a help pFile, discard it's contents
+*/
+ if (pHelp)
+ DelFile (pHelp);
+ }
+return TRUE;
+/* end LooseFocus */}
+
+/*** CloseWin - Close a window on the help file
+*
+* Closes the help window, if it is up. Maintains window currancy after the
+* close. Relies on an eventual call to LooseFocus (above) to deallocate the
+* topic text, if it is there, and discard the help pFile.
+*
+* Can be called by editor event processor, in response to CANCEL or EXIT
+* event.
+*
+* Input:
+* dummy - EVTargs ignored.
+*
+* Output:
+* Returns TRUE.
+*
+*************************************************************************/
+flagType pascal EXTERNAL CloseWin (
+ EVTargs far *dummy
+ ) {
+
+
+#if defined(PWB)
+ /*
+ ** Look for the window that has the help file in it. If found, close it.
+ */
+ if (pWinHelp) {
+ if (!CloseWnd (pWinHelp)) {
+ return TRUE;
+ }
+
+#else
+
+ PWND pWinCur; /* window on entry */
+
+ UNREFERENCED_PARAMETER( dummy );
+ /*
+ ** Look for the window that has the help file in it. If found, close it.
+ */
+ if (pWinHelp) {
+ SetEditorObject (RQ_WIN_CUR | 0xff, pWinHelp, 0);
+ if (fSplit) {
+ fExecute ("meta window");
+ } else {
+ fExecute ("setfile");
+ }
+ GetEditorObject (RQ_WIN_HANDLE, 0, &pWinCur);
+
+#endif
+
+ pWinHelp = 0;
+ if (pWinUser) {
+ SetEditorObject (RQ_WIN_CUR | 0xff, pWinUser, 0);
+ }
+ }
+ return TRUE;
+}
diff --git a/private/utils/mep/extens/mhelp/mhfile.c b/private/utils/mep/extens/mhelp/mhfile.c
new file mode 100644
index 000000000..0ece1c03b
--- /dev/null
+++ b/private/utils/mep/extens/mhelp/mhfile.c
@@ -0,0 +1,344 @@
+/*************************************************************************
+**
+** mhfile - file manipulation for the help extension for the Microsoft Editor
+**
+** Copyright <C> 1988, Microsoft Corporation
+**
+** Revision History:
+**
+** 09-Dec-1988 ln Changes for Dialog help
+** 02-Sep-1988 ln Make all data inited. Add info in debug vers.
+** 15-Aug-1988 ln New HelpOpen return values
+** [] 16-May-1988 Created, extracted from mehelp.c
+*/
+#include <stdlib.h> /* ultoa */
+#include <string.h> /* string functions */
+#define _INCLUDE_TOOLS_
+#include "mh.h" /* help extension include file */
+
+/*************************************************************************
+**
+** static data
+*/
+static uchar envvar[]= "HELPFILES"; /* help file list env var */
+static flagType fOpen = FALSE;/* file open attempted */
+static uchar szfiles[BUFLEN] = ""; /* string for open help files */
+
+
+
+
+/************************************************************************
+**
+** closehelp - close an open help file
+**
+** Purpose:
+**
+** Entry:
+** pfn = pointer to filename.
+**
+** Exit:
+**
+** Exceptions:
+**
+*/
+flagType pascal near closehelp(pfn)
+char *pfn;
+{
+int iHelpNew; /* index into file table */
+nc ncNew; /* new file's initial nc */
+
+/*
+** attempt to open the file first, to get the initial context. If we cannot
+** open the file, we stop here, since it wasn't open to begin with.
+*/
+ncNew = HelpOpen(pfn);
+if (ISERROR(ncNew)) {
+/*
+** Scan the current file list for the same handle. If the handle returned
+** by HelpOpen above is already in the table, then the file was already open,
+** and we zero out that table entry.
+*/
+ for (iHelpNew=MAXFILES-1; iHelpNew>=0; iHelpNew--) {
+ if ((files[iHelpNew].ncInit.mh == ncNew.mh) &&
+ (files[iHelpNew].ncInit.cn == ncNew.cn)) { /* if already open */
+ files[iHelpNew].ncInit.mh = 0;
+ files[iHelpNew].ncInit.cn = 0; /* remove from list */
+ }
+ }
+/*
+** We destory all traces of back-trace and currency, since these contexts may
+** reference the now closed helpfile, close it and return.
+*/
+ HelpClose(ncNew); /* close the file */
+ while (HelpNcBack().cn); /* destroy back-trace */
+ ncCur.mh = ncLast.mh = 0; /* and clear currancy */
+ ncCur.cn = ncLast.cn = 0;
+ }
+return TRUE; /* and we're done */
+
+/* end closehelp */}
+
+/************************************************************************
+**
+** openhelp - open a help file & add to list of files
+**
+** Purpose:
+**
+** Entry:
+** pfn = pointer to filename.
+**
+** Exit:
+**
+** Exceptions:
+**
+*/
+void pascal near openhelp(char *pfn, struct findType *dummy1, void *ReturnValue)
+{
+int iHelpNew; /* index into file table */
+nc ncNew; /* new file's initial nc */
+char *pExt = 0; /* pointer to extension string */
+flagType RetVal;
+buffer pfnbuf;
+assert (pfn);
+
+
+fOpen = TRUE; /* we HAVE openned something */
+/*
+** preserve any prepended extensions.
+*/
+if (*pfn == '.') {
+ pExt = pfn;
+ while (*pfn && (*pfn != ':'))
+ pfn++; /* point to actual filename */
+ if (*pfn) *pfn++ = 0; /* terminate ext string */
+ }
+
+/*
+** attempt to open the file. If we cannot open the file, we stop here.
+*/
+ncNew = HelpOpen(pfn);
+if (ISERROR(ncNew)) {
+ strcpy (pfnbuf, pfn);
+ strcpy(buf,"Can't open [");
+ strcat(buf,pfnbuf);
+
+ switch (ncNew.cn) {
+ case HELPERR_FNF:
+ pfn = "]: Not Found";
+ break;
+ case HELPERR_READ:
+ pfn = "]: Read Error";
+ break;
+ case HELPERR_LIMIT:
+ pfn = "]: Too many help files";
+ break;
+ case HELPERR_BADAPPEND:
+ pfn = "]: Bad appended help file";
+ break;
+ case HELPERR_NOTHELP:
+ pfn = "]: Not a help file";
+ break;
+ case HELPERR_BADVERS:
+ pfn = "]: Bad help file version";
+ break;
+ case HELPERR_MEMORY:
+ pfn = "]: Out of Memory";
+ break;
+ default:
+ pfn = "]: Unkown error 0x ";
+ _ultoa (ncNew.cn, &pfn[18], 16);
+ }
+
+ strcat(buf,pfn);
+ errstat(buf,NULL);
+ debmsg (buf);
+ debend (TRUE);
+
+ if ( ReturnValue ) {
+ *((flagType *)ReturnValue) = FALSE;
+ }
+ return;
+ }
+/*
+** Scan the current file list for the same handle. If the handle returned
+** by HelpOpen above is already in the table, then the file was already open,
+** and we don't need to add it.
+*/
+for (iHelpNew=MAXFILES-1; iHelpNew>=0; iHelpNew--)
+ if ((files[iHelpNew].ncInit.mh == ncNew.mh) &&
+ (files[iHelpNew].ncInit.cn == ncNew.cn)) { /* if already open */
+ ifileCur = iHelpNew; /* set currency */
+ procExt(iHelpNew,pExt); /* process extensions */
+ if ( ReturnValue ) {
+ *((flagType *)ReturnValue) = TRUE;
+ }
+ return;
+ }
+/*
+** Scan the file list again for an unused slot. Once found, save the initial
+** context for that help file, and finally set it up as the first help file
+** to be searched.
+*/
+for (iHelpNew=MAXFILES-1; iHelpNew>=0; iHelpNew--)
+ if ((files[iHelpNew].ncInit.mh == 0) &&
+ (files[iHelpNew].ncInit.cn == 0)) { /* if available slot */
+ files[iHelpNew].ncInit = ncNew; /* save initial context */
+ ifileCur = iHelpNew; /* and set currency */
+ procExt(iHelpNew,pExt); /* process extensions */
+ if ( ReturnValue ) {
+ *((flagType *)ReturnValue) = TRUE;
+ }
+ return;
+ }
+/*
+** If we got here, it's because the loop above didn't find any open slots in
+** our file table. Complain, close and exit.
+*/
+errstat ("Too many help files",NULL);
+HelpClose(ncNew);
+if ( ReturnValue ) {
+ *((flagType *)ReturnValue) = FALSE;
+}
+dummy1;
+/* end openhelp */}
+
+/************************************************************************
+**
+** procExt - process default extensions for file
+**
+** Purpose:
+** fill in extension table for an openned file
+**
+** Entry:
+** ifileCur = filetable index
+** pExt = pointer to extension string
+**
+** Exit:
+** filetable entry updated
+*/
+void pascal near procExt(ifileCur, pExt)
+int ifileCur;
+char *pExt;
+{
+int i,j;
+char *pExtDst; /* place to put it */
+
+if (pExt) { /* if there is one */
+ pExt++; /* skip leading period */
+ for (i=0; i<MAXEXT; i++) { /* for all possible ext slots */
+ pExtDst = files[ifileCur].exts[i]; /* point to destination */
+ j = 0;
+ while (*pExt && (*pExt != '.') && (j++ < 3))
+ *pExtDst++ = *pExt++;
+ if (*pExt == '.')
+ pExt++; /* skip period separator */
+ *pExtDst = 0; /* always terminate */
+ }
+ }
+
+/* end procExt */}
+
+/*** opendefault - if no files open yet, open the default set
+*
+* We delay this operation, in the case that the user will have a helpfiles:
+* switch which will locate the helpfiles explicitly. In those cases this
+* routine does nothing, and we don;t waste time up front openning files
+* only to close them later.
+*
+* On the other hand, if he has not set a helpfiles switch by his first
+* request for help, we want to try either the environment variable, if it
+* exists, or when all else fails, default to mep.hlp.
+*
+* Input:
+* none
+*
+* Output:
+* Returns nothing. Helpfiles open, we hope.
+*
+*************************************************************************/
+void pascal near opendefault ( void ) {
+
+char *tmp;
+
+if (!fOpen) {
+ if (getenv (envvar)) {
+// prochelpfiles (getenv (envvar)); /* Process user-spec'd files */
+ prochelpfiles (tmp=getenvOem (envvar)); /* Process user-spec'd files */
+ free( tmp );
+ }
+ else
+ openhelp ("mep.hlp", NULL, NULL); /* else use default */
+ }
+/* end opendefault */}
+
+/************************************************************************
+**
+** prochelpfiles - process helpfiles: switch
+**
+** Purpose:
+** called by the editor each time the helpfiles switch is changed.
+**
+** Entry:
+** pszfiles = pointer to new switch value
+**
+** Exit:
+**
+** Exceptions:
+**
+*/
+flagType pascal EXTERNAL prochelpfiles (pszfiles)
+char *pszfiles;
+{
+char cTerm; /* terminating character */
+int iHelp;
+char *pEnd; /* pointer to end of current fn */
+
+if ( !ExtensionLoaded ) {
+ return FALSE;
+}
+strncpy(szfiles,pszfiles,BUFLEN); /* save specified string */
+/*
+** begin by closing all open help files and loosing curency
+*/
+for (iHelp=MAXFILES-1; iHelp>=0; iHelp--)
+ if ((files[iHelp].ncInit.mh) &&
+ (files[iHelp].ncInit.cn)) { /* if open file */
+ HelpClose(files[iHelp].ncInit); /* close it */
+ files[iHelp].ncInit.mh = 0;
+ files[iHelp].ncInit.cn = 0;
+ }
+while (HelpNcBack().cn); /* destroy back-trace */
+ncCur.mh = ncLast.mh = 0; /* and clear currancy */
+ncCur.cn = ncLast.cn = 0;
+
+while (*pszfiles) { /* while files to proc */
+ if (*pszfiles == ' ') /* strip leading spaces */
+ pszfiles++;
+ else {
+ pEnd = pszfiles;
+ while (*pEnd && (*pEnd != ' ') && (*pEnd != ';')) pEnd++; /* move to end of fn */
+ cTerm = *pEnd; /* save terminator */
+ *pEnd = 0;
+
+
+ forfile(pszfiles, A_ALL, openhelp, NULL);
+
+#if rjsa
+ // Since pszfiles may contain wild characters, we use
+ // ffirst/fnext to open all of them
+ //
+ rc = ffirst(pszfiles, A_ALL, &buffer);
+ while (!rc) {
+ buffer.fbuf.achName[buffer.fbuf.cchName] = '\0';
+ openhelp(buffer.fbuf.achName, NULL, NULL);
+ rc = fnext(&buffer);
+ }
+#endif
+ pszfiles = pEnd; /* point to end */
+ if (cTerm) pszfiles++; /* if more, move to next */
+ }
+ }
+ifileCur = MAXFILES-1;
+
+return TRUE;
+/* end prochelpfiles */}
diff --git a/private/utils/mep/extens/mhelp/mhlook.c b/private/utils/mep/extens/mhelp/mhlook.c
new file mode 100644
index 000000000..229260a00
--- /dev/null
+++ b/private/utils/mep/extens/mhelp/mhlook.c
@@ -0,0 +1,255 @@
+/*** mhlook - Help Look-Up code.
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* This module contains routines dealing with searching for and (hopefully)
+* finding help information
+*
+* Revision History (most recent first):
+*
+* 30-Mar-1989 ln pass popup flag around correctly.
+* [] 12-Mar-1989 LN Split off of mhdisp.c
+*
+*************************************************************************/
+#include <string.h> /* string functions */
+
+#include "mh.h" /* help extension include file */
+
+
+/*** fHelpCmd - Display topic text or execute command.
+*
+* Input:
+* szCur = context string
+* fStay = TRUE => keep focus in current window, else move focus to
+* newly opened help window.
+* fWantPopUp = TRUE => display as popup window. (Ignored in non-CW)
+*
+* Exit:
+* returns TRUE on success.
+*
+*************************************************************************/
+flagType pascal near fHelpCmd (
+ char *szCur,
+ flagType fStay,
+ flagType fWantPopUp
+ ) {
+
+ int i; /* index while checking for helpfiles*/
+ nc ncCur = {0,0}; /* nc found */
+
+
+ //
+ // If a command to display a context (!C), just remove the command
+ //
+ if (*(ushort UNALIGNED *)szCur == 0x4321) {
+ szCur += 2;
+ }
+
+ //
+ // If the command starts with an exclamation point, then go execute it.
+ //
+ if (*szCur == '!') {
+ return fContextCommand (szCur+1);
+ }
+
+ stat(szCur);
+
+ debmsg ("Searching:");
+
+ //
+ // search algorithm:
+ // 1) if help is not up, or we're looking for a different string than the
+ // last string we found, or it's a local context, try the same help file
+ // as the last look-up, if there was a last lookup.
+ // 2) If that fails, and it's not a local context, and we're not to present
+ // a list, then look in the help file(s) that are associated with the
+ // current file extension.
+ // 3) If that fails, and it's not a local context, then search all the help
+ // files.
+ // 4) If THAT fails, then check to see if there are any help files open
+ // at all, and return an appropriate error message on that.
+ //
+ if (ncInitLast.mh && ncInitLast.cn && (strcmp (szCur, szLastFound) || !(*szCur))) {
+ ncCur = ncSearch (szCur, NULL, ncInitLast, FALSE, FALSE);
+ }
+
+ if (!ncCur.mh && !ncCur.cn && *szCur && fnExtCur && !fList) {
+ nc ncTmp = {0,0};
+ ncCur = ncSearch (szCur, fnExtCur, ncTmp, FALSE, FALSE);
+ }
+
+ if (!ncCur.mh && !ncCur.cn && *szCur) {
+ nc ncTmp = {0,0};
+ ncCur = ncSearch (szCur, NULL, ncTmp, FALSE, fList);
+ }
+
+ if (!ncCur.mh && !ncCur.cn) {
+ for (i=MAXFILES-1; i; i--) {
+ if ((files[i].ncInit.mh || files[i].ncInit.cn)) {
+ return errstat ("Help on topic not found:",szCur);
+ }
+ }
+ return errstat ("No Open Help Files", NULL);
+ }
+
+ //
+ // Save this as the last context string actually found
+ //
+ xrefCopy (szLastFound, szCur);
+
+ debend (TRUE);
+ return fDisplayNc ( ncCur /* nc to display */
+ , TRUE /* add to backtrace list */
+ , fStay /* keep focus in current win? */
+ , fWantPopUp); /* as a pop-up? */
+
+}
+
+/*** fContextCommand - execute context command
+*
+* Input:
+* szCur = pointer to context command
+*
+* Output:
+* Returns TRUE if it was executed
+*
+*************************************************************************/
+flagType pascal near fContextCommand (
+char *szCur
+) {
+switch (*szCur++) {
+
+case ' ': /* exeute DOS command */
+case '!': /* exeute DOS command */
+ strcpy(buf,"arg \"");
+ strcat(buf,szCur);
+ strcat(buf,"\" shell");
+ fExecute(buf); /* execute as shell cmd */
+ break;
+
+case 'm': /* execute editor macro */
+ fExecute(szCur);
+ break;
+
+default:
+ return FALSE;
+ }
+
+Display ();
+return TRUE;
+
+/* end fContextCommand */}
+
+/** ncSearch - find help on context string
+*
+* search all the currently active help files for help on a particular
+* topic. If desired, restricts the search to those files which are
+* associated with a particular extension.
+*
+* Entry:
+* pText = text to get help on
+* pExt = If non-null, the extension to restrict the search to.
+* ncInit = if non-null, ncInit of the only help file to look in
+* fAgain = If non-null, skip helpfiles until ncInit found, then
+* pick up the search.
+* fList = if true, present a list box of the posibilities.
+*
+* Exit:
+* returns nc found, or NULL
+*
+*************************************************************************/
+nc pascal near ncSearch (
+uchar far *pText,
+uchar far *pExt,
+nc ncInit,
+flagType fAgain,
+flagType fList
+) {
+int iHelp; /* index into helpfile table */
+int j;
+nc ncRet = {0,0}; /* nc found */
+
+UNREFERENCED_PARAMETER( fList );
+
+debmsg (" [");
+debmsg (pText);
+debmsg ("]:");
+/*
+ * If this is just a single search (ncInit specified, and not a search
+ * "again"), then JUST look in the single file.
+ */
+if ((ncInit.mh || ncInit.cn) && !fAgain)
+ ncRet = HelpNc(pText,ncInit);
+/*
+ * If fList is specified, then search ALL the databases for ALL ocurrances
+ * of the string, and make a list of the nc's we find.
+ */
+#if defined(PWB)
+else if (fList) {
+ iHelp = ifileCur;
+ cList = 0;
+ do {
+ if (files[iHelp].ncInit) {
+ ncRet = files[iHelp].ncInit;
+ while ( (cList < CLISTMAX)
+ && (rgncList[cList] = HelpNc(pText,ncRet))) {
+ ncRet = rgncList[cList++];
+ ncRet.cn++;
+ }
+ }
+ iHelp += iHelp ? -1 : MAXFILES-1;
+ }
+ while ((iHelp != ifileCur) && (cList < CLISTMAX));
+
+ if (cList == 0) {
+ ncRet.mh = ncRet.cn = 0;
+ return ncRet;
+ }
+ if (cList == 1)
+ return rgncList[0];
+ return ncChoose(pText);
+ }
+#endif
+
+else {
+ iHelp = ifileCur; /* start with current file */
+ do {
+ if ((files[iHelp].ncInit.mh) &&
+ (files[iHelp].ncInit.cn)) { /* if helpfile open */
+ if (pExt) { /* if an extension was specified*/
+ for (j=0; j<MAXEXT; j++) { /* for all listed defaults */
+ if (fAgain) {
+ if ((ncInit.mh == files[iHelp].ncInit.mh) &&
+ (ncInit.cn == files[iHelp].ncInit.cn)) {
+ fAgain = FALSE;
+ }
+ }
+ else if (strcmp(files[iHelp].exts[j],pExt) == 0) {
+ debmsg (":");
+ ncRet = HelpNc(pText,files[iHelp].ncInit);
+ break;
+ }
+ }
+ }
+
+ else { /* no extension specified */
+ if (fAgain && ((ncInit.mh == files[iHelp].ncInit.mh) &&
+ (ncInit.cn == files[iHelp].ncInit.cn)))
+ fAgain = FALSE;
+ else {
+ ncRet = HelpNc(pText,files[iHelp].ncInit);
+ debmsg (":");
+ }
+ }
+ }
+ if (ncRet.mh || ncRet.cn)
+ ncInitLastFile = files[iHelp].ncInit;
+ iHelp += iHelp ? -1 : MAXFILES-1;
+ }
+ while ((iHelp != ifileCur) && ((ncRet.mh == 0) && (ncRet.cn == 0)));
+ }
+
+debmsg ((ncRet.mh && ncRet.cn) ? "Y" : "N");
+
+return ncRet;
+/* end ncSearch */}
diff --git a/private/utils/mep/extens/mhelp/mhutil.c b/private/utils/mep/extens/mhelp/mhutil.c
new file mode 100644
index 000000000..03377d688
--- /dev/null
+++ b/private/utils/mep/extens/mhelp/mhutil.c
@@ -0,0 +1,342 @@
+/*** mhutil - utilities for the help extension for the Microsoft Editor
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History (most recent first):
+*
+* 01-Dec-1988 ln Cleanup & dislog help
+* 28-Sep-1988 ln Correct GrabWord return value
+* 02-Sep-1988 ln Make all data inited. Add info in debug vers.
+* [] 16-May-1988 Extracted from mehelp.c
+*
+*************************************************************************/
+#include <string.h> /* string functions */
+#include <malloc.h>
+#include "mh.h" /* help extension include file */
+
+
+
+/************************************************************************
+**
+** procArgs
+**
+** Purpose:
+** decode arguments passed into extension into commonly used variables.
+**
+** Entry:
+** pArg = pointer to arg structure, courtesy of Z
+**
+** Exit:
+** returns pArg->argType. Global variables updated.
+*/
+int pascal near procArgs (pArg)
+ARG far *pArg; /* argument data */
+{
+buf[0] = 0;
+pArgWord = pArgText = 0;
+rnArg.flFirst.col = rnArg.flLast.col = 0;
+rnArg.flFirst.lin = rnArg.flLast.lin = 0;
+cArg = 0;
+
+opendefault ();
+pFileCur = FileNameToHandle ("", ""); /* get current file handle */
+fnCur[0] = 0;
+GetEditorObject(RQ_FILE_NAME,0,fnCur); /* get filename */
+fnExtCur = strchr (fnCur, '.'); /* and pointer to extension */
+
+switch (pArg->argType) {
+ case NOARG: /* <function> only, no arg */
+ cArg = 0;
+ pArgText = NULL;
+ break;
+
+ case NULLARG: /* <arg><function> */
+ cArg = pArg->arg.nullarg.cArg; /* get <arg> count */
+ GrabWord (); /* get argtext and argword */
+ break;
+
+ case STREAMARG: /* <arg>line movement<function> */
+ cArg = pArg->arg.streamarg.cArg;/* get <arg> count */
+ rnArg.flFirst.col = pArg->arg.streamarg.xStart;
+ rnArg.flLast.col = pArg->arg.streamarg.xEnd;
+ rnArg.flFirst.lin = pArg->arg.streamarg.yStart;
+ if (GetLine(rnArg.flFirst.lin, buf, pFileCur) > rnArg.flFirst.col) {
+ pArgText = &buf[rnArg.flFirst.col]; /* point at word */
+ buf[rnArg.flLast.col] = 0; /* terminate string */
+ }
+ break;
+
+ case TEXTARG: /* <arg> text <function> */
+ cArg = pArg->arg.textarg.cArg; /* get <arg> count */
+ pArgText = pArg->arg.textarg.pText;
+ break;
+ }
+return pArg->argType;
+/* end procArgs */}
+
+/************************************************************************
+**
+** GrabWord - Grab the word under the editor cursor
+**
+** Purpose:
+** grabs the word underneath the cursor for context sensitive help look-up.
+**
+** Entry:
+** none
+**
+** Returns:
+** nothing. pArgWord points to word, if it was parsed.
+*/
+void pascal near GrabWord () {
+
+pArgText = pArgWord = 0;
+pFileCur = FileNameToHandle ("", ""); /* get current file handle */
+GetTextCursor (&rnArg.flFirst.col, &rnArg.flFirst.lin);
+if (GetLine(rnArg.flFirst.lin, buf, pFileCur)) { /* get line */
+ pArgText = &buf[rnArg.flFirst.col]; /* point at word */
+ while (!wordSepar((int)*pArgText))
+ pArgText++; /* search for end */
+ *pArgText = 0; /* and terminate */
+ pArgWord = pArgText = &buf[rnArg.flFirst.col]; /* point at word */
+ while ((pArgWord > &buf[0]) && !wordSepar ((int)*(pArgWord-1)))
+ pArgWord--;
+ }
+/* end GrabWord */}
+
+/*** appTitle - Append help file title to buffer
+*
+* Read in the title of a help file and append it to a buffer.
+*
+* Input:
+* fpDest - far pointer to destination of string
+* ncInit - Any nc of file to get title for
+*
+* Output:
+* Returns
+*
+*************************************************************************/
+void pascal near appTitle (
+char far *pDest,
+nc ncInit
+) {
+/*
+** first, point to end of string to append to
+*/
+while (*pDest)
+ pDest++;
+/*
+** Start by getting the info on the file referenced, so that we can get the
+** ncInit for that file.
+*/
+if (!HelpGetInfo (ncInit, &hInfoCur, sizeof(hInfoCur))) {
+ ncInit = NCINIT(&hInfoCur);
+/*
+** Find the context string, and read the topic. Then just read the first
+** line into the destination
+*/
+ ncInit = HelpNc ("h.title",ncInit);
+ if (ncInit.cn && (fReadNc(ncInit))) {
+ pDest += HelpGetLine (1, BUFLEN, pDest, pTopic);
+ *pDest = 0;
+ free (pTopic);
+ pTopic = NULL;
+ }
+/*
+** If no title was found, then just place the help file name there.
+*/
+ else
+ strcpy (pDest, HFNAME(&hInfoCur));
+ }
+/*
+** If we couldn't even get the info, then punt...
+*/
+else
+ strcpy (pDest, "** unknown **");
+/* end appTitle */}
+
+
+/*** errstat - display error status message
+*
+* In non cw, just display the strings on the status line. In CW, bring up
+* a message box.
+*
+* Input:
+* sz1 = first error message line
+* sz2 = second. May be NULL.
+*
+* Output:
+* Returns FALSE
+*************************************************************************/
+flagType pascal near errstat (
+char *sz1,
+char *sz2
+) {
+#if defined(PWB)
+DoMessageBox (sz1, sz2, NULL, MBOX_OK);
+#else
+buffer buf;
+
+strcpy (buf, sz1);
+if (sz2) {
+ strcat (buf, " ");
+ strcat (buf, sz2);
+ }
+stat (buf);
+#endif
+return FALSE;
+/* end errstat */}
+
+/*** stat - display status line message
+*
+* Places extension name and message on the status line
+*
+* Entry:
+* pszFcn - Pointer to string to be prepended.
+*
+* Exit:
+* none
+*
+*************************************************************************/
+void pascal near stat(pszFcn)
+char *pszFcn; /* function name */
+{
+buffer buf; /* message buffer */
+
+strcpy(buf,"mhelp: "); /* start with name */
+if (strlen(pszFcn) > 72) {
+ pszFcn+= strlen(pszFcn) - 69;
+ strcat (buf, "...");
+ }
+strcat(buf,pszFcn); /* append message */
+DoMessage (buf); /* display */
+/* end stat */}
+
+#ifdef DEBUG
+buffer debstring = {0};
+extern int delay; /* message delay */
+
+/*** debhex - output long in hex
+*
+* Display the value of a long in hex
+*
+* Input:
+* lval = long value
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void pascal near debhex (
+long lval
+) {
+char lbuf[10];
+
+_ultoa (lval, lbuf, 16);
+debmsg (lbuf);
+/* end debhex */}
+
+/*** debmsg - piece together debug message
+*
+* Outputs a the cummulative message formed by successive calls.
+*
+* Input:
+* psz = pointer to message part
+*
+* Output:
+* Returns nothing
+*************************************************************************/
+void pascal near debmsg (
+char far *psz
+) {
+_stat (strcat (debstring, psz ? psz : "<NULL>" ));
+/* end debmsg */}
+
+/*** debend - terminates message accumulation & pauses
+*
+* Terminates the message accumulation, displays the final message, and
+* pauses, either for the pause time, or for a keystroke.
+*
+* Input:
+* fWait = TRUE => wait for a keystroke
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void pascal near debend (
+flagType fWait
+) {
+if (fWait && delay) {
+#if defined(PWB)
+ DoMessageBox (debstring, NULL, NULL, MBOX_OK);
+#else
+ _stat (strcat (debstring, " Press a key..."));
+ ReadChar ();
+#endif
+ }
+#ifdef OS2
+else if (delay)
+ DosSleep ((long)delay);
+#endif
+debstring[0] = 0;
+/* end debend */}
+
+/*** _mhassertexit - display assertion message and exit
+*
+* Input:
+* pszExp - expression which failed
+* pszFn - filename containing failure
+* line - line number failed at
+*
+* Output:
+* Doesn't return
+*
+*************************************************************************/
+void pascal near _mhassertexit (
+char *pszExp,
+char *pszFn,
+int line
+) {
+char lbuf[10];
+
+_ultoa (line, lbuf, 10);
+strcpy (buf, pszExp);
+strcat (buf, " in ");
+strcat (buf, pszFn);
+strcat (buf, ": line ");
+strcat (buf, lbuf);
+errstat ("Help assertion failed", buf);
+
+fExecute ("exit");
+
+/* end _mhassertexit */}
+
+#endif
+
+
+flagType pascal wordSepar (int i) {
+ CHAR c = (CHAR)i;
+ if (((c >= 'a') && (c <= 'z')) ||
+ ((c >= 'A') && (c <= 'Z')) ||
+ ((c >= '0') && (c <= '9')) ||
+ ( c == '_' ) ||
+ ( c == '$' ) ) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+
+char far * pascal near xrefCopy (char far *dst, char far *src)
+{
+ if ( *src ) {
+ strcpy( dst, src );
+ } else {
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ }
+
+ return dst;
+}
diff --git a/private/utils/mep/extens/mhelp/mhwin.c b/private/utils/mep/extens/mhelp/mhwin.c
new file mode 100644
index 000000000..d06ba1e87
--- /dev/null
+++ b/private/utils/mep/extens/mhelp/mhwin.c
@@ -0,0 +1,140 @@
+/*** mhwin - Help Windowing Code
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* This module contains routines dealing with opening and closing the help
+* display window.
+*
+* Revision History (most recent first):
+*
+* [] 12-Mar-1989 LN Split off of mhdisp.c
+*
+*************************************************************************/
+#include <string.h> /* string functions */
+
+#include "mh.h" /* help extension include file */
+
+/*** OpenWin - Open a window on the help file, empty & make current.
+*
+* Entry:
+* cLines = Desired size of window.
+*
+* Exit:
+* Returns help file PWND
+*
+*************************************************************************/
+PWND pascal near OpenWin (
+ushort cLines
+) {
+PWND pWinCur; /* win handle for current win */
+winContents wc; /* description of win contents */
+int winSize; /* size of current window */
+
+fInOpen = TRUE;
+/*
+** Get a handle to the current window, and a handle to the help window if up.
+** If they are NOT the same, then save the "current" handle as the one the
+** user had active prior to asking for help.
+*/
+GetEditorObject (RQ_WIN_HANDLE, 0, &pWinCur);
+pWinHelp = FindHelpWin (FALSE);
+if (pWinHelp != pWinCur)
+ pWinUser = pWinCur;
+/*
+** If no help window was found. Attempt to split the current window, if
+** it's big enough, and that's requested
+*/
+if (!pWinHelp) {
+ GetEditorObject (RQ_WIN_CONTENTS | 0xff, pWinUser, &wc);
+#if defined(PWB)
+/*
+** In PWB we just ask the editor to split the current window in half.
+*/
+ fSplit = FALSE;
+ if ((wc.arcWin.ayBottom - wc.arcWin.ayTop >= 12) && fCreateWindow) {
+ fSplit = SplitWnd (pWinUser, FALSE, (wc.arcWin.ayBottom - wc.arcWin.ayTop)/2);
+ GetEditorObject (RQ_WIN_HANDLE, 0, &pWinHelp);
+ }
+ }
+/*
+** We have a window, of some sort, attempt to resize the window to the
+** requested size.
+*/
+if (cLines) {
+ cLines += 2;
+ GetEditorObject (RQ_WIN_CONTENTS | 0xff, pWinHelp, &wc);
+ wc.arcWin.ayBottom = wc.arcWin.ayTop + cLines;
+ Resize (pWinHelp, wc.arcWin);
+ }
+#else
+/*
+** Non PWB: Attempt to split the resulting current window to the desired size.
+** by moving the cursor there, and executing arg window. Note that if the
+** window had already existed, we won't even try to resize.
+*/
+ winSize = wc.arcWin.ayBottom - wc.arcWin.ayTop;
+ if ( (cLines < 6)
+ || (cLines > (ushort)(winSize - 6)))
+ cLines = (ushort)(winSize / 2);
+ if ((cLines > 6) && fCreateWindow) {
+ fSplit = SplitWnd(pWinUser, FALSE, (LINE)cLines);
+ //fSplit = SplitWnd(pWinUser, FALSE, wc.flPos.lin + (long)cLines);
+ // rjsa MoveCur (wc.flPos.col, wc.flPos.lin + (long)cLines);
+ // rjsa fSplit = fExecute ("arg window");
+ GetEditorObject (RQ_WIN_HANDLE, 0, &pWinHelp);
+ }
+ else
+ pWinHelp = pWinUser;
+ }
+#endif
+/*
+** Set the window to be the current window, and move the help file to the
+** top of that window's file list.
+*/
+SetEditorObject (RQ_WIN_CUR | 0xff, pWinHelp, 0);
+DelFile (pHelp);
+asserte (pFileToTop (pHelp));
+fInOpen = FALSE;
+return pWinHelp;
+
+/* end OpenWin */}
+
+/*** FindHelpWin - Locate window containing help & make current
+*
+* For all windows in the system, look for a window that has the help file
+* in it. If found, set focus there.
+*
+* Entry:
+* fSetCur = TRUE=> set help window current when found
+*
+* Globals:
+* cWinSystem = returned number of windows in system
+*
+* Returns:
+* pWin of help file
+*
+*************************************************************************/
+PWND pascal near FindHelpWin (
+flagType fSetCur
+) {
+int cWinSystem; /* number of windows in system */
+winContents wc; /* description of win contents */
+
+pWinHelp = 0;
+for (cWinSystem=1; cWinSystem<=8; cWinSystem++) {
+ if (GetEditorObject (RQ_WIN_CONTENTS | cWinSystem, 0, &wc)) {
+ if (wc.pFile == pHelp) {
+ if (fSetCur) {
+ SetEditorObject (RQ_WIN_CUR | cWinSystem, 0, 0);
+ GetEditorObject (RQ_WIN_HANDLE, 0, &pWinHelp);
+ }
+ else
+ GetEditorObject (RQ_WIN_HANDLE | cWinSystem, 0, &pWinHelp);
+ break;
+ }
+ }
+ else
+ break;
+ }
+return pWinHelp;
+/* end FindHelpWin */}
diff --git a/private/utils/mep/extens/mhelp/sources b/private/utils/mep/extens/mhelp/sources
new file mode 100644
index 000000000..226d0504c
--- /dev/null
+++ b/private/utils/mep/extens/mhelp/sources
@@ -0,0 +1,56 @@
+MAJORCOMP=utils
+MINORCOMP=mep
+
+TARGETNAME=mhelp
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+LINKLIBS=\nt\public\sdk\lib\*\exthdr.lib
+TARGETLIBS=\nt\private\sdktools\ztools\src\obj\*\ztools.lib \
+ \nt\public\sdk\lib\*\kernel32.lib \
+ \nt\public\sdk\lib\*\user32.lib
+
+INCLUDES=.;..\..\inc;..\..\help\inc;\nt\private\sdktools\ztools\inc
+
+SOURCES= mhcore.c \
+ mhdisp.c \
+ mhevt.c \
+ mhfile.c \
+ mhlook.c \
+ mhutil.c \
+ mhwin.c \
+ mhelp.rc
+
+C_DEFINES=-D_OS2_20_=0 -DNO_EXT_KEYS -Dpascal= -Dfar= -DNOLANMAN -DNT
+UMTYPE=console
+UMRES=obj\*\mhelp.res
+USE_CRTDLL=1
+
+!IF 0
+#
+#
+#
+#MAJORCOMP=utils
+#MINORCOMP=mep
+#
+#TARGETNAME=mhelp
+#TARGETPATH=obj
+#TARGETTYPE=LIBRARY
+#TARGETLIBS=\nt\public\sdk\lib\*\exthdr.lib \nt\private\sdktools\ztools\src\obj\*\ztools.lib
+#
+#INCLUDES=.;..\..\inc;..\..\help\inc;\nt\private\sdktools\ztools\inc
+#
+#SOURCES= helphck.c \
+# mhcore.c \
+# mhdisp.c \
+# mhevt.c \
+# mhfile.c \
+# mhlook.c \
+# mhutil.c \
+# mhwin.c
+#
+#C_DEFINES=-D_OS2_20_=0 -DNO_EXT_KEYS -DNOLANMAN -DNT -DHELP_HACK
+#UMTYPE=console
+#
+#
+!ENDIF
+
diff --git a/private/utils/mep/extens/pmatch/makefile b/private/utils/mep/extens/pmatch/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/mep/extens/pmatch/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/mep/extens/pmatch/pmatch.c b/private/utils/mep/extens/pmatch/pmatch.c
new file mode 100644
index 000000000..b8b331e26
--- /dev/null
+++ b/private/utils/mep/extens/pmatch/pmatch.c
@@ -0,0 +1,544 @@
+#define EXT_ID "pmatch ver 1.02 "##__DATE__##" "##__TIME__
+#include "ext.h"
+
+/*
+ * Modifications
+ * 12-Sep-1988 mz Made WhenLoaded match declaration
+ *
+ */
+
+#define fLeftSide(ch) ((ch) == '[' || (ch) == '{' || (ch) == '(' || (ch) == '<' )
+#define EOF (int)0xFFFFFFFF
+#define BOF (int)0xFFFFFFFE
+#define EOL (int)0xFFFFFFFD
+
+#ifndef TRUE
+#define FALSE 0
+#define TRUE (!FALSE)
+#endif
+
+#ifndef NULL
+#define NULL ((void *) 0)
+#endif
+
+#define SQ '\''
+#define DQ '\"'
+#define ANYCHAR '\0'
+#define BACKSLASH '\\'
+
+/****************************************************************************
+ * *
+ * Handle apostrophes ( which look like single quotes, but don't come in *
+ * pairs ) by defining a maximum number of chars that can come between *
+ * single quotes. 4 will handle '\000' and '\x00' *
+ * *
+ ****************************************************************************/
+
+#define SQTHRESH 4
+
+flagType pascal EXTERNAL PMatch (unsigned, ARG far *, flagType);
+char MatChar (char);
+void openZFile (void);
+void lopen (PFILE, int, int) ;
+int rgetc (void);
+int ngetc (void);
+int lgetc (void);
+void pos (COL far *, LINE far *);
+flagType ParenMatch (int, flagType);
+
+
+/****************************************************************************
+ * *
+ * PMatch(argData, pArg, fMeta) *
+ * *
+ * argData - ignored *
+ * pArg - ignored *
+ * fMeta - TRUE means search for first matchable character *
+ * *
+ * RETURNS: *
+ * *
+ * TRUE if matching character was found. *
+ * FALSE if not. *
+ * *
+ * SIDE EFFECTS: *
+ * *
+ * Changes location of cursor. *
+ * *
+ * DESCRIPTION: *
+ * *
+ * <pmatch>: If the cursor is on a "match" character, find the *
+ * match and move the cursor there. If not, do *
+ * nothing. *
+ * *
+ * <arg><pmatch>: Same as <pmatch>, but search forward for a "match" *
+ * character if we're not on one. *
+ * *
+ * Always ignore characters between quotes. *
+ * *
+ * Match characters currently supported are: *
+ * *
+ * '{' and '}' *
+ * '[' and ']' *
+ * '(' and ')' *
+ * '<' and '>' *
+ * *
+ * NOTES: *
+ * *
+ * This is defined as a CURSORFUNC, and therefore can be used to *
+ * select text as part of an argument. For example, to grab the body *
+ * of a function, go to the opening brace of the body and do *
+ * <arg><pmatch><pick>. *
+ * *
+ ****************************************************************************/
+
+flagType pascal EXTERNAL PMatch (
+unsigned int argData,
+ARG far * pArg,
+flagType fMeta
+)
+{
+ COL x;
+ LINE y;
+ char ch;
+
+
+ //
+ // Unreferenced parameters
+ //
+ (void)argData;
+ (void)pArg;
+
+ /* Set up file functions */
+ openZFile ();
+
+ /* If current character has no match ... */
+ if (!MatChar (ch = (char)ngetc()))
+ {
+ if (fMeta)
+ { /* Move forward looking for first matchable character */
+
+ if (!ParenMatch (ANYCHAR, TRUE)) return FALSE;
+
+ pos ((COL far *)&x, (LINE far *)&y);
+ MoveCur (x, y);
+ return TRUE;
+ }
+ else return FALSE;
+ }
+
+ if (ParenMatch ((int)ch, (flagType)fLeftSide(ch)))
+ { /* We got one */
+ pos ((COL far *)&x, (LINE far *)&y);
+
+ MoveCur (x, y);
+
+ return TRUE;
+ }
+
+ return FALSE; /* No match found */
+}
+
+
+/****************************************************************************
+ * *
+ * ParenMatch (chOrig, fForward) *
+ * *
+ * chOrig - character we are trying to match. *
+ * fForward - TRUE means search forward, FALSE search backwards *
+ * Returns TRUE if match found, false otherwise *
+ * *
+ * RETURNS: * *
+ * *
+ * TRUE if matching character found, FALSE if not. *
+ * *
+ * SIDE EFFECTS: *
+ * *
+ * Changes internal cursor location *
+ * *
+ * DESCRIPTION: *
+ * *
+ * Search for the next character that "pairs" with 'ch'. Account for * *
+ * nesting. Ignore all characters between double quotes and single *
+ * quotes. Recognize escaped quotes. Account for apostrophes. *
+ * *
+ ****************************************************************************/
+
+flagType ParenMatch (
+ int chOrig,
+ flagType fForward
+ )
+{
+ int lvl = 0, state = 0, sqcnt = 0;
+ int (*nextch)(void) = (int (*)(void))(fForward ? rgetc : lgetc);
+ int (*_ungetch)(void) = (int (*)(void))(fForward ? lgetc : rgetc);
+ int ch, chMatch;
+
+
+ if (chOrig) chMatch = (int)MatChar ((char)chOrig);
+
+ while ((ch = (*nextch)()) >= 0)
+ switch (state)
+ {
+ case 0: /* Regular text */
+ if (ch == SQ)
+ if (fForward) state = 1;
+ else state = 5;
+ else if (ch == DQ)
+ if (fForward) state = 3;
+ else state = 7;
+ else
+ if (chOrig != ANYCHAR)
+ if (ch == chOrig) lvl++; /* Nest in one */
+ else
+ {
+ if (ch == chMatch) /* Nest out or ...*/
+ if (!lvl--) goto found;/* Found it! */
+ }
+ else
+ if ((flagType)MatChar ((char)ch)) goto found; /* Found one! */
+
+ break;
+
+ case 1: /* Single quote moving forwards */
+ sqcnt++;
+ if (ch == BACKSLASH) state = 2;
+ else if (ch == SQ || /* We matched the ', or ... */
+ sqcnt > SQTHRESH ) /* ... we gave up trying */
+ {
+ sqcnt = 0;
+ state = 0;
+ }
+ break;
+
+ case 2: /* Escaped character inside single quotes */
+ sqcnt++;
+ state = 1;
+ break;
+
+ case 3: /* Double quote moving forwards */
+ if (ch == BACKSLASH) state = 4;
+ else if (ch == DQ) state = 0;
+ break;
+
+ case 4: /* Escaped character inside double quotes */
+ state = 3;
+ break;
+
+ case 5: /* Single quote moving backwards */
+ sqcnt++;
+ if (ch == SQ) state = 6;
+ else if (sqcnt > SQTHRESH)
+ {
+ sqcnt = 0;
+ state = 0;
+ }
+ break;
+
+ case 6: /* Check for escaped single quote moving backwards */
+ sqcnt++;
+ if (ch == BACKSLASH) state = 5;
+ else
+ {
+ sqcnt = 0;
+ (*_ungetch)();
+ state = 0;
+ }
+ break;
+
+ case 7: /* Double quote moving backwards */
+ if (ch == DQ) state = 8;
+ break;
+
+ case 8: /* Check for escaped double quote moving backwards */
+ if (ch == BACKSLASH) state = 7;
+ else
+ {
+ (*_ungetch)();
+ state = 0;
+ }
+ break;
+ }
+
+ return FALSE;
+
+ found: return TRUE;
+}
+
+
+/****************************************************************************
+ * *
+ * MatChar(ch) *
+ * *
+ * ch - Character to match *
+ * *
+ * RETURNS: *
+ * *
+ * Character that matches the argument *
+ * *
+ * SIDE EFFECTS: *
+ * *
+ * None. *
+ * *
+ * DESCRIPTION *
+ * *
+ * Given one character out of one of the pairs {}, [], (), <>, return *
+ * the other one. *
+ * *
+ ****************************************************************************/
+
+char MatChar (
+ char ch
+ )
+{
+ switch (ch)
+ {
+ case '{': return '}';
+ case '}': return '{';
+ case '[': return ']';
+ case ']': return '[';
+ case '(': return ')';
+ case ')': return '(';
+ case '<': return '>';
+ case '>': return '<';
+ default : return '\0';
+ }
+}
+
+
+/****************************************************************************
+ * *
+ * Extension specific file reading state. *
+ * *
+ * The static globals record the current state of file reading. The *
+ * pmatch extension reads through the file either forwards or backwards. *
+ * The state is kept as the current column and row, the contents of the *
+ * current line, the length of the current line and the file, and some *
+ * flags. *
+ * *
+ ****************************************************************************/
+
+static char LineBuf[BUFLEN]; /* Text of current line in file */
+static COL col ; /* Current column in file (0-based) */
+static LINE line ; /* Current line in file (0-based) */
+static int numCols ; /* Columns of text on curent line */
+static LINE numLines; /* Number of lines in the file */
+static PFILE pFile ; /* File to be reading from */
+static flagType fEof ; /* TRUE ==> end-of-file reached last time */
+static flagType fBof ; /* TRUE ==> begin-of-file reached last time */
+char CurFile[] = "" ; /* Current file to Z */
+
+
+/****************************************************************************
+ * *
+ * openZFile() *
+ * *
+ * SIDE EFFECTS: *
+ * *
+ * Changes globals pFile, fEof, fBof, col, line, numCols, numLines *
+ * and LineBuf *
+ * *
+ * DESCRIPTION: *
+ * *
+ * Opens the current file. This must be called before trying to read *
+ * the file. This is not a true "open" because it need not be closed *
+ * *
+ ****************************************************************************/
+
+void openZFile ()
+{
+ COL x;
+ LINE y;
+
+ GetTextCursor ((COL far *)&x, (LINE far *)&y);
+
+ /* Get Z handle for current file */
+ pFile = FileNameToHandle (CurFile, CurFile);
+ fEof = FALSE; /* We haven't read the end of file */
+ fBof = FALSE; /* We haven't read the beginning of file */
+ col = x; /* We start where Z is now in the file */
+ line = y; /* We start where Z is now in the file */
+ /* We pre-read the current line */
+ numCols = GetLine (line, (char far *)LineBuf, pFile);
+ /* We find the length of file (in lines) */
+ numLines = FileLength (pFile);
+}
+
+
+/****************************************************************************
+ * *
+ * rgetc () *
+ * *
+ * RETURNS: *
+ * *
+ * Next character in file, not including line terminators. EOF if *
+ * there are no more. *
+ * *
+ * SIDE EFFECTS: *
+ * *
+ * Changes globals col, numCols, numLines, LineBuf, fEof, fBof and *
+ * line. *
+ * *
+ * DESCRIPTION: *
+ * *
+ * Advances current file position to the right, then returns the *
+ * character found there. Reads through blank lines if necessary *
+ * *
+ ****************************************************************************/
+
+int
+rgetc ()
+{
+
+ if (fEof) return (int)EOF; /* We already hit EOF last time */
+
+ if (++col >= numCols) /* If next character is on the next line ... */
+ {
+ /* ... get next non-blank line (or EOF) */
+ while ( ++line < numLines &&
+ !(numCols = GetLine (line, (char far *)LineBuf, pFile)));
+
+ if (line >= numLines)
+ { /* Oh, no more lines */
+ fEof = TRUE;
+ return (int)EOF;
+ }
+
+ col = 0; /* We got a line, so start in column 0 */
+ }
+
+ fBof = FALSE; /* We got something, so we can't be at BOF */
+ return LineBuf[col];
+}
+
+
+/****************************************************************************
+ * *
+ * ngetc() *
+ * *
+ * RETURNS: *
+ * *
+ * Character at current position. EOF or BOF if we are at end or top *
+ * of file. *
+ * *
+ ****************************************************************************/
+
+int
+ngetc()
+{
+ if (fEof) return (int)EOF;
+ if (fBof) return (int)BOF;
+
+ return LineBuf[col];
+}
+
+
+/****************************************************************************
+ * *
+ * lgetc () *
+ * *
+ * RETURNS: *
+ * *
+ * Previous character in file, not including line terminators. EOF *
+ * if there are no more. *
+ * *
+ * SIDE EFFECTS: *
+ * *
+ * Changes globals col, numCols, numLines, LineBuf, fEof, fBof and *
+ * line. *
+ * *
+ * DESCRIPTION: *
+ * *
+ * Decrements current file position to the right, then returns the *
+ * character found there. Reads through blank lines if necessary *
+ * *
+ ****************************************************************************/
+
+int
+lgetc ()
+{
+ if (fBof) return (int)BOF; /* We already it BOF last time */
+
+ if (--col < 0)
+ { /* If prev character is on prev line ... */
+ /* ... get prev non-blank line (or BOF) */
+ while ( --line >= 0 &&
+ !(numCols = GetLine (line, (char far *)LineBuf, pFile)));
+
+ if (line < 0)
+ { /* We're at the top of the file */
+ fBof = TRUE;
+ return (int)BOF;
+ }
+
+ col = numCols - 1; /* We got a line, so start at last character */
+ }
+
+ fEof = (int)FALSE;
+ return LineBuf[col];
+}
+
+
+/****************************************************************************
+ * *
+ * pos (&x, &y) *
+ * *
+ * SIDE EFFECTS: *
+ * *
+ * Fills memory at *x and *y with current file position. *
+ * *
+ * DESCRIPTION: *
+ * *
+ * Gets the current file position. Far pointers are needed because *
+ * SS != DS. *
+ * *
+ ****************************************************************************/
+
+void pos (fpx, fpy)
+COL far *fpx;
+LINE far *fpy;
+{
+ *fpx = col;
+ *fpy = line;
+}
+
+
+/****************************************************************************
+ * *
+ * No special switches. *
+ * *
+ ****************************************************************************/
+
+struct swiDesc swiTable[] =
+{
+ { NULL, NULL, (int)NULL }
+};
+
+
+/****************************************************************************
+ * *
+ * <pmatch> is a cursor func, takes no arguments. *
+ * *
+ ****************************************************************************/
+
+struct cmdDesc cmdTable[] =
+{
+ { "pmatch", (funcCmd) PMatch, 0, CURSORFUNC },
+ { NULL, NULL, (unsigned)NULL, (unsigned)NULL }
+};
+
+
+/****************************************************************************
+ * *
+ * WhenLoaded () *
+ * *
+ * DESCRIPTION: *
+ * *
+ * Attach to ALT+P and issue sign-on message. *
+ * *
+ ****************************************************************************/
+
+void EXTERNAL WhenLoaded ()
+{
+ DoMessage (EXT_ID);
+ SetKey ("pmatch", "alt+p");
+}
diff --git a/private/utils/mep/extens/pmatch/pmatch.def b/private/utils/mep/extens/pmatch/pmatch.def
new file mode 100644
index 000000000..b26d5a74b
--- /dev/null
+++ b/private/utils/mep/extens/pmatch/pmatch.def
@@ -0,0 +1,7 @@
+LIBRARY PMATCH
+
+DESCRIPTION 'MEP extension'
+
+EXPORTS
+ EntryPoint
+ ModInfo
diff --git a/private/utils/mep/extens/pmatch/pmatch.rc b/private/utils/mep/extens/pmatch/pmatch.rc
new file mode 100644
index 000000000..863f2cf7f
--- /dev/null
+++ b/private/utils/mep/extens/pmatch/pmatch.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Parenthesis Match Utility"
+#define VER_INTERNALNAME_STR "pmatch"
+#define VER_ORIGINALNAME_STR "PMATCH.DLL"
+
+#include "common.ver"
diff --git a/private/utils/mep/extens/pmatch/sources b/private/utils/mep/extens/pmatch/sources
new file mode 100644
index 000000000..c0fce1efe
--- /dev/null
+++ b/private/utils/mep/extens/pmatch/sources
@@ -0,0 +1,16 @@
+MAJORCOMP=utils
+MINORCOMP=mep
+
+TARGETNAME=pmatch
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+LINKLIBS=\nt\public\sdk\lib\*\exthdr.lib
+
+INCLUDES=.;..\..\inc;\nt\private\sdktools\ztools\inc
+
+SOURCES= pmatch.c pmatch.rc
+
+C_DEFINES=-D_OS2_20_=0 -DNO_EXT_KEYS -DEXTERNAL= -DEXPORT= -Dpascal= -Dfar= -DNOLANMAN -DNT
+UMTYPE=console
+UMRES=obj\*\pmatch.res
+ \ No newline at end of file
diff --git a/private/utils/mep/extens/skel/makefile b/private/utils/mep/extens/skel/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/mep/extens/skel/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/mep/extens/skel/skel.c b/private/utils/mep/extens/skel/skel.c
new file mode 100644
index 000000000..164c7316a
--- /dev/null
+++ b/private/utils/mep/extens/skel/skel.c
@@ -0,0 +1,101 @@
+/*** skel.c - skeleton for editor extension
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Purpose:
+* Example source code for a loadable C editor extension.
+*
+* NOTE: This code is shipped with the product! This note and the revision
+* history should be removed before shipping.
+*
+* Revision History:
+* 24-Sep-1991 rs Ported to Windows NT
+* 16-Jan-1987 mz Add pascal typing. Export switch set
+* 21-May-1987 bw Add return from WhenLoaded for OS/2
+* 22-Oct-1987 mz Correct definitions as headers
+* 22-Jun-1988 ln Updated and documented
+* 12-Sep-1988 mz Made WhenLoaded match declaration
+*
+*************************************************************************/
+
+#include "ext.h"
+
+
+/** Skel - Sample Editing Function
+*
+* Purpose:
+* Sample editing function entry point.
+*
+* Editor functions are commands that can be attached to keys and are invoked
+* when those keys are struck.
+*
+* Input:
+* argData = Value of the keystroke used to invoke the function
+* pArg = Far pointer to a structure which defines the type of argument
+* passed by the invoker of the function
+* fMeta = Flag indicating whether the meta modifier was on at the time
+* the function was executed.
+*
+* Output:
+* Editor functions are expected to return a boolean value indicating success
+* or failure. Typically, TRUE is returned in the normal case. These values
+* can be tested inside of macros.
+*
+************************************************************************/
+flagType
+pascal
+EXTERNAL
+Skel (
+ unsigned int argData,
+ ARG far * pArg,
+ flagType fMeta
+ )
+{
+ return TRUE;
+}
+
+
+/*** WhenLoaded - Extension Initialization
+*
+* Purpose:
+* This function is called whenever the extension is loaded into memory.
+* Extension initialization may occur here.
+*
+* Input:
+* none
+*
+* Output:
+* none
+*
+*************************************************************************/
+void
+EXTERNAL
+WhenLoaded (
+ void
+ )
+{
+}
+
+
+//
+// Command description table. This is a vector of command descriptions that
+// contain the textual name of the function (for user assignment), a pointer
+// to the function to be called, and some data describing the type of
+// arguments that the function can take.
+//
+struct cmdDesc cmdTable[] = {
+ { "skel", Skel, 0, NOARG },
+ { NULL, NULL, NULL, NULL }
+};
+
+
+//
+// Switch description table. This is a vector of switch descriptions that
+// contain the textual name of the switch (for user assignment), a pointer to
+// the switch itself or a function to be called, and some data describing the
+// type of switch.
+//
+struct swiDesc swiTable[] =
+{
+ {NULL, NULL, NULL }
+};
diff --git a/private/utils/mep/extens/skel/skel.def b/private/utils/mep/extens/skel/skel.def
new file mode 100644
index 000000000..8a54c2d81
--- /dev/null
+++ b/private/utils/mep/extens/skel/skel.def
@@ -0,0 +1,10 @@
+; Any Editor extension for OS/2 Protect mode must be linked
+; with this .DEF file. The resulting .DLL file must be
+; placed in a directory pointed to by LIBPATH
+
+LIBRARY skel
+DATA MULTIPLE
+
+EXPORTS
+ ModInfo
+ EntryPoint
diff --git a/private/utils/mep/extens/skel/sources b/private/utils/mep/extens/skel/sources
new file mode 100644
index 000000000..61fa76bb0
--- /dev/null
+++ b/private/utils/mep/extens/skel/sources
@@ -0,0 +1,14 @@
+MAJORCOMP=utils
+MINORCOMP=mep
+
+TARGETNAME=skel
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+TARGETLIBS=\nt\public\sdk\lib\*\exthdr.lib
+
+INCLUDES=.;..\..\inc;\nt\private\sdktools\ztools\inc
+
+SOURCES= skel.c
+
+C_DEFINES=
+UMTYPE=console
diff --git a/private/utils/mep/extens/tglcase/makefile b/private/utils/mep/extens/tglcase/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/mep/extens/tglcase/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/mep/extens/tglcase/sources b/private/utils/mep/extens/tglcase/sources
new file mode 100644
index 000000000..bc696bc61
--- /dev/null
+++ b/private/utils/mep/extens/tglcase/sources
@@ -0,0 +1,16 @@
+MAJORCOMP=utils
+MINORCOMP=mep
+
+TARGETNAME=tglcase
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+LINKLIBS=\nt\public\sdk\lib\*\exthdr.lib
+
+INCLUDES=.;..\..\inc;\nt\private\sdktools\ztools\inc
+
+SOURCES= tglcase.c tglcase.rc
+
+C_DEFINES=-D_OS2_20_=0 -DNO_EXT_KEYS -DEXTERNAL= -DEXPORT= -Dpascal= -Dfar= -DNOLANMAN -DNT
+UMTYPE=console
+UMRES=obj\*\tglcase.res
+ \ No newline at end of file
diff --git a/private/utils/mep/extens/tglcase/tglcase.c b/private/utils/mep/extens/tglcase/tglcase.c
new file mode 100644
index 000000000..0a54eddd7
--- /dev/null
+++ b/private/utils/mep/extens/tglcase/tglcase.c
@@ -0,0 +1,172 @@
+/*** tglcase.c - case toggling editor extension
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Purpose:
+* Contains the tglcase function.
+*
+* Revision History:
+*
+* 28-Jun-1988 LN Created
+* 12-Sep-1988 mz Made WhenLoaded match declaration
+*
+*************************************************************************/
+#define EXT_ID " tglcase ver 1.00 "##__DATE__##" "##__TIME__
+
+#include <stdlib.h> /* min macro definition */
+#include <string.h> /* prototypes for string fcns */
+#include "ext.h"
+/*
+** Internal function prototypes
+*/
+void pascal id (char *);
+void EXTERNAL WhenLoaded (void);
+flagType pascal EXTERNAL tglcase (unsigned int, ARG far *, flagType);
+
+/*************************************************************************
+**
+** tglcase
+** Toggle the case of alphabetics contaied within the selected argument:
+**
+** NOARG - Toggle case of entire current line
+** NULLARG - Toggle case of current line, from cursor to end of line
+** LINEARG - Toggle case of range of lines
+** BOXARG - Toggle case of characters with the selected box
+** NUMARG - Converted to LINEARG before extension is called.
+** MARKARG - Converted to Appropriate ARG form above before extension is
+** called.
+**
+** STREAMARG - Not Allowed. Treated as BOXARG
+** TEXTARG - Not Allowed
+**
+*/
+flagType pascal EXTERNAL tglcase (
+ unsigned int argData, /* keystroke invoked with */
+ ARG *pArg, /* argument data */
+ flagType fMeta /* indicates preceded by meta */
+ )
+{
+PFILE pFile; /* file handle of current file */
+COL xStart; /* left border of arg area */
+LINE yStart; /* starting line of arg area */
+COL xEnd; /* right border of arg area */
+LINE yEnd; /* ending line of arg area */
+int cbLine; /* byte count of current line */
+COL xCur; /* current column being toggled */
+char buf[BUFLEN]; /* buffer for line being toggled*/
+register char c; /* character being analyzed */
+
+ //
+ // Unreferenced parameters
+ //
+ (void)argData;
+ (void)fMeta;
+
+id ("");
+pFile = FileNameToHandle ("", "");
+
+switch (pArg->argType) {
+/*
+** For the various argument types, set up a box (xStart, yStart) - (xEnd, yEnd)
+** over which the case conversion code below can operate.
+*/
+ case NOARG: /* case switch entire line */
+ xStart = 0;
+ xEnd = 256;
+ yStart = yEnd = pArg->arg.noarg.y;
+ break;
+
+ case NULLARG: /* case switch to EOL */
+ xStart = pArg->arg.nullarg.x;
+ xEnd = 32765;
+ yStart = yEnd = pArg->arg.nullarg.y;
+ break;
+
+ case LINEARG: /* case switch line range */
+ xStart = 0;
+ xEnd = 32765;
+ yStart = pArg->arg.linearg.yStart;
+ yEnd = pArg->arg.linearg.yEnd;
+ break;
+
+ case BOXARG: /* case switch box */
+ xStart = pArg->arg.boxarg.xLeft;
+ xEnd = pArg->arg.boxarg.xRight;
+ yStart = pArg->arg.boxarg.yTop;
+ yEnd = pArg->arg.boxarg.yBottom;
+ break;
+ }
+/*
+** Within the range of lines yStart to yEnd, get each line, and if non-null,
+** check each character. If alphabetic, replace with it's case-converted
+** value. After all characters have been checked, replace line in file.
+*/
+while (yStart <= yEnd) {
+ if (cbLine = GetLine (yStart, buf, pFile)) {
+ for (xCur = xStart; (xCur <= min(cbLine, xEnd)); xCur++) {
+ c = buf[xCur];
+ if ((c >= 'A') && (c <= 'Z'))
+ c += 'a'-'A';
+ else if ((c >= 'a') && (c <= 'z'))
+ c += 'A'-'a';
+ buf[xCur] = c;
+ }
+ PutLine (yStart++, buf, pFile);
+ }
+ }
+return 1;
+}
+
+/*************************************************************************
+**
+** WhenLoaded
+** Executed when extension gets loaded. Identify self & assign default
+** keystroke.
+**
+** Entry:
+** none
+*/
+void EXTERNAL WhenLoaded () {
+
+id("case conversion extension:");
+SetKey ("tglcase", "alt+c");
+/* end WhenLoaded */}
+
+/*************************************************************************
+**
+** id
+** identify ourselves, along with any passed informative message.
+**
+** Entry:
+** pszMsg = Pointer to asciiz message, to which the extension name
+** and version are appended prior to display.
+*/
+void pascal id (pszFcn)
+char *pszFcn; /* function name */
+{
+char buf[80]; /* message buffer */
+
+strcpy (buf,pszFcn); /* start with message */
+strcat (buf,EXT_ID); /* append version */
+DoMessage (buf);
+/* end id */}
+
+
+/*************************************************************************
+**
+** Switch communication table to the editor.
+** This extension defines no switches.
+*/
+struct swiDesc swiTable[] = {
+ {0, 0, 0}
+ };
+
+/*************************************************************************
+**
+** Command communication table to the editor.
+** Defines the name, location and acceptable argument types.
+*/
+struct cmdDesc cmdTable[] = {
+ {"tglcase", (funcCmd) tglcase,0, KEEPMETA | NOARG | BOXARG | NULLARG | LINEARG | MARKARG | NUMARG | MODIFIES},
+ {0, 0, 0}
+ };
diff --git a/private/utils/mep/extens/tglcase/tglcase.def b/private/utils/mep/extens/tglcase/tglcase.def
new file mode 100644
index 000000000..254e57449
--- /dev/null
+++ b/private/utils/mep/extens/tglcase/tglcase.def
@@ -0,0 +1,7 @@
+LIBRARY TGLCASE
+
+DESCRIPTION 'MEP extension'
+
+EXPORTS
+ EntryPoint
+ ModInfo
diff --git a/private/utils/mep/extens/tglcase/tglcase.rc b/private/utils/mep/extens/tglcase/tglcase.rc
new file mode 100644
index 000000000..91cef6ba7
--- /dev/null
+++ b/private/utils/mep/extens/tglcase/tglcase.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "TGL Utility for MEP"
+#define VER_INTERNALNAME_STR "tglcase"
+#define VER_ORIGINALNAME_STR "TGLCASE.DLL"
+
+#include "common.ver"
diff --git a/private/utils/mep/extens/ulcase/makefile b/private/utils/mep/extens/ulcase/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/mep/extens/ulcase/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/mep/extens/ulcase/sources b/private/utils/mep/extens/ulcase/sources
new file mode 100644
index 000000000..bde2cba39
--- /dev/null
+++ b/private/utils/mep/extens/ulcase/sources
@@ -0,0 +1,16 @@
+MAJORCOMP=utils
+MINORCOMP=mep
+
+TARGETNAME=ulcase
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+LINKLIBS=\nt\public\sdk\lib\*\exthdr.lib
+
+INCLUDES=.;..\..\inc;\nt\private\sdktools\ztools\inc
+
+SOURCES= ulcase.c ulcase.rc
+
+C_DEFINES=-D_OS2_20_=0 -DNO_EXT_KEYS -DEXTERNAL= -DEXPORT= -Dpascal= -Dfar= -DNOLANMAN -DNT
+UMTYPE=console
+UMRES=obj\*\ulcase.res
+ \ No newline at end of file
diff --git a/private/utils/mep/extens/ulcase/ulcase.c b/private/utils/mep/extens/ulcase/ulcase.c
new file mode 100644
index 000000000..607d74980
--- /dev/null
+++ b/private/utils/mep/extens/ulcase/ulcase.c
@@ -0,0 +1,166 @@
+#define EXT_ID " ulcase ver 2.01 "##__DATE__##" "##__TIME__
+/*
+** ULcase Z extension
+**
+** History:
+** 30-Mar-1988 Broken out of "myext"
+** 12-Sep-1988 mz Made WhenLoaded match declaration
+*/
+#include <ctype.h>
+
+#include "ext.h"
+
+#ifndef TRUE
+#define TRUE -1
+#define FALSE 0
+#endif
+
+#ifndef NULL
+#define NULL ((char *) 0)
+#endif
+
+flagType pascal ulcase (ARG *, int, int, int);
+
+/*************************************************************************
+**
+** id
+** identify the source of the operation being performed
+*/
+void id(char *pszFcn)
+{
+char buf[80]; /* message buffer */
+
+strcpy (buf,pszFcn); /* start with message */
+strcat (buf,EXT_ID); /* append version */
+DoMessage (buf);
+}
+
+/*************************************************************************
+**
+** ucase
+** convert arg to upper case.
+*/
+flagType pascal EXTERNAL
+ucase (
+ CMDDATA argData,
+ ARG far *pArg,
+ flagType fMeta
+ )
+{
+
+(void)argData;
+(void)fMeta;
+id("ucase:");
+return ulcase (pArg, 'a', 'z', 'A'-'a');
+}
+
+/*************************************************************************
+**
+** lcase
+** convert arg to lower case.
+*/
+flagType pascal EXTERNAL
+lcase (
+ CMDDATA argData,
+ ARG far *pArg,
+ flagType fMeta
+ )
+{
+(void)argData;
+(void)fMeta;
+id("lcase:");
+return ulcase (pArg, 'A', 'Z', 'a'-'A');
+}
+
+/*
+** ulcase
+** convert arg case.
+*/
+flagType pascal ulcase (pArg, cLow, cHigh, cAdj)
+ARG *pArg; /* argument data */
+int cLow; /* low char of range to check for */
+int cHigh; /* high char of range to check for */
+int cAdj; /* adjustment to make */
+{
+PFILE pFile;
+COL xStart;
+LINE yStart;
+COL xEnd;
+LINE yEnd;
+int i;
+COL xT;
+char buf[BUFLEN];
+
+
+pFile = FileNameToHandle ("", "");
+
+switch (pArg->argType) {
+
+ case NOARG: /* case switch entire line */
+ xStart = 0;
+ xEnd = 32765;
+ yStart = yEnd = pArg->arg.noarg.y;
+ break;
+
+ case NULLARG: /* case switch to EOL */
+ xStart = pArg->arg.nullarg.x;
+ xEnd = 32765;
+ yStart = yEnd = pArg->arg.nullarg.y;
+ break;
+
+ case LINEARG: /* case switch line range */
+ xStart = 0;
+ xEnd = 32765;
+ yStart = pArg->arg.linearg.yStart;
+ yEnd = pArg->arg.linearg.yEnd;
+ break;
+
+ case BOXARG: /* case switch box */
+ xStart = pArg->arg.boxarg.xLeft;
+ xEnd = pArg->arg.boxarg.xRight;
+ yStart = pArg->arg.boxarg.yTop;
+ yEnd = pArg->arg.boxarg.yBottom;
+ break;
+ }
+
+while (yStart <= yEnd) {
+ i = GetLine (yStart, buf, pFile);
+ xT = xStart; /* start at begin of box*/
+ while ((xT <= i) && (xT <= xEnd)) { /* while in box */
+ if ((int)buf[xT] >= cLow && (int)buf[xT] <= cHigh)
+ buf[xT] += (char)cAdj;
+ xT++;
+ }
+ PutLine (yStart++, buf, pFile);
+ }
+
+return TRUE;
+}
+
+/*
+** switch communication table to Z
+*/
+struct swiDesc swiTable[] = {
+ {0, 0, 0}
+ };
+
+/*
+** command communication table to Z
+*/
+struct cmdDesc cmdTable[] = {
+ { "ucase", ucase, 0, MODIFIES | KEEPMETA | NOARG | BOXARG | NULLARG | LINEARG },
+ { "lcase", lcase, 0, MODIFIES | KEEPMETA | NOARG | BOXARG | NULLARG | LINEARG },
+ {0, 0, 0}
+ };
+
+/*
+** WhenLoaded
+** Executed when these extensions get loaded. Identify self & assign keys.
+*/
+void EXTERNAL WhenLoaded () {
+
+id("case conversion:");
+SetKey ("ucase", "alt+u");
+SetKey ("lcase", "alt+l");
+}
+
diff --git a/private/utils/mep/extens/ulcase/ulcase.def b/private/utils/mep/extens/ulcase/ulcase.def
new file mode 100644
index 000000000..b25a1c699
--- /dev/null
+++ b/private/utils/mep/extens/ulcase/ulcase.def
@@ -0,0 +1,7 @@
+LIBRARY ULCASE
+
+DESCRIPTION 'MEP extension'
+
+EXPORTS
+ EntryPoint
+ ModInfo
diff --git a/private/utils/mep/extens/ulcase/ulcase.rc b/private/utils/mep/extens/ulcase/ulcase.rc
new file mode 100644
index 000000000..a3e69cf13
--- /dev/null
+++ b/private/utils/mep/extens/ulcase/ulcase.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Upper Case Utility for MEP"
+#define VER_INTERNALNAME_STR "ulcase"
+#define VER_ORIGINALNAME_STR "ULCASE.DLL"
+
+#include "common.ver"
diff --git a/private/utils/mep/extens/winclip/makefile b/private/utils/mep/extens/winclip/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/mep/extens/winclip/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/mep/extens/winclip/sources b/private/utils/mep/extens/winclip/sources
new file mode 100644
index 000000000..1795455b9
--- /dev/null
+++ b/private/utils/mep/extens/winclip/sources
@@ -0,0 +1,21 @@
+MAJORCOMP=utils
+MINORCOMP=mep
+
+TARGETNAME=winclip
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+LINKLIBS= \
+ $(BASEDIR)\public\sdk\lib\*\exthdr.lib \
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib
+
+
+INCLUDES=.
+
+SOURCES= winclip.c winclip.rc
+
+C_DEFINES=-D_OS2_20_=0 -DNO_EXT_KEYS -DEXTERNAL= -DEXPORT= -Dpascal= -Dfar= -DNOLANMAN -DNT
+
+DLLBASE=0x1000000
+UMTYPE=console
+UMRES=obj\*\winclip.res
diff --git a/private/utils/mep/extens/winclip/winclip.c b/private/utils/mep/extens/winclip/winclip.c
new file mode 100644
index 000000000..f42933eb0
--- /dev/null
+++ b/private/utils/mep/extens/winclip/winclip.c
@@ -0,0 +1,830 @@
+/*** winclip.c - windows clipboard editor extension
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Purpose:
+* Contains the tglcase function.
+*
+* Revision History:
+*
+* 28-Jun-1988 LN Created
+* 12-Sep-1988 mz Made WhenLoaded match declaration
+*
+*************************************************************************/
+#define EXT_ID " winclip ver 1.00 "##__DATE__
+
+#include <windows.h>
+#include <stdlib.h> /* min macro definition */
+#include <string.h> /* prototypes for string fcns */
+
+#undef pascal
+#include "../../inc/ext.h"
+
+#define M_FALSE ((flagType)0)
+#define M_TRUE ((flagType)(-1))
+
+#define BUFLEN_MAX (BUFLEN-1)
+
+/*
+** Internal function prototypes
+*/
+void pascal id (char *);
+void EXTERNAL WhenLoaded (void);
+flagType pascal EXTERNAL wincopy (unsigned int, ARG far *, flagType);
+flagType pascal EXTERNAL wincut (unsigned int, ARG far *, flagType);
+flagType pascal EXTERNAL winpaste (unsigned int, ARG far *, flagType);
+
+#ifdef DEBUG
+# define DPRINT(p) DoMessage(p)
+#else
+# define DPRINT(p)
+#endif
+
+HWND ghwndClip;
+HINSTANCE ghmod;
+int gfmtArgType;
+
+void DeleteArg( PFILE pFile, int argType, COL xStart, LINE yStart,
+ COL xEnd, COL yEnd );
+
+void InsertText( PFILE pFile, LPSTR pszText, DWORD dwInsMode,
+ COL xStart, LINE yStart );
+flagType pascal EXTERNAL WinCutCopy (ARG *pArg, flagType fCut, flagType fClip);
+LPSTR EndOfLine( LPSTR psz );
+LPSTR EndOfBreak( LPSTR psz );
+int ExtendLine( LPSTR psz, int cchSZ, char ch, int cchNew );
+
+/*************************************************************************
+**
+** wincopy
+** Toggle the case of alphabetics contaied within the selected argument:
+**
+** NOARG - Toggle case of entire current line
+** NULLARG - Toggle case of current line, from cursor to end of line
+** LINEARG - Toggle case of range of lines
+** BOXARG - Toggle case of characters with the selected box
+** NUMARG - Converted to LINEARG before extension is called.
+** MARKARG - Converted to Appropriate ARG form above before extension is
+** called.
+**
+** STREAMARG - Not Allowed. Treated as BOXARG
+** TEXTARG - Not Allowed
+**
+*/
+flagType pascal EXTERNAL wincopy (
+ unsigned int argData, /* keystroke invoked with */
+ ARG *pArg, /* argument data */
+ flagType fMeta /* indicates preceded by meta */
+ ) {
+
+ return WinCutCopy( pArg, M_FALSE, M_FALSE );
+}
+
+flagType pascal EXTERNAL wincut (
+ unsigned int argData, /* keystroke invoked with */
+ ARG *pArg, /* argument data */
+ flagType fMeta /* indicates preceded by meta */
+ ) {
+
+ return WinCutCopy( pArg, M_TRUE, fMeta );
+}
+
+flagType pascal EXTERNAL WinCutCopy (ARG *pArg, flagType fCut, flagType fNoClip)
+{
+ PFILE pFile; /* file handle of current file */
+ COL xStart, xEnd;
+ LINE yStart, yEnd;
+ char achLine[BUFLEN];
+ HANDLE hText;
+ LPSTR pszText;
+ int iLine, cchLine;
+ flagType fRet = M_TRUE;
+ int argSave, argType;
+
+ pFile = FileNameToHandle ("", "");
+
+
+ argSave = argType = pArg->argType;
+
+ switch( argType ) {
+ case BOXARG: /* case switch box */
+ xStart = pArg->arg.boxarg.xLeft;
+ xEnd = pArg->arg.boxarg.xRight + 1;
+ yStart = pArg->arg.boxarg.yTop;
+ yEnd = pArg->arg.boxarg.yBottom + 1;
+
+ /* At this point...
+ * [xy]Start is Inclusive, [xy]End is EXCLUSIVE of the box arg
+ */
+
+#ifdef DEBUG
+ wsprintf( achLine, " BoxDims : %d %d %d %d ", (int)xStart, (int)yStart, (int)xEnd, (int)yEnd);
+ DoMessage( achLine );
+#endif
+ break;
+
+ case NOARG:
+ /* convert NOARG to a STREAMARG on whole current line */
+ argType = STREAMARG;
+ argSave = LINEARG;
+ xStart = 0;
+ yStart = pArg->arg.noarg.y;
+ xEnd = 0;
+ yEnd = yStart + 1;
+ break;
+
+ case TEXTARG:
+ /*
+ * Text args are only for real text. NumArgs and MarkArgs are
+ * converted to stream or box args by the editor since we say
+ * we accept NUMARG and MARKARG during initialization.
+ */
+ argType = STREAMARG;
+ argSave = STREAMARG;
+ xStart = pArg->arg.textarg.x;
+ xEnd = lstrlen(pArg->arg.textarg.pText) + xStart;
+ yStart = yEnd = pArg->arg.textarg.y;
+ break;
+
+ case LINEARG: /* case switch line range */
+ /* convert LINEARG to a STREAMARG so we don't get lots of white space*/
+ argType = STREAMARG;
+ xStart = 0;
+ xEnd = 0;
+ yStart = pArg->arg.linearg.yStart;
+ yEnd = pArg->arg.linearg.yEnd + 1;
+#ifdef DEBUG
+ wsprintf( achLine, " LineDims : %d %d %d %d ", (int)xStart, (int)yStart, (int)xEnd, (int)yEnd);
+ DoMessage( achLine );
+#endif
+
+ /* At this point...
+ * [xy]Start is Inclusive, [xy]End is EXCLUSIVE of the line arg
+ */
+
+ break;
+
+ case STREAMARG:
+ /*
+ * Set Start == first char pos in stream, End == first char pos
+ * AFTER stream.
+ */
+ xStart = pArg->arg.streamarg.xStart;
+ xEnd = pArg->arg.streamarg.xEnd;
+ yStart = pArg->arg.streamarg.yStart;
+ yEnd = pArg->arg.streamarg.yEnd;
+#ifdef DEBUG
+ wsprintf( achLine, " StreamDims : %d %d %d %d ", (int)xStart, (int)yStart, (int)xEnd, (int)yEnd);
+ DoMessage( achLine );
+#endif
+ break;
+
+ default:
+#ifdef DEBUG
+ wsprintf( achLine, " Unknown Arg: 0x%04x", argType );
+ DoMessage( achLine );
+ return M_TRUE;
+#endif
+ return M_FALSE;
+ }
+
+ if (!fNoClip) {
+ if (argType == STREAMARG) {
+ int cch = 0;
+ int iChar;
+
+ for( iLine = yStart; iLine <= yEnd; iLine++ )
+ cch += GetLine (iLine, achLine, pFile) + 3;
+
+ hText = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, cch);
+
+ if (hText == NULL) {
+ DoMessage( " winclip: Out of Memory" );
+ return M_FALSE;
+ }
+
+ pszText = GlobalLock(hText);
+
+
+ iChar = xStart;
+
+ for( iLine = yStart; iLine < yEnd; iLine++ ) {
+ cchLine = GetLine (iLine, achLine, pFile);
+
+ /* Incase we start after the end of the line */
+ if (cchLine < iChar)
+ cch = 0;
+ else
+ cch = cchLine - iChar;
+
+ CopyMemory(pszText, &achLine[iChar], cch);
+ pszText += cch;
+ strcpy( pszText, "\r\n" );
+ pszText += 2;
+ iChar = 0;
+
+ }
+
+ /* Get partial last line */
+ if (xEnd != 0) {
+ cchLine = GetLine (iLine, achLine, pFile);
+
+ /* if line is short, then pad it out */
+ cchLine = ExtendLine( achLine, cchLine, ' ', xEnd );
+
+ if (cchLine < iChar)
+ cchLine = 0;
+ else
+ cchLine = xEnd - iChar;
+
+ CopyMemory(pszText, &achLine[iChar], cchLine);
+ pszText += cchLine;
+ }
+
+ } else {
+ LINE iLine;
+ int cchBox = xEnd - xStart;
+
+ hText = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
+ (yEnd - yStart) * (cchBox + 3));
+
+ if (hText == NULL) {
+ DoMessage( " winclip: Out of Memory" );
+ return M_FALSE;
+ }
+
+ pszText = GlobalLock(hText);
+
+ for( iLine = yStart; iLine < yEnd; iLine++ ) {
+ cchLine = GetLine (iLine, achLine, pFile);
+
+ if (argType == BOXARG)
+ cchLine = ExtendLine( achLine, cchLine, ' ', xEnd );
+
+ if (cchLine < xStart )
+ cchLine = 0;
+ else
+ cchLine -= xStart;
+
+ cchLine = min(cchLine, cchBox);
+
+ CopyMemory(pszText, &achLine[xStart], cchLine);
+ pszText += cchLine;
+ strcpy( pszText, "\r\n" );
+ pszText += 2;
+
+ }
+ }
+
+ *pszText = '\0';
+
+ GlobalUnlock(hText);
+
+ if (OpenClipboard(ghwndClip)) {
+ EmptyClipboard();
+
+ /*
+ * Set the text into the clipboard
+ */
+ if (SetClipboardData(CF_TEXT, hText) == hText) {
+ /*
+ * Remember the Arg type for pasting back
+ */
+ if (gfmtArgType != 0) {
+ DWORD *pdw;
+ HANDLE hArgType = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE,
+ sizeof(DWORD));
+
+ if (hArgType != NULL && (pdw = GlobalLock(hArgType)) != NULL) {
+ *pdw = (DWORD)(argSave);
+
+ GlobalUnlock(hArgType);
+
+ SetClipboardData(gfmtArgType, hArgType);
+ }
+ }
+ } else {
+ /* An error occured writing text to clipboard */
+
+ wsprintf(achLine, " winclip: Error (%ld) setting data",
+ GetLastError());
+ DoMessage( achLine );
+ fRet = M_FALSE;
+ }
+
+ CloseClipboard();
+ }
+ }
+
+ /*
+ * No need to free the handle, USER32 will do it (yes it keeps
+ * track of the client side handle) when we set the next clipboard
+ * data. (Love that Win3.1 compatibility!)
+ */
+ if (fRet && fCut)
+ DeleteArg( pFile, argType, xStart, yStart, xEnd, yEnd );
+
+
+ return fRet;
+}
+
+/*************************************************************************
+**
+** winpaste
+** Toggle the case of alphabetics contaied within the selected argument:
+**
+** NOARG - Toggle case of entire current line
+** NULLARG - Toggle case of current line, from cursor to end of line
+** LINEARG - Toggle case of range of lines
+** BOXARG - Toggle case of characters with the selected box
+** NUMARG - Converted to LINEARG before extension is called.
+** MARKARG - Converted to Appropriate ARG form above before extension is
+** called.
+**
+** STREAMARG - Not Allowed. Treated as BOXARG
+** TEXTARG - Not Allowed
+**
+*/
+flagType pascal EXTERNAL winpaste (
+ unsigned int argData, /* keystroke invoked with */
+ ARG *pArg, /* argument data */
+ flagType fMeta /* indicates preceded by meta */
+ )
+{
+ PFILE pFile; /* file handle of current file */
+ COL xStart, xEnd;
+ LINE yStart, yEnd;
+ int argType;
+ UINT fmtData = CF_TEXT;
+ DWORD dwInsMode = STREAMARG;
+ HANDLE hText;
+ LPSTR pszText;
+
+ /*
+ * Get the clipboard text and insertion type
+ */
+ if (pArg->argType == TEXTARG) {
+ int i, j;
+ char achLine[3 + 1 + 3 + 1 + 1 + BUFLEN + 1 + 1 + 5 + 1];
+ char *p;
+
+ /*
+ * Quick hack to make text arg pastes work like the do in MEP
+ */
+ j = pArg->arg.textarg.cArg;
+ if (j > 2)
+ j = 2;
+
+ achLine[0] = '\0';
+ for( i = 0; i < j; i++ )
+ lstrcat(achLine, "arg ");
+
+ p = achLine + lstrlen(achLine);
+ wsprintf( p, "\"%s\" paste", pArg->arg.textarg.pText );
+ return fExecute( achLine );
+ }
+
+ /* if no text then return FALSE */
+ if (!IsClipboardFormatAvailable(fmtData)) {
+
+ /* No text, try display text */
+ fmtData = CF_DSPTEXT;
+
+ if (!IsClipboardFormatAvailable(fmtData)) {
+ /* bummer! no text at all, return FALSE */
+ DoMessage( " winclip: invalid clipboard format" );
+ return M_FALSE;
+ }
+ }
+
+ if (!OpenClipboard(ghwndClip))
+ return M_FALSE;
+
+ hText = GetClipboardData(fmtData);
+ if (hText == NULL || (pszText = GlobalLock(hText)) == NULL) {
+ CloseClipboard();
+ return M_FALSE;
+ }
+
+
+ /* Get insert mode */
+
+ if (IsClipboardFormatAvailable(gfmtArgType)) {
+ DWORD *pdw;
+ HANDLE hInsMode;
+
+ hInsMode = GetClipboardData(gfmtArgType);
+
+ if (hInsMode != NULL && (pdw = GlobalLock(hInsMode)) != NULL) {
+ dwInsMode = *pdw;
+
+ GlobalUnlock(hInsMode);
+ }
+ }
+
+
+
+ pFile = FileNameToHandle ("", "");
+
+ argType = pArg->argType;
+
+ switch( argType ) {
+ case BOXARG: /* case switch box */
+ /*
+ * Set [xy]Start inclusive of box arg,
+ * [xy]End exclusive of box arg.
+ */
+ xStart = pArg->arg.boxarg.xLeft;
+ xEnd = pArg->arg.boxarg.xRight + 1;
+ yStart = pArg->arg.boxarg.yTop;
+ yEnd = pArg->arg.boxarg.yBottom + 1;
+ break;
+
+ case LINEARG: /* case switch line range */
+ /*
+ * Set [xy]Start inclusive of line arg,
+ * [xy]End exclusive of line arg.
+ */
+ xStart = 0;
+ xEnd = BUFLEN + 1;
+ yStart = pArg->arg.linearg.yStart;
+ yEnd = pArg->arg.linearg.yEnd + 1;
+ break;
+
+ case STREAMARG:
+ /*
+ * Set [xy]Start inclusive of stream
+ * xEnd is EXCLUSIVE of stream
+ * yEnd is INCLUSIVE of stream
+ */
+ xStart = pArg->arg.streamarg.xStart;
+ xEnd = pArg->arg.streamarg.xEnd;
+ yStart = pArg->arg.streamarg.yStart;
+ yEnd = pArg->arg.streamarg.yEnd;
+ break;
+
+ case NOARG:
+ xStart = pArg->arg.noarg.x;
+ xEnd = xStart + 1;
+ yStart = pArg->arg.noarg.y;
+ yEnd = yStart + 1;
+ break;
+
+ default:
+ GlobalUnlock(hText);
+ CloseClipboard();
+ return M_FALSE;
+ }
+
+
+ /*
+ * Delete any selection
+ */
+ DeleteArg( pFile, argType, xStart, yStart, xEnd, yEnd );
+
+ /*
+ * Insert new text with correct mode
+ */
+ InsertText( pFile, pszText, dwInsMode, xStart, yStart );
+
+ GlobalUnlock(hText);
+ CloseClipboard();
+
+ return M_TRUE;
+}
+
+/*************************************************************************
+**
+** windel
+**
+**
+*/
+flagType pascal EXTERNAL windel (
+ unsigned int argData, /* keystroke invoked with */
+ ARG *pArg, /* argument data */
+ flagType fMeta /* indicates preceded by meta */
+ )
+{
+ int argType = pArg->argType;
+
+ if (argType == NOARG)
+ return fExecute("delete");
+
+ if (argType == NULLARG) {
+ int c, x, y;
+ c = pArg->arg.nullarg.cArg;
+ x = pArg->arg.nullarg.x;
+ y = pArg->arg.nullarg.y;
+
+ pArg->argType = STREAMARG;
+ pArg->arg.streamarg.xStart = x;
+ pArg->arg.streamarg.xEnd = 0;
+ pArg->arg.streamarg.yStart = y;
+ pArg->arg.streamarg.yEnd = y + 1;
+ pArg->arg.streamarg.cArg = c;
+ }
+
+ return WinCutCopy (pArg, M_TRUE, fMeta);
+}
+
+/*************************************************************************
+**
+** WhenLoaded
+** Executed when extension gets loaded. Identify self & assign default
+** keystroke.
+**
+** Entry:
+** none
+*/
+void EXTERNAL WhenLoaded () {
+
+#if 0
+ WNDCLASS wc;
+
+ ghmod = GetModuleHandle(NULL);
+
+ wc.style = 0;
+ wc.lpfnWndProc = (WNDPROC)DefWindowProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = ghmod;
+ wc.hIcon = NULL;
+ wc.hCursor = NULL;
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL; /* Name of menu resource in .RC file. */
+ wc.lpszClassName = "WinClipWClass"; /* Name used in call to CreateWindow. */
+
+ if (RegisterClass(&wc) && (ghwndClip = CreateWindow( "WinClipWClass",
+ "ClipWindow", WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL,
+ ghmod, NULL)) != NULL ) {
+ id(" Windows Clipboard Extentions for MEP,");
+ } else {
+ DoMessage( " winclip: Initialization failed!" );
+ }
+#else
+ ghwndClip = NULL; //assign clipboard to this thread instead
+#endif
+
+ gfmtArgType = RegisterClipboardFormat( "MEP Arg Type" );
+
+#if 0
+ //SetKey ("wincut", "ctrl+x");
+ SetKey ("wincopy", "ctrl+c");
+ SetKey ("winpaste", "ctrl+v");
+#endif
+}
+
+/*************************************************************************
+**
+** id
+** identify ourselves, along with any passed informative message.
+**
+** Entry:
+** pszMsg = Pointer to asciiz message, to which the extension name
+** and version are appended prior to display.
+*/
+void pascal id (char *pszFcn) {
+ char buf[80];
+
+ strcpy (buf,pszFcn);
+ strcat (buf,EXT_ID);
+ DoMessage (buf);
+}
+
+
+/*************************************************************************
+**
+** Switch communication table to the editor.
+** This extension defines no switches.
+*/
+struct swiDesc swiTable[] = {
+ {0, 0, 0}
+};
+
+/*************************************************************************
+**
+** Command communication table to the editor.
+** Defines the name, location and acceptable argument types.
+*/
+struct cmdDesc cmdTable[] = {
+ {"wincopy", (funcCmd) wincopy, 0, KEEPMETA | NOARG | BOXARG | LINEARG | STREAMARG | MARKARG | NULLEOL | NUMARG },
+ {"wincut", (funcCmd) wincut, 0, NOARG | BOXARG | LINEARG | STREAMARG | MARKARG | NULLEOL | NUMARG | MODIFIES},
+ {"windel", (funcCmd) windel, 0, NOARG | BOXARG | LINEARG | STREAMARG | NULLARG | MODIFIES},
+ {"winpaste", (funcCmd) winpaste,0, KEEPMETA | NOARG | BOXARG | LINEARG | STREAMARG | TEXTARG | MODIFIES},
+ {0, 0, 0}
+};
+
+
+void DeleteArg( PFILE pFile, int argType, COL xStart, LINE yStart,
+ COL xEnd, COL yEnd ) {
+
+ switch( argType ) {
+
+ case STREAMARG:
+ DelStream(pFile, xStart, yStart, xEnd, yEnd);
+ break;
+
+ case LINEARG:
+ DelStream(pFile, 0, yStart, 0, yEnd);
+ break;
+
+
+ case BOXARG: {
+ LINE iLine;
+
+ for( iLine = yStart; iLine < yEnd; iLine++ ) {
+ DelStream( pFile, xStart, iLine, xEnd, iLine );
+ }
+
+ break;
+ }
+
+
+ default:
+ break;
+ }
+}
+
+
+
+
+void InsertText( PFILE pFile, LPSTR pszText, DWORD dwInsMode, COL xStart,
+ LINE yStart ) {
+ char ch;
+ int cchLine, cchText, cchCopy;
+ LPSTR pszNL;
+ char achLine[BUFLEN];
+ char achEnd[BUFLEN];
+
+ switch( dwInsMode ) {
+ case STREAMARG:
+ /*
+ * Split current line,
+ * tack first line from buffer to end of new line
+ * put the new lines in file
+ * shove the last line to the beggining of the 2nd half of the line
+ */
+ DPRINT( " Stream Paste" );
+ if ( *pszText == '\0' )
+ break;
+
+
+ pszNL = EndOfLine(pszText);
+
+ cchLine = GetLine( yStart, achLine, pFile );
+
+ if (cchLine < xStart)
+ cchLine = ExtendLine( achLine, cchLine, ' ', xStart );
+
+ cchText = pszNL - pszText;
+ if (xStart + cchText >= BUFLEN_MAX) {
+ cchText = BUFLEN_MAX - xStart;
+ pszNL = pszText + cchText;
+ }
+
+ strcpy( achEnd, &achLine[xStart] );
+ cchLine -= xStart;
+
+ CopyMemory( &achLine[xStart], pszText, cchText );
+ cchText += xStart;
+ achLine[cchText] = '\0';
+
+
+ while( *pszNL ) {
+ PutLine( yStart++, achLine, pFile );
+ CopyLine( NULL, pFile, 0, 0, yStart );
+
+ pszText = EndOfBreak(pszNL);
+ pszNL = EndOfLine(pszText);
+
+ cchText = pszNL - pszText;
+
+ CopyMemory( achLine, pszText, cchText );
+ achLine[cchText] = '\0';
+ }
+
+ cchCopy = 0;
+ if (cchLine + cchText > BUFLEN_MAX) {
+ cchCopy = (cchLine + cchText) - BUFLEN_MAX;
+ cchLine = cchLine - cchCopy;
+ }
+
+ CopyMemory( &achLine[cchText], achEnd, cchLine );
+ achLine[cchLine+cchText] = '\0';
+ PutLine( yStart++, achLine, pFile );
+
+ if (cchCopy != 0) {
+ CopyLine( NULL, pFile, 0, 0, yStart );
+ CopyMemory( achLine, &achEnd[cchLine], cchCopy );
+ achLine[cchCopy] = '\0';
+ PutLine( yStart++, achLine, pFile);
+ }
+ break;
+
+ case BOXARG:
+ /*
+ * Insert the text as a block into the middle of each line.
+ * This could be tricky since we need to pad all short lines
+ * out with spaces to match the lenght of the longest line
+ * in the text.
+ */
+
+ DPRINT( " Box Paste" );
+ while( *pszText ) {
+ pszNL = EndOfLine(pszText);
+
+ cchLine = GetLine( yStart, achLine, pFile );
+
+ if (cchLine < xStart)
+ cchLine = ExtendLine( achLine, cchLine, ' ', xStart );
+
+ cchText = pszNL - pszText;
+ if (cchLine + cchText > BUFLEN_MAX)
+ cchText = BUFLEN_MAX - cchLine;
+
+ /* insert text in middle of line */
+ strcpy( achEnd, &achLine[xStart] );
+ CopyMemory( &achLine[xStart], pszText, cchText );
+ strcpy( &achLine[xStart + cchText], achEnd );
+
+ /* put line in file */
+ PutLine( yStart++, achLine, pFile );
+
+ pszText = EndOfBreak(pszNL);
+ }
+ break;
+
+ case LINEARG:
+ /*
+ * shove the lines in the buffer before the current line
+ */
+ DPRINT( " Line Paste" );
+ while( *pszText ) {
+ pszNL = EndOfLine(pszText);
+ ch = *pszNL;
+ *pszNL = '\0';
+ CopyLine( NULL, pFile, 0, 0, yStart );
+ PutLine( yStart++, pszText, pFile);
+ *pszNL = ch;
+ pszText = EndOfBreak(pszNL);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+}
+
+
+LPSTR EndOfLine( LPSTR psz ) {
+ int c;
+
+ c = 0;
+ while( *psz && *psz != '\r' && *psz != '\n' && c++ < BUFLEN_MAX )
+ psz++;
+
+ return psz;
+}
+
+LPSTR EndOfBreak( LPSTR psz ) {
+ char chSkip;
+
+ switch( *psz ) {
+ case '\r':
+ chSkip = '\n';
+ break;
+
+ case '\n':
+ chSkip = '\r';
+ break;
+
+ default:
+ return psz;
+
+ }
+
+ if (*(++psz) == chSkip)
+ psz++;
+
+ return psz;
+}
+
+
+int ExtendLine( LPSTR psz, int cchLine, char ch, int cchTotal ) {
+
+ if ( cchLine >= cchTotal )
+ return cchLine;
+
+ if (cchTotal > BUFLEN_MAX)
+ cchTotal = BUFLEN_MAX;
+
+ psz = &psz[cchLine];
+
+ while( cchLine++ < cchTotal )
+ *psz++ = ch;
+
+ *psz = '\0';
+
+ return cchLine;
+}
diff --git a/private/utils/mep/extens/winclip/winclip.def b/private/utils/mep/extens/winclip/winclip.def
new file mode 100644
index 000000000..254e57449
--- /dev/null
+++ b/private/utils/mep/extens/winclip/winclip.def
@@ -0,0 +1,7 @@
+LIBRARY TGLCASE
+
+DESCRIPTION 'MEP extension'
+
+EXPORTS
+ EntryPoint
+ ModInfo
diff --git a/private/utils/mep/extens/winclip/winclip.rc b/private/utils/mep/extens/winclip/winclip.rc
new file mode 100644
index 000000000..7021c5c72
--- /dev/null
+++ b/private/utils/mep/extens/winclip/winclip.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Clipboard Utility for MEP"
+#define VER_INTERNALNAME_STR "winclip"
+#define VER_ORIGINALNAME_STR "winclip.DLL"
+
+#include "common.ver"
diff --git a/private/utils/mep/help/dirs b/private/utils/mep/help/dirs
new file mode 100644
index 000000000..129a62c4a
--- /dev/null
+++ b/private/utils/mep/help/dirs
@@ -0,0 +1,24 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+
+!ENDIF
+
+DIRS=enginlib
+
+OPTIONAL_DIRS=
diff --git a/private/utils/mep/help/enginlib/hback.c b/private/utils/mep/help/enginlib/hback.c
new file mode 100644
index 000000000..68242e0c3
--- /dev/null
+++ b/private/utils/mep/help/enginlib/hback.c
@@ -0,0 +1,105 @@
+/*** hlback.c - help library historical back-trace routines & data
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Purpose:
+*
+* Revision History:
+*
+* 02-Aug-1988 ln Correct HelpNcBack
+* 19-May-1988 LN Split off from help.c
+*
+*************************************************************************/
+#include <assert.h> /* debugging assertions */
+#include <stdio.h>
+
+#if defined (OS2)
+#else
+#include <windows.h>
+#endif
+
+
+#include "help.h" /* global (help & user) decl */
+#include "helpfile.h" /* help file format definition */
+#include "helpsys.h" /* internal (help sys only) decl*/
+
+/*************************************************************************
+**
+** cBack, iBackLast, rgncBack
+** System context back-trace list.
+**
+** cBack - Number of entries in back-trace list
+** iBackLast - Index to last back trace entry
+** rgncBack - Array of back-trace entries
+*/
+extern ushort cBack; /* Number of Back-List entries */
+static ushort iBackLast; /* Back-List Last entry index */
+static nc rgncBack[MAXBACK+1]; /* Back-List */
+
+/************************************************************************
+**
+** HelpNcRecord - Remember context for back-trace
+**
+** Purpose:
+** records a context number for back-trace.
+**
+** Entry:
+** ncCur = context number to record.
+**
+** Exit:
+** none
+**
+** Exceptions:
+** none
+*/
+void far pascal LOADDS HelpNcRecord(ncCur)
+nc ncCur;
+{
+ushort *pcBack = &cBack;
+
+if ((ncCur.mh || ncCur.cn) &&
+ ((ncCur.mh != rgncBack[iBackLast].mh) ||
+ (ncCur.cn != rgncBack[iBackLast].cn))) {
+ iBackLast = (ushort)(((int)iBackLast + 1) % MAXBACK);
+ rgncBack[iBackLast] = ncCur;
+ if (*pcBack < MAXBACK)
+ (*pcBack)++;
+}
+/* end HelpNcRecord */}
+
+/******************************************************************************
+**
+** HelpNcBack - Return previously viewed context
+**
+** Purpose:
+** Returns the context number corresponding to the historically previously
+** viewed topic.
+**
+** Entry:
+** None
+**
+** Exit:
+** Returns context number
+**
+** Exceptions:
+** Returns NULL on backup list exhuasted
+**
+** Algorithm:
+**
+** If backlist not empty
+** context is last entry in back list
+** remove last entry
+** else
+** return NULL
+*/
+nc far pascal LOADDS HelpNcBack(void) {
+nc ncLast = {0,0}; /* return value */
+ushort *pcBack = &cBack;
+
+if (*pcBack) {
+ ncLast = rgncBack[iBackLast];
+ iBackLast = iBackLast == 0 ? (ushort)MAXBACK-1 : (ushort)iBackLast-1;
+ (*pcBack)--;
+ }
+return ncLast;
+/* end HelpNcBack */}
diff --git a/private/utils/mep/help/enginlib/hctl.c b/private/utils/mep/help/enginlib/hctl.c
new file mode 100644
index 000000000..a0d3797c1
--- /dev/null
+++ b/private/utils/mep/help/enginlib/hctl.c
@@ -0,0 +1,72 @@
+/**************************************************************************
+ *hctl - enable/disable retrieval of control lines
+ *
+ * Copyright <C> 1989, Microsoft Corporation
+ *
+ * Purpose:
+ *
+ * Revision History:
+ *
+ * 10-Oct-1990 RJSA Translated to C
+ * 13-May-1990 LN Unlock topic text when through with it.
+ * [] 22-Feb-1989 LN Created
+ *
+ **************************************************************************/
+
+#include <stdio.h>
+#if defined (OS2)
+#define INCL_BASE
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include <help.h>
+#include <helpfile.h>
+#include <helpsys.h>
+
+
+
+/**** helpctl - enable/disable retrieval of control lines
+ * void far pascal helpctl(
+ * uchar far *pTopic,
+ * f fEnable
+ * )
+ *
+ * Purpose:
+ * Enables or disables retrieval of embedded help control lines
+ *
+ * Entry:
+ * pTopic = Topic text
+ * fEnable = TRUE=> allow lookups of control lines, else disable
+ *
+ * Exit:
+ * returns nothing
+ *
+ **************************************************************************/
+
+void pascal
+HelpCtl (
+ PB pTopic,
+ f fEnable
+ ) {
+
+ struct topichdr UNALIGNED *pT;
+
+
+ pT = PBLOCK(pTopic);
+
+ if (pT) {
+
+ pT->lnCur = 1;
+ pT->lnOff = sizeof(struct topichdr);
+ pT->linChar = pT->appChar;
+
+ if (fEnable) {
+ pT->linChar = 0xFF;
+ }
+
+ PBUNLOCK(pTopic);
+ }
+
+}
diff --git a/private/utils/mep/help/enginlib/hdata.c b/private/utils/mep/help/enginlib/hdata.c
new file mode 100644
index 000000000..bffddefa5
--- /dev/null
+++ b/private/utils/mep/help/enginlib/hdata.c
@@ -0,0 +1,46 @@
+/*** hdata.c - global help engine data definitions.
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Purpose:
+*
+* Revision History:
+*
+* [] 01-Mar-1989 LN Created
+*
+*************************************************************************/
+
+#include <stdio.h>
+
+#if defined (OS2)
+#else
+#include <windows.h>
+#endif
+
+#include "help.h" /* global (help & user) decl */
+#include "helpfile.h" /* help file format definition */
+#include "helpsys.h" /* internal (help sys only) decl*/
+
+/*************************************************************************
+**
+** Global data
+** BEWARE. The effects of global data on reentrancy should be VERY carefully
+** considered.
+**
+**************************************************************************
+**
+** tbmhFdb[]
+** Table of FDB handles. Non-zero value indicates allocated to open help file.
+** We make this table one larger than it needs to be to save code later on.
+*/
+mh tbmhFdb[MAXFILES+1] = {0};
+/*
+** szNil
+** Null string.
+*/
+char szNil[1] = "";
+/*
+** cBack
+** count of entries in the help back-trace list
+*/
+ushort cBack = 0; /* Number of Back-List entries */
diff --git a/private/utils/mep/help/enginlib/help.c b/private/utils/mep/help/enginlib/help.c
new file mode 100644
index 000000000..f520d0a0b
--- /dev/null
+++ b/private/utils/mep/help/enginlib/help.c
@@ -0,0 +1,1745 @@
+/*** help.c - help library main
+*
+* Copyright <C> 1988-1990, Microsoft Corporation
+*
+* Definitions:
+*
+* Context Map: Mapping of context number to topic number.
+* Allows multiple contexts to be associated with a
+* single topic. Syncronized with the context
+* string table, each entry contains the topic
+* number associated with the corresponding context
+* string.
+*
+* Context String: String on which help can be "looked up".
+*
+* Context String Table: Table of all valid context strings in a
+* particular help file.
+*
+* Local Context: A type of context which bypasses the context
+* string and context numbers. In cross references,
+* encoded as a cross reference string of NULL,
+* followed by a topic number ored with 0x8000.
+*
+* nc: (Context Number) A long which uniquely
+* identifies a help file and context string, or
+* for local contexts, the helpfile and topic
+* number. Formatted as:
+*
+* +----------------+----------------+
+* | Fdb Mem Handle | context number |
+* +----------------+----------------+
+*
+* Where the upper word is the memory handle of the
+* allocated fdb for the help file. The lower word
+* is the either the "true" context number (see
+* below) if <= 0x7fff, or the actual topic number
+* or'ed with 0x8000.
+*
+* Topic: Actual help textual entry. May be compressed.
+*
+* Topic Index: Table of file positions of all topics contained
+* in a help file. Indexed by the topic number,
+* returns that topics physical position in the
+* file.
+*
+* Topic Number: Index to a particular topic. Topic numbers are
+* zero based, and reflect the physical ordering of
+* the topics in the file.
+*
+* "True" context number: is the zero based index or string number in the
+* <context string table>. I.E. the "n'th" string
+* has context number "n".
+*
+* The progression from string to true context number to topic number to file
+* position is:
+*
+* 1) Context String ==> "True" Context Number
+*
+* The string is searched for in the <context string table>, and
+* it's number becomes the "true" context number.
+*
+* 2) "True" Context Number ==> Topic Number
+*
+* The context number is an index into the <context map>, returing
+* the topic number associated with the context number.
+*
+* 3) Topic Number ==> File Position
+*
+* The topic number is used as an index into the Topic Index, from
+* which the physical file position is retrieved.
+*
+* Notes:
+* QuickPascal requires NO initialized data. In this case, CLEAR is defined,
+* and the HelpInit routine is included. We also play some pointer games to
+* simple variables, because the C compiler can generate CONST segment
+* entries for the SEG of various vars. (This enables it to load the segment
+* register directly, rather than by using SEG varname and another
+* register). Q/P cannot support this action by the compiler.
+*
+* QuickHelp for OS/2 is reentrant. This code should remain reentrant up to
+* but not including allocating and deallocating fdbs.
+*
+* Revision History:
+*
+* 17-Aug-1990 ln Don't blindly request 64k of an ascii file. Query
+* for size first, then read. Allocations based on
+* previous topic size requests may cause the OS to
+* GPFault for an out of range read.
+* 16-Jul-1990 ln Searching for "filename!" where filename is a QH
+* file, will now fail, rather than GP fault. Searching
+* for "!" will now succeed.
+* 08-Jun-1990 ln Remove HelpLock usage in HelpNcCmp
+* 13-Apr-1990 ln Try to get HelpSzContext to return strings in more
+* cases where it can.
+* 12-Mar-1990 ln Rename CloseFile -> HelpCloseFile
+* 08-Oct-1989 ln Changes to improve the previous change to work (allow
+* decompression) more often in low memory bases.
+* Deallocate table in OpenCore to reduce fragmentation
+* in non-moveable memory systems.
+* 19-May-1989 ln Correct bug in decompressing, where we would not
+* decompress if the tables didn;t exist.
+* 12-Apr-1989 ln Ensure that we handle Locks failing correctly. Also
+* remove TossPortion usage. Unlock handles directly.
+* 10-Mar-1989 ln Change MapTopicToContext to look forward. Changed
+* HelpNc to look begining at passed context string.
+* 17-Jan-1989 ln Correct creation of basename in HelpOpen to account
+* for environment syntax.
+* 09-Dec-1988 ln Add HelpNcUniq
+* 25-Oct-1988 ln Added minascii support to HelpNcPrev. Correct
+* minascii bug in HelpSzContext.
+* 14-Sep-1988 ln Improve doc. Remove ambiguity in MapContextToTopic
+* return value. Improve error checking in various
+* places.
+* 01-Sep-1988 ln Check ReadHelpFile return value in LoadPortion
+* 12-Aug-1988 ln Add check for memory discarded in alloc durring
+* HelpDecomp.
+* 08-Aug-1988 ln Ensure HelpClose closes ALL files. (Off by one error
+* in loop).
+* 14-Apr-1988 ln Modified to conform to QC (CW?) restriction that
+* prohibits any segments from being locked when an
+* allocation is performed.
+* [] 15-Dec-1987 ln Created, for design.
+*
+*************************************************************************/
+
+#include <assert.h> /* debugging assertions */
+#include <io.h> /* I/O function declarations */
+#include <stdlib.h> /* standard library */
+
+#include <stdio.h> /* standard I/O definitions */
+
+#if defined (OS2)
+#define INCL_BASE
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include "help.h" /* global (help & user) decl */
+#include "helpfile.h" /* help file format definition */
+#include "helpsys.h" /* internal (help sys only) decl*/
+
+#define MASIZE 512 /* size of ma input buffer */
+#define MAOVER 64 /* size of ma search overlap */
+
+#define ISERROR(x) (((x).mh == 0L) && ((x).cn <= HELPERR_MAX))
+#define SETERROR(x,y) { (x).mh = 0L; (x).cn = y; }
+
+/*************************************************************************
+**
+** Forward definitions
+*/
+void pascal near CloseShrink(nc, f);
+f pascal near LoadFdb (mh, fdb far *);
+mh pascal near LoadPortion (int, mh);
+ushort pascal near MapContexttoTopic (nc, fdb far *);
+nc pascal near MapTopictoContext(ushort, fdb far *, int);
+nc pascal near NextPrev(nc,int);
+nc pascal near OpenCore(FILE *, ulong, uchar far *, struct helpheader *, fdb far *);
+f pascal near PutFdb (mh, fdb far *);
+f pascal near SizePos (nc, ushort *,ulong *);
+
+ushort pascal near decomp (uchar far *, uchar far *, uchar far *, uchar far *);
+char far * pascal near hfmemzer(void far *, ushort);
+char far * pascal near hfstrchr(char far *, char);
+char far * pascal near hfstrcpy(char far *, char far *);
+ushort pascal near hfstrlen(char far *);
+f pascal far HelpCmp (uchar far *, uchar far *, ushort, f, f);
+f pascal near HelpCmpSz (uchar far *, uchar far *);
+void pascal near kwPtrBuild(uchar far *, ushort);
+
+#if ASCII
+long pascal near maLocate (fdb far *, uchar far *, ulong,
+ f (pascal far *)(uchar far *, uchar far *, ushort, f, f));
+
+nc pascal near combineNc (ulong, mh);
+ulong pascal near NctoFo (ulong);
+#endif
+
+/*************************************************************************
+**
+** External Global data
+** BEWARE. The effects of global data on reentrancy should be VERY carefully
+** considered.
+**
+*************************************************************************/
+extern mh tbmhFdb[MAXFILES+1];
+extern char szNil[1];
+extern ushort cBack;
+
+#ifdef CLEAR
+/*************************************************************************
+**
+** HelpInit - One-time initialization
+**
+** Purpose:
+** Performs one-time initialization. Right now that's a zero fill of static
+** memory for those environments which don't support pre-inited static
+** memory.
+**
+** Entry:
+** none
+**
+** Exit:
+** none
+**
+*/
+void far pascal LOADDS HelpInit () {
+
+hfmemzer (tbmhFdb, sizeof(tbmhFdb)); /* zero entire fdb handle table */
+hfmemzer (szNil, sizeof(szNil)); /* zero null string */
+hfmemzer (&cBack, sizeof(cBack)); /* zero back trace count */
+
+/* end HelpInit */}
+#endif
+
+/*************************************************************************
+**
+** HelpOpen - Open help file & return help handle.
+**
+** Purpose:
+** Given the file basename, locate the associated help file on the path, and
+** open it, initializing internal data structures as appropriate.
+**
+** Entry:
+** fpszName - base filename to be openned.
+**
+** Exit:
+** nc initial context for openned file.
+**
+** Exceptions:
+** Returns error code on failure to open for any reason.
+**
+*/
+nc far pascal LOADDS HelpOpen (
+char far *fpszName
+) {
+FILE *fhT; /* temp file handle */
+fdb fdbLocal; /* local copy of fdb to use */
+uchar far *fpszBase; /* base filename */
+void far *fpT;
+struct helpheader hdrLocal; /* for use by opencore */
+nc ncRet = {0,0}; /* first context */
+mh *ptbmhFdb; /* pointer into mh table */
+
+/*
+** create basename by removing possible env variable, drive, and scanning
+** for last path seperator
+*/
+fpszBase = fpszName;
+if (fpT = hfstrchr(fpszBase,':'))
+ fpszBase = (uchar far *)fpT+1;
+while (fpT = hfstrchr(fpszBase,'\\'))
+ fpszBase = (uchar far *)fpT+1;
+/*
+** Scan FDB's for an open file of the same base name. If we encounter the name,
+** in either the true filename, or file header, just return that file's initial
+** context. Otherwise fall below to try and open it.
+*/
+for (ptbmhFdb=&tbmhFdb[1]; ptbmhFdb<=&tbmhFdb[MAXFILES]; ptbmhFdb++) {
+ if (LoadFdb (*ptbmhFdb,&fdbLocal)) {
+ if (HelpCmpSz(fpszBase,fdbLocal.fname) ||
+ HelpCmpSz(fpszBase,fdbLocal.hdr.fname))
+ ncRet = fdbLocal.ncInit;
+ if (ncRet.mh && ncRet.cn)
+ return ncRet;
+ }
+ }
+/*
+** Open file. If we can, then call the core open routine to open the file (and
+** any anything appended to it).
+**
+** Warning: the app may callback HelpClose at this point.
+*/
+if (fhT = OpenFileOnPath(fpszName,FALSE)) {
+ ncRet = OpenCore (fhT,0L,fpszBase,&hdrLocal,&fdbLocal);
+ if (ISERROR(ncRet))
+ HelpCloseFile (fhT);
+ return ncRet;
+ }
+
+SETERROR(ncRet, HELPERR_FNF);
+return ncRet;
+// rjsa return HELPERR_FNF;
+
+/* end HelpOpen*/}
+
+/*************************************************************************
+**
+** OpenCore - Recursive core of HelpOpen
+**
+** Purpose:
+** Given the open file handle, initialize internal data structures as
+** appropriate. Attempt to open any file that is appended.
+**
+** Entry:
+** fhT - Open file handle
+** offset - Offset from start of file of help file to open
+** fpszBase - pointer to base filename
+**
+** Exit:
+** initial context, or NULL on failure.
+**
+** Exceptions:
+** Returns NULL on failure to open for any reason.
+**
+*/
+nc pascal near OpenCore (
+FILE * fhHelp,
+ulong offset,
+uchar far *fpszBase, /* base filename */
+struct helpheader *phdrLocal,
+fdb far *pfdbLocal /* pointer to current FDB */
+) {
+//void far *fpT;
+int ihFree; /* handle for free fdb (& index)*/
+mh mhCur; /* current memory handle */
+nc ncFirst = {0,0}; /* first context */
+nc ncInit; /* first context */
+mh *pmhT; /* pointer into mh table */
+
+/*
+** Read in helpfile header
+*/
+if (ReadHelpFile(fhHelp,
+ offset,
+ (char far *)phdrLocal,
+ (ushort)sizeof(struct helpheader))) {
+/*
+** search for available fdb
+*/
+ for (ihFree = MAXFILES, pmhT = &tbmhFdb[MAXFILES];
+ ihFree && *pmhT;
+ ihFree--, pmhT--);
+/*
+** if an offset is present, and this is NOT a compressed file, or there is no
+** available fdb, ignore the operation.
+*/
+ if ( offset
+ && (phdrLocal->wMagic != wMagicHELP)
+ && (phdrLocal->wMagic != wMagicHELPOld)
+ ) {
+ SETERROR(ncInit, HELPERR_BADAPPEND);
+ return ncInit;
+ // rjsa return HELPERR_BADAPPEND;
+ }
+ if (ihFree == 0) {
+ SETERROR(ncInit, HELPERR_LIMIT);
+ return ncInit;
+ // rjsa return HELPERR_LIMIT;
+ }
+/*
+** allocate fdb. Again, if we can't, skip it all and return NULL.
+*/
+ if (mhCur = *pmhT = HelpAlloc((ushort)sizeof(fdb))) {
+/*
+** Fill in helpfile header & appropriate fdb fields
+*/
+ hfmemzer(pfdbLocal,sizeof(fdb)); /* zero entire fdb */
+ pfdbLocal->fhHelp = fhHelp; /* file handle */
+ ncFirst.mh = pfdbLocal->ncInit.mh = mhCur;
+ ncFirst.cn = pfdbLocal->ncInit.cn = 0L;
+ // rjsa ncFirst = pfdbLocal->ncInit = ((long)mhCur) << 16; /* initial context */
+ pfdbLocal->foff = offset; /* appended offset */
+ hfstrcpy(pfdbLocal->fname,fpszBase); /* include base filename*/
+/*
+** if this is a compressed file (signified by the first two bytes of the header
+** we read in above), then note the file type in the fdb. We unlock the fdb, as
+** MapTopicToContext and the recursion might cause memory allocation. We get a
+** context number for the first topic, and recurse and attempt to open any
+** appended file.
+*/
+ if ( (phdrLocal->wMagic == wMagicHELPOld)
+ || (phdrLocal->wMagic == wMagicHELP)
+ ) {
+ if ((phdrLocal->wMagic == wMagicHELP)
+ && (phdrLocal->wVersion > wHelpVers)) {
+ SETERROR(ncInit, HELPERR_BADVERS);
+ return ncInit;
+ // rjsa return HELPERR_BADVERS;
+ }
+ pfdbLocal->hdr = *phdrLocal;
+ pfdbLocal->ftype = FTCOMPRESSED | FTFORMATTED;
+ if (PutFdb (mhCur, pfdbLocal)) {
+ ncFirst = MapTopictoContext(0,pfdbLocal,0);
+
+ // We free the context map (the only thing loaded by the
+ // MapTopictoContext) in order to reduce fragmentation in
+ // non-moveable memory based systems.
+ //
+ HelpDealloc (pfdbLocal->rgmhSections[HS_CONTEXTMAP]);
+ pfdbLocal->rgmhSections[HS_CONTEXTMAP] = 0;
+
+ ncInit = OpenCore(fhHelp,pfdbLocal->hdr.tbPos[HS_NEXT]+offset,szNil,phdrLocal,pfdbLocal);
+ if (LoadFdb (mhCur, pfdbLocal)) {
+ //if (ncInit.cn > HELPERR_MAX) {
+ if ( !(ISERROR(ncInit)) ) {
+ pfdbLocal->ncLink = ncInit;
+ } else {
+ pfdbLocal->ncLink.mh = (mh)0;
+ pfdbLocal->ncLink.cn = 0L;
+ }
+ // rjsa pfdbLocal->ncLink = ncInit > HELPERR_MAX ? ncInit : 0;
+ pfdbLocal->ncInit = ncFirst;
+ }
+ }
+ }
+#if ASCII
+/*
+** In the case of a minascii formatted file (signified by the first two bytes
+** of the header being ">>") we just set up the filetype and "applications
+** specific character". The default "ncFirst" is the context for the first
+** topic.
+*/
+ else if (phdrLocal->wMagic == 0x3e3e) { /* minascii formatted? */
+ pfdbLocal->ftype = FTFORMATTED;
+ pfdbLocal->hdr.appChar = '>'; /* ignore lines with this*/
+ }
+#endif
+ else if ((phdrLocal->wMagic & 0x8080) == 0) { /* ascii unformatted? */
+ pfdbLocal->ftype = 0;
+ pfdbLocal->hdr.appChar = 0xff; /* ignore lines with this*/
+ }
+ else {
+ SETERROR(ncInit, HELPERR_NOTHELP);
+ return ncInit;
+ // rjsa return HELPERR_NOTHELP;
+ }
+
+ if (!PutFdb (mhCur, pfdbLocal)) {
+ ncFirst.mh = (mh)0;
+ ncFirst.cn = 0L;
+ }
+ }
+ else {
+ SETERROR(ncFirst, HELPERR_MEMORY);
+ // rjsa ncFirst = HELPERR_MEMORY; /* error reading file */
+ }
+}
+else {
+ SETERROR(ncFirst, HELPERR_READ);
+ // rjsa ncFirst = HELPERR_READ; /* error reading file */
+}
+
+return ncFirst; /* return valid context */
+
+/* end OpenCore */}
+
+
+/*************************************************************************
+**
+** HelpClose - Close Help file
+**
+** Purpose:
+** Close a help file, deallocate all memory associated with it, and free the
+** handle.
+**
+** Entry:
+** ncClose - Context for file to be closed. If zero, close all.
+**
+** Exit:
+** None
+**
+** Exceptions:
+** All errors are ignored.
+**
+*/
+void far pascal LOADDS HelpClose (
+nc ncClose
+) {
+CloseShrink(ncClose,TRUE); /* close file(s) */
+/* end HelpClose */}
+
+/*************************************************************************
+**
+** HelpShrink - Release all dynamic memory
+**
+** Purpose:
+** A call to this routines causes the help system to release all dynamic
+** memory it may have in use.
+**
+** Entry:
+** None.
+**
+** Exit:
+** None.
+**
+** Exceptions:
+** None.
+**
+*/
+void far pascal LOADDS HelpShrink(void) {
+ nc ncTmp = {0,0};
+CloseShrink(ncTmp,0);
+// rjsa CloseShrink(0,0);
+/* end HelpShrink */}
+
+/*************************************************************************
+**
+** CloseShrink - Deallocate memory and possibly Close Help file
+**
+** Purpose:
+** Deallocate all memory associated with a help file, and possibly close free
+** it.
+**
+** Entry:
+** ncClose - Context for file. If zero, do all.
+** fClose - TRUE if a close operation.
+**
+** Exit:
+** None
+**
+** Exceptions:
+** All errors are ignored.
+**
+*/
+void pascal near CloseShrink (
+nc ncClose,
+f fClose
+) {
+fdb fdbLocal; /* pointer to current FDB */
+int i;
+mh mhClose; /* fdb mem hdl to file to close */
+mh *pmhFdb; /* pointer to FDB's table entry */
+
+
+mhClose = ncClose.mh; /* get index */
+// rjsa mhClose = (mh)HIGH(ncClose); /* get index */
+for (pmhFdb = &tbmhFdb[0]; /* for each possible entry */
+ pmhFdb <= &tbmhFdb[MAXFILES];
+ pmhFdb++
+ ) {
+ if ((mhClose == 0) /* if all selected */
+ || (mhClose == *pmhFdb)) { /* or this one selected */
+
+ if (LoadFdb (*pmhFdb, &fdbLocal)) { /* if open file */
+/*
+ * Recurse to close/shrink any appended files
+ */
+ if ((fdbLocal.ncLink.mh || fdbLocal.ncLink.cn) && mhClose)
+ CloseShrink (fdbLocal.ncLink, fClose);
+
+ for (i=HS_count-2; i>=0; i--) /* for dyn mem handles */
+ HelpDealloc(fdbLocal.rgmhSections[i]); /* dealloc */
+ hfmemzer(fdbLocal.rgmhSections,sizeof(fdbLocal.rgmhSections));
+
+ if (fClose) {
+ HelpCloseFile(fdbLocal.fhHelp); /* close file */
+ HelpDealloc(*pmhFdb); /* deallocate fdb */
+ *pmhFdb = 0;
+ }
+ else
+ PutFdb (*pmhFdb, &fdbLocal); /* update FDB */
+ }
+ }
+ }
+/* end CloseShrink */}
+
+/*** HelpNcCmp - Look up context string, provide comparison routine
+*
+* Given an ascii string, determine the context number of that string. Uses
+* user-supplied comparison routine.
+*
+* Entry:
+* lpszContext - Pointer to asciiz context string.
+* ncInital - Starting Context, used to locate file.
+* lpfnCmp - far pointer to comparison routine to use.
+*
+* Exit:
+* Context number, if found.
+*
+* Exceptions:
+* Returns NULL if context string not found.
+*
+*************************************************************************/
+nc far pascal LOADDS HelpNcCmp (
+char far *fpszContext,
+nc ncInitial,
+f (pascal far *lpfnCmp)(uchar far *, uchar far *, ushort, f, f)
+) {
+f fFound = FALSE; // TRUE -> found
+f fOpened = FALSE; // TRUE -> file was openned here
+fdb fdbLocal; // pointer to current FDB
+char far *fpszT; // temp far pointer
+long i;
+long iStart; // nc to start looking at
+mh mhCur; // memory handle locked
+nc ncRet = {0,0}; // The return value
+char far *fpszContexts; // pointer to context strings
+
+
+// if the context string includes a "filename!", then open that as a help
+// file, and point to the context string which may follow.
+//
+if ((fpszT = hfstrchr(fpszContext,'!')) && (fpszT != fpszContext)) {
+ *fpszT = 0;
+ ncInitial = HelpOpen(fpszContext);
+ *fpszT++ = '!';
+ fpszContext = fpszT;
+ fOpened = TRUE;
+}
+
+// if helpfile was not openned, just return the error
+//
+if (ISERROR(ncInitial)) {
+ ncInitial.mh = (mh)0;
+ ncInitial.cn = 0L;
+ return ncInitial;
+}
+
+// For compressed files we scan the context strings in the file (I know,
+// it's stupid code, but this turns out not to be that speed critical in
+// comparision with decompression, so I haven't bothered), to get the
+// context number.
+//
+// If not found, and there IS a linked (appended) file, we recurse to search
+// that file as well.
+//
+// The context number for compressed files is just the zero based string
+// number, plus the number of predefined contexts, with the fdb memory
+// handle in the upper word.
+//
+if (LoadFdb (ncInitial.mh, &fdbLocal)) {
+ if (fdbLocal.ftype & FTCOMPRESSED) {
+
+ // If not a local context look up, get the context strings, and
+ // search
+ //
+ if (*fpszContext) {
+ mhCur = LoadPortion (HS_CONTEXTSTRINGS, ncInitial.mh);
+ if ( (mhCur == (mh)0)
+ || (mhCur == (mh)(-1))
+ || (!(fpszContexts = HelpLock(mhCur)))
+ ) {
+ ncRet.mh = (mh)0;
+ ncRet.cn = 0L;
+ return ncRet;
+ }
+ i=0;
+
+ // iStart allows us to begin searching from the context string
+ // passed, as opposed to from the begining each time. This
+ // allows the application to "carry on" a search from othe last
+ // place we found a match. This is usefull for multiple
+ // duplicate context resolution, as well as inexact matching.
+ //
+ iStart = ncInitial.cn;
+ if (iStart & 0x8000)
+ iStart = 0;
+ else
+ iStart--; /* table index is 0 based */
+
+ do {
+ if (i >= iStart) {
+ fFound = lpfnCmp ( fpszContext
+ , fpszContexts
+ , 0xffff
+ , (f)(fdbLocal.hdr.wFlags & wfCase)
+ , (f)FALSE);
+ }
+ while (*fpszContexts++); /* point to next string */
+ i++;
+ }
+ while ((i < (int)fdbLocal.hdr.cContexts) && !fFound);
+ HelpUnlock (mhCur);
+
+ if (fFound) { /* if a match found */
+ ncRet.mh = ncInitial.mh;
+ ncRet.cn = i + fdbLocal.hdr.cPreDef;
+ // rjsa ncRet = (i+fdbLocal.hdr.cPreDef) /* string # */
+ // | HIGHONLY(ncInitial); /* & fdb handle */
+ }
+ else {
+ ncInitial.mh = (mh)0;
+ ncInitial.cn = 0L;
+ ncRet = HelpNcCmp (fpszContext,fdbLocal.ncLink, lpfnCmp);
+ }
+ }
+ else if (!fOpened) {
+ ncRet.mh = ncInitial.mh;
+ ncRet.cn = *(UNALIGNED ushort far *)(fpszContext + 1);
+ // rjsa ncRet = *(ushort far *)(fpszContext + 1) /* word following*/
+ // | HIGHONLY(ncInitial); /* & fdb handle */
+ }
+ }
+#if ASCII
+/*
+** For minimally formatted ascii files, we sequentially scan the file itself
+** for context string definitions until we find the string we care about.
+**
+** The context number for minascii files is the the byte position/4 of the
+** beginning of the associated topic, with the fdb memory handle in the upper
+** word.
+*/
+ else if (fdbLocal.ftype & FTFORMATTED) {
+ if (*fpszContext) {
+ ncRet.cn = maLocate(&fdbLocal, fpszContext, 0L, lpfnCmp);
+ if (ncRet.cn == -1L) {
+ ncRet.mh = (mh)0;
+ ncRet.cn = 0L;
+ } else {
+ ncRet = combineNc(ncRet.cn, fdbLocal.ncInit.mh);
+ }
+ // rjsa ncRet = maLocate(&fdbLocal, fpszContext, 0L, lpfnCmp);
+ // ncRet = (ncRet == -1L)
+ // ? 0
+ // : combineNc(ncRet,HIGH(fdbLocal.ncInit));
+ }
+ }
+/*
+** for unformatted ascii files, there must have been NO context string to be
+** searched for. In that case, the context number is always 1, plus the fdb
+** mem handle.
+*/
+ else if (*fpszContext == 0) { /* if null context string */
+ ncRet.mh = ncInitial.mh;
+ ncRet.cn = 1L;
+ // rjsa ncRet = HIGHONLY(ncInitial) + 1;
+ }
+#endif
+}
+
+return ncRet;
+
+/* end HelpNcCmp */}
+
+/*** HelpNc - Look up context string
+*
+* Given an ascii string, determine the context number of that string.
+*
+* Entry:
+* lpszContext - Pointer to asciiz context string.
+* ncInital - Starting Context, used to locate file.
+*
+* Exit:
+* Context number, if found.
+*
+* Exceptions:
+* Returns NULL if context string not found.
+*
+*************************************************************************/
+nc far pascal LOADDS HelpNc (
+char far *fpszContext,
+nc ncInitial
+) {
+return HelpNcCmp (fpszContext, ncInitial, HelpCmp);
+/* end HelpNc */}
+
+
+/*************************************************************************
+**
+** HelpNcCb - Return count of bytes in compressed topic
+**
+** Purpose:
+** Returns the size in bytes of the compressed topic. Provided for
+** applications to determine how big a buffer to allocate.
+**
+** Entry:
+** ncCur - Context number to return info on.
+**
+** Exit:
+** Count of bytes in the compressed topic
+**
+** Exceptions:
+** Returns 0 on error.
+**
+*/
+ushort far pascal LOADDS HelpNcCb (
+nc ncCur
+) {
+ulong position;
+ushort size;
+
+return SizePos(ncCur,&size,&position) ? size+(ushort)4 : (ushort)0;
+
+/* end HelpNcCb */}
+
+/******************************************************************************
+**
+** HelpLook - Return compressed topic text
+**
+** Purpose:
+** Places the compressed topic text referenced by a passed context number into
+** a user supplied buffer.
+**
+** Entry:
+** ncCur - Context number for which to return text
+** pbDest - Pointer to buffer in which to place the result.
+**
+** Exit:
+** Count of bytes in >uncompressed< topic. This is encoded based on file type.
+**
+** Exceptions:
+** Returns NULL on any error
+**
+*/
+ushort far pascal LOADDS HelpLook (
+nc ncCur,
+PB pbDest
+) {
+fdb fdbLocal; /* pointer to current FDB */
+char far *fpszDest;
+int i;
+ulong position = 0;
+ushort size = 0;
+
+if (LoadFdb (ncCur.mh, &fdbLocal)) { /* get fdb down */
+/*
+** for both kinds of formatted files, we determine the position of the topic,
+** and read it in.
+*/
+ if (fdbLocal.ftype) {
+ if (SizePos (ncCur,&size,&position)) {
+ if (fpszDest = (char far *)PBLOCK(pbDest)) {
+
+#ifdef BIGDEBUG
+ {
+ char DbgBuf[128];
+ sprintf(DbgBuf, "HELP: Reading Topic for Context %d at %lX, size %d\n", ncCur.cn, position + fdbLocal.foff, size );
+ OutputDebugString(DbgBuf);
+ }
+#endif
+
+ size = (ushort)ReadHelpFile(fdbLocal.fhHelp
+ ,position + fdbLocal.foff
+ ,fpszDest
+ ,size);
+
+#ifdef BIGDEBUG
+ {
+ char DbgBuf[128];
+ sprintf(DbgBuf, " Read %d bytes to address %lX\n", size, fpszDest );
+ OutputDebugString(DbgBuf);
+ }
+#endif
+/*
+** for compressed files, if the read was sucessfull, we then return the
+** uncompressed size which is the first word of the topic.
+*/
+#if ASCII
+ if (fdbLocal.ftype & FTCOMPRESSED) {
+#endif
+ if (size)
+ size = *(ushort far *)fpszDest+(ushort)1;
+#if ASCII
+ }
+ else {
+/*
+** for minascii files, We also set up for the terminating NULL by scanning for
+** the ">>" which begins the next topic, adjusting the size as well.
+*/
+ size -= 4;
+ for (i=4; i; i--)
+ if (fpszDest[++size] == '>') break;
+ fpszDest[size++] = 0;
+ }
+#endif
+ }
+ }
+ }
+#if ASCII
+ else { /* unformatted ascii */
+/*
+** for unformatted ascii, we just read in (first 64k of) the file.
+*/
+ if (fpszDest = PBLOCK (pbDest)) {
+ if (SizePos (ncCur,&size,&position)) {
+ size = (ushort)ReadHelpFile(fdbLocal.fhHelp,0L,fpszDest,size);
+ fpszDest[size++] = 0; /* terminate ascii text */
+ }
+ }
+ }
+#endif
+ PBUNLOCK (pbDest);
+ }
+if (size) size += sizeof(topichdr); /* adjust for prepended topichdr*/
+return size;
+/* end HelpLook */}
+
+/******************************************************************************
+**
+** HelpDecomp - Decompress Topic Text
+**
+** Purpose:
+** Fully decompress topic text. Decompresses based on current file, from one
+** buffer to another.
+**
+** Entry:
+** pbTopic - Pointer to compressed topic text
+** pbDest - Pointer to destination buffer
+**
+** Exit:
+** FALSE on successful completion
+**
+** Exceptions:
+** Returns TRUE on any error.
+**
+*/
+f far pascal LOADDS HelpDecomp (
+PB pbTopic,
+PB pbDest,
+nc ncContext
+) {
+fdb fdbLocal; // pointer to current FDB
+uchar far *fpszDest; // pointer to destination
+uchar far *fpTopic; // pointer to locked topic
+f fRv = TRUE; // return Value
+mh mhFdb; // handle to the fdb
+mh mhHuff;
+mh mhKey;
+
+mhFdb = ncContext.mh;
+if (LoadFdb (mhFdb, &fdbLocal)) { /* lock fdb down */
+ if (fdbLocal.ftype & FTCOMPRESSED) {
+
+ // This funky sequence of code attempts to ensure that both the
+ // huffman and keyword decompression tables are loaded simultaneously
+ // since we cannot decompress without both.
+ //
+ // We do things three times to cover the following cases:
+ //
+ // 1) huffman loaded ok
+ // keyword loaded ok
+ // huffman already loaded
+ //
+ // 2) huffman loaded ok
+ // keyword loaded ok after HelpShrink (huffman discarded)
+ // huffman re-loaded ok (HelpShrink freed enough for both)
+ //
+ // 3) huffman loaded ok after HelpShrink
+ // keyword loaded ok after HelpShrink (huffman discarded)
+ // huffman re-loaded ok (memory fragmentation allowed it)
+ //
+ // The other cases, where either the load fails immediatly after
+ // any HelpShrink call, are the cases we cannot handle.
+ //
+ // Since handles can change due to the reallocation that can ocurr
+ // in the HelpShrink-reload sequence, we simply do the three
+ // loads, and then ensure that all the handles match what's in the
+ // fdb. If they don't, we fail.
+ //
+ mhHuff = LoadPortion (HS_HUFFTREE,mhFdb);
+ mhKey = LoadPortion (HS_KEYPHRASE,mhFdb);
+ mhHuff = LoadPortion (HS_HUFFTREE,mhFdb);
+
+ if ( LoadFdb (mhFdb, &fdbLocal)
+ && (mhKey == fdbLocal.rgmhSections[HS_KEYPHRASE])
+ && (mhHuff == fdbLocal.rgmhSections[HS_HUFFTREE])) {
+
+ char far *fpHuff;
+ char far *fpKey;
+
+ // At this point we lock EVERYTHING and ensure that we have
+ // valid pointers to it all. (Some swapped memory systems can
+ // fail at this point, so we need to be sensitive).
+ //
+ fpHuff = HelpLock (mhHuff);
+ fpKey = HelpLock (mhKey);
+ fpTopic = PBLOCK (pbTopic);
+ fpszDest = PBLOCK (pbDest);
+
+ if ( fpTopic
+ && fpszDest
+ && (fpHuff || (mhHuff == 0))
+ && (fpKey || (mhKey == 0))
+ ) {
+ decomp (fpHuff, fpKey, fpTopic, fpszDest+sizeof(topichdr));
+ fRv = FALSE;
+ }
+ }
+
+ // Unlock the handles, if they were valid.
+ //
+ if (mhKey != (mh)(-1))
+ HelpUnlock (mhKey);
+ if (mhHuff != (mh)(-1))
+ HelpUnlock (mhHuff);
+ }
+ else {
+ fpszDest = PBLOCK (pbDest);
+#if ASCII
+/*
+** ascii, just copy
+*/
+ fpTopic = PBLOCK(pbTopic);
+ if (fpTopic && fpszDest) {
+ hfstrcpy(fpszDest+sizeof(topichdr),fpTopic);
+#else
+ {
+#endif
+ fRv = FALSE;
+ }
+ }
+ if (!fRv) {
+ ((topichdr far *)fpszDest)->ftype = fdbLocal.ftype;
+ ((topichdr far *)fpszDest)->appChar = (uchar)fdbLocal.hdr.appChar;
+ ((topichdr far *)fpszDest)->linChar = (uchar)fdbLocal.hdr.appChar;
+ ((topichdr far *)fpszDest)->lnCur = 1;
+ ((topichdr far *)fpszDest)->lnOff = sizeof(topichdr);
+ }
+ PBUNLOCK (pbTopic);
+ PBUNLOCK (pbDest);
+ }
+return fRv;
+/* end HelpDecomp */}
+
+/******************************************************************************
+**
+** HelpNcNext - Return next context number
+**
+** Purpose:
+** Returns the context number corresponding to a physical "next" in the help
+** file.
+**
+** Entry:
+** None
+**
+** Exit:
+** Returns context number
+**
+** Exceptions:
+** Returns NULL on any error
+**
+*/
+nc far pascal LOADDS HelpNcNext (
+nc ncCur
+) {
+return NextPrev(ncCur,1); /* get next */
+/* end HelpNcNext */}
+
+/******************************************************************************
+**
+** HelpNcPrev - Return phyiscally previous context
+**
+** Purpose:
+** Returns the context number corresponding to the physically previous topic.
+**
+** Entry:
+** None
+**
+** Exit:
+** Returns context number
+**
+** Exceptions:
+** Returns NULL on any error
+**
+*/
+nc far pascal LOADDS HelpNcPrev (
+nc ncCur
+) {
+return NextPrev(ncCur,-1); /* get previous */
+/* end HelpNcPrev */}
+
+/******************************************************************************
+**
+** HelpNcUniq - Return nc guaranteed unique for a given topic
+**
+** Purpose:
+** Maps a context number to a local context number. This is provided such
+** that all context numbers which map to the same topic can be transformed
+** into the same nc which maps to that topic. The information on the
+** context string originally used is lost.
+**
+** Entry:
+** None
+**
+** Exit:
+** Returns context number
+**
+** Exceptions:
+** Returns NULL on any error
+**
+*/
+nc far pascal LOADDS HelpNcUniq (
+nc ncCur
+) {
+fdb fdbLocal; /* pointer to current FDB */
+
+if (LoadFdb (ncCur.mh, &fdbLocal))
+ if (fdbLocal.ftype & FTCOMPRESSED) {
+ nc ncTmp;
+
+ ncTmp.mh = fdbLocal.ncInit.mh;
+ ncTmp.cn = MapContexttoTopic(ncCur, &fdbLocal);
+ ncTmp.cn |= 0x8000;
+
+ ncCur = ncTmp;
+
+ // rjsa return MapContexttoTopic (ncCur,&fdbLocal)
+ // | (fdbLocal.ncInit & 0xffff0000)
+ // | 0x8000;
+
+ }
+return ncCur;
+/* end HelpNcUniq */}
+
+/******************************************************************************
+**
+** NextPrev - Return phyiscally next or previous context
+**
+** Purpose:
+** Returns the context number corresponding to the physically next or previous
+** topic.
+**
+** Entry:
+** ncCur = Current Context
+** fNext = 1 for next, -1 for previous.
+**
+** Exit:
+** Returns context number
+**
+** Exceptions:
+** Returns NULL on any error
+**
+*/
+nc pascal near NextPrev (
+ nc ncCur,
+ int fNext
+ ) {
+
+ fdb fdbLocal; /* pointer to current FDB */
+ REGISTER nc ncNext = {0,0};
+
+ if (LoadFdb (ncCur.mh, &fdbLocal)) {
+
+ //
+ // For a compressed file the next/previous physical is computed by taking the
+ // context number, mapping it to its corresponding topic number, incrementing
+ // or decrementing the topic number (remember, topic numbers are in physical
+ // order), and then mapping that back to a context number.
+ //
+ // When nexting, we also support nexting into any appended file.
+ //
+ if (fdbLocal.ftype & FTCOMPRESSED) {
+ unsigned short cn;
+
+ cn = (ushort)(((ncCur.cn & 0x8000)
+ ? ncCur.cn & 0x7ffff
+ : MapContexttoTopic(ncCur, &fdbLocal))
+ + (ushort)fNext);
+
+ ncNext = MapTopictoContext(cn, (fdb far *)&fdbLocal, fNext);
+
+ // rjsa ncNext = MapTopictoContext((ushort)(((ncCur & 0x8000)
+ // ? ncCur & 0x7fff
+ // : MapContexttoTopic (ncCur,&fdbLocal))
+ // + fNext)
+ // ,(fdb far *)&fdbLocal);
+
+ //
+ // if we could not come up with a next, try to find a next using "local"
+ // context numbers. Map the context number to a topic number, and if that is
+ // not out of range, return it as a context.
+ //
+ if (!(ncNext.cn)) {
+
+ // rjsa if ((ncNext = MapContexttoTopic (ncCur,&fdbLocal)) == 0xffff)
+ // ncNext = 0;
+ ncNext.cn = MapContexttoTopic(ncCur, &fdbLocal);
+
+ if (ncNext.cn == 0xffff) {
+
+ ncNext.mh = (mh)0;
+ ncNext.cn = 0L;
+
+ } else {
+
+ ncNext.cn += fNext;
+
+ if (ncNext.cn >= fdbLocal.hdr.cTopics) {
+
+ ncNext.mh = (mh)0;
+ ncNext.cn = 0L;
+
+ } else {
+
+ // rjsa ncNext |= (fdbLocal.ncInit & 0xffff0000) | 0x8000;
+ ncNext.mh = fdbLocal.ncInit.mh;
+ ncNext.cn = 0x8000;
+ }
+ }
+ }
+
+ if (!(ncNext.cn & 0x7fff) && (fNext>0)) {
+ ncNext = fdbLocal.ncLink;
+ }
+ }
+
+#if ASCII
+
+ //
+ // minascii files:
+ // next'ing: we just sequentially search the file for the first context to
+ // come along after that pointed to by our current context number.
+ //
+ else if (fdbLocal.ftype & FTFORMATTED) {
+
+ if (fNext > 0) {
+
+ ncNext.cn = maLocate(&fdbLocal,szNil,NctoFo(ncCur.cn)+4, HelpCmp);
+ if (ncNext.cn == -1L) {
+ ncNext.mh = (mh)0;
+ ncNext.cn = 0L;
+ } else {
+ ncNext = combineNc(ncNext.cn, ncCur.mh);
+ }
+ // rjsa ncNext = (ncNext == -1L)
+ // ? 0
+ // : combineNc(ncNext,HIGH(ncCur));
+
+ } else {
+
+ nc ncTemp;
+
+ //
+ // prev'ing: start at the begining of the file, looking for the last context
+ // which is less than the current one.
+ //
+
+ ncNext = ncTemp = fdbLocal.ncInit;
+ while (NctoFo(ncTemp.cn) < NctoFo(ncCur.cn)) {
+ ncNext = ncTemp;
+ ncTemp.cn = maLocate(&fdbLocal,szNil,NctoFo(ncTemp.cn)+4, HelpCmp);
+
+ if (ncTemp.cn == -1L) {
+ ncTemp.mh = (mh)0;
+ ncTemp.cn = 0L;
+ } else {
+ ncTemp = combineNc(ncTemp.cn,fdbLocal.ncInit.mh);
+ }
+ // rjsa ncTemp = (ncTemp == -1L)
+ // ? 0
+ // : combineNc(ncTemp,HIGH(fdbLocal.ncInit));
+ }
+ }
+ }
+#endif
+ }
+ return ncNext;
+}
+
+/*************************************************************************
+**
+** HelpSzContext - Return string mapping to context number
+**
+** Purpose:
+** Construct a string, which when looked-up, will return the passed context
+** number.
+**
+** Entry:
+** pBuf = place to put the string
+** ncCur = The context number desired
+**
+** Exit:
+** True on sucess.
+**
+*/
+f pascal far LOADDS HelpSzContext (
+uchar far *pBuf,
+nc ncCur
+) {
+f fRet = FALSE; /* return value */
+ulong i;
+fdb fdbLocal; /* pointer to current FDB */
+mh mhCur; /* handle we're dealing with */
+char far *fpszContexts; /* pointer to context strings */
+
+*pBuf = 0;
+if (LoadFdb (ncCur.mh, &fdbLocal)) { /* lock fdb down */
+/*
+** Everybody starts with a filename
+*/
+ if (*fdbLocal.hdr.fname)
+ pBuf = hfstrcpy(pBuf,fdbLocal.hdr.fname);
+ else
+ pBuf = hfstrcpy(pBuf,fdbLocal.fname);
+ *(ushort far *)pBuf = '!'; /* includes null term */
+ pBuf++;
+ fRet = TRUE;
+
+ // if we've been given a local context number, see if we can synthesize
+ // a context number from which we might get a string. If we can't get
+ // one, then return just the filename.
+ //
+ if ((i = ncCur.cn) & 0x8000) { /* context # */
+ ncCur = MapTopictoContext ((ushort)(ncCur.cn & 0x7fff),&fdbLocal,0);
+ if ((i = ncCur.cn) & 0x8000) /* context # */
+ return fRet;
+ }
+/*
+** For compressed files (signified by being able to load context strings) we
+** just walk the context strings looking for string number "ncCur". Once found,
+** the returned string is just the concatenated filename, "!" and context
+** string.
+*/
+ mhCur = LoadPortion(HS_CONTEXTSTRINGS, ncCur.mh);
+ if (mhCur && (mhCur != (mh)(-1)) && (fpszContexts = HelpLock(mhCur))) {
+ if (i && (i <= fdbLocal.hdr.cContexts)) {
+ while (--i)
+ while (*fpszContexts++);/* point to next string */
+ hfstrcpy(pBuf,fpszContexts);/* copy over */
+ }
+ HelpUnlock (mhCur);
+ }
+ else if (fdbLocal.ftype & FTCOMPRESSED)
+ return FALSE;
+#if ASCII
+/*
+** for min ascii files, we search for the topic, and copy over the context
+** string directly from the file.
+*/
+ else if (fdbLocal.ftype & FTFORMATTED) {
+ long fpos;
+
+ if ((fpos = maLocate(&fdbLocal,szNil,NctoFo(ncCur.cn)-1,HelpCmp)) != -1L) {
+ fpos = ReadHelpFile(fdbLocal.fhHelp,fpos+2,pBuf,80);
+ *(pBuf+fpos) = 0; /* ensure terminated */
+ if (pBuf = hfstrchr(pBuf,'\r'))
+ *pBuf = 0; /* terminate at CR */
+ }
+ }
+#endif
+ }
+return fRet;
+/* end HelpSzContext */}
+
+/******************************************************************************
+**
+** LoadPortion - Load a section of the help file
+**
+** Purpose:
+** If not loaded, allocates memory for and loads a section (as defined in
+** helpfile.h) of the current help file. Once loaded, or if already loaded,
+** locks it, and returns the the memory handle and pointer.
+**
+** This routine must be far, since it is an entry point for HelpMake
+**
+** Entry:
+** hsCur = Help section to be loaded.
+** mhfdb = memory handle for fdb
+**
+** Exit:
+** returns handle for memory
+**
+** Exceptions:
+** returns NULL on portion not existing, 0xffff on inability to allocate memory.
+**
+*/
+mh pascal near LoadPortion (
+int hsCur,
+mh mhfdb
+) {
+fdb fdbLocal;
+char far *fpDest = 0;
+int i;
+mh mhNew = 0; /* pointer to mh destination */
+ushort osize; /* additional prepended size */
+ushort size;
+
+if (LoadFdb (mhfdb, &fdbLocal)) {
+ if (((mhNew = fdbLocal.rgmhSections[hsCur]) == 0)
+ && fdbLocal.hdr.tbPos[hsCur]) {
+
+ for (i=hsCur+1; i<HS_count; i++)
+ if (fdbLocal.hdr.tbPos[i]) {
+ size = (ushort)(fdbLocal.hdr.tbPos[i]-fdbLocal.hdr.tbPos[hsCur]);
+ break;
+ }
+
+ osize = (hsCur == HS_KEYPHRASE) ? 1024*sizeof(PVOID) : 0;
+/*
+** Alloc the memory required. Re-read the FDB, incase intervening calls to
+** HelpShrink causes deallocs of other beasties.
+*/
+ if ( (mhNew = HelpAlloc(size + osize))
+ && LoadFdb (mhfdb, &fdbLocal)) {
+ fdbLocal.rgmhSections[hsCur] = mhNew;
+ if (PutFdb (mhfdb, &fdbLocal)) {
+ fpDest = (char far *)HelpLock(mhNew);
+ if (fpDest && ReadHelpFile(fdbLocal.fhHelp
+ ,(ulong)fdbLocal.hdr.tbPos[hsCur] + fdbLocal.foff
+ ,fpDest + osize
+ ,size)) {
+
+ if (hsCur == HS_KEYPHRASE)
+ kwPtrBuild(fpDest,size);/* build keyword pointers */
+ HelpUnlock (mhNew);
+ }
+ else {
+ fdbLocal.rgmhSections[hsCur] = 0;
+ HelpDealloc (mhNew);
+ PutFdb (mhfdb, &fdbLocal);
+ mhNew = (mh)(-1);
+ }
+ }
+ else
+ mhNew = (mh)0;
+ }
+ else
+ mhNew = (mh)(-1);
+ }
+ }
+
+return mhNew;
+
+/* end LoadPortion */}
+
+/*************************************************************************
+**
+** SizePos - Return count of bytes in compressed topic, and position
+**
+** Purpose:
+** Returns the size in bytes of the compressed topic, and it's location in the
+** help file.
+**
+** Entry:
+** ncCur - Context number to return info on.
+** psize - Pointer to place to put the size
+** ppos - Pointer to place to put the position
+**
+** Exit:
+** Returns TRUE on success.
+**
+** Exceptions:
+** Returns FALSE on all errors.
+**
+** Algorithm:
+**
+** If current help handle valid
+** If filetype is compressed
+** If context map not loaded, load it
+** Lock context map
+** Map context to topic number
+** Unlock context map
+** If topic index not loaded, load it
+** Lock topic index
+** size is difference in file positions
+** Unlock topic index
+** else if filetype is formatted ascii
+** seek to context file position
+** scan for next context definition
+** size is difference in file positions
+** else if filetype is unformatted ascii
+** size is filesize
+*/
+f pascal near SizePos (
+nc ncCur,
+ushort *psize,
+ulong *ppos
+) {
+fdb fdbLocal; /* pointer to current FDB */
+char far *fpT; /* temp pointer */
+REGISTER f fRv = FALSE; /* return value */
+ushort iTopic; /* topic index */
+mh mhCur; /* handle being locked */
+
+if (LoadFdb (ncCur.mh, &fdbLocal)) { /* get fdb copy */
+ if (fdbLocal.ftype & FTCOMPRESSED) {/* if a standard compressed file*/
+ if ((iTopic = MapContexttoTopic (ncCur,&fdbLocal)) != 0xffff) {
+ mhCur = LoadPortion(HS_INDEX,ncCur.mh);
+ if (mhCur && (mhCur != (mh)(-1)) && (fpT = HelpLock(mhCur))) {
+ *ppos = ((long far *)fpT)[iTopic];
+ *psize = (ushort)(((long far *)fpT)[iTopic+1] - *ppos);
+ HelpUnlock (mhCur);
+ fRv = TRUE;
+ }
+ }
+ }
+
+#if ASCII
+ else if (fdbLocal.ftype & FTFORMATTED) {/* if a formatted ascii file*/
+ if ((*psize = (ushort)(maLocate(&fdbLocal, szNil, NctoFo(ncCur.cn)+4, HelpCmp)))
+ == 0xffff)
+ *psize = (ushort)ReadHelpFile(fdbLocal.fhHelp,0L,NULL,0);
+ else
+ *psize -= (ushort)NctoFo(ncCur.cn);
+ *ppos = (ulong) maLocate(&fdbLocal, szNil, NctoFo(ncCur.cn)-1, HelpCmp);
+ fRv = TRUE;
+ }
+ else { /* unformatted ascii */
+ *ppos = ReadHelpFile(fdbLocal.fhHelp,0L,NULL,0);
+ *psize = (*ppos > (ulong)(65535-sizeof(topichdr)-4))
+ ? (ushort)(65535-sizeof(topichdr)-4)
+ : (ushort)*ppos;
+ *ppos = 0L; /* position is always zero. */
+ fRv = TRUE;
+ }
+#endif
+ }
+
+return fRv;
+/* end SizePos */}
+
+/************************************************************************
+**
+** MapContexttoTopic
+**
+** Purpose:
+** Given a context number, return the topic number which it maps to. This
+** is just a direct index of the context number into the context map.
+**
+** Entry:
+** ncCur = context number to be mapped
+** fpfdbCur = pointer to associated fdb
+**
+** Exit:
+** Returns zero based topic number, or 0xffff on error.
+*/
+ushort pascal near MapContexttoTopic (
+nc ncCur, /* context number to map */
+fdb far *fpfdbCur /* pointer to current FDB */
+) {
+REGISTER ushort topic = 0xffff; /* value to return */
+ushort far *fpT; /* pointer to context map */
+mh mhCur; /* handle being locked */
+
+if (ncCur.cn) {
+/*
+** Local contexts: the topic number is already encoded in the low word, if the
+** high bit of that word is set.
+*/
+ if (ncCur.cn & 0x8000)
+ topic = (ushort)(ncCur.cn & 0x7fff);
+/*
+** Normal Contexts: low word of nc is an index into the context map which
+** returns the topic number
+*/
+ else {
+ mhCur = LoadPortion(HS_CONTEXTMAP,fpfdbCur->ncInit.mh);
+ if (mhCur && (mhCur != (mh)(-1)) && (fpT = HelpLock(mhCur))) {
+ topic = fpT[ncCur.cn-1];
+ HelpUnlock (mhCur);
+ }
+ }
+ }
+return topic;
+/* end MapContexttoTopic */}
+
+/************************************************************************
+**
+** MapTopictoContext
+**
+** Purpose:
+** Given a topic number, return a context which maps to it.
+**
+** This involves searching the context map for the first context entry that
+** maps to the desired topic number.
+**
+** Entry:
+** iTopic = topic number to map back to a context number
+** fpfdbCur = pointer to associated fdb
+**
+** Exit:
+** Returns a valid nc into the file.
+**
+** Exceptions:
+** If the incoming iTopic is invalid, or a read error occurs, then the nc
+** returned refers to the topic number 0.
+**
+*/
+nc pascal near MapTopictoContext(
+ushort iTopic, /* topic number to map */
+fdb far *fpfdbCur, /* pointer to current FDB */
+int Dir
+) {
+ ushort cTopics; /* number of topics to search */
+ ushort far *fpContextMap; /* pointer to the context map */
+ mh mhPortion; /* mem handle for the context map*/
+ nc ncMatch = {0,0}; /* return value */
+
+ mhPortion = LoadPortion (HS_CONTEXTMAP,fpfdbCur->ncInit.mh);
+ if (mhPortion && (mhPortion != (mh)(-1))) {
+ if (fpContextMap = HelpLock(mhPortion)) {
+ if (iTopic >= fpfdbCur->hdr.cTopics) {
+ iTopic = 0;
+ }
+ ncMatch.mh = (mh)0L;
+ ncMatch.cn = 0x8000 | iTopic;
+ // rjsa ncMatch = 0x8000 | iTopic;
+ cTopics = 0;
+ while (cTopics < fpfdbCur->hdr.cContexts) {
+ if ( Dir == 0 ) {
+ if (iTopic == fpContextMap[cTopics++]) {
+ ncMatch.cn = cTopics; /* nc's are one based */
+ break;
+ }
+ } else if ( Dir > 0 ) {
+ if (iTopic <= fpContextMap[cTopics++]) {
+ ncMatch.cn = cTopics; /* nc's are one based */
+ break;
+ }
+
+ } else if ( Dir < 0 ) {
+
+ if (iTopic == fpContextMap[cTopics++]) {
+ ncMatch.cn = cTopics;
+ break;
+ } else if (iTopic < fpContextMap[cTopics-1]) {
+ ncMatch.cn = cTopics-1;
+ break;
+ }
+ }
+ }
+ //if ( iTopic != fpContextMap[cTopics-1] ) {
+ // ncMatch.cn = 0;
+ //}
+ if ( cTopics >= fpfdbCur->hdr.cContexts) {
+ ncMatch.cn = 0;
+ }
+ HelpUnlock (mhPortion);
+ }
+ }
+ ncMatch.mh = (fpfdbCur->ncInit).mh;
+ return ncMatch;
+ // rjsa return ncMatch | HIGHONLY(fpfdbCur->ncInit);
+}
+
+/************************************************************************
+**
+** LoadFdb - make local copy of fdb.
+**
+** Purpose:
+** Used to create a local copy of an FDB, so that we don't have to keep a
+** locked, far copy around.
+**
+** Entry:
+** mhFdb - memory handle for the FDB
+** fpFdbDest - Pointer to destination for FDB copy
+**
+** Exit:
+** returns TRUE if FDB copied.
+*/
+f pascal near LoadFdb (
+mh mhfdb,
+fdb far *fpfdbDest
+) {
+fdb far *fpfdbCur; /* pointer to current FDB */
+
+if (fpfdbCur = HelpLock (mhfdb)) {
+ *fpfdbDest = *fpfdbCur;
+ HelpUnlock (mhfdb);
+ return TRUE;
+ }
+return FALSE;
+/* end LoadFdb */}
+
+/************************************************************************
+**
+** PutFdb - make local copy of fdb permanent.
+**
+** Purpose:
+** Used to copy a local copy of an FDB to the "real" one, so that we don't
+** have to keep a locked, far copy around.
+**
+** Entry:
+** mhFdb - memory handle for the FDB
+** fpfdbSrc - Pointer to source of FDB copy
+**
+** Exit:
+** returns TRUE if FDB copied.
+*/
+f pascal near PutFdb (
+mh mhfdb,
+fdb far *fpfdbSrc
+) {
+fdb far *fpfdbCur; /* pointer to current FDB */
+
+if (fpfdbCur = HelpLock (mhfdb)) {
+ *fpfdbCur = *fpfdbSrc;
+ HelpUnlock (mhfdb);
+ return TRUE;
+ }
+return FALSE;
+/* end PutFdb */}
+
+#if ASCII
+/************************************************************************
+**
+** maLocate - Locate context in minimally formatted ascii file.
+**
+** Purpose:
+** Performs sequential searches on mimimally formatted ascii files to locate
+** lines beginning with ">>" and a context string.
+**
+** Entry:
+** fpfdbCur = Pointer to current fdb
+** fpszSrc = Pointer to context string to be found (or null for next
+** string)
+** offset = offset at which to begin search.
+** lpfnCMp = pointer to comparison routine to use
+**
+** Exit:
+** returns file offset of ">>" of context string.
+**
+** Exceptions:
+** returns -1 on error.
+**
+*/
+long pascal near maLocate (
+fdb far *fpfdbCur,
+uchar far *fpszSrc,
+ulong offset,
+f (pascal far *lpfnCmp)(uchar far *, uchar far *, ushort, f, f)
+) {
+uchar buffer[MASIZE+1]; /* input buffer */
+ushort cbBuf = 0; /* count of bytes in buffer */
+ushort cbSrc; /* length of source string */
+uchar far *pBuf; /* pointer into buffer */
+uchar far *pBufT; /* temp pointer into buffer */
+
+cbSrc = hfstrlen(fpszSrc)+1; /* get length of input */
+if (offset == 0xffffffff) /* special case */
+ offset = 0;
+while (cbBuf += (ushort)ReadHelpFile(fpfdbCur->fhHelp
+ , offset+cbBuf
+ , buffer+cbBuf
+ , MASIZE-cbBuf)) {
+
+ buffer[cbBuf] = 0; /* ensure strings terminated */
+ pBuf = &buffer[0];
+ while (pBuf = hfstrchr(pBuf,'>')) { /* look for start of context */
+ if ((*(pBuf+1) == '>') /* if >> found */
+ && ((*(pBuf-1) == '\n') /* at beginning of line */
+ || ((offset == 0) /* or beginning of file */
+ && (pBuf == (char far *)&buffer[0])))) {
+ pBufT = pBuf +2;
+ if (lpfnCmp (fpszSrc, pBufT, cbSrc, FALSE, TRUE))
+ return offset + (ulong)(pBuf - (uchar far *)&buffer[0]);
+ }
+ pBuf += 2;
+ }
+ if (cbBuf == MASIZE) { /* if buffer full */
+ hfstrcpy(buffer,buffer+MASIZE-MAOVER); /* copy down overlap */
+ cbBuf = MAOVER; /* and leave that in */
+ offset += MASIZE-MAOVER; /* file pos of buffer[0] */
+ }
+ else {
+ offset += cbBuf;
+ cbBuf = 0; /* else we're empty */
+ }
+ }
+return -1;
+
+/* end maLocate */}
+#endif
diff --git a/private/utils/mep/help/enginlib/helpcell.c b/private/utils/mep/help/enginlib/helpcell.c
new file mode 100644
index 000000000..cb1d64900
--- /dev/null
+++ b/private/utils/mep/help/enginlib/helpcell.c
@@ -0,0 +1,138 @@
+/*** helpcell.c - HelpGetCells routine.
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Purpose:
+*
+* Revision History:
+*
+* 25-Jan-1990 ln locate -> hlp_locate
+* [] 04-Aug-1988 LN Created...split from helpif.c. Added auto-fill.
+*
+*************************************************************************/
+
+#include <stdio.h>
+
+#if defined (OS2)
+#else
+#include <windows.h>
+#endif
+
+#include "help.h"
+#include "helpfile.h"
+#include "helpsys.h"
+
+/************************************************************************
+**
+** Foward Declarations
+*/
+uchar near pascal toupr(uchar);
+
+/************************************************************************
+**
+** HelpGetCells - Return a string of character / attribute pairs from helpfile
+**
+** Purpose:
+** Interpret the help files stored format and return a line at a time of
+** character & attribute information.
+**
+** Entry:
+** ln = 1 based line number to return
+** cbMax = Max number of characters to transfer
+** pbDst = pointer to destination
+** pbTopic = pointer to topic text
+** prgAttr = pointer to array of character attributes
+**
+** Exit:
+** returns number of bytes transfered, or -1 if that line does not exist.
+** DOES blank fill to the cbMax width.
+**
+** Exceptions:
+**
+*/
+int far pascal LOADDS HelpGetCells(ln,cbMax,pbDst,pbTopic,prgAttr)
+int ln;
+int cbMax;
+char far *pbDst;
+PB pbTopic;
+uchar far *prgAttr;
+{
+ushort cbAttr; /* length of current attribute */
+ushort cbAttrCur = 0; /* length of current attribute */
+ushort cbSrc; /* count of source characters */
+uchar cAttrCur; /* current attribute */
+uchar iAttrCur; /* index to current attribute */
+uchar far *pTopic; /* pointer to topic */
+uchar far *pchSrc; /* pointer to source characters */
+topichdr far *pHdr; /* pointer to topic header */
+
+pTopic = PBLOCK (pbTopic);
+pHdr = (topichdr far *)pTopic;
+if ((pTopic = hlp_locate(ln,pTopic)) == NULL)/* locate line */
+ ln = -1;
+
+else if (pHdr->ftype & FTCOMPRESSED) {
+ ln=0;
+ pchSrc = pTopic; /* point to character data */
+ pTopic += (*pTopic); /* point to attribute data */
+ cbAttr = *((ushort far UNALIGNED *)pTopic)++ - (ushort)sizeof(ushort);/* count of attribute bytes */
+ cbSrc = (ushort)((*pchSrc++) -1); /* get count of characters */
+
+ while (cbSrc-- && cbMax--) { /* while characters to get */
+/*
+ * Time for a new attribute. If there are attributes left (cbAttr > 0) then
+ * just get the next one (length & index). If there weren't any left, or the
+ * last one had an index of 0xff (indicating end), then we'll use the index
+ * zero attribute byte, else pick up the current attribute byte and move on
+ * in the attribute string.
+ */
+ if (cbAttrCur == 0) {
+ if (cbAttr > 0) {
+ cbAttrCur = ((intlineattr far UNALIGNED *)pTopic)->cb;
+ iAttrCur = ((intlineattr far UNALIGNED *)pTopic)->attr;
+ }
+ if ((cbAttr <= 0) || (iAttrCur == 0xff))
+ cAttrCur = prgAttr[0];
+ else {
+ cAttrCur = prgAttr[iAttrCur];
+ ((intlineattr far *)pTopic)++;
+ cbAttr -= 2;
+ }
+ }
+ *((ushort far UNALIGNED *)pbDst)++ = (ushort)((cAttrCur << 8) | *pchSrc++); /* stuff char & attr*/
+ cbAttrCur--;
+ ln += 2;
+ }
+ }
+#if ASCII
+else {
+/*
+** For ascii files, just copy line over with attr[0]
+*/
+ ln=0;
+ while (*pTopic && (*pTopic != '\r') && cbMax--) {
+ if (*pTopic == '\t') {
+ pTopic++;
+ do {
+ *((ushort far UNALIGNED *)pbDst)++ = (ushort)((prgAttr[0] << 8) | ' ');
+ ln += 2;
+ }
+ while ((ln % 16) && cbMax--);
+ }
+ else {
+ *((ushort far UNALIGNED *)pbDst)++ = (ushort)((prgAttr[0] << 8) | *pTopic++);
+ ln += 2;
+ }
+ }
+ }
+#endif
+#if 0
+/*
+ * blank fill the rest of the line
+ */
+while (cbMax--)
+ *((ushort far UNALIGNED *)pbDst)++ = (prgAttr[0] << 8) | ' '; /* stuff char & attr*/
+#endif
+PBUNLOCK (pbTopic);
+return ln;
+/* end HelpGetCells */}
diff --git a/private/utils/mep/help/enginlib/helpcnt.c b/private/utils/mep/help/enginlib/helpcnt.c
new file mode 100644
index 000000000..8e64feb6a
--- /dev/null
+++ b/private/utils/mep/help/enginlib/helpcnt.c
@@ -0,0 +1,54 @@
+/*** helpcnt.c - HelpcLines routine.
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+*
+* 25-Jan-1990 ln locate -> hlp_locate
+* 19-Aug-1988 ln Changed to use new locate routine.
+* [] 10-Aug-1988 LN Created
+*
+*************************************************************************/
+
+#include <stdio.h>
+
+#if defined (OS2)
+#else
+#include <windows.h>
+#endif
+
+#include "help.h"
+#include "helpfile.h"
+#include "helpsys.h"
+
+
+/*** HelpcLines - Return number of lines in topic
+*
+* Purpose:
+* Interpret the help files stored format and return the number of lines
+* contained therein.
+*
+* It *is* sensitive to the applications control character, again just like
+* HelpGetLine, and will return total number of lines if the header.linChar
+* is set to 0xff, or the number of lines that do NOT begin with
+* header.linChar.
+*
+* Input:
+* pbTopic = pointer to topic text
+*
+* Output:
+* Returns number of lines in topic.
+*
+*************************************************************************/
+int far pascal LOADDS HelpcLines(
+PB pbTopic
+) {
+REGISTER ushort cLines; /* count of lines */
+uchar far *pTopic; /* pointer to topic */
+
+pTopic = PBLOCK (pbTopic);
+cLines = (ushort)hlp_locate (-1,pTopic);
+PBUNLOCK (pbTopic);
+
+return cLines;
+/* end HelpcLines */}
diff --git a/private/utils/mep/help/enginlib/helpdec.c b/private/utils/mep/help/enginlib/helpdec.c
new file mode 100644
index 000000000..0f6324a52
--- /dev/null
+++ b/private/utils/mep/help/enginlib/helpdec.c
@@ -0,0 +1,722 @@
+/*************************************************************************
+ * helpdec - HelpDecomp routine and Other ASM code
+ *
+ * Copyright <C> 1988, Microsoft Corporation
+ *
+ * Purpose:
+ *
+ * Revision History:
+ *
+ * 08-Oct-1990 RJSA Converted to C
+ * 22-Dec-1988 LN Removed MASM High Level Lang support (Need
+ * to control segments better than that will
+ * let me)
+ * 08-Dec-1988 LN CSEG
+ * 16-Feb-1988 LN Rewrite for (some) speed
+ * [] 17-Jan-1988 LN Created
+ *
+ **************************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#if defined (OS2)
+#define INCL_BASE
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+
+#include <help.h>
+#include <helpfile.h>
+
+#pragma function( memset, memcpy, memcmp, strcpy, strcmp, strcat )
+
+// In order to increase performance, and because of the functions
+// decomp and NextChar being tightly coupled, global variables are
+// used instead of passing parameters.
+//
+
+PBYTE pHuffmanRoot; // Root of Huffman Tree
+PBYTE pCompTopic; // Current pointer to text (compressed)
+BYTE BitMask; // Rotating bit mask
+BOOL IsCompressed; // True if text is compressed
+
+
+BYTE NextChar (void);
+BOOL pascal HelpCmp (PCHAR fpsz1, PCHAR fpsz2, USHORT cbCmp, BOOL fCase, BOOL fTerm);
+
+
+/**************************************************************************
+ *
+ * Decomp - Decompress Topic Text
+ * f near pascal Decomp(fpHuffmanRoot, fpKeyphrase, fpTopic, fpDest)
+ * uchar far *fpHuffmanRoot
+ * uchar far *fpKeyphrase
+ * uchar far *fpTopic
+ * uchar far *fpDest
+ *
+ * Purpose:
+ * Fully decompress topic text. Decompresses based on current file, from one
+ * buffer to another.
+ *
+ * Entry:
+ * fpHuffmanRoot - Pointer to root of huffman tree (or NULL if no huffman)
+ * fpKeyphrase - Pointer to keyphrase table (or NULL if no keyphrase)
+ * fpTopic - Pointer to compressed topic text
+ * fpDest - Pointer to destination buffer
+ *
+ * Exit:
+ * FALSE on successful completion
+ *
+ * Exceptions:
+ * Returns TRUE on any error.
+ *
+ **************************************************************************/
+BOOL pascal decomp (
+ PCHAR fpHuffmanRoot,
+ PCHAR fpKeyphrase,
+ PCHAR fpTopic,
+ PCHAR fpDest
+ ){
+
+ int cDecomp; /* count of totally decompressed */
+ BYTE c; /* byte read */
+
+#ifdef BIGDEBUG
+ char DbgB[128];
+ char *DbgP = fpDest;
+#endif
+
+
+ // Initialize global variables.
+
+ pHuffmanRoot = (PBYTE)fpHuffmanRoot;
+ pCompTopic = (PBYTE)fpTopic + sizeof(USHORT);
+ BitMask = 0x01;
+ IsCompressed = fpHuffmanRoot
+ ? ((*(USHORT UNALIGNED *)((PBYTE)fpHuffmanRoot + 2)) != 0xFFFF)
+ : FALSE;
+
+ cDecomp = *((USHORT UNALIGNED *)fpTopic);
+
+#ifdef BIGDEBUG
+ sprintf(DbgB, "DECOMPRESSING: HuffmanRoot: %lx, Keyphrase: %lx\n", fpHuffmanRoot, fpKeyphrase );
+ OutputDebugString(DbgB);
+ sprintf(DbgB, " Topic: %lx, Dest: %lx\n", fpTopic, fpDest );
+ OutputDebugString(DbgB);
+ if ( IsCompressed ) {
+ OutputDebugString(" The Topic IS Compressed\n");
+ }
+#endif
+
+ while ( cDecomp > 0 ) {
+
+ c = NextChar();
+
+ //
+ // At this point a valid character has been found and huffman decoded. We must
+ // now perform any other decoding on it that is required.
+ //
+ // Variables are:
+ // c = character
+ // cDecomp = Output count remaining
+ // BitMask = bit mask for interpreting input stream
+ //
+ // "Magic Cookie" decompression.
+ // The chararacter stream after huffman encoding is "cookie" encoded, in that
+ // certain characters are flags which when encountered mean something other than
+ // themselves. All characters which are NOT such flags (or cookies, as they seem
+ // to be called), are simply copied to the output stream.
+ //
+ // We first check the character to see if it IS a cookie. If it is NOT, we just
+ // store it, and get the next input byte
+ //
+
+ if ((c >= C_MIN) && (c <= C_MAX)) {
+
+ BYTE Cookie = c ;
+
+#ifdef BIGDEBUG
+ OutputDebugString("Cookie\n");
+#endif
+ // c is a cookie of some sort, jump to the appropriate
+ // cookie eater.
+
+ c = NextChar();
+
+ switch (Cookie) {
+ case C_KEYPHRASE0:
+ case C_KEYPHRASE1:
+ case C_KEYPHRASE2:
+ case C_KEYPHRASE3:
+ case C_KEYPHRASE_SPACE0:
+ case C_KEYPHRASE_SPACE1:
+ case C_KEYPHRASE_SPACE2:
+ case C_KEYPHRASE_SPACE3:
+ {
+ ULONG Index; /* Keyword index */
+ PBYTE pKey; /* Keyword */
+ BYTE Size; /* Keyword size */
+
+ if ((Cookie >= C_KEYPHRASE_SPACE0) && (Cookie <= C_KEYPHRASE_SPACE3)) {
+ Index = (ULONG)((int)Cookie - C_MIN - 4);
+ } else {
+ Index = (ULONG)((int)Cookie - C_MIN);
+ }
+ Index = (ULONG)(((Index * 0x100) + c) * sizeof(PVOID));
+
+ pKey = *(PBYTE *)(((PBYTE)fpKeyphrase) + Index);
+
+ // pKey = *(PBYTE *)(fpKeyphrase + Index);
+
+ Size = *pKey++;
+
+ {
+ BYTE i = Size;
+
+ while (i--) {
+ *fpDest++ = *pKey++;
+ }
+ cDecomp -=Size;
+ }
+ if ((Cookie >= C_KEYPHRASE_SPACE0) && (Cookie <= C_KEYPHRASE_SPACE3)) {
+ *fpDest++ = ' ';
+ cDecomp--;
+ }
+ break;
+ }
+
+ case C_RUNSPACE:
+ {
+ BYTE Count = c;
+
+ while (Count--) {
+ *fpDest++ = ' ';
+ }
+ cDecomp -= c;
+ break;
+ }
+
+ case C_RUN:
+ {
+ BYTE b = c;
+ BYTE Cnt;
+
+ Cnt = c = NextChar();
+
+ while (Cnt--) {
+ *fpDest++ = b;
+ }
+ cDecomp -= c;
+ break;
+ }
+
+ case C_QUOTE:
+ *fpDest++ = c;
+ cDecomp--;
+ break;
+
+ }
+
+ } else {
+
+ // c is not a cookie
+
+ *fpDest++ = c;
+ cDecomp--;
+ }
+ }
+
+ *fpDest++ = '\00'; // Null terminate string
+
+#ifdef BIGDEBUG
+ sprintf( DbgB, "Decompressed topic: [%s]\n", DbgP );
+ OutputDebugString( DbgB );
+
+ if ( cDecomp < 0 ) {
+ sprintf( DbgB, "DECOMPRESSION ERROR: cDecomp = %d!\n", cDecomp );
+ OutputDebugString(DbgB);
+ }
+#endif
+
+ return FALSE;
+}
+
+
+
+
+/**************************************************************************
+ *
+ * NextChar - Return next character from input stream
+ *
+ * Purpose:
+ * Returns next character from input stream, performing huffman decompression
+ * if enabled.
+ *
+ * Entry:
+ * fpHuffmanRoot = pointer to root of huffman tree
+ * pfpTopic = pointer to pointer to Topic
+ * pBitmask = pointer to bit mask of current bit
+ *
+ * Exit:
+ * Returns character
+ * *pfpTopic and *pBitMask updated.
+ *
+ **************************************************************************
+ *
+ * Format of Huffman decode tree:
+ * The Huffman decode tree is a binary tree used to decode a bitstream into a
+ * character stream. The tree consists of nodes (internal nodes and leaves).
+ * Each node is represented by a word. If the high bit in the word is set then
+ * the node is a leaf. If the node is an internal node, then the value of the
+ * node is the index of the right branch in the binary tree. The left branch is
+ * the node following the current node (in memory). If the node is a leaf, then
+ * the low byte of the node is a character.
+ *
+ * e.g.
+ * 0: 0004 0
+ * 1: 0003 / \
+ * 2: 8020 / \
+ * 3: 8065 1 \------4
+ * 4: 0006 / \ / \
+ * 5: 806C / \ / \
+ * 6: 8040 2 3 5 6
+ * ' ' 'e' 'l' '@'
+ *
+ * Using the Huffman decode tree:
+ * The huffman decode tree is used to decode a bitstream into a character
+ * string. The bitstream is used to traverse the decode tree. Whenever a zero
+ * is detected in the bit stream we take the right branch, when one is detected
+ * we take the left branch. When a leaf is reached in the tree, the value of
+ * the leaf (a character) is output, and the current node is set back to the
+ *
+ ********************************************************************/
+
+BYTE
+NextChar (
+ void
+ ) {
+
+ BYTE b; // current source byte
+
+#ifdef BIGDEBUG
+ char DbgB[128];
+ OutputDebugString("NextChar:\n");
+#endif
+
+ if (IsCompressed) {
+
+ USHORT HuffmanNode; // curent node in the huffman tree
+ USHORT UNALIGNED *pHuffmanNext; // next node in the huffman tree
+
+ //
+ // Huffman decoding.
+ // This first part of the decode loop performs the actual huffman decode. This
+ // code is very speed critical. We walk the tree, as defined by the bit pattern
+ // coming in, and exit this portion of the code when we reach a leaf which
+ // contains the character that the bit pattern represented.
+ //
+
+ pHuffmanNext = (USHORT UNALIGNED *)pHuffmanRoot;
+ HuffmanNode = *pHuffmanNext;
+
+ b = *(pCompTopic - 1); // get last byte read
+
+ while (!(HuffmanNode & 0x8000)) { // while not leaf
+
+ BitMask >>= 1;
+
+ if (!(BitMask)) {
+ //
+ // Get new byte from input
+ //
+ b = *pCompTopic++;
+ BitMask = 0x80;
+#ifdef BIGDEBUG
+ sprintf(DbgB, "\tb=%02x Mask=%02x Node=%04x", b, BitMask, HuffmanNode );
+ OutputDebugString(DbgB);
+#endif
+ } else {
+#ifdef BIGDEBUG
+ sprintf(DbgB, "\tb=%02x Mask=%02x Node=%04x", b, BitMask, HuffmanNode );
+ OutputDebugString(DbgB);
+#endif
+ }
+
+ if (b & BitMask) {
+ //
+ // one: take left branch
+ //
+ pHuffmanNext++;
+ } else {
+ //
+ // zero: take right branch
+ //
+ pHuffmanNext = (PUSHORT)((PBYTE)pHuffmanRoot + HuffmanNode);
+#ifdef BIGDEBUG
+ sprintf(DbgB, " <%04x+%02x=%04x (%04x)>", pHuffmanRoot, HuffmanNode,
+ pHuffmanNext, *pHuffmanNext );
+ OutputDebugString( DbgB );
+#endif
+ }
+
+ HuffmanNode = *pHuffmanNext;
+
+#ifdef BIGDEBUG
+ sprintf(DbgB, " Next=%04x\n", HuffmanNode );
+ OutputDebugString(DbgB);
+#endif
+
+ }
+
+ b = (BYTE)HuffmanNode; // character is low byte of leaf node
+
+ } else {
+ b = *pCompTopic++; // not compressed, simply return byte
+ }
+
+#ifdef BIGDEBUG
+ sprintf(DbgB, "\t---->%2x [%c]\n", b,b);
+ OutputDebugString(DbgB);
+#endif
+
+ return b;
+}
+
+
+/**************************************************************************
+ *
+ * HelpCmpSz - help system string comparison routine.
+ * f near pascal HelpCmpSz (fpsz1, fpsz2)
+ * uchar far *fpsz1*
+ * uchar far *fpsz2*
+ *
+ * Purpose:
+ * Perform string comparisons for help system look-up.
+ * Default case of HelpCmp below.
+ *
+ * Entry:
+ * fpsz1 = Far pointer to string 1. (Usually the constant string
+ * being "looked-up".
+ * fpsz2 = Far pointer to string 2. This is usually the string table
+ * being searched.
+ *
+ * Exit:
+ * TRUE on match
+ *
+ ********************************************************************/
+BOOL pascal
+HelpCmpSz (
+ PCHAR fpsz1,
+ PCHAR fpsz2
+ ){
+ return HelpCmp(fpsz1, fpsz2, (USHORT)0xFFFF, TRUE, FALSE); // fcase, fTerm
+}
+
+
+/**************************************************************************
+ *
+ * HelpCmp - help system string comparison routine.
+ * f near pascal HelpCmp (fpsz1, fpsz2, cbCmp, fCase, fTerm)
+ * uchar far *fpsz1
+ * uchar far *fpsz2
+ * ushort cbCmp
+ * f fCase
+ * f fTerm
+ *
+ * Purpose:
+ * Perform string comparisons for help system look-up.
+ *
+ * Entry:
+ * fpsz1 = Far pointer to string 1. (Usually the constant string being
+ * "looked-up"). NOTE THAT IF THIS STRING IS NULL, WE RETURN
+ * TRUE!
+ * fpsz2 = Far pointer to string 2. This is usually the string table
+ * being searched.
+ * cbCmp = Max number of bytes to compare.
+ * fCase = TRUE if search is to be case sensitive.
+ * fTerm = TRUE if we allow special termination processing.
+ *
+ * Exit:
+ * TRUE on match
+ *
+ ********************************************************************/
+
+BOOL pascal
+HelpCmp (
+ PCHAR fpsz1,
+ PCHAR fpsz2,
+ USHORT cbCmp,
+ BOOL fCase,
+ BOOL fTerm
+ ){
+
+ register PBYTE p1 = (PBYTE)fpsz1;
+ register PBYTE p2 = (PBYTE)fpsz2;
+
+ while (cbCmp--) {
+
+ if ((!*p1) && (!*p2)) {
+ //
+ // Got a match
+ //
+ return TRUE;
+ }
+
+ if (!fCase) {
+ if (toupper((char)*p1) != toupper((char)*p2)) {
+ break;
+ }
+ p1++;
+ p2++;
+ } else {
+ if (*p1++ != *p2++) {
+ break;
+ }
+ }
+ }
+
+ if (!cbCmp) {
+ return TRUE;
+ }
+
+
+ // At this point, we have terminated the comparison. Termination conditions
+ // were:
+ //
+ // character count exausted: CX == zero. (Complete match, return TRUE)
+ // Null terminator found: CX != zero, & Zero flag set. (Complete match,
+ // return TRUE)
+ // non-match found CX != zero, & Zero flag clear.
+ //
+ // In the later case, if special termination processing is NOT selected, we
+ // return FALSE, having found a mis-match.
+ //
+ // If special termination processing is TRUE, then if the mismatched character
+ // from string 1 is a null, and the mismatched character from string 2 is any
+ // whitespace or CR, we declare a match. (This is used in minascii processing).
+ //
+
+ if (fTerm) {
+ p1--; p2--;
+ if ((! *p1) &&
+ ((*p2 == '\n') || (*p2 == '\t') || (*p2 == ' '))) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+/*************************************************************************
+ *
+ * hfstrlen - far string length
+ *
+ * Purpose:
+ * return length of null terminated string.
+ *
+ * Entry:
+ * fpszSrc = pointer to source
+ *
+ * Exit:
+ * returns length
+ *
+ *************************************************************************/
+USHORT
+hfstrlen (
+ PCHAR fpszSrc
+ ){
+ return (USHORT)strlen(fpszSrc);
+}
+
+
+/*************************************************************************
+ *
+ * hfstrcpy - far string copy
+ *
+ * Purpose:
+ * copy strings
+ *
+ * Entry:
+ * fpszDst = pointer to destination
+ * fpszSrc = pointer to source
+ *
+ * Exit:
+ * pointer to terminating null in destination
+ *
+ *************************************************************************/
+PCHAR
+hfstrcpy (
+ PCHAR fpszDst,
+ PCHAR fpszSrc
+ ) {
+ return (PCHAR)strcpy(fpszDst, fpszSrc);
+}
+
+
+
+/*************************************************************************
+ *
+ * hfstrchr - search for character in far string
+ *
+ * Purpose:
+ * a near, pascal routine (for size/speed) to search for a character in
+ * a far string.
+ *
+ * Entry:
+ * fpsz = far pointer to string
+ * c = character to locate
+ *
+ * Exit:
+ * returns far pointer into string
+ *
+ * Exceptions:
+ * returns NULL on character not in string
+ *
+ *************************************************************************/
+PCHAR
+hfstrchr (
+ PCHAR fpsz,
+ char c
+ ){
+ return (PCHAR)strchr(fpsz, c);
+}
+
+
+
+/*************************************************************************
+ *
+ * hfmemzer - zero out memory area.
+ *
+ * Purpose:
+ * a near, pascal routine (for size/speed) to fill an area with zero
+ *
+ * Entry:
+ * fpb = far pointer to buffer
+ * cb = count of zeros to store
+ *
+ * Exit:
+ *
+ *************************************************************************/
+void
+hfmemzer (
+ PVOID fpb,
+ ULONG cb
+ ) {
+ memset(fpb, '\00', cb);
+}
+
+
+
+
+/*************************************************************************
+ *
+ * NctoFo - extract file offset from NC
+ *
+ * Purpose:
+ * Extracts the file offset for a minascii file, and returns it as a long.
+ *
+ * Entry:
+ * nc = context number
+ *
+ * Exit:
+ * returns file offset
+ *
+ *************************************************************************/
+ULONG
+NctoFo (
+ ULONG nc
+ ) {
+ nc = nc & 0x0000FFFF;
+ nc *= 4;
+ return nc;
+}
+
+
+
+/*************************************************************************
+ *
+ * combineNc - combine a minascii file offset and fdb handle into nc.
+ *
+ * Purpose:
+ * Combines a minascii file offset and fdb memory handle into an NC. If the
+ * file offset is 0xffffffff, we return zero.
+ *
+ * Entry:
+ * offset = long file offset
+ * mh = fdb mem handle
+ *
+ * Exit:
+ * returns NC (DX = mem handle, AX = filepos/4), or 0L if offset==FFFFFFFF
+ *
+ *************************************************************************/
+nc pascal
+combineNc (
+ ULONG offset,
+ mh mh
+ ){
+ nc ncRet = {0,0};
+ if (offset = 0xFFFFFFFF) {
+ return ncRet;
+ }
+ ncRet.mh = mh;
+ ncRet.cn = offset/4;
+ return ncRet;
+}
+
+
+/*************************************************************************
+ *
+ * toupr - convert char to upper case
+ *
+ * Purpose:
+ *
+ * Entry:
+ * chr = character
+ *
+ * Exit:
+ * returns upper case character
+ *
+ *************************************************************************/
+char
+toupr (
+ char chr
+ ){
+ return (char)toupper(chr);
+}
+
+
+
+/*************************************************************************
+ *kwPtrBuild - Build table of pointers to keywords.
+ *void pascal near kwPtrBuild(uchar far *fpTable, ushort tsize)
+ *
+ *Purpose:
+ * Builds a table of pointers to the keyword strings in the passed string array.
+ * The table is built in the first 4k of the passed buffer. The strings are
+ * assummed to start immediately thereafter.
+ *
+ *Entry:
+ * fpTable - pointer to string table
+ * tsize - size, in bytes, of strings
+ *
+ *Exit:
+ * none
+ *
+ *******************************************************************************/
+void
+kwPtrBuild (
+ PVOID fpTable,
+ USHORT tsize
+ ) {
+ PBYTE fpStr = (PBYTE)fpTable + 1024 * sizeof (PVOID);
+ PBYTE *fpTbl = fpTable;
+ while (tsize > 0) {
+ UCHAR sSize = (UCHAR)(*fpStr) + (UCHAR)1;
+ *fpTbl++ = fpStr;
+ tsize -= sSize;
+ fpStr += sSize;
+ }
+}
diff --git a/private/utils/mep/help/enginlib/helpdll.c b/private/utils/mep/help/enginlib/helpdll.c
new file mode 100644
index 000000000..4f9a28754
--- /dev/null
+++ b/private/utils/mep/help/enginlib/helpdll.c
@@ -0,0 +1,190 @@
+/*************************************************************************
+**
+** helpdll - stubs for call-back routines when used as dll.
+**
+** Copyright <C> 1987, Microsoft Corporation
+**
+** Purpose:
+**
+** Revision History:
+**
+** 12-Mar-1990 ln CloseFile -> HelpCloseFile
+** [] 22-Jan-1988 LN Created
+**
+*************************************************************************/
+
+#include <stdio.h>
+#include <malloc.h>
+#if defined (OS2)
+#define INCL_BASE
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include "help.h" /* global (help & user) decl */
+#include "helpsys.h" /* internal (help sys only) decl*/
+
+
+#ifdef OS2
+int _acrtused; /* define to disable crt0 */
+#endif
+
+char far * pascal near hfstrchr(char far *, char);
+
+/************************************************************************
+ *
+ * OpenFileOnPath - Open a file located somewhere on the PATH
+ *
+ * Purpose:
+ *
+ * Entry:
+ * pszName - far pointer to filename to open
+ * mode - read/write mode
+ *
+ * Exit:
+ * returns file handle
+ *
+ * Exceptions:
+ * return 0 on error.
+ *
+ */
+FILE *
+pascal
+far
+OpenFileOnPath(
+ char far *pszName,
+ int mode
+ )
+{
+ FILE *fh;
+ char szNameFull[260];
+ char szNameFull1[260];
+
+ fh = (FILE *)pathopen(pszName, szNameFull, "rb");
+
+ if (!fh) {
+
+ char *pszPath;
+ char *pT;
+
+ if (*pszName == '$') {
+ if (pT = hfstrchr(pszName,':')) { /* if properly terminated */
+ *pT = 0; /* terminate env variable */
+ pszPath = pszName+1; /* get path name */
+ pszName = pT+1; /* and point to filename part */
+ }
+ } else {
+ pszPath = "PATH";
+ }
+ sprintf(szNameFull, "$%s:%s", pszPath, pszName);
+ fh = (FILE *)pathopen(szNameFull, szNameFull1, "rb");
+
+ }
+
+ return fh;
+}
+
+
+
+/************************************************************************
+ *
+ * HelpCloseFile - Close a file
+ *
+ * Purpose:
+ *
+ * Entry:
+ * fh = file handle
+ *
+ * Exit:
+ * none
+ *
+ */
+void
+pascal
+far
+HelpCloseFile(
+ FILE* fh
+ )
+{
+ fclose(fh);
+}
+
+
+
+
+/************************************************************************
+ *
+ * ReadHelpFile - locate and read data from help file
+ *
+ * Purpose:
+ * reads cb bytes from the file fh, at file position fpos, placing them in
+ * pdest. Special case of pdest==0, returns file size of fh.
+ *
+ * Entry:
+ * fh = File handle
+ * fpos = position to seek to first
+ * pdest = location to place it
+ * cb = count of bytes to read
+ *
+ * Exit:
+ * returns length of data read
+ *
+ * Exceptions:
+ * returns 0 on errors.
+ *
+ */
+unsigned long
+pascal
+far
+ReadHelpFile (
+ FILE *fh,
+ unsigned long fpos,
+ char far *pdest,
+ unsigned short cb
+ )
+{
+ unsigned long cRet = 0;
+
+
+ if (pdest) {
+ //
+ // Read cb bytes
+ //
+ if (!fseek(fh, fpos, SEEK_SET)) {
+ cRet = fread(pdest, 1, cb, fh);
+ }
+
+ } else {
+ //
+ // Return size of file (yuck!)
+ //
+ fseek(fh, 0, SEEK_END);
+ fgetpos(fh, (fpos_t *) &cRet);
+ }
+
+ return cRet;
+}
+
+
+
+
+/************************************************************************
+**
+** HelpAlloc - Allocate a segment of memory for help
+**
+** Purpose:
+**
+** Entry:
+** size = size of memory segment desired
+**
+** Exit:
+** returns handle on success
+**
+** Exceptions:
+** returns NULL on failure
+*/
+mh pascal far HelpAlloc(ushort size)
+{
+ return (mh)malloc(size);
+/* end HelpAlloc */}
diff --git a/private/utils/mep/help/enginlib/helpif.c b/private/utils/mep/help/enginlib/helpif.c
new file mode 100644
index 000000000..9f04366dc
--- /dev/null
+++ b/private/utils/mep/help/enginlib/helpif.c
@@ -0,0 +1,308 @@
+/*** helpif.c - help routines for user interface assistance.
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Purpose:
+* These routines aid in the interpretation of help text by applications.
+* After decompression, the help text is encoded into a line oriented format
+* which includes text, highlighting and cross reference information.
+*
+* Each line of text is formatted in the database as:
+*
+* +--------+----------------+--------+---------------+------+---------------+
+* | cbText | - Ascii Text - | cbAttr | - Attr info - | 0xff | - Xref Info - |
+* +--------+----------------+--------+---------------+------+---------------+
+*
+* Where:
+*
+* cbText - a BYTE which contains the length of the ascii text plus
+* one (for itself).
+* Ascii Text - Just that, the ascii text to be displayed
+* cbAttr - a WORD which contains the length of the attribute
+* information *plus* the cross reference information.
+* Attr info - attribute/length pairs of highlighting information plus
+* two (for itself).
+* 0xff - Attr info terminator byte (present ONLY IF Xref
+* information follows)
+* Xref Info - Cross Referencing information.
+*
+* Notes:
+* If the LAST attributes on a line are "plain", then the attribute/length
+* pair is omitted, and the rest of the line is assumed plain.
+*
+* Given a pointer to a line, a pointer to the next line is:
+*
+* Pointer + cbText + cbAttr
+*
+* A line which has no cross-reference or highlighting will have a cbAttr of
+* 2, and nothing else.
+*
+* Revision History:
+*
+* 25-Jan-1990 ln locate -> hlp_locate
+* 19-Aug-1988 ln Move "locate" to assembly language hloc.asm
+* [] 26-Jan-1988 LN Created
+*
+*************************************************************************/
+#include <stdlib.h>
+#include <stdio.h>
+
+#if defined (OS2)
+#else
+#include <windows.h>
+#endif
+
+#include "help.h"
+#include "helpfile.h"
+#include "helpsys.h"
+
+/************************************************************************
+**
+** Foward Declarations
+*/
+uchar near pascal toupr(uchar);
+
+/*** HelpGetLineAttr - Return attributes associated with a line of ascii text
+*
+* Interprets the help files stored format and return a line at a time of
+* attribute information.
+*
+* Input:
+* ln = 1 based line number to return
+* cbMax = Max number of bytes to transfer
+* pbDst = pointer to destination
+* pbTopic = PB pointer to topic text
+*
+* Output:
+* Returns number of characters transfered (not including terminating 0xffff
+* attribute), or 0 if that line does not exist.
+*
+*************************************************************************/
+ushort far pascal LOADDS HelpGetLineAttr(
+ushort ln,
+int cbMax,
+lineattr far *pbDst,
+PB pbTopic
+) {
+lineattr far *pbDstBegin;
+uchar far *pTopic;
+/*
+** Form valid (locked) pointer to topic text & working pointer to detination
+*/
+pTopic = PBLOCK (pbTopic);
+pbDstBegin = pbDst;
+/*
+** Information is on present in compressed files. Locate the line in the text,
+** and then point at the attribute information therein.
+*/
+#if ASCII
+if (((topichdr far *)pTopic)->ftype & FTCOMPRESSED) {
+#endif
+ if (pTopic = hlp_locate(ln,pTopic)) {
+ pTopic += *pTopic;
+/*
+** Start by giving ln the count of encoded bytes. Then while there are
+** bytes, and we have enough room in the destination, AND we haven't reached
+** the end of the attribute information, then for each cb/attr pair, copy
+** them over, converting from our internal byte-per format to the external
+** word-per format.
+*/
+ ln = *((ushort far UNALIGNED *)pTopic)++ - (ushort)2;
+ while ( ln
+ && (cbMax >= sizeof(lineattr))
+ && (((intlineattr far *)pTopic)->attr != (uchar)0xff)
+ ) {
+ *(ushort UNALIGNED *)&(pbDst->cb) = ((intlineattr far UNALIGNED *)pTopic)->cb;
+ *(ushort UNALIGNED *)&(pbDst->attr) = ((intlineattr far UNALIGNED *)pTopic)->attr;
+ pbDst++;
+ ((intlineattr *)pTopic)++;
+ cbMax -= sizeof(lineattr);
+ ln -= sizeof(intlineattr);
+ }
+ }
+#if ASCII
+ }
+#endif
+PBUNLOCK (pbTopic);
+/*
+** Finally, if there is room in the destination buffer, terminate the
+** attributes with "default attributes to the end of line", and then
+** attribute ffff, signalling the end of the buffer.
+*/
+if (cbMax >= sizeof(lineattr)) {
+ pbDst->cb = 0xffff;
+ pbDst->attr = 0;
+ cbMax -= sizeof(lineattr);
+ pbDst++;
+ }
+if (cbMax >= sizeof(pbDst->attr))
+ pbDst->attr = 0xffff;
+/*
+** return the number of bytes transferred, not including the terminating
+** word.
+*/
+return (ushort)((uchar far *)pbDst - (uchar far *)pbDstBegin);
+
+/* end HelpGetLineAttr */}
+
+/************************************************************************
+**
+** HelpHlNext - Locate next cross reference
+**
+** Purpose:
+** Locates the next cross reference in the help topic. Locates either the
+** next physical cross reference, or the next referece beginning with a
+** particular character (case insensitive!). Locates either forward or
+** backward.
+**
+** Entry:
+** cLead = leading character, or flag, indicating direction and type
+** of search. May be:
+** NULL: Get next sequential cross reference
+** -1: Get previous sequential cross reference
+** char: Get next cross reference beginning with 'char'
+** -char: Get previous cross reference beginning with
+** 'char'
+** pbTopic = pointer to topic text.
+** photspot = pointer to hotspot structure to recive info. (line and col
+** indicate starting point)
+**
+** Exit:
+** returns TRUE if cross reference found, hotspot structure updated.
+**
+** Exceptions:
+** returns 0 if no such cross reference.
+*/
+f pascal far LOADDS HelpHlNext(cLead,pbTopic, photspot)
+int cLead;
+PB pbTopic;
+hotspot far *photspot;
+{
+ushort cbAttr;
+ushort col;
+ushort ln;
+uchar far *pbEnd; /* pointer to next line */
+uchar far *pbLineCur; /* pointer to current line */
+uchar far *pbFound = 0; /* found entry, perhaps */
+uchar far *pText;
+uchar far *pTopic;
+
+pTopic = PBLOCK (pbTopic);
+col = photspot->col; /* save these */
+ln = photspot->line;
+if (((topichdr far *)pTopic)->ftype & FTCOMPRESSED) {
+ while (1) {
+ if (ln == 0) break; /* if not found, ret */
+ pbLineCur = hlp_locate(ln,pTopic); /* find line */
+ if (pbLineCur == 0) break; /* if not found, ret */
+ pText = pbLineCur; /* point at topic text */
+ pbLineCur += *pbLineCur; /* skip the topic text */
+ cbAttr = *((ushort far UNALIGNED *)pbLineCur)++ - (ushort)sizeof(ushort);
+ pbEnd = pbLineCur + cbAttr; /* next line */
+ while (cbAttr && (((intlineattr far UNALIGNED *)pbLineCur)->attr != 0xff)) {
+ pbLineCur += sizeof(intlineattr);
+ cbAttr -=sizeof(intlineattr);
+ }
+ if (cbAttr)
+ pbLineCur += sizeof(uchar); /* skip (0xff) attr */
+
+ while (pbLineCur < pbEnd) { /* scan rest for data */
+/*
+** in a forward scan, the first cross reference (with appropriate char) that is
+** greater than our current position, is the correct one.
+*/
+ if (cLead >= 0) { /* forward scan */
+ if (col <= *(pbLineCur+1)) /* if found */
+ if ((cLead == 0) /* and criteria met */
+ || (toupr(*(pText + *pbLineCur)) == (uchar)cLead)) {
+ pbFound = pbLineCur;
+ break;
+ }
+ }
+/*
+** in a backward scan, we accept the LAST item we find which is less than
+** the current position.
+*/
+ else {
+ if (col > *(pbLineCur)) /* if a candidate found */
+ if ((cLead == -1) /* and criteria met */
+ || (toupr(*(pText + *pbLineCur)) == (uchar)-cLead))
+ pbFound = pbLineCur;/* remember it */
+ }
+ pbLineCur += 2; /* skip column spec */
+ if (*pbLineCur)
+ while (*pbLineCur++); /* skip string */
+ else
+ pbLineCur += 3;
+ }
+
+ if (pbFound) { /* if we found one */
+ *(ushort UNALIGNED *)&(photspot->line) = ln;
+ *(ushort UNALIGNED *)&(photspot->col) = (ushort)*pbFound++;
+ *(ushort UNALIGNED *)&(photspot->ecol) = (ushort)*pbFound++;
+ *(uchar *UNALIGNED *)&(photspot->pXref) = pbFound;
+ PBUNLOCK (pbTopic);
+ return TRUE;
+ }
+/*
+** move on to next line.
+*/
+ if (cLead >= 0) {
+ ln++;
+ col = 0;
+ }
+ else {
+ ln--;
+ col = 127;
+ }
+ }
+ }
+
+PBUNLOCK (pbTopic);
+return FALSE;
+/* end HelpHlNext */}
+
+/************************************************************************
+**
+** HelpXRef - Return pointer to Xref String
+**
+** Purpose:
+** Given a row, column (in a hotspot structure) and topic, return a pointer
+** to a cross reference string.
+**
+** Entry:
+** pbTopic = Pointer to topic text
+** photspot = Pointer to hotspot structure to update
+**
+** Exit:
+** returns far pointer into topic text of cross reference string & updates
+** hotspot structure.
+**
+** Exceptions:
+** returns NULL if no cross reference for that line.
+**
+*/
+char far * pascal far LOADDS HelpXRef(pbTopic, photspot)
+PB pbTopic;
+hotspot far *photspot;
+{
+uchar far *pTopic;
+ushort col; /* column requested */
+ushort ln; /* line requested */
+
+pTopic = PBLOCK (pbTopic);
+col = photspot->col; /* save these */
+ln = photspot->line;
+if (((topichdr far *)pTopic)->ftype & FTCOMPRESSED)
+ if (HelpHlNext(0,pbTopic,photspot)) /* if xref found */
+ if ( (photspot->line == ln) /* & our req. in range */
+ && ( (col >= photspot->col)
+ && (col <= photspot->ecol))) {
+ PBUNLOCK (pbTopic);
+ return photspot->pXref; /* return ptr */
+ }
+
+PBUNLOCK (pbTopic);
+return 0;
+
+/* end HelpXRef */}
diff --git a/private/utils/mep/help/enginlib/hinfo.c b/private/utils/mep/help/enginlib/hinfo.c
new file mode 100644
index 000000000..c34fa9376
--- /dev/null
+++ b/private/utils/mep/help/enginlib/hinfo.c
@@ -0,0 +1,57 @@
+/*** hinfo.c - helpgetinfo support
+*
+* Copyright <C> 1989, Microsoft Corporation
+*
+* Purpose:
+*
+* Revision History:
+*
+* [] 09-Mar-1989 LN Created
+*
+*************************************************************************/
+
+#include <stdio.h>
+
+#if defined (OS2)
+#else
+#include <windows.h>
+#endif
+
+#include "help.h" /* global (help & user) decl */
+#include "helpfile.h" /* help file format definition */
+#include "helpsys.h" /* internal (help sys only) decl*/
+
+/*
+** external definitions
+*/
+f pascal near LoadFdb (mh, fdb far *);
+
+/*** HelpGetInfo - Return public info to caller
+*
+* Returns a data structure to the caller which allows him into some of
+* our internal data.
+*
+* Input:
+* ncInfo = nc requesting info on
+* fpDest = pointer to location to place into
+* cbDest = size of destination
+*
+* Output:
+* Returns NULL on success, count of bytes required if cbDest too small,
+* or -1 on any other error
+*
+*************************************************************************/
+int far pascal LOADDS HelpGetInfo (
+nc ncInfo,
+helpinfo far *fpDest,
+int cbDest
+) {
+if (cbDest < sizeof (helpinfo))
+ return sizeof (helpinfo);
+if (LoadFdb (ncInfo.mh, &(fpDest->fileinfo))) {
+ fpDest->filename[0] = 0;
+ return 0;
+ }
+return -1;
+
+/* end HelpGetInfo */}
diff --git a/private/utils/mep/help/enginlib/hline.c b/private/utils/mep/help/enginlib/hline.c
new file mode 100644
index 000000000..a9376f361
--- /dev/null
+++ b/private/utils/mep/help/enginlib/hline.c
@@ -0,0 +1,139 @@
+/**************************************************************************
+ *HelpGetLine - Return a line of ascii text
+ *
+ * Copyright <C> 1988, Microsoft Corporation
+ *
+ * Revision History:
+ *
+ * 25-Jan-1990 ln LOCATE -> HLP_LOCATE
+ * 22-Feb-1989 ln Check correctly for end of topic while copying
+ * line.
+ * 22-Dec-1988 LN Removed MASM High Level Lang support (Need
+ * to control segments better than that will
+ * let me)
+ * 08-Dec-1988 LN CSEG
+ * 11-Nov-1988 ln Adjust cbMax on entry
+ * 03-Nov-1988 ln Added GQ sensitivity
+ * [] 22-Sep-1988 LN Created
+ *
+ * Notes:
+ *
+ * Sensitive to the following switches:
+ *
+ * HOFFSET - If defined, handle/offset version
+ * OS2 - If defined, OS/2 protect mode version
+ * DSLOAD - If defined, causes DS to be reloaded, if needed
+ * ASCII - If TRUE, includes ASCII support code
+ * GQ - If defined, INC BP before saving & DEC before restore
+ *
+ **************************************************************************/
+
+#include <stdio.h>
+#if defined (OS2)
+#define INCL_BASE
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include <help.h>
+#include <helpfile.h>
+#include <helpsys.h>
+
+
+
+/**** HelpGetLine - Return a line of ascii text
+ *
+ * Interpret the help files stored format and return a line at a time of
+ * ascii text.
+ *
+ * ushort far pascal LOADDS HelpGetLine (
+ * ushort ln, = 1 based line number to return
+ * ushort cbMax, = Max number of bytes to transfer
+ * uchar far *pszDst, = pointer to destination
+ * PB pbTopic = PB pointer to topic text
+ *
+ * Output:
+ * Returns number of characters transfered, or 0 if that line does not exist.
+ *
+ *************************************************************************/
+USHORT pascal
+HelpGetLine (
+ USHORT ln,
+ USHORT cbMax,
+ PUCHAR pszDst,
+ PB pbTopic
+ ) {
+
+ struct topichdr *pT;
+ USHORT cbTransfered = 0;
+ PUCHAR pszDstOrg = pszDst;
+
+ cbMax--; //adjust to account for terminating zero
+
+ pT = PBLOCK(pbTopic);
+
+ if (pT) {
+
+ PCHAR pLine = hlp_locate(ln, (PCHAR)pT);
+
+ if (pLine) {
+
+ *pszDst = ' ';
+ *(pszDst +1) = '\00'; // initialize dest.
+
+
+ if (pT->ftype & FTCOMPRESSED) {
+
+ // For compressed files, get the length of the line from the
+ // first byte, and of course skip that byte. Form the
+ // maximum byte count ot be transfered as the lesser of the
+ // actual length of the line or caller cbMax.
+
+ USHORT Len = (USHORT)*pLine++ - 1;
+
+ if (Len) {
+ ULONG LongLen;
+ Len = (Len > cbMax) ? cbMax : Len;
+
+ LongLen = Len/sizeof(ULONG);
+ Len = (USHORT)(Len % sizeof(ULONG));
+
+
+ while (LongLen--) {
+ *((ULONG *UNALIGNED)pszDst)++ = *((ULONG UNALIGNED *)pLine)++;
+ }
+ while (Len--) {
+ *pszDst++ = *pLine++;
+ }
+ *pszDst++ = '\00'; // Null terminate it
+ cbTransfered = (USHORT)(pszDst - pszDstOrg);
+ } else {
+ cbTransfered = 2;
+ }
+
+ } else {
+
+ // For non-compressed files, copy one line
+
+ PCHAR pSrc = pLine;
+ CHAR c = *pLine;
+
+ if (c == '\n') {
+ cbTransfered = 2;
+ } else {
+ while (c != '\00' && c != '\n') {
+ c = *pszDst++ = *pLine++;
+ }
+ *(pszDst-1) = '\00'; // null terminate it
+
+ cbTransfered = (USHORT)(pszDst - pszDstOrg);
+ }
+ }
+ }
+
+ PBUNLOCK(pbTopic);
+ }
+
+ return cbTransfered;
+}
diff --git a/private/utils/mep/help/enginlib/hloc.c b/private/utils/mep/help/enginlib/hloc.c
new file mode 100644
index 000000000..273303a67
--- /dev/null
+++ b/private/utils/mep/help/enginlib/hloc.c
@@ -0,0 +1,146 @@
+/**************************************************************************
+ *hlp_locate - locate line in help text
+ *
+ * Copyright <C> 1988, Microsoft Corporation
+ *
+ * Purpose:
+ *
+ * Revision History:
+ *
+ * 17-OCt-1990 RJSA translated to C
+ * 25-Jan-1990 LN renamed to hlp_locate
+ * 22-Dec-1988 LN Removed MASM High Level Lang support (Need
+ * to control segments better than that will
+ * let me)
+ * 08-Dec-1988 LN CSEG
+ * [] 18-Aug-1988 LN Created
+ *
+ *
+ **************************************************************************/
+
+#include <stdio.h>
+#if defined (OS2)
+#define INCL_BASE
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include <help.h>
+#include <helpfile.h>
+#include <helpsys.h>
+
+
+
+/**** hlp_locate - locate a line in the buffer
+ * uchar far * near pascal hlp_locate(
+ * ushort ln,
+ * uchar far *pTopic
+ * )
+ *
+ * Purpose:
+ * commonly used routine to find a line in the topic text.
+ *
+ * Entry:
+ * ln = 1 based line number to look for (-1 means return number
+ * of lines in topic)
+ * pTopic = Topic text to look for it in
+ *
+ * Exit:
+ * returns pointer to start of line
+ *
+ * Exceptions:
+ * returns NULL on not found
+ *
+ **************************************************************************/
+
+PCHAR pascal
+hlp_locate (
+ SHORT ln,
+ PCHAR pTopic
+ ){
+
+ struct topichdr UNALIGNED *pT = (struct topichdr *)pTopic;
+ PBYTE pSrc = (PBYTE)pTopic;
+ SHORT lnOrig = ln;
+
+ if (pT->lnCur <= (USHORT)ln) {
+
+ // Use last past position calculated
+
+ ln -= (pT->lnCur );
+ pSrc += pT->lnOff;
+
+ } else {
+
+ // Start from beginning
+
+ pSrc += sizeof(struct topichdr);
+ }
+
+ if (pT->ftype & FTCOMPRESSED) {
+
+ // Compressed file. Walk over each text\attribute pair
+ // until the desired line is found.
+
+ while ( *pSrc && ln) {
+
+ pSrc += *pSrc;
+ pSrc += *(USHORT UNALIGNED *)pSrc;
+
+ if ( *pSrc && *(pSrc+1) != pT->linChar ) {
+ ln--;
+ }
+ }
+
+ //while (*pSrc && ln) {
+ //
+ // if (*(pSrc + 1) != pT->linChar) {
+ // ln--;
+ // }
+ // pSrc += *pSrc;
+ // pSrc += *(PUSHORT)pSrc;
+ //}
+
+ } else {
+
+ // ASCII file
+
+ while (*pSrc && ln) {
+ if (*pSrc != pT->linChar) {
+ ln--;
+ }
+
+ while (*pSrc && *pSrc != 0x0A) {
+ pSrc++;
+ }
+ if (*pSrc)
+ pSrc++;
+ }
+ }
+
+ if (*pSrc) {
+
+ // Line found. Update the topic hdr with the pointers to the text
+ // and line number that we just found, to help speed us up next time.
+
+ pT->lnOff = (USHORT)((PBYTE)pSrc - (PBYTE)pT);
+ pT->lnCur = lnOrig;
+
+ } else {
+
+ //
+ // Line not found. Update nothing and return NULL
+ // (Side Effect: line requested (ln) - line count left (ln) is the
+ // number of lines in the topic! If original ln is -1, we'll return
+ // that instead!
+
+ if (lnOrig == -1)
+ pSrc = (PBYTE)(lnOrig - ln);
+ else
+ pSrc = (PBYTE)0L;
+ }
+
+ return pSrc;
+
+}
diff --git a/private/utils/mep/help/enginlib/makefile b/private/utils/mep/help/enginlib/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/mep/help/enginlib/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/mep/help/enginlib/mshelp.def b/private/utils/mep/help/enginlib/mshelp.def
new file mode 100644
index 000000000..8686b0eaa
--- /dev/null
+++ b/private/utils/mep/help/enginlib/mshelp.def
@@ -0,0 +1,29 @@
+LIBRARY MSHELP
+
+DESCRIPTION 'Help engine'
+
+EXPORTS
+ HelpcLines
+ HelpClose
+ HelpCtl
+ HelpDecomp
+ HelpGetCells
+ HelpGetInfo
+ HelpGetLine
+ HelpGetLineAttr
+ HelpHlNext
+ HelpLook
+ HelpNc
+ HelpNcBack
+ HelpNcCb
+ HelpNcCmp
+ HelpNcNext
+ HelpNcPrev
+ HelpNcRecord
+ HelpNcUniq
+ HelpOpen
+ HelpShrink
+ HelpSzContext
+ HelpXRef
+ LoadFdb
+ LoadPortion
diff --git a/private/utils/mep/help/enginlib/mshelp.rc b/private/utils/mep/help/enginlib/mshelp.rc
new file mode 100644
index 000000000..039e42627
--- /dev/null
+++ b/private/utils/mep/help/enginlib/mshelp.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "MS Help Utility DLL"
+#define VER_INTERNALNAME_STR "mshelp"
+#define VER_ORIGINALNAME_STR "MSHELP.DLL"
+
+#include "common.ver"
diff --git a/private/utils/mep/help/enginlib/mshelp1.def b/private/utils/mep/help/enginlib/mshelp1.def
new file mode 100644
index 000000000..d06263f3a
--- /dev/null
+++ b/private/utils/mep/help/enginlib/mshelp1.def
@@ -0,0 +1,29 @@
+LIBRARY MSHELP1
+
+DESCRIPTION 'Help engine'
+
+EXPORTS
+ _HelpcLines
+ _HelpClose
+ _HelpCtl
+ _HelpDecomp
+ _HelpGetCells
+ _HelpGetInfo
+ _HelpGetLine
+ _HelpGetLineAttr
+ _HelpHlNext
+ _HelpLook
+ _HelpNc
+ _HelpNcBack
+ _HelpNcCb
+ _HelpNcCmp
+ _HelpNcNext
+ _HelpNcPrev
+ _HelpNcRecord
+ _HelpNcUniq
+ _HelpOpen
+ _HelpShrink
+ _HelpSzContext
+ _HelpXRef
+ _LoadFdb
+ _LoadPortion
diff --git a/private/utils/mep/help/enginlib/sources b/private/utils/mep/help/enginlib/sources
new file mode 100644
index 000000000..177480707
--- /dev/null
+++ b/private/utils/mep/help/enginlib/sources
@@ -0,0 +1,35 @@
+MAJORCOMP=sdktools
+MINORCOMP=engine
+
+TARGETNAME=mshelp
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+
+TARGETLIBS=\nt\public\sdk\lib\*\kernel32.lib \
+ \nt\private\sdktools\ztools\src\obj\*\ztools.lib \
+ \nt\public\sdk\lib\*\user32.lib
+
+INCLUDES=.;..\inc;
+
+SOURCES= hback.c \
+ hctl.c \
+ hdata.c \
+ helpcell.c \
+ helpcnt.c \
+ helpdec.c \
+ helpdll.c \
+ helpif.c \
+ hinfo.c \
+ hline.c \
+ hloc.c \
+ help.c \
+ mshelp.rc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+C_DEFINES=-D_OS2_20_=0 -DNO_EXT_KEYS -Dpascal= -Dfar= -DNOLANMAN -DNT -DDEBUG
+!ELSE
+C_DEFINES=-D_OS2_20_=0 -DNO_EXT_KEYS -Dpascal= -Dfar= -DNOLANMAN -DNT
+!ENDIF
+UMTYPE=console
+UMRES=obj\*\mshelp.res
+USE_CRTDLL=1
diff --git a/private/utils/mep/help/htest/cons.c b/private/utils/mep/help/htest/cons.c
new file mode 100644
index 000000000..894a78325
--- /dev/null
+++ b/private/utils/mep/help/htest/cons.c
@@ -0,0 +1,2200 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ console.c
+
+Abstract:
+
+ Interface to the console for Win32 applications.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 30-Nov-1990
+
+
+Revision History:
+
+
+--*/
+
+#include <string.h>
+#include <malloc.h>
+#include <assert.h>
+#include <windows.h>
+
+#define FREE(x) free(x)
+#define MALLOC(x) malloc(x)
+#define REALLOC(x,y) realloc(x,y)
+
+#include "cons.h"
+
+
+
+//
+// EVENT BUFFER
+//
+// The event buffer is used to store event records from the input
+// queue.
+//
+#define INITIAL_EVENTS 32
+#define MAX_EVENTS 64
+#define EVENT_INCREMENT 4
+
+#define ADVANCE TRUE
+#define NOADVANCE FALSE
+#define WAIT TRUE
+#define NOWAIT FALSE
+
+//
+// For accessing fields of an event record
+//
+#define EVENT_TYPE(p) ((p)->EventType)
+#define EVENT_DATA(p) ((p)->Event)
+
+//
+// For casting event records
+//
+#define PMOUSE_EVT(p) (&(EVENT_DATA(p).MouseEvent))
+#define PWINDOW_EVT(p) (&(EVENT_DATA(p).WindowBufferSizeEvent))
+#define PKEY_EVT(p) (&(EVENT_DATA(p).KeyEvent))
+
+//
+// The event buffer structure
+//
+typedef struct EVENT_BUFFER {
+ DWORD MaxEvents; // Max number of events in buffer
+ DWORD NumberOfEvents; // Number of events in buffer
+ DWORD EventIndex; // Event Index
+ BOOL BusyFlag; // Busy flag
+ CRITICAL_SECTION CriticalSection; // To maintain integrity
+ CRITICAL_SECTION PeekCriticalSection; // While peeking
+ PINPUT_RECORD EventBuffer; // Event Buffer
+} EVENT_BUFFER, *PEVENT_BUFFER;
+
+
+
+
+
+//
+// Screen attributes
+//
+#define BLACK_FGD 0
+#define BLUE_FGD FOREGROUND_BLUE
+#define GREEN_FGD FOREGROUND_GREEN
+#define CYAN_FGD (FOREGROUND_BLUE | FOREGROUND_GREEN)
+#define RED_FGD FOREGROUND_RED
+#define MAGENTA_FGD (FOREGROUND_BLUE | FOREGROUND_RED)
+#define YELLOW_FGD (FOREGROUND_GREEN | FOREGROUND_RED)
+#define WHITE_FGD (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)
+
+#define BLACK_BGD 0
+#define BLUE_BGD BACKGROUND_BLUE
+#define GREEN_BGD BACKGROUND_GREEN
+#define CYAN_BGD (BACKGROUND_BLUE | BACKGROUND_GREEN)
+#define RED_BGD BACKGROUND_RED
+#define MAGENTA_BGD (BACKGROUND_BLUE | BACKGROUND_RED)
+#define YELLOW_BGD (BACKGROUND_GREEN | BACKGROUND_RED)
+#define WHITE_BGD (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED)
+
+
+
+//
+// The AttrBg and AttrFg arrays are used for mapping DOS attributes
+// to the new attributes.
+//
+WORD AttrBg[ ] = {
+ BLACK_BGD, // black
+ BLUE_BGD, // blue
+ GREEN_BGD, // green
+ CYAN_BGD, // cyan
+ RED_BGD, // red
+ MAGENTA_BGD, // magenta
+ YELLOW_BGD, // brown
+ WHITE_BGD, // light gray
+ BACKGROUND_INTENSITY | BLACK_BGD, // dark gray
+ BACKGROUND_INTENSITY | BLUE_BGD, // light blue
+ BACKGROUND_INTENSITY | GREEN_BGD, // light green
+ BACKGROUND_INTENSITY | CYAN_BGD, // light cyan
+ BACKGROUND_INTENSITY | RED_BGD, // light red
+ BACKGROUND_INTENSITY | MAGENTA_BGD, // light magenta
+ BACKGROUND_INTENSITY | YELLOW_BGD, // light yellow
+ BACKGROUND_INTENSITY | WHITE_BGD // white
+};
+
+WORD AttrFg[ ] = {
+ BLACK_FGD, // black
+ BLUE_FGD, // blue
+ GREEN_FGD, // green
+ CYAN_FGD, // cyan
+ RED_FGD, // red
+ MAGENTA_FGD, // magenta
+ YELLOW_FGD, // brown
+ WHITE_FGD, // light gray
+ FOREGROUND_INTENSITY | BLACK_FGD, // dark gray
+ FOREGROUND_INTENSITY | BLUE_FGD, // light blue
+ FOREGROUND_INTENSITY | GREEN_FGD, // light green
+ FOREGROUND_INTENSITY | CYAN_FGD, // light cyan
+ FOREGROUND_INTENSITY | RED_FGD, // light red
+ FOREGROUND_INTENSITY | MAGENTA_FGD, // light magenta
+ FOREGROUND_INTENSITY | YELLOW_FGD, // light yellow
+ FOREGROUND_INTENSITY | WHITE_FGD // white
+};
+
+//
+// GET_ATTRIBUTE performs the mapping from old attributes to new attributes
+//
+#define GET_ATTRIBUTE(x) (AttrFg[x & 0x000F ] | AttrBg[( x & 0x00F0 ) >> 4])
+
+
+//
+// The LINE_INFO structure contains information about each line in the
+// screen buffer.
+//
+typedef struct _LINE_INFO {
+
+ BOOL Dirty; // True if has not been displayed
+ int colMinChanged; // if dirty, smallest col changed
+ int colMaxChanged; // if dirty, biggest col changed
+ PCHAR_INFO Line; // Pointer to the line.
+
+} LINE_INFO, *PLINE_INFO;
+
+#define ResetLineInfo(pli) \
+ { pli->Dirty = 0; \
+ pli->colMinChanged = 1000; \
+ pli->colMaxChanged = -1; \
+ }
+
+//
+// The SCREEN_DATA structure contains the information about individual
+// screens.
+//
+typedef struct SCREEN_DATA {
+ HANDLE ScreenHandle; // Handle to screen
+ PLINE_INFO LineInfo; // Array of line info.
+ PCHAR_INFO ScreenBuffer; // Screen buffer
+ ULONG MaxBufferSize; // Max. buffer size
+ ATTRIBUTE AttributeOld; // Attribute - original
+ WORD AttributeNew; // Attribute - converted
+ ROW FirstRow; // First row to update
+ ROW LastRow; // Last row to update
+ CRITICAL_SECTION CriticalSection; // To maintain integrity
+ DWORD CursorSize; // Cursor Size
+ SCREEN_INFORMATION ScreenInformation; // Screen information
+} SCREEN_DATA, *PSCREEN_DATA;
+
+
+//
+// Static global data
+//
+static EVENT_BUFFER EventBuffer; // Event buffer
+static HANDLE hInput; // handle to stdin
+static HANDLE hOutput; // handle to stdout
+static HANDLE hError; // handle to stderr
+static PSCREEN_DATA OutputScreenData; // Screen data for hOutput
+static PSCREEN_DATA ActiveScreenData; // Points to current screen data
+static BOOL Initialized = FALSE; // Initialized flag
+
+
+#if defined (DEBUG)
+ static char DbgBuffer[128];
+#endif
+
+
+//
+// Local Prototypes
+//
+BOOL
+InitializeGlobalState (
+ void
+ );
+
+
+PSCREEN_DATA
+MakeScreenData (
+ HANDLE ScreenHandle
+ );
+
+BOOL
+InitLineInfo (
+ PSCREEN_DATA ScreenData
+ );
+
+PINPUT_RECORD
+NextEvent (
+ BOOL fAdvance,
+ BOOL fWait
+ );
+
+void
+MouseEvent (
+ PMOUSE_EVENT_RECORD pEvent
+ );
+
+BOOL
+WindowEvent (
+ PWINDOW_BUFFER_SIZE_RECORD pEvent
+ );
+
+BOOL
+KeyEvent (
+ PKEY_EVENT_RECORD pEvent,
+ PKBDKEY pKey
+ );
+
+
+BOOL
+PutEvent (
+ PINPUT_RECORD InputRecord
+ );
+
+
+BOOL
+InitializeGlobalState (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Initializes our global state data.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if success
+ FALSE otherwise.
+
+--*/
+{
+
+
+ //
+ // Initialize the event buffer
+ //
+ InitializeCriticalSection( &(EventBuffer.CriticalSection) );
+ InitializeCriticalSection( &(EventBuffer.PeekCriticalSection) );
+ EventBuffer.NumberOfEvents = 0;
+ EventBuffer.EventIndex = 0;
+ EventBuffer.BusyFlag = FALSE;
+ EventBuffer.EventBuffer = MALLOC( INITIAL_EVENTS * sizeof(INPUT_RECORD) );
+
+ if ( !EventBuffer.EventBuffer ) {
+ return FALSE;
+ }
+
+ EventBuffer.MaxEvents = INITIAL_EVENTS;
+
+
+ //
+ // Get handles to stdin, stdout and stderr
+ //
+ hInput = GetStdHandle( STD_INPUT_HANDLE );
+ hOutput = GetStdHandle( STD_OUTPUT_HANDLE );
+ hError = GetStdHandle( STD_ERROR_HANDLE );
+
+
+ //
+ // Initialize the screen data for hOutput
+ //
+ if ( !(OutputScreenData = MakeScreenData( hOutput )) ) {
+ return FALSE;
+ }
+
+
+ //
+ // Current screen is hOutput
+ //
+ ActiveScreenData = OutputScreenData;
+
+
+ return (Initialized = TRUE);
+
+}
+
+
+
+
+
+PSCREEN_DATA
+MakeScreenData (
+ HANDLE ScreenHandle
+ )
+/*++
+
+Routine Description:
+
+ Allocates memory for a SCREEN_DATA information and initializes it.
+
+Arguments:
+
+ ScreenHandle - Supplies handle of screen.
+
+Return Value:
+
+ POINTER to allocated SCREEN_DATA structure
+
+--*/
+{
+ PSCREEN_DATA ScreenData; // Pointer to screen data
+ CONSOLE_SCREEN_BUFFER_INFO ScrInfo; // Screen buffer info.
+
+
+ //
+ // Allocate space for the screen data.
+ //
+ if ( !(ScreenData = (PSCREEN_DATA)MALLOC(sizeof(SCREEN_DATA))) ) {
+ return NULL;
+ }
+
+ //
+ // Allocate space for our copy of the screen buffer.
+ //
+ GetConsoleScreenBufferInfo( ScreenHandle,
+ &ScrInfo );
+
+ ScreenData->MaxBufferSize = ScrInfo.dwSize.Y *
+ ScrInfo.dwSize.X;
+
+ ScreenData->ScreenBuffer = (PCHAR_INFO)MALLOC( ScreenData->MaxBufferSize *
+ sizeof(CHAR_INFO));
+
+ if ( !ScreenData->ScreenBuffer ) {
+ FREE( ScreenData );
+ return NULL;
+ }
+
+ //
+ // Allocate space for the LineInfo array
+ //
+ ScreenData->LineInfo = (PLINE_INFO)MALLOC( ScrInfo.dwSize.Y * sizeof( LINE_INFO ) );
+ if ( !ScreenData->LineInfo ) {
+ FREE( ScreenData->ScreenBuffer );
+ FREE( ScreenData );
+ return NULL;
+ }
+
+
+ //
+ // Memory has been allocated, now initialize the structure
+ //
+ ScreenData->ScreenHandle = ScreenHandle;
+
+ ScreenData->ScreenInformation.NumberOfRows = ScrInfo.dwSize.Y;
+ ScreenData->ScreenInformation.NumberOfCols = ScrInfo.dwSize.X;
+
+ ScreenData->ScreenInformation.CursorRow = ScrInfo.dwCursorPosition.Y;
+ ScreenData->ScreenInformation.CursorCol = ScrInfo.dwCursorPosition.X;
+
+ ScreenData->AttributeNew = ScrInfo.wAttributes;
+ ScreenData->AttributeOld = 0x00;
+
+ ScreenData->FirstRow = ScreenData->ScreenInformation.NumberOfRows;
+ ScreenData->LastRow = 0;
+
+ InitializeCriticalSection( &(ScreenData->CriticalSection) );
+
+ InitLineInfo( ScreenData );
+
+ return ScreenData;
+}
+
+
+
+
+
+BOOL
+InitLineInfo (
+ PSCREEN_DATA ScreenData
+ )
+/*++
+
+Routine Description:
+
+ Initializes the LineInfo array.
+
+Arguments:
+
+ ScreenData - Supplies pointer to screen data.
+
+Return Value:
+
+ TRUE if initialized, false otherwise.
+
+--*/
+{
+
+ ROW Row;
+ COLUMN Cols;
+ PLINE_INFO LineInfo;
+ PCHAR_INFO CharInfo;
+
+
+ LineInfo = ScreenData->LineInfo;
+ CharInfo = ScreenData->ScreenBuffer;
+ Row = ScreenData->ScreenInformation.NumberOfRows;
+ Cols = ScreenData->ScreenInformation.NumberOfCols;
+
+ while ( Row-- ) {
+
+ //
+ // BUGBUG Temporary
+ //
+ // assert( LineInfo < (ScreenData->LineInfo + ScreenData->ScreenInformation.NumberOfRows));
+ // assert( (CharInfo + Cols) <= (ScreenData->ScreenBuffer + ScreenData->MaxBufferSize) );
+
+ ResetLineInfo (LineInfo);
+
+ LineInfo->Line = CharInfo;
+
+ LineInfo++;
+ CharInfo += Cols;
+
+ }
+
+ return TRUE;
+}
+
+
+
+
+
+PSCREEN
+consoleNewScreen (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Creates a new screen.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Pointer to screen data.
+
+--*/
+{
+ PSCREEN_DATA ScreenData; // Screen data
+ HANDLE NewScreenHandle;
+ SMALL_RECT NewSize;
+ CONSOLE_SCREEN_BUFFER_INFO ScrInfo; // Screen buffer info.
+ CONSOLE_CURSOR_INFO CursorInfo;
+
+ if ( !Initialized ) {
+
+ //
+ // We have to initialize our global state.
+ //
+ if ( !InitializeGlobalState() ) {
+ return NULL;
+ }
+ }
+
+ //
+ // Create a new screen buffer
+ //
+ NewScreenHandle = CreateConsoleScreenBuffer(GENERIC_WRITE | GENERIC_READ,
+ 0,
+ NULL,
+ CONSOLE_TEXTMODE_BUFFER,
+ NULL );
+
+ if (NewScreenHandle == INVALID_HANDLE_VALUE) {
+ //
+ // No luck
+ //
+ return NULL;
+ }
+
+ //
+ // We want the new window to be the same size as the current one, so
+ // we resize it.
+ //
+ GetConsoleScreenBufferInfo( ActiveScreenData->ScreenHandle,
+ &ScrInfo );
+
+ NewSize.Left = 0;
+ NewSize.Top = 0;
+ NewSize.Right = ScrInfo.srWindow.Right - ScrInfo.srWindow.Left;
+ NewSize.Bottom = ScrInfo.srWindow.Bottom - ScrInfo.srWindow.Top;
+
+ SetConsoleWindowInfo( NewScreenHandle, TRUE, &NewSize );
+
+ //
+ // Now we create a screen data structure for it.
+ //
+ if ( !(ScreenData = MakeScreenData(NewScreenHandle)) ) {
+ CloseHandle(NewScreenHandle);
+ return NULL;
+ }
+
+
+ CursorInfo.bVisible = TRUE;
+ ScreenData->CursorSize = CursorInfo.dwSize = 25;
+
+ SetConsoleCursorInfo ( ScreenData->ScreenHandle,
+ &CursorInfo );
+
+ //
+ // We are all set. We return a pointer to the
+ // screen data.
+ //
+ return (PSCREEN)ScreenData;
+}
+
+
+
+
+
+BOOL
+consoleCloseScreen (
+ PSCREEN pScreen
+ )
+/*++
+
+Routine Description:
+
+ Closes a screen.
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data.
+
+Return Value:
+
+ TRUE if screen closed.
+ FALSE otherwise
+
+--*/
+{
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+
+ //
+ // We cannot close the active screen
+ //
+ if ( !ScreenData || (ScreenData == ActiveScreenData) ) {
+ return FALSE;
+ }
+
+ if (ScreenData->ScreenHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(ScreenData->ScreenHandle);
+ }
+
+ FREE( ScreenData->LineInfo );
+ FREE( ScreenData->ScreenBuffer );
+ FREE( ScreenData );
+
+ return TRUE;
+}
+
+
+
+
+
+PSCREEN
+consoleGetCurrentScreen (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Returns the current screen.
+
+Arguments:
+
+ none.
+
+Return Value:
+
+ Pointer to currently active screen data.
+
+--*/
+{
+ if ( !Initialized ) {
+
+ //
+ // We have to initialize our global state.
+ //
+ if (!InitializeGlobalState()) {
+ return NULL;
+ }
+ }
+
+ return (PSCREEN)ActiveScreenData;
+}
+
+
+
+
+
+BOOL
+consoleSetCurrentScreen (
+ PSCREEN pScreen
+ )
+/*++
+
+Routine Description:
+
+ Sets the active screen.
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data.
+
+Return Value:
+
+ TRUE if the active screen set
+ FALSE otherwise.
+
+--*/
+{
+ BOOL ScreenSet = TRUE;
+ PSCREEN_DATA CurrentScreen = ActiveScreenData;
+
+
+ EnterCriticalSection( &(CurrentScreen->CriticalSection) );
+
+ ScreenSet = SetConsoleActiveScreenBuffer( ((PSCREEN_DATA)pScreen)->ScreenHandle);
+
+ if (ScreenSet) {
+ ActiveScreenData = (PSCREEN_DATA)pScreen;
+ }
+
+ LeaveCriticalSection( &(CurrentScreen->CriticalSection) );
+
+ return ScreenSet;
+}
+
+
+
+
+
+BOOL
+consoleGetScreenInformation (
+ PSCREEN pScreen,
+ PSCREEN_INFORMATION pScreenInfo
+ )
+/*++
+
+Routine Description:
+
+ Sets the active screen.
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data.
+ pScreenInfo - Supplies pointer to screen info buffer
+
+Return Value:
+
+ TRUE if the screen info returned
+ FALSE otherwise.
+
+--*/
+{
+
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+
+ if (!ScreenData) {
+ return FALSE;
+ }
+
+ EnterCriticalSection( &(ScreenData->CriticalSection) );
+
+ memcpy(pScreenInfo, &(ScreenData->ScreenInformation), sizeof(SCREEN_INFORMATION));
+
+ LeaveCriticalSection( &(ScreenData->CriticalSection) );
+
+ return TRUE;
+}
+
+
+
+BOOL
+consoleSetScreenSize (
+ PSCREEN pScreen,
+ ROW Rows,
+ COLUMN Cols
+ )
+/*++
+
+Routine Description:
+
+ Sets the screen size
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data.
+ Rows - Number of rows
+ Cols - Number of columns
+
+Return Value:
+
+ TRUE if screen size changed successfully
+ FALSE otherwise.
+
+--*/
+{
+
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+ CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo;
+ SMALL_RECT ScreenRect;
+ COORD ScreenSize;
+ USHORT MinRows;
+ USHORT MinCols;
+ ULONG NewBufferSize;
+ BOOL WindowSet = FALSE;
+ BOOL Status = FALSE;
+
+ //
+ // Won't attempt to resize larger than the largest window size
+ //
+ ScreenSize = GetLargestConsoleWindowSize( ScreenData->ScreenHandle );
+
+ if ( (Rows > (ROW)ScreenSize.Y) || (Cols > (COLUMN)ScreenSize.X) ) {
+ return FALSE;
+ }
+
+ EnterCriticalSection( &(ScreenData->CriticalSection) );
+
+ //
+ // Obtain the current screen information.
+ //
+ if ( GetConsoleScreenBufferInfo( ScreenData->ScreenHandle, &ScreenBufferInfo ) ) {
+
+ //
+ // If the desired buffer size is smaller than the current window
+ // size, we have to resize the current window first.
+ //
+ if ( ( Rows < (ROW)
+ (ScreenBufferInfo.srWindow.Bottom -
+ ScreenBufferInfo.srWindow.Top + 1) ) ||
+ ( Cols < (COLUMN)
+ (ScreenBufferInfo.srWindow.Right -
+ ScreenBufferInfo.srWindow.Left + 1) ) ) {
+
+ //
+ // Set the window to a size that will fit in the current
+ // screen buffer and that is no bigger than the size to
+ // which we want to grow the screen buffer.
+ //
+ MinRows = (USHORT)min( (int)Rows, (int)(ScreenBufferInfo.dwSize.Y) );
+ MinCols = (USHORT)min( (int)Cols, (int)(ScreenBufferInfo.dwSize.X) );
+
+ ScreenRect.Top = 0;
+ ScreenRect.Left = 0;
+ ScreenRect.Right = (SHORT)MinCols - (SHORT)1;
+ ScreenRect.Bottom = (SHORT)MinRows - (SHORT)1;
+
+ WindowSet = (BOOL)SetConsoleWindowInfo( ScreenData->ScreenHandle, TRUE, &ScreenRect );
+
+ if ( !WindowSet ) {
+ //
+ // ERROR
+ //
+ goto Done;
+ }
+ }
+
+ //
+ // Set the screen buffer size to the desired size.
+ //
+ ScreenSize.X = (WORD)Cols;
+ ScreenSize.Y = (WORD)Rows;
+
+ if ( !SetConsoleScreenBufferSize( ScreenData->ScreenHandle, ScreenSize ) ) {
+
+ //
+ // ERROR
+ //
+ //
+ // Return the window to its original size. We ignore the return
+ // code because there is nothing we can do about it.
+ //
+ SetConsoleWindowInfo( ScreenData->ScreenHandle, TRUE, &(ScreenBufferInfo.srWindow) );
+
+ goto Done;
+ }
+
+ //
+ // resize the screen buffer. Note that the contents of the screen
+ // buffer are not valid anymore. Someone else will have to update
+ // them.
+ //
+ NewBufferSize = Rows * Cols;
+
+ if (ScreenData->MaxBufferSize < NewBufferSize ) {
+ ScreenData->ScreenBuffer = REALLOC( ScreenData->ScreenBuffer, NewBufferSize * sizeof(CHAR_INFO));
+ ScreenData->MaxBufferSize = NewBufferSize;
+ ScreenData->LineInfo = REALLOC( ScreenData->LineInfo, Rows * sizeof( LINE_INFO ) );
+ }
+
+ //
+ // Set the Window Size. We know that we can grow the window to this size
+ // because we tested the size against the largest window size at the
+ // beginning of the function.
+ //
+ ScreenRect.Top = 0;
+ ScreenRect.Left = 0;
+ ScreenRect.Right = (SHORT)Cols - (SHORT)1;
+ ScreenRect.Bottom = (SHORT)Rows - (SHORT)1;
+
+ WindowSet = (BOOL)SetConsoleWindowInfo( ScreenData->ScreenHandle, TRUE, &ScreenRect );
+
+ if ( !WindowSet ) {
+ //
+ // We could not resize the window. We will leave the
+ // resized screen buffer.
+ //
+ // ERROR
+ //
+ goto Done;
+ }
+
+ //
+ // Update the screen size
+ //
+ ScreenData->ScreenInformation.NumberOfRows = Rows;
+ ScreenData->ScreenInformation.NumberOfCols = Cols;
+
+ InitLineInfo( ScreenData );
+
+ //
+ // Done
+ //
+ Status = TRUE;
+
+ } else {
+
+ //
+ // ERROR
+ //
+ }
+
+Done:
+ //
+ // Invalidate the entire screen buffer
+ //
+ ScreenData->FirstRow = ScreenData->ScreenInformation.NumberOfRows;
+ ScreenData->LastRow = 0;
+
+ LeaveCriticalSection( &(ScreenData->CriticalSection) );
+ return Status;
+
+}
+
+
+
+
+BOOL
+consoleSetCursor (
+ PSCREEN pScreen,
+ ROW Row,
+ COLUMN Col
+ )
+/*++
+
+Routine Description:
+
+ Moves the cursor to a certain position.
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data
+ Row - Supplies row coordinate
+ Col - Supplies column coordinate
+
+Return Value:
+
+ TRUE if moved
+ FALSE otherwise.
+
+--*/
+{
+
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+ COORD Position;
+ BOOL Moved = FALSE;
+
+
+ EnterCriticalSection( &(ScreenData->CriticalSection) );
+
+ if ((Row != ScreenData->ScreenInformation.CursorRow) ||
+ (Col != ScreenData->ScreenInformation.CursorCol) ) {
+
+ assert( Row < ScreenData->ScreenInformation.NumberOfRows);
+ assert( Col < ScreenData->ScreenInformation.NumberOfCols);
+
+ Position.Y = (SHORT)Row;
+ Position.X = (SHORT)Col;
+
+ if ( SetConsoleCursorPosition( ScreenData->ScreenHandle,
+ Position )) {
+ //
+ // Cursor moved, update the data
+ //
+ ScreenData->ScreenInformation.CursorRow = Row;
+ ScreenData->ScreenInformation.CursorCol = Col;
+
+ Moved = TRUE;
+ }
+ }
+
+ LeaveCriticalSection( &(ScreenData->CriticalSection) );
+
+ return Moved;
+}
+
+
+
+
+BOOL
+consoleSetCursorStyle (
+ PSCREEN pScreen,
+ ULONG Style
+ )
+
+/*++
+
+Routine Description7:
+
+ Sets the cursor style. The two available styles are: underscrore and
+ box
+
+Arguments:
+
+ Style - New cursor style
+
+Return Value:
+
+ True if cursor style set
+
+--*/
+
+{
+
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+ CONSOLE_CURSOR_INFO CursorInfo;
+
+ CursorInfo.bVisible = TRUE;
+
+ if ( Style == CURSOR_STYLE_UNDERSCORE ) {
+
+ CursorInfo.dwSize = 25;
+
+ } else if ( Style == CURSOR_STYLE_BOX ) {
+
+ CursorInfo.dwSize = 100;
+
+ } else {
+
+ return FALSE;
+
+ }
+
+ ScreenData->CursorSize = CursorInfo.dwSize;
+
+ return SetConsoleCursorInfo ( ScreenData->ScreenHandle,
+ &CursorInfo );
+
+}
+
+
+
+
+
+ULONG
+consoleWriteLine (
+ PSCREEN pScreen,
+ PVOID pBuffer,
+ ULONG BufferSize,
+ ROW Row,
+ COLUMN Col,
+ ATTRIBUTE Attribute,
+ BOOL Blank
+ )
+/*++
+
+Routine Description7:
+
+ Writes a buffer to the screen with the specified attribute and blanks
+ to end of row.
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data
+ pBuffer - Supplies pointer to buffer
+ BufferSize - Supplies the size of the buffer
+ Row - Supplies row coordinate
+ Col - Supplies column coordinate
+ Attr - Supplies the attribute
+ Blank - TRUE if we should blank to end of last row written.
+
+Return Value:
+
+ Number of bytes written
+
+--*/
+{
+
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+ PLINE_INFO LineInfo;
+ PCHAR_INFO CharInfo;
+ CHAR_INFO Char;
+ WORD Attr;
+
+ char * p = (char *)pBuffer;
+
+ COLUMN ColsLeft; // Available columns
+ COLUMN InfoCols; // Columns taken from buffer
+ COLUMN BlankCols; // Columns to be blanked
+ COLUMN Column; // Counter;
+
+ //
+ // We will ignore writes outside of the screen buffer
+ //
+ if ( ( Row >= ScreenData->ScreenInformation.NumberOfRows ) ||
+ ( Col >= ScreenData->ScreenInformation.NumberOfCols ) ) {
+ return TRUE;
+ }
+
+ //
+ // Ignore trivial writes
+ //
+
+ if (BufferSize == 0 && !Blank)
+ return TRUE;
+
+
+ EnterCriticalSection( &(ScreenData->CriticalSection) );
+
+ //
+ // We will truncate writes that are too long
+ //
+ if ( (Col + BufferSize) >= ScreenData->ScreenInformation.NumberOfCols ) {
+ BufferSize = ScreenData->ScreenInformation.NumberOfCols - Col;
+ }
+
+ LineInfo = ScreenData->LineInfo + Row;
+ CharInfo = LineInfo->Line + Col;
+
+ ColsLeft = ScreenData->ScreenInformation.NumberOfCols - Col;
+ InfoCols = min( BufferSize, ColsLeft );
+ BlankCols = Blank ? (ColsLeft - InfoCols) : 0;
+
+ //
+ // Set the attribute
+ //
+ if ( Attribute != ScreenData->AttributeOld ) {
+ ScreenData->AttributeOld = Attribute;
+ ScreenData->AttributeNew = GET_ATTRIBUTE(Attribute);
+ }
+ Attr = ScreenData->AttributeNew;
+
+ //
+ // set up default attribute
+ //
+
+ Char.Attributes = Attr;
+
+ //
+ // set up number of columns to draw
+ //
+
+ Column = InfoCols;
+
+ //
+ // draw chars in all specified columns
+ //
+
+ while ( Column-- ) {
+
+ //
+ // use character from input string
+ //
+
+ Char.Char.AsciiChar = *p++;
+
+ //
+ // update change portions of line info
+ //
+
+ if (CharInfo->Attributes != Char.Attributes ||
+ CharInfo->Char.AsciiChar != Char.Char.AsciiChar) {
+
+ LineInfo->colMinChanged = min (LineInfo->colMinChanged, CharInfo - LineInfo->Line);
+ LineInfo->colMaxChanged = max (LineInfo->colMaxChanged, CharInfo - LineInfo->Line);
+ LineInfo->Dirty = TRUE;
+ }
+
+ //
+ // set up new character
+ //
+
+ *CharInfo++ = Char;
+ }
+
+
+ //
+ // Blank to end of line
+ //
+ Char.Attributes = Attr;
+ Char.Char.AsciiChar = ' ';
+ Column = BlankCols;
+ while ( Column-- ) {
+ //
+ // update change portions of line info
+ //
+
+ if (CharInfo->Attributes != Char.Attributes ||
+ CharInfo->Char.AsciiChar != Char.Char.AsciiChar) {
+
+ LineInfo->colMinChanged = min (LineInfo->colMinChanged, CharInfo - LineInfo->Line);
+ LineInfo->colMaxChanged = max (LineInfo->colMaxChanged, CharInfo - LineInfo->Line);
+ LineInfo->Dirty = TRUE;
+ }
+
+ *CharInfo++ = Char;
+ }
+
+ //
+ // Update row information
+ //
+ if ( Row < ScreenData->FirstRow ) {
+ ScreenData->FirstRow = Row;
+ }
+ if ( Row > ScreenData->LastRow ) {
+ ScreenData->LastRow = Row;
+ }
+
+ LeaveCriticalSection( &(ScreenData->CriticalSection) );
+
+ return (ULONG)(InfoCols + BlankCols);
+}
+
+
+
+
+
+BOOL
+consoleShowScreen (
+ PSCREEN pScreen
+ )
+/*++
+
+Routine Description:
+
+ Moves data from our screen buffer to the console screen buffer.
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data
+
+Return Value:
+
+ TRUE if done
+ FALSE otherwise
+
+--*/
+{
+
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+ CONSOLE_CURSOR_INFO CursorInfo;
+ PLINE_INFO LineInfo;
+ BOOL Shown = FALSE;
+ ROW FirstRow;
+ ROW LastRow;
+ COLUMN LastCol;
+
+ COORD Position;
+ COORD Size;
+ SMALL_RECT Rectangle;
+
+ EnterCriticalSection( &(ScreenData->CriticalSection) );
+
+ if ( ScreenData->FirstRow <= ScreenData->LastRow ) {
+
+ Size.X = (SHORT)(ScreenData->ScreenInformation.NumberOfCols);
+ Size.Y = (SHORT)(ScreenData->ScreenInformation.NumberOfRows);
+
+ FirstRow = ScreenData->FirstRow;
+ LineInfo = ScreenData->LineInfo + FirstRow;
+
+ LastCol = ScreenData->ScreenInformation.NumberOfCols-1;
+
+ //
+ // Find next dirty block
+ //
+ while ( (FirstRow <= ScreenData->LastRow) && !LineInfo->Dirty ) {
+ FirstRow++;
+ LineInfo++;
+ }
+
+ while ( FirstRow <= ScreenData->LastRow ) {
+
+ int colLeft, colRight;
+
+ //
+ // Get the block
+ //
+
+ LastRow = FirstRow;
+
+ //
+ // set up for left/right boundary accrual
+ //
+
+ colLeft = LastCol + 1;
+ colRight = -1;
+
+ while ( (LastRow <= ScreenData->LastRow) && LineInfo->Dirty ) {
+
+ //
+ // accrue smallest bounding right/left margins
+ //
+
+ colLeft = min (colLeft, LineInfo->colMinChanged);
+ colRight = max (colRight, LineInfo->colMaxChanged);
+
+ //
+ // reset line information
+ //
+
+ ResetLineInfo (LineInfo);
+
+ //
+ // advance to next row
+ //
+
+ LastRow++;
+ LineInfo++;
+ }
+ LastRow--;
+
+
+ //
+ // Write the block
+ //
+ assert( FirstRow <= LastRow );
+
+ Position.X = (SHORT)colLeft;
+ Position.Y = (SHORT)FirstRow;
+
+ Rectangle.Top = (SHORT)FirstRow;
+ Rectangle.Bottom = (SHORT)LastRow;
+ Rectangle.Left = (SHORT) colLeft;
+ Rectangle.Right = (SHORT) colRight;
+
+ //
+ // Performance hack: making the cursor invisible speeds
+ // screen updates.
+ //
+ CursorInfo.bVisible = FALSE;
+ CursorInfo.dwSize = ScreenData->CursorSize;
+ SetConsoleCursorInfo ( ScreenData->ScreenHandle,
+ &CursorInfo );
+
+ Shown = WriteConsoleOutput( ScreenData->ScreenHandle,
+ ScreenData->ScreenBuffer,
+ Size,
+ Position,
+ &Rectangle );
+
+#if defined (DEBUG)
+ if ( !Shown ) {
+ char DbgB[128];
+ sprintf(DbgB, "MEP: WriteConsoleOutput Error %d\n", GetLastError() );
+ OutputDebugString( DbgB );
+ }
+#endif
+ assert( Shown );
+
+ CursorInfo.bVisible = TRUE;
+ SetConsoleCursorInfo ( ScreenData->ScreenHandle,
+ &CursorInfo );
+
+ FirstRow = LastRow + 1;
+
+ //
+ // Find next dirty block
+ //
+ while ( (FirstRow <= ScreenData->LastRow) && !LineInfo->Dirty ) {
+ FirstRow++;
+ LineInfo++;
+ }
+ }
+
+ ScreenData->LastRow = 0;
+ ScreenData->FirstRow = ScreenData->ScreenInformation.NumberOfRows;
+
+ }
+
+ LeaveCriticalSection( &(ScreenData->CriticalSection) );
+
+ return Shown;
+
+}
+
+
+
+
+
+BOOL
+consoleClearScreen (
+ PSCREEN pScreen,
+ BOOL ShowScreen
+ )
+/*++
+
+Routine Description:
+
+ Clears the screen
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data
+
+Return Value:
+
+ TRUE if screen cleared
+ FALSE otherwise
+
+--*/
+{
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+ ROW Rows;
+ BOOL Status = TRUE;
+
+ EnterCriticalSection( &(ScreenData->CriticalSection) );
+
+ Rows = ScreenData->ScreenInformation.NumberOfRows;
+
+ while ( Rows-- ) {
+ consoleWriteLine( pScreen, NULL, 0, Rows, 0, ScreenData->AttributeOld, TRUE );
+ }
+
+ if (ShowScreen) {
+ Status = consoleShowScreen( pScreen );
+ }
+
+ LeaveCriticalSection( &(ScreenData->CriticalSection) );
+
+ return Status;
+}
+
+
+
+
+
+
+
+BOOL
+consoleSetAttribute (
+ PSCREEN pScreen,
+ ATTRIBUTE Attribute
+ )
+/*++
+
+Routine Description:
+
+ Sets the console attribute
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data
+ Attribute - Supplies the attribute
+
+Return Value:
+
+ TRUE if Attribute set
+ FALSE otherwise
+
+--*/
+{
+
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+
+ EnterCriticalSection( &(ScreenData->CriticalSection) );
+
+ if (Attribute != ScreenData->AttributeOld) {
+ ScreenData->AttributeOld = Attribute;
+ ScreenData->AttributeNew = GET_ATTRIBUTE(Attribute);
+ }
+
+ LeaveCriticalSection( &(ScreenData->CriticalSection) );
+
+ return TRUE;
+}
+
+
+
+
+
+
+
+
+
+BOOL
+consoleFlushInput (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Flushes input events.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if success, FALSE otherwise
+
+--*/
+{
+ EventBuffer.NumberOfEvents = 0;
+
+ return FlushConsoleInputBuffer( hInput );
+}
+
+
+
+
+
+
+
+BOOL
+consoleGetMode (
+ PKBDMODE pMode
+ )
+/*++
+
+Routine Description:
+
+ Get current console mode.
+
+Arguments:
+
+ pMode - Supplies a pointer to the mode flag variable
+
+Return Value:
+
+ TRUE if success, FALSE otherwise.
+
+--*/
+{
+ return GetConsoleMode( hInput,
+ pMode );
+}
+
+
+
+
+
+
+BOOL
+consoleSetMode (
+ KBDMODE Mode
+ )
+/*++
+
+Routine Description:
+
+ Sets the console mode.
+
+Arguments:
+
+ Mode - Supplies the mode flags.
+
+Return Value:
+
+ TRUE if success, FALSE otherwise
+
+--*/
+{
+ return SetConsoleMode( hInput,
+ Mode );
+}
+
+
+BOOL
+consoleIsKeyAvailable (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Returns TRUE if a key is available in the event buffer.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if a key is available in the event buffer
+ FALSE otherwise
+
+--*/
+
+{
+ BOOL IsKey = FALSE;
+ PINPUT_RECORD pEvent;
+ DWORD Index;
+
+ EnterCriticalSection( &(EventBuffer.CriticalSection) );
+
+ for ( Index = EventBuffer.EventIndex; Index < EventBuffer.NumberOfEvents; Index++ ) {
+
+ pEvent = EventBuffer.EventBuffer + EventBuffer.EventIndex;
+
+ if ( ((EVENT_TYPE(pEvent)) == KEY_EVENT) &&
+ (PKEY_EVT(pEvent))->bKeyDown ) {
+ IsKey = TRUE;
+ break;
+ }
+ }
+
+ LeaveCriticalSection( &(EventBuffer.CriticalSection) );
+
+ return IsKey;
+}
+
+
+
+
+BOOL
+consoleDoWindow (
+ void
+ )
+
+/*++
+
+Routine Description:
+
+ Responds to a window event
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if window changed
+ FALSE otherwise
+
+--*/
+
+{
+
+ PINPUT_RECORD pEvent;
+
+ pEvent = NextEvent( NOADVANCE, NOWAIT );
+
+ if (( EVENT_TYPE(pEvent) ) == WINDOW_BUFFER_SIZE_EVENT) {
+
+ pEvent = NextEvent( ADVANCE, WAIT );
+ WindowEvent(PWINDOW_EVT(pEvent));
+ }
+
+ return FALSE;
+
+}
+
+
+
+
+
+BOOL
+consolePeekKey (
+ PKBDKEY Key
+ )
+
+/*++
+
+Routine Description:
+
+ Gets the next key from the input buffer if the buffer is not empty.
+
+
+Arguments:
+
+ Key - Supplies a pointer to a key structure
+
+Return Value:
+
+ TRUE if keystroke read, FALSE otherwise.
+
+--*/
+
+{
+
+ PINPUT_RECORD pEvent;
+ BOOL Done = FALSE;
+ BOOL IsKey = FALSE;
+
+ EnterCriticalSection(&(EventBuffer.PeekCriticalSection));
+
+ do {
+
+ pEvent = NextEvent( NOADVANCE, NOWAIT );
+
+ if ( pEvent ) {
+
+ switch ( EVENT_TYPE(pEvent) ) {
+
+ case KEY_EVENT:
+ if (KeyEvent(PKEY_EVT(pEvent), Key)){
+ IsKey = TRUE;
+ Done = TRUE;
+ }
+ break;
+
+ case MOUSE_EVENT:
+ Done = TRUE;
+ break;
+
+
+ case WINDOW_BUFFER_SIZE_EVENT:
+ Done = TRUE;
+ break;
+
+ default:
+ assert( FALSE );
+ break;
+ }
+
+ if ( !Done ) {
+ NextEvent( ADVANCE, NOWAIT );
+ }
+
+ } else {
+ Done = TRUE;
+ }
+
+ } while ( !Done );
+
+ LeaveCriticalSection(&(EventBuffer.PeekCriticalSection));
+
+ return IsKey;
+
+}
+
+
+
+
+
+
+BOOL
+consoleGetKey (
+ PKBDKEY Key,
+ BOOL fWait
+ )
+/*++
+
+Routine Description:
+
+ Gets the next key from the input buffer.
+
+Arguments:
+
+ Key - Supplies a pointer to a key structure
+ fWait - Supplies a flag:
+ if TRUE, the function blocks until a key is ready.
+ if FALSE, the function returns immediately.
+
+Return Value:
+
+ TRUE if keystroke read, FALSE otherwise.
+
+--*/
+{
+
+ PINPUT_RECORD pEvent;
+
+ do {
+ pEvent = NextEvent( ADVANCE, fWait );
+
+ if (pEvent) {
+
+ switch ( EVENT_TYPE(pEvent) ) {
+
+ case KEY_EVENT:
+ if (KeyEvent(PKEY_EVT(pEvent), Key)) {
+ return TRUE;
+ }
+ break;
+
+ case MOUSE_EVENT:
+ MouseEvent(PMOUSE_EVT(pEvent));
+ break;
+
+ case WINDOW_BUFFER_SIZE_EVENT:
+ WindowEvent(PWINDOW_EVT(pEvent));
+ break;
+
+ default:
+ break;
+ }
+ }
+ } while (fWait);
+
+ return FALSE;
+}
+
+
+BOOL
+consolePutKey (
+ PKBDKEY Key
+ )
+/*++
+
+Routine Description:
+
+ Puts a key in the console's input buffer
+
+Arguments:
+
+ Key - Supplies a pointer to a key structure
+
+Return Value:
+
+ TRUE if key put, false otherwise
+
+--*/
+{
+
+ INPUT_RECORD InputRecord;
+
+ InputRecord.EventType = KEY_EVENT;
+
+ InputRecord.Event.KeyEvent.bKeyDown = FALSE;
+ InputRecord.Event.KeyEvent.wRepeatCount = 0;
+ InputRecord.Event.KeyEvent.wVirtualKeyCode = Key->Scancode;
+ InputRecord.Event.KeyEvent.wVirtualScanCode = 0;
+ InputRecord.Event.KeyEvent.uChar.UnicodeChar = Key->Unicode;
+ InputRecord.Event.KeyEvent.dwControlKeyState = Key->Flags;
+
+ if ( PutEvent( &InputRecord )) {
+ InputRecord.Event.KeyEvent.bKeyDown = TRUE;
+ return PutEvent( &InputRecord );
+ }
+ return FALSE;
+}
+
+
+BOOL
+consolePutMouse(
+ ROW Row,
+ COLUMN Col,
+ DWORD MouseFlags
+ )
+/*++
+
+Routine Description:
+
+ Puts a mose event in the console's input buffer
+
+Arguments:
+
+ Row - Supplies the row
+ Col - Supplies the column
+ MouseFlags - Supplies the flags
+
+Return Value:
+
+ TRUE if key put, false otherwise
+
+--*/
+{
+
+ INPUT_RECORD InputRecord;
+ COORD Position;
+ DWORD Flags;
+
+ InputRecord.EventType = MOUSE_EVENT;
+
+ Position.Y = (WORD)(Row - 1);
+ Position.X = (WORD)(Col - 1);
+
+ Flags = 0;
+
+
+ InputRecord.Event.MouseEvent.dwMousePosition = Position;
+ InputRecord.Event.MouseEvent.dwButtonState = Flags;
+ InputRecord.Event.MouseEvent.dwControlKeyState = 0;
+ InputRecord.Event.MouseEvent.dwEventFlags = 0;
+
+ return PutEvent( &InputRecord );
+}
+
+
+
+BOOL
+consoleIsBusyReadingKeyboard (
+ )
+/*++
+
+Routine Description:
+
+ Determines if the console is busy reading the keyboard
+
+Arguments:
+
+ None
+
+Return Value:
+
+ TRUE if console is busy reading the keyboard.
+
+--*/
+{
+ BOOL Busy;
+
+ EnterCriticalSection(&(EventBuffer.CriticalSection));
+ Busy = EventBuffer.BusyFlag;
+ LeaveCriticalSection(&(EventBuffer.CriticalSection));
+
+ return Busy;
+}
+
+
+
+BOOL
+consoleEnterCancelEvent (
+ )
+{
+
+ INPUT_RECORD Record;
+
+ Record.EventType = KEY_EVENT;
+ Record.Event.KeyEvent.bKeyDown = TRUE;
+ Record.Event.KeyEvent.wRepeatCount = 0;
+ Record.Event.KeyEvent.wVirtualKeyCode = VK_CANCEL;
+ Record.Event.KeyEvent.wVirtualScanCode = 0;
+ Record.Event.KeyEvent.uChar.AsciiChar = 0;
+ Record.Event.KeyEvent.dwControlKeyState = 0;
+
+ return PutEvent( &Record );
+}
+
+
+PINPUT_RECORD
+NextEvent (
+ BOOL fAdvance,
+ BOOL fWait
+ )
+/*++
+
+Routine Description:
+
+ Returns pointer to next event record.
+
+Arguments:
+
+ fAdvance - Supplies a flag:
+ if TRUE: Advance to next event record
+ if FALSE: Do not advance to next event record
+
+ fWait - Supplies a flag:
+ if TRUE, the blocks until an event is ready.
+ if FALSE, return immediately.
+
+Return Value:
+
+ Pointer to event record, or NULL.
+
+--*/
+{
+ PINPUT_RECORD pEvent;
+ BOOL Success;
+
+ EnterCriticalSection(&(EventBuffer.CriticalSection));
+
+ //
+ // If the busy flag is set, then the buffer is in the process of
+ // being read. Only one thread should want to wait, so it is
+ // safe to simply return.
+ //
+ if ( EventBuffer.BusyFlag ) {
+ assert( !fWait );
+ LeaveCriticalSection(&(EventBuffer.CriticalSection));
+ return NULL;
+ }
+
+ if (EventBuffer.NumberOfEvents == 0) {
+
+ //
+ // No events in buffer, read as many as we can
+ //
+ DWORD NumberOfEvents;
+
+ //
+ // If the buffer is too big, resize it
+ //
+ if ( EventBuffer.MaxEvents > MAX_EVENTS ) {
+
+ EventBuffer.EventBuffer = REALLOC( EventBuffer.EventBuffer,
+ MAX_EVENTS * sizeof( INPUT_RECORD ) );
+
+ EventBuffer.MaxEvents = MAX_EVENTS;
+ assert( EventBuffer.EventBuffer );
+
+ //CleanExit( 1, 0 );
+ }
+
+ Success = PeekConsoleInput( hInput,
+ EventBuffer.EventBuffer,
+ EventBuffer.MaxEvents,
+ &NumberOfEvents);
+
+ if ((!Success || (NumberOfEvents == 0)) && (!fWait)) {
+ //
+ // No events available and don't want to wait,
+ // return.
+ //
+ LeaveCriticalSection(&(EventBuffer.CriticalSection));
+ return NULL;
+ }
+
+ //
+ // Since we will block, we have to leave the critical section.
+ // We set the Busy flag to indicate that the buffer is being
+ // read.
+ //
+ EventBuffer.BusyFlag = TRUE;
+ LeaveCriticalSection(&(EventBuffer.CriticalSection));
+
+ Success = ReadConsoleInput (hInput,
+ EventBuffer.EventBuffer,
+ EventBuffer.MaxEvents,
+ &EventBuffer.NumberOfEvents);
+
+ EnterCriticalSection(&(EventBuffer.CriticalSection));
+
+ EventBuffer.BusyFlag = FALSE;
+
+ if (!Success) {
+#if defined( DEBUG )
+ OutputDebugString(" Error: Cannot read console events\n");
+ assert( Success );
+#endif
+ EventBuffer.NumberOfEvents = 0;
+ }
+ EventBuffer.EventIndex = 0;
+ }
+
+ pEvent = EventBuffer.EventBuffer + EventBuffer.EventIndex;
+
+ //
+ // If Advance flag is set, we advance the pointer to the next
+ // record.
+ //
+ if (fAdvance) {
+ if (--(EventBuffer.NumberOfEvents)) {
+
+ switch (EVENT_TYPE(pEvent)) {
+
+ case KEY_EVENT:
+ case MOUSE_EVENT:
+ case WINDOW_BUFFER_SIZE_EVENT:
+ (EventBuffer.EventIndex)++;
+ break;
+
+ default:
+#if defined( DEBUG)
+ sprintf(DbgBuffer, "WARNING: unknown event type %X\n", EVENT_TYPE(pEvent));
+ OutputDebugString(DbgBuffer);
+#endif
+ (EventBuffer.EventIndex)++;
+ break;
+ }
+ }
+ }
+
+
+ LeaveCriticalSection(&(EventBuffer.CriticalSection));
+
+ return pEvent;
+}
+
+
+
+
+
+void
+MouseEvent (
+ PMOUSE_EVENT_RECORD pEvent
+ )
+/*++
+
+Routine Description:
+
+ Processes mouse events.
+
+Arguments:
+
+ pEvent - Supplies pointer to event record
+
+Return Value:
+
+ None..
+
+--*/
+{
+
+}
+
+
+
+
+
+BOOL
+WindowEvent (
+ PWINDOW_BUFFER_SIZE_RECORD pEvent
+ )
+/*++
+
+Routine Description:
+
+ Processes window size change events.
+
+Arguments:
+
+ pEvent - Supplies pointer to event record
+
+Return Value:
+
+ None
+
+--*/
+{
+ return TRUE;
+}
+
+
+
+
+
+BOOL
+KeyEvent (
+ PKEY_EVENT_RECORD pEvent,
+ PKBDKEY pKey
+ )
+/*++
+
+Routine Description:
+
+ Processes key events.
+
+Arguments:
+
+ pEvent - Supplies pointer to event record
+ pKey - Supplies pointer to key structure to fill out.
+
+Return Value:
+
+ TRUE if key structured filled out, FALSE otherwise.
+
+--*/
+{
+ // static BOOL AltPressed = FALSE;
+
+ if (pEvent->bKeyDown) {
+
+ WORD Scan = pEvent->wVirtualKeyCode;
+
+ //
+ // Pressing the ALT key generates an event, but we filter this
+ // out.
+ //
+ if (Scan == VK_MENU) {
+ return FALSE;
+ }
+
+
+ if (Scan != VK_NUMLOCK && // NumLock
+ Scan != VK_CAPITAL && // Caps Lock
+ Scan != VK_SHIFT && // Shift
+ Scan != VK_CONTROL ) { // Ctrl
+
+ pKey->Unicode = pEvent->uChar.UnicodeChar;
+ pKey->Scancode = pEvent->wVirtualKeyCode;
+ pKey->Flags = pEvent->dwControlKeyState;
+
+//#if defined (DEBUG)
+// sprintf(DbgBuffer, " KEY: Scan %d '%c'\n", pKey->Scancode, pKey->Unicode );
+// OutputDebugString(DbgBuffer);
+//#endif
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+
+ }
+
+ } else {
+
+ return FALSE;
+
+ }
+}
+
+
+BOOL
+PutEvent (
+ PINPUT_RECORD InputRecord
+ )
+{
+
+ EnterCriticalSection(&(EventBuffer.CriticalSection));
+
+ //
+ // If no space at beginning of buffer, resize and shift right
+ //
+ if ( EventBuffer.EventIndex == 0 ) {
+
+ EventBuffer.EventBuffer = REALLOC( EventBuffer.EventBuffer,
+ (EventBuffer.MaxEvents + EVENT_INCREMENT) * sizeof(INPUT_RECORD));
+
+ if ( !EventBuffer.EventBuffer ) {
+ //CleanExit(1, 0);
+ }
+
+ memmove( EventBuffer.EventBuffer + EVENT_INCREMENT,
+ EventBuffer.EventBuffer ,
+ EventBuffer.NumberOfEvents * sizeof(INPUT_RECORD) );
+
+ EventBuffer.EventIndex = EVENT_INCREMENT;
+ }
+
+ //
+ // Add event
+ //
+ EventBuffer.EventIndex--;
+ EventBuffer.NumberOfEvents++;
+
+ memcpy( EventBuffer.EventBuffer + EventBuffer.EventIndex,
+ InputRecord,
+ sizeof(INPUT_RECORD ));
+
+ LeaveCriticalSection(&(EventBuffer.CriticalSection));
+
+ return TRUE;
+}
diff --git a/private/utils/mep/help/htest/cons.h b/private/utils/mep/help/htest/cons.h
new file mode 100644
index 000000000..8dd1846e5
--- /dev/null
+++ b/private/utils/mep/help/htest/cons.h
@@ -0,0 +1,253 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ console.h
+
+Abstract:
+
+ Interface to the console-management functions for Win32 applications.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 30-Nov-1990
+
+
+Revision History:
+
+
+--*/
+
+
+
+
+//
+// Some common typedefs...
+//
+typedef ULONG ROW, *PROW; // row
+typedef ULONG COLUMN, *PCOLUMN; // column
+typedef DWORD KBDMODE, *PKBDMODE; // Keyboard mode
+typedef DWORD ATTRIBUTE, *PATTRIBUTE; // Screen Attribute
+typedef PVOID PSCREEN; // The screen
+
+
+
+//
+// Console Input Mode flags. They are the same as the NT flags
+//
+#define CONS_ENABLE_LINE_INPUT ENABLE_LINE_INPUT
+#define CONS_ENABLE_PROCESSED_INPUT ENABLE_PROCESSED_INPUT
+#define CONS_ENABLE_ECHO_INPUT ENABLE_ECHO_INPUT
+#define CONS_ENABLE_WINDOW_INPUT ENABLE_WINDOW_INPUT
+#define CONS_ENABLE_MOUSE_INPUT ENABLE_MOUSE_INPUT
+
+//
+// Cursor styles
+//
+#define CURSOR_STYLE_UNDERSCORE 0
+#define CURSOR_STYLE_BOX 1
+
+
+//
+// The information about a screen is retrieved in the following
+// structure:
+//
+typedef struct SCREEN_INFORMATION {
+ ROW NumberOfRows; // Number of rows
+ COLUMN NumberOfCols; // Number of columns
+ ROW CursorRow; // Cursor row position
+ COLUMN CursorCol; // Cursor column position
+} SCREEN_INFORMATION, *PSCREEN_INFORMATION;
+
+
+
+
+//
+// The information about each keystroke is returned in
+// the KBDKEY structure.
+//
+typedef struct KBDKEY {
+ WORD Unicode; // character unicode
+ WORD Scancode; // key scan code
+ DWORD Flags; // keyboard state flags
+} KBDKEY, *PKBDKEY;
+
+//
+// The following macros access particular fields within the
+// KBDKEY structure. They exist to facilitate porting of OS/2
+// programs.
+//
+#define KBDKEY_ASCII(k) (UCHAR)((k).Unicode)
+#define KBDKEY_SCAN(k) ((k).Scancode)
+#define KBDKEY_FLAGS(k) ((k).Flags)
+
+
+#define NEXT_EVENT_NONE 0
+#define NEXT_EVENT_KEY 1
+#define NEXT_EVENT_WINDOW 2
+
+//
+// ControlKeyState flags. They are the same as the NT status flags.
+//
+#define CONS_RIGHT_ALT_PRESSED RIGHT_ALT_PRESSED
+#define CONS_LEFT_ALT_PRESSED LEFT_ALT_PRESSED
+#define CONS_RIGHT_CTRL_PRESSED RIGHT_CTRL_PRESSED
+#define CONS_LEFT_CTRL_PRESSED LEFT_CTRL_PRESSED
+#define CONS_SHIFT_PRESSED SHIFT_PRESSED
+#define CONS_NUMLOCK_PRESSED NUMLOCK_ON
+#define CONS_SCROLLLOCK_PRESSED SCROLLLOCK_ON
+#define CONS_CAPSLOCK_PRESSED CAPSLOCK_ON
+#define CONS_ENHANCED_KEY ENHANCED_KEY
+
+
+
+
+
+//
+// Screen Management functions
+//
+PSCREEN
+consoleNewScreen (
+ void
+ );
+
+BOOL
+consoleCloseScreen (
+ PSCREEN pScreen
+ );
+
+PSCREEN
+consoleGetCurrentScreen (
+ void
+ );
+
+BOOL
+consoleSetCurrentScreen (
+ PSCREEN pScreen
+ );
+
+BOOL
+consoleGetScreenInformation (
+ PSCREEN pScreen,
+ PSCREEN_INFORMATION pScreenInformation
+ );
+
+BOOL
+consoleSetScreenSize (
+ PSCREEN Screen,
+ ROW Rows,
+ COLUMN Cols
+ );
+
+
+
+//
+// Cursor management
+//
+BOOL
+consoleSetCursor (
+ PSCREEN pScreen,
+ ROW Row,
+ COLUMN Col
+ );
+
+//
+// Cursor style
+//
+BOOL
+consoleSetCursorStyle (
+ PSCREEN pScreen,
+ ULONG Style
+ );
+
+
+
+//
+// Screen output functions
+//
+ULONG
+consoleWriteLine (
+ PSCREEN pScreen,
+ PVOID pBuffer,
+ ULONG BufferSize,
+ ROW Row,
+ COLUMN Col,
+ ATTRIBUTE Attribute,
+ BOOL Blank
+ );
+
+BOOL
+consoleShowScreen (
+ PSCREEN pScreen
+ );
+
+BOOL
+consoleClearScreen (
+ PSCREEN pScreen,
+ BOOL ShowScreen
+ );
+
+BOOL
+consoleSetAttribute (
+ PSCREEN pScreen,
+ ATTRIBUTE Attribute
+ );
+
+
+
+
+
+
+
+//
+// Input functions
+//
+BOOL
+consoleFlushInput (
+ void
+ );
+
+BOOL
+consoleIsKeyAvailable (
+ void
+ );
+
+BOOL
+consoleDoWindow (
+ void
+ );
+
+BOOL
+consoleGetKey (
+ PKBDKEY pKey,
+ BOOL fWait
+ );
+
+BOOL
+consolePutKey (
+ PKBDKEY pKey
+ );
+
+BOOL
+consolePutMouse (
+ ROW Row,
+ COLUMN Col,
+ DWORD MouseFlags
+ );
+
+BOOL
+consolePeekKey (
+ PKBDKEY pKey
+ );
+
+BOOL
+consoleGetMode (
+ PKBDMODE Mode
+ );
+
+BOOL
+consoleSetMode (
+ KBDMODE Mode
+ );
diff --git a/private/utils/mep/help/htest/htest.c b/private/utils/mep/help/htest/htest.c
new file mode 100644
index 000000000..76b4d8dce
--- /dev/null
+++ b/private/utils/mep/help/htest/htest.c
@@ -0,0 +1,1441 @@
+/*** htest - help engine test harness
+*
+* Copyright <C> 1987, Microsoft Corporation
+*
+* Revision History:
+*
+* 15-Dec-1988 ln Added dump command
+* [] 21-Oct-1988 LN New Version
+*
+*************************************************************************/
+
+#include <io.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if defined (OS2)
+#define INCL_SUB
+#define INCL_DOSMODULEMGR
+#define INCL_DOSFILEMGR
+#define INCL_DOSMISC
+#include <ctype.h>
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include "cons.h"
+
+#include "help.h"
+#include "helpfile.h" /* help file format definition */
+#include "helpsys.h" /* internal (help sys only) decl*/
+
+#if defined (OS2)
+#define HELPDLL_NAME "mshelp1.dll"
+#define HELPDLL_BASE "mshelp1"
+#else
+#define HELPDLL_NAME "mshelp.dll"
+#define HELPDLL_BASE "mshelp"
+#endif
+/*
+ * text color values
+ */
+#define BLACK 0
+#define BLUE 1
+#define GREEN 2
+#define CYAN 3
+#define RED 4
+#define MAGENTA 5
+#define BROWN 6
+#define WHITE 7
+#define GREY 8
+#define LIGHTBLUE 9
+#define LIGHTGREEN 10
+#define LIGHTCYAN 11
+#define LIGHTRED 12
+#define LIGHTMAGENTA 13
+#define YELLOW 14
+#define BRIGHTWHITE 15
+
+#define BUFSIZE 128 /* text buffer size */
+
+#define ISERROR(x) (((x).mh == 0L) && ((x).cn <= HELPERR_MAX))
+#define SETERROR(x,y) { (x).mh = 0L; (x).cn = y;}
+
+typedef void pascal (*void_F) (void);
+typedef int pascal (*int_F) (void);
+typedef ushort pascal (*ushort_F) (void);
+typedef f pascal (*f_F) (void);
+typedef char * pascal (*pchar_F) (void);
+typedef nc pascal (*nc_F) (void);
+typedef mh pascal (*mh_F) (void);
+
+#if !defined (HELP_HACK)
+
+#define HelpcLines ((int_F) (pEntry[P_HelpcLines ]))
+#define HelpClose ((void_F) (pEntry[P_HelpClose ]))
+#define HelpCtl ((void_F) (pEntry[P_HelpCtl ]))
+#define HelpDecomp ((f_F) (pEntry[P_HelpDecomp ]))
+#define HelpGetCells ((int_F) (pEntry[P_HelpGetCells ]))
+#define HelpGetInfo ((inf_F) (pEntry[P_HelpGetInfo ]))
+#define HelpGetLine ((ushort_F) (pEntry[P_HelpGetLine ]))
+#define HelpGetLineAttr ((ushort_F) (pEntry[P_HelpGetLineAttr]))
+#define HelpHlNext ((f_F) (pEntry[P_HelpHlNext ]))
+#define HelpLook ((ushort_F) (pEntry[P_HelpLook ]))
+#define HelpNc ((nc_F) (pEntry[P_HelpNc ]))
+#define HelpNcBack ((nc_F) (pEntry[P_HelpNcBack ]))
+#define HelpNcCb ((ushort_F) (pEntry[P_HelpNcCb ]))
+#define HelpNcCmp ((nc_F) (pEntry[P_HelpNcCmp ]))
+#define HelpNcNext ((nc_F) (pEntry[P_HelpNcNext ]))
+#define HelpNcPrev ((nc_F) (pEntry[P_HelpNcPrev ]))
+#define HelpNcRecord ((void_F) (pEntry[P_HelpNcRecord ]))
+#define HelpNcUniq ((nc_F) (pEntry[P_HelpNcUniq ]))
+#define HelpOpen ((nc_F) (pEntry[P_HelpOpen ]))
+#define HelpShrink ((void_F) (pEntry[P_HelpShrink ]))
+#define HelpSzContext ((f_F) (pEntry[P_HelpSzContext ]))
+#define HelpXRef ((pchar_F) (pEntry[P_HelpXRef ]))
+#define LoadFdb ((f_F) (pEntry[P_LoadFdb ]))
+#define LoadPortion ((mh_F) (pEntry[P_LoadPortion ]))
+
+#endif
+
+enum {
+ P_HelpcLines,
+ P_HelpClose,
+ P_HelpCtl,
+ P_HelpDecomp,
+ P_HelpGetCells,
+ P_HelpGetInfo,
+ P_HelpGetLine,
+ P_HelpGetLineAttr,
+ P_HelpHlNext,
+ P_HelpLook,
+ P_HelpNc,
+ P_HelpNcBack,
+ P_HelpNcCb,
+ P_HelpNcCmp,
+ P_HelpNcNext,
+ P_HelpNcPrev,
+ P_HelpNcRecord,
+ P_HelpNcUniq,
+ P_HelpOpen,
+ P_HelpShrink,
+ P_HelpSzContext,
+ P_HelpXRef,
+ P_LoadFdb,
+ P_LoadPortion,
+ LASTENTRYPOINT
+ } ENTRYPOINTS;
+
+#define NUM_ENTRYPOINTS (LASTENTRYPOINT - P_HelpcLines)
+
+
+typedef nc pascal (*PHF) (void);
+
+
+/*
+ * Global Data
+ */
+char buf[BUFSIZ]; /* text buffer */
+char cell[2] = {' ',0x1f}; /* background clearing cell */
+#define ColorByte cell[1]
+int curline; /* current line output */
+char *errTbl[] = {
+ "",
+ "help file not found",
+ "ReadHelpFile failed on header",
+ "to many open helpfiles",
+ "bad appeneded file",
+ "Not a help file",
+ "newer or incompatible help file",
+ "memory allocation failed"
+ };
+f fBoth = FALSE; /* both stdout & screen */
+f fEnable = FALSE; /* enable control lines in disp */
+int iNcCur; /* current index in ncTbl */
+int lastline;
+int lLast; /* last starting line number disp*/
+mh mhTopicCur; /* mem handle for most recent */
+uchar mpAttr[] = { /* on-screen color map */
+ 0x1f, /* 0: normal text */
+ 0x1c, /* 1: bold */
+ 0x1a, /* 2: italics */
+ 0x1e, /* 3: bold italics */
+ 0x7f, /* 4: underline */
+ 0x7c, /* 5: bold ul */
+ 0x7a, /* 6: italics ul */
+ 0x7e /* 7: bold italics ul */
+ };
+nc ncCur; /* most recently read in topic */
+nc ncTbl[MAXFILES]; /* table of open nc's */
+char far * pTopicCur; /* ptr to most recent topic */
+char *spaces = " \r\n";
+
+#if defined (OS2)
+HMODULE hModule;
+#else
+HANDLE hModule;
+#endif
+
+PHF pEntry[NUM_ENTRYPOINTS] = {0};
+#if defined (OS2)
+char * szEntryName[NUM_ENTRYPOINTS] = {
+ "_HelpcLines",
+ "_HelpClose",
+ "_HelpCtl",
+ "_HelpDecomp",
+ "_HelpGetCells",
+ "_HelpGetInfo",
+ "_HelpGetLine",
+ "_HelpGetLineAttr",
+ "_HelpHlNext",
+ "_HelpLook",
+ "_HelpNc",
+ "_HelpNcBack",
+ "_HelpNcCb",
+ "_HelpNcCmp",
+ "_HelpNcNext",
+ "_HelpNcPrev",
+ "_HelpNcRecord",
+ "_HelpNcUniq",
+ "_HelpOpen",
+ "_HelpShrink",
+ "_HelpSzContext",
+ "_HelpXRef",
+ "_LoadFdb",
+ "_LoadPortion",
+ };
+
+#else
+char * szEntryName[NUM_ENTRYPOINTS] = {
+ "HelpcLines",
+ "HelpClose",
+ "HelpCtl",
+ "HelpDecomp",
+ "HelpGetCells",
+ "HelpGetInfo",
+ "HelpGetLine",
+ "HelpGetLineAttr",
+ "HelpHlNext",
+ "HelpLook",
+ "HelpNc",
+ "HelpNcBack",
+ "HelpNcCb",
+ "HelpNcCmp",
+ "HelpNcNext",
+ "HelpNcPrev",
+ "HelpNcRecord",
+ "HelpNcUniq",
+ "HelpOpen",
+ "HelpShrink",
+ "HelpSzContext",
+ "HelpXRef",
+ "LoadFdb",
+ "LoadPortion",
+ };
+
+#endif
+
+// rjsa VIOMODEINFO screen;
+
+/*
+ * Forward declarations
+ */
+#define ASSERTDOS(x) assertDos(x, __FILE__, __LINE__)
+void pascal near assertDos (USHORT, CHAR *, USHORT);
+void pascal near cls (void);
+void pascal near dispCmd (int, int);
+void pascal near dumpCmd ();
+void pascal near dumpfileCmd ( char *);
+void pascal near fileCmd (char *);
+void pascal near helpCmd (void);
+void pascal near lookupCmd (char *, int);
+void pascal near outtext (char *, BYTE);
+void pascal near outtextat (char *, int, int, BYTE);
+uchar far * pascal near phrasecopy (uchar *, uchar far *);
+void pascal near xrefCmd (char *);
+
+#undef HelpDealloc
+#undef HelpLock
+#undef HelpUnlock
+
+void pascal far HelpDealloc (mh);
+void far * pascal far HelpLock (mh);
+void pascal far HelpUnlock (mh);
+
+f pascal near LoadFdb (mh, fdb far *);
+mh pascal near LoadPortion (USHORT, mh);
+//char far * pascal near hfstrcpy(char far *, char far *);
+//ushort pascal near hfstrlen(char far *);
+
+
+void LoadTheDll(void);
+USHORT WrtCellStr (PBYTE buf, int cb, int row, int col);
+USHORT WrtLineAttr( PBYTE buf, lineattr* rgAttr, int cb, int row, int col );
+USHORT WrtCharStrAtt (PBYTE pText, int cb, int row, int col, PBYTE pcolor);
+
+
+PSCREEN Scr;
+
+/*** main - main program
+*
+* Input:
+* Standard C main, all ignored
+*
+* Output:
+* Returns via exit()
+*
+*************************************************************************/
+void main(
+USHORT argc,
+char **argv
+) {
+char c;
+nc ncNull = {0,0};
+SCREEN_INFORMATION ScrInfo;
+/*
+ * parse any options
+ */
+if (argc > 1)
+ while ((** ++argv) == '-') {
+ c = *(++(*argv));
+ switch (toupper(c)) {
+ case 'B': /* -b: both screen and stdout */
+ fBoth = TRUE;
+ break;
+ default:
+ fputs ("Unknown switch ignored", stderr);
+ break;
+ }
+ }
+
+// InitializeGlobalState();
+Scr = consoleGetCurrentScreen();
+
+// Load help engine DLL and initialize pointers to entry
+// points.
+//
+LoadTheDll();
+
+#if defined(CLEAR)
+HelpInit();
+#endif
+
+/*
+ * Start by getting the current config & clearing screen.
+ */
+// rjsa screen.cb = sizeof(screen);
+// rjsa assertDos (VioGetMode (&screen, 0));
+// rjsa lastline = screen.row-1;
+consoleGetScreenInformation( Scr, &ScrInfo );
+lastline = ScrInfo.NumberOfRows-2;
+// lastline = 22;
+cls();
+helpCmd();
+/*
+ * main loop. Position at bottom of screen, and accept one command at at time
+ * from there. Interpret commands until done.
+ */
+do {
+ outtextat ("\r\n", lastline, 0, BRIGHTWHITE);
+ outtextat (spaces, lastline, 0, BRIGHTWHITE);
+ outtextat ("HTEST Command> ", lastline, 0, BRIGHTWHITE);
+ // rjsa VioSetCurPos (lastline, 15, 0);
+ consoleSetCursor(Scr, lastline, 16);
+ gets (buf);
+ cls ();
+ outtextat ("\r\n", lastline, 0, BRIGHTWHITE);
+ outtextat ("Processing: ", lastline, 0, LIGHTRED);
+ outtextat (buf, lastline, 12, BRIGHTWHITE);
+ outtextat ("\r\n", lastline, 0, BRIGHTWHITE);
+/*
+ * ctrl on/off
+ */
+ if (!strcmp (buf,"ctrl on")) {
+ fEnable = TRUE;
+ cls ();
+ outtextat ("Control Lines Displayed", 0, 0, BRIGHTWHITE);
+ }
+ else if (!strcmp (buf,"ctrl off")) {
+ fEnable = FALSE;
+ cls ();
+ outtextat ("Control Lines NOT Displayed", 0, 0, BRIGHTWHITE);
+ }
+/*
+ * disp
+ */
+ else if (!strcmp (buf,"disp"))
+ dispCmd (1,lastline);
+/*
+ * down
+ */
+ else if (!strcmp (buf,"down"))
+ dispCmd (lLast+1,lLast + lastline);
+/*
+ * dump
+ */
+ else if (!strncmp (buf, "dump ", 5))
+ dumpfileCmd(buf+5);
+ else if (!strcmp (buf,"dump"))
+ dumpCmd ();
+/*
+ * file newhelpfilename
+ */
+ else if (!strncmp (buf,"file ", 5))
+ fileCmd (buf+5);
+/*
+ * help
+ */
+ else if (!strcmp (buf,"help"))
+ helpCmd ();
+/*
+ * look helpstring
+ */
+ else if (!strncmp (buf,"look ", 5))
+ lookupCmd (buf+5,0);
+/*
+ * look
+ */
+ else if (!strcmp (buf,"look"))
+ lookupCmd (NULL,0);
+/*
+ * next
+ */
+ else if (!strcmp (buf,"next"))
+ lookupCmd (NULL,1);
+/*
+ * prev
+ */
+ else if (!strcmp (buf,"prev"))
+ lookupCmd (NULL,-1);
+/*
+ * up
+ */
+ else if (!strcmp (buf,"up")) {
+ lLast = max (1, lLast-1);
+ dispCmd (lLast,lLast + lastline);
+ }
+/*
+ * xref xrefnumber
+ */
+ else if (!strncmp (buf,"xref", 4))
+ xrefCmd (buf+4);
+/*
+ * + page down
+ */
+ else if (!strcmp (buf,"+")) {
+ lLast += lastline;
+ dispCmd (lLast,lLast + lastline);
+ }
+/*
+ * - page up
+ */
+ else if (!strcmp (buf,"-")) {
+ lLast = max (1, lLast - (lastline));
+ dispCmd (lLast,lLast + lastline);
+ }
+ }
+/*
+ * exit
+ */
+while (strncmp(buf,"exit",4));
+outtextat (spaces, lastline, 0, BRIGHTWHITE);
+HelpClose (ncNull);
+
+/* end main */}
+
+
+
+
+
+
+/*** dispCmd - display topic text
+*
+* displays the topic text on the screen.
+*
+* Input:
+* lStart - starting line
+* lEnd - ending line
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void pascal near dispCmd (
+int lStart,
+int lEnd
+) {
+char buf[BUFSIZ*2];
+lineattr rgAttr[BUFSIZ];
+int cb;
+int lineCur = 0;
+
+ HelpCtl (pTopicCur, fEnable);
+ cls ();
+ lLast = lStart;
+ while (lStart<lEnd) {
+ if (!isatty(_fileno(stdout)) || fBoth) {
+ cb = (int)HelpGetLine (lStart, BUFSIZ*2, (char far *)buf, pTopicCur);
+ if (cb == 0)
+ lStart = lEnd;
+ buf[cb-1] = '\r';
+ buf[cb] = '\n';
+ buf[cb+1] = 0;
+ outtext (buf, BLACK);
+ buf[cb-1] = 0;
+ }
+ if (isatty(_fileno(stdout)) || fBoth) {
+ cb = HelpGetLine(lStart, BUFSIZ*2, (char far*)buf, pTopicCur );
+ HelpGetLineAttr( lStart, BUFSIZ*sizeof(lineattr), rgAttr, pTopicCur );
+ WrtLineAttr(buf, rgAttr, cb, lineCur++, 0 );
+ }
+
+ //if (isatty(fileno(stdout)) || fBoth) {
+ // cb = HelpGetCells (lStart, BUFSIZ*2, buf, pTopicCur, mpAttr);
+ // if (cb == -1)
+ // lStart = lEnd;
+ // else
+ // ASSERTDOS (WrtCellStr (buf, cb, lineCur++, 0));
+ // }
+
+ lStart++;
+ }
+
+/* end dispCmd */}
+
+static char *szHS[] = { "HS_INDEX",
+ "HS_CONTEXTSTRINGS",
+ "HS_CONTEXTMAP",
+ "HS_KEYPHRASE",
+ "HS_HUFFTREE",
+ "HS_TOPICS",
+ "unused (6)",
+ "unused (7)",
+ "HS_NEXT" };
+
+/*** dumpCmd - process dump command
+*
+* Dumps the contents of the current help file
+*
+* NOTE:
+* This function uses all sorts of "internal" knowledge and calls to
+* do it's job.
+*
+* Input:
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void pascal near dumpCmd () {
+char buf[BUFSIZ];
+int cbKeyPhrase;
+fdb fdbLocal; /* local copy of fdb to use */
+uchar far *fpT;
+ushort far *fpW;
+int i;
+nc ncNext; /* nc init of appended file */
+//uchar uc;
+
+cls();
+ncNext = ncCur;
+while (ncNext.cn) {
+ if (LoadFdb (ncNext.mh, &fdbLocal)) {
+ sprintf (buf,"fhHelp %u\r\n", fdbLocal.fhHelp);
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"ncInit %08lx\r\n", fdbLocal.ncInit);
+ outtext (buf, BRIGHTWHITE);
+ for (i=0; i<HS_count; i++) {
+ sprintf (buf,"rgmhSections[%18s] %04x\r\n", szHS[i], fdbLocal.rgmhSections[i]);
+ outtext (buf, BRIGHTWHITE);
+ }
+ sprintf (buf,"ftype %02x\r\n", fdbLocal.ftype );
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"fname %14s\r\n", fdbLocal.fname );
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"foff %08lx\r\n", fdbLocal.foff );
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"ncLink %08lx\r\n", fdbLocal.ncLink);
+ outtext (buf, BRIGHTWHITE);
+
+ sprintf (buf,"hdr.wMagic %04x\r\n", fdbLocal.hdr.wMagic );
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"hdr.wVersion %04x\r\n", fdbLocal.hdr.wVersion );
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"hdr.wFlags %04x\r\n", fdbLocal.hdr.wFlags );
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"hdr.appChar %04x\r\n", fdbLocal.hdr.appChar );
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"hdr.cTopics %04x\r\n", fdbLocal.hdr.cTopics );
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"hdr.cContexts %04x\r\n", fdbLocal.hdr.cContexts );
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"hdr.cbWidth %04x\r\n", fdbLocal.hdr.cbWidth );
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"hdr.cPreDef %04x\r\n", fdbLocal.hdr.cPreDef );
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"hdr.fname %s\r\n", fdbLocal.hdr.fname );
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"hdr.reserved[0] %04x\r\n", fdbLocal.hdr.reserved[0]);
+ outtext (buf, BRIGHTWHITE);
+ sprintf (buf,"hdr.reserved[1] %04x\r\n", fdbLocal.hdr.reserved[1]);
+
+ for (i=0; i<HS_count; i++) {
+ sprintf (buf,"hdr.tbPos[%18s] %08lx\r\n", szHS[i], fdbLocal.hdr.tbPos[i]);
+ outtext (buf, BRIGHTWHITE);
+ }
+ outtext ("----- ----- -----\r\n", LIGHTGREEN);
+/*
+ * Topic Index
+ * This is just a table of (long) offsets within the current file. We just
+ * report the values, and also calculate the size of each entry by looking
+ * at the position of the entry following.
+ */
+ fpT = HelpLock (LoadPortion( HS_INDEX ,ncNext.mh));
+ if (fpT) {
+ outtext ("Topic Index:\r\n", LIGHTRED);
+ for (i = 0; i < (int)fdbLocal.hdr.cTopics; i++) {
+ sprintf (buf, " %2d: %08lx, %ld bytes\r\n", i, ((long far *)fpT)[i], ((long far *)fpT)[i+1]-((long far *)fpT)[i]);
+ outtext (buf, BRIGHTWHITE);
+ }
+ outtext ("----- ----- -----\r\n", LIGHTGREEN);
+ }
+/*
+ * context strings
+ * This is just a table of null terminated strings, in no particular order.
+ * We just list them out sequentially.
+ */
+ fpT = HelpLock (LoadPortion( HS_CONTEXTSTRINGS ,ncNext.mh));
+ if (fpT) {
+ outtext ("Context strings:\r\n", LIGHTRED);
+ for (i=0; i<(int)fdbLocal.hdr.cContexts; i++) {
+
+ sprintf (buf, " %03d: ", i);
+ // rjsa hfstrcpy ((char far *)buf+7, fpT);
+ strcpy ((char far *)buf+7, fpT);
+ strcat (buf, "\r\n");
+ outtext (buf, BRIGHTWHITE);
+
+ // rjsa fpT += hfstrlen(fpT) +1;
+ fpT += strlen(fpT) +1;
+ }
+ outtext ("----- ----- -----\r\n", LIGHTGREEN);
+ }
+/*
+ * Context Map
+ * This is the mapping of context strings to actual topic numbers. The context
+ * strings map one to one to the entries in this table, which in turn contains
+ * indexes into the topic index at the head of the file. We just dump this
+ * table sequentially.
+ */
+ fpT = HelpLock (LoadPortion( HS_CONTEXTMAP ,ncNext.mh));
+ if (fpT) {
+ outtext ("Context map:\r\n", LIGHTRED);
+ outtext (" Ctx Topic\r\n",BRIGHTWHITE);
+ outtext (" --- -----\r\n",BRIGHTWHITE);
+ for (i=0; i<(int)fdbLocal.hdr.cContexts; i++) {
+ sprintf (buf, " %03d: %04d\r\n", i, ((ushort far *)fpT)[i]);
+ outtext (buf, BRIGHTWHITE);
+ }
+ outtext ("----- ----- -----\r\n", LIGHTGREEN);
+ }
+/*
+ * keyword table
+ * This is a table of byte-prefixed strings, which we output in order,
+ * synthesizing the tokens that they would be in the text as well.
+ */
+ fpT = HelpLock (LoadPortion( HS_KEYPHRASE, ncNext.mh));
+ if (fpT) {
+ cbKeyPhrase = 0;
+ for (i=HS_HUFFTREE; i<HS_count; i++)
+ if (fdbLocal.hdr.tbPos[i]) {
+ cbKeyPhrase = (ushort)(fdbLocal.hdr.tbPos[i] - fdbLocal.hdr.tbPos[HS_KEYPHRASE]);
+ break;
+ }
+
+ outtext ("Keyphrase Table:\r\n", LIGHTRED);
+ outtext (" Token Phrase\r\n",BRIGHTWHITE);
+ outtext (" ----- ------\r\n",BRIGHTWHITE);
+ i = 0;
+ fpT += 1024 * sizeof (PVOID);
+ fpW = (ushort far *)(fpT + cbKeyPhrase);
+ while (fpT < (uchar far *)fpW) {
+ sprintf (buf, " %04x: ", i+(C_KEYPHRASE0 << 8));
+ fpT = phrasecopy (buf+8, fpT);
+ strcat (buf, "\r\n");
+ outtext (buf, BRIGHTWHITE);
+ i++;
+ }
+ outtext ("----- ----- -----\r\n", LIGHTGREEN);
+ }
+/*
+ * huffman table
+ * here we try to get fancy and output some information about the table format
+ */
+ fpW = HelpLock (LoadPortion( HS_HUFFTREE, ncNext.mh));
+ if (fpW) {
+ outtext ("Huffman Tree:\r\n", LIGHTRED);
+ i = 0;
+ while (*fpW) {
+ sprintf (buf, " 0x%03x: 0x%04x, %s\r\n", i++, *fpW, *fpW & 0x8000 ? "Leaf" : "Node");
+ fpW++;
+ outtext (buf, BRIGHTWHITE);
+ }
+ }
+ outtext ("===== ===== =====\r\n", YELLOW);
+ ncNext = fdbLocal.ncLink;
+ }
+ else {
+ sprintf(buf, "Cannot load fdb for %08lx\r\n",ncCur);
+ outtext (buf, LIGHTRED);
+ return;
+ }
+ }
+/* end dumpCmd */}
+
+/*** dumpfileCmd - process dump command
+*
+* Dumps the contents of the current help file
+*
+* NOTE:
+* This function uses all sorts of "internal" knowledge and calls to
+* do it's job.
+*
+* Input:
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void pascal near dumpfileCmd (char *fname) {
+char buf[BUFSIZ];
+int cbKeyPhrase;
+fdb fdbLocal; /* local copy of fdb to use */
+uchar far *fpT;
+ushort far *fpW;
+int i;
+nc ncNext; /* nc init of appended file */
+//uchar uc;
+
+FILE* fh = fopen(fname, "w");
+if (!fh) {
+ return;
+}
+ncNext = ncCur;
+while (ncNext.cn) {
+ if (LoadFdb (ncNext.mh, &fdbLocal)) {
+ sprintf (buf,"fhHelp %u\r\n", fdbLocal.fhHelp);
+ fprintf( fh, buf );
+ sprintf (buf,"ncInit %08lx\r\n", fdbLocal.ncInit);
+ fprintf( fh, buf );
+ for (i=0; i<HS_count; i++) {
+ sprintf (buf,"rgmhSections[%18s] %04x\r\n", szHS[i], fdbLocal.rgmhSections[i]);
+ fprintf( fh, buf );
+ }
+ sprintf (buf,"ftype %02x\r\n", fdbLocal.ftype );
+ fprintf( fh, buf );
+ sprintf (buf,"fname %14s\r\n", fdbLocal.fname );
+ fprintf( fh, buf );
+ fprintf( fh, buf );
+ sprintf (buf,"foff %08lx\r\n", fdbLocal.foff );
+ fprintf( fh, buf );
+ sprintf (buf,"ncLink %08lx\r\n", fdbLocal.ncLink);
+ fprintf( fh, buf );
+
+ sprintf (buf,"hdr.wMagic %04x\r\n", fdbLocal.hdr.wMagic );
+ fprintf( fh, buf );
+ sprintf (buf,"hdr.wVersion %04x\r\n", fdbLocal.hdr.wVersion );
+ fprintf( fh, buf );
+ sprintf (buf,"hdr.wFlags %04x\r\n", fdbLocal.hdr.wFlags );
+ fprintf( fh, buf );
+ sprintf (buf,"hdr.appChar %04x\r\n", fdbLocal.hdr.appChar );
+ fprintf( fh, buf );
+ sprintf (buf,"hdr.cTopics %04x\r\n", fdbLocal.hdr.cTopics );
+ fprintf( fh, buf );
+ sprintf (buf,"hdr.cContexts %04x\r\n", fdbLocal.hdr.cContexts );
+ fprintf( fh, buf );
+ sprintf (buf,"hdr.cbWidth %04x\r\n", fdbLocal.hdr.cbWidth );
+ fprintf( fh, buf );
+ sprintf (buf,"hdr.cPreDef %04x\r\n", fdbLocal.hdr.cPreDef );
+ fprintf( fh, buf );
+ sprintf (buf,"hdr.fname %s\r\n", fdbLocal.hdr.fname );
+ fprintf( fh, buf );
+ sprintf (buf,"hdr.reserved[0] %04x\r\n", fdbLocal.hdr.reserved[0]);
+ fprintf( fh, buf );
+ sprintf (buf,"hdr.reserved[1] %04x\r\n", fdbLocal.hdr.reserved[1]);
+
+ for (i=0; i<HS_count; i++) {
+ sprintf (buf,"hdr.tbPos[%18s] %08lx\r\n", szHS[i], fdbLocal.hdr.tbPos[i]);
+ fprintf( fh, buf );
+ }
+ fprintf( fh,"----- ----- -----\r\n" );
+/*
+ * Topic Index
+ * This is just a table of (long) offsets within the current file. We just
+ * report the values, and also calculate the size of each entry by looking
+ * at the position of the entry following.
+ */
+ fpT = HelpLock (LoadPortion( HS_INDEX ,ncNext.mh));
+ if (fpT) {
+ fprintf( fh,"Topic Index:\r\n" );
+ for (i = 0; i < (int)fdbLocal.hdr.cTopics; i++) {
+ sprintf (buf, " %2d: %08lx, %ld bytes\r\n", i, ((long far *)fpT)[i], ((long far *)fpT)[i+1]-((long far *)fpT)[i]);
+ fprintf( fh, buf );
+ }
+ fprintf( fh,"----- ----- -----\r\n" );
+ }
+/*
+ * context strings
+ * This is just a table of null terminated strings, in no particular order.
+ * We just list them out sequentially.
+ */
+ fpT = HelpLock (LoadPortion( HS_CONTEXTSTRINGS ,ncNext.mh));
+ if (fpT) {
+ fprintf( fh, "Context strings:\r\n" );
+ for (i=0; i<(int)fdbLocal.hdr.cContexts; i++) {
+
+ sprintf (buf, " %03d: ", i);
+ // rjsa hfstrcpy ((char far *)buf+7, fpT);
+ strcpy ((char far *)buf+7, fpT);
+ strcat (buf, "\r\n");
+ fprintf( fh, buf );
+
+ // rjsa fpT += hfstrlen(fpT) +1;
+ fpT += strlen(fpT) +1;
+ }
+ fprintf( fh,"----- ----- -----\r\n" );
+ }
+/*
+ * Context Map
+ * This is the mapping of context strings to actual topic numbers. The context
+ * strings map one to one to the entries in this table, which in turn contains
+ * indexes into the topic index at the head of the file. We just dump this
+ * table sequentially.
+ */
+ fpT = HelpLock (LoadPortion( HS_CONTEXTMAP ,ncNext.mh));
+ if (fpT) {
+ fprintf( fh, "Context map:\r\n" );
+ fprintf( fh, " Ctx Topic\r\n" );
+ fprintf( fh, " --- -----\r\n" );
+ for (i=0; i<(int)fdbLocal.hdr.cContexts; i++) {
+ sprintf (buf, " %03d: %04d\r\n", i, ((ushort far *)fpT)[i]);
+ fprintf( fh, buf );
+ }
+ fprintf( fh, "----- ----- -----\r\n" );
+ }
+/*
+ * keyword table
+ * This is a table of byte-prefixed strings, which we output in order,
+ * synthesizing the tokens that they would be in the text as well.
+ */
+ fpT = HelpLock (LoadPortion( HS_KEYPHRASE, ncNext.mh));
+ if (fpT) {
+ cbKeyPhrase = 0;
+ for (i=HS_HUFFTREE; i<HS_count; i++)
+ if (fdbLocal.hdr.tbPos[i]) {
+ cbKeyPhrase = (ushort)(fdbLocal.hdr.tbPos[i] - fdbLocal.hdr.tbPos[HS_KEYPHRASE]);
+ break;
+ }
+
+ fprintf( fh, "Keyphrase Table:\r\n" );
+ fprintf( fh, " Token Phrase\r\n" );
+ fprintf( fh, " ----- ------\r\n" );
+ i = 0;
+ fpT += 1024 * sizeof (PVOID);
+ fpW = (ushort far *)(fpT + cbKeyPhrase);
+ while (fpT < (uchar far *)fpW) {
+ sprintf (buf, " %04x: ", i+(C_KEYPHRASE0 << 8));
+ fpT = phrasecopy (buf+8, fpT);
+ strcat (buf, "\r\n");
+ fprintf( fh, buf );
+ i++;
+ }
+ fprintf( fh,"----- ----- -----\r\n" );
+ }
+/*
+ * huffman table
+ * here we try to get fancy and output some information about the table format
+ */
+ fpW = HelpLock (LoadPortion( HS_HUFFTREE, ncNext.mh));
+ if (fpW) {
+ fprintf( fh, "Huffman Tree:\r\n" );
+ i = 0;
+ while (*fpW) {
+ sprintf (buf, " 0x%03x: 0x%04x, %s\r\n", i++, *fpW, *fpW & 0x8000 ? "Leaf" : "Node");
+ fpW++;
+ fprintf( fh, buf );
+ }
+ }
+ fprintf( fh, "===== ===== =====\r\n" );
+ ncNext = fdbLocal.ncLink;
+ }
+ else {
+ sprintf(buf, "Cannot load fdb for %08lx\r\n",ncCur);
+ fprintf( fh, buf );
+ fclose(fh);
+ return;
+ }
+ }
+/* end dumpCmd */}
+
+
+/*** fileCmd - process file command
+*
+* Opens the help file specified.
+*
+* Input:
+* pName = name of help file to be added
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void pascal near fileCmd (
+char *pName
+) {
+char buf[BUFSIZ];
+int i;
+nc ncInit;
+
+sprintf (buf,"Opening %s...\r\n",pName);
+outtext (buf, BRIGHTWHITE);
+/*
+ * search file table for available slot
+ */
+for (i=0; i<MAXFILES; i++)
+ if (!ncTbl[i].cn)
+ break;
+if (i >= MAXFILES) {
+ sprintf(buf, "Cannot open %s: htest's open file limit exceeded\r\n",pName);
+ outtext (buf, LIGHTRED);
+ return;
+ }
+
+iNcCur = i;
+
+ncInit = HelpOpen(pName);
+
+for (i=0; i<MAXFILES; i++)
+ if ((ncTbl[i].mh == ncInit.mh) && (ncTbl[i].cn == ncInit.cn)) {
+ iNcCur = i;
+ sprintf (buf, "File #%d; Initial Context: 0x%04lx (file already open)\r\n",iNcCur,ncInit);
+ outtext (buf, BRIGHTWHITE);
+ return;
+ }
+
+if (ISERROR(ncInit)) {
+ sprintf(buf, "Cannot open %s: 0x%04lx, %s\r\n",pName,ncInit, errTbl[ncInit.cn]);
+ outtext (buf, LIGHTRED);
+ return;
+ }
+/*
+ * output initial context, and the available memory
+ */
+ncCur = ncTbl[iNcCur] = ncInit;
+sprintf (buf, "File #%d; Initial Context: 0x%04lx\r\n",iNcCur,ncInit.cn);
+outtext (buf, BRIGHTWHITE);
+
+lookupCmd(NULL, 0);
+/* end fileCmd */}
+
+/*** helpCmd - display help on commands
+*
+* Input:
+* none
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void pascal near helpCmd () {
+
+outtext ("HTEST - Help Engine Test Harness\r\n", BRIGHTWHITE);
+outtext ("\r\n", BRIGHTWHITE);
+outtext ("Comands:\r\n", BRIGHTWHITE);
+outtext ("\r\n", BRIGHTWHITE);
+outtext ("ctrl on/off - turn on/off display of control lines\r\n", BRIGHTWHITE);
+outtext ("disp - display first screen of most recently read topic\r\n", BRIGHTWHITE);
+outtext ("down - move ahead one line in topic and display\r\n", BRIGHTWHITE);
+outtext ("dump - dump file info (very large)\r\n", BRIGHTWHITE);
+outtext ("exit - exit htest\r\n", BRIGHTWHITE);
+outtext ("file x - open new help file, or make help file current\r\n", BRIGHTWHITE);
+outtext ("help - display this screen\r\n", BRIGHTWHITE);
+outtext ("look x - loop up context string & fetch topic\r\n", BRIGHTWHITE);
+outtext ("next - fetch next physical topic\r\n", BRIGHTWHITE);
+outtext ("prev - fetch previous physical topic\r\n", BRIGHTWHITE);
+outtext ("up - move back one line in topic and display\r\n", BRIGHTWHITE);
+outtext ("xref x - display all xrefs in current topic, or look up #x\r\n", BRIGHTWHITE);
+outtext ("+ - move & redisplay one page down\r\n", BRIGHTWHITE);
+outtext ("- - move & redisplay one page up\r\n", BRIGHTWHITE);
+/* end helpCmd */}
+
+/*** lookupCmd - process file command
+*
+* Looks up the specified string in the current helpfile, or the next help
+* topic.
+*
+* Input:
+* pString = help string to look up
+* dir = direction: 0= look up string, 1=get next, -1= get previous
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void pascal near lookupCmd (
+char *pString,
+int dir
+) {
+char buf[BUFSIZ];
+unsigned cbCompressed;
+unsigned cbUncompressed;
+char far *pCompressed;
+/*
+ * Start with the simple look up of the conetxt to get an nc. Report on
+ * failure.
+ */
+if (pString)
+ ncCur = HelpNc(pString,ncTbl[iNcCur]);
+else if (dir>0) {
+ if (!ncCur.cn)
+ ncCur = ncTbl[iNcCur];
+ else
+ ncCur = HelpNcNext(ncCur);
+ }
+else if (dir<0) {
+ if (!ncCur.cn)
+ ncCur = ncTbl[iNcCur];
+ else if (ncCur.cn != ncTbl[iNcCur].cn)
+ ncCur = HelpNcPrev(ncCur);
+ }
+else
+ ncCur = ncTbl[iNcCur];
+
+if (!ncCur.cn) {
+ outtext ("Lookup Failed: HelpNc/HelpNcNext/HelpNcPrev returned 0", LIGHTRED);
+ return;
+ }
+/*
+ * It exists. Indicate what file we're looking in, what we found, and the
+ * nc that was returned
+ */
+sprintf (buf, "File #%d; Looking up:%s\r\n",iNcCur,
+ pString ? (*pString ? pString : "local context")
+ : (dir ? ((dir>0) ? "**NEXT**" : "**PREV**")
+ : "current"));
+outtext (buf, BRIGHTWHITE);
+sprintf (buf, "nc returned = %08lx\r\n",ncCur.cn);
+outtext (buf, BRIGHTWHITE);
+/*
+ * Free up memory for previously current topic
+ */
+if (mhTopicCur)
+ free(mhTopicCur);
+/*
+ * Get the compressed memory size required, and report it. Alloc it.
+ */
+cbCompressed = HelpNcCb(ncCur);
+sprintf (buf, "size of compressed topic = %d\r\n",cbCompressed);
+outtext (buf, BRIGHTWHITE);
+pCompressed = malloc(cbCompressed);
+/*
+ * read in the compressed topic, getting the size required for the
+ * uncompressed results. Report that, and allocate it.
+ */
+cbUncompressed = HelpLook(ncCur,pCompressed);
+sprintf (buf, "size of UNcompressed topic = %d\r\n",cbUncompressed);
+outtext (buf, BRIGHTWHITE);
+mhTopicCur = malloc(cbUncompressed);
+//pTopicCur = MAKEP (mhTopicCur, 0);
+pTopicCur = mhTopicCur;
+/*
+ * Decompress the topic.
+ */
+HelpDecomp(pCompressed,pTopicCur,ncCur);
+outtext ("Decompressed\r\n", BRIGHTWHITE);
+/*
+ * exercise SzContext and cLines routines, reporting results
+ */
+HelpSzContext(buf,ncCur);
+strcat (buf, "\r\n");
+outtext (buf, BRIGHTWHITE);
+sprintf(buf,"%d lines\r\n", HelpcLines(pTopicCur));
+outtext (buf, BRIGHTWHITE);
+/*
+ * Report the amount of available memory at this point, and then free up the
+ * compressed text
+ */
+free(pCompressed);
+
+/* end lookupCmd */}
+
+/*** xrefCmd - process xref command
+*
+* Display or execute cross reference
+*
+* Input:
+* pText = pointer to ascii text which, if a non-zero number, indicates the
+* xref to execute. If zero, display all
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void pascal near xrefCmd (
+char *pText
+) {
+hotspot hsCur; /* hot spot definition */
+int i; /* working counter */
+int iReq; /* request value */
+char *pT; /* temp pointer */
+
+iReq = atoi (pText);
+hsCur.line = hsCur.col = 1;
+i = 1;
+while (HelpHlNext(0,pTopicCur,&hsCur)) {
+/*
+ * if not explicit request, then list as much as we can
+ */
+ if (!iReq) {
+ sprintf (buf, "Xref [%d] @ line: %05d columns %02d to %02d = "
+ ,i
+ ,hsCur.line
+ ,hsCur.col
+ ,hsCur.ecol);
+ pT = buf + strlen(buf);
+ if (*hsCur.pXref)
+ while (*pT++ = *hsCur.pXref++);
+ else
+ sprintf(pT, "Local >> topic # 0x%04x ",*(ushort far *)(hsCur.pXref+1));
+ strcat (buf, "\r\n");
+ outtext (buf, LIGHTGREEN);
+ }
+ else if (i == iReq) {
+ pT = buf;
+ if (*hsCur.pXref)
+ while (*pT++ = *hsCur.pXref++);
+ else {
+ *pT++ = *hsCur.pXref++;
+ *pT++ = *hsCur.pXref++;
+ *pT++ = *hsCur.pXref++;
+ }
+ lookupCmd (buf, 0);
+ return;
+ }
+ ++i;
+ hsCur.col = hsCur.ecol+(ushort)1;
+ }
+/* end xrefCmd */}
+
+/*** outtext - output text with specific colors
+*
+* sets the forground color and location as appropriate, and displays the
+* desired text. Checks for redirection, and if redirected, just outputs the
+* text to stdout.
+*
+* Input:
+* ptext = pointer to text to output
+* color = color to use
+*
+* Output:
+* Returns
+*
+*************************************************************************/
+void pascal near outtext (
+char *pText,
+BYTE color
+) {
+outtextat (pText, curline++, 0, color);
+if (curline >= lastline) {
+ if (isatty(_fileno(stdout))
+ && !fBoth) {
+
+ outtextat ("More...", lastline, 0, BRIGHTWHITE);
+ // rjsa VioSetCurPos (lastline, 8, 0);
+#if defined (OS2)
+ consoleSetCursor(lastline,8);
+#else
+ consoleSetCursor(Scr,lastline,8);
+#endif
+ gets (buf);
+ }
+ curline = 0;
+ cls ();
+ }
+
+/* end outtext */}
+
+/*** outtextat - put text with specific colors at a specific place
+*
+* sets the forground color and location as appropriate, and displays the
+* desired text. Checks for redirection, and if redirected, just outputs the
+* text to stdout.
+*
+* Input:
+* ptext = pointer to text to output
+* col = column to put into
+* color = color to use
+*
+* Output:
+* Returns
+*
+*************************************************************************/
+void pascal near outtextat (
+char *pText,
+int line,
+int col,
+BYTE color
+) {
+char *pEol; /* ptr to nl, if present */
+int len;
+
+color |= (ColorByte & 0xf0);
+if ((isatty(_fileno(stdout)) || fBoth) && (line <= lastline)) {
+ len = strlen(pText);
+ if (pEol = strchr (pText, '\r'))
+ *pEol = 0;
+ // rjsa VioWrtCharStrAtt (pText, strlen(pText), line, col, (PBYTE)&color, 0);
+ WrtCharStrAtt (pText, strlen(pText), line, col, (PBYTE)&color);
+
+ if (pEol)
+ *pEol = '\r';
+ }
+if (!isatty(_fileno(stdout)) || fBoth)
+ printf ("%s",pText);
+/* end outtextat */}
+
+/*** assertDos - asserts that a dos call returned a zero
+*
+* Just prints the number passed it if non-zero, and quits
+*
+* Input:
+* Return code from a dos call
+*
+* Output:
+* Returns only if zero passed in
+*
+*************************************************************************/
+void pascal near assertDos (
+USHORT rv,
+CHAR * pFile,
+USHORT LineNo
+) {
+if (rv) {
+ printf ("assertDos: %u (0x%04x) File %s, line %u\n", rv, rv, pFile, LineNo);
+ exit (1);
+ }
+/* end assertDos*/}
+
+/*** cls - clear screen
+*
+* Clear screen to current backround color
+*
+* Input:
+* none
+*
+* Output:
+* Returns screen clear
+*
+*************************************************************************/
+void pascal near cls () {
+curline = 0;
+// rjsa VioScrollUp (0, 0, 0xffff, 0xffff, 0xffff, cell, 0);
+consoleSetAttribute( Scr, 0x1f );
+consoleClearScreen(Scr, TRUE);
+/* end cls */}
+
+/*** phrasecopy - copy a keyword phrase from the table
+*
+* Copies a byte-length-prefixed string from far memory to a null terminated
+* string in near memory.
+*
+* Input:
+* dst - near pointer to destination
+* src - far pointer to source
+*
+* Output:
+* Returns far pointer to byte following source string
+*
+*************************************************************************/
+uchar far * pascal near phrasecopy (
+uchar *dst,
+uchar far *src
+) {
+register int i;
+
+if (i = (int)*src++)
+ while (i--)
+ *dst++ = *src++;
+*dst = 0;
+return src;
+/* end phrasecopy */}
+
+
+
+void far * pascal HelpLock(mhCur)
+mh mhCur;
+{
+//return MAKEP(mhCur,0);
+return mhCur;
+}
+
+void pascal HelpUnlock(mhCur)
+mh mhCur;
+{
+ mhCur;
+}
+
+void pascal HelpDealloc(mhCur)
+mh mhCur;
+{
+if (mhCur)
+ free(mhCur);
+}
+
+
+
+
+USHORT WrtCellStr (PBYTE buf, int cb, int row, int col) {
+ int cl = col;
+ //consoleSetCursor(Scr,row,col);
+ while (cb) {
+ UCHAR c;
+ UCHAR attr;
+
+ c = *buf++;
+ attr = *buf++;
+
+ //consoleSetAttribute(Scr,attr);
+ //consoleWrite(Scr,&c,1);
+
+ consoleWriteLine( Scr, &c, 1, row, cl, attr, FALSE );
+ cl++;
+
+ cb -= 2;
+ }
+ consoleShowScreen(Scr);
+ return 0;
+}
+
+
+USHORT WrtLineAttr ( PBYTE pText,
+ lineattr *rgAttr,
+ int cb,
+ int row,
+ int col
+ ) {
+
+ lineattr *Attr = rgAttr;
+ char *p = pText;
+ int l = cb;
+ int len;
+
+ consoleSetCursor(Scr, row, col );
+
+ while (cb > 0) {
+
+ if ( Attr->cb == 0xFFFF || Attr->attr == 0xFFFF ) {
+ len = cb;
+ } else {
+ len = Attr->cb;
+ }
+
+ outtextat (p, row, col, mpAttr[Attr->attr] );
+ col += len;
+ p += len;
+ cb -= len;
+ Attr++;
+
+ }
+ return (USHORT)l;
+}
+
+
+
+USHORT WrtCharStrAtt (PBYTE pText, int cb, int row, int col, PBYTE pcolor) {
+ //consoleSetCursor(Scr,row,col);
+ //consoleSetAttribute(Scr,*pcolor);
+ //consoleWrite( Scr,pText, cb );
+ consoleWriteLine( Scr, pText, cb, row, col, *pcolor, FALSE );
+ consoleShowScreen(Scr);
+ return 0;
+}
+
+/**********************************************************************
+ *
+ * LoadTheDll
+ *
+ * Loads the help engine dll (mshelp.dll) and initializes the
+ * pointers to the dll's entry points.
+ *
+ **********************************************************************/
+
+void
+LoadTheDll (
+ void) {
+
+
+#if defined (OS2)
+ USHORT rc;
+ CHAR szFullName[256];
+ CHAR szErrorName[256];
+ USHORT i;
+
+
+ strcpy(szFullName, HELPDLL_BASE);
+ strcpy(szErrorName, HELPDLL_NAME);
+
+ ASSERTDOS(rc = DosLoadModule(szErrorName,
+ 256,
+ szFullName,
+ &hModule));
+
+
+ for (i=0; i<LASTENTRYPOINT; i++) {
+ ASSERTDOS (rc = DosQueryProcAddr(hModule,
+ 0L,
+ szEntryName[i],
+ (PFN*)&(pEntry[i])));
+ }
+#else
+
+#if defined (HELP_HACK)
+
+ //pEntry[0] = (PHF)HelpcLines;
+ //pEntry[1] = (PHF)HelpClose;
+ //pEntry[2] = (PHF)HelpCtl;
+ //pEntry[3] = (PHF)HelpDecomp;
+ //pEntry[4] = (PHF)HelpGetCells;
+ //pEntry[5] = (PHF)HelpGetInfo;
+ //pEntry[6] = (PHF)HelpGetLine;
+ //pEntry[7] = (PHF)HelpGetLineAttr;
+ //pEntry[8] = (PHF)HelpHlNext;
+ //pEntry[9] = (PHF)HelpLook;
+ //pEntry[10] = (PHF)HelpNc;
+ //pEntry[11] = (PHF)HelpNcBack;
+ //pEntry[12] = (PHF)HelpNcCb;
+ //pEntry[13] = (PHF)HelpNcCmp;
+ //pEntry[14] = (PHF)HelpNcNext;
+ //pEntry[15] = (PHF)HelpNcPrev;
+ //pEntry[16] = (PHF)HelpNcRecord;
+ //pEntry[17] = (PHF)HelpNcUniq;
+ //pEntry[18] = (PHF)HelpOpen;
+ //pEntry[19] = (PHF)HelpShrink;
+ //pEntry[20] = (PHF)HelpSzContext;
+ //pEntry[21] = (PHF)HelpXRef;
+ //pEntry[22] = (PHF)LoadFdb;
+ //pEntry[23] = (PHF)LoadPortion;
+
+
+
+#else
+ USHORT i;
+ hModule = LoadLibrary(HELPDLL_NAME);
+ for (i=0; i<LASTENTRYPOINT; i++) {
+ pEntry[i] = (PHF)GetProcAddress(hModule, (LPSTR)szEntryName[i]);
+ }
+#endif
+
+#endif
+}
diff --git a/private/utils/mep/help/htest/makefile b/private/utils/mep/help/htest/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/mep/help/htest/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/mep/help/htest/sources b/private/utils/mep/help/htest/sources
new file mode 100644
index 000000000..dbc302203
--- /dev/null
+++ b/private/utils/mep/help/htest/sources
@@ -0,0 +1,18 @@
+MAJORCOMP=sdktools
+MINORCOMP=htest
+
+TARGETNAME=cons
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+INCLUDES=.;..\inc;..\..\inc;\nt\private\sdktools\ztools\inc
+
+
+SOURCES=cons.c
+
+
+UMAPPL=htest
+
+C_DEFINES=-D_OS2_20_=0 -DNO_EXT_KEYS -Dpascal= -Dfar= -DNOLANMAN -DNT -DHELP_HACK
+UMTYPE=console
+UMLIBS= obj\*\cons.lib ..\mshelp\obj\*\mshelp.lib ..\enginlib\obj\*\engine.lib \nt\private\sdktools\ztools\src\obj\*\ztools.lib
diff --git a/private/utils/mep/help/inc/farutil.h b/private/utils/mep/help/inc/farutil.h
new file mode 100644
index 000000000..ff41ac36e
--- /dev/null
+++ b/private/utils/mep/help/inc/farutil.h
@@ -0,0 +1,30 @@
+/*************************************************************************
+**
+** farutil.h - procedure definitions for farutil package
+**
+** Copyright <C> 1988, Microsoft Corporation
+**
+** Purpose:
+**
+** Revision History:
+**
+** [] 08-May-1988 LN Created
+**
+*************************************************************************/
+typedef char f;
+typedef unsigned char uchar;
+typedef unsigned long ulong;
+typedef unsigned short ushort;
+
+char far * pascal far farAlloc(ulong);
+void pascal far farFree (char far *);
+uchar far * pascal far farMemset(uchar far *, uchar, ushort);
+uchar far * pascal far farMove (uchar far *, uchar far *, ushort);
+uchar far * pascal far farMoveDn (uchar far *, uchar far *, ushort);
+uchar far * pascal far farMoveUp (uchar far *, uchar far *, ushort);
+int pascal far farRead (int, uchar far *, int);
+int pascal far farStrcmp (uchar far *, uchar far *);
+int pascal far farStrncmp (uchar far *, uchar far *, int);
+uchar far * pascal far farStrcpy (uchar far *, uchar far *);
+int pascal far farStrlen (uchar far *);
+int pascal far farWrite (int, uchar far *, int);
diff --git a/private/utils/mep/help/inc/help.h b/private/utils/mep/help/inc/help.h
new file mode 100644
index 000000000..4ba09bf2e
--- /dev/null
+++ b/private/utils/mep/help/inc/help.h
@@ -0,0 +1,235 @@
+/*
+** help.h
+**
+** typedefs & definitions used in the help system and by those who use it.
+**
+** define:
+** HOFFSET - to define buffer pointers (PB's) as handle/offset, else
+** they are defined as void far *.
+*/
+typedef char f; /* boolean */
+typedef unsigned char uchar;
+typedef unsigned long ulong;
+typedef unsigned short ushort;
+
+/*
+** lineattr
+** external representation of line attributes, as returned by HelpGetLineAttr
+*/
+typedef struct lineattr { /* LA */
+ ushort attr; /* attribute index */
+ ushort cb; /* count of bytes */
+ } lineattr;
+/*
+** mh
+** a memory handle is defined for use with systems that use dynamic, moveable
+** memory. It is long, so that in simple cases where memory is NOT moveable,
+** the handle can contain the far pointer to the base.
+*/
+typedef void * mh; /* dynamic memory handle */
+/*
+** nc
+** a context number is a unique id associated with each context string.
+**
+** fhnc returns the file memory handle from the nc
+** fLocal returns TRUE if the context is a uniq context number (local, or
+** result of explicit uniq call.
+*/
+typedef struct _nc {
+ mh mh;
+ ulong cn;
+ } nc ; /* context number */
+// rjsa #define fmhnc(x) ((unsigned)(((unsigned long)x & 0xffff0000L) >> 16))
+#define fmhnc(x) ((x).mh)
+#define fUniq(x) ((x).cn & 0x8000)
+
+/*
+** topichdr
+** header placed (by HelpDecomp) at the begining of every decompressed topic
+*/
+typedef struct topichdr { /* TH */
+ uchar appChar; /* app-specific character const */
+ uchar linChar; /* character for line removal */
+ uchar ftype; /* source file type */
+ ushort lnCur; /* line number last accessed */
+ ushort lnOff; /* offset into topic for that line*/
+ } topichdr;
+
+/*
+** hotspot
+** defines the position of an embedded cross reference, or "hotspot". Used by
+** HelpHlNext and HelpXRef
+*/
+typedef struct hotspot { /* HS */
+ ushort line; /* the topic line with an xref */
+ ushort col; /* the starting column of xref */
+ ushort ecol; /* the ending columng of xref */
+ uchar far *pXref; /* pointer to xref string */
+ } hotspot;
+/*
+** helpheader
+** This defines the actual structure of a help file header. Provided here
+** for HelpGetInfo
+*/
+#define HS_count 9 /* number-1 of sections defined */
+
+#pragma pack(1)
+typedef struct helpheader { /* HH */
+ ushort wMagic; /* word indicating help file */
+ ushort wVersion; /* helpfile version */
+ ushort wFlags; /* flags */
+ ushort appChar; /* application specific char */
+ ushort cTopics; /* count of topics */
+ ushort cContexts; /* count of context strings */
+ ushort cbWidth; /* fixed width */
+ ushort cPreDef; /* count of pre-defined contexts*/
+ uchar fname[14]; /* base file name */
+ ushort reserved[2]; /* unused */
+ ulong tbPos[HS_count]; /* positions for file sections */
+ } helpheader;
+#pragma pack()
+/*
+** fdb
+** Dynamically allocated structure which is created for each open help file.
+** Remains allocated for the life of the file.
+**
+** rgmhSections contains dynamic memory handles. Each open file has various
+** dynamic memory buffers associated with it. Each can be present or discarded,
+** as memory constrictions determine. If needed and not present, they are
+** reloaded from the associated help file. All may be discarded when memory
+** gets tight. An entry is defined for each help file section, except for the
+** Topics themselves.
+**
+*/
+typedef struct fdb { /* FDB */
+ FILE * fhHelp; /* OS file handle */
+ nc ncInit; /* initial context (includes mh)*/
+ mh rgmhSections[HS_count-1]; /* dynamic memory handles */
+ uchar ftype; /* file type */
+ uchar fname[14]; /* base file name */
+ ulong foff; /* our file offset, if appended */
+ nc ncLink; /* nc linking any appended file */
+ helpheader hdr; /* file header */
+ } fdb;
+/*
+** helpinfo
+** structure of information relating to a help file and/or context returned
+** by HelpGetInfo
+*/
+typedef struct helpinfo { /* HI */
+ fdb fileinfo; /* entire fdb copied out */
+ char filename[1]; /* filename appended to data */
+ } helpinfo;
+/*
+** Macros for accessing helpinfo data
+*/
+#define FHHELP(x) ((x)->fileinfo.fhHelp)
+#define NCINIT(x) ((x)->fileinfo.ncInit)
+#define FTYPE(x) ((x)->fileinfo.ftype)
+#define FNAME(x) ((x)->fileinfo.fname)
+#define FOFF(x) ((x)->fileinfo.foff)
+#define NCLINK(x) ((x)->fileinfo.ncLink)
+#define WMAGIC(x) ((x)->fileinfo.hdr.wMagic)
+#define WVERSION(x) ((x)->fileinfo.hdr.wVersion)
+#define WFLAGS(x) ((x)->fileinfo.hdr.wFlags)
+#define APPCHAR(x) ((x)->fileinfo.hdr.appChar)
+#define CTOPICS(x) ((x)->fileinfo.hdr.cTopics)
+#define CCONTEXTS(x) ((x)->fileinfo.hdr.cContexts)
+#define CBWIDTH(x) ((x)->fileinfo.hdr.cbWidth)
+#define CPREDEF(x) ((x)->fileinfo.hdr.cPreDef)
+#define HFNAME(x) ((x)->fileinfo.hdr.fname)
+#define TBPOS(x) ((x)->fileinfo.hdr.tbPos)
+
+/******************************************************************************
+**
+** Some versions of the help engine run with SS!=DS, and thus require the
+** _loadds attribute on function calls.
+*/
+#ifdef DSLOAD
+#define LOADDS _loadds
+#else
+#define LOADDS
+#endif
+
+/******************************************************************************
+**
+** PB
+** pointer to a buffer. Based on the switch HOFFSET, it is either a
+** handle-offset or a far pointer. In the handle/offset case, the high word
+** contains a memory handle which must be locked, to get a "real" address, to
+** which the offset is added.
+*/
+#ifdef HOFFSET
+#define PB ulong
+#else
+#define PB void far *
+#endif
+
+typedef PB pb;
+
+/******************************************************************************
+**
+** Forward declarations
+*/
+void far pascal LOADDS HelpInit (void);
+
+void far pascal LOADDS HelpClose(nc);
+nc far pascal LOADDS HelpOpen(char far *);
+
+nc far pascal LOADDS HelpNc(char far *, nc);
+nc far pascal LOADDS HelpNcCmp (char far *, nc,
+ f (pascal far *)(uchar far *, uchar far *, ushort, f, f));
+ushort far pascal LOADDS HelpNcCb(nc);
+ushort far pascal LOADDS HelpLook(nc, PB);
+f far pascal LOADDS HelpDecomp(PB, PB, nc);
+void far pascal LOADDS HelpCtl(PB, f);
+
+nc far pascal LOADDS HelpNcNext(nc);
+nc far pascal LOADDS HelpNcPrev(nc);
+nc far pascal LOADDS HelpNcUniq(nc);
+
+void far pascal LOADDS HelpNcRecord(nc);
+nc far pascal LOADDS HelpNcBack(void);
+
+f far pascal LOADDS HelpSzContext(uchar far *, nc);
+int far pascal LOADDS HelpGetInfo (nc, helpinfo far *, int);
+
+void far pascal LOADDS HelpShrink(void);
+
+int far pascal LOADDS HelpGetCells(int, int, char far *, PB, uchar far *);
+ushort far pascal LOADDS HelpGetLine(ushort, ushort, uchar far *, PB);
+ushort far pascal LOADDS HelpGetLineAttr(ushort, int, lineattr far *, PB);
+int far pascal LOADDS HelpcLines(PB);
+
+f far pascal LOADDS HelpHlNext(int, PB, hotspot far *);
+char far * pascal far LOADDS HelpXRef(PB, hotspot far *);
+
+/******************************************************************************
+**
+** constant declarations
+**
+** Character attribute bits. These bits are order together to form attribute
+** indecies. Data in the help file has associated with it attribute information
+** encoded in length/index pairs. Each index is simply a constant which
+** indicates which of several attributes should be applied to the characters in
+** that portion of the line.
+*/
+#define A_PLAIN 0 /* plain, "normal" text */
+#define A_BOLD 1 /* emboldened text */
+#define A_ITALICS 2 /* italicised text */
+#define A_UNDERLINE 4 /* underlined text */
+
+/******************************************************************************
+**
+** Help Error Codes.
+**
+** Return values greater than HELPERR_MAX are valid nc's.
+*/
+#define HELPERR_FNF 1 /* OpenFileOnPath failed */
+#define HELPERR_READ 2 /* ReadHelpFile failed on header*/
+#define HELPERR_LIMIT 3 /* to many open helpfiles */
+#define HELPERR_BADAPPEND 4 /* bad appeneded file */
+#define HELPERR_NOTHELP 5 /* Not a help file */
+#define HELPERR_BADVERS 6 /* newer or incompatible help file */
+#define HELPERR_MEMORY 7 /* memory allocation failed */
+#define HELPERR_MAX 10 /* max help error */
diff --git a/private/utils/mep/help/inc/helpfile.h b/private/utils/mep/help/inc/helpfile.h
new file mode 100644
index 000000000..6dd159bc1
--- /dev/null
+++ b/private/utils/mep/help/inc/helpfile.h
@@ -0,0 +1,95 @@
+/*
+** helpfile.h
+**
+** This file defines the help file format.
+**
+**
+** +---------------------+
+** | Header |
+** +---------------------+
+** | Topic index |
+** +---------------------+
+** | Context strings |
+** +---------------------+
+** | Context map |
+** +---------------------+
+** | Keyphrase table |
+** +---------------------+
+** | Huffman decode tree |
+** +---------------------+
+** | Filename Map |
+** +---------------------+
+** | Compressed topics |
+** +---------------------+
+**
+** Header: described by the structure below.
+**
+** Topic index: an array of dwords indexed by topic number that gives the file
+** position of the topic. Note: topic n+1 follows topic n so the index can be
+** used to compute the size of a topic as well.
+**
+** Context Strings: An array of (null terminated) strings which map to context
+** numbers in the following Context Map. These strings are used to for topic
+** look-up when no predefined Context Number has been assigned.
+**
+** Context map: an array of words which maps a context to a topic. This allows
+** the order of context numbers to differ from the order of topics in the help
+** file, and allows more than one context to map to the same topic.
+**
+** Keyphrase table: table of strings used to compress the topic text.
+**
+** Huffman decode tree: tree representing the character mapping used in huffman
+** copression of the help text.
+**
+** Filename Map: Table of filenames and Topic Index ranges used to redirect
+** certain topics to other help files. Used in combined help files.
+**
+** Compressed Topics: The compressed text for all topics. When the help file is
+** built, the topics are first keyphrase and runlength compressed, and are the
+** Huffman encoded. So to decode a topic, it must first be Huffman decoded, and
+** then keyphrase and runlength expanded. Keyphrase and runlength encoding
+** cookies are described below. Huffman decoding is discussed in dehuff.asm.
+*/
+
+/*
+** Numbers for each of the sections of the help file
+*/
+#define HS_INDEX 0 /* topic index */
+#define HS_CONTEXTSTRINGS 1 /* Context Strings */
+#define HS_CONTEXTMAP 2 /* context to topic map */
+#define HS_KEYPHRASE 3 /* keyphrase table */
+#define HS_HUFFTREE 4 /* huffman decode tree */
+#define HS_TOPICS 5 /* compressed topic text */
+#define HS_NEXT 8 /* position of cat'ed helpfile */
+
+#define wMagicHELP 0x4e4c /* New Help file magic word */
+#define wMagicHELPOld 0x928b /* Old Help file magic word */
+#define wHelpVers 2 /* helpfile version */
+
+
+#define wfCase 0x0001 /* set= Preserve case */
+#define wfLock 0x0002 /* set= file locked */
+
+/*
+** Keyphrase and run length encoding cookies. Each compressed keyphrase or
+** character run is replaced by one of these cookies with appropriate
+** parameters.
+**
+** Keyphrase cookies are followed by a one byte keyphrase index.
+** Runspace is followed by a one byte count of spaces.
+** Run is followed by a character and a count of repititions.
+** Quote is followed by a character.
+*/
+#define C_MIN 0x10 /* Bottom of cookie range */
+#define C_KEYPHRASE0 0x10 /* 1st keyphrase cookie */
+#define C_KEYPHRASE1 0x11 /* 2nd keyphrase cookie */
+#define C_KEYPHRASE2 0x12 /* 3rd keyphrase cookie */
+#define C_KEYPHRASE3 0x13 /* 3rd keyphrase cookie */
+#define C_KEYPHRASE_SPACE0 0x14 /* 1st keyphrase + space cookie */
+#define C_KEYPHRASE_SPACE1 0x15 /* 2nd keyphrase + space cookie */
+#define C_KEYPHRASE_SPACE2 0x16 /* 3rd keyphrase + space cookie */
+#define C_KEYPHRASE_SPACE3 0x17 /* 3rd keyphrase + space cookie */
+#define C_RUNSPACE 0x18 /* Cookie for runs of spaces */
+#define C_RUN 0x19 /* Cookie for runs of non-space */
+#define C_QUOTE 0x1a /* Cookie to quote non-cookies */
+#define C_MAX 0x1a /* top of cookie range */
diff --git a/private/utils/mep/help/inc/helpmake.h b/private/utils/mep/help/inc/helpmake.h
new file mode 100644
index 000000000..c41fdfa0e
--- /dev/null
+++ b/private/utils/mep/help/inc/helpmake.h
@@ -0,0 +1,195 @@
+/*************************************************************************
+**
+** helpmake.h - misc definitions common to helpmake
+**
+** Copyright <C> 1987, Microsoft Corporation
+**
+** Revision History:
+**
+** 31-Jul-1990 ln csVal takes a param.
+** 04-Jul-1990 JCK Add F_LOCALCONTEXT to allow escaped @
+** 28-Oct-1988 ln Add parameter to rlCompress
+** 12-Aug-1988 ln Add COLMAX, local context routines & pass1a
+** [] 18-Dec-1987 LN Created
+**
+*************************************************************************/
+
+/************************************************************************
+**
+** Includes required for subsequent definitions in this file.
+*/
+#include "help.h" // structires & constants
+#include "helpfile.h" // help file structure
+#include "helpsys.h" // misc commn defs
+#include "hmmsg.h" // error message numbers
+#include "farutil.h" // far memory utils
+#include "vm.h" // virtual memory management
+
+/*************************************************************************
+**
+** definitions
+**
+*/
+#define TRUE 1
+#define FALSE 0
+
+#define ASTACKSIZE 50 // size of attribute stack
+#define BUFSIZE 512 // size of line buffers
+#define CBFBUF 64000 // size of far buffer(s)
+#define CBIOBUF 16000 // file buffer size (60k)
+#define CBRTFMAX 40 // max length of RTF keyword
+#define CBSZCONTEXT 60000 // context string buffer size
+#define CCONTEXTMAX 10000 // max number of contexts
+#define CTOPICSMAX 10000 // max number of topics
+#define COLMAX 250 // max column we can run into
+#define FBUFSIZE 2048 // size of buffers used
+#define MAXBACKC 128 // max number of back-up characters
+
+#define F_RTF 1 // RTF file type
+#define F_QH 2 // QuickHelp format
+#define F_MINASCII 3 // minimal ascii
+#define F_MAX 3 // maximum
+
+#define F_LOCALCONTEXT 0xff // marker for local context
+
+#define CMP_RUNLENGTH 0x01 // runlength encoding
+#define CMP_KEYWORD 0x02 // base keyword encoding
+#define CMP_KEYWORD2 0x04 // "agressive" keyword
+#define CMP_HUFFMAN 0x08 // huffman encoding
+#define CMP_MAX 0x0f // maximum
+
+/*
+** formatting tokens. Embedded in non-rtf text, and converter from (longer)
+** rtf equivalents by the RTF stripper.
+*/
+#define FM_ANCHOR 'a' | 0xff00 // anchor cross reference
+#define FM_PLAIN 'p' | 0xff00 // plain text
+#define FM_BOLD 'b' | 0xff00 // bold text
+#define FM_ITALIC 'i' | 0xff00 // italic
+#define FM_HIDDEN 'v' | 0xff00 // hidden text
+#define FM_UNDERLINE 'u' | 0xff00 // underline
+#define FM_DEFAULT 'd' | 0xff00 // paragraph defaults
+#define FM_FINDENT 'f' | 0xff00 // first line indent
+#define FM_LINDENT 'l' | 0xff00 // paragraph left indent
+#define FM_TAB 't' | 0xff00 // tab character
+#define FM_LINE 'n' | 0xff00 // exlicit line break
+#define FM_BLOCKBEG '{' | 0xff00 // block begin
+#define FM_BLOCKEND '}' | 0xff00 // block begin
+
+typedef char buffer[256]; // line buffer
+typedef char f; // boolean
+
+struct kwi { // keyword info structure
+ char far *fpszKw; // pointer to the actual keyword
+ int cbKw; // length of keyword
+ ushort cKwInst; // count of keyword instances
+ ushort cKwSpInst; // count of keyword-space instances
+ int savings; // computed savings for this word
+ };
+
+/*
+** transitem
+** dotcommand translation item
+*/
+struct transitem {
+ char *pdotcmd; // original dot command
+ int cbdotcmd; // length of said dot command
+ char *pnewcmd; // replacement command
+ char cbnewcmd; // length of said new cmd
+ };
+
+// context string
+// context string item in a linked list
+//
+typedef struct _cshdr {
+ va vaNext; // next item in list or NULL
+ va vaTopic; // va of topic
+ uchar cbszCs; // length of context string + null
+ } cshdr;
+
+typedef struct _cs {
+ cshdr cshdr; // header info
+ buffer szCs; // context string + terminating null
+ } cs;
+
+/*
+** verbosity level definitions.
+*/
+#define V_BANNER (verbose >= 1) // (default) print banner
+#define V_PASSES (verbose >= 2) // print pass names
+#define V_CONTEXTS (verbose >= 3) // print contexts on 1st pass
+#define V_CONTEXTS2 (verbose >= 4) // print contexts on each pass
+#define V_STEPS (verbose >= 5) // print intermediate steps
+#define V_STATS (verbose >= 6) // print statistics
+#define V_DSTATS (verbose >= 10) // print debug statistics
+#define V_ARGS (verbose >= 20) // print prog arguments
+#define V_KEYWORD (verbose >= 30) // print keyword table
+#define V_HUFFMAN (verbose >= 40) // print huffman table
+
+/************************************************************************
+**
+** HelpMake function forward definitions
+*/
+void pascal AddContextString (char *);
+va pascal AddKw (uchar far *);
+void pascal addXref (uchar *, uchar *, ushort, ushort);
+void pascal BackUp (int);
+void pascal BackUpToken (int);
+uchar * pascal basename (uchar *);
+void pascal ContextVA (va);
+ushort pascal counttab (struct hnode *, int, ulong);
+void pascal decode (int, char **, int, f);
+int pascal DofarWrite (int, uchar far *, int);
+void pascal DumpRtf (uchar far *, nc, int, f);
+void pascal encode (int, char **, int);
+f pascal fControlLine (void);
+va pascal FindKw (uchar far *, f);
+int pascal getcProc (void);
+int pascal getcQH (void);
+int pascal getcRTF (void);
+void pascal help ();
+void pascal hmerror (ushort, uchar *, ulong);
+f pascal hmmsg (ushort);
+int hnodecomp (struct hnode **, struct hnode **);
+void pascal HuffBuild (void);
+void pascal HuffCompress (uchar far *, uchar far *);
+ushort pascal HuffDump (void);
+void pascal HuffInit (void);
+void pascal HuffFreq (uchar far *, ushort);
+void pascal HuffStats (void);
+uchar * pascal getFarMsg (ushort, uchar *);
+void pascal InitOutput (int);
+void pascal kwAnal (uchar far *, int);
+void pascal kwCompress (uchar far *);
+f pascal kwSepar (char);
+mh pascal LoadPortion (int, mh);
+ushort pascal LocalContext (uchar *, ushort);
+void pascal LocalContextFix (uchar far *);
+ushort pascal MapLocalContext (ushort);
+int pascal NextChar (void);
+char * pascal NextContext (f);
+uchar * pascal NextLine (void);
+long pascal NextNum (void);
+void pascal parserefs (uchar *, uchar *);
+void pascal pass1 (int, char **);
+void pascal pass1a (void);
+void pascal pass2 (void);
+void pascal pass3 (void);
+void pascal passfa (void);
+void pascal passfb (int);
+uchar pascal PopAttr (void);
+f pascal procRTF (char *, char *);
+void pascal PushAttr (uchar);
+void pascal rlCompress (uchar far *, ushort);
+int pascal SkipDest (int,char **);
+void pascal SkipSpace (void);
+void pascal SkipVal (char **);
+void pascal SortKw (void);
+void pascal split (int, char **);
+uchar * pascal trim (uchar *, f);
+
+#ifdef DEBUG
+void pascal csVal (va);
+#else
+#define csVal(x)
+#endif
diff --git a/private/utils/mep/help/inc/helpsys.h b/private/utils/mep/help/inc/helpsys.h
new file mode 100644
index 000000000..2997b6d6a
--- /dev/null
+++ b/private/utils/mep/help/inc/helpsys.h
@@ -0,0 +1,92 @@
+/*
+** helpsys.h - Help system internal definitions
+**
+** Copyright <C> 1987, Microsoft Corporation
+**
+** Purpose:
+** Contains definitions used within the help system.
+**
+** Revision History:
+**
+** 12-Mar-1990 CloseFile -> HelpCloseFile
+** 22-Jan-1990 MAXFILES from 50 to 100
+** [] 14-Dec-1987 Created
+**
+*/
+
+/*
+** definitions
+*/
+#ifndef NULL
+#define NULL 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+#define ASCII 1 /* build with ASCII support */
+
+#define MAXBACK 20 /* max number of back-up's */
+#define MAXFILES 100 /* max number of open helpfiles */
+
+#define FTCOMPRESSED 0x01 /* 1=compressed, 0=ascii */
+#define FTFORMATTED 0x02 /* 1=formatted, 0=unformatted */
+#define FTMERGED 0x04 /* 1=merged index, 0=normal */
+
+#define REGISTER register
+
+#define HIGHONLY(l) ((ulong)l & 0xffff0000)
+#define HIGH(l) ((ushort)(HIGHONLY(l) >> 16))
+#define LOW(l) ((ushort)((ulong)l & 0xffff))
+
+/*
+** Forward declarations for client application call-back routines
+*/
+
+#if rjsa
+#define HelpDealloc(sel) DosFreeSeg(sel)
+#define HelpLock(sel) ((void *)((ulong)sel << 16))
+#define HelpUnlock(sel)
+#else
+#define HelpDealloc(x) free(x)
+#define HelpLock(x) (x)
+#define HelpUnlock(x)
+#endif
+
+
+
+
+void pascal HelpCloseFile(FILE *);
+mh pascal HelpAlloc(ushort);
+FILE * pascal OpenFileOnPath(char *, int);
+ulong pascal ReadHelpFile(FILE *, ulong, char *, ushort);
+
+/*
+** intlineattr
+** internal representation of lineattributes
+*/
+typedef struct intlineattr { /* ILA */
+ uchar attr; /* attribute index */
+ uchar cb; /* count of bytes */
+ } intlineattr;
+
+/******************************************************************************
+**
+** PB maniputalors
+** Macros for locking and unlocking handle:offsets, as appropriate.
+*/
+#ifdef HOFFSET
+#define PBLOCK(ho) (((char *)HelpLock(HIGH(ho))) + LOW(ho))
+#define PBUNLOCK(ho) HelpUnlock(HIGH(ho))
+#else
+#define PBLOCK(ho) ((void *)ho)
+#define PBUNLOCK(ho)
+#endif
+
+
+
+PCHAR pascal hlp_locate (SHORT ln, PCHAR pTopic);
+
+
+FILE *pathopen (char *name, char *buf, char *mode);
diff --git a/private/utils/mep/help/inc/huffman.h b/private/utils/mep/help/inc/huffman.h
new file mode 100644
index 000000000..f1f79b347
--- /dev/null
+++ b/private/utils/mep/help/inc/huffman.h
@@ -0,0 +1,8 @@
+/***
+ *
+ * encode.h - header file for encode.c
+ *
+ * [] 22-Jun-87 KHD Created
+ * 01-Jul-87 LeeAc Modified.
+ *
+ *****************************************************************/
diff --git a/private/utils/mep/help/inc/rtf.h b/private/utils/mep/help/inc/rtf.h
new file mode 100644
index 000000000..f0efb40e3
--- /dev/null
+++ b/private/utils/mep/help/inc/rtf.h
@@ -0,0 +1,94 @@
+/*
+** rtf.h - definitions for the character codes used by RTF. |
+**
+** Copyright <C> 1987, Microsoft Corporation
+**
+** Purpose:
+**
+** Revision History:
+**
+** [] 17-Dec-1987 LN: Stolen from Excel code
+**
+*/
+#define cRTFMinus '-'
+#define cRTFPlus '+'
+#define cRTFTilda '~'
+#define cRTFDash '-'
+#define cRTFUnder '_'
+#define cRTFSemi ';'
+#define cRTFq '\''
+#define cRTFlb '{'
+#define cRTFrb '}'
+#define cRTFbs '\\'
+#define cRTFv 'v'
+
+/*
+** defines for primary symbol type
+*/
+#define SK_NORMAL 0 /* normal type, check token */
+#define SK_SKIPDEST 1 /* skip entire destination */
+#define SK_SKIPVALUE 2 /* skip the value */
+#define SK_SPECIAL 4 /* special character */
+#define SK_REPLACE 5 /* replace RTF token */
+#define SK_NIL 0xff /* nil type */
+
+/*
+** defines for symbols we actually care about
+*/
+#define TK_OFF 0x80 /* high bit is on/off flag */
+#define TK_NIL 0
+#define TK_ANSI 1
+#define TK_BITMAP 2 /* compressed bitmap filename follows? */
+#define TK_BLUE 3
+#define TK_BOLD 4
+#define TK_BORDERB 5
+#define TK_BORDERL 6
+#define TK_BORDERR 7
+#define TK_BORDERT 8
+#define TK_BOX 9
+#define TK_CENTERED 10
+#define TK_COLORBACK 11
+#define TK_COLORFORE 12
+#define TK_COLORTABLE 13
+#define TK_FIRSTLINE 14
+#define TK_FONTSIZE 15
+#define TK_FORMULA 16
+#define TK_GREEN 17
+#define TK_HEX 18
+#define TK_INVISIBLE 19 /* hidden text is filename: note/topic/bitmap */
+#define TK_ITALIC 20
+#define TK_JUSTIFY 21
+#define TK_LEFT 22
+#define TK_LEFTINDENT 23
+#define TK_LINE 24
+#define TK_MACCHARS 25
+#define TK_NEWLINE 26
+#define TK_NONBREAKINGDASH 27
+#define TK_NONBREAKINGSPACE 28
+#define TK_NONREQUIREDDASH 29
+#define TK_PARADEFAULT 30
+#define TK_PCCHARS 31
+#define TK_PLAIN 32
+#define TK_RED 33
+#define TK_RIGHT 34
+#define TK_RIGHTINDENT 35
+#define TK_RTAB 36
+#define TK_SIDEBYSIDE 37
+#define TK_SPACEAFTER 38
+#define TK_SPACEBEFORE 39
+#define TK_SPACELINE 40
+#define TK_STRIKEOUT 41 /* strikeout is hotspot for Topic */
+#define TK_TABCHAR 42
+#define TK_TABSTOP 43
+#define TK_UNDERLINE 44 /* underline is hotspot for Definition */
+
+/*
+** structure definition for parse table
+*/
+struct tsnPE
+ {
+ uchar *pch; // pointer to symbol string
+ uchar sk; // primary symbol kind
+ ushort tk; // token - one of the above TK_, or FM_
+ };
+typedef struct tsnPE PE;
diff --git a/private/utils/mep/help/inc/vm.h b/private/utils/mep/help/inc/vm.h
new file mode 100644
index 000000000..d22cb6379
--- /dev/null
+++ b/private/utils/mep/help/inc/vm.h
@@ -0,0 +1,46 @@
+/*************************************************************************
+**
+** vm.h - procedure definitions for VM package
+**
+** Copyright <C> 1988, Microsoft Corporation
+**
+** Purpose:
+**
+** Revision History:
+**
+** [] 21-Apr-1988 LN Created
+**
+*************************************************************************/
+typedef char f; /* boolean */
+typedef unsigned char uchar;
+typedef unsigned long ulong;
+typedef unsigned short ushort;
+typedef void far * va; /* virtual address */
+
+#define VANIL ((va)0xffffffff) /* NIL value */
+#define VANULL ((va)0) /* NULL value */
+
+ulong pascal far VMsize (long);
+
+uchar far * pascal far FMalloc (ulong);
+void pascal far FMfree (uchar far *);
+uchar far * pascal far LMalloc (ushort);
+
+void pascal far fpbToVA (char far *, va, ushort);
+void pascal far pbToVA (char *, va, ushort);
+void pascal far VATofpb (va, char far *, ushort);
+void pascal far VATopb (va, char *, ushort);
+void pascal far VAToVA (va, va, ulong);
+f pascal far VMInit (void);
+ulong pascal far VMreadlong (va);
+void pascal far VMwritelong (va, long);
+
+void pascal far VMFinish(void);
+void pascal far VMFlush (void);
+void pascal far VMShrink(f);
+
+#ifdef DEBUG
+void pascal far _vmChk (long, long);
+#else
+#define _vmChk(x,y)
+#endif
diff --git a/private/utils/mep/help/inc/zlib.h b/private/utils/mep/help/inc/zlib.h
new file mode 100644
index 000000000..437c362ba
--- /dev/null
+++ b/private/utils/mep/help/inc/zlib.h
@@ -0,0 +1,9 @@
+char *pathcat (char *pDst, char *pSrc);
+char *pname (char *pszName);
+LPSTR strbscan (const LPSTR pszStr, const LPSTR pszSet );
+char fPathChr( int c );
+BOOLEAN forsemi (char *p, BOOLEAN (*proc)( char*, void * ), void *args);
+
+
+#define strend(x) ((x)+strlen(x))
+#define PSEPSTR "/"
diff --git a/private/utils/mep/help/mshelp/help.c b/private/utils/mep/help/mshelp/help.c
new file mode 100644
index 000000000..f520d0a0b
--- /dev/null
+++ b/private/utils/mep/help/mshelp/help.c
@@ -0,0 +1,1745 @@
+/*** help.c - help library main
+*
+* Copyright <C> 1988-1990, Microsoft Corporation
+*
+* Definitions:
+*
+* Context Map: Mapping of context number to topic number.
+* Allows multiple contexts to be associated with a
+* single topic. Syncronized with the context
+* string table, each entry contains the topic
+* number associated with the corresponding context
+* string.
+*
+* Context String: String on which help can be "looked up".
+*
+* Context String Table: Table of all valid context strings in a
+* particular help file.
+*
+* Local Context: A type of context which bypasses the context
+* string and context numbers. In cross references,
+* encoded as a cross reference string of NULL,
+* followed by a topic number ored with 0x8000.
+*
+* nc: (Context Number) A long which uniquely
+* identifies a help file and context string, or
+* for local contexts, the helpfile and topic
+* number. Formatted as:
+*
+* +----------------+----------------+
+* | Fdb Mem Handle | context number |
+* +----------------+----------------+
+*
+* Where the upper word is the memory handle of the
+* allocated fdb for the help file. The lower word
+* is the either the "true" context number (see
+* below) if <= 0x7fff, or the actual topic number
+* or'ed with 0x8000.
+*
+* Topic: Actual help textual entry. May be compressed.
+*
+* Topic Index: Table of file positions of all topics contained
+* in a help file. Indexed by the topic number,
+* returns that topics physical position in the
+* file.
+*
+* Topic Number: Index to a particular topic. Topic numbers are
+* zero based, and reflect the physical ordering of
+* the topics in the file.
+*
+* "True" context number: is the zero based index or string number in the
+* <context string table>. I.E. the "n'th" string
+* has context number "n".
+*
+* The progression from string to true context number to topic number to file
+* position is:
+*
+* 1) Context String ==> "True" Context Number
+*
+* The string is searched for in the <context string table>, and
+* it's number becomes the "true" context number.
+*
+* 2) "True" Context Number ==> Topic Number
+*
+* The context number is an index into the <context map>, returing
+* the topic number associated with the context number.
+*
+* 3) Topic Number ==> File Position
+*
+* The topic number is used as an index into the Topic Index, from
+* which the physical file position is retrieved.
+*
+* Notes:
+* QuickPascal requires NO initialized data. In this case, CLEAR is defined,
+* and the HelpInit routine is included. We also play some pointer games to
+* simple variables, because the C compiler can generate CONST segment
+* entries for the SEG of various vars. (This enables it to load the segment
+* register directly, rather than by using SEG varname and another
+* register). Q/P cannot support this action by the compiler.
+*
+* QuickHelp for OS/2 is reentrant. This code should remain reentrant up to
+* but not including allocating and deallocating fdbs.
+*
+* Revision History:
+*
+* 17-Aug-1990 ln Don't blindly request 64k of an ascii file. Query
+* for size first, then read. Allocations based on
+* previous topic size requests may cause the OS to
+* GPFault for an out of range read.
+* 16-Jul-1990 ln Searching for "filename!" where filename is a QH
+* file, will now fail, rather than GP fault. Searching
+* for "!" will now succeed.
+* 08-Jun-1990 ln Remove HelpLock usage in HelpNcCmp
+* 13-Apr-1990 ln Try to get HelpSzContext to return strings in more
+* cases where it can.
+* 12-Mar-1990 ln Rename CloseFile -> HelpCloseFile
+* 08-Oct-1989 ln Changes to improve the previous change to work (allow
+* decompression) more often in low memory bases.
+* Deallocate table in OpenCore to reduce fragmentation
+* in non-moveable memory systems.
+* 19-May-1989 ln Correct bug in decompressing, where we would not
+* decompress if the tables didn;t exist.
+* 12-Apr-1989 ln Ensure that we handle Locks failing correctly. Also
+* remove TossPortion usage. Unlock handles directly.
+* 10-Mar-1989 ln Change MapTopicToContext to look forward. Changed
+* HelpNc to look begining at passed context string.
+* 17-Jan-1989 ln Correct creation of basename in HelpOpen to account
+* for environment syntax.
+* 09-Dec-1988 ln Add HelpNcUniq
+* 25-Oct-1988 ln Added minascii support to HelpNcPrev. Correct
+* minascii bug in HelpSzContext.
+* 14-Sep-1988 ln Improve doc. Remove ambiguity in MapContextToTopic
+* return value. Improve error checking in various
+* places.
+* 01-Sep-1988 ln Check ReadHelpFile return value in LoadPortion
+* 12-Aug-1988 ln Add check for memory discarded in alloc durring
+* HelpDecomp.
+* 08-Aug-1988 ln Ensure HelpClose closes ALL files. (Off by one error
+* in loop).
+* 14-Apr-1988 ln Modified to conform to QC (CW?) restriction that
+* prohibits any segments from being locked when an
+* allocation is performed.
+* [] 15-Dec-1987 ln Created, for design.
+*
+*************************************************************************/
+
+#include <assert.h> /* debugging assertions */
+#include <io.h> /* I/O function declarations */
+#include <stdlib.h> /* standard library */
+
+#include <stdio.h> /* standard I/O definitions */
+
+#if defined (OS2)
+#define INCL_BASE
+#include <os2.h>
+#else
+#include <windows.h>
+#endif
+
+#include "help.h" /* global (help & user) decl */
+#include "helpfile.h" /* help file format definition */
+#include "helpsys.h" /* internal (help sys only) decl*/
+
+#define MASIZE 512 /* size of ma input buffer */
+#define MAOVER 64 /* size of ma search overlap */
+
+#define ISERROR(x) (((x).mh == 0L) && ((x).cn <= HELPERR_MAX))
+#define SETERROR(x,y) { (x).mh = 0L; (x).cn = y; }
+
+/*************************************************************************
+**
+** Forward definitions
+*/
+void pascal near CloseShrink(nc, f);
+f pascal near LoadFdb (mh, fdb far *);
+mh pascal near LoadPortion (int, mh);
+ushort pascal near MapContexttoTopic (nc, fdb far *);
+nc pascal near MapTopictoContext(ushort, fdb far *, int);
+nc pascal near NextPrev(nc,int);
+nc pascal near OpenCore(FILE *, ulong, uchar far *, struct helpheader *, fdb far *);
+f pascal near PutFdb (mh, fdb far *);
+f pascal near SizePos (nc, ushort *,ulong *);
+
+ushort pascal near decomp (uchar far *, uchar far *, uchar far *, uchar far *);
+char far * pascal near hfmemzer(void far *, ushort);
+char far * pascal near hfstrchr(char far *, char);
+char far * pascal near hfstrcpy(char far *, char far *);
+ushort pascal near hfstrlen(char far *);
+f pascal far HelpCmp (uchar far *, uchar far *, ushort, f, f);
+f pascal near HelpCmpSz (uchar far *, uchar far *);
+void pascal near kwPtrBuild(uchar far *, ushort);
+
+#if ASCII
+long pascal near maLocate (fdb far *, uchar far *, ulong,
+ f (pascal far *)(uchar far *, uchar far *, ushort, f, f));
+
+nc pascal near combineNc (ulong, mh);
+ulong pascal near NctoFo (ulong);
+#endif
+
+/*************************************************************************
+**
+** External Global data
+** BEWARE. The effects of global data on reentrancy should be VERY carefully
+** considered.
+**
+*************************************************************************/
+extern mh tbmhFdb[MAXFILES+1];
+extern char szNil[1];
+extern ushort cBack;
+
+#ifdef CLEAR
+/*************************************************************************
+**
+** HelpInit - One-time initialization
+**
+** Purpose:
+** Performs one-time initialization. Right now that's a zero fill of static
+** memory for those environments which don't support pre-inited static
+** memory.
+**
+** Entry:
+** none
+**
+** Exit:
+** none
+**
+*/
+void far pascal LOADDS HelpInit () {
+
+hfmemzer (tbmhFdb, sizeof(tbmhFdb)); /* zero entire fdb handle table */
+hfmemzer (szNil, sizeof(szNil)); /* zero null string */
+hfmemzer (&cBack, sizeof(cBack)); /* zero back trace count */
+
+/* end HelpInit */}
+#endif
+
+/*************************************************************************
+**
+** HelpOpen - Open help file & return help handle.
+**
+** Purpose:
+** Given the file basename, locate the associated help file on the path, and
+** open it, initializing internal data structures as appropriate.
+**
+** Entry:
+** fpszName - base filename to be openned.
+**
+** Exit:
+** nc initial context for openned file.
+**
+** Exceptions:
+** Returns error code on failure to open for any reason.
+**
+*/
+nc far pascal LOADDS HelpOpen (
+char far *fpszName
+) {
+FILE *fhT; /* temp file handle */
+fdb fdbLocal; /* local copy of fdb to use */
+uchar far *fpszBase; /* base filename */
+void far *fpT;
+struct helpheader hdrLocal; /* for use by opencore */
+nc ncRet = {0,0}; /* first context */
+mh *ptbmhFdb; /* pointer into mh table */
+
+/*
+** create basename by removing possible env variable, drive, and scanning
+** for last path seperator
+*/
+fpszBase = fpszName;
+if (fpT = hfstrchr(fpszBase,':'))
+ fpszBase = (uchar far *)fpT+1;
+while (fpT = hfstrchr(fpszBase,'\\'))
+ fpszBase = (uchar far *)fpT+1;
+/*
+** Scan FDB's for an open file of the same base name. If we encounter the name,
+** in either the true filename, or file header, just return that file's initial
+** context. Otherwise fall below to try and open it.
+*/
+for (ptbmhFdb=&tbmhFdb[1]; ptbmhFdb<=&tbmhFdb[MAXFILES]; ptbmhFdb++) {
+ if (LoadFdb (*ptbmhFdb,&fdbLocal)) {
+ if (HelpCmpSz(fpszBase,fdbLocal.fname) ||
+ HelpCmpSz(fpszBase,fdbLocal.hdr.fname))
+ ncRet = fdbLocal.ncInit;
+ if (ncRet.mh && ncRet.cn)
+ return ncRet;
+ }
+ }
+/*
+** Open file. If we can, then call the core open routine to open the file (and
+** any anything appended to it).
+**
+** Warning: the app may callback HelpClose at this point.
+*/
+if (fhT = OpenFileOnPath(fpszName,FALSE)) {
+ ncRet = OpenCore (fhT,0L,fpszBase,&hdrLocal,&fdbLocal);
+ if (ISERROR(ncRet))
+ HelpCloseFile (fhT);
+ return ncRet;
+ }
+
+SETERROR(ncRet, HELPERR_FNF);
+return ncRet;
+// rjsa return HELPERR_FNF;
+
+/* end HelpOpen*/}
+
+/*************************************************************************
+**
+** OpenCore - Recursive core of HelpOpen
+**
+** Purpose:
+** Given the open file handle, initialize internal data structures as
+** appropriate. Attempt to open any file that is appended.
+**
+** Entry:
+** fhT - Open file handle
+** offset - Offset from start of file of help file to open
+** fpszBase - pointer to base filename
+**
+** Exit:
+** initial context, or NULL on failure.
+**
+** Exceptions:
+** Returns NULL on failure to open for any reason.
+**
+*/
+nc pascal near OpenCore (
+FILE * fhHelp,
+ulong offset,
+uchar far *fpszBase, /* base filename */
+struct helpheader *phdrLocal,
+fdb far *pfdbLocal /* pointer to current FDB */
+) {
+//void far *fpT;
+int ihFree; /* handle for free fdb (& index)*/
+mh mhCur; /* current memory handle */
+nc ncFirst = {0,0}; /* first context */
+nc ncInit; /* first context */
+mh *pmhT; /* pointer into mh table */
+
+/*
+** Read in helpfile header
+*/
+if (ReadHelpFile(fhHelp,
+ offset,
+ (char far *)phdrLocal,
+ (ushort)sizeof(struct helpheader))) {
+/*
+** search for available fdb
+*/
+ for (ihFree = MAXFILES, pmhT = &tbmhFdb[MAXFILES];
+ ihFree && *pmhT;
+ ihFree--, pmhT--);
+/*
+** if an offset is present, and this is NOT a compressed file, or there is no
+** available fdb, ignore the operation.
+*/
+ if ( offset
+ && (phdrLocal->wMagic != wMagicHELP)
+ && (phdrLocal->wMagic != wMagicHELPOld)
+ ) {
+ SETERROR(ncInit, HELPERR_BADAPPEND);
+ return ncInit;
+ // rjsa return HELPERR_BADAPPEND;
+ }
+ if (ihFree == 0) {
+ SETERROR(ncInit, HELPERR_LIMIT);
+ return ncInit;
+ // rjsa return HELPERR_LIMIT;
+ }
+/*
+** allocate fdb. Again, if we can't, skip it all and return NULL.
+*/
+ if (mhCur = *pmhT = HelpAlloc((ushort)sizeof(fdb))) {
+/*
+** Fill in helpfile header & appropriate fdb fields
+*/
+ hfmemzer(pfdbLocal,sizeof(fdb)); /* zero entire fdb */
+ pfdbLocal->fhHelp = fhHelp; /* file handle */
+ ncFirst.mh = pfdbLocal->ncInit.mh = mhCur;
+ ncFirst.cn = pfdbLocal->ncInit.cn = 0L;
+ // rjsa ncFirst = pfdbLocal->ncInit = ((long)mhCur) << 16; /* initial context */
+ pfdbLocal->foff = offset; /* appended offset */
+ hfstrcpy(pfdbLocal->fname,fpszBase); /* include base filename*/
+/*
+** if this is a compressed file (signified by the first two bytes of the header
+** we read in above), then note the file type in the fdb. We unlock the fdb, as
+** MapTopicToContext and the recursion might cause memory allocation. We get a
+** context number for the first topic, and recurse and attempt to open any
+** appended file.
+*/
+ if ( (phdrLocal->wMagic == wMagicHELPOld)
+ || (phdrLocal->wMagic == wMagicHELP)
+ ) {
+ if ((phdrLocal->wMagic == wMagicHELP)
+ && (phdrLocal->wVersion > wHelpVers)) {
+ SETERROR(ncInit, HELPERR_BADVERS);
+ return ncInit;
+ // rjsa return HELPERR_BADVERS;
+ }
+ pfdbLocal->hdr = *phdrLocal;
+ pfdbLocal->ftype = FTCOMPRESSED | FTFORMATTED;
+ if (PutFdb (mhCur, pfdbLocal)) {
+ ncFirst = MapTopictoContext(0,pfdbLocal,0);
+
+ // We free the context map (the only thing loaded by the
+ // MapTopictoContext) in order to reduce fragmentation in
+ // non-moveable memory based systems.
+ //
+ HelpDealloc (pfdbLocal->rgmhSections[HS_CONTEXTMAP]);
+ pfdbLocal->rgmhSections[HS_CONTEXTMAP] = 0;
+
+ ncInit = OpenCore(fhHelp,pfdbLocal->hdr.tbPos[HS_NEXT]+offset,szNil,phdrLocal,pfdbLocal);
+ if (LoadFdb (mhCur, pfdbLocal)) {
+ //if (ncInit.cn > HELPERR_MAX) {
+ if ( !(ISERROR(ncInit)) ) {
+ pfdbLocal->ncLink = ncInit;
+ } else {
+ pfdbLocal->ncLink.mh = (mh)0;
+ pfdbLocal->ncLink.cn = 0L;
+ }
+ // rjsa pfdbLocal->ncLink = ncInit > HELPERR_MAX ? ncInit : 0;
+ pfdbLocal->ncInit = ncFirst;
+ }
+ }
+ }
+#if ASCII
+/*
+** In the case of a minascii formatted file (signified by the first two bytes
+** of the header being ">>") we just set up the filetype and "applications
+** specific character". The default "ncFirst" is the context for the first
+** topic.
+*/
+ else if (phdrLocal->wMagic == 0x3e3e) { /* minascii formatted? */
+ pfdbLocal->ftype = FTFORMATTED;
+ pfdbLocal->hdr.appChar = '>'; /* ignore lines with this*/
+ }
+#endif
+ else if ((phdrLocal->wMagic & 0x8080) == 0) { /* ascii unformatted? */
+ pfdbLocal->ftype = 0;
+ pfdbLocal->hdr.appChar = 0xff; /* ignore lines with this*/
+ }
+ else {
+ SETERROR(ncInit, HELPERR_NOTHELP);
+ return ncInit;
+ // rjsa return HELPERR_NOTHELP;
+ }
+
+ if (!PutFdb (mhCur, pfdbLocal)) {
+ ncFirst.mh = (mh)0;
+ ncFirst.cn = 0L;
+ }
+ }
+ else {
+ SETERROR(ncFirst, HELPERR_MEMORY);
+ // rjsa ncFirst = HELPERR_MEMORY; /* error reading file */
+ }
+}
+else {
+ SETERROR(ncFirst, HELPERR_READ);
+ // rjsa ncFirst = HELPERR_READ; /* error reading file */
+}
+
+return ncFirst; /* return valid context */
+
+/* end OpenCore */}
+
+
+/*************************************************************************
+**
+** HelpClose - Close Help file
+**
+** Purpose:
+** Close a help file, deallocate all memory associated with it, and free the
+** handle.
+**
+** Entry:
+** ncClose - Context for file to be closed. If zero, close all.
+**
+** Exit:
+** None
+**
+** Exceptions:
+** All errors are ignored.
+**
+*/
+void far pascal LOADDS HelpClose (
+nc ncClose
+) {
+CloseShrink(ncClose,TRUE); /* close file(s) */
+/* end HelpClose */}
+
+/*************************************************************************
+**
+** HelpShrink - Release all dynamic memory
+**
+** Purpose:
+** A call to this routines causes the help system to release all dynamic
+** memory it may have in use.
+**
+** Entry:
+** None.
+**
+** Exit:
+** None.
+**
+** Exceptions:
+** None.
+**
+*/
+void far pascal LOADDS HelpShrink(void) {
+ nc ncTmp = {0,0};
+CloseShrink(ncTmp,0);
+// rjsa CloseShrink(0,0);
+/* end HelpShrink */}
+
+/*************************************************************************
+**
+** CloseShrink - Deallocate memory and possibly Close Help file
+**
+** Purpose:
+** Deallocate all memory associated with a help file, and possibly close free
+** it.
+**
+** Entry:
+** ncClose - Context for file. If zero, do all.
+** fClose - TRUE if a close operation.
+**
+** Exit:
+** None
+**
+** Exceptions:
+** All errors are ignored.
+**
+*/
+void pascal near CloseShrink (
+nc ncClose,
+f fClose
+) {
+fdb fdbLocal; /* pointer to current FDB */
+int i;
+mh mhClose; /* fdb mem hdl to file to close */
+mh *pmhFdb; /* pointer to FDB's table entry */
+
+
+mhClose = ncClose.mh; /* get index */
+// rjsa mhClose = (mh)HIGH(ncClose); /* get index */
+for (pmhFdb = &tbmhFdb[0]; /* for each possible entry */
+ pmhFdb <= &tbmhFdb[MAXFILES];
+ pmhFdb++
+ ) {
+ if ((mhClose == 0) /* if all selected */
+ || (mhClose == *pmhFdb)) { /* or this one selected */
+
+ if (LoadFdb (*pmhFdb, &fdbLocal)) { /* if open file */
+/*
+ * Recurse to close/shrink any appended files
+ */
+ if ((fdbLocal.ncLink.mh || fdbLocal.ncLink.cn) && mhClose)
+ CloseShrink (fdbLocal.ncLink, fClose);
+
+ for (i=HS_count-2; i>=0; i--) /* for dyn mem handles */
+ HelpDealloc(fdbLocal.rgmhSections[i]); /* dealloc */
+ hfmemzer(fdbLocal.rgmhSections,sizeof(fdbLocal.rgmhSections));
+
+ if (fClose) {
+ HelpCloseFile(fdbLocal.fhHelp); /* close file */
+ HelpDealloc(*pmhFdb); /* deallocate fdb */
+ *pmhFdb = 0;
+ }
+ else
+ PutFdb (*pmhFdb, &fdbLocal); /* update FDB */
+ }
+ }
+ }
+/* end CloseShrink */}
+
+/*** HelpNcCmp - Look up context string, provide comparison routine
+*
+* Given an ascii string, determine the context number of that string. Uses
+* user-supplied comparison routine.
+*
+* Entry:
+* lpszContext - Pointer to asciiz context string.
+* ncInital - Starting Context, used to locate file.
+* lpfnCmp - far pointer to comparison routine to use.
+*
+* Exit:
+* Context number, if found.
+*
+* Exceptions:
+* Returns NULL if context string not found.
+*
+*************************************************************************/
+nc far pascal LOADDS HelpNcCmp (
+char far *fpszContext,
+nc ncInitial,
+f (pascal far *lpfnCmp)(uchar far *, uchar far *, ushort, f, f)
+) {
+f fFound = FALSE; // TRUE -> found
+f fOpened = FALSE; // TRUE -> file was openned here
+fdb fdbLocal; // pointer to current FDB
+char far *fpszT; // temp far pointer
+long i;
+long iStart; // nc to start looking at
+mh mhCur; // memory handle locked
+nc ncRet = {0,0}; // The return value
+char far *fpszContexts; // pointer to context strings
+
+
+// if the context string includes a "filename!", then open that as a help
+// file, and point to the context string which may follow.
+//
+if ((fpszT = hfstrchr(fpszContext,'!')) && (fpszT != fpszContext)) {
+ *fpszT = 0;
+ ncInitial = HelpOpen(fpszContext);
+ *fpszT++ = '!';
+ fpszContext = fpszT;
+ fOpened = TRUE;
+}
+
+// if helpfile was not openned, just return the error
+//
+if (ISERROR(ncInitial)) {
+ ncInitial.mh = (mh)0;
+ ncInitial.cn = 0L;
+ return ncInitial;
+}
+
+// For compressed files we scan the context strings in the file (I know,
+// it's stupid code, but this turns out not to be that speed critical in
+// comparision with decompression, so I haven't bothered), to get the
+// context number.
+//
+// If not found, and there IS a linked (appended) file, we recurse to search
+// that file as well.
+//
+// The context number for compressed files is just the zero based string
+// number, plus the number of predefined contexts, with the fdb memory
+// handle in the upper word.
+//
+if (LoadFdb (ncInitial.mh, &fdbLocal)) {
+ if (fdbLocal.ftype & FTCOMPRESSED) {
+
+ // If not a local context look up, get the context strings, and
+ // search
+ //
+ if (*fpszContext) {
+ mhCur = LoadPortion (HS_CONTEXTSTRINGS, ncInitial.mh);
+ if ( (mhCur == (mh)0)
+ || (mhCur == (mh)(-1))
+ || (!(fpszContexts = HelpLock(mhCur)))
+ ) {
+ ncRet.mh = (mh)0;
+ ncRet.cn = 0L;
+ return ncRet;
+ }
+ i=0;
+
+ // iStart allows us to begin searching from the context string
+ // passed, as opposed to from the begining each time. This
+ // allows the application to "carry on" a search from othe last
+ // place we found a match. This is usefull for multiple
+ // duplicate context resolution, as well as inexact matching.
+ //
+ iStart = ncInitial.cn;
+ if (iStart & 0x8000)
+ iStart = 0;
+ else
+ iStart--; /* table index is 0 based */
+
+ do {
+ if (i >= iStart) {
+ fFound = lpfnCmp ( fpszContext
+ , fpszContexts
+ , 0xffff
+ , (f)(fdbLocal.hdr.wFlags & wfCase)
+ , (f)FALSE);
+ }
+ while (*fpszContexts++); /* point to next string */
+ i++;
+ }
+ while ((i < (int)fdbLocal.hdr.cContexts) && !fFound);
+ HelpUnlock (mhCur);
+
+ if (fFound) { /* if a match found */
+ ncRet.mh = ncInitial.mh;
+ ncRet.cn = i + fdbLocal.hdr.cPreDef;
+ // rjsa ncRet = (i+fdbLocal.hdr.cPreDef) /* string # */
+ // | HIGHONLY(ncInitial); /* & fdb handle */
+ }
+ else {
+ ncInitial.mh = (mh)0;
+ ncInitial.cn = 0L;
+ ncRet = HelpNcCmp (fpszContext,fdbLocal.ncLink, lpfnCmp);
+ }
+ }
+ else if (!fOpened) {
+ ncRet.mh = ncInitial.mh;
+ ncRet.cn = *(UNALIGNED ushort far *)(fpszContext + 1);
+ // rjsa ncRet = *(ushort far *)(fpszContext + 1) /* word following*/
+ // | HIGHONLY(ncInitial); /* & fdb handle */
+ }
+ }
+#if ASCII
+/*
+** For minimally formatted ascii files, we sequentially scan the file itself
+** for context string definitions until we find the string we care about.
+**
+** The context number for minascii files is the the byte position/4 of the
+** beginning of the associated topic, with the fdb memory handle in the upper
+** word.
+*/
+ else if (fdbLocal.ftype & FTFORMATTED) {
+ if (*fpszContext) {
+ ncRet.cn = maLocate(&fdbLocal, fpszContext, 0L, lpfnCmp);
+ if (ncRet.cn == -1L) {
+ ncRet.mh = (mh)0;
+ ncRet.cn = 0L;
+ } else {
+ ncRet = combineNc(ncRet.cn, fdbLocal.ncInit.mh);
+ }
+ // rjsa ncRet = maLocate(&fdbLocal, fpszContext, 0L, lpfnCmp);
+ // ncRet = (ncRet == -1L)
+ // ? 0
+ // : combineNc(ncRet,HIGH(fdbLocal.ncInit));
+ }
+ }
+/*
+** for unformatted ascii files, there must have been NO context string to be
+** searched for. In that case, the context number is always 1, plus the fdb
+** mem handle.
+*/
+ else if (*fpszContext == 0) { /* if null context string */
+ ncRet.mh = ncInitial.mh;
+ ncRet.cn = 1L;
+ // rjsa ncRet = HIGHONLY(ncInitial) + 1;
+ }
+#endif
+}
+
+return ncRet;
+
+/* end HelpNcCmp */}
+
+/*** HelpNc - Look up context string
+*
+* Given an ascii string, determine the context number of that string.
+*
+* Entry:
+* lpszContext - Pointer to asciiz context string.
+* ncInital - Starting Context, used to locate file.
+*
+* Exit:
+* Context number, if found.
+*
+* Exceptions:
+* Returns NULL if context string not found.
+*
+*************************************************************************/
+nc far pascal LOADDS HelpNc (
+char far *fpszContext,
+nc ncInitial
+) {
+return HelpNcCmp (fpszContext, ncInitial, HelpCmp);
+/* end HelpNc */}
+
+
+/*************************************************************************
+**
+** HelpNcCb - Return count of bytes in compressed topic
+**
+** Purpose:
+** Returns the size in bytes of the compressed topic. Provided for
+** applications to determine how big a buffer to allocate.
+**
+** Entry:
+** ncCur - Context number to return info on.
+**
+** Exit:
+** Count of bytes in the compressed topic
+**
+** Exceptions:
+** Returns 0 on error.
+**
+*/
+ushort far pascal LOADDS HelpNcCb (
+nc ncCur
+) {
+ulong position;
+ushort size;
+
+return SizePos(ncCur,&size,&position) ? size+(ushort)4 : (ushort)0;
+
+/* end HelpNcCb */}
+
+/******************************************************************************
+**
+** HelpLook - Return compressed topic text
+**
+** Purpose:
+** Places the compressed topic text referenced by a passed context number into
+** a user supplied buffer.
+**
+** Entry:
+** ncCur - Context number for which to return text
+** pbDest - Pointer to buffer in which to place the result.
+**
+** Exit:
+** Count of bytes in >uncompressed< topic. This is encoded based on file type.
+**
+** Exceptions:
+** Returns NULL on any error
+**
+*/
+ushort far pascal LOADDS HelpLook (
+nc ncCur,
+PB pbDest
+) {
+fdb fdbLocal; /* pointer to current FDB */
+char far *fpszDest;
+int i;
+ulong position = 0;
+ushort size = 0;
+
+if (LoadFdb (ncCur.mh, &fdbLocal)) { /* get fdb down */
+/*
+** for both kinds of formatted files, we determine the position of the topic,
+** and read it in.
+*/
+ if (fdbLocal.ftype) {
+ if (SizePos (ncCur,&size,&position)) {
+ if (fpszDest = (char far *)PBLOCK(pbDest)) {
+
+#ifdef BIGDEBUG
+ {
+ char DbgBuf[128];
+ sprintf(DbgBuf, "HELP: Reading Topic for Context %d at %lX, size %d\n", ncCur.cn, position + fdbLocal.foff, size );
+ OutputDebugString(DbgBuf);
+ }
+#endif
+
+ size = (ushort)ReadHelpFile(fdbLocal.fhHelp
+ ,position + fdbLocal.foff
+ ,fpszDest
+ ,size);
+
+#ifdef BIGDEBUG
+ {
+ char DbgBuf[128];
+ sprintf(DbgBuf, " Read %d bytes to address %lX\n", size, fpszDest );
+ OutputDebugString(DbgBuf);
+ }
+#endif
+/*
+** for compressed files, if the read was sucessfull, we then return the
+** uncompressed size which is the first word of the topic.
+*/
+#if ASCII
+ if (fdbLocal.ftype & FTCOMPRESSED) {
+#endif
+ if (size)
+ size = *(ushort far *)fpszDest+(ushort)1;
+#if ASCII
+ }
+ else {
+/*
+** for minascii files, We also set up for the terminating NULL by scanning for
+** the ">>" which begins the next topic, adjusting the size as well.
+*/
+ size -= 4;
+ for (i=4; i; i--)
+ if (fpszDest[++size] == '>') break;
+ fpszDest[size++] = 0;
+ }
+#endif
+ }
+ }
+ }
+#if ASCII
+ else { /* unformatted ascii */
+/*
+** for unformatted ascii, we just read in (first 64k of) the file.
+*/
+ if (fpszDest = PBLOCK (pbDest)) {
+ if (SizePos (ncCur,&size,&position)) {
+ size = (ushort)ReadHelpFile(fdbLocal.fhHelp,0L,fpszDest,size);
+ fpszDest[size++] = 0; /* terminate ascii text */
+ }
+ }
+ }
+#endif
+ PBUNLOCK (pbDest);
+ }
+if (size) size += sizeof(topichdr); /* adjust for prepended topichdr*/
+return size;
+/* end HelpLook */}
+
+/******************************************************************************
+**
+** HelpDecomp - Decompress Topic Text
+**
+** Purpose:
+** Fully decompress topic text. Decompresses based on current file, from one
+** buffer to another.
+**
+** Entry:
+** pbTopic - Pointer to compressed topic text
+** pbDest - Pointer to destination buffer
+**
+** Exit:
+** FALSE on successful completion
+**
+** Exceptions:
+** Returns TRUE on any error.
+**
+*/
+f far pascal LOADDS HelpDecomp (
+PB pbTopic,
+PB pbDest,
+nc ncContext
+) {
+fdb fdbLocal; // pointer to current FDB
+uchar far *fpszDest; // pointer to destination
+uchar far *fpTopic; // pointer to locked topic
+f fRv = TRUE; // return Value
+mh mhFdb; // handle to the fdb
+mh mhHuff;
+mh mhKey;
+
+mhFdb = ncContext.mh;
+if (LoadFdb (mhFdb, &fdbLocal)) { /* lock fdb down */
+ if (fdbLocal.ftype & FTCOMPRESSED) {
+
+ // This funky sequence of code attempts to ensure that both the
+ // huffman and keyword decompression tables are loaded simultaneously
+ // since we cannot decompress without both.
+ //
+ // We do things three times to cover the following cases:
+ //
+ // 1) huffman loaded ok
+ // keyword loaded ok
+ // huffman already loaded
+ //
+ // 2) huffman loaded ok
+ // keyword loaded ok after HelpShrink (huffman discarded)
+ // huffman re-loaded ok (HelpShrink freed enough for both)
+ //
+ // 3) huffman loaded ok after HelpShrink
+ // keyword loaded ok after HelpShrink (huffman discarded)
+ // huffman re-loaded ok (memory fragmentation allowed it)
+ //
+ // The other cases, where either the load fails immediatly after
+ // any HelpShrink call, are the cases we cannot handle.
+ //
+ // Since handles can change due to the reallocation that can ocurr
+ // in the HelpShrink-reload sequence, we simply do the three
+ // loads, and then ensure that all the handles match what's in the
+ // fdb. If they don't, we fail.
+ //
+ mhHuff = LoadPortion (HS_HUFFTREE,mhFdb);
+ mhKey = LoadPortion (HS_KEYPHRASE,mhFdb);
+ mhHuff = LoadPortion (HS_HUFFTREE,mhFdb);
+
+ if ( LoadFdb (mhFdb, &fdbLocal)
+ && (mhKey == fdbLocal.rgmhSections[HS_KEYPHRASE])
+ && (mhHuff == fdbLocal.rgmhSections[HS_HUFFTREE])) {
+
+ char far *fpHuff;
+ char far *fpKey;
+
+ // At this point we lock EVERYTHING and ensure that we have
+ // valid pointers to it all. (Some swapped memory systems can
+ // fail at this point, so we need to be sensitive).
+ //
+ fpHuff = HelpLock (mhHuff);
+ fpKey = HelpLock (mhKey);
+ fpTopic = PBLOCK (pbTopic);
+ fpszDest = PBLOCK (pbDest);
+
+ if ( fpTopic
+ && fpszDest
+ && (fpHuff || (mhHuff == 0))
+ && (fpKey || (mhKey == 0))
+ ) {
+ decomp (fpHuff, fpKey, fpTopic, fpszDest+sizeof(topichdr));
+ fRv = FALSE;
+ }
+ }
+
+ // Unlock the handles, if they were valid.
+ //
+ if (mhKey != (mh)(-1))
+ HelpUnlock (mhKey);
+ if (mhHuff != (mh)(-1))
+ HelpUnlock (mhHuff);
+ }
+ else {
+ fpszDest = PBLOCK (pbDest);
+#if ASCII
+/*
+** ascii, just copy
+*/
+ fpTopic = PBLOCK(pbTopic);
+ if (fpTopic && fpszDest) {
+ hfstrcpy(fpszDest+sizeof(topichdr),fpTopic);
+#else
+ {
+#endif
+ fRv = FALSE;
+ }
+ }
+ if (!fRv) {
+ ((topichdr far *)fpszDest)->ftype = fdbLocal.ftype;
+ ((topichdr far *)fpszDest)->appChar = (uchar)fdbLocal.hdr.appChar;
+ ((topichdr far *)fpszDest)->linChar = (uchar)fdbLocal.hdr.appChar;
+ ((topichdr far *)fpszDest)->lnCur = 1;
+ ((topichdr far *)fpszDest)->lnOff = sizeof(topichdr);
+ }
+ PBUNLOCK (pbTopic);
+ PBUNLOCK (pbDest);
+ }
+return fRv;
+/* end HelpDecomp */}
+
+/******************************************************************************
+**
+** HelpNcNext - Return next context number
+**
+** Purpose:
+** Returns the context number corresponding to a physical "next" in the help
+** file.
+**
+** Entry:
+** None
+**
+** Exit:
+** Returns context number
+**
+** Exceptions:
+** Returns NULL on any error
+**
+*/
+nc far pascal LOADDS HelpNcNext (
+nc ncCur
+) {
+return NextPrev(ncCur,1); /* get next */
+/* end HelpNcNext */}
+
+/******************************************************************************
+**
+** HelpNcPrev - Return phyiscally previous context
+**
+** Purpose:
+** Returns the context number corresponding to the physically previous topic.
+**
+** Entry:
+** None
+**
+** Exit:
+** Returns context number
+**
+** Exceptions:
+** Returns NULL on any error
+**
+*/
+nc far pascal LOADDS HelpNcPrev (
+nc ncCur
+) {
+return NextPrev(ncCur,-1); /* get previous */
+/* end HelpNcPrev */}
+
+/******************************************************************************
+**
+** HelpNcUniq - Return nc guaranteed unique for a given topic
+**
+** Purpose:
+** Maps a context number to a local context number. This is provided such
+** that all context numbers which map to the same topic can be transformed
+** into the same nc which maps to that topic. The information on the
+** context string originally used is lost.
+**
+** Entry:
+** None
+**
+** Exit:
+** Returns context number
+**
+** Exceptions:
+** Returns NULL on any error
+**
+*/
+nc far pascal LOADDS HelpNcUniq (
+nc ncCur
+) {
+fdb fdbLocal; /* pointer to current FDB */
+
+if (LoadFdb (ncCur.mh, &fdbLocal))
+ if (fdbLocal.ftype & FTCOMPRESSED) {
+ nc ncTmp;
+
+ ncTmp.mh = fdbLocal.ncInit.mh;
+ ncTmp.cn = MapContexttoTopic(ncCur, &fdbLocal);
+ ncTmp.cn |= 0x8000;
+
+ ncCur = ncTmp;
+
+ // rjsa return MapContexttoTopic (ncCur,&fdbLocal)
+ // | (fdbLocal.ncInit & 0xffff0000)
+ // | 0x8000;
+
+ }
+return ncCur;
+/* end HelpNcUniq */}
+
+/******************************************************************************
+**
+** NextPrev - Return phyiscally next or previous context
+**
+** Purpose:
+** Returns the context number corresponding to the physically next or previous
+** topic.
+**
+** Entry:
+** ncCur = Current Context
+** fNext = 1 for next, -1 for previous.
+**
+** Exit:
+** Returns context number
+**
+** Exceptions:
+** Returns NULL on any error
+**
+*/
+nc pascal near NextPrev (
+ nc ncCur,
+ int fNext
+ ) {
+
+ fdb fdbLocal; /* pointer to current FDB */
+ REGISTER nc ncNext = {0,0};
+
+ if (LoadFdb (ncCur.mh, &fdbLocal)) {
+
+ //
+ // For a compressed file the next/previous physical is computed by taking the
+ // context number, mapping it to its corresponding topic number, incrementing
+ // or decrementing the topic number (remember, topic numbers are in physical
+ // order), and then mapping that back to a context number.
+ //
+ // When nexting, we also support nexting into any appended file.
+ //
+ if (fdbLocal.ftype & FTCOMPRESSED) {
+ unsigned short cn;
+
+ cn = (ushort)(((ncCur.cn & 0x8000)
+ ? ncCur.cn & 0x7ffff
+ : MapContexttoTopic(ncCur, &fdbLocal))
+ + (ushort)fNext);
+
+ ncNext = MapTopictoContext(cn, (fdb far *)&fdbLocal, fNext);
+
+ // rjsa ncNext = MapTopictoContext((ushort)(((ncCur & 0x8000)
+ // ? ncCur & 0x7fff
+ // : MapContexttoTopic (ncCur,&fdbLocal))
+ // + fNext)
+ // ,(fdb far *)&fdbLocal);
+
+ //
+ // if we could not come up with a next, try to find a next using "local"
+ // context numbers. Map the context number to a topic number, and if that is
+ // not out of range, return it as a context.
+ //
+ if (!(ncNext.cn)) {
+
+ // rjsa if ((ncNext = MapContexttoTopic (ncCur,&fdbLocal)) == 0xffff)
+ // ncNext = 0;
+ ncNext.cn = MapContexttoTopic(ncCur, &fdbLocal);
+
+ if (ncNext.cn == 0xffff) {
+
+ ncNext.mh = (mh)0;
+ ncNext.cn = 0L;
+
+ } else {
+
+ ncNext.cn += fNext;
+
+ if (ncNext.cn >= fdbLocal.hdr.cTopics) {
+
+ ncNext.mh = (mh)0;
+ ncNext.cn = 0L;
+
+ } else {
+
+ // rjsa ncNext |= (fdbLocal.ncInit & 0xffff0000) | 0x8000;
+ ncNext.mh = fdbLocal.ncInit.mh;
+ ncNext.cn = 0x8000;
+ }
+ }
+ }
+
+ if (!(ncNext.cn & 0x7fff) && (fNext>0)) {
+ ncNext = fdbLocal.ncLink;
+ }
+ }
+
+#if ASCII
+
+ //
+ // minascii files:
+ // next'ing: we just sequentially search the file for the first context to
+ // come along after that pointed to by our current context number.
+ //
+ else if (fdbLocal.ftype & FTFORMATTED) {
+
+ if (fNext > 0) {
+
+ ncNext.cn = maLocate(&fdbLocal,szNil,NctoFo(ncCur.cn)+4, HelpCmp);
+ if (ncNext.cn == -1L) {
+ ncNext.mh = (mh)0;
+ ncNext.cn = 0L;
+ } else {
+ ncNext = combineNc(ncNext.cn, ncCur.mh);
+ }
+ // rjsa ncNext = (ncNext == -1L)
+ // ? 0
+ // : combineNc(ncNext,HIGH(ncCur));
+
+ } else {
+
+ nc ncTemp;
+
+ //
+ // prev'ing: start at the begining of the file, looking for the last context
+ // which is less than the current one.
+ //
+
+ ncNext = ncTemp = fdbLocal.ncInit;
+ while (NctoFo(ncTemp.cn) < NctoFo(ncCur.cn)) {
+ ncNext = ncTemp;
+ ncTemp.cn = maLocate(&fdbLocal,szNil,NctoFo(ncTemp.cn)+4, HelpCmp);
+
+ if (ncTemp.cn == -1L) {
+ ncTemp.mh = (mh)0;
+ ncTemp.cn = 0L;
+ } else {
+ ncTemp = combineNc(ncTemp.cn,fdbLocal.ncInit.mh);
+ }
+ // rjsa ncTemp = (ncTemp == -1L)
+ // ? 0
+ // : combineNc(ncTemp,HIGH(fdbLocal.ncInit));
+ }
+ }
+ }
+#endif
+ }
+ return ncNext;
+}
+
+/*************************************************************************
+**
+** HelpSzContext - Return string mapping to context number
+**
+** Purpose:
+** Construct a string, which when looked-up, will return the passed context
+** number.
+**
+** Entry:
+** pBuf = place to put the string
+** ncCur = The context number desired
+**
+** Exit:
+** True on sucess.
+**
+*/
+f pascal far LOADDS HelpSzContext (
+uchar far *pBuf,
+nc ncCur
+) {
+f fRet = FALSE; /* return value */
+ulong i;
+fdb fdbLocal; /* pointer to current FDB */
+mh mhCur; /* handle we're dealing with */
+char far *fpszContexts; /* pointer to context strings */
+
+*pBuf = 0;
+if (LoadFdb (ncCur.mh, &fdbLocal)) { /* lock fdb down */
+/*
+** Everybody starts with a filename
+*/
+ if (*fdbLocal.hdr.fname)
+ pBuf = hfstrcpy(pBuf,fdbLocal.hdr.fname);
+ else
+ pBuf = hfstrcpy(pBuf,fdbLocal.fname);
+ *(ushort far *)pBuf = '!'; /* includes null term */
+ pBuf++;
+ fRet = TRUE;
+
+ // if we've been given a local context number, see if we can synthesize
+ // a context number from which we might get a string. If we can't get
+ // one, then return just the filename.
+ //
+ if ((i = ncCur.cn) & 0x8000) { /* context # */
+ ncCur = MapTopictoContext ((ushort)(ncCur.cn & 0x7fff),&fdbLocal,0);
+ if ((i = ncCur.cn) & 0x8000) /* context # */
+ return fRet;
+ }
+/*
+** For compressed files (signified by being able to load context strings) we
+** just walk the context strings looking for string number "ncCur". Once found,
+** the returned string is just the concatenated filename, "!" and context
+** string.
+*/
+ mhCur = LoadPortion(HS_CONTEXTSTRINGS, ncCur.mh);
+ if (mhCur && (mhCur != (mh)(-1)) && (fpszContexts = HelpLock(mhCur))) {
+ if (i && (i <= fdbLocal.hdr.cContexts)) {
+ while (--i)
+ while (*fpszContexts++);/* point to next string */
+ hfstrcpy(pBuf,fpszContexts);/* copy over */
+ }
+ HelpUnlock (mhCur);
+ }
+ else if (fdbLocal.ftype & FTCOMPRESSED)
+ return FALSE;
+#if ASCII
+/*
+** for min ascii files, we search for the topic, and copy over the context
+** string directly from the file.
+*/
+ else if (fdbLocal.ftype & FTFORMATTED) {
+ long fpos;
+
+ if ((fpos = maLocate(&fdbLocal,szNil,NctoFo(ncCur.cn)-1,HelpCmp)) != -1L) {
+ fpos = ReadHelpFile(fdbLocal.fhHelp,fpos+2,pBuf,80);
+ *(pBuf+fpos) = 0; /* ensure terminated */
+ if (pBuf = hfstrchr(pBuf,'\r'))
+ *pBuf = 0; /* terminate at CR */
+ }
+ }
+#endif
+ }
+return fRet;
+/* end HelpSzContext */}
+
+/******************************************************************************
+**
+** LoadPortion - Load a section of the help file
+**
+** Purpose:
+** If not loaded, allocates memory for and loads a section (as defined in
+** helpfile.h) of the current help file. Once loaded, or if already loaded,
+** locks it, and returns the the memory handle and pointer.
+**
+** This routine must be far, since it is an entry point for HelpMake
+**
+** Entry:
+** hsCur = Help section to be loaded.
+** mhfdb = memory handle for fdb
+**
+** Exit:
+** returns handle for memory
+**
+** Exceptions:
+** returns NULL on portion not existing, 0xffff on inability to allocate memory.
+**
+*/
+mh pascal near LoadPortion (
+int hsCur,
+mh mhfdb
+) {
+fdb fdbLocal;
+char far *fpDest = 0;
+int i;
+mh mhNew = 0; /* pointer to mh destination */
+ushort osize; /* additional prepended size */
+ushort size;
+
+if (LoadFdb (mhfdb, &fdbLocal)) {
+ if (((mhNew = fdbLocal.rgmhSections[hsCur]) == 0)
+ && fdbLocal.hdr.tbPos[hsCur]) {
+
+ for (i=hsCur+1; i<HS_count; i++)
+ if (fdbLocal.hdr.tbPos[i]) {
+ size = (ushort)(fdbLocal.hdr.tbPos[i]-fdbLocal.hdr.tbPos[hsCur]);
+ break;
+ }
+
+ osize = (hsCur == HS_KEYPHRASE) ? 1024*sizeof(PVOID) : 0;
+/*
+** Alloc the memory required. Re-read the FDB, incase intervening calls to
+** HelpShrink causes deallocs of other beasties.
+*/
+ if ( (mhNew = HelpAlloc(size + osize))
+ && LoadFdb (mhfdb, &fdbLocal)) {
+ fdbLocal.rgmhSections[hsCur] = mhNew;
+ if (PutFdb (mhfdb, &fdbLocal)) {
+ fpDest = (char far *)HelpLock(mhNew);
+ if (fpDest && ReadHelpFile(fdbLocal.fhHelp
+ ,(ulong)fdbLocal.hdr.tbPos[hsCur] + fdbLocal.foff
+ ,fpDest + osize
+ ,size)) {
+
+ if (hsCur == HS_KEYPHRASE)
+ kwPtrBuild(fpDest,size);/* build keyword pointers */
+ HelpUnlock (mhNew);
+ }
+ else {
+ fdbLocal.rgmhSections[hsCur] = 0;
+ HelpDealloc (mhNew);
+ PutFdb (mhfdb, &fdbLocal);
+ mhNew = (mh)(-1);
+ }
+ }
+ else
+ mhNew = (mh)0;
+ }
+ else
+ mhNew = (mh)(-1);
+ }
+ }
+
+return mhNew;
+
+/* end LoadPortion */}
+
+/*************************************************************************
+**
+** SizePos - Return count of bytes in compressed topic, and position
+**
+** Purpose:
+** Returns the size in bytes of the compressed topic, and it's location in the
+** help file.
+**
+** Entry:
+** ncCur - Context number to return info on.
+** psize - Pointer to place to put the size
+** ppos - Pointer to place to put the position
+**
+** Exit:
+** Returns TRUE on success.
+**
+** Exceptions:
+** Returns FALSE on all errors.
+**
+** Algorithm:
+**
+** If current help handle valid
+** If filetype is compressed
+** If context map not loaded, load it
+** Lock context map
+** Map context to topic number
+** Unlock context map
+** If topic index not loaded, load it
+** Lock topic index
+** size is difference in file positions
+** Unlock topic index
+** else if filetype is formatted ascii
+** seek to context file position
+** scan for next context definition
+** size is difference in file positions
+** else if filetype is unformatted ascii
+** size is filesize
+*/
+f pascal near SizePos (
+nc ncCur,
+ushort *psize,
+ulong *ppos
+) {
+fdb fdbLocal; /* pointer to current FDB */
+char far *fpT; /* temp pointer */
+REGISTER f fRv = FALSE; /* return value */
+ushort iTopic; /* topic index */
+mh mhCur; /* handle being locked */
+
+if (LoadFdb (ncCur.mh, &fdbLocal)) { /* get fdb copy */
+ if (fdbLocal.ftype & FTCOMPRESSED) {/* if a standard compressed file*/
+ if ((iTopic = MapContexttoTopic (ncCur,&fdbLocal)) != 0xffff) {
+ mhCur = LoadPortion(HS_INDEX,ncCur.mh);
+ if (mhCur && (mhCur != (mh)(-1)) && (fpT = HelpLock(mhCur))) {
+ *ppos = ((long far *)fpT)[iTopic];
+ *psize = (ushort)(((long far *)fpT)[iTopic+1] - *ppos);
+ HelpUnlock (mhCur);
+ fRv = TRUE;
+ }
+ }
+ }
+
+#if ASCII
+ else if (fdbLocal.ftype & FTFORMATTED) {/* if a formatted ascii file*/
+ if ((*psize = (ushort)(maLocate(&fdbLocal, szNil, NctoFo(ncCur.cn)+4, HelpCmp)))
+ == 0xffff)
+ *psize = (ushort)ReadHelpFile(fdbLocal.fhHelp,0L,NULL,0);
+ else
+ *psize -= (ushort)NctoFo(ncCur.cn);
+ *ppos = (ulong) maLocate(&fdbLocal, szNil, NctoFo(ncCur.cn)-1, HelpCmp);
+ fRv = TRUE;
+ }
+ else { /* unformatted ascii */
+ *ppos = ReadHelpFile(fdbLocal.fhHelp,0L,NULL,0);
+ *psize = (*ppos > (ulong)(65535-sizeof(topichdr)-4))
+ ? (ushort)(65535-sizeof(topichdr)-4)
+ : (ushort)*ppos;
+ *ppos = 0L; /* position is always zero. */
+ fRv = TRUE;
+ }
+#endif
+ }
+
+return fRv;
+/* end SizePos */}
+
+/************************************************************************
+**
+** MapContexttoTopic
+**
+** Purpose:
+** Given a context number, return the topic number which it maps to. This
+** is just a direct index of the context number into the context map.
+**
+** Entry:
+** ncCur = context number to be mapped
+** fpfdbCur = pointer to associated fdb
+**
+** Exit:
+** Returns zero based topic number, or 0xffff on error.
+*/
+ushort pascal near MapContexttoTopic (
+nc ncCur, /* context number to map */
+fdb far *fpfdbCur /* pointer to current FDB */
+) {
+REGISTER ushort topic = 0xffff; /* value to return */
+ushort far *fpT; /* pointer to context map */
+mh mhCur; /* handle being locked */
+
+if (ncCur.cn) {
+/*
+** Local contexts: the topic number is already encoded in the low word, if the
+** high bit of that word is set.
+*/
+ if (ncCur.cn & 0x8000)
+ topic = (ushort)(ncCur.cn & 0x7fff);
+/*
+** Normal Contexts: low word of nc is an index into the context map which
+** returns the topic number
+*/
+ else {
+ mhCur = LoadPortion(HS_CONTEXTMAP,fpfdbCur->ncInit.mh);
+ if (mhCur && (mhCur != (mh)(-1)) && (fpT = HelpLock(mhCur))) {
+ topic = fpT[ncCur.cn-1];
+ HelpUnlock (mhCur);
+ }
+ }
+ }
+return topic;
+/* end MapContexttoTopic */}
+
+/************************************************************************
+**
+** MapTopictoContext
+**
+** Purpose:
+** Given a topic number, return a context which maps to it.
+**
+** This involves searching the context map for the first context entry that
+** maps to the desired topic number.
+**
+** Entry:
+** iTopic = topic number to map back to a context number
+** fpfdbCur = pointer to associated fdb
+**
+** Exit:
+** Returns a valid nc into the file.
+**
+** Exceptions:
+** If the incoming iTopic is invalid, or a read error occurs, then the nc
+** returned refers to the topic number 0.
+**
+*/
+nc pascal near MapTopictoContext(
+ushort iTopic, /* topic number to map */
+fdb far *fpfdbCur, /* pointer to current FDB */
+int Dir
+) {
+ ushort cTopics; /* number of topics to search */
+ ushort far *fpContextMap; /* pointer to the context map */
+ mh mhPortion; /* mem handle for the context map*/
+ nc ncMatch = {0,0}; /* return value */
+
+ mhPortion = LoadPortion (HS_CONTEXTMAP,fpfdbCur->ncInit.mh);
+ if (mhPortion && (mhPortion != (mh)(-1))) {
+ if (fpContextMap = HelpLock(mhPortion)) {
+ if (iTopic >= fpfdbCur->hdr.cTopics) {
+ iTopic = 0;
+ }
+ ncMatch.mh = (mh)0L;
+ ncMatch.cn = 0x8000 | iTopic;
+ // rjsa ncMatch = 0x8000 | iTopic;
+ cTopics = 0;
+ while (cTopics < fpfdbCur->hdr.cContexts) {
+ if ( Dir == 0 ) {
+ if (iTopic == fpContextMap[cTopics++]) {
+ ncMatch.cn = cTopics; /* nc's are one based */
+ break;
+ }
+ } else if ( Dir > 0 ) {
+ if (iTopic <= fpContextMap[cTopics++]) {
+ ncMatch.cn = cTopics; /* nc's are one based */
+ break;
+ }
+
+ } else if ( Dir < 0 ) {
+
+ if (iTopic == fpContextMap[cTopics++]) {
+ ncMatch.cn = cTopics;
+ break;
+ } else if (iTopic < fpContextMap[cTopics-1]) {
+ ncMatch.cn = cTopics-1;
+ break;
+ }
+ }
+ }
+ //if ( iTopic != fpContextMap[cTopics-1] ) {
+ // ncMatch.cn = 0;
+ //}
+ if ( cTopics >= fpfdbCur->hdr.cContexts) {
+ ncMatch.cn = 0;
+ }
+ HelpUnlock (mhPortion);
+ }
+ }
+ ncMatch.mh = (fpfdbCur->ncInit).mh;
+ return ncMatch;
+ // rjsa return ncMatch | HIGHONLY(fpfdbCur->ncInit);
+}
+
+/************************************************************************
+**
+** LoadFdb - make local copy of fdb.
+**
+** Purpose:
+** Used to create a local copy of an FDB, so that we don't have to keep a
+** locked, far copy around.
+**
+** Entry:
+** mhFdb - memory handle for the FDB
+** fpFdbDest - Pointer to destination for FDB copy
+**
+** Exit:
+** returns TRUE if FDB copied.
+*/
+f pascal near LoadFdb (
+mh mhfdb,
+fdb far *fpfdbDest
+) {
+fdb far *fpfdbCur; /* pointer to current FDB */
+
+if (fpfdbCur = HelpLock (mhfdb)) {
+ *fpfdbDest = *fpfdbCur;
+ HelpUnlock (mhfdb);
+ return TRUE;
+ }
+return FALSE;
+/* end LoadFdb */}
+
+/************************************************************************
+**
+** PutFdb - make local copy of fdb permanent.
+**
+** Purpose:
+** Used to copy a local copy of an FDB to the "real" one, so that we don't
+** have to keep a locked, far copy around.
+**
+** Entry:
+** mhFdb - memory handle for the FDB
+** fpfdbSrc - Pointer to source of FDB copy
+**
+** Exit:
+** returns TRUE if FDB copied.
+*/
+f pascal near PutFdb (
+mh mhfdb,
+fdb far *fpfdbSrc
+) {
+fdb far *fpfdbCur; /* pointer to current FDB */
+
+if (fpfdbCur = HelpLock (mhfdb)) {
+ *fpfdbCur = *fpfdbSrc;
+ HelpUnlock (mhfdb);
+ return TRUE;
+ }
+return FALSE;
+/* end PutFdb */}
+
+#if ASCII
+/************************************************************************
+**
+** maLocate - Locate context in minimally formatted ascii file.
+**
+** Purpose:
+** Performs sequential searches on mimimally formatted ascii files to locate
+** lines beginning with ">>" and a context string.
+**
+** Entry:
+** fpfdbCur = Pointer to current fdb
+** fpszSrc = Pointer to context string to be found (or null for next
+** string)
+** offset = offset at which to begin search.
+** lpfnCMp = pointer to comparison routine to use
+**
+** Exit:
+** returns file offset of ">>" of context string.
+**
+** Exceptions:
+** returns -1 on error.
+**
+*/
+long pascal near maLocate (
+fdb far *fpfdbCur,
+uchar far *fpszSrc,
+ulong offset,
+f (pascal far *lpfnCmp)(uchar far *, uchar far *, ushort, f, f)
+) {
+uchar buffer[MASIZE+1]; /* input buffer */
+ushort cbBuf = 0; /* count of bytes in buffer */
+ushort cbSrc; /* length of source string */
+uchar far *pBuf; /* pointer into buffer */
+uchar far *pBufT; /* temp pointer into buffer */
+
+cbSrc = hfstrlen(fpszSrc)+1; /* get length of input */
+if (offset == 0xffffffff) /* special case */
+ offset = 0;
+while (cbBuf += (ushort)ReadHelpFile(fpfdbCur->fhHelp
+ , offset+cbBuf
+ , buffer+cbBuf
+ , MASIZE-cbBuf)) {
+
+ buffer[cbBuf] = 0; /* ensure strings terminated */
+ pBuf = &buffer[0];
+ while (pBuf = hfstrchr(pBuf,'>')) { /* look for start of context */
+ if ((*(pBuf+1) == '>') /* if >> found */
+ && ((*(pBuf-1) == '\n') /* at beginning of line */
+ || ((offset == 0) /* or beginning of file */
+ && (pBuf == (char far *)&buffer[0])))) {
+ pBufT = pBuf +2;
+ if (lpfnCmp (fpszSrc, pBufT, cbSrc, FALSE, TRUE))
+ return offset + (ulong)(pBuf - (uchar far *)&buffer[0]);
+ }
+ pBuf += 2;
+ }
+ if (cbBuf == MASIZE) { /* if buffer full */
+ hfstrcpy(buffer,buffer+MASIZE-MAOVER); /* copy down overlap */
+ cbBuf = MAOVER; /* and leave that in */
+ offset += MASIZE-MAOVER; /* file pos of buffer[0] */
+ }
+ else {
+ offset += cbBuf;
+ cbBuf = 0; /* else we're empty */
+ }
+ }
+return -1;
+
+/* end maLocate */}
+#endif
diff --git a/private/utils/mep/help/mshelp/makefile b/private/utils/mep/help/mshelp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/mep/help/mshelp/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/mep/help/mshelp/mshelp.def b/private/utils/mep/help/mshelp/mshelp.def
new file mode 100644
index 000000000..8686b0eaa
--- /dev/null
+++ b/private/utils/mep/help/mshelp/mshelp.def
@@ -0,0 +1,29 @@
+LIBRARY MSHELP
+
+DESCRIPTION 'Help engine'
+
+EXPORTS
+ HelpcLines
+ HelpClose
+ HelpCtl
+ HelpDecomp
+ HelpGetCells
+ HelpGetInfo
+ HelpGetLine
+ HelpGetLineAttr
+ HelpHlNext
+ HelpLook
+ HelpNc
+ HelpNcBack
+ HelpNcCb
+ HelpNcCmp
+ HelpNcNext
+ HelpNcPrev
+ HelpNcRecord
+ HelpNcUniq
+ HelpOpen
+ HelpShrink
+ HelpSzContext
+ HelpXRef
+ LoadFdb
+ LoadPortion
diff --git a/private/utils/mep/help/mshelp/mshelp.rc b/private/utils/mep/help/mshelp/mshelp.rc
new file mode 100644
index 000000000..039e42627
--- /dev/null
+++ b/private/utils/mep/help/mshelp/mshelp.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "MS Help Utility DLL"
+#define VER_INTERNALNAME_STR "mshelp"
+#define VER_ORIGINALNAME_STR "MSHELP.DLL"
+
+#include "common.ver"
diff --git a/private/utils/mep/help/mshelp/mshelp1.def b/private/utils/mep/help/mshelp/mshelp1.def
new file mode 100644
index 000000000..d06263f3a
--- /dev/null
+++ b/private/utils/mep/help/mshelp/mshelp1.def
@@ -0,0 +1,29 @@
+LIBRARY MSHELP1
+
+DESCRIPTION 'Help engine'
+
+EXPORTS
+ _HelpcLines
+ _HelpClose
+ _HelpCtl
+ _HelpDecomp
+ _HelpGetCells
+ _HelpGetInfo
+ _HelpGetLine
+ _HelpGetLineAttr
+ _HelpHlNext
+ _HelpLook
+ _HelpNc
+ _HelpNcBack
+ _HelpNcCb
+ _HelpNcCmp
+ _HelpNcNext
+ _HelpNcPrev
+ _HelpNcRecord
+ _HelpNcUniq
+ _HelpOpen
+ _HelpShrink
+ _HelpSzContext
+ _HelpXRef
+ _LoadFdb
+ _LoadPortion
diff --git a/private/utils/mep/help/mshelp/sources b/private/utils/mep/help/mshelp/sources
new file mode 100644
index 000000000..f99b23b8c
--- /dev/null
+++ b/private/utils/mep/help/mshelp/sources
@@ -0,0 +1,24 @@
+MAJORCOMP=utils
+MINORCOMP=mshelp
+
+TARGETNAME=mshelp
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+
+SYNCHRONIZE_DRAIN=1
+
+# TARGETLIBS=..\enginlib\obj\*\engine.lib \nt\public\sdk\lib\*\kernel32.lib \nt\public\sdk\lib\*\crt.lib
+LINKLIBS=..\enginlib\obj\*\engine.lib
+TARGETLIBS=\nt\public\sdk\lib\*\kernel32.lib \
+ \nt\private\sdktools\ztools\src\obj\*\ztools.lib \
+ \nt\public\sdk\lib\*\user32.lib
+
+INCLUDES=.;..\inc;
+
+SOURCES= help.c mshelp.rc
+
+
+C_DEFINES=-D_OS2_20_=0 -DNO_EXT_KEYS -Dpascal= -Dfar= -DNOLANMAN -DNT
+UMTYPE=console
+UMRES=obj\*\mshelp.res
+USE_CRTDLL=1
diff --git a/private/utils/mep/inc/cmds.h b/private/utils/mep/inc/cmds.h
new file mode 100644
index 000000000..1ec6db7d0
--- /dev/null
+++ b/private/utils/mep/inc/cmds.h
@@ -0,0 +1,117 @@
+/*** CMDS.H
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Purpose:
+*
+* Revision History:
+*
+* 18-Aug-1988 bw Initial version, stripped from KEY.C and KEYCW.C
+* 07-Sep-1988 bw Add RECORD_PLAYBACK stuff
+* 26-Sep-1988 bp Add <topfile>, <endfile> and <message>
+* 26-Sep-1988 bp Modified syntax (1+x vs x+1) to reduce nesting in macro expansion
+* 11-Oct-1988 bw Add <selcur> to CW version
+* 17-Oct-1988 bw Add <record>
+* 14-Oct-1988 ln Add <nextmsg>
+* 18-Oct-1988 bw Add <tell>
+* 18-Oct-1988 ln Add <debugmode>
+* 24-Oct-1988 bw Add <noedit>
+* 24-Oct-1988 bw Add <lastselect>
+* 26-Oct-1988 bp Add <print>
+* 27-Oct-1988 bp Change <topfile> to <begfile>
+* 21-Nov-1988 bp Add <saveall>
+* 01-Dec-1988 bw Add <resize>
+* 10-Dec-1988 bp Add <repeat>
+* 14-Dec-1988 ln Add <mgrep>
+* 16-Dec-1988 ln Add <mreplace>
+* 04-Jan-1989 bp Add <menukey>
+* 11-Jan-1989 ln Zoom->maximize
+* 17-Jan-1989 bw Add <selmode> in CW version
+* 30-Jan-1989 bw Remove <dumpscreen> (replaced with ScrollLock Key)
+* 15-Feb-1989 bp Add <prompt>
+*
+* WARNING -- it is important that the ordering here reflects EXACTLY the
+* ordering in the cmdDesc table in table.c
+*
+*************************************************************************/
+
+
+#define CMD_doarg (PCMD)&cmdTable[0]
+#define CMD_assign 1 + CMD_doarg
+#define CMD_backtab 2 + CMD_doarg
+#define CMD_begfile 3 + CMD_doarg
+#define CMD_begline 4 + CMD_doarg
+#define CMD_boxstream 5 + CMD_doarg
+#define CMD_cancel 6 + CMD_doarg
+#define CMD_cdelete 7 + CMD_doarg
+#define CMD_compile 8 + CMD_doarg
+#define CMD_zpick 9 + CMD_doarg
+#define CMD_curdate 10 + CMD_doarg
+#define CMD_curday 11 + CMD_doarg
+#define CMD_curtime 12 + CMD_doarg
+#define CMD_delete 13 + CMD_doarg
+#define CMD_down 14 + CMD_doarg
+#define CMD_emacscdel 15 + CMD_doarg
+#define CMD_emacsnewl 16 + CMD_doarg
+#define CMD_endfile 17 + CMD_doarg
+#define CMD_endline 18 + CMD_doarg
+#define CMD_environment 19 + CMD_doarg
+#define CMD_zexecute 20 + CMD_doarg
+#define CMD_zexit 21 + CMD_doarg
+#define CMD_graphic 22 + CMD_doarg
+#define CMD_home 23 + CMD_doarg
+#define CMD_information 24 + CMD_doarg
+#define CMD_zinit 25 + CMD_doarg
+#define CMD_insert 26 + CMD_doarg
+#define CMD_insertmode 27 + CMD_doarg
+#define CMD_lastselect 28 + CMD_doarg
+#define CMD_textarg 29 + CMD_doarg
+#define CMD_ldelete 30 + CMD_doarg
+#define CMD_left 31 + CMD_doarg
+#define CMD_linsert 32 + CMD_doarg
+#define CMD_mark 33 + CMD_doarg
+#define CMD_message 34 + CMD_doarg
+#define CMD_meta 35 + CMD_doarg
+#define CMD_mgrep 36 + CMD_doarg
+#define CMD_mlines 37 + CMD_doarg
+#define CMD_mpage 38 + CMD_doarg
+#define CMD_mpara 39 + CMD_doarg
+#define CMD_mreplace 40 + CMD_doarg
+#define CMD_msearch 41 + CMD_doarg
+#define CMD_mword 42 + CMD_doarg
+#define CMD_newline 43 + CMD_doarg
+#define CMD_nextmsg 44 + CMD_doarg
+#define CMD_noedit 45 + CMD_doarg
+#define CMD_noop 46 + CMD_doarg
+#define CMD_put 47 + CMD_doarg
+#define CMD_pbal 48 + CMD_doarg
+#define CMD_plines 49 + CMD_doarg
+#define CMD_ppage 50 + CMD_doarg
+#define CMD_ppara 51 + CMD_doarg
+#define CMD_zprint 52 + CMD_doarg
+#define CMD_prompt 53 + CMD_doarg
+#define CMD_psearch 54 + CMD_doarg
+#define CMD_pword 55 + CMD_doarg
+#define CMD_qreplace 56 + CMD_doarg
+#define CMD_quote 57 + CMD_doarg
+#define CMD_record 58 + CMD_doarg
+#define CMD_refresh 59 + CMD_doarg
+#define CMD_repeat 60 + CMD_doarg
+#define CMD_replace 61 + CMD_doarg
+#define CMD_restcur 62 + CMD_doarg
+#define CMD_right 63 + CMD_doarg
+#define CMD_saveall 64 + CMD_doarg
+#define CMD_savecur 65 + CMD_doarg
+#define CMD_savetmp 66 + CMD_doarg
+#define CMD_sdelete 67 + CMD_doarg
+#define CMD_searchall 68 + CMD_doarg
+#define CMD_setfile 69 + CMD_doarg
+#define CMD_setwindow 70 + CMD_doarg
+#define CMD_zspawn 71 + CMD_doarg
+#define CMD_sinsert 72 + CMD_doarg
+#define CMD_tab 73 + CMD_doarg
+#define CMD_tell 74 + CMD_doarg
+#define CMD_unassigned 75 + CMD_doarg
+#define CMD_undo 76 + CMD_doarg
+#define CMD_up 77 + CMD_doarg
+#define CMD_window 78 + CMD_doarg
diff --git a/private/utils/mep/inc/console.h b/private/utils/mep/inc/console.h
new file mode 100644
index 000000000..0794ea651
--- /dev/null
+++ b/private/utils/mep/inc/console.h
@@ -0,0 +1,262 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ console.h
+
+Abstract:
+
+ Interface to the console-management functions for Win32 applications.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 30-Nov-1990
+
+
+Revision History:
+
+
+--*/
+
+
+
+
+//
+// Some common typedefs...
+//
+typedef ULONG ROW, *PROW; // row
+typedef ULONG COLUMN, *PCOLUMN; // column
+typedef DWORD KBDMODE, *PKBDMODE; // Keyboard mode
+typedef DWORD ATTRIBUTE, *PATTRIBUTE; // Screen Attribute
+typedef PVOID PSCREEN; // The screen
+
+
+
+//
+// Console Input Mode flags. They are the same as the NT flags
+//
+#define CONS_ENABLE_LINE_INPUT ENABLE_LINE_INPUT
+#define CONS_ENABLE_PROCESSED_INPUT ENABLE_PROCESSED_INPUT
+#define CONS_ENABLE_ECHO_INPUT ENABLE_ECHO_INPUT
+#define CONS_ENABLE_WINDOW_INPUT ENABLE_WINDOW_INPUT
+#define CONS_ENABLE_MOUSE_INPUT ENABLE_MOUSE_INPUT
+
+//
+// Cursor styles
+//
+#define CURSOR_STYLE_UNDERSCORE 0
+#define CURSOR_STYLE_BOX 1
+
+
+//
+// The information about a screen is retrieved in the following
+// structure:
+//
+typedef struct SCREEN_INFORMATION {
+ ROW NumberOfRows; // Number of rows
+ COLUMN NumberOfCols; // Number of columns
+ ROW CursorRow; // Cursor row position
+ COLUMN CursorCol; // Cursor column position
+} SCREEN_INFORMATION, *PSCREEN_INFORMATION;
+
+
+
+
+//
+// The information about each keystroke is returned in
+// the KBDKEY structure.
+//
+typedef struct KBDKEY {
+ WORD Unicode; // character unicode
+ WORD Scancode; // key scan code
+ DWORD Flags; // keyboard state flags
+} KBDKEY, *PKBDKEY;
+
+//
+// The following macros access particular fields within the
+// KBDKEY structure. They exist to facilitate porting of OS/2
+// programs.
+//
+#define KBDKEY_ASCII(k) (UCHAR)((k).Unicode)
+#define KBDKEY_SCAN(k) ((k).Scancode)
+#define KBDKEY_FLAGS(k) ((k).Flags)
+
+
+#define NEXT_EVENT_NONE 0
+#define NEXT_EVENT_KEY 1
+#define NEXT_EVENT_WINDOW 2
+
+//
+// ControlKeyState flags. They are the same as the NT status flags.
+//
+#define CONS_RIGHT_ALT_PRESSED RIGHT_ALT_PRESSED
+#define CONS_LEFT_ALT_PRESSED LEFT_ALT_PRESSED
+#define CONS_RIGHT_CTRL_PRESSED RIGHT_CTRL_PRESSED
+#define CONS_LEFT_CTRL_PRESSED LEFT_CTRL_PRESSED
+#define CONS_SHIFT_PRESSED SHIFT_PRESSED
+#define CONS_NUMLOCK_PRESSED NUMLOCK_ON
+#define CONS_SCROLLLOCK_PRESSED SCROLLLOCK_ON
+#define CONS_CAPSLOCK_PRESSED CAPSLOCK_ON
+#define CONS_ENHANCED_KEY ENHANCED_KEY
+
+
+
+
+
+//
+// Screen Management functions
+//
+PSCREEN
+consoleNewScreen (
+ void
+ );
+
+BOOL
+consoleCloseScreen (
+ PSCREEN pScreen
+ );
+
+PSCREEN
+consoleGetCurrentScreen (
+ void
+ );
+
+BOOL
+consoleSetCurrentScreen (
+ PSCREEN pScreen
+ );
+
+BOOL
+consoleGetScreenInformation (
+ PSCREEN pScreen,
+ PSCREEN_INFORMATION pScreenInformation
+ );
+
+BOOL
+consoleSetScreenSize (
+ PSCREEN Screen,
+ ROW Rows,
+ COLUMN Cols
+ );
+
+
+
+//
+// Cursor management
+//
+BOOL
+consoleSetCursor (
+ PSCREEN pScreen,
+ ROW Row,
+ COLUMN Col
+ );
+
+//
+// Cursor style
+//
+BOOL
+consoleSetCursorStyle (
+ PSCREEN pScreen,
+ ULONG Style
+ );
+
+
+
+//
+// Screen output functions
+//
+ULONG
+consoleWriteLine (
+ PSCREEN pScreen,
+ PVOID pBuffer,
+ ULONG BufferSize,
+ ROW Row,
+ COLUMN Col,
+ ATTRIBUTE Attribute,
+ BOOL Blank
+ );
+
+BOOL
+consoleShowScreen (
+ PSCREEN pScreen
+ );
+
+BOOL
+consoleClearScreen (
+ PSCREEN pScreen,
+ BOOL ShowScreen
+ );
+
+BOOL
+consoleSetAttribute (
+ PSCREEN pScreen,
+ ATTRIBUTE Attribute
+ );
+
+BOOL
+consoleScrollVert (
+ PSCREEN pScreen,
+ ROW Top,
+ COLUMN Left,
+ ROW Bottom,
+ COLUMN Right,
+ INT Rows
+ );
+
+
+
+
+
+
+//
+// Input functions
+//
+BOOL
+consoleFlushInput (
+ void
+ );
+
+BOOL
+consoleIsKeyAvailable (
+ void
+ );
+
+BOOL
+consoleDoWindow (
+ void
+ );
+
+BOOL
+consoleGetKey (
+ PKBDKEY pKey,
+ BOOL fWait
+ );
+
+BOOL
+consolePutKey (
+ PKBDKEY pKey
+ );
+
+BOOL
+consolePutMouse (
+ ROW Row,
+ COLUMN Col,
+ DWORD MouseFlags
+ );
+
+BOOL
+consolePeekKey (
+ PKBDKEY pKey
+ );
+
+BOOL
+consoleGetMode (
+ PKBDMODE Mode
+ );
+
+BOOL
+consoleSetMode (
+ KBDMODE Mode
+ );
diff --git a/private/utils/mep/inc/ext.h b/private/utils/mep/inc/ext.h
new file mode 100644
index 000000000..07dc03026
--- /dev/null
+++ b/private/utils/mep/inc/ext.h
@@ -0,0 +1,599 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ext.h
+
+Abstract:
+
+ Microsoft Editor extension definitions.
+
+#ifndef SHIP
+
+ NOTES:
+ THIS FILE IS SHIPPED WITH THE PRODUCT!!!!
+
+ BE VERY carefull what gets put into this file. Technically, if it
+ is NOT required for extension writers, it does NOT belong here.
+
+ 1) This note, the file history and all code within "#ifndef SHIP" and
+ "#if defined EDITOR" conditionals should be REMOVED before shipping.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 06-Nov-1990 ported from M 1.02
+
+Revision History:
+
+ 26-Nov-1991 mz Strip off near/far
+
+
+#endif
+
+--*/
+
+
+#include <windows.h>
+
+
+//
+// Macro Definitions
+//
+// BUFLEN is the maximum line length that can be passed or will be returned
+// by the editor.
+//
+#define BUFLEN 251
+
+//
+// NT versions of the editor no longer use 16-bit specific attributes.
+// Set them into ignore state
+//
+
+#define near
+#define far
+#define LOADDS
+#define EXPORT
+#define EXTERNAL
+#define INTERNAL
+
+#undef pascal
+#define pascal
+
+//
+// RQ_... are various request types supported for Get/Set EditorObject
+//
+#define RQ_FILE 0x1000 // GetEditorObject: File request
+#define RQ_FILE_HANDLE 0x1000 // File Handle
+#define RQ_FILE_NAME 0x1100 // ASCIIZ filename
+#define RQ_FILE_FLAGS 0x1200 // flags
+#define RQ_FILE_REFCNT 0x1300 // reference count
+#define RQ_WIN 0x2000 // Window request
+#define RQ_WIN_HANDLE 0x2000 // Window Handle
+#define RQ_WIN_CONTENTS 0x2100 // Window Contents
+#define RQ_WIN_CUR 0x2200 // Current Window
+#define RQ_COLOR 0x9000 // Color request
+#define RQ_CLIP 0xf000 // clipboard type
+
+#define RQ_THIS_OBJECT 0x00FF // function is directed to input object
+
+#define RQ_FILE_INIT 0x00FE // file is init file
+
+//
+// toPif is used when placing numeric or boolean switches in the swiDesc table
+// to eliminate C 5.X compiler warnings.
+//
+// For example: { "Switchname", toPIF(switchvar), SWI_BOOLEAN },
+//
+#define toPIF(x) (PIF)(long)(void *)&x
+
+
+//
+// Editor color table endicies. (Colors USERCOLORMIN - USERCOLORMAX are
+// unassigned and available for extension use).
+//
+#define FGCOLOR 21 // foreground (normal) color
+#define HGCOLOR (1 + FGCOLOR) // highlighted region color
+#define INFCOLOR (1 + HGCOLOR) // information color
+#define SELCOLOR (1 + INFCOLOR) // selection color
+#define WDCOLOR (1 + SELCOLOR) // window border color
+#define STACOLOR (1 + WDCOLOR) // status line color
+#define ERRCOLOR (1 + STACOLOR) // error message color
+#define USERCOLORMIN (1 + ERRCOLOR) // begining of extension colors
+#define USERCOLORMAX 35 // end of extension colors
+
+
+//
+// General type Definitions
+//
+typedef int COL; // column or position with line
+
+#if !defined (EDITOR)
+
+#if !defined( _FLAGTYPE_DEFINED_ )
+#define _FLAGTYPE_DEFINED_ 1
+typedef char flagType;
+#endif
+typedef long LINE; // line number within file
+typedef void* PFILE; // editor file handle
+
+#if !defined (EXTINT)
+
+typedef void* PWND; // editor window handle
+
+#endif // EXTINT
+
+#endif // EDITOR
+
+
+typedef char buffer[BUFLEN]; // miscellaneous buffer
+typedef char linebuf[BUFLEN]; // line buffer
+typedef char pathbuf[MAX_PATH]; // Pathname buffer
+
+
+typedef struct fl { // file location
+ LINE lin; // - line number
+ COL col; // - column
+} fl;
+
+typedef struct sl { // screen location
+ int lin; // - line number
+ int col; // - column
+} sl;
+
+typedef struct rn { // file range
+ fl flFirst; // - Lower line, or leftmost col
+ fl flLast; // - Higher, or rightmost
+} rn;
+
+
+typedef struct lineAttr { // Line color attribute info
+ unsigned char attr; // - Attribute of piece
+ unsigned char len; // - Bytes in colored piece
+} lineAttr;
+
+#if !defined (cwExtraWnd)
+
+typedef struct ARC {
+ BYTE axLeft;
+ BYTE ayTop;
+ BYTE axRight;
+ BYTE ayBottom;
+} ARC;
+#endif // cwExtraWnd
+
+
+//
+// Argument defininition structures.
+//
+// We define a structure for each of the argument types that may be
+// passed to an extension function. Then, we define the structure
+// argType which is used to pass these arguments around in a union.
+//
+typedef struct noargType { // no argument specified
+ LINE y; // - cursor line
+ COL x; // - cursor column
+} NOARGTYPE;
+
+typedef struct textargType { // text argument specified
+ int cArg; // - count of <arg>s pressed
+ LINE y; // - cursor line
+ COL x; // - cursor column
+ char *pText; // - ptr to text of arg
+} TEXTARGTYPE;
+
+typedef struct nullargType { // null argument specified
+ int cArg; // - count of <arg>s pressed
+ LINE y; // - cursor line
+ COL x; // - cursor column
+} NULLARGTYPE;
+
+typedef struct lineargType { // line argument specified
+ int cArg; // - count of <arg>s pressed
+ LINE yStart; // - starting line of range
+ LINE yEnd; // - ending line of range
+} LINEARGTYPE;
+
+typedef struct streamargType { // stream argument specified
+ int cArg; // - count of <arg>s pressed
+ LINE yStart; // - starting line of region
+ COL xStart; // - starting column of region
+ LINE yEnd; // - ending line of region
+ COL xEnd; // - ending column of region
+} STREAMARGTYPE;
+
+typedef struct boxargType { // box argument specified
+ int cArg; // - count of <arg>s pressed
+ LINE yTop; // - top line of box
+ LINE yBottom; // - bottom line of bix
+ COL xLeft; // - left column of box
+ COL xRight; // - right column of box
+} BOXARGTYPE;
+
+typedef union ARGUNION {
+ struct noargType noarg;
+ struct textargType textarg;
+ struct nullargType nullarg;
+ struct lineargType linearg;
+ struct streamargType streamarg;
+ struct boxargType boxarg;
+} ARGUNION;
+
+typedef struct argType {
+ int argType;
+ ARGUNION arg;
+} ARG;
+
+
+
+//
+// Function definition table definitions
+//
+typedef unsigned long CMDDATA;
+typedef flagType (*funcCmd)(CMDDATA argData, ARG *pArg, flagType fMeta);
+
+typedef struct cmdDesc { // function definition entry
+ char *name; // - pointer to name of fcn
+ funcCmd func; // - pointer to function
+ CMDDATA arg; // - used internally by editor
+ unsigned argType; // - user args allowed
+} CMD, *PCMD;
+
+
+typedef unsigned short KeyHandle;
+
+#define NOARG 0x0001 // no argument specified
+#define TEXTARG 0x0002 // text specified
+#define NULLARG 0x0004 // arg + no cursor movement
+#define NULLEOL 0x0008 // null arg => text from arg->eol
+#define NULLEOW 0x0010 // null arg => text from arg->end word
+#define LINEARG 0x0020 // range of entire lines
+#define STREAMARG 0x0040 // from low-to-high, viewed 1-D
+#define BOXARG 0x0080 // box delimited by arg, cursor
+
+#define NUMARG 0x0100 // text => delta to y position
+#define MARKARG 0x0200 // text => mark at end of arg
+
+#define BOXSTR 0x0400 // single-line box => text
+
+#define FASTKEY 0x0800 // Fast repeat function
+#define MODIFIES 0x1000 // modifies file
+#define KEEPMETA 0x2000 // do not eat meta flag
+#define WINDOWFUNC 0x4000 // moves window
+#define CURSORFUNC 0x8000 // moves cursor
+
+
+
+//
+// Switch definition table defintions
+//
+typedef flagType (*PIF)(char *);
+typedef char* (*PIFC)(char *);
+
+typedef union swiAct { // switch location or routine
+ PIF pFunc; // - routine for text
+ PIFC pFunc2; // - routine for text
+ int *ival; // - integer value for NUMERIC
+ flagType *fval; // - flag value for BOOLEAN
+} swiAct;
+
+typedef struct swiDesc { // switch definition entry
+ char *name; // - pointer to name of switch
+ swiAct act; // - pointer to value or fcn
+ int type; // - flags defining switch type
+} SWI, *PSWI;
+
+
+#define SWI_BOOLEAN 0 // Boolean switch
+#define SWI_NUMERIC 1 // hex or decimal switch
+#define SWI_SCREEN 4 // switch affects screen
+#define SWI_SPECIAL 5 // textual switch
+#define SWI_SPECIAL2 6 // #5, returning an error string
+#define RADIX10 (0x0A << 8) // numeric switch is decimal
+#define RADIX16 (0x10 << 8) // numeric switch is hex
+
+
+//
+// Get/Set EditorObject data structures
+//
+typedef struct winContents{ // define window contents
+ PFILE pFile; // - handle of file displayed
+ ARC arcWin; // - location of window
+ fl flPos; // - upper left corner wrt file
+} winContents;
+
+
+//
+// FILE flags values
+//
+#define DIRTY 0x01 // file had been modified
+#define FAKE 0x02 // file is a pseudo file
+#define REAL 0x04 // file has been read from disk
+#define DOSFILE 0x08 // file has CR-LF
+#define TEMP 0x10 // file is a temp file
+#define NEW 0x20 // file has been created by editor
+#define REFRESH 0x40 // file needs to be refreshed
+#define READONLY 0x80 // file may not be editted
+
+#define DISKRO 0x0100 // file on disk is read only
+#define MODE1 0x0200 // Meaning depends on the file
+#define VALMARKS 0x0400 // file has valid marks defined
+
+
+
+//
+// Event processing definitions
+//
+typedef struct mouseevent { // mouse event data
+ short msg; // type of message
+ short wParam; // CW wParam
+ long lParam; // CW lParam
+ sl sl; // screen location of mouse event
+ fl fl; // file location (if event in win)
+} MOUSEEVENT, *PMOUSEEVENT;
+
+
+typedef struct KEY_DATA {
+ BYTE Ascii; // Ascii code
+ BYTE Scan; // Scan code
+ BYTE Flags; // Flags
+ BYTE Unused; // Unused byte
+} KEY_DATA, *PKEY_DATA;
+
+//
+// Following are the values for the Flags field of KEY_DATA
+//
+#define FLAG_SHIFT 0x01
+#define FLAG_CTRL 0x04
+#define FLAG_ALT 0x08
+#define FLAG_NUMLOCK 0x20
+
+
+typedef union KEY_INFO {
+ KEY_DATA KeyData;
+ long LongData;
+} KEY_INFO, *PKEY_INFO;
+
+
+typedef union EVTARGUNION {
+ KEY_INFO key; // keystroke for key event
+ char * pfn; // asciiz filename
+ PMOUSEEVENT pmouse; // ptr to mouse event data
+ union Rec *pUndoRec; // undo information
+} EVTARGUNION;
+
+typedef struct EVTargs { // arguments to event dispatches
+ PFILE pfile; // -file handle for file events
+ EVTARGUNION arg;
+} EVTargs, *PEVTARGS;
+
+
+typedef struct eventType { // event definition struct
+ unsigned evtType; // - type
+ flagType (*func)(EVTargs *); // - handler
+ struct eventType *pEVTNext; // - next handler in list
+ PFILE focus; // - applicable focus
+ EVTargs arg; // - applicable agruments
+} EVT, *PEVT;
+
+#define EVT_RAWKEY 1 // ALL keystrokes
+#define EVT_KEY 2 // Editting keystrokes
+#define EVT_GETFOCUS 3 // file GETs focus.
+#define EVT_LOSEFOCUS 4 // file looses focus.
+#define EVT_EXIT 5 // about to exit.
+#define EVT_SHELL 6 // about to sell or compile
+#define EVT_UNLOAD 7 // about to be unloaded.
+#define EVT_IDLE 8 // idle event
+#define EVT_CANCEL 9 // do-nothing cancel
+#define EVT_REFRESH 10 // about to refresh a file
+#define EVT_FILEREADSTART 11 // about to read file
+#define EVT_FILEREADEND 12 // finshed reading file
+#define EVT_FILEWRITESTART 13 // about to write file
+#define EVT_FILEWRITEEND 14 // finshed writing file
+// 15
+// 16
+// 17
+// 18
+// 19
+#define EVT_EDIT 20 // editting action
+#define EVT_UNDO 21 // undone action
+#define EVT_REDO 22 // redone action
+
+
+//
+// Undo, Redo and Edit event structs
+//
+#define EVENT_REPLACE 0
+#define EVENT_INSERT 1
+#define EVENT_DELETE 2
+#define EVENT_BOUNDARY 3
+
+#if !defined (EDITOR)
+typedef struct replaceRec {
+ int op; // operation
+ long dummy[2]; // editor interal
+ LINE length; // length of repalcement
+ LINE line; // start of replacement
+} REPLACEREC;
+
+typedef struct insertRec {
+ int op; // operation
+ long dummy[2]; // editor interal
+ LINE length; // length of file
+ LINE line; // line number that was operated on
+ LINE cLine; // number of lines inserted
+} INSERTREC;
+
+typedef struct deleteRec {
+ int op; // operation
+ long dummy[2]; // editor interal
+ LINE length; // length of file
+ LINE line; // line number that was operated on
+ LINE cLine; // Number of lines deleted
+} DELETEREC;
+
+typedef struct boundRec {
+ int op; // operation (BOUND)
+ long dummy[2]; // editor interal
+ int flags; // flags of file
+ long modify; // Date/Time of last modify
+ fl flWindow; // position in file of window
+ fl flCursor; // position in file of cursor
+} BOUNDREC;
+
+typedef union Rec {
+ struct replaceRec r;
+ struct insertRec i;
+ struct deleteRec d;
+ struct boundRec b;
+} REC;
+#endif // editor
+
+
+
+//
+// Build command definitions
+//
+#define MAKE_FILE 1 // rule is for a filename
+#define MAKE_SUFFIX 2 // rule is a suffix rule
+#define MAKE_TOOL 4 // rule is for a tool
+#define MAKE_BLDMACRO 8 // rule is for a build macro
+#define MAKE_DEBUG 0x80 // rule is debug version
+
+
+#define LOWVERSION 0x0014 // lowest version of extensions we handle
+#define HIGHVERSION 0x0014 // highest version of extensions we handle
+
+#define VERSION 0x0014 // our current version
+
+typedef struct ExtensionTable {
+ long version;
+ long cbStruct;
+ PCMD cmdTable;
+ PSWI swiTable;
+ struct CallBack {
+ PFILE (*AddFile) (char *);
+ flagType (*BadArg) (void);
+ char (*Confirm) (char *, char *);
+ void (*CopyBox) (PFILE, PFILE, COL, LINE, COL, LINE, COL, LINE);
+ void (*CopyLine) (PFILE, PFILE, LINE, LINE, LINE);
+ void (*CopyStream) (PFILE, PFILE, COL, LINE, COL, LINE, COL, LINE);
+ void (*DeRegisterEvent) (EVT *);
+ flagType (*DeclareEvent) (unsigned, EVTargs *);
+ void (*DelBox) (PFILE, COL, LINE, COL, LINE);
+ void (*DelFile) (PFILE);
+ void (*DelLine) (PFILE, LINE, LINE);
+ void (*DelStream) (PFILE, COL, LINE, COL, LINE);
+ void (*Display) (void);
+ int (*DoMessage) (char *);
+ flagType (*fChangeFile) (flagType, char *);
+ void (*Free) (void *);
+ flagType (*fExecute) (char *);
+ int (*fGetMake) (int, char *, char *);
+ LINE (*FileLength) (PFILE);
+ PFILE (*FileNameToHandle) (char *, char *);
+ flagType (*FileRead) (char *, PFILE);
+ flagType (*FileWrite) (char *, PFILE);
+ PSWI (*FindSwitch) (char *);
+ flagType (*fSetMake) (int, char *, char *);
+ flagType (*GetColor) (LINE, lineAttr *, PFILE);
+ void (*GetTextCursor) (COL *, LINE *);
+ flagType (*GetEditorObject) (unsigned, void *, void *);
+ char * (*GetEnv) (char *);
+ int (*GetLine) (LINE, char *, PFILE);
+ char * (*GetListEntry) (PCMD, int, flagType);
+ flagType (*GetString) (char *, char *, flagType);
+ int (*KbHook) (void);
+ void (*KbUnHook) (void);
+ void * (*Malloc) (size_t);
+ void (*MoveCur) (COL, LINE);
+ char * (*NameToKeys) (char *, char *);
+ PCMD (*NameToFunc) (char *);
+ flagType (*pFileToTop) (PFILE);
+ void (*PutColor) (LINE, lineAttr *, PFILE);
+ void (*PutLine) (LINE, char *, PFILE);
+ int (*REsearch) (PFILE, flagType, flagType, flagType, flagType, char *, fl *);
+ long (*ReadChar) (void);
+ PCMD (*ReadCmd) (void);
+ void (*RegisterEvent) (EVT *);
+ void (*RemoveFile) (PFILE);
+ flagType (*Replace) (char, COL, LINE, PFILE, flagType);
+ char * (*ScanList) (PCMD, flagType);
+ int (*search) (PFILE, flagType, flagType, flagType, flagType, char *, fl *);
+ void (*SetColor) (PFILE, LINE, COL, COL, int);
+ flagType (*SetEditorObject) (unsigned, void *, void *);
+ void (*SetHiLite) (PFILE, rn, int);
+ flagType (*SetKey) (char *, char *);
+ flagType (*SplitWnd) (PWND, flagType, int);
+ } CallBack;
+ } EXTTAB;
+
+//
+// Editor low level function prototypes.
+//
+// This list defines the routines within the editor which may be called
+// by extension functions.
+//
+#if !defined (EDITOR)
+
+extern EXTTAB ModInfo;
+
+#define AddFile(x) ModInfo.CallBack.AddFile(x)
+#define BadArg ModInfo.CallBack.BadArg
+#define Confirm(x,y) ModInfo.CallBack.Confirm(x,y)
+#define CopyBox(x,y,z,a,b,c,d,e) ModInfo.CallBack.CopyBox(x,y,z,a,b,c,d,e)
+#define CopyLine(x,y,z,a,b) ModInfo.CallBack.CopyLine(x,y,z,a,b)
+#define CopyStream(x,y,z,a,b,c,d,e) ModInfo.CallBack.CopyStream(x,y,z,a,b,c,d,e)
+#define DeRegisterEvent(x) ModInfo.CallBack.DeRegisterEvent(x)
+#define DeclareEvent(x,y) ModInfo.CallBack.DeclareEvent(x,y)
+#define DelBox(x,y,z,a,b) ModInfo.CallBack.DelBox(x,y,z,a,b)
+#define DelFile(x) ModInfo.CallBack.DelFile(x)
+#define DelLine(x,y,z) ModInfo.CallBack.DelLine(x,y,z)
+#define DelStream(x,y,z,a,b) ModInfo.CallBack.DelStream(x,y,z,a,b)
+#define Display ModInfo.CallBack.Display
+#define DoMessage(x) ModInfo.CallBack.DoMessage(x)
+#define fChangeFile(x,y) ModInfo.CallBack.fChangeFile(x,y)
+#define Free(x) ModInfo.CallBack.Free(x)
+#define fExecute(x) ModInfo.CallBack.fExecute(x)
+#define fGetMake(x,y,z) ModInfo.CallBack.fGetMake(x,y,z)
+#define FileLength(x) ModInfo.CallBack.FileLength(x)
+#define FileNameToHandle(x,y) ModInfo.CallBack.FileNameToHandle(x,y)
+#define FileRead(x,y) ModInfo.CallBack.FileRead(x,y)
+#define FileWrite(x,y) ModInfo.CallBack.FileWrite(x,y)
+#define FindSwitch(x) ModInfo.CallBack.FindSwitch(x)
+#define fSetMake(x,y,z) ModInfo.CallBack.fSetMake(x,y,z)
+#define GetColor(x,y,z) ModInfo.CallBack.GetColor(x,y,z)
+#define GetTextCursor(x,y) ModInfo.CallBack.GetTextCursor(x,y)
+#define GetEditorObject(x,y,z) ModInfo.CallBack.GetEditorObject(x,y,z)
+#define GetEnv(x) ModInfo.CallBack.GetEnv(x)
+#define GetLine(x,y,z) ModInfo.CallBack.GetLine(x,y,z)
+#define GetListEntry(x,y,z) ModInfo.CallBack.GetListEntry(x,y,z)
+#define GetString(x,y,z) ModInfo.CallBack.GetString(x,y,z)
+#define KbHook ModInfo.CallBack.KbHook
+#define KbUnHook ModInfo.CallBack.KbUnHook
+#define Malloc(x) ModInfo.CallBack.Malloc(x)
+#define MoveCur(x,y) ModInfo.CallBack.MoveCur(x,y)
+#define NameToKeys(x,y) ModInfo.CallBack.NameToKeys(x,y)
+#define NameToFunc(x) ModInfo.CallBack.NameToFunc(x)
+#define pFileToTop(x) ModInfo.CallBack.pFileToTop(x)
+#define PutColor(x,y,z) ModInfo.CallBack.PutColor(x,y,z)
+#define PutLine(x,y,z) ModInfo.CallBack.PutLine(x,y,z)
+#define REsearch(x,y,z,a,b,c,d) ModInfo.CallBack.REsearch(x,y,z,a,b,c,d)
+#define ReadChar ModInfo.CallBack.ReadChar
+#define ReadCmd ModInfo.CallBack.ReadCmd
+#define RegisterEvent(x) ModInfo.CallBack.RegisterEvent(x)
+#define RemoveFile(x) ModInfo.CallBack.RemoveFile(x)
+#define Replace(x,y,z,a,b) ModInfo.CallBack.Replace(x,y,z,a,b)
+#define ScanList(x,y) ModInfo.CallBack.ScanList(x,y)
+#define search(x,y,z,a,b,c,d) ModInfo.CallBack.search(x,y,z,a,b,c,d)
+#define SetColor(x,y,z,a,b) ModInfo.CallBack.SetColor(x,y,z,a,b)
+#define SetEditorObject(x,y,z) ModInfo.CallBack.SetEditorObject(x,y,z)
+#define SetHiLite(x,y,z) ModInfo.CallBack.SetHiLite(x,y,z)
+#define SetKey(x,y) ModInfo.CallBack.SetKey(x,y)
+#define SplitWnd(x,y,z) ModInfo.CallBack.SplitWnd(x,y,z)
+
+
+void WhenLoaded (void);
+
+#endif // EDITOR
diff --git a/private/utils/mep/inc/extint.h b/private/utils/mep/inc/extint.h
new file mode 100644
index 000000000..41b4144b0
--- /dev/null
+++ b/private/utils/mep/inc/extint.h
@@ -0,0 +1,62 @@
+/*** extint.h - include for for internal extensions
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Contains definitions required by extensions which are internal to Microsoft
+*
+* Revision History:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+#if defined(CW)
+#if !defined(EDITOR)
+#define CC 1 /* use a real C compiler */
+#define cwExtraWnd 5 /* number of extra bytes in PWND*/
+#define DLG_CONST /* are dialogs type const? */
+#define HELP_BUTTON
+
+#include <cwindows.h> /* CW definitions */
+#include <csdm.h> /* SDM definitions */
+#include <csdmtmpl.h> /* SDM dialog template stuff */
+
+#define EXTINT 1 /* extint included. */
+#include "ext.h" /* real ext.h */
+
+#include "menu.h" /* menu id's & other defs */
+#endif
+
+/************************************************************************
+*
+* types and globals needed for handling menu command and dialog boxes.
+* DLGDATA holds all the info needed to handle a dialog boxed menu
+* command.
+*
+*************************************************************************/
+typedef struct DlgData {
+ DLG * pDialog; /* Dialog Template */
+ int cbDialog; /* size of that template */
+ WORD cabi; /* CAB index */
+ flagType (*pfnCab)(HCAB, flagType, TMC); /* massager*/
+ } DLGDATA;
+#endif
+
+/************************************************************************
+*
+* Additional exports.
+*
+*************************************************************************/
+#ifndef EDITOR
+TMC PerformDialog (DLGDATA *);
+void DlgHelp (int);
+void DoEnableTmc (TMC, BOOL);
+flagType DoSetDialogCaption (char *);
+void DoSzToCab (unsigned, char *, WORD);
+char * DoSzFromCab (unsigned, char *, WORD, WORD);
+void DoGetTmcText (TMC, char *, WORD);
+WORD DoGetTmcVal (TMC);
+void DoSetTmcListWidth (TMC, WORD);
+void DoSetTmcText (TMC, char *);
+void DoSetTmcVal (TMC, WORD);
+void DoRedisplayListBox (TMC);
+void DoTmcListBoxAddString (TMC, char *, BOOL);
+#endif
diff --git a/private/utils/mep/inc/keyboard.h b/private/utils/mep/inc/keyboard.h
new file mode 100644
index 000000000..da0a356c4
--- /dev/null
+++ b/private/utils/mep/inc/keyboard.h
@@ -0,0 +1,8 @@
+void mepInitKeyboard ( void );
+BOOL TypeAhead ( void );
+KBDKEY ReadChar ( void );
+
+void KbHook ( void );
+void KbUnHook ( void );
+KBDMODE KbGetMode ( void );
+void KbSetMode ( KBDMODE Mode );
diff --git a/private/utils/mep/inc/keys.h b/private/utils/mep/inc/keys.h
new file mode 100644
index 000000000..1624721f7
--- /dev/null
+++ b/private/utils/mep/inc/keys.h
@@ -0,0 +1,4 @@
+/* Virtual Keys, Standard Set =*/
+
+
+EDITOR_KEY TranslateKey (KBDKEY KbdKey);
diff --git a/private/utils/mep/inc/menu.h b/private/utils/mep/inc/menu.h
new file mode 100644
index 000000000..f0c7e60dc
--- /dev/null
+++ b/private/utils/mep/inc/menu.h
@@ -0,0 +1,360 @@
+/*** menu.h - macros and constants for menu.c
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+
+#if !defined(CW)
+# error This module must be compiled with /DCW
+#else
+
+#define DLG_CONST
+
+/****************************************************************************
+ * *
+ * Editor constants *
+ * *
+ * C_MENUSTRINGS_MAX *
+ * C_CITEM_MAX *
+ * *
+ ****************************************************************************/
+
+#define C_MENUSTRINGS_MAX 128
+#define C_ITEM_MAX 21
+
+
+/****************************************************************************
+ * *
+ * Actions associated with menu items *
+ * *
+ * Each menu item keeps a value in bParamUser that tells wich kind of action*
+ * it is associated with (dialog box, command, macro or "other") and gives *
+ * an index to the associated table (DialogData, CommandData or MacroData). *
+ * *
+ ****************************************************************************/
+
+/*
+ * COMDATA structure used for menu items directly relating to editor commands
+ */
+typedef struct comData {
+ PCMD pCmd; /* pointer to command */
+ flagType fKeepArg; /* arg to be used or not */
+ };
+
+/*
+ * Mask to get the menu item type
+ */
+#define iXXXMENU 0xC0
+
+/*
+ * Menu item action types
+ */
+#define iDLGMENU 0x00
+#define iCOMMENU 0x40
+#define iMACMENU 0x80
+#define iOTHMENU 0xC0
+
+/*
+ * CommandData indices for menu items directly relating to editor commands
+ */
+#define iCOMNEXT iCOMMENU /* 0 */
+#define iCOMSAVEALL (1 + iCOMNEXT) /* 1 */
+#define iCOMSHELL (1 + iCOMSAVEALL) /* 2 */
+#define iCOMUNDO (1 + iCOMSHELL) /* 3 */
+#define iCOMREPEAT (1 + iCOMUNDO) /* 0 */
+#define iCOMCUT (1 + iCOMREPEAT) /* 0 */
+#define iCOMCOPY (1 + iCOMCUT) /* 4 */
+#define iCOMPASTE (1 + iCOMCOPY) /* 0 */
+#define iCOMDROPANCHOR (1 + iCOMPASTE) /* 5 */
+#define iCOMANCHOR (1 + iCOMDROPANCHOR) /* 0 */
+#define iCOMBOXMODE (1 + iCOMANCHOR) /* 0 */
+#define iCOMREADONLY (1 + iCOMBOXMODE) /* 6 */
+#define iCOMFINDSEL (1 + iCOMREADONLY) /* 0 */
+#define iCOMFINDLAST (1 + iCOMFINDSEL) /* 7 */
+#define iCOMNEXTERR (1 + iCOMFINDLAST) /* 8 */
+#define iCOMDEBUGBLD (1 + iCOMNEXTERR) /* 9 */
+#define iCOMRECORD (1 + iCOMDEBUGBLD) /* 10 */
+#define iCOMRESIZE (1 + iCOMRECORD) /* 11 */
+#define iCOMMAXIMIZE (1 + iCOMRESIZE) /* 12 */
+
+/*
+ * MacroData indices for menu items directly relating to pre-defined macros
+ */
+#define iMACSAVE iMACMENU /* 0 */
+#define iMACQUIT (1 + iMACSAVE) /* 1 */
+#define iMACREDO (1 + iMACQUIT) /* 2 */
+#define iMACCLEAR (1 + iMACREDO) /* 3 */
+#define iMACPREVERR (1 + iMACCLEAR) /* 4 */
+#define iMACSETERR (1 + iMACPREVERR) /* 5 */
+#define iMACCLEARLIST (1 + iMACSETERR) /* 6 */
+#define iMACERRWIN (1 + iMACCLEARLIST) /* 7 */
+#define iMACHSPLIT (1 + iMACERRWIN) /* 8 */
+#define iMACVSPLIT (1 + iMACHSPLIT) /* 9 */
+#define iMACCLOSE (1 + iMACVSPLIT) /* 10 */
+#define iMACASSIGNKEY (1 + iMACCLOSE) /* 11 */
+#define iMACRESTORE (1 + iMACASSIGNKEY) /* 12 */
+
+
+
+/****************************************************************************
+ * *
+ * Menu items with variable content and/or meaning: We store their set of *
+ * data in an ITEMDATA structure and do the update with the UPDITEM macro *
+ * *
+ ****************************************************************************/
+
+/*
+ * ITEMDATA structure used for menu items with variable content and/or meaning
+ */
+typedef struct {
+ BYTE ichHilite;
+ BYTE bParamUser;
+ WORD wParamUser;
+ } ITEMDATA, *PITEMDATA;
+
+/*
+ * UPDITEM (pItem, pItemData)
+ *
+ * Where:
+ * pItem is an object of type PMENUITEM
+ * pItemData is an object of type PITEMDATA
+ *
+ * Will update Item with ItemData data:
+ *
+ * pItem->ichHilite with pItemData->ichHilite
+ * pItem->bParamUser with pItemData->bParamUser
+ * pItem->wParamUser with pItemData->wParamUser
+ */
+#define UPDITEM(pItem, pItemData) \
+ (pItem)->ichHilite = (pItemData)->ichHilite, \
+ (pItem)->bParamUser = (pItemData)->bParamUser,\
+ (pItem)->wParamUser = (pItemData)->wParamUser
+
+
+/****************************************************************************
+ * *
+ * Prdefined Menus and Menuitems data *
+ * *
+ * Note: *
+ * *
+ * MENU ID's are comprised of two parts: *
+ * *
+ * . The high byte identifies the parent menu *
+ * . The low byte identifies the actual menu item. *
+ * *
+ * The low byte - 1 can be used as an index into the respective menu *
+ * tables providing that the item is in the STATIC part of the menu *
+ * *
+ * For the 'dynamic' part of certain predefined menus, we use id's with *
+ * low byte values with high bit set. This allow us to still use the low *
+ * byte as an index for any extension-supplied items we might insert *
+ * between the static part and the dynamic part. *
+ * *
+ * Menus with dynamic parts are the File and Run menus (for now..) *
+ * *
+ ****************************************************************************/
+
+/*
+ * File Menu
+ *
+ * Note: Alternate files items are dynamic
+ *
+ */
+#define MID_FILE 0x0000
+#define RX_FILE 2
+#define ICH_FILE 0
+#define CCH_FILE 4
+#define CCIT_FILE 12
+#define WP_FILE ((12<<9)|(21<<4)|0)
+
+#define MID_NEW (MID_FILE + 1)
+#define MID_OPEN (MID_FILE + 2)
+#define MID_MERGE (MID_FILE + 3)
+#define MID_NEXT (MID_FILE + 4)
+#define MID_SAVE (MID_FILE + 5)
+#define MID_SAVEAS (MID_FILE + 6)
+#define MID_SAVEALL (MID_FILE + 7)
+
+#define MID_PRINT (MID_FILE + 9)
+#define MID_SHELL (MID_FILE + 10)
+
+#define MID_EXIT (MID_FILE + 12)
+
+#define MID_FILE1 (MID_FILE + 0x80 + 0)
+#define MID_FILE2 (MID_FILE + 0x80 + 1)
+#define MID_FILE3 (MID_FILE + 0x80 + 2)
+#define MID_FILE4 (MID_FILE + 0x80 + 3)
+#define MID_FILE5 (MID_FILE + 0x80 + 4)
+#define MID_FILE6 (MID_FILE + 0x80 + 5)
+#define MID_FILE7 (MID_FILE + 0x80 + 6)
+#define MID_MORE (MID_FILE + 0x80 + 7)
+
+
+/*
+ * Edit Menu
+ */
+#define MID_EDIT 0x0100
+#define RX_EDIT 8
+#define ICH_EDIT 0
+#define CCH_EDIT 4
+#define CCIT_EDIT 18
+#define WP_EDIT ((18<<9)|(18<<4)|1)
+
+#define MID_UNDO (MID_EDIT + 1)
+#define MID_REDO (MID_EDIT + 2)
+#define MID_REPEAT (MID_EDIT + 3)
+
+#define MID_CUT (MID_EDIT + 5)
+#define MID_COPY (MID_EDIT + 6)
+#define MID_PASTE (MID_EDIT + 7)
+#define MID_CLEAR (MID_EDIT + 8)
+
+#define MID_DROPANCHOR (MID_EDIT + 10)
+#define MID_ANCHOR (MID_EDIT + 11)
+
+#define MID_BOXMODE (MID_EDIT + 13)
+#define MID_READONLY (MID_EDIT + 14)
+
+#define MID_SETREC (MID_EDIT + 16)
+#define MID_RECORD (MID_EDIT + 17)
+#define MID_EDITMACROS (MID_EDIT + 18)
+
+
+/*
+ * Search Menu
+ */
+#define MID_SEARCH 0x0200
+#define RX_SEARCH 14
+#define ICH_SEARCH 0
+#define CCH_SEARCH 6
+#define CCIT_SEARCH 14
+#define WP_SEARCH ((14<<9)|(14<<4)|2)
+
+#define MID_FIND (MID_SEARCH + 1)
+#define MID_FINDSEL (MID_SEARCH + 2)
+#define MID_FINDLAST (MID_SEARCH + 3)
+#define MID_REPLACE (MID_SEARCH + 4)
+#define MID_FINDFILE (MID_SEARCH + 5)
+
+#define MID_NEXTERR (MID_SEARCH + 7)
+#define MID_PREVERR (MID_SEARCH + 8)
+#define MID_SETERR (MID_SEARCH + 9)
+#define MID_ERRWIN (MID_SEARCH + 10)
+
+#define MID_GOTOMARK (MID_SEARCH + 12)
+#define MID_DEFMARK (MID_SEARCH + 13)
+#define MID_SETMARK (MID_SEARCH + 14)
+
+
+/*
+ * Make Menu
+ */
+#define MID_MAKE 0x0300
+#define RX_MAKE 22
+#define ICH_MAKE 0
+#define CCH_MAKE 4
+#define CCIT_MAKE 8
+#define WP_MAKE ((8<<9)|(8<<4)|3)
+
+#define MID_COMPILE (MID_MAKE + 1)
+#define MID_BUILD (MID_MAKE + 2)
+#define MID_REBUILD (MID_MAKE + 3)
+#define MID_TARGET (MID_MAKE + 4)
+
+#define MID_SETLIST (MID_MAKE + 6)
+#define MID_EDITLIST (MID_MAKE + 7)
+#define MID_CLEARLIST (MID_MAKE + 8)
+
+
+/*
+ * Run Menu
+ *
+ * Note: User menu items are dynamic
+ *
+ */
+#define MID_RUN 0x0400
+#define RX_RUN 28
+#define ICH_RUN 0
+#define CCH_RUN 3
+#define CCIT_RUN 5
+#define WP_RUN ((5<<9)|(12<<4)|4)
+
+#define MID_EXECUTE (MID_RUN + 1)
+#define MID_DEBUG (MID_RUN + 2)
+
+#define MID_RUNAPP (MID_RUN + 4)
+#define MID_CUSTOM (MID_RUN + 5)
+
+#define MID_USER1 (MID_RUN + 0x80 + 0)
+#define MID_USER2 (MID_RUN + 0x80 + 1)
+#define MID_USER3 (MID_RUN + 0x80 + 2)
+#define MID_USER4 (MID_RUN + 0x80 + 3)
+#define MID_USER5 (MID_RUN + 0x80 + 4)
+#define MID_USER6 (MID_RUN + 0x80 + 5)
+
+/*
+ * Window Menu
+ */
+#define MID_WINDOW 0x0500
+#define RX_WINDOW 33
+#define ICH_WINDOW 0
+#define CCH_WINDOW 6
+#define CCIT_WINDOW 5
+#define WP_WINDOW ((5<<9)|(5<<4)|5)
+
+#define MID_SPLITH (MID_WINDOW + 1)
+#define MID_SPLITV (MID_WINDOW + 2)
+#define MID_SIZE (MID_WINDOW + 3)
+#define MID_MAXIMIZE (MID_WINDOW + 4)
+#define MID_CLOSE (MID_WINDOW + 5)
+
+/*
+ * Options Menu
+ */
+#define MID_OPTIONS 0x0600
+#define RX_OPTIONS 41
+#define ICH_OPTIONS 0
+#define CCH_OPTIONS 7
+#define CCIT_OPTIONS 4
+#define WP_OPTIONS ((4<<9)|(4<<4)|6)
+
+#define MID_DEBUGBLD (MID_OPTIONS + 1)
+#define MID_ENVIRONMENT (MID_OPTIONS + 2)
+#define MID_ASSIGNKEY (MID_OPTIONS + 3)
+#define MID_SETSWITCH (MID_OPTIONS + 4)
+
+
+/*
+ * Extension Menus are last+1 through last+n
+ */
+#define MID_EXTENSION 0x700
+
+
+
+
+#if !defined(EXTINT)
+/****************************************************************************
+ * *
+ * FARDATA.C global variables *
+ * *
+ ****************************************************************************/
+
+int cMenuStrings;
+
+char * MenuTitles [];
+char * HelpStrings [];
+char * HelpContexts [];
+
+char * MacroData [];
+struct comData CommandData [];
+
+ITEMDATA InitItemData [];
+
+ITEMDATA SelModeItemData [];
+ITEMDATA MaximizeItemData [];
+#endif
+
+#endif /* if defined(CW) */
diff --git a/private/utils/mep/inc/mep.h b/private/utils/mep/inc/mep.h
new file mode 100644
index 000000000..f57dff637
--- /dev/null
+++ b/private/utils/mep/inc/mep.h
@@ -0,0 +1,812 @@
+/*** mep.h - primary include file for editor
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+* 10-Jan-1991 ramonsa Converted to Win32 API
+* 26-Nov-1991 mz Strip off near/far
+*
+************************************************************************/
+
+#include <ctype.h>
+#include <direct.h>
+#include <fcntl.h>
+#include <io.h>
+#include <malloc.h>
+#include <math.h>
+#include <process.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys\types.h>
+#include <sys\stat.h>
+#include <time.h>
+#include <stdio.h>
+#include <share.h>
+
+//
+// WINDOWS includes
+//
+#include <windows.h>
+
+#include <dos.h>
+#include <tools.h>
+#include <remi.h>
+
+#include "console.h"
+
+typedef HANDLE FILEHANDLE, *PFILEHANDLE;
+typedef DWORD ACCESSMODE, *PACCESSMODE;
+typedef DWORD SHAREMODE, *PSHAREMODE;
+typedef DWORD MOVEMETHOD, *PMOVEMETHOD;
+
+#define ACCESSMODE_READ GENERIC_READ
+#define ACCESSMODE_WRITE GENERIC_WRITE
+#define ACCESSMODE_RW (GENERIC_READ | GENERIC_WRITE)
+
+#define SHAREMODE_READ FILE_SHARE_READ
+#define SHAREMODE_WRITE FILE_SHARE_WRITE
+#define SHAREMODE_NONE 0
+
+#define FROM_BEGIN FILE_BEGIN
+#define FROM_CURRENT FILE_CURRENT
+#define FROM_END FILE_END
+
+#define SHAREMODE_RW (SHAREMODE_READ | SHAREMODE_WRITE)
+
+
+//
+// assertion support
+//
+// assert - assertion macro. We define our own, because if we abort we need
+// to be able to shut down cleanly (or at least die trying). This
+// version also saves us some code over the C library one.
+//
+// asserte - version of assert that always executes the expression, regardless
+// of debug state.
+//
+#ifdef DEBUG
+#define REGISTER
+#define assert(exp) { \
+ if (!(exp)) \
+ _assertexit (#exp, __FILE__, __LINE__); \
+ }
+#define asserte(exp) assert(exp)
+#else
+#define REGISTER register
+#define assert(exp)
+#define asserte(exp) ((exp) != 0)
+#endif
+
+typedef long LINE; // line number within file
+
+// LINEREC - The text of the file is an array of line pointers/lengths. A
+// single procedure call can be used to grab the line *AND* its length.
+// Color in the file is an array of pointer to attr/length arrays.
+
+typedef struct _lineRecType {
+ PVOID vaLine; // long address of line
+ BOOL Malloced; // Ture if address allocated via malloc
+ int cbLine; // number of bytes in line
+} LINEREC;
+
+// VALINE (l) - Returns virtual address of the line record
+// (lineRecType) for line l.
+
+#define VALINE(l) (pFile->plr + (l))
+
+// Each file that is in memory has a unique descriptor. This is so that
+// editing the same file in two windows will allow updates to be reflected
+// in both.
+//
+// NOTE: pFileNext must be the first field in the structure. Certain places
+// in the code require this.
+
+typedef struct fileType {
+ struct fileType *pFileNext; // next file in chain
+#ifdef DEBUG
+ int id; // debug id byte
+#endif
+ char *pName; // file name
+ LINEREC *plr; // addr of line table
+ BYTE *pbFile; // addr of full file image
+ LINE lSize; // number of lines in block
+ LINE cLines; // number of lines in file
+ PVOID vaColor; // addr of color table
+ PVOID vaHiLite; // highlighting info
+ PVOID vaUndoHead; // head of undo list
+ PVOID vaUndoTail; // end of undo list
+ PVOID vaUndoCur; // current pos in undo list
+ PVOID vaMarks; // Marks in this file
+ int cUndo; // number of undo-able entries
+ int refCount; // reference count window references
+ int type; // type of this file
+ int flags; // flags for dirty, permanent, etc
+ time_t modify; // Date/Time of last modify
+} *PFILE;
+
+
+//
+// for the display manager, there is a separate window allocated for each
+// window on the screen. Each window has display-relevant information.
+//
+typedef struct windowType *PWND;
+
+
+//
+// ext.h is the include file provided to extension writers. It should contain
+// only definitions that are meaningfull to them. The EDITOR definition below
+// prevents it from defining some typedefs and function prototypes which
+// conflict with editor internals.
+//
+#define EDITOR
+#include "ext.h"
+
+struct windowType {
+ struct instanceType *pInstance; // address of instance list
+ sl Size; // size of window
+ sl Pos; // position of window
+};
+
+#define BELL 0x07
+#define SHELL "cmd.exe"
+#define TMPVER "TMP4" // temp file revision
+
+//
+// debug at a certain place
+//
+#if defined (DEBUG)
+
+#define MALLOC(x) DebugMalloc(x, FALSE, __FILE__, __LINE__)
+#define REALLOC(x, y) DebugRealloc(x, y, FALSE, __FILE__, __LINE__)
+#define FREE(x) DebugFree(x, __FILE__, __LINE__)
+#define ZEROMALLOC(x) DebugMalloc(x, TRUE, __FILE__, __LINE__)
+#define ZEROREALLOC(x,y ) DebugRealloc(x, y, TRUE, __FILE__, __LINE__)
+#define MEMSIZE(x) DebugMemSize(x, __FILE__, __LINE__)
+
+#else
+
+#define MALLOC(x) malloc(x)
+#define REALLOC(x, y) realloc(x, y)
+#define FREE(x) free(x)
+#define ZEROMALLOC(x) ZeroMalloc(x)
+#define ZEROREALLOC(x,y ) ZeroRealloc(x, y)
+#define MEMSIZE(x) MemSize(x)
+
+#endif
+
+
+//
+// ID's for assertion checking
+//
+#ifdef DEBUG
+#define ID_PFILE 0x5046 // PF
+#define ID_INSTANCE 0x494E // IN
+#endif
+
+
+//
+// list of files and their debug values
+//
+#define TEXTLINE 0x1
+#define ZALLOC 0x2
+#define VMUTIL 0x4
+#define VM 0x8
+#define FILEIO 0x10
+#define CMD 0x20
+#define PICK 0x40
+#define ZINIT 0x80
+#define WINDOW 0x100
+#define DISP 0x200
+#define Z 0x400
+#define Z19 0x800
+#define LOAD 0x1000
+
+#define MAXWIN 8
+#define MAXMAC 1024
+
+
+
+
+// **************************************************************
+//
+// Macros for accessing fields of struct instanceType
+//
+// **************************************************************
+
+#define XWIN(f) (f)->flWindow.col
+#define YWIN(f) (f)->flWindow.lin
+#define XCUR(f) (f)->flCursorCur.col
+#define YCUR(f) (f)->flCursorCur.lin
+#define FLAGS(f) (f)->flags
+#define XOLDWIN(f) (f)->flOldWin.col
+#define YOLDWIN(f) (f)->flOldWin.lin
+#define XOLDCUR(f) (f)->flOldCur.col
+#define YOLDCUR(f) (f)->flOldCur.lin
+#define FTYPE(f) (f)->type
+
+
+
+
+// **************************************************************
+//
+// VACOLOR (l) - Returns virtual address of the color record
+// (colorRecType) for line l.
+//
+// **************************************************************
+
+#define VACOLOR(l) (PVOID)((PBYTE)pFile->vaColor+sizeof(struct colorRecType)*((long)(l)))
+
+
+
+
+// **************************************************************
+//
+// Flags indicating what has changed since the last display update.
+//
+// RCURSOR: The cursor has moved. This means the cursor should
+// be physically moved on the screen, and that the
+// cursor position status should be changed.
+// RTEXT: The editing area has been changed. A more precise
+// breakdown is available by examining the fChange array.
+// RSTATUS: In the original interface, this means that something
+// on the bottom screen line has changed. In the CW
+// interface, this means something in the status window
+// has changed (either the insert mode or the learn mode)
+// RHIGH: This is set to mean highlighting should be displayed.
+// RFILE: The file-specific information has changed. CW
+// interface only.
+// RHELP: The Help window has changed. CW interface only.
+//
+// **************************************************************
+
+#define RCURSOR 0x01
+#define RTEXT 0x02
+#define RSTATUS 0x04
+#define RHIGH 0x08
+
+
+// **************************************************************
+//
+// argument types and arg structures
+//
+// **************************************************************
+
+#define GETARG (NOARG|TEXTARG|NULLARG|NULLEOL|NULLEOW|LINEARG|STREAMARG|BOXARG)
+ // arg processing required
+
+#define COLORBG -1
+#define COLORNOR 0
+#define COLORINF 1
+#define COLORERR 2
+#define COLORSTA 3
+
+#define INTENSE 8
+
+#define WHITE 7
+#define YELLOW 6
+#define MAGENTA 5
+#define RED 4
+#define CYAN 3
+#define GREEN 2
+#define BLUE 1
+#define BLACK 0
+
+#define B_BAK 0
+#define B_UNDEL 1
+#define B_NONE 2
+
+#define MONO 0
+#define CGA 1
+#define EGA 2
+#define VGA 3
+#define MCGA 4
+#define VIKING 5
+
+#define MAXUSE 20
+#define GRAPH 0x01 // parsing editing chars in macro body
+#define EXEC 0x02 // macro is an execution; ending sets fBreak
+#define INIT 0x04 // macro needs to be initialized
+
+struct macroInstanceType {
+ char *beg; // pointer to beginning of string
+ char *text; // pointer to next command
+ flagType flags; // what type of function is next
+ };
+
+typedef struct macroInstanceType MI, *PMI;
+
+//
+// flags for fChange
+//
+#define FMODIFY 0x01 // TRUE => line was modified
+
+
+
+// **************************************************************
+//
+// Macros for dealing with windows.
+//
+// **************************************************************
+
+#define WINYSIZE(pwin) ((pwin)->Size.lin)
+#define WINXSIZE(pwin) ((pwin)->Size.col)
+#define WINYPOS(pwin) ((pwin)->Pos.lin)
+#define WINXPOS(pwin) ((pwin)->Pos.col)
+#define WININST(pwin) ((pwin)->pInstance)
+
+
+#define XSCALE(x) max(1,(x)*WINXSIZE(pWinCur)/slSize.col)
+#define YSCALE(y) max(1,(y)*WINYSIZE(pWinCur)/slSize.lin)
+
+
+
+// **************************************************************
+//
+// for each instance of a file in memory, there is a window that is
+// allocated for it. The structure has all relevant information for the
+// instance within the window. No display information is kept here
+//
+// **************************************************************
+
+struct instanceType {
+ struct instanceType *pNext; // ptr to next file activation
+#ifdef DEBUG
+ int id; // debug id byte
+#endif
+ PFILE pFile; // ptr to file structure
+ fl flOldWin; // previous file pos of window
+ fl flOldCur; // previous file cursor
+ fl flWindow; // file coord of window
+ fl flCursorCur; // file pos of cursor
+ fl flSaveWin; // saved coord of window
+ fl flSaveCur; // saved y coord of cursor
+ fl flArg; // Last Arg position
+ fl flCursor; // Cursor just before last function
+ flagType fSaved; // TRUE => values below valid
+ };
+
+typedef struct instanceType *PINS;
+
+
+// **************************************************************
+//
+// Each mark that is defined is present in a linked list
+//
+// **************************************************************
+
+typedef struct mark MARK;
+typedef struct filemarks FILEMARKS;
+
+struct mark {
+ unsigned flags; //
+ unsigned cb; // Bytes in this mark structure, including name
+ fl fl; // Location of the mark
+ char szName[1]; // Name of mark
+};
+
+struct filemarks {
+ unsigned cb; // Total bytes in struct, including marks
+ MARK marks[1]; // marks for this file
+ };
+
+
+
+struct colorRecType {
+ PVOID vaColors; // Address of lineAttr array
+ int cbColors;
+ };
+
+extern struct cmdDesc cmdTable[];
+
+extern struct swiDesc swiTable[];
+
+extern char * cftab[];
+
+struct fTypeInfo {
+ char *ext; // extention of file type
+ int ftype; // numerical type
+};
+
+struct compType {
+ struct compType *pNext; // next link in compile list
+ char *pExt; // pointer to extension
+ char *pCompile; // pointer to compile text
+};
+
+typedef struct compType COMP;
+
+#define TEXTFILE 0
+#define CFILE 1
+#define ASMFILE 2
+#define PASFILE 3
+#define FORFILE 4
+#define LSPFILE 5
+#define BASFILE 6
+
+//
+// return values for FileStatus
+//
+#define FILECHANGED 0 // timestamps differ
+#define FILEDELETED 1 // file is not on disk
+#define FILESAME 2 // timestamps match
+
+extern struct fTypeInfo ftypetbl[];
+extern char * mpTypepName[];
+
+
+
+// **************************************************************
+//
+// Initialization flags. These are set when an initialization task has
+// been performed. It is examined in CleanExit to determine what needs
+// to be restored.
+//
+// **************************************************************
+
+#define INIT_VIDEO 1 // Video state is set up
+#define INIT_KBD 2 // Keyboard is set to editor state
+#define INIT_EDITVIDEO 4 // Editor video state is established
+#define INIT_SIGNALS 8 // Signal handlers have been set up
+#define INIT_VM 0x10 // VM has been initialized
+
+
+
+
+// **************************************************************
+//
+// CleanExit() flags
+//
+// **************************************************************
+
+#define CE_VM 1 // Clean Up VM
+#define CE_SIGNALS 2 // Clean up signals
+#define CE_STATE 4 // Update state file
+
+
+
+// **************************************************************
+//
+// zloop() flags
+//
+// **************************************************************
+
+#define ZL_CMD 1 // command key, should be an event
+#define ZL_BRK 2 // take fBreak into account
+
+
+
+// **************************************************************
+//
+// getstring() flags
+//
+// **************************************************************
+
+#define GS_NEWLINE 1 // Entry must be terminated by newline
+#define GS_INITIAL 2 // Entry is hilighted and cleared if graphic
+#define GS_KEYBOARD 4 // Entry must from the keyboard
+#define GS_GETSTR 8 // Called from getstring(), not SDM
+
+
+// **************************************************************
+//
+// type for pointer to function *
+//
+// **************************************************************
+
+typedef void ( *PFUNCTION)(char *, flagType);
+
+//
+// Internal structure of a key
+//
+typedef struct _EDITOR_KEY {
+ KEY_INFO KeyInfo;
+ WORD KeyCode;
+} EDITOR_KEY, *PEDITOR_KEY;
+
+
+
+// **************************************************************
+//
+// Editor Globals.
+//
+// slSize - Under CW, these are the total number of rows and
+// columns available. Without CW, these represent the
+// editing area, which is 2 less.
+//
+// **************************************************************
+
+extern sl slSize; // dimensions of the screen
+#define XSIZE slSize.col
+#define YSIZE slSize.lin
+
+extern PFILE pFilePick; // pick buffer
+extern PFILE pFileFileList; // command line file list
+extern PFILE pFileIni; // TOOLS.INI
+extern PFILE pFileMark; // Current mark definition file
+extern PFILE pFileAssign; // <assign>
+extern struct instanceType *pInsCur; // currently active window
+extern PWND pWinCur; // pointer to current window
+extern struct windowType WinList[]; // head of all windows
+extern int iCurWin; // index of current window
+extern int cWin; // count of active windows
+extern PFILE pFileHead; // address of head of file list
+extern COMP *pCompHead; // address of head of compile extension list
+extern MARK *pMarkHead; // address of head of mark list
+extern char *pMarkFile; // additional file to search for marks
+extern char *pPrintCmd; // pointer to <printcmd> string
+extern PFILE pPrintFile; // file currently printed (to PRN)
+
+//
+// Global vars for the fScan routine.
+//
+extern buffer scanbuf; // buffer for file scanning
+extern buffer scanreal; // buffer for file scanning
+extern int scanlen; // length of said buffer
+extern fl flScan; // file loc of current scan
+extern rn rnScan; // range of scan
+
+#if DEBUG
+extern int debug, indent; // debugging flags
+extern FILEHANDLE debfh; // debugging output file
+#endif
+
+//
+// ARG processing vars
+//
+extern fl flArg; // file pos of 1st arg
+extern int argcount; // number of args hit
+extern flagType fBoxArg; // TRUE => boxarg, FALSE => streamarg
+extern ARG NoArg; // predefined no arg struct
+
+extern flagType fInSelection; // TRUE => Selecting text
+
+extern fl flLow; // low values for args
+extern fl flHigh; // high values for args
+extern LINE lSwitches; // Line # in <assign> of switches
+extern int cRepl; // number of replaces
+extern COL xMargin; // column of right margin
+extern int backupType; // type of backup being done
+extern int cUndelCount; // max num of undel backups of the same file
+extern char *ronlypgm; // program to run on readonly files
+extern buffer buf; // temp line buffer
+extern buffer textbuf; // buffer for text arguments
+extern int Zvideo; // Handle for Z video state
+extern int DOSvideo; // Handle for DOS video state
+extern flagType fAskExit; // TRUE => prompt at exit
+extern flagType fAskRtn; // TRUE => prompt on return from PUSHED
+extern flagType fAutoSave; // TRUE => always save files on switches
+extern flagType fBreak; // TRUE => exit current TopLoop call
+extern flagType fCgaSnow; // TRUE => CGA has snow, so fix it
+extern flagType *fChange; // TRUE => line was changed
+extern unsigned fInit; // Flags describing what has been initialized
+extern flagType fCtrlc; // TRUE => control-c interrupt
+extern flagType fDebugMode; // TRUE => compiles are debug
+extern flagType fMetaRecord; // TRUE => Don't execute anything
+extern flagType fDefaults; // TRUE => do not load users TOOLS.INI
+extern flagType fDisplay; // TRUE => need to redisplay
+extern flagType fDisplayCursorLoc; // TRUE => pos of cursor vs window displayed
+extern flagType fEditRO; // TRUE => allow editting of DISKRO files
+extern flagType fErrPrompt; // TRUE => prompt after errors
+extern flagType fGlobalRO; // TRUE => no editing allowed
+extern flagType fInsert; // TRUE => insertmode is on
+extern flagType fMacroRecord; // TRUE => We're recording into <record>
+extern flagType fMessUp; // TRUE => there is a message on dialog line
+extern flagType fMeta; // TRUE => <meta> command pressed
+extern flagType fMsgflush; // TRUE => flush previous compile messages
+extern flagType fNewassign; // TRUE => <assign> needs refreshing
+extern flagType fRealTabs; // TRUE => tabs are VI-like
+extern flagType fRetVal; // return value of last editing function call
+extern flagType fSaveScreen; // TRUE => Restore DOS screen
+extern flagType fShortNames; // TRUE => do short-filename matching
+extern flagType fSoftCR; // TRUE => use soft carriage returns
+extern flagType fTabAlign; // TRUE => allign cursor to tab characters
+extern flagType fTextarg; // TRUE => text was typed in
+extern flagType fTrailSpace; // TRUE => allow trailing spaces in lines
+extern flagType fWordWrap; // TRUE => space in col 72 goes to newline
+
+//
+// Search/Replace globals
+//
+extern flagType fUnixRE; // TRUE => Use UNIX RE's (unixre: switch)
+extern flagType fSrchAllPrev; // TRUE => previously searched for all
+extern flagType fSrchCaseSwit; // TRUE => case is significant (case: switch)
+extern flagType fSrchCasePrev; // TRUE => case was significant
+extern flagType fSrchDirPrev; // TRUE => previously searched forward
+extern flagType fSrchRePrev; // TRUE => search previously used RE's
+extern flagType fSrchWrapSwit; // TRUE => searches wrap (wrap: switch)
+extern flagType fSrchWrapPrev; // TRUE => previously did wrap
+extern flagType fRplRePrev; // TRUE => replace previously used RE's
+extern buffer srchbuf; // search buffer
+extern buffer srcbuf; // source string for replace
+extern buffer rplbuf; // destination string for replace
+extern flagType fUseMouse; // TRUE => Handle mouse events
+
+#define SIGBREAK 21 // Taken from signal.h
+extern flagType fReDraw; // TRUE => Screen is already locked
+extern unsigned LVBlength; // Bytes in LVB (returned from VioGetBuf)
+extern unsigned kbdHandle; // Handle of logical keyboard
+
+extern HANDLE semIdle; // Idle thread semaphore
+
+extern PCMD *rgMac; // set of macro definitions
+extern int cMac; // number of macros
+
+extern int ballevel; // current level in paren balance
+extern char *balopen, *balclose; // balance open string, close string
+
+extern unsigned kindpick; // what is in the pick buffer
+extern char tabDisp; // character for tab expansion in display
+extern char trailDisp; // Character for trailing spaces
+extern char Name[]; // editor name
+extern char Version[]; // editor version
+extern char CopyRight[]; // editor copyright message
+extern int EnTab; // 0 => no tab 1 => min 2 => max tabification
+extern int tmpsav; // number of past files to remember
+extern int hike; // value of HIKE: switch
+extern int vscroll; // value of VSCROLL: switch
+extern int hscroll; // value of HSCROLL: switch
+extern int tabstops; // value of TABSTOPS: switch
+extern int fileTab; // spacing of tab chars in file
+extern int CursorSize; // cursor size
+extern EDITOR_KEY keyCmd; // last commands keystroke
+#define isaUserMin 21 // cw min isa, for consistancy in indecies
+extern int ColorTab[]; // 16 available colors.
+#define fgColor ColorTab[0] // foreground color
+#define hgColor ColorTab[1] // highlight color
+#define infColor ColorTab[2] // information color
+#define selColor ColorTab[3] // selection color
+#define wdColor ColorTab[4] // window border color
+#define staColor ColorTab[5] // status color
+#define errColor ColorTab[6] // error color
+extern LINE cNoise; // number of lines between noise on status
+extern int cUndo; // count of undo operations retained
+
+extern int cArgs; // number of files on command line
+extern char **pArgs; // pointer to files in command line
+
+extern PFILE pFileIni; // pfile for tools.ini
+
+extern char * pNameEditor; // Base name of editor as invoked
+extern char * pNameTmp; // Pathname of .TMP file ( based on name )
+extern char * pNameInit; // Pathname of tools.ini
+extern char * pNameHome; // "INIT", or "HOME" if "INIT" not defined
+extern char *pComSpec; // name of command processor
+extern char *eolText; // eol characters for text files
+
+
+extern struct cmdDesc cmdUnassigned; // unassigned function
+extern struct cmdDesc cmdGraphic; // self editing function
+
+extern char *getlbuf; // pointer to fast read-in buffer
+extern unsigned getlsize; // length of buffer
+
+extern int cMacUse; // number of macros in use
+extern struct macroInstanceType mi[]; // state of macros
+
+#define MAXEXT 50
+
+extern int cCmdTab; // number of cmd tables
+extern PCMD cmdSet[]; // set of cmd tables
+extern PSWI swiSet[]; // set of swi tables
+extern char *pExtName[]; // set of extension names
+ // CONSIDER: making pExtNames be or include
+ // CONSIDER: the handles, such that arg meta
+ // CONSIDER: load can discard an extension
+
+extern PSCREEN OriginalScreen; // Original screen
+extern PSCREEN MepScreen; // Out screen
+extern KBDMODE OriginalScreenMode; // Original screen Mode
+
+
+// **************************************************************
+//
+// Background threads
+//
+// **************************************************************
+
+//
+// A global critical section is used for synchronizing
+// threads
+//
+extern CRITICAL_SECTION IOCriticalSection;
+extern CRITICAL_SECTION UndoCriticalSection;
+extern CRITICAL_SECTION ScreenCriticalSection;
+
+#define MAXBTQ 32 // Maximum number of entries in
+ // background threads queues
+//
+// Background thread data structure
+//
+typedef struct BTD {
+
+ PFILE pBTFile; // Log file handle
+ LPBYTE pBTName; // Log file name
+ flagType flags; // Flags: BT_BUSY and BT_UPDATE
+ ULONG cBTQ; // # of entries in queue
+ ULONG iBTQPut; // Index at wich to put next
+ ULONG iBTQGet; // Index at wich to get next
+
+ CRITICAL_SECTION CriticalSection;// Protects critical info
+ PROCESS_INFORMATION ProcessInfo; // Process information
+ HANDLE ThreadHandle; // Thread Handle
+ BOOL ProcAlive; // True if child process
+
+ struct {
+ PFUNCTION pBTJProc; // Procedure to call
+ LPBYTE pBTJStr; // Command to spawn or parameter
+ } BTQJob[MAXBTQ]; // Holds queued jobs
+ struct BTD *pBTNext; // Next BTD in list
+} BTD;
+
+//
+// Background threads flags
+//
+
+#define BT_BUSY 1
+#define BT_UPDATE 2
+
+#define fBusy(pBTD) (pBTD->flags & BT_BUSY)
+
+#define UpdLog(pBTD) (pBTD->flags |= BT_UPDATE)
+#define NoUpdLog(pBTD) (pBTD->flags &= ~BT_UPDATE)
+
+//
+// Background compile and print threads
+//
+extern BTD *pBTDComp; // Compile thread
+extern BTD *pBTDPrint; // Print thread
+
+
+//
+// For dual code
+//
+#define PFILECOMP pBTDComp->pBTFile
+
+
+// **************************************************************
+//
+// Constant strings. Various strings that are used many times are
+// defined here once to save space. The values are set in ZINIT.C
+//
+// Macro versions are also defined to cast to a non-const, for use where
+// where only a non-const expression will do.
+//
+// **************************************************************
+
+extern char rgchComp[]; // "<compile>"
+extern char rgchPrint[]; // "<print>"
+extern char rgchAssign[]; // "<assign>"
+extern char rgchAutoLoad[]; // "m*.mxt" or equiv...
+extern char rgchEmpty[]; // ""
+extern char rgchInfFile[]; // "<information-file>"
+extern char rgchWSpace[]; // our defintion of whitespace
+extern char rgchUntitled[]; // "<untitled>"
+
+#define RGCHASSIGN ((char *)rgchAssign)
+#define RGCHEMPTY ((char *)rgchEmpty)
+#define RGCHWSPACE ((char *)rgchWSpace)
+#define RGCHUNTITLED ((char *)rgchUntitled)
+
+
+typedef struct MSG_TXT{
+ WORD usMsgNo;
+ LPBYTE pMsgTxt;
+} MSG_TXT;
+
+extern MSG_TXT MsgStr[]; // Message strings
+
+
+
+
+extern flagType fInCleanExit;
+extern flagType fSpawned;
+
+
+#include "meptype.h"
+#include "msg.h"
+
+
+#ifdef FPO
+#pragma optimize( "y", off )
+#endif
diff --git a/private/utils/mep/inc/mepext.h b/private/utils/mep/inc/mepext.h
new file mode 100644
index 000000000..3632880a7
--- /dev/null
+++ b/private/utils/mep/inc/mepext.h
@@ -0,0 +1,23 @@
+/* zext.h - Z extension structures
+ *
+ * Z extension files are identified as follows:
+ *
+ * o Valid EXE-format files
+ *
+ * Modifications
+ *
+ * 26-Nov-1991 mz Strip off near/far
+ *
+ */
+
+/* The beginning of the user's DS is laid out as follows:
+ */
+
+struct ExtDS {
+ int version;
+ struct cmdDesc *cmdTable;
+ struct swiDesc *swiTable;
+ unsigned dgroup;
+ unsigned cCalls;
+ unsigned (*callout[1])();
+ };
diff --git a/private/utils/mep/inc/meptype.h b/private/utils/mep/inc/meptype.h
new file mode 100644
index 000000000..99f0d1a42
--- /dev/null
+++ b/private/utils/mep/inc/meptype.h
@@ -0,0 +1,590 @@
+/*** ztype.h - forward declarations
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Editor functions - forward type declarations to allow for type-checking
+*
+* Revision History:
+*
+* 26-Nov-1991 mz Strip off near/far
+*************************************************************************/
+
+
+flagType assign (CMDDATA, ARG *, flagType);
+flagType backtab (CMDDATA, ARG *, flagType);
+flagType begfile (CMDDATA, ARG *, flagType);
+flagType begline (CMDDATA, ARG *, flagType);
+flagType BoxStream (CMDDATA, ARG *, flagType);
+flagType cancel (CMDDATA, ARG *, flagType);
+flagType cdelete (CMDDATA, ARG *, flagType);
+flagType compile (CMDDATA, ARG *, flagType);
+flagType curdate (CMDDATA, ARG *, flagType);
+flagType curday (CMDDATA, ARG *, flagType);
+flagType curtime (CMDDATA, ARG *, flagType);
+flagType delete (CMDDATA, ARG *, flagType);
+flagType doarg (CMDDATA, ARG *, flagType);
+flagType down (CMDDATA, ARG *, flagType);
+flagType emacscdel (CMDDATA, ARG *, flagType);
+flagType emacsnewl (CMDDATA, ARG *, flagType);
+flagType endfile (CMDDATA, ARG *, flagType);
+flagType endline (CMDDATA, ARG *, flagType);
+flagType environment (CMDDATA, ARG *, flagType);
+flagType zexecute (CMDDATA, ARG *, flagType);
+flagType zexit (CMDDATA, ARG *, flagType);
+flagType graphic (CMDDATA, ARG *, flagType);
+flagType home (CMDDATA, ARG *, flagType);
+flagType information (CMDDATA, ARG *, flagType);
+flagType zinit (CMDDATA, ARG *, flagType);
+flagType insert (CMDDATA, ARG *, flagType);
+flagType insertmode (CMDDATA, ARG *, flagType);
+flagType lastselect (CMDDATA, ARG *, flagType);
+flagType ldelete (CMDDATA, ARG *, flagType);
+flagType left (CMDDATA, ARG *, flagType);
+flagType linsert (CMDDATA, ARG *, flagType);
+flagType macro (CMDDATA, ARG *, flagType);
+flagType mark (CMDDATA, ARG *, flagType);
+flagType zmessage (CMDDATA, ARG *, flagType);
+flagType meta (CMDDATA, ARG *, flagType);
+flagType mgrep (CMDDATA, ARG *, flagType);
+flagType mlines (CMDDATA, ARG *, flagType);
+flagType mpage (CMDDATA, ARG *, flagType);
+flagType mpara (CMDDATA, ARG *, flagType);
+flagType mreplace (CMDDATA, ARG *, flagType);
+flagType msearch (CMDDATA, ARG *, flagType);
+flagType mword (CMDDATA, ARG *, flagType);
+flagType newline (CMDDATA, ARG *, flagType);
+flagType nextmsg (CMDDATA, ARG *, flagType);
+flagType noedit (CMDDATA, ARG *, flagType);
+flagType noop (CMDDATA, ARG *, flagType);
+flagType pbal (CMDDATA, ARG *, flagType);
+flagType zpick (CMDDATA, ARG *, flagType);
+flagType plines (CMDDATA, ARG *, flagType);
+flagType ppage (CMDDATA, ARG *, flagType);
+flagType ppara (CMDDATA, ARG *, flagType);
+flagType zPrint (CMDDATA, ARG *, flagType);
+flagType psearch (CMDDATA, ARG *, flagType);
+flagType searchall (CMDDATA, ARG *, flagType);
+flagType put (CMDDATA, ARG *, flagType);
+flagType pword (CMDDATA, ARG *, flagType);
+flagType qreplace (CMDDATA, ARG *, flagType);
+flagType quote (CMDDATA, ARG *, flagType);
+flagType record (CMDDATA, ARG *, flagType);
+flagType refresh (CMDDATA, ARG *, flagType);
+flagType repeat (CMDDATA, ARG *, flagType);
+flagType zreplace (CMDDATA, ARG *, flagType);
+flagType sdelete (CMDDATA, ARG *, flagType);
+flagType restcur (CMDDATA, ARG *, flagType);
+flagType right (CMDDATA, ARG *, flagType);
+flagType saveall (CMDDATA, ARG *, flagType);
+flagType savetmpfile (CMDDATA, ARG *, flagType);
+flagType savecur (CMDDATA, ARG *, flagType);
+flagType setfile (CMDDATA, ARG *, flagType);
+flagType setwindow (CMDDATA, ARG *, flagType);
+flagType sinsert (CMDDATA, ARG *, flagType);
+flagType zspawn (CMDDATA, ARG *, flagType);
+flagType tab (CMDDATA, ARG *, flagType);
+flagType ztell (CMDDATA, ARG *, flagType);
+flagType lasttext (CMDDATA, ARG *, flagType);
+flagType promptarg (CMDDATA, ARG *, flagType);
+flagType unassigned (CMDDATA, ARG *, flagType);
+flagType zundo (CMDDATA, ARG *, flagType);
+flagType up (CMDDATA, ARG *, flagType);
+flagType window (CMDDATA, ARG *, flagType);
+flagType SetWinCur (int);
+
+/*************************************************************************
+ *
+ * Exported entries
+ *
+ * Direct Exports
+ */
+PFILE AddFile (char *);
+char BadArg (void);
+void CopyBox (PFILE,PFILE,COL ,LINE ,COL ,LINE ,COL ,LINE);
+void CopyLine (PFILE,PFILE,LINE ,LINE ,LINE);
+void CopyStream (PFILE,PFILE,COL ,LINE ,COL ,LINE ,COL ,LINE);
+flagType DeclareEvent (unsigned, EVTargs *);
+void RegisterEvent (EVT *pEVTDef);
+void DeRegisterEvent (EVT *pEVTDef);
+void DelBox (PFILE, COL, LINE, COL, LINE);
+void DelStream (PFILE, COL, LINE, COL, LINE);
+void DoDisplay (void);
+LINE FileLength (PFILE);
+int fGetMake (int, char *, char *);
+flagType fSetMake (int, char *, char *);
+unsigned short hWalkMake (unsigned short, int *, char *, char *);
+void GetTextCursor (COL *, LINE *);
+flagType GetEditorObject (unsigned, void *, void *);
+void MoveCur (COL ,LINE);
+flagType pFileToTop (PFILE);
+void postspawn (flagType);
+flagType prespawn (flagType);
+
+PCMD ReadCmd (void);
+void RemoveFile (PFILE);
+flagType Replace (char, COL, LINE, PFILE, flagType);
+/*
+ * Routines " ed" through a filter in load.c
+ */
+void DelFile (PFILE, flagType);
+void DelLine (flagType, PFILE, LINE ,LINE);
+void Display (void);
+char fChangeFile (char , char *);
+flagType fExecute (char *);
+PFILE FileNameToHandle (const char *, const char *);
+flagType FileRead (char *,PFILE, flagType);
+flagType FileWrite (char *,PFILE);
+PSWI FindSwitch (char *);
+flagType GetColor (LINE, struct lineAttr *, PFILE);
+flagType GetColorUntabbed(LINE, struct lineAttr *, PFILE);
+int GetLine (LINE ,char *,PFILE);
+int GetLineUntabed (LINE ,char *,PFILE);
+void PutColor (LINE, struct lineAttr *, PFILE);
+void PutColorPhys (LINE, struct lineAttr *, PFILE);
+void PutLine (LINE, char *, PFILE);
+void DelColor (LINE, PFILE);
+int REsearch (PFILE, flagType, flagType, flagType, flagType, struct patType *, fl *);
+int search (PFILE, flagType, flagType, flagType, flagType, char *, fl *);
+flagType SetKey (char *,char *);
+char * GetTagLine (LINE *, char *, PFILE);
+void PutTagLine (PFILE, char *, LINE, COL);
+
+
+/*
+ * Switch setting functions
+ */
+char * SetBackup (char *);
+char * SetCursorSizeSw (char *);
+char * SetExt (char *);
+char * SetFileTab (char *);
+char * SetLoad (char *);
+char * SetMarkFile (char *);
+flagType SetPrintCmd (char *);
+flagType SetROnly (char *);
+flagType SetTabDisp (char *);
+flagType SetTrailDisp (char *);
+char * SetKeyboard (char *);
+
+/* definitions.
+ */
+char * SetCursorSize ( int );
+void resetarg (void);
+void delarg (ARG *);
+flagType fCursor (PCMD);
+flagType fWindow (PCMD);
+flagType Arg (flagType);
+void IncArg (void);
+flagType fGenArg (ARG *, unsigned int);
+void UpdateHighLight(COL, LINE, flagType);
+PCMD NameToFunc (char *);
+flagType DoAssign (char *);
+flagType SetNamedKey (char *,char *);
+flagType SetMacro (const char *, const char *);
+flagType SetSwitch (char *,char *);
+flagType DoCDelete (char);
+char confirm (char *, char *);
+int askuser (int, int, char *,char *);
+void FlushInput (void);
+char * BuildFence (const char *, const char *, char *);
+void DoFence (char *, flagType);
+void cursorfl (fl);
+void docursor (COL ,LINE);
+int dobol (void);
+int doeol (void);
+int doftab (int);
+int dobtab (int);
+flagType DoText (int ,int);
+flagType SplitWnd (PWND, flagType, int);
+void DoStatus (void);
+void redraw (PFILE, LINE ,LINE);
+void newscreen (void);
+void newwindow (void);
+void noise (LINE);
+void cdecl StatusCat (unsigned int, char *, char *, ...);
+void bell (void);
+void makedirty (PFILE);
+void doscreen (COL ,LINE ,COL ,LINE);
+void delay (int);
+void SetScreen (void);
+void HighLight (COL ,LINE ,COL ,LINE);
+void AdjustLines (PFILE, LINE ,LINE);
+flagType UpdateIf (PFILE, LINE, flagType);
+PWND IsVispFile (PFILE, PWND);
+ULONG MepWrite (ULONG Row, ULONG Col, PVOID pBuffer, ULONG BufferSize, DWORD attr, BOOL BlankToEndOfLine, BOOL ShowIt);
+flagType fInRange (long ,long ,long);
+int DisplayLine (int, char *, struct lineAttr **, char *, struct lineAttr **);
+void ShowTrailDisp (buffer, int);
+char * GetFileTypeName(void);
+void SetFileType (PFILE);
+flagType fInitFileMac (PFILE);
+void AutoSave (void);
+void AutoSaveFile (PFILE);
+void IncFileRef (PFILE);
+void DecFileRef (PFILE);
+char fChangeDrive (const char *);
+void zputsinit (void);
+int zputs (char *, int, FILEHANDLE);
+int zputsflush (FILEHANDLE);
+void ReestimateLength (PFILE,FILEHANDLE,long);
+LINE readlines (PFILE, FILEHANDLE);
+char fReadOnly (char *);
+void SaveAllFiles (void);
+char LoadDirectory (char *,PFILE);
+char LoadFake (char *,PFILE);
+char SaveFake (char *,PFILE);
+char fScan (fl,flagType ( *)(void),char, flagType);
+void setAllScan (char);
+PCMD getstring (char *,char *,PCMD,flagType);
+void ScrollOut (char *, char *, int, int, flagType);
+flagType edit (char);
+flagType szEdit (char *);
+void FreeMacs (void);
+void CodeToName (WORD ,char *);
+WORD NameToCode (char *);
+void FuncOut (PCMD, PFILE);
+char * FuncToKey (PCMD, char *);
+void UnassignedOut (PFILE);
+char * FuncToKeys (PCMD, char *);
+PCMD ReadCmdAndKey (char *);
+int tblFind (char * [],char * ,flagType);
+char parseline (char *,char * *,char * *);
+int csoftcr (COL ,LINE ,char *);
+int softcr (void);
+flagType mtest (void);
+flagType mlast (void);
+flagType fFindLabel (struct macroInstanceType *,buffer);
+void mPopToTop (void);
+PCMD mGetCmd (void);
+flagType fParseMacro (struct macroInstanceType *, char *);
+int fMacResponse (void);
+
+flagType GoToMark (char *);
+PFILE FindMark (char *, fl *, flagType);
+MARK * FindLocalMark (char *, flagType);
+MARK * GetMarkFromLoc (LINE, COL);
+void MarkInsLine (LINE, LINE, PFILE);
+void MarkDelLine (PFILE, LINE, LINE);
+void MarkDelStream (PFILE, COL, LINE, COL, LINE);
+void MarkDelBox (PFILE, COL, LINE, COL, LINE);
+flagType fReadMarks (PFILE);
+void WriteMarks (PFILE);
+void UpdMark (FILEMARKS **, char *, LINE, COL, flagType);
+void DefineMark (char *, PFILE, LINE, COL, flagType);
+void DeleteMark (char *);
+void DelPMark (MARK *);
+void MarkCopyLine (PFILE, PFILE, LINE, LINE, LINE);
+void MarkCopyBox (PFILE, PFILE, COL, LINE, COL, LINE, COL, LINE);
+FILEMARKS * GetFMFromFile (PFILE, COL, LINE, COL, LINE);
+void AddFMToFile (PFILE, FILEMARKS *, COL, LINE);
+void FreeCache (void);
+flagType fCacheMarks (PFILE);
+void AdjustMarks (MARK *, LINE);
+flagType fMarkIsTemp (char *);
+flagType fFMtoPfile (PFILE, FILEMARKS *);
+PVOID FMtoVM (FILEMARKS *);
+PVOID GetMarkRange (PFILE, LINE, LINE);
+void PutMarks (PFILE, PVOID, LINE);
+int flcmp (fl *, fl *);
+
+char fDoBal (void);
+int InSet (char ,char *);
+void pick (COL ,LINE ,COL ,LINE ,int);
+void ReplaceEdit (char *,char *);
+void simpleRpl (char *);
+void patRpl (void);
+char fDoReplace (void);
+flagType doreplace (flagType, ARG *, flagType, flagType);
+void AppFile (char *, PFILE);
+void appmsgs (int, PFILE);
+void showasg (PFILE);
+flagType infprint (PFILE,PFILE);
+void showinf (PFILE);
+void ShowMake (PFILE);
+int TabMin (int ,char *,char *);
+int TabMax (int ,char *,char *);
+int LineLength (LINE ,PFILE);
+void InsertLine (LINE, char *, PFILE);
+LINE zprintf (PFILE, LINE, char const *, ...);
+int gettextline (char ,LINE ,char *,PFILE, char);
+int getcolorline (flagType, LINE, struct lineAttr *, PFILE);
+void puttextline (flagType, flagType, LINE, char *, PFILE);
+void putcolorline (flagType, LINE, struct lineAttr *, PFILE);
+void BlankLines (LINE ,PVOID);
+void BlankColor (LINE, PVOID);
+void growline (LINE ,PFILE);
+void InsLine (flagType, LINE ,LINE ,PFILE);
+flagType fInsSpace (COL ,LINE ,int ,PFILE, linebuf);
+flagType fInsSpaceColor (COL ,LINE ,int ,PFILE, linebuf, struct lineAttr *);
+void delspace (COL ,LINE ,int ,PFILE, linebuf);
+int fcolcpy (struct lineAttr * , struct lineAttr * );
+void ShiftColor (struct lineAttr [], COL, int);
+void SetColor (PFILE, LINE, COL, COL, int);
+void CopyColor (PFILE, PFILE, LINE, COL, COL, LINE, COL);
+void SetColorBuf (struct lineAttr *, COL, int, int);
+flagType fGetColorPos (struct lineAttr **, COL *);
+void ColorToPhys (struct lineAttr *, LINE, PFILE);
+void ColorToLog (struct lineAttr *, char *);
+
+void SetHiLite (PFILE, rn, int);
+void ClearHiLite (PFILE, flagType);
+flagType UpdHiLite (PFILE, LINE, COL, COL, struct lineAttr **);
+void UpdOneHiLite (struct lineAttr *, COL, COL, flagType, int);
+void rnOrder (rn *);
+
+void BoxToStream (ARG *);
+void StreamToBox (ARG *);
+
+void AckReplace (LINE, flagType);
+void AckMove (LINE, LINE);
+void DoAssignLine (LINE);
+void UpdToolsIni (char *);
+LINE FindMatchLine (char *, char *, char *, int, LINE *);
+
+void GetCurPath (char *);
+flagType SetCurPath (char *);
+
+flagType ExpungeFile (void);
+void FreeFileVM (PFILE);
+PFILE pFileLRU (PFILE);
+
+
+void saveflip (void);
+void restflip (void);
+void movewin (COL ,LINE);
+void SortWin (void);
+int WinInsert (PWND);
+char Adjacent (int ,int);
+char WinClose (int);
+char fDoWord (void);
+PCMD zloop (flagType);
+flagType zspawnp (char const *, flagType);
+flagType DoCancel (void);
+char testmeta (void);
+char * ZMakeStr (const char *);
+void TCcursor (char ,char);
+
+#define sout(x,y,p,clr) ((int)x + MepWrite(y, x, p, strlen(p), clr, FALSE, fReDraw))
+#define soutb(x,y,p,clr) ((int)x + MepWrite(y, x, p, strlen(p), clr, TRUE, fReDraw))
+#define vout(x,y,p,c,clr) ((int)x + MepWrite(y, x, p, c, clr, FALSE, fReDraw))
+#define voutb(x,y,p,c,clr) ((int)x + MepWrite(y, x, p, c, clr, TRUE, fReDraw))
+
+#define consoleMoveTo(y, x) consoleSetCursor(MepScreen, y, x)
+
+
+int coutb (int ,int ,char *,int ,struct lineAttr *);
+void ToRaw (void);
+void ToCooked (void);
+char * VideoTag (void);
+char * whiteskip (char const *);
+char * whitescan (char const *);
+int RemoveTrailSpace (char *);
+char * DoubleSlashes (char *);
+char * UnDoubleSlashes(char *);
+flagType FmtAssign (char *, ...);
+flagType SendCmd (PCMD);
+void RecordCmd (PCMD);
+void RecordString (char *);
+void AppendMacroToRecord (PCMD);
+flagType fSyncFile (PFILE, flagType);
+void RemoveInstances(PFILE);
+int FileStatus (PFILE, char *);
+void SetModTime (PFILE);
+time_t ModTime (char *);
+void LengthCheck (LINE, int, char *);
+void IntError (char *);
+#if 0
+flagType CheckForDirt (void);
+#else
+flagType fSaveDirtyFiles(void);
+#endif
+flagType InitExt (char *);
+LINE DoInit (char *, char *, LINE);
+char * IsTag (char *);
+LINE LocateTag (PFILE, char *);
+char * GetIniVar (char *, char *);
+int loadini (flagType);
+int init (void);
+void WriteTMPFile (void);
+flagType ReadTMPFile ();
+void RemoveTop (void);
+flagType dosearch (flagType, ARG *, flagType, flagType);
+int REsearchS (PFILE, flagType, flagType, flagType, flagType, char *, fl *);
+void mgrep1file (char *, struct findType *, void *);
+void mrepl1file (char *, struct findType *, void *);
+flagType mgrep1env (char *, va_list);
+flagType fFileAdvance (void);
+LINE SetFileList (void);
+void TopLoop (void);
+void LeaveZ (void);
+void CleanExit (int, flagType);
+flagType fPushEnviron (char *, flagType);
+flagType fIsNum (char *);
+void InitNames (char *);
+void ParseCmd (char *, char **, char **);
+flagType fIsBlank (PFILE, LINE);
+flagType fVideoAdjust (int, int);
+
+
+flagType disperr (int, ...);
+flagType dispmsg (int, ...);
+int domessage (char *, ...);
+int printerror (char *,...);
+char * GetMsg (unsigned, char *);
+void CreateUndoList (PFILE);
+void LinkAtHead (PVOID, union Rec *,PFILE);
+int FreeUndoRec (flagType,PFILE);
+int UnDoRec (PFILE);
+void LogReplace (PFILE, LINE, LINEREC *, struct colorRecType *);
+void LogInsert (PFILE, LINE, LINE);
+void LogDelete (PFILE, LINE, LINE);
+void LogBoundary (void);
+int ReDoRec (PFILE);
+flagType fIdleUndo (flagType);
+void FlushUndoBuffer (void);
+void RemoveUndoList (PFILE);
+flagType fundoable (flagType);
+LINE updateLine (PFILE, LINE);
+LINE unupdateLine (PFILE, LINE);
+
+int ZFormat (REGISTER char *, const REGISTER char *, va_list);
+
+/* Declarations controlled by C runtime
+ */
+int CtrlC (ULONG);
+void _CRTAPI1 main (int ,char * *);
+
+#if defined (DEBUG)
+
+void * DebugMalloc (int, BOOL, char *, int);
+void * DebugRealloc (void *, int, BOOL, char *, int);
+void DebugFree (void *, char *, int);
+unsigned DebugMemSize (void *, char *, int);
+
+#endif
+/*
+ * Debugging assertion support
+ */
+#ifdef DEBUG
+void _assertexit (char *, char *, int);
+void _heapdump (char *);
+flagType _pfilechk (void);
+flagType _pinschk (PINS);
+void * _nearCheck (void *, char *, char *, int);
+#endif
+
+void * ZeroMalloc (int);
+void * ZeroRealloc (void *, int);
+unsigned MemSize (void *);
+
+/* Assembly declarations
+ */
+int fstrnicmp (char *, char *, int);
+char * fstrcpy (char *, char *);
+int fstrlen (char *);
+int zfstrcmp (char *, char *);
+int fstricmp (char *, char *);
+int iHash (long, int);
+
+int Untab (int, const char*, int, char*, char);
+COL AlignChar (COL, const char*);
+
+void KbHookAsm (void);
+flagType SetKBType (void);
+void GetScreenSize (int *, int *);
+flagType SetScreenSize (int, int);
+void SetVideoState (int);
+void SaveScreen (void);
+void RestoreScreen (void);
+void WindowChange ( ROW Rows, COLUMN Cols);
+int LineOut (int, int, const char *, int, int);
+int LineOutB (int, int, const char *, int, int);
+void HWInit (void);
+void HWReset (void);
+flagType Idle (void);
+//void Yield (void);
+//char * lsearch (char *, int, char *, int);
+
+int DosLoadModuleHack (char *, int, char *, unsigned int *);
+void IdleThread ( void );
+int OS2toErrno (int);
+char * OS2toErrText (int, char *);
+
+flagType fMapEnv (char *pSrc, char *pDst, int cbDst);
+flagType fSetEnv (char *p);
+void showenv (PFILE pFile);
+/*
+ * Extension Load/Auto-Load
+ */
+#if defined (HELP_HACK )
+char * HelpLoad(void);
+#endif
+char * load (char *, flagType);
+void AutoLoadExt (void);
+flagType AutoLoadDir (char *, va_list);
+void AutoLoadFile (char *, struct findType *, void *);
+
+/*
+ * Printing
+ */
+
+flagType DoPrint (PFILE, flagType);
+PFILE GetTmpFile (void);
+
+
+void CleanPrint (char *, flagType);
+
+
+
+/*
+ * Background Threads
+ */
+
+BTD* BTCreate (char *);
+flagType BTAdd (BTD *, PFUNCTION, char *);
+flagType BTKill (BTD *);
+flagType BTKillAll (void);
+flagType BTWorking (void);
+void BTIdle (void);
+void BThread (BTD *);
+
+
+/*
+ * List handling module
+ */
+void ListWalker (PCMD, flagType ( *)(PCMD, char *, PMI, int), flagType);
+char * ScanList (PCMD, flagType);
+char * ScanMyList (PCMD, PMI, buffer, flagType);
+flagType fParseList (PMI,char *);
+flagType fScanPush (PMI);
+flagType fScanPop (PMI);
+PCMD GetListHandle (char *, flagType);
+void AddStrToList (PCMD, char *);
+flagType fInList (PCMD, char *, flagType);
+flagType fDelStrFromList(PCMD, char *, flagType);
+flagType CheckAndDelStr (PCMD, char *, PMI, int);
+char * GetListEntry (PCMD, int, flagType);
+int ListLen (PCMD, flagType);
+flagType fEmptyList (PCMD);
+void InitParse (PCMD, PMI);
+void Listize (char *);
+char * CanonFilename (char * src, char * dst);
+flagType fEnvar (char *);
+void ClearList (PCMD);
+/*
+ * real tabs
+ */
+char * pLog (char*, COL, flagType);
+int cbLog (char *);
+COL colPhys (char *, char *);
+COL DecCol (COL, char *);
+COL IncCol (COL, char *);
+
+
+FILEHANDLE MepFOpen (LPBYTE FileName, ACCESSMODE Access, SHAREMODE Share, BOOL fCreate);
+void MepFClose (FILEHANDLE Handle );
+DWORD MepFRead (PVOID pBuffer, DWORD Size, FILEHANDLE Handle);
+DWORD MepFWrite (PVOID pBuffer, DWORD Size, FILEHANDLE Handle);
+DWORD MepFSeek (FILEHANDLE Handle, DWORD Distance, MOVEMETHOD MoveMethod);
+
+#pragma intrinsic( memset, memcpy )
+
diff --git a/private/utils/mep/inc/mouse.h b/private/utils/mep/inc/mouse.h
new file mode 100644
index 000000000..6448d592f
--- /dev/null
+++ b/private/utils/mep/inc/mouse.h
@@ -0,0 +1,35 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ mouse.h
+
+Abstract:
+
+ Mouse management for MEP
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 07-Nov-1991
+
+
+Revision History:
+
+
+--*/
+
+
+//
+// Mouse flags
+//
+#define MOUSE_CLICK_LEFT 0x0001
+#define MOUSE_CLICK_RIGHT 0x0002
+#define MOUSE_DOUBLE_CLICK 0x0010
+
+
+//
+// The Mouse handler
+//
+void DoMouse( ROW Row, COLUMN Col, DWORD MouseFlags );
diff --git a/private/utils/mep/inc/msg.h b/private/utils/mep/inc/msg.h
new file mode 100644
index 000000000..1045d45b2
--- /dev/null
+++ b/private/utils/mep/inc/msg.h
@@ -0,0 +1,63 @@
+#define MSGERR_INV_ARG 8001
+#define MSGERR_ARG_REQ 8002
+#define MSGERR_NOEDIT 8003
+#define MSGERR_NOREP 8004
+#define MSGERR_NOCREAT 8005
+#define MSGERR_OPEN 8006
+#define MSGERR_RONLY 8007
+#define MSGERR_SPACE 8008
+#define MSGERR_DEL 8009
+#define MSGERR_REN 8010
+#define MSGERR_OLDVER 8011
+#define MSGERR_SAVEDIR 8012
+#define MSGERR_STFILE 8013
+#define MSGERR_UNDO 8014
+#define MSGERR_REDO 8015
+#define MSGERR_ITHREAD 8016
+#define MSGERR_CTHREAD 8017
+#define MSGERR_PTHREAD 8018
+#define MSGERR_TOOLS 8019
+#define MSGERR_ZFORMAT 8020
+#define MSGERR_ZTELL 8021
+#define MSGERR_CMPCMD 8022
+#define MSGERR_CMPCMD2 8023
+#define MSGERR_CMPFULL 8024
+#define MSGERR_CMPCANT 8025
+#define MSGERR_CMPSRC 8026
+#define MSGERR_PRTFULL 8027
+#define MSGERR_PRTCANT 8028
+#define MSGERR_NOMEM 8029
+#define MSGERR_QUIT 8030
+#define MSG_ASSIGN_HDR 9001
+#define MSG_SWITCH_HDR 9025
+#define MSG_KEYS_HDR1 9050
+#define MSG_KEYS_HDR2 9054
+#define MSG_ASG_FUNC 9061
+#define MSG_ASG_MACROS 9062
+#define MSG_ASG_NUMER 9063
+#define MSG_ASG_BOOL 9064
+#define MSG_ASG_TEXT 9065
+#define MSG_ASG_CLIP 9066
+#define MSG_ASG_LINES 9067
+#define MSG_ASG_PAGES 9068
+#define MSG_PRESS_ANY 10000
+#define MSG_ARGCOUNT 10001
+#define MSG_NEXTFILE 10002
+#define MSG_SAVING 10003
+#define MSG_TELLPROMPT 10004
+#define MSG_SAVEALL 10005
+#define MSG_SAVEONE 10006
+#define MSG_QUEUED 10007
+#define MSG_CMPDONE 10008
+#define MSG_PRINTING 10009
+#define MSG_SCANFILE 10010
+#define MSG_ASN_MISS 10100
+#define MSG_ASN_MISSK 10101
+#define MSG_ASN_UNKKEY 10102
+#define MSG_ASN_INUSE 10103
+#define MSG_ASN_MROOM 10104
+#define MSG_ASN_NOTSWI 10105
+#define MSG_ASN_ILLSET 10106
+#define MSG_ASN_WINCHG 10107
+#define MSG_ASN_UNSUP 10108
+#define MSG_ASN_INVAL 10109
diff --git a/private/utils/mep/inc/version.h b/private/utils/mep/inc/version.h
new file mode 100644
index 000000000..58d5056cb
--- /dev/null
+++ b/private/utils/mep/inc/version.h
@@ -0,0 +1,4 @@
+#define rmj 2
+#define rmm 0
+#define rup 0
+#define szVerName "( Windows NT )"
diff --git a/private/utils/mep/src/arg.c b/private/utils/mep/src/arg.c
new file mode 100644
index 000000000..d9c427c37
--- /dev/null
+++ b/private/utils/mep/src/arg.c
@@ -0,0 +1,929 @@
+/*** arg.c - argument handler
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+*
+* 26-Nov-1991 mz Strip out near/far
+*
+*************************************************************************/
+#include "mep.h"
+
+
+typedef flagType (*FUNCSAVED)(CMDDATA, ARG *, flagType);
+
+PVOID vaHiLiteSave = (PVOID)(-1L);
+fl flLastArg;
+fl flLastCursor;
+
+//
+// Globals set by SendCmd and used by repeat to repeat the last command
+//
+flagType fOKSaved = FALSE;
+FUNCSAVED funcSaved;
+CMDDATA argDataSaved;
+ARG argSaved;
+flagType fMetaSaved;
+
+
+
+/*** doarg - perform arg processing
+*
+* doarg is the editor function that is used to indicate the beginning of
+* an argument to an editor function.
+*
+* Input:
+* Standard Editting Function (Everything ignored).
+*
+* Output:
+* Returns the value returned by editor function that terminates arg. If
+* invalid arg was found, then the return is FALSE.
+*
+*************************************************************************/
+flagType
+doarg (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ ) {
+
+ return Arg (FALSE);
+ argData; pArg; fMeta;
+}
+
+
+
+/*** resetarg - throw away all arg input and restore cursor position.
+*
+* Several functions (cancel, invalid args) discard the current arg context.
+* We parse the current arg input and then reset the cursor to the original
+* position.
+*
+* Input:
+* nothing
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void
+resetarg (void)
+{
+ UpdateHighLight (-1, -1L, FALSE);
+ pInsCur->pFile->vaHiLite = vaHiLiteSave;
+ vaHiLiteSave = (PVOID)(-1L);
+ if (argcount)
+ pInsCur->flCursorCur = flArg;
+ argcount = 0;
+}
+
+
+
+/*** fCursor - decide if an editor function is a cursor movement function
+*
+* When reading in an argument, editor functions that move the cursor are
+* allowed as long as no text has been input. fCursor defines that set
+* of allowed functions.
+*
+* Input:
+* pCmd = pointer to the internal editor function
+*
+* Output:
+* Returns TRUE if pCmd is a cursor movement function
+*
+*************************************************************************/
+flagType
+fCursor (
+ PCMD pCmd
+ ) {
+ return (flagType) TESTFLAG (pCmd->argType, CURSORFUNC);
+}
+
+
+
+/*** fWindow - decide if an editor function is a window movement function
+*
+* After highlighting text, we are allowed to move the window about via
+* window movement functions without removing the highlight. fWindow
+* defines that set of window functions.
+*
+* Input:
+* pf = pointer to the internal editor function
+*
+* Output:
+* Returns TRUE if pf is a window movement function
+*
+*************************************************************************/
+flagType fWindow (
+ PCMD pCmd
+ ) {
+ return (flagType) TESTFLAG (pCmd->argType, WINDOWFUNC);
+}
+
+
+
+/*** Arg - perform all low-level arg processing
+*
+* Arg () is responsible for the display of the arg, handling all cursor
+* movement, handling textarg input.
+*
+* Input:
+* fToText = TRUE => go immediately to text arg processing, else allow
+* allow cursor movement
+* fRestore = TRUE => Establish a test selection before continuing
+* Output:
+* Returns value returned by editor function that terminates arg. If invalid
+* arg was found, then the return is FALSE.
+*
+*************************************************************************/
+flagType
+Arg (
+ flagType fRestore
+ ) {
+ REGISTER PCMD pFunc = NULL;
+ char p[20];
+ char tbuf[20];
+
+ /*
+ * We are being called for a lastselect. Restore the
+ * text selection stored in pInsCur and continue
+ */
+ if (fRestore) {
+ vaHiLiteSave = pInsCur->pFile->vaHiLite;
+ ClearHiLite (pInsCur->pFile, FALSE);
+ flArg = pInsCur->flArg;
+ cursorfl (pInsCur->flCursor);
+ UpdateHighLight (XCUR(pInsCur), YCUR(pInsCur), TRUE);
+ argcount++;
+ } else {
+ IncArg ();
+ }
+
+ if (!mtest()) {
+ dispmsg (MSG_ARGCOUNT,argcount);
+ }
+
+ /*
+ * Loop to do do cursor movements and display any extra arg indicators
+ */
+
+ fInSelection = TRUE;
+
+ while (TRUE) {
+ if ((pFunc = zloop (ZL_BRK)) == NULL) {
+ return FALSE;
+ } else if ((PVOID)pFunc->func == (PVOID)doarg) {
+ argcount++;
+ if (!mtest()) {
+ dispmsg (MSG_ARGCOUNT,argcount);
+ }
+ } else if (fCursor (pFunc) || (PVOID)pFunc->func == (PVOID)meta) {
+ fRetVal = SendCmd (pFunc);
+ UpdateHighLight ( XCUR(pInsCur), YCUR(pInsCur), TRUE);
+ } else {
+ break;
+ }
+ }
+
+ fInSelection = FALSE;
+
+ /*
+ * Get text arg, if needed.
+ * Note that we only accept textarg if no cursor movement occured
+ */
+ if ( (((PVOID)pFunc->func == (PVOID)graphic) ||
+ ((PVOID)pFunc->func == (PVOID)quote))
+ && (pInsCur->flCursorCur.lin == flArg.lin)
+ && (pInsCur->flCursorCur.col == flArg.col)
+ ) {
+ fTextarg = TRUE;
+ sprintf(p,GetMsg(MSG_ARGCOUNT, tbuf), argcount);
+ strcat (p, ": ");
+ textbuf[0] = '\0';
+ pFunc = getstring (textbuf, p, pFunc, FALSE);
+ }
+
+ /*
+ * If textarg ended in valid function, execute it.
+ */
+ if (pFunc != NULL) {
+ if (!fTextarg) {
+ pInsCur->flArg = flArg;
+ pInsCur->flCursor = pInsCur->flCursorCur;
+ }
+ return (SendCmd (pFunc));
+ }
+
+ return FALSE;
+}
+
+
+
+/*** IncArg - Increment the arg count
+*
+* If first arg, save current highlight info on th file, and clear any
+* highlighting on screen. Set flArg to be the arg start position, and
+* highlight that position.
+*
+* Input:
+* Nothing
+*
+* Output:
+* Nothing
+*
+*************************************************************************/
+void IncArg (
+) {
+ if (!argcount++) {
+ vaHiLiteSave = pInsCur->pFile->vaHiLite;
+ ClearHiLite (pInsCur->pFile, FALSE);
+ flArg = pInsCur->flCursorCur;
+ UpdateHighLight (XCUR(pInsCur)+1, YCUR(pInsCur), TRUE);
+ }
+}
+
+
+
+/**** fGenArg - generate the argument based upon editor state
+*
+* fGenArg is called to convert the combination of arg, cursor, and
+* additional text into an argument structure to be handed to the editor
+* functions.
+*
+* Input:
+* pArg = pointer to arg structure that will be filled in
+* flags = bit vector indicating type of arg processing required
+*
+* Globals:
+* argcount = number of times ARG has been hit
+* fBoxArg = Determines argument type (non-CW)
+* SelMode = Determines argument type (CW)
+* flArg = File location of arg cursor (may be updated)
+* fTextarg = TRUE => textarg is present
+* pInsCur = used for current user cursor location
+* textbuf = buffer containing any text argument
+*
+* Output:
+* Returns TRUE if a valid argument was parsed off, FALSE otherwise
+*
+*************************************************************************/
+flagType
+fGenArg (
+ REGISTER ARG *pArg,
+ unsigned int flags
+ ) {
+ int cArg = argcount;
+ long numVal = 0; /* value of numarg */
+ flagType fTextArgLocal = fTextarg;
+
+ fTextarg = FALSE;
+ argcount = 0;
+ if (cArg == 0) {
+ if (TESTFLAG (flags, NOARG)) {
+ pArg->argType = NOARG;
+ pArg->arg.noarg.y = YCUR(pInsCur);
+ pArg->arg.noarg.x = XCUR(pInsCur);
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ } else {
+ fl flLow;
+ fl flHigh;
+ fl flCur;
+
+ flCur = pInsCur->flCursorCur;
+
+ cursorfl (flArg);
+ /* Specially handle text arguments. User may specify a
+ * number or a mark that will define the other endpoint
+ * of an arg region.
+ */
+ if (fTextArgLocal) {
+ if (TESTFLAG (flags, NUMARG) && fIsNum (textbuf)) {
+
+ numVal = atol (textbuf);
+ if (numVal != 0)
+ flArg.lin = lmax ((LINE)0, flArg.lin + numVal + (numVal > 0 ? -1 : 1));
+ fTextArgLocal = FALSE;
+ } else if (TESTFLAG (flags,MARKARG) && FindMark (textbuf, &flArg, FALSE)) {
+ fTextArgLocal = FALSE;
+ }
+ }
+
+ flLow.col = min (flArg.col, flCur.col);
+ flHigh.col = max (flArg.col, flCur.col);
+ flLow.lin = lmin (flArg.lin, flCur.lin);
+ flHigh.lin = lmax (flArg.lin, flCur.lin);
+
+ /* flArg represents the location of one part of an argument
+ * and the current cursor position represent the location of the
+ * other end. Based upon the flags, we ascertain what type of
+ * argument is intended.
+ */
+ if (fTextArgLocal) {
+ if (TESTFLAG (flags, TEXTARG)) {
+ pArg->argType = TEXTARG;
+ pArg->arg.textarg.cArg = cArg;
+ pArg->arg.textarg.y = flCur.lin;
+ pArg->arg.textarg.x = flCur.col;
+ pArg->arg.textarg.pText = (char *) textbuf;
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ } else if (flCur.col == flArg.col && flCur.lin == flArg.lin && numVal == 0) {
+ if (TESTFLAG (flags, NULLARG)) {
+ pArg->argType = NULLARG;
+ pArg->arg.nullarg.cArg = cArg;
+ pArg->arg.nullarg.y = flCur.lin;
+ pArg->arg.nullarg.x = flCur.col;
+ return TRUE;
+ } else if (TESTFLAG (flags, NULLEOL | NULLEOW)) {
+ fInsSpace (flArg.col, flArg.lin, 0, pFileHead, textbuf);
+ if (TESTFLAG (flags, NULLEOW)) {
+ *whitescan (pLog(textbuf, flArg.col, TRUE)) = 0;
+ }
+ strcpy (&textbuf[0], pLog (textbuf, flArg.col, TRUE));
+ pArg->argType = TEXTARG;
+ pArg->arg.textarg.cArg = cArg;
+ pArg->arg.textarg.y = flCur.lin;
+ pArg->arg.textarg.x = flCur.col;
+ pArg->arg.textarg.pText = (char *) textbuf;
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ } else if (TESTFLAG (flags, BOXSTR) && flCur.lin == flArg.lin) {
+ fInsSpace (flHigh.col, flArg.lin, 0, pFileHead, textbuf);
+ *pLog (textbuf, flHigh.col, TRUE) = 0;
+ strcpy (&textbuf[0], pLog (textbuf, flLow.col, TRUE));
+ pArg->argType = TEXTARG;
+ pArg->arg.textarg.cArg = cArg;
+ pArg->arg.textarg.y = flArg.lin;
+ pArg->arg.textarg.x = flArg.col;
+ pArg->arg.textarg.pText = (char *) textbuf;
+ return TRUE;
+ } else if (fBoxArg) {
+ if (TESTFLAG (flags, LINEARG) && flArg.col == flCur.col) {
+ pArg->argType = LINEARG;
+ pArg->arg.linearg.cArg = cArg;
+ pArg->arg.linearg.yStart = flLow.lin;
+ pArg->arg.linearg.yEnd = flHigh.lin;
+ return TRUE;
+ } else if (TESTFLAG (flags, BOXARG) && flArg.col != flCur.col) {
+ pArg->argType = BOXARG;
+ pArg->arg.boxarg.cArg = cArg;
+ pArg->arg.boxarg.yTop = flLow.lin;
+ pArg->arg.boxarg.yBottom = flHigh.lin;
+ pArg->arg.boxarg.xLeft = flLow.col;
+ pArg->arg.boxarg.xRight = flHigh.col-1;
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ } else if (TESTFLAG (flags, STREAMARG)) {
+ pArg->argType = STREAMARG;
+ pArg->arg.streamarg.cArg = cArg;
+ if (flCur.lin > flLow.lin) {
+ pArg->arg.streamarg.yStart = flArg.lin;
+ pArg->arg.streamarg.xStart = flArg.col;
+ pArg->arg.streamarg.yEnd = flCur.lin;
+ pArg->arg.streamarg.xEnd = flCur.col;
+ } else if (flArg.lin == flCur.lin) {
+ pArg->arg.streamarg.yStart = pArg->arg.streamarg.yEnd = flArg.lin;
+ pArg->arg.streamarg.xStart = flLow.col;
+ pArg->arg.streamarg.xEnd = flHigh.col;
+ } else {
+ pArg->arg.streamarg.yStart = flCur.lin;
+ pArg->arg.streamarg.xStart = flCur.col;
+ pArg->arg.streamarg.yEnd = flArg.lin;
+ pArg->arg.streamarg.xEnd = flArg.col;
+ }
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+}
+
+
+
+/*** BadArg - inform the user that an invalid arg was input
+*
+* Clear arg & print standard error message.
+*
+* Input:
+* none
+*
+* Output:
+* Returns FALSE
+*
+*************************************************************************/
+flagType
+BadArg ()
+{
+ resetarg ();
+ return disperr (MSGERR_INV_ARG);
+}
+
+
+
+/*** SendCmd - take a CMD and call it with the appropriate argument parsing
+*
+* If the function to be executed is not a window movement command nor a
+* cursor movement command, we remove any highlighting that is present. For
+* cleanliness, we pass a NOARG to cursor and window functions if none is
+* specified. If the function takes args, we decode them. Any errors report
+* back at this point. Finally, we dispatch to the function, sending him the
+* appropriate argument.
+*
+* Input:
+* pCmd = pointer to command to execute.
+*
+* Output:
+* Returns value returned by command
+*
+*************************************************************************/
+flagType
+SendCmd (
+PCMD pCmd
+) {
+ ARG arg;
+ flagType fMeta = (flagType) (TESTFLAG (pCmd->argType, KEEPMETA) ? FALSE : testmeta ());
+ flagType fArg = (flagType) argcount;
+
+ arg.argType = NOARG;
+ arg.arg.noarg.x = XCUR(pInsCur);
+ arg.arg.noarg.y = YCUR(pInsCur);
+
+ if (TESTFLAG(pCmd->argType, GETARG)) {
+ if (!fGenArg (&arg, pCmd->argType)) {
+ if (fArg) {
+ BadArg ();
+ } else {
+ disperr (MSGERR_ARG_REQ);
+ }
+ return FALSE;
+ }
+ if (!fCursor (pCmd) && ! fWindow (pCmd)) {
+
+ // Not a coursor position.
+ // discard any pre-existing highlighting.
+
+ PVOID vaSave;
+
+ vaSave = pInsCur->pFile->vaHiLite;
+ pInsCur->pFile->vaHiLite = vaHiLiteSave;
+ vaHiLiteSave = (PVOID)(-1L);
+ ClearHiLite (pInsCur->pFile, TRUE);
+
+ pInsCur->pFile->vaHiLite = vaSave;
+ } else if (vaHiLiteSave == (PVOID)(-1L)) {
+
+ // Preserve pre-existing hilighting
+
+ vaHiLiteSave = pInsCur->pFile->vaHiLite;
+ ClearHiLite (pInsCur->pFile, FALSE);
+ }
+ resetarg ();
+ }
+
+ if ( TESTFLAG (pCmd->argType, MODIFIES)
+ && (TESTFLAG (pFileHead->flags, READONLY) || fGlobalRO)) {
+ return disperr (MSGERR_NOEDIT);
+ }
+
+ if (!fMetaRecord || (PVOID)pCmd->func == (PVOID)record) {
+ if (((PVOID)pCmd->func != (PVOID)repeat) && !mtest()) {
+ if (argSaved.argType == TEXTARG) {
+ FREE (argSaved.arg.textarg.pText);
+ }
+ funcSaved = (FUNCSAVED)pCmd->func;
+ argDataSaved = pCmd->arg;
+ argSaved = arg;
+ fMetaSaved = fMeta;
+ if (arg.argType == TEXTARG) {
+ argSaved.arg.textarg.pText = ZMakeStr (arg.arg.textarg.pText);
+ }
+ fOKSaved = TRUE;
+ }
+ return (*pCmd->func) (pCmd->arg, (ARG *)&arg, fMeta);
+ }
+}
+
+
+
+/*** repeat - repeat the last command
+*
+* repeat is the editor function that is used to repeat the last executed function
+*
+* Input:
+* Standard Editting Function. (Everything ignored)
+*
+* Output:
+* Returns .....
+*
+*************************************************************************/
+flagType
+repeat (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ ) {
+ return fOKSaved
+ ? (*funcSaved) (argDataSaved, (ARG *) &argSaved, fMetaSaved)
+ : disperr (MSGERR_NOREP);
+
+ argData; pArg; fMeta;
+}
+
+
+/*** lasttext - perform arg processing on the dialog line
+*
+* TextArg is the editor function that is used to allow reediting of a text
+* arg on the dialog line.
+*
+* If used with a selection, the first line of the selection is presented
+* for editing.
+*
+* Input:
+* Standard Editting Function.
+*
+* Output:
+* Returns .....
+*
+* Globals:
+* textbuf = buffer containing any the argument
+*
+*************************************************************************/
+flagType
+lasttext (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ ) {
+ REGISTER PCMD pFunc = NULL;
+ int cArg = 0;
+ char p[20];
+ char tbuf[20];
+
+ switch (pArg->argType) {
+ case NULLARG:
+ cArg = pArg->arg.nullarg.cArg;
+
+ case NOARG:
+ cArg ++;
+ break;
+
+ case BOXARG:
+ fInsSpace (pArg->arg.boxarg.xRight, pArg->arg.boxarg.yTop, 0, pFileHead, textbuf);
+ *pLog (textbuf, pArg->arg.boxarg.xRight+1, TRUE) = 0;
+ strcpy (textbuf, pLog (textbuf, pArg->arg.boxarg.xLeft, TRUE));
+ cArg = pArg->arg.boxarg.cArg;
+ break;
+
+ case LINEARG:
+ GetLine (pArg->arg.linearg.yStart, textbuf, pFileHead);
+ cArg = pArg->arg.linearg.cArg;
+ break;
+
+ case STREAMARG:
+ fInsSpace (pArg->arg.streamarg.xStart, pArg->arg.streamarg.yStart, 0, pFileHead, textbuf);
+ if (pArg->arg.streamarg.yStart == pArg->arg.streamarg.yEnd) {
+ *pLog (textbuf, pArg->arg.streamarg.xEnd+1, TRUE) = 0;
+ }
+ strcpy (textbuf, pLog (textbuf, pArg->arg.streamarg.xStart, TRUE));
+ cArg = pArg->arg.streamarg.cArg;
+ break;
+
+ default:
+ break;
+ }
+
+ while (cArg--) {
+ IncArg();
+ }
+
+ sprintf(p,GetMsg(MSG_ARGCOUNT, tbuf), argcount);
+ strcat (p, ": ");
+ if (pFunc = getstring (textbuf, p, NULL, GS_INITIAL)) {
+ fTextarg = TRUE;
+ return (SendCmd (pFunc));
+ } else {
+ return FALSE;
+ }
+
+ argData; fMeta;
+}
+
+
+/*** promptarg - Prompt the use for a textarg on the dialog line
+*
+* If used with a selection, the first line of the selection is used
+* as prompt string.
+*
+* Input:
+* Standard Editting Function.
+*
+* Output:
+* Returns .....
+*
+* Globals:
+* textbuf = buffer containing any the argument
+*
+*************************************************************************/
+flagType
+promptarg (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ ) {
+
+ REGISTER PCMD pFunc = NULL;
+ linebuf lbPrompt;
+ int cArg = 0;
+
+ switch (pArg->argType) {
+ case BOXARG:
+ fInsSpace (pArg->arg.boxarg.xRight, pArg->arg.boxarg.yTop, 0, pFileHead, lbPrompt);
+ *pLog (lbPrompt, pArg->arg.boxarg.xRight+1, TRUE) = 0;
+ strcpy (lbPrompt, pLog (lbPrompt, pArg->arg.boxarg.xLeft, TRUE));
+ cArg = pArg->arg.boxarg.cArg;
+ break;
+
+ case LINEARG:
+ GetLine (pArg->arg.linearg.yStart, lbPrompt, pFileHead);
+ cArg = pArg->arg.linearg.cArg;
+ break;
+
+ case STREAMARG:
+ fInsSpace (pArg->arg.streamarg.xStart, pArg->arg.streamarg.yStart, 0, pFileHead, lbPrompt);
+ if (pArg->arg.streamarg.yStart == pArg->arg.streamarg.yEnd) {
+ *pLog (lbPrompt, pArg->arg.streamarg.xEnd+1, TRUE) = 0;
+ }
+ strcpy (lbPrompt, pLog (lbPrompt, pArg->arg.streamarg.xStart, TRUE));
+ cArg = pArg->arg.streamarg.cArg;
+ break;
+
+ case TEXTARG:
+ strcpy ((char *) lbPrompt, pArg->arg.textarg.pText);
+ cArg = pArg->arg.textarg.cArg;
+ break;
+
+ default:
+ break;
+ }
+
+ while (cArg--) {
+ IncArg();
+ }
+
+ textbuf[0] = '\0';
+
+ pFunc = getstring (textbuf, lbPrompt, NULL, GS_NEWLINE | GS_KEYBOARD);
+ if (pFunc && ((PVOID)pFunc->func != (PVOID)cancel)) {
+ fTextarg = TRUE;
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+
+ argData; fMeta;
+}
+
+
+
+/*** UpdateHighLight - Highlight screen during <arg> text selection.
+*
+* Maintains screen highlighting information.
+*
+* Input:
+* x, y = position of cursor. (y == -1L causes highlighting to be
+* removed)
+* fBoxToLine = TRUE => Turn boxarg into a linearg if arg and cursor
+* columns are the same
+*
+* Global:
+* flArg = Position in file when <arg> was hit.
+*
+* Output:
+*
+*************************************************************************/
+void
+UpdateHighLight (
+ COL x,
+ LINE y,
+ flagType fBoxToLine
+ ) {
+
+ static fl flCursor = {-1, -1L};
+ rn rnHiLite;
+
+ /*
+ * if remove request, clear it out
+ */
+ if (y == -1L) {
+ ClearHiLite (pInsCur->pFile,TRUE);
+ flCursor.lin = -1L;
+ } else if (fBoxArg) {
+ /*
+ * Transition points where we remove highlighting before updating new
+ * highlighting:
+ *
+ * currently columns are equal, and new highlight would not be.
+ * currently columns are not equal, and new highlight would be.
+ * New cursor position differs in BOTH x and y positions from old.
+ * new position equals the arg position
+ */
+ if ( ((flCursor.col == flArg.col) && (x != flCursor.col))
+ || ((flCursor.col != flArg.col) && (x == flArg.col))
+ || ((flCursor.col != x) && (flCursor.lin != y))
+ || ((flArg.col == x) && (flArg.lin == y))
+ ) {
+ ClearHiLite (pInsCur->pFile,TRUE);
+ }
+ flCursor.lin = y;
+ flCursor.col = x;
+ /*
+ * define New Highlight square
+ */
+ rnHiLite.flFirst = flArg;
+ rnHiLite.flLast = flCursor;
+ /*
+ * Ending column is off-by-one. If unequal, adjust accordingly.
+ */
+ if (rnHiLite.flFirst.col < rnHiLite.flLast.col) {
+ rnHiLite.flLast.col--;
+ } else if ( (rnHiLite.flFirst.col == rnHiLite.flLast.col)
+ && (rnHiLite.flFirst.lin != rnHiLite.flLast.lin)) {
+ /*
+ * If columns are same, and lines are different, then highlight entire lines.
+ */
+
+ rnHiLite.flFirst.col = 0;
+ rnHiLite.flLast.col = sizeof(linebuf);
+ }
+ SetHiLite (pInsCur->pFile, rnHiLite, SELCOLOR);
+ } else { /* !fBoxArg */
+
+ /*
+ * If we're on the arg line, we can just clear the highlighting
+ * and redraw.
+ */
+ if (y == flArg.lin) {
+ ClearHiLite (pInsCur->pFile, TRUE);
+
+ rnHiLite.flFirst = flArg;
+ rnHiLite.flLast.col = x;
+ rnHiLite.flLast.lin = y;
+
+ if (x > flArg.col) {
+ rnHiLite.flLast.col--;
+ }
+
+ SetHiLite (pInsCur->pFile, rnHiLite, SELCOLOR);
+ } else {
+ /*
+ * We're not on the arg line. If we have changed lines, we have
+ * to eliminate the range that specifies the line we're on.
+ * Currently, this means we have to clear the entire hiliting and
+ * regenerate.
+ * If we have not changed lines, only the current line will be updated
+ */
+
+ if (flCursor.lin != y) {
+ ClearHiLite (pInsCur->pFile, TRUE);
+
+ /*
+ * First, generate the arg line
+ */
+ rnHiLite.flFirst = flArg;
+ rnHiLite.flLast.lin = flArg.lin;
+
+ if (y < flArg.lin) {
+ rnHiLite.flLast.col = 0;
+ } else {
+ rnHiLite.flLast.col = sizeof(linebuf);
+ }
+
+ SetHiLite (pInsCur->pFile, rnHiLite, SELCOLOR);
+
+ /*
+ * Now generate the block between the arg and the current
+ * lines.
+ */
+ rnHiLite.flFirst.col = 0;
+ rnHiLite.flLast.col = sizeof(linebuf);
+
+ if (y < flArg.lin) {
+ rnHiLite.flFirst.lin = y + 1;
+ rnHiLite.flLast.lin = flArg.lin - 1;
+ } else {
+ rnHiLite.flFirst.lin = flArg.lin + 1;
+ rnHiLite.flLast.lin = y - 1;
+ }
+
+ if (rnHiLite.flLast.lin - rnHiLite.flFirst.lin >= 0) {
+ SetHiLite (pInsCur->pFile, rnHiLite, SELCOLOR);
+ }
+ }
+
+ /*
+ * Now do the current line
+ */
+ rnHiLite.flFirst.lin = y;
+ rnHiLite.flLast.lin = y;
+ rnHiLite.flLast.col = x;
+
+ if (y < flArg.lin) {
+ rnHiLite.flFirst.col = sizeof(linebuf);
+ } else {
+ rnHiLite.flFirst.col = 0;
+ rnHiLite.flLast.col--;
+ }
+
+ SetHiLite (pInsCur->pFile, rnHiLite, SELCOLOR);
+ }
+ flCursor.col = x;
+ flCursor.lin = y;
+ }
+
+ fBoxToLine;
+}
+
+
+/*** BoxStream - Editor command - toggles box/stream modes
+*
+* Toggles the user between box and stream selection modes.
+*
+* Input:
+* Standard Editting function. (Though everything is ignored)
+*
+* Output:
+* Returns TRUE if we are now in box mode, FALSE for stream.
+*
+*************************************************************************/
+flagType
+BoxStream (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ ) {
+
+ fBoxArg = (flagType) !fBoxArg;
+ if (argcount) {
+ UpdateHighLight (-1, -1L, TRUE);
+ UpdateHighLight (XCUR(pInsCur), YCUR(pInsCur), TRUE);
+ }
+ return fBoxArg;
+
+ argData; pArg; fMeta;
+}
+
+
+/*** lastselect - Restore last text selection
+*
+* Purpose:
+*
+* To quickly restore the user text selection after a function has been
+* executed. This function does not exit until the user completes their
+* selection.
+*
+* Input:
+*
+* The usual editor command arguments. None is used.
+*
+* Output:
+*
+* Returns FALSE if we are already in text selection mode, TRUE otherwise.
+*
+* Notes:
+*
+* The items we must save and restore are:
+*
+* flArg - Spot where user hit <arg>
+* flCursor - Spot where cursor was last
+*
+* Note that the boxstream state and the argcount are not preserved.
+*
+* We rely on Arg () to set up for us.
+*
+*************************************************************************/
+
+flagType
+lastselect (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ ) {
+ if (argcount) {
+ return FALSE;
+ }
+
+ Arg (TRUE);
+
+ return TRUE;
+
+ argData; pArg; fMeta;
+}
diff --git a/private/utils/mep/src/assign.c b/private/utils/mep/src/assign.c
new file mode 100644
index 000000000..eea2ac6f1
--- /dev/null
+++ b/private/utils/mep/src/assign.c
@@ -0,0 +1,846 @@
+/**** assign.c - keyboard reassignment and switch setting
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+* 26-Nov-1991 mz Strip out near/far
+*
+*
+*************************************************************************/
+#include "mep.h"
+
+
+#define DEBFLAG CMD
+
+/****************************************************************************
+ * *
+ * Assignment types. Used by UpdToolsIni *
+ * *
+ ****************************************************************************/
+
+#define ASG_MACRO 0
+#define ASG_KEY 1
+#define ASG_SWITCH 2
+
+
+/*** NameToFunc - map a user-specified function name into internal structure
+ *
+ * Given a name of a function, find it in the system table or in the set
+ * of defined macros. Return the pointer to the command structure
+ *
+ * Since, with user-defined extensions as well as macros, there is the
+ * possibility of name collision (effectively masking one function) we allow
+ * disambiguation by specifying an extension name ala .DEF file format:
+ *
+ * func - look up func in macro table and then in extensions
+ * in order of installation
+ * exten.func - look up func in exten only.
+ *
+ * pName = char pointer to potential name
+ *
+ * Returns pointer to command structure if found, NULL otherwise
+ *
+ *************************************************************************/
+PCMD
+FindNameInCmd (
+ char *pName,
+ PCMD pCmd
+ ) {
+ while (pCmd->name) {
+ if (!_stricmp (pName, pCmd->name)) {
+ return pCmd;
+ }
+ pCmd++;
+ }
+ return NULL;
+}
+
+
+PCMD
+NameToFunc (
+ char *pName
+ ) {
+
+ /* see if an extension override is present
+ */
+ {
+ char *pExt = pName;
+ PCMD pCmd;
+ int i;
+
+ pName = strbscan (pExt, ".");
+ if (*pName != '\0') {
+ *pName++ = '\0';
+ for (i = 0; i < cCmdTab; i++) {
+ if (!_stricmp (pExt, pExtName[i])) {
+ pCmd = FindNameInCmd (pName, cmdSet[i]);
+ pName[-1] = '.';
+ return pCmd;
+ }
+ }
+ return NULL;
+ }
+ pName = pExt;
+ }
+
+ {
+ REGISTER int k;
+
+ for (k = 0; k < cMac; k++) {
+ if (!_stricmp (pName, rgMac[k]->name)) {
+ return rgMac[k];
+ }
+ }
+ }
+
+
+ {
+ int i;
+ REGISTER PCMD pCmd;
+
+ /* look up function name in table */
+ for (i = 0; i < cCmdTab; i++) {
+ if ((pCmd = FindNameInCmd (pName, cmdSet[i])) != NULL) {
+ return pCmd;
+ }
+ }
+ return NULL;
+ }
+}
+
+
+
+/*** DoAssign - make assignment
+*
+* Purpose:
+* Executes the keystroke and macro assignment strings passed to it by either
+* the assign command processor, or the tools.ini file processor.
+*
+* Input:
+* asg = Pointer to asciiz assignment string. The line is assumed
+* to be clean (see GetTagLine).
+*
+* Output:
+* TRUE is assignment made
+*
+*************************************************************************/
+flagType
+DoAssign (
+ char *asg
+ ) {
+
+ REGISTER char *p;
+ flagType fRet;
+
+ asg = whiteskip (asg);
+ RemoveTrailSpace (asg);
+
+ if (*(p = strbscan(asg,":")) == 0) {
+ return disperr (MSG_ASN_MISS, asg);
+ }
+
+ *p++ = 0;
+ _strlwr (asg);
+ RemoveTrailSpace (asg);
+ p = whiteskip (p);
+
+ if (*p == '=') {
+ fRet = SetMacro (asg, p = whiteskip (p+1));
+ } else {
+ fNewassign = TRUE;
+ if (NameToFunc (asg) == NULL) {
+ fRet = SetSwitch (asg, p);
+ } else {
+ fRet = SetKey (asg, p);
+ if (!fRet) {
+ if (*p == '\0') {
+ disperr (MSG_ASN_MISSK, asg);
+ } else {
+ disperr (MSG_ASN_UNKKEY, p);
+ }
+ }
+ }
+ }
+ return fRet;
+}
+
+
+/*** SetMacro - define a keystroke macro
+*
+* Input:
+* name = lowercase macro name
+* p = sequence of editor functions and/or quoted text
+*
+* Output:
+*
+*************************************************************************/
+flagType
+SetMacro (
+ char const *name,
+ char const *p
+ ) {
+
+ REGISTER PCMD pFunc;
+ int i, j;
+
+ /* MACRO-NAME:=functions */
+ /* see if macro already defined */
+ for (i = 0; i < cMac; i++) {
+ if (!strcmp (rgMac[i]->name, name)) {
+ for (j = 0; j < cMacUse; j++) {
+ if ((char *) mi[j].beg == rgMac[j]->name) {
+ return disperr (MSG_ASN_INUSE, name);
+ }
+ }
+ break;
+ }
+ }
+
+ if (i != cMac) {
+ /*
+ * redefining a macro: realloc exiting text
+ */
+ rgMac[i]->arg = (CMDDATA)ZEROREALLOC ((char *) rgMac[i]->arg, strlen(p)+1);
+ strcpy ((char *) rgMac[i]->arg, p);
+ return TRUE;
+ }
+
+ if (cMac >= MAXMAC) {
+ return disperr (MSG_ASN_MROOM, name);
+ }
+
+ pFunc = (PCMD) ZEROMALLOC (sizeof (*pFunc));
+ pFunc->arg = (unsigned) ZMakeStr (p);
+ pFunc->name = ZMakeStr (name);
+ pFunc->func = macro;
+ pFunc->argType = KEEPMETA;
+ rgMac[cMac++] = pFunc;
+
+
+ return TRUE;
+}
+
+
+/*** assign - assign editting function
+*
+* Handle key, switch and macro assignments
+*
+* Input:
+* Standard editting function
+*
+* Output:
+* Returns TRUE on success
+*
+*************************************************************************/
+flagType
+assign (
+ CMDDATA argData,
+ REGISTER ARG *pArg,
+ flagType fMeta
+ ) {
+
+ fl flNew;
+ linebuf abuf;
+ char * pBuf = NULL;
+
+ switch (pArg->argType) {
+
+ case NOARG:
+ GetLine (pArg->arg.noarg.y, abuf, pFileHead);
+ return DoAssign (abuf);
+
+ case TEXTARG:
+ strcpy ((char *) abuf, pArg->arg.textarg.pText);
+ if (!strcmp(abuf, "?")) {
+ AutoSave ();
+ return fChangeFile (FALSE, rgchAssign);
+ }
+ return DoAssign (abuf);
+
+ /* NULLARG is transformed into text to EOL */
+ case LINEARG:
+ flNew.lin = pArg->arg.linearg.yStart;
+ while ( flNew.lin <= pArg->arg.linearg.yEnd &&
+ (pBuf = GetTagLine (&flNew.lin, pBuf, pFileHead))) {
+ if (!DoAssign (pBuf)) {
+ flNew.col = 0;
+ cursorfl (flNew);
+ if (pBuf) {
+ FREE (pBuf);
+ }
+ return FALSE;
+ }
+ }
+ if (pBuf) {
+ FREE (pBuf);
+ }
+ return TRUE;
+
+ /* STREAMARG is illegal */
+ case BOXARG:
+ for (flNew.lin = pArg->arg.boxarg.yTop; flNew.lin <= pArg->arg.boxarg.yBottom; flNew.lin++) {
+ fInsSpace (pArg->arg.boxarg.xRight, flNew.lin, 0, pFileHead, abuf);
+ abuf[pArg->arg.boxarg.xRight+1] = 0;
+ if (!DoAssign (&abuf[pArg->arg.boxarg.xLeft])) {
+ flNew.col = pArg->arg.boxarg.xLeft;
+ cursorfl (flNew);
+ return FALSE;
+ }
+ }
+ return TRUE;
+ }
+
+ argData; fMeta;
+}
+
+
+/*** FindSwitch - lookup switch
+*
+* Locate switch descriptor, given it's name
+*
+* Input:
+* p = pointer to text switch name
+*
+* Output:
+* Returns PSWI, or NULL if not found.
+*
+*************************************************************************/
+PSWI
+FindSwitch (
+ char *p
+ ) {
+
+ REGISTER PSWI pSwi;
+ int i;
+
+ for (i = 0; i < cCmdTab; i++) {
+ for (pSwi = swiSet[i]; pSwi != NULL && pSwi->name != NULL; pSwi++) {
+ if (!strcmp (p, pSwi->name)) {
+ return pSwi;
+ }
+ }
+ }
+ return NULL;
+}
+
+
+/*** SetSwitch - Set a switch to a particular value
+*
+* Given a switch name, and a value to set it to, perform the assignment
+*
+* Input:
+* p = pointer to switch name (possibly prefexed by "no" if a
+* boolean
+* val = new value to set switch to
+*
+* Output:
+* Returns TRUE on success
+*
+*************************************************************************/
+flagType
+SetSwitch (
+ char *p,
+ char *val
+ ) {
+
+ PSWI pSwi;
+ int i;
+ flagType f;
+ char *pszError;
+ fl flNew; /* new location of cursor */
+
+ f = TRUE;
+
+ /* figure out if no is a prefix or not
+ */
+
+ if ((pSwi = FindSwitch (p)) == NULL) {
+ if (!_strnicmp ("no", p, 2)) {
+ p += 2;
+ f = FALSE;
+ if ((pSwi = FindSwitch (p)) != NULL && pSwi->type != SWI_BOOLEAN) {
+ pSwi = NULL;
+ }
+ }
+ }
+
+ if (pSwi == NULL) {
+ return disperr (MSG_ASN_NOTSWI, p);
+ }
+
+ switch (pSwi->type & 0xFF) {
+ case SWI_BOOLEAN:
+ if (*val == 0) {
+ *pSwi->act.fval = f;
+ return TRUE;
+ } else if (!f) {
+ printerror ("Boolean switch style conflict");
+ return FALSE;
+ } else if (!_stricmp (val, "no")) {
+ *pSwi->act.fval = FALSE;
+ return TRUE;
+ } else if (!_stricmp (val, "yes")) {
+ *pSwi->act.fval = TRUE;
+ return TRUE;
+ }
+ break;
+
+ case SWI_NUMERIC:
+ if (!f) {
+ if (*val == 0) {
+ val = "0";
+ } else {
+ break;
+ }
+ }
+ if (*val != 0) {
+ *pSwi->act.ival = ntoi (val, pSwi->type >> 8);
+ return TRUE;
+ }
+ break;
+
+ case SWI_SCREEN:
+ /* change screen parameters */
+ i = atoi (val);
+ if (i == 0) {
+ return disperr (MSG_ASN_ILLSET);
+ }
+ if ((cWin > 1) &&
+ (((pSwi->act.ival == (int *)&XSIZE) && (i != XSIZE)) ||
+ ((pSwi->act.ival == (int *)&YSIZE) && (i != YSIZE)))) {
+ disperr (MSG_ASN_WINCHG);
+ delay (1);
+ return FALSE;
+ }
+ if ((pSwi->act.ival == (int *)&XSIZE && !fVideoAdjust (i, YSIZE)) ||
+ (pSwi->act.ival == (int *)&YSIZE && !fVideoAdjust (XSIZE, i))) {
+ return disperr (MSG_ASN_UNSUP);
+ }
+ SetScreen ();
+ if (pInsCur && (YCUR(pInsCur) - YWIN(pInsCur) > YSIZE)) {
+ flNew.col = XCUR(pInsCur);
+ flNew.lin = YWIN(pInsCur) + YSIZE - 1;
+ cursorfl (flNew);
+ }
+ domessage (NULL);
+ return TRUE;
+
+ case SWI_SPECIAL:
+ /* perform some special initialization */
+ if ( ! (*pSwi->act.pFunc) (val) ) {
+ return disperr (MSG_ASN_INVAL, pSwi->name, val);
+ }
+ return TRUE;
+
+ case SWI_SPECIAL2:
+ /* perform special initialization with possible error return string */
+ if (pszError = (*pSwi->act.pFunc2) (val)) {
+ printerror (pszError);
+ return FALSE;
+ }
+ return TRUE;
+
+ default:
+ break;
+ }
+}
+
+
+/*** AckReplace - Acknowledge changes to <assign> file.
+*
+* Purpose:
+*
+* To be called whenever a line in the current file changes. Allows
+* special handling for some files.
+*
+* Input:
+* line - Number of the line that changed
+* fUndo - TRUE if this replacement is an <undo> operation.
+*
+* Output: None
+*
+* Notes:
+*
+* Currently, this means making changes to <assign> take effect immediately.
+* If the user has changed the current line without leaving it, we flag
+* the change so it will take place after they leave. If the user is
+* elsewhere, the change takes place now.
+*
+*************************************************************************/
+
+static flagType fChanged = FALSE;
+
+void
+AckReplace (
+ LINE line,
+ flagType fUndo
+ ) {
+
+
+ if (pInsCur->pFile == pFileAssign) {
+ if (YCUR(pInsCur) == line || fUndo) {
+ fChanged = (flagType)!fUndo;
+ } else {
+ DoAssignLine (line);
+ }
+ }
+}
+
+
+
+/*** AckMove - Possibly parse line in <assign> file.
+*
+* Purpose:
+*
+* To be called whenever the cursor moves to a new line in the current
+* file. This allows special line processing to take place after a
+* line has been changed.
+*
+* Input:
+* lineOld - Number of line we're moving from.
+* lineNew - Number of line we're moving to.
+*
+* Output: None.
+*
+* Notes:
+*
+* Currently, this makes the <assign> file work. If the line we are
+* moving from has changed, we make the assignment. We rely on AckReplace
+* to set fChanged ONLY when the affected file is <assign>.
+*
+*************************************************************************/
+
+void
+AckMove (
+ LINE lineOld,
+ LINE lineNew
+ ) {
+ if (pInsCur->pFile== pFileAssign && fChanged && lineOld != lineNew ) {
+ fChanged = FALSE;
+ DoAssignLine (lineOld);
+ }
+}
+
+
+
+/*** DoAssignLine - Take line from current file and <assign> with it
+*
+* Purpose:
+*
+* Used by the Ack* functions to perform an <assign> when the time is
+* right.
+*
+* Input:
+* line - Line in the file to read.
+*
+* Output: None
+*
+*************************************************************************/
+
+#define CINDEX(clr) ((&clr-&ColorTab[0])+isaUserMin)
+
+void
+DoAssignLine (
+ LINE line
+ ) {
+ fl flNew;
+ char *pch;
+ struct lineAttr rgColor[2];
+
+ flNew.lin = line;
+ if ((pch = GetTagLine (&flNew.lin, NULL, pInsCur->pFile)) &&
+ flNew.lin == line+1) {
+ if (!DoAssign(pch)) {
+ flNew.col = XCUR(pInsCur);
+ flNew.lin--;
+ cursorfl (flNew);
+ DelColor (line, pInsCur->pFile);
+ } else {
+ /*
+ * Hilite the changed line so we can find it again
+ */
+ rgColor[0].attr = rgColor[1].attr = (unsigned char)CINDEX(hgColor);
+ rgColor[0].len = (unsigned char)slSize.col;
+ rgColor[1].len = 0xFF;
+ PutColor (line, rgColor, pInsCur->pFile);
+ }
+ }
+}
+
+
+
+/*** UpdToolsIni - Update one entry in the tools.ini file
+*
+* Purpose:
+*
+* Used for automatic updates, such as when the <assign> file is saved.
+*
+* The posible values for asgType are:
+*
+* ASG_MACRO - This is a macro assignment.
+* ASG_KEY - This assigns a function to a key.
+* ASG_SWITCH - THis assigns a value to a switch.
+*
+* Input:
+* pszValue - Complete string to enter, as in "foo:value".
+* asgType - Type of assignment.
+*
+* Output: None
+*
+* Notes:
+*
+* If necessary, the string will be broken across several lines using
+* the continuation character.
+*
+* UNDONE: This "effort" has not been made"
+* Every effort is made to preserve the user's tools.ini format. To this
+* end:
+*
+* o When an entry already exists for the given switch or function,
+* the new value is written over the old value, with the first
+* non-space character of each coinciding.
+*
+* o If an entry does not exist, a new entry is made at the end
+* of the section, and is indented to match the previous entry.
+*
+* We find an existing string by searching through the tagged sections
+* in the same order in which they are read, then pick the last instance
+* of the string. In other words, the assignment we replace will be
+* the one that was actually used. This order is assumed to be:
+*
+* [NAME]
+* [NAME-os version]
+* [NAME-video type]
+* [NAME-file extension]
+* [NAME-..] (if no file extension section)
+*
+* If we are not replacing an existing string, we add the new string at
+* the end of the [MEP] section.
+*
+* The string pszAssign is altered.
+*
+*************************************************************************/
+
+void
+UpdToolsIni (
+ char * pszAssign
+ ) {
+
+ char * pchLeft;
+ char * pchRight;
+ int asgType;
+ LINE lReplace, lAdd = 0L, l;
+ linebuf lbuf;
+ flagType fTagFound = TRUE;
+
+ if (pFileIni == NULL || pFileIni == (PFILE)-1) {
+ /*
+ ** We ASS-U-ME here that pFileIni has no
+ ** value because there is no TOOLS.INI file
+ */
+ if (CanonFilename ("$INIT:tools.ini", lbuf)) {
+ pFileIni = AddFile (lbuf);
+ assert (pFileIni);
+ pFileIni->refCount++;
+ SETFLAG (FLAGS(pFileIni), DOSFILE);
+ FileRead (lbuf, pFileIni, FALSE);
+ } else {
+ return;
+ }
+ }
+
+ /* First, figure out what is what */
+ pchLeft = whiteskip (pszAssign);
+ pchRight = strchr (pchLeft, ':');
+ *pchRight++ = '\0';
+ if (*pchRight == '=') {
+ asgType = ASG_MACRO;
+ pchRight++;
+ } else {
+ asgType = NameToFunc (pchLeft) ? ASG_KEY : ASG_SWITCH;
+ }
+ pchRight = whiteskip (pchRight);
+
+
+ // First, let's search through the [NAME] section. If
+ // we are replacing, we search for the line to replace.
+ // If we are not, we are simply trying to find the end.
+ //
+ lReplace = 0L;
+
+ if (0L < (l = FindMatchLine (NULL, pchLeft, pchRight, asgType, &lAdd))) {
+ lReplace = l;
+ } else {
+ fTagFound = (flagType)!l;
+ }
+
+ //sprintf (lbuf, "%d.%d", _osmajor, _osminor);
+ //if (_osmajor >= 10 && !_osmode) {
+ // strcat (lbuf, "R");
+ //}
+ if (0L < (l = FindMatchLine (lbuf, pchLeft, pchRight, asgType, &lAdd))) {
+ lReplace = l;
+ } else {
+ fTagFound = (flagType)(fTagFound || (flagType)!l);
+ }
+
+ if (0L < (l = FindMatchLine (VideoTag(), pchLeft, pchRight, asgType, &lAdd))) {
+ lReplace = l;
+ } else {
+ fTagFound = (flagType)(fTagFound || (flagType)!l);
+ }
+
+ // UNDONE: This should try to read the extension section
+ // currently "active". What it does is read the extension
+ // section appropriate to the current file. If these are
+ // not the same, it fails.
+ //
+ if (extention (pInsCur->pFile->pName, lbuf)) {
+ if (0L < (l = FindMatchLine (lbuf, pchLeft, pchRight, asgType, &lAdd))) {
+ lReplace = l;
+ } else if (l == -1L) {
+ if (0L < (l = FindMatchLine ("..", pchLeft, pchRight, asgType, &lAdd))) {
+ lReplace = l;
+ } else {
+ fTagFound = (flagType)(fTagFound || (flagType)!l);
+ }
+ }
+ }
+
+
+ // If we are not supposed to replace a line,
+ // or if we are but we can't find a suitable
+ // line, we simply insert the new line
+ //
+ strcpy (lbuf, pchLeft);
+ if (asgType == ASG_MACRO) {
+ strcat (lbuf, ":= ");
+ } else {
+ strcat (lbuf, ": ");
+ }
+ strcat (lbuf, pchRight);
+
+ if (!fTagFound) {
+ lAdd = 1L;
+ InsLine (FALSE, 0L, 1L, pFileIni);
+ sprintf (buf, "[%s]", pNameEditor);
+ PutTagLine (pFileIni, buf, 0L, 0);
+ }
+
+ if (lReplace == 0L) {
+ assert (lAdd <= pFileIni->cLines);
+ InsLine (FALSE, lAdd, 1L, pFileIni);
+ } else {
+ lAdd = lReplace;
+ }
+
+ PutLine (lAdd, lbuf, pFileIni);
+}
+
+
+/*** FindMatchLine - Find a line to replace in TOOLS.INI
+*
+* Purpose:
+*
+* Called from UpdToolsIni to find the right place to update
+*
+* Input:
+* pszTag - Which tagged section to look in
+* pszLeft - Left side of the assignment
+* pszRight- Right side of the assignment
+* asgType - Type of assignment (one of ASG_*)
+* plAdd - Returns line number of place to insert a new line
+*
+* Output:
+*
+* Returns line number in pFileIni of matchine line, 0L if there is
+* no match and -1L if the specified tag does not exist.
+*
+*************************************************************************/
+
+LINE
+FindMatchLine (
+ char * pszTag,
+ char * pszLeft,
+ char * pszRight,
+ int asgType,
+ LINE * plAdd
+ ) {
+
+ char pszTagBuf[80];
+ char * pchRight, * pchLeft;
+ LINE lCur, lNext, lReplace = 0L;
+ flagType fUser = FALSE;
+ flagType fExtmake = FALSE;
+ int cchExt;
+
+ strcpy (pszTagBuf, pNameEditor);
+ if (pszTag) {
+ strcat (pszTagBuf, "-");
+ strcat (pszTagBuf, pszTag);
+ }
+
+ if ((LINE)0 == (lNext = LocateTag (pFileIni, pszTagBuf))) {
+ return -1L;
+ }
+
+ if (!_stricmp (pszLeft, "user")) {
+ fUser = TRUE;
+ } else if (!_stricmp (pszLeft, "extmake")) {
+ pchRight = whitescan (pszRight);
+ cchExt = pchRight - pszRight;
+ fExtmake = TRUE;
+ }
+
+ // Get each line in the current section, checking the right
+ // or left side for a match with the passed-in string.
+ //
+ pchLeft = NULL;
+ while (lCur = lNext, pchLeft = GetTagLine (&lNext, pchLeft, pFileIni)) {
+ pchRight = strbscan (pchLeft, ":");
+ *pchRight = '\0';
+ if (pchRight[1] == '=') {
+ if (asgType != ASG_MACRO) {
+ continue;
+ }
+ pchRight++;
+ } else if (asgType == ASG_MACRO) {
+ continue;
+ }
+ pchRight = whiteskip (pchRight);
+
+ switch (asgType) {
+ case ASG_KEY:
+ if (!_stricmp (pszRight, pchRight)) {
+ lReplace = lCur;
+ }
+ break;
+
+ case ASG_SWITCH:
+ if (!_stricmp (pszLeft, pchLeft)) {
+ lReplace = lCur;
+ }
+ break;
+
+ case ASG_MACRO:
+ if (fUser) {
+ continue;
+ }
+
+ if (!_stricmp (pszLeft, pchLeft)) {
+ if (!(fExtmake && _strnicmp (pszRight, pchRight, cchExt))) {
+ lReplace = lCur;
+ }
+ }
+ break;
+
+ default:
+ assert (FALSE);
+ }
+ }
+
+ if (!pszTag) {
+ *plAdd = lCur;
+ }
+ return lReplace;
+}
diff --git a/private/utils/mep/src/build.c b/private/utils/mep/src/build.c
new file mode 100644
index 000000000..9cc5cb587
--- /dev/null
+++ b/private/utils/mep/src/build.c
@@ -0,0 +1,326 @@
+/*** build.c - utilities for build process
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+* 26-Nov-1991 mz Strip out near/far
+*
+*
+*************************************************************************/
+#include "mep.h"
+
+
+/***
+*
+* Structures & Types
+*
+*************************************************************************/
+/*
+ * BUILDCMD - Build command linked list element
+ */
+struct BuildCmdType {
+ struct BuildCmdType *pNext; /* next in list */
+ int flags; /* command type */
+ char *pRule; /* pointer to rule/filename */
+ char *pCmd; /* pointer to command text */
+ };
+
+typedef struct BuildCmdType BUILDCMD;
+
+/***
+*
+* Module data
+*
+*************************************************************************/
+static BUILDCMD *pBuildCmdHead = NULL; /* head of linked list */
+static BUILDCMD *pBuildCmdCur = NULL; /* most recent lookup */
+
+/*** fSetMake - Define Build Command
+*
+* Defines the filename extensions (.C, .BAS, etc) to which a given tool
+* command line applies OR the tool class which a command line defines.
+*
+* Input:
+* SetType = MAKE_SUFFIX = define suffix rule
+* MAKE_FILE = define command for specfic file
+* MAKE_TOOL = define tool command line
+* MAKE_DEBUG = definition is for DEBUG, else RELEASE
+*
+* fpszCmd = Formatted command string. Uses current extmake formatting
+* rules. (%s, etc.)
+*
+* fpszExt = If MAKE_EXT = suffixes (i.e. ".c.obj")
+* If MAKE_FILE = filename (must include ".")
+* If MAKE_TOOL = tool name (no "." allowed)
+*
+* Output:
+* Returns TRUE on success. FALSE on any error.
+*
+*************************************************************************/
+flagType
+fSetMake (
+ int SetType,
+ char *fpszCmd,
+ char *fpszExt
+ ) {
+ buffer buf;
+
+ assert (fpszCmd && fpszExt && SetType);
+ while (*fpszCmd == ' ') {
+ fpszCmd++;
+ }
+ if (fGetMake (SetType, (char *)buf, fpszExt)) {
+ /*
+ * If it already existed, then just free teh previous definitions, in
+ * preparation for replacement.
+ */
+ assert (pBuildCmdCur->pCmd);
+ assert (pBuildCmdCur->pRule);
+ pBuildCmdCur->pCmd = ZEROREALLOC (pBuildCmdCur->pCmd, strlen(fpszCmd)+1);
+ pBuildCmdCur->pRule = ZEROREALLOC (pBuildCmdCur->pRule,strlen(fpszExt)+1);
+ strcpy ((char *)pBuildCmdCur->pCmd, fpszCmd);
+ strcpy ((char *)pBuildCmdCur->pRule,fpszExt);
+ } else {
+ /*
+ * It didn't already exist, so create a new struct at the head of the list,
+ * to be filled in below.
+ */
+ pBuildCmdCur = (BUILDCMD *)ZEROMALLOC (sizeof(BUILDCMD));
+ pBuildCmdCur->pNext = pBuildCmdHead;
+ pBuildCmdCur->pCmd = ZMakeStr (fpszCmd);
+ pBuildCmdCur->pRule = ZMakeStr (fpszExt);
+ pBuildCmdHead = pBuildCmdCur;
+ }
+ pBuildCmdCur->flags = SetType;
+ return TRUE;
+}
+
+
+
+/*** fGetMake - Return Build Command
+*
+* Returns the command line which applies to a file or filename extension.
+*
+* Input:
+* GetType = MAKE_SUFFIX = return suffix rule
+* MAKE_FILE = return command for specfic file
+* MAKE_TOOL = return tool command line
+* MAKE_DEBUG = definition is for DEBUG, else RELEASE
+*
+* fpszCmdDst = Location to place the formatted command string. Must be
+* BUFLEN bytes long.
+*
+* fpszExt = If MAKE_EXT = suffixes (i.e. ".c.obj") for desired
+* command.
+* If MAKE_FILE = filename for desired command
+* If MAKE_TOOL = name of tool
+*
+* Output:
+* Returns 0 on any error, else returns the GetType.
+*
+*************************************************************************/
+int
+fGetMake (
+ int GetType,
+ char *fpszCmdDst,
+ char *fpszExt
+ ) {
+ assert (fpszCmdDst && fpszExt && GetType);
+ /*
+ * Here we just walk the linked list looking for an entry whose flags match,
+ * and, if a file or suffix rule, whose rule matches.
+ */
+ for (pBuildCmdCur = pBuildCmdHead;
+ pBuildCmdCur;
+ pBuildCmdCur = pBuildCmdCur->pNext) {
+
+ if (pBuildCmdCur->flags == GetType) {
+ if (!_stricmp((char *)pBuildCmdCur->pRule,fpszExt)) {
+ strcpy (fpszCmdDst,(char *)pBuildCmdCur->pCmd);
+ return pBuildCmdCur->flags;
+ }
+ }
+ }
+ return 0;
+}
+
+
+/*** hWalkMake - return make commands one at a time.
+*
+* Allow an external anyone to walk the command list.
+*
+* Input
+*
+* Output:
+* Returns .....
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+unsigned
+short
+hWalkMake (
+ unsigned short handle,
+ int *Type,
+ char *pszRuleDest,
+ char *pszCmdDest
+ ) {
+
+ if (handle) {
+ pBuildCmdCur = ((BUILDCMD *)handle)->pNext;
+ } else {
+ pBuildCmdCur = pBuildCmdHead;
+ }
+
+ if (pBuildCmdCur) {
+ *Type = pBuildCmdCur->flags;
+ strcpy (pszRuleDest, pBuildCmdCur->pRule);
+ strcpy (pszCmdDest, pBuildCmdCur->pCmd);
+ }
+ return (unsigned short) pBuildCmdCur;
+}
+
+
+/*** fShowMake - Show current build commands
+*
+* Append a textual representation of the current build commands to the
+* passed pFile
+*
+* Input:
+* pFile = File handle to be added to
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void
+ShowMake (
+ PFILE pFile
+ ) {
+ buffer buf;
+
+ assert (pFile);
+ /*
+ * Here we just walk the linked list and append lines with the info
+ */
+ for (pBuildCmdCur = pBuildCmdHead;
+ pBuildCmdCur;
+ pBuildCmdCur = pBuildCmdCur->pNext) {
+
+ if (TESTFLAG (pBuildCmdCur->flags, MAKE_FILE)) {
+ sprintf (buf, " extmake:[%s]", pBuildCmdCur->pRule);
+ } else if (TESTFLAG (pBuildCmdCur->flags, MAKE_SUFFIX)) {
+ sprintf (buf, " extmake:%s", pBuildCmdCur->pRule);
+ } else if (TESTFLAG (pBuildCmdCur->flags, MAKE_TOOL)) {
+ sprintf (buf, " extmake:*%s", pBuildCmdCur->pRule);
+ } else if (TESTFLAG (pBuildCmdCur->flags, MAKE_BLDMACRO)) {
+ sprintf (buf, " extmake:$%s", pBuildCmdCur->pRule);
+ } else {
+ assert (FALSE);
+ }
+ sprintf (strend(buf), "%s %s"
+ , TESTFLAG (pBuildCmdCur->flags, MAKE_DEBUG) ? ",D" : RGCHEMPTY
+ , pBuildCmdCur->pCmd
+ );
+ AppFile (buf, pFile);
+ }
+}
+
+
+/*** SetExt - assign a particular compile action to a particular action.
+*
+* This is called during any initialization to cause a string to be
+* associated with a particular compile action.
+*
+* Input:
+* val = char pointer to a string of the form:
+* .ext string = define .ext.obj rule
+* .ext.ext string = define .ext.ext rule
+* filename.ext string = define rule for filename.ext
+* command string = define rule for command
+*
+* During build any %s's in the string are replaced with the
+* name of the file being compiled.
+*
+* Output:
+* Returns TRUE, or FALSE if any errors are found.
+*
+*************************************************************************/
+char *
+SetExt (
+ char *val
+ ) {
+
+ buffer extbuf; /* buffer to work on extension */
+ REGISTER int maketype = 0; /* type of build command */
+ char *pCompile; /* pointer to command portion */
+ char *pExt; /* pointer to extension portion */
+ REGISTER char *pT; /* temp pointer */
+ buffer tmpval; /* (near) buffer to work on */
+
+ assert (val);
+ strcpy ((char *) tmpval, val);
+ /*
+ * seperate the extension part from the command part. If there is no command,
+ * that's an error.
+ */
+ ParseCmd (tmpval, &pExt, &pCompile);
+ if (*pCompile == '\0') {
+ return "extmake: Command missing";
+ }
+ /*
+ * CONSIDER: this syntax is somewhat ugly, and unclean to parse
+ *
+ * Copy the extension part to a local buffer, so we can work on it. Set make
+ * type based on the following rules:
+ *
+ * Starts with dot: --> suffix rule.
+ * Starts with "*" --> tool rule.
+ * Starts with "$" --> build macro
+ * Starts with "[" --> filename rule.
+ * "text" --> Special old-style "tool rule" for TEXT
+ * text <= 3 characters --> old style suffix rule
+ *
+ * In all cases: contains ",d" --> DEBUG rule.
+ */
+ _strlwr (pExt);
+ strcpy (extbuf, pExt);
+
+ if (pT = strstr (extbuf,",d")) {
+ maketype = MAKE_DEBUG;
+ *pT = 0;
+ }
+
+ if (extbuf[0] == '.') {
+ maketype |= MAKE_SUFFIX;
+ } else if (extbuf[0] == '[') {
+ strcpy (extbuf, extbuf+1);
+ maketype |= MAKE_FILE;
+ if (pT = strchr (extbuf,']')) {
+ *pT = 0;
+ }
+ } else if (extbuf[0] == '*') {
+ strcpy (extbuf, extbuf+1);
+ maketype |= MAKE_TOOL;
+ } else if (extbuf[0] == '$') {
+ strcpy (extbuf, extbuf+1);
+ maketype |= MAKE_BLDMACRO;
+ } else if (!_stricmp (extbuf, "text")) {
+ maketype |= MAKE_TOOL;
+ } else if (strlen(extbuf) <= 3) {
+ ((unsigned short *)extbuf)[0] = (unsigned short)'.';
+ strcat (extbuf,pExt);
+ strcat (extbuf,".obj");
+ maketype |= MAKE_SUFFIX;
+ } else {
+ return "extmake: Bad syntax in extension";
+ }
+
+ if (fSetMake (maketype, (char *)pCompile, (char *)extbuf)) {
+ return NULL;
+ } else {
+ return "extmake: Error in command line";
+ }
+}
diff --git a/private/utils/mep/src/cdelete.c b/private/utils/mep/src/cdelete.c
new file mode 100644
index 000000000..13f4d59c5
--- /dev/null
+++ b/private/utils/mep/src/cdelete.c
@@ -0,0 +1,157 @@
+/*** cdelete.c - delete the previous character in a line
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+#include "mep.h"
+
+/*** cdelete - character delete function
+*
+* Input:
+* Standard editing function
+*
+* Output:
+* Returns TRUE on deletion
+*
+*************************************************************************/
+flagType
+cdelete (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ ) {
+ return DoCDelete (FALSE);
+
+ argData; pArg; fMeta;
+}
+
+
+/*** emacsdel - emacs character delete function
+*
+* Input:
+* Standard editing function
+*
+* Output:
+* Returns TRUE on deletion
+*
+*************************************************************************/
+flagType
+emacscdel (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ ) {
+ return DoCDelete (TRUE);
+
+ argData; pArg; fMeta;
+
+}
+
+
+/*** DoCDelete - perform character deletion
+*
+* Delete the character at the current cursor location
+*
+* Input:
+* fEmacs - EMACs type delete flag
+*
+* Output:
+* Returns TRUE on deletion
+*
+*************************************************************************/
+flagType
+DoCDelete (
+ flagType fEmacs
+ ) {
+
+ fl fl; /* file loc to position at */
+ int x;
+ char *p;
+ linebuf tempbuf;
+ struct lineAttr rgla[sizeof(linebuf)];
+ flagType fColor;
+
+ fl.col = XCUR(pInsCur);
+ fl.lin = YCUR(pInsCur);
+ /*
+ * xCursor is zero. If yCursor is also zero (top of file), we can't move
+ * back, so nothing to delete. Otherwise, move to end of previous line, and
+ * if emacs & insert mode, join the lines.
+ */
+ if (fl.col == 0) {
+ if (fl.lin == 0) {
+ return FALSE;
+ } else {
+ fl.lin--;
+ fl.col = LineLength (fl.lin, pFileHead);
+ if (fInsert && fEmacs) {
+ DelStream (pFileHead, fl.col, fl.lin, 0, fl.lin + 1);
+ }
+ }
+ } else {
+ /*
+ * column is non-zero, so back it up one.
+ */
+ GetLine (fl.lin, tempbuf, pFileHead);
+ x = cbLog (tempbuf);
+ fl.col = DecCol (fl.col, tempbuf);
+ /*
+ * we're in the middle of a line. If in insert mode, back up the cursor, and
+ * delete the character there.
+ */
+ if (fInsert) {
+ DelBox (pFileHead, fl.col, fl.lin, fl.col, fl.lin);
+ } else {
+ /*
+ * we're in the middle of a line, but not insert mode. Get the text of the
+ * line & pointer to character.
+ */
+ p = pLog (tempbuf, fl.col, TRUE);
+ /*
+ * If emacs, and we're actually IN text, then replace the character with a
+ * space.
+ */
+ if (fEmacs) {
+ if (fl.col+1 <= x && *p != ' ') {
+ *p = ' ';
+ // SetColor (pFileHead, fl.lin, fl.col, 1, fgColor);
+ PutLine (fl.lin, tempbuf, pFileHead);
+ }
+ }
+ /*
+ * if we're beyond the end of the line, just position to the end of the line.
+ */
+ else if (fl.col+1 > x) {
+ fl.col = x;
+ }
+ /*
+ * if the first non-blank character is PAST the current position, then just
+ * position at the begining of the line.
+ */
+ else if ((colPhys (tempbuf, whiteskip (tempbuf)) > fl.col)) {
+ fl.col = 0;
+ }
+ /*
+ * finaly, when all else fails, back up, and replace the character under the
+ * cursor with a space.
+ */
+ else if (*p != ' ') {
+ *pLog (tempbuf,fl.col,TRUE) = ' ';
+ if (fColor = GetColor (fl.lin, rgla, pFileHead)) {
+ ShiftColor (rgla, fl.col, -1);
+ ColorToLog (rgla, buf);
+ }
+ PutLine (fl.lin, tempbuf, pFileHead);
+ if (fColor) {
+ PutColor (fl.lin, rgla, pFileHead);
+ }
+ }
+ }
+ }
+ cursorfl (fl);
+
+ return TRUE;
+}
diff --git a/private/utils/mep/src/cmd.c b/private/utils/mep/src/cmd.c
new file mode 100644
index 000000000..2c4602254
--- /dev/null
+++ b/private/utils/mep/src/cmd.c
@@ -0,0 +1,220 @@
+/*** cmd.c - handle simple keyboard interactions
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+
+#include "mep.h"
+#include "keyboard.h"
+
+
+
+#define DEBFLAG CMD
+
+struct cmdDesc cmdUnassigned = { "unassigned", unassigned, 0, FALSE };
+
+/*** unassigned - function assigned to unassigned keystrokes
+*
+* display an informative message about the unassigned key
+*
+* Input:
+* Standard editing function
+*
+* Output:
+* Returns FALSE
+*
+*************************************************************************/
+flagType
+unassigned (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ ) {
+ buffer buf;
+
+ CodeToName ( (WORD)argData, buf);
+ printerror ("%s is not assigned to any editor function",buf);
+
+ return FALSE;
+
+ pArg; fMeta;
+}
+
+
+
+/*** confirm - ask our dear user a yes/no question
+*
+* Purpose:
+* Asks the user a yes/no question, and gets his single character response. If
+* in a macro, the reponse may also come from the macro stream, or from the
+* passed "if in a macro" default response.
+*
+* Input:
+* fmtstr = prompt format string
+* arg = prompt format parameters
+*
+* Output:
+* TRUE if 'y', else FALSE.
+*
+*************************************************************************/
+flagType
+confirm (
+ char *fmtstr,
+ char *arg
+ ) {
+ return (flagType)(askuser ('n', 'y', fmtstr, arg) == 'y');
+}
+
+
+/*** askuser - ask our dear user a question
+*
+* Purpose:
+* Asks the user a question, and gets his single character response. If in
+* a macro, the reponse may also come from the macro stream, or from the
+* passed "if in a macro" default response.
+*
+* Input:
+* defans = default answer for non-alpha responses
+* defmac = default answer if executing in a macro and no "<" is present
+* fmtstr = prompt format string
+* arg = prompt format parameters
+*
+* Output:
+* the lowercase character response. If the user presses <cancel>, the
+* integer -1 is returned.
+*
+*************************************************************************/
+int
+askuser (
+ int defans,
+ int defmac,
+ char *fmtstr,
+ char *arg
+ ) {
+ int c;
+ int x;
+ PCMD pcmd;
+
+ switch (c = fMacResponse()) {
+ case 0:
+ if ((c = defmac) == 0) {
+ goto askanyway;
+ }
+ break;
+
+ default:
+ break;
+
+ case -1:
+ askanyway:
+ DoDisplay ();
+ consoleMoveTo( YSIZE, x = domessage (fmtstr, arg));
+ c = (pcmd = ReadCmd())->arg & 0xff;
+ SETFLAG (fDisplay,RCURSOR);
+ if ((PVOID)pcmd->func == (PVOID)cancel) {
+ sout (x, YSIZE, "cancelled", infColor);
+ return -1;
+ } else {
+ if (!isalpha (c)) {
+ c = defans;
+ }
+ vout (x, YSIZE, (char *)&c, 1, infColor);
+ }
+ break;
+ }
+ return tolower(c);
+}
+
+
+/*** FlushInput - remove all typeahead.
+*
+* FlushInput is called when some action invalidates all input.
+*
+* Input:
+* none
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void
+FlushInput (
+ void
+ ) {
+ register BOOL MoreInput;
+ while (MoreInput = TypeAhead()) {
+ ReadCmd ();
+ }
+}
+
+/*** fSaveDirtyFile - Prompt the user to save or lose dirty files
+*
+* Purpose:
+*
+* Called just before exit to give the user control over soon-to-be-lost
+* editing changes.
+*
+* Input: None.
+*
+* Output:
+*
+* Returns TRUE if the user wants to exit, FALSE if not.
+*
+*************************************************************************/
+flagType
+fSaveDirtyFiles (
+ void
+ ) {
+
+ REGISTER PFILE pFile;
+ int cDirtyFiles = 0;
+ flagType fAgain;
+ buffer buf;
+
+ assert (_pfilechk());
+ for (pFile = pFileHead; pFile; pFile = pFile->pFileNext) {
+ if ((FLAGS(pFile) & (DIRTY | FAKE)) == DIRTY) {
+ if (++cDirtyFiles == 2) {
+ do {
+ fAgain = FALSE;
+ switch (askuser (-1, -1, GetMsg (MSG_SAVEALL, buf), NULL)) {
+ case 'y':
+ SaveAllFiles ();
+ return TRUE;
+
+ case 'n':
+ break;
+
+ case -1:
+ return FALSE;
+
+ default:
+ fAgain = TRUE;
+ }
+ } while (fAgain);
+ }
+
+ do {
+ fAgain = FALSE;
+ switch (askuser (-1, -1, GetMsg (MSG_SAVEONE, buf), pFile->pName)) {
+ case 'y':
+ FileWrite (pFile->pName, pFile);
+
+ case 'n':
+ break;
+
+ case -1:
+ return FALSE;
+
+ default:
+ fAgain = TRUE;
+ }
+ } while (fAgain);
+ }
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/mep/src/compile.c b/private/utils/mep/src/compile.c
new file mode 100644
index 000000000..c684a9a47
--- /dev/null
+++ b/private/utils/mep/src/compile.c
@@ -0,0 +1,541 @@
+/*** compile.c - perform asynch compile
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+
+#include "mep.h"
+
+
+static char szFencePost[] = "+++ M ";
+static LINE yComp = 0; /* last line viewed in compile log */
+
+/*** compile - <compile> editor function
+*
+* Implements the <compile> editor function:
+* compile = display compile status
+* arg compile = compile using command based on file extension
+* arg text compile = compile using command associated with text
+* arg arg text compile = compile using "text" as command
+* [arg] arg meta compile = Kill current background compile
+*
+* Input:
+* Standard editing function.
+*
+* Output:
+* Returns TRUE if compile succesfully started or queued.
+*
+*************************************************************************/
+flagType
+compile (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+) {
+ static char szStatus[] = "no compile in progress";
+
+ buffer pCmdBuf; /* compile command to execute */
+ buffer pFileBuf; /* current filename.ext */
+ buffer pMsgBuf;
+
+ int rc; /* Used to pick up return codes */
+
+
+ switch (pArg->argType) {
+
+ case NOARG:
+
+ domessage (fBusy(pBTDComp) ? szStatus+3 : szStatus);
+ return (flagType) (fBusy(pBTDComp));
+
+ case NULLARG:
+
+ if (fMeta) {
+ return (flagType) BTKill (pBTDComp);
+ }
+
+ /*
+ * no text was entered, we use default settings according to filename
+ * or extension. Form filename.ext in pFileBuf, get filename extension
+ * into pCmdBuf, and append .obj for the suffix rule.
+ */
+ fileext (pFileHead->pName, pFileBuf);
+ extention (pFileBuf, pCmdBuf);
+
+ /*
+ * if we don't find a command specifically for this file, or a
+ * command for this suffix rule, trying both DEBUG and non-debug
+ * in both cases, print error and return.
+ */
+ if (!(fGetMake (MAKE_FILE, (char *)pMsgBuf, (char *)pFileBuf))) {
+ //if (!(fGetMake (MAKE_SUFFIX, (char *)pMsgBuf, (char *)pCmdBuf))) {
+ strcat (pCmdBuf, ".obj");
+ if (!(fGetMake (MAKE_SUFFIX, (char *)pMsgBuf, (char *)pCmdBuf))) {
+ return disperr (MSGERR_CMPCMD2, pFileBuf);
+ }
+ //}
+ }
+
+ /*
+ * pMsgBuf has the user specified compile command, pFileBuf has
+ * the filename. sprintf them together into pCmdBuf.
+ */
+ UnDoubleSlashes (pMsgBuf);
+ if ( (rc = sprintf (pCmdBuf, pMsgBuf, pFileBuf)) == 0) {
+ return disperr (rc, pMsgBuf);
+ }
+ break;
+
+ case TEXTARG:
+ /*
+ * text was entered. If 1 arg, use the command associated with "text",
+ * else use the text itself.
+ */
+ strcpy ((char *) buf, pArg->arg.textarg.pText);
+ if (pArg->arg.textarg.cArg == 1) {
+ if (!fGetMake (MAKE_TOOL, (char *)pMsgBuf, (char *)"text")) {
+ return disperr (MSGERR_CMPCMD);
+ }
+ UnDoubleSlashes (pMsgBuf);
+ if (rc = sprintf (pCmdBuf, pMsgBuf, buf)) {
+ return disperr (rc, pMsgBuf);
+ }
+ } else {
+ strcpy (pCmdBuf, buf);
+ }
+ break;
+
+ default:
+ assert (FALSE);
+ }
+ /*
+ * At this point, pCmdBuf has the formatted command we are to exec off, and
+ * pFileBuf has the filename.ext of the current file. (pMsgBuf is free)
+ */
+
+ AutoSave ();
+ Display ();
+
+ /*
+ * If there's no activity underway and the log file is not empty and
+ * the user wants to flush it: Let's flush !
+ */
+ if ( !fBusy(pBTDComp)
+ && (pBTDComp->pBTFile)
+ && (pBTDComp->pBTFile->cLines)
+ && (confirm ("Delete current contents of compile log ? ", NULL))
+ ) {
+ DelFile (pBTDComp->pBTFile, FALSE);
+ yComp = 0;
+ }
+
+ /*
+ * The log file will be updated dynamically
+ */
+ UpdLog(pBTDComp);
+
+ /*
+ * Send jobs
+ */
+ if (pBTDComp->cBTQ > MAXBTQ-2) {
+ return disperr (MSGERR_CMPFULL);
+ }
+
+ if ( BTAdd (pBTDComp, (PFUNCTION)DoFence, pCmdBuf)
+ && BTAdd (pBTDComp, NULL, pCmdBuf)) {
+ return dispmsg (MSG_QUEUED, pCmdBuf);
+ } else {
+ return disperr (MSGERR_CMPCANT);
+ }
+
+ argData;
+}
+
+
+/*** nextmsg - <nextmsg> editor function
+*
+* Implements the <nextmsg> editor function:
+* nextmsg = move to next compile error within "pasture"
+* arg numarg nextmsg = move to "nth" next compile error within the
+* pasture, where "n" may be a signed long.
+* arg nextmsg = move to next compile error within the pasture
+* that does not refer to current file
+* meta nextmsg = jump the fence into the next pasture.
+* Discard previous pasture.
+* arg arg nextmsg = if current file is compile log, then set
+* the current location for next error to the
+* current line in the log. If the file is NOT
+* the compile log, and it is visible in a
+* window, change focus to that window. If the
+* file is NOT visible, then split the current
+* window to make it visible. If we cannot
+* split, then do nothing.
+*
+* Attempt to display the next error message from the compile. Also make
+* sure that if being displayed, the <compile> psuedo file moves with us.
+*
+* Input:
+* Standard editing function.
+*
+* Output:
+* Returns TRUE if message read, or function yCompeted. FALSE if no more
+* messages or no log to begin with.
+*
+*************************************************************************/
+
+struct msgType {
+ char *pattern;
+ int cArgs;
+ };
+
+static struct msgType CompileMsg [] =
+{ { "%s %ld %d:", 3 }, /* Zibo grep */
+ { "%[^( ](%ld,%d):", 3 }, /* new masm */
+ { "%[^( ](%ld):", 2 }, /* cmerge/masm */
+ { "%[^: ]:%ld:", 2 }, /* bogus unix GREP */
+ { "\"%[^\" ]\", line %ld:", 2 }, /* random unix CC */
+ { NULL, 0 } };
+
+flagType
+nextmsg (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ ) {
+
+ FILEHANDLE fh; /* handle for locating file */
+ flagType fHopping = FALSE; /* TRUE = hopping the fence */
+ pathbuf filebuf; /* filename from error message */
+ fl flErr; /* location of error */
+ flagType fLook; /* look at this error message? */
+ int i; /* everyone's favorite index */
+ LINE oMsgNext = 1; /* relative message number desired */
+ char *p; /* temp pointer */
+ char *pText; /* pointer into text buffer */
+ rn rnCur; /* range highlighted in log */
+ pathbuf tempbuf; /* text arg buffer */
+ linebuf textbuf; /* text arg buffer */
+
+ /*
+ * if there's no log, there's no work.
+ */
+ if (!PFILECOMP || !PFILECOMP->cLines) {
+ return FALSE;
+ }
+
+ switch (pArg->argType) {
+
+ case NULLARG:
+ /*
+ * arg arg: if current file is <compile>, set yComp to current position
+ * therein & get next message. If more than one window, move to the next
+ * window in the system before doing that.
+ */
+ if (pArg->arg.nullarg.cArg >= 2) {
+ if (pFileHead == PFILECOMP) {
+ yComp = lmax (YCUR(pInsCur) - 1, 0L);
+ if (cWin > 1) {
+ pArg->argType = NOARG;
+ window (0, pArg, FALSE);
+ }
+ break;
+ }
+ /*
+ * If the file is visible, the we can just make it current, adn we're done.
+ */
+ else for (i=cWin; i; ) {
+ pInsCur = WININST(&WinList[--i]);
+ if (pInsCur->pFile == PFILECOMP) {
+ SetWinCur (i);
+ return TRUE;
+ }
+ }
+ /*
+ * The file is not visible, see if we can split the window and go to it.
+ */
+ if ((WINYSIZE(pWinCur) > 20) && (cWin < MAXWIN)) {
+ if (SplitWnd (pWinCur, FALSE, WINYSIZE(pWinCur) / 2)) {
+ newscreen ();
+ SETFLAG (fDisplay, RCURSOR|RSTATUS);
+ SetWinCur (cWin-1);
+ fChangeFile (FALSE, rgchComp);
+ flErr.lin = 0;
+ flErr.col = 0;
+ cursorfl (flErr);
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+ /*
+ * Null arg: get the first line of the next file. That is signified by the
+ * special case offset of 0.
+ */
+ else {
+ oMsgNext = 0;
+ }
+
+ case NOARG:
+ /*
+ * meta: hop to next fence. Begin deleting lines util a fence is reached, or
+ * until there are no more lines. Set up to then read the next message line.
+ */
+ if (fMeta) {
+ do {
+ DelLine (FALSE, PFILECOMP, 0L, 0L);
+ GetLine (0L, textbuf, PFILECOMP);
+ } while (strncmp (textbuf, szFencePost, sizeof(szFencePost)-1)
+ && PFILECOMP->cLines);
+ yComp = 0;
+ }
+ /*
+ * No arg: we just get the next line (offset = 1)
+ */
+ break;
+
+ case TEXTARG:
+ /*
+ * text arg is an absolute or relative message number. If it is absolute, (no
+ * leading plus or minus sign), we reset yComp to 0 to get the n'th line
+ * from the begining of the log.
+ */
+ strcpy ((char *)textbuf, pArg->arg.textarg.pText);
+ pText = textbuf;
+ if (*pText == '+') {
+ pText++;
+ }
+ if (!fIsNum (pText)) {
+ return BadArg ();
+ }
+ if (isdigit(textbuf[0])) {
+ yComp = 0;
+ }
+ oMsgNext = atol (pText);
+ break;
+
+ default:
+ assert (FALSE);
+ }
+ /*
+ * Ensure that the compile log file has no highlighting.
+ */
+
+ ClearHiLite (PFILECOMP, TRUE);
+
+ /*
+ * This loop gets executed once per line in the file as we pass over them. We
+ * break out of the loop when the desired error line is found, or we run out
+ * of messages
+ *
+ * Entry:
+ * yComp = line # previously viewed. (0 if no messages viewed yet)
+ * oMsgNext = relative message number we want to view, or 0, indicating
+ * first message of next file.
+ */
+ while (TRUE) {
+ /*
+ * Move to check next line.
+ */
+ if (oMsgNext >= 0) {
+ yComp++;
+ } else if (oMsgNext < 0) {
+ yComp--;
+ }
+ /*
+ * read current line from the log file & check for fences & end of file. If
+ * we encounter a fence or off the end, declare that there are no more
+ * messages in this pasture.
+ */
+
+ NoUpdLog(pBTDComp);
+
+ GetLine (lmax (yComp,1L), textbuf, PFILECOMP);
+ if ( (yComp <= 0L)
+ || (yComp > PFILECOMP->cLines)
+ || !strncmp (textbuf, szFencePost, sizeof(szFencePost)-1)
+ ) {
+ UpdLog(pBTDComp);
+ if (!fBusy(pBTDComp) || (yComp <= 0L)) {
+ yComp = 0;
+ }
+ domessage ("No more compilation messages" );
+ return FALSE;
+ }
+ /*
+ * Attempt to isolate file, row, column from the line.
+ */
+ for (i = 0; CompileMsg[i].pattern != NULL; i++) {
+ flErr.lin = 0;
+ flErr.col = 0;
+ if (sscanf (textbuf, CompileMsg[i].pattern, filebuf, &flErr.lin,
+ &flErr.col) == CompileMsg[i].cArgs) {
+ break;
+ }
+ }
+ /*
+ * If A validly formatted line was found, and we can find a message (After :)
+ * then skip spaces prior to the error message (pointed to by p), pretty up
+ * the file, convert it to canonicalized form
+ */
+ if ( CompileMsg[i].pattern
+ && (*(p = strbscan (textbuf+strlen(filebuf), ":")))
+ ) {
+ p = whiteskip (p+1);
+ if (filebuf[0] != '<') {
+ rootpath (filebuf, tempbuf);
+ } else {
+ strcpy (tempbuf, filebuf);
+ }
+ /*
+ * Adjust the error message counter such that we'll display the "nth" message
+ * we encounter. Set stupid flag to indicate whether we should look at this
+ * error message.
+ */
+ fLook = FALSE;
+ if (oMsgNext > 0) {
+ if (!--oMsgNext) {
+ fLook = TRUE;
+ }
+ } else if (oMsgNext < 0) {
+ if (!++oMsgNext) {
+ fLook = TRUE;
+ }
+ } else {
+ fLook = (flagType) _strcmpi (pFileHead->pName, tempbuf);
+ }
+
+ if (fLook) {
+ /*
+ * if about to change to new file, check for existance first, and if found,
+ * autosave our current file.
+ */
+ if (_strcmpi(pFileHead->pName, tempbuf)) {
+ fh = MepFOpen(tempbuf, ACCESSMODE_READ, SHAREMODE_RW, FALSE);
+ if (fh == NULL) {
+ return disperr (MSGERR_CMPSRC, tempbuf);
+ }
+ MepFClose (fh);
+ AutoSave ();
+ }
+ /*
+ * Change the current file to that listed in the error message. If successfull,
+ * then also change our cursor location to that of the error.
+ */
+ if (filebuf[0] != 0) {
+ if (!fChangeFile (FALSE, strcpy (buf, tempbuf))) {
+ return FALSE;
+ }
+ if (flErr.lin--) {
+ if (flErr.col) {
+ flErr.col--;
+ } else {
+ cursorfl (flErr);
+ flErr.col = dobol ();
+ }
+ cursorfl (flErr);
+ }
+ }
+ /*
+ * Update the contents of the compile log, if it happens to be displayed.
+ */
+ rnCur.flLast.lin = rnCur.flFirst.lin = lmax (yComp,0L);
+ rnCur.flFirst.col = 0;
+ rnCur.flLast.col = sizeof(linebuf);
+ SetHiLite (PFILECOMP, rnCur, HGCOLOR);
+ UpdateIf (PFILECOMP, lmax (yComp,0L), FALSE);
+ /*
+ * Place the actual error message text on the dialog line.
+ */
+ if ((int)strlen(p) >= XSIZE) {
+ p[XSIZE] = '\0';
+ }
+ domessage( "%s", p );
+ return TRUE;
+ }
+ }
+ }
+
+ argData;
+}
+
+
+/*** DoFence - Build Fence message line & put it in the log file
+*
+* Builds the line output to the compile log which seperates succesive
+* compiles and puts it into the log file.
+*
+* "+++ PWB Compile: [drive:pathname] command"
+*
+* Input:
+* pCmd = ptr to command to execute (Series of null terminated strings)
+*
+* Output:
+* Returns nothing
+*
+* Remarks: - Under OS/2, since we're called by the background thread, we
+* need to switch stack checking off
+* - The background thread calls this routime at idle time
+*
+*************************************************************************/
+
+// #pragma check_stack (off)
+
+void
+DoFence (
+ char *pCmd,
+ flagType fKilled
+ ) {
+ linebuf pFenceBuf;
+
+ if (!fKilled) {
+ AppFile (BuildFence ("Compile", pCmd, pFenceBuf), pBTDComp->pBTFile);
+ UpdateIf (pBTDComp->pBTFile, pBTDComp->pBTFile->cLines - 1, FALSE);
+ }
+}
+
+
+// #pragma check_stack ()
+
+
+/*** BuildFence - Build Fence message line
+*
+* Builds the line output to the compile log which seperates succesive
+* compiles.
+*
+* "+++ PWB Compile: [drive:pathname] command"
+*
+* Input:
+* pFunction = pointer to function name being dealt with
+* pCmd = ptr to command to execute (Series of null terminated strings)
+* pFenceBuf = ptr to buffer in wich to put constructed fence
+*
+* Output:
+* Returns nothing
+*
+* Remarks: - Under OS/2, since we're called by the background thread, we
+* need to switch stack checking off
+* - The background thread calls this routime at idle time
+*
+*************************************************************************/
+
+// #pragma check_stack (off)
+
+char *
+BuildFence (
+ char const *pFunction,
+ char const *pCmd,
+ char *pFenceBuf
+ ) {
+ strcpy (pFenceBuf, szFencePost);
+ strcat (pFenceBuf, pFunction);
+ strcat (pFenceBuf, ": [");
+ GetCurPath (strend (pFenceBuf));
+ strcat (pFenceBuf, "] ");
+ strcat (pFenceBuf, pCmd);
+ return (pFenceBuf);
+}
+
+// #pragma check_stack ()
diff --git a/private/utils/mep/src/console.c b/private/utils/mep/src/console.c
new file mode 100644
index 000000000..f7f5adf2b
--- /dev/null
+++ b/private/utils/mep/src/console.c
@@ -0,0 +1,2456 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ console.c
+
+Abstract:
+
+ Interface to the console for Win32 applications.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 30-Nov-1990
+
+
+Revision History:
+
+
+--*/
+
+#include <string.h>
+#include "mep.h"
+#include "mouse.h"
+
+
+
+
+//
+// EVENT BUFFER
+//
+// The event buffer is used to store event records from the input
+// queue.
+//
+#define INITIAL_EVENTS 32
+#define MAX_EVENTS 64
+#define EVENT_INCREMENT 4
+
+#define ADVANCE TRUE
+#define NOADVANCE FALSE
+#define WAIT TRUE
+#define NOWAIT FALSE
+
+//
+// For accessing fields of an event record
+//
+#define EVENT_TYPE(p) ((p)->EventType)
+#define EVENT_DATA(p) ((p)->Event)
+
+//
+// For casting event records
+//
+#define PMOUSE_EVT(p) (&(EVENT_DATA(p).MouseEvent))
+#define PWINDOW_EVT(p) (&(EVENT_DATA(p).WindowBufferSizeEvent))
+#define PKEY_EVT(p) (&(EVENT_DATA(p).KeyEvent))
+#define PMENU_EVT(p) (&(EVENT_DATA(p).MenuEvent))
+#define PFOCUS_EVT(p) (&(EVENT_DATA(p).FocusEvent))
+//
+// The event buffer structure
+//
+typedef struct EVENT_BUFFER {
+ DWORD MaxEvents; // Max number of events in buffer
+ DWORD NumberOfEvents; // Number of events in buffer
+ DWORD EventIndex; // Event Index
+ BOOL BusyFlag; // Busy flag
+ CRITICAL_SECTION CriticalSection; // To maintain integrity
+ CRITICAL_SECTION PeekCriticalSection; // While peeking
+ PINPUT_RECORD EventBuffer; // Event Buffer
+} EVENT_BUFFER, *PEVENT_BUFFER;
+
+
+
+
+
+//
+// Screen attributes
+//
+#define BLACK_FGD 0
+#define BLUE_FGD FOREGROUND_BLUE
+#define GREEN_FGD FOREGROUND_GREEN
+#define CYAN_FGD (FOREGROUND_BLUE | FOREGROUND_GREEN)
+#define RED_FGD FOREGROUND_RED
+#define MAGENTA_FGD (FOREGROUND_BLUE | FOREGROUND_RED)
+#define YELLOW_FGD (FOREGROUND_GREEN | FOREGROUND_RED)
+#define WHITE_FGD (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED)
+
+#define BLACK_BGD 0
+#define BLUE_BGD BACKGROUND_BLUE
+#define GREEN_BGD BACKGROUND_GREEN
+#define CYAN_BGD (BACKGROUND_BLUE | BACKGROUND_GREEN)
+#define RED_BGD BACKGROUND_RED
+#define MAGENTA_BGD (BACKGROUND_BLUE | BACKGROUND_RED)
+#define YELLOW_BGD (BACKGROUND_GREEN | BACKGROUND_RED)
+#define WHITE_BGD (BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED)
+
+
+
+//
+// The AttrBg and AttrFg arrays are used for mapping DOS attributes
+// to the new attributes.
+//
+WORD AttrBg[ ] = {
+ BLACK_BGD, // black
+ BLUE_BGD, // blue
+ GREEN_BGD, // green
+ CYAN_BGD, // cyan
+ RED_BGD, // red
+ MAGENTA_BGD, // magenta
+ YELLOW_BGD, // brown
+ WHITE_BGD, // light gray
+ BACKGROUND_INTENSITY | BLACK_BGD, // dark gray
+ BACKGROUND_INTENSITY | BLUE_BGD, // light blue
+ BACKGROUND_INTENSITY | GREEN_BGD, // light green
+ BACKGROUND_INTENSITY | CYAN_BGD, // light cyan
+ BACKGROUND_INTENSITY | RED_BGD, // light red
+ BACKGROUND_INTENSITY | MAGENTA_BGD, // light magenta
+ BACKGROUND_INTENSITY | YELLOW_BGD, // light yellow
+ BACKGROUND_INTENSITY | WHITE_BGD // white
+};
+
+WORD AttrFg[ ] = {
+ BLACK_FGD, // black
+ BLUE_FGD, // blue
+ GREEN_FGD, // green
+ CYAN_FGD, // cyan
+ RED_FGD, // red
+ MAGENTA_FGD, // magenta
+ YELLOW_FGD, // brown
+ WHITE_FGD, // light gray
+ FOREGROUND_INTENSITY | BLACK_FGD, // dark gray
+ FOREGROUND_INTENSITY | BLUE_FGD, // light blue
+ FOREGROUND_INTENSITY | GREEN_FGD, // light green
+ FOREGROUND_INTENSITY | CYAN_FGD, // light cyan
+ FOREGROUND_INTENSITY | RED_FGD, // light red
+ FOREGROUND_INTENSITY | MAGENTA_FGD, // light magenta
+ FOREGROUND_INTENSITY | YELLOW_FGD, // light yellow
+ FOREGROUND_INTENSITY | WHITE_FGD // white
+};
+
+//
+// GET_ATTRIBUTE performs the mapping from old attributes to new attributes
+//
+#define GET_ATTRIBUTE(x) (AttrFg[x & 0x000F ] | AttrBg[( x & 0x00F0 ) >> 4])
+
+
+//
+// The LINE_INFO structure contains information about each line in the
+// screen buffer.
+//
+typedef struct _LINE_INFO {
+
+ BOOL Dirty; // True if has not been displayed
+ BOOL Garbage; // True if contents are garbage
+ int colMinChanged; // if dirty, smallest col changed
+ int colMaxChanged; // if dirty, biggest col changed
+ PCHAR_INFO Line; // Pointer to the line.
+
+} LINE_INFO, *PLINE_INFO;
+
+#define ResetLineInfo(pli) \
+ { pli->Dirty = FALSE; \
+ pli->Garbage = TRUE; \
+ pli->colMinChanged = 10000; \
+ pli->colMaxChanged = -1; \
+ }
+
+//
+// The SCREEN_DATA structure contains the information about individual
+// screens.
+//
+typedef struct SCREEN_DATA {
+ HANDLE ScreenHandle; // Handle to screen
+ PLINE_INFO LineInfo; // Array of line info.
+ PCHAR_INFO ScreenBuffer; // Screen buffer
+ ULONG MaxBufferSize; // Max. buffer size
+ ATTRIBUTE AttributeOld; // Attribute - original
+ WORD AttributeNew; // Attribute - converted
+ ROW FirstRow; // First row to update
+ ROW LastRow; // Last row to update
+ CRITICAL_SECTION CriticalSection; // To maintain integrity
+ DWORD CursorSize; // Cursor Size
+ SCREEN_INFORMATION ScreenInformation; // Screen information
+} SCREEN_DATA, *PSCREEN_DATA;
+
+
+//
+// Static global data
+//
+static EVENT_BUFFER EventBuffer; // Event buffer
+static HANDLE hInput; // handle to stdin
+static HANDLE hOutput; // handle to stdout
+static HANDLE hError; // handle to stderr
+static PSCREEN_DATA OutputScreenData; // Screen data for hOutput
+static PSCREEN_DATA ActiveScreenData; // Points to current screen data
+static BOOL Initialized = FALSE; // Initialized flag
+
+
+#if defined (DEBUG)
+ static char DbgBuffer[128];
+#endif
+
+
+//
+// Local Prototypes
+//
+BOOL
+InitializeGlobalState (
+ void
+ );
+
+
+PSCREEN_DATA
+MakeScreenData (
+ HANDLE ScreenHandle
+ );
+
+BOOL
+InitLineInfo (
+ PSCREEN_DATA ScreenData
+ );
+
+PINPUT_RECORD
+NextEvent (
+ BOOL fAdvance,
+ BOOL fWait
+ );
+
+void
+MouseEvent (
+ PMOUSE_EVENT_RECORD pEvent
+ );
+
+BOOL
+WindowEvent (
+ PWINDOW_BUFFER_SIZE_RECORD pEvent
+ );
+
+BOOL
+MenuEvent (
+ PMENU_EVENT_RECORD pEvent
+ );
+
+BOOL
+FocusEvent (
+ PFOCUS_EVENT_RECORD pEvent
+ );
+
+BOOL
+KeyEvent (
+ PKEY_EVENT_RECORD pEvent,
+ PKBDKEY pKey
+ );
+
+
+BOOL
+PutEvent (
+ PINPUT_RECORD InputRecord
+ );
+
+
+BOOL
+InitializeGlobalState (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Initializes our global state data.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if success
+ FALSE otherwise.
+
+--*/
+{
+
+
+ //
+ // Initialize the event buffer
+ //
+ InitializeCriticalSection( &(EventBuffer.CriticalSection) );
+ InitializeCriticalSection( &(EventBuffer.PeekCriticalSection) );
+ EventBuffer.NumberOfEvents = 0;
+ EventBuffer.EventIndex = 0;
+ EventBuffer.BusyFlag = FALSE;
+ EventBuffer.EventBuffer = MALLOC( INITIAL_EVENTS * sizeof(INPUT_RECORD) );
+
+ if ( !EventBuffer.EventBuffer ) {
+ return FALSE;
+ }
+
+ EventBuffer.MaxEvents = INITIAL_EVENTS;
+
+
+ //
+ // Get handles to stdin, stdout and stderr
+ //
+ hInput = GetStdHandle( STD_INPUT_HANDLE );
+ hOutput = GetStdHandle( STD_OUTPUT_HANDLE );
+ hError = GetStdHandle( STD_ERROR_HANDLE );
+
+
+ //
+ // Initialize the screen data for hOutput
+ //
+ if ( !(OutputScreenData = MakeScreenData( hOutput )) ) {
+ return FALSE;
+ }
+
+
+ //
+ // Current screen is hOutput
+ //
+ ActiveScreenData = OutputScreenData;
+
+
+ return (Initialized = TRUE);
+
+}
+
+
+
+
+
+PSCREEN_DATA
+MakeScreenData (
+ HANDLE ScreenHandle
+ )
+/*++
+
+Routine Description:
+
+ Allocates memory for a SCREEN_DATA information and initializes it.
+
+Arguments:
+
+ ScreenHandle - Supplies handle of screen.
+
+Return Value:
+
+ POINTER to allocated SCREEN_DATA structure
+
+--*/
+{
+ PSCREEN_DATA ScreenData; // Pointer to screen data
+ CONSOLE_SCREEN_BUFFER_INFO ScrInfo; // Screen buffer info.
+
+
+ //
+ // Allocate space for the screen data.
+ //
+ if ( !(ScreenData = (PSCREEN_DATA)MALLOC(sizeof(SCREEN_DATA))) ) {
+ return NULL;
+ }
+
+ //
+ // Allocate space for our copy of the screen buffer.
+ //
+ GetConsoleScreenBufferInfo( ScreenHandle,
+ &ScrInfo );
+
+ ScreenData->MaxBufferSize = ScrInfo.dwSize.Y *
+ ScrInfo.dwSize.X;
+
+ ScreenData->ScreenBuffer = (PCHAR_INFO)MALLOC( ScreenData->MaxBufferSize *
+ sizeof(CHAR_INFO));
+
+ if ( !ScreenData->ScreenBuffer ) {
+ FREE( ScreenData );
+ return NULL;
+ }
+
+ //
+ // Allocate space for the LineInfo array
+ //
+ ScreenData->LineInfo = (PLINE_INFO)MALLOC( ScrInfo.dwSize.Y * sizeof( LINE_INFO ) );
+ if ( !ScreenData->LineInfo ) {
+ FREE( ScreenData->ScreenBuffer );
+ FREE( ScreenData );
+ return NULL;
+ }
+
+
+ //
+ // Memory has been allocated, now initialize the structure
+ //
+ ScreenData->ScreenHandle = ScreenHandle;
+
+ ScreenData->ScreenInformation.NumberOfRows = ScrInfo.dwSize.Y;
+ ScreenData->ScreenInformation.NumberOfCols = ScrInfo.dwSize.X;
+
+ ScreenData->ScreenInformation.CursorRow = ScrInfo.dwCursorPosition.Y;
+ ScreenData->ScreenInformation.CursorCol = ScrInfo.dwCursorPosition.X;
+
+ ScreenData->AttributeNew = ScrInfo.wAttributes;
+ ScreenData->AttributeOld = 0x00;
+
+ ScreenData->FirstRow = ScreenData->ScreenInformation.NumberOfRows;
+ ScreenData->LastRow = 0;
+
+ InitializeCriticalSection( &(ScreenData->CriticalSection) );
+
+ InitLineInfo( ScreenData );
+
+ return ScreenData;
+}
+
+
+
+
+
+BOOL
+InitLineInfo (
+ PSCREEN_DATA ScreenData
+ )
+/*++
+
+Routine Description:
+
+ Initializes the LineInfo array.
+
+Arguments:
+
+ ScreenData - Supplies pointer to screen data.
+
+Return Value:
+
+ TRUE if initialized, false otherwise.
+
+--*/
+{
+
+ ROW Row;
+ COLUMN Cols;
+ PLINE_INFO LineInfo;
+ PCHAR_INFO CharInfo;
+
+
+ LineInfo = ScreenData->LineInfo;
+ CharInfo = ScreenData->ScreenBuffer;
+ Row = ScreenData->ScreenInformation.NumberOfRows;
+ Cols = ScreenData->ScreenInformation.NumberOfCols;
+
+ while ( Row-- ) {
+
+ ResetLineInfo (LineInfo);
+
+ LineInfo->Line = CharInfo;
+
+ LineInfo++;
+ CharInfo += Cols;
+
+ }
+
+ return TRUE;
+}
+
+
+
+
+
+PSCREEN
+consoleNewScreen (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Creates a new screen.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Pointer to screen data.
+
+--*/
+{
+ PSCREEN_DATA ScreenData; // Screen data
+ HANDLE NewScreenHandle;
+ SMALL_RECT NewSize;
+ CONSOLE_SCREEN_BUFFER_INFO ScrInfo; // Screen buffer info.
+ CONSOLE_CURSOR_INFO CursorInfo;
+
+ if ( !Initialized ) {
+
+ //
+ // We have to initialize our global state.
+ //
+ if ( !InitializeGlobalState() ) {
+ return NULL;
+ }
+ }
+
+ //
+ // Create a new screen buffer
+ //
+ NewScreenHandle = CreateConsoleScreenBuffer(GENERIC_WRITE | GENERIC_READ,
+ 0,
+ NULL,
+ CONSOLE_TEXTMODE_BUFFER,
+ NULL );
+
+ if (NewScreenHandle == INVALID_HANDLE_VALUE) {
+ //
+ // No luck
+ //
+ return NULL;
+ }
+
+ //
+ // We want the new window to be the same size as the current one, so
+ // we resize it.
+ //
+ GetConsoleScreenBufferInfo( ActiveScreenData->ScreenHandle,
+ &ScrInfo );
+
+ NewSize.Left = 0;
+ NewSize.Top = 0;
+ NewSize.Right = ScrInfo.srWindow.Right - ScrInfo.srWindow.Left;
+ NewSize.Bottom = ScrInfo.srWindow.Bottom - ScrInfo.srWindow.Top;
+
+ SetConsoleWindowInfo( NewScreenHandle, TRUE, &NewSize );
+
+ //
+ // Now we create a screen data structure for it.
+ //
+ if ( !(ScreenData = MakeScreenData(NewScreenHandle)) ) {
+ CloseHandle(NewScreenHandle);
+ return NULL;
+ }
+
+
+ CursorInfo.bVisible = TRUE;
+ ScreenData->CursorSize = CursorInfo.dwSize = 25;
+
+ SetConsoleCursorInfo ( ScreenData->ScreenHandle,
+ &CursorInfo );
+
+ //
+ // We are all set. We return a pointer to the
+ // screen data.
+ //
+ return (PSCREEN)ScreenData;
+}
+
+
+
+
+
+BOOL
+consoleCloseScreen (
+ PSCREEN pScreen
+ )
+/*++
+
+Routine Description:
+
+ Closes a screen.
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data.
+
+Return Value:
+
+ TRUE if screen closed.
+ FALSE otherwise
+
+--*/
+{
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+
+ //
+ // We cannot close the active screen
+ //
+ if ( !ScreenData || (ScreenData == ActiveScreenData) ) {
+ return FALSE;
+ }
+
+ if (ScreenData->ScreenHandle != INVALID_HANDLE_VALUE) {
+ CloseHandle(ScreenData->ScreenHandle);
+ }
+
+ FREE( ScreenData->LineInfo );
+ FREE( ScreenData->ScreenBuffer );
+ FREE( ScreenData );
+
+ return TRUE;
+}
+
+
+
+
+
+PSCREEN
+consoleGetCurrentScreen (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Returns the current screen.
+
+Arguments:
+
+ none.
+
+Return Value:
+
+ Pointer to currently active screen data.
+
+--*/
+{
+ if ( !Initialized ) {
+
+ //
+ // We have to initialize our global state.
+ //
+ if (!InitializeGlobalState()) {
+ return NULL;
+ }
+ }
+
+ return (PSCREEN)ActiveScreenData;
+}
+
+
+
+
+
+BOOL
+consoleSetCurrentScreen (
+ PSCREEN pScreen
+ )
+/*++
+
+Routine Description:
+
+ Sets the active screen.
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data.
+
+Return Value:
+
+ TRUE if the active screen set
+ FALSE otherwise.
+
+--*/
+{
+ BOOL ScreenSet = TRUE;
+ PSCREEN_DATA CurrentScreen = ActiveScreenData;
+
+
+ EnterCriticalSection( &(CurrentScreen->CriticalSection) );
+
+ ScreenSet = SetConsoleActiveScreenBuffer( ((PSCREEN_DATA)pScreen)->ScreenHandle);
+
+ if (ScreenSet) {
+ ActiveScreenData = (PSCREEN_DATA)pScreen;
+ }
+
+ LeaveCriticalSection( &(CurrentScreen->CriticalSection) );
+
+ return ScreenSet;
+}
+
+
+
+
+
+BOOL
+consoleGetScreenInformation (
+ PSCREEN pScreen,
+ PSCREEN_INFORMATION pScreenInfo
+ )
+/*++
+
+Routine Description:
+
+ Sets the active screen.
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data.
+ pScreenInfo - Supplies pointer to screen info buffer
+
+Return Value:
+
+ TRUE if the screen info returned
+ FALSE otherwise.
+
+--*/
+{
+
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+
+ if (!ScreenData) {
+ return FALSE;
+ }
+
+ EnterCriticalSection( &(ScreenData->CriticalSection) );
+
+ memcpy(pScreenInfo, &(ScreenData->ScreenInformation), sizeof(SCREEN_INFORMATION));
+
+ LeaveCriticalSection( &(ScreenData->CriticalSection) );
+
+ return TRUE;
+}
+
+
+
+BOOL
+consoleSetScreenSize (
+ PSCREEN pScreen,
+ ROW Rows,
+ COLUMN Cols
+ )
+/*++
+
+Routine Description:
+
+ Sets the screen size
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data.
+ Rows - Number of rows
+ Cols - Number of columns
+
+Return Value:
+
+ TRUE if screen size changed successfully
+ FALSE otherwise.
+
+--*/
+{
+
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+ CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo;
+ SMALL_RECT ScreenRect;
+ COORD ScreenSize;
+ USHORT MinRows;
+ USHORT MinCols;
+ ULONG NewBufferSize;
+ BOOL WindowSet = FALSE;
+ BOOL Status = FALSE;
+
+ //
+ // Won't attempt to resize larger than the largest window size
+ //
+ ScreenSize = GetLargestConsoleWindowSize( ScreenData->ScreenHandle );
+
+ if ( (Rows > (ROW)ScreenSize.Y) || (Cols > (COLUMN)ScreenSize.X) ) {
+ return FALSE;
+ }
+
+ EnterCriticalSection( &(ScreenData->CriticalSection) );
+
+ //
+ // Obtain the current screen information.
+ //
+ if ( GetConsoleScreenBufferInfo( ScreenData->ScreenHandle, &ScreenBufferInfo ) ) {
+
+ //
+ // If the desired buffer size is smaller than the current window
+ // size, we have to resize the current window first.
+ //
+ if ( ( Rows < (ROW)
+ (ScreenBufferInfo.srWindow.Bottom -
+ ScreenBufferInfo.srWindow.Top + 1) ) ||
+ ( Cols < (COLUMN)
+ (ScreenBufferInfo.srWindow.Right -
+ ScreenBufferInfo.srWindow.Left + 1) ) ) {
+
+ //
+ // Set the window to a size that will fit in the current
+ // screen buffer and that is no bigger than the size to
+ // which we want to grow the screen buffer.
+ //
+ MinRows = (USHORT)min( (int)Rows, (int)(ScreenBufferInfo.dwSize.Y) );
+ MinCols = (USHORT)min( (int)Cols, (int)(ScreenBufferInfo.dwSize.X) );
+
+ ScreenRect.Top = 0;
+ ScreenRect.Left = 0;
+ ScreenRect.Right = (SHORT)MinCols - (SHORT)1;
+ ScreenRect.Bottom = (SHORT)MinRows - (SHORT)1;
+
+ WindowSet = (BOOL)SetConsoleWindowInfo( ScreenData->ScreenHandle, TRUE, &ScreenRect );
+
+ if ( !WindowSet ) {
+ //
+ // ERROR
+ //
+ goto Done;
+ }
+ }
+
+ //
+ // Set the screen buffer size to the desired size.
+ //
+ ScreenSize.X = (WORD)Cols;
+ ScreenSize.Y = (WORD)Rows;
+
+ if ( !SetConsoleScreenBufferSize( ScreenData->ScreenHandle, ScreenSize ) ) {
+
+ //
+ // ERROR
+ //
+ //
+ // Return the window to its original size. We ignore the return
+ // code because there is nothing we can do about it.
+ //
+ SetConsoleWindowInfo( ScreenData->ScreenHandle, TRUE, &(ScreenBufferInfo.srWindow) );
+ goto Done;
+ }
+
+ //
+ // resize the screen buffer. Note that the contents of the screen
+ // buffer are not valid anymore. Someone else will have to update
+ // them.
+ //
+ NewBufferSize = Rows * Cols;
+
+ if (ScreenData->MaxBufferSize < NewBufferSize ) {
+ ScreenData->ScreenBuffer = REALLOC( ScreenData->ScreenBuffer, NewBufferSize * sizeof(CHAR_INFO));
+ ScreenData->MaxBufferSize = NewBufferSize;
+ ScreenData->LineInfo = REALLOC( ScreenData->LineInfo, Rows * sizeof( LINE_INFO ) );
+ }
+
+ //
+ // Set the Window Size. We know that we can grow the window to this size
+ // because we tested the size against the largest window size at the
+ // beginning of the function.
+ //
+ ScreenRect.Top = 0;
+ ScreenRect.Left = 0;
+ ScreenRect.Right = (SHORT)Cols - (SHORT)1;
+ ScreenRect.Bottom = (SHORT)Rows - (SHORT)1;
+
+ WindowSet = (BOOL)SetConsoleWindowInfo( ScreenData->ScreenHandle, TRUE, &ScreenRect );
+
+ if ( !WindowSet ) {
+ //
+ // We could not resize the window. We will leave the
+ // resized screen buffer.
+ //
+ // ERROR
+ //
+ InitLineInfo( ScreenData );
+ goto Done;
+ }
+
+ //
+ // Update the screen size
+ //
+ ScreenData->ScreenInformation.NumberOfRows = Rows;
+ ScreenData->ScreenInformation.NumberOfCols = Cols;
+
+ InitLineInfo( ScreenData );
+
+ //
+ // Done
+ //
+ Status = TRUE;
+
+ } else {
+
+ //
+ // ERROR
+ //
+ Status = FALSE;
+ }
+
+Done:
+ //
+ // Invalidate the entire screen buffer
+ //
+ ScreenData->FirstRow = ScreenData->ScreenInformation.NumberOfRows;
+ ScreenData->LastRow = 0;
+
+ LeaveCriticalSection( &(ScreenData->CriticalSection) );
+ return Status;
+
+}
+
+
+
+
+BOOL
+consoleSetCursor (
+ PSCREEN pScreen,
+ ROW Row,
+ COLUMN Col
+ )
+/*++
+
+Routine Description:
+
+ Moves the cursor to a certain position.
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data
+ Row - Supplies row coordinate
+ Col - Supplies column coordinate
+
+Return Value:
+
+ TRUE if moved
+ FALSE otherwise.
+
+--*/
+{
+
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+ COORD Position;
+ BOOL Moved = FALSE;
+
+
+ EnterCriticalSection( &(ScreenData->CriticalSection) );
+
+ if ((Row != ScreenData->ScreenInformation.CursorRow) ||
+ (Col != ScreenData->ScreenInformation.CursorCol) ) {
+
+ assert( Row < ScreenData->ScreenInformation.NumberOfRows);
+ assert( Col < ScreenData->ScreenInformation.NumberOfCols);
+
+ Position.Y = (SHORT)Row;
+ Position.X = (SHORT)Col;
+
+ if ( SetConsoleCursorPosition( ScreenData->ScreenHandle,
+ Position )) {
+ //
+ // Cursor moved, update the data
+ //
+ ScreenData->ScreenInformation.CursorRow = Row;
+ ScreenData->ScreenInformation.CursorCol = Col;
+
+ Moved = TRUE;
+ }
+ }
+
+ LeaveCriticalSection( &(ScreenData->CriticalSection) );
+
+ return Moved;
+}
+
+
+
+
+BOOL
+consoleSetCursorStyle (
+ PSCREEN pScreen,
+ ULONG Style
+ )
+
+/*++
+
+Routine Description7:
+
+ Sets the cursor style. The two available styles are: underscrore and
+ box
+
+Arguments:
+
+ Style - New cursor style
+
+Return Value:
+
+ True if cursor style set
+
+--*/
+
+{
+
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+ CONSOLE_CURSOR_INFO CursorInfo;
+
+ CursorInfo.bVisible = TRUE;
+
+ if ( Style == CURSOR_STYLE_UNDERSCORE ) {
+
+ CursorInfo.dwSize = 25;
+
+ } else if ( Style == CURSOR_STYLE_BOX ) {
+
+ CursorInfo.dwSize = 100;
+
+ } else {
+
+ return FALSE;
+
+ }
+
+ ScreenData->CursorSize = CursorInfo.dwSize;
+
+ return SetConsoleCursorInfo ( ScreenData->ScreenHandle,
+ &CursorInfo );
+
+}
+
+
+
+
+
+ULONG
+consoleWriteLine (
+ PSCREEN pScreen,
+ PVOID pBuffer,
+ ULONG BufferSize,
+ ROW Row,
+ COLUMN Col,
+ ATTRIBUTE Attribute,
+ BOOL Blank
+ )
+/*++
+
+Routine Description7:
+
+ Writes a buffer to the screen with the specified attribute and blanks
+ to end of row.
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data
+ pBuffer - Supplies pointer to buffer
+ BufferSize - Supplies the size of the buffer
+ Row - Supplies row coordinate
+ Col - Supplies column coordinate
+ Attr - Supplies the attribute
+ Blank - TRUE if we should blank to end of last row written.
+
+Return Value:
+
+ Number of bytes written
+
+--*/
+{
+
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+ PLINE_INFO LineInfo;
+ PCHAR_INFO CharInfo;
+ CHAR_INFO Char;
+ WORD Attr;
+
+ char * p = (char *)pBuffer;
+
+ COLUMN ColsLeft; // Available columns
+ COLUMN InfoCols; // Columns taken from buffer
+ COLUMN BlankCols; // Columns to be blanked
+ COLUMN Column; // Counter;
+
+ //
+ // We will ignore writes outside of the screen buffer
+ //
+ if ( ( Row >= ScreenData->ScreenInformation.NumberOfRows ) ||
+ ( Col >= ScreenData->ScreenInformation.NumberOfCols ) ) {
+ return TRUE;
+ }
+
+ //
+ // Ignore trivial writes
+ //
+ if (BufferSize == 0 && !Blank) {
+ return TRUE;
+ }
+
+
+ EnterCriticalSection( &(ScreenData->CriticalSection) );
+
+
+ //
+ // We will truncate writes that are too long
+ //
+ if ( (Col + BufferSize) >= ScreenData->ScreenInformation.NumberOfCols ) {
+ BufferSize = ScreenData->ScreenInformation.NumberOfCols - Col;
+ }
+
+ LineInfo = ScreenData->LineInfo + Row;
+ CharInfo = LineInfo->Line + Col;
+
+ ColsLeft = ScreenData->ScreenInformation.NumberOfCols - Col;
+ InfoCols = min( BufferSize, ColsLeft );
+ BlankCols = Blank ? (ColsLeft - InfoCols) : 0;
+
+ //
+ // Set the attribute
+ //
+ if ( Attribute != ScreenData->AttributeOld ) {
+ ScreenData->AttributeOld = Attribute;
+ ScreenData->AttributeNew = GET_ATTRIBUTE(Attribute);
+ }
+ Attr = ScreenData->AttributeNew;
+
+ //
+ // set up default attribute
+ //
+ Char.Attributes = Attr;
+
+ //
+ // set up number of columns to draw
+ //
+ Column = InfoCols;
+
+ //
+ // draw chars in all specified columns
+ //
+ while ( Column-- ) {
+
+ //
+ // use character from input string
+ //
+ Char.Char.AsciiChar = *p++;
+
+ //
+ // update change portions of line info
+ //
+ if (LineInfo->Garbage ||
+ CharInfo->Attributes != Char.Attributes ||
+ CharInfo->Char.AsciiChar != Char.Char.AsciiChar) {
+
+ LineInfo->colMinChanged = min (LineInfo->colMinChanged, CharInfo - LineInfo->Line);
+ LineInfo->colMaxChanged = max (LineInfo->colMaxChanged, CharInfo - LineInfo->Line);
+ LineInfo->Dirty = TRUE;
+ }
+
+ //
+ // set up new character
+ //
+ *CharInfo++ = Char;
+ }
+
+
+ //
+ // Blank to end of line
+ //
+ Char.Attributes = Attr;
+ Char.Char.AsciiChar = ' ';
+ Column = BlankCols;
+
+ while ( Column-- ) {
+
+ //
+ // update change portions of line info
+ //
+ if (LineInfo->Garbage ||
+ CharInfo->Attributes != Char.Attributes ||
+ CharInfo->Char.AsciiChar != Char.Char.AsciiChar) {
+
+ LineInfo->colMinChanged = min (LineInfo->colMinChanged, CharInfo - LineInfo->Line);
+ LineInfo->colMaxChanged = max (LineInfo->colMaxChanged, CharInfo - LineInfo->Line);
+ LineInfo->Dirty = TRUE;
+ }
+
+ *CharInfo++ = Char;
+ }
+
+
+ //
+ // Update row information
+ //
+ if ( Row < ScreenData->FirstRow ) {
+ ScreenData->FirstRow = Row;
+ }
+ if ( Row > ScreenData->LastRow ) {
+ ScreenData->LastRow = Row;
+ }
+
+ LeaveCriticalSection( &(ScreenData->CriticalSection) );
+
+ return (ULONG)(InfoCols + BlankCols);
+}
+
+
+
+
+
+BOOL
+consoleShowScreen (
+ PSCREEN pScreen
+ )
+/*++
+
+Routine Description:
+
+ Moves data from our screen buffer to the console screen buffer.
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data
+
+Return Value:
+
+ TRUE if done
+ FALSE otherwise
+
+--*/
+{
+
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+ CONSOLE_CURSOR_INFO CursorInfo;
+ PLINE_INFO LineInfo;
+ BOOL Shown = FALSE;
+ ROW FirstRow;
+ ROW LastRow;
+ COLUMN LastCol;
+
+ COORD Position;
+ COORD Size;
+ SMALL_RECT Rectangle;
+
+ EnterCriticalSection( &(ScreenData->CriticalSection) );
+
+ if ( ScreenData->FirstRow <= ScreenData->LastRow ) {
+
+ Size.X = (SHORT)(ScreenData->ScreenInformation.NumberOfCols);
+ Size.Y = (SHORT)(ScreenData->ScreenInformation.NumberOfRows);
+
+ FirstRow = ScreenData->FirstRow;
+ LineInfo = ScreenData->LineInfo + FirstRow;
+
+ LastCol = ScreenData->ScreenInformation.NumberOfCols-1;
+
+ //
+ // Find next dirty block
+ //
+ while ( (FirstRow <= ScreenData->LastRow) && !LineInfo->Dirty ) {
+ FirstRow++;
+ LineInfo++;
+ }
+
+ while ( FirstRow <= ScreenData->LastRow ) {
+
+ int colLeft, colRight;
+
+ //
+ // Get the block
+ //
+
+ LastRow = FirstRow;
+
+ //
+ // set up for left/right boundary accrual
+ //
+
+ colLeft = LastCol + 1;
+ colRight = -1;
+
+ while ( (LastRow <= ScreenData->LastRow) && LineInfo->Dirty ) {
+
+ //
+ // accrue smallest bounding right/left margins
+ //
+
+ colLeft = min (colLeft, LineInfo->colMinChanged);
+ colRight = max (colRight, LineInfo->colMaxChanged);
+
+ //
+ // reset line information
+ //
+
+ ResetLineInfo (LineInfo);
+
+ //
+ // advance to next row
+ //
+
+ LastRow++;
+ LineInfo++;
+ }
+ LastRow--;
+
+
+ //
+ // Write the block
+ //
+ assert( FirstRow <= LastRow );
+
+ Position.X = (SHORT)colLeft;
+ Position.Y = (SHORT)FirstRow;
+
+ Rectangle.Top = (SHORT)FirstRow;
+ Rectangle.Bottom = (SHORT)LastRow;
+ Rectangle.Left = (SHORT) colLeft;
+ Rectangle.Right = (SHORT) colRight;
+
+ //
+ // Performance hack: making the cursor invisible speeds
+ // screen updates.
+ //
+ CursorInfo.bVisible = FALSE;
+ CursorInfo.dwSize = ScreenData->CursorSize;
+ SetConsoleCursorInfo ( ScreenData->ScreenHandle,
+ &CursorInfo );
+
+ Shown = WriteConsoleOutput( ScreenData->ScreenHandle,
+ ScreenData->ScreenBuffer,
+ Size,
+ Position,
+ &Rectangle );
+
+#if defined (DEBUG)
+ if ( !Shown ) {
+ char DbgB[128];
+ sprintf(DbgB, "MEP: WriteConsoleOutput Error %d\n", GetLastError() );
+ OutputDebugString( DbgB );
+ }
+#endif
+ assert( Shown );
+
+ CursorInfo.bVisible = TRUE;
+ SetConsoleCursorInfo ( ScreenData->ScreenHandle,
+ &CursorInfo );
+
+ FirstRow = LastRow + 1;
+
+ //
+ // Find next dirty block
+ //
+ while ( (FirstRow <= ScreenData->LastRow) && !LineInfo->Dirty ) {
+ FirstRow++;
+ LineInfo++;
+ }
+ }
+
+ ScreenData->LastRow = 0;
+ ScreenData->FirstRow = ScreenData->ScreenInformation.NumberOfRows;
+
+ }
+
+ LeaveCriticalSection( &(ScreenData->CriticalSection) );
+
+ return Shown;
+
+}
+
+
+
+
+
+BOOL
+consoleClearScreen (
+ PSCREEN pScreen,
+ BOOL ShowScreen
+ )
+/*++
+
+Routine Description:
+
+ Clears the screen
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data
+
+Return Value:
+
+ TRUE if screen cleared
+ FALSE otherwise
+
+--*/
+{
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+ ROW Rows;
+ BOOL Status = TRUE;
+
+ EnterCriticalSection( &(ScreenData->CriticalSection) );
+
+ Rows = ScreenData->ScreenInformation.NumberOfRows;
+
+ while ( Rows-- ) {
+ consoleWriteLine( pScreen, NULL, 0, Rows, 0, ScreenData->AttributeOld, TRUE );
+ }
+
+ if (ShowScreen) {
+ Status = consoleShowScreen( pScreen );
+ }
+
+ LeaveCriticalSection( &(ScreenData->CriticalSection) );
+
+ return Status;
+}
+
+
+
+BOOL
+consoleScrollVert (
+ PSCREEN pScreen,
+ ROW Top,
+ COLUMN Left,
+ ROW Bottom,
+ COLUMN Right,
+ INT Rows
+ )
+/*++
+
+Routine Description:
+
+ Scrolls
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data
+ Top - Supplies top row
+ Left - Supplies left column
+ Bottom - Supplies bottom row
+ Right - Supplies right column
+ Rows - Number of rows to scroll
+
+Return Value:
+
+ TRUE if scrolled
+ FALSE otherwise
+
+--*/
+
+{
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+ SMALL_RECT Rect;
+ COORD Coord;
+ CHAR_INFO CharInfo;
+ BOOLEAN Ok;
+ PLINE_INFO LineInfo;
+ ROW R;
+
+ if ( Rows ) {
+
+ EnterCriticalSection( &(ScreenData->CriticalSection) );
+
+ //
+ // If there is something to flush, we flush it now
+ //
+ if ( ScreenData->FirstRow <= ScreenData->LastRow ) {
+ consoleShowScreen( pScreen );
+ }
+
+
+ //
+ // Scroll
+ //
+ Coord.X = (SHORT)Left;
+ Coord.Y = (SHORT)Top;
+
+ Rect.Left = (SHORT)Left;
+ Rect.Top = (SHORT)Top;
+ Rect.Right = (SHORT)Right;
+ Rect.Bottom = (SHORT)Bottom;
+
+ if ( Rows > 0 ) {
+
+ Rect.Top += Rows;
+
+ } else {
+
+ Rect.Bottom += Rows;
+ Coord.Y -= Rows;
+ }
+
+
+ CharInfo.Char.AsciiChar = ' ';
+ CharInfo.Attributes = ScreenData->AttributeNew;
+
+ Ok = ScrollConsoleScreenBuffer(
+ ScreenData->ScreenHandle,
+ &Rect,
+ NULL,
+ Coord,
+ &CharInfo
+ );
+
+ //
+ // Mark all the lines in our buffer as containing garbage
+ //
+ LineInfo = ScreenData->LineInfo + Top;
+ R = Bottom - Top + 1;
+
+ while ( R-- ) {
+ LineInfo->Garbage = TRUE;
+ LineInfo++;
+ }
+
+ LeaveCriticalSection( &(ScreenData->CriticalSection) );
+ }
+
+ return Ok;
+}
+
+
+
+
+
+
+BOOL
+consoleSetAttribute (
+ PSCREEN pScreen,
+ ATTRIBUTE Attribute
+ )
+/*++
+
+Routine Description:
+
+ Sets the console attribute
+
+Arguments:
+
+ pScreen - Supplies pointer to screen data
+ Attribute - Supplies the attribute
+
+Return Value:
+
+ TRUE if Attribute set
+ FALSE otherwise
+
+--*/
+{
+
+ PSCREEN_DATA ScreenData = (PSCREEN_DATA)pScreen;
+
+ EnterCriticalSection( &(ScreenData->CriticalSection) );
+
+ if (Attribute != ScreenData->AttributeOld) {
+ ScreenData->AttributeOld = Attribute;
+ ScreenData->AttributeNew = GET_ATTRIBUTE(Attribute);
+ }
+
+ LeaveCriticalSection( &(ScreenData->CriticalSection) );
+
+ return TRUE;
+}
+
+
+
+
+
+
+
+
+
+BOOL
+consoleFlushInput (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Flushes input events.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if success, FALSE otherwise
+
+--*/
+{
+ EventBuffer.NumberOfEvents = 0;
+
+ return FlushConsoleInputBuffer( hInput );
+}
+
+
+
+
+
+
+
+BOOL
+consoleGetMode (
+ PKBDMODE pMode
+ )
+/*++
+
+Routine Description:
+
+ Get current console mode.
+
+Arguments:
+
+ pMode - Supplies a pointer to the mode flag variable
+
+Return Value:
+
+ TRUE if success, FALSE otherwise.
+
+--*/
+{
+ return GetConsoleMode( hInput,
+ pMode );
+}
+
+
+
+
+
+
+BOOL
+consoleSetMode (
+ KBDMODE Mode
+ )
+/*++
+
+Routine Description:
+
+ Sets the console mode.
+
+Arguments:
+
+ Mode - Supplies the mode flags.
+
+Return Value:
+
+ TRUE if success, FALSE otherwise
+
+--*/
+{
+ return SetConsoleMode( hInput,
+ Mode );
+}
+
+
+BOOL
+consoleIsKeyAvailable (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Returns TRUE if a key is available in the event buffer.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if a key is available in the event buffer
+ FALSE otherwise
+
+--*/
+
+{
+ BOOL IsKey = FALSE;
+ PINPUT_RECORD pEvent;
+ DWORD Index;
+
+ EnterCriticalSection( &(EventBuffer.CriticalSection) );
+
+ for ( Index = EventBuffer.EventIndex; Index < EventBuffer.NumberOfEvents; Index++ ) {
+
+ pEvent = EventBuffer.EventBuffer + EventBuffer.EventIndex;
+
+ if ( ((EVENT_TYPE(pEvent)) == KEY_EVENT) &&
+ (PKEY_EVT(pEvent))->bKeyDown ) {
+ IsKey = TRUE;
+ break;
+ }
+ }
+
+ LeaveCriticalSection( &(EventBuffer.CriticalSection) );
+
+ return IsKey;
+}
+
+
+
+
+BOOL
+consoleDoWindow (
+ void
+ )
+
+/*++
+
+Routine Description:
+
+ Responds to a window event
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if window changed
+ FALSE otherwise
+
+--*/
+
+{
+
+ PINPUT_RECORD pEvent;
+
+ pEvent = NextEvent( NOADVANCE, NOWAIT );
+
+ if (( EVENT_TYPE(pEvent) ) == WINDOW_BUFFER_SIZE_EVENT) {
+
+ pEvent = NextEvent( ADVANCE, WAIT );
+ WindowEvent(PWINDOW_EVT(pEvent));
+ }
+
+ return FALSE;
+
+}
+
+
+
+
+
+BOOL
+consolePeekKey (
+ PKBDKEY Key
+ )
+
+/*++
+
+Routine Description:
+
+ Gets the next key from the input buffer if the buffer is not empty.
+
+
+Arguments:
+
+ Key - Supplies a pointer to a key structure
+
+Return Value:
+
+ TRUE if keystroke read, FALSE otherwise.
+
+--*/
+
+{
+
+ PINPUT_RECORD pEvent;
+ BOOL Done = FALSE;
+ BOOL IsKey = FALSE;
+
+ EnterCriticalSection(&(EventBuffer.PeekCriticalSection));
+
+ do {
+
+ pEvent = NextEvent( NOADVANCE, NOWAIT );
+
+ if ( pEvent ) {
+
+ switch ( EVENT_TYPE(pEvent) ) {
+
+ case KEY_EVENT:
+ if (KeyEvent(PKEY_EVT(pEvent), Key)){
+ IsKey = TRUE;
+ Done = TRUE;
+ }
+ break;
+
+ case MOUSE_EVENT:
+ Done = TRUE;
+ break;
+
+
+ case WINDOW_BUFFER_SIZE_EVENT:
+ Done = TRUE;
+ break;
+
+ case MENU_EVENT:
+ case FOCUS_EVENT:
+ Done = TRUE;
+ break;
+
+ default:
+ assert( FALSE );
+ break;
+ }
+
+ if ( !Done ) {
+ NextEvent( ADVANCE, NOWAIT );
+ }
+
+ } else {
+ Done = TRUE;
+ }
+
+ } while ( !Done );
+
+ LeaveCriticalSection(&(EventBuffer.PeekCriticalSection));
+
+ return IsKey;
+
+}
+
+
+
+
+
+
+BOOL
+consoleGetKey (
+ PKBDKEY Key,
+ BOOL fWait
+ )
+/*++
+
+Routine Description:
+
+ Gets the next key from the input buffer.
+
+Arguments:
+
+ Key - Supplies a pointer to a key structure
+ fWait - Supplies a flag:
+ if TRUE, the function blocks until a key is ready.
+ if FALSE, the function returns immediately.
+
+Return Value:
+
+ TRUE if keystroke read, FALSE otherwise.
+
+--*/
+{
+
+ PINPUT_RECORD pEvent;
+
+ do {
+ pEvent = NextEvent( ADVANCE, fWait );
+
+ if (pEvent) {
+
+ switch ( EVENT_TYPE(pEvent) ) {
+
+ case KEY_EVENT:
+ if (KeyEvent(PKEY_EVT(pEvent), Key)) {
+ return TRUE;
+ }
+ break;
+
+ case MOUSE_EVENT:
+ MouseEvent(PMOUSE_EVT(pEvent));
+ break;
+
+ case WINDOW_BUFFER_SIZE_EVENT:
+ WindowEvent(PWINDOW_EVT(pEvent));
+ break;
+
+ case MENU_EVENT:
+ MenuEvent(PMENU_EVT(pEvent));
+ break;
+
+ case FOCUS_EVENT:
+ FocusEvent(PFOCUS_EVT(pEvent));
+ break;
+
+ default:
+ break;
+ }
+ }
+ } while (fWait);
+
+ return FALSE;
+}
+
+
+BOOL
+consolePutKey (
+ PKBDKEY Key
+ )
+/*++
+
+Routine Description:
+
+ Puts a key in the console's input buffer
+
+Arguments:
+
+ Key - Supplies a pointer to a key structure
+
+Return Value:
+
+ TRUE if key put, false otherwise
+
+--*/
+{
+
+ INPUT_RECORD InputRecord;
+
+ InputRecord.EventType = KEY_EVENT;
+
+ InputRecord.Event.KeyEvent.bKeyDown = FALSE;
+ InputRecord.Event.KeyEvent.wRepeatCount = 0;
+ InputRecord.Event.KeyEvent.wVirtualKeyCode = Key->Scancode;
+ InputRecord.Event.KeyEvent.wVirtualScanCode = 0;
+ InputRecord.Event.KeyEvent.uChar.UnicodeChar = Key->Unicode;
+ InputRecord.Event.KeyEvent.dwControlKeyState = Key->Flags;
+
+ if ( PutEvent( &InputRecord )) {
+ InputRecord.Event.KeyEvent.bKeyDown = TRUE;
+ return PutEvent( &InputRecord );
+ }
+ return FALSE;
+}
+
+
+BOOL
+consolePutMouse(
+ ROW Row,
+ COLUMN Col,
+ DWORD MouseFlags
+ )
+/*++
+
+Routine Description:
+
+ Puts a mose event in the console's input buffer
+
+Arguments:
+
+ Row - Supplies the row
+ Col - Supplies the column
+ MouseFlags - Supplies the flags
+
+Return Value:
+
+ TRUE if key put, false otherwise
+
+--*/
+{
+
+ INPUT_RECORD InputRecord;
+ COORD Position;
+ DWORD Flags;
+
+ InputRecord.EventType = MOUSE_EVENT;
+
+ Position.Y = (WORD)(Row - 1);
+ Position.X = (WORD)(Col - 1);
+
+ Flags = 0;
+
+ if ( MouseFlags & MOUSE_CLICK_LEFT ) {
+ Flags |= FROM_LEFT_1ST_BUTTON_PRESSED;
+ }
+ if ( MouseFlags & MOUSE_CLICK_RIGHT ) {
+ Flags |= RIGHTMOST_BUTTON_PRESSED;
+ }
+ if ( MouseFlags & MOUSE_DOUBLE_CLICK ) {
+ Flags |= DOUBLE_CLICK;
+ }
+
+ InputRecord.Event.MouseEvent.dwMousePosition = Position;
+ InputRecord.Event.MouseEvent.dwButtonState = Flags;
+ InputRecord.Event.MouseEvent.dwControlKeyState = 0;
+ InputRecord.Event.MouseEvent.dwEventFlags = 0;
+
+ return PutEvent( &InputRecord );
+}
+
+
+
+BOOL
+consoleIsBusyReadingKeyboard (
+ )
+/*++
+
+Routine Description:
+
+ Determines if the console is busy reading the keyboard
+
+Arguments:
+
+ None
+
+Return Value:
+
+ TRUE if console is busy reading the keyboard.
+
+--*/
+{
+ BOOL Busy;
+
+ EnterCriticalSection(&(EventBuffer.CriticalSection));
+ Busy = EventBuffer.BusyFlag;
+ LeaveCriticalSection(&(EventBuffer.CriticalSection));
+
+ return Busy;
+}
+
+
+
+BOOL
+consoleEnterCancelEvent (
+ )
+{
+
+ INPUT_RECORD Record;
+ DWORD dw;
+
+ Record.EventType = KEY_EVENT;
+ Record.Event.KeyEvent.bKeyDown = TRUE;
+ Record.Event.KeyEvent.wRepeatCount = 0;
+ Record.Event.KeyEvent.wVirtualKeyCode = VK_CANCEL;
+ Record.Event.KeyEvent.wVirtualScanCode = 0;
+ Record.Event.KeyEvent.uChar.AsciiChar = 0;
+ Record.Event.KeyEvent.dwControlKeyState = 0;
+
+ PutEvent( &Record );
+
+ Record.Event.KeyEvent.bKeyDown = TRUE;
+ WriteConsoleInput( hInput, &Record, 1, &dw );
+
+ return TRUE;
+}
+
+
+PINPUT_RECORD
+NextEvent (
+ BOOL fAdvance,
+ BOOL fWait
+ )
+/*++
+
+Routine Description:
+
+ Returns pointer to next event record.
+
+Arguments:
+
+ fAdvance - Supplies a flag:
+ if TRUE: Advance to next event record
+ if FALSE: Do not advance to next event record
+
+ fWait - Supplies a flag:
+ if TRUE, the blocks until an event is ready.
+ if FALSE, return immediately.
+
+Return Value:
+
+ Pointer to event record, or NULL.
+
+--*/
+{
+ PINPUT_RECORD pEvent;
+ BOOL Success;
+
+ EnterCriticalSection(&(EventBuffer.CriticalSection));
+
+ //
+ // If the busy flag is set, then the buffer is in the process of
+ // being read. Only one thread should want to wait, so it is
+ // safe to simply return.
+ //
+ if ( EventBuffer.BusyFlag ) {
+ assert( !fWait );
+ LeaveCriticalSection(&(EventBuffer.CriticalSection));
+ return NULL;
+ }
+
+ if (EventBuffer.NumberOfEvents == 0) {
+
+ //
+ // No events in buffer, read as many as we can
+ //
+ DWORD NumberOfEvents;
+
+ //
+ // If the buffer is too big, resize it
+ //
+ if ( EventBuffer.MaxEvents > MAX_EVENTS ) {
+
+ EventBuffer.EventBuffer = REALLOC( EventBuffer.EventBuffer,
+ MAX_EVENTS * sizeof( INPUT_RECORD ) );
+
+ EventBuffer.MaxEvents = MAX_EVENTS;
+ assert( EventBuffer.EventBuffer );
+ CleanExit( 1, 0 );
+ }
+
+ Success = PeekConsoleInput( hInput,
+ EventBuffer.EventBuffer,
+ EventBuffer.MaxEvents,
+ &NumberOfEvents);
+
+ if ((!Success || (NumberOfEvents == 0)) && (!fWait)) {
+ //
+ // No events available and don't want to wait,
+ // return.
+ //
+ LeaveCriticalSection(&(EventBuffer.CriticalSection));
+ return NULL;
+ }
+
+ //
+ // Since we will block, we have to leave the critical section.
+ // We set the Busy flag to indicate that the buffer is being
+ // read.
+ //
+ EventBuffer.BusyFlag = TRUE;
+ LeaveCriticalSection(&(EventBuffer.CriticalSection));
+
+ Success = ReadConsoleInput (hInput,
+ EventBuffer.EventBuffer,
+ EventBuffer.MaxEvents,
+ &EventBuffer.NumberOfEvents);
+
+ EnterCriticalSection(&(EventBuffer.CriticalSection));
+
+ EventBuffer.BusyFlag = FALSE;
+
+ if (!Success) {
+#if defined( DEBUG )
+ OutputDebugString(" Error: Cannot read console events\n");
+ assert( Success );
+#endif
+ EventBuffer.NumberOfEvents = 0;
+ }
+ EventBuffer.EventIndex = 0;
+ }
+
+ pEvent = EventBuffer.EventBuffer + EventBuffer.EventIndex;
+
+ //
+ // If Advance flag is set, we advance the pointer to the next
+ // record.
+ //
+ if (fAdvance) {
+ if (--(EventBuffer.NumberOfEvents)) {
+
+ switch (EVENT_TYPE(pEvent)) {
+
+ case KEY_EVENT:
+ case MOUSE_EVENT:
+ case WINDOW_BUFFER_SIZE_EVENT:
+ case MENU_EVENT:
+ case FOCUS_EVENT:
+ (EventBuffer.EventIndex)++;
+ break;
+
+ default:
+#if defined( DEBUG)
+ sprintf(DbgBuffer, "WARNING: unknown event type %X\n", EVENT_TYPE(pEvent));
+ OutputDebugString(DbgBuffer);
+#endif
+ (EventBuffer.EventIndex)++;
+ break;
+ }
+ }
+ }
+
+
+ LeaveCriticalSection(&(EventBuffer.CriticalSection));
+
+ return pEvent;
+}
+
+
+
+
+
+void
+MouseEvent (
+ PMOUSE_EVENT_RECORD pEvent
+ )
+/*++
+
+Routine Description:
+
+ Processes mouse events.
+
+Arguments:
+
+ pEvent - Supplies pointer to event record
+
+Return Value:
+
+ None..
+
+--*/
+{
+ static BOOL Pressed = FALSE;
+ DWORD MouseFlags;
+
+ //
+ // We only know left and right mouse buttons
+ //
+ pEvent->dwButtonState &= ( FROM_LEFT_1ST_BUTTON_PRESSED | RIGHTMOST_BUTTON_PRESSED );
+
+ //
+ // Let the editor handle the mouse event
+ //
+ MouseFlags = 0x00;
+ if ( pEvent->dwButtonState & FROM_LEFT_1ST_BUTTON_PRESSED ) {
+ MouseFlags |= MOUSE_CLICK_LEFT;
+ }
+ if ( pEvent->dwButtonState & RIGHTMOST_BUTTON_PRESSED ) {
+ MouseFlags |= MOUSE_CLICK_RIGHT;
+ }
+ if ( pEvent->dwEventFlags & DOUBLE_CLICK ) {
+ MouseFlags |= MOUSE_DOUBLE_CLICK;
+ }
+
+ DoMouse( pEvent->dwMousePosition.Y+1,
+ pEvent->dwMousePosition.X+1,
+ MouseFlags );
+
+ Pressed = (BOOL)pEvent->dwButtonState;
+}
+
+
+
+
+
+BOOL
+WindowEvent (
+ PWINDOW_BUFFER_SIZE_RECORD pEvent
+ )
+/*++
+
+Routine Description:
+
+ Processes window size change events.
+
+Arguments:
+
+ pEvent - Supplies pointer to event record
+
+Return Value:
+
+ None
+
+--*/
+{
+
+ ROW Rows;
+ COLUMN Cols;
+ ULONG NewBufferSize;
+ CONSOLE_SCREEN_BUFFER_INFO ScrInfo; // Screen buffer info.
+
+ UNREFERENCED_PARAMETER( pEvent );
+
+ GetConsoleScreenBufferInfo( ActiveScreenData->ScreenHandle,
+ &ScrInfo );
+
+ Rows = ScrInfo.dwSize.Y;
+ Cols = ScrInfo.dwSize.X;
+
+ if ( Rows > ActiveScreenData->ScreenInformation.NumberOfRows ||
+ Cols > ActiveScreenData->ScreenInformation.NumberOfCols ) {
+
+ //
+ // resize the screen buffer. Note that the contents of the screen
+ // buffer are not valid anymore. Someone else will have to update
+ // them.
+ //
+ NewBufferSize = Rows * Cols;
+
+ if (ActiveScreenData->MaxBufferSize < NewBufferSize ) {
+ ActiveScreenData->ScreenBuffer = REALLOC( ActiveScreenData->ScreenBuffer, NewBufferSize * sizeof(CHAR_INFO));
+ ActiveScreenData->MaxBufferSize = NewBufferSize;
+ ActiveScreenData->LineInfo = REALLOC( ActiveScreenData->LineInfo, Rows * sizeof( LINE_INFO ) );
+ }
+
+ //
+ // Set the size
+ //
+ ActiveScreenData->ScreenInformation.NumberOfRows = Rows;
+ ActiveScreenData->ScreenInformation.NumberOfCols = Cols;
+
+ ActiveScreenData->FirstRow = ActiveScreenData->ScreenInformation.NumberOfRows;
+ ActiveScreenData->LastRow = 0;
+
+ InitLineInfo( ActiveScreenData );
+
+ //
+ // Let the editor respond the the event
+ //
+ WindowChange( Rows, Cols );
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+BOOL
+MenuEvent (
+ PMENU_EVENT_RECORD pEvent
+ )
+/*++
+
+Routine Description:
+
+ Processes menu events
+
+Arguments:
+
+ pEvent - Supplies pointer to event record
+
+Return Value:
+
+ None
+
+--*/
+{
+ UNREFERENCED_PARAMETER( pEvent );
+ return TRUE;
+}
+
+BOOL
+FocusEvent (
+ PFOCUS_EVENT_RECORD pEvent
+ )
+/*++
+
+Routine Description:
+
+ Processes focus events
+
+Arguments:
+
+ pEvent - Supplies pointer to event record
+
+Return Value:
+
+ None
+
+--*/
+{
+ UNREFERENCED_PARAMETER( pEvent );
+ return TRUE;
+
+}
+
+
+BOOL
+KeyEvent (
+ PKEY_EVENT_RECORD pEvent,
+ PKBDKEY pKey
+ )
+/*++
+
+Routine Description:
+
+ Processes key events.
+
+Arguments:
+
+ pEvent - Supplies pointer to event record
+ pKey - Supplies pointer to key structure to fill out.
+
+Return Value:
+
+ TRUE if key structured filled out, FALSE otherwise.
+
+--*/
+{
+ // static BOOL AltPressed = FALSE;
+
+ if (pEvent->bKeyDown) {
+
+ WORD Scan = pEvent->wVirtualKeyCode;
+
+ //
+ // Pressing the ALT key generates an event, but we filter this
+ // out.
+ //
+ //if (Scan == VK_MENU) {
+ // return FALSE;
+ //}
+ if ( Scan == VK_MENU && pEvent->uChar.UnicodeChar == 0 ) {
+ return FALSE;
+ }
+
+ if (Scan != VK_NUMLOCK && // NumLock
+ Scan != VK_CAPITAL && // Caps Lock
+ Scan != VK_SHIFT && // Shift
+ Scan != VK_CONTROL ) { // Ctrl
+
+ pKey->Unicode = pEvent->uChar.UnicodeChar;
+ pKey->Scancode = pEvent->wVirtualKeyCode;
+ pKey->Flags = pEvent->dwControlKeyState;
+
+//#if defined (DEBUG)
+// sprintf(DbgBuffer, " KEY: Scan %d Unicode %x\n", pKey->Scancode, pKey->Unicode );
+// OutputDebugString(DbgBuffer);
+//#endif
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+
+ }
+
+ } else {
+
+ return FALSE;
+
+ }
+}
+
+
+BOOL
+PutEvent (
+ PINPUT_RECORD InputRecord
+ )
+{
+
+ EnterCriticalSection(&(EventBuffer.CriticalSection));
+
+ //
+ // If no space at beginning of buffer, resize and shift right
+ //
+ if ( EventBuffer.EventIndex == 0 ) {
+
+ EventBuffer.EventBuffer = REALLOC( EventBuffer.EventBuffer,
+ (EventBuffer.MaxEvents + EVENT_INCREMENT) * sizeof(INPUT_RECORD));
+
+ if ( !EventBuffer.EventBuffer ) {
+ CleanExit(1, 0);
+ }
+
+ memmove( EventBuffer.EventBuffer + EVENT_INCREMENT,
+ EventBuffer.EventBuffer ,
+ EventBuffer.NumberOfEvents * sizeof(INPUT_RECORD) );
+
+ EventBuffer.EventIndex = EVENT_INCREMENT;
+ }
+
+ //
+ // Add event
+ //
+ EventBuffer.EventIndex--;
+ EventBuffer.NumberOfEvents++;
+
+ memcpy( EventBuffer.EventBuffer + EventBuffer.EventIndex,
+ InputRecord,
+ sizeof(INPUT_RECORD ));
+
+ LeaveCriticalSection(&(EventBuffer.CriticalSection));
+
+ return TRUE;
+}
diff --git a/private/utils/mep/src/cursor.c b/private/utils/mep/src/cursor.c
new file mode 100644
index 000000000..08694daad
--- /dev/null
+++ b/private/utils/mep/src/cursor.c
@@ -0,0 +1,861 @@
+/*** cursor.c - cursor movement functions
+*
+* Modifications:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+
+#include "mep.h"
+#include "keyboard.h"
+#include "keys.h"
+
+void
+GetTextCursor (
+ COL *px,
+ LINE *py
+ ) {
+ *px = XCUR(pInsCur);
+ *py = YCUR(pInsCur);
+}
+
+
+/*** docursor/cursorfl - Move cursor to new location, adjust windows as needed
+*
+* Purpose:
+*
+* This moves the cursor to a new file position in the current file.
+* If this position is not visible, the current window is readjusted.
+* The rules for vertical adjustment are:
+*
+* If the new location is within 'vscroll' lines of the current
+* window, scroll by vscroll lines in the appropriate direction.
+*
+* If the new location is further away, adjust the window so that
+* the new location is 'hike' lines from the top.
+*
+* The rules for horizontal adjustment is:
+*
+* If the new location is within 'hscroll' lines of the current
+* window, scroll by hscroll lines in the appropriate direction
+*
+* If the new location is further away, adjust the window so that
+* the new location is 'hscroll' lines from the edge that's in
+* the direction we moved.
+*
+* cursorfl is the same as docursor, but takes an fl instead.
+*
+* if realtabs is on, cursor is snapped to right hand column of underlying
+* tab characters.
+*
+* Input:
+* x - new file column (docursor only)
+* y - new file line (docursor only)
+* fl - new file position (cursorfl only)
+*
+* Globals:
+* pWinCur - Window and
+* pInsCur - file to operate in.
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void
+docursor (
+ COL x,
+ LINE y
+ ) {
+
+ fl fl;
+
+ fl.col = x;
+ fl.lin = y;
+ cursorfl(fl);
+}
+
+
+void
+cursorfl (
+ fl flParam
+ ) {
+ fl flNew; /* New cursor position, window relative */
+ fl flWin; /* Window position after adjustments */
+ sl slScroll; /* h & vscroll, scaled to window size */
+ linebuf buf;
+
+ flParam.col = max( 0, flParam.col );
+ flParam.lin = lmax( (LINE)0, flParam.lin );
+
+ /*
+ * if real tabs are on, snap to right of any tab we might be over
+ */
+ if (fRealTabs && fTabAlign) {
+ GetLine (flParam.lin, buf, pFileHead);
+ if (flParam.col < cbLog(buf)) {
+ flParam.col = AlignChar (flParam.col, buf);
+ }
+ }
+
+ slScroll.col = XSCALE (hscroll);
+ slScroll.lin = YSCALE (vscroll);
+
+ flWin = pInsCur->flWindow;
+
+ /* Check for horizontal window adjustments */
+
+ flNew.col = flParam.col - flWin.col;
+ if (flNew.col < 0) { /* We went off the left edge */
+ flWin.col -= slScroll.col;
+ if (flNew.col < -slScroll.col) { /* One hscroll wont do it */
+ flWin.col += flNew.col + 1;
+ }
+ } else if (flNew.col >= WINXSIZE(pWinCur)) { /* off the right edge */
+ flWin.col += slScroll.col;
+ if (flNew.col >= WINXSIZE(pWinCur) + slScroll.col) { /* ...more than hscroll */
+ flWin.col += flNew.col - WINXSIZE(pWinCur);
+ }
+ }
+
+ /* Check for vertical window adjustments */
+
+ flNew.lin = flParam.lin - flWin.lin; /* Too far off, use hike */
+
+ if (flNew.lin < -slScroll.lin || flNew.lin >= WINYSIZE(pWinCur) + slScroll.lin) {
+
+ flWin.lin = flParam.lin - YSCALE(hike);
+ } else if (flNew.lin < 0) { /* Off the top */
+ flWin.lin -= slScroll.lin;
+ } else if (flNew.lin >= WINYSIZE(pWinCur)) { /* Off the bottom */
+ flWin.lin += slScroll.lin;
+ }
+
+ flWin.col = max (0, flWin.col); /* Can't move window beyond 0 */
+ flWin.lin = lmax ((LINE)0, flWin.lin);
+
+ doscreen (flWin.col, flWin.lin, flParam.col, flParam.lin);
+}
+
+/*** doscreen - update screen window and cursor locations
+*
+* Purpose:
+* Performs reasonable bounds checking on the input parameters, and sets the
+* window position and cursor location to values which are legal
+* approximiations for out of range values.
+*
+* Input:
+* wx,wy = Proposed new window position (top left corner of screen)
+* cx,cy = Proposed new cursor position
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void
+doscreen(
+ REGISTER COL wx,
+ REGISTER LINE wy,
+ COL cx,
+ LINE cy
+ ) {
+
+ COL dx;
+ LINE dy, yOld;
+ LINE First, Last;
+
+ /*
+ * limit window x position to somewhere near our max line length
+ * limit window y position to last line of the file (only if we know the
+ * length)
+ */
+ wx = max( 0, min( wx, (COL)sizeof(linebuf)-(WINXSIZE(pWinCur) - XSCALE (hscroll))));
+ wy = lmax( (LINE)0, TESTFLAG (pFileHead->flags, REAL) ? lmin( wy, pFileHead->cLines - 1 ) : wy );
+
+ /*
+ * dx,dy is window movement delta, if a change, save it.
+ */
+ dx = wx - XWIN(pInsCur);
+ dy = wy - YWIN(pInsCur);
+
+ if ( dx || dy ) {
+ saveflip ();
+
+
+ if ( dy > 0 ) {
+
+ First = YWIN(pInsCur) + WINYSIZE(pWinCur);
+ Last = YWIN(pInsCur) + WINYSIZE(pWinCur) + dy;
+
+ } else {
+
+ First = YWIN(pInsCur) + dy;
+ Last = YWIN(pInsCur);
+ }
+ }
+
+ XCUR(pInsCur) = min (max( wx, min( cx, wx+WINXSIZE(pWinCur)-1 ) ), sizeof(linebuf)-2);
+ yOld = YCUR(pInsCur);
+ YCUR(pInsCur) = lmax( wy, lmin( cy, wy+WINYSIZE(pWinCur)-1 ) );
+ AckMove (yOld, YCUR(pInsCur));
+ XWIN(pInsCur) = wx;
+ YWIN(pInsCur) = wy;
+
+ if ( dx || dy ) {
+ SETFLAG (fDisplay, RSTATUS);
+
+ // If we're not in a macro and it makes sense to scroll quickly
+ // do it
+
+ if ( !mtest () && dy && !fInSelection &&
+ (Last < pFileHead->cLines-1) && (abs(dy) < WINYSIZE(pWinCur)) ) {
+
+
+ consoleSetAttribute( MepScreen, fgColor );
+ consoleScrollVert( MepScreen, WINYPOS(pWinCur), WINXPOS(pWinCur),
+ WINYPOS(pWinCur)+WINYSIZE(pWinCur)-1,
+ WINXPOS(pWinCur)+WINXSIZE(pWinCur)-1, dy );
+
+ // We've scrolled the window. However, the update state in
+ // fChange[] is out of date. We need to scroll it in parallel
+ // However, since the fChange array is for the SCREEN and not
+ // for the window, we can't simply SCROLL it. Perhaps, one day,
+ // we can make it per-window but for now, we just force
+ // a synchronous update which can be ugly in a macro.
+
+ redraw( pFileHead, First, Last);
+ DoDisplay ();
+
+ } else {
+ newwindow ();
+ }
+ }
+ SETFLAG (fDisplay, RCURSOR);
+}
+
+
+/*** dobol - returns column position of first non-blank character
+*
+* Input:
+* none
+*
+* Global:
+* pInsCur - Current instance
+* pFileHead - Current file
+*
+* Output:
+* Returns column of first non-blank character
+*
+*************************************************************************/
+int
+dobol (
+ void
+ ) {
+
+ REGISTER char *p = buf;
+
+ GetLine (YCUR(pInsCur), p, pFileHead);
+ return colPhys (p, (whiteskip (p)));
+}
+
+int
+doeol (
+ void
+ ) {
+ return LineLength (YCUR(pInsCur), pFileHead);
+}
+
+
+/*** doftab - tab function
+*
+* Moves the cursor ahead one tab stop. If realtabs and tab align are on,
+* moves to first tab stop off of the current character.
+*
+* Input:
+* col = current column
+*
+* Output:
+* Returns new column
+*
+*************************************************************************/
+int
+doftab (
+ int col
+ ) {
+ REGISTER int newcol;
+
+ if (tabstops) {
+ newcol = col + tabstops - (col%tabstops);
+
+ if (fRealTabs && fTabAlign) {
+ linebuf buf;
+
+ GetLine (YCUR(pInsCur), buf, pFileHead);
+ while (col >= AlignChar(newcol,buf))
+ newcol += tabstops;
+ }
+ return newcol;
+ } else {
+ return col;
+ }
+}
+
+
+int
+dobtab (
+ REGISTER int col
+ ) {
+ return col - (tabstops ? (1 + (col-1)%tabstops) : 0);
+}
+
+
+flagType
+left (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ ) {
+
+ int x = XCUR(pInsCur);
+
+ docursor(fMeta ? XWIN(pInsCur) : XCUR(pInsCur)-1, YCUR(pInsCur));
+ return (flagType)(x != XCUR(pInsCur));
+
+ argData; pArg;
+}
+
+
+
+flagType
+right (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ ) {
+
+ linebuf buf;
+
+ if (fMeta) {
+ docursor (XWIN(pInsCur)+WINXSIZE(pWinCur)-1, YCUR(pInsCur));
+ } else if (fRealTabs && fTabAlign) {
+ GetLine (YCUR(pInsCur), buf, pFileHead);
+ docursor(colPhys(buf, pLog(buf,XCUR(pInsCur),FALSE)+1), YCUR(pInsCur));
+ } else {
+ docursor (XCUR(pInsCur)+1, YCUR(pInsCur));
+ }
+ return (flagType)(XCUR(pInsCur) < LineLength (YCUR(pInsCur), pFileHead));
+
+ argData; pArg;
+}
+
+
+
+flagType
+up (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ ) {
+
+
+ LINE y = YCUR(pInsCur);
+ LINE LinesUp = 1;
+ KBDKEY Key;
+ EDITOR_KEY KeyInfo;
+
+ //
+ // Check if there are more up keys and add them up.
+ // Do this only if NOT in a macro
+ //
+
+ if (!mtest ())
+ while (TRUE) {
+
+ if (!consolePeekKey( &Key ))
+ break;
+
+ KeyInfo = TranslateKey( Key );
+
+ if ( KeyInfo.KeyCode == 0x110)
+ LinesUp++;
+ else
+ if (KeyInfo.KeyCode == 0x111 && LinesUp > 0)
+ LinesUp--;
+ else
+ break;
+
+ consoleGetKey( &Key, FALSE );
+ }
+
+ while ( LinesUp-- )
+ docursor (XCUR(pInsCur), fMeta ? YWIN(pInsCur) : YCUR(pInsCur)-1 );
+
+ return (flagType)(y != YCUR(pInsCur));
+
+ argData; pArg;
+}
+
+
+
+flagType
+down (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ ) {
+
+ LINE y = YCUR(pInsCur);
+ LINE LinesDown = 1;
+ KBDKEY Key;
+ EDITOR_KEY KeyInfo;
+
+ //
+ // Check if there are more up keys and add them up.
+ // Do this only if NOT in a macro
+ //
+ if (!mtest ())
+ while (TRUE) {
+
+ if (!consolePeekKey( &Key ))
+ break;
+
+ KeyInfo = TranslateKey( Key );
+
+ if ( KeyInfo.KeyCode == 0x111)
+ LinesDown++;
+ else
+ if (KeyInfo.KeyCode == 0x110 && LinesDown > 0)
+ LinesDown--;
+ else
+ break;
+
+ consoleGetKey( &Key, FALSE );
+ }
+
+ while ( LinesDown--)
+ docursor (XCUR(pInsCur), fMeta ? YWIN(pInsCur)+WINYSIZE(pWinCur)-1 : YCUR(pInsCur)+1);
+
+ return (flagType)(y != YCUR(pInsCur));
+
+ argData; pArg;
+}
+
+
+
+flagType
+begline (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ ) {
+ int x = XCUR(pInsCur);
+
+ docursor (fMeta ? 0 : dobol(), YCUR(pInsCur));
+ return (flagType)(x != XCUR(pInsCur));
+
+ argData; pArg;
+}
+
+
+
+flagType
+endline (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ ) {
+ int x = XCUR(pInsCur);
+
+ docursor (fMeta ? WINXSIZE(pWinCur) : doeol(), YCUR(pInsCur));
+ return (flagType)(x != XCUR(pInsCur));
+
+ argData; pArg;
+}
+
+
+
+flagType
+home (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ ) {
+ fl flBefore;
+
+ flBefore = pInsCur->flCursorCur;
+
+ if (fMeta) {
+ docursor (XWIN(pInsCur)+WINXSIZE(pWinCur)-1,
+ YWIN(pInsCur)+WINYSIZE(pWinCur)-1 );
+ } else {
+ cursorfl (pInsCur->flWindow);
+ }
+ return (flagType)((flBefore.col != XCUR(pInsCur)) || (flBefore.lin != YCUR(pInsCur)));
+ argData; pArg; fMeta;
+}
+
+
+
+flagType
+tab (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ ) {
+ int x = XCUR(pInsCur);
+
+ docursor( doftab( XCUR(pInsCur)), YCUR(pInsCur));
+ return (flagType)(x != XCUR(pInsCur));
+
+ argData; pArg; fMeta;
+}
+
+
+
+flagType
+backtab (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ ) {
+ int x = XCUR(pInsCur);
+
+ docursor (dobtab (XCUR(pInsCur)), YCUR(pInsCur));
+ return (flagType)(x != XCUR(pInsCur));
+
+ argData; pArg; fMeta;
+}
+
+
+
+flagType
+fIsBlank (
+ PFILE pFile,
+ LINE line
+ ) {
+ linebuf buf;
+
+ return (flagType)(gettextline (TRUE, line, buf, pFile, ' ') == 0
+ || (*whiteskip (buf) == 0));
+}
+
+
+
+/* ppara - move cursor forward by paragraphs
+ *
+ * <ppara> moves forward to the beginning of the next paragraph. This
+ * is defined as moving to line i where line i-1 is blank, line i
+ * is non-blank and line i is after the one the cursor is on. If we are
+ * beyond end-of-file, the cursor is not moved.
+ *
+ * <meta><ppara> moves forward to the first blank line beyond the current/
+ * next paragraph. This is defined as moving to line i where line i-1 is
+ * non-blank, line i is blank and line i is after the one the cursor is on.
+ * If we are beyond end-of-file, the cursor is not moved.
+ */
+flagType
+ppara (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ ) {
+ LINE y;
+ LINE y1 = YCUR(pInsCur);
+
+ if (YCUR(pInsCur) >= pFileHead->cLines) {
+ return FALSE;
+ }
+
+ if (!fMeta) {
+ for (y = YCUR(pInsCur) + 1; y < pFileHead->cLines; y++) {
+ if (fIsBlank (pFileHead, y-1) && !fIsBlank (pFileHead, y)) {
+ break;
+ }
+ }
+ } else {
+ for (y = YCUR(pInsCur) + 1; y < pFileHead->cLines; y++) {
+ if (!fIsBlank (pFileHead, y-1) && fIsBlank (pFileHead, y)) {
+ break;
+ }
+ }
+ }
+
+ docursor (0, y);
+ return (flagType)(y1 != YCUR(pInsCur));
+
+ argData; pArg;
+}
+
+
+
+
+/* mpara - move cursor backward by paragraphs
+ *
+ * <mpara> moves backward to the beginning of the previous paragraph. This
+ * is defined as moving to line i where line i-1 is blank, line i
+ * is non-blank and line i is before the one the cursor is on. If we are
+ * at the beginning of the file, the cursor is not moved.
+ *
+ * <meta><mpara> moves backward to the first blank line before the current/
+ * next paragraph. This is defined as moving to line i where line i-1 is
+ * non-blank, line i is blank and line i is before the one the cursor is on.
+ * If we are at the beginning of the file, the cursor is not moved.
+ */
+flagType
+mpara (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ ) {
+ LINE y;
+ LINE y1 = YCUR(pInsCur);
+
+ if (YCUR(pInsCur) == 0) {
+ return FALSE;
+ }
+
+ if (!fMeta) {
+ for (y = YCUR(pInsCur) - 1; y > 0; y--) {
+ if (fIsBlank (pFileHead, y-1) && !fIsBlank (pFileHead, y)) {
+ break;
+ }
+ }
+ } else {
+ for (y = YCUR(pInsCur) - 1; y > 0; y--) {
+ if (!fIsBlank (pFileHead, y-1) && fIsBlank (pFileHead, y)) {
+ break;
+ }
+ }
+ }
+
+ docursor (0, y);
+ return (flagType)(y1 != YCUR(pInsCur));
+
+ argData; pArg;
+}
+
+
+
+/*** ppage - moves the cursor down by pages
+*
+* Purpose: <ppage> moves the cursor one page forward. The size of the
+* page is actually the vertical size of the current window.
+*
+* Input: none
+*
+* Output:
+* Returns True if possible movement, False if cursor already at end
+* of file.
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+
+flagType
+ppage (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ ) {
+
+ LINE y = YCUR(pInsCur);
+ LINE PagesDown = 1;
+ KBDKEY Key;
+ EDITOR_KEY KeyInfo;
+
+ //
+ // Check if there are more keys and add them up.
+ // Do this only if NOT in a macro
+ //
+
+ if (!mtest ())
+ while (TRUE) {
+
+ if (!consolePeekKey( &Key ))
+ break;
+
+ KeyInfo = TranslateKey( Key );
+
+ if ( KeyInfo.KeyCode == 0x113)
+ PagesDown++;
+ else
+ if (KeyInfo.KeyCode == 0x112 && PagesDown > 0)
+ PagesDown--;
+ else
+ break;
+
+ consoleGetKey( &Key, FALSE );
+ }
+
+
+ if (PagesDown > 0)
+ doscreen (XWIN(pInsCur), YWIN(pInsCur)+(PagesDown * WINYSIZE(pWinCur)),
+ XCUR(pInsCur), YCUR(pInsCur)+(PagesDown * WINYSIZE(pWinCur)) );
+
+ return (flagType)(y != YCUR(pInsCur));
+
+ argData; pArg; fMeta;
+}
+
+
+
+/*** mppage - moves the cursor up page by page
+*
+* Purpose: <mpage> moves the cursor one page backwards. The size of the
+* page is actually the vertical size of the current window.
+*
+* Input: none
+*
+* Output:
+* Returns True if possible movement, False if cursor already at top
+* of file.
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+flagType
+mpage (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ ) {
+
+ LINE y = YCUR(pInsCur);
+ LINE PagesUp = 1;
+ KBDKEY Key;
+ EDITOR_KEY KeyInfo;
+
+ //
+ // Check if there are more keys and add them up.
+ // Do this only if NOT in a macro
+ //
+ if (!mtest ())
+ while (TRUE) {
+
+ if (!consolePeekKey( &Key ))
+ break;
+
+ KeyInfo = TranslateKey( Key );
+
+ if ( KeyInfo.KeyCode == 0x112)
+ PagesUp++;
+ else
+ if (KeyInfo.KeyCode == 0x113 && PagesUp > 0)
+ PagesUp--;
+ else
+ break;
+
+ consoleGetKey( &Key, FALSE );
+ }
+
+
+ if (PagesUp > 0)
+ doscreen (XWIN(pInsCur), YWIN(pInsCur)-(PagesUp * WINYSIZE(pWinCur)),
+ XCUR(pInsCur), YCUR(pInsCur)-(PagesUp * WINYSIZE(pWinCur)));
+
+ return (flagType)(y != YCUR(pInsCur));
+
+ argData; pArg; fMeta;
+}
+
+
+
+/*** endfile - Sets the cursor at end of file
+*
+* Purpose:
+*
+* Input: none
+*
+* Output:
+* Returns True if possible movement, False if cursor already at end
+* of file.
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+flagType
+endfile (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ ) {
+ fl flBefore;
+
+ flBefore = pInsCur->flCursorCur;
+ doscreen (0, pFileHead->cLines - YSCALE (hike), 0, pFileHead->cLines );
+ return (flagType)((flBefore.col != XCUR(pInsCur)) || (flBefore.lin != YCUR(pInsCur)));
+
+ argData; pArg; fMeta;
+}
+
+
+
+/*** begfile - Sets the cursor at top of file
+*
+* Purpose:
+*
+* Input: none
+*
+* Output:
+* Returns True if possible movement, False if cursor already at top
+* of file.
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+flagType
+begfile (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ ) {
+ fl flBefore;
+
+ flBefore = pInsCur->flCursorCur;
+ doscreen( 0, (LINE)0, 0, (LINE)0 );
+ return (flagType)((flBefore.col != XCUR(pInsCur)) || (flBefore.lin != YCUR(pInsCur)));
+
+ argData; pArg; fMeta;
+}
+
+
+flagType
+savecur (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ ) {
+ pInsCur->flSaveWin = pInsCur->flWindow;
+ pInsCur->flSaveCur = pInsCur->flCursorCur;
+ return pInsCur->fSaved = TRUE;
+
+ argData; pArg; fMeta;
+}
+
+
+
+flagType
+restcur (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ ) {
+ if (pInsCur->fSaved) {
+ pInsCur->flWindow = pInsCur->flSaveWin;
+ pInsCur->flCursorCur = pInsCur->flSaveCur;
+ pInsCur->fSaved = FALSE;
+ SETFLAG (fDisplay, RSTATUS | RCURSOR);
+ newwindow ();
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+
+ argData; pArg; fMeta;
+}
diff --git a/private/utils/mep/src/delete.c b/private/utils/mep/src/delete.c
new file mode 100644
index 000000000..9af24e082
--- /dev/null
+++ b/private/utils/mep/src/delete.c
@@ -0,0 +1,126 @@
+/* sdelete.c - stream delete of characters
+ *
+ * Modifications:
+ * 26-Nov-1991 mz Strip off near/far
+ */
+
+#include "mep.h"
+
+
+flagType
+delete (
+ CMDDATA argType,
+ ARG * pArg,
+ flagType fMeta
+ ) {
+ switch (pArg->argType) {
+ case BOXARG:
+ case LINEARG:
+ ldelete (argType, pArg, fMeta);
+ break;
+
+ default:
+ sdelete (argType, pArg, fMeta);
+ break;
+ }
+ return TRUE;
+}
+
+
+
+flagType
+sdelete (
+ CMDDATA argType,
+ ARG * pArg,
+ flagType fMeta
+ ) {
+
+ fl fl;
+
+ switch (pArg->argType) {
+
+ case NOARG:
+ /* reduce line by one character. No length overflow is possible */
+ DelBox (pFileHead, XCUR (pInsCur), YCUR (pInsCur), XCUR (pInsCur), YCUR (pInsCur));
+ return TRUE;
+
+ /* TEXTARG illegal */
+ case NULLARG:
+ if (!fMeta) {
+ pick (pArg->arg.nullarg.x, pArg->arg.nullarg.y,
+ 0, pArg->arg.nullarg.y+1, STREAMARG);
+ }
+ DelStream (pFileHead, pArg->arg.nullarg.x, pArg->arg.nullarg.y,
+ 0, pArg->arg.nullarg.y+1);
+ return TRUE;
+
+ case LINEARG:
+ case BOXARG:
+ BoxToStream (pArg);
+
+ case STREAMARG:
+ if (!fMeta) {
+ pick (pArg->arg.streamarg.xStart, pArg->arg.streamarg.yStart,
+ pArg->arg.streamarg.xEnd, pArg->arg.streamarg.yEnd, STREAMARG);
+ }
+ DelStream (pFileHead,
+ pArg->arg.streamarg.xStart, pArg->arg.streamarg.yStart,
+ pArg->arg.streamarg.xEnd, pArg->arg.streamarg.yEnd);
+ fl.col = pArg->arg.streamarg.xStart;
+ fl.lin = pArg->arg.streamarg.yStart;
+ cursorfl (fl);
+ return TRUE;
+ }
+
+ argType;
+}
+
+
+
+/*** BoxToStream - Convert a box/line arg to a stream arg
+*
+* Purpose:
+*
+* Input:
+*
+* Output:
+*
+* Returns
+*
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+void
+BoxToStream (
+ ARG * pArg
+ ) {
+
+ ARG arg;
+
+ arg = *pArg;
+
+ pArg->argType = STREAMARG;
+
+ if (arg.argType == LINEARG) {
+ pArg->arg.streamarg.yStart = arg.arg.linearg.yStart;
+ pArg->arg.streamarg.yEnd = arg.arg.linearg.yEnd;
+ pArg->arg.streamarg.xStart = pArg->arg.streamarg.xEnd = flArg.col;
+ } else {
+ pArg->arg.streamarg.yStart = arg.arg.boxarg.yTop;
+ pArg->arg.streamarg.yEnd = arg.arg.boxarg.yBottom;
+
+ if ((flArg.lin == arg.arg.boxarg.yTop &&
+ flArg.col == arg.arg.boxarg.xLeft) ||
+ (flArg.lin == arg.arg.boxarg.yBottom &&
+ flArg.col == arg.arg.boxarg.xRight + 1)) {
+ pArg->arg.streamarg.xStart = arg.arg.boxarg.xLeft;
+ pArg->arg.streamarg.xEnd = arg.arg.boxarg.xRight + 1;
+ } else {
+ pArg->arg.streamarg.xStart = arg.arg.boxarg.xRight + 1;
+ pArg->arg.streamarg.xEnd = arg.arg.boxarg.xLeft;
+ }
+ }
+}
diff --git a/private/utils/mep/src/display.c b/private/utils/mep/src/display.c
new file mode 100644
index 000000000..c6f26adaa
--- /dev/null
+++ b/private/utils/mep/src/display.c
@@ -0,0 +1,1055 @@
+/*** display.c - display the current file
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+#define INCL_SUB
+#define INCL_MESSAGES
+
+#include "mep.h"
+#include <stdarg.h>
+#include "keyboard.h"
+
+#define DEBFLAG DISP
+
+
+
+/*** Display & DoDisplay - update the physical display
+*
+* We examine all the hints left around for us by the editing and attempt to
+* make a minimal set of changes to the screen. We will do this until one of
+* the following conditions exist:
+*
+* - the screen is completely updated
+* - there is a keystroke waiting for us
+*
+* When one occurs, we return.
+*
+* The hints that are left around are as follows:
+*
+* fDisplay is a bit field indicating what part of the general display needs
+* to be updated. The fields (and the corresponding areas) are:
+*
+* RTEXT the window on the file(s)
+* RSTATUS the status line on the bottom of the screen
+* RCURSOR the cursor
+* RHIGH the region [xhlStart,yhlStart] [xhlEnd,yhlEnd] is to be
+* highlighted on the screen.
+*
+* fChange[i] is a bit field for each line of the display indicating how the
+* line might have changed. The fields are:
+*
+* FMODIFY the line has changed somewhat; ideally, we merely compare
+* each character in the new line (retrieved with GetLine)
+* with the one kept in the screen shadow array.
+*
+* Display checks first to see if we are in a macro, and returns if we are.
+* DoDisplay does not check.
+*
+* Input:
+* none, other than various globals mentioned above.
+*
+* Output:
+* screen updated or key hit (or macro in progress for Display).
+*
+*************************************************************************/
+
+void
+Display (
+ void
+ ) {
+ if (!mtest ()) {
+ DoDisplay ();
+ }
+}
+
+
+
+void
+DoDisplay (
+ void
+ ) {
+
+ int Row, Col;
+
+ if (pFileHead == NULL) {
+ return;
+ }
+
+ if (TESTFLAG (fDisplay, RCURSOR)) {
+
+ Row = YCUR(pInsCur) - YWIN(pInsCur) + WINYPOS(pWinCur);
+ Col = XCUR(pInsCur) - XWIN(pInsCur) + WINXPOS(pWinCur);
+
+ if ( Row >= YSIZE || Col >= XSIZE ) {
+ docursor( XCUR(pInsCur), YCUR(pInsCur) );
+ }
+ }
+
+ /*
+ * If text needs updating, do so. Return immediately if a keystroke was
+ * pressed.
+ */
+ if (TESTFLAG (fDisplay, RTEXT) && !DoText (0, YSIZE)) {
+ return;
+ }
+
+ if ((fDisplayCursorLoc && TESTFLAG (fDisplay, RCURSOR)) ||
+ TESTFLAG (fDisplay, RSTATUS)) {
+ DoStatus ();
+ }
+
+ if (TESTFLAG (fDisplay, RCURSOR)) {
+
+ Row = YCUR(pInsCur) - YWIN(pInsCur) + WINYPOS(pWinCur);
+ Col = XCUR(pInsCur) - XWIN(pInsCur) + WINXPOS(pWinCur);
+
+ consoleMoveTo( Row, Col );
+ RSETFLAG (fDisplay, RCURSOR);
+ }
+}
+
+
+/*** DoText - Update window text
+*
+* Purpose:
+* Update given window until entirely accurate or until there are *
+* are keystrokes waiting to be entered. Use the hints in fDisplay *
+* and fChange to guide the update. *
+*
+* Input:
+* yLow 0-based beginning line number of display update
+* yHigh 0-based ending line number of display update
+*
+* Output:
+* Returns TRUE if successfully updated screen *
+* FALSE if keystrokes are awaiting *
+*
+*************************************************************************/
+
+flagType
+DoText (
+ int yLow,
+ int yHigh
+ ) {
+
+ REGISTER int yCur;
+ int yMin = -1;
+ int yMax = 0;
+
+ flagType fReturn = TRUE;
+
+ struct lineAttr *plaFile = NULL;
+ struct lineAttr *plaScr = NULL;
+ struct lineAttr *plaFileLine;
+ struct lineAttr *plaScrLine;
+
+ char *pchFileLine = NULL;
+ char pchScrLine[ 2 * sizeof(linebuf) * (1 + sizeof(struct lineAttr))];
+ int cchScrLine;
+
+ // int chkpnt = yHigh - yLow > 25 ? 20 : 5;
+ int chkpnt = yHigh - yLow > 25 ? 10 : 3;
+
+
+ fReDraw = FALSE;
+
+ plaScr = (struct lineAttr *) (pchScrLine + sizeof(linebuf));
+ if (cWin > 1) {
+ pchFileLine = pchScrLine + sizeof(linebuf) * (1 + sizeof(struct lineAttr));
+ plaFile = (struct lineAttr *) (pchFileLine + sizeof(linebuf));
+ }
+
+ /*
+ * For each line in the window, if the line is marked changed, update it.
+ */
+ for (yCur = yLow; yCur < yHigh; ) {
+
+ if (TESTFLAG(fChange[yCur], FMODIFY)) {
+ if (yMin == -1) {
+ yMin = yCur;
+ }
+ yMax = yCur;
+
+ /*
+ * get and display the line
+ */
+ plaScrLine = plaScr;
+ plaFileLine = plaFile;
+ cchScrLine = DisplayLine (yCur, pchScrLine, &plaScrLine, pchFileLine, &plaFileLine);
+ coutb (0, yCur, pchScrLine, cchScrLine, plaScrLine);
+
+ RSETFLAG(fChange[yCur],FMODIFY);
+ /*
+ * if it is time to check, and there is a character waiting, stop
+ * the update process, and go process it
+ */
+ if ( (yCur % chkpnt == 0) && TypeAhead() ) {
+ fReturn = FALSE;
+ break;
+ }
+ }
+ yCur++;
+ }
+
+ if (fReturn) {
+ RSETFLAG (fDisplay, RTEXT);
+ }
+ //
+ // Update the screen
+ //
+ fReDraw = TRUE;
+ vout(0,0,NULL,0,0);
+ return fReturn;
+}
+
+
+
+/*** DoStatus - Update the status line
+*
+* Purpose:
+* Creates and displays the status line on the bottom of the screen.
+*
+* Input:
+* None, other than the various globals that go into the status line.
+*
+* Output:
+* Returns status line output
+*
+*************************************************************************/
+
+#define CINDEX(clr) (unsigned char) ((&clr-&ColorTab[0])+isaUserMin)
+
+void
+DoStatus (
+ void
+ ) {
+ struct lineAttr rglaStatus[10]; /* color array for status line */
+ int cch;
+ int ilaStatus = 0; /* index into color array */
+ int i;
+ char *pchEndBuf; /* save for end of buffer */
+ char buf[512];
+
+
+ /*
+ * Start with filename, and file type
+ */
+ strcpy (buf, pFileHead->pName);
+ strcat (buf, " (");
+ strcpy ((char *)strend(buf), GetFileTypeName ());
+
+ /*
+ * Add other file characterisctics
+ */
+ if (!TESTFLAG (FLAGS (pFileHead), DOSFILE)) {
+ strcat (buf," NL");
+ }
+
+ if (TESTFLAG (FLAGS (pFileHead), TEMP)) {
+ strcat (buf, " temp");
+ }
+
+ if ((TESTFLAG (FLAGS (pFileHead), READONLY)) | fGlobalRO) {
+ strcat (buf, " No-Edit");
+ }
+
+ if (TESTFLAG (FLAGS (pFileHead), DISKRO)) {
+ strcat (buf, " RO-File");
+ }
+
+ rglaStatus[ilaStatus].attr = CINDEX(staColor);
+ rglaStatus[ilaStatus++].len = (unsigned char) strlen (buf);
+
+ if (TESTFLAG (FLAGS(pFileHead), DIRTY)) {
+ strcat (buf, " modified");
+ rglaStatus[ilaStatus].attr = CINDEX(errColor);
+ rglaStatus[ilaStatus++].len = 9;
+ }
+
+ pchEndBuf = strend (buf);
+ sprintf (strend(buf), ") Length=%ld ", pFileHead->cLines);
+
+ /*
+ * Add current location
+ */
+ if (fDisplayCursorLoc) {
+ sprintf (strend(buf), "Cursor=(%ld,%d)", YCUR(pInsCur)+1, XCUR(pInsCur)+1);
+ } else {
+ sprintf (strend(buf), "Window=(%ld,%d)", YWIN(pInsCur)+1, XWIN(pInsCur)+1);
+ }
+ rglaStatus[ilaStatus].attr = CINDEX(staColor);
+ rglaStatus[ilaStatus++].len = (unsigned char) (strend(buf) - pchEndBuf);
+
+ /*
+ * Add global state indicators
+ */
+ if (fInsert | fMeta | fCtrlc | fMacroRecord) {
+ rglaStatus[ilaStatus].attr = CINDEX(infColor);
+ rglaStatus[ilaStatus].len = 0;
+ if (fInsert) {
+ strcat (buf, " insert");
+ rglaStatus[ilaStatus].len += 7;
+ }
+ if (fMeta) {
+ strcat (buf, " meta");
+ rglaStatus[ilaStatus].len += 5;
+ }
+ if (fCtrlc) {
+ strcat (buf, " cancel");
+ rglaStatus[ilaStatus].len += 7;
+ fCtrlc = FALSE;
+ FlushInput ();
+ }
+ if (fMacroRecord) {
+ strcat (buf, " REC");
+ rglaStatus[ilaStatus].len += 4;
+ }
+ ilaStatus++;
+ }
+
+ rglaStatus[ilaStatus].attr = CINDEX(staColor);
+ rglaStatus[ilaStatus].len = 0xff;
+ pchEndBuf = buf;
+
+ /*
+ * if the net result is too long, eat the first part of the filename with
+ * an elipses (Leave room for BC as well).
+ */
+ cch = strlen(buf) - (XSIZE - 4);
+
+ if (cch > 0) {
+ pchEndBuf = buf + cch;
+ pchEndBuf[0] = '.';
+ pchEndBuf[1] = '.';
+ pchEndBuf[2] = '.';
+
+ i = 0;
+
+ while ( cch && i <= ilaStatus ) {
+
+ if ( (int)rglaStatus[i].len > cch ) {
+
+ rglaStatus[i].len -= cch;
+ cch = 0;
+
+ } else {
+
+ cch -= rglaStatus[i].len;
+ rglaStatus[i].len = 0;
+
+ }
+
+ i++;
+ }
+ }
+
+ fReDraw = FALSE;
+ coutb (0, YSIZE+1, pchEndBuf, strlen(pchEndBuf), rglaStatus);
+
+ fReDraw = TRUE;
+ voutb (XSIZE-2, YSIZE+1, BTWorking() ? "BP" : " ", 2, errColor);
+
+ RSETFLAG (fDisplay, RSTATUS);
+
+}
+
+
+
+/*** newscreen - Mark entire screen dirty
+*
+* Forces entire screen to be redrawn.
+*
+* Input:
+* none
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void
+newscreen (
+ void
+ ) {
+
+ REGISTER int iLine = YSIZE;
+
+ while (iLine--) {
+ SETFLAG ( fChange[iLine], FMODIFY );
+ }
+
+ SETFLAG (fDisplay, RTEXT);
+}
+
+
+
+/*** redraw - Mark a range of lines in file dirty
+*
+* Marks a range of lines in a file as needing to be updated. Each window that
+* they occur in is marked.
+*
+* Input:
+* pFile = File handle containing dirty lines
+* linFirst, linLast = Range of lines to mark
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void
+redraw (
+ PFILE pFile,
+ LINE linFirst,
+ LINE linLast
+ ) {
+
+ LINE linFirstUpd, linLastUpd;
+ REGISTER PINS pInsTmp;
+
+ int iWinTmp;
+ REGISTER struct windowType *pWinTmp;
+
+ if (linFirst > linLast) {
+ linFirstUpd = linLast;
+ linLast = linFirst;
+ linFirst = linFirstUpd;
+ }
+
+ for (iWinTmp = 0, pWinTmp = WinList; iWinTmp < cWin; iWinTmp++, pWinTmp++) {
+ if (pWinTmp->pInstance) {
+ if (pFile == pWinTmp->pInstance->pFile) {
+ pInsTmp = pWinTmp->pInstance;
+ linFirstUpd = WINYPOS(pWinTmp) + lmax (0L, linFirst-YWIN(pInsTmp)-1);
+ linLastUpd = WINYPOS(pWinTmp) + lmin ((long) (WINYSIZE(pWinTmp) - 1), linLast - YWIN(pInsTmp));
+ while (linFirstUpd <= linLastUpd) {
+ SETFLAG (fChange[linFirstUpd++],FMODIFY);
+ }
+ }
+ }
+ }
+ SETFLAG (fDisplay, RTEXT);
+}
+
+
+
+/*** newwindow - Mark current window dirty
+*
+* Mark all lines in the current window as needing to be updated
+*
+* Input:
+* none
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void
+newwindow (
+ void
+ ) {
+
+ REGISTER int iLine;
+
+ //
+ // We ignore the next two assertions, because of a more involved problem of
+ // screen size being set up AFTER instances and window layout have been read
+ // in on start up. This means that for a short period of time, these
+ // conditions might actually exist. We check for the error and limit the
+ // access of the fchange array for now.
+ //
+ // assert (MEMSIZE (fChange) >= WINYSIZE (pWinCur));
+ // assert (WINYSIZE (pWinCur) + WINYPOS (pWinCur) <= YSIZE);
+
+ for (iLine = 0; iLine < WINYSIZE (pWinCur); iLine++) {
+ if (iLine + WINYPOS(pWinCur) < YSIZE) {
+ SETFLAG (fChange[iLine + WINYPOS(pWinCur)],FMODIFY);
+ }
+ }
+ SETFLAG (fDisplay, RTEXT);
+}
+
+
+
+/*** noise
+*
+* Input:
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void
+noise (
+ REGISTER LINE lin
+ ) {
+
+ char szTinyBuf[10];
+
+ if (lin && cNoise) {
+ if ((lin % cNoise) == 0) {
+ sprintf (szTinyBuf, " %ld", lin);
+ soutb (XSIZE-10, YSIZE+1, szTinyBuf, fgColor);
+ }
+ }
+
+}
+
+
+
+/*** dispmsg - display retrieved message on help/status line
+*
+* Places a message on the help/status line. It is removed the next time
+* activity occurrs on that line.
+*
+* In the CW version, the resulting (formatted) message is placed in the
+* local heap, and actually displayed by the WndProc for the help window.
+*
+* Input:
+* iMsg = index for message string to be retrieved and displayed.
+* The string may have embedded printf formatting. If iMsg
+* is zero, the status line is cleared.
+* ... = variable number of args per the formatted string
+*
+* Output:
+* Returns TRUE
+*
+*************************************************************************/
+flagType
+dispmsg (
+ int iMsg,
+ ...
+ ) {
+
+ buffer fmtstr; /* retrieved formatting string */
+ //buffer textbuf; /* formatted output line */
+ char textbuf[ 512 ];
+ int len; /* Length of message */
+ va_list Argument;
+
+ va_start(Argument, iMsg);
+
+ if (fMessUp = (flagType)iMsg) {
+ GetMsg (iMsg, fmtstr);
+ ZFormat (textbuf, fmtstr, Argument);
+ len = strlen(textbuf);
+ if (len > (XSIZE-1)) {
+ //
+ // message is too long, we will truncate it
+ //
+ textbuf[XSIZE-1] = '\0';
+ }
+ } else {
+ textbuf[0] = ' ';
+ textbuf[1] = '\0';
+ }
+
+ fReDraw = TRUE;
+ soutb (0, YSIZE, textbuf, infColor);
+
+ va_end(Argument);
+
+ return TRUE;
+}
+
+
+
+/*** disperr - display error message on status line
+*
+* prints a formatted error message on the status line, and then waits for a
+* keystroke. Once hit, the message is cleared.
+*
+* Input:
+* iMsg = index for message string to be retrieved and displayed.
+* The string may have embedded printf formatting.
+* ... = variable number of args per the formatted string
+*
+* Output:
+* returns FALSE
+*
+*************************************************************************/
+flagType
+disperr (
+ int iMsg,
+ ...
+ ) {
+
+ buffer pszFmt; /* retrieved formatting string */
+ buffer bufLocal; /* formatted output line */
+ va_list Arguments;
+
+ assert (iMsg);
+ GetMsg (iMsg, pszFmt);
+
+ va_start(Arguments, iMsg);
+
+ ZFormat (bufLocal, pszFmt, Arguments);
+
+ fReDraw = TRUE;
+ bell ();
+ FlushInput ();
+ soutb (0, YSIZE, bufLocal, errColor);
+ if (fErrPrompt) {
+ asserte (*GetMsg (MSG_PRESS_ANY, bufLocal));
+ soutb (XSIZE-strlen(bufLocal)-1, YSIZE, bufLocal, errColor);
+ SetEvent( semIdle );
+ ReadChar ();
+ WaitForSingleObject(semIdle, INFINITE);
+ bufLocal[0] = ' ';
+ bufLocal[1] = '\0';
+ soutb(0, YSIZE, bufLocal, errColor);
+ } else {
+ delay (1);
+ }
+
+ va_end(Arguments);
+
+ return FALSE;
+}
+
+
+
+/*** domessage - display a message on the help-status line
+*
+* Places a message on the help/status line. It is removed the next time
+* activity occurrs on that line.
+*
+* In the CW version, the resulting (formatted) message is placed in the
+* local heap, and actually displayed by the WndProc for the help window.
+*
+* Input:
+* pszFmt - Printf formatting string
+* ... - variable number of args as per the formatting string
+*
+* Output:
+* Returns nothing
+*
+* UNDONE: all calls to domessage should be replaced by calls to dispmsg
+*
+*************************************************************************/
+int
+domessage (
+ char *pszFmt,
+ ...
+ ) {
+
+
+#define NEEDED_SPACE_AFTER_MESSAGE 12
+
+ char bufLocal[512];
+ va_list Arguments;
+ int Length;
+ char *Msg;
+
+ va_start(Arguments, pszFmt);
+
+ if (fMessUp = (flagType)(pszFmt != NULL)) {
+ ZFormat (bufLocal, pszFmt, Arguments);
+ } else {
+ bufLocal[0] = ' ';
+ bufLocal[1] = '\0';
+ }
+
+ fReDraw = TRUE;
+
+ va_end(Arguments);
+
+ //
+ // We have to make sure that the message is not too long for
+ // this line. If it is, se only display the last portion of it.
+ //
+ Length = strlen( bufLocal );
+
+ if ( Length > XSIZE - NEEDED_SPACE_AFTER_MESSAGE ) {
+ Msg = (char *)bufLocal + (Length - ( XSIZE - NEEDED_SPACE_AFTER_MESSAGE ));
+ Length = XSIZE - NEEDED_SPACE_AFTER_MESSAGE;
+ } else {
+ Msg = (char *)bufLocal;
+ }
+
+ soutb( 0, YSIZE, Msg, infColor );
+
+ return Length;
+
+}
+
+
+
+/*** printerror - print error message on status line
+*
+* prints a formatted error message on the status line, and then waits for a
+* keystroke. Once hit, the message is cleared.
+*
+* Input:
+* printf style parameters
+*
+* Output:
+* Number of characters output in error message
+*
+*************************************************************************/
+int
+printerror (
+ char *pszFmt,
+ ...
+ ) {
+
+ buffer bufLocal;
+ va_list Arguments;
+ REGISTER int cch;
+
+ va_start(Arguments, pszFmt);
+
+ ZFormat (bufLocal, pszFmt, Arguments);
+
+ fReDraw = TRUE;
+ bell ();
+ FlushInput ();
+ cch = soutb (0, YSIZE, bufLocal, errColor);
+ if (fErrPrompt) {
+ asserte (*GetMsg (MSG_PRESS_ANY, bufLocal));
+ soutb (XSIZE-strlen(bufLocal)-1, YSIZE, bufLocal, errColor);
+ SetEvent( semIdle );
+ ReadChar ();
+ WaitForSingleObject(semIdle, INFINITE);
+ bufLocal[0] = ' ';
+ bufLocal[1] = '\0';
+ soutb(0, YSIZE, bufLocal, errColor);
+ } else {
+ delay (1);
+ }
+
+ va_end(Arguments);
+
+ return cch;
+}
+
+
+
+/*** bell
+*
+* Input:
+*
+* Output:
+*
+*************************************************************************/
+void
+bell (
+ void
+ ) {
+
+ printf ("%c", BELL);
+
+}
+
+
+
+/*** makedirty
+*
+*
+* Input:
+*
+* Output:
+*
+*************************************************************************/
+void
+makedirty (
+ REGISTER PFILE pFileDirty
+ ) {
+ if (!TESTFLAG(FLAGS(pFileDirty),DIRTY)) {
+ if (pFileDirty == pFileHead) {
+ SETFLAG (fDisplay, RSTATUS);
+ }
+ SETFLAG (FLAGS(pFileDirty), DIRTY);
+ }
+}
+
+
+
+/*** delay
+*
+* Input:
+*
+* Output:
+*
+*************************************************************************/
+void
+delay (
+ int cSec
+ ) {
+
+ long lTimeNow, lTimeThen;
+
+ if (mtest () && !mlast ()) {
+ return;
+ }
+ time (&lTimeThen);
+ do {
+ if (TypeAhead ()) {
+ return;
+ }
+ Sleep (100);
+ time (&lTimeNow);
+ } while (lTimeNow - lTimeThen < cSec + 1);
+}
+
+
+
+/*** SetScreen
+*
+* Purpose:
+* SetScreen () - Set up the editor's internal structures to match the screen
+* size described by ySize and xSize. Set the hardware to the mode in
+* Zvideo.
+*
+* Input:
+*
+* Output:
+*
+*************************************************************************/
+void
+SetScreen (
+ void
+ ) {
+ fChange = ZEROREALLOC (fChange, YSIZE * sizeof (*fChange));
+ SETFLAG (fDisplay, RSTATUS);
+ if (cWin == 1) {
+ WINXSIZE(pWinCur) = XSIZE;
+ WINYSIZE(pWinCur) = YSIZE;
+ }
+ newscreen ();
+ // SetVideoState(Zvideo);
+}
+
+
+
+/*** HighLight
+*
+*
+* Input:
+*
+* Output:
+*
+*************************************************************************/
+void
+HighLight (
+ COL colFirst,
+ LINE linFirst,
+ COL colLast,
+ LINE linLast
+ ) {
+
+ rn rnCur;
+
+ rnCur.flFirst.lin = linFirst;
+ rnCur.flFirst.col = colFirst;
+ rnCur.flLast.lin = linLast;
+ rnCur.flLast.col = colLast;
+
+ SetHiLite (pFileHead, rnCur, INFCOLOR);
+}
+
+
+
+/*** AdjustLines - change all information relevant to deletion/insertion of
+* lines in a file.
+*
+* Purpose:
+* When we are deleting or inserting lines, there is some updating that we
+* need to do to retain some consistency in the user's view of the screen.
+* The updating consists of:
+*
+* Adjusting all window instances of this window to prevent "jumping".
+* We enumerate all window instances. If the top of the window is
+* above or inside the deleted/inserted range, do nothing. If the top of
+* the window is below the inserted/deleted range, we modify the cursor
+* and window position to prevent the window from moving on the text
+* being viewed.
+*
+* Ditto for all flip positions
+*
+* Input:
+* pFile file that is being modified
+* lin beginning line of modification
+* clin number of lines being inserted (> 0) or deleted (< 0)
+*
+* Output:
+*
+*************************************************************************/
+void
+AdjustLines (
+ PFILE pFile,
+ LINE lin,
+ LINE clin
+ ) {
+
+ int iWin;
+ REGISTER PINS pInsTmp;
+
+ /* walk all instances looking for one whose pFile matches
+ */
+
+ for (iWin = 0; iWin < cWin; iWin++) {
+ for (pInsTmp = WININST(WinList + iWin); pInsTmp != NULL; pInsTmp = pInsTmp->pNext) {
+ if (pInsTmp != pInsCur && pInsTmp->pFile == pFile) {
+ /* adjust current position if necessary
+ */
+ if (YWIN(pInsTmp) >= lin) {
+ YWIN(pInsTmp) = lmax ((LINE)0, YWIN(pInsTmp) + clin);
+ YCUR(pInsTmp) = lmax ((LINE)0, YCUR(pInsTmp) + clin);
+ }
+ /* adjust flip position if necessary
+ */
+ if (YOLDWIN(pInsTmp) >= lin) {
+ YOLDWIN(pInsTmp) = lmax ((LINE)0, YOLDWIN(pInsTmp) + clin);
+ YOLDCUR(pInsTmp) = lmax ((LINE)0, YOLDCUR(pInsTmp) + clin);
+ }
+ }
+ }
+ }
+}
+
+
+
+
+/*** UpdateIf - Move the cursor position if a particlar file is displayed
+*
+* Used to update the view on windows which are not necessarily the current
+* window. Examples: tying together the compile error log with the current
+* view on the source code.
+*
+* Input:
+* pFileChg = pointer to the file whose display is to be updated.
+* yNew = New cursor line position.
+* fTop = cursor line should be positionned at top/bottom of the window
+*
+* Output:
+* Returns TRUE if on-screen and updated.
+*
+*************************************************************************/
+flagType
+UpdateIf (
+ PFILE pFileChg,
+ LINE linNew,
+ flagType fTop
+ ) {
+
+ PINS pInsCur;
+ PWND pWndFound = NULL;
+ flagType fFound = FALSE;
+
+ /*
+ * If this is the top file, we don't want to do anything
+ */
+ if (pFileChg == pFileHead) {
+ return FALSE;
+ }
+
+ /*
+ * Walk the window list, and check to see if the top instance (file
+ * currently in view) is the one we care about. If so, update its cursor
+ * and window position.
+ */
+ while (pWndFound = IsVispFile (pFileChg, pWndFound)) {
+ if (pWndFound != pWinCur) {
+ pInsCur = WININST(pWndFound);
+ YCUR(pInsCur) = linNew;
+ XCUR(pInsCur) = 0;
+ YWIN(pInsCur) = fTop ?
+ YCUR(pInsCur) :
+ lmax (0L, YCUR(pInsCur) - (WINYSIZE(pWndFound)-1));
+ XWIN(pInsCur) = 0;
+ fFound = TRUE;
+ }
+ }
+
+ /*
+ * If any visible instances of the file were discovered above, redraw the
+ * entire file, such that all windows will be updated, regardless of view.
+ */
+ if (fFound) {
+ redraw (pFileChg, 0L, pFileChg->cLines);
+ }
+
+ return fFound;
+}
+
+
+
+/*** IsVispFile - See if pfile is visibke
+*
+* Determines if a particular pFile is currently visible to the user, and
+* returns a pointer to the window first found in.
+*
+* Input:
+* pFile = pFile of interest
+* pWin = pWin to start at, or NULL to start at begining
+*
+* Output:
+* Returns pWin of first window found, or NULL
+*
+*************************************************************************/
+PWND
+IsVispFile (
+ PFILE pFile,
+ REGISTER PWND pWnd
+ ) {
+
+ /*
+ * If NULL starting pWnd specified, then start at first one.
+ */
+ if (!pWnd++) {
+ pWnd = &WinList[0];
+ }
+
+ /*
+ * for all remaining windows currently active, check top instance for pFile
+ * of interest
+ */
+ for (; pWnd < &WinList[cWin]; pWnd++) {
+ if (WININST(pWnd)->pFile == pFile) {
+ return pWnd;
+ }
+ }
+ return NULL;
+}
+
+
+
+
+
+/*** GetMsg - Message Retriever
+*
+* Purpose:
+* Get an error message from the message segment and copy it to a
+* buffer, returning a pointer to the buffer.
+*
+* Input:
+* iMsg = Message number to get
+* pchDst = pointer to place to put it
+*
+* Output:
+* returns pDest
+*
+* Exceptions:
+* None
+*
+*************************************************************************/
+char *
+GetMsg (
+ unsigned iMsg,
+ char *pchDst
+ ) {
+
+ char *pch;
+ WORD i;
+
+ for (i=0; (MsgStr[i].usMsgNo != (WORD)iMsg) && (MsgStr[i].usMsgNo != 0); i++);
+ pch = MsgStr[i].pMsgTxt;
+
+ strcpy ((char *)pchDst, pch);
+
+ return pchDst;
+
+}
diff --git a/private/utils/mep/src/dline.c b/private/utils/mep/src/dline.c
new file mode 100644
index 000000000..78d2d3dd1
--- /dev/null
+++ b/private/utils/mep/src/dline.c
@@ -0,0 +1,325 @@
+/*** dline.c - return one display line
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+
+#include "mep.h"
+
+
+/*** fInRange - return true if the arguments are in order
+*
+* Input:
+*
+* Output:
+*
+*************************************************************************/
+flagType
+fInRange (
+ long a,
+ long x,
+ long b
+ ) {
+ return (flagType) (((a <= x) && (x <= b)) || ((a >= x) && (x >= b)));
+}
+
+
+
+/*
+ * Characters used in window borders
+ */
+
+#define DHBAR ((char)0xCD)
+#define DVBAR ((char)0xBA)
+#define DLTEE ((char)0xB9)
+#define DUTEE ((char)0xCA)
+#define DRTEE ((char)0xCC)
+#define DDTEE ((char)0xCB)
+#define DCRSS ((char)0xCE)
+
+/*** DisplayLine - Get's the i'th display line of a window
+*
+* Gets exactly what needs to be shown in the i'th line of the screen.
+* This takes care of showing trailing spaces, drawing borders, etc...
+*
+* Input:
+* yScrLine - Get i'th line showing in the window
+* pchScrLine - pointer to line buffer where the screen line is to be put
+* pplaScrLine - pointer to pointer to place to put color info
+* pchFileLine - pointer to line buffer
+* pplaFileLine - pointer to pointer to place to put color info
+*
+* Note:
+* If there is only one window on the screen then we only need one line
+* buffer and one color buffer. DoText should have taken care of this so
+* pchFileLine and *pplaFileLine should be both NULL.
+*
+* Output:
+* Returns Length of string in pchScrLine
+*
+****************************************************************************/
+int
+DisplayLine (
+ int yScrLine,
+ char *pchScrLine,
+ struct lineAttr **pplaScrLine,
+ char *pchFileLine,
+ struct lineAttr **pplaFileLine
+ ) {
+
+ int iWnd;
+ REGISTER PWND pWnd;
+ PINS pIns;
+ PFILE pFile;
+
+ int cch;
+ REGISTER char *pch;
+
+ /*
+ * one window, speed hack:
+ *
+ * if there is only one window, just grab the line, append any trailing
+ * space display, move the applicable portion of the line to the head of
+ * the buffer, space fill out to the window width, and get the color info
+ * for the line.
+ */
+ if (cWin == 1) {
+
+ /*
+ * we always get the detab'ed (non-RAW) line for displaying.
+ */
+ cch = gettextline (FALSE,
+ yScrLine + YWIN(pInsCur),
+ pchScrLine,
+ pFileHead,
+ tabDisp);
+ ShowTrailDisp (pchScrLine, cch);
+
+ /*
+ * Scroll left to match instance
+ */
+ if (XWIN(pInsCur)) {
+ cch = max (0, min (cch - XWIN(pInsCur), XSIZE));
+ memmove( pchScrLine, (pchScrLine + XWIN(pInsCur)), cch );
+ } else {
+ cch = min (cch, XSIZE);
+ }
+
+ /*
+ * Pad end of line with blanks
+ */
+ if (cch < XSIZE) {
+ memset ((char *) pchScrLine + cch, ' ', XSIZE - cch);
+ }
+ pchScrLine[XSIZE] = 0;
+
+ /*
+ * Get color and hiliting info from the file
+ * (UpdHilite takes care of left scroll)
+ */
+ GetColorUntabbed ((LINE)(yScrLine + YWIN(pInsCur)), *pplaScrLine, pFileHead);
+ UpdHiLite (pFileHead,
+ (LINE) (yScrLine + YWIN(pInsCur)),
+ XWIN(pInsCur),
+ XWIN(pInsCur) + XSIZE - 1,
+ pplaScrLine);
+ return XSIZE;
+ }
+
+ /*
+ * Multiple windows
+ *
+ * initially set up the line to be all dashes (horizontal screen split)
+ * with window borders color
+ */
+ memset ((char *) (pchScrLine), DHBAR, XSIZE);
+ pchScrLine[XSIZE] = 0;
+ (*pplaScrLine)->len = 0xff;
+ (*pplaScrLine)->attr = WDCOLOR;
+
+ /*
+ * for each active window
+ */
+ for (iWnd = 0, pWnd = WinList; iWnd < cWin; iWnd++, pWnd++) {
+ /*
+ * if the display line is in the window
+ */
+ if (fInRange ((long) WINYPOS(pWnd),
+ (long) yScrLine,
+ (long) (WINYPOS(pWnd) + WINYSIZE(pWnd) - 1))) {
+ /*
+ * Do window on right
+ */
+ if (WINXPOS(pWnd)) {
+ switch (*(pch = pchScrLine + WINXPOS(pWnd) - 1) & 0xFF) {
+ case DHBAR:
+ *pch = DLTEE;
+ break;
+ case DRTEE:
+ *pch = DVBAR;
+ break;
+ case DUTEE:
+ *pch = DLTEE;
+ break;
+ case DCRSS:
+ *pch = DLTEE;
+ break;
+ }
+ }
+ /*
+ * blank the window
+ */
+ memset ((char *) pchScrLine + WINXPOS(pWnd), ' ', WINXSIZE(pWnd));
+ UpdOneHiLite (*pplaScrLine,
+ WINXPOS(pWnd),
+ WINXSIZE(pWnd),
+ TRUE,
+ FGCOLOR);
+
+ /*
+ * retrieve the window instance and current file
+ */
+ pIns = pWnd->pInstance;
+ pFile = pIns->pFile;
+
+ /*
+ * get the correct line from the file
+ */
+ cch = gettextline (FALSE,
+ (LINE) (yScrLine - WINYPOS(pWnd) + YWIN(pIns)),
+ pchFileLine,
+ pFile,
+ tabDisp);
+ ShowTrailDisp (pchFileLine, cch);
+
+ /*
+ * if line is visible
+ */
+ if (cch >= XWIN (pIns)) {
+
+ /*
+ * move the visible portion of the line into the buffer
+ */
+ memmove((char*)( pchScrLine + WINXPOS( pWnd )),
+ (char*)( pchFileLine + XWIN( pIns )),
+ min (cch-XWIN(pIns), WINXSIZE(pWnd)));
+
+ /*
+ * Get color and hiliting info from the file
+ * (UpdHilite takes care of left scroll)
+ */
+ GetColorUntabbed ((LINE) (yScrLine - WINYPOS(pWnd) + YWIN(pIns)),
+ *pplaFileLine,
+ pFile);
+ UpdHiLite (pFile,
+ (LINE) (yScrLine - WINYPOS(pWnd) + YWIN(pIns)),
+ XWIN(pIns),
+ XWIN(pIns) + WINXSIZE(pWnd) - 1,
+ pplaFileLine);
+
+ /*
+ * Put it in the screen buffer
+ */
+ UpdOneHiLite (*pplaScrLine,
+ WINXPOS(pWnd),
+ WINXSIZE(pWnd),
+ FALSE,
+ (int) *pplaFileLine);
+ }
+ /*
+ * do window left
+ */
+ switch (*(pch = pchScrLine + WINXPOS(pWnd) + WINXSIZE(pWnd)) & 0xFF) {
+ case DHBAR:
+ *pch = DRTEE;
+ break;
+ case DLTEE:
+ *pch = DVBAR;
+ break;
+ case DCRSS:
+ *pch = DRTEE;
+ break;
+ }
+ } else {
+ /*
+ * test for break immediately above
+ */
+ if (WINYPOS(pWnd) + WINYSIZE(pWnd) == yScrLine) {
+ switch (*(pch = pchScrLine + WINXPOS(pWnd) + WINXSIZE(pWnd)) & 0xFF) {
+ case DHBAR:
+ *pch = DUTEE;
+ break;
+ case DDTEE:
+ *pch = DCRSS;
+ break;
+ }
+ } else {
+ /*
+ * test for break immediately below
+ */
+ if (WINYPOS(pWnd)-1 == yScrLine) {
+ switch (*(pch = pchScrLine + WINXPOS(pWnd) + WINXSIZE(pWnd)) & 0xFF) {
+ case DHBAR:
+ *pch = DDTEE;
+ break;
+ case DUTEE:
+ *pch = DCRSS;
+ break;
+ }
+ }
+ }
+ }
+ }
+ pchScrLine[XSIZE] = 0;
+ return XSIZE;
+}
+
+
+
+/*** SetTrailDisp - set character displayed for trailing spaces.
+*
+* Input:
+*
+* Output:
+*
+*************************************************************************/
+flagType
+SetTrailDisp (
+ char * val
+ ) {
+ buffer locval;
+
+ strcpy ((char *) locval, val);
+
+ trailDisp = (char) atoi (locval);
+
+ newscreen ();
+ return TRUE;
+}
+
+
+
+/*** ShowTrailDisp
+*
+* Input:
+*
+* Output:
+*
+*************************************************************************/
+void
+ShowTrailDisp (
+ buffer buf,
+ int len
+ ) {
+ REGISTER char * p;
+
+ if (trailDisp) {
+ p = &buf[len];
+ while (p > buf && p[-1] == ' ') {
+ *--p = trailDisp;
+ }
+ }
+}
diff --git a/private/utils/mep/src/env.c b/private/utils/mep/src/env.c
new file mode 100644
index 000000000..c368647ee
--- /dev/null
+++ b/private/utils/mep/src/env.c
@@ -0,0 +1,288 @@
+/* env.c - manipulate editor environment
+ *
+ * Modifications:
+ *
+ * 26-Nov-1991 mz Strip off near/far
+ *
+ */
+
+#include "mep.h"
+
+/* environment - function to perform environment manipulation
+ *
+ * set environment
+ * display environment
+ * perform env substitution
+ *
+ * fn sets environment
+ * meta fn does env substitution
+ *
+ * noarg sets current line into env
+ * textarg sets text into env single ? displays env
+ * nullarg sets to eol into env
+ * linearg sets each line into env
+ * streamarg sets each fragment into env
+ * boxarg sets each fragment into env
+ *
+ * meta noarg maps current line
+ * meta textarg illegal
+ * meta nullarg maps to eol
+ * meta linearg maps each line
+ * meta streamarg maps each fragment
+ * meta boxarg maps each fragment
+ *
+ * argData keystroke
+ * pArg definition of arguments
+ * fMeta TRUE => meta was invoked
+ *
+ * Returns: TRUE if operation was successful
+ * FALSE otherwise
+ */
+
+static char *pmltl = "Mapped line %ld too long";
+
+
+
+flagType
+environment (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ ){
+
+ linebuf ebuf, ebuf1;
+ LINE l;
+ int ol;
+
+ if (!fMeta) {
+ /* Perform environment modifications
+ */
+ switch (pArg->argType) {
+
+ case NOARG:
+ GetLine (pArg->arg.noarg.y, ebuf, pFileHead);
+ return fSetEnv (ebuf);
+
+ case TEXTARG:
+ strcpy ((char *) ebuf, pArg->arg.textarg.pText);
+ return fSetEnv (ebuf);
+
+ case NULLARG:
+ fInsSpace (pArg->arg.nullarg.x, pArg->arg.nullarg.y, 0, pFileHead, ebuf);
+ return fSetEnv (&ebuf[pArg->arg.nullarg.x]);
+
+ case LINEARG:
+ for (l = pArg->arg.linearg.yStart; l <= pArg->arg.linearg.yEnd; l++) {
+ GetLine (l, ebuf, pFileHead);
+ if (!fSetEnv (ebuf)) {
+ docursor (0, l);
+ return FALSE;
+ }
+ }
+ return TRUE;
+
+ case BOXARG:
+ for (l = pArg->arg.boxarg.yTop; l <= pArg->arg.boxarg.yBottom; l++) {
+ fInsSpace (pArg->arg.boxarg.xRight, l, 0, pFileHead, ebuf);
+ ebuf[pArg->arg.boxarg.xRight+1] = 0;
+ if (!fSetEnv (&ebuf[pArg->arg.boxarg.xLeft])) {
+ docursor (pArg->arg.boxarg.xLeft, l);
+ return FALSE;
+ }
+ }
+ return TRUE;
+
+ }
+ } else {
+ /* Perform environment substitutions
+ */
+ switch (pArg->argType) {
+
+ case NOARG:
+ GetLine (pArg->arg.noarg.y, ebuf, pFileHead);
+ if (!fMapEnv (ebuf, ebuf, sizeof(ebuf))) {
+ printerror (pmltl, pArg->arg.noarg.y+1);
+ return FALSE;
+ }
+ PutLine (pArg->arg.noarg.y, ebuf, pFileHead);
+ return TRUE;
+
+ case TEXTARG:
+ return BadArg ();
+
+ case NULLARG:
+ fInsSpace (pArg->arg.nullarg.x, pArg->arg.nullarg.y, 0, pFileHead, ebuf);
+ if (!fMapEnv (&ebuf[pArg->arg.nullarg.x],
+ &ebuf[pArg->arg.nullarg.x],
+ sizeof(ebuf) - pArg->arg.nullarg.x)) {
+ printerror (pmltl, pArg->arg.nullarg.y+1);
+ return FALSE;
+ }
+ PutLine (pArg->arg.nullarg.y, ebuf, pFileHead);
+ return TRUE;
+
+ case LINEARG:
+ for (l = pArg->arg.linearg.yStart; l <= pArg->arg.linearg.yEnd; l++) {
+ GetLine (l, ebuf, pFileHead);
+ if (!fMapEnv (ebuf, ebuf, sizeof (ebuf))) {
+ printerror (pmltl, l+1);
+ docursor (0, l);
+ return FALSE;
+ }
+ PutLine (l, ebuf, pFileHead);
+ }
+ return TRUE;
+
+ case BOXARG:
+ for (l = pArg->arg.boxarg.yTop; l <= pArg->arg.boxarg.yBottom; l++) {
+ fInsSpace (pArg->arg.boxarg.xRight, l, 0, pFileHead, ebuf);
+ ol = pArg->arg.boxarg.xRight + 1 - pArg->arg.boxarg.xLeft;
+ memmove ( ebuf1, &ebuf[pArg->arg.boxarg.xLeft], ol);
+ ebuf1[ol] = 0;
+ if (!fMapEnv (ebuf1, ebuf1, sizeof (ebuf1)) ||
+ strlen (ebuf1) + strlen (ebuf) - ol >= sizeof (ebuf)) {
+ printerror (pmltl, l+1);
+ docursor (0, l);
+ return FALSE;
+ }
+ strcat (ebuf1, &ebuf[pArg->arg.boxarg.xRight + 1]);
+ strcpy (&ebuf[pArg->arg.boxarg.xLeft], ebuf1);
+ PutLine (l, ebuf, pFileHead);
+ }
+ return TRUE;
+
+ }
+ }
+ argData;
+}
+
+
+
+
+/* fMapEnv - perform environment substitutions
+ *
+ * pSrc character pointer to pattern string
+ * pDst character pointer to destination buffer
+ * cbDst amount of space in destination
+ *
+ * Returns TRUE if successful substitution
+ * FALSE if length overflow
+ */
+flagType
+fMapEnv (
+ char *pSrc,
+ char *pDst,
+ int cbDst
+ ) {
+
+ buffer tmp;
+ char *pTmp, *p, *pEnd, *pEnv;
+ int l;
+
+ /* when we find a $()-surrounded token, we'll null-terminate it using p
+ * and attempt to find it in the environment. If we find it, we replace
+ * it. If we don't find it, we drop it out.
+ */
+
+ pTmp = tmp;
+ pEnd = pTmp + cbDst;
+
+ while (*pSrc != 0) {
+ if (pSrc[0] == '$' && pSrc[1] == '(' && *(p = strbscan (pSrc + 2, ")")) != '\0') {
+ *p = '\0';
+ //pEnv = getenv(pSrc + 2);
+ pEnv = getenvOem(pSrc + 2);
+ *p = ')';
+ if (pEnv != NULL) {
+ if ((l = strlen (pEnv)) + pTmp > pEnd) {
+ free(pEnv);
+ return FALSE;
+ } else {
+ strcpy (pTmp, pEnv);
+ pTmp += l;
+ }
+ free(pEnv);
+ }
+ pSrc = p + 1;
+ continue;
+ }
+ if (pTmp > pEnd) {
+ return FALSE;
+ } else {
+ *pTmp++ = *pSrc++;
+ }
+ }
+ *pTmp = '\0';
+ strcpy (pDst, tmp);
+ return TRUE;
+}
+
+
+
+
+/* fSetEnv - take some text and set it in the environment
+ *
+ * We ignore leading/trailing blanks. "VAR=blah" is done with quotes removed.
+ *
+ * p character pointer to text
+ *
+ * returns TRUE if successfully set
+ * FALSE otherwise
+ */
+flagType
+fSetEnv (
+ char *p
+ ){
+ char *p1;
+
+ p = whiteskip (p);
+ RemoveTrailSpace (p);
+ /* Handle quoting
+ */
+ p1 = strend (p) - 1;
+
+ if (strlen (p) > 2 && *p == '"' && *p1 == '"') {
+ p++;
+ *p1 = 0;
+ }
+
+ if (!strcmp (p, "?")) {
+ AutoSave ();
+ return fChangeFile (FALSE, "<environment>");
+ }
+
+ if ((p = ZMakeStr (p)) == NULL) {
+ return FALSE;
+ }
+
+// if (putenv (p)) {
+ if (putenvOem (p)) {
+ FREE (p);
+ return FALSE;
+ }
+
+ FREE (p);
+ return TRUE;
+}
+
+
+
+
+/* showenv - dump the environment into a file
+ *
+ * pFile file where output goes
+ */
+void
+showenv (
+ PFILE pFile
+ ){
+
+ int i;
+
+ DelFile (pFile, FALSE);
+ for (i = 0; environ[i] != NULL; i++) {
+ AppFile (environ[i], pFile);
+ }
+ RSETFLAG (FLAGS(pFile), DIRTY);
+ SETFLAG (FLAGS(pFile), READONLY);
+}
diff --git a/private/utils/mep/src/event.c b/private/utils/mep/src/event.c
new file mode 100644
index 000000000..b72f8fd48
--- /dev/null
+++ b/private/utils/mep/src/event.c
@@ -0,0 +1,116 @@
+/*** event.c - handle events for z extensions
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+#include "mep.h"
+
+EVT *pEVTHead = NULL; /* head of event chain */
+
+
+/*** DeclareEvent - post the ocurrance of an event, and pass message
+*
+* Called by the various pieces of code that actualy detect event ocurrance,
+* this routine traverses the event handler list, and invokes the event handler
+* for each with matching criteria.
+*
+* event - Event Type.
+* pargs - Pointer to any args to be passed to the handling routine
+*
+* Returns - TRUE if the event has been consumed, and should be further
+* ignored by the caller. Else FALSE.
+*
+*************************************************************************/
+flagType
+DeclareEvent (
+ unsigned event,
+ EVTargs *pargs
+ ) {
+
+ EVT *pEVTCur;
+
+ //
+ // For each in chain, if:
+ // - event type matches
+ // - focus is not specified, (all files) or matches the current focus
+ // - if it's a keyboard event, either no key was specified, or the
+ // matching key was specified
+ // then we invoke the handler.
+ //
+ for (pEVTCur = pEVTHead; pEVTCur; pEVTCur = pEVTCur->pEVTNext) {
+ assert (pEVTCur->pEVTNext != pEVTCur);
+ if (pEVTCur->evtType != event) {
+ //
+ // Skip events that don't match
+ //
+ } else if (pEVTCur->focus != NULL && pEVTCur->focus != pFileHead) {
+ //
+ // Skip events that aren't for this file
+ //
+ } else if ((event == EVT_KEY || event == EVT_RAWKEY) &&
+ pEVTCur->arg.arg.key.LongData != 0 && pEVTCur->arg.arg.key.LongData != pargs->arg.key.LongData) {
+ //
+ // Skip events that don't match keystrokes
+ //
+ } else if (pEVTCur->func (pargs) != 0) {
+ //
+ // Event handler eats event, don't propogate it
+ //
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+
+
+/* RegisterEvent - Register Event handler
+ *
+ * Called by the extension that wishes to recieve event notification. Just
+ * places ptr at head of list.
+ *
+ * pEVTDef - Pointer to Event Definition struct.
+ *
+ */
+void
+RegisterEvent (
+ EVT *pEVTDef
+ ) {
+ pEVTDef->pEVTNext = pEVTHead;
+ pEVTHead = pEVTDef;
+}
+
+
+
+/* DeRegisterEvent - DeRegister Event handler
+ *
+ * Called by the extension that wishes to stop recieving event notification.
+ * Just removes struct from list.
+ *
+ * pEVTDef - Pointer to Event Definition struct.
+ *
+ */
+void
+DeRegisterEvent (
+ EVT *pEVTDef
+ ) {
+
+ EVT *pEVTCur;
+
+ if (pEVTHead) {
+ if (pEVTHead == pEVTDef) {
+ pEVTHead = pEVTDef->pEVTNext;
+ } else {
+ for (pEVTCur=pEVTHead; pEVTCur; pEVTCur=pEVTCur->pEVTNext) {
+ if (pEVTCur->pEVTNext == pEVTDef) {
+ pEVTCur->pEVTNext = pEVTDef->pEVTNext;
+ break;
+ }
+ }
+ }
+ }
+}
diff --git a/private/utils/mep/src/file.c b/private/utils/mep/src/file.c
new file mode 100644
index 000000000..27ea62e5c
--- /dev/null
+++ b/private/utils/mep/src/file.c
@@ -0,0 +1,895 @@
+/*** file.c - file management
+*
+* The internal file structure uses a combination of local memory
+* (managed by LMAlloc and free) and virtual memory (managed by malloc/ffree
+* and (pb|VA)To(pb|VA)).
+*
+* We maintain one record for each file that Z has "in memory". If a file
+* appears in multiple windows, there is only one record for that file.
+* Each window is treated as a separate instance of the editor, with a
+* separate record for each file that is present in that window.
+*
+* Graphically, this appears as follows:
+*
+* WinList (set of windows on the screen) 0 ... cWin-1
+* +---------------+---------------+---------------+---------------+
+* | Window 1 | Window 2 | Window 3 | Window 4 |
+* | | | | |
+* |windowType | | | |
+* | | | | |
+* |pInstance-+ |pInstance-+ |pInstance-+ |pInstance-+ |
+* +----------|----+----------|----+----------|----+----------|----+
+* | v v |
+* v ... ... v
+* +-------------+ pFileHead +-------------+
+* |instanceType | | |instanceType |
+* | | +----------+-----------+ | |
+* +--pNext | | v | +--pNext |
+* | |pFile------------+ +-------------+ | | |pFile |
+* | +-------------+ |fileType | | | +-------------+
+* | | | | |
+* +------+ +--pFileNext | | +------+
+* | +-----pName | | |
+* v | | +-------------+ | v
+* +-------------+ | | | +-------------+
+* |instanceType | | | | |instanceType |
+* | | | | | | |
+* +--pNext | | +--------+ | +--pNext |
+* | |pFile----+ | | | +-------pFile |
+* | +---------|---+ | v | +-------------+
+* | | | +-------------+ |
+* +------+ v | |fileType | +------+
+* | ... | | | |
+* v | +--pFileNext | v
+* ... | | |pName | ...
+* +-----------+ | +-------------+
+* | |
+* v |
+* +--------+ |
+* |filename| +--------+
+* +--------+ |
+* v
+* ...
+*
+* Modifications:
+*
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+#define INCL_DOSFILEMGR
+
+#include "mep.h"
+
+#define DIRTY 0x01 /* file had been modified */
+#define FAKE 0x02 /* file is a pseudo file */
+#define REAL 0x04 /* file has been read from disk */
+#define DOSFILE 0x08 /* file has CR-LF */
+#define TEMP 0x10 /* file is a temp file */
+#define NEW 0x20 /* file has been created by editor*/
+#define REFRESH 0x40 /* file needs to be refreshed */
+#define READONLY 0x80 /* file may not be editted */
+
+
+
+#define DEBFLAG FILEIO
+
+/*** AutoSave - take current file and write it out if necessary
+*
+* AutoSave is called when it makes sense to be paranoid about saving the
+* file. We save the file only when autosaving is enabled and when the
+* file is real and dirty.
+*
+* Input:
+* none
+*
+* Output:
+* none
+*
+*************************************************************************/
+void
+AutoSave (
+ void
+ ) {
+ AutoSaveFile (pFileHead);
+}
+
+
+/*** AutoSaveFile - AutoSave a specific file
+*
+* Called when it makes sense to be paranoid about saving a specific file. We
+* save the file only when autosaving is enabled and when the file is real and
+* dirty.
+*
+* Input:
+* pFile = File to be autosaved
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void
+AutoSaveFile (
+ PFILE pFile
+ ) {
+ if (fAutoSave && (FLAGS(pFile) & (DIRTY | FAKE)) == DIRTY) {
+ fSyncFile (pFile, TRUE);
+ FileWrite (NULL, pFile);
+ }
+}
+
+
+
+/* GetFileTypeName - return the text corresponding to the file type
+ *
+ * GetFileTypeName takes the file type as set in the file structure of the
+ * current file and returns the textual string corresponding to that type.
+ *
+ * returns character pointer to the type-specific text
+ */
+char *
+GetFileTypeName (
+ void
+ ) {
+ if (TESTFLAG (FLAGS (pFileHead),FAKE)) {
+ return "pseudo";
+ }
+ return mpTypepName[FTYPE (pFileHead)];
+}
+
+
+
+/* SetFileType - set the file type of a file based upon its extension
+ *
+ * pFile pointer to file whose type will be determined
+ */
+void
+SetFileType (
+ PFILE pFile
+ ) {
+ pathbuf fext;
+ REGISTER int i;
+
+ extention (pFile->pName, fext);
+
+ for (i = 0; ftypetbl[i].ext; i++) {
+ if (!strcmp (ftypetbl[i].ext, (char *)&fext[1])) {
+ break;
+ }
+ }
+
+ FTYPE(pFile) = ftypetbl[i].ftype;
+}
+
+
+
+
+/* fChangeFile - change the current file, drive or directory. We form the
+ * canonicalized name and attempt to find it in our internal list. If
+ * present, then things are simple: relink it to the head of the current
+ * window instance set. If not present, then we need to read it in.
+ *
+ * The actual algorithm is much simpler:
+ *
+ * If file not in file list then
+ * create new entry in file list
+ * Find file in file list
+ * If file not in window instance list then
+ * add file to top of window instance list
+ * while files in window instance list do
+ * select top file
+ * if file is in memory then
+ * change succeeded
+ * else
+ * if read in succeeds then
+ * change succeeded
+ * pop off top file
+ * change failed
+ *
+ *
+ * fShort TRUE => allow searching for short names
+ * name name of file.
+ *
+ * Returns: TRUE if change succeeded
+ * FALSE otherwise
+ */
+flagType
+fChangeFile (
+ flagType fShort,
+ char *name
+ ) {
+
+ PFILE pFileTmp;
+ pathbuf bufCanon;
+ flagType fRead;
+
+ //
+ // Turn file name into canonical form
+ //
+
+ if (!CanonFilename (name, bufCanon)) {
+
+ //
+ // We may have failed because a drive or directory
+ // went away. If the file named is on the file
+ // list, we remove it.
+ //
+
+ printerror ("Cannot access %s - %s", name, error () );
+
+ pFileTmp = FileNameToHandle (name, (fShort && fShortNames) ? name : NULL);
+ if (pFileTmp != NULL) {
+ RemoveFile (pFileTmp);
+ }
+
+ return FALSE;
+ }
+
+ //
+ // name has the input name
+ // bufCanon has the full "real" name
+ //
+ // Check to see if the file is in the current file set
+ //
+
+ pFileTmp = FileNameToHandle (bufCanon, (fShort && fShortNames) ? name : NULL);
+
+ if (pFileTmp == NULL) {
+
+ //
+ // File not loaded. If it is a directory, change to it
+ //
+
+ if (strlen (bufCanon) == 2 && bufCanon[1] == ':') {
+ bufCanon[2] = '\\';
+ }
+
+ if (_chdir (bufCanon) != -1) {
+ domessage ("Changed directory to %s", bufCanon);
+ return TRUE;
+ }
+
+ //
+ // Must be a file. Create a new internal file for it
+ //
+ pFileTmp = AddFile (bufCanon);
+ }
+
+ //
+ // Bring the found file to the top of the MRU list
+ //
+
+ pFileToTop (pFileTmp);
+
+ //
+ // if the file is not currently in memory, read it in
+ //
+ domessage (NULL);
+
+ if (((FLAGS (pFileHead) & (REAL|REFRESH)) == REAL)
+ || (fRead = FileRead (pFileHead->pName, pFileHead, TRUE))) {
+
+ // If we just read in the file AND the file is new then
+ // reset cached location to TOF.
+ //
+ if (fRead && TESTFLAG (FLAGS (pFileHead), NEW)) {
+ YCUR(pInsCur) = 0;
+ XCUR(pInsCur) = 0;
+ }
+ fSyncFile (pFileHead, TRUE);
+ cursorfl (pInsCur->flCursorCur);
+ fInitFileMac (pFileHead);
+
+ //
+ // Set the window's title
+ //
+ //char *p;
+ //p = pFileHead->pName + strlen(pFileHead->pName);
+ //
+ //while ( p > pFileHead->pName && *p != '\\' ) {
+ // p--;
+ //}
+ //if ( *p == '\\' ) {
+ // p++;
+ //}
+ //sprintf( bufCanon, "%s - %s", pNameEditor, p );
+ //SetConsoleTitle( bufCanon );
+ return TRUE;
+ }
+
+ // The file was not successfully read in. Remove this instance and
+ // return the indicated error.
+ //
+ RemoveTop ();
+
+ return FALSE;
+}
+
+
+
+
+/*** fInitFileMac - Initialize macros associated with a file
+*
+* Sets the curfile family of macros, and attempts to read any extension-
+* specific section from tools.ini.
+*
+* Input:
+* pFileNew = File to set information for
+*
+* Output:
+* Returns TRUE if TOOLS.INI section found, else FALSE
+*
+*************************************************************************/
+flagType
+fInitFileMac (
+ PFILE pFileNew
+ ) {
+
+ char fbuf[ 512 ];
+
+ strcpy (fbuf, pFileNew->pName);
+ FmtAssign ("curFile:=\"%s\"", DoubleSlashes (fbuf));
+
+ filename (pFileNew->pName, fbuf);
+ FmtAssign ("curFileNam:=\"%s\"", fbuf);
+
+ if (!extention (pFileNew->pName, fbuf)) {
+ fbuf[0] = '.';
+ fbuf[1] = '\0';
+ }
+ FmtAssign ("curFileExt:=\"%s\"", fbuf);
+
+ return InitExt (fbuf);
+}
+
+
+
+
+/* AddFile - create a named file buffer
+ *
+ * Create and initialize a named buffer. The contents are initially
+ * empty.
+ *
+ * p character pointer to name
+ *
+ * returns file handle to internal file structure
+ */
+PFILE
+AddFile (
+ char *p
+ ) {
+
+ PFILE pFileTmp;
+ PFILE pFileSrch;
+
+#ifdef DEBUG
+ /*
+ * assert we're not attempting to add a duplicate entry
+ */
+ for (pFileTmp = pFileHead;
+ pFileTmp != NULL;
+ pFileTmp = pFileTmp->pFileNext) {
+
+ assert (_stricmp ((char *)(pFileTmp->pName), p));
+ }
+#endif
+
+ pFileTmp = (PFILE) ZEROMALLOC (sizeof (*pFileTmp));
+#ifdef DEBUG
+ pFileTmp->id = ID_PFILE;
+#endif
+ pFileTmp->pName = ZMakeStr (p);
+
+ /*
+ * Everything that we explicitly set NULL, we can assume, as LMAlloc init's
+ * the allocated PFILE to all nulls.
+ *
+ * pFileTmp->pFileNext = NULL;
+ * pFileTmp->cLines = 0;
+ * pFileTmp->refCount = 0;
+ * FLAGS(pFileTmp) = FALSE;
+ * pFileTmp->cUndo = 0;
+ */
+ pFileTmp->plr = NULL;
+ pFileTmp->pbFile = NULL;
+ pFileTmp->vaColor = (PVOID)(-1L);
+ pFileTmp->vaHiLite = (PVOID)(-1L);
+ pFileTmp->vaMarks = NULL;
+ pFileTmp->vaUndoCur = pFileTmp->vaUndoHead = pFileTmp->vaUndoTail = (PVOID)(-1L);
+
+ CreateUndoList (pFileTmp);
+ /*
+ * Place the file at the end of the pFile list
+ */
+ if (pFileHead == NULL) {
+ pFileHead = pFileTmp;
+ } else {
+ for (pFileSrch = pFileHead;
+ pFileSrch->pFileNext;
+ pFileSrch = pFileSrch->pFileNext) {
+ ;
+ }
+ pFileSrch->pFileNext = pFileTmp;
+ }
+
+ SetFileType (pFileTmp);
+
+ return pFileTmp;
+}
+
+
+
+
+/* IncFileRef - note a new reference to a file
+ */
+void
+IncFileRef (
+ PFILE pFile
+ ) {
+ pFile -> refCount++;
+}
+
+
+
+
+
+/* DecFileRef - remove a reference to a file
+ *
+ * When the reference count goes to zero, we remove the file from the memory
+ * set
+ */
+void
+DecFileRef (
+ PFILE pFileTmp
+ ) {
+ if (--(pFileTmp->refCount) <= 0) {
+ RemoveFile (pFileTmp);
+ }
+}
+
+
+
+/* FileNameToHandle - return handle corresponding to the file name
+ *
+ * FileNameToHandle is used to locate the buffer pointer corresponding to
+ * a specified file. Short names are allowed. If the input name is 0-length
+ * we return the current file.
+ *
+ * pName character pointer to name being located. Case is significant.
+ * pShortName short name of file. This may be NULL
+ *
+ * Returns handle to specified file (if found) or NULL.
+ */
+PFILE
+FileNameToHandle (
+ char const *pName,
+ char const *pShortName
+ ) {
+
+ PFILE pFileTmp;
+
+ if (pName[0] == 0) {
+ return pFileHead;
+ }
+
+ for (pFileTmp = pFileHead; pFileTmp != NULL; pFileTmp = pFileTmp->pFileNext)
+ if (!_stricmp (pName, pFileTmp->pName))
+ return pFileTmp;
+
+ if ( pShortName != NULL ) {
+ for (pFileTmp = pFileHead; pFileTmp != NULL; pFileTmp = pFileTmp->pFileNext) {
+ REGISTER char *pFileName = pFileTmp->pName;
+ pathbuf nbuf;
+
+ if (filename (pFileName, nbuf) &&
+ !_stricmp (nbuf, pShortName)) {
+ return pFileTmp;
+ }
+ }
+ }
+ //for (pFileTmp = pFileHead; pFileTmp != NULL; pFileTmp = pFileTmp->pFileNext) {
+ //REGISTER char *pFileName = pFileTmp->pName;
+ //pathbuf nbuf;
+ //
+ //if (!stricmp (pName, pFileName) ||
+ // (pShortName != NULL &&
+ // filename (pFileName, nbuf) &&
+ // !stricmp (nbuf, pShortName))) {
+ // return pFileTmp;
+ // }
+ //}
+ return NULL;
+}
+
+
+
+/*** pFileToTop - make the specified file the top of the current window
+*
+* Search the instance list in the current window for the file. If it is
+* found, relink it to be the top one. Otherwise, allocate a new instance for
+* it and place it at the top of the instance list. Also bring the file to
+* the top of the pFileHead file list. Ensure that it is on the list to begin
+* with.
+*
+* Input:
+* pFileTmp = file to bring to top
+*
+* OutPut:
+* Returns FALSE if the pFile is invalid or NULL
+*
+*************************************************************************/
+flagType
+pFileToTop (
+ PFILE pFileTmp
+ ) {
+
+ EVTargs e;
+ PINS pInsLast = (PINS) &pInsCur;
+ PINS pInsTmp = pInsCur;
+ PFILE pFilePrev;
+
+ assert (_pfilechk());
+ assert (_pinschk(pInsCur));
+
+ /*
+ * if we're about to lose focus, declare it
+ */
+ if (pFileTmp != pFileHead) {
+ e.pfile = pFileHead;
+ DeclareEvent (EVT_LOSEFOCUS,(EVTargs *)&e);
+ }
+
+ /*
+ * Move file to head of file list. Ensure, at the same time, that the file
+ * is in fact ON the list, and declare the event if in fact it is moved.
+ */
+ if (pFileTmp != pFileHead) {
+ for (pFilePrev = pFileHead;
+ pFilePrev && (pFilePrev->pFileNext != pFileTmp);
+ pFilePrev = pFilePrev->pFileNext ) {
+ ;
+
+ }
+
+ if (!pFilePrev) {
+ return FALSE;
+ }
+
+ pFilePrev->pFileNext = pFileTmp->pFileNext;
+ pFileTmp->pFileNext = pFileHead;
+ pFileHead = pFileTmp;
+
+ e.pfile = pFileHead;
+ DeclareEvent (EVT_GETFOCUS,(EVTargs *)&e);
+ }
+
+ /*
+ * pFileTmp now points to a file structure for the correct file. Try to find
+ * an instance of the file in the current window. If not in the instance
+ * list, allocate it. If it is in the instance list, remove it.
+ */
+ while (pInsTmp != NULL) {
+ if (pInsTmp->pFile == pFileTmp) {
+ break;
+ }
+ pInsLast = pInsTmp;
+ pInsTmp = pInsTmp->pNext;
+ }
+
+ if (pInsTmp == NULL) {
+ pInsTmp = (PINS) ZEROMALLOC (sizeof (*pInsTmp));
+ pInsTmp->pFile = pFileTmp;
+#ifdef DEBUG
+ pInsTmp->id = ID_INSTANCE;
+#endif
+ IncFileRef (pFileTmp);
+ } else {
+ pInsLast->pNext = pInsTmp->pNext;
+ }
+ /*
+ * Regardless, then, of where it came from, place the new instance back onto
+ * the head of the list
+ */
+ pInsTmp->pNext = pInsCur;
+ WININST(pWinCur) = pInsCur = pInsTmp;
+
+ SETFLAG(fDisplay, RCURSOR | RSTATUS);
+ newscreen ();
+
+ return TRUE;
+
+}
+
+
+
+/* RemoveTop - removes the top file in the current instance list
+ * If there is no next file, leave
+ */
+void
+RemoveTop (
+ void
+ ) {
+ PINS pInsTmp = pInsCur;
+
+ WININST(pWinCur) = pInsCur = pInsCur->pNext;
+ FREE ((char *) pInsTmp);
+ DecFileRef (pFileHead);
+ if (pInsCur) {
+ pFileToTop (pInsCur->pFile);
+ }
+}
+
+
+
+
+/*** RemoveFile - free up all resources attached to a particular file
+*
+* Purpose:
+*
+* To free all memory used to keep track of a file. If the file still
+* appears in some instance lists, it is removed from them.
+*
+* Input:
+*
+* pFileRem - File in question
+*
+* Output:
+*
+* Returns TRUE.
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+void
+RemoveFile (
+ PFILE pFileRem
+ ) {
+
+ PFILE pFilePrev = (PFILE) &pFileHead;
+ PFILE pFileTmp = pFileHead;
+
+ if (pFileRem->refCount > 0) {
+ RemoveInstances (pFileRem);
+ }
+
+ while (pFileTmp != pFileRem) {
+ pFilePrev = pFileTmp;
+ pFileTmp = pFileTmp->pFileNext;
+ if (pFileTmp == NULL) {
+ IntError ("RemoveFile can't find file");
+ }
+ }
+
+
+ /*
+ * It's important that pFileNext be the first field in a pfile, and we assert
+ * that here. This allows us to not special case pFileHead, but adjust it by
+ * treating it as the pFileNext of a non-existant structure.
+ */
+ assert ((void *)&(pFilePrev->pFileNext) == (void *)pFilePrev);
+ pFilePrev->pFileNext = pFileTmp->pFileNext;
+
+ FreeFileVM (pFileTmp);
+
+ FREE (pFileTmp->pName);
+
+#if DEBUG
+ pFileTmp->id = 0;
+#endif
+
+ FREE ((char *) pFileTmp);
+
+ if (pFileTmp == pFileIni) {
+ pFileIni = NULL;
+ }
+}
+
+
+
+/*** RemoveInstances - Remove all instances of a file
+*
+* Purpose:
+*
+* Used by RemoveFile to make sure that there are no file instances
+* referring to a given file
+*
+* Input:
+* pFile = File in question
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void
+RemoveInstances (
+ PFILE pFile
+ ) {
+
+ PINS pIns;
+ PINS pInsPrev;
+ PWND pWndCur;
+
+ for (pWndCur = &WinList[0];
+ pWndCur < &WinList[cWin];
+ pWndCur++) {
+
+ pInsPrev = NULL;
+ pIns = WININST(pWndCur);
+ while (pIns) {
+
+ /*
+ * assert not an infinite loop
+ */
+ assert (!pInsPrev || (pIns != WININST (pWndCur)));
+
+ if (pIns->pFile == pFile) {
+ if (!pInsPrev) {
+ WININST (pWndCur) = pIns->pNext;
+ } else {
+ pInsPrev->pNext = pIns->pNext;
+ }
+ {
+ PINS pInsTmp = pIns;
+ pIns = pIns->pNext;
+ FREE(pInsTmp);
+ }
+ } else {
+ pInsPrev = pIns;
+ pIns = pIns->pNext;
+ }
+ }
+ assert (_pinschk (WININST (pWndCur)));
+ }
+ //
+ // If the resulting instance list for the current window becomes empty,
+ // bring up the <untitled> file in it.
+ //
+ if (!(pInsCur = WININST (pWinCur))) {
+ fChangeFile (FALSE, RGCHUNTITLED);
+ }
+}
+
+
+
+
+/* fSyncFile - Attempt to make logical file and physical file the same
+ *
+ * When editing in a network or multi-tasking environment, we need to make
+ * sure that changes made underneath us are properly reflected to the
+ * user. We do this by snapshotting the time-of-last-write and periodically
+ * comparing it with the version on disk. When a mismatch is found, we
+ * prompt the user and give him the opportunity to reread the file
+ *
+ * pFileLoc file structure of interest
+ * fPrompt TRUE => prompt user for permission to refresh, else just
+ * refresh.
+ *
+ * returns TRUE iff the logical file and the physical file are the same.
+ */
+flagType
+fSyncFile (
+ PFILE pFileLoc,
+ flagType fPrompt
+ ) {
+ if (pFileLoc == NULL) {
+ pFileLoc = pFileHead;
+ }
+
+ switch (FileStatus (pFileLoc, NULL)) {
+
+ case FILECHANGED:
+ if (fPrompt) {
+ if (!confirm ("%s has been changed. Refresh? ", pFileLoc->pName)) {
+ /* No, validate this edit session */
+ SetModTime (pFileLoc);
+ return FALSE;
+ }
+ }
+ FileRead (strcpy( buf, pFileLoc->pName ), pFileLoc, TRUE);
+ RSETFLAG (FLAGS (pFileLoc), DIRTY);
+ SETFLAG (fDisplay, RSTATUS);
+ return TRUE;
+
+ case FILEDELETED:
+ domessage ("File has been deleted");
+ break;
+
+ default:
+ break;
+
+ }
+ return TRUE;
+}
+
+
+
+
+/* FileStatus - compare logical info about a file with file on disk
+ *
+ * Compare the last modified time with the last snapshot. If the filename
+ * contains metachars, the file is not believed to have changed. Further, if
+ * the file is a pseudo file, it cannot have changed.
+ *
+ * pFile file of interest (contains mod time)
+ * pName name of file to examine (when writing to diff. name)
+ *
+ * returns FILECHANGED if timestamps differ
+ * FILEDELETED if file on disk does not exist
+ * FILESAME if timestamps are the same
+ */
+int
+FileStatus (
+ PFILE pFile,
+ char *pName
+ ){
+
+ long modtime;
+
+ if (TESTFLAG(FLAGS(pFile),FAKE)) {
+ return FILESAME;
+ }
+
+ if (pName == NULL) {
+ pName = pFile->pName;
+ }
+
+ if (*strbscan (pName, "?*") != 0) {
+ return FILESAME;
+ }
+
+ if ((modtime = ModTime (pName)) == 0L) {
+ return FILEDELETED;
+ }
+
+ if (pFile->modify != modtime) {
+ return FILECHANGED;
+ }
+
+ return FILESAME;
+}
+
+
+
+
+/* SetModTime - Snapshot a file's last-modification time
+ *
+ * pFile file of interest
+ */
+void
+SetModTime (
+ PFILE pFile
+ ) {
+ pFile->modify = ModTime (pFile->pName);
+}
+
+
+
+/* ModTime - Return the time of last modification for a file
+ *
+ * If the file does not exist or contains meta chars, return 0 as the time-
+ * stamp.
+ *
+ * pName character pointer to file name
+ *
+ * Returns last modification time of file.
+ */
+
+time_t
+ModTime (
+ char *pName
+ ) {
+
+ struct _stat statbuf;
+
+ if (*strbscan (pName, "?*")) {
+ return 0L;
+ }
+
+ if (_stat (pName, &statbuf) == -1) {
+ return 0L;
+ }
+
+ return statbuf.st_mtime;
+
+}
diff --git a/private/utils/mep/src/fileio.c b/private/utils/mep/src/fileio.c
new file mode 100644
index 000000000..551ff2041
--- /dev/null
+++ b/private/utils/mep/src/fileio.c
@@ -0,0 +1,1497 @@
+/*** fileio.c - perform low-level file input and output
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+*
+* 26-Nov-1991 mz Strip off near/far
+*************************************************************************/
+#include "mep.h"
+
+#include <rm.h>
+
+int fdeleteFile( char *p );
+
+/* Large-buffer I/O routines
+ *
+ * It is best for Z to read in data in large blocks. The fewer times we
+ * issue system calls, the better. The VM code has conveniently allocated
+ * us some large amount of space for us. All we need to do is maintain
+ * a pointer to the next characters to read/write and a count of the number
+ * of characters in the buffer
+ *
+ * The data structures used are:
+ *
+ * char *getlbuf;
+ * This is a long pointer to the beginning of the buffer.
+ * char *getlptr;
+ * This is a long pointer to the next char position in the buffer.
+ * unsigned int getlsize;
+ * This is the length of the buffer in bytes.
+ *
+ * The routines provided to access this are:
+ *
+ * zputsinit ();
+ * Initializes for subsequent zputs's.
+ * zputs (buf, len, fh);
+ * Writes out from buf length len using getlbuf and fh.
+ * Returns EOF if no more room.
+ * zputsflush (fh);
+ * Flushes out the buffer. Returns EOF if no more room.
+ */
+
+char *getlbuf = NULL;
+char *getlptr = NULL;
+// unsigned int getlsize = 0;
+unsigned int getlc = 0;
+
+// BUGBUG
+// FileExists is used because of problems with stat() and
+// FindFirstFile() which are not easily reproducible.
+flagType FileExists (char *path );
+
+// BUGBUG
+// MepMove is used because FAT does not provide rename functionality
+#define rename MepMove
+int MepMove ( char *oldname, char *newname);
+
+
+
+/* zputsinit - initialize for future zputs's
+ *
+ * Set next-char pointer to beginning. Set count of chars to 0
+ */
+void
+zputsinit (
+ void
+ )
+{
+ getlptr = getlbuf;
+ getlc = 0;
+}
+
+
+
+
+
+/*** zputs - output a string
+*
+* Input:
+* p = character pointer to data to be output
+* len = number of bytes to output
+* fh = DOS file handle to use
+*
+* Output:
+* Returns EOF if out-of-space
+*
+*************************************************************************/
+int
+zputs (
+ char *p,
+ int len,
+ FILEHANDLE fh
+ )
+{
+ REGISTER unsigned int c;
+
+ while (len != 0) {
+ c = len;
+ if (c > (unsigned)(getlsize-getlc)) {
+ c = (unsigned)(getlsize-getlc);
+ }
+ memmove (getlptr, (char*)p, c);
+ len -= c;
+ getlptr += c;
+ getlc += c;
+ p += c;
+ if (getlc == getlsize) {
+ if (zputsflush (fh) == EOF) {
+ return EOF;
+ }
+ }
+ }
+ return !EOF;
+}
+
+
+
+
+
+/*** zputsflush - dump out buffered data
+*
+* Input:
+* fh = DOS file handle to use for output
+*
+* Output:
+* Returns EOF if disk full
+*
+*************************************************************************/
+int
+zputsflush (
+ FILEHANDLE fh
+ )
+{
+
+ ULONG bytesWritten;
+
+ // rjsa DosWrite (fh, getlbuf, getlc, &bytesWritten);
+ bytesWritten = MepFWrite(getlbuf, getlc, fh);
+ if (bytesWritten != getlc) {
+ return EOF;
+ }
+ zputsinit ();
+ return !EOF;
+}
+
+
+
+
+
+/* ReestimateLength - reestimate the length of a file based on
+ * the current file position and length in bytes
+ */
+void
+ReestimateLength (
+ PFILE pFile,
+ FILEHANDLE fh,
+ long len
+ )
+{
+ LINE avg;
+
+ if (pFile->cLines == 0) {
+ avg = 400;
+ } else {
+ avg = (MepFSeek (fh, 0L, FROM_CURRENT) - getlc) / pFile->cLines;
+ avg = len / avg;
+ }
+
+ growline (avg + 1, pFile);
+}
+
+
+
+
+
+/* read lines from the specified handle.
+ */
+LINE
+readlines (
+ PFILE pFile,
+ FILEHANDLE fh
+ )
+{
+ LINE line = 0; /* line number being read in */
+ long bufpos = 0L; /* position of beg of buffer in file */
+ unsigned int buflen = 0; /* number of bytes of data in buffer */
+ long cbFile; // length of file
+ char *pb;
+
+
+ cbFile = MepFSeek(fh, 0L, FROM_END);
+
+ MepFSeek (fh, 0L, FROM_BEGIN);
+
+ pFile->pbFile = MALLOC (cbFile);
+
+ if ( pFile->pbFile == NULL ) {
+ //
+ // No heap space, cannot read file
+ //
+ disperr (MSGERR_NOMEM);
+ return -1;
+ }
+
+ // Assume a non-dos file until we see a CR-LF.
+ RSETFLAG (FLAGS (pFile), DOSFILE);
+
+ // Read entire file into buffer and set up for scan
+ buflen = MepFRead (pFile->pbFile, cbFile, fh);
+ pb = pFile->pbFile;
+
+ // Loop, while there's more data to parse
+ while (buflen != 0) {
+ LINEREC vLine; // line record of current line
+ REGISTER int iCharPos = 0; // logical line length (tabs expanded)
+
+ vLine.cbLine = 0;
+ vLine.vaLine = (PVOID)pb;
+ vLine.Malloced = FALSE;
+
+ // Loop, processing each character in the line
+ //
+ // Special char handling is as follows:
+ // 0. Lines are broken at end of input
+ // 1. Lines are broken when they overflow line buffers
+ // 2. Lines are broken at \n's or \r\n's.
+ // 3. Lines are broken at \0's since the editor relies on asciiz
+ // 4. Embedded \r's are retained.
+
+ while (TRUE) {
+ int c; // char being processed
+
+ // if no more data, break current line.
+ if (buflen == 0)
+ break;
+
+ // if \n or \0 then eat it and break current line
+ if (pb[0] == '\n' || pb[0] == '\0') {
+ pb++;
+ buflen--;
+ break;
+ }
+
+ // if \r\n then eat them and break current line
+ if (pb[0] == '\r' && buflen > 1 && pb[1] == '\n') {
+ pb += 2;
+ buflen -= 2;
+ SETFLAG (FLAGS (pFile), DOSFILE);
+ break;
+ }
+
+ // if no more room to expand in a buffer, break current line
+ if (iCharPos >= sizeof (linebuf)-1)
+ break;
+
+ // Get current character
+ c = *pb++;
+ buflen--;
+
+ // We have a character that we allow in the
+ // line. Advance length of logical line.
+ if (c != 0x09)
+ iCharPos++;
+ else {
+ // Expand a tab to the next logical position
+ iCharPos += 8 - (iCharPos & 7);
+
+ // if the tab causes overflow in the line length
+ // back up over the tab and break the line
+ if (iCharPos >= sizeof(linebuf)-1) {
+ pb--;
+ buflen++;
+ break;
+ }
+ }
+
+ // Advance length of physical line
+ vLine.cbLine++;
+ }
+
+ // If the user halted reading the file in, undo everything
+ if (fCtrlc) {
+ FlushInput ();
+ DelFile (pFile, FALSE);
+ return -1;
+ }
+
+ // Give the user feedback about our progress
+ noise (line);
+
+ // If we're within 10 lines of the end of the line array then
+ if (line >= pFile->lSize-10) {
+ LINE avg;
+ // reestimate the number of lines
+
+ if (pFile->cLines == 0)
+ // Assume 400 lines if the file is now empty
+ avg = 400;
+ else {
+ // compute average line length so far
+ avg = (pb - pFile->pbFile) / pFile->cLines;
+
+ // extrapolate number of lines in entire file from this
+ // average
+ avg = cbFile / avg;
+ }
+ growline (avg + 1, pFile);
+ }
+
+ if (pFile->cLines <= line) {
+ growline (line+1, pFile);
+ pFile->cLines = line+1;
+ }
+
+ pFile->plr[line++] = vLine;
+ }
+
+ if (line == 0)
+ SETFLAG (FLAGS (pFile), DOSFILE);
+
+ RSETFLAG (FLAGS(pFile), DIRTY);
+ newscreen ();
+ return line;
+}
+
+
+
+
+
+/*** FileRead - read in a file
+*
+* The file structure is all set up; all that needs to be done is to fill in
+* the lines parts. We delete everything currently in the file. If the file
+* is designated as a pseudo file (first char is a <), then we go and check
+* for the specially named files. Otherwise we try to read in the file. If
+* that fails, and we can, we try to create it. If everything fails, we
+* return FALSE.
+*
+* Input:
+* name = pointer to file name to read
+* pFile = file structure to read the file into.
+* fAsk = TRUE -> ask to create if it doesn't exist
+*
+* Output:
+* Returns TRUE on read in.
+* Modifies global fUserCanceledRead
+*
+* Notes:
+* Hack (terrible one): Under CW, FileRead sets fUserCanceledRead anytime
+* there has been an attempt to read a non existent file AND the user
+* has been prompted for file creation AND the user canceled the operation
+*
+* This is used by fFileAdvance (ZEXIT.C) and ReadStateFile (STATFILE.C)
+*
+*************************************************************************/
+flagType
+FileRead (
+ char *name,
+ PFILE pFile,
+ flagType fAsk
+ )
+{
+
+ EVTargs e;
+ FILEHANDLE fh;
+ flagType fNew = FALSE;
+ char *n;
+ buffer Buf;
+
+ assert (pFile);
+
+
+ e.pfile = pFile;
+ e.arg.pfn = (char *)name;
+ if (DeclareEvent (EVT_FILEREADSTART, (EVTargs *)&e)) {
+ return TRUE;
+ }
+
+ if (!mtest ()) {
+ dispmsg (MSG_NEXTFILE, name);
+ }
+
+ /* process special names */
+ if (*name == '<') {
+ fNew = LoadFake (name, pFile);
+ DeclareEvent (EVT_FILEREADEND, (EVTargs *)&e);
+ return fNew;
+ }
+
+ DelFile (pFile, FALSE);
+
+ if (*strbscan (name, "?*") != 0) {
+ fNew = LoadDirectory (name, pFile);
+ DeclareEvent (EVT_FILEREADEND, (EVTargs *)&e);
+ return fNew;
+ }
+
+ if ((fh = MepFOpen (name, ACCESSMODE_READ, SHAREMODE_RW, FALSE)) == NULL) {
+ if (!fAsk) {
+ DeclareEvent (EVT_FILEREADEND, (EVTargs *)&e);
+ return FALSE;
+ }
+ if (!confirm ("%s does not exist. Create? ", name)) {
+ DeclareEvent (EVT_FILEREADEND, (EVTargs *)&e);
+ return FALSE;
+ }
+ if ((fh = MepFOpen (name, ACCESSMODE_WRITE, SHAREMODE_RW, TRUE)) == NULL) {
+ n = name;
+ if ( strlen(name) > 20 ) {
+ strcpy( Buf, name + strlen(name)-20);
+ Buf[0] = Buf[1] = Buf[2] = '.';
+ n = Buf;
+ }
+ disperr (MSGERR_NOCREAT, n, error ());
+ DeclareEvent (EVT_FILEREADEND, (EVTargs *)&e);
+ return FALSE;
+ }
+ SETFLAG (FLAGS (pFile), NEW);
+ fNew = TRUE;
+ }
+
+ if (fNew) {
+ PutLine((LINE)0, RGCHEMPTY, pFile);
+ SETFLAG (FLAGS (pFile), DOSFILE);
+ } else if (readlines (pFile, fh) == -1) {
+ DoCancel();
+ MepFClose (fh);
+ DeclareEvent (EVT_FILEREADEND, (EVTargs *)&e);
+ return FALSE;
+ }
+
+ MepFClose (fh);
+ SETFLAG (FLAGS(pFile), REAL);
+ RSETFLAG (FLAGS(pFile), READONLY);
+
+ if (fReadOnly (name)) {
+ SETFLAG (FLAGS(pFile), DISKRO);
+ if (!fEditRO) {
+ SETFLAG (FLAGS(pFile), READONLY);
+ }
+ } else {
+ RSETFLAG (FLAGS(pFile), DISKRO);
+ }
+
+ SetModTime (pFile);
+ CreateUndoList (pFile);
+ (void)fReadMarks (pFile);
+
+ DeclareEvent (EVT_FILEREADEND, (EVTargs *)&e);
+
+ return TRUE;
+}
+
+
+
+
+
+/* fReadOnly - see if a file is read-only
+ *
+ * p full name of file
+ *
+ * Returns: TRUE iff file is read only
+ */
+flagType
+fReadOnly (
+ char *p
+ )
+{
+
+ DWORD Attr;
+
+ Attr = GetFileAttributes(p);
+
+ if ( Attr != -1 && (Attr & FILE_ATTRIBUTE_READONLY) != 0)
+ return TRUE;
+ else
+ return FALSE;
+}
+
+
+int
+ZFormatArgs (REGISTER char * Buf, const char * Format, ...)
+{
+ va_list arglist;
+ int result;
+
+ va_start (arglist, Format);
+ result = ZFormat (Buf, Format, arglist);
+ va_end (arglist);
+ return result;
+}
+
+/*** FileWrite - Write file to disk
+*
+* Writes out the specified file. If no name was given then use the name
+* originally assigned to the file; else use the given name. We start by
+* writing to a temp file (extention .$). If this succeeds, we fdelete the
+* source (for undeleteability) and rename the temp to the source.
+*
+* Input:
+* savename = name to save as.
+* pFile = file to be saved
+*
+* Returns:
+*
+*************************************************************************/
+flagType
+FileWrite (
+ char *savename,
+ PFILE pFile
+ )
+{
+
+ EVTargs e;
+ FILEHANDLE fh; /* file handle for output */
+ LINE i;
+ int len, blcnt;
+ pathbuf fullname, tmpname;
+ char linebuffer[sizeof(linebuf) + 2];
+ char *p;
+ PCMD pCmd;
+ flagType fNewName = FALSE;
+ char *fileEOL;
+ int cbfileEOL;
+
+ //
+ // If we are trying to save a FAKE file with a <name>,
+ // we call SaveFake for special processing.
+ //
+
+ if (TESTFLAG (FLAGS(pFile), FAKE) && !savename &&
+ (pFile->pName[0] == '\0' || pFile->pName[0] == '<')) {
+ return SaveFake (pFile->pName, pFile);
+ }
+
+ //if (TESTFLAG (FLAGS(pFile), FAKE) && savename &&
+ //(savename[0] == '\0' || savename[0] == '<'))
+ // return SaveFake (savename, pFile);
+
+ //
+ // get a canonical form of the output file name. If no name was
+ // input, use the name in the file itself
+ //
+
+ if (!savename || !*savename) {
+ strcpy (fullname, pFile->pName);
+ } else if (rootpath (savename, fullname)) {
+ return disperr (MSGERR_OPEN, savename, "");
+ }
+
+ savename = fullname;
+
+ //
+ // See if it is a directory. If so, we cannot save to it.
+ //
+
+ {
+ DWORD att = GetFileAttributes (fullname);
+
+ if (att != -1 && TESTFLAG (att, FILE_ATTRIBUTE_DIRECTORY))
+ return disperr (MSGERR_SAVEDIR, fullname);
+ }
+
+ //
+ // If the file is read-only, display a message and let the user direct
+ // us to use the readonly program to rectify it.
+ //
+
+ if (fReadOnly (fullname)) {
+ disperr (MSGERR_RONLY, fullname);
+ if (ronlypgm != NULL) {
+ if (strstr (ronlypgm, "%s") != NULL) {
+ fileext (fullname, buf);
+ sprintf (tmpname, ronlypgm, buf);
+ }
+ else
+ ZFormatArgs (tmpname, ronlypgm, fullname);
+ if (confirm("Invoke: \"%s\" (y/n)?", tmpname))
+ if (zspawnp (tmpname, TRUE))
+ SetModTime (pFile);
+ }
+
+ //
+ // We've given the user one chance to fix the read-onlyness of the
+ // file. We now prompt him until he gives us a writeable name or
+ // cancels.
+ //
+ if ( !savename || !*savename ) {
+ strcpy( tmpname, pFile->pName );
+ } else {
+ strcpy( tmpname, savename );
+ }
+ //tmpname[0] = '\0';
+ while (fReadOnly (fullname)) {
+
+ pCmd = getstring (tmpname, "New file name: ", NULL,
+ GS_NEWLINE | GS_INITIAL | GS_KEYBOARD);
+
+ if ( pCmd == NULL || (PVOID)pCmd->func == (PVOID)cancel)
+ return FALSE;
+
+ CanonFilename (tmpname, fullname);
+
+ if (!TESTFLAG(FLAGS(pFile), FAKE))
+ fNewName = TRUE;
+ }
+ }
+
+ //
+ // fullname is the name of the file we are writing
+ //
+
+ upd (fullname, ".$", tmpname);
+
+ //
+ // Send notification about the beginning of the write operation
+ //
+
+ e.pfile = pFile;
+ e.arg.pfn = (char *)savename;
+ if (DeclareEvent (EVT_FILEWRITESTART, (EVTargs *)&e))
+ return TRUE;
+
+
+ if (!(fh = MepFOpen(tmpname, ACCESSMODE_RW, SHAREMODE_READ, FALSE))) {
+ if (!(fh = MepFOpen(tmpname, ACCESSMODE_RW, SHAREMODE_READ, TRUE))) {
+ disperr (MSGERR_OPEN, tmpname, error ());
+ DeclareEvent (EVT_FILEWRITEEND, (EVTargs *)&e);
+ return FALSE;
+ }
+ }
+
+ dispmsg (MSG_SAVING, fullname);
+ blcnt = 0;
+ zputsinit ();
+ fileEOL = TESTFLAG (FLAGS (pFile), DOSFILE) ? "\r\n" : "\n";
+ cbfileEOL = strlen (fileEOL);
+
+ for (i = 0; i < pFile->cLines; i++) {
+
+ /*
+ * always get the RAW line for output. No tab conversions here.
+ */
+
+ len = gettextline (TRUE, i, linebuffer, pFile, ' ');
+
+ if (!mtest ()) {
+ noise (i);
+ }
+
+ if (fCtrlc) {
+ DoCancel();
+ MepFClose (fh);
+ _unlink (tmpname);
+ DeclareEvent (EVT_FILEWRITEEND, (EVTargs *)&e);
+ return FALSE;
+ }
+
+ if (len) {
+ while (blcnt--) {
+ if (zputs (fileEOL, cbfileEOL, fh) == EOF) {
+ if (!fCtrlc) {
+ disperr (MSGERR_SPACE, tmpname);
+ } else {
+ FlushInput ();
+ }
+ MepFClose (fh);
+ _unlink (tmpname);
+ DeclareEvent (EVT_FILEWRITEEND, (EVTargs *)&e);
+ return FALSE;
+ }
+ }
+ blcnt = 0;
+ if (zputs (linebuffer, len, fh) == EOF ||
+ zputs (fileEOL, cbfileEOL, fh) == EOF) {
+
+ if (!fCtrlc)
+ disperr (MSGERR_SPACE, tmpname);
+ else
+ FlushInput ();
+ MepFClose (fh);
+ _unlink (tmpname);
+ DeclareEvent (EVT_FILEWRITEEND, (EVTargs *)&e);
+ return FALSE;
+ }
+ } else {
+ blcnt++;
+ }
+ }
+
+ if (zputsflush (fh) == EOF) {
+
+ if (!fCtrlc) {
+ disperr (MSGERR_SPACE, tmpname);
+ } else {
+ FlushInput ();
+ }
+
+ MepFClose (fh);
+ _unlink (tmpname);
+ DeclareEvent (EVT_FILEWRITEEND, (EVTargs *)&e);
+ return FALSE;
+ }
+
+ MepFClose (fh);
+
+ /* fullname NAME.EXT
+ * tmpname NAME.$
+ * buf temp buffer
+ */
+ rootpath (fullname, buf);
+ strcpy (fullname, buf);
+
+ /* fullname full NAME.EXT
+ * tmpname NAME.$
+ * buf temp buffer
+ */
+ if (!_strcmpi (fullname, pFile->pName) && TESTFLAG (FLAGS (pFile), NEW)) {
+ if (_unlink (fullname) == -1) {
+ fileext (fullname, fullname);
+ disperr (MSGERR_DEL, fullname, error ());
+ _unlink (tmpname);
+ DeclareEvent (EVT_FILEWRITEEND, (EVTargs *)&e);
+ return FALSE;
+ }
+ }
+ else {
+ switch (backupType) {
+
+ case B_BAK:
+ upd (fullname, ".bak", linebuffer);
+ /* foo.bar => foo.bak */
+ if (_unlink (linebuffer) == -1) {
+ p = error ();
+ if (FileExists(linebuffer)) {
+ fileext (linebuffer, linebuffer);
+ disperr (MSGERR_DEL, linebuffer, p);
+ _unlink (tmpname);
+ DeclareEvent (EVT_FILEWRITEEND, (EVTargs *)&e);
+ return FALSE;
+ }
+ }
+ if (rename (fullname, linebuffer) == -1) {
+ p = error ();
+ if (FileExists(fullname)) {
+ disperr (MSGERR_REN, fullname, linebuffer, p);
+ _unlink (tmpname);
+ DeclareEvent (EVT_FILEWRITEEND, (EVTargs *)&e);
+ return FALSE;
+ }
+ }
+ break;
+
+ case B_UNDEL:
+ /* remove foo.bar */
+ i = fdeleteFile (fullname);
+ if (i && i != 1) {
+ _unlink (tmpname);
+ DeclareEvent (EVT_FILEWRITEEND, (EVTargs *)&e);
+ return disperr (MSGERR_OLDVER, fullname);
+ }
+
+ case B_NONE:
+ if (_unlink (fullname) == -1) {
+ p = error ();
+ if (FileExists(fullname)) {
+ _unlink (tmpname);
+ DeclareEvent (EVT_FILEWRITEEND, (EVTargs *)&e);
+ fileext (fullname, fullname);
+ return disperr (MSGERR_DEL, fullname, p);
+ }
+ }
+ }
+ }
+
+ if (rename (tmpname, fullname) == -1) {
+ disperr (MSGERR_REN, tmpname, fullname, error ());
+ _unlink (tmpname);
+ DeclareEvent (EVT_FILEWRITEEND, (EVTargs *)&e);
+ return FALSE;
+ }
+
+ RSETFLAG (FLAGS (pFile), NEW);
+
+ if (!_strcmpi (savename, pFile->pName) || fNewName) {
+ if (fNewName) {
+ /*
+ * We gave a new name to this file and successfully saved it:
+ * this becomes the new file's name
+ */
+ FREE (pFile->pName);
+ pFile->pName = ZMakeStr (fullname);
+ }
+ RSETFLAG (FLAGS(pFile), (DIRTY | DISKRO));
+ SETFLAG (fDisplay,RSTATUS);
+ SetModTime( pFile );
+ }
+
+ WriteMarks (pFile);
+ DeclareEvent (EVT_FILEWRITEEND, (EVTargs *)&e);
+
+ return TRUE;
+}
+
+
+
+
+/* fdeleteFile - Remove file the way RM does it - checks for undelcount
+ *
+ * This code is extracted from Ztools. the only difference being that this
+ * checks for undelcount so our deleted stuff don't grow without bounds
+ *
+ * The delete operation is performed by indexing the file name in a separate
+ * directory and then renaming the selected file into that directory.
+ *
+ * Returns:
+ *
+ * 0 if fdelete was successful
+ * 1 if the source file did not exist
+ * 2 if the source was read-only or if the rename failed
+ * 3 if the index was not accessable
+ */
+int
+fdeleteFile(
+ char *p
+ )
+{
+ char dir[MAXPATHLEN]; /* deleted directory */
+ char idx[MAXPATHLEN]; /* deleted index */
+ char szRec[MAXPATHLEN]; /* deletion entry in index */
+ char recbuf[MAXPATHLEN];
+ int attr, fhidx;
+ int errc;
+ int count,c;
+
+ fhidx = -1;
+
+ //
+ // See if the file exists
+ //
+ if( ( attr = GetFileAttributes( p ) ) == -1) {
+ errc = 1;
+ goto Cleanup;
+ }
+
+ //
+ // What about read-only files?
+ //
+ if (TESTFLAG (attr, FILE_ATTRIBUTE_READONLY)) {
+ errc = 2;
+ goto Cleanup;
+ }
+
+ //
+ // Form an attractive version of the name
+ //
+ pname (p);
+
+ //
+ // generate deleted directory name, using defaults from input file
+ //
+ upd (p, RM_DIR, dir);
+
+ //
+ // Generate index name
+ //
+ strcpy (idx, dir);
+ pathcat (idx, RM_IDX);
+
+ //
+ // make sure directory exists (reasonably)
+ //
+ if( _mkdir (dir) == 0 ) {
+ SetFileAttributes(dir, FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM);
+ }
+
+ //
+ // extract filename/extention of file being deleted
+ //
+ fileext (p, szRec);
+
+ //
+ // try to open or create the index
+ //
+ if ((fhidx = _open (idx, O_CREAT | O_RDWR | O_BINARY,
+ S_IWRITE | S_IREAD)) == -1) {
+ errc = 3;
+ goto Cleanup;
+ }
+
+ if (!convertIdxFile (fhidx, dir)) {
+ errc = 3;
+ goto Cleanup;
+ }
+
+ //
+ // scan the index and count how many copies of this file already exist
+ //
+ for (count=c=0; readNewIdxRec( fhidx, recbuf, c++ ); ) {
+ if ( !strcmp( szRec, recbuf )) {
+ count++;
+ }
+ }
+
+ if (count < cUndelCount) {
+
+ //
+ // Determine new name
+ //
+ sprintf (strend (dir), "\\deleted.%03x",
+ _lseek (fhidx, 0L, SEEK_END) / RM_RECLEN);
+
+ //
+ // Move the file into the directory
+ //
+ _unlink (dir);
+
+ if (rename(p, dir) == -1) {
+ errc = 2;
+ goto Cleanup;
+ }
+
+ //
+ // Index the file
+ //
+ if (!writeNewIdxRec (fhidx, szRec)) {
+ rename( dir, p );
+ errc = 2;
+ goto Cleanup;
+ }
+ } else {
+
+ char buf1[MAXPATHLEN], buf2[MAXPATHLEN], *p1;
+
+ strcpy (buf1, dir);
+ strcat (buf1, "\\deleted.");
+ p1 = strend (buf1);
+ *buf2 = 0;
+
+ _lseek( fhidx, 0L, SEEK_SET );
+
+ for ( count=c=0; readNewIdxRec( fhidx, recbuf, c++ ); count++ ) {
+ if (!strcmp ( szRec, recbuf)) {
+ sprintf (p1, "%03x", count);
+ if (! *buf2) {
+ _unlink (buf1);
+ } else {
+ rename (buf1, buf2);
+ }
+ strcpy (buf2, buf1);
+ }
+ }
+ rename (p, buf2);
+ }
+
+ errc = 0;
+
+Cleanup:
+ if ( fhidx != -1 ) {
+ _close(fhidx);
+ }
+
+ return errc;
+}
+
+
+
+
+/* SetBackup - assign the mode of file backup
+ *
+ * This is called during initialization to set the backup type
+ *
+ * val char pointer to "undel", "none", "bak"
+ *
+ * If any errors are found, SetBackup will return FALSE otherwise it returns
+ * TRUE.
+ */
+char *
+SetBackup (
+ char *val
+ )
+{
+ buffer bufLocal;
+
+ strcpy ((char *) bufLocal, val);
+ _strlwr (bufLocal);
+
+ if (!strcmp (bufLocal, "undel")) {
+ backupType = B_UNDEL;
+ } else if (!strcmp (bufLocal, "bak")) {
+ backupType = B_BAK;
+ } else if (!strcmp (bufLocal, "none")) {
+ backupType = B_NONE;
+ } else {
+ return "Backup type must be one of 'undel', 'bak or 'none'";
+ }
+
+ return NULL;
+}
+
+
+
+
+
+/* SetFileTab - set the spacing of tab characters in the file
+ *
+ * This is called during initialization to set the number of spaces per
+ * file tab character for output display. This is for brain-dead people
+ * who presume that 0x09 is not on 8-character boundaries. The legal
+ * range for this value is 1-8.
+ *
+ * val char pointer to remainder of assignment
+ *
+ * If any errors are found, SetFileTab will return FALSE, otherwise it returns
+ * TRUE.
+ */
+char *
+SetFileTab (
+ char *val
+ )
+{
+ int i;
+ buffer tmpval;
+
+ strcpy ((char *) tmpval, val);
+
+ i = atoi (tmpval);
+
+ if (i < 1 || i > 8) {
+ return "filetab: Value must be between 1 and 8";
+ }
+
+ fileTab = i;
+ newscreen ();
+ return NULL;
+}
+
+
+
+
+
+/* SetROnly - set the read-only program
+ *
+ * This is called during initialization to set the program called when
+ * trying to write a read-only program.
+ *
+ * val char pointer to remainder of assignment
+ *
+ * If any errors are found, SetROnly will return FALSE, otherwise it returns
+ * TRUE.
+ */
+flagType
+SetROnly (
+ char *pCmd
+ )
+{
+
+ if (ronlypgm != NULL)
+ FREE (ronlypgm);
+
+ if (strlen (pCmd) != 0)
+ ronlypgm = ZMakeStr (pCmd);
+ else
+ ronlypgm = NULL;
+
+ return TRUE;
+}
+
+
+
+
+
+/* SortedFileInsert - take the passed in line and insert it into the file
+ *
+ * pFile file for insertion
+ * pStr pointer to string
+ */
+void
+SortedFileInsert (
+ PFILE pFile,
+ char *pStr
+ )
+{
+ linebuf buf;
+ LINE hi, lo, mid;
+ int d;
+
+ hi = pFile->cLines-1;
+ lo = 0;
+
+ while (lo <= hi) {
+ mid = (hi + lo) / 2;
+ GetLine (mid, buf, pFile);
+ d = strcmp (pStr, buf);
+ if (d < 0) {
+ hi = mid - 1;
+ } else if (d == 0) {
+ return;
+ } else {
+ lo = mid + 1;
+ }
+ }
+
+ /* lo is the line # for insertion
+ */
+ InsertLine (lo, pStr, pFile);
+}
+
+
+
+
+
+struct ldarg {
+ PFILE pFile;
+ int linelen;
+ };
+
+
+/* LoadDirectoryProc - take enumerated file and place into file
+ *
+ * szFile pointer to file name to place into file
+ * pfbuf pointer to find buffer
+ * pData pointer to data for insertion
+ */
+void
+LoadDirectoryProc (
+ char * szFile,
+ struct findType *pfbuf,
+ void *pData
+ )
+{
+ struct ldarg *pldarg = (struct ldarg *)pData;
+
+ pldarg->linelen = max (pldarg->linelen, (int)strlen(szFile));
+ SortedFileInsert (pldarg->pFile, szFile);
+
+ pfbuf;
+}
+
+
+
+
+
+/* LoadDirectory - load the matching contents of the name into a fake file.
+ *
+ * name matching pattern for files
+ *
+ * Returns: TRUE always
+ */
+
+static char szNoMatchingFiles[] = "No matching files";
+
+flagType
+LoadDirectory (
+ char *fname,
+ PFILE pFile
+ )
+{
+ struct ldarg ldarg;
+
+ ldarg.linelen = 0;
+ ldarg.pFile = pFile;
+
+ /* Make sure undo believes that this file is fake.
+ */
+ SETFLAG (FLAGS(pFile), FAKE + REAL);
+
+ /* We walk the matching files, entering the names into the file one at
+ * a time in sorted order and, at the same time, determine the max string
+ * length.
+ * We then use CopyBox to collapse the file.
+ */
+
+ /* Enumerate all lines into file
+ */
+ forfile ((char *)fname, A_ALL, LoadDirectoryProc, &ldarg);
+
+ /* If file is empty, note it
+ */
+ if (pFile->cLines == 0) {
+ AppFile (szNoMatchingFiles, pFile);
+ } else {
+
+ /* File is pFile->cLines long with a max line len of
+ * ldarg.linelen. Since we are gathering the thing in columns
+ * we will have pwinCur->xSize / (ldarg.linelen + 2) columns, each of
+ * which will have pFile->cLines / # cols lines.
+ */
+ int ccol;
+ LINE cline, i;
+
+ ccol = max (WINXSIZE(pWinCur) / (ldarg.linelen + 2), 1);
+ cline = (pFile->cLines + ccol - 1) / ccol;
+ ldarg.linelen = WINXSIZE(pWinCur) / ccol;
+
+ /* Now, for each of the columns, copy them into position. Remember
+ * that one column is ALREADY in position.
+ */
+ for (i = 1; i < ccol; i++) {
+ /* copy lines cline..2*cline - 1
+ * columns 0..ldarg.linelen to
+ * line 0, column ldarg.linelen*i
+ */
+ CopyBox (pFile, pFile, 0, cline,
+ ldarg.linelen-1, 2 * cline - 1,
+ ldarg.linelen * (int) i, (LINE)0);
+ DelLine (TRUE, pFile, cline, 2 * cline - 1);
+ }
+ }
+ RSETFLAG (FLAGS(pFile), DIRTY);
+ return TRUE;
+}
+
+
+
+
+
+/* LoadFake - load a fake or pseudo file into memory. Fake files are used
+ * for two purposes: as temporary buffers or for information displays.
+ *
+ * name name of pseudo file
+ *
+ * Returns: TRUE always.
+ */
+flagType
+LoadFake (
+ char *name,
+ PFILE pFile
+ )
+{
+ SETFLAG (FLAGS(pFile), FAKE | REAL | REFRESH | DOSFILE);
+ if (!strcmp (name, rgchInfFile)) {
+ showinf (pFile);
+ } else if (!strcmp (name, rgchAssign)) {
+ showasg (pFile);
+ } else if (!strcmp (name, "<environment>")) {
+ showenv (pFile);
+ } else {
+ RSETFLAG (FLAGS(pFile), REFRESH);
+ }
+ return TRUE;
+}
+
+
+
+
+/*** SaveFake - "Save" a pseudo-file. Meaning depends on file
+*
+* Purpose:
+*
+* In some cases, "saving" a pseudo-file means something. Currently
+* we have:
+*
+* <assign> - Update changed lines to TOOLS.INI.
+*
+* Input:
+* savename -
+* pFile -
+*
+* Output:
+*
+* Returns TRUE if file was saved, FALSE if not
+*
+*************************************************************************/
+flagType
+SaveFake (
+ char * savename,
+ PFILE pFile
+ )
+{
+ struct lineAttr rnBuf[10];
+ LINE l;
+
+ if (!_stricmp (pFile->pName, rgchAssign)) {
+ for (l = 0; l < pFile->cLines; l++) {
+ if (GetColor (l, rnBuf, pFile)) {
+ GetLine (l, buf, pFile);
+ UpdToolsIni (buf);
+ DelColor (l, pFile);
+ redraw (pFile, l, l);
+ }
+ }
+ } else {
+ return FALSE;
+ }
+
+ return TRUE;
+
+ savename;
+}
+
+
+
+
+
+/*** SaveAllFiles - Find all dirty files and save them to disk
+*
+* Purpose:
+*
+* To save all dirty files, of course.
+*
+* Input:
+*
+* Output:
+*
+* Returns
+*
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+void
+SaveAllFiles (
+ void
+ )
+{
+ PFILE pFile;
+ int i;
+
+ i = 0;
+ for (pFile = pFileHead; pFile; pFile = pFile->pFileNext) {
+ if ((FLAGS(pFile) & (DIRTY | FAKE)) == DIRTY) {
+ FileWrite (NULL, pFile);
+ i++;
+ }
+ }
+
+ domessage ("Save %d files", i);
+
+}
+
+
+
+
+FILEHANDLE
+MepFOpen (
+ LPBYTE FileName,
+ ACCESSMODE Access,
+ SHAREMODE Share,
+ BOOL fCreate
+ )
+{
+ FILEHANDLE Handle;
+
+ Handle = CreateFile(FileName, Access, Share, NULL, OPEN_EXISTING, 0, NULL);
+ if ((Handle == INVALID_HANDLE_VALUE) && fCreate) {
+ Handle = CreateFile(FileName, Access, Share, NULL, CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ }
+ if (Handle == INVALID_HANDLE_VALUE) {
+ return (HANDLE)0;
+ } else {
+ return Handle;
+ }
+}
+
+
+
+
+void
+MepFClose (
+ FILEHANDLE Handle
+ )
+{
+ CloseHandle(Handle);
+}
+
+
+
+DWORD
+MepFRead (
+ PVOID pBuffer,
+ DWORD Size,
+ FILEHANDLE Handle
+ )
+{
+ DWORD BytesRead;
+ if ( !ReadFile(Handle, pBuffer, Size, &BytesRead, NULL) ) {
+ return 0;
+ } else {
+ return BytesRead;
+ }
+}
+
+
+
+
+DWORD
+MepFWrite (
+ PVOID pBuffer,
+ DWORD Size,
+ FILEHANDLE Handle
+ )
+{
+ DWORD BytesWritten;
+
+ if ( !WriteFile(Handle, pBuffer, Size, &BytesWritten, NULL) ) {
+ return 0;
+ } else {
+ return BytesWritten;
+ }
+}
+
+
+DWORD
+MepFSeek (
+ FILEHANDLE Handle,
+ DWORD Distance,
+ MOVEMETHOD MoveMethod
+ )
+{
+ assert (Handle != INVALID_HANDLE_VALUE);
+ return SetFilePointer(Handle, Distance, NULL, MoveMethod);
+}
+
+
+
+
+
+
+flagType
+FileExists (
+ char *path
+ )
+{
+ return (flagType)((GetFileAttributes(path) == -1) ? FALSE : TRUE);
+}
+
+
+//
+// rename may be defined as MepMove, but now we want the real one, so
+// we undefine it.
+//
+#ifdef rename
+#undef rename
+#endif
+
+int MepMove (
+ char *oldname,
+ char *newname
+ )
+{
+ #define BUFFERSIZE (1024 * 32)
+
+ FILE *fhSrc, *fhDst;
+ void *buffer;
+ size_t BytesRead;
+ size_t BytesWritten;
+
+
+ if (FileExists (newname)) {
+ return -1;
+ }
+
+ //
+ // First, try the rename
+ //
+ if (rename(oldname, newname) == 0) {
+ return 0;
+ }
+
+ //
+ // Cannot rename, try to copy
+ //
+ if (!(fhSrc = fopen(oldname, "r"))) {
+ return -1;
+ }
+
+ if (!(fhDst = fopen(newname, "w"))) {
+ fclose(fhSrc);
+ return -1;
+ }
+
+ buffer = MALLOC(BUFFERSIZE);
+ if ( !buffer ) {
+ disperr (MSGERR_NOMEM);
+ return -1;
+ }
+
+ do {
+ BytesRead = fread(buffer, 1, BUFFERSIZE, fhSrc);
+ if (BytesRead) {
+ BytesWritten = fwrite(buffer, 1, BytesRead, fhDst);
+ }
+
+ } while (BytesRead);
+
+ fclose(fhSrc);
+ fclose(fhDst);
+
+ FREE(buffer);
+
+ return _unlink(oldname);
+
+}
diff --git a/private/utils/mep/src/fscan.c b/private/utils/mep/src/fscan.c
new file mode 100644
index 000000000..7cb482c1b
--- /dev/null
+++ b/private/utils/mep/src/fscan.c
@@ -0,0 +1,168 @@
+/*** fscan.c - iterate a function across all characters in a file
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+*
+* 27-Nov-1991 mz Strip procedure qualifiers
+*
+*************************************************************************/
+#include "mep.h"
+
+/*** fScan - Apply (*pevent)() until it returns TRUE
+*
+* Starting one character to the right of (x, y) (left for !fFor), move
+* through the file forward (backward for !fFor) and call pevent on each
+* character. Also call once at the end of each line on the '\0' character.
+*
+* Input:
+* flStart - location in pFileHead at which to start scan
+* pevent - function to call for done signal
+* fFor - TRUE means go forward through file, FALSE backwards
+* fWrap - TRUE means wrap around the ends of the file, ending at the
+* starting position. The range to be scanned (defined below)
+* must include the appropriate start/end of the file.
+*
+* Globals:
+* rnScan - Region to confine scan to.
+*
+* Returns TRUE if pevent returned true for some file position FALSE if we
+* ran out of scanning region first.
+*
+* During the life of fScan, the following globals are valid, and maybe
+* used by pevent:
+*
+* flScan - Position in file pevent should look at.
+* scanbuf - Contents of line to be looking at.
+* scanreal - Un-Detabbed version of same.
+* scanlen - Number of characters in scanbuf.
+*
+* The line in scanbuf is detabbed, howver the pevent routine is called once
+* per physical character, if fRealTabs is true.
+*
+*************************************************************************/
+flagType
+fScan (
+ fl flStart,
+ flagType (*pevent) (void),
+ flagType fFor,
+ flagType fWrap
+ ) {
+
+ LINE yLim; /* limitting line for scanning */
+
+ flScan = flStart;
+
+ if (!fFor) {
+ /*
+ * backwards scan.
+ *
+ * dec current column. If it steps outside of rnScan, then back up a line, and
+ * set the column to the right hand column.
+ */
+ if (--flScan.col < rnScan.flFirst.col) {
+ flScan.lin--;
+ flScan.col = rnScan.flLast.col;
+ }
+ /*
+ * While we are within the line range of rnScan, check for CTRL-C aborts, and
+ * get each line.
+ */
+ yLim = rnScan.flFirst.lin;
+ while (flScan.lin >= yLim) {
+ if (fCtrlc) {
+ return (flagType)!DoCancel();
+ }
+ scanlen = GetLine (flScan.lin, scanreal, pFileHead) ;
+ scanlen = Untab (fileTab, scanreal, scanlen, scanbuf, ' ');
+ /*
+ * ensure that the scan column position is within range, and then for every
+ * column in the rane of the current line, call the pevent routine
+ */
+ flScan.col = min ( ( flScan.col < 0
+ ? rnScan.flLast.col
+ : flScan.col)
+ , scanlen);
+
+ while (flScan.col >= rnScan.flFirst.col) {
+ if ((*pevent)()) {
+ return TRUE;
+ }
+ if (fRealTabs) {
+ flScan.col = colPhys (scanreal, (pLog (scanreal, flScan.col, TRUE) - 1));
+ } else {
+ flScan.col--;
+ }
+ }
+ /*
+ * display status to user. If we just scanned to begining of file, and we are
+ * to wrap, then set the new stop limit as the old start position, and set the
+ * next line to be scanned as the last in the file.
+ */
+ noise (flScan.lin--);
+ if ((flScan.lin < 0) && fWrap) {
+ yLim = flStart.lin;
+ flScan.lin = pFileHead->cLines - 1;
+ }
+ }
+ } else {
+ /*
+ * forwards scan. Same structure as above, only in the other direction.
+ */
+ flScan.col++;
+ yLim = rnScan.flLast.lin;
+ while (flScan.lin <= yLim) {
+ if (fCtrlc) {
+ return (flagType)!DoCancel();
+ }
+ scanlen = GetLine (flScan.lin, scanreal, pFileHead);
+ scanlen = Untab (fileTab, scanreal, scanlen, scanbuf, ' ');
+ scanlen = min (rnScan.flLast.col, scanlen);
+ while (flScan.col <= scanlen) {
+ if ((*pevent)()) {
+ return TRUE;
+ }
+ if (fRealTabs) {
+ flScan.col = colPhys (scanreal, (pLog (scanreal, flScan.col, TRUE) + 1));
+ } else {
+ flScan.col++;
+ }
+ }
+ flScan.col = rnScan.flFirst.col;
+ noise (++flScan.lin);
+ if (fWrap && (flScan.lin >= pFileHead->cLines)) {
+ flScan.lin = 0;
+ if (flStart.lin) {
+ yLim = flStart.lin - 1;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ return FALSE;
+}
+
+
+
+
+/*** setAllScan - set maximal scan range
+*
+* Sets scan range such that fScan operates on the entire file.
+*
+* Input:
+* fDir = TRUE => scan will procede forwards, else backwards
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void
+setAllScan (
+ flagType fDir
+ ) {
+ rnScan.flFirst.col = 0;
+ rnScan.flFirst.lin = fDir ? YCUR(pInsCur) : 0;
+ rnScan.flLast.col = sizeof(linebuf)-1;
+ rnScan.flLast.lin = pFileHead->cLines - 1;
+}
diff --git a/private/utils/mep/src/getstr.c b/private/utils/mep/src/getstr.c
new file mode 100644
index 000000000..b0e7808b5
--- /dev/null
+++ b/private/utils/mep/src/getstr.c
@@ -0,0 +1,314 @@
+/*** getstr.c - text argument handler
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+
+#include "mep.h"
+#include "cmds.h"
+
+
+#define ISWORD(c) (isalnum(c) || isxdigit(c) || c == '_' || c == '$')
+
+
+
+/*** getstring - one line editor
+*
+* This routine handles the entering and editting of single line responses
+* on the dialog line.
+*
+* Input:
+* pb = pointer to destination buffer for user's response
+* prompt = pointer to prompt string
+* pFunc = first editting function to process
+* flags = GS_NEWLINE entry must be terminated by newline, else any other
+* non-recognized function will do.
+* GS_INITIAL entry is highlighted, and if first function is
+* graphic, the entry is replaced by that graphic.
+* GS_KEYBOARD entry must from the keyboard (critical situation ?)
+*
+* Output:
+* Returns pointer to command which terminated the entry
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+PCMD
+getstring (
+ char *pb,
+ char *prompt,
+ PCMD pFunc,
+ flagType flags
+ ) {
+
+ flagType fMetaTextArg;
+
+ int xbeg;
+ int iRespCur; /* current position in response */
+
+ if ((iRespCur = strlen(pb)) == 0) {
+ RSETFLAG(flags, GS_INITIAL);
+ }
+ memset ((char *) pb+iRespCur, '\0', sizeof(linebuf) - iRespCur);
+
+ if (pFunc != NULL) {
+ xbeg = flArg.col;
+ } else {
+ iRespCur = 0;
+ xbeg = XCUR(pInsCur);
+ }
+
+ fMetaTextArg = fMeta;
+
+ /*
+ * main editing loop. [Re]Display entry line & process editting action.
+ */
+ while (TRUE) {
+ ScrollOut (prompt, pb, iRespCur, TESTFLAG(flags, GS_INITIAL) ? hgColor : fgColor, (flagType) TESTFLAG (flags, GS_KEYBOARD));
+ RSETFLAG (fDisplay, RCURSOR);
+ if (pFunc == NULL) {
+ if ((pFunc = (TESTFLAG (flags, GS_KEYBOARD) ? ReadCmd () : zloop (FALSE))) == NULL) {
+ SETFLAG (fDisplay, RCURSOR);
+ break;
+ }
+ }
+ SETFLAG (fDisplay, RCURSOR);
+
+
+ if ((PVOID)pFunc->func == (PVOID)newline ||
+ (PVOID)pFunc->func == (PVOID)emacsnewl) {
+ //
+ // newline functions: if allowed, terminate, else not allowed
+ // at all
+ //
+ if (!TESTFLAG(flags, GS_NEWLINE)) {
+ bell ();
+ } else {
+ break;
+ }
+ } else if ((PVOID)pFunc->func == (PVOID)graphic ||
+ (PVOID)pFunc->func == (PVOID)quote) {
+ //
+ // graphic functions: place the graphic character into the
+ // response buffer. If erasing default response, then remove it
+ // from buffer.
+ //
+ if (TESTFLAG(flags, GS_INITIAL)) {
+ iRespCur = 0;
+ memset ((char *) pb, '\0', sizeof(linebuf));
+ }
+ if (pFunc->func == quote) {
+ while ((pFunc->arg = ReadCmd()->arg) == 0) {
+ ;
+ }
+ }
+ if (fInsert) {
+ memmove ((char*) pb+iRespCur+1, (char*)pb+iRespCur, sizeof(linebuf)-iRespCur-2);
+ }
+ pb[iRespCur++] = (char)pFunc->arg;
+ } else if ((PVOID)pFunc->func == (PVOID)insertmode) {
+ //
+ // insert command.
+ //
+ insertmode (0, (ARG *) NULL, FALSE);
+ } else if ((PVOID)pFunc->func == (PVOID)meta) {
+ //
+ // meta command
+ //
+ meta (0, (ARG *) NULL, FALSE);
+ } else if ((PVOID)pFunc->func == (PVOID)left ||
+ (PVOID)pFunc->func == (PVOID)cdelete ||
+ (PVOID)pFunc->func == (PVOID)emacscdel) {
+ //
+ // Cursor leftward-movement functions: update cursor position
+ // and optionally remove characters from buffer.
+ //
+ if (iRespCur > 0) {
+ iRespCur--;
+ if ((PVOID)pFunc->func != (PVOID)left) {
+ if (fInsert) {
+ memmove ( (char*) pb+iRespCur, (char*) pb+iRespCur+1, sizeof(linebuf)-iRespCur);
+ } else if (!pb[iRespCur+1]) {
+ pb[iRespCur] = 0;
+ } else {
+ pb[iRespCur] = ' ';
+ }
+ }
+ }
+ } else if ((PVOID)pFunc->func == (PVOID)right) {
+ //
+ // Cursor right movement functions: update cursor position, and
+ // possibly get characters from current display.
+ //
+ if (pFileHead && pb[iRespCur] == 0) {
+ fInsSpace (xbeg+iRespCur, YCUR(pInsCur), 0, pFileHead, buf);
+ pb[iRespCur] = buf[xbeg+iRespCur];
+ pb[iRespCur+1] = 0;
+ }
+ iRespCur++;
+ } else if ((PVOID)pFunc->func == (PVOID)begline ||
+ (PVOID)pFunc->func == (PVOID)home) {
+ //
+ // Home function: update cursor position
+ //
+ iRespCur = 0;
+ } else if ((PVOID)pFunc->func == (PVOID)endline) {
+ //
+ // End function: update cursor position
+ //
+ iRespCur = strlen (pb);
+ } else if ((PVOID)pFunc->func == (PVOID)delete ||
+ (PVOID)pFunc->func == (PVOID)sdelete) {
+ //
+ // Delete function: remove character
+ //
+ memmove ( (char*) pb+iRespCur, (char*) pb+iRespCur+1, sizeof(linebuf)-iRespCur);
+ } else if ((PVOID)pFunc->func == (PVOID)insert ||
+ (PVOID)pFunc->func == (PVOID)sinsert) {
+ //
+ // Insert function: insert space
+ //
+ memmove ( (char*) pb+iRespCur+1, (char*) pb+iRespCur, sizeof(linebuf)-iRespCur-1);
+ pb[iRespCur] = ' ';
+ } else if((PVOID)pFunc->func == (PVOID)doarg) {
+ //
+ // Arg function: clear from current position to end
+ // of response.
+ //
+ memset ((char *) pb+iRespCur, '\0', sizeof(linebuf) - iRespCur);
+ } else if ((PVOID)pFunc->func == (PVOID)pword) {
+ //
+ // Pword function: mive roght until the char to the left of
+ // the cursor is not part of a word, but the char under the
+ // cursor is.
+ //
+ while (pb[iRespCur] != 0) {
+ iRespCur++;
+ if (!ISWORD (pb[iRespCur-1]) && ISWORD (pb[iRespCur])) {
+ break;
+ }
+ }
+ } else if ((PVOID)pFunc->func == (PVOID)mword) {
+ //
+ // Mword function
+ //
+ while (iRespCur > 0) {
+ if (--iRespCur == 0 ||
+ (!ISWORD (pb[iRespCur-1]) && ISWORD (pb[iRespCur]))) {
+ break;
+ }
+ }
+ } else if (TESTFLAG (pFunc->argType, CURSORFUNC)) {
+ //
+ // Other cursor movement function: not allowed, so beep.
+ //
+ bell ();
+ } else {
+ //
+ // All other functions: if new line required to terminate,
+ // then beep, otherwise terminate and return the
+ // function terminated with.
+ //
+ if ((PVOID)pFunc != (PVOID)NULL) {
+ if (TESTFLAG(flags, GS_NEWLINE) && (PVOID)pFunc->func != (PVOID)cancel) {
+ bell ();
+ } else {
+ break;
+ }
+ }
+
+ }
+ /*
+ * process here to truncate any potential buffer overruns
+ */
+ if (!TESTFLAG(pFunc->argType, KEEPMETA)) {
+ fMeta = FALSE;
+ }
+ pFunc = NULL;
+ if (iRespCur > sizeof(linebuf) - 2) {
+ iRespCur = sizeof(linebuf) - 2;
+ pb[iRespCur+1] = 0;
+ bell ();
+ }
+ RSETFLAG(flags, GS_INITIAL);
+ }
+
+ fMeta = fMetaTextArg ^ fMeta;
+ return pFunc;
+}
+
+
+
+
+/*** ScrollOut - Update dialog line
+*
+* Place a prompt, and a portion of the users response, onto the dialog of the
+* screen. Update the cursor position to the requested position relative to
+* the begining of the users response. Always ensure that that cursor position
+* is within the text actually displayed.
+*
+* Input:
+* szPrompt - Text of prompt
+* szResp - Text of users response
+* xCursor - Current X position within reponse that is to get cursor
+* coResp - Color to display response as
+* fVisible - Forces display
+*
+* Globals:
+* hscroll - Horizontal scroll amount
+* infColor - Color that prompt will be displayed with
+* slSize - Version 1 only, contains line on screen for output.
+*
+* Output:
+* Dialog line updated.
+*
+*************************************************************************/
+void
+ScrollOut (
+ char *szPrompt, /* prompt text */
+ char *szResp, /* users response string */
+ int xCursor, /* Current pos w/in response */
+ int coResp, /* response color */
+ flagType fVisible /* force display */
+ ) {
+
+ int cbPrompt; /* length of the prompt string */
+ int cbResp; /* length of the text displayed */
+ int cbDisp; /* This position must be disp'd */
+ int xOff; /* offset of string trailer */
+
+#define LXSIZE XSIZE
+
+ if (!mtest () || mlast () || fVisible) {
+ cbPrompt = strlen (szPrompt);
+ cbResp = strlen (szResp);
+
+ /*
+ * The distance of the new cursor position is calculated from the
+ * left edge of the text to be displayed. If there is more text
+ * than there is window, we also adjust the left edge based on hscroll.
+ */
+ if (xOff = max (xCursor - (LXSIZE - cbPrompt - 1), 0)) {
+ xOff += hscroll - (xOff % hscroll);
+ }
+
+ cbDisp = min (LXSIZE-cbPrompt, cbResp-xOff);
+
+ /*
+ * output the prompt, the reponse string in the requested color,
+ * if required blank what's left, and finally update the cursor
+ * position.
+ */
+ vout (0, YSIZE, szPrompt, cbPrompt, infColor);
+ vout (cbPrompt, YSIZE, (char *)(szResp + xOff), cbDisp, coResp);
+ if (cbPrompt + cbDisp < LXSIZE) {
+ voutb (cbPrompt + cbDisp, YSIZE, " ", 1, fgColor);
+ }
+ consoleMoveTo( YSIZE, xCursor-xOff+cbPrompt);
+ }
+}
diff --git a/private/utils/mep/src/graphic.c b/private/utils/mep/src/graphic.c
new file mode 100644
index 000000000..1a24ab30c
--- /dev/null
+++ b/private/utils/mep/src/graphic.c
@@ -0,0 +1,420 @@
+/*** graphic.c - simple single character editing
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+*
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+
+#include "mep.h"
+#include "keyboard.h"
+
+
+struct cmdDesc cmdGraphic = { "graphic", graphic, 0, FALSE };
+
+/*** graphic - Editor <graphic> function
+*
+* Purpose:
+* Inserts character in text at current cursor position. Delete
+* previously selected text if any.
+*
+* Input:
+* the usual
+*
+* Output:
+* TRUE if character successfully inserted (FALSE means line too long)
+*
+* Notes:
+*
+*************************************************************************/
+flagType
+graphic (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ )
+{
+ delarg (pArg);
+ return edit ( ((KEY_DATA *)&argData)->Ascii );
+
+ fMeta;
+}
+
+
+
+
+
+/*** szEdit - insert a string at the current position.
+*
+* Purpose:
+* Inserts character in text at current cursor position.
+*
+* Input:
+* sz = String to be entered
+*
+* Output:
+* FALSE if the line was too long, else true.
+*
+* Notes:
+*
+*************************************************************************/
+flagType
+szEdit (
+ char *sz
+ )
+{
+ while (*sz) {
+ if (!edit (*sz++)) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+
+
+
+
+/*** edit
+*
+* Purpose:
+* Inserts character in text at current cursor position.
+*
+* Input:
+* c = Character to be entered
+*
+* Output:
+* FALSE if the line was too long, else true.
+*
+* Notes:
+*
+*************************************************************************/
+flagType
+edit (
+ char c
+ )
+{
+ COL dx;
+ fl fl; /* loc to place cursor at */
+ COL tmpx;
+ COL x;
+
+ /*
+ * point at current location
+ */
+ fl.col = XCUR(pInsCur);
+ fl.lin = YCUR(pInsCur);
+
+ if (fWordWrap && xMargin > 0) {
+
+ /*
+ * if space entered just past right margin, then copy everything to the right
+ * of the space to the next line.
+ */
+ if (c == ' ' && fl.col >= xMargin) {
+ tmpx = softcr ();
+ CopyStream (NULL, pFileHead, fl.col, fl.lin,
+ tmpx, fl.lin+1,
+ fl.col, fl.lin);
+ fl.lin++;
+ fl.col = tmpx;
+ cursorfl (fl);
+ return TRUE;
+ } else if (fl.col >= xMargin + 5) {
+
+ /* move backward to the beginning of the current word
+ * and break it there.
+ *
+ * Make sure we have a line that contains the cursor
+ */
+ fInsSpace (fl.col, fl.lin, 0, pFileHead, buf);
+
+ /* We'll go backwards to find the first place where
+ * the char there is non-space and the char to
+ * the left of it is a space. We'll break the line at
+ * that place.
+ */
+ for (x = fl.col - 1; x > 1; x--) {
+ if (buf[x-1] == ' ' && buf[x] != ' ') {
+ break;
+ }
+ }
+
+ /* if we've found the appropriate word, break it there
+ */
+ if (x > 1) {
+ dx = fl.col - x;
+ tmpx = softcr ();
+ CopyStream (NULL, pFileHead, x, fl.lin,
+ tmpx, fl.lin + 1,
+ x, fl.lin);
+ fl.col = tmpx + dx;
+ fl.lin++;
+ cursorfl (fl);
+ }
+ }
+ }
+
+ if (Replace (c, fl.col, fl.lin, pFileHead, fInsert)) {
+ right ((CMDDATA)0, (ARG *)NULL, FALSE);
+ return TRUE;
+ } else {
+ LengthCheck (fl.lin, 0, NULL);
+ return FALSE;
+ }
+}
+
+
+
+
+
+/*** quote - Editor <quote> function
+*
+* Purpose:
+* Inserts character in text at current cursor position. Delete
+* previously selected text if any.
+*
+* Input:
+* the usual
+*
+* Output:
+* TRUE if character successfully inserted (FALSE means line too long)
+*
+*************************************************************************/
+flagType
+quote (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ )
+{
+ char c;
+
+ delarg (pArg);
+
+ while ((c = (char)(ReadCmd()->arg)) == 0) {
+ ;
+ }
+ return edit (c);
+
+ argData; fMeta;
+}
+
+
+
+
+/*** delarg - deletes current selected area
+*
+* Purpose:
+* <graphic> and <quote> delete previously selected text. Here we do it
+*
+* Input:
+* pArg pointer to current ARG structure
+*
+* Output:
+* None
+*
+* Notes:
+*
+*************************************************************************/
+void
+delarg (
+ ARG * pArg
+ )
+{
+ fl fl;
+
+ switch (pArg->argType) {
+
+ case STREAMARG:
+ DelStream (pFileHead,
+ pArg->arg.streamarg.xStart, pArg->arg.streamarg.yStart,
+ pArg->arg.streamarg.xEnd, pArg->arg.streamarg.yEnd );
+ fl.col = pArg->arg.streamarg.xStart;
+ fl.lin = pArg->arg.streamarg.yStart;
+ break;
+
+ case LINEARG:
+ DelLine (TRUE, pFileHead,
+ pArg->arg.linearg.yStart, pArg->arg.linearg.yEnd);
+ fl.col = 0;
+ fl.lin = pArg->arg.linearg.yStart;
+ break;
+
+ case BOXARG:
+ DelBox (pFileHead,
+ pArg->arg.boxarg.xLeft, pArg->arg.boxarg.yTop,
+ pArg->arg.boxarg.xRight, pArg->arg.boxarg.yBottom);
+ fl.col = pArg->arg.boxarg.xLeft;
+ fl.lin = pArg->arg.boxarg.yTop;
+ break;
+
+ default:
+ return;
+ }
+ cursorfl(fl);
+}
+
+
+
+
+
+/*** Replace - edit character in a file
+*
+* Purpose:
+* Replace will take the specified character and place it into the
+* specified position in the specified file. If the edit is a NOP
+* (overstriking the same character) then no modification takes place
+*
+* Input:
+* c character to edit in file
+* x, y column, row of file to be changed
+* pFile file being modified
+* fInsert TRUE => character is inserted before the position
+*
+* Output:
+* TRUE => line was successfully edited, FALSE => line was too long
+*
+* Notes:
+*
+*************************************************************************/
+flagType
+Replace (
+ char c,
+ COL x,
+ LINE y,
+ PFILE pFile,
+ flagType fInsert
+ )
+{
+ linebuf buf; /* working buffer */
+ struct lineAttr rgla[sizeof(linebuf)];
+ flagType fColor = FALSE, fSpace = 0;
+ char *pxLog;
+
+ fColor = GetColor (y, rgla, pFile);
+
+ if (fInsSpaceColor (x, y, fInsert ? 1 : 0, pFile, buf, fColor ? rgla : NULL)) {
+
+ pxLog = pLog (buf, x, TRUE);
+
+ if (cbLog(buf) <= x) {
+
+ /*
+ * If the logical length of the buffer is less than what we need, then it was
+ * at least space filled by fInsert, and we just need to append our character
+ * to the buffer
+ */
+
+ *(unsigned int UNALIGNED *)pxLog = (unsigned int)(unsigned char)c;
+
+ } else if (fInsert || (*pxLog != c)) {
+
+ /*
+ * if we're inserting, or the character we're overtyping is different, place
+ * the character. Be sure to check the new logical length of the line as well,
+ * in case it was a tab that overflowed it.
+ */
+
+ *pxLog = c;
+ if (cbLog(buf) >= sizeof(linebuf)) {
+ return FALSE;
+ }
+ }
+
+ if (fInsert) {
+ MarkCopyBox (pFile, pFile, x, y, sizeof(linebuf), y, x+1, y);
+ }
+
+ PutLine (y, buf, pFile);
+ if (fColor) {
+ ColorToLog (rgla, buf);
+ PutColor (y, rgla, pFile);
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+
+
+
+/*** curdate, curday and curtime - editting functions
+*
+* Purpose:
+* insert current day/date/time into text being editted
+*
+* Input:
+* Standard Editting Function
+*
+* Output:
+* Returns TRUE if text entered.
+*
+*************************************************************************/
+flagType
+curdate (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ )
+{
+ buffer buf;
+ long ltime;
+ char *s;
+
+ time (&ltime);
+ s = ctime (&ltime);
+ sprintf (buf, "%.2s-%.3s-%.4s", s+8, s+4, s+20);
+ return szEdit (buf);
+
+ argData; pArg; fMeta;
+}
+
+
+
+
+flagType
+curday (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ )
+{
+ buffer buf;
+ long ltime;
+ char *s;
+
+ time (&ltime);
+ s = ctime (&ltime);
+ sprintf (buf, "%.3s",s);
+ return szEdit (buf);
+
+ argData; pArg; fMeta;
+}
+
+
+
+
+
+flagType
+curtime (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ )
+{
+ buffer buf;
+ long ltime;
+ char *s;
+
+ time (&ltime);
+ s = ctime (&ltime);
+ sprintf (buf, "%.8s",s+11);
+ return szEdit (buf);
+
+
+ argData; pArg; fMeta;
+}
diff --git a/private/utils/mep/src/hilite.c b/private/utils/mep/src/hilite.c
new file mode 100644
index 000000000..3a59c0d99
--- /dev/null
+++ b/private/utils/mep/src/hilite.c
@@ -0,0 +1,610 @@
+/*** hilite.c - editor multiple-file highlighting support
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Contains the common code to maintain multiple highlighted regions across
+* multiple files.
+*
+* Highlighting Overview
+*
+* Each pFile contains a vm pointer to a linked list of blocks each of which
+* contain up to RNMAX ranges in the file currently highlighted. The ranges
+* are maintained in order of the first coordinate of the range (see below),
+* though they may overlap. Each block may not be completely full, due to the
+* insertion algorithm which maintains the order.
+*
+* +---------------+ +---------------+ +---------------+
+* pFile->vaHiLite-->|vaNext |-->|vaNext |-->|-1L |
+* +---------------+ +---------------+ +---------------+
+* |irnMac | |irnMac | |irnMac |
+* +---------------+ +---------------+ +---------------+
+* |rnHiLite[RNMAX]| |rnHiLite[RNMAX]| |rnHiLite[RNMAX]|
+* +---------------+ +---------------+ +---------------+
+*
+* Clearing all current highlighting for a file simply involves deallocating
+* the list of highlight ranges.
+*
+* Adding a highlight region either updates an existing region (if the start
+* points are the same, and the new end point is the same in one direction and
+* greater in the other), or insertion of a new range in the sorted list. If
+* a block is full, when asertion is attempted in that block, the block will
+* be split in half, and a new block inserted into the linked list.
+*
+* Each range is "normally" an ordered pair of coordinates (a range, or rn)
+* specifying the range of the file to be hilighted. However, Arg processing
+* always specifies that the first coordinate of this pair is the location at
+* which the user hit ARG, and the second is the travelling corrdinate as he
+* specifies the region on screen. For this reason, if the x coordinates are
+* in reverse order, the right-most coordinate is decremented by one to
+* reflect the correct highlighting for arguments.
+*
+*
+* Revision History:
+*
+* 26-Nov-1991 mz Strip off near/far
+*************************************************************************/
+
+#include "mep.h"
+
+#define RNMAX 20 /* max number of rns per block */
+ /* MUST BE EVEN */
+
+/*
+ * HiLiteBlock - block of highlighting information as kept in VM
+ */
+struct HiLiteBlock {
+ PVOID vaNext; /* va of next block, or -1 */
+ int irnMac; /* number of rns in block */
+ rn rnHiLite[RNMAX]; /* ranges with highlighting */
+ char coHiLite[RNMAX]; /* colors to be used */
+ };
+
+
+
+/*** SetHiLite - Mark a range in a file to be highlighted
+*
+* Marks the specfied range in a file as needing to be highlighted. The next
+* time that portion of the file is updated on screen, the highlighting
+* attributes will be applied.
+*
+* Input:
+* pFile = file to be highlighted
+* rnCur = Range to be highlighted
+* coCur = Color to use for highlighting
+*
+* Output:
+*
+*************************************************************************/
+void
+SetHiLite (
+ PFILE pFile,
+ rn rnCur,
+ int coCur
+ ) {
+
+ struct HiLiteBlock hbCur; /* block being worked on */
+ int irnCur; /* index into block */
+ PVOID vaCur; /* va of current block */
+ PVOID vaNew; /* va of new split block */
+ PVOID vaNext; /* va of next block */
+
+ /*
+ * If the file does not yet have one, allocate the first highlight block
+ */
+ if (pFile->vaHiLite == (PVOID)(-1L)) {
+ irnCur = 0;
+ hbCur.vaNext = (PVOID)(-1L);
+ hbCur.irnMac = 0;
+ vaCur = pFile->vaHiLite = MALLOC ((long)sizeof(hbCur));
+ } else {
+ vaCur = pFile->vaHiLite;
+ while (1) {
+ // rjsa VATopb (vaCur, (char *)&hbCur, sizeof(hbCur));
+ memmove((char *)&hbCur, vaCur, sizeof(hbCur));
+ assert (hbCur.irnMac <= RNMAX);
+
+ /*
+ * search contents of current block for first range which occurs on
+ * the same or a later position than the new one.
+ */
+ for (irnCur = 0; irnCur<hbCur.irnMac; irnCur++) {
+ if (hbCur.rnHiLite[irnCur].flFirst.lin > rnCur.flFirst.lin) {
+ break;
+ }
+ if ( (hbCur.rnHiLite[irnCur].flFirst.lin == rnCur.flFirst.lin)
+ && (hbCur.rnHiLite[irnCur].flFirst.col >= rnCur.flFirst.col)) {
+ break;
+ }
+ }
+ /*
+ * if we found something, exit the search, else move to next block,
+ * if there is one.
+ */
+ if (irnCur != hbCur.irnMac) {
+ break;
+ }
+ if (hbCur.vaNext == (PVOID)(-1L)) {
+ break;
+ }
+ vaCur = hbCur.vaNext;
+ }
+ }
+
+ /*
+ * vaCur = va of block needing insertion/modification
+ * irnCur = index of rn for same or later position
+ * hbCur = contents of block last read
+ *
+ * if irnCur<RNMAX we operate on the current block, else we allocate a
+ * new one, link it to the list, and place our new highlighted region
+ * in it.
+ */
+ if (irnCur >= RNMAX) {
+ hbCur.vaNext = MALLOC ((long)sizeof(hbCur));
+ // rjsa pbToVA ((char *)&hbCur, vaCur, sizeof(hbCur));
+ memmove(vaCur, (char *)&hbCur, sizeof(hbCur));
+ vaCur = hbCur.vaNext;
+ hbCur.vaNext = (PVOID)(-1L);
+ hbCur.irnMac = 1;
+ hbCur.rnHiLite[0] = rnCur;
+ // rjsa pbToVA ((char *)&hbCur, vaCur, sizeof(hbCur));
+ memmove(vaCur, (char *)&hbCur, sizeof(hbCur));
+ return;
+ }
+
+ /*
+ * If the upper first coordinate matches, and one of the second coordinates
+ * then just update the second.
+ */
+ if ( (irnCur >= 0)
+ && ( (hbCur.rnHiLite[irnCur].flFirst.lin == rnCur.flFirst.lin)
+ && (hbCur.rnHiLite[irnCur].flFirst.col == rnCur.flFirst.col))
+ && ( (hbCur.rnHiLite[irnCur].flLast.lin == rnCur.flLast.lin)
+ || (hbCur.rnHiLite[irnCur].flLast.col == rnCur.flLast.col))
+ && (hbCur.coHiLite[irnCur] == (char)coCur)
+ ) {
+
+ /*
+ * If the columns have changed, redraw the entire range (only the columns
+ * changed, but on all lines), otherwise just redraw those lines which
+ * have changed.
+ */
+ if (hbCur.rnHiLite[irnCur].flLast.col != rnCur.flLast.col) {
+ redraw (pFile,rnCur.flFirst.lin,rnCur.flLast.lin);
+ } else {
+ redraw (pFile,hbCur.rnHiLite[irnCur].flLast.lin,rnCur.flLast.lin);
+ }
+ hbCur.rnHiLite[irnCur].flLast = rnCur.flLast;
+ } else {
+ redraw (pFile,rnCur.flFirst.lin,rnCur.flLast.lin);
+
+ /*
+ * if the block to be modified is full, then split it into two blocks.
+ */
+ if (hbCur.irnMac == RNMAX) {
+ hbCur.irnMac = RNMAX/2;
+ vaNext = hbCur.vaNext;
+ vaNew = hbCur.vaNext = MALLOC ((long)sizeof(hbCur));
+ // rjsa pbToVA ((char *)&hbCur, vaCur, sizeof(hbCur));
+ memmove(vaCur, (char *)&hbCur, sizeof(hbCur));
+ memmove ((char *)&hbCur.rnHiLite[0],
+ (char *)&hbCur.rnHiLite[RNMAX/2]
+ ,(RNMAX/2)*sizeof(rn));
+ memmove ((char *)&hbCur.coHiLite[0],
+ (char *)&hbCur.coHiLite[RNMAX/2]
+ ,(RNMAX/2)*sizeof(char));
+ hbCur.vaNext = vaNext;
+ // rjsa pbToVA ((char *)&hbCur, vaNew, sizeof(hbCur));
+ memmove(vaNew, (char *)&hbCur, sizeof(hbCur));
+
+ /*
+ * select which of the two blocks (vaCur, the first half; or vaNew,
+ * the second) to operate on. ReRead the old block if required.
+ */
+ if (irnCur >= RNMAX/2) {
+ vaCur = vaNew;
+ irnCur -= RNMAX/2;
+ } else {
+ //rjsa VATopb (vaCur, (char *)&hbCur, sizeof(hbCur));
+ memmove((char *)&hbCur, vaCur, sizeof(hbCur));
+ }
+ }
+
+ /*
+ * Move the rn's that follow where we want to be, up by one,
+ * and insert ours.
+ */
+ if (irnCur < hbCur.irnMac) {
+ memmove ((char *)&hbCur.rnHiLite[irnCur+1],
+ (char *)&hbCur.rnHiLite[irnCur]
+ ,(hbCur.irnMac - irnCur)*sizeof(rn));
+ }
+ memmove ((char *)&hbCur.coHiLite[irnCur+1],
+ (char *)&hbCur.coHiLite[irnCur]
+ ,(hbCur.irnMac - irnCur));
+ hbCur.rnHiLite[irnCur] = rnCur;
+ hbCur.coHiLite[irnCur] = (char)coCur;
+ hbCur.irnMac++;
+ }
+
+ /*
+ * update the block in vm
+ */
+ // rjsa pbToVA ((char *)&hbCur, vaCur, sizeof(hbCur));
+ memmove(vaCur, (char *)&hbCur, sizeof(hbCur));
+}
+
+
+
+/*** ClearHiLite - remove all highlighting from a file
+*
+* Removes all highlighting information for a file, and marks those lines
+* affected as needing to be redrawn.
+*
+* Input:
+* pFile = file affected.
+* fFree = TRUE => free the VM used
+*
+* Output:
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+void
+ClearHiLite (
+ PFILE pFile,
+ flagType fFree
+ ) {
+
+ struct HiLiteBlock *hbCur, *hbNext;
+ int irn;
+
+ while (pFile->vaHiLite != (PVOID)(-1L)) {
+
+ hbCur = ( struct HiLiteBlock *)(pFile->vaHiLite );
+
+ assert (hbCur->irnMac <= RNMAX);
+
+ /*
+ * for each of the highlight ranges in the block, mark the lines as
+ * needing to be redrawn, so that highlighting will be removed from
+ * the screen.
+ */
+ for (irn = hbCur->irnMac; irn; ) {
+ irn--;
+ redraw (pFile
+ ,hbCur->rnHiLite[irn].flFirst.lin
+ ,hbCur->rnHiLite[irn].flLast.lin
+ );
+ }
+
+ /*
+ * discard the vm used by the block, and point at the next block in
+ * the chain
+ */
+ hbNext = hbCur->vaNext;
+ if (fFree) {
+ FREE(pFile->vaHiLite);
+ }
+ pFile->vaHiLite = hbNext;
+ }
+}
+
+
+
+/*** UpdHiLite - Update a color buffer with highlighting information
+*
+* Apply all highlighting ranges that apply to a particluar portion
+* of a line in a file to a color buffer. Ensure that areas outside
+* the highlight range are unaffected, and that areas within are
+* updated appropriately.
+*
+* Input:
+* pFile = File being operated on
+* lin = line
+* colFirst = first col
+* colLast = last col
+* ppla = Pointer to Pointer to lineattr array to be updated
+*
+* Output:
+* Returns TRUE if highlighting occurred.
+*
+*************************************************************************/
+flagType
+UpdHiLite (
+ PFILE pFile,
+ LINE lin,
+ COL colFirst,
+ COL colLast,
+ struct lineAttr **ppla
+ ) {
+
+ struct HiLiteBlock *hbCur; /* block being worked on */
+ PVOID vaCur; /* va of current block */
+ int irnCur; /* index into block */
+
+ COL colHiFirst;
+ COL colHiLast;
+ COL colHiTmp;
+
+ COL col;
+ struct lineAttr *pla;
+
+ flagType fRv = FALSE; /* highlighting occurred */
+
+ /*
+ * First we scroll it to the left (if needed)
+ */
+ if (colFirst) {
+ for (col = 0, pla = *ppla;
+ col + pla->len <= colFirst;
+ col += pla++->len) {
+ ;
+ }
+
+ if (col < colFirst && pla->len != 0xff) {
+ pla->len -= (unsigned char) (colFirst - col);
+ }
+
+ /*
+ * Take care here we modify THEIR pointer
+ */
+ *ppla = pla;
+ }
+
+ /*
+ * for all blocks of hiliting info
+ */
+ vaCur = pFile->vaHiLite;
+ while (vaCur != (PVOID)(-1L)) {
+
+ /*
+ * get block
+ */
+ hbCur = (struct HiLiteBlock *)vaCur;
+ assert (hbCur->irnMac <= RNMAX);
+
+ /*
+ * for each range within the block
+ */
+ for (irnCur = 0; irnCur<hbCur->irnMac; irnCur++) {
+ /*
+ * is the range affecting the line we're looking for ?
+ */
+ if (fInRange (hbCur->rnHiLite[irnCur].flFirst.lin
+ ,lin
+ ,hbCur->rnHiLite[irnCur].flLast.lin)) {
+
+ /*
+ * Watch out: range coordinates might be inversed
+ */
+ if ( (colHiFirst = hbCur->rnHiLite[irnCur].flFirst.col)
+ > (colHiLast = hbCur->rnHiLite[irnCur].flLast.col)) {
+
+ colHiTmp = colHiFirst - 1;
+ colHiFirst = colHiLast;
+ colHiLast = colHiTmp;
+ }
+
+
+ /*
+ * is the range affecting the portion of line we're looking for ?
+ */
+ if (!(colHiLast < colFirst || colHiFirst > colLast)) {
+ /*
+ * Yes: signals work done and do the hilite
+ */
+ fRv = TRUE;
+ UpdOneHiLite (*ppla
+ ,max(colFirst, colHiFirst) - colFirst
+ ,min(colLast, colHiLast ) - max(colFirst, colHiFirst) + 1
+ ,TRUE
+ ,(int) hbCur->coHiLite[irnCur]);
+ }
+ }
+ }
+ vaCur = hbCur->vaNext;
+ }
+ return fRv;
+}
+
+
+
+/*** UpdOneHiLite - Update the highlighting on one line of attributes
+*
+* Modifies an existing attribute line to include highlighting.
+*
+* Input:
+* pla = Pointer to attribute information for line
+* colFirst = Starting column
+* colLast = Ending column
+* fattr (CW only) = TRUE: attr is color index
+* FALSE: attr is pointer to lineAttr array
+* attr = color index or pointer to lineAttr array to be used
+*
+* Output:
+* *pla updated
+*
+*************************************************************************/
+void
+UpdOneHiLite (
+ struct lineAttr *pla,
+ COL colFirst,
+ COL len,
+ flagType fattr,
+ int attr
+ ) {
+
+ struct lineAttr *plaFirstMod; /* pointer to first cell to be modified */
+ struct lineAttr *plaLastMod; /* pointer to last cell to be modified */
+ COL colLast = colFirst + len - 1;
+ COL colFirstMod; /* starting column for first modified cell */
+ COL colLastMod; /* starting column for last modified cell */
+
+ struct lineAttr *plaSrc; /* source pointer for moving cells */
+ struct lineAttr *plaDst; /* destination pointer for moving cells */
+ struct lineAttr *plaSrcSav; /* temporary pointer */
+
+ struct lineAttr *plaExt; /* pointer to external array of lineAttr */
+ COL colSrc;
+ COL colSrcEnd;
+
+ struct lineAttr rglaTmp[3]; /* buffer for creating cells */
+ int claTmp = 0; /* number of cells to insert */
+
+ /*
+ * First we Find the first cell that will be affected by the change
+ */
+ for (colFirstMod = 0, plaFirstMod = pla;
+ colFirstMod + plaFirstMod->len <= colFirst;
+ colFirstMod += plaFirstMod++->len) {
+ ;
+ }
+
+ /*
+ * Next we find the last cell that will be affected by the change
+ */
+ for (colLastMod = colFirstMod, plaLastMod = plaFirstMod;
+ colLastMod + plaLastMod->len <= colLast;
+ colLastMod += plaLastMod++->len) {
+ ;
+ }
+
+ /*
+ * If the first affected cell doesn't start on our boundary, let's
+ * create a new cell to be inserted
+ */
+ if (colFirstMod < colFirst) {
+ rglaTmp[0].len = (unsigned char) (colFirst - colFirstMod);
+ rglaTmp[0].attr = plaFirstMod->attr;
+ claTmp++;
+ } else {
+ rglaTmp[0].len = 0;
+ }
+
+ if (fattr) {
+ /*
+ * Only one color for the updated range: we always create
+ * the cell of new color
+ */
+ rglaTmp[1].len = (unsigned char) (colLast - colFirst + 1);
+ rglaTmp[1].attr = (unsigned char) attr;
+ claTmp++;
+ } else {
+ /*
+ * Colors for the updated range come from an array of lineAttr
+ * We first get its address (this is a hack because 16 bit pointer
+ * can be cast to an int)
+ */
+ plaExt = (struct lineAttr *) attr;
+
+ /*
+ * Count the number of cells to copy.
+ */
+ for (plaSrc = plaExt, colSrc = 0, colSrcEnd = colLast - colFirst + 1;
+ colSrc + plaSrc->len <= colSrcEnd;
+ colSrc += plaSrc++->len, claTmp++) {
+ ;
+ }
+
+ /*
+ * Build trailing cell if needed
+ */
+ if (colSrc < colSrcEnd) {
+ rglaTmp[1].len = (unsigned char) (colSrcEnd - colSrc);
+ rglaTmp[1].attr = (unsigned char) plaSrc->attr;
+ claTmp++;
+ } else {
+ rglaTmp[1].len = 0;
+ }
+ }
+
+ /*
+ * If the last affected cell doesn't end on our boundary, we
+ * create a new cell to be inserted. We take care of the final
+ * cell.
+ */
+ if (colLastMod + plaLastMod->len > colLast + 1) {
+ rglaTmp[2].len = (unsigned char) ((plaLastMod->len == 0xff) ?
+ 0xff :
+ colLastMod + (int) plaLastMod->len - colLast - 1);
+ rglaTmp[2].attr = plaLastMod->attr;
+ claTmp++;
+ } else {
+ rglaTmp[2].len = 0;
+ }
+
+ /*
+ * Then we move the info tail to its new place if needed
+ *
+ * UNDONE: Here we could use Move() instead of copying cell by cell
+ */
+ if (plaLastMod->len != 0xff) {
+ plaDst = plaFirstMod + claTmp;
+ plaSrc = plaLastMod + 1;
+ if (plaDst < plaSrc) {
+ do {
+ *plaDst++ = *plaSrc;
+ } while (plaSrc++->len != 0xff);
+ } else {
+ for (plaSrcSav = plaSrc; plaSrc->len != 0xff; plaSrc++) {
+ ;
+ }
+ plaDst += plaSrc - plaSrcSav;
+ do {
+ *plaDst-- = *plaSrc--;
+ } while (plaSrc >= plaSrcSav);
+ }
+ }
+
+ /*
+ * Finally insert the created cells
+ */
+ for (plaDst = plaFirstMod, claTmp = 0; claTmp < 3; claTmp++) {
+ if (claTmp == 1 && !fattr) {
+ /*
+ * UNDONE: Here we could use Move() instead of copying cell by cell
+ */
+ for (plaSrc = plaExt, colSrc = 0, colSrcEnd = colLast - colFirst + 1;
+ colSrc + plaSrc->len <= colSrcEnd;
+ plaDst++, colSrc += plaSrc++->len) {
+ *plaDst = *plaSrc;
+ }
+ }
+ if (rglaTmp[claTmp].len) {
+ *plaDst++ = rglaTmp[claTmp];
+ }
+ }
+}
+
+
+
+
+
+/*** rnOrder - ensure that a range is in correct first/last order
+*
+* Ensure that a range is in correct first/last order
+*
+* Input:
+* prn = Pointer to range
+*
+* Output:
+* *prn updated
+*
+*************************************************************************/
+void
+rnOrder (
+ rn *prn
+ ) {
+
+ rn rnTmp;
+
+ rnTmp.flFirst.lin = lmin (prn->flFirst.lin, prn->flLast.lin);
+ rnTmp.flLast.lin = lmax (prn->flFirst.lin, prn->flLast.lin);
+ rnTmp.flFirst.col = min (prn->flFirst.col, prn->flLast.col);
+ rnTmp.flLast.col = max (prn->flFirst.col, prn->flLast.col);
+
+ *prn = rnTmp;
+}
diff --git a/private/utils/mep/src/insert.c b/private/utils/mep/src/insert.c
new file mode 100644
index 000000000..cada84e59
--- /dev/null
+++ b/private/utils/mep/src/insert.c
@@ -0,0 +1,72 @@
+/* sinsert.c - stream insert of characters
+ *
+ * Modifications:
+ *
+ * 26-Nov-1991 mz Strip off near/far
+ */
+
+#include "mep.h"
+
+
+flagType
+insert (
+ CMDDATA argType,
+ ARG * pArg,
+ flagType fMeta
+ ) {
+
+ switch (pArg->argType) {
+
+ case BOXARG:
+ case LINEARG:
+ linsert (argType, pArg, fMeta);
+ break;
+
+ default:
+ sinsert (argType, pArg, fMeta);
+ break;
+ }
+ return TRUE;
+}
+
+
+
+flagType
+sinsert (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ ) {
+
+ switch (pArg->argType) {
+
+ case NOARG:
+ CopyBox (NULL, pFileHead, pArg->arg.noarg.x, pArg->arg.noarg.y,
+ pArg->arg.noarg.x, pArg->arg.noarg.y,
+ pArg->arg.noarg.x, pArg->arg.noarg.y);
+ return TRUE;
+
+ /* TEXTARG illegal */
+
+ case NULLARG:
+ flHigh.col = 0;
+ flHigh.lin++;
+ CopyStream (NULL, pFileHead, pArg->arg.nullarg.x, pArg->arg.nullarg.y,
+ 0, pArg->arg.nullarg.y + 1,
+ pArg->arg.nullarg.x, pArg->arg.nullarg.y);
+ return TRUE;
+
+ case LINEARG:
+ case BOXARG:
+ BoxToStream (pArg);
+
+ case STREAMARG:
+ CopyStream (NULL, pFileHead,
+ pArg->arg.streamarg.xStart, pArg->arg.streamarg.yStart,
+ pArg->arg.streamarg.xEnd, pArg->arg.streamarg.yEnd,
+ pArg->arg.streamarg.xStart, pArg->arg.streamarg.yStart);
+ return TRUE;
+ }
+
+ argData; fMeta;
+}
diff --git a/private/utils/mep/src/key.c b/private/utils/mep/src/key.c
new file mode 100644
index 000000000..32ae803e8
--- /dev/null
+++ b/private/utils/mep/src/key.c
@@ -0,0 +1,1087 @@
+/*** key.c - keyboard handling routines
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+*
+* 03-Dec-1990 ramonsa addapted from old key.c
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+#define INCL_DOSSEMAPHORES
+#include "mep.h"
+
+#include "keyboard.h"
+#include "keys.h"
+#include "cmds.h"
+
+
+
+
+//
+// CodeCmdMap
+//
+// The KeyCode field in the KEY_INFO structure used within the editor
+// is just an index into this table.
+//
+// This table contains pointers to the editor functions attached to
+// particular keystrokes.
+//
+PCMD CodeCmdMap [] =
+ {
+
+ //************************************************************
+/* Key */ //
+/* Index */ // 256 ASCII characters
+ //
+ // BugBug this is from the old code, there is no reason to have
+ // 256 entries here.
+ //
+/* 0000 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0004 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0008 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 000C */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0010 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0014 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0018 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 001C */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+
+/* 0020 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0024 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0028 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 002C */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0030 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0034 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0038 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 003C */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+
+/* 0040 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0044 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0048 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 004C */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0050 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0054 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0058 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 005C */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+
+/* 0060 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0064 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0068 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 006C */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0070 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0074 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0078 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 007C */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+
+/* 0080 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0084 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0088 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 008C */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0090 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0094 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0098 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 009C */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+
+/* 00A0 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 00A4 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 00A8 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 00AC */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 00B0 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 00B4 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 00B8 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 00BC */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+
+/* 00C0 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 00C4 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 00C8 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 00CC */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 00D0 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 00D4 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 00D8 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 00DC */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+
+/* 00E0 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 00E4 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 00E8 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 00EC */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 00F0 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 00F4 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 00F8 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 00FC */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+
+
+ //**********************************************************
+ //
+ // Special Keys
+ //
+ //
+ // Function Keys (f1-f12)
+ //
+/* 0100 */ CMD_unassigned, CMD_setfile, CMD_psearch, CMD_msearch,
+/* 0104 */ CMD_unassigned, CMD_window, CMD_zexecute, CMD_zexit,
+/* 0108 */ CMD_meta, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+
+ //
+ // Numeric white keys (Numlock off)
+ //
+ // Home End Left Right
+/* 010C */ CMD_begline, CMD_endline, CMD_left, CMD_right,
+ // Up Down Pgup Pgdown
+/* 0110 */ CMD_up, CMD_down, CMD_mpage, CMD_ppage,
+ // Ins Del Goto
+/* 0114 */ CMD_insertmode, CMD_delete, CMD_unassigned, CMD_unassigned,
+
+ //
+ // Numeric white keys (Numlock on) 0-9
+ //
+/* 0118 */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 011C */ CMD_graphic, CMD_graphic, CMD_graphic, CMD_graphic,
+/* 0120 */ CMD_graphic, CMD_graphic, CMD_unassigned, CMD_unassigned,
+
+ //
+ // Numeric grey keys
+ //
+ // NUM- NUM+ NUM* NUM/
+/* 0124 */ CMD_graphic, CMD_zpick, CMD_graphic, CMD_graphic,
+ // NUMENTER
+/* 0128 */ CMD_emacsnewl, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+
+ // Named Keys :
+ //
+ // SPACE BKSP TAB BKTAB
+/* 012C */ CMD_unassigned, CMD_emacscdel, CMD_tab, CMD_unassigned,
+ // ESC ENTER
+/* 0130 */ CMD_cancel, CMD_emacsnewl, CMD_unassigned, CMD_unassigned,
+
+ //
+ // Additional:
+ //
+/* 0134 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+/* 0138 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+/* 013C */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+
+
+
+ //*************************************************************
+ //
+ // ALT+ 0-9
+ //
+/* 0140 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+/* 0144 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+/* 0148 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+
+ //
+ // ALT+ a-z
+ //
+/* 014C */ CMD_doarg, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+/* 0150 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+/* 0154 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+/* 0158 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+/* 015C */ CMD_unassigned, CMD_record, CMD_unassigned, CMD_unassigned,
+/* 0160 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+/* 0164 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+
+ //
+ // ALT+ function keys (f1-f12)
+ //
+/* 0168 */ CMD_unassigned, CMD_zprint, CMD_unassigned, CMD_unassigned,
+/* 016C */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+/* 0170 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+
+ //
+ // ALT+ lower case punctuation
+ //
+ // ` - = [
+/* 0174 */ CMD_unassigned, CMD_unassigned, CMD_assign, CMD_unassigned,
+ // ] \ ; '
+/* 0178 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+ // , . /
+/* 017C */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+
+ //
+ // ALT+ numeric white keys (Numlock off)
+ //
+ // Home End Left Right
+/* 0180 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+ // Up Down Pgup Pgdown
+/* 0184 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+ // Ins Del Goto
+/* 0188 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+
+ //
+ // ALT+ numeric white keys (Numlock on) 0-9
+ //
+/* 018C */ CMD_noop, CMD_noop, CMD_noop, CMD_noop,
+/* 0190 */ CMD_noop, CMD_noop, CMD_noop, CMD_noop,
+/* 0194 */ CMD_noop, CMD_noop, CMD_noop, CMD_unassigned,
+
+ //
+ // ALT+ numeric grey keys
+ //
+ // NUM- NUM+ NUM* NUM/
+/* 0198 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+ // NUMENTER
+/* 019C */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+
+ //
+ // ALT+ named keys:
+ //
+ // SPACE BKSP TAB BKTAB
+/* 01A0 */ CMD_unassigned, CMD_undo, CMD_unassigned, CMD_unassigned,
+ // ESC ENTER
+/* 01A4 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+
+ //
+ // Additional:
+ //
+/* 01A8 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+/* 01AC */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+/* 01B0 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+
+
+
+ //*************************************************************
+ //
+ // CTRL+ 0-9
+ //
+/* 01B4 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+/* 01B8 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+/* 01BC */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+
+ //
+ // CTRL+ a-z
+ //
+/* 01C0 */ CMD_mword, CMD_boxstream, CMD_ppage, CMD_right,
+/* 01C4 */ CMD_up, CMD_pword, CMD_cdelete, CMD_unassigned,
+/* 01C8 */ CMD_unassigned, CMD_sinsert, CMD_unassigned, CMD_replace,
+/* 01CC */ CMD_mark, CMD_linsert, CMD_textarg, CMD_quote,
+/* 01D0 */ CMD_unassigned, CMD_mpage, CMD_left, CMD_tell,
+/* 01D4 */ CMD_lastselect, CMD_insertmode, CMD_mlines, CMD_down,
+/* 01D8 */ CMD_ldelete, CMD_plines, CMD_unassigned, CMD_unassigned,
+
+ //
+ // CTRL+ function keys (f1-f12)
+ //
+/* 01DC */ CMD_unassigned, CMD_unassigned, CMD_compile, CMD_unassigned,
+/* 01E0 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_zprint,
+/* 01E4 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+
+ //
+ // CTRL+ lower case punctuation
+ //
+ // ` - = [
+/* 01E8 */ CMD_unassigned, CMD_unassigned, CMD_noop, CMD_pbal,
+ // ] \ ; '
+/* 01EC */ CMD_setwindow, CMD_qreplace, CMD_unassigned, CMD_unassigned,
+ // , . /
+/* 01F0 */ CMD_unassigned, CMD_noop, CMD_unassigned, CMD_unassigned,
+
+
+ //
+ // CTRL+ numeric white keys (Numlock off)
+ //
+ // Home End Left Right
+/* 01F4 */ CMD_home, CMD_unassigned, CMD_mword, CMD_pword,
+ // Up Down Pgup Pgdown
+/* 01F8 */ CMD_unassigned, CMD_unassigned, CMD_begfile, CMD_endfile,
+ // Ins Del Goto
+/* 01FC */ CMD_zpick, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+
+ //
+ // CTRL+ numeric white keys (Numlock on) (0-9)
+ //
+/* 0200 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+/* 0204 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+/* 0208 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+
+ //
+ // CTRL+ numeric grey keys
+ //
+ // NUM- NUM+ NUM* NUM/
+/* 020C */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+ // NUMENTER
+/* 0210 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+
+ //
+ // CTRL+ named keys
+ //
+ // SPACE BKSP TAB BKTAB
+/* 0214 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+ // ESC ENTER
+/* 0218 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+
+ //
+ // Additional:
+ //
+/* 021C */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+/* 0220 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+/* 0224 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+
+
+
+ //*************************************************************
+ //
+ // SHIFT+ function keys (f1-f12)
+ //
+/* 0228 */ CMD_information,CMD_unassigned, CMD_nextmsg, CMD_unassigned,
+/* 022C */ CMD_unassigned, CMD_searchall, CMD_refresh, CMD_zinit,
+/* 0230 */ CMD_zspawn, CMD_information,CMD_unassigned, CMD_unassigned,
+
+ //
+ // SHIFT+ numeric white keys (Numlock off)
+ //
+ // Home End Left Right
+/* 0234 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+ // Up Down Pgup Pgdown
+/* 0238 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+ // Ins Del Goto
+/* 023C */ CMD_put, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+
+ //
+ // SHIFT+ numeric white keys (Numlock on) (0-9)
+ //
+/* 0240 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+/* 0244 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+/* 0248 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+
+ //
+ // SHIFT+ numeric grey keys
+ //
+ // NUM- NUM+ NUM* NUM/
+/* 024C */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+ // NUMENTER
+/* 0250 */ CMD_unassigned, CMD_unassigned, CMD_unassigned, CMD_unassigned,
+
+ //
+ // SHIFT+ named keys
+ //
+ // SPACE BKSP TAB BKTAB
+/* 0254 */ CMD_graphic, CMD_unassigned, CMD_backtab, CMD_unassigned,
+ // ESC ENTER
+/* 0258 */ CMD_unassigned, CMD_emacsnewl, CMD_unassigned, CMD_unassigned,
+
+
+ NULL
+};
+
+#define LAST_CODE 0x25b
+
+
+typedef struct KEYNAME {
+ WORD KeyCode; // Key Code
+ char *pName; // name of key
+} KEYNAME, *PKEYNAME;
+
+
+//
+// CodeNameMap
+//
+// This table maps KeyCodes to their corresponding printable name
+// and vice-versa.
+//
+KEYNAME CodeNameMap[] =
+{
+
+ { 0x0100, "f1" }, { 0x0101, "f2" },
+ { 0x0102, "f3" }, { 0x0103, "f4" },
+ { 0x0104, "f5" }, { 0x0105, "f6" },
+ { 0x0106, "f7" }, { 0x0107, "f8" },
+ { 0x0108, "f9" }, { 0x0109, "f10" },
+ { 0x010A, "f11" }, { 0x010B, "f12" },
+
+ { 0x010C, "home" }, { 0x010D, "end" },
+ { 0x010E, "left" }, { 0x010F, "right" },
+ { 0x0110, "up" }, { 0x0111, "down" },
+ { 0x0112, "pgup" }, { 0x0113, "pgdn" },
+ { 0x0114, "ins" }, { 0x0115, "del" },
+ { 0x0116, "goto" },
+
+ { 0x0118, "num0" }, { 0x0119, "num1" },
+ { 0x011A, "num2" }, { 0x011B, "num3" },
+ { 0x011C, "num4" }, { 0x011D, "num5" },
+ { 0x011E, "num6" }, { 0x011F, "num7" },
+ { 0x0120, "num8" }, { 0x0121, "num9" },
+
+ { 0x0124, "num-" }, { 0x0125, "num+" },
+ { 0x0126, "num*" }, { 0x0127, "num/" },
+ { 0x0128, "numenter" },
+
+ { 0x012C, "space" }, { 0x012D, "bksp" },
+ { 0x012E, "tab" }, { 0x012F, "bktab" },
+ { 0x0130, "esc" }, { 0x0131, "enter" },
+
+ { 0x0140, "alt+0" }, { 0x0141, "alt+1" },
+ { 0x0142, "alt+2" }, { 0x0143, "alt+3" },
+ { 0x0144, "alt+4" }, { 0x0145, "alt+5" },
+ { 0x0146, "alt+6" }, { 0x0147, "alt+7" },
+ { 0x0148, "alt+8" }, { 0x0149, "alt+9" },
+
+ { 0x014C, "alt+a" }, { 0x014D, "alt+b" },
+ { 0x014E, "alt+c" }, { 0x014F, "alt+d" },
+ { 0x0150, "alt+e" }, { 0x0151, "alt+f" },
+ { 0x0152, "alt+g" }, { 0x0153, "alt+h" },
+ { 0x0154, "alt+i" }, { 0x0155, "alt+j" },
+ { 0x0156, "alt+k" }, { 0x0157, "alt+l" },
+ { 0x0158, "alt+m" }, { 0x0159, "alt+n" },
+ { 0x015A, "alt+o" }, { 0x015B, "alt+p" },
+ { 0x015C, "alt+q" }, { 0x015D, "alt+r" },
+ { 0x015E, "alt+s" }, { 0x015F, "alt+t" },
+ { 0x0160, "alt+u" }, { 0x0161, "alt+v" },
+ { 0x0162, "alt+w" }, { 0x0163, "alt+x" },
+ { 0x0164, "alt+y" }, { 0x0165, "alt+z" },
+
+ { 0x0168, "alt+f1" }, { 0x0169, "alt+f2" },
+ { 0x016A, "alt+f3" }, { 0x016B, "alt+f4" },
+ { 0x016C, "alt+f5" }, { 0x016D, "alt+f6" },
+ { 0x016E, "alt+f7" }, { 0x016F, "alt+f8" },
+ { 0x0170, "alt+f9" }, { 0x0171, "alt+f10" },
+ { 0x0172, "alt+f11" }, { 0x0173, "alt+f12" },
+
+ { 0x0174, "alt+`" }, { 0x0175, "alt+-" },
+ { 0x0176, "alt+=" }, { 0x0177, "alt+[" },
+ { 0x0178, "alt+]" }, { 0x0179, "alt+\\" },
+ { 0x017A, "alt+;" }, { 0x017B, "alt+'" },
+ { 0x017C, "alt+," }, { 0x017D, "alt+." },
+ { 0x017E, "alt+/" },
+
+ { 0x0180, "alt+home" }, { 0x0181, "alt+end" },
+ { 0x0182, "alt+left" }, { 0x0183, "alt+right" },
+ { 0x0184, "alt+up" }, { 0x0185, "alt+down" },
+ { 0x0186, "alt+pgup" }, { 0x0187, "alt+pgdn" },
+ { 0x0188, "alt+ins" }, { 0x0189, "alt+del" },
+ { 0x018A, "alt+goto" },
+
+ { 0x018C, "alt+num0" }, { 0x018D, "alt+num1" },
+ { 0x018E, "alt+num2" }, { 0x018F, "alt+num3" },
+ { 0x0190, "alt+num4" }, { 0x0191, "alt+num5" },
+ { 0x0192, "alt+num6" }, { 0x0193, "alt+num7" },
+ { 0x0194, "alt+num8" }, { 0x0195, "alt+num9" },
+
+ { 0x0198, "alt+num-" }, { 0x0199, "alt+num+" },
+ { 0x019A, "alt+num*" }, { 0x019B, "alt+num/" },
+ { 0x019C, "alt+numenter" },
+
+ { 0x01A0, "alt+space" }, { 0x01A1, "alt+bksp" },
+ { 0x01A2, "alt+tab" }, { 0x01A3, "alt+bktab" },
+ { 0x01A4, "alt+esc" }, { 0x01A5, "alt+enter" },
+
+ { 0x01B4, "ctrl+0" }, { 0x01B5, "ctrl+1" },
+ { 0x01B6, "ctrl+@" },
+ { 0x01B6, "ctrl+2" }, { 0x01B7, "ctrl+3" },
+ { 0x01B8, "ctrl+4" }, { 0x01B9, "ctrl+5" },
+ { 0x01BA, "ctrl+^" },
+ { 0x01BA, "ctrl+6" }, { 0x01BB, "ctrl+7" },
+ { 0x01BC, "ctrl+8" }, { 0x01BD, "ctrl+9" },
+
+ { 0x01C0, "ctrl+a" }, { 0x01C1, "ctrl+b" },
+ { 0x01C2, "ctrl+c" }, { 0x01C3, "ctrl+d" },
+ { 0x01C4, "ctrl+e" }, { 0x01C5, "ctrl+f" },
+ { 0x01C6, "ctrl+g" }, { 0x01C7, "ctrl+h" },
+ { 0x01C8, "ctrl+i" }, { 0x01C9, "ctrl+j" },
+ { 0x01CA, "ctrl+k" }, { 0x01CB, "ctrl+l" },
+ { 0x01CC, "ctrl+m" }, { 0x01CD, "ctrl+n" },
+ { 0x01CE, "ctrl+o" }, { 0x01CF, "ctrl+p" },
+ { 0x01D0, "ctrl+q" }, { 0x01D1, "ctrl+r" },
+ { 0x01D2, "ctrl+s" }, { 0x01D3, "ctrl+t" },
+ { 0x01D4, "ctrl+u" }, { 0x01D5, "ctrl+v" },
+ { 0x01D6, "ctrl+w" }, { 0x01D7, "ctrl+x" },
+ { 0x01D8, "ctrl+y" }, { 0x01D9, "ctrl+z" },
+
+ { 0x01DC, "ctrl+f1" }, { 0x01DD, "ctrl+f2" },
+ { 0x01DE, "ctrl+f3" }, { 0x01DF, "ctrl+f4" },
+ { 0x01E0, "ctrl+f5" }, { 0x01E1, "ctrl+f6" },
+ { 0x01E2, "ctrl+f7" }, { 0x01E3, "ctrl+f8" },
+ { 0x01E4, "ctrl+f9" }, { 0x01E5, "ctrl+f10" },
+ { 0x01E6, "ctrl+f11" }, { 0x01E7, "ctrl+f12" },
+
+ { 0x01E8, "ctrl+`" }, { 0x01E9, "ctrl+-" },
+ { 0x01EA, "ctrl+=" }, { 0x01EB, "ctrl+[" },
+ { 0x01EC, "ctrl+]" }, { 0x01ED, "ctrl+\\" },
+ { 0x01EE, "ctrl+;" }, { 0x01EF, "ctrl+'" },
+ { 0x01F0, "ctrl+," }, { 0x01F1, "ctrl+." },
+ { 0x01F2, "ctrl+/" },
+
+ { 0x01F4, "ctrl+home" }, { 0x01F5, "ctrl+end" },
+ { 0x01F6, "ctrl+left" }, { 0x01F7, "ctrl+right" },
+ { 0x01F8, "ctrl+up" }, { 0x01F9, "ctrl+down" },
+ { 0x01FA, "ctrl+pgup" }, { 0x01FB, "ctrl+pgdn" },
+ { 0x01FC, "ctrl+ins" }, { 0x01FD, "ctrl+del" },
+ { 0x01FE, "ctrl+goto" },
+
+ { 0x0200, "ctrl+num0" }, { 0x0201, "ctrl+num1" },
+ { 0x0202, "ctrl+num2" }, { 0x0203, "ctrl+num3" },
+ { 0x0204, "ctrl+num4" }, { 0x0205, "ctrl+num5" },
+ { 0x0206, "ctrl+num6" }, { 0x0207, "ctrl+num7" },
+ { 0x0208, "ctrl+num8" }, { 0x0209, "ctrl+num9" },
+
+ { 0x020C, "ctrl+num-" }, { 0x020D, "ctrl+num+" },
+ { 0x020E, "ctrl+num*" }, { 0x020F, "ctrl+num/" },
+ { 0x0210, "ctrl+numenter" },
+
+ { 0x0214, "ctrl+space" }, { 0x0215, "ctrl+bksp" },
+ { 0x0216, "ctrl+tab" }, { 0x0217, "ctrl+bktab" },
+ { 0x0218, "ctrl+esc" }, { 0x0219, "ctrl+enter" },
+
+ { 0x0228, "shift+f1" }, { 0x0229, "shift+f2" },
+ { 0x022A, "shift+f3" }, { 0x022B, "shift+f4" },
+ { 0x022C, "shift+f5" }, { 0x022D, "shift+f6" },
+ { 0x022E, "shift+f7" }, { 0x022F, "shift+f8" },
+ { 0x0230, "shift+f9" }, { 0x0231, "shift+f10" },
+ { 0x0232, "shift+f11" }, { 0x0233, "shift+f12" },
+
+ { 0x0234, "shift+home" }, { 0x0235, "shift+end" },
+ { 0x0236, "shift+left" }, { 0x0237, "shift+right" },
+ { 0x0238, "shift+up" }, { 0x0239, "shift+down" },
+ { 0x023A, "shift+pgup" }, { 0x023B, "shift+pgdn" },
+ { 0x023C, "shift+ins" }, { 0x023D, "shift+del" },
+ { 0x023E, "shift+goto" },
+
+ { 0x0240, "shift+num0" }, { 0x0241, "shift+num1" },
+ { 0x0242, "shift+num2" }, { 0x0243, "shift+num3" },
+ { 0x0244, "shift+num4" }, { 0x0245, "shift+num5" },
+ { 0x0246, "shift+num6" }, { 0x0247, "shift+num7" },
+ { 0x0248, "shift+num8" }, { 0x0249, "shift+num9" },
+
+ { 0x024C, "shift+num-" }, { 0x024D, "shift+num+" },
+ { 0x024E, "shift+num*" }, { 0x024F, "shift+num/" },
+ { 0x0250, "shift+numenter"},
+
+ { 0x0254, "shift+space" }, { 0x0255, "shift+bksp" },
+ { 0x0256, "shift+tab" }, { 0x0257, "shift+bktab" },
+ { 0x0258, "shift+esc" }, { 0x0259, "shift+enter" },
+
+
+ { 0x0000, NULL }
+};
+
+char UnknownKey [] = "???";
+
+
+/*** ReadCmd - read the next command from the keyboard.
+*
+* ReadCmd is used whenever an editor function is being read. It reads a
+* keystroke and looks it up in the key definition table and returns the
+* matching function.
+*
+* Input:
+* none
+*
+* Globals:
+* keyCmd = last key hit. Updated.
+*
+* Output:
+* Returns a pointer to function. If not a macro, the function's arg is the
+* keystroke actually used. In addition, the key used is placed in wKeyCmd.
+*
+*************************************************************************/
+PCMD
+ReadCmd (
+ void
+ ) {
+
+ WORD i; /* key code */
+ EVTargs e; /* arg struct for declaring event*/
+
+ do {
+ if (!TypeAhead () ) {
+
+ SetEvent( semIdle );
+
+ keyCmd = TranslateKey (ReadChar ());
+
+ WaitForSingleObject(semIdle, INFINITE);
+ } else {
+ keyCmd = TranslateKey (ReadChar ());
+ }
+ e.arg.key = keyCmd.KeyInfo;
+ } while (DeclareEvent (EVT_RAWKEY, (EVTargs *)&e));
+
+ if (fCtrlc && keyCmd.KeyCode == 0) {
+ return NameToFunc ("cancel");
+ }
+
+ i = keyCmd.KeyCode;
+
+ if (i > 0 && i <= LAST_CODE) {
+ if ((PVOID)CodeCmdMap[i]->func != (PVOID)macro) {
+ if ( (PVOID)CodeCmdMap[i]->func == (PVOID)(unassigned) ) {
+ CodeCmdMap[i]->arg = (long)keyCmd.KeyCode;
+ } else {
+ CodeCmdMap[i]->arg = keyCmd.KeyInfo.LongData;
+ }
+ }
+ return CodeCmdMap[i];
+ }
+
+ return (PCMD) &cmdUnassigned;
+}
+
+
+
+/*** FreeMacs - Unassign all keys assigned to macros
+*
+* This routine is used to unassign all keys that are assigned to macro
+* definitions. Called immediately prior to releasing all macro definitions.
+*
+* Input:
+* none
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void
+FreeMacs (
+ void
+ ) {
+ int i = 0;
+
+ while (CodeCmdMap[i]) {
+ if ((PVOID)CodeCmdMap[i]->func == (PVOID)macro) {
+ CodeCmdMap[i] = CMD_unassigned;
+ }
+ i++;
+ }
+}
+
+
+
+
+
+
+
+
+
+/*** CodeToName - convert a key codeinto a printable name for the keystroke
+*
+* Purpose:
+*
+* If the index is >= 0x0100, we use the text corresponding to the key in
+* the special key table. If the index is <= 0x00FF, we look up the
+* key (= index) in the special key table and use the corresponding string.
+* If the key is < 0x0020, we display it as ^ followed by a letter. If
+* the key is >= 0x0080, we display the key as alt-ddd. Otherwise, the
+* index itself is a printable character.
+*
+* Input:
+*
+* index Index of keystroke of interest
+*
+* Output:
+*
+* p buffer to place readable name
+*
+*************************************************************************/
+void
+CodeToName (
+ WORD Code,
+ char *p
+ ) {
+
+ WORD i = 0;
+ char * pName = NULL;
+
+ while (CodeNameMap[i].pName != NULL) {
+ if (CodeNameMap[i].KeyCode == (WORD)Code) {
+ pName = CodeNameMap[i].pName;
+ break;
+ }
+ i++;
+ }
+
+ if (pName) {
+ strcpy(p, pName);
+ } else {
+ *p = '\0';
+ }
+}
+
+
+
+
+
+/*** NameToCode - convert a key name into a key code
+*
+* Purpose:
+*
+* If the name is one character, then index = first char of name. If name
+* is two characters and begins with ^, then index = control-second
+* character. If the name is alt-ddd, then use ddd as the index.
+* Otherwise, look up name in key table, convert the found keystroke to an
+* index and return that index.
+*
+* Input:
+*
+* pName character pointer to name being indexed
+*
+* Output:
+*
+* Returns 0-based index of matching key or 0 if not found
+*
+*************************************************************************/
+WORD
+NameToCode (
+ char *pName
+ )
+{
+
+ WORD i = (WORD)strlen (pName);
+ WORD Code = 0;
+ char Name[20];
+
+ if (i == 1) {
+ //
+ // Code is ascii
+ //
+ return (WORD)(pName[0]);
+ } else if (i == 2 && pName[0] == '^') {
+ sprintf(Name, "ctrl+%c", pName[1]);
+ } else {
+ strcpy(Name, pName);
+ }
+
+ i = 0;
+ while (CodeNameMap[i].pName != NULL) {
+ if (!strcmp(Name, CodeNameMap[i].pName)) {
+ Code = CodeNameMap[i].KeyCode;
+ break;
+ }
+ i++;
+ }
+
+ if (Code) {
+ return Code;
+ } else {
+ return 0;
+ }
+}
+
+
+
+
+/*** SetKey - associate an editor function with a keystroke
+*
+* SetKey is used to create a keyboard assignment. Any current assignment to
+* the keystroke is discarded and each time that particular keystroke is
+* seen, the corresponding editor function will be invoked.
+*
+* Input:
+* name = local pointer to name of string being assigned
+* p = pointer to keystroke
+*
+* Output:
+* Returns TRUE if a successful assignment was made.
+*
+*************************************************************************/
+flagType
+SetKey (
+ char *name,
+ char *p
+ )
+{
+
+ WORD Code;
+ buffer keybuf;
+ PCMD pCmd;
+
+ if (strlen(strcpy (keybuf, p)) > 1) {
+ _strlwr (keybuf) ;
+ }
+ Code = NameToCode (keybuf);
+ if (Code) {
+ if (pCmd = NameToFunc (name)) {
+ CodeCmdMap[Code] = pCmd;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+
+/*** FuncOut - append into a file current key assignments
+*
+* Purpose:
+*
+* Input:
+*
+* pFunc pointer to command structure
+* pFile file to place text
+*
+* Output: None.
+*
+*************************************************************************/
+void
+FuncOut (
+ PCMD pFunc,
+ PFILE pFile
+ ) {
+
+ WORD i;
+ char *p;
+ flagType fFirst;
+
+ if ((PVOID)pFunc->func != (PVOID)graphic && (PVOID)pFunc->func != (PVOID)unassigned) {
+ sprintf (buf, "%20Fs:", pFunc->name);
+ p = buf + 21;
+ fFirst = TRUE;
+
+ for (i = 0; CodeCmdMap[i] != NULL; i++) {
+ if (CodeCmdMap[i] == pFunc) {
+ CodeToName (i, p);
+ AppFile (buf, pFile);
+ fFirst = FALSE;
+ }
+ }
+
+ if (fFirst) {
+ sprintf (p, "is unassigned");
+ buf[0] = ';';
+ AppFile (buf, pFile);
+ }
+ }
+}
+
+
+
+
+/*** FuncToKeys - return all key names for a key attached to the given function
+*
+* Purpose:
+*
+* Input:
+*
+* Output:
+*
+* Returns
+*
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+char *
+FuncToKeys (
+ PCMD pFunc,
+ char * dst
+ ) {
+
+ WORD i;
+ flagType f = FALSE;
+
+ for (i = 0; CodeCmdMap[i] != NULL; i++) {
+ if (CodeCmdMap[i] == pFunc) {
+ if (f) {
+ sprintf (strend (dst), " and ");
+ }
+ f = TRUE;
+ CodeToName (i, strend (dst));
+ }
+ }
+
+ if (!f) {
+ sprintf (strend (dst), "is unassigned");
+ }
+
+ return dst;
+}
+
+
+
+
+/*** FuncToKey - return a key name for a key attached to the given function
+*
+* Purpose:
+*
+* used only by showasg ()
+*
+* Input:
+*
+* Output:
+*
+* Returns
+*
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+char *
+FuncToKey (
+ PCMD pFunc,
+ char * dst
+ ) {
+
+ WORD i;
+
+ dst[0] = '\0';
+
+ for (i = 0; CodeCmdMap[i] != NULL; i++) {
+ if (CodeCmdMap[i] == pFunc) {
+ CodeToName (i, dst);
+ break;
+ }
+ }
+ return dst;
+}
+
+
+
+
+/*** UnassignedOut - Dump the names of all unassigned keys to a file
+*
+* Purpose:
+*
+* Used by showasg to generate the table of unassigned keys.
+*
+* Input:
+* pFile - File to dump to.
+*
+* Output: None
+*
+*************************************************************************/
+void
+UnassignedOut (
+ PFILE pFile
+ ) {
+
+ WORD i, col = 0;
+ char KeyName[20];
+
+ buf[0] = ';';
+
+ for (i = 0; CodeCmdMap[i] != NULL; i++) {
+ if ((PVOID)CodeCmdMap[i]->func == (PVOID)unassigned) {
+ CodeToName (i, KeyName);
+ sprintf (buf + col * 16 + 1, "%14s |", KeyName);
+ if (col++ == 4) {
+ AppFile (buf, pFile);
+ col = 0;
+ }
+ }
+ }
+}
+
+
+
+
+
+/****************************************************************************
+ * *
+ * SetKeyboard - Handle 'keyboard:' editor switch *
+ * *
+ * DESCRIPTION: *
+ * *
+ * In order to support the extra keys on the IBM Enhanced keyboards, *
+ * it is necessary to use a separate INT 16H service to characters. *
+ * This can cause two problems: *
+ * *
+ * 1. If the keyboard is mistakenly identified as enhanced when *
+ * it is not, unpredictable bad things may happen. *
+ * *
+ * 2. Mouse menus don't support the enhanced keyboard BIOS call. *
+ * There may be other programs that do not either. *
+ * *
+ * The user can then set 'keyboard:compatible' to solve the problem. *
+ * This will prevent the user of F11, F12 and the grey keys. *
+ * *
+ * Switch values are: *
+ * *
+ * keyboard:enhanced - Use INT 16H, AH = 10H * *
+ * keyboard:compatible - Use INT 16H, AH = 0 * *
+ * keyboard: - Detect keyboard type and use that *
+ * *
+ * INPUT: *
+ * *
+ * lpszVal String following the colon *
+ * *
+ * OUTPUT: *
+ * *
+ * Int16_CmdBase Set to 0 or 10H *
+ * *
+ * RETURNS: *
+ * *
+ * TRUE if lpszVal is acceptable *
+ * FALSE if lpszVal is not recognized *
+ * FALSE if lpszVal is 'enhanced', but we detect a compatible keyboard *
+ * *
+ ****************************************************************************/
+char *
+SetKeyboard (
+ char *lpszVal
+ ) {
+
+ return NULL;
+
+ lpszVal;
+}
+
+
+
+/*** ReadCmdAndKey - Read a key, return the command and key name
+*
+* Purpose:
+*
+* This is used only by the <tell> function. Waits for a key press,
+* then fills 'buf' with the name of the key.
+*
+* Input:
+* buf - Place for the key name
+*
+* Output:
+*
+* buf - Gets filled with keyname.
+*
+* Returns the PCMD attached to the key.
+*
+*************************************************************************/
+PCMD
+ReadCmdAndKey (
+ char * buf
+ ) {
+
+ WORD i;
+ EVTargs e;
+ PCMD pCmd;
+ EDITOR_KEY k;
+
+ do {
+ if (!TypeAhead () ) {
+
+ SetEvent( semIdle);
+ k = TranslateKey (ReadChar ());
+ WaitForSingleObject( semIdle, INFINITE);
+ } else {
+ k = TranslateKey (ReadChar ());
+ }
+ e.arg.key = k.KeyInfo;
+ } while (DeclareEvent (EVT_RAWKEY, (EVTargs *)&e));
+
+ if (i = k.KeyCode) {
+ CodeToName (i, buf);
+ pCmd = CodeCmdMap[i];
+ } else {
+ strcpy (buf, UnknownKey);
+ pCmd = CMD_unassigned;
+ }
+
+ return pCmd;
+}
+
+//
+// No-op, provided for compatibility with other versions of MEP, which do
+// not map the entire keyboard
+//
+flagType
+noop (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ )
+{
+ argData; pArg; fMeta;
+
+ return TRUE;
+}
diff --git a/private/utils/mep/src/keyboard.c b/private/utils/mep/src/keyboard.c
new file mode 100644
index 000000000..57a76ca73
--- /dev/null
+++ b/private/utils/mep/src/keyboard.c
@@ -0,0 +1,240 @@
+#include "mep.h"
+#include "keyboard.h"
+
+void
+mepInitKeyboard (
+ void
+ ) {
+
+ KBDMODE Mode;
+
+ Mode = CONS_ENABLE_ECHO_INPUT | CONS_ENABLE_WINDOW_INPUT | CONS_ENABLE_MOUSE_INPUT ;
+ consoleSetMode(Mode);
+}
+
+
+
+void
+KbHook (
+ void
+ ){
+
+ KBDMODE Mode = OriginalScreenMode & ~(CONS_ENABLE_LINE_INPUT | CONS_ENABLE_PROCESSED_INPUT | CONS_ENABLE_ECHO_INPUT );
+ consoleSetMode(Mode);
+ consoleFlushInput();
+}
+
+
+
+void
+KbUnHook (
+ void
+ ){
+
+ consoleSetMode(OriginalScreenMode);
+}
+
+
+
+
+KBDMODE
+KbGetMode (
+ void
+ ){
+
+ KBDMODE Mode;
+
+ consoleGetMode(&Mode);
+ return Mode;
+}
+
+
+
+void
+KbSetMode (
+ KBDMODE Mode
+ ){
+
+ consoleSetMode(Mode);
+}
+
+
+
+BOOL
+TypeAhead (
+ void
+ ) {
+ return consoleIsKeyAvailable();
+}
+
+
+
+
+
+KBDKEY
+ReadChar (
+ void
+ ) {
+
+ KBDKEY kbdi;
+ consoleGetKey(&kbdi, TRUE);
+ return kbdi;
+}
+
+
+
+void
+GetScreenSize (
+ int* pYsize,
+ int* pXsize
+ ) {
+
+ SCREEN_INFORMATION ScreenInformation;
+ consoleGetScreenInformation( MepScreen, &ScreenInformation );
+ *pYsize = (int)(ScreenInformation.NumberOfRows);
+ *pXsize = (int)(ScreenInformation.NumberOfCols);
+
+}
+
+
+
+
+flagType
+SetScreenSize (
+ int YSize,
+ int XSize
+ ) {
+
+ if (consoleSetScreenSize( MepScreen, YSize, XSize)) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+
+
+void
+SetVideoState (
+ int handle
+ ) {
+
+ consoleClearScreen(MepScreen, TRUE);
+
+ handle;
+}
+
+
+
+
+
+
+
+void
+SaveScreen (
+ void
+ ) {
+ //KBDMODE Mode = OriginalScreenMode & ~(CONS_ENABLE_LINE_INPUT | CONS_ENABLE_PROCESSED_INPUT | CONS_ENABLE_ECHO_INPUT );
+ //consoleSetMode(Mode);
+ consoleSetCurrentScreen(MepScreen);
+}
+
+
+
+
+void
+RestoreScreen (
+ void
+ ) {
+ //consoleSetMode(OriginalScreenMode);
+ consoleSetCurrentScreen(OriginalScreen);
+}
+
+
+
+void
+WindowChange (
+ ROW Rows,
+ COLUMN Cols
+ )
+{
+
+ char bufLocal[2];
+
+ if ( (cWin > 1) && (( Rows > (ROW)(YSIZE+2) ) || ( Cols > (COLUMN)(XSIZE) )) ) {
+ //
+ // Won't allow to grow the screen if we have more than one window.
+ //
+ consoleSetScreenSize(MepScreen, YSIZE+2, XSIZE );
+ disperr (MSG_ASN_WINCHG);
+ return;
+ }
+
+ // EnterCriticalSection( &ScreenCriticalSection );
+
+ // consoleClearScreen( MepScreen, FALSE );
+
+
+ if ( Rows == (ROW)YSIZE+3 ) {
+ //
+ // Erase the status line.
+ //
+
+ bufLocal[0] = ' ';
+ bufLocal[1] = '\0';
+ soutb(0, YSIZE+1, bufLocal, fgColor);
+ }
+
+ YSIZE = Rows-2;
+ XSIZE = Cols;
+ // LeaveCriticalSection( &ScreenCriticalSection );
+ SetScreen();
+ Display();
+}
+
+
+/* SetCursorSize - set the cursor size
+ *
+ */
+char *
+SetCursorSizeSw (
+ char *val
+ )
+{
+ int i;
+ buffer tmpval;
+
+ strcpy ((char *) tmpval, val);
+
+ i = atoi (tmpval);
+
+ if (i != 0 && i != 1) {
+ return "CursorSize: Value must be 0 or 1";
+ }
+
+ CursorSize = i;
+
+ return SetCursorSize( CursorSize );
+
+}
+
+
+char *
+SetCursorSize (
+ int Size
+ )
+{
+ ULONG CursorStyle;
+
+ if ( Size == 0 ) {
+ CursorStyle = CURSOR_STYLE_UNDERSCORE;
+ } else {
+ CursorStyle = CURSOR_STYLE_BOX;
+ }
+
+ if ( !consoleSetCursorStyle( MepScreen, CursorStyle ) ) {
+ return "CursorSize: Cannot set Cursor size";
+ }
+
+ return NULL;
+}
diff --git a/private/utils/mep/src/lang.c b/private/utils/mep/src/lang.c
new file mode 100644
index 000000000..ed6634964
--- /dev/null
+++ b/private/utils/mep/src/lang.c
@@ -0,0 +1,169 @@
+/*** lang.c - Language dependent routines
+*
+* Copyright <C> 1989, Microsoft Corporation
+*
+* Revision History:
+*
+* 26-Nov-1991 mz Strip off near/far
+*************************************************************************/
+#include "mep.h"
+
+typedef int ( _CRTAPI1 *STRCMP) (const char *, const char *);
+
+
+/* return index+1 of first string s that is in table */
+int
+tblFind (
+ char * tbl[],
+ char * s,
+ flagType fCase
+ )
+{
+ int i;
+ STRCMP f;
+
+ f = fCase ? (STRCMP)FNADDR(strcmp) : (STRCMP)FNADDR(_stricmp);
+ for (i=0; tbl[i]; i++) {
+ if (!(*f) (tbl[i], s)) {
+ return i+1;
+ }
+ }
+ return 0;
+}
+
+
+
+
+flagType
+parseline (
+ char *pbuf,
+ char **ppbegtok,
+ char **ppendtok
+ ) {
+
+ char *p1, *p2;
+
+ p1 = whiteskip (pbuf);
+ if (!*p1) {
+ return FALSE;
+ } else if (*(p2 = whitescan (p1))) {
+ *p2++ = 0;
+ p2 += strlen( p2 ) - 1;
+ while (*p2)
+ if (*p2 == ' ') {
+ break;
+ } else {
+ p2--;
+ }
+ if (!*++p2) {
+ p2 = NULL;
+ }
+ } else {
+ p2 = NULL;
+ }
+ *ppbegtok = p1;
+ *ppendtok = p2;
+ return TRUE;
+}
+
+
+
+
+//
+// csoftcr - perform C soft CR processing.
+//
+// Algorithm:
+// Given that you have just entered a newline at the end of a line:
+// If the original line begins with "}", tab back once.
+// else If the original line ends with "{" or begins with a C keyword, tab
+// in once.
+// else If the line >preceding< the original line >doen't< end with "{"
+// but does begin with a C keyword, tab back once.
+//
+// C keywords used are: if, else, for, while, do, case, default.
+//
+int
+csoftcr (
+ COL x,
+ LINE y,
+ char *pbuf
+ ) {
+
+ char *pbeg, *pend;
+
+ if (parseline (pbuf, &pbeg, &pend)) {
+ if (*pbeg == '}') {
+ return dobtab (x);
+ } else if ( (pend && *pend == '{' ) || tblFind (cftab, pbeg, TRUE ) ) {
+ return doftab (x);
+ } else if (y) {
+ GetLineUntabed (y-1, pbuf, pFileHead);
+ if (parseline (pbuf, &pbeg, &pend)) {
+ if ( !(pend && *pend == '{') && tblFind (cftab, pbeg, TRUE) ) {
+ return dobtab (x);
+ }
+ }
+ }
+ }
+ return -1;
+}
+
+
+
+
+//
+// softcr - perform semi-intelegent indenting.
+//
+// Algorithm:
+// Given that you have just entered a newline at the end of a line:
+// Move to the first non-blank position on the line.
+// If a C file, attempt to get new x position.
+// If not found, move to the first non-blank position on the following
+// line.
+// If that line was blank, stay in the original first non-blank position.
+//
+int
+softcr (
+ void
+ ) {
+
+ linebuf pbuf;
+ char *p;
+ int x1, x2;
+
+
+ if (!fSoftCR) {
+ return 0;
+ }
+
+ GetLineUntabed (YCUR(pInsCur), pbuf, pFileHead);
+
+ if (*(p=whiteskip(pbuf)) == 0) {
+ p = pbuf;
+ }
+ x1 = p - pbuf;
+
+ switch (FTYPE(pFileHead)) {
+
+ case CFILE:
+ x2 = csoftcr (x1, YCUR(pInsCur), pbuf);
+ break;
+
+ default:
+ x2 = -1;
+ break;
+
+ }
+
+ if (x2 >= 0) {
+ return x2;
+ }
+
+ GetLineUntabed (YCUR(pInsCur)+1, pbuf, pFileHead);
+ if (pbuf[0] != 0) {
+ if (*(p=whiteskip (pbuf)) != 0) {
+ return p - pbuf;
+ }
+ }
+ return x1;
+}
diff --git a/private/utils/mep/src/ldelete.c b/private/utils/mep/src/ldelete.c
new file mode 100644
index 000000000..3e12c05e4
--- /dev/null
+++ b/private/utils/mep/src/ldelete.c
@@ -0,0 +1,126 @@
+/*** LDELETE.C
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+*
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+
+#include "mep.h"
+
+flagType
+ldelete (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ ) {
+
+ fl fl;
+ int l;
+
+ if (pArg->argType == STREAMARG) {
+ StreamToBox (pArg);
+ }
+
+ switch (pArg->argType) {
+
+ case NOARG:
+ if (!fMeta) {
+ pick (0, pArg->arg.noarg.y, 0, pArg->arg.noarg.y, LINEARG);
+ }
+ DelLine (TRUE, pFileHead, pArg->arg.noarg.y, pArg->arg.noarg.y);
+ break;
+
+ case NULLARG:
+ l = LineLength (pArg->arg.nullarg.y, pFileHead);
+ if (!fMeta) {
+ pick (min (l, pArg->arg.nullarg.x), pArg->arg.nullarg.y,
+ max (l, pArg->arg.nullarg.x)-1, pArg->arg.nullarg.y,
+ BOXARG);
+ }
+ DelBox (pFileHead, min (l, pArg->arg.nullarg.x), pArg->arg.nullarg.y,
+ max (l, pArg->arg.nullarg.x)-1, pArg->arg.nullarg.y);
+ return TRUE;
+
+ case LINEARG:
+ if (!fMeta) {
+ pick (0, pArg->arg.linearg.yStart,
+ 0, pArg->arg.linearg.yEnd, LINEARG);
+ }
+ DelLine (TRUE, pFileHead, pArg->arg.linearg.yStart,
+ pArg->arg.linearg.yEnd);
+ fl.col = pInsCur->flCursorCur.col;
+ fl.lin = pArg->arg.linearg.yStart;
+ cursorfl (fl);
+ break;
+
+ case BOXARG:
+ if (!fMeta) {
+ pick (pArg->arg.boxarg.xLeft, pArg->arg.boxarg.yTop,
+ pArg->arg.boxarg.xRight, pArg->arg.boxarg.yBottom, BOXARG);
+ }
+ DelBox (pFileHead, pArg->arg.boxarg.xLeft, pArg->arg.boxarg.yTop,
+ pArg->arg.boxarg.xRight, pArg->arg.boxarg.yBottom);
+ fl.col = pArg->arg.boxarg.xLeft;
+ fl.lin = pArg->arg.boxarg.yTop;
+ cursorfl (fl);
+ break;
+
+ default:
+ return FALSE;
+ }
+ return TRUE;
+
+ argData;
+}
+
+
+
+
+/*** StreamToBox - Convert a stream arg to a box/line arg
+*
+* Purpose:
+*
+* Input:
+*
+* Output:
+*
+* Returns
+*
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+void
+StreamToBox (
+ ARG * pArg
+ ) {
+
+ ARG arg;
+
+ arg = *pArg;
+
+ if (arg.arg.streamarg.xStart == arg.arg.streamarg.xEnd) {
+ pArg->argType = LINEARG;
+
+ pArg->arg.linearg.yStart = arg.arg.streamarg.yStart;
+ pArg->arg.linearg.yEnd = arg.arg.streamarg.yEnd;
+ } else {
+ pArg->argType = BOXARG;
+
+ pArg->arg.boxarg.yTop = arg.arg.streamarg.yStart;
+ pArg->arg.boxarg.yBottom = arg.arg.streamarg.yEnd;
+
+ if (arg.arg.streamarg.xEnd > arg.arg.streamarg.xStart) {
+ pArg->arg.boxarg.xLeft = arg.arg.streamarg.xStart;
+ pArg->arg.boxarg.xRight = arg.arg.streamarg.xEnd - 1;
+ } else {
+ pArg->arg.boxarg.xLeft = arg.arg.streamarg.xEnd;
+ pArg->arg.boxarg.xRight = arg.arg.streamarg.xStart -1;
+ }
+ }
+}
diff --git a/private/utils/mep/src/linsert.c b/private/utils/mep/src/linsert.c
new file mode 100644
index 000000000..ce6564464
--- /dev/null
+++ b/private/utils/mep/src/linsert.c
@@ -0,0 +1,58 @@
+/*** linsert.c - line insert
+*
+* Modifications:
+*
+* 26-Nov-1991 mz Strip off near/far
+*************************************************************************/
+#include "mep.h"
+
+
+flagType
+linsert (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ ) {
+
+ linebuf lbuf;
+ int l;
+
+ if (pArg->argType == STREAMARG) {
+ StreamToBox (pArg);
+ }
+
+ switch (pArg->argType) {
+ case NOARG:
+ CopyLine (NULL, pFileHead, pArg->arg.noarg.y, pArg->arg.noarg.y,
+ pArg->arg.noarg.y);
+ return TRUE;
+
+ /* TEXTARG illegal */
+
+ case NULLARG:
+ GetLine (pArg->arg.nullarg.y, lbuf, pFileHead);
+ strcpy (lbuf, whiteskip (lbuf));
+ l = strlen (lbuf) + 1;
+ if (l + pArg->arg.nullarg.x > sizeof(linebuf)) {
+ LengthCheck (pArg->arg.nullarg.y, 0, NULL);
+ }
+ memmove ((char *) lbuf + pArg->arg.nullarg.x,(char *) lbuf,
+ sizeof(linebuf) - l - pArg->arg.nullarg.x);
+ memset ((char *) lbuf, ' ', pArg->arg.nullarg.x);
+ PutLine (pArg->arg.nullarg.y, lbuf, pFileHead);
+ return TRUE;
+
+ case LINEARG:
+ CopyLine (NULL, pFileHead, pArg->arg.linearg.yStart, pArg->arg.linearg.yEnd,
+ pArg->arg.linearg.yStart);
+ return TRUE;
+
+ case BOXARG:
+ CopyBox (NULL, pFileHead, pArg->arg.boxarg.xLeft, pArg->arg.boxarg.yTop,
+ pArg->arg.boxarg.xRight, pArg->arg.boxarg.yBottom,
+ pArg->arg.boxarg.xLeft, pArg->arg.boxarg.yTop);
+ return TRUE;
+ }
+
+ argData; fMeta;
+}
diff --git a/private/utils/mep/src/list.c b/private/utils/mep/src/list.c
new file mode 100644
index 000000000..f23f257a9
--- /dev/null
+++ b/private/utils/mep/src/list.c
@@ -0,0 +1,880 @@
+/*** LIST.C File list handling functions
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* In order to operate on a list of files, instead of just the current
+* file, we use a file list. This is a name, much like a macro name, whose
+* value is a bunch of strings and/or lists. We can think of a typical
+* list this way:
+*
+* list:= "one two three" sub1 "four" sub2 "five"
+* sub1:= "subone subtwo" sub2 "subthree"
+* sub2:= "whatever something nothing"
+*
+* Revision History:
+* 26-Nov-1991 mz Strip off near/far
+*************************************************************************/
+
+#include "mep.h"
+
+/****************************************************************************
+ *
+ * LISTS:
+ *
+ * A list is kept as a macro. The interface defined here assumes
+ * the existence of M macro handling.
+ *
+ ****************************************************************************/
+
+#define LITERAL 1
+
+static buffer bufList;
+static MI ScanStack[MAXUSE];
+static int scanSP;
+
+
+/*** ListWalker - Given a list head, call back with each list member
+*
+* Purpose:
+*
+* To walk through a list and call back to a function with information
+* about each list element. This function is used when the caller needs
+* access to the list itself. When a copy of the list's elements is
+* sufficient, ScanList is preferred.
+*
+* This function should not be used outside of this module.
+*
+* Input:
+* Parameters:
+* imac -> Index of list
+* pfn -> Call back function
+*
+* Output: None
+*
+* Notes:
+*
+* The callback function takes four arguments:
+*
+* pcmd - The handle of the list currently being searched. This is
+* important because it may be different from the original
+* during a recursive scan.
+*
+* str - A buffer containing a copy of the current string
+*
+* pmi - A pointer to the macro instance structure. This contains:
+*
+* -> text - A pointer just beyond the current element
+* -> beg - The start of the current list.
+*
+* i - The index of the current element within the current sublist.
+*
+*************************************************************************/
+void
+ListWalker (
+ PCMD pcmd,
+ flagType (*pfn)(PCMD, char *, PMI, int),
+ flagType fRecurse
+ ) {
+
+ MI mi;
+ int i;
+
+ if (pcmd == NULL) {
+ return;
+ }
+
+ assert ((PVOID)pcmd->func == (PVOID)macro);
+
+ InitParse (pcmd, &mi);
+ for (i = 0; fParseList (&mi, bufList); i++) {
+ if (!fRecurse || TESTFLAG (mi.flags, LITERAL)) {
+ if (!TESTFLAG (mi.flags, LITERAL)) {
+ Listize (bufList);
+ }
+ if (!(*pfn)(pcmd, bufList, &mi, i)) {
+ return;
+ }
+ }else {
+ ListWalker (GetListHandle (bufList, FALSE), pfn, TRUE);
+ }
+ }
+}
+
+
+
+
+
+/*** ScanList - External list scanner, does not require keeping an instance
+*
+* Purpose:
+* To scan through a list. Calling with a list handle will return the
+* first element of the list. To get the rest of the list, call with
+* NULL until NULL is returned.
+*
+* Input:
+* Parameters:
+* pcmdStart -> Handle of list to start scanning, or NULL to get
+* next element.
+* fRecurse -> TRUE means go down sublists, FALSE means return
+* sublist names with '@' prepended.
+*
+* Output:
+* Returns Pointer to next element, or NULL if there are no more.
+*
+* Note:
+* Does not allow multiple simultaneous scans.
+*
+*************************************************************************/
+char *
+ScanList (
+ PCMD pcmdStart,
+ flagType fRecurse
+ ) {
+ static MI mi;
+
+ return ScanMyList (pcmdStart, &mi, bufList, fRecurse);
+}
+
+
+
+
+
+/*** ScanMyList - Real list scanner
+*
+* Purpose:
+* To scan through a list. Calling with a list handle will return the
+* first element of the list. To get the rest of the list, call with
+* NULL until NULL is returned.
+*
+* Input:
+* Parameters:
+* pcmdStart -> Handle of list to start scanning, or NULL to get
+* next element.
+* pmi -> pointer to instance MI structure
+* bufScan -> pointer to instance buffer
+* fRecurse -> TRUE means go down sublists, FALSE means return
+* sublist names with '@' prepended.
+* Output:
+* Returns Pointer to next element, or NULL if there are no more.
+*
+* Note:
+* Allows multiple simultaneous scans.
+*
+*************************************************************************/
+char *
+ScanMyList (
+ PCMD pcmdStart,
+ REGISTER PMI pmi,
+ buffer bufScan,
+ flagType fRecurse
+ ) {
+
+ if (pcmdStart) {
+ scanSP = -1; /* Clear list stack */
+ InitParse (pcmdStart, pmi);
+ }
+
+ while (!fParseList(pmi, bufScan)) { /* Pop till we find something */
+ if (!(fRecurse && fScanPop (pmi))) {
+ return NULL; /* We're completely done */
+ }
+ }
+
+ /* Push lists till we hit a string */
+
+ while (!TESTFLAG(pmi->flags, LITERAL)) {
+ if (fRecurse) {
+ if (pcmdStart = GetListHandle (bufScan, FALSE)) {
+ if (!fScanPush (pmi)) { /* Stack overflow */
+ printerror ("List Error: Nested too deeply at '%s'", bufScan);
+ return NULL;
+ }
+ InitParse (pcmdStart, pmi);
+ } else { /* Error! List does not exist */
+ printerror ("List Error: '%s' does not exist", bufScan);
+ return NULL;
+ }
+
+ if (!fParseList (pmi, bufScan)) {
+ if (!fScanPop (pmi)) {
+ return NULL;
+ }
+ }
+ } else {
+ Listize (bufScan);
+ break;
+ }
+ }
+ return bufScan;
+}
+
+
+
+
+/*** fParseList - Return next list element
+*
+* Purpose:
+*
+* To read a list.
+*
+* Input:
+* Parameters:
+* pmi -> macroInstance. Points to a macro value and the
+* element to be returned.
+*
+* Output:
+* Parameters:
+* pmi -> The current element field is advanced. The flags
+* field indicates whether we found a literal or a
+* sublist.
+* buf -> Place to put the element. If this is NULL, we do not
+* return the element.
+*
+* Returns TRUE if something was found.
+*
+*************************************************************************/
+flagType
+fParseList (
+ REGISTER PMI pmi,
+ REGISTER char * buf
+ ) {
+
+ assert (pmi);
+ assert (pmi->text);
+
+ /* CONSIDER: DO we really want to ignore empty quote pairs? */
+ /* Scan through any number of double quote pairs */
+ while (*(pmi->text = whiteskip (pmi->text)) == '"') {
+ pmi->flags ^= LITERAL;
+ pmi->text++;
+ }
+
+ if (*pmi->text == '\0') {
+ return FALSE;
+ }
+
+ if (buf) { /* Copy to whitspace, " or end of string */
+ while (!strchr ("\"\t ", *pmi->text)) {
+ if (*pmi->text == '\\') {
+ /* Backslashes protect characters */
+ pmi->text++;
+ }
+ *buf++ = *pmi->text++;
+ }
+ *buf = '\0';
+ }
+ return TRUE;
+}
+
+
+
+
+
+/****************************************************************************
+ *
+ * List Stack Management.
+ *
+ * ScanList uses a stack of MI's to keep track
+ * of what has been scanned so far. The stack elements are kept in
+ * a private stack defined here.
+ *
+ ****************************************************************************/
+
+
+/*** fScanPush - Save current list scan state
+*
+* Purpose:
+*
+* Called by ScanList to save its place so a sublist can be scanned
+*
+* Input:
+* Parameters:
+* pmi -> Pointer to instance to save.
+*
+* Output:
+* Returns FALSE for a stack overflow, TRUE otherwise.
+*
+*************************************************************************/
+flagType
+fScanPush (
+ PMI pmi
+ ) {
+
+ if (scanSP >= (MAXUSE-1)) {
+ return FALSE;
+ }
+
+ ScanStack[++scanSP] = *pmi;
+ assert (scanSP >= 0);
+ return TRUE;
+}
+
+
+
+
+/*** fScanPop - Restore previous scan state
+*
+* Purpose:
+*
+* Restore state after scanning a sublist
+*
+* Input: None.
+*
+* Output:
+* Parameters:
+* pmi -> Place to put previous state
+*
+* Returns TRUE if a meaningful pop took place, FALSE if there was no
+* previous state.
+*
+*************************************************************************/
+flagType
+fScanPop (
+ PMI pmi /* register here increases code size */
+ ) {
+
+ if (scanSP < 0) {
+ return FALSE;
+ }
+
+ *pmi = ScanStack[scanSP--];
+ return TRUE;
+}
+
+
+
+
+/*** GetListHandle - Create a handle for the given list name
+*
+* Purpose:
+*
+* It's much easier to deal with lists if the user can carry around something
+* that tells us how to access a list quickly. Therefore, we use this to
+* take a literal name and return a PCMD of the macro
+*
+* Input:
+* Parameters:
+* sz -> Name to look for.
+*
+* Output:
+*
+* Returns PLHEAD
+*
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+PCMD
+GetListHandle (
+ char * sz, /* register doesn't help */
+ flagType fCreate
+ )
+{
+
+ REGISTER PCMD * prgMac;
+
+ for (prgMac = rgMac; prgMac < &rgMac[cMac]; prgMac++) {
+ if (!strcmp ((*prgMac)->name, sz)) {
+ return *prgMac;
+ }
+ }
+
+ if (!fCreate) {
+ return NULL;
+ }
+
+ SetMacro (sz, rgchEmpty);
+
+ return rgMac[cMac-1];
+}
+
+
+
+
+/*** AddStrToList - Add a list item to the end of a list
+*
+* Purpose:
+*
+* This is how we build lists, n'est-ce pas?
+*
+* Input:
+* Parameters:
+* pcmd-> List to append to
+* sz -> Item to add. If this item begins with a @, then we add
+* a list (not the contents, the name).
+*
+* Output:
+*
+* Returns
+*
+*
+* Exceptions:
+*
+* Notes:
+*
+* If the original string ends in a double quote ("), we assume that
+* this is a closing quote; the string ends with a literal. If the
+* original ends with anything else, we assume that it is the end of
+* a list name. If the string passed in begins with a '@', the rest
+* of the string is a list name.
+*
+* To append a list to either type of original, we append a space and
+* the list name.
+*
+* To append a literal to a literal terminated original, we replace the
+* original's double quote with a space, append the new string, then
+* append a double quote.
+*
+* To append a literal to a list terminated original, we append a space
+* and double quote, the new string, then a double quote.
+*
+* Backslashes are doubled. This allows the list to be read by the
+* macro processor.
+*
+*************************************************************************/
+void
+AddStrToList (
+ PCMD pcmd,
+ char * sz /* register doesn't help */
+ ) {
+
+ flagType fString = TRUE; /* TRUE -> sz is a string, FALSE a list */
+ flagType fQuote = FALSE; /* TRUE means original ends in string */
+ int len; /* Length of original string */
+ int lensz; /* Length of new string */
+ int fudge = 0; /* Additional spaces or quotes */
+ REGISTER char * pchOld; /* Original list */
+ pathbuf szPathName; /* Place to put fully qualified filename*/
+
+ if (!pcmd) {
+ return;
+ }
+
+ // The user should not be able to pass in a non-macro PCMD. The
+ // user can specify a name for a list, and that name must be
+ // translated into a PCMD by GetListHandle. That function will
+ // not return a PCMD for anything other than a macro.
+ //
+ assert ((PVOID)pcmd->func == (PVOID)macro);
+
+ pchOld = (char *)pcmd->arg;
+
+ len = RemoveTrailSpace (pchOld);
+
+ if (sz[0] == '@') { /* We simply append this to the original */
+ sz[0] = ' ';
+ fString = FALSE;
+ strcpy (szPathName, sz);
+ } else {
+ CanonFilename (sz, szPathName);
+ DoubleSlashes (szPathName);
+
+ if (len && pchOld[len-1] == '"') {
+ fQuote = TRUE; /* We're appending a literal to */
+ fudge = 1; /* a list ending in a literal */
+ pchOld[len-1] = ' ';
+ } else {
+ fudge = 3; /* Appending literal to non-literal */
+ }
+ }
+
+ lensz = strlen (szPathName);
+
+ /* Now generate new string */
+
+ pcmd->arg = (CMDDATA)ZEROREALLOC ((char *)pcmd->arg, len + lensz + fudge + 1);
+ strcpy ((char *)pcmd->arg, pchOld);
+
+ if (fString && !fQuote) {
+ strcat ((char *)pcmd->arg, " \"");
+ }
+
+ strcat ((char *)pcmd->arg, szPathName);
+
+ if (fString) {
+ strcat ((char *)pcmd->arg, "\"");
+ }
+}
+
+
+
+
+/*** fInList - Check to see if a string is already in the list
+*
+* Purpose:
+*
+* To see if an element is in a list.
+*
+* Input:
+* Parameters:
+* pcmd -> List to look in
+* pch -> Literal to look for
+*
+* Output:
+*
+* Returns TRUE iff pch is in pcmd
+*
+*************************************************************************/
+flagType
+fInList (
+ PCMD pcmd,
+ char * pch,
+ flagType fRecurse
+ ) {
+
+ char * pchList; /* register here increases code size */
+ MI mi;
+
+ for (pchList = ScanMyList (pcmd, &mi, bufList, fRecurse);
+ pchList;
+ pchList = ScanMyList (NULL, &mi, bufList, fRecurse)) {
+ if (!_stricmp (pchList, pch)) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+
+/*** fDelStrFromList -
+*
+* Purpose:
+*
+* Input:
+*
+* Output:
+*
+* Returns
+*
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+flagType
+fDelStrFromList (
+ PCMD pcmd,
+ char * pch,
+ flagType fRecurse
+ ) {
+
+ strcpy (buf, pch);
+ ListWalker (pcmd, CheckAndDelStr, fRecurse);
+
+ return (flagType)(buf[0] == '\0');
+}
+
+
+
+
+/*** CheckAndDelStr - If str matches buf, remove it
+*
+* Purpose:
+*
+* ListWalker callback function for fDelStrFromList. Deletes a string from
+* a list.
+*
+* Input:
+* Parameters:
+* pcmd -> List to remove from
+* pch -> Copy of the element to remove
+* pmi -> Scan state
+* i -> Index into pcmd of the element.
+*
+* Output:
+*
+* Returns TRUE if successful
+*
+* Notes:
+*
+* We use ListWalker instead of ScanList because we need access to the
+* list position itself, not a copy of the element.
+*
+*************************************************************************/
+flagType
+CheckAndDelStr(
+ PCMD pcmd,
+ char * pch,
+ PMI pmi, /* register doesn't help */
+ int i
+ ) {
+
+ char * pchNext; /* register doesn't help */
+
+ if (!strcmp (pch, buf)) {
+ DoubleSlashes (buf);
+ pchNext = strbscan (pmi->text, " \t\"");
+ memmove (pmi->text - strlen(buf), pchNext, strlen (pchNext) + 1);
+ buf[0] = '\0'; /* signal success */
+ return FALSE;
+ }
+
+ return TRUE;
+
+ pcmd; i;
+}
+
+
+
+
+/*** GetListEntry - Given an index into a list, get the index'th element
+*
+* Purpose:
+*
+* To get a particular list element when its position is known.
+*
+* Input:
+* Parameters:
+* pcmd -> The list.
+* iList -> The index.
+*
+* Output:
+*
+* Returns pointer to the element, or NULL if there is no iList'th element
+*
+*************************************************************************/
+char *
+GetListEntry (
+ PCMD pcmd,
+ int iList,
+ flagType fRecurse
+ ) {
+
+ int i;
+ REGISTER char * pchList;
+ MI mi;
+
+ for (pchList = ScanMyList (pcmd, &mi, bufList, fRecurse), i = 0;
+ pchList && i < iList;
+ pchList = ScanMyList (NULL, &mi, bufList, fRecurse), i++) {
+ ;
+ }
+ return pchList;
+}
+
+
+
+
+
+/*** ListLen - Return the number of elements in the list
+*
+* Purpose:
+*
+* To count the elements in a list. Useful when you don't want to toast
+* ScanList.
+*
+* Input:
+* Parameters:
+* pcmd -> The list.
+*
+* Output:
+*
+* Returns Number of items in list.
+*
+*************************************************************************/
+int
+ListLen (
+ PCMD pcmd,
+ flagType fRecurse
+ ) {
+
+ MI mi;
+ int i = 0;
+
+ if (ScanMyList (pcmd, &mi, bufList, fRecurse)) {
+ do {
+ i++;
+ }while (ScanMyList (NULL, &mi, bufList, fRecurse));
+ }
+ return i;
+}
+
+
+
+
+/*** fEmptyList - Test the list for being empty
+*
+* Purpose:
+*
+* The fastest way to check for an empty list. Useful when you don't
+* want to toast ScanList.
+*
+* Input:
+* Parameters:
+* pcmd -> The list, of course.
+*
+* Output:
+*
+* Returns TRUE for empty list.
+*
+*************************************************************************/
+flagType
+fEmptyList (
+ PCMD pcmd
+ ) {
+
+ MI mi;
+
+ return (flagType)(NULL != ScanMyList (pcmd, &mi, bufList, FALSE));
+}
+
+
+
+
+
+/*** InitParse - set a search instance to the beginning of a list
+*
+* Purpose:
+*
+* To set up a parsing instance to the beginning of a list.
+*
+* Input:
+* Parameters:
+* pcmd -> List
+* pmi -> instance
+*
+* Output: None.
+*
+*************************************************************************/
+void
+InitParse (
+ PCMD pcmd,
+ PMI pmi /* register doesn't help */
+ ) {
+
+ pmi->beg = pmi->text = (char *)pcmd->arg;
+ pmi->flags = 0;
+}
+
+
+
+
+/*** Listize - Prepend a '@' to the argument
+*
+* Purpose:
+*
+* To turn a string into a list name. Works in place, assumes there is
+* room for it.
+*
+* Input:
+* Parameters:
+* sz -> Name to mess with
+*
+* Output: None.
+*
+*************************************************************************/
+void
+Listize (
+ REGISTER char * sz
+ ) {
+
+ memmove ( sz+1, sz,strlen (sz)+1);
+ sz[0] = '@';
+}
+
+
+
+/*** CanonFilename - Replace a simple filename with a full pathname
+*
+* Purpose:
+*
+* To get a full pathname for a file. The file need not exist.
+* The simple filename may be of the form $ENV:name or $(ENV):name.
+*
+* Input:
+*
+* szName -> Relative path/filename.
+* pchCanon -> Result.
+*
+* Output:
+*
+* Returns pointer to full, lower-case pathaname with drive.
+*
+* Notes:
+*
+* If szName has an $ENV specification and ENV is not defined, the
+* file is searched for in the root.
+* If given drive is a ghost drive, let the system prompt for a disk
+* change.
+*
+*************************************************************************/
+char *
+CanonFilename (
+ char * szName,
+ char * pchCanon
+ ) {
+
+ pathbuf buf;
+
+ if ( strlen(szName) < sizeof(buf) ) {
+ if (szName[0] == '<' || szName[0] == '\0') {
+ strcpy (pchCanon, szName);
+ return pchCanon;
+ }
+
+ strcpy (buf, szName);
+
+ if ( szName
+ && (szName[0] != '$' || findpath(szName, buf, TRUE))
+ && !rootpath (buf, pchCanon)) {
+
+ _strlwr (pchCanon);
+ return pchCanon;
+ }
+ }
+ return NULL;
+
+}
+
+
+
+
+
+/*** fEnvar - Check a filename for having a $ENV at the front
+*
+* Purpose:
+*
+* Input:
+*
+* Output:
+*
+* Returns
+*
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+flagType
+fEnvar (
+ char * szName
+ ) {
+ return (flagType)((szName[0] == '$') && strchr (szName, ':'));
+}
+
+
+
+
+/*** ClearList - Make a list empty
+*
+* Purpose:
+*
+* To quickly empty an existing list.
+*
+* Input:
+* pcmd -> List to clear
+*
+* Output: None
+*
+*************************************************************************/
+void
+ClearList (
+ PCMD pcmd
+ ) {
+ SetMacro ((char *)(int)(long)pcmd->name, rgchEmpty);
+}
diff --git a/private/utils/mep/src/load.c b/private/utils/mep/src/load.c
new file mode 100644
index 000000000..c70199afb
--- /dev/null
+++ b/private/utils/mep/src/load.c
@@ -0,0 +1,880 @@
+/*** load.c - handle z extensions
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* (The following discussion is applicable ONLY to Z running on DOS 3.x and
+* before).
+*
+* Z is extended by reading special EXE files into memory and performing
+* some simple links between Z and the module. The entry point as specified
+* in the EXE is called. This entry is defined by the extension library
+* (which calls the user routine WhenLoaded).
+*
+* Issues:
+*
+* Initialization
+* The WhenLoaded routine is called. Since it has full _access to all Z
+* functions, it's entry-point table needs to be defined beforehand.
+*
+* Solved by having the entry-point table statically defined and
+* located through a well-known pointer in the image.
+*
+* Entry points
+* Z services need to have entry points allowing data
+* references. All extension entry points needs to be too.
+*
+* Extensions are done by mandate. Z services will have stub routines
+* that perform the calling sequence conversions.
+*
+* Revision History:
+*
+* 26-Nov-1991 mz Strip off near/far
+*************************************************************************/
+#define INCL_DOSMODULEMGR
+#define INCL_DOSFILEMGR
+#define INCL_DOSINFOSEG
+
+#include "mep.h"
+#include "keyboard.h"
+#include "cmds.h"
+#include "keys.h"
+
+#include <stdlib.h>
+#include <errno.h>
+
+
+#include "mepext.h"
+
+#define DEBFLAG LOAD
+
+
+
+
+/*** extension stub routines
+*
+* These routines are required under the following conditions:
+*
+* - The exported entry point takes a different parameter list than the
+* "real" internal routine.
+*
+* - The exported entry point takes pointers, and the
+* "real" routine takes pointers.
+*
+* In general, we try to maintain the exported routines as close to thier
+* internal counterparts as is possible.
+*
+*************************************************************************/
+void
+E_DelLine (
+ PFILE pFile,
+ LINE yStart,
+ LINE yEnd
+ ) {
+
+ DelLine (TRUE, pFile, yStart, yEnd);
+}
+
+char *
+E_getenv (char *p)
+{
+ return (getenvOem(p));
+}
+
+void
+E_DelFile (PFILE pFile)
+{
+ DelFile (pFile, TRUE);
+}
+
+
+int
+E_GetLine (
+ LINE line,
+ char *buf,
+ PFILE pFile
+ ) {
+
+ int i;
+ flagType fTabsSave = fRealTabs;
+
+ fRealTabs = FALSE;
+ i = GetLine (line, buf, pFile);
+ fRealTabs = fTabsSave;
+
+ return i;
+}
+
+
+
+long
+E_ReadChar (void)
+{
+ EDITOR_KEY Key;
+
+ Key = TranslateKey( ReadChar() );
+
+ return Key.KeyInfo.LongData;
+}
+
+
+/*** E_FileNameToHandle - Extension interface
+*
+* Equivalent to our FileNameToHandle routine, except that strings are
+* copied local before FileNameToHandle is actually called, and we do
+* attempt to ensure that the file has been read prior to returning.
+*
+* Input:
+* As per FileNameToHandle
+*
+* Output:
+* Returns PFILE if successfull, else NULL.
+*
+* Exceptions:
+* Since we may call FileRead, the actions that ocurr there also apply
+* here.
+*
+*************************************************************************/
+PFILE
+E_FileNameToHandle (
+ char *pName,
+ char *pShortName
+ ) {
+
+ PFILE pFileNew;
+
+ if (pFileNew = FileNameToHandle (pName, pShortName )) {
+ if (TESTFLAG(FLAGS (pFileNew),REFRESH)) {
+ FileRead (pFileNew->pName, pFileNew, TRUE);
+ }
+ }
+ return pFileNew;
+}
+
+
+flagType
+E_FileRead (
+ char *name,
+ PFILE pFile
+ ) {
+
+ return FileRead (name, pFile, TRUE);
+}
+
+int
+E_DoMessage (
+ char *p
+ ) {
+
+ return (p != 0) ? domessage ("%s", p) : domessage(NULL);
+}
+
+
+void
+MoveCur (
+ COL x,
+ LINE y
+ ) {
+
+ fl fl;
+
+ fl.col = x;
+ fl.lin = y;
+ cursorfl (fl);
+}
+
+
+
+void
+E_Free(
+ void * p
+ )
+{
+ FREE( p );
+}
+
+
+
+void *
+E_Malloc(
+ size_t n
+ )
+{
+
+ return MALLOC( n );
+}
+
+
+
+
+
+
+/* GetEditorObject - Extension gateway into Z internal data
+ *
+ * This routines allows the extension user to get >copies< of certain Z editor
+ * internal data items.
+ *
+ * index = index to data item desired
+ * wParam = word parameter
+ * pDest = pointer to the location to place whatever it is the user
+ * wanted.
+ *
+ * The index varies, based on the request type. For RQ_FILE and RQ_WIN, the
+ * low byte of the index specifes the "nth most recent file" or "window #n".
+ * Special case value of FF, causes wParam to be used as the file or window
+ * handle. Window values are 1-8, 0 is current window.
+ *
+ * returns TRUE on successfull copy of data, else FALSE for bad request.
+ */
+flagType
+GetEditorObject (
+ unsigned index,
+ void *wParam,
+ void *pDest
+ ) {
+
+ unsigned lowbyte;
+ PFILE pFileCur;
+ PWND pWinLocal;
+
+ lowbyte = index & 0x00ff;
+
+ switch (index & 0xf000) { /* upper nyble is request type */
+
+ case RQ_FILE:
+ if (lowbyte == RQ_THIS_OBJECT) {
+ pFileCur = (PFILE)wParam;
+ } else if (lowbyte == RQ_FILE_INIT) {
+ pFileCur = pFileIni;
+ } else {
+ pFileCur = pFileHead;
+ while (lowbyte-- && pFileCur) {
+ pFileCur = pFileCur->pFileNext;
+ }
+ }
+
+ if (pFileCur == 0) {
+ return FALSE;
+ }
+
+ switch (index & 0xff00) { /* field request in next nyble */
+
+ case RQ_FILE_HANDLE:
+ *(PFILE *)pDest = pFileCur;
+ return TRUE;
+
+ case RQ_FILE_NAME:
+ strcpy((char *)pDest,pFileCur->pName);
+ return TRUE;
+
+ case RQ_FILE_FLAGS:
+ *(int *)pDest = pFileCur->flags;
+ return TRUE;
+ }
+ break;
+
+ //
+ // We support the direct manipulation of the ref count, so that extensions
+ // can cause pFiles to be preserved even when explicitly arg-refresh'ed by
+ // users
+ //
+ case RQ_FILE_REFCNT:
+ // What is pFileCur?
+ pFileCur = pFileHead;
+ *(int *)pDest = pFileCur->refCount;
+ return TRUE;
+
+ case RQ_WIN:
+ if (lowbyte == RQ_THIS_OBJECT) {
+ pWinLocal = (PWND)wParam;
+ } else if (lowbyte == 0) {
+ pWinLocal = pWinCur;
+ } else if ((int)lowbyte <= cWin) {
+ pWinLocal = &(WinList[lowbyte-1]);
+ } else {
+ pWinLocal = 0;
+ }
+
+ if (pWinLocal == 0) {
+ return FALSE;
+ }
+
+ switch (index & 0xff00) { /* field request in next nyble */
+
+ case RQ_WIN_HANDLE:
+ *(PWND *)pDest = pWinLocal;
+ return TRUE;
+
+ case RQ_WIN_CONTENTS:
+ //{
+ // char b[256];
+ // sprintf(b, "GetWinContents: Index %d Win 0x%x pFile 0x%x\n",
+ // lowbyte, pWinLocal, pWinLocal->pInstance->pFile );
+ // OutputDebugString(b);
+ //}
+ ((winContents *)pDest)->pFile = pWinLocal->pInstance->pFile;
+ ((winContents *)pDest)->arcWin.axLeft = (BYTE)pWinLocal->Pos.col;
+ ((winContents *)pDest)->arcWin.ayTop = (BYTE)pWinLocal->Pos.lin;
+ ((winContents *)pDest)->arcWin.axRight = (BYTE)(pWinLocal->Pos.col + pWinLocal->Size.col);
+ ((winContents *)pDest)->arcWin.ayBottom = (BYTE)(pWinLocal->Pos.lin + pWinLocal->Size.lin);
+ ((winContents *)pDest)->flPos = pWinLocal->pInstance->flWindow;
+ return TRUE;
+ }
+ break;
+
+ case RQ_COLOR:
+ if (lowbyte >= 20) {
+ *(unsigned char *)pDest = (unsigned char)ColorTab[lowbyte-20];
+ }
+ return TRUE;
+
+ case RQ_CLIP:
+ *(unsigned *)pDest = kindpick;
+ return TRUE;
+
+ }
+
+ return FALSE;
+}
+
+
+
+
+
+/* SetEditorObject - Extension gateway into setting Z internal data
+ *
+ * This routines allows the extension user to set certain Z editor internal
+ * data items.
+ *
+ * index = index to data item desired
+ * pSrc = pointer to the location to get whatever it is the user
+ * wishes to set it to.
+ *
+ * returns TRUE on successfull copy of data, else FALSE for bad request.
+ */
+flagType
+SetEditorObject(
+ unsigned index,
+ void *wParam,
+ void *pSrc
+ ) {
+
+ unsigned lowbyte;
+ PFILE pFileCur;
+ PWND pWinLocal;
+
+ lowbyte = index & 0xff;
+ switch (index & 0xf000) { /* upper nyble is request type */
+
+ case RQ_FILE:
+ if (lowbyte == RQ_THIS_OBJECT) {
+ pFileCur = (PFILE)wParam;
+ } else {
+ pFileCur = pFileHead;
+ while (lowbyte-- && pFileCur) {
+ pFileCur = pFileCur->pFileNext;
+ }
+ }
+
+ if (pFileCur == 0) {
+ return FALSE;
+ }
+
+ switch (index & 0xff00) { /* field request in next nyble */
+
+ case RQ_FILE_FLAGS:
+ pFileCur->flags = *(int *)pSrc;
+ return TRUE;
+
+ //
+ // We support the direct manipulation of the ref count, so that extensions
+ // can cause pFiles to be preserved even when explicitly arg-refresh'ed by
+ // users
+ //
+ case RQ_FILE_REFCNT:
+ pFileCur->refCount = *(int *)pSrc;
+ return TRUE;
+ }
+ break;
+
+ case RQ_WIN:
+ if (lowbyte == RQ_THIS_OBJECT) {
+ pWinLocal = (PWND)wParam;
+ } else if (lowbyte == 0) {
+ pWinLocal = pWinCur;
+ } else if ((int)lowbyte <= cWin) {
+ pWinLocal = &WinList[lowbyte-1];
+ } else {
+ pWinLocal = 0;
+ }
+
+ if (pWinLocal == 0) {
+ return FALSE;
+ }
+
+ switch (index & 0xff00) { /* field request in next nyble */
+ case RQ_WIN_CUR:
+ SetWinCur (pWinLocal - WinList);
+ return TRUE;
+
+ default:
+ break;
+ }
+
+ case RQ_COLOR:
+ if (lowbyte >= isaUserMin) {
+ ColorTab[lowbyte-isaUserMin] = *(unsigned char *)pSrc;
+ }
+ break;
+
+ case RQ_CLIP:
+ kindpick = (WORD)wParam;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+
+/* NameToKeys - returns keys associated with function name
+ *
+ * pName - pointer to function key name
+ * pDest - pointer to place for keys assigned (Can be same as pName)
+ */
+char *
+NameToKeys (
+ char *pName,
+ char *pDest
+ ) {
+
+ buffer lbuf;
+ PCMD pCmd;
+
+ strcpy ((char *) lbuf, pName);
+ pCmd = NameToFunc (lbuf);
+ lbuf[0] = 0;
+ if (pCmd) {
+ FuncToKeys(pCmd,lbuf);
+ }
+ strcpy (pDest, (char *) lbuf);
+
+ return pDest;
+}
+
+
+
+/* E_KbHook - Hook keyboard, AND force next display to update screen
+ */
+int
+E_KbHook(
+ void
+ ) {
+
+ newscreen ();
+ KbHook();
+ return 1;
+}
+
+
+
+
+/* E_Error - Invalid entry
+ */
+int
+E_Error(
+ void
+ ) {
+
+ printerror ("Illegal Extension Interface Called");
+ return 0;
+}
+
+
+
+/*** E_GetString - interface for prompting the user
+*
+* Prompts the user for a string, and returns the result.
+*
+* Input:
+* fpb = pointer to destination buffer for user's response
+* fpPrompt = pointer to prompt string
+* fInitial = TRUE => entry is highlighted, and if first function is
+* graphic, the entry is replaced by that graphic.
+*
+* Output:
+* Returns TRUE if canceled, else FALSE
+*
+*************************************************************************/
+flagType
+E_GetString (
+ char *fpb,
+ char *fpPrompt,
+ flagType fInitial
+ ) {
+
+ UNREFERENCED_PARAMETER( fInitial );
+
+ return (flagType)(CMD_cancel == getstring (fpb, fpPrompt, NULL, GS_NEWLINE | GS_INITIAL));
+
+}
+
+EXTTAB et =
+ { VERSION,
+ sizeof (struct CallBack),
+ NULL,
+ NULL,
+ {
+ AddFile,
+ BadArg,
+ confirm,
+ CopyBox,
+ CopyLine,
+ CopyStream,
+ DeRegisterEvent,
+ DeclareEvent,
+ DelBox,
+ E_DelFile,
+ E_DelLine,
+ DelStream,
+ DoDisplay,
+ E_DoMessage,
+ fChangeFile,
+ E_Free,
+ fExecute,
+ fGetMake,
+ FileLength,
+ E_FileNameToHandle,
+ E_FileRead,
+ FileWrite,
+ FindSwitch,
+ fSetMake,
+ GetColor,
+ GetTextCursor,
+ GetEditorObject,
+ E_getenv,
+ E_GetLine,
+ GetListEntry,
+ E_GetString,
+ E_KbHook,
+ KbUnHook,
+ E_Malloc,
+ MoveCur,
+ NameToKeys,
+ NameToFunc,
+ pFileToTop,
+ PutColor,
+ PutLine,
+ REsearchS,
+ E_ReadChar,
+ ReadCmd,
+ RegisterEvent,
+ RemoveFile,
+ Replace,
+ ScanList,
+ search,
+ SetColor,
+ SetEditorObject,
+ SetHiLite,
+ SetKey,
+ SplitWnd
+ }
+ };
+
+
+/*** SetLoad - load a new extension to Z
+*
+* Since tools.ini really cannot execute editor commands as it is read,
+* we can get modules loaded by making the load operation a switch. SetLoad
+* is the mechanism by which things get loaded.
+*
+* Input:
+* val = char pointer to remainder of assignment
+*
+* Output:
+* Returns pointer to error string if any errors are found, else NULL.
+*
+*************************************************************************/
+char *
+SetLoad (
+ char *val
+ ) {
+ char *pemsg; /* error returned by load */
+
+ if (pemsg = load (val, TRUE)) {
+ return pemsg;
+ } else {
+ return NULL;
+ }
+}
+
+
+
+
+/*** load - load, link, initialize Z extensions
+*
+* Read the header into memory.
+* Allocate memory, perform relocations, link to resident, initialize.
+*
+* Input:
+* pName = character pointer to name of file to be loaded
+* fLibPath = TRUE => search 8 character basename under OS/2, allowing
+* basename.DLL in LIBPATH.
+*
+* Output:
+* Returns C error code
+*
+*************************************************************************/
+char *
+load (
+ char *pName,
+ flagType fLibpath
+ ) {
+
+ pathbuf fbuf; /* full path (or user spec'd) */
+ pathbuf fname; /* copy of input param */
+ int i; /* everyone's favorite utility var*/
+ EXTTAB *pExt; /* pointer to the extension hdr */
+ char *pT; /* temp pointer to filename */
+
+ HANDLE modhandle; /* library handle */
+ FARPROC pInit; /* pointer to init routine */
+
+
+ /*
+ * barf if we have too many extensions
+ */
+ if (cCmdTab >= MAXEXT) {
+ return sys_errlist[ENOMEM];
+ }
+
+
+ /*
+ * make near copy of string
+ */
+ strcpy ((char *) fname, pName);
+
+ /*
+ * Form a fully qualified pathname in fbuf. If can't qualify, and there is
+ * no extension, append ".PXT". If that fails, then just copy the text into
+ * fbuf).
+ */
+ if (!findpath (fname, fbuf, FALSE)) {
+ if (!(pT = strrchr (fname, '\\'))) {
+ pT = fname;
+ }
+ if (!(strchr(pT, '.'))) {
+ strcat (pT, ".pxt");
+ if (!findpath (fname, fbuf, FALSE)) {
+ strcpy (fbuf, fname);
+ }
+ } else {
+ strcpy (fbuf, fname);
+ }
+ }
+
+ /*
+ * See if extension already loaded, by looking for the filename.ext in the
+ * table. If already loaded, we're done.
+ */
+ filename (fbuf, fname);
+ for (i = 1; i < cCmdTab; i++) {
+ if (!strcmp (pExtName[i], fname)) {
+ return 0;
+ }
+ }
+
+ if (! (modhandle = LoadLibrary(fbuf))) {
+ if (fLibpath) {
+ filename(fbuf, fname);
+ if (!(modhandle = LoadLibrary(fname))) {
+ //
+ // error here
+ //
+ sprintf( buf, "load:%s - Cannot load, Error: %d", fname, GetLastError() );
+ return buf;
+ }
+ }
+ }
+
+
+ /*
+ * One way or another, we succeeded. Now get the address of the ModInfo
+ */
+ if (!(pExt = (EXTTAB *)GetProcAddress(modhandle, "ModInfo"))) {
+ FreeLibrary(modhandle);
+ return buf;
+ }
+
+ //
+ // Version check. Check to see if the extensions version is in our
+ // allowed range. If it isn't, we fail due to a bad version. If it
+ // is, we handle it specially
+ //
+
+ if (pExt->version < LOWVERSION || pExt->version > HIGHVERSION) {
+ FreeLibrary(modhandle);
+ return sys_errlist[ENOEXEC];
+ }
+
+ //
+ // For now, we will allow appending of entries. Make sure that the
+ // number required by the extension is not more than we can supply
+ //
+
+ if (pExt->cbStruct > sizeof (struct CallBack)) {
+ FreeLibrary(modhandle);
+ return sys_errlist[ENOEXEC];
+ }
+
+ /*
+ * get the current registers (for our DS), and get the entry point to the
+ * .DLL.
+ */
+ if (!(pInit = GetProcAddress(modhandle, "EntryPoint"))) {
+ FreeLibrary(modhandle);
+ return buf;
+ }
+ /*
+ * Copy to the extension's call table the table we have defined. Copy only
+ * the number of entry points that the extension knows about, in case it is
+ * less than we support.
+ */
+ memmove (&pExt->CallBack, &et.CallBack, pExt->cbStruct);
+
+ /*
+ * Now that we know the extension will be staying, set up the appropriate
+ * info in our internal tables.
+ */
+ filename (fname, fbuf);
+ pExtName[cCmdTab] = ZMakeStr (fbuf);
+ swiSet[cCmdTab ] = pExt->swiTable;
+ cmdSet[cCmdTab++] = pExt->cmdTable;
+
+ /*
+ * Finally, Initialize the extension
+ */
+ //assert (_heapchk() == _HEAPOK);
+ (*pInit) ();
+ //assert (_heapchk() == _HEAPOK);
+
+ /*
+ * use root extension name for TOOLS.INI initialization & Load any
+ * extension-specific switches
+ */
+ filename (pExtName[cCmdTab-1], fname);
+ DoInit (fname, NULL, 0L);
+
+ return 0;
+}
+
+
+
+
+
+
+
+/*** AutoLoadExt - Automatically load extensions
+*
+* Search for, and automatically load extensions.
+*
+* On startup, this routine is called to search for and load extension which
+* match a particular name pattern:
+*
+* Version 1.x,: m*.mxt on PATH
+* Version 2.x,: pwb*.mxt on PATH
+*
+* Under OS/2, the normal load processing does NOT occur, such that M*.DLL
+* is NOT looked for on the path.
+*
+* Any failures during these loads are NOT reported. It is assumed that any
+* files which match the pattern and cannot be loaded are not valid
+* extensions. The "load:" command executed anywhere else will report the
+* appropriate errors on explicit attempts to load the files.
+*
+* Input:
+* none
+*
+* Output:
+* Returns nothing.
+*
+*************************************************************************/
+void
+AutoLoadExt (
+ void
+ ) {
+ char *pathenv; /* contents of PATH environment var*/
+ va_list templist;
+
+ memset( &templist, 0, sizeof(va_list) );
+ AutoLoadDir (".", templist);
+ // pathenv = getenv("PATH");
+ pathenv = getenvOem("PATH");
+ if (pathenv) {
+ forsemi (pathenv, AutoLoadDir, NULL);
+ free( pathenv );
+ }
+}
+
+
+
+
+/*** AutoLoadDir - Scan one directory for Auto-Load files
+*
+* Support routine for AutoLoadExt. Generally called by forsemi(). Scans a single
+* directory for files which can be autoloaded.
+*
+* Input:
+* dirname = directory name.
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+flagType
+AutoLoadDir (
+ char *dirname,
+ va_list dummy
+ ) {
+
+ buffer patbuf;
+ /*
+ * Construct the fully qualified pattern to be searched for, and use forfile.
+ */
+ strcpy (patbuf, dirname);
+ if ( patbuf[0] != '\0' ) {
+ if ( patbuf[strlen(patbuf) - 1] != '\\' ) {
+ strcat(patbuf, "\\");
+ }
+ }
+ strcat (patbuf, rgchAutoLoad);
+ forfile (patbuf, A_ALL, AutoLoadFile, NULL);
+ return TRUE;
+ dummy;
+}
+
+
+
+
+
+/*** AutoLoadFile - Auto-Load one extension
+*
+* Called by forfile() when a match is found. Simply calls load() with
+* the filename.
+*
+* Input:
+* szFile - filename to attempt to load
+*
+* Output:
+* Returns nothing.
+*
+*************************************************************************/
+void
+AutoLoadFile (
+ char *szFile,
+ struct findType *pfbuf,
+ void * dummy
+ ) {
+
+ load (szFile, FALSE);
+
+ pfbuf; dummy;
+}
diff --git a/private/utils/mep/src/macro.c b/private/utils/mep/src/macro.c
new file mode 100644
index 000000000..1de8de994
--- /dev/null
+++ b/private/utils/mep/src/macro.c
@@ -0,0 +1,465 @@
+/* macro.c - perform keystroke macro execution
+*
+* Modifications:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+
+#include "mep.h"
+
+
+/* macros are simply a list of editor functions interspersed with quoted
+ * strings. The execution of a macro is nothing more than locating each
+ * individual function and calling it (calling graphic (c) for each quoted
+ * character c). We maintain a stack of macros being executed; yes, there is
+ * a finite nesting limit. Sue me.
+ *
+ * Each editor function returns a state value:
+ * TRUE => the function in some way succeeded
+ * FALSE => the functin in some way failed
+ *
+ * There are several macro-specific functions that can be used to take
+ * advantage of these values:
+ *
+ *
+ * :>label defines a text label in a macro
+ *
+ * =>label All are transfers of control. => is unconditional transfer,
+ * ->label -> transfers if the previous operation failed and +> transfers
+ * +>label if the previous operation succeeded.
+ * If the indicated label is not found, all macros are terminated
+ * with an error. If no label follows the operator it is assumed
+ * to be an exit.
+ */
+
+
+
+/* macro adds a new macro to the set being executed
+ *
+ * argData pointer to text of macro
+ */
+flagType
+macro (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ ){
+ return fPushEnviron ((char *) argData, FALSE);
+
+ pArg; fMeta;
+}
+
+
+
+
+
+/* mtest returns TRUE if a macro is in progress
+ */
+flagType
+mtest (
+ void
+ ) {
+ return (flagType)(cMacUse > 0);
+}
+
+
+
+
+
+/* mlast returns TRUE if we are in a macro and the next command must come
+ * from the keyboard
+ */
+flagType
+mlast (
+ void
+ ) {
+ return (flagType)(cMacUse == 1
+ && ( (mi[0].text[0] == '\0')
+ || ( (mi[0].text[0] == '\"')
+ && (*whiteskip(mi[0].text + 1) == '\0')
+ )
+ )
+ );
+}
+
+
+
+
+
+/* fParseMacro - parses off next macro command
+ *
+ * fParse macro takes a macro instance and advances over the next command,
+ * copying the command to a separate buffer. We return a flag indicating
+ * the type of command found.
+ *
+ * pMI pointer to macro instance
+ * pBuf pointer to buffer where parsed command is placed
+ *
+ * returns flags of type of command found
+ */
+flagType
+fParseMacro (
+ struct macroInstanceType *pMI,
+ char *pBuf
+ ) {
+
+ char *p;
+ flagType fRet = FALSE;
+
+ // Make sure the instance is initialized. This means that ->text
+ // is pointing to the first command in the macro. If this is a graphic
+ // character, skip over the " and set the GRAPH flag.
+ //
+ if (TESTFLAG (pMI->flags, INIT)) {
+ pMI->text = whiteskip (pMI->text);
+ if (*pMI->text == '"') {
+ pMI->text++;
+ SETFLAG (pMI->flags, GRAPH);
+ }
+ RSETFLAG (pMI->flags, INIT);
+ }
+
+ if (TESTFLAG (pMI->flags, GRAPH) && *pMI->text != '\0') {
+ // We are inside quotes. If we are now looking at
+ // a \, skip to the next character. Don't forget to check
+ // for a \ followed by nothing.
+ //
+ if (*pMI->text == '\\') {
+ if (*++pMI->text == 0) {
+ return FALSE;
+ }
+ }
+ *pBuf++ = *pMI->text++;
+ *pBuf = 0;
+
+ // If the next character is a ", move -> up to the following
+ // command and signal that we're out of quotes.
+ //
+ if (*pMI->text == '"') {
+ RSETFLAG (pMI->flags, GRAPH);
+ pMI->text = whiteskip (pMI->text+1);
+ }
+ fRet = GRAPH;
+ } else {
+ // We are outside quotes. First read through any
+ // <x commands.
+ //
+ while (*(pMI->text) == '<') {
+ pMI->text = whiteskip(whitescan(pMI->text));
+ }
+
+ // Now skip through whitespace to the command name.
+ // Copy what we find into the caller's buffer.
+ //
+ p = whitescan (pMI->text);
+ memmove ((char*) pBuf, (char *) pMI->text, p-pMI->text);
+ pBuf[p-pMI->text] = '\0';
+
+ pMI->text = whiteskip (p); /* Find the next thing in the macro. */
+ }
+
+ // If the next thing is a quote, enter quote mode.
+ //
+ if (*pMI->text == '"') {
+ SETFLAG (pMI->flags, GRAPH);
+ pMI->text++;
+ }
+ return fRet;
+}
+
+
+
+
+
+/*** fMacResponse - peek ahead and eat any embedded macro response
+*
+* Purpose:
+* Scans ahead in the macro text for an item beginning with a "<", which
+* supplies a response to the question asked by a preceding function.
+*
+* Input:
+* None
+*
+* Output:
+* Returns NULL if not found, -1 if the user is to be prompted, and a character
+* if a character is supplied.
+*
+* Exceptions:
+* none
+*
+*************************************************************************/
+int
+fMacResponse (
+ void
+ ) {
+
+ int c;
+ struct macroInstanceType *pMI;
+
+ if (mtest()) {
+ pMI = &mi[cMacUse-1];
+ if ((TESTFLAG (pMI->flags, INIT | GRAPH)) == 0) {
+ if (*(pMI->text) != '<')
+ return 0;
+ c = (int)*(pMI->text+1);
+ if ((c == 0) || (c == ' ')) {
+ return -1;
+ }
+ pMI->text = whiteskip(pMI->text+2);
+ return c;
+ }
+ }
+ return -1;
+}
+
+
+
+
+/* fFindLabel finds a label in macro text
+ *
+ * The goto macro functions call fFindLabel to find the appropriate label.
+ * We scan the text (skipping quoted text) to find the :> leader for the label.
+ *
+ * pMI pointer to active macro instance
+ * lbl label to find (case is not significant) with goto operator
+ * =>, -> or +> This will be modified.
+ *
+ * returns TRUE iff label was found
+ */
+flagType
+fFindLabel (
+ struct macroInstanceType *pMI,
+ buffer lbl
+ ) {
+
+ buffer lbuf;
+
+ lbl[0] = ':';
+ pMI->text = pMI->beg;
+ while (*pMI->text != '\0') {
+ if (!TESTFLAG (fParseMacro (pMI, lbuf), GRAPH)) {
+ if (!_stricmp (lbl, lbuf)) {
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+
+
+
+/* mPopToTop - clear off intermediate macros up to a fence
+ */
+void
+mPopToTop (
+ void
+ ) {
+
+ while (cMacUse && !TESTFLAG (mi[cMacUse-1].flags, EXEC)) {
+ cMacUse--;
+ }
+}
+
+
+
+
+/* mGetCmd returns the next command from the current macro, popping state
+ *
+ * The command-reader code (cmd) calls mGetCmd when a macro is in progress.
+ * We are expected to return either a pointer to the function (cmdDesc) for
+ * the next function to execute or NULL if there the current macro is finished.
+ * We will adjust the state of the interpreter when a macro finishes. Any
+ * errors detected result in ALL macros being terminated.
+ *
+ * For infinite looping inside a macro, we will look for ^C too.
+ *
+ * returns NULL if current macro finishes
+ * pointer to function descriptor for next function to execute
+ */
+PCMD
+mGetCmd (
+ void
+ ) {
+
+ buffer mname;
+ PCMD pFunc;
+ struct macroInstanceType *pmi;
+
+ if (cMacUse == 0) {
+ IntError ("mGetCmd called with no macros in effect");
+ }
+ pmi = &mi[cMacUse-1];
+ while ( pmi->text && *pmi->text != '\0') {
+ // Use heuristic to see if infinite loop
+ //
+ if (fCtrlc) {
+ goto mGetCmdAbort;
+ }
+
+
+ if (TESTFLAG (fParseMacro (pmi, mname), GRAPH)) {
+ pFunc = &cmdGraphic;
+ pFunc->arg = mname[0];
+ return pFunc;
+ }
+
+ /*
+ * if end of macro, exit
+ */
+ if (!mname[0]) {
+ break;
+ }
+
+ _strlwr (mname);
+
+ pFunc = NameToFunc (mname);
+
+ // found an editor function / macro
+ //
+ if (pFunc != NULL) {
+ return pFunc;
+ }
+
+ if (mname[1] != '>' ||
+ (mname[0] != '=' && mname[0] != ':' &&
+ mname[0] != '+' && mname[0] != '-')) {
+ printerror ("unknown function %s", mname);
+ goto mGetCmdAbort;
+ }
+
+ /* see if goto is to be taken */
+ if (mname[0] == '=' ||
+ (fRetVal && mname[0] == '+') ||
+ (!fRetVal && mname[0] == '-')) {
+
+ /* if exit from current macro, then exit scanning loop
+ */
+ if (mname[2] == '\0') {
+ break;
+ }
+
+ /* find label
+ */
+ if (!fFindLabel (pmi, mname)) {
+ printerror ("Cannot find label %s", mname+2);
+mGetCmdAbort:
+ resetarg ();
+ DoCancel ();
+ mPopToTop ();
+ break;
+ }
+ }
+ }
+
+ /* we have exhausted the current macro. If it was entered via EXEC
+ * we must signal TopLoop that the party's over
+ */
+ fBreak = (flagType)(TESTFLAG (mi[cMacUse-1].flags, EXEC));
+ if ( cMacUse > 0 ) {
+ cMacUse--;
+ }
+ return NULL;
+}
+
+
+
+
+/* fPushEnviron - push a stream of commands into the environment
+ *
+ * The command-reader of Z (zloop) will retrieve commands either from the
+ * stack of macros or from the keyboard if the stack of macros is empty.
+ * fPushEnviron adds a new context to the stack.
+ *
+ * p character pointer to command set
+ * f flag indicating type of macro
+ *
+ * returns TRUE iff environment was successfully pushed
+ */
+flagType
+fPushEnviron (
+ char *p,
+ flagType f
+ ) {
+ if (cMacUse == MAXUSE) {
+ printerror ("Macros nested too deep");
+ return FALSE;
+ }
+ mi[cMacUse].beg = mi[cMacUse].text = p;
+ mi[cMacUse++].flags = (flagType)(f | INIT);
+ return TRUE;
+}
+
+
+
+
+
+/* fExecute - push a new macro into the environment
+ *
+ * pStr pointer to macro string to push
+ *
+ * returns value of last executed macro.
+ */
+flagType
+fExecute (
+ char *pStr
+ ) {
+
+ pStr = whiteskip (pStr);
+
+ if (fPushEnviron (pStr, EXEC)) {
+ TopLoop ();
+ }
+
+ return fRetVal;
+}
+
+
+
+
+
+/* zexecute pushes a new macro to the set being executed
+ *
+ * arg pointer to text of macro
+ */
+flagType
+zexecute (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ ) {
+
+ LINE i;
+ linebuf ebuf;
+
+ switch (pArg->argType) {
+
+ /* NOARG illegal */
+
+ case TEXTARG:
+ strcpy ((char *) ebuf, pArg->arg.textarg.pText);
+ fMeta = fExecute (ebuf);
+ break;
+
+ /* NULLARG converted to TEXTARG */
+
+ case LINEARG:
+ fMeta = FALSE;
+ for (i = pArg->arg.linearg.yStart; i <= pArg->arg.linearg.yEnd; i++) {
+ if (GetLine (i, ebuf, pFileHead) != 0) {
+ fMeta = fExecute (ebuf);
+ if (!fMeta) {
+ break;
+ }
+ }
+ }
+ break;
+
+ /* STREAMARG illegal */
+ /* BOXARG illegal */
+
+ }
+ Display ();
+ return fMeta;
+ argData;
+}
diff --git a/private/utils/mep/src/makefile b/private/utils/mep/src/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/mep/src/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/mep/src/mark.c b/private/utils/mep/src/mark.c
new file mode 100644
index 000000000..17aa96837
--- /dev/null
+++ b/private/utils/mep/src/mark.c
@@ -0,0 +1,1496 @@
+/* mark.c - do marking and repositioning
+*
+* Modifications:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+
+#include "mep.h"
+
+PFILE pFileMark = NULL; /* mark file handle */
+flagType fCacheDirty = 0; /* TRUE => cache has ben changed */
+PFILE pFileCache = NULL; /* Cached file */
+FILEMARKS * pfmCache = NULL; /* Cached marks */
+
+/* Flags for mark.flags */
+
+#define MF_DIRTY 1 /* Mark has changed, but is not written */
+#define MF_TEMP 2
+#define MF_DUMMY 4 /* This is dummry last mark */
+
+
+
+/*** mark - <mark> editor function
+*
+* Purpose:
+*
+* <mark> - Goes to top of file
+* <arg><mark> - Toggle last/current window position
+* <arg> textarg <mark> - Goes to named mark
+* <arg><arg> textarg <mark> - Defines mark at cursor
+* <arg><arg> textarg <mark> - Removes named mark
+*
+* Input:
+*
+* Output:
+*
+* Returns FALSE if you try to go to a non-existent mark, TRUE
+* otherwise.
+*
+*************************************************************************/
+flagType
+mark (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ ) {
+
+ buffer mbuf;
+
+ switch (pArg->argType) {
+
+ case NOARG:
+ docursor (0, (LINE)0);
+ return TRUE;
+
+ case TEXTARG:
+ strcpy ((char *) mbuf, pArg->arg.textarg.pText);
+ if (fIsNum (mbuf)) {
+ docursor (0, atol (mbuf)-1);
+ return TRUE;
+ }
+ if (pArg->arg.textarg.cArg == 2) {
+ if (fMeta) {
+ DeleteMark (mbuf);
+ } else {
+ DefineMark (mbuf, pFileHead, pArg->arg.textarg.y+1, pArg->arg.textarg.x+1, FALSE);
+ }
+ return TRUE;
+ } else {
+ return GoToMark (mbuf);
+ }
+
+ case NULLARG:
+ restflip();
+ return TRUE;
+
+ /* LINEARG illegal */
+ /* STREAMARG illegal */
+ /* BOXARG illegal */
+
+ }
+ argData;
+}
+
+
+
+
+
+/*** GoToMark - Move cursor to a mark
+*
+* Purpose:
+*
+* Goes to the named mark.
+*
+* Input:
+* pszMark - Name of mark to go to.
+*
+* Output:
+*
+* Returns TRUE if mark exists, FALSE, otherwise.
+*
+*************************************************************************/
+flagType
+GoToMark (
+ char * pszMark
+ ) {
+
+ PFILE pFile;
+ fl fl;
+
+ if (pFile = FindMark (pszMark, &fl, TRUE)) {
+ if (TESTFLAG(FLAGS(pFile), REAL) ||
+ FileRead (pFile->pName, pFile, FALSE)) {
+ pFileToTop (pFile);
+ cursorfl (fl);
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ } else {
+ printerror ("'%s': Mark not found", pszMark);
+ return FALSE;
+ }
+}
+
+
+
+
+
+/*** FindMark - Get a mark's file location - used from outside
+*
+* Purpose:
+*
+* Find a mark
+*
+* Input:
+* pszMark - Mark to search for.
+* fCheckAllFiles - TRUE => Search through all files for mark
+* FALSE => Look in only the current file
+*
+* Output:
+* * pfl - fl of mark.
+*
+* Returns pFile of file the mark is in, NULL if mark is not found.
+*
+*************************************************************************/
+PFILE
+FindMark (
+ char * pszMark,
+ fl * pfl,
+ flagType fCheckAllFiles
+ ) {
+
+ REGISTER PFILE pFile;
+ MARK UNALIGNED* pm;
+ char szMark[BUFLEN];
+ char szFile[BUFLEN];
+ linebuf lbuf;
+ LINE y, l;
+ COL x;
+
+ // If we are checking the current file only,
+ // make sure it's cached and check it.
+ //
+ if (!fCheckAllFiles) {
+ if (fCacheMarks (pFileHead) &&
+ (pm = FindLocalMark (pszMark, FALSE))) {
+ *pfl = pm->fl;
+ //return pFile;
+ return pFileHead;
+ } else {
+ return NULL;
+ }
+ }
+
+ // Now, trundle through the pFile list
+ // looking at the marks we have already
+ // read from the markfile.
+ //
+ for (pFile = pFileHead; pFile; pFile = pFile->pFileNext) {
+ if (TESTFLAG (FLAGS(pFile), VALMARKS) && fCacheMarks (pFile)) {
+ if (pm = FindLocalMark (pszMark, FALSE)) {
+ *pfl = pm->fl;
+ return pFile;
+ }
+ }
+ }
+
+ // None of the files we have read so far
+ // has the mark defined. We'll make one
+ // pass through the markfile to see if
+ // it's there.
+ //
+ if (pFileMark) {
+ for (l = 0L; l < pFileMark->cLines; l++) {
+ GetLine (l, lbuf, pFileMark);
+ if (sscanf (lbuf, " %[^ ] %[^ ] %ld %d ", szMark, buf, &y, &x) >= 3)
+ if (!_stricmp (szMark, pszMark)) {
+ CanonFilename (buf, szFile);
+ if (!(pFile = FileNameToHandle (szFile, NULL))) {
+ pFile = AddFile (szFile);
+ }
+ (void)fReadMarks (pFile);
+ pfl->lin = y - 1;
+ pfl->col = x - 1;
+ return pFile;
+ }
+ }
+ }
+ return NULL;
+}
+
+
+
+
+/*** FindLocalMark - Find a mark in a FILEMARKS structure
+*
+* Purpose:
+*
+* To find a mark in the cached marks. If found, a pointer into
+* the cache is returned,
+*
+* Input:
+* pszMark - Mark Name
+* fDirtyOnly - TRUE => Return only changed marks.
+*
+* Output:
+*
+* Returns pointer to mark.
+*
+*************************************************************************/
+MARK *
+FindLocalMark (
+ char * pszMark,
+ flagType fDirtyOnly
+ ) {
+
+ REGISTER MARK UNALIGNED * pm;
+
+ for (pm = pfmCache->marks; !TESTFLAG(pm->flags, MF_DUMMY) ; (char *)pm += pm->cb) {
+ if (!_stricmp (pszMark, pm->szName)) {
+ if (fDirtyOnly && !TESTFLAG(pm->flags, MF_DIRTY)) {
+ return NULL;
+ } else {
+ return (MARK *)pm;
+ }
+ }
+ assert (pm->cb);
+ }
+ return NULL;
+}
+
+
+
+
+
+/*** GetMarkFromLoc - Return the first mark past a given location
+*
+* Purpose:
+*
+* To get a pointer to a mark given its file location.
+*
+* Input:
+* x, y - Mark location
+*
+* Output:
+*
+* Returns Pointer to the mark.
+*
+*************************************************************************/
+MARK *
+GetMarkFromLoc (
+ LINE y,
+ COL x
+ ) {
+
+ REGISTER MARK UNALIGNED * pm;
+
+ for (pm = pfmCache->marks; !TESTFLAG(pm->flags, MF_DUMMY) ; (char *)pm += pm->cb) {
+ if (pm->fl.lin > y || ((pm->fl.lin == y) && (pm->fl.col >= x))) {
+ break;
+ }
+ }
+ return (MARK *) pm;
+}
+
+
+
+
+/*** SetMarkFile - Change markfile
+*
+* Purpose:
+*
+* Changes to a new markfile.
+*
+* Input:
+* val - String after the 'markfile' switch
+*
+* Output:
+*
+* Returns Error string if error, NULL otherwise
+*
+* Notes:
+*
+* We:
+*
+* UNDONE:o Magically ensure that the current markfile is up to date and
+* saved to disk. This means, at the very least, that there
+* can be no dirty files.
+*
+* o Remove the current markfile from the file list.
+*
+* o Read in the new markfile.
+*
+* o Invalidate all current marks. This is just marking them
+* invalid in the PFILE.
+*
+*
+*************************************************************************/
+char *
+SetMarkFile (
+ char *val
+ ) {
+
+ REGISTER PFILE pFile;
+ buffer tmpval;
+ pathbuf pathname;
+
+ strcpy ((char *) tmpval, val);
+
+ if (NULL == CanonFilename (tmpval, pathname)) {
+ sprintf (buf, "'%s': name is malformed", tmpval);
+ return buf;
+ }
+
+ if (!(pFile = FileNameToHandle (pathname, NULL))) {
+ pFile = AddFile (pathname);
+ }
+
+ if (!TESTFLAG(FLAGS(pFile), REAL) && !FileRead (pathname, pFile, FALSE)) {
+ RemoveFile (pFile);
+ sprintf (buf, "'%s' - %s", pathname, error());
+ return buf;
+ }
+
+ pFileMark = pFile;
+
+ for (pFile = pFileHead; pFile; pFile = pFile->pFileNext) {
+ if (!TESTFLAG(FLAGS(pFile), FAKE)) {
+ RSETFLAG (FLAGS(pFile), VALMARKS);
+ }
+ }
+ return NULL;
+}
+
+
+
+
+
+/*** MarkInsLine - Adjust marks after an InsLine
+*
+* Purpose:
+*
+* After InsLine inserts a bunch of blank lines, it calls this to update
+* any marks that would be "moved down".
+*
+* Input:
+* line - line number at which insertion took place
+* n - Number of new lines
+* pFile- File this occurred in
+*
+* Output: None
+*
+*************************************************************************/
+void
+MarkInsLine (
+ LINE line,
+ LINE n,
+ PFILE pFile
+ ) {
+
+ MARK UNALIGNED * pm;
+
+ if (!fCacheMarks (pFile)) {
+ return;
+ }
+
+ if (pm = GetMarkFromLoc (line, 0)) {
+ AdjustMarks ((MARK *)pm, n);
+ }
+}
+
+
+
+
+
+/*** MarkDelStream - Adjust Marks after a DelStream
+*
+* Purpose:
+*
+* After DelStream or DelLines removes a stream (DelLine removes a
+* "stream" with the beginning and ending points at the left and right
+* edges of the file), this takes care of updating any remaining
+* marks.
+*
+* Input:
+* pFile - Affected file
+* xStart - 0-based starting point
+* yStart
+* xEnd - 0-based ending point
+* yEnd
+*
+* Output: None
+*
+*************************************************************************/
+void
+MarkDelStream (
+ PFILE pFile,
+ COL xStart,
+ LINE yStart,
+ COL xEnd,
+ LINE yEnd
+ ) {
+
+ REGISTER MARK UNALIGNED * pm;
+ MARK UNALIGNED * pmStart = NULL;
+ MARK UNALIGNED * pmEnd = NULL;
+ fl flStart;
+ fl flEnd;
+ flagType fAgain = FALSE;
+
+ if (!fCacheMarks (pFile)) {
+ return;
+ }
+
+ /* yEnd++; WHY? */
+ flStart.lin = yStart;
+ flStart.col = xStart;
+ flEnd.lin = yEnd;
+ flEnd.col = xEnd;
+
+ for (pm = pfmCache->marks; pmEnd == NULL ; (char *)pm += pm->cb) {
+ // Look for first mark past beginning
+ // of stream. Assume for the moment that
+ // it is inside the stream
+ //
+ if (pmStart == NULL) {
+ if (flcmp (&flStart, (fl *) &pm->fl) < 1) {
+ pmStart = pm;
+ } else {
+ continue;
+ }
+ }
+
+ // A first mark has been found. We start
+ // looking for the first mark past the end
+ // of the stream. If these are the same,
+ // there are no marks to remove.
+ //
+ if (flcmp (&flEnd, (fl *) &pm->fl) < 1) {
+ // We know that we will end up here
+ // because the last "mark" is higher
+ // than any real mark
+ //
+ if ((pmEnd = pm) != pmStart)
+ // We're here if there were
+ // any marks inside the deleted
+ // stream
+ //
+ memmove ((char *)pmStart,
+ (char *)pmEnd,
+ ((char *)pfmCache + pfmCache->cb) - (char *)pmEnd );
+
+ if (pmStart->fl.lin == yEnd) {
+ pmStart->fl.col -= xEnd;
+ }
+ AdjustMarks ((MARK *)pmStart, yStart - (yEnd + 1));
+ }
+
+ assert (pm->cb ||
+ (TESTFLAG(pm->flags, MF_DUMMY) &&
+ pm->fl.lin == 0x7FFFFFFF &&
+ pm->fl.col == 0x7FFF));
+ }
+}
+
+
+
+
+
+
+/*** MarkDelBox - Adjust Marks after a DelBox
+*
+* Purpose:
+*
+* After deleting a box of text, we must remove any marks that are
+* defined inside it, then shift left any marks that are to the
+* right of it.
+*
+* Input:
+* pFile - Affected file
+* xLeft, yTop - Upper left hand corner of box
+* xRight, yBottom - Lower right hand corner of box
+*
+* Output: None
+*
+*************************************************************************/
+void
+MarkDelBox (
+ PFILE pFile,
+ COL xLeft,
+ LINE yTop,
+ COL xRight,
+ LINE yBottom
+ ) {
+
+ MARK UNALIGNED * pm;
+ MARK UNALIGNED * pmStart = NULL;
+ MARK UNALIGNED * pmEnd = NULL;
+ fl flUpLeft;
+ fl flLoRight;
+ flagType fAgain;
+ flagType fInBox = FALSE; /* Marks are within box top/bottom */
+
+ if (!fCacheMarks (pFile)) {
+ return;
+ }
+
+ /* yBottom++; WHY? */
+ flUpLeft.lin = yTop;
+ flUpLeft.col = xLeft;
+ flLoRight.lin = yBottom;
+ flLoRight.col = xRight;
+
+
+ for (pm = pfmCache->marks; !TESTFLAG(pm->flags, MF_DUMMY) ; !fAgain && ((char *)pm += pm->cb)) {
+ /* First, look for lowest possible mark */
+ fAgain = FALSE;
+ if (!fInBox) {
+ if (flcmp (&flUpLeft, (fl *) &pm->fl) < 1) {
+ fAgain = TRUE;
+ fInBox = TRUE;
+ } else {
+ ;
+ }
+ } else if (flcmp ((fl *) &pm->fl, &flLoRight) < 1) {
+ /* Now we're in range. Check
+ ** for being inside the box.
+ */
+ if (pm->fl.col >= xLeft) {
+ if (pm->fl.col <= xRight) {
+ DelPMark ((MARK *) pm);
+ fAgain = TRUE;
+ } else { /* Mark to the right of box */
+ pm->fl.col -= xRight - xLeft + 1;
+ }
+ } else {
+ ;
+ }
+ } else {
+ if (pm->fl.lin == yBottom) {
+ pm->fl.col -= xRight - xLeft + 1;
+ } else {
+ break; /* We've gone past the box */
+ }
+ }
+ }
+}
+
+
+
+
+
+/*** fReadMarks - Read marks from the current markfile
+*
+* Purpose:
+*
+* Gets the current marks for a given file.
+*
+* Input:
+* pFile - File to read marks for.
+*
+* Output:
+*
+* Returns TRUE if pFile has marks and they are in VM, FALSE otherwise.
+*
+*************************************************************************/
+flagType
+fReadMarks (
+ PFILE pFile
+ ) {
+
+ FILEMARKS UNALIGNED * pfm = NULL;
+ LINE l;
+ char szMark[BUFLEN];
+ char szFile[BUFLEN];
+ linebuf lbuf;
+ LINE yMark;
+ COL xMark;
+
+
+ if (TESTFLAG (FLAGS(pFile), VALMARKS)) {
+ return (flagType)(pFile->vaMarks != NULL);
+ }
+
+ // psuedo files cannot have marks
+ // saved in the markfile.
+ //
+ if (pFileMark == NULL || TESTFLAG(FLAGS(pFile), FAKE)) {
+ return FALSE;
+ }
+
+ for (l = 0L; l < pFileMark->cLines; l++) {
+ GetLine (l, lbuf, pFileMark);
+ if (sscanf (lbuf, " %[^ ] %[^ ] %ld %d ", szMark, szFile, &yMark, &xMark) >= 3) {
+ if (!_stricmp (szFile, pFile->pName)) {
+ UpdMark ((FILEMARKS **) &pfm, szMark, yMark, xMark, FALSE);
+ }
+ }
+ }
+
+ // Now pfm points to a good FILEMARKS structure.
+ // First, throw away current marks. Then, if we
+ // actually found some marks for this file, we
+ // put them in VM.
+ //
+ return fFMtoPfile (pFile, (FILEMARKS *)pfm);
+}
+
+
+
+
+/*** WriteMarks - Write Marks back out to the markfile.
+*
+* Purpose:
+*
+* To update the markfile if any marks have changed
+*
+* Input:
+* pFile - owner of the marks
+*
+* Output: None.
+*
+*************************************************************************/
+void
+WriteMarks (
+ PFILE pFile
+ ) {
+
+ REGISTER MARK UNALIGNED * pm;
+ char szMark[BUFLEN];
+ char szFile[BUFLEN];
+ linebuf lbuf;
+ LINE yMark, l;
+ COL xMark;
+
+ if (pFileMark == NULL || TESTFLAG(FLAGS(pFile), FAKE)) {
+ return;
+ }
+
+ if (!fCacheMarks (pFile)) {
+ return;
+ }
+
+ // First, we read the whole file looking for marks for
+ // this file. When we find one, we look it up in the
+ // cache to find the new value and write it back
+ // out. Unchanged marks are not re-written.
+ //
+ for (l = 0L; l < pFileMark->cLines; l++) {
+ GetLine (l, lbuf, pFileMark);
+ if (sscanf (lbuf, " %[^ ] %[^ ] %ld %d ", szMark, szFile, &yMark, &xMark) >= 3) {
+ if (!_stricmp (szFile, pFile->pName)) {
+ if (pm = FindLocalMark (szMark, TRUE)) {
+ sprintf (lbuf, "%s %s %ld %d", szMark, szFile, pm->fl.lin+1, pm->fl.col+1);
+ PutLine (l, lbuf, pFileMark);
+ RSETFLAG (pm->flags, MF_DIRTY);
+ }
+ }
+ }
+ }
+
+ // Now we read through the cache to find any new marks. These
+ // will be appended to the markfile.
+ //
+ for ( pm = pfmCache->marks;
+ !TESTFLAG(pm->flags, MF_DUMMY);
+ (char *)pm += pm->cb) {
+
+ if (TESTFLAG (pm->flags, MF_DIRTY)) {
+ sprintf (lbuf, "%s %s %ld %d", pm->szName,
+ pFile->pName,
+ pm->fl.lin + 1,
+ pm->fl.col + 1);
+ AppFile (lbuf, pFileMark);
+ }
+ }
+}
+
+
+
+
+
+/*** UpdMark - Add a mark to a FILEMARKS
+*
+* Purpose:
+*
+* This creates the FILEMARKS structure, adds marks to it and
+* updates existing marks in it. The caller does not need to
+* know which of these is going to happen.
+*
+* Input:
+* ppfm - Pointer to a pointer to FILEMARKS.
+* pszMark - Mark name.
+* yMark - Mark location (1-based)
+* xMark
+* fTemp - TRUE => This marks should not be written to the markfile
+*
+* Output: None. *ppfm may be changed
+*
+* Notes:
+*
+* The first argument is a ** because the * will be updated when a
+* re-LMAlloc is required.
+*
+*************************************************************************/
+void
+UpdMark (
+ FILEMARKS ** ppfm,
+ char * pszMark,
+ LINE yMark,
+ COL xMark,
+ flagType flags
+ ) {
+
+ FILEMARKS UNALIGNED * pfm;
+ FILEMARKS UNALIGNED * pfmOld; /* pfm prior to realloc */
+ REGISTER MARK UNALIGNED * pm;
+ int cbNewMark;
+ fl flMark;
+ flagType fExist = FALSE;
+
+ assert (ppfm);
+
+ /* Convert to 0-based */
+ flMark.lin = yMark-1;
+ flMark.col = xMark-1;
+ cbNewMark = sizeof(MARK) + strlen(pszMark);
+
+ // If we already have a FILEMARKS structure,
+ // we look for the slot in pfm->marks
+ // where the new mark will go.
+ //
+ if (pfm = *ppfm) {
+ for (pm = pfm->marks; !TESTFLAG(pm->flags, MF_DUMMY); (char *)pm += pm->cb) {
+ if (!_stricmp (pszMark, pm->szName)) {
+ fExist = TRUE;
+ break;
+ }
+
+ // Check for current mark coming later than
+ // new mark
+ //
+ if (flcmp ((fl *) &pm->fl, &flMark) > 0) {
+ break;
+ }
+ }
+ } else {
+ // New structure. Allocate mem and create
+ // a dummy mark.
+ //
+ pfm = (FILEMARKS *)ZEROMALLOC (sizeof(FILEMARKS));
+ pfm->cb = sizeof(FILEMARKS);
+ pm = pfm->marks;
+ pm->cb = sizeof(MARK);
+ pm->fl.lin = 0x7FFFFFFF;
+ pm->fl.col = 0x7FFF;
+ pm->szName[0] = '\0';
+ pm->flags = MF_DUMMY;
+ }
+
+ // At this point, pfm points to the current FILEMARKS
+ // structure, and pm points into that structure at
+ // the place where the new mark will go, or the existing
+ // mark be updated.
+ //
+ if (!fExist) {
+
+ pfmOld = pfm;
+
+ // First, get enough extra space for a new mark, adjusting pm
+ // if a new alloc was required
+ //
+ pfm = (FILEMARKS *)ZEROREALLOC((PVOID)pfm, pfm->cb + cbNewMark);
+ if (pfmOld != pfm) {
+ pm = (MARK *)((char *)pfm + ((char *)pm - (char *)pfmOld));
+ }
+
+ // Now pm points to the location in pfm where
+ // our new mark should go. We will move the
+ // original filemarks up to leave space for the
+ // new one.
+ //
+ memmove ((char *)((char *)pm + cbNewMark),
+ (char *)pm,
+ pfm->cb - ((char *)pm - (char *)pfm));
+
+ strcpy (pm->szName, pszMark);
+ pm->flags = 0;
+ pm->cb = cbNewMark;
+
+ pfm->cb += cbNewMark;
+ }
+
+ if (pfm == pfmCache) {
+ fCacheDirty = TRUE;
+ }
+ pm->flags = flags;
+ pm->fl = flMark;
+
+ *ppfm = (FILEMARKS *)pfm;
+}
+
+
+
+
+/*** DefineMark - Add new mark / update existing mark
+*
+* Purpose:
+*
+* This is called from the outside to create/update marks.
+*
+* Input:
+* pszMark - Mark's name
+* pFile - File the mark will be in
+* y, x - File location of the mark (1-based)
+* fTemp - True -> the mark is temporary
+*
+* Output: None.
+*
+*************************************************************************/
+void
+DefineMark (
+ char * pszMark,
+ PFILE pFile,
+ LINE y,
+ COL x,
+ flagType fTemp
+ ) {
+
+ flagType fFirstMark = (flagType)!fCacheMarks (pFile);
+
+ if (fFirstMark) {
+ FreeCache ();
+ }
+
+ UpdMark (&pfmCache, pszMark, y, x, (flagType)(MF_DIRTY | (fTemp ? MF_TEMP : 0)));
+
+ if (fFirstMark) {
+ pFileCache = pFile;
+ (void)fFMtoPfile (pFile, pfmCache);
+ }
+}
+
+
+
+
+
+/*** DeleteMark - Remove a mark
+*
+* Purpose:
+*
+* Un-define a mark.
+*
+* Input:
+* pszMark - Mark to remove
+*
+* Output: None
+*
+* Notes:
+*
+* A message is displayed reporting on success or failure.
+*
+*************************************************************************/
+void
+DeleteMark (
+ char * pszMark
+ ) {
+
+ REGISTER PFILE pFile;
+ MARK UNALIGNED * pm;
+
+ for (pFile = pFileHead; pFile; pFile = pFile->pFileNext) {
+ if (TESTFLAG (FLAGS(pFile), VALMARKS) && fCacheMarks (pFile)) {
+ if (pm = FindLocalMark (pszMark, FALSE)) {
+ DelPMark ((MARK *)pm);
+ domessage ("%s: mark deleted", pszMark);
+ return;
+ }
+ }
+ }
+ printerror ("%s: Mark not found", pszMark);
+}
+
+
+
+
+/*** DelPMark - Remove a mark when a pointer to the MARK is known
+*
+* Purpose:
+*
+* Physically remove a mark from a FILEMARKS structure
+*
+* Input:
+* pm - Pointer (into pfmCache) of mark to remove
+*
+* Output: None
+*
+*************************************************************************/
+void
+DelPMark (
+ MARK * pm
+ ) {
+
+ MARK UNALIGNED * p;
+ int cb;
+
+ p = pm;
+ cb = p->cb;
+
+ memmove ((char *)pm,
+ (char *)((char *)pm + cb),
+ ((char *)pfmCache + pfmCache->cb) - ((char *)pm + cb));
+
+ pfmCache->cb -= cb;
+}
+
+
+
+
+
+/*** MarkCopyLine - Copy marks after a CopyLine call
+*
+* Purpose:
+*
+* When CopyLine moves stuff from or to the clipboard, this moves marks
+* with it.
+*
+* Input:
+* pFileSrc - File moved from
+* pFileDst - File moved to
+* yStart - First line from pFileSrc
+* yEnd - Last number from pFileDst
+* yDst - Target line in pFileDst
+*
+* Output: None
+*
+* Notes:
+*
+* Marks are copied only from and to the clipboard.
+*
+*
+*************************************************************************/
+void
+MarkCopyLine (
+ PFILE pFileSrc,
+ PFILE pFileDst,
+ LINE yStart,
+ LINE yEnd,
+ LINE yDst
+ ) {
+
+ FILEMARKS * pfm;
+
+ if (pFileSrc != pFilePick && pFileDst != pFilePick) {
+ return;
+ }
+
+ if (NULL == (pfm = GetFMFromFile (pFileSrc, 0, yStart, sizeof(linebuf)-1, yEnd))) {
+ return;
+ }
+
+ AddFMToFile (pFileDst, pfm, 0, yDst);
+
+ if ( pfm ) {
+ FREE (pfm);
+ }
+}
+
+
+
+
+/*** MarkCopyBox - Copy marks after a CopyBox call
+*
+* Purpose:
+*
+* When CopyBox moves stuff from or to the clipboard, this moves marks
+* with it.
+*
+* Input:
+* pFileSrc - File moved from
+* pFileDst - File moved to
+* xLeft, yTop - Upper left corner of source box
+* xRight, yBottom - Lower right corner of source box
+* xDst, yDst - Upper left corner of target
+*
+* Output: None
+*
+* Notes:
+*
+* Marks are copied only from and to the clipboard.
+*
+*************************************************************************/
+void
+MarkCopyBox (
+ PFILE pFileSrc,
+ PFILE pFileDst,
+ COL xLeft,
+ LINE yTop,
+ COL xRight,
+ LINE yBottom,
+ COL xDst,
+ LINE yDst
+ )
+{
+
+ FILEMARKS UNALIGNED * pfm;
+
+ /* User is inserting blank region. */
+ if (pFileSrc == NULL) {
+ pFileSrc = pFileDst;
+ xDst = xRight + 1;
+ xRight = sizeof(linebuf);
+ } else if (pFileSrc != pFileDst &&
+ pFileSrc != pFilePick &&
+ pFileDst != pFilePick) {
+ return;
+ }
+
+ if (NULL == (pfm = GetFMFromFile (pFileSrc, xLeft, yTop, xRight, yBottom))) {
+ return;
+ }
+
+ AddFMToFile (pFileDst, (FILEMARKS *)pfm, xDst, yDst);
+
+ if ( pfm ) {
+ FREE (pfm);
+ }
+}
+
+
+
+
+
+/*** GetFMFromFile - Generate a FILEMARKS for marks in a file region
+*
+* Purpose:
+*
+* Generates a subset of a FILEMARKS structure whose marks fall
+* within a certain range. Needed by MarkCopy*.
+*
+* Input:
+* pFile - File to get marks from
+* xLeft, yTop - Start of range
+* xRight, yBottom - End of range
+*
+* Output:
+*
+* Returns Pointer to new structure, NULL if there are no marks in range
+*
+*************************************************************************/
+FILEMARKS *
+GetFMFromFile (
+ PFILE pFile,
+ COL xLeft,
+ LINE yTop,
+ COL xRight,
+ LINE yBottom
+ )
+{
+
+ FILEMARKS UNALIGNED * pfm = NULL;
+ REGISTER MARK UNALIGNED * pm;
+ fl flStart;
+ fl flEnd;
+ flagType fInRange = FALSE;
+
+ if (!fCacheMarks (pFile)) {
+ return NULL;
+ }
+
+ flStart.lin = yTop;
+ flStart.col = xLeft;
+ flEnd.lin = yBottom;
+ flEnd.col = xRight;
+
+ for (pm = pfmCache->marks; !TESTFLAG(pm->flags, MF_DUMMY); (char *)pm += pm->cb) {
+ if ((fInRange || flcmp (&flStart, (fl *) &pm->fl) < 1) &&
+ (flcmp ((fl *) &pm->fl, &flEnd) < 1)) {
+ fInRange = TRUE;
+ if ((pm->fl.col >= xLeft && pm->fl.col <= xRight)) {
+ UpdMark ( (FILEMARKS **) &pfm,
+ pm->szName,
+ pm->fl.lin - yTop + 1,
+ pm->fl.col - xLeft + 1,
+ (flagType)pm->flags);
+ }
+ } else {
+ break; /* We're out of range again*/
+ }
+ }
+ return (FILEMARKS *) pfm;
+}
+
+
+
+
+/*** AddFMToFile - Add a bunch of marks to a file
+*
+* Purpose:
+*
+* Insert the marks from one FILEMARKS structure into another. The
+* target structure is in pfmCache.
+*
+* Input:
+* pFile - Target file
+* pfm - Source marks
+* cZero - # of columns to adjust source marks to fit into target file
+* zZero - # of lines to adjust source marks to fit into target file
+*
+* Output: None
+*
+*************************************************************************/
+void
+AddFMToFile (
+ PFILE pFile,
+ FILEMARKS * pfm,
+ COL cZero,
+ LINE lZero
+ )
+{
+
+ REGISTER MARK UNALIGNED * pm;
+
+ if (lZero || cZero) {
+ for (pm = pfm->marks; !TESTFLAG(pm->flags, MF_DUMMY); (char *)pm += pm->cb) {
+ pm->fl.lin += lZero;
+ pm->fl.col += cZero;
+ }
+ }
+
+ if (!fCacheMarks (pFile)) {
+ (void)fFMtoPfile (pFile, pfm);
+ return;
+ }
+
+ for (pm = pfm->marks; !TESTFLAG(pm->flags, MF_DUMMY); (char *)pm += pm->cb) {
+ UpdMark (&pfmCache, pm->szName, pm->fl.lin+1, pm->fl.col+1, (flagType)pm->flags);
+ }
+}
+
+
+
+
+
+/*** FreeCache - Write a cache to VM
+*
+* Purpose:
+*
+* To save the marks for a file into VM.
+*
+* Input: None
+*
+* Output: None
+*
+*************************************************************************/
+void
+FreeCache (
+ void
+ ) {
+
+ if (pFileCache) {
+
+ assert (pfmCache);
+
+ if (fCacheDirty) {
+ if (pFileCache->vaMarks != NULL) {
+ FREE(pFileCache->vaMarks);
+ pFileCache->vaMarks = NULL;
+ }
+
+ memmove(pFileCache->vaMarks = MALLOC ((long)pfmCache->cb),
+ (char *)pfmCache,
+ pfmCache->cb);
+ }
+
+ FREE (pfmCache);
+ pFileCache = NULL;
+ pfmCache = NULL;
+ fCacheDirty = FALSE;
+ }
+}
+
+
+
+
+
+
+/*** fCacheMarks - Copy marks to a cache. Save caches contents if nec.
+*
+* Purpose:
+*
+* Before most mark operations can take place, the cache must contain
+* the marks for the given file.
+*
+* Input:
+* pFile - File to cache marks for.
+*
+* Output:
+*
+* Returns FALSE if the file has no marks, TRUE otherwise.
+*
+* Notes:
+*
+* On return the cache is usable whether or not the given file had marks.
+*
+*************************************************************************/
+flagType
+fCacheMarks (
+ PFILE pFile
+ ) {
+
+ unsigned cbCache;
+ FILEMARKS UNALIGNED *Marks;
+
+ assert (pFile);
+
+ // First we make sure that the VM version of
+ // marks is updated for this file. fReadMarks
+ // return TRUE iff the file has marks and they
+ // are in VM.
+ //
+ if (fReadMarks (pFile)) {
+
+ // The marks are ready to be cached. First,
+ // let's see if they are already chached.
+ //
+ if (pFileCache == pFile) {
+ return TRUE;
+ }
+
+ // They're not. If the cache is currently
+ // being used, we save it and clear it.
+ //
+ FreeCache ();
+
+ // Finally, alloc a new cache, plop
+ // the marks into it and mark the
+ // cache in use.
+ //
+ Marks = (FILEMARKS *)(pFile->vaMarks);
+ pfmCache = (FILEMARKS *)ZEROMALLOC (cbCache = (unsigned)(Marks->cb) );
+
+ memmove((char *)pfmCache, pFile->vaMarks, cbCache);
+
+ pFileCache = pFile;
+ fCacheDirty = FALSE;
+
+ return TRUE;
+ } else { /* No marks, return FALSE */
+ return FALSE;
+ }
+}
+
+
+
+
+
+
+/*** AdjustMarks - Change later marks when one has changed
+*
+* Purpose:
+*
+* To update marks in a FILEMARKS structure after some lines have been
+* added or removed.
+*
+* Input:
+* pm - pointer to first mark that has changed.
+* yDelta - Number of lines to change by. May be negative
+*
+* Output: None
+*
+*************************************************************************/
+void
+AdjustMarks (
+ REGISTER MARK * pm,
+ LINE yDelta
+ ) {
+
+ REGISTER MARK UNALIGNED * pm1;
+
+ assert (pm);
+
+ pm1 = pm;
+ for (;!TESTFLAG(pm1->flags, MF_DUMMY); (char *)pm1 += pm1->cb) {
+ pm1->fl.lin += yDelta;
+ SETFLAG (pm1->flags, MF_DIRTY);
+ }
+ fCacheDirty = TRUE;
+}
+
+
+
+
+
+
+/*** fFMtoPfile - Attach a FILEMARKS structure to a pFile.
+*
+* Purpose:
+*
+* To attach some marks to a file.
+*
+* Input:
+* pFile - File to get the marks
+* pfm - The marks
+*
+* Output:
+*
+* Returns TRUE if there were any marks, FALSE if not.
+*
+*************************************************************************/
+flagType
+fFMtoPfile (
+ PFILE pFile,
+ FILEMARKS * pfm
+ ) {
+
+ SETFLAG (FLAGS(pFile), VALMARKS);
+
+ if (pFile->vaMarks != NULL) {
+ FREE(pFile->vaMarks);
+ pFile->vaMarks = NULL;
+ }
+ return (flagType)((pFile->vaMarks = FMtoVM (pfm)) != NULL);
+}
+
+
+
+
+
+/*** fFMtoPfile - Copy a FILEMARKS structure into VM, return address
+*
+* Purpose:
+*
+* To convert a local FILEMARKS structure into a VM copy. Allocates
+* the VM and frees the local memory.
+*
+* Input:
+* pfm - Pointer to FILEMARKS. May be NULL.
+*
+* Output:
+*
+*
+*************************************************************************/
+PVOID
+FMtoVM (
+ FILEMARKS * pfm
+ ) {
+
+ PVOID l = NULL;
+
+ if (pfm) {
+
+ l = MALLOC ((long)(pfm->cb));
+ memmove(l, (char *)pfm, pfm->cb);
+
+ //
+ // I do not free pfm here because this should be done by the
+ // caller.
+ //
+ // if (pfm != pfmCache) {
+ // FREE (pfm);
+ // }
+
+ }
+
+ return l;
+}
+
+
+
+
+/*** GetMarkRange - Get a VM copy of a range of marks
+*
+* Purpose:
+*
+* Used by <undo> to get the marks attached to a piece of a file.
+*
+* Input:
+* pFile - File to check
+* xLeft, yTop - Upper left corner of range
+* xRight, yBottom - Lower right corner of range
+*
+* Output:
+*
+* Returns VM address of structure
+*
+*************************************************************************/
+PVOID
+GetMarkRange (
+ PFILE pFile,
+ LINE yStart,
+ LINE yEnd
+ ) {
+ return FMtoVM (GetFMFromFile (pFile, 0, yStart, sizeof(linebuf), yEnd));
+}
+
+
+
+
+/*** PutMarks - Put marks back into a file.
+*
+* Purpose:
+*
+* Used by <undo> to restore marks to a file.
+*
+* Input:
+* pfm - Pointer to FILEMARKS. May be NULL.
+*
+* Output:
+*
+*
+*************************************************************************/
+void
+PutMarks (
+ PFILE pFile,
+ PVOID vaMarks,
+ LINE y
+ ) {
+
+ FILEMARKS UNALIGNED * pfm;
+ FILEMARKS * Marks;
+ unsigned cb;
+
+ if ( vaMarks ) {
+
+ Marks = ((FILEMARKS *)vaMarks);
+
+ pfm = (FILEMARKS *)ZEROMALLOC (cb = (unsigned)Marks->cb);
+ memmove((char *)pfm, vaMarks, cb);
+
+ AddFMToFile (pFile, (FILEMARKS *) pfm, 0, y);
+ }
+}
+
+
+
+
+
+/*** flcmp - Returns relative position of two FL's
+*
+* Purpose:
+*
+* Useful for comparing the positions of two marks.
+*
+* Input:
+* pfl1 - "Left side" mark
+* pfl2 - "Right side" mark
+*
+* Output:
+*
+* Returns:
+*
+* < 0 *pfl1 < *pfl2
+* = 0 *pfl1 = *pfl2
+* > 0 *pfl1 > *pfl2
+*
+*
+*************************************************************************/
+int
+flcmp (
+ REGISTER fl * pfl1,
+ REGISTER fl * pfl2
+ ) {
+
+ REGISTER fl UNALIGNED * fl1 = pfl1;
+ REGISTER fl UNALIGNED * fl2 = pfl2;
+
+ if (fl1->lin < fl2->lin) {
+ return -1;
+ } else if (fl1->lin == fl2->lin) {
+ return fl1->col - fl2->col;
+ } else {
+ return 1;
+ }
+}
diff --git a/private/utils/mep/src/mep.c b/private/utils/mep/src/mep.c
new file mode 100644
index 000000000..6f9829f7f
--- /dev/null
+++ b/private/utils/mep/src/mep.c
@@ -0,0 +1,417 @@
+/*** mep.c - top level for editor
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+* 26-Nov-1991 mz Strip off near/far
+*************************************************************************/
+#define INCL_DOS
+
+#include "mep.h"
+#include "version.h"
+
+
+#define DEBFLAG Z
+
+/*
+ * use double macro level to force rup to be turned into string representation
+ */
+#define VER(x,y,z) VER2(x,y,z)
+#define VER2(x,y,z) "Version "###x##"."###y"."###z" "szVerName
+
+char Name[] = "Microsoft (R) Editor";
+char Version[] = VER(rmj,rmm,rup);
+char CopyRight[] = "Copyright (C) Microsoft Corp 1987-1990. All rights reserved";
+
+
+/*** main - program entry
+*
+* Input:
+* C standard command line parameters. Recognizes:
+*
+* /e string - Execute string of commands on startup
+* /t - Following file is "temporary", not kept in file history
+* /D - Don't read tools.ini
+* /r - Global no-edit mode (can't edit files)
+* /m markname - Start up at given mark
+* /pwb - Start as PWB
+*
+* When the editor is built with DEBUG defined, the following are also
+* recognized:
+*
+* /d debflags - Specifies which debugging to turn on
+* /f filename - Specifies file for debug output
+*
+* The following are present in the CW version of the editor only. They are
+* for testing only and should NOT be documented:
+*
+* /vt tapename- Set tape name
+* /vr - Record messages to file "default.key"
+* /vp - Play back messages from file "default.key"
+* /vd digit - Set playback delay from 0 to 9
+*
+*
+* Output:
+* Returns nothing. Exits via CleanExit()
+*
+* Exceptions:
+* Various and sundry, based on program operation
+*
+*************************************************************************/
+void _CRTAPI1
+main (
+ int c,
+ char **v
+ ) {
+
+ char *pExecute = NULL; /* string to execute on start */
+ char *szMark = NULL; /* mark to go to on start */
+ char *szName = v[0]; /* ptr to invokation name */
+ flagType InLoop = TRUE;
+
+ ConvertAppToOem( c, v );
+ SHIFT(c,v);
+#if DEBUG
+ debug = 0;
+ //debfh = stdout;
+#endif
+
+ while (c && fSwitChr (**v) && InLoop) {
+
+
+ switch ((*v)[1]) {
+#if DEBUG
+ case 'f':
+ case 'F':
+ SHIFT(c,v);
+ if ((debfh = MepFOpen(*v, ACCESSMODE_WRITE, SHAREMODE_RW, TRUE)) == NULL) {
+ printf("Can't open %s for debug output - using stdout\n", *v);
+ //debfh = stdout;
+ }
+ // setbuf(debfh, NULL);
+ break;
+#endif
+
+ case 'e':
+ case 'E':
+ //
+ // /e command to execute
+ //
+ if ( c > 1 ) {
+ SHIFT (c, v);
+ pExecute = *v;
+ }
+ break;
+
+ case 't':
+ case 'T':
+ //
+ // /t next file is temporary .. don't keep in file history
+ //
+ InLoop = FALSE;
+ break;
+
+
+#if DEBUG
+ case 'd':
+ //
+ // /d### debug level
+ //
+ SHIFT(c,v);
+ debug = ntoi (*v, 16);
+ break;
+#else
+ case 'd':
+#endif
+ case 'D':
+ //
+ // /D don't read tools.ini
+ //
+ fDefaults = TRUE;
+ break;
+
+ case 'r':
+ case 'R':
+ //
+ // /r Enter with noedit
+ //
+ fGlobalRO = TRUE;
+ break;
+
+ case 'm':
+ case 'M':
+ //
+ // /m markname - start at markname
+ //
+ SHIFT(c,v);
+ szMark = *v;
+
+ default:
+ printf ("%s %s\n", Name, Version);
+ printf ("%s\n", CopyRight);
+ printf("Usage: %s [/D] [/e cmd-string] [/m mark] [/r] [[/t] filename]*\n", szName);
+ fSaveScreen = FALSE;
+ exit(1);
+ break;
+ }
+ if (InLoop) {
+ SHIFT(c,v);
+ }
+ }
+
+ InitNames (szName);
+
+ cArgs = c;
+ pArgs = v;
+ // assert (_heapchk() == _HEAPOK);
+
+ /*
+ * At this point, command line arguments have been processed. Continue with
+ * initialization.
+ */
+ if (!init ()) {
+ CleanExit (1, CE_VM);
+ }
+
+ /*
+ * based on the re-entry state, take appropriate initial action:
+ * - PWB_ENTRY: process rest of command line
+ * - PWB_COMPILE: read compile log, and go to first error in log
+ * - PWB_SHELL: do nothing
+ */
+
+ if (szMark) {
+ GoToMark;
+ }
+ domessage (CopyRight);
+
+ Display ();
+
+ /*
+ * execute autostart macro if present
+ */
+ if (NameToFunc ("autostart")) {
+ fExecute ("autostart");
+ Display ();
+ }
+
+ /*
+ * execute command line /e parameter if present
+ */
+ if (pExecute) {
+ fExecute (pExecute);
+ }
+
+ TopLoop ();
+ CleanExit (0, CE_VM | CE_SIGNALS | CE_STATE);
+}
+
+
+
+
+
+/*** TopLoop - read a command and execute it until termination
+*
+* We read commands from the editor input and send them to the proper
+* recipients. We continue to do this until a termination flag is seen.
+*
+* Input:
+* None
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void
+TopLoop (
+ void
+ ) {
+ PCMD pFuncPrev = &cmdUnassigned;
+
+ while (!fBreak) {
+ PCMD pFunc = zloop (ZL_CMD | ZL_BRK);
+
+ if (pFunc != NULL) {
+ /* if prev wasn't graphic or this wasn't graphic then
+ * log a boundary
+ */
+ if (pFuncPrev->func != graphic || pFunc->func != graphic) {
+ LogBoundary ();
+ }
+ fRetVal = SendCmd (pFunc);
+ if (pFunc->func != cancel) {
+ if (fCtrlc) {
+ DoCancel ();
+ }
+ }
+ pFuncPrev = pFunc;
+ }
+ }
+ fBreak = FALSE;
+}
+
+
+
+
+
+/*** zloop - read next command, potentially updating screen
+*
+* zloop updates screen until a command is read that is not a macro
+* invocation. If a macro invocation is seen then just execute it and
+* continue. The reason for this is that the macro invocation will set up a
+* new input context that we'll retrieve in the next loop.
+*
+* We call RecordCmd for each command, in case we have recording on. If
+* the user has done <meta><record>, we record macro names, not their
+* values. This is because a macro with flow control, especially a loop,
+* will behave badly (possibly hang) because none of the editing commands
+* return values.
+*
+* Input:
+* flags - ZL_CMD command key, should be an event
+* - ZL_BRK take fBreak into account
+*
+* Output:
+* Returns a pointer to command structure that is next to be executed
+*
+*************************************************************************/
+PCMD
+zloop (
+ flagType flags
+ ) {
+
+ REGISTER PCMD pFunc;
+ EVTargs e;
+
+ while (!fBreak || !TESTFLAG(flags, ZL_BRK)) {
+
+ /*
+ * Between every command, check heap and pfile list consistancy
+ */
+ // assert (_heapchk() == _HEAPOK);
+ // assert (_pfilechk());
+
+ /* if macro in progress then
+ */
+ if (mtest ()) {
+ pFunc = mGetCmd ();
+ } else {
+ DoDisplay ();
+
+ do {
+ pFunc = ReadCmd ();
+ e.arg.key = keyCmd.KeyInfo;
+ if (!TESTFLAG(flags, ZL_CMD)) {
+ break;
+ }
+ } while (DeclareEvent (EVT_KEY, (EVTargs *)&e));
+ }
+
+ if (pFunc != NULL) {
+ RecordCmd (pFunc);
+ if (pFunc->func == macro) {
+ fRetVal = SendCmd (pFunc);
+ } else {
+ break;
+ }
+ }
+ }
+ return pFunc;
+}
+
+
+
+
+
+/*** Idle & IdleThread - Code executed at idle time
+*
+* Idle loop. Structured so that only ONE idle-item does something each time
+* though the loop. Ensures minimum exit delay. When nothing has
+* happened we sleep a bit each time, to make sure we're not hogging the CPU.
+*
+* Also causes the screen to be updated, if need be.
+*
+* Idle is structure so that routines which it calls return either:
+* TRUE - idle processing done, perhaps more to be done
+* FALSE - no idle processing done, and no more anticipated.
+*
+* Input:
+* none
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void
+IdleThread (
+ void
+ ) {
+ while (TRUE) {
+
+ WaitForSingleObject( semIdle, INFINITE);
+ Idle();
+ SetEvent( semIdle );
+ Sleep(100L);
+ }
+}
+
+
+
+flagType
+Idle (
+ void
+ ) {
+
+ if (TESTFLAG (fDisplay, (RTEXT | RCURSOR | RSTATUS))) {
+ DoDisplay ();
+ }
+
+ if (!DeclareEvent (EVT_IDLE, NULL)) {
+ if (!fIdleUndo (FALSE)) {
+ return FALSE;
+ }
+ }
+
+ /*
+ * got here, means someone processed idle, and may have more to do
+ */
+ return TRUE;
+}
+
+
+
+/*** IntError - Internal error Processor.
+*
+* Allow user to abort, or attempt to continue.
+*
+* Input:
+* p = pointer to error string
+*
+* Output:
+* Returns only if user says to.
+*
+*************************************************************************/
+void
+IntError (
+ char *p
+ ) {
+ static char pszMsg [] = "MEP internal error - %s, continue? ";
+
+ if ( OriginalScreen ) {
+ consoleSetCurrentScreen( OriginalScreen );
+ }
+ printf ("\n");
+ if (TESTFLAG (fInit, INIT_VIDEO)) {
+ if (!confirm (pszMsg, p)) {
+#if DEBUG
+ fflush (debfh);
+#endif
+ CleanExit (1, CE_STATE);
+ } else {
+ ;
+ }
+ } else {
+ printf (pszMsg, p);
+ CleanExit (1, FALSE);
+ }
+}
diff --git a/private/utils/mep/src/mep.ico b/private/utils/mep/src/mep.ico
new file mode 100644
index 000000000..0f0d2efe8
--- /dev/null
+++ b/private/utils/mep/src/mep.ico
Binary files differ
diff --git a/private/utils/mep/src/mep.rc b/private/utils/mep/src/mep.rc
new file mode 100644
index 000000000..471a5b4df
--- /dev/null
+++ b/private/utils/mep/src/mep.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Microsoft Extensible Editor"
+#define VER_INTERNALNAME_STR "mep"
+#define VER_ORIGINALFILENAME_STR "MEP.EXE"
+
+#include "common.ver"
+
+MEPICON ICON mep.ico
diff --git a/private/utils/mep/src/mepstr.c b/private/utils/mep/src/mepstr.c
new file mode 100644
index 000000000..d90e28e32
--- /dev/null
+++ b/private/utils/mep/src/mepstr.c
@@ -0,0 +1,172 @@
+/************************************************************************
+ *
+ * Microsoft Editor Messages and strings
+ *
+ *
+ * This file contains all the messages and strings used in MEP.
+ *
+ *
+ * Revision History:
+ *
+ * 9/28/90 ramonsa Adapted from original msg.txt file
+ *
+ ************************************************************************/
+
+
+
+/************************************************************************
+ *
+ * String constants
+ *
+ * Strings that are used only in a few places and that are used only by
+ * MEP are declared here.
+ *
+ ************************************************************************/
+
+
+
+
+
+
+
+/************************************************************************
+ *
+ * Messages
+ *
+ * Strings that might be shared are declared here for now. When the new
+ * message retriever is ready this might change.
+ *
+ * String constants are also declared here (for eliminating duplications)
+ * if:
+ *
+ * - They are long
+ * - They are used in different places but are not used extremely often
+ * (if they are used too often then they might be defined up here
+ * as constants to reduce the overhead at the expense of wasting
+ * memory.
+ *
+ *
+ * NOTE:
+ *
+ * Messages must have a number assigned in msg.h
+ *
+ ************************************************************************/
+
+#include "mep.h"
+
+
+MSG_TXT MsgStr[] = {
+
+//
+// 8000 series: error messages
+// // 8001
+ MSGERR_INV_ARG, "Invalid Argument", // 8002
+ MSGERR_ARG_REQ, "Argument Required", // 8003
+ MSGERR_NOEDIT, "No-Edit file may not be modified", // 8004
+ MSGERR_NOREP, "No command to repeat", // 8005
+ MSGERR_NOCREAT, "Cannot create %s - %s", // 8006
+ MSGERR_OPEN, "Cannot open %s - %s", // 8007
+ MSGERR_RONLY, "%s is read-only", // 8008
+ MSGERR_SPACE, "Out of space on %s", // 8009
+ MSGERR_DEL, "Can't delete %s - %s", // 8010
+ MSGERR_REN, "Can't rename %s to %s - %s", // 8011
+ MSGERR_OLDVER, "Can't delete old version of %s", // 8012
+ MSGERR_SAVEDIR, "Cannot save to directory: %s", // 8013
+ MSGERR_STFILE, "Unsupported status file version", // 8014
+ MSGERR_UNDO, "Nothing to UnDo", // 8015
+ MSGERR_REDO, "Nothing to ReDo", // 8016
+ MSGERR_ITHREAD, "Unable to start Idle thread", // 8017
+ MSGERR_CTHREAD, "Unable to start compile thread", // 8018
+ MSGERR_PTHREAD, "Unable to start printing thread", // 8019
+ MSGERR_TOOLS, "Unable to read TOOLS.INI[%s]", // 8020
+ MSGERR_ZFORMAT, "Unrecognized %% command in '%s'", // 8021
+ MSGERR_ZTELL, "%s is not an editor function or macro", // 8022
+ MSGERR_CMPCMD, "No compile command known", // 8023
+ MSGERR_CMPCMD2, "No compile command known for %s", // 8024
+ MSGERR_CMPFULL, "Compile list full, try later", // 8025
+ MSGERR_CMPCANT, "Cannot compile", // 8026
+ MSGERR_CMPSRC, "Source file not found: %s", // 8027
+ MSGERR_PRTFULL, "Print list full, try later", // 8025
+ MSGERR_PRTCANT, "Cannot print",
+ MSGERR_NOMEM, "Not enough memory",
+ MSGERR_QUIT, "Cannot recover from previous error, will quit",
+//
+// 9000 series: <assign> file text
+//
+ MSG_ASSIGN_HDR, "; Assigning Editor Functions and Macros to Keystrokes", // 9001
+ 9002, ";",
+ 9003, "; o To assign a function to a new key, find a line of the form",
+ 9004, "; \"func:keyname\" and replace \"keyname\" with the name of the new key.",
+ 9005, ";",
+ 9006, "; o To remove a function from a given key, find the line that reads",
+ 9007, "; \"unassigned:\" and append the key name.",
+ 9008, ";",
+ 9009, "; o The assignment you make will not take effect until you move the",
+ 9010, "; cursor to a different line. When you do, the line will be highlighted.",
+ 9011, ";",
+ 9012, "; o To make the assignment permanent, save this file.",
+ 9013, ";",
+ 9014, "; o A list of unused keys is shown after the assignment list.",
+ 9015, ";",
+ 9016, "; o To return to editing, use the File menu to switch back to your",
+ 9017, "; file.",
+ 9018, "?",
+
+ MSG_SWITCH_HDR, "; Setting Editor Switch Values", // 9025
+ 9026, ";",
+ 9027, "; o To change the value of a switch, find the line that shows the",
+ 9028, "; current value and enter a new value.",
+ 9029, ";",
+ 9030, "; o The change you make will not take effect until you move the cursor",
+ 9031, "; to a different line.",
+ 9032, "?",
+
+
+ MSG_KEYS_HDR1, "; Available Keys", // 9050
+ 9051, ";",
+ 9052, ";------------------------------------------------------------------------------",
+ 9053, "?",
+ MSG_KEYS_HDR2, "; PLAIN | SHIFT | CTRL | ALT | SHIFT+CTRL", // 9054
+ 9055, ";------------------------------------------------------------------------------",
+ 9056, "?",
+
+ MSG_ASG_FUNC, "; Instrinsic Editor Functions", // 9061
+ MSG_ASG_MACROS, "; Macros", // 9062
+ MSG_ASG_NUMER, "; Numeric Switches", // 9063
+ MSG_ASG_BOOL, "; Boolean Switches", // 9064
+ MSG_ASG_TEXT, "; Text Switches", // 9065
+ MSG_ASG_CLIP, "The clipboard is empty", // 9066
+ MSG_ASG_LINES, "%ld line%s in %s clipboard", // 9067
+ MSG_ASG_PAGES, "%d virtual pages", // 9068
+//
+// 10000 series: misc utility text
+//
+ MSG_PRESS_ANY, "Press any key...", // 10000
+ MSG_ARGCOUNT, "Arg [%d]", // 10001
+ MSG_NEXTFILE, "Next file is %s...", // 10002
+ MSG_SAVING, "Saving %s...", // 10003
+ MSG_TELLPROMPT, "Press key to tell about:", // 10004
+ MSG_SAVEALL, "Save all remaining changed files (Y/N)?", // 10005
+ MSG_SAVEONE, "%s has changed! Save changes (Y/N)?", // 10006
+ MSG_QUEUED, "Queued: %s", // 10007
+ MSG_CMPDONE, "Compilation complete", // 10008
+ MSG_PRINTING, "Printing %s... Press Esc to abort", // 10009
+ MSG_SCANFILE, "Scanning %s...", // 10010
+//
+// 10100: assign errors
+//
+ MSG_ASN_MISS, "missing ':' in %s", // 10100
+ MSG_ASN_MISSK, "Missing key assignment for '%s'", // 10101
+ MSG_ASN_UNKKEY, "'%s' is an unknown key", // 10102
+ MSG_ASN_INUSE, "macro %s is in use", // 10103
+ MSG_ASN_MROOM, "Not enough room for macro %s", // 10104
+ MSG_ASN_NOTSWI, "%s is not an editor switch", // 10105
+ MSG_ASN_ILLSET, "Illegal setting", // 10106
+ MSG_ASN_WINCHG, "Cannot change screen parameters when windows present", // 10107
+ MSG_ASN_UNSUP, "Not supported by video display", // 10108
+ MSG_ASN_INVAL, "%Fs: Invalid value '%s'", // 10109
+//
+// End of array
+//
+ 0, ""
+};
diff --git a/private/utils/mep/src/mouse.c b/private/utils/mep/src/mouse.c
new file mode 100644
index 000000000..93d1d47ca
--- /dev/null
+++ b/private/utils/mep/src/mouse.c
@@ -0,0 +1,283 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ mouse.c
+
+Abstract:
+
+ Mouse support for MEP
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 07-Nov-1991
+
+
+Revision History:
+
+
+--*/
+
+#include <string.h>
+#include "mep.h"
+#include "cmds.h"
+#include "mouse.h"
+
+
+
+void
+DoMouseInWindow(
+ ROW Row,
+ COLUMN Col,
+ DWORD MouseFlags
+ );
+
+flagType
+SetCurrentWindow(
+ int iWin
+ );
+
+void
+DoMouse(
+ ROW Row,
+ COLUMN Col,
+ DWORD MouseFlags
+ )
+/*++
+
+Routine Description:
+
+ Handles Mouse events. Invoked by the MEP console interface
+
+Arguments:
+
+ Row - Supplies row position of the mouse
+ Col - Supplies column position of the mouse
+ MouseFlags - Supplies miscelaneous flags
+
+Return Value:
+
+ none
+
+--*/
+
+
+{
+ int i;
+ KBDKEY Key;
+ static BOOL Clicked = FALSE;
+ static BOOL Dragging = FALSE;
+ static BOOL InMouse = FALSE;
+ static ROW LastRow;
+ static COLUMN LastCol;
+ struct windowType *winTmp;
+
+ if ( fUseMouse ) {
+ if ( !InMouse ) {
+ InMouse = TRUE;
+ if ( MouseFlags & MOUSE_CLICK_LEFT ) {
+ //
+ // If dragging, start selection
+ //
+ if ( !fInSelection && Clicked && !Dragging && ( (LastRow != Row) || (LastCol != Col) ) ) {
+
+
+ //#ifdef DEBUG
+ // char dbgb[256];
+ // sprintf( dbgb, " MOUSE: Selecting at Row %d, Col %d\n", Row, Col );
+ // OutputDebugString( dbgb );
+ //#endif
+ //
+ // Start selection
+ //
+ Key.Unicode = 'A';
+ Key.Scancode = 'A';
+ Key.Flags = CONS_RIGHT_ALT_PRESSED;
+
+ consolePutMouse( Row, Col, MouseFlags );
+ consolePutKey( &Key );
+ consolePutMouse( LastRow, LastCol, MouseFlags );
+
+ Dragging = TRUE;
+ InMouse = FALSE;
+
+ return;
+
+ } else {
+
+ Clicked = TRUE;
+ LastRow = Row;
+ LastCol = Col;
+ }
+
+ } else {
+
+ Clicked = FALSE;
+ Dragging = FALSE;
+ }
+
+ if ( cWin == 1 ) {
+
+ DoMouseInWindow( Row, Col, MouseFlags );
+
+ } else {
+
+ //
+ // Determine what window we're in
+ //
+ for ( i=0; i<cWin; i++ ) {
+
+ winTmp = &(WinList[i]);
+
+ if ( ( (LINE)(Row-1) >= WINYPOS( winTmp ) ) &&
+ ( (LINE)(Row-1) <= WINYPOS( winTmp ) + WINYSIZE( winTmp ) ) &&
+ ( (COL)(Col-1) >= WINXPOS( winTmp ) ) &&
+ ( (COL)(Col-1) < WINXPOS( winTmp ) + WINXSIZE( winTmp ) ) ) {
+
+ //
+ // Found the window that we're in. Make that window
+ // the current (i.e. "active" window ).
+ //
+ iCurWin = i;
+
+ if ( (winTmp == pWinCur) || SetCurrentWindow (iCurWin) ) {
+
+ DoMouseInWindow( Row - WINYPOS( winTmp ),
+ Col - WINXPOS( winTmp ),
+ MouseFlags );
+ }
+
+ break;
+ }
+ }
+ }
+
+ InMouse = FALSE;
+ }
+ }
+}
+
+
+flagType
+SetCurrentWindow(
+ int iWin
+ )
+{
+ flagType f;
+
+ WaitForSingleObject(semIdle, INFINITE);
+
+ f = SetWinCur( iWin );
+
+ SetEvent( semIdle );
+
+ return f;
+}
+
+
+void
+DoMouseInWindow(
+ ROW Row,
+ COLUMN Col,
+ DWORD MouseFlags
+ )
+/*++
+
+Routine Description:
+
+ Handles Mouse events. Called by DoMouse after setting the active
+ window.
+
+Arguments:
+
+ Row - Supplies row position of the mouse
+ Col - Supplies column position of the mouse
+ MouseFlags - Supplies miscelaneous flags
+
+Return Value:
+
+ none
+
+--*/
+
+{
+
+ KBDKEY Key;
+ static BOOL fFirstClick = FALSE;
+
+ WaitForSingleObject(semIdle, INFINITE);
+
+ //
+ // If the mouse is clicked, move the cursor to the mouse position.
+ //
+ if ( MouseFlags & MOUSE_CLICK_LEFT ) {
+
+ //
+ // Toggle boxmode if necessary
+ //
+ if ( fInSelection && (MouseFlags & MOUSE_CLICK_RIGHT) ) {
+ SendCmd( CMD_boxstream );
+ }
+
+ if ( (LINE)(Row-1) == WINYPOS( pWinCur ) + WINYSIZE( pWinCur ) ) {
+
+ //
+ // scroll the window
+ //
+ Key.Unicode = '\0';
+ Key.Scancode = VK_DOWN;
+ Key.Flags = 0;
+
+ consolePutMouse( Row + WINYPOS( pWinCur )-1,
+ Col + WINXPOS( pWinCur ),
+ MouseFlags );
+ consolePutKey( &Key );
+
+ } else if ( (LINE)(Row-1) < WINYPOS( pWinCur ) + WINYSIZE( pWinCur ) ) {
+
+ //
+ // Move the cursor to the new location
+ //
+ docursor( XWIN(pInsCur) + Col - 1, YWIN(pInsCur) + Row - 1 );
+
+ //
+ // If we are making a selection, hilite it
+ //
+ if ( fInSelection ) {
+ UpdateHighLight ( XCUR(pInsCur), YCUR(pInsCur), TRUE);
+ }
+ }
+
+ } else if ( MouseFlags & MOUSE_CLICK_RIGHT ) {
+
+ if ( !fInSelection ) {
+
+ if ( !fFirstClick ) {
+
+ fFirstClick = TRUE;
+
+ if ( (LINE)(Row-1) < WINYPOS( pWinCur ) + WINYSIZE( pWinCur ) ) {
+
+ //
+ // Position the cursor and press the F1 key
+ //
+ docursor( XWIN(pInsCur) + Col - 1, YWIN(pInsCur) + Row - 1 );
+
+ Key.Unicode = 0;
+ Key.Scancode = VK_F1;
+ Key.Flags = 0;
+ consolePutKey( &Key );
+ }
+ }
+ }
+
+ } else {
+
+ fFirstClick = FALSE;
+ }
+
+ SetEvent( semIdle );
+
+}
diff --git a/private/utils/mep/src/newline.c b/private/utils/mep/src/newline.c
new file mode 100644
index 000000000..869776ee4
--- /dev/null
+++ b/private/utils/mep/src/newline.c
@@ -0,0 +1,51 @@
+/* newline.c - move to the next line
+ *
+ * Modifications:
+ * 26-Nov-1991 mz Strip off near/far
+ */
+
+#include "mep.h"
+
+
+
+/* move to a new line unless in insert mode, then we split the current line
+ */
+flagType
+emacsnewl (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ ) {
+
+ int tmpx;
+
+ if (fInsert && !argcount) {
+ tmpx = softcr ();
+ CopyStream (NULL, pFileHead, XCUR (pInsCur), YCUR (pInsCur),
+ tmpx, YCUR (pInsCur)+1,
+ XCUR (pInsCur), YCUR (pInsCur));
+
+ redraw( pFileHead, YCUR(pInsCur)-1, YCUR(pInsCur)+1 );
+
+ docursor (tmpx, YCUR (pInsCur)+1);
+ return TRUE;
+ } else {
+ return newline (argData, pArg, fMeta);
+ }
+}
+
+
+
+
+flagType
+newline (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ ) {
+
+ docursor (fMeta ? 0 : softcr (), YCUR(pInsCur)+1);
+ return TRUE;
+
+ argData; pArg;
+}
diff --git a/private/utils/mep/src/pbal.c b/private/utils/mep/src/pbal.c
new file mode 100644
index 000000000..03a0b8e04
--- /dev/null
+++ b/private/utils/mep/src/pbal.c
@@ -0,0 +1,133 @@
+/*** pbal.c - balance parenthesis
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+* 26-Nov-1991 mz Strip off near/far
+*************************************************************************/
+
+#include "mep.h"
+
+
+#define BALOPEN "([{"
+#define BALCLOS ")]}"
+
+static flagType fBalMeta;
+
+
+
+flagType
+pbal (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ ) {
+
+ flagType fFor;
+ fl flCur;
+
+ fBalMeta = fMeta;
+
+ switch (pArg->argType) {
+
+ case NOARG: /* balance a single character */
+ balopen = BALOPEN;
+ balclose = BALCLOS;
+ setAllScan (fFor = FALSE);
+ break;
+
+
+ /* TEXTARG illegal */
+
+
+ case NULLARG:
+ balopen = BALCLOS;
+ balclose = BALOPEN;
+ setAllScan (fFor = TRUE);
+ break;
+
+ /* LINEARG illegal */
+ /* STREAMARG illegal */
+ /* BOXARG illegal */
+
+ }
+
+
+ ballevel = 0;
+ flCur.col = XCUR(pInsCur);
+ flCur.lin = YCUR(pInsCur);
+
+ if (!fScan (flCur, FNADDR(fDoBal), fFor, FALSE)) {
+ domessage ("No unbalanced characters found");
+ return FALSE;
+ }
+ return TRUE;
+
+ argData;
+}
+
+
+
+
+
+flagType
+fDoBal (
+ void
+ ) {
+
+ int k, x;
+
+ if ((k=InSet(scanbuf[flScan.col], balclose)) != -1) {
+ ballevel ++;
+ } else if ((k=InSet(scanbuf[flScan.col], balopen)) != -1) {
+ if (--ballevel < 0) {
+ HighLight (flScan.col, flScan.lin, flScan.col, flScan.lin);
+ if (!fInRange ((long)XWIN (pInsCur), (long)flScan.col, (long)(XWIN (pInsCur) + WINXSIZE(pWinCur))-1) ||
+ !fInRange (YWIN (pInsCur), flScan.lin, (YWIN (pInsCur) + WINYSIZE(pWinCur))-1)) {
+ /* Balance point not on screen, put onto status line
+ */
+ x = strlen (scanbuf);
+ if (x >= XSIZE) {
+ if (x - flScan.col < XSIZE/2) {
+ memmove ((char *) scanbuf, (char *) scanbuf + x - XSIZE, XSIZE);
+ flScan.col -= x - XSIZE;
+ } else {
+ memmove ((char *) scanbuf, (char *) scanbuf + flScan.col - XSIZE/2, XSIZE);
+ flScan.col = XSIZE/2;
+ }
+ }
+ scanbuf[XSIZE] = 0;
+ scanbuf[flScan.col] = 0;
+ x = sout (0, YSIZE, scanbuf, infColor);
+ x = vout (x, YSIZE, &balopen[k], 1, hgColor);
+ soutb (x, YSIZE, &scanbuf[flScan.col+1], infColor);
+ }
+ if (!fBalMeta) {
+ edit (balclose[k]);
+ }
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+
+
+
+int
+InSet (
+ char c,
+ char *p
+ )
+{
+
+ int i;
+
+ for (i=0; *p; i++) {
+ if (*p++ == c) {
+ return i;
+ }
+ }
+ return -1;
+}
diff --git a/private/utils/mep/src/pick.c b/private/utils/mep/src/pick.c
new file mode 100644
index 000000000..5b681af4a
--- /dev/null
+++ b/private/utils/mep/src/pick.c
@@ -0,0 +1,469 @@
+/*** pick.c - pick a piece of text and put it into the put buffer
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+#include "mep.h"
+
+
+#define DEBFLAG PICK
+
+
+
+flagType
+zpick (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ ) {
+
+ buffer pbuf;
+
+ /* LINEARG illegal */
+ /* BOXARG illegal */
+
+ switch (pArg->argType) {
+
+ case NOARG:
+ pick (0, pArg->arg.noarg.y, 0, pArg->arg.noarg.y, LINEARG);
+ return TRUE;
+
+ case TEXTARG:
+ if (pFilePick != pFileHead) {
+ DelFile (pFilePick, TRUE);
+ }
+ strcpy ((char *) pbuf, pArg->arg.textarg.pText);
+ PutLine ((LINE)0, pbuf, pFilePick);
+ kindpick = BOXARG;
+ return TRUE;
+
+ /* NULLARG is converted into TEXTARG */
+
+ case LINEARG:
+ pick (0, pArg->arg.linearg.yStart,
+ 0, pArg->arg.linearg.yEnd, LINEARG);
+ return TRUE;
+
+ case BOXARG:
+ pick (pArg->arg.boxarg.xLeft, pArg->arg.boxarg.yTop,
+ pArg->arg.boxarg.xRight, pArg->arg.boxarg.yBottom, BOXARG);
+ return TRUE;
+
+ case STREAMARG:
+ pick (pArg->arg.streamarg.xStart, pArg->arg.streamarg.yStart,
+ pArg->arg.streamarg.xEnd, pArg->arg.streamarg.yEnd, STREAMARG);
+ return TRUE;
+ }
+
+ argData; fMeta;
+}
+
+
+
+
+void
+pick (
+ COL xstart,
+ LINE ystart,
+ COL xend,
+ LINE yend,
+ int kind
+ )
+{
+
+ if (pFilePick != pFileHead) {
+ DelFile (pFilePick, TRUE);
+ }
+ kindpick = kind;
+
+ switch (kind) {
+
+ case LINEARG:
+ CopyLine (pFileHead, pFilePick, ystart, yend, (LINE)0);
+ break;
+
+ case BOXARG:
+ CopyBox (pFileHead, pFilePick, xstart, ystart, xend, yend, (COL)0, (LINE)0);
+ break;
+
+ case STREAMARG:
+ CopyStream (pFileHead, pFilePick, xstart, ystart, xend, yend, (COL)0, (LINE)0);
+ break;
+ }
+}
+
+
+
+
+flagType
+put (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ )
+{
+
+ flagType fTmp = FALSE;
+ int i;
+ buffer putbuf;
+ pathbuf filebuf;
+ FILEHANDLE fh;
+ PFILE pFileTmp;
+ char *pBuf;
+
+
+ switch (pArg->argType) {
+
+ case BOXARG:
+ case LINEARG:
+ case STREAMARG:
+ delarg (pArg);
+ break;
+
+ case TEXTARG:
+ strcpy ((char *) buf, pArg->arg.textarg.pText);
+ DelFile (pFilePick, TRUE);
+ if (pArg->arg.textarg.cArg > 1) {
+ pBuf = whiteskip (buf);
+ if (*pBuf == '!') {
+ findpath ("$TMP:z.$", filebuf, TRUE);
+ fTmp = TRUE;
+ sprintf (putbuf, "%s >%s", pBuf+1, filebuf);
+ zspawnp (putbuf, TRUE);
+ pBuf = filebuf;
+ }
+ if (*pBuf != '<') {
+ CanonFilename (pBuf, putbuf);
+ } else {
+ strcpy (putbuf, pBuf);
+ }
+ //
+ // If we find the file in the existing file history, read it in, if not already
+ // in, and just to a copy operation on the desired text.
+ //
+ if ((pFileTmp = FileNameToHandle (putbuf, pBuf)) != NULL) {
+ if (!TESTFLAG (FLAGS (pFileTmp), REAL)) {
+ if (!FileRead(pFileTmp->pName,pFileTmp, FALSE)) {
+ printerror ("Cannot read %s", pFileTmp->pName);
+ return FALSE;
+ }
+ }
+ CopyLine (pFileTmp, pFilePick, (LINE)0, pFileTmp->cLines-1, (LINE)0);
+ } else {
+ if ((fh = MepFOpen(putbuf, ACCESSMODE_READ, SHAREMODE_RW, FALSE)) == NULL) {
+ printerror ("%s does not exist", pBuf);
+ return FALSE;
+ }
+ readlines (pFilePick, fh);
+ MepFClose (fh);
+ }
+ if (fTmp) {
+ _unlink (filebuf);
+ }
+ kindpick = LINEARG;
+ } else {
+ PutLine ((LINE)0, buf, pFilePick);
+ kindpick = BOXARG;
+ }
+ break;
+ }
+
+ switch (kindpick) {
+
+ case LINEARG:
+ CopyLine (pFilePick, pFileHead, (LINE)0, pFilePick->cLines-1, YCUR (pInsCur));
+ break;
+
+ case BOXARG:
+ i = LineLength ((LINE)0, pFilePick);
+ CopyBox (pFilePick, pFileHead, 0, (LINE)0, i-1, pFilePick->cLines-1, XCUR (pInsCur), YCUR (pInsCur));
+ break;
+
+ case STREAMARG:
+ i = LineLength (pFilePick->cLines-1, pFilePick);
+ CopyStream (pFilePick, pFileHead, 0, (LINE)0, i, pFilePick->cLines-1, XCUR (pInsCur), YCUR (pInsCur));
+ break;
+ }
+
+ return TRUE;
+
+ argData; fMeta;
+}
+
+
+
+
+/*** CopyLine - copy lines between files
+*
+* If the source file is NULL, then we insert blank lines.
+*
+* Input:
+* pFileSrc = source file handle
+* pFileDst = destination file handle
+* yStart = first line to be copied
+* yEnd = last line to be copied
+* yDst = location of destination of copy
+*
+*************************************************************************/
+void
+CopyLine (
+ PFILE pFileSrc,
+ PFILE pFileDst,
+ LINE yStart,
+ LINE yEnd,
+ LINE yDst
+ )
+{
+ linebuf buf;
+ struct lineAttr * rgla = (struct lineAttr *)ZEROMALLOC (sizeof(linebuf) * sizeof(struct lineAttr));
+
+ if (pFileSrc != pFileDst) {
+ if (yStart <= yEnd) {
+ InsLine (TRUE, yDst, yEnd - yStart + 1, pFileDst);
+ if (pFileSrc != NULL) {
+ MarkCopyLine (pFileSrc, pFileDst, yStart, yEnd, yDst);
+ while (yStart <= yEnd) {
+ gettextline (TRUE, yStart++, buf, pFileSrc, ' ');
+ puttextline (TRUE, TRUE, yDst++, buf, pFileDst);
+ if (getcolorline (TRUE, yStart-1, rgla, pFileSrc)) {
+ putcolorline (TRUE, yDst-1, rgla, pFileDst);
+ }
+ }
+ }
+ }
+ }
+ FREE (rgla);
+}
+
+
+
+
+/*** CopyBox - copy a box from one place to another
+*
+* If the source file is NULL, then we insert blank space. We copy the box
+* defined by the LOGICAL box xLeft-xRight and yTop-yBottom inclusive.
+*
+* Input:
+* pFileSrc = source file handle
+* pFileDst = destination file handle
+* xLeft = column location of beginning of copy
+* yTop = line location of beginning of copy
+* xRight = column location of end of copy
+* yBottom = line location of end of copy
+* xDst = column location of destination of copy
+* yDst = line location of destination of copy
+*
+*************************************************************************/
+void
+CopyBox (
+ PFILE pFileSrc,
+ PFILE pFileDst,
+ COL xLeft,
+ LINE yTop,
+ COL xRight,
+ LINE yBottom,
+ COL xDst,
+ LINE yDst
+ )
+{
+ int cbDst; /* count of bytes in destination*/
+ int cbMove; /* count of bytes to move around*/
+ linebuf dstbuf; /* buffer for result */
+ char *pDst; /* physical pointer to dest */
+ char *pSrcLeft; /* physical pointer to src left */
+ char *pSrcRight; /* physical pointer to src right+1*/
+ linebuf srcbuf; /* buffer for source line */
+ struct lineAttr rgla[sizeof(linebuf)];
+ flagType fColor;
+
+ /*
+ * Do not allow overlapped copies.
+ */
+ if ((pFileSrc == pFileDst)
+ && (( fInRange ((LINE)xLeft, (LINE)xDst, (LINE)xRight)
+ && fInRange (yTop, yDst, yBottom))
+ || ( fInRange ((LINE)xLeft, (LINE)(xDst + xRight - xLeft), (LINE)xRight)
+ && fInRange (yTop, yDst + yBottom - yTop, yBottom))
+ )
+ ) {
+ return;
+ }
+
+ /*
+ * If valid left and right coordinates for box, then for each line...
+ */
+ if (xLeft <= xRight) {
+ /*
+ * Let the Marker update any affected marks.
+ */
+ MarkCopyBox (pFileSrc, pFileDst, xLeft, yTop, xRight, yBottom, xDst, yDst);
+ while (yTop <= yBottom) {
+
+ if (!pFileSrc) {
+ //
+ // File is not a file, just insert spaces.
+ //
+ if (!fInsSpace (xDst, yDst, xRight - xLeft + 1, pFileDst, dstbuf)) {
+ LengthCheck (yDst, 0, NULL);
+ }
+ pDst = pLog (dstbuf, xDst, TRUE);
+ } else {
+ //
+ // When source IS a file, we:
+ // - get both source and destination lines
+ // - ensure that the source line is detabbed (only way to ensure proper
+ // alignment in the copy.
+ // - get phsical pointers to right and left of source.
+ // - get phsical pointer to destination
+ // - get length of physical move and current destination
+ // - physical length check the potential destination result
+ // - open up a hole in the destination line for the source
+ // - copy the source range into the destination
+ // - perform logical length check.
+ //
+ fInsSpace (xRight+1, yTop, 0, pFileSrc, fRealTabs ? dstbuf : srcbuf);
+ if (fRealTabs) {
+ Untab (fileTab, dstbuf, strlen(dstbuf), srcbuf, ' ');
+ }
+ fInsSpace (xDst, yDst, 0, pFileDst, dstbuf);
+
+ pSrcLeft = pLog (srcbuf, xLeft, TRUE);
+ pSrcRight = pLog (srcbuf, xRight, TRUE) + 1;
+
+ pDst = pLog (dstbuf, xDst, TRUE);
+
+ cbMove = pSrcRight - pSrcLeft;
+ cbDst = strlen (dstbuf);
+
+ if (cbDst + cbMove > sizeof(linebuf)) {
+ LengthCheck (yDst, 0, NULL);
+ } else {
+ memmove (pDst + cbMove, pDst, strlen(dstbuf) - (pDst - dstbuf) + 1);
+
+ memmove (pDst, pSrcLeft, cbMove);
+
+ if (cbLog(dstbuf) > sizeof(linebuf)) {
+ LengthCheck (yDst, 0, NULL);
+ *pLog (dstbuf, sizeof(linebuf) - 1, TRUE) = 0;
+ }
+ }
+ }
+ if (fColor = GetColor (yDst, rgla, pFileDst)) {
+ if (pFileSrc) {
+ CopyColor (pFileSrc, pFileDst, yTop, xLeft, cbMove, yDst, xDst);
+ } else {
+ ShiftColor (rgla, pDst - dstbuf, xRight - xLeft + 1);
+ ColorToLog (rgla, dstbuf);
+ }
+ }
+ PutLine (yDst, dstbuf, pFileDst);
+ if (fColor) {
+ PutColor (yDst, rgla, pFileDst);
+ }
+ yDst++;
+ yTop++;
+ }
+ }
+}
+
+
+
+
+
+/*** CopyStream - copy a stream of text (including end-of-lines)
+*
+* If source file is NULL, then we insert blank space. We copy starting at
+* xStart/yStart and copy through to the character before xEnd/yEnd. This
+* means that to copy line Y INCLUDING the line separator, we specify
+* (xStart,yStart) = (0,Y) and (xEnd,yEnd) = (0, Y+1)
+*
+* Input:
+* pFileSrc = source file handle
+* pFileDst = destination file handle
+* xStart = column location of beginning of copy
+* yStart = line location of beginning of copy
+* xEnd = column location of end of copy
+* yEnd = line location of end of copy
+* xDst = column location of destination of copy
+* yDst = line location of destination of copy
+*
+*************************************************************************/
+void
+CopyStream (
+ PFILE pFileSrc,
+ PFILE pFileDst,
+ COL xStart,
+ LINE yStart,
+ COL xEnd,
+ LINE yEnd,
+ COL xDst,
+ LINE yDst
+ )
+{
+ linebuf dstbuf; /* buffer for result */
+ char *pDst;
+ linebuf srcbuf; /* buffer for source line */
+ LINE yDstLast;
+
+ /*
+ * validate copy...must be different files, and coordinates must make sense.
+ */
+ if (!(pFileSrc != pFileDst &&
+ (yStart < yEnd || (yStart == yEnd && xStart < xEnd)))) {
+ return;
+ }
+
+ /*
+ * Special case a single-line stream as a box copy
+ */
+ if (yStart == yEnd) {
+ CopyBox (pFileSrc, pFileDst, xStart, yStart, xEnd-1, yEnd, xDst, yDst);
+ return;
+ }
+
+ /*
+ * Valid stream copy. First, copy the intermediate lines.
+ */
+ CopyLine (pFileSrc, pFileDst, yStart+1, yEnd, yDst+1);
+
+ /*
+ * Form last line of destination stream. Copy last part of dest line onto
+ * last part of last source line. Make sure that each copy of the
+ * source/dest is correct length
+ */
+ fInsSpace (xDst, yDst, 0, pFileDst, dstbuf); /* dddddeeeeee */
+ if (pFileSrc != NULL) {
+ fInsSpace (xEnd, yEnd, 0, pFileSrc, srcbuf);/* AAAABBBBB */
+ } else {
+ memset ((char *) srcbuf, ' ', xEnd);
+ }
+ pDst = pLog (dstbuf,xDst, TRUE);
+ yDstLast = yDst + yEnd - yStart;
+ LengthCheck (yDstLast, xEnd, pDst);
+ strcpy ( pLog(srcbuf,xEnd,TRUE), pDst); /* AAAAeeeeee */
+ PutLine (yDstLast, srcbuf, pFileDst);
+
+ /*
+ * Form first line of destination stream. Copy last part of first source
+ * line onto last part of dest line
+ */
+ if (pFileSrc != NULL) {
+ fInsSpace (xStart, yStart, 0, pFileSrc, srcbuf);/* CCCCCDDDDD*/
+ LengthCheck (yDst, xDst, srcbuf + xStart);
+ strcpy (pDst, pLog(srcbuf,xStart,TRUE)); /* dddddDDDDD*/
+ } else {
+ *pDst = 0;
+ }
+ PutLine (yDst, dstbuf, pFileDst);
+
+ /*
+ * To update marks, we first adjust any marks at yDst, then add new
+ * marks from the src.
+ */
+ MarkCopyBox (pFileDst, pFileDst, xDst, yDst, sizeof(linebuf), yDst, xEnd-1, yDstLast);
+ MarkCopyBox (pFileSrc, pFileDst, 0, yEnd, xEnd, yEnd, 0, yDstLast);
+ MarkCopyBox (pFileSrc, pFileDst, xStart, yStart, sizeof(linebuf), yStart, xDst, yDst);
+}
diff --git a/private/utils/mep/src/record.c b/private/utils/mep/src/record.c
new file mode 100644
index 000000000..4a1f7cd23
--- /dev/null
+++ b/private/utils/mep/src/record.c
@@ -0,0 +1,509 @@
+/*** RECORD.C - Handle function-by-function recording
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+
+#include "mep.h"
+#include "cmds.h"
+
+
+/* Use the pFile MODE1 flag for <record> quote mode */
+#define INQUOTES MODE1
+
+
+static PFILE pFileRecord;
+static char szRecordName[] = "<record>";
+static PCMD pcmdRecord = NULL;
+
+
+
+/*** record - <record> edit command
+*
+* Purpose:
+*
+* Toggles recording state. When turning on, the file <record> is erased
+* (unless we are appending), the string "macroname:= " is inserted into
+* the file and quote mode is turned off. When turning off, quote marks
+* are appended to the macro (if needed) and the macro is assigned.
+*
+* <record> - Starts/stops recording using the current macro
+* name.
+* <arg> - Start/stops recording using the default macro
+* name.
+* <arg> textarg - Starts recording a macro named 'textarg'.
+* <meta> - Like <record>, but commands are not executed.
+* <arg> <arg> - Like <record>, but append to current recording.
+* <arg> <arg> textarg - Start appending to macro named 'textarg'.
+*
+* If recording is on, only <record> will work.
+*
+* Input:
+*
+* Output:
+*
+* Returns
+*
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+flagType
+record (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ )
+{
+ LINE line;
+ char *pch;
+ char *szDefaultName = "recordvalue";
+ char *lpch = NULL;
+ flagType fAppend = FALSE;
+ flagType fNameGiven = FALSE;
+
+ // Check for the <record> file. If we haven't done a <record>
+ // yet, see if the user has created it. If not, create it.
+ // If this is the first time through, make sure it gets set to
+ // READONLY.
+ //
+ if (pFileRecord == NULL) {
+ if ((pFileRecord = FileNameToHandle(szRecordName,szRecordName)) == NULL) {
+ pFileRecord = AddFile (szRecordName);
+ FileRead (szRecordName, pFileRecord, FALSE);
+ }
+ SETFLAG (FLAGS(pFileRecord), REAL | FAKE | DOSFILE);
+ }
+
+ if (fMacroRecord) {
+ // We need to turn off. Let's check for an open quote at the end
+ // of the recording and close it. Then we can DoAssign the whole
+ // thing and we're done.
+ //
+ if (pArg->argType == NOARG) {
+ if (TESTFLAG(FLAGS(pFileRecord), INQUOTES)) {
+ GetLine (pFileRecord->cLines-1, buf, pFileRecord);
+ strcat (buf, "\"");
+ PutLine (pFileRecord->cLines-1, buf, pFileRecord);
+ RSETFLAG (FLAGS(pFileRecord), INQUOTES);
+ }
+ fMacroRecord = FALSE;
+
+ if (fMetaRecord) {
+ domessage (NULL);
+ fMetaRecord = FALSE;
+ }
+
+ // This may look like we're supporting multiple macro
+ // definitions in the record file, but it is really a
+ // cheap way to get GetTagLine to free up the heap space
+ // it uses.
+ //
+ pch = NULL;
+ line = 0;
+ while ((pch = GetTagLine (&line, pch, pFileRecord))) {
+ DoAssign (pch);
+ }
+ } else {
+ ;
+ }
+ } else {
+ // We are turning recording on. First, decide on the name
+ // of the macro to record to, and whether we are appending
+ // or starting over.
+ //
+ switch (pArg->argType) {
+
+ case NOARG:
+ lpch = pcmdRecord ? pcmdRecord->name : (char *)szDefaultName;
+ break;
+
+ case TEXTARG:
+ lpch = pArg->arg.textarg.pText;
+ fNameGiven = TRUE;
+
+ case NULLARG:
+ fAppend = (flagType)(pArg->arg.textarg.cArg > 1);
+ break;
+ }
+
+ assert (lpch);
+ strcpy ((char far*)buf, lpch);
+
+ while ((pcmdRecord = NameToFunc (buf)) == NULL) {
+ if (!SetMacro (buf, RGCHEMPTY)) {
+ return FALSE;
+ }
+ }
+
+ // If we are not appending, we delete the file, insert a
+ // new name and possibly a current value.
+ //
+ if (!fAppend || fNameGiven) {
+ DelFile (pFileRecord, FALSE);
+ strcat (buf, ":=");
+ PutLine (0L, buf, pFileRecord);
+ if (fAppend) {
+ AppendMacroToRecord (pcmdRecord);
+ }
+ }
+
+
+ RSETFLAG (FLAGS(pFileRecord), INQUOTES);
+ fMacroRecord = TRUE;
+
+ if (fMetaRecord = fMeta) {
+ strcpy (buf, "<record>");
+ FuncToKey (CMD_record, buf);
+ domessage ("No-Execute Record Mode - Press %s to resume normal editing", buf);
+ }
+ }
+
+ SETFLAG (fDisplay, RSTATUS);
+ return fMacroRecord;
+
+ argData;
+}
+
+
+
+
+/*** tell - Editor command - Tells us the names and values of things
+*
+* Purpose:
+*
+* This allows the user to easily disover the name of a key, the name
+* of the function attached to a given key or the value of a macro.
+*
+* <tell> Prompts for a keystroke, then displays the key's
+* name and the function assigned to it in this
+* format: "function:KeyName"
+* <arg><tell> Like <tell>, but if the key has a macro attached,
+* displays "MacroName:= Macro Value"
+* <arg> textarg <tell> Like <arg><tell>, but gets the macro name from
+* the textarg instead of a keystroke.
+* <meta> All of the above, except the output is inserted into
+* the current file.
+*
+* Insertion takes place at the cursor. The insertion will be
+* atomic; the user will see only the final product.
+*
+* Input:
+*
+* The usual.
+*
+* Output:
+*
+* Returns FALSE if the function is <unassigned>, TRUE otherwise.
+*
+*************************************************************************/
+flagType
+ztell (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ )
+{
+ buffer buf;
+ buffer buf2;
+ PCMD pCmd;
+ char *pch;
+ flagType fWrap = fWordWrap;
+ flagType fInQuotes = FALSE;
+ flagType fMacro = FALSE;
+
+ switch (pArg->argType) {
+
+ case NOARG:
+ case NULLARG:
+ dispmsg (MSG_TELLPROMPT);
+ pCmd = ReadCmdAndKey (buf2);
+ if ((PVOID)pArg->argType == (PVOID)NULLARG &&
+ (PVOID)pCmd->func == (PVOID)macro) {
+ goto domacro;
+ }
+notmacro:
+ sprintf (buf, "%Fs:%s",pCmd->name, buf2);
+ break;
+
+ case TEXTARG:
+ strcpy (buf2, pArg->arg.textarg.pText);
+ if (NULL == (pCmd = NameToFunc (buf2))) {
+ disperr (MSGERR_ZTELL, buf2);
+ return FALSE;
+ }
+
+ if ((PVOID)pCmd->func == (PVOID)macro) {
+domacro:
+ fMacro = TRUE;
+ sprintf (buf, "%Fs:=", pCmd->name);
+ } else {
+ goto notmacro;
+ }
+ }
+
+ // Now buf is filled with the string to display.
+ // if fMacro is TRUE, we must also append the
+ // value of pCmd->arg
+ //
+ if (fMeta) {
+ fWordWrap = FALSE;
+ pch = buf - 1;
+doitagain:
+ while (*++pch) {
+ if (*pch == ' ' && XCUR(pInsCur) >= xMargin) {
+ edit (' ');
+ edit (' ');
+ edit ('\\');
+ docursor (softcr(), YCUR(pInsCur) + 1);
+ } else {
+ edit (*pch);
+ }
+ }
+ if (fMacro) {
+ pch = (char *)pCmd->arg - 1;
+ fMacro = FALSE;
+ goto doitagain;
+ }
+ fWordWrap = fWrap;
+ } else {
+ if (fMacro ) {
+ strncat (buf, (char *)pCmd->arg, XSIZE);
+ }
+ domessage (buf);
+ }
+ return (flagType)((PVOID)pCmd->func != (PVOID)unassigned);
+
+ argData;
+}
+
+
+
+/*** RecordCmd - Append a command name to the <record> file.
+*
+* Purpose:
+*
+* Whenever a command is about to be performed, this function should
+* be called.
+*
+* Input:
+* pCmd -> The command to record
+*
+* Output: None
+*
+* Notes:
+*
+* The basic operation is to append pCmd->name to the file. This
+* means checking for:
+*
+* o Line overflow. If appending to the line would overflow the
+* maximum line length (BUFLEN - 3), we must append a " \" and
+* write to the next line.
+*
+* o Graphic characters. If the function is <graphic>, then we add
+* the ASCII character, not "graphic". If we are outside quotes, we
+* must add quotes first and flag quote mode. To flag quote mode
+* we use the special 'MODE1' flag in pFile.
+*
+* o <unassigned>. This is considered user clumsiness and is not
+* recorded.
+*
+* o All other cases. If the previous function was <graphic> and the
+* current function is not, we must close quotes first.
+*
+*************************************************************************/
+void
+RecordCmd (
+ PCMD pCmd
+ )
+{
+ buffer szCmdName;
+ buffer buf;
+ REGISTER char * pchEndLine;
+ REGISTER char * pchNew;
+ char c;
+ LINE line;
+ int entab;
+
+ if (!fMacroRecord) { /* If we're not on, do nothing */
+ return;
+ }
+
+ assert (pFileRecord);
+
+ if ((PVOID)pCmd->func == (PVOID)unassigned ||
+ (PVOID)pCmd->func == (PVOID)record ||
+ (!fMetaRecord && (PVOID)pCmd->func == (PVOID)macro)) {
+ return;
+ }
+
+ // First, we get the current (i.e. last) line to play with.
+ // Let's also set a pointer to the end of it so we don't have
+ // to keep strcat'ing and strlen'ing it.
+ //
+ GetLine ((line = pFileRecord->cLines-1), buf, pFileRecord);
+ pchEndLine = strend (buf);
+ pchNew = szCmdName;
+
+
+ // Now we generate the new text. Since we may be moving into and
+ // out of quotes, we have four possible transitions from the
+ // previous entry:
+ //
+ // last cmd type this cmd type resulting pattern
+ //
+ // graphic graphic >c<
+ // non-graphic graphic > "c<
+ // graphic non-graphic >" cmdname<
+ // non-graphic non-graphic > cmdname<
+ //
+ if ((PVOID)pCmd->func == (PVOID)graphic) {
+ if (!TESTFLAG(FLAGS(pFileRecord), INQUOTES)) {
+ *pchEndLine++ = ' ';
+ *pchEndLine++ = '"';
+ SETFLAG (FLAGS(pFileRecord), INQUOTES);
+ }
+ c = (char)pCmd->arg;
+ if (c == '"' || c == '\\') {
+ *pchNew++ = '\\';
+ }
+
+ *pchNew++ = c;
+ *pchNew = '\0';
+ } else {
+ if (TESTFLAG (FLAGS(pFileRecord), INQUOTES)) {
+ *pchEndLine++ = '"';
+ RSETFLAG (FLAGS(pFileRecord), INQUOTES);
+ }
+ *pchEndLine++ = ' ';
+ strcpy ((char *)pchNew, pCmd->name);
+ }
+
+
+ // Finally, let's add the new text to the file. We'll add
+ // a continuation character if necessary.
+ //
+ entab = EnTab;
+ EnTab = 0;
+ if ((COL) ((pchEndLine - buf) + strlen (szCmdName)) > xMargin) {
+ strcpy (pchEndLine, " \\");
+ PutLine (line+1, szCmdName, pFileRecord);
+ UpdateIf (pFileRecord, line+1, FALSE);
+ } else {
+ strcpy (pchEndLine, szCmdName);
+ UpdateIf (pFileRecord, line, FALSE);
+ }
+
+ PutLine (line, buf, pFileRecord);
+ EnTab = entab;
+
+ return ;
+}
+
+
+
+
+
+/*** RecordString - Record an entire string
+*
+* Purpose:
+*
+* To record a string that woule be missed by RecordCmd.
+*
+* Input:
+* psz - String to record.
+*
+* Output: None
+*
+* Notes:
+*
+* Currently implemented by callinto RecordCmd. Should be implemented
+* by having RecordCmd and RecordString call common "write to <record>"
+* code.
+*
+*************************************************************************/
+void
+RecordString (
+ char * psz
+ )
+{
+
+ if (!fMacroRecord) { /* If we're not on, do nothing */
+ return;
+ }
+
+ while (*psz) {
+ (CMD_graphic)->arg = *psz++;
+ RecordCmd (CMD_graphic);
+ }
+}
+
+
+
+
+/*** AppendMacroToRecord - Append the current value of a macro to <record>
+*
+* Purpose:
+*
+* Input:
+*
+* Output:
+*
+* Returns
+*
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+void
+AppendMacroToRecord (
+ PCMD pCmdMac
+ )
+{
+ flagType fDone;
+ char *pchValue, *pch;
+ LINE line;
+
+
+ // First, get the raw macro value
+ //
+ pchValue = (char *)pCmdMac->arg;
+
+ // Now, throw the vlaue into the file one line
+ // at a time. Start at the end of the file
+ //
+ line = pFileRecord->cLines - 1;
+
+ do {
+ GetLine (line, buf, pFileRecord);
+
+ for (pch = pchValue + min ((ULONG)(xMargin + 5 - strlen(buf)), (ULONG)strlen (pchValue));
+ pch > pchValue && *pch && *pch != ' ' && *pch != '\t';
+ pch--) {
+ ;
+ }
+
+ // Now pch points at either the last space, the end
+ // of the value or the beginning. If it points to the
+ // beginning or end, we copy all of pchValue. Otherwise,
+ // we copy just up to pch
+ //
+ if (!*pch || pch == pchValue) {
+ strcat (buf, pchValue);
+ fDone = TRUE;
+ } else {
+ strncat (buf, pchValue, pch - pchValue);
+ strcat (buf, " \\");
+ pchValue = pch + 1;
+ }
+
+ PutLine (line++, buf, pFileRecord);
+ } while (!fDone);
+}
diff --git a/private/utils/mep/src/replace.c b/private/utils/mep/src/replace.c
new file mode 100644
index 000000000..eeb7f7a19
--- /dev/null
+++ b/private/utils/mep/src/replace.c
@@ -0,0 +1,569 @@
+/*** replace.c - string replacement functions
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Repalces funnel through these routines as follows:
+*
+* zreplace mreplace qreplace
+* \ | /
+* \ | /
+* \______ | ______/
+* \|/
+* v
+* doreplace
+* |
+* (fScan)
+* |
+* fDoReplace
+* / \
+* / \
+* patRpl simpleRpl (if a change is made)
+* \ /
+* \ /
+* ReplaceEdit
+*
+* Revision History:
+* 26-Nov-1991 mz Strip off near/far
+*************************************************************************/
+#define NOVM
+#include "mep.h"
+
+
+static flagType fQrpl = FALSE; /* TRUE => prompt for replacement */
+static struct patType *patBuf = NULL; /* compiled pattern */
+static int srchlen; /* length of textual search */
+static unsigned MaxREStack; /* Elements in RE stack */
+static RE_OPCODE ** REStack; /* Stack for REMatch */
+
+
+
+/*** mreplace - multiple file search and replace
+*
+* Perform a search and replace across multiple files. Acts like qreplace, in
+* that the first instance the user is always asked. he may then say "replace
+* all".
+*
+* Input:
+* Standard editting function.
+*
+* Output:
+* Returns TRUE on successfull replacement.
+*
+*************************************************************************/
+flagType
+mreplace (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ )
+{
+ return doreplace (TRUE, pArg, fMeta, TRUE);
+
+ argData;
+}
+
+
+
+/*** zreplace & qreplace - perform search/replace
+*
+* Editting functions which implement search & replace. qreplace prompts,
+* zreplace does not.
+*
+* Input:
+* Standard editting function parameters.
+*
+* Output:
+* Returns
+*
+*************************************************************************/
+flagType
+zreplace (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ )
+{
+ return doreplace (FALSE, pArg, fMeta, FALSE);
+
+ argData;
+}
+
+
+
+
+
+flagType
+qreplace (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ )
+{
+ return doreplace (TRUE, pArg, fMeta, FALSE);
+
+ argData;
+}
+
+
+
+
+/*** doreplace - perform search-replace
+*
+* Performs the actual search and replace argument verification, set up and
+* high level control.
+*
+* Input:
+* fQuery = TRUE if a query replace
+* pArg = pArg of parent function
+* fMeta = fMeta of parent function
+* fFiles = TRUE is multiple file search and replace.
+*
+* Output:
+* Returns .....
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+flagType
+doreplace (
+ flagType fQuery,
+ ARG * pArg,
+ flagType fMeta,
+ flagType fFiles
+ )
+{
+ buffer bufFn; /* filename buffer */
+ fl flStart;
+ char *p;
+ PCMD pCmd;
+ PFILE pFileSave; /* file to save as top of heap */
+
+ p = "Query Search string: ";
+ if (!fQuery) {
+ p += 6;
+ }
+
+ fQrpl = fQuery;
+ fSrchCasePrev = fMeta ? (flagType)!fSrchCaseSwit : fSrchCaseSwit;
+ Display ();
+ cRepl = 0;
+
+ /*
+ * If not menu-driven, ask the user for a search string. If none is entered,
+ * we're done.
+ */
+ if ((pCmd = getstring (srcbuf, p, NULL, GS_NEWLINE | GS_INITIAL)) == NULL || (PVOID)pCmd->func == (PVOID)cancel) {
+ return FALSE;
+ }
+
+ if (srcbuf[0] == '\0') {
+ return FALSE;
+ }
+
+ /*
+ * If RE search to take place, the compile the expression.
+ */
+ if (pArg->arg.nullarg.cArg == 2) {
+ if (patBuf != NULL) {
+ FREE ((char *) patBuf);
+ patBuf = NULL;
+ }
+ patBuf = RECompile (srcbuf, fSrchCaseSwit, (flagType)!fUnixRE);
+ if (patBuf == NULL) {
+ printerror ((RESize == -1) ?
+ "Invalid pattern" :
+ "Not enough memory for pattern");
+ return FALSE;
+ }
+ fRplRePrev = TRUE;
+ } else {
+ fRplRePrev = FALSE;
+ }
+
+ /*
+ * If not menu driven, ask the user for a replacement string. Confirm the
+ * entry of a null string. Error check the replacement if an RE search.
+ */
+ if ((pCmd = getstring (rplbuf, "Replace string: ", NULL, GS_NEWLINE | GS_INITIAL)) == NULL ||
+ (PVOID)pCmd->func == (PVOID)cancel) {
+ return FALSE;
+ }
+
+ if (rplbuf[0] == 0) {
+ if (!confirm ("Empty replacement string, confirm: ", NULL)) {
+ return FALSE;
+ }
+ }
+
+ if (fRplRePrev && !RETranslate (patBuf, rplbuf, scanreal)) {
+ printerror ("Invalid replacement pattern");
+ return FALSE;
+ }
+
+ srchlen = strlen (srcbuf);
+
+ switch (pArg->argType) {
+
+ case NOARG:
+ case NULLARG:
+ setAllScan (TRUE);
+ break;
+
+ case LINEARG:
+ rnScan.flFirst.col = 0;
+ rnScan.flLast.col = sizeof(linebuf)-1;
+ rnScan.flFirst.lin = pArg->arg.linearg.yStart;
+ rnScan.flLast.lin = pArg->arg.linearg.yEnd;
+ break;
+
+ case BOXARG:
+ rnScan.flFirst.col = pArg->arg.boxarg.xLeft;
+ rnScan.flLast.col = pArg->arg.boxarg.xRight;
+ rnScan.flFirst.lin = pArg->arg.boxarg.yTop;
+ rnScan.flLast.lin = pArg->arg.boxarg.yBottom;
+ break;
+
+ case STREAMARG:
+ if (pArg->arg.streamarg.yStart == pArg->arg.streamarg.yEnd) {
+ rnScan.flFirst.col = pArg->arg.streamarg.xStart;
+ rnScan.flLast.col = pArg->arg.streamarg.xEnd;
+ rnScan.flFirst.lin = pArg->arg.streamarg.yStart;
+ rnScan.flLast.lin = pArg->arg.streamarg.yEnd;
+ } else {
+ rnScan.flFirst.col = 0; /* Do all but last line first */
+ rnScan.flLast.col = sizeof(linebuf)-1;
+ rnScan.flFirst.lin = pArg->arg.streamarg.yStart;
+ rnScan.flLast.lin = pArg->arg.streamarg.yEnd - 1;
+ flStart.col = pArg->arg.streamarg.xStart - 1;
+ flStart.lin = rnScan.flFirst.lin;
+ fScan (flStart, fDoReplace , TRUE, fSrchWrapSwit);
+
+ rnScan.flLast.col = pArg->arg.streamarg.xEnd;
+ rnScan.flFirst.lin = ++rnScan.flLast.lin;
+ }
+ }
+
+ flStart.col = rnScan.flFirst.col-1;
+ flStart.lin = rnScan.flFirst.lin;
+ if (fRplRePrev) {
+ MaxREStack = 512;
+ REStack = (RE_OPCODE **)ZEROMALLOC (MaxREStack * sizeof(*REStack));
+ }
+
+ if (fFiles) {
+ /*
+ * Get the list handle, and initialize to start at the head of the list.
+ * Attempt to read each file.
+ */
+ if (pCmd = GetListHandle ("mgreplist", TRUE)) {
+ pFileSave = pFileHead;
+ p = ScanList (pCmd, TRUE);
+ while (p) {
+ CanonFilename (p, bufFn);
+ forfile (bufFn, A_ALL, mrepl1file, &p);
+ p = ScanList (NULL, TRUE);
+ if (fCtrlc) {
+ return FALSE;
+ }
+ }
+ pFileToTop (pFileSave);
+ dispmsg (0);
+ }
+ } else {
+ fScan (flStart, fDoReplace , TRUE, fSrchWrapSwit);
+ }
+
+ if (fRplRePrev) {
+ FREE (REStack);
+ }
+ domessage ("%d occurrences replaced", cRepl);
+ return (flagType)(cRepl != 0);
+}
+
+
+
+
+/*** mrepl1file - search/replace the contents of 1 file.
+*
+* Searches through one file for stuff.
+*
+* Input:
+*
+* Output:
+* Returns .....
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+void
+mrepl1file (
+ char *szGrepFile,
+ struct findType *pfbuf,
+ void *dummy
+ )
+{
+ flagType fDiscard; /* discard the file read? */
+ fl flGrep; /* ptr to current grep loc */
+ int cReplBefore; /* number of matches before */
+ PFILE pFileGrep; /* file to be grepped */
+
+ assert (szGrepFile);
+ assert (_pinschk(pInsCur));
+
+ if (fCtrlc) {
+ return;
+ }
+
+ /*
+ * If we can get a handle to the file, then it's alread in the list, and we
+ * should not discard it when done. If it is not in the list, we read it in,
+ * but we'll discard it, unless something is found there.
+ */
+ if (!(pFileGrep = FileNameToHandle (szGrepFile, szGrepFile))) {
+ pFileGrep = AddFile (szGrepFile);
+ SETFLAG (FLAGS (pFileGrep), REFRESH);
+ fDiscard = TRUE;
+ } else {
+ fDiscard = FALSE;
+ }
+
+ assert (_pinschk(pInsCur));
+
+ /*
+ * If the file needs to be physically read, do so.
+ */
+ if ((FLAGS (pFileGrep) & (REFRESH | REAL)) != REAL) {
+ FileRead (pFileGrep->pName, pFileGrep, FALSE);
+ RSETFLAG (FLAGS(pFileGrep), REFRESH);
+ }
+
+ dispmsg (MSG_SCANFILE, szGrepFile);
+ pFileToTop (pFileGrep);
+
+ /*
+ * run through the file, searching and replacing as we go.
+ */
+ cReplBefore = cRepl;
+ setAllScan (FALSE);
+ flGrep.col = rnScan.flFirst.col-1;
+ flGrep.lin = rnScan.flFirst.lin;
+ fScan (flGrep, fDoReplace, TRUE, FALSE);
+ /*
+ * If the search was not successfull, discard the file, if needed, and move
+ * to the next.
+ */
+ if (cReplBefore == cRepl) {
+ if (fDiscard) {
+ RemoveFile (pFileGrep);
+ }
+ } else {
+ AutoSaveFile (pFileGrep);
+ }
+
+ assert (_pinschk(pInsCur));
+
+ pfbuf; dummy;
+
+}
+
+
+
+
+/*** fDoReplace - called by fScan as file is scanned.
+*
+* Purpose:
+*
+* Input:
+*
+* Output:
+* Returns .....
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+flagType
+fDoReplace (
+ void
+ )
+{
+ int c;
+ char *p = pLog (scanreal, flScan.col, TRUE);
+
+ if (fRplRePrev) {
+ int rem;
+ flagType fAgain = TRUE;
+
+ do {
+ switch (rem = REMatch (patBuf, scanreal, p, REStack, MaxREStack, TRUE)) {
+ case REM_NOMATCH:
+ flScan.col = scanlen;
+ return FALSE;
+
+ case REM_STKOVR:
+ MaxREStack += 128;
+ REStack = (RE_OPCODE **)ZEROREALLOC ((char *)REStack, MaxREStack * sizeof(*REStack));
+ break;
+
+ default:
+ printerror ("Internal Error: RE error %d, line %ld", rem, flScan.lin);
+
+ case REM_MATCH:
+ fAgain = FALSE;
+ break;
+ }
+ } while (fAgain);
+
+ c = colPhys (scanreal, REStart (patBuf));
+ srchlen = RELength (patBuf, 0);
+ if (c + srchlen - 1 > scanlen) {
+ return FALSE;
+ }
+ flScan.col = c;
+ } else {
+ if ( (*(fSrchCasePrev ? strncmp : _strnicmp)) (srcbuf, p, srchlen)) {
+ return FALSE;
+ }
+ if (flScan.col + srchlen - 1 > scanlen) {
+ return FALSE;
+ }
+ }
+
+ if (fQrpl) {
+ ClearHiLite (pFileHead, TRUE);
+ Display();
+ cursorfl (flScan);
+ HighLight (flScan.col, flScan.lin, flScan.col+srchlen-1, flScan.lin);
+ Display ();
+ c = askuser ('n', 'a', "Replace this occurrence? (Yes/No/All/Quit): ",
+ NULL);
+ ClearHiLite (pFileHead, TRUE);
+ redraw (pFileHead, flScan.lin, flScan.lin);
+ RSETFLAG (fDisplay, RHIGH);
+
+ switch (c) {
+
+ case -1:
+ case 'q':
+ fCtrlc = TRUE;
+ return TRUE;
+
+ case 'n':
+ return FALSE;
+
+ case 'a':
+ dispmsg(0); /* clear dialog line */
+ fQrpl = FALSE;
+ break;
+ }
+ }
+
+ if (fRplRePrev) {
+ patRpl ();
+ } else {
+ simpleRpl (p);
+ }
+ return FALSE;
+}
+
+
+
+
+
+/*** simpleRpl & patRpl - perform textual replacement
+*
+* Purpose:
+*
+* Input:
+*
+* Output:
+* Returns .....
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+void
+simpleRpl (
+ char *p
+ )
+{
+ ReplaceEdit (p, rplbuf);
+}
+
+
+
+
+
+void
+patRpl (
+ void
+ )
+{
+ buffer txt;
+
+ RETranslate (patBuf, rplbuf, txt);
+ ReplaceEdit (REStart (patBuf), txt);
+}
+
+
+
+
+
+/*** ReplaceEdit - perform replacement in a line of text
+*
+* Purpose:
+*
+* Input:
+* p = pointer to beginning of match within scanreal
+* rpl = text of replacement
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void
+ReplaceEdit (
+ char *p,
+ char *rpl
+ )
+{
+ int c; /* length of replacement string */
+
+ /* if the len of line - len of search + len of replacement string < BUFLEN
+ * then we can make the replacement. Otherwise we flag an error and
+ * advance to the next line
+ */
+ c = strlen (rpl);
+ if (cbLog (scanreal) + c - srchlen < sizeof(linebuf)) {
+ /* open up a space in the buffer at the spot where the string was
+ * found. Move the characters starting at the END of the match to
+ * the point after where the END of the replacement is.
+ */
+ memmove ((char*) &p[c], (char *) &p[srchlen], sizeof(linebuf) - flScan.col - c);
+ memmove ((char *) p, (char *) rpl, c);
+ PutLine (flScan.lin, scanreal, pFileHead);
+
+ /* if search length != 0 or replace length != 0, skip over replacement */
+ if (srchlen != 0 || c != 0) {
+ flScan.col += c - 1;
+ }
+
+ //
+ // Adjust scan len to account for the fact that the end of the region being
+ // scanned may have moved as a result of the replacement. Adjust by the
+ // replacement difference, and bound by 0 and the length of the line.
+ //
+ scanlen = max (0, min (scanlen + c - srchlen, cbLog(scanreal)));
+ cRepl++;
+ } else {
+ printerror ("line %ld too long; replacement skipped", flScan.lin+1);
+ flScan.col = scanlen;
+ }
+}
diff --git a/private/utils/mep/src/search.c b/private/utils/mep/src/search.c
new file mode 100644
index 000000000..a751a1eb9
--- /dev/null
+++ b/private/utils/mep/src/search.c
@@ -0,0 +1,1126 @@
+/*** search.c - search routines for editor
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Searches funnel through these routines as follows:
+*
+* psearch msearch searchall mgrep
+* \ | / /
+* \ | / /
+* \_______|_______/ /
+* | /
+* v /
+* dosearch /
+* /___\_____________/
+* / \
+* / \
+* search REsearch REsearchS <=== all exported to extensions
+*
+* Global variables, and their meanings:
+*
+* User set-able switches:
+* fUnixRE unixre: switch. TRUE => Use UNIX Regular Expressions
+* fSrchCaseSwit case: switch. TRUE => case is significant
+* fSrchWrapSwit wrap: switch. TRUE => searches wrap
+*
+* Previous Search Parameters:
+* fSrchAllPrev TRUE => searched for all occurrances
+* fSrchCasePrev TRUE => case was significant
+* fSrchDirPrev TRUE => searched forward
+* fSrchRePrev TRUE => used a regular expressions
+* fSrchWrapPrev TRUE => wrapped around
+*
+* srchbuf search string
+*
+* Revision History:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+
+#include <string.h>
+#include <stdarg.h>
+#include "mep.h"
+
+
+static int cAll; /* count of ocurrances for all */
+static int cGrepped; /* count of ocurrances for mgrep*/
+static struct patType *patBuf = NULL; /* compiled pattern */
+
+
+/***************************************************************************\
+
+MEMBER: lsearch
+
+SYNOPSIS: strstr based on supplied lengths rather than strlen()
+
+ALGORITHM:
+
+ARGUMENTS:
+
+RETURNS:
+
+NOTES: Supplied strings may not be zero terminated or may have embedded
+ NULs
+ This is a brute force algorithm which should be updated to
+ something reasonable if performance is a problem
+
+HISTORY: 14-Aug-90 davegi
+ Created
+
+KEYWORDS:
+
+SEEALSO:
+
+\***************************************************************************/
+char*
+lsearch (
+ char* pchSrc,
+ ULONG cbSrc,
+ char* pchSub,
+ ULONG cbSub
+ )
+{
+
+ REGISTER ULONG i;
+ REGISTER ULONG j;
+
+ assert( pchSrc );
+ assert( pchSub );
+
+ // If the sub-string is longer than the source string or,
+ // cbSrc > strlen( pchSrc) (hack for backwards search), return NULL
+
+ if(( cbSub > cbSrc ) || ( cbSrc > strlen( pchSrc ) + 1)) {
+ return NULL;
+ }
+
+ // Short Circuit...
+ // If first character in pchSub does not exist in pchSrc
+
+ if( ! memchr( pchSrc, *pchSub, cbSrc )) {
+ return NULL;
+ }
+
+ i = j = 0;
+ do {
+ if( pchSrc[ i ] == pchSub[ j ] ) {
+ i++;
+ j++;
+ } else {
+ i = i - j + 1;
+ j = 0;
+ }
+ } while(( j < cbSub ) && ( i < cbSrc ));
+ return ( j >= cbSub ) ? &( pchSrc[ i - cbSub ]) : NULL;
+}
+
+
+
+static char szNullStr[] = "";
+
+
+/*** mgrep - multiple file search
+*
+* Using the internal editor search code, and optimizing for those files
+* already in memory, search for a string or regular expression.
+*
+* Searches the file list specified by the greplist macro.
+*
+* no arg: search for previous search string
+* Single arg: search for string.
+* Double arg: search for regular expression.
+* meta: toggle case from current switch setting
+*
+* Files to be searched which are already in the file history are simply
+* searched. Files which are NOT in the file history, are read in, and if
+* no occurance of the search string is found, they are then discarded as
+* well.
+*
+* Input:
+* Standard editting function
+*
+* Globals:
+* - grep file list
+* fSrchCaseSwit - users 'case' switch
+* fSrchRePrev - previous RE search flag
+* fUnixRE - users 'unixre' switch
+* pasBuf - compiled RE pattern
+* srchbuf - last searched for string.
+*
+* Output:
+* Returns TRUE on found.
+*
+*************************************************************************/
+flagType
+mgrep (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ )
+{
+ int l; /* length of matched string */
+ PCMD pcmdGrepList; /* pointer to grep list */
+ char *szGrepFile; /* pointer to current grep file */
+
+ assert (pArg);
+ fSrchCasePrev = fSrchCaseSwit; /* assume case switch to begin */
+
+ switch (pArg->argType) {
+
+ /*
+ * TEXTARG: use text as search string. If RE search, also compile the regular
+ * expression into patBuf. (Fall into NOARG code).
+ */
+ case TEXTARG:
+ strcpy ((char *) buf, pArg->arg.textarg.pText);
+ srchbuf[0] = 0;
+ if (pArg->arg.textarg.cArg == 2) {
+ if (patBuf != NULL) {
+ FREE((char *) patBuf);
+ }
+ patBuf = RECompile (buf, fSrchCaseSwit, (flagType)!fUnixRE);
+ if (patBuf == NULL) {
+ printerror ((RESize == -1) ? "Invalid pattern" : "Not enough memory for pattern");
+ return FALSE;
+ }
+ fSrchRePrev = TRUE;
+ } else {
+ fSrchRePrev = FALSE;
+ }
+ strcpy (srchbuf, buf);
+
+
+ /*
+ * NOARG: use previous search string & parameters
+ */
+ case NOARG:
+ if (srchbuf[0] == 0) {
+ printerror ("No search string specified");
+ return FALSE;
+ }
+ break;
+ }
+
+ /*
+ * Ee must ensure that no background compile is underway. Then get a pfile
+ * there.
+ */
+ if (fBusy(pBTDComp)) {
+ printerror ("Cannot mgrep to <compile> during background compile");
+ return FALSE;
+ }
+
+ if ((PFILECOMP = FileNameToHandle (rgchComp, rgchComp)) == NULL) {
+ PFILECOMP = AddFile ((char *)rgchComp);
+ FileRead ((char *)rgchComp, PFILECOMP, FALSE);
+ SETFLAG (FLAGS (PFILECOMP), READONLY);
+ }
+
+ /*
+ * Under OS/2, if it is clear that we will destroy the log file contents
+ * we ask the user and empty the file if he says so.
+ */
+ if (PFILECOMP->cLines
+ && (confirm ("Delete current contents of compile log ? ", NULL))
+ ) {
+ DelFile (PFILECOMP, FALSE);
+ }
+
+
+ BuildFence ("mgrep", rgchEmpty, buf);
+ AppFile (buf, PFILECOMP);
+ /*
+ * When not in a macro, indicate on the dialog line what it is we are
+ * searching for
+ */
+ if (!mtest ()) {
+ l = sout (0, YSIZE, "mgrep for '", infColor);
+ l = sout (l, YSIZE, srchbuf, fgColor);
+ soutb (l, YSIZE, "'", infColor);
+ }
+
+ if (fMeta) {
+ fSrchCasePrev = (flagType)!fSrchCasePrev;
+ }
+ cGrepped = 0;
+
+ /*
+ * Get the list handle, and initialize to start at the head of the list.
+ * Attempt to process each list element. If starts with "$", use forsemi to
+ * process each file or pattern in each directory listed in the environment
+ * variable, else process the filename directly.
+ */
+ if (pcmdGrepList = GetListHandle ("mgreplist", TRUE)) {
+ szGrepFile = ScanList (pcmdGrepList, TRUE);
+ while (szGrepFile) {
+ char *pathstr;
+ char *tmp = NULL;
+
+ if (*szGrepFile == '$') {
+ char *p;
+
+ if (*(p=strbscan (szGrepFile, ":"))) {
+ *p = 0;
+
+ if ((tmp = getenvOem (szGrepFile+1)) == NULL) {
+ pathstr = szNullStr;
+ } else {
+ pathstr = tmp;
+ }
+
+ *p++ = ':';
+ szGrepFile = p;
+ }
+ } else {
+ pathstr = szNullStr;
+ }
+
+ forsemi (pathstr, mgrep1env, szGrepFile);
+
+ if( tmp != NULL ) {
+ free( tmp );
+ }
+
+ szGrepFile = ScanList (NULL, TRUE);
+ if (fCtrlc) {
+ return FALSE;
+ }
+ }
+ }
+ if (cGrepped) {
+ nextmsg (0, &NoArg, FALSE);
+ }
+ domessage ("%d occurrences found",cGrepped);
+ return (flagType)(cGrepped != 0);
+
+ argData;
+}
+
+
+
+
+
+/*** mgrep1env - perform grep on environment variable when found
+*
+* Called when an environment variable is found in the mgrep list to
+* process all the files in that path. Called once per directory entry
+* in the list.
+*
+* Input:
+* pszEnv = pointer to directory name
+* pFileName = pointer to filename
+*
+* Output:
+* Returns nothing.
+*
+*************************************************************************/
+flagType
+mgrep1env (
+ char * pszEnv,
+ va_list pa
+ )
+{
+ char *pszFn = (char *)va_arg( pa, char* );
+ pathbuf bufFn; /* filename buffer */
+
+ if (fCtrlc) {
+ return TRUE;
+ }
+
+ /*
+ * construct full pathname in buffer.
+ */
+ {
+ pathbuf bufBuild;
+
+ strcpy (bufBuild, pszEnv);
+ if (*pszEnv && (*(strend(bufBuild)-1) != '\\')) {
+ *(int *) strend (bufBuild) = '\\';
+ }
+ strcat (bufBuild, pszFn);
+ CanonFilename (bufBuild, bufFn);
+ }
+
+ forfile (bufFn, A_ALL, mgrep1file, NULL);
+
+ return FALSE;
+}
+
+
+
+
+/*** mgrep1file - grep the contents of 1 file.
+*
+* Searches through one file for stuff.
+*
+* Input:
+*
+* Output:
+* Returns .....
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+void
+mgrep1file (
+ char *szGrepFile,
+ struct findType *pfbuf,
+ void * dummy
+ )
+{
+
+ flagType fDiscard; /* discard the file read? */
+ fl flGrep; /* ptr to current grep loc */
+ int l; /* length of matched string */
+ PFILE pFileGrep; /* file to be grepped */
+
+ assert (szGrepFile);
+
+ if (fCtrlc) {
+ return;
+ }
+
+ flGrep.lin = 0;
+ flGrep.col = 0;
+
+ /*
+ * If we can get a handle to the file, then it's alread in the list, and we
+ * should not discard it when done. If it is not in the list, we read it in,
+ * but we'll discard it, unless something is found there.
+ */
+ if (!(pFileGrep = FileNameToHandle (szGrepFile, szGrepFile))) {
+ pFileGrep = AddFile (szGrepFile);
+ SETFLAG (FLAGS (pFileGrep), REFRESH);
+ fDiscard = TRUE;
+ } else {
+ fDiscard = FALSE;
+ }
+
+ /*
+ * If the file needs to be physically read, do so.
+ */
+ if ((FLAGS (pFileGrep) & (REFRESH | REAL)) != REAL) {
+ FileRead (pFileGrep->pName, pFileGrep, FALSE);
+ RSETFLAG (FLAGS(pFileGrep), REFRESH);
+ }
+
+ /*
+ * Use either the normal searcher, or the regular expression searcher, based
+ * on the use of regular expressions.
+ */
+ do {
+ if (fSrchRePrev) {
+ l = REsearch (pFileGrep, /* file to search */
+ TRUE, /* direction: forward */
+ FALSE, /* not a searchall */
+ fSrchCasePrev, /* case */
+ FALSE, /* wrap */
+ patBuf, /* pattern */
+ &flGrep); /* start/end location */
+ } else {
+ l = search (pFileGrep,
+ TRUE, /* direction: forward */
+ FALSE, /* not a searchall */
+ fSrchCasePrev, /* case */
+ FALSE, /* wrap */
+ srchbuf, /* pattern */
+ &flGrep); /* start/end location */
+ }
+
+ if (l >= 0) {
+ /*
+ * if the search was successfull, if adding to <compile>, do so, else
+ * highlight the found search string and exit.
+ */
+ buffer linebuf;
+
+ fDiscard = FALSE;
+ cGrepped++;
+ GetLine (flGrep.lin, linebuf, pFileGrep);
+ zprintf ( PFILECOMP
+ , PFILECOMP->cLines
+ , "%s %ld %d: %s"
+ , pFileGrep->pName
+ , ++flGrep.lin
+ , ++flGrep.col
+ , linebuf);
+ } else {
+ /*
+ * If the search was not successfull, discard the file, if needed, and move
+ * to the next.
+ */
+ if (fDiscard) {
+ RemoveFile (pFileGrep);
+ }
+ if (UpdateIf (PFILECOMP, PFILECOMP->cLines, FALSE)) {
+ Display ();
+ }
+ return;
+ }
+ } while (TRUE);
+
+ pfbuf; dummy;
+}
+
+
+
+
+/*** psearch - plus search function
+*
+* Search the current file forward for a string.
+*
+* Input:
+* Standard Editor Editing Function
+*
+* Output:
+* Returns TRUE on success (at least one string found).
+*
+*************************************************************************/
+flagType
+psearch (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ )
+{
+ return dosearch (TRUE, pArg, fMeta, FALSE);
+
+ argData;
+}
+
+
+
+
+/*** msearch - minus search function
+*
+* Search the current file backward for a string.
+*
+* Input:
+* Standard Editor Editing Function
+*
+* Output:
+* Returns TRUE on success (at least one string found).
+*
+*************************************************************************/
+flagType
+msearch (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ )
+{
+ return dosearch (FALSE, pArg, fMeta, FALSE);
+
+ argData;
+}
+
+
+
+
+/*** searchall
+*
+* Searches the entire current file for a string, and highlights all ocurrances
+*
+* Input:
+* Standard Editor Editing Function
+*
+* Output:
+* Returns TRUE on success (at least one string found).
+*
+*************************************************************************/
+flagType
+searchall (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ )
+{
+ return dosearch (TRUE, pArg, fMeta, TRUE);
+
+ argData;
+}
+
+
+
+
+/*** dosearch - perform search operation
+*
+* Single funnel for all file search operations.
+*
+* NULLARG is converted into TEXTARG
+* LINEARG, STREAMARG, BOXARG are illegal
+*
+* Input:
+* fForard = TRUE => Indicates that search is forward
+* pArg = pointer to user specified args
+* fMeta = TRUE => if meta on
+* fAll = TRUE => highlight all ocurrances
+*
+* Output:
+* Returns TRUE if found
+*
+*************************************************************************/
+flagType
+dosearch (
+ flagType fForward,
+ ARG * pArg,
+ flagType fMeta,
+ flagType fAll
+ )
+{
+ int l; /* length of matched string */
+ fl flCur; /* file loc before/after search */
+ rn rnCur; /* range to be highlighted */
+
+ assert (pArg);
+ fSrchCasePrev = fSrchCaseSwit; /* assume case switch to begin */
+
+ switch (pArg->argType) {
+
+ /*
+ * TEXTARG: use text as search string. If RE search, also compile the regular
+ * expression into patBuf. (Fall into NOARG code).
+ */
+ case TEXTARG:
+ strcpy ((char *) buf, pArg->arg.textarg.pText);
+ srchbuf[0] = 0;
+ if (pArg->arg.textarg.cArg == 2) {
+ if (patBuf != NULL) {
+ FREE((char *) patBuf);
+ }
+ patBuf = RECompile (buf, fSrchCaseSwit, (flagType)!fUnixRE);
+ if (patBuf == NULL) {
+ printerror ((RESize == -1) ? "Invalid pattern" : "Not enough memory for pattern");
+ return FALSE;
+ }
+ fSrchRePrev = TRUE;
+ } else {
+ fSrchRePrev = FALSE;
+ }
+
+ fSrchWrapPrev = fSrchWrapSwit;
+ strcpy (srchbuf, buf);
+
+ /*
+ * NOARG: use previous search string & parameters
+ */
+ case NOARG:
+ if (srchbuf[0] == 0) {
+ printerror ("No search string specified");
+ return FALSE;
+ }
+ break;
+
+ }
+
+ /*
+ * The case to be used is the use's case switch, or the opposite of that if
+ * meta was specified. Save rest of globals as well.
+ */
+ fSrchAllPrev = fAll;
+ if (fMeta) {
+ fSrchCasePrev = (flagType)!fSrchCasePrev;
+ }
+
+ fSrchDirPrev = fForward;
+
+ /*
+ * When not in a macro, indicate on the dialog line what it is we are
+ * searching for
+ */
+ if (!mtest ()) {
+ char c;
+ l = sout (0, YSIZE, fSrchDirPrev ? "+Search for '" : "-Search for '", infColor);
+ c = srchbuf[ XSIZE - 14];
+ srchbuf[ XSIZE-14] = '\0';
+ l = sout (l, YSIZE, srchbuf, fgColor);
+ srchbuf[ XSIZE-14] = c;
+ soutb (l, YSIZE, "'", infColor);
+ }
+
+ /*
+ * If this is a search for all occurrances, we begin the search from the
+ * file begining. Otherwise, set the start position of the search to the
+ * current cursor position.
+ */
+ if (fSrchAllPrev) {
+ flCur.col = 0;
+ flCur.lin = 0;
+ } else {
+ flCur.col = XCUR (pInsCur) + (fSrchDirPrev ? 1 : -1);
+ flCur.lin = YCUR (pInsCur);
+ }
+
+ /*
+ * Use either the normal searcher, or the regular expression searcher, based
+ * on the use of regular expressions.
+ */
+ if (fSrchRePrev) {
+ l = REsearch (pFileHead,
+ fSrchDirPrev,
+ fSrchAllPrev,
+ fSrchCasePrev,
+ fSrchWrapPrev,
+ patBuf,
+ &flCur);
+ } else {
+ l = search (pFileHead,
+ fSrchDirPrev,
+ fSrchAllPrev,
+ fSrchCasePrev,
+ fSrchWrapPrev,
+ srchbuf,
+ &flCur);
+ }
+
+ /*
+ * if the search was successfull, output the count of items founf for search
+ * all, or highlight the found search string for a single ocurrance search
+ */
+ if (l >= 0) {
+ if (fSrchAllPrev) {
+ newscreen ();
+ domessage ("%d occurrences found",cAll);
+ } else {
+ rnCur.flFirst = flCur;
+ rnCur.flLast.col = flCur.col+l-1;
+ rnCur.flLast.lin = flCur.lin;
+ ClearHiLite( pFileHead, TRUE);
+ SetHiLite (pFileHead,rnCur,HGCOLOR);
+ Display();
+ }
+ cursorfl (flCur);
+ return TRUE;
+ }
+
+ /*
+ * If the search was not successfull, indicate as such.
+ */
+ if (!mtest ()) {
+ srchbuf[XSIZE-12] = 0;
+ domessage (fSrchDirPrev ? "+'%s' not found" : "-'%s' not found", srchbuf);
+ }
+ return FALSE;
+}
+
+
+
+
+
+/*** search - look for a string in a file
+*
+* search will begin a scan of the file looking for a particular string in the
+* specified file beginning at the specified location. We perform simple
+* character string matching. We return the length and location of the match.
+*
+* Input:
+* pFile = pointer to file structure to be searched
+* fForward = TRUE => search forward from the specified location
+* fAll = TRUE => find and highlight all ocurrances
+* fCase = TRUE => case is significant in comparisons
+* fWrap = TRUE => search wraps around ends of file
+* pat = character pointer to the search string
+* pflStart = pointers to the location of the beginning of search. Updated
+* to reflect the actually found location (or the first found
+* for a searchall).
+*
+* Output:
+* Returns length of match if found, -1 if not found
+*
+*************************************************************************/
+int
+search (
+ PFILE pFile,
+ flagType fForward,
+ flagType fAll,
+ flagType fCase,
+ flagType fWrap,
+ char *pat,
+ fl *pflStart
+ )
+{
+ int cbPhys; /* physical length of line */
+ fl flCur; /* current location in file */
+ LINE yMac;
+ linebuf sbuf;
+ linebuf pbuf;
+ int lpat = strlen (pat);
+ int l;
+ char *pFound;
+ char *pSearch; /* point at which to search */
+ rn rnCur; /* range to be highlighted */
+
+ assert (pat && pflStart && pFile);
+ strcpy (pbuf, pat);
+ if (!fCase) {
+ _strlwr (pbuf);
+ }
+ cAll = 0;
+ flCur = *pflStart;
+
+ if (fForward) {
+ /*
+ * forward search. Search every line up until the end of the file. (or up
+ * until the original start position, if wrap was set). Check for CTRL+C
+ * break, and get each lines text.
+ */
+ yMac = pFile->cLines;
+
+ while (flCur.lin < yMac) {
+ if (fCtrlc) {
+ break;
+ }
+ cbPhys = GetLine (flCur.lin, sbuf, pFile);
+ l = cbLog (sbuf);
+
+ /*
+ * search the buffer for the string of interest. Convert string to lower case
+ * first if case insensitive search.
+ */
+ if (!fCase) {
+ _strlwr (sbuf);
+ }
+
+ pSearch = pLog (sbuf,flCur.col,TRUE);
+ if (colPhys (sbuf, pSearch) != flCur.col) {
+ pSearch++;
+ }
+
+ while ((l > flCur.col)
+ && (pFound = lsearch (pSearch, cbPhys - (pSearch-sbuf), pbuf, lpat))) {
+
+ /*
+ * string found. Compute starting column of match. If not already found,
+ * update the caller's copy. For search-all, add the highlight, else for
+ * search once, return the length.
+ */
+ flCur.col = colPhys (sbuf, pFound);
+ if (!cAll) {
+ *pflStart = flCur;
+ }
+ cAll++;
+ if (!fAll) {
+ return colPhys(sbuf, pFound+lpat) - colPhys(sbuf, pFound);
+ }
+ rnCur.flFirst = flCur;
+ rnCur.flLast.lin = flCur.lin;
+ rnCur.flLast.col = flCur.col+lpat-1;
+ SetHiLite (pFile,rnCur,HGCOLOR);
+ pSearch = pLog (sbuf,flCur.col,TRUE) + 1;
+ flCur.col = colPhys (sbuf, pSearch);
+ }
+ noise (flCur.lin++);
+
+ /*
+ * if wrap around supported, then if we're at the end of the file, wrap around
+ * to the begining.
+ */
+ if (fWrap && (flCur.lin >= pFile->cLines)) {
+ yMac = pflStart->lin;
+ flCur.lin = 0;
+ }
+ flCur.col = 0;
+ }
+ } else {
+ /*
+ * backwards search. Doesn't have to be concerned about searchall, since those
+ * always occur forward. Otherwise, the same as above, only backwards.
+ */
+ assert (!fAll);
+ yMac = 0;
+ while (flCur.lin >= yMac) {
+ if (fCtrlc) {
+ break;
+ }
+ GetLine (flCur.lin, sbuf, pFile) - 1;
+ l = cbLog (sbuf);
+
+ /*
+ * search the buffer for the string of interest. Convert string to lower
+ * case first if case insensitive search. Terminate the buffer at the
+ * starting column (this is a backwards search)
+ */
+ if (!fCase) {
+ _strlwr (sbuf);
+ }
+ pSearch = pLog (sbuf, flCur.col, TRUE);
+ *(pSearch+1) = 0;
+ cbPhys = pSearch - sbuf;
+ pSearch = sbuf;
+
+ /*
+ * search the line forward once for any occurrance. Then if FOUND, search
+ * repeatedly for the LAST occurrance in the text, and return the info on
+ * that.
+ */
+ if (pFound = lsearch (pSearch, cbPhys - (pSearch-sbuf), pbuf, lpat)) {
+ do {
+ pSearch = pFound;
+ } while (pFound = lsearch (pSearch+1, cbPhys - (pSearch-sbuf) , pbuf, lpat));
+ flCur.col = colPhys (sbuf, pSearch);
+ *pflStart = flCur;
+ return colPhys(sbuf, pLog (sbuf,flCur.col,TRUE) + lpat) - flCur.col;
+ }
+ noise (flCur.lin--);
+ if (fWrap && (flCur.lin < 0)) {
+ yMac = pflStart->lin;
+ flCur.lin = pFile->cLines-1;
+ }
+ flCur.col = sizeof(linebuf)-1;
+ }
+ }
+
+ /*
+ * end of search. if a search for all, and found at least one, then return the
+ * pattern length. Else, return -1.
+ */
+ if (fAll && cAll) {
+ return lpat;
+ }
+ return -1;
+}
+
+
+
+
+/*** REsearch - look for a pattern in a file
+*
+* REsearch will begin a scan of the file looking for a particular pattern
+* in the specified file beginning at the specified location. We perform
+* regular expression matching. We return the length and location of the
+* match.
+*
+* Input:
+* pFile = pointer to file structure to be searched
+* fForward = TRUE => search forward from the specified location
+* fAll = TRUE => find and highlight all ocurrances
+* fCase = TRUE => case is significant in comparisons
+* fWrap = TRUE => search wraps around ends of file
+* pat = pointer to compiled pattern
+* pflStart = pointers to the location of the beginning of search. Updated
+* to reflect the actually found location (or the first found
+* for a searchall).
+*
+* Output:
+* Returns length of (first) match if found, -1 if not found
+*
+*************************************************************************/
+int
+REsearch (
+ PFILE pFile,
+ flagType fForward,
+ flagType fAll,
+ flagType fCase,
+ flagType fWrap,
+ struct patType *pat,
+ fl *pflStart
+ )
+{
+ fl flCur;
+ int l, rem;
+ rn rnCur; /* area to be highlighted */
+ linebuf sbuf;
+ LINE yMac;
+ unsigned MaxREStack = 512;
+ RE_OPCODE **REStack = (RE_OPCODE **)ZEROMALLOC (MaxREStack * sizeof(*REStack));
+ flagType fAgain;
+
+ assert (pat && pflStart && pFile);
+ cAll = 0;
+ flCur = *pflStart;
+
+ if (fForward) {
+ /*
+ * forward search. Search every line up until the end of the file. (or up
+ * until the original start position, if wrap was set). Check for CTRL+C
+ * break, and get each lines text.
+ */
+ yMac = pFile->cLines;
+ while (flCur.lin < yMac) {
+ if (fCtrlc) {
+ break;
+ }
+ if (GetLine (flCur.lin, sbuf, pFile) >= flCur.col) {
+ fAgain = TRUE;
+ do {
+ switch (rem = REMatch (pat, sbuf, pLog (sbuf, flCur.col, TRUE), REStack, MaxREStack, TRUE)) {
+
+ case REM_MATCH:
+ //
+ // update rnCur to reflect the logical coordinates of the string actually
+ // found.
+ // when real tabs are on, REStart returns the physical character position of
+ // the found string, which still needs to be mapped to the logical columns.
+ //
+ rnCur.flFirst.lin = rnCur.flLast.lin = flCur.lin;
+ rnCur.flFirst.col = colPhys (sbuf, REStart ((struct patType *) patBuf));
+ rnCur.flLast.col = colPhys (sbuf, REStart ((struct patType *) patBuf) + RELength (pat, 0)) - 1;
+
+ //
+ // If not already found, update the caller's copy. For search-all, add the
+ // highlight, else for search once, return the length.
+ //
+ if (!cAll++) {
+ *pflStart = rnCur.flFirst;
+ }
+ if (fAll) {
+ SetHiLite (pFile,rnCur,HGCOLOR);
+ } else {
+ FREE (REStack);
+ return rnCur.flLast.col - rnCur.flFirst.col + 1;
+ }
+ flCur.col = rnCur.flFirst.col + 1;
+ break;
+
+ case REM_STKOVR:
+ //
+ // The RE machine stack overflowed. Increase and try again
+ //
+ MaxREStack += 128;
+ REStack = (RE_OPCODE **)ZEROREALLOC((PVOID)REStack, MaxREStack * sizeof (*REStack));
+ break;
+
+ //
+ // Either REM_INVALID (we passed in bad parameters), or REM_UNDEF (undefined
+ // opcode in pattern. Either way, it's an internal error
+ //
+ default:
+ printerror ("Internal Error: RE error %d, line %ld", rem, flCur.lin);
+
+ case REM_NOMATCH:
+ fAgain = FALSE;
+ break;
+
+ }
+ } while (fAgain);
+ }
+ noise (flCur.lin++);
+
+ /*
+ * if wrap around supported, then if we're at the end of the file, wrap around
+ * to the begining.
+ */
+ if (fWrap && (flCur.lin >= pFile->cLines)) {
+ yMac = pflStart->lin;
+ flCur.lin = 0;
+ }
+ flCur.col = 0;
+ }
+ } else {
+ /*
+ * backwards search. Doesn't have to be concerned about searchall, since those
+ * always occur forward. Otherwise, the same as above, only backwards.
+ */
+ assert (!fAll);
+ if (flCur.col < 0) {
+ flCur.lin--;
+ }
+ yMac = 0;
+ while (flCur.lin >= yMac) {
+ if (fCtrlc) {
+ break;
+ }
+ l = GetLine (flCur.lin, sbuf, pFile);
+ if (flCur.col < 0) {
+ flCur.col = l;
+ }
+ fAgain = TRUE;
+ do {
+ switch (rem = REMatch (pat, sbuf, pLog (sbuf, flCur.col, TRUE), REStack, MaxREStack, FALSE)) {
+ case REM_MATCH:
+ pflStart->col = colPhys (sbuf, REStart ((struct patType *) patBuf));
+ pflStart->lin = flCur.lin;
+ FREE (REStack);
+ return colPhys (sbuf, REStart ((struct patType *) patBuf) + RELength (pat, 0))
+ - colPhys (sbuf, REStart ((struct patType *) patBuf));
+
+ case REM_STKOVR:
+ MaxREStack += 128;
+ REStack = (RE_OPCODE **)ZEROREALLOC ((PVOID)REStack, MaxREStack * sizeof(*REStack));
+ break;
+
+ default:
+ printerror ("Internal Error: RE error %d, line %ld", rem, flCur.lin);
+
+ case REM_NOMATCH:
+ fAgain = FALSE;
+ break;
+ }
+ } while (fAgain);
+
+ flCur.col = -1;
+ noise (flCur.lin--);
+ if (fWrap && (flCur.lin < 0)) {
+ yMac = pflStart->lin;
+ flCur.lin = pFile->cLines-1;
+ }
+ }
+ }
+
+ FREE (REStack);
+
+ /*
+ * end of search. if a search for all, and found at least one, then return the
+ * pattern length. Else, return -1.
+ */
+ if (fAll && cAll) {
+ return RELength (pat, 0);
+ }
+ return -1;
+
+ fCase;
+}
+
+
+
+
+/*** REsearchS - look for a pattern in a file
+*
+* REsearchS will begin a scan of the file looking for a particular pattern
+* in the specified file beginning at the specified location. We perform
+* regular expression matching. We return the length and location of the
+* match.
+*
+* REsearchS is the same as REsearch, except that is takes an uncompiled
+* string.
+*
+* Input:
+* pFile = pointer to file structure to be searched
+* fForward = TRUE => search forward from the specified location
+* fAll = TRUE => find and highlight all ocurrances
+* fCase = TRUE => case is significant in comparisons
+* fWrap = TRUE => search wraps around ends of file
+* pat = pointer to RE character string
+* pflStart = pointers to the location of the beginning of search. Updated
+* to reflect the actually found location (or the first found
+* for a searchall).
+*
+* Output:
+* Returns length of (first) match if found, -1 if not found
+*
+*************************************************************************/
+int
+REsearchS (
+ PFILE pFile,
+ flagType fForward,
+ flagType fAll,
+ flagType fCase,
+ flagType fWrap,
+ char *pat,
+ fl *pflStart
+ )
+{
+ assert (pat && pflStart && pFile);
+ if (patBuf != NULL) {
+ FREE ((char *) patBuf);
+ }
+ patBuf = RECompile (pat, fCase, (flagType)!fUnixRE);
+ if (patBuf == NULL) {
+ printerror ( (RESize == -1) ? "Invalid pattern" : "Not enough memory for pattern");
+ return -1;
+ }
+ return REsearch (pFile, fForward, fAll, fCase, fWrap, patBuf, pflStart);
+
+}
diff --git a/private/utils/mep/src/setfile.c b/private/utils/mep/src/setfile.c
new file mode 100644
index 000000000..feeeba35d
--- /dev/null
+++ b/private/utils/mep/src/setfile.c
@@ -0,0 +1,300 @@
+/* setfile.c - top-level file management commands
+*
+* Modifications:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+#include "mep.h"
+
+
+static char *NoAlternate = "no alternate file";
+
+
+/*** setfile - editor command to change and save files
+*
+* <setfile> - set to previous file on instance list
+* <arg> text <setfile> - set to specified file
+* <arg> <setfile> - set to file spacified at current cursor pos
+* <arg><arg> text <setfile> - write current file to specified filename
+* <arg><arg> <setfile> - write current file to disk
+* <meta> ... - do not autosave current file on change
+*
+* The following is undocumented:
+*
+* <arg><arg> "text" <meta> <setfile> - Like <arg><arg><setfile>, but
+* doesn't prompt for confirmation
+* and switches to new file even
+* for pseudo-files.
+*
+* Input:
+* Standard editting function
+*
+* Output:
+* Returns TRUE on success
+*
+*************************************************************************/
+flagType
+setfile (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ )
+{
+ linebuf name; /* name to set to. 'linebuf', so fInsSpace can take it */
+ pathbuf path;
+ char *p = name;
+
+ switch (pArg->argType) {
+
+ case NOARG:
+ if (pInsCur->pNext == NULL) {
+ domessage( NoAlternate );
+ return FALSE;
+ }
+ name[0] = 0;
+ break;
+
+ case TEXTARG:
+ if (pArg->arg.textarg.cArg > 1) {
+ CanonFilename (pArg->arg.textarg.pText, path);
+ /* The fMeta thing is a definite hack */
+ if (fMeta || confirm("Do you want to save this file as %s ?", path)) {
+ if (FileWrite (path, pFileHead)) {
+ if (!TESTFLAG (FLAGS(pFileHead), FAKE) || fMeta) {
+ FREE (pFileHead->pName);
+ pFileHead->pName = ZMakeStr (path);
+ RSETFLAG (FLAGS(pFileHead), (DIRTY | FAKE | TEMP));
+ }
+ SETFLAG (fDisplay, RSTATUS);
+ SetModTime( pFileHead );
+ return TRUE;
+ }
+ else
+ return FALSE;
+ }
+ else {
+ DoCancel();
+ return FALSE;
+ }
+ }
+ else
+ findpath (pArg->arg.textarg.pText, name, TRUE);
+ break;
+
+ case NULLARG:
+ if (pArg->arg.nullarg.cArg > 1)
+ return (flagType)!FileWrite (NULL, pFileHead);
+
+ fInsSpace (pArg->arg.nullarg.x, pArg->arg.nullarg.y, 0, pFileHead, name);
+ p = pLog(name,pArg->arg.nullarg.x,TRUE);
+
+ //
+ // Check to see if this a C file and it is an #include line
+ //
+
+ if ((FTYPE (pFileHead) == CFILE && strpre ("#include ", p)) ||
+ (FTYPE (pFileHead) == ASMFILE && strpre ("include", p))) {
+
+ //
+ // skip the include directive
+ //
+
+ p = whitescan (p);
+ p = whiteskip (p);
+ }
+
+ /*
+ * Terminate filename at first whitespace
+ */
+ *whitescan (p) = 0;
+
+ /*
+ * If file is C, attempt to strip off #include delimiters if present
+ */
+ if (FTYPE (pFileHead) == CFILE) {
+ if (*p == '"')
+ *strbscan (++p, "\"") = 0;
+ else
+ if (*p == '<') {
+ *strbscan (++p, ">") = 0;
+ sprintf (path, "$INCLUDE:%s", p);
+ CanonFilename (path, p = name);
+ }
+ else
+ *strbscan (p, "\">") = 0;
+ }
+ else {
+ /*
+ * If file is ASM, attempt to remove comment chars if present
+ */
+ if (FTYPE (pFileHead) == ASMFILE)
+ * strbscan (p, ";") = 0;
+ }
+
+ break;
+ }
+
+ if (!fMeta)
+ AutoSave ();
+
+ if (name[0] == 0) {
+ strcpy (name, pInsCur->pNext->pFile->pName);
+ }
+
+ return fChangeFile (TRUE, p);
+
+ argData;
+}
+
+
+
+
+/*** refresh - re-read or discard file
+*
+* <refresh> - re-read current file
+* <arg> <refresh> - remove current file from memory
+*
+* Input:
+* Standard editting function
+*
+* Output:
+* Returns TRUE on success
+*
+*************************************************************************/
+flagType
+refresh (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ )
+{
+ EVTargs e;
+
+ switch (pArg->argType) {
+ case NOARG:
+ if (confirm("Do you want to reread this file? ", NULL)) {
+ /*
+ * Offer to the extensions as an event
+ */
+ e.pfile = pFileHead;
+ DeclareEvent (EVT_REFRESH,(EVTargs *)&e);
+
+ /*
+ * if assigns, force re-read
+ */
+ if (!strcmp (pFileHead->pName, rgchAssign)) {
+ fNewassign = TRUE;
+ }
+
+ FileRead (pFileHead->pName, pFileHead, TRUE);
+ RSETFLAG (FLAGS (pFileHead), DIRTY);
+ SETFLAG (fDisplay, RSTATUS);
+ return TRUE;
+ }
+ return FALSE;
+
+ case NULLARG:
+ if (pInsCur->pNext == NULL) {
+ domessage( NoAlternate );
+ return FALSE;
+ }
+ if (!confirm ("Do you want to delete this file from the current window? ", NULL)) {
+ return FALSE;
+ }
+
+ RemoveTop ();
+
+ newscreen ();
+
+ while (pInsCur != NULL) {
+ if (fChangeFile (FALSE, pFileHead->pName)) {
+ return TRUE;
+ }
+ }
+ return fChangeFile (FALSE, rgchUntitled);
+ }
+ argData; fMeta;
+}
+
+
+
+
+/*** noedit - Toggle no-edit flags
+*
+* Purpose:
+*
+* To give the user control over the edit/no-edit state of the editor and
+* its files. The editor has two flags controlling this:
+*
+* Global no-edit => When flag is set, no file may be edited.
+* Per-file no-edit => When set, the given file cannot be edited
+*
+* This function can be invoked as follows:
+*
+* <noedit> Toggles global no-edit state. When set, has same
+* effect as /r switch.
+*
+* <meta><noedit> Toggles the per-file no-edit state for current file.
+*
+* Output: Returns new state. TRUE means no editing, FALSE means editing
+* is allowed
+*
+* Notes:
+*
+* This does not allow the user to change permissions on pseudo files.
+*
+*************************************************************************/
+flagType
+noedit (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ )
+{
+ SETFLAG (fDisplay, RSTATUS);
+
+ if (!fMeta) {
+ return fGlobalRO = (flagType)!fGlobalRO;
+ }
+
+ if (TESTFLAG (FLAGS(pFileHead), FAKE)) {
+ return (flagType)(TESTFLAG(FLAGS(pFileHead), READONLY));
+ }
+
+ if (TESTFLAG (FLAGS(pFileHead), READONLY)) {
+ RSETFLAG (FLAGS(pFileHead), READONLY);
+ return FALSE;
+ } else {
+ SETFLAG (FLAGS(pFileHead), READONLY);
+ return TRUE;
+ }
+ argData; pArg;
+}
+
+
+
+
+
+/*** saveall - Editor <saveall> function
+*
+* Purpose:
+* Saves all dirty files.
+*
+* Input: The usual. Accepts only NOARG.
+*
+* Output:
+* Returns always true.
+*
+*************************************************************************/
+flagType
+saveall (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ )
+{
+ SaveAllFiles ();
+ return TRUE;
+
+ argData; pArg; fMeta;
+}
diff --git a/private/utils/mep/src/show.c b/private/utils/mep/src/show.c
new file mode 100644
index 000000000..8b3152585
--- /dev/null
+++ b/private/utils/mep/src/show.c
@@ -0,0 +1,302 @@
+/*** show.c - useful information displays
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+#include "mep.h"
+#include "cmds.h"
+
+
+/*** showasg - construct the <assign> file
+*
+* Input:
+* pFile = pFile to contruct it in
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void
+showasg (
+ PFILE pFile
+ )
+{
+ int i, j;
+ PSWI pSwi;
+ linebuf tempbuf;
+ extern unsigned char Int16CmdBase;
+
+ /*
+ * if now new assignments have been made (and file isn't empty), then don't
+ * refresh the contents!
+ */
+ if (!fNewassign && pFile->cLines) {
+ return;
+ }
+
+ fNewassign = FALSE;
+ pFileAssign = pFile;
+ DelFile (pFile, FALSE);
+
+ /*
+ * Write header to assign file
+ */
+ appmsgs (MSG_ASSIGN_HDR, pFile);
+ AppFile ((char *)rgchEmpty, pFile);
+
+ /*
+ * Start editor section on intrinsic functions with editor name, comment, and
+ * dump the functions.
+ */
+ zprintf (pFile, pFile->cLines, "[%s]", pNameEditor);
+ AppFile (GetMsg (MSG_ASG_FUNC, tempbuf), pFile);
+ AppFile ((char *)rgchEmpty, pFile);
+ for (i = 0; cmdSet[0][i].name; i++) {
+ FuncOut (&cmdSet[0][i], pFile);
+ }
+ AppFile ((char *)rgchEmpty, pFile);
+
+ /*
+ * The section on macros
+ */
+ AppFile (GetMsg (MSG_ASG_MACROS, tempbuf), pFile);
+ AppFile ((char *)rgchEmpty, pFile);
+ for (i = 0; i < cMac; i++) {
+ FuncOut (rgMac[i], pFile);
+ }
+ AppFile ((char *)rgchEmpty, pFile);
+
+ /*
+ * section specfic to each extension
+ */
+ for (i = 1; i < cCmdTab; i++) {
+ zprintf (pFile, pFile->cLines, "[%s-%s]", pNameEditor, pExtName[i]);
+ AppFile ((char *)rgchEmpty, pFile);
+ for (j = 0; cmdSet[i][j].name; j++) {
+ FuncOut (&cmdSet[i][j], pFile);
+ }
+ AppFile ((char *)rgchEmpty, pFile);
+ }
+
+ /*
+ * Write available keys header
+ */
+ appmsgs (MSG_KEYS_HDR1, pFile);
+ UnassignedOut (pFile);
+ AppFile ((char *)rgchEmpty, pFile);
+
+ /*
+ * Remember the start of the switches section, and dump that header
+ */
+ lSwitches = pFile->cLines - 1;
+ appmsgs (MSG_SWITCH_HDR, pFile);
+
+ for (i = 0; i < cCmdTab; i++) {
+
+ if (i) {
+ zprintf (pFile, pFile->cLines, "[%s-%s]", pNameEditor, pExtName[i]);
+ } else {
+ zprintf (pFile, pFile->cLines, "[%s]", pNameEditor);
+ }
+
+ AppFile (GetMsg(MSG_ASG_NUMER, tempbuf), pFile);
+ AppFile ((char *)rgchEmpty, pFile);
+
+ for (pSwi = swiSet[i]; pSwi->name != NULL; pSwi++) {
+
+ if ((pSwi->type & 0xFF) == SWI_NUMERIC ||
+ (pSwi->type & 0xFF) == SWI_SCREEN) {
+
+ if ((pSwi->type & 0xFF00) == RADIX16) {
+ zprintf (pFile, pFile->cLines, "%20Fs:%x", pSwi->name, *pSwi->act.ival);
+ } else {
+ zprintf (pFile, pFile->cLines, "%20Fs:%d", pSwi->name, *pSwi->act.ival);
+ }
+
+ } else if ((i == 0) && (pSwi->type & 0xFF) >= SWI_SPECIAL) {
+
+ if (pSwi->act.pFunc2 == SetFileTab) {
+ j = fileTab;
+ } else if (pSwi->act.pFunc == SetTabDisp) {
+ j = (unsigned char)tabDisp;
+ } else if (pSwi->act.pFunc == SetTrailDisp) {
+ j = (unsigned char)trailDisp;
+ } else if (pSwi->act.pFunc == (PIF)SetCursorSizeSw ) {
+ j = CursorSize;
+ } else {
+ continue;
+ }
+
+ zprintf (pFile, pFile->cLines, "%20Fs:%ld", pSwi->name, (long)(unsigned)j);
+ }
+ }
+
+ AppFile ((char *)rgchEmpty, pFile);
+
+ AppFile (GetMsg(MSG_ASG_BOOL,tempbuf), pFile);
+ AppFile ((char *)rgchEmpty, pFile);
+
+ for (pSwi = swiSet[i]; pSwi->name != NULL; pSwi++) {
+ if ((pSwi->type & 0xFF) == SWI_BOOLEAN) {
+ zprintf (pFile, pFile->cLines, "%20Fs:%s", pSwi->name, *pSwi->act.fval ? "yes" : "no");
+ }
+ }
+
+ AppFile ((char *)rgchEmpty, pFile);
+
+ if (i == 0) {
+ AppFile (GetMsg(MSG_ASG_TEXT,tempbuf), pFile);
+ AppFile ((char *)rgchEmpty, pFile);
+
+ zprintf (pFile, pFile->cLines, "%11s:%s", "backup",
+ backupType == B_BAK ? "bak" : backupType == B_UNDEL ? "undel" : "none");
+
+ ShowMake (pFile);
+ if (pFileMark) {
+ zprintf (pFile, pFile->cLines, "%11s:%s", "markfile", pFileMark->pName);
+ }
+ zprintf (pFile, pFile->cLines, "%11s:%s", "printcmd", pPrintCmd ? pPrintCmd : "");
+ zprintf (pFile, pFile->cLines, "%11s:%s", "readonly", ronlypgm ? ronlypgm : "");
+ AppFile ((char *)rgchEmpty, pFile);
+
+ }
+ }
+
+ FTYPE(pFile) = TEXTFILE;
+ RSETFLAG (FLAGS(pFile), DIRTY);
+}
+
+
+
+/*** appmsgs - append series of text messages to pFile
+*
+* Appends a series of text strings to the passed pFile
+*
+* Input:
+* iMsg - Starting message number
+* pFile - pFile to append to
+*
+* Output:
+* Returns
+*
+*************************************************************************/
+void
+appmsgs (
+ int iMsg,
+ PFILE pFile
+ )
+{
+ linebuf tempbuf;
+
+ while (TRUE) {
+ GetMsg (iMsg++,tempbuf);
+ if (tempbuf[0] == '?') {
+ break;
+ }
+ AppFile (tempbuf, pFile);
+ }
+}
+
+
+static char szEmptyClipboard[] = "The clipboard is empty";
+
+
+/*** showinf - construct <information-file>
+*
+* Input:
+* pFile - pFile to construct in
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void
+showinf (
+ PFILE pFile
+ )
+{
+ PFILE pFileTmp;
+
+ DelFile (pFile, FALSE);
+ SETFLAG (FLAGS(pFile), READONLY);
+ AppFile (Name, pFile);
+ AppFile (Version, pFile);
+ AppFile ((char *)rgchEmpty, pFile);
+ RSETFLAG (FLAGS(pFile), DIRTY);
+ for (pFileTmp = pFileHead; pFileTmp != NULL; pFileTmp = pFileTmp->pFileNext) {
+ infprint (pFileTmp, pFile);
+ }
+ AppFile ((char *)rgchEmpty, pFile);
+ if (pFilePick->cLines == 0) {
+ AppFile (szEmptyClipboard, pFile);
+ } else {
+ zprintf (pFile, pFile->cLines, "%ld line%s in %s clipboard", pFilePick->cLines,
+ pFilePick->cLines == 1 ? (char *)rgchEmpty : "s",
+ kindpick == STREAMARG ? "stream" : kindpick == LINEARG ? "line" :
+ kindpick == BOXARG ? "box" : "?");
+ }
+ AppFile ((char *)rgchEmpty, pFile);
+ FTYPE(pFile) = TEXTFILE;
+ RSETFLAG (FLAGS(pFile), DIRTY);
+}
+
+
+
+
+/*** infprint - print info about 1 file
+*
+* Appends to the information file the info on 1 file
+*
+* Input:
+* pFile - pFile of interest
+* pFileDisplay - pFile to display in
+*
+* Output:
+* Returns FALSE
+*
+*************************************************************************/
+flagType
+infprint (
+ PFILE pFile,
+ PFILE pFileDisplay
+ )
+{
+ if (TESTFLAG(FLAGS(pFile),REAL)) {
+ zprintf (pFileDisplay, pFileDisplay->cLines, "%-30s %c%ld lines", pFile->pName,
+ TESTFLAG(FLAGS(pFile),DIRTY) ? '*' : ' ',
+ pFile->cLines);
+ } else {
+ zprintf (pFileDisplay, pFileDisplay->cLines, "%-20s", pFile->pName);
+ }
+ return FALSE;
+}
+
+
+
+
+/*** information - show editting history
+*
+* Display the information file
+*
+* Input:
+* standard editing function
+*
+* Output:
+* Returns TRUE on successfull display
+*
+*************************************************************************/
+flagType
+information (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ )
+{
+ AutoSave ();
+ return fChangeFile (FALSE, rgchInfFile);
+
+ argData; pArg; fMeta;
+}
diff --git a/private/utils/mep/src/sources b/private/utils/mep/src/sources
new file mode 100644
index 000000000..c88604b9d
--- /dev/null
+++ b/private/utils/mep/src/sources
@@ -0,0 +1,79 @@
+MAJORCOMP=sdktools
+MINORCOMP=mep
+
+TARGETNAME=mep
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+INCLUDES=..\inc;\nt\private\sdktools\ztools\inc
+
+SOURCES=arg.c \
+ assign.c \
+ build.c \
+ cdelete.c \
+ cmd.c \
+ compile.c \
+ console.c \
+ cursor.c \
+ delete.c \
+ display.c \
+ dline.c \
+ env.c \
+ event.c \
+ file.c \
+ fileio.c \
+ fscan.c \
+ getstr.c \
+ graphic.c \
+ hilite.c \
+ insert.c \
+ key.c \
+ lang.c \
+ ldelete.c \
+ linsert.c \
+ list.c \
+ load.c \
+ macro.c \
+ mark.c \
+ mep.c \
+ mepstr.c \
+ mouse.c \
+ newline.c \
+ pbal.c \
+ pick.c \
+ record.c \
+ replace.c \
+ search.c \
+ setfile.c \
+ show.c \
+ statfile.c \
+ tab.c \
+ table.c \
+ textline.c \
+ transkey.c \
+ undo.c \
+ untab.c \
+ keyboard.c \
+ window.c \
+ word.c \
+ z19.c \
+ zaux.c \
+ zdebug.c \
+ zexit.c \
+ zinit.c \
+ zprint.c \
+ zspawn.c \
+ zthread.c \
+ zutil.c \
+ mep.rc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+C_DEFINES=-D_OS2_20_=0 -DNO_EXT_KEYS -DNOLANMAN -DNT -DDEBUG
+!ELSE
+C_DEFINES=-D_OS2_20_=0 -DNO_EXT_KEYS -DNOLANMAN -DNT
+!ENDIF
+
+UMTYPE=console
+UMLIBS=\nt\public\sdk\lib\*\setargv.obj \
+ \nt\private\sdktools\ztools\src\obj\*\ztools.lib \
+ \nt\public\sdk\lib\*\user32.lib
diff --git a/private/utils/mep/src/statfile.c b/private/utils/mep/src/statfile.c
new file mode 100644
index 000000000..7f1041658
--- /dev/null
+++ b/private/utils/mep/src/statfile.c
@@ -0,0 +1,366 @@
+/*** statefile.c - Code for status/state file processing
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+*
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+
+#include "mep.h"
+
+
+
+/*** ReadTMPFile - Read the editor .STS/.TMP status file
+*
+* Load up the information from the project status file.
+*
+* Input:
+*
+* Output:
+*
+*************************************************************************/
+flagType
+ ReadTMPFile (
+ )
+{
+ FILE *fhTmp; /* .TMP file file handle */
+
+ PWND pWin = NULL;
+
+ int x; /* x corrdinate read from file */
+ int y; /* y corrdinate read from file */
+
+ char *pName;
+ char *pData;
+ PINS pInsNew = NULL;
+ PINS pInsHead = NULL;
+ PFILE pFileTmp; /* pFile being created */
+ PFILE *ppFileList;
+
+ ppFileList = &pFileHead;
+ while (pFileTmp = *ppFileList) {
+ ppFileList = &pFileTmp->pFileNext;
+ }
+
+ if ((fhTmp = pathopen (pNameTmp, buf, "rt")) != NULL) {
+
+ /*
+ * Read the header lines in the file. We ignore the first line (editor
+ * version), make sure that the second line contains the expected .TMP file
+ * version string, and the third line has two integers, which are the screen
+ * dimensions.
+ */
+ if ((fgetl (buf, sizeof(buf), fhTmp) == 0)
+ || (fgetl (buf, sizeof(buf), fhTmp) == 0)
+ || strcmp(buf,TMPVER)
+ || (fgetl (buf, sizeof(buf), fhTmp) == 0)
+ || (sscanf (buf, "%d %d", &x, &y) != 2)) {
+ } else {
+ /*
+ * For each line in the rest of the .TMP file, process
+ */
+ while (fgetl (buf, sizeof(buf), fhTmp) != 0) {
+ // assert (_heapchk() == _HEAPOK);
+ assert (_pfilechk());
+ /*
+ * Process previous search & replace strings
+ */
+ if (!_strnicmp ("SRCH:", buf, 5)) {
+ strcpy (srchbuf, buf+5);
+ } else if (!_strnicmp ("DST:", buf, 4)) {
+ strcpy (rplbuf, buf+4);
+ } else if (!_strnicmp ("SRC:", buf, 4)) {
+ strcpy (srcbuf, buf+4);
+ } else if (!_strnicmp ("INS:", buf, 4)) {
+ fInsert = (flagType)!_strnicmp ("ON", buf+4, 2);
+ } else {
+ switch (buf[0]) {
+
+ /*
+ * lines begining with ">" indicate a new window. On the rest of
+ * the line, the first two digits are the window screen position,
+ * and the next are the window size.
+ */
+ case '>':
+ pWin = &WinList[cWin++];
+ sscanf (buf+1, " %d %d %d %d ",
+ &WINXPOS(pWin), &WINYPOS(pWin),
+ &WINXSIZE(pWin), &WINYSIZE(pWin));
+ pWin->pInstance = NULL;
+ break;
+
+ /*
+ * Lines begining with a space are instance descriptors of the files
+ * in the most recent window's instance list.
+ */
+ case ' ':
+ /*
+ * allocate new instance, and place at tail of list (list now
+ * created in correct order).
+ */
+ if (pInsNew) {
+ pInsNew->pNext = (PINS) ZEROMALLOC (sizeof (*pInsNew));
+ pInsNew = pInsNew->pNext;
+ } else {
+ pInsHead = pInsNew = (PINS) ZEROMALLOC (sizeof (*pInsNew));
+ }
+#ifdef DEBUG
+ pInsNew->id = ID_INSTANCE;
+#endif
+ /*
+ * isolate filename and parse out instance information
+ */
+ ParseCmd (buf, &pName,&pData);
+ sscanf (pData, " %d %ld %d %ld "
+ , &XWIN(pInsNew), &YWIN(pInsNew)
+ , &XCUR(pInsNew), &YCUR(pInsNew));
+ //
+ // If the cursor position falls outside of the current
+ // window, we patch it
+ //
+ if( XCUR(pInsNew) - XWIN(pInsNew) > XSIZE ) {
+
+ XCUR(pInsNew) = XWIN(pInsNew) + XSIZE - 1;
+ }
+
+ if ( YCUR(pInsNew) - YWIN(pInsNew) > YSIZE ) {
+
+ YCUR(pInsNew) = YWIN(pInsNew) + YSIZE - 1;
+ }
+
+ /*
+ //
+ // If the window and cursor dimensions conflict with
+ // the current dimensions, we patch them.
+ //
+ if ((XWIN(pInsNew) > XSIZE) || (YWIN(pInsNew) > YSIZE)) {
+ XWIN(pInsNew) = XSIZE;
+ YWIN(pInsNew) = YSIZE;
+ }
+
+ //if ((XCUR(pInsNew) > XSIZE) || (YCUR(pInsNew) > YSIZE)) {
+ // XCUR(pInsNew) = 0;
+ // YCUR(pInsNew) = 0;
+ //}
+ */
+
+ /*
+ * create file structure
+ */
+ pFileTmp = (PFILE) ZEROMALLOC (sizeof (*pFileTmp));
+#ifdef DEBUG
+ pFileTmp->id = ID_PFILE;
+#endif
+ pFileTmp->pName = ZMakeStr (pName);
+
+ pFileTmp->plr = NULL;
+ pFileTmp->pbFile = NULL;
+ pFileTmp->vaColor = (PVOID)(-1L);
+ pFileTmp->vaHiLite = (PVOID)(-1L);
+ pFileTmp->vaUndoCur = (PVOID)(-1L);
+ pFileTmp->vaUndoHead = (PVOID)(-1L);
+ pFileTmp->vaUndoTail = (PVOID)(-1L);
+
+ CreateUndoList (pFileTmp);
+
+ /*
+ * Place the file at the end of the pFile list
+ */
+ *ppFileList = pFileTmp;
+ ppFileList = &pFileTmp->pFileNext;
+ SetFileType (pFileTmp);
+ IncFileRef (pFileTmp);
+ pInsNew->pFile = pFileTmp;
+ break;
+
+ /*
+ * A blank line occurrs at the end of the file list for a window.
+ * We use this to advance to next window. If we *just* found more
+ * than one window, fix the screen mode to match the last value
+ */
+ case '.':
+ case '\0':
+ if (cWin > 1 && !fVideoAdjust (x, y)) {
+ goto initonewin;
+ }
+ assert (pWin && cWin);
+ pWin->pInstance = pInsHead;
+ pInsHead = pInsNew = NULL;
+ break;
+ }
+ }
+ }
+ }
+
+ fclose (fhTmp);
+
+ /*
+ * At startup, current window is always first window
+ */
+ pWinCur = WinList;
+ }
+
+ if (cWin == 1) {
+ WINXSIZE(pWinCur) = XSIZE;
+ WINYSIZE(pWinCur) = YSIZE;
+ } else if (cWin == 0) {
+initonewin:
+ /*
+ * if no status file was read, ensure that we have at least one valid window,
+ * the size of the screen
+ */
+ cWin = 1;
+ pWinCur = WinList;
+ pWinCur->pInstance = NULL;
+ WINXSIZE(pWinCur) = XSIZE;
+ WINYSIZE(pWinCur) = YSIZE;
+ }
+
+ assert(pWinCur);
+
+ pInsCur = pWinCur->pInstance;
+
+ /*
+ * Get the file to edit from the command line, if any.
+ * This will eventually set pInsCur.
+ */
+ if (!fFileAdvance() && fCtrlc) {
+ CleanExit (1, CE_VM | CE_SIGNALS);
+ }
+
+ /*
+ * Find windows with no instance: set current file to <untitled>
+ */
+ for (pWin = WinList; pWin < &WinList[cWin]; pWin++) {
+ if (pWin->pInstance == NULL) {
+ pInsHead = (PINS) ZEROMALLOC (sizeof (*pInsHead));
+#ifdef DEBUG
+ pInsHead->id = ID_INSTANCE;
+#endif
+ if (!(pInsHead->pFile = FileNameToHandle (rgchUntitled, rgchEmpty))) {
+ pInsHead->pFile = AddFile ((char *)rgchUntitled);
+ }
+ IncFileRef (pInsHead->pFile);
+ pWin->pInstance = pInsHead;
+ }
+ }
+
+ /*
+ * Set current instance if not already done by fFileAdvance
+ */
+ if (pInsCur == NULL) {
+ pInsCur = pWinCur->pInstance;
+ }
+
+ assert (pInsCur);
+
+ /*
+ * If we cannot change to the current file, we will walk the window instance
+ * list until we get a valid file. If no one can be loaded then we switch to
+ * the <untitled> pseudo-file.
+ * NB: fChangeFile does a RemoveTop so we don't need to move pInsCur
+ */
+ while ((pInsCur != NULL) && (!fChangeFile (FALSE, pInsCur->pFile->pName))) {
+ ;
+ }
+
+ if (pInsCur == NULL) {
+ fChangeFile (FALSE, rgchUntitled);
+ }
+
+ return TRUE;
+}
+
+
+
+
+/*** WriteTMPFile
+*
+* Purpose:
+*
+* Input:
+*
+* Output:
+* Returns .....
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+void
+WriteTMPFile (
+ void
+ )
+{
+ FILE *fh;
+ int i, j;
+ PFILE pFileTmp;
+ PINS pInsTmp;
+
+ if ((fh = pathopen (pNameTmp, buf, "wt")) == NULL) {
+ return;
+ }
+ fprintf (fh, "%s %s\n", Name, Version);
+ fprintf (fh, TMPVER"\n");
+ fprintf (fh, "%d %d\n", XSIZE, YSIZE);
+
+ /*
+y * we truncate the search, src and rpl buffers back 10 characters each from the
+ * maximum before writing them out. This avoids more major hacks in the code
+ * which reads these lines back in, which limit the total line length to
+ * BUFLEN.
+ */
+ srchbuf[sizeof(srcbuf)-10] = 0;
+ srcbuf[sizeof(srcbuf)-10] = 0;
+ rplbuf[sizeof(rplbuf)-10] = 0;
+ fprintf (fh, "SRCH:");
+ fprintf (fh, "%s", srchbuf);
+ fprintf (fh, "\nSRC:");
+ fprintf (fh, "%s", srcbuf);
+ fprintf (fh, "\nDST:");
+ fprintf (fh, "%s", rplbuf);
+
+ fprintf (fh, "\nINS:%s\n", (fInsert)?"ON":"OFF");
+ for (i = 0; i < cWin; i++) {
+ if ((pInsTmp = WinList[i].pInstance) != NULL) {
+ fprintf (fh, "> %d %d %d %d\n", WinList[i].Pos.col, WinList[i].Pos.lin,
+ WinList[i].Size.col, WinList[i].Size.lin);
+ j = 0;
+ while (pInsTmp != NULL) {
+ if (tmpsav && tmpsav == j)
+ break;
+ pFileTmp = pInsTmp->pFile;
+ if (!TESTFLAG (FLAGS (pFileTmp), FAKE | TEMP)) {
+ j++;
+ fprintf (fh, " %s %d %ld %d %ld\n", pFileTmp->pName,
+ XWIN(pInsTmp), YWIN(pInsTmp),
+ XCUR(pInsTmp), YCUR(pInsTmp));
+ }
+ pInsTmp = pInsTmp->pNext;
+ }
+ /* empty window */
+ if (j == 0) {
+ fprintf (fh, " %s 0 0 0 0\n", rgchUntitled);
+ }
+ fprintf (fh, ".\n");
+ }
+ }
+ fclose (fh);
+}
+
+
+flagType
+savetmpfile (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ )
+{
+ argData; pArg; fMeta;
+
+ WriteTMPFile();
+ return TRUE;
+}
diff --git a/private/utils/mep/src/tab.c b/private/utils/mep/src/tab.c
new file mode 100644
index 000000000..4d74cbba7
--- /dev/null
+++ b/private/utils/mep/src/tab.c
@@ -0,0 +1,242 @@
+/*** tab.c - perform tabification on output
+*
+* Modifications:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+#include "mep.h"
+
+
+
+/*** TabMin - tabify buf, outside of strings
+*
+* tabify buf in place and return length. Take into account " and ' chars
+* and remember escaping
+*
+* Input:
+* tab = tab stops to entab to
+* src = source buffer
+* dst = destination buffer
+*
+* Output:
+* Returns physical length of buffer
+*
+*************************************************************************/
+int
+TabMin (
+ int tab,
+ char *src,
+ char *dst
+ )
+{
+ int column = 0; /* current column offset */
+ char cQuote; /* character that began a quote */
+ int cSpaces; /* count of spaces in run */
+ flagType fEscape = FALSE; /* TRUE => processing escape */
+ flagType fQuote = FALSE; /* TRUE => processing quote */
+ REGISTER char *pDst = dst; /* moving ptr into dest */
+ REGISTER char *pSrc = src; /* moving ptr into source */
+
+ /*
+ * while there are characters to output
+ */
+ while (*pSrc) {
+
+ /*
+ * if we are not quoting or escaping then we collect runs of spaces
+ */
+ if (!fQuote && !fEscape) {
+ cSpaces = 0;
+
+ /*
+ * while there are spaces or tabs, collect runs thereof each time we have
+ * advanced to a tab boundary output the tab and reset the count of spaces.
+ */
+
+ while ((*pSrc == ' ') || (*pSrc == '\t')) {
+ if (*pSrc == '\t') {
+ cSpaces = 0;
+ column += tab - (column % tab);
+ *pDst++ = '\t';
+ } else {
+ cSpaces++;
+ column++;
+ if ((column % tab) == 0) {
+ *pDst++ = (char)((cSpaces != 1) ? '\t' : ' ');
+ cSpaces = 0;
+ }
+ }
+ pSrc++;
+ }
+
+ /*
+ * non-space found. Output remainder of spaces
+ */
+ while (cSpaces--) {
+ *pDst++ = ' ';
+ }
+ }
+
+ /*
+ * determine what state we are in
+ */
+ if (!fQuote) {
+ if (!fEscape) {
+
+ /*
+ * if we are not quoting and we are not escaping, check for quoted strings and
+ * escaped characters.
+ */
+ if (*pSrc == '"' || *pSrc == '\'') {
+ cQuote = *pSrc;
+ fQuote = TRUE;
+ } else if (*pSrc == '\\') {
+ fEscape = TRUE;
+ }
+ } else {
+ //
+ // We are not quoting. If we are escaping, reset escape.
+ fEscape = FALSE;
+ }
+ } else if (!fEscape) {
+ //
+ // In a quote, not escaping, check for end of quote, or
+ // beginning of escape
+ //
+ if (*pSrc == cQuote) {
+ fQuote = FALSE;
+ } else if (*pSrc == '\\') {
+ fEscape = TRUE;
+ }
+ } else {
+ //
+ // Inside quote and inside escape, just reset escape mode
+ //
+ fEscape = FALSE;
+ }
+
+ /*
+ * Finally, output the character
+ */
+ if (*pSrc) {
+ *pDst++ = *pSrc++;
+ column++;
+ }
+ }
+
+ /*
+ * terminate the destination string, and return
+ */
+ *pDst = 0;
+ return pDst-dst;
+}
+
+
+
+
+
+/*** TabMax - tabify line regardless of content
+*
+* Input:
+* tab = tab stops to entab to
+* src = source buffer
+* dst = destination buffer
+*
+* Output:
+* Returns physical length of buffer
+*
+*************************************************************************/
+int
+TabMax (
+ int tab,
+ char *src,
+ char *dst
+ )
+{
+
+ int column = 0; /* current column offset */
+ unsigned cSpaces; /* count of spaces in run */
+ REGISTER char *pDst = dst; /* moving ptr into dest */
+ REGISTER char *pSrc = src; /* moving ptr into source */
+
+ /*
+ * while there are characters to output
+ */
+ while (*pSrc) {
+ cSpaces = 0;
+
+ /*
+ * coallesce runs of spaces while there are spaces to coallesce
+ */
+ while ((*pSrc == ' ') || (*pSrc == '\t')) {
+ if (*pSrc == '\t') {
+ cSpaces = 0;
+ column += tab - (column % tab);
+ *pDst++ = '\t';
+ } else {
+ cSpaces++;
+ column++;
+
+ /*
+ * if we have advanced to a tab boundary output a tab & reset the count of
+ * spaces
+ */
+ if ((column % tab) == 0) {
+ *pDst++ = (char)((cSpaces != 1) ? '\t' : ' ');
+ cSpaces = 0;
+ }
+ }
+ pSrc++;
+ }
+
+ /*
+ * output remainder of spaces
+ */
+ while (cSpaces--) {
+ *pDst++ = ' ';
+ }
+
+ /*
+ * Finally copy the character
+ */
+ if (*pSrc) {
+ *pDst++ = *pSrc++;
+ column++;
+ }
+ }
+
+ *pDst = 0;
+ return pDst-dst;
+}
+
+
+
+
+/*** SetTabDisp - tabdisp switch setting function
+*
+* set character displayed for tabs to a new character
+*
+* Input:
+* Standard switch setting routine: ptr to string
+*
+* Output:
+* Returns TRUE
+*
+*************************************************************************/
+flagType
+SetTabDisp (
+ char * val
+ )
+{
+ char NewVal;
+
+ if ((NewVal = (char)atoi(val)) == 0) {
+ NewVal = ' ';
+ }
+
+ tabDisp = NewVal;
+ newscreen ();
+
+ return TRUE;
+
+}
diff --git a/private/utils/mep/src/table.c b/private/utils/mep/src/table.c
new file mode 100644
index 000000000..a64553f34
--- /dev/null
+++ b/private/utils/mep/src/table.c
@@ -0,0 +1,315 @@
+/*** table.c - function tables for editor
+*
+* Modifications:
+*
+* 26-Nov-1991 mz Strip off near/far
+*
+* IMPORTANT: cmdTable and swiTable MUST be sorted according to name of the
+* command/switch. The table searching logic in ASSIGN.C will break otherwise.
+*
+* IMPORTANT: The names in cmdTable and SwiTable MUST be in lower case.
+*************************************************************************/
+
+#include "mep.h"
+
+
+// #define toPIF(x) (PIF)(long)(void *)&x
+
+/* short form to allow compact table description
+ */
+#define ANO NOARG
+#define ATXT TEXTARG
+#define ANUL NULLARG
+#define ALIN LINEARG
+#define ASTR STREAMARG
+#define ABOX BOXARG
+#define ANUM NUMARG
+#define AMRK MARKARG
+
+#define AEOL NULLEOL
+#define AEOW NULLEOW
+#define ABST BOXSTR
+#define FK FASTKEY
+
+#define MD MODIFIES
+#define KM KEEPMETA
+#define WFN WINDOWFUNC
+#define CFN CURSORFUNC
+
+/* names of internal editor functions
+ *
+ * Each function has a definition of how arguments are to be processed.
+ * This definition is comprised of a bitmap describing which arguments are
+ * legal and, if so, how they are to be interpreted. The definitions are:
+ *
+ *
+ * MODIFIES MD The function will modify the contents of the file being
+ * editted.
+ *
+ * KEEPMETA KM The function being executed does not take the <meta>
+ * prefix. The state of the <meta> flag is preserved
+ * across this editor function.
+ *
+ * CURSORFUNC CFN The function being executed is a cursor movement
+ * function. It is allowed within the context of
+ * an <arg> to select a file range on the screen; it
+ * cannot take an <arg>. It does not remove highlighting
+ * that is present on the screen.
+ *
+ * WINDOWFUNC WFN The function being executed is a window movement
+ * function. It does not remove highlighting that is
+ * present on the screen.
+ *
+ * NOARG ANO The function accepts the absence of an <arg> function.
+ * When called the function receives a pointer to a
+ * structure containing the location where the function
+ * is expected to be applied.
+ *
+ * TEXTARG ATXT The function accepts a textual argument that may
+ * be typed in or selected on the screen. The function is
+ * called with a pointer to the asciz text of the
+ * argument. See NULLEOL, NULLEOW, BOXSTR.
+ *
+ * NULLARG ANUL The function accepts an <arg> with no discernable
+ * cursor movement (cursor is on <arg> position). The
+ * function is called with a pointer to a structure
+ * containing the location of the arg within the file.
+ *
+ * NULLEOL AEOL The function accepts an <arg> with no discernable
+ * cursor movement (cursor is on <arg> position). The
+ * function is called with a pointer to a structure
+ * indicating TEXTARG and containing a pointer to the
+ * asciz text of the line from the cursor to end-of-line.
+ *
+ * NULLEOW AEOW The function accepts an <arg> with no discernable
+ * cursor movement (cursor is on <arg> position). The
+ * function is called with a pointer to a structure
+ * indicating TEXTARG and containing a pointer to the
+ * asciz text of the line from the cursor to the next
+ * whitespace.
+ *
+ * LINEARG ALIN The function accepts an <arg> that is in the same
+ * column as the cursor. The function is expected to be
+ * applied to all lines beginning in the range <arg> to
+ * cursor inclusive. The function is called with a
+ * pointer to a structure containing the beginning
+ * line of the range and the ending line of the range
+ *
+ * STREAMARG ASTR The function accepts an <arg> that is considered to
+ * apply beginning at a specific file location and
+ * proceeding through all intervening lines and line-
+ * breaks up until just to the left of the ending file
+ * position. The function is called with a pointer to
+ * a structure containing the beginning point of the range
+ * and the first point just beyond the end of the range.
+ *
+ * BOXARG ABOX The function accepts an <arg> that is considered to
+ * apply to a rectangle on the screen. The function is
+ * called with a pointer to a structure containing the
+ * left and right column boundaries (inclusive) and the
+ * top and bottom line numbers (inclusive) that describe
+ * the region.
+ *
+ * BOXSTR ABST If a BOXARG is presented to the function and the box
+ * contains only a single line, the function is called
+ * with a pointer to a structure marked TEXTARG and
+ * containing a pointer to the selection as an asciz
+ * string.
+ *
+ * NUMARG ANUM If text was specified and is numeric, it is considered
+ * to represent a number of lines offset from the cursor
+ * and represents the other end of an arg. The
+ * above tests are then applied, excluding TEXTARG.
+ *
+ * MARKARG AMRK If text was specified and interpreted as a mark, it is
+ * considered to be the other end of an arg. The above
+ * tests are then applied, excluding TEXTARG.
+ *
+ * FASTKEY FK The command will be repeated while the user holds down
+ * the invoking key.
+ */
+
+struct cmdDesc cmdTable[] = {
+/* 0|KM|CFN|WFN|ANO|ATXT|ANUL|AEOL|AEOW|ALIN|ASTR|ABOX|ABST|ANUM|AMRK|MD|FK*/
+{"arg", doarg, 0,0|KM },
+{"assign", assign, 0,0 |ANO|ATXT |AEOL |ALIN |ABOX|ABST|ANUM|AMRK },
+{"backtab", backtab, 0,0 |CFN },
+{"begfile", begfile, 0,0 |CFN },
+{"begline", begline, 0,0 |CFN },
+{"boxstream", BoxStream, 0,0 |CFN },
+{"cancel", cancel, 0,0 |ANO|ATXT|ANUL |ALIN|ASTR|ABOX },
+{"cdelete", cdelete, 0,0 |CFN |MD },
+{"compile", compile, 0,0 |ANO|ATXT|ANUL |ABST },
+{"copy", zpick, 0,0 |ANO|ATXT |AEOL |ALIN|ASTR|ABOX |ANUM|AMRK },
+{"curdate", curdate, 0,0 |ANO |MD },
+{"curday", curday, 0,0 |ANO |MD },
+{"curtime", curtime, 0,0 |ANO |MD },
+{"delete", delete, 0,0 |ANO |ANUL |ALIN|ASTR|ABOX |MD },
+{"down", down, 0,0 |CFN |FK},
+{"emacscdel", emacscdel, 0,0 |ANO |MD },
+{"emacsnewl", emacsnewl, 0,0 |ANO |MD },
+{"endfile", endfile, 0,0 |CFN },
+{"endline", endline, 0,0 |CFN },
+{"environment",environment,0,0 |ANO|ATXT|ANUL |ALIN |ABOX },
+{"execute", zexecute, 0,0 |ATXT |AEOL |ALIN |ABST|ANUM },
+{"exit", zexit, 0,0 |ANO |ANUL },
+{"graphic", graphic, 0,0 |ANO |ALIN|ASTR|ABOX |MD },
+{"home", home, 0,0 |CFN },
+{"information",information,0,0 |ANO },
+{"initialize", zinit, 0,0 |ANO|ATXT |AEOW |ABST },
+{"insert", insert, 0,0 |ANO |ANUL |ALIN|ASTR|ABOX |MD },
+{"insertmode", insertmode, 0,0 |ANO },
+{"lastselect", lastselect, 0,0|KM |ANO },
+{"lasttext", lasttext, 0,0|KM |ANO |ANUL |ALIN|ASTR|ABOX },
+{"ldelete", ldelete, 0,0 |ANO |ANUL |ALIN|ASTR|ABOX |ANUM|AMRK|MD },
+{"left", left, 0,0 |CFN |FK},
+{"linsert", linsert, 0,0 |ANO |ANUL |ALIN|ASTR|ABOX |ANUM|AMRK|MD },
+{"mark", mark, 0,0 |ANO|ATXT|ANUL |ABST },
+{"message", zmessage, 0,0 |ANO|ATXT|ANUL |ALIN|ASTR|ABOX },
+{"meta", meta, 0,0|KM },
+{"mgrep", mgrep, 0,0 |ANO|ATXT |AEOW |ABST },
+{"mlines", mlines, 0,0 |WFN|ANO|ATXT|ANUL |FK},
+{"mpage", mpage, 0,0 |CFN |FK},
+{"mpara", mpara, 0,0 |CFN |FK},
+{"mreplace", mreplace, 0,0 |ANO |ANUL |MD },
+{"msearch", msearch, 0,0 |ANO|ATXT |AEOW |ABST },
+{"mword", mword, 0,0 |CFN |FK},
+{"newline", newline, 0,0 |CFN },
+{"nextmsg", nextmsg, 0,0 |ANO|ATXT|ANUL },
+{"noedit", noedit, 0,0 |CFN },
+{"noop", noop, 0,0 |ANO |ALIN|ASTR|ABOX |MD },
+{"paste", put, 0,0 |ANO|ATXT |AEOL |ALIN|ASTR|ABOX |MD },
+{"pbal", pbal, 0,0 |ANO |ANUL |MD },
+{"plines", plines, 0,0 |WFN|ANO|ATXT|ANUL |FK},
+{"ppage", ppage, 0,0 |CFN |FK},
+{"ppara", ppara, 0,0 |CFN |FK},
+{"print", zPrint, 0,0 |ANO|ATXT |ALIN|ASTR|ABOX },
+{"prompt", promptarg, 0,0|KM |ANO|ATXT |ALIN|ASTR|ABOX },
+{"psearch", psearch, 0,0 |ANO|ATXT |AEOW |ABST },
+{"pword", pword, 0,0 |CFN |FK},
+{"qreplace", qreplace, 0,0 |ANO |ANUL |ALIN|ASTR|ABOX |ANUM|AMRK|MD },
+{"quote", quote, 0,0 |ANO |ALIN|ASTR|ABOX |MD },
+{"record", record, 0,0 |ANO|ATXT|ANUL },
+{"refresh", refresh, 0,0 |ANO |ANUL },
+{"repeat", repeat, 0,0 |ANO },
+{"replace", zreplace, 0,0 |ANO |ANUL |ALIN|ASTR|ABOX |ANUM|AMRK|MD },
+{"restcur", restcur, 0,0 |ANO },
+{"right", right, 0,0 |CFN |FK},
+{"saveall", saveall, 0,0 |ANO },
+{"savecur", savecur, 0,0 |ANO },
+{"savetmpfile", savetmpfile, 0,0 |ANO },
+{"sdelete", sdelete, 0,0 |ANO |ANUL |ALIN|ASTR|ABOX |MD },
+{"searchall", searchall, 0,0 |ANO|ATXT |AEOW |ABST },
+{"setfile", setfile, 0,0 |ANO|ATXT|ANUL |ABST },
+{"setwindow", setwindow, 0,0 |ANO |ANUL },
+{"shell", zspawn, 0,0 |ANO|ATXT |AEOL |ALIN |ABOX },
+{"sinsert", sinsert, 0,0 |ANO |ANUL |ALIN|ASTR|ABOX |MD },
+{"tab", tab, 0,0 |CFN },
+{"tell", ztell, 0,0 |ANO|ATXT|ANUL },
+{"unassigned", unassigned, 0,0 |ANO|ATXT|ANUL |ALIN|ASTR|ABOX },
+{"undo", zundo, 0,0 |ANO },
+{"up", up, 0,0 |CFN |FK},
+{"window", window, 0,0 |ANO |ANUL },
+{NULL, NULL, 0,0 }
+ };
+
+
+
+/* names of switches */
+struct swiDesc swiTable[] = {
+ { "askexit", toPIF(fAskExit), SWI_BOOLEAN },
+ { "askrtn", toPIF(fAskRtn), SWI_BOOLEAN },
+ { "autosave", toPIF(fAutoSave), SWI_BOOLEAN },
+ { "backup", (PIF)SetBackup, SWI_SPECIAL2 },
+ { "case", toPIF(fSrchCaseSwit), SWI_BOOLEAN },
+ { "cursorsize", (PIF)SetCursorSizeSw, SWI_SPECIAL2 },
+#if DEBUG
+ { "debug", toPIF(debug), SWI_NUMERIC | RADIX10},
+#endif
+ { "displaycursor", toPIF(fDisplayCursorLoc), SWI_BOOLEAN },
+ { "editreadonly", toPIF(fEditRO), SWI_BOOLEAN },
+ { "entab", toPIF(EnTab), SWI_NUMERIC | RADIX10},
+ { "enterboxmode", toPIF(fBoxArg), SWI_BOOLEAN },
+ { "enterinsmode", toPIF(fInsert), SWI_BOOLEAN },
+ { "errcolor", toPIF(errColor), SWI_NUMERIC | RADIX16},
+ { "errprompt", toPIF(fErrPrompt), SWI_BOOLEAN },
+ { "extmake", (PIF)SetExt, SWI_SPECIAL2 },
+ { "fgcolor", toPIF(fgColor), SWI_NUMERIC | RADIX16},
+ { "filetab", (PIF)SetFileTab, SWI_SPECIAL2 },
+ { "height", toPIF(YSIZE), SWI_SCREEN },
+ { "hgcolor", toPIF(hgColor), SWI_NUMERIC | RADIX16},
+ { "hike", toPIF(hike), SWI_NUMERIC | RADIX10},
+ { "hscroll", toPIF(hscroll), SWI_NUMERIC | RADIX10},
+ { "infcolor", toPIF(infColor), SWI_NUMERIC | RADIX16},
+ { "keyboard", (PIF)SetKeyboard, SWI_SPECIAL },
+ { "load", (PIF)SetLoad, SWI_SPECIAL2 },
+ { "markfile", (PIF)SetMarkFile, SWI_SPECIAL2 },
+ { "msgflush", toPIF(fMsgflush), SWI_BOOLEAN },
+ { "noise", toPIF(cNoise), SWI_NUMERIC | RADIX10},
+ { "printcmd", SetPrintCmd, SWI_SPECIAL },
+ { "readonly", SetROnly, SWI_SPECIAL },
+ { "realtabs", toPIF(fRealTabs), SWI_BOOLEAN },
+ { "rmargin", toPIF(xMargin), SWI_NUMERIC | RADIX10},
+ { "savescreen", toPIF(fSaveScreen), SWI_BOOLEAN },
+ { "searchwrap", toPIF(fSrchWrapSwit), SWI_BOOLEAN },
+ { "selcolor", toPIF(selColor), SWI_NUMERIC | RADIX16},
+ { "shortnames", toPIF(fShortNames), SWI_BOOLEAN },
+ { "snow", toPIF(fCgaSnow), SWI_BOOLEAN },
+ { "softcr", toPIF(fSoftCR), SWI_BOOLEAN },
+ { "stacolor", toPIF(staColor), SWI_NUMERIC | RADIX16},
+ { "tabalign", toPIF(fTabAlign), SWI_BOOLEAN },
+ { "tabdisp", SetTabDisp, SWI_SPECIAL },
+ { "tabstops", toPIF(tabstops), SWI_NUMERIC | RADIX10},
+ { "tmpsav", toPIF(tmpsav), SWI_NUMERIC | RADIX10},
+ { "traildisp", SetTrailDisp, SWI_SPECIAL },
+ { "trailspace", toPIF(fTrailSpace), SWI_BOOLEAN },
+ { "undelcount", toPIF(cUndelCount), SWI_NUMERIC | RADIX10},
+ { "undocount", toPIF(cUndo), SWI_NUMERIC | RADIX10},
+ { "unixre", toPIF(fUnixRE), SWI_BOOLEAN },
+ { "usemouse", toPIF(fUseMouse), SWI_BOOLEAN },
+ { "viewonly", toPIF(fGlobalRO), SWI_BOOLEAN },
+ { "vscroll", toPIF(vscroll), SWI_NUMERIC | RADIX10},
+ { "wdcolor", toPIF(wdColor), SWI_NUMERIC | RADIX16},
+ { "width", toPIF(XSIZE), SWI_SCREEN },
+ { "wordwrap", toPIF(fWordWrap), SWI_BOOLEAN },
+ { NULL, NULL, 0 }
+ };
+/* c keyword table for softcr routine */
+char * cftab[] = {
+ "if" ,
+ "else" ,
+ "for" ,
+ "while" ,
+ "do" ,
+ "case" ,
+ "default" ,
+ NULL
+ };
+
+/* file type table. Z identifies files by their extention. Many extentions
+ * can be a single type. The soft tabbing algorithms and the compile commands
+ * are driven by this mechanism.
+ */
+struct fTypeInfo ftypetbl[] = {
+ { "c", CFILE },
+ { "h", CFILE },
+ { "asm", ASMFILE },
+ { "inc", ASMFILE },
+ { "pas", PASFILE },
+ { "for", FORFILE },
+ { "lsp", LSPFILE },
+ { "bas", BASFILE },
+ { NULL, TEXTFILE }
+ };
+
+/* mpTypepName - pointers to the textual names of each type
+ */
+char * mpTypepName[] =
+ { "text", /* #define TEXTFILE 0 */
+ "C", /* #define CFILE 1 */
+ "macro", /* #define ASMFILE 2 */
+ "pascal", /* #define PASFILE 3 */
+ "fortran", /* #define FORFILE 4 */
+ "lisp", /* #define LSPFILE 5 */
+ "BASIC" /* #define BASFILE 6 */
+ };
diff --git a/private/utils/mep/src/textline.c b/private/utils/mep/src/textline.c
new file mode 100644
index 000000000..08296ef62
--- /dev/null
+++ b/private/utils/mep/src/textline.c
@@ -0,0 +1,2427 @@
+/*** textline.c - basic line manipulators for editor
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Edit-level to file-level interface.
+*
+* The internal representation of a file is that of an array of line records
+* with each line record containing a pointer to the text of the line and a
+* length of that line. The line array is pointed to by the plr field of
+* the file descriptor. The lSize field is the MAXIMUM number of lines that
+* the line array can hold and the cLines is the number of lines actually
+* present. Here are some assumptions:
+*
+* plr = NULL => no line array allocated
+* lineRec.vaLine = -1L => 0-length line
+*
+* Tabs: functions and characters.
+*
+* The tab function is a cursor movement command, and responds to the
+* "tabstops" editor switch. It has NO RELATIONSHIP to physical tab
+* characters, and how tab characters are treated or placed in the text file.
+*
+* Tab characters, their interpretation and placement in editted text, is
+* controlled by three switchs:
+*
+* Switch Editor Var Meaning
+* ----------- --------------- -------
+* filetab:
+* entab:
+* realtabs: fRealTabs TRUE => Tab characters are NOT treated as
+* runs of spaces for editting purposes. They
+* are defined as having variable (1-8)
+* multi-column width.
+* FALSE => Tabs characters in text are treated
+* as runs of spaces.
+*
+* Revision History:
+*
+* 26-Nov-1991 mz Strip near/far
+*************************************************************************/
+#include "mep.h"
+#include <stdarg.h>
+
+#define DELTA 400
+
+//
+// BugBug Compiler asserts generating intrinsic code for memset
+//
+#pragma function( memset )
+
+/*** LineLength - returns length of a specific line
+*
+* Input:
+* line = 0-based line number in file
+* pFile = pointer to file
+*
+* Output:
+* Returns the logical number of characters, after tab expansion
+*
+*************************************************************************/
+int
+LineLength (
+ LINE line,
+ PFILE pFile
+ )
+{
+ linebuf tmpbuf;
+
+ return GetLineUntabed (line, tmpbuf, pFile);
+}
+
+
+
+
+/*** GetLine - gets a line into a particular buffer.
+*
+* If "fReal-Tabs" is NOT set, the line has all tabs expanded into spaces.
+* No CR/LF is present.
+*
+* Input:
+* line = 0-based line number in file to return. Lines beyond EOF
+* are simply empty.
+* buf = destination of line.
+* pFile = pointer to the file structure from which the line is to be
+* retrieved.
+*
+* Output:
+* Returns the number of characters in the line.
+*
+*************************************************************************/
+int
+GetLine (
+ LINE line,
+ char *buf,
+ PFILE pFile
+ )
+{
+ return gettextline (fRealTabs, line, buf, pFile, ' ');
+}
+
+
+
+
+
+/*** GetLineUntabed - gets a line into a particular buffer, always untabed.
+*
+* The line has all tabs expanded into spaces.
+* No CR/LF is present.
+*
+* Input:
+* line = 0-based line number in file to return. Lines beyond EOF
+* are simply empty.
+* buf = destination of line.
+* pFile = pointer to the file structure from which the line is to be
+* retrieved.
+*
+* Output:
+* Returns the number of characters in the line.
+*
+*************************************************************************/
+int
+GetLineUntabed (
+ LINE line,
+ char *buf,
+ PFILE pFile
+ )
+{
+ return gettextline (FALSE, line, buf, pFile, ' ');
+}
+
+
+
+
+
+/****************************************************************************
+ * *
+ * GetColor (line, buf, pFile) *
+ * *
+ * line - 0-based line number in file to get color info for. *
+ * buf - Place to put copy of line color info. *
+ * pFile- File to retrieve info from. *
+ * *
+ * RETURNS: *
+ * *
+ * TRUE if there is color attached to this line, FALSE otherwise. *
+ * *
+ * DESCRIPTION: *
+ * *
+ * Gets the color array associated with given line in the given file. *
+ * The color array can be used by the cout routines to display the *
+ * line in different colors. *
+ * *
+ ****************************************************************************/
+flagType
+GetColor (
+ LINE line,
+ struct lineAttr * buf,
+ PFILE pFile
+ )
+{
+ return (flagType)getcolorline (fRealTabs, line, buf, pFile);
+}
+
+
+
+
+/*** GetColorUntabbed - Get color with "untabbing"
+*
+* Purpose:
+*
+* Input:
+*
+* Output:
+*
+* Returns
+*
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+flagType
+GetColorUntabbed (
+ LINE line,
+ struct lineAttr * buf,
+ PFILE pFile
+ )
+{
+ return (flagType)getcolorline (FALSE, line, buf, pFile);
+}
+
+
+
+/*** getcolorline
+*
+* Purpose:
+*
+* Input:
+*
+* Output:
+*
+* Returns
+*
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+int
+getcolorline (
+ flagType fRaw,
+ LINE line,
+ struct lineAttr * buf,
+ PFILE pFile
+ )
+{
+ struct colorRecType *vColor;
+ linebuf lbuf;
+
+ //
+ // Set default colors, in case there is no color for this line.
+ //
+ buf->len = 0xff;
+ buf->attr = FGCOLOR;
+
+ if ((pFile->vaColor == (PVOID)(-1L)) || (line >= pFile->cLines)) {
+ return FALSE;
+ }
+
+ vColor = VACOLOR(line);
+
+ if (vColor->vaColors == (PVOID)(-1L)) {
+ return FALSE;
+ }
+
+ memmove((char *)buf, vColor->vaColors, vColor->cbColors);
+
+ if (!fRaw) {
+ if (gettextline (TRUE, line, lbuf, pFile, ' ')) {
+ ColorToLog (buf, lbuf);
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+
+
+
+/****************************************************************************
+ * *
+ * PutColor (line, buf, pFile) *
+ * *
+ * line - 0-based line number in file to attach color to. *
+ * buf - Color array. *
+ * pFile- File to attach to. *
+ * *
+ * DESCRIPTION: *
+ * *
+ * Copies the contents of buf into VM space and attaches it to the *
+ * given line. If no colorRecType array exists, one is allocated. *
+ * If color for the given line already exists, it is discarded. *
+ * *
+ ****************************************************************************/
+void
+PutColor (
+ LINE line,
+ struct lineAttr * buf,
+ PFILE pFile
+ )
+{
+ putcolorline (FALSE, line, buf, pFile);
+}
+
+
+
+
+
+/*** PutColorPhys
+*
+* Purpose:
+*
+* Input:
+*
+* Output:
+*
+* Returns
+*
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+void
+PutColorPhys (
+ LINE line,
+ struct lineAttr * buf,
+ PFILE pFile
+ )
+{
+ putcolorline (TRUE, line, buf, pFile);
+}
+
+
+
+
+/*** putcolorline
+*
+* Purpose:
+*
+* Input:
+*
+* Output:
+*
+* Returns
+*
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+void
+putcolorline (
+ flagType fRaw,
+ LINE line,
+ struct lineAttr * buf,
+ PFILE pFile
+ )
+{
+ struct colorRecType vColor;
+ struct colorRecType *Color;
+ int cbBuf;
+ long l;
+ PBYTE vaColor;
+
+ //
+ // Ignore color for lines which don't exist.
+ //
+ if (line >= pFile->cLines) {
+ return;
+ }
+
+ //
+ // Make sure we have a color array. If it doesn't exist, allocate one for the
+ // number of lines we have so far. Initialize the entries therein to no color.
+ //
+ redraw (pFile, line, line);
+ if (pFile->vaColor == (PVOID)(-1L)) {
+ pFile->vaColor = MALLOC (pFile->lSize * sizeof(vColor));
+ if ( !pFile->vaColor ) {
+ disperr(MSGERR_NOMEM);
+ disperr(MSGERR_QUIT);
+ CleanExit(4,FALSE);
+ }
+ vColor.vaColors = (PVOID)(-1L);
+ vColor.cbColors = 0;
+ vaColor = (PBYTE)pFile->vaColor;
+ for (l=0; l<pFile->lSize; l++) {
+ memmove(vaColor, (char *)&vColor, sizeof(vColor));
+ vaColor += sizeof (vColor);
+ }
+ }
+
+ //
+ // Now throw away the current color info for the line in question, allocate
+ // new VM for the new information, then place the color info into VM, and
+ // update the VA info in the color array.
+ //
+ Color = VACOLOR(line);
+ if (Color->vaColors != (PVOID)(-1L)) {
+ FREE (Color->vaColors);
+ }
+ if (!fRaw) {
+ ColorToPhys (buf, line, pFile);
+ }
+ cbBuf = fcolcpy (NULL, (struct lineAttr *)buf) << 2;
+ Color->vaColors = MALLOC ((long)cbBuf);
+ if ( !Color->vaColors ) {
+ disperr(MSGERR_NOMEM);
+ disperr(MSGERR_QUIT);
+ CleanExit(4,FALSE);
+ }
+ Color->cbColors = cbBuf;
+ memmove(Color->vaColors, (char *)buf, cbBuf);
+}
+
+
+
+
+
+/*** DelColor - Remove color from a line
+*
+* Purpose:
+*
+* To free the color attached to a file line.
+*
+* Input:
+* line - Line to free
+* pFile- File with the color
+*
+* Output: None
+*
+*************************************************************************/
+void
+DelColor (
+ LINE line,
+ PFILE pFile
+ )
+{
+ struct colorRecType *vColor;
+
+ if (pFile->vaColor != (PVOID)-1L) {
+
+ vColor = VACOLOR(line);
+ if (vColor->vaColors != (PVOID)-1L) {
+ FREE(vColor->vaColors);
+ vColor->vaColors = (PVOID)-1L;
+ }
+ }
+}
+
+
+
+
+
+/*** gettextline - gets a line into a particular buffer.
+*
+* Input:
+* fRaw = TRUE => the line is returned unmodified, otherwise tabs are
+* expanded according to fileTab.
+* line = 0-based line number in file to return. Lines beyond EOF
+* are simply empty.
+* buf = destination of line.
+* pFile = pointer to the file structure from which the line is to be
+* retrieved.
+* bTab = character used for tab expansion
+*
+* Output:
+* Returns the number of characters in the line.
+*
+*************************************************************************/
+int
+gettextline (
+ flagType fRaw,
+ LINE line,
+ char *buf,
+ PFILE pFile,
+ char bTab
+ )
+{
+ LINEREC *vLine;
+ linebuf getbuf;
+ REGISTER char *p = fRaw ? buf : getbuf;
+ int cbLine;
+
+ if (pFile->cLines <= line) {
+ return buf[0] = 0;
+ }
+
+ /*
+ * get line record
+ */
+ vLine = VALINE(line);
+
+ if (vLine->vaLine == (PVOID)(-1L)) {
+ return buf[0] = 0;
+ }
+
+ cbLine = min (sizeof(linebuf)-1, vLine->cbLine);
+
+ /*
+ * get line
+ */
+ // BUGBUG remove
+ // memmove(p, vLine->vaLine == (PVOID)-1 ? (PVOID)(-(ULONG)vLine->vaLine) : vLine->vaLine, cbLine);
+
+ memmove(p, vLine->vaLine, cbLine );
+ p[cbLine] = 0;
+
+ if (!fRaw) {
+ return Untab (fileTab, p, strlen(p), buf, bTab);
+ } else {
+ return cbLine;
+ }
+}
+
+
+
+/* PutLine - put a buffer into the file. No CR/LF is present in the input
+ * line. Grow the file if need be.
+ *
+ * line 0-based line number in file to replace. Growth of the file
+ * inserts blank lines.
+ * buf source of line.
+ * pFile pointer to the file structure into which the line is to be
+ * place.
+ */
+void
+PutLine (
+ LINE line,
+ char *buf,
+ REGISTER PFILE pFile
+ )
+{
+ puttextline (FALSE, TRUE, line, buf, pFile);
+}
+
+
+
+
+/*** InsertLine - insert a buffer into the file.
+*
+* Like PutLine, except inserts the line immediately prior to the specified
+* line. Grows the file.
+*
+* Input:
+* line = 0-based line number in file to insert before.
+* buf = source of line.
+* pFile = pointer to the file structure into which the line is to be
+* placed.
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void
+InsertLine (
+ LINE line,
+ char *buf,
+ REGISTER PFILE pFile
+ )
+{
+ InsLine (TRUE, line, 1L, pFile);
+ puttextline (FALSE, TRUE, line, buf, pFile);
+}
+
+
+
+
+/*** zprintf - insert formatted text into file being editted
+*
+* Like fprintf, except that it inserts it's output into a file being
+* editted. "\n"'s in the text cause a line break, and insert multiple
+* lines. Examples:
+*
+* zprintf (pFile, line, "this is a number %d", num);
+*
+* Inserts a new line in front of line number "line" with the new text.
+*
+* zprintf (pFile, line, "this is \na number %d\n", num);
+*
+* Inserts three lines: one containing "this is", the next containing "a
+* number", and the last blank.
+*
+* Input:
+* pFile = target file
+* lFirst = starting line number
+* fmt = formatting string
+* ... = args as per string
+*
+* Output:
+* Returns the line number of the last line written + 1.
+*
+*************************************************************************/
+LINE
+zprintf (
+ PFILE pFile,
+ LINE lFirst,
+ char const *fmt,
+ ...
+ )
+{
+ linebuf fbuf; /* buffer into which to format */
+ REGISTER char *pEnd; /* pointer into it */
+ REGISTER char *pStart; /* pointer to begining of line */
+ va_list Arguments;
+
+ /*
+ * Start by getting the formatted text
+ */
+ va_start(Arguments, fmt);
+ ZFormat (fbuf, fmt, Arguments);
+
+ /*
+ * for each substring in the file, insert the text
+ */
+ pStart = fbuf;
+ do {
+ if (pEnd = strchr(fbuf,'\n')) {
+ *pEnd = 0;
+ }
+ InsertLine (lFirst++, pStart, pFile);
+ pStart = pEnd+1;
+ } while (pEnd);
+ va_end(Arguments);
+ return lFirst;
+}
+
+
+
+
+
+/* puttextline - put a buffer into the file. No CR/LF is present in the input
+ * line. Grow the file if need be. Convert to tabbed representation based on
+ * flag
+ *
+ * fRaw TRUE => line is placed into memory unmodified, otherwise
+ * trailing spaces are eliminated (fTrailSpace) and spaces are
+ * converted to tabs.
+ * fLog TRUE => make this action undo-able.
+ * line 0-based line number in file to replace. Growth of the file
+ * inserts blank lines.
+ * buf source of line.
+ * pFile pointer to the file structure into which the line is to be
+ * place.
+ */
+void
+puttextline (
+ flagType fRaw,
+ flagType fLog,
+ LINE line,
+ char *buf,
+ REGISTER PFILE pFile
+ )
+{
+ static struct lineAttr rgla[sizeof(linebuf)];
+ LINEREC *vLine;
+ struct colorRecType vColor;
+ int newLen;
+ flagType fChange, fColor;
+ linebuf putbuf;
+ PVOID va;
+
+ redraw (pFile, line, line);
+ makedirty (pFile);
+
+ if (pFile->cLines <= line) {
+ growline (line+1, pFile);
+ pFile->cLines = line+1;
+ SETFLAG (fDisplay, RSTATUS);
+ } else {
+ if (pFile == pInsCur->pFile) {
+ AckReplace (line, FALSE);
+ }
+ }
+
+ /* get line record */
+ vLine = VALINE(line);
+
+ fChange = FALSE;
+ newLen = strlen (buf);
+
+ if (!fRaw) {
+ if (!fTrailSpace && pFile == pFileHead) {
+ newLen = RemoveTrailSpace (buf);
+ }
+ if (fRealTabs) {
+ fColor = (flagType)getcolorline (FALSE, line, rgla, pFile);
+ }
+
+ switch (EnTab) {
+
+ case 0:
+ break;
+
+ case 1:
+ newLen = TabMin (fileTab, buf, putbuf);
+ buf = putbuf;
+ break;
+
+ case 2:
+ newLen = TabMax (fileTab, buf, putbuf);
+ buf = putbuf;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /* We now have the real text that we'd like to replace in the file.
+ * If logging is requested then
+ * we log this replacement action
+ * else
+ * free the current line
+ * allocate a new line
+ * copy the line into the allocated line
+ * set the length
+ * replace line record
+ */
+
+ if (fLog) {
+ if (pFile->vaColor != (PVOID)(-1)) {
+ memmove((char *)&vColor, VACOLOR(line), sizeof(vColor));
+ if (vColor.vaColors != (PVOID)(-1L)) {
+ va = MALLOC ((long)vColor.cbColors);
+ if ( !va ) {
+ disperr(MSGERR_NOMEM);
+ disperr(MSGERR_QUIT);
+ CleanExit(4,FALSE);
+ }
+ memmove(va, vColor.vaColors, (long)vColor.cbColors);
+ vColor.vaColors = va;
+ }
+ } else {
+ vColor.vaColors = (PVOID)(-1L);
+ vColor.cbColors = 0;
+ }
+
+ LogReplace (pFile, line, vLine, &vColor);
+ } else if (vLine->Malloced) {
+ vLine->Malloced = FALSE;
+ FREE (vLine->vaLine);
+ }
+
+ if (newLen == 0) {
+ vLine->vaLine = (PVOID)(-1L);
+ vLine->Malloced = FALSE;
+ } else {
+ vLine->vaLine = MALLOC((long) newLen);
+ if ( !vLine->vaLine ) {
+ disperr(MSGERR_NOMEM);
+ disperr(MSGERR_QUIT);
+ CleanExit(4,FALSE);
+ }
+ vLine->Malloced = TRUE;
+ vLine->cbLine = newLen;
+
+ memmove(vLine->vaLine, buf, newLen);
+
+ }
+ if (fRealTabs && !fRaw && fColor) {
+ PutColor (line, rgla, pFile);
+ }
+}
+
+
+
+
+
+/* FileLength - return the number of lines in a file
+ *
+ * pFile handle of file
+ *
+ * returns number of lines in file
+ */
+LINE
+FileLength (
+ PFILE pFile
+ )
+{
+ return pFile->cLines;
+}
+
+
+
+
+
+/* BlankLines - blank a series of line records in a file's line structure.
+ * We can be either gross (fill in one at a time) or be reasonable (fill in
+ * fixed size blocks at a time, or be smart (fill a block then copy
+ * exponentially large blocks). We are smart.
+ *
+ * n number of line records to blank
+ * va virtual address of first line to blank
+ */
+void
+BlankLines (
+ LINE n,
+ PVOID va
+ )
+{
+
+ LINEREC vLine;
+ long copylen = (long) sizeof (vLine);
+ PBYTE dst = (PBYTE)va;
+ long amtleft = (long) sizeof (vLine) * n;
+ long amtdone = 0L;
+
+ vLine.vaLine = (PVOID)(-1L);
+ vLine.Malloced = FALSE;
+ vLine.cbLine = -1;
+
+ while (amtleft != 0L) {
+ if (amtdone == 0L) {
+ // Copy first blank line
+ memmove(dst, (char *)&vLine, (int) copylen);
+ } else {
+ // Copy bunch
+ copylen = amtleft < amtdone ? amtleft : amtdone;
+ memmove(dst, va, copylen);
+ }
+ dst += copylen;
+ amtleft -= copylen;
+ amtdone += copylen;
+ }
+}
+
+
+
+/* BlankColor - blank a series of color records in a file's line structure.
+ * We can be either gross (fill in one at a time) or be reasonable (fill in
+ * fixed size blocks at a time, or be smart (fill a block then copy
+ * exponentially large blocks). We are smart.
+ *
+ * n number of color records to blank
+ * va virtual address of first color to blank
+ */
+void
+BlankColor (
+ LINE n,
+ PVOID va
+ )
+{
+ struct colorRecType vColor;
+ long copylen = (long) sizeof (vColor);
+ PBYTE dst = (PBYTE)va;
+ long amtleft = (long) sizeof (vColor) * n;
+ long amtdone = 0L;
+
+ vColor.vaColors = (PVOID)(-1L);
+ vColor.cbColors = -1;
+ while (amtleft != 0L) {
+ if (amtdone == 0L) {
+ // Copy one
+ memmove(dst, (char *)&vColor, (int) copylen);
+ } else {
+ copylen = amtleft < amtdone ? amtleft : amtdone;
+ // Copy a bunch
+ memmove(dst, va, copylen);
+ }
+ dst += copylen;
+ amtleft -= copylen;
+ amtdone += copylen;
+ }
+}
+
+
+
+
+
+/* growLine - make a structure n lines long */
+void
+growline (
+ REGISTER LINE line,
+ REGISTER PFILE pFile
+ )
+{
+ long tmp1;
+ LINE lSize;
+ PBYTE vaTmp;
+ struct colorRecType vColor;
+
+ //
+ // IF the file has a color array, and if the requested growth is greater than
+ // the number of lines in the file, copy over the existing color array to
+ // larger VM, release the previous array, and initialize the "new" entries in
+ // that array.
+ //
+ if ((pFile->vaColor != (PVOID)(-1L)) && (pFile->lSize < line)) {
+ tmp1 = (lSize = line + DELTA) * (long) sizeof(vColor);
+ vaTmp = (PBYTE)MALLOC (tmp1);
+ if ( !vaTmp ) {
+ disperr(MSGERR_NOMEM);
+ disperr(MSGERR_QUIT);
+ CleanExit(4,FALSE);
+ }
+ memmove(vaTmp, pFile->vaColor, pFile->cLines * sizeof(vColor));
+ FREE (pFile->vaColor);
+ pFile->vaColor = (PVOID)vaTmp;
+ vColor.vaColors = (PVOID)(-1L);
+ vColor.cbColors = 0;
+ vaTmp += pFile->cLines * sizeof(vColor);
+ for (lSize = pFile->cLines; lSize < line+DELTA; lSize++) {
+ memmove(vaTmp, (char *)&vColor, sizeof(vColor));
+ vaTmp += sizeof(vColor);
+ }
+ }
+
+ //
+ // If there are no lines, or not enough lines allocated for, allocate a new
+ // line buffer which is larger than the request by DELTA lines (allows us to
+ // avoid this operation for every added line). If there were line records,
+ // move them into this new buffer, and free the old one. Blank out the added
+ // records.
+ //
+ if ((pFile->plr == NULL) || (pFile->lSize < line)) {
+ tmp1 = (lSize = line + DELTA) * (long) sizeof (LINEREC);
+ vaTmp = (PBYTE)MALLOC (tmp1);
+ if ( !vaTmp ) {
+ disperr(MSGERR_NOMEM);
+ disperr(MSGERR_QUIT);
+ CleanExit(4,FALSE);
+ }
+ if (pFile->plr != NULL) {
+ memmove(vaTmp, pFile->plr,
+ ((long)pFile->cLines) * sizeof (LINEREC));
+ FREE (pFile->plr);
+ }
+ pFile->lSize = lSize;
+ pFile->plr = (LINEREC *)vaTmp;
+ BlankLines (lSize - pFile->cLines, VALINE(pFile->cLines));
+ if (pFile->vaColor != (PVOID)(-1L)) {
+ BlankColor (lSize - pFile->cLines, VACOLOR(pFile->cLines));
+ }
+ }
+}
+
+
+
+
+/* DelLine - delete n lines from the file, starting at line n. Shrink what-
+ * ever structures are necessary.
+ *
+ * The line range yStart-yEnd is deleted inclusively.
+ *
+ *
+ * pFile file structure from which lines are deleted
+ * yStart beginning 0-based line number to be deleted
+ * yEnd ending line to be deleted
+ */
+void
+DelLine (
+ flagType fLog,
+ PFILE pFile,
+ LINE yStart,
+ LINE yEnd
+ )
+{
+ if (yStart >= pFile->cLines || yStart > yEnd) {
+ return;
+ }
+
+ redraw (pFile, yStart, pFile->cLines);
+ makedirty (pFile);
+
+ yEnd = lmin (yEnd, pFile->cLines-1);
+
+ /* if logging this delete operation is requested then
+ * Log the delete range
+ * else
+ * free up the data being deleted
+ */
+ if (fLog) {
+ LogDelete (pFile, yStart, yEnd);
+ }
+
+ /* block transfer the remainder of the file down
+ */
+ memmove(VALINE(yStart), VALINE(yEnd+1),
+ ((long)(pFile->cLines-yEnd-1))*sizeof(LINEREC));
+
+ /* Do the same for the color.
+ */
+ if (pFile->vaColor != (PVOID)(-1L)) {
+ memmove(VACOLOR(yStart), VACOLOR(yEnd+1),
+ ((long)(pFile->cLines-yEnd-1))*sizeof(struct colorRecType));
+ }
+
+ /* remove lines from count
+ */
+ pFile->cLines -= yEnd - yStart + 1;
+ SETFLAG (fDisplay, RSTATUS);
+
+ /* Clear out line records
+ */
+ BlankLines (yEnd - yStart + 1, VALINE (pFile->cLines));
+ if (pFile->vaColor != (PVOID)(-1L)) {
+ BlankColor (yEnd - yStart + 1, VACOLOR (pFile->cLines));
+ }
+
+ if (fLog) {
+ AdjustLines (pFile, yStart, yStart - yEnd - 1);
+ }
+
+ MarkDelStream (pFile, 0, yStart, sizeof(linebuf), yEnd);
+}
+
+
+
+
+
+/* DelFile - delete contents of file
+ *
+ * pFile file structure that is to be cleared
+ */
+void
+DelFile (
+ REGISTER PFILE pFile,
+ flagType fLog
+ )
+{
+ DelLine (fLog, pFile, (LINE)0, pFile->cLines - 1);
+ RSETFLAG (FLAGS(pFile), DIRTY);
+}
+
+
+
+
+
+/* InsLine - insert a block of blank lines into the file.
+ *
+ * line 0-based line before which the insertion will occur.
+ * n number of blank lines to insert
+ * pFile file structure for the operation
+ */
+void
+InsLine (
+ flagType fLog,
+ LINE line,
+ LINE n,
+ REGISTER PFILE pFile
+ )
+{
+ if (line >= pFile->cLines) {
+ return;
+ }
+ redraw (pFile, line, n+pFile->cLines);
+ makedirty (pFile);
+ if (fLog) {
+ LogInsert (pFile, line, n);
+ }
+ growline (pFile->cLines + n, pFile);
+ memmove(VALINE(line+n), VALINE(line),
+ (long)sizeof(LINEREC)*(pFile->cLines - line));
+ if (pFile->vaColor != (PVOID)(-1L)) {
+ memmove(VACOLOR(line+n), VACOLOR(line),
+ (long)sizeof(struct colorRecType)*(pFile->cLines - line));
+ BlankColor (n, VACOLOR(line));
+ }
+ BlankLines (n, VALINE(line));
+ pFile->cLines += n;
+ SETFLAG (fDisplay, RSTATUS);
+ if (fLog) {
+ AdjustLines (pFile, line, n);
+ }
+ MarkInsLine (line, n, pFile);
+}
+
+
+
+
+
+/*** fInsSpace - open up a space in a line.
+*
+* The line is retrieved and copied into buf and the appropriate number of
+* spaces are inserted. The line is NOT replaced in the file.
+*
+* Input:
+* x = 0-based logical column of insertion
+* y = 0-based line insertion
+* n = number of spaces to insert
+* pFile = file structure for the operation
+* buf = destination of line.
+*
+* Output:
+* Returns FALSE if line ended up too long (still copied, but truncated)
+*
+* Notes:
+*
+* Often called with n==0 for the following side effects:
+*
+* o Trailing spaces added up to column x.
+* o If column x is in a tab,
+* o Line truncated to sizeof linebuf.
+*
+* Otherwise GetLine is used.
+*
+*************************************************************************/
+flagType
+fInsSpace (
+ REGISTER COL x,
+ LINE y,
+ int n,
+ PFILE pFile,
+ linebuf buf
+ )
+{
+ return fInsSpaceColor (x, y, n, pFile, buf, NULL);
+}
+
+
+
+
+flagType
+fInsSpaceColor (
+ REGISTER COL x,
+ LINE y,
+ int n,
+ PFILE pFile,
+ linebuf buf,
+ struct lineAttr * pla
+ )
+{
+ int cbLine; /* logical length if line */
+ int cbMove; /* physical length to move */
+ int cbPhys; /* physical length of line */
+ int colPhys; /* Physical column x */
+ int i; /* temp */
+ flagType fRaw = TRUE; /* return value: init ok */
+
+ /*
+ * if the requested insertion is already too out, then truncate IT, and
+ * set return flag to indicate truncation.
+ */
+ if (x >= sizeof(linebuf)) {
+ x = sizeof(linebuf)-1;
+ fRaw = FALSE;
+ }
+
+ /*
+ * Read the line, get the logical length, and if needed, pad the line such
+ * that the logical length is x.
+ */
+ cbPhys = GetLine (y, buf, pFile);
+ cbLine = cbLog (buf);
+ if (cbLine < x) {
+ memset ((char *) buf+cbPhys, ' ', x-cbLine);
+ cbPhys += (x - cbLine);
+ buf[cbPhys] = 0;
+ cbLine = x;
+ assert (x == cbLog(buf));
+ }
+
+ /*
+ * In the case that the requested position is over a tab, we add spaces in
+ * front of the cursor position. We do this by adding the number of spaces
+ * between the requested column and the "aligned" column, and then aligning
+ * to that column.
+ */
+ i = AlignChar (x,buf);
+ n += x - i;
+ x = i;
+
+ /*
+ * open up a space of n chars at location x, moving the chars and NUL
+ * For overflow, we have two cases to consider:
+ * x + n + 1 > BUFLEN
+ * set n to be BUFLEN - 1 - x and continue
+ * cbLine + n + 1 > BUFLEN
+ * set cbLine to be BUFLEN - 1 - n and move the bytes
+ */
+ if (x + n + 1 > sizeof(linebuf)) {
+ n = sizeof(linebuf) - 1 - x;
+ fRaw = FALSE;
+ } else {
+ if (cbLine + n >= sizeof(linebuf)) {
+ cbLine = sizeof(linebuf) - 1 - n;
+ *pLog(buf,cbLine,TRUE) = 0;
+ cbPhys = strlen(buf);
+ fRaw = FALSE;
+ }
+ colPhys = pLog(buf,x,TRUE) - buf;
+ cbMove = cbPhys - colPhys + 1;
+ memmove ((char *) pLog(buf,x,FALSE)+n, (char *) pLog(buf,x,TRUE), cbMove);
+ if (pla) {
+ ShiftColor (pla, colPhys, n);
+ }
+ }
+ /*
+ * fill the new space with blanks
+ */
+ n += pLog(buf,x, FALSE) - pLog(buf,x, TRUE);
+ memset ((char *) pLog(buf,x, TRUE), ' ', n);
+ buf[sizeof(linebuf)-1] = 0;
+ return fRaw;
+}
+
+
+
+
+/*** delspace - delete text from a line
+*
+* The line is retrieved and copied into buf and the appropriate number of
+* characters are deleted. The line is NOT replaced in the file.
+*
+* Input:
+* xDel = 0-based logical column of deletion
+* yDel = 0-based line of deletion
+* cDel = logical number of spaces to delete
+* pFile = file structure for the operation
+* buf = buffer into which to place the resulting line
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void
+delspace (
+ COL xDel,
+ LINE yDel,
+ int cDel,
+ PFILE pFile,
+ linebuf buf
+ )
+{
+ int cDelPhys; /* count of bytes to remove from buff*/
+ int cLog; /* logical length of buffer */
+ REGISTER char *pDelPhys; /* pointer to physical deletion point*/
+
+ /*
+ * Get and compute the logical length of the line. We have work only if the
+ * logical length of the line is greater than (past) the logical deletion
+ * point.
+ */
+ GetLine (yDel, buf, pFile);
+ cLog = cbLog(buf);
+
+ if (cLog > xDel) {
+ /*
+ * Compute the physical deletion point (we use it a lot). If the end of the
+ * range to be deleted is beyond the actual end of the line, all we need do
+ * is truncate at the physical deletion point.
+ */
+ pDelPhys = pLog(buf,xDel,TRUE);
+ if (cLog <= xDel + cDel) {
+ *pDelPhys = 0;
+ } else if (cDel) {
+ /*
+ * Compute the physical length of bytes to be removed, and move the remaining
+ * portion of the line over that deleted.
+ */
+ cDelPhys = max ((pLog(buf,xDel+cDel,TRUE) - pDelPhys), 1);
+ memmove ((char*) pDelPhys,
+ (char*) pDelPhys + cDelPhys
+ , pLog(buf,cLog,TRUE) - pDelPhys - cDelPhys + 1);
+ }
+ }
+}
+
+
+
+
+
+/*** DelBox - delete a box from a file
+*
+* The box delimited by xLeft-xRight and yTop-yBottom is deleted inclusively.
+*
+* Input:
+* pFile = file to be modified
+* xLeft = column start of box
+* yTop = line start of box
+* xRight = column end of box
+* yBottom = line end of box
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void
+DelBox (
+ PFILE pFile,
+ REGISTER COL xLeft,
+ REGISTER LINE yTop,
+ COL xRight,
+ LINE yBottom
+ )
+{
+ linebuf buf;
+ struct lineAttr rgla[sizeof(linebuf)];
+ flagType fColor;
+ REGISTER int cCol = xRight - xLeft + 1;
+
+ MarkDelBox (pFile, xLeft, yTop, xRight, yBottom);
+ if (xLeft <= xRight) {
+ while (yTop <= yBottom) {
+ delspace (xLeft, yTop, cCol, pFile, buf);
+ if (fColor = GetColor (yTop, rgla, pFile)) {
+ ShiftColor (rgla, xRight, -cCol);
+ ColorToLog (rgla, buf);
+ }
+ PutLine (yTop++, buf, pFile);
+ if (fColor) {
+ PutColor (yTop-1, rgla, pFile);
+ }
+ }
+ }
+}
+
+
+
+
+
+/*** DelStream - delete a stream from a file
+*
+* The stream specified starting at (xStart,yStart) is deleted up through
+* the character before (xEnd, yEnd).
+*
+* Input:
+* pFile = file to be modified
+* xStart = column start of stream
+* yStart = line start of stream
+* xEnd = column end of stream
+* yEnd = line end of stream
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void
+DelStream (
+ PFILE pFile,
+ REGISTER COL xStart,
+ REGISTER LINE yStart,
+ COL xEnd,
+ LINE yEnd
+ )
+{
+ linebuf pbuf, sbuf;
+
+ CopyColor (pFile, pFile, yEnd, xEnd, sizeof(linebuf), yStart, xStart);
+ fInsSpace (xStart, yStart, 0, pFile, pbuf);
+ *pLog (pbuf, xStart, TRUE) = 0;
+ DelLine (TRUE, pFile, yStart, yEnd - 1);
+ delspace (0, yStart, xEnd, pFile, sbuf);
+ LengthCheck (yStart, xStart, sbuf);
+ strcpy (pLog (pbuf, xStart, TRUE), sbuf);
+ PutLine (yStart, pbuf, pFile);
+ MarkCopyBox (pFile, pFile, xEnd, yStart, sizeof(linebuf), yStart, xStart, yStart);
+}
+
+
+
+
+/* LengthCheck - verify/truncate a buffer prior to strcpy
+ *
+ * Verify that the result of a strcpy will fit within a buffer.
+ * If the line is too long, display an error and truncate the string so
+ * that it will fit within a buffer.
+ *
+ * line line of interest (for display)
+ * offset offset where strcpy begins
+ * pStr pointer to copied string. If NULL, the message is displayed.
+ */
+void
+LengthCheck (
+ LINE line,
+ int offset,
+ REGISTER char *pStr
+ )
+{
+ if (pStr == NULL || offset + strlen (pStr) + 1 > sizeof(linebuf)) {
+ printerror ("Line %ld too long", line + 1);
+ if (pStr != NULL) {
+ pStr[BUFLEN - offset - 1] = 0;
+ }
+ }
+}
+
+
+
+
+
+/****************************************************************************
+ * *
+ * fcolcpy (dst, src) *
+ * *
+ * dst - address of destination of copy *
+ * src - address of source of copy *
+ * *
+ * RETURNS: *
+ * *
+ * Number of struct lineAttr's copied *
+ * *
+ * DESCRIPTION: *
+ * *
+ * Copies the contents of src to dst. The length of the array, *
+ * including the terminating 0xFFFF, is returned. If the *
+ * destination is NULL, the number of items is still returned, but *
+ * no copy takes place. *
+ * *
+ ****************************************************************************/
+int
+fcolcpy (
+ struct lineAttr * dst,
+ struct lineAttr * src
+ )
+{
+
+ struct lineAttr *p = src;
+ int size;
+
+ while ((p->len != 0xFF) && ((p++)->attr != 0xFF)) {
+ }
+
+ size = (int)((PBYTE)p - (PBYTE)src);
+
+ if ( dst ) {
+ memmove((char *)dst, (char *)src, size);
+ }
+
+ return size / sizeof(struct lineAttr);
+}
+
+
+
+
+/*** FreeFile - Free all resources for LRU clean file or MRU dirty file
+*
+* Purpose:
+*
+* When we are low on memory, we call this to get some back. This frees
+* the text of the file from VM, as well as the pFile structure and name
+* from local memory.
+*
+* The strategy is to find the least recently used clean file and throw it
+* out. If there are no such files, we find the most recently used dirty
+* file, ask the user if he wants to save it, then flush it. The user
+* can hit <cancel> to not flush the file.
+*
+* Input:
+*
+* Output:
+*
+* Returns TRUE if successfull.
+*
+*
+* Exceptions:
+*
+* Pseudo files are not removed.
+* Dirty user files will be saved to disk first.
+*
+* Notes:
+*
+*************************************************************************/
+flagType
+ExpungeFile (
+ void
+ )
+{
+ flagType fRet = FALSE;
+ PFILE pFile;
+
+ /*
+ * Ensure that we do NOT attempt to update any text screens (and possibly
+ * attempt to allocate more memory).
+ */
+ RSETFLAG (fDisplay, RTEXT);
+
+ if (!(pFile = pFileLRU (pFileHead))) {
+
+ /*
+ * No LRU clean files found. Ask if user wants to save them all, and let
+ * him try. Then look for an LRU clean file again.
+ */
+ if (confirm ("Save all changed files?",NULL)) {
+ SaveAllFiles ();
+ }
+
+ if (!(pFile = pFileLRU (pFileHead))) {
+ /*
+ * No LRU clean files, and he didn't want to save them all. So, we walk
+ * the pFile list, and let him decide for each one. As soon as we find one
+ * that we can flush, do so.
+ */
+
+ for (pFile = pFileHead; pFile; pFile = pFile->pFileNext) {
+ if ( ((FLAGS(pFile) & (DIRTY | FAKE)) == DIRTY)
+ && (pFile != pFileIni)
+ && (pFile != pFileHead)
+ && (pFile != pFileMark)) {
+
+ if (confirm ("Save file %s before flushing?",pFile->pName)) {
+ FileWrite (NULL, pFile);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ /*
+ * We have some kind of pFile. Either it was clean, or it was dirty and the
+ * user said save it, or it is dirty, and the user said flush it anyway. So
+ * we do...
+ */
+ if (pFile) {
+ domessage ("Flushing %s from memory", pFile->pName);
+ RemoveFile (pFile);
+ fRet = TRUE;
+ }
+
+ SETFLAG (fDisplay, RTEXT);
+ return fRet;
+}
+
+
+
+
+
+/*** pFileLRU - Return last clean user file in file list
+*
+* Purpose:
+*
+* Used by ExpungeFile to find LRU clean file.
+*
+* Input:
+*
+* Head of list of files in MRU order
+*
+* Output:
+*
+* Returns LRU pFile.
+*
+*
+* Exceptions:
+*
+* TOOLS.INI and the current mark file
+*
+* Notes:
+*
+* The function recurses to the end of the list, then backtracks through
+* the unacceptable files to the one we want and returns that. The
+* recursion take 4 bytes for each call. The maximum number of calls
+* should be about 250.
+*
+*************************************************************************/
+PFILE
+pFileLRU (
+ PFILE pFile
+ )
+{
+ static PFILE pFileRet;
+
+ if (pFile == NULL) {
+ return NULL;
+ }
+
+ if (pFileRet = pFileLRU (pFile->pFileNext)) {
+ return pFileRet;
+ }
+
+ if (TESTFLAG (FLAGS(pFile), FAKE) || TESTFLAG (FLAGS(pFile), DIRTY)) {
+ return NULL;
+ }
+
+ if (pFile == pFileIni || pFile == pFileMark) {
+ return NULL;
+ }
+
+ return pFile;
+}
+
+
+
+
+
+
+/*** FreeFileVM - Free VM space associated with the given file
+*
+* Purpose:
+*
+* To recover VM used by a file
+*
+* Input:
+*
+* pFile - File in question.
+*
+* Output:
+*
+* Returns nothing
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+void
+FreeFileVM (
+ PFILE pFile
+ )
+{
+ LINE i;
+ LINEREC *vLine;
+
+
+ for (i = 0; i < min( 1, pFile->cLines ); i++) {
+ vLine = VALINE(i);
+ if (vLine->Malloced) {
+ vLine->Malloced = FALSE;
+ FREE (vLine->vaLine);
+ }
+ }
+
+ pFile->cLines = 0;
+ pFile->lSize = 0;
+
+ if (pFile->plr != NULL) {
+ FREE (pFile->plr);
+ pFile->plr = NULL;
+ }
+
+ if (pFile->pbFile != NULL) {
+ FREE (pFile->pbFile);
+ pFile->pbFile = NULL;
+ }
+
+ RemoveUndoList (pFile);
+
+ RSETFLAG (FLAGS (pFile), REAL);
+}
+
+
+
+
+
+
+/*** GetTagLine - Get a line, assuming a tools.ini-style format
+*
+* Purpose:
+*
+* To get a clean, complete line in DoAssign form. This means:
+*
+* o Blank lines are skipped
+* o Lines beginning with ';' are skipped
+* o Text past a ';' not in quotes is eliminated
+* o Lines with continuation characters are concatenated
+* o When we reach another tag, we stop reading
+*
+* The continuation character is a '\'; it must be preceded by
+* a space or tab and followed by nothing or whitespace and/or a comment.
+* Any leading whitespace on following lines is stripped.
+*
+* Input:
+* buf - Place to put result. This must be NULL initially and a
+* GetTagLine returned pointer afterwords
+*
+* Output:
+*
+* Returns pointer to next line, or NULL if we are done
+*
+* Notes:
+*
+* When we return NULL, we also free the buffer. If the caller stops
+* before NULL is returned, s/he must also free the buffer.
+*
+* Because a line may be arbitrarily long, we may need to LMAlloc more
+* space for it. Because of this, the routine itself will alloc all space
+* used. When a non-NULL pointer is passed in, it is assumed that this
+* points to the heap.
+*
+*************************************************************************/
+
+#define GTL_NORMAL 0
+#define GTL_QUOTE 1
+#define GTL_WS 2
+#define GTL_CONT 3
+
+char *
+GetTagLine (
+ LINE * pCurLine,
+ char * buf,
+ PFILE pFile
+ )
+{
+ int cch;
+ int ochScan; /* saved offset of pchScan */
+ int state = GTL_NORMAL;
+ int statePrev;
+ REGISTER char * pchScan;
+ char *pchSlash;
+ char *pch;
+ flagType fEof = FALSE;
+ flagType fWS;
+
+ if (buf == NULL) {
+ buf = ZEROMALLOC (sizeof(linebuf));
+ if ( !buf ) {
+ disperr(MSGERR_NOMEM);
+ disperr(MSGERR_QUIT);
+ CleanExit(4,FALSE);
+ }
+ }
+
+ buf[0] = '\0'; /* Ya start with nothin' */
+ pchScan = buf;
+
+ // We do this:
+ //
+ // Get a line
+ // If it's a tag line or the last line, stop reading
+ // If it is blank or begins with a ';', start over
+ // Clean up the line
+ // If we are left looking at a \, reset pointers, allocate
+ // Enough more space to leave BUFLEN bytes of space, and
+ // Start over.
+ //
+ // When we're done, 'buf' points to a complete line
+ //
+ while (TRUE) {
+ GetLine ((*pCurLine)++, pchScan, pFile);
+
+ if (IsTag (pchScan) || (*pCurLine) > pFile->cLines) {
+ (*pCurLine)--; /* Leave caller pointing at tag line */
+ fEof = TRUE;
+ break;
+ }
+
+ /* Squeeze out all leading spaces. */
+ pch = whiteskip (pchScan);
+ memmove ((char *)pchScan, (char*)pch, strlen(pch) + 1);
+
+ // Now look for a continuation sequence. This is whitespace
+ // followed by a \ followed by nothing but whitespace and/or
+ // a comment. We use a modified FSM with these states:
+ //
+ // GTL_NORMAL Outside quotes
+ // GTL_QUOTE Inside quotes
+ // GTL_WS Reading whitespace
+ // GTL_CONT Possible continuation sequence found.
+ //
+ for (fWS = TRUE, statePrev = state = GTL_NORMAL;
+ *pchScan;
+ pchScan++) {
+ if (*pchScan == ';' && fWS && statePrev != GTL_QUOTE) {
+ *pchScan-- = '\0';
+ } else {
+ fWS = (flagType)(strchr (rgchWSpace, *pchScan) != NULL);
+ switch (state) {
+
+ case GTL_NORMAL:
+ if (fWS) {
+ state = GTL_WS;
+ statePrev = GTL_NORMAL;
+ } else if (*pchScan == '"') {
+ state = GTL_QUOTE;
+ }
+ break;
+
+ case GTL_QUOTE:
+ if (fWS) {
+ state = GTL_WS;
+ statePrev = GTL_QUOTE;
+ } else if (*pchScan == '"') {
+ state = GTL_NORMAL;
+ }
+ break;
+
+ case GTL_WS:
+ if (*pchScan == '\\') {
+ pchSlash = pchScan;
+ state = GTL_CONT;
+ break;
+ }
+
+ case GTL_CONT:
+ if (!fWS) {
+ if (*pchScan == '"') {
+ state = statePrev == GTL_QUOTE ?
+ GTL_NORMAL :
+ GTL_QUOTE;
+ } else {
+ state = statePrev;
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if (state == GTL_CONT) {
+ pchScan = pchSlash-1; /* -1 to strip the space */
+ /* Make sure there is enough space for getline! */
+ cch = MEMSIZE (buf);
+ ochScan = (pchScan - buf);
+ if ((cch - ochScan) < sizeof(linebuf)) {
+ pch = buf = ZEROREALLOC (buf, cch + sizeof(linebuf));
+ pchScan = pch + ochScan;
+ }
+ } else if (buf[0] == '\0') {
+ continue;
+ } else {
+ break;
+ }
+ }
+
+
+ // 'buf' holds whatever we got. If 'fEof' is TRUE, this may be
+ // nothing at all. If 'fEof' is FALSE and we have nothing, then
+ // we are confused.
+ //
+ if (fEof) {
+ if (pchScan != buf) {
+ // The user had a continuation character at the end
+ // of the last line in the section or file. Erase the
+ // trailing [garbage] and issue a warning message.
+ //
+ printerror ("Warning: continuation character on last line!");
+ *pchScan = '\0';
+ return buf;
+ } else {
+ FREE (buf);
+ return NULL;
+ }
+ } else {
+ assert (buf[0]);
+ }
+
+ return buf;
+}
+
+
+
+
+
+/*** cbLog - return logical length of entabbed line
+*
+* Given a line possible entabbed, return the logical length of that line.
+*
+* Input:
+* pBuf = pointer to line in question
+*
+* Output:
+* Returns logical length of line
+*
+*************************************************************************/
+int
+cbLog (
+ REGISTER char *pBuf
+ )
+{
+ REGISTER int cbLine;
+
+ if (!fRealTabs) {
+ return strlen(pBuf);
+ }
+
+ cbLine = 0;
+ while (*pBuf) {
+ if (*pBuf++ == '\t') {
+ cbLine = ((cbLine + fileTab) / fileTab) * fileTab;
+ } else {
+ cbLine++;
+ }
+ }
+ return cbLine;
+}
+
+
+
+
+
+/*** colPhys - return logical column from physical pointer
+*
+* Given a buffer and a pointer into it, determine the logical column
+* that that pointer represents. If a null is encountered before the
+* pointer into the buffer, the rest of the buffer contents are ignored
+* (that is, tab expansion calculation is not done), and the column is
+* returned as if the rest of the line up to the pointer were NOT tabs.
+*
+* Input:
+* pBuf = pointer to buffer
+* pCur = pointer into buffer
+*
+* Output:
+* Returns 0 based column represented
+*
+*************************************************************************/
+COL
+colPhys (
+ char *pBuf,
+ char *pCur
+ )
+{
+ COL colRet = 0;
+
+ /*
+ * Special case the current pointer preceding the buffer, and return a
+ * column of -1.
+ */
+ if (pBuf > pCur) {
+ return -1;
+ }
+
+ while (*pBuf && (pBuf < pCur)) {
+ if (*pBuf++ == '\t') {
+ colRet = ((colRet + fileTab) / fileTab) * fileTab;
+ } else {
+ colRet++;
+ }
+ }
+
+ if (pBuf < pCur) {
+ colRet += (pCur - pBuf);
+ }
+
+ return colRet;
+}
+
+
+
+
+
+/*** IncCol, DecCol - Increment/Decrement a column w/ tabs
+*
+* Increment or decrement a column position, taking into account tab
+* characters on the line and the fRealTabs flag. Ensure that the resulting
+* logical column position rests on a character, or the first column
+* position of an underlying tab, if fRealTabs is on.
+*
+* Input:
+* col = column position to start
+* pText = buffer containing the text of the line
+*
+* Output:
+* Returns new column position
+*
+*************************************************************************/
+COL
+DecCol (
+ COL col,
+ char *pText
+ )
+{
+ return colPhys (pText, pLog (pText, col, FALSE) - 1);
+}
+
+
+
+
+
+COL
+IncCol (
+ COL col,
+ char *pText
+ )
+{
+ return colPhys (pText, pLog (pText, col, TRUE) + 1);
+}
+
+
+
+
+
+/*** AppFile - Append a line to the given file without logging the change
+*
+* Purpose:
+*
+* Used to generate pseudo files that display information, such as
+* <information> and <assign>.
+*
+* Input:
+* p - Line to add.
+* pFile - File to add it to
+*
+* Output: None.
+*
+*************************************************************************/
+void
+AppFile (
+ char *p,
+ PFILE pFile
+ )
+{
+ puttextline (FALSE, FALSE, pFile->cLines, p, pFile);
+}
+
+
+
+
+/*** PutTagLine - Put a line into file with continuation chars
+*
+* Purpose:
+*
+* Used to generate TOOLS.INI type entries, in which a single logical
+* line can be broken into many physical lines separated by continuation
+* characters.
+*
+* The current logical line is replaced.
+*
+* Input:
+* pFile - The file to put into
+* pszLine - The line to put
+* line - The number of the line to replace
+*
+* Output: None
+*
+*************************************************************************/
+void
+PutTagLine (
+ PFILE pFile,
+ char * pszLine,
+ LINE y,
+ COL x
+ )
+{
+ PFILE pFileCur = pFileHead;
+ fl flWindow;
+ fl flCursor;
+ flagType fWrap = fWordWrap;
+ LINE yCur;
+ linebuf lbuf;
+
+ // We remember which file we're in, then switch to the
+ // given and use edit() to insert to string. In between
+ // in each character we check to see if we have been bumped
+ // to thenext line. If so, we retrieve the previous line
+ // and append a continuation character. When we're done, we
+ // restore the previous state of pFile.
+ //
+ pFileToTop (pFile);
+ flWindow = pInsCur->flWindow;
+ flCursor = pInsCur->flCursorCur;
+
+ pInsCur->flCursorCur.lin = y;
+
+ if (x < 0) {
+ x = LineLength (y, pFile);
+ }
+
+ pInsCur->flCursorCur.col = x;
+
+ fWordWrap = TRUE;
+ yCur = y;
+
+ while (*pszLine) {
+ edit (*pszLine++);
+ if (yCur != YCUR(pInsCur)) {
+ GetLine (yCur, lbuf, pFile);
+ strcat (lbuf, " \\");
+ PutLine (yCur, lbuf, pFile);
+ yCur = YCUR(pInsCur);
+ }
+ }
+
+ fWordWrap = fWrap;
+ pInsCur->flWindow = flWindow;
+ pInsCur->flCursorCur = flCursor;
+ pFileToTop (pFileCur);
+}
+
+
+
+
+
+/*** ShiftColor - Shift color left or right within a line
+*
+* Purpose:
+*
+* Shifts color to the left or right. Shifting left deletes the
+* covered coilor. Shifting right propogates the color at the
+* left edge of the shift.
+*
+* Input:
+* rgla - Array of colors to work on.
+* xStart - Column to start with
+* n - Number of columns to shift by.
+*
+* Output: None.
+*
+* Notes:
+*
+* It is assumed that the color can properly be shifted by simply
+* adding or subtracting the given number of columns. This means
+* that when fRealTabs is on, the color array should be presented
+* in physical form, as returned by GetColor().
+*
+*************************************************************************/
+void
+ShiftColor (
+ struct lineAttr rgla[],
+ COL x,
+ int len
+ )
+{
+ struct lineAttr * plaEnd;
+ struct lineAttr * plaRight;
+ struct lineAttr * plaLeft;
+
+ int dColRight;
+ int dColLeft;
+ flagType fFoundRight = FALSE;
+ flagType fFoundLeft = FALSE;
+
+
+ plaEnd = plaLeft = plaRight = rgla;
+ dColRight = dColLeft = x;
+
+ fFoundRight = fGetColorPos (&plaRight, &dColRight);
+ fFoundLeft = fGetColorPos (&plaLeft, &dColLeft);
+ (void)fGetColorPos (&plaEnd, NULL);
+
+ if (!fFoundLeft) {
+ return;
+ }
+
+ if (len < 0) {
+ // User is shifting left. If the deletion
+ // all lies within a single color, we simply shorten
+ // that color. If it does not, we delete the entries
+ // for the colors we lose, then shorten the colors
+ // on either side.
+ //
+ if (plaLeft == plaRight) {
+ plaLeft->len = (unsigned char)((int)plaLeft->len + len);
+ } else {
+ memmove ((char *)(plaLeft + 1),
+ (char *)plaRight,
+ sizeof(*plaEnd) * (plaEnd - plaRight + 1));
+ plaLeft->len = (unsigned char)(dColLeft > 0 ? dColLeft : 0);
+ if (fFoundRight) {
+ (plaLeft+1)->len -= (unsigned char)dColRight;
+ }
+ }
+ } else {
+ plaLeft->len += (unsigned char)len;
+ }
+}
+
+
+
+
+/*** CopyColor - Copy part of a line of color
+*
+* Purpose:
+*
+* When text is copied, we make the color follow it with this.
+*
+* Input:
+* pFileSrc - Source of color. If NULL, the color is fgColor.
+* pFileDst - Destination of color.
+* yStart - Line to get color from.
+* xStart - Column to start in
+* len - length of color to copy
+* yDst - Line to put color on
+* xDst - Column to start in
+*
+* Output: None.
+*
+* Notes:
+*
+* The color copied overwrites existing color.
+*
+* This could be made faster by splicing in the color directly,
+* rather than calling UpdOneHiLite().
+*
+*************************************************************************/
+void
+CopyColor (
+ PFILE pFileSrc,
+ PFILE pFileDst,
+ LINE yStart,
+ COL xStart,
+ COL len,
+ LINE yDst,
+ COL xDst
+ )
+{
+ struct lineAttr * rglaSrc = (struct lineAttr *)ZEROMALLOC (sizeof(linebuf) * sizeof(struct lineAttr));
+ struct lineAttr * rglaDst = (struct lineAttr *)ZEROMALLOC (sizeof(linebuf) * sizeof(struct lineAttr));
+ struct lineAttr * plaLeft;
+ COL xLeft, cCol;
+ flagType fLeft = TRUE, fColorDst, fColorSrc = FALSE;
+
+ if ( !rglaSrc || !rglaDst ) {
+ disperr(MSGERR_NOMEM);
+ disperr(MSGERR_QUIT);
+ CleanExit(4,FALSE);
+ }
+
+
+ xLeft = xStart;
+
+ fColorDst = (flagType)getcolorline (TRUE, yDst, rglaDst, pFileDst);
+
+ if (!pFileSrc ||
+ !(fColorSrc = (flagType)GetColor (yStart, plaLeft = rglaSrc, pFileSrc)) ||
+ !(fLeft = fGetColorPos(&plaLeft, &xLeft)) ) {
+
+ if (fColorSrc || fColorDst) {
+ UpdOneHiLite (rglaDst, xDst, len, TRUE, fLeft ? fgColor : plaLeft->attr);
+ } else {
+ goto freestuff;
+ }
+ } else {
+ assert(plaLeft && plaLeft->len != 0xFF);
+
+ plaLeft->len -= (unsigned char)xLeft;
+
+ for (cCol = 0; cCol < len; cCol += plaLeft->len, plaLeft++) {
+ if (plaLeft->len != 0xFF) {
+ if ((int)plaLeft->len > (len - cCol)) {
+ plaLeft->len = (unsigned char)(len - cCol);
+ }
+ UpdOneHiLite (rglaDst, xDst + cCol, TRUE, plaLeft->len, plaLeft->attr);
+ }
+ }
+ }
+
+ putcolorline (TRUE, yDst, rglaDst, pFileDst);
+
+freestuff:
+ FREE (rglaSrc);
+ FREE (rglaDst);
+}
+
+
+
+
+
+/*** SetColor - Assign a color to a stretch of text
+*
+* Purpose:
+*
+* Add color to a file.
+*
+* Input:
+* pFile - File to add color to.
+* y - Line to add color to.
+* x - Column to start in.
+* len - Length of color.
+* color - color to attach.
+*
+* Output: None.
+*
+*************************************************************************/
+void
+SetColor (
+ PFILE pFile,
+ LINE y,
+ COL x,
+ COL len,
+ int color
+ )
+{
+ struct lineAttr * rgla = (struct lineAttr * )ZEROMALLOC (sizeof(linebuf) * sizeof(struct lineAttr));
+ struct lineAttr * pla;
+
+ if ( !rgla ) {
+ disperr(MSGERR_NOMEM);
+ disperr(MSGERR_QUIT);
+ CleanExit(4,FALSE);
+ }
+
+ if (GetColorUntabbed (y, rgla, pFile)) {
+ UpdOneHiLite (rgla, x, len, TRUE, color);
+ } else {
+ if (color == FGCOLOR) {
+ goto freeit;
+ }
+
+ pla = rgla;
+
+ if (x) {
+ pla->len = (unsigned char)x;
+ (pla++)->attr = (unsigned char)fgColor;
+ }
+
+ pla->len = (unsigned char)len;
+ pla->attr = (unsigned char)color;
+ (++pla)->len = 0xFF;
+ }
+
+ PutColor (y, rgla, pFile);
+
+freeit:
+ FREE (rgla);
+}
+
+
+
+
+
+/*** fGetColorPos - Get color array position of real column
+*
+* Purpose:
+*
+* Given an array of lineAttr and a column number, find the
+* color array element and offset that corresponds to that
+* absolute column.
+*
+* Input:
+* ppla - Color array to examine.
+* pOff - Column in text line to find. If NULL, this is a
+* request to find the array terminator.
+*
+* Output:
+* ppla - Element of input array that specifies the color field
+* in which the input column will be found. If the column
+* lies beyond the defined color, this will be the terminator.
+* pOff - The offset into the color field ppla which corresponds
+* to the user's column.
+*
+* Returns TRUE if the user's column lay within the color definition,
+* FALSE if not.
+*
+*************************************************************************/
+flagType
+fGetColorPos (
+ struct lineAttr **ppla,
+ COL * pOff
+ )
+{
+ COL Off;
+ COL x;
+
+ if (pOff) {
+ Off = *pOff;
+ }
+
+ for (x = 0; (*ppla)->len != 0xFF; x += (*ppla)->len, (*ppla)++) {
+ if (pOff && (Off - x < (COL)((*ppla)->len))) {
+ break;
+ }
+ }
+
+ if (pOff) {
+ *pOff = Off - x;
+ }
+
+ return (flagType)((*ppla)->len != 0xFF);
+}
+
+
+
+
+
+
+/*** ColorToPhys - Change a line's color info from logical to physical
+*
+* Purpose:
+*
+* The logical color representation encodes one color column per screen
+* column. The physical color representation encodes one color column
+* per file character. The difference is that the file character may
+* be a tab, which represents 1-8 screen columns.
+*
+* This function takes a logical color array and converts it to a
+* physical array, using the text the color is attached to.
+*
+* Input:
+* pla - Logical color array.
+* line - Line number this is attached to to.
+* pFile- File the line is in.
+*
+* Output: None
+*
+*************************************************************************/
+void
+ColorToPhys (
+ struct lineAttr * pla,
+ LINE line,
+ PFILE pFile
+ )
+{
+ struct lineAttr * plaCur;
+ linebuf lBuf;
+ COL xLog, xPhys, xShrink;
+ flagType fRealTabsOrig = fRealTabs;
+
+ fRealTabs = TRUE;
+ if (gettextline (TRUE, line, lBuf, pFile, ' ')) {
+ // We read through the color array, keeping
+ // track of the logical column represented
+ // by the color fields. At each field, we ask
+ // what physical column the end of the field
+ // represents. If the two columns differ,
+ // we shrink the current current field. The
+ // amount to shrink is the difference between
+ // the columns less the amount we have already
+ // shrunk.
+ //
+ for (plaCur = pla, xShrink = 0, xLog = plaCur->len;
+ plaCur->len != 0xFF;
+ xLog += (++plaCur)->len) {
+
+ xPhys = pLog(lBuf, xLog, FALSE) - lBuf;
+
+ plaCur->len -= (unsigned char)((xLog - xPhys) - xShrink);
+ xShrink += (xLog - xPhys) - xShrink;
+ }
+ }
+ fRealTabs = fRealTabsOrig;
+}
+
+
+
+
+
+/*** ColorToLog - Change a line's color info from physical to logical
+*
+* Purpose:
+*
+* This is the opposite of ColorToPhys.
+*
+* Input:
+* pla - Physical color array
+* pText - Text to for conversion
+*
+* Output: None.
+*
+*************************************************************************/
+void
+ColorToLog (
+ struct lineAttr * pla,
+ char * pText
+ )
+{
+ struct lineAttr * plaCur;
+ COL xLog, xPhys, xGrow;
+
+ // We read through the color array, keeping
+ // track of the phsyical column represented
+ // by the color fields. At each field, we ask
+ // what logical column the end of the field
+ // represents. If the two columns differ,
+ // we grow the current current field. The
+ // amount to grow is the difference between
+ // the columns less the amount we have already
+ // shrunk.
+ //
+ for (plaCur = pla, xGrow = 0, xPhys = plaCur->len;
+ plaCur->len != 0xFF;
+ xPhys += (++plaCur)->len) {
+
+ xLog = colPhys (pText, pText + xPhys);
+
+ plaCur->len += (unsigned char)((xLog - xPhys) - xGrow);
+ xGrow += (xLog - xPhys) - xGrow;
+ }
+}
diff --git a/private/utils/mep/src/transkey.c b/private/utils/mep/src/transkey.c
new file mode 100644
index 000000000..bc4e9f87e
--- /dev/null
+++ b/private/utils/mep/src/transkey.c
@@ -0,0 +1,442 @@
+/*** transkey.c - keyboard translation
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+*
+* 03-Dec-1990 ramonsa createdc
+*
+*************************************************************************/
+
+//#define INCL_DOSSEMAPHORES
+#include "mep.h"
+#include "keyboard.h"
+#include "keys.h"
+#include "cmds.h"
+
+
+WORD GetNumlockIndex (WORD Scan);
+
+
+
+
+#define NORMAL_KEY 0
+#define ALT_KEY 1
+#define CTRL_KEY 2
+#define SHIFT_KEY 3
+
+
+// This table is indexed by a Scan code (as found in the KBDKEY
+// structure), and contains entries for the corresponding internal
+// MEP codes.
+//
+WORD MapTable[][4] = {
+
+ // Normal Alt Ctrl Shift Scan code
+ //
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 00
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 01 Left mouse
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 02 Right mouse
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 03
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 04
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 05
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 06
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 07
+ { 0x012D, 0x01A1, 0x0215, 0x0255 }, // 08 bksp
+ { 0x012E, 0x01A2, 0x0216, 0x0256 }, // 09 tab-bktab
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 0A
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 0B
+ { 0x0116, 0x018A, 0x01FE, 0x0000 }, // 0C goto
+ { 0x0131, 0x01A5, 0x0219, 0x0259 }, // 0D enter
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 0E
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 0F
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 10 Shift
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 11 Ctrl
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 12
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 13 Pause
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 14 Caps Lock
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 15
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 16
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 17
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 18
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 19
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 1A
+ { 0x0130, 0x0000, 0x0218, 0x0258 }, // 1B esc
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 1C
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 1D
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 1E
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 1F
+ { 0x0000, 0x01A0, 0x0214, 0x0000 }, // 20 space
+ { 0x0112, 0x0186, 0x01FA, 0x023A }, // 21 pgup
+ { 0x0113, 0x0187, 0x01FB, 0x023B }, // 22 pgdown
+ { 0x010D, 0x0181, 0x01F5, 0x0235 }, // 23 end
+ { 0x010C, 0x0180, 0x01F4, 0x0234 }, // 24 home
+ { 0x010E, 0x0182, 0x01F6, 0x0236 }, // 25 left
+ { 0x0110, 0x0184, 0x01F8, 0x0238 }, // 26 up
+ { 0x010F, 0x0183, 0x01F7, 0x0237 }, // 27 right
+ { 0x0111, 0x0185, 0x01F9, 0x0239 }, // 28 down
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 29
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 2A
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 2B
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 2C Print Scrn
+ { 0x0114, 0x0188, 0x01FC, 0x023C }, // 2D ins
+ { 0x0115, 0x0189, 0x01FD, 0x023D }, // 2E del
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 2F
+ { 0x0000, 0x0140, 0x01B4, 0x0000 }, // 30 0
+ { 0x0000, 0x0141, 0x01B5, 0x0000 }, // 31 1
+ { 0x0000, 0x0142, 0x01B6, 0x0000 }, // 32 2
+ { 0x0000, 0x0143, 0x01B7, 0x0000 }, // 33 3
+ { 0x0000, 0x0144, 0x01B8, 0x0000 }, // 34 4
+ { 0x0000, 0x0145, 0x01B9, 0x0000 }, // 35 5
+ { 0x0000, 0x0146, 0x01BA, 0x0000 }, // 36 6
+ { 0x0000, 0x0147, 0x01BB, 0x0000 }, // 37 7
+ { 0x0000, 0x0148, 0x01BC, 0x0000 }, // 38 8
+ { 0x0000, 0x0149, 0x01BD, 0x0000 }, // 39 9
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 3A
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 3B
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 3C
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 3D
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 3E
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 3F
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 40
+ { 0x0000, 0x014C, 0x01C0, 0x0000 }, // 41 a
+ { 0x0000, 0x014D, 0x01C1, 0x0000 }, // 42 b
+ { 0x0000, 0x014E, 0x01C2, 0x0000 }, // 43 c
+ { 0x0000, 0x014F, 0x01C3, 0x0000 }, // 44 d
+ { 0x0000, 0x0150, 0x01C4, 0x0000 }, // 45 e
+ { 0x0000, 0x0151, 0x01C5, 0x0000 }, // 46 f
+ { 0x0000, 0x0152, 0x01C6, 0x0000 }, // 47 g
+ { 0x0000, 0x0153, 0x01C7, 0x0000 }, // 48 h
+ { 0x0000, 0x0154, 0x01C8, 0x0000 }, // 49 i
+ { 0x0000, 0x0155, 0x01C9, 0x0000 }, // 4A j
+ { 0x0000, 0x0156, 0x01CA, 0x0000 }, // 4B k
+ { 0x0000, 0x0157, 0x01CB, 0x0000 }, // 4C l
+ { 0x0000, 0x0158, 0x01CC, 0x0000 }, // 4D m
+ { 0x0000, 0x0159, 0x01CD, 0x0000 }, // 4E n
+ { 0x0000, 0x015A, 0x01CE, 0x0000 }, // 4F o
+ { 0x0000, 0x015B, 0x01CF, 0x0000 }, // 50 p
+ { 0x0000, 0x015C, 0x01D0, 0x0000 }, // 51 q
+ { 0x0000, 0x015D, 0x01D1, 0x0000 }, // 52 r
+ { 0x0000, 0x015E, 0x01D2, 0x0000 }, // 53 s
+ { 0x0000, 0x015F, 0x01D3, 0x0000 }, // 54 t
+ { 0x0000, 0x0160, 0x01D4, 0x0000 }, // 55 u
+ { 0x0000, 0x0161, 0x01D5, 0x0000 }, // 56 v
+ { 0x0000, 0x0162, 0x01D6, 0x0000 }, // 57 w
+ { 0x0000, 0x0163, 0x01D7, 0x0000 }, // 58 x
+ { 0x0000, 0x0164, 0x01D8, 0x0000 }, // 59 y
+ { 0x0000, 0x0165, 0x01D9, 0x0000 }, // 5A z
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 5B
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 5C
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 5D
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 5E
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 5F
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 60
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 61
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 62
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 63
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 64
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 65
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 66
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 67
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 68
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 69
+ { 0x0126, 0x019A, 0x020E, 0x024E }, // 6A num*
+ { 0x0125, 0x0199, 0x020D, 0x024D }, // 6B num+
+ { 0x0128, 0x019C, 0x0210, 0x0250 }, // 6C numenter
+ { 0x0124, 0x0198, 0x020C, 0x024C }, // 6D num-
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 6E
+ // { 0x0000, 0x017E, 0x01F2, 0x0000 }, // ?? /
+ { 0x0127, 0x019b, 0x020F, 0x024F }, // 6F num/
+ { 0x0100, 0x0168, 0x01DC, 0x0228 }, // 70 f1
+ { 0x0101, 0x0169, 0x01DD, 0x0229 }, // 71 f2
+ { 0x0102, 0x016A, 0x01DE, 0x022A }, // 72 f3
+ { 0x0103, 0x016B, 0x01DF, 0x022B }, // 73 f4
+ { 0x0104, 0x016C, 0x01E0, 0x022C }, // 74 f5
+ { 0x0105, 0x016D, 0x01E1, 0x022D }, // 75 f6
+ { 0x0106, 0x016E, 0x01E2, 0x022E }, // 76 f7
+ { 0x0107, 0x016F, 0x01E3, 0x022F }, // 77 f8
+ { 0x0108, 0x0170, 0x01E4, 0x0230 }, // 78 f9
+ { 0x0109, 0x0171, 0x01E5, 0x0231 }, // 79 f10
+ { 0x010A, 0x0172, 0x01E6, 0x0232 }, // 7A f11
+ { 0x010B, 0x0173, 0x01E7, 0x0233 }, // 7B f12
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 7C
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 7D
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 7E
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 7F
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 80
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 81
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 82
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 83
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 84
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 85
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 86
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 87
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 88
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 89
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 8A
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 8B
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 8C
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 8D
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 8E
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 8F
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 90 Num lock
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 91 Scroll Lock
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 92
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 93
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 94
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 95
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 96
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 97
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 98
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 99
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 9A
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 9B
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 9C
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 9D
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 9E
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // 9F
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // A0
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // A1
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // A2
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // A3
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // A4
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // A5
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // A6
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // A7
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // A8
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // A9
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // AA
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // AB
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // AC
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // AD
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // AE
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // AF
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // B0
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // B1
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // B2
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // B3
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // B4
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // B5
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // B6
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // B7
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // B8
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // B9
+ { 0x0000, 0x017A, 0x01EE, 0x0000 }, // BA ;
+ { 0x0000, 0x0176, 0x01EA, 0x0000 }, // BB +
+ { 0x0000, 0x017C, 0x01F0, 0x0000 }, // BC ,
+ { 0x0000, 0x0175, 0x01E9, 0x0000 }, // BD -
+ { 0x0000, 0x017D, 0x01F1, 0x0000 }, // BE .
+ { 0x0000, 0x017E, 0x01F2, 0x0000 }, // BF /
+ { 0x0000, 0x0174, 0x01E8, 0x0000 }, // C0 `
+ { 0x0000, 0x017B, 0x01EF, 0x0000 }, // C1 '
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // C2
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // C3
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // C4
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // C5
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // C6
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // C7
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // C8
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // C9
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // CA
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // CB
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // CC
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // CD
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // CE
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // CF
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // D0
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // D1
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // D2
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // D3
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // D4
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // D5
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // D6
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // D7
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // D8
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // D9
+ { 0x0000, 0x0000, 0x0000, 0x0000 }, // DA
+ { 0x0000, 0x0177, 0x01EB, 0x0000 }, // DB [
+ { 0x0000, 0x0179, 0x01ED, 0x0000 }, // DC backslash
+ { 0x0000, 0x0178, 0x01EC, 0x0000 }, // DD ]
+ { 0x0000, 0x017B, 0x01EF, 0x0000 }, // DE '
+ { 0x0000, 0x0176, 0x01EA, 0x0000 }, // DF =
+};
+
+#define LAST_SCAN 0xDF
+
+
+// This table contains entries for codes when NUMLOCK is on,
+// it is not indexed by scan code, but by an index obtain thru the
+// function GetNumlockIndex function.
+//
+WORD MapNumlockTable[][4] = {
+ // Special Alt Ctrl Shift Index Key
+ //
+ { 0x0118, 0x018C, 0x0200, 0x0240 }, // 0 num0
+ { 0x0119, 0x018D, 0x0201, 0x0241 }, // 1 num1
+ { 0x011A, 0x018E, 0x0202, 0x0242 }, // 2 num2
+ { 0x011B, 0x018F, 0x0203, 0x0243 }, // 3 num3
+ { 0x011C, 0x0190, 0x0204, 0x0244 }, // 4 num4
+ { 0x011D, 0x0191, 0x0205, 0x0245 }, // 5 num5
+ { 0x011E, 0x0192, 0x0206, 0x0246 }, // 6 num6
+ { 0x011F, 0x0193, 0x0207, 0x0247 }, // 7 num7
+ { 0x0120, 0x0194, 0x0208, 0x0248 }, // 8 num8
+ { 0x0121, 0x0195, 0x0209, 0x0249 }, // 9 num9
+ { 0x0124, 0x0198, 0x020C, 0x024C }, // 10 num-
+ { 0x0125, 0x0199, 0x020D, 0x024D }, // 11 num+
+ { 0x0126, 0x019A, 0x020E, 0x024E }, // 12 num*
+ { 0x0127, 0x019B, 0x020F, 0x024F }, // 13 num/
+ { 0x0128, 0x019C, 0x0210, 0x0250 }, // 14 numenter
+
+ { 0x0000, 0x0000, 0x0000, 0x0000 } // 15
+
+
+
+};
+
+#define NUMLOCK_NOMAP ((WORD)(-1))
+
+
+/*** TranslateKey
+*
+* Purpose:
+*
+* Translates a KBDKEY structure into a KEY_INFO structure.
+*
+* This is the only function within the editor that knows about
+* the scan codes in the KBDKEY structure. All other editor functions
+* use our own codes (as found in the KEY_INFO structure).
+*
+* Input:
+* KBDKEY structure
+*
+* Returns
+* KEY_INFO structure
+*
+*
+*************************************************************************/
+
+EDITOR_KEY
+TranslateKey (
+ KBDKEY kbdi
+ ) {
+
+ BYTE Ascii = (BYTE)kbdi.Unicode;
+ BYTE Scan = (BYTE)kbdi.Scancode;
+ BYTE Flags = 0x00;
+
+ DWORD KbdiFlags = kbdi.Flags;
+
+ EDITOR_KEY k;
+ WORD MepCode = 0;
+ WORD ControlKey = 0;
+ WORD Index;
+
+
+ if (Scan <= LAST_SCAN) {
+
+ if (KbdiFlags & (CONS_LEFT_ALT_PRESSED | CONS_RIGHT_ALT_PRESSED)) {
+ Flags |= FLAG_ALT;
+ ControlKey = ALT_KEY;
+ }
+
+ if (KbdiFlags & (CONS_LEFT_CTRL_PRESSED | CONS_RIGHT_CTRL_PRESSED)) {
+ Flags |= FLAG_CTRL;
+ //Ascii &= 0x0F;
+ if ( !ControlKey ) {
+ ControlKey = CTRL_KEY;
+ } else {
+ //
+ // Foreign keyboard stuff
+ //
+ if ( Ascii != 0x00 ) {
+ Flags = 0;
+ ControlKey = 0;
+ }
+ }
+ }
+
+ if (KbdiFlags & CONS_SHIFT_PRESSED) {
+ Flags |= FLAG_SHIFT;
+ if ( !ControlKey ) {
+ ControlKey = SHIFT_KEY;
+ }
+ }
+
+
+ if (KbdiFlags & CONS_NUMLOCK_PRESSED) {
+
+ Flags |= FLAG_NUMLOCK;
+
+ //
+ // Numlock is set, determine which table to use
+ //
+ Index = GetNumlockIndex(Scan);
+
+ if (Index == NUMLOCK_NOMAP) {
+ //
+ // Key not affected by Numlock, use normal table
+ //
+ MepCode = MapTable[Scan][ControlKey];
+ } else {
+ //
+ // Key is affected by Numlock, use special table
+ //
+ MepCode = MapNumlockTable[Index][ControlKey];
+ }
+ } else {
+ //
+ // Numlock not set, use normal table
+ //
+ MepCode = MapTable[Scan][ControlKey];
+ }
+ }
+
+ k.KeyInfo.KeyData.Ascii = Ascii;
+ k.KeyInfo.KeyData.Scan = Scan;
+ k.KeyInfo.KeyData.Flags = Flags;
+ k.KeyInfo.KeyData.Unused = 0x00;
+
+ if (MepCode) {
+ //
+ // Found an MEP code
+ //
+ k.KeyCode = MepCode;
+ } else {
+ //
+ // Our scan code is within the 256 ASCII characters, form the
+ // KEY_INFO structure and return.
+ //
+ k.KeyCode = Ascii;
+ }
+
+ return k;
+}
+
+
+
+
+
+WORD
+GetNumlockIndex (
+ WORD Scan
+ )
+{
+ switch (Scan) {
+ case 0x60: return 0; // num0
+ case 0x61: return 1; // num1
+ case 0x62: return 2; // num2
+ case 0x63: return 3; // num3
+ case 0x64: return 4; // num4
+ case 0x65: return 5; // num5
+ case 0x66: return 6; // num6
+ case 0x67: return 7; // num7
+ case 0x68: return 8; // num8
+ case 0x69: return 9; // num9
+ case 0x6D: return 10; // num-
+ case 0x6B: return 11; // num+
+ case 0x6A: return 12; // num*
+ case 0x6F: return 13; // num/
+ case 0x6C: return 14; // numenter
+ default: return NUMLOCK_NOMAP;
+ }
+}
diff --git a/private/utils/mep/src/undo.c b/private/utils/mep/src/undo.c
new file mode 100644
index 000000000..6afda951c
--- /dev/null
+++ b/private/utils/mep/src/undo.c
@@ -0,0 +1,984 @@
+/*** Undo.c - handle all undo operations for editor
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* N-level undo/redo:
+*
+* For each file, keep a d-linked list of edit records in VM, head / tail /
+* current pointers into this list, and a count of "boundaries" between
+* undo-able edit operations. When that count exceeds "cUndo", we move excess
+* records from the tail of the undo list to a dead-record list, for eventual
+* discard.
+*
+* Freeing or rereading a file flushes its undo list.
+*
+* There are 4 types of undo records:
+*
+* Putline logs a "replace" record
+* line
+* va of old line
+* No optimization for recycling same space
+* Optimization for replacing same line
+*
+* Insline logs an "insert" record
+* line
+* number of lines inserted
+*
+* Delline logs a "delete" record
+* line
+* number deleted
+* VAs of deleted lines
+*
+* Top loop logs "boundary" records
+* file flags
+* file modification time
+* window position
+* cursor position
+* Optimization of entering boundary on top of boundary
+* Top loop also contains an optimization to prevent boundaries between
+* graphic functions.
+*
+* UNDO moves backwards in the undo list, reversing the effects of each record
+* logged until a boundary is encountered.
+*
+* REDO moves forwards in the undo list, repeating the effects of each record
+* logged.
+*
+* After an UNDO or REDO, the next record logging will cause the undo records
+* from the current position forward to be moved to the dead-record list for
+* eventual discard.
+*
+* Discarding of dead records occurs durring the system idle loop, or when an
+* out-of-memory condition ocurrs.
+*
+* Revision History:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+
+#include "mep.h"
+
+
+
+#define HEAD TRUE
+#define TAIL FALSE
+
+#define LINEREC(va,l) ((PBYTE)(va)+sizeof(LINEREC)*((long)(l)))
+#define COLORREC(va,l) ((PBYTE)(va)+sizeof(struct colorRecType)*((long)(l)))
+
+#if defined (DEBUG)
+
+ #define DUMPIT(x,y) UNDODUMP(x,y)
+
+ void
+ UNDODUMP (
+ PVOID vaCur,
+ char *Stuff
+ );
+
+#else
+
+ #define DUMPIT(x,y)
+
+#endif
+
+
+PVOID vaDead = (PVOID)-1L; /* head of dead undo list */
+
+
+
+/*
+ * UNDO record definitions.
+ * NOTE: these records are duplicated in a less complete form in EXT.H for
+ * extension users. BE SURE to change them there if you EVER change them
+ */
+struct replaceRec {
+ int op; /* operation */
+ PVOID flink; /* editor internal */
+ PVOID blink; /* editor internal */
+ LINE length; /* length of replacement */
+ LINE line; /* start of replacement */
+ LINEREC vLine; /* text of line */
+ struct colorRecType vColor; /* color of line */
+ PVOID vaMarks; /* marks attached to line */
+ };
+
+struct insertRec {
+ int op; /* operation */
+ PVOID flink; /* editor internal */
+ PVOID blink; /* editor internal */
+ LINE length;
+ LINE line; /* line number that was operated on */
+ LINE cLine; /* number of lines inserted */
+ };
+
+struct deleteRec {
+ int op; /* operation */
+ PVOID flink; /* editor internal */
+ PVOID blink; /* editor internal */
+ LINE length;
+ LINE line; /* line number that was operated on */
+ LINE cLine; /* Number of lines deleted */
+ PVOID vaLines; /* editor internal */
+ PVOID vaColor; /* Color of lines */
+ PVOID vaMarks; /* marks attached to lines */
+ };
+
+struct boundRec {
+ int op; /* operation (BOUND) */
+ PVOID flink; /* editor interal */
+ PVOID blink; /* editor interal */
+ int flags; /* flags of file */
+ long modify; /* Date/Time of last modify */
+ fl flWindow; /* position in file of window */
+ fl flCursor; /* position in file of cursor */
+ };
+
+union Rec {
+ struct replaceRec r;
+ struct insertRec i;
+ struct deleteRec d;
+ struct boundRec b;
+ };
+
+
+
+/*** CreateUndoList - initialize undo list for a file.
+*
+* Allocate the doubly-linked undo list with a single boundary record. Also
+* clears any existing list.
+*
+* Input:
+* pFile = file to operate on
+*
+*************************************************************************/
+void
+CreateUndoList (
+ PFILE pFile
+ )
+{
+ struct boundRec *boundary;
+
+ RemoveUndoList (pFile);
+
+ if (!(FLAGS(pFile) & READONLY)) {
+
+ pFile->vaUndoCur = pFile->vaUndoHead = pFile->vaUndoTail
+ = MALLOC ((long)sizeof (union Rec));
+
+ boundary = (struct boundRec *)(pFile->vaUndoHead);
+
+ boundary->op = EVENT_BOUNDARY;
+ boundary->blink = boundary->flink = (PVOID)(-1L);
+ boundary->flWindow.col = boundary->flCursor.col = 0;
+ boundary->flWindow.lin = boundary->flCursor.lin = 0L;
+ boundary->flags = FLAGS (pFile);
+
+ }
+}
+
+
+
+
+
+/*** LinkAtHead - link a record in at the head of the undo queue
+*
+* This is the routine which also discards any re-doable operations. When
+* called, if the "current" position is not at the head of the list, that
+* means we are adding a new editting operation, and we discard everything
+* between the head of the list and the current position, which becomes the
+* new head.
+*
+* Input:
+* vaNewHead = new head of linked list
+* precNewHead = pointer to the record itself
+* pFile = file whose list we are mucking with
+*
+*************************************************************************/
+void
+LinkAtHead (
+ PVOID vaNewHead,
+ union Rec *precNewHead,
+ PFILE pFile
+ )
+{
+ EVTargs e; /* event notification parameters*/
+
+ /*
+ * Declare the event
+ */
+ e.arg.pUndoRec = precNewHead;
+ DeclareEvent (EVT_EDIT, &e);
+
+ /*
+ * discard any records between current position and head of list
+ */
+ while (pFile->vaUndoCur != pFile->vaUndoHead) {
+
+ if (((union Rec *)(pFile->vaUndoHead ))->b.op == EVENT_BOUNDARY) {
+ pFile->cUndo--;
+ }
+
+ FreeUndoRec ( HEAD, pFile );
+ }
+
+ /*
+ * Modify the current head of the list to point at the new head.
+ */
+ ((union Rec *)(pFile->vaUndoHead))->b.flink = vaNewHead;
+
+ /*
+ * Update the links in the new head, and send it out
+ */
+ memmove(vaNewHead, (char *)precNewHead, sizeof (union Rec));
+
+ ((union Rec *)vaNewHead)->b.flink = (PVOID)(-1L);
+ ((union Rec *)vaNewHead)->b.blink = pFile->vaUndoHead;
+
+ pFile->vaUndoCur = pFile->vaUndoHead = vaNewHead;
+
+}
+
+
+
+
+
+/*** LogReplace - log replace action
+*
+* Allocate (or update) a replace record.
+*
+* Input:
+* pFile = file being changed
+* line = line being replaced
+* vLine = linerec being replaced
+*
+*************************************************************************/
+void
+LogReplace (
+ PFILE pFile,
+ LINE line,
+ LINEREC * pvLine,
+ struct colorRecType * pvColor
+ )
+{
+ EVTargs e; /* event notification parameters*/
+ union Rec *rec;
+ union Rec rec1;
+ PVOID vaReplace;
+
+ if ( pFile->vaUndoHead == (PVOID)-1L) {
+ CreateUndoList( pFile );
+ }
+
+ vaReplace = pFile->vaUndoHead;
+
+ if (!(FLAGS(pFile) & READONLY)) {
+
+ rec = (union Rec *)vaReplace;
+
+ if ((rec->r.op == EVENT_REPLACE) && (rec->r.line == line)) {
+
+ /*
+ * Optimization for immediately replacing the same line in a file with no
+ * intervening boundary or other operation. Discard the passed in "old" line,
+ * and update the other data in the existing replace record.
+ */
+ rec->r.length = pFile->cLines;
+ e.arg.pUndoRec = rec;
+ DeclareEvent (EVT_EDIT, &e);
+
+ if (pvLine->Malloced) {
+ pvLine->Malloced = FALSE;
+ FREE(pvLine->vaLine);
+ pvLine->vaLine = (PVOID)-1L;
+ }
+
+ } else {
+
+ /*
+ * if not optimizable, create new replace record
+ */
+ vaReplace = MALLOC( (long)sizeof(union Rec) );
+
+ memcpy( &rec1, rec, sizeof(rec1) );
+
+ rec1.r.op = EVENT_REPLACE;
+ rec1.r.vLine = *pvLine;
+ rec1.r.line = line;
+ rec1.r.vColor = *pvColor;
+ rec1.r.vaMarks = GetMarkRange (pFile, line, line);
+ rec1.r.length = pFile->cLines;
+ LinkAtHead( vaReplace, &rec1, pFile );
+ }
+ }
+}
+
+
+
+
+/*** LogInsert - log line insertion
+*
+* Add one EVENT_INSERT record to head of list
+*
+* Input:
+* pFile = file being changed
+* line = line being inserted at
+* cLines = number of lines being inserted
+*
+*************************************************************************/
+void
+LogInsert (
+ PFILE pFile,
+ LINE line,
+ LINE cLines
+ )
+{
+ union Rec rec;
+ PVOID vaInsert;
+
+ if (!(FLAGS(pFile) & READONLY)) {
+
+ vaInsert = MALLOC( (long)sizeof(union Rec) );
+
+ rec.i.op = EVENT_INSERT;
+ rec.i.length= pFile->cLines;
+ rec.i.line = line;
+ rec.i.cLine = cLines;
+ LinkAtHead (vaInsert,&rec,pFile);
+
+ }
+}
+
+
+
+/*** LogDelete - Log delete action
+*
+* Add one EVENT_DELETE record to head of list
+*
+* Input:
+* pFile = file being changed
+* start = 1st line being deleted
+* end = last line being deleted
+*
+*************************************************************************/
+void
+LogDelete (
+ PFILE pFile,
+ LINE start,
+ LINE end
+ )
+{
+ union Rec rec;
+ long cLine;
+ PVOID vaDelete;
+
+ if (!(FLAGS(pFile) & READONLY)) {
+
+ cLine = end - start + 1;
+ vaDelete = MALLOC ((long) sizeof (union Rec));
+
+ rec.d.op = EVENT_DELETE;
+ rec.d.length = pFile->cLines;
+ rec.d.line = start;
+ rec.d.cLine = cLine;
+ rec.d.vaLines = MALLOC (cLine * sizeof (LINEREC));
+ rec.d.vaMarks = GetMarkRange (pFile, start, end);
+
+ memmove(rec.d.vaLines,
+ LINEREC (pFile->plr, start),
+ cLine * sizeof (LINEREC));
+
+ if (pFile->vaColor != (PVOID)-1L) {
+ rec.d.vaColor = MALLOC (cLine * sizeof (struct colorRecType));
+ memmove(rec.d.vaColor,
+ COLORREC (pFile->vaColor, start),
+ cLine * sizeof (struct colorRecType));
+ } else {
+ rec.d.vaColor = (PVOID)-1;
+ }
+
+ LinkAtHead( vaDelete, &rec, pFile );
+ }
+}
+
+
+
+
+
+/*** LogBoundary - note end of editor function
+*
+* Add one EVENT_BOUNDARY record to head of list. A boundary record signals
+* the end of a Z edit function. If count of undo operations on this file
+* exceeds the max allowed, move the overflow to the dead-record list for
+* eventual discard.
+*
+* If a EVENT_BOUNDARY record is already at the head, do not add another. This
+* allows LogBoundary() to be called at the top loop without generating bogus
+* EVENT_BOUNDARY records.
+*
+*************************************************************************/
+void
+LogBoundary (
+ void
+ )
+{
+ union Rec rec;
+ PVOID vaBound;
+ EVTargs e;
+
+ if (!(FLAGS(pFileHead) & READONLY)) {
+
+ vaBound = pFileHead->vaUndoCur;
+
+ memmove((char *)&rec, vaBound, sizeof (rec));
+
+ rec.b.flags = FLAGS (pFileHead);
+ rec.b.modify = pFileHead->modify;
+ rec.b.flWindow.col = XWIN (pInsCur);
+ rec.b.flWindow.lin = YWIN (pInsCur);
+ rec.b.flCursor.col = XCUR (pInsCur);
+ rec.b.flCursor.lin = YCUR (pInsCur);
+
+ if (rec.b.op != EVENT_BOUNDARY) {
+
+ vaBound = MALLOC ((long) sizeof (rec));
+
+ rec.b.op = EVENT_BOUNDARY;
+ LinkAtHead( vaBound, &rec, pFileHead );
+
+ (pFileHead->cUndo)++;
+
+ while ( pFileHead->cUndo > cUndo ) {
+ if (FreeUndoRec(TAIL,pFileHead) == EVENT_BOUNDARY) {
+ pFileHead->cUndo--;
+ }
+ }
+
+ } else {
+
+ e.arg.pUndoRec = &rec;
+ DeclareEvent (EVT_EDIT, &e);
+ memmove(vaBound, (char *) &rec.b, sizeof (rec.b));
+ }
+ }
+}
+
+
+
+
+
+/*** FreeUndoRec - move record to dead-record list
+*
+* Pick off one record from the Head of the list, or the tail of the list and
+* place it in the dead-record list. Return the .op of the next undo record.
+*
+* Input:
+* fHead = TRUE -> place at head of list
+* pFile = file to work on
+*
+*************************************************************************/
+int
+FreeUndoRec (
+ flagType fHead,
+ PFILE pFile
+ )
+{
+ PVOID vaNext;
+ PVOID vaRem;
+
+ /*
+ * Get the dead record, and move up the list (if at head), or truncate the list
+ * if at tail.
+ */
+ vaRem = fHead ? pFile->vaUndoHead : pFile->vaUndoTail;
+
+ if (fHead) {
+ vaNext = pFile->vaUndoHead = ((union Rec *)vaRem)->b.blink;
+ } else {
+ vaNext = pFile->vaUndoTail = ((union Rec *)vaRem)->b.flink;
+ }
+
+ /*
+ * Update the links in the newly exposed (head or tail) record.
+ */
+ if (fHead) {
+ ((union Rec *)vaNext)->b.flink = (PVOID)-1;
+ } else {
+ ((union Rec *)vaNext)->b.blink = (PVOID)-1;
+ }
+
+ EnterCriticalSection(&UndoCriticalSection);
+ /*
+ * Update the removed record to properly live in the dead list
+ */
+ ((union Rec *)vaRem)->b.blink = vaDead;
+ vaDead = vaRem;
+
+
+ LeaveCriticalSection(&UndoCriticalSection);
+
+ return ((union Rec *)vaNext)->b.op;
+}
+
+
+
+
+
+/*** UnDoRec - undo an editting action
+*
+* Reverse the action of the current undo record for the file. Do not log the
+* change. Return the type of the next record.
+*
+* Input:
+* pFile = file being operated on
+*
+*************************************************************************/
+int
+UnDoRec (
+ PFILE pFile
+ )
+{
+ union Rec *rec;
+ LINEREC vlCur;
+ struct colorRecType vcCur;
+ EVTargs e; /* event notification params */
+
+ rec = (union Rec *)(pFile->vaUndoCur);
+
+ e.arg.pUndoRec = rec;
+ DeclareEvent (EVT_UNDO, &e);
+
+ switch (rec->b.op) {
+
+ case EVENT_REPLACE:
+ /*
+ * Swap the line in the file with the line in the replace record.
+ */
+ memmove((char *)&vlCur,
+ LINEREC (pFile->plr, rec->r.line),
+ sizeof (vlCur));
+
+ memmove(LINEREC (pFile->plr, rec->r.line),
+ (char *)&rec->r.vLine,
+ sizeof (rec->r.vLine));
+
+ /* Do the same for the color.
+ *
+ */
+ if (pFile->vaColor != (PVOID)-1L) {
+
+ memmove((char *)&vcCur,
+ COLORREC (pFile->vaColor, rec->r.line),
+ sizeof (vcCur));
+
+ memmove(COLORREC (pFile->vaColor, rec->r.line),
+ (char *)&rec->r.vColor,
+ sizeof (rec->r.vColor));
+ }
+
+ rec->r.vLine = vlCur;
+ pFile->cLines = rec->r.length;
+ AckReplace( rec->r.line, TRUE );
+ PutMarks( pFile, rec->r.vaMarks, rec->r.line );
+ break;
+
+ case EVENT_INSERT:
+ /* delete the blank(!) lines that are present
+ */
+ DelLine( FALSE, pFile, rec->i.line, rec->i.line + rec->i.cLine - 1);
+ pFile->cLines = rec->i.length;
+ break;
+
+ case EVENT_DELETE:
+ /* insert a range of blank lines
+ * copy the linerecs from the stored location to the blank area
+ */
+ InsLine( FALSE, rec->d.line, rec->d.cLine, pFile );
+ memmove(LINEREC (pFile->plr, rec->d.line),
+ rec->d.vaLines,
+ (long)rec->d.cLine * sizeof (LINEREC));
+
+ if (pFile->vaColor != (PVOID)-1L) {
+
+ memmove(COLORREC (pFile->vaColor, rec->d.line),
+ rec->d.vaColor,
+ (long)rec->d.cLine * sizeof (struct colorRecType));
+ }
+
+ pFile->cLines = rec->d.length;
+ PutMarks (pFile, rec->d.vaMarks, rec->d.line);
+ break;
+ }
+
+ pFile->vaUndoCur = rec->i.blink;
+ return ((union Rec *)(pFile->vaUndoCur))->i.op;
+}
+
+
+
+
+/*** ReDoRec - redo editting action
+*
+* Repeat the action of the current undo record for a file. Do not log the
+* change.
+*
+* Input:
+* pFile = file to operate on
+*
+* Output:
+* Returns the type of record undone.
+*
+*************************************************************************/
+int
+ReDoRec (
+ PFILE pFile
+ )
+{
+ EVTargs e; /* event notification params */
+ union Rec *rec;
+ LINEREC vlCur;
+
+ rec = (union Rec *)(pFile->vaUndoCur);
+
+ e.arg.pUndoRec = rec;
+ DeclareEvent (EVT_UNDO, &e);
+
+ switch (rec->b.op) {
+
+ case EVENT_REPLACE:
+ /*
+ * Swap the line in the file with the line in the replace record.
+ */
+ memmove((char *)&vlCur,
+ LINEREC (pFile->plr, rec->r.line),
+ sizeof (vlCur));
+
+ memmove(LINEREC (pFile->plr, rec->r.line),
+ (char *)&rec->r.vLine,
+ sizeof (rec->r.vLine));
+
+ rec->r.vLine = vlCur;
+ pFile->cLines = rec->r.length;
+ AckReplace (rec->r.line, FALSE);
+ break;
+
+ case EVENT_INSERT:
+ /* Insert lines
+ */
+ InsLine(FALSE, rec->i.line, rec->i.cLine, pFile);
+ pFile->cLines = rec->d.length + rec->i.cLine;
+ break;
+
+ case EVENT_DELETE:
+ /* delete lines
+ */
+ DelLine( FALSE, pFile, rec->d.line, rec->d.line + rec->d.cLine - 1 );
+ pFile->cLines = rec->d.length - rec->d.cLine;
+ break;
+ }
+
+ pFile->vaUndoCur = rec->i.flink;
+ return ((union Rec *)(pFile->vaUndoCur))->i.op;
+}
+
+
+
+
+
+/*** zundo - Undo edit function
+*
+* <undo> - Reverse last edit function ( except undo )
+* <meta><undo> - Repeat previously undone action
+*
+* Input:
+* Standard editting function
+*
+* Output:
+* Returns TRUE if something done.
+*
+*************************************************************************/
+flagType
+zundo (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ )
+{
+ int fTmp;
+ union Rec rec;
+
+ if (!fundoable(fMeta)) {
+ if (!mtest ()) {
+ disperr (fMeta ? MSGERR_REDO : MSGERR_UNDO);
+ }
+ return FALSE;
+ }
+
+ LogBoundary ();
+
+ while ((fMeta ? ReDoRec (pFileHead) : UnDoRec (pFileHead)) != EVENT_BOUNDARY) {
+ ;
+ }
+
+ /*
+ * swap the flags so that traversals up and down the undo list work correctly.
+ * If we now think that the file might not be dirty, check the modification
+ * times as well. (This allows us to retain UNDO histories across file saves,
+ * without erroneously reporting that a file is clean when it is not).
+ * re-display the file.
+ */
+ memmove((char *)&rec, pFileHead->vaUndoCur, sizeof (rec));
+
+ fTmp = FLAGS (pFileHead);
+ rec.b.flags |= FLAGS(pFileHead) & VALMARKS;
+ FLAGS(pFileHead) = rec.b.flags;
+ rec.b.flags = fTmp;
+ SETFLAG (fDisplay, RSTATUS);
+
+ if (!TESTFLAG(FLAGS(pFileHead),DIRTY)
+ && (rec.b.modify != pFileHead->modify)) {
+ SETFLAG(FLAGS(pFileHead),DIRTY);
+ }
+
+ doscreen (rec.b.flWindow.col, rec.b.flWindow.lin, rec.b.flCursor.col, rec.b.flCursor.lin);
+ newscreen ();
+
+ return TRUE;
+
+ argData; pArg;
+}
+
+
+
+
+
+/*** fundoable - return TRUE/FALSE if something is un/redoable
+*
+* Input:
+* fMeta = TRUE -> redo check
+*
+* Output:
+* Returns TRUE is an undo or redo (as selected) can be performed
+*
+*************************************************************************/
+flagType
+fundoable (
+ flagType fMeta
+ )
+{
+ union Rec *rec;
+
+ if (!pFileHead || pFileHead->vaUndoCur == (PVOID)-1L) {
+ return FALSE;
+ }
+
+ rec = (union Rec *)(pFileHead->vaUndoCur);
+
+ if (fMeta && (rec->i.flink == (PVOID)(-1))) {
+ return FALSE;
+ } else if (!fMeta && (rec->i.blink == (PVOID)(-1))) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+
+
+/* fIdleUndo - while MEP is in an idle loop waiting for keystrokes, free
+ * the extra stuff from the dead-record list.
+ *
+ * returns TRUE iff more to free
+ */
+flagType
+fIdleUndo (
+ flagType fAll
+ )
+{
+ int i;
+ union Rec *rec;
+ LINEREC vLine;
+ flagType MoreToFree;
+ PVOID p;
+
+ EnterCriticalSection(&UndoCriticalSection);
+
+ // DUMPIT(vaDead, "\n\n***** In fIdleUndo\n");
+
+ /*
+ * if there is a dead list then
+ */
+ while (vaDead != (PVOID)(-1L)) {
+
+ rec = (union Rec *)vaDead;
+
+ /*
+ * Free stored lines(s)
+ */
+ switch (rec->b.op) {
+
+ case EVENT_REPLACE:
+ if (rec->r.vLine.Malloced) {
+ rec->r.vLine.Malloced = FALSE;
+ FREE(rec->r.vLine.vaLine);
+ rec->r.vLine.vaLine = (PVOID)-1L;
+ }
+ break;
+
+ case EVENT_DELETE:
+ BlankLines (rec->d.cLine, rec->d.vaLines);
+ for (i = 0; i < rec->d.cLine; i++) {
+ memmove((char *)&vLine, LINEREC(rec->d.vaLines,i), sizeof(vLine));
+ if (vLine.Malloced) {
+ vLine.Malloced = FALSE;
+ FREE (vLine.vaLine);
+ vLine.vaLine = (PVOID)-1L;
+ }
+ }
+ FREE (rec->d.vaLines);
+ break;
+
+ case EVENT_INSERT:
+ break;
+ }
+
+ /*
+ * free dead record.
+ */
+ p = vaDead;
+ vaDead = rec->b.blink;
+
+ FREE (p);
+
+
+ if (!fAll) {
+ break;
+ }
+ }
+
+ MoreToFree = (flagType)(vaDead != (PVOID)(-1L));
+
+ LeaveCriticalSection(&UndoCriticalSection);
+
+ return MoreToFree;
+
+}
+
+
+
+
+
+/* FlushUndo - Toss all unneeded undo records.
+ */
+void
+FlushUndoBuffer (
+ void
+ )
+{
+ PFILE pFile = pFileHead;
+
+ while (pFile) {
+ RemoveUndoList (pFile);
+ pFile = pFile->pFileNext;
+ }
+ fIdleUndo (TRUE);
+}
+
+
+
+
+
+/* RemoveUndoList - transfer undolist to end of the dead list.
+ */
+void
+RemoveUndoList (
+ PFILE pFile
+ )
+{
+
+ if (pFile->vaUndoTail != (PVOID)-1L) {
+
+ EnterCriticalSection(&UndoCriticalSection);
+
+ ((union Rec *)(pFile->vaUndoTail))->b.blink = vaDead;
+ vaDead = pFile->vaUndoHead;
+
+ LeaveCriticalSection(&UndoCriticalSection);
+
+ }
+ pFile->vaUndoHead = pFile->vaUndoTail = pFile->vaUndoCur = (PVOID)-1L;
+ pFile->cUndo = 0;
+}
+
+
+
+#ifdef DEBUG
+void
+UNDODUMP (
+ PVOID vaCur,
+ char *Stuff
+ )
+{
+ union Rec rec;
+
+ char DbgBuffer[256];
+
+
+ if (vaCur != (PVOID)-1) {
+ OutputDebugString (Stuff);
+ OutputDebugString("=============================================\n");
+ }
+
+ while (vaCur != (PVOID)-1L) {
+ memmove((char *)&rec, vaCur, sizeof (rec));
+ sprintf(DbgBuffer, "\nUndo Record at va = %X\n",vaCur);
+ OutputDebugString(DbgBuffer);
+ sprintf(DbgBuffer, " flink = %X\n",rec.b.flink);
+ OutputDebugString(DbgBuffer);
+ sprintf(DbgBuffer, " blink = %X\n",rec.b.blink);
+ OutputDebugString(DbgBuffer);
+
+ switch (rec.b.op) {
+
+ case EVENT_BOUNDARY:
+ OutputDebugString(" Operation = BOUNDARY\n");
+ sprintf(DbgBuffer," yW, xW, yC, xC = %ld, %d, %ld, %d\n",
+ rec.b.flWindow.lin, rec.b.flWindow.col, rec.b.flCursor.lin, rec.b.flCursor.col);
+ OutputDebugString(DbgBuffer);
+ sprintf(DbgBuffer, " flags = %X\n",rec.b.flags);
+ OutputDebugString(DbgBuffer);
+ break;
+
+ case EVENT_REPLACE:
+ OutputDebugString(" Operation = REPLACE\n");
+ sprintf(DbgBuffer, " line & length = %ld & %ld\n", rec.r.line, rec.r.length);
+ OutputDebugString(DbgBuffer);
+ sprintf(DbgBuffer, " vLine = va:%X cb:%d\n",rec.r.vLine.vaLine,
+ rec.r.vLine.cbLine);
+ OutputDebugString(DbgBuffer);
+ break;
+
+ case EVENT_INSERT:
+ OutputDebugString(" Operation = INSERT\n");
+ sprintf(DbgBuffer, " line & length = %ld & %ld\n", rec.i.line, rec.i.length);
+ OutputDebugString(DbgBuffer);
+ sprintf(DbgBuffer, " cLine = %ld\n",rec.i.cLine);
+ OutputDebugString(DbgBuffer);
+ break;
+
+ case EVENT_DELETE:
+ OutputDebugString(" Operation = DELETE\n");
+ sprintf(DbgBuffer, " line & length = %ld & %ld\n", rec.d.line, rec.d.length);
+ OutputDebugString(DbgBuffer);
+ sprintf(DbgBuffer, " cLine = %ld\n",rec.d.cLine);
+ OutputDebugString(DbgBuffer);
+ sprintf(DbgBuffer, " vaLines = %X\n",rec.d.vaLines);
+ OutputDebugString(DbgBuffer);
+ break;
+ }
+
+ vaCur = rec.b.blink;
+ }
+
+}
+#endif
diff --git a/private/utils/mep/src/untab.c b/private/utils/mep/src/untab.c
new file mode 100644
index 000000000..50e99118f
--- /dev/null
+++ b/private/utils/mep/src/untab.c
@@ -0,0 +1,330 @@
+#include <string.h>
+#include <stdlib.h>
+#include "mep.h"
+
+extern int fileTab;
+extern flagType fRealTabs;
+
+
+/***************************************************************************\
+
+MEMBER: Untab
+
+SYNOPSIS: Expand tabs in line
+
+ALGORITHM:
+
+ARGUMENTS: int - number of characters per tab
+ const char* - pointer to source line
+ int - number of chars in source line
+ char* - pointer to destination line
+ char - replacement character for tab
+
+RETURNS: int - length of untabbed line
+
+NOTES:
+
+HISTORY: 13-Jul-90 davegi
+ Saved pDst and computed return value from it rather tha pDst
+ 28-Jul-90 davegi
+ Converted from 286 MASM
+ 18-Mar-1992 markz
+ Untab at most BUFLEN chars
+
+KEYWORDS:
+
+SEEALSO:
+
+\***************************************************************************/
+
+int
+Untab (
+ int cbTab,
+ const char* pSrc,
+ int cbSrc,
+ char* pDst,
+ char cTab
+ )
+{
+
+ const char* pSrcStart;
+ const char* pDstStart;
+ int i;
+ int ccTab;
+ char buffer[128];
+
+ assert( pSrc );
+ assert( pDst );
+
+ if (( size_t )strlen(pSrc) != ( size_t ) cbSrc ) {
+ sprintf(buffer, "\nWARNING: strlen(pSrc) [%d] != cbSrc [%d]\n", strlen(pSrc), cbSrc);
+ OutputDebugString(buffer);
+ sprintf(buffer, "File %s, line %d\n", __FILE__, __LINE__ );
+ OutputDebugString(buffer);
+ cbSrc = (int)strlen(pSrc);
+ }
+
+ // assert( strlen( pSrc ) >= ( size_t ) cbSrc );
+
+ // Short circuit...
+ // If there are no tabs in the source, copy the source to the destination
+ // and return the supplied number of characters in the source (destination)
+
+ if( ! strchr( pSrc, '\t' )) {
+ strcpy( pDst, pSrc );
+ return cbSrc;
+ }
+
+ // Remember where we started
+
+ pSrcStart = pSrc;
+ pDstStart = pDst;
+
+ // While we are not at the end of the source copy a character from the
+ // source to the destination
+
+ while (*pSrc && pDst < pDstStart + BUFLEN - 1) {
+ if (( *pDst++ = *pSrc++ ) == '\t' ) {
+
+ // If the character copied was a tab, replace it with the
+ // appropriate number of cTab characters
+
+ pDst--;
+ ccTab = cbTab - (( pDst - pDstStart ) % cbTab );
+
+ for( i = 0; i < ccTab && pDst < pDstStart + BUFLEN - 1; i++ ) {
+ *pDst++ = cTab;
+ }
+ }
+ }
+
+ *pDst = '\0'; // Terminating NUL
+
+ //return strlen( pDstStart );
+ return pDst - pDstStart;
+}
+
+
+
+
+
+/***************************************************************************\
+
+MEMBER: AlignChar
+
+SYNOPSIS: Get logical starting column of character
+
+ALGORITHM:
+
+ARGUMENTS: COL -
+ const char* -
+
+RETURNS: COL - starting column of character
+
+NOTES:
+
+HISTORY:
+ 03-Jul-91 ramonsa
+ re-converted from 286 MASM
+ 20-Aug-90 davegi
+ Return the supplied column when end of buffer is reached
+ 14-Aug-90 davegi
+ Return supplied column when it's passed the end of the buf
+ 28-Jul-90 davegi
+ Converted from 286 MASM\
+
+KEYWORDS:
+
+SEEALSO:
+
+\***************************************************************************/
+
+COL
+AlignChar (
+ COL col,
+ const char* buf
+ )
+{
+ register int CurCol;
+ register int NextCol;
+ int NewCurCol;
+ char Char;
+
+
+ CurCol = col;
+
+ //
+ // If we are not using real tabs, we just return supplied column,
+ // otherwise we figure out the column position.
+ //
+ if ( fRealTabs ) {
+
+ NextCol = 0;
+
+ while ( NextCol <= col ) {
+
+ Char = *buf++;
+
+ if ( Char == '\0' ) {
+ //
+ // Reached end of file, return the supplied column
+ //
+ CurCol = col;
+ break;
+ }
+
+ CurCol = NextCol;
+
+ if ( Char == '\t' ) {
+
+ NewCurCol = NextCol;
+
+ CurCol += fileTab;
+
+ NextCol = CurCol - ( CurCol % fileTab);
+
+ CurCol = NewCurCol;
+
+ } else {
+
+ NextCol++;
+
+ }
+ }
+ }
+
+ return CurCol;
+
+}
+
+
+
+
+/***************************************************************************\
+
+MEMBER: pLog
+
+SYNOPSIS: Return a physical pointer given a logical offset
+
+ALGORITHM:
+
+ARGUMENTS:
+
+RETURNS: char* - pointer into pBuf
+
+NOTES: This is a many to one mapping due to tabs. That is, many logical
+ offsets may point to the same physical pointer if they point
+ to within a fileTab of a tab character.
+
+HISTORY: 13-Aug-90 davegi
+ Fixed return value when no tabs are present in line
+ Fixed return value when first char is a tab
+ 10-Aug-90 davegi
+ Fixed return value when xOff is negative
+ 28-Jul-90 davegi
+ Converted from 286 MASM
+
+KEYWORDS:
+
+SEEALSO:
+
+\***************************************************************************/
+
+char*
+pLog (
+ char* pBuf,
+ int xOff,
+ flagType fBound
+ )
+{
+
+ REGISTER char *pLast;
+ REGISTER int cbpBuf;
+ int cbpBufNext;
+
+ assert( pBuf );
+
+ // If xOff is 0 return pBuf
+
+ if( xOff == 0 ) {
+ return pBuf;
+ }
+
+ // If xOff is negative return pBuf - 1
+
+ if( xOff < 0 ) {
+ return pBuf - 1;
+ }
+
+ // If we're not using real tabs, return the physical pointer which is
+ // at the (possibly bounded) logical offset
+
+ if( ! fRealTabs ) {
+
+ // If required, bound the return value by the line length
+
+ if( fBound ) {
+ xOff = min(( size_t ) xOff, strlen( pBuf ));
+ }
+
+ return ( char* ) &( pBuf[ xOff ]);
+ }
+
+ if( ! strchr( pBuf, '\t' )) {
+
+ // If xOff is past the end of the line,
+ // return the physical pointer which is at the (possibly bounded)
+ // logical offset
+
+ if( xOff > ( cbpBuf = strlen( pBuf ))) {
+ if( fBound ) {
+ xOff = cbpBuf;
+ }
+ }
+ return ( char* ) &( pBuf[ xOff ]);
+ }
+
+
+ // pLast: last physical position in buffer;
+ // cbpBuf: Last LOGICAL offset within buffer;
+ // cbpNext: Next LOGICAL offset within buffer
+ // (i.e. cbpBuf + tab)
+
+
+ pLast = pBuf;
+ cbpBuf = 0;
+ while (pBuf = strchr(pBuf, '\t')) {
+ cbpBuf += pBuf - pLast;
+ if (xOff < cbpBuf) {
+ /*
+ * We're past the wanted column. Adjust and return
+ * pointer.
+ */
+ cbpBuf -= (pBuf - pLast);
+ return (char *)pLast + xOff - cbpBuf;
+ }
+ cbpBufNext = cbpBuf + fileTab - (cbpBuf + fileTab)%fileTab;
+ if ((cbpBuf <= xOff) && (xOff < cbpBufNext)) {
+ /*
+ * Wanted column lies within this tab. return current
+ * position.
+ */
+ return (char *)pBuf;
+ }
+ pLast = ++pBuf; // Skip this tab and continue
+ cbpBuf = cbpBufNext;
+ }
+
+ // No more tabs in buffer. If wanted column is past the end of the
+ // buffer, return pointer based on fBound. Otherwise the
+ // physical column is (xOff - cbpBuf) positions from pLast.
+
+ pBuf = pLast + strlen(pLast);
+ cbpBufNext = cbpBuf + pBuf - pLast;
+ if (xOff > cbpBufNext) {
+ if (fBound) {
+ return (char *)pBuf;
+ }
+ }
+ return (char *)pLast + xOff - cbpBuf;
+}
diff --git a/private/utils/mep/src/window.c b/private/utils/mep/src/window.c
new file mode 100644
index 000000000..60bc9ec51
--- /dev/null
+++ b/private/utils/mep/src/window.c
@@ -0,0 +1,526 @@
+/**** window.c - window movement commands
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+*
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+
+#include "mep.h"
+
+#define DEBFLAG WINDOW
+
+
+void
+saveflip (
+ void
+ )
+{
+ XOLDCUR(pInsCur) = XCUR(pInsCur);
+ YOLDCUR(pInsCur) = YCUR(pInsCur);
+ XOLDWIN(pInsCur) = XWIN(pInsCur);
+ YOLDWIN(pInsCur) = YWIN(pInsCur);
+}
+
+
+
+
+
+void
+restflip (
+ void
+ )
+{
+ doscreen( XOLDWIN(pInsCur), YOLDWIN(pInsCur),
+ XOLDCUR(pInsCur), YOLDCUR(pInsCur) );
+}
+
+
+
+
+
+void
+movewin (
+ COL x,
+ LINE y
+ )
+{
+ doscreen( x, y, XCUR(pInsCur), YCUR(pInsCur) );
+}
+
+
+
+
+
+flagType
+setwindow (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ )
+{
+ switch (pArg->argType) {
+
+ case NOARG:
+ if (fMeta) {
+ soutb (0, (int)(YCUR(pInsCur)-YWIN(pInsCur)), rgchEmpty, fgColor);
+ redraw (pFileHead, YCUR(pInsCur), YCUR(pInsCur));
+ SETFLAG( fDisplay, RCURSOR );
+ } else {
+ newscreen ();
+ SETFLAG( fDisplay, RSTATUS | RCURSOR );
+ }
+ return TRUE;
+
+ /* TEXTARG illegal */
+
+ case NULLARG:
+ movewin (XCUR(pInsCur), YCUR(pInsCur));
+ return TRUE;
+
+ /* LINEARG illegal */
+ /* STREAMARG illegal */
+ /* BOXARG illegal */
+
+ }
+
+ argData;
+}
+
+
+
+
+flagType
+plines (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ )
+{
+ buffer mbuf;
+
+ switch (pArg->argType) {
+
+ case NOARG:
+ movewin (XWIN(pInsCur), YWIN(pInsCur) + YSCALE (vscroll));
+ return TRUE;
+
+ case TEXTARG:
+ strcpy ((char *) mbuf, pArg->arg.textarg.pText);
+ if (fIsNum (mbuf)) {
+ movewin ( XWIN(pInsCur), YWIN(pInsCur) + atol (mbuf));
+ return TRUE;
+ } else {
+ return BadArg ();
+ }
+
+ case NULLARG:
+ movewin( XWIN(pInsCur), YCUR(pInsCur) );
+ return TRUE;
+
+ /* LINEARG illegal */
+ /* STREAMARG illegal */
+ /* BOXARG illegal */
+
+ }
+
+ argData; fMeta;
+}
+
+
+
+
+flagType
+mlines (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ )
+{
+ buffer mbuf;
+
+ switch (pArg->argType) {
+
+ case NOARG:
+ movewin (XWIN(pInsCur), YWIN(pInsCur) - YSCALE (vscroll));
+ return TRUE;
+
+ case TEXTARG:
+ strcpy ((char *) mbuf, pArg->arg.textarg.pText);
+ if (fIsNum (mbuf)) {
+ movewin (XWIN(pInsCur), YWIN(pInsCur) - atol (mbuf));
+ return TRUE;
+ } else {
+ return BadArg ();
+ }
+
+ case NULLARG:
+ movewin (XWIN(pInsCur), YCUR(pInsCur)-(WINYSIZE(pWinCur)-1));
+ return TRUE;
+
+ /* LINEARG illegal */
+ /* STREAMARG illegal */
+ /* BOXARG illegal */
+
+ }
+
+ argData; fMeta;
+}
+
+
+
+
+
+/*
+ * <window> Move to next window
+ * <arg><window> split window horizontal
+ * <arg><arg><window> split window vertical
+ * <meta><window> close/merge current window
+ *
+ * CW: needs this hack
+ * <arg><meta><window> Move to previous window
+ */
+flagType
+window (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ )
+{
+ int i, v;
+ flagType fVert = TRUE;
+
+ v = TRUE;
+
+ switch (pArg->argType) {
+
+ case NOARG:
+ /* change current window */
+ if (cWin != 1) {
+ if (fMeta) {
+ /* <meta><window> - close current window. Scan for window
+ * that is adjacent to iCurWin
+ */
+ if (!WinClose (iCurWin)) {
+ printerror ("Cannot close this window");
+ return FALSE;
+ }
+ } else {
+ /* select next window */
+ iCurWin = (iCurWin + 1) % cWin;
+ }
+
+ v = SetWinCur (iCurWin);
+ } else {
+ v = FALSE;
+ }
+ break;
+
+ case NULLARG:
+ if (cWin == MAXWIN) {
+ printerror ("Too many windows");
+ return FALSE;
+ }
+
+ if (pArg->arg.nullarg.cArg == 1) {
+ i = pArg->arg.nullarg.y - YWIN (pInsCur);
+ fVert = FALSE;
+ } else {
+ i = pArg->arg.nullarg.x - XWIN(pInsCur);
+ }
+
+ if (!SplitWnd (pWinCur, fVert, i)) {
+ return FALSE;
+ }
+
+ // docursor (XWIN(pInsCur), YWIN(pInsCur));
+ break;
+ }
+
+ newscreen ();
+ SETFLAG (fDisplay, RCURSOR|RSTATUS);
+ DoDisplay();
+ return (flagType)v;
+
+ argData;
+}
+
+
+
+
+
+/*** SplitWnd - Creates a new window by splitting an existing window
+*
+* Purpose:
+*
+* When the user asks to split a window, this is called. It does
+* everything after the split location is known.
+*
+* Input:
+* Parameters:
+* pWnd -> Window to split
+* fVert -> TRUE for vertical split, FALSE for horizontal
+* pos -> Window relative offset to split at
+*
+* Globals:
+* fZoomed -> To prevent splitting a zoomed window
+*
+* Output:
+*
+* Returns TRUE if we split, FALSE otherwise.
+*
+*************************************************************************/
+flagType
+SplitWnd (
+ PWND pWnd,
+ flagType fVert,
+ int pos
+ )
+{
+ PINS pInsTmp;
+ PINS pInsNext;
+ struct windowType winTmp;
+ LINE Line, LineWin;
+ LINE NewLineWin;
+ COL Col;
+
+ winTmp = *pWnd;
+ Line = YCUR(pInsCur);
+ Col = XCUR(pInsCur);
+ LineWin = YWIN(pInsCur);
+ NewLineWin = (Line == 0) ? Line : Line - 1;
+
+ if (!fVert) {
+ if (pos < 5 || WINYSIZE(pWnd) - pos < 5) {
+ printerror ("Window too small to split");
+ return FALSE;
+ }
+
+ /*
+ * new y size is remainder of window
+ * old y size is reduced by the new window and separator
+ * new y position is just below new separator
+ */
+ YWIN(pInsCur) = NewLineWin;
+ winTmp.Size.lin = WINYSIZE(pWnd) - pos - 2;
+ WINYSIZE(pWnd) -= winTmp.Size.lin + 1;
+ winTmp.Pos.lin = WINYPOS(pWnd) + WINYSIZE(pWnd) + 1;
+
+ } else {
+ if (pos < 10 || WINXSIZE(pWnd) - pos < 10) {
+ printerror ("Window too small to split");
+ return FALSE;
+ }
+
+ YWIN(pInsCur) = NewLineWin;
+ newwindow ();
+ winTmp.Size.col = WINXSIZE(pWnd) - pos - 2;
+ WINXSIZE(pWnd) -= winTmp.Size.col + 1;
+ winTmp.Pos.col = WINXPOS(pWnd) + WINXSIZE(pWnd) + 1;
+ }
+
+ //
+ // Allocate and set up the new current instance for this window.
+ // Set the new cursor position to home
+ //
+ pInsTmp = (PINS) ZEROMALLOC (sizeof (*pInsTmp));
+ *pInsTmp = *pInsCur;
+
+ winTmp.pInstance = pInsTmp;
+
+ //
+ // Walk the old instance list, and copy it to the new instance list
+ //
+ pInsNext = pInsCur;
+ while (pInsNext = pInsNext->pNext) {
+ pInsTmp->pNext = (PINS) ZEROMALLOC (sizeof (*pInsTmp));
+ pInsTmp = pInsTmp->pNext;
+ *pInsTmp = *pInsNext;
+ }
+ pInsTmp->pNext = NULL;
+ WinList[cWin++] = winTmp;
+ IncFileRef (pFileHead);
+ SortWin ();
+ YCUR(pInsCur) = Line;
+ XCUR(pInsCur) = Col;
+ YWIN(pInsCur) = LineWin;
+ return TRUE;
+}
+
+
+
+
+
+/* SortWin - sort window list based upon position on screen
+ */
+void
+SortWin (
+ void
+ )
+{
+ struct windowType winTmp;
+ int i, j;
+
+ for (i = 0; i < cWin; i++) {
+ for (j = i+1; j < cWin; j++) {
+ if (WinList[j].Pos.lin < WinList[i].Pos.lin ||
+ (WinList[j].Pos.lin == WinList[i].Pos.lin &&
+ WinList[j].Pos.col < WinList[i].Pos.col)) {
+ if (iCurWin == i) {
+ pWinCur = &WinList[iCurWin = j];
+ }
+ winTmp = WinList[i];
+ WinList[i] = WinList[j];
+ WinList[j] = winTmp;
+ }
+ }
+ }
+}
+
+
+
+
+
+
+/* SetWinCur - Set current window
+ *
+ * Entry:
+ * iWin = index to new current window.
+ */
+flagType
+SetWinCur (
+ int iWin
+ )
+{
+ iCurWin = iWin;
+ pWinCur = &WinList[iWin];
+ pInsCur = pWinCur->pInstance;
+
+ /*
+ * If we cannot change to the current file, we will walk the window instance
+ * list until we get a valid file. If no one can be loaded then we switch to
+ * the <untitled> pseudo-file.
+ * NB: fChangeFile does a RemoveTop so we don't need to move pInsCur
+ */
+ while ((pInsCur != NULL) && (!fChangeFile (FALSE, pInsCur->pFile->pName))) {
+ ;
+ }
+
+ if (pInsCur == NULL) {
+ fChangeFile (FALSE, rgchUntitled);
+ }
+ return (flagType)(pInsCur != NULL);
+}
+
+
+
+
+
+/* Adjacent - return true if two windows are adjacent to each other
+ *
+ * Adjacent returns true if window i is to the left or above window j
+ * and exactly matches some size attributes
+ */
+flagType
+Adjacent (
+ int i,
+ int j
+ )
+{
+ REGISTER PWND pWini = &WinList[i];
+ REGISTER PWND pWinj = &WinList[j];
+
+ if (WINYSIZE(pWini) == WINYSIZE(pWinj) &&
+ WINYPOS(pWini) == WINYPOS(pWinj) &&
+ (WINXPOS(pWini) + WINXSIZE(pWini) + 1 == WINXPOS(pWinj) ||
+ WINXPOS(pWinj) + WINXSIZE(pWinj) + 1 == WINXPOS(pWini))) {
+ return TRUE;
+ } else {
+ return (flagType)
+ (WINXSIZE(pWini) == WINXSIZE(pWinj) &&
+ WINXPOS(pWini) == WINXPOS(pWinj) &&
+ (WINYPOS(pWini) + WINYSIZE(pWini) + 1 == WINYPOS(pWinj) ||
+ WINYPOS(pWinj) + WINYSIZE(pWinj) + 1 == WINYPOS(pWini)));
+ }
+}
+
+
+
+
+
+
+/* WinClose - close a window.
+ *
+ * We walk the entire window list trying to find another window that
+ * is adjacent to the specified window. When found, we free all data relevant
+ * to the specified window and expand the found window to encompass the
+ * new region.
+ *
+ * j window to be closed
+ *
+ * returns TRUE iff window was closed
+ */
+flagType
+WinClose (
+ int j
+ )
+{
+ PINS pInsTmp;
+ PINS pInsNext;
+ REGISTER PWND pWini;
+ REGISTER PWND pWinj = &WinList[j];
+ int i;
+
+ /* Find adjacent window
+ */
+ for (i = 0; i < cWin; i++) {
+ if (Adjacent (i, j)) {
+ break;
+ }
+ }
+
+ /* No adjacent window found
+ */
+ if (i == cWin) {
+ return FALSE;
+ }
+
+ pWini = &WinList[i];
+
+ /* Free up all those instances
+ */
+ pInsTmp = pWinj->pInstance;
+ while (pInsTmp != NULL) {
+
+ /*
+ * we decrement the ref count here, without using DecFileRef, so that the file
+ * will NOT be removed by having a zero reference count. This allows it to
+ * live, unreferenced, in the file list, even if it is dirty. That allows us
+ * to close any window that has dirty files associated with it.
+ */
+ pInsTmp->pFile->refCount--;
+ pInsNext = pInsTmp;
+ pInsTmp = pInsTmp->pNext;
+ FREE ((char *) pInsNext);
+ }
+
+ /* Expand pWini to encompass pWinj
+ */
+ if (WINYPOS(pWinj) == WINYPOS(pWini)) {
+ WINXSIZE(pWini) += WINXSIZE(pWinj) + 1;
+ } else {
+ WINYSIZE(pWini) += WINYSIZE(pWinj) + 1;
+ }
+ WINXPOS(pWini) = min (WINXPOS(pWinj), WINXPOS(pWini));
+ WINYPOS(pWini) = min (WINYPOS(pWinj), WINYPOS(pWini));
+ memmove ((char *)&WinList[j], (char *)&WinList[j+1], (cWin-j-1) * sizeof (WinList[0]));
+ if (i > j) {
+ i--;
+ }
+ pWinCur = &WinList[iCurWin = i];
+ cWin--;
+ SortWin ();
+ return TRUE;
+}
diff --git a/private/utils/mep/src/word.c b/private/utils/mep/src/word.c
new file mode 100644
index 000000000..ee89d1752
--- /dev/null
+++ b/private/utils/mep/src/word.c
@@ -0,0 +1,129 @@
+/*** word.c - movement by words
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+#include "mep.h"
+
+#define ISWORD(c) (flagType)((isalnum(c) || isxdigit(c) || c == '_' || c == '$'))
+
+flagType fWordMeta;
+
+
+/*** fDoWord - Checks for beginning or end of word during fScan.
+*
+* Checks the character at flScan and the previous character for a change
+* between ISWORD and !ISWORD. This finds:
+*
+* ISWORD -> !ISWORD ==> Just after end of a word
+* !ISWORD -> ISWORD ==> First character of word.
+*
+* Normally returns TRUE for first character. If fWordMeta, returns TRUE for
+* end of word. fWordMeta holds <meta>, so <meta><xword> functions move to
+* end of word, while <xword> functions move to the beginning.
+*
+* Exception: if current character is last on the line and fWordMeta is set,
+* we return TRUE and move the cursor one character to the right.
+*
+* Globals:
+* scanbuf - Detabbed text of line being scanned.
+* scanlen - Index of last character in scanbuf
+* fWordMeta - Value of fMeta when editor function was invoked
+*
+* Outputs:
+* Returns if (fWordMeta)
+* TRUE - character at (flScan.col, flScan.lin) begins a word
+* FALSE - Otherwise
+* else
+* TRUE - character at (flScan.col - 1, flScan.lin) ends a word
+* FALSE - Otherwise
+*
+* Moves cursor before returning TRUE
+*
+*************************************************************************/
+flagType
+fDoWord (
+ void
+ )
+{
+ if (!fWordMeta) {
+ if (ISWORD (scanbuf[flScan.col]) && (flScan.col == 0 || !ISWORD (scanbuf[flScan.col-1]))) {
+ cursorfl (flScan);
+ return TRUE;
+ }
+ } else if (flScan.col > 0 && ISWORD (scanbuf[flScan.col-1])) {
+ if (!ISWORD (scanbuf[flScan.col])) {
+ cursorfl (flScan);
+ return TRUE;
+ } else if (flScan.col == scanlen) {
+ docursor (flScan.col+1, flScan.lin);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+
+
+
+/*** pword - move forward one word
+*
+* Input:
+* Standard Editting Function
+*
+* Output:
+* Returns TRUE on cursor moved
+*
+*************************************************************************/
+flagType
+pword (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ )
+{
+ fl flCur;
+
+ flCur = pInsCur->flCursorCur;
+ fWordMeta = fMeta;
+ setAllScan (TRUE);
+ fScan (flCur, FNADDR(fDoWord), TRUE, FALSE);
+ return (flagType)((flCur.col != XCUR(pInsCur)) || (flCur.lin != YCUR(pInsCur)));
+
+ argData; pArg;
+}
+
+
+
+
+
+/*** mword - move backwards one word
+*
+* Input:
+* Standard Editting Function
+*
+* Output:
+* Returns TRUE on cursor moved
+*
+*************************************************************************/
+flagType
+mword (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ )
+{
+ fl flCur;
+
+ flCur = pInsCur->flCursorCur;
+ fWordMeta = fMeta;
+ setAllScan (FALSE);
+ fScan (flCur, FNADDR(fDoWord), FALSE, FALSE);
+ return (flagType)((flCur.col != XCUR(pInsCur)) || (flCur.lin != YCUR(pInsCur)));
+
+ argData; pArg;
+}
diff --git a/private/utils/mep/src/z19.c b/private/utils/mep/src/z19.c
new file mode 100644
index 000000000..64fdd073c
--- /dev/null
+++ b/private/utils/mep/src/z19.c
@@ -0,0 +1,114 @@
+/* z19.c - Terminal dependent output routines.
+*
+* Modifications:
+*
+* 26-Nov-1991 mz Strip near/far
+*
+*************************************************************************/
+
+#include "mep.h"
+
+
+#define DEBFLAG Z19
+
+
+
+ULONG
+MepWrite (
+ ULONG Row,
+ ULONG Col,
+ PVOID pBuffer,
+ ULONG BufferSize,
+ DWORD Attr,
+ BOOL BlankToEndOfLine,
+ BOOL ShowIt
+ )
+{
+ ULONG CharactersWritten = 0;
+
+ // EnterCriticalSection( &ScreenCriticalSection );
+
+ if (pBuffer) {
+
+ CharactersWritten = consoleWriteLine( MepScreen,
+ pBuffer,
+ BufferSize,
+ Row,
+ Col,
+ Attr,
+ BlankToEndOfLine );
+
+ }
+
+ //
+ // If we want to update the screen, do it
+ //
+ if (ShowIt)
+ consoleShowScreen( MepScreen );
+
+ // LeaveCriticalSection( &ScreenCriticalSection );
+
+ return CharactersWritten;
+}
+
+
+
+
+/* coutb - output line with color, and blank extension
+ *
+ * Purpose:
+ * outputs a string of characters, utilizing an array of color information and
+ * blank extending the line to the right hand side of the window.
+ *
+ * Entry:
+ * pwnd = pointer to CW window info (CW version only)
+ * x = starting column for output
+ * y = line number to be written
+ * p = pointer to text
+ * c = count of characters in text
+ * colors = pointer to array of color info
+ *
+ * Returns:
+ */
+int
+coutb (
+ int x,
+ int y,
+ char *p,
+ int c,
+ struct lineAttr * colors
+ )
+{
+ int cnt;
+ DWORD clr;
+
+ int x1 = x;
+ char *p1 = p;
+ int c1 = c;
+ struct lineAttr *colors1 = colors;
+
+ if (c1) {
+ do {
+ cnt = min (c1, (int)colors1->len);
+ MepWrite( y,
+ x1,
+ p1,
+ cnt,
+ clr = (DWORD)ColorTab[colors1->attr - isaUserMin],
+ FALSE,
+ FALSE );
+
+ x1 += cnt;
+ p1 += cnt;
+ c1 -= cnt;
+ } while (((colors1++)->len != 0xFF) && (c1 > 0));
+ }
+
+ if (x1 < XSIZE) {
+ MepWrite( y, x1, " ", 1, clr, TRUE, fReDraw );
+ } else {
+ MepWrite( y, x1, NULL, 0, clr, FALSE, fReDraw );
+ }
+
+ return x1;
+}
diff --git a/private/utils/mep/src/zaux.c b/private/utils/mep/src/zaux.c
new file mode 100644
index 000000000..2a66062b3
--- /dev/null
+++ b/private/utils/mep/src/zaux.c
@@ -0,0 +1,510 @@
+/*** zaux.c - helper routines for Z
+*
+* Modifications
+*
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+#define INCL_SUB
+#define INCL_DOSERRORS
+#define INCL_DOSMISC
+
+#include "mep.h"
+#include <stdarg.h>
+#include <errno.h>
+
+/*** ParseCmd - Parse "command" line into two pieces
+*
+* Given a text string, returns a pointer to the first word (non-whitespace)
+* in the text, which is null terminated by this routine, and a pointer to
+* the second word.
+*
+* Input:
+* pText = Pointer to text string
+* ppCmd = Pointer to place to put pointer to first word
+* ppArg = Pointer to place to put pointer to second word
+*
+* Output:
+* Returns nothing. Pointers update, and string possible modified to include
+* null terminator after first word.
+*
+*************************************************************************/
+void
+ParseCmd (
+ char *pText,
+ char **ppCmd,
+ char **ppArg
+ )
+{
+ REGISTER char *pCmd; /* working pointer */
+ REGISTER char *pArg; /* working pointer */
+
+ pArg = whitescan (pCmd = whiteskip (pText));
+ if (*pArg) {
+ *pArg++ = '\0';
+ pArg = whiteskip (pArg);
+ }
+ *ppCmd = pCmd;
+ *ppArg = pArg;
+}
+
+
+
+
+
+char *
+whiteskip (
+ const char *p
+ )
+{
+ return strbskip ((char *)p, (char *)rgchWSpace);
+}
+
+
+
+
+
+char *
+whitescan (
+ const char *p
+ )
+{
+ return strbscan ((char *)p, (char *)rgchWSpace);
+}
+
+
+
+
+
+/*** RemoveTrailSpace - remove trailing white space characters from line
+*
+* Input:
+* p = pointer to line to be stripped.
+*
+* Output:
+* Returns new length of line.
+*
+*************************************************************************/
+int
+RemoveTrailSpace (
+ REGISTER char *p
+ )
+{
+ REGISTER int len = strlen (p);
+
+ while (len && strchr(rgchWSpace,p[len-1])) {
+ len--;
+ }
+
+ p[len] = 0;
+ return len;
+}
+
+
+
+
+/*** DoubleSlashes - given a character string, double all backslashes
+*
+* Input:
+* pbuf = pointer to character buffer
+*
+* Output:
+* Returns pbuf
+*
+*************************************************************************/
+char *
+DoubleSlashes (
+ char * pbuf
+ )
+{
+ REGISTER int l;
+ REGISTER char *p;
+
+ p = pbuf;
+ l = strlen (p);
+ while (l) {
+ if (*p == '\\') {
+ memmove ((char *) (p+1),(char *) p, l+1);
+ *p++ = '\\';
+ }
+ p++;
+ l--;
+ }
+ return pbuf;
+}
+
+
+
+
+
+/*** UnDoubleSlashes - given a character string, un-double all backslashes
+*
+* Input:
+* pbuf = pointer to character buffer
+*
+* Output:
+* Returns pbuf
+*
+*************************************************************************/
+char *
+UnDoubleSlashes (
+ char * pbuf
+ )
+{
+ REGISTER char *p1;
+ REGISTER char *p2;
+
+ p1 = p2 = pbuf;
+ while (*p1) {
+ if ((*p2++ = *p1++) == '\\') {
+ if (*p1 == '\\') {
+ p1++;
+ }
+ }
+ }
+ return pbuf;
+}
+
+
+
+
+/*** fIsNum - see if a string is entirely digits
+*
+* Input:
+* p = pointer to string
+*
+* Output:
+* Returns TRUE if valid number.
+*
+*************************************************************************/
+flagType
+fIsNum (
+ char *p
+ )
+{
+ if (*p == '-') {
+ p++;
+ }
+ return (flagType)(*strbskip (p, "0123456789") == 0);
+}
+
+
+
+
+
+/*** OS2toErrTxt - Get Error Text for OS/2 error
+*
+* Get the error message text for an OS/2 returned error.
+*
+* Input:
+* erc = OS/2 error number
+* buf = location to place the error (BUFSIZE)
+*
+* Output:
+* Returns buf
+*
+*************************************************************************/
+char *
+OS2toErrText (
+ int erc,
+ char * buf
+ )
+{
+
+ sprintf(buf, "Windows error No. %lu", GetLastError());
+ return buf;
+
+ erc;
+}
+
+
+
+
+
+/*** OS2toErrno - Convert OS/2 error code to C runtime error
+*
+* Purpose:
+* Maps errors returned by some OS/2 calls to equivalent C runtime errors,
+* such that routines which differ in OS/2 implementation can return equivalent
+* errors as their DOS counterparts.
+*
+* Input:
+* code = OS/2 returned error code
+*
+* Output:
+* returns a C runtime error constant
+*
+* Exceptions:
+* none
+*
+* Notes:
+* CONSIDER: It's been suggested that this routine, and error message
+* CONSIDER: presentation under OS/2 be changed to use DosGetMessage.
+*
+*************************************************************************/
+int
+OS2toErrno (
+ int code
+ )
+{
+ buffer buf;
+
+ printerror (OS2toErrText (code,buf));
+
+ return code;
+}
+
+
+
+
+union argPrintfType {
+ long *pLong;
+ int *pInt;
+ char **pStr;
+ char **fpStr;
+ };
+
+
+/*** ZFormat - replace the C runtime formatting routines.
+*
+* Purpose:
+*
+* ZFormat is a near-replacement for the *printf routines in the C runtime.
+*
+* Input:
+* pStr - destination string where formatted result is placed.
+* fmt - formatting string. Formats currently understood are:
+* %c single character
+* %[n][l]d %[n][l]x
+* %[m.n]s
+* %[m.n]|{dpfe}F - print drive, path, file, extension
+* of current file.
+* * may be used to copy in values for m and n from arg
+* list.
+* %%
+* arg - is a list of arguments
+*
+* Output:
+*
+* Returns 0 on success, MSGERR_* on failure. The MSGERR_* value may
+* be passed to disperr, as in:
+*
+* if (err = ZFormat (pszUser))
+* disperr (err, pszUser).
+*
+* Note that the error message wants to display the offending string.
+*
+* Currently, the only return value is:
+*
+* MSGERR_ZFORMAT 8020 Unrecognized %% command in '%s'
+*
+*************************************************************************/
+
+int
+ZFormat (
+ REGISTER char *pStr,
+ const REGISTER char *fmt,
+ va_list vl
+ )
+{
+ char c;
+ char * pchar;
+ int * pint;
+
+
+
+ *pStr = 0;
+ while (c = *fmt++) {
+ if (c != '%') {
+ *pStr++ = c;
+ } else {
+ flagType fFar = FALSE;
+ flagType fLong = FALSE;
+ flagType fW = FALSE;
+ flagType fP = FALSE;
+ flagType fdF = FALSE;
+ flagType fpF = FALSE;
+ flagType ffF = FALSE;
+ flagType feF = FALSE;
+ char fill = ' ';
+ int base = 10;
+ int w = 0;
+ int p = 0;
+ int s = 1;
+ int l;
+
+ c = *fmt;
+ if (c == '-') {
+ s = -1;
+ c = *++fmt;
+ }
+ if (isdigit (c) || c == '.' || c == '*') {
+ /* parse off w.p
+ */
+ fW = TRUE;
+ if (c == '*') {
+ pint = va_arg (vl, int *);
+ w = *pint;
+ fmt++;
+ } else {
+ if (c == '0') {
+ fill = '0';
+ }
+ w = s * atoi (fmt);
+ fmt = strbskip (fmt, "0123456789");
+ }
+ if (*fmt == '.') {
+ fP = TRUE;
+ if (fmt[1] == '*') {
+ p = va_arg (vl, int);
+ fmt += 2;
+ } else {
+ p = atoi (fmt+1);
+ fmt = strbskip (fmt+1, "0123456789");
+ }
+ }
+ }
+ if (*fmt == 'l') {
+ fLong = TRUE;
+ fmt++;
+ }
+ if (*fmt == 'F') {
+ fFar = TRUE;
+ fmt++;
+ }
+ if (*fmt == '|') {
+ while (*fmt != 'F') {
+ switch (*++fmt) {
+ case 'd': fdF = TRUE; break;
+ case 'p': fpF = TRUE; break;
+ case 'f': ffF = TRUE; break;
+ case 'e': feF = TRUE; break;
+ case 'F': if (fmt[-1] == '|') {
+ fdF = TRUE;
+ fpF = TRUE;
+ ffF = TRUE;
+ feF = TRUE;
+ }
+ break;
+ default :
+ // va_end(vl);
+ return MSGERR_ZFORMAT;
+ }
+ }
+ }
+
+ switch (*fmt++) {
+ case 'c':
+ p = va_arg (vl, int);
+ *pStr++ = (char)p;
+ *pStr = 0;
+
+ break;
+
+ case 'x':
+ base = 16;
+ case 'd':
+ if (fLong) {
+
+ _ltoa ( va_arg (vl, long), pStr, base);
+
+ } else {
+ _ltoa ( (long)va_arg (vl, int), pStr, base);
+
+ }
+ break;
+
+ case 's':
+ pchar = va_arg (vl, char *);
+ if (fFar) {
+ if (!fP) {
+ p = strlen ( pchar );
+ }
+ memmove ((char *) pStr, pchar , p);
+
+ } else {
+ if (!fP) {
+ p = strlen ( pchar );
+ }
+ memmove ((char *) pStr, pchar , p);
+
+ }
+ fill = ' ';
+ pStr[p] = 0;
+ break;
+
+ case 'F':
+ pStr[0] = 0;
+ if (fdF) {
+ drive (pFileHead->pName, pStr);
+ }
+ if (fpF) {
+ path (pFileHead->pName, strend(pStr));
+ }
+ if (ffF) {
+ filename (pFileHead->pName, strend(pStr));
+ }
+ if (feF) {
+ extention (pFileHead->pName, strend(pStr));
+ }
+ break;
+
+ case '%':
+ *pStr++ = '%';
+ *pStr = 0;
+ break;
+
+ default:
+ // va_end(vl);
+ return MSGERR_ZFORMAT;
+ }
+
+ /* text is immediately at pStr. Check width to justification
+ */
+ l = strlen (pStr);
+ if (w < 0) {
+ /* left-justify
+ */
+ w = -w;
+ if (l < w) {
+ memset ((char *) &pStr[l], fill, w - l);
+ pStr[w] = 0;
+ }
+ } else if (l < w) {
+ /* right-justify
+ */
+ memmove ((char *) &pStr[w-l], (char *) &pStr[0], l);
+ memset ((char *) &pStr[0], fill, w - l);
+ pStr[w] = 0;
+ }
+ pStr += strlen (pStr);
+ }
+ }
+ *pStr = 0;
+ // va_end(vl);
+ return 0;
+}
+
+/* FmtAssign - formatted assign
+ *
+ * FmtAssign is used to both format and perform an assignment
+ *
+ * pFmt character pointer to sprintf-style formatting
+ * arg set of unformatted arguments
+ *
+ * returns result of DoAssign upon formatted result
+ */
+flagType
+FmtAssign (
+ char *pFmt,
+ ...
+ )
+{
+ char buf[ 512 ];
+ va_list pArgs;
+
+ va_start (pArgs, pFmt);
+ ZFormat (buf, pFmt, pArgs);
+ va_end (pArgs);
+ return DoAssign (buf);
+}
diff --git a/private/utils/mep/src/zdebug.c b/private/utils/mep/src/zdebug.c
new file mode 100644
index 000000000..ef301542e
--- /dev/null
+++ b/private/utils/mep/src/zdebug.c
@@ -0,0 +1,305 @@
+/*** zdebug.c - perform debugging operations
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* NOTE:
+* The intent of this file is to contain primarily *non-release* code for
+* internal debugging. As such it exists in a seperate segment, and all
+* routines should be FAR.
+*
+* Revision History:
+*
+* 26-Nov-1991 mz Strip off near/far
+*************************************************************************/
+
+#include "mep.h"
+
+
+#define DEBFLAG Z
+
+#if defined DEBUG
+
+static char DbgBuffer[128];
+
+
+void *
+DebugMalloc (
+ int Size,
+ BOOL ZeroIt,
+ char * FileName,
+ int LineNumber
+ )
+{
+ void *b;
+ //int HeapStatus;
+
+ UNREFERENCED_PARAMETER( FileName );
+ UNREFERENCED_PARAMETER( LineNumber );
+
+ if (ZeroIt) {
+ b = ZeroMalloc(Size);
+ } else {
+ b = malloc(Size);
+ }
+
+ //
+ // Heap check time
+ //
+ // HeapStatus = _heapchk();
+ //
+ //if ( HeapStatus != _HEAPOK ) {
+ // sprintf(DbgBuffer, " Error: _heapchk status %d\n", HeapStatus );
+ // OutputDebugString(DbgBuffer);
+ // assert( HeapStatus == _HEAPOK );
+ //}
+
+ return b;
+
+}
+
+
+void *
+DebugRealloc (
+ void *Mem,
+ int Size,
+ BOOL ZeroIt,
+ char * FileName,
+ int LineNumber
+ )
+{
+ void * b;
+ //int HeapStatus;
+
+ if (ZeroIt) {
+ b = ZeroRealloc(Mem, Size);
+ } else {
+ b = realloc(Mem, Size);
+ }
+
+ //
+ // Heap check time
+ //
+ //HeapStatus = _heapchk();
+ //
+ //if ( HeapStatus != _HEAPOK ) {
+ // sprintf(DbgBuffer, " Error: _heapchk status %d\n", HeapStatus );
+ // OutputDebugString(DbgBuffer);
+ // assert( HeapStatus == _HEAPOK );
+ //}
+
+ return b;
+}
+
+
+
+
+
+
+void
+DebugFree (
+ void *Mem,
+ char *FileName,
+ int LineNumber
+ )
+{
+ //int HeapStatus;
+
+ free( Mem );
+
+ //
+ // Heap check time
+ //
+ //HeapStatus = _heapchk();
+ //
+ //if ( HeapStatus != _HEAPOK ) {
+ // sprintf(DbgBuffer, " Error: _heapchk status %d File %s line %d\n", HeapStatus, FileName, LineNumber );
+ // OutputDebugString(DbgBuffer);
+ // assert( HeapStatus == _HEAPOK );
+ //}
+}
+
+
+
+
+unsigned
+DebugMemSize (
+ void * Mem,
+ char * FileName,
+ int LineNumber
+ )
+{
+ return MemSize( Mem );
+}
+
+
+#endif
+
+
+#ifdef DEBUG
+/*** _assertexit - display assertion message and exit
+*
+* Input:
+* pszExp - expression which failed
+* pszFn - filename containing failure
+* line - line number failed at
+*
+* Output:
+* Doesn't return
+*
+*************************************************************************/
+void
+_assertexit (
+ char *pszExp,
+ char *pszFn,
+ int line
+ )
+{
+ static char _assertstring[] = "Editor assertion failed: %s, file %s, line %d\n";
+ static char AssertBuffer[256];
+
+ sprintf( AssertBuffer, _assertstring, pszExp, pszFn, line );
+
+ OutputDebugString( AssertBuffer );
+
+ // fprintf(stderr, _assertstring, pszExp, pszFn, line);
+ // fflush(stderr);
+ //
+ // BugBug
+ // If we CleanExit, then we will never be able to read the
+ // assertion text!
+ //
+ // if (!fInCleanExit) {
+ // CleanExit (1, CE_STATE);
+ // }
+ abort();
+}
+
+
+
+
+/*** _nearCheck - check far pointer to be a valid near one.
+*
+* asserts that the passed far pointer is indeed a valid near pointer
+*
+* Input:
+* fpCheck - pointer to be checked
+* pName - pointer to it's name
+* pFileName - pointer to file name containing the check
+* LineNum - the line number in the file containing the check
+*
+* Output:
+* Returns near pointer
+*
+* Exceptions:
+* asserts out on failure
+*
+*************************************************************************/
+void *
+_nearCheck (
+ void *fpCheck,
+ char *pName,
+ char *pFileName,
+ int LineNum
+ )
+{
+ return (void *)(int)(long)fpCheck;
+
+ pName; pFileName; LineNum;
+}
+
+
+
+
+/*** _pfilechk - verify integrity of the pfile list
+*
+* Purpose:
+*
+* Input:
+* none
+*
+* Output:
+* Returns TRUE if pfile list looks okay, else FALSE.
+*
+*************************************************************************/
+flagType
+_pfilechk (
+ void
+ )
+{
+ PFILE pFileTmp = pFileHead;
+
+ while ( pFileTmp != NULL ) {
+
+#ifdef DEBUG
+ if ( pFileTmp->id != ID_PFILE ) {
+ return FALSE;
+ }
+#endif
+ if ( pFileTmp->pName == NULL ) {
+ return FALSE;
+ }
+
+ pFileTmp = pFileTmp->pFileNext;
+ }
+
+ return TRUE;
+}
+
+
+
+
+
+/*** _pinschk - verify integrity of an instance list
+*
+* Purpose:
+*
+* Input:
+* pIns - Place to start the check
+*
+* Output:
+* Returns TRUE if instance list looks okay, else FALSE.
+*
+*************************************************************************/
+flagType
+_pinschk (
+ PINS pIns
+ )
+{
+ int cMax = 64000/sizeof(*pIns);
+
+ while (pIns && cMax--) {
+ if ( (pIns->id != ID_INSTANCE)
+ || (pIns->pFile == 0)
+ || ((PVOID)pIns->pNext == (PVOID)0xffff)
+ ) {
+ return FALSE;
+ }
+ pIns = pIns->pNext;
+ }
+ return (flagType)(cMax != 0);
+}
+
+
+
+
+
+/*** _heapdump - dump the heap status to stdout
+*
+* Purpose:
+*
+* Input:
+* p = pointer to title string
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+void
+_heapdump (
+ char *p
+ )
+{
+ p;
+}
+
+#endif
diff --git a/private/utils/mep/src/zexit.c b/private/utils/mep/src/zexit.c
new file mode 100644
index 000000000..f55398cb8
--- /dev/null
+++ b/private/utils/mep/src/zexit.c
@@ -0,0 +1,346 @@
+/*** zexit.c - perform exiting operations
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+
+#include "mep.h"
+#include "keyboard.h"
+
+
+extern char *ConsoleTitle;
+
+/*** zexit - exit the editor function
+*
+* Purpose:
+* <exit> save current file, state and advance to next file on
+* command line
+* <arg><exit> save current file, state and exit now
+* <meta><exit> save state and exit
+*
+* Input:
+* Standard editor function parameters
+*
+* Output:
+* Returns .....
+*
+* Exceptions:
+*
+*************************************************************************/
+flagType
+zexit (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ )
+{
+ flagType f = FALSE;
+
+ /*
+ * auto-save current file if appropriate
+ */
+ if (!fMeta) {
+ AutoSave ();
+ }
+
+
+ /*
+ * <exit> goes to the next file on the command line
+ * if we got an arg (<arg><exit> or <arg><meta><exit>) and some files remain
+ * from the command line, then we prompt the user for confirmation.
+ */
+ if ( ( (pArg->argType == NOARG)
+ || ( (pArg->argType == NULLARG)
+ && (pFileFileList)
+ && (pFileFileList->cLines)
+ && (!confirm ("You have more files to edit. Are you sure you want to exit? (y/n): ", NULL))
+ )
+ )
+ && fFileAdvance ()
+ ) {
+ return FALSE;
+ }
+
+ /*
+ * If there is background compile in progress that the user does not wish to
+ * kill, abort.
+ */
+ if (!BTKillAll ()) {
+ return FALSE;
+ }
+
+
+ /*
+ * If we ask, and the user changes his mind, abort.
+ */
+ if (fAskExit && !confirm("Are you sure you want to exit? (y/n): ", NULL)) {
+ return FALSE;
+ }
+
+
+ /* Prompt the user to save dirty files. If the user chooses
+ * not to exit at this time, fSaveDirtyFiles returns FALSE.
+ */
+ if (!fSaveDirtyFiles()) {
+ return FALSE;
+ }
+
+
+ /*
+ * At this point, it looks like we're going to exit. Give extensions a chance
+ * to change things prior to writing the temp file.
+ */
+ DeclareEvent (EVT_EXIT, NULL);
+
+ //
+ // Restore original console title
+ //
+ //SetConsoleTitle( &ConsoleTitle );
+
+ /*
+ * Finally, leave.
+ */
+ CleanExit (0, CE_VM | CE_SIGNALS | CE_STATE);
+
+ argData;
+}
+
+
+
+
+
+
+/*** fFileAdvance - attempt to read in the next file on the command line
+*
+* Purpose:
+* We get the next file from the command line and try to read it in.
+*
+* Input:
+*
+* Output:
+* Returns TRUE iff the next file was successfully read in
+*
+*************************************************************************/
+flagType
+fFileAdvance (
+ void
+ )
+{
+ pathbuf buf; /* buffer to get filename */
+ int cbLine; /* length of line */
+ flagType fTmp; /* TRUE=> temp file */
+ char *pBufFn; /* pointer to actual file name */
+
+ while (pFileFileList && (pFileFileList->cLines)) {
+
+ pBufFn = buf;
+ fTmp = FALSE;
+
+ /*
+ * get and delete the top line in the list, containing the next filename
+ */
+ cbLine = GetLine (0L, buf, pFileFileList);
+ DelLine (FALSE, pFileFileList, 0L, 0L);
+
+ if (pFileFileList->cLines == 0) {
+ RemoveFile (pFileFileList);
+ pFileFileList = 0;
+ }
+
+ if (cbLine) {
+
+ /*
+ * if it starts with "/t " the user wants it to be a temp
+ */
+ if ((buf[0] == '/') && (buf[1] == 't')) {
+ fTmp = TRUE;
+ pBufFn += 3;
+ }
+
+ /*
+ * if we can open it, and in fact it became the current file (not just
+ * a directory or drive change), set flags as appropriate and return
+ * success.
+ */
+ if (fChangeFile (FALSE, pBufFn)) {
+ if (strcmp(pFileHead->pName,pBufFn) == 0) {
+ if (fTmp) {
+ SETFLAG (FLAGS (pFileHead), TEMP);
+ }
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ if (pFileFileList) {
+ RemoveFile (pFileFileList);
+ pFileFileList = 0;
+ }
+ return FALSE;
+}
+
+
+
+
+
+/*** SetFileList - Create list of fully qualified paths
+*
+* Creates the <file-list> psuedo file, and scans the command line for all
+* non-switch parameters. For each of those it adds their fully qualified
+* path name to the psuedo file. This allows the user to change directories
+* at will, and not lose the ability to <exit> to get to the next file he
+* specified on the command line.
+*
+* Input:
+* none
+*
+* Output:
+* Returns number of files in <file-list>
+* <file-list> created
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+LINE
+SetFileList (
+ void
+ )
+{
+ pathbuf buf; /* buffer to build path in */
+ char *pBufAdd; /* pointer to place path at */
+
+ pFileFileList = AddFile ("<file-list>");
+ IncFileRef (pFileFileList);
+ SETFLAG (FLAGS(pFileFileList), REAL | FAKE | DOSFILE | READONLY);
+
+ pBufAdd = buf;
+
+ while (cArgs && !fCtrlc) {
+
+ if (fSwitChr (**pArgs)) {
+ //
+ // if filename is preceded by -t, then prepend a -t to the
+ // file list
+ //
+ _strlwr (*pArgs);
+ if (!strcmp ("t", *pArgs+1) && cArgs >= 2) {
+ strcpy (buf, "/t ");
+ pBufAdd = buf+3;
+ }
+ } else {
+ //
+ // Form full pathname, and add each filename to the file
+ // list pseudo-file
+ //
+ if ( strlen(*pArgs) > sizeof(buf) ) {
+ printerror( "File name too long." );
+ } else {
+ *pBufAdd = '\0';
+ CanonFilename (*pArgs, pBufAdd);
+ if ( *pBufAdd == '\0' || strlen(pBufAdd) > BUFLEN ) {
+ printerror( "File name too long." );
+ } else {
+ PutLine (pFileFileList->cLines, pBufAdd = buf, pFileFileList);
+ }
+ }
+ }
+
+ SHIFT (cArgs, pArgs);
+ }
+
+ return pFileFileList->cLines;
+}
+
+
+
+
+
+/*** CleanExit - Clean up and return to DOS.
+*
+* Input:
+* retc - Return code to DOS
+* flags = OR combination of one or more:
+* CE_VM Clean Up VM
+* CE_SIGNALS Clean up signals
+* CE_STATE Update state file
+*
+* Output:
+* Doesn't Return
+*
+*************************************************************************/
+void
+CleanExit (
+ int retc,
+ flagType flags
+ )
+{
+ fInCleanExit = TRUE;
+ domessage (NULL);
+ prespawn (flags);
+
+ //if (!fSaveScreen) {
+ // voutb (0, YSIZE+1, NULL, 0, fgColor);
+ //}
+
+ exit(retc);
+}
+
+
+
+
+
+/*** prespawn - pre-spawn "termination" processing
+*
+* A form of "termination" prior to spawning a process. Restore/save state as
+* required before shelling out a program
+*
+* Input:
+* flags = OR combination of one or more:
+* CE_VM Clean Up VM
+* CE_SIGNALS Clean up signals
+* CE_STATE Update state file
+*
+* Output:
+* Returns .....
+*
+*************************************************************************/
+flagType
+prespawn (
+ flagType flags
+ )
+{
+ if (TESTFLAG (flags, CE_STATE)) {
+ WriteTMPFile ();
+ }
+
+#if DEBUG
+ fflush (debfh);
+#endif
+
+ /*
+ * Unhook the keyboard and return it to cooked mode, reset hardware as
+ * appropriate and restore the screen mode on entry, and it's contents if
+ * so configured.
+ */
+ KbUnHook ();
+
+ SetErrorMode( 0 );
+
+ if (TESTFLAG(fInit, INIT_VIDEO)) {
+ SetVideoState(1);
+ }
+
+ //if (fSaveScreen) {
+ RestoreScreen();
+ //}
+
+ fSpawned = TRUE;
+
+ return TRUE;
+}
diff --git a/private/utils/mep/src/zinit.c b/private/utils/mep/src/zinit.c
new file mode 100644
index 000000000..97519f458
--- /dev/null
+++ b/private/utils/mep/src/zinit.c
@@ -0,0 +1,1181 @@
+/*** zinit.c - editor initialization
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+#define INCL_DOSFILEMGR
+#define INCL_SUB
+#define INCL_DOSERRORS
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSPROCESS
+
+#include "mep.h"
+#include "keyboard.h"
+#include <conio.h>
+
+
+#define DEBFLAG ZINIT
+
+#define TSTACK 2048 /* Thread stack size */
+
+/*
+ * Data initializations
+ */
+flagType fAskExit = FALSE;
+flagType fAskRtn = TRUE;
+flagType fAutoSave = TRUE;
+flagType fBoxArg = FALSE;
+flagType fCgaSnow = TRUE;
+flagType fEditRO = TRUE;
+flagType fErrPrompt = TRUE;
+flagType fGlobalRO = FALSE;
+flagType fInsert = TRUE;
+flagType fDisplayCursorLoc = FALSE;
+flagType fMacroRecord= FALSE;
+flagType fMsgflush = TRUE;
+flagType fNewassign = TRUE;
+flagType fRealTabs = TRUE;
+flagType fSaveScreen = TRUE;
+flagType fShortNames = TRUE;
+flagType fSoftCR = TRUE;
+flagType fTabAlign = FALSE;
+flagType fTrailSpace = FALSE;
+flagType fWordWrap = FALSE;
+flagType fBreak = FALSE;
+/*
+ * Search/Replace globals
+ */
+flagType fUnixRE = FALSE;
+flagType fSrchAllPrev = FALSE;
+flagType fSrchCaseSwit = FALSE;
+flagType fSrchDirPrev = TRUE;
+flagType fSrchRePrev = FALSE;
+flagType fSrchWrapSwit = FALSE;
+flagType fSrchWrapPrev = FALSE;
+flagType fUseMouse = FALSE;
+
+flagType fCtrlc;
+flagType fDebugMode;
+flagType fMetaRecord;
+flagType fDefaults;
+flagType fMessUp;
+flagType fMeta;
+flagType fRetVal;
+flagType fTextarg;
+flagType fSrchCasePrev;
+flagType fRplRePrev;
+buffer srchbuf;
+buffer srcbuf;
+buffer rplbuf;
+
+unsigned kbdHandle;
+
+int backupType = B_BAK;
+int cUndelCount = 32767; /* essentially, infinite */
+int cCmdTab = 1;
+LINE cNoise = 50;
+int cUndo = 10;
+int EnTab = 1;
+char * eolText = "\r\n"; /* our definition of end of line*/
+int fileTab = 8;
+int CursorSize=0;
+int hike = 4;
+int hscroll = 10;
+unsigned kindpick = LINEARG;
+char tabDisp = ' ';
+int tabstops = 4;
+int tmpsav = 20;
+char trailDisp = 0;
+int vscroll = 1;
+COL xMargin = 72;
+
+PCMD * rgMac = NULL; /* macro array */
+
+int cMac;
+
+int ballevel;
+char *balopen, *balclose;
+unsigned getlsize = 0xFE00;
+
+char Name[];
+char Version[];
+char CopyRight[];
+
+EDITOR_KEY keyCmd;
+
+int ColorTab[16];
+
+int cArgs;
+char **pArgs;
+
+char * pNameEditor;
+char * pNameTmp;
+char * pNameInit;
+char * pNameHome;
+char *pComSpec;
+
+int cMacUse;
+struct macroInstanceType mi[MAXUSE];
+
+PCMD cmdSet[MAXEXT];
+PSWI swiSet[MAXEXT];
+char *pExtName[MAXEXT];
+
+
+
+
+PSCREEN OriginalScreen;
+PSCREEN MepScreen;
+KBDMODE OriginalScreenMode;
+
+
+
+
+
+
+
+
+
+
+
+/*
+ * Compile and print threads
+ */
+BTD *pBTDComp = NULL;
+BTD *pBTDPrint = NULL;
+
+unsigned LVBlength = 0; /* We use this to know if we're detached */
+
+/*
+ * String values.
+ */
+char rgchPrint [] = "<print>";
+char rgchComp [] = "<compile>";
+char rgchAssign[] = "<assign>";
+char rgchEmpty[] = "";
+char rgchInfFile[]= "<information-file>";
+char rgchUntitled[]="<untitled>";
+char rgchWSpace[] = "\t "; /* our definition of white space*/
+char Shell[] = SHELL;
+char User[] = "USER";
+/*
+ * autoload extension paterns.
+ */
+char rgchAutoLoad[]="m*.pxt";
+
+sl slSize;
+PFILE pFilePick = NULL;
+PFILE pFileFileList = NULL;
+PFILE pFileAssign = NULL;
+PFILE pFileIni = NULL;
+struct windowType WinList[MAXWIN+1];
+int iCurWin = 0;
+PINS pInsCur = NULL;
+PWND pWinCur = NULL;
+int cWin = 0;
+PFILE pFileHead=NULL;
+COMP *pCompHead = NULL;
+MARK *pMarkHead = NULL;
+char *pMarkFile = NULL;
+char *pPrintCmd = NULL;
+PFILE pPrintFile = NULL;
+buffer scanbuf;
+buffer scanreal;
+int scanlen;
+fl flScan;
+rn rnScan;
+
+#ifdef DEBUG
+int debug, indent;
+FILEHANDLE debfh;
+#endif
+
+fl flArg;
+int argcount;
+
+flagType fInSelection = FALSE;
+
+fl flLow;
+fl flHigh;
+LINE lSwitches;
+int cRepl;
+char *ronlypgm = NULL;
+buffer buf;
+buffer textbuf;
+int Zvideo;
+int DOSvideo;
+
+flagType *fChange = NULL;
+unsigned fInit;
+flagType fSpawned = FALSE;
+
+
+
+
+
+flagType fDisplay = RCURSOR | RTEXT | RSTATUS;
+
+flagType fReDraw = TRUE;
+HANDLE semIdle = 0;
+
+char IdleStack[TSTACK*2]; /* Idle thread stack */
+
+int argcount = 0;
+CRITICAL_SECTION IOCriticalSection;
+CRITICAL_SECTION UndoCriticalSection;
+CRITICAL_SECTION ScreenCriticalSection;
+
+/*
+ * predefined args. Handy for invoking some set functions ourselves
+ */
+ARG NoArg = {NOARG, 0};
+
+
+/*
+ * The format of these strings is identical to that of the assignments in
+ * TOOLS.INI
+ */
+char * initTab[] = {
+/* Default compilers */
+ "extmake:c cl /c /Zp %|F",
+ "extmake:asm masm -Mx %|F;",
+ "extmake:pas pl /c -Zz %|F",
+ "extmake:for fl /c %|F",
+ "extmake:bas bc /Z %|F;",
+ "extmake:text nmake %s",
+
+/* Default macros */
+//
+// the F1 key is assigned to this message by default, so that in the case
+// that on-line help is NOT loaded, we respond with this message. Once the
+// help extension IS loaded, it automatically makes new assignments to these
+// keystrokes, and all is well with the world.
+//
+ "helpnl:=cancel arg \"OnLine Help Not Loaded\" message",
+ "helpnl:f1",
+ "helpnl:shift+f1",
+ "helpnl:ctrl+f1",
+ "helpnl:alt+f1",
+ NULL
+ };
+
+/*
+ * exttab is a table used to keep track of cached extension-specific TOOLS.INI
+ * sections.
+ */
+#define MAXEXTS 10 /* max number of unique extensions*/
+
+struct EXTINI {
+ LINE linSrc; /* TOOLS.INI line of the text */
+ char ext[5]; /* the file extension (w/ ".") */
+ } exttab[10] = {0};
+
+
+flagType fInCleanExit = FALSE;
+
+char ConsoleTitle[256];
+
+
+
+/*** InitNames - Initialize names used by editor
+*
+* Initializes various names used by the editor which are based on the name it
+* was invoked with. Called immediately on entry.
+*
+* Input:
+* name = Pointer to name editor invoked as
+*
+* Output:
+* Returns nothing
+*
+* pNameHome = environment variable to use as "home" directory
+* pNameEditor = name editor invoked as
+* pNameTmp = name of state preservation file (M.TMP)
+* pNameInit = name of tools initialization file (TOOLS.INI)
+* pComSpec = name of command processor
+*
+*************************************************************************/
+void
+InitNames (
+ char * name
+ )
+{
+ char *pname = name;
+ char *tmp;
+
+ //
+ // Just in case name has blanks after it, we will patch it
+ //
+ while ( *pname != '\0' &&
+ *pname != ' ' ) {
+ pname++;
+ }
+ *pname = '\0';
+
+
+ if (!getenv(pNameHome = "INIT")) {
+ pNameHome = User;
+ }
+
+ filename (name, buf);
+ pNameEditor = ZMakeStr (buf);
+
+ sprintf (buf, "$%s:%s.TMP", pNameHome, pNameEditor);
+ pNameTmp = ZMakeStr (buf);
+
+ sprintf (buf, "$%s:tools.ini", pNameHome);
+ pNameInit = ZMakeStr (buf);
+
+ pComSpec = NULL;
+ if (!(tmp = (char *)getenvOem("COMSPEC"))) {
+ pComSpec = Shell;
+ } else {
+ //
+ // We cannot keep a pointer to the environment table, so we
+ // point to a copy of the command interpreter path
+ //
+ char *p = MALLOC(strlen(tmp)+1);
+ strcpy(p,tmp);
+ pComSpec = p;
+ free( tmp );
+ }
+
+
+#if 0
+ if (!(pComSpec = getenv("COMSPEC"))) {
+ pComSpec = Shell;
+ } else {
+ //
+ // We cannot keep a pointer to the environment table, so we
+ // point to a copy of the command interpreter path
+ //
+ char *p = MALLOC(strlen(pComSpec)+1);
+ strcpy(p,pComSpec);
+ pComSpec = p;
+ }
+#endif
+}
+
+
+
+
+
+/*** init - one-time editor start-up initialization
+*
+* One-time editor initialzation code. This code is executed (only) at
+* start-up, after the command line switches have been parsed.
+*
+* Input:
+* none
+*
+* Output:
+* Returns TRUE if valid initialization
+*
+*************************************************************************/
+int
+init (
+ void
+ )
+{
+
+ DWORD TPID; /* Thread Id */
+ KBDMODE Mode; /* console mode */
+
+ /*
+ * Set up the base switch and command sets.
+ */
+ swiSet[0] = swiTable;
+ cmdSet[0] = cmdTable;
+ pExtName[0] = ZMakeStr (pNameEditor);
+
+ /*
+ * Initialize VM, and bomb off if that didn't work.
+ */
+ asserte( getlbuf = MALLOC( getlsize ));
+
+ // fSaveScreen = FALSE;
+ // CleanExit (1, FALSE);
+ rgMac = (PCMD *)MALLOC ((long)(MAXMAC * sizeof(PCMD)));
+ // assert (_heapchk() == _HEAPOK);
+
+
+ /*
+ * Attempt to get the *current* video state. If it's not one that we
+ * understand, bomb off. Else, get the x and y sizes, for possible use later
+ * as our editting mode, use postspawn to complete some initialization, and
+ * set up our default colors.
+ */
+
+ //
+ // Create a new screen buffer and make it the active one.
+ //
+ InitializeCriticalSection(&ScreenCriticalSection);
+ MepScreen = consoleNewScreen();
+ OriginalScreen = consoleGetCurrentScreen();
+ if ( !MepScreen || !OriginalScreen ) {
+ fprintf(stderr, "MEP Error: Could not allocate console buffer\n");
+ exit(1);
+ }
+ consoleGetMode(&OriginalScreenMode);
+ asserte(consoleSetCurrentScreen(MepScreen));
+ //
+ // Put the console in raw mode
+ //
+ Mode = (OriginalScreenMode & ~(CONS_ENABLE_LINE_INPUT | CONS_ENABLE_PROCESSED_INPUT | CONS_ENABLE_ECHO_INPUT )) | CONS_ENABLE_MOUSE_INPUT ;
+ consoleSetMode(Mode);
+ SetConsoleCtrlHandler( CtrlC, TRUE );
+
+ consoleFlushInput();
+
+ postspawn (FALSE);
+
+ hgColor = GREEN;
+ errColor = RED;
+ fgColor = WHITE;
+ infColor = YELLOW;
+ staColor = CYAN;
+ selColor = WHITE << 4;
+ wdColor = WHITE;
+
+ //
+ // Remember console title
+ //
+ ConsoleTitle[0] = '\0';
+ GetConsoleTitle( ConsoleTitle, sizeof(ConsoleTitle) );
+
+ /*
+ * Create the clipboard
+ */
+ pFilePick = AddFile ("<clipboard>");
+ pFilePick->refCount++;
+ SETFLAG (FLAGS(pFilePick), REAL | FAKE | DOSFILE | VALMARKS);
+
+ mepInitKeyboard( ); // Init the keyboard
+
+ //
+ // Initialize the critical section that we use for thread
+ // synchronization
+ //
+ InitializeCriticalSection(&IOCriticalSection);
+ InitializeCriticalSection(&UndoCriticalSection);
+
+ //
+ // Create the semIdle event
+ //
+
+ asserte(semIdle = CreateEvent(NULL, FALSE, FALSE, NULL));
+
+
+
+ /*
+ * Create list of fully qualified paths for files on argument line, then
+ * if files were specified, ensure that we are in initial state
+ */
+ SetFileList ();
+
+
+ /*
+ * Try to read the TMP file
+ */
+ ReadTMPFile ();
+
+
+ /*
+ * Update the screen data to reflect whatever resulted from reading the .TMP
+ * file.
+ */
+ SetScreen ();
+
+
+ /*
+ * read tools.ini for 1st time
+ */
+ loadini (TRUE);
+
+ SetScreen ();
+
+ //
+ // Set the cursor size
+ //
+ SetCursorSize( CursorSize );
+
+ //
+ // Make sure that hscroll is smaller than the window's width
+ //
+ if ( hscroll >= XSIZE ) {
+ hscroll = XSIZE-1;
+ }
+
+ AutoLoadExt ();
+
+ /*
+ * Create the Idle time thread
+ */
+
+ if (!CreateThread(NULL, TSTACK * 2, (LPTHREAD_START_ROUTINE)IdleThread, NULL, 0, &TPID)) {
+ disperr(MSGERR_ITHREAD);
+ }
+
+
+ /*
+ * Create background threads for <compile> and <print>,
+ */
+ pBTDComp = BTCreate (rgchComp);
+ pBTDPrint = BTCreate (rgchPrint);
+
+ assert(_pfilechk());
+ return TRUE;
+}
+
+
+
+
+
+/*** DoInit - Load init file section
+*
+* load from tools.ini, the tag name-tag into the editor configuration
+* table. set ffound to true if we find the appropriate file
+*
+* Input:
+* tag = the name of the subsection to be read, or NULL for base
+* section
+* pfFound = Pointer to flag to be set TRUE if any assignment is actually
+* made. May also be NULL.
+* linStart = line number to start processing from if we already have
+* a tools.ini. This make re-reading a previously read
+* section faster.
+*
+* Output:
+* Returns TOOLS.INI line number of matching section. Assignments may be made,
+* and pfFound updated accordingly.
+*
+*************************************************************************/
+LINE
+DoInit (
+ char *tag,
+ flagType *pfFound,
+ LINE linStart
+ )
+{
+ pathbuf buf; /* full filename for TOOLS.INI */
+ buffer bufTag; /* full tag to look for */
+ LINE cLine; /* line in TOOLS.INI */
+ REGISTER char *pTag; /* pointer to tag, if found */
+
+ /*
+ * if Tools.Ini hasn't already been found, attempt to locate it, and read in
+ * it's contents.
+ */
+ if (pFileIni == NULL) {
+ linStart = 0;
+ pFileIni = (PFILE)-1;
+ assert (pNameInit);
+ if (findpath (pNameInit, buf, TRUE)) {
+ pFileIni = FileNameToHandle (buf, NULL);
+ if (pFileIni == NULL) {
+ pFileIni = AddFile (buf);
+ assert (pFileIni);
+ pFileIni->refCount++;
+ SETFLAG (FLAGS(pFileIni), DOSFILE);
+ }
+ if (!TESTFLAG (FLAGS(pFileIni), REAL)) {
+ FileRead (buf, pFileIni, FALSE);
+ }
+ }
+ }
+
+ if (pFileIni != (PFILE)-1) {
+ /*
+ * If there is no starting line number, form the full tag name to be looked
+ * for, and scan the file for it.
+ */
+ if (!(cLine = linStart)) {
+ strcpy( bufTag, pNameEditor );
+ // strcpy (bufTag, "mepnt"); //pNameEditor);
+ if (tag != NULL && *tag != '\0') {
+ strcat (strcat (bufTag, "-"), tag);
+ }
+ _strlwr (bufTag);
+ linStart = cLine = LocateTag(pFileIni, bufTag);
+ }
+
+ /*
+ * if the section was found, scan that section, until a new tag line
+ * is found, and process the contents of that section
+ */
+ if (cLine) {
+ pTag = NULL;
+ while (pTag = GetTagLine (&cLine, pTag, pFileIni)) {
+ DoAssign (pTag);
+ if (pfFound) {
+ *pfFound = TRUE;
+ }
+ //assert (_heapchk() == _HEAPOK);
+ }
+ }
+ }
+ return linStart;
+}
+
+
+
+
+
+/*** IsTag - returns pointer to tag if line is marker; NULL otherwise
+*
+* Identify tag lines in TOOLS.INI
+*
+* Input:
+* buf = pointer to string to check
+*
+* Output:
+* Returns pointer to tag if line is marker; NULL otherwise
+*
+*************************************************************************/
+char *
+IsTag (
+ REGISTER char *buf
+ )
+{
+ REGISTER char *p;
+
+ assert (buf);
+ buf = whiteskip (buf);
+ if (*buf++ == '[') {
+ if (*(p = strbscan (buf, "]")) != '\0') {
+ *p = 0;
+ return buf;
+ }
+ }
+ return NULL;
+}
+
+
+
+
+
+/*** LocateTag - Find TAG in TOOLS.INI formatted file
+*
+* Locates a specific tag
+*
+* Input:
+* pFile = pFile of file to be searched
+* pText = text of the tag (no brackets)
+*
+* Output:
+* Returns line number +1 of tag line
+*
+*************************************************************************/
+LINE
+LocateTag (
+ PFILE pFile,
+ char *pText
+ )
+{
+ buffer buf; /* working buffer */
+ char c; /* temp char */
+ LINE lCur; /* current line number */
+ char *pTag; /* pointer to tag */
+ char *pTagEnd; /* pointer to end of */
+
+ for (lCur = 0; lCur < pFile->cLines; lCur++) {
+ GetLine (lCur, buf, pFile);
+ if (pTagEnd = pTag = IsTag (buf)) {
+ while (*pTagEnd) {
+ pTagEnd = whitescan (pTag = whiteskip (pTagEnd));
+ c = *pTagEnd;
+ *pTagEnd = 0;
+ if (!_stricmp (pText, pTag)) {
+ return lCur+1;
+ }
+ *pTagEnd = c;
+ }
+ }
+ }
+ return 0L;
+}
+
+/*** InitExt - execute extension-dependant TOOLS.INI assignments
+*
+* Executes the assignments in the user's TOOLS.INI that are specific to a
+* particular file extension.
+*
+* We cache the text of the tools.ini section in VM the first time it is read,
+* such that TOOLS.INI need not be read on every file change. This cache is
+* invalidated (and freed) on execution of the initialize command.
+*
+* Input:
+* szExt = Pointer to string containing extension. MAX 4 CHARACTERS!
+*
+* Output:
+* Returns TRUE if section found & executed.
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+flagType
+InitExt (
+ char *szExt
+ )
+{
+ flagType f; /* random flag */
+ static int iDiscard = 0; /* roving discard index */
+ struct EXTINI *pIni; /* pointer to found entry */
+ struct EXTINI *pIniNew = NULL; /* pointer to new entry */
+
+ /*
+ * Only do this if we actually have a valid tools.ini. Before the initial
+ * TOOLS.INI read, pFileIni will be zero, and we should not do this, because
+ * we might cause it to be read (and then loadini will destroy some of what
+ * happened, but not all). In cases where there simply is not TOOLS.INI
+ * pFileIni may be -1, but that's caught later.
+ */
+ if (pFileIni == NULL) {
+ return FALSE;
+ }
+
+ /*
+ * Search init table for the line number of cached init section, and as soon
+ * as found, re-read that section. ALSO, as we're walking, keep track of any
+ * free table entries we find, so that we can create a cache if it's not.
+ */
+ for (pIni = &exttab[0]; pIni <= &exttab[9]; pIni++) {
+ if (!strcmp (szExt, pIni->ext)) {
+ pIni->linSrc = DoInit (szExt, &f, pIni->linSrc);
+ return TRUE;
+ }
+ if (!(pIni->ext[0])) {
+ pIniNew = pIni;
+ }
+ }
+
+ /*
+ * we did not find the table entry for the extension, then attempt to create
+ * one. This means get rid of one, if there is no room.
+ */
+ if (!pIniNew) {
+ pIni = &exttab[iDiscard];
+ iDiscard = (iDiscard + 1) % 10;
+ } else {
+ pIni = pIniNew;
+ }
+ strcpy (pIni->ext, szExt);
+
+ /*
+ * read the section once to get the size. If the section does not exist, then
+ * discard the table entry, and look for the default section "[M-..]"
+ */
+ if (pIni->linSrc = DoInit (szExt, &f, 0L)) {
+ return TRUE;
+ }
+ pIni->ext[0] = 0;
+ DoInit ("..", &f, 0L);
+ return FALSE;
+}
+
+
+
+
+/*** loadini - load tools.ini data
+*
+* Reads TOOLS.INI at startup, and when the initialize function is used.
+*
+* Input:
+* fFirst = true if call at startup
+*
+* Output:
+* Returns
+*
+*************************************************************************/
+int
+loadini (
+ flagType fFirst
+ )
+{
+ buffer buf;
+ flagType fFound = FALSE;
+ int i;
+
+ /*
+ * Clear current keyboard assignments
+ */
+ if (!fFirst) {
+ FreeMacs ();
+ for (i = 0; i < cMac; i++) {
+ FREE ((char *)rgMac[i]->arg);
+ FREE ((char *)(int)(long)rgMac[i]);
+ }
+ cMac = 0;
+ // assert (_heapchk() == _HEAPOK);
+ }
+ FmtAssign ("curFileNam:=");
+ FmtAssign ("curFile:=");
+ FmtAssign ("curFileExt:=");
+
+ /*
+ * Load up the default settings for Z. These are stored as a simple
+ * table of strings to be handed to DoAssign. Their format is identical
+ * to that in the TOOLS.INI file.
+ */
+ for (i = 0; initTab[i]; i++) {
+ DoAssign (strcpy((char *)buf, initTab[i]));
+ }
+
+ /*
+ * if /D was not specified on startup, read tools.ini sections.
+ */
+ if (!fDefaults) {
+ /*
+ * Global editor section
+ */
+ DoInit (NULL, &fFound, 0L);
+
+ /*
+ * OS version dependent section
+ */
+ //sprintf (buf, "%d.%d", _osmajor, _osminor);
+ //if (_osmajor >= 10 && !_osmode) {
+ // strcat (buf, "R");
+ //}
+ //DoInit (buf, &fFound, 0L);
+
+ /*
+ * screen mode dependant section
+ */
+ DoInit (VideoTag(), &fFound, 0L);
+ }
+
+ /*
+ * if we have a current file, set filename macros, and read filename
+ * extension specific TOOLS.INI section
+ */
+ if (pFileHead) {
+ fInitFileMac (pFileHead);
+ }
+
+ newscreen ();
+
+ /*
+ * initialize variables whose initial values are dependant on tools.ini
+ * values. These are generally "last setting" switches used in menu displays
+ */
+ fSrchCasePrev = fSrchCaseSwit;
+ fSrchWrapPrev = fSrchWrapSwit;
+
+ // assert (_heapchk() == _HEAPOK);
+ assert (_pfilechk());
+
+ return fFound;
+}
+
+
+
+
+/*** zinit - <initialize> editor function
+*
+* Input:
+* Standard Editor Function
+*
+* Output:
+* Returns TRUE if successful
+*
+*************************************************************************/
+flagType
+zinit (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType fMeta
+ )
+{
+ flagType f;
+ buffer ibuf;
+
+ /*
+ * clear old version of tools.ini, and clear any cached extension-specific
+ * tools.ini stuff
+ */
+ if (pFileIni != NULL && (pFileIni != (PFILE)-1)) {
+ RemoveFile (pFileIni);
+ pFileIni = NULL;
+ memset ((char *)exttab, '\0', sizeof (exttab));
+ }
+
+ ibuf[0] = 0;
+
+ switch (pArg->argType) {
+
+ case NOARG:
+ f = (flagType)loadini (FALSE);
+ break;
+
+ case TEXTARG:
+ strcpy (ibuf, pArg->arg.textarg.pText);
+ DoInit (ibuf, &f, 0L);
+ break;
+ }
+
+ if (!f) {
+ disperr (MSGERR_TOOLS, ibuf);
+ }
+ return f;
+
+ argData; fMeta;
+}
+
+
+
+
+/*** fVideoAdjust - set screen modes
+*
+* understand what the screen capabilities are and adjust screen desires to
+* match up with screen capabilities.
+*
+* The routine GetVideoState does the following:
+*
+* Set up the fnMove/fnStore routine based upon screen capabilities
+* Return a handle encoding the possible and current display modes.
+*
+* Once this is complete, the user will request a particular size. The
+* request comes from either tools.ini or from the Z.TMP file. Tools.ini
+* gives the first-approximation of what the screen really should be. Z.TMP
+* gives the final determination.
+*
+* Given the type returned by GetVideoState, we will adjust xSize/ySize,
+* Zvideo and the window layout. If the screen can support a particular
+* xSize/ySize, then we set them up and return an indicator that
+* SetVideoState should be called.
+*
+* If a particular xSize/ySize cannot be supported, the screen is left
+*
+* Multiple windows present presents a problem. The best that we can do is
+* to toss all stored window information. We will return a failure
+* indication so that Z.TMP read-in can be suitably modified.
+*
+* Input:
+* xSizeNew = new size for xSize
+* ySizeNew = new size for ySize
+*
+* OutPut:
+* Returns TRUE if sizes are allowed
+*
+*************************************************************************/
+flagType
+fVideoAdjust (
+ int xSizeNew,
+ int ySizeNew
+ )
+{
+ //int newState;
+ SCREEN_INFORMATION ScrInfo;
+
+ if ( xSizeNew <= hscroll ) {
+ return FALSE;
+ }
+ if ( !SetScreenSize ( ySizeNew+2, xSizeNew ) ) {
+ return FALSE;
+ }
+
+ consoleGetScreenInformation( MepScreen, &ScrInfo );
+
+ //Zvideo = newState;
+
+ XSIZE = ScrInfo.NumberOfCols;
+ YSIZE = ScrInfo.NumberOfRows-2;
+
+ SetScreen ();
+ return TRUE;
+}
+
+
+
+//
+// BUGBUG should be in console header
+//
+BOOL
+consoleIsBusyReadingKeyboard (
+ );
+
+BOOL
+consoleEnterCancelEvent (
+ );
+
+
+/*** CtrlC - Handler for Control-C signal.
+*
+* Invalidate any type ahead and leave flag around. If the user presses
+* Ctrl-C or Ctrl-Break five times without getting the tfCtrlc flag
+* cleared, assume that the editor is hung and exit.
+*
+* Input:
+* none
+*
+* Output:
+* Returns nothing
+* Sets fCtrlc
+*
+*************************************************************************/
+int
+CtrlC (
+ ULONG CtrlType
+ )
+{
+
+ if ( !fSpawned ) {
+ CleanExit(4, FALSE );
+ }
+ return TRUE;
+
+ //if ( (CtrlType == CTRL_BREAK_EVENT) ||
+ // (CtrlType == CTRL_C_EVENT) ) {
+ // if ( !fSpawned ) {
+ // CleanExit(4, FALSE);
+ // }
+ // return TRUE;
+ //
+ //} else {
+ // return FALSE;
+ //}
+
+
+
+#if 0
+ static int cCtrlC;
+
+ CtrlType;
+
+ FlushInput ();
+
+ if (fCtrlc) {
+
+ /*
+ //
+ // BUGBUG The original MEP would coung the number of cTrlC and
+ // ask the user if he/she wanted to exit. How do we do that?
+ //
+
+ if (++cCtrlC > 10 ) {
+ COL oldx;
+ LINE oldy;
+ int x;
+ char c = 'x';
+
+ GetTextCursor( &oldx, &oldy );
+ bell();
+ consoleMoveTo( YSIZE, x = domessage ("**PANIC EXIT** Really exit and lose edits?", NULL));
+ while ( c != 'Y' && c != 'N' ) {
+ c = toupper(getch());
+ }
+ domessage (" ", NULL);
+ consoleMoveTo( oldy, oldx );
+
+ if ( c == 'Y' ) {
+ CleanExit( 4, FALSE );
+ } else {
+ fCtrlc = FALSE;
+ cCtrlC = 0;
+ }
+ }
+ */
+ } else {
+ fCtrlc = TRUE;
+ cCtrlC = 1;
+ if ( consoleIsBusyReadingKeyboard() ) {
+ consoleEnterCancelEvent();
+ }
+ }
+ return TRUE;
+#endif
+}
+
+
+
+
+/*** postspawn - Do state restore/re-init after to a spawn.
+*
+* This routine is nominally intended to restore editor state after a spawn
+* operation. However, we also use this during initialization to set it as
+* well.
+*
+* Input:
+* None
+*
+* Output:
+* Returns .....
+*
+*************************************************************************/
+void
+postspawn (
+ flagType fAsk
+ )
+{
+ if (!TESTFLAG(fInit, INIT_VIDEO)) {
+ GetScreenSize ( &YSIZE, &XSIZE);
+ //
+ // We need at lesast 3 lines:
+ // - Status Line
+ // - Message Line
+ // - Edit line
+ //
+ if ( YSIZE < 3 ) {
+ YSIZE = 3;
+ SetScreenSize( YSIZE, XSIZE );
+ }
+ YSIZE -= 2;
+ }
+ SETFLAG (fInit, INIT_VIDEO);
+
+
+ if (fAsk) {
+ printf ("Please strike any key to continue");
+ _getch();
+ FlushInput ();
+ printf ("\n");
+ }
+
+ //if (fSaveScreen) {
+ SaveScreen();
+ //}
+
+ SetScreen ();
+
+ dispmsg (0);
+ newscreen ();
+
+ fSpawned = FALSE;
+
+ SETFLAG (fDisplay, RTEXT | RSTATUS | RCURSOR);
+}
+
+
+
+
+
+/*** VideoTag - return video tag string
+*
+* Purpose:
+*
+* Input:
+*
+* Output:
+*
+* Returns
+*
+*
+* Exceptions:
+*
+* Notes:
+*
+*************************************************************************/
+
+char *
+VideoTag (
+ void
+ )
+{
+ return "vga";
+}
diff --git a/private/utils/mep/src/zprint.c b/private/utils/mep/src/zprint.c
new file mode 100644
index 000000000..473b4d179
--- /dev/null
+++ b/private/utils/mep/src/zprint.c
@@ -0,0 +1,376 @@
+/*** zprint.c - print functions
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+
+#define INCL_DOSPROCESS
+#include "mep.h"
+#include "keyboard.h"
+#include "keys.h"
+
+
+/*** SetPrintCmd - sets the print command string ************************
+*
+* Stores the given <printcmd> switch string to be used by the <print>
+* command and makes pPrintCmd global variable point to it.
+*
+* Input:
+* pCmd = pointer to the new command string
+* NULL means clear it up
+* Output:
+* Returns always TRUE
+*
+* Note:
+* pPrintCmd is assigned NULL when no <printcmd> defined
+*
+*************************************************************************/
+
+flagType
+SetPrintCmd (
+ char *pCmd
+ )
+{
+ if (pPrintCmd != NULL)
+ FREE (pPrintCmd);
+
+ if (strlen (pCmd) != 0)
+ pPrintCmd = ZMakeStr (pCmd);
+ else
+ pPrintCmd = NULL;
+
+ return TRUE;
+}
+
+
+
+
+
+
+/*** zPrint - <print> editor function
+*
+* Prints file(s) or designated area
+*
+* Input:
+* NOARG Print current file
+* TEXTARG List of files to print
+* STREAMARG Print designated area
+* BOXARG Print designated area
+* LINEARG Print designated area
+*
+* Output:
+* Returns TRUE if the printing has been successful, FALSE otherwise
+*
+*************************************************************************/
+flagType
+zPrint (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ )
+{
+ flagType fOK; /* Holds the return value */
+ PFILE pFile; /* general file pointer */
+
+ /*
+ * The following is used only when we scan a list of files (TEXTARG)
+ */
+ flagType fNewFile; /* Did we open a new file ? */
+ buffer pNameList; /* Holds the list of file names */
+ char *pName, *pEndName; /* Begining and end of file names */
+ flagType fDone = FALSE; /* Did we finish with the list ? */
+
+ /*
+ * If we can flush the files, that's the moment
+ */
+ AutoSave ();
+
+ switch (pArg->argType) {
+
+ case NOARG:
+ return (DoPrint (pFileHead, FALSE));
+
+ case TEXTARG:
+ /*
+ * Get the list in a buffer
+ */
+ strcpy ((char *) pNameList, pArg->arg.textarg.pText);
+
+ /*
+ * Empty list = no work
+ */
+ if (!*(pName = whiteskip (pNameList))) {
+ return FALSE;
+ }
+
+ /*
+ * For each name:
+ * - pName points at the begining
+ * - Make pEndName pointing just past its ends
+ * - If it's already the end of the string
+ * then we're done with the list
+ * else put a zero terminator there
+ * - Do the job with the name we've found :
+ * . Get the file handle (if it doen't exist yet,
+ * create one and switch fNewFile on
+ * . Call DoPrint
+ * - Let pName point to the next name
+ */
+ fOK = TRUE;
+
+ do {
+ pEndName = whitescan (pName);
+ if (*pEndName) {
+ *pEndName = 0;
+ } else {
+ fDone = TRUE;
+ }
+
+ if ((pFile = FileNameToHandle (pName, pName)) == NULL) {
+ pFile = AddFile (pName);
+ FileRead (pName, pFile, FALSE);
+ fNewFile = TRUE;
+ } else {
+ fNewFile = FALSE;
+ }
+
+ fOK &= DoPrint (pFile, FALSE);
+
+ if (fNewFile) {
+ RemoveFile (pFile);
+ }
+
+ pName = whiteskip (++pEndName);
+
+ } while (!fDone && *pName);
+
+ /*
+ * Just in case we would change the behaviour to stopping all
+ * things at the first error :
+ *
+ * } while (fOK && !fDone && *pName);
+ */
+ return (fOK);
+
+ case STREAMARG:
+ case BOXARG:
+ case LINEARG:
+ /*
+ * If we print an area, we'll put the text in a temporary file,
+ * call DoPrint with this file and then destroy it.
+ */
+ pFile = GetTmpFile ();
+
+ switch (pArg->argType) {
+ case STREAMARG:
+ CopyStream (pFileHead, pFile,
+ pArg->arg.streamarg.xStart, pArg->arg.streamarg.yStart,
+ pArg->arg.streamarg.xEnd, pArg->arg.streamarg.yEnd,
+ 0L,0L);
+ break;
+
+ case BOXARG:
+ CopyBox (pFileHead, pFile,
+ pArg->arg.boxarg.xLeft, pArg->arg.boxarg.yTop,
+ pArg->arg.boxarg.xRight, pArg->arg.boxarg.yBottom,
+ 0L,0L);
+ break;
+
+ case LINEARG:
+ CopyLine (pFileHead, pFile,
+ pArg->arg.linearg.yStart, pArg->arg.linearg.yEnd,
+ 0L);
+ break;
+ }
+
+ /*
+ * If we have to spawn a print command, then we need to make a real
+ * disk file
+ */
+ if (pPrintCmd && (!FileWrite (pFile->pName, pFile))) {
+ fOK = FALSE;
+ } else {
+ fOK = DoPrint (pFile, TRUE);
+ }
+ RemoveFile (pFile);
+ return (fOK);
+ }
+ argData; fMeta;
+}
+
+
+
+
+
+/*** DoPrint - Does the printing
+*
+* If a <printcmd> has been defined
+* queue up the job for the <print> thread (synchronous exec under DOS)
+* else
+* send the file to the printer, each line at a time
+*
+* Input:
+* pFile = File to be printed.
+*
+* Output:
+* Returns True if the printing has been succesful, False otherwise
+*
+*************************************************************************/
+flagType
+DoPrint (
+ PFILE pFile,
+ flagType fDelete
+ )
+{
+ assert (pFile);
+
+ if (pPrintCmd) {
+ buffer pCmdBuf; // Buffer for command construction
+
+ if (TESTFLAG (FLAGS (pFile), DIRTY) && confirm ("File %s is dirty, do you want to save it ?", pFile->pName))
+ FileWrite (pFile->pName, pFile);
+
+ sprintf (pCmdBuf, pPrintCmd, pFile->pName);
+
+
+ if (pBTDPrint->cBTQ > MAXBTQ-2)
+ disperr (MSGERR_PRTFULL);
+ else
+ if (BTAdd (pBTDPrint, (PFUNCTION)NULL, pCmdBuf) &&
+ (!fDelete || BTAdd (pBTDPrint, (PFUNCTION)CleanPrint, pFile->pName)))
+ return TRUE;
+ else
+ disperr (MSGERR_PRTCANT);
+
+ if (fDelete)
+ _unlink (pFile->pName);
+
+ return FALSE;
+ }
+ else {
+ static char szPrn[] = "PRN";
+ flagType fOK = TRUE; // Holds the return value
+ LINE lCur; // Number of line we're printing
+ char pLineBuf[sizeof(linebuf)+1];
+ // Holds the line we're printing
+ unsigned int cLen; // Length of line we're printing
+ EDITOR_KEY Key; // User input (for abortion)
+ int hPrn; // PRN file handle
+
+ dispmsg (MSG_PRINTING,pFile->pName);
+
+ if ((hPrn = _open (szPrn, O_WRONLY)) == -1) {
+ disperr (MSGERR_OPEN, szPrn, error());
+ fOK = FALSE;
+ }
+ else {
+ for (lCur = 0; lCur < pFile->cLines; lCur++) {
+ if (TypeAhead () &&
+ (Key = TranslateKey(ReadChar()), (Key.KeyCode == 0x130)) &&
+ (!Key.KeyInfo.KeyData.Flags)) {
+
+ fOK = FALSE;
+ break;
+ }
+ cLen = GetLine (lCur, pLineBuf, pFile);
+// * (int UNALIGNED *) (pLineBuf + cLen++) = '\n';
+ * (pLineBuf + cLen++) = '\n';
+ if (_write (hPrn, pLineBuf, cLen) == -1) {
+ disperr (MSGERR_PRTCANT);
+ fOK = FALSE;
+ break;
+ }
+ }
+ _close (hPrn);
+ }
+ domessage (NULL);
+
+ if (fDelete) {
+ _unlink (pFile->pName);
+ }
+ return fOK;
+ }
+}
+
+
+
+
+
+/*** GetTmpFile - Allocates temporary files
+*
+* Input:
+* nothing
+*
+* Output:
+* pointer to the allocated file
+*
+* Remark:
+* We do not use mktemp as it is creating files in the current directory.
+*
+* Notes:
+* - Each new call changes the content of the work buffer, so
+* the caller needs to save the string before doing a new call.
+* - There is a limit of 26 names to be generated
+*
+*************************************************************************/
+PFILE
+GetTmpFile (
+ void
+ )
+{
+ static pathbuf pPath = "";
+ static char *pVarLoc;
+
+ if (!*pPath) {
+ pathbuf pName;
+
+ sprintf (pName, "$TMP:ME%06d.PRN", _getpid);
+ findpath (pName, pPath, TRUE);
+ pVarLoc = strend (pPath) - 10;
+ *pVarLoc = 'Z';
+ }
+
+ if (*pVarLoc == 'Z') {
+ *pVarLoc = 'A';
+ } else {
+ ++*pVarLoc;
+ }
+
+ return (AddFile (pPath));
+
+}
+
+
+
+
+
+/*** Clean - cleans the printer intermediate file
+*
+* Input:
+* pName = Name of the file to get rid of
+*
+* Output:
+* None
+*
+* Remarks: - Under OS/2, since we're called by the background thread, we
+* need to switch stack checking off
+* - The background thread calls this routime at idle time
+*
+*************************************************************************/
+
+// #pragma check_stack (off)
+
+void
+CleanPrint (
+ char *pName,
+ flagType fKilled
+ )
+{
+ _unlink (pName);
+ fKilled;
+}
+
+// #pragma check_stack ()
diff --git a/private/utils/mep/src/zspawn.c b/private/utils/mep/src/zspawn.c
new file mode 100644
index 000000000..480aa2399
--- /dev/null
+++ b/private/utils/mep/src/zspawn.c
@@ -0,0 +1,157 @@
+/*** zspawn.c - shell command and support
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Contains the shell command, and associated support code.
+*
+* Revision History:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+
+#include "mep.h"
+#include "keyboard.h"
+
+
+
+
+/*** zspawn - <shell> editor function
+*
+* <shell> runs command
+* <meta><shell> runs command with no save of current file
+* <arg><shell> uses text from line on screen as program to execute
+* <arg>text<shell> does command /C text
+*
+* Input:
+* Standard Editting Function
+*
+* Output:
+* Returns TRUE on successfull spawn.
+*
+*************************************************************************/
+flagType
+zspawn (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ )
+{
+ buffer sbuf;
+ flagType f = FALSE;
+ LINE i;
+
+ DeclareEvent (EVT_SHELL, NULL);
+ if (!fMeta) {
+ AutoSave ();
+ }
+
+ soutb (0, YSIZE+1, "***** PUSHED *****", fgColor);
+ domessage (NULL);
+ consoleMoveTo( YSIZE, 0 );
+
+ switch (pArg->argType) {
+ case NOARG:
+ f = zspawnp (rgchEmpty, TRUE);
+ break;
+
+ case TEXTARG:
+ strcpy ((char *) sbuf, pArg->arg.textarg.pText);
+ f = zspawnp (sbuf, TRUE);
+ break;
+
+ /* NULLARG converted to TEXTARG*/
+
+ case LINEARG:
+ for (i = pArg->arg.linearg.yStart; i <= pArg->arg.linearg.yEnd; i++) {
+ GetLine (i, sbuf, pFileHead);
+ if (!(f = zspawnp (sbuf, (flagType)(i == pArg->arg.linearg.yEnd)))) {
+ docursor (0, i);
+ break;
+ }
+ }
+ break;
+
+ /* STREAMARG illegal */
+
+ case BOXARG:
+ for (i = pArg->arg.boxarg.yTop; i <= pArg->arg.boxarg.yBottom; i++) {
+ fInsSpace (pArg->arg.boxarg.xRight, i, 0, pFileHead, sbuf);
+ sbuf[pArg->arg.boxarg.xRight+1] = 0;
+ if (!(f = zspawnp (&sbuf[pArg->arg.boxarg.xLeft],
+ (flagType)(i == pArg->arg.boxarg.yBottom)))) {
+ docursor (pArg->arg.boxarg.xLeft, i);
+ break;
+ }
+ }
+ break;
+ }
+
+ fSyncFile (pFileHead, TRUE);
+ return f;
+
+ argData;
+}
+
+
+
+
+/*** zspawnp - shell out a program
+*
+* Execute the specified program, syncronously. Under DOS, if PWB and
+* minimize memory usage is on, we use the shell to execute the command,
+* else we just use system().
+*
+* Input:
+* p = pointer to command string
+* fAsk = TRUE => ask to hit any key before returning
+*
+* Globals:
+* fIsPwb = TRUE => we are executing as PWB
+* memuse = memory usage options
+*
+* Output:
+* Returns TRUE on success
+*
+*************************************************************************/
+flagType
+zspawnp (
+ REGISTER char const *p,
+ flagType fAsk
+ )
+{
+ int i;
+ flagType fCmd = FALSE; /* TRUE => null shell */
+ KBDMODE KbdMode;
+
+ /*
+ * support suppression of the prompt by explicit character in front of
+ * command, then skip any leading whitespace
+ */
+ if (*p == '!') {
+ fAsk = FALSE;
+ p++;
+ }
+
+ p = whiteskip (p);
+ /*
+ * if no command to execute, use command processor
+ */
+ if (!*p) {
+ fCmd = TRUE;
+ fAsk = FALSE;
+ p = pComSpec;
+ }
+
+ KbdMode = KbGetMode();
+ prespawn (CE_VM);
+ i = fCmd ? _spawnlp (P_WAIT, (char *)p, (char *)p, NULL) : system (p);
+ postspawn ((flagType)(!mtest () && fAskRtn && (i != -1) && fAsk));
+ // Hook the keyboard
+ KbHook();
+ KbSetMode(KbdMode);
+
+ if (i == -1) {
+ printerror ("Spawn failed on %s - %s", p, error ());
+ }
+ return (flagType)(i != -1);
+}
diff --git a/private/utils/mep/src/zthread.c b/private/utils/mep/src/zthread.c
new file mode 100644
index 000000000..54c57cd00
--- /dev/null
+++ b/private/utils/mep/src/zthread.c
@@ -0,0 +1,784 @@
+/*** zthread.c - Contains background processing threads code
+*
+* Purpose - Description
+*
+* This is a general purpose background threads manager, which allows to
+* create background threads of execution (BTCreate) to which "jobs" are
+* sent for being executed one at a time (BTAdd).
+*
+* A "Job" can either be:
+*
+* - An external command that will be executed by spawning a
+* command interpreter (the system shell) after standard i/o
+* redirection, so its output will be collected in a "log file"
+* accessible to the user as a Z pseudo-file.
+*
+* - A procedure.
+*
+* Jobs sent to a background thread are guaranteed to be executed
+* synchronously one at a time in the order they have been sent.
+*
+* When killing a background thread, any queued procedure will be called
+* with the fKilled flag on. This allow to have "cleanup" procedures.
+*
+* Warnings:
+*
+* - Take care that the data any queued procedure will eventually need
+* will be available by the time it will be called.
+*
+* - Procedures are called at idle-time (relatively to Z), that means
+* that they can use any Z functionality in them EXCEPT keyboard input.
+*
+* How it works:
+*
+* while (some work is left to be done) {
+* dequeue an action from the pending queue
+* if (it is an external command) {
+* enter a critical section------------+
+* create a pipe w/proper redirection |
+* spawn (no-wait) the action |
+* undo the redirection |
+* leave the critical section----------+
+* while (fgetl (pipe input)) {
+* Take semaphore for editing VM
+* append line to file
+* Release semaphore
+* }
+* }
+* else
+* call the procedure
+* }
+*
+* Basically, for each external command, we create a pipe, spawn the command
+* and let the child fill the pipe. When the child exits, the pipe gets
+* broken (we already closed the _write handle on our side) and fgetl gets
+* back an EOF.
+*
+*
+* Revision History:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+
+#define INCL_DOSQUEUES
+#include "mep.h"
+
+//
+// Duplicate a handle in the current process
+//
+#define DupHandle(a,b) DuplicateHandle(GetCurrentProcess(), \
+ a, \
+ GetCurrentProcess(), \
+ b, \
+ 0, \
+ TRUE, \
+ DUPLICATE_SAME_ACCESS)
+
+
+
+
+#define BTSTACKSIZE 2048
+
+static BTD *pBTList = NULL; /* Background Threads List */
+
+
+#define READ_BUFFER_SIZE 1024
+
+typedef struct _READ_BUFFER {
+
+ PVOID UserBuffer;
+ DWORD UserBufferSize;
+ HANDLE Handle;
+ DWORD BytesLeftInBuffer;
+ PBYTE NextByte;
+ BYTE Buffer[READ_BUFFER_SIZE];
+
+} READ_BUFFER, *PREAD_BUFFER;
+
+VOID
+InitReadBuffer(
+ PVOID UserBuffer,
+ DWORD UserBufferSize,
+ HANDLE Handle,
+ PREAD_BUFFER Buf
+ );
+
+BOOL
+ReadOneLine (
+ PREAD_BUFFER Buf
+ );
+
+
+
+/*** BTCreate - Creates a background thread
+*
+* Purpose:
+* To create a background thread, all we need to do is set up its
+* associated data structure.
+*
+* Input:
+*
+* pName = A symbolic name for the log file, just as <compile> or <print>.
+* This is the name under wich the user will get acces to the log
+* file.
+*
+* Output:
+* Returns a pointer to the allocated Background Thread Data structure
+*
+*************************************************************************/
+BTD *
+BTCreate (
+ char * pName
+ )
+{
+ BTD *pBTD; /* pointer to the created background */
+ /* thread's data structure */
+
+ /*
+ * Allocate the thread's data structure and its log file name
+ */
+ pBTD = (BTD *) ZEROMALLOC (sizeof (BTD));
+
+ /*
+ * Initialize the thread's data structure fields
+ */
+ pBTD->pBTName = ZMakeStr (pName);
+ pBTD->pBTFile = NULL;
+ pBTD->flags = BT_UPDATE;
+ pBTD->cBTQ = pBTD->iBTQPut = pBTD->iBTQGet = 0;
+
+ pBTD->ThreadHandle = INVALID_HANDLE_VALUE;
+ pBTD->ProcAlive = FALSE;
+ InitializeCriticalSection(&(pBTD->CriticalSection));
+
+ /*
+ * We maintain a list of background threads data structures. This is used
+ * by BTKillAll, BTWorking and BTIdle.
+ */
+ pBTD->pBTNext = pBTList;
+ pBTList = pBTD;
+
+ return (pBTD);
+}
+
+
+
+
+
+/*** BTAdd - Send procedure to be called or external command to be extecuted
+* by background thread
+*
+* Input:
+* pBTD - pointer to thread data structure
+* pProc - pointer to the procedure to be called (NULL if external command)
+* pStr - pointer to the procedure parameter (or external command to execute
+* if pBTProc is NULL)
+*
+* Output:
+*
+* Returns TRUE if procedure successfully queued
+*
+*************************************************************************/
+flagType
+BTAdd (
+ BTD *pBTD,
+ PFUNCTION pProc,
+ char *pStr
+ )
+{
+
+ HANDLE Handle; /* Thread handle */
+ DWORD tid; /* Thread id */
+
+ /*
+ * We will access the thread's critical data
+ */
+ EnterCriticalSection(&(pBTD->CriticalSection));
+
+
+ /*
+ * If the queue is full, we cannot insert the request
+ */
+ if (pBTD->cBTQ == MAXBTQ) {
+ LeaveCriticalSection(&(pBTD->CriticalSection));
+ return FALSE;
+ }
+
+
+ /*
+ * If the queue is empty AND there is no thread running,
+ * we have to start the thread...
+ */
+ if (pBTD->cBTQ == 0 && !fBusy(pBTD)) {
+ /*
+ * Create the log file if it doesn't exist yet
+ */
+ if (!(pBTD->pBTFile = FileNameToHandle (pBTD->pBTName, pBTD->pBTName))) {
+ pBTD->pBTFile = AddFile (pBTD->pBTName);
+ FileRead (pBTD->pBTName, pBTD->pBTFile, FALSE);
+ SETFLAG (FLAGS (pBTD->pBTFile), READONLY);
+
+ }
+
+ /*
+ * Start the thread
+ */
+ if (!(Handle = CreateThread( NULL,
+ BTSTACKSIZE,
+ (LPTHREAD_START_ROUTINE)BThread,
+ (LPVOID)pBTD,
+ 0,
+ &tid))) {
+ LeaveCriticalSection(&(pBTD->CriticalSection));
+ return FALSE;
+ }
+ pBTD->ThreadHandle = Handle;
+
+ }
+
+
+ /*
+ * Since there IS room, we just put the job at the PUT pointer.
+ */
+ pBTD->BTQJob[pBTD->iBTQPut].pBTJProc = pProc;
+ pBTD->BTQJob[pBTD->iBTQPut].pBTJStr = pStr ? ZMakeStr (pStr) : NULL;
+
+ pBTD->cBTQ++;
+ pBTD->iBTQPut = (pBTD->iBTQPut >= (MAXBTQ - 1)) ?
+ 0 :
+ pBTD->iBTQPut + 1;
+
+ /*
+ * We're finished with critical data
+ */
+ LeaveCriticalSection(&(pBTD->CriticalSection));
+
+ return TRUE;
+}
+
+
+
+
+
+/*** BTKill - Kill background job, if in progress
+*
+* Purpose:
+* Kills the background job and flushes the thread's associated queue
+*
+* Input:
+* pBTD - pointer to thread data structure
+*
+* Output:
+* Returns TRUE if background thread ends up idling, else false.
+*
+* Notes:
+* We'll call the queued procedures with fKilled flag on, and we'll free
+* the allocated strings.
+* We won't free the thread's stack (the thread has to finish).
+*
+*************************************************************************/
+flagType
+BTKill (
+ BTD *pBTD
+ )
+{
+ REGISTER ULONG iBTQ; /* just an index to the queue elements */
+
+ assert (pBTD);
+
+ /*
+ * We'll work if somthing's running and the user confirms
+ */
+ if ((fBusy(pBTD))
+ && confirm ("Kill background %s ?", pBTD->pBTName)
+ ) {
+
+
+ /*
+ * We will access critical data
+ */
+ EnterCriticalSection(&(pBTD->CriticalSection));
+
+ /*
+ * Kill any child process
+ */
+
+ if (pBTD->ProcAlive) {
+ TerminateProcess(pBTD->ProcessInfo.hProcess, 0);
+ pBTD->ProcAlive = FALSE;
+ }
+
+ /*
+ * Flush the queue:
+ * - Call the queued procedures with fKilled flag on
+ * - Free the strings
+ */
+ for (iBTQ = pBTD->iBTQGet;
+ iBTQ != pBTD->iBTQPut;
+ iBTQ = (iBTQ >= MAXBTQ - 1) ? 0 : iBTQ + 1
+ ) {
+ if (pBTD->BTQJob[iBTQ].pBTJProc != NULL) {
+ (*pBTD->BTQJob[iBTQ].pBTJProc) (pBTD->BTQJob[iBTQ].pBTJStr, TRUE);
+ }
+ if (pBTD->BTQJob[iBTQ].pBTJStr != NULL) {
+ FREE (pBTD->BTQJob[iBTQ].pBTJStr);
+ }
+ }
+
+ pBTD->cBTQ = pBTD->iBTQPut = pBTD->iBTQGet = 0;
+
+ /*
+ * We're done with critical data
+ */
+ LeaveCriticalSection(&(pBTD->CriticalSection));
+
+ /*
+ * We know the background thread didn't finish its job yet (It needs
+ * at least to get the semaphore before exiting), but we pretend...
+ */
+ return TRUE;
+ }
+
+ return (flagType) (!fBusy(pBTD));
+}
+
+
+
+
+/*** BTKillAll - Kill all background jobs, for editor termination
+*
+* Purpose:
+* Kills all background jobs and flush all threads' associated queues
+*
+* Input:
+* none
+*
+* Output:
+* Returns TRUE if all background jobs have been killed, else false.
+*
+*************************************************************************/
+flagType
+BTKillAll (
+ void
+ )
+{
+ REGISTER BTD *pBTD; /* pointer for scanning the threads list */
+
+ for (pBTD = pBTList; pBTD != NULL; pBTD = pBTD->pBTNext) {
+ if (!BTKill (pBTD)) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+
+
+/*** BTWorking - Checks if any background processing is underway...
+*
+* Input:
+* None
+*
+* Output:
+* Returns TRUE if some background processing is active, FALSE otherwise
+*
+* Notes:
+* We are just scanning each thread queue status using the global list.
+*
+*************************************************************************/
+flagType
+BTWorking (
+ void
+ )
+{
+ REGISTER BTD *pBTD; /* pointer for scanning the threads list */
+
+ for (pBTD = pBTList; pBTD != NULL; pBTD = pBTD->pBTNext) {
+ if (fBusy(pBTD)) {
+ break;
+ }
+ }
+ return (flagType) (pBTD != NULL);
+}
+
+
+
+
+
+/*** BThread - Separate thread that starts up jobs as they are put in the queue
+*
+* Input:
+* Nothing
+*
+* Output:
+* Nothing
+*
+* Notes:
+* - We won't send any message nor have any user interaction neither
+* call any non-reentrant procedure, except at idle time.
+*
+*
+*************************************************************************/
+
+// #pragma check_stack (off)
+void
+BThread (
+ BTD *pBTD
+ )
+{
+ /* and for reading the pipe */
+ PFUNCTION pProc; /* procedure to be called */
+ char *pStr; /* External command or parameter */
+
+
+ while (TRUE) {
+
+ //
+ // We will access critical data
+ //
+
+ EnterCriticalSection(&(pBTD->CriticalSection));
+
+ //
+ // If there's nothing in the queue, we end the thread.
+ //
+
+ if (pBTD->cBTQ == 0) {
+ pBTD->flags &= ~BT_BUSY;
+ SETFLAG (fDisplay, RSTATUS);
+ LeaveCriticalSection(&(pBTD->CriticalSection));
+ ExitThread( 0 );
+ }
+
+ //
+ // Set the status as busy
+ //
+
+ pBTD->flags |= BT_BUSY;
+ SETFLAG (fDisplay, RSTATUS);
+
+ //
+ // Copy out the Job
+ //
+
+ pProc = pBTD->BTQJob[pBTD->iBTQGet].pBTJProc;
+ pStr = pBTD->BTQJob[pBTD->iBTQGet].pBTJStr;
+
+ pBTD->cBTQ--;
+ pBTD->iBTQGet = (pBTD->iBTQGet >= (MAXBTQ - 1)) ?
+ 0 :
+ pBTD->iBTQGet + 1;
+
+ //
+ // We're done with the critical data
+ //
+
+ LeaveCriticalSection(&(pBTD->CriticalSection));
+
+ if (pProc != NULL) {
+
+ //
+ // Procedure to call: we'll do it at idle time and we'll free any
+ // stored parameter
+ //
+
+ WaitForSingleObject( semIdle, INFINITE);
+ (*pProc) (pStr, FALSE);
+ if (pStr)
+ FREE (pStr);
+ SetEvent( semIdle );
+ }
+ else {
+
+ //
+ // External command to spawn: First we build the command line
+ //
+
+ //
+ // Here we spawn processes under the Win32 subsystem of
+ // NT.
+ //
+
+ char CommandLine[MAX_PATH]; // Command line
+ BOOL StatusOk; // status value
+ HANDLE SavedStdIn; // Original Standard Input
+ HANDLE SavedStdOut; // Original Standard Output
+ HANDLE SavedStdErr; // Original Standard Error
+ HANDLE PipeRead; // Pipe - read end
+ HANDLE PipeWrite; // Pipe - write end
+ HANDLE OutHandle, ErrHandle;
+ STARTUPINFO StartupInfo; // Startup information
+ linebuf LineBuf; // Buffer for 1 line
+ READ_BUFFER ReadBuffer;
+ BOOL MoreToRead = TRUE; // There is more to read
+ SECURITY_ATTRIBUTES PipeAttributes; // Pipe Security attributes
+
+
+ strcpy(CommandLine, pComSpec); // Call command interpreter
+ strcat(CommandLine," /c "); // and execute
+ strcat(CommandLine, pStr); // the specified command
+
+ //
+ // First we save the standard handles
+ //
+
+ SavedStdIn = GetStdHandle(STD_INPUT_HANDLE);
+ SavedStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
+ SavedStdErr = GetStdHandle(STD_ERROR_HANDLE);
+
+ //
+ // Create a pipe
+ //
+
+ PipeAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
+ PipeAttributes.lpSecurityDescriptor = NULL,
+ PipeAttributes.bInheritHandle = TRUE;
+ StatusOk = CreatePipe( &PipeRead,
+ &PipeWrite,
+ &PipeAttributes,
+ 0 );
+
+ if (!StatusOk) {
+ domessage("Cannot create pipe - did not create process.");
+ continue;
+ }
+
+ //
+ // We will mess with standard handles, so do it
+ // in the IO critical section.
+ //
+
+ EnterCriticalSection(&IOCriticalSection);
+
+ //
+ // Redirect standard handles
+ //
+
+ SetStdHandle(STD_INPUT_HANDLE, INVALID_HANDLE_VALUE);
+ SetStdHandle(STD_OUTPUT_HANDLE, PipeWrite);
+ SetStdHandle(STD_ERROR_HANDLE, PipeWrite);
+
+ //
+ // Start the process
+ //
+
+ memset(&StartupInfo, '\0', sizeof(STARTUPINFO));
+ StartupInfo.cb = sizeof(STARTUPINFO);
+
+ StatusOk = CreateProcess( NULL,
+ CommandLine,
+ NULL,
+ NULL,
+ TRUE,
+ 0,
+ NULL,
+ NULL,
+ &StartupInfo,
+ &(pBTD->ProcessInfo) );
+
+ //
+ // Now restore the original handles
+ //
+ OutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
+ CloseHandle(OutHandle);
+
+ ErrHandle = GetStdHandle(STD_ERROR_HANDLE);
+
+ if (ErrHandle != OutHandle && ErrHandle != INVALID_HANDLE_VALUE)
+ CloseHandle(ErrHandle);
+
+
+ SetStdHandle(STD_INPUT_HANDLE, SavedStdIn);
+ SetStdHandle(STD_OUTPUT_HANDLE, SavedStdOut);
+ SetStdHandle(STD_ERROR_HANDLE, SavedStdErr);
+
+ LeaveCriticalSection(&IOCriticalSection);
+
+
+ if (StatusOk) {
+
+ //
+ // Copy all the output to the log file
+ //
+
+ InitReadBuffer( LineBuf, sizeof(linebuf), PipeRead, &ReadBuffer );
+
+ while (MoreToRead) {
+
+ if (ReadOneLine( &ReadBuffer ) ) {
+
+ //
+ // Append the new line
+ //
+
+ WaitForSingleObject( semIdle, INFINITE);
+ AppFile (LineBuf, pBTD->pBTFile);
+
+ //
+ // If the update flag is on, then we must update
+ // instances of the file so the last line we read
+ // will be displayed
+ //
+ if (pBTD->flags & BT_UPDATE)
+ UpdateIf (pBTD->pBTFile, pBTD->pBTFile->cLines - 1, FALSE);
+
+ SetEvent( semIdle );
+
+ }
+ else {
+ //
+ // We only stop trying if the process has terminated
+ //
+ if (WaitForSingleObject((pBTD->ProcessInfo.hProcess), 0 ) == 0)
+ MoreToRead = FALSE;
+ }
+ }
+
+ //
+ // Close the pipe handles (Note that the PipeWrite handle
+ // was closed above)
+
+ WaitForSingleObject( semIdle, INFINITE);
+ CloseHandle(PipeRead);
+ SetEvent( semIdle );
+
+ //
+ // Wait for the spawned process to terminate
+ //
+ }
+
+ WaitForSingleObject( semIdle, INFINITE);
+ if (pStr)
+ FREE (pStr);
+ bell ();
+ SetEvent( semIdle );
+
+ }
+
+ }
+}
+// #pragma check_stack ()
+
+
+VOID
+InitReadBuffer(
+ PVOID UserBuffer,
+ DWORD UserBufferSize,
+ HANDLE Handle,
+ PREAD_BUFFER Buf
+ )
+{
+ Buf->UserBuffer = UserBuffer;
+ Buf->UserBufferSize = UserBufferSize;
+ Buf->Handle = Handle;
+ Buf->BytesLeftInBuffer = 0;
+ Buf->NextByte = Buf->Buffer;
+}
+
+
+int
+ReadOneChar (
+ PREAD_BUFFER pbuf
+ )
+{
+ //
+ // Check to see if buffer is empty
+ //
+
+ if (pbuf->BytesLeftInBuffer == 0) {
+
+ //
+ // Check to see if a fill of the buffer fails
+ //
+
+ if (!ReadFile (pbuf->Handle, pbuf->Buffer, READ_BUFFER_SIZE, &pbuf->BytesLeftInBuffer, NULL)) {
+
+ //
+ // Fill failed, indicate buffer is empty and return EOF
+ //
+
+ pbuf->BytesLeftInBuffer = 0;
+ return -1;
+ }
+
+ //
+ // Check to see if nothing read
+ //
+ if (pbuf->BytesLeftInBuffer == 0)
+ return -1;
+
+ pbuf->NextByte = pbuf->Buffer;
+ }
+
+ //
+ // Buffer has pbuf->BytesLeftInBuffer chars left starting at
+ // pbuf->NextByte
+ //
+
+ pbuf->BytesLeftInBuffer--;
+ return *pbuf->NextByte++;
+}
+
+//
+// Assumes tabs are 8 spaces wide on input
+//
+
+
+BOOL
+ReadOneLine (
+ PREAD_BUFFER pbuf
+ )
+{
+ PBYTE p;
+ PBYTE pEnd;
+ int c;
+ int cchTab;
+
+ //
+ // Set pointer to beginning of output buffer
+ //
+
+ p = (PBYTE)pbuf->UserBuffer;
+ pEnd = p + pbuf->UserBufferSize - 1;
+
+ //
+ // read in chars, ignoring \r until buffer is full, \n, or \0
+ // expands tabs
+ //
+
+ while (p < pEnd) {
+ c = ReadOneChar (pbuf);
+
+ //
+ // CR is noise in line (we ignore it)
+ //
+
+ if (c == '\r')
+ continue;
+
+ //
+ // EOF or NL is end-of-line indicator
+ //
+
+ if (c == -1 || c == '\n')
+ break;
+
+ //
+ // tabs are expanded to 8 column boundaries, but not to
+ // overflow the line
+ //
+
+ if (c == '\t') {
+ cchTab = 8 - (p - (PBYTE)pbuf->UserBuffer) % 8;
+ cchTab = min (cchTab, pEnd - p);
+ while (cchTab--)
+ *p++ = (BYTE) ' ';
+ }
+ else
+ *p++ = (BYTE) c;
+ }
+
+ *p = 0;
+
+ return c != -1 || strlen (pbuf->UserBuffer) != 0;
+}
diff --git a/private/utils/mep/src/zutil.c b/private/utils/mep/src/zutil.c
new file mode 100644
index 000000000..4d844eccd
--- /dev/null
+++ b/private/utils/mep/src/zutil.c
@@ -0,0 +1,378 @@
+/*** zutil.c - misc utility functions not big enough to warrent their own file
+*
+* Copyright <C> 1988, Microsoft Corporation
+*
+* Revision History:
+* 26-Nov-1991 mz Strip off near/far
+*
+*************************************************************************/
+
+#include "mep.h"
+
+
+void *
+ZeroMalloc (
+ int Size
+ )
+{
+ return calloc(Size, 1);
+}
+
+
+
+
+void *
+ZeroRealloc (
+ void *pmem,
+ int Size
+ )
+{
+ int cbOrg = 0; /* original size of block */
+ void *p; /* pointer to returned block */
+
+ if (pmem) {
+ cbOrg = _msize (pmem);
+ }
+
+ p = realloc(pmem, Size);
+
+ /*
+ * if reallocated, and now larger, zero fill the new addition to the block.
+ * if a new allocation, zero fill the whole thing.
+ */
+ if (cbOrg < Size) {
+ memset ((char *)p+cbOrg, 0, Size-cbOrg);
+ }
+ return p;
+}
+
+
+
+
+
+unsigned
+MemSize (
+ void * p
+ )
+{
+ return _msize (p);
+}
+
+
+
+
+
+/*** ZMakeStr - Make local heap copy of string
+*
+* Allocate local memory for the passed string, and copy it into that memory.
+*
+* Input:
+* p = Pointer to string
+*
+* Output:
+* Returns pointer to newly allocated memory
+*
+* Exceptions:
+* LMAlloc
+*
+*************************************************************************/
+char *
+ZMakeStr (
+ char const *p
+ )
+{
+ return strcpy (ZEROMALLOC (strlen (p)+1), p);
+}
+
+
+
+
+
+/*** ZReplStr - Modify local heap copy of string
+*
+* Reallocate local memory for the passed string, and copy it into that memory.
+*
+* Input:
+* pDest = pointer to heap entry (NULL means get one)
+* p = Pointer to string
+*
+* Output:
+* Returns pointer to newly allocated memory
+*
+* Exceptions:
+* LMAlloc
+*
+*************************************************************************/
+char *
+ZReplStr (
+ char *pDest,
+ char const *p
+ )
+{
+ return pDest ? strcpy (ZEROREALLOC (pDest, strlen (p)+1), p) : ZMakeStr(p);
+}
+
+
+
+
+
+/*** DoCancel - clear input & force display update
+*
+* Input:
+* none
+*
+* Output:
+* Returns nothing
+*
+*************************************************************************/
+flagType
+DoCancel ()
+{
+ FlushInput ();
+ SETFLAG (fDisplay, RTEXT | RSTATUS);
+ return TRUE;
+}
+
+
+
+
+
+/*** cancel - <cancel> editting function
+*
+*
+*
+* Input:
+* Standard editing function
+*
+* Output:
+* Returns TRUE
+*
+*************************************************************************/
+flagType
+cancel (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ )
+{
+ if (pArg->argType == NOARG) {
+ fMeta = fMessUp;
+ domessage (NULL);
+ if (!fMeta) {
+ DeclareEvent (EVT_CANCEL, NULL);
+ }
+ } else {
+ domessage ("Argument cancelled");
+ resetarg ();
+ }
+ return DoCancel ();
+
+ argData;
+}
+
+
+
+
+/*** testmeta- return meta status & clear
+*
+* Returns current status of meta indicator, and clears it.
+*
+* Input:
+* none
+*
+* Output:
+* Returns previous setting of meta
+*
+*************************************************************************/
+flagType
+testmeta (
+ void
+ )
+{
+ flagType f;
+
+ f = fMeta;
+ fMeta = FALSE;
+ if (f) {
+ SETFLAG( fDisplay, RSTATUS );
+ }
+ return f;
+}
+
+
+
+
+
+/*** meta - <meta> editor function
+*
+* Toggle state of the meta flag, and cause screen status line to be updated.
+*
+* Input:
+* Standard editor function.
+*
+* Output:
+* Returns new META state
+*
+*************************************************************************/
+flagType
+meta (
+ CMDDATA argData,
+ ARG *pArg,
+ flagType MetaFlag
+ )
+{
+ SETFLAG( fDisplay, RSTATUS );
+ return fMeta = (flagType)!fMeta;
+
+ argData; pArg; MetaFlag;
+}
+
+
+
+
+
+/*** insertmode - <insertmode> editor function
+*
+* Toggle setting of fInsert flag & cause status line to be updated.
+*
+* Input:
+* Standard editting function
+*
+* Output:
+* Returns new fInsert value.
+*
+*************************************************************************/
+flagType
+insertmode (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ )
+{
+ SETFLAG( fDisplay, RSTATUS );
+ return fInsert = (flagType)!fInsert;
+
+ argData; pArg; fMeta;
+}
+
+
+
+
+
+/*** zmessage - <message> editor function
+*
+* Macro allowing the user to display a message on the dialog line
+*
+* Input:
+* User message (textarg) or no arg to clear the dialog line
+*
+* Output:
+* Returns always TRUE
+*
+*
+*************************************************************************/
+flagType
+zmessage (
+ CMDDATA argData,
+ ARG * pArg,
+ flagType fMeta
+ )
+{
+ linebuf lbMsg;
+ char *pch = lbMsg;
+
+ switch (pArg->argType) {
+
+ case NOARG:
+ pch = NULL;
+ break;
+
+ case TEXTARG:
+ strcpy ((char *) lbMsg, pArg->arg.textarg.pText);
+ break;
+
+ case NULLARG:
+ GetLine (pArg->arg.nullarg.y, lbMsg, pFileHead);
+ goto MsgAdjust;
+
+ case LINEARG:
+ GetLine (pArg->arg.linearg.yStart, lbMsg, pFileHead);
+ goto MsgAdjust;
+
+ case STREAMARG:
+ fInsSpace (pArg->arg.streamarg.xStart, pArg->arg.streamarg.yStart, 0, pFileHead, lbMsg);
+ if (pArg->arg.streamarg.yStart == pArg->arg.streamarg.yEnd) {
+ *pLog (lbMsg, pArg->arg.streamarg.xEnd+1, TRUE) = 0;
+ }
+ pch = pLog (lbMsg, pArg->arg.streamarg.xStart, TRUE);
+ goto MsgAdjust;
+
+ case BOXARG:
+ fInsSpace (pArg->arg.boxarg.xRight, pArg->arg.boxarg.yTop, 0, pFileHead, lbMsg);
+ *pLog (lbMsg, pArg->arg.boxarg.xRight+1, TRUE) = 0;
+ pch = pLog (lbMsg, pArg->arg.boxarg.xLeft, TRUE);
+MsgAdjust:
+ if (pch > lbMsg) {
+ strcpy (lbMsg, pch);
+ pch = lbMsg;
+ }
+ *pLog (lbMsg, XSIZE, TRUE) = 0;
+ break;
+ }
+
+ domessage (pch);
+ return TRUE;
+
+ argData; fMeta;
+}
+
+
+
+
+
+/*** GetCurPath gets the current drive and directory
+*
+* Input:
+* szBuf: buffer to receive the current path
+*
+* Output:
+* Nothing
+*
+*************************************************************************/
+void
+GetCurPath (
+ char *szBuf
+ )
+{
+
+ if (!GetCurrentDirectory(MAX_PATH, szBuf)) {
+ *szBuf = '\00';
+ }
+ _strlwr (szBuf);
+}
+
+
+
+
+
+/*** SetCurPath - sets the current drive and directory
+*
+* Input:
+* szPath: New path
+*
+* Output:
+* TRUE if successful, FALSE otherwise.
+*
+*************************************************************************/
+flagType
+SetCurPath (
+ char *szPath
+ )
+{
+
+ if (_chdir (szPath) == -1) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/mode/argument.cxx b/private/utils/mode/argument.cxx
new file mode 100644
index 000000000..ff5015de2
--- /dev/null
+++ b/private/utils/mode/argument.cxx
@@ -0,0 +1,2312 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Argument
+
+Abstract:
+
+ Argument processing for the MODE utility.
+
+ The functions in this file:
+
+ 1.- Parse the MODE command line.
+ 2.- Perform some basic argument validation.
+ 3.- Make a request packet that will be eventually routed to a
+ device handler.
+
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 26-Jun-1991
+
+Notes:
+
+ Due to the complexity of the MODE command line, and the fact that
+ we have to support both the DOS5 syntax (tagged parameters) and
+ the old DOS syntax (positional parameters), MODE does not use
+ the standard ULIB argument parsing. MODE does its own parsing
+ instead.
+
+ The mode command-line can take any of the following forms:
+
+ MODE [/?]
+
+ MODE [device] [/STATUS]
+
+ MODE device cp PREPARE=string
+
+ MODE device cp REFRESH
+
+ MODE device cp SELECT=codepage
+
+ MODE device cp [/STATUS]
+
+ MODE LPTn[:] [c][,l][,r]]
+
+ MODE LPTn[:] [COLS=c] [LINES=l] [RETRY=r]
+
+ MODE LPTn[:]=COMm[:]
+
+ MODE COMm[:] [b[,p[,d[,s[,r]]]]]
+
+ MODE COMm[:] [BAUD=b] [PARITY=p] [DATA=d] [STOP=s] [RETRY=r]
+ [to=on|off] [xon=on|off] [odsr=on|off] [octs=on|off]
+
+ MODE [c[,l]]
+
+ MODE CON[:] [COLS=c] [LINES=l]
+
+ MODE CON[:] [RATE=r DELAY=d]
+
+
+ where:
+
+
+ device := LPTn[:] | COMm[:] | CON[:]
+ cp := CP | CODEPAGE
+
+
+
+ The argument parsing of MODE does a syntax-directed translation of
+ the command line into a request packet. The translation is based on
+ the following language. Note that some terminal symbols (in uppercase)
+ might be language dependent.
+
+
+ mode := MODE { statusline | lptline | comline | conline | videoline }
+
+ statusline := /STA*
+
+ lptline := lptdev { lptredir | lptsetold | lptsetnew | lptcp | lptstatus }
+ lptred := =comdev
+ lptset := { n[,n][,c] | [COLS=n] [LINES=n] [RETRY=c] }
+ lptcp := cpstuff
+ lptstatus := { /STA* | }
+
+ comline := comdev { comset | comstatus }
+ comset := { n[,c[,n[,f[,c]]]] | [BAUD=n] [PARITY=c] [DATA=n] [STOP=f] [RETRY=c] }
+ [to=on|off] [xon=on|off] [odsr=on|off] [octs=on|off]
+ comstatus := { /STA* | }
+
+ conline := condev { conrc | contyp | concp | constatus }
+ conrc := [COLS=n] [LINES=n]
+ contyp := RATE=n DELAY=n
+ concp := cpstuff
+ constatus := { /STA* | }
+
+ videoline := n[,n]
+
+ cpstuff := cp { prepare | refresh | select | cpstatus}
+ cp := CP | CODEPAGE
+ prepare := PREPARE=*
+ refresh := REFRESH
+ select := SELECT=n
+ cpstatus := { /STA* | }
+
+ comdev := COMn[:]
+ lptdev := LPTn[:]
+ condev := CON[:]
+
+ n := Integer number
+ f := floating point number
+ c := character
+
+
+
+ The functions in this file parse the language shown above. Most of
+ the functions have names that correspond to non-terminal symbols in
+ the language.
+
+
+ There are 3 main functions used for reading the command line:
+
+ Match() - This function matches a pattern against whatever
+ is in the command line at the current position.
+
+ Note that this does not advance our current position
+ within the command line.
+
+ If the pattern has a magic character, then the
+ variables MatchBegin and MatchEnd delimit the
+ substring of the command line that matched that
+ magic character.
+
+
+ Advance() - This functions advances our current position within
+ the command line. The amount by which the position
+ is advanced is determined by the the last Match().
+
+
+ EndOfInput()- Returns TRUE if the command line has been consumed.
+
+
+
+ e.g. If the command line has the string "MODE COM1: 1200"
+
+ This is what the following sequence would do
+
+ Match( "*" ); // TRUE (matches "MODE")
+ Advance();
+
+ //
+ // Note that Match() does not advance our position
+ //
+ MATCH( "LPT" ); // FALSE (no match)
+ MATCH( "COM#" ); // TRUE (matches "COM" )
+ //
+ // At this point, MatchBegin and MatchEnd delimit the
+ // substring "1"
+ //
+ MATCH( "FOO" ); // FALSE (no match)
+
+ MATCH( "C*" ); // TRUE (matches "COM1:");
+ //
+ // At this point, MatchBegin and MatchEnd delimit the
+ // substring "OM1:"
+ //
+ Advance();
+
+ Match( "#" ); // TRUE (matches "1200");
+ Advance();
+
+ EndOfInput(); // TRUE
+
+
+
+Revision History:
+
+
+--*/
+
+
+#include "mode.hxx"
+#include "common.hxx"
+#include "lpt.hxx"
+#include "com.hxx"
+#include "cons.hxx"
+
+
+extern "C" {
+
+ #include <ctype.h>
+ #include <string.h>
+
+}
+
+
+//
+//Static data
+//
+PWSTRING CmdLine; // The command line
+CHNUM CharIndex; // Index of current character
+CHNUM AdvanceIndex; // Index of next parameter
+CHNUM ParmIndex; // Index of current parameter
+CHNUM MatchBegin; // First index of match
+CHNUM MatchEnd; // Last index of match
+
+//
+// Patterns.
+//
+// Most patterns contain terminal symbols. Certain characters in a
+// pattern have a magic meaning:
+//
+// '*' Matches everything up to the end of the parameter (parameters are
+// delimited by blank space).
+//
+// '#' Matches a sequence of digits
+//
+// '@' Matches a single character
+//
+// '[' Starts an optional sequence. If the first character in the
+// the sequence matches, then all the sequence should match. If
+// the first character in the sequence does not match, then the
+// sequence is skipped.
+//
+// ']' End of optional sequence
+//
+//
+
+
+//
+// Prototypoes
+//
+
+PREQUEST_HEADER
+LptLine (
+ );
+
+PREQUEST_HEADER
+LptRedir (
+ IN ULONG DeviceNumber
+ );
+
+PREQUEST_HEADER
+LptSet (
+ IN ULONG DeviceNumber
+ );
+
+PREQUEST_HEADER
+LptCp (
+ IN ULONG DeviceNumber
+ );
+
+PREQUEST_HEADER
+ComLine (
+ );
+
+PREQUEST_HEADER
+ComSet (
+ IN ULONG DeviceNumber
+ );
+
+PREQUEST_HEADER
+ConLine (
+ );
+
+PREQUEST_HEADER
+ConRc (
+ );
+
+PREQUEST_HEADER
+ConTyp (
+ );
+
+PREQUEST_HEADER
+ConCp (
+ );
+
+PREQUEST_HEADER
+VideoLine (
+ );
+
+PREQUEST_HEADER
+CpStuff (
+ IN DEVICE_TTYPE DeviceType,
+ IN ULONG DeviceNumber
+ );
+
+VOID
+AllocateResource(
+ );
+
+VOID
+DeallocateResource(
+ );
+
+BOOLEAN
+Match(
+ IN PCSTR Pattern
+ );
+
+BOOLEAN
+Match(
+ IN PCWSTRING Pattern
+ );
+
+VOID
+Advance(
+ );
+
+BOOLEAN
+EndOfInput(
+ );
+
+PREQUEST_HEADER
+MakeRequest(
+ IN DEVICE_TTYPE DeviceType,
+ IN LONG DeviceNumber,
+ IN REQUEST_TYPE RequestType,
+ IN ULONG Size
+ );
+
+ULONG
+GetNumber(
+ );
+
+
+
+
+INLINE
+BOOLEAN
+EndOfInput(
+ )
+
+/*++
+
+Routine Description:
+
+ Finds out if we are at the end of the command line.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ BOOLEAN - TRUE if at the end of input, FALSE otherwise
+
+
+--*/
+
+{
+
+ return (CharIndex >= CmdLine->QueryChCount());
+
+}
+
+PREQUEST_HEADER
+GetRequest(
+ )
+
+/*++
+
+Routine Description:
+
+ Parses the command line and makes a device request.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Pointer to the device request.
+
+Notes:
+
+--*/
+
+{
+
+ PREQUEST_HEADER Request = NULL;
+ DSTRING Switches;
+
+ Switches.Initialize("/-");
+
+ //
+ // Allocate strings (i.e. patterns ) from the resource
+ //
+ AllocateResource();
+
+ //
+ // Get the command line and parse it
+ //
+ if ( CmdLine->Initialize( GetCommandLine() )) {
+
+ //
+ // Before anything else, we look for a help switch somewhere
+ // in the command line. This kind of stinks, but this is how
+ // MODE works under DOS, se let's be compatible...
+ //
+ CharIndex = 0;
+
+ while ( TRUE ) {
+
+ //
+ // Look for a switch
+ //
+ CharIndex = CmdLine->Strcspn( &Switches, CharIndex );
+
+ if ( CharIndex != INVALID_CHNUM ) {
+
+ //
+ // There is a switch, see if it is the help switch
+ //
+ CharIndex++;
+
+ if ( Match( "?" )) {
+
+ //
+ // This is a help switch, Display help
+ //
+ DisplayMessageAndExit( MODE_MESSAGE_HELP, NULL, EXIT_SUCCESS );
+
+ }
+ } else {
+ break;
+ }
+ }
+
+ //
+ // No help requested, now we can parse the command line. First we
+ // initialize our indeces.
+ //
+ ParmIndex = 0;
+ CharIndex = 0;
+ AdvanceIndex = 0;
+
+ //
+ // Match the program name
+ //
+ Advance();
+
+ Match( "*" );
+ Advance();
+
+ //
+ // If there are no parameters, or the only parameter is the
+ // status switch, then this is a request for the status of
+ // all devices.
+ //
+ if ( EndOfInput() ) {
+
+ Request = MakeRequest( DEVICE_TYPE_ALL,
+ ALL_DEVICES,
+ REQUEST_TYPE_STATUS,
+ sizeof( REQUEST_HEADER ) );
+
+ } else if ( Match( "/STA*" ) ) {
+
+ Advance();
+
+ if ( !EndOfInput() ) {
+
+ ParseError();
+ }
+
+ Request = MakeRequest( DEVICE_TYPE_ALL,
+ ALL_DEVICES,
+ REQUEST_TYPE_STATUS,
+ sizeof( REQUEST_HEADER ) );
+
+
+ } else if ( Match( "LPT#[:]" ) ) {
+
+ //
+ // lptline
+ //
+ Request = LptLine();
+
+ } else if ( Match( "COM#[:]" ) ) {
+
+ //
+ // comline
+ //
+ Request = ComLine();
+
+ } else if ( Match( "CON[:]" ) ) {
+
+ //
+ // conline
+ //
+ Request = ConLine();
+
+ } else if ( Match( "#" ) ) {
+
+ //
+ // videoline
+ //
+ Request = VideoLine();
+
+ } else {
+
+ //
+ // Parse error
+ //
+ ParseError();
+ }
+
+ } else {
+
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY, NULL, (ULONG)EXIT_ERROR );
+
+ }
+
+ //
+ // Deallocate strings from resource
+ //
+ DeallocateResource();
+
+ //
+ // Return the request
+ //
+ return Request;
+
+}
+
+PREQUEST_HEADER
+LptLine (
+ )
+
+/*++
+
+Routine Description:
+
+ Takes care of parsing the lptline non-terminal symbol
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Pointer to the device request.
+
+Notes:
+
+--*/
+
+{
+ PREQUEST_HEADER Request;
+ ULONG DeviceNumber;
+
+ //
+ // Note that at this point we have matched the lpt device.
+ // Get the device number;
+ //
+ DeviceNumber = GetNumber();
+
+ Advance();
+
+ if ( EndOfInput() ) {
+
+ //
+ // End redirection
+ //
+ Request = MakeRequest( DEVICE_TYPE_LPT,
+ DeviceNumber,
+ REQUEST_TYPE_LPT_ENDREDIR,
+ sizeof( REQUEST_HEADER ) );
+
+ } else if ( Match( "/STA*" ) ) {
+
+ //
+ // Status request
+ //
+ Request = MakeRequest( DEVICE_TYPE_LPT,
+ DeviceNumber,
+ REQUEST_TYPE_STATUS,
+ sizeof( REQUEST_HEADER ) );
+
+ } else if ( Match ( "=" ) ) {
+
+ //
+ // lptredir
+ //
+ Request = LptRedir( DeviceNumber );
+
+ } else if ( Match( "#" ) || Match( "COLS=#" ) ||
+ Match( "LINES=#" ) || Match( "RETRY=@" ) ) {
+
+ //
+ // lptset
+ //
+ Request = LptSet( DeviceNumber );
+
+ } else if ( Match( "CP" ) || Match( "CODEPAGE" ) ) {
+
+ //
+ // lptcp
+ //
+ Request = LptCp( DeviceNumber );
+
+ } else {
+
+ //
+ // Error
+ //
+ ParseError();
+
+ }
+
+ return Request;
+
+}
+
+PREQUEST_HEADER
+LptRedir (
+ IN ULONG DeviceNumber
+ )
+
+/*++
+
+Routine Description:
+
+ Takes care of parsing the lptredir non-terminal symbol
+
+Arguments:
+
+ DeviceNumber - Supplies the device number
+
+Return Value:
+
+ Pointer to the device request.
+
+Notes:
+
+--*/
+
+{
+ PREQUEST_HEADER Request;
+ PLPT_REQUEST LptRequest;
+ ULONG ComDevice;
+
+ Advance();
+
+ //
+ // Can only redirect to COM devices
+ //
+ if ( Match( "COM#[:]" ) ) {
+
+ ComDevice = GetNumber();
+
+ Request = MakeRequest( DEVICE_TYPE_LPT,
+ DeviceNumber,
+ REQUEST_TYPE_LPT_REDIRECT,
+ sizeof(LPT_REQUEST ) );
+
+ LptRequest = (PLPT_REQUEST)Request;
+
+ LptRequest->Data.Redirect.DeviceType = DEVICE_TYPE_COM;
+ LptRequest->Data.Redirect.DeviceNumber = ComDevice;
+
+ } else {
+
+ //
+ // Error
+ //
+ ParseError();
+
+ }
+
+ return Request;
+}
+
+PREQUEST_HEADER
+LptSet (
+ IN ULONG DeviceNumber
+ )
+
+/*++
+
+Routine Description:
+
+ Takes care of parsing the lptset non-terminal symbol
+
+Arguments:
+
+ DeviceNumber - Supplies the device number
+
+Return Value:
+
+ Pointer to the device request.
+
+Notes:
+
+--*/
+
+{
+ PREQUEST_HEADER Request;
+ PLPT_REQUEST LptRequest;
+ BOOLEAN SetCols = FALSE;
+ BOOLEAN SetLines = FALSE;
+ BOOLEAN SetRetry = FALSE;
+ ULONG Cols;
+ ULONG Lines;
+ WCHAR Retry;
+
+
+ if ( Match( "#" ) ) {
+
+ //
+ // Old syntax, where parameter are positional and comma-delimited.
+ //
+ // We will use the following automata for parsing the input
+ // (eoi = end of input)
+ //
+ //
+ // eoi
+ // [Cols]------------->[End]
+ // | ^
+ // |, |eoi
+ // v |
+ // [X]-----------+
+ // | ^
+ // | # |eoi
+ // +-->[Lines]--+
+ // | | ^
+ // | |, |
+ // |<----+ |
+ // | |
+ // |, |eoi
+ // | |
+ // v |
+ // [Y]-----------+
+ // | ^
+ // | @ |eoi
+ // +-->[Retry]--+
+ //
+ //
+
+ Cols = GetNumber();
+ SetCols = TRUE;
+ Advance();
+
+ //
+ // X:
+ //
+ if ( !Match( "," ) ) {
+ goto Eoi;
+ }
+ Advance();
+
+ if ( Match( "#" ) ) {
+
+ // n
+ // Lines
+ //
+ Lines = GetNumber();
+ SetLines = TRUE;
+ Advance();
+ }
+
+ //
+ // Y:
+ //
+ if ( !Match ( "," ) ) {
+ goto Eoi;
+ }
+
+ if ( Match( "@" ) ) {
+
+ //
+ // Retry
+ //
+ Retry = CmdLine->QueryChAt( MatchBegin );
+ SetRetry = TRUE;
+ Advance();
+ }
+
+Eoi:
+ if ( !EndOfInput() ) {
+
+ //
+ // Error
+ //
+ ParseError();
+
+ }
+
+ } else {
+
+ //
+ // New syntax, where parameters are tagged. The language assumes
+ // that all parameters are optional (as long as there is at least
+ // one present). If some is required, it is up to the Device
+ // handler to complain latter on.
+ //
+
+ while ( !EndOfInput() ) {
+
+ if ( Match( "COLS=#" ) ) {
+ //
+ // COLS=
+ //
+ Cols = GetNumber();
+ SetCols = TRUE;
+ Advance();
+
+ } else if ( Match( "LINES=#" ) ) {
+ //
+ // LINES=
+ //
+ Lines = GetNumber();
+ SetLines = TRUE;
+ Advance();
+
+ } else if ( Match( "RETRY=@" ) ) {
+ //
+ // RETRY=
+ //
+ Retry = CmdLine->QueryChAt( MatchBegin );
+ SetRetry = TRUE;
+ Advance();
+
+ } else {
+
+ ParseError();
+ }
+ }
+
+ }
+
+
+ //
+ // Now that we parsed all the parameters, we make the request
+ // packet.
+ //
+ Request = MakeRequest( DEVICE_TYPE_LPT,
+ DeviceNumber,
+ REQUEST_TYPE_LPT_SETUP,
+ sizeof(LPT_REQUEST ) );
+
+ LptRequest = (PLPT_REQUEST)Request;
+
+ LptRequest->Data.Setup.SetCol = SetCols;
+ LptRequest->Data.Setup.SetLines = SetLines;
+ LptRequest->Data.Setup.SetRetry = SetRetry;
+ LptRequest->Data.Setup.Col = Cols;
+ LptRequest->Data.Setup.Lines = Lines;
+ LptRequest->Data.Setup.Retry = Retry;
+
+ return Request;
+}
+
+PREQUEST_HEADER
+LptCp (
+ IN ULONG DeviceNumber
+ )
+
+/*++
+
+Routine Description:
+
+ Takes care of parsing the lptcp non-terminal symbol
+
+Arguments:
+
+ DeviceNumber - Supplies the device number
+
+Return Value:
+
+ Pointer to the device request.
+
+Notes:
+
+--*/
+
+{
+
+ //
+ // Since this is the same for LPT and CON, we use the same
+ // function to handle both.
+ //
+ return CpStuff( DEVICE_TYPE_LPT, DeviceNumber );
+
+}
+
+PREQUEST_HEADER
+ComLine (
+ )
+
+/*++
+
+Routine Description:
+
+ Takes care of parsing the comline non-terminal symbol
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Pointer to the device request.
+
+Notes:
+
+--*/
+
+{
+ PREQUEST_HEADER Request;
+ ULONG DeviceNumber;
+
+ //
+ // Note that we have already matched the COM device.
+ // Get the device number;
+ //
+ DeviceNumber = GetNumber();
+
+ Advance();
+
+ if ( Match( "/STA*" ) || EndOfInput() ) {
+
+ //
+ // Status request
+ //
+ Request = MakeRequest( DEVICE_TYPE_COM,
+ DeviceNumber,
+ REQUEST_TYPE_STATUS,
+ sizeof( REQUEST_HEADER ) );
+
+
+ } else {
+
+ //
+ // comset
+ //
+ Request = ComSet( DeviceNumber );
+
+ }
+
+ return Request;
+
+}
+
+PREQUEST_HEADER
+ComSet (
+ IN ULONG DeviceNumber
+ )
+
+/*++
+
+Routine Description:
+
+ Takes care of parsing the comset non-terminal symbol
+
+Arguments:
+
+ DeviceNumber - Supplies the device number
+
+Return Value:
+
+ Pointer to the device request.
+
+Notes:
+
+--*/
+
+{
+ PREQUEST_HEADER Request;
+ PCOM_REQUEST ComRequest;
+
+
+ BOOLEAN SetBaud = FALSE;
+ BOOLEAN SetDataBits = FALSE;
+ BOOLEAN SetStopBits = FALSE;
+ BOOLEAN SetParity = FALSE;
+ BOOLEAN SetRetry = FALSE;
+ BOOLEAN SetTimeOut = FALSE;
+ BOOLEAN SetXon = FALSE;
+ BOOLEAN SetOdsr = FALSE;
+ BOOLEAN SetIdsr = FALSE;
+ BOOLEAN SetOcts = FALSE;
+ BOOLEAN SetDtrControl = FALSE;
+ BOOLEAN SetRtsControl = FALSE;
+
+ ULONG Baud;
+ ULONG DataBits;
+ STOPBITS StopBits;
+ PARITY Parity;
+ WCHAR Retry;
+ BOOLEAN TimeOut;
+ BOOLEAN Xon;
+ BOOLEAN Odsr;
+ BOOLEAN Idsr;
+ BOOLEAN Octs;
+ DTR_CONTROL DtrControl;
+ RTS_CONTROL RtsControl;
+
+
+ if ( Match( "#" ) ) {
+
+ //
+ // Old syntax, where parameter are positional and comma-delimited.
+ //
+ // We will use the following automata for parsing the input
+ // (eoi = end of input):
+ //
+ // eoi
+ // [Baud]------------->[End]
+ // | ^
+ // |, |eoi
+ // v |
+ // [a]-----------+
+ // | ^
+ // | @ |eoi
+ // +-->[Parity]-+
+ // | | ^
+ // | |, |
+ // |<----+ |
+ // | |
+ // |, |eoi
+ // | |
+ // v |
+ // [b]-----------+
+ // | ^
+ // | # |eoi
+ // +-->[Data]---+
+ // | | ^
+ // | |, |
+ // |<----+ |
+ // | |
+ // |, |eoi
+ // v |
+ // [c]-----------+
+ // | ^
+ // | # |eoi
+ // +-->[Stop]---+
+ //
+
+ //
+ // Assume xon=off
+ //
+
+ SetXon = TRUE;
+ SetOdsr = TRUE;
+ SetOcts = TRUE;
+ SetDtrControl = TRUE;
+ SetRtsControl = TRUE;
+ Xon = FALSE;
+ Odsr = FALSE;
+ Octs = FALSE;
+ DtrControl = DTR_ENABLE;
+ RtsControl = RTS_ENABLE;
+
+ Baud = ConvertBaudRate( GetNumber() );
+ SetBaud = TRUE;
+ Advance();
+
+ //
+ // A:
+ //
+ if ( !Match( "," ) ) {
+ goto Eoi;
+ }
+ Advance();
+
+ if ( !Match( "," ) && Match( "@" ) ) {
+
+ //
+ // Parity
+ //
+ Parity = ConvertParity( CmdLine->QueryChAt( MatchBegin ) );
+ SetParity = TRUE;
+ Advance();
+ }
+
+ //
+ // B:
+ //
+ if ( !Match( "," )) {
+ goto Eoi;
+ }
+ Advance();
+
+ if ( Match( "#" )) {
+
+ //
+ // Data bits
+ //
+ DataBits = ConvertDataBits( GetNumber() );
+ SetDataBits = TRUE;
+ Advance();
+ }
+
+ //
+ // C:
+ //
+ if ( !Match( "," )) {
+ goto Eoi;
+ }
+ Advance();
+
+ if ( Match( "1.5" ) ) {
+ StopBits = COMM_STOPBITS_15;
+ SetStopBits = TRUE;
+ Advance();
+ } else if ( Match( "#" ) ) {
+ StopBits = ConvertStopBits( GetNumber() );
+ SetStopBits = TRUE;
+ Advance();
+ }
+
+ if (!Match( "," )) {
+ goto Eoi;
+ }
+
+ Advance();
+
+ if ( Match( "x" )) {
+
+ //
+ // XON=ON
+ //
+ SetXon = TRUE;
+ SetOdsr = TRUE;
+ SetOcts = TRUE;
+ SetDtrControl = TRUE;
+ SetRtsControl = TRUE;
+ Xon = TRUE;
+ Odsr = FALSE;
+ Octs = FALSE;
+ DtrControl = DTR_ENABLE;
+ RtsControl = RTS_ENABLE;
+ Advance();
+
+ } else if ( Match( "p" )) {
+
+ //
+ // Permanent retry - Hardware handshaking
+ //
+
+ SetXon = TRUE;
+ SetOdsr = TRUE;
+ SetOcts = TRUE;
+ SetDtrControl = TRUE;
+ SetRtsControl = TRUE;
+ Xon = FALSE;
+ Odsr = TRUE;
+ Octs = TRUE;
+ DtrControl = DTR_HANDSHAKE;
+ RtsControl = RTS_HANDSHAKE;
+ Advance();
+
+ } else {
+
+ //
+ // XON=OFF
+ //
+ SetXon = TRUE;
+ SetOdsr = TRUE;
+ SetOcts = TRUE;
+ SetDtrControl = TRUE;
+ SetRtsControl = TRUE;
+ Xon = FALSE;
+ Odsr = FALSE;
+ Octs = FALSE;
+ DtrControl = DTR_ENABLE;
+ RtsControl = RTS_ENABLE;
+ }
+
+Eoi:
+ if ( !EndOfInput() ) {
+
+ //
+ // Error
+ //
+ ParseError();
+
+ }
+
+ } else {
+
+ //
+ // New syntax, where parameters are tagged. The language assumes
+ // that all parameters are optional (as long as there is at least
+ // one present). If some is required, it is up to the Device
+ // handler to complain latter on.
+ //
+
+
+ while ( !EndOfInput() ) {
+
+ if ( Match( "BAUD=#" ) ) {
+ //
+ // BAUD=
+ //
+ Baud = ConvertBaudRate( GetNumber() );
+ SetBaud = TRUE;
+ Advance();
+
+ } else if ( Match( "PARITY=@" ) ) {
+ //
+ // PARITY=
+ //
+ Parity = ConvertParity( CmdLine->QueryChAt( MatchBegin ) );
+ SetParity = TRUE;
+ Advance();
+
+ } else if ( Match( "DATA=#" ) ) {
+ //
+ // DATA=
+ //
+ DataBits = ConvertDataBits( GetNumber() );
+ SetDataBits = TRUE;
+ Advance();
+
+ } else if ( Match( "STOP=1.5" ) ) {
+ //
+ // STOP=1.5
+ //
+ StopBits = COMM_STOPBITS_15;
+ SetStopBits = TRUE;
+ Advance();
+
+ } else if ( Match( "STOP=#" ) ) {
+ //
+ // STOP=
+ //
+ StopBits = ConvertStopBits( GetNumber() );
+ SetStopBits = TRUE;
+ Advance();
+
+ } else if ( Match( "RETRY=@" ) ) {
+ //
+ // RETRY=
+ //
+ Retry = ConvertRetry( CmdLine->QueryChAt( MatchBegin ) );
+ SetRetry = TRUE;
+ Advance();
+
+ } else if ( Match( "TO=ON" ) ) {
+ //
+ // TO=ON
+ //
+ SetTimeOut = TRUE;
+ TimeOut = FALSE; // FALSE means finite timeout
+ Advance();
+
+ } else if ( Match( "TO=OFF" ) ) {
+ //
+ // TO=OFF
+ //
+ SetTimeOut = TRUE;
+ TimeOut = TRUE; // TRUE means infinite timeout
+ Advance();
+
+ } else if ( Match( "XON=ON" ) ) {
+ //
+ // XON=ON
+ //
+ SetXon = TRUE;
+ Xon = TRUE;
+ Advance();
+
+ } else if ( Match( "XON=OFF" ) ) {
+ //
+ // XON=OFF
+ //
+ SetXon = TRUE;
+ Xon = FALSE;
+ Advance();
+
+ } else if ( Match( "ODSR=ON" ) ) {
+ //
+ // ODSR=ON
+ //
+ SetOdsr = TRUE;
+ Odsr = TRUE;
+ Advance();
+
+ } else if ( Match( "ODSR=OFF" ) ) {
+ //
+ // ODSR=OFF
+ //
+ SetOdsr = TRUE;
+ Odsr = FALSE;
+ Advance();
+
+ } else if ( Match( "IDSR=ON" ) ) {
+ //
+ // IDSR=ON
+ //
+ SetIdsr = TRUE;
+ Idsr = TRUE;
+ Advance();
+
+ } else if ( Match( "IDSR=OFF" ) ) {
+ //
+ // IDSR=OFF
+ //
+ SetIdsr = TRUE;
+ Idsr = FALSE;
+ Advance();
+
+ } else if ( Match( "OCTS=ON" ) ) {
+ //
+ // OCS=ON
+ //
+ SetOcts = TRUE;
+ Octs = TRUE;
+ Advance();
+
+ } else if ( Match( "OCTS=OFF" ) ) {
+ //
+ // OCS=OFF
+ //
+ SetOcts = TRUE;
+ Octs = FALSE;
+ Advance();
+
+ } else if ( Match( "DTR=*" ) ) {
+ //
+ // DTR=
+ //
+ DtrControl = ConvertDtrControl( CmdLine, MatchBegin, MatchEnd ) ;
+ SetDtrControl = TRUE;
+ Advance();
+
+ } else if ( Match( "RTS=*" ) ) {
+ //
+ // RTS=
+ //
+ RtsControl = ConvertRtsControl( CmdLine, MatchBegin, MatchEnd ) ;
+ SetRtsControl = TRUE;
+ Advance();
+
+ } else {
+
+ ParseError();
+ }
+ }
+ }
+
+ //
+ // Now that parsing is done, we can make the request packet.
+ //
+ Request = MakeRequest( DEVICE_TYPE_COM,
+ DeviceNumber,
+ REQUEST_TYPE_COM_SET,
+ sizeof(COM_REQUEST ) );
+
+ ComRequest = (PCOM_REQUEST)Request;
+
+ ComRequest->Data.Set.SetBaud = SetBaud;
+ ComRequest->Data.Set.SetDataBits = SetDataBits;
+ ComRequest->Data.Set.SetStopBits = SetStopBits;
+ ComRequest->Data.Set.SetParity = SetParity;
+ ComRequest->Data.Set.SetRetry = SetRetry;
+ ComRequest->Data.Set.SetTimeOut = SetTimeOut;
+ ComRequest->Data.Set.SetXon = SetXon;
+ ComRequest->Data.Set.SetOdsr = SetOdsr;
+ ComRequest->Data.Set.SetIdsr = SetIdsr;
+ ComRequest->Data.Set.SetOcts = SetOcts;
+ ComRequest->Data.Set.SetDtrControl = SetDtrControl;
+ ComRequest->Data.Set.SetRtsControl = SetRtsControl;
+
+
+ ComRequest->Data.Set.Baud = Baud;
+ ComRequest->Data.Set.DataBits = DataBits;
+ ComRequest->Data.Set.StopBits = StopBits;
+ ComRequest->Data.Set.Parity = Parity;
+ ComRequest->Data.Set.Retry = Retry;
+ ComRequest->Data.Set.TimeOut = TimeOut;
+ ComRequest->Data.Set.Xon = Xon;
+ ComRequest->Data.Set.Odsr = Odsr;
+ ComRequest->Data.Set.Idsr = Idsr;
+ ComRequest->Data.Set.Octs = Octs;
+ ComRequest->Data.Set.DtrControl = DtrControl;
+ ComRequest->Data.Set.RtsControl = RtsControl;
+
+ return Request;
+
+}
+
+PREQUEST_HEADER
+ConLine (
+ )
+
+/*++
+
+Routine Description:
+
+ Takes care of parsing ConLine
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Pointer to the device request.
+
+Notes:
+
+--*/
+
+{
+ PREQUEST_HEADER Request;
+
+ Advance();
+
+ if ( Match( "/STA*" ) || EndOfInput() ) {
+
+ //
+ // Status request
+ //
+ Request = MakeRequest( DEVICE_TYPE_CON,
+ 0,
+ REQUEST_TYPE_STATUS,
+ sizeof( REQUEST_HEADER ) );
+
+
+ } else if ( Match( "COLS=#" ) || Match( "LINES=#" ) ) {
+
+ //
+ // conrc
+ //
+ Request = ConRc();
+
+ } else if ( Match( "RATE=#" ) || Match( "DELAY=#" ) ) {
+
+ //
+ // contyp
+ //
+ Request = ConTyp();
+
+ } else if ( Match( "CP" ) || Match( "CODEPAGE" ) ) {
+
+ //
+ // concp
+ //
+ Request = ConCp();
+
+ } else {
+
+ //
+ // Error
+ //
+ ParseError();
+
+ }
+
+ return Request;
+
+}
+
+PREQUEST_HEADER
+ConRc (
+ )
+
+/*++
+
+Routine Description:
+
+ Takes care of parsing the conrc non-terminal
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Pointer to the device request.
+
+Notes:
+
+--*/
+
+{
+ PREQUEST_HEADER Request;
+ PCON_REQUEST ConRequest;
+
+ BOOLEAN SetCol = FALSE;
+ BOOLEAN SetLines = FALSE;
+
+ ULONG Col;
+ ULONG Lines;
+
+ while ( !EndOfInput() ) {
+
+ if ( Match( "LINES=#" )) {
+ //
+ // LINES=
+ //
+ Lines = GetNumber();
+ SetLines = TRUE;
+ Advance();
+
+ } else if ( Match( "COLS=#" )) {
+ //
+ // COLS=
+ //
+ Col = GetNumber();
+ SetCol = TRUE;
+ Advance();
+
+ } else {
+
+ ParseError();
+ }
+ }
+
+ //
+ // We are done parsing, we make the request packet.
+ //
+ Request = MakeRequest( DEVICE_TYPE_CON,
+ 0,
+ REQUEST_TYPE_CON_SET_ROWCOL,
+ sizeof(CON_REQUEST ) );
+
+ ConRequest = (PCON_REQUEST)Request;
+
+ ConRequest->Data.RowCol.SetCol = SetCol;
+ ConRequest->Data.RowCol.SetLines = SetLines;
+ ConRequest->Data.RowCol.Col = Col;
+ ConRequest->Data.RowCol.Lines = Lines;
+
+ return Request;
+
+}
+
+PREQUEST_HEADER
+ConTyp (
+ )
+
+/*++
+
+Routine Description:
+
+ Takes care of parsing the contyp non-terminal
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Pointer to the device request.
+
+Notes:
+
+--*/
+
+{
+ PREQUEST_HEADER Request;
+ PCON_REQUEST ConRequest;
+
+ BOOLEAN SetRate = FALSE;
+ BOOLEAN SetDelay = FALSE;
+
+ ULONG Rate;
+ ULONG Delay;
+
+
+ //
+ // RATE=
+ //
+ if ( Match( "RATE=#" )) {
+ Rate = GetNumber();
+ SetRate = TRUE;
+ Advance();
+ }
+
+ //
+ // DELAY=
+ //
+ if ( Match( "DELAY=#" )) {
+ Delay = GetNumber();
+ SetDelay = TRUE;
+ Advance();
+ }
+
+ if ( !EndOfInput() ) {
+ //
+ // Error
+ //
+ ParseError();
+ }
+
+ //
+ // We are don parsing, we make the request packet.
+ //
+ Request = MakeRequest( DEVICE_TYPE_CON,
+ 0,
+ REQUEST_TYPE_CON_SET_TYPEMATIC,
+ sizeof(CON_REQUEST ) );
+
+ ConRequest = (PCON_REQUEST)Request;
+
+ ConRequest->Data.Typematic.SetRate = SetRate;
+ ConRequest->Data.Typematic.SetDelay = SetDelay;
+ ConRequest->Data.Typematic.Rate = Rate;
+ ConRequest->Data.Typematic.Delay = Delay;
+
+ return Request;
+
+}
+
+PREQUEST_HEADER
+ConCp (
+ )
+
+/*++
+
+Routine Description:
+
+ Takes care of parsing the concp non-terminal symbol
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Pointer to the device request.
+
+Notes:
+
+--*/
+
+{
+
+ return CpStuff( DEVICE_TYPE_CON, 0 );
+
+}
+
+PREQUEST_HEADER
+VideoLine (
+ )
+
+/*++
+
+Routine Description:
+
+ Takes care of parsing the videoline non-terminal symbol
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Pointer to the device request.
+
+Notes:
+
+--*/
+
+{
+
+ PREQUEST_HEADER Request;
+ PCON_REQUEST ConRequest;
+
+ BOOLEAN SetCol = FALSE;
+ BOOLEAN SetLines = FALSE;
+
+ ULONG Col;
+ ULONG Lines;
+
+ //
+ // This is in the old syntax, where parameter are positional
+ // and comma-delimited.
+ //
+ // We will use the following automata for parsing the input
+ // (eoi = end of input):
+ //
+ // eoi
+ // [Cols]--------->[End]
+ // | ^
+ // |, |
+ // v |
+ // [ ] |
+ // | |
+ // |# |
+ // | |
+ // v eoi |
+ // [Lines]-----+
+ //
+
+
+ if ( Match( "#" )) {
+ //
+ // Cols
+ //
+ Col = GetNumber();
+ SetCol = TRUE;
+ Advance();
+ }
+
+ if ( Match( "," ) ) {
+
+ Advance();
+
+ if ( Match( "#" )) {
+
+ Lines = GetNumber();
+ SetLines = TRUE;
+ Advance();
+
+ } else {
+
+ ParseError();
+
+ }
+ }
+
+ if ( !EndOfInput() ) {
+ //
+ // Error
+ //
+ ParseError();
+ }
+
+
+ //
+ // We are done parsing, make the request packet
+ //
+ Request = MakeRequest( DEVICE_TYPE_CON,
+ 0,
+ REQUEST_TYPE_CON_SET_ROWCOL,
+ sizeof(CON_REQUEST ) );
+
+ ConRequest = (PCON_REQUEST)Request;
+
+ ConRequest->Data.RowCol.SetCol = SetCol;
+ ConRequest->Data.RowCol.SetLines = SetLines;
+ ConRequest->Data.RowCol.Col = Col;
+ ConRequest->Data.RowCol.Lines = Lines;
+
+ return Request;
+
+}
+
+PREQUEST_HEADER
+CpStuff (
+ IN DEVICE_TTYPE DeviceType,
+ IN ULONG DeviceNumber
+ )
+
+/*++
+
+Routine Description:
+
+ Takes care of parsing the cpstuff non-terminal symbol
+
+Arguments:
+
+ DeviceType - Supplies device type
+ DeviceNumber - Supplies device number
+
+Return Value:
+
+ Pointer to the device request.
+
+Notes:
+
+--*/
+
+{
+
+ PREQUEST_HEADER Request;
+ PCON_REQUEST ConRequest;
+
+ Advance();
+
+ if ( Match( "PREPARE=*" ) ) {
+
+ //
+ //
+ // PREPARE=
+ //
+ // This is a No-Op
+ //
+ Request = MakeRequest( DeviceType,
+ DeviceNumber,
+ REQUEST_TYPE_CODEPAGE_PREPARE,
+ sizeof( REQUEST_HEADER ) );
+
+ } else if ( Match( "SELECT=#" ) ) {
+
+ //
+ //
+ // SELECT=
+ //
+ // Note that this relies on the fact that codepage requests
+ // are identical for all devices.
+ //
+
+ Request = MakeRequest( DeviceType,
+ DeviceNumber,
+ REQUEST_TYPE_CODEPAGE_SELECT,
+ sizeof( CON_REQUEST ) );
+
+ ConRequest = (PCON_REQUEST)Request;
+
+ ConRequest->Data.CpSelect.Codepage = GetNumber();
+
+ } else if ( Match( "/STA*" ) || EndOfInput() ) {
+
+ //
+ // /STATUS
+ //
+ Request = MakeRequest( DeviceType,
+ DeviceNumber,
+ REQUEST_TYPE_CODEPAGE_STATUS,
+ sizeof( REQUEST_HEADER ) );
+
+ } else if ( Match( "REFRESH" ) ) {
+
+ //
+ //
+ // REFRESH
+ //
+ // This is a No-Op
+ //
+ Request = MakeRequest( DeviceType,
+ DeviceNumber,
+ REQUEST_TYPE_CODEPAGE_REFRESH,
+ sizeof( REQUEST_HEADER ) );
+
+ } else {
+
+ ParseError();
+
+ }
+
+ return Request;
+
+}
+
+VOID
+AllocateResource(
+ )
+
+/*++
+
+Routine Description:
+
+ Allocate strings from the resource
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None
+
+Notes:
+
+--*/
+
+{
+
+ CmdLine = NEW DSTRING;
+
+
+}
+
+VOID
+DeallocateResource(
+ )
+
+/*++
+
+Routine Description:
+
+ Deallocate strings from the resource
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None
+
+Notes:
+
+--*/
+
+{
+
+ DELETE( CmdLine );
+
+}
+
+BOOLEAN
+Match(
+ IN PCSTR Pattern
+ )
+
+/*++
+
+Routine Description:
+
+ This function matches a pattern against whatever
+ is in the command line at the current position.
+
+ Note that this does not advance our current position
+ within the command line.
+
+ If the pattern has a magic character, then the
+ variables MatchBegin and MatchEnd delimit the
+ substring of the command line that matched that
+ magic character.
+
+Arguments:
+
+ Pattern - Supplies pointer to the pattern to match
+
+Return Value:
+
+ BOOLEAN - TRUE if the pattern matched, FALSE otherwise
+
+Notes:
+
+--*/
+
+{
+
+ DSTRING PatternString;
+ BOOLEAN StatusOk;
+
+ StatusOk = PatternString.Initialize( Pattern );
+
+ DebugAssert( StatusOk );
+
+ if ( StatusOk ) {
+
+ return Match( &PatternString );
+
+ } else {
+
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY, NULL, (ULONG)EXIT_ERROR );
+
+ }
+ //NOTREACHED
+ return StatusOk;
+}
+
+BOOLEAN
+Match(
+ IN PCWSTRING Pattern
+ )
+
+/*++
+
+Routine Description:
+
+ This function matches a pattern against whatever
+ is in the command line at the current position.
+
+ Note that this does not advance our current position
+ within the command line.
+
+ If the pattern has a magic character, then the
+ variables MatchBegin and MatchEnd delimit the
+ substring of the command line that matched that
+ magic character.
+
+Arguments:
+
+ Pattern - Supplies pointer to the pattern to match
+
+Return Value:
+
+ BOOLEAN - TRUE if the pattern matched, FALSE otherwise
+
+Notes:
+
+--*/
+
+{
+
+ CHNUM CmdIndex; // Index within command line
+ CHNUM PatternIndex; // Index within pattern
+ WCHAR PatternChar; // Character in pattern
+ WCHAR CmdChar; // Character in command line;
+
+ DebugPtrAssert( Pattern );
+
+ CmdIndex = CharIndex;
+ PatternIndex = 0;
+
+ while ( (PatternChar = Pattern->QueryChAt( PatternIndex )) != INVALID_CHAR ) {
+
+ switch ( PatternChar ) {
+
+ case '#':
+
+ //
+ // Match a number
+ //
+ MatchBegin = CmdIndex;
+ MatchEnd = MatchBegin;
+
+ //
+ // Get all consecutive digits
+ //
+ while ( ((CmdChar = CmdLine->QueryChAt( MatchEnd )) != INVALID_CHAR) &&
+ isdigit( (char)CmdChar ) ) {
+ MatchEnd++;
+ }
+ MatchEnd--;
+
+ if ( MatchBegin > MatchEnd ) {
+ //
+ // No number
+ //
+ return FALSE;
+ }
+
+ CmdIndex = MatchEnd + 1;
+ PatternIndex++;
+
+ break;
+
+
+ case '@':
+
+ //
+ // Match one character
+ //
+ if ( CmdIndex >= CmdLine->QueryChCount() ) {
+ return FALSE;
+ }
+
+ MatchBegin = MatchEnd = CmdIndex;
+ CmdIndex++;
+ PatternIndex++;
+
+ break;
+
+
+ case '*':
+
+ //
+ // Match everything up to next blank (or end of input)
+ //
+ MatchBegin = CmdIndex;
+ MatchEnd = MatchBegin;
+
+ while ( ( (CmdChar = CmdLine->QueryChAt( MatchEnd )) != INVALID_CHAR ) &&
+ ( CmdChar != (WCHAR)' ' ) ) {
+
+ MatchEnd++;
+ }
+ MatchEnd--;
+
+ CmdIndex = MatchEnd+1;
+ PatternIndex++;
+
+ break;
+
+ case '[':
+
+ //
+ // Optional sequence
+ //
+ PatternIndex++;
+
+ PatternChar = Pattern->QueryChAt( PatternIndex );
+ CmdChar = CmdLine->QueryChAt( CmdIndex );
+
+ //
+ // If the first charcter in the input does not match the
+ // first character in the optional sequence, we just
+ // skip the optional sequence.
+ //
+ if ( ( CmdChar == INVALID_CHAR ) ||
+ ( CmdChar == ' ') ||
+ ( towupper(CmdChar) != towupper(PatternChar) ) ) {
+
+ while ( PatternChar != ']' ) {
+ PatternIndex++;
+ PatternChar = Pattern->QueryChAt( PatternIndex );
+ }
+ PatternIndex++;
+
+ } else {
+
+ //
+ // Since the first character in the sequence matched, now
+ // everything must match.
+ //
+ while ( PatternChar != ']' ) {
+
+ if ( towupper(PatternChar) != towupper(CmdChar) ) {
+ return FALSE;
+ }
+ CmdIndex++;
+ PatternIndex++;
+ CmdChar = CmdLine->QueryChAt( CmdIndex );
+ PatternChar = Pattern->QueryChAt( PatternIndex );
+ }
+
+ PatternIndex++;
+ }
+
+ break;
+
+ default:
+
+ //
+ // Both characters must match
+ //
+ CmdChar = CmdLine->QueryChAt( CmdIndex );
+
+ if ( ( CmdChar == INVALID_CHAR ) ||
+ ( towupper(CmdChar) != towupper(PatternChar) ) ) {
+
+ return FALSE;
+
+ }
+
+ CmdIndex++;
+ PatternIndex++;
+
+ break;
+
+ }
+ }
+
+ AdvanceIndex = CmdIndex;
+
+ return TRUE;
+
+}
+
+VOID
+Advance(
+ )
+
+/*++
+
+Routine Description:
+
+ Advances our pointers to the beginning of the next lexeme
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+
+--*/
+
+{
+
+ CharIndex = AdvanceIndex;
+
+ //
+ // Skip blank space
+ //
+ if ( CmdLine->QueryChAt( CharIndex ) == ' ' ) {
+
+ while ( CmdLine->QueryChAt( CharIndex ) == ' ' ) {
+
+ CharIndex++;
+ }
+
+ ParmIndex = CharIndex;
+
+ }
+}
+
+VOID
+ParseError(
+ )
+
+/*++
+
+Routine Description:
+
+ Display Invalid parameter error message and exits
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+
+--*/
+
+{
+ DSTRING Parameter;
+ CHNUM ParmEnd;
+
+ //
+ // Look for end of parameter
+ //
+ ParmEnd = CmdLine->Strchr( ' ', ParmIndex );
+
+
+ Parameter.Initialize( CmdLine,
+ ParmIndex,
+ (ParmEnd == INVALID_CHNUM) ? TO_END : ParmEnd - ParmIndex );
+
+ DisplayMessageAndExit( MODE_ERROR_INVALID_PARAMETER,
+ &Parameter,
+ (ULONG)EXIT_ERROR );
+
+}
+
+PREQUEST_HEADER
+MakeRequest(
+ IN DEVICE_TTYPE DeviceType,
+ IN LONG DeviceNumber,
+ IN REQUEST_TYPE RequestType,
+ IN ULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ Makes a request and initializes its header.
+
+Arguments:
+
+ DeviceType - Supplies the type of device
+ DeviceNumber - Supplies the device number
+ RequestType - Supplies the type of request
+ Size - Supplies size of the request packet
+
+Return Value:
+
+ Pointer to the device request.
+
+Notes:
+
+--*/
+
+{
+
+ PREQUEST_HEADER Request;
+
+ DebugAssert( Size >= sizeof( REQUEST_HEADER )) ;
+
+ Request = (PREQUEST_HEADER)MALLOC( (unsigned int)Size );
+
+ DebugPtrAssert( Request );
+
+ if ( !Request ) {
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY, NULL, (ULONG)EXIT_ERROR );
+ }
+
+ Request->DeviceType = DeviceType;
+ Request->DeviceNumber = DeviceNumber;
+ Request->DeviceName = NULL;
+ Request->RequestType = RequestType;
+
+ return Request;
+
+}
+
+ULONG
+GetNumber(
+ )
+
+/*++
+
+Routine Description:
+
+ Converts the substring delimited by MatchBegin and MatchEnd into
+ a number.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ ULONG - The matched string converted to a number
+
+
+--*/
+
+{
+ LONG Number;
+
+
+ DebugAssert( MatchEnd >= MatchBegin );
+
+ if ( !CmdLine->QueryNumber( &Number, MatchBegin, (MatchEnd-MatchBegin)+1 ) ) {
+ ParseError();
+ }
+
+ return (ULONG)Number;
+
+}
diff --git a/private/utils/mode/argument.old b/private/utils/mode/argument.old
new file mode 100644
index 000000000..4b87d1d1a
--- /dev/null
+++ b/private/utils/mode/argument.old
@@ -0,0 +1,1518 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Argument
+
+Abstract:
+
+ Argument processing for the Mode utility. After parsing the
+ arguments off the command line, a minimum verification is done and
+ a request packet is formed and returned.
+
+ The request packet is eventually routed to the handler for a specific
+ device, which performs further verification and takes proper
+ action.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 26-Jun-1991
+
+Notes:
+
+
+ BUGBUG ramonsa 7/9/91
+
+ The number of stop bits can be 1, 1.5 or 2, Currently the library will
+ not support floating point operations, so there are no
+ floating-point-number arguments. We use a flag argument to handle
+ the 1.5 case. This should be fixed whenever the library supports
+ floating point.
+
+
+ The mode command-line can take any of the following forms:
+
+ MODE [/?]
+
+ MODE [device] [/STATUS]
+
+ MODE device CP PREPARE=string
+
+ MODE device CP REFRESH
+
+ MODE device CP SELECT=codepage
+
+ MODE device CP [/STATUS]
+
+ MODE LPTn[:] [COLS=c] [LINES=l] [RETRY=r]
+
+ MODE LPTn[:] = COMm[:]
+
+ MODE COMm[:] [BAUD=b] [PARITY=p] [DATA=d] [STOP=s] [RETRY=r]
+
+ MODE CON[:] [COLS=c] [LINES=l]
+
+ MODE CON[:] [RATE=r DELAY=d]
+
+
+Revision History:
+
+
+--*/
+
+#include "mode.hxx"
+
+#include "arg.hxx"
+#include "array.hxx"
+
+#include "common.hxx"
+#include "lpt.hxx"
+#include "com.hxx"
+#include "con.hxx"
+
+
+
+//
+// BUGBUG all variables here should be static
+//
+PWSTRING LptPattern = NULL;
+PWSTRING LptColonPattern = NULL;
+PWSTRING ComPattern = NULL;
+PWSTRING ComColonPattern = NULL;
+PWSTRING ConPattern = NULL;
+PWSTRING ConColonPattern = NULL;
+PWSTRING StatusPattern = NULL;
+PWSTRING ColPattern = NULL;
+PWSTRING LinesPattern = NULL;
+PWSTRING CpPattern = NULL;
+PWSTRING PreparePattern = NULL;
+PWSTRING RetryPattern = NULL;
+PWSTRING EqualPattern = NULL;
+PWSTRING BaudPattern = NULL;
+PWSTRING ParityPattern = NULL;
+PWSTRING DataPattern = NULL;
+PWSTRING StopPattern = NULL;
+PWSTRING Stop15Pattern = NULL;
+PWSTRING SelectPattern = NULL;
+PWSTRING RefreshPattern = NULL;
+PWSTRING RatePattern = NULL;
+PWSTRING DelayPattern = NULL;
+PWSTRING HelpPattern = NULL;
+
+
+//
+// Parsing preferences
+//
+PWSTRING Switches = NULL;
+
+
+//
+// Arguments
+//
+PPATH_ARGUMENT ProgramNameArg;
+PLONG_ARGUMENT LptArg;
+PLONG_ARGUMENT LptColonArg;
+PLONG_ARGUMENT ComArg;
+PLONG_ARGUMENT ComColonArg;
+PFLAG_ARGUMENT ConArg;
+PFLAG_ARGUMENT ConColonArg;
+PSTRING_ARGUMENT StatusArg;
+PLONG_ARGUMENT ColArg;
+PLONG_ARGUMENT LinesArg;
+PFLAG_ARGUMENT CpArg;
+PSTRING_ARGUMENT PrepareArg;
+PSTRING_ARGUMENT RetryArg;
+PFLAG_ARGUMENT EqualArg;
+PLONG_ARGUMENT BaudArg;
+PSTRING_ARGUMENT ParityArg;
+PLONG_ARGUMENT DataArg;
+PLONG_ARGUMENT StopArg;
+PFLAG_ARGUMENT Stop15Arg;
+PLONG_ARGUMENT SelectArg;
+PFLAG_ARGUMENT RefreshArg;
+PLONG_ARGUMENT RateArg;
+PLONG_ARGUMENT DelayArg;
+PFLAG_ARGUMENT HelpArg;
+
+
+//
+// The Argument lexemizer and lexeme array.
+//
+PARGUMENT_LEXEMIZER ArgLex;
+PARRAY LexArray;
+
+//
+// Some device information so we don't have to be querying the arguments
+// all the time.
+//
+BOOLEAN LptSet;
+ULONG LptNumber;
+BOOLEAN ComSet;
+ULONG ComNumber;
+BOOLEAN ConSet;
+
+
+
+
+VOID
+AllocateStuff(
+ );
+
+VOID
+DeallocateStuff(
+ );
+
+PARRAY
+GetArgumentArray(
+ );
+
+VOID
+ParseArguments(
+ IN PARRAY ArgArray
+ );
+
+PREQUEST_HEADER
+MakeRequest(
+ );
+
+PREQUEST_HEADER
+MakeStatusRequest(
+ );
+
+PREQUEST_HEADER
+MakeCodePageRequest(
+ );
+
+PREQUEST_HEADER
+MakeLptRequest(
+ );
+
+PREQUEST_HEADER
+MakeComRequest(
+ );
+
+PREQUEST_HEADER
+MakeConRequest(
+ );
+
+
+
+
+
+
+PREQUEST_HEADER
+GetRequest(
+ )
+
+/*++
+
+Routine Description:
+
+ Forms a device request based on the command line arguments.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Pointer to the device request.
+
+Notes:
+
+--*/
+
+{
+
+ PARRAY ArgArray;
+ PREQUEST_HEADER Request;
+
+ //
+ // Get strings from resource messages
+ //
+ AllocateStuff();
+
+ //
+ // Get array of arguments
+ //
+ ArgArray = GetArgumentArray();
+ DbgPtrAssert( ArgArray);
+
+ //
+ // Parse the arguments
+ //
+ ParseArguments( ArgArray );
+
+
+ //
+ // Verify the arguments and form a request packet
+ //
+ Request = MakeRequest();
+ DbgPtrAssert( Request );
+
+ //
+ // Deallocate resources
+ //
+ DELETE( ArgArray );
+ DeallocateStuff();
+
+ return Request;
+
+}
+
+VOID
+AllocateStuff(
+ )
+
+/*++
+
+Routine Description:
+
+ Obtains all necessary strings (e.g. argument patterns, switches) from
+ message.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None
+
+Notes:
+
+--*/
+
+{
+
+ //
+ // Get strings from resource
+ //
+ if ( !( ( LptPattern = QueryMessageString( MODE_PATTERN_LPT )) &&
+ ( LptColonPattern = QueryMessageString( MODE_PATTERN_LPTCOLON )) &&
+ ( ComPattern = QueryMessageString( MODE_PATTERN_COM )) &&
+ ( ComColonPattern = QueryMessageString( MODE_PATTERN_COMCOLON )) &&
+ ( ConPattern = QueryMessageString( MODE_PATTERN_CON )) &&
+ ( ConColonPattern = QueryMessageString( MODE_PATTERN_CONCOLON )) &&
+ ( StatusPattern = QueryMessageString( MODE_PATTERN_STATUS )) &&
+ ( ColPattern = QueryMessageString( MODE_PATTERN_COLUMNS )) &&
+ ( LinesPattern = QueryMessageString( MODE_PATTERN_LINES )) &&
+ ( CpPattern = QueryMessageString( MODE_PATTERN_CODEPAGE )) &&
+ ( PreparePattern = QueryMessageString( MODE_PATTERN_PREPARE )) &&
+ ( RetryPattern = QueryMessageString( MODE_PATTERN_RETRY )) &&
+ ( EqualPattern = QueryMessageString( MODE_PATTERN_EQUAL )) &&
+ ( BaudPattern = QueryMessageString( MODE_PATTERN_BAUD )) &&
+ ( ParityPattern = QueryMessageString( MODE_PATTERN_PARITY )) &&
+ ( DataPattern = QueryMessageString( MODE_PATTERN_DATA )) &&
+ ( StopPattern = QueryMessageString( MODE_PATTERN_STOP )) &&
+ ( Stop15Pattern = QueryMessageString( MODE_PATTERN_STOP_15 )) &&
+ ( SelectPattern = QueryMessageString( MODE_PATTERN_SELECT )) &&
+ ( RefreshPattern = QueryMessageString( MODE_PATTERN_REFRESH )) &&
+ ( RatePattern = QueryMessageString( MODE_PATTERN_RATE )) &&
+ ( DelayPattern = QueryMessageString( MODE_PATTERN_DELAY )) &&
+ ( HelpPattern = QueryMessageString( MODE_PATTERN_HELP )) &&
+ ( Switches = QueryMessageString( MODE_SWITCHES )) )) {
+
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY,
+ NULL,
+ EXIT_ERROR );
+
+ }
+
+ //
+ // Get argument objects. These are not global because the Create
+ // method would not be called on them.
+ //
+ if ( !( ProgramNameArg = NEW PATH_ARGUMENT) ||
+ !( LptArg = NEW LONG_ARGUMENT) ||
+ !( LptColonArg = NEW LONG_ARGUMENT) ||
+ !( ComArg = NEW LONG_ARGUMENT) ||
+ !( ComColonArg = NEW LONG_ARGUMENT) ||
+ !( ConArg = NEW FLAG_ARGUMENT) ||
+ !( ConColonArg = NEW FLAG_ARGUMENT) ||
+ !( StatusArg = NEW STRING_ARGUMENT) ||
+ !( ColArg = NEW LONG_ARGUMENT) ||
+ !( LinesArg = NEW LONG_ARGUMENT) ||
+ !( CpArg = NEW FLAG_ARGUMENT) ||
+ !( PrepareArg = NEW STRING_ARGUMENT) ||
+ !( RetryArg = NEW STRING_ARGUMENT) ||
+ !( EqualArg = NEW FLAG_ARGUMENT) ||
+ !( BaudArg = NEW LONG_ARGUMENT) ||
+ !( ParityArg = NEW STRING_ARGUMENT) ||
+ !( DataArg = NEW LONG_ARGUMENT) ||
+ !( StopArg = NEW LONG_ARGUMENT) ||
+ !( Stop15Arg = NEW FLAG_ARGUMENT) ||
+ !( SelectArg = NEW LONG_ARGUMENT) ||
+ !( RefreshArg = NEW FLAG_ARGUMENT) ||
+ !( RateArg = NEW LONG_ARGUMENT) ||
+ !( DelayArg = NEW LONG_ARGUMENT) ||
+ !( HelpArg = NEW FLAG_ARGUMENT) ) {
+
+
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY,
+ NULL,
+ EXIT_ERROR );
+
+ }
+
+ //
+ // Lexemizer stuff
+ //
+ if ( !( ArgLex = NEW ARGUMENT_LEXEMIZER) ||
+ !( LexArray = NEW ARRAY) ) {
+
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY,
+ NULL,
+ EXIT_ERROR );
+
+ }
+
+}
+
+VOID
+DeallocateStuff(
+ )
+
+/*++
+
+Routine Description:
+
+ Deletes all the allocated strings.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None
+
+Notes:
+
+--*/
+
+{
+
+ //
+ // The string from the resource
+ //
+ DELETE( LptPattern );
+ DELETE( LptColonPattern );
+ DELETE( ComPattern );
+ DELETE( ComColonPattern );
+ DELETE( ConPattern );
+ DELETE( ConColonPattern );
+ DELETE( StatusPattern );
+ DELETE( ColPattern );
+ DELETE( LinesPattern );
+ DELETE( CpPattern );
+ DELETE( PreparePattern );
+ DELETE( RetryPattern );
+ DELETE( EqualPattern );
+ DELETE( BaudPattern );
+ DELETE( ParityPattern );
+ DELETE( DataPattern );
+ DELETE( StopPattern );
+ DELETE( SelectPattern );
+ DELETE( RefreshPattern );
+ DELETE( RatePattern );
+ DELETE( DelayPattern );
+ DELETE( HelpPattern );
+ DELETE( Switches );
+
+ //
+ // The arguments
+ //
+ DELETE( ProgramNameArg );
+ DELETE( ProgramNameArg );
+ DELETE( LptArg );
+ DELETE( LptColonArg );
+ DELETE( ComArg );
+ DELETE( ComColonArg );
+ DELETE( ConArg );
+ DELETE( ConColonArg );
+ DELETE( StatusArg );
+ DELETE( ColArg );
+ DELETE( LinesArg );
+ DELETE( CpArg );
+ DELETE( PrepareArg );
+ DELETE( RetryArg );
+ DELETE( EqualArg );
+ DELETE( BaudArg );
+ DELETE( ParityArg );
+ DELETE( DataArg );
+ DELETE( StopArg );
+ DELETE( Stop15Arg );
+ DELETE( SelectArg );
+ DELETE( RefreshArg );
+ DELETE( RateArg );
+ DELETE( DelayArg );
+ DELETE( HelpArg );
+
+ //
+ // The lexemizer stuff
+ //
+ DELETE( ArgLex );
+ DELETE( LexArray );
+
+}
+
+PARRAY
+GetArgumentArray(
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes all the arguments
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None
+
+Notes:
+
+--*/
+
+{
+
+ PARRAY ArgArray;
+
+ if ( !( ( ArgArray = NEW ARRAY ) &&
+ ( ArgArray->Initialize( 22, 22, 0) ) &&
+
+ ( ProgramNameArg->Initialize( "*" )) &&
+ ( LptArg->Initialize( LptPattern )) &&
+ ( LptColonArg->Initialize( LptColonPattern )) &&
+ ( ComArg->Initialize( ComPattern )) &&
+ ( ComColonArg->Initialize( ComColonPattern )) &&
+ ( ConArg->Initialize( ConPattern )) &&
+ ( ConColonArg->Initialize( ConColonPattern )) &&
+ ( StatusArg->Initialize( StatusPattern )) &&
+ ( ColArg->Initialize( ColPattern )) &&
+ ( LinesArg->Initialize( LinesPattern )) &&
+ ( CpArg->Initialize( CpPattern )) &&
+ ( PrepareArg->Initialize( PreparePattern )) &&
+ ( RetryArg->Initialize( RetryPattern )) &&
+ ( EqualArg->Initialize( EqualPattern )) &&
+ ( BaudArg->Initialize( BaudPattern )) &&
+ ( ParityArg->Initialize( ParityPattern )) &&
+ ( DataArg->Initialize( DataPattern )) &&
+ ( StopArg->Initialize( StopPattern )) &&
+ ( Stop15Arg->Initialize( Stop15Pattern )) &&
+ ( SelectArg->Initialize( SelectPattern )) &&
+ ( RefreshArg->Initialize( RefreshPattern )) &&
+ ( RateArg->Initialize( RatePattern )) &&
+ ( DelayArg->Initialize( DelayPattern )) &&
+ ( HelpArg->Initialize( HelpPattern )) )) {
+
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY,
+ NULL,
+ EXIT_ERROR );
+
+ }
+
+ if ( !( ( ArgArray->Put( ProgramNameArg ) ) &&
+ ( ArgArray->Put( LptColonArg ) ) &&
+ ( ArgArray->Put( LptArg ) ) &&
+ ( ArgArray->Put( ComColonArg ) ) &&
+ ( ArgArray->Put( ComArg ) ) &&
+ ( ArgArray->Put( ConColonArg ) ) &&
+ ( ArgArray->Put( ConArg ) ) &&
+ ( ArgArray->Put( StatusArg ) ) &&
+ ( ArgArray->Put( ColArg ) ) &&
+ ( ArgArray->Put( LinesArg ) ) &&
+ ( ArgArray->Put( CpArg ) ) &&
+ ( ArgArray->Put( PrepareArg ) ) &&
+ ( ArgArray->Put( RetryArg ) ) &&
+ ( ArgArray->Put( EqualArg ) ) &&
+ ( ArgArray->Put( BaudArg ) ) &&
+ ( ArgArray->Put( ParityArg ) ) &&
+ ( ArgArray->Put( DataArg ) ) &&
+ ( ArgArray->Put( Stop15Arg ) ) &&
+ ( ArgArray->Put( StopArg ) ) &&
+ ( ArgArray->Put( SelectArg ) ) &&
+ ( ArgArray->Put( RefreshArg ) ) &&
+ ( ArgArray->Put( RateArg ) ) &&
+ ( ArgArray->Put( DelayArg ) ) &&
+ ( ArgArray->Put( HelpArg ) ) ) ) {
+
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY,
+ NULL,
+ EXIT_ERROR );
+
+ }
+
+ return ArgArray;
+
+}
+
+VOID
+ParseArguments(
+ IN PARRAY ArgArray
+ )
+
+/*++
+
+Routine Description:
+
+ Parses the command line
+
+Arguments:
+
+ ArgArray - Supplies pointer to array of arguments
+
+Return Value:
+
+ none
+
+Notes:
+
+--*/
+
+{
+
+ WSTRING CmdLine;
+
+
+ //
+ // Initialize the argument lexemizer
+ //
+ if ( !( CmdLine.Initialize( GetCommandLine() ) &&
+ LexArray->Initialize( 8, 8, 0) &&
+ ArgLex->Initialize( LexArray ) ) ) {
+
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY,
+ NULL,
+ EXIT_ERROR );
+
+ }
+
+ //
+ // Set our parsing preferences
+ //
+ ArgLex->PutSeparators( "," );
+ ArgLex->PutSwitches( Switches );
+ ArgLex->SetCaseSensitive( FALSE );
+
+ //
+ // Parse the arguments
+ //
+ if ( !(ArgLex->PrepareToParse( &CmdLine ))) {
+
+ DisplayMessageAndExit( MODE_ERROR_PARSE,
+ NULL,
+ EXIT_ERROR );
+
+ }
+
+
+ if ( !ArgLex->DoParsing( ArgArray ) ) {
+
+ DisplayMessageAndExit( MODE_ERROR_INVALID_PARAMETER,
+ ArgLex->QueryInvalidArgument(),
+ EXIT_ERROR );
+ }
+}
+
+PREQUEST_HEADER
+MakeRequest(
+ )
+
+/*++
+
+Routine Description:
+
+ Verifies the parameters and forms a device request.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Pointer to the device request.
+
+Notes:
+
+--*/
+
+{
+
+ //
+ // See if Help requested
+ //
+ // MODE [/?]
+ //
+ if ( HelpArg->QueryFlag() ) {
+
+ DisplayMessageAndExit( MODE_MESSAGE_HELP, NULL, EXIT_ERROR );
+ }
+
+ //
+ // We cannot have LPT1 and LPT1: at the same time
+ //
+ if ( ( LptArg->IsValueSet() && LptColonArg->IsValueSet() ) ||
+ ( ComArg->IsValueSet() && ComColonArg->IsValueSet() ) ||
+ ( ConArg->IsValueSet() && ConColonArg->IsValueSet() ) ) {
+
+ DisplayMessageAndExit( MODE_ERROR_INVALID_NUMBER_OF_PARAMETERS,
+ NULL,
+ EXIT_ERROR );
+ }
+
+ //
+ // Set the global device info. so we don't have to query the
+ // arguments all the time.
+ //
+ if ( LptArg->IsValueSet() ) {
+ LptSet = TRUE;
+ LptNumber = (ULONG)LptArg->QueryLong();
+ }
+
+ if ( LptColonArg->IsValueSet() ) {
+ LptSet = TRUE;
+ LptNumber = (ULONG)LptColonArg->QueryLong();
+ }
+
+ if ( ComArg->IsValueSet() ) {
+ ComSet = TRUE;
+ ComNumber = (ULONG)ComArg->QueryLong();
+ }
+
+ if ( ComColonArg->IsValueSet() ) {
+ ComSet = TRUE;
+ ComNumber = (ULONG)ComColonArg->QueryLong();
+ }
+
+ ConSet = (BOOLEAN)(ConArg->IsValueSet() || ConColonArg->IsValueSet());
+
+
+ //
+ // See if codepage stuff requested
+ //
+ // MODE device CP [/STATUS]
+ // MODE device CP PREPARE=string
+ // MODE device CP REFRESH
+ // MODE device CP SELECT=codepage
+ //
+ if ( CpArg->QueryFlag() ) {
+
+ return MakeCodePageRequest();
+
+ }
+
+ //
+ // See if Status requested
+ //
+ // MODE [device] [/STATUS]
+ //
+ if ( ( ArgLex->QueryConsumedCount() == 1 ) || StatusArg->IsValueSet() ) {
+
+ return MakeStatusRequest();
+ }
+
+ //
+ // See if LPT request
+ //
+ // MODE LPTn[:] [COLS=c] [LINES=l] [RETRY=r]
+ // MODE LPTn[:] = COMm[:]
+ //
+ if ( LptSet ) {
+
+ return MakeLptRequest();
+
+ }
+
+
+ //
+ // See if COM request
+ //
+ // MODE COMm[:] [BAUD=b] [PARITY=p] [DATA=d] [STOP=s] [RETRY=r]
+ //
+ if ( ComSet ) {
+
+ return MakeComRequest();
+
+ }
+
+ //
+ // See if CON request
+ //
+ // MODE CON[:] [COLS=c] [LINES=l]
+ //
+ // MODE CON[:] [RATE=r DELAY=d]
+ //
+ if ( ConSet ) {
+
+ return MakeConRequest();
+
+ }
+
+ //
+ // The request is incorrect
+ //
+ DisplayMessageAndExit( MODE_ERROR_INVALID_PARAMETER,
+ (PWSTRING)(LexArray->GetAt( 1 )),
+ EXIT_ERROR );
+
+ //
+ // To keep the compiler happy
+ //
+ return NULL;
+}
+
+
+
+PREQUEST_HEADER
+MakeStatusRequest(
+ )
+
+/*++
+
+Routine Description:
+
+ Verifies the parameters and forms a status request.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Pointer to the device request.
+
+Notes:
+
+--*/
+
+{
+
+ PREQUEST_HEADER Request;
+
+
+ //
+ // The maximum number of parameters is 3:
+ //
+ // MODE [device] /STATUS
+ //
+ if ( ArgLex->QueryConsumedCount() > 3 ) {
+
+ DisplayMessageAndExit( MODE_ERROR_INVALID_NUMBER_OF_PARAMETERS,
+ NULL,
+ EXIT_ERROR );
+ }
+
+ //
+ // Allocate the request header
+ //
+ Request = (PREQUEST_HEADER)MALLOC( sizeof( REQUEST_HEADER ) );
+ DbgPtrAssert( Request );
+ if ( !Request ) {
+
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY,
+ NULL,
+ EXIT_ERROR );
+ }
+
+ //
+ // Now initialzie the request according to the device type
+ //
+ Request->RequestType = REQUEST_TYPE_STATUS;
+
+ if ( LptSet ) {
+
+ //
+ // LPT Status request
+ //
+ Request->DeviceType = DEVICE_TYPE_LPT;
+ Request->DeviceNumber = LptNumber;
+
+ } else if ( ComSet ) {
+
+ //
+ // COM Status request
+ //
+ Request->DeviceType = DEVICE_TYPE_COM;
+ Request->DeviceNumber = ComNumber;
+
+ } else if ( ConSet ) {
+
+ //
+ // CON Status request
+ //
+ Request->DeviceType = DEVICE_TYPE_CON;
+ Request->DeviceNumber = 0;
+
+ } else {
+
+ //
+ // Everybody's status request
+ //
+ Request->DeviceType = DEVICE_TYPE_ALL;
+ Request->DeviceNumber = ALL_DEVICES;
+
+ }
+
+ return Request;
+
+}
+
+
+
+
+PREQUEST_HEADER
+MakeCodePageRequest(
+ )
+
+/*++
+
+Routine Description:
+
+ Verifies the parameters and forms a codepage request.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Pointer to the device request.
+
+Notes:
+
+--*/
+
+{
+ PREQUEST_HEADER Request;
+ PCON_REQUEST ConRequest;
+
+ //
+ // Only CON accepts codepage requests.
+ //
+ if ( LptSet || ComSet ) {
+
+ DisplayMessageAndExit( MODE_ERROR_CODEPAGE_OPERATION_NOT_SUPPORTED,
+ NULL,
+ EXIT_ERROR );
+ }
+ if ( !ConSet ) {
+
+ DisplayMessageAndExit( MODE_ERROR_INVALID_PARAMETER,
+ (PWSTRING)(LexArray->GetAt( 1 )),
+ EXIT_ERROR );
+ }
+
+
+ //
+ // Form the request depending on the Codepage option
+ //
+ if ( RefreshArg->IsValueSet() || PrepareArg->IsValueSet() ) {
+
+ //
+ // REFRESH - This is a NO-OP
+ // PREPARE - This is a NO-OP
+ //
+
+ if ( ArgLex->QueryConsumedCount() != 4 ) {
+
+ //
+ // Must have 4 arguments:
+ //
+ // MODE CON: CP REFRESH
+ //
+ DisplayMessageAndExit( MODE_ERROR_INVALID_NUMBER_OF_PARAMETERS,
+ NULL,
+ EXIT_ERROR );
+
+ }
+
+ Request = (PREQUEST_HEADER)MALLOC( sizeof( REQUEST_HEADER) );
+ DbgPtrAssert( Request );
+ if ( !Request ) {
+
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY,
+ NULL,
+ EXIT_ERROR );
+ }
+
+ Request->RequestType = REQUEST_TYPE_NULL;
+ Request->DeviceType = DEVICE_TYPE_ALL;
+
+ } else if ( SelectArg->IsValueSet() ) {
+
+ //
+ // SELECT
+ //
+
+ if ( ArgLex->QueryConsumedCount() != 4 ) {
+
+ //
+ // Must have 4 arguments:
+ //
+ // MODE CON: CP Select=codepage
+ //
+ DisplayMessageAndExit( MODE_ERROR_INVALID_NUMBER_OF_PARAMETERS,
+ NULL,
+ EXIT_ERROR );
+
+ }
+
+ ConRequest = (PCON_REQUEST)MALLOC( sizeof( CON_REQUEST ) );
+ DbgPtrAssert( ConRequest );
+ if ( !ConRequest ) {
+
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY,
+ NULL,
+ EXIT_ERROR );
+ }
+ Request = &(ConRequest->Header);
+
+ Request->RequestType = REQUEST_TYPE_CODEPAGE_SELECT;
+ Request->DeviceType = DEVICE_TYPE_CON;
+ Request->DeviceNumber = 0;
+
+ ConRequest->Data.CpSelect.Codepage = (ULONG)SelectArg->QueryLong();
+
+ } else {
+
+ //
+ // STATUS
+ //
+
+ if ( ArgLex->QueryConsumedCount() != (ULONG)(StatusArg->IsValueSet() ? 4 : 3) ) {
+
+ // Must have 3 or 4 arguments:
+ //
+ // MODE CON: CP [ /STATUS]
+ //
+ DisplayMessageAndExit( MODE_ERROR_INVALID_NUMBER_OF_PARAMETERS,
+ NULL,
+ EXIT_ERROR );
+ }
+
+
+ Request = (PREQUEST_HEADER)MALLOC( sizeof( REQUEST_HEADER) );
+ DbgPtrAssert( Request );
+ if ( !Request ) {
+
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY,
+ NULL,
+ EXIT_ERROR );
+ }
+
+ Request->RequestType = REQUEST_TYPE_CODEPAGE_STATUS;
+ Request->DeviceType = DEVICE_TYPE_CON;
+ Request->DeviceNumber = 0;
+
+ }
+
+ return Request;
+
+}
+
+
+
+
+PREQUEST_HEADER
+MakeLptRequest(
+ )
+
+/*++
+
+Routine Description:
+
+ Verifies the parameters and forms an LPT request.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Pointer to the device request.
+
+Notes:
+
+--*/
+
+{
+
+ PREQUEST_HEADER Request;
+ PLPT_REQUEST LptRequest;
+ ULONG ArgCnt;
+
+ //
+ // Form the request depending on the argument line
+ //
+ if ( ArgLex->QueryConsumedCount() == 2 ) {
+
+ //
+ // STATUS
+ //
+
+ Request = (PREQUEST_HEADER)MALLOC( sizeof( REQUEST_HEADER) );
+ DbgPtrAssert( Request );
+ if ( !Request ) {
+
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY,
+ NULL,
+ EXIT_ERROR );
+ }
+
+ Request->RequestType = REQUEST_TYPE_STATUS;
+ Request->DeviceType = DEVICE_TYPE_LPT;
+ Request->DeviceNumber = LptNumber;
+
+ } else if ( EqualArg->IsValueSet() ) {
+
+ //
+ // REDIRECTION
+ //
+ // MODE LPTn[:] = COMm[:]
+
+
+ if ( ArgLex->QueryConsumedCount() != 4 ) {
+
+ //
+ // Must have 4 arguments:
+ //
+ // MODE LPT1 = COM1
+ //
+ // BUGBUG What happens line is "LPT1=COM1" ?
+ //
+
+ DisplayMessageAndExit( MODE_ERROR_INVALID_NUMBER_OF_PARAMETERS,
+ NULL,
+ EXIT_ERROR );
+ }
+
+ //
+ // Can only redirect to COM
+ //
+ if ( !ComSet ) {
+ DisplayMessageAndExit( MODE_ERROR_INVALID_PARAMETER,
+ (PWSTRING)(LexArray->GetAt( 1 )),
+ EXIT_ERROR );
+ }
+
+ LptRequest = (PLPT_REQUEST)MALLOC( sizeof( LPT_REQUEST ) );
+ DbgPtrAssert( LptRequest );
+ if ( !LptRequest ) {
+
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY,
+ NULL,
+ EXIT_ERROR );
+ }
+ Request = &(LptRequest->Header);
+
+ Request->RequestType = REQUEST_TYPE_LPT_REDIRECT;
+ Request->DeviceType = DEVICE_TYPE_LPT;
+ Request->DeviceNumber = LptNumber;
+
+ LptRequest->Data.Redirect.DeviceType = DEVICE_TYPE_COM;
+ LptRequest->Data.Redirect.DeviceNumber = ComNumber;
+
+ } else if ( (ArgCnt = ( ColArg->IsValueSet() ? 1 : 0 ) +
+ ( LinesArg->IsValueSet() ? 1 : 0 ) +
+ ( RetryArg->IsValueSet() ? 1 : 0 )) > 0 ) {
+
+ //
+ // SET Lines & Columns
+ //
+
+ if ( ArgLex->QueryConsumedCount() > (ULONG)(2 + ArgCnt) ) {
+
+ //
+ // Must have 2 + ArgCnt arguments:
+ //
+ // MODE LPT1: [COLS=c] [LINES=l] [RETRY=r]
+ //
+ DisplayMessageAndExit( MODE_ERROR_INVALID_NUMBER_OF_PARAMETERS,
+ NULL,
+ EXIT_ERROR );
+ }
+
+ LptRequest = (PLPT_REQUEST)MALLOC( sizeof( LPT_REQUEST ) );
+ DbgPtrAssert( LptRequest );
+ if ( !LptRequest ) {
+
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY,
+ NULL,
+ EXIT_ERROR );
+ }
+ Request = &(LptRequest->Header);
+
+ Request->RequestType = REQUEST_TYPE_LPT_SETUP;
+ Request->DeviceType = DEVICE_TYPE_LPT;
+ Request->DeviceNumber = LptNumber;
+
+ LptRequest->Data.Setup.SetCol = FALSE;
+ LptRequest->Data.Setup.SetLines = FALSE;
+ LptRequest->Data.Setup.SetRetry = FALSE;
+
+ if ( ColArg->IsValueSet() ) {
+ LptRequest->Data.Setup.SetCol = TRUE;
+ LptRequest->Data.Setup.Col = ColArg->QueryLong();
+ }
+
+ if ( LinesArg->IsValueSet() ) {
+ LptRequest->Data.Setup.SetLines = TRUE;
+ LptRequest->Data.Setup.Lines = LinesArg->QueryLong();
+ }
+
+ if ( RetryArg->IsValueSet() ) {
+
+ LptRequest->Data.Setup.SetRetry = TRUE;
+ LptRequest->Data.Setup.Retry = 0;
+
+ }
+
+ } else {
+
+ //
+ // Invalid request
+ //
+
+ DisplayMessageAndExit( MODE_ERROR_INVALID_PARAMETER,
+ (PWSTRING)(LexArray->GetAt( 1 )),
+ EXIT_ERROR );
+
+ }
+
+ return Request;
+
+}
+
+
+
+
+PREQUEST_HEADER
+MakeComRequest(
+ )
+
+/*++
+
+Routine Description:
+
+ Verifies the parameters and forms a COM request.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Pointer to the device request.
+
+Notes:
+
+--*/
+
+{
+ PREQUEST_HEADER Request;
+ PCOM_REQUEST ComRequest;
+ ULONG ArgCnt;
+
+ if ( ArgLex->QueryConsumedCount() == 2 ) {
+
+ //
+ // Status request
+ //
+ Request = (PREQUEST_HEADER)MALLOC( sizeof( REQUEST_HEADER ) );
+ DbgPtrAssert( Request );
+ if ( !Request ) {
+
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY,
+ NULL,
+ EXIT_ERROR );
+ }
+
+ Request->RequestType = REQUEST_TYPE_STATUS;
+ Request->DeviceType = DEVICE_TYPE_COM;
+ Request->DeviceNumber = ComNumber;
+
+
+ } else if ( (ArgCnt = ( BaudArg->IsValueSet() ? 1 : 0 ) +
+ ( ParityArg->IsValueSet() ? 1 : 0 ) +
+ ( DataArg->IsValueSet() ? 1 : 0 ) +
+ ( Stop15Arg->IsValueSet() ? 1 : 0 ) +
+ ( StopArg->IsValueSet() ? 1 : 0 ) +
+ ( RetryArg->IsValueSet() ? 1 : 0 )) > 0 ) {
+
+
+ //
+ // Set COM Configuration
+ //
+
+ if ( ArgLex->QueryConsumedCount() > (ULONG)(2 + ArgCnt) ) {
+
+ //
+ // Must have 2 + ArgCnt arguments:
+ //
+ // MODE COM1: [ all options ]
+ //
+ DisplayMessageAndExit( MODE_ERROR_INVALID_NUMBER_OF_PARAMETERS,
+ NULL,
+ EXIT_ERROR );
+ }
+
+ ComRequest = (PCOM_REQUEST)MALLOC( sizeof( COM_REQUEST ) );
+ DbgPtrAssert( ComRequest );
+ if ( !ComRequest ) {
+
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY,
+ NULL,
+ EXIT_ERROR );
+ }
+ Request = &(ComRequest->Header);
+
+ Request->RequestType = REQUEST_TYPE_COM_SET;
+ Request->DeviceType = DEVICE_TYPE_COM;
+ Request->DeviceNumber = ComNumber;
+
+
+
+ ComRequest->Data.Set.SetBaud = FALSE;
+ ComRequest->Data.Set.SetDataBits = FALSE;
+ ComRequest->Data.Set.SetStopBits = FALSE;
+ ComRequest->Data.Set.SetParity = FALSE;
+ ComRequest->Data.Set.SetRetry = FALSE;
+
+ if ( BaudArg->IsValueSet() ) {
+
+ ComRequest->Data.Set.SetBaud = TRUE;
+ ComRequest->Data.Set.Baud = ConvertBaudRate( BaudArg->QueryLong(), ArgLex->GetLexemeAt( BaudArg->GetLexemeIndex()) );
+
+ }
+
+ if ( DataArg->IsValueSet() ) {
+
+ ComRequest->Data.Set.SetDataBits = TRUE;
+ ComRequest->Data.Set.DataBits = ConvertDataBits( DataArg->QueryLong(), ArgLex->GetLexemeAt( DataArg->GetLexemeIndex()) );
+ }
+
+ if ( Stop15Arg->IsValueSet() ) {
+ ComRequest->Data.Set.SetStopBits = TRUE;
+ ComRequest->Data.Set.StopBits = STOPBITS_15;
+ } else if ( StopArg->IsValueSet() ) {
+ ComRequest->Data.Set.SetStopBits = TRUE;
+ ComRequest->Data.Set.StopBits = ConvertStopBits( StopArg->QueryLong(), ArgLex->GetLexemeAt( StopArg->GetLexemeIndex()) );
+ }
+
+ if ( ParityArg->IsValueSet() ) {
+
+ ComRequest->Data.Set.SetParity = TRUE;
+ ComRequest->Data.Set.Parity = ConvertParity( ParityArg->GetString(), ArgLex->GetLexemeAt( ParityArg->GetLexemeIndex()) );
+ }
+
+ if ( RetryArg->IsValueSet() ) {
+ ComRequest->Data.Set.SetRetry = TRUE;
+ ComRequest->Data.Set.Retry = ConvertRetry( RetryArg->GetString(), ArgLex->GetLexemeAt( RetryArg->GetLexemeIndex()) );
+
+ }
+
+ } else {
+
+ //
+ // Invalid request
+ //
+
+ DisplayMessageAndExit( MODE_ERROR_INVALID_PARAMETER,
+ (PWSTRING)(LexArray->GetAt( 1 )),
+ EXIT_ERROR );
+
+ }
+
+
+ return Request;
+
+}
+
+
+
+
+PREQUEST_HEADER
+MakeConRequest(
+ )
+
+/*++
+
+Routine Description:
+
+ Verifies the parameters and forms a CON request.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Pointer to the device request.
+
+Notes:
+
+--*/
+
+{
+
+ PREQUEST_HEADER Request;
+ PCON_REQUEST ConRequest;
+ ULONG ArgCnt;
+
+ if ( ArgLex->QueryConsumedCount() == 2 ) {
+
+ //
+ // Status request
+ //
+ Request = (PREQUEST_HEADER)MALLOC( sizeof( REQUEST_HEADER ) );
+ DbgPtrAssert( Request );
+ if ( !Request ) {
+
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY,
+ NULL,
+ EXIT_ERROR );
+ }
+
+ Request->RequestType = REQUEST_TYPE_STATUS;
+ Request->DeviceType = DEVICE_TYPE_CON;
+ Request->DeviceNumber = 0;
+
+ } else if ( (ArgCnt = ( ColArg->IsValueSet() ? 1 : 0 ) +
+ ( LinesArg->IsValueSet() ? 1 : 0 )) > 0 ) {
+
+ //
+ // Set Lines and Columns
+ //
+
+ if ( ArgLex->QueryConsumedCount() > (ULONG)(2 + ArgCnt) ) {
+
+ //
+ // Must have 2 + ArgCnt arguments:
+ //
+ // MODE CON: [COLS=c] [ LINES=l]
+ //
+ DisplayMessageAndExit( MODE_ERROR_INVALID_NUMBER_OF_PARAMETERS,
+ NULL,
+ EXIT_ERROR );
+ }
+
+ ConRequest = (PCON_REQUEST)MALLOC( sizeof( CON_REQUEST ) );
+ DbgPtrAssert( ConRequest );
+ if ( !ConRequest ) {
+
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY,
+ NULL,
+ EXIT_ERROR );
+ }
+ Request = &(ConRequest->Header);
+
+ Request->RequestType = REQUEST_TYPE_CON_SET_ROWCOL;
+ Request->DeviceType = DEVICE_TYPE_CON;
+ Request->DeviceNumber = 0;
+
+ ConRequest->Data.RowCol.SetCol = FALSE;
+ ConRequest->Data.RowCol.SetLines = FALSE;
+
+ if ( ColArg->IsValueSet() ) {
+ ConRequest->Data.RowCol.SetCol = TRUE;
+ ConRequest->Data.RowCol.Col = ColArg->QueryLong();
+ }
+
+ if ( LinesArg->IsValueSet() ) {
+ ConRequest->Data.RowCol.SetLines = TRUE;
+ ConRequest->Data.RowCol.Lines = LinesArg->QueryLong();
+ }
+
+ } else if ( (ArgCnt = ( RateArg->IsValueSet() ? 1 : 0 ) +
+ ( DelayArg->IsValueSet() ? 1 : 0 )) > 0 ) {
+
+ //
+ // Set Typematic rate
+ //
+
+ if ( ArgLex->QueryConsumedCount() > (ULONG)(2 + ArgCnt) ) {
+
+ //
+ // Must have 2 + ArgCnt arguments:
+ //
+ // MODE CON: [RATE=r] [DELAY=d]
+ //
+ DisplayMessageAndExit( MODE_ERROR_INVALID_NUMBER_OF_PARAMETERS,
+ NULL,
+ EXIT_ERROR );
+ }
+
+ ConRequest = (PCON_REQUEST)MALLOC( sizeof( CON_REQUEST ) );
+ DbgPtrAssert( ConRequest );
+ if ( !ConRequest ) {
+
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY,
+ NULL,
+ EXIT_ERROR );
+ }
+ Request = &(ConRequest->Header);
+
+ Request->RequestType = REQUEST_TYPE_CON_SET_TYPEMATIC;
+ Request->DeviceType = DEVICE_TYPE_CON;
+ Request->DeviceNumber = 0;
+
+ ConRequest->Data.Typematic.SetRate = FALSE;
+ ConRequest->Data.Typematic.SetDelay = FALSE;
+
+ if ( RateArg->IsValueSet() ) {
+ ConRequest->Data.Typematic.SetRate = TRUE;
+ ConRequest->Data.Typematic.Rate = RateArg->QueryLong();
+ }
+
+ if ( DelayArg->IsValueSet() ) {
+ ConRequest->Data.Typematic.SetDelay = TRUE;
+ ConRequest->Data.Typematic.Delay = DelayArg->QueryLong();
+ }
+
+ } else {
+
+ //
+ // Invalid request
+ //
+
+ DisplayMessageAndExit( MODE_ERROR_INVALID_PARAMETER,
+ (PWSTRING)(LexArray->GetAt( 1 )),
+ EXIT_ERROR );
+
+ }
+
+ return Request;
+
+}
+
+PREQUEST_HEADER
+MakeRequest(
+ )
+
+/*++
+
+Routine Description:
+
+ Makes a request and initializes its header
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Pointer to the device request.
+
+Notes:
+
+--*/
+
+{
diff --git a/private/utils/mode/com.cxx b/private/utils/mode/com.cxx
new file mode 100644
index 000000000..5b9a7d2de
--- /dev/null
+++ b/private/utils/mode/com.cxx
@@ -0,0 +1,1208 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Com
+
+Abstract:
+
+ Takes care of request involving a COM device
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 26-Jun-1991
+
+Revision History:
+
+--*/
+
+
+
+#include "mode.hxx"
+#include "com.hxx"
+#include "array.hxx"
+#include "arrayit.hxx"
+#include "file.hxx"
+#include "path.hxx"
+#include "registry.hxx"
+#include "regvalue.hxx"
+
+
+#define DEFAULT_PARITY COMM_PARITY_EVEN
+#define DEFAULT_DATA_BITS 7
+
+
+
+
+//
+// Local prototypes
+//
+BOOLEAN
+ComStatus(
+ IN PCPATH DevicePath,
+ IN PREQUEST_HEADER Request
+ );
+
+BOOLEAN
+ComSetup(
+ IN PCPATH DevicePath,
+ IN PREQUEST_HEADER Request
+ );
+
+BOOLEAN
+IsAValidCommDevice (
+ IN DEVICE_TTYPE DeviceType,
+ IN ULONG DeviceNumber,
+ OUT PPATH *DevicePathPointer
+ );
+
+
+
+
+
+
+BOOLEAN
+ComAllocateStuff(
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes Data Structures used for COMM processing.
+
+Arguments:
+
+ nonde
+
+Return Value:
+
+ BOOLEAN - TRUE if global data initialized, FALSE otherwise
+
+Notes:
+
+--*/
+
+{
+
+ return TRUE;
+
+}
+
+BOOLEAN
+ComDeAllocateStuff(
+ )
+
+/*++
+
+Routine Description:
+
+ Deallocates the stuff allocated by ComAllocateStuff.
+
+Arguments:
+
+ nonde
+
+Return Value:
+
+ BOOLEAN - TRUE if global data de-initialized, FALSE otherwise
+
+Notes:
+
+--*/
+
+{
+
+ return TRUE;
+
+}
+
+BOOLEAN
+ComHandler(
+ IN PREQUEST_HEADER Request
+ )
+
+/*++
+
+Routine Description:
+
+ Handles serial port requests.
+
+Arguments:
+
+ Request - Supplies pointer to request
+
+Return Value:
+
+ BOOLEAN - TRUE if request serviced,
+ FALSE otherwise.
+
+Notes:
+
+--*/
+
+{
+
+
+ PPATH DevicePath; // Name of Device
+ BOOLEAN Served = TRUE; // TRUE if request served OK.
+
+ DebugPtrAssert( Request );
+ DebugAssert( Request->DeviceType == DEVICE_TYPE_COM );
+
+ //
+ // Make sure that the device exists, and at the same time get its
+ // name ( For calling APIs ).
+ //
+ if ( Request->DeviceName ) {
+
+ DevicePath = NEW PATH;
+ DevicePath->Initialize( Request->DeviceName );
+
+ } else {
+
+ if ( !IsAValidCommDevice( Request->DeviceType, Request->DeviceNumber, &DevicePath )) {
+
+ DisplayMessageAndExit( MODE_ERROR_INVALID_DEVICE_NAME,
+ DevicePath->GetPathString(),
+ (ULONG)EXIT_ERROR );
+
+ } else if ( !IsAValidDevice( Request->DeviceType, Request->DeviceNumber, NULL ) ) {
+
+ DisplayMessageAndExit( MODE_ERROR_DEVICE_UNAVAILABLE,
+ DevicePath->GetPathString(),
+ (ULONG)EXIT_ERROR );
+
+ }
+ }
+
+ //
+ // So the device is valid. Now serve the request
+ //
+ switch( Request->RequestType ) {
+
+ case REQUEST_TYPE_STATUS:
+
+ //
+ // Display state of COM device
+ //
+ Served = ComStatus( DevicePath, Request );
+ break;
+
+ case REQUEST_TYPE_COM_SET:
+
+ //
+ // Set state of COM device
+ //
+ Served = ComSetup( DevicePath, Request );
+ break;
+
+ default:
+
+ DebugAssert( FALSE );
+
+ }
+
+ DELETE( DevicePath );
+
+ return Served;
+
+}
+
+BOOLEAN
+ComStatus(
+ IN PCPATH DevicePath,
+ IN PREQUEST_HEADER Request
+ )
+
+/*++
+
+Routine Description:
+
+ Displays status if a COM device
+
+Arguments:
+
+ DevicePath - Supplies pointer to path of device
+ Request - Supplies pointer to request
+
+Return Value:
+
+ BOOLEAN - TRUE if status displayed successfully,
+ FALSE otherwise
+
+Notes:
+
+--*/
+
+{
+ DSTRING Data;
+ COMM_DEVICE CommDevice; // Comm object of the device.
+ BOOLEAN OpenError;
+ BOOLEAN Status;
+
+ DebugPtrAssert( DevicePath );
+ DebugPtrAssert( Request );
+
+ //
+ // Initialize the Comm object
+ //
+ Status = CommDevice.Initialize( DevicePath, &OpenError);
+
+
+ if ( Status ) {
+
+ //
+ // Write the Header
+ //
+ WriteStatusHeader( DevicePath );
+
+
+ //
+ // Baud rate
+ //
+ Data.Initialize( (ULONG)CommDevice.QueryBaudRate() );
+ DisplayMessage( MODE_MESSAGE_STATUS_BAUD, &Data );
+
+
+ //
+ // Parity
+ //
+ switch ( CommDevice.QueryParity() ) {
+
+ case COMM_PARITY_NONE:
+ Data.Initialize( "None" );
+ break;
+
+ case COMM_PARITY_ODD:
+ Data.Initialize( "Odd" );
+ break;
+
+ case COMM_PARITY_EVEN:
+ Data.Initialize( "Even" );
+ break;
+
+ case COMM_PARITY_MARK:
+ Data.Initialize( "Mark" );
+ break;
+
+ case COMM_PARITY_SPACE:
+ Data.Initialize( "Space" );
+ break;
+
+ default:
+ DebugAssert( FALSE );
+ }
+
+ DisplayMessage( MODE_MESSAGE_STATUS_PARITY, &Data );
+
+
+ //
+ // Data bits
+ //
+ Data.Initialize( (ULONG)CommDevice.QueryDataBits() );
+ DisplayMessage( MODE_MESSAGE_STATUS_DATA, &Data );
+
+
+ //
+ // Stop bits
+ //
+ switch ( CommDevice.QueryStopBits() ) {
+
+ case COMM_STOPBITS_15:
+ Data.Initialize( "1.5" );
+ break;
+
+ case COMM_STOPBITS_1:
+ Data.Initialize( 1 );
+ break;
+
+ case COMM_STOPBITS_2:
+ Data.Initialize( 2 );
+ break;
+
+ default:
+ DebugAssert( FALSE );
+ }
+
+ DisplayMessage( MODE_MESSAGE_STATUS_STOP, &Data );
+
+
+ //
+ // TimeOut
+ //
+ if ( CommDevice.QueryTimeOut() ) {
+ //
+ // TRUE means infinite timeout == no timeout
+ //
+ Data.Initialize( "OFF" );
+ } else {
+ Data.Initialize( "ON" );
+ }
+ DisplayMessage( MODE_MESSAGE_STATUS_TIMEOUT, &Data );
+
+
+ //
+ // XON/XOFF
+ //
+ if ( CommDevice.QueryXon() ) {
+ Data.Initialize( "ON" );
+ } else {
+ Data.Initialize( "OFF" );
+ }
+ DisplayMessage( MODE_MESSAGE_STATUS_XON, &Data );
+
+
+ //
+ // CTS
+ //
+ if ( CommDevice.QueryOcts() ) {
+ Data.Initialize( "ON" );
+ } else {
+ Data.Initialize( "OFF" );
+ }
+ DisplayMessage( MODE_MESSAGE_STATUS_OCTS, &Data );
+
+ //
+ // DSR handshaking
+ //
+ if ( CommDevice.QueryOdsr() ) {
+ Data.Initialize( "ON" );
+ } else {
+ Data.Initialize( "OFF" );
+ }
+ DisplayMessage( MODE_MESSAGE_STATUS_ODSR, &Data );
+
+ //
+ // DSR sensitivity
+ //
+ if ( CommDevice.QueryIdsr() ) {
+ Data.Initialize( "ON" );
+ } else {
+ Data.Initialize( "OFF" );
+ }
+ DisplayMessage( MODE_MESSAGE_STATUS_IDSR, &Data );
+
+ //
+ // DTR
+ //
+ switch( CommDevice.QueryDtrControl() ) {
+
+ case DTR_ENABLE:
+ Data.Initialize( "ON" );
+ break;
+
+ case DTR_DISABLE:
+ Data.Initialize( "OFF" );
+ break;
+
+ case DTR_HANDSHAKE:
+ Data.Initialize( "HANDSHAKE" );
+ break;
+
+ default:
+ Data.Initialize( "UNKNOWN" );
+ break;
+
+ }
+ DisplayMessage( MODE_MESSAGE_STATUS_DTR, &Data );
+
+
+ //
+ // RTS
+ //
+ switch( CommDevice.QueryRtsControl() ) {
+
+ case RTS_ENABLE:
+ Data.Initialize( "ON" );
+ break;
+
+ case RTS_DISABLE:
+ Data.Initialize( "OFF" );
+ break;
+
+ case RTS_HANDSHAKE:
+ Data.Initialize( "HANDSHAKE" );
+ break;
+
+ case RTS_TOGGLE:
+ Data.Initialize( "TOGGLE" );
+ break;
+
+ default:
+ Data.Initialize( "UNKNOWN" );
+ break;
+
+ }
+ DisplayMessage( MODE_MESSAGE_STATUS_RTS, &Data );
+
+ Get_Standard_Output_Stream()->WriteChar( '\r' );
+ Get_Standard_Output_Stream()->WriteChar( '\n' );
+
+ } else if ( !OpenError ) {
+
+ DisplayMessage( MODE_ERROR_CANNOT_ACCESS_DEVICE,
+ DevicePath->GetPathString() );
+
+ Status = TRUE;
+ }
+
+ return Status;
+}
+
+
+
+BOOLEAN
+ComSetup(
+ IN PCPATH DevicePath,
+ IN PREQUEST_HEADER Request
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the state of a COM port
+
+Arguments:
+
+ DevicePath - Supplies pointer to path of device
+ Request - Supplies pointer to request
+
+Return Value:
+
+ BOOLEAN - TRUE if state set successfully,
+ FALSE otherwise
+
+Notes:
+
+--*/
+
+{
+
+ PCOMM_DEVICE CommDevice; // Comm object of the device.
+ BOOLEAN Status = FALSE; // Indicates success or failure
+ PREQUEST_DATA_COM_SET Data; // Request data
+ BOOLEAN OpenError;
+ DSTRING Number;
+
+ DebugPtrAssert( DevicePath );
+ DebugPtrAssert( Request );
+
+ //
+ // Initialize the Comm object
+ //
+ CommDevice = NEW COMM_DEVICE;
+ if ( !CommDevice ) {
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY, NULL, (ULONG)EXIT_ERROR );
+ }
+ Status = CommDevice->Initialize( DevicePath, &OpenError );
+ if ( Status ) {
+
+ //
+ // We have the Comm object. Set the state according to
+ // the request.
+ //
+ Data = &(((PCOM_REQUEST)Request)->Data.Set);
+
+ //
+ // Baud rate
+ //
+ if ( Data->SetBaud ) {
+
+ CommDevice->SetBaudRate( Data->Baud );
+
+ }
+
+ //
+ // Data Bits
+ //
+ if ( Data->SetDataBits ) {
+
+ CommDevice->SetDataBits( Data->DataBits );
+
+ } else {
+
+ //
+ // Set default
+ //
+ if ( CommDevice->QueryDataBits() != DEFAULT_DATA_BITS ) {
+ CommDevice->SetDataBits( DEFAULT_DATA_BITS );
+ Number.Initialize( DEFAULT_DATA_BITS );
+ DisplayMessage( MODE_MESSAGE_USED_DEFAULT_DATA, &Number );
+ }
+ }
+
+ //
+ // Stop Bits
+ //
+ if ( Data->SetStopBits ) {
+
+ CommDevice->SetStopBits( Data->StopBits );
+
+ } else {
+
+ //
+ // Set default
+ //
+ if ( CommDevice->QueryBaudRate() == 110 ) {
+ if ( CommDevice->QueryStopBits() != COMM_STOPBITS_2 ) {
+ CommDevice->SetStopBits( COMM_STOPBITS_2 );
+ Number.Initialize( 2 );
+ DisplayMessage( MODE_MESSAGE_USED_DEFAULT_STOP, &Number );
+ }
+ } else {
+ if ( CommDevice->QueryStopBits() != COMM_STOPBITS_1 ) {
+ CommDevice->SetStopBits( COMM_STOPBITS_1 );
+ Number.Initialize( 1 );
+ DisplayMessage( MODE_MESSAGE_USED_DEFAULT_STOP, &Number );
+ }
+ }
+ }
+
+ //
+ // Parity
+ //
+ if ( Data->SetParity ) {
+
+ CommDevice->SetParity( Data->Parity );
+
+ } else {
+
+ //
+ // Set default
+ //
+ if ( CommDevice->QueryParity() != DEFAULT_PARITY ) {
+ CommDevice->SetParity( DEFAULT_PARITY );
+ DisplayMessage( MODE_MESSAGE_USED_DEFAULT_PARITY, NULL );
+ }
+ }
+
+ //
+ // Timeout
+ //
+ if ( Data->SetTimeOut ) {
+
+ CommDevice->SetTimeOut( Data->TimeOut );
+
+ }
+
+
+ //
+ // XON/XOFF
+ //
+ if ( Data->SetXon) {
+
+ CommDevice->SetXon( Data->Xon );
+
+ }
+
+
+ //
+ // CTS
+ //
+ if ( Data->SetOcts ) {
+
+ CommDevice->SetOcts( Data->Octs );
+ }
+
+ //
+ // DSR handshaking
+ //
+ if ( Data->SetOdsr ) {
+
+ CommDevice->SetOdsr( Data->Odsr );
+ }
+
+ //
+ // DSR sensitivity
+ //
+ if ( Data->SetIdsr ) {
+
+ CommDevice->SetIdsr( Data->Idsr );
+ }
+
+ //
+ // DTR
+ //
+ if ( Data->SetDtrControl ) {
+
+ CommDevice->SetDtrControl( Data->DtrControl );
+ }
+
+ //
+ // RTS
+ //
+ if ( Data->SetRtsControl ) {
+
+ CommDevice->SetRtsControl( Data->RtsControl );
+ }
+
+ //
+ // Now Commit the changes
+ //
+ if ( !CommDevice->CommitState() ) {
+
+ DisplayMessage( MODE_ERROR_SERIAL_OPTIONS_NOT_SUPPORTED, NULL );
+ DisplayMessageAndExit( MODE_MESSAGE_COM_NO_CHANGE,
+ NULL,
+ (ULONG)EXIT_ERROR );
+ }
+
+ } else if ( !OpenError ) {
+
+ DisplayMessageAndExit( MODE_ERROR_CANNOT_ACCESS_DEVICE,
+ DevicePath->GetPathString(),
+ (ULONG)EXIT_ERROR );
+ }
+
+ DELETE( CommDevice );
+
+ if ( Status ) {
+ //
+ // Display the status of the port (as confirmation ).
+ //
+ ComStatus( DevicePath, Request );
+
+ }
+
+ return Status;
+}
+
+
+LONG
+ConvertBaudRate (
+ IN LONG BaudIn
+ )
+
+/*++
+
+Routine Description:
+
+ Validates a baud rate given as an argument to the program, and converts
+ it to something that the COMM_DEVICE understands.
+
+Arguments:
+
+ BaudIn - Supplies the baud rate given by the user
+
+Return Value:
+
+ LONG - The baud rate
+
+
+--*/
+
+{
+ LONG BaudRate;
+
+ switch ( BaudIn ) {
+
+ case 11:
+ case 110:
+ BaudRate = 110;
+ break;
+
+ case 15:
+ case 150:
+ BaudRate = 150;
+ break;
+
+ case 30:
+ case 300:
+ BaudRate = 300;
+ break;
+
+ case 60:
+ case 600:
+ BaudRate = 600;
+ break;
+
+ case 12:
+ case 1200:
+ BaudRate = 1200;
+ break;
+
+ case 24:
+ case 2400:
+ BaudRate = 2400;
+ break;
+
+ case 48:
+ case 4800:
+ BaudRate = 4800;
+ break;
+
+ case 96:
+ case 9600:
+ BaudRate = 9600;
+ break;
+
+ case 19:
+ case 19200:
+ BaudRate = 19200;
+ break;
+
+ default:
+ BaudRate = BaudIn;
+
+ }
+
+ return BaudRate;
+}
+
+
+LONG
+ConvertDataBits (
+ IN LONG DataBitsIn
+ )
+
+/*++
+
+Routine Description:
+
+ Validates the number of data bits given as an argument to the program,
+ and converts it to something that the COMM_DEVICE understands.
+
+Arguments:
+
+ DataBitsIn - Supplies the number given by the user
+
+Return Value:
+
+ LONG - The number of data bits
+
+
+--*/
+
+{
+
+ if ( ( DataBitsIn != 5 ) &&
+ ( DataBitsIn != 6 ) &&
+ ( DataBitsIn != 7 ) &&
+ ( DataBitsIn != 8 ) ) {
+
+ ParseError();
+
+ }
+
+ return DataBitsIn;
+
+}
+
+
+STOPBITS
+ConvertStopBits (
+ IN LONG StopBitsIn
+ )
+
+/*++
+
+Routine Description:
+
+ Validates a number of stop bits given as an argument to the program,
+ and converts it to something that the COMM_DEVICE understands.
+
+Arguments:
+
+ StopBitsIn - Supplies the number given by the user
+
+Return Value:
+
+ STOPBITS - The number of stop bits
+
+
+--*/
+
+{
+ STOPBITS StopBits;
+
+ switch ( StopBitsIn ) {
+
+ case 1:
+ StopBits = COMM_STOPBITS_1;
+ break;
+
+ case 2:
+ StopBits = COMM_STOPBITS_2;
+ break;
+
+ default:
+ ParseError();
+
+ }
+
+ return StopBits;
+
+}
+
+
+PARITY
+ConvertParity (
+ IN WCHAR ParityIn
+ )
+
+/*++
+
+Routine Description:
+
+ Validates a parity given as an argument to the program, and converts
+ it to something that the COMM_DEVICE understands.
+
+Arguments:
+
+ ParityIn - Supplies the baud rate given by the user
+
+Return Value:
+
+ PARITY - The parity
+
+
+--*/
+
+{
+
+ DSTRING ParityString;;
+ WCHAR Par;
+ PARITY Parity;
+
+ //
+ // Get the character that specifies parity. We lowercase it
+ //
+ ParityString.Initialize( " " );
+ ParityString.SetChAt( ParityIn, 0 );
+
+ ParityString.Strlwr();
+ Par = ParityString.QueryChAt( 0 );
+
+ //
+ // Set the correct parity value depending on the character.
+ //
+ switch ( Par ) {
+
+ case 'n':
+ Parity = COMM_PARITY_NONE;
+ break;
+
+ case 'o':
+ Parity = COMM_PARITY_ODD;
+ break;
+
+ case 'e':
+ Parity = COMM_PARITY_EVEN;
+ break;
+
+ case 'm':
+ Parity = COMM_PARITY_MARK;
+ break;
+
+ case 's':
+ Parity = COMM_PARITY_SPACE;
+ break;
+
+ default:
+ ParseError();
+
+ }
+
+ return Parity;
+}
+
+
+WCHAR
+ConvertRetry (
+ IN WCHAR RetryIn
+ )
+
+/*++
+
+Routine Description:
+
+ Validates a retry value given as an argument to the program, and
+ converts it to something that the COMM_DEVICE understands.
+
+Arguments:
+
+ RetryIn - Supplies the retry value given by the user
+
+Return Value:
+
+ WCHAR - The retry value
+
+
+--*/
+
+{
+ return RetryIn;
+
+}
+
+
+
+DTR_CONTROL
+ConvertDtrControl (
+ IN PCWSTRING CmdLine,
+ IN CHNUM IdxBegin,
+ IN CHNUM IdxEnd
+ )
+
+/*++
+
+Routine Description:
+
+ Validates a DTR control value given as an argument to the
+ program, and converts it to something that the COMM_DEVICE
+ understands.
+
+Arguments:
+
+ CmdLine - Supplies the command line
+ IdxBegin - Supplies Index of first character
+ IdxEnd - Supplies Index of last character
+
+Return Value:
+
+ DTR_CONTROL - The DTR control value
+
+
+--*/
+
+{
+ DSTRING On;
+ DSTRING Off;
+ DSTRING Hs;
+
+
+ if ( On.Initialize( "ON" ) &&
+ Off.Initialize( "OFF" ) &&
+ Hs.Initialize( "HS" ) ) {
+
+
+ if ( !CmdLine->Stricmp( &On,
+ IdxBegin,
+ IdxEnd-IdxBegin+1,
+ 0,
+ On.QueryChCount() ) ) {
+
+ return DTR_ENABLE;
+ }
+
+ if ( !CmdLine->Stricmp( &Off,
+ IdxBegin,
+ IdxEnd-IdxBegin+1,
+ 0,
+ Off.QueryChCount() ) ) {
+
+ return DTR_DISABLE;
+ }
+
+ if ( !CmdLine->Stricmp( &Hs,
+ IdxBegin,
+ IdxEnd-IdxBegin+1,
+ 0,
+ Hs.QueryChCount() ) ) {
+
+ return DTR_HANDSHAKE;
+ }
+ }
+
+ ParseError();
+
+ return (DTR_CONTROL)-1;
+}
+
+
+
+RTS_CONTROL
+ConvertRtsControl (
+ IN PCWSTRING CmdLine,
+ IN CHNUM IdxBegin,
+ IN CHNUM IdxEnd
+ )
+
+/*++
+
+Routine Description:
+
+ Validates a RTS control value given as an argument to the
+ program, and converts it to something that the COMM_DEVICE
+ understands.
+
+Arguments:
+
+ CmdLine - Supplies the command line
+ IdxBegin - Supplies Index of first character
+ IdxEnd - Supplies Index of last character
+
+Return Value:
+
+ RTS_CONTROL - The RTS control value
+
+
+--*/
+
+{
+ DSTRING On;
+ DSTRING Off;
+ DSTRING Hs;
+ DSTRING Tg;
+
+
+ if ( On.Initialize( "ON" ) &&
+ Off.Initialize( "OFF" ) &&
+ Hs.Initialize( "HS" ) &&
+ Tg.Initialize( "TG" )
+ ) {
+
+
+ if ( !CmdLine->Stricmp( &On,
+ IdxBegin,
+ IdxEnd-IdxBegin+1,
+ 0,
+ On.QueryChCount() ) ) {
+
+ return RTS_ENABLE;
+ }
+
+ if ( !CmdLine->Stricmp( &Off,
+ IdxBegin,
+ IdxEnd-IdxBegin+1,
+ 0,
+ Off.QueryChCount() ) ) {
+
+ return RTS_DISABLE;
+ }
+
+ if ( !CmdLine->Stricmp( &Hs,
+ IdxBegin,
+ IdxEnd-IdxBegin+1,
+ 0,
+ Hs.QueryChCount() ) ) {
+
+ return RTS_HANDSHAKE;
+ }
+
+ if ( !CmdLine->Stricmp( &Tg,
+ IdxBegin,
+ IdxEnd-IdxBegin+1,
+ 0,
+ Tg.QueryChCount() ) ) {
+
+ return RTS_TOGGLE;
+ }
+ }
+
+ ParseError();
+
+ return (RTS_CONTROL)-1;
+}
+
+
+
+
+BOOLEAN
+IsAValidCommDevice (
+ IN DEVICE_TTYPE DeviceType,
+ IN ULONG DeviceNumber,
+ OUT PPATH *DevicePathPointer
+ )
+
+/*++
+
+Routine Description:
+
+ Determines if a certain comm device exists and optionally
+ creates a path for it.
+
+Arguments:
+
+ DeviceType - Supplies the type of device
+ DeviceNumber - Supplies the device number
+ DeviceName - Supplies a pointer to a pointer to the path for
+ the device.
+
+Return Value:
+
+ BOOLEAN - TRUE if the device exists,
+ FALSE otherwise.
+
+Notes:
+
+--*/
+
+{
+ DSTRING DeviceName;
+ DSTRING Number;
+ BOOLEAN Valid = FALSE;
+ REGISTRY Registry;
+ DSTRING ParentName;
+ DSTRING KeyName;
+ ARRAY ValueArray;
+ PARRAY_ITERATOR Iterator;
+ ULONG ErrorCode;
+ PCBYTE Data;
+ DSTRING PortName;
+ PREGISTRY_VALUE_ENTRY Value;
+
+
+ UNREFERENCED_PARAMETER( DeviceType );
+
+
+ if ( DeviceName.Initialize( (LPWSTR)L"COM" )&&
+ Number.Initialize( DeviceNumber ) &&
+ DeviceName.Strcat( &Number ) &&
+ ParentName.Initialize( "" ) &&
+ KeyName.Initialize( COMM_KEY_NAME ) &&
+ ValueArray.Initialize() &&
+ Registry.Initialize()
+ ) {
+
+
+ //
+ // Get the names of all the serial ports
+ //
+ if ( Registry.QueryValues(
+ PREDEFINED_KEY_LOCAL_MACHINE,
+ &ParentName,
+ &KeyName,
+ &ValueArray,
+ &ErrorCode
+ ) ) {
+
+ //
+ // See if the given name matches any of the serial ports
+ //
+ if ( Iterator = (PARRAY_ITERATOR)ValueArray.QueryIterator() ) {
+
+ while ( Value = (PREGISTRY_VALUE_ENTRY)(Iterator->GetNext() ) ) {
+
+ if ( Value->GetData( &Data ) ) {
+
+ if ( PortName.Initialize( (PWSTR)Data ) ) {
+
+ if ( !DeviceName.Stricmp( &PortName ) ) {
+
+ Valid = TRUE;
+
+ break;
+ }
+ }
+ }
+ }
+
+ DELETE( Iterator );
+ }
+ }
+
+ if ( DevicePathPointer ) {
+
+ *DevicePathPointer = NEW PATH;
+ (*DevicePathPointer)->Initialize( &DeviceName );
+ }
+
+ }
+
+ return Valid;
+}
diff --git a/private/utils/mode/com.hxx b/private/utils/mode/com.hxx
new file mode 100644
index 000000000..e0a7389ce
--- /dev/null
+++ b/private/utils/mode/com.hxx
@@ -0,0 +1,141 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ com.hxx
+
+Abstract:
+
+ Header specific to COM
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 26-Jun-1991
+
+
+Revision History:
+
+
+--*/
+
+#include "comm.hxx"
+#include "string.hxx"
+
+
+
+//
+// Registry key with the names of the serial ports
+//
+#define COMM_KEY_NAME "HARDWARE\\DEVICEMAP\\SERIALCOMM"
+
+
+//
+// Data for request type REQUEST_TYPE_COM_SET
+//
+typedef struct _REQUEST_DATA_COM_SET {
+
+ //
+ // These flags tell what options to set
+ //
+ BOOLEAN SetBaud;
+ BOOLEAN SetDataBits;
+ BOOLEAN SetStopBits;
+ BOOLEAN SetParity;
+ BOOLEAN SetRetry;
+ BOOLEAN SetTimeOut;
+ BOOLEAN SetXon;
+ BOOLEAN SetOdsr;
+ BOOLEAN SetIdsr;
+ BOOLEAN SetOcts;
+ BOOLEAN SetDtrControl;
+ BOOLEAN SetRtsControl;
+
+ //
+ // The values
+ //
+ ULONG Baud; // Baud rate
+ ULONG DataBits; // Number of data bits
+ STOPBITS StopBits; // Number of stop bits
+ PARITY Parity; // Parity
+ WCHAR Retry; // Retry
+ BOOLEAN TimeOut; // TimeOut
+ BOOLEAN Xon; // XON/XOFF protocol enabled/disabled
+ BOOLEAN Odsr; // DSR Handshaking
+ BOOLEAN Idsr; // DSR Sensitivity
+ BOOLEAN Octs; // CTS Handshaking
+ DTR_CONTROL DtrControl; // DTR Control
+ RTS_CONTROL RtsControl; // RTS Control
+
+} REQUEST_DATA_COM_SET, *PREQUEST_DATA_COM_SET;
+
+
+//
+// Data for requests to COM
+//
+typedef union _COM_REQUEST_DATA {
+
+ REQUEST_DATA_COM_SET Set;
+
+} COM_REQUEST_DATA, *PCOM_REQUEST_DATA;
+
+
+
+//
+// Structure of a request to COM
+//
+typedef struct _COM_REQUEST {
+
+ REQUEST_HEADER Header; // Request Header
+ COM_REQUEST_DATA Data; // Request data
+
+} COM_REQUEST, *PCOM_REQUEST;
+
+
+
+
+
+//
+// Prototypes
+//
+LONG
+ConvertBaudRate (
+ IN LONG BaudIn
+ );
+
+LONG
+ConvertDataBits (
+ IN LONG DataBitsIn
+ );
+
+STOPBITS
+ConvertStopBits (
+ IN LONG StopBitsIn
+ );
+
+PARITY
+ConvertParity (
+ IN WCHAR ParityIn
+ );
+
+WCHAR
+ConvertRetry (
+ IN WCHAR RetryIn
+ );
+
+
+DTR_CONTROL
+ConvertDtrControl (
+ IN PCWSTRING CmdLine,
+ IN CHNUM IdxBegin,
+ IN CHNUM IdxEnd
+ );
+
+
+RTS_CONTROL
+ConvertRtsControl (
+ IN PCWSTRING CmdLine,
+ IN CHNUM IdxBegin,
+ IN CHNUM IdxEnd
+ );
diff --git a/private/utils/mode/common.cxx b/private/utils/mode/common.cxx
new file mode 100644
index 000000000..220205036
--- /dev/null
+++ b/private/utils/mode/common.cxx
@@ -0,0 +1,345 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Common
+
+Abstract:
+
+ Takes care of request which are common to all devices.
+
+ Also contains any function which is common to two or more devices.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 26-Jun-1991
+
+Revision History:
+
+--*/
+
+#define _NTAPI_ULIB_
+
+#include "mode.hxx"
+#include "common.hxx"
+#include "com.hxx"
+#include "array.hxx"
+#include "arrayit.hxx"
+#include "stream.hxx"
+#include "system.hxx"
+#include "redir.hxx"
+#include "registry.hxx"
+#include "regvalue.hxx"
+
+
+
+BOOLEAN
+CommonHandler(
+ IN PREQUEST_HEADER Request
+ )
+
+/*++
+
+Routine Description:
+
+ Calls all the device handlers with the supplied request.
+
+Arguments:
+
+ Request - Supplies pointer to request
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+
+ ULONG Device; // Current device
+ REDIR_STATUS Status;
+ PPATH DevicePath;
+ REGISTRY Registry;
+ DSTRING ParentName;
+ DSTRING KeyName;
+ ARRAY ValueArray;
+ PARRAY_ITERATOR Iterator;
+ ULONG ErrorCode;
+ PCBYTE Data;
+ DSTRING PortName;
+ DSTRING QualifiedName;
+ PREGISTRY_VALUE_ENTRY Value;
+
+
+ DebugPtrAssert( Request );
+ DebugAssert( Request->DeviceType == DEVICE_TYPE_ALL );
+
+ //
+ // If this is not a null request, then we pass this request to all
+ // device handlers. Note that this means that a device handler must
+ // NOT modify the request, otherwise the next device handler would
+ // get a corrupted request.
+ //
+ if ( Request->RequestType != REQUEST_TYPE_NULL ) {
+
+ //
+ // LPT devices
+ //
+ for ( Device = 1; Device <= LAST_LPT; Device++ ) {
+
+ if ( IsAValidLptDevice( DEVICE_TYPE_LPT, Device, &DevicePath ) ||
+ REDIR::IsRedirected( &Status, DevicePath )
+ ) {
+
+ Request->DeviceType = DEVICE_TYPE_LPT;
+ Request->DeviceNumber = Device;
+
+ //
+ // Have it serviced
+ //
+ DeviceHandler[ DEVICE_TYPE_LPT ]( Request );
+ DELETE( DevicePath );
+ }
+ }
+
+
+ //
+ // COM devices
+ //
+ if ( ParentName.Initialize( "" ) &&
+ KeyName.Initialize( COMM_KEY_NAME ) &&
+ ValueArray.Initialize() &&
+ Registry.Initialize() &&
+ Registry.QueryValues(
+ PREDEFINED_KEY_LOCAL_MACHINE,
+ &ParentName,
+ &KeyName,
+ &ValueArray,
+ &ErrorCode
+ ) ) {
+
+ if ( Iterator = (PARRAY_ITERATOR)ValueArray.QueryIterator() ) {
+
+ while ( Value = (PREGISTRY_VALUE_ENTRY)(Iterator->GetNext() ) ) {
+
+ if ( Value->GetData( &Data ) ) {
+
+ if ( PortName.Initialize( (PWSTR)Data ) &&
+ QualifiedName.Initialize( L"\\\\.\\" ) &&
+ QualifiedName.Strcat( &PortName ) ) {
+
+ if ( SYSTEM::QueryFileType( &QualifiedName ) == CharFile ) {
+
+ Request->DeviceType = DEVICE_TYPE_COM;
+ Request->DeviceName = &PortName;
+
+ DeviceHandler[ DEVICE_TYPE_COM ]( Request );
+
+ }
+ }
+ }
+ }
+
+ DELETE( Iterator );
+ }
+ }
+
+ //
+ // CON device
+ //
+ Request->DeviceType = DEVICE_TYPE_CON;
+ Request->DeviceNumber = 1;
+ DeviceHandler[ DEVICE_TYPE_CON ]( Request );
+
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+IsAValidDevice (
+ IN DEVICE_TTYPE DeviceType,
+ IN ULONG DeviceNumber,
+ OUT PPATH *DevicePathPointer
+ )
+
+/*++
+
+Routine Description:
+
+ Determines if a certain device exists and optionally creates a path
+ for the device.
+
+Arguments:
+
+ DeviceType - Supplies the type of device
+ DeviceNumber - Supplies the device number
+ DeviceName - Supplies a pointer to a pointer to the path for
+ the device.
+
+Return Value:
+
+ BOOLEAN - TRUE if the device exists,
+ FALSE otherwise.
+
+Notes:
+
+--*/
+
+{
+ DSTRING DeviceName;
+ DSTRING QualifiedDeviceName;
+ DSTRING Number;
+ CHNUM Index;
+ FILE_TYPE DriveType;
+ PPATH DevicePath;
+
+
+ //
+ // Determine what device we're working with.
+ //
+ switch ( DeviceType ) {
+
+ case DEVICE_TYPE_COM:
+ DeviceName.Initialize("COM#");
+ break;
+
+ case DEVICE_TYPE_LPT:
+ DeviceName.Initialize("LPT#");
+ break;
+
+ case DEVICE_TYPE_CON:
+ DeviceName.Initialize("CON");
+ break;
+
+ default:
+ DebugAssert( FALSE );
+
+ }
+
+ //
+ // All devices (except the console) have a device number
+ //
+ if ( DeviceType != DEVICE_TYPE_CON ) {
+
+ //
+ // Get the device number in string form
+ //
+ Number.Initialize( DeviceNumber );
+
+ //
+ // Now substitute the matchnumber character with the number
+ //
+ Index = DeviceName.Strchr( '#' );
+ DebugAssert( Index != INVALID_CHNUM );
+
+ DeviceName.Replace( Index, 1, &Number );
+
+ }
+
+ //
+ // We have the device name, gets its type.
+ //
+ QualifiedDeviceName.Initialize( "\\\\.\\" );
+ QualifiedDeviceName.Strcat( &DeviceName );
+
+ DriveType = SYSTEM::QueryFileType( &QualifiedDeviceName );
+
+ //
+ // If the caller wants a path, make it.
+ //
+ if ( DevicePathPointer ) {
+
+ DevicePath = NEW PATH;
+ DebugPtrAssert( DevicePath );
+
+ if ( DevicePath ) {
+
+ DevicePath->Initialize( &DeviceName );
+
+ }
+
+ *DevicePathPointer = DevicePath;
+ }
+
+ //
+ // Now return whether the device is valid or not
+ //
+ return DriveType == CharFile;
+
+}
+
+BOOLEAN
+WriteStatusHeader (
+ IN PCPATH DevicePath
+ )
+
+/*++
+
+Routine Description:
+
+ Write the header for a status block.
+
+Arguments:
+
+ DevicePath - Supplies the device path
+
+Return Value:
+
+ BOOLEAN - TRUE if header written
+ FALSE otherwise.
+
+Notes:
+
+--*/
+
+{
+
+ PWSTRING Header;
+ CHNUM Index;
+
+ Header = QueryMessageString( MODE_MESSAGE_STATUS );
+
+ if ( !Header ) {
+
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY, NULL, (ULONG)EXIT_ERROR );
+
+ }
+
+ //
+ // Replace the match-all character in the header with the device
+ // path.
+ //
+ Index = Header->Strchr( '*' );
+ DebugAssert( Index != INVALID_CHNUM );
+
+ Header->Replace( Index, 1, DevicePath->GetPathString() );
+
+ //
+ // Display the header
+ //
+ Get_Standard_Output_Stream()->WriteChar( '\r' );
+ Get_Standard_Output_Stream()->WriteChar( '\n' );
+ Get_Standard_Output_Stream()->WriteString( Header );
+ Get_Standard_Output_Stream()->WriteChar( '\r' );
+ Get_Standard_Output_Stream()->WriteChar( '\n' );
+
+ //
+ // Underline it
+ //
+ for (Index = 0; Index < Header->QueryChCount(); Index++) {
+ Header->SetChAt( '-', Index );
+ }
+ Get_Standard_Output_Stream()->WriteString( Header );
+ Get_Standard_Output_Stream()->WriteChar( '\r' );
+ Get_Standard_Output_Stream()->WriteChar( '\n' );
+
+ DELETE( Header );
+
+ return TRUE;
+
+}
diff --git a/private/utils/mode/common.hxx b/private/utils/mode/common.hxx
new file mode 100644
index 000000000..e5bd203af
--- /dev/null
+++ b/private/utils/mode/common.hxx
@@ -0,0 +1,68 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ common.hxx
+
+Abstract:
+
+ Description of request data that is common to 2 or more devices.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 26-Jun-1991
+
+
+Revision History:
+
+
+--*/
+
+#include "string.hxx"
+
+
+//
+// Data for request type REQUEST_TYPE_CODEPAGE_PREPARE
+//
+typedef struct _REQUEST_DATA_CODEPAGE_PREPARE {
+
+ PWSTRING CodepageInfo; // String describing the codepage
+
+} REQUEST_CODEPAGE_PREPARE, *PREQUEST_CODEPAGE_PREPARE;
+
+
+
+//
+// Data for request type REQUEST_TYPE_CODEPAGE_SELECT
+//
+typedef struct _REQUEST_DATA_CODEPAGE_SELECT {
+
+ DWORD Codepag; // The codepage
+
+} REQUEST_CODEPAGE_SELECT, *PREQUEST_CODEPAGE_SELECT;
+
+
+
+//
+// Data for requests common to various devices
+//
+typedef union _COMMON_REQUEST_DATA {
+
+ REQUEST_CODEPAGE_PREPARE Prepare;
+ REQUEST_CODEPAGE_SELECT Select;
+
+} COMMON_REQUEST_DATA, *PCOMMON_REQUEST_DATA;
+
+
+
+//
+// Structure of a request common to 2 or more devices
+//
+typedef struct _COMMON_REQUEST {
+
+ REQUEST_HEADER Header; // Request Header
+ COMMON_REQUEST_DATA Data; // Data
+
+} COMMON_REQUEST, *PCOMMON_REQUEST;
diff --git a/private/utils/mode/cons.cxx b/private/utils/mode/cons.cxx
new file mode 100644
index 000000000..3dc07c820
--- /dev/null
+++ b/private/utils/mode/cons.cxx
@@ -0,0 +1,460 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Con
+
+Abstract:
+
+ Takes care of request involving the console ( CON: )
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 26-Jun-1991
+
+Notes:
+
+ This module issues direct calls to USER, because having ULIB doing
+ so causes programs to crash.
+
+Revision History:
+
+--*/
+
+
+#include "mode.hxx"
+#include "cons.hxx"
+#include "keyboard.hxx"
+#include "path.hxx"
+#include "screen.hxx"
+#include "stream.hxx"
+#include "system.hxx"
+
+//
+// Local prototypes
+//
+BOOLEAN
+ConStatus(
+ IN PREQUEST_HEADER Request,
+ IN BOOLEAN JustCodePage
+ );
+
+BOOLEAN
+ConCodePage(
+ IN PREQUEST_HEADER Request
+ );
+
+BOOLEAN
+ConSetRowCol(
+ IN PREQUEST_HEADER Request
+ );
+
+BOOLEAN
+ConSetTypematic(
+ IN PREQUEST_HEADER Request
+ );
+
+
+
+
+BOOLEAN
+ConHandler(
+ IN PREQUEST_HEADER Request
+ )
+
+/*++
+
+Routine Description:
+
+ Handles console requests
+
+Arguments:
+
+ Request - Supplies pointer to request
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+
+ BOOLEAN Served = TRUE; // TRUE if request served OK.
+
+ DebugPtrAssert( Request );
+ DebugAssert( Request->DeviceType == DEVICE_TYPE_CON );
+
+ //
+ // So the device is valid. Now serve the request
+ //
+ switch( Request->RequestType ) {
+
+ case REQUEST_TYPE_STATUS:
+
+ //
+ // Display state of CON device
+ //
+ Served = ConStatus( Request, FALSE );
+ break;
+
+ case REQUEST_TYPE_CODEPAGE_PREPARE:
+ case REQUEST_TYPE_CODEPAGE_SELECT:
+ case REQUEST_TYPE_CODEPAGE_REFRESH:
+
+ //
+ // Handle Codepage requests
+ //
+ Served = ConCodePage( Request );
+ break;
+
+ case REQUEST_TYPE_CODEPAGE_STATUS:
+
+ //
+ // Display codepage status
+ //
+ Served = ConStatus( Request, TRUE );
+ break;
+
+ case REQUEST_TYPE_CON_SET_ROWCOL:
+
+ //
+ // Set rows & columns
+ //
+ Served = ConSetRowCol( Request );
+ break;
+
+ case REQUEST_TYPE_CON_SET_TYPEMATIC:
+
+ //
+ // Set typematic rate
+ //
+ Served = ConSetTypematic( Request );
+ break;
+
+ default:
+
+ DisplayMessageAndExit( MODE_ERROR_INVALID_PARAMETER,
+ NULL,
+ (ULONG)EXIT_ERROR );
+
+ }
+
+ return Served;
+
+
+}
+
+BOOLEAN
+ConStatus(
+ IN PREQUEST_HEADER Request,
+ IN BOOLEAN JustCodePage
+ )
+
+/*++
+
+Routine Description:
+
+ Displays status of a console
+
+Arguments:
+
+ Request - Supplies pointer to request
+ JustCodePage- Supplies a flag which if TRUE means that only
+ the codepage status should be displayed.
+
+Return Value:
+
+ BOOLEAN - TRUE if status displayed successfully,
+ FALSE otherwise
+
+Notes:
+
+--*/
+
+{
+
+ SCREEN Screen;
+
+ PATH ConPath;
+
+ USHORT Rows;
+ USHORT Cols;
+
+ ULONG Delay = 0;
+ ULONG Speed = 0;
+
+ DSTRING CodepageName;
+
+ ULONG Language;
+ ULONG Country;
+ ULONG Codepage;
+
+ DSTRING CodepageString;
+ PSTR S1, S2;
+
+
+ if ( !ConPath.Initialize( (LPWSTR)L"CON" ) ) {
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY, NULL, (ULONG)EXIT_ERROR );
+ }
+
+ //
+ // Write the Header
+ //
+ WriteStatusHeader( &ConPath );
+
+ if ( !Screen.Initialize() ) {
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY, NULL, (ULONG)EXIT_ERROR );
+ }
+
+ if ( !JustCodePage ) {
+
+ //
+ // Display non-codepage information
+ //
+
+ Screen.QueryScreenSize( &Rows, &Cols );
+
+ Message->Set( MODE_MESSAGE_STATUS_LINES );
+ Message->Display( "%d", Rows );
+
+ Message->Set( MODE_MESSAGE_STATUS_COLS );
+ Message->Display( "%d", Cols );
+
+ if (!SystemParametersInfo( SPI_GETKEYBOARDSPEED, 0, (PVOID)&Speed, 0 )) {
+ ExitWithError( GetLastError() );
+ }
+ Message->Set( MODE_MESSAGE_STATUS_RATE );
+ Message->Display( "%d", Speed );
+
+ if (!SystemParametersInfo( SPI_GETKEYBOARDDELAY, 0, (PVOID)&Delay, 0 )) {
+ ExitWithError( GetLastError() );
+ }
+
+ Message->Set( MODE_MESSAGE_STATUS_DELAY );
+ Message->Display( "%d", Delay );
+
+
+ }
+
+ Message->Set( MODE_MESSAGE_STATUS_CODEPAGE );
+ Message->Display( "%d", Screen.QueryCodePage( ) );
+
+ Get_Standard_Output_Stream()->WriteChar( '\r' );
+ Get_Standard_Output_Stream()->WriteChar( '\n' );
+
+ return TRUE;
+}
+
+BOOLEAN
+ConCodePage(
+ IN PREQUEST_HEADER Request
+ )
+
+/*++
+
+Routine Description:
+
+ Handles Codepage requests for the console
+
+Arguments:
+
+ Request - Supplies pointer to request
+
+Return Value:
+
+ BOOLEAN - TRUE if request handled successfully,
+ FALSE otherwise
+
+Notes:
+
+--*/
+
+{
+ SCREEN Screen;
+ PREQUEST_DATA_CON_CODEPAGE_SELECT Data;
+
+
+ //
+ // We only process Codepage Select requests, all other requests
+ // are No-Ops. Note that the Codepage Status request is not
+ // processed here.
+ //
+ if ( Request->RequestType == REQUEST_TYPE_CODEPAGE_SELECT ) {
+
+ Data = (PREQUEST_DATA_CON_CODEPAGE_SELECT)&(((PCON_REQUEST)Request)->
+ Data.CpSelect);
+
+ if ( !Screen.Initialize() ) {
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY, NULL, (ULONG)EXIT_ERROR );
+ }
+
+ if ( !Screen.SetCodePage( Data->Codepage ) ||
+ !Screen.SetOutputCodePage( Data->Codepage) ) {
+ DisplayMessageAndExit( MODE_ERROR_INVALID_CODEPAGE, NULL, (ULONG)EXIT_ERROR );
+ }
+
+#ifdef JAPAN // ConCodePage()
+ // In above path, the console input/output codepage has been changed,
+ // we also need to locale data in thread information to get correct
+ // message data from resource.
+
+ if ( Data->Codepage == 932 ) {
+ SetThreadLocale(
+ MAKELCID(
+ MAKELANGID( LANG_JAPANESE, SUBLANG_ENGLISH_US ),
+ SORT_DEFAULT
+ )
+ );
+ } else {
+ SetThreadLocale(
+ MAKELCID(
+ MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ),
+ SORT_DEFAULT
+ )
+ );
+ }
+#endif // JAPAN
+
+ ConStatus( Request, FALSE );
+
+ } else {
+
+ DisplayMessageAndExit( MODE_MESSAGE_NOT_NEEDED, NULL, EXIT_SUCCESS );
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+ConSetRowCol(
+ IN PREQUEST_HEADER Request
+ )
+
+/*++
+
+Routine Description:
+
+ Sets number of rows and columns in the console window.
+
+
+Arguments:
+
+ Request - Supplies pointer to request
+
+Return Value:
+
+ BOOLEAN - TRUE if Number of Rows & Columns set successfully,
+ FALSE otherwise
+
+Notes:
+
+--*/
+
+{
+
+ PREQUEST_DATA_CON_ROWCOL Data;
+
+ SCREEN Screen;
+
+ USHORT Rows;
+ USHORT Cols;
+ BOOLEAN IsFullScreen;
+
+
+ DebugPtrAssert( Request);
+
+ Data = (PREQUEST_DATA_CON_ROWCOL)&(((PCON_REQUEST)Request)->Data.RowCol);
+
+ if ( !Screen.Initialize() ) {
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY, NULL, (ULONG)EXIT_ERROR );
+ }
+
+ if ( !Data->SetCol || !Data->SetLines ) {
+
+ //
+ // Since we don't have both values, take the current ones.
+ //
+ Screen.QueryScreenSize( &Rows, &Cols );
+ }
+
+ //
+ // Set the number of rows and columns
+ //
+ if ( Data->SetCol ) {
+
+ Cols = (USHORT)Data->Col;
+
+ }
+
+ if ( Data->SetLines ) {
+
+ Rows = (USHORT)Data->Lines;
+
+ }
+
+ if ( !Screen.ChangeScreenSize( Rows, Cols, &IsFullScreen ) ) {
+
+ //
+ // Cannot change the screen size
+ //
+ if ( IsFullScreen ) {
+ DisplayMessageAndExit( MODE_ERROR_FULL_SCREEN, NULL, (ULONG)EXIT_ERROR );
+ } else {
+ DisplayMessageAndExit( MODE_ERROR_INVALID_SCREEN_SIZE, NULL, (ULONG)EXIT_ERROR );
+ }
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+ConSetTypematic(
+ IN PREQUEST_HEADER Request
+ )
+
+/*++
+
+Routine Description:
+
+ Sets thje typematic rate
+
+Arguments:
+
+ DevicePath - Supplies pointer to path of device
+ Request - Supplies pointer to request
+
+Return Value:
+
+ BOOLEAN - TRUE if typematic rate set successfully,
+ FALSE otherwise
+
+Notes:
+
+--*/
+
+{
+ PREQUEST_DATA_CON_TYPEMATIC Data;
+
+ DebugPtrAssert( Request);
+
+
+ Data = (PREQUEST_DATA_CON_TYPEMATIC)&(((PCON_REQUEST)Request)->Data.Typematic);
+
+ if ( Data->SetRate ) {
+ if (!SystemParametersInfo( SPI_SETKEYBOARDSPEED, (UINT)Data->Rate, NULL, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE )) {
+ DisplayMessageAndExit( MODE_ERROR_INVALID_RATE, NULL, (ULONG)EXIT_ERROR);
+ }
+ }
+ if ( Data->SetDelay ) {
+ if (!SystemParametersInfo( SPI_SETKEYBOARDDELAY, (UINT)Data->Delay, NULL, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE )) {
+ DisplayMessageAndExit( MODE_ERROR_INVALID_DELAY, NULL, (ULONG)EXIT_ERROR);
+ }
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/mode/cons.hxx b/private/utils/mode/cons.hxx
new file mode 100644
index 000000000..3fc24c4d4
--- /dev/null
+++ b/private/utils/mode/cons.hxx
@@ -0,0 +1,90 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ com.hxx
+
+Abstract:
+
+ Header specific to the console ( CON: )
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 26-Jun-1991
+
+
+Revision History:
+
+
+--*/
+
+
+//
+// Data for request type REQUEST_TYPE_CON_ROWCOL
+//
+typedef struct _REQUEST_DATA_CON_ROWCOL {
+ //
+ // These flags tell what options to set
+ //
+ BOOLEAN SetCol;
+ BOOLEAN SetLines;
+ //
+ // These are the options
+ //
+ ULONG Col; // Number of columns
+ ULONG Lines; // Number of lines (rows)
+
+} REQUEST_DATA_CON_ROWCOL, *PREQUEST_DATA_CON_ROWCOL;
+
+
+//
+// Data for request type REQUEST_TYPE_CON_TYPEMATIC
+//
+typedef struct _REQUEST_DATA_CON_TYPEMATIC {
+ //
+ // These flags tell what options to set
+ //
+ BOOLEAN SetRate;
+ BOOLEAN SetDelay;
+ //
+ // Options
+ //
+ LONG Rate; // Rate value
+ LONG Delay; // Delay value
+
+} REQUEST_DATA_CON_TYPEMATIC, *PREQUEST_DATA_CON_TYPEMATIC;
+
+//
+// Data for request type REQUEST_TYPE_CODEPAGE_SELECT
+//
+typedef struct _REQUEST_DATA_CON_CODEPAGE_SELECT {
+
+ ULONG Codepage; // CodePage
+
+} REQUEST_DATA_CON_CODEPAGE_SELECT, *PREQUEST_DATA_CON_CODEPAGE_SELECT;
+
+
+//
+// Data for requests to CON
+//
+typedef union _CON_REQUEST_DATA {
+
+ REQUEST_DATA_CON_ROWCOL RowCol;
+ REQUEST_DATA_CON_TYPEMATIC Typematic;
+ REQUEST_DATA_CON_CODEPAGE_SELECT CpSelect;
+
+} CON_REQUEST_DATA, *PCON_REQUEST_DATA;
+
+
+
+//
+// Structure of a request to CON
+//
+typedef struct _CON_REQUEST {
+
+ REQUEST_HEADER Header; // Request Header
+ CON_REQUEST_DATA Data; // Request data
+
+} CON_REQUEST, *PCON_REQUEST;
diff --git a/private/utils/mode/lpt.cxx b/private/utils/mode/lpt.cxx
new file mode 100644
index 000000000..07ad6f944
--- /dev/null
+++ b/private/utils/mode/lpt.cxx
@@ -0,0 +1,664 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Lpt
+
+Abstract:
+
+ Takes care of request involving an LPT device
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 26-Jun-1991
+
+Revision History:
+
+--*/
+
+
+#define _NTAPI_ULIB_
+
+#include "mode.hxx"
+#include "lpt.hxx"
+#include "file.hxx"
+#include "path.hxx"
+#include "stream.hxx"
+#include "redir.hxx"
+#include "registry.hxx"
+#include "regvalue.hxx"
+#include "array.hxx"
+#include "arrayit.hxx"
+
+//
+// When an LPT port is set, mode only sends it an EPSON/IBM sequence.
+// The following macros define the EPSON sequences used.
+//
+#define CODE_ESCAPE 0x27
+#define CODE_COLS_80 0x18
+#define CODE_COLS_132 0x15
+#define CODE_LINES_6 '2'
+#define CODE_LINES_8 '0'
+
+#undef LAST_COM
+#define LAST_COM 4
+
+
+//
+// Local prototypes
+//
+BOOLEAN
+LptStatus(
+ IN PCPATH DevicePath,
+ IN PREQUEST_HEADER Request
+ );
+
+BOOLEAN
+LptCodePage(
+ IN PCPATH DevicePath,
+ IN PREQUEST_HEADER Request
+ );
+
+BOOLEAN
+LptSetup(
+ IN PCPATH DevicePath,
+ IN PREQUEST_HEADER Request
+ );
+
+BOOLEAN
+LptRedirect(
+ IN PCPATH DevicePath,
+ IN PREQUEST_HEADER Request
+ );
+
+BOOLEAN
+LptEndRedir(
+ IN PCPATH DevicePath,
+ IN PREQUEST_HEADER Request
+ );
+
+PPATH
+GetRedirection(
+ IN PCPATH DevicePath,
+ OUT PREDIR_STATUS RedirStatus
+ );
+
+
+
+BOOLEAN
+IsAValidLptDevice (
+ IN DEVICE_TTYPE DeviceType,
+ IN ULONG DeviceNumber,
+ OUT PPATH *DevicePathPointer
+ )
+
+/*++
+
+Routine Description:
+
+ Determines if a certain comm device exists and optionally
+ creates a path for it.
+
+Arguments:
+
+ DeviceType - Supplies the type of device
+ DeviceNumber - Supplies the device number
+ DeviceName - Supplies a pointer to a pointer to the path for
+ the device.
+
+Return Value:
+
+ BOOLEAN - TRUE if the device exists,
+ FALSE otherwise.
+
+Notes:
+
+--*/
+
+{
+ DSTRING DeviceName;
+ DSTRING AlternateName;
+ DSTRING Number;
+ BOOLEAN Valid = FALSE;
+ REGISTRY Registry;
+ DSTRING ParentName;
+ DSTRING KeyName;
+ ARRAY ValueArray;
+ PARRAY_ITERATOR Iterator;
+ ULONG ErrorCode;
+ PCBYTE Data;
+ DSTRING PortName;
+ PREGISTRY_VALUE_ENTRY Value;
+
+
+ UNREFERENCED_PARAMETER( DeviceType );
+
+
+ if ( DeviceName.Initialize( (LPWSTR)L"LPT" )&&
+ Number.Initialize( DeviceNumber ) &&
+ DeviceName.Strcat( &Number ) &&
+ AlternateName.Initialize( (LPWSTR)L"\\DosDevices\\" ) &&
+ AlternateName.Strcat( &DeviceName ) &&
+ ParentName.Initialize( "" ) &&
+ KeyName.Initialize( LPT_KEY_NAME ) &&
+ ValueArray.Initialize() &&
+ Registry.Initialize()
+ ) {
+
+
+ //
+ // Get the names of all the serial ports
+ //
+ if ( Registry.QueryValues(
+ PREDEFINED_KEY_LOCAL_MACHINE,
+ &ParentName,
+ &KeyName,
+ &ValueArray,
+ &ErrorCode
+ ) ) {
+
+ //
+ // See if the given name matches any of the serial ports
+ //
+ if ( Iterator = (PARRAY_ITERATOR)ValueArray.QueryIterator() ) {
+
+ while ( Value = (PREGISTRY_VALUE_ENTRY)(Iterator->GetNext() ) ) {
+
+ if ( Value->GetData( &Data ) ) {
+
+ if ( PortName.Initialize( (PWSTR)Data ) ) {
+
+ if ( !DeviceName.Stricmp( &PortName ) ||
+ !AlternateName.Stricmp( &PortName ) ) {
+
+ Valid = TRUE;
+
+ break;
+ }
+ }
+ }
+ }
+
+ DELETE( Iterator );
+ }
+ }
+
+ if ( DevicePathPointer ) {
+
+ *DevicePathPointer = NEW PATH;
+ (*DevicePathPointer)->Initialize( &DeviceName );
+ }
+
+ }
+
+ return Valid;
+}
+
+
+
+
+
+
+BOOLEAN
+LptHandler(
+ IN PREQUEST_HEADER Request
+ )
+
+/*++
+
+Routine Description:
+
+ Handles LPT requests
+
+Arguments:
+
+ Request - Supplies pointer to request
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ PPATH DevicePath; // Name of Device
+ BOOLEAN Served = TRUE; // TRUE if request served OK.
+ REDIR_STATUS Status;
+
+ DebugPtrAssert( Request );
+ DebugAssert( Request->DeviceType == DEVICE_TYPE_LPT );
+
+ //
+ // Make sure that the device exists, and at the same time get its
+ // name ( For calling APIs ).
+ //
+ if ( Request->DeviceName ) {
+
+ DevicePath = NEW PATH;
+ DevicePath->Initialize( Request->DeviceName );
+
+ } else if ( (!IsAValidLptDevice( Request->DeviceType, Request->DeviceNumber, &DevicePath ) &&
+ Request->RequestType != REQUEST_TYPE_LPT_REDIRECT &&
+ !REDIR::IsRedirected( &Status, DevicePath )) ||
+ Request->DeviceNumber > LAST_LPT ) {
+ DisplayMessageAndExit( MODE_ERROR_INVALID_DEVICE_NAME,
+ DevicePath->GetPathString(),
+ (ULONG)EXIT_ERROR );
+ }
+
+ //
+ // So the device is valid. Now serve the request
+ //
+ switch( Request->RequestType ) {
+
+
+ case REQUEST_TYPE_STATUS:
+
+ //
+ // Display State of device
+ //
+ Served = LptStatus( DevicePath, Request );
+ break;
+
+ case REQUEST_TYPE_CODEPAGE_PREPARE:
+ case REQUEST_TYPE_CODEPAGE_SELECT:
+ case REQUEST_TYPE_CODEPAGE_REFRESH:
+ case REQUEST_TYPE_CODEPAGE_STATUS:
+
+ //
+ // Codepage request
+ //
+ Served = LptCodePage( DevicePath, Request );
+ break;
+
+ case REQUEST_TYPE_LPT_SETUP:
+
+ //
+ // Printer setup
+ //
+ Served = LptSetup( DevicePath, Request );
+ break;
+
+ case REQUEST_TYPE_LPT_REDIRECT:
+
+ //
+ // Redirect LPT to COM
+ //
+ Served = LptRedirect( DevicePath, Request );
+ break;
+
+ case REQUEST_TYPE_LPT_ENDREDIR:
+
+ //
+ // End redirection of LPT
+ //
+ Served = LptEndRedir( DevicePath, Request );
+ break;
+
+ default:
+
+ DisplayMessageAndExit( MODE_ERROR_INVALID_PARAMETER,
+ NULL,
+ (ULONG)EXIT_ERROR );
+
+ }
+
+ DELETE( DevicePath );
+
+ return Served;
+
+}
+
+BOOLEAN
+LptStatus(
+ IN PCPATH DevicePath,
+ IN PREQUEST_HEADER Request
+ )
+
+/*++
+
+Routine Description:
+
+ Displays status if an LPT device
+
+Arguments:
+
+ DevicePath - Supplies pointer to path of device
+ Request - Supplies pointer to request
+
+Return Value:
+
+ BOOLEAN - TRUE if status displayed successfully,
+ FALSE otherwise
+
+Notes:
+
+--*/
+
+{
+
+ UNREFERENCED_PARAMETER( DevicePath );
+ UNREFERENCED_PARAMETER( Request );
+
+ PPATH RedirPath = NULL;
+ REDIR_STATUS RedirStatus;
+
+ RedirPath = GetRedirection( DevicePath, &RedirStatus );
+
+ if ( !RedirPath && (RedirStatus != REDIR_STATUS_NONEXISTENT) ) {
+ //
+ // We cannot find out the status of the redirection.
+ // This is almost certainly due to lack of privileges.
+ // We won't display the LPT status
+ //
+ return TRUE;
+ }
+
+ //
+ // Write the Header
+ //
+ WriteStatusHeader( DevicePath );
+
+
+ if ( !RedirPath ) {
+
+ DisplayMessage( MODE_MESSAGE_STATUS_NOT_REROUTED, NULL );
+
+ } else {
+
+ DisplayMessage( MODE_MESSAGE_STATUS_REROUTED, RedirPath->GetPathString() );
+
+ DELETE( RedirPath );
+ }
+
+ Get_Standard_Output_Stream()->WriteChar( '\r' );
+ Get_Standard_Output_Stream()->WriteChar( '\n' );
+
+ return TRUE;
+}
+
+BOOLEAN
+LptCodePage(
+ IN PCPATH DevicePath,
+ IN PREQUEST_HEADER Request
+ )
+
+/*++
+
+Routine Description:
+
+ Handles Codepage requests for LPT device
+
+Arguments:
+
+ DevicePath - Supplies pointer to path of device
+ Request - Supplies pointer to request
+
+Return Value:
+
+ BOOLEAN - TRUE if request handled successfully,
+ FALSE otherwise
+
+Notes:
+
+--*/
+
+{
+
+ UNREFERENCED_PARAMETER( DevicePath );
+ UNREFERENCED_PARAMETER( Request );
+
+ DisplayMessage( MODE_ERROR_CODEPAGE_OPERATION_NOT_SUPPORTED, NULL );
+
+ return TRUE;
+}
+
+BOOLEAN
+LptSetup(
+ IN PCPATH DevicePath,
+ IN PREQUEST_HEADER Request
+ )
+
+/*++
+
+Routine Description:
+
+ Sets LPT state
+
+Arguments:
+
+ DevicePath - Supplies pointer to path of device
+ Request - Supplies pointer to request
+
+Return Value:
+
+ BOOLEAN - TRUE if state set successfully,
+ FALSE otherwise
+
+Notes:
+
+--*/
+
+{
+
+ PREQUEST_DATA_LPT_SETUP Data;
+ PFSN_FILE Lpt;
+ PFILE_STREAM LptStream;
+
+
+
+ Data = (PREQUEST_DATA_LPT_SETUP)&(((PLPT_REQUEST)Request)->Data.Setup);
+
+ if ( ( Data->SetCol && (Data->Col != 132) && ( Data->Col != 80 ) ) ||
+ ( Data->SetLines && (Data->Lines != 6) && (Data->Lines != 8) ) ) {
+
+ //
+ // Invalid number of lines or columns
+ //
+ DisplayMessageAndExit( MODE_ERROR_LPT_CANNOT_SET, NULL, (ULONG)EXIT_ERROR );
+
+ }
+
+
+ Lpt = SYSTEM::QueryFile( DevicePath );
+ DebugPtrAssert( Lpt );
+
+ if ( Lpt ) {
+ LptStream = Lpt->QueryStream( WRITE_ACCESS );
+ DebugPtrAssert( LptStream );
+ }
+
+ if ( !Lpt || !LptStream ) {
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY, NULL, (ULONG)EXIT_ERROR );
+ }
+
+ if ( Data->SetCol ) {
+
+ //
+ // Set number of columns. The sequence consists of one byte.
+ //
+ LptStream->WriteByte( (Data->Col == 80) ? CODE_COLS_80 : CODE_COLS_132 );
+ }
+
+ if ( Data->SetLines ) {
+
+ //
+ // Set line spacing. The sequence consists of one escape byte
+ // followed by one CODE_LINES_6 or CODE_LINES 8 byte.
+ //
+ LptStream->WriteByte( CODE_ESCAPE );
+ LptStream->WriteByte( (Data->Lines == 6) ? CODE_LINES_6 : CODE_LINES_8 );
+
+ }
+
+ DELETE( LptStream );
+ DELETE( Lpt );
+
+ return TRUE;
+}
+
+BOOLEAN
+LptRedirect(
+ IN PCPATH DevicePath,
+ IN PREQUEST_HEADER Request
+ )
+
+/*++
+
+Routine Description:
+
+ Redirects LPT to a COMM port.
+
+Arguments:
+
+ DevicePath - Supplies pointer to path of device
+ Request - Supplies pointer to request
+
+Return Value:
+
+ BOOLEAN - TRUE if LPT redirected,
+ FALSE otherwise
+
+Notes:
+
+--*/
+
+{
+
+ PREQUEST_DATA_LPT_REDIRECT Data;
+ PPATH RedirPath;
+
+ Data = (PREQUEST_DATA_LPT_REDIRECT)&(((PLPT_REQUEST)Request)->Data.Redirect);
+
+ //
+ // Verify that the serial device specified is valid
+ //
+ if ( !IsAValidDevice( Data->DeviceType, Data->DeviceNumber, &RedirPath )) {
+
+ DisplayMessageAndExit( MODE_ERROR_INVALID_DEVICE_NAME,
+ RedirPath->GetPathString(),
+ (ULONG)EXIT_ERROR );
+
+ }
+
+ if ( !REDIR::Redirect( DevicePath, RedirPath ) ) {
+
+ DisplayMessageAndExit( MODE_ERROR_LPT_CANNOT_REROUTE, RedirPath->GetPathString(), (ULONG)EXIT_ERROR );
+
+ }
+
+ //
+ // Display the status as confirmation
+ //
+ LptStatus( DevicePath, Request );
+
+ DELETE( RedirPath );
+
+ return TRUE;
+}
+
+
+BOOLEAN
+LptEndRedir (
+ IN PCPATH DevicePath,
+ IN PREQUEST_HEADER Request
+ )
+
+/*++
+
+Routine Description:
+
+ Ends the redirection of an LPT port
+
+Arguments:
+
+ DevicePath - Supplies pointer to path of device
+ Request - Supplies pointer to request
+
+Return Value:
+
+ BOOLEAN - TRUE
+
+Notes:
+
+--*/
+
+{
+
+ REDIR_STATUS Status;
+
+ //
+ // If the LPT is being redirected, end the redirection
+ //
+ if ( REDIR::IsRedirected( &Status, DevicePath ) ) {
+
+ if ( !REDIR::EndRedirection( DevicePath )) {
+
+ DisplayMessageAndExit( MODE_ERROR_LPT_CANNOT_ENDREROUTE, NULL, (ULONG)EXIT_ERROR );
+ }
+ }
+
+ //
+ // Display status
+ //
+ LptStatus( DevicePath, Request );
+
+ return TRUE;
+
+}
+
+PPATH
+GetRedirection(
+ IN PCPATH DevicePath,
+ OUT PREDIR_STATUS RedirStatus
+ )
+
+/*++
+
+Routine Description:
+
+ Determines to what device is the LPT redirected to
+
+Arguments:
+
+ DevicePath - Supplies pointer to path of device
+
+ RedirStatus - Supplies pointer to redirection status
+
+Return Value:
+
+ PPATH - Pointer to the redirected device
+
+--*/
+
+{
+
+ ULONG DeviceNumber = 1;
+ PPATH DestPath = NULL;
+ BOOLEAN ValidDevice = TRUE;
+
+ if ( REDIR::IsRedirected( RedirStatus, DevicePath ) ) {
+
+ for ( DeviceNumber = 1; DeviceNumber <= LAST_COM; DeviceNumber++ ) {
+
+ IsAValidDevice( DEVICE_TYPE_COM, DeviceNumber, &DestPath );
+
+ if ( REDIR::IsRedirected( RedirStatus, DevicePath, DestPath )) {
+
+ break;
+
+ }
+
+ DELETE( DestPath );
+ DestPath = NULL;
+
+ }
+ }
+
+ return DestPath;
+
+}
diff --git a/private/utils/mode/lpt.hxx b/private/utils/mode/lpt.hxx
new file mode 100644
index 000000000..c76beb59c
--- /dev/null
+++ b/private/utils/mode/lpt.hxx
@@ -0,0 +1,95 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ com.hxx
+
+Abstract:
+
+ Header specific to LPT
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 26-Jun-1991
+
+
+Revision History:
+
+
+--*/
+
+
+#include "string.hxx"
+
+
+//
+// Registry key with the names of the serial ports
+//
+#define LPT_KEY_NAME "HARDWARE\\DEVICEMAP\\PARALLEL PORTS"
+
+//
+// Data for request type REQUEST_TYPE_LPT_SETUP
+//
+typedef struct _REQUEST_DATA_LPT_SETUP {
+
+ //
+ // These flags tell what options to set
+ //
+ BOOLEAN SetCol;
+ BOOLEAN SetLines;
+ BOOLEAN SetRetry;
+ //
+ // Options
+ //
+ ULONG Col;
+ ULONG Lines;
+ WCHAR Retry;
+
+} REQUEST_DATA_LPT_SETUP, *PREQUEST_DATA_LPT_SETUP;
+
+
+//
+// Data for request type REQUEST_TYPE_LPT_REDIRECT
+//
+typedef struct _REQUEST_DATA_LPT_REDIRECT {
+
+ DEVICE_TTYPE DeviceType;
+ ULONG DeviceNumber;
+
+} REQUEST_DATA_LPT_REDIRECT, *PREQUEST_DATA_LPT_REDIRECT;
+
+
+//
+// Data for request type REQUEST_TYPE_CODEPAGE_SELECT
+//
+typedef struct _REQUEST_DATA_LPT_CODEPAGE_SELECT {
+
+ ULONG Codepage; // CodePage
+
+} REQUEST_DATA_LPT_CODEPAGE_SELECT, *PREQUEST_DATA_LPT_CODEPAGE_SELECT;
+
+
+//
+// Data for requests to LPT
+//
+typedef union _LPT_REQUEST_DATA {
+
+ REQUEST_DATA_LPT_SETUP Setup;
+ REQUEST_DATA_LPT_REDIRECT Redirect;
+ REQUEST_DATA_LPT_CODEPAGE_SELECT CpSelect;
+
+} LPT_REQUEST_DATA, *PLPT_REQUEST_DATA;
+
+
+
+//
+// Structure of a request to LPT
+//
+typedef struct _LPT_REQUEST {
+
+ REQUEST_HEADER Header; // Request Header
+ LPT_REQUEST_DATA Data; // Request data
+
+} LPT_REQUEST, *PLPT_REQUEST;
diff --git a/private/utils/mode/makefile b/private/utils/mode/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/mode/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/mode/makefile.inc b/private/utils/mode/makefile.inc
new file mode 100644
index 000000000..6c93eb38d
--- /dev/null
+++ b/private/utils/mode/makefile.inc
@@ -0,0 +1,12 @@
+{}.cxx{obj\i386\}.obj:
+ $(386_COMPILER) -Fo$@ $(MAKEDIR)\$(<F)
+
+{}.cxx{obj\mips\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClMips $< " $(C_COMPILER) "
+ @$(C_COMPILER) -Fo$@ $(MAKEDIR)\$<
+
+{}.cxx{obj\alpha\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClAlpha $< " $(ALPHA_COMPILER) "
+ @$(ALPHA_COMPILER) -Fo$@ $(MAKEDIR)\$<
diff --git a/private/utils/mode/mode.cxx b/private/utils/mode/mode.cxx
new file mode 100644
index 000000000..2842591ec
--- /dev/null
+++ b/private/utils/mode/mode.cxx
@@ -0,0 +1,213 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Mode
+
+Abstract:
+
+ Mode utility
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 26-Jun-1991
+
+Revision History:
+
+--*/
+
+
+#include "mode.hxx"
+#include "system.hxx"
+
+
+
+//
+// Message stream
+//
+PSTREAM_MESSAGE Message;
+
+
+//
+// DeviceHandler is an array of pointers to the different device
+// handlers.
+//
+DEVICE_HANDLER DeviceHandler[ NUMBER_OF_DEVICE_TYPES ] = {
+
+ LptHandler,
+ ComHandler,
+ ConHandler,
+ CommonHandler
+
+ };
+
+
+
+
+VOID
+InitializeMode (
+ );
+
+VOID
+DeallocateResources (
+ );
+
+
+PSTREAM
+Get_Standard_Input_Stream();
+
+PSTREAM
+Get_Standard_Output_Stream();
+
+PSTREAM
+Get_Standard_Error_Stream();
+
+
+
+
+
+
+
+VOID _CRTAPI1
+main (
+ )
+
+/*++
+
+Routine Description:
+
+ Main function of the Mode utility
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ PREQUEST_HEADER Request;
+
+ //
+ // Initialize whatever is necessary
+ //
+ InitializeMode();
+
+ //
+ // Verify the OS version
+ //
+ if ( !SYSTEM::IsCorrectVersion() ) {
+
+ DisplayMessageAndExit( MODE_ERROR_INCORRECT_OS_VERSION,
+ NULL,
+ (ULONG)EXIT_ERROR );
+ }
+
+ //
+ // Obtain a request from the command line. Note that the
+ // first field of the request is the device type.
+ //
+ Request = GetRequest();
+ DebugPtrAssert( Request );
+ DebugAssert( Request->DeviceType <= DEVICE_TYPE_ALL );
+
+ //
+ // Let the device handler for the specified type take care of the
+ // request.
+ //
+ DebugPtrAssert( DeviceHandler[ Request->DeviceType ] );
+ DeviceHandler[ Request->DeviceType ]( Request );
+
+ //
+ // Deallocate resources
+ //
+ FREE( Request );
+ DeallocateResources();
+
+ //
+ // We're done
+ //
+ ExitMode( EXIT_SUCCESS );
+
+}
+
+VOID
+InitializeMode (
+ )
+
+/*++
+
+Routine Description:
+
+ Allocates resources and initializes Mode structures
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ if ( //
+ // Construct and initialize a STREAM_MESSAGE.
+ //
+ !(Message = NEW STREAM_MESSAGE ) ||
+ !Message->Initialize( Get_Standard_Output_Stream(),
+ Get_Standard_Input_Stream() )
+ ) {
+
+ //
+ // We don't have Message, so we cannot display the error
+ // text.
+ //
+ exit( EXIT_ERROR );
+ }
+
+ //
+ // Allocate resources which are private to each type of device
+ //
+ ComAllocateStuff();
+
+}
+
+VOID
+DeallocateResources (
+ )
+
+/*++
+
+Routine Description:
+
+ Deallocates resources allocated in InitializeMode
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+
+ DELETE( Message );
+ ComDeAllocateStuff();
+
+}
diff --git a/private/utils/mode/mode.hxx b/private/utils/mode/mode.hxx
new file mode 100644
index 000000000..bb7d5ecff
--- /dev/null
+++ b/private/utils/mode/mode.hxx
@@ -0,0 +1,293 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Mode.hxx
+
+Abstract:
+
+ Header file for the Mode utility
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 26-Jun-1991
+
+
+Revision History:
+
+
+--*/
+
+
+#include "ulib.hxx"
+#include "smsg.hxx"
+#include "wstring.hxx"
+
+#include "rtmsg.h"
+
+
+// ==================================================================
+//
+// Types
+//
+// ==================================================================
+
+
+//
+// Device types
+//
+typedef enum _DEVICE_TTYPE {
+
+ DEVICE_TYPE_LPT = 0,
+ DEVICE_TYPE_COM = 1,
+ DEVICE_TYPE_CON = 2,
+ DEVICE_TYPE_ALL = 3
+
+} DEVICE_TTYPE, *PDEVICE_TTYPE;
+
+
+//
+// Number of device types
+//
+#define NUMBER_OF_DEVICE_TYPES (DEVICE_TYPE_ALL + 1)
+
+#define LAST_LPT 9
+#define LAST_COM 9
+
+
+//
+// Request types
+//
+typedef enum _REQUEST_TYPE {
+
+ //
+ // NULL request (for operations accepted but that are no-ops )
+ //
+ REQUEST_TYPE_NULL,
+
+ //
+ // Requests common to 2 or more devices
+ //
+ REQUEST_TYPE_STATUS,
+ REQUEST_TYPE_CODEPAGE_PREPARE,
+ REQUEST_TYPE_CODEPAGE_SELECT,
+ REQUEST_TYPE_CODEPAGE_REFRESH,
+ REQUEST_TYPE_CODEPAGE_STATUS,
+ //
+ // LPT
+ //
+ REQUEST_TYPE_LPT_SETUP,
+ REQUEST_TYPE_LPT_REDIRECT,
+ REQUEST_TYPE_LPT_ENDREDIR,
+ //
+ // COM
+ //
+ REQUEST_TYPE_COM_SET,
+ //
+ // CONSOLE
+ //
+ REQUEST_TYPE_CON_SET_ROWCOL,
+ REQUEST_TYPE_CON_SET_TYPEMATIC
+
+} REQUEST_TYPE, *PREQUEST_TYPE;
+
+
+
+//
+// Request packet header
+//
+typedef struct _REQUEST_HEADER {
+
+ DEVICE_TTYPE DeviceType; // Device type
+ LONG DeviceNumber; // Device number
+ PWSTRING DeviceName; // Optional device name
+ REQUEST_TYPE RequestType; // Request type
+
+} REQUEST_HEADER, *PREQUEST_HEADER;
+//
+// ALL_DEVICES is a magic DeviceNumber that means "all devices available
+// of this type"
+//
+#define ALL_DEVICES ((LONG)-1)
+
+
+//
+// Device handler. A device handler is the function that takes care of
+// handling all requests for a device. There is one per device type.
+//
+typedef BOOLEAN( *DEVICE_HANDLER )( IN PREQUEST_HEADER Request );
+
+
+
+// ==================================================================
+//
+// Macros
+//
+// ==================================================================
+
+//
+// Exit codes
+//
+#define EXIT_SUCCESS 0
+#define EXIT_ERROR ((int)-1)
+
+
+
+// ==================================================================
+//
+// Global Data
+//
+// ==================================================================
+
+
+//
+// The message stream, for displaying messages
+//
+extern PSTREAM_MESSAGE Message;
+
+
+//
+// DeviceHandler is an array of pointers to the different device
+// handlers.
+//
+extern DEVICE_HANDLER DeviceHandler[];
+
+
+
+// ==================================================================
+//
+// Prototypes
+//
+// ==================================================================
+
+
+//
+// Argument.hxx
+//
+PREQUEST_HEADER
+GetRequest(
+ );
+
+VOID
+ParseError (
+ );
+
+
+//
+// common.cxx
+//
+BOOLEAN
+CommonHandler(
+ IN PREQUEST_HEADER Request
+ );
+
+
+BOOLEAN
+IsAValidDevice (
+ IN DEVICE_TTYPE DeviceType,
+ IN ULONG DeviceNumber,
+ OUT PPATH *DeviceName
+ );
+
+BOOLEAN
+IsAValidLptDevice (
+ IN DEVICE_TTYPE DeviceType,
+ IN ULONG DeviceNumber,
+ OUT PPATH *DeviceName
+ );
+
+BOOLEAN
+IsAValidCommDevice (
+ IN DEVICE_TTYPE DeviceType,
+ IN ULONG DeviceNumber,
+ OUT PPATH *DeviceName
+ );
+
+BOOLEAN
+WriteStatusHeader (
+ IN PCPATH DevicePath
+ );
+
+
+//
+// lpt.cxx
+//
+BOOLEAN
+LptHandler(
+ IN PREQUEST_HEADER Request
+ );
+
+
+//
+// Com.cxx
+//
+BOOLEAN
+ComAllocateStuff(
+ );
+
+BOOLEAN
+ComDeAllocateStuff(
+ );
+
+BOOLEAN
+ComHandler(
+ IN PREQUEST_HEADER Request
+ );
+
+
+
+
+
+//
+// con.cxx
+//
+BOOLEAN
+ConHandler(
+ IN PREQUEST_HEADER Request
+ );
+
+
+//
+// support.cxx
+//
+VOID
+DisplayMessage (
+ IN MSGID MsgId,
+ IN PCWSTRING String
+ );
+
+VOID
+DisplayMessageAndExit (
+ IN MSGID MsgId,
+ IN PCWSTRING String,
+ IN ULONG ExitCode
+ );
+
+PWSTRING
+QueryMessageString (
+ IN MSGID MsgId
+ );
+
+VOID
+ExitWithError(
+ IN DWORD ErrorCode
+ );
+
+VOID
+ExitMode(
+ IN DWORD ExitCode
+ );
+
+
+
+
+PSTREAM
+Get_Standard_Input_Stream();
+
+PSTREAM
+Get_Standard_Output_Stream();
+
+PSTREAM
+Get_Standard_Error_Stream();
diff --git a/private/utils/mode/mode.rc b/private/utils/mode/mode.rc
new file mode 100644
index 000000000..fd7cb5909
--- /dev/null
+++ b/private/utils/mode/mode.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "DOS Device MODE Utility"
+#define VER_INTERNALNAME_STR "mode\0"
+#define VER_ORIGINALFILENAME_STR "MODE.COM"
+
+#include "common.ver"
diff --git a/private/utils/mode/redir.cxx b/private/utils/mode/redir.cxx
new file mode 100644
index 000000000..a06d401d5
--- /dev/null
+++ b/private/utils/mode/redir.cxx
@@ -0,0 +1,307 @@
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+#include "path.hxx"
+#include "wstring.hxx"
+#include "redir.hxx"
+
+
+//
+// The string below represents the path used to determine whether or not
+// an LPT device is redirected to a COM device.
+// Due to performance, this path should always be defined in upper case.
+//
+
+#define LPT_REDIRECTION_PATH (LPWSTR)L"\\DOSDEVICES\\COM"
+
+
+
+
+BOOLEAN
+REDIR::Redirect (
+ IN PCPATH Device,
+ IN PCPATH Destination
+ )
+
+/*++
+
+Routine Description:
+
+ Redirects a device. The device is redirected by creating a symbolic link
+ to the destination device. If this is the first redirection of the device,
+ the original symbolic link is saved in the registry under a volatile key
+ so that it can be recovered latter on.
+
+ Note that redirection requires sufficient privileges to create symbolic
+ links and to create entries in the registry under SAVE_ROOT.
+
+Arguments:
+
+ Device - Supplies the device to be redirected.
+
+ Destination - Supplies the device to be redirected to
+
+Return Value:
+
+ BOOLEAN - TRUE if the device was successfully redirected.
+ FALSE otherwise.
+
+--*/
+
+{
+ BOOLEAN Redirected = FALSE;
+ PCWSTRING DeviceName;
+ PCWSTRING DestinationName;
+
+
+ DebugPtrAssert( Device );
+ DebugPtrAssert( Destination );
+
+ if( ( Device != NULL ) &&
+ ( Destination != NULL ) &&
+ ( ( DeviceName = Device->GetPathString() ) != NULL ) &&
+ ( ( DestinationName = Destination->GetPathString() ) != NULL )
+ ) {
+
+ Redirected = DefineDosDevice( 0,
+ DeviceName->GetWSTR(),
+ DestinationName->GetWSTR() );
+
+#if DBG
+ if( !Redirected ) {
+ DebugPrint( "MODE: DefineDosDevice() failed" );
+ DebugPrintf( "MODE: DefineDosDevice() failed, Device = %ls, Destination = %ls, Error = %d \n",
+ DeviceName->GetWSTR(),
+ DestinationName->GetWSTR(),
+ GetLastError() );
+ }
+#endif
+
+ }
+ return Redirected;
+}
+
+
+
+
+BOOLEAN
+REDIR::IsRedirected (
+ OUT PREDIR_STATUS Status,
+ IN PCPATH Device,
+ IN PCPATH Destination
+ )
+
+/*++
+
+Routine Description:
+
+ Determines if a device is being redirected to a specific device.
+
+Arguments:
+
+ Status - Supplies pointer to redirection status. Only set in
+ if the return value of this method is FALSE
+
+ Device - Supplies the device about which we want to find out if
+ it is redirected or not.
+
+ Destination - Supplies a pointer to a destination device.
+
+Return Value:
+
+ TRUE if the device is redirected to the destination
+ FALSE otherwise
+
+--*/
+
+{
+ BOOLEAN Redirected = FALSE;
+ PCWSTRING DeviceName;
+ PCWSTRING DestinationName;
+ DSTRING DstRedir;
+ FSTRING LptRedirectionPath;
+ DSTRING TmpString;
+ WCHAR buf[ 2*(MAX_PATH + 1) ];
+ PWSTR pwstrTarget;
+
+ DebugPtrAssert( Device );
+
+ *Status = REDIR_STATUS_ERROR;
+
+ if (NULL == (DeviceName = Device->GetPathString())) {
+ return FALSE;
+ }
+
+ if (!QueryDosDevice(DeviceName->GetWSTR(),
+ buf,
+ sizeof(buf) / sizeof(WCHAR))) {
+
+ // The device probably doesn't exist
+
+ return FALSE;
+ }
+
+ *Status = REDIR_STATUS_NONEXISTENT;
+
+ pwstrTarget = buf;
+
+ // Find out if the LPT device is redirected to the destination.
+
+ DstRedir.Initialize(pwstrTarget);
+
+ return INVALID_CHNUM != DstRedir.Strstr(Destination->GetPathString());
+}
+
+BOOLEAN
+REDIR::IsRedirected (
+ OUT PREDIR_STATUS Status,
+ IN PCPATH Device
+ )
+
+/*++
+
+Routine Description:
+
+ Determines if a device is being redirected to any device.
+
+Arguments:
+
+ Status - Supplies pointer to redirection status. Only set in
+ if the return value of this method is FALSE
+
+ Device - Supplies the device about which we want to find out if
+ it is redirected or not.
+
+Return Value:
+
+ TRUE if redirected, FALSE otherwise.
+
+--*/
+
+{
+ BOOLEAN Redirected = FALSE;
+ PCWSTRING DeviceName;
+ PCWSTRING DestinationName;
+ DSTRING DstRedir;
+ FSTRING LptRedirectionPath;
+ DSTRING TmpString;
+ WCHAR Buffer[ 2*(MAX_PATH + 1) ];
+ PWSTR Pointer;
+ PPATH Destination = NULL;
+
+ DebugPtrAssert( Device );
+
+ *Status = REDIR_STATUS_ERROR;
+
+ if( ( Device != NULL ) &&
+ ( ( DeviceName = Device->GetPathString() ) != NULL ) ) {
+
+ if( QueryDosDevice( DeviceName->GetWSTR(),
+ Buffer,
+ sizeof( Buffer ) / sizeof( WCHAR ) ) == 0 ) {
+ //
+ // The device probably doesn't exist
+ //
+
+ return( FALSE );
+ }
+
+
+ //
+ // At this point we know that the device exists.
+ // Assume that the device is not redirected.
+ //
+
+ *Status = REDIR_STATUS_NONEXISTENT;
+
+ Pointer = Buffer;
+
+ LptRedirectionPath.Initialize( LPT_REDIRECTION_PATH );
+
+ //
+ // Find out if the LPT device is redirected to a COM device
+ //
+
+ while( ( *Pointer != ( WCHAR )'\0' ) &&
+ DstRedir.Initialize( Pointer ) &&
+ ( DstRedir.Strupr() != NULL ) &&
+ !Redirected ) {
+
+ if( DstRedir.Strstr( &LptRedirectionPath ) != INVALID_CHNUM ) {
+ //
+ // The LPT device is redirected to a COM device
+ //
+ if( Destination != NULL ) {
+ if( ( ( DestinationName = Destination->GetPathString() ) != NULL ) &&
+ ( DstRedir.Strstr( DestinationName ) != INVALID_CHNUM ) ) {
+ Redirected = TRUE;
+ }
+ } else {
+ Redirected = TRUE;
+ }
+ }
+ Pointer += DstRedir.QueryChCount() + 1;
+ }
+ }
+
+ return Redirected;
+}
+
+
+
+
+BOOLEAN
+REDIR::EndRedirection (
+ IN PCPATH Device
+ )
+
+/*++
+
+Routine Description:
+
+ Ends the redirection of a device
+
+Arguments:
+
+ Device - Supplies the device
+
+
+Return Value:
+
+
+ TRUE if the device's redirection has ended.
+ FALSE otherwise
+
+
+--*/
+
+{
+ BOOLEAN Done = FALSE;
+ PCWSTRING DeviceName;
+ REDIR_STATUS Status;
+
+
+
+ DebugPtrAssert( Device );
+
+ if( IsRedirected( &Status, Device ) ) {
+ if( ( Device != NULL ) &&
+ ( ( DeviceName = Device->GetPathString() ) != NULL ) ) {
+
+ Done = DefineDosDevice( DDD_REMOVE_DEFINITION /* | DDD_RAW_TARGET_PATH */,
+ DeviceName->GetWSTR(),
+ NULL );
+
+#if DBG
+ if( !Done ) {
+ DebugPrint( "MODE: DefineDosDevice() failed" );
+ DebugPrintf( "MODE: DefineDosDevice() failed, Device = %ls, Destination = %ls, Error = %d \n",
+ DeviceName->GetWSTR(),
+ LPT_REDIRECTION_PATH,
+ GetLastError() );
+ }
+#endif
+ }
+ }
+ return Done;
+}
diff --git a/private/utils/mode/redir.hxx b/private/utils/mode/redir.hxx
new file mode 100644
index 000000000..12b459569
--- /dev/null
+++ b/private/utils/mode/redir.hxx
@@ -0,0 +1,69 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ redir.hxx
+
+Abstract:
+
+ This module contains redirection routines.
+
+Author:
+
+ Ramon San Andres (ramonsa) 04-Sep-91
+
+--*/
+
+
+#if !defined( _REDIR_DEFN_ )
+
+#define _REDIR_DEFN_
+
+DECLARE_CLASS( PATH );
+
+
+typedef enum _REDIR_STATUS {
+
+ REDIR_STATUS_NONEXISTENT,
+ REDIR_STATUS_ERROR
+
+} REDIR_STATUS, *PREDIR_STATUS;
+
+class REDIR {
+
+ public:
+
+ STATIC
+ BOOLEAN
+ IsRedirected (
+ OUT PREDIR_STATUS Status,
+ IN PCPATH Device,
+ IN PCPATH Destination
+ );
+
+ STATIC
+ BOOLEAN
+ IsRedirected (
+ OUT PREDIR_STATUS Status,
+ IN PCPATH Device
+ );
+
+ STATIC
+ BOOLEAN
+ EndRedirection (
+ IN PCPATH Device
+ );
+
+ STATIC
+ BOOLEAN
+ Redirect (
+ IN PCPATH Source,
+ IN PCPATH Destination
+ );
+
+};
+
+
+#endif // _REDIR_DEFN_
diff --git a/private/utils/mode/sources b/private/utils/mode/sources
new file mode 100644
index 000000000..f283f2965
--- /dev/null
+++ b/private/utils/mode/sources
@@ -0,0 +1,71 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+BLDCRT=1
+
+MAJORCOMP=utils
+MINORCOMP=mode
+
+TARGETNAME=mode
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=argument.cxx \
+ common.cxx \
+ com.cxx \
+ cons.cxx \
+ lpt.cxx \
+ redir.cxx \
+ support.cxx \
+ mode.rc
+
+INCLUDES=..\ulib\inc;..\ureg\inc;\nt\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+CXXFLAGS=+d
+UMLIBS=..\ulib\src\obj\*\ulib.lib \
+ ..\ureg\src\obj\*\ureg.lib \
+ obj\*\mode.lib \
+ \nt\public\sdk\lib\*\user32.lib \
+ \nt\public\sdk\lib\*\ntdll.lib
+
+UMTYPE=console
+UMAPPL=mode
+UMAPPLEXT=.com
+UMRES=obj\*\mode.res
diff --git a/private/utils/mode/support.cxx b/private/utils/mode/support.cxx
new file mode 100644
index 000000000..9ff5ba883
--- /dev/null
+++ b/private/utils/mode/support.cxx
@@ -0,0 +1,205 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Support
+
+Abstract:
+
+ Miscelaneous support functions for the XCopy directory copy
+ utility. All functions that are not involved directly in the
+ copy process go here.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 02-May-1991
+
+Revision History:
+
+--*/
+
+
+
+#include "mode.hxx"
+//#include "ulib.hxx"
+#include "system.hxx"
+//#include "mode.hxx"
+
+
+
+
+
+VOID
+DisplayMessage (
+ IN MSGID MsgId,
+ IN PCWSTRING String
+ )
+
+/*++
+
+Routine Description:
+
+ Displays a message, with an optional parameter
+
+Arguments:
+
+ MsgId - Supplies the Id of the message to display.
+ String - Supplies a string parameter for the message.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+
+
+ if (MsgId != 0) {
+ Message->Set( MsgId );
+
+ if ( String == NULL ) {
+ //
+ // The message has no parameters
+ //
+ Message->Display( "" );
+
+ } else {
+
+ //
+ // Display it.
+ //
+ Message->Display( "%W", String );
+ }
+ }
+
+}
+
+
+VOID
+DisplayMessageAndExit (
+ IN MSGID MsgId,
+ IN PCWSTRING String,
+ IN ULONG ExitCode
+ )
+
+/*++
+
+Routine Description:
+
+ Displays a message and exits the program with the supplied error code.
+ We support a maximum of one string parameter for the message.
+
+Arguments:
+
+ MsgId - Supplies the Id of the message to display.
+ String - Supplies a string parameter for the message.
+ ExitCode - Supplies the exit code with which to exit.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+
+ DisplayMessage( MsgId, String );
+
+ ExitMode( ExitCode );
+
+}
+
+PWSTRING
+QueryMessageString (
+ IN MSGID MsgId
+ )
+/*++
+
+Routine Description:
+
+ Obtains a string object initialized to the contents of some message
+
+Arguments:
+
+ MsgId - Supplies ID of the message
+
+Return Value:
+
+ PWSTRING - Pointer to initialized string object
+
+Notes:
+
+--*/
+
+{
+
+ PWSTRING String;
+
+ if ( ((String = NEW DSTRING) == NULL ) ||
+ !(SYSTEM::QueryResourceString( String, MsgId, "" )) ) {
+
+ DisplayMessageAndExit( MODE_ERROR_NO_MEMORY, NULL, (ULONG)EXIT_ERROR );
+ }
+
+ return String;
+
+}
+
+VOID
+ExitWithError(
+ IN DWORD ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Displays a message based on a WIN32 error code, and exits.
+
+Arguments:
+
+ ErrorCode - Supplies Windows error code
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ Message->Set( MODE_ERROR_EXTENDED );
+ Message->Display( "%d", ErrorCode );
+ ExitMode( (ULONG)EXIT_ERROR );
+}
+
+VOID
+ExitMode(
+ IN DWORD ExitCode
+ )
+
+/*++
+
+Routine Description:
+
+ Exits the program
+
+Arguments:
+
+ ExitCode - Supplies the exit code
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ exit( (int)ExitCode );
+}
diff --git a/private/utils/more/argument.cxx b/private/utils/more/argument.cxx
new file mode 100644
index 000000000..91115cf3b
--- /dev/null
+++ b/private/utils/more/argument.cxx
@@ -0,0 +1,470 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Argument
+
+Abstract:
+
+ Argument processing for the "MORE" pager
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 24-Apr-1990
+
+Notes:
+
+ The arguments accepted by the more pager are:
+
+ Extended mode switch.- This allows all other options. Without this
+ switch, no other options are allowed.
+
+ Help switch.- Displays usage.
+
+ ClearScreen switch.- Clears the screen before displaying each page.
+
+ SqueezeBlank switch.- Squeezes consecutive blank lines into a single
+ line.
+
+ ExpandFormFeed switch.- FormFeeds are expanded to fill the rest of
+ the screen.
+
+ Start at line.- Paging starts at the specified line of the
+ first file.
+
+ Tab expansion.- Expand tabs to this number of blanks
+
+ File list.- List of files to page.
+
+
+ The more pager obtains its arguments from two sources:
+
+ 1.- An environment variable ( "MORE" )
+ 2.- The command line.
+
+ The environment variable may specify any options, except a file
+ list.
+
+Revision History:
+
+
+--*/
+
+
+#include "ulib.hxx"
+#include "arg.hxx"
+#include "arrayit.hxx"
+#include "rtmsg.h"
+#include "path.hxx"
+#include "smsg.hxx"
+#include "system.hxx"
+#include "more.hxx"
+
+
+
+#define DEFAULT_TABEXP 8
+
+//
+// Static variables
+//
+//
+PFLAG_ARGUMENT ExtendedModeArgument;
+PFLAG_ARGUMENT ClearScreenArgument;
+PFLAG_ARGUMENT ExpandFormFeedArgument;
+PFLAG_ARGUMENT SqueezeBlanksArgument;
+PFLAG_ARGUMENT Help1Argument;
+PFLAG_ARGUMENT Help2Argument;
+PLONG_ARGUMENT StartAtLineArgument;
+PLONG_ARGUMENT TabExpArgument;
+
+
+
+VOID
+MORE::SetArguments(
+ )
+
+/*++
+
+Routine Description:
+
+ Obtains the arguments for the "more" pager.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ FLAG_ARGUMENT LocalExtendedModeArgument;
+ FLAG_ARGUMENT LocalClearScreenArgument;
+ FLAG_ARGUMENT LocalExpandFormFeedArgument;
+ FLAG_ARGUMENT LocalSqueezeBlanksArgument;
+ FLAG_ARGUMENT LocalHelp1Argument;
+ FLAG_ARGUMENT LocalHelp2Argument;
+ LONG_ARGUMENT LocalStartAtLineArgument;
+ LONG_ARGUMENT LocalTabExpArgument;
+
+ ExtendedModeArgument = &LocalExtendedModeArgument;
+ ClearScreenArgument = &LocalClearScreenArgument;
+ ExpandFormFeedArgument = &LocalExpandFormFeedArgument;
+ SqueezeBlanksArgument = &LocalSqueezeBlanksArgument;
+ Help1Argument = &LocalHelp1Argument;
+ Help2Argument = &LocalHelp2Argument;
+ StartAtLineArgument = &LocalStartAtLineArgument;
+ TabExpArgument = &LocalTabExpArgument;
+
+ //
+ // Get arguments from the environment variable
+ //
+ GetArgumentsMore();
+
+ //
+ // Get the arguments from the command line.
+ //
+ GetArgumentsCmd();
+
+ //
+ // Verify the arguments
+ //
+ CheckArgumentConsistency();
+
+}
+
+VOID
+MORE::GetArgumentsMore(
+ )
+
+/*++
+
+Routine Description:
+
+ Obtains the arguments from the "More" environment variable.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+
+ ARRAY ArgArray;
+ PWSTRING MoreVariableName;
+ PWSTRING MoreVariableValue;
+
+ //
+ // Get the name of the MORE environment variable and the argument
+ //
+ if ( (MoreVariableName = QueryMessageString( MORE_ENVIRONMENT_VARIABLE_NAME )) == NULL ) {
+
+ Fatal();
+ }
+
+ //
+ // Get the value of the MORE environment variable.
+ //
+ MoreVariableValue = SYSTEM::QueryEnvironmentVariable( MoreVariableName );
+
+ if ( MoreVariableValue != NULL ) {
+
+ //
+ // Now prepare for parsing
+ //
+ if ( //
+ // Initialize tha arguments
+ //
+ !(ArgArray.Initialize( 7, 7 )) ||
+ !(ExtendedModeArgument->Initialize( "/E" )) ||
+ !(ClearScreenArgument->Initialize( "/C" )) ||
+ !(ExpandFormFeedArgument->Initialize( "/P" )) ||
+ !(SqueezeBlanksArgument->Initialize( "/S" )) ||
+ !(Help1Argument->Initialize( "/?" )) ||
+ !(Help2Argument->Initialize( "/H" )) ||
+ !(StartAtLineArgument->Initialize( "+*" )) ||
+ !(TabExpArgument->Initialize( "/t*" )) ||
+ //
+ // Put the arguments in the argument array
+ //
+ !(ArgArray.Put( ExtendedModeArgument )) ||
+ !(ArgArray.Put( ClearScreenArgument )) ||
+ !(ArgArray.Put( ExpandFormFeedArgument )) ||
+ !(ArgArray.Put( SqueezeBlanksArgument )) ||
+ !(ArgArray.Put( Help1Argument )) ||
+ !(ArgArray.Put( Help2Argument )) ||
+ !(ArgArray.Put( StartAtLineArgument )) ||
+ !(ArgArray.Put( TabExpArgument ))
+ ) {
+
+ Fatal();
+ }
+
+ //
+ // Parse the arguments
+ //
+ ParseArguments( MoreVariableValue, &ArgArray );
+
+ //
+ // Set the global structures
+ //
+ _ExtendedModeSwitch = ExtendedModeArgument->QueryFlag();
+ _ClearScreenSwitch = ClearScreenArgument->QueryFlag();
+ _ExpandFormFeedSwitch = ExpandFormFeedArgument->QueryFlag();
+ _SqueezeBlanksSwitch = SqueezeBlanksArgument->QueryFlag();
+ _HelpSwitch = (BOOLEAN)(Help1Argument->QueryFlag() || Help2Argument->QueryFlag());
+ if ( StartAtLineArgument->IsValueSet() ) {
+ _StartAtLine = StartAtLineArgument->QueryLong();
+ }
+ if ( TabExpArgument->IsValueSet() ) {
+ _TabExp = TabExpArgument->QueryLong();
+ } else {
+ _TabExp = DEFAULT_TABEXP;
+ }
+
+ //
+ // Clean up
+ //
+ DELETE( MoreVariableValue );
+ }
+
+ DELETE( MoreVariableName );
+
+}
+
+VOID
+MORE::GetArgumentsCmd(
+ )
+
+/*++
+
+Routine Description:
+
+ Obtains the arguments from the Command line
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None
+
+Notes:
+
+--*/
+
+{
+
+ ARRAY ArgArray;
+ DSTRING CmdLine;
+ PATH_ARGUMENT ProgramNameArgument;
+
+ //
+ // Prepare for parsing
+ //
+ if (//
+ // Initialize the arguments
+ //
+ !(CmdLine.Initialize( GetCommandLine() )) ||
+ !(ArgArray.Initialize( 9, 9 )) ||
+ !(ProgramNameArgument.Initialize( "*" )) ||
+ !(ExtendedModeArgument->Initialize( "/E" )) ||
+ !(ClearScreenArgument->Initialize( "/C" )) ||
+ !(ExpandFormFeedArgument->Initialize( "/P" )) ||
+ !(SqueezeBlanksArgument->Initialize( "/S" )) ||
+ !(Help1Argument->Initialize( "/?" )) ||
+ !(Help2Argument->Initialize( "/H" )) ||
+ !(StartAtLineArgument->Initialize( "+*" )) ||
+ !(TabExpArgument->Initialize( "/t*" )) ||
+ ((_FilesArgument = NEW MULTIPLE_PATH_ARGUMENT) == NULL) ||
+ !(_FilesArgument->Initialize( "*", TRUE, TRUE )) ||
+
+ //
+ // Put the arguments in the argument array
+ //
+ !(ArgArray.Put( &ProgramNameArgument )) ||
+ !(ArgArray.Put( ExtendedModeArgument )) ||
+ !(ArgArray.Put( ClearScreenArgument )) ||
+ !(ArgArray.Put( ExpandFormFeedArgument )) ||
+ !(ArgArray.Put( SqueezeBlanksArgument )) ||
+ !(ArgArray.Put( Help1Argument )) ||
+ !(ArgArray.Put( Help2Argument )) ||
+ !(ArgArray.Put( StartAtLineArgument )) ||
+ !(ArgArray.Put( TabExpArgument )) ||
+ !(ArgArray.Put( _FilesArgument )) ) {
+
+ Fatal();
+ }
+
+ //
+ // Parse the arguments
+ //
+ ParseArguments( &CmdLine, &ArgArray );
+
+ //
+ // Set the global structures
+ //
+ _ExtendedModeSwitch |= ExtendedModeArgument->QueryFlag();
+ _ClearScreenSwitch |= ClearScreenArgument->QueryFlag();
+ _ExpandFormFeedSwitch |= ExpandFormFeedArgument->QueryFlag();
+ _SqueezeBlanksSwitch |= SqueezeBlanksArgument->QueryFlag();
+ _HelpSwitch |= Help1Argument->QueryFlag() || Help2Argument->QueryFlag();
+
+ if ( StartAtLineArgument->IsValueSet() ) {
+ _StartAtLine = StartAtLineArgument->QueryLong();
+ }
+ if ( TabExpArgument->IsValueSet() ) {
+ _TabExp = TabExpArgument->QueryLong();
+ } else {
+ _TabExp = DEFAULT_TABEXP;
+ }
+
+}
+
+VOID
+MORE::ParseArguments(
+ IN PWSTRING CmdLine,
+ OUT PARRAY ArgArray
+ )
+
+/*++
+
+Routine Description:
+
+ Parses a group of arguments
+
+Arguments:
+
+ CmdLine - Supplies pointer to a command line to parse
+ ArgArray - Supplies pointer to array of arguments
+
+Return Value:
+
+ none
+
+Notes:
+
+--*/
+
+{
+ ARGUMENT_LEXEMIZER ArgLex;
+ ARRAY LexArray;
+ PWSTRING InvalidParameter;
+
+ //
+ // Initialize lexeme array and the lexemizer.
+ //
+ if ( !(LexArray.Initialize( 8, 8 )) ||
+ !(ArgLex.Initialize( &LexArray )) ) {
+
+ Fatal();
+
+ }
+
+ //
+ // Set our parsing preferences
+ //
+ ArgLex.PutMultipleSwitch( "/ECPSH?" );
+ ArgLex.PutSwitches( "/" );
+ ArgLex.PutSeparators( " /\t" );
+ ArgLex.SetCaseSensitive( FALSE );
+ ArgLex.PutStartQuotes( "\"" );
+ ArgLex.PutEndQuotes( "\"" );
+
+ //
+ // Parse the arguments
+ //
+ if ( !(ArgLex.PrepareToParse( CmdLine ))) {
+
+ Fatal( EXIT_ERROR, MORE_ERROR_GENERAL, "" );
+
+ }
+
+ if ( !ArgLex.DoParsing( ArgArray ) ) {
+
+ _Message.Set(MSG_INVALID_PARAMETER);
+ _Message.Display("%W", InvalidParameter = ArgLex.QueryInvalidArgument() );
+ DELETE(InvalidParameter);
+ ExitProcess( 0 );
+ }
+
+ LexArray.DeleteAllMembers( );
+
+
+}
+
+VOID
+MORE::CheckArgumentConsistency (
+ )
+
+/*++
+
+Routine Description:
+
+ Checks the consistency of the arguments
+
+Arguments:
+
+ none
+
+Return Value:
+
+ none
+
+Notes:
+
+--*/
+
+{
+
+ BOOLEAN ExtendedSwitches;
+
+ if ( _HelpSwitch ) {
+
+ //
+ // Help wanted
+ //
+ Usage();
+ }
+
+ ExtendedSwitches = (BOOLEAN)( _ClearScreenSwitch ||
+ _ExpandFormFeedSwitch ||
+ _SqueezeBlanksSwitch ||
+ TabExpArgument->IsValueSet() ||
+ ( _StartAtLine > (LONG)0 ) ||
+ _FilesArgument->WildCardExpansionFailed() ||
+ ( _FilesArgument->QueryPathCount() > (ULONG)0));
+
+ //
+ // If the "extended" flag was not specified, then no other argument
+ // is allowed.
+ //
+ if ( !_ExtendedModeSwitch &&
+ ExtendedSwitches ) {
+
+ Fatal( EXIT_ERROR, MORE_ERROR_TOO_MANY_ARGUMENTS, "" );
+
+ }
+
+ //
+ // Error out if invalid file specified
+ //
+ if ( _FilesArgument->WildCardExpansionFailed() ) {
+ Fatal( EXIT_ERROR, MORE_ERROR_CANNOT_ACCESS, "%W", _FilesArgument->GetLexemeThatFailed() );
+ }
+
+}
diff --git a/private/utils/more/makefile b/private/utils/more/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/more/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/more/makefile.inc b/private/utils/more/makefile.inc
new file mode 100644
index 000000000..6c93eb38d
--- /dev/null
+++ b/private/utils/more/makefile.inc
@@ -0,0 +1,12 @@
+{}.cxx{obj\i386\}.obj:
+ $(386_COMPILER) -Fo$@ $(MAKEDIR)\$(<F)
+
+{}.cxx{obj\mips\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClMips $< " $(C_COMPILER) "
+ @$(C_COMPILER) -Fo$@ $(MAKEDIR)\$<
+
+{}.cxx{obj\alpha\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClAlpha $< " $(ALPHA_COMPILER) "
+ @$(ALPHA_COMPILER) -Fo$@ $(MAKEDIR)\$<
diff --git a/private/utils/more/more.cxx b/private/utils/more/more.cxx
new file mode 100644
index 000000000..ae9df87e7
--- /dev/null
+++ b/private/utils/more/more.cxx
@@ -0,0 +1,877 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ More
+
+Abstract:
+
+ "More" pager
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 11-Apr-1990
+
+Revision History:
+
+--*/
+
+
+#include "ulib.hxx"
+#include "arg.hxx"
+#include "arrayit.hxx"
+#include "error.hxx"
+#include "file.hxx"
+#include "filestrm.hxx"
+#include "keyboard.hxx"
+#include "rtmsg.h"
+#include "pager.hxx"
+#include "path.hxx"
+#include "smsg.hxx"
+#include "system.hxx"
+#include "more.hxx"
+
+#define NULL_CHARACTER ((CHAR)'\0')
+#define CTRLC_CHARACTER ((CHAR)0x03)
+
+//
+// Required by ULIB
+//
+ERRSTACK *perrstk;
+
+
+
+
+VOID _CRTAPI1
+main (
+ )
+
+/*++
+
+Routine Description:
+
+ Main function of the more pager.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+
+{
+
+ // Initialize stuff
+ //
+ DEFINE_CLASS_DESCRIPTOR( MORE );
+
+ //
+ // Now do the paging
+ //
+ {
+ MORE More;
+
+ //
+ // Initialize the MORE object.
+ //
+ if( More.Initialize() ) {
+
+ //
+ // Do the paging
+ //
+ More.DoPaging();
+ }
+ }
+}
+
+DEFINE_CONSTRUCTOR( MORE, PROGRAM );
+
+
+
+BOOLEAN
+MORE::Initialize (
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes the MORE object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ //
+ // Initialize program object
+ //
+ if( !PROGRAM::Initialize( MORE_MESSAGE_USAGE, MORE_ERROR_NO_MEMORY, EXIT_ERROR ) ) {
+
+ return FALSE;
+ }
+
+ //
+ // Initialize whatever needs initialization
+ //
+ InitializeThings();
+
+ //
+ // Do the argument parsing
+ //
+ SetArguments();
+
+ return TRUE;
+
+}
+
+MORE::~MORE (
+ )
+
+/*++
+
+Routine Description:
+
+ Destructs a MORE object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ //
+ // Deallocate the global structures previously allocated
+ //
+ DeallocateThings();
+
+ //
+ // Exit without error
+ //
+ exit( EXIT_NORMAL );
+
+}
+
+VOID
+MORE::InitializeThings (
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes the global variables that need initialization
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+
+ if ( //
+ // Initialize the library
+ //
+ !(_Keyboard = NEW KEYBOARD)
+
+
+ ) {
+
+ exit( EXIT_ERROR );
+
+ }
+
+ // MORE translates from MBCS to Unicode according to the
+ // current console codepage.
+ //
+ WSTRING::SetConsoleConversions();
+
+ if ( //
+ // Pager stuff
+ //
+ !DEFINE_CLASS_DESCRIPTOR( PAGER ) ||
+ //
+ // Misc. Strings
+ //
+ ((_LineDelimiters = NEW DSTRING) == NULL ) ||
+ !_LineDelimiters->Initialize( "\r\n" ) ||
+ ((_Percent = NEW DSTRING) == NULL ) ||
+ ((_Line = NEW DSTRING) == NULL ) ||
+ ((_OtherPrompt = NEW DSTRING) == NULL )
+ ) {
+
+ Fatal();
+
+ }
+
+ //
+ // Get the strings containing valid user options
+ //
+ if ( (( _Help = QueryMessageString( MORE_HELP )) == NULL ) ||
+ (( _DisplayLinesOption = QueryMessageString( MORE_OPTION_DISPLAYLINES )) == NULL ) ||
+ (( _SkipLinesOption = QueryMessageString( MORE_OPTION_SKIPLINES )) == NULL ) ||
+ (( _NextFileOption = QueryMessageString( MORE_OPTION_NEXTFILE )) == NULL ) ||
+ (( _ShowLineNumberOption = QueryMessageString( MORE_OPTION_SHOWLINENUMBER )) == NULL ) ||
+ (( _QuitOption = QueryMessageString( MORE_OPTION_QUIT )) == NULL ) ||
+ (( _Help1Option = QueryMessageString( MORE_OPTION_HELP1 )) == NULL ) ||
+ (( _Help2Option = QueryMessageString( MORE_OPTION_HELP2 )) == NULL ) ) {
+
+ Fatal();
+ }
+
+ _Keyboard->Initialize();
+ _Quit = FALSE;
+ _ExtendedModeSwitch = FALSE;
+ _ClearScreenSwitch = FALSE;
+ _ExpandFormFeedSwitch = FALSE;
+ _SqueezeBlanksSwitch = FALSE;
+ _HelpSwitch = FALSE;
+ _StartAtLine = 0;
+ _FilesArgument = NULL;
+
+}
+
+VOID
+MORE::DeallocateThings (
+ )
+
+/*++
+
+Routine Description:
+
+ Deallocates the global variables that need deallocation
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+
+ DELETE( _Keyboard );
+
+ DELETE( _FilesArgument );
+ DELETE( _LineDelimiters );
+ DELETE( _Percent );
+ DELETE( _Line );
+ DELETE( _Help );
+
+ //
+ // Delete the strings containing valid user options
+ //
+ DELETE( _DisplayLinesOption );
+ DELETE( _SkipLinesOption );
+ DELETE( _NextFileOption );
+ DELETE( _ShowLineNumberOption );
+ DELETE( _QuitOption );
+ DELETE( _Help1Option );
+ DELETE( _Help2Option );
+
+}
+
+VOID
+MORE::DoPaging (
+ )
+
+/*++
+
+Routine Description:
+
+ Does the paging.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ PPATH Path;
+ PITERATOR Iterator;
+ BOOLEAN IsFirstFile = TRUE;
+ ULONG FilesLeft;
+ PFSN_FILE FsnFile;
+ PFILE_STREAM FileStream;
+
+ FilesLeft = _FilesArgument->QueryPathCount();
+
+ if ( FilesLeft > 0 ) {
+
+ //
+ // We have a list of files, we will page each one in turn
+ //
+ // Get an iterator for going thru the file list
+ //
+ if ((Iterator = _FilesArgument->GetPathArray()->QueryIterator()) == NULL ) {
+
+ Fatal();
+ }
+
+ Path = (PPATH)Iterator->GetNext();
+
+ //
+ // Iterate thru all the files in the array
+ //
+ while ( Path && !_Quit) {
+
+ //
+ // Get a new stream out of the file name
+ //
+ if ((FsnFile = SYSTEM::QueryFile( Path )) == NULL ||
+ (FileStream = FsnFile->QueryStream( READ_ACCESS )) == NULL ) {
+ Fatal( EXIT_ERROR, MORE_ERROR_CANNOT_ACCESS, "%W", Path->GetPathString() );
+ }
+
+ PageStream( FileStream,
+ FsnFile,
+ IsFirstFile ? _StartAtLine : 0, --FilesLeft );
+
+ DELETE( FileStream );
+ DELETE( FsnFile );
+
+ Path = (PPATH)Iterator->GetNext();
+ IsFirstFile = FALSE;
+ }
+
+ DELETE( Iterator );
+
+ } else {
+
+ //
+ // The user did'nt specify a file list, so we will page
+ // standard input.
+ //
+ PageStream( GetStandardInput(),
+ NULL,
+ _StartAtLine,
+ 0 );
+ }
+}
+
+VOID
+MORE::PageStream (
+ IN PSTREAM Stream,
+ IN PFSN_FILE FsnFile,
+ IN ULONG FirstLineToDisplay,
+ IN ULONG FilesLeft
+ )
+
+/*++
+
+Routine Description:
+
+ Pages a stream
+
+Arguments:
+
+ Stream - Supplies pointer to stream
+ FsnFile - Supplies pointer to file object
+ FirstLineToDisplay - Supplies first line to display
+ FilesLeft - Files remaining to be displayed
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+
+ PAGER Pager;
+ ULONG LinesToDisplay;
+ BOOLEAN ClearScreen;
+ BOOLEAN StayInFile;
+
+ //
+ // Initialize the pager
+ //
+ if (!Pager.Initialize( Stream, this)) {
+
+ Fatal();
+
+ }
+
+ //
+ // Skip to the first line to be displayed
+ //
+ if ( FirstLineToDisplay > 0 ) {
+ Pager.SkipLines( FirstLineToDisplay, _TabExp );
+ }
+
+ LinesToDisplay = Pager.QueryLinesPerPage() - 1;
+ ClearScreen = _ClearScreenSwitch;
+ StayInFile = TRUE;
+
+ while (StayInFile && Pager.ThereIsMoreToPage() && !_Quit) {
+
+ // If QueryLinesPerPage() returns 0 then undo the -1 operation.
+
+ if (LinesToDisplay == (ULONG) -1) {
+ LinesToDisplay = 0;
+ }
+
+ //
+ // Display a group of lines
+ //
+ Pager.DisplayPage( LinesToDisplay,
+ ClearScreen,
+ _SqueezeBlanksSwitch,
+ _ExpandFormFeedSwitch,
+ _TabExp );
+
+ //
+ // If not at end of stream, we wait for an option
+ //
+ if (Pager.ThereIsMoreToPage() || (FilesLeft > 0)) {
+
+ StayInFile = DoOption( FsnFile, &Pager, &LinesToDisplay, &ClearScreen );
+ }
+ }
+}
+
+BOOLEAN
+MORE::DoOption (
+ IN PFSN_FILE FsnFile,
+ IN PPAGER Pager,
+ OUT PULONG LinesInPage,
+ OUT PBOOLEAN ClearScreen
+ )
+
+/*++
+
+Routine Description:
+
+ Gets an option from the user
+
+Arguments:
+
+ FsnFile - Supplies pointer to file object
+ Pager - Supplies pointer to pager
+ LinesInpage - Supplies pointer to lines to display in next page
+ ClearScreen - Supplies pointer to Clearscreen flag.
+
+Return Value:
+
+ TRUE if paging should continue for this file,
+ FALSE otherwise
+
+--*/
+
+{
+
+ WCHAR Char;
+ DSTRING String;
+ BOOLEAN ShowLineNumber = FALSE;
+ BOOLEAN ShowHelp = FALSE;
+ LONG Number;
+
+
+ String.Initialize( " " );
+
+ while ( TRUE ) {
+
+ //
+ // Display prompt
+ //
+ Prompt( FsnFile, Pager, ShowLineNumber, ShowHelp, 0 );
+
+ ShowHelp = FALSE;
+ ShowLineNumber = FALSE;
+
+ //
+ // Get option from the user
+ //
+ _Keyboard->DisableLineMode();
+ _Keyboard->ReadChar( &Char );
+ _Keyboard->EnableLineMode();
+ String.SetChAt(Char, 0);
+ String.Strupr();
+ Pager->ClearLine();
+
+ //
+ // If Ctl-C, get out
+ //
+ if ( Char == CTRLC_CHARACTER ) {
+
+ _Keyboard->EnableLineMode();
+ GenerateConsoleCtrlEvent( CTRL_C_EVENT, 0 );
+ _Quit = TRUE;
+ return FALSE;
+ }
+
+
+ //
+ // If not in extended mode, any key just advances one page
+ //
+ if ( !_ExtendedModeSwitch ) {
+ *LinesInPage = Pager->QueryLinesPerPage() - 1;
+ return TRUE;
+ }
+
+
+ //
+ // Now take the proper action
+ //
+ if ( String.QueryChAt(0) == (WCHAR)CARRIAGERETURN ) {
+
+ //
+ // Display next line of the file
+ //
+ *LinesInPage = 1;
+ *ClearScreen = FALSE;
+ return TRUE;
+
+ } else if ( String.QueryChAt(0) == (WCHAR)' ' ) {
+
+ //
+ // Display next page
+ //
+ *ClearScreen = _ClearScreenSwitch;
+ *LinesInPage = Pager->QueryLinesPerPage() - 1;
+ return TRUE;
+
+ } else if ( String.Stricmp(_DisplayLinesOption) == 0 ) {
+
+ //
+ // Display a certain number of lines. Get the number of lines
+ // to display
+ //
+ Prompt( FsnFile, Pager, ShowLineNumber, ShowHelp, MORE_LINEPROMPT );
+
+
+ *LinesInPage = ReadNumber();
+
+ //if ( ReadLine( _Keyboard, &String ) &&
+ // String.QueryNumber((PLONG)LinesInPage) ) {
+ //
+ // (*LinesInPage)--;
+ //
+ //} else {
+ // *LinesInPage = 0;
+ //}
+
+ Pager->ClearLine();
+
+ *ClearScreen = FALSE;
+ return TRUE;
+
+ } else if ( String.Stricmp(_SkipLinesOption) == 0 ) {
+
+ //
+ // Skip a certain number of lines and then display a page.
+ //
+ Prompt( FsnFile, Pager, ShowLineNumber, ShowHelp, MORE_LINEPROMPT );
+
+ Number = ReadNumber( );
+ if ( Number ) {
+ Pager->SkipLines( Number, _TabExp );
+ }
+
+ Pager->ClearLine();
+
+ *LinesInPage = Pager->QueryLinesPerPage() - 1;
+ return TRUE;
+
+ } else if ( String.Stricmp(_NextFileOption) == 0 ) {
+
+ //
+ // Stop paging this file
+ //
+ return FALSE;
+
+ } else if ( String.Stricmp(_QuitOption) == 0 ) {
+
+ //
+ // Quit the program
+ //
+ _Quit = TRUE;
+ return FALSE;
+
+ } else if ( String.Stricmp(_ShowLineNumberOption) == 0) {
+
+ //
+ // Prompt again, showing the line number within the file
+ //
+ ShowLineNumber = TRUE;
+
+ } else if ( ( String.Stricmp(_Help1Option) == 0) ||
+ ( String.Stricmp(_Help2Option) == 0)) {
+
+ //
+ // Prompt again, showing a message line
+ //
+ ShowHelp = TRUE;
+
+ }
+
+ }
+
+}
+
+VOID
+MORE::Prompt (
+ IN PFSN_FILE FsnFile,
+ IN PPAGER Pager,
+ IN BOOLEAN ShowLineNumber,
+ IN BOOLEAN ShowHelp,
+ IN MSGID OtherMsgId
+ )
+
+/*++
+
+Routine Description:
+
+ Displays prompt. The prompt consists of a "base" prompt (e.g.
+ "-- More --" plus various optional strings:
+
+ - Percentage of the file displayed so far.
+ - Line number within the file
+ - Help
+ - Other (e.g prompt for a number )
+
+
+Arguments:
+
+ FsnFile - Supplies pointer to file object
+ Pager - Supplies pointer to pager
+ ShowLineNumber - Supplies flag which if TRUE causes the current
+ line numnber to be displayed
+ HelpMsg - Supplies flag which if TRUE causes a brief help
+ to be displayed
+
+ OtherMsg - Supplies MsgId of any other string to be displayed
+
+Return Value:
+
+ none
+
+--*/
+
+{
+
+ CHAR NullBuffer = NULL_CHARACTER;
+ PVOID PercentMsg;
+ PVOID LineMsg;
+ PVOID HelpMsg;
+ PVOID OtherMsg;
+
+ //
+ // Obtain all the strings that form part of the prompt
+ //
+ if ( FsnFile != NULL ) {
+ SYSTEM::QueryResourceString( _Percent, MORE_PERCENT, "%d", Pager->QueryCurrentByte() * 100 / FsnFile->QuerySize());
+ _Percent->QuerySTR( 0, TO_END, (PSTR)_StringBuffer0, STRING_BUFFER_SIZE);
+ PercentMsg = (PVOID)_StringBuffer0;
+ } else {
+ PercentMsg = (PVOID)&NullBuffer;
+ }
+
+ if (ShowLineNumber) {
+ SYSTEM::QueryResourceString( _Line, MORE_LINE, "%d", Pager->QueryCurrentLine());
+ _Line->QuerySTR( 0, TO_END, (PSTR)_StringBuffer1, STRING_BUFFER_SIZE);
+ LineMsg = (PVOID)_StringBuffer1;
+ } else {
+ LineMsg = (PVOID)&NullBuffer;
+ }
+
+ if (ShowHelp) {
+ _Help->QuerySTR(0, TO_END, (PSTR)_StringBuffer2, STRING_BUFFER_SIZE);
+ HelpMsg = (PVOID)_StringBuffer2;
+ } else {
+ HelpMsg = (PVOID)&NullBuffer;
+ }
+
+ if (OtherMsgId != 0) {
+ SYSTEM::QueryResourceString( _OtherPrompt, OtherMsgId, "" );
+ _OtherPrompt->QuerySTR(0, TO_END, (PSTR)_StringBuffer3, STRING_BUFFER_SIZE);
+ OtherMsg = (PVOID)_StringBuffer3;
+ } else {
+ OtherMsg = (PVOID)&NullBuffer;
+ }
+
+ //
+ // Now display the prompt
+ //
+ DisplayMessage( MORE_PROMPT, NORMAL_MESSAGE, "%s%s%s%s", PercentMsg, LineMsg, HelpMsg, OtherMsg );
+}
+
+PWSTRING
+MORE::QueryMessageString (
+ IN MSGID MsgId
+ )
+/*++
+
+Routine Description:
+
+ Obtains a string object initialized to the contents of some message
+
+Arguments:
+
+ MsgId - Supplies ID of the message
+
+Return Value:
+
+ Pointer to initialized string object
+
+Notes:
+
+--*/
+
+{
+
+ PWSTRING String;
+
+ if ( ((String = NEW DSTRING) == NULL ) ||
+ !(SYSTEM::QueryResourceString( String, MsgId, "" )) ) {
+
+ DELETE( String );
+ String = NULL;
+ }
+
+ return String;
+
+}
+
+ULONG
+MORE::ReadNumber (
+ )
+/*++
+
+Routine Description:
+
+ Reads a number from the keyboard.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Number read
+
+Notes:
+
+--*/
+
+{
+ DSTRING NumberString;
+ DSTRING CharString;
+ PSTREAM StandardOut;
+ ULONG Number = 0;
+ LONG LongNumber;
+ WCHAR Char;
+ BOOLEAN Done = FALSE;
+ ULONG DigitCount = 0;
+
+ StandardOut = GetStandardOutput();
+
+ NumberString.Initialize( "" );
+ CharString.Initialize( " " );
+
+ while ( !Done ) {
+
+ _Keyboard->DisableLineMode();
+ _Keyboard->ReadChar( &Char );
+ _Keyboard->EnableLineMode();
+
+ switch ( Char ) {
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ CharString.SetChAt( Char, 0 );
+ NumberString.Strcat( &CharString );
+ StandardOut->WriteChar( Char );
+ DigitCount++;
+ break;
+
+ case '\b':
+ if ( DigitCount > 0 ) {
+ NumberString.Truncate( NumberString.QueryChCount() - 1 );
+ StandardOut->WriteChar( Char );
+ StandardOut->WriteChar( ' ' );
+ StandardOut->WriteChar( Char );
+ DigitCount--;
+ }
+ break;
+
+
+ case '\r':
+ case '\n':
+ Done = TRUE;
+ break;
+
+ case CTRLC_CHARACTER:
+ _Quit = TRUE;
+ Done = TRUE;
+ break;
+
+ default:
+ break;
+
+
+ }
+ }
+
+ if ( NumberString.QueryChCount() > 0 ) {
+
+ if ( NumberString.QueryNumber( &LongNumber ) ) {
+
+ Number = (ULONG)LongNumber;
+ }
+ }
+
+ return Number;
+}
diff --git a/private/utils/more/more.hxx b/private/utils/more/more.hxx
new file mode 100644
index 000000000..d36a2f7f2
--- /dev/null
+++ b/private/utils/more/more.hxx
@@ -0,0 +1,221 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ More.hxx
+
+Abstract:
+
+ This module contains the definition for the MORE class, which
+ implements the DOS5-compatible More pager.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 24-Apr-1990
+
+
+Revision History:
+
+
+--*/
+
+
+#if !defined( _MORE_ )
+
+#define _MORE_
+
+
+#include "arg.hxx"
+#include "object.hxx"
+#include "program.hxx"
+
+//
+// Commonly used character constants
+//
+#define CARRIAGERETURN '\r'
+#define LINEFEED '\n'
+#define FORMFEED '\f'
+
+//
+// Exit levels
+//
+#define EXIT_NORMAL 0
+#define EXIT_ERROR 1
+
+//
+// For prompting
+//
+#define STRING_BUFFER_SIZE 128
+
+//
+// Forward references
+//
+DECLARE_CLASS( ARRAY );
+DECLARE_CLASS( FSN_FILE );
+DECLARE_CLASS( KEYBOARD );
+DECLARE_CLASS( STREAM );
+DECLARE_CLASS( WSTRING );
+DECLARE_CLASS( PAGER );
+DECLARE_CLASS( MORE );
+
+class MORE : public PROGRAM {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( MORE );
+
+ NONVIRTUAL
+ ~MORE (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ );
+
+ NONVIRTUAL
+ VOID
+ DoPaging (
+ );
+
+
+
+ private:
+
+
+ NONVIRTUAL
+ VOID
+ CheckArgumentConsistency (
+ );
+
+ NONVIRTUAL
+ VOID
+ DeallocateThings (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DoOption (
+ IN PFSN_FILE FsnFile,
+ IN PPAGER Pager,
+ OUT PULONG LinesInpage,
+ OUT PBOOLEAN ClearScreen
+ );
+
+ NONVIRTUAL
+ VOID
+ GetArgumentsCmd(
+ );
+
+ NONVIRTUAL
+ VOID
+ GetArgumentsMore(
+ );
+
+ NONVIRTUAL
+ VOID
+ InitializeThings (
+ );
+
+ NONVIRTUAL
+ VOID
+ PageStream (
+ IN PSTREAM Stream,
+ IN PFSN_FILE FsnFile,
+ IN ULONG FirstLineToDisplay,
+ IN ULONG FilesLeft
+ );
+
+ NONVIRTUAL
+ VOID
+ ParseArguments(
+ IN PWSTRING CmdLine,
+ OUT PARRAY ArgArray
+ );
+
+ NONVIRTUAL
+ VOID
+ Prompt (
+ IN PFSN_FILE FsnFile,
+ IN PPAGER Pager,
+ IN BOOLEAN ShowLineNumber,
+ IN BOOLEAN ShowHelp,
+ IN MSGID OtherMsg
+ );
+
+ NONVIRTUAL
+ PWSTRING
+ QueryMessageString (
+ IN MSGID MsgId
+ );
+
+ NONVIRTUAL
+ ULONG
+ ReadNumber (
+ );
+
+ NONVIRTUAL
+ VOID
+ SetArguments(
+ );
+
+ //
+ // Command-line arguments.
+ //
+ BOOLEAN _ExtendedModeSwitch;
+ BOOLEAN _ClearScreenSwitch;
+ BOOLEAN _ExpandFormFeedSwitch;
+ BOOLEAN _SqueezeBlanksSwitch;
+ BOOLEAN _HelpSwitch;
+ LONG _StartAtLine;
+ LONG _TabExp;
+ PMULTIPLE_PATH_ARGUMENT _FilesArgument;
+
+ //
+ // String with end-of line delimiters
+ //
+ PWSTRING _LineDelimiters;
+
+ //
+ // Strings used while prompting
+ //
+ PWSTRING _Percent;
+ PWSTRING _Line;
+ PWSTRING _Help;
+ PWSTRING _OtherPrompt;
+
+ //
+ // Options during paging.
+ //
+ PWSTRING _DisplayLinesOption;
+ PWSTRING _SkipLinesOption;
+ PWSTRING _NextFileOption;
+ PWSTRING _ShowLineNumberOption;
+ PWSTRING _QuitOption;
+ PWSTRING _Help1Option;
+ PWSTRING _Help2Option;
+
+ //
+ // The quit flag is true when we want to stop paging
+ //
+ BOOLEAN _Quit;
+
+ //
+ // For displaying strings
+ //
+ BYTE _StringBuffer0[STRING_BUFFER_SIZE];
+ BYTE _StringBuffer1[STRING_BUFFER_SIZE];
+ BYTE _StringBuffer2[STRING_BUFFER_SIZE];
+ BYTE _StringBuffer3[STRING_BUFFER_SIZE];
+
+ //
+ // The real keyboard
+ //
+ PKEYBOARD _Keyboard;
+
+};
+
+
+#endif // _MORE_
diff --git a/private/utils/more/more.rc b/private/utils/more/more.rc
new file mode 100644
index 000000000..e3b8157f0
--- /dev/null
+++ b/private/utils/more/more.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "More Utility"
+#define VER_INTERNALNAME_STR "more\0"
+#define VER_ORIGINALFILENAME_STR "MORE.COM"
+
+#include "common.ver"
diff --git a/private/utils/more/pager.cxx b/private/utils/more/pager.cxx
new file mode 100644
index 000000000..e932c22ef
--- /dev/null
+++ b/private/utils/more/pager.cxx
@@ -0,0 +1,823 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ PAGER
+
+Abstract:
+
+ This module contains the implementations for the PAGER class
+
+Author:
+
+ Ramon Juan San Andres (RamonSA) 15-Apr-1990
+
+Notes:
+
+
+--*/
+
+#include "ulib.hxx"
+#include "filestrm.hxx"
+#include "wstring.hxx"
+#include "screen.hxx"
+#include "stream.hxx"
+#include "more.hxx"
+#include "pager.hxx"
+
+//
+// What constitutes a "blank" character (spaces and tabs)
+//
+#define BLANKCHARACTERS (LPWSTR)L" \t"
+#define TAB_CHAR (WCHAR)'\t'
+
+
+
+DEFINE_CONSTRUCTOR( PAGER, OBJECT );
+
+VOID
+PAGER::Construct (
+ )
+{
+ UNREFERENCED_PARAMETER( this );
+}
+
+PAGER::~PAGER (
+ )
+{
+
+ DELETE( _String );
+ DELETE( _Blanks );
+ DELETE( _BlankLine );
+
+}
+
+BOOLEAN
+PAGER::Initialize (
+ IN PSTREAM Stream,
+ IN PPROGRAM Program
+ )
+/*++
+
+Routine Description:
+
+ Phase 2 of construction for a pager object. It initializes its
+ internal data.
+
+Arguments:
+
+ Stream - Supplies the stream to be paged
+ Program - Supplies pointer to the program doing the paging.
+
+Return Value:
+
+ TRUE - If initialized correctly
+ FALSE - If something when wrong. (check error stack)
+
+--*/
+
+{
+
+ USHORT ScreenRows, RowsInPage;
+ CHNUM i;
+
+ _Stream = Stream;
+ _CurrentLineNumber = 0;
+ _StandardOutput = Program->GetStandardOutput();
+ _Screen = SCREEN::Cast( _StandardOutput );
+ _Position = INVALID_CHNUM;
+
+ //
+ // Get the page dimensions
+ //
+ if (_Screen) {
+ _Screen->QueryScreenSize( &ScreenRows, &_ColumnsInScreen, &RowsInPage, &_ColumnsInPage );
+ _RowsInPage = RowsInPage;
+ _ColumnsInPage = _ColumnsInScreen;
+ } else {
+
+ // If we don't have a screen then we should treat the page
+ // as infinitely long since we have no need to prompt.
+
+ _RowsInPage = (ULONG) -1;
+ _ColumnsInPage = (USHORT) -1;
+ }
+
+ if (!(_String = NEW DSTRING) ||
+ !(_Blanks = NEW DSTRING) ||
+ !(_BlankLine = NEW DSTRING) ||
+ !_String->Initialize() ||
+ !_Blanks->Initialize(BLANKCHARACTERS) ||
+ !_BlankLine->Resize(_Screen ? _ColumnsInPage : 0)) {
+
+ return FALSE;
+ }
+
+ for (i = 0; i < _BlankLine->QueryChCount(); i++) {
+ _BlankLine->SetChAt(' ', i);
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+PAGER::DisplayPage (
+ IN ULONG LinesInPage,
+ IN BOOLEAN ClearScreen,
+ IN BOOLEAN SqueezeBlankLines,
+ IN BOOLEAN ExpandFormFeed,
+ IN ULONG TabExp
+ )
+
+/*++
+
+Routine Description:
+
+ Displays a page of the screen
+
+Arguments:
+
+ LinesInPage - Supplies the desired number of lines in the page
+ ClearScreen - Supplies a flag, which if TRUE means that we
+ want to clear the screen before displaying the
+ page
+ SqueezeBlankLines - Supplies squeeze flag
+ ExpandFormFeed - Supplies formfeed expansion flag
+
+Return Value:
+
+ TRUE - If page displayed
+ FALSE otherwise
+
+--*/
+
+{
+ ULONG LinesLeft = LinesInPage;
+ BOOLEAN IgnoreBlankLine = FALSE;
+ CHNUM Length;
+ CHNUM FormFeedAt;
+
+
+ if ( TabExp > (ULONG)( _ColumnsInPage - 1 ) ) {
+ TabExp = _ColumnsInPage - 1 ;
+ }
+
+ //
+ // Clear the screen if instructed to do so
+ //
+ if ( ClearScreen && _Screen) {
+#ifdef DBCS // v-junm - 08/18/93
+// Also reset attributes.
+ _Screen->EraseScreenAndResetAttribute();
+#else
+ _Screen->EraseScreen();
+#endif
+ _Screen->MoveCursorTo( 0, 0 );
+ } else {
+ //
+ // Make sure that we start at the beginning of a line
+ //
+ ClearLine();
+ }
+
+ //
+ // Display up to LinesLeft lines
+ //
+
+ while ( LinesLeft > 0 &&
+ (ThereIsMoreToPage() || _Position != INVALID_CHNUM) ) {
+
+ //
+ // Get next string from input
+ //
+ if (!ReadNextString( TabExp )) {
+ return FALSE;
+ }
+
+#ifdef DBCS // v-junm - 08/18/93
+// Now QueryChCount returns the correct number of unicode chars. An additional
+// API, QueryByteCount was added.
+ Length = _String->QueryByteCount() - _Position;
+#else
+ Length = _String->QueryChCount() - _Position;
+#endif // DBCS
+
+ if ( SqueezeBlankLines ) {
+
+ if ( _String->Strspn( _Blanks, _Position ) == INVALID_CHNUM ) {
+
+ //
+ // This is a blank line. We must sqeeze
+ //
+ if ( IgnoreBlankLine ) {
+ //
+ // We ignore the line
+ //
+ _Position = INVALID_CHNUM;
+ continue;
+
+ } else {
+ //
+ // We will print a blank line and ignore the following
+ // blank lines.
+ //
+ DisplayBlankLine( 1 );
+ _Position = INVALID_CHNUM;
+ IgnoreBlankLine = TRUE;
+ continue;
+ }
+ } else if (IgnoreBlankLine) {
+ LinesLeft--;
+ IgnoreBlankLine = FALSE;
+ continue;
+ }
+ }
+
+
+ if ( ExpandFormFeed ) {
+ //
+ // Look for form feed within line
+ //
+ if ((FormFeedAt = _String->Strchr( FORMFEED,_Position )) != INVALID_CHNUM) {
+ if ( FormFeedAt == _Position ) {
+ //
+ // First character is a form feed.
+ //
+ // We will skip the formfeed character, and the
+ // rest of the screen will be blanked.
+ //
+ if ( SqueezeBlankLines ) {
+ if (!IgnoreBlankLine) {
+ DisplayBlankLine( 1 );
+ LinesLeft--;
+ IgnoreBlankLine = TRUE;
+ }
+ } else {
+ DisplayBlankLine( LinesLeft );
+ LinesLeft = 0;
+ }
+ _Position++;
+ continue;
+ }
+
+ Length = FormFeedAt - _Position;
+ }
+ }
+
+
+ //
+ // If the line is too long, we must split it
+ //
+ if (Length > (CHNUM)_ColumnsInPage) {
+ Length = (CHNUM)_ColumnsInPage;
+ }
+
+ //
+ // Display the string
+ //
+ DisplayString( _String, &_Position, Length );
+ IgnoreBlankLine = FALSE;
+
+ LinesLeft--;
+ }
+
+ return TRUE;
+}
+
+VOID
+PAGER::ClearLine (
+ )
+
+/*++
+
+Routine Description:
+
+ Clears a line
+
+Arguments:
+
+ none
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ USHORT ScreenRows, ScreenCols;
+ USHORT WindowRows, WindowCols;
+ CHNUM i;
+
+ if (_Screen) {
+
+ _Screen->QueryScreenSize( &ScreenRows,
+ &ScreenCols,
+ &WindowRows,
+ &WindowCols );
+ //
+ // If the number of columns has changed, re-initialize the
+ // blank line.
+ //
+ if ( ScreenCols != _ColumnsInPage ) {
+ _BlankLine->Resize(ScreenCols);
+ for (i = 0; i < ScreenCols; i++) {
+ _BlankLine->SetChAt(' ', i);
+ }
+ }
+ _RowsInPage = WindowRows;
+ _ColumnsInPage = ScreenCols;
+
+ _StandardOutput->WriteChar( (WCHAR)CARRIAGERETURN );
+ _StandardOutput->WriteString( _BlankLine, 0, _ColumnsInPage-1 );
+ _StandardOutput->WriteChar( (WCHAR)CARRIAGERETURN );
+ }
+}
+
+VOID
+PAGER::DisplayBlankLine (
+ IN ULONG Lines,
+ IN BOOLEAN NewLine
+ )
+
+/*++
+
+Routine Description:
+
+ Displays a number of blank lines
+
+Arguments:
+
+ Lines - Supplies the number of blank lines to display
+ NewLine - Supplies the newline flag
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ CHNUM Position;
+
+ while ( Lines-- ) {
+
+ Position = 0;
+
+ DisplayString( _BlankLine, &Position, _ColumnsInPage-1, (Lines > 0) ? TRUE : NewLine);
+
+ }
+}
+
+VOID
+PAGER::DisplayString (
+ IN PWSTRING String,
+ OUT PCHNUM Position,
+ IN CHNUM Length,
+ IN BOOLEAN NewLine
+ )
+
+/*++
+
+Routine Description:
+
+ Displays a chunk of the current string
+
+Arguments:
+
+ Length - Supplies the length of the string to display
+ NewLine - Supplies the newline flag
+
+Return Value:
+
+ none
+
+--*/
+
+{
+#ifdef DBCS // v-junm - 04/19/93
+
+ CHNUM UnicodeCharNum, // # of unicode characters to display
+ TempByteCount, // to minimize calls to QueryByteCount
+ index; // loop counter
+ PSTR STRBuffer; // ASCIIZ converted string pointer
+ static CHNUM OldPos; // Keeps old position in # of Unicode
+ BOOL DBCSFlag = FALSE; // Flag for ending leadbyte
+
+ TempByteCount = String->QueryByteCount();
+ Length = min( Length, TempByteCount );
+
+ // If the length of the string to display is shorter than
+ // the width of the screen, we do not have to do any DBCS
+ // checking. Just print it out. (Can be skipped for CP437)
+ //
+
+ if ( TempByteCount > _ColumnsInPage ) {
+
+ //
+ // Initialize # of unicode characters to #
+ // of ASCII chars to display.
+ //
+
+ UnicodeCharNum = Length;
+
+ //
+ // Get the string as a ASCIIZ text.
+ //
+
+ STRBuffer = String->QuerySTR();
+
+ if ( STRBuffer != NULL ) {
+
+ //
+ // Start changing the UnicodeCharNum from the actual
+ // number of bytes to the actual number of characters.
+ //
+
+ for( index = 0; index < Length; index++ ) {
+ if ( IsLeadByte( *(STRBuffer + index + _Position) ) ) {
+ index++;
+ UnicodeCharNum--;
+ DBCSFlag = TRUE;
+ }
+ else
+ DBCSFlag = FALSE;
+ }
+ DELETE( STRBuffer );
+ }
+
+ //
+ // If the following conditions are true, then there
+ // is a Leadbyte at the end of the screen that needs
+ // to be displayed on the next line with it's tail byte.
+ //
+
+ if ( DBCSFlag == TRUE && // String ends with DBCS.
+ index == (Length - 1) && // Only Leadbyte.
+ Length == (CHNUM)_ColumnsInPage // More rows to display.
+ ) {
+ Length--;
+ UnicodeCharNum--;
+ }
+
+ }
+ else
+//fix kksuzuka: #195
+//Overflow pagecolumns when writing 0D0A.
+//UnicodeCharNum = String->QueryChCount();
+ UnicodeCharNum = min( Length, String->QueryChCount() );
+
+ //
+ // When the string does not fit on one line and needs to be truncated,
+ // OldPos keeps the position where the string was truncated in Unicode
+ // location.
+ //
+
+
+ //
+ // If true, set to beginning of string.
+ //
+
+ if ( *Position == 0 )
+ OldPos = 0;
+
+ _StandardOutput->WriteString( String, OldPos, UnicodeCharNum );
+
+ //
+ // Set to last+1 char displayed in unicode character numbers.
+ //
+
+ OldPos += UnicodeCharNum;
+
+ //
+ // Update our position within the string
+ //
+
+ *Position += Length;
+
+ //
+ // Check if all the characters have been written.
+ //
+
+ if ( TempByteCount && (TempByteCount == *Position) &&
+ !(TempByteCount % _ColumnsInPage) ) {
+
+ //
+ // Characters have been written, but there is a LF/CR
+ // character at the that needs to be display that has
+ // not been displayed. (At _ColumnsInPage+1 location)
+ //
+
+ *Position = INVALID_CHNUM;
+// _StandardOutput->WriteChar( (WCHAR)CARRIAGERETURN );
+// _StandardOutput->WriteChar( (WCHAR)LINEFEED );
+
+ }
+ else if ( *Position >= TempByteCount )
+ *Position = INVALID_CHNUM;
+
+ if ( ((*Position != INVALID_CHNUM) || NewLine) &&
+ ( Length < _ColumnsInScreen || !_Screen ) ) {
+
+ _StandardOutput->WriteChar( (WCHAR)CARRIAGERETURN );
+ _StandardOutput->WriteChar( (WCHAR)LINEFEED );
+ }
+
+#else // DBCS
+
+ Length = min( Length, String->QueryChCount() );
+
+ _StandardOutput->WriteString( String, *Position, Length );
+
+ //
+ // Update our position within the string
+ //
+ *Position += Length;
+
+ if (*Position >= _String->QueryChCount()) {
+ *Position = INVALID_CHNUM;
+ }
+
+ if ( ((*Position != INVALID_CHNUM) || NewLine) &&
+ ( Length < _ColumnsInScreen || !_Screen ) ) {
+ _StandardOutput->WriteChar( (WCHAR)CARRIAGERETURN );
+ _StandardOutput->WriteChar( (WCHAR)LINEFEED );
+ }
+
+#endif // DBCS
+}
+
+
+ULONG
+PAGER::QueryCurrentByte (
+ )
+
+/*++
+
+Routine Description:
+
+ Queries the current Byte number
+
+Arguments:
+
+ none
+
+Return Value:
+
+ The current byte number
+
+--*/
+
+{
+
+ PFILE_STREAM pFileStream;
+ ULONG PointerPosition ;
+
+ if ((pFileStream = FILE_STREAM::Cast(_Stream)) == NULL ) {
+
+ return 0;
+
+ } else {
+
+ pFileStream->QueryPointerPosition( &PointerPosition );
+
+ return PointerPosition;
+ }
+}
+
+USHORT
+PAGER::QueryLinesPerPage (
+ )
+
+/*++
+
+Routine Description:
+
+ Queries the number of lines per page of output
+
+Arguments:
+
+ none
+
+Return Value:
+
+ The number of lines (rows) in a page
+
+--*/
+
+{
+ USHORT ScreenRows, ScreenCols;
+ USHORT WindowRows, WindowCols;
+ CHNUM i;
+
+ //
+ // If Paging to screen, get the current size of the window
+ //
+ if (_Screen) {
+
+ _Screen->QueryScreenSize( &ScreenRows,
+ &ScreenCols,
+ &WindowRows,
+ &WindowCols );
+ //
+ // If the number of columns has changed, re-initialize the
+ // blank line.
+ //
+ if ( WindowCols != _ColumnsInPage ) {
+ _BlankLine->Resize(ScreenCols);
+ for (i = 0; i < ScreenCols; i++) {
+ _BlankLine->SetChAt(' ', i);
+ }
+ }
+ _RowsInPage = WindowRows;
+ _ColumnsInPage = ScreenCols;
+ }
+
+ return (USHORT)_RowsInPage;
+}
+
+BOOLEAN
+PAGER::ReadNextString (
+ IN ULONG TabExp
+ )
+
+/*++
+
+Routine Description:
+
+ Reads in the next string from the input stream.
+
+Arguments:
+
+ TabExp - Supplies the number of blank characters per tab
+
+Return Value:
+
+ TRUE - If string read in
+ FALSE otherwise
+
+--*/
+
+{
+
+ if (_Position == INVALID_CHNUM ) {
+
+ CHNUM Idx;
+
+ //
+ // We have to read a new string from the input stream.
+ //
+ if (!_Stream->ReadLine( _String )) {
+ return FALSE;
+ }
+
+ _CurrentLineNumber++;
+ _Position = 0;
+
+ //
+ // Expand tabs
+ //
+ Idx = 0;
+#ifdef DBCS // v-junm - 08/18/93
+ while ( (Idx < _String->QueryByteCount()) &&
+#else
+ while ( (Idx < _String->QueryChCount()) &&
+#endif // DBCS
+ ((Idx = _String->Strchr( TAB_CHAR, Idx )) != INVALID_CHNUM) ) {
+
+ _String->Replace( Idx, // AtPosition
+ 1, // AtLength
+ _BlankLine, // String
+ 0, // FromPosition
+ TabExp ? TabExp - Idx%TabExp : 0 // FromLength
+ );
+
+ //
+ // MJB: If we're eliminating tabs we don't want to advance the
+ // index; removing the previous tab has pulled the next character
+ // in *to* the index, so it's already where we want it. Advancing
+ // regardless can cause every other adjacent tab not to be
+ // elminiated.
+ //
+
+ if (TabExp > 0) {
+ Idx++;
+ }
+ }
+
+ }
+
+ return TRUE;
+
+}
+
+BOOLEAN
+PAGER::SkipLines (
+ IN ULONG LinesToSkip,
+ IN ULONG TabExp
+ )
+
+/*++
+
+Routine Description:
+
+ Skips certain number of lines
+
+Arguments:
+
+ LinesToSkip - Supplies the number of lines to skip
+ TabExp - Supplies number of spaces per tab
+
+Return Value:
+
+ TRUE - If lines skipped
+ FALSE otherwise
+
+--*/
+
+{
+
+ if ( TabExp > (ULONG)( _ColumnsInPage - 1 ) ) {
+ TabExp = _ColumnsInPage - 1;
+ }
+
+ while ( LinesToSkip-- && ThereIsMoreToPage() ) {
+
+ if (!ReadNextString( TabExp )) {
+ return FALSE;
+ }
+
+ _Position = INVALID_CHNUM;
+
+ }
+
+ return TRUE;
+
+}
+
+#ifdef DBCS // v-junm - 09/24/93
+
+BOOLEAN
+PAGER::IsLeadByte(
+ IN BYTE c
+ )
+
+/*++
+
+Routine Description:
+
+ Checks to see if c is a leadbyte of a DBCS character.
+
+Arguments:
+
+ c - character to check to see if leadbyte.
+
+Return Value:
+
+ TRUE - leadbyte of DBCS character.
+ FALSE otherwise
+
+--*/
+
+{
+ CPINFO cp;
+ static UINT outputcp = GetConsoleOutputCP();
+ int i;
+
+ if ( GetCPInfo( outputcp, &cp ) ) {
+
+ //
+ // Code page info has been aquired. From code page info,
+ // the leadbyte range can be determined.
+ //
+
+ for( i = 0; cp.LeadByte[i] && cp.LeadByte[i+1]; i += 2 ) {
+
+ //
+ // There are leadbytes. Check to see if c falls in
+ // current leadbyte range.
+ //
+
+ if ( c >= cp.LeadByte[i] && c <= cp.LeadByte[i+1] )
+ return( TRUE );
+
+ }
+
+ return( FALSE );
+ }
+ else {
+
+ //
+ // This will not produce correct results if
+ // 'ConsoleOutputCP != SystemCP && DBCS System'
+ // Just making system conversion the default
+ // when GetCPInfo doesn't work.
+ //
+
+ return( IsDBCSLeadByte( c ) );
+ }
+}
+
+#endif DBCS
diff --git a/private/utils/more/pager.hxx b/private/utils/more/pager.hxx
new file mode 100644
index 000000000..3944ce054
--- /dev/null
+++ b/private/utils/more/pager.hxx
@@ -0,0 +1,210 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ PAGER
+
+Abstract:
+
+ This module contains the definition for the PAGER class, used by
+ the "More" utility
+
+Author:
+
+ Ramon Juan San Andres (RamonSA) 15-Apr-1990
+
+Notes:
+
+
+--*/
+
+
+#if !defined (_PAGER_)
+
+#define _PAGER_
+
+#include "object.hxx"
+#include "wstring.hxx"
+#include "stream.hxx"
+
+//
+// Forward references
+//
+DECLARE_CLASS( SCREEN );
+DECLARE_CLASS( PROGRAM );
+DECLARE_CLASS( PAGER );
+
+class PAGER : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( PAGER );
+
+ DECLARE_CAST_MEMBER_FUNCTION( PAGER );
+
+ NONVIRTUAL
+ ~PAGER (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ IN PSTREAM Stream,
+ IN PPROGRAM Program
+ );
+
+ NONVIRTUAL
+ VOID
+ ClearLine (
+ );
+
+ NONVIRTUAL
+ VOID
+ DisplayBlankLine (
+ IN ULONG Lines,
+ IN BOOLEAN NewLine DEFAULT TRUE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DisplayPage (
+ IN ULONG LinesInPage,
+ IN BOOLEAN ClearScreen,
+ IN BOOLEAN SqueezeBlankLines,
+ IN BOOLEAN ExpandFormFeed,
+ IN ULONG TabExp
+ );
+
+ NONVIRTUAL
+ VOID
+ DisplayString (
+ IN PWSTRING String,
+ OUT PCHNUM Position,
+ IN CHNUM Length,
+ IN BOOLEAN NewLine DEFAULT TRUE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ThereIsMoreToPage (
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryCurrentByte (
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryCurrentLine (
+ );
+
+ NONVIRTUAL
+ USHORT
+ QueryLinesPerPage (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SkipLines (
+ IN ULONG LinesToSkip,
+ IN ULONG TabExp
+ );
+
+#ifdef DBCS // v-junm - 09/24/93
+
+ BOOLEAN
+ IsLeadByte(
+ IN BYTE c
+ );
+
+#endif
+
+ private:
+
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ReadNextString (
+ IN ULONG TabExp
+ );
+
+ PSTREAM _Stream; // Stream to page
+ ULONG _CurrentLineNumber; // Current line number
+
+ ULONG _RowsInPage; // Rows per page
+ USHORT _ColumnsInPage; // Columns per page
+ USHORT _ColumnsInScreen; // Columns in screen
+
+ PWSTRING _String; // String with line
+ CHNUM _Position; // Position within String
+
+ PSCREEN _Screen; // Pointer to screen
+ PSTREAM _StandardOutput; // Standard output
+ PWSTRING _Blanks; // Blank characters
+ PWSTRING _BlankLine; // A line of blanks
+
+};
+
+INLINE
+BOOLEAN
+PAGER::ThereIsMoreToPage (
+ )
+
+/*++
+
+Routine Description:
+
+ Finds out if there is more stuff to page
+
+Arguments:
+
+ none
+
+Return Value:
+
+ True if there is more to page
+ FALSE otherwise
+
+--*/
+
+{
+
+ return !(_Stream->IsAtEnd());
+
+}
+
+INLINE
+ULONG
+PAGER::QueryCurrentLine (
+ )
+
+/*++
+
+Routine Description:
+
+ Queries the current line number
+
+Arguments:
+
+ none
+
+Return Value:
+
+ The current line number
+
+--*/
+
+{
+
+ return _CurrentLineNumber;
+
+}
+
+#endif // __PAGER__
+
diff --git a/private/utils/more/sources b/private/utils/more/sources
new file mode 100644
index 000000000..37373cbcf
--- /dev/null
+++ b/private/utils/more/sources
@@ -0,0 +1,65 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+BLDCRT=1
+
+MAJORCOMP=utils
+MINORCOMP=more
+
+TARGETNAME=more
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=argument.cxx \
+ pager.cxx \
+ more.rc
+
+INCLUDES=..\ulib\inc;\nt\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+UMLIBS= \
+ $(BASEDIR)\public\sdk\lib\*\setargv.obj \
+ ..\ulib\src\obj\*\ulib.lib \
+ obj\*\more.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+
+UMTYPE=console
+UMAPPL=more
+UMAPPLEXT=.com
+UMRES=obj\*\more.res
diff --git a/private/utils/ntbackup/dirs b/private/utils/ntbackup/dirs
new file mode 100644
index 000000000..4c6956183
--- /dev/null
+++ b/private/utils/ntbackup/dirs
@@ -0,0 +1,23 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl
+
+!ENDIF
+
+DIRS= src
diff --git a/private/utils/ntbackup/exchange/build/alphamk.inc b/private/utils/ntbackup/exchange/build/alphamk.inc
new file mode 100644
index 000000000..2498e84ca
--- /dev/null
+++ b/private/utils/ntbackup/exchange/build/alphamk.inc
@@ -0,0 +1,195 @@
+!IF 0
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ alphamk.inc
+
+Abstract:
+
+ This module contains the ALPHA specific build controls. It is included
+ by makefile.def.
+
+Author:
+
+ Jeff Havens (jhavens) 13-Feb-1994
+
+Revision History:
+
+!ENDIF
+
+#
+# Alpha option control
+#
+
+UMBASE=$(UMBASE:*=alpha)
+UMLIBS=$(UMLIBS:*=alpha)
+NTRES=$(NTRES:*=alpha)
+UMRES=$(UMRES:*=alpha)
+UMOBJS=$(UMOBJS:*=alpha)
+LINKLIBS=$(LINKLIBS:*=alpha)
+DLLBASE=$(DLLBASE:*=alpha)
+DLLDEF=$(DLLDEF:*=alpha)
+MACHINE_TARGETLIBS=$(MACHINE_TARGETLIBS:*=alpha)
+TARGET=$(TARGET:*=alpha)
+DYNLINK_LIB=$(DYNLINK_LIB:*=alpha)
+TARGETEXEFILES=$(TARGETEXEFILES:*=alpha)
+TARGETLIBFILES=$(TARGETLIBFILES:*=alpha)
+TARGETOBJFILES=$(TARGETOBJFILES:*=alpha)
+UMOBJFILES=$(UMOBJFILES:*=alpha)
+UMEXEFILES=$(UMEXEFILES:*=alpha)
+HEADERFILE=$(HEADERFILE:*=alpha)
+HEADEROBJNAME=$(HEADEROBJNAME:*=alpha)
+HEADEROBJ=$(HEADEROBJ:*=alpha)
+PRECOMPILED=$(PRECOMPILED:*=alpha)
+PRECOMPILED_CXX=$(PRECOMPILED_CXX:*=alpha)
+PRECOMPILED_TARGET=$(PRECOMPILED_TARGET:*=alpha)
+
+!ifdef NTTARGETFILES
+NTTARGETFILES=$(NTTARGETFILES:*=alpha)
+!endif
+!ifdef NTTARGETFILE0
+NTTARGETFILE0=$(NTTARGETFILE0:*=alpha)
+!endif
+!ifdef NTTARGETFILE1
+NTTARGETFILE1=$(NTTARGETFILE1:*=alpha)
+!endif
+
+!IF "$(GPSIZE)" != "0"
+
+LIBC_LIB=$(BASEDIR)\public\sdk\lib\alpha\small.lib $(LIBC_LIB)
+LINKGPSIZE=-gpsize:$(GPSIZE)
+
+!ENDIF
+
+ENTRY_SUFFIX=
+GDI_ENTRY_SUFFIX=
+
+!IF "$(MSC_OPTFLAGS)" == "/Oxs"
+DBGFLAGS=$(MSC_OPTFLAGS:/Oxs=/Ox)
+!ENDIF
+
+!IFDEF ALPHA_WARNING_LEVEL
+MSC_WARNING_LEVEL=$(ALPHA_WARNING_LEVEL)
+!ENDIF
+
+!IFDEF ALPHA_OPTIMIZATION
+MSC_OPTIMIZATION=$(ALPHA_OPTIMIZATION)
+!ENDIF
+
+!IFDEF ALPHA_CPPFLAGS
+MSC_CPPFLAGS=$(ALPHA_CPPFLAGS)
+!ENDIF
+
+ALPHA_AS=asaxp -nologo
+
+ALPHA_START_FILE=start.obj
+
+# Use /Z7 instead of /Zi
+
+DBGFLAGS=$(DBGFLAGS:/Zi=/Z7)
+
+ENV_DEFINES=$(LIBC_DEFINES) $(C_DEFINES) $(NET_C_DEFINES) $(MSC_CPPFLAGS) $(NTCPPFLAGS)
+STD_DEFINES=-DALPHA=1 -D_ALPHA_=1 -DNO_EXT_KEYS -DCONDITION_HANDLING=1 $(STD_DEFINES)
+
+STDFLAGS= /c /Zel /Zp8 /Gy $(MSC_WARNING_LEVEL) $(MFC_FLAGS)
+
+CDEFINES=$(STD_DEFINES) $(TARGET_DBG_DEFINES) $(ENV_DEFINES)
+CFLAGS=$(ALPHA_FLAGS) $(NTALPHAFLAGS) $(STDFLAGS) $(DBGFLAGS) $(ALPHA_PERFFLAGS) \
+ -D__stdcall= -D__cdecl=
+
+ALPHA_CDEFINES=$(CDEFINES)
+ALPHA_CFLAGS=$(CFLAGS)
+
+!IFNDEF _AXPACC_
+_AXPACC_=0
+!ENDIF
+
+ALPHA_CC = cl $(CBSTRING) -nologo -d2"switch no*check*" $(USER_C_FLAGS)
+
+C_COMPILER_NAME = $(ALPHA_CC)
+CXX_COMPILER_NAME = $(ALPHA_CC)
+C_PREPROCESSOR_NAME = $(ALPHA_CC)
+
+GLOBAL_C_FLAGS = -Ialpha\ -I. $(INCPATH0) $(CDEFINES) \
+ $(ALPHA_OPTIONS) $(CFLAGS) \
+ /Gt$(GPSIZE) -DFPO=1
+
+C_COMPILER_FLAGS = $(GLOBAL_C_FLAGS) $(PRECOMPILED) $(COMPILER_WARNINGS)
+CXX_COMPILER_FLAGS = $(GLOBAL_C_FLAGS) $(PRECOMPILED_CXX) $(COMPILER_WARNINGS)
+C_PREPROCESSOR_FLAGS = $(GLOBAL_C_FLAGS) -EP -Tc
+
+C_COMPILER= $(C_COMPILER_NAME) $(C_COMPILER_FLAGS)
+CXX_COMPILER=$(CXX_COMPILER_NAME) $(CXX_COMPILER_FLAGS)
+C_PREPROCESSOR = $(C_PREPROCESSOR_NAME) $(C_PREPROCESSOR_FLAGS)
+
+ALPHA_ASSEMBLER=$(ALPHA_AS) -O1 -Ialpha\ -I. $(INCPATH0) $(CDEFINES) \
+ $(ALPHA_FLAGS) $(NTALPHAFLAGS) $(ADBGFLAGS) \
+ -D_LANGUAGE_ASSEMBLY
+
+ECHO_MSG=ClAlpha $< " $(C_COMPILER) "
+ECHO_PRECOMPILED_MSG=CpAlpha $(PRECOMPILED_INCLUDE) " $(C_COMPILER) /Yl$(TARGETNAME) /Yc$(?F) $(HEADERFILE) $(HEADEROBJ) $(PRECOMPILED_FLAG)"
+
+{..\alpha\}.s{obj\alpha\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo AsAlpha $< " $(ALPHA_ASSEMBLER) "
+ @$(ALPHA_ASSEMBLER) -o $@ $(MAKEDIR)\..\alpha\$(<F)
+
+{alpha\}.s{obj\alpha\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo AsAlpha $< " $(ALPHA_ASSEMBLER) "
+ @$(ALPHA_ASSEMBLER) -o $@ $(MAKEDIR)\alpha\$(<F)
+
+.SUFFIXES: .il
+
+{}.il{}.cod:
+ @-erase $@ >nul 2>&1
+ @type <<
+$(ECHO_MSG)
+<<NOKEEP
+ @$(C_COMPILER_NAME) @<< -FAac -Fa$(<B).cod -B1..\bootbin\null.exe -Bk$(<B). -Fo$(MAKEDIR)\obj\alpha\$(<B).o $(MAKEDIR)\$(<B).c
+$(C_COMPILER_FLAGS: =
+)
+<<NOKEEP
+ @del obj\alpha\$(<B).o
+
+{}.il{obj\alpha\}.obj:
+ @-erase $@ >nul 2>&1
+ @type <<
+$(ECHO_MSG)
+<<NOKEEP
+ @$(C_COMPILER_NAME) @<< -B1..\bootbin\null.exe -Bk$(<B). -Fo$(MAKEDIR)\$@ $(MAKEDIR)\$(<B).c
+$(C_COMPILER_FLAGS: =
+)
+<<NOKEEP
+
+LIBRARY_OBJS=$(OBJECTS) $(LINKLIBS)
+
+!IFDEF TUKWILA
+_NTTREE=$(_NTALPHATREE)
+!ENDIF
+
+!IFDEF CAIRO_PRODUCT
+!IFDEF _CAIROALPHATREE
+_NTTREE=$(_CAIROALPHATREE)
+!ENDIF
+!ELSE
+!IFDEF _NTALPHATREE
+_NTTREE=$(_NTALPHATREE)
+!ENDIF
+!ENDIF
+
+!IFDEF KERNEL_MODE
+_NTTREE=$(_NTALPHATREE)\km
+!ENDIF
+
+!IFDEF _NTALPHALIBS
+_NTLIBS=$(_NTALPHALIBS)
+!ENDIF
+
+COPYDST=$(ALPHACOPYDST)
+
+LIB_COPY=ntalphacp.cmd
+
+NTTEST_LINK_OPTIONS= -base:0x80080000 -fixed -entry:KiSystemStartup
diff --git a/private/utils/ntbackup/exchange/build/coffbase.txt b/private/utils/ntbackup/exchange/build/coffbase.txt
new file mode 100644
index 000000000..5e8685239
--- /dev/null
+++ b/private/utils/ntbackup/exchange/build/coffbase.txt
@@ -0,0 +1,776 @@
+;
+; This file defines the base virtual address for Dynamic Link Libraries (DLL)
+; that are part of the Windows NT System. The first token on a line is the name
+; of the DLL and the second token is the base virtual address, in hexidecimal.
+; The third token is the maximum size of the DLL image file, including symbols.
+;
+; NOTE: I have used the convention of labelling unused areas as _FREExx_.
+; If you need an address, these are available. They were used by printer
+; drivers.
+
+usermode 0x01000000 0x60000000
+slm 0x11000000 0x40000000
+slmck 0x12000000 0x40000000
+sadmin 0x13000000 0x40000000
+;
+; OLE dlls
+;
+ole32 0x19e00000 0x00a00000
+oledlg 0x1a200000 0x00100000
+
+;
+; This section contains the Cairo images. Free areas are labelled with
+; _CFREExx_
+;
+
+proxy 0x10000000 0x00200000
+alertsys 0x10200000 0x00200000
+commnot 0x10400000 0x00200000
+cryptdll 0x10600000 0x00200000
+demoif 0x10800000 0x00200000
+menuedt 0x10a00000 0x00200000
+_CFREE00_ 0x10c00000 0x00200000
+clock 0x10e00000 0x00200000
+cal 0x11000000 0x00200000
+report 0x11200000 0x00200000
+desk 0x11400000 0x00200000
+cxxflt 0x11600000 0x00200000
+clocksch 0x11800000 0x00200000
+_CFREE01_ 0x11a00000 0x00200000
+iclass 0x11c00000 0x00200000
+_CFREE02_ 0x11e00000 0x00200000
+_CFREE02a 0x12000000 0x00200000
+iprod 0x12200000 0x00200000
+kerberos 0x12400000 0x00200000
+ofskd 0x12600000 0x00200000
+applet1 0x12800000 0x00200000
+cairocpl 0x12a00000 0x00200000
+cpo 0x12c00000 0x00200000
+deskapp 0x12e00000 0x00200000
+ntlm 0x13000000 0x00200000
+objsrv 0x13200000 0x00200000
+; for Cairo message store
+msgfno 0x13400000 0x00200000
+lnktrack 0x13600000 0x00200000
+pocket 0x13800000 0x00200000
+dsfsmsgs 0x13a00000 0x00200000
+_CFREE 0x13c00000 0x00200000
+scperf 0x13e00000 0x00100000
+msvcbook 0x13f00000 0x00100000
+dsyscpl 0x14000000 0x00200000
+bmpctl 0x14200000 0x00200000
+spintime 0x14400000 0x00200000
+grpbox 0x14600000 0x00200000
+security 0x14800000 0x00200000
+mdbmsg 0x14a00000 0x00200000
+bimport 0x14c00000 0x00200000
+
+oldctrls 0x15600000 0x00200000
+smctrls 0x15800000 0x00200000
+dahard 0x15a00000 0x00200000
+stdobj 0x15c00000 0x00200000
+csumcat 0x15e00000 0x00200000
+sysmgmt 0x16000000 0x00200000
+cpdskadm 0x16200000 0x00200000
+idfsvol 0x16400000 0x00200000
+testdll 0x16600000 0x00400000
+cap 0x16a00000 0x00200000
+sysinf 0x16c00000 0x00200000
+shdebug 0x16e00000 0x00100000
+_CFREE03_ 0x16f00000 0x00400000
+popups 0x17300000 0x00100000
+replsup 0x17400000 0x00200000
+schema 0x17700000 0x00200000
+useragnt 0x18000000 0x00200000
+vpcont 0x18200000 0x00200000
+uares 0x18400000 0x00200000
+rndrevrp 0x18600000 0x00200000
+pdfpage 0x18800000 0x00200000
+pkgpage 0x18a00000 0x00200000
+package 0x18e00000 0x00200000
+pdf 0x19000000 0x00200000
+dsys 0x19200000 0x00300000
+dfsprov 0x19500000 0x00100000
+dfsinstr 0x19600000 0x00200000
+lprofile 0x19800000 0x00200000
+;19e00000 - 1a2FFFFF used by ole32 and oledlg (see above)
+_CFREE04_ 0x1a300000 0x00B00000
+oleprx32 0x1b000000 0x00500000
+_CFREE05_ 0x1b000000 0x00600000
+testext 0x1b600000 0x00200000
+loghrs 0x1b800000 0x00100000
+scstg 0x1b900000 0x00100000
+smoke 0x1ba00000 0x00100000
+shamu 0x1bc00000 0x01000000
+
+; Repl dlls
+chglogdb 0x1cc00000 0x00100000
+dumyrclr 0x1cd00000 0x00100000
+flatrst 0x1ce00000 0x00100000
+_RFREE1_ 0x1cf00000 0x00300000
+orarcnlr 0x1d200000 0x00100000
+replui 0x1d300000 0x00100000
+roschlog 0x1d400000 0x00100000
+rsmgr 0x1d500000 0x00100000
+dsobjs 0x1d600000 0x00200000
+account 0x1d800000 0x00200000
+ora 0x1da00000 0x00200000
+oraexts 0x1dc00000 0x00100000
+dsmail 0x1dd00000 0x00100000
+atsvc 0x1de00000 0x00100000
+replperf 0x1e000000 0x00100000
+accctrl 0x1e100000 0x00100000
+dssrv 0x1e200000 0x00200000
+
+_CFREE06_ 0x1e400000 0x00600000
+
+;RTO dlls
+_CFREE07_ 0x1eA00000 0x00200000
+webcore 0x1eC00000 0x00200000
+rtoolbar 0x1eE00000 0x00200000
+rtfdoc 0x1f000000 0x00400000
+
+spincube 0x1f400000 0x00200000
+_CFREE08_ 0x1f600000 0x00A00000
+msgina 0x1f400000 0x00200000
+
+smss 0x20000000 0x40000000
+;
+; Printer drivers: resource only data, overlaps SMSS
+;
+brhj770 0x20000000 0x00100000
+brother9 0x20000000 0x00100000
+brothr24 0x20000000 0x00100000
+canon330 0x20000000 0x00100000
+canon800 0x20000000 0x00100000
+canonlbp 0x20000000 0x00100000
+cit24us 0x20000000 0x00100000
+cit9us 0x20000000 0x00100000
+citoh 0x20000000 0x00100000
+dec24pin 0x20000000 0x00100000
+dec9pin 0x20000000 0x00100000
+diconix 0x20000000 0x00100000
+epson24 0x20000000 0x00100000
+epson9 0x20000000 0x00100000
+escp2e 0x20000000 0x00100000
+escp2ms 0x20000000 0x00100000
+fuji24 0x20000000 0x00100000
+fuji9 0x20000000 0x00100000
+hpdskjet 0x20000000 0x00100000
+hppcl 0x20000000 0x00100000
+hppcl5ms 0x20000000 0x00100000
+pcl1200 0x20000000 0x00100000
+ibm238x 0x20000000 0x00100000
+ibm239x 0x20000000 0x00100000
+ibm5204 0x20000000 0x00100000
+ibm5204 0x20000000 0x00100000
+ibmppdsl 0x20000000 0x00100000
+ibmport 0x20000000 0x00100000
+jp350 0x20000000 0x00100000
+kyocera 0x20000000 0x00100000
+mantal 0x20000000 0x00100000
+mantal24 0x20000000 0x00100000
+mantal90 0x20000000 0x00100000
+mt735 0x20000000 0x00100000
+nec24pin 0x20000000 0x00100000
+oki24 0x20000000 0x00100000
+oki9ibm 0x20000000 0x00100000
+olidm24 0x20000000 0x00100000
+olidm9 0x20000000 0x00100000
+paintjet 0x20000000 0x00100000
+panson24 0x20000000 0x00100000
+panson9 0x20000000 0x00100000
+proprint 0x20000000 0x00100000
+proprn24 0x20000000 0x00100000
+ps1 0x20000000 0x00100000
+quietjet 0x20000000 0x00100000
+qwiii 0x20000000 0x00100000
+seiko 0x20000000 0x00100000
+seiko24e 0x20000000 0x00100000
+seikosh9 0x20000000 0x00100000
+star24e 0x20000000 0x00100000
+star9e 0x20000000 0x00100000
+starjet 0x20000000 0x00100000
+thinkjet 0x20000000 0x00100000
+ti850 0x20000000 0x00100000
+toshiba 0x20000000 0x00100000
+txtonly 0x20000000 0x00100000
+
+; Following have code in them
+
+oki9 0x20100000 0x00100000
+dec3200 0x20200000 0x00100000
+
+; End of printer overlap area.
+
+dbgss 0x30000000 0x30000000
+csrss 0x40000000 0x20000000
+cmd 0x50000000 0x10000000
+os2ss 0x40000000 0x20000000
+psxss 0x40000000 0x20000000
+ntdll 0x60100000 0x00100000
+dbgdll 0x60200000 0x00100000
+advapi32 0x60300000 0x00100000
+csrrtl 0x60400000 0x00100000
+csrsrv 0x60500000 0x00100000
+kernel32 0x60600000 0x00100000
+basertl 0x60700000 0x00100000
+basesrv 0x60800000 0x00100000
+user32 0x60A00000 0x00200000
+winsrv 0x60C00000 0x00700000
+winsrv2 0x60C00000 0x00700000
+rasdd 0x61300000 0x00100000
+sysmono 0x61400000 0x00100000
+courier 0x61500000 0x00100000
+helv 0x61600000 0x00100000
+times 0x61700000 0x00100000
+netapi32 0x61800000 0x00200000
+winmgr 0x62100000 0x00100000
+display 0x62200000 0x00100000
+vga 0x62200000 0x00400000
+winspool 0x62600000 0x00100000
+splsrv 0x62700000 0x00100000
+ntprint 0x62800000 0x00100000
+pscript 0x62900000 0x00100000
+halftone 0x62A00000 0x00100000
+lmspool 0x62B00000 0x00100000
+os2dll 0x63000000 0x00200000
+psxdll 0x63200000 0x00200000
+winnet 0x63400000 0x00100000
+msv1_0 0x63500000 0x00100000
+samlib 0x635A0000 0x00100000
+lsaap 0x63600000 0x00100000
+netrap 0x63700000 0x00100000
+TEMPNAME2 0x63800000 0x00700000
+console 0x63f00000 0x00100000
+gdi32 0x64000000 0x00200000
+media 0x65000000 0x00100000
+mediasrv 0x66000000 0x00100000
+
+lprmon 0x66100000 0x00100000
+lprhelp 0x66200000 0x00100000
+lpdsvc 0x66300000 0x00100000
+
+; OpenGL server-side DLL
+glsrv 0x66400000 0x00100000
+
+; kernel-mode user code
+winsrvk 0x66500000 0x00700000
+
+; This space is free!!
+_FREE04_ 0x66c00000 0x00500000
+nddeexts 0x67100000 0x00100000
+sde 0x67200000 0x00100000
+ndrd 0x67300000 0x00100000
+hdxdll 0x67400000 0x00100000
+splexts 0x67500000 0x00100000
+conexts 0x67600000 0x00100000
+gdiexts 0x67700000 0x00100000
+userexts 0x67800000 0x00100000
+; same as userexts
+userkdx 0x67800000 0x00100000
+ntsdexts 0x67900000 0x00100000
+plotter 0x67A00000 0x00100000
+rpcrt4 0x67B00000 0x00100000
+winmm 0x67D00000 0x00100000
+rpcssp 0x67E00000 0x00100000
+mciwave 0x67F00000 0x00100000
+rpclts1 0x68000000 0x00100000
+rpcltc1 0x68100000 0x00100000
+ldrdll 0x68200000 0x00100000
+mcicda 0x68300000 0x00100000
+plotui 0x68400000 0x00100000
+rasddui 0x68500000 0x00100000
+pscrptui 0x68600000 0x00100000
+mmio 0x68700000 0x00100000
+rpcnts1 0x68800000 0x00100000
+rpcntc1 0x68900000 0x00100000
+nlsapi 0x68A00000 0x00100000
+rpcltc6 0x68B00000 0x00100000
+rpclts6 0x68C00000 0x00100000
+olesvr32 0x68D00000 0x00100000
+olecli32 0x68E00000 0x00100000
+msgsvc 0x68F00000 0x00100000
+
+; This space for sale
+decpsmon 0x69000000 0x00100000
+
+sys003 0x69100000 0x00100000
+
+beta2 0x69200000 0x00600000
+psapi 0x69800000 0x00100000
+rpcdce4 0x69900000 0x00100000
+eventlog 0x69A00000 0x00100000
+xactsrv 0x69B00000 0x00100000
+winreg 0x69C00000 0x00100000
+samsrv 0x69D00000 0x00100000
+; same as samsrv
+samlsa 0x69D00000 0x00100000
+mmdrv 0x69F00000 0x00100000
+dlcapi 0x6A000000 0x00100000
+win32spl 0x6A100000 0x00100000
+localspl 0x6A200000 0x00100000
+rpclts5 0x6A300000 0x00100000
+rpcltc5 0x6A400000 0x00100000
+netlogon 0x6A500000 0x00200000
+; same as netlogon
+ntlmsvc 0x6A500000 0x00200000
+tmsre32 0x6A600000 0x00100000
+lsaudll 0x6A700000 0x00100000
+mciseq 0x6A800000 0x00100000
+winprint 0x6A900000 0x00100000
+localmon 0x6AA00000 0x00100000
+msaudite 0x6AB00000 0x00100000
+msobjs 0x6AC00000 0x00100000
+hpmon 0x6AD00000 0x00100000
+alrsvc 0x6AE00000 0x00100000
+srvsvc 0x6AF00000 0x00100000
+wkssvc 0x6B000000 0x00100000
+rpclts3 0x6B100000 0x00100000
+rpcltc3 0x6B200000 0x00100000
+htui 0x6B300000 0x00100000
+lsasrv 0x6B400000 0x00100000
+mmsndsrv 0x6B500000 0x00100000
+midi 0x6B600000 0x00100000
+browser 0x6B700000 0x00100000
+drivers 0x6B800000 0x00100000
+lmmon 0x6B900000 0x00100000
+spoolss 0x6BA00000 0x00100000
+sndblst 0x6BC00000 0x00100000
+opengl32 0x6BD00000 0x00100000
+ntlmssps 0x6BE00000 0x00100000
+glu32 0x6BF00000 0x00100000
+; OpenGL client-side installable driver
+ogldrv 0x6C000000 0x00100000
+
+dciman32 0x6C100000 0x00100000
+
+;
+; The following is an extension for NTSD which traces memory usage in the
+; ULIB utilities...
+;
+memtrace 0x6BF00000 0x00100000
+
+; Cairo Compound Document Forms
+formidbl 0x6C800000 0x00C00000
+fole2ui 0x6D400000 0x00400000
+
+; Windows 95 shell "Sharing" extensions
+ntshrui 0x6D500000 0x00100000
+
+; Win32 shell apps/dlls
+
+control 0x70000000 0x00100000
+access 0x70100000 0x00100000
+sound 0x70200000 0x00100000
+appwiz 0x70300000 0x00100000
+intl 0x70400000 0x00100000
+timedate 0x70500000 0x00100000
+utc 0x70500000 0x00100000
+mouse 0x70600000 0x00100000
+sysdm 0x70700000 0x00100000
+desk 0x70800000 0x00100000
+modem 0x70900000 0x00100000
+security 0x70A00000 0x00100000
+main 0x70B00000 0x00100000
+ups 0x70C00000 0x00100000
+cursors 0x70D00000 0x00100000
+pcmcia 0x70E00000 0x00100000
+comdlg32 0x70F00000 0x00100000
+linkinfo 0x71000000 0x00100000
+version 0x71100000 0x00100000
+comctl32 0x71200000 0x00100000
+nddeapi 0x71300000 0x00100000
+nddenb32 0x71400000 0x00100000
+t1instal 0x71500000 0x00100000
+profile 0x71600000 0x00100000
+mmsys 0x71700000 0x00100000
+ctape 0x71800000 0x00100000
+console 0x71900000 0x00100000
+shscrap 0x71A00000 0x00100000
+password 0x71B00000 0x00100000
+ftsrch 0x71C00000 0x00100000
+docprop 0x71D00000 0x00100000
+shell32 0x71E00000 0x00200000
+shellalt 0x71E00000 0x00200000
+synceng 0x71F00000 0x00080000
+syncui 0x71F80000 0x00080000
+
+; Win32 National Keyboard Layers
+
+kbdus 0x72000000 0x00100000
+kbdbe 0x73000000 0x00100000
+kbdbu 0x73000000 0x00100000
+kbdbr 0x73000000 0x00100000
+kbdca 0x73000000 0x00100000
+kbdcr 0x73000000 0x00100000
+kbdcz 0x73000000 0x00100000
+kbdda 0x73000000 0x00100000
+kbddv 0x73000000 0x00100000
+kbdes 0x73000000 0x00100000
+kbdfc 0x73000000 0x00100000
+kbdfi 0x73000000 0x00100000
+kbdfr 0x73000000 0x00100000
+kbdgr 0x73000000 0x00100000
+kbdhe 0x73000000 0x00100000
+kbdhe220 0x73000000 0x00100000
+kbdhela2 0x73100000 0x00100000
+kbdhe319 0x73000000 0x00100000
+kbdhela3 0x73100000 0x00100000
+kbdhu 0x73000000 0x00100000
+kbdhu1 0x73000000 0x00100000
+kbdic 0x73000000 0x00100000
+kbdit 0x73000000 0x00100000
+kbdit142 0x73000000 0x00100000
+kbdla 0x73000000 0x00100000
+kbdne 0x73000000 0x00100000
+kbdno 0x73000000 0x00100000
+kbdpl 0x73000000 0x00100000
+kbdpl1 0x73000000 0x00100000
+kbdpo 0x73000000 0x00100000
+kbdro 0x73000000 0x00100000
+kbdru 0x73000000 0x00100000
+kbdsf 0x73000000 0x00100000
+kbdsg 0x73000000 0x00100000
+kbdsl 0x73000000 0x00100000
+kbdsp 0x73000000 0x00100000
+kbdsv 0x73000000 0x00100000
+kbdsw 0x73000000 0x00100000
+kbdtuf 0x73000000 0x00100000
+kbdtuq 0x73000000 0x00100000
+kbduk 0x73000000 0x00100000
+kbdusl 0x73000000 0x00100000
+kbdusr 0x73000000 0x00100000
+kbdusx 0x73000000 0x00100000
+kbdhu1 0x73000000 0x00100000
+
+;
+; Cairo ofs dlls
+;
+query 0x74000000 0x00800000
+infosoft 0x74800000 0x00200000
+cxxflt 0x74a00000 0x00200000
+stemdll 0x7d000000 0x00200000
+
+;
+; The following is not currently used until we switch to the new image
+; format with the new section headers.
+;
+executive 0xD0020000 0x18000000
+
+;
+; The following are the Mep extensions
+;
+tglcase 0x09080000 0x00100000
+pmatch 0x09090000 0x00100000
+justify 0x090a0000 0x00100000
+ulcase 0x090b0000 0x00100000
+filter 0x090c0000 0x00100000
+mhelp 0x090d0000 0x00100000
+mepparty 0x090e0000 0x00100000
+srmep 0x090f0000 0x00100000
+mshelp 0x09100000 0x00100000
+mbrowse 0x09110000 0x00100000
+
+;
+; The following are the Z extensions
+;
+zextens 0x09120000 0x00200000
+
+;
+; The following are for the utilities
+;
+ulib 0x09800000 0x00200000
+uhpfs 0x09a10000 0x00100000
+ufat 0x09b20000 0x00100000
+untfs 0x09c30000 0x00100000
+ifsutil 0x09d40000 0x00100000
+cufat 0x09e50000 0x00100000
+cuhpfs 0x09f60000 0x00100000
+fmifs 0x0a070000 0x00100000
+uspifs 0x0a180000 0x00100000
+ureg 0x0a290000 0x00100000
+uofs 0x0a3a0000 0x00400000
+ofsutil 0x0a7b0000 0x00400000
+autoulib 0x0a7b0000 0x00400000
+autouofs 0x0a3a0000 0x00400000
+
+;
+; ofsutil and autoulib are never loaded at the same time
+;
+ulibif 0x0add0000 0x00100000
+cudbfs 0x0aee0000 0x00100000
+
+;
+; The following are for the net error messages
+;
+netmsg 0x09500000 0x00080000
+neth 0x09580000 0x00080000
+netevent 0x09600000 0x00080000
+
+;
+; The following is the I/O error log messages.
+;
+iologmsg 0x09700000 0x00080000
+
+;
+; The following is for the 16-bit loader for the OS/2 subsystem
+;
+loader 0x20000000 0x01000000
+
+;
+; The following is for the PE format image help routines.
+;
+
+imagehlp 0x20000000 0x01000000
+symhelp 0x21000000 0x01000000
+
+;
+; The following is for the Streams/Sockets dll's
+;
+wsock32 0x75000000 0x00400000
+winstrm 0x75400000 0x00100000
+inetmib1 0x75500000 0x00100000
+lmmib2 0x75600000 0x00100000
+tcpipsvc 0x75700000 0x00100000
+nbtsvc 0x75800000 0x00100000
+telnet 0x75900000 0x00100000
+wshtcpip 0x75a00000 0x00100000
+mgmtapi 0x75b00000 0x00100000
+icmp 0x75c00000 0x00100000
+inettrap 0x75d00000 0x00100000
+testdll 0x75e00000 0x00100000
+lmhsvc 0x75f00000 0x00100000
+dhcpsapi 0x76000000 0x00100000
+dhcpcsvc 0x76100000 0x00100000
+dhcpssvc 0x76200000 0x00100000
+tcpsvcs 0x76300000 0x00100000
+ftpsvc 0x76400000 0x00100000
+ftpsvapi 0x76500000 0x00100000
+ftpctrs 0x76600000 0x00100000
+
+;
+; The following are for rpc datagram transport modules
+;
+
+rpcdgc3 0x76700000 0x00100000
+rpcdgs3 0x76800000 0x00100000
+rpcdgc6 0x76900000 0x00100000
+rpcdgs6 0x76a00000 0x00100000
+
+;
+; The following are for RPC ADSP transport interface modules
+;
+
+rpcltc7 0X76b00000 0x00100000
+rpclts7 0X76c00000 0x00100000
+
+;
+; The following are for the HTTP (WWW) server
+;
+
+w3svc 0x76d00000 0x00100000
+w3svapi 0x76e00000 0x00100000
+w3ctrs 0x76f00000 0x00100000
+httpodbc 0x77700000 0x00100000
+
+;
+; The following are for Gopher Service
+;
+
+gopherd 0x77000000 0x00100000
+gdapi 0x77100000 0x00100000
+gdctrs 0x77200000 0x00100000
+gdspace 0x77300000 0x00100000
+
+;
+; The following are Internet services common dlls
+;
+
+tcpsvcs 0x77400000 0x00100000
+inetasrv 0x77500000 0x00100000
+inetctrs 0x77600000 0x00100000
+;used 0x77700000 0x00100000
+
+;
+; Smalprox dlls (client side internet proxy)
+;
+
+miniprox 0x77800000 0x00100000
+_wsock32 0x77900000 0x00080000
+wsock32f 0x77980000 0x00080000
+
+;
+; The following are for the windowed debugger (windbg)
+;
+
+eecxxx86 0x40000000 0x00200000
+eecxxmip 0x40000000 0x00200000
+eecxxalp 0x40000000 0x00200000
+eecxxppc 0x40000000 0x00200000
+eecxx 0x40000000 0x00200000
+emx86 0x48000000 0x00200000
+emmip 0x48000000 0x00200000
+emalp 0x48000000 0x00200000
+emppc 0x48000000 0x00200000
+shcoff 0x50000000 0x00200000
+shcv 0x50000000 0x00200000
+tlloc 0x58000000 0x00200000
+tlser 0x58000000 0x00200000
+tlser32s 0x58000000 0x00200000
+tlser32 0x58000000 0x00200000
+tlpipe 0x58000000 0x00200000
+dm 0x58200000 0x00200000
+dm32s 0x58200000 0x00200000
+dmkdx86 0x58200000 0x00200000
+dmkdmip 0x58200000 0x00200000
+dmkdalp 0x58200000 0x00200000
+dmkdppc 0x58200000 0x00200000
+kdextx86 0x58400000 0x00200000
+kdextmip 0x58400000 0x00200000
+kdextalp 0x58400000 0x00200000
+kdextppc 0x58400000 0x00200000
+
+;
+; The following are for the NetUI components.
+;
+
+acledit 0x58500000 0x00200000
+mpr 0x58700000 0x00100000
+ntlanman 0x58800000 0x00200000
+srvmgr 0x58a00000 0x00200000
+ncpa 0x58c00000 0x00200000
+mprui 0x58e00000 0x00200000
+netui0 0x59000000 0x00200000
+netui1 0x59200000 0x00300000
+netui2 0x59500000 0x00400000
+ftpsmx 0x59900000 0x00100000
+ftpmgr 0x59a00000 0x00100000
+nwcfg 0x59b00000 0x00100000
+ntlanui 0x59c00000 0x00200000
+tcpcfg 0x59e00000 0x00100000
+ipxcfg 0x59f00000 0x00100000
+ntlsapi 0x5a000000 0x00100000
+srvkd 0x5b000000 0x00100000
+llsrpc 0x5c000000 0x00100000
+
+;
+; Network Card detection
+;
+netdtect 0x79000000 0x00100000
+msncdet 0x79100000 0x00100000
+npincdet 0x79200000 0x00100000
+amdncdet 0x79300000 0x00100000
+netflx 0x79400000 0x00100000
+
+;
+; Bloodhound components
+;
+bhsupp 0x79700000 0x00100000
+nal 0x79800000 0x00100000
+bhmon 0x79900000 0x00100000
+ndis30 0x79A00000 0x00100000
+bhnetb 0x79B00000 0x00100000
+rnal 0x79C00000 0x00100000
+bhkctrl 0x79D00000 0x00100000
+;
+; Nw components
+;
+nwsap 0x7A100000 0x00100000
+
+
+;
+; Ports applet
+;
+port 0x73600000 0x00200000
+
+;
+; System applet
+;
+
+system 0x73800000 0x00200000
+
+; more Cairo control panel components
+
+cpprint 0x73A00000 0x00100000
+cpups 0x73B00000 0x00100000
+cpsrvcs 0x74c00000 0x00100000
+
+;
+; DS object property pages.
+;
+
+dsui 0x73C00000 0x00400000
+
+;
+; DS Container object class
+;
+
+dscont 0x7C800000 0x00100000
+
+;
+;
+; jet blue dll.
+;
+
+jet 0x7B100000 0x00400000
+
+
+;
+; wins dlls
+;
+winsctrs 0x7C100000 0x00100000
+winsmib 0x7C200000 0x00200000
+dhcpmib 0x7C400000 0x00100000
+winsevnt 0x7C500000 0x00100000
+winsrpc 0x7C600000 0x00100000
+winsrpcb 0x7C700000 0x00100000
+
+;
+; The following are for the SCC filters used by the Content index
+;
+SCCUT 0x7d500000 0x00040000
+SCCFA 0x7d540000 0x00040000
+SCCFI 0x7d580000 0x00040000
+SCCIFILT 0x7d600000 0x00040000
+VSACS 0x7d640000 0x00040000
+VSBMP 0x7d640000 0x00040000
+VSDBS 0x7d640000 0x00040000
+VSDRW 0x7d640000 0x00040000
+VSEXE 0x7d640000 0x00040000
+VSGIF 0x7d640000 0x00040000
+VSMCW 0x7d640000 0x00040000
+VSMSW 0x7d640000 0x00040000
+VSMWP2 0x7d640000 0x00040000
+VSMWPF 0x7d640000 0x00040000
+VSPCL 0x7d640000 0x00040000
+VSPDX 0x7d640000 0x00040000
+VSPFS 0x7d640000 0x00040000
+VSPP 0x7d640000 0x00040000
+VSQPW 0x7d640000 0x00040000
+VSRTF 0x7d640000 0x00040000
+VSTIFF 0x7d640000 0x00040000
+VSTEXT 0x7d640000 0x00040000
+VSTXT 0x7d640000 0x00040000
+VSVW3 0x7d640000 0x00040000
+VSW6 0x7d640000 0x00040000
+VSWKS 0x7d640000 0x00040000
+VSWMF 0x7d640000 0x00040000
+VSWORD 0x7d640000 0x00040000
+VSWORK 0x7d640000 0x00040000
+VSWP5 0x7d640000 0x00040000
+VSWP6 0x7d640000 0x00040000
+VSWPF 0x7d640000 0x00040000
+VSXL5 0x7d640000 0x00040000
+VSXY 0x7d640000 0x00040000
+
+;
+; MFC Dlls
+;
+CFM30 0x7d680000 0x00200000
+CFM30U 0x7d680000 0x00200000
+CFMO30 0x7d880000 0x00080000
+CFMO30U 0x7d880000 0x00080000
+NTCTL3D 0x7D900000 0x00010000
+
+
diff --git a/private/utils/ntbackup/exchange/build/i386mk.inc b/private/utils/ntbackup/exchange/build/i386mk.inc
new file mode 100644
index 000000000..91326b37a
--- /dev/null
+++ b/private/utils/ntbackup/exchange/build/i386mk.inc
@@ -0,0 +1,247 @@
+!IF 0
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ i386mk.inc
+
+Abstract:
+
+ This module contains the x86 specific build controls. It is included
+ by makefile.def.
+
+Author:
+
+ Jeff Havens (jhavens) 13-Feb-1994
+
+Revision History:
+
+!ENDIF
+
+#
+# x86 option control
+#
+
+UMBASE=$(UMBASE:*=i386)
+UMLIBS=$(UMLIBS:*=i386)
+NTRES=$(NTRES:*=i386)
+UMRES=$(UMRES:*=i386)
+UMOBJS=$(UMOBJS:*=i386)
+LINKLIBS=$(LINKLIBS:*=i386)
+DLLBASE=$(DLLBASE:*=i386)
+DLLDEF=$(DLLDEF:*=i386)
+MACHINE_TARGETLIBS=$(MACHINE_TARGETLIBS:*=i386)
+TARGET=$(TARGET:*=i386)
+DYNLINK_LIB=$(DYNLINK_LIB:*=i386)
+TARGETEXEFILES=$(TARGETEXEFILES:*=i386)
+TARGETLIBFILES=$(TARGETLIBFILES:*=i386)
+TARGETOBJFILES=$(TARGETOBJFILES:*=i386)
+UMOBJFILES=$(UMOBJFILES:*=i386)
+UMEXEFILES=$(UMEXEFILES:*=i386)
+HEADERFILE=$(HEADERFILE:*=i386)
+HEADEROBJNAME=$(HEADEROBJNAME:*=i386)
+HEADEROBJ=$(HEADEROBJ:*=i386)
+PRECOMPILED=$(PRECOMPILED:*=i386)
+PRECOMPILED_CXX=$(PRECOMPILED_CXX:*=i386)
+PRECOMPILED_TARGET=$(PRECOMPILED_TARGET:*=i386)
+
+!ifdef NTTARGETFILES
+NTTARGETFILES=$(NTTARGETFILES:*=i386)
+!endif
+!ifdef NTTARGETFILE0
+NTTARGETFILE0=$(NTTARGETFILE0:*=i386)
+!endif
+!ifdef NTTARGETFILE1
+NTTARGETFILE1=$(NTTARGETFILE1:*=i386)
+!endif
+
+!IF "$(DLLENTRY)" != "-noentry"
+DLLENTRY=$(DLLENTRY)@12
+!ENDIF
+
+!IFDEF STD_CALL_ENTRY
+UMENTRY=$(UMENTRY)@4
+!ENDIF
+
+ENTRY_SUFFIX=@8
+GDI_ENTRY_SUFFIX=@12
+
+!IFDEF 386_WARNING_LEVEL
+MSC_WARNING_LEVEL=$(386_WARNING_LEVEL)
+!ENDIF
+!IFDEF 386_OPTIMIZATION
+MSC_OPTIMIZATION=$(386_OPTIMIZATION)
+!message $(MAKEDIR)\sources (1) : Overriding default optimizations with $(386_OPTIMIZATION)
+!ELSE
+!IF "$(CBSTRING)" == ""
+MSC_OPTIMIZATION=$(MSC_OPTIMIZATION) /Gf /QI6
+!ELSE
+MSC_OPTIMIZATION=$(MSC_OPTIMIZATION) /QI6
+!ENDIF
+!ENDIF
+!IFDEF 386_CPPFLAGS
+MSC_CPPFLAGS=$(386_CPPFLAGS)
+!ENDIF
+
+STDFLAGS= /c /Zel /Zp8 /Gy $(CBSTRING) $(MSC_WARNING_LEVEL) $(MSC_CALL_TYPE) /G4 $(MFC_FLAGS)
+
+#LINKLIBS=$(LINKLIBS) $(BASEDIR)\public\sdk\lib\i386\int64.lib
+
+!IF "$(TARGETTYPE)"=="DRIVER" || \
+ "$(TARGETTYPE)"=="GDI_DRIVER" || \
+ "$(TARGETTYPE)"=="MINIPORT"
+#
+#Drivers don't link with link libs.
+#
+
+MACHINE_TARGETLIBS=$(MACHINE_TARGETLIBS) $(BASEDIR)\public\sdk\lib\i386\int64.lib
+!ENDIF
+
+!IF "$(386_STDCALL)" == "0"
+MSC_CALL_TYPE=/Gd
+MSC_CALL_DEFINE=
+!ELSE
+! IF "$(386_STDCALL)" == "2"
+MSC_CALL_TYPE=/Gr
+MSC_CALL_DEFINE=
+! ELSE
+MSC_CALL_TYPE=/Gz
+MSC_CALL_DEFINE=-DSTD_CALL
+! ENDIF
+!ENDIF
+
+!IF "$(NTDEBUG)" == "retail" || "$(NTDEBUG)" == ""
+! IFDEF NTNOFPO
+!MESSAGE $(NTMAKEENV)\i386mk.inc(1) : Overriding FPO default with NTNOFPO
+TARGET_DBG_DEFINES= $(TARGET_DBG_DEFINES) -DFPO=0
+DBGFLAGS=$(DBGFLAGS) /Oy-
+! ELSE
+TARGET_DBG_DEFINES= $(TARGET_DBG_DEFINES) -DFPO=1
+DBGFLAGS=$(DBGFLAGS) /Oy
+! ENDIF
+!ELSE
+TARGET_DBG_DEFINES= $(TARGET_DBG_DEFINES) -DFPO=0
+DBGFLAGS=$(DBGFLAGS) /Oy-
+386_ADBGFLAGS=$(386_ADBGFLAGS) /Zi
+!ENDIF
+
+# Use /Z7 instead of /Zi
+
+DBGFLAGS=$(DBGFLAGS:/Zi=/Z7)
+
+!IFDEF NTLEGO
+DBGFLAGS=$(DBGFLAGS) /Z7
+386_ADBGFLAGS=$(386_ADBGFLAGS) /Zi
+LINKER_FLAGS=$(LINKER_FLAGS) -debug:full -debugtype:cv,fixup
+LINKER_MERGE_RDATA=
+!ENDIF
+
+!IF "$(BROWSER_INFO)" == "yes"
+BROWSER= -FR$*.sbr
+!ELSE
+BROWSER=
+!ENDIF
+
+
+#
+# 386 option control
+#
+
+ENV_DEFINES= $(MSC_CPPFLAGS) $(NTCPPFLAGS)
+
+!IF "$(HALTYPE)" == ""
+HALDEF=
+!ELSE
+HALDEF=-D$(HALTYPE)=1
+!ENDIF
+
+STD_DEFINES= -D_X86_=1 -Di386=1 $(HALDEF) $(MSC_CALL_DEFINE) $(STD_DEFINES)
+
+CDEFINES=$(STD_DEFINES) $(TARGET_DBG_DEFINES) $(ENV_DEFINES) \
+ $(LIBC_DEFINES) $(C_DEFINES) $(NET_C_DEFINES)
+CFLAGS=$(386_FLAGS) $(NT386FLAGS) $(STDFLAGS) $(DBGFLAGS) \
+ $(BROWSER) $(386_PERFFLAGS) $(USER_C_FLAGS)
+386_ASMFLAGS=$(386_ADBGFLAGS) $(BROWSER) $(STD_DEFINES) \
+ $(TARGET_DBG_DEFINES) $(ENV_DEFINES) $(ASM_DEFINES)
+
+386_CDEFINES=$(CDEFINES)
+386_CFLAGS=$(CFLAGS)
+
+CC_NAME = cl -nologo
+
+C_COMPILER_NAME = $(CC_NAME)
+CXX_COMPILER_NAME = $(CC_NAME)
+C_PREPROCESSOR_NAME = $(CC_NAME)
+
+GLOBAL_C_FLAGS = -Ii386\ -I. $(INCPATH1) $(CDEFINES) $(CFLAGS)
+
+C_COMPILER_FLAGS = $(GLOBAL_C_FLAGS) $(PRECOMPILED) $(COMPILER_WARNINGS)
+CXX_COMPILER_FLAGS = $(GLOBAL_C_FLAGS) $(PRECOMPILED_CXX) $(COMPILER_WARNINGS)
+C_PREPROCESSOR_FLAGS = $(GLOBAL_C_FLAGS) -EP -Tc
+
+C_COMPILER = $(C_COMPILER_NAME) $(C_COMPILER_FLAGS)
+CXX_COMPILER = $(CXX_COMPILER_NAME) $(CXX_COMPILER_FLAGS)
+C_PREPROCESSOR = $(C_PREPROCESSOR_NAME) $(C_PREPROCESSOR_FLAGS)
+
+386_ASSEMBLER=ml -c -coff -Cx -nologo -Ii386\ -I. $(INCPATH1) -Zm $(386_ASMFLAGS)
+
+ECHO_MSG=$(C_COMPILER) $<
+ECHO_PRECOMPILED_MSG=$(C_COMPILER) /Yl$(TARGETNAME) $(HEADERFILE) $(HEADEROBJ) $(PRECOMPILED_FLAG) $(PRECOMPILED_INCLUDE)
+
+{}.c{}.asm:
+ $(C_COMPILER_NAME) @<< /Fa $(MAKEDIR)\$(<F)
+$(C_COMPILER_FLAGS: =
+)
+<<NOKEEP
+
+{..\i386\}.asm{}.lst:
+ $(386_ASSEMBLER) /Fl$@ /Foobj\i386\$(@B).obj $<
+
+{i386\}.asm{}.lst:
+ $(386_ASSEMBLER) /Fl$@ /Fo$(MAKEDIR)\obj\i386\$(@B).obj $<
+
+{..\i386\}.asm{obj\i386\}.obj:
+ $(386_ASSEMBLER) -Fo$(MAKEDIR)\$@ $<
+
+{i386\}.asm{obj\i386\}.obj:
+ $(386_ASSEMBLER) -Fo$(MAKEDIR)\$@ $<
+
+LINKFLAGS=$(LNKFLAGS)
+
+LIBRARY_OBJS=$(LINKLIBS) $(OBJECTS)
+
+!IFDEF TUKWILA
+_NTTREE=$(_NT386TREE)
+!ENDIF
+
+!IF DEFINED (CAIRO_PRODUCT)
+! IF DEFINED (_CAIRO386TREE)
+_NTTREE=$(_CAIRO386TREE)
+! ENDIF
+!ELSEIF DEFINED (CHICAGO_PRODUCT)
+! IF DEFINED (_CHICAGO386TREE)
+_NTTREE=$(_CHICAGO386TREE)
+! elseif defined(_NT386TREE)
+_NTTREE=$(_NT386TREE)
+! ENDIF
+!ELSEIF DEFINED (_NT386TREE)
+_NTTREE=$(_NT386TREE)
+!ENDIF
+
+!IFDEF KERNEL_MODE
+_NTTREE=$(_NT386TREE)\km
+!ENDIF
+
+!IFDEF _NT386LIBS
+_NTLIBS=$(_NT386LIBS)
+!ENDIF
+
+COPYDST=$(386COPYDST)
+LIB_COPY=nti386cp.cmd
+
+!IF "$(NTDEBUGTYPE)" == "windbg" || "$(NTDEBUGTYPE)" == "both"
+NTTEST_LINK_OPTIONS=-entry:main
+!ELSE
+NTTEST_LINK_OPTIONS=-fixed -base:0x80100000 -entry:main
+!ENDIF
diff --git a/private/utils/ntbackup/exchange/build/inc/common.ver b/private/utils/ntbackup/exchange/build/inc/common.ver
new file mode 100644
index 000000000..00c8f6b17
--- /dev/null
+++ b/private/utils/ntbackup/exchange/build/inc/common.ver
@@ -0,0 +1,96 @@
+
+/*---------------------------------------------------------------*/
+/* */
+/* The following section actually creates the version structure. */
+/* They are ignored if we are not being invoked by RC. */
+/* */
+/* ntverp.H must be included before including this file */
+/* */
+/* If VER_LEGALCOPYRIGHT_STR is not defined, it will be */
+/* constructed using VER_LEGALCOPYRIGHT_YEARS, so at least one */
+/* these macros must be defined before including this file. */
+/* */
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR, and */
+/* VER_INTERNALNAME_STR must be defined before including this */
+/* file. */
+/* */
+/* If VER_FILEVERSION is not defined, VER_PRODUCTVERSION will be */
+/* used instead. If VER_FILEVERSION_STR is not defined, */
+/* VER_PRODUCTVERSION_STR will be used instead. */
+/* */
+/* If VER_ORIGINALFILENAME_STR is not defined, it is set to */
+/* the value in VER_INTERNALNAME_STR. */
+/* */
+/* If INTL is defined, then this is assumed to be an */
+/* an international build; two string blocks will be created, */
+/* (since all version resources must have English), and the */
+/* second one can be localized */
+/* */
+/*---------------------------------------------------------------*/
+
+#ifdef RC_INVOKED
+
+#ifndef VER_LEGALCOPYRIGHT_YEARS
+#define VER_LEGALCOPYRIGHT_YEARS "1981-1995"
+#endif
+
+#ifndef VER_LEGALCOPYRIGHT_STR
+#define VER_LEGALCOPYRIGHT_STR "Copyright \251 Microsoft Corp. " VER_LEGALCOPYRIGHT_YEARS
+#endif
+
+#ifndef VER_PRODUCTNAME_STR
+#define VER_PRODUCTNAME_STR "Microsoft\256 Windows NT(TM) Operating System"
+#endif
+
+#ifndef VER_PRODUCTVERSION
+#define VER_PRODUCTVERSION 4,00,01,552
+#endif
+
+#ifndef VER_FILEVERSION
+#define VER_FILEVERSION VER_PRODUCTVERSION
+#endif
+
+#ifndef VER_PRODUCTVERSION_STR
+#define VER_PRODUCTVERSION_STR "4.00"
+#endif
+
+#ifndef VER_FILEVERSION_STR
+#define VER_FILEVERSION_STR VER_PRODUCTVERSION_STR
+#endif
+
+#ifndef VER_ORIGINALFILENAME_STR
+#define VER_ORIGINALFILENAME_STR VER_INTERNALNAME_STR
+#endif
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION VER_FILEVERSION
+PRODUCTVERSION VER_PRODUCTVERSION
+FILEFLAGSMASK VER_FILEFLAGSMASK
+FILEFLAGS VER_FILEFLAGS
+FILEOS VER_FILEOS
+FILETYPE VER_FILETYPE
+FILESUBTYPE VER_FILESUBTYPE
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904B0" /* LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP */
+ BEGIN
+ VALUE "CompanyName", VER_COMPANYNAME_STR
+ VALUE "FileDescription", VER_FILEDESCRIPTION_STR
+ VALUE "FileVersion", VER_FILEVERSION_STR
+ VALUE "InternalName", VER_INTERNALNAME_STR
+ VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR
+ VALUE "OriginalFilename",VER_ORIGINALFILENAME_STR
+ VALUE "ProductName", VER_PRODUCTNAME_STR
+ VALUE "ProductVersion", VER_PRODUCTVERSION_STR
+ END
+
+ END
+
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0409, 0x04B0
+ END
+END
+
+#endif
diff --git a/private/utils/ntbackup/exchange/build/inc/ntddscsi.h b/private/utils/ntbackup/exchange/build/inc/ntddscsi.h
new file mode 100644
index 000000000..332821056
--- /dev/null
+++ b/private/utils/ntbackup/exchange/build/inc/ntddscsi.h
@@ -0,0 +1,229 @@
+/*++ BUILD Version: 0001 // Increment this if a change has global effects
+
+Copyright (c) 1990-1993 Microsoft Corporation
+
+Module Name:
+
+ ntddscsi.h
+
+Abstract:
+
+ This is the include file that defines all constants and types for
+ accessing the SCSI port adapters.
+
+Author:
+
+ Jeff Havens
+
+Revision History:
+
+--*/
+
+#ifndef _NTDDSCSIH_
+#define _NTDDSCSIH_
+
+//
+// Device Name - this string is the name of the device. It is the name
+// that should be passed to NtOpenFile when accessing the device.
+//
+// Note: For devices that support multiple units, it should be suffixed
+// with the Ascii representation of the unit number.
+//
+
+#define IOCTL_SCSI_BASE FILE_DEVICE_CONTROLLER
+
+#define DD_SCSI_DEVICE_NAME "\\Device\\ScsiPort"
+
+
+//
+// NtDeviceIoControlFile IoControlCode values for this device.
+//
+// Warning: Remember that the low two bits of the code specify how the
+// buffers are passed to the driver!
+//
+
+#define IOCTL_SCSI_PASS_THROUGH CTL_CODE(IOCTL_SCSI_BASE, 0x0401, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_SCSI_MINIPORT CTL_CODE(IOCTL_SCSI_BASE, 0x0402, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_SCSI_GET_INQUIRY_DATA CTL_CODE(IOCTL_SCSI_BASE, 0x0403, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SCSI_GET_CAPABILITIES CTL_CODE(IOCTL_SCSI_BASE, 0x0404, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SCSI_PASS_THROUGH_DIRECT CTL_CODE(IOCTL_SCSI_BASE, 0x0405, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_SCSI_GET_ADDRESS CTL_CODE(IOCTL_SCSI_BASE, 0x0406, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SCSI_RESCAN_BUS CTL_CODE(IOCTL_SCSI_BASE, 0x0407, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_SCSI_GET_DUMP_POINTERS CTL_CODE(IOCTL_SCSI_BASE, 0x0408, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+//
+// Define the SCSI pass through structure.
+//
+
+typedef struct _SCSI_PASS_THROUGH {
+ USHORT Length;
+ UCHAR ScsiStatus;
+ UCHAR PathId;
+ UCHAR TargetId;
+ UCHAR Lun;
+ UCHAR CdbLength;
+ UCHAR SenseInfoLength;
+ UCHAR DataIn;
+ ULONG DataTransferLength;
+ ULONG TimeOutValue;
+ ULONG DataBufferOffset;
+ ULONG SenseInfoOffset;
+ UCHAR Cdb[16];
+}SCSI_PASS_THROUGH, *PSCSI_PASS_THROUGH;
+
+//
+// Define the SCSI pass through direct structure.
+//
+
+typedef struct _SCSI_PASS_THROUGH_DIRECT {
+ USHORT Length;
+ UCHAR ScsiStatus;
+ UCHAR PathId;
+ UCHAR TargetId;
+ UCHAR Lun;
+ UCHAR CdbLength;
+ UCHAR SenseInfoLength;
+ UCHAR DataIn;
+ ULONG DataTransferLength;
+ ULONG TimeOutValue;
+ PVOID DataBuffer;
+ ULONG SenseInfoOffset;
+ UCHAR Cdb[16];
+}SCSI_PASS_THROUGH_DIRECT, *PSCSI_PASS_THROUGH_DIRECT;
+
+//
+// Define SCSI information.
+// Used with the IOCTL_SCSI_GET_INQUIRY_DATA IOCTL.
+//
+
+typedef struct _SCSI_BUS_DATA {
+ UCHAR NumberOfLogicalUnits;
+ UCHAR InitiatorBusId;
+ ULONG InquiryDataOffset;
+}SCSI_BUS_DATA, *PSCSI_BUS_DATA;
+
+//
+// Define SCSI adapter bus information structure..
+// Used with the IOCTL_SCSI_GET_INQUIRY_DATA IOCTL.
+//
+
+typedef struct _SCSI_ADAPTER_BUS_INFO {
+ UCHAR NumberOfBuses;
+ SCSI_BUS_DATA BusData[1];
+} SCSI_ADAPTER_BUS_INFO, *PSCSI_ADAPTER_BUS_INFO;
+
+//
+// Define SCSI adapter bus information.
+// Used with the IOCTL_SCSI_GET_INQUIRY_DATA IOCTL.
+//
+
+typedef struct _SCSI_INQUIRY_DATA {
+ UCHAR PathId;
+ UCHAR TargetId;
+ UCHAR Lun;
+ BOOLEAN DeviceClaimed;
+ ULONG InquiryDataLength;
+ ULONG NextInquiryDataOffset;
+ UCHAR InquiryData[1];
+}SCSI_INQUIRY_DATA, *PSCSI_INQUIRY_DATA;
+
+//
+// Define header for I/O control SRB.
+//
+
+typedef struct _SRB_IO_CONTROL {
+ ULONG HeaderLength;
+ UCHAR Signature[8];
+ ULONG Timeout;
+ ULONG ControlCode;
+ ULONG ReturnCode;
+ ULONG Length;
+} SRB_IO_CONTROL, *PSRB_IO_CONTROL;
+
+//
+// SCSI port driver capabilities structure.
+//
+
+typedef struct _IO_SCSI_CAPABILITIES {
+
+ //
+ // Length of this structure
+ //
+
+ ULONG Length;
+
+ //
+ // Maximum transfer size in single SRB
+ //
+
+ ULONG MaximumTransferLength;
+
+ //
+ // Maximum number of physical pages per data buffer
+ //
+
+ ULONG MaximumPhysicalPages;
+
+ //
+ // Async calls from port to class
+ //
+
+ ULONG SupportedAsynchronousEvents;
+
+ //
+ // Alignment mask for data transfers.
+ //
+
+ ULONG AlignmentMask;
+
+ //
+ // Supports tagged queuing
+ //
+
+ BOOLEAN TaggedQueuing;
+
+ //
+ // Host adapter scans down for bios devices.
+ //
+
+ BOOLEAN AdapterScansDown;
+
+ //
+ // The host adapter uses programmed I/O.
+ //
+
+ BOOLEAN AdapterUsesPio;
+
+} IO_SCSI_CAPABILITIES, *PIO_SCSI_CAPABILITIES;
+
+typedef struct _SCSI_ADDRESS {
+ ULONG Length;
+ UCHAR PortNumber;
+ UCHAR PathId;
+ UCHAR TargetId;
+ UCHAR Lun;
+}SCSI_ADDRESS, *PSCSI_ADDRESS;
+
+//
+// Define structure for returning crash dump pointers.
+//
+
+typedef struct _ADAPTER_OBJECT;
+
+typedef struct _DUMP_POINTERS {
+ struct _ADAPTER_OBJECT *AdapterObject;
+ PVOID MappedRegisterBase;
+ PVOID PortConfiguration;
+ PVOID CommonBufferVa;
+ LARGE_INTEGER CommonBufferPa;
+ ULONG CommonBufferSize;
+} DUMP_POINTERS, *PDUMP_POINTERS;
+
+//
+// Define values for pass-through DataIn field.
+//
+
+#define SCSI_IOCTL_DATA_OUT 0
+#define SCSI_IOCTL_DATA_IN 1
+#define SCSI_IOCTL_DATA_UNSPECIFIED 2
+#endif
diff --git a/private/utils/ntbackup/exchange/build/inc/ntverp.h b/private/utils/ntbackup/exchange/build/inc/ntverp.h
new file mode 100644
index 000000000..e36cae5ed
--- /dev/null
+++ b/private/utils/ntbackup/exchange/build/inc/ntverp.h
@@ -0,0 +1,47 @@
+/****************************************************************************
+ * *
+ * ntverp.H -- Version information for internal builds *
+ * *
+ * This file is only modified by the official builder to update the *
+ * VERSION, VER_PRODUCTVERSION, VER_PRODUCTVERSION_STR and *
+ * VER_PRODUCTBETA_STR values. *
+ * *
+ ****************************************************************************/
+
+/*--------------------------------------------------------------*/
+/* the following values should be modified by the official */
+/* builder for each build */
+/*--------------------------------------------------------------*/
+
+#define VER_PRODUCTBUILD 599
+#define VER_PRODUCTVERSION_STR "4.00"
+#define VER_PRODUCTVERSION 4,00,VER_PRODUCTBUILD,1
+#define VER_PRODUCTBETA_STR ""
+
+/*--------------------------------------------------------------*/
+/* the following section defines values used in the version */
+/* data structure for all files, and which do not change. */
+/*--------------------------------------------------------------*/
+
+/* default is nodebug */
+#if DBG
+#define VER_DEBUG VS_FF_DEBUG
+#else
+#define VER_DEBUG 0
+#endif
+
+/* default is prerelease */
+#if BETA
+#define VER_PRERELEASE VS_FF_PRERELEASE
+#else
+#define VER_PRERELEASE 0
+#endif
+
+#define VER_FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#define VER_FILEOS VOS_NT_WINDOWS32
+#define VER_FILEFLAGS (VER_PRERELEASE|VER_DEBUG)
+
+#define VER_COMPANYNAME_STR "Microsoft Corporation"
+#define VER_PRODUCTNAME_STR "Microsoft\256 Windows NT(TM) Operating System"
+#define VER_LEGALTRADEMARKS_STR \
+"Microsoft\256 is a registered trademark of Microsoft Corporation. Windows NT(TM) is a trademark of Microsoft Corporation."
diff --git a/private/utils/ntbackup/exchange/build/inc/pcrt32.h b/private/utils/ntbackup/exchange/build/inc/pcrt32.h
new file mode 100644
index 000000000..9a6e59aec
--- /dev/null
+++ b/private/utils/ntbackup/exchange/build/inc/pcrt32.h
@@ -0,0 +1,39 @@
+/*
+ * porting macros for c runtimes - use these to let 16 bit crt calls work
+ * properly on 32 bit code.
+ */
+
+
+#define _ffree free
+#define _fmalloc malloc
+#define _fmemccpy memccpy
+#define _fmemchr memchr
+#define _fmemcmp memcmp
+#define _fmemcpy memcpy
+#define _fmemicmp memicmp
+#define _fmemmove memmove
+#define _fmemset memset
+#define _frealloc realloc
+#define _fstrcat strcat
+#define _fstrchr strchr
+#define _fstrcmp strcmp
+#define _fstrcpy strcpy
+#define _fstrcspn strcspn
+#define _fstrdup strdup
+#define _fstricmp stricmp
+#define _fstrlen strlen
+#define _fstrlwr strlwr
+#define _fstrncat strncat
+#define _fstrncmp strncmp
+#define _fstrncpy strncpy
+#define _fstrnicmp strnicmp
+#define _fstrnset strnset
+#define _fstrpbrk strpbrk
+#define _fstrrchr strrchr
+#define _fstrrev strrev
+#define _fstrset strset
+#define _fstrspn strspn
+#define _fstrstr strstr
+#define _fstrtok strtok
+#define _fstrupr strupr
+
diff --git a/private/utils/ntbackup/exchange/build/inc/plan32.h b/private/utils/ntbackup/exchange/build/inc/plan32.h
new file mode 100644
index 000000000..728c0d82e
--- /dev/null
+++ b/private/utils/ntbackup/exchange/build/inc/plan32.h
@@ -0,0 +1,14 @@
+/*****************************************************************************\
+* PLAN32.H - PORTABILITY MAPPING HEADER FILE
+*
+* This file provides macros to map portable lanman code to its 32 bit form.
+\*****************************************************************************/
+
+
+/*----------------------------------LANMAN----------------------------------*/
+
+/* LANMAN MACROS: */
+
+#define COPYTOARRAY(pDest, pSource) pDest = pSource
+
+/* LANMAN API: */
diff --git a/private/utils/ntbackup/exchange/build/inc/port1632.h b/private/utils/ntbackup/exchange/build/inc/port1632.h
new file mode 100644
index 000000000..d24831d19
--- /dev/null
+++ b/private/utils/ntbackup/exchange/build/inc/port1632.h
@@ -0,0 +1,40 @@
+/***************************************************************************\
+* Module Name: 1632PORT.H
+*
+* Copyright (c) 1985-1993, Microsoft Corporation
+*
+* Master include file for Portable Windows applications.
+*
+* History:
+* sanfords 1/10/91 Created
+*
+\***************************************************************************/
+
+/*
+ * This file maps a Meta-API for Windows to specific 16-bit or 32-bit forms
+ * allowing a single portable C source for windows to work on multiple
+ * versions of Windows.
+ */
+
+#ifndef _PORT1632_
+#define _PORT1632_
+
+#if defined(WIN16)
+/* ---------------- Maps to windows 3.0 and 3.1 16-bit APIs ----------------*/
+#include "ptypes16.h"
+#include "pwin16.h"
+#include "plan16.h"
+/* -------------------------------------------------------------------------*/
+
+#elif defined(WIN32)
+/* ---------------- Maps to windows 3.2 and 4.0 32-bit APIs ----------------*/
+#include "ptypes32.h"
+#include "pcrt32.h"
+#include "pwin32.h"
+#include "plan32.h"
+/* -------------------------------------------------------------------------*/
+#else
+#error You must define either WIN32 or WIN16
+#endif /* WIN32 or WIN16 */
+#endif /* ndef _PORT1632_ */
+
diff --git a/private/utils/ntbackup/exchange/build/inc/ptypes32.h b/private/utils/ntbackup/exchange/build/inc/ptypes32.h
new file mode 100644
index 000000000..8b2118b09
--- /dev/null
+++ b/private/utils/ntbackup/exchange/build/inc/ptypes32.h
@@ -0,0 +1,62 @@
+/*****************************************************************************\
+* PTYPES32.H - PORTABILITY MAPPING HEADER FILE
+*
+* This file provides types for 16/32 bit portable code.
+\*****************************************************************************/
+
+#include <setjmp.h>
+
+/* TYPES: */
+
+#define HUGE_T
+typedef DWORD WORD2DWORD ;
+typedef DWORD CHARPARM ;
+typedef DWORD SHORTPARM ;
+typedef DWORD VERSION ;
+typedef LPSTR PDLLMEM ;
+typedef unsigned long CHAR2ULONG ;
+typedef unsigned long USHORT2ULONG ;
+typedef unsigned long SHORT2ULONG ;
+typedef unsigned long INT2DWORD ;
+typedef unsigned short BYTE2WORD ;
+typedef POINTS MPOINT ;
+typedef WORD INT2WORD ;
+typedef jmp_buf MCATCHBUF ;
+typedef MCATCHBUF *LPMCATCHBUF ;
+
+#define HFILE2INT(h, flags) (INT)_open_osfhandle((long)(h), (int)(flags))
+#define INT2HFILE(i) (HFILE)_get_osfhandle((int)(i))
+#define DUPHFILE(h) MDupHandle(h)
+#define MGLOBALPTR(p) (LPSTR)(p)
+
+/* PRAGMAS */
+
+#define _LOADDS
+#define _EXPORT
+
+#define ERROR_GETADDR_FAILED 0x8001
+
+#define INITWINDOWS()
+
+#define WF_PMODE 0x0001 /* from winkrnl.h */
+#define WF_CPU286 0x0002
+#define WF_CPU386 0x0004
+#define WF_CPU486 0x0008
+#define WF_STANDARD 0x0010
+#define WF_WIN286 0x0010
+#define WF_ENHANCED 0x0020
+#define WF_WIN386 0x0020
+#define WF_CPU086 0x0040
+#define WF_CPU186 0x0080
+#define WF_LARGEFRAME 0x0100
+#define WF_SMALLFRAME 0x0200
+#define WF_80x87 0x0400
+
+
+/* DEFINITIONS */
+
+
+#define TF_FORCEDRIVE (BYTE)0x80
+#define DLLMEM_MOVEABLE 0
+#define DLLMEM_ZEROINIT GMEM_ZEROINIT
+
diff --git a/private/utils/ntbackup/exchange/build/inc/pwin32.h b/private/utils/ntbackup/exchange/build/inc/pwin32.h
new file mode 100644
index 000000000..2b9de0fe7
--- /dev/null
+++ b/private/utils/ntbackup/exchange/build/inc/pwin32.h
@@ -0,0 +1,305 @@
+/*****************************************************************************\
+* PWIN32.H - PORTABILITY MAPPING HEADER FILE
+*
+* This file provides macros to map portable windows code to its 32 bit form.
+\*****************************************************************************/
+
+/*-----------------------------------USER------------------------------------*/
+
+/* HELPER MACROS */
+
+#define MAPVALUE(v16, v32) (v32)
+#define MAPTYPE(v16, v32) v32
+#define MAKEMPOINT(l) (*((MPOINT *)&(l)))
+#define MPOINT2POINT(mpt,pt) ((pt).x = (mpt).x, (pt).y = (mpt).y)
+#define POINT2MPOINT(pt, mpt) ((mpt).x = (SHORT)(pt).x, (mpt).y = (SHORT)(pt).y)
+#define LONG2POINT(l, pt) ((pt).x = (SHORT)LOWORD(l), (pt).y = (SHORT)HIWORD(l))
+
+#define SETWINDOWUINT(hwnd, index, ui) (UINT)SetWindowLong(hwnd, index, (LONG)(ui))
+#define GETWINDOWUINT(hwnd, index) (UINT)GetWindowLong(hwnd, index)
+#define SETCLASSUINT(hwnd, index, ui) (UINT)SetClassLong(hwnd, index, (LONG)(ui))
+#define GETCLASSUINT(hwnd, index) (UINT)GetClassLong(hwnd, index)
+
+#define GETCBCLSEXTRA(hwnd) GETCLASSUINT(hwnd, GCL_CBCLSEXTRA)
+#define SETCBCLSEXTRA(hwnd, cb) SETCLASSUINT(hwnd, GCL_CBCLSEXTRA, cb)
+#define GETCBWNDEXTRA(hwnd) GETCLASSUINT(hwnd, GCL_CBWNDEXTRA)
+#define SETCBWNDEXTRA(hwnd, cb) SETCLASSUINT(hwnd, GCL_CBWNDEXTRA, cb)
+#define GETCLASSBRBACKGROUND(hwnd) (HBRUSH)GETCLASSUINT(hwnd, GCL_HBRBACKGROUND)
+#define SETCLASSBRBACKGROUND(hwnd, h) (HBRUSH)SETCLASSUINT(hwnd, GCL_HBRBACKGROUND, h)
+#define GETCLASSCURSOR(hwnd) (HCURSOR)GETCLASSUINT(hwnd, GCL_HCURSOR)
+#define SETCLASSCURSOR(hwnd, h) (HCURSOR)SETCLASSUINT(hwnd, GCL_HCURSOR, h)
+#define GETCLASSHMODULE(hwnd) (HMODULE)GETCLASSUINT(hwnd, GCL_HMODULE)
+#define SETCLASSHMODULE(hwnd, h) (HMODULE)SETCLASSUINT(hwnd, GCL_HMODULE, h)
+#define GETCLASSICON(hwnd) (HICON)GETCLASSUINT((hwnd), GCL_HICON)
+#define SETCLASSICON(hwnd, h) (HICON)SETCLASSUINT((hwnd), GCL_HICON, h)
+#define GETCLASSSTYLE(hwnd) GETCLASSUINT((hwnd), GCL_STYLE)
+#define SETCLASSSTYLE(hwnd, style) SETCLASSUINT((hwnd), GCL_STYLE, style)
+#define GETHWNDINSTANCE(hwnd) (HINSTANCE)GETWINDOWUINT((hwnd), GWL_HINSTANCE)
+#define SETHWNDINSTANCE(hwnd, h) (HINSTANCE)SETWINDOWUINT((hwnd), GWL_HINSTANCE, h)
+#define GETHWNDPARENT(hwnd) (HWND)GETWINDOWUINT((hwnd), GWL_HWNDPARENT)
+#define SETHWNDPARENT(hwnd, h) (HWND)SETWINDOWUINT((hwnd), GWL_HWNDPARENT, h)
+#define GETWINDOWID(hwnd) GETWINDOWUINT((hwnd), GWL_ID)
+#define SETWINDOWID(hwnd, id) SETWINDOWUINT((hwnd), GWL_ID, id)
+
+/* USER API */
+
+#define MDlgDirSelect(hDlg, lpstr, nLength, nIDListBox) \
+ DlgDirSelectEx(hDlg, lpstr, nLength, nIDListBox)
+
+#define MDlgDirSelectCOMBOBOX(hDlg, lpstr, nLength, nIDComboBox) \
+ DlgDirSelectComboBoxEx(hDlg, lpstr, nLength, nIDComboBox)
+
+#define MGetLastError GetLastError
+
+#define MMain(hInst, hPrevInst, lpCmdLine, nCmdShow) \
+ INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, \
+ INT nCmdShow) { \
+ INT _argc; \
+ CHAR **_argv;
+
+LPSTR MGetCmdLine(VOID);
+DWORD WINAPI MSendMsgEM_GETSEL(HWND hDlg, WORD2DWORD * piStart, WORD2DWORD * piEnd);
+
+
+/* USER MESSAGES: */
+
+#define GET_WPARAM(wp, lp) (wp)
+#define GET_LPARAM(wp, lp) (lp)
+
+#define GET_WM_ACTIVATE_STATE(wp, lp) LOWORD(wp)
+#define GET_WM_ACTIVATE_FMINIMIZED(wp, lp) (BOOL)HIWORD(wp)
+#define GET_WM_ACTIVATE_HWND(wp, lp) (HWND)(lp)
+#define GET_WM_ACTIVATE_MPS(s, fmin, hwnd) \
+ (WPARAM)MAKELONG((s), (fmin)), (LONG)(hwnd)
+
+#define GET_WM_CHARTOITEM_CHAR(wp, lp) (TCHAR)LOWORD(wp)
+#define GET_WM_CHARTOITEM_POS(wp, lp) HIWORD(wp)
+#define GET_WM_CHARTOITEM_HWND(wp, lp) (HWND)(lp)
+#define GET_WM_CHARTOITEM_MPS(ch, pos, hwnd) \
+ (WPARAM)MAKELONG((pos), (ch)), (LONG)(hwnd)
+
+#define GET_WM_COMMAND_ID(wp, lp) LOWORD(wp)
+#define GET_WM_COMMAND_HWND(wp, lp) (HWND)(lp)
+#define GET_WM_COMMAND_CMD(wp, lp) HIWORD(wp)
+#define GET_WM_COMMAND_MPS(id, hwnd, cmd) \
+ (WPARAM)MAKELONG(id, cmd), (LONG)(hwnd)
+
+#define WM_CTLCOLOR 0x0019
+
+#define GET_WM_CTLCOLOR_HDC(wp, lp, msg) (HDC)(wp)
+#define GET_WM_CTLCOLOR_HWND(wp, lp, msg) (HWND)(lp)
+#define GET_WM_CTLCOLOR_TYPE(wp, lp, msg) (WORD)(msg - WM_CTLCOLORMSGBOX)
+#define GET_WM_CTLCOLOR_MSG(type) (WORD)(WM_CTLCOLORMSGBOX+(type))
+#define GET_WM_CTLCOLOR_MPS(hdc, hwnd, type) \
+ (WPARAM)(hdc), (LONG)(hwnd)
+
+
+#define GET_WM_MENUSELECT_CMD(wp, lp) LOWORD(wp)
+#define GET_WM_MENUSELECT_FLAGS(wp, lp) (UINT)(int)(short)HIWORD(wp)
+#define GET_WM_MENUSELECT_HMENU(wp, lp) (HMENU)(lp)
+#define GET_WM_MENUSELECT_MPS(cmd, f, hmenu) \
+ (WPARAM)MAKELONG(cmd, f), (LONG)(hmenu)
+
+// Note: the following are for interpreting MDIclient to MDI child messages.
+#define GET_WM_MDIACTIVATE_FACTIVATE(hwnd, wp, lp) (lp == (LONG)hwnd)
+#define GET_WM_MDIACTIVATE_HWNDDEACT(wp, lp) (HWND)(wp)
+#define GET_WM_MDIACTIVATE_HWNDACTIVATE(wp, lp) (HWND)(lp)
+// Note: the following is for sending to the MDI client window.
+#define GET_WM_MDIACTIVATE_MPS(f, hwndD, hwndA)\
+ (WPARAM)(hwndA), 0
+
+#define GET_WM_MDISETMENU_MPS(hmenuF, hmenuW) (WPARAM)hmenuF, (LONG)hmenuW
+
+#define GET_WM_MENUCHAR_CHAR(wp, lp) (TCHAR)LOWORD(wp)
+#define GET_WM_MENUCHAR_HMENU(wp, lp) (HMENU)(lp)
+#define GET_WM_MENUCHAR_FMENU(wp, lp) (BOOL)HIWORD(wp)
+#define GET_WM_MENUCHAR_MPS(ch, hmenu, f) \
+ (WPARAM)MAKELONG(ch, f), (LONG)(hmenu)
+
+#define GET_WM_PARENTNOTIFY_MSG(wp, lp) LOWORD(wp)
+#define GET_WM_PARENTNOTIFY_ID(wp, lp) HIWORD(wp)
+#define GET_WM_PARENTNOTIFY_HWNDCHILD(wp, lp) (HWND)(lp)
+#define GET_WM_PARENTNOTIFY_X(wp, lp) (INT)LOWORD(lp)
+#define GET_WM_PARENTNOTIFY_Y(wp, lp) (INT)HIWORD(lp)
+#define GET_WM_PARENTNOTIFY_MPS(msg, id, hwnd) \
+ (WPARAM)MAKELONG(id, msg), (LONG)(hwnd)
+#define GET_WM_PARENTNOTIFY2_MPS(msg, x, y) \
+ (WPARAM)MAKELONG(0, msg), MAKELONG(x, y)
+
+#define GET_WM_VKEYTOITEM_CODE(wp, lp) (INT)LOWORD(wp)
+#define GET_WM_VKEYTOITEM_ITEM(wp, lp) HIWORD(wp)
+#define GET_WM_VKEYTOITEM_HWND(wp, lp) (HWND)(lp)
+#define GET_WM_VKEYTOITEM_MPS(code, item, hwnd) \
+ (WPARAM)MAKELONG(item, code), (LONG)(hwnd)
+
+#define GET_EM_SETSEL_START(wp, lp) (INT)(wp)
+#define GET_EM_SETSEL_END(wp, lp) (lp)
+#define GET_EM_SETSEL_MPS(iStart, iEnd) \
+ (WPARAM)(iStart), (LONG)(iEnd)
+
+#define GET_EM_LINESCROLL_MPS(vert, horz) \
+ (WPARAM)horz, (LONG)vert
+
+#define GET_WM_CHANGECBCHAIN_HWNDNEXT(wp, lp) (HWND)(lp)
+
+#define GET_WM_HSCROLL_CODE(wp, lp) LOWORD(wp)
+#define GET_WM_HSCROLL_POS(wp, lp) HIWORD(wp)
+#define GET_WM_HSCROLL_HWND(wp, lp) (HWND)(lp)
+#define GET_WM_HSCROLL_MPS(code, pos, hwnd) \
+ (WPARAM)MAKELONG(code, pos), (LONG)(hwnd)
+
+#define GET_WM_VSCROLL_CODE(wp, lp) LOWORD(wp)
+#define GET_WM_VSCROLL_POS(wp, lp) HIWORD(wp)
+#define GET_WM_VSCROLL_HWND(wp, lp) (HWND)(lp)
+#define GET_WM_VSCROLL_MPS(code, pos, hwnd) \
+ (WPARAM)MAKELONG(code, pos), (LONG)(hwnd)
+
+/* DDE macros */
+
+LONG WINAPI PackDDElParam(UINT msg, UINT uiLo, UINT uiHi);
+BOOL WINAPI UnpackDDElParam(UINT msg, LONG lParam, PUINT puiLo, PUINT puiHi);
+BOOL WINAPI FreeDDElParam(UINT msg, LONG lParam);
+UINT WINAPI MGetDDElParamLo(UINT msg, LONG lParam);
+UINT WINAPI MGetDDElParamHi(UINT msg, LONG lParam);
+BOOL WINAPI MPostDDEMsg(HWND hTo, UINT msg, HWND hFrom, UINT uiLo, UINT uiHi);
+
+#define DDEFREE(msg, lp) FreeDDElParam(msg, lp)
+
+#define GET_WM_DDE_ACK_STATUS(wp, lp) ((WORD)MGetDDElParamLo(WM_DDE_ACK, lp))
+#define GET_WM_DDE_ACK_ITEM(wp, lp) ((ATOM)MGetDDElParamHi(WM_DDE_ACK, lp))
+#define MPostWM_DDE_ACK(hTo, hFrom, wStatus, aItem) \
+ MPostDDEMsg(hTo, WM_DDE_ACK, hFrom, (UINT)wStatus, (UINT)aItem)
+
+#define GET_WM_DDE_ADVISE_HOPTIONS(wp, lp) ((HANDLE)MGetDDElParamLo(WM_DDE_ADVISE, lp))
+#define GET_WM_DDE_ADVISE_ITEM(wp, lp) ((ATOM)MGetDDElParamHi(WM_DDE_ADVISE, lp))
+#define MPostWM_DDE_ADVISE(hTo, hFrom, hOptions, aItem) \
+ MPostDDEMsg(hTo, WM_DDE_ADVISE, hFrom, (UINT)hOptions, (UINT)aItem)
+
+#define GET_WM_DDE_DATA_HDATA(wp, lp) ((HANDLE)MGetDDElParamLo(WM_DDE_DATA, lp))
+#define GET_WM_DDE_DATA_ITEM(wp, lp) ((ATOM)MGetDDElParamHi(WM_DDE_DATA, lp))
+#define MPostWM_DDE_DATA(hTo, hFrom, hData, aItem) \
+ MPostDDEMsg(hTo, WM_DDE_DATA, hFrom, (UINT)hData, (UINT)aItem)
+
+#define GET_WM_DDE_EXECUTE_HDATA(wp, lp) ((HANDLE)lp)
+#define MPostWM_DDE_EXECUTE(hTo, hFrom, hDataExec) \
+ PostMessage(hTo, WM_DDE_EXECUTE, (WPARAM)hFrom, (LONG)hDataExec)
+
+#define GET_WM_DDE_POKE_HDATA(wp, lp) ((HANDLE)MGetDDElParamLo(WM_DDE_POKE, lp))
+#define GET_WM_DDE_POKE_ITEM(wp, lp) ((ATOM)MGetDDElParamHi(WM_DDE_POKE, lp))
+#define MPostWM_DDE_POKE(hTo, hFrom, hData, aItem) \
+ MPostDDEMsg(hTo, WM_DDE_POKE, hFrom, (UINT)hData, (UINT)aItem)
+
+#define GET_WM_DDE_EXECACK_STATUS(wp, lp) ((WORD)MGetDDElParamLo(WM_DDE_ACK, lp))
+#define GET_WM_DDE_EXECACK_HDATA(wp, lp) ((HANDLE)MGetDDElParamHi(WM_DDE_ACK, lp))
+#define MPostWM_DDE_EXECACK(hTo, hFrom, wStatus, hCommands) \
+ MPostDDEMsg(hTo, WM_DDE_ACK, hFrom, (UINT)wStatus, (UINT)hCommands)
+
+#define GET_WM_DDE_REQUEST_FORMAT(wp, lp) ((ATOM)LOWORD(lp))
+#define GET_WM_DDE_REQUEST_ITEM(wp, lp) ((ATOM)HIWORD(lp))
+#define MPostWM_DDE_REQUEST(hTo, hFrom, fmt, aItem) \
+ MPostDDEMsg(hTo, WM_DDE_REQUEST, hFrom, (UINT)fmt, (UINT)aItem)
+
+#define GET_WM_DDE_UNADVISE_FORMAT(wp, lp) ((ATOM)LOWORD(lp))
+#define GET_WM_DDE_UNADVISE_ITEM(wp, lp) ((ATOM)HIWORD(lp))
+#define MPostWM_DDE_UNADVISE(hTo, hFrom, fmt, aItem) \
+ MPostDDEMsg(hTo, WM_DDE_UNADVISE, hFrom, (UINT)fmt, (UINT)aItem)
+
+#define MPostWM_DDE_TERMINATE(hTo, hFrom) \
+ PostMessage(hTo, WM_DDE_TERMINATE, (WPARAM)hFrom, 0L)
+
+
+/*-----------------------------------GDI-------------------------------------*/
+
+BOOL WINAPI MGetAspectRatioFilter(HDC hdc, INT * pcx, INT * pcy);
+BOOL WINAPI MGetBitmapDimension(HANDLE hBitmap, INT * pcx, INT *pcy);
+BOOL WINAPI MGetBrushOrg(HDC hdc, INT * px, INT * py);
+BOOL WINAPI MGetCurrentPosition(HDC hdc, INT * px, INT * py);
+BOOL WINAPI MGetTextExtent(HDC hdc, LPSTR lpstr, INT cnt, INT *pcx, INT *pcy);
+BOOL WINAPI MGetViewportExt(HDC hdc, INT * pcx, INT * pcy);
+BOOL WINAPI MGetViewportOrg(HDC hdc, INT * px, INT * py);
+BOOL WINAPI MGetWindowExt(HDC hdc, INT * pcx, INT * pcy);
+BOOL WINAPI MGetWindowOrg(HDC hdc, INT * px, INT * py);
+HANDLE WINAPI MGetMetaFileBits(HMETAFILE hmf);
+HMETAFILE WINAPI MSetMetaFileBits(HANDLE h);
+
+#define MCreateDiscardableBitmap(h, x, y) CreateCompatibleBitmap(h, (DWORD)(x), (DWORD)(y))
+#define MMoveTo(hdc, x, y) MoveToEx(hdc, x, y, NULL)
+#define MOffsetViewportOrg(hdc, x, y) OffsetViewportOrgEx(hdc, x, y, NULL)
+#define MOffsetWindowOrg(hdc, x, y) OffsetWindowOrgEx(hdc, x, y, NULL)
+#define MScaleViewportExt(hdc, x, y, xd, yd) ScaleViewportExtEx(hdc, x, y, xd, yd, NULL)
+#define MScaleWindowExt(hdc, x, y, xd, yd) ScaleWindowExtEx(hdc, x, y, xd, yd, NULL)
+#define MSetBitmapDimension(hbm, x, y) SetBitmapDimensionEx(hbm, (DWORD)(x), (DWORD)(y), NULL)
+#define MSetBrushOrg(hbm, x, y) SetBrushOrgEx(hbm, x, y, NULL)
+#define MSetViewportExt(hdc, x, y) SetViewportExtEx(hdc, x, y, NULL)
+#define MSetViewportOrg(hdc, x, y) SetViewportOrgEx(hdc, x, y, NULL)
+#define MSetWindowExt(hdc, x, y) SetWindowExtEx(hdc, x, y, NULL)
+#define MSetWindowOrg(hdc, x, y) SetWindowOrgEx(hdc, x, y, NULL)
+
+/* Removed APIs */
+
+#define MUnrealizeObject(h) ((h), TRUE)
+
+/*-------------------------------------DEV-----------------------------------*/
+
+DWORD WINAPI MDeviceCapabilities(LPSTR lpDriverName, LPSTR lpDeviceName,
+ LPSTR lpPort, WORD2DWORD nIndex, LPSTR lpOutput, LPDEVMODE lpDevMode);
+BOOL WINAPI MDeviceMode(HWND hWnd, LPSTR lpDriverName, LPSTR lpDeviceName, LPSTR lpOutput);
+WORD2DWORD WINAPI MExtDeviceMode(HWND hWnd,LPSTR lpDriverName,
+ LPDEVMODE lpDevModeOutput, LPSTR lpDeviceName, LPSTR lpPort,
+ LPDEVMODE lpDevModeInput, LPSTR lpProfile, WORD2DWORD flMode);
+
+/*-----------------------------------KERNEL----------------------------------*/
+
+HFILE WINAPI MDupHandle(HFILE h);
+BOOL WINAPI MFreeDOSEnvironment(LPSTR lpEnv);
+HANDLE WINAPI MGetInstHandle(VOID);
+LPSTR WINAPI MGetDOSEnvironment(VOID);
+WORD WINAPI MGetDriveType(INT nDrive);
+BYTE WINAPI MGetTempDrive(BYTE cDriveLtr);
+INT WINAPI MGetTempFileName(BYTE cDriveLtr, LPSTR lpstrPrefix, WORD wUnique, LPSTR lpTempFileName);
+INT WINAPI MReadComm(HFILE nCid, LPSTR lpBuf, INT nSize);
+INT WINAPI MWriteComm(HFILE nCid, LPSTR lpBuf, INT nSize);
+
+
+#define GETMAJORVERSION(x) ((x)&0xff)
+#define GETMINORVERSION(x) (((x)>>8)&0xff)
+
+/* FUNCTION MAPPINGS */
+
+#define GetInstanceData(hPrevInst, pbuf, cb) (cb)
+#define MOpenComm(lpstr, wqin, wqout) (wqin), (wqout), CreateFile(lpstr, \
+ GENERIC_READ | GENERIC_WRITE, 0, \
+ NULL, \
+ OPEN_EXISTING | TRUNCATE_EXISTING, \
+ FILE_FLAG_WRITE_THROUGH, 0)
+
+#define MSetCommState(h, lpDCB) SetCommState((HANDLE)h, lpDCB)
+#define MCloseComm(h) (INT)!CloseHandle((HANDLE)h)
+#define MDllSharedAlloc(dwFlags, dwBytes) GlobalAlloc(GMEM_DDESHARE | dwFlags, dwBytes)
+#define MDllSharedFlags(hMem) GlobalFlags(hMem)
+#define MDllSharedFree GlobalFree
+#define MDllSharedHandle GlobalHandle
+#define MDllSharedLock GlobalLock
+#define MDllSharedRealloc(hMem, dwBytes, dwFlags) \
+ GlobalReAlloc(hMem, dwBytes, dwFlags)
+#define MDllSharedSize GlobalSize
+#define MDllSharedUnlock GlobalUnlock
+#define MGetCurrentTask GetCurrentThreadId
+#define MGetModuleUsage(h) ((h), 1)
+#define MGetWinFlags() WF_PMODE
+#define MLoadLibrary(lpsz) LoadLibrary(lpsz)
+#define MLocalInit(w, p1, p2) ((w),(p1),(p2),TRUE)
+#define MLockData(dummy)
+#define MUnlockData(dummy)
+#define M_lclose(fh) _lclose((HFILE)fh)
+#define M_lcreat (HFILE)_lcreat
+#define MOpenFile (HFILE)OpenFile
+#define M_llseek(fh, lOff, iOrg) SetFilePointer((HANDLE)fh, lOff, NULL, (DWORD)iOrg)
+#define MDeleteFile DeleteFile
+#define M_lopen (HFILE)_lopen
+#define M_lread(fh, lpBuf, cb) _lread((HFILE)fh, lpBuf, cb)
+#define M_lwrite(fh, lpBuf, cb) _lwrite((HFILE)fh, lpBuf, cb)
+
+#define MCatch setjmp
+#define MThrow longjmp
+
diff --git a/private/utils/ntbackup/exchange/build/inc/uiexport.h b/private/utils/ntbackup/exchange/build/inc/uiexport.h
new file mode 100644
index 000000000..6bd0b59f4
--- /dev/null
+++ b/private/utils/ntbackup/exchange/build/inc/uiexport.h
@@ -0,0 +1,132 @@
+/**********************************************************************/
+/** Microsoft Windows NT **/
+/** Copyright(c) Microsoft Corp., 1992 **/
+/**********************************************************************/
+
+/*
+ uiexport.h
+
+ Prototypes for Net UI exported APIs
+
+
+
+ FILE HISTORY:
+ Johnl 17-Apr-1992 Created
+
+*/
+
+#ifndef _UIEXPORT_H_
+#define _UIEXPORT_H_
+
+
+/* Selections the user can make in the System focus dialog
+ */
+
+/* Low word of the selection type
+ */
+#define FOCUSDLG_DOMAINS_ONLY (1)
+#define FOCUSDLG_SERVERS_ONLY (2)
+#define FOCUSDLG_SERVERS_AND_DOMAINS (3)
+
+/* High word of the selection type contains a bitmask indicating
+ * which domains to display in the dialog.
+ * WARNING: This bitmask are shifted up 16 bits from the bitmask in
+ * \nt\private\net\ui\common\h\domenum.h. If you want to
+ * modify the values of the bitmask, you will need to
+ * make corresponding changes to domenum.h.
+ *
+ */
+
+#define FOCUSDLG_BROWSE_LOGON_DOMAIN 0x00010000
+#define FOCUSDLG_BROWSE_WKSTA_DOMAIN 0x00020000
+#define FOCUSDLG_BROWSE_OTHER_DOMAINS 0x00040000
+#define FOCUSDLG_BROWSE_TRUSTING_DOMAINS 0x00080000
+#define FOCUSDLG_BROWSE_WORKGROUP_DOMAINS 0x00100000
+
+/* Some handy combinations of flags.
+*/
+
+/* FOCUSDLG_BROWSE_LM2X_DOMAINS will return only the domains available
+ from a LanMan 2.x workstation. This returns just the logon,
+ workstation, and other domains. This is the default value.
+*/
+
+#define FOCUSDLG_BROWSE_LM2X_DOMAINS ( FOCUSDLG_BROWSE_LOGON_DOMAIN | \
+ FOCUSDLG_BROWSE_WKSTA_DOMAIN | \
+ FOCUSDLG_BROWSE_OTHER_DOMAINS )
+
+/*
+ FOCUSDLG_BROWSE_LOCAL_DOMAINS will return only the domains available
+ to the local machine. This returns the logon, workstation,
+ and other, plus the domains that trust "us".
+*/
+
+#define FOCUSDLG_BROWSE_LOCAL_DOMAINS ( FOCUSDLG_BROWSE_LM2X_DOMAINS | \
+ FOCUSDLG_BROWSE_TRUSTING_DOMAINS )
+
+/*
+ FOCUSDLG_BROWSE_ALL_DOMAINS is a conglomeration of all potential domain
+ sources available to the domain enumerator.
+*/
+
+#define FOCUSDLG_BROWSE_ALL_DOMAINS ( FOCUSDLG_BROWSE_LOCAL_DOMAINS | \
+ FOCUSDLG_BROWSE_WORKGROUP_DOMAINS )
+
+/*******************************************************************
+
+ NAME: I_SystemFocusDialog
+
+ SYNOPSIS: Presents a dialog to the user from which a server or domain
+ maybe selected.
+
+ ENTRY: hwndOwner - Parent window handle
+ nSelectionType - The type of selection the user is allowed
+ to make
+ pszName - The server or domain name. It will be
+ undefined if the user hits the CANCEL
+ button ( pfOK = FALSE )
+ cchBufSize - The buffer size of the lptstrName.
+ pfUserQuit - If the user hits the OKAY button, it will
+ return TRUE. Otherwise, it will return FALSE.
+ pszHelpFile - The helpfile to use when the user hits F1.
+ If NULL, the default helpfile is used.
+ nHelpContext - The helpcontext to use for the helpfile above.
+ If the above is NULL, this must be 0 (& vice
+ versa).
+
+ EXIT: if *pfOKPressed is TRUE (and an error didn't occur), then
+ lptstrName will be filled with the user selected name.
+
+ RETURNS: NO_ERROR on success, standard ERROR_* error code otherwise
+
+ NOTES: This will be a UNICODE only API when the net group goes UNICODE
+
+ HISTORY:
+ JohnL 22-Apr-1992 Added selection option, exported to private\inc
+ ChuckC 03-Nov-1992 Added helpfile & help context
+
+********************************************************************/
+
+UINT FAR PASCAL I_SystemFocusDialog(
+ HWND hwndOwner,
+ UINT nSelectionType,
+ LPWSTR pszName,
+ UINT cchBufSize,
+ BOOL *pfOKPressed,
+ LPWSTR pszHelpFile,
+ DWORD nHelpContext
+ );
+
+typedef UINT (FAR PASCAL *LPFNI_SYSTEMFOCUSDIALOG)(
+ HWND hwndOwner,
+ UINT nSelectionType,
+ LPWSTR pszName,
+ UINT cchBufSize,
+ BOOL *pfOKPressed,
+ LPWSTR pszHelpFile,
+ DWORD nHelpContext
+ );
+
+
+
+#endif //_UIEXPORT_H_
diff --git a/private/utils/ntbackup/exchange/build/inc/warning.h b/private/utils/ntbackup/exchange/build/inc/warning.h
new file mode 100644
index 000000000..a15603981
--- /dev/null
+++ b/private/utils/ntbackup/exchange/build/inc/warning.h
@@ -0,0 +1,22 @@
+#pragma warning(3:4092) // sizeof returns 'unsigned long'
+#pragma warning(3:4121) // structure is sensitive to alignment
+#pragma warning(3:4125) // decimal digit in octal sequence
+#pragma warning(3:4130) // logical operation on address of string constant
+#pragma warning(3:4132) // const object should be initialized
+#pragma warning(4:4206) // Source File is empty
+#pragma warning(4:4101) // Unreferenced local variable
+#pragma warning(4:4208) // delete[exp] - exp evaluated but ignored
+#pragma warning(3:4212) // function declaration used ellipsis
+#pragma warning(error:4700) // Local used w/o being initialized
+#pragma warning(error:4259) // pure virtual function was not defined
+#pragma warning(4:4509) // use of SEH with destructor
+#pragma warning(4:4177) // pragma data_seg s/b at global scope
+
+#if 0
+#pragma warning(3:4100) // Unreferenced formal parameter
+#pragma warning(3:4701) // local may be used w/o init
+#pragma warning(3:4702) // Unreachable code
+#pragma warning(3:4705) // Statement has no effect
+#pragma warning(3:4706) // assignment w/i conditional expression
+#pragma warning(3:4709) // command operator w/o index expression
+#endif
diff --git a/private/utils/ntbackup/exchange/build/makefile.def b/private/utils/ntbackup/exchange/build/makefile.def
new file mode 100644
index 000000000..7f7c14429
--- /dev/null
+++ b/private/utils/ntbackup/exchange/build/makefile.def
@@ -0,0 +1,2047 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ makefile.def
+
+Abstract:
+
+ This is the standard makefile for the components of the NT project.
+ It includes the following files:
+
+ .\sources. - developer supplies this file. It defines the
+ required TARGETNAME, TARGETPATH, TARGETTYPE and
+ SOURCES as well as optional macros that control
+ the behavior of the compiler and linker:
+
+ obj\_objects.mac - built by BUILD.EXE from .\sources.
+
+
+Targets:
+
+ all - Builds all targets in this make file
+
+ clean - Erase all targets that can be produced by this make
+ file, ignoring errors. Also rebuilds the depend target.
+
+ depend - Rebuilts source file dependencies, using BUILD.EXE tool
+
+Author:
+
+ Steve Wood (stevewo) 28-Feb-1989
+
+
+Revision History:
+ Reza Baghai (rezab) 25-Jan-1993
+ Added -order:*.prf switch for building EXEs
+ Added $(PERFLIBS) to *_LINKLIBS lines to allow linking with
+ optional performance tuning libraries
+ Sudeep Bharati (sudeepb) 10-Dec-1991
+ Added PROGLIB target type, so that NTVDM can export
+ interfaces from an EXE.
+
+ Roger Lanser (a-rlansr) 27-Apr-1993
+ Added MIPS C8 compiler and attempted to generalize variables
+ between the MIPS and INTEL version of C8.
+ Oh yes, removed last remnants of DECSTATION.
+
+Useful Variables Set:
+
+ CPUTYPE={I386|MIPS|ALPHA|PPC}
+
+Optional Controls Variables (partial list), these are environment variables,
+remember they can be set with env=value on the command line as well:
+
+NOTE: xxx_... is {MSC|386|mips|alpha|PPC} where MSC_ applies to the C8 compiler
+ independent of the cpu type. Specific cpu_ will take precedence
+ over the equivalent MSC_ variable.
+
+EXAMPLE: To compile with codeview symbols for windbg:
+
+ set NTDEBUG=ntsd
+ set NTDEBUGTYPE=windbg
+ set MSC_OPTIMIZATION=/Od
+
+
+ nttest=filename
+
+ umtest=filename
+
+ umappl=filename
+
+ NT_UP
+ Define as 0 in environment to turn on MP.
+ If undefined or equal to 1, you get UP.
+
+ xxx_warning_level
+
+ xxx_optimization
+
+ xxx_STDCALL = 1 use _stdcall calling convention
+ 0 use _cdecl calling convention
+
+ ntdebug
+
+ browser_info
+
+ xxx_cppflags
+
+ ntcppflags
+
+ NT_INST - set to turn on instrumentation
+
+ BASEDIR - \nt or \ntrel (default \nt)
+
+ PRECOMPILED_CXX=1 - do precompiled headers for CXX instead of C files
+ note: precompiled headers can not be used on both
+ c and cxx files in a single directory.
+
+ pnp_power=1 | 0 | <empty>
+
+!ENDIF
+
+!if 0
+!message You must use nmake version 1.30 or greater...
+!endif
+
+#
+# IDL/RDL/TDL build rules.
+#
+
+!ifdef IDL_RULES
+IDL_OUT_DIR =.
+IDL_HDR_OUT_DIR =.
+RDL_OUT_DIR =.
+RDL_HDR_OUT_DIR =.
+
+!ifndef MIDL_INCS
+MIDL_INCS = obj\$(TARGET_DIRECTORY)
+!endif
+
+!ifndef MC_OUT_DIR
+MC_OUT_DIR = obj\$(TARGET_DIRECTORY)
+!endif
+!endif
+
+
+#
+# Select build target and set platform specific variables.
+#
+
+!INCLUDE makefile.plt
+
+#
+# Include the developer supplied file that defines the TARGETNAME, TARGETPATH,
+# TARGETTYPE and SOURCES macros. Make sure it defines them.
+#
+
+!INCLUDE .\sources.
+SOURCES_USED=$(SOURCES_USED) .\sources
+
+#
+# Attempt to include the sources file from the target subdirectory.
+#
+
+!IF EXIST(.\$(TARGET_DIRECTORY)\sources.)
+!INCLUDE .\$(TARGET_DIRECTORY)\sources.
+SOURCES_USED=$(SOURCES_USED) .\$(TARGET_DIRECTORY)\sources.
+!ENDIF
+
+#
+# Attempt to include the sources file from the parent target subdirectory.
+#
+
+!IF EXIST(..\$(TARGET_DIRECTORY)\sources.)
+!INCLUDE ..\$(TARGET_DIRECTORY)\sources.
+SOURCES_USED=$(SOURCES_USED) ..\$(TARGET_DIRECTORY)\sources.
+!ENDIF
+
+!IF "$(_NT_LEGO_ON_THIS_MACHINE)" == ""
+!UNDEF NTLEGO
+!ENDIF
+
+!IFNDEF TARGETPATH
+!ERROR Your .\sources. file must define the TARGETPATH= macro
+!ENDIF
+
+!IFNDEF TARGETTYPE
+!ERROR Your .\sources. file must define the TARGETTYPE= macro
+!ENDIF
+
+!IFNDEF TARGETNAME
+! IF "$(TARGETTYPE)" != "NOTARGET"
+!ERROR Your .\sources. file must define the TARGETNAME= macro
+! ELSE
+TARGETNAME=
+! ENDIF
+!ENDIF
+
+!IFNDEF SOURCES
+!ERROR Your .\sources. file must define the SOURCES= macro
+!ENDIF
+
+!IFNDEF UMTYPE
+UMTYPE=nt
+!ENDIF
+
+!IFNDEF UMBASE
+! IFDEF COFFBASE
+UMBASE=@..\exchange\build\coffbase.txt,$(COFFBASE)
+! ELSE
+UMBASE=@..\exchange\build\coffbase.txt,usermode
+! ENDIF
+!ENDIF
+
+LINKLIBS=$(LINKLIBS) $(PERFLIBS)
+
+!IF DEFINED(USE_MFC) || DEFINED(USE_MFCUNICODE)
+
+#---------------------------------------------------------#
+# this set of defines establishes the "correct" build #
+# environment for an app that needs to use MFC. the #
+# app's sources file only needs to specify USE_MFC=1 #
+# and this makefile will set the enviroment up correctly. #
+#---------------------------------------------------------#
+
+UMENTRY=winmain
+UMENTRYABS=
+USE_CRTDLL=1 # CRTDLL s/b used if MFC is.
+
+MFC_FLAGS=$(MFC_FLAGS) -D_AFXDLL -D_AFX_NOFORCE_LIBS
+!IF "$(NTDEBUG)" == "retail" || "$(NTDEBUG)" == "" || "$(NTDEBUG)" == "ntsdnodbg"
+!IFDEF USE_MFCUNICODE
+MFC_LIBS=$(BASEDIR)\public\sdk\lib\*\cfm30u.lib $(BASEDIR)\public\sdk\lib\*\cfmo30u.lib
+!ELSE
+MFC_LIBS=$(BASEDIR)\public\sdk\lib\*\cfm30.lib $(BASEDIR)\public\sdk\lib\*\cfmo30.lib
+!ENDIF
+MFC_FLAGS=$(MFC_FLAGS) -DNDEBUG
+!ELSE
+!IFDEF USE_MFCUNICODE
+MFC_LIBS=$(BASEDIR)\public\sdk\lib\*\cfm30ud.lib $(BASEDIR)\public\sdk\lib\*\cfmo30ud.lib
+!ELSE
+MFC_LIBS=$(BASEDIR)\public\sdk\lib\*\cfm30d.lib $(BASEDIR)\public\sdk\lib\*\cfmo30d.lib
+!ENDIF
+MFC_FLAGS=$(MFC_FLAGS) -D_DEBUG
+USE_PDB=1
+!ENDIF
+
+!IFDEF USE_MFCUNICODE
+UNICODE=1
+MFC_FLAGS=$(MFC_FLAGS) -DUNICODE -D_UNICODE
+!ENDIF
+
+MFC_INCLUDES=$(BASEDIR)\public\sdk\inc\mfc30
+
+LINKLIBS=$(LINKLIBS) $(MFC_LIBS)
+
+!ENDIF # USE_MFC || USE_MFCUNICODE
+
+!IFDEF USE_CRTDLL
+
+LIBC_LIB=crtdll.lib
+LIBC_DEFINES=-D_DLL=1 -D_MT=1
+
+!ELSE
+
+! IFDEF USE_MSVCRT
+LIBC_LIB=msvcrt.lib
+LIBC_DEFINES=-D_DLL=1 -D_MT=1
+
+!ELSE
+
+! IFDEF USE_LIBCMT
+LIBC_LIB=libcmt.lib
+LIBC_DEFINES=-D_MT=1
+
+! ELSE
+
+LIBC_LIB=libc.lib
+LIBC_DEFINES=
+
+! ENDIF
+! ENDIF
+!ENDIF
+
+
+!IFNDEF GPSIZE
+GPSIZE= 0
+!ENDIF
+
+!IFDEF CAIRO_PRODUCT
+CAIRO_LIB_PATH=$(BASEDIR)\public\sdk\lib\cairo\*
+!ENDIF # CAIRO_PRODUCT
+
+!ifdef NTLIBPATH
+LIBRARY_PATH = $(NTLIBPATH)\*\lib
+!else
+!ifdef CHICAGO_PRODUCT
+LIBRARY_PATH = $(BASEDIR)\public\sdk\lib\chicago\*
+!else
+LIBRARY_PATH = $(BASEDIR)\public\sdk\lib\*
+!endif
+!endif
+
+!ifndef NTLIBCPATH
+NTLIBCPATH=$(LIBRARY_PATH)
+!endif
+
+LIBC_LIB = $(NTLIBCPATH)\$(LIBC_LIB)
+
+NT_LIBS=$(LIBRARY_PATH)\ntdll.lib
+GUI32_LIBS=$(LIBRARY_PATH)\gdi32.lib \
+ $(LIBRARY_PATH)\user32.lib
+
+!IFDEF CAIRO_PRODUCT
+!IFNDEF TUKWILA
+NT_LIBS=$(NT_LIBS:lib\*\ntdll.lib=lib\cairo\*\ntdll.lib)
+!ENDIF
+GUI32_LIBS=$(GUI32_LIBS:lib\*\user32.lib=lib\cairo\*\user32.lib)
+!ENDIF
+
+CRT_LIBS=
+
+NT_CRT=$(LIBRARY_PATH)\nt.lib
+WIN32_LIBS=$(LIBC_LIB) \
+ $(LIBRARY_PATH)\advapi32.lib \
+ $(LIBRARY_PATH)\kernel32.lib
+
+NTSS_LIBS=$(NT_LIBS) $(NT_CRT) $(BASEDIR)\public\sdk\lib\*\smdll.lib
+
+OS2_LIBS=$(NT_LIBS) $(BASEDIR)\public\sdk\lib\*\os2dll.lib \
+ $(CRT_LIBS)
+
+POSIX_LIBS=$(NT_LIBS) $(BASEDIR)\public\sdk\lib\*\libcpsx.lib \
+ $(BASEDIR)\public\sdk\lib\*\psxdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\psxrtl.lib
+
+!ifndef SUBSYSTEM_VERSION
+! ifndef EXPECTED_WINVER
+! ifdef CAIRO_PRODUCT
+SUBSYSTEM_WINVER = ,4.00
+! else
+SUBSYSTEM_WINVER = ,3.51
+! endif
+! else
+SUBSYSTEM_WINVER = ,$(EXPECTED_WINVER)
+! endif
+SUBSYSTEM_CONVER = ,3.51
+SUBSYSTEM_OS2VER =
+SUBSYSTEM_POSIXVER =
+SUBSYSTEM_NATVER = ,3.51
+!else
+SUBSYSTEM_WINVER = ,$(SUBSYSTEM_VERSION)
+SUBSYSTEM_CONVER = ,$(SUBSYSTEM_VERSION)
+SUBSYSTEM_OS2VER = ,$(SUBSYSTEM_VERSION)
+SUBSYSTEM_POSIXVER = ,$(SUBSYSTEM_VERSION)
+SUBSYSTEM_NATVER = ,$(SUBSYSTEM_VERSION)
+!endif
+
+!IF "$(UMTYPE)" == "nt"
+SUBSYSTEM=native$(SUBSYSTEM_NATVER)
+UMINCL=$(BASEDIR)\public\sdk\inc\crt
+
+
+STD_CALL_ENTRY=1
+UMENTRY=-entry:NtProcessStartup
+
+UMLIBS=$(UMLIBS) $(NT_LIBS) $(NT_CRT) $(CRT_LIBS)
+
+!ELSE
+! IF "$(UMTYPE)" == "windows"
+SUBSYSTEM=windows$(SUBSYSTEM_WINVER)
+UMINCL=$(BASEDIR)\public\sdk\inc\crt
+
+! IF "$(UMENTRY)" == "winmain"
+UMENTRY=-entry:WinMainCRTStartup
+! ELSE
+! IF "$(UMENTRYABS)" == ""
+UMENTRY=-entry:mainCRTStartup
+! ELSE
+UMENTRY=-entry:$(UMENTRYABS)
+! ENDIF
+! ENDIF
+
+#UMLIBS=$(UMLIBS) $(WIN32_LIBS) $(GUI32_LIBS)
+
+! ELSE
+! IF "$(UMTYPE)" == "console"
+SUBSYSTEM=console$(SUBSYSTEM_CONVER)
+UMINCL=$(BASEDIR)\public\sdk\inc\crt
+
+! IF "$(UMENTRY)" == "winmain"
+UMENTRY=-entry:WinMainCRTStartup
+! ELSE
+UMENTRY=-entry:mainCRTStartup
+! ENDIF
+
+UMLIBS=$(UMLIBS) $(WIN32_LIBS)
+
+! ELSE
+! IF "$(UMTYPE)" == "ntss"
+SUBSYSTEM=native$(SUBSYSTEM_NATVER)
+UMINCL=$(BASEDIR)\public\sdk\inc\crt
+
+STD_CALL_ENTRY=1
+UMENTRY=-entry:NtProcessStartup
+
+UMLIBS=$(UMLIBS) $(NTSS_LIBS) $(CRT_LIBS)
+
+! ELSE
+! IF "$(UMTYPE)" == "os2"
+SUBSYSTEM=os2$(SUBSYSTEM_OS2VER)
+UMINCL=$(BASEDIR)\public\sdk\inc\os2;$(BASEDIR)\public\sdk\inc\crt
+
+STD_CALL_ENTRY=1
+UMENTRY=-entry:NtProcessStartup
+
+UMLIBS=$(UMLIBS) $(OS2_LIBS)
+
+! ELSE
+! IF "$(UMTYPE)" == "posix"
+SUBSYSTEM=posix$(SUBSYSTEM_POSIXVER)
+UMINCL=$(BASEDIR)\public\sdk\inc\posix;$(BASEDIR)\public\sdk\inc\crt
+
+UMENTRY=-entry:__PosixProcessStartup
+
+UMLIBS=$(UMLIBS) $(POSIX_LIBS)
+
+! ELSE
+! ERROR Invalid UMTYPE value - $(UMTYPE)
+! ENDIF # UMTYPE == posix
+! ENDIF # UMTYPE == os2
+! ENDIF # UMTYPE == ntss
+! ENDIF # UMTYPE == console
+! ENDIF # UMTYPE == windows
+!ENDIF # UMTYPE == nt
+
+
+#
+# If you edit this line you need to modify $(BASEDIR)\private\sdktools\build\build.c
+#
+
+!IFDEF NTINCPATH
+NTINCLUDES=$(BASEDIR)\public\oak\inc;$(NTINCPATH)\$(TARGET_DIRECTORY)\inc
+!ELSE
+NTINCLUDES=$(BASEDIR)\public\oak\inc;$(BASEDIR)\public\sdk\inc
+!ENDIF
+
+!IFNDEF COMPILER_WARNINGS
+COMPILER_WARNINGS=-FI$(BASEDIR)\public\sdk\inc\warning.h
+!ENDIF
+
+!IFDEF CAIRO_PRODUCT
+NTINCLUDES=$(BASEDIR)\private\cinc;$(BASEDIR)\public\sdk\inc\cairo;$(NTINCLUDES)
+!IFDEF NOT_UNICODE
+WIN32_DEFINE=-DWIN32=300 -D_CAIRO_=300
+!ELSE
+WIN32_DEFINE=-DWIN32=300 -D_CAIRO_=300 -DUNICODE -D_UNICODE
+!ENDIF
+
+!ELSE
+
+!IFDEF CHICAGO_PRODUCT
+NTINCLUDES=$(BASEDIR)\private\cinc;$(BASEDIR)\public\sdk\inc\chicago;$(BASEDIR)\public\sdk\inc\chicago\crt;$(NTINCLUDES)
+WIN32_DEFINE=-DWIN32=200 -DFLAT -D_CHICAGO_=200
+
+LINKER_FLAGS=$(LINKER_FLAGS) -map
+
+!ELSE
+WIN32_DEFINE=-DWIN32=100 -D_NT1X_=100
+CAIRO_LIB_PATH=$(BASEDIR)\public\sdk\lib
+!ENDIF
+
+!ENDIF
+
+INCLUDES =$(INCLUDES: =)
+NTINCLUDES =$(NTINCLUDES: =)
+UMINCL =$(UMINCL: =)
+
+!IFDEF USER_INCLUDES
+USER_INCLUDES =$(USER_INCLUDES: =)
+USER_INCL0=-I$(USER_INCLUDES)
+USER_INCL1=-I$(USER_INCLUDES)
+!ELSE
+USER_INCL0=
+USER_INCL1=
+!ENDIF
+
+!IFDEF INCLUDES
+INCL=$(INCLUDES)
+INCPATH0=$(USER_INCL0:;= -I) -I$(INCL:;= -I) -I$(NTINCLUDES:;= -I) -I$(UMINCL:;= -I)
+INCPATH1=$(USER_INCL1:;= -I) -I$(INCL:;= -I) -I$(NTINCLUDES:;= -I) -I$(UMINCL:;= -I)
+!ELSE
+INCPATH0=$(USER_INCL0:;= -I) -I$(NTINCLUDES:;= -I) -I$(UMINCL:;= -I)
+INCPATH1=$(USER_INCL1:;= -I) -I$(NTINCLUDES:;= -I) -I$(UMINCL:;= -I)
+!ENDIF
+
+INCPATH0=$(INCPATH0:-I =)
+INCPATH1=$(INCPATH1:-I =)
+
+!IFDEF MFC_INCLUDES
+MFC_INCLUDES=$(MFC_INCLUDES: =)
+MFC_INCLUDES=-I$(MFC_INCLUDES:;= -I)
+INCPATH0=$(MFC_INCLUDES) $(INCPATH0)
+INCPATH1=$(MFC_INCLUDES) $(INCPATH1)
+!ENDIF
+
+!IFNDEF RELATIVE_DEPTH
+RELATIVE_DEPTH=..\..
+!ENDIF
+
+!IFNDEF DLLENTRY
+DLLENTRY=-noentry
+!ELSE
+DLLENTRY=-entry:$(DLLENTRY)
+!ENDIF
+
+!IFNDEF DLLBASE
+DLLBASE=@$(BASEDIR)\PUBLIC\SDK\LIB\coffbase.txt,$(TARGETNAME)
+!ENDIF
+
+!IFNDEF DLLDEF
+DLLDEF=$(@B).def
+!ENDIF
+
+!IFNDEF BOOTBASE
+! IFDEF FRAZZLE
+BOOTBASE=0xd0100000,0xd0104000
+! ELSE
+BOOTBASE=0xd0ff0000,0xd0ff4000
+! ENDIF
+!ENDIF
+
+DRIVERBASE=0x10000
+HALBASE=0x80400000
+
+#
+# Map lower case to upper case for variables that can be specified from the
+# command line.
+#
+
+!IFDEF nttest
+NTTEST=$(nttest)
+!ENDIF
+
+!IFDEF makedll
+MAKEDLL=$(makedll)
+!ENDIF
+
+!IFDEF umtest
+UMTEST=$(umtest)
+!ENDIF
+
+
+#
+# Include the list of object files (defined as the OBJECTS macro) that was
+# built by BUILD program, using the SOURCES= macro defined in the sources.
+# file. Use macro substitution to build the supported target objects.
+#
+
+!INCLUDE obj\_objects.mac
+
+!IF $(386)
+OBJECTS=$(386_OBJECTS)
+DLLLIBOBJECTS=$(386_DLLLIBOBJECTS)
+!ELSEIF $(MIPS)
+OBJECTS=$(MIPS_OBJECTS)
+DLLLIBOBJECTS=$(MIPS_DLLLIBOBJECTS)
+!ELSEIF $(ALPHA)
+OBJECTS=$(ALPHA_OBJECTS)
+DLLLIBOBJECTS=$(ALPHA_DLLLIBOBJECTS)
+!ELSEIF $(PPC)
+OBJECTS=$(PPC_OBJECTS)
+DLLLIBOBJECTS=$(PPC_DLLLIBOBJECTS)
+!ENDIF
+
+#
+# BUILD.EXE defines the NOLINK variable to disable the building of any
+# test executables when it is recursing on a dirs. file to build components
+# in subdirectories.
+#
+
+!IF "$(BUILDMSG)" != "Stop."
+! IFDEF NOLINK
+! UNDEF NTTEST
+! UNDEF MAKEDLL
+! ELSE
+! IFDEF nolink
+! UNDEF NTTEST
+! UNDEF MAKEDLL
+! ENDIF
+! ENDIF # DEF NOLINK
+!ENDIF # BUILDMSG != "Stop."
+
+
+#
+# Determine type of target link we are doing
+#
+!IF "$(TARGETTYPE)" == "PROGLIB"
+TARGETEXT=exe
+TARGETLIB=
+!ELSE
+! IF "$(TARGETTYPE)" == "PROGRAM"
+TARGETEXT=exe
+TARGETLIB=
+! ELSE
+! IF "$(TARGETTYPE)" == "DYNLINK"
+
+DYNLINK_LIB=$(TARGETPATH)\*\$(TARGETNAME).lib
+
+! IF "$(MAKEDLL)" != ""
+! IF "$(UMTYPE)" == "os2"
+TARGETLIB=$(BASEDIR)\public\sdk\lib\*\ntdll.lib
+! ELSE
+! IF "$(UMTYPE)" == "posix"
+TARGETLIB=$(BASEDIR)\public\sdk\lib\*\libcpsx.lib $(BASEDIR)\public\sdk\lib\*\ntdll.lib $(CRT_LIBS)
+! ELSE
+! IF "$(TARGETNAME)" == "ntdll"
+TARGETLIB=
+! ELSE
+! IFDEF USE_CRTDLL
+! IFDEF CHICAGO_PRODUCT
+TARGETLIB=$(WIN32DLL_LIBS) $(BASEDIR)\public\sdk\lib\*\crtdll.lib
+! ELSE
+TARGETLIB=$(WIN32DLL_LIBS) $(BASEDIR)\public\sdk\lib\*\crtdll.lib $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+! ENDIF
+! ELSE
+! IFDEF USE_MSVCRT
+TARGETLIB=$(WIN32DLL_LIBS) $(LIBC_LIB)
+! ELSE
+TARGETLIB=$(WIN32DLL_LIBS) $(BASEDIR)\public\sdk\lib\*\ntdll.lib $(CRT_LIBS)
+! ENDIF
+! ENDIF
+! ENDIF
+! ENDIF
+! ENDIF
+! IF "$(TARGETEXT)" == ""
+TARGETEXT=dll
+! ENDIF
+! IFDEF CAIROLIB
+
+#
+# If we are linking a DLL then add in the cairo libs.
+#
+
+TARGETLIB=$(CAIROLIB) $(TARGETLIB)
+! ENDIF
+! IFDEF CAIRO_PRODUCT
+! IFNDEF TUKWILA
+TARGETLIB=$(TARGETLIB:lib\*\ntdll.lib=lib\cairo\*\ntdll.lib)
+! ENDIF
+! ENDIF
+! ELSE # "$(MAKEDLL)" != ""
+TARGETEXT=lib
+TARGETLIB=
+! ENDIF # "$(MAKEDLL)" != ""
+! ELSE
+! IF "$(TARGETTYPE)" == "LIBRARY"
+TARGETEXT=lib
+TARGETLIB=
+! ELSE
+! IF "$(TARGETTYPE)" == "DRIVER"
+TARGETEXT=sys
+TARGETLIB=$(BASEDIR)\public\sdk\lib\*\ntoskrnl.lib $(BASEDIR)\public\sdk\lib\*\hal.lib $(CRT_LIBS)
+! ELSE
+! IF "$(TARGETTYPE)" == "EXPORT_DRIVER"
+! IF "$(MAKEDLL)" != ""
+TARGETEXT=sys
+TARGETLIB=$(BASEDIR)\public\sdk\lib\*\ntoskrnl.lib $(BASEDIR)\public\sdk\lib\*\hal.lib $(CRT_LIBS)
+! ELSE
+TARGETEXT=lib
+TARGETLIB=
+! ENDIF
+! ELSE
+! IF "$(TARGETTYPE)" == "HAL"
+! IF "$(MAKEDLL)" != ""
+TARGETEXT=dll
+TARGETLIB=$(BASEDIR)\public\sdk\lib\*\ntoskrnl.lib $(CRT_LIBS)
+! ELSE
+TARGETEXT=lib
+TARGETLIB=
+! ENDIF
+! ELSE
+! IF "$(TARGETTYPE)" == "BOOTPGM"
+TARGETEXT=sys
+! ELSE
+! IF "$(TARGETTYPE)" == "MINIPORT"
+TARGETEXT=sys
+! ELSE
+! IF "$(TARGETTYPE)" == "GDI_DRIVER"
+TARGETEXT=dll
+TARGETLIB=$(BASEDIR)\public\sdk\lib\km\*\win32k.lib
+! ENDIF # TARGETTYPE == GDI_DRIVER
+! ENDIF # TARGETTYPE == MINIPORT
+! ENDIF # TARGETTYPE == BOOTPGM
+! ENDIF # TARGETTYPE == HAL
+! ENDIF # TARGETTYPE == EXPORT_DRIVER
+! ENDIF # TARGETTYPE == DRIVER
+! ENDIF # TARGETTYPE == LIBRARY
+! ENDIF # TARGETTYPE == DYNLINK
+! ENDIF # TARGETTYPE == PROGRAM
+!ENDIF # TARGETTYPE == PROGLIB
+
+
+TARGET=
+
+!IF "$(TARGETTYPE)" != "UMAPPL_NOLIB"
+
+! IF "$(OBJECTS)" != ""
+TARGET=$(TARGETPATH)\*\$(TARGETNAME).$(TARGETEXT)
+! ENDIF
+
+!ENDIF # TARGETTYPE != UMAPPL_NOLIB
+
+!IFNDEF MACHINE_TARGETLIBS
+MACHINE_TARGETLIBS=$(TARGETLIB) $(TARGETLIBS)
+!ENDIF
+
+
+TARGETOBJFILES=$(TARGETOBJFILES) $(OBJECTS)
+
+!IF "$(NOLINK)" == "" || \
+ ("$(NOLINK)" != "" && ("$(TARGETTYPE)"=="LIBRARY" || \
+ ( ("$(TARGETTYPE)"=="DYNLINK" || \
+ "$(TARGETTYPE)"=="PROGLIB" || \
+ "$(TARGETTYPE)"=="EXPORT_DRIVER" || \
+ "$(TARGETTYPE)"=="HAL") && \
+ "$(MAKEDLL)" == "") \
+ ) \
+ )
+
+
+!IF "$(NOLINK)" != "" && "$(TARGET)" != ""
+TARGETLIBFILES=$(TARGETLIBFILES) $(TARGETPATH)\*\$(TARGETNAME).lib
+!ELSE
+TARGETEXEFILES=$(TARGETEXEFILES) $(TARGET)
+!ENDIF
+
+!ENDIF # NOLINK == "" || building .lib file for dll
+
+!IF "$(NTTEST)" != ""
+
+TARGETOBJFILES=$(TARGETOBJFILES) obj\*\$(NTTEST).obj
+
+! IFNDEF NOLINK
+
+TARGETEXEFILES=$(TARGETEXEFILES) obj\*\$(NTTEST).exe
+
+! ENDIF # NDEF NOLINK
+!ENDIF # NTTEST != ""
+
+UMOBJFILES=
+UMEXEFILES=
+
+!IF "$(UMAPPLEXT)" == ""
+! IFDEF _DOT_COM_FILE
+UMAPPLEXT=.com
+! ELSE
+UMAPPLEXT=.exe
+! ENDIF
+!ENDIF
+
+!IF "$(UMAPPL)" != ""
+
+UMOBJFILES=obj\*\$(UMAPPL:*=.obj obj\*\).obj
+
+
+! IF "$(UMAPPLEXT)" == ".com"
+! IFNDEF NOLINK
+
+UMEXEFILES=obj\*\$(UMAPPL:*=.com obj\*\).com
+! ENDIF
+! ELSE
+! IF "$(UMAPPLEXT)" == ".exe"
+! IFNDEF NOLINK
+
+UMEXEFILES=obj\*\$(UMAPPL:*=.exe obj\*\).exe
+! ENDIF
+! ELSE
+
+! IF "$(UMAPPLEXT)" == ".scr"
+! IFNDEF NOLINK
+
+UMEXEFILES=obj\*\$(UMAPPL:*=.scr obj\*\).scr
+
+! ENDIF
+
+! ELSE
+
+! ERROR Unsupport UMAPPLEXT = $(UMAPPLEXT)
+
+! ENDIF # UMAPPLEXT == .scr
+! ENDIF # UMAPPLEXT == .exe
+! ENDIF # UMAPPLEXT == .com
+!ENDIF # UMAPPL != ""
+
+!IF "$(UMTEST)" != ""
+
+UMOBJFILES=$(UMOBJFILES) obj\*\$(UMTEST:*=.obj obj\*\).obj
+
+! IFNDEF NOLINK
+
+UMEXEFILES=$(UMEXEFILES) obj\*\$(UMTEST:*=.exe obj\*\).exe
+
+! ENDIF
+!ENDIF
+
+#
+# Define NT_UP as 0 in environment to turn on MP.
+# If undefined or equal to 1, you get UP.
+#
+
+!IFNDEF NT_UP
+NT_UP=1
+!ENDIF
+
+!IF "$(NT_UP)"=="0"
+NT_UP_DEFINES=
+!ELSE
+NT_UP_DEFINES=-DNT_UP=1
+!ENDIF
+
+!IFNDEF NT_INST
+NT_INST=0
+!ENDIF
+
+!IFNDEF PNP_POWER
+PNP_POWER=0
+!ENDIF
+
+!IF "$(PNP_POWER)"=="0"
+NT_PNP_POWER_DEFINES=
+!ELSE
+NT_PNP_POWER_DEFINES=-D_PNP_POWER_=1
+!ENDIF
+
+
+#
+# User defined variables (environment variables or command line).
+# A cpu specific definition will take precedence over the MSC definition.
+#
+# xxx_WARNING_LEVEL
+# xxx_OPTIMIZATION
+# xxx_CPPFLAGS
+#
+
+!IFNDEF MSC_WARNING_LEVEL
+MSC_WARNING_LEVEL=/W3
+!ENDIF
+
+!IFNDEF MSC_OPTIMIZATION
+MSC_OPTFLAGS=/Oxs $(MSC_OPTIMIZATION)
+!ELSE
+MSC_OPTFLAGS=$(MSC_OPTIMIZATION)
+!ENDIF
+
+#
+# End of user defined variables.
+#
+
+!IFDEF NOT_LEAN_AND_MEAN
+STD_DEFINES=-DCONDITION_HANDLING=1 $(NT_UP_DEFINES) \
+ -DNT_INST=$(NT_INST) $(WIN32_DEFINE) $(NT_PNP_POWER_DEFINES)
+!ELSE
+STD_DEFINES=-DCONDITION_HANDLING=1 -DWIN32_LEAN_AND_MEAN=1 $(NT_UP_DEFINES) \
+ -DNT_INST=$(NT_INST) $(WIN32_DEFINE) $(NT_PNP_POWER_DEFINES)
+!ENDIF
+
+!IFNDEF CBSTRING
+!IF "$(MAJORCOMP)" == "ntos" || "$(MAJORCOMP)" == "NTOS"
+CBSTRING= -cbstring
+!ELSE
+CBSTRING=
+!ENDIF
+!ENDIF
+
+!IF "$(NTDEBUG)" == "retail"
+TARGET_DBG_DEFINES= -DDBG=0 -DDEVL=1
+DBGFLAGS=$(MSC_OPTFLAGS)
+!ELSE
+! IF "$(NTDEBUG)" == ""
+TARGET_DBG_DEFINES= -DDBG=0 -DDEVL=1
+DBGFLAGS=$(MSC_OPTFLAGS)
+! ELSE
+TARGET_DBG_DEFINES= -DDBG=1 -DDEVL=1
+!UNDEF NTLEGO
+! IF "$(NTDEBUG)" == "ntsd"
+DBGFLAGS=$(MSC_OPTFLAGS) /Zi
+! ELSE
+! IF "$(NTDEBUG)" == "cvp"
+DBGFLAGS=$(MSC_OPTFLAGS) /Zd
+! ELSE
+! IF "$(NTDEBUG)" == "sym"
+DBGFLAGS=$(MSC_OPTFLAGS) /Zd
+! ELSE
+! IF "$(NTDEBUG)" == "ntsdnodbg"
+DBGFLAGS=$(MSC_OPTFLAGS) /Zi
+TARGET_DBG_DEFINES= -DDBG=0 -DDEVL=1
+! ELSE
+! ERROR NTDEBUG macro can be either "retail", "", "ntsd", "cvp" or "sym" or "ntsdnodbg"
+! ENDIF
+! ENDIF # NTDEBUG == ntsdnodbg
+! ENDIF # NTDEBUG == sym
+! ENDIF # NTDEBUG == cvp
+! ENDIF # NTDEBUG == ""
+!ENDIF # NTDEBUG == retail
+
+!IF "$(NTDEBUGTYPE)" == "windbg"
+LINKER_DBG_TYPE = -debugtype:cv
+!ELSE
+! IF "$(NTDEBUGTYPE)" == "ntsd" || "$(NTDEBUGTYPE)" == "coff"
+LINKER_DBG_TYPE = -debugtype:coff
+! ELSE
+! IF "$(NTDEBUGTYPE)" == "both"
+LINKER_DBG_TYPE = -debugtype:both
+! ELSE
+! IF "$(NTDEBUGTYPE)" == ""
+LINKER_DBG_TYPE = -debugtype:coff
+! ELSE
+! ERROR NTDEBUGTYPE macro can one of "", "ntsd", "coff", "windbg" or "both"
+! ENDIF
+! ENDIF
+! ENDIF
+!ENDIF
+
+
+!IF "$(PRECOMPILED_OPTION)" == ""
+! IF "$(PRECOMPILED_INCLUDE)" != ""
+! IF "$(PRECOMPILED_INCLUDE)" != "$(PRECOMPILED_INCLUDE:.hxx=)"
+PRECOMPILED_CXX=1
+! ENDIF
+! IF "$(PRECOMPILED_INCLUDE)" != "$(PRECOMPILED_INCLUDE:.cxx=)"
+PRECOMPILED_CXX=1
+! ENDIF
+! IF "$(PRECOMPILED_PCH)" == ""
+PRECOMPILED_PCH=$(PRECOMPILED_INCLUDE:.hxx=.pch)
+PRECOMPILED_PCH=$(PRECOMPILED_PCH:.h=.pch)
+PRECOMPILED_PCH=$(PRECOMPILED_PCH:.cxx=.pch)
+PRECOMPILED_PCH=$(PRECOMPILED_PCH:.c=.pch)
+PRECOMPILED_PCH=$(PRECOMPILED_PCH:..\=)
+! ENDIF
+! IF "$(PRECOMPILED_OBJ)" == ""
+PRECOMPILED_OBJ=$(PRECOMPILED_PCH:.pch=.obj)
+! ENDIF
+! ENDIF
+!ENDIF
+
+! IF "$(PRECOMPILED_OPTION)" == ""
+! IF "$(PRECOMPILED_INCLUDE)" != ""
+! IF "$(PRECOMPILED_PCH)" != ""
+HEADERFILE=/Fpobj\*\$(PRECOMPILED_PCH)
+! ENDIF
+! IF "$(PRECOMPILED_OBJ)" != ""
+HEADEROBJNAME=obj\*\$(PRECOMPILED_OBJ)
+HEADEROBJ=/Fo$(MAKEDIR)\$(HEADEROBJNAME)
+! ENDIF
+! IF "$(PRECOMPILED_CXX)" == ""
+PRECOMPILED=/Yu$(PRECOMPILED_INCLUDE:..\=) $(HEADERFILE)
+PRECOMPILED_CXX=
+! ELSE
+PRECOMPILED=
+PRECOMPILED_CXX=/Yu$(PRECOMPILED_INCLUDE:..\=) $(HEADERFILE)
+! ENDIF
+PRECOMPILED_TARGET=obj\*\$(PRECOMPILED_PCH)
+! ELSE
+! IF "$(PRECOMPILED_INCLUDE)" != ""
+! IF "$(PRECOMPILED_CXX)" == ""
+PRECOMPILED=/Yu$(PRECOMPILED_INCLUDE)
+PRECOMPILED_CXX=
+! ELSE
+PRECOMPILED=
+PRECOMPILED_CXX=/Yu$(PRECOMPILED_INCLUDE)
+! ENDIF
+! ENDIF
+! ENDIF
+! ELSE
+! IF "$(PRECOMPILED_CXX)" == ""
+PRECOMPILED=$(PRECOMPILED_OPTION)
+PRECOMPILED_CXX=
+! ELSE
+PRECOMPILED=
+PRECOMPILED_CXX=$(PRECOMPILED_OPTION)
+! ENDIF
+PRECOMPILED_TARGET=$(PRECOMPILED_TARGET)
+! IF "$(PRECOMPILED_TARGET)" != ""
+HEADERFILE=/Fp$(PRECOMPILED_TARGET)
+! ENDIF
+! IF "$(PRECOMPILED_OBJ)" != ""
+HEADEROBJNAME=$(PRECOMPILED_OBJ)
+HEADEROBJ=/Fo$(HEADEROBJNAME)
+! ENDIF
+! ENDIF
+
+!IF ("$(PRECOMPILED_CXX)" == "") && ("$(USECXX_FLAG)" == "")
+PRECOMPILED_FLAG=/Tc
+!ELSE
+PRECOMPILED_FLAG=/Tp
+!ENDIF
+
+!IF "$(NTNOPCH)" != ""
+PRECOMPILED=
+PRECOMPILED_CXX=
+!ENDIF
+
+#
+# Set linker options
+#
+
+#
+# Merge _PAGE with PAGE, _TEXT with .text, and make sure
+# INIT sections are discardable
+#
+
+LINK_LIB_IGNORE_FLAG=-IGNORE:4001,4037,4039,4065,4070,4078,4087,4089
+LINKER_FLAGS = $(LINKER_FLAGS) \
+ -MERGE:_PAGE=PAGE \
+ -MERGE:_TEXT=.text \
+ -SECTION:INIT,d \
+ -OPT:REF \
+ -RELEASE \
+ -INCREMENTAL:NO \
+ -FULLBUILD \
+ -FORCE:MULTIPLE \
+ -NODEFAULTLIB \
+ $(LINK_LIB_IGNORE_FLAG)
+
+LINKER_MERGE_RDATA=-MERGE:.rdata=.text
+LINKER_OPTIDATA=-optidata
+
+!if "$(USE_PDB)" == ""
+LINKER_FLAGS = $(LINKER_FLAGS) -PDB:NONE
+!elseif ("$(PDB_ROOT)" != "") && ("$(CAIRO_PRODUCT)" == "")
+LINKER_FLAGS = $(LINKER_FLAGS) -PDB:$(PDB_ROOT)\$(TARGETEXT)^\
+PDB_ROOTUM = -PDB:$(PDB_ROOT)\$(UMAPPLEXT:.=)^\
+!elseif ("$(CAIROPDB_ROOT)" != "") && ("$(CAIRO_PRODUCT)" != "")
+LINKER_FLAGS = $(LINKER_FLAGS) -PDB:$(CAIROPDB_ROOT)\$(TARGETEXT)^\
+PDB_ROOTUM = -PDB:$(CAIROPDB_ROOT)\$(UMAPPLEXT:.=)^\
+!endif
+
+!IF "$(NTDEBUG)" == "ntsd" || "$(NTDEBUG)" == "ntsdnodbg"
+! IF "$(PERFFLAGS)" != ""
+LINKER_DBG_SECTION=-debug:mapped,FULL
+! ELSE
+LINKER_DBG_SECTION=-debug:notmapped,FULL
+! ENDIF # PERFFLAGS != NULL
+!ELSE
+! IF "$(NTDEBUG)" == "retail"
+LINKER_DBG_SECTION=-debug:NONE
+! ELSE
+! IF "$(PERFFLAGS)" != ""
+LINKER_DBG_SECTION=-debug:mapped,MINIMAL
+! ELSE
+LINKER_DBG_SECTION=-debug:notmapped,MINIMAL
+! ENDIF # PERFFLAGS != NULL
+! ENDIF # NTDEBUG == retail
+!ENDIF # NTDEBUG == ntsd
+
+!IF "$(NTLEANANDMEAN)" == "leanandmean"
+! IF "$(NTDEBUGTYPE)" == "coff" || \
+ "$(NTTEST)"=="ntoskrnl" || \
+ "$(NTTEST)"=="ntkrnlmp" || \
+ "$(TARGETTYPE)"=="DRIVER" || \
+ "$(TARGETTYPE)"=="MINIPORT" || \
+ "$(TARGETTYPE)"=="EXPORT_DRIVER" || \
+ "$(TARGETTYPE)"=="HAL"
+LINKER_DBG_SECTION=-debug:notmapped,minimal
+! ELSE
+LINKER_DBG_SECTION=-debug:none
+! ENDIF # NTDEBUGTYPE != coff || TARGETTYPE
+!ENDIF # NTLEANANDMEAN == leanandmean
+
+LINK_OS_VERSIONS = -version:3.51 -osversion:3.51
+
+LINKER_FLAGS = $(LINKER_FLAGS) $(LINKER_DBG_SECTION) $(LINKER_DBG_TYPE) $(LINK_OS_VERSIONS)
+LIBRARIAN_FLAGS = $(LIBRARIAN_FLAGS) $(LINK_LIB_IGNORE_FLAG)
+
+LIBRARIAN=lib -out:$@ $(LIBRARIAN_FLAGS) $(LINKER_DBG_TYPE) -machine:$(TARGET_DIRECTORY)
+LINKER=link -out:$@ -machine:$(TARGET_DIRECTORY)
+
+!IFDEF EXEPROFILEINPUT
+EXEORDER=-order:@$(@B).prf
+!ENDIF
+
+!IFNDEF DRIVER_ALIGNMENT
+DRIVER_ALIGNMENT=0x20
+!ENDIF
+
+!ifndef HAL_ALIGNMENT
+HAL_ALIGNMENT=0x20
+!endif
+
+!ifndef KERNEL_ALIGNMENT
+KERNEL_ALIGNMENT=0x40
+!endif
+
+#
+# Standard inference rules for C files that produce object files.
+#
+
+.SUFFIXES: .cxx .cpp .c .f .rc .s .asm .obj .exe .res .p .tdl .odl
+
+#
+# Processor specific control and options.
+#
+
+!include $(TARGET_DIRECTORY)mk.inc
+
+LINKER_FLAGS = $(LINKER_FLAGS) $(LINKER_MERGE_RDATA)
+
+#
+# Clear the suffixes list so we can ensure only pass zero stuff will be built
+#
+!IFDEF PASS0ONLY
+.SUFFIXES:
+!ENDIF
+
+#
+# If NTDBGFILES is defined then use binplace to split the symbols.
+# Define BINPLACE flags as needed if separate .DBG file requested.
+#
+
+!IFDEF NTDBGFILES
+BINPLACE_FLAGS=-s $(_NTTREE)\Symbols $(BINPLACE_FLAGS)
+!ENDIF
+
+!IFDEF _NTTREE
+! IFDEF _WIN95TREE
+! IFDEF NTDBGFILES
+BINPLACE_FLAGS95=$(BINPLACE_FLAGS) -s $(_WIN95TREE)\Symbols
+! ENDIF
+BINPLACE_CMD=binplace -R $(_WIN95TREE) $(BINPLACE_FLAGS95) $@\
+ & binplace -R $(_NTTREE) $(BINPLACE_FLAGS) $@
+! ELSE
+BINPLACE_CMD=binplace -R $(_NTTREE) $(BINPLACE_FLAGS) $@
+! ENDIF
+!ELSE
+BINPLACE_CMD=
+!ENDIF
+
+!ifdef NTDUMPAMAP
+MAPDUMP_CMD = link -dump -map $@ | sort /R /+62 > $(_NTDUMPAMAP)\$(@B).srt
+!else
+MAPDUMP_CMD =
+!endif
+
+
+#
+# Define this macro so including make files can supply a yes prompt
+# as appropriate. Put the "yes." file in a visible place for OEM's
+# so they can make too.
+#
+
+YESRESP=$(BASEDIR)\PUBLIC\OAK\INC\yes.
+
+!IFNDEF NOPASS0
+
+#
+# Pass Zero Inference Rules: IDL files (MIDL) and MC files
+#
+
+.SUFFIXES: .idl .mc
+
+!IF $(386)
+PASS0_OBJECTS=$(PASS0_386_OBJECTS)
+!ELSEIF $(MIPS)
+PASS0_OBJECTS=$(PASS0_MIPS_OBJECTS)
+!ELSEIF $(ALPHA)
+PASS0_OBJECTS=$(PASS0_ALPHA_OBJECTS)
+!ELSEIF $(PPC)
+PASS0_OBJECTS=$(PASS0_PPC_OBJECTS)
+!ENDIF
+
+!ENDIF # IFNDEF NOPASS0
+
+MIDL = midl
+MKTYPLIB = mktyplib
+!IFDEF USE_OLE_MC
+MC = mc -o
+!ELSE
+MC = mc
+!ENDIF
+
+!IF "$(IDL_TYPE)" == "ole" || "$(IDL_TYPE)" == ""
+IDL_TYPE=OLE
+!ELSEIF "$(IDL_TYPE)" == "rpc"
+IDL_TYPE=RPC
+!ENDIF
+
+!IFNDEF PASS0_HEADERDIR
+PASS0_HEADERDIR=$(TARGETPATH)
+!ENDIF
+
+!IFNDEF MIDL_OPTIMIZATION
+MIDL_OPTIMIZATION=-Oi1
+!ENDIF
+
+!IF "$(IDL_TYPE)" == "OLE"
+
+!IF DEFINED(PASS0_CLIENTDIR) || DEFINED(PASS0_SERVERDIR)
+!ERROR PASS0_CLIENTDIR and PASS0_SERVERDIR can only be used with IDL_TYPE=RPC!
+!ENDIF
+
+!IFNDEF PASS0_SOURCEDIR
+PASS0_SOURCEDIR=$(TARGETPATH)
+!ENDIF
+
+!IFNDEF MIDL_UUIDDIR
+MIDL_UUIDDIR=$(PASS0_SOURCEDIR)
+!ENDIF
+
+!IFNDEF NO_PASS0_RULES
+.idl{$(PASS0_HEADERDIR)}.h:
+ $(MIDL) \
+ -Zp8 \
+ $(INCPATH0) \
+ -char unsigned \
+ -ms_ext -c_ext \
+ -proxy $(PASS0_SOURCEDIR)\$(<:.idl=_p.c) \
+ -dlldata $(PASS0_SOURCEDIR)\dlldata.c \
+ -iid $(MIDL_UUIDDIR)\$(<:.idl=_i.c) \
+ -header $(PASS0_HEADERDIR)\$(<:.idl=.h) \
+ -cpp_cmd $(TARGET_CPP) \
+ $(C_DEFINES) \
+ $(MIDL_FLAGS) \
+ $(MIDL_OPTIMIZATION) \
+ $<
+!ENDIF
+
+!ELSEIF "$(IDL_TYPE)" == "RPC"
+
+!IF DEFINED(PASS0_SOURCEDIR) || DEFINED(MIDL_UUIDDR)
+!ERROR PASS0_SOURCEDIR and MIDL_UUIDDIR can only be used with IDL_TYPE=OLE!
+!ENDIF
+
+!IFNDEF PASS0_CLIENTDIR
+PASS0_CLIENTDIR=$(TARGETPATH)
+!ENDIF
+
+!IFNDEF PASS0_SERVERDIR
+PASS0_SERVERDIR=$(PASS0_CLIENTDIR)
+!ENDIF
+
+!IFNDEF NO_PASS0_RULES
+.idl{$(PASS0_HEADERDIR)}.h:
+ $(MIDL) \
+ -Zp8 \
+ $(INCPATH0) \
+ -char unsigned \
+ -ms_ext -c_ext \
+ -cstub $(PASS0_CLIENTDIR)\$(<:.idl=_c.c) \
+ -sstub $(PASS0_SERVERDIR)\$(<:.idl=_s.c) \
+ -cpp_cmd $(TARGET_CPP) \
+ $(C_DEFINES) \
+ $(MIDL_FLAGS) \
+ $(MIDL_OPTIMIZATION) \
+ $<
+!ENDIF
+
+!ELSE
+
+!ERROR Invalid IDL_TYPE value. Supported values: OLE and RPC.
+
+!ENDIF # IDL_TYPE
+
+
+!IFNDEF NO_PASS0_RULES
+
+!IFDEF PASS0_SOURCEDIR
+MC_SOURCEDIR=$(PASS0_SOURCEDIR)
+!ELSE
+MC_SOURCEDIR=$(PASS0_CLIENTDIR)
+!ENDIF
+
+.mc{$(PASS0_HEADERDIR)}.h:
+ $(MC) -h $(PASS0_HEADERDIR) -r $(MC_SOURCEDIR) $(MC_FLAGS) $<
+
+!IF "$(TARGET_CPP)" == "claxp"
+MKTYPLIB_CPP = cl
+!ELSE
+MKTYPLIB_CPP = $(TARGET_CPP)
+!ENDIF
+.odl{obj\$(TARGET_DIRECTORY)\}.tlb:
+ $(MKTYPLIB) \
+ $(INCPATH0) \
+ /tlb obj\$(TARGET_DIRECTORY)\$(<:.tdl=.tlb) \
+ -cpp_cmd $(MKTYPLIB_CPP) \
+ $(MKTYPLIB_FLAGS) \
+ $<
+ $(BINPLACE_CMD)
+
+.tdl{obj\$(TARGET_DIRECTORY)\}.tlb:
+ $(MKTYPLIB) \
+ $(INCPATH0) \
+ /tlb obj\$(TARGET_DIRECTORY)\$(<:.tdl=.tlb) \
+ -cpp_cmd $(MKTYPLIB_CPP) \
+ $(MKTYPLIB_FLAGS) \
+ $<
+ $(BINPLACE_CMD)
+
+!ENDIF
+
+#
+# Default language ID to US English (0x0409)
+#
+
+!IFDEF RCCODEPAGE
+RCOPTIONS=$(RCOPTIONS) -c $(RCCODEPAGE)
+!ENDIF
+
+RC_COMPILER=rc -l 409 $(RCOPTIONS)
+
+{..\}.rc{obj\$(TARGET_DIRECTORY)\}.res:
+ $(RC_COMPILER) -r -fo $(@R).tmp $(CDEFINES) -x $(INCPATH0) $<
+ @cvtres -$(TARGET_DIRECTORY) $(@R).tmp -r -o $@
+!IF "$(NTKEEPRESOURCETMPFILES)" == ""
+ @-erase $(@R).tmp
+!ENDIF
+
+{}.rc{obj\$(TARGET_DIRECTORY)\}.res:
+ $(RC_COMPILER) -r -fo $(@R).tmp $(CDEFINES) -x $(INCPATH0) $<
+ @cvtres -$(TARGET_DIRECTORY) $(@R).tmp -r -o $@
+!IF "$(NTKEEPRESOURCETMPFILES)" == ""
+ @-erase $(@R).tmp
+!ENDIF
+
+!IFNDEF NO_C_RULES
+
+ECHO_RSP = obj\$(TARGET_DIRECTORY)\echo.msg
+CL_RSP = obj\$(TARGET_DIRECTORY)\cl.rsp
+CLCOD_RSP = obj\$(TARGET_DIRECTORY)\clcod.rsp
+LINK_RSP = obj\$(TARGET_DIRECTORY)\lnk.rsp
+
+{..\}.cxx{obj\$(TARGET_DIRECTORY)\}.obj:
+ @type <<$(ECHO_RSP)
+$(ECHO_MSG)
+<<NOKEEP
+ @$(CXX_COMPILER_NAME) @<<$(CL_RSP) -Fo$(MAKEDIR)\$@ $(MAKEDIR)\..\$(<F)
+$(CXX_COMPILER_FLAGS: =
+)
+<<NOKEEP
+
+{..\$(TARGET_DIRECTORY)\}.cxx{obj\$(TARGET_DIRECTORY)\}.obj:
+ @type <<$(ECHO_RSP)
+$(ECHO_MSG)
+<<NOKEEP
+ @$(CXX_COMPILER_NAME) @<<$(CL_RSP) -Fo$(MAKEDIR)\$@ $(MAKEDIR)\$<
+$(CXX_COMPILER_FLAGS: =
+)
+<<NOKEEP
+
+{..\}.cpp{obj\$(TARGET_DIRECTORY)\}.obj:
+ @type <<$(ECHO_RSP)
+$(ECHO_MSG)
+<<NOKEEP
+ @$(CXX_COMPILER_NAME) @<<$(CL_RSP) -Fo$(MAKEDIR)\$@ $(MAKEDIR)\..\$(<F)
+$(CXX_COMPILER_FLAGS: =
+)
+<<NOKEEP
+
+{..\$(TARGET_DIRECTORY)\}.cpp{obj\$(TARGET_DIRECTORY)\}.obj:
+ @type <<$(ECHO_RSP)
+$(ECHO_MSG)
+<<NOKEEP
+ @$(CXX_COMPILER_NAME) @<<$(CL_RSP) -Fo$(MAKEDIR)\$@ $(MAKEDIR)\$<
+$(CXX_COMPILER_FLAGS: =
+)
+<<NOKEEP
+
+{}.cxx{obj\$(TARGET_DIRECTORY)\}.obj:
+ @type <<$(ECHO_RSP)
+$(ECHO_MSG)
+<<NOKEEP
+ @$(CXX_COMPILER_NAME) @<<$(CL_RSP) -Fo$(MAKEDIR)\$@ $(MAKEDIR)\$(<F)
+$(CXX_COMPILER_FLAGS: =
+)
+<<NOKEEP
+
+{$(TARGET_DIRECTORY)\}.cxx{obj\$(TARGET_DIRECTORY)\}.obj:
+ @type <<$(ECHO_RSP)
+$(ECHO_MSG)
+<<NOKEEP
+ @$(CXX_COMPILER_NAME) @<<$(CL_RSP) -Fo$(MAKEDIR)\$@ $(MAKEDIR)\$<
+$(CXX_COMPILER_FLAGS: =
+)
+<<NOKEEP
+
+{}.cpp{obj\$(TARGET_DIRECTORY)\}.obj:
+ @type <<$(ECHO_RSP)
+$(ECHO_MSG)
+<<NOKEEP
+ @$(CXX_COMPILER_NAME) @<<$(CL_RSP) -Fo$(MAKEDIR)\$@ $(MAKEDIR)\$(<F)
+$(CXX_COMPILER_FLAGS: =
+)
+<<NOKEEP
+
+{$(TARGET_DIRECTORY)\}.cpp{obj\$(TARGET_DIRECTORY)\}.obj:
+ @type <<$(ECHO_RSP)
+$(ECHO_MSG)
+<<NOKEEP
+ @$(CXX_COMPILER_NAME) @<<$(CL_RSP) -Fo$(MAKEDIR)\$@ $(MAKEDIR)\$<
+$(CXX_COMPILER_FLAGS: =
+)
+<<NOKEEP
+
+{..\}.cxx{}.cod:
+ @-erase $(CLCOD_RSP)
+ $(CXX_COMPILER_NAME) @<<$(CLCOD_RSP) /Fc $(MAKEDIR)\..\$(<F)
+$(CXX_COMPILER_FLAGS: =
+)
+<<KEEP
+
+{..\}.cxx{}.pp:
+ $(CXX_COMPILER_NAME) @<<$(CL_RSP) /E $(MAKEDIR)\$< > $@
+$(CXX_COMPILER_FLAGS: =
+)
+<<NOKEEP
+
+{..\}.cpp{}.cod:
+ @-erase $(CLCOD_RSP)
+ $(CXX_COMPILER_NAME) @<<$(CLCOD_RSP) /Fc $(MAKEDIR)\..\$(<F)
+$(CXX_COMPILER_FLAGS: =
+)
+<<KEEP
+
+{..\}.cpp{}.pp:
+ $(CXX_COMPILER_NAME) @<<$(CL_RSP) /E $(MAKEDIR)\$< > $@
+$(CXX_COMPILER_FLAGS: =
+)
+<<NOKEEP
+
+{}.cxx{}.cod:
+ @-erase $(CLCOD_RSP)
+ $(CXX_COMPILER_NAME) @<<$(CLCOD_RSP) /Fc $(MAKEDIR)\$(<F)
+$(CXX_COMPILER_FLAGS: =
+)
+<<KEEP
+
+{}.cxx{}.pp:
+ $(CXX_COMPILER_NAME) @<<$(CL_RSP) /E $(MAKEDIR)\$< > $@
+$(CXX_COMPILER_FLAGS: =
+)
+<<NOKEEP
+
+{}.cpp{}.cod:
+ @-erase $(CLCOD_RSP)
+ $(CXX_COMPILER_NAME) @<<$(CLCOD_RSP) /Fc $(MAKEDIR)\$(<F)
+$(CXX_COMPILER_FLAGS: =
+)
+<<KEEP
+
+{}.cpp{}.pp:
+ $(CXX_COMPILER_NAME) @<<$(CL_RSP) /E $(MAKEDIR)\$< > $@
+$(CXX_COMPILER_FLAGS: =
+)
+<<NOKEEP
+
+{..\}.c{obj\$(TARGET_DIRECTORY)\}.obj:
+ @type <<$(ECHO_RSP)
+$(ECHO_MSG)
+<<NOKEEP
+ @$(C_COMPILER_NAME) @<<$(CL_RSP) -Fo$(MAKEDIR)\$@ $(USECXX_FLAG) $(MAKEDIR)\..\$(<F)
+$(C_COMPILER_FLAGS: =
+)
+<<NOKEEP
+
+{..\$(TARGET_DIRECTORY)\}.c{obj\$(TARGET_DIRECTORY)\}.obj:
+ @type <<$(ECHO_RSP)
+$(ECHO_MSG)
+<<NOKEEP
+ @$(C_COMPILER_NAME) @<<$(CL_RSP) -Fo$(MAKEDIR)\$@ $(USECXX_FLAG) $(MAKEDIR)\$<
+$(C_COMPILER_FLAGS: =
+)
+<<NOKEEP
+
+{}.c{obj\$(TARGET_DIRECTORY)\}.obj:
+ @type <<$(ECHO_RSP)
+$(ECHO_MSG)
+<<NOKEEP
+ @$(C_COMPILER_NAME) @<<$(CL_RSP) -Fo$(MAKEDIR)\$@ $(USECXX_FLAG) $(MAKEDIR)\$(<F)
+$(C_COMPILER_FLAGS: =
+)
+<<NOKEEP
+
+{$(TARGET_DIRECTORY)\}.c{obj\$(TARGET_DIRECTORY)\}.obj:
+ @type <<$(ECHO_RSP)
+$(ECHO_MSG)
+<<NOKEEP
+ @$(C_COMPILER_NAME) @<<$(CL_RSP) -Fo$(MAKEDIR)\$@ $(USECXX_FLAG) $(MAKEDIR)\$<
+$(C_COMPILER_FLAGS: =
+)
+<<NOKEEP
+
+{..\}.c{}.cod:
+ @-erase $(CLCOD_RSP)
+ $(C_COMPILER_NAME) @<<$(CLCOD_RSP) /Fc $(USECXX_FLAG) $(MAKEDIR)\..\$(<F)
+$(C_COMPILER_FLAGS: =
+)
+<<KEEP
+
+{..\$(TARGET_DIRECTORY)\}.c{}.cod:
+ @-erase $(CLCOD_RSP)
+ $(C_COMPILER_NAME) @<<$(CLCOD_RSP) /Fc $(USECXX_FLAG) $(MAKEDIR)\$<
+$(C_COMPILER_FLAGS: =
+)
+<<KEEP
+
+{..\}.c{}.pp:
+ $(C_COMPILER_NAME) @<<$(CL_RSP) /E $(USECXX_FLAG) $(MAKEDIR)\$< > $@
+$(C_COMPILER_FLAGS: =
+)
+<<NOKEEP
+
+{..\$(TARGET_DIRECTORY)\}.c{}.pp:
+ $(C_COMPILER_NAME) @<<$(CL_RSP) /E $(USECXX_FLAG) $(MAKEDIR)\$< > $@
+$(C_COMPILER_FLAGS: =
+)
+<<NOKEEP
+
+{}.c{}.cod:
+ @-erase $(CLCOD_RSP)
+ $(C_COMPILER_NAME) @<<$(CLCOD_RSP) /Fc $(USECXX_FLAG) $(MAKEDIR)\$(<F)
+$(C_COMPILER_FLAGS: =
+)
+<<KEEP
+
+{$(TARGET_DIRECTORY)\}.c{}.cod:
+ @-erase $(CLCOD_RSP)
+ $(C_COMPILER_NAME) @<<$(CLCOD_RSP) /Fc $(USECXX_FLAG) $(MAKEDIR)\$<
+$(C_COMPILER_FLAGS: =
+)
+<<KEEP
+
+{}.c{}.pp:
+ $(C_COMPILER_NAME) @<<$(CL_RSP) /E $(USECXX_FLAG) $(MAKEDIR)\$< > $@
+$(C_COMPILER_FLAGS: =
+)
+<<NOKEEP
+
+{$(TARGET_DIRECTORY)\}.c{}.pp:
+ $(C_COMPILER_NAME) @<<$(CL_RSP) /E $(USECXX_FLAG) $(MAKEDIR)\$< > $@
+$(C_COMPILER_FLAGS: =
+)
+<<NOKEEP
+
+!ENDIF # NO_C_RULES
+
+!IF "$(NTNOFUZZYLOOKUP)"=="1"
+LIBRARY_OBJS=
+!ENDIF
+
+#
+# Standard inference rule for generating machine specific def files.
+#
+
+.SUFFIXES: .def .src
+
+CPPXX = $(C_PREPROCESSOR_FLAGS:/Tc=)
+CPPXX = $(CPPXX:-Tc=)
+
+{..\}.src{obj\$(TARGET_DIRECTORY)}.def:
+ $(C_PREPROCESSOR_NAME) @<<$(CL_RSP) /Tc$< > $@
+$(CPPXX: =
+)
+<<NOKEEP
+
+{}.src{obj\$(TARGET_DIRECTORY)}.def:
+ $(C_PREPROCESSOR_NAME) @<<$(CL_RSP) /Tc$< > $@
+$(CPPXX: =
+)
+<<NOKEEP
+
+{..\}.def{obj\$(TARGET_DIRECTORY)}.def:
+ $(C_PREPROCESSOR_NAME) @<<$(CL_RSP) /Tc$< > $@
+$(CPPXX: =
+)
+<<NOKEEP
+
+{}.def{obj\$(TARGET_DIRECTORY)}.def:
+ $(C_PREPROCESSOR_NAME) @<<$(CL_RSP) /Tc$< > $@
+$(CPPXX: =
+)
+<<NOKEEP
+
+#
+# Standard inference rule for User Mode object files that produce User Mode
+# image files
+#
+
+{obj\$(TARGET_DIRECTORY)\}.obj{obj\$(TARGET_DIRECTORY)\}$(UMAPPLEXT):
+ $(LINKER) @<<
+$(LINKER_FLAGS: =
+)
+$(PDB_ROOTUM)
+$(EXEORDER: =
+)
+$(LINKGPSIZE: =
+)
+$(LINKER_OPTIDATA)
+-base:$(UMBASE)
+-subsystem:$(SUBSYSTEM)
+$(UMENTRY)
+$(LINKFLAGS: =
+)
+$(UMRES: =
+)
+$<
+$(UMOBJS: =
+)
+$(UMLIBS: =
+)
+$(HEADEROBJNAME: =
+)
+$(CRTLIBS: =
+)
+$(LINKLIBS: =
+)
+<<NOKEEP
+ $(BINPLACE_CMD)
+
+#
+# Standard list of targets: all, clean and loc. all is the default target.
+#
+
+!IFNDEF PASS0ONLY
+
+all: obj\_objects.mac \
+ $(NTTARGETFILE0) \
+ $(PASS0_OBJECTS) \
+ $(PRECOMPILED_TARGET) \
+ $(HEADEROBJNAME) \
+ $(TARGETOBJFILES) \
+ $(TARGETLIBFILES) \
+ $(NTTARGETFILE1) \
+ $(TARGETEXEFILES) \
+ $(UMOBJFILES) \
+ $(UMEXEFILES) \
+ $(NTTARGETFILES) $(MISCFILES)
+!IFDEF MISCFILES
+! IFDEF _NTTREE
+ binplace -R $(_NTTREE) $(BINPLACE_FLAGS) $(MISCFILES)
+! ENDIF
+!ENDIF
+!IF "$(BUILDMSG)" != ""
+ @ech ; $(BUILDMSG) ;
+!ENDIF
+
+!ELSE # PASS0ONLY
+
+all: $(NTTARGETFILE0) \
+ $(PASS0_OBJECTS)
+!IF "$(BUILDMSG)" != ""
+ @ech ; $(BUILDMSG) ;
+!ENDIF
+
+!ENDIF # PASS0ONLY
+
+update:
+ @ech Updating library. ;
+
+obj\_objects.mac: $(SOURCES_USED)
+ @echo Rebuilding obj\_objects.mac from $(SOURCES_USED).
+ @build -Of >nul 2>&1
+ @echo obj\_objects.mac was rebuilt, please reinvoke NMAKE
+ @md \ >nul 2>nul
+
+loc:
+ @-loc *.h $(SOURCES)
+
+print:
+ @-ppr *.h $(SOURCES)
+
+!IFDEF NTTARGETFILES
+!INCLUDE .\makefile.inc
+!ELSE
+!IFDEF NTTARGETFILE0
+!INCLUDE .\makefile.inc
+!ELSE
+!IFDEF NTTARGETFILE1
+!INCLUDE .\makefile.inc
+!ENDIF
+!ENDIF
+!ENDIF
+
+!IF "$(PRECOMPILED_INCLUDE)" != ""
+$(PRECOMPILED_TARGET) $(HEADEROBJNAME): $(PRECOMPILED_INCLUDE)
+ @type <<
+$(ECHO_PRECOMPILED_MSG)
+<<NOKEEP
+ @$(C_COMPILER_NAME) @<< $(PRECOMPILED_FLAG)<<
+$(C_COMPILER_FLAGS: =
+) /Yl$(TARGETNAME) /Yc$(?F) $(HEADERFILE) $(HEADEROBJ)
+<<NOKEEP
+#include "$(?F)"
+<<NOKEEP
+!ENDIF
+
+!IFNDEF NOLINK
+
+!IF "$(UMTEST)" != "" || "$(UMAPPL)" != ""
+
+
+$(UMEXEFILES): $(UMLIBS) $(CRTLIBS) $(LINKLIBS)
+
+!ENDIF
+!ENDIF
+
+#
+# These dependencies produce the target binaries from the object files.
+# These will trigger the sources to object inference rules to generate the
+# object files.
+#
+
+!IF "$(TARGET)" != ""
+!IF "$(TARGETTYPE)"=="PROGLIB"
+$(TARGET:.exe=.lib) $(TARGET:.exe=.exp): $(DLLDEF) $(LIBRARY_OBJS)
+ -lib -out:$(@R).lib @<<
+$(LINK_LIB_IGNORE_FLAG)
+-machine:$(TARGET_DIRECTORY)
+-def:$(DLLDEF)
+-debugtype:cv
+-nodefaultlib
+$(LIBRARY_OBJS: =
+)
+<<NOKEEP
+$(TARGET): $(OBJECTS) $(TARGETPATH)\$(TARGET_DIRECTORY)\$(TARGETNAME).exp $(UMRES) $(UMLIBS) $(CRTLIBS) $(MACHINE_TARGETLIBS) $(LINKLIBS)
+ $(LINKER) @<<
+$(LINKER_FLAGS: =
+)
+$(EXEORDER: =
+)
+$(LINKGPSIZE: =
+)
+$(LINKER_OPTIDATA)
+-subsystem:$(SUBSYSTEM)
+-base:$(UMBASE)
+$(UMENTRY: =
+)
+$(LINKFLAGS: =
+)
+$(**: =
+)
+<<NOKEEP
+ $(BINPLACE_CMD)
+
+!ELSEIF "$(TARGETTYPE)"=="PROGRAM"
+
+$(TARGET): $(UMRES) $(OBJECTS) $(CRTLIBS) $(UMLIBS) $(MACHINE_TARGETLIBS) $(LINKLIBS)
+ $(LINKER) @<<
+$(LINKER_FLAGS: =
+)
+-subsystem:$(SUBSYSTEM)
+-base:$(UMBASE)
+$(LINKGPSIZE: =
+)
+$(UMENTRY: =
+)
+$(LINKFLAGS: =
+)
+$(LINKER_OPTIDATA)
+$(HEADEROBJNAME: =
+)
+$(**: =
+)
+<<NOKEEP
+ $(BINPLACE_CMD)
+
+!ELSEIF "$(TARGETTYPE)"=="DYNLINK"
+
+!IF "$(DLLLIBOBJECTS)" == ""
+
+$(DYNLINK_LIB) $(DYNLINK_LIB:.lib=.exp): $(DLLDEF) $(LIBRARY_OBJS)
+ -lib -out:$(@R).lib @<<
+$(LINK_LIB_IGNORE_FLAG)
+-machine:$(TARGET_DIRECTORY)
+-def:$(DLLDEF)
+-debugtype:cv
+-nodefaultlib
+$(LIBRARY_OBJS: =
+)
+<<NOKEEP
+
+!ELSE # "$(DLLLIBOBJECTS)" == ""
+
+$(DYNLINK_LIB) $(DYNLINK_LIB:.lib=.exp): $(DLLDEF) $(LIBRARY_OBJS) $(DLLLIBOBJECTS)
+ -lib -out:$(@D)\tmp.lib @<<
+$(LINK_LIB_IGNORE_FLAG)
+-machine:$(TARGET_DIRECTORY)
+-def:$(DLLDEF)
+-debugtype:cv
+-nodefaultlib
+$(LIBRARY_OBJS: =
+)
+<<NOKEEP
+ erase $(@R).exp
+ ren $(@D)\tmp.exp $(@B).exp
+ -lib -out:$(@R).lib @<<
+$(LINK_LIB_IGNORE_FLAG)
+-machine:$(TARGET_DIRECTORY)
+$(@D)\tmp.lib
+$(DLLLIBOBJECTS: =
+)
+<<NOKEEP
+ -erase $(@D)\tmp.lib
+
+!ENDIF # "$(DLLLIBOBJECTS)" == ""
+
+!IF "$(MAKEDLL)" != ""
+
+!IFDEF DLLORDER
+XXXORDER=-order:@$(DLLORDER)
+!ENDIF
+
+!IFDEF NTPROFILEINPUT
+XXXORDER=-order:@$(@B).prf
+#XXXORDER=$(XXXORDER:obj\$(TARGET_DIRECTORY)\=)
+!ENDIF
+
+$(TARGET): $(TARGETPATH)\$(TARGET_DIRECTORY)\$(TARGETNAME).exp $(OBJECTS) $(LINKLIBS) $(CRTLIBS) $(MACHINE_TARGETLIBS)
+ $(LINKER) @<<
+$(LINKER_FLAGS: =
+)
+-dll
+$(XXXORDER: =
+)
+$(LINKER_OPTIDATA)
+-base:$(DLLBASE)
+-subsystem:$(SUBSYSTEM)
+$(DLLENTRY: =
+)
+$(HEADEROBJNAME: =
+)
+$(**: =
+)
+<<NOKEEP
+ $(BINPLACE_CMD)
+ $(MAPDUMP_CMD)
+
+!ENDIF # "$(MAKEDLL)" != ""
+
+!ELSEIF "$(TARGETTYPE)"=="LIBRARY"
+
+$(TARGET): $(OBJECTS)
+ @-erase $@ >nul 2>nul
+ -$(LIBRARIAN) @<<
+$(HEADEROBJNAME: =
+)
+$(**: =
+)
+<<NOKEEP
+
+!ELSEIF "$(TARGETTYPE)"=="DRIVER" || \
+ "$(TARGETTYPE)"=="MINIPORT"
+
+!IFDEF NTPROFILEINPUT
+ORDER=-order:@$(@B).prf
+!ENDIF
+
+$(TARGET): $(OBJECTS) $(MACHINE_TARGETLIBS) $(CRTLIBS)
+ $(LINKER) @<<
+$(LINKER_FLAGS: =
+)
+$(ORDER: =
+)
+$(SECTION_INFO1)
+$(SECTION_INFO2)
+$(LINKER_OPTIDATA)
+-driver
+-align:$(DRIVER_ALIGNMENT)
+-subsystem:native$(SUBSYSTEM_NATVER)
+-base:$(DRIVERBASE)
+-entry:DriverEntry$(ENTRY_SUFFIX)
+-out:$(TARGET)
+$(HEADEROBJNAME: =
+)
+$(**: =
+)
+<<NOKEEP
+ $(BINPLACE_CMD)
+ $(MAPDUMP_CMD)
+
+!ELSEIF "$(TARGETTYPE)"=="GDI_DRIVER"
+
+!IFDEF NTPROFILEINPUT
+ORDER=-order:@$(@B).prf
+!ENDIF
+
+$(TARGET): $(OBJECTS) $(MACHINE_TARGETLIBS) $(CRTLIBS)
+ $(LINKER) @<<
+$(LINKER_FLAGS: =
+)
+-dll
+$(ORDER: =
+)
+$(SECTION_INFO1)
+$(SECTION_INFO2)
+$(LINKER_OPTIDATA)
+-driver
+-align:$(DRIVER_ALIGNMENT)
+-subsystem:native$(SUBSYSTEM_NATVER)
+-base:$(DRIVERBASE)
+-entry:DrvEnableDriver$(GDI_ENTRY_SUFFIX)
+-out:$(TARGET)
+$(HEADEROBJNAME: =
+)
+$(**: =
+)
+<<NOKEEP
+ $(BINPLACE_CMD)
+ $(MAPDUMP_CMD)
+
+!ELSEIF "$(TARGETTYPE)"=="EXPORT_DRIVER"
+
+!IFDEF NTPROFILEINPUT
+ORDER=-order:@$(@B).prf
+!ENDIF
+
+!IF "$(MAKEDLL)" == ""
+$(TARGET) $(TARGET:.lib=.exp): $(DLLDEF) $(OBJECTS) $(LINKLIBS)
+ -lib -out:$(@R).lib @<<
+-machine:$(TARGET_DIRECTORY)
+-def:$(DLLDEF)
+-debugtype:cv
+-nodefaultlib
+$(LINK_LIB_IGNORE_FLAG)
+$(OBJECTS)
+$(LINKLIBS)
+<<NOKEEP
+!ELSE
+$(TARGET:.sys=.lib) $(TARGET:.sys=.exp): $(DLLDEF) $(LIBRARY_OBJS)
+ -lib -out:$(@R).lib @<<
+-machine:$(TARGET_DIRECTORY)
+-def:$(DLLDEF)
+-debugtype:cv
+-nodefaultlib
+$(LINK_LIB_IGNORE_FLAG)
+$(LIBRARY_OBJS)
+<<NOKEEP
+$(TARGET): $(TARGETPATH)\$(TARGET_DIRECTORY)\$(TARGETNAME).exp $(OBJECTS) $(CRTLIBS) $(MACHINE_TARGETLIBS) $(LINKLIBS)
+ $(LINKER) @<<
+$(LINKER_FLAGS: =
+)
+$(ORDER: =
+)
+$(LINKER_OPTIDATA)
+-driver
+-align:$(DRIVER_ALIGNMENT)
+-subsystem:native$(SUBSYSTEM_NATVER)
+-base:$(DRIVERBASE)
+-entry:DriverEntry$(ENTRY_SUFFIX)
+-out:$(TARGET)
+$(HEADEROBJNAME: =
+)
+$(**: =
+)
+<<NOKEEP
+ $(BINPLACE_CMD)
+!ENDIF
+
+!ELSEIF "$(TARGETTYPE)"=="HAL"
+
+!IF "$(MAKEDLL)" == ""
+$(TARGET) $(TARGET:.lib=.exp): $(DLLDEF) obj\$(TARGET_DIRECTORY)\*.obj
+ -lib -out:$(@R).lib -machine:$(TARGET_DIRECTORY) @<<
+-def:$(DLLDEF)
+-debugtype:cv
+-nodefaultlib
+$(LINK_LIB_IGNORE_FLAG)
+obj\$(TARGET_DIRECTORY)\*.obj
+<<NOKEEP
+!ELSE
+$(TARGET:.dll=.lib) $(TARGET:.dll=.exp): $(DLLDEF) obj\$(TARGET_DIRECTORY)\*.obj
+ -lib -out:$(@R).lib -machine:$(TARGET_DIRECTORY) @<<
+-def:$(DLLDEF)
+-debugtype:cv
+-nodefaultlib
+$(LINK_LIB_IGNORE_FLAG)
+obj\$(TARGET_DIRECTORY)\*.obj
+<<NOKEEP
+
+$(TARGET): $(TARGETPATH)\$(TARGET_DIRECTORY)\$(TARGETNAME).exp $(OBJECTS) $(CRTLIBS) $(MACHINE_TARGETLIBS) $(LINKLIBS)
+ $(LINKER) @<<
+$(LINKER_FLAGS: =
+)
+$(LINKER_OPTIDATA)
+-driver
+-align:$(HAL_ALIGNMENT)
+-subsystem:$(SUBSYSTEM)
+-base:$(HALBASE)
+-miscrdata
+-dll
+-entry:HalInitSystem$(ENTRY_SUFFIX)
+-out:$(TARGET)
+$(**: =
+)
+<<NOKEEP
+ $(BINPLACE_CMD)
+ $(MAPDUMP_CMD)
+!ENDIF
+
+!ELSEIF "$(TARGETTYPE)"=="BOOTPGM"
+
+$(TARGET): $(OBJECTS) $(CRTLIBS) $(MACHINE_TARGETLIBS) $(LINKLIBS)
+ $(LINKER) @<<
+$(LINKER_FLAGS: =
+)
+-driver
+-subsystem:$(SUBSYSTEM)
+-base:$(BOOTBASE)
+-entry:_start
+-map:$(@R).map
+$(LINKFLAGS: =
+)
+$(**: =
+)
+<<NOKEEP
+
+!ENDIF
+!ENDIF
+
+!IFNDEF NOLINK
+
+!IF "$(NTTEST)" != ""
+
+!IF "$(TARGETPATH)"=="..\..\mpobj"
+KERNEL_DIR=mpobj
+KERNEL_TYPE=mp
+!ELSE
+KERNEL_DIR=obj
+KERNEL_TYPE=up
+!ENDIF
+
+!IFDEF NTPROFILEINPUT
+ORDER=-order:@..\$(@B).prf
+!ENDIF
+
+obj\$(TARGET_DIRECTORY)\$(NTTEST).exe: $(NTRES) obj\$(TARGET_DIRECTORY)\$(NTTEST).obj \
+ $(RELATIVE_DEPTH)\$(KERNEL_DIR)\$(TARGET_DIRECTORY)\*.lib \
+ $(LINKLIBS) \
+ $(BASEDIR)\public\sdk\lib\$(TARGET_DIRECTORY)\hal.lib \
+ $(BASEDIR)\public\sdk\lib\$(TARGET_DIRECTORY)\ntoskrnl.exp \
+ $(BASEDIR)\public\sdk\lib\$(TARGET_DIRECTORY)\lsakrnlp.lib \
+ $(BASEDIR)\public\sdk\lib\$(TARGET_DIRECTORY)\libcntpr.lib
+ $(LINKER) @<<
+$(LINKER_FLAGS: =
+)
+$(ORDER: =
+)
+$(LINKGPSIZE: =
+)
+$(NTTEST_LINK_OPTIONS: =
+)
+$(LINKER_OPTIDATA)
+-driver
+-align:$(KERNEL_ALIGNMENT)
+-subsystem:$(SUBSYSTEM)
+-miscrdata
+$(LINKFLAGS: =
+)
+$(**: =
+)
+<<NOKEEP
+ $(BINPLACE_CMD)
+ $(MAPDUMP_CMD)
+
+!ENDIF
+!ENDIF
diff --git a/private/utils/ntbackup/exchange/build/makefile.plt b/private/utils/ntbackup/exchange/build/makefile.plt
new file mode 100644
index 000000000..aa5899f6c
--- /dev/null
+++ b/private/utils/ntbackup/exchange/build/makefile.plt
@@ -0,0 +1,142 @@
+#
+# If not defined, specify where to get incs and libs.
+#
+
+!IFNDEF _NTROOT
+_NTROOT=\nt
+!ENDIF
+
+!IFNDEF BASEDIR
+BASEDIR=$(_NTDRIVE)$(_NTROOT)
+!ENDIF
+
+#
+# If not defined, define the build message banner.
+#
+
+!IFNDEF BUILDMSG
+BUILDMSG=
+!ENDIF
+
+#
+# Determine which target is being built (i386, Mips or Alpha) and define
+# the appropriate target variables.
+#
+
+!IFNDEF 386
+386=0
+!ENDIF
+
+!IFNDEF MIPS
+MIPS=0
+!ENDIF
+
+!IFNDEF ALPHA
+ALPHA=0
+!ENDIF
+
+!IFNDEF PPC
+PPC=0
+!ENDIF
+
+#
+# Default to building for the i386 target, if no target is specified.
+#
+
+!IF !$(386)
+! IF !$(MIPS)
+! IF !$(ALPHA)
+! IF !$(PPC)
+! IFDEF NTMIPSDEFAULT
+MIPS=1
+! IFNDEF TARGETCPU
+TARGETCPU=MIPS
+! ENDIF
+! ELSE
+! IFDEF NTALPHADEFAULT
+ALPHA=1
+! IFNDEF TARGETCPU
+TARGETCPU=ALPHA
+! ENDIF
+! ELSE
+! IFDEF NTPPCDEFAULT
+PPC=1
+! IFNDEF TARGETCPU
+TARGETCPU=PPC
+! ENDIF
+! ELSE
+386=1
+! IFNDEF TARGETCPU
+TARGETCPU=I386
+! ENDIF
+! ENDIF
+! ENDIF
+! ENDIF
+! ENDIF
+! ENDIF
+! ENDIF
+!ENDIF
+
+#
+# Define the target platform specific information.
+#
+
+!if $(386)
+
+ASM_SUFFIX=asm
+ASM_INCLUDE_SUFFIX=inc
+
+TARGET_BRACES=
+TARGET_CPP=cl
+TARGET_DEFINES=-Di386 -D_X86_
+TARGET_DIRECTORY=i386
+TARGET_NTTREE=$(_NT386TREE)
+
+MIDL_CPP=$(TARGET_CPP)
+MIDL_FLAGS=$(TARGET_DEFINES) -D_WCHAR_T_DEFINED
+
+!elseif $(MIPS)
+
+ASM_SUFFIX=s
+ASM_INCLUDE_SUFFIX=h
+
+TARGET_BRACES=-B
+TARGET_CPP=cl
+TARGET_DEFINES=-DMIPS -D_MIPS_
+TARGET_DIRECTORY=mips
+TARGET_NTTREE=$(_NTMIPSTREE)
+
+MIDL_CPP=$(TARGET_CPP)
+MIDL_FLAGS=$(TARGET_DEFINES) -D_WCHAR_T_DEFINED
+
+!elseif $(ALPHA)
+
+ASM_SUFFIX=s
+ASM_INCLUDE_SUFFIX=h
+
+TARGET_BRACES=-B
+TARGET_CPP=cl
+TARGET_DEFINES=-DALPHA -D_ALPHA_
+TARGET_DIRECTORY=alpha
+TARGET_NTTREE=$(_NTALPHATREE)
+
+MIDL_CPP=$(TARGET_CPP)
+MIDL_FLAGS=$(TARGET_DEFINES) -D_WCHAR_T_DEFINED
+
+!elseif $(PPC)
+
+ASM_SUFFIX=s
+ASM_INCLUDE_SUFFIX=h
+
+TARGET_BRACES=-B
+TARGET_CPP=cl
+TARGET_DEFINES=-DPPC -D_PPC_
+TARGET_DIRECTORY=ppc
+TARGET_NTTREE=$(_NTPPCTREE)
+
+MIDL_CPP=$(TARGET_CPP)
+MIDL_FLAGS=$(TARGET_DEFINES) -D_WCHAR_T_DEFINED
+
+!else
+!error Must define the target as 386, mips, alpha or ppc.
+!endif
diff --git a/private/utils/ntbackup/exchange/build/mipsmk.inc b/private/utils/ntbackup/exchange/build/mipsmk.inc
new file mode 100644
index 000000000..a38682d5c
--- /dev/null
+++ b/private/utils/ntbackup/exchange/build/mipsmk.inc
@@ -0,0 +1,218 @@
+!IF 0
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ mipsmk.inc
+
+Abstract:
+
+ This module contains the MIPs specific build controls. It is included
+ by makefile.def.
+
+Author:
+
+ Jeff Havens (jhavens) 13-Feb-1994
+
+Revision History:
+
+!ENDIF
+
+#
+# Mips option control
+#
+
+UMBASE=$(UMBASE:*=mips)
+UMLIBS=$(UMLIBS:*=mips)
+NTRES=$(NTRES:*=mips)
+UMRES=$(UMRES:*=mips)
+UMOBJS=$(UMOBJS:*=mips)
+LINKLIBS=$(LINKLIBS:*=mips)
+DLLBASE=$(DLLBASE:*=mips)
+DLLDEF=$(DLLDEF:*=mips)
+MACHINE_TARGETLIBS=$(MACHINE_TARGETLIBS:*=mips)
+TARGET=$(TARGET:*=mips)
+DYNLINK_LIB=$(DYNLINK_LIB:*=mips)
+TARGETEXEFILES=$(TARGETEXEFILES:*=mips)
+TARGETLIBFILES=$(TARGETLIBFILES:*=mips)
+TARGETOBJFILES=$(TARGETOBJFILES:*=mips)
+UMOBJFILES=$(UMOBJFILES:*=mips)
+UMEXEFILES=$(UMEXEFILES:*=mips)
+HEADERFILE=$(HEADERFILE:*=mips)
+HEADEROBJNAME=$(HEADEROBJNAME:*=mips)
+HEADEROBJ=$(HEADEROBJ:*=mips)
+PRECOMPILED=$(PRECOMPILED:*=mips)
+PRECOMPILED_CXX=$(PRECOMPILED_CXX:*=mips)
+PRECOMPILED_TARGET=$(PRECOMPILED_TARGET:*=mips)
+
+!ifdef NTTARGETFILES
+NTTARGETFILES=$(NTTARGETFILES:*=mips)
+!endif
+!ifdef NTTARGETFILE0
+NTTARGETFILE0=$(NTTARGETFILE0:*=mips)
+!endif
+!ifdef NTTARGETFILE1
+NTTARGETFILE1=$(NTTARGETFILE1:*=mips)
+!endif
+
+!IF "$(GPSIZE)" != "0"
+
+LIBC_LIB=$(BASEDIR)\public\sdk\lib\mips\small.lib $(LIBC_LIB)
+
+LINKGPSIZE=-gpsize:$(GPSIZE)
+
+!ENDIF
+
+LINKER_FLAGS = $(LINKER_FLAGS) -merge:.xdata=.rdata
+
+MIPS_ENDIAN=MIPSEL
+
+!IF "$(MIPS_F77)" == ""
+MIPS_F77=f772.20
+!ENDIF
+
+ENTRY_SUFFIX=
+GDI_ENTRY_SUFFIX=
+
+!IFDEF MIPS_WARNING_LEVEL
+MSC_WARNING_LEVEL=$(MIPS_WARNING_LEVEL)
+!ENDIF
+!IFDEF MIPS_OPTIMIZATION
+MSC_OPTIMIZATION=$(MIPS_OPTIMIZATION)
+!ENDIF
+!IFDEF MIPS_CPPFLAGS
+MSC_CPPFLAGS=$(MIPS_CPPFLAGS)
+!ENDIF
+
+#
+# Now a bunch of MIPS stuff
+#
+
+!IF "$(MSC_OPTFLAGS)" == "/Oxs"
+DBGFLAGS=$(MSC_OPTFLAGS:/Oxs=/Ox)
+!ENDIF
+
+DBGFLAGS = $(DBGFLAGS:/Zi=-Z7)
+
+# Use /Z7 instead of /Zi
+
+DBGFLAGS=$(DBGFLAGS:-Zi=-Z7)
+
+!IFNDEF MIPS_R3000
+MIPS_CPU=-DR4000 -D_M_MRX000=4000
+MIPS_TRAP_FILE=x4trap.obj
+!ELSE
+MIPS_CPU=-DR3000 -D_M_MRX000=3000
+MIPS_TRAP_FILE=x3trap.obj
+!ENDIF
+
+MIPS_ASM_DEFINES=$(MIPS_ASMCPP)
+ENV_DEFINES=$(LIBC_DEFINES) $(C_DEFINES) $(NET_C_DEFINES) $(MSC_CPPFLAGS) $(NTCPPFLAGS)
+
+STD_DEFINES=-DMIPS=1 -D_MIPS_=1 -D$(MIPS_ENDIAN) -DNO_EXT_KEYS -DCONDITION_HANDLING=1 $(STD_DEFINES)
+
+STDFLAGS=-c
+MS_MIPS=1
+
+MSC_C_COMPILER_NAME=cl $(CBSTRING) -nologo
+
+CDEFINES=$(STD_DEFINES) $(MIPS_CPU) $(TARGET_DBG_DEFINES) $(ENV_DEFINES)
+CFLAGS=$(MIPS_FLAGS) $(NTMIPSFLAGS) $(STDFLAGS) $(DBGFLAGS) $(MIPS_PERFFLAGS) $(USER_C_FLAGS)
+AFLAGS=-Gy $(MIPS_FLAGS) $(NTMIPSFLAGS) $(STDFLAGS) $(DBGFLAGS) $(MIPS_PERFFLAGS)
+
+MIPS_CDEFINES=$(CDEFINES)
+MIPS_CFLAGS=$(CFLAGS) -Zel -Zp8 -Gy $(MSC_WARNING_LEVEL) -QMOb4000
+MIPS_CFLAGS=$(MIPS_CFLAGS:-Qmips=-QM)
+
+C_PREPROCESSOR_NAME = $(MSC_C_COMPILER_NAME)
+C_COMPILER_NAME = $(MSC_C_COMPILER_NAME)
+CXX_COMPILER_NAME = $(MSC_C_COMPILER_NAME)
+MIPS_ASSEMBLER_NAME = $(MSC_C_COMPILER_NAME)
+
+GLOBAL_C_FLAGS = -nologo -Imips\ -I. $(INCPATH0) $(CDEFINES) $(MIPS_CFLAGS) \
+ -DFPO=1 -D__stdcall= -D__cdecl= -D_LANGUAGE_C -DLANGUAGE_C $(MFC_FLAGS)
+
+C_PREPROCESSOR_FLAGS = $(GLOBAL_C_FLAGS) $(PRECOMPILED) -EP -Tc
+C_COMPILER_FLAGS = $(GLOBAL_C_FLAGS) $(PRECOMPILED) -Gt$(GPSIZE) $(COMPILER_WARNINGS)
+CXX_COMPILER_FLAGS = $(GLOBAL_C_FLAGS) $(PRECOMPILED_CXX) -Gt$(GPSIZE) $(COMPILER_WARNINGS)
+
+C_PREPROCESSOR = $(C_PREPROCESSOR_NAME) $(C_PREPROCESSOR_FLAGS)
+C_COMPILER = $(C_COMPILER_NAME) $(C_COMPILER_FLAGS)
+CXX_COMPILER = $(CXX_COMPILER_NAME) $(CXX_COMPILER_FLAGS)
+
+ECHO_MSG=ClMips $< " $(C_COMPILER) "
+
+ECHO_PRECOMPILED_MSG=CpMips $(PRECOMPILED_INCLUDE) " $(C_COMPILER) \
+ /Yl$(TARGETNAME) /Yc$(?F) $(HEADERFILE) \
+ $(HEADEROBJ) $(PRECOMPILED_FLAG)"
+
+MIPS_FORTRAN_COMPILER=$(MIPS_F77) $(MSC_WARNINGS) $(MIPS_OPTIONS) -G $(GPSIZE) \
+ -excpt -G0 $(MSC_OPTIMIZATION) -O -EL -c
+
+MIPS_CRFILTER=echo SHOULDN'T NEED TO CRFILTER THIS!
+
+!IF "$(NTDEBUG)" == "" || "$(NTDEBUG)" == "retail"
+!IFNDEF MIPS_ENABLE_DIVIDE_CHECK
+MIPS_CFLAGS=$(MIPS_CFLAGS) -d2aNoDivCheck
+!ENDIF
+!ENDIF
+
+!ifdef MIPS_ENABLE_MIPS3
+AFLAGS=$(AFLAGS) -d2QMmips3
+!endif
+
+#
+# Use Mips MCL for assembler files.
+#
+
+MIPS_ASSEMBLER_FLAGS = -nologo -Gt$(GPSIZE) -Ge -c $(MIPS_CPU_SWITCHES) \
+ -Imips\ -I. $(INCPATH0) $(CDEFINES) \
+ $(AFLAGS) -D_LANGUAGE_ASSEMBLY
+
+MIPS_ASSEMBLER = $(MIPS_ASSEMBLER_NAME) $(MIPS_ASSEMBLER_FLAGS)
+
+{..\mips\}.s{obj\mips\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo AsMips $< " $(MIPS_ASSEMBLER) "
+ @$(MIPS_ASSEMBLER_NAME) @<< -Fo$(MAKEDIR)\$@ $<
+$(MIPS_ASSEMBLER_FLAGS: =
+)
+<<NOKEEP
+
+{mips\}.s{obj\mips\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo AsMips $< " $(MIPS_ASSEMBLER) $(MIPS_ASSEMBLER_FLAGS)"
+ @$(MIPS_ASSEMBLER_NAME) @<< -Fo$(MAKEDIR)\$@ $<
+$(MIPS_ASSEMBLER_FLAGS: =
+)
+<<NOKEEP
+
+LINKFLAGS=$(LNKFLAGS) -NODEFAULTLIB
+LIBRARY_OBJS=$(LINKLIBS) $(OBJECTS)
+# LIBRARY_OBJS=
+
+!IFDEF TUKWILA
+_NTTREE=$(_NTMIPSTREE)
+!ENDIF
+
+!IFDEF CAIRO_PRODUCT
+!IFDEF _CAIROMIPSTREE
+_NTTREE=$(_CAIROMIPSTREE)
+!ENDIF
+!ELSEIFDEF _NTMIPSTREE
+_NTTREE=$(_NTMIPSTREE)
+!ENDIF
+
+!IFDEF KERNEL_MODE
+_NTTREE=$(_NTMIPSTREE)\km
+!ENDIF
+
+!IFDEF _NTMIPSLIBS
+_NTLIBS=$(_NTMIPSLIBS)
+!ENDIF
+
+COPYDST=$(MIPSCOPYDST)
+LIB_COPY=ntmipscp.cmd
+
+NTTEST_LINK_OPTIONS= -base:0x10000 -entry:KiSystemStartup
diff --git a/private/utils/ntbackup/exchange/build/ppcmk.inc b/private/utils/ntbackup/exchange/build/ppcmk.inc
new file mode 100644
index 000000000..0503ff0b0
--- /dev/null
+++ b/private/utils/ntbackup/exchange/build/ppcmk.inc
@@ -0,0 +1,227 @@
+!IF 0
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ppcmk.inc
+
+Abstract:
+
+This module contains the PPC specific build controls. It is included
+by makefile.def.
+
+Author:
+
+Matt Holle (v-matth) 13-Feb-1994
+
+Revision History:
+
+!ENDIF
+
+
+#
+# PPC option control
+#
+
+UMBASE=$(UMBASE:*=ppc)
+UMLIBS=$(UMLIBS:*=ppc)
+NTRES=$(NTRES:*=ppc)
+UMRES=$(UMRES:*=ppc)
+UMOBJS=$(UMOBJS:*=ppc)
+LINKLIBS=$(LINKLIBS:*=ppc)
+DLLBASE=$(DLLBASE:*=ppc)
+DLLDEF=$(DLLDEF:*=ppc)
+MACHINE_TARGETLIBS=$(MACHINE_TARGETLIBS:*=ppc)
+TARGET=$(TARGET:*=ppc)
+DYNLINK_LIB=$(DYNLINK_LIB:*=ppc)
+TARGETEXEFILES=$(TARGETEXEFILES:*=ppc)
+TARGETLIBFILES=$(TARGETLIBFILES:*=ppc)
+TARGETOBJFILES=$(TARGETOBJFILES:*=ppc)
+UMOBJFILES=$(UMOBJFILES:*=ppc)
+UMEXEFILES=$(UMEXEFILES:*=ppc)
+HEADERFILE=$(HEADERFILE:*=ppc)
+HEADEROBJNAME=$(HEADEROBJNAME:*=ppc)
+HEADEROBJ=$(HEADEROBJ:*=ppc)
+PRECOMPILED=$(PRECOMPILED:*=ppc)
+PRECOMPILED_CXX=$(PRECOMPILED_CXX:*=ppc)
+PRECOMPILED_TARGET=$(PRECOMPILED_TARGET:*=ppc)
+
+#
+# Include 64-bit helper library
+#
+#LINKLIBS=$(LINKLIBS) $(BASEDIR)\public\sdk\lib\ppc\int64.lib
+!IF "$(TARGETTYPE)"=="DRIVER" || \
+ "$(TARGETTYPE)"=="GDI_DRIVER" || \
+ "$(TARGETTYPE)"=="MINIPORT"
+#
+#Drivers don't link with link libs.
+#
+MACHINE_TARGETLIBS=$(MACHINE_TARGETLIBS) $(BASEDIR)\public\sdk\lib\ppc\int64.lib
+!ENDIF
+
+!ifdef NTTARGETFILES
+NTTARGETFILES=$(NTTARGETFILES:*=ppc)
+!endif
+!ifdef NTTARGETFILE0
+NTTARGETFILE0=$(NTTARGETFILE0:*=ppc)
+!endif
+!ifdef NTTARGETFILE1
+NTTARGETFILE1=$(NTTARGETFILE1:*=ppc)
+!endif
+
+!IF "$(GPSIZE)" != "0"
+#
+# GPSIZE is irrelevant on PowerPC
+#
+LINKGPSIZE=
+!ENDIF
+
+ENTRY_SUFFIX=
+GDI_ENTRY_SUFFIX=
+
+!IF "$(MSC_OPTFLAGS)" == "/Oxs"
+DBGFLAGS=$(MSC_OPTFLAGS:/Oxs=/Ox)
+!ENDIF
+
+!IFDEF PPC_WARNING_LEVEL
+MSC_WARNING_LEVEL=$(PPC_WARNING_LEVEL)
+!ENDIF
+
+!IFDEF PPC_OPTIMIZATION
+MSC_OPTIMIZATION=$(PPC_OPTIMIZATION)
+!ELSE
+MSC_OPTIMIZATION=
+!ENDIF
+
+!IFDEF PPC_CPPFLAGS
+MSC_CPPFLAGS=$(PPC_CPPFLAGS)
+!ENDIF
+
+PPC_AS=pas
+PPC_DIS=pdis
+PPC_AS_WARNINGS=
+
+PPC_START_FILE=start.obj
+
+ENV_DEFINES=$(LIBC_DEFINES) $(C_DEFINES) $(NET_C_DEFINES) $(MSC_CPPFLAGS) $(NTCPPFLAGS) $(PM_DEFINES)
+STD_DEFINES=-DPPC=1 -D_PPC_=1 -DNO_EXT_KEYS $(STD_DEFINES) -D_M_PPC=1
+
+STDFLAGS=-c -Zel -Zp8 -Gy $(MFC_FLAGS)
+
+PPC_C_COMPILER_NAME = cl $(CBSTRING) -nologo
+PPC_CC = $(PPC_C_COMPILER_NAME)
+
+CDEFINES=$(STD_DEFINES) $(TARGET_DBG_DEFINES) $(ENV_DEFINES)
+CFLAGS=$(PPC_FLAGS) $(NTPPCFLAGS) $(STDFLAGS) $(DBGFLAGS) $(USER_C_FLAGS)
+
+PPC_CDEFINES= $(CDEFINES)
+PPC_CFLAGS = $(CFLAGS) -ZB64 $(MSC_WARNING_LEVEL) # -DALLOC_TEXT
+
+!IFNDEF PPC_OPTIONS
+PPC_OPTIONS=
+!ENDIF
+
+C_COMPILER_NAME = $(PPC_C_COMPILER_NAME)
+C_PREPROCESSOR_NAME = $(PPC_C_COMPILER_NAME)
+CXX_COMPILER_NAME = $(PPC_C_COMPILER_NAME)
+
+GLOBAL_C_FLAGS = -nologo -Ippc\ -I. $(INCPATH0) $(CDEFINES) $(PPC_OPTIONS) \
+ $(PPC_CFLAGS) -D__stdcall= -D__cdecl= -D_cdecl= -Dcdecl= \
+ -DFPO=1 -DLANGUAGE_C
+
+# Disable -WX for now
+
+GLOBAL_C_FLAGS = $(GLOBAL_C_FLAGS:-WX=)
+GLOBAL_C_FLAGS = $(GLOBAL_C_FLAGS:/WX=)
+
+C_PREPROCESSOR_FLAGS = $(GLOBAL_C_FLAGS) $(PRECOMPILED) -EP -Tc
+C_COMPILER_FLAGS = $(GLOBAL_C_FLAGS) $(PRECOMPILED) $(COMPILER_WARNINGS)
+CXX_COMPILER_FLAGS = $(GLOBAL_C_FLAGS) $(PRECOMPILED_CXX) $(COMPILER_WARNINGS)
+
+C_PREPROCESSOR = $(C_PREPROCESSOR_NAME) $(C_PREPROCESSOR_FLAGS)
+C_COMPILER = $(C_COMPILER_NAME) $(C_COMPILER_FLAGS)
+CXX_COMPILER = $(CXX_COMPILER_NAME) $(CXX_COMPILER_FLAGS)
+
+PPC_ASSEMBLER = $(PPC_AS) $(PPC_AS_WARNINGS)
+
+ECHO_MSG = ClPpc $< " $(C_COMPILER) "
+ECHO_PRECOMPILED_MSG = CpPpc $(PRECOMPILED_INCLUDE) " $(C_COMPILER) \
+ /Yl$(TARGETNAME) /Yc$(?F) $(HEADERFILE) \
+ $(HEADEROBJ) $(PRECOMPILED_FLAG)"
+
+{.\}.cxx{}.obj:
+ @$(ECHO_MSG)
+ @$(CXX_COMPILER) -Fo$(MAKEDIR)\$@ $(MAKEDIR)\..\$(<F)
+
+{.\}.cxx{obj\$(TARGET_DIRECTORY)\}.obj:
+ @$(ECHO_MSG)
+ @$(CXX_COMPILER) -Fo$(MAKEDIR)\$@ $(MAKEDIR)\..\$(<F)
+
+{}.cxx{obj\$(TARGET_DIRECTORY)\}.obj:
+ @$(ECHO_MSG)
+ @$(CXX_COMPILER) -Fo$(MAKEDIR)\$@ $(MAKEDIR)\..\$(<F)
+
+{..\ppc\}.s{obj\ppc\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo AsPpc $< " $(PPC_ASSEMBLER) "
+ $(C_PREPROCESSOR) $(MAKEDIR)\..\ppc\$(<F) > $(MAKEDIR)\obj\ppc\$(<B).i && $(PPC_ASSEMBLER) -o $@ $(MAKEDIR)\obj\ppc\$(<B).i
+ @-erase $(MAKEDIR)\obj\ppc\$(<B).i >nul 2>&1
+
+
+{ppc\}.s{obj\ppc\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo AsPpc $< " $(PPC_ASSEMBLER) "
+ $(C_PREPROCESSOR) $(MAKEDIR)\ppc\$(<F) > $(MAKEDIR)\obj\ppc\$(<B).i && $(PPC_ASSEMBLER) -o $@ $(MAKEDIR)\obj\ppc\$(<B).i
+ @-erase $(MAKEDIR)\obj\ppc\$(<B).i >nul 2>&1
+
+.SUFFIXES: .il
+
+{}.il{}.cod:
+ @-erase $@ >nul 2>&1
+ @echo MCL $<" $(C_COMPILER) "
+ @$(C_COMPILER) -FAac -Fa$(<B).cod -B1..\bootbin\null.exe -Bk$(<B). -Fo$(MAKEDIR)\obj\ppc\$(<B).o $(MAKEDIR)\$(<B).c
+ @del obj\ppc\$(<B).o
+
+#
+# No reodering under ppc.
+#
+
+LIBRARY_OBJS=$(LINKLIBS) $(OBJECTS)
+
+!IFDEF TUKWILA
+_NTTREE=$(_NTPPCTREE)
+!ENDIF
+
+!IFDEF CAIRO_PRODUCT
+!IFDEF _CAIROPPCTREE
+_NTTREE=$(_CAIROPPCTREE)
+!ENDIF
+!ELSE
+!IFDEF _NTPPCTREE
+_NTTREE=$(_NTPPCTREE)
+!ENDIF
+!ENDIF
+
+!IFDEF KERNEL_MODE
+_NTTREE=$(_NTPPCTREE)\km
+!ENDIF
+
+!IFDEF _NTPPCLIBS
+_NTLIBS=$(_NTPPCLIBS)
+!ENDIF
+
+COPYDST=$(PPCCOPYDST)
+
+LIB_COPY=ntppccp.cmd
+
+NTTEST_LINK_OPTIONS= -base:0x80100000 -entry:KiSystemStartup
+
+#
+# Move the compiler generated function descriptors into .rdata
+#
+# Can be removed when we switch to the MS PPC compiler (assuming
+# it emits the descriptor in .rdata already) BryanT
+#
+
+LINKER_FLAGS = -merge:.reldata=.rdata $(LINKER_FLAGS)
diff --git a/private/utils/ntbackup/exchange/inc/edbmsg.h b/private/utils/ntbackup/exchange/inc/edbmsg.h
new file mode 100644
index 000000000..2288317dc
--- /dev/null
+++ b/private/utils/ntbackup/exchange/inc/edbmsg.h
@@ -0,0 +1,1737 @@
+/*
+ * EDBMSG.H
+ *
+ * Microsoft Exchange Information Store
+ * Copyright (C) 1986-1996, Microsoft Corporation
+ *
+ * Contains declarations of additional properties and interfaces
+ * offered by Microsoft Exchange Information Store
+ */
+
+#ifndef _EDBMSG_
+#define _EDBMSG_
+
+//
+// SUCCESS
+//
+//
+// Values are 32 bit values layed out as follows:
+//
+// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+// +---+-+-+-----------------------+-------------------------------+
+// |Sev|C|R| Facility | Code |
+// +---+-+-+-----------------------+-------------------------------+
+//
+// where
+//
+// Sev - is the severity code
+//
+// 00 - Success
+// 01 - Informational
+// 10 - Warning
+// 11 - Error
+//
+// C - is the Customer code flag
+//
+// R - is a reserved bit
+//
+// Facility - is the facility code
+//
+// Code - is the facility's status code
+//
+//
+// Define the facility codes
+//
+#define FACILITY_SYSTEM 0x0
+#define FACILITY_EDB 0x800
+#define FACILITY_BACKUP 0x7FF
+
+
+//
+// Define the severity codes
+//
+#define STATUS_SEVERITY_WARNING 0x2
+#define STATUS_SEVERITY_SUCCESS 0x0
+#define STATUS_SEVERITY_INFORMATIONAL 0x1
+#define STATUS_SEVERITY_ERROR 0x3
+
+
+//
+// MessageId: hrNone
+//
+// MessageText:
+//
+// The operation was successful
+//
+#define hrNone ((HRESULT)0x00000000L)
+
+//
+// ERRORS
+//
+//
+// MessageId: hrNyi
+//
+// MessageText:
+//
+// The function is not yet implemented
+//
+#define hrNyi ((HRESULT)0xC0000001L)
+
+//
+// Backup errors
+//
+//
+// MessageId: hrInvalidParam
+//
+// MessageText:
+//
+// The parameter is not valid.
+//
+#define hrInvalidParam ((HRESULT)0xC7FF0001L)
+
+//
+// MessageId: hrError
+//
+// MessageText:
+//
+// An internal error has occurred.
+//
+#define hrError ((HRESULT)0xC7FF0002L)
+
+//
+// MessageId: hrInvalidHandle
+//
+// MessageText:
+//
+// The handle is not valid.
+//
+#define hrInvalidHandle ((HRESULT)0xC7FF0003L)
+
+//
+// MessageId: hrRestoreInProgress
+//
+// MessageText:
+//
+// The Restore process is already in progress.
+//
+#define hrRestoreInProgress ((HRESULT)0xC7FF0004L)
+
+//
+// MessageId: hrAlreadyOpen
+//
+// MessageText:
+//
+// The file specified is already open.
+//
+#define hrAlreadyOpen ((HRESULT)0xC7FF0005L)
+
+//
+// MessageId: hrInvalidRecips
+//
+// MessageText:
+//
+// The recipients are invalid.
+//
+#define hrInvalidRecips ((HRESULT)0xC7FF0006L)
+
+//
+// MessageId: hrCouldNotConnect
+//
+// MessageText:
+//
+// Unable to perform the backup. Either you are not connected to the specified backup server
+// or the service you are trying to backup is not running.
+//
+#define hrCouldNotConnect ((HRESULT)0xC7FF0007L)
+
+//
+// MessageId: hrRestoreMapExists
+//
+// MessageText:
+//
+// A restore map already exists for the specified component. You can only specify
+// a restore map when performing a full restore.
+//
+#define hrRestoreMapExists ((HRESULT)0xC7FF0008L)
+
+//
+// MessageId: hrIncrementalBackupDisabled
+//
+// MessageText:
+//
+// Another application has modified the specified Microsoft Exchange database such that any
+// subsequent backups will fail. You must perform a full backup to fix this problem.
+//
+#define hrIncrementalBackupDisabled ((HRESULT)0xC7FF0009L)
+
+//
+// MessageId: hrLogFileNotFound
+//
+// MessageText:
+//
+// Unable to perform an incremental backup because a required Microsoft Exchange database log file could not be found.
+//
+#define hrLogFileNotFound ((HRESULT)0xC7FF000AL)
+
+//
+// MessageId: hrCircularLogging
+//
+// MessageText:
+//
+// The Microsoft Exchange component specified is configured to use circular database logs.
+// It cannot be backed up without a full backup.
+//
+#define hrCircularLogging ((HRESULT)0xC7FF000BL)
+
+//
+// MessageId: hrNoFullRestore
+//
+// MessageText:
+//
+// The databases have not been restored to this machine. You cannot restore an incremental backup
+// until a full backup has been restored.
+//
+#define hrNoFullRestore ((HRESULT)0xC7FF000CL)
+
+//
+// MessageId: hrCommunicationError
+//
+// MessageText:
+//
+// A communications error occurred while attempting to perform a local backup.
+//
+#define hrCommunicationError ((HRESULT)0xC7FF000DL)
+
+//
+// MessageId: hrFullBackupNotTaken
+//
+// MessageText:
+//
+// You must perform a full backup before you can perform an incremental backup.
+//
+#define hrFullBackupNotTaken ((HRESULT)0xC7FF000EL)
+
+#define hrAlreadyListening ((HRESULT)RPC_S_ALREADY_LISTENING)
+//
+// ERRORS
+//
+//
+// SYSTEM errors
+//
+//
+// MessageId: hrFileClose
+//
+// MessageText:
+//
+// Unable to close the DOS file
+//
+#define hrFileClose ((HRESULT)0xC8000066L)
+
+//
+// MessageId: hrOutOfThreads
+//
+// MessageText:
+//
+// Unable to start a thread because there are none available.
+//
+#define hrOutOfThreads ((HRESULT)0xC8000067L)
+
+//
+// MessageId: hrTooManyIO
+//
+// MessageText:
+//
+// The system is busy because there are too many I/Os.
+//
+#define hrTooManyIO ((HRESULT)0xC8000069L)
+
+//
+// BUFFER MANAGER errors
+//
+//
+// MessageId: hrBFNotSynchronous
+//
+// MessageText:
+//
+// The buffer page has been evicted.
+//
+#define hrBFNotSynchronous ((HRESULT)0x880000C8L)
+
+//
+// MessageId: hrBFPageNotFound
+//
+// MessageText:
+//
+// Unable to find the page.
+//
+#define hrBFPageNotFound ((HRESULT)0x880000C9L)
+
+//
+// MessageId: hrBFInUse
+//
+// MessageText:
+//
+// Unable to abandon the buffer.
+//
+#define hrBFInUse ((HRESULT)0xC80000CAL)
+
+//
+// DIRECTORY MANAGER errors
+//
+//
+// MessageId: hrPMRecDeleted
+//
+// MessageText:
+//
+// The record has been deleted.
+//
+#define hrPMRecDeleted ((HRESULT)0xC800012EL)
+
+//
+// MessageId: hrRemainingVersions
+//
+// MessageText:
+//
+// There is idle work remaining.
+//
+#define hrRemainingVersions ((HRESULT)0x88000141L)
+
+//
+// RECORD MANAGER errors
+//
+//
+// MessageId: hrFLDKeyTooBig
+//
+// MessageText:
+//
+// The key was truncated because it is more than 255 bytes.
+//
+#define hrFLDKeyTooBig ((HRESULT)0x88000190L)
+
+//
+// MessageId: hrFLDTooManySegments
+//
+// MessageText:
+//
+// There are too many key segments.
+//
+#define hrFLDTooManySegments ((HRESULT)0xC8000191L)
+
+//
+// MessageId: hrFLDNullKey
+//
+// MessageText:
+//
+// The key is NULL.
+//
+#define hrFLDNullKey ((HRESULT)0x88000192L)
+
+//
+// LOGGING/RECOVERY errors
+//
+//
+// MessageId: hrLogFileCorrupt
+//
+// MessageText:
+//
+// The log file is damaged.
+//
+#define hrLogFileCorrupt ((HRESULT)0xC80001F5L)
+
+//
+// MessageId: hrNoBackupDirectory
+//
+// MessageText:
+//
+// No backup directory was given.
+//
+#define hrNoBackupDirectory ((HRESULT)0xC80001F7L)
+
+//
+// MessageId: hrBackupDirectoryNotEmpty
+//
+// MessageText:
+//
+// The backup directory is not empty.
+//
+#define hrBackupDirectoryNotEmpty ((HRESULT)0xC80001F8L)
+
+//
+// MessageId: hrBackupInProgress
+//
+// MessageText:
+//
+// Backup is already active.
+//
+#define hrBackupInProgress ((HRESULT)0xC80001F9L)
+
+//
+// MessageId: hrMissingPreviousLogFile
+//
+// MessageText:
+//
+// A log file for the checkpoint is missing.
+//
+#define hrMissingPreviousLogFile ((HRESULT)0xC80001FDL)
+
+//
+// MessageId: hrLogWriteFail
+//
+// MessageText:
+//
+// Unable to write to the log file.
+//
+#define hrLogWriteFail ((HRESULT)0xC80001FEL)
+
+//
+// MessageId: hrBadLogVersion
+//
+// MessageText:
+//
+// The version of the log file is not compatible with the version of the Microsoft Exchange Server database (EDB).
+//
+#define hrBadLogVersion ((HRESULT)0xC8000202L)
+
+//
+// MessageId: hrInvalidLogSequence
+//
+// MessageText:
+//
+// The time stamp in the next log does not match what was expected.
+//
+#define hrInvalidLogSequence ((HRESULT)0xC8000203L)
+
+//
+// MessageId: hrLoggingDisabled
+//
+// MessageText:
+//
+// The log is not active.
+//
+#define hrLoggingDisabled ((HRESULT)0xC8000204L)
+
+//
+// MessageId: hrLogBufferTooSmall
+//
+// MessageText:
+//
+// The log buffer is too small to be recovered.
+//
+#define hrLogBufferTooSmall ((HRESULT)0xC8000205L)
+
+//
+// MessageId: hrLogSequenceEnd
+//
+// MessageText:
+//
+// The maximum number of log files has been exceeded.
+//
+#define hrLogSequenceEnd ((HRESULT)0xC8000207L)
+
+//
+// MessageId: hrNoBackup
+//
+// MessageText:
+//
+// There is no backup in progress.
+//
+#define hrNoBackup ((HRESULT)0xC8000208L)
+
+//
+// MessageId: hrInvalidBackupSequence
+//
+// MessageText:
+//
+// The backup call is out of sequence.
+//
+#define hrInvalidBackupSequence ((HRESULT)0xC8000209L)
+
+//
+// MessageId: hrBackupNotAllowedYet
+//
+// MessageText:
+//
+// Unable to perform a backup now.
+//
+#define hrBackupNotAllowedYet ((HRESULT)0xC800020BL)
+
+//
+// MessageId: hrDeleteBackupFileFail
+//
+// MessageText:
+//
+// Unable to delete the backup file.
+//
+#define hrDeleteBackupFileFail ((HRESULT)0xC800020CL)
+
+//
+// MessageId: hrMakeBackupDirectoryFail
+//
+// MessageText:
+//
+// Unable to make a backup temporary directory.
+//
+#define hrMakeBackupDirectoryFail ((HRESULT)0xC800020DL)
+
+//
+// MessageId: hrInvalidBackup
+//
+// MessageText:
+//
+// An incremental backup cannot be performed when circular logging is enabled.
+//
+#define hrInvalidBackup ((HRESULT)0xC800020EL)
+
+//
+// MessageId: hrRecoveredWithErrors
+//
+// MessageText:
+//
+// Errors were encountered during the repair process.
+//
+#define hrRecoveredWithErrors ((HRESULT)0xC800020FL)
+
+//
+// MessageId: hrMissingLogFile
+//
+// MessageText:
+//
+// The current log file is missing.
+//
+#define hrMissingLogFile ((HRESULT)0xC8000210L)
+
+//
+// MessageId: hrLogDiskFull
+//
+// MessageText:
+//
+// The log disk is full.
+//
+#define hrLogDiskFull ((HRESULT)0xC8000211L)
+
+//
+// MessageId: hrBadLogSignature
+//
+// MessageText:
+//
+// A log file is damaged.
+//
+#define hrBadLogSignature ((HRESULT)0xC8000212L)
+
+//
+// MessageId: hrBadDbSignature
+//
+// MessageText:
+//
+// A database file is damaged.
+//
+#define hrBadDbSignature ((HRESULT)0xC8000213L)
+
+//
+// MessageId: hrBadCheckpointSignature
+//
+// MessageText:
+//
+// A checkpoint file is damaged.
+//
+#define hrBadCheckpointSignature ((HRESULT)0xC8000214L)
+
+//
+// MessageId: hrCheckpointCorrupt
+//
+// MessageText:
+//
+// A checkpoint file either could not be found or is damaged.
+//
+#define hrCheckpointCorrupt ((HRESULT)0xC8000215L)
+
+//
+// MessageId: hrDatabaseInconsistent
+//
+// MessageText:
+//
+// The database is damaged.
+//
+#define hrDatabaseInconsistent ((HRESULT)0xC8000226L)
+
+//
+// MessageId: hrConsistentTimeMismatch
+//
+// MessageText:
+//
+// There is a mismatch in the database's last consistent time.
+//
+#define hrConsistentTimeMismatch ((HRESULT)0xC8000227L)
+
+//
+// MessageId: hrPatchFileMismatch
+//
+// MessageText:
+//
+// The patch file is not generated from this backup.
+//
+#define hrPatchFileMismatch ((HRESULT)0xC8000228L)
+
+//
+// MessageId: hrRestoreLogTooLow
+//
+// MessageText:
+//
+// The starting log number is too low for the restore.
+//
+#define hrRestoreLogTooLow ((HRESULT)0xC8000229L)
+
+//
+// MessageId: hrRestoreLogTooHigh
+//
+// MessageText:
+//
+// The starting log number is too high for the restore.
+//
+#define hrRestoreLogTooHigh ((HRESULT)0xC800022AL)
+
+//
+// MessageId: hrGivenLogFileHasBadSignature
+//
+// MessageText:
+//
+// The log file downloaded from the tape is damaged.
+//
+#define hrGivenLogFileHasBadSignature ((HRESULT)0xC800022BL)
+
+//
+// MessageId: hrGivenLogFileIsNotContiguous
+//
+// MessageText:
+//
+// Unable to find a mandatory log file after the tape was downloaded.
+//
+#define hrGivenLogFileIsNotContiguous ((HRESULT)0xC800022CL)
+
+//
+// MessageId: hrMissingRestoreLogFiles
+//
+// MessageText:
+//
+// The data is not fully restored because some log files are missing.
+//
+#define hrMissingRestoreLogFiles ((HRESULT)0xC800022DL)
+
+//
+// MessageId: hrExistingLogFileHasBadSignature
+//
+// MessageText:
+//
+// The log file in the log file path is damaged.
+//
+#define hrExistingLogFileHasBadSignature ((HRESULT)0x8800022EL)
+
+//
+// MessageId: hrExistingLogFileIsNotContiguous
+//
+// MessageText:
+//
+// Unable to find a mandatory log file in the log file path.
+//
+#define hrExistingLogFileIsNotContiguous ((HRESULT)0x8800022FL)
+
+//
+// MessageId: hrMissingFullBackup
+//
+// MessageText:
+//
+// The database missed a previous full backup before the incremental backup.
+//
+#define hrMissingFullBackup ((HRESULT)0xC8000230L)
+
+//
+// MessageId: hrBadBackupDatabaseSize
+//
+// MessageText:
+//
+// The backup database size must be a multiple of 4K (4096 bytes).
+//
+#define hrBadBackupDatabaseSize ((HRESULT)0xC8000231L)
+
+//
+// MessageId: hrTermInProgress
+//
+// MessageText:
+//
+// The database is being shut down.
+//
+#define hrTermInProgress ((HRESULT)0xC80003E8L)
+
+//
+// MessageId: hrFeatureNotAvailable
+//
+// MessageText:
+//
+// The feature is not available.
+//
+#define hrFeatureNotAvailable ((HRESULT)0xC80003E9L)
+
+//
+// MessageId: hrInvalidName
+//
+// MessageText:
+//
+// The name is not valid.
+//
+#define hrInvalidName ((HRESULT)0xC80003EAL)
+
+//
+// MessageId: hrInvalidParameter
+//
+// MessageText:
+//
+// The parameter is not valid.
+//
+#define hrInvalidParameter ((HRESULT)0xC80003EBL)
+
+//
+// MessageId: hrColumnNull
+//
+// MessageText:
+//
+// The value of the column is null.
+//
+#define hrColumnNull ((HRESULT)0x880003ECL)
+
+//
+// MessageId: hrBufferTruncated
+//
+// MessageText:
+//
+// The buffer is too small for data.
+//
+#define hrBufferTruncated ((HRESULT)0x880003EEL)
+
+//
+// MessageId: hrDatabaseAttached
+//
+// MessageText:
+//
+// The database is already attached.
+//
+#define hrDatabaseAttached ((HRESULT)0x880003EFL)
+
+//
+// MessageId: hrInvalidDatabaseId
+//
+// MessageText:
+//
+// The database ID is not valid.
+//
+#define hrInvalidDatabaseId ((HRESULT)0xC80003F2L)
+
+//
+// MessageId: hrOutOfMemory
+//
+// MessageText:
+//
+// The computer is out of memory.
+//
+#define hrOutOfMemory ((HRESULT)0xC80003F3L)
+
+//
+// MessageId: hrOutOfDatabaseSpace
+//
+// MessageText:
+//
+// The database has reached the maximum size of 16 GB.
+//
+#define hrOutOfDatabaseSpace ((HRESULT)0xC80003F4L)
+
+//
+// MessageId: hrOutOfCursors
+//
+// MessageText:
+//
+// Out of table cursors.
+//
+#define hrOutOfCursors ((HRESULT)0xC80003F5L)
+
+//
+// MessageId: hrOutOfBuffers
+//
+// MessageText:
+//
+// Out of database page buffers.
+//
+#define hrOutOfBuffers ((HRESULT)0xC80003F6L)
+
+//
+// MessageId: hrTooManyIndexes
+//
+// MessageText:
+//
+// There are too many indexes.
+//
+#define hrTooManyIndexes ((HRESULT)0xC80003F7L)
+
+//
+// MessageId: hrTooManyKeys
+//
+// MessageText:
+//
+// There are too many columns in an index.
+//
+#define hrTooManyKeys ((HRESULT)0xC80003F8L)
+
+//
+// MessageId: hrRecordDeleted
+//
+// MessageText:
+//
+// The record has been deleted.
+//
+#define hrRecordDeleted ((HRESULT)0xC80003F9L)
+
+//
+// MessageId: hrReadVerifyFailure
+//
+// MessageText:
+//
+// A read verification error occurred.
+//
+#define hrReadVerifyFailure ((HRESULT)0xC80003FAL)
+
+//
+// MessageId: hrOutOfFileHandles
+//
+// MessageText:
+//
+// Out of file handles.
+//
+#define hrOutOfFileHandles ((HRESULT)0xC80003FCL)
+
+//
+// MessageId: hrDiskIO
+//
+// MessageText:
+//
+// A disk I/O error occurred.
+//
+#define hrDiskIO ((HRESULT)0xC80003FEL)
+
+//
+// MessageId: hrInvalidPath
+//
+// MessageText:
+//
+// The path to the file is not valid.
+//
+#define hrInvalidPath ((HRESULT)0xC80003FFL)
+
+//
+// MessageId: hrRecordTooBig
+//
+// MessageText:
+//
+// The record has exceeded the maximum size.
+//
+#define hrRecordTooBig ((HRESULT)0xC8000402L)
+
+//
+// MessageId: hrTooManyOpenDatabases
+//
+// MessageText:
+//
+// There are too many open databases.
+//
+#define hrTooManyOpenDatabases ((HRESULT)0xC8000403L)
+
+//
+// MessageId: hrInvalidDatabase
+//
+// MessageText:
+//
+// The file is not a database file.
+//
+#define hrInvalidDatabase ((HRESULT)0xC8000404L)
+
+//
+// MessageId: hrNotInitialized
+//
+// MessageText:
+//
+// The database was not yet called.
+//
+#define hrNotInitialized ((HRESULT)0xC8000405L)
+
+//
+// MessageId: hrAlreadyInitialized
+//
+// MessageText:
+//
+// The database was already called.
+//
+#define hrAlreadyInitialized ((HRESULT)0xC8000406L)
+
+//
+// MessageId: hrFileAccessDenied
+//
+// MessageText:
+//
+// Unable to access the file.
+//
+#define hrFileAccessDenied ((HRESULT)0xC8000408L)
+
+//
+// MessageId: hrBufferTooSmall
+//
+// MessageText:
+//
+// The buffer is too small.
+//
+#define hrBufferTooSmall ((HRESULT)0xC800040EL)
+
+//
+// MessageId: hrSeekNotEqual
+//
+// MessageText:
+//
+// Either SeekLE or SeekGE did not find an exact match.
+//
+#define hrSeekNotEqual ((HRESULT)0x8800040FL)
+
+//
+// MessageId: hrTooManyColumns
+//
+// MessageText:
+//
+// There are too many columns defined.
+//
+#define hrTooManyColumns ((HRESULT)0xC8000410L)
+
+//
+// MessageId: hrContainerNotEmpty
+//
+// MessageText:
+//
+// The container is not empty.
+//
+#define hrContainerNotEmpty ((HRESULT)0xC8000413L)
+
+//
+// MessageId: hrInvalidFilename
+//
+// MessageText:
+//
+// The filename is not valid.
+//
+#define hrInvalidFilename ((HRESULT)0xC8000414L)
+
+//
+// MessageId: hrInvalidBookmark
+//
+// MessageText:
+//
+// The bookmark is not valid.
+//
+#define hrInvalidBookmark ((HRESULT)0xC8000415L)
+
+//
+// MessageId: hrColumnInUse
+//
+// MessageText:
+//
+// The column is used in an index.
+//
+#define hrColumnInUse ((HRESULT)0xC8000416L)
+
+//
+// MessageId: hrInvalidBufferSize
+//
+// MessageText:
+//
+// The data buffer does not match the column size.
+//
+#define hrInvalidBufferSize ((HRESULT)0xC8000417L)
+
+//
+// MessageId: hrColumnNotUpdatable
+//
+// MessageText:
+//
+// Unable to set the column value.
+//
+#define hrColumnNotUpdatable ((HRESULT)0xC8000418L)
+
+//
+// MessageId: hrIndexInUse
+//
+// MessageText:
+//
+// The index is in use.
+//
+#define hrIndexInUse ((HRESULT)0xC800041BL)
+
+//
+// MessageId: hrNullKeyDisallowed
+//
+// MessageText:
+//
+// Null keys are not allowed on an index.
+//
+#define hrNullKeyDisallowed ((HRESULT)0xC800041DL)
+
+//
+// MessageId: hrNotInTransaction
+//
+// MessageText:
+//
+// The operation must be within a transaction.
+//
+#define hrNotInTransaction ((HRESULT)0xC800041EL)
+
+//
+// MessageId: hrNoIdleActivity
+//
+// MessageText:
+//
+// No idle activity occured.
+//
+#define hrNoIdleActivity ((HRESULT)0x88000422L)
+
+//
+// MessageId: hrTooManyActiveUsers
+//
+// MessageText:
+//
+// There are too many active database users.
+//
+#define hrTooManyActiveUsers ((HRESULT)0xC8000423L)
+
+//
+// MessageId: hrInvalidCountry
+//
+// MessageText:
+//
+// The country code is either not known or is not valid.
+//
+#define hrInvalidCountry ((HRESULT)0xC8000425L)
+
+//
+// MessageId: hrInvalidLanguageId
+//
+// MessageText:
+//
+// The language ID is either not known or is not valid.
+//
+#define hrInvalidLanguageId ((HRESULT)0xC8000426L)
+
+//
+// MessageId: hrInvalidCodePage
+//
+// MessageText:
+//
+// The code page is either not known or is not valid.
+//
+#define hrInvalidCodePage ((HRESULT)0xC8000427L)
+
+//
+// MessageId: hrNoWriteLock
+//
+// MessageText:
+//
+// There is no write lock at transaction level 0.
+//
+#define hrNoWriteLock ((HRESULT)0x8800042BL)
+
+//
+// MessageId: hrColumnSetNull
+//
+// MessageText:
+//
+// The column value is set to null.
+//
+#define hrColumnSetNull ((HRESULT)0x8800042CL)
+
+//
+// MessageId: hrVersionStoreOutOfMemory
+//
+// MessageText:
+//
+// lMaxVerPages exceeded (XJET only)
+//
+#define hrVersionStoreOutOfMemory ((HRESULT)0xC800042DL)
+
+//
+// MessageId: hrCurrencyStackOutOfMemory
+//
+// MessageText:
+//
+// Out of cursors.
+//
+#define hrCurrencyStackOutOfMemory ((HRESULT)0xC800042EL)
+
+//
+// MessageId: hrOutOfSessions
+//
+// MessageText:
+//
+// Out of sessions.
+//
+#define hrOutOfSessions ((HRESULT)0xC800044DL)
+
+//
+// MessageId: hrWriteConflict
+//
+// MessageText:
+//
+// The write lock failed due to an outstanding write lock.
+//
+#define hrWriteConflict ((HRESULT)0xC800044EL)
+
+//
+// MessageId: hrTransTooDeep
+//
+// MessageText:
+//
+// The transactions are nested too deeply.
+//
+#define hrTransTooDeep ((HRESULT)0xC800044FL)
+
+//
+// MessageId: hrInvalidSesid
+//
+// MessageText:
+//
+// The session handle is not valid.
+//
+#define hrInvalidSesid ((HRESULT)0xC8000450L)
+
+//
+// MessageId: hrSessionWriteConflict
+//
+// MessageText:
+//
+// Another session has a private version of the page.
+//
+#define hrSessionWriteConflict ((HRESULT)0xC8000453L)
+
+//
+// MessageId: hrInTransaction
+//
+// MessageText:
+//
+// The operation is not allowed within a transaction.
+//
+#define hrInTransaction ((HRESULT)0xC8000454L)
+
+//
+// MessageId: hrDatabaseDuplicate
+//
+// MessageText:
+//
+// The database already exists.
+//
+#define hrDatabaseDuplicate ((HRESULT)0xC80004B1L)
+
+//
+// MessageId: hrDatabaseInUse
+//
+// MessageText:
+//
+// The database is in use.
+//
+#define hrDatabaseInUse ((HRESULT)0xC80004B2L)
+
+//
+// MessageId: hrDatabaseNotFound
+//
+// MessageText:
+//
+// The database does not exist.
+//
+#define hrDatabaseNotFound ((HRESULT)0xC80004B3L)
+
+//
+// MessageId: hrDatabaseInvalidName
+//
+// MessageText:
+//
+// The database name is not valid.
+//
+#define hrDatabaseInvalidName ((HRESULT)0xC80004B4L)
+
+//
+// MessageId: hrDatabaseInvalidPages
+//
+// MessageText:
+//
+// The number of pages is not valid.
+//
+#define hrDatabaseInvalidPages ((HRESULT)0xC80004B5L)
+
+//
+// MessageId: hrDatabaseCorrupted
+//
+// MessageText:
+//
+// The database file is either damaged or cannot be found.
+//
+#define hrDatabaseCorrupted ((HRESULT)0xC80004B6L)
+
+//
+// MessageId: hrDatabaseLocked
+//
+// MessageText:
+//
+// The database is locked.
+//
+#define hrDatabaseLocked ((HRESULT)0xC80004B7L)
+
+//
+// MessageId: hrTableEmpty
+//
+// MessageText:
+//
+// An empty table was opened.
+//
+#define hrTableEmpty ((HRESULT)0x88000515L)
+
+//
+// MessageId: hrTableLocked
+//
+// MessageText:
+//
+// The table is locked.
+//
+#define hrTableLocked ((HRESULT)0xC8000516L)
+
+//
+// MessageId: hrTableDuplicate
+//
+// MessageText:
+//
+// The table already exists.
+//
+#define hrTableDuplicate ((HRESULT)0xC8000517L)
+
+//
+// MessageId: hrTableInUse
+//
+// MessageText:
+//
+// Unable to lock the table because it is already in use.
+//
+#define hrTableInUse ((HRESULT)0xC8000518L)
+
+//
+// MessageId: hrObjectNotFound
+//
+// MessageText:
+//
+// The table or object does not exist.
+//
+#define hrObjectNotFound ((HRESULT)0xC8000519L)
+
+//
+// MessageId: hrCannotRename
+//
+// MessageText:
+//
+// Unable to rename the temporary file.
+//
+#define hrCannotRename ((HRESULT)0xC800051AL)
+
+//
+// MessageId: hrDensityInvalid
+//
+// MessageText:
+//
+// The file/index density is not valid.
+//
+#define hrDensityInvalid ((HRESULT)0xC800051BL)
+
+//
+// MessageId: hrTableNotEmpty
+//
+// MessageText:
+//
+// Unable to define the clustered index.
+//
+#define hrTableNotEmpty ((HRESULT)0xC800051CL)
+
+//
+// MessageId: hrInvalidTableId
+//
+// MessageText:
+//
+// The table ID is not valid.
+//
+#define hrInvalidTableId ((HRESULT)0xC800051EL)
+
+//
+// MessageId: hrTooManyOpenTables
+//
+// MessageText:
+//
+// Unable to open any more tables.
+//
+#define hrTooManyOpenTables ((HRESULT)0xC800051FL)
+
+//
+// MessageId: hrIllegalOperation
+//
+// MessageText:
+//
+// The operation is not supported on tables.
+//
+#define hrIllegalOperation ((HRESULT)0xC8000520L)
+
+//
+// MessageId: hrObjectDuplicate
+//
+// MessageText:
+//
+// The table or object name is already being used.
+//
+#define hrObjectDuplicate ((HRESULT)0xC8000522L)
+
+//
+// MessageId: hrInvalidObject
+//
+// MessageText:
+//
+// The object is not valid for operation.
+//
+#define hrInvalidObject ((HRESULT)0xC8000524L)
+
+//
+// MessageId: hrIndexCantBuild
+//
+// MessageText:
+//
+// Unable to build a clustered index.
+//
+#define hrIndexCantBuild ((HRESULT)0xC8000579L)
+
+//
+// MessageId: hrIndexHasPrimary
+//
+// MessageText:
+//
+// The primary index is already defined.
+//
+#define hrIndexHasPrimary ((HRESULT)0xC800057AL)
+
+//
+// MessageId: hrIndexDuplicate
+//
+// MessageText:
+//
+// The index is already defined.
+//
+#define hrIndexDuplicate ((HRESULT)0xC800057BL)
+
+//
+// MessageId: hrIndexNotFound
+//
+// MessageText:
+//
+// The index does not exist.
+//
+#define hrIndexNotFound ((HRESULT)0xC800057CL)
+
+//
+// MessageId: hrIndexMustStay
+//
+// MessageText:
+//
+// Unable to delete a clustered index.
+//
+#define hrIndexMustStay ((HRESULT)0xC800057DL)
+
+//
+// MessageId: hrIndexInvalidDef
+//
+// MessageText:
+//
+// The index definition is illegal.
+//
+#define hrIndexInvalidDef ((HRESULT)0xC800057EL)
+
+//
+// MessageId: hrIndexHasClustered
+//
+// MessageText:
+//
+// The clustered index is already defined.
+//
+#define hrIndexHasClustered ((HRESULT)0xC8000580L)
+
+//
+// MessageId: hrCreateIndexFailed
+//
+// MessageText:
+//
+// Unable to create the index because an error occurred while creating a table.
+//
+#define hrCreateIndexFailed ((HRESULT)0x88000581L)
+
+//
+// MessageId: hrTooManyOpenIndexes
+//
+// MessageText:
+//
+// Out of index description blocks.
+//
+#define hrTooManyOpenIndexes ((HRESULT)0xC8000582L)
+
+//
+// MessageId: hrColumnLong
+//
+// MessageText:
+//
+// The column value is too long.
+//
+#define hrColumnLong ((HRESULT)0xC80005DDL)
+
+//
+// MessageId: hrColumnDoesNotFit
+//
+// MessageText:
+//
+// The field will not fit in the record.
+//
+#define hrColumnDoesNotFit ((HRESULT)0xC80005DFL)
+
+//
+// MessageId: hrNullInvalid
+//
+// MessageText:
+//
+// The value cannot be null.
+//
+#define hrNullInvalid ((HRESULT)0xC80005E0L)
+
+//
+// MessageId: hrColumnIndexed
+//
+// MessageText:
+//
+// Unable to delete because the column is indexed.
+//
+#define hrColumnIndexed ((HRESULT)0xC80005E1L)
+
+//
+// MessageId: hrColumnTooBig
+//
+// MessageText:
+//
+// The length of the field exceeds the maximum length of 255 bytes.
+//
+#define hrColumnTooBig ((HRESULT)0xC80005E2L)
+
+//
+// MessageId: hrColumnNotFound
+//
+// MessageText:
+//
+// Unable to find the column.
+//
+#define hrColumnNotFound ((HRESULT)0xC80005E3L)
+
+//
+// MessageId: hrColumnDuplicate
+//
+// MessageText:
+//
+// The field is already defined.
+//
+#define hrColumnDuplicate ((HRESULT)0xC80005E4L)
+
+//
+// MessageId: hrColumn2ndSysMaint
+//
+// MessageText:
+//
+// Only one auto-increment or version column is allowed per table.
+//
+#define hrColumn2ndSysMaint ((HRESULT)0xC80005E6L)
+
+//
+// MessageId: hrInvalidColumnType
+//
+// MessageText:
+//
+// The column data type is not valid.
+//
+#define hrInvalidColumnType ((HRESULT)0xC80005E7L)
+
+//
+// MessageId: hrColumnMaxTruncated
+//
+// MessageText:
+//
+// The column was truncated because it exceeded the maximum length of 255 bytes.
+//
+#define hrColumnMaxTruncated ((HRESULT)0x880005E8L)
+
+//
+// MessageId: hrColumnCannotIndex
+//
+// MessageText:
+//
+// Unable to index a long value column.
+//
+#define hrColumnCannotIndex ((HRESULT)0xC80005E9L)
+
+//
+// MessageId: hrTaggedNotNULL
+//
+// MessageText:
+//
+// Tagged columns cannot be null.
+//
+#define hrTaggedNotNULL ((HRESULT)0xC80005EAL)
+
+//
+// MessageId: hrNoCurrentIndex
+//
+// MessageText:
+//
+// The entry is not valid without a current index.
+//
+#define hrNoCurrentIndex ((HRESULT)0xC80005EBL)
+
+//
+// MessageId: hrKeyIsMade
+//
+// MessageText:
+//
+// The key is completely made.
+//
+#define hrKeyIsMade ((HRESULT)0xC80005ECL)
+
+//
+// MessageId: hrBadColumnId
+//
+// MessageText:
+//
+// The column ID is not correct.
+//
+#define hrBadColumnId ((HRESULT)0xC80005EDL)
+
+//
+// MessageId: hrBadItagSequence
+//
+// MessageText:
+//
+// There is a bad instance identifier for a multivalued column.
+//
+#define hrBadItagSequence ((HRESULT)0xC80005EEL)
+
+//
+// MessageId: hrCannotBeTagged
+//
+// MessageText:
+//
+// AutoIncrement and Version cannot be multivalued.
+//
+#define hrCannotBeTagged ((HRESULT)0xC80005F1L)
+
+//
+// MessageId: hrRecordNotFound
+//
+// MessageText:
+//
+// Unable to find the key.
+//
+#define hrRecordNotFound ((HRESULT)0xC8000641L)
+
+//
+// MessageId: hrNoCurrentRecord
+//
+// MessageText:
+//
+// The currency is not on a record.
+//
+#define hrNoCurrentRecord ((HRESULT)0xC8000643L)
+
+//
+// MessageId: hrRecordClusteredChanged
+//
+// MessageText:
+//
+// A clustered key cannot be changed.
+//
+#define hrRecordClusteredChanged ((HRESULT)0xC8000644L)
+
+//
+// MessageId: hrKeyDuplicate
+//
+// MessageText:
+//
+// The key already exists.
+//
+#define hrKeyDuplicate ((HRESULT)0xC8000645L)
+
+//
+// MessageId: hrAlreadyPrepared
+//
+// MessageText:
+//
+// The current entry has already been copied or cleared.
+//
+#define hrAlreadyPrepared ((HRESULT)0xC8000647L)
+
+//
+// MessageId: hrKeyNotMade
+//
+// MessageText:
+//
+// No key was made.
+//
+#define hrKeyNotMade ((HRESULT)0xC8000648L)
+
+//
+// MessageId: hrUpdateNotPrepared
+//
+// MessageText:
+//
+// Update was not prepared.
+//
+#define hrUpdateNotPrepared ((HRESULT)0xC8000649L)
+
+//
+// MessageId: hrwrnDataHasChanged
+//
+// MessageText:
+//
+// Data has changed.
+//
+#define hrwrnDataHasChanged ((HRESULT)0x8800064AL)
+
+//
+// MessageId: hrerrDataHasChanged
+//
+// MessageText:
+//
+// The operation was abandoned because data has changed.
+//
+#define hrerrDataHasChanged ((HRESULT)0xC800064BL)
+
+//
+// MessageId: hrKeyChanged
+//
+// MessageText:
+//
+// Moved to a new key.
+//
+#define hrKeyChanged ((HRESULT)0x88000652L)
+
+//
+// MessageId: hrTooManySorts
+//
+// MessageText:
+//
+// There are too many sort processes.
+//
+#define hrTooManySorts ((HRESULT)0xC80006A5L)
+
+//
+// MessageId: hrInvalidOnSort
+//
+// MessageText:
+//
+// An operation that is not valid occurred in the sort.
+//
+#define hrInvalidOnSort ((HRESULT)0xC80006A6L)
+
+//
+// MessageId: hrTempFileOpenError
+//
+// MessageText:
+//
+// Unable to open the temporary file.
+//
+#define hrTempFileOpenError ((HRESULT)0xC800070BL)
+
+//
+// MessageId: hrTooManyAttachedDatabases
+//
+// MessageText:
+//
+// There are too many databases open.
+//
+#define hrTooManyAttachedDatabases ((HRESULT)0xC800070DL)
+
+//
+// MessageId: hrDiskFull
+//
+// MessageText:
+//
+// The disk is full.
+//
+#define hrDiskFull ((HRESULT)0xC8000710L)
+
+//
+// MessageId: hrPermissionDenied
+//
+// MessageText:
+//
+// Permission is denied.
+//
+#define hrPermissionDenied ((HRESULT)0xC8000711L)
+
+//
+// MessageId: hrFileNotFound
+//
+// MessageText:
+//
+// Unable to find the file.
+//
+#define hrFileNotFound ((HRESULT)0xC8000713L)
+
+//
+// MessageId: hrFileOpenReadOnly
+//
+// MessageText:
+//
+// The database file is read only.
+//
+#define hrFileOpenReadOnly ((HRESULT)0x88000715L)
+
+//
+// MessageId: hrAfterInitialization
+//
+// MessageText:
+//
+// Unable to restore after initialization.
+//
+#define hrAfterInitialization ((HRESULT)0xC800073AL)
+
+//
+// MessageId: hrLogCorrupted
+//
+// MessageText:
+//
+// The database log files are damaged.
+//
+#define hrLogCorrupted ((HRESULT)0xC800073CL)
+
+//
+// MessageId: hrInvalidOperation
+//
+// MessageText:
+//
+// The operation is not valid.
+//
+#define hrInvalidOperation ((HRESULT)0xC8000772L)
+
+//
+// MessageId: hrAccessDenied
+//
+// MessageText:
+//
+// Access is denied.
+//
+#define hrAccessDenied ((HRESULT)0xC8000773L)
+
+#endif // _EDBMSG_
diff --git a/private/utils/ntbackup/exchange/inc/jet.h b/private/utils/ntbackup/exchange/inc/jet.h
new file mode 100644
index 000000000..7ced38f62
--- /dev/null
+++ b/private/utils/ntbackup/exchange/inc/jet.h
@@ -0,0 +1,1804 @@
+#if !defined(_JET_INCLUDED)
+#define _JET_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(_M_ALPHA)
+#pragma pack(8)
+#else
+#pragma pack(4)
+#endif
+
+#define JET_API __stdcall
+#define JET_NODSAPI __stdcall
+
+typedef long JET_ERR;
+
+typedef unsigned long JET_INSTANCE; /* Instance Identifier */
+typedef unsigned long JET_SESID; /* Session Identifier */
+typedef unsigned long JET_TABLEID; /* Table Identifier */
+typedef unsigned long JET_COLUMNID; /* Column Identifier */
+
+typedef unsigned long JET_DBID; /* Database Identifier */
+typedef unsigned long JET_OBJTYP; /* Object Type */
+typedef unsigned long JET_COLTYP; /* Column Type */
+typedef unsigned long JET_GRBIT; /* Group of Bits */
+typedef unsigned long JET_ACM; /* Access Mask */
+typedef unsigned long JET_RNT; /* Repair Notification Type */
+
+typedef unsigned long JET_SNP; /* Status Notification Process */
+typedef unsigned long JET_SNT; /* Status Notification Type */
+typedef unsigned long JET_SNC; /* Status Notification Code */
+typedef double JET_DATESERIAL; /* JET_coltypDateTime format */
+typedef unsigned long JET_HANDLE; /* backup file handle */
+
+typedef JET_ERR (__stdcall *JET_PFNSTATUS)(JET_SESID sesid, JET_SNP snp, JET_SNT snt, void *pv);
+
+typedef struct tagCONVERT
+ {
+ char *szOldDll;
+ char *szOldSysDb;
+ unsigned long fDbAttached; // Return value indicating if Db was attached
+ } JET_CONVERT;
+
+
+typedef enum
+ {
+ opDBUTILConsistency,
+ opDBUTILDumpData,
+ opDBUTILDumpMetaData,
+ opDBUTILDumpSpace,
+ opDBUTILDumpHeader,
+ opDBUTILDumpLogfile,
+ opDBUTILDumpCheckpoint
+ } DBUTIL_OP;
+
+typedef struct tagDBUTIL
+ {
+ unsigned long cbStruct;
+ char *szDatabase;
+ char *szTable;
+ char *szIndex;
+ DBUTIL_OP op;
+ JET_GRBIT grbitOptions;
+ } JET_DBUTIL;
+
+#define JET_bitDBUtilOptionAllNodes 0x00000001
+#define JET_bitDBUtilOptionKeyStats 0x00000002
+#define JET_bitDBUtilOptionPageDump 0x00000004
+#define JET_bitDBUtilOptionDumpVerbose 0x10000000 // DEBUG only
+
+
+ /* Session information bits */
+
+#define JET_bitCIMCommitted 0x00000001
+#define JET_bitCIMDirty 0x00000002
+#define JET_bitAggregateTransaction 0x00000008
+
+ /* JetGetLastErrorInfo structure */
+
+typedef struct
+ {
+ unsigned long cbStruct; /* Size of this structure */
+ JET_ERR err; /* Extended error code (if any) */
+ unsigned long ul1; /* First general purpose integer */
+ unsigned long ul2; /* Second general purpose integer */
+ unsigned long ul3; /* Third general purpose integer */
+ } JET_EXTERR;
+
+ /* Status Notification Structures */
+
+typedef struct /* Status Notification Progress */
+ {
+ unsigned long cbStruct; /* Size of this structure */
+ unsigned long cunitDone; /* Number of units of work completed */
+ unsigned long cunitTotal; /* Total number of units of work */
+ } JET_SNPROG;
+
+ /* ErrCount Notification Structures */
+
+typedef struct /* Status Notification Progress */
+ {
+ unsigned long cbStruct; /* Size of this structure */
+ unsigned long cRecUniqueKeyViolation;
+ unsigned long cRecTypeConversionFail;
+ unsigned long cRecRecordLocked;
+ unsigned long cRecTotal; /* Total number of units of work */
+ } JET_SNERRCNT;
+
+
+typedef struct /* Status Notification Message */
+ {
+ unsigned long cbStruct; /* Size of this structure */
+ JET_SNC snc; /* Status Notification Code */
+ unsigned long ul; /* Numeric identifier */
+ char sz[256]; /* Identifier */
+ } JET_SNMSG;
+
+
+typedef struct
+ {
+ unsigned long cbStruct;
+ JET_OBJTYP objtyp;
+ JET_DATESERIAL dtCreate;
+ JET_DATESERIAL dtUpdate;
+ JET_GRBIT grbit;
+ unsigned long flags;
+ unsigned long cRecord;
+ unsigned long cPage;
+ } JET_OBJECTINFO;
+
+
+/* required for Exchange to make RSTMAP RPC capable
+/**/
+#ifdef MIDL_PASS
+#define RPC_STRING [string]
+#else
+#define RPC_STRING
+typedef unsigned short WCHAR;
+#endif
+
+typedef struct
+ {
+ RPC_STRING char *szDatabaseName;
+ RPC_STRING char *szNewDatabaseName;
+ } JET_RSTMAP; /* restore map */
+
+/* required for Exchange unicode support
+/**/
+#define UNICODE_RSTMAP
+
+typedef struct tagJET_RSTMAPW {
+ RPC_STRING WCHAR *wszDatabaseName;
+
+ RPC_STRING WCHAR *wszNewDatabaseName;
+ } JET_RSTMAPW, *PJET_RSTMAPW;
+
+ /* The following flags appear in the grbit field above */
+
+#define JET_bitTableInfoUpdatable 0x00000001
+#define JET_bitTableInfoBookmark 0x00000002
+#define JET_bitTableInfoRollback 0x00000004
+#define JET_bitTableInfoRestartable 0x00000008
+#define JET_bitTableInfoNoInserts 0x00000010
+
+ /* The following flags occur in the flags field above */
+
+#define JET_bitSaveUIDnPWD 0x20000000 /* this bit is only */
+ /* appropriate for rmt links */
+#define JET_bitObjectExclusive 0x40000000 /* Open link exclusively */
+#define JET_bitObjectSystem 0x80000000
+
+
+typedef struct
+ {
+ unsigned long cbStruct;
+ JET_TABLEID tableid;
+ unsigned long cRecord;
+ JET_COLUMNID columnidcontainername;
+ JET_COLUMNID columnidobjectname;
+ JET_COLUMNID columnidobjtyp;
+ JET_COLUMNID columniddtCreate;
+ JET_COLUMNID columniddtUpdate;
+ JET_COLUMNID columnidgrbit;
+ JET_COLUMNID columnidflags;
+ JET_COLUMNID columnidcRecord; /* Level 2 info */
+ JET_COLUMNID columnidcPage; /* Level 2 info */
+ } JET_OBJECTLIST;
+
+#define cObjectInfoCols 9
+
+typedef struct
+ {
+ unsigned long cbStruct;
+ JET_TABLEID tableid;
+ unsigned long cRecord;
+ JET_COLUMNID columnidSid;
+ JET_COLUMNID columnidACM;
+ JET_COLUMNID columnidgrbit; /* grbit from JetSetAccess */
+ } JET_OBJECTACMLIST;
+
+#define cObjectAcmCols 3
+
+
+typedef struct
+ {
+ unsigned long cbStruct;
+ JET_TABLEID tableid;
+ unsigned long cRecord;
+ JET_COLUMNID columnidPresentationOrder;
+ JET_COLUMNID columnidcolumnname;
+ JET_COLUMNID columnidcolumnid;
+ JET_COLUMNID columnidcoltyp;
+ JET_COLUMNID columnidCountry;
+ JET_COLUMNID columnidLangid;
+ JET_COLUMNID columnidCp;
+ JET_COLUMNID columnidCollate;
+ JET_COLUMNID columnidcbMax;
+ JET_COLUMNID columnidgrbit;
+ JET_COLUMNID columnidDefault;
+ JET_COLUMNID columnidBaseTableName;
+ JET_COLUMNID columnidBaseColumnName;
+ JET_COLUMNID columnidDefinitionName;
+ } JET_COLUMNLIST;
+
+#define cColumnInfoCols 14
+
+typedef struct
+ {
+ unsigned long cbStruct;
+ JET_COLUMNID columnid;
+ JET_COLTYP coltyp;
+ unsigned short wCountry;
+ unsigned short langid;
+ unsigned short cp;
+ unsigned short wCollate; /* Must be 0 */
+ unsigned long cbMax;
+ JET_GRBIT grbit;
+ } JET_COLUMNDEF;
+
+
+typedef struct
+ {
+ unsigned long cbStruct;
+ JET_COLUMNID columnid;
+ JET_COLTYP coltyp;
+ unsigned short wCountry;
+ unsigned short langid;
+ unsigned short cp;
+ unsigned short wFiller; /* Must be 0 */
+ unsigned long cbMax;
+ JET_GRBIT grbit;
+ char szBaseTableName[256];
+ char szBaseColumnName[256];
+ } JET_COLUMNBASE;
+
+typedef struct
+ {
+ unsigned long cbStruct;
+ JET_TABLEID tableid;
+ unsigned long cRecord;
+ JET_COLUMNID columnidindexname;
+ JET_COLUMNID columnidgrbitIndex;
+ JET_COLUMNID columnidcKey;
+ JET_COLUMNID columnidcEntry;
+ JET_COLUMNID columnidcPage;
+ JET_COLUMNID columnidcColumn;
+ JET_COLUMNID columnidiColumn;
+ JET_COLUMNID columnidcolumnid;
+ JET_COLUMNID columnidcoltyp;
+ JET_COLUMNID columnidCountry;
+ JET_COLUMNID columnidLangid;
+ JET_COLUMNID columnidCp;
+ JET_COLUMNID columnidCollate;
+ JET_COLUMNID columnidgrbitColumn;
+ JET_COLUMNID columnidcolumnname;
+ } JET_INDEXLIST;
+
+
+
+typedef struct tag_JET_COLUMNCREATE
+ {
+ unsigned long cbStruct; // size of this structure (for future expansion)
+ char *szColumnName; // column name
+ JET_COLTYP coltyp; // column type
+ unsigned long cbMax; // the maximum length of this column (only relevant for binary and text columns)
+ JET_GRBIT grbit; // column options
+ void *pvDefault; // default value (NULL if none)
+ unsigned long cbDefault; // length of default value
+ unsigned long cp; // code page (for text columns only)
+ JET_COLUMNID columnid; // returned column id
+ JET_ERR err; // returned error code
+ } JET_COLUMNCREATE;
+
+
+typedef struct tagJET_INDEXCREATE
+ {
+ unsigned long cbStruct; // size of this structure (for future expansion)
+ char *szIndexName; // index name
+ char *szKey; // index key
+ unsigned long cbKey; // length of key
+ JET_GRBIT grbit; // index options
+ unsigned long ulDensity; // index density
+ JET_ERR err; // returned error code
+ } JET_INDEXCREATE;
+
+
+typedef struct tagJET_TABLECREATE
+ {
+ unsigned long cbStruct; // size of this structure (for future expansion)
+ char *szTableName; // name of table to create.
+ unsigned long ulPages; // initial pages to allocate for table.
+ unsigned long ulDensity; // table density.
+ JET_COLUMNCREATE *rgcolumncreate; // array of column creation info
+ unsigned long cColumns; // number of columns to create
+ JET_INDEXCREATE *rgindexcreate; // array of index creation info
+ unsigned long cIndexes; // number of indexes to create
+ JET_GRBIT grbit; // Abort column/index creation on error?
+ JET_TABLEID tableid; // returned tableid.
+ unsigned long cCreated; // count of objects created (columns+table+indexes).
+ } JET_TABLECREATE;
+
+
+#define cIndexInfoCols 15
+
+typedef struct
+ {
+ unsigned long cbStruct;
+ JET_TABLEID tableid;
+ unsigned long cRecord;
+ JET_COLUMNID columnidReferenceName;
+ JET_COLUMNID columnidgrbit;
+ JET_COLUMNID columnidcColumn;
+ JET_COLUMNID columnidiColumn;
+ JET_COLUMNID columnidReferencingTableName;
+ JET_COLUMNID columnidReferencingColumnName;
+ JET_COLUMNID columnidReferencedTableName;
+ JET_COLUMNID columnidReferencedColumnName;
+ } JET_RELATIONSHIPLIST;
+
+/* for backward compatibility */
+typedef JET_RELATIONSHIPLIST JET_REFERENCELIST;
+
+#define cReferenceInfoCols 8
+
+typedef struct
+ {
+ unsigned long cbStruct;
+ unsigned long ibLongValue;
+ unsigned long itagSequence;
+ JET_COLUMNID columnidNextTagged;
+ } JET_RETINFO;
+
+typedef struct
+ {
+ unsigned long cbStruct;
+ unsigned long ibLongValue;
+ unsigned long itagSequence;
+ } JET_SETINFO;
+
+typedef struct
+ {
+ unsigned long cbStruct;
+ unsigned long centriesLT;
+ unsigned long centriesInRange;
+ unsigned long centriesTotal;
+ } JET_RECPOS;
+
+typedef struct
+ {
+ unsigned long cDiscont;
+ unsigned long cUnfixedMessyPage;
+ unsigned long centriesLT;
+ unsigned long centriesTotal;
+ unsigned long cpgCompactFreed;
+ } JET_OLCSTAT;
+
+typedef struct
+ {
+ unsigned long ctableid;
+ JET_TABLEID rgtableid[1];
+ } JET_MGBLIST;
+
+/*** Property Manager Structure ***/
+typedef struct
+ {
+ unsigned long cbStruct;
+ JET_TABLEID tableid;
+ JET_COLUMNID columnidColumnName;
+ JET_COLUMNID columnidPropertyName;
+ JET_COLUMNID columnidGrbit;
+ JET_COLUMNID columnidPropertyValue;
+ JET_COLUMNID columnidColtyp;
+ } JET_PROPERTYLIST;
+
+
+/************************************************************************/
+/************************* JET CONSTANTS ************************/
+/************************************************************************/
+
+#define JET_tableidNil ((JET_TABLEID) 0xFFFFFFFF)
+
+#define JET_sesidNil ((JET_SESID) 0xFFFFFFFF)
+
+ /* Max size of a bookmark */
+
+#define JET_cbBookmarkMost 4
+
+ /* Max length of a object/column/index/property name */
+
+#define JET_cbNameMost 64
+
+ /* Max length of a "name.name.name..." construct */
+
+#define JET_cbFullNameMost 255
+
+ /* Max size of long-value column chunk */
+
+#define JET_cbColumnLVChunkMost 4035
+
+ /* Max size of non-long-value column data */
+
+#define JET_cbColumnMost 255
+
+ /* Max size of a sort/index key */
+
+#define JET_cbKeyMost 255
+
+ /* Max number of components in a sort/index key */
+
+#define JET_ccolKeyMost 12
+
+ /* Max number of columns in a table/query */
+
+#define JET_ccolTableMost 255
+
+ /* Max Length of a property in the property manager */
+#define JET_cbPropertyMost 2048
+
+ /* Largest initial substring of a long value used in an expression */
+
+#define JET_cbExprLVMost 0x8000L /*** 32 K ***/
+
+ /* Max size of returned (from SQLDriverConnect) conn string */
+
+#define JET_cbConnectMost 255
+
+ /* Max number of levels in an MGB */
+
+#define JET_wGroupLevelMax 12
+
+ /* Size restrictions for Pins */
+#define JET_cchPINMax 20
+#define JET_cchPINMin 4
+
+ /* System parameter codes for JetSetSystemParameter */
+
+/* not supported */
+#define JET_paramPfnStatus 2 /* Status callback function */
+#define JET_paramPfnError 3 /* Error callback function */
+#define JET_paramHwndODBC 4 /* Window handle for ODBC use */
+#define JET_paramIniPath 5 /* Path to the ini file */
+#define JET_paramPageTimeout 6 /* Red ISAM page timeout value */
+#define JET_paramODBCQueryTimeout 7 /* ODBC async query timeout value */
+#define JET_paramODBCLoginTimeout 25 /* ODBC connection attempt timeout value */
+#define JET_paramExprObject 26 /* Expression Evaluation callback */
+#define JET_paramGetTypeComp 27 /* Expression Evaluation callback */
+#define JET_paramHostVersion 28 /* Host Version callback */
+#define JET_paramSQLTraceMode 29 /* Enable/disable SQL tracing */
+#define JET_paramEventId 46 /* NT event id */
+#define JET_paramEventCategory 47 /* NT event category */
+#define JET_paramRmtXactIsolation 39 /* Do not share connections with other sessions */
+#define JET_paramJetInternal 35 /* Whether internal to JET; if set, allows ISAM to do things which are prevented in general */
+#define JET_paramFullQJet 38 /* Allow full QJet functionality */
+
+#define JET_paramLogFlushThreshold 18 /* log buffer flush threshold in 512 bytes [10] */
+#define JET_paramLogFlushPeriod 22 /* log flush period in miliseconds [45] */
+
+#define JET_paramOnLineCompact 37 /* Options for compact pages on-line */
+#define JET_paramRecovery 30 /* Switch for log on/off */
+
+/* debug only not supported */
+#define JET_paramTransactionLevel 32 /* Transaction level of session */
+#define JET_paramAssertAction 44 /* debug only determines action on assert */
+#define JET_paramPrintFunction 49 /* debug only. synched print function */
+#define JET_paramRFS2IOsPermitted 54 /* # IOs permitted to succeed (-1 = all) */
+#define JET_paramRFS2AllocsPermitted 55 /* # allocs permitted to success (-1 = all) */
+
+/* fully supported parameters */
+/* Note that one page = 4kBytes.
+/**/
+#define JET_paramSysDbPath 0 /* path to the system database (defunct) ["<base name>.<base ext>"] */
+#define JET_paramSystemPath 0 /* path to check point file ["."] */
+#define JET_paramTempPath 1 /* path to the temporary database ["."] */
+#define JET_paramMaxBuffers 8 /* maximum page cache size in pages [512] */
+#define JET_paramMaxSessions 9 /* maximum number of sessions [128] */
+#define JET_paramMaxOpenTables 10 /* maximum number of open tables [300] */
+#define JET_paramPreferredMaxOpenTables 59 /* prefered maximum number of open tables [300] */
+#define JET_paramMaxVerPages 11 /* maximum version store size in 16KB buckets [64] */
+#define JET_paramMaxCursors 12 /* maximum number of open cursors [1024] */
+#define JET_paramLogFilePath 13 /* path to the log file directory ["."] */
+#define JET_paramMaxOpenTableIndexes 14 /* maximum open table indexes [300] */
+#define JET_paramMaxTemporaryTables 15 /* maximum concurrent JetCreateIndex [20] */
+#define JET_paramLogBuffers 16 /* maximum log buffers in 512 bytes [21] */
+#define JET_paramLogFileSize 17 /* maximum log file size in kBytes [5120] */
+#define JET_paramBfThrshldLowPrcnt 19 /* low percentage clean buffer flush start [20] */
+#define JET_paramBfThrshldHighPrcnt 20 /* high percentage clean buffer flush stop [80] */
+#define JET_paramWaitLogFlush 21 /* log flush wait time in milliseconds [15] */
+#define JET_paramLogCheckpointPeriod 23 /* checkpoint period in 512 bytes [1024] */
+#define JET_paramLogWaitingUserMax 24 /* maximum sessions waiting log flush [3] */
+#define JET_paramSessionInfo 33 /* per session information [0] */
+#define JET_paramPageFragment 34 /* maximum disk extent considered fragment in pages [8] */
+#define JET_paramMaxOpenDatabases 36 /* maximum number of open databases [100] */
+#define JET_paramBufBatchIOMax 41 /* maximum batch IO in pages [64] */
+#define JET_paramPageReadAheadMax 42 /* maximum read-ahead IO in pages [20] */
+#define JET_paramAsynchIOMax 43 /* maximum asynchronous IO in pages [64] */
+#define JET_paramEventSource 45 /* language independant process descriptor string [""] */
+#define JET_paramDbExtensionSize 48 /* database extension size in pages [16] */
+#define JET_paramCommitDefault 50 /* default grbit for JetCommitTransaction [0] */
+#define JET_paramBufLogGenAgeThreshold 51 /* age threshold in log files [2] */
+#define JET_paramCircularLog 52 /* boolean flag for circular logging [0] */
+#define JET_paramPageTempDBMin 53 /* minimum size temporary database in pages [0] */
+#define JET_paramBaseName 56 /* base name for all DBMS object names ["edb"] */
+#define JET_paramBaseExtension 57 /* base extension for all DBMS object names ["edb"] */
+#define JET_paramTableClassName 58 /* table stats class name (class #, string) */
+
+ /* Flags for JetTerm2 */
+
+#define JET_bitTermComplete 0x00000001
+#define JET_bitTermAbrupt 0x00000002
+
+ /* Flags for JetIdle */
+
+#define JET_bitIdleRemoveReadLocks 0x00000001
+#define JET_bitIdleFlushBuffers 0x00000002
+#define JET_bitIdleCompact 0x00000004
+#define JET_bitIdleStatus 0x80000000
+
+ /* Flags for JetEndSession */
+
+#define JET_bitForceSessionClosed 0x00000001
+
+ /* Flags for JetOpenDatabase */
+
+#define JET_bitDbReadOnly 0x00000001
+#define JET_bitDbExclusive 0x00000002 /* multiple opens allowed */
+#define JET_bitDbRemoteSilent 0x00000004
+#define JET_bitDbSingleExclusive 0x00000008 /* opened exactly once */
+
+ /* Flags for JetCloseDatabase */
+
+#define JET_bitDbForceClose 0x00000001
+
+ /* Flags for JetCreateDatabase */
+
+#define JET_bitDbVersion10 0x00000002 /* INTERNAL USE ONLY */
+#define JET_bitDbVersion1x 0x00000004
+#define JET_bitDbRecoveryOff 0x00000008 /* disable logging/recovery for this database */
+#define JET_bitDbNoLogging JET_bitDbRecoveryOff
+#define JET_bitDbCompleteConnstr 0x00000020
+#define JET_bitDbVersioningOff 0x00000040
+
+ /* Flags for JetBackup */
+
+#define JET_bitBackupIncremental 0x00000001
+#define JET_bitKeepOldLogs 0x00000002
+#define JET_bitBackupAtomic 0x00000004
+
+ /* Database types */
+
+#define JET_dbidNil ((JET_DBID) 0xFFFFFFFF)
+#define JET_dbidNoValid ((JET_DBID) 0xFFFFFFFE) /* used as a flag to indicate that there is no valid dbid */
+
+ /* Flags for JetCreateLink */
+
+/* Can use JET_bitObjectExclusive to cause linked to database to be opened */
+/* exclusively. */
+
+
+
+ /* Flags for JetCreateTableColumnIndex */
+#define JET_bitTableCreateCheckColumnNames 0x00000001 /* Ensures that each column
+ /* specified in the JET_COLUMNCREATE
+ /* array has a unique name
+ /* (for performance reasons,
+ /* the default is to NOT perform
+ /* this check and rely on the
+ /* function caller to ensure
+ /* column name uniqueness).
+ /**/
+#define JET_bitTableCreateCompaction 0x40000000 /* Internal grbit used when
+ /* creating a table during
+ /* off-line compact.
+ /**/
+#define JET_bitTableCreateSystemTable 0x80000000 /* Internal grbit used when
+ /* creating system tables.
+ /**/
+
+
+ /* Flags for JetAddColumn, JetGetColumnInfo, JetOpenTempTable */
+
+#define JET_bitColumnFixed 0x00000001
+#define JET_bitColumnTagged 0x00000002
+#define JET_bitColumnNotNULL 0x00000004
+#define JET_bitColumnVersion 0x00000008
+#define JET_bitColumnAutoincrement 0x00000010
+#define JET_bitColumnUpdatable 0x00000020 /* JetGetColumnInfo only */
+#define JET_bitColumnTTKey 0x00000040 /* JetOpenTempTable only */
+#define JET_bitColumnTTDescending 0x00000080 /* JetOpenTempTable only */
+#define JET_bitColumnNotLast 0x00000100 /* Installable ISAM option */
+#define JET_bitColumnRmtGraphic 0x00000200 /* JetGetColumnInfo */
+#define JET_bitColumnMultiValued 0x00000400
+#define JET_bitColumnColumnGUID 0x00000800
+#define JET_bitColumnMostMany 0x00001000
+#define JET_bitColumnPreventDelete 0x00002000
+
+ /* Flags for JetSetCurrentIndex */
+
+#define JET_bitMoveFirst 0x00000000
+#define JET_bitMoveBeforeFirst 0x00000001
+#define JET_bitNoMove 0x00000002
+
+ /* Flags for JetMakeKey */
+
+#define JET_bitNewKey 0x00000001
+#define JET_bitStrLimit 0x00000002
+#define JET_bitSubStrLimit 0x00000004
+#define JET_bitNormalizedKey 0x00000008
+#define JET_bitKeyDataZeroLength 0x00000010
+
+#ifdef DBCS /* johnta: LIKE "ABC" not converted to ="ABC" for Japanese */
+#define JET_bitLikeExtra1 0x00000020
+#endif /* DBCS */
+
+ /* Flags for ErrDispSetIndexRange */
+
+#define JET_bitRangeInclusive 0x00000001
+#define JET_bitRangeUpperLimit 0x00000002
+#define JET_bitRangeInstantDuration 0x00000004
+#define JET_bitRangeRemove 0x00000008
+
+ /* Constants for JetMove */
+
+#define JET_MoveFirst (0x80000000)
+#define JET_MovePrevious (-1)
+#define JET_MoveNext (+1)
+#define JET_MoveLast (0x7fffffff)
+
+ /* Flags for JetMove */
+
+#define JET_bitMoveKeyNE 0x00000001
+#define JET_bitMoveCheckTS 0x00000002
+#define JET_bitMoveInPage 0x00000004
+
+ /* Flags for JetSeek */
+
+#define JET_bitSeekEQ 0x00000001
+#define JET_bitSeekLT 0x00000002
+#define JET_bitSeekLE 0x00000004
+#define JET_bitSeekGE 0x00000008
+#define JET_bitSeekGT 0x00000010
+#define JET_bitSetIndexRange 0x00000020
+
+ /* Flags for JetFastFind */
+
+#define JET_bitFFindBackwards 0x00000001
+#define JET_bitFFindFromCursor 0x00000004
+
+ /* Flags for JetCreateIndex */
+
+#define JET_bitIndexUnique 0x00000001
+#define JET_bitIndexPrimary 0x00000002
+#define JET_bitIndexDisallowNull 0x00000004
+#define JET_bitIndexIgnoreNull 0x00000008
+#define JET_bitIndexClustered 0x00000010
+#define JET_bitIndexIgnoreAnyNull 0x00000020
+#define JET_bitIndexIgnoreFirstNull 0x00000040
+#define JET_bitIndexLazyFlush 0x00000080
+#define JET_bitIndexEmptyTable 0x40000000 // Internal use only
+#define JET_bitIndexReference 0x80000000 /* IndexInfo only */
+
+ /* Flags for index key definition */
+
+#define JET_bitKeyAscending 0x00000000
+#define JET_bitKeyDescending 0x00000001
+
+
+ /* Flags for JetCreateRelationship */
+
+#define JET_bitRelationUnique 0x00000001
+#define JET_bitRelationDontEnforce 0x00000002
+#define JET_bitRelationInherited 0x00000004
+#define JET_bitRelationTestLegal 0x00000008 /* don't create relationship */
+
+#define JET_bitRelationshipMatchMask 0x000000F0
+#define JET_bitRelationMatchDefault 0x00000000
+#define JET_bitRelationMatchFull 0x00000010
+
+#define JET_bitRelationUpdateActionMask 0x00000F00
+#define JET_bitRelationUpdateDisallow 0x00000000
+#define JET_bitRelationUpdateCascade 0x00000100
+#define JET_bitRelationUpdateSetNull 0x00000200
+#define JET_bitRelationUpdateSetDefault 0x00000300
+
+#define JET_bitRelationDeleteActionMask 0x0000F000
+#define JET_bitRelationDeleteDisallow 0x00000000
+#define JET_bitRelationDeleteCascade 0x00001000
+#define JET_bitRelationDeleteSetNull 0x00002000
+#define JET_bitRelationDeleteSetDefault 0x00003000
+
+#define JET_bitRelationUserMask 0xFF000000 /* non-enforced values */
+#define JET_bitRelationJoinMask 0x03000000
+#define JET_bitRelationInner 0x00000000
+#define JET_bitRelationLeft 0x01000000
+#define JET_bitRelationRight 0x02000000
+
+
+ /* Flags for JetCreateReference/JetCreateRelationship */
+ /* NOTE: use the bitRelationship flags instead! */
+
+#define JET_ReferenceUnique JET_bitRelationUnique
+#define JET_ReferenceDontEnforce JET_bitRelationDontEnforce
+#define JET_ReferenceMatchTypeMask JET_bitRelationMatchMask
+#define JET_ReferenceMatchDefault JET_bitRelationMatchDefault
+#define JET_ReferenceMatchFull JET_bitRelationMatchFull
+#define JET_ReferenceUpdateActionMask JET_bitRelationUpdateActionMask
+#define JET_ReferenceUpdateDisallow JET_bitRelationUpdateDisallow
+#define JET_ReferenceUpdateCascade JET_bitRelationUpdateCascade
+#define JET_ReferenceUpdateSetNull JET_bitRelationUpdateSetNull
+#define JET_ReferenceUpdateSetDefault JET_bitRelationUpdateSetDefault
+#define JET_ReferenceDeleteActionMask JET_bitRelationDeleteActionMask
+#define JET_ReferenceDeleteDisallow JET_bitRelationDeleteDisallow
+#define JET_ReferenceDeleteCascade JET_bitRelationDeleteCascade
+#define JET_ReferenceDeleteSetNull JET_bitRelationDeleteSetNull
+#define JET_ReferenceDeleteSetDefault JET_bitRelationDeleteSetDefault
+
+
+ /* Flags for JetOpenTable */
+
+#define JET_bitTableDenyWrite 0x00000001
+#define JET_bitTableDenyRead 0x00000002
+#define JET_bitTableReadOnly 0x00000004
+#define JET_bitTableAppendOnly 0x00000008
+#define JET_bitTableUpdatable 0x00000010
+#define JET_bitTableScrollable 0x00000020
+#define JET_bitTableFixedSet 0x00000040 /* Fixed working set */
+#define JET_bitTableInconsistent 0x00000080
+#define JET_bitTableBulk 0x00000100
+#define JET_bitTableUsePrimaryIndex 0x00000200 /* Use with FixedSet */
+#define JET_bitTableSampleData 0x00000400
+#define JET_bitTableQuickBrowse 0x00000800 /* Bias optimizer toward index usage */
+#define JET_bitTableDDL 0x00001000 /* similar to JET_bitTableBulk, for DDL */
+#define JET_bitTablePassThrough 0x00002000 /* Remote DBs Only */
+#define JET_bitTableRowReturning 0x00004000
+#define JET_bitTableSequential 0x00008000 /* Intend to access table sequentially */
+
+#define JET_bitTableClassMask 0x000F0000 /* table stats class mask */
+#define JET_bitTableClassNone 0x00000000 /* table belongs to no stats class (default) */
+#define JET_bitTableClass1 0x00010000 /* table belongs to stats class 1 */
+#define JET_bitTableClass2 0x00020000 /* table belongs to stats class 2 */
+#define JET_bitTableClass3 0x00030000 /* table belongs to stats class 3 */
+#define JET_bitTableClass4 0x00040000 /* table belongs to stats class 4 */
+#define JET_bitTableClass5 0x00050000 /* table belongs to stats class 5 */
+#define JET_bitTableClass6 0x00060000 /* table belongs to stats class 6 */
+#define JET_bitTableClass7 0x00070000 /* table belongs to stats class 7 */
+#define JET_bitTableClass8 0x00080000 /* table belongs to stats class 8 */
+#define JET_bitTableClass9 0x00090000 /* table belongs to stats class 9 */
+#define JET_bitTableClass10 0x000A0000 /* table belongs to stats class 10 */
+#define JET_bitTableClass11 0x000B0000 /* table belongs to stats class 11 */
+#define JET_bitTableClass12 0x000C0000 /* table belongs to stats class 12 */
+#define JET_bitTableClass13 0x000D0000 /* table belongs to stats class 13 */
+#define JET_bitTableClass14 0x000E0000 /* table belongs to stats class 14 */
+#define JET_bitTableClass15 0x000F0000 /* table belongs to stats class 15 */
+
+ /* Flags for JetSetQoSql/JetRetrieveQoSql */
+#define JET_bitSqlPassThrough 0x00000001 /* Pass through Query returning records */
+#define JET_bitSqlSPTBulkOp 0x00000002 /* SPT query returning no table */
+
+ /* Flags for JetOpenVtQbe */
+
+#define JET_bitQBEAddBrackets 0x00000001
+#define JET_bitQBERemoveEquals 0x00000002
+
+ /* Flags for JetOpenTempTable and ErrIsamOpenTempTable */
+
+#define JET_bitTTIndexed 0x00000001 /* Allow seek */
+#define JET_bitTTUnique 0x00000002 /* Remove duplicates */
+#define JET_bitTTUpdatable 0x00000004 /* Allow updates */
+#define JET_bitTTScrollable 0x00000008 /* Allow backwards scrolling */
+
+ /* Flags for JetSetColumn */
+
+#define JET_bitSetAppendLV 0x00000001
+#define JET_bitSetValidate 0x00000002
+#define JET_bitSetOverwriteLV 0x00000004 /* overwrite JET_coltypLong* byte range */
+#define JET_bitSetSizeLV 0x00000008 /* set JET_coltypLong* size */
+#define JET_bitSetValidateColumn 0x00000010
+#define JET_bitSetZeroLength 0x00000020
+#define JET_bitSetSeparateLV 0x00000040 /* force LV separation */
+#define JET_bitSetNoVersion 0x00000080 /* INTERNAL USE ONLY */
+
+ /* Set column parameter structure for JetSetColumns */
+
+typedef struct {
+ JET_COLUMNID columnid;
+ const void *pvData;
+ unsigned long cbData;
+ JET_GRBIT grbit;
+ unsigned long ibLongValue;
+ unsigned long itagSequence;
+ JET_ERR err;
+} JET_SETCOLUMN;
+
+ /* Options for JetPrepareUpdate */
+
+#define JET_prepInsert 0
+#define JET_prepInsertBeforeCurrent 1
+#define JET_prepReplace 2
+#define JET_prepCancel 3
+#define JET_prepReplaceNoLock 4
+#define JET_prepInsertCopy 5
+
+ /* Flags for JetRetrieveColumn */
+
+#define JET_bitRetrieveCopy 0x00000001
+#define JET_bitRetrieveFromIndex 0x00000002
+#define JET_bitRetrieveCase 0x00000004
+#define JET_bitRetrieveTag 0x00000008
+#define JET_bitRetrieveNull 0x00000010 /* for columnid 0 only */
+#define JET_bitRetrieveIgnoreDefault 0x00000020 /* for columnid 0 only */
+#define JET_bitRetrieveLongId 0x00000040
+#define JET_bitRetrieveRecord 0x80000000
+#define JET_bitRetrieveFDB 0x40000000
+#define JET_bitRetrieveBookmarks 0x20000000
+
+ /* Retrieve column parameter structure for JetRetrieveColumns */
+
+typedef struct {
+ JET_COLUMNID columnid;
+ void *pvData;
+ unsigned long cbData;
+ unsigned long cbActual;
+ JET_GRBIT grbit;
+ unsigned long ibLongValue;
+ unsigned long itagSequence;
+ JET_COLUMNID columnidNextTagged;
+ JET_ERR err;
+} JET_RETRIEVECOLUMN;
+
+ /* Flags for JetFillFatCursor */
+
+#define JET_bitFCFillRange 0x00000001
+#define JET_bitFCRefreshRange 0x00000002
+#define JET_bitFCFillMemos 0x00000004
+
+ /* Flags for JetCommitTransaction */
+
+#define JET_bitCommitFlush 0x00000001 /* commit and flush page buffers. */
+#define JET_bitCommitLazyFlush 0x00000004 /* lazy flush log buffers. */
+#define JET_bitWaitLastLevel0Commit 0x00000010 /* wait for last level 0 commit record flushed */
+
+ /* Flags for JetRollback */
+
+#define JET_bitRollbackAll 0x00000001
+
+ /* Flags for JetSetAccess and JetGetAccess */
+
+#define JET_bitACEInheritable 0x00000001
+
+ /* Flags for JetCreateSystemDatabase */
+
+#define JET_bitSysDbOverwrite 0x00000001
+
+ /* Flags for Jet Property Management */
+#define JET_bitPropDDL 0x00000001 /* also used for setting */
+#define JET_bitPropInherited 0x00000002 /* not used for setting */
+
+ /* JPM Flags that are only used for setting properties */
+#define JET_bitPropReplaceOnly 0x00000010
+#define JET_bitPropInsertOnly 0x00000020
+#define JET_bitPropDeleteOnly 0x00000040
+
+ /* InfoLevels for Jet Property Management */
+#define JET_PropertyValue 0
+#define JET_PropertyCount 1
+#define JET_PropertySingleCollection 2
+#define JET_PropertyAllCollections 3
+
+ /* Collate values for JetGetColumnInfo and JetGetIndexInfo */
+
+#define JET_sortBinary 0x0000
+#define JET_sortEFGPI 0x0100
+#define JET_sortSNIFD 0x0101
+#define JET_sortSpanish 0x0102
+#define JET_sortDutch 0x0103
+#define JET_sortSweFin 0x0104
+#define JET_sortNorDan 0x0105
+#define JET_sortIcelandic 0x0106
+#define JET_sortCyrillic 0x0107
+#define JET_sortCzech 0x0108
+#define JET_sortHungarian 0x0109
+#define JET_sortPolish 0x010A
+#define JET_sortArabic 0x010B
+#define JET_sortHebrew 0x010C
+#define JET_sortMax 0x010C /* Max for nonDBCS sort orders */
+
+#ifdef DBCS /* johnta: Add the new Japanese sorting order */
+#define JET_sortJapanese 0x010D
+#endif /* DBCS */
+
+#define JET_sortUnknown 0xFFFF
+
+ /* Paradox ISAM specific collate values */
+
+#define JET_sortPdxIntl 0x1000
+#define JET_sortPdxSwedFin 0x1001
+#define JET_sortPdxNorDan 0x1002
+
+ /* Info parameter for JetGetDatabaseInfo */
+
+#define JET_DbInfoFilename 0
+#define JET_DbInfoConnect 1
+#define JET_DbInfoCountry 2
+#define JET_DbInfoLangid 3
+#define JET_DbInfoCp 4
+#define JET_DbInfoCollate 5
+#define JET_DbInfoOptions 6
+#define JET_DbInfoTransactions 7
+#define JET_DbInfoVersion 8
+#define JET_DbInfoIsam 9
+#define JET_DbInfoFilesize 10
+#define JET_DbInfoSpaceOwned 11
+#define JET_DbInfoSpaceAvailable 12
+
+ /* Database versions returned by JetGetDatabaseInfo */
+
+#define JET_DbVersion10 0x00010000
+#define JET_DbVersion11 0x00010001
+#define JET_DbVersion20 0x00020000
+
+
+ /* Isam specific info returned by JetGetDatabaseInfo */
+
+#define JET_IsamInvalid 0
+#define JET_IsamBuiltinRed 1
+#define JET_IsamBuiltinBlue 2
+
+#define JET_IsamInstRed 21
+#define JET_IsamInstBlue 22
+#define JET_IsamInstFox 23
+#define JET_IsamInstParadox 24
+#define JET_IsamInstDbase 25
+#define JET_IsamInstBtrieve 26
+
+#define JET_IsamBuilinMost JET_BuiltinBlue
+#define JET_IsamInstMin JET_IsamInstRed
+#define JET_IsamInstMost JET_IsamInstBtrieve
+
+ /* Link specific info for link identification */
+#define JET_bitLinkInvalid 0x00000000
+#define JET_bitLinkRemote 0x00100000
+#define JET_bitLinkBuiltinRed 0x00200000
+#define JET_bitLinkBuiltinBlue 0x00300000
+#define JET_bitLinkInstRed 0x00400000
+#define JET_bitLinkInstBlue 0x00500000
+#define JET_bitLinkInstFox 0x00600000
+#define JET_bitLinkInstParadox 0x00700000
+#define JET_bitLinkInstDbase 0x00800000
+#define JET_bitLinkInstBtrieve 0x00900000
+
+#define JET_bitFourByteBookmark 0x00000001
+#define JET_bitContiguousBookmarks 0x00000002
+
+ /* Column data types */
+
+#define JET_coltypNil 0
+#define JET_coltypBit 1 /* True or False, Never NULL */
+#define JET_coltypUnsignedByte 2 /* 1-byte integer, unsigned */
+#define JET_coltypShort 3 /* 2-byte integer, signed */
+#define JET_coltypLong 4 /* 4-byte integer, signed */
+#define JET_coltypCurrency 5 /* 8 byte integer, signed */
+#define JET_coltypIEEESingle 6 /* 4-byte IEEE single precision */
+#define JET_coltypIEEEDouble 7 /* 8-byte IEEE double precision */
+#define JET_coltypDateTime 8 /* Integral date, fractional time */
+#define JET_coltypBinary 9 /* Binary data, < 255 bytes */
+#define JET_coltypText 10 /* ANSI text, case insensitive, < 255 bytes */
+#define JET_coltypLongBinary 11 /* Binary data, long value */
+#define JET_coltypLongText 12 /* ANSI text, long value */
+#define JET_coltypDatabase 13 /* Database name parameter */
+#define JET_coltypTableid 14 /* Tableid parameter */
+#define JET_coltypOLE 15 /* OLE blob */
+#define JET_coltypGUID 15
+#define JET_coltypMax 16 /* the number of column types */
+ /* used for validity tests and */
+ /* array declarations. */
+
+ /* Info levels for JetGetObjectInfo */
+
+#define JET_ObjInfo 0U
+#define JET_ObjInfoListNoStats 1U
+#define JET_ObjInfoList 2U
+#define JET_ObjInfoSysTabCursor 3U
+#define JET_ObjInfoListACM 4U /* Blocked by JetGetObjectInfo */
+#define JET_ObjInfoNoStats 5U
+#define JET_ObjInfoSysTabReadOnly 6U
+#define JET_ObjInfoRulesLoaded 7U
+#define JET_ObjInfoMax 8U
+
+ /* Info levels for JetGetTableInfo */
+
+#define JET_TblInfo 0U
+#define JET_TblInfoName 1U
+#define JET_TblInfoDbid 2U
+#define JET_TblInfoMostMany 3U
+#define JET_TblInfoRvt 4U
+#define JET_TblInfoOLC 5U
+#define JET_TblInfoResetOLC 6U
+#define JET_TblInfoSpaceUsage 7U
+#define JET_TblInfoDumpTable 8U
+#define JET_TblInfoSpaceAlloc 9U
+#define JET_TblInfoSpaceOwned 10U // OwnExt
+#define JET_TblInfoSpaceAvailable 11U // AvailExt
+
+ /* Info levels for JetGetIndexInfo and JetGetTableIndexInfo */
+
+#define JET_IdxInfo 0U
+#define JET_IdxInfoList 1U
+#define JET_IdxInfoSysTabCursor 2U
+#define JET_IdxInfoOLC 3U
+#define JET_IdxInfoResetOLC 4U
+#define JET_IdxInfoSpaceAlloc 5U
+#define JET_IdxInfoLangid 6U
+#define JET_IdxInfoCount 7U
+
+ /* Info levels for JetGetReferenceInfo and JetGetTableReferenceInfo */
+
+#define JET_ReferenceInfo 0U
+#define JET_ReferenceInfoReferencing 1U
+#define JET_ReferenceInfoReferenced 2U
+#define JET_ReferenceInfoAll 3U
+#define JET_ReferenceInfoCursor 4U
+
+ /* Info levels for JetGetColumnInfo and JetGetTableColumnInfo */
+
+#define JET_ColInfo 0U
+#define JET_ColInfoList 1U
+ /* CONSIDER: Info level 2 is valid */
+#define JET_ColInfoSysTabCursor 3U
+#define JET_ColInfoBase 4U
+#define JET_ColInfoListCompact 5U
+
+
+ /* Attribute types for query definitions */
+
+#define JET_qoaBeginDef 0
+#define JET_qoaOperation 1
+#define JET_qoaParameter 2
+#define JET_qoaOptions 3
+#define JET_qoaDatabase 4
+#define JET_qoaInputTable 5
+#define JET_qoaOutput 6
+#define JET_qoaJoin 7
+#define JET_qoaRestriction 8
+#define JET_qoaGroup 9
+#define JET_qoaGroupRstr 10
+#define JET_qoaOrdering 11
+#define JET_qoaEndDef 255
+#define JET_qoaValidLeast JET_qoaOperation
+#define JET_qoaValidMost JET_qoaOrdering
+
+
+ /* Query object options */
+
+#define JET_bitFqoOutputAllCols 0x0001
+#define JET_bitFqoRemoveDups 0x0002
+#define JET_bitFqoOwnerAccess 0x0004
+#define JET_bitFqoDistinctRow 0x0008
+#define JET_bitFqoTop 0x0010
+#define JET_bitFqoPercent 0x0020
+#define JET_bitFqoCorresponding 0x0040 /* JET_qopSetOperation */
+
+ /* Query object join type */
+
+#define JET_fjoinInner 1
+#define JET_fjoinLeftOuter 2
+#define JET_fjoinRightOuter 3
+
+ /* Query object operations */
+
+#define JET_qopSelect 1
+#define JET_qopSelectInto 2
+#define JET_qopInsertSelection 3
+#define JET_qopUpdate 4
+#define JET_qopDelete 5
+#define JET_qopTransform 6
+#define JET_qopDDL 7
+#define JET_qopSqlPassThrough 8
+#define JET_qopSetOperation 9
+#define JET_qopSPTBulk 10
+
+#define JET_bitqopSelect 0x0000
+#define JET_bitqopTransform 0x0010
+#define JET_bitqopDelete 0x0020
+#define JET_bitqopUpdate 0x0030
+#define JET_bitqopInsertSelection 0x0040
+#define JET_bitqopSelectInto 0x0050
+#define JET_bitqopDDL 0x0060
+#define JET_bitqopSqlPassThrough 0x0070
+#define JET_bitqopSetOperation 0x0080
+#define JET_bitqopSPTBulk 0x0090
+
+ /* Engine Object Types */
+
+#define JET_objtypNil 0
+#define JET_objtypTable 1
+#define JET_objtypDb 2
+#define JET_objtypContainer 3
+#define JET_objtypSQLLink 4
+#define JET_objtypQuery 5
+#define JET_objtypLink 6
+#define JET_objtypTemplate 7
+#define JET_objtypRelationship 8
+
+ /* All types less than JET_objtypClientMin are reserved by JET */
+
+#define JET_objtypClientMin 0x8000
+
+ /* Security Constant Values */
+
+#define JET_cchUserNameMax 20
+#define JET_cchPasswordMax 14
+
+ /* Security Access Masks */
+
+#define JET_acmNoAccess 0x00000000L
+#define JET_acmFullAccess 0x000FFFFFL
+
+#define JET_acmSpecificMask 0x0000FFFFL
+#define JET_acmSpecific_1 0x00000001L
+#define JET_acmSpecific_2 0x00000002L
+#define JET_acmSpecific_3 0x00000004L
+#define JET_acmSpecific_4 0x00000008L
+#define JET_acmSpecific_5 0x00000010L
+#define JET_acmSpecific_6 0x00000020L
+#define JET_acmSpecific_7 0x00000040L
+#define JET_acmSpecific_8 0x00000080L
+#define JET_acmSpecific_9 0x00000100L
+#define JET_acmSpecific_10 0x00000200L
+#define JET_acmSpecific_11 0x00000400L
+#define JET_acmSpecific_12 0x00000800L
+#define JET_acmSpecific_13 0x00001000L
+#define JET_acmSpecific_14 0x00002000L
+#define JET_acmSpecific_15 0x00004000L
+#define JET_acmSpecific_16 0x00008000L
+
+#define JET_acmStandardMask 0x00FF0000L
+#define JET_acmDelete 0x00010000L
+#define JET_acmReadControl 0x00020000L
+#define JET_acmWriteDac 0x00040000L
+#define JET_acmWriteOwner 0x00080000L
+
+#define JET_acmTblCreate (JET_acmSpecific_1)
+#define JET_acmTblAccessRcols (JET_acmSpecific_2)
+#define JET_acmTblReadDef (JET_acmSpecific_3)
+#define JET_acmTblWriteDef (JET_acmSpecific_4)
+#define JET_acmTblRetrieveData (JET_acmSpecific_5)
+#define JET_acmTblInsertData (JET_acmSpecific_6)
+#define JET_acmTblReplaceData (JET_acmSpecific_7)
+#define JET_acmTblDeleteData (JET_acmSpecific_8)
+
+#define JET_acmDbCreate (JET_acmSpecific_1)
+#define JET_acmDbOpen (JET_acmSpecific_2)
+
+ /* Compact Options */
+
+#define JET_bitCompactDontCopyLocale 0x00000004 /* Don't copy locale from source to dest */
+#define JET_bitCompactVersion10 0x00000008 /* Destination is version 1.0 format */
+#define JET_bitCompactVersion1x 0x00000010 /* Destination is version 1.x format */
+#define JET_bitCompactStats 0x00000020 /* Dump off-line compaction stats (only when progress meter also specified) */
+
+ /* On-line Compact Options */
+
+#define JET_bitCompactOn 0x00000001 /* enable on-line compaction */
+
+ /* Repair Notification Types */
+
+#define JET_rntSelfContained 0
+#define JET_rntDeletedIndex 1
+#define JET_rntDeletedRec 2
+#define JET_rntDeletedLv 3
+#define JET_rntTruncated 4
+
+ /* Status Notification Processes */
+
+#define JET_snpIndex 0
+#define JET_snpQuery 1
+#define JET_snpRepair 2
+#define JET_snpImex 3
+#define JET_snpCompact 4
+#define JET_snpFastFind 5
+#define JET_snpODBCNotReady 6
+#define JET_snpQuerySort 7
+#define JET_snpRestore 8
+#define JET_snpBackup 9
+#define JET_snpUpgrade 10
+
+ /* Status Notification Types */
+
+#define JET_sntProgress 0 /* callback for progress */
+#define JET_sntMessage 1
+#define JET_sntBulkRecords 2 /* callback for # rec for bulk op */
+#define JET_sntFail 3 /* callback for failure during progress */
+#define JET_sntErrCount 4 /* callback for err count */
+#define JET_sntBegin 5 /* callback for beginning of operation */
+#define JET_sntComplete 6 /* callback for completion of operation */
+#define JET_sntCantRollback 7 /* callback for no rollback */
+#define JET_sntRestoreMap 8 /* callback for restore map */
+
+ /* Message codes for JET_snpCompact */
+
+#define JET_sncCopyObject 0 /* Starting to copy object */
+#define JET_sncCopyFailed 1 /* Copy of this object failed */
+#define JET_sncYield 2 /* Client can yield/check for user interrupt */
+#define JET_sncTransactionFull 3 /* Client can yield/check for user interrupt */
+#define JET_sncAboutToWrap 4 /* Find find is about to wrap */
+
+ /* Message codes for JET_snpODBCNotReady */
+
+#define JET_sncODBCNotReady 0 /* Waiting for results from ODBC */
+
+
+ /* Constants for the [ODBC] section of JET.INI */
+
+#define JET_SQLTraceCanonical 0x0001 /* Output ODBC Generic SQL */
+
+ /* Constants for the [Debug] section of JET.INI */
+
+ /* APITrace */
+
+#define JET_APITraceEnter 0x0001
+#define JET_APITraceExit 0x0002
+#define JET_APITraceExitError 0x0004
+#define JET_APIBreakOnError 0x0008
+#define JET_APITraceCount 0x0010
+#define JET_APITraceNoIdle 0x0020
+#define JET_APITraceParameters 0x0040
+
+ /* IdleTrace */
+
+#define JET_IdleTraceCursor 0x0001
+#define JET_IdleTraceBuffer 0x0002
+#define JET_IdleTraceFlush 0x0004
+
+ /* AssertAction */
+
+#define JET_AssertExit 0x0000 /* Exit the application */
+#define JET_AssertBreak 0x0001 /* Break to debugger */
+#define JET_AssertMsgBox 0x0002 /* Display message box */
+#define JET_AssertStop 0x0004 /* Alert and stop */
+
+ /* IOTrace */
+
+#define JET_IOTraceAlloc 0x0001 /* DB Page Allocation */
+#define JET_IOTraceFree 0x0002 /* DB Page Free */
+#define JET_IOTraceRead 0x0004 /* DB Page Read */
+#define JET_IOTraceWrite 0x0008 /* DB Page Write */
+#define JET_IOTraceError 0x0010 /* DB Page I/O Error */
+
+ /* MemTrace */
+
+#define JET_MemTraceAlloc 0x0001 /* Memory allocation */
+#define JET_MemTraceRealloc 0x0002 /* Memory reallocation */
+#define JET_MemTraceFree 0x0004 /* Memory free */
+
+ /* RmtTrace */
+
+#define JET_RmtTraceError 0x0001 /* Remote server error message */
+#define JET_RmtTraceSql 0x0002 /* Remote SQL Prepares & Exec's */
+#define JET_RmtTraceAPI 0x0004 /* Remote ODBC API calls */
+#define JET_RmtTraceODBC 0x0008
+#define JET_RmtSyncODBC 0x0010 /* Turn on ODBC Sync mode */
+
+/**********************************************************************/
+/*********************** ERROR CODES **************************/
+/**********************************************************************/
+
+/* SUCCESS */
+
+#define JET_errSuccess 0 /* Successful Operation */
+
+/* ERRORS */
+
+#define JET_wrnNyi -1 /* Function Not Yet Implemented */
+
+/* SYSTEM errors
+/**/
+#define JET_errRfsFailure -100 /* JET_errRfsFailure */
+#define JET_errRfsNotArmed -101 /* JET_errRfsFailure */
+#define JET_errFileClose -102 /* Could not close DOS file */
+#define JET_errOutOfThreads -103 /* Could not start thread */
+#define JET_errTooManyIO -105 /* System busy due to too many IOs */
+#define JET_errDatabase200Format -106 /* 200 format database */
+#define JET_errDatabase400Format -107 /* 400 format database */
+
+/* BUFFER MANAGER errors
+/**/
+#define wrnBFNotSynchronous 200 /* Buffer page evicted */
+#define wrnBFPageNotFound 201 /* Page not found */
+#define errBFInUse -202 /* Cannot abandon buffer */
+#define wrnBFNewIO 203 /* Buffer access caused a new IO (cache miss) */
+#define wrnBFCacheMiss 204 /* Buffer access was a cache miss but didn't cause a new IO */
+#define wrnBFNoBufAvailable 205 /* Need to allocate new buffer for read (used in Async IO ) */
+
+/* DIRECTORY MANAGER errors
+/**/
+#define errPMOutOfPageSpace -300 /* Out of page space */
+#define errPMItagTooBig -301 /* Itag too big */
+#define errPMRecDeleted -302 /* Record deleted */
+#define errPMTagsUsedUp -303 /* Tags used up */
+#define wrnBMConflict 304 /* conflict in BM Clean up */
+#define errDIRNoShortCircuit -305 /* No Short Circuit Avail */
+#define errDIRCannotSplit -306 /* Cannot horizontally split FDP */
+#define errDIRTop -307 /* Cannot go up */
+#define errDIRFDP 308 /* On an FDP Node */
+#define errDIRNotSynchronous -309 /* May have left critical section */
+#define wrnDIREmptyPage 310 /* Moved through empty page */
+#define errSPConflict -311 /* Device extent being extended */
+#define wrnNDFoundLess 312 /* Found Less */
+#define wrnNDFoundGreater 313 /* Found Greater */
+#define errNDOutSonRange -314 /* Son out of range */
+#define errNDOutItemRange -315 /* Item out of range */
+#define errNDGreaterThanAllItems -316 /* Greater than all items */
+#define errNDLastItemNode -317 /* Last node of item list */
+#define errNDFirstItemNode -318 /* First node of item list */
+#define wrnNDDuplicateItem 319 /* Duplicated Item */
+#define errNDNoItem -320 /* Item not there */
+#define JET_wrnRemainingVersions 321 /* Some versions couldn't be cleaned */
+#define JET_wrnPreviousVersion 322 /* Version already existed */
+#define JET_errPageBoundary -323 /* Reached Page Boundary */
+#define JET_errKeyBoundary -324 /* Reached Key Boundary */
+#define errDIRInPageFather -325 /* sridFather in page to free */
+#define errBMMaxKeyInPage -326 /* used by OLC to avoid cleanup of parent pages */
+#define JET_errBadPageLink -327 /* next/previous page link page does not point back to source */
+#define JET_errBadBookmark -328 /* bookmark has no corresponding address in database */
+#define wrnBMCleanNullOp 329 /* BMClean returns this on encountering a page
+ /* deleted MaxKeyInPage [but there was no conflict]
+
+/* RECORD MANAGER errors
+/**/
+#define wrnFLDKeyTooBig 400 /* Key too big (truncated it) */
+#define errFLDTooManySegments -401 /* Too many key segments */
+#define wrnFLDNullKey 402 /* Key is entirely NULL */
+#define wrnFLDOutOfKeys 403 /* No more keys to extract */
+#define wrnFLDNullSeg 404 /* Null segment in key */
+#define wrnRECLongField 405 /* Separated long value */
+#define JET_wrnSeparateLongValue 406 /* Separated long value */
+#define JET_wrnRecordFoundGreater JET_wrnSeekNotEqual
+#define JET_wrnRecordFoundLess JET_wrnSeekNotEqual
+#define JET_errColumnIllegalNull JET_errNullInvalid
+#define wrnFLDNullFirstSeg 407 /* Null first segment in key */
+#define JET_errKeyTooBig -408 /* Key with column truncation still truncated */
+
+/* LOGGING/RECOVERY errors
+/**/
+#define JET_errInvalidLoggedOperation -500 /* Logged operation cannot be redone */
+#define JET_errLogFileCorrupt -501 /* Log file is corrupt */
+#define errLGNoMoreRecords -502 /* Last log record read */
+#define JET_errNoBackupDirectory -503 /* No backup directory given */
+#define JET_errBackupDirectoryNotEmpty -504 /* The backup directory is not emtpy */
+#define JET_errBackupInProgress -505 /* Backup is active already */
+#define JET_errMissingPreviousLogFile -509 /* Missing the log file for check point */
+#define JET_errLogWriteFail -510 /* Fail when writing to log file */
+#define JET_errBadLogVersion -514 /* Version of log file is not compatible with Jet version */
+#define JET_errInvalidLogSequence -515 /* Timestamp in next log does not match expected */
+#define JET_errLoggingDisabled -516 /* Log is not active */
+#define JET_errLogBufferTooSmall -517 /* Log buffer is too small for recovery */
+#define errLGNotSynchronous -518 /* retry to LGLogRec */
+#define JET_errLogSequenceEnd -519 /* Exceed maximum log file number */
+#define JET_errNoBackup -520 /* No backup in progress */
+#define JET_errInvalidBackupSequence -521 /* Backup call out of sequence */
+#define JET_errBackupNotAllowedYet -523 /* Can not do backup now */
+#define JET_errDeleteBackupFileFail -524 /* Could not delete backup file */
+#define JET_errMakeBackupDirectoryFail -525 /* Could not make backup temp directory */
+#define JET_errInvalidBackup -526 /* Cannot incremental backup when circular logging enabled */
+#define JET_errRecoveredWithErrors -527 /* For repair, restored with errors */
+#define JET_errMissingLogFile -528 /* current log file missing */
+#define JET_errLogDiskFull -529 /* log disk full */
+#define JET_errBadLogSignature -530 /* bad signature for a log file */
+#define JET_errBadDbSignature -531 /* bad signature for a db file */
+#define JET_errBadCheckpointSignature -532 /* bad signature for a checkpoint file */
+#define JET_errCheckpointCorrupt -533 /* checkpoint file not found or corrupt */
+#define JET_errMissingPatchPage -534 /* patch file page not found during recovery */
+
+
+#define JET_errDatabaseInconsistent -550 /* database is in inconsistent state */
+#define JET_errConsistentTimeMismatch -551 /* database last consistent time unmatched */
+#define JET_errDatabasePatchFileMismatch -552 /* patch file is not generated from this backup */
+#define JET_errEndingRestoreLogTooLow -553 /* the starting log number too low for the restore */
+#define JET_errStartingRestoreLogTooHigh -554 /* the starting log number too high for the restore */
+#define JET_errGivenLogFileHasBadSignature -555 /* Restore log file has bad signature */
+#define JET_errGivenLogFileIsNotContiguous -556 /* Restore log file is not contiguous */
+#define JET_errMissingRestoreLogFiles -557 /* Some restore log files are missing */
+#define JET_wrnExistingLogFileHasBadSignature 558 /* Existing log file has bad signature */
+#define JET_wrnExistingLogFileIsNotContiguous 559 /* Existing log file is not contiguous */
+#define JET_errMissingFullBackup -560 /* The database miss a previous full backup befor incremental backup */
+#define JET_errBadBackupDatabaseSize -561 /* The backup database size is not in 4k */
+#define JET_errDatabaseAlreadyUpgraded -562 /* Attempted to upgrade a database that is already current */
+
+#define JET_errTermInProgress -1000 /* Termination in progress */
+#define JET_errFeatureNotAvailable -1001 /* API not supported */
+#define JET_errInvalidName -1002 /* Invalid name */
+#define JET_errInvalidParameter -1003 /* Invalid API parameter */
+#define JET_wrnColumnNull 1004 /* Column is NULL-valued */
+#define JET_wrnBufferTruncated 1006 /* Buffer too small for data */
+#define JET_wrnDatabaseAttached 1007 /* Database is already attached */
+#define JET_wrnSortOverflow 1009 /* Sort does not fit in memory */
+#define JET_errInvalidDatabaseId -1010 /* Invalid database id */
+#define JET_errOutOfMemory -1011 /* Out of Memory */
+#define JET_errOutOfDatabaseSpace -1012 /* Maximum database size reached */
+#define JET_errOutOfCursors -1013 /* Out of table cursors */
+#define JET_errOutOfBuffers -1014 /* Out of database page buffers */
+#define JET_errTooManyIndexes -1015 /* Too many indexes */
+#define JET_errTooManyKeys -1016 /* Too many columns in an index */
+#define JET_errRecordDeleted -1017 /* Record has been deleted */
+#define JET_errReadVerifyFailure -1018 /* Read verification error */
+#define JET_errOutOfFileHandles -1020 /* Out of file handles */
+#define JET_errDiskIO -1022 /* Disk IO error */
+#define JET_errInvalidPath -1023 /* Invalid file path */
+#define JET_errRecordTooBig -1026 /* Record larger than maximum size */
+#define JET_errTooManyOpenDatabases -1027 /* Too many open databases */
+#define JET_errInvalidDatabase -1028 /* Not a database file */
+#define JET_errNotInitialized -1029 /* JetInit not yet called */
+#define JET_errAlreadyInitialized -1030 /* JetInit already called */
+#define JET_errFileAccessDenied -1032 /* Cannot access file */
+#define JET_errQueryNotSupported -1034 /* Query support unavailable */
+#define JET_errSQLLinkNotSupported -1035 /* SQL Link support unavailable */
+#define JET_errBufferTooSmall -1038 /* Buffer is too small */
+#define JET_wrnSeekNotEqual 1039 /* SeekLE or SeekGE didn't find exact match */
+#define JET_errTooManyColumns -1040 /* Too many columns defined */
+#define JET_errContainerNotEmpty -1043 /* Container is not empty */
+#define JET_errInvalidFilename -1044 /* Filename is invalid */
+#define JET_errInvalidBookmark -1045 /* Invalid bookmark */
+#define JET_errColumnInUse -1046 /* Column used in an index */
+#define JET_errInvalidBufferSize -1047 /* Data buffer doesn't match column size */
+#define JET_errColumnNotUpdatable -1048 /* Cannot set column value */
+#define JET_errIndexInUse -1051 /* Index is in use */
+#define JET_errLinkNotSupported -1052 /* Link support unavailable */
+#define JET_errNullKeyDisallowed -1053 /* Null keys are disallowed on index */
+#define JET_errNotInTransaction -1054 /* Operation must be within a transaction */
+#define JET_wrnNoErrorInfo 1055 /* No extended error information */
+#define JET_wrnNoIdleActivity 1058 /* No idle activity occured */
+#define JET_errTooManyActiveUsers -1059 /* Too many active database users */
+#define JET_errInvalidAppend -1060 /* Cannot append long value */
+#define JET_errInvalidCountry -1061 /* Invalid or unknown country code */
+#define JET_errInvalidLanguageId -1062 /* Invalid or unknown language id */
+#define JET_errInvalidCodePage -1063 /* Invalid or unknown code page */
+#define JET_wrnNoWriteLock 1067 /* No write lock at transaction level 0 */
+#define JET_wrnColumnSetNull 1068 /* Column set to NULL-value */
+#define JET_errVersionStoreOutOfMemory -1069 /* lMaxVerPages exceeded (XJET only) */
+#define JET_errCurrencyStackOutOfMemory -1070 /* lCSRPerfFUCB * lMaxCursors exceeded (XJET only) */
+#define JET_errOutOfSessions -1101 /* Out of sessions */
+#define JET_errWriteConflict -1102 /* Write lock failed due to outstanding write lock */
+#define JET_errTransTooDeep -1103 /* Xactions nested too deeply */
+#define JET_errInvalidSesid -1104 /* Invalid session handle */
+#define JET_errSessionWriteConflict -1107 /* Another session has private version of page */
+#define JET_errInTransaction -1108 /* Operation not allowed within a transaction */
+#define JET_errDatabaseDuplicate -1201 /* Database already exists */
+#define JET_errDatabaseInUse -1202 /* Database in use */
+#define JET_errDatabaseNotFound -1203 /* No such database */
+#define JET_errDatabaseInvalidName -1204 /* Invalid database name */
+#define JET_errDatabaseInvalidPages -1205 /* Invalid number of pages */
+#define JET_errDatabaseCorrupted -1206 /* non-db file or corrupted db */
+#define JET_errDatabaseLocked -1207 /* Database exclusively locked */
+#define JET_errCannotDisableVersioning -1208 /* Cannot disable versioning for this database */
+#define JET_wrnTableEmpty 1301 /* Open an empty table */
+#define JET_errTableLocked -1302 /* Table is exclusively locked */
+#define JET_errTableDuplicate -1303 /* Table already exists */
+#define JET_errTableInUse -1304 /* Table is in use, cannot lock */
+#define JET_errObjectNotFound -1305 /* No such table or object */
+#define JET_errDensityInvalid -1307 /* Bad file/index density */
+#define JET_errTableNotEmpty -1308 /* Cannot define clustered index */
+#define JET_errInvalidTableId -1310 /* Invalid table id */
+#define JET_errTooManyOpenTables -1311 /* Cannot open any more tables */
+#define JET_errIllegalOperation -1312 /* Oper. not supported on table */
+#define JET_errObjectDuplicate -1314 /* Table or object name in use */
+#define JET_errInvalidObject -1316 /* object is invalid for operation */
+#define JET_errIndexCantBuild -1401 /* Cannot build clustered index */
+#define JET_errIndexHasPrimary -1402 /* Primary index already defined */
+#define JET_errIndexDuplicate -1403 /* Index is already defined */
+#define JET_errIndexNotFound -1404 /* No such index */
+#define JET_errIndexMustStay -1405 /* Cannot delete clustered index */
+#define JET_errIndexInvalidDef -1406 /* Illegal index definition */
+#define JET_errIndexHasClustered -1408 /* Clustered index already defined */
+#define JET_errInvalidCreateIndex -1409 /* Invali create index description */
+#define JET_errTooManyOpenIndexes -1410 /* Out of index description blocks */
+#define JET_errColumnLong -1501 /* Column value is long */
+#define JET_errColumnNoChunk -1502 /* no such chunk in long value */
+#define JET_errColumnDoesNotFit -1503 /* Field will not fit in record */
+#define JET_errNullInvalid -1504 /* Null not valid */
+#define JET_errColumnIndexed -1505 /* Column indexed, cannot delete */
+#define JET_errColumnTooBig -1506 /* Field length is > maximum */
+#define JET_errColumnNotFound -1507 /* No such column */
+#define JET_errColumnDuplicate -1508 /* Field is already defined */
+#define JET_errColumn2ndSysMaint -1510 /* Second autoinc or version column */
+#define JET_errInvalidColumnType -1511 /* Invalid column data type */
+#define JET_wrnColumnMaxTruncated 1512 /* Max length too big, truncated */
+#define JET_errColumnCannotIndex -1513 /* Cannot index Bit,LongText,LongBinary */
+#define JET_errTaggedNotNULL -1514 /* No non-NULL tagged columns */
+#define JET_errNoCurrentIndex -1515 /* Invalid w/o a current index */
+#define JET_errKeyIsMade -1516 /* The key is completely made */
+#define JET_errBadColumnId -1517 /* Column Id Incorrect */
+#define JET_errBadItagSequence -1518 /* Bad itagSequence for tagged column */
+#define JET_errColumnInRelationship -1519 /* Cannot delete, column participates in relationship */
+#define JET_wrnCopyLongValue 1520 /* Single instance column bursted */
+#define JET_errCannotBeTagged -1521 /* AutoIncrement and Version cannot be tagged */
+#define JET_errRecordNotFound -1601 /* The key was not found */
+#define JET_errRecordNoCopy -1602 /* No working buffer */
+#define JET_errNoCurrentRecord -1603 /* Currency not on a record */
+#define JET_errRecordClusteredChanged -1604 /* Clustered key may not change */
+#define JET_errKeyDuplicate -1605 /* Illegal duplicate key */
+#define JET_errAlreadyPrepared -1607 /* Already copy/clear current */
+#define JET_errKeyNotMade -1608 /* No call to JetMakeKey */
+#define JET_errUpdateNotPrepared -1609 /* No call to JetPrepareUpdate */
+#define JET_wrnDataHasChanged 1610 /* Data has changed */
+#define JET_errDataHasChanged -1611 /* Data has changed, operation aborted */
+#define JET_wrnKeyChanged 1618 /* Moved to new key */
+#define JET_errTooManySorts -1701 /* Too many sort processes */
+#define JET_errInvalidOnSort -1702 /* Invalid operation on Sort */
+#define JET_errTempFileOpenError -1803 /* Temp file could not be opened */
+#define JET_errTooManyAttachedDatabases -1805 /* Too many open databases */
+#define JET_errDiskFull -1808 /* No space left on disk */
+#define JET_errPermissionDenied -1809 /* Permission denied */
+#define JET_errFileNotFound -1811 /* File not found */
+#define JET_wrnFileOpenReadOnly 1813 /* Database file is read only */
+#define JET_errAfterInitialization -1850 /* Cannot Restore after init. */
+#define JET_errLogCorrupted -1852 /* Logs could not be interpreted */
+#define JET_errInvalidOperation -1906 /* invalid operation */
+#define JET_errAccessDenied -1907 /* access denied */
+#define JET_wrnIdleFull 1908 /* ilde registry full */
+
+
+/**********************************************************************/
+/*********************** PROTOTYPES **************************/
+/**********************************************************************/
+
+#if !defined(_JET_NOPROTOTYPES)
+
+JET_ERR JET_API JetInit(JET_INSTANCE *pinstance);
+
+JET_ERR JET_API JetTerm(JET_INSTANCE instance);
+
+JET_ERR JET_API JetTerm2( JET_INSTANCE instance, JET_GRBIT grbit );
+
+JET_ERR JET_API JetSetSystemParameter(JET_INSTANCE *pinstance, JET_SESID sesid, unsigned long paramid,
+ unsigned long lParam, const char *sz);
+
+JET_ERR JET_API JetGetSystemParameter(JET_INSTANCE instance, JET_SESID sesid, unsigned long paramid,
+ unsigned long *plParam, char *sz, unsigned long cbMax);
+
+#define ctAccessPage 1
+#define ctLatchConflict 2
+#define ctSplitRetry 3
+#define ctNeighborPageScanned 4
+#define ctSplits 5
+JET_ERR JET_API JetResetCounter( JET_SESID sesid, long CounterType );
+JET_ERR JET_API JetGetCounter( JET_SESID sesid, long CounterType, long *plValue );
+
+JET_ERR JET_API JetBeginSession(JET_INSTANCE instance, JET_SESID *psesid,
+ const char *szUserName, const char *szPassword);
+
+JET_ERR JET_API JetDupSession(JET_SESID sesid, JET_SESID *psesid);
+
+JET_ERR JET_API JetEndSession(JET_SESID sesid, JET_GRBIT grbit);
+
+JET_ERR JET_API JetGetVersion(JET_SESID sesid, unsigned long *pwVersion);
+
+JET_ERR JET_API JetIdle(JET_SESID sesid, JET_GRBIT grbit);
+
+JET_ERR JET_API JetCreateDatabase(JET_SESID sesid,
+ const char *szFilename, const char *szConnect,
+ JET_DBID *pdbid, JET_GRBIT grbit);
+
+JET_ERR JET_API JetAttachDatabase(JET_SESID sesid, const char *szFilename, JET_GRBIT grbit );
+
+JET_ERR JET_API JetDetachDatabase(JET_SESID sesid, const char *szFilename);
+
+JET_ERR JET_API JetCreateTable(JET_SESID sesid, JET_DBID dbid,
+ const char *szTableName, unsigned long lPages, unsigned long lDensity,
+ JET_TABLEID *ptableid);
+
+JET_ERR JET_API JetCreateTableColumnIndex( JET_SESID sesid, JET_DBID dbid,
+ JET_TABLECREATE *ptablecreate );
+
+JET_ERR JET_API JetDeleteTable(JET_SESID sesid, JET_DBID dbid,
+ const char *szTableName);
+
+JET_ERR JET_API JetGetTableColumnInfo(JET_SESID sesid, JET_TABLEID tableid,
+ const char *szColumnName, void *pvResult, unsigned long cbMax,
+ unsigned long InfoLevel);
+
+JET_ERR JET_API JetGetColumnInfo(JET_SESID sesid, JET_DBID dbid,
+ const char *szTableName, const char *szColumnName,
+ void *pvResult, unsigned long cbMax, unsigned long InfoLevel);
+
+JET_ERR JET_API JetAddColumn(JET_SESID sesid, JET_TABLEID tableid,
+ const char *szColumn, const JET_COLUMNDEF *pcolumndef,
+ const void *pvDefault, unsigned long cbDefault,
+ JET_COLUMNID *pcolumnid);
+
+JET_ERR JET_API JetDeleteColumn(JET_SESID sesid, JET_TABLEID tableid,
+ const char *szColumn);
+
+JET_ERR JET_API JetGetTableIndexInfo(JET_SESID sesid, JET_TABLEID tableid,
+ const char *szIndexName, void *pvResult, unsigned long cbResult,
+ unsigned long InfoLevel);
+
+JET_ERR JET_API JetGetTableInfo(JET_SESID sesid, JET_TABLEID tableid,
+ void *pvResult, unsigned long cbMax, unsigned long InfoLevel);
+
+JET_ERR JET_API JetGetIndexInfo(JET_SESID sesid, JET_DBID dbid,
+ const char *szTableName, const char *szIndexName,
+ void *pvResult, unsigned long cbResult, unsigned long InfoLevel);
+
+JET_ERR JET_API JetCreateIndex(JET_SESID sesid, JET_TABLEID tableid,
+ const char *szIndexName, JET_GRBIT grbit,
+ const char *szKey, unsigned long cbKey, unsigned long lDensity);
+
+JET_ERR JET_API JetDeleteIndex(JET_SESID sesid, JET_TABLEID tableid,
+ const char *szIndexName);
+
+JET_ERR JET_API JetGetObjectInfo(JET_SESID sesid, JET_DBID dbid,
+ JET_OBJTYP objtyp, const char *szContainerName,
+ const char *szObjectName, void *pvResult, unsigned long cbMax,
+ unsigned long InfoLevel);
+
+JET_ERR JET_API JetBeginTransaction(JET_SESID sesid);
+
+JET_ERR JET_API JetCommitTransaction(JET_SESID sesid, JET_GRBIT grbit);
+
+JET_ERR JET_API JetRollback(JET_SESID sesid, JET_GRBIT grbit);
+
+JET_ERR JET_API JetGetDatabaseInfo(JET_SESID sesid, JET_DBID dbid,
+ void *pvResult, unsigned long cbMax, unsigned long InfoLevel);
+
+JET_ERR JET_API JetCloseDatabase(JET_SESID sesid, JET_DBID dbid,
+ JET_GRBIT grbit);
+
+JET_ERR JET_API JetCloseTable(JET_SESID sesid, JET_TABLEID tableid);
+
+JET_ERR JET_API JetOpenDatabase(JET_SESID sesid, const char *szFilename,
+ const char *szConnect, JET_DBID *pdbid, JET_GRBIT grbit);
+
+JET_ERR JET_API JetOpenTable(JET_SESID sesid, JET_DBID dbid,
+ const char *szTableName, const void *pvParameters,
+ unsigned long cbParameters, JET_GRBIT grbit, JET_TABLEID *ptableid);
+
+JET_ERR JET_API JetDelete(JET_SESID sesid, JET_TABLEID tableid);
+
+JET_ERR JET_API JetUpdate(JET_SESID sesid, JET_TABLEID tableid,
+ void *pvBookmark, unsigned long cbBookmark,
+ unsigned long *pcbActual);
+
+JET_ERR JET_API JetRetrieveColumn(JET_SESID sesid, JET_TABLEID tableid,
+ JET_COLUMNID columnid, void *pvData, unsigned long cbData,
+ unsigned long *pcbActual, JET_GRBIT grbit, JET_RETINFO *pretinfo);
+
+JET_ERR JET_API JetRetrieveColumns( JET_SESID sesid, JET_TABLEID tableid,
+ JET_RETRIEVECOLUMN *pretrievecolumn, unsigned long cretrievecolumn );
+
+JET_ERR JET_API JetSetColumn(JET_SESID sesid, JET_TABLEID tableid,
+ JET_COLUMNID columnid, const void *pvData, unsigned long cbData,
+ JET_GRBIT grbit, JET_SETINFO *psetinfo);
+
+JET_ERR JET_API JetSetColumns(JET_SESID sesid, JET_TABLEID tableid,
+ JET_SETCOLUMN *psetcolumn, unsigned long csetcolumn );
+
+JET_ERR JET_API JetPrepareUpdate(JET_SESID sesid, JET_TABLEID tableid,
+ unsigned long prep);
+
+JET_ERR JET_API JetGetRecordPosition(JET_SESID sesid, JET_TABLEID tableid,
+ JET_RECPOS *precpos, unsigned long cbRecpos);
+
+JET_ERR JET_API JetGotoPosition(JET_SESID sesid, JET_TABLEID tableid,
+ JET_RECPOS *precpos );
+
+JET_ERR JET_API JetGetCursorInfo(JET_SESID sesid, JET_TABLEID tableid,
+ void *pvResult, unsigned long cbMax, unsigned long InfoLevel);
+
+JET_ERR JET_API JetDupCursor(JET_SESID sesid, JET_TABLEID tableid,
+ JET_TABLEID *ptableid, JET_GRBIT grbit);
+
+JET_ERR JET_API JetGetCurrentIndex(JET_SESID sesid, JET_TABLEID tableid,
+ char *szIndexName, unsigned long cchIndexName);
+
+JET_ERR JET_API JetSetCurrentIndex(JET_SESID sesid, JET_TABLEID tableid,
+ const char *szIndexName);
+
+JET_ERR JET_API JetSetCurrentIndex2(JET_SESID sesid, JET_TABLEID tableid,
+ const char *szIndexName, JET_GRBIT grbit );
+
+JET_ERR JET_API JetMove(JET_SESID sesid, JET_TABLEID tableid,
+ long cRow, JET_GRBIT grbit);
+
+JET_ERR JET_API JetMakeKey(JET_SESID sesid, JET_TABLEID tableid,
+ const void *pvData, unsigned long cbData, JET_GRBIT grbit);
+
+JET_ERR JET_API JetSeek(JET_SESID sesid, JET_TABLEID tableid,
+ JET_GRBIT grbit);
+
+JET_ERR JET_API JetGetBookmark(JET_SESID sesid, JET_TABLEID tableid,
+ void *pvBookmark, unsigned long cbMax,
+ unsigned long *pcbActual);
+
+JET_ERR JET_API JetCompact(JET_SESID sesid, const char *szDatabaseSrc,
+ const char *szDatabaseDest, JET_PFNSTATUS pfnStatus, JET_CONVERT *pconvert,
+ JET_GRBIT grbit);
+
+JET_ERR JET_API JetDBUtilities( JET_DBUTIL *pdbutil );
+
+JET_ERR JET_API JetGotoBookmark(JET_SESID sesid, JET_TABLEID tableid,
+ void *pvBookmark, unsigned long cbBookmark);
+
+JET_ERR JET_API JetComputeStats(JET_SESID sesid, JET_TABLEID tableid);
+
+typedef unsigned long JET_VSESID; /* Received from dispatcher */
+
+struct tagVDBFNDEF;
+
+typedef unsigned long JET_VDBID; /* Received from dispatcher */
+
+struct tagVTFNDEF;
+
+typedef unsigned long JET_VTID; /* Received from dispatcher */
+
+JET_ERR JET_API JetOpenTempTable(JET_SESID sesid,
+ const JET_COLUMNDEF *prgcolumndef, unsigned long ccolumn,
+ JET_GRBIT grbit, JET_TABLEID *ptableid,
+ JET_COLUMNID *prgcolumnid);
+
+JET_ERR JET_API JetOpenTempTable2( JET_SESID sesid,
+ const JET_COLUMNDEF *prgcolumndef,
+ unsigned long ccolumn,
+ unsigned long langid,
+ JET_GRBIT grbit,
+ JET_TABLEID *ptableid,
+ JET_COLUMNID *prgcolumnid );
+
+JET_ERR JET_API JetBackup( const char *szBackupPath, JET_GRBIT grbit, JET_PFNSTATUS pfnStatus );
+
+JET_ERR JET_API JetRestore(const char *sz, JET_PFNSTATUS pfn );
+JET_ERR JET_API JetRestore2(const char *sz, const char *szDest, JET_PFNSTATUS pfn );
+
+JET_ERR JET_API JetSetIndexRange(JET_SESID sesid,
+ JET_TABLEID tableidSrc, JET_GRBIT grbit);
+
+JET_ERR JET_API JetIndexRecordCount(JET_SESID sesid,
+ JET_TABLEID tableid, unsigned long *pcrec, unsigned long crecMax );
+
+JET_ERR JET_API JetRetrieveKey(JET_SESID sesid,
+ JET_TABLEID tableid, void *pvData, unsigned long cbMax,
+ unsigned long *pcbActual, JET_GRBIT grbit );
+
+JET_ERR JET_API JetBeginExternalBackup( JET_GRBIT grbit );
+
+JET_ERR JET_API JetGetAttachInfo( void *pv,
+ unsigned long cbMax,
+ unsigned long *pcbActual );
+
+JET_ERR JET_API JetOpenFile( const char *szFileName,
+ JET_HANDLE *phfFile,
+ unsigned long *pulFileSizeLow,
+ unsigned long *pulFileSizeHigh );
+
+JET_ERR JET_API JetReadFile( JET_HANDLE hfFile,
+ void *pv,
+ unsigned long cb,
+ unsigned long *pcb );
+
+JET_ERR JET_API JetCloseFile( JET_HANDLE hfFile );
+
+JET_ERR JET_API JetGetLogInfo( void *pv,
+ unsigned long cbMax,
+ unsigned long *pcbActual );
+
+JET_ERR JET_API JetTruncateLog( void );
+
+JET_ERR JET_API JetEndExternalBackup( void );
+
+JET_ERR JET_API JetExternalRestore( char *szCheckpointFilePath, char *szLogPath, JET_RSTMAP *rgstmap, long crstfilemap, char *szBackupLogPath, long genLow, long genHigh, JET_PFNSTATUS pfn );
+
+#endif /* _JET_NOPROTOTYPES */
+
+#pragma pack()
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _JET_INCLUDED */
+
+
+
+
diff --git a/private/utils/ntbackup/exchange/inc/jetbcli.h b/private/utils/ntbackup/exchange/inc/jetbcli.h
new file mode 100644
index 000000000..a5703feff
--- /dev/null
+++ b/private/utils/ntbackup/exchange/inc/jetbcli.h
@@ -0,0 +1,407 @@
+/*
+ * EDBBCLI.H
+ *
+ * Microsoft Exchange Information Store
+ * Copyright (C) 1986-1996, Microsoft Corporation
+ *
+ * Contains declarations of additional definitions and interfaces
+ * for the Exchange Online Backup Client APIs.
+ */
+
+#ifndef _EDBBCLI_
+#define _EDBBCLI_
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef MIDL_PASS
+#define RPC_STRING [string]
+#else
+#define RPC_STRING
+typedef unsigned short WCHAR;
+#endif
+
+#define EDBBACK_MDB_SERVER "Exchange MDB Database"
+#define EDBBACK_DS_SERVER "Exchange DS Database"
+
+#ifndef EDBBACK_BUILD
+#define EDBBACK_API __declspec(dllimport) _stdcall
+#else
+#define EDBBACK_API
+#endif
+
+typedef DWORD ERR;
+
+typedef LONG HRESULT;
+typedef LONG C;
+typedef TCHAR BFT;
+
+//
+// Type of backup passed into HrBackupPrepare()
+//
+
+#define BACKUP_TYPE_FULL 0x01
+#define BACKUP_TYPE_LOGS_ONLY 0x02
+
+//
+// Set the current log number to this value to disable incremental or
+// differential backup.
+//
+#define BACKUP_DISABLE_INCREMENTAL 0xffffffff
+
+//
+// Backup/Restore file types
+//
+//
+// Please note that these file types are binary values, even though they are text (or wchar) typed.
+//
+// The code in the backup API's rely on the fact that values 0-256 in 8 bit ascii map to the values 0-256 in unicode.
+//
+
+//
+// If the BFT_DIRECTORY bit is set on the backup file type, it indicates that the path specified is a directory,
+// otherwise it is a file name.
+//
+
+#define BFT_DIRECTORY 0x80
+
+//
+// If the BFT_DATABASE bit is set on the backup file type, it indicates that the file goes into the database directory.
+//
+
+#define BFT_DATABASE_DIRECTORY 0x40
+
+//
+// If the BFT_LOG bit is set on the backup file type, it indicates that the file goes into the log directory.
+//
+
+#define BFT_LOG_DIRECTORY 0x20
+
+//
+// Database logs.
+//
+
+#define BFT_LOG (BFT)(TEXT('\x01') | BFT_LOG_DIRECTORY)
+#define BFT_LOG_DIR (BFT)(TEXT('\x02') | BFT_DIRECTORY)
+
+//
+// Checkpoint file.
+//
+
+#define BFT_CHECKPOINT_DIR (BFT)(TEXT('\x03') | BFT_DIRECTORY)
+
+//
+// Database types.
+//
+#define BFT_MDB_PRIVATE_DATABASE (BFT)(TEXT('\x05') | BFT_DATABASE_DIRECTORY)
+#define BFT_MDB_PUBLIC_DATABASE (BFT)(TEXT('\x06') | BFT_DATABASE_DIRECTORY)
+#define BFT_DSA_DATABASE (BFT)(TEXT('\x07') | BFT_DATABASE_DIRECTORY)
+
+//
+// JET patch files
+//
+//
+//
+
+#define BFT_PATCH_FILE (BFT)(TEXT('\x08') | BFT_LOG_DIRECTORY)
+
+//
+// Catch all for unknown file types.
+//
+
+#define BFT_UNKNOWN (BFT)(TEXT('\x0f'))
+
+#include <edbmsg.h>
+
+typedef void *HBC;
+
+typedef struct tagEDB_RSTMAPA
+{
+ RPC_STRING char *szDatabaseName;
+ RPC_STRING char *szNewDatabaseName;
+} EDB_RSTMAPA, *PEDB_RSTMAPA; /* restore map */
+
+// required for Exchange unicode support.
+// UNDONE: NYI
+#define UNICODE_RSTMAP
+
+typedef struct tagEDB_RSTMAPW {
+ RPC_STRING WCHAR *wszDatabaseName;
+ RPC_STRING WCHAR *wszNewDatabaseName;
+} EDB_RSTMAPW, *PEDB_RSTMAPW;
+
+#ifdef UNICODE
+#define EDB_RSTMAP EDB_RSTMAPW
+#define PEDB_RSTMAP PEDB_RSTMAPW
+#else
+#define EDB_RSTMAP EDB_RSTMAPA
+#define PEDB_RSTMAP PEDB_RSTMAPA
+#endif
+
+
+HRESULT
+EDBBACK_API
+HrBackupPrepareA(
+ IN char * szBackupServer,
+ IN char * szBackupAnnotation,
+ IN unsigned long grbit,
+ IN unsigned long btBackupType,
+ OUT HBC *hbcBackupContext
+ );
+
+HRESULT
+EDBBACK_API
+HrBackupPrepareW(
+ IN WCHAR * wszBackupServer,
+ IN WCHAR * wszBackupAnnotation,
+ IN unsigned long grbit,
+ IN unsigned long btBackupType,
+ OUT HBC *hbcBackupContext
+ );
+
+#ifdef UNICODE
+#define HrBackupPrepare HrBackupPrepareW
+#else
+#define HrBackupPrepare HrBackupPrepareA
+#endif
+
+
+HRESULT
+EDBBACK_API
+HrBackupGetDatabaseNamesA(
+ IN HBC pvBackupContext,
+ OUT LPSTR *ppszAttachmentInformation,
+ OUT LPDWORD pcbSize
+ );
+
+HRESULT
+EDBBACK_API
+HrBackupGetDatabaseNamesW(
+ IN HBC pvBackupContext,
+ OUT LPWSTR *ppszAttachmentInformation,
+ OUT LPDWORD pcbSize
+ );
+
+#ifdef UNICODE
+#define HrBackupGetDatabaseNames HrBackupGetDatabaseNamesW
+#else
+#define HrBackupGetDatabaseNames HrBackupGetDatabaseNamesA
+#endif
+
+HRESULT
+EDBBACK_API
+HrBackupOpenFileW(
+ IN HBC pvBackupContext,
+ IN WCHAR * wszAttachmentName,
+ IN DWORD cbReadHintSize,
+ OUT LARGE_INTEGER *pliFileSize
+ );
+
+HRESULT
+EDBBACK_API
+HrBackupOpenFileA(
+ IN HBC pvBackupContext,
+ IN char * szAttachmentName,
+ IN DWORD cbReadHintSize,
+ OUT LARGE_INTEGER *pliFileSize
+ );
+
+#ifdef UNICODE
+#define HrBackupOpenFile HrBackupOpenFileW
+#else
+#define HrBackupOpenFile HrBackupOpenFileA
+#endif
+
+
+HRESULT
+EDBBACK_API
+HrBackupRead(
+ IN HBC pvBackupContext,
+ IN PVOID pvBuffer,
+ IN DWORD cbBuffer,
+ OUT PDWORD pcbRead
+ );
+
+HRESULT
+EDBBACK_API
+HrBackupClose(
+ IN HBC pvBackupContext
+ );
+
+HRESULT
+EDBBACK_API
+HrBackupGetBackupLogsA(
+ IN HBC pvBackupContext,
+ IN LPSTR *szBackupLogFile,
+ IN PDWORD pcbSize
+ );
+
+HRESULT
+EDBBACK_API
+HrBackupGetBackupLogsW(
+ IN HBC pvBackupContext,
+ IN LPWSTR *szBackupLogFile,
+ IN PDWORD pcbSize
+ );
+
+#ifdef UNICODE
+#define HrBackupGetBackupLogs HrBackupGetBackupLogsW
+#else
+#define HrBackupGetBackupLogs HrBackupGetBackupLogsA
+#endif
+
+HRESULT
+EDBBACK_API
+HrBackupTruncateLogs(
+ IN HBC pvBackupContext
+ );
+
+
+HRESULT
+EDBBACK_API
+HrBackupEnd(
+ IN HBC pvBackupContext
+ );
+
+
+VOID
+EDBBACK_API
+BackupFree(
+ IN PVOID pvBuffer
+ );
+
+
+HRESULT
+EDBBACK_API
+HrRestoreGetDatabaseLocationsA(
+ IN HBC hbcBackupContext,
+ OUT LPSTR *ppszDatabaseLocationList,
+ OUT LPDWORD pcbSize
+ );
+
+HRESULT
+EDBBACK_API
+HrRestoreGetDatabaseLocationsW(
+ IN HBC pvBackupContext,
+ OUT LPWSTR *ppszDatabaseLocationList,
+ OUT LPDWORD pcbSize
+ );
+
+#ifdef UNICODE
+#define HrRestoreGetDatabaseLocations HrRestoreGetDatabaseLocationsW
+#else
+#define HrRestoreGetDatabaseLocations HrRestoreGetDatabaseLocationsA
+#endif
+
+HRESULT
+EDBBACK_API
+HrRestorePrepareA(
+ char * szServerName,
+ char * szServiceAnnotation,
+ HBC *phbcBackupContext
+ );
+
+HRESULT
+EDBBACK_API
+HrRestorePrepareW(
+ WCHAR * szServerName,
+ WCHAR * szServiceAnnotation,
+ HBC *phbcBackupContext
+ );
+
+#ifdef UNICODE
+#define HrRestorePrepare HrRestorePrepareW
+#else
+#define HrRestorePrepare HrRestorePrepareA
+#endif
+
+//
+// HrRestoreRegister will register a restore
+// operation. It will interlock all subsequent
+// restore operations, and will prevent the restore target
+// from starting until the call to HrRestoreRegisterComplete.
+//
+
+HRESULT
+EDBBACK_API
+HrRestoreRegisterA(
+ IN HBC hbcRestoreContext,
+ IN char * szCheckpointFilePath,
+ IN char * szLogPath,
+ IN EDB_RSTMAPA rgrstmap[],
+ IN C crstmap,
+ IN char * szBackupLogPath,
+ IN ULONG genLow,
+ IN ULONG genHigh
+ );
+
+HRESULT
+EDBBACK_API
+HrRestoreRegisterW(
+ IN HBC hbcRestoreContext,
+ IN WCHAR * wszCheckpointFilePath,
+ IN WCHAR * wszLogPath,
+ IN EDB_RSTMAPW rgrstmap[],
+ IN C crstmap,
+ IN WCHAR * wszBackupLogPath,
+ IN ULONG genLow,
+ IN ULONG genHigh
+ );
+
+#ifdef UNICODE
+#define HrRestoreRegister HrRestoreRegisterW
+#else
+#define HrRestoreRegister HrRestoreRegisterA
+#endif
+
+//
+// HrRestoreRegisterComplete will complete a restore
+// operation. It will allow further subsequent
+// restore operations, and will allow the restore target
+// to start if hrRestoreState is success.
+//
+// If hrRestoreState is NOT hrNone, this will
+// prevent the restore target from restarting.
+//
+
+HRESULT
+EDBBACK_API
+HrRestoreRegisterComplete(
+ HBC hbcRestoreContext,
+ HRESULT hrRestoreState
+ );
+
+HRESULT
+EDBBACK_API
+HrRestoreEnd(
+ HBC hbcRestoreContext
+ );
+
+HRESULT
+EDBBACK_API
+HrSetCurrentBackupLogW(
+ WCHAR *wszServerName,
+ WCHAR * wszBackupAnnotation,
+ DWORD dwCurrentLog
+ );
+
+HRESULT
+EDBBACK_API
+HrSetCurrentBackupLogA(
+ CHAR * szServerName,
+ CHAR * szBackupAnnotation,
+ DWORD dwCurrentLog
+ );
+
+#ifdef UNICODE
+#define HrSetCurrentBackupLog HrSetCurrentBackupLogW
+#else
+#define HrSetCurrentBackupLog HrSetCurrentBackupLogA
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _EDBBCLI_
+
diff --git a/private/utils/ntbackup/exchange/inc/morpc.h b/private/utils/ntbackup/exchange/inc/morpc.h
new file mode 100644
index 000000000..50e9ea91f
--- /dev/null
+++ b/private/utils/ntbackup/exchange/inc/morpc.h
@@ -0,0 +1,352 @@
+#ifndef __MORPC_H__
+#define __MORPC_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define small char
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+
+
+extern RPC_IF_HANDLE TriggerMonitoringRPC_ServerIfHandle;
+
+extern RPC_IF_HANDLE TriggerMonitoringRPC_ClientIfHandle;
+
+#ifndef _SIZE_T_DEFINED
+typedef unsigned int size_t;
+#define _SIZE_T_DEFINED
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef _ERROR_STATUS_T_DEFINED
+typedef unsigned long error_status_t;
+#define _ERROR_STATUS_T_DEFINED
+#endif
+
+#ifndef _WCHAR_T_DEFINED
+typedef unsigned short wchar_t;
+#define _WCHAR_T_DEFINED
+#endif
+
+#define szTriggerRPCProtocol TEXT("ncacn_np")
+#define szTriggerRPCEndpoint TEXT("\\pipe\\Trigger")
+#define szTriggerRPCSecurity TEXT("Security=impersonation dynamic true")
+typedef small RPC_BOOL;
+
+typedef small RPC_BYTE;
+
+typedef long RPC_INT;
+
+typedef long RPC_SC;
+
+typedef long RPC_DWORD;
+
+typedef wchar_t RPC_CHAR;
+
+typedef RPC_CHAR *RPC_SZ;
+
+typedef struct __MIDL_TriggerMonitoringRPC_0001
+ {
+ short rgwSystemTime[8];
+ }
+RPC_SYSTEMTIME;
+
+typedef struct __MIDL_TriggerMonitoringRPC_0002
+ {
+ RPC_BYTE rgbTzi[172];
+ }
+RPC_TIME_ZONE_INFORMATION;
+
+typedef struct __MIDL_TriggerMonitoringRPC_0003
+ {
+ long rgdwServiceStatus[7];
+ }
+RPC_SERVICE_STATUS;
+
+typedef struct __MIDL_TriggerMonitoringRPC_0004
+ {
+ RPC_SYSTEMTIME st;
+ RPC_TIME_ZONE_INFORMATION tzi;
+ RPC_DWORD dwReturn;
+ }
+RemoteSystemTimeInfo;
+
+typedef struct _RemoteServiceStatus
+ {
+ RPC_SC sc;
+ RPC_SZ szShortName;
+ RPC_SZ szDisplayName;
+ RPC_SZ szVersion;
+ RPC_SERVICE_STATUS ss;
+ struct _RemoteServiceStatus *prssNext;
+ }
+RemoteServiceStatus;
+
+typedef struct _BackupListNode
+ {
+ struct _BackupListNode *pnodeNext;
+ struct _BackupListNode *pnodeChildren;
+ RPC_SZ szName;
+ }
+BackupListNode;
+
+RPC_SC _cdecl ScNetworkTimingTest(
+ handle_t h,
+ long cbSend,
+ small rgbSend[],
+ long cbReceive,
+ small rgbReceive[]);
+RPC_SC _cdecl ScGetMaintenanceMode(
+ handle_t h,
+ RPC_BOOL *pfValue,
+ RPC_SYSTEMTIME *pst,
+ RPC_SZ szUser,
+ long cchMac);
+RPC_SC _cdecl ScSetMaintenanceMode(
+ handle_t h,
+ RPC_BOOL fNew,
+ RPC_SZ szUser);
+RPC_SC _cdecl ScGetRemoteSystemTime(
+ handle_t h,
+ RPC_SYSTEMTIME *pst);
+RPC_SC _cdecl ScSetRemoteSystemTime(
+ handle_t h,
+ RPC_SYSTEMTIME *pst);
+#define dwServerFlagMapiRunning 0x00000001
+RPC_SC _cdecl ScGetRemoteServerStatus(
+ handle_t h,
+ RPC_DWORD *pdwServerFlags,
+ RemoteSystemTimeInfo *prsti,
+ RemoteServiceStatus *prss);
+RPC_SC _cdecl ScRasEnumEntries(
+ handle_t h,
+ RPC_INT cb,
+ RPC_BYTE rgbRasEnumEntries[],
+ RPC_INT *pcEntries);
+RPC_SC _cdecl ScGetBackupListNode(
+ handle_t h,
+ BackupListNode **ppnode);
+RPC_SC _cdecl ScRunRID(
+ handle_t h);
+RPC_SC _cdecl ScRunDRACheck(
+ handle_t h,
+ RPC_DWORD dw);
+#define BPTAdd 1
+#define BPTRemove 2
+#define BPTUpdate 3
+RPC_SC _cdecl ScBulkCreateProxy(
+ handle_t h,
+ RPC_SZ szHeader,
+ RPC_DWORD dwOptions);
+RPC_SC _cdecl ScCreateProxy(
+ handle_t h,
+ RPC_SZ szDN);
+RPC_SC _cdecl ScIsProxyUnique(
+ handle_t h,
+ RPC_SZ szProxy,
+ RPC_BOOL *pfUnique,
+ RPC_SZ *pszOwner);
+#define scNoError 0
+#define scInvalidData 1
+#define scCannotLogData 2
+RPC_SC _cdecl ScSaveTrackingData(
+ handle_t h,
+ RPC_INT cb,
+ RPC_BYTE pb[],
+ RPC_DWORD dwFlags);
+#define tevtMessageTransferIn 0
+#define tevtReportTransferIn 2
+#define tevtMessageSubmission 4
+#define tevtMessageTransferOut 7
+#define tevtReportTransferOut 8
+#define tevtMessageDelivery 9
+#define tevtReportDelivery 10
+#define tevtStartAssocByMTSUser 18
+#define tevtReleaseAssocByMTSUser 23
+#define tevtDLExpansion 26
+#define tevtRedirection 28
+#define tevtRerouting 29
+#define tevtDowngrading 31
+#define tevtReportAbsorption 33
+#define tevtReportGenerated 34
+#define tevtUnroutableReportDiscard 43
+#define tevtMessageLocalDelivery 1000
+typedef struct __MIDL_TriggerMonitoringRPC_0005
+ {
+ RPC_INT nEventType;
+ RPC_SYSTEMTIME stEvent;
+ RPC_SZ szGatewayName;
+ RPC_SZ szPartner;
+ RPC_SZ szMTSID;
+ RPC_SZ szRemoteID;
+ RPC_SZ szOriginator;
+ RPC_INT nPriority;
+ RPC_INT nLength;
+ RPC_INT nSeconds;
+ RPC_INT nCost;
+ }
+RPC_GATEWAY_TRACK_INFORMATION;
+
+RPC_SC _cdecl ScSaveGatewayTrackingData(
+ handle_t h,
+ RPC_GATEWAY_TRACK_INFORMATION *pgti,
+ RPC_INT cszRecipients,
+ RPC_SZ rgszRecipients[]);
+
+#if !defined(IMPORT_USED_MULTIPLE) && !defined(IMPORT_USED_SINGLE)
+
+/* routine that gets node for struct __MIDL_TriggerMonitoringRPC_0001 */
+void _gns___MIDL_TriggerMonitoringRPC_0001 (RPC_SYSTEMTIME *, PRPC_MESSAGE);
+
+/* routine that gets node for struct __MIDL_TriggerMonitoringRPC_0002 */
+void _gns___MIDL_TriggerMonitoringRPC_0002 (RPC_TIME_ZONE_INFORMATION *, PRPC_MESSAGE);
+
+/* routine that gets node for struct __MIDL_TriggerMonitoringRPC_0003 */
+void _gns___MIDL_TriggerMonitoringRPC_0003 (RPC_SERVICE_STATUS *, PRPC_MESSAGE);
+
+/* routine that gets node for struct __MIDL_TriggerMonitoringRPC_0004 */
+void _gns___MIDL_TriggerMonitoringRPC_0004 (RemoteSystemTimeInfo *, PRPC_MESSAGE);
+
+/* routine that sizes graph for struct _RemoteServiceStatus */
+void _sgs__RemoteServiceStatus (RemoteServiceStatus *, PRPC_MESSAGE);
+
+/* routine that puts graph for struct _RemoteServiceStatus */
+void _pgs__RemoteServiceStatus (RemoteServiceStatus *, PRPC_MESSAGE);
+
+/* routine that gets node for struct _RemoteServiceStatus */
+void _gns__RemoteServiceStatus (RemoteServiceStatus *, PRPC_MESSAGE);
+
+/* routine that gets graph for struct _RemoteServiceStatus */
+void _ggs__RemoteServiceStatus (RemoteServiceStatus *, unsigned char **, PRPC_MESSAGE);
+
+/* routine that allocates graph for struct _RemoteServiceStatus */
+void _ags__RemoteServiceStatus(unsigned char **, PRPC_MESSAGE);
+
+/* routine that frees graph for struct _RemoteServiceStatus */
+void _fgs__RemoteServiceStatus (RemoteServiceStatus *);
+
+/* routine that sizes graph for struct _BackupListNode */
+void _sgs__BackupListNode (BackupListNode *, PRPC_MESSAGE);
+
+/* routine that puts graph for struct _BackupListNode */
+void _pgs__BackupListNode (BackupListNode *, PRPC_MESSAGE);
+
+/* routine that gets graph for struct _BackupListNode */
+void _ggs__BackupListNode (BackupListNode *, unsigned char **, PRPC_MESSAGE);
+
+/* routine that allocates graph for struct _BackupListNode */
+void _ags__BackupListNode(unsigned char **, PRPC_MESSAGE);
+
+/* routine that frees graph for struct _BackupListNode */
+void _fgs__BackupListNode (BackupListNode *);
+
+/* routine that sizes graph for struct __MIDL_TriggerMonitoringRPC_0005 */
+void _sgs___MIDL_TriggerMonitoringRPC_0005 (RPC_GATEWAY_TRACK_INFORMATION *, PRPC_MESSAGE);
+
+/* routine that puts graph for struct __MIDL_TriggerMonitoringRPC_0005 */
+void _pgs___MIDL_TriggerMonitoringRPC_0005 (RPC_GATEWAY_TRACK_INFORMATION *, PRPC_MESSAGE);
+
+/* routine that gets node for struct __MIDL_TriggerMonitoringRPC_0005 */
+void _gns___MIDL_TriggerMonitoringRPC_0005 (RPC_GATEWAY_TRACK_INFORMATION *, PRPC_MESSAGE);
+
+/* routine that gets graph for struct __MIDL_TriggerMonitoringRPC_0005 */
+void _ggs___MIDL_TriggerMonitoringRPC_0005 (RPC_GATEWAY_TRACK_INFORMATION *, unsigned char **, PRPC_MESSAGE);
+
+/* routine that allocates graph for struct __MIDL_TriggerMonitoringRPC_0005 */
+void _ags___MIDL_TriggerMonitoringRPC_0005(unsigned char **, PRPC_MESSAGE);
+
+/* routine that frees graph for struct __MIDL_TriggerMonitoringRPC_0005 */
+void _fgs___MIDL_TriggerMonitoringRPC_0005 (RPC_GATEWAY_TRACK_INFORMATION *);
+
+#endif /*!defined(IMPORT_USED_MULTIPLE) && !defined(IMPORT_USED_SINGLE)*/
+
+typedef struct _TriggerMonitoringRPC_SERVER_EPV
+ {
+ RPC_SC (_cdecl __RPC_FAR * ScNetworkTimingTest)(
+ handle_t h,
+ long cbSend,
+ small *rgbSend,
+ long cbReceive,
+ small *rgbReceive);
+ RPC_SC (_cdecl __RPC_FAR * ScGetMaintenanceMode)(
+ handle_t h,
+ RPC_BOOL *pfValue,
+ RPC_SYSTEMTIME *pst,
+ RPC_SZ szUser,
+ long cchMac);
+ RPC_SC (_cdecl __RPC_FAR * ScSetMaintenanceMode)(
+ handle_t h,
+ RPC_BOOL fNew,
+ RPC_SZ szUser);
+ RPC_SC (_cdecl __RPC_FAR * ScGetRemoteSystemTime)(
+ handle_t h,
+ RPC_SYSTEMTIME *pst);
+ RPC_SC (_cdecl __RPC_FAR * ScSetRemoteSystemTime)(
+ handle_t h,
+ RPC_SYSTEMTIME *pst);
+ RPC_SC (_cdecl __RPC_FAR * ScGetRemoteServerStatus)(
+ handle_t h,
+ RPC_DWORD *pdwServerFlags,
+ RemoteSystemTimeInfo *prsti,
+ RemoteServiceStatus *prss);
+ RPC_SC (_cdecl __RPC_FAR * ScRasEnumEntries)(
+ handle_t h,
+ RPC_INT cb,
+ RPC_BYTE *rgbRasEnumEntries,
+ RPC_INT *pcEntries);
+ RPC_SC (_cdecl __RPC_FAR * ScGetBackupListNode)(
+ handle_t h,
+ BackupListNode **ppnode);
+ RPC_SC (_cdecl __RPC_FAR * ScRunRID)(
+ handle_t h);
+ RPC_SC (_cdecl __RPC_FAR * ScRunDRACheck)(
+ handle_t h,
+ RPC_DWORD dw);
+ RPC_SC (_cdecl __RPC_FAR * ScBulkCreateProxy)(
+ handle_t h,
+ RPC_SZ szHeader,
+ RPC_DWORD dwOptions);
+ RPC_SC (_cdecl __RPC_FAR * ScCreateProxy)(
+ handle_t h,
+ RPC_SZ szDN);
+ RPC_SC (_cdecl __RPC_FAR * ScIsProxyUnique)(
+ handle_t h,
+ RPC_SZ szProxy,
+ RPC_BOOL *pfUnique,
+ RPC_SZ *pszOwner);
+ RPC_SC (_cdecl __RPC_FAR * ScSaveTrackingData)(
+ handle_t h,
+ RPC_INT cb,
+ RPC_BYTE *pb,
+ RPC_DWORD dwFlags);
+ RPC_SC (_cdecl __RPC_FAR * ScSaveGatewayTrackingData)(
+ handle_t h,
+ RPC_GATEWAY_TRACK_INFORMATION *pgti,
+ RPC_INT cszRecipients,
+ RPC_SZ *rgszRecipients);
+ }
+TriggerMonitoringRPC_SERVER_EPV;
+void __RPC_FAR * __RPC_API MIDL_user_allocate(size_t);
+void __RPC_API MIDL_user_free(void __RPC_FAR *);
+#ifndef __MIDL_USER_DEFINED
+#define midl_user_allocate MIDL_user_allocate
+#define midl_user_free MIDL_user_free
+#define __MIDL_USER_DEFINED
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/private/utils/ntbackup/exchange/inc/rpcbak.h b/private/utils/ntbackup/exchange/inc/rpcbak.h
new file mode 100644
index 000000000..b33cb8cdc
--- /dev/null
+++ b/private/utils/ntbackup/exchange/inc/rpcbak.h
@@ -0,0 +1,225 @@
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+/* File created by MIDL compiler version 2.00.0104 */
+/* at Mon Jan 29 16:52:29 1996
+ */
+//@@MIDL_FILE_HEADING( )
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __rpcbak_h__
+#define __rpcbak_h__
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+/* Forward Declarations */
+
+void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t);
+void __RPC_USER MIDL_user_free( void __RPC_FAR * );
+
+#ifndef __TriggerBackupRPC_INTERFACE_DEFINED__
+#define __TriggerBackupRPC_INTERFACE_DEFINED__
+
+/****************************************
+ * Generated header for interface: TriggerBackupRPC
+ * at Mon Jan 29 16:52:29 1996
+ * using MIDL 2.00.0104
+ ****************************************/
+/* [auto_handle][unique][version][uuid] */
+
+
+#ifndef RPC_COMMON_IDL
+#define RPC_COMMON_IDL
+#define szTriggerRPCProtocol TEXT("ncacn_np")
+#define szTriggerRPCSecurity TEXT("Security=impersonation dynamic true")
+ /* size is 4 */
+typedef long RPC_BOOL;
+
+ /* size is 1 */
+typedef small RPC_BYTE;
+
+ /* size is 4 */
+typedef long RPC_INT;
+
+ /* size is 4 */
+typedef long RPC_SC;
+
+ /* size is 4 */
+typedef long RPC_EC;
+
+ /* size is 4 */
+typedef long RPC_DWORD;
+
+ /* size is 2 */
+typedef wchar_t RPC_CHAR;
+
+ /* size is 4 */
+typedef /* [string] */ RPC_CHAR __RPC_FAR *RPC_SZ;
+
+ /* size is 16 */
+typedef struct __MIDL_TriggerBackupRPC_0001
+ {
+ short rgwSystemTime[ 8 ];
+ } RPC_SYSTEMTIME;
+
+ /* size is 172 */
+typedef struct __MIDL_TriggerBackupRPC_0002
+ {
+ RPC_BYTE rgbTzi[ 172 ];
+ } RPC_TIME_ZONE_INFORMATION;
+
+ /* size is 28 */
+typedef struct __MIDL_TriggerBackupRPC_0003
+ {
+ long rgdwServiceStatus[ 7 ];
+ } RPC_SERVICE_STATUS;
+
+#define ecOK 0 // no error
+#define ecGeneralFailure 50001 // a failure occurred that caused proxy generation to stop
+#define ecSomeProxiesFailed 50002 // some proxies failed to get generated
+#define ecTargetNotValid 50003 // supplied target address not valid
+#define ecTargetNotUnique 50004 // supplied target address not unique
+#define ecProxyDLLNotImplemented 50005 // not implemented yet
+#define ecProxyDLLOOM 50006 // memory allocation error
+#define ecProxyDLLError 50007 // general error
+#define ecProxyDLLProtocol 50008 // protocol error
+#define ecProxyDLLSyntax 50009 // syntax error
+#define ecProxyDLLEOF 50010 // end of file
+#define ecProxyDLLSoftware 50011 // error in software
+#define ecProxyDLLConfig 50012 // configuration error
+#define ecProxyDLLContention 50013 // contention error
+#define ecProxyDLLNotFound 50014 // not found
+#define ecProxyDLLDiskSpace 50015 // out of disk space
+#define ecProxyDLLException 50016 // exception thrown
+#define ecProxyDLLDefault 50017 // unknown error
+#define ecProxyNotValid 50018 // supplied proxy not valid
+#define ecProxyNotUnique 50019 // supplied proxy not unique or unable to generate a unique proxy
+#define ecProxyDuplicate 50020 // a primary proxy of the same type was also supplied
+ /* size is 16 */
+typedef struct _PROXYNODE
+ {
+ struct _PROXYNODE __RPC_FAR *pnodeNext;
+ RPC_SZ wszProxy;
+ RPC_EC ec;
+ RPC_SZ wszDN;
+ } PROXYNODE;
+
+ /* size is 4 */
+typedef struct _PROXYNODE __RPC_FAR *PPROXYNODE;
+
+ /* size is 48 */
+typedef struct _PROXYINFO
+ {
+ RPC_BOOL fContinueOnError;
+ RPC_BOOL fIgnoreOldSecondaries;
+ RPC_SZ wszDN;
+ RPC_SZ wszNickName;
+ RPC_SZ wszCommonName;
+ RPC_SZ wszDisplayName;
+ RPC_SZ wszSurName;
+ RPC_SZ wszGivenName;
+ RPC_SZ wszInitials;
+ RPC_SZ wszTargetAddress;
+ PROXYNODE __RPC_FAR *pPNVerifyProxy;
+ PROXYNODE __RPC_FAR *pPNExcludeProxy;
+ } PROXYINFO;
+
+ /* size is 4 */
+typedef struct _PROXYINFO __RPC_FAR *PPROXYINFO;
+
+ /* size is 8 */
+typedef struct _PROXYLIST
+ {
+ PROXYNODE __RPC_FAR *__RPC_FAR *ppPNProxy;
+ PROXYNODE __RPC_FAR *__RPC_FAR *ppPNFailedProxyType;
+ } PROXYLIST;
+
+ /* size is 4 */
+typedef struct _PROXYLIST __RPC_FAR *PPROXYLIST;
+
+ /* size is 192 */
+typedef struct __MIDL_TriggerBackupRPC_0004
+ {
+ RPC_SYSTEMTIME st;
+ RPC_TIME_ZONE_INFORMATION tzi;
+ RPC_DWORD dwReturn;
+ } RemoteSystemTimeInfo;
+
+ /* size is 48 */
+typedef struct _RemoteServiceStatus
+ {
+ RPC_SC sc;
+ RPC_SZ szShortName;
+ RPC_SZ szDisplayName;
+ RPC_SZ szVersion;
+ RPC_SERVICE_STATUS ss;
+ struct _RemoteServiceStatus __RPC_FAR *prssNext;
+ } RemoteServiceStatus;
+
+#define rmsSuspendRepair 0x0001
+#define rmsSuspendNotif 0x0002
+ /* size is 24 */
+typedef struct _RemoteMaintenanceStatus
+ {
+ RPC_DWORD dwStatus;
+ RPC_SYSTEMTIME st;
+ RPC_SZ szUser;
+ } RemoteMaintenanceStatus;
+
+ /* size is 12 */
+typedef struct _BackupListNode
+ {
+ struct _BackupListNode __RPC_FAR *pnodeNext;
+ struct _BackupListNode __RPC_FAR *pnodeChildren;
+ RPC_SZ szName;
+ } BackupListNode;
+
+ /* size is 44 */
+typedef struct _DistributedLockOwner
+ {
+ RPC_CHAR rgchComputer[ 17 ];
+ RPC_DWORD dwPID;
+ RPC_DWORD dwTID;
+ } DistributedLockOwner;
+
+#define DLR_NO_WAIT 0x00000001
+#define cchMaxLockName 17
+ /* size is 84 */
+typedef struct _DistributedLockRequest
+ {
+ RPC_CHAR rgchLockName[ 17 ];
+ RPC_DWORD dwFlags;
+ DistributedLockOwner dlo;
+ } DistributedLockRequest;
+
+ /* size is 48 */
+typedef struct _DistributedLockReply
+ {
+ RPC_BOOL fGranted;
+ DistributedLockOwner dlo;
+ } DistributedLockReply;
+
+#endif // #ifndef RPC_COMMON_IDL
+ /* size is 4 */
+RPC_SC __cdecl ScGetBackupListNode(
+ /* [in] */ handle_t h,
+ /* [out][in] */ BackupListNode __RPC_FAR *__RPC_FAR *ppnode);
+
+
+
+extern RPC_IF_HANDLE TriggerBackupRPC_ClientIfHandle;
+extern RPC_IF_HANDLE TriggerBackupRPC_ServerIfHandle;
+#endif /* __TriggerBackupRPC_INTERFACE_DEFINED__ */
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/private/utils/ntbackup/exchange/inc/rpcpri.h b/private/utils/ntbackup/exchange/inc/rpcpri.h
new file mode 100644
index 000000000..4d41fc290
--- /dev/null
+++ b/private/utils/ntbackup/exchange/inc/rpcpri.h
@@ -0,0 +1,288 @@
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+/* File created by MIDL compiler version 2.00.0104 */
+/* at Mon Jan 29 16:52:33 1996
+ */
+//@@MIDL_FILE_HEADING( )
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __rpcpri_h__
+#define __rpcpri_h__
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+/* Forward Declarations */
+
+void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t);
+void __RPC_USER MIDL_user_free( void __RPC_FAR * );
+
+#ifndef __TriggerPrivateRPC_INTERFACE_DEFINED__
+#define __TriggerPrivateRPC_INTERFACE_DEFINED__
+
+/****************************************
+ * Generated header for interface: TriggerPrivateRPC
+ * at Mon Jan 29 16:52:33 1996
+ * using MIDL 2.00.0104
+ ****************************************/
+/* [auto_handle][unique][version][uuid] */
+
+
+#ifndef RPC_COMMON_IDL
+#define RPC_COMMON_IDL
+#define szTriggerRPCProtocol TEXT("ncacn_np")
+#define szTriggerRPCSecurity TEXT("Security=impersonation dynamic true")
+ /* size is 4 */
+typedef long RPC_BOOL;
+
+ /* size is 1 */
+typedef small RPC_BYTE;
+
+ /* size is 4 */
+typedef long RPC_INT;
+
+ /* size is 4 */
+typedef long RPC_SC;
+
+ /* size is 4 */
+typedef long RPC_EC;
+
+ /* size is 4 */
+typedef long RPC_DWORD;
+
+ /* size is 2 */
+typedef wchar_t RPC_CHAR;
+
+ /* size is 4 */
+typedef /* [string] */ RPC_CHAR __RPC_FAR *RPC_SZ;
+
+ /* size is 16 */
+typedef struct __MIDL_TriggerPrivateRPC_0001
+ {
+ short rgwSystemTime[ 8 ];
+ } RPC_SYSTEMTIME;
+
+ /* size is 172 */
+typedef struct __MIDL_TriggerPrivateRPC_0002
+ {
+ RPC_BYTE rgbTzi[ 172 ];
+ } RPC_TIME_ZONE_INFORMATION;
+
+ /* size is 28 */
+typedef struct __MIDL_TriggerPrivateRPC_0003
+ {
+ long rgdwServiceStatus[ 7 ];
+ } RPC_SERVICE_STATUS;
+
+#define ecOK 0 // no error
+#define ecGeneralFailure 50001 // a failure occurred that caused proxy generation to stop
+#define ecSomeProxiesFailed 50002 // some proxies failed to get generated
+#define ecTargetNotValid 50003 // supplied target address not valid
+#define ecTargetNotUnique 50004 // supplied target address not unique
+#define ecProxyDLLNotImplemented 50005 // not implemented yet
+#define ecProxyDLLOOM 50006 // memory allocation error
+#define ecProxyDLLError 50007 // general error
+#define ecProxyDLLProtocol 50008 // protocol error
+#define ecProxyDLLSyntax 50009 // syntax error
+#define ecProxyDLLEOF 50010 // end of file
+#define ecProxyDLLSoftware 50011 // error in software
+#define ecProxyDLLConfig 50012 // configuration error
+#define ecProxyDLLContention 50013 // contention error
+#define ecProxyDLLNotFound 50014 // not found
+#define ecProxyDLLDiskSpace 50015 // out of disk space
+#define ecProxyDLLException 50016 // exception thrown
+#define ecProxyDLLDefault 50017 // unknown error
+#define ecProxyNotValid 50018 // supplied proxy not valid
+#define ecProxyNotUnique 50019 // supplied proxy not unique or unable to generate a unique proxy
+#define ecProxyDuplicate 50020 // a primary proxy of the same type was also supplied
+ /* size is 16 */
+typedef struct _PROXYNODE
+ {
+ struct _PROXYNODE __RPC_FAR *pnodeNext;
+ RPC_SZ wszProxy;
+ RPC_EC ec;
+ RPC_SZ wszDN;
+ } PROXYNODE;
+
+ /* size is 4 */
+typedef struct _PROXYNODE __RPC_FAR *PPROXYNODE;
+
+ /* size is 48 */
+typedef struct _PROXYINFO
+ {
+ RPC_BOOL fContinueOnError;
+ RPC_BOOL fIgnoreOldSecondaries;
+ RPC_SZ wszDN;
+ RPC_SZ wszNickName;
+ RPC_SZ wszCommonName;
+ RPC_SZ wszDisplayName;
+ RPC_SZ wszSurName;
+ RPC_SZ wszGivenName;
+ RPC_SZ wszInitials;
+ RPC_SZ wszTargetAddress;
+ PROXYNODE __RPC_FAR *pPNVerifyProxy;
+ PROXYNODE __RPC_FAR *pPNExcludeProxy;
+ } PROXYINFO;
+
+ /* size is 4 */
+typedef struct _PROXYINFO __RPC_FAR *PPROXYINFO;
+
+ /* size is 8 */
+typedef struct _PROXYLIST
+ {
+ PROXYNODE __RPC_FAR *__RPC_FAR *ppPNProxy;
+ PROXYNODE __RPC_FAR *__RPC_FAR *ppPNFailedProxyType;
+ } PROXYLIST;
+
+ /* size is 4 */
+typedef struct _PROXYLIST __RPC_FAR *PPROXYLIST;
+
+ /* size is 192 */
+typedef struct __MIDL_TriggerPrivateRPC_0004
+ {
+ RPC_SYSTEMTIME st;
+ RPC_TIME_ZONE_INFORMATION tzi;
+ RPC_DWORD dwReturn;
+ } RemoteSystemTimeInfo;
+
+ /* size is 48 */
+typedef struct _RemoteServiceStatus
+ {
+ RPC_SC sc;
+ RPC_SZ szShortName;
+ RPC_SZ szDisplayName;
+ RPC_SZ szVersion;
+ RPC_SERVICE_STATUS ss;
+ struct _RemoteServiceStatus __RPC_FAR *prssNext;
+ } RemoteServiceStatus;
+
+#define rmsSuspendRepair 0x0001
+#define rmsSuspendNotif 0x0002
+ /* size is 24 */
+typedef struct _RemoteMaintenanceStatus
+ {
+ RPC_DWORD dwStatus;
+ RPC_SYSTEMTIME st;
+ RPC_SZ szUser;
+ } RemoteMaintenanceStatus;
+
+ /* size is 12 */
+typedef struct _BackupListNode
+ {
+ struct _BackupListNode __RPC_FAR *pnodeNext;
+ struct _BackupListNode __RPC_FAR *pnodeChildren;
+ RPC_SZ szName;
+ } BackupListNode;
+
+ /* size is 44 */
+typedef struct _DistributedLockOwner
+ {
+ RPC_CHAR rgchComputer[ 17 ];
+ RPC_DWORD dwPID;
+ RPC_DWORD dwTID;
+ } DistributedLockOwner;
+
+#define DLR_NO_WAIT 0x00000001
+#define cchMaxLockName 17
+ /* size is 84 */
+typedef struct _DistributedLockRequest
+ {
+ RPC_CHAR rgchLockName[ 17 ];
+ RPC_DWORD dwFlags;
+ DistributedLockOwner dlo;
+ } DistributedLockRequest;
+
+ /* size is 48 */
+typedef struct _DistributedLockReply
+ {
+ RPC_BOOL fGranted;
+ DistributedLockOwner dlo;
+ } DistributedLockReply;
+
+#endif // #ifndef RPC_COMMON_IDL
+ /* size is 4 */
+RPC_SC __cdecl ScGetMaintenanceMode(
+ /* [in] */ handle_t h,
+ /* [out] */ RPC_DWORD __RPC_FAR *pdw,
+ /* [out] */ RPC_SYSTEMTIME __RPC_FAR *pst,
+ /* [out] */ RPC_SZ __RPC_FAR *pszUser);
+
+ /* size is 4 */
+RPC_SC __cdecl ScSetMaintenanceMode(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_DWORD dw,
+ /* [in] */ RPC_SZ szUser);
+
+ /* size is 4 */
+RPC_SC __cdecl ScGetRemoteSystemTime(
+ /* [in] */ handle_t h,
+ /* [out] */ RPC_SYSTEMTIME __RPC_FAR *pst);
+
+ /* size is 4 */
+RPC_SC __cdecl ScSetRemoteSystemTime(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_SYSTEMTIME __RPC_FAR *pst);
+
+#define dwServerFlagMapiRunning 0x00000001
+#define dwServerFlagNoPrivateStore 0x00000002
+ /* size is 4 */
+RPC_SC __cdecl ScGetRemoteServerStatus(
+ /* [in] */ handle_t h,
+ /* [out] */ RPC_DWORD __RPC_FAR *pdwServerFlags,
+ /* [out] */ RemoteSystemTimeInfo __RPC_FAR *prsti,
+ /* [out][in] */ RemoteServiceStatus __RPC_FAR *prss,
+ /* [out] */ RemoteMaintenanceStatus __RPC_FAR *prms);
+
+ /* size is 4 */
+RPC_SC __cdecl ScRunOffLineABTask(
+ /* [in] */ handle_t h);
+
+ /* size is 4 */
+RPC_SC __cdecl ScGetDistributedLock(
+ /* [in] */ handle_t h,
+ /* [in] */ DistributedLockRequest __RPC_FAR *pdlRequest,
+ /* [out] */ DistributedLockReply __RPC_FAR *pdlReply);
+
+ /* size is 4 */
+RPC_SC __cdecl ScReleaseDistributedLock(
+ /* [in] */ handle_t h,
+ /* [in] */ DistributedLockRequest __RPC_FAR *pdlRequest);
+
+ /* size is 4 */
+RPC_SC __cdecl ScKillDistributedLock(
+ /* [in] */ handle_t h,
+ /* [in] */ DistributedLockRequest __RPC_FAR *pdlRequest,
+ /* [out] */ DistributedLockReply __RPC_FAR *pdlReply);
+
+ /* size is 4 */
+RPC_SC __cdecl ScRasEnumEntries(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_INT cb,
+ /* [size_is][out] */ RPC_BYTE __RPC_FAR rgbRasEnumEntries[ ],
+ /* [out] */ RPC_INT __RPC_FAR *pcEntries);
+
+ /* size is 4 */
+RPC_SC __cdecl ScGetExtensionPath(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_SZ szExtensionName,
+ /* [in] */ RPC_SZ szExtensionCPU,
+ /* [out] */ RPC_SZ __RPC_FAR *pszExtensionPath);
+
+
+
+extern RPC_IF_HANDLE TriggerPrivateRPC_ClientIfHandle;
+extern RPC_IF_HANDLE TriggerPrivateRPC_ServerIfHandle;
+#endif /* __TriggerPrivateRPC_INTERFACE_DEFINED__ */
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/private/utils/ntbackup/exchange/inc/rpcpub.h b/private/utils/ntbackup/exchange/inc/rpcpub.h
new file mode 100644
index 000000000..8be1b562b
--- /dev/null
+++ b/private/utils/ntbackup/exchange/inc/rpcpub.h
@@ -0,0 +1,387 @@
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+/* File created by MIDL compiler version 2.00.0104 */
+/* at Mon Jan 29 16:52:25 1996
+ */
+//@@MIDL_FILE_HEADING( )
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __rpcpub_h__
+#define __rpcpub_h__
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+/* Forward Declarations */
+
+void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t);
+void __RPC_USER MIDL_user_free( void __RPC_FAR * );
+
+#ifndef __TriggerPublicRPC_INTERFACE_DEFINED__
+#define __TriggerPublicRPC_INTERFACE_DEFINED__
+
+/****************************************
+ * Generated header for interface: TriggerPublicRPC
+ * at Mon Jan 29 16:52:25 1996
+ * using MIDL 2.00.0104
+ ****************************************/
+/* [auto_handle][unique][version][uuid] */
+
+
+#ifndef RPC_COMMON_IDL
+#define RPC_COMMON_IDL
+#define szTriggerRPCProtocol TEXT("ncacn_np")
+#define szTriggerRPCSecurity TEXT("Security=impersonation dynamic true")
+ /* size is 4 */
+typedef long RPC_BOOL;
+
+ /* size is 1 */
+typedef small RPC_BYTE;
+
+ /* size is 4 */
+typedef long RPC_INT;
+
+ /* size is 4 */
+typedef long RPC_SC;
+
+ /* size is 4 */
+typedef long RPC_EC;
+
+ /* size is 4 */
+typedef long RPC_DWORD;
+
+ /* size is 2 */
+typedef wchar_t RPC_CHAR;
+
+ /* size is 4 */
+typedef /* [string] */ RPC_CHAR __RPC_FAR *RPC_SZ;
+
+ /* size is 16 */
+typedef struct __MIDL_TriggerPublicRPC_0001
+ {
+ short rgwSystemTime[ 8 ];
+ } RPC_SYSTEMTIME;
+
+ /* size is 172 */
+typedef struct __MIDL_TriggerPublicRPC_0002
+ {
+ RPC_BYTE rgbTzi[ 172 ];
+ } RPC_TIME_ZONE_INFORMATION;
+
+ /* size is 28 */
+typedef struct __MIDL_TriggerPublicRPC_0003
+ {
+ long rgdwServiceStatus[ 7 ];
+ } RPC_SERVICE_STATUS;
+
+#define ecOK 0 // no error
+#define ecGeneralFailure 50001 // a failure occurred that caused proxy generation to stop
+#define ecSomeProxiesFailed 50002 // some proxies failed to get generated
+#define ecTargetNotValid 50003 // supplied target address not valid
+#define ecTargetNotUnique 50004 // supplied target address not unique
+#define ecProxyDLLNotImplemented 50005 // not implemented yet
+#define ecProxyDLLOOM 50006 // memory allocation error
+#define ecProxyDLLError 50007 // general error
+#define ecProxyDLLProtocol 50008 // protocol error
+#define ecProxyDLLSyntax 50009 // syntax error
+#define ecProxyDLLEOF 50010 // end of file
+#define ecProxyDLLSoftware 50011 // error in software
+#define ecProxyDLLConfig 50012 // configuration error
+#define ecProxyDLLContention 50013 // contention error
+#define ecProxyDLLNotFound 50014 // not found
+#define ecProxyDLLDiskSpace 50015 // out of disk space
+#define ecProxyDLLException 50016 // exception thrown
+#define ecProxyDLLDefault 50017 // unknown error
+#define ecProxyNotValid 50018 // supplied proxy not valid
+#define ecProxyNotUnique 50019 // supplied proxy not unique or unable to generate a unique proxy
+#define ecProxyDuplicate 50020 // a primary proxy of the same type was also supplied
+ /* size is 16 */
+typedef struct _PROXYNODE
+ {
+ struct _PROXYNODE __RPC_FAR *pnodeNext;
+ RPC_SZ wszProxy;
+ RPC_EC ec;
+ RPC_SZ wszDN;
+ } PROXYNODE;
+
+ /* size is 4 */
+typedef struct _PROXYNODE __RPC_FAR *PPROXYNODE;
+
+ /* size is 48 */
+typedef struct _PROXYINFO
+ {
+ RPC_BOOL fContinueOnError;
+ RPC_BOOL fIgnoreOldSecondaries;
+ RPC_SZ wszDN;
+ RPC_SZ wszNickName;
+ RPC_SZ wszCommonName;
+ RPC_SZ wszDisplayName;
+ RPC_SZ wszSurName;
+ RPC_SZ wszGivenName;
+ RPC_SZ wszInitials;
+ RPC_SZ wszTargetAddress;
+ PROXYNODE __RPC_FAR *pPNVerifyProxy;
+ PROXYNODE __RPC_FAR *pPNExcludeProxy;
+ } PROXYINFO;
+
+ /* size is 4 */
+typedef struct _PROXYINFO __RPC_FAR *PPROXYINFO;
+
+ /* size is 8 */
+typedef struct _PROXYLIST
+ {
+ PROXYNODE __RPC_FAR *__RPC_FAR *ppPNProxy;
+ PROXYNODE __RPC_FAR *__RPC_FAR *ppPNFailedProxyType;
+ } PROXYLIST;
+
+ /* size is 4 */
+typedef struct _PROXYLIST __RPC_FAR *PPROXYLIST;
+
+ /* size is 192 */
+typedef struct __MIDL_TriggerPublicRPC_0004
+ {
+ RPC_SYSTEMTIME st;
+ RPC_TIME_ZONE_INFORMATION tzi;
+ RPC_DWORD dwReturn;
+ } RemoteSystemTimeInfo;
+
+ /* size is 48 */
+typedef struct _RemoteServiceStatus
+ {
+ RPC_SC sc;
+ RPC_SZ szShortName;
+ RPC_SZ szDisplayName;
+ RPC_SZ szVersion;
+ RPC_SERVICE_STATUS ss;
+ struct _RemoteServiceStatus __RPC_FAR *prssNext;
+ } RemoteServiceStatus;
+
+#define rmsSuspendRepair 0x0001
+#define rmsSuspendNotif 0x0002
+ /* size is 24 */
+typedef struct _RemoteMaintenanceStatus
+ {
+ RPC_DWORD dwStatus;
+ RPC_SYSTEMTIME st;
+ RPC_SZ szUser;
+ } RemoteMaintenanceStatus;
+
+ /* size is 12 */
+typedef struct _BackupListNode
+ {
+ struct _BackupListNode __RPC_FAR *pnodeNext;
+ struct _BackupListNode __RPC_FAR *pnodeChildren;
+ RPC_SZ szName;
+ } BackupListNode;
+
+ /* size is 44 */
+typedef struct _DistributedLockOwner
+ {
+ RPC_CHAR rgchComputer[ 17 ];
+ RPC_DWORD dwPID;
+ RPC_DWORD dwTID;
+ } DistributedLockOwner;
+
+#define DLR_NO_WAIT 0x00000001
+#define cchMaxLockName 17
+ /* size is 84 */
+typedef struct _DistributedLockRequest
+ {
+ RPC_CHAR rgchLockName[ 17 ];
+ RPC_DWORD dwFlags;
+ DistributedLockOwner dlo;
+ } DistributedLockRequest;
+
+ /* size is 48 */
+typedef struct _DistributedLockReply
+ {
+ RPC_BOOL fGranted;
+ DistributedLockOwner dlo;
+ } DistributedLockReply;
+
+#endif // #ifndef RPC_COMMON_IDL
+ /* size is 4 */
+RPC_SC __cdecl ScNetworkTimingTest(
+ /* [in] */ handle_t h,
+ /* [in] */ long cbSend,
+ /* [size_is][in] */ small __RPC_FAR rgbSend[ ],
+ /* [in] */ long cbReceive,
+ /* [size_is][out] */ small __RPC_FAR rgbReceive[ ]);
+
+ /* size is 4 */
+RPC_SC __cdecl ScRunRID(
+ /* [in] */ handle_t h);
+
+ /* size is 4 */
+RPC_SC __cdecl ScRunRIDEx(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_BOOL fProxySpace,
+ /* [in] */ RPC_BOOL fGwart);
+
+ /* size is 4 */
+RPC_SC __cdecl ScRunDRACheck(
+ /* [in] */ handle_t h,
+ RPC_DWORD dw);
+
+#define BPTAdd 1
+#define BPTRemove 2
+#define BPTUpdate 3
+ /* size is 4 */
+RPC_SC __cdecl ScBulkCreateProxy(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_SZ szHeader,
+ /* [in] */ RPC_DWORD dwOptions);
+
+ /* size is 4 */
+RPC_SC __cdecl ScBulkCreateMultiProxy(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_INT cszHeader,
+ /* [size_is][in] */ RPC_SZ __RPC_FAR rgszRecipients[ ],
+ /* [in] */ RPC_DWORD dwOptions);
+
+ /* size is 4 */
+RPC_SC __cdecl ScBulkUpdateMultiProxy(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_INT cszSiteAddress,
+ /* [size_is][in] */ RPC_SZ __RPC_FAR rgszOldSiteAddress[ ],
+ /* [size_is][in] */ RPC_SZ __RPC_FAR rgszNewSiteAddress[ ],
+ /* [in] */ RPC_BOOL fSaveSiteAddress);
+
+ /* size is 4 */
+RPC_SC __cdecl ScGetBulkProxyStatus(
+ /* [in] */ handle_t h,
+ /* [out] */ RPC_SYSTEMTIME __RPC_FAR *pstTimeStart,
+ /* [out] */ RPC_DWORD __RPC_FAR *pdwTimeStart,
+ /* [out] */ RPC_DWORD __RPC_FAR *pdwTimeCur,
+ /* [out] */ RPC_INT __RPC_FAR *piRecipients,
+ /* [out] */ RPC_INT __RPC_FAR *pcRecipients);
+
+ /* size is 4 */
+RPC_SC __cdecl ScBulkProxyHalt(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_BOOL fWaitForShutdown);
+
+ /* size is 4 */
+RPC_EC __cdecl EcGetProxies(
+ /* [in] */ handle_t h,
+ /* [in] */ PPROXYINFO pProxyInfo,
+ /* [out][in] */ PPROXYLIST pProxyList);
+
+ /* size is 4 */
+RPC_SC __cdecl ScIsProxyUnique(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_SZ szProxy,
+ /* [out] */ RPC_BOOL __RPC_FAR *pfUnique,
+ /* [out] */ RPC_SZ __RPC_FAR *pszOwner);
+
+ /* size is 4 */
+RPC_SC __cdecl ScProxyValidate(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_SZ szProxy,
+ /* [out] */ RPC_BOOL __RPC_FAR *pfValid,
+ /* [out] */ RPC_SZ __RPC_FAR *pszProxyCorrected);
+
+ /* size is 4 */
+RPC_SC __cdecl ScSiteProxyValidate(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_SZ szSiteProxy,
+ /* [out] */ RPC_BOOL __RPC_FAR *pfValid,
+ /* [out] */ RPC_SZ __RPC_FAR *pszSiteProxyCorrected);
+
+ /* size is 4 */
+RPC_SC __cdecl ScProxyReset(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_BOOL fWaitUntilCompleted);
+
+#define scNoError 0
+#define scInvalidData 1
+#define scCannotLogData 2
+ /* size is 4 */
+RPC_SC __cdecl ScSaveTrackingData(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_INT cb,
+ /* [size_is][in] */ RPC_BYTE __RPC_FAR pb[ ],
+ /* [in] */ RPC_DWORD dwFlags);
+
+#define tevtMessageTransferIn 0
+#define tevtReportTransferIn 2
+#define tevtMessageSubmission 4
+#define tevtMessageTransferOut 7
+#define tevtReportTransferOut 8
+#define tevtMessageDelivery 9
+#define tevtReportDelivery 10
+#define tevtStartAssocByMTSUser 18
+#define tevtReleaseAssocByMTSUser 23
+#define tevtDLExpansion 26
+#define tevtRedirection 28
+#define tevtRerouting 29
+#define tevtDowngrading 31
+#define tevtReportAbsorption 33
+#define tevtReportGenerated 34
+#define tevtUnroutableReportDiscard 43
+#define tevtMessageLocalDelivery 1000
+#define tevtMessageBackboneTransferIn 1001
+#define tevtMessageBackboneTransferOut 1002
+#define tevtMessageGatewayTransferOut 1003
+#define tevtMessageGatewayTransferIn 1004
+#define tevtReportGatewayTransferIn 1005
+#define tevtReportGatewayTransferOut 1006
+#define tevtReportGatewayGenerated 1007
+#define tevtUserMin 2000
+ /* size is 60 */
+typedef struct __MIDL_TriggerPublicRPC_0005
+ {
+ RPC_INT nEventType;
+ RPC_SYSTEMTIME stEvent;
+ RPC_SZ szGatewayName;
+ RPC_SZ szPartner;
+ RPC_SZ szMTSID;
+ RPC_SZ szRemoteID;
+ RPC_SZ szOriginator;
+ RPC_INT nPriority;
+ RPC_INT nLength;
+ RPC_INT nSeconds;
+ RPC_INT nCost;
+ RPC_SZ szSubjectID;
+ } RPC_GATEWAY_TRACK_INFORMATION;
+
+ /* size is 4 */
+RPC_SC __cdecl ScSaveGatewayTrackingData(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_GATEWAY_TRACK_INFORMATION __RPC_FAR *pgti,
+ /* [in] */ RPC_INT cszRecipients,
+ /* [size_is][in] */ RPC_SZ __RPC_FAR rgszRecipients[ ]);
+
+
+
+extern RPC_IF_HANDLE TriggerPublicRPC_ClientIfHandle;
+extern RPC_IF_HANDLE TriggerPublicRPC_ServerIfHandle;
+#endif /* __TriggerPublicRPC_INTERFACE_DEFINED__ */
+
+/****************************************
+ * Generated header for interface: __MIDL__intf_0001
+ * at Mon Jan 29 16:52:25 1996
+ * using MIDL 2.00.0104
+ ****************************************/
+/* [local] */
+
+
+#define szTrackReportRecipientInfoDelivered L("\t0")
+#define szTrackReportRecipientInfoNonDelivered L("\t1")
+
+
+extern RPC_IF_HANDLE __MIDL__intf_0001_ClientIfHandle;
+extern RPC_IF_HANDLE __MIDL__intf_0001_ServerIfHandle;
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/private/utils/ntbackup/exchange/inc/sadapi.h b/private/utils/ntbackup/exchange/inc/sadapi.h
new file mode 100644
index 000000000..ce471ed40
--- /dev/null
+++ b/private/utils/ntbackup/exchange/inc/sadapi.h
@@ -0,0 +1,197 @@
+/*
+ * sadapi.h
+ *
+ * Copyright (c) Microsoft Corp. 1986-1996. All Rights Reserved.
+ *
+ * Definition of the public RPC APIs from the SAD Exchange service
+ *
+ */
+
+
+#ifndef _SADLIB_H_
+#define _SADLIB_H_
+
+#include <rpcpub.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+/*
+ * Return codes for all functions except SAD_EcGetProxies() and SAD_EcGetProxiesBI().
+ * In addition to this list are all normal NT error codes...
+ */
+typedef enum _SC_RETURN_VALUES
+{
+ SC_OK = 0, // no error
+ SC_Error = 49001, // general error
+ SC_BPActive, // bulk proxy generation is currently running
+ SC_BPInactive, // bulk proxy generation is not currently running
+ SC_BPShutdownPending, // a shutdown in bulk proxy generation is in progress
+ SC_BPSiteAddressMismatch, // a Site Address Mismatch between rgszOldSiteAddress
+ // and rgszNewSiteAddress lists in ScBulkUpdateMultiProxy
+} SC_RETURN_VALUES;
+
+
+#define cchMaxServer (MAX_COMPUTERNAME_LENGTH + 1)
+
+typedef struct _RPCBINDINFO
+{
+ handle_t h;
+ WCHAR wszServer[cchMaxServer];
+ RPC_IF_HANDLE hClientIfHandle;
+} RPCBINDINFO, *PRPCBINDINFO;
+
+
+// Utility entry points
+RPC_SC WINAPI SAD_ScBindA(PRPCBINDINFO pBI, LPSTR szServer);
+RPC_SC WINAPI SAD_ScBindW(PRPCBINDINFO pBI, LPWSTR wszServer);
+void WINAPI SAD_Unbind(PRPCBINDINFO pBI);
+
+#ifdef UNICODE
+#define SAD_ScBind SAD_ScBindW
+#else
+#define SAD_ScBind SAD_ScBindA
+#endif
+
+
+
+// Message Tracking group
+RPC_SC WINAPI SAD_ScSaveGatewayTrackingData(PRPCBINDINFO pBI,
+ RPC_GATEWAY_TRACK_INFORMATION * pgti,
+ INT cszRecipients,
+ LPWSTR rgwszRecipients[]);
+
+// for Microsoft Internal Use ONLY
+RPC_SC WINAPI SAD_ScSaveTrackingData(PRPCBINDINFO pBI, INT cb, BYTE pb[], DWORD dwFlags);
+
+
+// for Gateways - cause the routing table to be recalculated
+RPC_SC WINAPI SAD_ScRunRIDA(LPSTR szServer);
+RPC_SC WINAPI SAD_ScRunRIDW(LPWSTR wszServer);
+RPC_SC WINAPI SAD_ScRunRIDExA(LPSTR szServer, RPC_BOOL fProxySpace, RPC_BOOL fGwart);
+RPC_SC WINAPI SAD_ScRunRIDExW(LPWSTR wszServer, RPC_BOOL fProxySpace, RPC_BOOL fGwart);
+
+#ifdef UNICODE
+#define SAD_ScRunRID SAD_ScRunRIDW
+#define SAD_ScRunRIDEx SAD_ScRunRIDExW
+#else
+#define SAD_ScRunRID SAD_ScRunRIDA
+#define SAD_ScRunRIDEx SAD_ScRunRIDExA
+#endif
+
+
+
+// Proxy Entry points
+
+RPC_EC WINAPI SAD_EcGetProxies(LPWSTR wszServer, PPROXYINFO pProxyInfo, PPROXYLIST pProxyList);
+RPC_EC WINAPI SAD_EcGetProxiesBI(PRPCBINDINFO pBI, PPROXYINFO pProxyInfo, PPROXYLIST pProxyList);
+void WINAPI SAD_FreeProxyListNode(PPROXYNODE pnode);
+RPC_SC WINAPI SAD_ScIsProxyUniqueA(LPSTR szServer,
+ LPSTR szProxy, RPC_BOOL * pfUnique, LPSTR * pszExisting);
+RPC_SC WINAPI SAD_ScIsProxyUniqueW(LPWSTR wszServer,
+ LPWSTR szProxy, RPC_BOOL * pfUnique, LPWSTR * pszExisting);
+
+// dwOptions values for SAD_ScBulkCreateProxy() and SAD_ScBulkCreateMultiProxy()
+#define BPTAdd 1
+#define BPTRemove 2
+#define BPTUpdate 3
+
+RPC_SC WINAPI SAD_ScBulkCreateProxyA(LPSTR szServer, LPSTR szHeader, DWORD dwOptions);
+RPC_SC WINAPI SAD_ScBulkCreateProxyW(LPWSTR wszServer, LPWSTR wszHeader, DWORD dwOptions);
+RPC_SC WINAPI SAD_ScBulkCreateMultiProxyA(LPSTR szServer,
+ INT cszHeader,
+ LPSTR rgszHeader[],
+ DWORD dwOptions);
+RPC_SC WINAPI SAD_ScBulkCreateMultiProxyW(LPWSTR wszServer,
+ INT cwszHeader,
+ LPWSTR rgwszHeader[],
+ DWORD dwOptions);
+RPC_SC WINAPI SAD_ScBulkUpdateMultiProxy(LPWSTR wszServer,
+ INT cwszSiteAddress,
+ LPWSTR rgwszOldSiteAddress[],
+ LPWSTR rgwszNewSiteAddress[],
+ RPC_BOOL fSaveSiteAddress);
+
+
+RPC_SC WINAPI SAD_ScGetBulkProxyStatusA(LPSTR szServer,
+ RPC_SYSTEMTIME * pstTimeStart,
+ DWORD * pdwTimeStart,
+ DWORD * pdwTimeCur,
+ INT * piRecipients,
+ INT * pcRecipients);
+RPC_SC WINAPI SAD_ScGetBulkProxyStatusW(LPWSTR wszServer,
+ RPC_SYSTEMTIME * pstTimeStart,
+ DWORD * pdwTimeStart,
+ DWORD * pdwTimeCur,
+ INT * piRecipients,
+ INT * pcRecipients);
+RPC_SC WINAPI SAD_ScBulkProxyHaltA(LPSTR szServer, RPC_BOOL fWaitForShutdown);
+RPC_SC WINAPI SAD_ScBulkProxyHaltW(LPWSTR wszServer, RPC_BOOL fWaitForShutdown);
+
+#ifdef UNICODE
+#define SAD_ScIsProxyUnique SAD_ScIsProxyUniqueW
+#define SAD_ScBulkCreateProxy SAD_ScBulkCreateProxyW
+#define SAD_ScBulkCreateMultiProxy SAD_ScBulkCreateMultiProxyW
+#define SAD_ScGetBulkProxyStatus SAD_ScGetBulkProxyStatusW
+#define SAD_ScBulkProxyHalt SAD_ScBulkProxyHaltW
+#else
+#define SAD_ScIsProxyUnique SAD_ScIsProxyUniqueA
+#define SAD_ScBulkCreateProxy SAD_ScBulkCreateProxyA
+#define SAD_ScBulkCreateMultiProxy SAD_ScBulkCreateMultiProxyA
+#define SAD_ScGetBulkProxyStatus SAD_ScGetBulkProxyStatusA
+#define SAD_ScBulkProxyHalt SAD_ScBulkProxyHaltA
+#endif
+
+
+
+
+
+
+// Backup entry point (available only in UNICODE!)
+
+RPC_SC WINAPI SAD_ScGetBackupListNodeW(LPWSTR wszServer, BackupListNode ** ppnode);
+void WINAPI SAD_FreeBackupListNode(BackupListNode * pnode);
+
+
+// Run DRA Check calling parameters (dwCheck)
+#define INTRASITE_CHECK 0
+#define INTERSITE_CHECK 1
+
+RPC_SC WINAPI SAD_ScRunDRACheck(LPWSTR wszServer, RPC_DWORD dwCheck);
+
+
+
+// These few lines (or equivalent) need to be supplied by the application that links
+// with SADAPI.LIB.
+#ifdef _SAMPLE_CODE
+void __RPC_FAR * __RPC_API midl_user_allocate(size_t cb)
+{
+ void * pv;
+
+ pv = GlobalAlloc(GMEM_FIXED, cb);
+ if (!pv)
+ RpcRaiseException(RPC_S_OUT_OF_MEMORY);
+
+ return pv;
+}
+
+void __RPC_API midl_user_free(void __RPC_FAR * pv)
+{
+ GlobalFree(pv);
+}
+#endif
+
+
+
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // #ifndef _SADLIB_H_
diff --git a/private/utils/ntbackup/exchange/readme.txt b/private/utils/ntbackup/exchange/readme.txt
new file mode 100644
index 000000000..bc2ba8226
--- /dev/null
+++ b/private/utils/ntbackup/exchange/readme.txt
@@ -0,0 +1,8 @@
+The files below this directory are coppied from Exchange's
+tdcommon directory.
+
+Please to not modify. Simply copy the updates from the
+\\iyf\src\tdcommon directory
+
+Thanks,
+Steve
diff --git a/private/utils/ntbackup/inc/abort.h b/private/utils/ntbackup/inc/abort.h
new file mode 100644
index 000000000..7c068fd3c
--- /dev/null
+++ b/private/utils/ntbackup/inc/abort.h
@@ -0,0 +1,30 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: abort.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+ Location: BE_PUBLIC
+
+
+ $Log: G:/LOGFILES/ABORT.H_V $
+ *
+ * Rev 1.0 09 May 1991 13:31:00 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef _abort_h_
+#define _abort_h_
+
+#define CONTINUE_PROCESSING ( ( INT8 ) 0 )
+#define ABORT_CTRL_BREAK ( ( INT8 )-1 )
+#define ABORT_AT_EOM ( ( INT8 )-2 )
+#define ABORT_PROCESSED ( ( INT8 )-3 )
+
+#endif
diff --git a/private/utils/ntbackup/inc/add_icon.h b/private/utils/ntbackup/inc/add_icon.h
new file mode 100644
index 000000000..c71c1d282
--- /dev/null
+++ b/private/utils/ntbackup/inc/add_icon.h
@@ -0,0 +1,36 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: add_icon.h
+
+ Description: Dialog item IDs for adding an icon.
+
+ $Log: G:/UI/LOGFILES/ADD_ICON.H_V $
+
+ Rev 1.3 04 Oct 1992 19:46:10 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.2 06 Apr 1992 09:56:12 CHUCKB
+Added define for translation.
+
+ Rev 1.1 27 Jan 1992 12:50:52 GLENN
+Fixed dialog IDs.
+
+*******************************************************************************/
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_JOBPROGMANITEM 32
+#else
+#include "dlg_ids.h"
+#endif
+
+#ifndef _add_icon_h_
+
+#define _add_icon_h_
+
+#define IDD_J_JOBS 0x0068
+#define IDD_J_PMGROUPS 0x0069
+
+#endif
diff --git a/private/utils/ntbackup/inc/adv_rest.h b/private/utils/ntbackup/inc/adv_rest.h
new file mode 100644
index 000000000..4855399ae
--- /dev/null
+++ b/private/utils/ntbackup/inc/adv_rest.h
@@ -0,0 +1,35 @@
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_ADVRESTORE 7
+#else
+#include "dlg_ids.h"
+#endif
+
+#define IDD_A_INCL 106
+#define IDD_A_EXCL 107
+#define IDD_A_SUBDIRS 108
+#define IDD_A_PATH 110
+#define IDD_A_FILE 111
+#define IDD_A_TMONTH 126
+#define IDD_A_TDAY 127
+#define IDD_A_TYEAR 128
+#define IDD_A_FMONTH 129
+#define IDD_A_FDAY 130
+#define IDD_A_FYEAR 131
+#define IDD_A_FROMBOX 141
+#define IDD_A_TOBOX 142
+
+#define IDD_A_ALLFILES 0x016D
+#define IDD_A_RANGE 0x016F
+#define IDD_A_FROM_LEFT 0x0195
+#define IDD_A_TO_LEFT 0x0196
+#define IDD_A_FROM_RIGHT 0x0199
+#define IDD_A_TO_RIGHT 0x019A
+#define IDD_A_DEVICE 0x0167
+#define IDD_A_BACKUPSET 0x0168
+
+#define IDD_A_BACKUPSETLABEL 0x0169
+#define IDD_A_PATHLABEL 0x0202
+#define IDD_A_FILELABEL 0x0203
+#define IDD_A_DEVICELABEL 0x0166
+
diff --git a/private/utils/ntbackup/inc/adv_sel.h b/private/utils/ntbackup/inc/adv_sel.h
new file mode 100644
index 000000000..4e6c32807
--- /dev/null
+++ b/private/utils/ntbackup/inc/adv_sel.h
@@ -0,0 +1,61 @@
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_SELECTADVANCED 3
+#else
+#include "dlg_ids.h"
+#endif
+
+#define IDD_A_DATES 105
+#define IDD_A_INCL 106
+#define IDD_A_EXCL 107
+#define IDD_A_SUBDIRS 108
+#define IDD_A_ONLYMOD 109
+#define IDD_A_PATH 110
+#define IDD_A_FILE 111
+#define IDD_A_TARGPATH 112
+#define IDD_A_NOTDEL 114
+#define IDD_A_ONLYDEL 115
+#define IDD_A_NOTACC 116
+#define IDD_A_NUMDAYS 117
+#define IDD_A_PITIME 118
+#define IDD_A_SALFILES 119
+#define IDD_A_HID 120
+#define IDD_A_READONLY 121
+#define IDD_A_SYS 122
+#define IDD_A_GROUP 123
+#define IDD_A_BEFORE 124
+#define IDD_A_AFTER 125
+#define IDD_A_TMONTH 126
+#define IDD_A_TDAY 127
+#define IDD_A_TYEAR 128
+#define IDD_A_FMONTH 129
+#define IDD_A_FDAY 130
+#define IDD_A_FYEAR 131
+#define IDD_SELECT_BOX 132
+#define IDD_UP 140
+#define IDD_A_FROMBOX 141
+#define IDD_A_TOBOX 142
+
+#define IDD_A_ALLFILES 0x016D
+#define IDD_A_ALLMOD 0x016E
+#define IDD_A_LASTNDAYS 0x0170
+#define IDD_A_RANGE 0x016F
+#define IDD_A_FROM 0x0191
+#define IDD_A_TO 0x0192
+#define IDD_A_FROM_1 0x0193
+#define IDD_A_TO_1 0x0194
+#define IDD_A_FROM_LEFT 0x0195
+#define IDD_A_TO_LEFT 0x0196
+#define IDD_A_FROM_2 0x0197
+#define IDD_A_TO_2 0x0198
+#define IDD_A_FROM_RIGHT 0x0199
+#define IDD_A_TO_RIGHT 0x019A
+#define IDD_A_FROM_3 0x019B
+#define IDD_A_TO_3 0x019C
+#define IDD_A_DEVICE 0x0167
+#define IDD_A_NUMWIN 0x0168
+
+#define IDD_THE_LAST 0xFFEE
+#define IDD_DAYS 0xFFEF
+
diff --git a/private/utils/ntbackup/inc/adv_serv.h b/private/utils/ntbackup/inc/adv_serv.h
new file mode 100644
index 000000000..573018eb9
--- /dev/null
+++ b/private/utils/ntbackup/inc/adv_serv.h
@@ -0,0 +1,53 @@
+
+#include "dlg_ids.h"
+
+#define IDD_A_DATES 105
+#define IDD_A_INCL 106
+#define IDD_A_EXCL 107
+#define IDD_A_SUBDIRS 108
+#define IDD_A_ONLYMOD 109
+#define IDD_A_PATH 110
+#define IDD_A_FILE 111
+#define IDD_A_TARGPATH 112
+#define IDD_A_NOTDEL 114
+#define IDD_A_ONLYDEL 115
+#define IDD_A_NOTACC 116
+#define IDD_A_NUMDAYS 117
+#define IDD_A_PITIME 118
+#define IDD_A_SALFILES 119
+#define IDD_A_HID 120
+#define IDD_A_READONLY 121
+#define IDD_A_SYS 122
+#define IDD_A_GROUP 123
+#define IDD_A_BEFORE 124
+#define IDD_A_AFTER 125
+#define IDD_A_TMONTH 126
+#define IDD_A_TDAY 127
+#define IDD_A_TYEAR 128
+#define IDD_A_FMONTH 129
+#define IDD_A_FDAY 130
+#define IDD_A_FYEAR 131
+#define IDD_SELECT_BOX 132
+#define IDD_UP 140
+#define IDD_A_FROMBOX 141
+#define IDD_A_TOBOX 142
+
+#define IDD_A_ALLFILES 0x016D
+#define IDD_A_ALLMOD 0x016E
+#define IDD_A_LASTNDAYS 0x0170
+#define IDD_A_RANGE 0x016F
+#define IDD_A_FROM 0x0191
+#define IDD_A_TO 0x0192
+#define IDD_A_FROM_1 0x0193
+#define IDD_A_TO_1 0x0194
+#define IDD_A_FROM_LEFT 0x0195
+#define IDD_A_TO_LEFT 0x0196
+#define IDD_A_FROM_2 0x0197
+#define IDD_A_TO_2 0x0198
+#define IDD_A_FROM_RIGHT 0x0199
+#define IDD_A_TO_RIGHT 0x019A
+#define IDD_A_FROM_3 0x019B
+#define IDD_A_TO_3 0x019C
+#define IDD_A_DEVICE 0x0167
+#define IDD_A_NUMWIN 0x0168
+
diff --git a/private/utils/ntbackup/inc/afp_fs.h b/private/utils/ntbackup/inc/afp_fs.h
new file mode 100644
index 000000000..fa389ece5
--- /dev/null
+++ b/private/utils/ntbackup/inc/afp_fs.h
@@ -0,0 +1,301 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: afp_fs.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+ Location:
+
+
+ $Log: N:/LOGFILES/AFP_FS.H_V $
+ *
+ * Rev 1.14 05 Jan 1993 13:21:22 CHUCKB
+ * Change per code review (took out AFP_IsBlkComplete).
+ *
+ * Rev 1.13 03 Dec 1992 16:48:24 CHUCKB
+ * Added prototype for AFP_IsBlockComplete().
+ *
+ * Rev 1.12 25 Nov 1992 10:51:10 CHUCKB
+ * Made changes for MTF 4.0.
+ *
+ * Rev 1.11 25 Sep 1992 16:08:18 CARLS
+ * added AFP_GetDispSizeDBLK
+ *
+ * Rev 1.10 24 Sep 1992 17:28:44 CHUCKB
+ * Changes for Graceful Red.
+ *
+ * Rev 1.9 22 Sep 1992 17:15:00 CHUCKB
+ * Removed references to fs_GetTotalSizeDBLK().
+ *
+ * Rev 1.8 17 Sep 1992 13:51:54 CHUCKB
+ * Changed return type of prototype for AFP_DetachDLE().
+ *
+ * Rev 1.7 28 Aug 1992 16:09:48 BARRY
+ * Added some 64-bit structures.
+ *
+ * Rev 1.6 28 May 1992 10:39:36 BARRY
+ * Added search mode support prototypes.
+ *
+ * Rev 1.5 20 Dec 1991 09:13:10 STEVEN
+ * move common functions into tables
+ *
+ * Rev 1.4 10 Sep 1991 18:18:36 DON
+ * if NLM, then handles need to be INT32
+ *
+ * Rev 1.3 15 Aug 1991 14:18:08 DON
+ * if OS_NLM, need a LONG trust_index
+ *
+ * Rev 1.2 23 May 1991 18:20:46 BARRY
+ * Remove prototype for function that's been removed.
+ *
+ * Rev 1.1 23 May 1991 16:46:38 BARRY
+ * Changes for FindFirst/Next to scan for dirs only
+ *
+ * Rev 1.0 09 May 1991 13:31:02 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef AFP_FS_H
+#define AFP_FS_H
+
+typedef struct AFP_FILE_HAND_STRUCT {
+#if defined(OS_NLM)
+ UINT32 res_hand ;
+ UINT32 data_hand ;
+#else
+ UINT8 res_hand ;
+ UINT8 data_hand ;
+#endif
+ UINT32 res_size ;
+ UINT32 data_size ;
+ UINT32 res_offset ;
+ UINT32 data_offset ;
+ UINT32 trust_size ;
+ UINT32 trust_offset ;
+ UINT8 trust_format ;
+#if defined(OS_NLM)
+ UINT32 trust_index ; /* Holds trust read index between calls */
+#else
+ UINT16 trust_index ; /* Holds trust read index between calls */
+#endif
+ CHAR file_name[14] ; /* File name for subsequent trust calls */
+
+ UINT64 nextStreamHeaderPosition;
+ UINT64 objPos; /* Object position on restore */
+ UINT64 dataStart; /* Position start of stream's data */
+ UINT32 active_stream_id ; /* id of the stream being processed */
+
+} AFP_FILE_HAND_STRUCT, *AFP_FILE_HAND;
+
+typedef struct AFP_RESERVED_SH_STRUCT {
+ INT16 fhdl ; /* AFP file handle */
+ INT16 active ; /* is stream being processed */
+ STREAM_INFO sh ; /* AFP reserved stream info */
+} AFP_RESERVED_SH, *AFP_RESERVED_SH_PTR ;
+
+ /* sizeof FILE_HAND plus afp reserved struct */
+#define FS_SIZEOF_RESERVED_FILE_HAND \
+ ( sizeof(FILE_HAND_STRUCT) + sizeof(AFP_RESERVED_SH) )
+
+INT16 AFP_FindDrives( DLE_HAND hand, BE_CFG_PTR cfg, UINT32 mask );
+
+INT16 AFP_AttachToDLE(
+ FSYS_HAND fsh, /* I - File system handle */
+ GENERIC_DLE_PTR dle, /*I/O- drive to attach to. list element expanded */
+ CHAR_PTR u_name, /* I - user name NOT USED */
+ CHAR_PTR pswd ); /* I - passowrd NOT USED */
+
+INT16 AFP_DetachDLE( FSYS_HAND fsh ) ;
+
+INT16 AFP_PopMinDDB( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+INT16 AFP_PushMinDDB(
+ FSYS_HAND fsh,
+ DBLK_PTR dblk ) ;
+
+INT16 AFP_FindFirst(
+ FSYS_HAND fsh,
+ DBLK_PTR dblk,
+ CHAR_PTR sname,
+ UINT16 find_type );
+
+INT16 AFP_GetObjInfo(
+ FSYS_HAND fsh ,
+ DBLK_PTR dblk );
+
+INT16 AFP_VerObjInfo(
+ FSYS_HAND fsh,
+ DBLK_PTR dblk ) ;
+
+INT16 AFP_SetObjInfo(
+ FSYS_HAND fsh,
+ DBLK_PTR dblk );
+
+
+INT16 AFP_FindNext(
+ FSYS_HAND fsh,
+ DBLK_PTR dblk ) ;
+
+INT16 AFP_ChangeDir(
+ FSYS_HAND fsh,
+ CHAR_PTR path,
+ INT16 psize ) ;
+
+INT16 AFP_UpDir( FSYS_HAND fsh ) ;
+
+INT16 AFP_GetCurrentPath(
+ FSYS_HAND fsh,
+ CHAR_PTR path,
+ INT16 *size );
+
+INT16 AFP_GetBasePath(
+ FSYS_HAND fsh,
+ CHAR_PTR base_path,
+ INT16 *size );
+
+INT16 AFP_GetCurrentDDB(
+ FSYS_HAND fsh,
+ DBLK_PTR dblk );
+
+INT16 AFP_GetSpecDBLKS(
+ FSYS_HAND fsh,
+ DBLK_PTR dblk,
+ INT32 *index ) ;
+
+INT16 AFP_DeleteObj(
+ FSYS_HAND fsh,
+ DBLK_PTR dblk ) ;
+
+INT16 AFP_MatchDBLK(
+ FSYS_HAND fsh,
+ DBLK_PTR dblk1,
+ DBLK_PTR dblk2,
+ BOOLEAN disp_flag,
+ struct FSE *fse) ;
+
+INT16 AFP_SetAFPInfo( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+
+INT16 AFP_CreateObj(
+ FSYS_HAND fsh,
+ DBLK_PTR dblk );
+
+INT16 AFP_OpenObj(
+ FSYS_HAND fsh,
+ FILE_HAND *hand,
+ DBLK_PTR dblk,
+ OPEN_MODE mode ) ;
+
+INT16 AFP_CloseObj( FILE_HAND hand ) ;
+
+INT16 AFP_ReadObj(
+ FILE_HAND hand,
+ CHAR_PTR buf,
+ UINT16 *size,
+ UINT16 *blk_size,
+ STREAM_INFO_PTR s_info ) ;
+
+INT16 AFP_SeekObj(
+ FILE_HAND hand,
+ UINT32 *offset );
+
+INT16 AFP_VerObj(
+ FILE_HAND hand,
+ CHAR_PTR buf,
+ CHAR_PTR data,
+ UINT16 *size,
+ UINT16 *blk_size,
+ STREAM_INFO_PTR s_info ) ;
+
+INT16 AFP_WriteObj(
+ FILE_HAND hand,
+ CHAR_PTR buf,
+ UINT16 *size,
+ UINT16 *blk_size,
+ STREAM_INFO_PTR s_info ) ;
+
+
+INT16 AFP_ModFnameFDB( FSYS_HAND fsh, BOOLEAN set_it, DBLK_PTR fdb, CHAR_PTR buf, INT16 *size );
+
+INT16 AFP_ModPathDDB( FSYS_HAND fsh, BOOLEAN set_it, DBLK_PTR fdb, CHAR_PTR buf, INT16 *size );
+
+INT16 AFP_GetOSFnameFDB( DBLK_PTR fdb, CHAR_PTR buf );
+
+INT16 AFP_GetOSPathDDB( FSYS_HAND fsh, DBLK_PTR fdb, CHAR_PTR buf );
+
+INT16 AFP_GetDirIDinDDB( DBLK_PTR ddb, CHAR_PTR buf );
+
+INT16 AFP_GetCdateDBLK( DBLK_PTR dblk, DATE_TIME *buf ) ;
+
+INT16 AFP_ModBdateDBLK( BOOLEAN set_it, DBLK_PTR dblk, DATE_TIME *buf ) ;
+
+INT16 AFP_GetMdateDBLK( DBLK_PTR dblk, DATE_TIME *buf ) ;
+
+INT16 AFP_ModAdateDBLK( BOOLEAN set_it, DBLK_PTR dblk, DATE_TIME *buf ) ;
+
+UINT64 AFP_GetDisplaySizeDBLK( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+
+INT16 AFP_GetFileVerFDB( DBLK_PTR dblk, UINT32 *ver ) ;
+
+INT16 AFP_ModAttribDBLK( BOOLEAN get_set, DBLK_PTR dblk, UINT32 *attrib) ;
+
+INT16 AFP_GetObjTypeDBLK( DBLK_PTR dblk, OBJECT_TYPE *type ) ;
+
+INT16 AFP_GetOS_InfoDBLK( DBLK_PTR dblk, CHAR_PTR os_info, INT16 *size ) ;
+
+INT16 AFP_GetActualSizeDBLK( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+
+INT16 AFP_SizeofFname( FSYS_HAND fsh, DBLK_PTR fdb ) ;
+
+INT16 AFP_SizeofOSFname( FSYS_HAND fsh, DBLK_PTR fdb ) ;
+
+INT16 AFP_SizeofOSPath( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+INT16 AFP_SizeofDirID( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+INT16 AFP_SizeofPath( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+INT16 AFP_SizeofOSInfo( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+INT16 AFP_CreateFDB( FSYS_HAND fsh, GEN_FDB_DATA_PTR data ) ;
+
+INT16 AFP_CreateDDB( FSYS_HAND fsh, GEN_DDB_DATA_PTR data ) ;
+
+VOID AFP_SetOwnerId( FSYS_HAND fsh, DBLK_PTR dblk, UINT32 id ) ;
+
+INT16 AFP_ChangeIntoDDB( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+INT16 AFP_GetFileInfo386( FSYS_HAND fsh, DBLK_PTR fdb ) ;
+
+INT16 AFP_GetDirInfo386( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+INT16 AFP_GetSearchMode( FSYS_HAND fsh, DBLK_PTR fdb ) ;
+
+INT16 AFP_SetFileInfo386( FSYS_HAND fsh, DBLK_PTR fdb ) ;
+
+UINT64 AFP_GetDispSizeDBLK( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+
+UINT16 AFP_SpecExcludeObj( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR ddb, /* I - Descriptor block of ddb */
+ DBLK_PTR fdb ) ; /* I - Descriptor block of fdb */
+
+UINT16 AFP_SetDataSize( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR ddb, /* I - Descriptor block of ddb */
+ UINT32 size ) ; /* I - new size */
+
+VOID AFP_CheckBindClose( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+
+INT16 AFP_ChangeIntoSubDir( FSYS_HAND fsh, CHAR_PTR l_path,
+ CHAR_PTR s_name, UINT32 entry_id ) ;
+
+VOID AFP_InitMakeData( FSYS_HAND fsh,
+ INT16 blkType,
+ CREATE_DBLK_PTR data );
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/afpdblk.h b/private/utils/ntbackup/inc/afpdblk.h
new file mode 100644
index 000000000..8e5b5a630
--- /dev/null
+++ b/private/utils/ntbackup/inc/afpdblk.h
@@ -0,0 +1,149 @@
+/** :IH1: Copyright (C) Maynard Electronics, Inc 1984-89
+
+:Name: afpcblk.h
+
+:Description: This file contains the definition of the Novell
+ file and directory control blocks.
+
+:Units: Novell < 2.15 File System
+
+
+ $Log: N:/LOGFILES/AFPDBLK.H_V $
+ *
+ * Rev 1.2 05 Jan 1993 17:41:44 CHUCKB
+ * Added some defines per code review.
+ *
+ * Rev 1.1 28 Aug 1992 16:10:28 BARRY
+ * No longer need nov386.h.
+ *
+ * Rev 1.0 09 May 1991 13:31:00 HUNTER
+ * Initial revision.
+
+
+
+**/
+
+#ifndef afpdblk_h
+#define afpdblk_h
+
+/* miximum Novell string lengths */
+#define AFP_MAX_FSIZE 33
+#define AFP_MAX_FLENGTH 32
+
+#define AFP_MAX_SHORT_NAME 16
+#define AFP_MAX_SHORT_PATH 255
+
+#define AFP_NET_HAND_SIZE 6
+
+#define AFP_READ_ONLY 1
+#define AFP_HIDDEN 2
+#define AFP_SYSTEM 4
+#define AFP_EXECUTE 8
+#define AFP_SUBDIR 0x10
+#define AFP_ARCHIVE 0x20
+#define AFP_SHARE 0x80
+#define AFP_TRANS 0x10
+#define AFP_INDEX 0x20
+#define AFP_IN_USE 0x8000
+#define AFP_EMPTY_DIR 0x8000
+
+/* Bit values for the AFP set info bit map */
+#define AFP_SET_ATTRIBUTES 0x0001 /* Set DOS and extended attrs */
+#define AFP_SET_CREATE_DATE 0x0002 /* Set creation date */
+#define AFP_SET_ACCESS_DATE 0x0004 /* Set last access date */
+#define AFP_SET_MODIFY_DATE 0x0008 /* Set modify date and time */
+#define AFP_SET_BACKUP_DATE 0x0010 /* Set archive date and time */
+#define AFP_SET_ALL_INFO 0xffff /* Set all fields */
+
+#define CONVERT_DOS_ATTRIB( atrib ) ((UINT32)(attrib) << 16 )
+
+/* defines used for FSYS_HAND reserved space */
+#define BIND_CLOSED 0x80
+#define BIND_FILE1 0x01 /* NET$BIND or NET$OBJ */
+#define BIND_FILE2 0x02 /* NET$BVAL or NET$VAL */
+#define BIND_FILE3 0x04 /* NET$PROP */
+#define BIND_ALL_286 0x03
+#define BIND_ALL_386 0x07
+
+
+typedef struct AFPNOV_COMMON {
+ UINT32 search_id ; /* */
+ UINT32 entry_id ; /* request */
+ CHAR filespec[AFP_MAX_FSIZE];
+
+
+ UINT16 attrib ;
+ UINT16 create_date ;
+ UINT16 access_date ; /* empty for directories */
+ UINT16 modify_date ;
+ UINT16 modify_time ;
+ UINT16 backup_date ;
+ UINT16 backup_time ;
+ UINT8 finder_info[32] ;
+ UINT8 long_name[AFP_MAX_FSIZE - 1] ;
+ UINT32 owner_id ;
+ CHAR short_name[15] ;
+
+ BOOLEAN os_info_complete ;
+ UINT16 tape_attribs ;
+
+} AFPNOV_COMMON ;
+
+typedef struct AFP_FDB {
+ UINT8 blk_type ; /* block id = FDB_ID */
+ COM_DBLK fs_reserved ;
+
+ AFPNOV_COMMON com ;
+
+ UINT32 data_fork_size ;
+ UINT32 data_fork_offset;
+ UINT32 res_fork_size ;
+ UINT32 res_fork_offset ;
+
+ UINT16 os_name ; /* for backup will be short name */
+
+ NOVELL_386_FILE info_386 ;
+
+} AFP_FDB, *AFP_FDB_PTR ;
+
+
+typedef struct AFP_DDB {
+ UINT8 blk_type ; /* block id = DDB_ID */
+ COM_DBLK fs_reserved ;
+
+ AFPNOV_COMMON com ;
+
+ UINT16 data_size ;
+ UINT32 creat_date ;
+ UINT8 max_rights ;
+ UINT32 trust_fork_size ;
+ UINT32 trust_fork_offset;
+
+ INT16 path_leng ;
+ UINT16 path ; /* short path names \FRED\SUE */
+
+ UINT16 long_path; /* long name for backup :FRED:SUE */
+ INT16 long_path_leng ;
+
+ UINT16 os_path; /* short name for backup */
+ INT16 os_path_leng ;
+
+ UINT8 trust_fork_format ;
+ NOVELL_386_DIR info_386 ;
+
+} AFP_DDB, *AFP_DDB_PTR;
+
+/*
+ Minimal DDB
+*/
+typedef struct AFP_MIN_DDB {
+ Q_ELEM q ;
+ UINT32 search_id ;
+ UINT32 entry_id ;
+ CHAR filespec[ AFP_MAX_FSIZE ] ; /* search path */
+ CHAR_PTR path; /* path made of short names */
+ CHAR_PTR long_path; /* path made from long names */
+} AFP_MIN_DDB, *AFP_MIN_DDB_PTR;
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/afplib.h b/private/utils/ntbackup/inc/afplib.h
new file mode 100644
index 000000000..57119dc70
--- /dev/null
+++ b/private/utils/ntbackup/inc/afplib.h
@@ -0,0 +1,86 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: afplib.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+ Location:
+
+
+ $Log: N:/LOGFILES/AFPLIB.H_V $
+ *
+ * Rev 1.3 25 Nov 1992 10:51:18 CHUCKB
+ * Made changes for MTF 4.0.
+ *
+ * Rev 1.2 13 Aug 1991 09:54:22 DAVIDH
+ * Updated for NLM.
+ *
+ * Rev 1.1 23 May 1991 16:46:16 BARRY
+ * Changes for FindFirst/Next to scan for dirs only
+ *
+ * Rev 1.0 09 May 1991 13:31:20 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#define AFP_FORK_IND_DATA 0x00
+#define AFP_FORK_IND_RES 0x01
+
+#define AFP_DENY_NONE 0
+#define AFP_DENY_ALL 12
+#define AFP_DENY_WRITE 8
+
+#define AFP_READ_ACCESS 1
+#define AFP_WRITE_ACCESS 2
+#define AFP_VERIFY_ACCESS 0x81
+
+#define AFP_ACCESS_FILTER 0xf
+
+#ifndef afpdblk_h
+#include "afpdblk.h"
+#endif
+
+UINT32 AFP_GetEntryId(
+#if OS_NLM
+ FSYS_HAND fsh, /* I - File system handle used to get current path */
+#else
+ UINT8 drive_hand, /* I - Netware directory handle */
+#endif
+ CHAR_PTR path ) ; /* I - Netware path from handle */
+
+INT16 ScanDirAFP(
+ FSYS_HAND fsh,
+ DBLK_PTR dblk,
+ UINT16 find_type ) ;
+
+INT16 GetFileInfoAFP(
+ FSYS_HAND fsh ,
+ DBLK_PTR dblk ) ;
+
+INT16 AFP_AllocTempHand( FSYS_HAND fsh, UINT32 entry_id, UINT8 *dir_hand ) ;
+
+INT16 AFP_GetIdForDDB(
+ FSYS_HAND fsh,
+ CHAR_PTR path,
+ UINT32 *id ) ;
+
+INT16 AFP_GetMaxRights(
+ FSYS_HAND fsh,
+ UINT32 entry_id,
+ UINT8 *max_rights,
+ UINT32 *creat_date ) ;
+
+INT16 GetShortNameAFP( FSYS_HAND, CHAR_PTR, CHAR_PTR, UINT32 * ) ;
+
+INT16 AFP_FixPathInCurDDB( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+
+INT16 AFP_LowLevelOpen( FSYS_HAND, AFP_FDB_PTR, UINT8 *, UINT8, UINT32 *, INT8 ) ;
+
+VOID ConvertHandAFP( FSYS_HAND fsh, CHAR_PTR net_hand, UINT32 fork_size,
+ UINT8 mode, UINT8 *dos_hand );
+
diff --git a/private/utils/ntbackup/inc/all.h b/private/utils/ntbackup/inc/all.h
new file mode 100644
index 000000000..b6d7f7768
--- /dev/null
+++ b/private/utils/ntbackup/inc/all.h
@@ -0,0 +1,48 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <conio.h>
+#include <ctype.h>
+#include <io.h>
+#include <dos.h>
+#include <fcntl.h>
+#include <time.h>
+#include <string.h>
+#include <share.h>
+#include <direct.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys\types.h>
+#include <sys\stat.h>
+
+#ifndef OS_WIN32 //16-bit specific stuff
+# include <bios.h>
+#endif
+
+#include <windows.h>
+#ifdef OS_WIN32 //32-bit specific stuff
+# include <port1632.h>
+#endif
+
+#include <dde.h>
+
+#include <commdlg.h> //common dialog types, etc.
+
+
+#if !defined( OEM_MSOFT ) // Microsoft app doesn't have email feature
+#include <mapi.h> // email
+#endif
+
+#include "portdefs.h"
+#include "stdtypes.h"
+#include "bengine.h"
+
+#ifdef OS_WIN32
+# include "omevent.h"
+#endif
+
+#ifndef SOME
+# include "some.h"
+#endif
+
+
diff --git a/private/utils/ntbackup/inc/appdefs.h b/private/utils/ntbackup/inc/appdefs.h
new file mode 100644
index 000000000..b05d189c4
--- /dev/null
+++ b/private/utils/ntbackup/inc/appdefs.h
@@ -0,0 +1,177 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: appdefs.h
+
+ Description: This file includes global definitions.
+
+ $Log: G:/UI/LOGFILES/APPDEFS.H_V $
+
+ Rev 1.19 01 Mar 1994 15:52:22 STEVEN
+the compiler decides what a character's value is. We should be specific
+
+ Rev 1.18 16 Nov 1993 20:40:44 STEVEN
+increase size of temp strings
+
+ Rev 1.17 14 May 1993 16:21:14 CHUCKB
+Changed max tape password length to 32 for this week.
+
+ Rev 1.16 30 Apr 1993 16:04:00 GLENN
+Added Log file root name size stuff.
+
+ Rev 1.15 19 Apr 1993 15:19:12 GLENN
+Changed max tape name, bset name, bset description.
+
+ Rev 1.14 08 Apr 1993 17:33:32 chrish
+Changed NTPASSWORDPREFIX.
+
+ Rev 1.13 13 Nov 1992 17:40:54 chrish
+Increased tape password length to 256. Added stuff for Tape Security for NT.
+
+ Rev 1.12 01 Nov 1992 16:29:58 DAVEV
+Unicode changes
+
+ Rev 1.11 22 Oct 1992 14:06:12 DAVEV
+remove typedefs of LPSHORT & LPUSHORT
+
+ Rev 1.10 04 Oct 1992 19:46:16 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.9 19 May 1992 10:35:08 MIKEP
+mips changes
+
+ Rev 1.8 20 Apr 1992 13:51:44 GLENN
+Added define for status line text size.
+
+ Rev 1.7 10 Mar 1992 14:01:12 JOHNWT
+fixed block copy error
+
+ Rev 1.6 02 Mar 1992 17:38:00 CARLS
+added define for MAX_READ_TAPE_PASSWORD
+
+ Rev 1.5 19 Feb 1992 10:17:14 ROBG
+Added MAX_UI_FULLPATH_LEN, MAX_UI_SMALLRES_LEN.
+
+ Rev 1.4 11 Feb 1992 11:56:24 MIKEP
+bump size of filenames
+
+ Rev 1.3 06 Feb 1992 17:44:02 JOHNWT
+added pwdb things
+
+ Rev 1.2 23 Jan 1992 12:32:10 GLENN
+Added window title length and size definitions.
+
+ Rev 1.1 10 Jan 1992 16:48:34 DAVEV
+16/32 bit port-2nd pass
+
+ Rev 1.0 20 Nov 1991 19:42:12 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+#ifndef APPDEFS_H
+
+#define APPDEFS_H
+
+
+//
+// Special character added to beginning of the tape password when the
+// NTBACKUP application secures a tape. This character is also stored onto
+// the tape as the tape password under NTBACKUP app.
+//
+#define NTPASSWORDPREFIX ((CHAR)(254)) // This is an ASCII 254
+ // character
+
+//
+// Global Defines
+//
+
+#define MAX_READ_TAPE_PASSWORD_LEN 128
+#define MAX_READ_TAPE_PASSWORD_SIZE (MAX_TAPE_PASSWORD_LEN+1)
+
+#define MAX_TAPE_PASSWORD_LEN 32
+#define MAX_TAPE_PASSWORD_SIZE (MAX_TAPE_PASSWORD_LEN+1)
+
+#define MAX_UI_FILENAME_LEN 255
+#define MAX_UI_FILENAME_SIZE (MAX_UI_FILENAME_LEN+1)
+
+#define MAX_UI_PATH_LEN 255
+#define MAX_UI_PATH_SIZE (MAX_UI_PATH_LEN+1)
+
+#define MAX_UI_FULLPATH_LEN (MAX_UI_PATH_LEN+MAX_UI_FILENAME_LEN)
+#define MAX_UI_FULLPATH_SIZE (MAX_UI_PATH_LEN+MAX_UI_FILENAME_LEN+1)
+
+#define MAX_TAPE_NAME_LEN 50
+#define MAX_TAPE_NAME_SIZE (MAX_TAPE_NAME_LEN+1)
+
+#define MAX_BSET_NAME_LEN 50
+#define MAX_BSET_NAME_SIZE (MAX_BSET_NAME_LEN+1)
+
+#define MAX_BSET_DESC_LEN 50
+#define MAX_BSET_DESC_SIZE (MAX_BSET_DESC_LEN+1)
+
+#define MAX_GROUPNAME_LEN 30
+#define MAX_GROUPNAME_SIZE (MAX_GROUPNAME_LEN+1)
+
+#define MAX_UI_DATE_LEN 30
+#define MAX_UI_DATE_SIZE (MAX_UI_DATE_LEN+1)
+
+#define MAX_UI_TIME_LEN 30
+#define MAX_UI_TIME_SIZE (MAX_UI_TIME_LEN+1)
+
+#define MAX_UI_RESOURCE_LEN 255
+#define MAX_UI_RESOURCE_SIZE (MAX_UI_RESOURCE_LEN+1)
+
+#define MAX_UI_LOGFILEROOT_LEN 6
+#define MAX_UI_LOGFILEROOT_SIZE (MAX_UI_LOGFILEROOT_LEN+1)
+
+// Use small resources length for very small strings.
+
+#define MAX_UI_SMALLRES_LEN 30
+#define MAX_UI_SMALLRES_SIZE (MAX_UI_SMALLRES_LEN+1)
+
+#define MAX_UI_WIN_TITLE_LEN 130
+#define MAX_UI_WIN_TITLE_SIZE (MAX_UI_WIN_TITLE_LEN+1)
+
+#define MAX_STATUS_LINE_LEN 100
+#define MAX_STATUS_LINE_SIZE (MAX_STATUS_LINE_LEN+1)
+
+#define MAX_ENCRYPTION_KEY_SIZE 24
+#define PASSWORD_SIGNATURE_SIZE 12
+
+// These must match the defines used in other products (ie 3.1) if
+// the PWDB is to be moveable between products, especially the
+// DBPW_KEY. If the lock keys are not the same, we can not recognize
+// a locked PWDB and will allow anyone to use it !
+
+#define MAX_PWDBASE_REC_SIZE 230
+#define MAX_LOCKPW_LEN 20
+#define MAX_LOCKPW_SIZE MAX_LOCKPW_LEN+1
+#define DBPW_KEY TEXT("8% øîÈ") // key for lock password
+#define DBPW_NODBPW TEXT("&%@!Ú(") // pw to indicate lock removed
+
+#define GB_TMP_STRING_SIZE 2000
+
+#define ENG_REV_MAJ 1
+#define ENG_REV_MIN 0
+
+#define MKT_VER_MAJ 1
+#define MKT_VER_MIN 0
+
+#define NOT_LOGGING 0
+#define NOW_LOGGING 1
+#define STOP_LOGGING 2
+
+
+// ????? remove as many of the following as possible. Change all references
+// to LMHANDLE and LMHANDLE_PTR to the appropriate memory casts.
+
+typedef CHAR FAR * LMHANDLE ;
+typedef void FAR * LMHANDLE_PTR ;
+
+#define XOR( x, y ) ( (!x && y) || (x && !y) )
+
+
+#endif
diff --git a/private/utils/ntbackup/inc/aspi.h b/private/utils/ntbackup/inc/aspi.h
new file mode 100644
index 000000000..240413f7f
--- /dev/null
+++ b/private/utils/ntbackup/inc/aspi.h
@@ -0,0 +1,7 @@
+#ifndef ASPI_RH
+
+#define ASPI_RH
+
+#define SES_ENG_ASPI 0
+
+#endif
diff --git a/private/utils/ntbackup/inc/backgrnd.h b/private/utils/ntbackup/inc/backgrnd.h
new file mode 100644
index 000000000..e8f21078c
--- /dev/null
+++ b/private/utils/ntbackup/inc/backgrnd.h
@@ -0,0 +1,126 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: backgrnd.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+ Location:
+
+
+ $Log: N:/LOGFILES/BACKGRND.H_V $
+ *
+ * Rev 1.1 11 Sep 1991 09:59:18 DON
+ * changed 'far' to PTR_SIZE - defined in stdtypes.h for portability
+ *
+ * Rev 1.0 09 May 1991 13:31:04 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+/**
+ :IH1: Copyright (C) Maynard Electronics, Inc. 1984-89
+
+ :Name: backgrnd.h
+
+ :Description: Contains the function prototypes for the background
+ process manager.
+
+ The data structure required by applications to use the
+ background process manager is listed below:
+
+ typedef struct { ... } BACKGROUND_CONTROL;
+
+ The application must allocate and pass a structure
+ of type BACKGROUND_CONTROL to the InstallBackgroundRoutine
+ function. The structure must be static until it is
+ passed to the RemoveBackgroundRoutine function.
+
+ The interfaces to the background process manager are
+ listed below:
+
+ VOID InstallBackgroundRoutine( BACKGRND_CONTROL_PTR control_elem_ptr,
+ BACKGRND_FUNC_PTR func_ptr );
+
+ This function installs a function to be called repeatedly
+ in the background, behind the main program.
+
+
+ VOID RemoveBackgroundRoutine( BACKGRND_CONTROL_PTR control_elem_ptr );
+
+ This function removes a previously installed background routine.
+ The control_elem_ptr must point to the same structure which was
+ passed to the InstallBackgroundRoutine.
+
+ The InstallInt28Routine and RemoveInt28Routine functions work
+ similarly, except that the handlers they install are called
+ when DOS is idling at the prompt (DOS alternates between issuing
+ a no-wait keyboard read and calling interrupt 28).
+
+ InstallBackgroundHooks traps the interrupt vectors necessary for
+ background processing. RemoveBackgroundHooks restores the vectors
+ to their system defaults.
+
+ Since background routines are frequently used to schedule
+ processes to occur at a later time the following macros are
+ provided
+
+ TIME() - returns a UINT32 representing the number of
+ clock ticks since the first background
+ routine was installed.
+
+ NO_TIMEOUT - a value which TIME() will always be less than.
+
+ $Header: N:/LOGFILES/BACKGRND.H_V 1.1 11 Sep 1991 09:59:18 DON $
+
+ $Log$
+
+ Rev 2.0 18 May 1990 19:06:36 PAT
+ Baseline Maynstream 3.1
+**/
+
+
+
+#ifndef BACKGRND
+#define BACKGRND
+
+
+typedef UINT32 TIMEOUT_VALUE;
+extern TIMEOUT_VALUE background_timer;
+
+
+typedef Q_ELEM BACKGRND_CONTROL;
+
+typedef BACKGRND_CONTROL PTR_SIZE *BACKGRND_CONTROL_PTR;
+
+#define BACKGRND_FUNC PF_VOID
+
+typedef enum { CallerIPX,CallerInt28 } CallerType;
+
+typedef VOID (PTR_SIZE *BACKGRND_FUNC_PTR)( CallerType caller );
+
+#define INTR_NUM (0x1C)
+
+
+
+VOID InstallBackgroundRoutine( BACKGRND_CONTROL_PTR control_elem_ptr, BACKGRND_FUNC_PTR func_ptr );
+VOID RemoveBackgroundRoutine( BACKGRND_CONTROL_PTR control_elem_ptr );
+VOID InstallInt28Routine( BACKGRND_CONTROL_PTR control_elem_ptr, BACKGRND_FUNC_PTR func_ptr );
+VOID RemoveInt28Routine( BACKGRND_CONTROL_PTR control_elem_ptr );
+VOID InstallBackgroundHooks( VOID );
+VOID RemoveBackgroundHook( VOID );
+
+extern UINT8 In28Hook;
+
+#define TIME() background_timer
+#define NO_TIMEOUT ( (UINT32) ( (TIMEOUT_VALUE) 1) << (((sizeof(TIMEOUT_VALUE)-1)*8) - 1) )
+
+#endif
+
+
+
+
diff --git a/private/utils/ntbackup/inc/be_debug.h b/private/utils/ntbackup/inc/be_debug.h
new file mode 100644
index 000000000..d6c939bcb
--- /dev/null
+++ b/private/utils/ntbackup/inc/be_debug.h
@@ -0,0 +1,51 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: be_debug.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: header for debug printing
+
+ Location: BE_PRIVATE
+
+
+ $Log: M:/LOGFILES/BE_DEBUG.H_V $
+ *
+ * Rev 1.1 22 Sep 1992 10:39:42 ChuckS
+ * Added DEBUG_REGISTER_ERR define for use of RegisterError
+ *
+ * Rev 1.0 09 May 1991 15:50:02 STEVEN
+ * Initial revision.
+ *
+ * Rev 1.0 09 May 1991 13:31:04 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef BE_DEBUG_H
+#define BE_DEBUG_H
+
+/* The following defines are a copy of the ones in UI's debug.h */
+
+#define DEBUG_TEMPORARY 0x0000
+#define DEBUG_USER_INTERFACE 0x0001
+#define DEBUG_LOOPS 0x0002
+#define DEBUG_FILE_SYSTEM 0x0004
+#define DEBUG_CATALOGS 0x0008
+#define DEBUG_REMOTE_DRIVE 0x0010
+#define DEBUG_TAPE_FORMAT 0x0020
+#define DEBUG_DEVICE_DRIVER 0x0040
+#define DEBUG_REGISTER_ERROR 0x0080
+#define DEBUG_TEMP_WIN_END 0x8000
+
+VOID BE_Zprintf( UINT16 mask_bits, ... ) ;
+
+/* Close your eyes! You really don't want to see what follows */
+
+/* Copy the resource defines from the user interface */
+#include "eng_dbug.h"
+
+#endif
diff --git a/private/utils/ntbackup/inc/be_init.h b/private/utils/ntbackup/inc/be_init.h
new file mode 100644
index 000000000..5e515a119
--- /dev/null
+++ b/private/utils/ntbackup/inc/be_init.h
@@ -0,0 +1,108 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: be_init.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Definition of be_init structure, various defines and
+ function prototypes.
+
+ Location: BE_PUBLIC
+
+
+ $Log: Q:/LOGFILES/BE_INIT.H_V $
+ *
+ * Rev 1.9 22 Jul 1993 11:34:40 ZEIR
+ * Add'd software_name to be_init_str for MTF
+ *
+ * Rev 1.8 09 Jun 1993 15:24:16 MIKEP
+ * enable c++
+ *
+ * Rev 1.7 23 Jan 1992 15:23:56 CLIFF
+ * Added BE_InitLW function
+ *
+ * Rev 1.6 14 Nov 1991 09:16:18 BARRY
+ * Moved file system init specifiers from be_init.h to fsys_str.h.
+ *
+ * Rev 1.5 24 Oct 1991 15:28:22 BARRY
+ * TRICYCLE: Added file_systems bit-mask field to BE_INIT_STR and
+ * created #defines for each file system.
+ *
+ * Rev 1.4 17 Oct 1991 01:41:00 ED
+ * BIGWHEEL - 8200sx - Added catalog_directory to BE_INIT sruct.
+ *
+ * Rev 1.3 27 Jun 1991 15:35:22 JOHNW
+ * Added driver_directory field to be_init structure.
+ *
+ * Rev 1.2 21 Jun 1991 13:23:26 BARRY
+ * Changes for new config.
+ *
+ * Rev 1.1 04 Jun 1991 19:12:42 BARRY
+ * Removed ControlBreak handler stuff--moved to os-specific modules.
+ *
+ * Rev 1.0 09 May 1991 13:30:58 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef _be_init_h_
+#define _be_init_h_
+
+#include <stdarg.h>
+#include "dilhwd.h"
+
+/*
+ Initialization parameter block
+*/
+typedef struct BE_INIT_STR *BE_INIT_STR_PTR;
+typedef struct BE_INIT_STR {
+ UINT16 units_to_init ;
+ struct BSD_LIST **bsd_list_ptr ;
+ struct HEAD_DLE **dle_list_ptr ;
+ struct THW **thw_list_ptr ;
+ BOOLEAN (*critical_error_handler)( CHAR_PTR, UINT16 ) ;
+ VOID (*debug_print)( UINT16, CHAR_PTR, va_list ) ;
+ DIL_HWD_PTR dhwd_ptr ;
+ CHAR driver_name[ 84 ] ;
+ UINT16 number_of_cards ;
+ UINT16 max_channels ;
+ UINT16 tf_buffer_size ;
+ UINT16 remote_filter ;
+ struct VM_STR *vm_hand ;
+ CHAR_PTR driver_directory ;
+ CHAR_PTR catalog_directory ;
+ UINT32 file_systems ; /* Bits set to pick and choose */
+ CHAR_PTR software_name ;
+} BE_INIT_STR ;
+
+/*
+ Error returns
+*/
+#define BE_INIT_SUCCESS 0
+#define BE_FILE_SYS_FAIL -10000
+#define BE_TAPE_FMT_FAIL -10001
+#define BE_SMB_FAIL -10002
+#define BE_NRL_FAIL -10003
+#define BE_BSDU_FAIL -10004
+
+/* defines for units to init */
+#define BE_INIT_FSYS BIT0
+#define BE_INIT_BSDU BIT1
+#define BE_INIT_TFL BIT2
+#define BE_INIT_ALL 0xffff
+
+/*
+ Prototypes
+*/
+
+VOID BE_InstallCtrlBreakHandler( VOID );
+VOID BE_RemoveCtrlBreakHandler( VOID );
+
+INT16 BE_Init( BE_INIT_STR_PTR be_ptr, struct BE_CFG * conf_ptr ) ;
+VOID BE_Deinit( struct HEAD_DLE * ) ;
+VOID BE_InitLW( BE_INIT_STR_PTR be_ptr ) ;
+#endif
+
diff --git a/private/utils/ntbackup/inc/be_tfutl.h b/private/utils/ntbackup/inc/be_tfutl.h
new file mode 100644
index 000000000..d9cb43589
--- /dev/null
+++ b/private/utils/ntbackup/inc/be_tfutl.h
@@ -0,0 +1,53 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: be_tfutl.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Prototypes for Backup Engine utility interface functions
+ for tape format layer calls
+
+ Location: BE_PUBLIC
+
+
+ $Log: J:/LOGFILES/BE_TFUTL.H_V $
+ *
+ * Rev 1.4 28 Jan 1993 09:25:54 DON
+ * Removed BE_EjectTape prototype
+ *
+ * Rev 1.3 09 Nov 1992 15:22:20 DON
+ * Added a prototype to allow UI to eject a tape
+ *
+ * Rev 1.2 13 Oct 1992 12:44:56 CHARLIE
+ * Added prototype for BE_NonNativeFormat
+ *
+ * Rev 1.1 28 Jun 1991 12:06:22 STEVEN
+ * Changes for new BE_CFG
+ *
+ * Rev 1.0 09 May 1991 13:30:32 HUNTER
+ * Initial revision.
+
+**/
+/* begin include list */
+#ifndef _be_tfl_xface_h_
+#define _be_tfl_xface_h_
+
+#include "thw.h"
+#include "be_init.h"
+/* $end$ include list */
+
+/* Defines for Multi-drive status check */
+#define BE_NO_MULTI_DRIVE 0
+#define BE_MULTI_DRIVE 1
+#define BE_END_OF_CHANNEL 2
+
+CHAR_PTR BE_GetCurrentDeviceName( UINT16 channel ) ;
+THW_PTR BE_GetCurrentDevice( UINT16 channel ) ;
+INT16 BE_ReinitTFLayer( BE_INIT_STR_PTR be_ptr, struct BE_CFG *cfg ) ;
+UINT8 BE_CheckMultiDrive( UINT16 channel ) ;
+BOOLEAN BE_DeviceWriteProtected( UINT16 channel ) ;
+BOOLEAN BE_NonNativeFormat( UINT16 channel ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/bec_prv.h b/private/utils/ntbackup/inc/bec_prv.h
new file mode 100644
index 000000000..bac29eb2c
--- /dev/null
+++ b/private/utils/ntbackup/inc/bec_prv.h
@@ -0,0 +1,31 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: bec_prv.h
+
+ Date Updated: 18-Jun-91
+
+ Description: Structures and definitions private to the Backup
+ Engine configuration unit.
+
+ $Log: N:/LOGFILES/BEC_PRV.H_V $
+
+ Rev 1.0 19 Jun 1991 10:38:56 BARRY
+Initial revision.
+
+**/
+
+#if !defined( BEC_PRV_H )
+#define BEC_PRV_H
+
+/*
+ * Queue of config structures along with counting semaphore
+ */
+typedef struct BE_CFG_QUEUE_ITEM {
+ BE_CFG_PTR cfg;
+ INT16 use_count;
+} BE_CFG_QITEM, *BE_CFG_QITEM_PTR;
+
+
+#endif /* BEC_PRV_H */
diff --git a/private/utils/ntbackup/inc/beconfig.h b/private/utils/ntbackup/inc/beconfig.h
new file mode 100644
index 000000000..6e2433bbf
--- /dev/null
+++ b/private/utils/ntbackup/inc/beconfig.h
@@ -0,0 +1,598 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: beconfig.h
+
+ Date Updated: 18-Jun-91
+
+ Description: Interface to the Backup Engine configuration unit.
+
+ $Log: Q:/LOGFILES/BECONFIG.H_V $
+
+ Rev 1.49 28 Jul 1993 15:21:16 TerriLynn
+Switched the values of SYPL on and off for ECC translation.
+
+ Rev 1.48 23 Jul 1993 12:13:04 TerriLynn
+Updated sypl defines per LANMAN Upgrade requirements
+
+ Rev 1.47 23 Jul 1993 11:44:26 TerriLynn
+Added extern for Sytron ECC flag
+
+ Rev 1.46 23 Jul 1993 10:59:12 TerriLynn
+Added specific SYPL defines for the
+new Sytron ECC flag.
+
+ Rev 1.45 21 Jul 1993 17:30:18 TerriLynn
+Added Process Sytron ECC Flag
+
+ Rev 1.44 01 Jul 1993 16:45:30 Aaron
+Added ProcSpecialFiles macros
+
+ Rev 1.43 30 Jun 1993 15:23:44 BARRY
+Add process_special_files
+
+ Rev 1.42 17 Jun 1993 16:42:50 DEBBIE
+Changed backup_without_expanding to backup_as_expanded.
+
+ Rev 1.41 09 Jun 1993 15:45:48 MIKEP
+enable c++
+
+ Rev 1.40 30 Apr 1993 16:42:44 DOUG
+Moved NRL_SPX_MaxIpxPacketSize out of CLient only #ifdef
+
+ Rev 1.39 19 Apr 1993 16:58:40 DOUG
+Added new NRL/TLI fields
+
+ Rev 1.38 30 Mar 1993 18:08:44 DON
+Changed migrated/compressed stuff!
+
+ Rev 1.37 24 Mar 1993 15:45:02 DEBBIE
+added fields and macros for migrated files and for uncompressing files
+
+ Rev 1.36 22 Mar 1993 16:49:18 JOHNES
+
+
+ Rev 1.35 19 Mar 1993 11:37:56 JOHNES
+Ifdef'ed out (from P_CLIENT) a bunch of GRFS related fields we don't use
+in the client.
+
+ Rev 1.34 16 Mar 1993 15:07:40 JOHNES
+Ifdef'ed out all references to keep_drive_list (for P_CLIENT only).
+
+ Rev 1.33 11 Mar 1993 11:44:20 ANDY
+Added GRFS and NRL parameters for ENDEAVOUR
+
+ Rev 1.32 01 Mar 1993 17:38:10 MARILYN
+added config option telling whether or not to process checksum streams
+
+ Rev 1.31 09 Feb 1993 10:00:52 DOUG
+Added Client supervisor mode flag
+
+ Rev 1.30 05 Feb 1993 22:32:28 MARILYN
+removed copy/move functionality
+
+ Rev 1.29 08 Dec 1992 14:24:32 DON
+Integrated Move/Copy into tips
+
+ Rev 1.28 08 Dec 1992 11:45:30 DOUG
+Added new GRFS and NRL parameters
+
+ Rev 1.27 13 Oct 1992 12:30:20 STEVEN
+added otc catalog level
+
+ Rev 1.26 28 Aug 1992 16:18:20 BARRY
+Added values for net_num.
+
+ Rev 1.25 23 Jul 1992 09:33:24 STEVEN
+fix warnings
+
+ Rev 1.24 21 May 1992 17:27:18 TIMN
+Added string type defines and partition name type
+
+ Rev 1.23 04 May 1992 12:22:40 STEVEN
+NT_STUFF added string types
+
+ Rev 1.22 02 Feb 1992 17:59:36 GREGG
+Fixed macro to set initial_buff_alloc.
+
+ Rev 1.21 02 Feb 1992 15:54:14 GREGG
+Removed utf_supported boolean from config, and added UINT16 initial_buff_alloc.
+
+ Rev 1.20 27 Jan 1992 18:16:00 GREGG
+Added new config element: utf_supported.
+
+ Rev 1.19 22 Jan 1992 10:49:48 DON
+added define for ENABLE_REMOTE_AFP to special word defines
+
+ Rev 1.18 13 Jan 1992 18:35:50 STEVEN
+added config switch for BSD sort
+
+ Rev 1.17 19 Nov 1991 13:14:32 STEVEN
+added wait time defines for SKIP_OPEN_FILES
+
+ Rev 1.16 14 Nov 1991 10:20:02 BARRY
+TRICYCLE: Added restore_security.
+
+ Rev 1.15 06 Nov 1991 18:37:24 GREGG
+BIGWHEEL - 8200sx - Added catalog_level to BE config.
+
+ Rev 1.14 02 Oct 1991 15:52:48 STEVEN
+BIGWEEL - Added support for Prompt before restore over existing
+
+ Rev 1.13 19 Sep 1991 12:57:12 STEVEN
+Added machine type to config structure
+
+ Rev 1.12 16 Aug 1991 08:59:50 STEVEN
+remove display_novell_servers from structure
+
+ Rev 1.11 12 Aug 1991 16:30:32 BARRY
+Removed macros BEC_GetDisplayNetwareServers() and
+BEC_SetDisplayNetwareServers().
+
+ Rev 1.10 23 Jul 1991 16:23:28 BARRY
+Added prototype for new function BEC_UpdateConfig.
+
+ Rev 1.9 22 Jul 1991 17:36:22 BARRY
+Fix max and min problem.
+
+ Rev 1.8 11 Jul 1991 15:55:08 BARRY
+Made definition of min and max each conditional.
+
+ Rev 1.7 01 Jul 1991 18:41:44 BARRY
+Fixed definition of min() and max(); fixed SetXXX macros.
+
+ Rev 1.6 01 Jul 1991 17:35:32 STEVEN
+added min and max
+
+ Rev 1.5 30 Jun 1991 12:36:52 BARRY
+Changes for partition routines, removal of default drive list.
+
+ Rev 1.4 28 Jun 1991 16:56:20 BARRY
+Got rid of default drive and SetKeepDrive().
+
+ Rev 1.3 26 Jun 1991 16:49:28 BARRY
+tfl_buff_size was misspelled.
+
+ Rev 1.2 25 Jun 1991 15:04:16 BRYAN
+Changed dos_drive_list to keep_drive_list
+
+ Rev 1.1 21 Jun 1991 10:16:18 STEVEN
+added macros and removed ifdefs
+
+ Rev 1.0 19 Jun 1991 10:39:40 BARRY
+Initial revision.
+
+**/
+
+#if !defined( BECONFIG_H )
+#define BECONFIG_H
+
+/*
+ * Since some systems define max and min as functions instead of macros,
+ * define a macro for our own max and min macros here.
+ */
+#define BEC_MIN(x,y) ((x) < (y) ? (x) : (y))
+#define BEC_MAX(x,y) ((x) > (y) ? (x) : (y))
+
+/* return value defines */
+#define BEC_ERR_BASE 0xff00 /* Need to verify this? */
+#define BEC_NOT_IN_QUEUE BEC_ERR_BASE + 1 /* Release of cfg not in Q */
+
+/* Definition of Special Word values */
+#define CREATE_FLOPPY_DLES 0x0002
+#define IGNORE_MAYNARD_ID 0x0020
+#define ENABLE_REMOTE_AFP 0x0040
+#define FAST_TDEMO 0x4000
+
+/* Values for net_num */
+#define NO_NET_DEFINED 0
+#define NOVELL_ADVANCED 1
+#define NOVELL_4_6 2
+#define IBM_PC_NET 3
+
+
+/* Definition of ExistFlag values */
+#define BEC_NO_REST_OVER_EXIST 0
+#define BEC_REST_OVER_EXIST 1
+#define BEC_PROMPT_REST_OVER_EXIST 2
+
+
+/* Definition of SkipOpenFiles values */
+#define BEC_WAIT_OPEN_FILES 0
+#define BEC_SKIP_OPEN_FILES 1
+#define BEC_TIME_WAIT_OPEN_FILES 2
+
+/* Cataloging Levels */
+#define CATALOGS_NONE 0
+#define CATALOGS_PARTIAL 1
+#define CATALOGS_FULL 2
+
+/* NT_STUFF string types */
+#define BEC_ANSI_STR 1
+#define BEC_UNIC_STR 2
+#define BEC_WIDE_STR BEC_UNIC_STR
+
+/* EMS stuff */
+#define BEC_EMS_PUBLIC 1
+#define BEC_EMS_PRIVATE 2
+#define BEC_EMS_BOTH 3
+
+#if defined(OS_NLM)
+/* NRL Protocol types are bit-mapped flags */
+#define NRL_PROT_SPX 0x01
+#define NRL_PROT_TCP 0x02
+#define NRL_PROT_ADSP 0x04
+#endif /* OS_NLM */
+
+#define SYPL_ECC_AUTO 2 /* The default value */
+#define SYPL_ECC_ON 1 /* Forces procesing of Sytron ECC */
+#define SYPL_ECC_OFF 0 /* Depends on hardware ECC */
+
+typedef struct PART_ENTRY {
+ struct PART_ENTRY *next ;
+ INT16 drv_num ;
+ INT16 partition_num ;
+ INT8 partition_name[13] ;
+ INT16 partition_name_size ;
+} PART_ENTRY ;
+
+
+typedef struct BE_CFG *BE_CFG_PTR;
+typedef struct BE_CFG {
+ UINT16 special_word ; /* special word */
+ UINT16 max_buffers ; /* max number of tape buffers */
+ UINT16 reserve_mem ; /* amt not to give to buffers */
+ UINT16 tfl_buff_size ; /* buffer size for tape format*/
+ UINT16 max_buffer_size ; /* SMB maximum buffer size */
+ INT16 skip_open_files ; /* skip open files (NETWORK) */
+ INT16 backup_files_inuse ; /* try to backup files in use */
+ INT16 support_afp_server ; /* support AFP files on */
+ INT16 extended_date_support ; /* extended date support */
+ INT16 hidden_flg ; /* don't read hidden files */
+ INT16 special_flg ; /* don't read system files */
+ INT16 set_archive_flg ; /* set archive bit */
+ INT16 modified_only_flg ; /* backup modified stuff only */
+ INT16 proc_empty_flg ; /* restore empty directorys */
+ INT16 exist_flg ; /* restore existing files? */
+ INT16 prompt_flg ; /* prompt on restore */
+ PART_ENTRY *part_list ; /* partition list */
+#if !defined(P_CLIENT)
+ CHAR keep_drive_list[26 + 1] ; /* drives to keep */
+#endif /* !P_CLIENT */
+ INT16 net_num ; /* network number */
+ INT16 remote_drive_backup ; /* Remote drive backup enabled*/
+ BOOLEAN use_ffr ; /* true if user wants ffr */
+ UINT16 write_format ; /* To specify TF write format */
+ UINT16 nrl_dos_vector ;
+ BOOLEAN xlock ;
+ UINT16 machine_type ;
+ INT16 catalog_level ; /* Catalog level, 0=none, 1=partial, 2=full */
+ BOOLEAN restore_security ; /* Restore security info */
+ BOOLEAN sort_bsd_by_dle ; /* if true we sort the bsds by DLE */
+ UINT16 initial_buff_alloc ; /* mem allocated for tape buffers at init */
+ UINT16 string_types ;
+ UINT16 otc_cat_level ; /* on tape catalog requested level */
+ UINT16 max_remote_resources; /* cumulative sum of all remote resource buffers added */
+#if !defined(P_CLIENT)
+ CHAR backup_server_name[16 + 1] ; /* name of current backup server for netbios */
+#endif /* !P_CLIENT */
+ UINT16 NRL_transport_type; /* NRL transport type (SPX, NetBIOS */
+ UINT16 GRFS_timeout_seconds; /* GRFS response timeout (0=no timeout) */
+ UINT16 NRL_spx_max_ipx_packet ; /* NRL max allowable packet size */
+#if !defined(P_CLIENT)
+ UINT16 NRL_callback_stack_size ; /* NRL callback stack size */
+ UINT16 NRL_max_local_resources ; /* NRL cumulative local resources */
+ UINT16 NRL_max_con_connections ; /* NRL maximum allowed connections */
+#endif /* !P_CLIENT */
+ CHAR NRL_backup_server_list[100+1];/* NRL string of backup servers space delimited */
+#if !defined(P_CLIENT)
+ UINT16 NRL_spx_listens_per_sess ; /* NRL number of listen ecbs per session */
+ UINT16 NRL_spx_retry_count ; /* NRL spx number of times to retry a packet */
+ UINT16 NRL_nb_retry_count ; /* NRL NetBios number of times to retry a packet */
+#endif /* !P_CLIENT */
+ UINT16 NRL_nb_adapter_number; /* NRL adapter number for LAN */
+ CHAR NRL_nb_device_name[8+1]; /* NRL name of LAN device */
+#if !defined(P_CLIENT)
+ UINT16 GRFS_max_con_sessions; /* NRL maximum number of agents allowed */
+#endif /* !P_CLIENT */
+ BOOLEAN supervisor_mode; /* Is Client in Supervisor mode? */
+ BOOLEAN process_checksum_streams ; /* Generate a checksum stream for each stream written */
+#if !defined(P_CLIENT)
+ BOOLEAN backup_migrated_files ; /* backup migrated files */
+ BOOLEAN backup_as_expanded ; /* backup compressed files as expanded files */
+#endif /* !P_CLIENT */
+ /* and use this information to verify the integrity of */
+ /* said stream on tape. */
+#if defined(OS_NLM)
+ UINT16 NRL_protocols; /* NRL protocols to load */
+ UINT16 TCP_cleanup_interval; /* Seconds between TCP resource cleanup */
+ UINT16 TCP_listen_port; /* TCP port for resource listen thread */
+#endif
+ BOOLEAN process_special_files; /* process registry, etc. */
+ INT16 sypl_ecc_flg ; /* process sytron ecc */
+ INT16 ems_pub_pri ;
+ INT16 ems_rip_kick ;
+ INT16 ems_wipe_clean ;
+} BE_CFG;
+
+
+
+/* prototypes relating to the configuration unit */
+
+VOID BEC_Init( VOID ) ;
+VOID BEC_Close( VOID ) ;
+INT16 BEC_UseConfig( BE_CFG_PTR cfg );
+INT16 BEC_ReleaseConfig( BE_CFG_PTR cfg );
+BE_CFG_PTR BEC_CloneConfig( BE_CFG_PTR cfg );
+INT16 BEC_UpdateConfig( BE_CFG_PTR dst, BE_CFG_PTR src );
+
+INT8_PTR BEC_GetPartitionName( BE_CFG_PTR cfg, INT16 drv_num, INT16 part_num ) ;
+INT16 BEC_SetPartitionName( BE_CFG_PTR cfg, INT16 drv_num, INT16 part_num, INT8_PTR part_name, INT16 part_name_size ) ;
+PART_ENTRY *BEC_GetFirstPartition( BE_CFG_PTR cfg ) ;
+PART_ENTRY *BEC_GetNextPartition( BE_CFG_PTR cfg, PART_ENTRY *curr_part ) ;
+INT16 BEC_AddPartition( BE_CFG_PTR cfg, INT16 drv_num, INT16 part_num, INT8_PTR name, INT16 name_size ) ;
+
+#if !defined(P_CLIENT)
+ BOOLEAN BEC_KeepDrive( BE_CFG_PTR cfg, CHAR drv_letter ) ;
+#endif /* !P_CLIENT */
+
+VOID BEC_CheckNetworkType( VOID ) ;
+
+extern BE_CFG uw_max_cfg ;
+extern BE_CFG uw_min_cfg ;
+extern INT16 gnProcessSytronECC ;
+/*
+ * Accessing/setting macros.
+ */
+
+#define BEC_SetStringTypes( x, v ) ( (x)->string_types = (v) )
+#define BEC_GetStringTypes( x ) ( (x)->string_types )
+
+#define BEC_GetSpecialWord( x ) ( (x)->special_word )
+#define BEC_SetSpecialWord( x, v ) ( (x)->special_word = (v) )
+
+
+/**********************************************************************
+
+ Old tape buffer business.
+
+ #ifdef MAYN_OS2
+ #define BEC_GetMaxNumTapeBuffers( x ) ( (x)->max_num_tape_bufs )
+ #define BEC_SetMaxNumTapeBuffers( x, v ) ( (x)->max_num_tape_bufs = (v) )
+ #else
+ #define BEC_GetReserveMemory( x ) ( (x)->reserve_memory )
+ #define BEC_SetReserveMemory( x, v ) ( (x)->reserve_memory = (v) )
+ #endif
+
+**********************************************************************/
+
+#define BEC_GetMaxTapeBuffers( x ) ( (x)->max_buffers )
+#define BEC_SetMaxTapeBuffers( x, v ) ( (x)->max_buffers = \
+ BEC_MAX( BEC_MIN( (v), uw_max_cfg.max_buffers), uw_min_cfg.max_buffers ) )
+
+#define BEC_GetTFLBuffSize( x ) ( (x)->tfl_buff_size )
+#define BEC_SetTFLBuffSize( x, v ) ( (x)->tfl_buff_size = \
+ BEC_MAX( BEC_MIN( (v), uw_max_cfg.tfl_buff_size), uw_min_cfg.tfl_buff_size ) )
+
+#define BEC_GetReserveMem( x ) ( (x)->reserve_mem )
+#define BEC_SetReserveMem( x, v ) ( (x)->reserve_mem = \
+ BEC_MAX( BEC_MIN( (v), uw_max_cfg.reserve_mem), uw_min_cfg.reserve_mem ) )
+
+#define BEC_GetSkipOpenFiles( x ) ( (x)->skip_open_files )
+#define BEC_SetSkipOpenFiles( x, v ) ( (x)->skip_open_files = \
+ BEC_MAX( BEC_MIN( (v), uw_max_cfg.skip_open_files), uw_min_cfg.skip_open_files ) )
+
+#define BEC_GetBackupFilesInUse( x ) ( (x)->backup_files_inuse )
+#define BEC_SetBackupFilesInUse( x, v ) ( (x)->backup_files_inuse = \
+ BEC_MAX( BEC_MIN( (v), uw_max_cfg.backup_files_inuse), uw_min_cfg.backup_files_inuse ) )
+
+#define BEC_GetAFPSupport( x ) ( (x)->support_afp_server )
+#define BEC_SetAFPSupport( x, v ) ( (x)->support_afp_server = \
+ BEC_MAX( BEC_MIN( (v), uw_max_cfg.support_afp_server), uw_min_cfg.support_afp_server ) )
+
+#define BEC_GetExtendedDateSupport( x ) ( (x)->extended_date_support )
+#define BEC_SetExtendedDateSupport( x, v ) ( (x)->extended_date_support = \
+ BEC_MAX( BEC_MIN( (v), uw_max_cfg.extended_date_support), uw_min_cfg.extended_date_support ) )
+
+#define BEC_GetHiddenFlag( x ) ( (x)->hidden_flg )
+#define BEC_SetHiddenFlag( x, v ) ( (x)->hidden_flg = \
+ BEC_MAX( BEC_MIN( (v), uw_max_cfg.hidden_flg), uw_min_cfg.hidden_flg ) )
+
+#define BEC_GetSpecialFlag( x ) ( (x)->special_flg )
+#define BEC_SetSpecialFlag( x, v ) ( (x)->special_flg = \
+ BEC_MAX( BEC_MIN( (v), uw_max_cfg.special_flg), uw_min_cfg.special_flg ) )
+
+#define BEC_GetSetArchiveFlag( x ) ( (x)->set_archive_flg )
+#define BEC_SetSetArchiveFlag( x, v ) ( (x)->set_archive_flg = \
+ BEC_MAX( BEC_MIN( (v), uw_max_cfg.set_archive_flg), uw_min_cfg.set_archive_flg ) )
+
+#define BEC_GetModifiedOnlyFlag( x ) ( (x)->modified_only_flg )
+#define BEC_SetModifiedOnlyFlag( x, v ) ( (x)->modified_only_flg = \
+ BEC_MAX( BEC_MIN( (v), uw_max_cfg.set_archive_flg), uw_min_cfg.set_archive_flg ) )
+
+#define BEC_GetProcEmptyFlag( x ) ( (x)->proc_empty_flg )
+#define BEC_SetProcEmptyFlag( x, v ) ( (x)->proc_empty_flg = \
+ BEC_MAX( BEC_MIN( (v), uw_max_cfg.proc_empty_flg), uw_min_cfg.proc_empty_flg ) )
+
+#define BEC_GetExistFlag( x ) ( (x)->exist_flg )
+#define BEC_SetExistFlag( x, v ) ( (x)->exist_flg = \
+ BEC_MAX( BEC_MIN( (v), uw_max_cfg.exist_flg), uw_min_cfg.exist_flg ) )
+
+#define BEC_GetPromptFlag( x ) ( (x)->prompt_flg )
+#define BEC_SetPromptFlag( x, v ) ( (x)->prompt_flg = \
+ BEC_MAX( BEC_MIN( (v), uw_max_cfg.prompt_flg), uw_min_cfg.prompt_flg ) )
+
+#define BEC_GetPartList( x ) ( (x)->part_list )
+#define BEC_SetPartList( x, v ) ( (x)->part_list = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.part_list), uw_min_cfg.part_list ) )
+
+#define BEC_GetNetNum( x ) ( (x)->net_num )
+#define BEC_SetNetNum( x, v ) ( (x)->net_num = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.net_num), uw_min_cfg.net_num ) )
+
+#if !defined(P_CLIENT)
+ #define BEC_GetKeepDriveList( x ) ( (x)->keep_drive_list )
+#endif /* !P_CLIENT */
+
+#define BEC_GetRemoteDriveBackup( x ) ( (x)->remote_drive_backup )
+#define BEC_SetRemoteDriveBackup( x, v ) ( (x)->remote_drive_backup = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.remote_drive_backup), uw_min_cfg.remote_drive_backup ) )
+
+#define BEC_GetNRLDosVector( x ) ( (x)->nrl_dos_vector )
+#define BEC_SetNRLDosVector( x, v ) ( (x)->nrl_dos_vector = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.nrl_dos_vector), uw_min_cfg.nrl_dos_vector ) )
+
+#define BEC_GetMaxBufferSize( x ) ( (x)->max_buffer_size )
+#define BEC_SetMaxBufferSize( x, v ) ( (x)->max_buffer_size = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.max_buffer_size), uw_min_cfg.max_buffer_size ) )
+
+#define BEC_GetFastFileRestore( x ) ( (x)->use_ffr )
+#define BEC_SetFastFileRestore( x, v ) ( (x)->use_ffr = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.use_ffr), uw_min_cfg.use_ffr ) )
+
+#define BEC_GetWriteFormat( x ) ( (x)->write_format )
+#define BEC_SetWriteFormat( x, v ) ( (x)->write_format = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.write_format), uw_min_cfg.write_format ) )
+
+#define BEC_LockConfig( x ) ( (x)->xlock = 1 )
+#define BEC_UnLockConfig( x ) ( (x)->xlock = 0 )
+
+#define BEC_GetConfiguredMachineType( x ) ( (x)->machine_type )
+#define BEC_SetConfiguredMachineType( x, v ) ( (x)->machine_type = (v))
+
+#define BEC_GetCatalogLevel( x ) ( (x)->catalog_level )
+#define BEC_SetCatalogLevel( x, v ) ( (x)->catalog_level = (v) )
+
+#define BEC_GetOtcCatalogLevel( x ) ( (x)->otc_cat_level )
+#define BEC_SetOtcCatalogLevel( x, v ) ( (x)->otc_cat_level = (v) )
+
+#define BEC_GetRestoreSecurity( x ) ( (x)->restore_security )
+#define BEC_SetRestoreSecurity( x, v ) ( (x)->restore_security = ((v) ? TRUE : FALSE ))
+
+#define BEC_GetSortBSD( x ) ( (x)->sort_bsd_by_dle )
+#define BEC_SetSortBSD( x, v ) ( (x)->sort_bsd_by_dle = (v) )
+
+#define BEC_GetInitialBuffAlloc( x ) ( (x)->initial_buff_alloc )
+#define BEC_SetInitialBuffAlloc( x, v ) ( (x)->initial_buff_alloc = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.initial_buff_alloc ), uw_min_cfg.initial_buff_alloc ) )
+
+#define BEC_GetMaxRemoteResources( x ) ( (x)->max_remote_resources )
+#define BEC_SetMaxRemoteResources( x, v ) ( (x)->max_remote_resources = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.max_remote_resources), uw_min_cfg.max_remote_resources ) )
+
+#define BEC_GetInitialBuffAlloc( x ) ( (x)->initial_buff_alloc )
+#define BEC_SetInitialBuffAlloc( x, v ) ( (x)->initial_buff_alloc = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.initial_buff_alloc ), uw_min_cfg.initial_buff_alloc ) )
+
+#if !defined(P_CLIENT)
+ #define BEC_GetBackupServerName( x ) ( (x)->backup_server_name )
+ #define BEC_SetBackupServerName( x, v ) ( strcpy( (x)->backup_server_name, (v) ) )
+#endif /* !P_CLIENT */
+
+#define BEC_GetNRLTransportType( x ) ( (x)->NRL_transport_type )
+#define BEC_SetNRLTransportType( x, v ) ( (x)->NRL_transport_type = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.NRL_transport_type), uw_min_cfg.NRL_transport_type ) )
+
+#define BEC_GetGRFSTimeoutSeconds( x ) ( (x)->GRFS_timeout_seconds )
+#define BEC_SetGRFSTimeoutSeconds( x, v ) ( (x)->GRFS_timeout_seconds = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.GRFS_timeout_seconds), uw_min_cfg.GRFS_timeout_seconds ) )
+
+#define BEC_GetNRLSPXMaxIpxPacket( x ) ( (x)->NRL_spx_max_ipx_packet )
+#define BEC_SetNRLSPXMaxIpxPacket( x, v ) ( (x)->NRL_spx_max_ipx_packet = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.NRL_spx_max_ipx_packet ), uw_min_cfg.NRL_spx_max_ipx_packet ) )
+
+#if !defined(P_CLIENT)
+
+ #define BEC_GetNRLCallbackStackSize( x ) ( (x)->NRL_callback_stack_size )
+ #define BEC_SetNRLCallbackStackSize( x, v ) ( (x)->NRL_callback_stack_size = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.NRL_callback_stack_size), uw_min_cfg.NRL_callback_stack_size ) )
+
+ #define BEC_GetNRLMaxLocalResources( x ) ( (x)->NRL_max_local_resources )
+ #define BEC_SetNRLMaxLocalResources( x, v ) ( (x)->NRL_max_local_resources = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.NRL_max_local_resources), uw_min_cfg.NRL_max_local_resources ) )
+
+ #define BEC_GetNRLMaxConConnections( x ) ( (x)->NRL_max_con_connections )
+ #define BEC_SetNRLMaxConConnections( x, v ) ( (x)->NRL_max_con_connections = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.NRL_max_con_connections ), uw_min_cfg.NRL_max_con_connections ) )
+
+ #define BEC_GetNRLBackupServerList( x ) ( (x)->NRL_backup_server_list )
+ #define BEC_SetNRLBackupServerList( x, v ) ( strcpy( (x)->NRL_backup_server_list, (v) ) )
+
+ #define BEC_GetNRLSPXListensPerSess( x ) ( (x)->NRL_spx_listens_per_sess )
+ #define BEC_SetNRLSPXListensPerSess( x, v ) ( (x)->NRL_spx_listens_per_sess = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.NRL_spx_listens_per_sess ), uw_min_cfg.NRL_spx_listens_per_sess ) )
+
+ #define BEC_GetNRLSPXRetryCount( x ) ( (x)->NRL_spx_retry_count )
+ #define BEC_SetNRLSPXRetryCount( x, v ) ( (x)->NRL_spx_retry_count = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.NRL_spx_retry_count ), uw_min_cfg.NRL_spx_retry_count ) )
+
+ #define BEC_GetNRLNBRetryCount( x ) ( (x)->NRL_nb_retry_count )
+ #define BEC_SetNRLNBRetryCount( x, v ) ( (x)->NRL_nb_retry_count = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.NRL_nb_retry_count ), uw_min_cfg.NRL_nb_retry_count ) )
+#endif /* !P_CLIENT */
+
+#define BEC_GetNRLNBAdapterNumber( x ) ( (x)->NRL_nb_adapter_number )
+#define BEC_SetNRLNBAdapterNumber( x, v ) ( (x)->NRL_nb_adapter_number = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.NRL_nb_adapter_number ), uw_min_cfg.NRL_nb_adapter_number ) )
+
+#define BEC_GetNRLNBDeviceName( x ) ( (x)->NRL_nb_device_name )
+#define BEC_SetNRLNBDeviceName( x, v ) ( strcpy( (x)->NRL_nb_device_name, (v) ) )
+
+#if !defined(P_CLIENT)
+ #define BEC_GetGRFSMaxConSessions( x ) ( (x)->GRFS_max_con_sessions )
+ #define BEC_SetGRFSMaxConSessions( x, v ) ( (x)->GRFS_max_con_sessions = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.GRFS_max_con_sessions ), uw_min_cfg.GRFS_max_con_sessions ) )
+#endif /* !P_CLIENT */
+
+#define BEC_GetSupervisorMode( x ) ( (x)->supervisor_mode )
+#define BEC_SetSupervisorMode( x, v ) ( (x)->supervisor_mode = ((v) ? TRUE : FALSE ))
+
+#define BEC_GetProcChecksumStrm( x ) ( (x)->process_checksum_streams )
+#define BEC_SetProcChecksumStrm( x, v ) ( (x)->process_checksum_streams = ((v) ? TRUE : FALSE ))
+
+#define BEC_GetProcSpecialFiles( x ) ( (x)->process_special_files )
+#define BEC_SetProcSpecialFiles( x, v ) ( (x)->process_special_files = ((v) ? TRUE : FALSE ))
+
+#if !defined(P_CLIENT)
+
+ #define BEC_GetBackupMigratedFiles( x ) ( (x)->backup_migrated_files )
+ #define BEC_SetBackupMigratedFiles( x, v ) ( (x)->backup_migrated_files = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.backup_migrated_files ), uw_min_cfg.backup_migrated_files ) )
+
+ #define BEC_GetBackupAsExpanded( x ) ( (x)->backup_as_expanded )
+ #define BEC_SetBackupAsExpanded( x, v ) ( (x)->backup_as_expanded = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.backup_as_expanded ), uw_min_cfg.backup_as_expanded ) )
+#endif /* !P_CLIENT */
+
+#if defined(OS_NLM)
+
+#define BEC_GetNRLProtocolsSupported( x ) ( (x)->NRL_protocols )
+#define BEC_SetNRLProtocolsSupported( x, v ) ( (x)->NRL_protocols = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.NRL_protocols), uw_min_cfg.NRL_protocols ) )
+#define BEC_GetTCPCleanupInterval( x ) ( (x)->TCP_cleanup_interval )
+#define BEC_SetTCPCleanupInterval( x, v ) ( (x)->TCP_cleanup_interval = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.TCP_cleanup_interval), uw_min_cfg.TCP_cleanup_interval ) )
+#define BEC_GetTCPListenPort( x ) ( (x)->TCP_listen_port )
+#define BEC_SetTCPListenPort( x, v ) ( (x)->TCP_listen_port = \
+ BEC_MAX( BEC_MIN( ( v ), uw_max_cfg.TCP_listen_port), uw_min_cfg.TCP_listen_port ) )
+
+#endif /* OS_NLM */
+
+#define BEC_GetProcessSytronECCFlag( x ) ( (x)->sypl_ecc_flg )
+#define BEC_SetProcessSytronECCFlag( x, v ) ( (x)->sypl_ecc_flg = \
+ BEC_MAX( BEC_MIN( (v), uw_max_cfg.sypl_ecc_flg), uw_min_cfg.sypl_ecc_flg ) )
+
+#define BEC_GetEmsPubPri( x ) ( (x)->ems_pub_pri )
+#define BEC_SetEmsPubPri( x, v ) ( (x)->ems_pub_pri = \
+ BEC_MAX( BEC_MIN( (v), uw_max_cfg.ems_pub_pri), uw_min_cfg.ems_pub_pri ) )
+
+#define BEC_GetEmsRipKick( x ) ( (x)->ems_rip_kick )
+#define BEC_SetEmsRipKick( x, v ) ( (x)->ems_rip_kick = \
+ BEC_MAX( BEC_MIN( (v), uw_max_cfg.ems_rip_kick), uw_min_cfg.ems_rip_kick ) )
+
+#define BEC_GetEmsWipeClean( x ) ( (x)->ems_wipe_clean )
+#define BEC_SetEmsWipeClean( x, v ) ( (x)->ems_wipe_clean = \
+ BEC_MAX( BEC_MIN( (v), uw_max_cfg.ems_wipe_clean), uw_min_cfg.ems_wipe_clean ) )
+#endif /* BECONFIG_H */
+
diff --git a/private/utils/ntbackup/inc/bengine.h b/private/utils/ntbackup/inc/bengine.h
new file mode 100644
index 000000000..7f569ee35
--- /dev/null
+++ b/private/utils/ntbackup/inc/bengine.h
@@ -0,0 +1,82 @@
+
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: BENGINE.H
+
+ Description:
+
+ An include file for those of us who don't care which backup
+ engine files we need.
+
+ $Log: G:/UI/LOGFILES/BENGINE.H_V $
+
+ Rev 1.14 05 Aug 1993 16:29:12 MARINA
+added sleep.h
+
+ Rev 1.13 18 Jun 1993 16:52:24 CARLS
+removed MAYN_DEMO around tdemo.h
+
+ Rev 1.12 18 Jun 1993 16:46:10 CARLS
+added tdemo.h for NtDemo build
+
+ Rev 1.11 13 May 1993 11:39:28 MIKEP
+Untemporarily remove nrl.h
+
+ Rev 1.10 12 May 1993 12:04:36 Aaron
+Temporarily (?) removed nrl.h
+
+ Rev 1.9 04 Oct 1992 19:46:18 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.8 07 Jul 1992 16:03:30 MIKEP
+unicode changes
+
+ Rev 1.7 27 Jun 1992 17:58:54 MIKEP
+changes for qtc
+
+ Rev 1.6 14 May 1992 17:39:54 MIKEP
+nt pass2
+
+ Rev 1.5 11 May 1992 12:18:44 STEVEN
+move stdmath.c
+
+ Rev 1.4 11 May 1992 10:51:42 STEVEN
+stdmath
+
+ Rev 1.3 09 Dec 1991 10:07:48 MIKEP
+cut it down
+
+
+
+*****************************************************/
+
+// Bengine.H
+
+#ifndef BENGINE_H
+#define BENGINE_H
+
+#include "stdwcs.h"
+#include "fartypes.h"
+#include "stdmath.h"
+#include "lis.h"
+#include "be_tfutl.h"
+#include "be_init.h"
+#include "enc_pub.h"
+#include "loops.h"
+#include "tbe_defs.h"
+#include "tbe_err.h"
+#include "tfldefs.h"
+#include "tfpoll.h"
+#include "tflproto.h"
+#include "machine.h"
+#include "nrl.h"
+#include "qtc.h"
+#include "sleep.h"
+
+#ifdef OS_WIN32
+#include "tdemo.h"
+#endif
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/bitmaps.h b/private/utils/ntbackup/inc/bitmaps.h
new file mode 100644
index 000000000..c4885b214
--- /dev/null
+++ b/private/utils/ntbackup/inc/bitmaps.h
@@ -0,0 +1,200 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: bitmaps.h
+
+ Description: This file contains the BITMAP IDs for the Maynstream GUI
+ project.
+
+ $Log: G:/UI/LOGFILES/BITMAPS.H_V $
+
+ Rev 1.12 02 Apr 1993 13:51:22 GLENN
+Added info bitmaps for toolbar.
+
+ Rev 1.11 20 Jan 1993 20:57:22 MIKEP
+floppy
+
+ Rev 1.10 04 Oct 1992 19:46:20 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.9 09 Sep 1992 17:09:26 GLENN
+Added net connect and disconnect bitmap IDs.
+
+ Rev 1.8 20 Aug 1992 08:45:08 GLENN
+Added TAPES and TAPESINDRIVE bitmap stuff.
+
+ Rev 1.7 07 Jul 1992 10:14:26 MIKEP
+fix duplicate entry.
+
+ Rev 1.6 06 Jul 1992 10:32:48 MIKEP
+added ram and cdrom drives
+
+ Rev 1.5 03 Jun 1992 13:33:48 JOHNWT
+added empty dir bitmaps
+
+ Rev 1.4 22 Apr 1992 17:56:44 GLENN
+Added shark and diver bitmap stuff.
+
+ Rev 1.3 09 Mar 1992 09:19:24 GLENN
+Added logo bitmap support.
+
+ Rev 1.2 16 Dec 1991 17:05:40 GLENN
+Added exit button stuff.
+
+ Rev 1.1 15 Dec 1991 10:21:08 MIKEP
+hidden files
+
+ Rev 1.0 20 Nov 1991 19:34:36 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+// BITMAP RESOURCE IDs -- RANGE: 100 - 299
+// ( also used for Bitmap Table indexing)
+
+#define BM_OFFSET 100
+
+#define IDRBM_FLOPPYDRIVE 100 // Unfortunately, you can't add the
+#define IDRBM_HARDDRIVE 101 // BM_OFFSET directly to the base value
+#define IDRBM_RAMDRIVE 102 // to come up with the ID numbers.
+#define IDRBM_NETDRIVE 103 // The Windows' resource compiler can't
+#define IDRBM_TAPEDRIVE01 104 // handle it.
+#define IDRBM_TAPEDRIVE02 105
+#define IDRBM_TAPEDRIVE03 106
+#define IDRBM_MACRO 107
+#define IDRBM_SEL_NONE 108
+#define IDRBM_SEL_PART 109
+#define IDRBM_SEL_ALL 110
+#define IDRBM_FOLDER 111
+#define IDRBM_FOLDERPLUS 112
+#define IDRBM_FOLDERMINUS 113
+#define IDRBM_EXE 114
+#define IDRBM_FILE 115
+#define IDRBM_DOC 116
+#define IDRBM_FOLDEROPEN 117
+#define IDRBM_FOLDERPLUSOPEN 118
+#define IDRBM_FOLDERMINUSOPEN 119
+#define IDRBM_BACKUP 120
+#define IDRBM_RESTORE 121
+#define IDRBM_ERASE 122
+#define IDRBM_RETENSION 123
+#define IDRBM_JOBSTATUS 124
+#define IDRBM_SELECT 125
+#define IDRBM_SELECTALL 126
+#define IDRBM_DESELECT 127
+#define IDRBM_CHECK 128
+#define IDRBM_UNCHECK 129
+#define IDRBM_MODIFIED 130
+#define IDRBM_ADVANCED 131
+#define IDRBM_UNDO 132
+#define IDRBM_RUN 133
+#define IDRBM_SCHEDULE 134
+#define IDRBM_RECORD 135
+#define IDRBM_EDIT 136
+#define IDRBM_SAVE 137
+#define IDRBM_TEST 138
+#define IDRBM_INSERT 139
+#define IDRBM_DELETE 140
+#define IDRBM_SAVEAS 141
+#define IDRBM_CANCEL 142
+#define IDRBM_BACKUP_GRAY 143
+#define IDRBM_RESTORE_GRAY 144
+#define IDRBM_ERASE_GRAY 145
+#define IDRBM_TRANSFER 146
+#define IDRBM_TRANSFER_GRAY 147
+#define IDRBM_RETENSION_GRAY 148
+#define IDRBM_PARENTDIR 149
+#define IDRBM_MEMORY 150
+#define IDRBM_SEARCH 151
+#define IDRBM_TAPE 152
+#define IDRBM_SERVER 153
+#define IDRBM_SDISK 154
+#define IDRBM_IMAGE IDRBM_SDISK // IMAGE IS THE SAME AS A SMALL DISK
+#define IDRBM_BSET 155
+#define IDRBM_LOGFILE 156
+#define IDRBM_UPARROW 157
+#define IDRBM_DNARROW 158
+#define IDRBM_CATALOG 159
+#define IDRBM_VERIFY 160
+#define IDRBM_BSETPART 161
+#define IDRBM_SERVERDETACHED 162
+#define IDRBM_CHECK_GRAY 163
+#define IDRBM_UNCHECK_GRAY 164
+#define IDRBM_MODIFIED_GRAY 165
+#define IDRBM_ADVANCED_GRAY 166
+#define IDRBM_CATALOG_GRAY 167
+#define IDRBM_VERIFY_GRAY 168
+#define IDRBM_SEARCH_GRAY 169
+#define IDRBM_NEXTSET 170
+#define IDRBM_NEXTSET_GRAY 171
+#define IDRBM_EJECT 172
+#define IDRBM_EJECT_GRAY 173
+#define IDRBM_TAPEINDRIVE 174
+#define IDRBM_REWIND 175
+#define IDRBM_REWIND_GRAY 176
+#define IDRBM_LTAPE 177
+#define IDRBM_UPARROW_GRAY 178
+#define IDRBM_DOWNARROW_GRAY 179
+#define IDRBM_RT_ARROW 180
+#define IDRBM_CORRUPTFILE 181
+#define IDRBM_FOLDERC 182
+#define IDRBM_FOLDERPLUSC 183
+#define IDRBM_FOLDERMINUSC 184
+#define IDRBM_FOLDEROPENC 185
+#define IDRBM_FOLDERPLUSOPENC 186
+#define IDRBM_FOLDERMINUSOPENC 187
+#define IDRBM_HFILE 188
+#define IDRBM_HEXEFILE 189
+#define IDRBM_HCRPTFILE 190
+#define IDRBM_EXIT 191
+#define IDRBM_EXIT_GRAY 192
+#define IDRBM_LOGO 193
+#define IDRBM_SEL_ALL_RED 194
+#define IDRBM_CHECK_RED 195
+#define IDRBM_UNCHECK_RED 196
+#define IDRBM_ADVANCED_RED 197
+#define IDRBM_SHARK1 198
+#define IDRBM_SHARK2 199
+#define IDRBM_SHARK3 200
+#define IDRBM_DIVER1 201
+#define IDRBM_DIVER2 202
+#define IDRBM_DIVER3 203
+#define IDRBM_FOLDER_EN 204
+#define IDRBM_FOLDER_EM 205
+#define IDRBM_FOLDER_EP 206
+#define IDRBM_FOLDER_EON 207
+#define IDRBM_FOLDER_EOM 208
+#define IDRBM_FOLDER_EOP 209
+#define IDRBM_FOLDER_ECN 210
+#define IDRBM_FOLDER_ECM 211
+#define IDRBM_FOLDER_ECP 212
+#define IDRBM_FOLDER_EOCN 213
+#define IDRBM_FOLDER_EOCM 214
+#define IDRBM_FOLDER_EOCP 215
+#define IDRBM_CDROM 216
+#define IDRBM_TAPES 217
+#define IDRBM_TAPESINDRIVE 218
+#define IDRBM_NETCONNECT 219
+#define IDRBM_NETCONNECT_GRAY 220
+#define IDRBM_NETDISCON 221
+#define IDRBM_NETDISCON_GRAY 222
+#define IDRBM_FLOPPYSINDRIVE 223
+#define IDRBM_FLOPPYINDRIVE 224
+#define IDRBM_FLOPPYS 225
+#define IDRBM_FLOPPY 226
+#define IDRBM_INFO 227
+#define IDRBM_INFO_GRAY 228
+#define IDRBM_COLINDICATOR 229
+#define IDRBM_EMS_ENTERPRISE 230
+#define IDRBM_EMS_SITE 231
+#define IDRBM_EMS_SERVER 232
+#define IDRBM_EMS_MDB 233
+#define IDRBM_EMS_DSA 234
+#define IDRBM_RCVR_STATUS 235
+#define IDRBM_EMS_MDBX 236
+#define IDRBM_EMS_DSAX 237
+#define IDRBM_EMS_MDBP 238
+#define IDRBM_EMS_DSAP 239
+#define IDRBM_BLANK16x16 240
diff --git a/private/utils/ntbackup/inc/bkup.h b/private/utils/ntbackup/inc/bkup.h
new file mode 100644
index 000000000..37f725d91
--- /dev/null
+++ b/private/utils/ntbackup/inc/bkup.h
@@ -0,0 +1,82 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: bkup.h
+
+ Description:
+
+
+ $Log: G:\ui\logfiles\bkup.h_v $
+
+ Rev 1.6 28 Jul 1993 17:03:14 CARLS
+added spinner box ID
+
+ Rev 1.5 13 Mar 1993 11:50:44 MIKEP
+fixes over the weekend to build
+
+ Rev 1.4 18 Feb 1993 13:34:24 BURT
+Change for Cayman
+
+
+ Rev 1.3 04 Oct 1992 19:46:22 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.2 06 Apr 1992 09:56:32 CHUCKB
+Added define for translation.
+
+ Rev 1.1 16 Dec 1991 14:24:50 CARLS
+added define for the HELP BUTTON
+
+ Rev 1.0 20 Nov 1991 19:41:00 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_BACKUPSET 33
+#else
+#include "dlg_ids.h"
+#endif
+
+#ifndef BKUP_H
+#define BKUP_H
+
+#define IDM_BACKUPSET 228
+#define IDD_BKUP_INFO_TITLE 101
+#define IDD_BKUP_OK_BUTTON 102
+#define IDD_BKUP_SCROLLBAR 103
+#define IDD_BKUP_CANCEL_BUTTON 104
+#define IDD_BKUP_DESCRIPTION 106
+#define IDD_BKUP_APPEND 108
+#define IDD_BKUP_REPLACE 109
+#define IDD_BKUP_NEXT_BUTTON 111
+#define IDD_BKUP_DRIVE_NAME 112
+#define IDD_BKUP_AUTO_VERIFY 114
+#define IDD_BKUP_TAPE_NAME 117
+#define IDD_BKUP_PASSWORD 118
+#define IDD_BKUP_BACKUP_BINDERY 121
+#define IDD_BKUP_INCLUDE_CATALOGS 122
+#define IDD_BKUP_CATALOG_FULL 123
+#define IDD_BKUP_CATALOG_PARTIAL 124
+#define IDD_BKUP_METHOD 220
+#define IDD_BKUP_SKIP_YES 230
+#define IDD_BKUP_SKIP_NO 231
+#define IDD_BKUP_SKIP_WAIT 232
+#define IDD_BKUP_SKIP_TIME 233
+#define IDD_BKUP_CURRENT_TAPE_NAME 234
+#define IDD_BKUP_PASSWORD_TEXT 125
+#define IDD_BKUP_TAPE_TEXT 240
+#define IDD_BKUP_TAPE_NAME_TEXT 241
+#define IDD_BKUP_SKIP_SECONDS 235
+#define IDD_BKUP_HELP_BUTTON 107
+#define IDD_BKUP_HARDCOMP 242
+#define IDD_BKUP_SOFTCOMP 243
+#define IDD_BKUP_SPINNERBOX 244
+
+#ifdef CAYMAN
+#define IDD_BKUP_REGISTRY 119
+#endif
+
+#endif
diff --git a/private/utils/ntbackup/inc/bsdu.h b/private/utils/ntbackup/inc/bsdu.h
new file mode 100644
index 000000000..18ba98c1b
--- /dev/null
+++ b/private/utils/ntbackup/inc/bsdu.h
@@ -0,0 +1,566 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: bsdu.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This header file contains all the function prototypes
+ and macro definitions for the entry points into the BSDU
+
+ Location: BE_PUBLIC
+
+
+ $Log: M:/LOGFILES/BSDU.H_V $
+ *
+ * Rev 1.33.1.0 24 Nov 1993 14:53:32 BARRY
+ * Unicode fixes
+ *
+ * Rev 1.33 20 Jul 1993 17:32:52 MIKEP
+ * Add prototype for bsd_findbyname
+ *
+ * Rev 1.32 20 Jul 1993 11:09:42 MIKEP
+ * add bsd_getname macro
+ *
+ * Rev 1.31 19 Jul 1993 10:21:48 BARRY
+ * BSD_GetDLE changed to function call -- no longer have ptr to DLE.
+ *
+ * Rev 1.30 21 Jun 1993 09:02:36 ChuckS
+ * Added macros for cat_status field.
+ *
+ * Rev 1.29 29 Apr 1993 11:00:24 MIKEP
+ * Add on tape catalog version to bsd
+ *
+ * Rev 1.28 05 Feb 1993 22:29:50 MARILYN
+ * removed copy/move functionality
+ *
+ * Rev 1.27 08 Dec 1992 14:43:54 DON
+ * changed BSD_BACKUP_DIFERENTIAL to BSD_BACKUP_DIFFERENTIAL (2 Fs)
+ *
+ * Rev 1.26 07 Dec 1992 18:20:56 DON
+ * incorporated Marilyns stuff for copy/move
+ *
+ * Rev 1.25 18 Sep 1992 15:53:14 STEVEN
+ * fix spelling
+ *
+ * Rev 1.24 17 Sep 1992 11:12:48 STEVEN
+ * add support for daily backup
+ *
+ * Rev 1.23 12 Aug 1992 17:46:52 STEVEN
+ * fixed bugs at microsoft
+ *
+ * Rev 1.22 29 Jul 1992 15:30:44 STEVEN
+ * fix warnings
+ *
+ * Rev 1.20 27 May 1992 15:37:04 TIMN
+ * Fixed syntax error
+ *
+ * Rev 1.19 14 May 1992 13:45:32 STEVEN
+ * added tim's UNICODE changes
+ *
+ * Rev 1.18 14 May 1992 13:06:28 STEVEN
+ * added support for unreadable BSETS
+ *
+ * Rev 1.17 13 May 1992 19:16:52 TIMN
+ * Updated protos with size parameter
+ *
+ * Rev 1.16 11 May 1992 10:39:22 STEVEN
+ * added get macor for volume name
+ *
+ * Rev 1.15 08 May 1992 16:24:24 STEVEN
+ * added volume label to BSD
+ *
+ * Rev 1.14 29 Apr 1992 16:00:50 BARRY
+ * Added initial selection status for UIs.
+ *
+ * Rev 1.13 20 Apr 1992 11:22:28 BARRY
+ * Added BSD_GetCount macro. Returns the number of BSDs in a list.
+ *
+ * Rev 1.12 14 Jan 1992 10:25:38 STEVEN
+ * fix warnings for WIN32
+ *
+ * Rev 1.11 18 Oct 1991 14:22:06 STEVEN
+ * BIGWHEEL-fix bug in entire dir support
+ *
+ * Rev 1.10 19 Sep 1991 11:04:14 STEVEN
+ * 8200SX - Added GetPrequalify() & BSD_HardwareSupportFeatures()
+ *
+ * Rev 1.9 27 Aug 1991 17:33:58 STEVEN
+ * added BSD target dir support
+ *
+ * Rev 1.8 23 Aug 1991 17:01:42 STEVEN
+ * added support for NORMAL/COPY/DIFFERENTIAL/INCREMENTAL
+ *
+ * Rev 1.7 20 Aug 1991 09:53:44 STEVEN
+ * add ui configuration to BSD structure
+ *
+ * Rev 1.6 23 Jul 1991 16:20:26 STEVEN
+ * added BSD_RefreshConfig( )
+ *
+ * Rev 1.5 21 Jun 1991 08:44:20 STEVEN
+ * new config unit
+ *
+ * Rev 1.4 20 Jun 1991 10:50:28 STEVEN
+ * tried to put 2 in a 1bit bitfield
+ *
+ * Rev 1.3 13 Jun 1991 14:02:06 STEVEN
+ * need version # in LBA for FFR
+ *
+ * Rev 1.2 12 Jun 1991 15:59:50 STEVEN
+ * added virtual memory for LBAs
+ *
+ * Rev 1.1 29 May 1991 17:22:52 STEVEN
+ * Re-Design of BSDU for New Fast File Restore
+ *
+ * Rev 1.0 09 May 1991 13:33:22 HUNTER
+ * Initial revision.
+
+**/
+
+#ifndef BSDU_h
+#define BSDU_h 1
+
+#include "queues.h"
+#include "datetime.h"
+#include "bsdu_str.h"
+
+/* $end$ */
+
+/**
+ Constants used as parameters and return values
+**/
+#define USE_WILD_CARD TRUE
+#define NO_WILD_CARD FALSE
+
+#define INCLUDE_SUBDIRS TRUE
+#define NOT_INC_SUBDIRS FALSE
+
+#define NON_DELETED_FILES_ONLY 0
+#define DELETED_FILES_ONLY 1
+#define DELETED_AND_NON_DELETED 2
+
+#define LBA_BEGIN_POSITION 0 /* LBA types - e.g. C:\fred\*.* */
+#define LBA_SINGLE_OBJECT 1 /* - e.g. C:\fred\sue.c */
+
+#define BSD_PROCESS_OBJECT 1
+#define BSD_PROCESS_ELEMENTS 2
+#define BSD_SPECIAL_OBJECT 3
+#define FSL_EMPTY 4
+#define BSD_PROCESS_ENTIRE_DIR 5
+#define BSD_SKIP_OBJECT 0
+
+#define SINGLE_FILE_SELECTION 1
+#define ENTIRE_DIR_SELECTION 2
+#define PARTIAL_SELECTION 0
+
+/*
+ * Values for selection status. The value INITIAL_SELECTED is required by
+ * some UIs for generality, but is NEVER, and shall NEVER be returned by
+ * the BSDU as a selection status.
+ */
+#define INITIAL_SELECTED 255
+#define NONE_SELECTED 0
+#define ALL_SELECTED 1
+#define SOME_SELECTED 2
+
+#define INCLUDE ((UINT16)1)
+#define EXCLUDE ((UINT16)0)
+
+/* defines for backup_type parm to BSD_SetBackupType() */
+#define BSD_BACKUP_COMPATIBLE 0
+#define BSD_BACKUP_NORMAL 1
+#define BSD_BACKUP_COPY 2
+#define BSD_BACKUP_DIFFERENTIAL 3
+#define BSD_BACKUP_INCREMENTAL 4
+#define BSD_BACKUP_DAILY 5
+
+/* BSD header function codes */
+#define BSD_BACKUP 1
+#define BSD_RESTORE 2
+#define BSD_VERIFY 3
+#define BSD_MISC_OPER 4
+#define BSD_TRANSFER 5
+#define BSD_ANY_FUNC 0 /* internal use only */
+
+
+/**
+ BSD manipulation functions
+**/
+INT16 BSD_OpenList( BSD_HAND *bsdh, struct VM_STR *vm_hand ) ;
+VOID BSD_CloseList( BSD_HAND bsdh ) ;
+
+INT16 BSD_Add( BSD_HAND bsdh, BSD_PTR *bsd, struct BE_CFG *cfg, VOID_PTR stats,
+ struct GENERIC_DLE *dle, UINT32 tape_id, UINT16 tape_num,
+ INT16 set_num, struct THW *thw, DATE_TIME_PTR sort_date );
+
+VOID BSD_Remove( BSD_PTR bsd ) ;
+
+INT16 BSD_SetTapeLabel( BSD_PTR bsd, VOID_PTR label, INT16 label_size ) ;
+
+INT16 BSD_SetVolumeLabel( BSD_PTR bsd, VOID_PTR label, INT16 label_size ) ;
+
+INT16 BSD_SetBackupLabel( BSD_PTR bsd, VOID_PTR label, INT16 label_size ) ;
+
+INT16 BSD_SetBackupDescript( BSD_PTR bsd, VOID_PTR descript, INT16 dscr_size ) ;
+
+INT16 BSD_SetTapePswd( BSD_PTR bsd, VOID_PTR tape_pswd, INT16 psw_size ) ;
+
+INT16 BSD_SetBackupPswd( BSD_PTR bsd, VOID_PTR backup_pswd, INT16 psw_size ) ;
+
+INT16 BSD_SetUserName( BSD_PTR bsd, VOID_PTR name, INT16 name_size ) ;
+
+VOID BSD_SetTapePos( BSD_PTR bsd, UINT32 tape_id, UINT16 tape_num,
+ UINT16 set_num ) ;
+
+BSD_PTR BSD_FindByDLE( BSD_HAND bsdh, struct GENERIC_DLE *dle ) ;
+
+BSD_PTR BSD_FindByName( BSD_HAND bsdh, CHAR_PTR name ) ;
+
+BSD_PTR BSD_FindBySourceDevice( BSD_HAND bsdh, VOID_PTR apps_ptr ) ;
+
+BSD_PTR BSD_FindByTapeID( BSD_HAND bsdh, UINT32 tape_id, UINT16 set_num ) ;
+
+INT16 BSD_CreatFSE( FSE_PTR *fse, INT16 oper, VOID_PTR path, INT16 psize,
+ VOID_PTR fname, INT16 fnsize, BOOLEAN wilds, BOOLEAN inc_sub ) ;
+
+VOID BSD_AddFSE( BSD_PTR bsd, FSE_PTR fse ) ;
+
+VOID BSD_RemoveFSE( FSE_PTR fse ) ;
+
+VOID BSD_ClearAllFSE( BSD_PTR bsd ) ;
+
+VOID BSD_ClearDelete( BSD_PTR bsd ) ;
+
+struct FSYS_HAND_STRUCT ;
+struct DBLK ;
+
+INT16 BSD_MatchObj( BSD_PTR bsd, FSE_PTR *fse, struct FSYS_HAND_STRUCT *fsh,
+ struct DBLK *ddb, struct DBLK *fdb, BOOLEAN disp_flag ) ;
+
+INT16 BSD_MatchPathAndFile( BSD_PTR bsd, FSE_PTR *fse,
+ CHAR_PTR fname, CHAR_PTR path, INT16 psize, UINT32 attr,
+ DATE_TIME_PTR date, DATE_TIME_PTR access_date,
+ DATE_TIME_PTR backup_date, BOOLEAN deleted_flag, BOOLEAN disp_flag ) ;
+
+VOID BSD_SaveLastOper( BSD_HAND bsdh );
+
+VOID BSD_ClearLastOper( BSD_HAND bsdh );
+
+VOID BSD_ClearCurrOper( BSD_HAND bsdh );
+
+VOID BSD_ProcLastOper( BSD_HAND bsdh );
+
+VOID BSD_SwapOper( BSD_HAND bsdh );
+
+VOID BSD_BeginFunction( BSD_HAND bsdh, INT16 function ) ; /* fred */
+
+struct GENERIC_DLE* BSD_GetDLE( BSD_PTR bsd );
+
+VOID BSD_SetDLE( BSD_PTR bsd, struct GENERIC_DLE *dle ) ;
+
+INT16 BSD_SetTargetInfo( BSD_PTR bsd, VOID_PTR tgt_path, INT16 psize ) ;
+VOID BSD_GetTargetInfo( BSD_PTR bsd, VOID_PTR *path, INT16 *psize );
+
+VOID BSD_SetBackupType( BSD_PTR bsd, INT16 backup_type ) ;
+
+VOID BSD_RefreshConfig( BSD_HAND bsdh, struct BE_CFG *conf ) ;
+
+BOOLEAN BSD_HardwareSupportsFeature( BSD_PTR bsd, UINT32 feature ) ;
+
+/**
+ FSE Manipulation functions
+**/
+
+INT16 FSE_Copy( FSE_PTR orig_fse, FSE_PTR *new_fse ) ;
+
+INT16 FSE_SetTargetInfo( FSE_PTR fse, VOID_PTR tgt_path, INT16 psize, VOID_PTR tgt_fname, INT16 fn_size ) ;
+VOID FSE_GetTargetInfo( FSE_PTR fse, VOID_PTR *path, INT16 *psize, VOID_PTR *fname, INT16 *fnsize );
+
+INT16 FSE_SetModDate( FSE_PTR fse, DATE_TIME_PTR pre, DATE_TIME_PTR post ) ;
+INT16 FSE_SetAccDate( FSE_PTR fse, DATE_TIME_PTR pre ) ;
+INT16 FSE_SetBakDate( FSE_PTR fse, DATE_TIME_PTR pre ) ;
+VOID FSE_GetModDate( FSE_PTR fse, DATE_TIME_PTR *pre, DATE_TIME_PTR *post ) ;
+VOID FSE_GetAccDate( FSE_PTR fse, DATE_TIME_PTR *pre ) ;
+VOID FSE_GetBakDate( FSE_PTR fse, DATE_TIME_PTR *pre ) ;
+
+INT16 FSE_SetAttribInfo( FSE_PTR fse, UINT32 a_on_mask, UINT32 a_off_mask ) ;
+VOID FSE_GetAttribInfo( FSE_PTR fse, UINT32_PTR a_on_mask, UINT32_PTR a_off_mask ) ;
+/**
+ BSD Macros
+**/
+
+
+#define BSD_GetFirst( bsdh ) \
+ (BSD_PTR)QueueHead( &(bsdh->current_q_hdr) )
+
+#define BSD_GetNext( bsd ) \
+ (BSD_PTR)QueueNext( &((bsd)->q) )
+
+#define BSD_GetName( bsd ) \
+ ((bsd)->dle_name)
+#define BSD_GetTapeCatVer( bsd ) \
+ ((bsd)->tape_cat_ver)
+#define BSD_SetTapeCatVer( bsd, version ) \
+ ((bsd)->tape_cat_ver = (version))
+
+#define BSD_GetTapeID( bsd ) \
+ ((bsd)->tape_id)
+#define BSD_GetTapeNum( bsd )\
+ ((bsd)->tape_num)
+#define BSD_GetSetNum( bsd ) \
+ ((bsd)->set_num)
+#define BSD_GetVolumeLabel( bsd )\
+ ((bsd)->vol_label)
+#define BSD_SizeofVolumeLabel( bsd )\
+ ((bsd)->vol_label_size)
+#define BSD_GetTapeLabel( bsd )\
+ ((bsd)->tape_label)
+#define BSD_SizeofTapeLabel( bsd )\
+ ((bsd)->tape_label_size)
+#define BSD_GetTapePswd( bsd )\
+ ((bsd)->tape_pswd)
+#define BSD_GetTapePswdSize( bsd )\
+ ((bsd)->tape_pswd_size)
+#define BSD_GetBackupLabel( bsd )\
+ ((bsd)->set_label)
+#define BSD_SizeofBackupLabel( bsd )\
+ ((bsd)->set_label_size)
+#define BSD_GetBackupPswd( bsd )\
+ ((bsd)->set_pswd)
+#define BSD_GetBackupPswdSize( bsd )\
+ ((bsd)->set_pswd_size)
+#define BSD_GetBackupDescript( bsd )\
+ ((bsd)->set_descript)
+#define BSD_SizeofBackupDescript( bsd )\
+ ((bsd)->set_descript_size)
+#define BSD_GetUserName( bsd )\
+ ((bsd)->user_name)
+#define BSD_SizeofUserName( bsd )\
+ ((bsd)->user_name_size)
+
+#define BSD_SetLogicalSourceDevice( bsd, app_ptr )\
+ ((bsd)->source_dev = (app_ptr))
+
+#define BSD_GetLogicalSourceDevice( bsd )\
+ ((bsd)->source_dev)
+
+#define BSD_GetMarkStatus( bsd ) \
+ ((bsd)->select_status)
+
+#define BSD_SetMarkStatus( bsd, stat ) \
+ ((bsd)->select_status = (stat) )
+
+
+#define BSD_GetConfigData( bsd ) \
+ ((bsd)->cfg)
+
+#define BSD_GetStatData( bsd ) \
+ ((bsd)->stats)
+
+#define BSD_GetUIConfig( bsd ) \
+ ((bsd)->ui_config)
+
+#define BSD_SetUIConfig( bsd, cfg ) \
+ ((bsd)->ui_config = (VOID_PTR)(cfg))
+
+#define BSD_GetTHW( bsd ) \
+ ((bsd)->thw)
+
+#define BSD_SetTHW( bsd, inp_thw ) \
+ ((bsd)->thw = (inp_thw))
+
+#define BSD_GetOperStatus( bsd )\
+ ( (bsd)->oper_status )
+
+#define BSD_SetOperStatus( bsd, status ) \
+ ((bsd)->oper_status = (status))
+
+#define BSD_GetProcSpecialFlg( bsd ) \
+ ((bsd)->flags.proc_special )
+
+#define BSD_SetProcSpecialFlg( bsd, value ) \
+ ((bsd)->flags.proc_special = value )
+
+#define BSD_GetProcElemOnlyFlg( bsd ) \
+ ((bsd)->flags.proc_nosecure )
+
+#define BSD_SetProcElemOnlyFlg( bsd, value ) \
+ ((bsd)->flags.proc_nosecure = value ) /* FALSE to process security */
+
+#define BSD_GetBackupType( bsd ) \
+ ((bsd)->flags.backup_type )
+
+#define BSD_CompatibleBackup( bsd ) \
+ (!(bsd)->flags.sup_back_type)
+
+#define BSD_SetArchiveBackup( bsd ) \
+ ((bsd)->flags.set_mod_flag )
+
+#define BSD_ModFilesOnly( bsd ) \
+ ((bsd)->flags.modify_only)
+
+#define BSD_GetPBA( bsd ) \
+ ((bsd)->pba )
+
+#define BSD_SetPBA( bsd, val ) \
+ ((bsd)->pba = val )
+
+#define BSD_ViewDate( bsd ) \
+ ( &((bsd)->sort_date) )
+
+#define BSD_GetFunctionCode( bsdh ) \
+ ((bsdh)->function_code )
+
+#define BSD_IsTapeNameChangable( bsd ) \
+ ( (bsd)->flags.tp_name_chg )
+
+#define BSD_IsBsetNameChangable( bsd ) \
+ ( (bsd)->flags.bs_name_chg )
+
+#define BSD_IsBsetDescriptChangable( bsd ) \
+ ( (bsd)->flags.bs_dscr_chg )
+
+#define BSD_MarkTapeNameNotChangable( bsd ) \
+ ( (bsd)->flags.tp_name_chg = FALSE )
+
+#define BSD_MarkBsetNameNotChangable( bsd ) \
+ ( (bsd)->flags.bs_name_chg = FALSE )
+
+#define BSD_MarkBsetDescrNotChangable( bsd ) \
+ ( (bsd)->flags.bs_dscr_chg = FALSE )
+
+#define BSD_SetFullyCataloged( bsd, full ) \
+ ( (bsd)->flags.fully_cataloged = (full) )
+
+#define BSD_GetFullyCataloged( bsd ) \
+ ( (bsd)->flags.fully_cataloged )
+
+#define BSD_IsBsetUnReadable( bsd ) \
+ ( (bsd)->flags.unreadable_set )
+
+#define BSD_SetBsetUnReadable( bsd ) \
+ ( (bsd)->flags.unreadable_set = TRUE )
+
+#define BSD_SetPrequalified( bsd, t_or_f ) \
+ ( (bsd)->flags.prequalified = (t_or_f) )
+
+#define BSD_GetPrequalified( bsd ) \
+ ( (bsd)->flags.prequalified )
+
+/* can only be done if BSD added with NULL sort date */
+#define BSD_SetDate( bsd, date ) \
+ ( (bsd)->sort_date = *date )
+
+
+#define BSD_GetCount( bsd_hand ) (QueueCount( &((bsd_hand)->current_q_hdr)) )
+
+
+/**
+ FSE Macros
+**/
+
+#define BSD_GetFirstFSE( bsd ) \
+ ( (FSE_PTR)QueueHead( &((bsd)->fse_q_hdr) ) )
+
+#define BSD_GetLastFSE( bsd ) \
+ ( (FSE_PTR)QueueTail( &((bsd)->fse_q_hdr) ) )
+
+#define BSD_GetNextFSE( fse ) \
+ ( (FSE_PTR)QueueNext( &((fse)->q) ) )
+
+#define BSD_GetPrevFSE( fse ) \
+ ( (FSE_PTR)QueuePrev( &((fse)->q) ) )
+
+
+#define FSE_GetSelectType( fse ) \
+ ((fse)->flgs.select_type )
+
+#define FSE_HasTargetInfo( fse ) \
+ ((fse)->tgt != NULL )
+
+#define FSE_HasComplexInfo( fse ) \
+ ((fse)->cplx != NULL )
+
+#define FSE_GetPath( fse, dirptr, size ) \
+ ( (*(dirptr) = (fse)->dir),\
+ (*(size) = (fse)->dir_leng))
+
+#define FSE_GetFname( fse ) \
+ ((fse)->fname)
+
+#define FSE_MarkDeleted( fse ) \
+ ((fse)->flgs.proced_fse = 1)
+
+#define FSE_GetDeleteMark( fse ) \
+ ((fse)->flgs.proced_fse)
+
+#define FSE_SetAllVersionsFlg( fse, val ) \
+ ((fse)->flgs.all_vers = (val) )
+
+#define FSE_SetDeletedVersionFlg( fse, val ) \
+ ((fse)->flgs.del_files = (val) )
+
+#define FSE_GetDeletedVersionFlg( fse ) \
+ ((fse)->flgs.del_files)
+
+#define FSE_SetIncSubFlag( fse, flag ) \
+ ((fse)->flgs.inc_subdir = (UINT16)(!(!(flag))))
+
+#define FSE_SetWildFlag( fse, flag ) \
+ ((fse)->flgs.wild_cards = (UINT16)(!(!(flag))))
+
+#define FSE_GetIncSubFlag( fse ) \
+ ((fse)->flgs.inc_subdir)
+
+#define FSE_GetWildFlag( fse ) \
+ ((fse)->flgs.wild_cards)
+
+#define FSE_SetOperType( fse, flag ) \
+ ((fse)->flgs.inc_exc = (flag) )
+
+#define FSE_GetOperType( fse ) \
+ ((fse)->flgs.inc_exc)
+
+VOID BSD_ClearAllLBA( BSD_PTR bsd ) ;
+
+INT16 BSD_AddLBAElem( BSD_PTR bsd, UINT32 lba, UINT16 tape_num, UINT16 type, UINT16 ver ) ;
+
+INT16 BSD_GetFirstLBA( BSD_PTR bsd, LBA_ELEM_PTR lba ) ;
+
+INT16 BSD_GetNextLBA( BSD_PTR bsd, LBA_ELEM_PTR lba ) ;
+
+#define LBA_GetLBA( lba_elem ) \
+ ( (lba_elem)->lba_val )
+
+#define LBA_GetTapeNum( lba_elem ) \
+ ( (lba_elem)->tape_num )
+
+#define LBA_GetType( lba_elem ) \
+ ( (lba_elem)->type )
+
+#define LBA_GetFileVer( lba_elem ) \
+ ( (lba_elem)->file_ver_num )
+
+#define BSD_SetCatStatus( bsd, status ) \
+ ( (bsd)->cat_status = status )
+
+#define BSD_GetCatStatus( bsd ) \
+ ( (bsd)->cat_status )
+
+#define BSD_GetOsId( bsd ) \
+ ( (bsd)->set_os_id )
+
+#define BSD_GetOsVer( bsd ) \
+ ( (bsd)->set_os_ver )
+
+#define BSD_SetOsId( bsd, v ) \
+ ( (bsd)->set_os_id = v )
+
+#define BSD_SetOsVer( bsd, v ) \
+ ( (bsd)->set_os_ver = v )
+
+#endif
+
+
+
diff --git a/private/utils/ntbackup/inc/bsdu_str.h b/private/utils/ntbackup/inc/bsdu_str.h
new file mode 100644
index 000000000..efc0e2be1
--- /dev/null
+++ b/private/utils/ntbackup/inc/bsdu_str.h
@@ -0,0 +1,264 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: bsdu_str.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This header file contains the structures maintained by
+ the BSDU unit.
+
+ Location: BE_PUBLIC
+
+
+ $Log: M:/LOGFILES/BSDU_STR.H_V $
+ *
+ * Rev 1.22.1.0 24 Nov 1993 14:53:32 BARRY
+ * Unicode fixes
+ *
+ * Rev 1.22 19 Jul 1993 10:23:42 BARRY
+ * No longer retain pointer to DLE -- use device name instead.
+ *
+ * Rev 1.21 21 Jun 1993 09:02:46 ChuckS
+ * Added cat_status field to BSD for restore
+ *
+ * Rev 1.20 29 Apr 1993 11:00:16 MIKEP
+ * Add on tape catalog version to bsd
+ *
+ * Rev 1.19 05 Feb 1993 22:30:06 MARILYN
+ * removed copy/move functionality
+ *
+ * Rev 1.18 07 Dec 1992 17:12:24 DON
+ * incorporated Marilyns stuff for copy/move
+ *
+ * Rev 1.17 29 Jul 1992 15:31:44 STEVEN
+ * fix warnings
+ *
+ * Rev 1.15 06 Jul 1992 16:18:56 STEVEN
+ * fix sizes for all files
+ *
+ * Rev 1.14 19 May 1992 15:13:58 TIMN
+ * Added all file defines
+ *
+ * Rev 1.13 14 May 1992 13:45:36 STEVEN
+ * added tim's UNICODE changes
+ *
+ * Rev 1.12 14 May 1992 13:06:30 STEVEN
+ * added support for unreadable BSETS
+ *
+ * Rev 1.11 13 May 1992 19:18:08 TIMN
+ * Added string size fields in BSD struct
+ *
+ * Rev 1.10 08 May 1992 16:24:22 STEVEN
+ * added volume label to BSD
+ *
+ * Rev 1.9 19 Sep 1991 10:58:30 STEVEN
+ * 8200SX - Added prequalified boolean
+ *
+ * Rev 1.8 27 Aug 1991 17:34:16 STEVEN
+ * added BSD target dir support
+ *
+ * Rev 1.7 23 Aug 1991 17:02:02 STEVEN
+ * added support for NORMAL/COPY/DIFERENTIAL/INCREMENTAL
+ *
+ * Rev 1.6 20 Aug 1991 09:53:38 STEVEN
+ * add ui configuration to BSD structure
+ *
+ * Rev 1.5 26 Jun 1991 13:50:16 STEVEN
+ *
+ * Rev 1.4 21 Jun 1991 08:44:40 STEVEN
+ * new config unit
+ *
+ * Rev 1.3 13 Jun 1991 14:02:26 STEVEN
+ * need version # in LBA for FFR
+ *
+ * Rev 1.2 12 Jun 1991 16:00:12 STEVEN
+ * added virtual memory for LBAs
+ *
+ * Rev 1.1 20 May 1991 10:13:46 STEVEN
+ * Re-Design of BSDU for new FFR
+ *
+ * Rev 1.0 09 May 1991 13:30:32 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef BSDU_STR_H
+#define BSDU_STR_H 1
+
+
+#if defined( UNICODE )
+# define ALL_FILES TEXT("*.*")
+# define ALL_FILES_LENG ((UINT16)8) /* length for ALL_FILES */
+# define ALL_FILES2 TEXT("*")
+# define ALL_FILES2_LENG ((UINT16)4) /* length for ALL_FILES2 */
+#else
+# define ALL_FILES "*.*"
+# define ALL_FILES_LENG ((UINT16)4) /* length for ALL_FILES */
+# define ALL_FILES2 "*"
+# define ALL_FILES2_LENG ((UINT16)2) /* length for ALL_FILES2 */
+#endif
+
+
+/*
+ Define the Backup Set Descriptor List data structure
+
+ The BSD_LIST contains two BSD queues. The first queue is for current
+ selections. The second queue is for selections from the previous operation.
+ After a backup or a restore, the second queue should be removed and the first
+ queue should moved to the second position.
+
+*/
+
+typedef struct FSE_FLAGS {
+ UINT16 select_type : 2 ;
+ UINT16 inc_exc : 1 ;
+ UINT16 del_files : 2 ;
+ UINT16 all_vers : 1 ;
+ UINT16 inc_subdir : 1 ;
+ UINT16 proced_fse : 1 ;
+ UINT16 wild_cards : 1 ;
+} FSE_FLAGS ;
+
+typedef struct BSD_FLGS{
+ UINT16 bs_name_chg : 1 ; /* TRUE if backup set name is changable */
+ UINT16 tp_name_chg : 1 ; /* TRUE if tape name is changable */
+ UINT16 bs_dscr_chg : 1 ; /* TRUE if backup description changable */
+ UINT16 fully_cataloged :1 ; /* TRUE if fully cataloged set */
+ UINT16 proc_special :1 ; /* should we process special files */
+ UINT16 proc_nosecure :1 ; /* should we process security */
+ UINT16 sup_back_type :1 ; /* support NORMAL/COPY/DIFER/INCREM */
+ UINT16 modify_only : 1 ; /* backup modified files only */
+ UINT16 set_mod_flag : 1 ; /* clear the modified flag after backup */
+ UINT16 backup_type : 3 ; /* support NORMAL/COPY/DIFER/INCREM */
+ UINT16 prequalified : 1 ; /* TRUE if prequalified set */
+ UINT16 unreadable_set : 1 ; /* TRUE if set is unreadable */
+
+} BSD_FLAGS ;
+
+typedef struct BSD_LIST {
+ struct VM_STR *vm_hand ;
+ Q_HEADER current_q_hdr ; /* pointer to list of BSDs */
+ INT16 function_code ; /* backup, restore, verify or other */
+ Q_HEADER last_q_hdr ; /* pointer to last oper's list of BSDs */
+} BSD_LIST, *BSD_HAND;
+
+
+
+/*
+ Define the Backup Set Descriptor Element
+
+ The BSD contains information about the tape of intrest and the
+ disk of intrest. It also contains the head of the FSE queue.
+ The BSD queue is sorted by sort_date, and then by tape number, and
+ then by disk device name. The BSD also contains processing flags
+ and operation completion codes.
+
+*/
+
+typedef struct BSD {
+ Q_ELEM q ; /* points to next BSD */
+ Q_HEADER fse_q_hdr ; /* Queue of FSEs */
+ UINT32 lba_vm_q_head; /* lba Queue cross linked with FSEs */
+ UINT32 lba_vm_q_tail; /* lba Queue cross linked with FSEs */
+ VOID_PTR source_dev ; /* Identifies the source Device */
+ UINT32 tape_id ; /* Identifies set of tapes */
+ UINT16 tape_num ; /* Specifies tape number of set */
+ INT16 set_num ; /* Specifies what set to process */
+ UINT32 pba ; /* Physical Block Address of set */
+ INT16 select_status ; /* Some, All, file, dir, or complex */
+ INT16 vol_label_size ; /* size of volume name */
+ VOID_PTR vol_label ; /* source volume name from VCB */
+ INT16 tape_label_size ; /* size of tape label */
+ VOID_PTR tape_label ; /* user suplied tape label in VCB */
+ INT16 set_label_size ; /* size of set label */
+ VOID_PTR set_label ; /* user suplied set label in VCB */
+ INT16 set_descript_size ; /* size of set description */
+ VOID_PTR set_descript ; /* user suplied set descriptin VCB */
+ INT16 user_name_size ; /* size of user name */
+ VOID_PTR user_name ; /* user suplied name for himself */
+ INT16 tape_pswd_size ; /* size of tape passowrd */
+ VOID_PTR tape_pswd ; /* user specified tape password */
+ INT16 set_pswd_size ; /* size of backup set password */
+ VOID_PTR set_pswd ; /* user specified set password */
+ struct BE_CFG *cfg ; /* pointer to Configuration data */
+ struct HEAD_DLE *dle_head; /* list in which DLE is contained */
+ CHAR_PTR dle_name; /* name for DLE */
+ VOID_PTR stats; /* pointer to statistics structure */
+ struct THW *thw ; /* specifies which tape drive to use*/
+ UINT16 oper_status ; /* status of last operation */
+ BSD_FLAGS flags ; /* bit flags */
+ UINT16 tgt_fse_exist; /* TRUE if a Target FSE exists */
+ DATE_TIME sort_date ; /* date used to sort bsd's */
+ VOID_PTR ui_config ; /* user interface config */
+ VOID_PTR target_path ; /* BSD target path */
+ INT16 tgt_psize ; /* BSD target path size */
+ VOID_PTR match_buffer ; /* internaly used by the matcher */
+ INT16 match_buffer_size ; /* internaly used by the matcher */
+ UINT8 tape_cat_ver ; /* MTF on tape catalog version */
+ UINT32 cat_status ; /* Catalog status word - valid on restore only */
+ UINT8 set_os_id ;
+ UINT8 set_os_ver ;
+} BSD, *BSD_PTR ;
+
+/*
+ Define the File Selection Element
+
+ Each FSE descripes a set of files to be processed. A simple FSE only
+ contains a path, file name, and a set of FSE flags.
+
+*/
+
+
+/*
+ Define the Complex data for an FSE
+
+ A complex FSE contins target directory paths and file names, Before and
+ After dates, as well as attribute flags.
+
+*/
+
+typedef struct FSE_TGT_INFO {
+ INT16 psize ; /* length of new directory name */
+ VOID_PTR path ; /* new directory name for restore/ver */
+ INT16 fnsize ; /* length of new file name */
+ VOID_PTR fname; /* new file name for restore/verify */
+} FSE_TGT_INFO, *FSE_TGT_INFO_PTR ;
+
+typedef struct COMP_FSE {
+ DATE_TIME_PTR pre_m_date ; /* only backup files before this date */
+ DATE_TIME_PTR post_m_date ; /* only backup files after this data */
+ DATE_TIME_PTR access_date; /* Proc things backup up before this date*/
+ DATE_TIME_PTR backup_date; /* Proc things backup up before this date*/
+ UINT32 attr_on_mask ; /* mask of attributes which must be on */
+ UINT32 attr_off_mask ; /* mask of attributes which must be off */
+} FSE_COMPLEX, *FSE_COMPLEX_PTR ;
+
+
+typedef struct FSE {
+ Q_ELEM q ; /* queue of FSEs in order of addition */
+ FSE_FLAGS flgs ; /* misc flags */
+ INT16 dir_leng; /* length of directory name to match */
+ VOID_PTR dir ; /* directory name to match */
+ INT16 fname_leng ; /* length of file name to match */
+ VOID_PTR fname ; /* file name to match */
+
+ FSE_TGT_INFO_PTR tgt ;
+ FSE_COMPLEX_PTR cplx ; /* pointer to complex information */
+
+} FSE, *FSE_PTR;
+
+typedef struct LBA_ELEM {
+
+ UINT32 next ; /* vm queue element - next element pointer */
+ UINT32 vm_ptr ; /* vm pointer for current element */
+ UINT32 lba_val ; /* value of the lba */
+ UINT8 tape_num ; /* tape sequence number */
+ UINT8 type ; /* type of LBA - Single Object or Begin Position */
+ UINT8 file_ver_num; /* file version number for restore of ALL versions */
+
+} LBA_ELEM, *LBA_ELEM_PTR ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/buff_prv.h b/private/utils/ntbackup/inc/buff_prv.h
new file mode 100644
index 000000000..7814ae7c8
--- /dev/null
+++ b/private/utils/ntbackup/inc/buff_prv.h
@@ -0,0 +1,35 @@
+/**
+
+ Unit: Tape Format
+
+ Name: buff_prv.h
+
+ Description: Buffer Manager Private data and types
+
+ $Log: T:/LOGFILES/BUFF_PRV.H_V $
+
+ Rev 1.4 04 Feb 1992 21:13:54 GREGG
+Moved DOS specific stuff to DOS specific header file.
+
+ Rev 1.3 16 Jan 1992 21:04:54 GREGG
+Changes resulting from code review on 1/16/92.
+
+ Rev 1.2 14 Jan 1992 02:02:08 GREGG
+Skateboard - Added internal buffer management structure (DOS only).
+
+ Rev 1.1 13 Jan 1992 19:48:08 NED
+changed mw_vcb_requirements to uw_
+changed lw_bm_master_list to uw_
+
+ Rev 1.0 03 Jan 1992 15:09:22 GREGG
+Initial revision.
+
+**/
+
+#if !defined( _BUFFPRIV_H )
+#define _BUFFPRIV_H
+
+extern Q_HEADER uw_bm_master_list ; /* list of all the lists */
+extern BUF_REQ_PTR uw_vcb_requirements; /* passed via BM_SetVCBRequirements() */
+
+#endif /* _BUFFPRIV_H */
diff --git a/private/utils/ntbackup/inc/buffman.h b/private/utils/ntbackup/inc/buffman.h
new file mode 100644
index 000000000..94c34dd38
--- /dev/null
+++ b/private/utils/ntbackup/inc/buffman.h
@@ -0,0 +1,405 @@
+/**
+
+ Unit: Tape Format
+
+ Name: buffman.h
+
+ Description: New Buffer Manager interface
+
+ $Log: N:/LOGFILES/BUFFMAN.H_V $
+ *
+ * Rev 1.23 10 Jun 1993 08:09:12 MIKEP
+ * enable c++
+ *
+ * Rev 1.22 17 Mar 1993 14:54:16 GREGG
+ * This is Terri Lynn. Added Gregg's changes to switch a tape drive's block
+ * mode so that it matches the block size of the current tape.
+ *
+ * Rev 1.21 09 Mar 1993 18:14:12 GREGG
+ * Initial changes for new stream and EOM processing.
+ *
+ * Rev 1.20 26 May 1992 22:54:00 GREGG
+ * Changed BM_SetBytesFree macro to eliminate warnings.
+ *
+ * Rev 1.19 02 Apr 1992 15:23:16 STEVEN
+ * fix compiler error with trinary and /Ox
+ *
+ * Rev 1.18 11 Feb 1992 17:09:32 NED
+ * Changed translator interface slightly from buffman.
+ *
+ * Rev 1.17 04 Feb 1992 20:56:40 GREGG
+ * Changes for dealing with new config parameters.
+ *
+ * Rev 1.16 16 Jan 1992 21:01:00 GREGG
+ * Changed InitList and OS_InitList prototypes to return INT16 not UINT16.
+ *
+ * Rev 1.15 16 Jan 1992 18:36:24 NED
+ * Skateboard: buffer manager changes
+ *
+ * Rev 1.14 14 Jan 1992 19:44:28 NED
+ * Added prototype of BM_OS_CleanupList()
+ *
+ * Rev 1.13 14 Jan 1992 02:16:02 GREGG
+ * Skateboard - Bug fixes.
+ *
+ * Rev 1.12 13 Jan 1992 20:02:24 NED
+ * supressed silly warning
+ *
+ * Rev 1.11 13 Jan 1992 19:46:52 NED
+ * Added prototypes for BM_AllocVCB() and BM_FreeVCB()
+ * Added conditional for DOS for BM_RESERVED_SIZE
+ *
+ * Rev 1.10 13 Jan 1992 13:48:14 GREGG
+ * Skateboard - Bug fixes.
+ *
+ * Rev 1.9 07 Jan 1992 15:11:00 NED
+ * added pointer to buffer pool within BUF struct
+ *
+ * Rev 1.8 03 Jan 1992 13:32:04 GREGG
+ * New buffer management integration
+ *
+ * Rev 1.7 10 Dec 1991 16:40:36 GREGG
+ * SKATEBOARD - New Buf. Mgr. - Initial integration.
+ *
+ * Rev 1.6 22 Aug 1991 16:44:14 NED
+ * Added macros for referencing the internals of the buffer structure.
+ *
+ * Rev 1.5 24 Jun 1991 13:24:34 CARLS
+ * Added os_reserved array for Windows
+ *
+ * Rev 1.4 04 Jun 1991 11:22:48 BARRY
+ * Removed OS-specific fields from the BUF structure. These are
+ * now allocated as part of the buffer.
+ *
+ * Rev 1.3 03 Jun 1991 08:58:28 CARLS
+ * typing error
+ *
+ * Rev 1.2 03 Jun 1991 08:33:22 CARLS
+ * added changes for Windows
+ *
+ * Rev 1.1 10 May 1991 17:10:18 GREGG
+ * Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:13:06 GREGG
+Initial revision.
+
+**/
+
+#if !defined( _BUFFMAN_H )
+#define _BUFFMAN_H
+
+/* How to describe the specific requirements for one chunk */
+
+typedef struct BLOCK_REQ *BLOCK_REQ_PTR;
+typedef struct BLOCK_REQ
+{
+ UINT16 min_size ; /* Minimum size of allocation */
+ UINT16 max_size ; /* Maximum size of allocation */
+ UINT16 incr_size ; /* Size to increase by if reallocated for more space */
+ UINT16 block ; /* rw_size must be multiple of this size */
+ UINT16 align ; /* physical byte alignment of allocation */
+}
+BLOCK_REQ;
+
+#define BR_DONT_CARE 0 /* use for size requirements */
+
+/* defines used for align or block requirements */
+#define BR_ALIGN_DONT_CARE 1
+#define BR_ALIGN_WORD 2
+#define BR_ALIGN_64K 0
+
+/* How to describe all the requirements for the buffer manager */
+
+typedef struct BUF_REQ *BUF_REQ_PTR;
+typedef struct BUF_REQ
+{
+ BLOCK_REQ a; /* for tape format transfers */
+ UINT16 tf_size ; /* size which TF can use */
+ UINT16 rw_size ; /* size of device driver transfers */
+
+ BLOCK_REQ b; /* for auxiliary uses */
+} BUF_REQ;
+
+/* Error codes returned from buffer manager requirements sub(sub)unit */
+
+typedef enum BR_ERR
+{
+ BR_NO_ERR = 0, /* OK */
+ BR_ERR_INCOMPATIBLE, /* new requirement is incompatible with current */
+ BR_ERR_BAD_REQUIREMENT /* requirement given is internally inconsistent */
+} BR_ERR;
+
+typedef enum BR_ERR *BR_ERR_PTR;
+
+#if defined( OS_DOS )
+
+ struct _DOS_MEM_CHUNK; /* forward reference */
+
+ /* Pointer to element of DOS memory management linked list */
+ typedef struct _DOS_MEM_CHUNK * DOS_MEM_CHUNK_PTR ;
+
+#endif
+
+/* Pointer to BUF structure to be declared later (mutual reference problem) */
+
+typedef struct BUF *BUF_PTR ;
+
+/* List of buffers, containing a requirements context. */
+
+typedef struct BUF_LIST *BUF_LIST_PTR;
+typedef struct BUF_LIST
+{
+ BUF_REQ requirements_context ;
+ UINT32 max_memory ; /* our suggested memory limit */
+
+ /* BM Private: */
+ Q_HEADER list_header ; /* list of BUFs */
+ BUF_PTR vcb_buff ;
+ UINT32 memory_used ; /* total memory we actually used */
+ Q_ELEM q_elem ; /* for BM list-of-lists */
+#if defined( OS_DOS )
+ DOS_MEM_CHUNK_PTR dos_mem_pool ; /* for DOS memory management */
+#endif
+
+} BUF_LIST;
+
+/* The BUF structure itself. */
+
+typedef struct BUF
+{
+ Q_ELEM tf_qe ; /* Struct for TF queue manipulations */
+
+ /*****************************************/
+ /* BM Private: */
+ BUF_LIST_PTR list_ptr; /* list which this buffer is on (ugh!) */
+ UINT16 alloc_size ; /* size of primary (xfer) allocation
+ * plus BM_RESERVED_SIZE */
+ UINT16 aux_size ; /* size of allocation "b" */
+ Q_ELEM bm_qe ; /* Struct for BM queue manipulations */
+ UINT16 gotten : 1; /* TRUE if BM_Get has been called with no BM_Put */
+ UINT16 reserved : 1; /* TRUE if BM_PutAll should not put this one */
+ /*****************************************/
+
+ /* immediately prior to this allocation is a BM_OS_RESERVED. */
+ VOID_PTR ptr1 ; /* Ptr to primary (xfer) allocation */
+
+ VOID_PTR ptr2 ; /* secondary allocation (opt.) */
+
+ UINT16 tf_size ; /* size which TF can use */
+ UINT16 rw_size ; /* size of device driver transfers */
+
+ UINT16 bytes_free ; /* The number of free in this buffer */
+ UINT16 no_dblks ; /* The number of Dblk */
+ UINT16 next_byte ; /* Write: Where to store next byte
+ Read: Where to get next byte */
+ UINT32 beginning_lba ;
+ INT16 read_error ; /* return code from TpReceive */
+} BUF ;
+
+/* Buffer Pool functions ("inline" and otherwise) */
+
+#define BM_ListCount( buf_list_ptr ) QueueCount(&(buf_list_ptr)->list_header)
+#define BM_ListHead( buf_list_ptr ) QueueHead(&(buf_list_ptr)->list_header)
+#define BM_ListTail( buf_list_ptr ) QueueTail(&(buf_list_ptr)->list_header)
+#define BM_ListRequirements( buf_list_ptr ) (&(buf_list_ptr)->requirements_context)
+#define BM_SetListRequirements( buf_list_ptr, buf_req_ptr ) ((buf_list_ptr)->requirements_context = *(buf_req_ptr))
+
+/* Initialize an empty list */
+INT16 BM_InitList(
+ BUF_LIST_PTR list_ptr, /* I/O -- list to de-initialize */
+ UINT16 initial_buff_alloc /* I -- Initial memory to allocate */
+);
+
+/* De-initialize a list: free all the buffers on the list */
+VOID BM_DeInitList(
+ BUF_LIST_PTR list_ptr /* I/O -- list to de-initialize */
+);
+
+/* Do a BM_Put on all non-reserved buffers in a pool */
+VOID BM_PutAll(
+ BUF_LIST_PTR list_ptr /* I/O -- list to Put */
+);
+
+/* Do a BM_Free on all non-reserved buffers in a pool */
+VOID BM_FreeAll(
+ BUF_LIST_PTR list_ptr /* I/O -- list to Free */
+);
+
+/* Buffer functions ("inline" and otherwise) */
+
+#define BM_Reserve( buf_ptr ) ((buf_ptr)->reserved = 1)
+#define BM_UnReserve( buf_ptr ) ((buf_ptr)->reserved = 0)
+#define BM_QElem( buf_ptr ) ((buf_ptr)->tf_qe)
+#define BM_BMQElem( buf_ptr ) ((buf_ptr)->bm_qe)
+#define BM_XferBase( buf_ptr ) ((buf_ptr)->ptr1)
+#define BM_XferSize( buf_ptr ) ((buf_ptr)->rw_size)
+#define BM_TFSize( buf_ptr ) ((buf_ptr)->tf_size)
+#define BM_BytesFree( buf_ptr ) ((buf_ptr)->bytes_free)
+#define BM_NoDblks( buf_ptr ) ((buf_ptr)->no_dblks)
+#define BM_NextByteOffset( buf_ptr ) ((buf_ptr)->next_byte)
+#define BM_BeginningLBA( buf_ptr ) ((buf_ptr)->beginning_lba)
+#define BM_ReadError( buf_ptr ) ((buf_ptr)->read_error)
+#define BM_AuxBase( buf_ptr ) ((buf_ptr)->ptr2)
+#define BM_AuxSize( buf_ptr ) ((buf_ptr)->aux_size)
+
+#define BM_NextBytePtr( buf_ptr ) (VOID_PTR)((UINT8_PTR)BM_XferBase(buf_ptr) + BM_NextByteOffset(buf_ptr))
+#define BM_LastByteOffset( buf_ptr ) (BM_NextByteOffset(buf_ptr) + BM_BytesFree(buf_ptr))
+#define BM_LastBytePtr( buf_ptr ) (VOID_PTR)((UINT8_PTR)BM_XferBase(buf_ptr) + BM_LastByteOffset(buf_ptr))
+
+#define BM_SetNoDblks( buf_ptr, n ) ((buf_ptr)->no_dblks = (n))
+#define BM_IncNoDblks( buf_ptr ) ((buf_ptr)->no_dblks++)
+
+/* note: we clip bytes_free to at most tf_size */
+#define BM_SetBytesFree( buf_ptr, n ) \
+ if ((n) >= (buf_ptr)->tf_size ) { \
+ (buf_ptr)->bytes_free = (buf_ptr)->tf_size ; \
+ } else { \
+ (buf_ptr)->bytes_free = (n) ; \
+ }
+
+#define BM_SetReadError( buf_ptr, n ) ((buf_ptr)->read_error = (n))
+#define BM_SetNextByteOffset( buf_ptr, n ) ((buf_ptr)->next_byte = (n))
+#define BM_SetBeginningLBA( buf_ptr, n ) ((buf_ptr)->beginning_lba = (n))
+
+#define BM_IsVCBBuff( buf_ptr ) ((buf_ptr) == (buf_ptr->list_ptr->vcb_buff))
+
+/* Put a buffer back on the buffer pool */
+#define BM_Put( buf_ptr ) { msassert( buf_ptr != NULL ); buf_ptr->gotten = FALSE; }
+
+/* Initialize the buffer manager subsystem */
+VOID BM_Init( VOID ) ;
+
+/* De-initialize the buffer manager subsystem */
+VOID BM_DeInit( VOID ) ;
+
+/* Set a requirements context to default values */
+VOID BM_ClearRequirements(
+ BUF_REQ_PTR context /* I/O -- context to clear */
+);
+
+/* Add a set of requirements to an existing context */
+BR_ERR BM_AddRequirements(
+ BUF_REQ_PTR context, /* I/O -- context to add requirements to */
+ BUF_REQ_PTR newreqs /* I -- new requirements */
+);
+
+/* Return the amount of memory used by a (hypothetical) buffer */
+UINT32 BM_RequiredSize(
+ BUF_REQ_PTR br_ptr /* I - requirements pointer */
+);
+
+/* Return the amount of memory used by a (hypothetical) buffer
+ * if it has 0 bytes of main and auxiliary allocation.
+ */
+UINT16 BM_BufferOverhead( VOID );
+
+/* Increases the size of the auxiliary buffer based on an increment value
+ * specified in the requirements context.
+ */
+INT16 BM_ReallocAux(
+ BUF_LIST_PTR list_ptr,
+ BUF_PTR buf_ptr
+);
+
+/********************************************************************
+ * OS-Specific functions
+ ********************************************************************/
+
+/* Allocate a buffer for the given list */
+BUF_PTR BM_Alloc( /* Return: NULL if unsuccessful */
+ BUF_LIST_PTR pool /* list we're allocating it for */
+);
+
+/* Allocate a VCB Buffer */
+BUF_PTR BM_AllocVCB(
+ BUF_LIST_PTR pool_ptr ); /* I - list to allocate from */
+
+/* Return a buffer to the OS free pool */
+VOID BM_Free(
+ BUF_LIST_PTR pool, /* list we're freeing it from */
+ BUF_PTR buffer /* the buffer to free */
+) ;
+
+/* Free a VCB buffer */
+VOID BM_FreeVCB(
+ BUF_LIST_PTR pool_ptr,
+ BUF_PTR buf_ptr );
+
+/* Resize the given buffer (may be VCB buffer) */
+INT16 BM_ReSizeBuff(
+ BUF_PTR buf_ptr,
+ BUF_LIST_PTR pool_ptr ) ;
+
+/* this re-sizes every buffer on the given list
+ * which isn't marked as reserved.
+ * Returns TFLE_xxx
+ */
+INT16 BM_ReSizeList(
+ BUF_LIST_PTR pool /* list to re-size */
+);
+
+/********************************************************************
+ * Non-OS-Specific functions
+ ********************************************************************/
+
+/* Get a buffer from the buffer pool */
+BUF_PTR BM_Get(
+ BUF_LIST_PTR pool /* describes buffer to Get */
+);
+
+/* clear out the TF fields (counts and offsets) in a buffer */
+VOID BM_InitBuf(
+ BUF_PTR buffer
+);
+
+/* Use some of the remaining bytes in a buffer. */
+VOID BM_UpdCnts(
+ BUF_PTR buffer,
+ UINT16 nused
+);
+
+/* consume all the remaining bytes in a buffer */
+VOID BM_UseAll(
+ BUF_PTR buffer
+);
+
+/* Set the buffer manager's idea of the VCB requirements
+ * argument must point to statically allocated memory (no copying is done)
+ */
+VOID BM_SetVCBRequirements(
+ BUF_REQ_PTR vcb_reqs /* points to vcb requirements structure */
+);
+
+/* Get the VCB buffer from the buffer pool */
+BUF_PTR BM_GetVCBBuff(
+ BUF_LIST_PTR pool /* describes buffer to Get */
+);
+
+/* Put a buffer back on the buffer pool */
+VOID BM_PutVCBBuff(
+ BUF_PTR buffer /* buffer to return to pool */
+) ;
+
+/* Translator interface */
+
+/* given a pointer to one of the two Q_ELEM's (link or channel_link)
+ * within the first THW_INF of a (master or channel) drive list,
+ * return translator's requirements via supplied BUF_REQ_PTR.
+ * Return TRUE if requirements structure was filled in.
+ * Assume that each Q_ELEM in list has its "ptr" member pointing at
+ * the THW_INF structure.
+ */
+typedef BOOLEAN (*BM_TR_GET_VCB_REQ_FUNC_PTR)(
+ BUF_REQ_PTR requirements, /* O -- translator's requirements */
+ Q_ELEM_PTR first_drive, /* I -- first drive in list */
+ UINT16 suggested_buff_size /* I - size from config */
+);
+
+typedef VOID (*BM_TR_GET_PREF_FUNC_PTR)(
+ Q_ELEM_PTR first_drive, /* I -- first drive in list */
+ UINT16 suggested_number_of_buffers, /* I -- from config */
+ UINT32 suggested_buffer_size, /* I -- from config */
+ UINT32_PTR buffer_requirements_ptr /* I/O -- needed */
+);
+
+#endif /* _BUFFMAN_H */
diff --git a/private/utils/ntbackup/inc/buffnt.h b/private/utils/ntbackup/inc/buffnt.h
new file mode 100644
index 000000000..8a3fcf408
--- /dev/null
+++ b/private/utils/ntbackup/inc/buffnt.h
@@ -0,0 +1,34 @@
+/**
+
+ Unit: Buffer Manager
+
+ Name: buffnt.h
+
+ Description: OS specific Buffer Manager defines, types and protos
+
+ $Log: T:\logfiles\buffnt.h_v $
+
+ Rev 1.1 28 Jan 1994 18:25:30 GREGG
+Fixed MIPS 16 byte alignment requirement bug.
+
+ Rev 1.0 26 Feb 1992 12:04:02 STEVEN
+Initial revision.
+
+**/
+
+// For byte allignment requirements on tape buffers
+#define BM_NT_DEFAULT_BUF_ALGN_SZ 16
+
+INT16 BM_OS_InitList( BUF_LIST_PTR list_ptr, UINT16 initial_buff_alloc ) ;
+
+#define BM_OS_DeInitList( x )
+#define BM_OS_CleanupList( x )
+#define BM_OS_BufferRequirements( avail_mem, x ) \
+ *avail_mem = 16UL * 1024UL * 1024UL
+
+/* prior to the allocation pointed at by BUF::ptr1, there exists the
+ * following area which may be used for OS-specific purposes.
+ * Thus the real allocation size is actually
+ * larger than that requested by BM_RESERVED_SIZE.
+ */
+#define BM_RESERVED_SIZE 0
diff --git a/private/utils/ntbackup/inc/catmaint.h b/private/utils/ntbackup/inc/catmaint.h
new file mode 100644
index 000000000..bc5e6d4b3
--- /dev/null
+++ b/private/utils/ntbackup/inc/catmaint.h
@@ -0,0 +1,12 @@
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_OPERATIONSCATMAINT 27
+#else
+#include "dlg_ids.h"
+#endif
+
+#define IDD_C_TAPE 0x00C9
+#define IDD_C_CHANGE 0x00CB
+#define IDD_C_REMOVE 0x00CA
+
diff --git a/private/utils/ntbackup/inc/cattape.h b/private/utils/ntbackup/inc/cattape.h
new file mode 100644
index 000000000..b175f0720
--- /dev/null
+++ b/private/utils/ntbackup/inc/cattape.h
@@ -0,0 +1,47 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: cattape.h
+
+ Description:
+
+
+ $Log: G:/UI/LOGFILES/CATTAPE.H_V $
+
+ Rev 1.4 04 Oct 1992 19:46:26 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.3 06 Apr 1992 09:56:06 CHUCKB
+Added define for translation.
+
+ Rev 1.2 27 Jan 1992 12:50:44 GLENN
+Fixed dialog IDs.
+
+ Rev 1.1 14 Dec 1991 11:16:50 CARLS
+new IDs for full/partial
+
+ Rev 1.0 09 Dec 1991 17:06:34 CARLS
+Initial revision.
+
+*******************************************************************************/
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_CATTAPE 29
+#else
+#include "dlg_ids.h"
+#endif
+
+#ifndef CATTAPE_H
+#define CATTAPE_H
+
+#define IDD_CATTAPE_MESSAGE 104
+#define IDD_CATTAPE_CONTINUE_BUTTON 101
+#define IDD_CATTAPE_CANCEL_BUTTON 102
+#define IDD_CATTAPE_HELP_BUTTON 103
+#define IDD_CATTAPE_EXCLAMATION_BITMAP 105
+#define IDD_CATTAPE_CATALOG_FULL 106
+#define IDD_CATTAPE_CATALOG_PARTIAL 107
+
+#endif
diff --git a/private/utils/ntbackup/inc/cbemon.h b/private/utils/ntbackup/inc/cbemon.h
new file mode 100644
index 000000000..48c7b5b2f
--- /dev/null
+++ b/private/utils/ntbackup/inc/cbemon.h
@@ -0,0 +1,125 @@
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+
+ Name: ddemang.h
+
+ Description: Status information for remote monitoring.
+
+ $Log: G:\ui\logfiles\cbemon.h_v $
+
+ Rev 1.3 27 Jun 1993 14:15:00 MIKEP
+add STAT_DRIVE_ERROR state.
+
+ Rev 1.2 15 Jun 1993 13:31:14 DARRYLP
+enhancements
+
+ Rev 1.1 27 Apr 1993 19:56:30 DARRYLP
+ID additions.
+
+ Rev 1.2 08 Apr 1993 16:38:14 DARRYLP
+Updates...
+
+******************************************************************************/
+
+#ifndef DDEMANG_H
+
+#define DDEMANG_H
+
+// Status Block Layout
+
+typedef struct
+{
+ DWORD Instance; // Instance of application reporting data.
+ DWORD DataSize; // Size in bytes of structure passed in
+ DWORD Unicode; // Non-zero if strings are unicode format
+
+ DWORD OperationStatus; // one of the STA_OPER_? defines
+ DWORD AppStatus; // one of the STA_APP_? defines
+ DWORD DriveStatus; // one of the STA_DRIVE_? defines
+
+ DWORD TapeFamily; // current tape in the drive
+ DWORD TapeSeqNumber;
+
+ DWORD BackupSet; // if writing, reading or cataloging a set
+
+ DWORD DirCount; // Directories backed up, restored, etc.
+ DWORD FileCount; // Files backed up, restored, etc.
+ DWORD ByteCountLo; // Bytes read/written
+ DWORD ByteCountHi;
+ DWORD CorruptFileCount;
+ DWORD SkippedFileCount;
+
+ DWORD ElapsedSeconds; // Time spent on current backup set in seconds
+
+ DWORD TapeFamilyNeeded;
+ DWORD TapeSeqNeeded;
+
+ // All strings are NULL terminated.
+
+ DWORD OffsetTapeDriveName;
+ DWORD OffsetCurrentTapeName;
+ DWORD OffsetServerVolume;
+ DWORD OffsetTapeDriveIdentifier;
+ DWORD OffsetTapeNeededName;
+ DWORD OffsetDiskName;
+ DWORD OffsetActiveFile;
+ DWORD OffsetErrorMsg;
+ DWORD OffsetActiveDir;
+} STAT_SETSTATUSBLOCK, *PSTAT_SETSTATUSBLOCK;
+
+#define STAT_OPER_IDLE 0
+#define STAT_OPER_BACKUP 1
+#define STAT_OPER_RESTORE 2
+#define STAT_OPER_ERASE 3
+#define STAT_OPER_VERIFY 4
+#define STAT_OPER_TENSION 5
+#define STAT_OPER_FORMAT 6
+#define STAT_OPER_TRANSFER 7
+#define STAT_OPER_CATALOG 8
+
+#define STAT_APP_OK 0
+#define STAT_APP_NEEDTAPE 1
+#define STAT_START_BACKUP 2
+#define STAT_END_BACKUP 3
+#define STAT_WAITING_OPENFILE 4
+#define STAT_SKIPPED_FILE 5
+#define STAT_CORRUPT_FILE 6
+#define STAT_ERROR 7
+
+#define STAT_DRIVE_EMPTY 0
+#define STAT_DRIVE_FOREIGN 1
+#define STAT_DRIVE_VALID 2
+#define STAT_DRIVE_BLANK 3
+#define STAT_DRIVE_UNFORMATTED 4
+#define STAT_DRIVE_BAD 5
+#define STAT_DRIVE_BUSY 6
+#define STAT_DRIVE_ERROR 7
+
+#define IDSM_INSTANCE 1
+#define IDSM_DATASIZE 2
+#define IDSM_UNICODE 3
+#define IDSM_OPERATIONSTATUS 4
+#define IDSM_APPSTATUS 5
+#define IDSM_DRIVESTATUS 6
+#define IDSM_TAPEFAMILY 7
+#define IDSM_TAPESEQNUMBER 8
+#define IDSM_BACKUPSET 9
+#define IDSM_DIRCOUNT 10
+#define IDSM_FILECOUNT 11
+#define IDSM_BYTECOUNTLO 12
+#define IDSM_BYTECOUNTHI 13
+#define IDSM_CORRUPTFILECOUNT 14
+#define IDSM_SKIPPEDFILECOUNT 15
+#define IDSM_ELAPSEDSECONDS 16
+#define IDSM_TAPEFAMILYNEEDED 17
+#define IDSM_TAPESEQNEEDED 18
+#define IDSM_OFFSETTAPEDRIVENAME 19
+#define IDSM_OFFSETCURRENTTAPENAME 20
+#define IDSM_OFFSETSERVERVOLUME 21
+#define IDSM_OFFSETTAPEDRIVEIDENTIFIER 22
+#define IDSM_OFFSETTAPENEEDEDNAME 23
+#define IDSM_OFFSETDISKNAME 24
+#define IDSM_OFFSETACTIVEFILE 25
+#define IDSM_OFFSETERRORMSG 26
+#define IDSM_OFFSETACTIVEDIR 27
+#endif
diff --git a/private/utils/ntbackup/inc/channel.h b/private/utils/ntbackup/inc/channel.h
new file mode 100644
index 000000000..98338a701
--- /dev/null
+++ b/private/utils/ntbackup/inc/channel.h
@@ -0,0 +1,212 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: channel.h
+
+ Description: Contains the control structure for each channel session.
+ This is the where any specific information for a given
+ channel is stored. The TFL has an array of these for all
+ possible channels. The channel number returned by the TFL
+ is an index into this array.
+
+
+ $Log: N:/LOGFILES/CHANNEL.H_V $
+ *
+ * Rev 1.19 15 Jun 1993 09:15:22 MIKEP
+ * warning fixes
+ *
+ * Rev 1.18 17 May 1993 20:12:38 GREGG
+ * Added logic to deal with the fact that the app above tape format doesn't
+ * keep track of the lba of the vcb.
+ *
+ * Rev 1.17 26 Apr 1993 11:45:38 GREGG
+ * Seventh in a series of incremental changes to bring the translator in line
+ * with the MTF spec:
+ *
+ * - Changed handling of EOM processing during non-OTC EOS processing.
+ *
+ * Matches CHANNEL.H 1.17, MAYN40RD.C 1.60, TFWRITE.C 1.63, MTF.H 1.5,
+ * TFLUTILS.C 1.44, MTF10WDB.C 1.10, MTF10WT.C 1.9
+ *
+ * Rev 1.16 17 Mar 1993 15:31:10 TERRI
+ * Added macro CurMediaType for use in the Sytos Plus translator.
+ *
+ * Rev 1.15 09 Mar 1993 18:14:04 GREGG
+ * Initial changes for new stream and EOM processing.
+ *
+ * Rev 1.14 22 Oct 1992 10:54:30 HUNTER
+ * Stream changes.
+ *
+ * Rev 1.13 17 Aug 1992 09:09:04 GREGG
+ * Changes to deal with block sizeing scheme.
+ *
+ * Rev 1.12 04 Aug 1992 15:16:38 GREGG
+ * Burt's fixes for variable length block support.
+ *
+ * Rev 1.11 21 May 1992 16:27:32 GREGG
+ * Added read_from_tape boolean to channel for cases where the translator wants to do the reading him
+ * self.
+ *
+ * Rev 1.10 29 Apr 1992 13:09:04 GREGG
+ * ROLLER BLADES - Added CH_EOM_BETWEEN_SETS channel status bit.
+ *
+ * Rev 1.9 05 Apr 1992 19:18:02 GREGG
+ * ROLLER BLADES - Added lb_size (logical block size) element to channel.
+ *
+ * Rev 1.8 25 Mar 1992 21:46:36 GREGG
+ * ROLLER BLADES - Added 64 bit support.
+ *
+ * Rev 1.7 10 Dec 1991 16:42:28 GREGG
+ * SKATEBOARD - New Buf. Mgr. - Initial integration.
+ *
+ * Rev 1.6 29 Oct 1991 08:47:54 HUNTER
+ * VBLK - Added bits to indicate variable data blocks.
+ *
+ * Rev 1.5 17 Oct 1991 01:14:12 GREGG
+ * BIGWHEEL - 8200SX - Added SX_INFO to channel structure.
+ *
+ * Rev 1.4 17 Sep 1991 13:54:18 GREGG
+ * Added save_fmt and save_env to channel structure for saving fmt during write continuation.
+ *
+ * Rev 1.3 22 Jul 1991 10:54:32 GREGG
+ * Added CH_EOS_AT_EOM channel status bit.
+ *
+ * Rev 1.2 15 Jul 1991 14:53:04 NED
+ * Removed unreferenced channel status bits and added CH_CONTINUING.
+ *
+ * Rev 1.1 10 May 1991 17:09:42 GREGG
+ * Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:13:14 GREGG
+Initial revision.
+
+**/
+#ifndef _CHANNEL_JUNK
+#define _CHANNEL_JUNK
+
+#include <queues.h>
+
+#include "fsys.h"
+#include "drive.h"
+#include "buffman.h"
+#include "dblkmap.h"
+#include "tflstats.h"
+#include "tpos.h"
+#include "sxtf.h"
+
+/* $end$ include list */
+
+typedef struct _CHANNEL {
+ UINT16 status ; /* The bit field containing stuff */
+ UINT16 mode ; /* Read or Write Mode */
+ DRIVE_PTR cur_drv ; /* The current drive we are operating on */
+ BUF_PTR cur_buff ; /* The current buffer if there is one */
+ BUF_PTR hold_buff ; /* To deal with var stream headers across buffer boundaries */
+ INT16 hiwater ; /* Hi-Water mark */
+ INT16 buffs_enqd ; /* The number of buffs enqued*/
+ UINT64 retranslate_size ; /* Should we recall the translators again */
+ BUF_PTR eom_buff ; /* The buffer at EOM */
+ UINT32 eom_id ; /* The last ID before EOM */
+ UINT16 eom_filter ; /* The filter used on the last block */
+ Q_HEADER channel_list ; /* Contains the channel list */
+ UINT16 perm_filter ; /* The permanent filter */
+ UINT16 loop_filter ; /* The filter from loops */
+ UINT16 active_filter ; /* Active filter */
+ UINT32 eom_lba ; /* The LBA at EOM */
+ UINT32 running_lba ; /* The running LBA */
+ UINT16 cur_fmt ; /* index into Current format (r/w) */
+ VOID_PTR fmt_env ; /* Current Environment Pointer for Channel */
+ UINT16 save_fmt ; /* To save cur_fmt at Continuation time */
+ VOID_PTR save_env ; /* To save fmt_env at Continuation time */
+ FSYS_HAND cur_fsys ; /* Current File System */
+ UINT8_PTR lst_osvcb ; /* The last VCB written to tape */
+ UINT8_PTR lst_osddb ; /* The last OSDDB written to tape */
+ UINT8_PTR lst_osfdb ; /* The last OSFDB written to tape */
+ UINT16 lst_tblk ; /* The last type of TAPE BLOCK */
+ DBLK_PTR cur_dblk ; /* The transfer OS DB buffer */
+ DBLKMAP_PTR map_entry ; /* For the dblk map entry */
+ TPOS_PTR ui_tpos ; /* The user interface TPOS */
+ UINT32 lst_did ; /* The last directory ID */
+ UINT32 lst_fid ; /* The last file ID */
+ INT32 tape_id ; /* The tape id */
+ INT16 ts_num ; /* Tape sequence */
+ INT16 bs_num ; /* backup set num */
+ UINT32 blocks_used ; /* number of tape blocks discarded */
+ SX_INFO sx_info ; /* for Exabyte SX - 2200+ positioning */
+ BUF_LIST buffer_list ; /* our pool of buffers for this channel */
+ UINT16 lb_size ; /* logical block size */
+ BOOLEAN read_from_tape ;
+ STREAM_INFO current_stream ; /* The current stream header */
+ INT16 cross_set ;
+ UINT32 cross_lba ;
+} CHANNEL, *CHANNEL_PTR ;
+
+/* NOTE: The fields "lst_osvcb", "lst_osddb", and "lst_fdb", during a write
+ operation normally contain the last TAPE BLOCK ( i.e. in the write
+ tape format ) of the respective types that was to tape. However,
+ when an EOM condition occurs these are translated in OSDBLKS there
+ current type can be determined by the matching flag, 0 for tape
+ block, 1 for DBLK.
+*/
+
+/* Gets the current Block size */
+#define ChannelBlkSize( channel ) (channel)->cur_drv->thw_inf.drv_info.drv_bsize
+
+/* Gets the Filemark Position of the current drive */
+#define NoFmksOnTape( channel ) (channel)->cur_drv->cur_pos.fmks
+
+/* Gets the Physical Block Address for this VCB */
+#define PbaOfVCB( channel ) (channel)->cur_drv->cur_pos.pba_vcb
+
+/* Current Drive Status */
+#define CurDrvStatus( channel ) (channel)->cur_drv->thw.drv_status
+
+/* Current Drive Attributes */
+#define CurDrvAttribs( channel ) (channel)->cur_drv->thw_inf.drv_info.drv_features
+
+/* Current Media Type */
+#define CurMediaType( channel ) (channel)->cur_drv->thw_inf.drv_info.drv_media
+
+/* Is there a tape mounted */
+#define IsTapeMounted( channel ) (channel)->cur_drv->tape_mounted
+
+/* Some Macros */
+
+/* Status Stuff */
+#define CH_IN_USE 0x0001
+#define CH_AT_EOM 0x0002
+#define CH_CONTINUING 0x0004
+#define CH_EOS_AT_EOM 0x0008
+#define CH_DATA_PHASE 0x0020
+#define CH_DONE 0x0040
+#define CH_VCB_DBLK 0x0080
+#define CH_DDB_DBLK 0x0100
+#define CH_FDB_DBLK 0x0200
+#define CH_FATAL_ERR 0x0400
+#define CH_SKIP_ALL_STREAMS 0x0800
+#define CH_SKIP_CURRENT_STREAM 0x1000
+
+// The following bit will be set to indicate that we need to write the
+// start VBLK after we do an AcquireWriteBuffer.
+#define CH_NEED_VBLK 0x1000
+
+#define SetChannelStatus( x, b ) ( (x)->status = ( (x)->status | (b) ) )
+#define ClrChannelStatus( x, b ) ( (x)->status = ( (x)->status & ~(b) ) )
+#define IsChannelStatus( x, b ) ( (x)->status & (b) )
+
+#define InUse( x ) IsChannelStatus( x, CH_IN_USE )
+#define AtEOM( x ) IsChannelStatus( x, CH_AT_EOM )
+#define DataPhase( x ) IsChannelStatus( x, CH_DATA_PHASE )
+#define IsSetDone( x ) IsChannelStatus( x, CH_DONE )
+#define FatalError( x ) IsChannelStatus( x, CH_FATAL_ERR )
+#define VarBlkPhase( x ) IsChannelStatus( x, CH_VAR_DATA )
+#define NeedVarBlk( x ) IsChannelStatus( x, CH_NEED_VBLK )
+
+/* values for retranslate_size */
+#define CH_NO_RETRANSLATE (~(0UL)) /* no retranslate */
+#define CH_IMMEDIATE_RETRANSLATE (0UL) /* retranslate on next chunk */
+/* Added these for the 4.0 format 64 Bit flavors */
+#define CH_NO_RETRANSLATE_40 (U64_Init( CH_NO_RETRANSLATE, CH_NO_RETRANSLATE ) )
+#define CH_IMMEDIATE_RETRANSLATE_40 (U64_Init( 0L, 0L ) )
+#endif
diff --git a/private/utils/ntbackup/inc/checksum.h b/private/utils/ntbackup/inc/checksum.h
new file mode 100644
index 000000000..7c1c8cdc6
--- /dev/null
+++ b/private/utils/ntbackup/inc/checksum.h
@@ -0,0 +1,27 @@
+/*==========================================================================
+
+ checksum.h - Experimental checksum algorithm.
+
+ Don Cross, 11 December 1992.
+
+ $Log: J:/LOGFILES/CHECKSUM.H_V $
+
+ Rev 1.2 03 Mar 1993 07:41:06 MARILYN
+added version info
+
+
+==========================================================================*/
+#ifndef _CHECKSUM_H_
+#define _CHECKSUM_H_
+
+VOID Checksum_Init ( UINT32_PTR checksum_ptr );
+
+UINT32 Checksum_Block ( UINT32_PTR checksum_ptr,
+ VOID_PTR data_ptr,
+ UINT32 data_len );
+
+INT16 LP_InsertChecksumStream( UINT32 checkSum, LP_ENV_PTR lp ) ;
+INT16 LP_VerifyChecksumStream( UINT32 checksum, LP_ENV_PTR lp ) ;
+
+#endif
+/*--- end of file checksum.h ---*/
diff --git a/private/utils/ntbackup/inc/cli.h b/private/utils/ntbackup/inc/cli.h
new file mode 100644
index 000000000..4125d12c4
--- /dev/null
+++ b/private/utils/ntbackup/inc/cli.h
@@ -0,0 +1,38 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: cli.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+ Location:
+
+
+ $Log: G:/LOGFILES/CLI.H_V $
+ *
+ * Rev 1.0 09 May 1991 13:32:46 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef _cli_h_
+#define _cli_h_
+
+
+extern BOOLEAN EnableInterrupts( VOID );
+extern BOOLEAN DisableInterrupts( VOID );
+
+#define RestoreInterruptState( interrupts_were_enabled ) if ( interrupts_were_enabled ) { \
+ EnableInterrupts(); \
+ } \
+ else { \
+ DisableInterrupts(); \
+ }
+
+
+
+#endif
diff --git a/private/utils/ntbackup/inc/config.h b/private/utils/ntbackup/inc/config.h
new file mode 100644
index 000000000..2426702fa
--- /dev/null
+++ b/private/utils/ntbackup/inc/config.h
@@ -0,0 +1 @@
+#include "muiconf.h"
diff --git a/private/utils/ntbackup/inc/crit_err.h b/private/utils/ntbackup/inc/crit_err.h
new file mode 100644
index 000000000..ed37da0e1
--- /dev/null
+++ b/private/utils/ntbackup/inc/crit_err.h
@@ -0,0 +1,35 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: crit_err.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This header file externs the uw_critical_error
+ flag ;
+
+
+ $Log: N:/LOGFILES/CRIT_ERR.H_V $
+ *
+ * Rev 1.1 04 Jun 1991 19:14:04 BARRY
+ * Critical error stuff is now os-specific. Critical error structures
+ * and functions now reside in separate source files.
+ *
+ *
+ * Rev 1.0 09 May 1991 13:30:36 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef CRIT_ERR_H
+#define CRIT_ERR_H
+
+extern INT16 (*uw_crit_err)( CHAR_PTR name, UINT16 err_code ) ;
+extern BOOLEAN uw_critical_error ;
+
+VOID InitCritErrorHandler( BOOLEAN (*crit_err)( CHAR_PTR, UINT16 ) );
+VOID DeInitCritErrorHandler( VOID );
+
+#endif
diff --git a/private/utils/ntbackup/inc/criterr.h b/private/utils/ntbackup/inc/criterr.h
new file mode 100644
index 000000000..5ca7c5ab2
--- /dev/null
+++ b/private/utils/ntbackup/inc/criterr.h
@@ -0,0 +1,91 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: criterr.h
+
+ Description:
+
+ Location:
+
+
+ $Log: G:/UI/LOGFILES/CRITERR.H_V $
+
+ Rev 1.1 04 Oct 1992 19:46:28 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.0 20 Nov 1991 19:36:24 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifndef CRITERR_H
+#define CRITERR_H
+
+#define IGNORE 0
+#define RETRY 1
+#define ABORT 2
+#define FAIL 3
+
+#define CRITICAL_WRITE 0
+#define CRITICAL_READ 1
+
+#define DOS_AREA 0
+#define FAT_AREA 1
+#define DIR_AREA 2
+#define DATA_AREA 3
+
+#define DISK_REC_ERROR 16
+#define DISK_UNREC_ERROR 32
+#define DISK_CRITICAL_ERROR ( DISK_REC_ERROR | DISK_UNREC_ERROR )
+#define CHAR_CRITICAL_ERROR 64
+
+#define is_disk_recoverable(x) ( x & DISK_REC_ERROR )
+#define WRITE_PROTECT_ERROR DISK_REC_ERROR + 0
+#define DRIVE_NOT_READY DISK_REC_ERROR + 1
+#define DRIVE_ERROR DISK_REC_ERROR + 2
+
+#define is_disk_unrecoverable(x) ( x & DISK_UNREC_ERROR )
+#define BAD_FAT DISK_UNREC_ERROR + 0
+#define INVALID_DRIVE DISK_UNREC_ERROR + 1
+#define INTERNAL_ERROR DISK_UNREC_ERROR + 2
+#define GENERAL_ERROR DISK_UNREC_ERROR + 3
+
+#define OUT_OF_PAPER CHAR_CRITICAL_ERROR + 1
+#define UNKNOWN CHAR_CRITICAL_ERROR + 2
+
+#define C_ERR_INPUT_TIMEOUT ( 18 * 60 * 1 )
+
+#define is_disk_error(x) ( x & DISK_CRITICAL_ERROR )
+
+/*
+
+ Function declarations
+
+ set_critical_error( disk_exc_handler, char_exc_handler )
+
+ where,
+
+ INT16 disk_exc_handler( error, drive, drive_oper, drive_region )
+ INT16 error; type of disk error
+ INT16 drive; A=0, B=1, etc...
+ INT16 drive_oper; read or write
+ INT16 drive_region; region on DISK
+
+ and,
+
+ where,
+
+ INT16 char_exc_handler( error, dev_name );
+ INT16 error; type of character error
+ CHAR far *dev_name; character device name
+
+ either entry can be NULL.
+
+*/
+
+VOID set_critical_error( INT16 ( *c_disk_err_rout ) ( ),
+ INT16 ( *c_char_err_rout ) ( ) ) ;
+
+
+#endif
diff --git a/private/utils/ntbackup/inc/ctl3d.h b/private/utils/ntbackup/inc/ctl3d.h
new file mode 100644
index 000000000..72280c31b
--- /dev/null
+++ b/private/utils/ntbackup/inc/ctl3d.h
@@ -0,0 +1,91 @@
+/*-----------------------------------------------------------------------
+| CTL3D.DLL
+|
+| Adds 3d effects to Windows controls
+|
+| See ctl3d.doc for info
+|
+-----------------------------------------------------------------------*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+BOOL WINAPI Ctl3dSubclassDlg(HWND, WORD);
+BOOL WINAPI Ctl3dSubclassDlgEx(HWND, DWORD);
+
+WORD WINAPI Ctl3dGetVer(void);
+BOOL WINAPI Ctl3dEnabled(void);
+
+HBRUSH WINAPI Ctl3dCtlColor(HDC, LONG); // ARCHAIC, use Ctl3dCtlColorEx
+HBRUSH WINAPI Ctl3dCtlColorEx(UINT wm, WPARAM wParam, LPARAM lParam);
+
+BOOL WINAPI Ctl3dColorChange(void);
+
+BOOL WINAPI Ctl3dSubclassCtl(HWND);
+BOOL WINAPI Ctl3dSubclassCtlEx(HWND, int);
+BOOL WINAPI Ctl3dUnsubclassCtl(HWND);
+
+LONG WINAPI Ctl3dDlgFramePaint(HWND, UINT, WPARAM, LPARAM);
+
+BOOL WINAPI Ctl3dAutoSubclass(HANDLE);
+BOOL WINAPI Ctl3dIsAutoSubclass(VOID);
+BOOL WINAPI Ctl3dUnAutoSubclass(VOID);
+
+BOOL WINAPI Ctl3dRegister(HANDLE);
+BOOL WINAPI Ctl3dUnregister(HANDLE);
+
+//begin DBCS: far east short cut key support
+VOID WINAPI Ctl3dWinIniChange(void);
+//end DBCS
+
+
+/* Ctl3d Control ID */
+#define CTL3D_BUTTON_CTL 0
+#define CTL3D_LISTBOX_CTL 1
+#define CTL3D_EDIT_CTL 2
+#define CTL3D_COMBO_CTL 3
+#define CTL3D_STATIC_CTL 4
+
+/* Ctl3dSubclassDlg3d flags */
+#define CTL3D_BUTTONS 0x0001
+#define CTL3D_LISTBOXES 0x0002
+#define CTL3D_EDITS 0x0004
+#define CTL3D_COMBOS 0x0008
+#define CTL3D_STATICTEXTS 0x0010
+#define CTL3D_STATICFRAMES 0x0020
+
+#define CTL3D_NODLGWINDOW 0x00010000
+#define CTL3D_ALL 0xffff
+
+#define WM_DLGBORDER (WM_USER+3567)
+/* WM_DLGBORDER *(int FAR *)lParam return codes */
+#define CTL3D_NOBORDER 0
+#define CTL3D_BORDER 1
+
+#define WM_DLGSUBCLASS (WM_USER+3568)
+/* WM_DLGSUBCLASS *(int FAR *)lParam return codes */
+#define CTL3D_NOSUBCLASS 0
+#define CTL3D_SUBCLASS 1
+
+#define CTLMSGOFFSET 3569
+#ifdef WIN32
+#define CTL3D_CTLCOLORMSGBOX (WM_USER+CTLMSGOFFSET)
+#define CTL3D_CTLCOLOREDIT (WM_USER+CTLMSGOFFSET+1)
+#define CTL3D_CTLCOLORLISTBOX (WM_USER+CTLMSGOFFSET+2)
+#define CTL3D_CTLCOLORBTN (WM_USER+CTLMSGOFFSET+3)
+#define CTL3D_CTLCOLORSCROLLBAR (WM_USER+CTLMSGOFFSET+4)
+#define CTL3D_CTLCOLORSTATIC (WM_USER+CTLMSGOFFSET+5)
+#define CTL3D_CTLCOLORDLG (WM_USER+CTLMSGOFFSET+6)
+#else
+#define CTL3D_CTLCOLOR (WM_USER+CTLMSGOFFSET)
+#endif
+
+
+/* Resource ID for 3dcheck.bmp (for .lib version of ctl3d) */
+#define CTL3D_3DCHECK 26567
+
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/private/utils/ntbackup/inc/cursors.h b/private/utils/ntbackup/inc/cursors.h
new file mode 100644
index 000000000..a0ad8d95e
--- /dev/null
+++ b/private/utils/ntbackup/inc/cursors.h
@@ -0,0 +1,38 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: cursors.h
+
+ Description: This file contains the CURSOR IDs for the Maynstream GUI
+ project.
+
+ $Log: G:/UI/LOGFILES/CURSORS.H_V $
+
+ Rev 1.2 04 Oct 1992 19:46:28 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.1 26 Mar 1992 08:53:08 GLENN
+Added new pen.
+
+ Rev 1.0 20 Nov 1991 19:36:04 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+// CURSOR RESOURCE IDs
+
+// Windows Internal Cursors.
+
+#define IDRC_ARROW IDC_ARROW
+#define IDRC_WAIT IDC_WAIT
+#define IDRC_IBEAM IDC_IBEAM
+
+// GUI Subsystem Cursors. -- RANGE: 21 - 30
+
+#define IDRC_PEN ID(21)
+#define IDRC_HAND ID(22)
+#define IDRC_HSLIDER ID(23)
+#define IDRC_HELP ID(24)
+#define IDRC_PEN2 ID(25)
diff --git a/private/utils/ntbackup/inc/d_o_bkup.h b/private/utils/ntbackup/inc/d_o_bkup.h
new file mode 100644
index 000000000..37a906b80
--- /dev/null
+++ b/private/utils/ntbackup/inc/d_o_bkup.h
@@ -0,0 +1,80 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: D_O_BKUP.H
+
+ Description:
+
+ $Log: G:\ui\logfiles\d_o_bkup.h_v $
+
+ Rev 1.4 25 Jun 1993 10:31:56 CARLS
+added GenerateDefaultTapeName prototype
+
+ Rev 1.3 04 Oct 1992 19:46:52 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.2 28 Jul 1992 14:55:10 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.1 20 Dec 1991 13:19:16 CARLS
+
+ Rev 1.0 20 Nov 1991 19:37:48 SYSTEM
+Initial revision.
+
+*****************************************************/
+#ifndef d_o_bkup_h
+#define d_o_bkup_h
+
+#ifdef OEM_EMS
+
+// Control Modes
+#define CM_HIDE 0
+#define CM_ENABLE 1
+#define CM_DISABLE 2
+
+typedef struct DLG_CTRL_ENTRY {
+ INT iCtlId;
+ HWND hCtlWnd;
+ INT iCtlDispStyle;
+} DLG_CTRL_ENTRY;
+
+typedef struct DLG_DISPLAY_ENTRY {
+ INT iDispType;
+ DLG_CTRL_ENTRY *CtlTable;
+ UINT16 ucCtrls;
+ DWORD help_id;
+
+} DLG_DISPLAY_ENTRY;
+
+typedef struct DLG_MODE {
+ WORD wModeType;
+ DLG_DISPLAY_ENTRY *DispTable;
+ UINT16 ucDispTables;
+ DLG_DISPLAY_ENTRY *pCurDisp;
+} DLG_MODE;
+
+DLG_MODE *DM_InitCtrlTables( HWND, DLG_MODE *, UINT16, WORD );
+
+VOID DM_DispShowControls( HWND, DLG_MODE *, INT );
+
+DWORD DM_ModeGetHelpId( DLG_MODE * );
+
+#endif // OEM_EMS
+
+
+BOOL DM_StartDialog( HWND, WORD, VOID_PTR ) ;
+INT DM_StartBackupSet( INT ) ;
+VOID BackupSetSave( HWND ) ;
+#ifndef OEM_EMS
+VOID BackupSetRetrieve( HWND ) ;
+#else
+VOID BackupSetRetrieve( HWND, DLG_MODE * );
+#endif
+INT BackupSetDefaultDescription( VOID ) ;
+VOID BackupSetDefaultSettings( VOID ) ;
+BSD_PTR GetBSDPointer( WORD ) ;
+VOID PropagateTapeName( VOID ) ;
+VOID PropagateTapePassword( VOID ) ;
+VOID GenerateDefaultTapeName( CHAR_PTR ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/d_o_rset.h b/private/utils/ntbackup/inc/d_o_rset.h
new file mode 100644
index 000000000..637b02e97
--- /dev/null
+++ b/private/utils/ntbackup/inc/d_o_rset.h
@@ -0,0 +1,47 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: D_O_RSET.H
+
+ Description:
+
+ $Log: G:/UI/LOGFILES/D_O_RSET.H_V $
+
+ Rev 1.4 04 Oct 1992 19:46:54 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.3 28 Jul 1992 14:55:00 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.2 22 Jan 1992 16:21:46 CHUCKB
+Changed prototype for RestoreSetSave.
+
+ Rev 1.1 20 Jan 1992 09:46:10 GLENN
+Moved configuration definitions to MUICONF.H
+
+ Rev 1.0 20 Nov 1991 19:35:18 SYSTEM
+Initial revision.
+
+*****************************************************/
+#ifndef d_o_rset_h
+#define d_o_rset_h
+
+// For restore definitions, see muiconf.h
+
+BOOL RestoreSetSave( HWND ) ;
+#ifndef OEM_EMS
+VOID RestoreSetRetrieve ( HWND );
+#else
+VOID RestoreSetRetrieve( HWND, DLG_MODE * );
+#endif
+INT RestoreSetDefaultDescription( VOID ) ;
+
+BSD_PTR GetTapeBSDPointer( INT ) ;
+VOID GetCurrentRestoreDriveList( HWND ) ;
+VOID GetRestoreDrive( HWND ) ;
+VOID SetRestoreDrive( HWND ) ;
+VOID RestoreSaveTargetPaths( VOID ) ;
+VOID SetDefaultDLE( HWND ) ;
+INT GetMaxBSDCount( VOID ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/datetime.h b/private/utils/ntbackup/inc/datetime.h
new file mode 100644
index 000000000..eb9438a32
--- /dev/null
+++ b/private/utils/ntbackup/inc/datetime.h
@@ -0,0 +1,119 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: datetime.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the definition for the date_time structure.
+
+ Location: BE_PUBLIC
+
+
+ $Log: M:/LOGFILES/DATETIME.H_V $
+ *
+ * Rev 1.6 09 Jul 1993 13:26:48 JOHNES
+ * Added another display buffer #define.
+ *
+ * Rev 1.5 09 Jul 1993 11:54:34 JOHNES
+ * Added some #defines for date and time display buffer sizes.
+ *
+ *
+ * Rev 1.4 08 Jun 1993 13:59:44 MIKEP
+ * Enable C++ compile.
+ *
+ * Rev 1.3 05 Nov 1992 15:23:58 STEVEN
+ * unicode
+ *
+ * Rev 1.2 24 Jun 1991 17:08:08 STEVEN
+ * remove MBS switch
+ *
+ * Rev 1.1 21 Jun 1991 10:54:44 BILLB
+ * Removed include for mbsmac.h
+ *
+ *
+ * Rev 1.0 09 May 1991 13:31:08 HUNTER
+ * Initial revision.
+
+**/
+
+#ifndef _DATE_TIME_J
+#define _DATE_TIME_J
+/* $end$ include list */
+
+ /* Nobody seemed to know what these buffer sizes should be */
+ /* so I dropped these in. I'm not sure ho often they will */
+ /* be used though. */
+#define DISP_DATE_SIZE 9 /* xx/xx/xx(null) */
+#define DISP_TIME_HR_MIN_SIZE 6 /* hh:mm(null) */
+#define DISP_TIME_HMS_SIZE 9 /* hh:mm:ss(null) */
+#define DISP_TIME_HR_MIN_AP_SIZE 7 /* hh:mmp(null) */
+#define DISP_DATE_TIME_SIZE 16 /* xx/xx/xx hh:mmp(null) see UI_ThisDateTimetoString */
+
+
+
+/* Predefine the generic Date & Time structure used throughout */
+
+typedef struct DATE_TIME *DATE_TIME_PTR;
+typedef struct DATE_TIME {
+ UINT16 date_valid ; /* TRUE or FALSE */
+ UINT16 year ; /* year since 1900 */
+ UINT16 month ; /* 1 to 12 */
+ UINT16 day ; /* 1 to 31 */
+ UINT16 hour ; /* 0 to 23 */
+ UINT16 minute ; /* 0 to 59 */
+ UINT16 second ; /* 0 to 59 */
+ UINT16 day_of_week ; /* 1 to 7 for Sunday to Saturday */
+} DATE_TIME;
+
+VOID GetCurrentDate( DATE_TIME_PTR date_time ) ;
+
+INT32 datecmp( DATE_TIME_PTR date_time1, DATE_TIME_PTR date_time2 );
+
+VOID DOSDateTime(
+ DATE_TIME_PTR date_time, /* I - maynard date time to convert */
+ UINT16_PTR date, /* O - DOS dta date structure */
+ UINT16_PTR time ) ; /* O - DOS dta time structure */
+
+
+UINT16 ConvertDateDOS( DATE_TIME_PTR date ) ;
+
+UINT16 ConvertTimeDOS( DATE_TIME_PTR date ) ;
+
+VOID DateTimeDOS(
+ UINT16 DOS_date ,
+ UINT16 DOS_time ,
+ DATE_TIME_PTR date_time ) ;
+
+VOID StringToDateTime( CHAR_PTR date_str, CHAR_PTR time_str, DATE_TIME_PTR date_time );
+
+INT16 CompDate( DATE_TIME_PTR d1, DATE_TIME_PTR d2 ) ;
+
+
+#define DateTimeToDateString( date_time, date_str ) \
+ if ( (date_str) != NULL ) { \
+ sprintf( (date_str), TEXT("%02d/%02d/%02d"), (date_time)->month, \
+ (date_time)->day, \
+ (date_time)->year % 100 ); \
+ }
+
+#define DateTimeToTimeString( date_time, time_str ) \
+ if ( (time_str) != NULL ) { \
+ sprintf( (time_str), TEXT("%02d:%02d:%02d"), (date_time)->hour, \
+ (date_time)->minute, \
+ (date_time)->second ); \
+ }
+
+#define DateTimeToString( date_time, date_str, time_str ) \
+ { \
+ DateTimeToDateString( (date_time), (date_str) ); \
+ DateTimeToTimeString( (date_time), (time_str) ); \
+ }
+
+#define hour12( hour ) ( hour == 0 ? 12:( hour > 12 ) ? hour - 12 : hour )
+
+VOID CurrentDateTimetoString( CHAR_PTR buffer ) ;
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/dateutil.h b/private/utils/ntbackup/inc/dateutil.h
new file mode 100644
index 000000000..0af630429
--- /dev/null
+++ b/private/utils/ntbackup/inc/dateutil.h
@@ -0,0 +1,114 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+ Name: dateutil.h
+
+ Description: This is the header file for the date utilities module. These are the functions
+ contained in the "DATEUTIL" module :
+
+ DU_IsLeapYear - This routine accepts a year and determines if it is a leap year.
+
+ DU_DateTimeToTm - This routine will accept a tm structure and build the DATE_TIME structure.
+
+ DU_TmToDateTime - This routine will accept the DATE_TIME structure and build a tm structure.
+
+ DU_Time_TToDateTime - This routine takes a time_t pointer which contains a date and time
+ represented as the number of seconds passed since 00:00:00 Jan 1, 1970 (GMT),
+ and converts it to a structure of type DATE_TIME pointed to by datetime.
+
+ DU_DateTimeToTime_T - This routine takes a pointer to a structure of type DATE_TIME
+ and converts it to the number of seconds passed since 00:00:00
+ Jan 1, 1970 (GMT) and assigns that value to the time_t pointer.
+
+ DU_JulianToDateTime - This routine takes a julian date [0-365] and a year and updates
+ the DATE_TIME structure.
+
+ DU_CalcTargetDateBackwd - This routine when passed a date_time structure by reference, and the
+ number of days to go back, it will accordingly update the date_time
+ structure.
+
+ DU_CalcTargetDateFwd - This routine when passed a date_time structure by reference, and the
+ number of days to go forward, it will accordingly update the date_time
+ structure.
+
+ DU_CalcNumberDaysBackwd - This routine when passed a date_time structure by reference, will calculate the
+ number of days that date is back from the current date. It will not update the
+ date_time structure at all.
+
+ DU_CalcNumDaysFromToday - The given DATE_TIME structure is converted into a time_t value. Then the current
+ time_t is read from the system clock. This routine will then calculate the
+ difference in days between the current date and the given date.
+
+ $Log: G:/UI/LOGFILES/DATEUTIL.H_V $
+
+ Rev 1.1 04 Oct 1992 19:46:30 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.0 20 Nov 1991 19:36:30 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifndef _dateutil_h
+#define _dateutil_h
+
+#include "stdtypes.h"
+#include "datetime.h"
+#include <time.h>
+/* $end$ include list */
+
+/***** function prototypes *******/
+
+BOOLEAN DU_IsLeapYear(
+ INT16 year
+ ) ;
+
+INT16 DU_DateTimeToTm(
+ struct tm *ms_date_ptr,
+ DATE_TIME_PTR start_date
+ ) ;
+
+INT16 DU_TmToDateTime(
+ struct tm *ms_date_ptr,
+ DATE_TIME_PTR start_date
+ ) ;
+
+INT16 DU_CalcTargetDateBackwd(
+ DATE_TIME_PTR start_date,
+ INT16 days_to_go_back
+ ) ;
+
+INT16 DU_CalcTargetDateFwd(
+ DATE_TIME_PTR start_date,
+ INT16 days_to_go_fwd
+ ) ;
+
+INT16 DU_JulianToDateTime(
+ INT16 j_date,
+ INT16 year,
+ DATE_TIME_PTR dt
+ ) ;
+
+INT16 DU_Time_TToDateTime(
+ time_t *timet,
+ DATE_TIME_PTR datetime
+ ) ;
+
+INT16 DU_DateTimeToTime_T(
+ time_t *timet,
+ DATE_TIME_PTR datetime
+ ) ;
+
+INT16 DU_CalcNumDaysFromToday(
+ DATE_TIME date_time, /* I - date time to be subtracted from today's date */
+ INT16_PTR days_from_today /* O - difference in days from given date and today's date */
+ ) ;
+
+INT16 DU_CalcNumberDaysBackwd(
+ DATE_TIME_PTR input_date,
+ INT16_PTR days_back_ptr
+ ) ;
+
+#endif
+
+
diff --git a/private/utils/ntbackup/inc/dblkmap.h b/private/utils/ntbackup/inc/dblkmap.h
new file mode 100644
index 000000000..8bfe97c4c
--- /dev/null
+++ b/private/utils/ntbackup/inc/dblkmap.h
@@ -0,0 +1,37 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: dblkmap.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the definition for DBLK map
+
+ Location:
+
+
+ $Log: N:/LOGFILES/DBLKMAP.H_V $
+ *
+ * Rev 1.2 13 May 1992 12:01:40 STEVEN
+ * 40 format changes
+ *
+ * Rev 1.1 10 May 1991 17:08:40 GREGG
+ * Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:13:16 GREGG
+Initial revision.
+
+**/
+#ifndef _DBLK_MAP
+#define _DBLK_MAP
+
+/* $end$ include list */
+
+typedef struct {
+ UINT16 blk_type ; /* The type of this block */
+ UINT16 blk_offset ; /* Where the block resides in the buffer */
+ UINT64 blk_data ; /* data size for block */
+} DBLKMAP, *DBLKMAP_PTR ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/dblks.h b/private/utils/ntbackup/inc/dblks.h
new file mode 100644
index 000000000..320227318
--- /dev/null
+++ b/private/utils/ntbackup/inc/dblks.h
@@ -0,0 +1,281 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: dblks.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file defines the DBLK structure and contains
+ the definition of the BLOCK IDs
+
+ Location: BE_PUBLIC
+
+
+ $Log: T:/LOGFILES/DBLKS.H_V $
+ *
+ * Rev 1.22 13 Oct 1993 20:31:24 GREGG
+ * Redefined attribute bit values to match the MTF spec.
+ *
+ * Rev 1.21 03 Sep 1993 10:48:12 GREGG
+ * Set DBLK data size to 1024 and added comment about how to alloc a DBLK struct.
+ *
+ * Rev 1.20 06 Aug 1993 16:33:14 DON
+ * Added VOLB attribute defines for no_redirect_restore and non_volume
+ *
+ * Rev 1.19 15 Jul 1993 19:17:10 GREGG
+ * Added VCB attrib bits for FUTURE_VER, COMPRESSED and ENCRYPTED sets.
+ *
+ * Rev 1.18 15 Jul 1993 13:49:00 DON
+ * Added a field to the common dblk for 'name space'
+ *
+ * Rev 1.17 13 Jul 1993 19:15:12 GREGG
+ * Added 'compressed_obj' element to common DBLK.
+ *
+ * Rev 1.16 09 Jun 1993 15:37:06 MIKEP
+ * enable c++
+ *
+ * Rev 1.15 26 Apr 1993 02:43:38 GREGG
+ * Sixth in a series of incremental changes to bring the translator in line
+ * with the MTF spec:
+ *
+ * - Redefined attribute bits to match the spec.
+ * - Eliminated unused/undocumented bits.
+ * - Added code to translate bits on tapes that were written wrong.
+ *
+ * Matches MAYN40RD.C 1.59, DBLKS.H 1.15, MAYN40.H 1.34, OTC40RD.C 1.26,
+ * SYPL10RD.C 1.8, BACK_VCB.C 1.17, MAYN31RD.C 1.44, SYPL10.H 1.2
+ *
+ * Rev 1.14 11 Nov 1992 22:49:28 STEVEN
+ * This is Gregg checking files in for Steve. I don't know what he did!
+ *
+ * Rev 1.13 10 Nov 1992 08:12:30 STEVEN
+ * move os path to common part of dblk
+ *
+ * Rev 1.12 20 Oct 1992 15:00:54 STEVEN
+ * added otc stuff for qtc/otc communication
+ *
+ * Rev 1.11 09 Oct 1992 15:57:58 STEVEN
+ * added Daily backup set support
+ *
+ * Rev 1.10 23 Sep 1992 09:31:02 BARRY
+ * Removed remain_size from DBLK.
+ *
+ * Rev 1.9 21 Sep 1992 16:13:40 BARRY
+ * Added FILE_NAME_IN_STREAM attribute definition.
+ *
+ * Rev 1.8 23 Jul 1992 09:05:52 STEVEN
+ * fix warnings
+ *
+ * Rev 1.7 09 Jun 1992 16:59:32 BURT
+ * removed LBA VALID BIT per GH
+ *
+ * Rev 1.6 09 Jun 1992 14:18:40 BURT
+ * Moved some attribute bit defines
+ *
+ *
+ * Rev 1.5 22 May 1992 11:32:42 STEVEN
+ * miss-pell-ed Special
+ *
+ * Rev 1.4 21 May 1992 13:46:32 STEVEN
+ * more long path support
+ *
+ * Rev 1.3 13 May 1992 12:02:14 STEVEN
+ * 40 format changes
+ *
+ * Rev 1.2 05 May 1992 17:20:52 STEVEN
+ * added special bit
+ *
+ * Rev 1.1 12 Mar 1992 15:53:12 STEVEN
+ * 64 bit changes
+ *
+ * Rev 1.0 09 May 1991 13:30:52 HUNTER
+ * Initial revision.
+
+**/
+/* begin include list */
+
+/* $end$ include list */
+#ifndef DBLKS_H
+#define DBLKS_H
+
+/* block types */
+#define UDB_ID ((UINT8)0)
+#define VCB_ID ((UINT8)1)
+#define DDB_ID ((UINT8)8)
+#define FDB_ID ((UINT8)9)
+#define IDB_ID ((UINT8)10)
+#define CFDB_ID ((UINT8)11)
+
+/* SSET (VCB) Attributes */
+
+#define VCB_ARCHIVE_BIT BIT0 /* This is an Transfer set */
+#define VCB_COPY_SET BIT1 /* backup all do not reset modified flag */
+#define VCB_NORMAL_SET BIT2 /* backup all and reset modified flag */
+#define VCB_DIFFERENTIAL_SET BIT3 /* backup modified files and do NOT reset */
+#define VCB_INCREMENTAL_SET BIT4 /* backup modified files and reset modified flag */
+#define VCB_DAILY_SET BIT5 /* backup file modified today */
+#define VCB_OUT_OF_SEQUENCE_BIT BIT6
+#define VCB_IMAGE_BIT BIT7
+
+/* The following three bits are in the vendor specific portion the SSET
+ attribute bit field. They are used internally, and not specified in
+ the MTF document.
+*/
+
+#define VCB_FUTURE_VER_BIT BIT24
+#define VCB_COMPRESSED_BIT BIT25
+#define VCB_ENCRYPTED_BIT BIT26
+
+/* VOLB Attributes (currently only used in the MTF translator) */
+
+#define VOLB_NO_REDIRECT_RESTORE BIT0
+#define VOLB_NON_VOLUME BIT1
+
+/* DIRB (DDB) attribute defines (common to all OS's) */
+
+#define DIR_EMPTY_BIT BIT16
+#define DIR_PATH_IN_STREAM_BIT BIT17
+#define DIR_CORRUPT_BIT BIT18
+
+/* The following bit is in the vendor specific portion the DIRB attribute
+ bit field. It is used internally to indicate that the true type for the
+ DBLK is DBDB (Database DBLK), and is not specified in the MTF document.
+*/
+#define DIR_IS_REALLY_DB BIT24
+
+/* FILE (FDB) attribute defines (common to all OS's) */
+
+#define FILE_IN_USE_BIT BIT16
+#define FILE_NAME_IN_STREAM_BIT BIT17
+#define FILE_CORRUPT_BIT BIT18
+
+/* The following define is used in OUR APP ONLY instead of FILE_CORRUPT_BIT
+ and DIR_CORRUPT_BIT.
+*/
+#define OBJ_CORRUPT_BIT BIT18
+
+/* The following defines are for attribute bits in the "OS Specific"
+ portion of the DBLK attribute field. They are common to NT, SMS, UNIX
+ and Macintosh.
+
+ DO NOT USE THESE FOR DOS OS/2 or non-SMS Novell!!!
+*/
+#define OBJ_READONLY_BIT BIT8
+#define OBJ_HIDDEN_BIT BIT9
+#define OBJ_SYSTEM_BIT BIT10
+#define OBJ_MODIFIED_BIT BIT11
+
+/* DIRB (DDB) attribute bits for DOS */
+
+#define DOS_DIRB_READONLY_BIT BIT8
+#define DOS_DIRB_HIDDEN_BIT BIT9
+#define DOS_DIRB_SYSTEM_BIT BIT10
+#define DOS_DIRB_MODIFIED_BIT BIT11
+
+/* FILE (FDB) attribute bits for DOS */
+
+#define DOS_FILE_READONLY_BIT BIT0
+#define DOS_FILE_HIDDEN_BIT BIT1
+#define DOS_FILE_SYSTEM_BIT BIT2
+#define DOS_FILE_MODIFIED_BIT BIT5
+
+/* DIRB (DDB) attribute bits for OS/2 */
+
+#define OS2_DIRB_READONLY_BIT BIT8
+#define OS2_DIRB_HIDDEN_BIT BIT9
+#define OS2_DIRB_SYSTEM_BIT BIT10
+#define OS2_DIRB_MODIFIED_BIT BIT11
+
+/* FILE (FDB) attribute bits for OS/2 */
+
+#define OS2_FILE_READONLY_BIT BIT0
+#define OS2_FILE_HIDDEN_BIT BIT1
+#define OS2_FILE_SYSTEM_BIT BIT2
+#define OS2_FILE_MODIFIED_BIT BIT5
+
+/* DIRB (DDB) attribute bits for non-SMS Novell */
+
+#define NOV_DIRB_READ_ACCESS_BIT BIT0
+#define NOV_DIRB_WRITE_ACCESS_BIT BIT1
+#define NOV_DIRB_OPEN_FILE_RIGHTS_BIT BIT2
+#define NOV_DIRB_CREATE_FILE_RIGHTS_BIT BIT3
+#define NOV_DIRB_DELETE_FILE_RIGHTS_BIT BIT4
+#define NOV_DIRB_PARENTAL_RIGHTS_BIT BIT5
+#define NOV_DIRB_SEARCH_RIGHTS_BIT BIT6
+#define NOV_DIRB_MOD_FILE_ATTRIBS_BIT BIT7
+#define NOV_DIRB_READONLY_BIT BIT8
+#define NOV_DIRB_HIDEN_BIT BIT9
+#define NOV_DIRB_SYSTEM_BIT BIT10
+#define NOV_DIRB_MODIFIED_BIT BIT11
+
+/* FILE (FDB) attribute bits for non-SMS Novell */
+
+#define NOV_FILE_READONLY_BIT BIT0
+#define NOV_FILE_HIDDEN_BIT BIT1
+#define NOV_FILE_SYSTEM_BIT BIT2
+#define NOV_FILE_EXECUTE_ONLY_BIT BIT3
+#define NOV_FILE_MODIFIED_BIT BIT5
+#define NOV_FILE_SHAREABLE_BIT BIT7
+#define NOV_FILE_TRANSACTIONAL_BIT BIT12
+#define NOV_FILE_INDEXING_BIT BIT13
+
+/* CFIL (CFDB) attribute defines (common to all OS's) */
+
+#define CFDB_LENGTH_CHANGE_BIT BIT16
+#define CFDB_UNREADABLE_BLK_BIT BIT17
+#define CFDB_DEADLOCK_BIT BIT18
+
+
+typedef struct FS_NAME_Q_ELEM *FS_NAME_Q_ELEM_PTR ;
+typedef struct FS_NAME_Q_ELEM {
+ Q_ELEM q ; /* queue element structure for q-ing */
+ UINT16 alloc_size ; /* size of allocated buf -> to by path */
+ CHAR_PTR name ; /* allocated buffer and FS_Path */
+ INT16 name_size; /* length of of FS_Path in bytes */
+} FS_NAME_Q_ELEM ;
+
+typedef struct COMMON_DBLK_DATA {
+ UINT32 blkid ;
+ BOOLEAN continue_obj ;
+ BOOLEAN compressed_obj ;
+ VOID_PTR stream_ptr ; /* pointer to path stream read in */
+ UINT16 stream_offset ; /* current pointer into stream */
+ UINT16 tape_seq_num ;
+ UINT16 string_type ;
+ FS_NAME_Q_ELEM_PTR os_name ;
+ union {
+ UINT32 did ;
+ UINT32 f_mark ;
+ } f_d;
+ struct {
+ UINT32 pba ;
+ UINT32 lba ;
+ }ba;
+ UINT8 os_id ;
+ UINT8 os_ver ;
+ /* SMS is the only FS using this now */
+ UINT32 name_space; /* current name space */
+}COM_DBLK ;
+
+
+/* Note that the number of elements in the data array used to be hard coded
+ to make the structure size exactly 1024. With various compilers doing
+ different structure packing this is no longer possible, and we can't
+ make this a packed structure since a) this would cause alignment faults
+ on some machines and b) we rely on the first two elements in this
+ structure matching up with the first two elements in other structures!!!
+ As a result, I've changed the array size to a flat 1024 to avoid
+ any confusion that there is a known size for this structure. Any
+ allocation of a structure of this type or of a data space to hold this
+ structure should use "sizeof" to allocate the memory.
+*/
+typedef struct DBLK *DBLK_PTR;
+typedef struct DBLK {
+ UINT8 blk_type ;
+ COM_DBLK com ;
+ UINT8 data[1024] ;
+} DBLK;
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/dddefs.h b/private/utils/ntbackup/inc/dddefs.h
new file mode 100644
index 000000000..d30ead37d
--- /dev/null
+++ b/private/utils/ntbackup/inc/dddefs.h
@@ -0,0 +1,50 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: dddefs.h
+
+ Description: Contains defines for parameters to Tp calls
+
+ $Log: T:/LOGFILES/DDDEFS.H_V $
+ *
+ * Rev 1.4 17 May 1993 19:05:42 GREGG
+ * Cleaned up the file, and added parameter defines for new function TpSpace.
+
+**/
+#ifndef _DD_DEFINES
+#define _DD_DEFINES
+
+/* For TpReadEndSet and TpSpace */
+
+// Note: The first three defines are for backward compatability with
+// TpReadEndSet. Calls to TpSpace should use the new 'SPACE_'
+// defines! TpSpace will eventually replace TpReadEndSet.
+
+#define FORWARD 0
+#define BACKWARD 1
+#define TO_EOD 2
+
+#define SPACE_FWD_FMK 0
+#define SPACE_BKWD_FMK 1
+#define SPACE_EOD 2
+#define SPACE_FWD_BLK 3
+#define SPACE_BKWD_BLK 4
+
+
+/* For TpErase */
+
+#define ERASE_TYPE_SECURITY 0
+#define ERASE_TYPE_FORMAT 1
+
+
+/* For TpSpecial: SS_CHANGE_BLOCK_SIZE */
+
+#define DEFAULT_BLOCK_SIZE 0xffffffff
+
+
+/* For TpSpecial: SS_SET_DRV_COMPRESSION */
+
+#define ENABLE_DRV_COMPRESSION 0
+#define DISABLE_DRV_COMPRESSION 1
+
+#endif
diff --git a/private/utils/ntbackup/inc/debug.h b/private/utils/ntbackup/inc/debug.h
new file mode 100644
index 000000000..1c23f0168
--- /dev/null
+++ b/private/utils/ntbackup/inc/debug.h
@@ -0,0 +1,90 @@
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: debug.h
+
+ Description: This file contains the structures, definitions, macros,
+ and function prototypes for the Maynstream GUI
+ Debug Manager (DBM).
+
+ $Log: G:/UI/LOGFILES/DEBUG.H_V $
+
+ Rev 1.6 14 Oct 1992 15:51:16 GLENN
+Added /ZL debug logging command line support.
+
+ Rev 1.5 04 Oct 1992 19:46:32 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.4 30 Sep 1992 10:47:04 DAVEV
+Unicode strlen verification, MikeP's chgs from MS
+
+ Rev 1.3 20 Mar 1992 14:41:26 GLENN
+Updated.
+
+ Rev 1.2 19 Mar 1992 16:32:20 MIKEP
+more lines
+
+ Rev 1.1 19 Mar 1992 09:30:48 MIKEP
+debug to file
+
+ Rev 1.0 20 Nov 1991 19:35:32 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+
+#ifndef _debug_h_
+#define _debug_h_
+
+#define DEBUG_TEMPORARY 0x0000
+#define DEBUG_USER_INTERFACE 0x0001
+#define DEBUG_LOOPS 0x0002
+#define DEBUG_FILE_SYSTEM 0x0004
+#define DEBUG_CATALOGS 0x0008
+#define DEBUG_REMOTE_DRIVE 0x0010
+#define DEBUG_TAPE_FORMAT 0x0020
+#define DEBUG_DEVICE_DRIVER 0x0040
+#define DEBUG_TEMP_WIN_END 0x8000
+
+/* the above defines are copied in the Bengine BE_debug.h" header file */
+/* if you make a change duplicate in the other file */
+
+VOID zprintf( UINT16, ... ) ;
+VOID zvprintf( UINT16, va_list );
+
+// DEFINITIONS
+
+#define DBM_LINELENGTH 80
+#define DBM_MIN_LINES 10
+#define DBM_NUM_LINES 50
+#define DBM_MAX_LINES 250
+
+#define DBM_WINDOW 1
+#define DBM_FILE 2
+
+
+// DATA STRUCTURES
+
+typedef struct {
+
+ UCHAR szMsg[ DBM_LINELENGTH ];
+ BYTE bTag;
+ Q_ELEM pQElem;
+
+} DS_DEBUGITEM, DEBUGITEM, *PDS_DEBUGITEM, *DEBUGITEM_PTR;
+
+
+// FUCTION PROTOTYPES
+
+BOOL DBM_Init( VOID );
+BOOL DBM_Deinit( VOID );
+BOOL DBM_InsertItem( CHAR_PTR );
+BOOL DBM_Reset( WORD );
+BOOL DBM_SetDebugToFile ( BOOL );
+INT DBM_GetMsgCount( WORD );
+BOOL DBM_SetMsgCount( WORD, INT );
+
+#include "eng_dbug.h"
+
+#endif
diff --git a/private/utils/ntbackup/inc/del_sel.h b/private/utils/ntbackup/inc/del_sel.h
new file mode 100644
index 000000000..9ec70b52b
--- /dev/null
+++ b/private/utils/ntbackup/inc/del_sel.h
@@ -0,0 +1,9 @@
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_SELECTDELETE 6
+#else
+#include "dlg_ids.h"
+#endif
+
+#define IDD_DS_LIST 0x0065
diff --git a/private/utils/ntbackup/inc/details.h b/private/utils/ntbackup/inc/details.h
new file mode 100644
index 000000000..53d0e36b0
--- /dev/null
+++ b/private/utils/ntbackup/inc/details.h
@@ -0,0 +1,173 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: details.h
+
+ Description: This file contains header information for the details.c module.
+
+
+ $Log: J:\ui\logfiles\details.h_v $
+
+ Rev 1.12 07 Feb 1994 02:06:26 GREGG
+Fixed and expanded 'extended error reporting'.
+
+ Rev 1.11 15 Sep 1993 13:48:32 CARLS
+added prototype for UI_BuildFullPathFromDDB2
+
+ Rev 1.10 16 Mar 1993 16:47:46 BARRY
+Enlarged UI_MAX_FILE_DISPLAY.
+
+ Rev 1.9 01 Nov 1992 16:30:12 DAVEV
+Unicode changes
+
+ Rev 1.8 04 Oct 1992 19:46:36 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.7 27 Jul 1992 14:53:10 JOHNWT
+ChuckB fixed references for NT.
+
+ Rev 1.6 11 May 1992 19:44:42 STEVEN
+64bit and large path sizes
+
+ Rev 1.5 14 Feb 1992 09:29:24 MIKEP
+enlarge fields for os/2
+
+ Rev 1.4 10 Feb 1992 10:39:22 CHUCKB
+Moved prototype for BuildNumeralWithCommas from details.h to muiutil.h.
+
+ Rev 1.3 31 Jan 1992 13:01:58 GLENN
+Put UI_ReportDiagError() in hwcheck.h.
+
+ Rev 1.2 08 Jan 1992 10:41:10 CARLS
+Added define DETAIL_PRINT_ERROR_DEVIVE
+
+ Rev 1.1 23 Dec 1991 16:31:20 DAVEV
+Removed UI_DotDotDot & related routines
+
+ Rev 1.0 20 Nov 1991 19:39:42 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+/* $end$ include list */
+
+#ifndef _details_h_
+#define _details_h_
+
+#include "fsys.h"
+#include "tpos.h"
+#include "stats.h"
+
+
+
+/* Initialization defined types for call to UI_UnitsInit */
+#define INIT_ALL -1
+#define INIT_FSYS_BSDU ((INT16)BIT0)
+#define INIT_TFL ((INT16)BIT1)
+#define REINIT_TFL ((INT16)BIT2)
+
+/* Tape Format Initialization error help sessions */
+#define DRIVER_LOAD_FAILURE 6800
+#define REMOTE_INIT_FAILURE 6810
+#define BENGINE_IN_USE 6820
+#define UI_NO_CONTROLLERS 6830
+
+INT16 UI_UnitsInit( BE_INIT_STR_PTR, INT16 ) ;
+VOID UI_UnitsDeInit( VOID ) ;
+
+INT16 UI_TmenuUnitsInit( VOID ) ;
+VOID DefineChannel( BE_INIT_STR_PTR ) ;
+VOID open_tp_win( VOID ) ;
+VOID close_tp_win( VOID ) ;
+
+typedef enum {
+
+ UI_START,
+ UI_END
+
+} UI_TYPE ;
+
+/* display related constants */
+
+#define UI_MAX_DETAIL_LENGTH ( 256 )
+
+#define UI_MAX_TAPENAME_LENGTH ( 80 )
+#define UI_MAX_VOLUME_LENGTH ( 256 )
+#define UI_MAX_LABEL_LENGTH ( 256 )
+
+#define UI_MAX_PATH_LENGTH ( 1024 )
+#define UI_MAX_FILENAME_LENGTH ( 255 )
+
+#define UI_MAX_ATTRIBS_LENGTH ( 15 )
+#define UI_ATTRIBS_PADDING ( 12 )
+#define UI_MAX_NUMERAL_LENGTH ( 26 )
+#define UI_COMMA_SPACING ( 3 )
+#define UI_DOT_COUNT ( 5 )
+#define UI_DOT_TIME ( 9L )
+#define UI_SEARCHING_TIME ( 90L )
+#define UI_SEARCH_MSG_LENGTH ( 50 )
+#define UI_MAX_WIDE_FILE_DISPLAY ( 12 )
+#define UI_MAX_FILE_DISPLAY ( 24 )
+#define UI_TRUNCATION TEXT("...")
+
+/* Define error types for handling loops related errors */
+#define DETAIL_PRINT_ERR_ONLY 0
+#define DETAIL_PRINT_VALUE 1
+#define DETAIL_PRINT_DEVICE 2
+#define DETAIL_PRINT_ERROR_DEVICE 3
+
+extern BOOLEAN lw_search_first_time ;
+
+/* Function prototypes for common USER INTERFACE utilities */
+
+VOID UI_SetResources( VOID ) ;
+CHAR UI_AmOrPm( INT ) ;
+VOID UI_BuildFileDetail( CHAR_PTR, FSYS_HAND, DBLK_PTR, BOOLEAN ) ;
+VOID UI_BuildFileSelectLine( CHAR_PTR buffer, CHAR_PTR name, INT16 name_len, BOOLEAN dir, UINT32 attr, OBJECT_TYPE obj_type, UINT64 size, DATE_TIME *date ) ;
+VOID UI_BuildFileAttribs( CHAR_PTR buffer, UINT32 attrib, OBJECT_TYPE obj_type ) ;
+VOID UI_BuildDirAttribs( CHAR_PTR buffer, UINT32 attrib, OBJECT_TYPE obj_type ) ;
+CHAR_PTR UI_AllocPathBuffer( CHAR_PTR *buffer, UINT16 leng );
+VOID UI_FreePathBuffer( CHAR_PTR *buffer ) ;
+VOID UI_BuildDelimitedPathFromDDB( CHAR_PTR *buffer, FSYS_HAND fsh, DBLK_PTR ddb_dblk_ptr, CHAR delim, BOOLEAN OS_flag ) ;
+VOID UI_BuildFullPathFromDDB( CHAR_PTR *buffer, FSYS_HAND fsh, DBLK_PTR ddb_dblk_ptr, CHAR delim, BOOLEAN OS_flag ) ;
+VOID UI_BuildFullPathFromDDB2( CHAR_PTR *buffer, FSYS_HAND fsh, DBLK_PTR ddb_dblk_ptr, CHAR delim, BOOLEAN OS_flag ) ;
+VOID UI_BuildNumeralWithCommas( CHAR_PTR numeral ) ;
+VOID UI_BytesProcessed( STATS_PTR op_stats_ptr ) ;
+VOID UI_RateProcessed( STATS_PTR op_stats_ptr ) ;
+VOID UI_Time( STATS_PTR op_stats_ptr, INT res_id, UI_TYPE type ) ;
+VOID UI_AppendDelimiter( CHAR_PTR buffer, CHAR delim ) ;
+VOID UI_ClearLastDisplayedFile( VOID ) ;
+VOID UI_ConditionAtEnd( VOID ) ;
+VOID UI_DisplayBreakMsg( VOID ) ;
+VOID UI_ProcessErrorCode( INT16 error, INT16_PTR disposition, INT16 channel ) ;
+INT8 UI_TapeDriveCount( VOID ) ;
+VOID UI_FixPath( CHAR_PTR path_ptr, INT16 length, CHAR delim ) ;
+VOID UI_TruncateString( CHAR_PTR buffer, INT16 length, BOOLEAN replace_spaces ) ;
+BOOLEAN UI_CheckWriteProtectedDevice( UINT16 tf_message, TPOS_PTR tpos, CHAR_PTR drive_name ) ;
+CHAR_PTR UI_DisplayableTapeName( CHAR_PTR tape_name, DATE_TIME_PTR date ) ;
+VOID UI_DisplayFile( CHAR_PTR filename ) ;
+INT16 UI_MaxDirectoryLength( VOID ) ;
+INT16 UI_AttachDrive( FSYS_HAND *, GENERIC_DLE_PTR, BOOLEAN );
+CHAR_PTR UI_GetDLEDescription( GENERIC_DLE_PTR dle_ptr );
+BOOLEAN UI_GetExtendedErrorString( INT16 error, CHAR_PTR msg ) ;
+
+
+UINT16 UI_GetVCB_TPos(
+ UINT16 message,
+ TPOS_PTR tpos_ptr,
+ BOOLEAN valid_vcb_flag,
+ DBLK_PTR vcb_ptr,
+ UINT16 mode ) ;
+
+
+
+#ifdef MAYN_OS2
+VOID UI_GetTickCount( UINT32 *tick_count_ptr ) ;
+#endif
+
+
+#define MacintoshVCB( v ) ( strcmp( TEXT("MACF"), FS_ViewShortMachNameInVCB( (v) ) ) == 0 )
+
+
+#endif
diff --git a/private/utils/ntbackup/inc/detdrive.h b/private/utils/ntbackup/inc/detdrive.h
new file mode 100644
index 000000000..74eb5be30
--- /dev/null
+++ b/private/utils/ntbackup/inc/detdrive.h
@@ -0,0 +1,34 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: detdrive.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains function prototype for DetermineDriver.
+
+ Location: BE_PUBLIC
+
+
+ $log$
+
+**/
+/* $end$ include list */
+
+#ifndef DETDRIVERFUNC
+#define DETDRIVERFUNC
+
+typedef
+ struct {
+ CHAR driver_name[9] ;
+ INT16 driver_type ;
+ } DET_DRIVER, *DET_DRIVER_PTR ;
+
+BOOLEAN DetermineDriver( DET_DRIVER_PTR, INT16 ) ;
+
+#endif
+
+
+
+
diff --git a/private/utils/ntbackup/inc/detnet.h b/private/utils/ntbackup/inc/detnet.h
new file mode 100644
index 000000000..fa295bf05
--- /dev/null
+++ b/private/utils/ntbackup/inc/detnet.h
@@ -0,0 +1,32 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: detnet.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains prototypes for determining the
+ network.
+
+
+ $Log: N:/LOGFILES/DETNET.H_V $
+ *
+ * Rev 1.1 25 Jun 1991 10:50:58 BARRY
+ * Update prototypes to reflect new config.
+ *
+ * Rev 1.0 09 May 1991 13:30:44 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#define NOVELL_ADVANCED 1
+#define NOVELL_4_6 2
+#define IBM_PC_NET 3
+
+INT16 IdentifyNet( CHAR drive, struct BE_CFG *cfg, UINT16 *version ) ;
+
+INT16 CheckNovell( CHAR drive_num, UINT16 *version ) ;
+
+INT16 CheckIBM_PC_Net( VOID ) ;
diff --git a/private/utils/ntbackup/inc/dialmang.h b/private/utils/ntbackup/inc/dialmang.h
new file mode 100644
index 000000000..d9f737c86
--- /dev/null
+++ b/private/utils/ntbackup/inc/dialmang.h
@@ -0,0 +1,481 @@
+/****************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+ Name: DIALMANG.H
+
+ Description: This header file contains prototypes for the
+ dialog manager. This include file is used
+ by most dialogs and JOB and SCHEDULE related
+ operations.
+
+ $Log: G:\UI\LOGFILES\DIALMANG.H_V $
+
+ Rev 1.47.2.0 02 Feb 1994 11:32:42 Glenn
+Added log file browse ID and PROTOTYPE.
+
+ Rev 1.47 30 Jul 1993 15:58:02 CHUCKB
+Added prototype for DM_WaitForDevice.
+
+ Rev 1.46 14 Jul 1993 09:22:22 CARLS
+added prototypes for skipno dialog functions
+
+ Rev 1.45 13 Jul 1993 17:23:48 MARINA
+correct struct DIALOG_TABLE
+
+ Rev 1.44 22 Jun 1993 15:33:44 GLENN
+change type of handle in prototype.
+
+ Rev 1.43 09 Jun 1993 15:07:16 MIKEP
+enable c++
+
+
+ Rev 1.42 25 May 1993 14:23:36 chrish
+Prototype for DM_Abort backup/restore abort dialog window procedure.
+
+ Rev 1.41 14 May 1993 15:26:02 CARLS
+changed DM_StartSkipOpen prototype
+
+ Rev 1.40 27 Apr 1993 18:05:32 KEVINS
+Enhanced DS_SEARCH structure to include password, subdirectories, and max number of hits.
+
+ Rev 1.39 12 Mar 1993 08:41:08 CARLS
+added prototype for DM_StartFormat
+
+ Rev 1.38 10 Mar 1993 17:23:02 chrish
+Changed prototype for function DM_GetTapePswd to add another parameter
+being passed.
+
+ Rev 1.37 01 Nov 1992 16:30:26 DAVEV
+Unicode changes
+
+ Rev 1.36 07 Oct 1992 15:36:04 MIKEP
+fix nt warnings
+
+ Rev 1.35 04 Oct 1992 19:46:40 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.34 21 Sep 1992 16:51:40 DARRYLP
+Updates for WFW email.
+
+ Rev 1.33 17 Sep 1992 18:03:58 DARRYLP
+New dialog and controls for WFW email.
+
+ Rev 1.32 08 Sep 1992 13:46:10 CHUCKB
+*proc has to be in parentheses.
+
+ Rev 1.31 04 Sep 1992 18:10:34 CHUCKB
+Fixed NT warning in dialog table structure (can't just use FARPROC).
+
+ Rev 1.30 12 Aug 1992 18:24:28 STEVEN
+fix warning
+
+ Rev 1.29 28 Jul 1992 15:08:24 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.28 26 Jun 1992 15:56:36 DAVEV
+
+
+ Rev 1.27 11 Jun 1992 11:00:24 GLENN
+Removed MEMORYTRACE references.
+
+ Rev 1.26 14 May 1992 16:43:06 MIKEP
+nt pass 2
+
+ Rev 1.25 12 May 1992 21:22:56 MIKEP
+NT pass 1
+
+ Rev 1.24 07 Apr 1992 10:57:02 CHUCKB
+Moved DM_DisplayModesMatch prototype.
+
+ Rev 1.23 06 Apr 1992 10:52:06 DAVEV
+Added defines for new d_browse.c module
+
+ Rev 1.22 20 Mar 1992 14:26:50 DAVEV
+temporarly remove conditional inclusion of omhelpid.h instead of helpids.h for OEM_MSOFT
+
+ Rev 1.21 16 Mar 1992 17:04:50 DAVEV
+deleted special omdialog.h version of dialogs.h
+
+ Rev 1.20 12 Mar 1992 11:18:40 DAVEV
+include omdialog.h instead of dialogs.h for Nostradamus (does not affect Winter Park)
+
+ Rev 1.19 03 Mar 1992 17:24:20 GLENN
+Removed bogus IDS_MAXDIALOGNUMS and associated references in dialmang and d_erase.
+
+ Rev 1.18 26 Feb 1992 11:58:16 DAVEV
+Include OMHELPID.H instead of HELPIDS.H if OEM_MSOFT defined
+
+ Rev 1.17 25 Feb 1992 11:37:36 JOHNWT
+removed unneeded defines
+
+ Rev 1.16 31 Jan 1992 13:43:14 JOHNWT
+changed DM_CenterDialog proto
+
+ Rev 1.15 27 Jan 1992 00:39:38 CHUCKB
+Updated dialog id's.
+
+ Rev 1.14 24 Jan 1992 14:01:12 CHUCKB
+Put more dialogs on net.
+
+ Rev 1.13 18 Jan 1992 11:18:26 CARLS
+added DM_CenterDialog prototype
+
+ Rev 1.12 13 Jan 1992 16:49:40 CHUCKB
+Took out defines for job and schedule database file names.
+
+ Rev 1.11 09 Jan 1992 18:25:54 DAVEV
+16/32 bit port 2nd pass
+
+ Rev 1.10 06 Jan 1992 11:01:46 CHUCKB
+Added include for helpids.h.
+
+ Rev 1.9 23 Dec 1991 15:47:48 GLENN
+Added Settings Options stuff
+
+ Rev 1.8 14 Dec 1991 11:15:42 CARLS
+changes for cattape.dlg
+
+ Rev 1.7 10 Dec 1991 15:41:32 CHUCKB
+Increased max dialog num.
+
+ Rev 1.6 10 Dec 1991 13:35:22 CHUCKB
+Added prototype for advanced restore.
+
+ Rev 1.5 10 Dec 1991 09:51:26 CHUCKB
+No change.
+
+ Rev 1.4 07 Dec 1991 11:51:58 CARLS
+changed prototype for DM_CatTape
+
+ Rev 1.3 06 Dec 1991 15:53:04 JOHNWT
+added DM_NextSet
+
+ Rev 1.2 04 Dec 1991 16:32:42 DAVEV
+16/32 bit Windows port changes-1st pass
+
+ Rev 1.1 02 Dec 1991 14:15:20 CHUCKB
+Changed return type of DM_DaysInMonth to INT.
+
+ Rev 1.0 20 Nov 1991 19:34:20 SYSTEM
+Initial revision.
+
+****************************************************************************/
+
+#ifndef DIALMANG_H
+
+#define DIALMANG_H
+
+typedef struct tm * TIME_PTR;
+
+#include "dlg_ids.h"
+#include "datetime.h"
+
+#if defined ( OEM_MSOFT ) // Include OEM Microsoft product specific headers
+
+# include "omhelpid.h"
+
+#else // Include standard Maynstream product headers
+
+# include "helpids.h"
+
+#endif
+
+#include "dialogs.h"
+
+
+// Defines for the Dialog Manager's table of dialog callback procedures.
+
+#define MODAL 0
+#define MODELESS 1
+
+// defines for DM_ShowDialog return codes
+
+#define DM_SHOWNOTFOUND -1
+#define DM_SHOWCANCEL 0
+#define DM_SHOWOK 1
+
+
+#define DM_CATCANCEL 1
+#define DM_CATPARTIAL 2
+#define DM_CATSKIP 2
+#define DM_CATREREAD 2
+#define DM_CATREMOVE 3
+#define DM_CATPROCEED 4
+
+
+/* Defines for Database Information and Sizes */
+
+#define MAX_PATH_LEN 256
+#define MAX_NUM_SCHEDS 40
+
+/* Defines used when accessing the JOB and SCHEDULE files */
+
+#define FOPEN_ERR -1 // Also defined in jobs.h
+#define FREAD_ERR -2 // and schedule.h
+#define FWRITE_ERR -3
+#define FCLOSE_ERR -4
+
+#define JOBIO 1 // IO error types
+#define SCHEDULEIO (JOBIO+1) // for DialogOnError
+
+
+/* Defines for Timers */
+#define ID_TIMER 1
+
+/* Defines and Macros for Time Functions */
+#define MAX_TIMEBUF_LEN 80
+#define YEAR( x ) ( ( x )->tm_year )
+#define MONTH( x ) ( ( x )->tm_mon + 1 )
+#define MDAY( x ) ( ( x )->tm_mday )
+#define WDAY( x ) ( ( x )->tm_wday )
+#define HOUR( x ) ( ( x )->tm_hour )
+#define MIN( x ) ( ( x )->tm_min )
+#define SEC( x ) ( ( x )->tm_sec )
+
+/* Defines and Macros for CDS functions and Operations */
+#define SELECTION_EXTENSION TEXT("*.BKS")
+
+/* Defines for operation list, tape, job, and schedule functions */
+#define BACKUP 0
+#define ERASE 1
+#define RESTORE 2 // TENSION is defined as 5 in script.h
+#define TRANSFER 4
+#define VERIFY 3
+#define APPEND 6
+#define OVERWRITE 7
+
+// defines for short date formats
+
+#define MDY 1
+#define DMY 2
+#define YMD 3
+
+typedef struct DIALOG_TABLE *DIALOG_TABLE_PTR;
+typedef struct DIALOG_TABLE {
+
+ FARPROC proc;
+ WORD proc_num;
+ BOOL type;
+
+} DIALOG_TABLE;
+
+
+// EXTERNAL DECLARATIONS
+
+extern DIALOG_TABLE DialogCallBackTable[];
+
+
+// Defines for structures used by some dialogs.
+
+typedef struct DS_LOGIN *DS_LOGIN_PTR;
+typedef struct DS_LOGIN {
+
+ LPSTR Server_Name;
+ LPSTR User_Name;
+ INT User_Name_Len;
+ LPSTR Password;
+ INT Password_Len;
+ BOOL Ok;
+
+} DS_LOGIN ;
+
+// Defines for complex info for advanced selections (selection criteria)
+
+#define ADV_ALL 0
+#define ADV_MOD 1
+#define ADV_ACCESS 2
+#define ADV_DATES 3
+
+typedef struct DS_ADVANCED *DS_ADVANCED_PTR;
+typedef struct DS_ADVANCED {
+
+ BOOL Include; // is this an include or exclude
+ VOID_PTR vlm; // the vlm for this selection; NULL for restore
+ CHAR Path[255]; // path to select
+ CHAR File[255]; // file spec for the path
+ BOOL Subdirs; // include subdirectories or not
+ DATE_TIME BeforeDate; // to date; only select files hit before this date
+ DATE_TIME AfterDate; // from date
+ INT criteria; // all files, only modified files, LAD, or date range
+ DATE_TIME LastAccessDate; // files not accessed in this many days
+ UINT32 tape_fid; // family id of a tape to be restored from
+ INT bset_num; // backup set to be restored from; -1 for all
+
+} DS_ADVANCED;
+
+typedef struct DS_RESTORE *DS_RESTORE_PTR;
+typedef struct DS_RESTORE {
+
+ LPSTR lpszBackupSetName;
+ VOID_PTR vlpServerList;
+ VOID_PTR vlpDriveList;
+ VOID_PTR dle;
+
+} DS_RESTORE;
+
+typedef struct DS_SEARCH *DS_SEARCH_PTR;
+typedef struct DS_SEARCH {
+
+ UINT32 Tape;
+ CHAR Path[255];
+ CHAR File[255];
+ UINT16 MaxSrchResults;
+ BOOL SrchPasswProtTapes;
+ BOOL SrchSubdirs;
+
+} DS_SEARCH;
+
+
+
+typedef struct STATUSDATA
+ {
+ WORD wCode;
+ CHAR achMsg[80];
+ } STATUSDATA;
+
+/* attribute flags for DlgDirList */
+
+#define ATTR_DIRS 0xC010 /* find drives and directories */
+#define ATTR_FILES 0x0000 /* find ordinary files */
+#define PROP_FILENAME szPropertyName /* name of property for dialog */
+
+// flag to indicate a config change for the current operation only
+
+#define TEMPCHANGE (LONG)1
+
+ //defines for DM_GetBrowsePath (see d_browse.c)
+# define BROWSE_MAXPATH 1024
+# define BROWSE_MAXDRIVE 3 //drive name: 'X:' X is drive letter
+
+//
+// dialog proc prototypes
+//
+
+DLGRESULT APIENTRY DM_Abort (HWND, MSGID, MP1, MP2); // chs:05-25-93
+DLGRESULT APIENTRY DM_AboutWinter (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_AdvBackup (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_AdvSave (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_AdvUse (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_AdvRestore (HWND, MSGID, MP1, MP2);
+
+// attach to another server
+
+DLGRESULT APIENTRY DM_Attach (HWND, MSGID, MP1, MP2);
+
+// operations
+
+DLGRESULT APIENTRY DM_BackupTargetMin (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_EraseTape (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_TensionTarget (HWND, MSGID, MP1, MP2);
+
+DLGRESULT APIENTRY DM_PromptLabel (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_SearchTape (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_TapePswd (HWND, MSGID, MP1, MP2);
+
+DLGRESULT APIENTRY DM_RestoreTarget (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_VerifyTarget (HWND, MSGID, MP1, MP2);
+
+DLGRESULT APIENTRY DM_CatalogMaint (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_CatalogTape (HWND, MSGID, MP1, MP2);
+
+DLGRESULT APIENTRY DM_DeleteSelection (HWND, MSGID, MP1, MP2);
+
+DLGRESULT APIENTRY DM_BackupSet (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_RestoreSet (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_Runtime (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_Tension (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_ReenterPassword (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_SkipOpen (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_FileReplace (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_Erase (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_NextSet (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_SkipNo (HWND, MSGID, MP1, MP2);
+
+#if defined ( OEM_EMS )
+DLGRESULT APIENTRY DM_ExchgConnect (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_ExchgRecover (HWND, MSGID, MP1, MP2);
+#endif
+
+// settings
+
+DLGRESULT APIENTRY DM_OptionHardware (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_OptionRestore (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_HardwareConfig (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_OptionsBackup (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_OptionRestore (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_OptionsCatalog (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_OptionsLogging (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_OptionsNetwork (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_OptionsTransfer (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_SettingsOptions (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_SettingsDebug (HWND, MSGID, MP1, MP2);
+
+// jobs/scheduler
+
+DLGRESULT APIENTRY DM_New (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_JobOpt (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_Jobs (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_Schedule (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_SchedOpt (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_ProgManItem (HWND, MSGID, MP1, MP2);
+
+// email/windows for workgroups
+
+DLGRESULT APIENTRY DM_Email (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_EmailLogon (HWND, MSGID, MP1, MP2);
+
+// other function prototypes
+
+DLGRESULT APIENTRY DM_PWDBPassword (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY DM_WaitForDevice (HWND, MSGID, MP1, MP2);
+
+INT APIENTRY DM_BeginDialogProcess ( HWND, HANDLE, WORD, PVOID, PVOID );
+VOID DM_MakeHelpPathName ( LPSTR );
+FARPROC DM_SelectProcInstance ( HANDLE );
+PVOID DM_GetRestoreDestination ( LPSTR, VOID_PTR, PVOID );
+PVOID DM_GetVerifyDestination ( LPSTR, VOID_PTR, PVOID );
+BOOL DM_IsLeapYear ( INT );
+INT DM_DialogOnError ( INT nError, WORD wType );
+BOOL DM_IsDateValid ( INT, INT, INT, INT, INT, INT );
+VOID DM_CenterDialog ( HWND );
+
+VOID DM_DisplayModesMatch ( VOID );
+
+BOOL APIENTRY DM_IsInDlgTable ( HWND, WORD );
+INT APIENTRY DM_ShowDialog ( HWND, WORD, PVOID );
+VOID APIENTRY DM_InitDialogs ( VOID );
+
+INT DM_CatMaint ( UINT32 * );
+INT DM_CatBset ( LPSTR );
+INT DM_CatTape ( INT * );
+BOOL DM_GetTapePswd ( LPSTR, LPSTR, LPSTR, LPSTR, INT16 ); // chs:03-10-93
+
+VOID GetTimeDateString ( TIME_PTR, LPSTR, INT );
+VOID GetTimeDateStruct ( TIME_PTR );
+
+DS_SEARCH_PTR DM_GetSearchItem ( VOID );
+INT DM_DaysInMonth ( INT, INT );
+
+BOOL DM_ProceedWithErase ( VOID );
+INT DM_CountLetters ( CHAR string[], INT index );
+VOID DM_ParseShortDate ( VOID );
+VOID DM_ParseTime ( VOID );
+
+INT DM_StartSkipOpen ( CHK_OPEN TryOpen, UINT32 parm ) ;
+INT DM_StartSkipNo ( VOID );
+INT DM_StartErase ( VOID );
+INT DM_StartFormat ( VOID );
+INT DM_StartVerifyBackupSet ( VOID );
+INT DM_StartRestoreBackupSet ( VOID );
+VOID DM_StartNextSet ( VOID );
+
+BOOL DM_AttachToServer ( LPSTR, LPSTR, INT, LPSTR, INT ); // I - length of password
+
+// Prototype for displaying a 'Browse to Path' dialog based on the
+// common dialog: GetSaveFileName (see commdlg.h)
+// Use CommDlgExtendedError() to determine error condition on FALSE return
+
+BOOL DM_GetBrowsePath ( HWND, HINSTANCE, LPSTR, UINT );
+BOOL DM_BrowseForLogFilePath ( HWND, HINSTANCE, LPSTR, UINT );
+
+#endif
diff --git a/private/utils/ntbackup/inc/dialogs.h b/private/utils/ntbackup/inc/dialogs.h
new file mode 100644
index 000000000..feb8ee5f0
--- /dev/null
+++ b/private/utils/ntbackup/inc/dialogs.h
@@ -0,0 +1,363 @@
+
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: dialogs.h
+
+ Description: Contains dialog control id's for most of the dialogs
+ in MaynStream for Windows ( a.k.a. Winter Park ).
+
+ $Log: G:\UI\LOGFILES\DIALOGS.H_V $
+
+ Rev 1.43.2.0 02 Feb 1994 11:32:36 Glenn
+Added log file browse ID and PROTOTYPE.
+
+ Rev 1.43 05 Aug 1993 20:41:26 CHUCKB
+Fixed define for IDD_WAITDEV_TEXT.
+
+ Rev 1.42 03 Aug 1993 21:02:10 TIMN
+Added hardware dialog id
+
+ Rev 1.41 30 Jul 1993 14:55:12 CHUCKB
+Added an id for the wait-for-drive dialog.
+
+ Rev 1.40 14 Jul 1993 09:21:42 CARLS
+added IDs for skipno dialog
+
+ Rev 1.39 29 Jun 1993 20:09:02 BARRY
+Nostradamus doesn't use abortdlg.h
+
+ Rev 1.38 29 Jun 1993 17:35:06 GLENN
+Added new style about box support.
+
+ Rev 1.37 25 May 1993 14:22:56 chrish
+Added include for new backup/restore dialog box "abortdlg.h".
+
+ Rev 1.36 15 Apr 1993 13:32:14 CLIFF
+Added stuff for the dummy device driver.
+
+ Rev 1.35 18 Feb 1993 13:36:14 BURT
+Change for Cayman
+
+
+ Rev 1.34 26 Oct 1992 10:40:02 STEVEN
+fix bugs for nt
+
+ Rev 1.33 04 Oct 1992 19:46:42 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.32 21 Sep 1992 16:52:00 DARRYLP
+Updates for WFW email.
+
+ Rev 1.31 17 Sep 1992 18:03:28 DARRYLP
+New dialog for WFW email.
+
+ Rev 1.30 19 Aug 1992 14:13:16 CHUCKB
+Added id's for new about dialog controls.
+
+ Rev 1.29 26 Jun 1992 15:56:42 DAVEV
+
+
+ Rev 1.28 09 Apr 1992 11:38:12 GLENN
+Added about box version string ID.
+
+ Rev 1.27 06 Apr 1992 04:34:02 CHUCKB
+Added another include.
+
+ Rev 1.26 06 Apr 1992 04:23:38 CHUCKB
+Added some include files.
+
+ Rev 1.25 06 Apr 1992 04:22:04 CHUCKB
+Fixed some control ids for 3 dialogs.
+
+ Rev 1.24 06 Apr 1992 10:56:48 DAVEV
+added defines for 'Browse to Path' dialog
+
+ Rev 1.23 18 Mar 1992 14:32:46 DAVEV
+Updates for OEM_MSOFT version of dialog
+
+ Rev 1.22 24 Feb 1992 09:36:56 ROBG
+Deleted printlog.h
+
+ Rev 1.21 31 Jan 1992 12:44:10 CHUCKB
+Moved attach-to-server id's to srvlogin.h
+
+ Rev 1.20 30 Jan 1992 16:30:28 GLENN
+Moved the skip/wait on open file stuff to muiconf.c
+
+ Rev 1.19 28 Jan 1992 09:56:28 CARLS
+removed the defines for Tension dialog
+
+ Rev 1.18 27 Jan 1992 12:51:00 GLENN
+Fixed dialog IDs.
+
+ Rev 1.17 27 Jan 1992 00:41:52 CHUCKB
+Updated dialog id's.
+
+ Rev 1.16 25 Jan 1992 21:29:24 CHUCKB
+Fixed some defines.
+
+ Rev 1.15 24 Jan 1992 14:00:54 CHUCKB
+Put more dialogs on net.
+
+ Rev 1.14 10 Jan 1992 11:04:02 CHUCKB
+No change.
+
+ Rev 1.13 09 Jan 1992 14:53:26 JOHNWT
+added confirm new dbpw equates
+
+ Rev 1.12 06 Jan 1992 13:48:28 JOHNWT
+added id for new pw text
+
+ Rev 1.11 23 Dec 1991 15:37:06 GLENN
+Added Settings Options stuff
+
+ Rev 1.10 19 Dec 1991 13:35:22 CHUCKB
+Added new id's for debug settings dialog.
+
+ Rev 1.9 17 Dec 1991 17:39:36 CHUCKB
+Added ids for new backup settings controls.
+
+ Rev 1.8 14 Dec 1991 13:49:34 JOHNWT
+new network settings dialog
+
+ Rev 1.7 13 Dec 1991 16:14:00 JOHNWT
+added defines for loginpw.dlg
+
+ Rev 1.6 10 Dec 1991 13:39:48 CHUCKB
+Added template id for lanstream tape password dialog.
+
+ Rev 1.5 08 Dec 1991 18:48:44 JOHNWT
+changed next set cancel to abort
+
+ Rev 1.4 07 Dec 1991 12:19:26 CARLS
+
+ Rev 1.3 06 Dec 1991 15:53:52 JOHNWT
+added defines for DM_NextSet
+
+ Rev 1.2 05 Dec 1991 16:20:54 CARLS
+changed value of skip open files defines
+
+ Rev 1.1 04 Dec 1991 17:08:12 CHUCKB
+Added new id's for int'l stuff.
+
+ Rev 1.0 20 Nov 1991 19:38:36 SYSTEM
+Initial revision.
+
+*****************************************************/
+
+#ifndef dialogs_h
+#define dialogs_h
+
+#include <dlgs.h> //common dialog ids used by DM_GetBrowsePath dialog
+
+// UNIVERSAL DEFINITIONS FOR ALL DIALOGS
+
+#include "add_icon.h"
+#include "adv_rest.h"
+#include "adv_sel.h"
+#include "adv_serv.h"
+#include "catmaint.h"
+#include "del_sel.h"
+
+#ifdef WFW
+#ifndef OEM_MSOFT
+# include "email.h"
+# include "emllogon.h"
+#endif
+#endif
+
+#include "hwdlg.h"
+
+#include "jobsetup.h"
+#include "job_new.h"
+#include "job_opts.h"
+#include "loginpw.h"
+#include "ltappswd.h"
+#include "msgboxid.h"
+#include "network.h"
+#include "nextset.h"
+#include "save_sel.h"
+#include "sched.h"
+#include "sch_opts.h"
+#include "tsearch.h"
+#include "setback.h"
+#include "set_cat.h"
+#include "set_dbug.h"
+#include "set_log.h"
+#include "set_opts.h"
+#include "set_prt.h"
+#include "set_rest.h"
+#include "srvlogin.h"
+#include "tapepswd.h"
+#include "tension.h"
+#include "use_sel.h"
+
+#define IDD_FILEOPEN ID(290)
+#define IDD_FILENAME 291
+#define IDD_FILES 292
+#define IDD_PATH 293
+#define IDD_DIRS 294
+
+#define IDD_ABOUT ID(300)
+#define IDD_ABOUT_VERSION 301
+#define IDD_ABOUT_RES_STR 302
+#define IDD_ABOUT_RES_SIZ 303
+#define IDD_ABOUT_MEM_STR 304
+#define IDD_ABOUT_MEM_SIZ 305
+#define IDD_ABOUT_MODE_STR 306
+
+#define IDD_ABOUTAPPNAME 301
+#define IDD_ABOUTVERSION 302
+#define IDD_ABOUTOTHERSTUFF 303
+#define IDD_ABOUTUSERNAME 304
+#define IDD_ABOUTCOMPANYNAME 305
+#define IDD_ABOUTSERIALNUM 306
+#define IDD_ABOUTMEMTITLE 307
+#define IDD_ABOUTMEMORY 308
+#define IDD_ABOUTPROCESSORTITLE 309
+#define IDD_ABOUTPROCESSOR 310
+#define IDD_ABOUTICON 311
+#define IDD_ABOUTIDENTTITLE 312
+#define IDD_ABOUTIDENT 313
+#define IDD_ABOUTPRODID 314
+
+#define IDD_FIND ID(400)
+#define IDD_SEARCH 401
+#define IDD_PREV 402
+#define IDD_NEXT IDOK
+#define IDD_CASE 403
+
+#define IDD_SAVEAS ID(500)
+#define IDD_SAVEFROM 501
+#define IDD_SAVETO 502
+
+#define IDD_PRINT ID(600)
+#define IDD_PRINTDEVICE 601
+#define IDD_PRINTPORT 602
+#define IDD_PRINTTITLE 603
+
+#define IDD_FONT ID(700)
+#define IDD_FACES 701
+#define IDD_SIZES 702
+#define IDD_BOLD 703
+#define IDD_ITALIC 704
+#define IDD_FONTTITLE 705
+
+
+/* attribute flags for DlgDirList */ // -- WHY THE HECK IS THIS STUFF HERE?????
+
+#define ATTR_DIRS 0xC010 /* find drives and directories */
+#define ATTR_FILES 0x0000 /* find ordinary files */
+#define PROP_FILENAME szPropertyName /* name of property for dialog */
+
+/* backup/restore/verify target; also Hardware dialog */
+
+#define IDD_DRIVELIST 121
+#define IDD_BSETNAME 122
+#define IDD_CURDRIVE 123
+#define IDD_DEFDRIVE 124
+
+/* restore control */
+
+#define IDD_RAUTOV 105
+
+/* erase operation controls */
+
+#define IDD_TAPENAME 110
+#define IDD_SETSONTAPE 111
+#define IDD_SECERASE 112
+#define IDD_PLABEL 113
+
+/* printer setup */
+
+#define IDD_PRSETUP 107
+
+/* search */
+
+#define IDD_FS_HELP 101
+#define IDD_FS_DIR 102
+#define IDD_FS_TEXT1 103
+#define IDD_FS_TEXT2 104
+#define IDD_FS_FILE 105
+#define IDD_FS_ENTIREDISK 106
+#define IDD_FS_ALLDISKS 107
+#define IDD_FS_ALLTAPES 108
+
+#define IDD_BEFORE_UP 300
+#define IDD_BEFORE_DOWN 302
+#define IDD_AFTER_UP 301
+#define IDD_AFTER_DOWN 303
+#define IDD_NUMDAYS_UP 304
+#define IDD_NUMDAYS_DOWN 305
+
+/* local to the callback table */
+
+#define IDD_TAPELABEL 105
+
+/* reenter password dialog */
+
+#define IDD_PASSWORD_OK 102
+#define IDD_PASSWORD_EDIT 103
+
+/* skipno dialog */
+
+#define IDD_SKIPNO_TEXT 101
+#define IDD_SKIPNO_YES 110
+#define IDD_SKIPNO_ALL 112
+#define IDD_SKIPNO_NO 111
+#define IDD_SKIPNO_CANCEL 114
+#define IDD_SKIPNO_BITMAP 120
+
+/* job/scheduler controls */
+
+#include "jobs.h"
+
+/* backup set dialog */
+#ifdef OEM_MSOFT
+# include "ombkup.h"
+#else
+# include "bkup.h"
+#endif
+
+#include "omxchng.h"
+
+/* runtime dialog */
+
+#include "rt_dlg.h"
+
+/* restore target dialog */
+
+#if defined ( OEM_MSOFT )
+# include "omrset.h"
+#else
+# include "rset.h"
+#endif
+#include "skipopen.h"
+#include "freplace.h"
+#include "erase.h"
+#include "cattape.h"
+#if !defined( OEM_MSOFT)
+#include "abortdlg.h" // chs:05-25-93
+#endif
+
+/* message box defines for msgbox dialog box */
+
+#define IDD_MESSAGE_BOX 280
+
+/* Browse to Path dialog id - Note: this dialog is NOT placed int the */
+/* Dialog Manager table! This dialog is used as a replacement */
+/* to the COMMDLG GetSaveFileName dialog. */
+
+#define IDD_BROWSE ID(800) //an unused dialog id
+#define IDD_LOGFILEBROWSE ID(801) //an unused dialog id
+
+#define IDD_WAITDEV_TEXT 850
+
+/* Dummy device driver dialog */
+
+#ifdef DUMMY_DD
+#include "ddd_dlg.h"
+#endif
+
+#endif
diff --git a/private/utils/ntbackup/inc/dil.h b/private/utils/ntbackup/inc/dil.h
new file mode 100644
index 000000000..4da0898a9
--- /dev/null
+++ b/private/utils/ntbackup/inc/dil.h
@@ -0,0 +1,94 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: dil.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the function prototypes for the Device Independent
+ Layer ( DIL ).
+
+ Location: BE_PRIVATE
+
+
+ $Log: T:\logfiles\dil.h_v $
+ *
+ * Rev 1.8 28 Jan 1994 18:25:28 GREGG
+ * Fixed MIPS 16 byte alignment requirement bug.
+ *
+ * Rev 1.7 07 Jan 1994 14:46:40 CLIFF
+ * Added DDD_ChangeTape prototype.
+ *
+ * Rev 1.6 17 May 1993 19:04:50 GREGG
+ * Added prototype for new function TpSpace.
+ *
+ * Rev 1.5 21 Jan 1993 14:56:26 GREGG
+ * Added 'erase type' parameter to TpErase prototype.
+ *
+ * Rev 1.4 25 Aug 1992 13:03:48 NED
+ * Changed dil.h to declare all Tpxxx() calls as TP_TYPE,
+ * which is _far _pascal under OS2, nothing otherwise.
+ * Included dil.h in dil.c for OS/2 as well.
+ * Ansified function definitions.
+ * Changed MAYN_xxx to OS_xxx definitions, checked for usage in dil.h
+ * Now, calls from the application to the loaddrv.c layer are _far _pascal,
+ * as well as the calls from the app to the DLL.
+
+**/
+#ifndef PICKLES
+#define PICKLES
+
+/* paranoia... */
+#if defined( MAYN_WIN ) && !defined( OS_WIN )
+ #error Change your MAYN_WIN define to OS_WIN (or add OS_WIN)!
+#elif defined( MAYN_OS2 ) && !defined( OS_OS2 )
+ #error Change your MAYN_OS2 define to OS_OS2 (or add OS_OS2)!
+#elif defined( MAYN_NLM ) && !defined( OS_NLM )
+ #error Change your MAYN_NLM define to OS_NLM (or add OS_NLM)!
+#endif
+
+#if !defined(TP_TYPE) /* allow override of TP_TYPE */
+ #if defined(OS_OS2)
+ #define TP_TYPE _far _pascal
+ #else
+ /* default to cdecl or whatever */
+ #define TP_TYPE
+ #endif
+#endif
+
+BOOLEAN TP_TYPE TpInit( DIL_HWD_PTR, INT16 ) ;
+BOOLEAN TP_TYPE TpAuto( DIL_HWD_PTR, INT16 ) ;
+VOID TP_TYPE TpRelease( void ) ;
+BOOLEAN TP_TYPE TpReset( INT16 ) ;
+INT16 TP_TYPE TpOpen( DIL_HWD_PTR, INT16 ) ;
+BOOLEAN TP_TYPE TpClose( INT16 ) ;
+BOOLEAN TP_TYPE TpCloseRewind( INT16 ) ;
+BOOLEAN TP_TYPE TpWrite( INT16, UINT8_PTR, UINT32 ) ;
+BOOLEAN TP_TYPE TpRead( INT16, UINT8_PTR, UINT32 ) ;
+BOOLEAN TP_TYPE TpRewind( INT16, BOOLEAN ) ;
+BOOLEAN TP_TYPE TpEject( INT16 ) ;
+BOOLEAN TP_TYPE TpErase( INT16, INT16 ) ;
+BOOLEAN TP_TYPE TpRetension( INT16 ) ;
+BOOLEAN TP_TYPE TpWriteEndSet( INT16 ) ;
+
+// TpSpace is a super set of TpReadEndSet, and will eventually replace
+// it completely.
+
+BOOLEAN TP_TYPE TpReadEndSet( INT16, INT16, INT16 ) ;
+BOOLEAN TP_TYPE TpSpace( INT16, INT16, INT16 ) ;
+
+BOOLEAN TP_TYPE TpReceive( INT16, RET_BUF_PTR ) ;
+BOOLEAN TP_TYPE TpSpecial( INT16, INT16, UINT32 ) ;
+BOOLEAN TP_TYPE TpStatus( INT16 ) ;
+BOOLEAN TP_TYPE TpSeek( INT16, UINT32, BOOLEAN ) ;
+BOOLEAN TP_TYPE TpGetPosition( INT16, BOOLEAN ) ;
+BOOLEAN TP_TYPE TpDismount( INT16 ) ;
+BOOLEAN TP_TYPE TpMount( INT16 ) ;
+BOOLEAN TP_TYPE TpLock( INT8_PTR, INT32_PTR ) ;
+BOOLEAN TP_TYPE TpUnlock( INT32_PTR ) ;
+BOOLEAN TP_TYPE TpGetTapeBuffAlignment( INT_PTR ) ;
+BOOLEAN TP_TYPE DDD_ChangeTape( INT16, INT16, INT16 ) ;
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/dilhwd.h b/private/utils/ntbackup/inc/dilhwd.h
new file mode 100644
index 000000000..a5ddb657c
--- /dev/null
+++ b/private/utils/ntbackup/inc/dilhwd.h
@@ -0,0 +1,55 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: ndilhwd.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the Generic Hardware description Structure.
+
+ Location: BE_PUBLIC
+
+
+ $log$
+
+**/
+/* $end$ include list */
+
+#ifndef DILHWD
+
+#define DILHWD
+
+typedef struct DIL_HWD {
+ CHAR driver_label[25] ; /* Contains the text description */
+ UINT16 no_attached_drives ; /* The Number of Maynard Drives Attached to this Card */
+ UINT16 card_attribs ; /* The attributes for this card .. defined below */
+ UINT16 init_error ; /* Error Type on Init */
+ UINT32 parameters[20] ; /* Parameter array */
+} DIL_HWD, *DIL_HWD_PTR ;
+
+/* The Possible initialization errors */
+
+#define DD_INIT_ERR_NO_DRIVES 0x01
+#define DD_INIT_ERR_IRQ_CONFLICT 0x02
+#define DD_INIT_ERR_DMA_CONFLICT 0x03
+#define DD_INIT_ERR_NO_CARD_DETECTED 0x04
+#define DD_INIT_ERR_SCCB_POOL 0x05
+#define DD_INIT_ERR_SCBD 0x06 /* SCBD access failure (driver ".sys" probably not installed) */
+#define DD_INIT_ERR_NO_ASPI_MANAGER 0x07
+#define DD_INIT_ERR_NOT_ASPI_DEVICE 0x08
+#define DD_INIT_ERR_MEMALLOC_FAILED 0x09
+#define DD_INIT_ERR_CARD_ALREADY_INIT 0x0A /* dil_hwd/card/device already initialized */
+#define DD_INIT_ERR_INVALID_PARAMETER 0x0B /* invalid value(s) in dil_hwd.parameter[] */
+#define DD_INIT_ERR_INVALID_BASEADDR 0x0C /* invalid base address value in dil_hwd.parameter[] */
+#define DD_INIT_ERR_INVALID_IRQ 0x0D /* invalid IRQ channel value in dil_hwd.parameter[] */
+#define DD_INIT_ERR_INVALID_DMA 0x0E /* invalid DMA channel value in dil_hwd.parameter[] */
+
+#define DD_INIT_ERR_NO_SYS_DETECTED 0x31
+#define DD_INIT_ERR_TCB_ALLOCATION 0x32
+
+/* Card Attributes */
+
+#define DD_CARD_NON_ASYNC 0x01
+
+#endif
diff --git a/private/utils/ntbackup/inc/dilntprv.h b/private/utils/ntbackup/inc/dilntprv.h
new file mode 100644
index 000000000..503a7d2dc
--- /dev/null
+++ b/private/utils/ntbackup/inc/dilntprv.h
@@ -0,0 +1,41 @@
+/**
+Copyright(c) Conner Software Products Group 1993
+
+ Name: dilntprv.h
+
+ Description: Contains defines types and prototypes shared by dilntmsc.c
+ and dilnttp.c.
+
+ $Log: T:/LOGFILES/DILNTPRV.H_V $
+
+ Rev 1.0 17 May 1993 16:49:58 GREGG
+DILNTTP.C, DILNTMSC.C and DILNTPRV.H replace DIL_NT.C at rev. 1.44.
+
+**/
+
+#define NUM_TCBS 30
+#define SIGNALEDSTATE 0x00000000
+
+//
+// Defines for terminating the thread process
+//
+#define FOREVER_FOREVER 1
+#define FOREVER_STOP 2
+
+
+// use as semaphore wait timeout values
+#define WAITFOREVER 0xffffffff
+#define NOWAIT 0x1
+
+typedef struct {
+ Q_ELEM q_stuff ;
+ MSL_REQUEST dil_request ;
+ RET_BUF ret_stuff ;
+} FAKE_TCB, *FAKE_TCB_PTR ;
+
+BOOLEAN CreateCQueue( Q_HEADER_PTR queue, Q_HEADER_PTR outqueue ) ;
+HANDLE CreateAThread( VOID ) ;
+BOOLEAN CEnqueue( Q_HEADER_PTR queue, Q_HEADER_PTR outqueue, FAKE_TCB tmpTCB ) ;
+BOOLEAN COutDequeue( Q_HEADER_PTR outqueue, Q_HEADER_PTR inqueue ) ;
+
+
diff --git a/private/utils/ntbackup/inc/dle.h b/private/utils/ntbackup/inc/dle.h
new file mode 100644
index 000000000..e863de56f
--- /dev/null
+++ b/private/utils/ntbackup/inc/dle.h
@@ -0,0 +1,286 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: dle.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This header file provides declarations
+ need to access the FSU for DLE specific functions.
+
+ Location: BE_PUBLIC
+
+
+ $Log: M:/LOGFILES/DLE.H_V $
+ *
+ * Rev 1.26 03 Aug 1993 16:29:18 JOHNES
+ * Added DLE_GetAttachCount macro.
+ *
+ * Rev 1.25 19 Jul 1993 10:25:44 BARRY
+ * Added macro to get the list in which a DLE is contained.
+ *
+ * Rev 1.24 17 Jun 1993 11:38:40 ChuckS
+ * Added DLE_IsNonVolume macro.
+ *
+ * Rev 1.23 14 Jun 1993 18:09:36 BARRY
+ * Fixed error in change to FS_PromptForBindery macro.
+ *
+ * Rev 1.22 11 Jun 1993 14:18:50 BARRY
+ * Changed prompt FS_PromptForBindery to use new special files definitions.
+ *
+ * Rev 1.21 04 Jun 1993 17:35:58 ChuckS
+ * P_CLIENT & OS_DOS only: Added prototype for functional form of
+ * DLE_GetDefaultDrive.
+ *
+ * Rev 1.20 22 Apr 1993 10:12:04 BILLB
+ * Added support for GRFS Device subtypes
+ *
+ * Rev 1.19 18 Mar 1993 15:20:22 ChuckS
+ * Changes for Generic Device Names for VOLB
+ *
+ * Rev 1.18 16 Dec 1992 11:50:44 DON
+ * Changed file system specific Server/Volume macros into functions - dleget.c
+ *
+ * Rev 1.17 09 Dec 1992 11:40:48 DON
+ * Changed function prototype to macro for DLE_
+ *
+ * Rev 1.16 11 Nov 1992 22:09:44 GREGG
+ * Unicodeized literals.
+ *
+ * Rev 1.15 21 Jul 1992 14:04:20 STEVEN
+ * added support for DLE_GetUserName
+ *
+ * Rev 1.14 28 May 1992 09:44:12 BARRY
+ * Move changes on branches back to tip.
+ *
+ * Rev 1.14 28 May 1992 09:43:56 BARRY
+ * Move changes on branches back to tip.
+ *
+ * Rev 1.13 21 May 1992 13:46:54 STEVEN
+ * more long path support
+ *
+ * Rev 1.12 28 Feb 1992 14:42:58 STEVEN
+ * fix bug with display name
+ *
+ * Rev 1.11 13 Feb 1992 11:37:38 STEVEN
+ * fix support stuff
+ *
+ * Rev 1.10 20 Dec 1991 09:31:12 STEVEN
+ * move common files to tables
+ *
+ * Rev 1.9 31 Oct 1991 16:25:42 BARRY
+ * TRICYCLE: Added a DLE features macro and converted SupportChild()
+ * to use this macro.
+ *
+ * Rev 1.8 01 Oct 1991 12:58:18 BARRY
+ * Tag BE_CFG_PTRs passed to DLE functions.
+ *
+ * Rev 1.7 08 Aug 1991 19:09:22 DON
+ * added support for NLM_SERVER_ONLY to DLE_SupportChild macro
+ *
+ * Rev 1.5 30 Jul 1991 10:19:20 DON
+ * ifdef'd macros for accessing info.server/info.nlm_server data
+ *
+ * Rev 1.4 21 Jun 1991 13:23:16 BARRY
+ * Changes for new config.
+ *
+ * Rev 1.3 18 Jun 1991 13:50:32 STEVEN
+ * DEFINE MBS_DEV_TYPE
+ *
+ * Rev 1.2 30 May 1991 13:51:44 BARRY
+ * No longer have selector to DLE_UpdateList().
+ *
+ * Rev 1.1 20 May 1991 16:42:16 STEVEN
+ * queues.h should be in quotes
+ *
+ * Rev 1.0 09 May 1991 13:31:10 HUNTER
+ * Initial revision.
+
+**/
+#ifndef DLE_H
+#define DLE_H 1
+#include "queues.h"
+#include "beconfig.h"
+#include "dle_str.h"
+/* $end$ include list */
+
+/**
+ Defines for DLE parameters
+**/
+
+/* DLE_DeviceDispName() - type */
+#define DISP_LONG_DEV_NAME 0
+#define DISP_SHORT_DEV_NAME 1
+#define MBS_DEV_NAME 2
+#define GEN_LONG_DEV_NAME 3
+
+
+/**
+ Macros used to access the DLE
+**/
+
+#define DLE_DeviceDispName( dle, dev_name, size, disp_type ) \
+ (msassert ( func_tab[ (dle)->type ].DevDispName != NULL),\
+ (func_tab [(dle)->type].DevDispName( dle, dev_name, size, disp_type ) ) )
+
+#define DLE_DeviceName( dle, dev_name, size ) \
+ DLE_DeviceDispName( dle, dev_name, size, GEN_LONG_DEV_NAME )
+
+#define DLE_GetVolName( dle, buffer ) \
+ (msassert ( func_tab[ (dle)->type ].GetVolName != NULL),\
+ (func_tab [(dle)->type].GetVolName( dle, buffer ) ) )
+
+#define DLE_SizeofVolName( dle ) \
+ (msassert ( func_tab[ (dle)->type ].SizeofVolName != NULL),\
+ (func_tab [(dle)->type].SizeofVolName( dle ) ) )
+
+#define DLE_SizeofDevName( dle ) \
+ (msassert( func_tab[ (dle)->type ].SizeofDevName != NULL ), \
+ (func_tab[ (dle)->type ].SizeofDevName( dle ) ) )
+
+#define DLE_ViewUserName( dle ) \
+ ((dle)->user_name)
+
+#define DLE_SizeofUserName( dle ) \
+ ((dle)->user_name_leng)
+
+#define FS_MakePath( buf, bsize, dle, path, psize, fname ) \
+ (msassert ( func_tab[ (dle)->type ].MakePath != NULL),\
+ (func_tab [(dle)->type].MakePath( buf, bsize, dle, path, psize, fname ) ) )
+
+#if defined( P_CLIENT ) && defined( OS_DOS )
+
+GENERIC_DLE_PTR DLE_GetDefaultDrive( DLE_HAND hand ) ;
+
+#else
+
+#define DLE_GetDefaultDrive( hand ) \
+ ((hand)->default_drv)
+#endif
+
+#define DLE_GetOsId( dle ) \
+ ((dle)->os_id)
+
+
+#define DLE_SetDefaultDrive( hand, dle ) \
+ ((hand)->default_drv = (dle))
+
+#define DLE_GetDeviceType( dle ) \
+ ((dle)->type & (~HAND_MADE_MASK))
+
+#define DLE_GetDeviceSubType( dle ) \
+ ((dle)->subtype)
+
+#define DLE_GetDeviceName( dle ) \
+ ( (dle)->device_name)
+
+#define DLE_GetDeviceNameLeng( dle ) \
+ ( (dle)->device_name_leng)
+
+#define DLE_GetPathDelim( dle ) \
+ ( (dle)->path_delim)
+
+#define DLE_GetHandle( dle ) \
+ ( (dle)->handle )
+
+#define DLE_GetParent( dle ) \
+ ( (dle)->parent )
+
+#define DLE_PswdRequired( dle ) \
+ ( (dle)->pswd_required)
+
+#define DLE_PswdSaved( dle ) \
+ ( (dle)->pswd_saved)
+
+#define DLE_UserRequired( dle ) \
+ ( (dle)->name_required)
+
+#define DLE_UserSaved( dle ) \
+ ( (dle)->name_saved)
+
+#define DLE_DriveWriteable( dle ) \
+ ( (dle)->dle_writeable)
+
+#define DLE_GetNumChild( dle ) \
+ (QueueCount( &(dle)->child_q ) )
+
+#define DLE_HasFeatures( dle, mask ) \
+ ( ( ((dle)->feature_bits & (mask)) == (mask) ? TRUE : FALSE ) )
+
+#define DLE_SupportChild( dle ) \
+ ( DLE_HasFeatures( (dle), DLE_FEAT_SUPPORTS_CHILDREN ) )
+
+#define DLE_SupportAccessDate( dle ) \
+ ( DLE_HasFeatures( (dle), DLE_FEAT_ACCESS_DATE ) )
+
+#define DLE_IsNonVolume( dle ) \
+ ( DLE_HasFeatures( dle, DLE_FEAT_NON_VOLUME_OBJECT ) )
+
+#define FS_PromptForBindery( dle ) \
+ ( DLE_HasFeatures( (dle), DLE_FEAT_BKUP_SPECIAL_FILES ) || \
+ DLE_HasFeatures( (dle), DLE_FEAT_REST_SPECIAL_FILES ))
+
+
+#define FS_PromptForSecure( dle ) \
+ ( DLE_HasFeatures( (dle), DLE_FEAT_DATA_SECURITY ) )
+
+#define DLE_IncBSDCount( dle ) \
+ ( (dle)->bsd_use_count++ )
+
+#define DLE_DecBSDCount( dle ) \
+ ( (dle)->bsd_use_count-- )
+
+#define DLE_IsImageDOS( dle ) \
+ ( ((dle)->type == LOCAL_IMAGE) && ((dle)->info.image->drive_char != TEXT('\0') ) )
+
+#define DLE_GetImageDriveNum( dle ) \
+ ((dle)->info.image->drive_num & 0x7f )
+
+#define DLE_GetImagePartNum( dle ) \
+ ((dle)->info.image->partition )
+
+#define DLE_IsTemporary( dle ) \
+ ( (dle)->type & HAND_MADE_MASK )
+
+#define DLE_GetAttachCount( dle ) \
+ ( (dle)->attach_count )
+
+
+/**
+ DLE support functions
+**/
+INT16 DLE_ResetList( DLE_HAND hand );
+
+INT16 DLE_Remove( DLE_HAND hand, GENERIC_DLE_PTR dle ) ;
+
+INT16 DLE_GetFirst( DLE_HAND hand, GENERIC_DLE_PTR *dle );
+
+INT16 DLE_GetFirstChild( GENERIC_DLE_PTR server_dle, GENERIC_DLE_PTR *dle ) ;
+
+INT16 DLE_GetNext( GENERIC_DLE_PTR *dle ) ;
+
+INT16 DLE_GetPrev( GENERIC_DLE_PTR *dle ) ;
+
+INT16 DLE_FindByName( DLE_HAND hand, CHAR_PTR name, INT16 type, GENERIC_DLE_PTR *dle ) ;
+
+INT16 DLE_OSVerToType( UINT8 os_id, UINT8 os_ver ) ;
+
+INT16 DLE_UpdateList( DLE_HAND dle_hand, BE_CFG_PTR cfg ) ;
+
+INT16 DLE_DeleteList( DLE_HAND dle_hand, BE_CFG_PTR cfg, UINT16 dle_selector ) ;
+
+VOID DLE_SetPartName( DLE_HAND dle_hand, UINT16 drive_num, UINT16 part_num, CHAR_PTR name ) ;
+
+INT16 FS_AddTempDLE( DLE_HAND dle_hand, CHAR_PTR name, CHAR_PTR vol_name, INT16 type ) ;
+
+INT16 DLE_ServerLoggedIn( GENERIC_DLE_PTR server_dle ) ;
+
+CHAR_PTR DLE_GetServerPswd( GENERIC_DLE_PTR server_dle ) ;
+
+CHAR_PTR DLE_GetServerUserName( GENERIC_DLE_PTR server_dle ) ;
+
+UINT8 DLE_GetServerNum( GENERIC_DLE_PTR server_dle ) ;
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/dle_str.h b/private/utils/ntbackup/inc/dle_str.h
new file mode 100644
index 000000000..9092c0635
--- /dev/null
+++ b/private/utils/ntbackup/inc/dle_str.h
@@ -0,0 +1,662 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: dle_str.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains the structures for the DLE
+
+ Location: BE_PUBLIC
+
+
+
+ $Log: M:/LOGFILES/DLE_STR.H_V $
+ *
+ * Rev 1.40.1.1 04 Jan 1994 11:02:42 BARRY
+ * Added Unicode name feature bit
+ *
+ * Rev 1.40.1.0 18 Oct 1993 19:22:08 STEVEN
+ * add support for SPACE & PERIOD
+ *
+ * Rev 1.40 26 Jul 1993 17:05:56 STEVEN
+ * fixe restore active file with registry
+ *
+ * Rev 1.39 17 Jun 1993 11:39:12 ChuckS
+ * Added define of DLE_FEAT_NON_VOLUME_OBJECT
+ *
+ * Rev 1.38 11 Jun 1993 14:17:40 BARRY
+ * Separated special files into backup and restore special files.
+ *
+ * Rev 1.37 09 Jun 1993 19:18:58 MIKEP
+ * more c++ changes
+ *
+ * Rev 1.35 09 Jun 1993 10:44:24 BARRY
+ * Added a default security descriptor and its ACL to NTFS dle.
+ *
+ * Rev 1.34 23 Apr 1993 05:31:18 BILLB
+ * Fixed GRFS_MAC_AGENT define (was GRFS_MAX_AGENT. oopsy!)
+ *
+ * Rev 1.33 22 Apr 1993 10:12:14 BILLB
+ * Added support for GRFS Device subtypes
+ *
+ * Rev 1.32 16 Apr 1993 13:55:20 MIKEP
+ * add case preserving option
+ *
+ * Rev 1.31 15 Jan 1993 13:19:10 BARRY
+ * added support for new error messages and backup priviladge
+ *
+ * Rev 1.30 13 Jan 1993 15:04:12 DOUG
+ * Changed FS_RMFS to FS_GRFS
+ *
+ * Rev 1.29 07 Dec 1992 12:16:48 DON
+ * Changes for when to prompt for username/password
+ *
+ * Rev 1.28 11 Nov 1992 22:09:54 GREGG
+ * Unicodeized literals.
+ *
+ * Rev 1.27 04 Nov 1992 17:59:28 BARRY
+ * Added fs_name to NTFS dle.
+ *
+ * Rev 1.26 13 Oct 1992 12:27:30 STEVEN
+ * added case sensitive feature bit
+ *
+ * Rev 1.25 07 Oct 1992 14:50:50 STEVEN
+ * size should be INT
+ *
+ * Rev 1.24 05 Oct 1992 13:03:22 STEVEN
+ * added registry path size to NTFS DLE
+ *
+ * Rev 1.23 05 Oct 1992 11:46:42 STEVEN
+ * added registry path to NTFS DLE
+ *
+ * Rev 1.22 29 Jul 1992 15:34:14 STEVEN
+ * fix warnings
+ *
+ * Rev 1.21 23 Jul 1992 12:36:16 STEVEN
+ * fix mare warnings
+ *
+ * Rev 1.20 23 Jul 1992 11:27:12 STEVEN
+ * user_name_leng is int not char_ptr
+ *
+ * Rev 1.19 23 Jul 1992 11:03:22 BURT
+ * Fixed errant ')'s caused by macro error.
+ *
+ *
+ * Rev 1.18 23 Jul 1992 09:54:16 STEVEN
+ * fix warnings
+ *
+ * Rev 1.17 21 Jul 1992 14:04:32 STEVEN
+ * added support for DLE_GetUserName
+ *
+ * Rev 1.16 09 Jul 1992 14:46:16 STEVEN
+ * BE_Unicode updates
+ *
+ * Rev 1.15 02 Jul 1992 10:23:34 MIKEP
+ * Add feature bit for remote device.
+ *
+ * Rev 1.14 28 May 1992 09:44:16 BARRY
+ * Move changes on branches back to tip.
+ *
+ * Rev 1.13 21 May 1992 13:46:44 STEVEN
+ * more long path support
+ *
+ * Rev 1.12 07 May 1992 08:38:42 STEVEN
+ * moved osid and osver
+ *
+ * Rev 1.11 12 Mar 1992 17:14:08 DOUG
+ * Added changes for RMFS support.
+ *
+ * Rev 1.10 20 Dec 1991 09:31:30 STEVEN
+ * move common files to tables
+ *
+ * Rev 1.9 31 Oct 1991 19:01:56 BARRY
+ * Added another feature definition.
+ *
+ * Rev 1.8 31 Oct 1991 16:27:56 BARRY
+ * TRICYCLE: Added a field in GENERIC_DLE to hold a set of feature bits.
+ * Added some #defines for current "special" features.
+ *
+ * Rev 1.7 03 Oct 1991 09:39:04 BARRY
+ * Add new field for SMS object DLE.
+ *
+ * Rev 1.6 10 Sep 1991 18:17:10 DON
+ * rearranged the order of drive types
+ *
+ * Rev 1.5 10 Sep 1991 17:08:48 BARRY
+ * Added SMS dle structures.
+ *
+ * Rev 1.4 13 Aug 1991 16:51:46 DON
+ * removed server member from NLM dle types
+ *
+ * Rev 1.3 31 Jul 1991 18:41:38 DON
+ * added new dle types for the NLM
+ * NLM_DLE && NLM_AFP_DLE && NLM_SERVER_DLE
+ *
+ * Rev 1.2 30 Jun 1991 16:21:08 BARRY
+ * Added stuff for the Ersatz file system.
+ *
+ * Rev 1.1 23 May 1991 16:50:04 BARRY
+ * DLE types are no longer enumerated based on product #defines.
+ *
+ * Rev 1.0 09 May 1991 13:30:48 HUNTER
+ * Initial revision.
+
+**/
+
+#ifndef DLE_STR_H
+#define DLE_STR_H
+#include "queues.h"
+
+
+/**
+ File System constants
+**/
+
+/*
+ text string limits
+*/
+#define NOV_SERV_NAM_SIZE 48 /* server name size */
+#define NOV_VOL_NAM_SIZE 16 /* volume name size */
+#define NOV_MAXDSIZE 512 /* current directory */
+
+/*
+ File system types
+*/
+#define GENERIC_DATA ((UINT8)0) /* g */
+#define NLM_SERVER_ONLY ((UINT8)1) /* v */
+#define NLM_VOLUME ((UINT8)2) /* l */
+#define NLM_AFP_VOLUME ((UINT8)3) /* p */
+#define NOVELL_DRV ((UINT8)4) /* n */
+#define NOVELL_AFP_DRV ((UINT8)5) /* a */
+#define NOVELL_SERVER_ONLY ((UINT8)6) /* s */
+#define LOCAL_DOS_DRV ((UINT8)7) /* d */
+#define REMOTE_DOS_DRV ((UINT8)8) /* r */
+#define LOCAL_IMAGE ((UINT8)9) /* i */
+#define REMOTE_WORK_STAT ((UINT8)10) /* w */
+#define LOCAL_OS2_DRV ((UINT8)11) /* o */
+#define ERSATZ_DRV ((UINT8)12) /* e */
+#define SMS_AGENT ((UINT8)13) /* tsa */
+#define SMS_SERVICE ((UINT8)14) /* ts */
+#define SMS_OBJECT ((UINT8)15) /* m */
+#define LOCAL_NTFS_DRV ((UINT8)16) /* t */
+#define GRFS_SERVER ((UINT8)17) /* gr */
+#define FS_EMS_DRV ((UINT8)18) /* x */
+
+#define MAX_DRV_TYPES ((UINT8)19)
+
+/*
+ GRFS specific device sub types
+*/
+#define GRFS_GENERIC_AGENT ((UINT8)0)
+#define GRFS_DOS_AGENT ((UINT8)1)
+#define GRFS_OS2_AGENT ((UINT8)2)
+#define GRFS_MAC_AGENT ((UINT8)3)
+#define GRFS_UNIX_AGENT ((UINT8)4)
+
+/*
+ EMS specific device sub types
+*/
+#define EMS_ENTERPRISE ((UINT8)1)
+#define EMS_SITE ((UINT8)2)
+#define EMS_SERVER ((UINT8)3)
+#define EMS_BRICK ((UINT8)4)
+#define EMS_MDB ((UINT8)5)
+#define EMS_DSA ((UINT8)6)
+
+
+/* Used by DLE_UpdateList to release specific DLE's */
+
+#define DEL_NOTHING ((UINT16)BIT0)
+#define SERVER_VOLUMES ((UINT16)BIT1)
+#define MAP_NETWORK_DRIVES ((UINT16)BIT2)
+
+#define UNKNOWN_NET 0xff
+
+#define ANY_DRIVE_TYPE ((INT16)-1)
+#define HAND_MADE_MASK 0x80
+
+/* Used to ID Dynamic, Initial, or No login status */
+
+#define NO_LOGIN 0
+#define INIT_LOGIN 1
+#define DYNAMIC_LOGIN 2
+
+
+/* Feature bits for DLEs. (See GENERIC_DLE struct and macros in DLE.H) */
+
+#define DLE_FEAT_REDIRECTED_RESTORE 0x0001 /* can redirect restores */
+#define DLE_FEAT_SUPPORTS_CHILDREN 0x0002 /* DLE_SupportChild should go away */
+#define DLE_FEAT_REMOVABLE_MEDIA 0x0004 /* Device has removable media */
+#define DLE_FEAT_REMOVABLE_MEDIA 0x0004 /* Device has removable media */
+#define DLE_FEAT_ACCESS_DATE 0x0008 /* Device supports access dates */
+#define DLE_FEAT_BKUP_SPECIAL_FILES 0x0010 /* Device supports backup of special files */
+#define DLE_FEAT_REST_SPECIAL_FILES 0x0020 /* Device supports restore of special files */
+#define DLE_FEAT_DATA_SECURITY 0x0040 /* Device supports network security */
+#define DLE_FEAT_REMOTE_DRIVE 0x0080 /* Device is not local */
+#define DLE_FEAT_MAPPED_DRIVE 0x0100 /* Device is mapped to a drive letter */
+#define DLE_FEAT_CASE_SENSITIVE 0x0200 /* Device were FRED.C != fred.c */
+#define DLE_FEAT_CASE_PRESERVING 0x0400 /* Device retains case but FRED==fred */
+#define DLE_FEAT_NON_VOLUME_OBJECT 0x0800 /* Device is non-volume, eg Directory services, bindery */
+#define DLE_FEAT_UNICODE_NAMES 0x1000 /* Device accepts Unicode names */
+#define DLE_FEAT_NON_DISPLAYABLE_CONT 0x2000 /* Device accepts Unicode names */
+
+/**
+ OS specific portions of DLE
+**/
+
+/*
+ IMAGE Specific DLE
+*/
+
+typedef struct LOCAL_IMAGE_DLE_INFO *LOCAL_IMAGE_DLE_INFO_PTR;
+typedef struct LOCAL_IMAGE_DLE_INFO {
+ INT8 drive_num; /* physical drive number */
+ INT8 partition; /* partition to backup for IMAGE */
+ CHAR drive_char; /* DOS drive letter for partition */
+ UINT16 bytes_per_sector; /* number of bytes per sector */
+ INT8 boot; /* boot indicator */
+ UINT8 bhead; /* beginning head number */
+ UINT8 bsect; /* beginning sector number */
+ UINT8 bcyl; /* beginning cylinder number */
+ UINT8 sysi; /* system indicator flag */
+ UINT8 ehead; /* ending head number */
+ UINT8 esect; /* ending sector number */
+ UINT8 ecyl; /* ending cylinder number */
+ UINT32 rsect; /* beginning relative sector */
+ UINT32 nsect; /* number of sectors in partition */
+ UINT16 hhead; /* highest head number on drive */
+ UINT16 hcyl; /* highest cylinder number on drive */
+ UINT16 hsect; /* highest sector number on drive */
+ UINT32 bytes_on_partition; /* nsect * bytes_per_sector */
+} LOCAL_IMAGE_DLE_INFO ;
+
+/*
+ Specific info for HAND_MADE DLE's
+*/
+typedef struct HAND_MADE_DLE_INFO *HAND_MADE_DLE_INFO_PTR;
+typedef struct HAND_MADE_DLE_INFO {
+ CHAR vol_name[2] ; /* variable sized */
+} HAND_MADE_DLE_INFO;
+
+/*
+ DOS Specific DLE
+*/
+typedef struct LOCAL_DOS_DRV_DLE_INFO *LOCAL_DOS_DRV_DLE_INFO_PTR;
+
+typedef struct LOCAL_DOS_DRV_DLE_INFO {
+
+ /* warning: This structure is shared by the FAKE_REMOTE_DOS_DRV_DLE */
+
+ CHAR drive; /* Dos Drive letter */
+ CHAR volume_label[13]; /* volume label */
+ CHAR_PTR base_path; /* points to '\0' for regular DOS, but */
+ /* points to some path for TDEMO fake remotes */
+} LOCAL_DOS_DRV_DLE_INFO;
+
+typedef struct LOCAL_NTFS_DRV_DLE_INFO *LOCAL_NTFS_DRV_DLE_INFO_PTR;
+
+typedef struct LOCAL_NTFS_DRV_DLE_INFO {
+ CHAR drive; /* Dos Drive letter */
+ BOOLEAN mac_name_syntax; /* if true "\\?\" syntax valid */
+ CHAR_PTR volume_label; /* volume label */
+ CHAR_PTR registry_path; /* needed for mapped LANMAN drvs */
+ INT registry_path_size; /* needed for mapped LANMAN drvs */
+ INT16 fname_leng ; /* size of path element */
+ DWORD vol_flags ; /* flags from GetVolInfo() */
+ CHAR_PTR fs_name; /* name of file system */
+ VOID_PTR sd; /* sec. descriptor for create */
+ VOID_PTR sdacl; /* acl for sec descriptor above */
+ CHAR_PTR LastSysRegPath ; /* last system registry path */
+ CHAR_PTR LastSysRegPathNew ; /* new fnme forLastSysRegPath */
+ CHAR user_name[ 2 ] ; /* user name - must be last */
+
+} LOCAL_DOS_NTFS_DLE_INFO;
+
+
+typedef struct EMS_ENTERP_DLE_INFO *EMS_ENTERP_DLE_INFO_PTR;
+
+typedef struct EMS_ENTERP_DLE_INFO {
+ INT type ; /* ems dle type must be first element */
+ CHAR_PTR enterprise_name; /* volume label */
+ CHAR_PTR server_name; /* volume label */
+} EMS_ENTERP_DLE_INFO;
+
+typedef struct EMS_SITE_DLE_INFO *EMS_SITE_DLE_INFO_PTR;
+
+typedef struct EMS_SITE_DLE_INFO {
+ INT type ; /* ems dle type must be first element */
+ CHAR_PTR site_name; /* volume label */
+} EMS_SITE_DLE_INFO;
+
+typedef struct EMS_SERVER_DLE_INFO *EMS_SERVER_DLE_INFO_PTR;
+
+typedef struct EMS_SERVER_DLE_INFO {
+ INT type ; /* ems dle type must be first element */
+ VOID_PTR mail_hand ; /* handle from logon */
+ CHAR_PTR server_name; /* volume label */
+} EMS_SERVER_DLE_INFO;
+
+typedef struct EMS_MDB_DSA_DLE_INFO *EMS_MDB_DSA_DLE_INFO_PTR;
+
+typedef struct EMS_MDB_DSA_DLE_INFO {
+ INT type ; /* ems dle type must be first element */
+ CHAR_PTR server_name; /* volume label */
+} EMS_MDB_DSA_DLE_INFO;
+
+typedef struct EMS_BRICK_DLE_INFO *EMS_BRICK_DLE_INFO_PTR;
+
+typedef struct EMS_BRICK_DLE_INFO {
+ INT type ; /* ems dle type must be first element */
+ VOID_PTR mail_hand ; /* handle from logon */
+ CHAR_PTR server_name; /* volume label */
+
+} EMS_BRICK_DLE_INFO;
+
+typedef struct LOCAL_OS2_DRV_DLE_INFO *LOCAL_OS2_DRV_DLE_INFO_PTR;
+
+typedef struct LOCAL_OS2_DRV_DLE_INFO {
+
+ INT16 fname_fmt; /* max size of file name */
+ CHAR drive; /* Dos Drive letter */
+ CHAR volume_label[13]; /* volume label */
+ CHAR_PTR base_path; /* points to '\0' for regular OS2*/
+
+} LOCAL_OS2_DRV_DLE_INFO;
+/* values for fname_fmt */
+#define FAT_FNAME 0
+#define HPFS_FNAME 1
+
+
+/*
+ Fake published volumes of a Fake Remote workstation
+*/
+typedef struct FAKE_REMOTE_DOS_DRV_DLE * FAKE_REMOTE_DOS_DRV_DLE_PTR ;
+
+typedef struct FAKE_REMOTE_DOS_DRV_DLE {
+ CHAR drive; /* must start out with the */
+ CHAR volume_label[13]; /* entire LOCAL_DOS_DRV_DLE_INFO */
+ CHAR_PTR base_path;
+
+ CHAR_PTR password;
+
+} FAKE_REMOTE_DOS_DRV_DLE ;
+
+/*
+ Remote workstations
+*/
+typedef struct REMOTE_WORK_STAT_DLE *REMOTE_WORK_STAT_DLE_PTR;
+
+typedef struct REMOTE_WORK_STAT_DLE {
+ struct CONNECTION_STRUCT *connect_ptr;
+ struct APPLICATION_STRUCT *application_ptr;
+} REMOTE_WORK_STAT_DLE;
+
+
+/*
+ Fake Remote workstations ( for TDEMO )
+*/
+typedef struct FAKE_REMOTE_WORK_STAT_DLE * FAKE_REMOTE_WORK_STAT_DLE_PTR ;
+
+typedef struct FAKE_REMOTE_WORK_STAT_DLE {
+ INT16 first_alias ;
+ INT16 num_aliases ;
+} FAKE_REMOTE_WORK_STAT_DLE ;
+
+/*
+ Published volumes on remote workstations
+*/
+typedef struct REMOTE_DOS_DRV_DLE *REMOTE_DOS_DRV_DLE_PTR ;
+typedef struct REMOTE_DOS_DRV_DLE {
+ CHAR pswd[9] ; /* Used to login to a remote drv */
+ struct CONNECTION_STRUCT *connect_ptr;
+ struct DEVICE_STRUCT *device_ptr;
+} REMOTE_DOS_DRV_DLE;
+
+
+/*
+ Drives for the Ersatz file system
+*/
+typedef struct ERSATZ_DRV_DLE *ERSATZ_DRV_DLE_PTR ;
+typedef struct ERSATZ_DRV_DLE {
+ CHAR *volume_label ;
+ INT16 block_size ;
+} ERSATZ_DRV_DLE;
+
+
+/*
+ Novell Server
+*/
+
+#define USER_NAME_MAX_SIZE 48 /* User name may be 47 bytes */
+#define USER_PASSWORD_MAX_SIZE 128 /* Password may be 127 bytes */
+
+typedef struct NOVELL_SERVER_DLE *NOVELL_SERVER_DLE_PTR ;
+typedef struct NOVELL_SERVER_DLE {
+ INT16 login_status ; /* 1 if logged in at init time, */
+ /* otherwise 0 */
+ CHAR user_name[USER_NAME_MAX_SIZE] ;
+ CHAR pswd [USER_PASSWORD_MAX_SIZE] ;
+ UINT8 server_num ; /* inited if logged in */
+} NOVELL_SERVER_DLE ;
+
+typedef struct NLM_SERVER_DLE *NLM_SERVER_DLE_PTR ;
+typedef struct NLM_SERVER_DLE {
+ INT16 login_status ; /* 1 if logged in at init time, */
+ /* otherwise 0 */
+ CHAR user_name[USER_NAME_MAX_SIZE] ;
+ CHAR pswd [USER_PASSWORD_MAX_SIZE] ;
+ UINT8 server_num ; /* inited if logged in */
+} NLM_SERVER_DLE ;
+
+/*
+ NOVELL < 2.15 Specific DLE
+*/
+typedef struct NOV_DRV_DLE {
+
+ /* !!!!!! SEE AFP DLE below !!!!!! */
+
+ UINT8 drive_handle; /* network path num */
+ CHAR drive; /* Dos Drive letter */
+ UINT8 vol_num ; /* volume number */
+ UINT8 server_num ; /* server number */
+ UINT8 server_support ; /* TTS, etc support */
+ CHAR_PTR ser_name; /* Server name */
+ CHAR_PTR volume ; /* volume name */
+ CHAR_PTR base_path; /* path name, not incl final '\' */
+ INT8 num_bind_close; /* # of apps who closed bindery */
+ NOVELL_SERVER_DLE_PTR server; /* points to server data */
+} *NOV_DRV_DLE_PTR;
+
+/*
+ NOVELL NLM Specific DLE
+*/
+typedef struct NLM_DLE {
+
+ /* !!!!!! SEE NLM AFP DLE below !!!!!! */
+
+ UINT8 vol_num ; /* volume number */
+ UINT8 server_num ; /* server number */
+ UINT8 server_support ; /* TTS, etc support */
+ CHAR_PTR ser_name; /* Server name */
+ CHAR_PTR volume ; /* volume name */
+ INT8 num_bind_close; /* # of apps who closed bindery */
+} *NLM_DLE_PTR;
+
+/*
+ NOVELL NLM AFP Specific DLE
+*/
+typedef struct NLM_AFP_DLE {
+ UINT8 vol_num ; /* --------------------------- */
+ UINT8 server_num ; /* !!! MUST BE The SAME !!! */
+ UINT8 server_support ; /* as */
+ CHAR_PTR ser_name; /* */
+ CHAR_PTR volume; /* !! NLM_DLE !! */
+ INT8 num_bind_close; /* ---------------------------- */
+ UINT32 base_entry_id; /* entry ID of base directory */
+} *NLM_AFP_DLE_PTR;
+
+/*
+ NOVELL >= 2.15 Specific DLE
+*/
+typedef struct NOV_AFP_DRV_DLE {
+ UINT8 drive_handle; /* --------------------------- */
+ CHAR drive; /* */
+ UINT8 vol_num ; /* !!! MUST BE The SAME !!! */
+ UINT8 server_num ; /* */
+ UINT8 server_support ; /* as */
+ CHAR_PTR ser_name; /* */
+ CHAR_PTR volume; /* !! NOV_DRV_DLE !! */
+ CHAR_PTR base_path; /* */
+ INT8 num_bind_close; /* */
+ NOVELL_SERVER_DLE_PTR server; /* ---------------------------- */
+ UINT32 base_entry_id; /* entry ID of base directory */
+} *NOV_AFP_DRV_DLE_PTR;
+
+
+/*
+ Other Netowrk Specific DLE
+*/
+typedef struct IBM_PC_LAN_DRV_DLE{
+ CHAR drive; /* Dos Drive letter */
+ CHAR volume_label[13]; /* volume label */
+} *IBM_PC_LAN_DRV_DLE_PTR;
+
+
+/*
+ * Novell's SMS Target Service Agent DLE
+ */
+typedef struct SMS_TSA_DLE *SMS_TSA_DLE_PTR;
+typedef struct SMS_TSA_DLE {
+ CHAR_PTR tsa_name; /* name of the TSA */
+ UINT32 connection; /* Connection established with TSA */
+} SMS_TSA_DLE;
+
+/*
+ * Novell's SMS Target Service DLE
+ */
+typedef struct SMS_TS_DLE *SMS_TS_DLE_PTR;
+typedef struct SMS_TS_DLE {
+ CHAR_PTR ts_name; /* service's name (same as dev name) */
+ CHAR_PTR user_name; /* User name specified at attach time */
+ CHAR_PTR password; /* Password specified at attach time */
+} SMS_TS_DLE;
+
+/*
+ * Novell's SMS Target Service Object DLE
+ */
+typedef struct SMS_TSO_DLE *SMS_TSO_DLE_PTR;
+typedef struct SMS_TSO_DLE {
+ CHAR_PTR object_name; /* object's name (same as device name) */
+ BOOLEAN superset_object; /* object is superset of its siblings? */
+ BOOLEAN objectIsVolume; /* object is a "volume" */
+} SMS_TSO_DLE;
+
+
+/*
+ GRFS workstations
+*/
+
+#define GRFS_MAX_DLE_NAME_LEN 128
+
+typedef struct GRFS_SERVER_DLE *GRFS_SERVER_DLE_PTR;
+typedef struct GRFS_SERVER_DLE {
+ CHAR user_name[USER_NAME_MAX_SIZE];
+ CHAR password[USER_PASSWORD_MAX_SIZE];
+ CHAR device_name[GRFS_MAX_DLE_NAME_LEN+1];
+ UINT16 type;
+ UINT32 dle_id;
+ VOID_PTR res_ptr;
+ VOID_PTR connect_ptr;
+ BOOLEAN obj_find_more;
+ BOOLEAN spec_enum_more;
+ CHAR_PTR spec_space;
+ UINT16 spec_space_size;
+ UINT16 spec_space_pos;
+ BOOLEAN shadow_attach;
+} GRFS_SERVER_DLE;
+
+
+
+typedef union {
+ VOID_PTR any; /* generic reference to any of the following pointers */
+ LOCAL_IMAGE_DLE_INFO_PTR image;
+ LOCAL_DOS_DRV_DLE_INFO_PTR dos;
+ EMS_ENTERP_DLE_INFO_PTR xenterp ;
+ EMS_SITE_DLE_INFO_PTR xsite;
+ EMS_SERVER_DLE_INFO_PTR xserv;
+ EMS_MDB_DSA_DLE_INFO_PTR xmono;
+ EMS_BRICK_DLE_INFO_PTR xbrick;
+ LOCAL_NTFS_DRV_DLE_INFO_PTR ntfs;
+ LOCAL_OS2_DRV_DLE_INFO_PTR os2;
+ REMOTE_WORK_STAT_DLE_PTR work_stat;
+ REMOTE_DOS_DRV_DLE_PTR remote;
+ NOV_DRV_DLE_PTR nov;
+ NOV_AFP_DRV_DLE_PTR afp;
+ NOVELL_SERVER_DLE_PTR server;
+ IBM_PC_LAN_DRV_DLE_PTR pclan;
+ HAND_MADE_DLE_INFO_PTR user ;
+ FAKE_REMOTE_WORK_STAT_DLE_PTR fake_work_stat ;
+ FAKE_REMOTE_DOS_DRV_DLE_PTR fake_remote ;
+ ERSATZ_DRV_DLE_PTR ersatz ;
+ NLM_DLE_PTR nlm ;
+ NLM_AFP_DLE_PTR nlm_afp ;
+ NLM_SERVER_DLE_PTR nlm_server ;
+ SMS_TSA_DLE_PTR sms_tsa ;
+ SMS_TS_DLE_PTR sms_ts ;
+ SMS_TSO_DLE_PTR sms_tso ;
+ GRFS_SERVER_DLE_PTR grfs ;
+} DRIVE_INFO_PTR ;
+
+/**
+ Generic Drive List Element
+**/
+typedef struct HEAD_DLE *DLE_HEAD_PTR;
+typedef struct HEAD_DLE *DLE_HAND;
+
+typedef struct GENERIC_DLE *GENERIC_DLE_PTR;
+typedef struct GENERIC_DLE {
+ Q_ELEM q; /* Queue list element */
+ DLE_HEAD_PTR handle; /* pointer to the DLE queue head */
+ GENERIC_DLE_PTR parent ; /* pointer to parent DLE */
+ Q_HEADER child_q; /* queue of children DLEs */
+ UINT8 type; /* type of dle */
+ UINT8 subtype; /* a dle subtype, for those who want it*/
+ CHAR_PTR device_name; /* device label used in drive select */
+ INT16 device_name_leng ; /* length of device name */
+ CHAR_PTR user_name ; /* pointer to user name in specif info */
+ UINT16 user_name_leng ;/* length of user name in specif info */
+ CHAR path_delim ; /* Character used between dir names */
+ UINT8 pswd_required ; /* size of password required */
+ UINT8 name_required ; /* size of login name is required */
+ BOOLEAN pswd_saved ; /* TRUE if password is already saved */
+ BOOLEAN name_saved ; /* TRUE if name is already saved */
+ BOOLEAN dle_writeable; /* FALSE if drive is write protected */
+ UINT16 os_version ; /* verson of operating system */
+ INT16 attach_count ; /* number of attachments to me */
+ INT16 bsd_use_count; /* number of BSD's pointing to me */
+ BOOLEAN dynamic_info ; /* TRUE if the following pointer should be freed before freeing this structure. */
+ DRIVE_INFO_PTR info; /* pointer to Non Generic portion */
+ UINT16 feature_bits ; /* tells features/capabilities of DLE */
+ UINT8 os_id ;
+ UINT8 os_ver ;
+} GENERIC_DLE;
+
+/**
+ Handle for Drive List
+**/
+
+typedef struct HEAD_DLE {
+ Q_HEADER q_hdr ;
+ GENERIC_DLE_PTR default_drv ; /* used to return to default drive */
+ Q_HEADER fsh_queue ; /* Q of all allocated FS handles */
+ UINT32 file_sys_mask ;
+ INT16 (*crit_err)() ; /* pointer to UI critical err hand */
+ INT16 fs_initialized ; /* bit_mask specifies whats inited */
+ UINT16 remote_filter ; /* bit_mask specifies visible remote reource types */
+
+} HEAD_DLE ;
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/dlg_ids.h b/private/utils/ntbackup/inc/dlg_ids.h
new file mode 100644
index 000000000..a27bc6d65
--- /dev/null
+++ b/private/utils/ntbackup/inc/dlg_ids.h
@@ -0,0 +1,140 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: dlg_ids.h
+
+ Description: Dialog ID file.
+
+ $Log: G:\ui\logfiles\dlg_ids.h_v $
+
+ Rev 1.11 01 Aug 1993 13:12:38 MIKEP
+add idd_waitdevice
+
+ Rev 1.10 27 Jul 1993 13:22:10 chrish
+CAYMAN EPR 0638: Added new define IDD_PMDUMMYABORT for print aborting.
+
+ Rev 1.9 14 Jul 1993 09:22:56 CARLS
+added ID for skipno dialog
+
+ Rev 1.8 25 May 1993 14:24:00 chrish
+Added new define IDD_ABORT_BOX for backup/restore abort dialog box.
+
+ Rev 1.7 31 Oct 1992 14:56:50 MIKEP
+continue adding small catalog dialog
+
+ Rev 1.6 04 Oct 1992 19:46:44 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.5 21 Sep 1992 16:51:08 DARRYLP
+Updates for WFW email routines.
+
+ Rev 1.4 17 Sep 1992 18:04:24 DARRYLP
+New Dialog ID for WFW email.
+
+ Rev 1.3 02 Sep 1992 15:07:22 GLENN
+Added the choose font dialog ID.
+
+ Rev 1.2 06 Apr 1992 09:54:06 CHUCKB
+Added define for translation.
+
+ Rev 1.1 24 Feb 1992 09:38:52 ROBG
+Added IDD_PMABORT for print manager.
+
+ Rev 1.0 27 Jan 1992 10:14:48 GLENN
+Initial revision.
+
+*******************************************************************************/
+
+#ifndef DLG_IDS_H
+#define DLG_IDS_H
+
+// UNIVERSAL DEFINITIONS FOR ALL DIALOGS
+
+#undef IDHELP
+#define IDHELP 100
+
+#define IDD_HELPABOUTWINTERPARK 1
+
+#define IDD_OPERATIONSERASE 2
+
+#define IDD_SELECTADVANCED 3
+#define IDD_SELECTSAVE 4
+#define IDD_SELECTUSE 5
+#define IDD_SELECTDELETE 6
+#define IDD_ADVRESTORE 7
+
+#define IDD_JOBNEW 8
+#define IDD_JOBMAINTENANCE 9
+#define IDD_JOBOPTS 10
+#define IDD_JOBSCHEDULE 11
+#define IDD_SCHEDOPTS 12
+
+#define IDD_SETTINGSOPTIONS 13
+#define IDD_SETTINGSBACKUP 14
+#define IDD_SETTINGSRESTORE 15
+#define IDD_SETTINGSLOGGING 16
+#define IDD_SETTINGSNETWORK 17
+#define IDD_SETTINGSCATALOG 18
+#define IDD_SETTINGSHARDWARE 19
+#define IDD_SETTINGSDEBUGWINDOW 20
+
+#define IDD_PSWD 21
+#define IDD_RESTORE 22
+#define IDD_VERIFY 23
+#define IDD_SEARCHTAPE 24
+
+#define IDD_FILESETUP 25
+#define IDD_FILEPRINT 26
+
+#define IDD_OPERATIONSCATMAINT 27
+#define IDD_CATBSET 28
+#define IDD_CATTAPE 29
+#define IDD_TAPEPSWD 30
+#define IDD_LANTAPEPSWD 31
+
+#define IDD_JOBPROGMANITEM 32
+
+#define IDD_BACKUPSET 33
+#define IDD_RESTORESET 34
+#define IDD_VERIFYSET 35
+#define IDD_REENTER_PASSWORD 36
+#define IDD_SKIPOPEN 37
+#define IDD_FILEREPLACE 38
+#define IDD_ERASE 39
+#define IDD_RUNTIME 40
+#define IDD_TENSION 41
+#define IDD_NEXT_SET 42
+#define IDD_PWDB_PASSWORD 43
+#define IDD_EMAIL 44
+#define IDD_EMAILLOGON 45
+
+
+// This define doesn't happen to be used by any menus.
+
+#define IDD_MESSAGE_BOX 280
+
+// Not in dialog manager. Used as modeless in print manager.
+
+#define IDD_PMABORT 46
+
+// FONT
+
+#define IDD_CHOOSEFONT 47
+
+
+#define IDD_CATALOG 48
+
+#define IDD_ABORT_BOX 49 // chs:05-25-93
+
+#define IDD_SKIPNO 50
+
+#define IDD_PMDUMMYABORT 51 // chs:07-27-93
+
+#define IDD_WAITDEVICE 52
+
+#define IDD_CONNECT_XCHNG 53
+
+#define IDD_XCHG_RECOVER 54
+
+#endif
diff --git a/private/utils/ntbackup/inc/dlm.h b/private/utils/ntbackup/inc/dlm.h
new file mode 100644
index 000000000..0327d2849
--- /dev/null
+++ b/private/utils/ntbackup/inc/dlm.h
@@ -0,0 +1,469 @@
+/****************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+ Name: DLM.H
+
+ Description: This header file contains prototypes for the
+ display list manager.
+
+ $Log: G:/UI/LOGFILES/DLM.H_V $
+
+ Rev 1.24 15 Jun 1993 09:58:08 MIKEP
+enable c++
+
+ Rev 1.23 28 Apr 1993 15:36:00 GLENN
+Added DLM_GetPixelStringWidth() for column width calculations.
+
+ Rev 1.22 02 Apr 1993 15:53:14 ROBG
+Changed FocusItem to be UINT for both NT and WINDOWS.
+
+ Rev 1.21 10 Feb 1993 13:09:18 ROBG
+Added conditional OS_WIN32 to definition of szText buffer.
+This static buffer is used by application code to pass
+text strings to the DLM. One buffer per object.
+
+ Rev 1.20 21 Dec 1992 12:28:58 DAVEV
+Enabled for Unicode - IT WORKS!!
+
+ Rev 1.19 11 Dec 1992 18:31:08 GLENN
+Fixed horizontal spelling and ColWidth spelling.
+
+ Rev 1.18 14 Oct 1992 15:49:10 GLENN
+Added Selection Framing Support for List Boxes without the FOCUS.
+
+ Rev 1.17 04 Oct 1992 19:46:48 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.16 08 Sep 1992 09:24:36 ROBG
+Changed the x and y positional variables to short from USHORT.
+
+ Rev 1.15 20 Aug 1992 11:50:00 ROBG
+Added function DLM_SetFont to support the modification of fonts in the
+listboxes.
+
+ Rev 1.14 19 Mar 1992 09:12:04 ROBG
+Added new routine prototype for DLM_SetHorizontalExt.
+
+ Rev 1.13 10 Feb 1992 09:17:52 GLENN
+Changed DLM_KeyUp to receive a pointer to the key.
+
+ Rev 1.12 26 Dec 1991 16:01:10 ROBG
+Removed reference to DLM_ROW_VECTOR.
+
+ Rev 1.11 26 Dec 1991 10:20:34 ROBG
+Removed define for DLM_LARGEBITMTAPSSTEXT.
+
+ Rev 1.10 19 Dec 1991 08:52:00 ROBG
+Added prototype for DLM_Deinit.
+
+ Rev 1.9 17 Dec 1991 18:03:00 ROBG
+Corrected misspellings in DLM_Get, SetCheckboxWidth/Height.
+
+ Rev 1.8 17 Dec 1991 15:08:52 ROBG
+Changed usDummy field to a define field of 'usTrkPtFailure'.
+
+ Rev 1.7 17 Dec 1991 14:01:20 ROBG
+Moved from private header file DLM_GetDispHdr.
+
+ Rev 1.6 16 Dec 1991 09:42:02 ROBG
+Added routine DLM_GetObjectList.
+
+ Rev 1.5 12 Dec 1991 17:11:58 DAVEV
+16/32 bit port -2nd pass
+
+ Rev 1.4 10 Dec 1991 14:19:34 GLENN
+Added DLM_MULTICOLUMN same as DLM_COLUMN_VECTOR
+
+ Rev 1.3 03 Dec 1991 16:13:54 GLENN
+Added DLM_CharToItem() prototype.
+
+ Rev 1.2 02 Dec 1991 13:13:18 ROBG
+Added some new style macros.
+
+ Rev 1.1 27 Nov 1991 10:33:46 ROBG
+Changed dlm_displistterm prototype.
+
+ Rev 1.0 20 Nov 1991 19:34:04 SYSTEM
+Initial revision.
+
+****************************************************************************/
+
+#ifndef dlm_h
+#define dlm_h
+
+#define DLM_SINGLECOLUMN 1
+#define DLM_MULTICOLUMN 2
+#define DLM_COLUMN_VECTOR DLM_MULTICOLUMN
+#define DLM_HIERARCHICAL 4
+
+#define DLM_LARGEBITMAPSLTEXT 1 /* Text to the right of bitmap */
+#define DLM_SMALL_BITMAPS 3
+#define DLM_ICONS 4
+
+#define DLM_CHECKBOX 1
+#define DLM_BITMAP 2
+#define DLM_ICON 3
+#define DLM_TEXT_ONLY 4
+
+#define DLM_TREELISTBOX 1
+#define DLM_FLATLISTBOX 2
+ /* bTextMode bits */
+#define DLM_TEXT_RIGHT_OF_ITEM BIT0
+#define DLM_ITALIC BIT1
+#define DLM_UNDERLINE BIT2
+#define DLM_BOLD BIT3
+#define DLM_RIGHT_JUSTIFY BIT4
+#define DLM_LEFT_JUSTIFY BIT5
+
+
+#define DLM_ANSI_FIXED_FONT 0
+#define DLM_ANSI_VAR_FONT 1
+#define DLM_DEVICEDEFAULT_FONT 2
+#define DLM_OEM_FIXED_FONT 3
+#define DLM_SYSTEM_FONT 4
+
+// LIST BOX SCROLL TYPES -- OTHERS CAN BE ADDED AS NEEDED
+
+#define DLM_SCROLLTOP SB_TOP
+#define DLM_SCROLLBOTTOM SB_BOTTOM
+
+#define DLMERR_OUT_OF_MEMORY 1
+#define DLMERR_TERMINATE_FAILED 2
+#define DLMERR_PROCESS_FAILED 3
+#define DLMERR_LIST_NOT_FOUND 4
+#define DLMERR_INIT_FAILED 5
+
+
+typedef struct _DLM_ITEM {
+ BYTE cbNum ; /* Number of item in sequential list. */
+ BYTE bType; /* Type of object to display. */
+ /* Not Used fdor parent list items. */
+ /* For Parent list items: */
+ /* BIT0 Displayed status. */
+ /* 1 if displayed, else 0. */
+ /* BIT1 Tagged status. */
+ /* 1 if tagged, else 0. */
+ WORD wId ; /* Id of a bitmap or icon */
+ BYTE bTextMode ; /* Where to place the text and style */
+ BYTE bMaxTextLen; /* Maximum Length in characters of text. */
+ /* This length is used to determine */
+ /* row or column sizes so that high- */
+ /* lighting may occur for a fixed region.*/
+ BYTE bLevel ; /* In a hierarchical list, the entry */
+ /* will help identify the indentation */
+ /* of the item. */
+ BYTE bTag ; /* Tag state 0:no 1:yes */
+
+#if defined( OS_WIN32 )
+ BYTE szText[600] ; /* Allow for very long name with NT */
+#else
+ BYTE szText[133] ;
+#endif
+
+ } DLM_ITEM, *DLM_ITEM_PTR ;
+
+
+typedef USHORT (*GET_COUNT_PTR) ( LMHANDLE dhListHdr ) ;
+typedef PVOID (*GET_FIRST_PTR) ( LMHANDLE dhListHdr ) ;
+typedef PVOID (*GET_NEXT_PTR) ( LMHANDLE dhListItem ) ;
+typedef PVOID (*GET_PREV_PTR) ( LMHANDLE dhListItem ) ;
+typedef BYTE (*GET_TAG_PTR) ( LMHANDLE dhListItem ) ;
+typedef PVOID (*SET_TAG_PTR) ( LMHANDLE dhListItem, BYTE fTag ) ;
+typedef BYTE (*GET_SELECT_PTR) ( LMHANDLE dhListItem ) ;
+typedef PVOID (*SET_SELECT_PTR) ( LMHANDLE dhListItem, BYTE fSelect ) ;
+typedef PVOID (*GET_OBJECTS_PTR) ( LMHANDLE dhListItem ) ;
+typedef BOOL (*SET_OBJECTS_PTR) ( LMHANDLE dhListItem, WORD bOperation, WORD bObjectNum ) ;
+typedef PVOID (*SET_FOCUS_PTR) ( LMHANDLE dhListItem ) ;
+
+
+typedef struct _DLM_HEADER {
+ BYTE bMode ;
+ BYTE bDisplay ;
+ BYTE bListBoxType ;
+ VOID_PTR lpdsListHdr ;
+ WORD nTextFont ;
+ GET_COUNT_PTR pfnGetItemCount ;
+ GET_FIRST_PTR pfnGetFirstItem ;
+ GET_NEXT_PTR pfnGetNext ;
+ GET_PREV_PTR pfnGetPrev ;
+ GET_TAG_PTR pfnGetTag ;
+ SET_TAG_PTR pfnSetTag ;
+ GET_SELECT_PTR pfnGetSelect ;
+ SET_SELECT_PTR pfnSetSelect ;
+ GET_OBJECTS_PTR pfnGetObjects ;
+ SET_OBJECTS_PTR pfnSetObjects ;
+ SET_FOCUS_PTR pfnSetItemFocus ;
+ BYTE bMaxNumObjects ;
+
+ USHORT cxColWidth ;
+ USHORT cyColHeight ;
+
+ USHORT cxCheckBoxWidth ;
+ USHORT cyCheckBoxHeight ;
+ USHORT cxBitMapWidth ;
+ USHORT cyBitMapHeight ;
+ USHORT cxTextWidth ;
+ USHORT cyTextHeight ;
+
+ short cxBeforeCheckBox ;
+ short cxBeforeBitMap ;
+ short cxBeforeText ;
+
+ short cyBeforeCheckBox ;
+ short cyBeforeBitMap ;
+ short cyBeforeText ;
+
+ USHORT cxHierTab ;
+ USHORT cxHierHorzLine ;
+ USHORT cxHierHorzLen ;
+ USHORT cLastTreeSelect ;
+
+ USHORT usItemCount ;
+
+ UINT unFocusItem ;
+ USHORT usTrkPtFailure ;
+
+ short nMaxWidth ;
+
+ LMHANDLE dhAnchorItem ;
+ USHORT iAnchorItem ;
+
+ BYTE fKeyDown ;
+ BYTE fKeyUp ;
+ WORD wKeyValue ;
+
+ WORD wHorizontalExtent ;
+ WORD xOrigin ;
+
+ WORD fFocus ;
+ WORD hWndFocus ;
+ PVOID pGetObjBuffer;
+
+} DLM_HEADER, *DLM_HEADER_PTR ;
+
+typedef struct _DLM_INIT {
+ BYTE bMode ;
+ BYTE bDisplay ;
+ BYTE bListBoxType ;
+ VOID_PTR lpdsListHdr ;
+ WORD nTextFont ;
+ GET_COUNT_PTR pfnGetItemCount ;
+ GET_FIRST_PTR pfnGetFirstItem ;
+ GET_NEXT_PTR pfnGetNext ;
+ GET_PREV_PTR pfnGetPrev ;
+ GET_TAG_PTR pfnGetTag ;
+ SET_TAG_PTR pfnSetTag ;
+ GET_SELECT_PTR pfnGetSelect ;
+ SET_SELECT_PTR pfnSetSelect ;
+ GET_OBJECTS_PTR pfnGetObjects ;
+ SET_OBJECTS_PTR pfnSetObjects ;
+ SET_FOCUS_PTR pfnSetItemFocus ;
+ BYTE bMaxNumObjects ;
+} DLM_INIT, *DLM_INIT_PTR ;
+
+
+#define DLM_Mode( p, x ) ( (p)->bMode = x )
+#define DLM_Display( p, x ) ( (p)->bDisplay = x )
+#define DLM_ListBoxType( p, x ) ( (p)->bListBoxType = x )
+#define DLM_DispHdr( p, x ) ( (p)->lpdsListHdr = (VOID_PTR) x )
+#define DLM_TextFont( p, x ) ( (p)->nTextFont = (WORD) x )
+#define DLM_GetItemCount( p, x ) ( (p)->pfnGetItemCount = (GET_COUNT_PTR) x )
+#define DLM_GetFirstItem( p, x ) ( (p)->pfnGetFirstItem = (GET_FIRST_PTR) x )
+#define DLM_GetNext( p, x ) ( (p)->pfnGetNext = (GET_NEXT_PTR) x )
+#define DLM_GetPrev( p, x ) ( (p)->pfnGetPrev = (GET_PREV_PTR) x )
+#define DLM_GetTag( p, x ) ( (p)->pfnGetTag = (GET_TAG_PTR) x )
+#define DLM_SetTag( p, x ) ( (p)->pfnSetTag = (SET_TAG_PTR) x )
+#define DLM_GetSelect( p, x ) ( (p)->pfnGetSelect = (GET_SELECT_PTR) x )
+#define DLM_SetSelect( p, x ) ( (p)->pfnSetSelect = (SET_SELECT_PTR) x )
+#define DLM_GetObjects( p, x ) ( (p)->pfnGetObjects = (GET_OBJECTS_PTR) x )
+#define DLM_SetObjects( p, x ) ( (p)->pfnSetObjects = (SET_OBJECTS_PTR) x )
+#define DLM_SSetItemFocus( p, x ) ( (p)->pfnSetItemFocus = (SET_FOCUS_PTR) x )
+#define DLM_MaxNumObjects( p, x ) ( (p)->bMaxNumObjects = x )
+#define DLM_GetObjBuffer( p, x ) ( (p)->pGetObjBuffer = (VOID_PTR x )
+
+#define DLM_GMode( p ) (p)->bMode
+#define DLM_GDisplay( p ) (p)->bDisplay
+#define DLM_GListBoxType( p ) (p)->bListBoxType
+#define DLM_GDispHdr( p ) (p)->lpdsListHdr
+#define DLM_GTextFont( p ) (p)->nTextFont
+#define DLM_GGetItemCount( p ) (p)->pfnGetItemCount
+#define DLM_GGetFirstItem( p ) (p)->pfnGetFirstItem
+#define DLM_GGetNext( p ) (p)->pfnGetNext
+#define DLM_GGetPrev( p ) (p)->pfnGetPrev
+#define DLM_GGetTag( p ) (p)->pfnGetTag
+#define DLM_GSetTag( p ) (p)->pfnSetTag
+#define DLM_GGetSelect( p ) (p)->pfnGetSelect
+#define DLM_GSetSelect( p ) (p)->pfnSetSelect
+#define DLM_GGetObjects( p ) (p)->pfnGetObjects
+#define DLM_GSetObjects( p ) (p)->pfnSetObjects
+#define DLM_GSetItemFocus( p ) (p)->pfnSetItemFocus
+#define DLM_GMaxNumObjects( p ) (p)->bMaxNumObjects
+#define DLM_GGetObjBuffer( p ) (p)->pGetObjBuffer
+
+// New macros for accessing the fields in DLM_ITEM and DLM_HEADER.
+
+#define DLM_GetMode( x ) ( (x)->bMode )
+#define DLM_SetMode( x, y ) ( (x)->bMode = (y) )
+
+#define DLM_GetDisplay( x ) ( (x)->bDisplay )
+#define DLM_SetDisplay( x, y ) ( (x)->bDisplay = (y) )
+
+#define DLM_GetListBoxType( x ) ( (x)->bListBoxType )
+#define DLM_SetListBoxType( x, y ) ( (x)->bListBoxType = (y) )
+
+#define DLM_GetDisplayHdr( x ) ( (x)->lpdsListHdr )
+#define DLM_SetDisplayHdr( x, y ) ( (x)->lpdsListHdr = (PVOID) (y) )
+
+#define DLM_GetTextFont( x ) ( (x)->nTextFont )
+#define DLM_SetTextFont( x, y ) ( (x)->nTextFont = (WORD) (y) )
+
+#define DLM_GetFnGetItemCount( x ) ( (x)->pfnGetItemCount )
+#define DLM_SetFnGetItemCount( x, y ) ( (x)->pfnGetItemCount = (GET_COUNT_PTR) (y) )
+
+#define DLM_GetFnGetFirstItem( x ) ( (x)->pfnGetFirstItem )
+#define DLM_SetFnGetFirstItem( x, y ) ( (x)->pfnGetFirstItem = (GET_FIRST_PTR) (y) )
+
+#define DLM_GetFnGetNext( x ) ( (x)->pfnGetNext )
+#define DLM_SetFnGetNext( x, y ) ( (x)->pfnGetNext = (GET_NEXT_PTR (y) )
+
+#define DLM_GetFnGetPrev( x ) ( (x)->pfnGetPrev )
+#define DLM_SetFnGetPrev( x, y ) ( (x)->pfnGetPrev = (GET_PREV_PTR (y) )
+
+#define DLM_GetFnGetTag( x ) ( (x)->pfnGetTag )
+#define DLM_SetFnGetTag( x, y ) ( (x)->pfnGetTag = (GET_TAG_PTR (y) )
+
+#define DLM_GetFnSetTag( x ) ( (x)->pfnSetTag )
+#define DLM_SetFnSetTag( x, y ) ( (x)->pfnSetTag = (SET_TAG_PTR (y) )
+
+#define DLM_GetFnGetSelect( x ) ( (x)->pfnGetSelect )
+#define DLM_SetFnGetSelect( x, y ) ( (x)->pfnGetSelect = (GET_SELECT_PTR (y) )
+
+#define DLM_GetFnSetSelect( x ) ( (x)->pfnSetSelect )
+#define DLM_SetFnSetSelect( x, y ) ( (x)->pfnSetSelect = (SET_SELECT_PTR (y) )
+
+#define DLM_GetFnGetObjects( x ) ( (x)->pfnGetObjects )
+#define DLM_SetFnGetObjects( x, y ) ( (x)->pfnGetObjects = (GET_OBJECTS_PTR (y) )
+
+#define DLM_GetFnSetObjects( x ) ( (x)->pfnSetObjects )
+#define DLM_SetFnSetObjects( x, y ) ( (x)->pfnSetObjects = (SET_OBJECTS_PTR (y) )
+
+#define DLM_GetFnSetItemFocus( x ) ( (x)->pfnSetItemFocus )
+#define DLM_SetFnSetItemFocus( x, y ) ( (x)->pfnSetItemFocus = (SET_FOCUS_PTR (y) )
+
+#define DLM_GetMaxNumObjects( x ) ( (x)->bMaxNumObjects )
+#define DLM_SetMaxNumObjects( x, y ) ( (x)->bMaxNumObjects = (y) )
+
+#define DLM_GetBufferForObjects( x ) ( (x)->pGetObjBuffer )
+#define DLM_SetBufferForObjects( x, y ) ( (x)->pGetObjBuffer = (PVOID) (y) )
+
+#define DLM_GetColWidth( x ) ( (x)->cxColWidth )
+#define DLM_SetColWidth( x, y ) ( (x)->cxColWidth = (USHORT) (y) )
+
+#define DLM_GetColHeight( x ) ( (x)->cyColHeight )
+#define DLM_SetColHeight( x, y ) ( (x)->cyColHeight = (USHORT) (y) )
+
+#define DLM_GetCheckBoxWidth( x ) ( (x)->cxCheckBoxWidth )
+#define DLM_SetCheckBoxWidth( x, y ) ( (x)->cxCheckBoxWidth = (USHORT) (y) )
+
+#define DLM_GetCheckBoxHeight( x ) ( (x)->cyCheckBoxHeight )
+#define DLM_SetCheckBoxHeight( x, y ) ( (x)->cyCheckBoxHeight = (USHORT) (y) )
+
+#define DLM_GetBitMapWidth( x ) ( (x)->cxBitMapWidth )
+#define DLM_SetBitMapWidth( x, y ) ( (x)->cxBitMapWidth = (USHORT) (y) )
+
+#define DLM_GetBitMapHeight( x ) ( (x)->cyBitMapHeight )
+#define DLM_SetBitMapHeight( x, y ) ( (x)->cyBitMapHeight = (USHORT) (y) )
+
+#define DLM_GetTextWidth( x ) ( (x)->cxTextWidth )
+#define DLM_SetTextWidth( x, y ) ( (x)->cxTextWidth = (USHORT) (y) )
+
+#define DLM_GetTextHeight( x ) ( (x)->cyTextHeight )
+#define DLM_SetTextHeight( x, y ) ( (x)->cyTextHeight = (USHORT) (y) )
+
+#define DLM_GetTrkPtFailure( x ) ( (x)->usTrkPtFailure )
+#define DLM_SetTrkPtFailure( x, y ) ( (x)->usTrkPtFailure = (USHORT) (y) )
+
+// Used by DLM only. Relates to the DLM_HEADER structure.
+
+#define DLM_HdrFirstItem( p ) (p)->dhFirstItem
+#define DLM_HdrLastItem( p ) (p)->dhLastItem
+#define DLM_HdrFirstDisp( p ) (p)->dhFirstDisp
+#define DLM_HdrLastDisp( p ) (p)->dhLastDisp
+#define DLM_HdrAnchorItem p ) (p)->dhAnchorItem
+
+
+// Used to access DLM_ITEM */
+
+#define DLM_ItemcbNum( p ) (p)->cbNum
+#define DLM_ItembType( p ) (p)->bType
+#define DLM_ItemwId( p ) (p)->wId
+#define DLM_ItembTextMode( p ) (p)->bTextMode
+#define DLM_ItembMaxTextLen( p ) (p)->bMaxTextLen
+#define DLM_ItembLevel( p ) (p)->bLevel
+#define DLM_ItembTag( p ) (p)->bTag
+#define DLM_ItemqszString( p ) (p)->szText
+
+// New macros for accessing the fields in DLM_ITEM
+
+#define DLM_GetItemNumber( x ) ( (x)->cbNum )
+#define DLM_SetItemNumber( x, y ) ( (x)->cbNum = (y) )
+
+#define DLM_GetItemType( x ) ( (x)->bType )
+#define DLM_SetItemType( x, y ) ( (x)->bType = (y) )
+
+#define DLM_GetItemId( x ) ( (x)->wId )
+#define DLM_SetItemId( x, y ) ( (x)->wId = (y) )
+
+#define DLM_GetItemTextMode( x ) ( (x)->bTextMode )
+#define DLM_SetItemTextMode( x, y ) ( (x)->bTextMode = (y) )
+
+#define DLM_GetItemMaxTextLen( x ) ( (x)->bMaxTextLen )
+#define DLM_SetItemMaxTextLen( x, y ) ( (x)->bMaxTextLen = (y) )
+
+#define DLM_GetItemLevel( x ) ( (x)->bLevel )
+#define DLM_SetItemLevel( x, y ) ( (x)->bLevel = (y) )
+
+#define DLM_GetItemTag( x ) ( (x)->bTag )
+#define DLM_SetItemTag( x, y ) ( (x)->bTag = (y) )
+
+#define DLM_GetItemText( x ) ( (x)->szText )
+#define DLM_SetItemText( x, y ) ( lstrcpy ( (x)->szText, (y) ) )
+
+VOID DLM_Deinit ( VOID ) ;
+WORD DLM_Init ( HWND hWnd ) ;
+WORD DLM_DispListInit ( PVOID pWinInfo, DLM_INIT_PTR pdsInit ) ;
+WORD DLM_DispListTerm ( PVOID pWinInfo, HWND hWndCtl ) ;
+WORD DLM_DispListProc ( HWND hWndCtl, WORD iAnchorIndex, LMHANDLE dhAnchorHandle ) ;
+WORD DLM_DispListModeGet ( HWND hWnd, BYTE bType, LPBYTE lpbMode ) ;
+WORD DLM_DispListModeSet ( HWND hWnd, BYTE bType, BYTE bMode ) ;
+WORD DLM_SetAnchor ( HWND hWndCtl, WORD iAnchorItem, LMHANDLE dhAnchorAddr ) ;
+WORD DLM_Update ( HWND hWnd, BYTE bType, WORD wMsg, LMHANDLE dhStartItem, USHORT usCnt ) ;
+WORD DLM_UpdateFocus ( HWND hWndLB, BOOL fSetFocus ) ;
+WORD DLM_UpdateTags ( HWND hWnd, BYTE bType ) ;
+
+WORD DLM_WMSize ( HWND hWnd, MP1 mp1, MP2 mp2 ) ;
+WORD DLM_WMDestroy ( HWND hWnd ) ;
+WORD DLM_WMLButton ( HWND hWnd, WORD wMsg, MP1 mp1, MP2 mp2 ) ;
+WORD DLM_WMDrawItem ( HWND hWnd, LPDRAWITEMSTRUCT lpdis ) ;
+WORD DLM_WMMeasureItem ( HWND hWnd, LPMEASUREITEMSTRUCT lParam ) ;
+WORD DLM_WMDeleteItem ( HWND hWnd, LPDELETEITEMSTRUCT lParam ) ;
+WORD DLM_LBNmessages ( HWND hWnd, MP1 mp1, MP2 mp2 ) ;
+BOOL DLM_KeyDown ( HWND hWnd, LPWORD pwKey, MP2 mp2 ) ;
+BOOL DLM_KeyUp ( HWND hWnd, LPWORD pwKey, MP2 mp2 ) ;
+WORD DLM_WMTrackPoint ( HWND hWnd, MP1 mp1, MP2 mp2 ) ;
+BOOL DLM_CursorInCheckBox ( HWND hWnd, POINT pt ) ;
+PVOID DLM_GetObjectsBuffer ( HWND hWndCtl ) ;
+VOID DLM_ScrollListBox ( HWND hWnd, WORD wType ) ;
+PVOID DLM_GetFocusItem ( HWND hWndCtl ) ;
+VOID DLM_SetFocusItem ( LPDRAWITEMSTRUCT lpdis, LPRECT prcItem ) ;
+BOOL DLM_CharToItem ( HWND hWndListBox, DLM_HEADER_PTR pHdr, LPWORD pwKey ) ;
+VOID DLM_SetHorizontalExt ( HWND hWndCtl, DLM_HEADER_PTR pHdr , PVOID pListItem ) ;
+VOID DLM_SetFont ( HWND hWnd ) ;
+
+INT DLM_GetPixelStringWidth ( HWND hWndLB, LPSTR lpString, INT nStringLen );
+
+DLM_ITEM_PTR DLM_GetFirstObject( LPBYTE lpObjLst , LPBYTE bpObjCnt ) ;
+DLM_HEADER_PTR DLM_GetDispHdr( HWND hWndCtl ) ;
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/dlm_prv.h b/private/utils/ntbackup/inc/dlm_prv.h
new file mode 100644
index 000000000..7859c9d22
--- /dev/null
+++ b/private/utils/ntbackup/inc/dlm_prv.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+ Name: DLM_PRV.H
+
+ Description: This header file contains private defines, prototypes,
+ and variables for the display list manager.
+
+ $Log: G:/UI/LOGFILES/DLM_PRV.H_V $
+
+ Rev 1.10 01 Nov 1992 16:30:40 DAVEV
+Unicode changes
+
+ Rev 1.9 04 Oct 1992 19:46:50 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.8 08 Sep 1992 10:37:22 ROBG
+Changed the x and y positions to short versus USHORT.
+
+ Rev 1.7 15 Jan 1992 15:22:52 DAVEV
+16/32 bit port-2nd pass
+
+ Rev 1.6 26 Dec 1991 10:22:00 ROBG
+Removed prototype for DLM_DrawLMapSText.
+
+ Rev 1.5 19 Dec 1991 09:40:10 ROBG
+Fixed bug.
+
+ Rev 1.4 19 Dec 1991 09:38:28 ROBG
+Added DLM_GetWidth
+
+
+ Rev 1.3 19 Dec 1991 08:43:12 ROBG
+Added mwpTempObjBuff.
+
+ Rev 1.2 17 Dec 1991 17:34:42 ROBG
+Added two fields to remember the maximum width of a character font.
+
+ Rev 1.1 17 Dec 1991 14:02:28 ROBG
+Move out the definition DLM_GetDispHdr.
+
+ Rev 1.0 20 Nov 1991 19:33:48 SYSTEM
+Initial revision.
+
+****************************************************************************/
+
+#ifndef dlm_prv_h
+#define dlm_prv_h
+
+VOID DLM_GetRect ( HWND hWndCtl, DLM_HEADER_PTR pHdr,
+// LPSHORT pcxPos, short cyPos,
+ SHORT *pcxPos, short cyPos,
+ LPRECT lpRect, DLM_ITEM_PTR lpDispItem ) ;
+
+VOID DLM_GetWidth ( HWND hWndCtl, DLM_HEADER_PTR pHdr,
+ SHORT * pcxPos, DLM_ITEM_PTR lpDispItem ) ;
+// LPSHORT pcxPos, DLM_ITEM_PTR lpDispItem ) ;
+
+WORD DLM_ProcessButton ( HWND hWnd , DLM_HEADER_PTR pHdr, WORD msg,
+ LPRECT lpRect, USHORT wCurSel,
+ LMHANDLE dhListItem,DLM_ITEM_PTR lpDispItem ) ;
+WORD DLM_DrawLMapLText ( HWND hWnd, LPDRAWITEMSTRUCT lpdis ) ;
+WORD DLM_DrawSMapLText ( HWND hWnd, LPDRAWITEMSTRUCT lpdis ) ;
+WORD DLM_DrawTree ( HWND hWnd, LPDRAWITEMSTRUCT lpdis ) ;
+BOOL DLM_IsFocusInWindow( HWND hWnd,HWND hWndCtl ) ;
+
+VOID DLM_InitScrnValues ( DLM_HEADER_PTR pHdr ) ;
+WORD DLM_LBNflatmsgs ( HWND hWnd, MP1 mp1, MP2 mp2 ) ;
+VOID DLM_SpaceBarPressed ( HWND hWndListBox, DLM_HEADER_PTR pHdr, LPWORD pwKey ) ;
+
+
+// Module wide variables
+
+INT16 mwDLMInflate ;
+
+USHORT mwcxDLMFontFilesMaxWidth ;
+USHORT mwcxDLMFontFilesWidth ;
+USHORT mwcyDLMFontFilesHeight ;
+
+USHORT mwcxDLMIconLabelsMaxWidth ;
+USHORT mwcxDLMIconLabelsWidth ;
+USHORT mwcyDLMIconLabelsHeight ;
+
+USHORT mwcxDLMFontLogMaxWidth ;
+USHORT mwcxDLMFontLogWidth ;
+USHORT mwcyDLMFontLogHeight ;
+
+BYTE mwfFontSizesSet ;
+LPSTR mwpTempObjBuff ;
+#endif
+
+
+
diff --git a/private/utils/ntbackup/inc/do_misc.h b/private/utils/ntbackup/inc/do_misc.h
new file mode 100644
index 000000000..dbe6dc880
--- /dev/null
+++ b/private/utils/ntbackup/inc/do_misc.h
@@ -0,0 +1,62 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: do_misc.h
+
+ Description: Miscellaneous functions used prior to calling loops engines
+
+
+ $Log: G:/UI/LOGFILES/DO_MISC.H_V $
+
+ Rev 1.5 04 Oct 1992 19:46:52 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.4 22 Jan 1992 16:58:00 JOHNWT
+removed UI_RequestTape
+
+ Rev 1.3 10 Jan 1992 12:39:38 JOHNWT
+added UI_DisplayBSDVCB
+
+ Rev 1.2 12 Dec 1991 11:07:34 JOHNWT
+removed UI_GetPasswordsAndLabels
+
+ Rev 1.1 03 Dec 1991 18:15:32 JOHNWT
+added UI_RequestTape
+
+ Rev 1.0 20 Nov 1991 19:41:38 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifndef _do_misc_h_
+#define _do_misc_h_
+
+#include "tpos.h"
+
+/* return values for do_*( ) */
+
+#define ABNORMAL_TERMINATION 1
+#define FILES_SKIPPED 2
+#define FILES_DIFFERENT 3
+
+INT16 UI_ExcludeInternalFiles( INT16 operation ) ;
+UINT16 UI_CheckOldTapePassword( struct DBLK *cur_vcb ) ;
+UINT16 UI_UpdateTpos( TPOS_PTR tpos, DBLK_PTR cur_vcb, BOOLEAN next_set_desired ) ;
+VOID UI_DisplayVCB( struct DBLK * vcb_ptr ) ;
+VOID UI_DisplayBSDVCB( BSD_PTR ) ;
+INT16 UI_ReplaceTape( CHAR_PTR drive_name ) ;
+INT16 UI_ReplaceBlankTape( CHAR_PTR drive_name ) ;
+INT16 UI_ReplaceForeignTape( CHAR_PTR drive_name ) ;
+INT16 UI_InsertTape( CHAR_PTR drive_name ) ;
+BOOLEAN UI_CheckUserAbort( UINT16 message ) ;
+VOID UI_CheckContinueDots( BOOLEAN_PTR dot_dot_mode, UINT16_PTR dot_dot_msg, UINT16 message ) ;
+INT16 UI_ProcessVCBatEOD( TPOS_PTR tpos, CHAR_PTR drive_name ) ;
+INT16 UI_PromptNextTape( TPOS_PTR tpos, DBLK_PTR cur_vcb, BOOLEAN valid_vcb_flag, UINT16 mode, CHAR_PTR tape_name, CHAR_PTR drive_name ) ;
+BOOLEAN UI_ReturnToTOC( UINT16 channel, BOOLEAN check_tape_change ) ;
+INT16 UI_HandleTapeReadError( CHAR_PTR drive_name ) ;
+INT16 TryToCreateFFRQueue( struct LIS *, INT16 ) ;
+VOID UI_ChkDispGlobalError ( VOID ) ;
+VOID UI_AddSpecialIncOrExc( BSD_PTR bsd, BOOLEAN IsInclude ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/dos_fs.h b/private/utils/ntbackup/inc/dos_fs.h
new file mode 100644
index 000000000..12fd061cf
--- /dev/null
+++ b/private/utils/ntbackup/inc/dos_fs.h
@@ -0,0 +1,279 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: dos_fs.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains the prototypes for the DOS
+ file system functions.
+
+ $Log: O:/LOGFILES/DOS_FS.H_V $
+ *
+ * Rev 1.10 03 Nov 1992 16:29:58 TIMN
+ * Added macros for processing streams
+ *
+ * Rev 1.9 21 Oct 1992 13:09:06 CARLS
+ * changed DOS_SetHandObjSizeLo to DOS_SetHandObjSize because size is now UINT64
+ *
+ * Rev 1.8 29 Sep 1992 17:47:28 CHUCKB
+ * Added s_info to prototype for DOSCompleteBlk().
+ *
+ * Rev 1.7 24 Sep 1992 12:00:48 TIMN
+ * Deleted references to f(x) FS_GetTotalSizeDBLK()
+ *
+ * Rev 1.6 24 Sep 1992 11:58:04 TIMN
+ * Updated DOS FileSys to support MTF v4.0 format (stream info structs in data streams)
+ *
+ * Rev 1.5 14 May 1992 17:03:24 STEVEN
+ * 40 format
+ *
+ * Rev 1.4 13 May 1992 16:50:02 STEVEN
+ * 40 FORMAT update
+ *
+ * Rev 1.3 13 Dec 1991 09:30:44 STEVEN
+ * move common functions to tabels
+ *
+ * Rev 1.2 10 Jul 1991 13:09:54 STEVEN
+ * Added DOS_GetSpecDBLKS().
+ *
+ * Rev 1.1 23 May 1991 16:46:12 BARRY
+ * Changes for FindFirst/Next to scan for dirs only
+ *
+ * Rev 1.0 09 May 1991 13:32:58 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ include list */
+
+#ifndef _dos_fs_h_
+#define _dos_fs_h_
+
+#include "fsys.h"
+
+
+typedef struct DOS_RESERVED_SH_STRUCT {
+ INT16 fhdl ; /* DOS file handle */
+ INT16 active ; /* is stream being processed */
+ STREAM_INFO sh ; /* DOS reserved stream info */
+} DOS_RESERVED_SH, *DOS_RESERVED_SH_PTR ;
+
+ /* sizeof FILE_HAND plus dos reserved struct */
+#define FS_SIZEOF_RESERVED_FILE_HAND \
+ ( sizeof(FILE_HAND_STRUCT) + sizeof(DOS_RESERVED_SH) )
+
+
+#define _DEREF_HandObjHandPtr(hand) ( (DOS_RESERVED_SH_PTR)((hand)->obj_hand.ptr) )
+
+#define _DOS_GetHandObjFileHandle(hand) ( (_DEREF_HandObjHandPtr(hand)->fhdl ) )
+#define _DOS_GetHandObjSize(hand) ( (_DEREF_HandObjHandPtr(hand)->sh.size ) )
+
+#define _DOS_SetHandObjFileHandle(hand,h) ( (_DEREF_HandObjHandPtr(hand)->fhdl ) = (h) )
+#define _DOS_SetHandObjSize(hand,v) ( (_DEREF_HandObjHandPtr(hand)->sh.size = (v) ) )
+
+#define _DOS_IsStrmBeingProcessed(hand) ( (_DEREF_HandObjHandPtr(hand)->active ) )
+#define _DOS_SetStrmProcessState(hand,v) ( (_DEREF_HandObjHandPtr(hand)->active ) = (v) )
+
+#define _DOS_WriteStrmInfo(hand) ( (_DEREF_HandObjHandPtr(hand)->active ) == FALSE )
+#define _DOS_ProcessData(hand) ( (_DEREF_HandObjHandPtr(hand)->active ) == FALSE )
+#define _DOS_SetProcessData(hand,v) ( (_DEREF_HandObjHandPtr(hand)->active ) = !(v) )
+
+
+INT16 DOS_AttachToDLE( FSYS_HAND fsh, /* I - File system handle */
+ GENERIC_DLE_PTR dle, /*I/O- drive to attach to. list element expanded */
+ CHAR_PTR u_name, /* I - user name NOT USED */
+ CHAR_PTR pswd); /* I - passowrd NOT USED */
+
+INT16 DOS_DetachDLE( FSYS_HAND fsh ); /* I - */
+
+INT16 DOS_AllocFileHand( FILE_HAND *file_hand ) ; /* I/O - */
+VOID DOS_MemsetFileHand( FILE_HAND *file_hand ) ; /* I/O - */
+
+INT16 DOS_CreateObj( FSYS_HAND fsh, /* I - File system to create object one */
+ DBLK_PTR dblk); /* I - Describes object to create */
+
+INT16 DOS_OpenObj( FSYS_HAND fsh, /* I - file system that the file is opened on */
+ FILE_HAND *hand, /* O - allocated handle */
+ DBLK_PTR dblk, /*I/O- describes the file to be opened */
+ OPEN_MODE mode); /* I - open mode */
+
+INT16 DOS_ReadObj( FILE_HAND hand, /* I - handle of object to read from */
+ CHAR_PTR buf, /* O - buffer to place data into */
+ UINT16 *size, /*I/O- Entry: size of buf; Exit: number of bytes read */
+ UINT16 *blk_size, /* O - Block size needed for next read */
+ STREAM_INFO_PTR s_info ) ; /*I/O- struct to place stream header info */
+
+
+INT16 DOS_WriteObj( FILE_HAND hand, /* I - handle of object to read from */
+ CHAR_PTR buf, /* O - buffer to place data into */
+ UINT16 *size, /*I/O- Entry: size of buf; Exit: number of bytes read */
+ UINT16 *blk_size, /* O - Block size need for next read */
+ STREAM_INFO_PTR s_info ) ; /*I/O- struct to place stream header info */
+
+INT16 DOS_VerObj( FILE_HAND hand, /* I - file handle to verify data with */
+ CHAR_PTR buf, /* I - buffer needed to perform verify */
+ CHAR_PTR data, /* I - data to verify against */
+ UINT16 *size, /*I/O- size of buffers / amount verified */
+ UINT16 *blk_size, /* O - minum size of block for next call */
+ STREAM_INFO_PTR s_info ) ; /*I/O- struct to place stream header info */
+
+
+INT16 DOS_CloseObj( FILE_HAND hand ); /* I - handle of object to close */
+
+INT16 DOS_DeleteObj( FSYS_HAND fsh,
+ DBLK_PTR dblk );
+
+INT16 DOS_FindFirst( FSYS_HAND fsh, /* I - file system handle */
+ DBLK_PTR dblk, /* O - pointer to place to put the dblk data */
+ CHAR_PTR sname, /* I - search name */
+ UINT16 obj_type); /* I - object type (all objs, dirs, etc.) */
+
+INT16 DOS_FindNext( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ); /* O - Discriptor block */
+
+INT16 DOS_GetObjInfo( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ); /*I/O- On entry it is minimal on exit Complete */
+
+INT16 DOS_VerObjInfo( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ); /* I - DBLK to compare OS against */
+
+INT16 DOS_ChangeDir( FSYS_HAND fsh, /* I - file system to changing directories on */
+ CHAR_PTR path, /* I - describes the path of the new directory */
+ INT16 psize); /* I - specifies the length of the path */
+
+INT16 DOS_UpDir( FSYS_HAND fsh ); /* I - file system to change directories in */
+
+INT16 DOS_GetCurrentPath( FSYS_HAND fsh, /* I - file system to get current path from */
+ CHAR_PTR path, /* O - buffer to place this path */
+ INT16 *size); /*I/O- size of buffer on entry & on exit */
+
+INT16 DOS_SeekObj( FILE_HAND hand, /* I - Opened object to seek into */
+ UINT32 *offset ); /*I/O- Offset to seek; Number of bytes actualy seeked */
+
+INT16 DOS_GetMaxSizeDBLK( FSYS_HAND fsh /* not used */ );
+
+INT16 DOS_GetBasePath( FSYS_HAND fsh, /* I - file system to get base path from */
+ CHAR_PTR full_path, /* O - buffer to place this path */
+ INT16 *size ); /*I/O- size of buffer on entry & on exit */
+
+INT16 DOS_GetCurrentDDB( FSYS_HAND fsh, /* I - file system to get DDB from */
+ DBLK_PTR dblk ); /* O - place to put the DDB data */
+
+INT16 DOS_SetObjInfo( FSYS_HAND fsh, /* I - file system handle */
+ DBLK_PTR dblk); /* I - data to write to disk */
+
+INT16 DOS_ModFnameFDB( FSYS_HAND fsh, /* I - File system handle */
+ BOOLEAN set_it, /* I - TRUE if setting file name, FALSE if getting */
+ DBLK_PTR dblk, /* I - Descriptor block to get file name from */
+ CHAR_PTR buf, /*I/O- file name to read (or to write) */
+ INT16 *size ) ; /*I/O- size buffer on entry and exit */
+
+INT16 DOS_ModPathDDB( FSYS_HAND fsh, /* I - File system handle */
+ BOOLEAN set_it , /* I - TRUE if setting path, FALSE if getting */
+ DBLK_PTR dblk, /* I - Descriptor block to get path from */
+ CHAR_PTR buf, /*I/O- path to read (or to write) */
+ INT16 *size ); /*I/O- size of buffer on entry and exit */
+
+INT16 DOS_GetOSFnameFDB( DBLK_PTR dblk , /* I - Descriptor block to get path from */
+ CHAR_PTR buf ); /*I/O- path to read (or to write) */
+
+INT16 DOS_GetOSPathDDB(
+ FSYS_HAND fsh, /* I - File System handle */
+ DBLK_PTR dblk , /* I - Descriptor block to get path from */
+ CHAR_PTR buf ); /*I/O- path to read (or to write) */
+
+INT16 DOS_GetFileVerFDB( DBLK_PTR dblk ,
+ UINT32 *version ) ;
+
+INT16 DOS_GetCdateDBLK( DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ); /*I/O- createion date to read (or to write) */
+
+INT16 DOS_GetMdateDBLK( DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ) ; /* O - modify date to write */
+
+INT16 DOS_ModBdateDBLK( BOOLEAN set_it , /* I - TRUE if setting creation date, FALSE if getting */
+ DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ) ; /*I/O- createion date to read (or to write) */
+
+INT16 DOS_ModAdateDBLK( BOOLEAN set_it , /* I - TRUE if setting creation date, FALSE if getting */
+ DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ) ; /*I/O- createion date to read (or to write) */
+
+UINT64 DOS_GetDisplaySizeDBLK( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ) ; /* I - Descriptor block to get generic data size for */
+
+INT16 DOS_GetOS_InfoDBLK( DBLK_PTR dblk, /* I - DBLK to get the info from */
+ CHAR_PTR os_info, /* O - Buffer to place data */
+ INT16 *size ); /*I/O- Buffer size / data length */
+
+
+INT16 DOS_ModAttribDBLK( BOOLEAN set_it ,
+ DBLK_PTR dblk ,
+ UINT32_PTR attr );
+
+
+INT16 DOS_GetObjTypeDBLK( DBLK_PTR dblk,
+ OBJECT_TYPE *type );
+
+
+INT16 DOS_GetActualSizeDBLK( FSYS_HAND fsh,
+ DBLK_PTR dblk ) ;
+
+INT16 DOS_SizeofFname( FSYS_HAND fsh, /* I - file system in use */
+ DBLK_PTR fdb ); /* I - dblk to get fname from */
+
+INT16 DOS_SizeofOSFname( FSYS_HAND fsh, /* I - file system in use */
+ DBLK_PTR fdb ) ; /* I - dblk to get fname from */
+
+INT16 DOS_SizeofPath( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR ddb ) ; /* I - DBLK to get path size from */
+
+INT16 DOS_SizeofOSPath( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR ddb ) ; /* I - DBLK to get path size from */
+
+INT16 DOS_SizeofOSInfo( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ); /* I - DBLK to get size of OS info for */
+
+
+INT16 DOS_PushMinDDB( FSYS_HAND fsh,
+ DBLK_PTR dblk );
+
+INT16 DOS_PopMinDDB( FSYS_HAND fsh ,
+ DBLK_PTR dblk );
+
+INT16 DOS_CreateFDB( FSYS_HAND fsh,
+ GEN_FDB_DATA_PTR dat ) ;
+
+INT16 DOS_CreateDDB( FSYS_HAND fsh,
+ GEN_DDB_DATA_PTR dat ) ;
+
+INT16 DOS_CreateIDB( FSYS_HAND fsh,
+ GEN_IDB_DATA_PTR dat ) ;
+
+VOID DOS_SetOwnerId( FSYS_HAND fsh, DBLK_PTR dblk, UINT32 id ) ;
+
+BOOLEAN DOS_ProcessDDB( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+INT16 DOS_ChangeIntoDDB( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+VOID DOS_GetRealBasePath( FSYS_HAND fsh, CHAR_PTR path ) ;
+
+
+INT16 DOS_GetSpecDBLKS(
+ FSYS_HAND fsh,
+ DBLK_PTR dblk,
+ INT32 *index );
+
+INT16 DOS_FindDrives( DLE_HAND hand, BE_CFG_PTR cfg, UINT32 fsys_mask );
+
+VOID DOS_GetVolName( GENERIC_DLE_PTR dle, CHAR_PTR buffer ) ;
+
+INT16 DOS_SizeofVolName( GENERIC_DLE_PTR dle ) ;
+
+BOOLEAN DOS_IsBlkComplete( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+INT16 DOS_CompleteBlk( FSYS_HAND fsh, DBLK_PTR dblk, CHAR_PTR buffer, UINT16 *size, STREAM_INFO_PTR sinfo ) ;
+VOID DOS_ReleaseBlk( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+VOID DOS_InitMakeData( FSYS_HAND fsh, INT16 blk_type, CREATE_DBLK_PTR data ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/doscom.h b/private/utils/ntbackup/inc/doscom.h
new file mode 100644
index 000000000..407eb6f30
--- /dev/null
+++ b/private/utils/ntbackup/inc/doscom.h
@@ -0,0 +1,170 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: doscom.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: DOS utility functions.
+
+
+ $Log: M:/LOGFILES/DOSCOM.H_V $
+ *
+ * Rev 1.6 08 Jul 1992 15:19:20 BARRY
+ * Added extended error stuff.
+ *
+ * Rev 1.5 24 Feb 1992 17:06:54 BARRY
+ * Fixed MakePath overflow problem.
+ *
+ * Rev 1.4 20 Dec 1991 09:12:54 STEVEN
+ * move common functions into tables
+ *
+ * Rev 1.3 25 Nov 1991 15:47:10 STEVEN
+ * need to reset DTA
+ *
+ * Rev 1.2 10 Sep 1991 18:18:56 DON
+ * types needed to be declared the same as WATCOM
+ *
+ * Rev 1.1 23 May 1991 16:46:32 BARRY
+ * Changes for FindFirst/Next to scan for dirs only
+ *
+ * Rev 1.0 09 May 1991 13:33:38 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef _doscom_h_
+#define _doscom_h_
+
+#define DOS_MAX_DSIZE 128
+#define DOS_MAX_FSIZE 13
+
+typedef struct DOS_DTA {
+ CHAR reserved[21];
+ UINT8 attr;
+ UINT16 time;
+ UINT16 date;
+ UINT32 size;
+ CHAR name[ DOS_MAX_FSIZE + 1 ];
+} DOS_DTA;
+
+
+
+/* The following macros convert a dos format date or time UINT16 into */
+/* a UINT16 suitable for placing in a DATE_TIME structure. */
+
+#define GET_DOS_YEAR( dos_date ) ( 1980 + ( (UINT16)(dos_date) >> 9 ) )
+#define GET_DOS_MONTH( dos_date ) (((dos_date) & 0x1ff) >> 5)
+#define GET_DOS_DAY( dos_date ) ( (dos_date) & 0x1f )
+#define GET_DOS_HOUR( dos_time ) ( ((UINT16)(dos_time)) >> 11 )
+#define GET_DOS_MINUTE( dos_time ) ( ( (dos_time) & 0x7e0 ) >> 5 )
+#define GET_DOS_SECOND( dos_time ) ( ( (dos_time) & 0x1f ) << 1 )
+
+
+#define DA_READONLY 0x01
+#define DA_HIDDEN 0x02
+#define DA_SYSTEM 0x04
+#define DA_DIRECTORY 0x10
+#define DA_MODIFIED 0x20
+
+#define DENY_NONE_MODE 0x40
+#define DENY_WRITE_MODE 0x20
+#define COMPATIBLE_MODE 0x00
+
+#define READ_ACCESS 0x00
+#define WRITE_ACCESS 0x01
+
+
+enum {
+ DOS_LOCUS_UNKNOWN = 1,
+ DOS_LOCUS_BLOCK_DEVICE,
+ DOS_LOCUS_NETWORK,
+ DOS_LOCUS_SERIAL,
+ DOS_LOCUS_MEMORY
+};
+
+enum {
+ DOS_ACTION_RETRY = 1,
+ DOS_ACTION_DELAY_RETRY,
+ DOS_ACTION_USER_INPUT,
+ DOS_ACTION_QUIT,
+ DOS_ACTION_EXIT,
+ DOS_ACTION_IGNORE,
+ DOS_ACTION_RETRY_USER
+};
+
+enum {
+ DOS_CLASS_OUT_OF_RESOURCE = 1,
+ DOS_CLASS_TEMP_SITUATION,
+ DOS_CLASS_AUTHORIZATION,
+ DOS_CLASS_INTERNAL,
+ DOS_CLASS_HARDWARE,
+ DOS_CLASS_SYSTEM,
+ DOS_CLASS_APP_ERROR,
+ DOS_CLASS_NOT_FOUND,
+ DOS_CLASS_BAD_FORMAT,
+ DOS_CLASS_LOCKED,
+ DOS_CLASS_MEDIA,
+ DOS_CLASS_ALREADY_EXISTS,
+ DOS_CLASS_UNKNOWN
+};
+
+INT16 GetExtendErrDOS( VOID ) ;
+
+VOID GetErrorClassDOS( UINT16 *extended_err,
+ UINT8 *error_class,
+ UINT8 *locus,
+ UINT8 *action );
+
+INT16 CreateFileDOS( CHAR_PTR path, UINT16 *hand ) ;
+
+INT16 CreateDirDOS( CHAR_PTR path );
+
+INT16 SetAttribDOS( CHAR_PTR path, INT16 attrib );
+
+INT16 DeleteFileDOS( CHAR_PTR path ) ;
+
+INT16 DeleteDirDOS( CHAR_PTR path );
+
+UINT16 ClusterAvailDOS( CHAR drive );
+
+INT16 FindFirstDOS( CHAR_PTR path, struct DOS_DTA * dta, UINT16 obj_type ) ;
+
+INT16 FindNextDOS( struct DOS_DTA * dta, UINT16 obj_type ) ;
+
+VOID * SetDTA( struct DOS_DTA * dta ) ;
+
+INT16 OpenFileDOS( CHAR_PTR path, UINT16 open_mode, UINT16 *hand, UINT32 *size ) ;
+
+INT16 CloseFileDOS( UINT16 hand ) ;
+
+INT16 LockFileDOS( UINT16 hand );
+
+INT16 UnlockFileDOS( UINT16 hand );
+
+INT16 GetExtendErrDOS( VOID ) ;
+
+INT16 ReadFileDOS( UINT16 hand, UINT32 pos, CHAR_PTR buf, UINT16 *size ) ;
+
+INT16 WriteFileDOS( UINT16 hand, CHAR_PTR buf, UINT16 *size ) ;
+
+INT16 SeekFileDOS( UINT16 hand, INT32 offset, INT16 mode );
+
+INT16 SetFileDateTimeDOS( UINT16 hand, UINT16 date, UINT16 time );
+
+UINT16 DOS_ValidFileName( CHAR_PTR name );
+
+VOID DOS_MakeName( CHAR_PTR dest, CHAR_PTR source, UINT8 os_id, UINT8 os_ver ) ;
+
+VOID DOS_MakePath( CHAR_PTR dest, INT16 destsize, CHAR_PTR source, INT16 leng, UINT8 os_id, UINT8 os_ver ) ;
+
+INT16 MatchFname( CHAR_PTR name1, CHAR_PTR name2 );
+
+BOOLEAN IsMappedDrive( CHAR drive ) ;
+
+BOOLEAN IsNetDrive( CHAR drive ) ;
+
+
+#endif
diff --git a/private/utils/ntbackup/inc/dosdblk.h b/private/utils/ntbackup/inc/dosdblk.h
new file mode 100644
index 000000000..8c1f49aca
--- /dev/null
+++ b/private/utils/ntbackup/inc/dosdblk.h
@@ -0,0 +1,74 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: dosdblk.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains the definition of the DOS
+ file and directory control blocks.
+
+
+ $Log: G:/LOGFILES/DOSDBLK.H_V $
+ *
+ * Rev 1.0 09 May 1991 13:31:12 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ include list */
+
+
+#ifndef dosdblk_h
+#define dosdblk_h
+
+
+#include "queues.h"
+#include "doscom.h"
+
+
+typedef struct DOS_FDB_INFO *DOS_FDB_INFO_PTR;
+
+typedef struct DOS_FDB_INFO {
+ BOOLEAN inuse_attrib ;
+ UINT16 handle ; /* set: DOS_CreateFile */
+ UINT16 os_name ;
+} DOS_FDB_INFO ;
+
+
+typedef struct DOS_DDB_INFO *DOS_DDB_INFO_PTR;
+
+typedef struct DOS_DDB_INFO {
+ BOOLEAN empty_attrib ;
+ CHAR path[ DOS_MAX_DSIZE ] ; /* build from "name" and current dir */
+ UINT16 os_path ;
+ UINT16 os_path_leng ;
+} DOS_DDB_INFO;
+
+
+
+typedef struct DOS_DBLK *DOS_DBLK_PTR;
+
+typedef struct DOS_DBLK {
+ UINT8 blk_type; /* values: DDB_ID, FDB_ID set: DOS */
+ COM_DBLK fs_reserved ;
+ DOS_DTA dta;
+ BOOLEAN os_info_complete; /* TRUE if GetObjInfo doesn't have to do anything */
+ UINT16 tape_attribs ;
+ union {
+ DOS_DDB_INFO d;
+ DOS_FDB_INFO f;
+ } b;
+} DOS_DBLK;
+
+
+typedef struct DOS_MIN_DDB *DOS_MIN_DDB_PTR;
+
+typedef struct DOS_MIN_DDB {
+ Q_ELEM q ;
+ UINT8 reserved[ 21 ] ; /* reserved for dos */
+ UINT16 psize ; /* size of path string */
+ CHAR_PTR path; /* build from "name" and current dir */
+} DOS_MIN_DDB;
+
+#endif
diff --git a/private/utils/ntbackup/inc/drive.h b/private/utils/ntbackup/inc/drive.h
new file mode 100644
index 000000000..8e3187d42
--- /dev/null
+++ b/private/utils/ntbackup/inc/drive.h
@@ -0,0 +1,135 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: drive.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This contains the internal drive definition structure. This
+ is a superset of the THW structure that is used by the
+ upper layers.
+
+
+ $Log: G:/LOGFILES/DRIVE.H_V $
+ *
+ * Rev 1.11 17 Mar 1993 14:57:34 GREGG
+ * This is Terri Lynn. Added Gregg's changes to switch a tape drive's block mode
+ * to match the block size of the current tape
+ *
+ * Rev 1.10 09 Nov 1992 10:49:14 GREGG
+ * Added macro for checking Fast EOD drive feature.
+ *
+ * Rev 1.9 05 Apr 1992 19:15:46 GREGG
+ * Added macro to check for TDI_REV_FMK drive feature.
+ *
+ * Rev 1.8 08 Feb 1992 14:37:06 GREGG
+ * Changed INT16 lst_oper element in drive structure to BOOLEAN force_rewind,
+ * since this is what the lst_oper field had been reduced to anyway.
+ *
+ * Rev 1.7 17 Oct 1991 01:17:02 GREGG
+ * BIGWHEEL - 8200SX - Added support macros.
+ *
+ * Rev 1.6 14 Oct 1991 10:58:14 GREGG
+ * Added TF_PollDrive state st_BSTAT (busy statusing).
+ *
+ * Rev 1.5 28 Sep 1991 21:45:24 GREGG
+ * Added two booleans to poll_stuff.
+ *
+ * Rev 1.4 09 Sep 1991 21:19:24 GREGG
+ * Added elements to drive structure for TF_PollDrive.
+ *
+ * Rev 1.3 15 Jul 1991 14:54:58 NED
+ * Removed unnecessary include.
+ *
+ * Rev 1.2 05 Jun 1991 19:15:48 NED
+ * changed include list
+ *
+ * Rev 1.1 10 May 1991 17:09:54 GREGG
+ * Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:13:04 GREGG
+Initial revision.
+
+**/
+#ifndef _DRIVE_STUFF
+#define _DRIVE_STUFF
+
+#include "thw.h"
+#include "dblks.h"
+#include "tloc.h"
+#include "buffman.h"
+#include "tflstats.h"
+/* $end$ include list */
+
+typedef struct {
+ VOID_PTR channel ;
+ INT16 state ;
+ BOOLEAN no_tape_reported ;
+ BOOLEAN reentered ;
+ BOOLEAN first_status ;
+ INT blk_size_idx ;
+ UINT16 def_blk_size ;
+} POLL_STUFF ;
+
+
+typedef struct {
+ THW thw_inf ; /* Tape Hardware Structure */
+ Q_HEADER inproc_q ; /* Buffers that have been sent to the drive */
+ BOOLEAN trans_started ;/* Transfer was started */
+ BOOLEAN vcb_valid ; /* Is the DBLK VCB below valid */
+ BOOLEAN tape_mounted ; /* Is the tape mounted */
+ DBLK cur_vcb ; /* Current VCB */
+ BUF_PTR hold_buff ; /* For watches */
+ UINT32 pos_inf ; /* current tape position */
+ TLOC cur_pos ; /* Current Tape Location */
+ INT16 drv_hdl ; /* Drive handle ( TFL's ) */
+ UINT16 drv_no ; /* Drive Number ( TFL's ) */
+ BOOLEAN force_rewind ; /* force rewind of current tape */
+ TF_STATS cur_stats ; /* Current Statistics */
+ UINT16 last_cur_fmt ; /* save index into Current format (r/w) */
+ VOID_PTR last_fmt_env ; /* save Current Environment Pointer for Channel */
+ POLL_STUFF poll_stuff ; /* stuff for TF_PollDrive */
+} DRIVE, *DRIVE_PTR ;
+
+/* Position Stuff */
+#define SupportBlkPos( x ) ( (x)->thw_inf.drv_info.drv_features & TDI_FAST_NBLK )
+#define SupportRevFmk( x ) ( (x)->thw_inf.drv_info.drv_features & TDI_REV_FMK )
+#define SupportFastEOD( x ) ( (x)->thw_inf.drv_info.drv_features & TDI_FAST_EOD )
+#define SupportSXShowBlk( x ) ( (x)->thw_inf.drv_info.drv_features & TDI_SHOW_BLK )
+#define SupportSXFindBlk( x ) ( (x)->thw_inf.drv_info.drv_features & TDI_FIND_BLK )
+#define CurPBAofVCB( x ) ( (x)->cur_pos.pba_vcb )
+#define DriveAttributes( x ) ( (x)->thw_inf.drv_info.drv_features )
+
+/* State Definitions for TF_PollDrive */
+/* Note: These are listed here because they are referenced in MountTape */
+
+#define st_SSDC 0 /* Same Status, Different Call */
+#define st_BSTAT 1 /* Busy STATusing */
+#define st_BMNT 2 /* Busy MouNTing */
+#define st_BREW 3 /* Busy REWinding */
+#define st_BREAD 4 /* Busy READing */
+#define st_HOSED 5 /* Guess */
+#define st_CLOSED 6 /* Drive not being polled */
+
+/* Current Position Information */
+#define AT_EOD 0x00000001 /* At End of Data */
+#define AT_EOS 0x00000002 /* At End of A Set */
+#define AT_EOM 0x00000004 /* At End of Media */
+#define AT_BOT 0x00000008 /* Beginning of Tape */
+#define AT_FMK 0x00000010 /* At A FileMark */
+#define NO_STAT 0x00000020 /* Don't Status this drive */
+#define REW_CLOSE 0x00000040 /* Rewind on Close */
+#define DONT_CLOSE 0x00000080 /* Don't Close this drive */
+#define AT_MOS 0x00000100 /* In the Middle of Set */
+#define TAPE_FULL 0x00000200 /* The current tape in the drive is full */
+#define WATCHED 0x00000400 /* The driver was watched */
+#define TAPE_ERR 0x00000800 /* There was an error on this tape */
+#define SHORT_SET 0x00001000 /* This Set occupies Less than a buffer */
+
+/* Usage Macros */
+#define SetPosBit( x, b ) ( (x)->pos_inf |= (b) )
+#define ClrPosBit( x, b ) ( (x)->pos_inf &= ~(b) )
+#define IsPosBitSet( x, b ) ( (x)->pos_inf & (b) )
+
+#endif
diff --git a/private/utils/ntbackup/inc/drvinf.h b/private/utils/ntbackup/inc/drvinf.h
new file mode 100644
index 000000000..9109a37a5
--- /dev/null
+++ b/private/utils/ntbackup/inc/drvinf.h
@@ -0,0 +1,113 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-91
+
+ Name: drvinf.h
+
+ Description: Structure that describes a drives features.
+
+ $Log: Q:/LOGFILES/DRVINF.H_V $
+
+ Rev 1.12 16 Apr 1993 14:22:04 chrish
+Added define for HW compression.
+
+ Rev 1.11 17 Mar 1993 15:06:02 TERRI
+Added change block size define
+
+ Rev 1.10 24 Feb 1993 15:26:26 GREGG
+Added TDI_SHORT_ERASE and TDI_LONG_ERASE feature bits.
+
+ Rev 1.9 12 Feb 1993 09:00:12 STEVEN
+added TID_FORMAT
+
+ Rev 1.8 08 Dec 1992 08:16:10 IAN
+Added defines for DRV_??? structure elements.
+
+ Rev 1.7 29 Sep 1992 14:11:00 DON
+added TDI_LOADER feature bit
+
+ Rev 1.6 14 Mar 1992 17:41:54 CLIFF
+Moved controller id to the dil hardware structure.
+
+ Rev 1.5 12 Mar 1992 21:02:46 CLIFF
+Added a controller id field.
+
+ Rev 1.4 15 Jan 1992 16:08:02 CLIFF
+Added a second firmware number
+
+ Rev 1.3 10 Jan 1992 14:43:38 CLIFF
+Added field for vendor specified id field
+
+ Rev 1.2 10 Oct 1991 11:36:34 STEVEN
+added retension type
+
+ Rev 1.1 17 Jul 1991 13:55:46 JOHNS
+Updated to current source from ENG3:SYS3.
+
+**/
+
+#ifndef DRVINF
+
+#define DRVINF
+
+#define DRV_VENDOR_LEN 8
+#define DRV_PRODUCT_LEN 16
+#define DRV_FIRMREV_LEN 4
+#define DRV_FIRMNUM_LEN 5
+#define DRV_SPEC_ID_LEN 16
+
+
+typedef struct {
+ CHAR drv_vendor[DRV_VENDOR_LEN+1] ; /* contains the vendor information */
+ CHAR drv_product[DRV_PRODUCT_LEN+1] ; /* contains the product description */
+ CHAR drv_firmnum[DRV_FIRMNUM_LEN+1] ; /* contains the firmware/product number */
+ CHAR drv_firmrev[DRV_FIRMREV_LEN+1] ; /* contains the firmware revision number */
+ CHAR drv_spec_id[DRV_SPEC_ID_LEN+1] ; /* vendor specified unique id */
+ UINT16 drv_media ; /* media type for this drive */
+ UINT16 drv_bsize ; /* contains the block size */
+ UINT32 drv_features ; /* what this drive supports */
+ UINT16 drv_addr ; /* The address of the tape */
+} DRV_INF, *DRV_INF_PTR ;
+
+
+/* The following define the attributes of the given drive */
+
+#define TDI_FAST_FMK 0x00000001 /* Fast filemark search */
+#define TDI_FAST_NBLK 0x00000002 /* Position to any block on tape */
+#define TDI_FAST_EOD 0x00000004 /* Fast position to End of Data */
+#define TDI_REV_FMK 0x00000008 /* Forward search for end of data */
+#define TDI_OVERWRITE 0x00000010 /* Overwrite */
+#define TDI_DIR_TRACK 0x00000020 /* Directory Track Support */
+#define TDI_BLK_POS 0x00000040 /* Returns Block Position */
+#define TDI_FMK 0x00000080 /* Filemarks supported */
+#define TDI_NODATA 0x00000100 /* No Data exceptions supported */
+#define TDI_NODATA_FMK 0x00000200 /* No Data exceptions supported when
+ spacing to filemark */
+#define TDI_RETENSION 0x00000800 /* the drive support retension */
+#define TDI_UNLOAD 0x00000400 /* Load unload command support */
+#define TDI_REAL_BLK_POS 0x00001000 /* Real Block Positioning required - drive does
+ not auto compensate for ECC, etc. */
+#define TDI_SHOW_BLK 0x00002000 /* SHOW Special Block capability */
+#define TDI_FIND_BLK 0x00004000 /* FIND Special Block capability */
+#define TDI_MODE_CHANGE 0x00008000 /* Supports FFR mode changing between
+ FFR and non FFR modes */
+#define TDI_LOADER 0x00010000 /* Loader Device Capability */
+#define TDI_FORMAT 0x00020000 /* Format Tape Capability (DC2000) */
+
+#define TDI_SHORT_ERASE 0x00040000 /* Supports Short Erase */
+#define TDI_LONG_ERASE 0x00080000 /* Supports Long (Secure) Erase */
+
+#define TDI_CHNG_BLK_SIZE 0x00100000 /* Supports multiple block sizes */
+
+#define TDI_DRV_COMPRESSION 0x00200000 /* chs:04-16-93 Supports hardware compression */
+#define TDI_DRV_COMPRESS_ON 0x00400000 /* chs:04-16-93 compression currently turned on */
+#define TDI_DRV_COMPRES_INIT 0x00800000 /* chs:04-16-93 compression on at init */
+
+/* Media Types */
+
+#define CARTRIDGE 0
+#define CASSETTE 1
+#define T8MM 2 /* formerly EXABYTE */
+#define T4MM 3 /* formerly DAT */
+#define UNKNOWN 0xffff
+
+#endif
diff --git a/private/utils/ntbackup/inc/ems.h b/private/utils/ntbackup/inc/ems.h
new file mode 100644
index 000000000..3483ba4cd
--- /dev/null
+++ b/private/utils/ntbackup/inc/ems.h
@@ -0,0 +1,45 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: ems.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Defines all EMS constants and function prototypes
+
+ Location:
+
+
+ $Log: G:/LOGFILES/EMS.H_V $
+ *
+ * Rev 1.0 09 May 1991 13:32:42 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+#ifndef EMS_H
+
+#define EMS_H
+
+#include "StdTypes.H"
+/*
+ Define EMS functions
+*/
+#define EMS_INIT 0x40
+#define EMS_GET_FRAME_ADDRESS 0x41
+#define EMS_GET_PAGE_COUNT 0x42
+#define EMS_ALLOCATE_PAGES 0x43
+#define EMS_MAP_PAGE 0x44
+#define EMS_DEALLOCATE_PAGES 0x45
+#define EMS_GET_EMM_VERSION 0x46
+#define EMS_SAVE_PAGE_MAP 0x47
+#define EMS_RESTORE_PAGE_MAP 0x48
+
+#define EMS_VECTOR 0x67
+
+#define EMS_PAGE_SIZE ( 1024 * 16 )
+
+UINT16 EMSFunction( UINT8, UINT16, UINT16, UINT16_PTR, UINT16 ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/ems_fs.h b/private/utils/ntbackup/inc/ems_fs.h
new file mode 100644
index 000000000..d3813d0eb
--- /dev/null
+++ b/private/utils/ntbackup/inc/ems_fs.h
@@ -0,0 +1,471 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: ems_fs.h
+
+ Description: This file contains the prototypes for the NTFS
+ file system functions.
+
+ $Log: M:/LOGFILES/NTFS_FS.H_V $
+
+
+**/
+
+#include "fsys.h"
+#include "queues.h"
+
+
+//EMS String Aray
+extern CHAR_PTR gszEmsStringList[] ;
+#define EMS_String( id ) gszEmsStringList[id]
+#define MDB_Bricked 0
+#define MDB_Monolithic 1
+#define DSA 2
+#define Mailboxes 3
+#define Public_Folders 4
+
+
+typedef struct _EMS_FSYS_RESERVED {
+ UINT16 file_scan_mode ;
+ CHAR_PTR work_buf ;
+ UINT16 work_buf_size ;
+ BOOLEAN work_buf_in_use ;
+ XCHANGE_PATHS paths;
+ CHAR CheckpointFilePath[256];
+ CHAR LogPath[256];
+ CHAR jet_rstmap[256 * 3 * 2];
+ INT map_size ;
+ CHAR BackupLogPath[256];
+ ULONG low_log;
+ ULONG high_log;
+ VOID_PTR service_restart_list ;
+ INT service_restart_list_size ;
+ BOOLEAN attach_failed ;
+ PVOID restore_context ;
+
+} EMS_FSYS_RESERVED, *EMS_FSYS_RESERVED_PTR ;
+
+
+#define REG_SUBKEY_MDB_PRIVATE TEXT("SYSTEM\\CurrentControlSet\\Services\\MSExchangeIS\\ParametersPrivate")
+#define REG_SUBKEY_MDB_BASE TEXT("SYSTEM\\CurrentControlSet\\Services\\MSExchangeIS")
+#define REG_SUBKEY_MDB_RIP TEXT("SYSTEM\\CurrentControlSet\\Services\\MSExchangeIS\\Restore in Progress")
+#define REG_VALUE_MDB_PRIVATE TEXT("DB Path")
+#define REG_SUBKEY_MDB_PUBLIC TEXT("SYSTEM\\CurrentControlSet\\Services\\MSExchangeIS\\ParametersPublic")
+#define REG_VALUE_MDB_PUBLIC TEXT("DB Path")
+#define REG_SUBKEY_MDB_SYSTEM TEXT("SYSTEM\\CurrentControlSet\\Services\\MSExchangeIS\\ParametersSystem")
+#define REG_VALUE_MDB_SYSTEM TEXT("DB System Path")
+#define REG_VALUE_MDB_LOGDIR TEXT("DB Log Path")
+#define REG_VALUE_DISSALOW TEXT("Disallow diff/inc backup")
+#define REG_VALUE_CIRCULAR TEXT("Circular Logging")
+#define REG_SUBKEY_DSA TEXT("SYSTEM\\CurrentControlSet\\Services\\MSExchangeDS\\Parameters")
+#define REG_SUBKEY_DSA_BASE TEXT("SYSTEM\\CurrentControlSet\\Services\\MSExchangeDS")
+#define REG_SUBKEY_DSA_RIP TEXT("SYSTEM\\CurrentControlSet\\Services\\MSExchangeDS\\Restore in Progress")
+#define REG_SUBKEY_RIP TEXT("Restore in Progress")
+#define REG_VALUE_DB_PATH TEXT("DSA Database file")
+#define REG_VALUE_DSA_LOGDIR TEXT("Database log files path")
+#define REG_VALUE_DSA_SYSTEM TEXT("EDB system file")
+#define REG_VALUE_RIP_CPFILE TEXT("CheckpointFilePath")
+#define REG_VALUE_RIP_LOG_PATH TEXT("LogPath")
+#define REG_VALUE_RIP_RSTMAP TEXT("JET_RstMap")
+#define REG_VALUE_RIP_MAPSIZE TEXT("JET_RstMap Size")
+#define REG_VALUE_RIP_BKUPLOG TEXT("BackupLogPath")
+#define REG_VALUE_RIP_LOGLOW TEXT("LowLog Number")
+#define REG_VALUE_RIP_LOGHIGH TEXT("HighLog Number")
+#define SERVICE_MESSAGE_DB TEXT("MSExchangeIS")
+#define SERVICE_MAD TEXT("MSExchangeSA")
+#define SERVICE_DIRECTORY_SYNC TEXT("MSExchangeDXA")
+#define SERVICE_MESSAGE_TRANS TEXT("MSExchangeMTA")
+#define SERVICE_DIRECTORY TEXT("MSExchangeDS")
+
+
+CHAR_PTR EMS_BuildMungedName( FSYS_HAND fsh, CHAR_PTR new_path, CHAR_PTR fname ) ;
+
+INT16 EMS_ConvertJetError( INT status ) ;
+
+INT16 EMS_LoadRIP( CHAR_PTR server_name,
+ INT type,
+ CHAR_PTR CheckpointFilePath,
+ CHAR_PTR LogPath,
+ CHAR_PTR jet_rstmap,
+ INT_PTR map_size,
+ CHAR_PTR BackupLogPath,
+ INT_PTR low_log,
+ INT_PTR high_log ) ;
+
+INT16 EMS_SaveRIP( CHAR_PTR server_name,
+ INT type,
+ CHAR_PTR CheckpointFilePath,
+ CHAR_PTR LogPath,
+ CHAR_PTR jet_rstmap,
+ INT_PTR map_size,
+ CHAR_PTR BackupLogPath,
+ INT_PTR low_log,
+ INT_PTR high_log ) ;
+
+INT16 EMS_DeleteRIP( CHAR_PTR server_name,
+ INT type ) ;
+
+INT EMS_GetValFromReg(
+CHAR_PTR machine,
+CHAR_PTR key_name,
+CHAR_PTR value_name,
+CHAR_PTR buffer,
+INT buf_size ) ;
+
+INT EMS_SetValFromReg(
+CHAR_PTR machine,
+CHAR_PTR key_name,
+CHAR_PTR value_name,
+CHAR_PTR buffer );
+
+BOOLEAN EMS_IsServiceRunning( CHAR_PTR server_name, CHAR_PTR servic_name ) ;
+
+VOID EMS_ZeroCheckSum( FILE_HAND hand ) ;
+VOID EMS_CalcCheckSum( FILE_HAND hand, BYTE_PTR buf, INT size ) ;
+INT16 EMS_LoadNameList( FSYS_HAND fsh, FILE_HAND hand, INT list_type );
+
+INT16 EMS_AttachToDLE( FSYS_HAND fsh, /* I - File system handle */
+ GENERIC_DLE_PTR dle, /*I/O- drive to attach to. list element expanded */
+ CHAR_PTR u_name, /* I - user name NOT USED */
+ CHAR_PTR pswd); /* I - passowrd NOT USED */
+
+INT16 EMS_DetachDLE( FSYS_HAND fsh ); /* I - */
+
+INT32 EMS_EndOperationOnDLE( FSYS_HAND fsh ); /* I - */
+
+INT16 EMS_CreateObj( FSYS_HAND fsh, /* I - File system to create object one */
+ DBLK_PTR dblk); /* I - Describes object to create */
+
+INT16 EMS_OpenObj( FSYS_HAND fsh, /* I - file system that the file is opened on */
+ FILE_HAND *hand, /* O - allocated handle */
+ DBLK_PTR dblk, /*I/O- describes the file to be opened */
+ OPEN_MODE mode); /* I - open mode */
+
+INT16 EMS_ReadObj( FILE_HAND hand, /* I - handle of object to read from */
+ BYTE_PTR buf, /* O - buffer to place data into */
+ UINT16 *size, /*I/O- Entry: size of buf; Exit: number of bytes read */
+ UINT16 *blk_size, /* O - Block size needed for next read */
+ STREAM_INFO_PTR s_info); /* O - Stream information for the data returned */
+
+
+INT16 EMS_WriteObj( FILE_HAND hand, /* I - handle of object to read from */
+ BYTE_PTR buf, /* O - buffer to place data into */
+ UINT16 *size, /*I/O- Entry: size of buf; Exit: number of bytes read */
+ UINT16 *blk_size, /* O - Block size need for next read */
+ STREAM_INFO_PTR s_info); /* I - Stream information for the data passed in */
+
+INT16 EMS_VerObj( FILE_HAND hand, /* I - file handle to verify data with */
+ BYTE_PTR buf, /* I - buffer needed to perform verify */
+ BYTE_PTR data, /* I - data to verify against */
+ UINT16 *size, /*I/O- size of buffers / amount verified */
+ UINT16 *blk_size, /* O - minum size of block for next call */
+ STREAM_INFO_PTR s_info); /* I - Stream information for the data passed in */
+
+
+INT16 EMS_CloseObj( FILE_HAND hand ); /* I - handle of object to close */
+
+INT16 EMS_DeleteObj( FSYS_HAND fsh,
+ DBLK_PTR dblk );
+
+INT16 EMS_FindFirst( FSYS_HAND fsh, /* I - file system handle */
+ DBLK_PTR dblk, /* O - pointer to place to put the dblk data */
+ CHAR_PTR sname, /* I - search name */
+ UINT16 obj_type); /* I - object type (all objs, dirs, etc.) */
+
+INT16 EMS_FindNext( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ); /* O - Discriptor block */
+
+INT16 EMS_GetObjInfo( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ); /*I/O- On entry it is minimal on exit Complete */
+
+INT16 EMS_VerObjInfo( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ); /* I - DBLK to compare OS against */
+
+INT16 EMS_ChangeDir( FSYS_HAND fsh, /* I - file system to changing directories on */
+ CHAR_PTR path, /* I - describes the path of the new directory */
+ INT16 psize); /* I - specifies the length of the path */
+
+INT16 EMS_UpDir( FSYS_HAND fsh ); /* I - file system to change directories in */
+
+INT16 EMS_GetCurrentPath( FSYS_HAND fsh, /* I - file system to get current path from */
+ CHAR_PTR path, /* O - buffer to place this path */
+ INT16 *size); /*I/O- size of buffer on entry & on exit */
+
+INT16 EMS_SeekObj( FILE_HAND hand, /* I - Opened object to seek into */
+ UINT32 *offset ); /*I/O- Offset to seek; Number of bytes actualy seeked */
+
+INT16 EMS_GetMaxSizeDBLK( FSYS_HAND fsh /* not used */ );
+
+INT16 EMS_GetCurrentDDB( FSYS_HAND fsh, /* I - file system to get DDB from */
+ DBLK_PTR dblk ); /* O - place to put the DDB data */
+
+INT16 EMS_SetObjInfo( FSYS_HAND fsh, /* I - file system handle */
+ DBLK_PTR dblk); /* I - data to write to disk */
+
+INT16 EMS_ModFnameFDB( FSYS_HAND fsh, /* I - File system handle */
+ BOOLEAN set_it, /* I - TRUE if setting file name, FALSE if getting */
+ DBLK_PTR dblk, /* I - Descriptor block to get file name from */
+ CHAR_PTR buf, /*I/O- file name to read (or to write) */
+ INT16 *size ) ; /*I/O- size buffer on entry and exit */
+
+INT16 EMS_ModPathDDB( FSYS_HAND fsh, /* I - File system handle */
+ BOOLEAN set_it , /* I - TRUE if setting path, FALSE if getting */
+ DBLK_PTR dblk, /* I - Descriptor block to get path from */
+ CHAR_PTR buf, /*I/O- path to read (or to write) */
+ INT16 *size ); /*I/O- size of buffer on entry and exit */
+
+INT16 EMS_GetOSFnameFDB( DBLK_PTR dblk , /* I - Descriptor block to get path from */
+ CHAR_PTR buf ); /*I/O- path to read (or to write) */
+
+INT16 EMS_GetOSPathDDB(
+ FSYS_HAND fsh, /* I - File System handle */
+ DBLK_PTR dblk , /* I - Descriptor block to get path from */
+ CHAR_PTR buf ); /*I/O- path to read (or to write) */
+
+INT16 EMS_GetFileVerFDB( DBLK_PTR dblk ,
+ UINT32 *version ) ;
+
+INT16 EMS_GetCdateDBLK( DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ); /*I/O- createion date to read (or to write) */
+
+INT16 EMS_GetMdateDBLK( DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ) ; /* O - modify date to write */
+
+INT16 EMS_ModBdateDBLK( BOOLEAN set_it , /* I - TRUE if setting creation date, FALSE if getting */
+ DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ) ; /*I/O- createion date to read (or to write) */
+
+INT16 EMS_ModAdateDBLK( BOOLEAN set_it , /* I - TRUE if setting creation date, FALSE if getting */
+ DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ) ; /*I/O- createion date to read (or to write) */
+
+UINT64 EMS_GetDisplaySizeDBLK( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ) ; /* I - Descriptor block to get generic data size for */
+
+INT16 EMS_GetOS_InfoDBLK( DBLK_PTR dblk, /* I - DBLK to get the info from */
+ BYTE_PTR os_info, /* O - Buffer to place data */
+ INT16 *size ); /*I/O- Buffer size / data length */
+
+
+INT16 EMS_ModAttribDBLK( BOOLEAN set_it ,
+ DBLK_PTR dblk ,
+ UINT32_PTR attr );
+
+
+INT16 EMS_GetObjTypeDBLK( DBLK_PTR dblk,
+ OBJECT_TYPE *type );
+
+
+INT16 EMS_GetActualSizeDBLK( FSYS_HAND fsh,
+ DBLK_PTR dblk ) ;
+
+INT16 EMS_SizeofFname( FSYS_HAND fsh, /* I - file system in use */
+ DBLK_PTR fdb ); /* I - dblk to get fname from */
+
+INT16 EMS_SizeofOSFname( FSYS_HAND fsh, /* I - file system in use */
+ DBLK_PTR fdb ) ; /* I - dblk to get fname from */
+
+INT16 EMS_SizeofPath( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR ddb ) ; /* I - DBLK to get path size from */
+
+INT16 EMS_SizeofOSPath( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR ddb ) ; /* I - DBLK to get path size from */
+
+INT16 EMS_SizeofOSInfo( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ); /* I - DBLK to get size of OS info for */
+
+
+INT16 EMS_PushMinDDB( FSYS_HAND fsh,
+ DBLK_PTR dblk );
+
+INT16 EMS_PopMinDDB( FSYS_HAND fsh ,
+ DBLK_PTR dblk );
+
+INT16 EMS_CreateFDB( FSYS_HAND fsh,
+ GEN_FDB_DATA_PTR dat ) ;
+
+INT16 EMS_CreateDDB( FSYS_HAND fsh,
+ GEN_DDB_DATA_PTR dat ) ;
+
+INT16 EMS_CreateIDB( FSYS_HAND fsh,
+ GEN_IDB_DATA_PTR dat ) ;
+
+VOID EMS_SetOwnerId( FSYS_HAND fsh, DBLK_PTR dblk, UINT32 id ) ;
+
+BOOLEAN EMS_ProcessDDB( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+INT16 EMS_ChangeIntoDDB( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+INT16 EMS_FindClose( FSYS_HAND fsh,
+ DBLK_PTR dblk ) ;
+
+INT16 EMS_GetSpecDBLKS(
+ FSYS_HAND fsh,
+ DBLK_PTR dblk,
+ INT32 *index );
+
+INT16 EMS_DeviceDispName(
+GENERIC_DLE_PTR dle,
+CHAR_PTR dev_name,
+INT16 size,
+INT16 type ) ;
+
+INT16 EMS_FindDrives( DLE_HAND hand, BE_CFG_PTR cfg, UINT32 fsys_mask );
+
+VOID EMS_RemoveDLE( GENERIC_DLE_PTR dle ) ;
+
+VOID EMS_GetVolName( GENERIC_DLE_PTR dle, CHAR_PTR buffer ) ;
+
+INT16 EMS_SizeofVolName( GENERIC_DLE_PTR dle ) ;
+
+VOID EMS_EmptyFindHandQ( FSYS_HAND fsh ) ;
+
+INT16 EMS_EnumSpecFiles(
+ GENERIC_DLE_PTR dle,
+ UINT16 *index,
+ CHAR_PTR *path,
+ INT16 *psize,
+ CHAR_PTR *fname ) ;
+
+INT16 EMS_GetSpecDBLKS(
+ FSYS_HAND fsh,
+ DBLK_PTR dblk,
+ INT32 *index );
+
+VOID EMS_InitMakeData( FSYS_HAND fsh, INT16 blk_type, CREATE_DBLK_PTR data ) ;
+BOOLEAN EMS_IsBlkComplete( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+INT16 EMS_CompleteBlk( FSYS_HAND fsh, DBLK_PTR dblk, BYTE_PTR buffer, UINT16 *size, STREAM_INFO *sinfo ) ;
+VOID EMS_ReleaseBlk( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+
+INT16 EMS_DupBlk( FSYS_HAND fsh, DBLK_PTR db_org, DBLK_PTR db_dup );
+
+INT16 EMS_SpecExcludeObj( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR ddb, /* I - Descriptor block of ddb */
+ DBLK_PTR fdb ) ; /* I - Descriptor block of fdb */
+
+
+INT16 EMS_SetupPathInDDB(
+ FSYS_HAND fsh,
+ DBLK_PTR ddblk,
+ CHAR_PTR cur_dir,
+ CHAR_PTR sub_dir_name,
+ UINT16 buf_req_size ) ;
+
+INT16 EMS_SetupFileNameInFDB( FSYS_HAND fsh,
+ DBLK_PTR dblk,
+ CHAR_PTR fname,
+ UINT16 bufMinSize );
+
+INT16 EMS_SetupWorkPath(
+ FSYS_HAND fsh,
+ CHAR_PTR cur_dir,
+ CHAR_PTR sname,
+ CHAR_PTR *path_string ) ;
+
+VOID EMS_ReleaseWorkPath( FSYS_HAND fsh ) ;
+
+VOID EMS_FixPath( CHAR_PTR path, INT16_PTR size, INT16 fname_size ) ;
+
+//
+// Private Registry API functions
+//
+
+// Call backup for backup operations and both for restore operations.
+
+INT REG_AssertBackupPrivilege( VOID );
+INT REG_AssertRestorePrivilege( VOID );
+
+// Given a drive, path, and file name I'll tell you if it
+// is an active registry file.
+
+INT REG_IsRegistryFile(
+ GENERIC_DLE_PTR dle,
+ CHAR_PTR FileSpec );
+
+INT REG_IsEventFile(
+ GENERIC_DLE_PTR dle,
+ CHAR_PTR FileSpec,
+ CHAR_PTR buffer );
+
+// Called by the file system to determine if/where the
+// registry is for each drive.
+// Everyone else can get the info from the DLE's.
+
+INT REG_GetRegistryPath(
+CHAR *Machine,
+CHAR Drive,
+CHAR_PTR Path,
+INT *PathSize );
+
+// Try to backup up an active registry file.
+
+INT REG_BackupRegistryFile(
+GENERIC_DLE_PTR dle,
+CHAR_PTR RegFileSpec,
+CHAR_PTR TempFileSpec );
+
+// Most dangerous of all. Try to restore an active registry file.
+
+INT REG_RestoreRegistryFile(
+GENERIC_DLE_PTR dle,
+CHAR_PTR RegFileSpec,
+CHAR_PTR NewFileSpec,
+CHAR_PTR OldFileSpec );
+
+INT REG_IsCurDirRegistryPath(
+IN FSYS_HAND fsh ) ;
+
+VOID REG_MoveActiveRenameKey(
+GENERIC_DLE_PTR dle,
+CHAR_PTR RegFileSpec ) ;
+
+
+#define EMS_GetRegistryPath( dle ) ((dle)->info.ntfs->registry_path )
+#define EMS_GetRegistryPathSize( dle ) ((dle)->info.ntfs->registry_path_size )
+
+
+UINT32 EMS_MSoftToMayn( UINT32 msoftID );
+UINT32 EMS_MaynToMSoft( UINT32 maynID );
+
+INT16 EMS_FillOutDBLK( FSYS_HAND fsh,
+ DBLK_PTR dblk,
+ WIN32_FIND_DATA *find_data );
+
+CHAR_PTR EMS_MakeTempName( CHAR_PTR path,
+ CHAR_PTR prefix) ;
+
+
+INT16 EMS_TranslateBackupError( DWORD backupError );
+
+/*
+ * Init/Deinit for one-time work in TINITFS.C
+ */
+INT16 EMS_InitFileSys( DLE_HAND hand, BE_CFG_PTR cfg, UINT32 fsys_mask );
+VOID EMS_DeInitFileSys( DLE_HAND hand );
+
+/*
+ * Operations on temporary file names (for active restores)
+ */
+VOID EMS_InitTemp( VOID );
+VOID EMS_DeinitTemp( VOID );
+BOOLEAN EMS_SaveTempName( CHAR_PTR tapeName, CHAR_PTR diskName );
+CHAR_PTR EMS_GetTempName( CHAR_PTR tapeName );
+
+
+/*
+ * Utility and debug functions
+ */
+
+#if defined( FS_DEBUG )
+#define EMS_DebugPrint EMS_DebugPrintFunction
+#else
+#define EMS_DebugPrint
+#endif
+
+VOID EMS_DebugPrintFunction( CHAR *fmt, ... );
+CHAR_PTR EMS_DuplicateString( CHAR_PTR src );
+
+
+
+
diff --git a/private/utils/ntbackup/inc/ems_jet.h b/private/utils/ntbackup/inc/ems_jet.h
new file mode 100644
index 000000000..0bfba59b2
--- /dev/null
+++ b/private/utils/ntbackup/inc/ems_jet.h
@@ -0,0 +1,21 @@
+
+
+typedef long EC;
+typedef void *HBC;
+
+EC EMS_BackupPrepare(LPSTR a,LPSTR b, unsigned long c, INT d, HBC *e) ;
+EC EMS_BackupGetAttachmentInfo( PVOID a, LPSTR *b, LPDWORD c);
+EC EMS_BackupRead(PVOID a, PVOID b, DWORD c, PDWORD d );
+EC EMS_BackupClose(PVOID a) ;
+EC EMS_BackupOpen(PVOID a, LPSTR b, DWORD c, LARGE_INTEGER *d);
+EC EMS_GetBackupLogs( PVOID a, LPSTR *b, LPDWORD c);
+EC EMS_TruncateLogs(PVOID a) ;
+EC EMS_BackupEnd(PVOID a) ;
+VOID EMS_BackupFree(PVOID a) ;
+EC EMS_RestoreEnd(PVOID a ) ;
+EC EMS_RestorePrepare( PVOID a, PVOID b, PVOID *c ) ;
+EC EMS_RestoreRegister( PVOID a, PVOID b, PVOID c, PVOID d, INT e, PVOID f, INT g, INT h) ;
+EC EMS_RestoreLocations( PVOID a, PVOID b, INT *c) ;
+EC EMS_RestoreComplete( PVOID a, INT b) ;
+
+
diff --git a/private/utils/ntbackup/inc/emsdblk.h b/private/utils/ntbackup/inc/emsdblk.h
new file mode 100644
index 000000000..c5f983007
--- /dev/null
+++ b/private/utils/ntbackup/inc/emsdblk.h
@@ -0,0 +1,106 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: emsdblk.h
+
+ Description: This file contains the definition of the DOS
+ file and directory control blocks.
+
+
+ $Log: M:/LOGFILES/EMSDBLK.H_V $
+
+**/
+/* $end$ include list */
+
+#ifndef emsdblk_h
+#define emssdblk_h
+
+#include "queues.h"
+
+#define EMS_MDB_PRI_FILE_DATA 0x00010001
+#define EMS_MDB_PUB_FILE_DATA 0x00010002
+#define EMS_MDB_OTH_FILE_DATA 0x00010003
+#define EMS_DSA_FILE_DATA 0x00010004
+#define EMS_FOLDER_DATA 0x00010005
+
+/* Matches bottom portion of NT stream headers */
+
+typedef struct{
+ CHAR FnameSystem[256];
+ CHAR FnamePrivate[256];
+ CHAR FnamePublic[256];
+ CHAR LogDir[256];
+} MDB_PATHS ;
+
+typedef struct {
+ CHAR DbPath[256] ;
+ CHAR SystemPath[256];
+ CHAR LogDir[256] ;
+} DSA_PATHS ;
+
+
+typedef union {
+ DSA_PATHS dsa;
+ MDB_PATHS mdb;
+} XCHANGE_PATHS ;
+
+#define EMS_MAX_STREAM_NAME_LENG 512
+typedef struct _EMS_STREAM_NAME {
+ UINT32 name_leng ;
+ UINT8 name[ EMS_MAX_STREAM_NAME_LENG ] ;
+} EMS_STREAM_NAME, *EMS_STREAM_NAME_PTR;
+
+#define EMS_DOING_LOGS 1
+#define EMS_DOING_DB 0
+typedef struct _EMS_OBJ_HAND {
+ HANDLE fhand;
+ VOID_PTR context;
+ UINT32 currentStreamId ;
+ EMS_STREAM_NAME strm_name;
+ UINT64 nextStreamHeaderPos;
+ UINT64 curPos;
+ BOOLEAN needPathList ;
+ INT pathListSize ;
+ BOOLEAN needStreamHeader; /* Ready for SH on backup */
+ BOOLEAN db_restored ;
+ UINT32 check_sum ;
+ UINT32 residule_byte_count ;
+ INT time_for_checksum ;
+ BOOLEAN nameComplete;
+ INT db_or_log; //EMS_DOING_LOG or EMS_DOING_DB
+ INT name_list_offset ;
+ CHAR_PTR name_list;
+ XCHANGE_PATHS org_paths;
+ BOOLEAN skip_data ;
+ INT open_ret_val ;
+} EMS_OBJ_HAND, *EMS_OBJ_HAND_PTR;
+
+
+typedef struct _EMS_DBLK *EMS_DBLK_PTR;
+
+typedef struct _EMS_DBLK {
+ UINT8 blk_type; /* values: DDB_ID, FDB_ID set: DOS */
+ COM_DBLK fs_reserved ;
+ INT ems_type ;
+ UINT64 display_size ;
+ BOOLEAN os_info_complete; /* TRUE if GetObjInfo doesn't have to do anything */
+ BOOLEAN name_complete; /* TRUE if name/path is restored to DBLK */
+ BOOLEAN backup_completed ;
+ UINT32 context ;
+ FS_NAME_Q_ELEM_PTR full_name_ptr ;
+} EMS_DBLK;
+
+
+typedef struct _EMS_MIN_DDB *EMS_MIN_DDB_PTR;
+
+typedef struct _EMS_MIN_DDB {
+ Q_ELEM q ;
+ HANDLE scan_hand; /* windows handle for scan */
+ BOOLEAN path_in_stream ;
+ UINT16 psize ; /* size of path string */
+ CHAR_PTR path; /* build from "name" and current dir */
+} EMS_MIN_DDB;
+
+
+#endif
diff --git a/private/utils/ntbackup/inc/enc_priv.h b/private/utils/ntbackup/inc/enc_priv.h
new file mode 100644
index 000000000..c6ae1795f
--- /dev/null
+++ b/private/utils/ntbackup/inc/enc_priv.h
@@ -0,0 +1,67 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: enc_priv.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+ Location: BE_PRIVATE
+
+
+ $Log: Q:/LOGFILES/ENC_PRIV.H_V $
+ *
+ * Rev 1.1 08 Oct 1992 12:47:08 DAVEV
+ * fixes for handling Unicode passwords
+ *
+ * Rev 1.0 09 May 1991 13:32:36 HUNTER
+ * Initial revision.
+
+**/
+
+/*
+** Define pointer sizes for CodeRunner version if they aren't already
+*/
+#ifndef PTR_SIZE
+#ifdef CODERUNNER
+#define PTR_SIZE far
+#else
+#define PTR_SIZE
+#endif
+#endif
+
+#ifndef ENCRYPTS
+
+#define ENCRYPTS
+
+#include "StdTypes.H"
+/* $end$ include list */
+
+
+/* Encryption Algorithms */
+
+typedef struct MAYXOR_ALGOR {
+ INT8 PTR_SIZE *key ;
+ INT16 ksize ;
+ UINT8 feedback ;
+ INT16 block_size ;
+ INT32 bytes_processed ;
+} MAYXOR_ALGOR ;
+
+typedef struct MAYHDW_ALGOR {
+ INT16 temp ;
+} MAYHDW_ALGOR ;
+
+/* Encryption Unit Handle for each algorithm */
+typedef struct EU_HAND {
+ INT16 algor ;
+ INT16 mode ;
+ union {
+ struct MAYHDW_ALGOR hdwr;
+ struct MAYXOR_ALGOR exor;
+ } algors ;
+} EU_HAND;
+
+#endif
diff --git a/private/utils/ntbackup/inc/enc_pub.h b/private/utils/ntbackup/inc/enc_pub.h
new file mode 100644
index 000000000..c6ce78053
--- /dev/null
+++ b/private/utils/ntbackup/inc/enc_pub.h
@@ -0,0 +1,69 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: enc_pub.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+ Location: BE_PUBLIC
+
+
+ $Log: Q:/LOGFILES/ENC_PUB.H_V $
+ *
+ * Rev 1.2 08 Oct 1992 12:47:08 DAVEV
+ * fixes for handling Unicode passwords
+ *
+ * Rev 1.1 14 May 1991 12:01:02 JOHNW
+ * Added #define for a do-nothing encryption algorithm.
+ *
+ * Rev 1.0 09 May 1991 13:30:40 HUNTER
+ * Initial revision.
+
+**/
+
+#ifndef ENCRYPES
+
+#define ENCRYPES
+
+#include "stdtypes.h"
+/* $end$ include list */
+
+#ifndef PTR_SIZE
+#ifdef CODERUNNER
+#define PTR_SIZE far
+#else
+#define PTR_SIZE
+#endif
+#endif
+
+/* Algorithm type defined */
+#define ENC_ALGOR_0 0 /* Do nothing. ie Encrypt( "John" ) == "John" */
+#define ENC_ALGOR_1 1 /* Maynard's 2.0 password encryption algorithm */
+#define ENC_ALGOR_2 2 /* to become Maynards's hardware encryption algorithm */
+#define ENC_ALGOR_3 3 /* Maynard Encryption Standard */
+
+/* Mode type defined */
+#define ENCRYPT 100 /* set mode to encrypt code */
+#define DECRYPT 500 /* set mode to decrypt code */
+
+/* Error values defined */
+#define EU_NO_ERROR 0
+#define EU_ALGORITHM_UNKNOWN -600
+#define EU_MEMORY_ERROR -601
+#define EU_ENCRYPTION_ERROR -602
+
+typedef struct EU_HAND PTR_SIZE *EU_HAND_PTR ;
+
+/* Encryption Unit Interface prototypes */
+/* EU_Open, EU_Encrypt, EU_ResetHand, EU_Close */
+
+EU_HAND_PTR EU_Open( INT16 algor, INT16 mode, INT8_PTR key, INT16 ksize,
+ INT16_PTR block_size, INT16_PTR error ) ;
+INT16 EU_Encrypt( EU_HAND_PTR en_un_hn, INT8_PTR data, INT16 dsize ) ;
+INT16 EU_ResetHand( EU_HAND_PTR en_un_hn ) ;
+VOID EU_Close( EU_HAND_PTR en_un_hn ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/eng_dbug.h b/private/utils/ntbackup/inc/eng_dbug.h
new file mode 100644
index 000000000..0ea8b624f
--- /dev/null
+++ b/private/utils/ntbackup/inc/eng_dbug.h
@@ -0,0 +1,110 @@
+#ifndef ENG_DBUG_SH
+
+#define ENG_DBUG_SH
+
+//DEBUG ERROR MESSAGE
+
+#define RES_DBUG_MESSAGE 3800
+
+#define RES_CONFIG_REMOTE RES_DBUG_MESSAGE + 0
+#define RES_CONFIG_NRL_DOS_VECTOR RES_DBUG_MESSAGE + 1
+#define RES_SMB_INITIALIZE RES_DBUG_MESSAGE + 2
+#define RES_REMOTE_BUFFERS RES_DBUG_MESSAGE + 3
+#define RES_NO_NRL_FUNCTION_TABLE RES_DBUG_MESSAGE + 4
+#define RES_REWIND_DRIVE_HDL RES_DBUG_MESSAGE + 5
+#define RES_DRV_RET RES_DBUG_MESSAGE + 6
+#define RES_RET_VAL_EQUALS RES_DBUG_MESSAGE + 7
+#define RES_ERASE_EXABYTE_SECURITY RES_DBUG_MESSAGE + 8
+#define RES_CALLING_ERASE RES_DBUG_MESSAGE + 9
+#define RES_CALLING_WRITE_END_SET RES_DBUG_MESSAGE + 10
+#define RES_READ_NEXT_SET RES_DBUG_MESSAGE + 11
+#define RES_READ_END_SET RES_DBUG_MESSAGE + 12
+#define RES_END_OF_SET RES_DBUG_MESSAGE + 13
+#define RES_END_OF_MEDIA RES_DBUG_MESSAGE + 14
+#define RES_TP_READ RES_DBUG_MESSAGE + 15
+#define RES_DRV_ERROR_BYTES_RCVD RES_DBUG_MESSAGE + 16
+#define RES_READ_NEXT_SET_RETVAL RES_DBUG_MESSAGE + 17
+#define RES_GOTO_BCKUP_SET RES_DBUG_MESSAGE + 18
+#define RES_OPEN_DRIVE_CARD_NO RES_DBUG_MESSAGE + 19
+#define RES_CLOSE_DRIVE RES_DBUG_MESSAGE + 20
+#define RES_REWIND RES_DBUG_MESSAGE + 21
+#define RES_NO_REWIND RES_DBUG_MESSAGE + 22
+#define RES_BADDR_IRQ_DMA_NO_DRIVES RES_DBUG_MESSAGE + 23
+#define RES_UPDATE_DRIVE_STATUS RES_DBUG_MESSAGE + 24
+#define RES_VAL_CHANGED RES_DBUG_MESSAGE + 25
+#define RES_VAL_UNCHANGED RES_DBUG_MESSAGE + 26
+#define RES_CATALOG_TIME RES_DBUG_MESSAGE + 27
+#define RES_UI_TPOS_TAPE_SET RES_DBUG_MESSAGE + 28
+#define RES_IMAGE_DIFFERENCE RES_DBUG_MESSAGE + 29
+#define RES_HEX_BYTE RES_DBUG_MESSAGE + 30
+#define RES_DISK_CONTENTS RES_DBUG_MESSAGE + 31
+#define RES_NEW_LINE RES_DBUG_MESSAGE + 32
+#define RES_TAPE_PARTITION_SPECS RES_DBUG_MESSAGE + 33
+#define RES_DISK_PARTITION_SPECS RES_DBUG_MESSAGE + 34
+#define RES_REM_ATTACH_TO_DLE RES_DBUG_MESSAGE + 35
+#define RES_SMB_CONNECT_APPLICATION RES_DBUG_MESSAGE + 36
+#define RES_FOUND_REMOTE_DEVICE RES_DBUG_MESSAGE + 37
+#define RES_REMOTE_BINDING RES_DBUG_MESSAGE + 38
+#define RES_FAILED RES_DBUG_MESSAGE + 39
+#define RES_OKAY RES_DBUG_MESSAGE + 40
+#define RES_SMB_RELEASE RES_DBUG_MESSAGE + 41
+#define RES_REM_SMB_DISCONNECT RES_DBUG_MESSAGE + 42
+#define RES_HEX_INT RES_DBUG_MESSAGE + 43
+#define RES_RWS_ATTACH_TO_DLE RES_DBUG_MESSAGE + 44
+#define RES_DLE_GET_CHILD RES_DBUG_MESSAGE + 45
+#define RES_RWS_SMB_DISCONNECT RES_DBUG_MESSAGE + 46
+#define RES_SOFT_ERRORS_UNDERRUNS RES_DBUG_MESSAGE + 47
+#define RES_REQUESTED_SET RES_DBUG_MESSAGE + 48
+#define RES_RESIDUAL_READ_BUFFER RES_DBUG_MESSAGE + 49
+#define RES_ATTEMPTING_TO_VCB RES_DBUG_MESSAGE + 50
+#define RES_CURRENT_VCB RES_DBUG_MESSAGE + 51
+#define RES_POSITION_AT_SET RES_DBUG_MESSAGE + 52
+#define RES_UI_MSG RES_DBUG_MESSAGE + 53
+#define RES_TF_CLOSE_SET RES_DBUG_MESSAGE + 54
+#define RES_FATAL_ERROR_DETECTED RES_DBUG_MESSAGE + 55
+#define RES_READ_BUFFER_LEFT_OVER RES_DBUG_MESSAGE + 56
+#define RES_TF_OPEN_SET RES_DBUG_MESSAGE + 57
+#define RES_HOLD_BUFFER RES_DBUG_MESSAGE + 58
+#define RES_DESTROY_HOLD_BUFFER RES_DBUG_MESSAGE + 59
+#define RES_OPEN_REQUESTED_REWIND RES_DBUG_MESSAGE + 60
+#define RES_END_OF_TFOPEN_SET RES_DBUG_MESSAGE + 61
+#define RES_TF_ALLOCATE_BUFFERS RES_DBUG_MESSAGE + 62
+#define RES_END_ALLOCATE RES_DBUG_MESSAGE + 63
+#define RES_TF_FREE_BUFFERS RES_DBUG_MESSAGE + 64
+#define RES_END_EQUALS RES_DBUG_MESSAGE + 65
+#define RES_TF_GETNEXT_TAPE_REQUEST RES_DBUG_MESSAGE + 66
+#define RES_TF_GETNEXT_ERROR RES_DBUG_MESSAGE + 67
+#define RES_ABORT_READ RES_DBUG_MESSAGE + 68
+#define RES_INITIATE_WATCH RES_DBUG_MESSAGE + 69
+#define RES_WATCH_REWIND RES_DBUG_MESSAGE + 70
+#define RES_DEVICE_ERROR RES_DBUG_MESSAGE + 71
+#define RES_GOTO_LBA RES_DBUG_MESSAGE + 72
+#define RES_DRIVER_TO_LOAD RES_DBUG_MESSAGE + 73
+#define RES_LOADING_DRIVER RES_DBUG_MESSAGE + 74
+#define RES_TPINIT_FAILURE RES_DBUG_MESSAGE + 75
+#define RES_WATCH_DRIVE_CALLED RES_DBUG_MESSAGE + 76
+#define RES_WATCH_DRIVE_STATUS RES_DBUG_MESSAGE + 77
+#define RES_WATCH_DRIVE_EXIT RES_DBUG_MESSAGE + 78
+#define RES_WATCH_DRIVE_END RES_DBUG_MESSAGE + 79
+#define RES_GET_CURRENT_POS_STAT RES_DBUG_MESSAGE + 80
+#define RES_UI_PURGE_CATALOG RES_DBUG_MESSAGE + 81
+#define RES_UNFORMATED_STRING RES_DBUG_MESSAGE + 82
+#define RES_IMAGE_BAD_VERIFY RES_DBUG_MESSAGE + 83
+#define RES_IMAGE_BAD_BLOCK RES_DBUG_MESSAGE + 84
+#define RES_IMAGE_BAD_READ RES_DBUG_MESSAGE + 85
+#define RES_IMAGE_BAD_WRITE RES_DBUG_MESSAGE + 86
+#define RES_CLOSE_BINDERY RES_DBUG_MESSAGE + 87
+#define RES_AL_RESULT RES_DBUG_MESSAGE + 88
+#define RES_OPEN_BINDERY RES_DBUG_MESSAGE + 89
+#define RES_PARM_BLK_DESCR RES_DBUG_MESSAGE + 90
+#define RES_PARM_BLK RES_DBUG_MESSAGE + 91
+#define RES_CRIT_ADDRS RES_DBUG_MESSAGE + 92
+#define RES_ATTACH_TO_DLE RES_DBUG_MESSAGE + 93
+#define RES_DETACH_FROM_DLE RES_DBUG_MESSAGE + 94
+#define RES_NOVELL_SERVER_INFO RES_DBUG_MESSAGE + 95
+#define RES_DLE_BASE_PATH RES_DBUG_MESSAGE + 96
+#define RES_NO_ATTACHED_DRIVES RES_DBUG_MESSAGE + 97
+#define RES_INIT_ERROR RES_DBUG_MESSAGE + 98
+
+
+#endif
diff --git a/private/utils/ntbackup/inc/eng_err.h b/private/utils/ntbackup/inc/eng_err.h
new file mode 100644
index 000000000..f83bf080b
--- /dev/null
+++ b/private/utils/ntbackup/inc/eng_err.h
@@ -0,0 +1,116 @@
+#ifndef ENG_ERR_SH
+
+#define ENG_ERR_SH
+
+//BACKUP ENGINE ERROR MESSAGE
+
+#define RES_ERR_MESSAGE 3500
+
+#define RES_OUT_OF_MEMORY RES_ERR_MESSAGE + 0
+#define RES_RESOURCE_FILE_ERROR RES_ERR_MESSAGE + 1
+#define RES_INVALID_DATE RES_ERR_MESSAGE + 2
+#define RES_SAVE_CONFIG_ERROR RES_ERR_MESSAGE + 3
+#define RES_ALL_PARTITIONS_KNOWN RES_ERR_MESSAGE + 4
+#define RES_SCRIPT_DELETE_ERROR RES_ERR_MESSAGE + 5
+#define RES_SCRIPT_NOTHING_SELECTED RES_ERR_MESSAGE + 6
+#define RES_ERROR_WRITING_SCRIPT RES_ERR_MESSAGE + 7
+#define RES_USER_TAPE_ABORT RES_ERR_MESSAGE + 8
+#define RES_END_CHANNEL RES_ERR_MESSAGE + 9
+#define RES_ERROR_CONTINUE RES_ERR_MESSAGE + 10
+#define RES_WRITE_PROT RES_ERR_MESSAGE + 11
+#define RES_UNKNOWN_TF_MSG RES_ERR_MESSAGE + 12
+#define RES_UNKNOWN_MSG_HNDLR_MSG RES_ERR_MESSAGE + 13
+#define RES_UNKNOWN_LOOPS_ERR RES_ERR_MESSAGE + 14
+#define RES_OPEN_LOG_ERROR RES_ERR_MESSAGE + 15
+#define RES_PRINTER_INIT_ERROR RES_ERR_MESSAGE + 16
+#define RES_UNKNOWN_LOG_MSG RES_ERR_MESSAGE + 17
+#define RES_ERROR_OPENING_PWDBASE RES_ERR_MESSAGE + 18
+#define RES_COMMAND_SYNTAX_ERROR RES_ERR_MESSAGE + 19
+#define RES_SCRIPT_SYNTAX_ERROR RES_ERR_MESSAGE + 20
+#define RES_SCRIPT_OPEN_ERROR RES_ERR_MESSAGE + 21
+#define RES_SCRIPT_NESTING_ERROR RES_ERR_MESSAGE + 22
+#define RES_DRIVE_MATCH_ERROR RES_ERR_MESSAGE + 23
+#define RES_FILE_RENAME_ERROR RES_ERR_MESSAGE + 24
+#define RES_INVALID_SOURCE RES_ERR_MESSAGE + 25
+#define RES_INVALID_TARGET RES_ERR_MESSAGE + 26
+#define RES_INVALID_PARAMETER RES_ERR_MESSAGE + 27
+#define RES_ERROR_UPDATING_PDBASE RES_ERR_MESSAGE + 28
+#define RES_ERROR_READING_PDBASE RES_ERR_MESSAGE + 29
+#define RES_PDBASE_FULL RES_ERR_MESSAGE + 30
+#define RES_REMOTE_DENIED_READ RES_ERR_MESSAGE + 31
+#define RES_REMOTE_DENIED_DELETE RES_ERR_MESSAGE + 32
+#define RES_UNKNOWN_PDBASE_ERROR RES_ERR_MESSAGE + 33
+#define RES_CANT_DETERMINE_DOS_PART RES_ERR_MESSAGE + 34
+#define RES_MISMATCHED_PASSWORD RES_ERR_MESSAGE + 35
+#define RES_ERROR_DURING_ATTACH RES_ERR_MESSAGE + 36
+#define RES_CAT_DELETE_ERROR_MSG RES_ERR_MESSAGE + 37
+#define RES_ERROR_POSITIONING_TAPE RES_ERR_MESSAGE + 38
+#define RES_NO_FILE_IN_DIR RES_ERR_MESSAGE + 39
+#define RES_EU_ERROR RES_ERR_MESSAGE + 40
+#define RES_BACKUP_NO_SELECTIONS RES_ERR_MESSAGE + 41
+#define RES_VERIFY_NO_SELECTIONS RES_ERR_MESSAGE + 42
+#define RES_INVALID_WILDCARDS RES_ERR_MESSAGE + 43
+#define RES_INVALID_DOS_FNAME RES_ERR_MESSAGE + 44
+#define RES_INVALID_FSPEC RES_ERR_MESSAGE + 45
+#define RES_INVALID_DRIVE_SPEC RES_ERR_MESSAGE + 46
+#define RES_INVALID_PATH_SPEC RES_ERR_MESSAGE + 47
+#define RES_DONT_SPECIFY_DRIVE RES_ERR_MESSAGE + 48
+#define RES_DONT_SPECIFY_PATH RES_ERR_MESSAGE + 49
+#define RES_DONT_SPECIFY_FNAME RES_ERR_MESSAGE + 50
+#define RES_EOM_TAPE_ABORT RES_ERR_MESSAGE + 51
+#define RES_FATAL_CAT_ERROR RES_ERR_MESSAGE + 52
+#define RES_UNKNOWN_CAT_ERR RES_ERR_MESSAGE + 53
+#define RES_USER_CAT_ABORT RES_ERR_MESSAGE + 54
+#define RES_ERROR_TITLE RES_ERR_MESSAGE + 55
+#define RES_NO_MORE_CONNECTIONS RES_ERR_MESSAGE + 56
+#define RES_NO_HELP_AVAIL RES_ERR_MESSAGE + 57
+#define RES_TEMP_CAT_OPEN_ERR RES_ERR_MESSAGE + 58
+#define RES_TEMP_CAT_SEEK_ERR RES_ERR_MESSAGE + 59
+#define RES_TEMP_CAT_READ_ERR RES_ERR_MESSAGE + 60
+#define RES_TEMP_CAT_WRITE_ERR RES_ERR_MESSAGE + 61
+#define RES_TEMP_CAT_UNLINK_ERR RES_ERR_MESSAGE + 62
+#define RES_TEMP_CAT_UNKNOWN_ERR RES_ERR_MESSAGE + 63
+#define RES_EMBEDDED_PW_MISMATCH RES_ERR_MESSAGE + 64
+#define RES_CAT_ERASE_ERROR_MSG RES_ERR_MESSAGE + 65
+#define RES_UNKNOWN_LOOPS_PROMPT RES_ERR_MESSAGE + 66
+#define RES_EMPTY_DRIVE_ERROR RES_ERR_MESSAGE + 67
+#define RES_DIR_ERROR_MSG RES_ERR_MESSAGE + 68
+#define RES_VMEM_CRIT_ERR RES_ERR_MESSAGE + 69
+#define RES_REST_PARTITION_ERR RES_ERR_MESSAGE + 70
+#define RES_VER_PARTITION_ERR RES_ERR_MESSAGE + 71
+#define RES_TEMP_CAT_LEVEL_ZERO_ERR RES_ERR_MESSAGE + 72
+#define RES_CAT_LEVEL_ZERO_ERR RES_ERR_MESSAGE + 73
+#define RES_RESTORE_NO_SELECTIONS RES_ERR_MESSAGE + 74
+#define RES_INSUFFICIENT_DISK_SPACE_ERR RES_ERR_MESSAGE + 75
+#define RES_CATALOG_UNUSABLE RES_ERR_MESSAGE + 76
+#define RES_DEVICE_DEAD RES_ERR_MESSAGE + 77
+#define RES_REST_IMAGE_SEQUENCE_ERR RES_ERR_MESSAGE + 78
+#define RES_VER_IMAGE_SEQUENCE_ERR RES_ERR_MESSAGE + 79
+#define RES_ARCHIVE_NO_SELECTIONS RES_ERR_MESSAGE + 80
+#define RES_UNEXPECTED_EOS RES_ERR_MESSAGE + 81
+#define RES_FOREIGN_TAPE_ERROR RES_ERR_MESSAGE + 82
+#define RES_FATAL_TAPE_READ_ERR RES_ERR_MESSAGE + 83
+#define RES_FATAL_TAPE_WRITE_ERR RES_ERR_MESSAGE + 84
+#define RES_FATAL_TAPE_FMT_ERR RES_ERR_MESSAGE + 85
+#define RES_FATAL_TAPE_TRANS_ERR RES_ERR_MESSAGE + 86
+#define RES_FATAL_TAPE_ERR RES_ERR_MESSAGE + 87
+#define RES_FATAL_TAPE_DRIVE_ERR RES_ERR_MESSAGE + 88
+#define RES_INVALID_NUMERAL RES_ERR_MESSAGE + 89
+#define RES_DLE_HAS_NO_CHILDREN RES_ERR_MESSAGE + 90
+#define RES_SERVER_ADDR_NOT_FOUND RES_ERR_MESSAGE + 91
+#define RES_BAD_ATTACH_TO_SERVER RES_ERR_MESSAGE + 92
+#define RES_BAD_SERVER_LOGIN RES_ERR_MESSAGE + 93
+#define RES_MISSING_HW_RESOURCE RES_ERR_MESSAGE + 94
+#define RES_INCONSISTENT_HW_PARMS RES_ERR_MESSAGE + 95
+#define RES_UNKNOWN_HW_ERR RES_ERR_MESSAGE + 96
+#define RES_BENGINE_IN_USE RES_ERR_MESSAGE + 97
+#define RES_ERROR_DURING_LOGOUT RES_ERR_MESSAGE + 98
+#define RES_NO_DRIVERS_FOUND RES_ERR_MESSAGE + 99
+#define RES_NET_OPTIONS_NOT_AVAIL RES_ERR_MESSAGE + 100
+#define RES_CONTROL_OPTIONS_NOT_AVAIL RES_ERR_MESSAGE + 101
+#define RES_FATAL_TAPE_FMT_NO_APPEND RES_ERR_MESSAGE + 102
+#define RES_FATAL_TAPE_FMT_NO_APPEND RES_ERR_MESSAGE + 102
+#define RES_ERROR_EMS_RESTART RES_ERR_MESSAGE + 103
+#define RES_ERROR_COMPRESS_FILE_FAIL RES_ERR_MESSAGE + 104
+
+#endif
diff --git a/private/utils/ntbackup/inc/eng_fmt.h b/private/utils/ntbackup/inc/eng_fmt.h
new file mode 100644
index 000000000..a51eaad7b
--- /dev/null
+++ b/private/utils/ntbackup/inc/eng_fmt.h
@@ -0,0 +1,15 @@
+#ifndef ENG_FMT_SH
+
+#define ENG_FMT_SH
+
+#define RES_MY40_TRANS 0
+#define RES_MY31_TRANS 1
+#define RES_MY30_TRANS 2
+#define RES_MY25_TRANS 3
+#define RES_QS19_TRANS 4
+#define RES_SY31_TRANS 5
+#define RES_UTF_TRANS 6
+#define RES_SYPL10_TRANS 7
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/eng_mq.h b/private/utils/ntbackup/inc/eng_mq.h
new file mode 100644
index 000000000..8df97889e
--- /dev/null
+++ b/private/utils/ntbackup/inc/eng_mq.h
@@ -0,0 +1,13 @@
+#ifndef ENG_MQ_SH
+
+#define ENG_MQ_SH
+
+#define RES_DD_HLP_RES_01 0
+#define RES_DOUBLE_BORDER 1
+#define RES_HW_BORDER 2
+#define RES_DOUBLE_TOP_BORDER 3
+#define RES_ERROR_LIST 4
+#define RES_CARD_LIST 5
+#define RES_DD_CONF 6
+
+#endif
diff --git a/private/utils/ntbackup/inc/eng_msg.h b/private/utils/ntbackup/inc/eng_msg.h
new file mode 100644
index 000000000..c0b8a335f
--- /dev/null
+++ b/private/utils/ntbackup/inc/eng_msg.h
@@ -0,0 +1,462 @@
+#ifndef ENG_MSG_SH
+
+#define ENG_MSG_SH
+
+#define RES_MESSAGE 3000
+
+#define RES_YES_KEY RES_MESSAGE + 0
+#define RES_NO_KEY RES_MESSAGE + 1
+#define RES_YES_STRING RES_MESSAGE + 2
+#define RES_NO_STRING RES_MESSAGE + 3
+#define RES_PRE_NOON RES_MESSAGE + 4
+#define RES_AFTER_NOON RES_MESSAGE + 5
+#define RES_SAVED_CONFIG RES_MESSAGE + 6
+#define RES_BACKUP_STATUS_LABEL RES_MESSAGE + 7
+#define RES_ARCHIVE_STATUS_LABEL RES_MESSAGE + 8
+#define RES_RESTORE_STATUS_LABEL RES_MESSAGE + 9
+#define RES_VERIFY_STATUS_LABEL RES_MESSAGE + 10
+#define RES_DIRECTORY_STATUS_LABEL RES_MESSAGE + 11
+#define RES_INSERT_NEW_TAPE RES_MESSAGE + 12
+#define RES_REPLACE_OLD_TAPE RES_MESSAGE + 13
+#define RES_CONTINUE RES_MESSAGE + 14
+#define RES_TAPE_NOT_INSERTED RES_MESSAGE + 15
+#define RES_DISPLAY_VCB RES_MESSAGE + 16
+#define RES_APPEND_QUEST RES_MESSAGE + 17
+#define RES_REPLACE_WARNING RES_MESSAGE + 18
+#define RES_REPLACE_TAPE RES_MESSAGE + 19
+#define RES_RESTORE_QUEST RES_MESSAGE + 20
+#define RES_VERIFY_QUEST RES_MESSAGE + 21
+#define RES_DIRECTORY_QUEST RES_MESSAGE + 22
+#define RES_SEARCH_QUEST RES_MESSAGE + 23
+#define RES_CONTINUE_QUEST RES_MESSAGE + 24
+#define RES_FOREIGN_TAPE_MSG RES_MESSAGE + 25
+#define RES_BLANK_TAPE RES_MESSAGE + 26
+#define RES_NO_MORE_TAPE_INFO RES_MESSAGE + 27
+#define RES_SEARCHING RES_MESSAGE + 28
+#define RES_REWINDING RES_MESSAGE + 29
+#define RES_WAITING RES_MESSAGE + 30
+#define RES_BACKUP_STARTED RES_MESSAGE + 31
+#define RES_RESTORE_STARTED RES_MESSAGE + 32
+#define RES_VERIFY_STARTED RES_MESSAGE + 33
+#define RES_DIRECTORY RES_MESSAGE + 34
+#define RES_FILE_SKIPPED RES_MESSAGE + 35
+#define RES_BACKUP_COMPLETED RES_MESSAGE + 36
+#define RES_RESTORE_COMPLETED RES_MESSAGE + 37
+#define RES_VERIFY_COMPLETED RES_MESSAGE + 38
+#define RES_BACKED_UP_DIR_FILE RES_MESSAGE + 39
+#define RES_BACKED_UP_DIR_FILES RES_MESSAGE + 40
+#define RES_BACKED_UP_DIRS_FILES RES_MESSAGE + 41
+#define RES_BACKED_UP_MAC RES_MESSAGE + 42
+#define RES_BACKED_UP_MACS RES_MESSAGE + 43
+#define RES_BACKED_UP_CORRUPT_WARNING RES_MESSAGE + 44
+#define RES_BACKED_UP_CORRUPT RES_MESSAGE + 45
+#define RES_BACKED_UP_CORRUPTS RES_MESSAGE + 46
+#define RES_BACKED_UP_IN_USE_WARNING RES_MESSAGE + 47
+#define RES_BACKED_UP_IN_USE RES_MESSAGE + 48
+#define RES_BACKED_UP_IN_USES RES_MESSAGE + 49
+#define RES_FILE_SKIPPED_STAT RES_MESSAGE + 50
+#define RES_FILE_SKIPPEDS_STAT RES_MESSAGE + 51
+#define RES_RESTORED_DIR_FILE RES_MESSAGE + 52
+#define RES_RESTORED_DIR_FILES RES_MESSAGE + 53
+#define RES_RESTORED_DIRS_FILES RES_MESSAGE + 54
+#define RES_RESTORED_MAC RES_MESSAGE + 55
+#define RES_RESTORED_MACS RES_MESSAGE + 56
+#define RES_RESTORED_CORRUPT RES_MESSAGE + 57
+#define RES_RESTORED_CORRUPTS RES_MESSAGE + 58
+#define RES_RESTORED_CORRUPT_WARNING RES_MESSAGE + 59
+#define RES_RESTORED_IN_USE RES_MESSAGE + 60
+#define RES_RESTORED_IN_USES RES_MESSAGE + 61
+#define RES_RESTORED_IN_USE_WARNING RES_MESSAGE + 62
+#define RES_VERIFIED_DIR_FILE RES_MESSAGE + 63
+#define RES_VERIFIED_DIR_FILES RES_MESSAGE + 64
+#define RES_VERIFIED_DIRS_FILES RES_MESSAGE + 65
+#define RES_VERIFIED_MAC RES_MESSAGE + 66
+#define RES_VERIFIED_MACS RES_MESSAGE + 67
+#define RES_FILE_IS_DIFFERENT RES_MESSAGE + 68
+#define RES_FILES_DIFFERENT RES_MESSAGE + 69
+#define RES_FILE_NOT_FOUND_ON_DISK RES_MESSAGE + 70
+#define RES_PROCESSED_BYTES RES_MESSAGE + 71
+#define RES_PROCESSED_BYTES_MIN RES_MESSAGE + 72
+#define RES_PROCESSED_BYTES_SEC RES_MESSAGE + 73
+#define RES_PROCESS_RATE RES_MESSAGE + 74
+#define RES_VERIFIED_DIRS_FILE RES_MESSAGE + 75
+#define RES_RESTORE_TITLE RES_MESSAGE + 76 /* open for use */
+#define RES_TENSION_TITLE RES_MESSAGE + 77 /* open for use */
+#define RES_ERASE_TITLE RES_MESSAGE + 78 /* open for use */
+#define RES_FILE_READ_ERROR RES_MESSAGE + 79
+#define RES_FILE_WRITE_ERROR RES_MESSAGE + 80
+#define RES_DIR_STARTED RES_MESSAGE + 81
+#define RES_DIR_COMPLETED RES_MESSAGE + 82
+#define RES_DIR_DIR_FILE RES_MESSAGE + 83
+#define RES_DIR_DIR_FILES RES_MESSAGE + 84
+#define RES_DIR_DIRS_FILES RES_MESSAGE + 85
+#define RES_DIR_MAC RES_MESSAGE + 86
+#define RES_DIR_MACS RES_MESSAGE + 87
+#define RES_DIR_CORRUPT_WARNING RES_MESSAGE + 88
+#define RES_DIR_CORRUPT RES_MESSAGE + 89
+#define RES_DIR_CORRUPTS RES_MESSAGE + 90
+#define RES_DIR_IN_USE_WARNING RES_MESSAGE + 91
+#define RES_DIR_IN_USE RES_MESSAGE + 92
+#define RES_DIR_IN_USES RES_MESSAGE + 93
+#define RES_WRITE_PROTECTED RES_MESSAGE + 94
+#define RES_UNKNOWN_DEVICE RES_MESSAGE + 95
+#define RES_DRIVE_NOT_READY RES_MESSAGE + 96
+#define RES_SEEK_ERROR RES_MESSAGE + 97
+#define RES_SECTOR_NOT_FOUND RES_MESSAGE + 98
+#define RES_PRINTER_ERROR RES_MESSAGE + 99
+#define RES_WRITE_ERROR RES_MESSAGE + 100
+#define RES_READ_ERROR RES_MESSAGE + 101
+#define RES_GENERAL_FAILURE RES_MESSAGE + 102
+#define RES_UNRECOVERABLE_DISK_ERROR RES_MESSAGE + 103
+#define RES_SKIPPED_SCRIPT_HEADER RES_MESSAGE + 104
+#define RES_SKIPPED_SCRIPT_ERROR RES_MESSAGE + 105
+#define RES_WAITING_FOR_OPEN RES_MESSAGE + 106
+#define RES_DISPLAY_VOLUME RES_MESSAGE + 107
+#define RES_CORRUPT_HEADER RES_MESSAGE + 108
+#define RES_CATALOG_MAINTENANCE_STATUS RES_MESSAGE + 109
+#define RES_CATALOG_DIRECTORY_STATUS RES_MESSAGE + 110
+#define RES_CATALOG_TAPE_SUCCESS_MSG RES_MESSAGE + 111
+#define RES_CATALOG_TAPE_ERROR_MSG RES_MESSAGE + 112
+#define RES_CATALOG_CONTINUATION_MSG RES_MESSAGE + 113
+#define RES_INSERT_CONTINUATION_MSG RES_MESSAGE + 114
+#define RES_INSERT_TAPE_TO_CATALOG_MSG RES_MESSAGE + 115
+#define RES_CAT_DELETE_SUCCESS_MSG RES_MESSAGE + 116
+#define RES_CAT_NO_ITEMS_MSG RES_MESSAGE + 117
+#define RES_FILE_DIFFERENT RES_MESSAGE + 118
+#define RES_ON_TAPE RES_MESSAGE + 119
+#define RES_ON_DISK RES_MESSAGE + 120
+#define RES_VERIFY_SCRIPT_HEADER RES_MESSAGE + 121
+#define RES_VERIFY_DATA_DIFFERENCE RES_MESSAGE + 122
+#define RES_VERIFY_OPEN_ERROR RES_MESSAGE + 123
+#define RES_VERIFY_DATA_VERIFIED RES_MESSAGE + 124
+#define RES_SKIPPING_REMOTE RES_MESSAGE + 125
+#define RES_CANT_SEARCH RES_MESSAGE + 126
+#define RES_DELETE_STARTED RES_MESSAGE + 127
+#define RES_DELETE_COMPLETED RES_MESSAGE + 128
+#define RES_DELETE_DIR_FILE RES_MESSAGE + 129
+#define RES_DELETE_DIR_FILES RES_MESSAGE + 130
+#define RES_DELETE_DIRS_FILES RES_MESSAGE + 131
+#define RES_DELETE_MAC RES_MESSAGE + 132
+#define RES_DELETE_MACS RES_MESSAGE + 133
+#define RES_RESTORE_FILE_PROMPT RES_MESSAGE + 134
+#define RES_ENTER_TAPE_PASSWORD RES_MESSAGE + 135
+#define RES_NO_TAPE_PASSWORD RES_MESSAGE + 136
+#define RES_CONFIRM_TAPE_PASSWORD RES_MESSAGE + 137
+#define RES_TAPE_PASSWORD_MISMATCH RES_MESSAGE + 138
+#define RES_TAPE_PASSWORD_MATCH RES_MESSAGE + 139
+#define RES_VERIFY_TAPE_PASSWORD RES_MESSAGE + 140
+#define RES_VERIFY_PASSWORD_MISMATCH RES_MESSAGE + 141
+#define RES_NO_PREVIOUS_MATCH RES_MESSAGE + 142
+#define RES_NO_NEXT_MATCH RES_MESSAGE + 143
+#define RES_TAPE_CREATED RES_MESSAGE + 144
+#define RES_TAPE_REQUEST RES_MESSAGE + 145
+#define RES_TAPE_FAMILY_CONTINUES_MSG RES_MESSAGE + 146
+#define RES_DIR_EMPTY_MSG RES_MESSAGE + 147
+#define RES_DIR_SUCCESS_MSG RES_MESSAGE + 148
+#define RES_CATALOG_A_TAPE_STATUS RES_MESSAGE + 149
+#define RES_FILE_NOT_FOUND RES_MESSAGE + 150
+#define RES_FILES_NOT_FOUND RES_MESSAGE + 151
+#define RES_DIRECTORY_NOT_FOUND RES_MESSAGE + 152
+#define RES_DIRECTORYS_NOT_FOUND RES_MESSAGE + 153
+#define RES_DIRECTORY_NOT_FOUND_ON_DISK RES_MESSAGE + 154
+#define RES_FULL_TAPE RES_MESSAGE + 155
+#define RES_TAPE_WEAR RES_MESSAGE + 156
+#define RES_INSERT_NEXT_TAPE RES_MESSAGE + 157
+#define RES_WRONG_TAPE RES_MESSAGE + 158
+#define RES_ARCHIVE_REPLACE_WARNING RES_MESSAGE + 159
+#define RES_CORRUPT_RESTORE_WARNING RES_MESSAGE + 160
+#define RES_OUT_OF_SEQUENCE_WARNING RES_MESSAGE + 161
+#define RES_RESTORE_SHORTER_WARNING RES_MESSAGE + 162
+#define RES_IMAGE_PERC_COMPLETE RES_MESSAGE + 163
+#define RES_IMAGE_BACKED_UP RES_MESSAGE + 164
+#define RES_IMAGE_RESTORED RES_MESSAGE + 165
+#define RES_IMAGE_VERIFIED RES_MESSAGE + 166
+#define RES_IMAGE_DIFFERENT RES_MESSAGE + 167
+#define RES_IMAGE_RESTORE_ERROR RES_MESSAGE + 168
+#define RES_ABORT_RETRY_FAIL RES_MESSAGE + 169
+#define RES_FAIL_KEY RES_MESSAGE + 170
+#define RES_FAIL_STRING RES_MESSAGE + 171
+#define RES_ABORT_KEY RES_MESSAGE + 172
+#define RES_ABORT_STRING RES_MESSAGE + 173
+#define RES_RETRY_KEY RES_MESSAGE + 174
+#define RES_RETRY_STRING RES_MESSAGE + 175
+#define RES_MISSING_NKS RES_MESSAGE + 176
+#define RES_MISSING_RSS RES_MESSAGE + 177
+#define RES_RESTORE_BINDERY RES_MESSAGE + 178
+#define RES_RESTORE_SECURITY RES_MESSAGE + 179
+#define RES_RESTORE_RECOVER RES_MESSAGE + 180
+#define RES_RECOVERED_FILE RES_MESSAGE + 181
+#define RES_RECOVERED_DIR RES_MESSAGE + 182
+#define RES_DATA_LOST RES_MESSAGE + 183
+#define RES_TENSION_STATUS_LABEL RES_MESSAGE + 184
+#define RES_ERASE_STATUS_LABEL RES_MESSAGE + 185
+#define RES_ERASE_QUEST RES_MESSAGE + 186
+#define RES_TENSION_STARTED RES_MESSAGE + 187
+#define RES_TENSION_COMPLETED RES_MESSAGE + 188
+#define RES_ERASE_STARTED RES_MESSAGE + 189
+#define RES_ERASE_COMPLETED RES_MESSAGE + 190
+#define RES_SEC_ERASE_STARTED RES_MESSAGE + 191
+#define RES_SEC_ERASE_COMPLETED RES_MESSAGE + 192
+#define RES_CATALOG_STARTED RES_MESSAGE + 193
+#define RES_CATALOG_COMPLETED RES_MESSAGE + 194
+#define RES_DISPLAY_TAPE RES_MESSAGE + 195
+#define RES_UNCATALOGED_TAPE RES_MESSAGE + 196
+#define RES_CATALOGED_SET RES_MESSAGE + 197
+#define RES_CATALOGED_SETS RES_MESSAGE + 198
+#define RES_CATALOG_QUEST RES_MESSAGE + 199
+#define RES_ALREADY_CATALOGED_SET RES_MESSAGE + 200
+#define RES_CATALOGING_ITEMS RES_MESSAGE + 201
+#define RES_CATALOG_NO_ITEMS RES_MESSAGE + 202
+#define RES_CATALOG_COMPACT_LABEL RES_MESSAGE + 203
+#define RES_CATALOG_COMPACT_PROMPT RES_MESSAGE + 204
+#define RES_CATALOG_INFO RES_MESSAGE + 205
+#define RES_CATALOG_SIZE RES_MESSAGE + 206
+#define RES_CATALOG_COMPACT_STARTED RES_MESSAGE + 207
+#define RES_CATALOG_COMPACT_COMPLETED RES_MESSAGE + 208
+#define RES_AVAILABLE_DISK_SPACE RES_MESSAGE + 209
+#define RES_CATALOG_TAPE_FAMILY RES_MESSAGE + 210
+#define RES_CATALOG_BSET RES_MESSAGE + 211
+#define RES_DELETE_QUEST RES_MESSAGE + 212
+#define RES_PROMPT_VERIFY_BACKUP RES_MESSAGE + 213
+#define RES_PROMPT_VERIFY_RESTORE RES_MESSAGE + 214
+#define RES_MESSAGE_TITLE RES_MESSAGE + 215
+#define RES_NEWLY_CATALOGED_SET RES_MESSAGE + 216
+#define RES_CAT_NO_TAPES_MSG RES_MESSAGE + 217
+#define RES_IMAGE_FOUND RES_MESSAGE + 218
+#define RES_NUM_IMAGE_FOUND RES_MESSAGE + 219
+#define RES_PAGE_UP_ONLY RES_MESSAGE + 220
+#define RES_PAGE_DOWN_ONLY RES_MESSAGE + 221
+#define RES_PAGE_UP_AND_DOWN RES_MESSAGE + 222
+#define RES_NONE_SOME_ALL RES_MESSAGE + 223
+#define RES_DRIVE_TYPES RES_MESSAGE + 224
+#define RES_COMPACTION_OUT_OF_SPACE RES_MESSAGE + 225
+#define RES_CATALOG_CLEANUP_STARTED RES_MESSAGE + 226
+#define RES_CATALOG_CLEANUP_COMPLETED RES_MESSAGE + 227
+#define RES_CATALOGING_IN_PROGRESS RES_MESSAGE + 228
+#define RES_CATALOGING_COMPLETE RES_MESSAGE + 229
+#define RES_TAPE_SELECTION_STATUS RES_MESSAGE + 230
+#define RES_TARGET_DRIVE_WINDOW RES_MESSAGE + 231
+#define RES_ALL_FILES_SELECTED RES_MESSAGE + 232
+#define RES_NO_FILES_SELECTED RES_MESSAGE + 233
+#define RES_SOME_FILES_SELECTED RES_MESSAGE + 234
+#define RES_SEARCHING_FILES RES_MESSAGE + 235
+#define RES_SEARCH_NO_ITEMS_FOUND RES_MESSAGE + 236
+#define RES_CHECKING_DRIVE RES_MESSAGE + 237
+#define RES_POSITION_TAPE RES_MESSAGE + 238
+#define RES_CATALOG_ERASED_TAPE RES_MESSAGE + 239
+#define RES_CATALOG_NO_INFORMATION RES_MESSAGE + 240
+#define RES_TAPE_FILE_SELECT_TAPE RES_MESSAGE + 241
+#define RES_TAPE_FILE_SELECT_LINE2 RES_MESSAGE + 242
+#define RES_FILE_OPEN_ERROR RES_MESSAGE + 243
+#define RES_NOTICES_TITLE RES_MESSAGE + 244
+#define RES_BUILDING_DIRECTORY RES_MESSAGE + 245
+#define RES_VM_CRITICAL_ERROR RES_MESSAGE + 246
+#define RES_EMPTY_TREE_WARNING RES_MESSAGE + 247
+#define RES_ERASE_CAT_WARNING RES_MESSAGE + 248
+#define RES_CONTINU_FILE_WARNING RES_MESSAGE + 249
+#define RES_CONTINU_FILE_PROMPT RES_MESSAGE + 250
+#define RES_CONTINU_IMAGE_WARNING RES_MESSAGE + 251
+#define RES_CATALOG_REPAIR_LABEL RES_MESSAGE + 252
+#define RES_CATALOG_REPAIR_STARTED RES_MESSAGE + 253
+#define RES_CATALOG_REPAIR_COMPLETE RES_MESSAGE + 254
+#define RES_CATALOG_RECREATE_PROMPT RES_MESSAGE + 255
+#define RES_CATALOG_REPAIR_OUT_OF_SPACE RES_MESSAGE + 256
+#define RES_INSERT_MULTI_TAPES RES_MESSAGE + 257
+#define RES_TAPE_DRIVE_NAME RES_MESSAGE + 258
+#define RES_PRODUCT_DESCRIPT RES_MESSAGE + 259
+#define RES_WAIT_AND_REPLACE_TAPE RES_MESSAGE + 260
+#define RES_MAKE_ANOTHER_COPY RES_MESSAGE + 261
+#define RES_ANY_KEY_ESC RES_MESSAGE + 262
+#define RES_DIRECTORY_DIFFERENT RES_MESSAGE + 263
+#define RES_IMAGE_LOGING_WARNING RES_MESSAGE + 264
+#define RES_CATALOG_LEVEL_ZERO RES_MESSAGE + 265
+#define RES_SECURITY_DIFFERENCE RES_MESSAGE + 266
+#define RES_SECURITY_DIFFERENCES RES_MESSAGE + 267
+#define RES_INSUFFICIENT_PRIVILEGE RES_MESSAGE + 268
+#define RES_INSUFFICIENT_DISK_SPACE RES_MESSAGE + 269
+#define RES_ERROR_CREATING_FILE RES_MESSAGE + 270
+#define RES_ERROR_CREATING_DIR RES_MESSAGE + 271
+#define RES_ERROR_RESTORING_AFP_FILE RES_MESSAGE + 272
+#define RES_ERROR_RESTORING_FILE RES_MESSAGE + 273
+#define RES_ERROR_RESTORING_DIR RES_MESSAGE + 274
+#define RES_ERROR_RESTORING_FILE_SEC RES_MESSAGE + 275
+#define RES_ERROR_RESTORING_DIR_SEC RES_MESSAGE + 276
+#define RES_ERROR_RESTORING_TRUSTEE_SEC RES_MESSAGE + 277
+#define RES_EMPTY_DIRECTORY_MESSAGE RES_MESSAGE + 278
+#define RES_CATALOGING_AT_LEVEL_ZERO RES_MESSAGE + 279
+#define RES_CATALOG_DELETE_COMPLETE RES_MESSAGE + 280
+#define RES_CATALOGING_TERMINATED RES_MESSAGE + 281
+#define RES_SEARCHING_NEXT_FILE RES_MESSAGE + 282
+#define RES_MENU_CONTINUE RES_MESSAGE + 283
+#define RES_TEMP_CAT_WARNING RES_MESSAGE + 284
+#define RES_SKIP_CONTINUE RES_MESSAGE + 285
+#define RES_OS_FILE_INFO_DIFFERENT RES_MESSAGE + 286
+#define RES_FULLY_CATALOGED_TAPE RES_MESSAGE + 287
+#define RES_TAPE_FILE_SELECT_BSET RES_MESSAGE + 288
+#define RES_BACKUP_SET_BYTES RES_MESSAGE + 289
+#define RES_NOT_CATALOGING_WARNING RES_MESSAGE + 290
+#define RES_MORE RES_MESSAGE + 291
+#define RES_CONVERT_MAC_BSET RES_MESSAGE + 292
+#define RES_SCRIPT_MARKER RES_MESSAGE + 293
+#define RES_NO_DRIVER_LOADED RES_MESSAGE + 294
+#define RES_SERVER_LOGOUT_DENIED RES_MESSAGE + 295
+#define RES_BAD_ATTR_READ RES_MESSAGE + 296
+#define RES_DISPLAY_BSD_VCB RES_MESSAGE + 297
+#define RES_DETERMINING_LBAS RES_MESSAGE + 298
+#define RES_SKIPPED_DEVICE RES_MESSAGE + 299
+#define RES_ERROR_DURING_OPERATION RES_MESSAGE + 300
+#define RES_ERROR_FILE_TO_EXAMINE RES_MESSAGE + 301
+#define RES_FILE_SECURITY_DIFF RES_MESSAGE + 302
+#define RES_FILE_EA_DIFF RES_MESSAGE + 303
+#define RES_FILE_RES_DIFF RES_MESSAGE + 304
+#define RES_SET_LAD_STARTED RES_MESSAGE + 305
+#define RES_SET_LAD_COMPLETED RES_MESSAGE + 306
+#define RES_ERROR_SETTING_LAD RES_MESSAGE + 307
+#define RES_NOERROR_DURING_OPERATION RES_MESSAGE + 308
+#define RES_NO_TRANSFER_APPEND RES_MESSAGE + 309
+#define RES_MKT_VER_MAJ RES_MESSAGE + 310
+#define RES_MKT_VER_MIN RES_MESSAGE + 311
+#define RES_ENG_VER_MAJ RES_MESSAGE + 312
+#define RES_ENG_VER_MIN RES_MESSAGE + 313
+#define RES_EMPTY_DIR_WARNING RES_MESSAGE + 314
+#define RES_BACKUP_BINDERY RES_MESSAGE + 315
+#define RES_RECOVERY_PROMPT RES_MESSAGE + 316
+#define RES_USER_INPUT RES_MESSAGE + 317
+#define RES_CONNECTION_PASSWORD RES_MESSAGE + 318
+#define RES_REPLACE_SCRIPT RES_MESSAGE + 319
+#define RES_TAPE_NAME RES_MESSAGE + 320
+#define RES_BACKUP_SET_NAME RES_MESSAGE + 321
+#define RES_BACKUP_SET_DESCR RES_MESSAGE + 322
+#define RES_DISPLAY_VERIFY_INFO RES_MESSAGE + 323
+#define RES_CATALOG_TITLE RES_MESSAGE + 324 /* open for use */
+#define RES_DELETE_TITLE RES_MESSAGE + 325 /* open for use */
+#define RES_ERASE_BAD_TAPE RES_MESSAGE + 326
+#define RES_TARGET_TRANSFER_TITLE RES_MESSAGE + 327
+#define RES_ERASE_FOREIGN_TAPE RES_MESSAGE + 328
+#define RES_ERASE_BLANK_TAPE RES_MESSAGE + 329
+#define RES_ERASE_NO_TAPE RES_MESSAGE + 330
+#define RES_ERASE_TAPE_INFO1 RES_MESSAGE + 331
+#define RES_ERASE_TAPE_INFO2 RES_MESSAGE + 332
+#define RES_ABORT_QUESTION RES_MESSAGE + 333
+#define RES_PROCESS_ABORTED RES_MESSAGE + 334
+#define RES_ERASE_DRIVE_BUSY RES_MESSAGE + 335
+#define RES_NEED_NEXT_TAPE RES_MESSAGE + 336
+#define RES_TAPE_FULL RES_MESSAGE + 337
+#define RES_RESTORE_DESC_1 RES_MESSAGE + 338
+#define RES_RETENSION_MESSAGE RES_MESSAGE + 339
+#define RES_TITLE_NEW_LINE RES_MESSAGE + 340
+#define RES_NEXT_SET RES_MESSAGE + 341
+#define RES_NO_NEXT_SET RES_MESSAGE + 342
+#define RES_FOUND_BSET RES_MESSAGE + 343
+#define RES_ERASE_POLL_DRIVE_DISABLED RES_MESSAGE + 344
+#define RES_POLL_DRIVE_BAD_TAPE RES_MESSAGE + 345
+#define RES_POLL_DRIVE_GOOFY_TAPE RES_MESSAGE + 346
+#define RES_KEEP_CURRENT_SETTINGS RES_MESSAGE + 347
+#define RES_ERASE_PWDB RES_MESSAGE + 348
+#define RES_PWDB_DISABLED RES_MESSAGE + 349
+#define RES_PWDB_BAD_CONFIRM RES_MESSAGE + 350
+#define RES_INIT_FILE_SYSTEM RES_MESSAGE + 351
+#define RES_INIT_HARDWARE RES_MESSAGE + 352
+#define RES_INIT_APPLICATION RES_MESSAGE + 353
+#define RES_APPLICATION_INIT RES_MESSAGE + 354
+#define RES_INIT_VLM RES_MESSAGE + 355
+#define RES_OPENING_LOG_NAME RES_MESSAGE + 356
+#define RES_ERROR_ATTACHING RES_MESSAGE + 357
+#define RES_CLOSING_LOG_NAME RES_MESSAGE + 358
+#define RES_ALREADY_FULLY_CATALOGED RES_MESSAGE + 359
+#define RES_VLM_BLANK_TAPE RES_MESSAGE + 360
+#define RES_VLM_FOREIGN_TAPE RES_MESSAGE + 361
+#define RES_VLM_BAD_TAPE RES_MESSAGE + 362
+#define RES_FILE_WAS_SKIPPED RES_MESSAGE + 363
+#define RES_FILE_WAS_SKIPPED_USER RES_MESSAGE + 364
+#define RES_IMAGE_BACKUP RES_MESSAGE + 365
+#define RES_VLM_NO_TAPE RES_MESSAGE + 366
+#define RES_VLM_BUSY_DRIVE RES_MESSAGE + 367
+#define RES_VLM_UNFORMATED_TAPE RES_MESSAGE + 368
+#define RES_FILE_DETAIL RES_MESSAGE + 369
+#define RES_BACKED_UP_DIRS_FILE RES_MESSAGE + 370
+#define RES_CONTINUE_BACKUP_ABORT RES_MESSAGE + 371 // chs:02-08-93
+#define RES_NEW_PROCESSED_BYTES RES_MESSAGE + 372
+#define RES_BYTES_PROCESSED RES_MESSAGE + 373
+#define RES_BYTES_PROCESSED_HOUR RES_MESSAGE + 374
+#define RES_BYTES_PROCESSED_HOURS RES_MESSAGE + 375
+#define RES_BYTES_PROCESSED_MINUTE1 RES_MESSAGE + 376
+#define RES_BYTES_PROCESSED_MINUTES1 RES_MESSAGE + 377
+#define RES_BYTES_PROCESSED_MINUTE2 RES_MESSAGE + 378
+#define RES_BYTES_PROCESSED_MINUTES2 RES_MESSAGE + 379
+#define RES_BYTES_PROCESSED_SECOND RES_MESSAGE + 380
+#define RES_BYTES_PROCESSED_SECONDS RES_MESSAGE + 381
+#define RES_DISPLAY_VOLUME_1 RES_MESSAGE + 382
+#define RES_CONTINUE_RESTORE_ABORT RES_MESSAGE + 383 // chs:02-08-93
+
+//
+// ABORT ERROR STRING
+//
+
+#define RES_CURRENT_FILE RES_MESSAGE + 384
+#define RES_UNUSED RES_MESSAGE + 385
+#define RES_BACKUP_ABORT_EOF RES_MESSAGE + 386
+#define RES_RESTORE_ABORT_EOF RES_MESSAGE + 387
+
+#define RES_RESTORED_DIRS_FILE RES_MESSAGE + 388 // chs:02-11-93
+
+#define RES_FORMAT_TAPE_WARNING RES_MESSAGE + 389
+#define RES_FORMAT_DIALOG_TITLE RES_MESSAGE + 390
+
+#define RES_FORMAT_STARTED RES_MESSAGE + 391
+#define RES_FORMAT_COMPLETED RES_MESSAGE + 392
+#define RES_ABORT_OPERATION RES_MESSAGE + 393
+
+#define RES_SEARCHING_FOR_EOD RES_MESSAGE + 394
+#define RES_DRIVE_ERROR_DETECTED RES_MESSAGE + 395
+#define RES_OPERATION_COMPLETED RES_MESSAGE + 396 // chs:04-30-93
+#define RES_TAPE_FULL_REWOUND RES_MESSAGE + 397 // chs:05-03-93
+#define RES_NEED_NEXT_TAPE_REWOUND RES_MESSAGE + 398 // chs:05-10-93
+#define RES_INSERT_NEXT_TAPE_REWOUND RES_MESSAGE + 399 // chs:05-10-93
+#define RES_ACTIVE_FILES_RESTORED RES_MESSAGE + 400
+#define RES_SAME_TAPE_FAMILY RES_MESSAGE + 401 // chs:05-20-93
+#define RES_FOREIGN_TAPE_MSG2 RES_MESSAGE + 402
+
+#define RES_BACKUP_ABORT_PART2 RES_MESSAGE + 403 // chs:05-25-93
+#define RES_RESTORE_ABORT_PART2 RES_MESSAGE + 404 // chs:05-25-93
+#define RES_DELETE_DIRS_FILE RES_MESSAGE + 405 // chs:05-26-93
+
+#define RES_HW_COMP_FAILURE RES_MESSAGE + 406 // chs:06-01-93
+#define RES_HW_UNCOMP_FAILURE RES_MESSAGE + 407 // chs:06-01-93
+#define RES_RESUME_PROCESS RES_MESSAGE + 408 // chs:07-13-93
+
+#define RES_USE_TAPE_CATALOGS RES_MESSAGE + 409
+#define RES_VLM_ECC_TAPE RES_MESSAGE + 410
+#define RES_VLM_FUTURE_TAPE RES_MESSAGE + 411
+
+#define RES_NOAPPEND RES_MESSAGE + 412
+#define RES_NODISKSPACE RES_MESSAGE + 413
+
+#define RES_COMM_FAILURE RES_MESSAGE + 414
+#define RES_FILE_NOT_DELETED RES_MESSAGE + 415
+#define RES_DIRECTORY_NOT_DELETED RES_MESSAGE + 416
+#define RES_VLM_GOOFY_TAPE RES_MESSAGE + 417
+#define RES_USESYPLFLAG RES_MESSAGE + 418
+#define RES_VLM_SQL_TAPE RES_MESSAGE + 419
+
+// LOADER
+#define RES_LDR_DUPLICATE_MAG_NAME RES_MESSAGE + 420
+#define RES_LDR_INVALID_MAG_SIZE RES_MESSAGE + 421
+#define RES_LDR_GROUP_NAME_NOT_FOUND RES_MESSAGE + 422
+#define RES_LDR_DUPLICATE_GROUP_NAME RES_MESSAGE + 423
+#define RES_LDR_INVALID_STATING_SLOT RES_MESSAGE + 424
+#define RES_LDR_INVALID_NUMBER_SLOTS RES_MESSAGE + 425
+#define RES_LDR_SLOT_IN_USE RES_MESSAGE + 426
+#define RES_LDR_BAD_MAG_NAME RES_MESSAGE + 427
+#define RES_LDR_WRONG_CONF RES_MESSAGE + 428
+#define RES_LDR_ERASING_GROUP RES_MESSAGE + 429
+#define RES_LDR_OPERATION_ABORTED RES_MESSAGE + 430
+#define RES_LDR_STARTING_TAPE_GROUP RES_MESSAGE + 431
+#define RES_LDR_DEFAULT_SLOTS RES_MESSAGE + 432
+#define RES_LDR_DEFAULT_SLOT RES_MESSAGE + 433
+#define RES_LDR_NO_SELECTION RES_MESSAGE + 434
+// LOADER
+
+#define RES_RESTOREWRITEERROR RES_MESSAGE + 435
+
+#endif
diff --git a/private/utils/ntbackup/inc/entrydat.h b/private/utils/ntbackup/inc/entrydat.h
new file mode 100644
index 000000000..906f25735
--- /dev/null
+++ b/private/utils/ntbackup/inc/entrydat.h
@@ -0,0 +1,57 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: entrydat.h
+
+ Description: Defines and prototypes for entry validation routines
+
+
+ $Log: G:/UI/LOGFILES/ENTRYDAT.H_V $
+
+ Rev 1.1 04 Oct 1992 19:47:04 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.0 20 Nov 1991 19:36:46 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifndef ENTRYDAT_H
+#define ENTRYDAT_H
+
+/* begin include list */
+#include "dw.h"
+/* $end$ include list */
+
+#define OUTPUT_ALL_ITEMS 13
+#define OUTPUT_PRT_ITEMS 9
+#define OUTPUT_NO_ITEMS 3
+
+
+INT16 chk_output_level( WDATA_PNTR, CHAR_PTR ) ;
+INT16 chk_valid_file_no_wild( WDATA_PNTR, CHAR_PTR ) ;
+INT16 chk_output_mode( WDATA_PNTR, CHAR_PTR ) ;
+INT16 chk_net_num( WDATA_PNTR, CHAR_PTR ) ;
+INT16 chk_valid_date( WDATA_PNTR, CHAR_PTR ) ;
+INT16 chk_valid_path( WDATA_PNTR, CHAR_PTR ) ;
+INT16 chk_valid_generic_path( WDATA_PNTR, CHAR_PTR ) ;
+INT16 chk_valid_generic_file( WDATA_PNTR, CHAR_PTR ) ;
+
+INT16 chk_valid_device_path( WDATA_PNTR, CHAR_PTR ) ;
+INT16 chk_valid_device_file( WDATA_PNTR, CHAR_PTR ) ;
+
+INT16 chk_valid_file( WDATA_PNTR, CHAR_PTR ) ;
+INT16 chk_file_name( WDATA_PNTR, CHAR_PTR, BOOLEAN ) ;
+INT16 chk_f_or_p_option( WDATA_PNTR, CHAR_PTR ) ;
+INT16 chk_output_level( WDATA_PNTR, CHAR_PTR ) ;
+INT16 all_strings_valid( WDATA_PNTR, CHAR_PTR ) ;
+INT16 chk_valid_yes_no( WDATA_PNTR, CHAR_PTR ) ;
+INT16 chk_valid_yes_no_prompt( WDATA_PNTR, CHAR_PTR ) ;
+INT16 chk_catalog_level( WDATA_PNTR, CHAR_PTR ) ;
+INT16 chk_valid_unknown_bset( WDATA_PNTR, CHAR_PTR ) ;
+INT16 chk_valid_numeral( WDATA_PNTR, CHAR_PTR ) ;
+INT16 chk_valid_yes_no_autodetermine( WDATA_PNTR, CHAR_PTR ) ;
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/erase.h b/private/utils/ntbackup/inc/erase.h
new file mode 100644
index 000000000..9dece1a8f
--- /dev/null
+++ b/private/utils/ntbackup/inc/erase.h
@@ -0,0 +1,52 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: erase.h
+
+ Description:
+
+
+ $Log: G:/UI/LOGFILES/ERASE.H_V $
+
+ Rev 1.4 13 Nov 1992 17:45:24 chrish
+Added some stuff for formatting a tape radio button in the erase.
+
+ Rev 1.3 04 Oct 1992 19:47:04 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.2 06 Apr 1992 09:53:28 CHUCKB
+Added define for translation.
+
+ Rev 1.1 27 Mar 1992 10:29:52 DAVEV
+OEM_MSOFT: add id for Quick Erase button
+
+ Rev 1.0 20 Nov 1991 19:37:02 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_ERASE 39
+#else
+#include "dlg_ids.h"
+#endif
+
+#ifndef ERASE_H
+#define ERASE_H
+
+#define IDM_ERASE 322
+#define IDD_ERASE_LINE1 130
+#define IDD_ERASE_LINE2 131
+#define IDD_ERASE_LINE3 132
+#define IDD_ERASE_CONTINUE_BUTTON 101
+#define IDD_ERASE_CANCEL_BUTTON 102
+#define IDD_ERASE_HELP_BUTTON 103
+#define IDD_ERASE_FORMAT_BUTTON 104
+#define IDD_ERASE_QUICK_BUTTON 105 //OEM_MSOFT use only
+#define IDD_ERASE_SECURE_BUTTON 106
+#define IDD_ERASE_EXCLAMATION_BITMAP 107
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/err_stgs.h b/private/utils/ntbackup/inc/err_stgs.h
new file mode 100644
index 000000000..bf3840ae0
--- /dev/null
+++ b/private/utils/ntbackup/inc/err_stgs.h
@@ -0,0 +1,11 @@
+
+// defines for error messages
+
+#define IDS_JOBIOERR 2000 // is this the highest prime?
+#define IDS_SCHEDULEIOERR (IDS_JOBIOERR+1)
+#define IDS_FOPENERR (IDS_SCHEDULEIOERR+1)
+#define IDS_FREADERR (IDS_FOPENERR+1)
+#define IDS_FWRITEERR (IDS_FREADERR+1)
+#define IDS_FCLOSEERR (IDS_FWRITEERR+1)
+
+
diff --git a/private/utils/ntbackup/inc/error.h b/private/utils/ntbackup/inc/error.h
new file mode 100644
index 000000000..bce5806b6
--- /dev/null
+++ b/private/utils/ntbackup/inc/error.h
@@ -0,0 +1,31 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: error.h
+
+ Description:
+
+
+ $Log: G:/UI/LOGFILES/ERROR.H_V $
+
+ Rev 1.2 04 Oct 1992 19:47:06 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.1 28 Jul 1992 14:55:06 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.0 20 Nov 1991 19:39:22 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifndef _error_h_
+#define _error_h_
+
+VOID eprintf( CHAR_PTR, ... ) ;
+VOID eresprintf( INT, ... ) ;
+
+BOOLEAN eresprintf_cancel( INT, ... ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/esa.h b/private/utils/ntbackup/inc/esa.h
new file mode 100644
index 000000000..595f0b248
--- /dev/null
+++ b/private/utils/ntbackup/inc/esa.h
@@ -0,0 +1,124 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-92
+
+
+ Name: esa.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Extanded Status Array (ESA)
+ The value of byte zero in the Extended Status Array
+ determines the type of data contained within bytes one
+ through seven. ESA_STATUS_TYPE_IDX is used as an index to
+ byte zero. Note that the high bit of byte zero identifies
+ the array as being either four or eight bytes as shown
+ below.
+
+
+ Location: RET_BUF, CHANNEL, and TPOS
+
+
+ $Log: O:/LOGFILES/ESA.H_V $
+
+ Rev 1.2 25 Jan 1993 10:08:38 TIMN
+Fixed MOVE_ESA macro
+
+**/
+/* $end$ include list */
+
+#ifndef _ESA
+#define _ESA
+
+/*------------------------------------------------------------------------------------------------------|
+| Status Type | E x t e n d e d S t a t u s A r r a y |
+| Discription | |
+|---------------|---------------------------------------------------------------------------------------|
+| |Byte 0 |Byte 1 |Byte 2 |Byte 3 |Byte 4 |Byte 5 |Byte 6 |Byte 7 |
+|-------------------------------------------------------------------------------------------------------|
+|QIC 02 |0x00 |0x00 |Execption |Execption | |
+| | | |Status |Status | |
+| | | |(Byte 0) |(Byte 1) | |
+|------------------------------------------------------------ |
+|SCSI 1 |0x01 |Sense Key |0x00 |0x00 | |
+| | |(Byte 2) | | | |
+|------------------------------------------------------------ |
+|SCSI 2 |0x02 |Sense Key |ASC |ASCQ | |
+| | |(Byte 2) |(Byte 12) |(Byte 13) | |
+|------------------------------------------------------------ |
+|Reserved |0x03-0x0E | | | | |
+|(Standard) | | | | | |
+|------------------------------------------------------------ |
+|SCSI 2 |0x0F |Sense Key |ASC |ASCQ | |
+|Translation | | | | | |
+|------------------------------------------------------------ |
+|Exabyte 8500 |0x10 |Sense Key |ASC |ASCQ | |
+| | |(Byte 2) | | | |
+|------------------------------------------------------------ |
+|Reserved |0x11-0x7F | | | | |
+|(Vendor Unique)| | | | | |
+|-------------------------------------------------------------------------------------------------------|
+|QIC 02 |0x80 |0x00 |Execption |Execption |Execption |Execption |Execption |Execption |
+| | | |Status |Status |Status |Status |Status |Status |
+| | | |(Byte 0) |(Byte 1) |(Byte 2) |(Byte 3) |(Byte 4) |(Byte 5) |
+|-------------------------------------------------------------------------------------------------------|
+|SCSI 1 |0x81 |Sense Key |0x00 |0x00 |0x00 |0x00 |0x00 |0x00 |
+| | |(Byte 2) | | | | | | |
+|-------------------------------------------------------------------------------------------------------|
+|SCSI 2 |0x82 |Sense Key |ASC |ASCQ |0x00 |0x00 |0x00 |0x00 |
+| | |(Byte 2) |(Byte 12) |(Byte 13) | | | | |
+|-------------------------------------------------------------------------------------------------------|
+|Reserved |0x83-0x8E | |
+|(Standard) | | |
+|-------------------------------------------------------------------------------------------------------|
+|SCSI 2 |0x8F |Sense Key |ASC |ASCQ |0x00 |0x00 |0x00 |0x00 |
+|Translation | | | | | | | | |
+|-------------------------------------------------------------------------------------------------------|
+|VP525 |0x90 |Sense Key |0x00 |0x00 |Extended |Extended |0x00 |0x00 |
+| | |(Byte 2) | | |Sense |Sense | | |
+| | | | | |(Byte 10) |(Byte 11) | | |
+|-------------------------------------------------------------------------------------------------------|
+|Exabyte |0x91 |Sense Key |ASC |ASCQ |Extended |Extended |Extended |0x00 |
+| | |(Byte 2) |(Byte 12) |(Byte 13) |Sense |Sense |Sense | |
+| | | | | |(Byte 19) |(Byte 20) |(Byte 21) | |
+|-------------------------------------------------------------------------------------------------------|
+|Reserved |0x92-0xFF | |
+|(Vendor Unique)| | |
+|------------------------------------------------------------------------------------------------------*/
+
+#define ESA_ARRAY_LENGTH 8
+#define ESA_STATUS_TYPE_IDX 0
+ /* Use when QIC 02 | See comment above for use */
+#define ESA_SENSE_KEY_IDX 1 /* ------------------------|-------------------------------------- */
+#define ESA_EXC0_OR_ASC_IDX 2 /* EXC0 = Exception Status | ASC = Additonal Sense Code */
+#define ESA_EXC1_OR_ASCQ_IDX 3 /* EXC1 | ASCQ = Additonal Sense Code Qualifier */
+#define ESA_EXC2_OR_EXT0_IDX 4 /* EXC2 | EXT0 = Extended Sence */
+#define ESA_EXC3_OR_EXT1_IDX 5 /* EXC3 | EXT1 */
+#define ESA_EXC4_OR_EXT2_IDX 6 /* EXC4 | EXT2 */
+#define ESA_EXC5_IDX 7 /* EXC5 | */
+
+
+typedef struct {
+ UINT16 esa_valid ;
+ UINT8 esa[ ESA_ARRAY_LENGTH ]; /* Extended Status Array */
+} ESA ;
+
+#define ESA_VALIDITY 0xFACE
+
+/**
+ Macro Definitions
+**/
+
+#define VALID_ESA(ESAfrom) ((ESAfrom).esa_valid == ESA_VALIDITY)
+
+#define MAKE_ESA_VALID(esa) ((esa).esa_valid = ESA_VALIDITY)
+
+#define MAKE_ESA_INVALID(esa) ((esa).esa_valid = 0)
+
+#ifdef MS_DEBUG
+# define MOVE_ESA(to,from) \
+ if ( VALID_ESA( from ) ) { (to) = (from) ; }
+#else
+# define MOVE_ESA(to,from)
+#endif
+
+#endif /* end file */
diff --git a/private/utils/ntbackup/inc/f31proto.h b/private/utils/ntbackup/inc/f31proto.h
new file mode 100644
index 000000000..50f604e8e
--- /dev/null
+++ b/private/utils/ntbackup/inc/f31proto.h
@@ -0,0 +1,50 @@
+/*
+ $Log: T:/LOGFILES/F31PROTO.H_V $
+ *
+ * Rev 1.7 18 Nov 1992 10:39:46 HUNTER
+ * Bug Fixes
+ *
+ *
+ * Rev 1.6 11 Nov 1992 09:50:06 HUNTER
+ * Deleted write prototypes and modified other prototypes.
+ *
+ * Rev 1.5 19 Nov 1991 08:56:16 GREGG
+ * VBLK - Corrected prototype misspelling.
+ *
+ * Rev 1.4 18 Nov 1991 19:59:18 GREGG
+ * Added BOOLEAN abort parameter to F31_WtCloseSet and F31_WtVCB.
+ *
+ * Rev 1.3 07 Nov 1991 15:25:44 unknown
+ * VBLK - Added support for MaynStream v3.1
+ *
+ *
+ * Rev 1.2 16 Sep 1991 20:08:20 GREGG
+ * Changed prototype for SetupFormatEnv to return TFLE_xxx.
+ *
+ * Rev 1.1 03 Jun 1991 10:36:30 NED
+ * added parameter to MoveToVCB()
+ *
+ * Rev 1.0 10 May 1991 15:33:02 GREGG
+ * Initial revision.
+
+*/
+
+#ifndef _F31_PROTOS
+#define _F31_PROTOS
+
+INT16 F31_Initialize( CHANNEL_PTR ) ;
+VOID F31_DeInitialize( VOID_PTR * ) ;
+BOOLEAN F31_Determiner( VOID_PTR ) ;
+UINT16 F31_SizeofTBLK( VOID_PTR ) ;
+INT16 F31_DetBlkType( CHANNEL_PTR, BUF_PTR, UINT16_PTR ) ;
+UINT16 F31_RdException( CHANNEL_PTR, INT16 ) ;
+UINT16 F31_CalculatePad( UINT16, UINT32, UINT16 ) ;
+INT16 F31_RdVCB( CHANNEL_PTR, BUF_PTR ) ;
+INT16 F31_RdDDB( CHANNEL_PTR, BUF_PTR ) ;
+INT16 F31_RdFDB( CHANNEL_PTR, BUF_PTR ) ;
+INT16 F31_RdCFDB( CHANNEL_PTR, BUF_PTR ) ;
+INT16 F31_RdUDB( CHANNEL_PTR, BUF_PTR ) ;
+BOOLEAN F31_RdContTape( CHANNEL_PTR, BUF_PTR ) ;
+INT16 F31_MoveToVCB( CHANNEL_PTR, INT16, BOOLEAN_PTR, BOOLEAN ) ;
+INT16 F31_RdStream( CHANNEL_PTR, BUF_PTR ) ;
+#endif
diff --git a/private/utils/ntbackup/inc/f40proto.h b/private/utils/ntbackup/inc/f40proto.h
new file mode 100644
index 000000000..de8f24ddd
--- /dev/null
+++ b/private/utils/ntbackup/inc/f40proto.h
@@ -0,0 +1,242 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-92
+
+
+ Name: mayn40.h
+
+ Description: Maynard's 4.0 Format prototypes. See the Document for
+ complete details.
+
+
+ $Log: T:/LOGFILES/F40PROTO.H_V $
+
+ Rev 1.32 20 Oct 1993 19:37:04 GREGG
+Added string type conversion of tape name password if THDR type != SSET type.
+
+ Rev 1.31 08 Sep 1993 13:26:46 GREGG
+Changed proto of F40_InitTape to match version 1.27 of mtf10wdb.c.
+
+ Rev 1.30 17 Jul 1993 17:56:54 GREGG
+Changed write translator functions to return INT16 TFLE_xxx errors instead
+of BOOLEAN TRUE/FALSE. Files changed:
+ MTF10WDB.C 1.23, TRANSLAT.H 1.22, F40PROTO.H 1.30, FMTENG.H 1.23,
+ TRANSLAT.C 1.43, TFWRITE.C 1.68, MTF10WT.C 1.18
+
+ Rev 1.29 22 Jun 1993 10:53:30 GREGG
+Added API to change the catalog directory path.
+
+ Rev 1.28 08 Jun 1993 00:05:38 GREGG
+Fix for bug in the way we were handling EOM and continuation OTC entries.
+Files modified for fix: mtf10wt.c, otc40wt.c, otc40msc.c f40proto.h mayn40.h
+
+ Rev 1.27 29 Apr 1993 22:26:54 GREGG
+Added proto for F40_StartRead (new in mayn40rd.c).
+
+ Rev 1.26 25 Apr 1993 17:36:04 GREGG
+Fourth in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Parse the device name and volume name out of the FS supplied "volume
+ name", and write it to tape as separate fields.
+ - Generate the "volume name" the FS and UI expect out of the device
+ name and volume name on tape.
+ - Write all strings without NULL terminater, and translate them back
+ to NULL terminated strings on the read side.
+
+Matches: MTF10WDB.C 1.8, F40PROTO.H 1.26, OTC40WT.C 1.24, MAYN40.H 1.33,
+ MAYN40RD.C 1.57, OTC40RD.C 1.25
+
+ Rev 1.25 18 Apr 1993 00:48:46 GREGG
+First in a series of incremental changes to bring the translator in line
+with the MTF spec:
+ - Changed prototype for F40_SaveLclName (CHAR_PTRs are now UINT8_PTRs).
+
+Matches: MTF10WDB.C 1.6, MTF10WT.C 1.6, MAYN40RD.C 1.53 and MAYN40.H 1.31
+
+ Rev 1.24 09 Mar 1993 18:14:48 GREGG
+Initial changes for new stream and EOM processing.
+
+ Rev 1.23 27 Jan 1993 14:42:56 GREGG
+Added prototypes of formerly static function due to the split of mayn40wt.c.
+
+ Rev 1.22 26 Jan 1993 01:30:58 GREGG
+Added Fast Append functionality.
+
+ Rev 1.21 07 Dec 1992 23:36:16 GREGG
+Removed proto for OTC_GetDataSize (it no longer exists).
+
+ Rev 1.20 02 Dec 1992 13:49:12 GREGG
+Changed proto for F40_GetBlkType (unicode fix).
+
+ Rev 1.19 24 Nov 1992 18:18:30 GREGG
+Updates to match MTF document.
+
+ Rev 1.18 23 Nov 1992 12:17:44 GREGG
+Fixed Prototype for F40_ParseEOM().
+
+ Rev 1.17 23 Nov 1992 10:59:58 HUNTER
+Changed Prototype for F40_ParseEOM().
+
+ Rev 1.16 23 Nov 1992 10:20:18 HUNTER
+Added prototype for F40_ParseEOM().
+
+ Rev 1.15 23 Nov 1992 10:05:46 GREGG
+Changes for path in stream.
+
+ Rev 1.14 09 Nov 1992 10:49:20 GREGG
+Added and altered prototypes for new OTC method.
+
+ Rev 1.13 03 Nov 1992 09:37:02 HUNTER
+Changes for Stream Stuff
+
+ Rev 1.12 22 Oct 1992 10:51:14 HUNTER
+changes for new stream header stuff
+
+ Rev 1.11 25 Sep 1992 09:30:32 GREGG
+Added F40_RdEOSPadBlk prototype.
+
+ Rev 1.10 22 Sep 1992 09:01:42 GREGG
+Initial changes to handle physical block sizes greater than 1K.
+
+ Rev 1.9 30 Jul 1992 16:48:54 GREGG
+Added protos for formerly static functions.
+
+ Rev 1.8 01 Jul 1992 18:34:46 GREGG
+Added protos for date conversion routines.
+
+ Rev 1.7 09 Jun 1992 16:03:52 GREGG
+Added proto for F40_CalcChecksum.
+
+ Rev 1.6 08 Jun 1992 16:56:22 GREGG
+Changed return type for F40_SaveLclName.
+
+ Rev 1.5 01 Jun 1992 15:49:56 GREGG
+Changed last param of F40_SaveLclName from INT16 to UINT16.
+
+ Rev 1.4 20 May 1992 18:16:20 GREGG
+Changes to support OTC read.
+
+ Rev 1.3 05 May 1992 11:29:48 GREGG
+Changed protos to a bunch of function which now need the environment.
+
+ Rev 1.2 29 Apr 1992 13:01:56 GREGG
+Added/Removed/Changed prototypes.
+
+ Rev 1.1 05 Apr 1992 17:57:02 GREGG
+ROLLER BLADES - Initial OTC integration.
+
+ Rev 1.0 25 Mar 1992 20:52:22 GREGG
+Initial revision.
+
+**/
+
+
+#ifndef _F40_PROTOS
+#define _F40_PROTOS
+#include "mayn40.h"
+
+INT16 F40_Initialize( CHANNEL_PTR ) ;
+VOID F40_DeInitialize( VOID_PTR * ) ;
+BOOLEAN F40_Determiner( VOID_PTR ) ;
+UINT16 F40_SizeofTBLK( VOID_PTR ) ;
+INT16 F40_DetBlkType( CHANNEL_PTR, BUF_PTR, UINT16_PTR ) ;
+UINT16 F40_RdException( CHANNEL_PTR, INT16 ) ;
+INT16 F40_StartRead( CHANNEL_PTR ) ;
+
+/***** These have been added for the start of OTC support
+ NOTE that these have changes that may be removed or
+ altered when the translator no longer needs to use
+ smoke and mirrors to process TAPE and VOLB blocks.
+******/
+INT16 F40_RdVOLB( BUF_PTR buffer, VOID_PTR env_ptr, BOOLEAN_PTR cont_volb, UINT8_PTR str_type ) ;
+INT16 F40_NewTape( CHANNEL_PTR channel, BUF_PTR buffer, BOOLEAN_PTR need_read ) ;
+
+INT16 F40_WtVOLB( CHANNEL_PTR channel, BUF_PTR buffer, BOOLEAN continuation, UINT16_PTR offset ) ;
+INT16 F40_WriteInit( CHANNEL_PTR channel, UINT16 otc_level, BUF_PTR buffer ) ;
+INT16 F40_InitTape( CHANNEL_PTR channel, BOOLEAN continuation, BUF_PTR tmpBUF ) ;
+
+/* Set the 4 char block type name in the current header */
+VOID F40_SetBlkType( MTF_DB_HDR_PTR cur_hdr, UINT8_PTR block_type ) ;
+/* Get a UINT16 value that represents the current block type name */
+UINT16 F40_GetBlkType( MTF_DB_HDR_PTR cur_hdr ) ;
+
+INT16 F40_RdSSET( CHANNEL_PTR, BUF_PTR ) ;
+INT16 F40_RdDIRB( CHANNEL_PTR, BUF_PTR ) ;
+INT16 F40_RdFILE( CHANNEL_PTR, BUF_PTR ) ;
+INT16 F40_RdIMAG( CHANNEL_PTR, BUF_PTR ) ;
+INT16 F40_RdCFIL( CHANNEL_PTR, BUF_PTR ) ;
+INT16 F40_RdUDB( CHANNEL_PTR, BUF_PTR ) ;
+INT16 F40_RdMDB( CHANNEL_PTR, BUF_PTR ) ;
+INT16 F40_RdStream( CHANNEL_PTR, BUF_PTR ) ;
+BOOLEAN F40_Recall( CHANNEL_PTR, BUF_PTR ) ;
+BOOLEAN F40_RdContTape( CHANNEL_PTR, BUF_PTR ) ;
+INT16 F40_WtSSET( CHANNEL_PTR, BUF_PTR, BOOLEAN ) ;
+INT16 F40_WtDIRB( CHANNEL_PTR, BUF_PTR, BOOLEAN ) ;
+INT16 F40_WtDBDB( CHANNEL_PTR, BUF_PTR, BOOLEAN ) ;
+INT16 F40_WtFILE( CHANNEL_PTR, BUF_PTR, BOOLEAN ) ;
+INT16 F40_WtESET( CHANNEL_PTR, BUF_PTR, BOOLEAN, BOOLEAN ) ;
+INT16 F40_WtStream( CHANNEL_PTR, BUF_PTR, STREAM_INFO_PTR ) ;
+INT16 F40_EndData( CHANNEL_PTR, BUF_PTR ) ;
+INT16 F40_WtCFIL( CHANNEL_PTR, BUF_PTR, BOOLEAN ) ;
+INT16 F40_WtIMAG( CHANNEL_PTR, BUF_PTR, BOOLEAN ) ;
+INT16 F40_WtContVStream( CHANNEL_PTR, BUF_PTR ) ;
+VOID F40_WtEndVStream( CHANNEL_PTR, BUF_PTR, UINT16 ) ;
+INT16 F40_WtCloseSet( CHANNEL_PTR, BOOLEAN ) ;
+VOID F40_ParseWrittenBuffer( CHANNEL_PTR, BUF_PTR, UINT16 ) ;
+INT16 F40_WtCloseTape( CHANNEL_PTR ) ;
+INT16 F40_WtContTape( CHANNEL_PTR ) ;
+VOID F40_WtEOSPadBlk( CHANNEL_PTR ) ;
+INT16 F40_MoveToVCB( CHANNEL_PTR, INT16, BOOLEAN_PTR, BOOLEAN ) ;
+INT16 F40_SeekEOD( CHANNEL_PTR ) ;
+
+INT16 F40_SaveLclName( UINT8_PTR *dest_string, UINT8_PTR source_string,
+ UINT16_PTR dest_length, UINT16_PTR last_alloc_size,
+ UINT16 source_length ) ;
+UINT16 F40_CopyAndTerminate( UINT8_PTR *, UINT8_PTR, UINT16, UINT8, UINT8 ) ;
+UINT16 F40_CalcChecksum( UINT16_PTR StartPtr, UINT16 Length ) ;
+VOID TapeDateToDate( DATE_TIME_PTR date, MTF_DATE_TIME_PTR tape_date ) ;
+VOID DateToTapeDate( MTF_DATE_TIME_PTR tape_date, DATE_TIME_PTR date ) ;
+UINT16 SetupDBHeader( UINT8_PTR block_type, CHANNEL_PTR channel,
+ DBLK_PTR cur_dblk, MTF_DB_HDR_PTR cur_hdr,
+ UINT16 offset, BOOLEAN data_to_follow,
+ BOOLEAN continuation ) ;
+UINT32 F40_CalcRunningLBA( F40_ENV_PTR ) ;
+VOID F40_SetBlkType( MTF_DB_HDR_PTR, UINT8_PTR ) ;
+
+/* On Tape Catalog APIs in MYN40OTC.C */
+
+INT F40_LoadSM( CHANNEL_PTR channel, BOOLEAN_PTR complete, BOOLEAN get_best ) ;
+INT F40_LoadFDD( CHANNEL_PTR channel ) ;
+INT F40_GetNextSMEntry( CHANNEL_PTR channel ) ;
+INT F40_GetNextFDDEntry( CHANNEL_PTR channel ) ;
+VOID F40_CloseCatalogs( VOID_PTR env_ptr ) ;
+
+/* On Tape Catalog Protos (for modules OTC40RD.C, OTC40MSC.C & OTC40WT.C) */
+
+INT16 OTC_GetPrevSM( CHANNEL_PTR channel, BUF_PTR buffer, BOOLEAN get_best, BOOLEAN expect_sm ) ;
+INT16 OTC_GenSMHeader( CHANNEL_PTR channel ) ;
+INT16 OTC_OpenSM( F40_ENV_PTR cur_env, BOOLEAN appending, BOOLEAN_PTR sm_exists ) ;
+INT16 OTC_OpenFDD(F40_ENV_PTR cur_env ) ;
+VOID OTC_Close( F40_ENV_PTR cur_env, UINT16 otc_files, BOOLEAN delete_after ) ;
+INT16 OTC_WriteCat( CHANNEL_PTR channel, MTF_ESET_PTR cur_eset ) ;
+INT16 OTC_GenVolEntry( F40_ENV_PTR cur_env, MTF_VOL_PTR cur_volb, INT16 seq_num ) ;
+INT16 OTC_GenDirEntry( CHANNEL_PTR channel, MTF_DIR_PTR cur_dir, INT16 seq_num ) ;
+INT16 OTC_GenDBDBEntry( CHANNEL_PTR channel, F40_DBDB_PTR cur_dir, INT16 seq_num ) ;
+INT16 OTC_GenFileEntry( F40_ENV_PTR cur_env, MTF_FILE_PTR cur_file, INT16 seq_num ) ;
+INT16 OTC_GenEndEntry( CHANNEL_PTR channel ) ;
+INT16 OTC_GenSMEntry( MTF_SSET_PTR cur_sset, CHANNEL_PTR channel, BOOLEAN continuation ) ;
+INT16 OTC_MarkLastEntryCorrupt( F40_ENV_PTR cur_env ) ;
+INT16 OTC_RdSSET( CHANNEL_PTR channel ) ;
+INT16 OTC_RdDIR( CHANNEL_PTR channel ) ;
+INT16 OTC_RdFILE( CHANNEL_PTR channel ) ;
+INT16 OTC_FDDtoFile( CHANNEL_PTR channel ) ;
+INT16 OTC_ReadABuff( F40_ENV_PTR cur_env, UINT16 length ) ;
+INT16 OTC_GetFDDType( CHANNEL_PTR channel, UINT16_PTR blk_type ) ;
+INT16 OTC_SkipFDDEntry( CHANNEL_PTR channel ) ;
+INT16 OTC_SkipFDDContEntries( CHANNEL_PTR channel ) ;
+INT16 OTC_UpdateSMEntry( F40_ENV_PTR cur_env ) ;
+INT16 OTC_PreprocessEOM( F40_ENV_PTR cur_env, UINT32 cross_lba ) ;
+INT16 OTC_PostprocessEOM( CHANNEL_PTR channel, UINT32 sset_lba ) ;
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/fake_fs.h b/private/utils/ntbackup/inc/fake_fs.h
new file mode 100644
index 000000000..d051bbc0f
--- /dev/null
+++ b/private/utils/ntbackup/inc/fake_fs.h
@@ -0,0 +1,31 @@
+#ifndef _fake_fs_h_
+#define _fake_fs_h_
+
+INT16 FAKE_REM_AttachToDLE( FSYS_HAND fsh , /* I - File system handle */
+ GENERIC_DLE_PTR dle , /*I/O- drive to attach to. list element expanded */
+ CHAR_PTR u_name, /* I - user name NOT USED */
+ CHAR_PTR pswd ); /* I - passowrd */
+
+
+INT16 FAKE_REM_DetachDLE( FSYS_HAND fsh ) ;
+
+
+
+INT16 FAKE_RWS_AttachToDLE( FSYS_HAND fsh , /* I - File system handle */
+ GENERIC_DLE_PTR dle , /*I/O- drive to attach to. list element expanded */
+ CHAR_PTR u_name , /* I - user name NOT USED */
+ CHAR_PTR pswd ); /* I - passowrd NOT USED */
+
+
+
+INT16 FAKE_RWS_DetachDLE( FSYS_HAND fsh ) ;
+UINT16 AddRemoteDriveDLEs( GENERIC_DLE_PTR parent_dle ) ;
+
+INT16 FREM_Initialize(
+DLE_HAND dle_hand,
+BE_CFG_PTR cfg,
+UINT32 file_sys_mask ) ;
+
+VOID FREM_Deinit( DLE_HAND dle_hand ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/farlib.h b/private/utils/ntbackup/inc/farlib.h
new file mode 100644
index 000000000..83a6abe60
--- /dev/null
+++ b/private/utils/ntbackup/inc/farlib.h
@@ -0,0 +1,152 @@
+/*
+** Stuff to glue together code written for MSC to the CR libraries
+*/
+
+/*
+** Functions that operate on large data pointers, since we MUST
+** compile in small model.
+*/
+
+#include "stdtypes.h"
+#include "fartypes.h"
+
+#ifndef _farlib_
+#define _farlib_
+
+INT8 memfcmp( VOID_FAR_PTR arg1,VOID_FAR_PTR arg2,UINT16 cnt );
+INT8 memficmp( VOID_FAR_PTR arg1,VOID_FAR_PTR arg2,UINT16 cnt );
+VOID memfcpy( VOID_FAR_PTR dest,VOID_FAR_PTR src,UINT16 cnt );
+VOID memfset( VOID_FAR_PTR dest,CHAR c,UINT16 cnt );
+VOID strfcpy( CHAR_FAR_PTR dest,CHAR_FAR_PTR src );
+VOID strnfcpy( CHAR_FAR_PTR dest,CHAR_FAR_PTR src,UINT16 max );
+INT16 strnfcmp( CHAR_FAR_PTR str1,CHAR_FAR_PTR str2,UINT16 max );
+INT16 strfcmp( CHAR_FAR_PTR str1,CHAR_FAR_PTR str2 );
+VOID strnfcat( CHAR_FAR_PTR str1,CHAR_FAR_PTR str2,UINT16 max );
+
+typedef VOID ( _interrupt far * INT_HANDLER )( VOID ) ;
+
+INT_HANDLER getvect( UINT8 vector ) ;
+VOID setvect( UINT8 vector,INT_HANDLER newhandler ) ;
+
+/*
+** Make sure our routines are available if needed
+*/
+#undef memcmp
+#undef memicmp
+#undef memcpy
+#undef memset
+#undef strcpy
+#undef strncpy
+#undef strcmp
+#undef strncmp
+#undef strcat
+#undef strncat
+#undef malloc
+#undef free
+#undef calloc
+#undef realloc
+
+#define memcmp(a1,a2,n) memfcmp(a1,a2,n)
+#define memicmp(a1,a2,n) memficmp(a1,a2,n)
+#define memcpy(d,s,n) memfcpy(d,s,n)
+#define memset(d,c,n) memfset(d,c,n)
+#define strcpy(d,s) strfcpy(d,s)
+#define strncpy(d,s,n) strnfcpy(d,s,n)
+#define strcmp(s1,s2) strfcmp(s1,s2)
+#define strncmp(s1,s2,n) strnfcmp(s1,s2,n)
+#define strncat(s1,s2,n) strnfcat(s1,s2,n)
+
+/*
+** String functions needed in native model but not included in CodeRunner
+*/
+
+CHAR_PTR strrev( CHAR_PTR str );
+CHAR_PTR strcat( CHAR_PTR str1,CHAR_PTR str2 );
+CHAR_PTR strchr( CHAR_PTR str,CHAR c );
+
+/*
+** Replacement for the standard library memory management
+*/
+
+#define FP_SEG(fp) ((UINT16) ((UINT32)(VOID_FAR_PTR)(fp)>>16))
+#define FP_OFF(fp) ((UINT16) (fp))
+
+#define MK_FP(seg,off) \
+ ((VOID_FAR_PTR) (((UINT32)seg<<16)|off))
+
+VOID_FAR_PTR tsrmalloc( UINT16 amount );
+VOID (* tsrheapbreak( VOID ))( VOID );
+VOID_FAR_PTR strdup( char *s );
+
+
+#define malloc(x) tsrmalloc(x)
+#define free(x)
+#define calloc(x,y) NULL
+#define realloc(x) NULL
+
+/*
+** Often used macros from the std libraries
+*/
+
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+
+/*
+** Map the int86 and int86x functions to the CodeRunner equivalents
+*/
+
+#ifndef _REGS_DEFINED
+
+/* word registers */
+
+struct WORDREGS {
+ unsigned int ax;
+ unsigned int bx;
+ unsigned int cx;
+ unsigned int dx;
+ unsigned int si;
+ unsigned int di;
+ unsigned int cflag;
+ };
+
+
+/* byte registers */
+
+struct BYTEREGS {
+ unsigned char al, ah;
+ unsigned char bl, bh;
+ unsigned char cl, ch;
+ unsigned char dl, dh;
+ };
+
+
+/* general purpose registers union -
+ * overlays the corresponding word and byte registers.
+ */
+
+union REGS {
+ struct WORDREGS x;
+ struct BYTEREGS h;
+ };
+
+
+/* segment registers */
+
+struct SREGS {
+ unsigned int es;
+ unsigned int cs;
+ unsigned int ss;
+ unsigned int ds;
+ };
+
+#define _REGS_DEFINED
+
+#endif
+
+INT16 int86(INT8, union REGS *, union REGS *);
+INT16 int86x(INT8, union REGS *, union REGS *, struct SREGS *);
+VOID dosver( CHAR_PTR major,CHAR_PTR minor );
+
+extern int _doserrno;
+#endif
+
diff --git a/private/utils/ntbackup/inc/fartypes.h b/private/utils/ntbackup/inc/fartypes.h
new file mode 100644
index 000000000..833846773
--- /dev/null
+++ b/private/utils/ntbackup/inc/fartypes.h
@@ -0,0 +1,36 @@
+/*
+** Far pointers to various types
+*/
+
+#ifndef _far_types_
+#define _far_types_
+
+#ifndef MK_FP
+#define MK_FP(seg,off) \
+ ((VOID_FAR_PTR) (((UINT32)seg<<16)|off))
+#endif
+
+/*
+** The Watcom C compiler has no idea what far pointers are, so just
+** define them out. (Watcom predefines 'far' to '__far', so actually
+** need to define that one out.)
+*/
+
+#ifdef __WATCOMC__
+#define __far
+#endif
+
+typedef VOID far *VOID_FAR_PTR;
+
+typedef CHAR far *CHAR_FAR_PTR;
+typedef INT8 far *INT8_FAR_PTR;
+typedef UINT8 far *UINT8_FAR_PTR;
+typedef INT16 far *INT16_FAR_PTR;
+typedef UINT16 far *UINT16_FAR_PTR;
+typedef INT32 far *INT32_FAR_PTR;
+typedef UINT32 far *UINT32_FAR_PTR;
+typedef BOOLEAN far *BOOLEAN_FAR_PTR;
+
+typedef VOID (far *VOID_FAR_PF)();
+
+#endif
diff --git a/private/utils/ntbackup/inc/filerepl.h b/private/utils/ntbackup/inc/filerepl.h
new file mode 100644
index 000000000..ec4f6c891
--- /dev/null
+++ b/private/utils/ntbackup/inc/filerepl.h
@@ -0,0 +1,68 @@
+/***************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+
+ Name: filerepl.h
+
+ Description: This file contains the definitions, macros, and function
+ prototypes for the FREPLACE code.
+
+ $Log: G:/UI/LOGFILES/FILEREPL.H_V $
+
+ Rev 1.2 04 Oct 1992 19:47:08 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.1 12 Aug 1992 18:28:34 STEVEN
+fix warinings
+
+ Rev 1.0 20 Nov 1991 19:39:48 SYSTEM
+Initial revision.
+
+****************************************************/
+
+#ifndef FILEREPL_H
+#define FILEREPL_H
+
+#define FILE_REPLACE_YES_BUTTON 1
+#define FILE_REPLACE_YES_TO_ALL_BUTTON 2
+#define FILE_REPLACE_NO_BUTTON 3
+#define FILE_REPLACE_CANCEL_BUTTON 4
+
+#define FILE_REPLACE_ATTRIBUTES_LEN 80
+#define FILE_REPLACE_ATTRIBUTES_SIZE ( FILE_REPLACE_ATTRIBUTES_LEN + 1 )
+
+#define DRIVE_LEN 3
+#define DRIVE_SIZE ( DRIVE_LEN + 1 )
+
+#define SERVER_NAME_LEN 48
+#define SERVER_NAME_SIZE ( SERVER_NAME_LEN + 1 )
+
+#define VOLUME_NAME_LEN 16
+#define VOLUME_NAME_SIZE ( VOLUME_NAME_LEN + 1 )
+
+#define FILE_REPLACE_VOLUME_NAME_LEN ( DRIVE_LEN + SERVER_NAME_LEN + VOLUME_NAME_LEN )
+#define FILE_REPLACE_VOLUME_NAME_SIZE ( FILE_REPLACE_VOLUME_NAME_LEN + 1 )
+
+
+
+
+typedef struct file_replace_temp {
+ WORD dialog_return_status ;
+ CHAR source_volume[ FILE_REPLACE_VOLUME_NAME_SIZE ] ;
+ CHAR destination_volume[ FILE_REPLACE_VOLUME_NAME_SIZE ] ;
+ CHAR source_path[ MAX_UI_PATH_SIZE ] ;
+ CHAR destination_path[ MAX_UI_PATH_SIZE ] ;
+ CHAR line_1[ FILE_REPLACE_VOLUME_NAME_LEN + MAX_UI_PATH_SIZE ] ;
+ CHAR line_2[ FILE_REPLACE_ATTRIBUTES_SIZE ] ;
+ CHAR line_3[ FILE_REPLACE_VOLUME_NAME_LEN + MAX_UI_PATH_SIZE ] ;
+ CHAR line_4[ FILE_REPLACE_ATTRIBUTES_SIZE ] ;
+}FILE_REPLACE_TEMP, *FILE_REPLACE_TEMP_PTR ;
+
+
+/*
+// Call back functions for the display manager
+*/
+
+INT16 DM_StartConfirmFileReplace( FILE_REPLACE_TEMP_PTR ) ;
+VOID DisplayDirectory( HWND, LPSTR, WORD ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/finitfs.h b/private/utils/ntbackup/inc/finitfs.h
new file mode 100644
index 000000000..fa52028ce
--- /dev/null
+++ b/private/utils/ntbackup/inc/finitfs.h
@@ -0,0 +1,31 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: finitfs.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+ Location:
+
+
+ $Log: N:/LOGFILES/FINITFS.H_V $
+ *
+ * Rev 1.1 21 Jun 1991 13:20:58 BARRY
+ * Changes for new config.
+ *
+ * Rev 1.0 09 May 1991 13:33:00 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+INT16 AddFakeRemoteWorkStationDLEs( DLE_HAND hand );
+
+INT16 InitializeFakeRemote( DLE_HAND dle_hand, struct BE_CFG *cfg ) ;
+
+VOID RemoveFakeRemote( DLE_HAND dle_hand ) ;
+
+
diff --git a/private/utils/ntbackup/inc/fmteng.h b/private/utils/ntbackup/inc/fmteng.h
new file mode 100644
index 000000000..fc0750da5
--- /dev/null
+++ b/private/utils/ntbackup/inc/fmteng.h
@@ -0,0 +1,215 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: fmteng.h
+
+ Date Updated: $./FDT$ $./FTM$
+ 7/21/1989 14:4:121
+
+ Description: The functions and structs defined by this guy are used
+ to determine, setup and free environments that are format
+ and operation specific.
+
+
+ $Log: T:/LOGFILES/FMTENG.H_V $
+ *
+ * Rev 1.24 08 Sep 1993 18:15:46 GREGG
+ * Changed proto of init_tape to match f40proto.h r1.31 and mtf10wdb.c r1.27.
+ *
+ * Rev 1.23 17 Jul 1993 17:56:58 GREGG
+ * Changed write translator functions to return INT16 TFLE_xxx errors instead
+ * of BOOLEAN TRUE/FALSE. Files changed:
+ * MTF10WDB.C 1.23, TRANSLAT.H 1.22, F40PROTO.H 1.30, FMTENG.H 1.23,
+ * TRANSLAT.C 1.43, TFWRITE.C 1.68, MTF10WT.C 1.18
+ *
+ * Rev 1.22 22 Jun 1993 10:53:28 GREGG
+ * Added API to change the catalog directory path.
+ *
+ * Rev 1.21 09 Mar 1993 18:14:38 GREGG
+ * Initial changes for new stream and EOM processing.
+ *
+ * Rev 1.20 26 Jan 1993 01:30:54 GREGG
+ * Added Fast Append functionality.
+ *
+ * Rev 1.19 23 Nov 1992 10:59:28 HUNTER
+ * Changed prototype for EOM parse function.
+ *
+ * Rev 1.18 09 Nov 1992 10:49:00 GREGG
+ * Added tape catalog entry points.
+ *
+ * Rev 1.17 03 Nov 1992 09:36:46 HUNTER
+ * Changes for stream stuff
+ *
+ * Rev 1.16 22 Oct 1992 10:53:04 HUNTER
+ * Changes for new stream headers
+ *
+ * Rev 1.15 22 Sep 1992 09:01:56 GREGG
+ * Initial changes to handle physical block sizes greater than 1K.
+ *
+ * Rev 1.14 14 Aug 1992 16:19:56 GREGG
+ * Removed size fields in function table.
+ *
+ * Rev 1.13 20 May 1992 18:16:38 GREGG
+ * Changes to support OTC read.
+ *
+ * Rev 1.12 29 Apr 1992 12:59:26 GREGG
+ * Added parameter to init_tape function entry.
+ *
+ * Rev 1.11 05 Apr 1992 17:55:18 GREGG
+ * ROLLER BLADES - Initial OTC integration.
+ *
+ * Rev 1.10 25 Mar 1992 20:46:10 GREGG
+ * ROLLER BLADES - Added eom_lba_size.
+ *
+ * Rev 1.9 04 Feb 1992 21:24:38 NED
+ * Changes to Buffer Management translator hooks.
+ *
+ * Rev 1.8 16 Jan 1992 18:31:38 ZEIR
+ * Latest BufferMan solution no longer requires StartReadHook.
+ *
+ *
+ * Rev 1.7 02 Jan 1992 14:49:26 NED
+ * Buffer Manager/UTF translator integration.
+ *
+ * Rev 1.6 05 Dec 1991 14:05:56 GREGG
+ * SKATEBOARD - New Buff Mgt - Initial Integration.
+ *
+ * Rev 1.5 18 Nov 1991 19:59:56 GREGG
+ * Added BOOLEAN abort parameter to wt_mk_vcb and wt_close_set.
+ *
+ * Rev 1.4 07 Nov 1991 15:24:14 HUNTER
+ * VBLK - Added functions for Variable Blocks
+ *
+ * Rev 1.3 16 Sep 1991 20:09:48 GREGG
+ * Changed prototype for SetupFormatEnv to return TFLE_xxx.
+ *
+ * Rev 1.2 03 Jun 1991 10:55:48 GREGG
+ * Changed protos for deinitializer and move_to_vcb.
+ *
+ * Rev 1.1 10 May 1991 14:26:24 GREGG
+ * Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:17:50 GREGG
+Initial revision.
+
+**/
+
+#ifndef _FMT_ENG
+#define _FMT_ENG
+
+#include "buffman.h"
+#include "channel.h"
+#include "fmtinf.h"
+#include "translat.h"
+#include "fsys.h"
+
+/* $end$ */
+/* private data structure used by access routines in translat.c */
+
+typedef struct {
+
+ /* return TRUE if this format recognizes the given data */
+ BOOLEAN (*determiner)( VOID_PTR ) ;
+
+ /* set up translator-specific environment, allocate memory, etc. */
+ INT16 (*initializer)( CHANNEL_PTR ) ;
+
+ /* undo initialization */
+ VOID (*deinitializer)( VOID_PTR * ) ;
+
+ /* see buffman.h for these two */
+ BM_TR_GET_VCB_REQ_FUNC_PTR set_buffer_requirements ;
+ BM_TR_GET_PREF_FUNC_PTR get_preferred_space ;
+
+ /* to be called upon receiving a buffer full during read */
+ VOID (*read_buffer_hook)( CHANNEL_PTR, BUF_PTR ) ;
+
+ /* given a buffer, return block type BT_xxx */
+ INT16 (*parser)( CHANNEL_PTR, BUF_PTR, UINT16_PTR ) ;
+
+ UINT16 (*sizeof_tblk)( VOID_PTR ) ;
+
+ /* called when read returns an exception */
+ UINT16 (*exception_action)( CHANNEL_PTR, INT16 ) ;
+
+ /* called upon first examining a new tape. This may do special
+ per-tape things for the translator.
+ */
+ INT16 (*new_tape)( CHANNEL_PTR, BUF_PTR, BOOLEAN_PTR ) ;
+
+ /* Initialize OTC temporary files */
+ INT16 (*write_init)( CHANNEL_PTR, UINT16, BUF_PTR ) ;
+
+ /* Write a TAPE header block */
+ INT16 (*init_tape)( CHANNEL_PTR, BOOLEAN, BUF_PTR ) ;
+
+ /* Move to OTC */
+ INT16 (*start_read)( CHANNEL_PTR ) ;
+
+ /* Move to next/prior/current VCB position */
+ INT16 (*move_to_vcb)( CHANNEL_PTR, INT16, BOOLEAN_PTR, BOOLEAN ) ;
+
+ /* Move to End of Data (for fast append) */
+ INT16 (*seek_eod)( CHANNEL_PTR ) ;
+
+ /* Get the current VCB */
+ INT16 (*get_current_vcb)( CHANNEL_PTR, BUF_PTR ) ;
+
+ /* Call to check validity of VCB or NULL if no append of other
+ formats is possible
+ */
+ BOOLEAN (*verify_vcb)( VOID_PTR ) ;
+
+ BOOLEAN (*rd_cont_tape)( CHANNEL_PTR, BUF_PTR ) ;
+
+ BOOLEAN (*rd_recall)( CHANNEL_PTR, BUF_PTR ) ;
+
+ /* Read conversion routines: */
+ INT16 (*rd_mk_vcb)( CHANNEL_PTR, BUF_PTR ) ;
+ INT16 (*rd_mk_ddb)( CHANNEL_PTR, BUF_PTR ) ;
+ INT16 (*rd_mk_fdb)( CHANNEL_PTR, BUF_PTR ) ;
+ INT16 (*rd_mk_idb)( CHANNEL_PTR, BUF_PTR ) ;
+ INT16 (*rd_mk_cfdb)( CHANNEL_PTR, BUF_PTR ) ;
+ INT16 (*rd_mk_bsdb)( CHANNEL_PTR, BUF_PTR ) ;
+ INT16 (*rd_mk_osudb)( CHANNEL_PTR, BUF_PTR ) ;
+ INT16 (*rd_mk_mdb)( CHANNEL_PTR, BUF_PTR ) ;
+ INT16 (*rd_mk_stream) ( CHANNEL_PTR, BUF_PTR ) ;
+
+ /* Write conversion routines: */
+ INT16 (*wt_mk_vcb)( CHANNEL_PTR, BUF_PTR, BOOLEAN ) ;
+ INT16 (*wt_mk_ddb)( CHANNEL_PTR, BUF_PTR, BOOLEAN ) ;
+ INT16 (*wt_mk_fdb)( CHANNEL_PTR, BUF_PTR, BOOLEAN ) ;
+ INT16 (*wt_mk_stream)( CHANNEL_PTR, BUF_PTR, STREAM_INFO_PTR ) ;
+ INT16 (*wt_mk_enddata)( CHANNEL_PTR, BUF_PTR ) ;
+ INT16 (*wt_mk_idb)( CHANNEL_PTR, BUF_PTR, BOOLEAN ) ;
+ INT16 (*wt_mk_cfdb)( CHANNEL_PTR, BUF_PTR, BOOLEAN ) ;
+ INT16 (*wt_cont_vstrm)( CHANNEL_PTR, BUF_PTR ) ;
+ VOID (*wt_end_vstrm)( CHANNEL_PTR, BUF_PTR, UINT16 ) ;
+ VOID (*wt_parse_written)( CHANNEL_PTR, BUF_PTR, UINT16 ) ;
+ INT16 (*wt_close_tape)( CHANNEL_PTR ) ;
+
+ INT16 (*wt_cont_set)( CHANNEL_PTR ) ;
+
+ INT16 (*wt_close_set)( CHANNEL_PTR, BOOLEAN ) ;
+
+ VOID (*wt_eos_pad_blk)( CHANNEL_PTR ) ;
+
+ /* On Tape Catalog Routines: */
+ INT (*load_set_map)( CHANNEL_PTR, BOOLEAN_PTR, BOOLEAN ) ;
+
+ INT (*load_set_cat)( CHANNEL_PTR ) ;
+
+ INT (*get_next_sm_entry)( CHANNEL_PTR ) ;
+
+ INT (*get_next_sc_entry)( CHANNEL_PTR ) ;
+
+ VOID (*close_catalogs)( VOID_PTR ) ;
+
+} FMT, *FMT_PTR ;
+
+/* The external tape format table (see fmttab.c) */
+
+extern FMT supported_fmts[] ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/fmtinf.h b/private/utils/ntbackup/inc/fmtinf.h
new file mode 100644
index 000000000..4b000a598
--- /dev/null
+++ b/private/utils/ntbackup/inc/fmtinf.h
@@ -0,0 +1,121 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+$name$
+.module information
+
+$paths$
+headers\fmtinf.h
+subsystem\TAPE FORMAT\fmtinf.h
+$0$
+
+ Name: fmtinf.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Describes a support format entry.
+
+ Location: BE_PUBLIC
+
+$Header: T:/LOGFILES/FMTINF.H_V 1.11 22 Apr 1993 03:31:24 GREGG $
+
+$Log: T:/LOGFILES/FMTINF.H_V $
+ *
+ * Rev 1.11 22 Apr 1993 03:31:24 GREGG
+ * Third in a series of incremental changes to bring the translator in line
+ * with the MTF spec:
+ *
+ * - Removed all references to the DBLK element 'string_storage_offset',
+ * which no longer exists.
+ * - Check for incompatable versions of the Tape Format and OTC and deals
+ * with them the best it can, or reports tape as foreign if they're too
+ * far out. Includes ignoring the OTC and not allowing append if the
+ * OTC on tape is a future rev, different type, or on an alternate
+ * partition.
+ * - Updated OTC "location" attribute bits, and changed definition of
+ * CFIL to store stream number instead of stream ID.
+ *
+ * Matches: TFL_ERR.H 1.9, MTF10WDB.C 1.7, TRANSLAT.C 1.39, FMTINF.H 1.11,
+ * OTC40RD.C 1.24, MAYN40RD.C 1.56, MTF10WT.C 1.7, OTC40MSC.C 1.20
+ * DETFMT.C 1.13, MTF.H 1.4
+ *
+ * Rev 1.10 22 Jan 1993 13:55:30 unknown
+ * Add the min_size_for_tblk field that was added in rev 1.8.1.0. This revision
+ * should work with the rev 1.11 of the lwtfinf.c.
+ *
+ *
+ * Rev 1.9 30 Apr 1992 16:47:58 CHARLIE
+ * Eliminated MAXFORMATNAME
+ *
+ * Eliminated format_name in TFINF
+ *
+ * format_id in TFINF is a resource index specified in eng_fmt.h to allow
+ * the UI to control the string associated with each format
+ *
+ * Rev 1.8 31 Mar 1992 14:22:18 NED
+ * added indication that translators could read from VCB buffer
+ *
+ * Rev 1.7 22 Jul 1991 12:41:14 GREGG
+ * Added format attribute bit to indicate we must write a continuation tape if
+ * EOS coincides with EOM.
+ *
+ * Rev 1.6 07 Jun 1991 01:21:46 GREGG
+ * Changed proto from TF_GetTapeFormatIndex to TF_GetTapeFormatID
+ *
+ * Rev 1.5 06 Jun 1991 11:30:00 GREGG
+ * added format_id field
+ *
+ * Rev 1.4 05 Jun 1991 15:23:20 NED
+ * added TF_GetTapeFormatIndex() and TF_GetTapeFormatFromIndex() calls,
+ * TAPES_FIRST_TO_LAST attribute bit, and define for UNKNOWN_FORMAT
+ *
+ * Rev 1.3 21 May 1991 17:00:56 NED
+ * added max_password_size field to structure,
+ * moved function declarations to this module.
+ *
+ * Rev 1.2 17 May 1991 08:57:02 DAVIDH
+ * Cleared up errors found by Watcom compiler.
+ *
+ * Rev 1.1 10 May 1991 17:25:54 GREGG
+ * Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:15:36 GREGG
+Initial revision.
+
+$-4$
+**/
+#ifndef _FMT_INF
+#define _FMT_INF
+
+/* $end$ include list */
+
+#define TFGT_UNKNOWN_FORMAT 0xffff /* what you'll get if you ask for an index and we don't know yet */
+
+/* Define format attribute bits */
+
+#define RD_FORMAT_BIT BIT0 /* We can read this type */
+#define WT_FORMAT_BIT BIT1 /* We can write this type */
+#define INDEX_SUPPORTED BIT2 /* Indexes are supported */
+#define POS_INF_AVAIL BIT3 /* Tape Contains positional information */
+#define APPEND_SUPPORTED BIT4 /* we can append our own sets after these */
+#define TAPES_FIRST_TO_LAST BIT5 /* we've got to see our family in order. */
+#define MUST_WRITE_CONT BIT6 /* We have to write a continuation tape, at
+ EOM even if we hit EOS at the same time. */
+#define CAN_READ_FROM_VCB_BUFF BIT7 /* we can start reading using the data
+ contained in the VCB buffer */
+
+typedef struct {
+ UINT16 attributes ;
+ UINT16 max_password_size ; /* length of max password + 1 */
+ UINT16 format_id ;
+ UINT16 min_size_for_tblk ;
+} TFINF, *TFINF_PTR ;
+
+TFINF_PTR TF_GetTapeFormatInfo( UINT16_PTR num_formats ) ;
+TFINF_PTR TF_GetTapeFormat( UINT16 channel_no ) ;
+UINT16 TF_GetTapeFormatID( UINT16 channel_no ) ;
+TFINF_PTR TF_GetTapeFormatFromID( UINT16 format_id ) ;
+
+#endif
+
+
diff --git a/private/utils/ntbackup/inc/freplace.h b/private/utils/ntbackup/inc/freplace.h
new file mode 100644
index 000000000..51792e509
--- /dev/null
+++ b/private/utils/ntbackup/inc/freplace.h
@@ -0,0 +1,44 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: freplace.h
+
+ Description:
+
+
+ $Log: G:/UI/LOGFILES/FREPLACE.H_V $
+
+ Rev 1.2 04 Oct 1992 19:47:10 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.1 06 Apr 1992 09:53:46 CHUCKB
+Added define for translation.
+
+ Rev 1.0 20 Nov 1991 19:41:14 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_FILEREPLACE 38
+#else
+#include "dlg_ids.h"
+#endif
+
+#ifndef FREPLACE_H
+#define FREPLACE_H
+
+#define IDD_FILE_REPLACE_LINE1 101
+#define IDD_FILE_REPLACE_LINE2 102
+#define IDD_FILE_REPLACE_LINE3 103
+#define IDD_FILE_REPLACE_LINE4 104
+#define IDD_FILE_REPLACE_YES 110
+#define IDD_FILE_REPLACE_ALL 112
+#define IDD_FILE_REPLACE_NO 111
+#define IDD_FILE_REPLACE_CANCEL 114
+#define IDD_FILE_REPLACE_HELP 105
+#define IDD_FILE_REPLACE_BITMAP 120
+
+#endif
diff --git a/private/utils/ntbackup/inc/fsstream.h b/private/utils/ntbackup/inc/fsstream.h
new file mode 100644
index 000000000..e4006ed11
--- /dev/null
+++ b/private/utils/ntbackup/inc/fsstream.h
@@ -0,0 +1,149 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: fsstream.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains stream info structure and related
+ definitions for the file system internals.
+
+ Location: BE_PUBLIC
+
+
+ $Log: M:/LOGFILES/FSSTREAM.H_V $
+
+ Rev 1.14 06 Dec 1993 11:44:30 BARRY
+Corrected stream headers for path/file names
+
+ Rev 1.13 09 Jun 1993 15:35:50 MIKEP
+enable c++
+
+ Rev 1.12 31 Mar 1993 08:51:00 MARILYN
+changed the CRCD checksum stream it to CSUM
+
+ Rev 1.11 01 Mar 1993 17:33:12 MARILYN
+added a CRCD stream header id for checksum streams
+
+ Rev 1.10 17 Nov 1992 16:04:34 BARRY
+Changed ULNK to LINK.
+
+ Rev 1.9 17 Nov 1992 14:15:26 GREGG
+Added PAD stream type.
+
+ Rev 1.8 13 Nov 1992 16:46:00 DON
+Added SMS Stream Header IDs
+
+ Rev 1.7 11 Nov 1992 10:33:02 TIMN
+Changed macro names due to OS2 compiler confusion
+
+ Rev 1.6 26 Oct 1992 17:58:46 BARRY
+Changed NTFS link id.
+
+ Rev 1.5 21 Oct 1992 19:37:54 BARRY
+Added LINK stream header type for NTFS linked files.
+
+ Rev 1.4 16 Oct 1992 15:42:04 STEVEN
+fix stream size problem
+
+ Rev 1.3 16 Oct 1992 10:49:50 STEVEN
+make stream header with uint64 instead of two 32
+
+ Rev 1.2 14 Oct 1992 12:38:10 TIMN
+Moved macros for stream infos from fsys_prv.h
+
+ Rev 1.1 06 Oct 1992 13:33:08 TIMN
+Added fs stream attrib normal
+
+**/
+
+#ifndef _fsstream_h_
+#define _fsstream_h_
+
+
+/* begin include list */
+
+/** are the tf_attrib defines included **/
+#ifndef STREAM_VARIABLE
+# include "tfldefs.h"
+#endif
+
+/* $end$ include list */
+
+
+typedef struct STREAM_INFO *STREAM_INFO_PTR;
+typedef struct STREAM_INFO {
+ UINT32 id ;
+ UINT16 fs_attrib ;
+ UINT16 tf_attrib ;
+ UINT64 size ;
+} STREAM_INFO;
+
+
+/** stream id values **/
+
+#define STRM_INVALID 0
+#define STRM_GENERIC_DATA 0x4e415453 /* 'STAN' */
+#define STRM_PAD 0x44415053 /* 'SPAD' */
+
+#define STRM_PATH_NAME 0x4d414e50 /* 'PNAM' */
+#define STRM_FILE_NAME 0x4d414e46 /* 'FNAM' */
+
+#define STRM_OTC_SM 0x504d5354 /* 'TSMP' On Tape Catalog Set Map */
+#define STRM_OTC_FDD 0x44444654 /* 'TFDD' On Tape Catalog File/Directory Detail */
+
+#define STRM_OS2_EA 0x4145324f /* 'O2EA' */
+#define STRM_OS2_ACL 0x4c43414f /* 'OACL' */
+
+#define STRM_NT_EA 0x4145544e /* 'NTEA' */
+#define STRM_NT_ACL 0x4c43414e /* 'NACL' */
+
+#define STRM_MAC_RESOURCE 0x4353524d /* 'MRSC' */
+#define STRM_NOV_TRUST_286 0x3638324e /* 'N286' */
+#define STRM_NOV_TRUST_386 0x3638334e /* 'N386' */
+#define STRM_NTFS_ALT_DATA 0x54414441 /* 'ADAT' */
+
+#define STRM_NTFS_LINK 0x4b4e494c /* 'LINK' */
+
+#define STRM_SMS_DATA 0x44534d53 /* 'SMSD' */
+#define STRM_CHECKSUM_DATA 0x4d555343 /* 'CSUM' */
+
+#define STRM_EMS_MONO_DB 0x42444d58 /* 'XMDB' */
+#define STRM_EMS_MONO_LOG 0x474c4f58 /* 'XLOG' */
+#define STRM_EMS_MONO_PATHS 0x48545058 /* 'XPTH' */
+
+/** stream attrib values (fs) **/
+
+#define STRM_ATTRIB_NORMAL 0x0000
+#define STRM_ATTRIB_MODIFIED_ON_READ 0x0001
+#define STRM_ATTRIB_CONTAINS_SECURITY 0x0002
+
+
+/** stream macros **/
+
+#define FS_InvalidateStrmId(s_info) ( (s_info)->id = STRM_INVALID )
+
+#define FS_IsStrmGeneric(s_info) ( (s_info)->id == STRM_GENERIC_DATA )
+#define FS_IsStrmIdInvalid(s_info) ( (s_info)->id == STRM_INVALID )
+
+#define FS_IsStrmVariableLength(s_info) \
+ ( (s_info)->tf_attrib & STREAM_VARIABLE )
+
+#define FS_IsStrmModifiedDuringRead(s_info) \
+ ( (s_info)->fs_attrib & STRM_ATTRIB_MODIFIED_ON_READ )
+
+#define FS_IsStreamChecksumed(s_info) \
+ ( (s_info)->tf_attrib & STREAM_CHECKSUMED )
+
+#define FS_GetStrmId(s_info) ( (s_info)->id )
+#define FS_GetStrmAttrib(s_info) ( (s_info)->fs_attrib )
+#define FS_GetStrmSizeLo(s_info) ( (s_info)->size.lsw )
+#define FS_GetStrmSizeHi(s_info) ( (s_info)->size.msw )
+
+#define FS_SetStrmId(s_info,Id) ( (s_info)->id = Id )
+#define FS_SetStrmAttrib(s_info,fsAttrib) ( (s_info)->fs_attrib = fsAttrib )
+#define FS_SetStrmSizeLo(s_info,sizelo) ( (s_info)->size.lsw = sizelo )
+#define FS_SetStrmSizeHi(s_info,sizehi) ( (s_info)->size.msw = sizehi )
+
+#endif
diff --git a/private/utils/ntbackup/inc/fsys.h b/private/utils/ntbackup/inc/fsys.h
new file mode 100644
index 000000000..f6b58d560
--- /dev/null
+++ b/private/utils/ntbackup/inc/fsys.h
@@ -0,0 +1,798 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: fsys.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This header file provides necessary declarations
+ for the File System Unit (FSU).
+
+ Location: BE_PUBLIC
+
+
+ $Log: Q:\logfiles\fsys.h_v $
+ *
+ * Rev 1.44 02 Feb 1994 17:46:16 chrish
+ * Added FS_ViewStringTypeInDBLK macro - tells if tape is ANSI or
+ * UNICODE.
+ *
+ * Rev 1.43 10 Jan 1994 16:41:28 ZEIR
+ * ad'd FS_SetCompressedBlock() macro
+ *
+ * Rev 1.42 24 Nov 1993 14:55:18 BARRY
+ * Changed CHAR_PTRs in I/O functions to BYTE_PTRs; fixed silly macros
+ *
+ * Rev 1.41 20 Sep 1993 17:22:00 DON
+ * Added prototype FS_GeneratedErrorLog() which is currently only supported by
+ * the SMS File System. If table entry is NULL the FALSE else return value
+ * from fsh->tab_ptr->GeneratedErrorLog. Requires fsys_str.h and corresponding
+ * entry added to OS specific tables.
+
+ Rev 1.0 20 Sep 1993 17:20:50 DON
+Added new table entry GeneratedErrorLog
+ *
+ * Rev 1.40 06 Aug 1993 16:33:52 DON
+ * Added macros to access new fields in vcb
+ *
+ * Rev 1.39 30 Jul 1993 13:20:30 STEVEN
+ * if dir too deep make new one
+ *
+ * Rev 1.38 16 Jul 1993 08:50:18 DON
+ * Added Macros to Set/Get name space element in either the FSYS_HAND or COM_DBLK. Also, per Gregg, removed macros for compressed, encrypted and future!
+ *
+ * Rev 1.37 13 Jul 1993 19:07:50 GREGG
+ * Added access macros for info on compression, encryption and future rev sets.
+ *
+ * Rev 1.36 26 May 1993 15:19:04 BARRY
+ * Put back Chris's double-null empty strings.
+ *
+ * Rev 1.35 23 May 1993 21:03:42 BARRY
+ * Integrate Steve's unicode changes, got rid of // comments.
+ *
+ * Rev 1.34 18 May 1993 13:56:00 chrish
+ * NOSTRADAMUS EPR 0069 - Modified these macros below to check the string lengths
+ * before returning back the content of the vcb else if zreo return a null string.
+ *
+ * #define FS_ViewTapeNameInVCB( vcb )
+ * #define FS_ViewSetNameInVCB( vcb )
+ * #define FS_ViewSetDescriptInVCB( vcb )
+ * #define FS_ViewUserNameInVCB( vcb )
+ * #define FS_ViewMachNameInVCB( vcb )
+ * #define FS_ViewShortMachNameInVCB( vcb )
+ * #define FS_ViewTapePasswordInVCB( vcb )
+ * #define FS_ViewSetPswdInVCB( vcb )
+ * #define FS_ViewVolNameInVCB( vcb )
+ * #define FS_ViewDevNameInVCB( vcb )
+ *
+ * Rev 1.33 25 Apr 1993 20:12:28 GREGG
+ * Fifth in a series of incremental changes to bring the translator in line
+ * with the MTF spec:
+ *
+ * - Store the corrupt stream number in the CFIL tape struct and the CFDB.
+ *
+ * Matches: MTF10WDB.C 1.9, FSYS.H 1.33, FSYS_STR.H 1.47, MAKECFDB.C 1.2,
+ * BACK_OBJ.C 1.36, MAYN40RD.C 1.58
+ *
+ * Rev 1.32 19 Apr 1993 18:01:52 GREGG
+ * Second in a series of incremental changes to bring the translator in line
+ * with the MTF spec:
+ *
+ * Changes to write version 2 of OTC, and to read both versions.
+ *
+ * Matches: mayn40rd.c 1.55, otc40msc.c 1.19, otc40rd.c 1.23, otc40wt.c 1.23,
+ * makevcb.c 1.15, fsys.h 1.32, fsys_str.h 1.46, tpos.h 1.16,
+ * mayn40.h 1.32, mtf.h 1.3.
+ *
+ * NOTE: There are additional changes to the catalogs needed to save the OTC
+ * version and put it in the tpos structure before loading the OTC
+ * File/Directory Detail. These changes are NOT listed above!
+ *
+ * Rev 1.31 18 Mar 1993 15:20:16 ChuckS
+ * Additional macros for Device Name in VCB
+ *
+ * Rev 1.30 27 Jan 1993 16:07:28 GREGG
+ * Added Set macros for Tape Catalog Level and Set Catalog Valid boolean in VCB.
+ *
+ * Rev 1.29 22 Dec 1992 09:09:18 TIMN
+ * Added size parameter to FS_InitStrmInfo f(x)
+ *
+ * Rev 1.28 16 Dec 1992 10:06:54 STEVEN
+ * fix macro for MIPS
+ *
+ * Rev 1.27 14 Dec 1992 12:37:16 DAVEV
+ * Enabled for Unicode compile
+ *
+ * Rev 1.26 07 Dec 1992 16:28:46 STEVEN
+ * various fixes for NT
+ *
+ * Rev 1.25 11 Nov 1992 22:09:58 GREGG
+ * Unicodeized literals.
+ *
+ * Rev 1.24 23 Oct 1992 13:10:26 STEVEN
+ * fix typos
+ *
+ * Rev 1.23 21 Oct 1992 10:39:48 GREGG
+ * Changed 'set_catalog_level' to 'on_tape_cat_level'.
+ *
+ * Rev 1.22 20 Oct 1992 19:37:38 GREGG
+ * Fixed typo in last change.
+ *
+ * Rev 1.21 20 Oct 1992 15:00:56 STEVEN
+ * added otc stuff for qtc/otc communication
+ *
+ * Rev 1.20 14 Oct 1992 12:37:36 TIMN
+ * Moved macros for stream infos from fsys_prv.h
+ *
+ * Rev 1.19 06 Oct 1992 12:51:42 BARRY
+ * CompleteBLK gets s_info too.
+ *
+ * Rev 1.18 05 Oct 1992 11:24:00 STEVEN
+ * moved stream stuff to fsstream.h
+ *
+ * Rev 1.17 23 Sep 1992 09:47:06 BARRY
+ * Removed FS_GetRemainSizeDBLK and FS_SetRemainSizeDBLK macros.
+ *
+ * Rev 1.16 22 Sep 1992 15:29:22 BARRY
+ * Removed FS_GetTotalSizeFromDBLK.
+ *
+ * Rev 1.15 01 Sep 1992 16:13:08 STEVEN
+ * added stream headers to fsys API
+ *
+ * Rev 1.14 23 Jul 1992 12:39:46 STEVEN
+ * fix warnings
+ *
+ * Rev 1.13 09 Jul 1992 14:45:28 STEVEN
+ * BE_Unicode updates
+ *
+ * Rev 1.12 09 Jun 1992 13:56:42 BURT
+ * added is block continued macro
+ *
+ * Rev 1.11 13 May 1992 12:02:24 STEVEN
+ * 40 format changes
+ *
+ * Rev 1.10 10 May 1992 10:40:32 STEVEN
+ * fix typos
+ *
+ * Rev 1.9 12 Mar 1992 15:53:16 STEVEN
+ * 64 bit changes
+ *
+ * Rev 1.8 03 Mar 1992 16:11:02 STEVEN
+ * added functions for long paths
+ *
+ * Rev 1.7 13 Feb 1992 11:37:36 STEVEN
+ * fix support stuff
+ *
+ * Rev 1.6 20 Dec 1991 09:32:06 STEVEN
+ * move common files to tables
+ *
+ * Rev 1.5 25 Nov 1991 16:25:50 BARRY
+ * Added fsh to GetOSPathDDB.
+ *
+ * Rev 1.4 24 Oct 1991 15:03:38 BARRY
+ * TRICYCLE: Added the file system bit-mask selector to proto
+ * for FS_InitFileSys().
+ *
+ * Rev 1.3 14 Aug 1991 12:50:44 STEVEN
+ * add FindObjClose
+ *
+ * Rev 1.2 21 Jun 1991 13:23:36 BARRY
+ * Changes for new config.
+ *
+ * Rev 1.1 23 May 1991 16:54:08 BARRY
+ * Changed macro for FindFirstObj to pass new paramter; added FindFirstDir().
+ *
+ * Rev 1.0 09 May 1991 13:33:12 HUNTER
+ * Initial revision.
+
+**/
+#ifndef FSYS_H
+#define FSYS_H
+
+#include "msassert.h"
+#include "queues.h"
+#include "datetime.h"
+#include "fsys_err.h"
+#include "dle.h"
+#include "dblks.h"
+#include "fsstream.h"
+#include "fsys_str.h"
+
+
+/* $end$ include list */
+
+/**
+ critical error defines
+**/
+#define WRITE_PROTECT 0
+#define UNKNOWN_DEVICE 1
+#define DRIVE_NOT_READY 2
+#define SEEK_ERROR 6
+#define SECTOR_NOT_FOUND 8
+#define PRINTER_ERROR 9
+#define WRITE_ERROR 0xa
+#define READ_ERROR 0xb
+#define GENERAL_FAILURE 0xc
+#define DEVICE_DEAD 0xd /* No possible way to recover */
+
+#define CRIT_NO_RETRY 0
+#define CRIT_RETRY 1
+#define CRIT_ABORT 2
+
+
+#define OBJECT_ALL 0
+#define OBJECT_DIR 1
+
+
+/**
+ Return values for File system Functions
+**/
+#define FS_NORMAL_FILE 0
+#define FS_SPECIAL_DIR 1
+#define FS_SPECIAL_FILE 2
+#define FS_EXCLUDE_FILE 3
+
+/**
+ Macros for accessing the file system table
+**/
+
+#define FS_FindDrives( dle_type, hand, cfg, fsys_mask ) \
+ (msassert ( func_tab[ dle_type ].FindDrives != NULL),\
+ (func_tab [(dle_type)].FindDrives( hand, cfg, fsys_mask ) ) )
+
+
+#define FS_ProcessDDB( fsh, ddb )\
+ (msassert( fsh->tab_ptr->ProcessDDB != NULL ), \
+ (fsh->tab_ptr->ProcessDDB( fsh, ddb ) ) )
+
+#define FS_GetCurrentDDB( fsh, ddb )\
+ (msassert( fsh->tab_ptr->GetCurrentDDB != NULL ), \
+ (fsh->tab_ptr->GetCurrentDDB( fsh, ddb ) ) )
+
+#define FS_GetCurrentPath( fsh, path, size )\
+ (msassert( fsh->tab_ptr->GetCurrentPath != NULL ), \
+ (fsh->tab_ptr->GetCurrentPath( fsh, path, size ) ) )
+
+#define FS_ChangeDir( fsh, path, size ) \
+ (msassert( fsh->tab_ptr->ChangeDir != NULL ), \
+ (fsh->tab_ptr->ChangeDir( fsh, path, size ) ) )
+
+#define FS_ChangeIntoDDB( fsh, dblk ) \
+ (msassert( fsh->tab_ptr->ChangeIntoDDB != NULL ), \
+ (fsh->tab_ptr->ChangeIntoDDB( fsh, dblk ) ) )
+
+#define FS_UpDir( fsh ) \
+ (msassert( fsh->tab_ptr->ChangeDirUp != NULL ), \
+ (fsh->tab_ptr->ChangeDirUp( fsh ) ) )
+
+#define FS_CreateObj( fsh, dblk ) \
+ (msassert( fsh->tab_ptr->CreateObj != NULL ), \
+ (fsh->tab_ptr->CreateObj( fsh, dblk ) ) )
+
+#define FS_OpenObj( fsh, f_hand, dblk, mode ) \
+ (msassert( fsh->tab_ptr->OpenObj != NULL ), \
+ (fsh->tab_ptr->OpenObj( fsh, f_hand, dblk, mode ) ) )
+
+#define FS_SeekObj( f_hand, offset ) \
+ (msassert( (f_hand)->fsh->tab_ptr->SeekObj != NULL ), \
+ ((f_hand)->fsh->tab_ptr->SeekObj( f_hand, offset ) ) )
+
+#define FS_ReadObj( f_hand, buf, size, blk_size, s_info )\
+ (msassert( (f_hand)->fsh->tab_ptr->ReadObj != NULL ), \
+ ((f_hand)->fsh->tab_ptr->ReadObj( f_hand, buf, size, blk_size, s_info ) ) )
+
+#define FS_VerifyObj( f_hand, buf, data, size, blk_size, s_info )\
+ (msassert( (f_hand)->fsh->tab_ptr->VerifyObj != NULL ), \
+ ((f_hand)->fsh->tab_ptr->VerifyObj( f_hand, buf, data, size, blk_size, s_info ) ) )
+
+#define FS_WriteObj( f_hand, buf, size, blk_size, s_info )\
+ (msassert( (f_hand)->fsh->tab_ptr->WriteObj != NULL ), \
+ ((f_hand)->fsh->tab_ptr->WriteObj( f_hand, buf, size, blk_size, s_info ) ) )
+
+#define FS_CloseObj( f_hand )\
+ (msassert( (f_hand)->fsh->tab_ptr->CloseObj != NULL ), \
+ ((f_hand)->fsh->tab_ptr->CloseObj( f_hand ) ) )
+
+#define FS_DeleteObj( fsh, dblk ) \
+ (msassert( fsh->tab_ptr->DeleteObj != NULL ), \
+ (fsh->tab_ptr->DeleteObj( fsh, dblk ) ) )
+
+#define FS_GetObjPosition( f_hand )\
+ ( (f_hand)->obj_pos )
+
+#define FS_GetObjInfo( fsh, dblk ) \
+ (msassert( fsh->tab_ptr->GetObjInfo != NULL ), \
+ (fsh->tab_ptr->GetObjInfo( fsh, dblk ) ) )
+
+#define FS_SetObjInfo( fsh, dblk ) \
+ (msassert( fsh->tab_ptr->SetObjInfo != NULL ), \
+ (fsh->tab_ptr->SetObjInfo( fsh, dblk ) ) )
+
+#define FS_VerObjInfo( fsh, dblk ) \
+ (msassert( fsh->tab_ptr->VerObjInfo != NULL ), \
+ (fsh->tab_ptr->VerObjInfo( fsh, dblk ) ) )
+
+#define FS_FindFirstObj( fsh, fdb, fname ) \
+ (msassert( fsh->tab_ptr->FindFirstObj != NULL ), \
+ (fsh->tab_ptr->FindFirstObj( fsh, fdb, fname, OBJECT_ALL ) ) )
+
+#define FS_FindFirstDir( fsh, fdb, dname ) \
+ (msassert( fsh->tab_ptr->FindFirstObj != NULL ), \
+ (fsh->tab_ptr->FindFirstObj( fsh, fdb, dname, OBJECT_DIR ) ) )
+
+#define FS_FindNextObj( fsh, dblk ) \
+ (msassert( fsh->tab_ptr->FindNextObj != NULL ), \
+ (fsh->tab_ptr->FindNextObj( fsh, dblk ) ) )
+
+#define FS_FindObjClose( fsh, dblk ) \
+ (msassert( fsh->tab_ptr->FindObjClose != NULL ), \
+ (fsh->tab_ptr->FindObjClose( fsh, dblk ) ) )
+
+#define FS_PushMinDDB( fsh, ddb ) \
+ (msassert( fsh->tab_ptr->PushMinDDB != NULL ), \
+ (fsh->tab_ptr->PushMinDDB( fsh, ddb ) ) )
+
+#define FS_PopMinDDB( fsh, ddb ) \
+ (msassert( fsh->tab_ptr->PopMinDDB != NULL ), \
+ (fsh->tab_ptr->PopMinDDB( fsh, ddb ) ) )
+
+#define FS_GetSpecialDBLKS( fsh, dblk, index ) \
+ (msassert( fsh->tab_ptr->GetSpecialDBLKS != NULL ), \
+ (fsh->tab_ptr->GetSpecialDBLKS( fsh, dblk, index ) ) )
+
+#define FS_EnumSpecialFiles( dle, index, path, psize, fname )\
+ (msassert ( func_tab[ (dle)->type ].EnumSpecialFiles != NULL),\
+ (func_tab [(dle)->type].EnumSpecialFiles( dle, index, path, psize, fname ) ) )
+
+#define FS_GetObjTypeDBLK( fsh, ddb, type ) \
+ (msassert( fsh->tab_ptr->GetObjTypeDBLK != NULL ), \
+ (fsh->tab_ptr->GetObjTypeDBLK( ddb, type ) ) )
+
+#define FS_SetObjTypeDBLK( fsh, ddb, type ) \
+ (msassert( fsh->tab_ptr->SetObjTypeDBLK != NULL ), \
+ (fsh->tab_ptr->SetObjTypeDBLK( ddb, type ) ) )
+
+#define FS_EndOperationOnDLE( fsh )\
+ (msassert( fsh->tab_ptr->EndOperationOnDLE != NULL ), \
+ (fsh->tab_ptr->EndOperationOnDLE( fsh ) ) )
+
+/**
+ Macros used to access the translation routines in the FSU table.
+ The first parameter to the File System Table functions is
+ a flag specifying whether the access is to GET or SET the memory.
+ The flag is TRUE for SET and FALSE for GET.
+**/
+
+/*
+ Names
+*/
+#define FS_GetFnameFromFDB( fsh, fdb, buf ) \
+ (msassert( fsh->tab_ptr->ModFnameFDB != NULL ), \
+ (fsh->tab_ptr->ModFnameFDB( fsh, FALSE, fdb, buf, NULL )) )
+#define FS_GetPathFromDDB( fsh, ddb, buf ) \
+ (msassert( fsh->tab_ptr->ModPathDDB != NULL ), \
+ (fsh->tab_ptr->ModPathDDB( fsh, FALSE, ddb, buf, NULL ) ) )
+#define FS_GetOSFnameFromFDB( fsh, fdb, buf ) \
+ (msassert( fsh->tab_ptr->GetOSFnameFDB != NULL ), \
+ (fsh->tab_ptr->GetOSFnameFDB( fdb, buf )) )
+#define FS_GetOSPathFromDDB( fsh, ddb, buf ) \
+ (msassert( fsh->tab_ptr->GetOSPathDDB != NULL ), \
+ (fsh->tab_ptr->GetOSPathDDB( fsh, ddb, buf ) ) )
+
+#define FS_SetFnameInFDB( fsh, fdb, buf, max ) \
+ (msassert( fsh->tab_ptr->ModFnameFDB != NULL ), \
+ (fsh->tab_ptr->ModFnameFDB( fsh, TRUE, fdb, buf, max )) )
+#define FS_SetPathInDDB( fsh, ddb, buf, max ) \
+ (msassert( fsh->tab_ptr->ModPathDDB != NULL ), \
+ (fsh->tab_ptr->ModPathDDB( fsh, TRUE, ddb, buf, max ) ) )
+#define FS_GetPnameIDB( fsh, idb, pname )\
+ (msassert( fsh->tab_ptr->GetPnameIDB != NULL ), \
+ (fsh->tab_ptr->GetPnameIDB( fsh, idb, pname ) ) )
+
+/*
+ Generic Dates
+*/
+#define FS_GetCDateFromDBLK( fsh, dblk, buf ) \
+ (msassert( fsh->tab_ptr->GetCDateDBLK != NULL ), \
+ (fsh->tab_ptr->GetCDateDBLK( dblk, buf ) ) )
+#define FS_GetMDateFromDBLK( fsh, dblk, buf ) \
+ (msassert( fsh->tab_ptr->GetMDateDBLK != NULL ), \
+ (fsh->tab_ptr->GetMDateDBLK( dblk, buf ) ) )
+#define FS_GetBDateFromDBLK( fsh, dblk, buf ) \
+ (msassert( fsh->tab_ptr->ModBDateDBLK != NULL ), \
+ (fsh->tab_ptr->ModBDateDBLK( FALSE, dblk, buf ) ) )
+
+#define FS_SetBDateInDBLK( fsh, dblk, buf ) \
+ (msassert( fsh->tab_ptr->ModBDateDBLK != NULL ), \
+ (fsh->tab_ptr->ModBDateDBLK( TRUE, dblk, buf ) ) )
+
+
+/*
+ Other FDB/DDB/IDB generic data
+*/
+#define FS_GetFileVerFromFDB( fsh, fdb, ver ) \
+ (msassert( fsh->tab_ptr->GetFileVerFDB != NULL ), \
+ (fsh->tab_ptr->GetFileVerFDB( fdb, ver ) ) )
+
+#define FS_SetOwnerIDinFDB( fsh, fdb, id ) \
+ (msassert( fsh->tab_ptr->SetOwnerId != NULL ), \
+ (fsh->tab_ptr->SetOwnerId( fsh, fdb, id ) ) )
+
+#define FS_SpecExcludeObj( fsh, ddb, fdb ) \
+ (msassert( fsh->tab_ptr->SpecExcludeObj != NULL ), \
+ (fsh->tab_ptr->SpecExcludeObj( fsh, ddb ,fdb ) ) )
+
+#define FS_SetDataSizeInDBLK( fsh, ddb, size ) \
+ (msassert( fsh->tab_ptr->SetDataSize != NULL ), \
+ (fsh->tab_ptr->SetDataSize( fsh, ddb ,size ) ) )
+
+UINT16 FS_ViewDriveSecSizeIDB( FSYS_HAND fsh, DBLK_PTR idb );
+UINT16 FS_ViewDriveNumSecIDB( FSYS_HAND fsh, DBLK_PTR idb );
+UINT16 FS_ViewDriveNumHeadsIDB( FSYS_HAND fsh, DBLK_PTR idb );
+UINT32 FS_ViewPartRelSecIDB( FSYS_HAND fsh, DBLK_PTR idb );
+UINT32 FS_ViewPartNumSecIDB( FSYS_HAND fsh, DBLK_PTR idb );
+UINT16 FS_ViewPartSysIndIDB( FSYS_HAND fsh, DBLK_PTR idb );
+#define FS_ViewPartBadBlkFlagIDB( fsh, idb ) FALSE
+
+/*
+ Other FDB/DDB OS specific data used for backup
+*/
+#define FS_GetADateFromDBLK( fsh, dblk, buf ) \
+ (msassert( fsh->tab_ptr->ModADateDBLK != NULL ), \
+ (fsh->tab_ptr->ModADateDBLK( FALSE, dblk, buf ) ) )
+
+#define FS_SetADateInDBLK( fsh, dblk, buf ) \
+ (msassert( fsh->tab_ptr->ModADateDBLK != NULL ), \
+ (fsh->tab_ptr->ModADateDBLK( TRUE, dblk, buf ) ) )
+
+/*
+ Other FDB/DDB OS specific data used for restore
+*/
+#define FS_SetOwnerId( fsh, dblk, owner ) \
+ (SUCCESS)
+
+/**
+ Routines used to create OS specific DBLKS from generic data
+**/
+#define FS_GetMaxSizeDBLK( fsh )\
+ ( 900 ) ;
+
+#define FS_InitializeGOS( fsh, gos ) \
+ (msassert( fsh->tab_ptr->InitializeGOS != NULL ), \
+ ( (fsh)->tab_ptr->InitializeGOS( (fsh), (gos) ) ) )
+
+#define FS_CreateGenFDB( fsh, data )\
+ (msassert( fsh->tab_ptr->CreateGenFDB != NULL ), \
+ ( (fsh)->tab_ptr->CreateGenFDB( (fsh), (data) ) ) )
+#define FS_CreateGenIDB( fsh, data )\
+ (msassert( fsh->tab_ptr->CreateGenIDB != NULL ), \
+ ( (fsh)->tab_ptr->CreateGenIDB( (fsh), (data) ) ) )
+
+#define FS_CreateGenDDB( fsh, data )\
+ (msassert( fsh->tab_ptr->CreateGenDDB != NULL ), \
+ ( (fsh)->tab_ptr->CreateGenDDB( (fsh), (data) ) ) )
+
+/**
+ General purpose macros and CFDB/VCB macros
+**/
+
+#define FS_GetCorruptOffsetInCFDB( cfdb ) ( ((CFDB_PTR)cfdb)->corrupt_offset )
+#define FS_GetCorruptStrmNumInCFDB( cfdb ) ( ((CFDB_PTR)cfdb)->stream_number )
+#define FS_GetBlockType( dblk ) ((dblk)->blk_type)
+#define FS_ViewStringTypeinDBLK( dblk ) ((dblk)->com.string_type) // chs:02-01-94
+#define FS_ViewBLKIDinDBLK( dblk ) ((dblk)->com.blkid)
+#define FS_ViewDIDinDBLK( dblk ) ((dblk)->com.f_d.did)
+#define FS_ViewLBAinDBLK( dblk ) ((dblk)->com.ba.lba)
+#define FS_SetLBAinDBLK( dblk, lbai ) ((dblk)->com.ba.lba = (lbai))
+#define FS_ViewPBAinVCB( dblk ) ((dblk)->com.ba.pba)
+#define FS_SetPBAinVCB( dblk, pbai ) ((dblk)->com.ba.pba = (pbai))
+#define FS_ViewFMARKinVCB( dblk ) ((dblk)->com.f_d.f_mark)
+#define FS_ViewTFMajorVerInVCB( vcb ) ( ((VCB_PTR)(vcb))->tf_major_ver )
+#define FS_ViewTFMinorVerInVCB( vcb ) ( ((VCB_PTR)(vcb))->tf_minor_ver )
+#define FS_ViewSWMajorVerInVCB( vcb ) ( ((VCB_PTR)(vcb))->sw_major_ver )
+#define FS_ViewSWMinorVerInVCB( vcb ) ( ((VCB_PTR)(vcb))->sw_minor_ver )
+#define FS_ViewTapeIDInVCB( vcb ) ( ((VCB_PTR)(vcb))->tape_id )
+#define FS_ViewTSNumInVCB( vcb ) ( ((VCB_PTR)(vcb))->tape_seq_num )
+#define FS_ViewBSNumInVCB( vcb ) ( ((VCB_PTR)(vcb))->backup_set_num )
+#define FS_ViewPswdEncryptInVCB( vcb ) ( ((VCB_PTR)(vcb))->password_encrypt_alg )
+#define FS_ViewDataEncryptInVCB( vcb ) ( ((VCB_PTR)(vcb))->data_encrypt_alg )
+#define FS_GetSetCatPbaInVCB( vcb ) ( ((VCB_PTR)(vcb))->set_cat_pba )
+#define FS_GetSetCatSeqNumberInVCB( vcb ) ( ((VCB_PTR)(vcb))->set_cat_tape_seq_num )
+#define FS_GetOnTapeCatLevel( vcb ) ( ((VCB_PTR)(vcb))->on_tape_cat_level )
+#define FS_IsSetCatInfoValid( vcb ) ( ((VCB_PTR)(vcb))->set_cat_info_valid )
+#define FS_GetOnTapeCatVer( vcb ) ( ((VCB_PTR)(vcb))->on_tape_cat_ver )
+#define FS_ViewVendorIdInVCB( vcb ) ( ((VCB_PTR)(vcb))->vendor_id )
+
+#define FS_IsNoRedirectRestore( vcb ) ( ((VCB_PTR)(vcb))->no_redirect_restore )
+#define FS_IsNonVolume( vcb ) ( ((VCB_PTR)(vcb))->non_volume )
+#define FS_ViewNumFiles( vcb ) ( ((VCB_PTR)(vcb))->set_cat_num_files )
+#define FS_ViewNumDirs( vcb ) ( ((VCB_PTR)(vcb))->set_cat_num_dirs )
+#define FS_ViewNumCorrupt( vcb ) ( ((VCB_PTR)(vcb))->set_cat_num_corrupt )
+
+#define FS_ViewTapeNameInVCB( vcb ) ( ( ((VCB_PTR )vcb)->tape_name_leng) \
+ ? ( (CHAR_PTR)((INT8_PTR)(vcb) + ((VCB_PTR)(vcb))->tape_name) ) \
+ : TEXT("") )
+
+#define FS_ViewSetNameInVCB( vcb ) ( ( ((VCB_PTR)vcb)->backup_set_name_leng) \
+ ? ( (CHAR_PTR)((INT8_PTR)(vcb) + ((VCB_PTR)(vcb))->backup_set_name) ) \
+ : TEXT("") )
+
+#define FS_ViewSetDescriptInVCB( vcb ) ( ( ((VCB_PTR)vcb)->backup_set_descript_leng) \
+ ? ( (CHAR_PTR)((INT8_PTR)(vcb) + ((VCB_PTR)(vcb))->backup_set_descript) ) \
+ : TEXT("") )
+
+#define FS_ViewUserNameInVCB( vcb ) ( ( ((VCB_PTR)vcb)->user_name_leng) \
+ ? ( (CHAR_PTR)((INT8_PTR)(vcb) + ((VCB_PTR)(vcb))->user_name) ) \
+ : TEXT("") )
+
+#define FS_ViewMachNameInVCB( vcb ) ( ( ((VCB_PTR)vcb)->machine_name_leng) \
+ ? ( (CHAR_PTR)((INT8_PTR)(vcb) + ((VCB_PTR)(vcb))->machine_name) ) \
+ : TEXT("") )
+
+#define FS_ViewShortMachNameInVCB( vcb ) ( ( ((VCB_PTR)vcb)->short_machine_name_leng) \
+ ? ( (CHAR_PTR)((INT8_PTR)(vcb) + ((VCB_PTR)(vcb))->short_machine_name) ) \
+ : TEXT("") )
+
+#define FS_ViewTapePasswordInVCB( vcb ) ( ( ((VCB_PTR)vcb)->tape_password_leng) \
+ ? ( (CHAR_PTR)((INT8_PTR)(vcb) + ((VCB_PTR)(vcb))->tape_password) ) \
+ : TEXT("") )
+
+#define FS_ViewSetPswdInVCB( vcb ) ( ( ((VCB_PTR)vcb)->backup_set_password_leng) \
+ ? ( (CHAR_PTR)((INT8_PTR)(vcb) + ((VCB_PTR)(vcb))->backup_set_password) ) \
+ : TEXT("") )
+
+#define FS_ViewVolNameInVCB( vcb ) ( ( ((VCB_PTR)vcb)->vol_name_leng) \
+ ? ( (CHAR_PTR)((INT8_PTR)(vcb) + ((VCB_PTR)(vcb))->vol_name) ) \
+ : TEXT("") )
+
+#define FS_ViewDevNameInVCB( vcb ) ( ( ((VCB_PTR)vcb)->dev_name_leng) \
+ ? ( (CHAR_PTR)((INT8_PTR)(vcb) + ((VCB_PTR)(vcb))->dev_name) ) \
+ : TEXT("") )
+
+#define FS_ViewBackupDateInVCB( vcb ) (&( ((VCB_PTR)(vcb))->backup_date ))
+
+
+/* set macros */
+#define FS_SetTapeIDInVCB( vcb, val ) ( ((VCB_PTR)(vcb))->tape_id = (val) )
+#define FS_SetTSNumInVCB( vcb, val ) ( ((VCB_PTR)(vcb))->tape_seq_num = (val) )
+#define FS_SetBSNumInVCB( vcb, val ) ( ((VCB_PTR)(vcb))->backup_set_num = (val) )
+#define FS_SetBackupDateInVCB( vcb, val ) ( (((VCB_PTR)(vcb))->backup_date) = *(val) )
+
+#define FS_SetTFMajorVerInVCB( vcb, val ) ( ((VCB_PTR)(vcb))->tf_major_ver = (CHAR)(val) )
+#define FS_SetTFMinorVerInVCB( vcb, val ) ( ((VCB_PTR)(vcb))->tf_minor_ver = (CHAR)(val) )
+#define FS_SetSWMajorVerInVCB( vcb, val ) ( ((VCB_PTR)(vcb))->sw_major_ver = (CHAR)(val) )
+#define FS_SetSWMinorVerInVCB( vcb, val ) ( ((VCB_PTR)(vcb))->sw_minor_ver = (CHAR)(val) )
+
+#define FS_SetOnTapeCatLevel( vcb, val ) ( ((VCB_PTR)(vcb))->on_tape_cat_level = (val) )
+#define FS_SetSetCatInfoValid( vcb, val ) ( ((VCB_PTR)(vcb))->set_cat_info_valid = (val) )
+#define FS_SetOnTapeCatVer( vcb, val ) ( ((VCB_PTR)(vcb))->on_tape_cat_ver = (val) )
+
+/* get macros */
+#define FS_GetVolNameInVCB( vcb, dest ) \
+ ( memcpy( (dest), ((INT8_PTR)(vcb)) + ((VCB_PTR)(vcb))->vol_name, ((VCB_PTR)(vcb))->vol_name_leng ) )
+#define FS_GetDevNameInVCB( vcb, dest ) \
+ ( memcpy( (dest), ((INT8_PTR)(vcb)) + ((VCB_PTR)(vcb))->dev_name, ((VCB_PTR)(vcb))->dev_name_leng ) )
+
+#define FS_GetTapeNameInVCB( vcb, t_name )\
+ ( memcpy((t_name), ((INT8_PTR)(vcb)) + ((VCB_PTR)(vcb))->tape_name, ((VCB_PTR)(vcb))->tape_name_leng ) )
+#define FS_GetSetNameInVCB( vcb, set_name ) \
+ ( memcpy((set_name), ((INT8_PTR)(vcb)) + ((VCB_PTR)(vcb))->backup_set_name, ((VCB_PTR)(vcb))->backup_set_name_leng ) )
+#define FS_GetSetDescrInVCB( vcb, set_name ) \
+ ( memcpy((set_name), ((INT8_PTR)(vcb)) + ((VCB_PTR)(vcb))->backup_set_descript, ((VCB_PTR)(vcb))->backup_set_descript_leng ) )
+#define FS_GetUserNameInVCB( vcb, u_name )\
+ ( memcpy((u_name), ((INT8_PTR)(vcb)) + ((VCB_PTR)(vcb))->user_name, ((VCB_PTR)(vcb))->user_name_leng ) )
+#define FS_GetMachNameInVCB( vcb, long_machine )\
+ ( memcpy( (long_machine), ((INT8_PTR)(vcb)) + ((VCB_PTR)(vcb))->machine_name, ((VCB_PTR)(vcb))->machine_name_leng ) )
+#define FS_GetShortMachNameInVCB( vcb, short_machine )\
+ ( memcpy((short_machine), ((INT8_PTR)(vcb)) + ((VCB_PTR)(vcb))->short_machine_name, ((VCB_PTR)(vcb))->short_machine_name_leng ) )
+#define FS_GetTapePswdInVCB( vcb, tp_pswd )\
+ ( memcpy( (tp_pswd), ((INT8_PTR)(vcb)) + ((VCB_PTR)(vcb))->tape_password, \
+ ((VCB_PTR)(vcb))->tape_password_leng ) )
+#define FS_GetSetPswdInVCB( vcb, set_pswd )\
+ ( memcpy( (set_pswd), ((INT8_PTR)(vcb)) + ((VCB_PTR)(vcb))->backup_set_password, \
+ ((VCB_PTR)(vcb))->backup_set_password_leng ) )
+
+#define FS_GetBackupDateInVCB( vcb, b_date )\
+ ( *(b_date) = ((VCB_PTR)(vcb))->backup_date )
+
+#define FS_IsBlockContinued( dblk ) \
+ ( (dblk)->com.continue_obj )
+
+#define FS_IsBlockCompressed( dblk ) ( (dblk)->com.compressed_obj )
+#define FS_SetCompressedBlock( dblk ) ( (dblk)->com.compressed_obj = TRUE )
+
+#define FS_GetBlockTapeSeqNumber( dblk ) \
+ ( (dblk)->com.tape_seq_num )
+
+/**
+ size macros
+**/
+
+/*
+ sizes of FDB/DDB/IDB text fields
+*/
+#define FS_SizeofFnameInFDB( fsh, fdb ) \
+ (INT16)(msassert( fsh->tab_ptr->SizeofFnameInFDB != NULL ), \
+ (fsh->tab_ptr->SizeofFnameInFDB( fsh, fdb ) ) )
+
+#define FS_SizeofPnameInIDB( fsh, idb )\
+ (msassert( fsh->tab_ptr->SizeofPnameInIDB != NULL ), \
+ (fsh->tab_ptr->SizeofPnameInIDB( fsh, idb ) ) )
+
+#define FS_SizeofPathInDDB( fsh, ddb ) \
+ (INT16)(msassert( fsh->tab_ptr->SizeofPathInDDB != NULL ), \
+ (fsh->tab_ptr->SizeofPathInDDB( fsh, ddb ) ) )
+
+#define FS_SizeofOSFnameInFDB( fsh, fdb ) \
+ (INT16)(msassert( fsh->tab_ptr->SizeofOSFnameInFDB != NULL ), \
+ (fsh->tab_ptr->SizeofOSFnameInFDB( fsh, fdb ) ) )
+
+#define FS_SizeofOSPathInDDB( fsh, ddb ) \
+ (INT16)(msassert( fsh->tab_ptr->SizeofOSPathInDDB != NULL ), \
+ (fsh->tab_ptr->SizeofOSPathInDDB( fsh, ddb ) ) )
+
+#define FS_IsBlkComplete( fsh, dblk ) \
+ (msassert( fsh->tab_ptr->IsBlkComplete != NULL ), \
+ (fsh->tab_ptr->IsBlkComplete( fsh, dblk ) ) )
+
+#define FS_CompleteBlk( fsh, dblk, buffer, size, sinfo ) \
+ (msassert( fsh->tab_ptr->CompleteBlk != NULL ), \
+ (fsh->tab_ptr->CompleteBlk( fsh, dblk, buffer, size, sinfo ) ) )
+
+#define FS_ReleaseDBLK( fsh, dblk ) \
+ (msassert( fsh->tab_ptr->ReleaseBlk != NULL ), \
+ (fsh->tab_ptr->ReleaseBlk( fsh, dblk ) ) )
+
+#define FS_DuplicateDBLK( fsh, dblk_org, dblk_dup ) \
+ (msassert( fsh->tab_ptr->DupBlk != NULL ), \
+ (fsh->tab_ptr->DupBlk( fsh, dblk_org, dblk_dup ) ) )
+
+
+#define FS_GetDisplaySizeFromDBLK( fsh, dblk ) \
+ (fsh->tab_ptr->GetDisplaySizeDBLK( fsh, dblk ) )
+
+
+/*
+ size of VCB text fields
+*/
+#define FS_SizeofVolNameInVCB( vcb ) ( ((VCB_PTR)vcb)->vol_name_leng)
+#define FS_SizeofDevNameInVCB( vcb ) ( ((VCB_PTR)vcb)->dev_name_leng)
+#define FS_SizeofTapeNameInVCB( vcb ) ( ((VCB_PTR)vcb)->tape_name_leng)
+#define FS_SizeofBackupSetNameInVCB( vcb ) ( ((VCB_PTR)vcb)->backup_set_name_leng)
+#define FS_SizeofSetDescriptInVCB( vcb ) ( ((VCB_PTR)vcb)->backup_set_descript_leng)
+#define FS_SizeofUserNameInVCB( vcb ) ( ((VCB_PTR)vcb)->user_name_leng)
+#define FS_SizeofMachNameInVCB( vcb ) ( ((VCB_PTR)vcb)->machine_name_leng)
+#define FS_SizeofShortMachNameInVCB( vcb ) ( ((VCB_PTR)vcb)->short_machine_name_leng)
+#define FS_SizeofTapePswdInVCB( vcb ) ( ((VCB_PTR)vcb)->tape_password_leng)
+#define FS_SizeofSetPswdInVCB( vcb ) ( ((VCB_PTR)vcb)->backup_set_password_leng)
+
+
+/**
+ FSU initialization & support functions
+**/
+INT16 FS_InitFileSys( DLE_HAND *dle_ptr, BOOLEAN(*crit_err)(CHAR_PTR, UINT16),
+ struct BE_CFG *cfg, UINT16 remote_filter, UINT32 file_systems ) ;
+
+VOID FS_RemoveFileSys( DLE_HAND dle_hand ) ;
+
+INT16 FS_ParsePath( DLE_HAND dle_hand,
+ CHAR_PTR input_text,
+ GENERIC_DLE_PTR *dle,
+ CHAR_PTR path,
+ INT16 *psize,
+ CHAR_PTR *file,
+ BOOLEAN *star_star ) ;
+
+#define FS_GuessDelimFromPath( path ) \
+ ( (*path == TEXT(':')) ? TEXT(':') : TEXT('\\') )
+
+/* values for fs_initialized */
+#define NRL_INITIALIZED 1
+#define SMB_INITIALIZED 2
+#define DOS_INITIALIZED 4
+#define IMAG_INITIALIZED 8
+#define NOV_INITIALIZED 16
+#define AFP_INITIALIZED 32
+#define FS_InitStatus( dle_hand ) \
+ ((dle_hand)->fs_initialized)
+
+INT16 FS_OpenFileSys( FSYS_HAND *fsh, INT16 type,
+ struct BE_CFG *cfg ) ;
+
+INT16 FS_ReOpenFileSys( FSYS_HAND fsh, INT16 type,
+ struct BE_CFG *cfg ) ;
+
+INT16 FS_CloseFileSys( FSYS_HAND fsh ) ;
+
+INT16 FS_AttachToDLE( FSYS_HAND *fsh, GENERIC_DLE_PTR dle, struct BE_CFG *cfg,
+ CHAR_PTR user_name, CHAR_PTR password ) ;
+
+INT16 FS_DetachDLE( FSYS_HAND fsh ) ;
+
+UINT16 FS_GetActualSizeDBLK( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+
+UINT16 FS_GetStringTypes( FSYS_HAND fsh ) ;
+
+
+/*
+ Translation functions
+*/
+
+VOID FS_SetDefaultDBLK( FSYS_HAND fsh, INT8 blk_type, CREATE_DBLK_PTR data ) ;
+
+INT16 FS_GetOSid_verFromDBLK( FSYS_HAND fsh, DBLK_PTR dblk, UINT16 *id, UINT16 *ver ) ;
+
+#define FS_GetOSid_verFromVCB( dblk, id, ver ) \
+ (FS_GetOSid_verFromDBLK( NULL, (dblk), (id), (ver) ) )
+
+UINT32 FS_GetAttribFromDBLK( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+
+#define FS_GetAttribFromVCB( dblk ) \
+ (FS_GetAttribFromDBLK( NULL, (dblk) ) )
+
+UINT32 FS_SetAttribFromDBLK( FSYS_HAND fsh, DBLK_PTR dblk, UINT32 attrib ) ;
+
+INT16 FS_GetOS_InfoFromDBLK( FSYS_HAND fsh, DBLK_PTR dblk, VOID_PTR os_info ) ;
+
+INT16 FS_SizeofOS_InfoInDBLK( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+
+INT16 FS_CreateGenVCB( FSYS_HAND fsh, GEN_VCB_DATA_PTR data ) ;
+
+INT16 FS_CreateGenCFDB( FSYS_HAND fsh, GEN_CFDB_DATA_PTR data ) ;
+
+INT16 FS_CreateGenUDB( FSYS_HAND fsh, GEN_UDB_DATA_PTR data ) ;
+
+/*
+ Misc functions needed for User interface
+*/
+
+CHAR FS_GetDelimiterFromOSID( UINT16 id, UINT16 ver ) ;
+
+#define DLE_LogoutDevice( dle ) \
+ (msassert ( func_tab[ (dle)->type ].LogoutDevice != NULL),\
+ (func_tab [(dle)->type].LogoutDevice( dle ) ) )
+
+ // Currently only supported in the SMS File System
+#define FS_GeneratedErrorLog( fsh, fhand ) \
+ ( ( (fsh)->tab_ptr->GeneratedErrorLog ) \
+ ? (fsh)->tab_ptr->GeneratedErrorLog( fsh, fhand ) \
+ : FALSE )
+
+/**
+ macro and proto for stream info (fsys\common\)
+**/
+
+#define FS_CopyStrmInfo( s_info_dst_ptr, s_info_src_ptr ) \
+ ( memmove( s_info_dst_ptr, s_info_src_ptr, sizeof( *s_info_src_ptr ) ) )
+
+VOID FS_InitStrmInfo( STREAM_INFO_PTR s_info, UINT32 id, UINT16 fs_attrib, UINT32 size_lo ) ;
+
+#define FS_GetNameSpace( fsh ) ((fsh)->cur_dir_info.con)
+#define FS_SetNameSpace( fsh, ns ) ((fsh)->cur_dir_info.con = (ns))
+
+#define FS_GetNameSpaceFromDBLK( dblk ) ((dblk)->com.name_space)
+#define FS_SetNameSpaceInDBLK( dblk, ns ) ((dblk)->com.name_space = (ns))
+
+// The following is a layer violation
+#define EMS_PCT_CONTINUE 0xffffffff
+#ifdef FS_EMS
+INT EMS_AddToServerList( DLE_HAND dle_list, CHAR_PTR server_name ) ;
+INT EMS_RemoveFromServerList( CHAR_PTR server_name ) ;
+
+VOID
+EMS_GetStreamName(
+ FILE_HAND hand, /* I - handle of object to read from */
+ BYTE_PTR buf, /* O - buffer to place data into */
+ UINT16 *size ); /*I/O- Entry: size of buf; Exit: number of bytes read */
+
+CHAR_PTR EMS_EnumSvrInList( INT *index );
+
+#else
+#define EMS_AddToServerList( x, y ) (FALSE)
+#define EMS_EnumSvrInList( x ) ( NULL )
+#define EMS_GetStreamName( x,y,z) (NULL)
+#define EMS_RemoveFromServerList( server_name ) (FALSE)
+#endif
+
+#endif
diff --git a/private/utils/ntbackup/inc/fsys_err.h b/private/utils/ntbackup/inc/fsys_err.h
new file mode 100644
index 000000000..452776a83
--- /dev/null
+++ b/private/utils/ntbackup/inc/fsys_err.h
@@ -0,0 +1,148 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: fsys_err.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: File system error values
+
+ Location: BE_PUBLIC
+
+
+ $Log: L:/LOGFILES/FSYS_ERR.H_V $
+ *
+ * Rev 1.14 30 Jul 1993 13:20:22 STEVEN
+ * if dir too deep make new one
+ *
+ * Rev 1.13 29 Jun 1993 17:09:02 BARRY
+ * Added FS_SKIP_OBJECT
+ *
+ * Rev 1.12 13 May 1993 13:37:30 BARRY
+ * Added FS_RESTORED_ACTIVE for NT.
+ *
+ * Rev 1.11 31 Mar 1993 08:57:08 MARILYN
+ * defined the error FS_NO_CHECKSUM
+ *
+ * Rev 1.10 01 Mar 1993 17:37:26 MARILYN
+ * added checksum verification errors
+ *
+ * Rev 1.9 15 Jan 1993 13:19:14 BARRY
+ * added support for new error messages and backup priviladge
+ *
+ * Rev 1.8 13 Jan 1993 10:30:14 STEVEN
+ * added unable to lock
+ *
+ * Rev 1.7 07 Dec 1992 12:18:14 DON
+ * Added a new error code for CRC Failure
+ *
+ * Rev 1.6 04 Sep 1992 09:20:04 BILLB
+ * Added FS_WARN_BASE and FS_DONT_WANT_STREAM so that we can refuse a particular
+ * substream in FS_WriteObject() and FS_VerifyObject().
+ *
+ * Rev 1.5 21 May 1992 13:46:20 STEVEN
+ * more long path support
+ *
+ * Rev 1.4 13 May 1992 15:24:08 BARRY
+ * Added FS_NET_DEV_ERROR.
+ *
+ * Rev 1.3 03 Mar 1992 15:17:24 DOUG
+ * Added FS_CHILDREN_NOT_COMPLETE, and FS_COMM_FAILURE
+ *
+ * Rev 1.2 30 Oct 1991 11:01:42 LORIB
+ * Changes for ACL. Added file system error for ACL data difference.
+ *
+ * Rev 1.1 29 Oct 1991 13:28:12 BARRY
+ * TRICYCLE: New file system read error.
+ *
+ * Rev 1.0 09 May 1991 13:30:44 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef FSYS_ERR_H
+#define FSYS_ERR_H
+
+#define FS_WARN_BASE (-0x150)
+
+#define FS_ERR_BASE (-0x200)
+
+#define FS_NEVER_ATTACHED (FS_ERR_BASE +1)
+#define FS_BAD_DBLK (FS_ERR_BASE +2)
+#define FS_DLE_NOT_ATTACHED (FS_ERR_BASE +3)
+#define FS_STACK_EMPTY (FS_ERR_BASE +4)
+#define FS_ACCESS_DENIED (FS_ERR_BASE +5)
+#define FS_OUT_OF_SPACE (FS_ERR_BASE +6)
+#define FS_NO_MORE (FS_ERR_BASE +7)
+#define FS_NOT_FOUND (FS_ERR_BASE +8)
+#define FS_INVALID_DIR (FS_ERR_BASE +9)
+#define FS_AT_ROOT (FS_ERR_BASE +10)
+#define FS_OBJECT_NOT_OPENED (FS_ERR_BASE +11)
+#define FS_EOF_REACHED (FS_ERR_BASE +12)
+#define FS_DEVICE_ERROR (FS_ERR_BASE +13)
+#define FS_GDATA_DIFFERENT (FS_ERR_BASE +14)
+#define FS_SECURITY_DIFFERENT (FS_ERR_BASE +15)
+#define FS_OPENED_INUSE (FS_ERR_BASE +16)
+#define FS_IN_USE_ERROR (FS_ERR_BASE +17)
+#define FS_INFO_DIFFERENT (FS_ERR_BASE +18)
+#define FS_BUFFER_TO_SMALL (FS_ERR_BASE +19)
+#define FS_DEFAULT_SPECIFIED (FS_ERR_BASE +20)
+#define FS_RESDATA_DIFFERENT (FS_ERR_BASE +21)
+#define FS_INCOMPATIBLE_OBJECT (FS_ERR_BASE +22)
+#define FS_NOT_INITIALIZED (FS_ERR_BASE +23)
+#define FS_UNDEFINED_TYPE (FS_ERR_BASE +24)
+#define FS_NOT_OPEN (FS_ERR_BASE +25)
+#define FS_INVALID_DLE (FS_ERR_BASE +26)
+#define FS_NO_MORE_DLE (FS_ERR_BASE +27)
+#define FS_BAD_DLE_HAND (FS_ERR_BASE +28)
+#define FS_DRIVE_LIST_ERROR (FS_ERR_BASE +29)
+#define FS_ATTACH_TO_PARENT (FS_ERR_BASE +30)
+#define FS_DEVICE_NOT_FOUND (FS_ERR_BASE +31)
+#define FS_BAD_INPUT_DATA (FS_ERR_BASE +32)
+#define FS_OS_ATTRIB_DIFFER (FS_ERR_BASE +37)
+
+#define INVALID_PATH_DESCRIPTOR (FS_ERR_BASE +33)
+#define INVALID_FILE_DESCRIPTOR (FS_ERR_BASE +34)
+#define DRIVE_DESCRIPTOR_ERROR (FS_ERR_BASE +35)
+#define FS_NO_MORE_CONNECTIONS (FS_ERR_BASE +36)
+
+#define FS_SERVER_ADDR_NOT_FOUND (FS_ERR_BASE +38)
+#define FS_MAX_SERVER_CONNECTIONS (FS_ERR_BASE +39)
+#define FS_BAD_ATTACH_TO_SERVER (FS_ERR_BASE +40)
+#define FS_BAD_SERVER_LOGIN (FS_ERR_BASE +41)
+#define FS_SERVER_LOGOUT_DENIED (FS_ERR_BASE +42)
+#define FS_BAD_ATTR_READ (FS_ERR_BASE +43)
+#define FS_EADATA_DIFFERENT (FS_ERR_BASE +44)
+#define FS_OBJECT_CORRUPT (FS_ERR_BASE +45) /* Read failed and can no longer be read */
+#define FS_ACLDATA_DIFFERENT (FS_ERR_BASE +46)
+#define FS_CHILDREN_NOT_COMPLETE (FS_ERR_BASE +47)
+#define FS_COMM_FAILURE (FS_ERR_BASE +48)
+#define FS_NET_DEV_ERROR (FS_ERR_BASE +49) /* Error on net drive */
+#define FS_STREAM_NOT_FOUND (FS_ERR_BASE +50)
+#define FS_STREAM_COMPLETE (FS_ERR_BASE +51)
+
+#define FS_CRC_FAILURE (FS_ERR_BASE +52) /* CRC failed to match */
+
+#define FS_UNABLE_TO_LOCK (FS_ERR_BASE +53) /* cannot lock data stream */
+#define FS_STREAM_CORRUPT (FS_ERR_BASE +54) /* one stream is hosed, others may be OK */
+
+#define FS_NO_CHECKSUM (FS_ERR_BASE +55) /* this data does not contain a checksum stream */
+#define FS_SKIP_OBJECT (FS_ERR_BASE +56) /* Don't process this object */
+#define FS_PATH_TOO_LONG (FS_ERR_BASE +57) /* Cannot create object because path is too deep */
+
+#define FS_EMS_CIRC_LOG (FS_ERR_BASE +58)
+#define FS_EMS_NO_LOG_BKUP (FS_ERR_BASE +59)
+#define FS_EMS_NO_PUBLIC (FS_ERR_BASE +60)
+#define FS_EMS_NO_PRIVATE (FS_ERR_BASE +61)
+
+/* File System warnings */
+
+#define FS_DONT_WANT_STREAM (FS_WARN_BASE + 1) /* Skip a particular data substream */
+#define FS_BUSY (FS_WARN_BASE + 2) /* Can't do something now, worth a retry */
+#define FS_NO_SECURITY (FS_WARN_BASE + 3) /* Expected to get security info but didn't */
+#define FS_RESTORED_ACTIVE (FS_WARN_BASE + 4) /* Restored over an active (running) file */
+#define FS_COMPRES_RESET_FAIL (FS_WARN_BASE + 5) /* failed to reset compression mode */
+
+#endif
diff --git a/private/utils/ntbackup/inc/fsys_prv.h b/private/utils/ntbackup/inc/fsys_prv.h
new file mode 100644
index 000000000..4416a5cbf
--- /dev/null
+++ b/private/utils/ntbackup/inc/fsys_prv.h
@@ -0,0 +1,240 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: fsys_prv.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+ Location:
+
+
+ $Log: M:/LOGFILES/FSYS_PRV.H_V $
+ *
+ * Rev 1.23 15 Jan 1994 19:16:30 BARRY
+ * Change CHAR_PTR name parameter in FS_SetupOSPathOrNameInDBLK to
+ * BYTE_PTR since it takes data in either ANSI/Unicode at run-time.
+ *
+ * Rev 1.22 24 Nov 1993 14:54:30 BARRY
+ * Changed CHAR_PTRs in I/O functions to BYTE_PTRs
+ *
+ * Rev 1.21 14 Oct 1993 17:49:52 STEVEN
+ * fix unicode bugs
+ *
+ * Rev 1.20 07 Sep 1993 14:44:10 MARINA
+ * Barry's MSNET changes
+ *
+ * Rev 1.19 13 Jan 1993 15:05:42 DOUG
+ * Changed FS_RMFS to FS_GRFS
+ *
+ * Rev 1.18 07 Dec 1992 16:30:56 STEVEN
+ * fixes from microsoft
+ *
+ * Rev 1.17 10 Nov 1992 08:12:46 STEVEN
+ * move os path to common part of dblk
+ *
+ * Rev 1.16 14 Oct 1992 12:39:16 TIMN
+ * Removed macros for stream infos
+ *
+ * Rev 1.15 07 Oct 1992 16:31:38 TIMN
+ * Updated FS_InitStrmInfo with fs_attrib parameter
+ *
+ * Rev 1.14 25 Sep 1992 12:52:26 CARLS
+ * added FS_InitStrmInfo
+ *
+ * Rev 1.13 21 Sep 1992 16:11:50 BARRY
+ * Updated stream helper functions for new stream design.
+ *
+ * Rev 1.12 18 Sep 1992 15:49:22 BARRY
+ * No longer support FS_GetStreamInfo and FS_WriteStreamHeader functions.
+ *
+ * Rev 1.11 21 May 1992 15:20:46 STEVEN
+ * added stream helper functions
+ *
+ * Rev 1.10 01 Mar 1992 12:39:20 DOUG
+ * Added support for RMFS.
+ *
+ * Rev 1.9 22 Jan 1992 10:24:06 STEVEN
+ * fix warnings for WIN32
+ *
+ * Rev 1.8 20 Dec 1991 09:11:52 STEVEN
+ * move common functions into tables
+ *
+ * Rev 1.7 24 Oct 1991 15:00:28 BARRY
+ * TRICYCLE: Added SMS function table pointers.
+ *
+ * Rev 1.6 06 Aug 1991 18:23:46 DON
+ * added nlm server volume func_list's
+ *
+ * Rev 1.5 26 Jun 1991 11:03:28 BARRY
+ * Cahnged prototype for Ersatz.
+ *
+ * Rev 1.4 22 Jun 1991 14:14:22 BARRY
+ * Added stuff for Ersatz file system.
+ *
+ * Rev 1.3 21 Jun 1991 13:21:24 BARRY
+ * Changes for new config.
+ *
+ * Rev 1.2 04 Jun 1991 19:35:14 BARRY
+ * Change last MAYN_OS2 ifdef to FS_OS2.
+ *
+ * Rev 1.1 23 May 1991 16:47:16 BARRY
+ * Changed FSYSs to be conditional on FS_XXX defines instead of product defines.
+ *
+ * Rev 1.0 09 May 1991 13:30:48 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef _fsys_prv_h_
+#define _fsys_prv_h_
+
+#define CUR_DIR_CHUNK 64
+
+UINT16 FindAllMappedDrives( DLE_HAND hand, struct BE_CFG *cfg, BOOLEAN delete_old ) ;
+VOID DLE_QueueInsert( DLE_HAND dle_hand, GENERIC_DLE_PTR new_dle ) ;
+
+INT16 FS_SavePath( FSYS_HAND fsh, UINT8_PTR path, UINT16 path_len );
+INT16 FS_AppendPath( FSYS_HAND fsh, UINT8_PTR path, UINT16 path_len );
+
+INT16 memver( BYTE_PTR buf1, BYTE_PTR buf2, UINT16 *size );
+
+INT16 DUMMY_CreateIDB( FSYS_HAND fsh, GEN_IDB_DATA_PTR data ) ;
+INT16 DUMMY_EnumSpecFiles( GENERIC_DLE_PTR dle, UINT16 *index, CHAR_PTR *path, INT16 *psize, CHAR_PTR *fname ) ;
+INT16 DUMMY_GetSpecDBLKS( FSYS_HAND fsh, DBLK_PTR dblk, INT32 *index );
+
+INT16 DUMMY_InitGOS( FSYS_HAND fsh, GOS_PTR gos ) ;
+
+INT16 DUMMY_LogoutDevice( GENERIC_DLE_PTR dle ) ;
+
+VOID DLE_RemoveRecurse(
+GENERIC_DLE_PTR dle,
+BOOLEAN ignore_use ) ;
+
+INT16 FS_FillBufferWithStream( FSYS_HAND fsh,
+ DBLK_PTR dblk,
+ VOID_PTR buffer,
+ UINT16 *size,
+ STREAM_INFO *stream_id );
+
+VOID FS_GetStreamInfo( FSYS_HAND fsh,
+ DBLK_PTR dblk,
+ STREAM_INFO_PTR *stream_info,
+ BYTE_PTR *stream_data );
+
+INT16 FS_SetupOSPathOrNameInDBLK( FSYS_HAND fsh,
+ DBLK_PTR dblk,
+ BYTE_PTR name_ptr,
+ INT16 name_size ) ;
+
+VOID FS_ReleaseOSPathOrNameInDBLK( FSYS_HAND fsh,
+ DBLK_PTR dblk ) ;
+
+FS_NAME_Q_ELEM_PTR FS_AllocPathOrName( FSYS_HAND fsh,
+ INT16 name_size ) ;
+
+VOID FS_FreeOSPathOrNameQueueInHand( FSYS_HAND fsh ) ;
+
+
+#if defined( FS_OS2 )
+INT16 AddOS2_DLE( DLE_HAND hand, CHAR drive, GENERIC_DLE_PTR *dle ) ;
+extern FUNC_LIST OS2FuncTab ;
+extern INT16 uw_os_version ;
+#define OS2_VER_1_1 0xa0a
+#define OS2_VER_1_2 0xa14
+#endif
+
+#if defined( FS_DOS )
+INT16 AddDOS_DLE( DLE_HAND hand, CHAR drive, GENERIC_DLE_PTR *dle ) ;
+extern FUNC_LIST DOSFuncTab ;
+#endif
+
+#if defined( FS_NTFS )
+VOID AddDLEsForNTFS( DLE_HAND hand ) ;
+extern FUNC_LIST NTFSFuncTab ;
+#endif
+
+#if defined( FS_EMS )
+VOID AddDLEsForEMS( DLE_HAND hand ) ;
+extern FUNC_LIST EMSFuncTab ;
+#endif
+
+#if defined( FS_ERSATZ )
+INT16 InitializeErsatzFS( DLE_HAND dle_hand ) ;
+extern FUNC_LIST ErsatzFuncTab ;
+#endif
+
+#if defined( FS_IMAGE )
+extern FUNC_LIST ImageTab ;
+#endif
+
+#if defined( FS_NONAFP )
+INT16 AddNOV_DLE( DLE_HAND hand, CHAR drive, UINT16 version, GENERIC_DLE_PTR *dle ) ;
+extern FUNC_LIST NovellFuncTab ;
+#endif
+
+#if defined( FS_AFP )
+INT16 AddAFP_DLE( DLE_HAND hand, CHAR drive, UINT16 version, GENERIC_DLE_PTR *dle ) ;
+extern FUNC_LIST AFP_NovellFuncTab ;
+#endif
+
+#if defined( FS_NOV_SERVER )
+extern FUNC_LIST ServerVolFuncTab ;
+#endif
+
+#if defined( FS_NLMNOV )
+extern FUNC_LIST NLMNovellFuncTab ;
+#endif
+
+#if defined( FS_NLMAFP )
+extern FUNC_LIST NLMAFPNovellFuncTab ;
+#endif
+
+#if defined( FS_NLMSERVER )
+extern FUNC_LIST NLMServerVolFuncTab ;
+#endif
+
+#if defined( FS_AFP ) || defined( FS_NONAFP )
+#define NOVELL_ADVANCED 1
+#define NOVELL_4_6 2
+#define IBM_PC_NET 3
+
+INT16 IdentifyNet( CHAR drive, struct BE_CFG *cfg, UINT16 *version ) ;
+#endif
+
+
+#if defined( FS_REMOTE )
+extern FUNC_LIST RemoteFuncTab ;
+extern FUNC_LIST RemoteWSFuncTab ;
+
+#elif defined( FS_FAKEREM )
+extern FUNC_LIST FakeRemoteFuncTab ;
+extern FUNC_LIST FakeRemoteWSFuncTab ;
+#endif
+
+extern FUNC_LIST GENFuncTab ;
+
+#if defined( SET_LAD )
+extern FUNC_LIST NullFuncTab ; /* GRH 10/13/90 - For Set_LAD */
+#endif
+
+#if defined( FS_SMS )
+extern FUNC_LIST TSAFuncTab ;
+extern FUNC_LIST TSFuncTab ;
+extern FUNC_LIST SMSFuncTab ;
+
+INT16 AddSmsTsaDLEs( DLE_HAND hand );
+#endif
+
+#if defined( FS_GRFS )
+extern FUNC_LIST GRFSFuncTab ;
+#endif
+
+#if defined( FS_MSNET )
+extern FUNC_LIST MSNetFuncTab ;
+#endif
+
+#endif
diff --git a/private/utils/ntbackup/inc/fsys_str.h b/private/utils/ntbackup/inc/fsys_str.h
new file mode 100644
index 000000000..cb9a51d3e
--- /dev/null
+++ b/private/utils/ntbackup/inc/fsys_str.h
@@ -0,0 +1,873 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: fsys_str.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains structure definitions for
+ The file system internals.
+
+ Location: BE_PUBLIC
+
+
+ $Log: M:/LOGFILES/FSYS_STR.H_V $
+ *
+ * Rev 1.56 24 Nov 1993 14:54:32 BARRY
+ * Changed CHAR_PTRs in I/O functions to BYTE_PTRs
+ *
+ * Rev 1.55 29 Sep 1993 20:28:40 GREGG
+ * Removed the dummy function from the table since it was only there to shut
+ * the compiler up. The compiler was complaining because the last initializer
+ * was followed by a comma, so I also removed the last comma, and in some
+ * cases, added NULLs for new functions which had been added to the bottom of
+ * the table since the last update.
+ * Files Modified: GEN_TAB.C, GR_TAB.C, TSA_TAB.C, TS_TAB.C, MNET_TAB.C,
+ * SMS_TAB.C, NTFS_TAB.C and FSYS_STR.H
+ *
+ * Rev 1.54 20 Sep 1993 17:25:02 DON
+ * Added new func table entry GeneratedErrorLog() which is currently only
+ * supported by the SMS File System. Requires prototype in fsys.h and
+ * corresponding entries added to OS specific tables.
+ * Modules updated include: gen_tab, gr_tab, sms_tab, tsa_tab, and ts_tab.
+
+ Rev 1.0 20 Sep 1993 17:20:54 DON
+Added new table entry GeneratedErrorLog
+ *
+ * Rev 1.53 13 Sep 1993 14:58:42 DOUG
+ * Added id values for GRFS Unix and Mac Agents
+ *
+ * Rev 1.52 11 Aug 1993 13:21:36 DON
+ * ***
+ * *** NOTE ***
+ *
+ * Addition of OFFSETS to ALLOCATED DATA in the VCB structure require
+ * a corresponding change to dblksize.c to account for the additional
+ * length!
+ *
+ * ***
+ *
+ * Rev 1.51 06 Aug 1993 16:34:52 DON
+ * Added booleans no_redirect_restore and non_volume to VCB and VCB_DATA structures
+ *
+ * Rev 1.50 30 Jul 1993 13:20:54 STEVEN
+ * if dir too deep make new one
+ *
+ * Rev 1.49 15 Jul 1993 19:19:42 GREGG
+ * Added compressed_obj and vendor_id; Removed compression_alg.
+ *
+ * Rev 1.48 09 Jun 1993 15:40:32 MIKEP
+ * enable c++
+ *
+ * Rev 1.47 25 Apr 1993 20:12:28 GREGG
+ * Fifth in a series of incremental changes to bring the translator in line
+ * with the MTF spec:
+ *
+ * - Store the corrupt stream number in the CFIL tape struct and the CFDB.
+ *
+ * Matches: MTF10WDB.C 1.9, FSYS.H 1.33, FSYS_STR.H 1.47, MAKECFDB.C 1.2,
+ * BACK_OBJ.C 1.36, MAYN40RD.C 1.58
+ *
+ * Rev 1.46 19 Apr 1993 18:01:52 GREGG
+ * Second in a series of incremental changes to bring the translator in line
+ * with the MTF spec:
+ *
+ * Changes to write version 2 of OTC, and to read both versions.
+ *
+ * Matches: mayn40rd.c 1.55, otc40msc.c 1.19, otc40rd.c 1.23, otc40wt.c 1.23,
+ * makevcb.c 1.15, fsys.h 1.32, fsys_str.h 1.46, tpos.h 1.16,
+ * mayn40.h 1.32, mtf.h 1.3.
+ *
+ * NOTE: There are additional changes to the catalogs needed to save the OTC
+ * version and put it in the tpos structure before loading the OTC
+ * File/Directory Detail. These changes are NOT listed above!
+ *
+ * Rev 1.45 18 Mar 1993 15:20:18 ChuckS
+ * Additional fields for Device Name in VCB
+ *
+ * Rev 1.44 16 Mar 1993 09:56:32 BARRY
+ * Added bit for initialization of MS network file system.
+ *
+ * Rev 1.43 10 Nov 1992 08:12:22 STEVEN
+ * move os path to common part of dblk
+ *
+ * Rev 1.42 21 Oct 1992 10:39:46 GREGG
+ * Changed 'set_catalog_level' to 'on_tape_cat_level'.
+ *
+ * Rev 1.41 20 Oct 1992 15:32:22 STEVEN
+ * added tape sequence number to standard structure
+ *
+ * Rev 1.40 20 Oct 1992 15:01:00 STEVEN
+ * added otc stuff for qtc/otc communication
+ *
+ * Rev 1.39 05 Oct 1992 11:24:04 STEVEN
+ * moved stream stuff to fsstream.h
+ *
+ * Rev 1.38 23 Sep 1992 13:49:40 BARRY
+ * Eliminated total_size from STD_DBLK_DATA.
+ *
+ * Rev 1.37 23 Sep 1992 09:47:38 BARRY
+ * Removed rem_size from STD_DBLK_DATA.
+ *
+ * Rev 1.36 22 Sep 1992 18:20:08 BARRY
+ * Updated CompleteBlk function for new STREAM_INFO parameter.
+ *
+ * Rev 1.35 22 Sep 1992 15:29:24 BARRY
+ * Removed FS_GetTotalSizeFromDBLK.
+ *
+ * Rev 1.34 21 Sep 1992 16:12:24 BARRY
+ * Added stream_info to fsh.
+ *
+ * Rev 1.33 18 Sep 1992 15:48:42 BARRY
+ * Removed FS_STREAM_HEADER and associated definitions.
+ *
+ * Rev 1.32 03 Sep 1992 16:28:36 BARRY
+ * Changed stream header IDs. Removed hasStreamHeaders from std_dat.
+ *
+ * Rev 1.31 01 Sep 1992 16:37:48 STEVEN
+ * fix typo
+ *
+ * Rev 1.30 01 Sep 1992 16:13:12 STEVEN
+ * added stream headers to fsys API
+ *
+ * Rev 1.29 14 Aug 1992 10:51:36 BARRY
+ * Added hasStreamHeaders field to standard dblk.
+ *
+ * Rev 1.28 12 Aug 1992 13:06:12 BARRY
+ * Removed SMS fields from GOS.
+ *
+ * Rev 1.27 11 Aug 1992 17:20:52 BARRY
+ * Added stream id STRM_UNKNOWN.
+ *
+ * Rev 1.26 24 Jul 1992 14:30:10 NED
+ * Incorporated Skateboard and BigWheel changed into Graceful Red code,
+ * including MTF4.0 translator support, adding 3.1 file-system structures
+ * support to the 3.1 translator, additions to GOS to support non-4.0 translators.
+ *
+ * Rev 1.25 24 Jul 1992 13:59:42 BARRY
+ * Added some stream IDs and names.
+ *
+ * Rev 1.24 22 Jul 1992 13:38:32 CHUCKB
+ * In function table structure, changed return type of Get Volume Name function to VOID.
+ *
+ * Rev 1.23 22 Jul 1992 13:20:14 GREGG
+ * Changed stream header struct to match Microsoft spec, and added three new
+ * stream types for OTC.
+ *
+ * Rev 1.22 09 Jul 1992 14:45:32 STEVEN
+ * BE_Unicode updates
+ *
+ * Rev 1.21 21 May 1992 13:47:06 STEVEN
+ * more long path support
+ *
+ * Rev 1.20 04 May 1992 09:41:40 LORIB
+ * Fixed error in structure member name.
+ *
+ * Rev 1.19 16 Mar 1992 11:57:48 STEVEN
+ * added stream header for 4.0 format
+ *
+ * Rev 1.18 13 Mar 1992 09:18:32 LORIB
+ * Changes for Tape Format 4.0 and variable path length support.
+ *
+ * Rev 1.17 03 Mar 1992 16:10:48 STEVEN
+ * added functions for long paths
+ *
+ * Rev 1.16 28 Feb 1992 13:05:44 STEVEN
+ * step one for varible length paths
+ *
+ * Rev 1.15 07 Feb 1992 16:11:34 STEVEN
+ * added object types
+ *
+ * Rev 1.14 13 Jan 1992 18:42:32 STEVEN
+ * added NTFS_ID and NTFS_VER
+ *
+ * Rev 1.13 20 Dec 1991 09:31:48 STEVEN
+ * move common files to tables
+ *
+ * Rev 1.12 25 Nov 1991 16:54:02 BRYAN
+ * Forgot to update fsys_str.h for parameter change to GetOSPathDDB().
+ *
+ * Rev 1.11 14 Nov 1991 09:16:38 BARRY
+ * Moved file system init specifiers from be_init.h to fsys_str.h.
+ *
+ * Rev 1.10 06 Nov 1991 08:50:48 BARRY
+ * Removed path changes.
+ *
+ * Rev 1.9 31 Oct 1991 18:48:10 BARRY
+ * Added info field for cur_dir to FSH.
+ *
+ * Rev 1.8 31 Oct 1991 16:32:00 BARRY
+ * TRICYCLE: Added support for supplemental path info to FS entry points.
+ * Added new os_ver change for LoriB's ACL additions to OS/2 file system.
+ *
+ * Rev 1.7 22 Aug 1991 16:50:02 BARRY
+ * Added Novell SMS id and ver.
+ *
+ * Rev 1.6 14 Aug 1991 12:50:22 STEVEN
+ * add FindObjClose
+ *
+ * Rev 1.5 07 Aug 1991 11:47:32 DAVIDH
+ * Added FS_AFP_NLM_VER define.
+ *
+ * Rev 1.4 30 Jun 1991 16:20:56 BARRY
+ * Added stuff for the Ersatz file system.
+ *
+ * Rev 1.3 21 Jun 1991 13:42:40 STEVEN
+ * software versions should be unsigned
+ *
+ * Rev 1.2 21 Jun 1991 13:23:06 BARRY
+ * Changes for new config.
+ *
+ * Rev 1.1 23 May 1991 16:51:44 BARRY
+ * Changed queues.h include to double quotes.
+ *
+ * Rev 1.0 09 May 1991 13:31:30 HUNTER
+ * Initial revision.
+
+**/
+/* begin include list */
+#ifndef FSYS_STR_H
+#define FSYS_STR_H 1
+
+#include "queues.h"
+
+/* $end$ include list */
+
+
+/**
+ OS_ID definitions
+**/
+#define FS_PC_DOS 0
+#define FS_PC_DOS_VER 0
+#define FS_NON_AFP_NOV 1
+#define FS_NON_AFP_NOV_VER 0
+#define FS_PC_OS2 2
+#define FS_PC_OS2_VER 0
+#define FS_PC_OS2_ACL_VER 1 /* For LAN Manager ACL support */
+#define FS_MAC_FINDER 3
+#define FS_MAC_FINDER_VER 0
+#define FS_MAC_TOPS 4
+#define FS_MAC_TOPS_VER 0
+#define FS_MAC_APPLESHARE 5
+#define FS_MAC_APPLESHARE_VER 0
+#define FS_A_UX 6
+#define FS_A_UX_VER 0
+#define FS_PC_IMAGE 7
+#define FS_PC_IMAGE_VER 0
+#define FS_AFP_NOVELL 8
+#define FS_AFP_NOVELL_VER 0
+#define FS_AFP_NOVELL31 9 /* AFP dirs for MaynStream 3.1+ */
+#define FS_AFP_NOVELL31_VER 1 /* For files and dirs under 3.1+ */
+#define FS_AFP_NLM_VER 2 /* For NLM files and dirs */
+
+#define FS_NON_AFP_NOV31 10 /* NONAFP dirs for MaynStream 3.1+ */
+#define FS_NON_AFP_NOV31_VER 1 /* For files and dirs under 3.1+ */
+
+#define FS_ERSATZ 11 /* The phony file system */
+#define FS_ERSATZ_VER 0
+
+#define FS_NLM_AFP_NOVELL31 12 /* NLM AFP system */
+#define FS_NLM_AFP_NOVELL31_VER 1 /* for files and dirs under 3.1 */
+
+#define FS_NOV_SMS 13 /* Novell SMS file system */
+#define FS_NOV_SMS_VER 0
+
+#define FS_NTFS_ID 14 /* Windows32 NT file system */
+#define FS_NTFS_VER 0
+
+#define FS_GOS 0xff
+#define FS_UNKNOWN_OS -1
+#define FS_GOS_UTF_VER 1
+
+/* OS IDs and VERs for older FSs writing the MTF 4.0 format */
+#define FS_PC_OS2_40 16
+#define FS_PC_OS2_40_VER 0
+
+#define FS_NONAFP_NOV_40 17
+#define FS_NONAFP_NOV_40_VER 0
+
+#define FS_AFP_NOVELL_40 18
+#define FS_AFP_NOVELL_40_VER 0
+
+#define FS_GRFS_UNIX 20
+#define FS_GRFS_UNIX_VER 0
+
+#define FS_GRFS_MAC 21
+#define FS_GRFS_MAC_VER 0
+
+#define FS_EMS_MDB_ID 30
+#define FS_EMS_MDB_VER 0
+
+#define FS_EMS_DSA_ID 31
+#define FS_EMS_DSA_VER 0
+
+//#define FS_EMS_BRICK_ID 32
+//#define FS_EMS_BRICK_VER 0
+//
+//#define FS_EMS_SERVER_ID 33
+//#define FS_EMS_SERVER_VER 0
+
+#define FS_UNKNOWN_VER -1
+
+
+/*
+ * Bit values for selected file systems to init.
+ */
+#define FS_INIT_GENERIC BIT0 /* Generic FS -- required */
+#define FS_INIT_NLM_NOV BIT1 /* NLM AFP and NONAFP */
+#define FS_INIT_NLM_SERVER BIT3 /* NLM server only */
+#define FS_INIT_NOVELL BIT4 /* DOS AFP and NONAFP */
+#define FS_INIT_NOVELL_SERVER BIT6 /* DOS server only */
+#define FS_INIT_IBM_PC_LAN BIT7 /* PC lan */
+#define FS_INIT_DOS_REMOTE BIT8 /* REMOTE and REMOTE WS */
+#define FS_INIT_IMAGE BIT9 /* DOS images */
+#define FS_INIT_OS2 BIT10 /* OS2 FAT and HPFS */
+#define FS_INIT_ERSATZ BIT11 /* Dummy file system */
+#define FS_INIT_SMS BIT12 /* Novell SMS */
+#define FS_INIT_MSNET BIT13 /* MSoft Network File Sys */
+#define FS_INIT_ALL 0xffffffff /* Enable all compiled FSs */
+
+
+/**
+ support structures for File System Functions
+**/
+
+typedef union {
+ UINT32 con;
+ VOID_PTR ptr;
+} SPACE32 ;
+
+/*
+ File system handle structure.
+*/
+typedef struct FSYS_HAND_STRUCT {
+ DLE_HAND dle_hand ; /* pointer to active DLE list */
+ GENERIC_DLE_PTR attached_dle; /* pointer to attached DLE */
+ INT16 leng_dir ; /* length of directory */
+ CHAR_PTR cur_dir; /* needed to build DDB path text */
+ SPACE32 cur_dir_info ; /* optional info about current dir */
+ struct BE_CFG *cfg; /* pointer to configuration */
+ INT16 f_type ; /* type of file system */
+ struct FUNC_LIST *tab_ptr ; /* pointer to function table */
+ Q_HEADER min_ddb_stk ; /* PushMinDDB() stack */
+ SPACE32 reserved ; /* used internally .. OS depend */
+ BOOLEAN hand_in_use ; /* TRUE of the file handle is used */
+ struct FILE_HAND_STRUCT *file_hand ;
+ Q_HEADER in_use_name_q ; /* path buffer queue */
+ Q_HEADER avail_name_q ; /* path buffer queue */
+ BYTE_PTR stream_ptr ; /* pointer to path stream read in */
+ UINT16 stream_buf_size ; /* size of above buffer */
+ STREAM_INFO stream_info; /* info for path/file name stream */
+} *FSYS_HAND;
+
+
+/*
+ Open modes for the FS_OpenFile() function
+*/
+typedef enum {
+ FS_READ,
+ FS_WRITE,
+ FS_VERIFY
+} OPEN_MODE ;
+
+typedef enum {
+ FROM_START,
+ FROM_END,
+ FROM_CURRENT
+} SEEK_MODE ;
+
+typedef enum {
+ DOS_OBJECT,
+ NOV_OBJECT,
+ AFP_OBJECT,
+ IMAGE_OBJECT,
+ OS2_OBJECT,
+ NOV_SMS_OBJECT,
+ NTFS_OBJECT,
+ UNKNOWN_OBJECT
+} OBJECT_TYPE ;
+
+/*
+ FSU file handle
+*/
+
+typedef struct FILE_HAND_STRUCT *FILE_HAND;
+typedef struct FILE_HAND_STRUCT {
+ FSYS_HAND fsh ; /* file system handle */
+ INT16 mode; /* mode for opening */
+ BOOLEAN opened_in_use; /* TRUE if file opened in use */
+ UINT32 size ; /* size of opened file/dir data */
+ UINT32 obj_pos; /* file pointer possition */
+ SPACE32 obj_hand ; /* OS specific object handle */
+ DBLK_PTR dblk ; /* used to close the object */
+} FILE_HAND_STRUCT;
+
+
+/*
+ Request structure standard elements
+*/
+typedef struct STD_DBLK_DATA *STD_DBLK_DATA_PTR;
+typedef struct STD_DBLK_DATA {
+ DBLK_PTR dblk; /* points to requesters memory */
+ UINT8 os_id; /* the ID of the OS_INFO below */
+ UINT8 os_ver; /* the version of the OS_INFO below */
+ /* data. ( offset from start of data) */
+ UINT64 disp_size; /* size to display to user */
+ BOOLEAN continue_obj ; /* true if object is a continuation */
+ /* of a split DBLK */
+ UINT32 attrib ; /* Gen common attributes TFLDEFS.H */
+ UINT32 blkid ; /* tape format block ID */
+ UINT32 did ; /* tape format directory ID */
+ UINT32 lba; /* logical block address */
+ UINT16 string_type ; /* type of strings UNICODE/ASCII */
+ UINT16 tape_seq_num ; /* tape # where block exists */
+ BYTE_PTR os_info; /* pointer to OS info structure */
+ UINT16 os_info_size; /* size of OS info structure */
+ BOOLEAN compressed_obj ; /* data associated w/ DBLK is compressed */
+} STD_DBLK_DATA ;
+
+/*
+ * These bits have been added in NetWare 386 and reside in the new additional
+ * 16-bits of attributes kept for '386 files and directories. (Stored in the
+ * "attributes_386" field of the NetWare 386 info for FDBs and DDBs.)
+ */
+#define NOV_IMM_PURGE 0x0001 /* Purge immediate */
+#define NOV_REN_INHIBIT 0x0002 /* Rename inhibit */
+#define NOV_DEL_INHIBIT 0x0004 /* Delete inhibit */
+#define NOV_CPY_INHIBIT 0x0008 /* Copy inhibit */
+
+/*
+ * Additional information kept by NetWare 386 for directories that
+ * we'll add to the DDB.
+ */
+typedef struct NOVELL_386_DIR {
+ BOOLEAN info_valid ; /* TRUE when info below is valid */
+ UINT32 maximum_space ; /* Max disk space allowed for dir */
+ UINT16 attributes_386 ; /* Most sig 16 bits of 32-bit attr */
+ UINT8 extend_attr ; /* Most sig byte of low 16 bits */
+ UINT8 inherited_rights ; /* Most sig byte of rights mask */
+} NOVELL_386_DIR ;
+
+/*
+ * Additional information kept by NetWare 386 for files that we'll keep
+ * in the FDB.
+ */
+typedef struct NOVELL_386_FILE {
+ BOOLEAN info_valid ; /* TRUE when info below is valid */
+ UINT16 creation_time ;
+ UINT32 archiver_id ;
+ UINT16 attributes_386 ; /* Most sig 16 bits of 32-bit attr */
+ UINT32 last_modifier_id ;
+ UINT32 trust_fork_size ; /* Trustee info */
+ UINT32 trust_fork_offset ;
+ UINT8 trust_fork_format ; /* See NOVCOM.H for trust formats */
+ UINT16 inherited_rights ; /* Rights mask--new for files */
+} NOVELL_386_FILE ;
+
+/*
+ Global OS-info structure
+*/
+typedef struct GOS *GOS_PTR;
+typedef struct GOS{
+ UINT32 nov_owner_id;
+ UINT8 max_rights ; /* NOV max rights */
+ UINT8 finder[32]; /* MAC finder data */
+ ACHAR long_name[32] ; /* MAC long name */
+ UINT32 data_fork_size ; /* size of the generic data fork */
+ UINT32 data_fork_offset ; /* offset to start of generic data fork */
+ UINT32 res_fork_size ; /* size of MAC resource data */
+ UINT32 res_fork_offset ; /* offset to start of MAC resource data */
+ UINT32 trust_fork_size ; /* size of novell trustee data */
+ UINT32 trust_fork_offset; /* offset to start of novell trustee data */
+ INT16 long_path_leng ; /* MAC long path length */
+ ACHAR_PTR long_path ; /* MAC long path in format -> :fred:sue */
+ UINT8 trust_fork_format ;/* format type of trustee information */
+
+ /* NK 7/7/92 added for translators: */
+ /* the following bit definitions are the same as used by Novell */
+
+ /* Novell directory max rights */
+ UINT novell_directory_max_rights;
+
+ #define NOVA_DIR_READ_RIGHTS BIT0
+ #define NOVA_DIR_WRITE_RIGHTS BIT1
+ #define NOVA_DIR_OPEN_FILE_RIGHTS BIT2
+ #define NOVA_DIR_CREATE_FILE_RIGHTS BIT3
+ #define NOVA_DIR_DELETE_FILE_RIGHTS BIT4
+ #define NOVA_DIR_PARENTAL_RIGHTS BIT5
+ #define NOVA_DIR_SEARCH_RIGHTS BIT6
+ #define NOVA_DIR_MOD_FILE_ATTRIBS BIT7
+
+ /* Novell file attributes */
+ UINT novell_file_attributes;
+ #define NOVA_FILE_READ_ONLY BIT0
+ #define NOVA_FILE_HIDDEN BIT1
+ #define NOVA_FILE_SYSTEM BIT2
+ #define NOVA_FILE_EXECUTE_ONLY BIT3
+ #define NOVA_FILE_MODIFIED BIT5
+ #define NOVA_FILE_SHAREABLE BIT7
+
+ /* Novell file extended attributes */
+ UINT novell_extended_attributes;
+ #define NOVA_FILE_TRANSACTIONAL BIT4
+ #define NOVA_FILE_INDEXING BIT5
+
+ /* OS/2 file and directory fields */
+ DATE_TIME access_date ;
+ UINT32 ea_fork_size ;
+ UINT32 ea_fork_offset;
+ UINT32 acl_fork_size ;
+ UINT32 acl_fork_offset;
+ UINT32 alloc_size ;
+
+ /* AFP fields */
+ NOVELL_386_DIR dir_info_386 ;
+ NOVELL_386_FILE file_info_386 ;
+ BYTE proDosInfo[6] ; /* Added in version 1. */
+
+ /* non-AFP fields */
+ UINT16 access_date16;
+
+} GOS;
+
+/* Novell trustee fork data formats */
+#define TRUSTEE_FMT_286 1 /* NetWare 286 formatted trustees */
+#define TRUSTEE_FMT_386 2 /* NetWare 386 formatted trustees */
+#define TRUSTEE_FMT_UTF 3 /* 6 byte format for gos.trust_fork_format */
+
+
+/*
+ Request structure for FS_CreateVCB() function
+*/
+/*
+ NOTE:Addition of OFFSETS to ALLOCATED DATA in this structure require
+ a change to dblksize.c to account for the additional length!
+*/
+typedef struct GEN_VCB_DATA *GEN_VCB_DATA_PTR;
+typedef struct GEN_VCB_DATA {
+
+ STD_DBLK_DATA std_data;
+
+ UINT32 f_mark ; /* tape format - number of file marks */
+ UINT32 tape_id ; /* tape format - tape ID */
+ UINT16 tape_seq_num ; /* which tape in a tape family */
+ CHAR_PTR tape_name ; /* text tape name */
+ UINT16 tape_name_size ; /* size of the above name */
+ UINT16 bset_num ; /* backup set number in tape family */
+ CHAR_PTR bset_name ; /* text backup set name */
+ UINT16 bset_name_size ; /* size of the above name */
+ CHAR_PTR bset_descript ; /* text description of backup set */
+ UINT16 bset_descript_size ; /* size of the above description */
+ CHAR tf_major_ver ; /* tape format version - major */
+ CHAR tf_minor_ver ; /* tape format version - minor */
+ CHAR sw_major_ver ; /* application version - major */
+ CHAR sw_minor_ver ; /* application version - minor */
+ CHAR_PTR machine_name ; /* text name of source machine */
+ UINT16 machine_name_size ; /* size of the above name */
+ CHAR_PTR short_m_name ; /* short name for the machine */
+ UINT16 short_m_name_size ; /* size of the above name */
+ CHAR_PTR volume_name ; /* text name of the Disk volume */
+ UINT16 volume_name_size ; /* size of the above name */
+ CHAR_PTR user_name ; /* name of the user who backed up */
+ UINT16 user_name_size ; /* size of the above name */
+ UINT16 password_encrypt_alg; /* algorithm used to encrypt the password*/
+ UINT16 data_encrypt_alg ; /* algorithm used to encrypt the data */
+ CHAR_PTR bset_password ; /* backup set password */
+ UINT16 bset_password_size ; /* size of the above password */
+ CHAR_PTR tape_password ; /* tape password */
+ UINT16 tape_password_size ; /* size of the above password */
+ UINT32 pba ; /* physical block address */
+ UINT32 set_cat_pba ; /* oba if set catatalog */
+ UINT16 set_cat_tape_seq_num ;/* sequence number of tape where cat is */
+ UINT16 set_cat_num_files ; /* number of files */
+ UINT16 set_cat_num_dirs ; /* numbers of directores in set */
+ UINT16 set_cat_num_corrupt ; /* number of corrupt objects */
+ UINT16 on_tape_cat_level ; /* catalog level FULL - PARTIAL- NONE */
+ BOOLEAN set_cat_info_valid ; /* TRUE if the set catalog info is valid */
+ UINT8 on_tape_cat_ver ; /* OTC version */
+ DATE_TIME_PTR date ; /* backup date and time */
+ CHAR_PTR device_name ; /* points to full device name */
+ UINT16 dev_name_size ; /* Size of the device name */
+ UINT16 vendor_id ;
+ BOOLEAN no_redirect_restore ; /* set can not be redirected */
+ BOOLEAN non_volume ; /* set can only be restored to non volume */
+
+} GEN_VCB_DATA;
+
+/*
+ Request structure for FS_CreateFDB() function
+*/
+typedef struct GEN_FDB_DATA *GEN_FDB_DATA_PTR;
+typedef struct GEN_FDB_DATA {
+
+ STD_DBLK_DATA std_data;
+
+ CHAR_PTR fname; /* text file name */
+ UINT16 fname_size ; /* name of above file */
+ DATE_TIME_PTR creat_date; /* date of creation */
+ DATE_TIME_PTR mod_date; /* date of last write */
+ DATE_TIME_PTR backup_date; /* date of last backup*/
+ DATE_TIME_PTR access_date; /* date of last access*/
+ UINT32 file_ver; /* file verison */
+} GEN_FDB_DATA;
+
+/*
+ Request structure for FS_CreateCFDB() function
+*/
+typedef struct GEN_CFDB_DATA *GEN_CFDB_DATA_PTR;
+typedef struct GEN_CFDB_DATA {
+
+ STD_DBLK_DATA std_data;
+
+ UINT32 corrupt_offset; /* offset to first corrupt byte */
+ UINT16 stream_number ; /* sequence number of first corrupt stream */
+
+} GEN_CFDB_DATA;
+
+/*
+ Request structure for FS_CreateUDB() function
+*/
+typedef struct GEN_UDB_DATA *GEN_UDB_DATA_PTR ;
+typedef struct GEN_UDB_DATA {
+
+ STD_DBLK_DATA std_data;
+
+} GEN_UDB_DATA;
+
+/*
+ Request structure for FS_CreateIDB() function
+*/
+
+typedef struct GEN_IDB_DATA *GEN_IDB_DATA_PTR;
+typedef struct GEN_IDB_DATA {
+
+ STD_DBLK_DATA std_data;
+
+ CHAR_PTR pname ; /* partion name */
+ UINT16 pname_size ; /* size of the above name */
+ UINT16 byte_per_sector ; /* number of bytes per sector */
+ UINT16 hsect ; /* sectors per track */
+ UINT16 hhead ; /* number of heads */
+ UINT32 rsect ; /* starting relative sector number */
+ UINT32 num_sect ; /* total num of sectors in partition */
+ UINT16 sys_ind ; /* OS indicatior - see DOS Tec-Ref */
+ BOOLEAN has_bad_blk_map ; /* TRUE if data contains bad blk maps*/
+
+} GEN_IDB_DATA;
+
+/*
+ Request structure for FS_CreateDDB() function
+*/
+typedef struct GEN_DDB_DATA *GEN_DDB_DATA_PTR;
+typedef struct GEN_DDB_DATA {
+
+ STD_DBLK_DATA std_data;
+
+ CHAR_PTR path_name ; /* path name in generic format */
+ INT16 path_size ; /* size of the above name */
+ DATE_TIME_PTR creat_date; /* creation date */
+ DATE_TIME_PTR mod_date; /* date of last modification */
+ DATE_TIME_PTR backup_date; /* date of last backup */
+ DATE_TIME_PTR access_date; /* date of last access */
+} GEN_DDB_DATA;
+
+
+typedef union CREATE_DBLK *CREATE_DBLK_PTR;
+typedef union CREATE_DBLK {
+ GEN_UDB_DATA u;
+ GEN_VCB_DATA v;
+ GEN_FDB_DATA f;
+ GEN_CFDB_DATA c;
+ GEN_IDB_DATA i;
+ GEN_DDB_DATA d;
+} CREATE_DBLK ;
+
+/**
+ File system functions
+**/
+typedef struct FUNC_LIST *FUNC_LIST_PTR;
+typedef struct FUNC_LIST {
+
+ INT16 ( *InitFsys )( DLE_HAND hand, struct BE_CFG *cfg, UINT32 fsys_mask ) ;
+ INT16 ( *FindDrives )( DLE_HAND hand, struct BE_CFG *cfg, UINT32 fsys_mask ) ;
+ VOID ( *RemoveDrive )( GENERIC_DLE_PTR dle ) ;
+ VOID ( *DeInit )( DLE_HAND hand ) ;
+
+ INT16 ( *DevDispName)(GENERIC_DLE_PTR dle, CHAR_PTR name, INT16 size, INT16 type ) ;
+ VOID ( *GetVolName)(GENERIC_DLE_PTR dle, CHAR_PTR name ) ;
+ INT16 ( *SizeofVolName)(GENERIC_DLE_PTR dle ) ;
+ INT16 ( *MakePath)( CHAR_PTR buf, INT16 bsize, GENERIC_DLE_PTR dle, CHAR_PTR path, INT16 psize, CHAR_PTR fname ) ;
+ VOID ( *InitMakeData)( FSYS_HAND fsh, INT16 blk_type, CREATE_DBLK_PTR data ) ;
+
+ BOOLEAN ( *IsBlkComplete)( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+ INT16 ( *CompleteBlk )( FSYS_HAND fsh, DBLK_PTR dblk, BYTE_PTR buffer, UINT16 *size, STREAM_INFO_PTR sinfo ) ;
+ INT16 ( *DupBlk)( FSYS_HAND fsh, DBLK_PTR dblk_org, DBLK_PTR dblk_dup ) ;
+ VOID ( *ReleaseBlk)( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+
+ INT16 ( *AttachToDLE )( FSYS_HAND fsh, GENERIC_DLE_PTR dle, CHAR_PTR uname, CHAR_PTR pswd ) ;
+ INT16 ( *DetachDLE )( FSYS_HAND fsh ) ;
+ INT32 ( *EndOperationOnDLE )( FSYS_HAND fsh ) ;
+
+ BOOLEAN ( *ProcessDDB )( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+ INT16 ( *GetCurrentDDB )( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+ INT16 ( *GetCurrentPath )( FSYS_HAND fsh, CHAR_PTR path, INT16 *size ) ;
+ INT16 ( *GetDirIDinDDB )( DBLK_PTR ddb, CHAR_PTR buf ) ;
+ INT16 ( *SizeofDirIDinDDB )( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+ INT16 ( *GetBasePath )( FSYS_HAND fsh, CHAR_PTR path, INT16 *size ) ;
+ INT16 ( *ChangeDir )( FSYS_HAND fsh, CHAR_PTR path, INT16 psize ) ;
+ INT16 ( *ChangeDirUp )( FSYS_HAND fsh ) ;
+
+ INT16 ( *CreateObj )( FSYS_HAND fsh, DBLK_PTR dblk );
+ INT16 ( *OpenObj )( FSYS_HAND fsh, FILE_HAND *hand, DBLK_PTR dblk, OPEN_MODE Mode ) ;
+ INT16 ( *SeekObj )( FILE_HAND hand, UINT32 *offset ) ;
+ INT16 ( *ReadObj )( FILE_HAND hand, BYTE_PTR buffer, UINT16 *size, UINT16 *blk_size, STREAM_INFO_PTR s_info ) ;
+ INT16 ( *WriteObj )( FILE_HAND hand, BYTE_PTR buffer, UINT16 *size, UINT16 *blk_size, STREAM_INFO_PTR s_info ) ;
+ INT16 ( *VerifyObj )( FILE_HAND hand, BYTE_PTR buffer, BYTE_PTR data, UINT16 *size, UINT16 *blk_size, STREAM_INFO_PTR s_info ) ;
+ INT16 ( *CloseObj )( FILE_HAND hand ) ;
+ INT16 ( *DeleteObj )( FSYS_HAND fsh, DBLK_PTR dblk );
+
+ INT16 ( *GetObjInfo )( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+ INT16 ( *SetObjInfo )( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+ INT16 ( *VerObjInfo )( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+
+ INT16 ( *FindFirstObj )( FSYS_HAND fsh, DBLK_PTR ddb, CHAR_PTR os_name, UINT16 obj_type ) ;
+ INT16 ( *FindNextObj )( FSYS_HAND fsh, DBLK_PTR Info ) ;
+ INT16 ( *PushMinDDB )( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+ INT16 ( *PopMinDDB )( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+ INT16 ( *GetSpecialDBLKS )( FSYS_HAND fsh, DBLK_PTR cblock, INT32 *index );
+ INT16 ( *EnumSpecialFiles )( GENERIC_DLE_PTR dle, UINT16 *index, CHAR_PTR *path, INT16 *psize, CHAR_PTR *fname ) ;
+
+ /* get_set is TRUE for SET and FALSE for get */
+ INT16 ( *ModFnameFDB )( FSYS_HAND fsh, BOOLEAN get_set, DBLK_PTR fdb, CHAR_PTR buf, INT16_PTR max ) ;
+ INT16 ( *ModPathDDB )( FSYS_HAND fsh, BOOLEAN get_set, DBLK_PTR ddb, CHAR_PTR buf, INT16_PTR max ) ;
+ INT16 ( *GetOSFnameFDB )( DBLK_PTR fdb, CHAR_PTR buf ) ;
+ INT16 ( *GetPnameIDB )( FSYS_HAND fsh, DBLK_PTR fdb, CHAR_PTR buf ) ;
+ INT16 ( *GetOSPathDDB )( FSYS_HAND fsh, DBLK_PTR ddb, CHAR_PTR buf ) ;
+ INT16 ( *GetCDateDBLK )( DBLK_PTR dblk, DATE_TIME *buf ) ;
+ INT16 ( *GetMDateDBLK )( DBLK_PTR dblk, DATE_TIME *buf ) ;
+ INT16 ( *ModBDateDBLK )( BOOLEAN get_set, DBLK_PTR dblk, DATE_TIME *buf ) ;
+ INT16 ( *ModADateDBLK )( BOOLEAN get_set, DBLK_PTR dblk, DATE_TIME *buf ) ;
+ UINT64 ( *GetDisplaySizeDBLK )( FSYS_HAND fsh, DBLK_PTR fdb ) ;
+ INT16 ( *ModAttribDBLK )( BOOLEAN get_set, DBLK_PTR dblk, UINT32 *attrib ) ;
+ INT16 ( *GetFileVerFDB )( DBLK_PTR fdb, UINT32_PTR ver ) ;
+ VOID ( *SetOwnerId )( FSYS_HAND fsh, DBLK_PTR fdb, UINT32 id ) ;
+
+ INT16 ( *GetObjTypeDBLK )( DBLK_PTR dblk, OBJECT_TYPE *type ) ;
+
+ INT16 ( *SizeofFnameInFDB )( FSYS_HAND fsh, DBLK_PTR fdb ) ;
+
+ INT16 ( *SizeofPathInDDB )( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+ INT16 ( *SizeofOSFnameInFDB )( FSYS_HAND fsh, DBLK_PTR fdb ) ;
+ INT16 ( *SizeofPnameInIDB )( FSYS_HAND fsh, DBLK_PTR fdb ) ;
+ INT16 ( *SizeofOSPathInDDB )( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+ INT16 ( *SizeofOSInfo )( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+ INT16 ( *GetOS_InfoDBLK )( DBLK_PTR dblk, BYTE_PTR os_info, INT16_PTR size ) ;
+ INT16 ( *GetActualSizeDBLK )( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+
+ INT16 ( *InitializeGOS )( FSYS_HAND fsh, GOS_PTR gos ) ;
+
+ INT16 ( *CreateGenFDB )( FSYS_HAND fsh, GEN_FDB_DATA_PTR data ) ;
+ INT16 ( *CreateGenIDB )( FSYS_HAND fsh, GEN_IDB_DATA_PTR data ) ;
+ INT16 ( *CreateGenDDB )( FSYS_HAND fsh, GEN_DDB_DATA_PTR data ) ;
+
+ INT16 ( *ChangeIntoDDB )( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+
+ INT16 ( *SpecExcludeObj )( FSYS_HAND fsh, DBLK_PTR ddb, DBLK_PTR fdb ) ;
+
+ INT16 ( *SetDataSize )( FSYS_HAND fsh, DBLK_PTR ddb, UINT32 size ) ;
+
+ INT16 ( *SetObjTypeDBLK )( DBLK_PTR dblk, OBJECT_TYPE type ) ;
+
+ INT16 ( *LogoutDevice) ( GENERIC_DLE_PTR dle ) ;
+
+ INT16 ( *FindObjClose )( FSYS_HAND fsh, DBLK_PTR Info ) ;
+
+ INT16 ( *SizeofDevName )( GENERIC_DLE_PTR dle ) ;
+
+ BOOLEAN ( *GeneratedErrorLog )( FSYS_HAND fsh, INT fhand );
+
+} FUNC_LIST;
+
+extern FUNC_LIST func_tab[ MAX_DRV_TYPES ] ;
+
+/* VCB structure */
+/*
+ NOTE:Addition of OFFSETS to ALLOCATED DATA in this structure require
+ a change to dblksize.c to account for the additional length!
+*/
+typedef struct VCB *VCB_PTR;
+typedef struct VCB {
+ UINT8 blk_type ; /* block type - VCB */
+ COM_DBLK fs_reserved ; /* generic DBLK information */
+ UINT32 vcb_attributes ; /* generic VCB attribute */
+ UINT32 tape_id ; /* tape identifyer */
+ UINT16 tape_seq_num ; /* which tape in the a tape family */
+
+ /* this MUST remain INT16, we use -1 as a backup set number */
+ INT16 backup_set_num ; /* backup set number in a family */
+
+ /* this information is for On Tape Catalogs */
+ UINT32 set_cat_pba ; /* oba if set catatalog */
+ UINT16 set_cat_tape_seq_num ;/* sequence number of tape where cat is */
+ UINT16 set_cat_num_files ; /* number of files */
+ UINT16 set_cat_num_dirs ; /* numbers of directores in set */
+ UINT16 set_cat_num_corrupt ; /* number of corrupt objects */
+ UINT16 on_tape_cat_level ; /* catalog level FULL - PARTIAL- NONE */
+ BOOLEAN set_cat_info_valid ; /* TRUE if the set catalog info is valid */
+ UINT8 on_tape_cat_ver ; /* OTC version */
+
+ UINT32 size ; /* size of VCB data - should be 0 */
+ UCHAR tf_major_ver; /* tape format version - major */
+ UCHAR tf_minor_ver; /* tape format version - minor */
+ UCHAR sw_major_ver; /* application version - major */
+ UCHAR sw_minor_ver; /* application version - minor */
+ UINT8 os_id ; /* OS id of device backed up */
+ UINT8 os_ver ; /* OS version of device backed up */
+ DATE_TIME backup_date ; /* date and time of backup */
+ UINT16 password_encrypt_alg; /* password encryption algorithm */
+ UINT16 data_encrypt_alg ; /* data encryption algorithm */
+
+ UINT16 tape_name ; /* text tape name offset */
+ INT16 tape_name_leng ; /* size of the above name */
+ UINT16 backup_set_name ; /* text backup set name offset */
+ INT16 backup_set_name_leng; /* size of the above name */
+ UINT16 backup_set_descript ; /* backup set description offset */
+ INT16 backup_set_descript_leng; /* size of the above */
+ UINT16 user_name ; /* text user name who backed up */
+ INT16 user_name_leng ; /* size of the above name */
+ UINT16 tape_password ; /* tape password offset */
+ INT16 tape_password_leng ; /* size of the password */
+ UINT16 backup_set_password ; /* backup set password offset */
+ INT16 backup_set_password_leng; /* size of the password */
+ UINT16 machine_name ; /* machine name offset */
+ INT16 machine_name_leng ; /* length of the above name */
+ UINT16 short_machine_name ; /* short machine name offset */
+ INT16 short_machine_name_leng ; /* length of the above name */
+ UINT16 vol_name ; /* source volume name offset */
+ INT16 vol_name_leng ; /* name length */
+ UINT16 dev_name ; /* source device name offset */
+ INT16 dev_name_leng ; /* sizeof device name */
+ UINT16 vendor_id ;
+ BOOLEAN no_redirect_restore ; /* set can not be redirected */
+ BOOLEAN non_volume ; /* set can only be restored to non volume */
+
+} VCB ;
+
+/* corruption attributes */
+#define LENGTH_ERROR BIT16
+#define IO_ERROR BIT17
+#define DEADLOCK_ERROR BIT18
+
+typedef struct CFDB *CFDB_PTR;
+typedef struct CFDB {
+ UINT8 blk_type ; /* block type - CVDB */
+ COM_DBLK fs_reserved ; /* generic DBLK data */
+ UINT32 corrupt_offset; /* offset to first corrupt byte */
+ UINT32 attributes; /* type of corruption */
+ UINT16 stream_number ; /* sequence number of first corrupt stream */
+}CFDB ;
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/gen_fs.h b/private/utils/ntbackup/inc/gen_fs.h
new file mode 100644
index 000000000..258197023
--- /dev/null
+++ b/private/utils/ntbackup/inc/gen_fs.h
@@ -0,0 +1,187 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: dos_fs.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains the prototypes for the GEN
+ file system functions.
+
+ $Log: M:/LOGFILES/GEN_FS.H_V $
+ *
+ * Rev 1.12 24 Nov 1993 14:55:56 BARRY
+ * Changed CHAR_PTRs in I/O functions to BYTE_PTRs
+ *
+ * Rev 1.11 30 Jul 1993 13:20:46 STEVEN
+ * if dir too deep make new one
+ *
+ * Rev 1.10 11 May 1993 08:19:50 BRYAN
+ * Fixed signed/unsigned and type mismatch warnings.
+ *
+ * Rev 1.9 08 May 1993 14:25:38 DOUG
+ * Added prototype for GEN_FlushDLEs(), found in dleupdat.c
+ *
+ * Rev 1.8 25 Sep 1992 10:23:44 CHUCKB
+ * Added sinfo to prototype for GEN_CompleteBLK().
+ *
+ * Rev 1.7 22 Sep 1992 17:15:12 CHUCKB
+ * Removed references to fs_GetTotalSizeDBLK().
+ *
+ * Rev 1.6 17 Aug 1992 16:34:18 BURT
+ * Updated at MSoft to prevent warnings during NT app build.
+ *
+ *
+ * Rev 1.5 04 May 1992 09:38:10 LORIB
+ * Fixes for function prototype definitions.
+ *
+ * Rev 1.4 03 Mar 1992 16:16:06 STEVEN
+ * added functions for long paths
+ *
+ * Rev 1.3 13 Dec 1991 09:30:20 STEVEN
+ * move common functions to tabels
+ *
+ * Rev 1.2 27 Nov 1991 10:35:24 BARRY
+ * Fixed GEN_GetOSPath parameters.
+ *
+ * Rev 1.1 14 Aug 1991 13:02:00 STEVEN
+ * added FindClose
+ *
+ * Rev 1.0 09 May 1991 13:31:38 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ include list */
+
+#include "fsys.h"
+
+
+INT16 GEN_GetOSFnameFDB( DBLK_PTR dblk , /* I - Descriptor block to get path from */
+ CHAR_PTR buf ); /*I/O- path to read (or to write) */
+
+INT16 GEN_GetPartName( FSYS_HAND fsh, /* I - file system handle */
+ DBLK_PTR dblk , /* I - Descriptor block to get path from */
+ CHAR_PTR buf ); /*I/O- path to read (or to write) */
+
+INT16 GEN_GetOSPathDDB(
+ FSYS_HAND fsh, /* I - file system handle */
+ DBLK_PTR dblk , /* I - Descriptor block to get path from */
+ CHAR_PTR buf ); /*I/O- path to read (or to write) */
+
+INT16 GEN_GetFileVerFDB( DBLK_PTR dblk ,
+ UINT32 *version ) ;
+
+INT16 GEN_GetCdateDBLK( DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ); /*I/O- createion date to read (or to write) */
+
+INT16 GEN_GetMdateDBLK( DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ) ; /* O - modify date to write */
+
+INT16 GEN_ModBdateDBLK( BOOLEAN set_it , /* I - TRUE if setting creation date, FALSE if getting */
+ DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ) ; /*I/O- createion date to read (or to write) */
+
+INT16 GEN_ModAdateDBLK( BOOLEAN set_it , /* I - TRUE if setting creation date, FALSE if getting */
+ DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ) ; /*I/O- createion date to read (or to write) */
+
+INT16 GEN_GetOS_InfoDBLK( DBLK_PTR dblk, /* I - DBLK to get the info from */
+ CHAR_PTR os_info, /* O - Buffer to place data */
+ INT16 *size ); /*I/O- Buffer size / data length */
+
+
+INT16 GEN_ModAttribDBLK( BOOLEAN set_it ,
+ DBLK_PTR dblk ,
+ UINT32_PTR attr );
+
+
+INT16 GEN_GetObjTypeDBLK( DBLK_PTR dblk,
+ OBJECT_TYPE *type );
+
+
+INT16 GEN_GetActualSizeDBLK( FSYS_HAND fsh,
+ DBLK_PTR dblk ) ;
+
+INT16 GEN_SizeofOSFname( FSYS_HAND fsh, /* I - file system in use */
+ DBLK_PTR fdb ) ; /* I - dblk to get fname from */
+
+INT16 GEN_SizeofPartName( FSYS_HAND fsh, /* I - file system in use */
+ DBLK_PTR fdb ) ; /* I - dblk to get fname from */
+
+INT16 GEN_SizeofOSPath( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR ddb ) ; /* I - DBLK to get path size from */
+
+INT16 GEN_SizeofOSInfo( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ); /* I - DBLK to get size of OS info for */
+
+INT16 GEN_CreateFDB( FSYS_HAND fsh,
+ GEN_FDB_DATA_PTR dat ) ;
+
+INT16 GEN_CreateDDB( FSYS_HAND fsh,
+ GEN_DDB_DATA_PTR dat ) ;
+
+INT16 GEN_CreateIDB( FSYS_HAND fsh,
+ GEN_IDB_DATA_PTR dat ) ;
+
+VOID GEN_SetOwnerId( FSYS_HAND fsh, DBLK_PTR dblk, UINT32 id ) ;
+
+BOOLEAN GEN_ProcessDDB( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+// UINT64 GEN_GetTotalSizeDBLK( FSYS_HAND fsh, /* I - File system handle */
+// DBLK_PTR dblk ) ; /* I - Descriptor block to get generic data size for */
+
+UINT64 GEN_GetDisplaySizeDBLK( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ) ; /* I - Descriptor block to get generic data size for */
+
+INT16 GEN_SpecExcludeObj( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR ddb, /* I - Descriptor block of ddb */
+ DBLK_PTR fdb ) ; /* I - Descriptor block of fdb */
+
+INT16 GEN_SetDataSize( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR ddb, /* I - Descriptor block of ddb */
+ UINT32 size ) ; /* I - new size */
+
+INT16 GEN_SetObjTypeDBLK( DBLK_PTR dblk,
+ OBJECT_TYPE type );
+
+INT16 GEN_FindClose( FSYS_HAND fsh,
+ DBLK_PTR dblk ) ;
+
+INT16 GEN_DeviceDispName(
+GENERIC_DLE_PTR dle,
+CHAR_PTR dev_name,
+INT16 size,
+INT16 type ) ;
+
+VOID GEN_GetVolName( GENERIC_DLE_PTR dle, CHAR_PTR buffer ) ;
+
+INT16 GEN_SizeofVolName( GENERIC_DLE_PTR dle ) ;
+
+INT16 GEN_MakePath(
+CHAR_PTR buf, /* O - buffer to place path string into */
+INT16 bsize , /* I - size of above buffer */
+GENERIC_DLE_PTR dle , /* I - Drive the selection is from */
+CHAR_PTR path , /* I - path string in generic format */
+INT16 psize , /* I - size of above path */
+CHAR_PTR fname ) ;/* I - null terminated file name */
+
+INT16 GEN_InitFileSys(
+DLE_HAND hand,
+BE_CFG_PTR cfg,
+UINT32 fsys_mask ) ;
+
+VOID GEN_DeInitFileSys( DLE_HAND hand ) ;
+
+INT16 GEN_FindDrives( DLE_HAND dle_hand, BE_CFG_PTR cfg, UINT32 fsys_mask ) ;
+
+VOID GEN_RemoveDLE( GENERIC_DLE_PTR dle ) ;
+
+VOID GEN_InitMakeData( FSYS_HAND fsh, INT16 blk_type, CREATE_DBLK_PTR data ) ;
+BOOLEAN GEN_IsBlkComplete( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+INT16 GEN_CompleteBlk( FSYS_HAND fsh, DBLK_PTR dblk, BYTE_PTR buffer, UINT16 *size, STREAM_INFO_PTR sinfo ) ;
+VOID GEN_ReleaseBlk( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+
+INT16 GEN_DupBlk( FSYS_HAND fsh, DBLK_PTR db_org, DBLK_PTR db_dup ) ;
+
+void GEN_FlushDLEs( DLE_HAND dle_hand, UINT8 flush_dle_type );
diff --git a/private/utils/ntbackup/inc/gendblk.h b/private/utils/ntbackup/inc/gendblk.h
new file mode 100644
index 000000000..51502c2ba
--- /dev/null
+++ b/private/utils/ntbackup/inc/gendblk.h
@@ -0,0 +1,54 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: dosdblk.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains the definition of the GEN
+ file and directory control blocks.
+
+
+ $Log: N:/LOGFILES/GENDBLK.H_V $
+ *
+ * Rev 1.3 11 Nov 1992 10:44:16 STEVEN
+ * fix os_name for gen_fs
+ *
+ * Rev 1.2 17 Mar 1992 09:05:44 STEVEN
+ * format 40 - added 64 bit support
+ *
+ * Rev 1.1 21 Jan 1992 14:28:12 BARRY
+ * Added gen_size field to DBLK.
+ *
+ * Rev 1.0 09 May 1991 13:30:46 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ include list */
+
+
+#ifndef gendblk_h
+#define gendblk_h
+
+
+#include "queues.h"
+
+typedef struct GEN_DBLK *GEN_DBLK_PTR;
+
+typedef struct GEN_DBLK {
+ UINT8 blk_type; /* values: DDB_ID, FDB_ID set: GEN */
+ COM_DBLK fs_reserved ;
+ OBJECT_TYPE obj_type ;
+ UINT64 size ;
+ UINT64 disp_size ;
+ UINT32 tape_attribs ;
+ DATE_TIME bdate ;
+ DATE_TIME cdate ;
+ DATE_TIME mdate ;
+ DATE_TIME adate ;
+ UINT16 os_part_name ;
+} GEN_DBLK;
+
+
+#endif
diff --git a/private/utils/ntbackup/inc/generr.h b/private/utils/ntbackup/inc/generr.h
new file mode 100644
index 000000000..70d55c4eb
--- /dev/null
+++ b/private/utils/ntbackup/inc/generr.h
@@ -0,0 +1,72 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: generr.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the generic error codes.
+
+ Location: BE_PRIVATE
+
+
+$Log: T:/LOGFILES/GENERR.H_V $
+ *
+ * Rev 1.4 23 Mar 1993 21:53:06 GREGG
+ * Added VCS log to header.
+ *
+ * Rev 1.3 22 Mar 1993 17:09:18 chrish
+ * Added define for GEN_ERR_UNRECOGNIZED_MEDIA.
+ *
+ * Rev 1.2 17 Mar 1993 15:01:14 GREGG
+ * This is Terri Lynn. Added Gregg's changes to switch the tape drive's block mode
+ * to match the block size of the current tape.
+ *
+ * Rev 1.1 12 Aug 1992 15:13:22 DON
+ * added Loader error support
+ *
+ * Rev 1.0 15 May 1991 10:32:24 STEVEN
+ * Initial revision.
+
+**/
+/* $end$ include list */
+
+#ifndef GENERRS
+
+#define GENERRS
+
+#define GEN_NO_ERR 0 /* no error code */
+#define GEN_ERR_TIMEOUT 1 /* timeout error */
+#define GEN_ERR_EOM 2 /* end of media */
+#define GEN_ERR_BAD_DATA 3 /* bad read */
+#define GEN_ERR_NO_MEDIA 4 /* put the tape in */
+#define GEN_ERR_ENDSET 5 /* filemark detected */
+#define GEN_ERR_NO_DATA 6 /* no data */
+#define GEN_ERR_INVALID_CMD 7 /* invalid command */
+#define GEN_ERR_RESET 8 /* reset */
+#define GEN_ERR_WRT_PROTECT 9 /* cartridge write protect */
+#define GEN_ERR_HARDWARE 10 /* hardware error */
+#define GEN_ERR_UNDETERMINED 11 /* you are really screwed !! */
+#define GEN_ERR_EOM_OVERFLOW 12 /* physical end of media */
+
+#define GEN_ERR_DOOR_AJAR 13 /* door open condition prevents further operation */
+#define GEN_ERR_NO_CARTRIDGE 14 /* no multi media holder installed */
+#define GEN_ERR_WRONG_MODE 15 /* the target was manually setup in a mode that */
+#define GEN_ERR_FORMAT 16 /* Media not formatted */
+#define GEN_ERR_SW_REJECT_CMD 17 /* S/W Command rejection by driver */
+#define GEN_ERR_MEMORY 18 /* A memory problem detected by driver */
+#define GEN_ERR_LOAD_UNLOAD 19 /* Load/Insert media failure */
+#define GEN_ERR_DEST_FULL 20 /* Cannot return tape to original cartridge position */
+#define GEN_ERR_EMPTY_SRC 21 /* Selected source was empty */
+#define GEN_ERR_DRIVE_CLOSED 22 /* Automated access to drive restricted by closed door */
+#define GEN_ERR_ARM_FULL 23 /* Attemp to get new tape with arm full */
+#define GEN_ERR_DRIVE_FULL 24 /* Cannot put the requested tape in the drive because drive is full */
+#define GEN_ERR_UNEXPECTED_TAPE 25 /* Encountered a tape in the drive when the driver thought it was empty */
+
+#define GEN_ERR_WRONG_BLOCK_SIZE 26 /* Current drive block size setting doesn't match tape */
+
+#define GEN_ERR_UNRECOGNIZED_MEDIA 27 // DC2000 drives to detect if tape is // chs:03-22-93
+ // unformatted // chs:03-22-93
+
+#endif
diff --git a/private/utils/ntbackup/inc/genfuncs.h b/private/utils/ntbackup/inc/genfuncs.h
new file mode 100644
index 000000000..31473afa7
--- /dev/null
+++ b/private/utils/ntbackup/inc/genfuncs.h
@@ -0,0 +1,73 @@
+
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: genfuncs.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the generic function codes.
+ NOTE: In the event a new command is added to this
+ function list, the symbols GEN_LSTCMD_QIC and/or
+ GEN_LSTCMD must be updated to reflect that fact.
+ GEN_LSTCMD_QIC only applies to the Maynard QIC driver.
+
+ Location: BE_PRIVATE
+
+
+ $Log: T:/LOGFILES/GENFUNCS.H_V $
+ *
+ * Rev 1.3 17 May 1993 19:08:02 GREGG
+ * Added define for GEN_SPACE. Note that it has the same value as
+ * GEN_READ_ENDSET, and will EVENTUALY replace it.
+ *
+ * Rev 1.2 22 Jan 1992 13:59:24 ED
+ * SKATEBOARD: added #defines (GEN_LSTCMD_QIC,GEN_LSTCMD) to denote the end of the function list. Re
+ * stored GEN_SPECIAL to place QIC driver expects it. Added comments. Fixed bad $log$ token.
+
+**/
+/* $end$ include list */
+
+#ifndef GENFUNCS
+
+#define GENFUNCS
+
+#define GEN_INIT 0 /* Initialise the tape device */
+#define GEN_OPEN 1 /* open the tape device */
+#define GEN_NRCLOSE 2 /* close the tape device no rewind */
+#define GEN_RCLOSE 3 /* close the tape device w/ rewind */
+#define GEN_READ 4 /* read from tape device */
+#define GEN_WRITE 5 /* write to tape device */
+#define GEN_WRITE_ENDSET 6 /* write filemark to tape */
+
+// The next two have the same value on purpose! GEN_SPACE will eventually
+// replace GEN_READ_ENDSET.
+
+#define GEN_READ_ENDSET 7 /* read to filemark */
+#define GEN_SPACE 7 /* space forward or backward by blocks or */
+ /* filemarks, or to end of data. */
+
+#define GEN_ERASE 8 /* erase the tape */
+#define GEN_REWIND 9 /* rewind the tape */
+#define GEN_REWINDI 10 /* rewind the tape, immediate */
+#define GEN_RETEN 11 /* retension the tape */
+#define GEN_STATUS 12 /* get status from tape device */
+#define GEN_RESET 13 /* reset tape drive */
+#define GEN_RELEASE 14 /* Unload the driver */
+#define GEN_READBLK 15 /* Read Block */
+#define GEN_SEEK 16 /* Seek to a position */
+#define GEN_GETPOS 17 /* Get the position */
+#define GEN_AUTO_TEL 18 /* device enquiry */
+#define GEN_MOUNT 19 /* Mount */
+#define GEN_DISMOUNT 20 /* DisMount */
+#define GEN_SPECIAL 21 /* special code */
+#define GEN_EJECT 22 /* eject the tape */
+#define GEN_LOCK 0xf0
+#define GEN_UNLOCK 0xf1
+#define GEN_LSTCMD_QIC GEN_SPECIAL /* end of func table for QIC driver */
+#define GEN_LSTCMD GEN_EJECT /* end of func table for everyone else */
+
+/* note -1, -2 are reserved by the new SCSI Driver, TP */
+
+#endif
diff --git a/private/utils/ntbackup/inc/genstat.h b/private/utils/ntbackup/inc/genstat.h
new file mode 100644
index 000000000..a25f2235d
--- /dev/null
+++ b/private/utils/ntbackup/inc/genstat.h
@@ -0,0 +1,44 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-92
+
+ Name: genstat.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the Generic Status definitions for the tape
+ drives.
+
+ Location: BE_PUBLIC
+
+ $Log: J:/LOGFILES/GENSTAT.H_V $
+ *
+ * Rev 1.1 13 Oct 1992 12:56:42 CHARLIE
+ * Added TPS_NON_NATIVE_FORMAT & enabled PVCS logging
+
+**/
+
+#ifndef _STATUS_BITS
+#define _STATUS_BITS
+
+#include <stdtypes.h>
+
+/* $end$ include list */
+
+#define TPS_NO_TAPE 0x1
+#define TPS_WRITE_PROTECT 0x2
+#define TPS_NEW_TAPE 0x4
+#define TPS_RESET 0x8
+#define TPS_BOT 0x10
+#define TPS_EOM 0x20
+#define TPS_ILL_CMD 0x40
+#define TPS_NO_DATA 0x80
+#define TPS_FMK 0x100
+#define TPS_STREAM 0x200
+#define TPS_RUN 0x400
+#define TPS_NOT_READY 0x800
+#define TPS_EOM_OVERFLOW 0x1000
+#define TPS_NON_NATIVE_FORMAT 0x2000
+#define TPS_DRV_FAILURE 0x80000000
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/get_next.h b/private/utils/ntbackup/inc/get_next.h
new file mode 100644
index 000000000..62a71ce17
--- /dev/null
+++ b/private/utils/ntbackup/inc/get_next.h
@@ -0,0 +1,33 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: get_next.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: header for get next routines to be used entirely by the loops
+
+
+ $Log: N:/LOGFILES/GET_NEXT.H_V $
+ *
+ * Rev 1.1 24 May 1991 14:58:06 STEVEN
+ * fixes for new Getnext
+ *
+ * Rev 1.0 09 May 1991 13:31:28 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef _get_next_h_
+#define _get_next_h_
+
+/* getnext prototypes */
+INT16 LP_GetNextDLEBlock( LP_ENV_PTR lp_env_ptr, DBLK_PTR *dblk_ptr ) ;
+INT16 LP_GetNextTPEBlock( LP_ENV_PTR lp_env_ptr, DBLK_PTR *dblk_ptr ) ;
+VOID LP_ClearPDL( LP_ENV_PTR lp ) ;
+
+#endif
+
+
diff --git a/private/utils/ntbackup/inc/global.h b/private/utils/ntbackup/inc/global.h
new file mode 100644
index 000000000..ca2b06e20
--- /dev/null
+++ b/private/utils/ntbackup/inc/global.h
@@ -0,0 +1,422 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: ss_globl.h
+
+ Description: This file contains references to all of the global
+ variables used by the GUI project.
+
+ $Log: G:/UI/LOGFILES/GLOBAL.H_V $
+
+ Rev 1.59 26 Jan 1994 13:23:16 STEVEN
+protected ansi tapes read with unicode app
+
+ Rev 1.58 24 Jan 1994 14:47:44 GREGG
+Added option to log mem_debug consistancy checks but not raise an exception.
+
+ Rev 1.57 12 Jan 1994 10:20:00 MikeP
+add abort in middle of file flag
+
+ Rev 1.56 07 Jan 1994 13:44:32 CARLS
+added loader default record name
+
+ Rev 1.55 20 Dec 1993 15:08:28 GLENN
+Changed global app strings to be LPSTR instead of CHAR [].
+
+ Rev 1.54 20 Dec 1993 09:29:40 CARLS
+removed LOADER ifdef
+
+ Rev 1.53 14 Dec 1993 11:13:36 BARRY
+Changed print buffer to dynamic memory on Unicode
+
+ Rev 1.52 13 Dec 1993 14:56:48 CARLS
+loader changes
+
+ Rev 1.51 06 Dec 1993 16:12:08 chrish
+Removed reference to gb_swcompression. Backed out previous software
+compression support change.
+
+ Rev 1.50 06 Dec 1993 15:48:32 CARLS
+removed loader prototype
+
+ Rev 1.49 01 Dec 1993 17:30:12 CARLS
+Added loader support
+
+ Rev 1.48 19 Oct 1993 14:57:20 MIKEP
+add lastopertotalbytes for gas guage
+
+ Rev 1.47 11 Oct 1993 09:22:58 MIKEP
+add gfNoCATS
+
+ Rev 1.46 24 Sep 1993 14:36:44 MARINA
+added network view globals
+
+ Rev 1.45 10 Sep 1993 17:49:10 chrish
+Added code for software compression support.
+
+ Rev 1.44 03 Aug 1993 20:57:48 CHUCKB
+Added extern reference to global job name string.
+
+ Rev 1.43 15 Jun 1993 18:21:20 GLENN
+Readded gfDummyDriver flag.
+
+ Rev 1.42 15 Jun 1993 13:17:58 DARRYLP
+More status monitor features
+
+ Rev 1.41 15 Jun 1993 11:27:26 MIKEP
+enable c++
+
+ Rev 1.40 14 Jun 1993 20:58:02 MIKEP
+enable c++
+
+ Rev 1.39 11 Jun 1993 15:51:16 GLENN
+Added gfDummyDriver flag. Rearranged status block global.
+
+ Rev 1.38 14 May 1993 14:04:02 TIMN
+Removed extern refernce for global variable TapeDevice for multiple
+instances. Also need global.c.
+
+
+ Rev 1.37 14 May 1993 09:41:06 DARRYLP
+Moved SetStatusBlock to resolve compile warnings.
+
+ Rev 1.36 27 Apr 1993 16:24:58 DARRYLP
+Status monitor enhancements.
+
+ Rev 1.35 19 Apr 1993 15:20:48 GLENN
+Added tape name global.
+
+ Rev 1.34 13 Apr 1993 17:09:36 CHUCKB
+Added declaration for gfIsJobRunning.
+
+ Rev 1.33 09 Apr 1993 15:41:02 GLENN
+Ifdef'd the DDE status globals for not OEM_MSOFT so that they are included in future releases.
+
+ Rev 1.32 09 Apr 1993 14:18:44 GLENN
+Added gnReturnCode. Moved ddemang.h to ss_gui.h.
+
+ Rev 1.31 08 Apr 1993 13:41:16 DARRYLP
+Changes for STAT_SetStatus call.
+
+ Rev 1.30 24 Mar 1993 14:54:08 DARRYLP
+Added help for Font viewer/common dialogs.
+
+ Rev 1.29 22 Mar 1993 10:05:56 DARRYLP
+Added new DDE manager window.
+
+ Rev 1.28 12 Mar 1993 14:45:36 MIKEP
+add auto format call
+
+ Rev 1.27 12 Mar 1993 14:34:16 MIKEP
+auto call erase if foreign tape
+
+ Rev 1.26 07 Mar 1993 12:34:48 MIKEP
+add missing tape option
+
+ Rev 1.25 20 Oct 1992 14:27:04 MIKEP
+abort at EOF
+
+ Rev 1.24 20 Oct 1992 14:20:24 MIKEP
+add support for getcurrentoperation
+
+ Rev 1.23 04 Oct 1992 19:47:14 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.22 04 Sep 1992 10:36:30 MIKEP
+add tapedevice for nt
+
+ Rev 1.21 02 Sep 1992 10:16:24 GLENN
+Added the highlight color stuff.
+
+ Rev 1.20 07 Aug 1992 13:29:48 MIKEP
+add global dil for nt
+
+ Rev 1.19 04 Aug 1992 10:05:20 MIKEP
+no cats flag
+
+ Rev 1.18 10 Jun 1992 16:12:56 GLENN
+Updated according to NT SPEC.
+
+ Rev 1.17 31 May 1992 11:14:10 MIKEP
+auto catalog changes
+
+ Rev 1.16 20 Apr 1992 13:51:18 GLENN
+Remove hard coded status line text size.
+
+ Rev 1.15 07 Apr 1992 15:45:44 GLENN
+Added APP exe name, exe version, res version, eng release globals.
+
+ Rev 1.14 24 Mar 1992 11:46:36 DAVEV
+OEM_MSOFT: removed ghWndLogFiles and ghWndLogFileView & all references
+
+ Rev 1.13 25 Feb 1992 12:08:38 MIKEP
+multidrive
+
+ Rev 1.12 23 Feb 1992 14:00:58 GLENN
+Updated frame client rect var.
+
+ Rev 1.11 19 Feb 1992 11:20:18 MIKEP
+free drive handles
+
+ Rev 1.10 11 Feb 1992 17:33:14 GLENN
+Added mdi client subclass globals.
+
+ Rev 1.9 20 Jan 1992 13:11:00 MIKEP
+epr fixes
+
+ Rev 1.8 23 Dec 1991 11:42:06 JOHNWT
+forgot to change the type
+
+ Rev 1.7 23 Dec 1991 11:40:40 JOHNWT
+changed gfPWForPWDBVerfified to ...State
+
+ Rev 1.6 20 Dec 1991 17:02:34 JOHNWT
+removed ghRuntimeDialog!
+
+ Rev 1.5 18 Dec 1991 11:43:46 JOHNWT
+added ghRuntimeDialog
+
+ Rev 1.4 14 Dec 1991 13:47:34 JOHNWT
+added gfPWForPWDBVerified
+
+ Rev 1.3 12 Dec 1991 17:12:26 DAVEV
+16/32 bit port -2nd pass
+
+ Rev 1.2 06 Dec 1991 17:41:22 GLENN
+Added gnMainRibbonWidth
+
+ Rev 1.1 04 Dec 1991 18:06:34 GLENN
+Added terminat app flag.
+
+ Rev 1.0 20 Nov 1991 19:40:10 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+#ifndef SS_GLOBAL_H
+
+#define SS_GLOBAL_H
+
+
+#include "appdefs.h"
+
+// MODULE GLOBAL VARIABLES for the GUI
+
+#ifdef SS_GUI
+
+extern INT gnReturnCode;
+
+extern HINSTANCE ghInst;
+extern HINSTANCE ghResInst;
+extern HANDLE ghAccel;
+extern HWND ghWndFrame;
+extern HWND ghWndMDIClient;
+extern HWND ghWndActiveDoc;
+extern HWND ghWndMainRibbon;
+extern HWND ghWndDocRibbon;
+extern HWND ghWndCommonDlg;
+extern HWND ghWndDebug;
+extern HWND ghWndDiskVols; // TEMP
+extern HWND ghWndTapeVols; // TEMP
+extern HWND ghWndJobs; // TEMP
+extern HWND ghModelessDialog;
+
+extern HMENU ghMenuJobs;
+
+extern LPSTR glpCmdLine;
+extern CHAR gszStatusLine[];
+extern CHAR gszTapeName[];
+
+extern RECT gRectFrameClient; // Frame's client area rectangle.
+extern RECT gpStatusRect; // Status line rectangle.
+extern HPEN ghPenBlack; // Black pen.
+extern HPEN ghPenWhite; // White pen.
+extern HPEN ghPenGray; // Gray pen.
+extern HPEN ghPenBackGnd; // Background pen.
+extern HPEN ghPenForeGnd; // Foreground pen.
+extern HPEN ghPenBtnText; // Button text pen.
+extern HPEN ghPenLtGray; // Button face pen.
+extern HPEN ghPenDkGray; // Button shadow pen.
+extern HBRUSH ghBrushLtGray; // Light Gray brush.
+extern HBRUSH ghBrushGray; // Gray brush.
+extern HBRUSH ghBrushBlack; // Black brush.
+extern HBRUSH ghBrushDkGray; // Dark Gray brush.
+extern HBRUSH ghBrushWhite; // White brush.
+extern HBRUSH ghBrushHighLight; // High Light brush.
+
+extern HFONT ghFontStatus; // Status Line Font.
+extern HFONT ghFontMsgBox; // Message Box Font.
+extern HFONT ghFontRibbon; // Ribbon Button Font.
+extern HFONT ghFontFiles; // File Font.
+extern HFONT ghFontLog; // Log File Font.
+extern HFONT ghFontIconLabels; // Icon Label Font.
+
+extern COLORREF gColorForeGnd; // Foreground Color
+extern COLORREF gColorBackGnd; // Background Color
+
+extern COLORREF gColorHighLight;
+extern COLORREF gColorHighLightText;
+
+extern ULONG gulFiles;
+extern ULONG gulBytes;
+extern ULONG gulDirectories;
+
+extern INT gnBorderWidth;
+extern INT gnMainRibbonHeight;
+
+extern INT16 gnNumJobs ;
+extern BOOL gfEditJob ;
+extern WORD gwCurrentJobIndex ;
+extern CHAR_PTR gpszJobName ;
+
+extern INT16 gnNumScheds ;
+extern INT16 gnEditSched ;
+
+extern BOOL gfDeleteCatalogs;
+extern BOOL gfShowStatusLine;
+extern BOOL gfShowMainRibbon;
+extern BOOL gfShowDocRibbon;
+extern BOOL gfDebug;
+extern BOOL gfPollDrive;
+extern BOOL gfAppInitialized;
+extern BOOL gfTerminateApp;
+extern BOOL gfIsJobRunning;
+
+extern HCURSOR ghCursorPen;
+extern BOOL gfOperation;
+extern BOOL gfHWInitialized;
+
+extern HRIBBON ghRibbonMain;
+extern HRIBBON ghRibbonDoc;
+
+extern WNDPROC glpfnNewListProc;
+extern WNDPROC glpfnOldListProc;
+extern WNDPROC glpfnNewMDIClientProc;
+extern WNDPROC glpfnOldMDIClientProc;
+
+extern POINT gDLMpt;
+
+extern BOOL gfDummyDriver;
+extern BOOL gfIndicators;
+extern BOOL gfReplace;
+extern BOOL gfServers;
+extern BOOL gfNetworks;
+extern BOOL gfEnhanced;
+
+#ifdef OEM_EMS
+extern BOOL gfExchange;
+#endif
+
+extern INT16 gCatMaintChoice;
+extern INT16 gCatBsetChoice;
+extern INT16 gCatTapeChoice;
+
+extern INT16 gViewNetChoices;
+
+#ifdef OEM_EMS
+extern INT16 gViewXchgChoices;
+#endif
+
+extern INT gfPWForPWDBState;
+
+extern INT gfAbortInMiddleOfFile;
+extern INT gfNoCATS;
+extern INT gfIgnoreOTC;
+extern INT gfCallEraseTape;
+extern INT gfCallFormatTape;
+
+extern INT gb_last_operation;
+extern INT gbCurrentOperation;
+extern INT gbAbortAtEOF;
+
+#if defined( UNICODE )
+extern CHAR_PTR gszTprintfBuffer;
+#else
+extern CHAR gszTprintfBuffer[];
+#endif
+
+extern LPSTR gszAppName;
+extern LPSTR gszExeVer;
+extern LPSTR gszResVer;
+extern LPSTR gszEngRel;
+
+
+extern UINT64 gn64LastOperTotalBytes;
+
+extern void SetStatusBlock(INT, DWORD);
+
+#ifndef OEM_MSOFT // NOT for MSOFT
+
+ extern HWND ghWndLogFiles;
+ extern HWND ghWndLogFileView;
+ extern PSTAT_SETSTATUSBLOCK pSTAT_SetStatusBlock;
+ extern ULONG (FAR PASCAL *glpfnSetStatus)(PSTAT_SETSTATUSBLOCK);
+ extern void SendStatusMsg(PSTAT_SETSTATUSBLOCK pStatusBlk);
+ extern void CALLBACK StatusTimerProc(void);
+ extern LPSTR glpOffsetTapeDriveName;
+ extern LPSTR glpOffsetCurrentTapeName;
+ extern LPSTR glpOffsetServerVolume;
+ extern LPSTR glpOffsetTapeDriveIdentifier;
+ extern LPSTR glpOffsetTapeNeededName;
+ extern LPSTR glpOffsetDiskName;
+ extern LPSTR glpOffsetActiveFile;
+ extern LPSTR glpOffsetErrorMsg;
+ extern LPSTR glpOffsetActiveDir;
+
+#endif // ! OEM_MSOFT
+
+#endif
+
+// LOADER
+extern BOOL gfLoaderEnabled ;
+extern CHAR gLDR_DefaultMagName[] ;
+
+
+typedef struct _AUTO_PASSWORD {
+ CHAR signature[ PASSWORD_SIGNATURE_SIZE ];
+ CHAR string[ MAX_TAPE_PASSWORD_LEN + 1 ];
+} AUTO_PASSWORD;
+
+extern AUTO_PASSWORD gb_auto_password;
+extern INT8 gb_encryption_key[];
+extern INT8 gb_abort_flag ;
+extern CHAR gb_exe_path[];
+extern CHAR gb_exe_fname[];
+extern CHAR gb_tmp_string[];
+extern INT16 gb_logging;
+extern INT gb_logging_error;
+extern BOOLEAN gb_error_during_operation;
+extern INT gb_new_tape_flag;
+
+
+#ifdef DLE_H
+extern DLE_HAND dle_list;
+#endif
+
+#ifdef BSDU_h
+extern BSD_HAND bsd_list;
+extern BSD_HAND tape_bsd_list;
+
+#endif
+
+#ifdef THW_STUFF
+#include "dilhwd.h"
+extern THW_PTR thw_list;
+extern DIL_HWD_PTR gb_dhw_ptr;
+
+#ifdef OS_WIN32
+extern DIL_HWD gb_NTDIL;
+# ifdef OEM_MSOFT
+ extern INT TapeDevice; // Multi-instance doesn't use this
+# endif
+#endif
+
+#endif
+
+#ifdef MEM_DEBUG
+extern BOOLEAN gb_no_abort_on_mem_check;
+#endif
+
+#endif
diff --git a/private/utils/ntbackup/inc/helpids.h b/private/utils/ntbackup/inc/helpids.h
new file mode 100644
index 000000000..681331ea7
--- /dev/null
+++ b/private/utils/ntbackup/inc/helpids.h
@@ -0,0 +1,231 @@
+/****************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+ Name: HELPIDS.H
+
+ Description: This header file contains helpids for the
+ help manager.
+
+ $Log: G:/UI/LOGFILES/HELPIDS.H_V $
+
+ Rev 1.17 07 Jul 1993 16:39:42 TIMN
+Added id for Abort box
+
+ Rev 1.16 22 Apr 1993 16:02:16 GLENN
+Added file SORT option support.
+
+ Rev 1.15 20 Apr 1993 10:57:08 DARRYLP
+Added patch for help ids for Hardware settings dialog.
+
+ Rev 1.14 02 Apr 1993 13:50:54 GLENN
+Changed to new help IDs. Added OPERATIONSINFO.
+
+ Rev 1.13 24 Mar 1993 10:16:30 DARRYLP
+Removed unused HELPID_VIEWFONT, it has been replaced.
+
+ Rev 1.12 24 Mar 1993 10:04:48 DARRYLP
+Added help for Fonts and Formatting.
+
+ Rev 1.11 10 Mar 1993 12:51:16 CARLS
+Changes to move Format tape to the Operations menu
+
+ Rev 1.10 06 Oct 1992 13:11:06 DARRYLP
+Changed values, adding email and login screens
+
+ Rev 1.9 06 Oct 1992 09:21:04 DARRYLP
+Added Email and Emllogon ids.
+
+ Rev 1.8 08 Sep 1992 15:47:46 DARRYLP
+Added defines for Connect, Disconnect and Fonts
+
+ Rev 1.7 17 Mar 1992 11:55:46 ROBG
+changed
+
+ Rev 1.6 17 Mar 1992 10:54:46 ROBG
+changed
+
+ Rev 1.5 17 Mar 1992 09:59:56 ROBG
+changed
+
+ Rev 1.4 10 Feb 1992 09:13:04 GLENN
+Updated.
+
+ Rev 1.3 13 Jan 1992 15:25:32 ROBG
+Added HELPID_DIALOGTRANSFER
+
+ Rev 1.2 10 Jan 1992 17:38:06 ROBG
+Changes.
+
+ Rev 1.1 11 Dec 1991 13:41:12 ROBG
+Added helpids for the launcher.
+
+ Rev 1.0 20 Nov 1991 19:33:28 SYSTEM
+Initial revision.
+
+****************************************************************************/
+
+#ifndef helpids_h
+#define helpids_h
+
+
+#define HELPID_MINIMIZE_ICON 1
+#define HELPID_MAXIMIZE_ICON 2
+#define HELPID_SYSTEM_MENU 3
+#define HELPID_TITLE_BAR 4
+#define HELPID_SIZING_BORDER 5
+#define HELPID_FRAME_WINDOW 6
+#define HELPID_STATUSLINE 7
+#define HELPID_CLIENT_WINDOW 8
+#define HELPID_DOC_WINDOW 9
+#define HELPID_RIBBON_WINDOW 10
+
+#define HELPID_DISKS 11
+#define HELPID_TAPES 12
+#define HELPID_MACROS 13
+#define HELPID_JOBS 14
+#define HELPID_DISKTREE 15
+#define HELPID_TAPETREE 16
+#define HELPID_SERVERS 17
+#define HELPID_LOGFILES 18
+#define HELPID_DEBUG 19
+#define HELPID_SEARCH 20
+#define HELPID_LOGVIEW 21
+#define HELPID_JOBSELECT 22
+#define HELPID_MDISELECT 23
+
+// These processed on a "listbox" control.
+// begin
+
+#define HELPID_DISKTREELEFT 30
+#define HELPID_DISKTREERIGHT 31
+#define HELPID_TAPETREELEFT 32
+#define HELPID_TAPETREERIGHT 33
+#define HELPID_SERVERLEFT 34
+#define HELPID_SERVERRIGHT 35
+
+// end
+
+#define HELPID_FILEPRINT 100
+#define HELPID_FILESETUP 101
+#define HELPID_FILEEXIT 102
+
+#define HELPID_JOBMAINTENANCE 204
+
+#define HELPID_TREEEXPANDONE 300
+#define HELPID_TREEEXPANDBRANCH 301
+#define HELPID_TREEEXPANDALL 302
+#define HELPID_TREECOLLAPSEBRANCH 303
+
+#define HELPID_VIEWTREEANDDIR 400
+#define HELPID_VIEWTREEONLY 401
+#define HELPID_VIEWDIRONLY 402
+#define HELPID_VIEWSPLIT 403
+#define HELPID_VIEWALLFILEDETAILS 404
+#define HELPID_VIEWSORTNAME 405
+#define HELPID_VIEWSORTTYPE 406
+#define HELPID_VIEWSORTSIZE 407
+#define HELPID_VIEWSORTDATE 408
+#define HELPID_VIEWFONTS 409
+
+#define HELPID_OPERATIONSBACKUP 500
+#define HELPID_OPERATIONSRESTORE 501
+#define HELPID_OPERATIONSTRANSFER 502
+#define HELPID_OPERATIONSVERIFY 503
+#define HELPID_OPERATIONSINFO 504
+#define HELPID_OPERATIONSCATALOG 505
+#define HELPID_OPERATIONSCATMAINT 506
+#define HELPID_OPERATIONSSEARCH 507
+#define HELPID_OPERATIONSNEXTSET 508
+#define HELPID_OPERATIONSEJECT 509
+#define HELPID_OPERATIONSERASE 510
+#define HELPID_OPERATIONSRETENSION 511
+#define HELPID_OPERATIONSCONNECT 512
+#define HELPID_OPERATIONSDISCON 513
+#define HELPID_OPERATIONSFORMAT 514
+
+#define HELPID_SELECTCHECK 600
+#define HELPID_SELECTUNCHECK 601
+#define HELPID_SELECTADVANCED 603
+#define HELPID_SELECTSUBDIRS 604
+#define HELPID_SELECTSAVE 605
+#define HELPID_SELECTUSE 606
+#define HELPID_SELECTDELETE 607
+#define HELPID_SELECTCLEAR 608
+
+#define HELPID_SETTINGSBACKUP 700
+#define HELPID_SETTINGSRESTORE 701
+#define HELPID_SETTINGSLOGGING 702
+#define HELPID_SETTINGSNETWORK 703
+#define HELPID_SETTINGSCATALOG 704
+#define HELPID_SETTINGSHARDWARE 705
+#define HELPID_SETTINGSDEBUGWINDOW 706
+#define HELPID_SETTINGSGENERAL 707
+
+#define HELPID_WINDOWSCASCADE 800
+#define HELPID_WINDOWSTILE 801
+#define HELPID_WINDOWSREFRESH 802
+#define HELPID_WINDOWSCLOSEALL 803
+#define HELPID_WINDOWSARRANGEICONS 804
+
+#define HELPID_HELPINDEX 900
+#define HELPID_HELPSEARCH 901
+#define HELPID_HELPUSINGHELP 902
+#define HELPID_HELPABOUTWINTERPARK 903
+
+#define HELPID_DIALOGABOUT 2000
+#define HELPID_DIALOGSELECTADVANCED 2010
+#define HELPID_DIALOGSELECTSAVE 2020
+#define HELPID_DIALOGSELECTUSE 2030
+#define HELPID_DIALOGSELECTDELETE 2040
+#define HELPID_DIALOGADVRESTORE 2050
+#define HELPID_DIALOGJOBEDIT 2060
+#define HELPID_DIALOGJOBNEW 2070
+#define HELPID_DIALOGJOBMAINTENANCE 2080
+#define HELPID_DIALOGJOBOPTS 2090
+#define HELPID_DIALOGJOBSCHEDULE 2100
+#define HELPID_DIALOGSCHEDOPTS 2110
+#define HELPID_DIALOGEMAIL 2120
+#define HELPID_DIALOGLOGON 2130
+#define HELPID_DIALOGSETTINGSOPTIONS 2140
+#define HELPID_DIALOGSETTINGSBACKUP 2150
+#define HELPID_DIALOGSETTINGSRESTORE 2160
+#define HELPID_DIALOGSETTINGSLOGGING 2170
+#define HELPID_DIALOGSETTINGSNETWORK 2180
+#define HELPID_DIALOGSETTINGSCATALOG 2190
+
+// Note: The following two ID's need to be the same for now.
+#define HELPID_DIALOGSETTINGSHARDWARE 2200
+#define HELPID_OPERATIONSHARDWARE 2200
+
+#define HELPID_DIALOGSETTINGSDEBUG 2210
+#define HELPID_DIALOGLOGINPSWD 2220
+#define HELPID_DIALOGSEARCHTAPE 2230
+#define HELPID_DIALOGPRINTERSETUP 2240
+#define HELPID_DIALOGPRINT 2250
+#define HELPID_DIALOGCATMAINT 2260
+#define HELPID_DIALOGCATTAPE 2270
+#define HELPID_DIALOGTAPEPSWD 2280
+#define HELPID_DIALOGLANTAPEPSWD 2290
+#define HELPID_DIALOGJOBPROGRAMITEM 2300
+#define HELPID_DIALOGBACKUPSET 2310
+#define HELPID_DIALOGRESTORESET 2320
+#define HELPID_DIALOGVERIFYSET 2330
+#define HELPID_DIALOGREENTERPASSWORD 2340
+#define HELPID_DIALOGSKIPOPEN 2350
+#define HELPID_DIALOGFILEREPLACE 2360
+#define HELPID_DIALOGERASE 2370
+#define HELPID_DIALOGRUNTIME 2380
+#define HELPID_DIALOGTENSION 2390
+#define HELPID_DIALOGNEXTSET 2400
+#define HELPID_DIALOGPWDBPASSWORD 2410
+#define HELPID_DIALOGTRANSFER 2420
+#define HELPID_DIALOGFORMAT 2430
+#define HELPID_DIALOGABORT 2440
+
+// Defines for the three topics for the launcher.
+
+#define HELPID_LAUNCHMAINSCREEN 2460
+#define HELPID_LAUNCHRUNDELAY 2470
+#define HELPID_LAUNCHSCHEDDELAY 2480
+
+#endif
diff --git a/private/utils/ntbackup/inc/helpmang.h b/private/utils/ntbackup/inc/helpmang.h
new file mode 100644
index 000000000..66c4f76db
--- /dev/null
+++ b/private/utils/ntbackup/inc/helpmang.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+ Name: helpmang.h
+
+ Description: This file contains prototypes for the Help Manager.
+
+ $Log: G:/UI/LOGFILES/HELPMANG.H_V $
+
+ Rev 1.11 19 Jul 1993 19:22:12 MARINA
+move mw* vars into source
+
+ Rev 1.10 18 Jan 1993 14:49:26 GLENN
+Changed HM_EnterIdle() return type.
+
+ Rev 1.9 01 Nov 1992 16:30:54 DAVEV
+Unicode changes
+
+ Rev 1.8 04 Oct 1992 19:47:16 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.7 23 Apr 1992 14:23:52 ROBG
+Changed prototype of HM_EnterIdle.
+
+ Rev 1.6 05 Feb 1992 18:08:04 GLENN
+Replaced dialog string lookup table and supporting code with IDHELP call to specific dialog.
+
+ Rev 1.6 05 Feb 1992 17:54:42 GLENN
+Replaced dialog string lookup table and supporting code with IDHELP call to specific dialog.
+
+ Rev 1.5 24 Jan 1992 10:11:52 GLENN
+Matched the deinit call with it's prototype.
+
+ Rev 1.4 18 Dec 1991 15:52:46 DAVEV
+16/32 bit port - 2nd pass
+
+ Rev 1.3 12 Dec 1991 17:13:42 DAVEV
+16/32 bit port -2nd pass
+
+ Rev 1.2 10 Dec 1991 16:27:52 GLENN
+Fixed changes added for NT
+
+ Rev 1.1 05 Dec 1991 11:34:56 DAVEV
+16/32 bit Windows port changes - 1st pass
+
+ Rev 1.0 20 Nov 1991 19:34:32 SYSTEM
+Initial revision.
+
+****************************************************************************/
+
+
+#ifndef HELPMANG_H
+#define HELPMANG_H
+
+
+typedef struct {
+
+ WORD wMenuId ;
+ WORD wHelpId ;
+
+} HELPID_MENUID_TABLE, far * LPHELPID_MENUID_TABLE ;
+
+
+#define NAME_MAX_SIZE 128
+
+INT APIENTRY HM_DialogFilter( INT nCode, MP1 mp1, MP2 mp2 ) ;
+VOID HM_Init( VOID ) ;
+VOID HM_Deinit( VOID ) ;
+WORD HM_FindHelpId( WORD wMenuId ) ;
+VOID HM_MakeHelpPathName( LPSTR szFileName ) ;
+BOOL HM_WMCommandProcessing( HWND hWnd, WORD wId ) ;
+VOID HM_WinHelp( HWND hWnd, WORD wCommand, DWORD dwData ) ;
+VOID HM_MenuCommands( HWND hWnd, WORD wId ) ;
+BOOL HM_ContextLbuttonDown ( HWND hWnd, MP1 mp1, MP2 mp2 ) ;
+BOOL HM_KeyDown( HWND hWnd, MP1 mp1 ) ;
+BOOL HM_SetCursor( HWND hWnd ) ;
+VOID HM_InitMenu( VOID ) ;
+BOOL HM_EnterIdle( HWND hWnd, MP1 mp1, WORD mwLastMenuID, WORD mwLastMenuState ) ;
+VOID HM_CloseHelpWindow ( HWND hWnd ) ;
+VOID HM_GetWindowClassHelpId ( HWND hWnd ,LPDWORD pdwNewContextId , LPSTR szClass ) ;
+
+// MACROS
+
+#define HM_DialogHelp( id ) HM_WinHelp( ghWndFrame, HELP_CONTEXT, (DWORD) (id) )
+
+#endif
diff --git a/private/utils/ntbackup/inc/hwcheck.h b/private/utils/ntbackup/inc/hwcheck.h
new file mode 100644
index 000000000..0717b92d6
--- /dev/null
+++ b/private/utils/ntbackup/inc/hwcheck.h
@@ -0,0 +1,30 @@
+
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: hwcheck.h
+
+ Description: Prototypes and defines for checking tape hardware status
+
+ Location:
+
+
+ $Log: G:/UI/LOGFILES/HWCHECK.H_V $
+
+ Rev 1.1 04 Oct 1992 19:47:16 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.0 31 Jan 1992 16:19:04 GLENN
+Initial revision.
+
+*******************************************************************************/
+
+#ifndef CHECK_TAPE_HW
+
+#define CHECK_TAPE_HW
+
+BOOL HWC_TapeHWProblem ( BSD_HAND );
+VOID HWC_ReportDiagError ( BE_INIT_STR_PTR, INT16, INT16_PTR ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/hwconf.h b/private/utils/ntbackup/inc/hwconf.h
new file mode 100644
index 000000000..3061fd22b
--- /dev/null
+++ b/private/utils/ntbackup/inc/hwconf.h
@@ -0,0 +1,217 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: hwconf.h
+
+ Description: Include file for generic hardware configuration
+
+
+ $Log: G:\ui\logfiles\hwconf.h_v $
+
+ Rev 1.15 30 Nov 1993 19:18:56 TIMN
+Added cmdline /tape:x option to NTJ
+
+ Rev 1.14 06 Aug 1993 13:57:50 TIMN
+Corrected timer parameter type
+
+ Rev 1.12 05 Aug 1993 19:36:06 TIMN
+Added f(x) proto for wait dialog timer
+
+ Rev 1.11 03 Aug 1993 20:59:18 TIMN
+Cleaned up protos
+
+ Rev 1.10 09 Jun 1993 15:07:52 MIKEP
+enable c++
+
+ Rev 1.9 04 Jun 1993 10:57:18 GLENN
+Added HWC_HasDeviceChanged().
+
+ Rev 1.8 21 May 1993 16:33:38 Aaron
+Removed OS_WIN32 conditional
+
+ Rev 1.7 19 May 1993 09:16:30 TIMN
+Added f(x) prototype for NT to get special features for a tape device.
+
+ Rev 1.6 14 May 1993 14:07:34 TIMN
+Added f(x) prototypes for multiple instances. No other files required.
+
+ Rev 1.5 03 May 1993 15:44:24 TIMN
+Added f(x) protos for checking if a device is claimed or not (for NT).
+Changes are part of the multiple instance support.
+
+ Rev 1.4 04 Oct 1992 19:47:18 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.3 28 Sep 1992 17:07:16 GLENN
+MikeP changes ( Added HWC_GetTapeDevice() )
+
+ Rev 1.2 19 Mar 1992 16:46:48 GLENN
+Added enhanced status support.
+
+ Rev 1.1 17 Mar 1992 15:37:24 GLENN
+Added HWC_GetLastErrorString() function.
+
+ Rev 1.0 20 Nov 1991 19:33:42 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifndef _hwconf_h_
+
+#define _hwconf_h_
+
+#define HW_NO_ERROR 0
+#define HW_INVALID_PARM 1
+#define HW_ERROR_DISPLAYED 2
+#define HW_ERROR_NO_RES_FILE 3
+#define HW_UNKNOWN_ERROR 4
+#define HW_ERROR_DETECTED 5
+#define HW_CHANGE_SUCCESS 6
+
+/* process flags for ProcessDILHWD() */
+#define HW_DISP_ERROR 0
+#define HW_RET_ERROR 1
+#define HW_DISP_WARNING 2
+
+#define HW_NUM_FIXED_PARMS 3
+#define HW_CTYPE_PARM 1
+
+/* DIL_HWD error definitions */
+#define HW_JUMPER_WARNING 1000
+#define HW_NUM_DRIVES_MISMATCH 1001
+#define HW_NO_TARGET_IDS 1002
+#define HW_CONTROLLER_DISABLED 1003
+#define HW_TEST_SUCCESSFUL 1004
+
+/**********************************************************************
+* MACHINE TYPE MASKS *
+* These defines relate directly to identical defines in the hardware *
+* resource files. If these change, identical changes must be made to *
+* the resource files. *
+**********************************************************************/
+
+#define PC_ISA_BUS 1 /* 8 bit bus */
+#define AT_ISA_BUS 2 /* 16 bit bus */
+#define AT_EISA_BUS 4 /* 32 bit bus */
+#define MICRO_CHANNEL_BUS 8 /* micro channel bus */
+#define ISA_BUS_GROUP 3 /* 8 and 16 bit busses */
+#define EISA_BUS_GROUP 7 /* 8, 16, and 32 bit busses */
+
+
+typedef struct ERROR_ELEM *ERROR_ELEM_PTR;
+typedef struct ERROR_ELEM {
+ UINT16 num_errors ; /* number of error numbers */
+ UINT16 *errnum ; /* pointer to error number list */
+ UINT16 num_loci ; /* number of loci */
+ UINT16 *locus ; /* pointer to loci number list */
+ BOOLEAN no_card_error ; /* is this a card not found error? */
+ struct HELP_STRUCT *error ; /* pointer to error structure */
+} ERROR_ELEM ;
+
+typedef struct ERROR_LIST *ERROR_LIST_PTR;
+typedef struct ERROR_LIST {
+ UINT16 num_elems ; /* number of error items in list */
+ ERROR_ELEM_PTR err_elem ; /* pointer to error items list */
+} ERROR_LIST ;
+
+typedef struct CARD_Q_ELEM *CARD_Q_ELEM_PTR;
+typedef struct CARD_Q_ELEM {
+ CHAR_PTR desc ; /* the verbal description of the card */
+ CHAR_PTR dll_name ; /* the dll file name */
+ CHAR_PTR sys_name ; /* the system file name */
+ BOOLEAN sys_required ; /* is a loadable system required */
+ BOOLEAN prev_used ; /* was this driver previously used */
+ INT16 num_parms ; /* number of default parms */
+ UINT16 dflt_parms[20] ; /* default parameters */
+} CARD_Q_ELEM ;
+
+typedef struct CARD_ELEM *CARD_ELEM_PTR;
+typedef struct CARD_ELEM {
+ UINT32 machine_mask ; /* machine mask */
+ UINT16 num_parm_indexes ; /* number of default parm indexes */
+ UINT16 *default_indexes ; /* default index list pointer */
+ INT16 priority ; /* the queueing priority */
+ CHAR_PTR desc ; /* the verbal description of the card */
+ CHAR_PTR dll_name ; /* the dll file name */
+ CHAR_PTR sys_name ; /* the system file name */
+ BOOLEAN sys_required ; /* is a loadable system required? */
+} CARD_ELEM ;
+
+typedef struct CARD_LIST *CARD_LIST_PTR;
+typedef struct CARD_LIST {
+ UINT16 num_elems ; /* number of cards in resource */
+ CARD_ELEM_PTR card_elem ; /* pointer to the card element list */
+} CARD_LIST;
+
+typedef struct OPTION_ELEM *OPTION_ELEM_PTR;
+typedef struct OPTION_ELEM {
+ CHAR_PTR name ; /* the verbose name of the element */
+ UINT32 value ; /* the actual value of the element */
+ UINT32 mask ; /* the mask to match card types */
+ BOOLEAN override_unique ; /* is this not so unique? */
+} OPTION_ELEM;
+
+typedef struct OPTION_LIST *OPTION_LIST_PTR ;
+typedef struct OPTION_LIST {
+ INT16 parm_number ; /* parm number in driver struct array */
+ BOOLEAN controller_type ; /* is this a controller type? */
+ BOOLEAN must_be_unique ; /* are options in this list unique? */
+ UINT32 jumper_switch ; /* mask: is ctlr option a jmpr/switch */
+ UINT32 changeable ; /* mask: is ctlr option changeable? */
+ INT16 num_options ; /* number of options in list */
+ OPTION_ELEM_PTR options_ptr ; /* pointer to options list elements */
+} OPTION_LIST ;
+
+/* list of item flags & indexes into the controller list array */
+typedef struct CTRL_ITEM *CTRL_ITEM_PTR ;
+typedef struct CTRL_ITEM {
+ UINT32 ctype_mask ; /* mask for valid controller card */
+ INT16 olist_index ; /* which option list is active FIXED */
+ INT16 option_index ; /* what is the selected option in list */
+ INT16 conflict_item ; /* dw item for conflict marker */
+ INT16 card_next_item ; /* index of next item for controller card */
+ INT16 controller_num ; /* controller number for the config file */
+} CTRL_ITEM ;
+
+typedef struct DD_CONFIG *DD_CONFIG_PTR ;
+typedef struct DD_CONFIG {
+ CHAR_PTR dd_description ; /* device driver description */
+ INT16 max_cards ; /* maximum number of configurable cards */
+ UINT16 *card_list_ptr ;
+ INT16 num_option_lists ; /* number of option lists */
+ OPTION_LIST_PTR option_list_ptr ;
+ INT16 num_ctrl_items ; /* redundant because in dw struct */
+ CTRL_ITEM_PTR item_list_ptr ;
+} DD_CONFIG ;
+
+
+/* function prototypes */
+
+INT HWC_InitDILHWD( DIL_HWD_PTR *, INT * ) ;
+INT HWC_ProcessDILHWD( INT, DIL_HWD_PTR ) ;
+INT HWC_ProcessError( WORD, WORD, WORD, WORD, CDS_PTR ) ;
+LPSTR HWC_GetLastErrorString( VOID ) ;
+VOID HWC_SetLastErrorString( LPSTR ) ;
+INT HWC_GetTapeDevice( VOID ) ;
+
+INT HWC_InitTapeDevice( VOID ) ;
+INT HWC_DeInitTapeDevice( VOID ) ;
+INT HWC_SelectTapeDevice( INT nTapeDevice ) ;
+
+BOOL HWC_IsDeviceNoDevice( VOID ) ;
+BOOL HWC_HasDeviceChanged( VOID ) ;
+VOID HWC_BuildJobDeviceComboBox( HWND hDlg, INT idControl ) ;
+LPSTR HWC_GetDeviceNameForStatusLine( LPSTR, INT ) ;
+VOID HWC_GetDeviceSpecialFeatures( INT device, UINT32_PTR pFeatures, BOOL fOption ) ;
+
+BOOL HWC_IsDeviceAvailable( INT ) ;
+HANDLE HWC_ClaimDevice( INT ) ;
+BOOL HWC_UnClaimDevice( HANDLE *hClaimedDevice ) ;
+
+VOID HWC_DeviceConflictTimer( INT nDeviceNumber, HANDLE *hDevice ) ;
+
+INT HWC_ClaimJobsDevice( CHAR_PTR pszTapeDriveName ) ;
+INT HWC_UnClaimJobsDevice( CHAR_PTR pszTapeDriveName ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/hwctext.h b/private/utils/ntbackup/inc/hwctext.h
new file mode 100644
index 000000000..74af37d7b
--- /dev/null
+++ b/private/utils/ntbackup/inc/hwctext.h
@@ -0,0 +1,198 @@
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+
+ Name: hwctext.h
+
+ Description: This file contains the STRING IDs for the Maynstream GUI
+ project HARDWARE CONFIGURATION.
+
+ $Log: G:/UI/LOGFILES/HWCTEXT.H_V $
+
+ Rev 1.15 05 Aug 1993 19:33:44 TIMN
+Removed unused ids
+
+ Rev 1.14 03 Aug 1993 21:05:00 TIMN
+Removed unused hardware settings id
+
+ Rev 1.13 30 Jul 1993 19:01:50 TIMN
+Removed unused ids and added new ones
+
+ Rev 1.12 26 Jul 1993 17:15:18 GLENN
+Added strings to support new list box style dialog. Now supports device status.
+
+ Rev 1.11 21 Jun 1993 13:15:54 CHUCKB
+Added define for current device string.
+
+ Rev 1.10 15 Jun 1993 12:09:02 GLENN
+Added support for the NT dummy device driver.
+
+ Rev 1.9 04 Jun 1993 10:58:00 GLENN
+Added new strings for HWC.
+
+ Rev 1.8 30 Nov 1992 16:08:40 GLENN
+Added IBM PS/2 SCSI hardware support.
+
+ Rev 1.7 04 Oct 1992 19:47:20 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.6 02 Oct 1992 16:27:00 STEVEN
+Added polldrive failure ID.
+
+ Rev 1.5 04 May 1992 16:41:22 GLENN
+Added PS/2 QIC and SCSI stuff.
+
+ Rev 1.4 19 Mar 1992 16:46:56 GLENN
+Added enhanced status support.
+
+ Rev 1.3 17 Mar 1992 15:34:56 GLENN
+Moved POLLDRIVE IDs from STRINGS.H to HWCTEXT.H
+
+ Rev 1.2 10 Feb 1992 09:16:12 GLENN
+Added warning text ID.
+
+ Rev 1.1 29 Jan 1992 17:55:14 GLENN
+Added Testing hardware ID.
+
+ Rev 1.0 24 Jan 1992 19:05:16 GLENN
+Initial revision.
+
+******************************************************************************/
+
+#ifndef HWCTEXT_H
+#define HWCTEXT_H
+
+// hardware settings dialog control text
+
+#define IDS_HWC_START 5000
+
+
+#define IDS_HWC_DRIVER_MS_SCSI (IDS_HWC_START+0)
+#define IDS_HWC_CARD_0_MS_SCSI (IDS_HWC_START+1)
+#define IDS_HWC_CARD_1_MS_SCSI (IDS_HWC_START+2)
+#define IDS_HWC_CARD_2_MS_SCSI (IDS_HWC_START+3)
+
+#define IDS_HWC_DRIVER_MS_QIC (IDS_HWC_START+4)
+#define IDS_HWC_CARD_0_MS_QIC (IDS_HWC_START+5)
+#define IDS_HWC_CARD_1_MS_QIC (IDS_HWC_START+6)
+
+#define IDS_HWC_DRIVER_AD_SCSI (IDS_HWC_START+7)
+#define IDS_HWC_CARD_0_AD_SCSI (IDS_HWC_START+8)
+#define IDS_HWC_CARD_1_AD_SCSI (IDS_HWC_START+9)
+
+#define IDS_HWC_DRIVER_MS_DUMMY (IDS_HWC_START+10)
+#define IDS_HWC_CARD_0_MS_DUMMY (IDS_HWC_START+11)
+
+#define IDS_HWC_DRIVER_IBM_SCSI (IDS_HWC_START+12)
+#define IDS_HWC_CARD_0_IBM_SCSI (IDS_HWC_START+13)
+
+
+#define IDS_HWC_ATTACHED (IDS_HWC_START+31)
+#define IDS_HWC_IOADDRESS (IDS_HWC_START+32)
+#define IDS_HWC_IRQNUM (IDS_HWC_START+33)
+#define IDS_HWC_DMACHANNEL (IDS_HWC_START+34)
+
+#define IDS_HWC_AUTO (IDS_HWC_START+35)
+#define IDS_HWC_NONDMA (IDS_HWC_START+36)
+
+#define IDS_HWC_IO_360 (IDS_HWC_START+40)
+#define IDS_HWC_IO_370 (IDS_HWC_START+41)
+#define IDS_HWC_IO_FF60 (IDS_HWC_START+42)
+#define IDS_HWC_IO_FF70 (IDS_HWC_START+43)
+
+#define IDS_HWC_NUMBERS (IDS_HWC_START+50)
+#define IDS_HWC_0 (IDS_HWC_NUMBERS+0)
+#define IDS_HWC_1 (IDS_HWC_NUMBERS+1)
+#define IDS_HWC_2 (IDS_HWC_NUMBERS+2)
+#define IDS_HWC_3 (IDS_HWC_NUMBERS+3)
+#define IDS_HWC_4 (IDS_HWC_NUMBERS+4)
+#define IDS_HWC_5 (IDS_HWC_NUMBERS+5)
+#define IDS_HWC_6 (IDS_HWC_NUMBERS+6)
+#define IDS_HWC_7 (IDS_HWC_NUMBERS+7)
+#define IDS_HWC_8 (IDS_HWC_NUMBERS+8)
+#define IDS_HWC_9 (IDS_HWC_NUMBERS+9)
+#define IDS_HWC_10 (IDS_HWC_NUMBERS+10)
+#define IDS_HWC_11 (IDS_HWC_NUMBERS+11)
+#define IDS_HWC_12 (IDS_HWC_NUMBERS+12)
+#define IDS_HWC_13 (IDS_HWC_NUMBERS+13)
+#define IDS_HWC_14 (IDS_HWC_NUMBERS+14)
+#define IDS_HWC_15 (IDS_HWC_NUMBERS+15)
+
+#define IDS_HWC_STATUS_ACTIVE (IDS_HWC_START+80)
+#define IDS_HWC_STATUS_MAYBEINUSE (IDS_HWC_START+81)
+#define IDS_HWC_STATUS_AVAILABLE (IDS_HWC_START+82)
+#define IDS_HWC_STATUS_INUSE (IDS_HWC_START+83)
+#define IDS_HWC_STATUS_INVALIDDRIVE (IDS_HWC_START+84)
+
+#define IDS_HWC_TESTRESULTSTITLE (IDS_HWC_START+100)
+
+#define IDS_HWC_TESTED_NOT (IDS_HWC_START+101)
+#define IDS_HWC_TESTED_GOOD (IDS_HWC_START+102)
+#define IDS_HWC_TESTED_BAD (IDS_HWC_START+103)
+#define IDS_HWC_TESTED_INIT (IDS_HWC_START+104)
+
+#define IDS_HWC_NOCONFIG (IDS_HWC_START+105)
+
+#define IDS_HWC_INIT_SUCCESS (IDS_HWC_START+110)
+
+#define IDS_HWC_JUMPER_CHANGE (IDS_HWC_START+111)
+
+#define IDS_HWC_NO_DRIVE (IDS_HWC_START+112)
+#define IDS_HWC_INTERRUPT_CONFLICT (IDS_HWC_START+113)
+#define IDS_HWC_DMA_CONFLICT (IDS_HWC_START+114)
+#define IDS_HWC_NO_CARD (IDS_HWC_START+115)
+#define IDS_HWC_INVALID_BASE_ADDR (IDS_HWC_START+116)
+#define IDS_HWC_INVALID_INTERRUPT (IDS_HWC_START+117)
+#define IDS_HWC_INVALID_DMA (IDS_HWC_START+118)
+#define IDS_HWC_ATTACHED_DRIVES (IDS_HWC_START+119)
+#define IDS_HWC_NO_TARGET_ID (IDS_HWC_START+120)
+#define IDS_HWC_CARD_DISABLED (IDS_HWC_START+121)
+#define IDS_HWC_NO_DRIVE_LOADED (IDS_HWC_START+122)
+#define IDS_HWC_ERROR_NUMBER (IDS_HWC_START+123)
+
+#define IDS_HWC_WARNING_TITLE (IDS_HWC_START+124)
+#define IDS_HWC_NO_CONFIG (IDS_HWC_START+125)
+
+#define IDS_HWC_INVALID_DEVICE_TITLE (IDS_HWC_START+126)
+#define IDS_HWC_INVALID_DEVICE_MSG (IDS_HWC_START+127)
+#define IDS_HWC_NOINST_DEVICE_TITLE (IDS_HWC_START+128)
+#define IDS_HWC_NOINST_DEVICE_MSG (IDS_HWC_START+129)
+#define IDS_HWC_NOSEL_DEVICE_TITLE (IDS_HWC_START+130)
+#define IDS_HWC_NOSEL_DEVICE_MSG (IDS_HWC_START+131)
+
+#define IDS_HWC_NO_DEVICE_TEXT (IDS_HWC_START+134)
+
+#define IDS_HWC_DEV_CONFLICT_TITLE (IDS_HWC_START+136)
+#define IDS_HWC_DEV_CONFLICT_MSG (IDS_HWC_START+137)
+#define IDS_HWC_DEV_CONFLICT2_MSG (IDS_HWC_START+138)
+
+#define IDS_HWC_DEV_UNASSIGNED (IDS_HWC_START+139)
+#define IDS_HWC_DEV_NODEVICE (IDS_HWC_START+140)
+
+#define IDS_HWC_DUMMY_DEVICE_TEXT (IDS_HWC_START+141)
+#define IDS_HWC_DUMMY_DEVICE_DLL (IDS_HWC_START+142)
+
+#define IDS_HWC_DEV_CURRENTDEVICE (IDS_HWC_START+143)
+
+// MI and NO DEVICE STUFF
+
+
+// POLL DRIVE STRING DEFINES
+
+#define IDS_POLLDRIVESTART (IDS_HWC_START+150)
+#define IDS_POLLDRIVE_MESSAGE (IDS_POLLDRIVESTART+0)
+#define IDS_POLLDRIVE_BIGPROBLEM (IDS_POLLDRIVESTART+1)
+#define IDS_POLLDRIVE_SMALLPROBLEM (IDS_POLLDRIVESTART+2)
+#define IDS_POLLDRIVE_INIT (IDS_POLLDRIVESTART+3)
+#define IDS_POLLDRIVE_INIT_FAILED (IDS_POLLDRIVESTART+4)
+#define IDS_POLLDRIVE_START (IDS_POLLDRIVESTART+5)
+#define IDS_POLLDRIVE_POLL (IDS_POLLDRIVESTART+6)
+#define IDS_POLLDRIVE_STOP (IDS_POLLDRIVESTART+7)
+#define IDS_POLLDRIVE_START_REENT (IDS_POLLDRIVESTART+8)
+#define IDS_POLLDRIVE_POLL_REENT (IDS_POLLDRIVESTART+9)
+#define IDS_POLLDRIVE_STOP_REENT (IDS_POLLDRIVESTART+10)
+#define IDS_POLLDRIVE_FAILED_MINOR (IDS_POLLDRIVESTART+11)
+#define IDS_POLLDRIVE_FAILED_SEVERE (IDS_POLLDRIVESTART+12)
+#define IDS_POLLDRIVE_TAPE_EJECT (IDS_POLLDRIVESTART+13)
+#define IDS_POLLDRIVE_DRIVE_FAILURE (IDS_POLLDRIVESTART+14)
+
+#endif
diff --git a/private/utils/ntbackup/inc/hwdlg.h b/private/utils/ntbackup/inc/hwdlg.h
new file mode 100644
index 000000000..63f04e74a
--- /dev/null
+++ b/private/utils/ntbackup/inc/hwdlg.h
@@ -0,0 +1,79 @@
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_SETTINGSHARDWARE 19
+#else
+#include "dlg_ids.h"
+#endif
+
+// hardware settings
+
+#define IDD_H_TEST 105
+
+#define IDD_H_CONTROLLER 106
+
+
+#define IDD_H_CSTATUSBOX 110
+#define IDD_H_ENABLED 111
+#define IDD_H_DISABLED 112
+#define IDD_H_UNABLETOUSE 113
+#define IDD_H_CARDSTATUS 114
+
+#define IDD_H_SCSITARGET 120
+#define IDD_H_TARGET0 121
+#define IDD_H_TARGET1 122
+#define IDD_H_TARGET2 123
+#define IDD_H_TARGET3 124
+#define IDD_H_TARGET4 125
+#define IDD_H_TARGET5 126
+#define IDD_H_TARGET6 127
+#define IDD_H_TARGET7 128
+
+#define IDD_H_SETTINGSBOX 130
+
+
+
+#define HWC_MAXLISTBOXES 4
+
+#define HWC_FIRSTLISTBOX 0
+#define HWC_SECONDLISTBOX 1
+#define HWC_THIRDLISTBOX 2
+#define HWC_FOURTHLISTBOX 3
+
+#define HWC_LISTBOXNAMES 140
+
+#define HWC_LISTBOXES 150
+
+#define IDD_H_FIRSTSTRING (HWC_LISTBOXNAMES+HWC_FIRSTLISTBOX)
+#define IDD_H_SECONDSTRING (HWC_LISTBOXNAMES+HWC_SECONDLISTBOX)
+#define IDD_H_THIRDSTRING (HWC_LISTBOXNAMES+HWC_THIRDLISTBOX)
+#define IDD_H_FOURTHSTRING (HWC_LISTBOXNAMES+HWC_FOURTHLISTBOX)
+
+#define IDD_H_FIRSTBOX (HWC_LISTBOXES+HWC_FIRSTLISTBOX)
+#define IDD_H_SECONDBOX (HWC_LISTBOXES+HWC_SECONDLISTBOX)
+#define IDD_H_THIRDBOX (HWC_LISTBOXES+HWC_THIRDLISTBOX)
+#define IDD_H_FOURTHBOX (HWC_LISTBOXES+HWC_FOURTHLISTBOX)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/private/utils/ntbackup/inc/iblock.h b/private/utils/ntbackup/inc/iblock.h
new file mode 100644
index 000000000..b5e3ce973
--- /dev/null
+++ b/private/utils/ntbackup/inc/iblock.h
@@ -0,0 +1,29 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: iblock.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+ Location:
+
+
+ $Log: G:/LOGFILES/IBLOCK.H_V $
+ *
+ * Rev 1.0 09 May 1991 13:33:16 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef _iblock_h_
+#define _iblock_h_
+
+VOID MarkBlockBad( CHAR_PTR buf, UINT16 block_size );
+UINT16 ImageBlockType( FILE_HAND hand, CHAR_PTR buf, UINT16 block_size );
+VOID AdvanceImageHandle( FILE_HAND hand, UINT16 distance );
+
+#endif
diff --git a/private/utils/ntbackup/inc/ibm_scsi.h b/private/utils/ntbackup/inc/ibm_scsi.h
new file mode 100644
index 000000000..9153a81d0
--- /dev/null
+++ b/private/utils/ntbackup/inc/ibm_scsi.h
@@ -0,0 +1,7 @@
+#ifndef IBM_SCSI_RH
+
+#define IBM_SCSI_RH
+
+#define SES_ENG_IS 0
+
+#endif
diff --git a/private/utils/ntbackup/inc/icons.h b/private/utils/ntbackup/inc/icons.h
new file mode 100644
index 000000000..a05e1a773
--- /dev/null
+++ b/private/utils/ntbackup/inc/icons.h
@@ -0,0 +1,62 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: icons.h
+
+ Description: This file contains the ICON IDs for the Maynstream GUI
+ project.
+
+ $Log: G:/UI/LOGFILES/ICONS.H_V $
+
+ Rev 1.3 04 Oct 1992 19:47:24 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.2 03 Mar 1992 18:18:18 GLENN
+Added done icon.
+
+ Rev 1.1 22 Jan 1992 12:22:26 GLENN
+Added animated icons
+
+ Rev 1.0 20 Nov 1991 19:41:30 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+// ICON RESOURCE IDs -- RANGE: 1 - 20
+
+#define IDRI_WNTRPARK ID(1)
+#define IDRI_SETUP ID(2)
+#define IDRI_DISKS ID(3)
+#define IDRI_TAPES ID(4)
+#define IDRI_JOBS ID(5)
+#define IDRI_JOBS1 ID(6)
+#define IDRI_JOBS2 ID(7)
+#define IDRI_TREE ID(8)
+#define IDRI_FILES ID(9)
+#define IDRI_TREEFILE ID(10)
+#define IDRI_DEBUG ID(11)
+#define IDRI_SERVERS ID(12)
+#define IDRI_LOGFILES ID(13)
+#define IDRI_SEARCH ID(14)
+#define IDRI_BACKUP ID(15)
+#define IDRI_RESTORE ID(16)
+#define IDRI_TRANSFER ID(17)
+#define IDRI_DONE ID(18)
+#define IDRI_EXCHANGE ID(19)
+
+#define IDRI_BKUP0 ID(20)
+#define IDRI_BKUP1 ID(21)
+#define IDRI_BKUP2 ID(22)
+#define IDRI_BKUP3 ID(23)
+#define IDRI_BKUP4 ID(24)
+#define IDRI_BKUP5 ID(25)
+#define IDRI_BKUP6 ID(26)
+#define IDRI_BKUP7 ID(27)
+#define IDRI_BKUP8 ID(28)
+
+#define IDRI_SPIN0 ID(30)
+#define IDRI_SPIN1 ID(31)
+#define IDRI_SPIN2 ID(32)
+#define IDRI_SPIN3 ID(33)
diff --git a/private/utils/ntbackup/inc/image_fs.h b/private/utils/ntbackup/inc/image_fs.h
new file mode 100644
index 000000000..612a49197
--- /dev/null
+++ b/private/utils/ntbackup/inc/image_fs.h
@@ -0,0 +1,165 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: image_fs.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains the prototypes for the IMAGE
+ file system functions.
+
+ $Log: N:/LOGFILES/IMAGE_FS.H_V $
+ *
+ * Rev 1.3 22 Sep 1992 17:15:26 CHUCKB
+ * Removed references to fs_GetTotalSizeDBLK().
+ *
+ * Rev 1.2 16 Dec 1991 18:12:26 STEVEN
+ * move common functions into table
+ *
+ * Rev 1.1 23 May 1991 16:46:00 BARRY
+ * Changes for FindFirst/Next to scan for dirs only
+ *
+ * Rev 1.0 09 May 1991 13:31:36 HUNTER
+ * Initial revision.
+
+**/
+
+#ifndef _image_fs_h_
+#define _image_fs_h_
+
+#include "fsys.h"
+
+
+INT16 IM_AttachToDLE( FSYS_HAND fsh, /* I - File system handle */
+ GENERIC_DLE_PTR dle, /*I/O- drive to attach to. list element expanded */
+ CHAR_PTR u_name, /* I - user name NOT USED */
+ CHAR_PTR pswd); /* I - passowrd NOT USED */
+
+INT16 IM_DetachDLE( FSYS_HAND fsh ); /* I - */
+
+INT16 IM_CreateObj( FSYS_HAND fsh, /* I - File system to create object one */
+ DBLK_PTR dblk); /* I - Describes object to create */
+
+INT16 IM_OpenObj( FSYS_HAND fsh, /* I - file system that the file is opened on */
+ FILE_HAND *hand, /* O - allocated handle */
+ DBLK_PTR dblk, /*I/O- describes the file to be opened */
+ OPEN_MODE mode); /* I - open mode */
+
+INT16 IM_ReadObj( FILE_HAND hand, /* I - handle of object to read from */
+ CHAR_PTR buf, /* O - buffer to place data into */
+ UINT16 *size, /*I/O- Entry: size of buf; Exit: number of bytes read */
+ UINT16 *blk_size); /* O - Block size needed for next read */
+
+
+INT16 IM_WriteObj( FILE_HAND hand, /* I - handle of object to read from */
+ CHAR_PTR buf, /* I - buffer to place data into */
+ UINT16 *size, /*I/O- Entry: size of buf; Exit: number of bytes read */
+ UINT16 *blk_size); /* O - Block size need for next read */
+
+INT16 IM_VerifyObj( FILE_HAND hand, /* I - file handle to verify data with */
+ CHAR_PTR buf, /* I - buffer needed to perform verify */
+ CHAR_PTR data, /* I - data to verify against */
+ UINT16 *size, /*I/O- size of buffers / amount verified */
+ UINT16 *blk_size); /* O - minum size of block for next call */
+
+
+INT16 IM_CloseObj( FILE_HAND hand ); /* I - handle of object to close */
+
+IM_ReturnInfoSucces( FSYS_HAND fsh,
+ DBLK_PTR dblk );
+
+
+INT16 IM_FindFirst( FSYS_HAND fsh, /* I - file system handle */
+ DBLK_PTR dblk, /* O - pointer to place to put the dblk data */
+ CHAR_PTR sname, /* I - serach name */
+ UINT16 find_type ) ; /* I - type of search */
+
+INT16 IM_FindNext( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ); /* O - Discriptor block */
+
+
+INT16 IM_GetCurrentPath( FSYS_HAND fsh, /* I - file system to get current path from */
+ CHAR_PTR path, /* O - buffer to place this path */
+ INT16 *size); /*I/O- size of buffer on entry & on exit */
+
+INT16 IM_SeekObj( FILE_HAND hand, /* I - Opened object to seek into */
+ UINT32 *offset ); /*I/O- Offset to seek; Number of bytes actualy seeked */
+
+INT16 IM_GetMaxSizeDBLK( FSYS_HAND fsh /* not used */ );
+
+INT16 IM_GetBasePath( FSYS_HAND fsh, /* I - file system to get base path from */
+ CHAR_PTR full_path, /* O - buffer to place this path */
+ INT16 *size ); /*I/O- size of buffer on entry & on exit */
+
+INT16 IM_ReturnInfoSuccess( FSYS_HAND fsh, /* I - file system handle */
+ DBLK_PTR dblk ); /* I - data to write to disk */
+
+INT16 IM_GetNoDateDBLK( DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ); /*I/O- createion date to read (or to write) */
+
+INT16 IM_ModNoDateDBLK( BOOLEAN set_it , /* I - TRUE if setting creation date, FALSE if getting */
+ DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ) ; /*I/O- createion date to read (or to write) */
+
+UINT32 IM_GetGenSizeDBLK( FSYS_HAND fsh,
+ DBLK_PTR dblk );
+
+INT16 IM_ModAttribDBLK( BOOLEAN set_it ,
+ DBLK_PTR dblk ,
+ UINT32_PTR attr );
+
+
+INT16 IM_GetObjTypeDBLK( DBLK_PTR dblk,
+ OBJECT_TYPE *type );
+
+
+// UINT32 IM_GetTotalSizeDBLK( FSYS_HAND fsh,
+// DBLK_PTR dblk );
+
+VOID IM_SetOwnerId( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk, /* O - DBLK to modify */
+ UINT32 id ); /* I - value to set it to */
+
+UINT32 IM_GetGenOffsetDBLK( FSYS_HAND fsh , /* I - File system handle - not used */
+ DBLK_PTR dblk ); /* I - Descriptor block to get generic data size for */
+
+INT16 IM_SizeofOSInfo( FSYS_HAND fsh , /* I - File system handle */
+ DBLK_PTR dblk ); /* I - DBLK to get size of OS info for */
+
+INT16 IM_GetOS_InfoDBLK( DBLK_PTR dblk , /* I - DBLK to get the info from */
+ CHAR_PTR os_info , /* O - Buffer to place data */
+ INT16 *size ); /*I/O- Buffer size / data length */
+
+INT16 IM_GetActualSizeDBLK( FSYS_HAND fsh ,
+ DBLK_PTR dblk );
+
+INT16 IM_CreateIDB( FSYS_HAND fsh, GEN_IDB_DATA_PTR dat );
+
+
+INT16 IM_UpDir( FSYS_HAND fsh ) ;
+
+
+INT16 IM_ChangeDir( FSYS_HAND fsh, CHAR_PTR path, INT16 psize ) ;
+
+INT16 IM_GetCurrentDDB( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+
+INT16 IM_GetPname( FSYS_HAND fsh,
+ DBLK_PTR dblk, /* I - Descriptor block to get path from */
+ CHAR_PTR buf ); /*I/O- path to read (or to write) */
+
+INT16 IM_SizeofPname( FSYS_HAND fsh,
+ DBLK_PTR dblk ); /* I - Descriptor block to get path from */
+
+INT16 IM_FindDrives( DLE_HAND hand, BE_CFG_PTR cfg ) ;
+
+INT16 IM_MakePath(
+CHAR_PTR buf,
+INT16 bsize,
+GENERIC_DLE_PTR dle,
+CHAR_PTR path,
+INT16 psize,
+CHAR_PTR fname ) ;
+
+
+#endif
diff --git a/private/utils/ntbackup/inc/imdblk.h b/private/utils/ntbackup/inc/imdblk.h
new file mode 100644
index 000000000..6e9fd4530
--- /dev/null
+++ b/private/utils/ntbackup/inc/imdblk.h
@@ -0,0 +1,56 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: imdblk.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains the definition of the IMAGE
+ descriptor block for the IMAGE file system.
+
+
+
+ $Log: G:/LOGFILES/IMDBLK.H_V $
+ *
+ * Rev 1.0 09 May 1991 13:32:34 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ include list */
+
+
+
+#ifndef imdblk_h
+#define imdblk_h
+
+
+typedef struct IMAGE_DBLK *IMAGE_DBLK_PTR;
+
+typedef struct IMAGE_DBLK {
+ UINT8 blk_type; /* IDB_ID */
+ COM_DBLK fs_reserved ;
+ UINT8_PTR allocated_buff;
+ UINT8_PTR dma_buff;
+
+ UINT16 bytes_per_sector;
+ UINT16 bytes_per_track;
+ UINT16 hsect; /* number of sectors per track */
+ UINT16 hhead; /* number of heads */
+ UINT32 rsect; /* relative sector number of partition's first sector */
+ UINT32 num_sect; /* number of sectors in partition */
+ UINT16 sys_ind; /* partition's system indicator */
+ BOOLEAN has_bad_blk_maps; /* TRUE if dblks may contain the < 2.6 bad block maps */
+ UINT32 dist_to_bad_block_map;
+ UINT8_PTR saved_bad_block_map;
+ UINT16 size_of_bad_block_map; /* size needed for saved_bad_block_map ( on tape their may be a */
+ /* whole sector worth, however only the first n bytes are significant) */
+
+ UINT16 part_name ;
+
+} IMAGE_DBLK;
+
+
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/install.h b/private/utils/ntbackup/inc/install.h
new file mode 100644
index 000000000..7a385f4e3
--- /dev/null
+++ b/private/utils/ntbackup/inc/install.h
@@ -0,0 +1,148 @@
+/******************************************************************************
+Copyright (c) Glenn Hansen. 1993
+GSH
+
+ Name: install.h
+
+ Description: This file contains the headers and definitions for a
+ Generic Installation program for Windows and Windows NT.
+
+ $Log: G:\ui\logfiles\install.h_v $
+
+ Rev 1.0 17 Aug 1993 16:38:16 GLENN
+Initial revision.
+
+******************************************************************************/
+
+
+// Include the common product definition file.
+
+#ifndef _install_h_
+#define _install_h_
+
+#include "proddefs.h"
+
+#define ID(x) MAKEINTRESOURCE(x)
+
+// DEFINITIONS and IDs
+
+#define IDC_NTINSTC 1
+
+#define IDD_QUESTION 1
+#define IDD_NLS 2
+
+#define IDDC_PATH 200
+#define IDDC_SPECIFYTARGET 201
+#define IDDC_ADDLAUNCHER 202
+
+#define IDDC_LANGUAGESTART 1000
+
+#define IDDC_LANGUAGE1 (IDDC_LANGUAGESTART+1)
+#define IDDC_LANGUAGE2 (IDDC_LANGUAGESTART+2)
+#define IDDC_LANGUAGE3 (IDDC_LANGUAGESTART+3)
+#define IDDC_LANGUAGE4 (IDDC_LANGUAGESTART+4)
+#define IDDC_LANGUAGE5 (IDDC_LANGUAGESTART+5)
+#define IDDC_LANGUAGE6 (IDDC_LANGUAGESTART+6)
+#define IDDC_LANGUAGE7 (IDDC_LANGUAGESTART+7)
+#define IDDC_LANGUAGE8 (IDDC_LANGUAGESTART+8)
+
+#define IDRBM_TITLEBOX 100
+#define IDRBM_APPLOGO 101
+#define IDRBM_PERCDONE 102
+#define IDRBM_GRANITE 103
+
+#define IDD_BLACK 0
+#define IDD_BLUE 1
+#define IDD_GREEN 2
+#define IDD_CYAN 3
+#define IDD_RED 4
+#define IDD_MAGENTA 5
+#define IDD_YELLOW 6
+#define IDD_WHITE 7
+#define IDD_GRAY 8
+#define IDD_DKBLUE 9
+#define IDD_DKGRAY 10
+#define IDD_DKGREEN 11
+
+#define IDD_RECT 20
+#define IDD_ELL 21
+
+#define IDD_PAINT 30
+
+#define BM_OFFSET 100
+
+#define DEST_PATH_LEN 128
+#define DEST_PATH_SIZE (DEST_PATH_LEN + 1)
+
+#define INFOWIN_WIDTH 340
+#define INFOWIN_HEIGHT 200
+
+#define PERCWIN_WIDTH 356
+#define PERCWIN_HEIGHT 170
+#define PERCWIN_BAR_WIDTH 300
+#define PERCWIN_BAR_HEIGHT 28
+
+#define WM_INITAPPLICATION (WM_USER+201)
+
+// STRING TABLE IDs
+
+#include "inststr.h"
+
+// GLOBALS
+
+extern HINSTANCE ghInst;
+extern HINSTANCE ghResInst;
+extern BOOL gfCmdLine;
+extern HWND ghWndFrame;
+extern HWND ghWndClient;
+extern HWND ghWndInfo;
+extern HWND ghWndInfoText;
+extern HWND ghWndPerc;
+extern HWND ghWndPercButton;
+extern INT gnTitleBitmapBottom;
+extern CHAR gszAppDestPath[DEST_PATH_SIZE];
+extern CHAR gszWelcomeText[120];
+extern BOOL gfCancel;
+extern INT gnLanguageID;
+extern BOOL gfWaiting;
+
+// MACROS
+
+#define RSM_StringCopy( x, y, z ) RSM_StringLoad( x, y, z )
+
+// FUNCTION PROTOTYPES
+
+WINRESULT WINAPI _export FrameWndProc ( HWND, MSGID, MP1, MP2 );
+WINRESULT WINAPI _export ClientWndProc ( HWND, MSGID, MP1, MP2 );
+WINRESULT WINAPI _export InfoWndProc ( HWND, MSGID, MP1, MP2 );
+WINRESULT WINAPI _export PercentWndProc ( HWND, MSGID, MP1, MP2 );
+WINRESULT WINAPI _export ButtonWndProc ( HWND, MSGID, MP1, MP2 );
+DLGRESULT WINAPI _export DM_NLSDlg ( HWND, MSGID, MP1, MP2 );
+DLGRESULT WINAPI _export DM_TargetDlg ( HWND, MSGID, MP1, MP2 );
+WINRESULT WINAPI _export WM_DDEClientWndProc ( HWND, MSGID, MP1, MP2 );
+
+BOOL EnablePercentDone ( BOOL );
+BOOL SetPercentDone ( INT );
+BOOL SetPercentText ( INT );
+BOOL EnableInfo ( BOOL );
+BOOL SetInfoBox ( UINT );
+BOOL CheckForCancel ( VOID );
+BOOL DM_ShowNLSDlg ( HWND );
+BOOL DM_ShowTargetDlg ( HWND, LPSTR );
+INT WM_MsgBox ( LPSTR, LPSTR, WORD, WORD );
+VOID WM_MultiTask ( VOID );
+INT RSM_StringLoad ( UINT, LPSTR, INT );
+INT RSM_Sprintf ( LPSTR, LPSTR, ... );
+BOOL RSM_BitmapDraw ( WORD, INT, INT, INT, INT, HDC );
+HBITMAP RSM_BitmapLoad ( WORD );
+BOOL RSM_GetBitmapSize ( WORD, LPINT, LPINT );
+VOID DrawBorder ( HDC, LPRECT, HPEN, HPEN );
+VOID DrawButtonUpBorder ( HDC, LPRECT );
+VOID DrawGroupBorder ( HDC, LPRECT );
+VOID DrawStatusBorder ( HDC, LPRECT );
+VOID DrawStatusRaisedBorder ( HDC, LPRECT );
+VOID DrawTileBorder ( HDC, LPRECT );
+INT ChiselText ( HDC, LPSTR, INT, LPRECT, UINT );
+VOID STM_Recessed3D ( HDC, LPRECT );
+
+#endif
diff --git a/private/utils/ntbackup/inc/int21.h b/private/utils/ntbackup/inc/int21.h
new file mode 100644
index 000000000..130eb2317
--- /dev/null
+++ b/private/utils/ntbackup/inc/int21.h
@@ -0,0 +1,23 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: int21.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This header file has the prototype for the INT21 handler
+ entry points.
+
+
+ $Log: G:/LOGFILES/INT21.H_V $
+ *
+ * Rev 1.0 09 May 1991 13:31:34 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+INT16 GetFuncNum( VOID );
+VOID Init_INT21( VOID ) ;
+VOID Remove_INT21( VOID ) ;
diff --git a/private/utils/ntbackup/inc/ipx.h b/private/utils/ntbackup/inc/ipx.h
new file mode 100644
index 000000000..572fae356
--- /dev/null
+++ b/private/utils/ntbackup/inc/ipx.h
@@ -0,0 +1,125 @@
+/** :IH1: Copyright (C) Maynard Electronics, Inc. 1984-89
+
+ :Name: IPX.H
+
+ :Description: Header file for all IPX functions.
+
+
+ $Log: G:/LOGFILES/IPX.H_V $
+ *
+ * Rev 1.0 09 May 1991 13:33:16 HUNTER
+ * Initial revision.
+
+
+$Log$
+
+ Rev 2.2 16 Jan 1991 08:53:22 JIMG
+ Use ScheduleIPXEvent
+
+ Rev 2.1 17 Dec 1990 10:19:30 JIMG
+ Fixed spelling error in function name
+
+ Rev 2.0 21 May 1990 14:02:22 PAT
+ Baseline Maynstream 3.1
+
+ Initial revision.
+**/
+
+#ifndef IPX
+#define IPX
+
+#pragma pack(1) /* force byte allignment */
+
+typedef struct IPX_NETWORK { UINT8 digits[4]; } IPX_NETWORK;
+typedef struct IPX_NODE { UINT8 digits[6]; } IPX_NODE;
+typedef struct IPX_SOCKET { UINT8 digits[2]; } IPX_SOCKET;
+
+typedef IPX_NETWORK far *IPX_NETWORK_PTR;
+
+typedef struct IPXAddress
+{
+ IPX_NETWORK network; /* high-low */
+ IPX_NODE node; /* high-low */
+ IPX_SOCKET socket; /* high-low */
+} IPXAddress;
+
+typedef IPXAddress far *IPXAddress_PTR;
+
+typedef struct IPXHeader
+{
+ UINT16 checkSum; /* high-low */
+ UINT16 length; /* high-low */
+ UINT8 transportControl;
+ UINT8 packetType; /* must initialize for send */
+ IPXAddress destination; /* must initialize for send */
+ IPXAddress source; /* ??? */
+} IPXHeader;
+
+typedef IPXHeader far *IPXHeader_PTR;
+
+typedef struct ECBFragment
+{
+ VOID far *address;
+ UINT16 size; /* low-high */
+} ECBFragment;
+
+typedef VOID (far *FAR_PF_VOID)();
+
+typedef struct ECB
+{
+ VOID far *linkAddress;
+ FAR_PF_VOID ESRAddress; /* must initialize */
+ UINT8 inUseFlag;
+ UINT8 completionCode;
+ UINT16 socketNumber; /* high-low, must initialize */
+ UINT8 IPXWorkspace[4];
+ UINT8 driverWorkspace[12];
+ IPX_NODE immediateAddress; /* high-low, must initialize for send */
+ UINT16 fragmentCount; /* low-high, must initialize */
+ ECBFragment fragmentDescriptor[1]; /* must initialize */
+} ECB;
+
+typedef ECB far *ECB_PTR;
+
+/* You must have at least one fragment for the IPXHeader. If you want */
+/* to break up the data into more fragments then you must declare an */
+/* ECB and as many additional fragments as you need in a single */
+/* structure. */
+/* */
+/* Example: typedef struct ECB3 { */
+/* ECB ecb; */
+/* ECBFragment fragmentDescriptor[2]; */
+/* } ECB3; */
+/* ECB3 foo; */
+/* You should refer to the last two fragments as */
+/* foo.ecb.fragmentDescriptor[1] and foo.ecb.fragmentDescriptor[2]. */
+
+BOOLEAN IPXInitialize( VOID );
+UINT8 IPXOpenSocket( UINT16 *socketNumber_ptr, UINT16 socketLongevity );
+VOID IPXSendPacket( ECB far *eventControlBlock_ptr );
+VOID IPXListenForPacket( ECB far *eventControlBlock_ptr );
+VOID IPXCloseSocket( UINT16 socketNumber );
+UINT8 IPXGetLocalTarget( IPXAddress far *networkAddress_ptr, VOID far *immediateAddress_ptr,
+ UINT16 far *transportTime_ptr );
+VOID IPXGetInternetworkAddress( IPXAddress far *networkAddress_ptr );
+VOID IPXScheduleIPXEvent( ECB far *eventControlBlock_ptr, UINT16 delay_time );
+UINT8 IPXCancelEvent( ECB far *eventControlBlock_ptr );
+UINT16 IPXGetIntervalMarker( VOID );
+VOID IPXRelinquishControl( VOID ) ;
+VOID LogIPXCall( UINT16 CallerID,ECB far *ecb_ptr ) ;
+
+#ifdef MSDEBUG
+#define IPXLog(x,y) LogIPXCall(x,y)
+#else
+#define IPXLog(x,y)
+#endif
+
+#define Hi(x) ((UINT8) ((x) >> 8 ))
+#define Lo(x) ((UINT8) ((x) & 0x00FF))
+#define Int16Swap(x) ( ( Lo(x) << 8 ) | Hi(x) )
+
+#define IPX_MAX_DATA_SIZE (576 - sizeof( IPXHeader ))
+
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/islecfg.h b/private/utils/ntbackup/inc/islecfg.h
new file mode 100644
index 000000000..a72c624ff
--- /dev/null
+++ b/private/utils/ntbackup/inc/islecfg.h
@@ -0,0 +1,7 @@
+#ifndef ISLECFG_RH
+
+#define ISLECFG_RH
+
+#define SES_ENG_ISLE 0
+
+#endif
diff --git a/private/utils/ntbackup/inc/job_new.h b/private/utils/ntbackup/inc/job_new.h
new file mode 100644
index 000000000..98d74c53d
--- /dev/null
+++ b/private/utils/ntbackup/inc/job_new.h
@@ -0,0 +1,15 @@
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_JOBNEW 8
+#else
+#include "dlg_ids.h"
+#endif
+
+#define IDD_J_COPTIONS 0x006A
+#define IDD_J_CJOBNAME 0x006C
+#define IDD_J_CSELECT 0x006E
+#define IDD_J_COPERATION 0x0070
+#define IDD_J_CADDTOPM 0x0071
+#define IDD_J_CMINIMIZE 0x0072
+
diff --git a/private/utils/ntbackup/inc/job_opts.h b/private/utils/ntbackup/inc/job_opts.h
new file mode 100644
index 000000000..7ace8dc58
--- /dev/null
+++ b/private/utils/ntbackup/inc/job_opts.h
@@ -0,0 +1,76 @@
+
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: job_opts.h
+
+ Description: Job options dialog ID header file.
+
+ $Log: G:/UI/LOGFILES/JOB_OPTS.H_V $
+
+ Rev 1.8 06 Jul 1993 09:48:44 chrish
+Cayman EPR 0452: Added the id IDD_J_JOBOPT_HWCOMP for supporting hardware
+compression
+
+ Rev 1.7 21 Jun 1993 11:00:40 CHUCKB
+Added define for drive name control.
+
+ Rev 1.6 04 Oct 1992 19:47:34 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.5 06 Apr 1992 09:53:52 CHUCKB
+Added define for translation.
+
+ Rev 1.4 19 Mar 1992 16:34:14 CHUCKB
+Added id for bindery checkbox.
+
+ Rev 1.3 27 Jan 1992 14:55:34 CHUCKB
+Updated id's.
+
+ Rev 1.2 27 Jan 1992 13:48:24 GLENN
+Fixed IDs
+
+ Rev 1.1 27 Jan 1992 12:50:38 GLENN
+Fixed dialog IDs.
+
+*******************************************************************************/
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_JOBOPTS 10
+#else
+#include "dlg_ids.h"
+#endif
+
+#ifndef _job_opts_h_
+
+#define _job_opts_h_
+
+#define IDD_J_JOBOPT_AUTOVERIFY 301
+#define IDD_J_JOBOPT_BACKFLAG 302
+#define IDD_J_JOBOPT_INCCATS 303
+#define IDD_J_JOBOPT_SKIPOPEN 304
+#define IDD_J_JOBOPT_LOGPRT 305
+#define IDD_J_JOBOPT_APPEND 307
+#define IDD_J_JOBOPT_REPLACE 308
+#define IDD_J_JOBOPT_USEPSWD 309
+#define IDD_J_JOBOPT_PSWD 310
+#define IDD_J_JOBOPT_TAPENAME 311
+#define IDD_J_JOBOPT_DESC 312
+#define IDD_J_JOBOPT_TAPEPROMPT 313
+#define IDD_J_JOBOPT_METHOD 314
+#define IDD_J_JOBOPT_DRIVENAME 315
+
+#define IDD_J_JOBOPT_NUMSECSBOX 0x0067
+#define IDD_J_JOBOPT_EJECT 0x0069
+#define IDD_J_JOBOPT_BINDERY 0x006A
+#define IDD_J_JOBOPT_SKIPYES 0x0076
+#define IDD_J_JOBOPT_SKIPNO 0x0077
+#define IDD_J_JOBOPT_SKIPWAIT 0x0078
+#define IDD_J_JOBOPT_NUMSECS 0x0079
+#define IDD_J_JOBOPT_PARTCAT 0x007A
+#define IDD_J_JOBOPT_FULLCAT 0x007B
+#define IDD_J_JOBOPT_HWCOMP 0x007C // chs:07-06-93
+
+#endif
diff --git a/private/utils/ntbackup/inc/jobs.h b/private/utils/ntbackup/inc/jobs.h
new file mode 100644
index 000000000..450585ae2
--- /dev/null
+++ b/private/utils/ntbackup/inc/jobs.h
@@ -0,0 +1,337 @@
+/****************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+ Name: JOBS.H
+
+ Description: This header file contains prototypes for the
+ processing of JOB related operations.
+
+ $Log: G:\ui\logfiles\jobs.h_v $
+
+ Rev 1.26 10 Aug 1993 11:11:54 CHUCKB
+Took out prototype for JOB_GetDevice because we don't need it any more.
+
+ Rev 1.25 10 Aug 1993 10:35:08 TIMN
+Added disable wait define
+
+ Rev 1.24 05 Aug 1993 18:55:26 CHUCKB
+Added fields to struct for waiting for a device.
+
+ Rev 1.23 03 Aug 1993 21:06:50 CHUCKB
+Added prototype for JOB_GetDevice.
+
+ Rev 1.22 03 Aug 1993 16:38:08 CHUCKB
+Moved prototype for JOB_LogJob from job_strt.c to here.
+
+ Rev 1.21 02 Aug 1993 17:52:38 CHUCKB
+Added new struct and defines for wait-device dialog.
+
+ Rev 1.20 30 Jul 1993 10:48:50 CHUCKB
+Changed macro for SetTapePassword to use a length.
+
+ Rev 1.19 27 Jul 1993 22:15:40 CHUCKB
+Added field and macros for password length.
+
+ Rev 1.18 06 Jul 1993 09:49:30 chrish
+Cayman EPR 0452: Added two additional macros to support hardware compression
+for running a job.
+ Macros:
+ 1. JOB_GetHWCompression
+ 2. JOB_SetHWCompression
+
+ Added fhwcompression field to JOBREC structure to support hardware
+compression for running a job.
+
+
+
+ Rev 1.17 21 Jun 1993 10:47:26 CHUCKB
+Added field for device name, along with size defines and macros.
+
+ Rev 1.16 04 Oct 1992 19:47:28 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.15 22 Sep 1992 10:57:50 GLENN
+Added Job name ID, file name ID, method, append, verify, support to JOB_MakeAutoJob ().
+
+ Rev 1.14 18 Sep 1992 17:31:18 GLENN
+Changed the make auto jobs header.
+
+ Rev 1.13 06 Apr 1992 09:56:18 CHUCKB
+Added define for translation.
+
+ Rev 1.12 19 Mar 1992 16:33:46 CHUCKB
+Added bindery field to job structure and incremented job version number.
+
+ Rev 1.11 21 Feb 1992 16:10:08 CHUCKB
+Changed job record structure and macros for NT/MIPS.
+
+ Rev 1.10 12 Feb 1992 09:19:06 CHUCKB
+Changed job version number because job record structure changed (max file name len).
+
+ Rev 1.9 05 Feb 1992 09:00:02 CHUCKB
+Took out JOB_Error; it is no longer needed.
+
+ Rev 1.8 03 Feb 1992 16:58:48 CHUCKB
+Added prototype for JOB_Error().
+
+ Rev 1.7 24 Jan 1992 14:01:30 CHUCKB
+Put more dialogs on net.
+
+ Rev 1.6 15 Jan 1992 09:28:24 ROBG
+Added define for JOB_VER_NUM.
+
+ Rev 1.5 10 Jan 1992 19:19:32 CHUCKB
+Put in field/macros for eject tape option.
+
+ Rev 1.4 17 Dec 1991 17:49:24 CHUCKB
+No change.
+
+ Rev 1.3 10 Dec 1991 09:48:40 CHUCKB
+Fixed prototype for makeautojob.
+
+ Rev 1.2 09 Dec 1991 17:03:08 CHUCKB
+Added prototype for MakeAutoJob.
+
+ Rev 1.1 21 Nov 1991 17:30:16 DAVEV
+Changed function prototype of JOB_EnumPMGroupWindows for new portable
+definition of a callback procedure (must be APIENTRY and second parameter
+is a LONG).
+
+ Rev 1.0 20 Nov 1991 19:35:38 SYSTEM
+Initial revision.
+
+****************************************************************************/
+
+#ifndef jobs_h
+
+#define jobs_h
+
+// defines for run jobs dialog
+
+#include "jobsetup.h"
+
+// defines for new jobs dialog
+
+#include "job_new.h"
+
+#define IDD_J_CSELTXT 204
+#define IDD_J_CUNATTEND 207
+
+// defines for job options dialog
+
+#include "job_opts.h"
+
+#define IDD_J_JOBOPT_UP 318
+#define IDD_J_JOBOPT_DOWN 319
+
+// defines for schedule jobs dialog
+
+#include "sch_opts.h"
+
+#define IDD_J_SQUEUE 401
+
+// defines for job schedule options
+
+#define IDD_NUMHOURS_UP 526
+#define IDD_NUMHOURS_DOWN 527
+#define IDD_NUMDATE_UP 528
+#define IDD_NUMDATE_DOWN 529
+
+#define IDD_J_SLAST 555
+
+#define IDD_J_SSHOWWKS 560
+#define IDD_J_SFIRST 561
+#define IDD_J_SSECOND 562
+#define IDD_J_STHIRD 563
+#define IDD_J_SFOURTH 564
+#define IDD_J_SNUMBER 573
+
+// Version of job records
+
+#define JOB_VER_NUM 4
+
+// job type/method defines
+
+#define JOBBACKUP 100
+#define JOBRESTORE 101
+#define JOBTRANSFER 102
+
+#define MAX_JOBNAME_LEN 32
+#define MAX_JOBNAME_SIZE 33
+#define MAX_DESC_LEN 60
+#define MAX_DESC_SIZE 61
+#define MAX_DEVICE_NAME_LEN 255
+#define MAX_DEVICE_NAME_SIZE MAX_DEVICE_NAME_LEN + 1
+#define JOB_NOTSCHEDULED (-1)
+
+/* Defines used when accessing the JOB and SCHEDULE files */
+
+#define FOPEN_ERR -1
+#define FREAD_ERR -2
+#define FWRITE_ERR -3
+#define FCLOSE_ERR -4
+
+// JOB STRUCTURE -- optimized for NT on MIPS
+
+typedef struct {
+
+ INT32 nOperType ; // Backup, transfer, etc.
+ INT32 fAddToPm ; // Add job to PM
+ INT32 fRunMinimized ; // Minimize on use
+ INT32 fAutoVerify ; // Autoverify oper
+ INT32 fSetArchiveBit ; // Set backup flag
+ INT32 fIncCats ; // Include cats in operations
+ INT32 fSkipOpen ; // Skip files in use
+ INT32 nWaitTime ; // # of seconds to wait for open files
+ INT32 fPrintLog ; // Print the log when done
+ INT32 fCatalogLevel ; // Enable full cataloging
+ INT32 fAppend ; // Append or overwrite tape
+ INT32 fPassword ; // Password protect tapes
+ INT32 nMethod ; // backup method (inc., dif., norm., copy)
+ INT32 fEjectTape ; // True if eject tape on exit
+ INT32 fBackupBindery ; // True if bindery files are to be backed up
+ INT32 fhwcompression; // chs: 07-06-93 True if to enable HW compression
+ INT32 nPasswordLen ; // Length of password (it might have nulls in it)
+
+ // Name of the tape to create
+ TCHAR szTapeName[MAX_TAPE_NAME_SIZE+4-((MAX_TAPE_NAME_SIZE)%4)] ;
+ // Password for the tape
+ TCHAR szTapePassword[MAX_TAPE_PASSWORD_SIZE+4-((MAX_TAPE_PASSWORD_SIZE)%4)] ;
+ // Name of this job
+ TCHAR szJobName[MAX_JOBNAME_SIZE+4-((MAX_JOBNAME_SIZE)%4)];
+ // Name of selection file
+ TCHAR szSelectName[MAX_UI_FILENAME_SIZE+4-((MAX_UI_FILENAME_SIZE)%4)] ;
+ // Name of tape device
+ TCHAR szDeviceName[MAX_DEVICE_NAME_SIZE*sizeof(TCHAR)] ;
+
+ Q_ELEM pQElem ;
+
+} JOBREC, *JOBREC_PTR ;
+
+// The following structure is used by the error dialog for the case when
+// a drive is requested, but either doesn't exist any more or is already
+// in use.
+
+#ifdef OS_WIN32
+
+typedef struct {
+
+ LPSTR lpszDriveName; // Name of a drive to wait for
+ INT nDlgType ; // Type of dialog (see below)
+ PF_VOID pfnCallBack ; // Pointer to function to claim drive
+ INT nWaitTime ; // Num of seconds to wait between tries
+ INT nDevNum ; // Device number (lun) from registry
+ HANDLE hDrive ; // Handle for nDevNum (returned from pfnCallBack)
+
+} WAITDEV, *WAITDEV_PTR ;
+
+// WaitDevice dialog types
+
+#define WAITDEV_INVALID_JOB 1 // not used
+#define WAITDEV_INVALID_NOTJOB 2 // device name is invalid
+#define WAITDEV_NOTAVAIL_WAIT 3 // device conflict; wait to claim it
+#define WAITDEV_NOTAVAIL 4 // device conflict; just notify user
+
+#define WAITDEV_DISABLEWAIT -1 // stored in nWaitTime to display msg
+ // without waiting
+
+#endif
+
+// JOB MACROS
+
+#define JOB_GetJobName( x ) ( (x)->szJobName )
+#define JOB_SetJobName( x, y ) ( lstrcpy ( (x)->szJobName, (y) ) )
+
+#define JOB_GetSelectName( x ) ( (x)->szSelectName )
+#define JOB_SetSelectName( x, y ) ( lstrcpy ( (x)->szSelectName, (y) ) )
+
+#define JOB_GetOperType( x ) ( (INT)(x)->nOperType )
+#define JOB_SetOperType( x, y ) ( (x)->nOperType = (INT32)(y) )
+
+#define JOB_GetAddToPm( x ) ( (BOOL)(x)->fAddToPm )
+#define JOB_SetAddToPm( x, y ) ( (x)->fAddToPm = (INT32)(y) )
+
+#define JOB_GetRunMinimized( x ) ( (BOOL)(x)->fRunMinimized )
+#define JOB_SetRunMinimized( x, y ) ( (x)->fRunMinimized = (INT32)(y) )
+
+#define JOB_GetAutoVerify( x ) ( (BOOL)(x)->fAutoVerify )
+#define JOB_SetAutoVerify( x, y ) ( (x)->fAutoVerify = (INT32)(y) )
+
+#define JOB_GetSetArchiveBit( x ) ( (BOOL)(x)->fSetArchiveBit )
+#define JOB_SetSetArchiveBit( x, y ) ( (x)->fSetArchiveBit = (INT32)(y) )
+
+#define JOB_GetIncCats( x ) ( (BOOL)(x)->fIncCats )
+#define JOB_SetIncCats( x, y ) ( (x)->fIncCats = (INT32)(y) )
+
+#define JOB_GetSkipOpen( x ) ( (BOOL)(x)->fSkipOpen )
+#define JOB_SetSkipOpen( x, y ) ( (x)->fSkipOpen = (INT32)(y) )
+
+#define JOB_GetWaitTime( x ) ( (INT)(x)->nWaitTime )
+#define JOB_SetWaitTime( x, y ) ( (x)->nWaitTime = (INT32)(y) )
+
+#define JOB_GetPrintLog( x ) ( (BOOL)(x)->fPrintLog )
+#define JOB_SetPrintLog( x, y ) ( (x)->fPrintLog = (INT32)(y) )
+
+#define JOB_GetCatalogLevel( x ) ( (BOOL)(x)->fCatalogLevel )
+#define JOB_SetCatalogLevel( x, y ) ( (x)->fCatalogLevel = (INT32)(y) )
+
+#define JOB_GetAppend( x ) ( (BOOL)(x)->fAppend )
+#define JOB_SetAppend( x, y ) ( (x)->fAppend = (INT32)(y) )
+
+#define JOB_GetPassword( x ) ( (BOOL)(x)->fPassword )
+#define JOB_SetPassword( x, y ) ( (x)->fPassword = (INT32)(y) )
+
+#define JOB_GetMethod( x ) ( (INT)(x)->nMethod )
+#define JOB_SetMethod( x, y ) ( (x)->nMethod = (INT32)(y) )
+
+#define JOB_GetTapeName( x ) ( (x)->szTapeName )
+#define JOB_SetTapeName( x, y ) ( lstrcpy ( (x)->szTapeName, (y) ) )
+
+#define JOB_GetTapePassword( x ) ( (x)->szTapePassword )
+#define JOB_SetTapePassword( x, y, z) ( memmove ( (x)->szTapePassword, (y), (z) ) )
+
+#define JOB_GetEjectTape( x ) ( (BOOL)(x)->fEjectTape )
+#define JOB_SetEjectTape( x, y ) ( (x)->fEjectTape = (INT32)(y) )
+
+#define JOB_GetBackupBindery( x ) ( (BOOL)(x)->fBackupBindery )
+#define JOB_SetBackupBindery( x, y ) ( (x)->fBackupBindery = (INT32)(y) )
+
+#define JOB_GetDeviceName( x ) ( (x)->szDeviceName )
+#define JOB_SetDeviceName( x, y ) ( lstrcpy ( (x)->szDeviceName, (y) ) )
+
+#define JOB_GetHWCompression( x ) ( (BOOL)(x)->fhwcompression ) // chs:07-06-93
+#define JOB_SetHWCompression( x, y ) ( (x)->fhwcompression = (INT32)(y) ) // chs:07-06-93
+
+#define JOB_GetPasswordLen( x ) ( (x)->nPasswordLen )
+#define JOB_SetPasswordLen( x, y ) ( (x)->nPasswordLen = (INT32)(y) )
+
+
+// JOB PROTOTYPES
+
+BOOL JOB_AnyJobFiles ( VOID ) ;
+VOID JOB_DeInitQueue ( VOID ) ;
+VOID JOB_EnQueueJob ( JOBREC_PTR ) ;
+JOBREC_PTR JOB_FindByIndex ( INT ) ;
+JOBREC_PTR JOB_FindJob ( LPSTR ) ;
+INT JOB_GetCount ( VOID ) ;
+VOID_PTR JOB_GetFirstItem ( Q_HEADER_PTR ) ;
+VOID_PTR JOB_GetNext ( VOID_PTR, LPSTR ) ;
+VOID_PTR JOB_GetNextItem ( JOBREC_PTR ) ;
+JOBREC_PTR JOB_GetNextJob ( JOBREC_PTR ) ;
+JOBREC_PTR JOB_InitJob ( VOID ) ;
+VOID JOB_InitQueue ( VOID ) ;
+BOOL JOB_IsIconic ( LPSTR ) ;
+VOID JOB_LogJob ( LPSTR, WORD ); // FALSE if end of execution
+VOID JOB_MakeAutoJob ( INT, INT, INT, INT, BOOL, BOOL ) ;
+INT JOB_ReadList ( VOID ) ;
+VOID JOB_Refresh ( VOID ) ;
+VOID JOB_Remove ( LPSTR ) ;
+INT JOB_SaveList ( VOID ) ;
+BOOL JOB_StartJob ( LPSTR, INT ) ;
+
+BOOL APIENTRY JOB_EnumPMGroupWindows ( HWND, LONG ) ;
+BOOL JOB_AddToProgmanWindow ( HWND, LPSTR, LPSTR ) ;
+BOOL JOB_BuildJobQueue ( Q_HEADER_PTR ) ;
+
+
+#endif
diff --git a/private/utils/ntbackup/inc/jobsetup.h b/private/utils/ntbackup/inc/jobsetup.h
new file mode 100644
index 000000000..cd3418d1c
--- /dev/null
+++ b/private/utils/ntbackup/inc/jobsetup.h
@@ -0,0 +1,15 @@
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_JOBMAINTENANCE 9
+#else
+#include "dlg_ids.h"
+#endif
+
+#define IDD_J_JOBLIST 0x0065
+#define IDD_J_NEW 0x0067
+#define IDD_J_EDIT 0x0068
+#define IDD_J_DEL 0x0069
+#define IDD_J_RUN 0x006A
+#define IDD_J_SCH 0x006C
+
diff --git a/private/utils/ntbackup/inc/jobstat.h b/private/utils/ntbackup/inc/jobstat.h
new file mode 100644
index 000000000..1c47239b4
--- /dev/null
+++ b/private/utils/ntbackup/inc/jobstat.h
@@ -0,0 +1,108 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: jobstat.h
+
+ Description:
+
+
+ $Log: G:/UI/LOGFILES/JOBSTAT.H_V $
+
+ Rev 1.12 10 May 1993 18:22:50 GLENN
+Added JS_OkToClose() prototype to see if the Runtime Status Dialog is OK to close.
+
+ Rev 1.11 18 Jan 1993 14:48:26 GLENN
+Added JS_ReportStreamError.
+
+ Rev 1.10 30 Oct 1992 17:56:24 MIKEP
+started small catalog window
+
+ Rev 1.9 04 Oct 1992 19:47:32 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.8 30 Jul 1992 09:50:50 STEVEN
+fix warnings
+
+ Rev 1.7 20 Jul 1992 10:01:48 JOHNWT
+added gas gauge display
+
+ Rev 1.6 17 Mar 1992 16:53:36 CARLS
+added ID for ABORT_CHECK
+
+ Rev 1.5 20 Feb 1992 14:45:50 CARLS
+added IDs for new abort function
+
+ Rev 1.4 20 Dec 1991 17:05:24 JOHNWT
+returned CREATE_DIALOG
+
+ Rev 1.3 19 Dec 1991 09:59:18 JOHNWT
+Changes for app-modal RTD
+
+ Rev 1.2 09 Dec 1991 17:45:46 JOHNWT
+removed yprompt, YesNoDialogText, RunTimeMessageBox prototypes
+
+ Rev 1.1 06 Dec 1991 09:37:56 CARLS
+added define for catalog title
+
+ Rev 1.0 20 Nov 1991 19:35:28 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifndef _jobstat_h_
+#define _jobstat_h_
+
+#define JOB_STATUS_CREATE_DIALOG ((WORD)1)
+#define JOB_STATUS_DESTROY_DIALOG ((WORD)2)
+#define JOB_STATUS_DIRECTORY_NAMES ((WORD)3)
+#define JOB_STATUS_ELAPSED_TIME ((WORD)4)
+#define JOB_STATUS_FILES_PROCESSED ((WORD)5)
+#define JOB_STATUS_BYTES_PROCESSED ((WORD)6)
+#define JOB_STATUS_VOLUMN_NAME ((WORD)7)
+#define JOB_STATUS_VOLUME_NAME ((WORD)7)
+#define JOB_STATUS_EXCEPTION_WINDOW ((WORD)8)
+#define JOB_STATUS_DIRECTORIES_PROCESS ((WORD)9)
+#define JOB_STATUS_SKIPPED_FILES ((WORD)10)
+#define JOB_STATUS_CORRUPT_FILES ((WORD)11)
+#define JOB_STATUS_FILE_NAMES ((WORD)12)
+#define JOB_STATUS_LISTBOX ((WORD)13)
+#define JOB_STATUS_ABORT_OFF ((WORD)14)
+#define JOB_STATUS_ABORT_ON ((WORD)15)
+#define JOB_STATUS_BACKUP_TITLE ((WORD)16)
+#define JOB_STATUS_RESTORE_TITLE ((WORD)17)
+#define JOB_STATUS_VERIFY_TITLE ((WORD)18)
+#define JOB_STATUS_VOLUME_HARDDRIVE ((WORD)19)
+#define JOB_STATUS_VOLUME_NETDRIVE ((WORD)20)
+#define JOB_STATUS_VOLUME_TAPE ((WORD)21)
+#define JOB_STATUS_SOURCE_NAME ((WORD)22)
+#define JOB_STATUS_DEST_NAME ((WORD)23)
+#define JOB_STATUS_N_OF_N ((WORD)24)
+#define JOB_STATUS_ABORT ((WORD)25)
+#define JOB_STATUS_CATALOG_TITLE ((WORD)26)
+#define JOB_STATUS_ABORT_ENABLE ((WORD)27)
+#define JOB_STATUS_ABORT_DISABLE ((WORD)28)
+#define JOB_STATUS_ABORT_CHECK ((WORD)29)
+#define JOB_STATUS_CREATE_SMALL_DIALOG ((WORD)30)
+#define JOB_STATUS_FS_TYPE ((WORD)31)
+
+#define JOB_TENSION_CREATE_DIALOG ((WORD)1)
+#define JOB_TENSION_DESTROY_DIALOG ((WORD)2)
+#define JOB_TENSION_LISTBOX ((WORD)3)
+#define JOB_TENSION_ABORT_OFF ((WORD)4)
+#define JOB_TENSION_ABORT_ON ((WORD)5)
+#define JOB_TENSION_DRAW_BITMAP ((WORD)6)
+#define JOB_TENSION_ERASE_TITLE ((WORD)7)
+#define JOB_TENSION_TENSION_TITLE ((WORD)8)
+
+/*
+ Prototypes
+*/
+VOID JobStatusTension(WORD);
+VOID JobStatusBackupRestore(WORD);
+VOID JobStatusAbort(VOID *);
+VOID JobStatusStats(UINT64);
+BOOL JS_OkToClose ( VOID );
+VOID JS_ReportStreamError ( FSYS_HAND, GENERIC_DLE_PTR, UINT32, WORD, INT16, DBLK_PTR, DBLK_PTR );
+
+#endif
diff --git a/private/utils/ntbackup/inc/keys.h b/private/utils/ntbackup/inc/keys.h
new file mode 100644
index 000000000..35b7412f3
--- /dev/null
+++ b/private/utils/ntbackup/inc/keys.h
@@ -0,0 +1,37 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: keys.h
+
+ Description: This file contains the ACCELERATOR KEY IDs and
+ miscellaneous key IDs for the Maynstream GUI project.
+
+ $Log: G:/UI/LOGFILES/KEYS.H_V $
+
+ Rev 1.2 04 Oct 1992 19:47:36 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.1 03 Dec 1991 16:04:52 GLENN
+Remove old ribbon accel keys - no longer used. Added some Virtual Keys.
+
+ Rev 1.0 20 Nov 1991 19:37:06 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+
+#ifndef _KEYS_H
+#define _KEYS_H
+
+// WINDOWS ACCELERATOR KEY ID's
+
+#define IDRA_ACCKEYS ID(1)
+
+
+#define VK_8 0x38
+#define VK_OEM_PLUS 0xBB
+#define VK_OEM_MINUS 0xBD
+
+#endif
diff --git a/private/utils/ntbackup/inc/launcher.h b/private/utils/ntbackup/inc/launcher.h
new file mode 100644
index 000000000..5c911308b
--- /dev/null
+++ b/private/utils/ntbackup/inc/launcher.h
@@ -0,0 +1,197 @@
+/****************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+RCG
+ Name: LAUNCHER.H
+
+ Description: This header file contains prototypes for the
+ launcher.
+
+ $Log: G:/UI/LOGFILES/LAUNCHER.H_V $
+
+ Rev 1.18 30 Jul 1993 15:16:28 chrish
+Made change such that there is a maximum and minimum delay time for launcher.
+
+ Rev 1.17 16 Jun 1993 15:08:12 MIKEP
+change types to match global.c again
+
+ Rev 1.16 18 Feb 1993 15:14:38 chrish
+Added stuff for CAYMAN.
+
+ Rev 1.15 04 Oct 1992 19:47:38 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.14 06 Apr 1992 12:26:04 JOHNWT
+added gfTerminateApp
+
+ Rev 1.13 23 Mar 1992 12:33:22 JOHNWT
+added RSM_Sprintf prototype
+
+ Rev 1.12 16 Mar 1992 15:37:50 JOHNWT
+various changes
+
+ Rev 1.11 20 Feb 1992 16:19:40 JOHNWT
+added TempCDS
+
+ Rev 1.10 13 Feb 1992 08:15:42 JOHNWT
+globals change
+
+ Rev 1.9 07 Feb 1992 16:54:22 ROBG
+Changes.
+
+ Rev 1.8 07 Feb 1992 10:15:56 ROBG
+Release after Code Review.
+
+ Rev 1.7 30 Jan 1992 15:55:26 ROBG
+Final Release.
+
+ Rev 1.6 29 Jan 1992 14:59:06 ROBG
+Added logic to support scheduled delays.
+
+ Rev 1.5 23 Jan 1992 11:02:02 ROBG
+chkin for Rob
+
+ Rev 1.4 03 Jan 1992 15:19:54 ROBG
+Final Release before alpha.
+
+ Rev 1.3 30 Dec 1991 16:03:26 ROBG
+minor changes.
+
+ Rev 1.2 13 Dec 1991 10:43:18 ROBG
+Modified to relect JOB and SCHEDULE queues.
+
+ Rev 1.0 14 Oct 1991 14:15:26 ROBG
+Initial revision.
+
+****************************************************************************/
+
+#ifndef LAUNCHER_H
+
+#include <time.h>
+
+#define LAUNCHER_H
+
+// Configuration defines found only in muiconf.c
+
+//#define CDS_SkipBlanks(x) ( for( ; *x == ' '; x ++ ) )
+
+#define WM_ASKTORUN (WM_USER+209) // Used by Launcher only
+#define WM_ASKTOSCHEDULE (WM_USER+210) // Used by Launcher only
+
+// Launcher error codes
+
+#define LCH_ERRREGCLASS 100
+#define LCH_ERRTIMERINIT 101
+
+// Size of file mapped object shared between the Launcher and the
+// backup application.
+
+#define MAPOBJECTSIZE 255
+
+// Timeout value in the delay and run dialogs is LOBYTE of CMS_LAUNCHERFLAG.
+// chs:07-30-93 #define WAIT_FOR_X_SECONDS ( gwLauncherFlag & 0x00ff )
+
+#define LCH_MAX_WAIT_TIME 999
+#define LCH_MIN_WAIT_TIME 0
+
+#define WAIT_FOR_X_SECONDS ( ( gwLauncherFlag > LCH_MAX_WAIT_TIME ) || ( gwLauncherFlag < LCH_MIN_WAIT_TIME ) ? LCH_MAX_WAIT_TIME : gwLauncherFlag ) // chs:07-30-93
+
+
+// Globals
+
+extern Q_HEADER_PTR mwSchedQueue ; // Queue header of the launcher's list
+ // of jobs scheduled.
+
+extern CHAR gb_data_path [ MAX_UI_PATH_SIZE + MAX_UI_FILENAME_SIZE ] ; // Data Path directory.
+extern CHAR gb_exe_path [ MAX_UI_PATH_SIZE + MAX_UI_FILENAME_SIZE ] ; // Executable directory.
+extern CHAR gszWindowName [ MAX_UI_RESOURCE_SIZE ] ;
+extern CHAR gszClassName [ MAX_UI_RESOURCE_SIZE ] ;
+extern CHAR gszHelpFileName [ MAX_UI_PATH_SIZE + MAX_UI_FILENAME_SIZE ] ;
+extern CHAR gszRunningJobName [ MAX_UI_RESOURCE_SIZE ] ;
+
+extern INT16 gwLauncherFlag ; // Launcher Flag found in MAYNARD.INI.
+extern INT16 gnNumScheds ; // Number of current scheduled jobs.
+extern INT16 gnNumJobs; // Number of current jobs.
+extern HINSTANCE ghInst ; // Instance handle.
+extern HINSTANCE ghResInst ; // Instance handle of resources. (same as ghInst )
+extern HWND ghModelessDialog ; // Handle used to show a dialog.
+extern HANDLE ghAccel; // define it to resolve muiutil ref
+extern HWND ghWndMDIClient; // define it to resolve muiutil ref
+extern HWND ghWndFrame ; // Handle of main window handle. (Set to hidden ).
+extern HWND ghDlg ; // Handle of main dialog.
+extern HWND ghwndLastFocus ; // Handle of control with focus
+extern BOOL gfDlgProcComplete ; // Flag used to check if processing in a dialog is occurring.
+extern BOOL gfTimerProcessing ; // Flag used to keep timer processing in sync.
+extern INT16 gnModalDlgTimerValue ; // Value of the main timer.
+extern INT16 gnRunSchedIndex ; // Index into schedule table of running job.
+extern LONG glRunSchedKey ; // Key of running job.
+extern INT16 gnDelayJobIndex ; // Index into schedule table of delayed job.
+extern BYTE gbDelayMinutes ; // Delay Minutes.
+extern BYTE gbDelayHours ; // Delay Hours.
+
+#ifndef CAYMAN
+ extern HANDLE ghMainTimer ; // Handle of main watchdog timer.
+#else
+ extern HTIMER ghMainTimer ; // Handle of main watchdog timer.
+#endif
+
+extern INT gnRunJobIndex ; // Index of running job.
+extern BOOL gfMissedJobs ; // Flag indicating whether jobs were missed.
+extern BOOL gfAskedOnce ; // Flag indicating whether the user has been asked
+ // about closing Winback to run a scheduled job.
+extern BOOL gfDebug; // if /Z was specified
+extern BOOL gfCodeView; // if /CV was specified
+extern BOOL gfCVTwoMonitors; // if /2 was specified
+
+extern LONG glStartTime ; // Time the launcher began in time_t form.
+extern struct tm gtmStartTime ; // Time the launcher began in tm form.
+extern LONG glEndTimeOfJob ; // Time when last job terminated in time_t form.
+
+extern BOOL gfTerminateApp ; // Needed to resolve external ref
+extern CDS PermCDS ; // Needed to resolve external references and structures.
+extern CDS TempCDS ; // Needed to resolve external references and structures.
+extern BE_CFG PermBEC ; // Needed to resolve external references and structures.
+
+#ifdef CAYMAN
+ extern CHAR_PTR gbMappedObjName; // Name of mapping object
+ extern LPVOID gbMappedObjBuffer; // Global mapped object buffer
+#endif
+
+// Prototypes
+
+WINRESULT APIENTRY LauncherWndProc (HWND hWnd, MSGID wMsg, MP1 wParam, MP2 lParam ) ; // chs: 02-18-93
+DLGRESULT APIENTRY LCH_LaunchDlg (HWND hdlg, MSGID wMsg, MP1 wParam, MP2 lParam ) ; // chs: 02-18-93
+DLGRESULT APIENTRY LCH_DelayValuesDlg (HWND hdlg, MSGID wMsg, MP1 wParam, MP2 lParam ) ; // chs: 02-18-93
+WINRESULT APIENTRY LCH_SetFocus (HWND hWnd, MSGID wMsg, MP1 wParam, MP2 lParam ) ; // chs: 02-18-93
+
+WORD LCH_Init ( void ) ;
+VOID LCH_Deinit ( void ) ;
+VOID LCH_SetMaynFolder ( void ) ;
+VOID LCH_GetTimeDateString( TIME_PTR time_struct , CHAR_PTR buffer , INT16 show_Wday ) ;
+
+
+BOOLEAN LCH_TimeToRun ( SCHEDREC_PTR pRec , BOOLEAN bInit ) ;
+VOID LCH_ProcessQueue( void ) ;
+VOID LCH_UpdateQueue ( HWND hdlg ) ;
+VOID LCH_BuildDisplayString ( CHAR_PTR buffer, SCHEDREC_PTR pSchedRec, INT nIndex ) ;
+VOID LCH_LaunchJob ( WORD wIndex ) ;
+BOOL LCH_IsWinterParkRunning( void ) ;
+VOID LCH_InitCDS ( VOID ) ;
+VOID LCH_DeInitCDS ( VOID ) ;
+VOID LCH_TimerForModalDlgs ( VOID ) ;
+VOID LCH_UpdateDialogTime ( void ) ;
+VOID LCH_LookAtQueue( void ) ;
+VOID LCH_SetNoJobsRunning( void ) ;
+BOOL LCH_AJobIsRunning( void ) ;
+VOID LCH_SortScheduleQueue ( void ) ;
+INT16 LCH_ItemCompare( Q_ELEM_PTR pLogElem1, Q_ELEM_PTR pLogElem2 ) ;
+VOID LCH_ProcessSkip( SCHEDREC_PTR pSchedRec ) ;
+VOID LCH_ProcessHold( SCHEDREC_PTR pSchedRec ) ;
+VOID LCH_EnableCorrectButtons ( VOID ) ;
+
+INT WM_MsgBox ( LPSTR lpszTitle, LPSTR lpszMessage, WORD wType, WORD wIcon );
+INT RSM_StringLoad ( VOID_PTR pID, LPSTR lpBuffer, INT nBufferMax ) ;
+VOID HH_WinHelp ( HWND hWnd, WORD wCommand, DWORD dwData ) ;
+INT RSM_Sprintf ( LPSTR, LPSTR, ... );
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/ld_dvr.h b/private/utils/ntbackup/inc/ld_dvr.h
new file mode 100644
index 000000000..ff90d83dd
--- /dev/null
+++ b/private/utils/ntbackup/inc/ld_dvr.h
@@ -0,0 +1,26 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: ld_dvr.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Function prototypes for load driver unit
+
+ Location: BE_PRIVATE
+
+
+ $log$
+
+**/
+
+#ifndef _lddvr_
+#define _lddvr_
+
+typedef UINT16 (*DRIVERHANDLE)() ;
+
+UINT8_PTR DriverLoad( CHAR_PTR,DRIVERHANDLE *,VOID_PTR,UINT16 ) ;
+VOID DriverUnLoad( UINT8_PTR ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/ldialogs.h b/private/utils/ntbackup/inc/ldialogs.h
new file mode 100644
index 000000000..39b874b7e
--- /dev/null
+++ b/private/utils/ntbackup/inc/ldialogs.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+ Name: LDIALOGS.H
+
+ Description: This header file contains the dialog and icons
+ IDs for the launcher's dialogs.
+
+ $Log: G:/UI/LOGFILES/LDIALOGS.H_V $
+
+ Rev 1.6 03 Mar 1993 10:21:16 chrish
+Put back #define launcher 114 and #ifdef for CAYMAN NT.
+
+ Rev 1.5 18 Feb 1993 15:18:34 chrish
+Added #define IDRI_LAUNCHER for CAYMAN
+
+ Rev 1.4 04 Oct 1992 19:47:40 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.3 30 Mar 1992 15:19:04 JOHNWT
+DLL res conversion
+
+ Rev 1.2 12 Feb 1992 13:31:44 ROBG
+Deleted IDD_LCH_ACTIVEJOB and IDD_LCH_LB1RIGHT.
+
+ Rev 1.1 13 Dec 1991 10:44:38 ROBG
+Modified to reflect JOB and SCHEDULE queues.
+
+ Rev 1.0 14 Oct 1991 14:14:56 ROBG
+Initial revision.
+
+
+****************************************************************************/
+
+#ifndef ldialogs_h
+#define ldialogs_h
+
+#define IDD_LCHRUNJOB 90
+#define IDD_LCHSCHEDULE 91
+
+#define IDD_LCH_SCHEDULE 101
+
+#define IDD_LCH_JOBNAME 110
+#define IDD_LCH_HOURS 111
+#define IDD_LCH_MINUTES 112
+
+#define IDD_LCH_TIMECNT 118
+
+#define IDD_LCH_NODELAY 130
+#define IDD_LCH_SCHDELAY 131
+#define IDD_LCH_PUTONHOLD 132
+
+#define IDD_LCH_HOLDBUTTON 108
+#define IDD_LCH_UNHOLDBUTTON 115
+#define IDD_LCH_EMPTYQUEUE 102
+#define IDD_LCH_LABELSTATUS 140
+#define IDD_LCH_LABELSCRIPT 104
+#define IDD_LCH_LABELNEXTDATE 142
+#define IDD_LCH_HELPBUTTON 106
+#define IDD_LCH_SKIPBUTTON 107
+
+#ifdef CAYMAN // chs: 03-03-93
+ #define IDRI_LAUNCHER 114 // chs: 03-03-93
+#else // chs: 03-03-93
+ #define launcher 114 // chs: 03-03-93
+#endif // chs: 03-03-93
+
+#define IDD_LCHCURTIME 116
+
+#endif
+
+
diff --git a/private/utils/ntbackup/inc/lis.h b/private/utils/ntbackup/inc/lis.h
new file mode 100644
index 000000000..ef6099e00
--- /dev/null
+++ b/private/utils/ntbackup/inc/lis.h
@@ -0,0 +1,94 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: lis.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+ Location: BE_PUBLIC
+
+
+ $Log: N:/LOGFILES/LIS.H_V $
+ *
+ * Rev 1.7 09 Jun 1993 15:22:40 MIKEP
+ * enable c++
+ *
+ * Rev 1.6 23 Mar 1992 14:25:52 GREGG
+ * Added BOOLEAN rewind_sdrv to GETVCB structure.
+ *
+ * Rev 1.5 07 Nov 1991 14:14:36 GREGG
+ * BIGWHEEL - 8200sx - Removed cat_enabled boolean from lis struct.
+ * Note: A re-design eliminated the need for the 1.4 change. However, v1.4
+ * was released for public consumption (first release of BigWheel) a.d must,
+ * therefore, remain in the logfile.
+ *
+ * Rev 1.4 07 Nov 1991 14:08:12 GREGG
+ * BIGWHEEL - 8200sx - Added cat_enabled boolean to lis struct.
+ *
+ * Rev 1.3 21 Jun 1991 08:43:42 STEVEN
+ * new config unit
+ *
+ * Rev 1.2 07 Jun 1991 09:01:34 JOHNW
+ * Moved typedef of TPOS_HANDLER to tpos.h
+ *
+ * Rev 1.1 24 May 1991 14:59:46 STEVEN
+ * removed un-necessary entries from the lis structure
+ *
+ * Rev 1.0 09 May 1991 13:31:52 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef _lis_h_
+#define _lis_h_
+
+#include "fsys.h"
+#include "bsdu.h"
+#include "tpos.h"
+#include "abort.h"
+
+typedef INT16 ( *MSG_HANDLER )( UINT16 msg, INT32 pid, BSD_PTR bsd_ptr, FSYS_HAND fsh, TPOS_PTR tpos, ... ) ;
+
+/* Macros for Abort Flag */
+
+#define LP_GetAbortFlag( lis_ptr ) ( *((lis_ptr)->abort_flag_ptr) )
+#define LP_SetAbortFlag( lis_ptr , v ) ( *((lis_ptr)->abort_flag_ptr) = v )
+#define LP_AbortFlagIsSet( lis_ptr ) ( *((lis_ptr)->abort_flag_ptr) != CONTINUE_PROCESSING )
+
+typedef struct LIS *LIS_PTR;
+typedef struct LIS {
+ TPOS_HANDLER tape_pos_handler ;
+ MSG_HANDLER message_handler ;
+ VOID_PTR ui_cfg_ptr ; /* user interface config */
+ INT16 oper_type ; /* current operation type */
+ INT16 mode ; /* this is passed back to the message handler */
+ UINT32 pid ; /* this is passed back to the message handler */
+ BOOLEAN auto_det_sdrv ; /* indicator for whether to auto-determine starting tape drive */
+
+ BSD_PTR curr_bsd_ptr ; /* set by the loops for the user interface tape positioning routine */
+ INT8_PTR abort_flag_ptr ; /* address of the global abort flag */
+ struct VM_STR *vmem_hand ; /* space for temporary file. e.g. Virtual Memory */
+ struct BSD_LIST *bsd_list; /* copy of bsd_list for tools to use */
+} LIS ;
+
+
+/*
+ LP_GetVCB interface structure
+*/
+
+
+typedef struct GETVCB *GETVCB_PTR;
+typedef struct GETVCB {
+ UINT32 tape_fid ; /* input */
+ UINT16 tape_seq_num ; /* input */
+ UINT16 backup_set_num ; /* input */
+ struct BE_CFG *cfg ; /* input */
+ FSYS_HAND fsys_handle ;
+ BOOLEAN rewind_sdrv ;
+} GETVCB;
+
+#endif
diff --git a/private/utils/ntbackup/inc/log.h b/private/utils/ntbackup/inc/log.h
new file mode 100644
index 000000000..ccc8ddef6
--- /dev/null
+++ b/private/utils/ntbackup/inc/log.h
@@ -0,0 +1,335 @@
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: log.h
+
+ Description: This file contains the structures, definitions, macros,
+ and function prototypes for the Maynstream GUI
+ Log File Manager (LOG).
+
+ $Log: G:/UI/LOGFILES/LOG.H_V $
+
+ Rev 1.18 04 Jun 1993 10:16:46 DARRYLP
+Upped our viewable log limit to 65530.
+
+ Rev 1.17 02 May 1993 16:55:08 MIKEP
+add call to support log files base name changing.
+
+ Rev 1.16 29 Mar 1993 11:03:02 TIMN
+Added protos for getting only the catalog path or filename
+
+ Rev 1.15 14 Jan 1993 16:23:22 DAVEV
+chg LPLONG to INT32_PTR
+
+ Rev 1.14 01 Nov 1992 16:31:08 DAVEV
+Unicode changes
+
+ Rev 1.13 04 Oct 1992 19:47:42 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.12 28 Jul 1992 14:56:48 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.11 09 Mar 1992 14:08:10 ROBG
+changed
+
+ Rev 1.10 09 Mar 1992 13:49:46 ROBG
+changed
+
+ Rev 1.9 09 Mar 1992 10:46:06 ROBG
+added LOG_NUMHEADERLINES
+
+ Rev 1.8 09 Mar 1992 09:12:42 ROBG
+added LOG_Clearblocks
+
+ Rev 1.7 06 Mar 1992 16:32:14 ROBG
+changed
+
+ Rev 1.6 02 Mar 1992 10:46:36 ROBG
+changed
+
+ Rev 1.5 02 Mar 1992 10:44:14 ROBG
+unchanged
+
+ Rev 1.4 25 Feb 1992 21:47:54 GLENN
+Added LOG_SetCurrentLogName().
+
+ Rev 1.3 21 Feb 1992 15:02:36 ROBG
+More changes
+
+ Rev 1.2 13 Jan 1992 09:51:54 ROBG
+Deleted LOG_PREFIX and LOG_EXTENSION.
+
+ Rev 1.1 05 Dec 1991 17:33:34 GLENN
+Added deinit code
+
+ Rev 1.0 20 Nov 1991 19:38:26 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+
+#ifndef _LOG_H
+
+#define _LOG_H
+
+#define NUM_DEST_TYPES 5
+
+#define LOG_MAXLOGFILES 100
+#define LOG_FILEEXISTS 0
+#define LOG_NUMHEADERLINES 4
+#define LOG_MAXRECS 65530
+
+#define MAX_LOGNAME_LEN 256
+
+#define LOG_FILENAMELENGTH (MAX_UI_FILENAME_SIZE )
+#define LOG_DATETIMELENGTH 50 // 50 to leave room for additional text.
+
+#define LINE_PRINTER TEXT("LPT1")
+#define VERIFY_LOG TEXT("VERIFY")
+#define SKIPPED_LOG TEXT("SKIPPED")
+#define EXCLUDE_LOG TEXT("EXCLUDE")
+#define CORRUPT_LOG TEXT("CORRUPT")
+#define DEBUG_LOG TEXT("DEBUG")
+#define BKS_EXT TEXT(".BKS")
+#define TKS_EXT TEXT(".TKS")
+#define RSS_EXT TEXT(".RSS")
+#define LST_EXT TEXT(".LST")
+#define LOG_EXT TEXT(".LOG")
+
+/* Output file destinations */
+
+enum{
+ LOGGING_FILE, /* log file type */
+ CORRUPT_FILE, /* log file type */ /* <-- maintain these contiguous */
+ DEBUG_LOG_FILE, /* log file type */
+ SKIPPED_FILE, /* script file type */
+ VERIFY_FILE /* script file type */
+} LOG_DESTS ;
+
+
+/* Message types passed to lresprintf */
+enum{
+ LOG_START,
+ LOG_MSG,
+ LOG_ERROR,
+ LOG_WARNING,
+ LOG_DIRECTORY,
+ LOG_FILE,
+ LOG_STREAM,
+ LOG_END
+} LOG_MESSAGES ;
+
+typedef struct log_dest {
+ FILE *fh; /* associated file handle */
+ INT16 mode ; /* open mode for file, -1=config determine,1=overwrite mode, 2=append */
+} LOG_DEST, *LOG_DEST_PTR ;
+
+extern LOG_DEST output_dest[] ;
+
+// DATA STRUCTURES
+
+typedef struct {
+
+ UCHAR szFileName[ LOG_FILENAMELENGTH ] ;
+ UCHAR szDateTime[ LOG_DATETIMELENGTH ] ;
+ BYTE bTag ;
+ LONG lSize ;
+ UINT16 iDate ;
+ UINT16 iTime ;
+ Q_ELEM pQElem ;
+
+} DS_LOGITEM, *PDS_LOGITEM, *LOGITEM_PTR ;
+
+typedef struct {
+
+ INT16 nLineNo ;
+ LPSTR szLine ; // Dynamically allocated from global heap.
+ BYTE bTag ;
+ Q_ELEM pQElem ;
+
+} DS_LOGVIEWITEM, *PDS_LOGVIEWITEM, *LOGVIEWITEM_PTR ;
+
+
+// Macros for list of log files.
+
+#define LOG_GetFileName( x ) ( (x)->szFileName )
+#define LOG_SetFileName( x, y ) ( lstrcpy ( (x)->szFileName, (y) ) )
+
+#define LOG_GetDateTime( x ) ( (x)->szDateTime )
+#define LOG_SetDateTime( x, y ) ( lstrcpy ( (x)->szDateTime, (y) ) )
+
+#define LOG_GetItemSize( x ) ( (x)->lSize )
+#define LOG_SetItemSize( x, y ) ( (x)->lSize = (y) )
+
+#define LOG_GetItemDate( x ) ( (x)->iDate )
+#define LOG_SetItemDate( x, y ) ( (x)->iDate = (y) )
+
+#define LOG_GetItemTime( x ) ( (x)->iTime )
+#define LOG_SetItemTime( x, y ) ( (x)->iTime = (y) )
+
+// Macros for viewing a log file.
+
+#define LOG_GetViewLineNo( x ) ( (x)->nLineNo )
+#define LOG_SetViewLineNo( x, y ) ( (x)->nLineNo = (y) )
+
+#define LOG_GetViewLine( x ) ( (x)->szLine )
+#define LOG_SetViewLine( x, y ) ( lstrcpy ( (x)->szLine, (y) ) )
+
+// Macros for both lists.
+
+#define LOG_GetTagField( x ) ( (x)->bTag )
+#define LOG_SetTagField( x, y ) ( (x)->bTag = (y) )
+
+#define LOG_GetQElem( x ) ( (x)->pQElem )
+#define LOG_SetQElem( x, y ) ( (x)->pQElem = (y) )
+
+// Log View window
+
+typedef struct {
+
+ LPSTR pszBuffer ;
+ HFONT hFont ;
+ FILE *fp ;
+ INT cxChar ;
+ INT cxCaps ;
+ INT cyChar ;
+ INT cxClient ;
+ INT cyClient ;
+ INT nMaxWidth ;
+ INT nVscrollPos ;
+ INT nVscrollMax ;
+ INT nHscrollPos ;
+ INT nHscrollMax ;
+ INT nLines ;
+ INT nBlocksMax ;
+ INT nBlocksUsed ;
+ INT nRecsPerBlock ;
+ INT nMaxStringLen ;
+ INT nPaintBeg ;
+ INT nPaintEnd ;
+ INT nRecsPerTrack ;
+ INT nTrackMax ;
+ LONG lTotalLines ;
+ LONG lTopLine ;
+ INT32_PTR pLogArray ;
+ CHAR szFileName [ MAX_UI_FULLPATH_SIZE ] ;
+
+} DLM_LOGITEM, far *DLM_LOGITEM_PTR ;
+
+#define L_GetVisibleTopLine( x ) ( (x)->lTopLine )
+#define L_SetVisibleTopLine( x, y ) ( (x)->lTopLine = (y) )
+
+#define L_GetTotalLines( x ) ( (x)->lTotalLines )
+#define L_SetTotalLines( x, y ) ( (x)->lTotalLines = (y) )
+
+#define L_GetTrackMax( x ) ( (x)->nTrackMax )
+#define L_SetTrackMax( x, y ) ( (x)->nTrackMax = (y) )
+
+#define L_GetRecsPerTrack( x ) ( (x)->nRecsPerTrack )
+#define L_SetRecsPerTrack( x, y ) ( (x)->nRecsPerTrack = (y) )
+
+#define L_GetPaintBeg( x ) ( (x)->nPaintBeg )
+#define L_SetPaintBeg( x, y ) ( (x)->nPaintBeg = (y) )
+
+#define L_GetPaintEnd( x ) ( (x)->nPaintEnd )
+#define L_SetPaintEnd( x, y ) ( (x)->nPaintEnd = (y) )
+
+#define L_GetCharWidth( x ) ( (x)->cxChar )
+#define L_SetCharWidth( x, y ) ( (x)->cxChar = (y) )
+
+#define L_GetBuffer( x ) ( (x)->pszBuffer )
+#define L_SetBuffer( x, y ) ( lstrcpy ( (x)->pszBuffer, (y) ) )
+
+#define L_GetFont( x ) ( (x)->hFont )
+#define L_SetFont( x, y ) ( (x)->hFont = (y) )
+
+#define L_GetFileName( x ) ( (x)->szFileName )
+#define L_SetFileName( x, y ) ( lstrcpy ( (x)->szFileName, (y) ) )
+
+#define L_GetFilePtr( x ) ( (x)->fp )
+#define L_SetFilePtr( x, y ) ( (x)->fp = (y) )
+
+#define L_GetCharWidth( x ) ( (x)->cxChar )
+#define L_SetCharWidth( x, y ) ( (x)->cxChar = (y) )
+
+#define L_GetCharWidthCaps( x ) ( (x)->cxCaps )
+#define L_SetCharWidthCaps( x, y ) ( (x)->cxCaps = (y) )
+
+#define L_GetCharHeight( x ) ( (x)->cyChar )
+#define L_SetCharHeight( x, y ) ( (x)->cyChar = (y) )
+
+#define L_GetClientWidth( x ) ( (x)->cxClient )
+#define L_SetClientWidth( x, y ) ( (x)->cxClient = (y) )
+
+#define L_GetClientHeight( x ) ( (x)->cyClient )
+#define L_SetClientHeight( x, y ) ( (x)->cyClient = (y) )
+
+#define L_GetMaxWidth( x ) ( (x)->nMaxWidth )
+#define L_SetMaxWidth( x, y ) ( (x)->nMaxWidth = (y) )
+
+#define L_GetVscrollPos( x ) ( (x)->nVscrollPos )
+#define L_SetVscrollPos( x, y ) ( (x)->nVscrollPos = (y) )
+
+#define L_GetVscrollMax( x ) ( (x)->nVscrollMax )
+#define L_SetVscrollMax( x, y ) ( (x)->nVscrollMax = (y) )
+
+#define L_GetHscrollPos( x ) ( (x)->nHscrollPos )
+#define L_SetHscrollPos( x, y ) ( (x)->nHscrollPos = (y) )
+
+#define L_GetHscrollMax( x ) ( (x)->nHscrollMax )
+#define L_SetHscrollMax( x, y ) ( (x)->nHscrollMax = (y) )
+
+#define L_GetNumOfLines( x ) ( (x)->nLines )
+#define L_SetNumOfLines( x, y ) ( (x)->nLines = (LONG) (y) )
+
+#define L_GetNumOfUsedBlocks( x ) ( (x)->nBlocksUsed )
+#define L_SetNumOfUsedBlocks( x, y ) ( (x)->nBlocksUsed = (y) )
+
+#define L_GetMaxNumOfBlocks( x ) ( (x)->nBlocksMax )
+#define L_SetMaxNumOfBlocks( x, y ) ( (x)->nBlocksMax = (y) )
+
+#define L_GetArrayPtr( x ) ( (x)->pLogArray )
+#define L_SetArrayPtr( x, y ) ( (x)->pLogArray = (INT32_PTR) (y) )
+
+#define L_GetBlockPtr( x, i ) ( (INT32_PTR) ( (x)->pLogArray[ i ] ) )
+#define L_SetBlockPtr( x, i, y ) ( (x)->pLogArray[i] = (y) )
+
+#define L_GetRecsPerBlock( x ) ( (x)->nRecsPerBlock )
+#define L_SetRecsPerBlock( x, y ) ( (x)->nRecsPerBlock = (y) )
+
+#define L_RecNumber( x ) ( L_GetTotalLines( x ) % L_GetRecsPerBlock( x ) )
+#define L_NewBlock( x ) ( L_RecNumber( x ) == 0 )
+
+#define L_GetMaxStringLen( x ) ( (x)->nMaxStringLen )
+#define L_SetMaxStringLen( x, y ) ( (x)->nMaxStringLen = (y) )
+
+
+// FUNCTION PROTOTYPES
+
+VOID LOG_BaseNameChanged ( VOID );
+VOID LOG_Init ( VOID );
+VOID LOG_Deinit ( VOID );
+VOID_PTR LOG_GetLogFileName ( VOID_PTR, LPSTR );
+VOID LOG_Refresh ( VOID );
+VOID LOG_GenerateLogFileName ( LPSTR pDest ) ;
+VOID LOG_GetCurrentLogPathOnly ( CHAR_PTR path ) ;
+LPSTR LOG_GetCurrentLogNameOnly ( VOID ) ;
+LPSTR LOG_GetCurrentLogName ( VOID ) ;
+LPSTR LOG_GetCurrentViewLogName ( VOID ) ;
+VOID LOG_GetCurrentTime ( LPSTR szDate, LPSTR szTime ) ;
+VOID LOG_SetCurrentLogName ( LPSTR );
+VOID LOG_ClearBlocks ( DLM_LOGITEM_PTR pDlm ) ;
+VOID LOG_GetViewHdrLine ( DLM_LOGITEM_PTR pDlm , INT i , LPSTR pszResult ) ;
+
+// OLD LOG FUNCTION PROTOTYPES
+
+VOID lprintf ( INT file, CHAR_PTR fmt, ... ) ;
+VOID lresprintf( INT file, INT message, ... ) ;
+VOID lvprintf ( INT file, CHAR_PTR fmt, va_list arg_ptr) ;
+BOOLEAN LogFileExists( INT index ) ;
+
+#define UI_LoggingActive( log_num ) ( output_dest[ log_num ].fh )
+
+#endif
diff --git a/private/utils/ntbackup/inc/loginpw.h b/private/utils/ntbackup/inc/loginpw.h
new file mode 100644
index 000000000..01698bcff
--- /dev/null
+++ b/private/utils/ntbackup/inc/loginpw.h
@@ -0,0 +1,35 @@
+
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1992
+
+ Name: loginpw.h
+
+ Description: Contains control ids for items in password database dialog
+
+ $Log: G:/UI/LOGFILES/LOGINPW.H_V $
+
+ Rev 1.1 04 Oct 1992 19:47:44 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.0 06 Apr 1992 04:05:02 CHUCKB
+Initial revision.
+
+*****************************************************/
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_PWDB_PASSWORD 43
+#else
+#include "dlg_ids.h"
+#endif
+
+
+/* login pw for pwdb */
+
+#define IDD_PWDB_PWTEXT 287
+#define IDD_PWDB_NEWPW 288
+#define IDD_PWDB_PW 289
+#define IDD_PWDB_NEWPWTEXT 291
+#define IDD_PWDB_CONFIRM 290
+#define IDD_PWDB_CONFTEXT 293
+
diff --git a/private/utils/ntbackup/inc/loop_prv.h b/private/utils/ntbackup/inc/loop_prv.h
new file mode 100644
index 000000000..2ff315370
--- /dev/null
+++ b/private/utils/ntbackup/inc/loop_prv.h
@@ -0,0 +1,368 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: loop_prv.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: private loops header file
+
+ Location:
+
+
+ $Log: T:\logfiles\loop_prv.h_v $
+ *
+ * Rev 1.23.1.0 28 Jan 1994 11:14:04 GREGG
+ * More Warning Fixes
+ *
+ * Rev 1.23 26 Jul 1993 14:52:12 CARLS
+ * added LP_MsgNotDeleted & LP_MsgCommFailure macros
+ *
+ * Rev 1.22 13 May 1993 13:45:40 BARRY
+ * Added macro for LP_MsgRestoredActive for NT.
+ *
+ * Rev 1.21 31 Mar 1993 08:57:34 MARILYN
+ * added the prototype for LP_MsgNoChecksum
+ *
+ * Rev 1.20 01 Mar 1993 17:40:14 MARILYN
+ * added a prototype for LP_TapeVerifyOBJ
+ *
+ * Rev 1.19 18 Jan 1993 12:36:34 STEVEN
+ * added stuff for locked files
+ *
+ * Rev 1.18 20 Nov 1992 10:38:28 STEVEN
+ * added suport for continue VCB message
+ *
+ * Rev 1.17 04 Nov 1992 09:28:10 STEVEN
+ * fix initial receive
+ *
+ * Rev 1.16 03 Nov 1992 10:08:56 STEVEN
+ * change the way we skip data
+ *
+ * Rev 1.15 13 Oct 1992 17:20:20 STEVEN
+ * save old tf message
+ *
+ * Rev 1.14 16 Sep 1992 16:54:46 STEVEN
+ * added support for stream info struct for Tpfmt
+ *
+ * Rev 1.13 10 Jul 1992 16:33:00 STEVEN
+ * Added temp path buffer ptr.
+ *
+ * Rev 1.12 10 Jun 1992 15:53:32 TIMN
+ * Changed CHAR data to INT8 for UNIC
+ *
+ * Rev 1.11 30 Mar 1992 14:44:00 NED
+ * added Large Directory message to trunk
+ *
+ * Rev 1.10 11 Mar 1992 10:07:28 STEVEN
+ * added member to PDL q head for GTNXTDLE
+ *
+ * Rev 1.9 28 Feb 1992 10:32:06 GREGG
+ * Added struct elem set_opened and changed some protos.
+ *
+ * Rev 1.8 06 Nov 1991 18:27:26 GREGG
+ * BIGWHEEL - 8200sx - Added cat_enabled to lp structure.
+ *
+ * Rev 1.7 18 Oct 1991 13:41:20 STEVEN
+ * TRICYCLE-added function for end of varible length file
+ *
+ * Rev 1.6 18 Oct 1991 13:38:56 STEVEN
+ * BIGWHEEL-added disk block to prompt for restore over exist
+ *
+ * Rev 1.5 27 Jun 1991 13:03:40 STEVEN
+ * unnecessary parm to ReceiveData
+ *
+ * Rev 1.4 24 Jun 1991 17:10:36 STEVEN
+ * remove date time from StartBS
+ *
+ * Rev 1.3 17 Jun 1991 15:24:10 CARLS
+ * LP_PadData is called from lptools.c
+ *
+ * Rev 1.2 13 Jun 1991 14:55:28 STEVEN
+ * LBA now in virtual memory
+ *
+ * Rev 1.1 24 May 1991 14:58:18 STEVEN
+ * fixes for new Getnext
+ *
+ * Rev 1.0 09 May 1991 13:32:16 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef _loop_prv_h_
+#define _loop_prv_h_
+
+#include "tfldefs.h"
+#include "bsdu_str.h"
+
+/* loop environment structure */
+
+typedef struct {
+ UINT16 memory_allocated ;
+ UINT16 buffer_size ;
+ UINT16 buffer_used ;
+ INT8_PTR buffer ;
+} DATA_FRAGMENT, *DATA_FRAGMENT_PTR ;
+
+typedef struct {
+ struct VM_STR *vm_hdl ;
+ VOID_PTR pdl_head ;
+ VOID_PTR vm_last_elem ;
+} PDL_Q_HEAD, *PDL_HAND ;
+
+
+typedef struct {
+ LIS_PTR lis_ptr ; /* pointer to loop interface structure */
+ GENERIC_DLE_PTR curr_dle ;
+ FSYS_HAND curr_fsys ; /* current fsys_hand */
+ BOOLEAN blk_is_empty ;
+ INT16 last_tape_message ;
+ INT16 initial_tape_buf_used ;
+ BOOLEAN ignore_data_for_ddb ;
+ DBLK_PTR empty_blk ;
+ DBLK_PTR curr_blk ;
+ DBLK_PTR curr_ddb ;
+ DBLK dblk1 ; /* these three blocks are */
+ DBLK dblk2 ; /* pointed to by the above */
+ DBLK dblk3 ; /* three pointers. */
+ FILE_HAND *f_hand ;
+ RR rr ;
+ TPOS tpos ;
+ UINT16 channel ;
+ DATE_TIME backup_dt ;
+ INT8_PTR very_buff ; /* verify buffer */
+ BOOLEAN set_opened ; /* see lp_tdir.c for usage */
+
+ /* get next special variables */
+ INT32 seq_num ;
+ BOOLEAN get_spcl ;
+ BOOLEAN after_bs ;
+ BOOLEAN start_new_dir ;
+ BOOLEAN get_next_first_time ;
+ BOOLEAN get_first_file ;
+ BOOLEAN proc_curr_dir ;
+ BOOLEAN send_saved_block ;
+ PDL_HAND pdl_q ;
+ BOOLEAN tape_rd_error ; /* If this is true, check the error locus in the rr struct */
+
+ /* during restore and verify operations indicates whether or not to process FDBs from tape */
+ INT16 ddb_create_error ;
+
+ /* used for fast file restore */
+ BOOLEAN ffr_inited;
+ INT16 ffr_state;
+ struct FSE *ffr_last_fse;
+ LBA_ELEM ffr_last_lba;
+ struct FSE *tgt_info ;
+ DBLK_PTR saved_ddb ;
+
+ BOOLEAN cat_enabled ;
+
+ INT8_PTR newpath_buf ; /* internaly used by gtnxttpe for target path */
+ UINT16 newpath_buf_sz ; /* internaly used by gtnxttpe for target path */
+
+ UINT32 current_stream_id ;
+ UINT64 current_stream_size ;
+ FILE_HAND file_hand ;
+ INT8_PTR buf_start ;
+ UINT16 read_size ;
+ UINT16 blk_size ;
+ BOOLEAN corrupt_file ;
+
+} LP_ENV, *LP_ENV_PTR ;
+
+/* defines for path comparison */
+#define PATH_BEFORE -1
+#define PATH_AFTER 1
+#define PATH_EQUAL 0
+
+/* dpath structure */
+typedef struct {
+ INT16 path_size ;
+ CHAR_PTR path_ptr ;
+} DPATH, *DPATH_PTR ;
+
+/* tape dir structure */
+typedef struct t_dir {
+ struct t_dir *next_dir ;
+ struct t_item *first_item ;
+ struct t_item *last_item ;
+ DPATH dir_name ;
+} T_DIR, *T_DIR_PTR ;
+
+/* tape file structure */
+typedef struct t_item {
+ struct t_item *next_item ;
+ DBLK_PTR blk ;
+} T_ITEM, *T_ITEM_PTR ;
+
+/* defines for verify */
+#define LOOP_VERIFY_BUFFER 1024*10
+
+/* Macros */
+
+#define LP_SkipData( lp ) ( ( lp )->rr.filter_to_use = TF_SKIP_ALL_DATA )
+#define LP_SkipStream( lp ) ( ( lp )->rr.filter_to_use = TF_SKIP_DATA_STREAM )
+
+/* Macros for calling message handler */
+
+/* general messages */
+#define LP_MsgStartOP( pid, bsd_ptr, fsys, tpos )\
+ ( lp->lis_ptr->message_handler( MSG_START_OPERATION, pid, bsd_ptr, fsys, tpos ) )
+
+#define LP_MsgEndOP( pid, bsd_ptr, fsys, tpos )\
+ ( lp->lis_ptr->message_handler( MSG_END_OPERATION, pid, bsd_ptr, fsys, tpos ) )
+
+#define LP_MsgStartBS( pid, bsd_ptr, fsys, tpos, vcb )\
+ ( lp->lis_ptr->message_handler( MSG_START_BACKUP_SET, pid, bsd_ptr, fsys, tpos, vcb ) )
+
+#define LP_MsgEndBS( pid, bsd_ptr, fsys, tpos )\
+ ( lp->lis_ptr->message_handler( MSG_END_BACKUP_SET, pid, bsd_ptr, fsys, tpos ) )
+
+/* logging messages */
+#define LP_MsgLogBlock( pid, bsd_ptr, fsys, tpos, dblk_ptr )\
+ ( lp->lis_ptr->message_handler( MSG_LOG_BLOCK, pid, bsd_ptr, fsys, tpos, dblk_ptr ) )
+
+#define LP_MsgLogStream( pid, bsd_ptr, fsys, tpos, string )\
+ ( lp->lis_ptr->message_handler( MSG_LOG_STREAM_NAME, pid, bsd_ptr, fsys, tpos, string ) )
+
+
+#define LP_MsgContinueVCB( pid, bsd_ptr, fsys, tpos, dblk_ptr )\
+ ( lp->lis_ptr->message_handler( MSG_CONT_VCB, pid, bsd_ptr, fsys, tpos, dblk_ptr ) )
+
+/* statistics messages */
+#define LP_MsgBlockProcessed( pid, bsd_ptr, fsys, tpos, dblk_ptr )\
+ ( lp->lis_ptr->message_handler( MSG_BLOCK_PROCESSED, pid, bsd_ptr, fsys, tpos, dblk_ptr ) )
+
+#define LP_MsgBytesProcessed( pid, bsd_ptr, fsys, tpos, byte_count )\
+ ( lp->lis_ptr->message_handler( MSG_BYTES_PROCESSED, pid, bsd_ptr, fsys, tpos, byte_count ) )
+
+#define LP_MsgBlockInuse( pid, bsd_ptr, fsys, tpos, dblk_ptr, ddb_dblk_ptr )\
+ ( lp->lis_ptr->message_handler( MSG_BLOCK_INUSE, pid, bsd_ptr, fsys, tpos, dblk_ptr, ddb_dblk_ptr ) )
+
+#define LP_MsgBlockSkipped( pid, bsd_ptr, fsys, tpos, dblk_ptr, ddb_dblk_ptr )\
+ ( lp->lis_ptr->message_handler( MSG_BLOCK_SKIPPED, pid, bsd_ptr, fsys, tpos, dblk_ptr, ddb_dblk_ptr ) )
+
+#define LP_MsgBytesSkipped( pid, bsd_ptr, fsys, tpos, byte_count )\
+ ( lp->lis_ptr->message_handler( MSG_BYTES_SKIPPED, pid, bsd_ptr, fsys, tpos, byte_count ) )
+
+#define LP_MsgBlockBad( pid, bsd_ptr, fsys, tpos, dblk_ptr, ddb_dblk_ptr )\
+ ( lp->lis_ptr->message_handler( MSG_BLOCK_BAD, pid, bsd_ptr, fsys, tpos, dblk_ptr, ddb_dblk_ptr ) )
+
+#define LP_MsgBytesBad( pid, bsd_ptr, fsys, tpos, byte_count )\
+ ( lp->lis_ptr->message_handler( MSG_BYTES_BAD, pid, bsd_ptr, fsys, tpos, byte_count ) )
+
+#define LP_MsgBlockDeleted( pid, bsd_ptr, fsys, tpos, dblk_ptr )\
+ ( lp->lis_ptr->message_handler( MSG_BLOCK_DELETED, pid, bsd_ptr, fsys, tpos, dblk_ptr ) )
+
+#define LP_MsgBytesDeleted( pid, bsd_ptr, fsys, tpos, byte_count )\
+ ( lp->lis_ptr->message_handler( MSG_BYTES_DELETED, pid, bsd_ptr, fsys, tpos, byte_count ) )
+
+#define LP_MsgTapeStats( pid, bsd_ptr, fsys, tpos )\
+ ( lp->lis_ptr->message_handler( MSG_TAPE_STATS, pid, bsd_ptr, fsys, tpos ) )
+
+#define LP_MsgStartClock( pid, bsd_ptr, fsys, tpos )\
+ ( lp->lis_ptr->message_handler( MSG_START_CLOCK, pid, bsd_ptr, fsys, tpos ) )
+
+#define LP_MsgStopClock( pid, bsd_ptr, fsys, tpos )\
+ ( lp->lis_ptr->message_handler( MSG_STOP_CLOCK, pid, bsd_ptr, fsys, tpos ) )
+
+#define LP_MsgRestoredActive( pid, bsd_ptr, fsys, tpos, ddb_dblk_ptr, dblk_ptr )\
+ ( lp->lis_ptr->message_handler( MSG_RESTORED_ACTIVE, pid, bsd_ptr, fsys, tpos, ddb_dblk_ptr, dblk_ptr ) )
+
+/* error message */
+#define LP_MsgError( pid, bsd_ptr, fsys, tpos, error, ddb_dblk_ptr, dblk_ptr, strm_id )\
+ ( lp->lis_ptr->message_handler( MSG_TBE_ERROR, pid, bsd_ptr, fsys, tpos, error, ddb_dblk_ptr, dblk_ptr, strm_id ) )
+
+/* error message for Attribute Read Error */
+#define LP_MsgAttrReadError( pid, bsd_ptr, fsys, tpos, blk_ptr)\
+ (lp->lis_ptr->message_handler(MSG_ATTR_READ_ERROR, pid, bsd_ptr, fsys, tpos, blk_ptr) )
+
+/* verify messages */
+#define LP_MsgBlkNotFound( pid, bsd_ptr, fsys, tpos, tape_dblk_ptr, ddb_dblk_ptr )\
+ ( lp->lis_ptr->message_handler( MSG_BLK_NOT_FOUND, pid, bsd_ptr, fsys, tpos, tape_dblk_ptr, ddb_dblk_ptr ) )
+#define LP_MsgBlkDifferent( pid, bsd_ptr, fsys, tpos, tape_dblk_ptr, disk_dblk_ptr, os_flag, os_err )\
+ ( lp->lis_ptr->message_handler( MSG_BLK_DIFFERENT, pid, bsd_ptr, fsys, tpos,\
+ tape_dblk_ptr, disk_dblk_ptr, os_flag, os_err ) )
+#define LP_MsgLogDifference( pid, bsd_ptr, fsys, tpos, dblk_ptr, ddb_dblk_ptr, strm_id, os_err )\
+ ( lp->lis_ptr->message_handler( MSG_LOG_DIFFERENCE, pid, bsd_ptr, fsys, tpos, dblk_ptr, ddb_dblk_ptr, strm_id, os_err ) )
+
+/* misc message */
+#define LP_MsgIdle( pid, bsd_ptr, fsys, tpos )\
+ ( lp->lis_ptr->message_handler( MSG_IDLE, pid, bsd_ptr, fsys, tpos ) )
+#define LP_MsgOpenedInUse( pid, bsd_ptr, fsys, tpos, dblk_ptr )\
+ ( lp->lis_ptr->message_handler( MSG_IN_USE, pid, bsd_ptr, fsys, tpos, dblk_ptr ) )
+#define LP_MsgObjectInUse( pid, bsd_ptr, fsys, tpos, dblk_ptr, TryOpen, parm )\
+ ( lp->lis_ptr->message_handler( MSG_IN_USE_WAIT, pid, bsd_ptr, fsys, tpos, dblk_ptr, TryOpen, parm ) )
+#define LP_MsgPrompt( pid, bsd_ptr, fsys, tpos, type, dblk, ddblk )\
+ ( lp->lis_ptr->message_handler( MSG_PROMPT, pid, bsd_ptr, fsys, tpos, type, dblk, ddblk ) )
+#define LP_MsgEOM( pid, bsd_ptr, fsys, tpos, vcb_ptr, ddb_ptr, fdb_ptr, idb_ptr ) \
+ ( lp->lis_ptr->message_handler( MSG_EOM, pid, bsd_ptr, fsys, tpos, vcb_ptr, ddb_ptr, fdb_ptr, idb_ptr ) )
+#define LP_MsgRecDDB( pid, bsd_ptr, fsys, tpos )\
+ ( lp->lis_ptr->message_handler( MSG_ACK_DDB_RECOVERED, pid, bsd_ptr, fsys, tpos ) )
+#define LP_MsgRecFDB( pid, bsd_ptr, fsys, tpos )\
+ ( lp->lis_ptr->message_handler( MSG_ACK_FDB_RECOVERED, pid, bsd_ptr, fsys, tpos ) )
+#define LP_MsgDataLost( pid, bsd_ptr, fsys, tpos, file_offset, data_loss )\
+ ( lp->lis_ptr->message_handler( MSG_DATA_LOST, pid, bsd_ptr, fsys, tpos, file_offset, data_loss ) )
+#define LP_MsgLargeDirectory( pid, bsd_ptr, fsys, tpos )\
+ ( lp->lis_ptr->message_handler( MSG_LARGE_DIRECTORY, pid, bsd_ptr, fsys, tpos ) )
+#define LP_MsgNoChecksum( pid, bsd_ptr, fsys, tpos, dblk_ptr, ddb_dblk_ptr, os_err )\
+ ( lp->lis_ptr->message_handler( MSG_NO_CHECKSUM, pid, bsd_ptr, fsys, tpos, dblk_ptr, ddb_dblk_ptr, os_err ) )
+
+#define LP_MsgNotDeleted( pid, bsd_ptr, fsys, tpos, dblk_ptr )\
+ ( lp->lis_ptr->message_handler( MSG_NOT_DELETED, pid, bsd_ptr, fsys, tpos, dblk_ptr ) )
+
+#define LP_MsgCommFailure( pid, bsd_ptr, fsys, tpos, dblk_ptr, ddb_dblk_ptr, os_err )\
+ ( lp->lis_ptr->message_handler( MSG_COMM_FAILURE, pid, bsd_ptr, fsys, tpos, dblk_ptr, ddb_dblk_ptr, os_err ) )
+
+/* Tension Message handler interface */
+#define LP_MsgEndTens( oper_type )\
+ ( lp->lis_ptr->message_handler( MSG_END_BACKUP_SET, 0L, NULL, NULL, &lp->tpos, oper_type ) )
+
+/* routines to get the environment structure and initialize it */
+LP_ENV_PTR LP_GetLoopEnvironment( VOID ) ;
+VOID LP_DisposeLoopEnvironment( LP_ENV_PTR ) ;
+
+/* Backup private definitions */
+INT16 LP_BackupDLE( BSD_PTR bsd_ptr, LP_ENV_PTR lp_env_ptr,
+ UINT16 tfl_open_mode, INT16 channel_no, THW_PTR sdrv ) ;
+INT16 LP_BackupVCB( BSD_PTR bsd_ptr, LP_ENV_PTR lp_env_ptr ) ;
+INT16 LP_BackupOBJ( LP_ENV_PTR lp_env_ptr, DBLK_PTR blk_ptr, DATA_FRAGMENT_PTR frag_ptr ) ;
+
+/* Restore private definitions */
+INT16 LP_RestoreDLE( BSD_PTR bsd_ptr, LP_ENV_PTR lp_env_ptr,
+ BOOLEAN reuse_bsd, INT16 channel_no, THW_PTR sdrv ) ;
+INT16 LP_RestoreOBJ( LP_ENV_PTR lp_env_ptr, DBLK_PTR blk_ptr, DATA_FRAGMENT_PTR frag_ptr ) ;
+
+/* Verify private definitions */
+INT16 LP_VerifyDLE( BSD_PTR bsd_ptr, LP_ENV_PTR lp_env_ptr,
+ BOOLEAN reuse_bsd, INT16 channel_no, THW_PTR sdrv ) ;
+INT16 LP_VerifyOBJ( LP_ENV_PTR lp_env_ptr, DBLK_PTR blk_ptr, DATA_FRAGMENT_PTR frag_ptr ) ;
+
+/* Tape directory */
+INT16 LP_AddDirToTree( TAPE_DIR_PTR tape_dir_ptr, DPATH_PTR dir_ptr ) ;
+INT16 LP_AddBlockToTree( TAPE_DIR_PTR tape_dir_ptr, DBLK_PTR blk_ptr ) ;
+T_DIR_PTR LP_FindDir( TAPE_DIR_PTR tape_dir_ptr,
+ T_DIR_PTR start_dir_ptr, DPATH_PTR dir_ptr, INT16 num_levels ) ;
+
+/* Checksum verification of a tape */
+INT16 LP_TapeVerifyOBJ( LP_ENV_PTR lp, DBLK_PTR tape_dblk_ptr ) ;
+
+/* loop tools */
+INT16 LP_StartTPEDialogue( LP_ENV_PTR lp, BOOLEAN write ) ;
+INT16 LP_Send( LP_ENV_PTR lp, BOOLEAN data_flag ) ;
+INT16 LP_SendDataEnd( LP_ENV_PTR lp ) ;
+INT16 LP_FinishedOper( LP_ENV_PTR lp ) ;
+INT16 LP_ReceiveDBLK( LP_ENV_PTR lp ) ;
+INT16 LP_ReceiveData( LP_ENV_PTR lp, UINT32 amount_used ) ;
+INT16 LP_ProcessEOM( LP_ENV_PTR lp, UINT16 tf_message ) ;
+
+VOID LP_PadData( INT8_PTR buf, UINT32 count ) ;
+
+INT16 LP_CheckForOpen( UINT32 ) ;
+
+INT16 LP_CheckForReadLock( UINT32 ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/loops.h b/private/utils/ntbackup/inc/loops.h
new file mode 100644
index 000000000..0578f8d41
--- /dev/null
+++ b/private/utils/ntbackup/inc/loops.h
@@ -0,0 +1,85 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: loops.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+ Location: BE_PUBLIC
+
+
+ $Log: J:/LOGFILES/LOOPS.H_V $
+ *
+ * Rev 1.6 01 Mar 1993 17:39:54 MARILYN
+ * added a prototype for LP_Tape_Verify_Engine
+ *
+ * Rev 1.5 05 Feb 1993 22:32:06 MARILYN
+ * removed copy/move functionality
+ *
+ * Rev 1.4 09 Nov 1992 10:49:18 GREGG
+ * Added proto for LP_Tape_Cat_Engine.
+ *
+ * Rev 1.3 03 Nov 1992 19:32:20 DON
+ * incorporated marilyns changes for copy function
+ *
+ * Rev 1.2 05 Oct 1992 12:27:00 DON
+ * added macro for LOADER to get a lw_last_tpdrv
+ *
+ * Rev 1.1 16 Jul 1991 15:07:32 BARRY
+ * Removed prototype for LP_GetLBAList(). (This has been moved to the UI.)
+ *
+ * Rev 1.0 09 May 1991 13:32:12 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef _loops_h_
+#define _loops_h_
+
+#include "lis.h"
+#include "lp_msg.h"
+#include "fsys.h"
+#include "bsdu.h"
+#include "thw.h"
+
+typedef struct {
+ VOID_PTR lp ;
+ FSYS_HAND curr_fsys ;
+ BOOLEAN first_time ;
+ BOOLEAN last_time ;
+ BOOLEAN valid_save_block ;
+} TAPE_DIR, *TAPE_DIR_PTR ;
+
+extern THW_PTR lw_toc_tpdrv ;
+extern THW_PTR lw_last_tpdrv ;
+#define LP_LastTapeDrive() (THW_PTR)lw_last_tpdrv
+
+INT16 LP_Backup_Engine( LIS_PTR lis_ptr ) ;
+INT16 LP_Restore_Engine( LIS_PTR lis_ptr ) ;
+INT16 LP_Verify_Engine( LIS_PTR lis_ptr ) ;
+INT16 LP_Delete_Engine( LIS_PTR lis_ptr ) ;
+INT16 LP_Archive_Engine( LIS_PTR lis_ptr ) ;
+INT16 LP_Tension_Engine( LIS_PTR lis_ptr ) ;
+INT16 LP_Erase_Engine( LIS_PTR lis_ptr, BOOLEAN security_erase_flag ) ;
+INT16 LP_Format_Engine( LIS_PTR lis_ptr ) ;
+INT16 LP_List_Tape_Engine( LIS_PTR lis_ptr ) ;
+INT16 LP_Tape_Cat_Engine( LIS_PTR lis_ptr ) ;
+INT16 LP_Tension_Tape_Engine( LIS_PTR lis_ptr ) ;
+INT16 LP_Tape_Verify_Engine( LIS_PTR lis_ptr ) ;
+
+INT16 LP_GetVCB( GETVCB_PTR get_vcb_ptr, TPOS_HANDLER tpos_rout, THW_PTR tdrv_list, VOID_PTR ref ) ;
+INT16 LP_StartTapeDirectory( TAPE_DIR_PTR tape_dir_ptr, LIS_PTR lis_ptr, INT32 tape_id, INT16 tape_no, INT16 bno,
+ THW_PTR tdrv_list ) ;
+INT16 LP_EndTapeDirectory( TAPE_DIR_PTR tape_dir_ptr, BOOLEAN premature_user_end ) ;
+INT16 LP_ReadTape( TAPE_DIR_PTR tape_dir_ptr, BOOLEAN *valid_blk, DBLK_PTR dblk_ptr ) ;
+
+THW_PTR LP_DetermineStartingTPDrv( INT16 oper_type, BSD_PTR bsd_ptr, TPOS_PTR tpos, BOOLEAN auto_determine_sdrv ) ;
+VOID LP_DetermineCurrentTPDrv( BSD_PTR bsd_ptr, INT16 channel ) ;
+VOID LP_CloseSet( INT16 channel ) ;
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/lp_msg.h b/private/utils/ntbackup/inc/lp_msg.h
new file mode 100644
index 000000000..f2f021be0
--- /dev/null
+++ b/private/utils/ntbackup/inc/lp_msg.h
@@ -0,0 +1,183 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: lp_msg.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+ Location: BE_PUBLIC
+
+
+ $Log: N:\logfiles\lp_msg.h_v $
+ *
+ * Rev 1.9.1.0 04 Mar 1994 16:53:00 STEVEN
+ *
+ * Rev 1.9 26 Jul 1993 14:50:00 CARLS
+ * added MSG_NOT_DELETED & MSG_COMM_FAILURE
+ *
+ * Rev 1.8 13 May 1993 13:40:32 BARRY
+ * Added MSG_RESTORED_ACTIVE.
+ *
+ * Rev 1.7 31 Mar 1993 08:56:30 MARILYN
+ * added the msg MSG_NO_CHECKSUM
+ *
+ * Rev 1.6 05 Feb 1993 22:34:36 MARILYN
+ * removed copy/move functionality
+ *
+ * Rev 1.5 20 Nov 1992 10:39:58 STEVEN
+ * added suport for continue VCB message
+ *
+ * Rev 1.4 13 Nov 1992 18:16:50 ZEIR
+ * Ad'd LP_OPEN_SRC&DST_ERROR s
+ *
+ * Rev 1.3 06 Nov 1992 18:01:04 MARILYN
+ * Added new LP_ msg for source and destination the same for copy/move
+ *
+ * Rev 1.2 27 Mar 1992 15:56:12 NED
+ * Added Large Directory message
+ *
+ * Rev 1.1 22 May 1991 11:40:56 DAVIDH
+ * Converted enum's to typedefs and added dummy value of 256 at the end
+ * to force the size under Watcom to 2 bytes.
+ *
+ * Rev 1.0 09 May 1991 13:32:18 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+
+#ifndef _lp_msg_h_
+#define _lp_msg_h_
+
+#define LP_ERROR_BASE ( -0x2048 )
+
+#define LP_DATA_VERIFIED ( -1L )
+#define LP_OPEN_ERROR ( -2L )
+
+typedef enum LOOP_MESSAGES {
+
+/* general messages */
+ MSG_START_OPERATION,
+ MSG_END_OPERATION,
+ MSG_START_BACKUP_SET,
+ MSG_END_BACKUP_SET,
+
+/* logging messages */
+ MSG_LOG_BLOCK,
+ MSG_LOG_STREAM_NAME,
+
+/* statistics messages */
+ MSG_BLOCK_PROCESSED,
+ MSG_BYTES_PROCESSED,
+ MSG_BLOCK_SKIPPED,
+ MSG_BYTES_SKIPPED,
+ MSG_BLOCK_BAD,
+ MSG_BYTES_BAD,
+ MSG_BLOCK_DELETED,
+ MSG_BYTES_DELETED,
+ MSG_TAPE_STATS,
+ MSG_STOP_CLOCK,
+ MSG_START_CLOCK,
+
+/* Error messages */
+ MSG_TBE_ERROR,
+
+/* verify messages */
+ MSG_BLK_NOT_FOUND,
+ MSG_BLK_DIFFERENT,
+ MSG_LOG_DIFFERENCE,
+
+/* misc messages */
+ MSG_IDLE,
+ MSG_IN_USE,
+ MSG_IN_USE_WAIT,
+ MSG_PROMPT,
+ MSG_EOM,
+ MSG_ACK_FDB_RECOVERED,
+ MSG_ACK_DDB_RECOVERED,
+ MSG_DATA_LOST,
+ MSG_ACCIDENTAL_VCB,
+ MSG_BLOCK_INUSE,
+ MSG_ATTR_READ_ERROR,
+ MSG_LARGE_DIRECTORY, /* over 35 whatevers in directory */
+ MSG_CONT_VCB,
+ MSG_NO_CHECKSUM,
+ MSG_RESTORED_ACTIVE,
+ MSG_NOT_DELETED,
+ MSG_COMM_FAILURE,
+
+ /* Force Watcom to allocate two bytes. */
+ MSG__FORCE_WATCOM_SIZE=256
+} LOOP_MESSAGES ;
+
+/* prompt message codes */
+typedef enum PROMPT_MESSAGE_CODES {
+ CORRUPT_BLOCK_PROMPT,
+ ASK_TO_REPLACE_MODIFIED,
+ ASK_TO_REPLACE_EXISTING,
+ ASK_TO_RESTORE_CONTINUE,
+ ASK_DISK_FULL,
+ /* Force Watcom to allocate two bytes. */
+ ASK__FORCE_WATCOM_SIZE=256
+} PROMPT_MESSAGE_CODES ;
+
+/* return values from message hander */
+typedef enum HANDLER_RESPONSES {
+ MSG_ACK=0,
+ SKIP_TO_NEXT_ITEM=0,
+ ABORT_OPERATION,
+ SKIP_BLOCK,
+ OBJECT_OPENED_SUCCESSFULLY,
+ OBJECT_OPENED_INUSE,
+ RETRY,
+ SKIP_OBJECT,
+ SKIP_TO_NEXT_BSET,
+ OPERATION_COMPLETE,
+ AUXILARY_ERROR,
+ /* Force Watcom to allocate two bytes. */
+ HR__FORCE_WATCOM_SIZE=256
+ } HANDLER_RESPONSES ;
+
+/* parameter to ObjectInUse message */
+typedef INT16 ( *CHK_OPEN )( UINT32 lp ) ;
+
+/* object skipped causes */
+typedef enum SKIPPED_CAUSES {
+ OBJECT_IN_USE,
+ ERROR_CONDITION,
+ /* Force Watcom to allocate two bytes. */
+ SC__FORCE_WATCOM_SIZE=256
+}SKIPPED_CAUSES ;
+
+/* errors for MSG_TBE_ERROR */
+typedef enum ERROR_MESSAGES {
+ LP_OUT_OF_MEMORY_ERROR = LP_ERROR_BASE,
+ LP_FILE_READ_ERROR,
+ LP_FILE_NOT_FOUND_ERROR,
+ LP_TAPE_WRITE_ERROR,
+ LP_TAPE_READ_ERROR,
+ LP_FILE_IN_USE_ERROR,
+ LP_USER_ABORT_ERROR,
+ LP_TAPE_POS_ERROR,
+ LP_ACCESS_DENIED_ERROR,
+ LP_FILE_OPEN_ERROR,
+ LP_FILE_WRITE_ERROR,
+ LP_FILE_CREATION_ERROR,
+ LP_DRIVE_ATTACH_ERROR,
+ LP_CHANGE_DIRECTORY_ERROR,
+ LP_PRIVILEGE_ERROR,
+ LP_OUT_OF_SPACE_ERROR,
+ LP_INVALID_DRIVE_ERROR,
+ LP_END_OPER_FAILED,
+
+ /* Force Watcom to allocate two bytes. */
+ LP__FORCE_WATCOM_SIZE=256
+ }ERROR_MESSAGES ;
+
+#endif
+
+
diff --git a/private/utils/ntbackup/inc/lstdres.h b/private/utils/ntbackup/inc/lstdres.h
new file mode 100644
index 000000000..6513506e3
--- /dev/null
+++ b/private/utils/ntbackup/inc/lstdres.h
@@ -0,0 +1,116 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: lstdres.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the function prototypes for the standard
+ resources.
+
+ Location: BE_PRIVATE
+
+
+ $Log: N:/LOGFILES/LSTDRES.H_V $
+ *
+ * Rev 1.5 12 Aug 1992 17:47:22 STEVEN
+ * fixed bugs at microsoft
+ *
+ * Rev 1.4 24 Jul 1992 16:00:50 STEVEN
+ * fix warnings
+ *
+ * Rev 1.3 27 May 1992 18:52:42 STEVEN
+ * switches need to match tfinit.c
+ *
+ * Rev 1.2 28 Aug 1991 09:40:24 ED
+ * Roll in Bonoman's changes (Panther). Fiexed bad log token.
+
+**/
+/* $end$ */
+
+#ifndef _LMSLRES
+#define _LMSLRES
+
+#include "detdrive.h"
+
+/* Resources from the MSC libraries that everyone uses */
+
+#if ( !defined( OS_OS2 ) && !defined( OS_WIN32 ) )
+typedef INT16 ( * PF_intdosx )( union REGS *, union REGS *, struct SREGS * );
+typedef VOID ( * PF_free )( VOID_PTR ) ;
+typedef VOID ( * PF_memset )( VOID_PTR,INT16,UINT16 ) ;
+typedef INT16 ( * PF_inp )( UINT16 ) ;
+typedef UINT16 ( * PF_inpw )( UINT16 ) ;
+typedef INT16 ( * PF_outp )( UINT16,INT16 ) ;
+typedef UINT16 ( * PF_outpw )( UINT16,UINT16 ) ;
+typedef VOID_PTR ( * PF_calloc )( size_t,size_t ) ;
+typedef INT16 ( * PF_int86 )( INT16, union REGS *, union REGS * ) ;
+typedef INT16 ( * PF_int86x )( INT16, union REGS *, union REGS *,struct SREGS * ) ;
+#endif
+typedef UINT8_PTR ( * PF_DriverLoad )( CHAR_PTR,DRIVERHANDLE *,VOID_PTR,UINT16 ) ;
+typedef CHAR_PTR ( * PF_CDS_GetMaynFolder )( VOID ) ;
+
+/* The structure we'll have at the top of our header */
+
+typedef struct {
+#if ( !defined( OS_OS2 ) && !defined( OS_WIN32 ) )
+ PF_intdosx intdosx ;
+ PF_free free ;
+ PF_memset memset ;
+ PF_inp inp ;
+ PF_inpw inpw ;
+ PF_outp outp ;
+ PF_outpw outpw ;
+ PF_calloc calloc ;
+ PF_int86 int86 ;
+ PF_int86x int86x ;
+#endif
+ PF_DriverLoad DriverLoad ;
+ PF_CDS_GetMaynFolder CDS_GetMaynFolder ;
+} STD_RESOURCES_INIT ;
+
+#define STD_BUILD_TCB 0
+#define STD_DEBUILD_TCB 1
+
+typedef BOOLEAN (* PF_STDENTRY)( UINT16,INT16,VOID_PTR ) ;
+
+typedef BOOLEAN (* PF_DDRENTRY)( DET_DRIVER_PTR, INT16 ) ;
+
+/*
+** SetCurrentMSL is used to give the handle of the currently loaded MSL to
+** the interface layer so the DIL can call it.
+*/
+
+extern VOID SetActiveMSL( DRIVERHANDLE ) ;
+
+typedef struct {
+ PF_STDENTRY STDENTRY ;
+ UINT16 rmtseg ;
+ STD_RESOURCES_INIT rsrc ;
+} STD_RESOURCES ;
+
+/*
+** This is defined in d_main.asm, the prefix code that makes
+** this module loadable. Note that we only include this code
+** if TDHRES.H has not been loaded; e.g. they don't have the
+** real functions already linked in. (We also keep them from
+** including TDGRES.H after this)
+*/
+
+
+extern STD_RESOURCES funs_tbl ;
+
+#define _intdosx(a,b,c) ( funs_tbl.rsrc.intdosx( a,b,c ) )
+#define _MemFree(a) ( funs_tbl.rsrc.free( a ) )
+#define _MemFill(a,b,c) ( funs_tbl.rsrc.memset( a,b,c ) )
+#define _InByte(a) ( funs_tbl.rsrc.inp( a ) )
+#define _InWord(a) ( funs_tbl.rsrc.inpw( a ) )
+#define _OutByte(a,b) ( funs_tbl.rsrc.outp( a,b ) )
+#define _OutWord(a,b) ( funs_tbl.rsrc.outpw( a,b ) )
+#define _MemAlloc(a,b) ( funs_tbl.rsrc.calloc( a,b ) )
+#define _int86(a,b,c) ( funs_tbl.rsrc.int86( a,b,c ) )
+#define _int86x(a,b,c,d) ( funs_tbl.rsrc.int86x( a,b,c,d ) )
+#define _DriverLoad(a,b,c,d) ( funs_tbl.rsrc.DriverLoad( a,b,c,d ) )
+#define _CDS_GetMaynFolder() ( funs_tbl.rsrc.CDS_GetMaynFolder( ) )
+#endif
diff --git a/private/utils/ntbackup/inc/ltappswd.h b/private/utils/ntbackup/inc/ltappswd.h
new file mode 100644
index 000000000..6586c04e0
--- /dev/null
+++ b/private/utils/ntbackup/inc/ltappswd.h
@@ -0,0 +1,41 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: ltappswd.h
+
+ Description: LAN Tape Password dialog ID header file.
+
+ $Log: G:/UI/LOGFILES/LTAPPSWD.H_V $
+
+ Rev 1.5 04 Oct 1992 19:47:46 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.4 03 Apr 1992 11:07:44 CHUCKB
+Added defines for translation.
+
+ Rev 1.3 27 Jan 1992 12:50:30 GLENN
+Fixed dialog IDs.
+
+*******************************************************************************/
+
+#ifndef _ltappswd_h_
+#define _ltappswd_h_
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_LANTAPEPSWD 31
+#else
+#include "dlg_ids.h"
+#endif
+
+#define IDD_T_TAPESTR 0x0065
+#define IDD_T_BKSTR 0x0066
+#define IDD_T_USTR 0x0067
+#define IDD_T_PSWD 0x006B
+#define IDD_T_TAPENAME 0x006C
+#define IDD_T_BSNAME 0x006D
+#define IDD_T_UNAME 0x006E
+#define IDD_T_PSWDSTR 0x006A
+
+#endif
diff --git a/private/utils/ntbackup/inc/lw_cntl.h b/private/utils/ntbackup/inc/lw_cntl.h
new file mode 100644
index 000000000..3ff7efe58
--- /dev/null
+++ b/private/utils/ntbackup/inc/lw_cntl.h
@@ -0,0 +1,43 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: lw_cntl.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the main control struct for the tape format layer.
+
+
+ $Log: N:/LOGFILES/LW_CNTL.H_V $
+ *
+ * Rev 1.2 10 Dec 1991 16:41:38 GREGG
+ * SKATEBOARD - New Buf. Mgr. - Initial integration.
+ *
+ * Rev 1.1 10 May 1991 17:09:04 GREGG
+ * Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:13:12 GREGG
+Initial revision.
+
+**/
+#ifndef _MAIN_CNTL_JUNK
+#define _MAIN_CNTL_JUNK
+
+#include "dilhwd.h"
+
+/* $end$ include list */
+
+
+typedef struct _LW_CNTL {
+ BOOLEAN drives_active ; /* Are Drives active */
+ BOOLEAN driver_inited ; /* Is the drive inited */
+ DIL_HWD_PTR cntl_cards ; /* The controller cards for the system */
+ VOID_PTR driver_addr ; /* The driver load address */
+ UINT16 no_channels ; /* The number of channels */
+ UINT16 no_chans_open ; /* The number of Channels Opened */
+ BOOLEAN use_fast_file ; /* FALSE if UI wants to suppress FF */
+} LW_CNTL, *LW_CNTL_PTR ;
+
+
+#endif
diff --git a/private/utils/ntbackup/inc/lw_data.h b/private/utils/ntbackup/inc/lw_data.h
new file mode 100644
index 000000000..bf29ed3d2
--- /dev/null
+++ b/private/utils/ntbackup/inc/lw_data.h
@@ -0,0 +1,116 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: lw_data.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the extern definitions for all layer wide data
+ structures for the Tape Format.
+
+
+ $Log: T:\logfiles\lw_data.h_v $
+ *
+ * Rev 1.12 30 Aug 1993 18:47:46 GREGG
+ * Modified the way we control hardware compression from software to work around
+ * a bug in Archive DAT DC firmware rev. 3.58 (we shipped a lot of them).
+ * Files Modified: lw_data.c, lw_data.h, tfstuff.c, mtf10wdb.c, mtf10wt.c and
+ * drives.c
+ *
+ * Rev 1.11 22 Jul 1993 12:11:32 ZEIR
+ * add'd lw_software_name & _len
+ *
+ * Rev 1.10 11 May 1993 21:55:34 GREGG
+ * Moved Sytos translator stuff from layer-wide area to translator.
+ *
+ * Rev 1.9 10 May 1993 15:13:14 Terri_Lynn
+ * Added Steve's changes and My changes for EOM processing
+ *
+ * Rev 1.8 17 Mar 1993 15:10:34 GREGG
+ * This is Terri Lynn. Added external declarations for Sytos Plus and Gregg's
+ * block mode changes.
+ *
+ *
+ * Rev 1.7 24 Jul 1992 14:32:08 NED
+ * added 64-bit constants lw_UINT64_ZERO and lw_UINT64_MAX
+ *
+ * Rev 1.6 05 Apr 1992 19:14:30 GREGG
+ * ROLLER BLADES - Changed lw_sx_file_path to lw_cat_file_path.
+ *
+ * Rev 1.5 16 Jan 1992 18:36:52 NED
+ * Skateboard: buffer manager changes
+ *
+ * Rev 1.4 02 Jan 1992 15:07:00 NED
+ * Buffer Manager/UTF translator integration.
+ *
+ * Rev 1.3 10 Dec 1991 16:41:08 GREGG
+ * SKATEBOARD - New Buf. Mgr. - Initial integration.
+ *
+ * Rev 1.2 17 Oct 1991 01:20:52 GREGG
+ * BIGWHEEL - 8200sx - Added sx file path pointers.
+ *
+ * Rev 1.1 10 May 1991 17:08:54 GREGG
+ * Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:13:10 GREGG
+Initial revision.
+
+**/
+#ifndef _LW_DATA_JUNK
+#define _LW_DATA_JUNK
+
+#include "tfldefs.h"
+#include "drive.h"
+#include "channel.h"
+#include "lw_cntl.h"
+#include "fmtinf.h"
+#include "buffman.h"
+
+/* $end$ include list */
+
+/* The Channel Array */
+extern CHANNEL_PTR lw_channels ;
+
+/* The Drive List */
+extern DRIVE_PTR lw_drives ;
+
+/* The Drive linked list */
+extern Q_HEADER lw_drive_list ;
+
+/* The TFL Control structure */
+extern LW_CNTL lw_tfl_control ;
+
+/* The current byte format indicator */
+extern UINT16 lw_byte_fmt ;
+
+/* The Tape Format descriptions */
+extern TFINF lw_fmtdescr[] ;
+extern UINT16 lw_num_supported_fmts ;
+
+/* The directory where catalog type files should be written */
+extern CHAR_PTR lw_cat_file_path ;
+extern CHAR_PTR lw_cat_file_path_end ;
+
+/* The name of this software - who's creating sets for MTF */
+extern CHAR_PTR lw_software_name ;
+extern UINT16 lw_software_name_len ;
+
+/* Our default requirements */
+extern BUF_REQ lw_default_bm_requirements ;
+extern BUF_REQ lw_default_vcb_requirements ;
+extern UINT16 lw_buff_size ; /* KLUDGE! */
+
+/* 64 bit constants to avoid calling U64_Init all the time. */
+extern const UINT64 lw_UINT64_ZERO ;
+extern const UINT64 lw_UINT64_MAX ;
+
+/* List of valid tape drive physical block sizes. */
+extern UINT32 lw_blk_size_list[] ;
+extern INT lw_num_blk_sizes ;
+
+/* TRUE if we want the next set to be backed up with hardware compression */
+extern BOOLEAN lw_hw_comp ;
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/lwdefs.h b/private/utils/ntbackup/inc/lwdefs.h
new file mode 100644
index 000000000..00beeaffd
--- /dev/null
+++ b/private/utils/ntbackup/inc/lwdefs.h
@@ -0,0 +1,37 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: lwdefs.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the internal Layer Wide Defines.
+
+
+ $Log: L:/LOGFILES/LWDEFS.H_V $
+ *
+ * Rev 1.3 13 Apr 1992 10:22:02 BURT
+ * Increased default buffer size to 4096 to accomodate 4.0 tape format
+ * needs.
+ *
+ *
+ * Rev 1.2 16 Jan 1992 18:37:18 NED
+ * Skateboard: buffer manager changes
+ *
+ * Rev 1.1 10 May 1991 17:09:28 GREGG
+ * Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:13:08 GREGG
+Initial revision.
+
+**/
+#ifndef _LW_DEFS
+#define _LW_DEFS
+
+/* size used at a minimum for VCB buffers
+ * for those translators which don't care */
+#define TF_DEFAULT_VCB_SIZE (32*1024)
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/lwprotos.h b/private/utils/ntbackup/inc/lwprotos.h
new file mode 100644
index 000000000..5ef0c2205
--- /dev/null
+++ b/private/utils/ntbackup/inc/lwprotos.h
@@ -0,0 +1,133 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: lwprotos.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the layer wide function prototypes.
+
+
+ $Log: G:/LOGFILES/LWPROTOS.H_V $
+ *
+ * Rev 1.16 17 Mar 1993 14:55:52 GREGG
+ * This is Terri Lynn. Added Gregg's change to switch a tape drive's block mode
+ * to match the block size of the current tape.
+ *
+ * Rev 1.15 09 Mar 1993 18:14:08 GREGG
+ * Initial changes for new stream and EOM processing.
+ *
+ * Rev 1.14 18 Jan 1993 14:09:58 GREGG
+ * Changes to allow format command passed to driver through TpErase.
+ *
+ * Rev 1.13 11 Nov 1992 22:10:02 GREGG
+ * Changed proto for EraseDrive.
+ *
+ * Rev 1.12 22 Sep 1992 09:15:50 GREGG
+ * Initial changes to handle physical block sizes greater than 1K.
+ *
+ * Rev 1.11 17 Aug 1992 09:09:14 GREGG
+ * Changes to deal with block sizeing scheme.
+ *
+ * Rev 1.10 29 Apr 1992 13:11:44 GREGG
+ * ROLLER BLADES - Added prototype for ReadABuff.
+ *
+ * Rev 1.9 25 Mar 1992 18:27:50 GREGG
+ * ROLLER BLADES - Changed GotoBlock prototype.
+ *
+ * Rev 1.8 15 Jan 1992 01:51:50 GREGG
+ * Added BOOLEAN vcb_only parameter to PositionAtSet.
+ *
+ * Rev 1.7 03 Jan 1992 11:23:52 NED
+ * Added prototype for DumpDebug()
+ *
+ * Rev 1.6 10 Dec 1991 16:42:02 GREGG
+ * SKATEBOARD - New Buf. Mgr. - Initial integration.
+ *
+ * Rev 1.5 14 Oct 1991 10:56:36 GREGG
+ * Changed return type for UpdateDriveStatus.
+ *
+ * Rev 1.4 21 Aug 1991 14:45:06 GREGG
+ * Added prototype for new function 'RewindDriveImmediate'.
+ *
+ * Rev 1.3 09 Jul 1991 16:48:28 NED
+ * Changed prototype for GotoBckUpSet.
+ *
+ * Rev 1.2 05 Jun 1991 19:16:08 NED
+ * added prototype for FormatIndexFromID()
+ *
+ * Rev 1.1 10 May 1991 17:10:08 GREGG
+ * Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:13:06 GREGG
+Initial revision.
+
+**/
+#ifndef _LW_PROTOPLASM
+#define _LW_PROTOPLASM
+
+#include "reqrep.h"
+#include "channel.h"
+#include "tpos.h"
+
+/* For the device driver */
+#include "retbuf.h"
+#include "dilhwd.h"
+
+/* $end$ include list */
+
+INT16 PositionAtSet( CHANNEL_PTR channel, TPOS_PTR position, BOOLEAN vcb_only ) ;
+
+INT16 UpdateDriveStatus( DRIVE_PTR drive ) ;
+INT16 SetupDriveList( DIL_HWD_PTR cards, INT16 no_cards ) ;
+
+INT16 OpenDrive( DRIVE_PTR, TPOS_PTR ) ;
+INT16 CloseDrive( DRIVE_PTR, TPOS_PTR, UINT16, BOOLEAN ) ;
+
+INT16 MountTape( DRIVE_PTR, TPOS_PTR, BOOLEAN_PTR ) ;
+INT16 DisMountTape( DRIVE_PTR, TPOS_PTR, BOOLEAN ) ;
+
+INT16 ResetChannelList( CHANNEL_PTR channel, BOOLEAN rew_cur_drv ) ;
+INT16 NextDriveInChannel( CHANNEL_PTR channel, BOOLEAN rew_cur_drv ) ;
+INT16 PrevDriveInChannel( CHANNEL_PTR channel, BOOLEAN rew_cur_drv ) ;
+
+INT16 RewindDrive( DRIVE_PTR curDRV, TPOS_PTR ui_tpos, BOOLEAN call_ui, BOOLEAN reset_flg, UINT16 mode ) ;
+INT16 EraseDrive( CHANNEL_PTR channel, BOOLEAN security, BOOLEAN format ) ;
+INT16 RetensionDrive( CHANNEL_PTR ) ;
+INT16 WriteEndSet( DRIVE_PTR ) ;
+INT16 MapGenErr2UIMesg( INT16 gen_error ) ;
+INT16 GotoBckUpSet( CHANNEL_PTR channel, INT16_PTR desired_set_ptr, TPOS_PTR ui_tpos ) ;
+VOID ResetDrivePosition( DRIVE_PTR ) ;
+INT16 GotoBlock( CHANNEL_PTR, UINT32, TPOS_PTR, UINT16_PTR ) ;
+INT16 GetCurrentPosition( DRIVE_PTR ) ;
+INT16 MoveFileMarks( CHANNEL_PTR channel, INT16 number, INT16 direction ) ;
+VOID RewindDriveImmediate( DRIVE_PTR curDRV ) ;
+VOID DumpDebug( INT16 drv_hdl );
+
+/* routines in drives.c */
+
+INT16 ReadABuff( CHANNEL_PTR channel, BOOLEAN try_resize, BOOLEAN_PTR resized_buff ) ;
+INT16 SetDrvBlkSize( CHANNEL_PTR channel, BUF_PTR buffer, UINT32 size, BOOLEAN_PTR resized_buff ) ;
+INT16 MoveNextSet( CHANNEL_PTR channel, TPOS_PTR ui_tpos ) ;
+INT16 ReadThisSet( CHANNEL_PTR channel ) ;
+INT16 ReadNewTape( CHANNEL_PTR channel, TPOS_PTR ui_tpos, BOOLEAN read_tape ) ;
+
+
+/* Buffer Engineering */
+INT16 GetDBLKMapStorage( CHANNEL_PTR channel, BUF_PTR buffer ) ;
+UINT8_PTR GetDATAStorage( CHANNEL_PTR, UINT16_PTR ) ;
+BUF_PTR SnagBuffer( CHANNEL_PTR ) ;
+VOID PuntBuffer( CHANNEL_PTR ) ;
+UINT16 FormatIndexFromID( UINT16 format_id ) ;
+
+/* IO Functions */
+INT16 DoWrite( CHANNEL_PTR, RR_PTR ) ;
+INT16 DoRead( CHANNEL_PTR, RR_PTR ) ;
+
+/* This determines if a return value is a TFLE_xxx error code (as opposed
+ to a TF_xxx message.
+*/
+#define IsTFLE( x ) ( ((INT16) (x) ) < 0 )
+
+#endif
diff --git a/private/utils/ntbackup/inc/machine.h b/private/utils/ntbackup/inc/machine.h
new file mode 100644
index 000000000..e290a79f0
--- /dev/null
+++ b/private/utils/ntbackup/inc/machine.h
@@ -0,0 +1,43 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: machine.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Header for machine.c
+
+ Location: BE_PUBLIC
+
+
+ $Log: T:/LOGFILES/MACHINE.H_V $
+ *
+ * Rev 1.1 28 Feb 1992 13:44:04 NED
+ * added prototype for IsIRQ()
+ *
+ * Rev 1.0 09 May 1991 13:32:56 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef _machine_h_
+#define _machine_h_
+
+/* machine types */
+#define UNKNOWN_MACHINE ( 0x0 )
+#define IBM_PS2 ( 0x1 )
+#define IBM_PC ( 0x2 )
+#define IBM_XT_OR_PC_PORTABLE ( 0x3 )
+#define IBM_PC_JR ( 0x4 )
+#define IBM_AT ( 0x5 )
+
+#define MACHINE_ID_SEGMENT ( 0xf000 )
+#define MACHINE_ID_OFFSET ( 0xfffe )
+
+INT16 GetMachineType( VOID ) ;
+
+BOOLEAN IsIRQ( UINT8 IRQ_number, UINT16 base );
+
+#endif
diff --git a/private/utils/ntbackup/inc/mayn31.h b/private/utils/ntbackup/inc/mayn31.h
new file mode 100644
index 000000000..2091cc562
--- /dev/null
+++ b/private/utils/ntbackup/inc/mayn31.h
@@ -0,0 +1,512 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: mayn31.h
+
+ Date Updated: $./FDT$ $./FTM$
+ 8/17/1989 10:4:121
+
+ Description: Maynard's 3.1 Format... See the Document for
+ complete details.
+
+
+ $Log: T:/LOGFILES/MAYN31.H_V $
+ *
+ * Rev 1.15 10 Jan 1995 14:27:14 GREGG
+ * Added code to deal with continuation bits wrongly set in DDBs.
+ *
+ * Rev 1.14 01 Aug 1994 21:56:42 GREGG
+ * Added replaced internal structures in the Novell OS Info with packed
+ * versions. The unpacked versions made the structure size different than
+ * the size on tape! MAYN31RD.C rev 1.54 is needed with this change.
+ *
+ * Rev 1.13 17 Jan 1994 14:56:56 GREGG
+ * Unicode fixes.
+ *
+ * Rev 1.12 12 Jan 1993 11:10:50 GREGG
+ * Fixed problem with not recognizing we had repositioned and needed a new DBLK.
+ *
+ * Rev 1.11 06 Jan 1993 17:20:28 GREGG
+ * Added pad stream to skip the pad data.
+ *
+ * Rev 1.10 18 Nov 1992 10:39:30 HUNTER
+ * Bug fixes
+ *
+ * Rev 1.9 11 Nov 1992 09:48:54 HUNTER
+ * Changes for Streams.
+ *
+ * Rev 1.8 24 Jul 1992 14:41:10 NED
+ * Incorporated Skateboard and BigWheel changed into Graceful Red code,
+ * including MTF4.0 translator support, adding 3.1 file-system structures
+ * support to the 3.1 translator, additions to GOS to support non-4.0 translators.
+ * Also did Unicode and 64-bit filesize changes.
+ *
+ * Rev 1.7 28 Apr 1992 09:35:54 HUNTER
+ * Added "vblk_scan" variable to 3.1 environment.
+ *
+ * Rev 1.6 12 Dec 1991 10:49:36 HUNTER
+ * Changed VBLK identifier defines.
+ *
+ * Rev 1.5 17 Nov 1991 17:38:50 GREGG
+ * Changed value of DB_VAR_BLKS_BIT (it was stepping on ARCHIVE_BIT).
+ *
+ * Rev 1.4 07 Nov 1991 15:23:36 HUNTER
+ * VBLK - Further Variable Block support
+ *
+ * Rev 1.3 29 Oct 1991 10:12:50 HUNTER
+ * VBLK - Added VBLK structure and new bits to support Variable length blocks.
+ *
+ * Rev 1.2 22 Jul 1991 11:50:50 GREGG
+ * Added EOS_AT_EOM attribute bit.
+ *
+ * Rev 1.1 10 May 1991 14:25:46 GREGG
+ * Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:17:38 GREGG
+Initial revision.
+
+**/
+
+#ifndef _MAYN31_FMT
+#define _MAYN31_FMT
+
+
+
+#include "datetime.h"
+#include "fsys_str.h"
+
+#define F31_MAX_STREAMS 5
+
+typedef struct {
+ UINT32 nxt_id ;
+ UINT16 os_id ;
+ UINT16 os_ver ;
+ UINT16 next_dir_id ;
+ UINT16 next_file_id ;
+ UINT16 pellet_offset ;
+ BOOLEAN vblk_scan ;
+ UINT16 no_streams ;
+ UINT16 cur_stream ;
+ STREAM_INFO streams[F31_MAX_STREAMS] ;
+ UINT32 pad_size ;
+ BOOLEAN stream_mode ;
+ UINT32 curr_lba ;
+ BOOLEAN in_streams ;
+ BOOLEAN cont_vcb ;
+} F31_ENV, *F31_ENV_PTR ;
+
+
+#pragma pack(1)
+
+
+/* Version Defines */
+#define FORMAT_MAJOR 3
+#define FORMAT_MINOR 1
+
+
+/* Minimum number of bytes buffered for a proper determination
+*/
+
+#define F31_MIN_BYTES_FOR_ID 1024L
+
+/* The DB attribute bit fields defined are the same for all logical tape
+ blocks. If any bit is set in the upper word of the attribute field
+ then the data has been altered. The currently defined attributes are:
+*/
+
+#define F31_DB_CONT_BIT BIT0
+#define F31_DB_EOS_AT_EOM_BIT BIT8
+#define F31_DB_VAR_BLKS BIT19
+#define F31_DB_ENCRYPT_BIT BIT24
+#define F31_DB_COMPRESS_BIT BIT25
+
+/* This is the Attribute Mask for changing DBLK attributes into tape attributes */
+
+#define F31_ATTRIB_MASK 0xff000001L
+
+/* The "hdr_chksm" refers to the checksum of the first nine fields of the
+ block header, these fields are always in INTEL format. The following
+ define specifies the length of this first checksum.
+*/
+
+/* In UINT16s */
+#define F31_HDR_CHKSUM_LEN 14
+
+/* The block types for the 3.1 types are defined as below */
+
+#define F31_VCB_ID 1 /* Volume Control Block */
+#define F31_CVCB_ID 2 /* Closing Volume Control Block */
+#define F31_BSDB_ID 3 /* Backup Summary Descriptor Block */
+#define F31_DDB_ID 8 /* Directory Descriptor Block */
+#define F31_FDB_ID 9 /* File Descriptor Block */
+#define F31_IDB_ID 10 /* Image Descriptor Block */
+#define F31_CFDB_ID 11 /* Corrupt File Descriptor Block */
+
+
+/* The "block header" is common to all logical tape blocks. The software
+ need only analyze the block header to determine the type of tape block
+ it is and whether the software understands this particular tape block
+ or not.
+*/
+
+typedef struct {
+ /* This initial portion is always in INTEL format */
+ UINT16 type ; /* Unique identifier, see above */
+ UINT32 length ; /* Length in 1/2K (512byte) units */
+ UINT32 pba_vcb ; /* Physical block address of the sets VCB */
+ UINT32 fmks ; /* Number of file marks till next DB */
+ UINT32 lba ; /* Logical block addrs, relative to the VCB */
+ UINT32 blk_id ; /* This is the Control Block ID */
+ UINT16 format ; /* Intel/Motorola, see above */
+ UINT16 os_id ; /* Originators machine/OS, see above */
+ UINT16 os_ver ; /* Originators OS version number */
+ UINT16 hdr_chksm ; /* Checksum of the block header. The algorithm
+ is: XOR each word preceeding this one and
+ store the result here. (When the checksum
+ is varified the 'block_type' checked for
+ a non_zero value also. */
+ /* From this point on everything is in 'format' byte order */
+ UINT16 reserved[16] ; /* Never checksumed, for internal use... */
+ UINT16 blk_chksm ; /* The XOR sum for 'the rest of the BD' */
+ UINT16 chksm_len ; /* The length of 'the rest of the BD' */
+ UINT32 blk_attribs ; /* Addition DB information, see above */
+ UINT16 var_len_off ; /* Offset to strings... */
+ UINT16 non_gen_off ; /* Offset to non_generic DB specifics */
+ UINT16 non_gen_siz ; /* its Size (Bytes, padded to word boundry) */
+ UINT16 data_off ; /* Offset to data */
+ UINT32 tot_data_siz ; /* Total data size */
+ UINT32 rem_data_siz ; /* Remaining data size */
+ UINT32 gen_data_siz ; /* Generic data size */
+ UINT32 gen_data_off ; /* Generic data offset */
+} DB_HDR, * DB_HDR_PTR ;
+
+/* Generic 3.1 VCB defines and structs */
+
+typedef struct {
+ DB_HDR hdr ;
+ UINT32 vcb_attribs ;
+ DATE_TIME backup_date ;
+ UINT16 tf_mjr_ver ;
+ UINT16 tf_mnr_ver ;
+ UINT16 sw_mjr_ver ;
+ UINT16 sw_mnr_ver ;
+ INT32 id ;
+ INT16 ts_num ;
+ INT16 bs_num ;
+ UINT16 pass_encrypt_algm ;
+ UINT16 data_encrypt_algm ;
+ UINT16 data_compress_algm ;
+ UINT16 t_name_len ;
+ UINT16 t_name_off ;
+ UINT16 bs_name_len ;
+ UINT16 bs_name_off ;
+ UINT16 bs_desc_len ;
+ UINT16 bs_desc_off ;
+ UINT16 vol_name_len ;
+ UINT16 vol_name_off ;
+ UINT16 t_pass_len ;
+ UINT16 t_pass_off ;
+ UINT16 bs_pass_len ;
+ UINT16 bs_pass_off ;
+ UINT16 username_len ;
+ UINT16 username_off ;
+ UINT16 mach_name_len ;
+ UINT16 mach_name_off ;
+ UINT16 shrt_mach_name_len ;
+ UINT16 shrt_mach_name_off ;
+} F31_VCB, *F31_VCB_PTR ;
+
+
+/* Generic 3.1 ClosingVCB (CVCB) defines and structs */
+
+typedef struct {
+ DB_HDR hdr ;
+} F31_CVCB, * F31_CVCB_PTR ;
+
+
+/* Generic 3.1 BSDB defines and structs */
+
+typedef F31_VCB F31_BSDB, * F31_BSDB_PTR ;
+
+
+/* Generic 3.1 DDB defines and structs */
+
+typedef struct {
+ DB_HDR hdr ;
+ UINT32 dir_attribs ;
+ DATE_TIME mod_date ;
+ DATE_TIME create_date ;
+ DATE_TIME backup_date ;
+ UINT32 dir_id ;
+ UINT16 dir_name_len ;
+ UINT16 dir_name_off ;
+} F31_DDB, * F31_DDB_PTR ;
+
+
+/* Generic 3.1 FDB defines and structs */
+
+typedef struct {
+ DB_HDR hdr ;
+ UINT32 file_attribs ;
+ UINT32 file_version ;
+ DATE_TIME mod_date ;
+ DATE_TIME create_date ;
+ DATE_TIME backup_date ;
+ UINT32 dir_id ;
+ UINT16 file_name_len ;
+ UINT16 file_name_off ;
+} F31_FDB, * F31_FDB_PTR ;
+
+
+/* Generic 3.1 IDB defines and structs */
+
+typedef struct {
+ DB_HDR hdr ;
+ UINT32 image_attribs ;
+ UINT32 partition_siz ;
+ UINT32 bytes_in_sector ;
+ UINT32 no_of_sectors ;
+ UINT16 no_of_heads ;
+ UINT32 relative_sector ;
+ UINT32 part_no_of_sector ;
+ UINT16 part_sys_ind ;
+ UINT16 partition_name_len ;
+ UINT16 partition_name_off ;
+} F31_IDB, * F31_IDB_PTR ;
+
+
+/* Generic 3.1 CFDB defines and structs */
+
+typedef struct {
+ DB_HDR hdr ;
+ UINT32 crupt_file_attribs ;
+ UINT32 file_id ;
+ UINT32 dir_id ;
+ UINT32 file_offset ;
+} F31_CFDB, * F31_CFDB_PTR ;
+
+
+/* Generic 3.1 Undefined Descriptor Block (UDB) defines and structs */
+
+typedef struct {
+ DB_HDR hdr ;
+} F31_UDB, * F31_UDB_PTR ;
+
+
+/* The Defines for the Variable Length Block */
+#define F31_VBLK_CONT 0xCF0
+#define F31_VBLK_END 0xCFF
+
+
+typedef struct {
+ UINT16 vblk_type ; /* The type of variable length blocks */
+ UINT32 no_blks ; /* The number of tape blocks */
+ UINT32 dead_space ; /* Space to skip */
+ UINT32 amt_data ; /* The amount of file data */
+} PELLET, * PELLET_PTR ;
+
+
+#define F31_VCB_CONT_BIT BIT0 /* Continuation Tape */
+#define F31_VCB_ARCHIVE_BIT BIT1 /* This is an Transfer set */
+#define F31_VCB_PASSWORD_BIT BIT2 /* Set has a password */
+#define F31_VCB_DIR_TRK_NDX_BIT BIT3 /* Directory track utilized */
+#define F31_VCB_END_NDX_BIT BIT4
+#define F31_VCB_PBA_BIT BIT5 /* Physical Block address is valid */
+#define F31_VCB_LBA_BIT BIT6 /* Logical Block Address is valid */
+#define F31_VCB_PREPARED_TAPE BIT7 /* This is an MBS Prepared tape ( a NULL set ) */
+#define F31_VCB_EOS_AT_EOM BIT8 /* Special case: EOS hit at EOM. */
+#define F31_VCB_COPY_SET BIT9 /* backup all do not reset modified flag */
+#define F31_VCB_NORMAL_SET BIT10 /* backup all and reset modified flag */
+#define F31_VCB_DIFFERENTIAL_SET BIT11 /* backup modified files and do NOT reset */
+#define F31_VCB_INCREMENTAL_SET BIT12 /* backup modified files and reset modified flag */
+#define F31_VCB_NOT_START_CONTINUE BIT13 /* if set VCB can't be used to start with continue set */
+#define F31_VCB_VAR_BLKS_BIT BIT19 /* This block is variable length */
+#define F31_VCB_UNSUPPORTED_BIT BIT23 /* We can't do any operations on this set */
+#define F31_VCB_ENCRYPT_BIT BIT24 /* The data is encrypted */
+#define F31_VCB_COMPRESS_BIT BIT25 /* The data is compressed */
+
+/* BSDB attribute defines */
+
+#define F31_BSDB_CONT_BIT BIT0
+#define F31_BSDB_ACHIVE_BIT BIT1
+#define F31_BSDB_PASSWORD_BIT BIT2
+#define F31_BSDB_DIR_TRK_NDX_BIT BIT3
+#define F31_BSDB_END_NDX_BIT BIT4
+#define F31_BSDB_PBA_BIT BIT5
+#define F31_BSDB_LBA_BIT BIT6
+#define F31_BSDB_VAR_BLKS_BIT BIT19 /* This block is variable length */
+#define F31_BSDB_ABORTED_SET_BIT BIT22 /* Aborted Backup Set */
+#define F31_BSDB_ENCRYPT_BIT BIT24
+#define F31_BSDB_COMPRESS_BIT BIT25
+
+/* DDB attribute defines */
+
+#define F31_DDB_CONT_BIT BIT0
+#define F31_DDB_EMPTY_BIT BIT7
+#define F31_DDB_READ_ACCESS_BIT BIT8
+#define F31_DDB_WRITE_ACCESS_BIT BIT9
+#define F31_DDB_OPEN_FILE_RIGHTS_BIT BIT10
+#define F31_DDB_CREATE_FILE_RIGHTS_BIT BIT11
+#define F31_DDB_DELETE_FILE_RIGHTS_BIT BIT12
+#define F31_DDB_PARENTAL_RIGHTS_BIT BIT13
+#define F31_DDB_SEARCH_RIGHTS_BIT BIT14
+#define F31_DDB_MOD_FILE_ATTRIBS_BIT BIT15
+#define F31_DDB_HIDDEN_BIT BIT16
+#define F31_DDB_SYSTEM_BIT BIT17
+#define F31_DDB_VAR_BLKS_BIT BIT19 /* This block is variable length */
+#define F31_DDB_ENCRYPT_BIT BIT24
+#define F31_DDB_COMPRESS_BIT BIT25
+
+
+/* FDB attribute defines */
+
+#define F31_FDB_CONT_BIT BIT0
+#define F31_FDB_CORRUPT_FILE BIT6
+#define F31_FDB_IN_USE_BIT BIT7
+#define F31_FDB_READ_ONLY_BIT BIT8
+#define F31_FDB_HIDDEN_BIT BIT9
+#define F31_FDB_SYSTEM_BIT BIT10
+#define F31_FDB_EXECUTE_ONLY_BIT BIT11
+#define F31_FDB_MODIFIED_BIT BIT13
+#define F31_FDB_SHAREABLE_BIT BIT15
+#define F31_FDB_VAR_BLKS_BIT BIT19 /* This block is variable length */
+#define F31_FDB_TRANSACTIONAL_BIT BIT20
+#define F31_FDB_INDEXING_BIT BIT21
+#define F31_FDB_ENCRYPT_BIT BIT24
+#define F31_FDB_COMPRESS_BIT BIT25
+
+
+/* CFDB attribute defines */
+
+#define F31_CFDB_CONT_BIT BIT0
+#define F31_CFDB_LENGTH_CHANGE_BIT BIT16
+#define F31_CFDB_UNREADABLE_BLK_BIT BIT17
+#define F31_CFDB_DEADLOCK_BIT BIT18
+#define F31_CFDB_ENCRYPT_BIT BIT24
+#define F31_CFDB_COMPRESS_BIT BIT25
+
+/* IDB attribute defines */
+
+#define F31_IDB_CONT_BIT BIT0
+#define F31_IDB_ENCRYPT_BIT BIT24
+#define F31_IDB_COMPRESS_BIT BIT25
+
+typedef struct F31_NOVELL_386_DIR {
+ BOOLEAN info_valid ; /* TRUE when info below is valid */
+ UINT32 maximum_space ; /* Max disk space allowed for dir */
+ UINT16 attributes_386 ; /* Most sig 16 bits of 32-bit attr */
+ UINT8 extend_attr ; /* Most sig byte of low 16 bits */
+ UINT8 inherited_rights ; /* Most sig byte of rights mask */
+} F31_NOVELL_386_DIR ;
+
+typedef struct F31_NOVELL_386_FILE {
+ BOOLEAN info_valid ; /* TRUE when info below is valid */
+ UINT16 creation_time ;
+ UINT32 archiver_id ;
+ UINT16 attributes_386 ; /* Most sig 16 bits of 32-bit attr */
+ UINT32 last_modifier_id ;
+ UINT32 trust_fork_size ; /* Trustee info */
+ UINT32 trust_fork_offset ;
+ UINT8 trust_fork_format ; /* See NOVCOM.H for trust formats */
+ UINT16 inherited_rights ;
+} F31_NOVELL_386_FILE ;
+
+typedef struct F31_NOV_FILE_OS_INFO {
+ UINT32 owner_id;
+ UINT16 access_date ;
+ F31_NOVELL_386_FILE info_386 ;
+ UINT32 data_fork_offset ;
+} F31_NOV_FILE_OS_INFO, *F31_NOV_FILE_OS_INFO_PTR;
+
+
+typedef struct F31_NOV_DIR_OS_INFO {
+ UINT32 owner_id;
+ UINT32 trust_fork_size ;
+ UINT32 trust_fork_offset;
+ UINT8 trust_fork_format ;
+ F31_NOVELL_386_DIR info_386 ;
+} F31_NOV_DIR_OS_INFO, *F31_NOV_DIR_OS_INFO_PTR;
+
+
+typedef struct F31_AFP_FILE_OS_INFO {
+ UINT8 finder[32];
+ ACHAR long_name[32] ;
+ UINT32 data_fork_size ;
+ UINT32 data_fork_offset ;
+ UINT32 res_fork_size ;
+ UINT32 res_fork_offset ;
+ UINT32 owner_id ;
+ UINT16 access_date ;
+ F31_NOVELL_386_FILE info_386 ;
+ UINT8 proDosInfo[6] ; /* Added in version 1. */
+} F31_AFP_FILE_OS_INFO, *F31_AFP_FILE_OS_INFO_PTR;
+
+typedef struct F31_OLD_AFP_DIR_OS_INFO {
+ UINT8 finder[32];
+ UINT32 owner_id;
+ UINT32 trust_fork_size ;
+ UINT32 trust_fork_offset;
+ INT16 path_leng ;
+ ACHAR long_path[2] ; /* :fred:sue */
+} F31_OLD_AFP_DIR_OS_INFO, *F31_OLD_AFP_DIR_OS_INFO_PTR;
+
+
+typedef struct F31_AFP_DIR_OS_INFO {
+ UINT8 finder[32];
+ UINT32 owner_id;
+ UINT32 trust_fork_size ;
+ UINT32 trust_fork_offset;
+ UINT8 trust_fork_format ;
+ UINT16 lpath_leng ;
+ UINT16 long_path ; /* :fred:sue */
+ F31_NOVELL_386_DIR info_386 ;
+ UINT8 proDosInfo[6] ; /* Added in version 1. */
+} F31_AFP_DIR_OS_INFO, *F31_AFP_DIR_OS_INFO_PTR;
+
+
+/* OS2's File system info */
+typedef struct F31_OS2_FILE_OS_INFO {
+ UINT32 alloc_size ;
+ UINT32 data_fork_size ;
+ UINT32 data_fork_offset ;
+ UINT32 ea_fork_size ;
+ UINT32 ea_fork_offset ;
+ DATE_TIME access_date ;
+ UINT16 lname_leng ;
+ UINT16 long_name ;
+ UINT32 acl_fork_size ;
+ UINT32 acl_fork_offset ;
+} F31_OS2_FILE_OS_INFO, *F31_OS2_FILE_OS_INFO_PTR;
+
+
+typedef struct F31_OS2_DIR_OS_INFO {
+ DATE_TIME access_date ;
+ UINT32 ea_fork_size ;
+ UINT32 ea_fork_offset;
+ UINT16 path_leng ;
+ UINT16 path ;
+ UINT32 acl_fork_size ;
+ UINT32 acl_fork_offset;
+} F31_OS2_DIR_OS_INFO, *F31_OS2_DIR_OS_INFO_PTR;
+
+
+/*
+ * Info for SMS FDBs and DDBs.
+ */
+typedef struct F31_SMS_OS_INFO {
+ UINT32 attrib; /* SMS attributes (these can't be mapped) */
+ DATE_TIME access_date;
+ BOOLEAN is_object; /* Is this DDB / FDB a major object? */
+ UINT32 name_space; /* SMS's value for the generic name */
+ UINT32 creator_name_space; /* SMS's value for the creator name */
+ UINT16 creator_name; /* Path/name in the creator's name space */
+ UINT16 creator_name_length;
+} F31_SMS_OS_INFO, *F31_SMS_OS_INFO_PTR;
+
+#pragma pack()
+
+
+#endif
+
+
diff --git a/private/utils/ntbackup/inc/mayn40.h b/private/utils/ntbackup/inc/mayn40.h
new file mode 100644
index 000000000..1f3fbee30
--- /dev/null
+++ b/private/utils/ntbackup/inc/mayn40.h
@@ -0,0 +1,463 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-92
+
+
+ Name: mayn40.h
+
+ Description: Maynard's 4.0 Format. See the Document for
+ complete details.
+
+
+ $Log: T:/LOGFILES/MAYN40.H_V $
+
+ Rev 1.38.1.3 12 Jan 1995 11:13:22 GREGG
+Calculate OTC addrs from fmk instead of always asking (fixes Wangtek bug).
+
+ Rev 1.38.1.2 08 Jan 1995 22:08:20 GREGG
+Added database type DBLK.
+
+ Rev 1.38.1.1 26 Oct 1993 21:34:04 GREGG
+Increased size of OTC temp file name strings in environment.
+
+ Rev 1.38.1.0 15 Sep 1993 21:43:58 GREGG
+Added otc file name strings to the environment structure.
+
+ Rev 1.38 04 Jul 1993 03:37:34 GREGG
+Added eom_file_id and eom_dir_id to environment.
+
+ Rev 1.37 08 Jun 1993 00:08:24 GREGG
+Fix for bug in the way we were handling EOM and continuation OTC entries.
+Files modified for fix: mtf10wt.c, otc40wt.c, otc40msc.c f40proto.h mayn40.h
+
+ Rev 1.36 19 May 1993 14:17:14 ZEIR
+ad'd #def for conner_software_vendor_id as 0x0CBE
+
+ Rev 1.35 29 Apr 1993 23:38:32 GREGG
+Rearranged environment structure to avoid bug in MIPS compiler.
+
+ Rev 1.34 26 Apr 1993 02:43:38 GREGG
+Sixth in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Redefined attribute bits to match the spec.
+ - Eliminated unused/undocumented bits.
+ - Added code to translate bits on tapes that were written wrong.
+
+Matches MAYN40RD.C 1.59, DBLKS.H 1.15, MAYN40.H 1.34, OTC40RD.C 1.26,
+ SYPL10RD.C 1.8, BACK_VCB.C 1.17, MAYN31RD.C 1.44, SYPL10.H 1.2
+
+ Rev 1.33 25 Apr 1993 17:36:08 GREGG
+Fourth in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Parse the device name and volume name out of the FS supplied "volume
+ name", and write it to tape as separate fields.
+ - Generate the "volume name" the FS and UI expect out of the device
+ name and volume name on tape.
+ - Write all strings without NULL terminater, and translate them back
+ to NULL terminated strings on the read side.
+
+Matches: MTF10WDB.C 1.8, F40PROTO.H 1.26, OTC40WT.C 1.24, MAYN40.H 1.33,
+ MAYN40RD.C 1.57, OTC40RD.C 1.25
+
+ Rev 1.32 19 Apr 1993 18:02:32 GREGG
+Second in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ Changes to write version 2 of OTC, and to read both versions.
+
+Matches: mayn40rd.c 1.55, otc40msc.c 1.19, otc40rd.c 1.23, otc40wt.c 1.23,
+ makevcb.c 1.15, fsys.h 1.32, fsys_str.h 1.46, tpos.h 1.16,
+ mayn40.h 1.32, mtf.h 1.3.
+
+NOTE: There are additional changes to the catalogs needed to save the OTC
+ version and put it in the tpos structure before loading the OTC
+ File/Directory Detail. These changes are NOT listed above!
+
+ Rev 1.31 18 Apr 1993 00:44:16 GREGG
+First in a series of incremental changes to bring the translator in line
+with the MTF spec:
+ - Change string storage pointers in environment from CHAR_PTRs
+ to UINT8_PTRs.
+ - Added define for software vendor id.
+
+Matches: MTF10WT.C 1.6, MTF10WDB.C 1.6, MAYN40RD.C 1.53 and F40PROTO.H 1.25
+
+ Rev 1.30 14 Apr 1993 02:00:52 GREGG
+Fixes to deal with non-ffr tapes in ffr drives (i.e. EXB2200 in EXB5000).
+
+ Rev 1.29 07 Apr 1993 16:28:16 GREGG
+Added boolean 'unaligned_stream' to environment.
+
+ Rev 1.28 24 Mar 1993 10:22:16 ChuckS
+Added fields for device_name to F40_ENV
+
+ Rev 1.27 09 Mar 1993 18:14:44 GREGG
+Initial changes for new stream and EOM processing.
+
+ Rev 1.26 21 Dec 1992 12:28:12 DAVEV
+Enabled for Unicode - IT WORKS!!
+
+ Rev 1.25 07 Dec 1992 10:18:32 GREGG
+Added fields to the format environment for code to put links in the FDD.
+
+ Rev 1.24 24 Nov 1992 18:18:26 GREGG
+Updates to match MTF document.
+
+ Rev 1.23 23 Nov 1992 10:06:30 GREGG
+Changes for path in stream.
+
+ Rev 1.22 19 Nov 1992 10:14:14 GREGG
+Added eom_stream to environment.
+
+ Rev 1.21 17 Nov 1992 14:18:36 GREGG
+Fixed stream definition, and updated OTC structures.
+
+ Rev 1.20 12 Nov 1992 16:41:16 HUNTER
+Added stuff for frag buffer.
+
+ Rev 1.19 09 Nov 1992 10:49:06 GREGG
+Removed unused elements in environment structure.
+
+ Rev 1.18 03 Nov 1992 10:31:36 HUNTER
+Added pad size.
+
+ Rev 1.17 22 Oct 1992 10:55:44 HUNTER
+New stream changes
+
+ Rev 1.16 25 Sep 1992 09:31:42 GREGG
+Changed define for ESPB value to BT_MDB.
+
+ Rev 1.15 22 Sep 1992 09:23:54 GREGG
+Initial changes to handle physical block sizes greater than 1K.
+
+ Rev 1.14 22 Sep 1992 09:04:56 HUNTER
+Revised stream header structure
+
+ Rev 1.13 06 Aug 1992 12:10:26 BURT
+Changed members of PELLET struct back to UINT32s.
+
+
+ Rev 1.12 04 Aug 1992 16:51:10 GREGG
+Burt's fixes for variable length block support.
+
+ Rev 1.11 04 Aug 1992 16:37:10 GREGG
+Added define for unique chksum each time the format is changed.
+
+ Rev 1.10 30 Jul 1992 16:46:46 GREGG
+Added 'end_set_continuing' BOOLEAN to environment.
+
+ Rev 1.9 01 Jul 1992 19:29:02 GREGG
+Defined new date/time structure for storing dates on tape, replaced existing
+date/time structure with new one in tape headers and OTC, and rearranged
+structures to align on 4 byte boundaries with the new date stuctures.
+
+ Rev 1.8 09 Jun 1992 19:31:24 GREGG
+Rearranged header and OTC structures to allign them on 4 byte boundries
+(MIPS needs this). Also removed filemark_count elements, and added some
+new defines and cleaned up the file.
+
+ Rev 1.7 29 May 1992 15:11:20 GREGG
+Added last access date field to DIR block and FDD DIR entry.
+
+ Rev 1.6 22 May 1992 15:29:22 GREGG
+Removed defines that are now defined elsewhere.
+
+ Rev 1.5 20 May 1992 18:16:00 GREGG
+Changes to support OTC read.
+
+ Rev 1.4 05 May 1992 11:27:46 GREGG
+Folded 'local_tape' global into environment.
+
+ Rev 1.3 29 Apr 1992 12:41:26 GREGG
+Changes for new EOM handling.
+
+ Rev 1.2 05 Apr 1992 18:13:42 GREGG
+ROLLER BLADES - Initial OTC integration.
+
+ Rev 1.1 02 Apr 1992 15:12:34 BURT
+Added pragmas to turn packing on and put it back to what is was
+before. This is just for the structures that will be written to
+tape.
+
+
+ Rev 1.0 25 Mar 1992 20:52:24 GREGG
+Initial revision.
+
+**/
+
+#ifndef _MAYN40_FMT
+#define _MAYN40_FMT
+
+/*#include <stdio.h> -- this include violates UNICODE support! */
+ /* (actually, so do the following 2 also, but */
+ /* they are not causing any problem -- YET!) */
+#include "datetime.h" /* Unicode violation - get this include outahere!*/
+#include "stdmath.h" /* Unicode violation - get this include outahere!*/
+#include "mtf.h"
+
+#define CONNER_SOFTWARE_VENDOR_ID 0x0CBE
+
+#define INTERIM_CHECKSUM_BASE 0x0U
+
+/* Auxiliary buffer requirements */
+
+#define F40_DEFAULT_AUX_BUFFER_SIZE 256
+#define F40_AUX_BUFFER_INCR_SIZE 128
+
+/* Logical Block Size for the tapes we write. */
+#define F40_LB_SIZE 1024L
+
+/* Stream header Check Sum Length */
+#define F40_STREAM_CHKSUM_LEN (((sizeof(MTF_STREAM) - sizeof(UINT16)) / 2))
+
+/* 16 bit ID's for the internal use of determining what block type we have */
+#define F40_SSET_IDI BT_VCB /* Volume Control Block */
+#define F40_EOTM_IDI BT_CVCB /* Closing Volume Control Block */
+#define F40_ESET_IDI BT_BSDB /* Backup Summary Descriptor Block */
+#define F40_DIRB_IDI BT_DDB /* Directory Descriptor Block */
+#define F40_FILE_IDI BT_FDB /* File Descriptor Block */
+#define F40_IMAG_IDI BT_IDB /* Image Descriptor Block */
+#define F40_CFIL_IDI BT_CFDB /* Corrupt File Descriptor Block */
+#define F40_VOLB_IDI 13 /* Volume Descriptor Block */
+#define F40_DBDB_IDI BT_DDB /* Database Descriptor Block */
+#define F40_ESPB_IDI BT_MDB /* End of Set Pad Block */
+#define F40_TAPE_IDI 100 /* For tape header id */
+
+/*
+ The header checksum length will now be the full size of the DBLK header
+ minus the size of the header checksum field itself. NOTE: This is the
+ size in 16 bit (2 byte) words.
+*/
+
+#define F40_HDR_CHKSUM_LEN (((sizeof(MTF_DB_HDR) - sizeof(UINT16)) / 2))
+
+
+#pragma pack(1)
+
+/**/
+/*
+ Generic 4.0 IMAG struct
+*/
+
+#define F40_IMAG_N "IMAG" /* Image Descriptor Block ID */
+
+typedef struct {
+ MTF_DB_HDR block_hdr ;
+ UINT32 image_attribs ;
+ UINT32 partition_size ;
+ UINT32 bytes_in_sector ;
+ UINT32 no_of_sectors ;
+ UINT32 relative_sector_no ;
+ UINT32 partition_no_of_sector ;
+ UINT16 partition_sys_ind ;
+ UINT16 no_of_heads ;
+ MTF_TAPE_ADDRESS partition_name ;
+} F40_IMAG, * F40_IMAG_PTR ;
+
+
+/**/
+/*
+ Generic 4.0 Undefined Descriptor Block (UDB) struct
+*/
+typedef struct {
+ MTF_DB_HDR block_hdr ;
+} F40_UDB, * F40_UDB_PTR ;
+
+
+/**/
+/*
+ Database DBLK and FDD Entry (DBDB)
+*/
+
+#define F40_DBDB_N "DBDB" /* Image Descriptor Block ID */
+
+typedef struct {
+ MTF_DB_HDR block_hdr ;
+ UINT32 database_attribs ;
+ MTF_DATE_TIME backup_date ;
+ MTF_TAPE_ADDRESS database_name ;
+} F40_DBDB, * F40_DBDB_PTR ;
+
+typedef struct {
+ MTF_DATE_TIME backup_date ;
+ UINT32 database_attribs ;
+ MTF_TAPE_ADDRESS database_name ;
+ MTF_TAPE_ADDRESS os_info ;
+} F40_FDD_DBDB, * F40_FDD_DBDB_PTR ;
+
+#pragma pack()
+
+typedef struct {
+
+ /* NOTE: These first three fields have to stay in this position until
+ the MIPS compiler is fixed!!! (Alignment problems)
+ */
+ MTF_STREAM cur_stream ;
+ UINT16 sm_count ;
+ MTF_STREAM eom_stream ;
+
+ UINT32 corrupt_obj_count ;
+ UINT64 used_so_far ;
+ MTF_TAPE tape_hdr ;
+ UINT8_PTR tape_name ;
+ UINT16 tape_name_size ;
+ UINT16 tape_name_alloc ;
+ UINT8_PTR tape_password ;
+ UINT16 tape_password_size ;
+ UINT16 tape_password_alloc ;
+ UINT8_PTR vol_name ;
+ UINT16 vol_name_size ;
+ UINT16 vol_name_alloc ;
+ UINT8_PTR machine_name ;
+ UINT16 machine_name_size ;
+ UINT16 machine_name_alloc ;
+ UINT8_PTR device_name ;
+ UINT16 device_name_size ;
+ UINT16 device_name_alloc ;
+ UINT16 max_otc_level ;
+ UINT16 cur_otc_level ;
+ BOOLEAN fdd_aborted ;
+ BOOLEAN sm_aborted ;
+ BOOLEAN fdd_completed ;
+ BOOLEAN fdd_continuing ;
+ BOOLEAN sm_continuing ;
+ UINT32 fdd_pba ;
+ UINT16 fdd_seq_num ;
+ UINT32 eset_pba ;
+ BOOLEAN sm_adjusted ;
+ FILE * otc_fdd_fptr ;
+ FILE * otc_eom_fptr ;
+ FILE * otc_sm_fptr ;
+ CHAR sm_fname[14] ;
+ CHAR fdd_fname[14] ;
+ CHAR eom_fname[14] ;
+ long last_fdd_offset ;
+ UINT16 last_fdd_type ;
+ long last_sm_offset ;
+ long cont_sm_offset ;
+ UINT32 dir_count ;
+ UINT32 file_count ;
+ BOOLEAN eotm_no_first_fmk ;
+ BOOLEAN sm_at_eom ;
+ BOOLEAN end_set_continuing ;
+ BOOLEAN make_streams_invisible ;
+ UINT8 frag[512] ;
+ UINT16 frag_cnt ;
+ UINT32 var_stream_offset ;
+ BOOLEAN stream_crosses ;
+ UINT16 stream_offset ;
+ UINT16 pad_size ;
+ BOOLEAN stream_at_eom ;
+ BOOLEAN pstream_crosses ;
+ UINT16 pstream_offset ;
+ BOOLEAN unaligned_stream ;
+ UINT8_PTR util_buff ;
+ UINT16 util_buff_size ;
+ UINT8_PTR otc_buff ;
+ UINT16 otc_buff_size ;
+ UINT8_PTR otc_buff_ptr ;
+ UINT16 otc_buff_remaining ;
+ long * dir_links ;
+ UINT16 dir_level ;
+ UINT16 max_dir_level ;
+ UINT16 dir_links_size ;
+ long last_volb ;
+ UINT32 last_sset_pba ;
+ UINT8 otc_ver ;
+ BOOLEAN old_tape ;
+ UINT32 eom_file_id ;
+ UINT32 eom_dir_id ;
+ UINT32 eset_base_addr ;
+
+} F40_ENV, *F40_ENV_PTR ;
+
+/**/
+
+#define F40_INIT_UTIL_BUFF_SIZE 2048
+#define F40_UTIL_BUFF_INC 512
+
+#define F40_INIT_OTC_BUFF_SIZE 2048
+#define F40_OTC_BUFF_INC 512
+
+#define F40_INIT_DIR_LINKS_SIZE 100
+#define F40_DIR_LINKS_INC 25
+
+/* For first parameter to OTC_Close function if F40_OTC.C */
+#define OTC_CLOSE_FDD 0
+#define OTC_CLOSE_SM 1
+#define OTC_CLOSE_ALL 2
+
+/* Returns from FDD block determiner (also used to store type of last
+ FDD entry written in case we need to go back and mark it corrupt).
+*/
+#define FDD_UNKNOWN_BLK 0
+#define FDD_VOL_BLK 1
+#define FDD_DIR_BLK 2
+#define FDD_FILE_BLK 3
+#define FDD_END_BLK 4
+#define FDD_DBDB_BLK 5
+
+/* For translating old MTF tapes where the attribute bits were screwed up. */
+
+#define OLD_VCB_COPY_SET BIT9 // new: BIT1
+#define OLD_VCB_NORMAL_SET BIT10 // new: BIT2
+#define OLD_VCB_DIFFERENTIAL_SET BIT11 // new: BIT3
+#define OLD_VCB_INCREMENTAL_SET BIT12 // new: BIT4
+#define OLD_VCB_DAILY_SET BIT13 // new: BIT5
+#define OLD_VCB_ARCHIVE_BIT BIT1 // new: BIT0
+#define OLD_DIR_EMPTY_BIT BIT1 // new: BIT16
+#define OLD_DIR_PATH_IN_STREAM_BIT BIT2 // new: BIT17
+#define OLD_FILE_IN_USE_BIT BIT1 // new: BIT16
+#define OLD_FILE_NAME_IN_STREAM_BIT BIT2 // new: BIT17
+#define OLD_OBJ_CORRUPT_BIT BIT15 // new: BIT18
+#define OLD_CFDB_LENGTH_CHANGE_BIT BIT0 // new: BIT16
+#define OLD_CFDB_UNREADABLE_BLK_BIT BIT1 // new: BIT17
+#define OLD_CFDB_DEADLOCK_BIT BIT2 // new: BIT18
+
+
+/**
+ Driver call macro:
+
+ Input : 1. Drive handle
+ 2. Function call (with parameters)
+ 3. Driver call return buffer (RET_BUF)
+ 4. Expected error return from driver call
+ 5. Expected error return from driver call
+ 6. Statement or block of statements to be
+ executed on failure
+
+ This macro makes the requested driver call, does the TpReceive
+ if necessary, and handles any error which you do not indicate
+ is expected.
+
+ The function using the macro MUST be of type INT16 since TFLE_xxx
+ will be automatically returned on error.
+
+ If you have only one allowable error, you must supply it as
+ exp1 and exp2. If you have more allowable, this macro will
+ not work for you.
+
+ NOTE: This macro is NOT intended or appropriate for all driver
+ calls. It is used mostly for OTC code to clean up and
+ simplify functions which made several driver calls.
+**/
+
+#define DRIVER_CALL( hndl, func, rb, exp1, exp2, cleanup ) \
+ \
+ if( func == SUCCESS ) { \
+ while( TpReceive( hndl, &rb ) == FAILURE ) { \
+ ThreadSwitch( ) ; \
+ } \
+ if( rb.gen_error != exp1 && rb.gen_error != exp2 ) { \
+ cleanup ; \
+ return( TFLE_DRIVE_FAILURE ) ; \
+ } \
+ } else { \
+ cleanup ; \
+ return( TFLE_DRIVER_FAILURE ) ; \
+ }
+
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/mem.h b/private/utils/ntbackup/inc/mem.h
new file mode 100644
index 000000000..92ed619ce
--- /dev/null
+++ b/private/utils/ntbackup/inc/mem.h
@@ -0,0 +1,113 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: mem_prv.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file describes all the data structures internal kept
+ by the MaynStream memory functions.
+
+ Note: All addresses are saved as paragraphs.
+
+ Location:
+
+
+ $Log: P:/LOGFILES/MEM.H_V $
+ *
+ * Rev 1.2 20 Dec 1991 13:27:08 STEVEN
+ * far not necessary because we do everything in LARG model
+ *
+ * Rev 1.1 25 Jun 1991 17:13:20 BARRY
+ * Made bit-field declarations shorts instead of ints.
+ *
+ * Rev 1.0 09 May 1991 13:33:18 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+#ifndef MEM_H
+
+#define MEM_H
+
+#define MEM_ALLOCATED_BLK 0
+#define MEM_FREE_BLK 1
+
+#define MEM_THRESHOLD ( 8 * 1024 )
+
+typedef struct {
+ unsigned short blk_type:1 ;
+ unsigned short size:15 ;
+} BLK_DEF, *BLK_DEF_PTR ;
+
+typedef struct {
+ BLK_DEF blk_def ;
+ UINT16 next_larger_blk ; /* paragraph containing the location of the
+ next larger block */
+ UINT16 next_smaller_blk ; /* paragraph containing the location of the
+ next smaller block */
+ UINT16 next_same_blk ; /* paragraph containing the location of a
+ block of the same size */
+} FREE_BLK, *FREE_BLK_PTR ;
+
+typedef struct {
+ BLK_DEF blk_def ;
+ CHAR data[1] ; /* data area for the allocated block */
+} ALLOC_BLK, *ALLOC_BLK_PTR ;
+
+typedef struct {
+ CHAR data[14] ;
+ unsigned short blk_type:1 ;
+ unsigned short size:15 ;
+} TOP_BLK, *TOP_BLK_PTR ;
+
+typedef struct {
+ UINT32 num_allocs ;
+ UINT16 pool_size ; /* Size of the pool in paragraphs */
+ UINT16 pool_left ; /* size of the pool remaining */
+ UINT16 pool_ptr ; /* first paragraph of requested block */
+ UINT16 buf_size_threshold ; /* Size specifying whether buffers are allocated
+ from the top or bottom of the pool */
+ FREE_BLK_PTR first_free ;
+ FREE_BLK_PTR last_free ;
+} MEM_STR, *MEM_STR_PTR ;
+
+/* This structure is used for debugging purposes */
+#ifdef MEM_DEBUG
+typedef struct {
+ CHAR fname[10] ;
+ INT16 line_num ;
+} DBG_ALLOC, *DBG_ALLOC_PTR ;
+#endif
+
+/* Define external global memory structure */
+extern MEM_STR gb_dos_pool ;
+extern MEM_STR gb_ems_pool ;
+extern BOOLEAN gb_ems_avail ;
+
+/* Define Function Prototypes */
+UINT16 MemDOSInit( UINT16 ) ;
+VOID InsertFreeBlock( MEM_STR_PTR, FREE_BLK_PTR, UINT16 ) ;
+VOID RemoveFreeBlock( MEM_STR_PTR, FREE_BLK_PTR ) ;
+
+/* Define DOS memory macros */
+#define MemAvail( ) ( ( UINT32 ) gb_dos_pool.pool_left << 4 )
+#define MemMax( ) ( ( UINT32 ) gb_dos_pool.last_free->blk_def.size << 4 )
+
+/* Define EMS memory support routines */
+UINT16 MemEMSInit( UINT16 ) ;
+VOID MemEMSDeInit( VOID ) ;
+VOID_PTR EMSmalloc( size_t ) ;
+VOID_PTR EMScalloc( size_t, size_t ) ;
+VOID EMSfree( VOID_PTR ) ;
+
+/* Define EMS memory macros */
+#define EMSMemAvail( ) ( ( UINT32 ) gb_ems_pool.pool_left << 4 )
+#define EMSMemMax( ) ( ( UINT32 ) gb_ems_pool.last_free->blk_def.size << 4 )
+
+/* Definition to convert paragraphs to pointers and vice versa */
+#define MakePtrFromPgraph( paragraph ) ( ( ( VOID_PTR ) ( ( UINT32 ) ( paragraph ) << 16 ) ) )
+#define MakePgraphFromPtr( ptr ) ( ( UINT16 ) ( ( UINT32 ) ( ( UINT32 ) ( ptr ) ) >> 16 ) )
+
+#endif
diff --git a/private/utils/ntbackup/inc/memmang.h b/private/utils/ntbackup/inc/memmang.h
new file mode 100644
index 000000000..4b63de641
--- /dev/null
+++ b/private/utils/ntbackup/inc/memmang.h
@@ -0,0 +1,125 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: memmang.h
+
+ Description: This file contains the definitions, macros, and function
+ prototypes for the MaynStream GUI Memory Manger (MEM).
+
+ $Log: J:\ui\logfiles\memmang.h_v $
+
+ Rev 1.6.1.0 24 Jan 1994 15:14:24 GREGG
+Added file name and line number to debug alloc functions.
+
+ Rev 1.6 20 Jan 1993 19:55:16 MIKEP
+add nt memory display
+
+ Rev 1.5 04 Oct 1992 19:47:48 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.4 01 Apr 1992 11:51:38 STEVEN
+added memmory manager for WIN32
+
+ Rev 1.3 04 Feb 1992 16:06:26 STEVEN
+MEM_Init should be stubed out with a SUCCESS
+
+ Rev 1.2 31 Jan 1992 16:06:18 DAVEV
+added include <malloc.h> if compiling for NT version only
+
+ Rev 1.1 15 Jan 1992 15:22:30 DAVEV
+16/32 bit port-2nd pass
+
+ Rev 1.0 20 Nov 1991 19:38:46 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+#ifndef SS_MEM_H
+
+#define SS_MEM_H
+
+// Global Variables -- put in appropriate header file.
+
+extern UINT gunSegCount;
+extern ULONG gulMemAvail;
+extern ULONG gulMemUsed;
+extern BOOL gfShowMemory;
+
+
+/*=======================================================================*/
+#ifdef OS_WIN32 /* 32-bit Windows/NT ONLY */
+/*=======================================================================*/
+
+# include <malloc.h>
+ // No memory management routines needed for NT - just use std C functions
+
+ INT MEM_StartShowMemory( VOID );
+ INT MEM_StopShowMemory( VOID );
+
+#ifdef MEM_DEBUG
+
+ PVOID MEM_Malloc( UINT, ACHAR_PTR, INT );
+ PVOID MEM_Calloc( UINT, UINT, ACHAR_PTR, INT );
+ VOID MEM_Free( PVOID, ACHAR_PTR, INT );
+ PVOID MEM_ReAlloc( PVOID, UINT, ACHAR_PTR, INT );
+
+# define malloc( x ) MEM_Malloc( x, __FILE__, __LINE__ )
+# define calloc( x, y ) MEM_Calloc( x, y, __FILE__, __LINE__ )
+# define free( x ) MEM_Free( x, __FILE__, __LINE__ )
+# define realloc( x, y ) MEM_ReAlloc( x, y, __FILE__, __LINE__ )
+
+#else
+
+ PVOID MEM_Malloc( UINT );
+ PVOID MEM_Calloc( UINT, UINT );
+ VOID MEM_Free( PVOID );
+ PVOID MEM_ReAlloc( PVOID, UINT );
+
+# define malloc( x ) MEM_Malloc( x )
+# define calloc( x, y ) MEM_Calloc( x, y )
+# define free( x ) MEM_Free( x )
+# define realloc( x, y ) MEM_ReAlloc( x, y )
+
+#endif
+
+# define MEM_Init() (SUCCESS)
+# define MEM_Deinit() (SUCCESS)
+
+ //Note: MEM_TapeBufAlloc/Free only used in MEMMANG.C
+
+/*=======================================================================*/
+#else /* 16-bit Windows/DOS ONLY */
+/*=======================================================================*/
+
+ // GUI Function Prototypes
+
+
+ BOOL MEM_Init( VOID );
+ BOOL MEM_Deinit( VOID );
+ PVOID MEM_Malloc( UINT );
+ PVOID MEM_Calloc( UINT, UINT );
+ BOOL MEM_Free( PVOID );
+ PVOID MEM_ReAlloc( PVOID, UINT );
+
+ PVOID MEM_TapeBufAlloc( UINT );
+ VOID MEM_TapeBufFree( PVOID );
+
+# ifdef malloc
+# undef malloc
+# undef calloc
+# undef free
+# undef realloc
+# endif
+
+# define malloc( x ) MEM_Malloc( x )
+# define calloc( x, y ) MEM_Calloc( x, y )
+# define free( x ) MEM_Free( x )
+# define realloc( x, y ) MEM_ReAlloc( x, y )
+
+/*=======================================================================*/
+#endif /* END 16-bit Windows/DOS ONLY */
+/*=======================================================================*/
+
+#endif
diff --git a/private/utils/ntbackup/inc/menumang.h b/private/utils/ntbackup/inc/menumang.h
new file mode 100644
index 000000000..08ab9ab97
--- /dev/null
+++ b/private/utils/ntbackup/inc/menumang.h
@@ -0,0 +1,107 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: menumang.h
+
+ Description: This file contains the definitions, macros, and function
+ prototypes for the MaynStream GUI Menu Manager (MM).
+
+ $Log: G:/UI/LOGFILES/MENUMANG.H_V $
+
+ Rev 1.10 14 May 1993 16:12:32 GLENN
+Fixed MM_IS_MENU_CLOSED for NT. The original NT documentation was wrong - online menu is right.
+
+ Rev 1.9 22 Apr 1993 16:01:54 GLENN
+Added file SORT option support.
+
+ Rev 1.8 09 Apr 1993 14:16:36 GLENN
+Added MM_MENUCLOSED for NT.
+
+ Rev 1.7 04 Oct 1992 19:47:48 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.6 15 Apr 1992 16:48:58 GLENN
+Added MM_ShowMenuStatusHelp() call to show status help only for valid menu IDs.
+
+ Rev 1.5 25 Feb 1992 17:10:12 DAVEV
+changed ntmenus.h to ommenus.h to reflect OEM_MSOFT purpose of file
+
+ Rev 1.4 25 Feb 1992 14:14:18 DAVEV
+Conditionally include 'ntmenus.h' for Win32/NT instead of 'menus.h'
+
+ Rev 1.3 12 Dec 1991 17:13:16 DAVEV
+16/32 bit port -2nd pass
+
+ Rev 1.2 10 Dec 1991 15:52:10 STEVEN
+fix bug in pragma
+
+ Rev 1.1 02 Dec 1991 18:01:08 DAVEV
+16/32 bit Windows port changes
+
+ Rev 1.0 20 Nov 1991 19:38:30 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+#ifndef SS_MM_H
+
+#define SS_MM_H
+
+#ifdef OEM_MSOFT
+# include "omMenus.h"
+#else
+# include "menus.h"
+#endif
+
+//NOTE: the definition of this macro will have to be changed for
+// WIN32! I'm not quite sure what the proper definition should be
+// right now, but this will work for now.
+
+#ifndef OS_WIN32
+
+#define MM_MENUCLOSED 0x0000FFFF
+#define MM_IS_MENU_CLOSED(mp1,mp2) (mp2==MM_MENUCLOSED)
+
+#else //case for WIN32 needed!
+
+#define MM_MENUCLOSED 0xFFFF
+#define MM_IS_MENU_CLOSED(mp1,mp2) (((mp2)==0)&&(HIWORD(mp1)==(WORD)MM_MENUCLOSED))
+
+#endif
+
+// MENU ITEM ENABLE BIT MASKS - for use with WinInfo.dwMenuState.
+
+#define MMDOC_TREEGROUP 0x0000000F
+#define MMDOC_FILEGROUP 0x000000F0
+#define MMDOC_SORTGROUP 0x00000F00
+
+#define MMDOC_TREEANDDIR 0x00000001
+#define MMDOC_TREEONLY 0x00000002
+#define MMDOC_DIRONLY 0x00000004
+
+#define MMDOC_NAMEONLY 0x00000010
+#define MMDOC_FILEDETAILS 0x00000020
+
+#define MMDOC_SORTNAME 0x00000100
+#define MMDOC_SORTTYPE 0x00000200
+#define MMDOC_SORTSIZE 0x00000400
+#define MMDOC_SORTDATE 0x00000800
+
+// MACROS
+
+#define MM_HasTreeMenu( x ) ( x & MMDOC_TREEGROUP )
+#define MM_HasViewMenu( x ) ( x & MMDOC_TREEGROUP )
+
+
+// FUNCTION PROTOTYPES
+
+VOID MM_Init ( HMENU );
+LPSTR MM_GetJobNameFromMenu ( WORD, LPSTR );
+BOOL MM_MenuCmdHandler ( HWND, WORD );
+VOID MM_ShowMenuStatusHelp ( WORD );
+
+#endif
+
+
diff --git a/private/utils/ntbackup/inc/menus.h b/private/utils/ntbackup/inc/menus.h
new file mode 100644
index 000000000..91010075f
--- /dev/null
+++ b/private/utils/ntbackup/inc/menus.h
@@ -0,0 +1,141 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: menus.h
+
+ Description: This file contains the MENU IDs for the Maynstream GUI
+ project.
+
+ $Log: G:/UI/LOGFILES/MENUS.H_V $
+
+ Rev 1.8 22 Apr 1993 16:02:04 GLENN
+Added file SORT option support.
+
+ Rev 1.7 02 Apr 1993 14:00:08 GLENN
+Overhauled the numbering -- it really needed it.
+
+ Rev 1.6 10 Mar 1993 12:52:12 CARLS
+Changes to move Format tape to the Operations menu
+
+ Rev 1.5 04 Oct 1992 19:47:50 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.4 08 Sep 1992 15:51:12 DARRYLP
+Added Connect, Disconnect and Fonts items.
+
+ Rev 1.3 02 Mar 1992 11:29:08 DAVEV
+Added checking to disallow multiple inclusions of this file
+
+ Rev 1.2 10 Feb 1992 09:13:34 GLENN
+Changed Settings - Options to Settings - General.
+
+ Rev 1.1 07 Jan 1992 17:23:48 GLENN
+Added MDI split/slider support
+
+ Rev 1.0 20 Nov 1991 19:37:58 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+#ifndef MENUS_H_INCL // Do not allow multiple inclusions of this file
+#define MENUS_H_INCL
+
+
+#define WINDOWSMENUPOSITION 7 // position of window menu.
+#define JOBSMENUPOSITION 5 // position of the jobs menu
+#define JOBSMENUSEPARATORPOS 1 // position of the jobs menu job names separator
+
+// MENU ID RANGES
+
+#define MM_ID_MIN 1000
+#define MM_ID_MAX 2999
+
+#define IDM_WINDOWSFIRSTCHILD 2000 // menu ID of the first MDI Child
+#define IDM_JOBSFIRSTJOB 2100 // menu ID of the first JOB
+#define IDM_JOBSLASTJOB 2199 // menu ID of the last JOB
+
+// MENU ID's
+
+#define IDRM_MAINMENU ID(1)
+
+#define IDM_FILE 1000
+#define IDM_FILEPRINT 1001
+#define IDM_FILESETUP 1002
+#define IDM_FILEEXIT 1003
+
+#define IDM_TREE 1100
+#define IDM_TREEEXPANDONE 1101
+#define IDM_TREEEXPANDBRANCH 1102
+#define IDM_TREEEXPANDALL 1103
+#define IDM_TREECOLLAPSEBRANCH 1104
+
+#define IDM_VIEW 1200
+#define IDM_VIEWTREEANDDIR 1201
+#define IDM_VIEWTREEONLY 1202
+#define IDM_VIEWDIRONLY 1203
+#define IDM_VIEWSPLIT 1204
+#define IDM_VIEWALLFILEDETAILS 1205
+#define IDM_VIEWSORTNAME 1206
+#define IDM_VIEWSORTTYPE 1207
+#define IDM_VIEWSORTSIZE 1208
+#define IDM_VIEWSORTDATE 1209
+#define IDM_VIEWFONT 1210
+
+#define IDM_OPERATIONS 1300
+#define IDM_OPERATIONSBACKUP 1301
+#define IDM_OPERATIONSRESTORE 1302
+#define IDM_OPERATIONSTRANSFER 1303
+#define IDM_OPERATIONSVERIFY 1304
+#define IDM_OPERATIONSINFO 1305
+#define IDM_OPERATIONSCATALOG 1306
+#define IDM_OPERATIONSCATMAINT 1307
+#define IDM_OPERATIONSSEARCH 1308
+#define IDM_OPERATIONSNEXTSET 1309
+#define IDM_OPERATIONSEJECT 1310
+#define IDM_OPERATIONSERASE 1311
+#define IDM_OPERATIONSRETENSION 1312
+#define IDM_OPERATIONSFORMAT 1313
+#define IDM_OPERATIONSCONNECT 1314
+#define IDM_OPERATIONSDISCON 1315
+
+#define IDM_SELECT 1400
+#define IDM_SELECTCHECK 1401
+#define IDM_SELECTUNCHECK 1402
+#define IDM_SELECTADVANCED 1403
+#define IDM_SELECTSUBDIRS 1404
+#define IDM_SELECTSAVE 1405
+#define IDM_SELECTUSE 1406
+#define IDM_SELECTDELETE 1407
+#define IDM_SELECTCLEAR 1408
+
+#define IDM_JOBS 1500
+#define IDM_JOBMAINTENANCE 1501
+
+#define IDM_SETTINGS 1600
+#define IDM_SETTINGSBACKUP 1601
+#define IDM_SETTINGSRESTORE 1602
+#define IDM_SETTINGSLOGGING 1603
+#define IDM_SETTINGSNETWORK 1604
+#define IDM_SETTINGSCATALOG 1605
+#define IDM_SETTINGSHARDWARE 1606
+#define IDM_SETTINGSDEBUGWINDOW 1607
+#define IDM_SETTINGSGENERAL 1608
+
+#define IDM_WINDOW 1700
+#define IDM_WINDOWSCASCADE 1701
+#define IDM_WINDOWSTILE 1702
+#define IDM_WINDOWSREFRESH 1703
+#define IDM_WINDOWSCLOSEALL 1704
+#define IDM_WINDOWSARRANGEICONS 1705
+
+#define IDM_HELP 1800
+#define IDM_HELPINDEX 1801
+#define IDM_HELPSEARCH 1802
+#define IDM_HELPUSINGHELP 1803
+#define IDM_HELPABOUTWINTERPARK 1804
+
+
+#endif // MENUS_H_INCL
+
diff --git a/private/utils/ntbackup/inc/message.h b/private/utils/ntbackup/inc/message.h
new file mode 100644
index 000000000..91a91c91b
--- /dev/null
+++ b/private/utils/ntbackup/inc/message.h
@@ -0,0 +1,16 @@
+#define IDD_JS_ABORT 123
+#define IDD_JS_BP 119
+#define IDD_JS_CF 136
+#define IDD_JS_DP 139
+#define IDD_JS_DRIVE 127
+#define IDD_JS_ET 121
+#define IDD_JS_FILE 141
+#define IDD_JS_FOLDER 138
+#define IDD_JS_FP 122
+#define IDD_JS_LINE1 125
+#define IDD_JS_LINE2 126
+#define IDD_JS_LISTBOX 131
+#define IDD_JS_NET_NAME 130
+#define IDD_JS_OK 120
+#define IDD_JS_SF 137
+
diff --git a/private/utils/ntbackup/inc/minmax.h b/private/utils/ntbackup/inc/minmax.h
new file mode 100644
index 000000000..1a8a6ffd6
--- /dev/null
+++ b/private/utils/ntbackup/inc/minmax.h
@@ -0,0 +1,27 @@
+/**
+
+ Unit: Tape Format
+
+ Name: minmax.h
+
+ Description: "Inline" functions (macros) for min, max
+
+ $Log: N:/LOGFILES/MINMAX.H_V $
+
+ Rev 1.0 10 Dec 1991 16:59:56 GREGG
+Initial revision.
+
+**/
+
+#if !defined( _MINMAX_H )
+#define _MINMAX_H
+
+#if !defined( MIN )
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+#if !defined( MAX )
+#define MAX(a,b) (((a)>(b))?(a):(b))
+#endif
+
+#endif /* _MINMAX_H */
diff --git a/private/utils/ntbackup/inc/misc.h b/private/utils/ntbackup/inc/misc.h
new file mode 100644
index 000000000..90f4242fb
--- /dev/null
+++ b/private/utils/ntbackup/inc/misc.h
@@ -0,0 +1,27 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: misc.h
+
+ Description:
+
+
+ $Log: G:/UI/LOGFILES/MISC.H_V $
+
+ Rev 1.1 04 Oct 1992 19:47:54 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.0 20 Nov 1991 19:40:26 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifndef _misc_h_
+#define _misc_h_
+
+CHAR g_disk( VOID ) ;
+INT16 s_disk( CHAR disk_letter ) ;
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/ms_qic.h b/private/utils/ntbackup/inc/ms_qic.h
new file mode 100644
index 000000000..5f54f85ee
--- /dev/null
+++ b/private/utils/ntbackup/inc/ms_qic.h
@@ -0,0 +1,7 @@
+#ifndef MS_QIC_RH
+
+#define MS_QIC_RH
+
+#define SES_ENG_MQ 0
+
+#endif
diff --git a/private/utils/ntbackup/inc/ms_scsi.h b/private/utils/ntbackup/inc/ms_scsi.h
new file mode 100644
index 000000000..f1ca30135
--- /dev/null
+++ b/private/utils/ntbackup/inc/ms_scsi.h
@@ -0,0 +1,7 @@
+#ifndef MS_SCSI_RH
+
+#define MS_SCSI_RH
+
+#define SES_ENG_MS 0
+
+#endif
diff --git a/private/utils/ntbackup/inc/msassert.h b/private/utils/ntbackup/inc/msassert.h
new file mode 100644
index 000000000..f90b73f3a
--- /dev/null
+++ b/private/utils/ntbackup/inc/msassert.h
@@ -0,0 +1,84 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: msassert.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+ Location:
+
+
+ $Log: M:/LOGFILES/MSASSERT.H_V $
+ *
+ * Rev 1.8 04 Jan 1994 10:55:06 BARRY
+ * Don't pass expression to function
+ *
+ * Rev 1.7 16 Nov 1993 15:42:04 BARRY
+ * String pointers to assert functions are not CHAR_PTR, they are char *
+ *
+ * Rev 1.6 05 Mar 1993 09:57:10 MIKEP
+ * fix warning for cayman
+ *
+ * Rev 1.5 11 Nov 1992 22:09:46 GREGG
+ * Unicodeized literals.
+ *
+ * Rev 1.4 29 Jul 1992 15:26:20 STEVEN
+ * fix warnings
+ *
+ * Rev 1.3 23 Jul 1992 08:32:20 STEVEN
+ * fix warnings
+ *
+ * Rev 1.2 02 Dec 1991 12:42:58 STEVEN
+ * expresion is 32 bits in 32bit model, should be int not INT16
+ *
+ * Rev 1.1 16 May 1991 09:41:38 DAVIDH
+ * Cast no-op in msassert with a VOID -- clears up Watcom warnings.
+ *
+ * Rev 1.0 09 May 1991 13:32:30 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#if !defined( _msassert_h_ )
+#define _msassert_h_
+
+#if defined(MS_RELEASE)
+
+#if !defined(OS_WIN32)
+# pragma message( "Warning: No msassert code." )
+#endif
+
+/* define macros to no op */
+
+#define msassert(exp) (VOID) 0
+#define mscassert(exp) (VOID) 0
+
+#else
+
+/* Prototypes to the msassert functions */
+VOID msassert_func( char *exp_string, char *file_name, int line );
+VOID mscassert_func( char *exp_string, char *file_name );
+
+#if defined(MSDEBUG)
+
+
+#define msassert(exp) (VOID)((exp) || (msassert_func( #exp, __FILE__, __LINE__ ),0))
+#define mscassert(exp) (VOID)((exp) || (mscassert_func( #exp, __FILE__ ),0))
+
+#else
+#if !defined(OS_WIN32)
+# pragma message( "Warning: no expression strings in msassert code." )
+#endif
+
+#define msassert(exp) (VOID)((exp) || (msassert_func( "", __FILE__, __LINE__ ),0))
+#define mscassert(exp) (VOID)((exp) || (mscassert_func( "", __FILE__ ),0))
+
+#endif
+#endif
+#endif
+
+
diff --git a/private/utils/ntbackup/inc/msg.h b/private/utils/ntbackup/inc/msg.h
new file mode 100644
index 000000000..3b236bb09
--- /dev/null
+++ b/private/utils/ntbackup/inc/msg.h
@@ -0,0 +1,30 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: msg.h
+
+ Description:
+
+
+ $Log: G:/UI/LOGFILES/MSG.H_V $
+
+ Rev 1.1 04 Oct 1992 19:47:54 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.0 20 Nov 1991 19:41:44 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifndef _msg_h_
+#define _msg_h_
+
+VOID mprintf( CHAR_PTR, ... ) ;
+VOID mresprintf( INT16, ... ) ;
+
+VOID open_res_message( INT16 res_id, ... ) ;
+VOID open_message( CHAR_PTR fmt, ... ) ;
+VOID close_message( VOID ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/msgbox.h b/private/utils/ntbackup/inc/msgbox.h
new file mode 100644
index 000000000..9a037f2e4
--- /dev/null
+++ b/private/utils/ntbackup/inc/msgbox.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+JPW
+
+ Name: msgbox.h
+
+ Description: This header file contains defines and structure for
+ message box processing.
+
+ $Log: G:/UI/LOGFILES/MSGBOX.H_V $
+
+ Rev 1.8 04 Mar 1994 16:58:08 STEVEN
+prompt if disk is full
+
+ Rev 1.7 04 Oct 1992 19:47:56 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.6 23 Mar 1992 16:11:26 JOHNWT
+added WMMB_BUT2DEFAULT
+
+ Rev 1.5 22 Mar 1992 12:53:24 JOHNWT
+added WMMB_OKDISABLE
+
+ Rev 1.4 30 Jan 1992 11:41:32 JOHNWT
+moved WMMB_SYSMODAL from msgbox.c
+
+ Rev 1.3 21 Jan 1992 16:52:16 JOHNWT
+changed checkyy to noyycheck flag
+
+ Rev 1.2 24 Nov 1991 13:04:32 JOHNWT
+removed large font on inst line
+
+ Rev 1.1 21 Nov 1991 18:12:10 JOHNWT
+added yy flag check
+
+ Rev 1.0 20 Nov 1991 19:34:26 SYSTEM
+Initial revision.
+
+****************************************************************************/
+
+#ifndef msgbox_h
+#define msgbox_h
+
+/* constants for the wType parameter */
+
+#define WMMB_OK 0x0001
+#define WMMB_RETRYCANCEL 0x0002
+#define WMMB_YESNO 0x0004
+#define WMMB_OKCANCEL 0x0008
+#define WMMB_CONTABORT 0x0010
+#define WMMB_CONTCANCEL 0x0020
+#define WMMB_OKDISABLE 0x0040
+#define WMMB_ABORTRETRYIGNOR 0x0080
+
+#define WMMB_BUT2DEFAULT 0x0400 /* make button 2 the default */
+#define WMMB_NOYYCHECK 0x0800 /* skip check of YY flag */
+#define WMMB_INSTBIG 0x1000 /* use big font for inst text */
+#define WMMB_MSGBIG 0x2000 /* use big font for message text */
+#define WMMB_MSGBIGBOLD 0x4000 /* use big/bold font for msg text */
+#define WMMB_SYSMODAL 0x8000 /* make system modal msg box */
+
+/* constants for the wIcon parameter */
+
+#define WMMB_ICONQUESTION 1
+#define WMMB_ICONSTOP 2
+#define WMMB_ICONINFORMATION 3
+#define WMMB_ICONEXCLAMATION 4
+
+/* constants for the return value from WM_MessageBox */
+
+#define WMMB_IDOK 1 /* affirmative answers */
+#define WMMB_IDRETRY 1
+#define WMMB_IDYES 1
+#define WMMB_IDCONTINUE 1
+
+#define WMMB_IDCANCEL 0 /* negative answers */
+#define WMMB_IDNO 0
+#define WMMB_IDABORT 0
+#define WMMB_IDDISABLE 0
+
+#define WMMB_IDIGNOR 2
+
+/* Function prototypes */
+
+INT WM_MsgBox ( LPSTR, LPSTR, WORD, WORD );
+INT WM_MessageBox ( CHAR_PTR, CHAR_PTR, WORD, WORD, CHAR_PTR, WORD, WORD );
+
+#endif
diff --git a/private/utils/ntbackup/inc/msgboxid.h b/private/utils/ntbackup/inc/msgboxid.h
new file mode 100644
index 000000000..510e369bf
--- /dev/null
+++ b/private/utils/ntbackup/inc/msgboxid.h
@@ -0,0 +1,31 @@
+
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1992
+
+ Name:
+
+ Description: Contains dialog control id's for the generic message box
+
+ $Log: G:/UI/LOGFILES/MSGBOXID.H_V $
+
+ Rev 1.1 04 Oct 1992 19:47:58 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.0 07 Apr 1992 09:38:10 CHUCKB
+Initial revision.
+
+
+*****************************************************/
+
+#ifdef TRANSLATE
+#define IDD_MESSAGE_BOX 280
+#else
+#include "dlg_ids.h"
+#endif
+
+#define IDD_MSG_ICON 100
+#define IDD_MSG_TEXT 101
+#define IDD_MSG_INST 103
+#define IDD_MSG_BUT1 104
+#define IDD_MSG_BUT2 105
+#define IDD_MSG_BUT3 106
diff --git a/private/utils/ntbackup/inc/msii.h b/private/utils/ntbackup/inc/msii.h
new file mode 100644
index 000000000..1bcb61aca
--- /dev/null
+++ b/private/utils/ntbackup/inc/msii.h
@@ -0,0 +1,9 @@
+#ifndef MSII_RH
+
+#define MSII_RH
+
+#define SES_ENG_ERR 0
+#define SES_ENG_MSG 1
+#define SES_ENG_DBUG 2
+
+#endif
diff --git a/private/utils/ntbackup/inc/msinstal.h b/private/utils/ntbackup/inc/msinstal.h
new file mode 100644
index 000000000..4b9c9d712
--- /dev/null
+++ b/private/utils/ntbackup/inc/msinstal.h
@@ -0,0 +1,134 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: msinstal.h
+
+ Description: Include file for INSTALL.c
+
+ Location:
+
+
+ $Log: G:/UI/LOGFILES/MSINSTAL.H_V $
+
+ Rev 1.1 04 Oct 1992 19:48:00 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.0 20 Nov 1991 19:38:10 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifndef MSINSTAL_H
+#define MSINSTAL_H
+
+/*
+ Define the subfunctions of install, and various types and
+ defines as required.
+*/
+
+#define MAXILINES 17
+#define MAXSLINES 8
+#define MAXELINES 8
+
+#define PARAGRAPHS_REQUESTED 5000
+
+#ifdef MAYN_OS2
+#define MAX_DISKETTES 5
+#else
+#define MAX_DISKETTES 6
+#endif
+
+#define LOOP 0
+#define NOT_DONE 1
+#define ERROR 2
+#define DONE 3
+
+#define FOUND 0
+#define NOT_FOUND 1
+#define ALREADY_INSTALLED 2
+
+#define NUM_LANG 7 /* Number of different languages supported */
+#define MAX_FILES_TO_COPY 50 /* somewhat arbitrary value */
+
+struct FILE_LIST_T
+{
+ CHAR_PTR name ;
+ INT16 found ;
+} ;
+
+/* operation values for oper and critcial error handler */
+
+VOID build_def_path( CHAR_PTR ) ;
+INT16 process_path( CHAR_PTR ) ;
+INT16 build_batch_files( CHAR_PTR , CHAR ) ;
+INT16 build_save_diskette( CHAR ) ;
+INT16 display_screen( WINDOW * wp, INT16 id, INT16 ( * get_input_func) ( WINDOW * ) ) ;
+INT16 process_screen( WINDOW *, CHAR_PTR [], INT16, INT16 ( * ) ( WINDOW * ) ) ;
+VOID write_window( WINDOW *, CHAR_PTR [], INT16 ) ;
+INT16 any_key_press( WINDOW * ) ;
+INT16 get_continue( WINDOW * ) ;
+BOOLEAN ask_y_n( WINDOW * ) ;
+BOOLEAN get_right_vol( CHAR_PTR first_file) ;
+INT16 copy_all_files( CHAR_PTR ) ;
+INT16 update_flist( struct FILE_LIST_T [], CHAR_PTR , INT16_PTR ) ;
+BOOLEAN flist_done( struct FILE_LIST_T [] ) ;
+VOID copy_config( FILE * from, FILE * to, INT16_PTR num_buff_ptr, INT16_PTR num_files_ptr ) ;
+INT16 await_exit( WINDOW_PTR wp ) ;
+INT16 get_drive( WINDOW * ) ;
+INT16 await_disk_change( WINDOW *) ;
+INT16 copy_to_diskette( CHAR_PTR ) ;
+BOOLEAN build_config_file( VOID ) ;
+INT16 build_save_autoexec( VOID ) ;
+INT16 await_output_disk( WINDOW *) ;
+VOID terminate( INT16, INT16 ) ;
+INT16 cbrk_handler( VOID ) ;
+INT16 get_retry( WINDOW * ) ;
+INT16 disk_err_handler( INT16, INT16, INT16, INT16 ) ;
+INT16 char_err_handler( INT16, CHAR_PTR ) ;
+VOID file_copy_error( INT16 ) ;
+INT16 get_install_opt2( WINDOW * ) ;
+INT16 get_install_opt3( WINDOW * ) ;
+/* INT16 help( CHAR_PTR, INT16, CHAR [] ) ; */
+INT16 get_backup_server_name( WINDOW_PTR wp ) ;
+/* VOID menu_help( INT16 i[], INT16 j ) ; */
+INT16 confirm_path( WINDOW * ) ;
+VOID append_ps2_list( VOID ) ;
+VOID printmes( INT16 ) ;
+VOID wprintmes( WINDOW *, INT16 ) ;
+BOOLEAN build_flist_for_copy( VOID ) ;
+VOID clean_screen( BOOLEAN error ) ;
+
+
+/*
+ Data defintions
+*/
+
+extern WINDOW *instruction_window ;
+extern WINDOW *status_window ;
+extern WINDOW *error_window ;
+
+extern struct FILE_LIST_T flist[] ;
+extern CHAR msii_path[] ; /* target path */
+extern CHAR bw_help_attr[] ;
+
+
+
+
+/* screen attributes */
+
+extern CHAR error_border[] ;
+extern CHAR menu_border[] ;
+extern INT16 misc_help_session[] ;
+
+/*
+#define NOMEM (-10)
+#define FRMBD (-11)
+#define NFILE (-12)
+#define NOTO (-13)
+#define NODISK (-14)
+#define FRMRD (-15)
+*/
+#define PASSWORD_OPTION 2
+
+#endif
diff --git a/private/utils/ntbackup/inc/mslreq.h b/private/utils/ntbackup/inc/mslreq.h
new file mode 100644
index 000000000..23a4ebf3e
--- /dev/null
+++ b/private/utils/ntbackup/inc/mslreq.h
@@ -0,0 +1,26 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-91
+
+ Name: mslreq.h
+
+ Description: This contains the structure definition for the MSL request
+ structure. This is passed, filled in, to BuildTCB.
+
+ $Log: Q:/LOGFILES/MSLREQ.H_V $
+
+ Rev 1.0 17 Jul 1991 14:51:40 ED
+Initial revision.
+**/
+
+#include "stdtypes.h"
+
+typedef struct {
+ INT16 gen_func_code ; /* generic function code */
+ UINT8_PTR baddr ; /* buffer address */
+ UINT32 length ; /* length of buffer */
+ INT16 misc ; /* miscellaneous */
+ UINT32 parm1 ; /* misc param. */
+} MSL_REQUEST, *MSL_REQUEST_PTR ;
+
+
+
diff --git a/private/utils/ntbackup/inc/msmktemp.h b/private/utils/ntbackup/inc/msmktemp.h
new file mode 100644
index 000000000..771d22bc7
--- /dev/null
+++ b/private/utils/ntbackup/inc/msmktemp.h
@@ -0,0 +1,10 @@
+/*
+
+ $Log: T:/LOGFILES/MSMKTEMP.H_V $
+
+ Rev 1.0 14 Oct 1993 18:20:16 GREGG
+Initial revision.
+
+*/
+
+CHAR_PTR msmktemp( CHAR_PTR template ) ;
diff --git a/private/utils/ntbackup/inc/mtf.h b/private/utils/ntbackup/inc/mtf.h
new file mode 100644
index 000000000..29516a0fe
--- /dev/null
+++ b/private/utils/ntbackup/inc/mtf.h
@@ -0,0 +1,512 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-92
+
+
+ Name: mtf.h
+
+ Description: Microsoft Tape Format v1.0 tape structure definitions
+ and attribute bit definitions.
+
+
+ $Log: T:/LOGFILES/MTF.H_V $
+
+ Rev 1.6 20 Jun 1993 16:19:56 GREGG
+Changed data encrypt bit def and replaced compr algor with vendor id in SSET.
+
+ Rev 1.5 26 Apr 1993 11:45:48 GREGG
+Seventh in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Changed handling of EOM processing during non-OTC EOS processing.
+
+Matches CHANNEL.H 1.17, MAYN40RD.C 1.60, TFWRITE.C 1.63, MTF.H 1.5,
+ TFLUTILS.C 1.44, MTF10WDB.C 1.10, MTF10WT.C 1.9
+
+ Rev 1.4 22 Apr 1993 03:31:38 GREGG
+Third in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Removed all references to the DBLK element 'string_storage_offset',
+ which no longer exists.
+ - Check for incompatable versions of the Tape Format and OTC and deals
+ with them the best it can, or reports tape as foreign if they're too
+ far out. Includes ignoring the OTC and not allowing append if the
+ OTC on tape is a future rev, different type, or on an alternate
+ partition.
+ - Updated OTC "location" attribute bits, and changed definition of
+ CFIL to store stream number instead of stream ID.
+
+Matches: TFL_ERR.H 1.9, MTF10WDB.C 1.7, TRANSLAT.C 1.39, FMTINF.H 1.11,
+ OTC40RD.C 1.24, MAYN40RD.C 1.56, MTF10WT.C 1.7, OTC40MSC.C 1.20
+ DETFMT.C 1.13, MTF.H 1.4
+
+ Rev 1.3 19 Apr 1993 18:02:30 GREGG
+Second in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ Changes to write version 2 of OTC, and to read both versions.
+
+Matches: mayn40rd.c 1.55, otc40msc.c 1.19, otc40rd.c 1.23, otc40wt.c 1.23,
+ makevcb.c 1.15, fsys.h 1.32, fsys_str.h 1.46, tpos.h 1.16,
+ mayn40.h 1.32, mtf.h 1.3.
+
+NOTE: There are additional changes to the catalogs needed to save the OTC
+ version and put it in the tpos structure before loading the OTC
+ File/Directory Detail. These changes are NOT listed above!
+
+ Rev 1.2 07 Dec 1992 10:20:26 GREGG
+Changes for tf ver moved to SSET, otc ver added to SSET and links added to FDD.
+
+ Rev 1.1 24 Nov 1992 18:18:50 GREGG
+Updates to match MTF document.
+
+ Rev 1.0 23 Nov 1992 14:25:14 GREGG
+Initial revision.
+
+**/
+
+#ifndef _MTF_H_
+#define _MTF_H_
+
+/**/
+/*
+ MTF Constants
+*/
+
+#define FORMAT_VER_MAJOR 1
+#define FORMAT_VER_MINOR 0
+
+#define TAPE_CATALOG_VER 2
+
+#define PW_ENCRYPT_NONE 0
+#define DATA_ENCRYPT_NONE 0
+#define COMPRESS_NONE 0
+#define ECC_NONE 0
+
+#define MTF10_OTC 1
+
+#define LOCAL_TZ 127
+
+
+/*
+ MTF Block Types
+*/
+
+#define MTF_TAPE_N "TAPE" /* Tape Header ID */
+#define MTF_VOLB_N "VOLB" /* Volume Control Block ID */
+#define MTF_SSET_N "SSET" /* Start of Backup Set Description Block ID */
+#define MTF_ESET_N "ESET" /* End of Backup Set Description Block ID */
+#define MTF_EOTM_N "EOTM" /* End of tape, continuation Block ID */
+#define MTF_DIRB_N "DIRB" /* Directory Descriptor Block ID */
+#define MTF_FILE_N "FILE" /* File Descriptor Block ID */
+#define MTF_CFIL_N "CFIL" /* Corrupt File Descriptor Block ID */
+#define MTF_ESPB_N "ESPB" /* End of Set Pad Block */
+#define MTF_SSES_N "SSES"
+#define MTF_ESES_N "ESES"
+
+
+/*
+ DBLK Block Attributes
+
+ The lower 16 bits are reserved for general attribute bits (those
+ which may appear in more than one type of DBLK), the upper 16 are
+ for attributes which are specific to one type of DBLK.
+
+ Note that the block specific bit definitions overlap, and the block
+ type is used to determine the meaning of a given bit.
+*/
+
+/* General : */
+#define MTF_DB_CONT_BIT 0x00000001UL
+#define MTF_DB_COMPRESS_BIT 0x00000004UL
+#define MTF_DB_EOS_AT_EOM_BIT 0x00000008UL
+#define MTF_DB_VAR_BLKS_BIT 0x00000010UL
+#define MTF_DB_SESSION_BIT 0x00000020UL
+
+/* THDR : */
+#define MTF_DB_SM_EXISTS 0x00010000UL
+#define MTF_DB_FDD_ALLOWED 0x00020000UL
+#define MTF_DB_SM_ALT_OVERWRITE 0x00040000UL
+#define MTF_DB_FDD_ALT_PART 0x00080000UL
+#define MTF_DB_SM_ALT_APPEND 0x00200000UL
+
+/* SSET : */
+#define MTF_DB_FDD_EXISTS 0x00010000UL
+#define MTF_DB_ENCRYPT_BIT 0x00020000UL
+
+/* ESET : */
+#define MTF_DB_FDD_ABORTED_BIT 0x00010000UL
+#define MTF_DB_END_OF_FAMILY_BIT 0x00020000UL
+#define MTF_DB_ABORTED_SET_BIT 0x00040000UL
+#define MTF_DB_SET_VERIFIED_BIT 0x00080000UL
+
+/* EOTM : */
+#define MTF_DB_NO_ESET_PBA 0x00010000UL
+#define MTF_DB_INVALID_ESET_PBA 0x00020000UL
+
+
+/* Turn on packing here. Need to be sure that date is packed. */
+#pragma pack(1)
+
+/**/
+/*
+ Compressed date structure for storing dates in minimal space on tape:
+
+ BYTE 0 BYTE 1 BYTE 2 BYTE 3 BYTE 4
+ 76543210 76543210 76543210 76543210 76543210
+ yyyyyyyy yyyyyymm mmdddddh hhhhmmmm mmssssss
+*/
+typedef struct {
+ UINT8 dt_field[5] ;
+} MTF_DATE_TIME, * MTF_DATE_TIME_PTR ;
+
+
+/**/
+/*
+ Tape Address
+*/
+typedef struct {
+ UINT16 data_size; /* Size of the data */
+ UINT16 data_offset; /* Offset to the data */
+} MTF_TAPE_ADDRESS, * MTF_TAPE_ADDRESS_PTR;
+
+
+/**/
+/*
+ Stream Header
+*/
+typedef struct {
+ UINT32 id ; /* Identifier for stream */
+ UINT16 fs_attribs ; /* FileSystem Attribute */
+ UINT16 tf_attribs ; /* TapeFormat Attributes */
+ UINT64 data_length ; /* Offset to stream */
+ UINT16 encr_algor ; /* Data encryption algorithm */
+ UINT16 comp_algor ; /* Data compression algorithm */
+ UINT16 chksum ; /* Checksum */
+} MTF_STREAM, * MTF_STREAM_PTR ;
+
+
+/**/
+/*
+ Common DBLK Header
+*/
+typedef struct {
+ UINT8 block_type[4] ; /* Unique identifier, see above */
+ UINT32 block_attribs ; /* Common attributes for this block */
+ UINT16 offset_to_data ; /* Offset to data associated with this
+ DBLK, or offset to next DBLK or
+ filemark if there is no associated
+ data.
+ */
+ UINT8 machine_os_id ; /* Machine/OS id where written, low byte */
+ UINT8 machine_os_version ; /* Machine/OS id where written, high byte */
+ UINT64 displayable_size ; /* Displayable data size */
+ UINT64 logical_block_address ; /* Logical blk address relative to SSET */
+ UINT64 session_id ; /* For interleaved streams */
+ UINT32 control_block_id ; /* Used for error recovery */
+
+ UINT8 reserved[4] ; /* Was offset to string storage */
+ MTF_TAPE_ADDRESS os_specific_data ; /* Size and offset of OS specific stuff */
+ UINT8 string_type ; /* ASCII, Unicode, etc. */
+ UINT8 pad ; /* For alignment purposes */
+ UINT16 hdr_chksm ; /* Checksum of the block header. The
+ algorithm is: XOR each word preceeding
+ this one and store the result here.
+ (When the checksum is verified the
+ 'block_type' is also checked for a
+ non-zero value.
+ */
+} MTF_DB_HDR, * MTF_DB_HDR_PTR ;
+
+
+/**/
+/*
+ Tape Header DBLK (TAPE)
+*/
+typedef struct {
+ MTF_DB_HDR block_header;
+ UINT32 tape_id_number ;
+ UINT32 tape_attributes ;
+ UINT16 tape_seq_number ;
+ UINT16 password_encryption_algor;
+ UINT16 ecc_algorithm ;
+ UINT16 tape_catalog_type ;
+ MTF_TAPE_ADDRESS tape_name ;
+ MTF_TAPE_ADDRESS tape_description ;
+ MTF_TAPE_ADDRESS tape_password ;
+ MTF_TAPE_ADDRESS software_name ;
+ UINT16 logical_block_size ;
+ UINT16 software_vendor_id ;
+ MTF_DATE_TIME tape_date ;
+ UINT8 tf_major_ver ;
+} MTF_TAPE, * MTF_TAPE_PTR;
+
+
+/**/
+/*
+ Start of Set DBLK (SSET)
+*/
+typedef struct {
+ MTF_DB_HDR block_hdr ;
+ UINT32 sset_attribs ;
+ UINT16 password_encryption_algor ;
+ UINT16 data_encryption_algor ;
+ UINT16 software_vendor_id ;
+ UINT16 backup_set_number ;
+ MTF_TAPE_ADDRESS backup_set_name ;
+ MTF_TAPE_ADDRESS backup_set_description ;
+ MTF_TAPE_ADDRESS backup_set_password ;
+ MTF_TAPE_ADDRESS user_name ;
+ UINT64 physical_block_address ;
+ MTF_DATE_TIME backup_date ;
+ UINT8 software_ver_mjr ;
+ UINT8 software_ver_mnr ;
+ INT8 time_zone ;
+ UINT8 tf_minor_ver ;
+ UINT8 tape_cat_ver ;
+} MTF_SSET, * MTF_SSET_PTR ;
+
+
+/**/
+/*
+ Volume DBLK (VOLB)
+*/
+typedef struct {
+ MTF_DB_HDR block_hdr ;
+ UINT32 volume_attribs ;
+ MTF_TAPE_ADDRESS device_name ;
+ MTF_TAPE_ADDRESS volume_name ;
+ MTF_TAPE_ADDRESS machine_name ;
+ MTF_DATE_TIME backup_date ;
+} MTF_VOL, * MTF_VOL_PTR ;
+
+
+/**/
+/*
+ Directory DBLK (DIRB)
+*/
+typedef struct {
+ MTF_DB_HDR block_hdr ;
+ UINT32 directory_attribs ;
+ MTF_DATE_TIME last_mod_date ;
+ MTF_DATE_TIME create_date ;
+ MTF_DATE_TIME backup_date ;
+ MTF_DATE_TIME last_access_date ;
+ UINT32 directory_id ;
+ MTF_TAPE_ADDRESS directory_name ;
+} MTF_DIR, * MTF_DIR_PTR ;
+
+
+/**/
+/*
+ File DBLK (FILE)
+*/
+typedef struct {
+ MTF_DB_HDR block_hdr ;
+ UINT32 file_attributes ;
+ MTF_DATE_TIME last_mod_date ;
+ MTF_DATE_TIME create_date ;
+ MTF_DATE_TIME backup_date ;
+ MTF_DATE_TIME last_access_date ;
+ UINT32 directory_id ;
+ UINT32 file_id ;
+ MTF_TAPE_ADDRESS file_name ;
+} MTF_FILE, * MTF_FILE_PTR ;
+
+
+/**/
+/*
+ Corrupt File DBLK (CFIL)
+*/
+typedef struct {
+ MTF_DB_HDR block_hdr ;
+ UINT32 corrupt_file_attribs ;
+ UINT32 file_id ;
+ UINT32 directory_id ;
+ UINT64 stream_offset ;
+ UINT16 corrupt_stream_number ;
+} MTF_CFIL, * MTF_CFIL_PTR ;
+
+
+/**/
+/*
+ Start of Set DBLK (ESET)
+*/
+typedef struct {
+ MTF_DB_HDR block_hdr ;
+ UINT32 eset_attribs ;
+ UINT32 corrupt_file_count ;
+ UINT64 set_map_phys_blk_adr ;
+ UINT64 fdd_phys_blk_adr ;
+ UINT16 fdd_tape_seq_number ;
+ UINT16 backup_set_number ;
+ MTF_DATE_TIME backup_date ;
+} MTF_ESET, * MTF_ESET_PTR ;
+
+
+/**/
+/*
+ End of Tape DBLK (EOTM)
+*/
+typedef struct {
+ MTF_DB_HDR block_hdr;
+ UINT64 eset_phys_blk_adr ;
+} MTF_EOTM, * MTF_EOTM_PTR;
+
+
+/**/
+/*
+ End of Set Pad DBLK (ESPB)
+*/
+typedef struct {
+ MTF_DB_HDR block_hdr ;
+} MTF_ESPB, * MTF_ESPB_PTR ;
+
+
+
+/***************************************************************************\
+
+ MTF On Tape Catalog Structures
+
+\***************************************************************************/
+
+/**/
+/*
+ Set Map Header
+*/
+typedef struct {
+ UINT32 family_id ;
+ UINT16 num_set_recs ;
+ UINT8 pad[2] ;
+} MTF_SM_HDR, * MTF_SM_HDR_PTR ;
+
+
+/**/
+/*
+ Set Map Entry
+*/
+typedef struct {
+ UINT16 length ;
+ UINT16 seq_num ;
+ UINT32 blk_attribs ;
+ UINT32 set_attribs ;
+ UINT64 sset_pba ;
+ UINT64 fdd_pba ;
+ UINT16 fdd_seq_num ;
+ UINT16 set_num ;
+ UINT64 lba ;
+ UINT32 num_dirs ;
+ UINT32 num_files ;
+ UINT32 num_corrupt_files ;
+ UINT64 disp_size ;
+ UINT16 num_volumes ;
+ UINT16 pswd_encr_algor ;
+ MTF_TAPE_ADDRESS set_name ;
+ MTF_TAPE_ADDRESS password ;
+ MTF_TAPE_ADDRESS set_descr ;
+ MTF_TAPE_ADDRESS user_name ;
+ MTF_DATE_TIME backup_date ;
+ INT8 time_zone ;
+ UINT8 os_id ;
+ UINT8 os_ver ;
+ UINT8 string_type ;
+ UINT8 tf_minor_ver ;
+ UINT8 tape_cat_ver ;
+} MTF_SM_ENTRY, * MTF_SM_ENTRY_PTR ;
+
+
+/**/
+/*
+ File / Directory Detail Common Header
+*/
+typedef struct {
+ UINT16 length ;
+ UINT8 type[4] ;
+ UINT16 seq_num ;
+ UINT32 blk_attribs ;
+ UINT64 lba ;
+ UINT64 disp_size ;
+ INT32 link ;
+ UINT8 os_id ;
+ UINT8 os_ver ;
+ UINT8 string_type ;
+ UINT8 pad ;
+} MTF_FDD_HDR, * MTF_FDD_HDR_PTR ;
+
+
+/**/
+/*
+ File / Directory Detail and Set Map Volume Entry
+*/
+typedef struct {
+ UINT32 vol_attribs ;
+ MTF_TAPE_ADDRESS device_name ;
+ MTF_TAPE_ADDRESS vol_name ;
+ MTF_TAPE_ADDRESS machine_name ;
+ MTF_DATE_TIME backup_date ;
+} MTF_FDD_VOL_V1, * MTF_FDD_VOL_V1_PTR ;
+
+typedef struct {
+ UINT32 vol_attribs ;
+ MTF_TAPE_ADDRESS device_name ;
+ MTF_TAPE_ADDRESS vol_name ;
+ MTF_TAPE_ADDRESS machine_name ;
+ MTF_TAPE_ADDRESS os_info ;
+ MTF_DATE_TIME backup_date ;
+} MTF_FDD_VOL_V2, * MTF_FDD_VOL_V2_PTR ;
+
+
+/**/
+/*
+ File / Directory Detail Directory Entry
+*/
+typedef struct {
+ MTF_DATE_TIME last_mod_date ;
+ MTF_DATE_TIME create_date ;
+ MTF_DATE_TIME backup_date ;
+ MTF_DATE_TIME last_access_date ;
+ UINT32 dir_attribs ;
+ MTF_TAPE_ADDRESS dir_name ;
+} MTF_FDD_DIR_V1, * MTF_FDD_DIR_V1_PTR ;
+
+typedef struct {
+ MTF_DATE_TIME last_mod_date ;
+ MTF_DATE_TIME create_date ;
+ MTF_DATE_TIME backup_date ;
+ MTF_DATE_TIME last_access_date ;
+ UINT32 dir_attribs ;
+ MTF_TAPE_ADDRESS dir_name ;
+ MTF_TAPE_ADDRESS os_info ;
+} MTF_FDD_DIR_V2, * MTF_FDD_DIR_V2_PTR ;
+
+
+/**/
+/*
+ File / Directory Detail File Entry
+*/
+typedef struct {
+ MTF_DATE_TIME last_mod_date ;
+ MTF_DATE_TIME create_date ;
+ MTF_DATE_TIME backup_date ;
+ MTF_DATE_TIME last_access_date ;
+ UINT32 file_attribs ;
+ MTF_TAPE_ADDRESS file_name ;
+} MTF_FDD_FILE_V1, * MTF_FDD_FILE_V1_PTR ;
+
+typedef struct {
+ MTF_DATE_TIME last_mod_date ;
+ MTF_DATE_TIME create_date ;
+ MTF_DATE_TIME backup_date ;
+ MTF_DATE_TIME last_access_date ;
+ UINT32 file_attribs ;
+ MTF_TAPE_ADDRESS file_name ;
+ MTF_TAPE_ADDRESS os_info ;
+} MTF_FDD_FILE_V2, * MTF_FDD_FILE_V2_PTR ;
+
+
+/* Turn packing back to what was specified on command line, or default
+ packing.
+*/
+#pragma pack()
+
+#endif
diff --git a/private/utils/ntbackup/inc/mui.h b/private/utils/ntbackup/inc/mui.h
new file mode 100644
index 000000000..d56996795
--- /dev/null
+++ b/private/utils/ntbackup/inc/mui.h
@@ -0,0 +1,154 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: mui.h
+
+ Description: This file describes all the APIs and data structures
+ kept by the MaynStream User Interface (MUI) functions.
+
+ $Log: G:\ui\logfiles\mui.h_v $
+
+ Rev 1.22 21 Jul 1993 16:55:24 GLENN
+Added operation queing support.
+
+ Rev 1.21 15 Jul 1993 14:47:26 CARLS
+added skipno.h
+
+ Rev 1.20 30 Apr 1993 17:59:20 Aaron
+Removed OS_WIN32 condition on inclusion of ombatch.h
+
+ Rev 1.19 02 Apr 1993 13:52:24 GLENN
+Added MUI_IsInfoAvailable() and MUI_SetInfoAvailable().
+
+ Rev 1.18 11 Mar 1993 13:27:38 STEVEN
+add batch
+
+ Rev 1.17 20 Oct 1992 14:20:22 MIKEP
+add support for getcurrentoperation
+
+ Rev 1.16 04 Oct 1992 19:48:04 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.15 10 Sep 1992 17:21:20 GLENN
+Added MUI_IsTapeValid().
+
+ Rev 1.14 27 Jun 1992 10:49:14 MIKEP
+ move qtc.h to bengine.h
+
+ Rev 1.13 29 May 1992 16:05:20 JOHNWT
+PCH updates
+
+ Rev 1.12 19 May 1992 09:27:34 MIKEP
+mo changes
+
+ Rev 1.11 15 May 1992 13:38:30 MIKEP
+nt pass 2
+
+ Rev 1.10 14 May 1992 17:39:54 MIKEP
+nt pass2
+
+ Rev 1.9 11 May 1992 14:27:40 DAVEV
+OEM_MSOFT: modifications for batch command line support
+
+ Rev 1.8 07 Apr 1992 10:37:02 GLENN
+Added a call back when there is a system change. (future)
+
+ Rev 1.7 20 Mar 1992 17:24:50 GLENN
+Split out selection bar/ribbon stuff into muibar.c/h
+
+ Rev 1.6 03 Mar 1992 17:26:12 GLENN
+Added return type to MUI_StartOperation().
+
+ Rev 1.5 06 Feb 1992 11:38:28 CHUCKB
+No change.
+
+ Rev 1.4 06 Feb 1992 11:32:36 CHUCKB
+No change.
+
+ Rev 1.3 31 Jan 1992 12:54:42 GLENN
+Changed chkwh.h to hwcheck.h.
+
+ Rev 1.2 07 Jan 1992 17:22:00 GLENN
+Added header
+
+ Rev 1.1 04 Dec 1991 18:14:04 GLENN
+
+ Rev 1.0 20 Nov 1991 19:40:36 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+
+#ifndef MUI_H
+#define MUI_H
+
+#include "stats.h"
+#include "tape.h"
+#include "muiconf.h"
+#include "muiutil.h"
+#include "muibar.h"
+#include "rm.h"
+#include "res_io.h"
+#include "script.h"
+#include "log.h"
+#include "script_p.h"
+#include "scriperr.h"
+#include "error.h"
+#include "tbe_defs.h"
+#include "hwcheck.h"
+#include "details.h"
+#include "do_misc.h"
+#include "status.h"
+#include "global.h"
+#include "vlm.h"
+#include "std_err.h"
+#include "msii.h"
+#include "eng_msg.h"
+#include "eng_err.h"
+#include "do_misc.h"
+#include "be_init.h"
+#include "debug.h"
+#include "genstat.h"
+#include "jobstat.h"
+#include "polldrv.h"
+#include "password.h"
+#include "pdtypes.h"
+#include "vlm_find.h"
+#include "schedule.h"
+#include "d_o_bkup.h"
+#include "d_o_rset.h"
+#include "filerepl.h"
+#include "skipno.h"
+#include "ld_dvr.h"
+#include "lstdres.h"
+#include "hwconf.h"
+#include "dlm_prv.h"
+#include "dateutil.h"
+#include "jobs.h"
+#include "ombatch.h"
+
+BOOL MUI_Init ( VOID );
+VOID MUI_Deinit ( VOID );
+BOOL MUI_DisableOperations ( WORD );
+BOOL MUI_EnableOperations ( WORD );
+BOOL MUI_StartOperation ( WORD, BOOL );
+VOID MUI_ActivateDocument ( WORD );
+BOOL MUI_ProcessCommandLine ( LPSTR, INT * );
+VOID MUI_TapeInDrive ( BOOL );
+BOOL MUI_IsTapeInDrive ( VOID );
+BOOL MUI_IsTapeValid ( VOID );
+BOOL MUI_IsEjectSupported ( VOID );
+BOOL MUI_IsRetensionSupported ( VOID );
+BOOL MUI_IsInfoAvailable ( VOID );
+VOID MUI_SetInfoAvailable ( BOOL );
+VOID MUI_AdvancedSelections ( VOID );
+VOID MUI_UISystemChange ( VOID );
+
+BOOL MUI_QueueOperation ( UINT );
+VOID MUI_ReleaseQueuedOperation ( VOID );
+BOOL MUI_AnyQueuedOperations ( VOID );
+
+
+#endif
diff --git a/private/utils/ntbackup/inc/muibar.h b/private/utils/ntbackup/inc/muibar.h
new file mode 100644
index 000000000..13abb38f6
--- /dev/null
+++ b/private/utils/ntbackup/inc/muibar.h
@@ -0,0 +1,31 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: muibar.h
+
+ Description: This file describes all the APIs and data structures
+ kept by the MaynStream User Interface (MUI) selection
+ bar functions.
+
+ $Log: G:/UI/LOGFILES/MUIBAR.H_V $
+
+ Rev 1.1 04 Oct 1992 19:48:06 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.0 20 Mar 1992 17:25:06 GLENN
+Initial revision.
+
+******************************************************************************/
+
+
+#ifndef MUIBAR_H
+#define MUIBAR_H
+
+HRIBBON MUI_MakeMainRibbon ( VOID );
+VOID MUI_SetOperationButtons ( WORD );
+VOID MUI_SetActionButtons ( WORD );
+VOID MUI_SetButtonState ( WORD, WORD );
+
+#endif
diff --git a/private/utils/ntbackup/inc/muiconf.h b/private/utils/ntbackup/inc/muiconf.h
new file mode 100644
index 000000000..c1a4ff55e
--- /dev/null
+++ b/private/utils/ntbackup/inc/muiconf.h
@@ -0,0 +1,1376 @@
+/******************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: muiconf.h
+
+ Description:
+
+ $Log: J:\ui\logfiles\muiconf.h_v $
+
+ Rev 1.52.1.2 28 Jan 1994 11:17:20 GREGG
+More warning fixes.
+
+ Rev 1.52.1.1 24 Nov 1993 14:58:00 BARRY
+Fixed Unicode bugs; made font names bigger
+
+ Rev 1.52.1.0 04 Nov 1993 15:44:56 STEVEN
+japanese changes
+
+ Rev 1.52 23 Jul 1993 15:54:20 GLENN
+Added Flag to the ECC read and write macros.
+
+ Rev 1.51 23 Jul 1993 12:20:12 GLENN
+Added Sytron ECC and Drive Settling Time support.
+
+ Rev 1.50 22 Jul 1993 19:11:48 MARINA
+enable c++
+
+ Rev 1.49 21 Jul 1993 17:03:56 GLENN
+Changed the poll drive default frequency from 2 to 1.
+
+ Rev 1.48 19 Jul 1993 09:54:24 CARLS
+change for UseTapeCatalogs
+
+ Rev 1.47 16 Jul 1993 10:40:56 GLENN
+Added UseTapeCatalog and SortOptions support.
+
+ Rev 1.46 30 Jun 1993 16:01:38 CARLS
+added things for UseTapeCatalogs
+
+ Rev 1.45 09 Jun 1993 15:10:00 MIKEP
+enable c++
+
+ Rev 1.44 07 Jun 1993 10:11:12 chrish
+Nostradamus EPR 0490 - Added source to fix command line /r switch.
+
+Added "cmd_line_restrict_access" to the CDS structure, flag set when the /r
+is passed on the command line backup.
+
+Added the two macros below for the /r switch on the command line backup.
+ #define CDS_GetCmdLineRestrictAccess( x )
+ #define CDS_SetCmdLineRestrictAccess( x, v )
+
+ Rev 1.43 07 Jun 1993 10:05:54 GLENN
+Set User and Catalog data paths default to null strings.
+
+ Rev 1.42 18 May 1993 15:05:08 GLENN
+Added tape settling time to hardware data structure.
+
+ Rev 1.41 06 May 1993 17:53:06 KEVINS
+Added s/w, h/w compression, and fixes.
+
+ Rev 1.40 30 Apr 1993 15:56:38 GLENN
+Added INI command line support. Added Data Path setting support.
+
+ Rev 1.39 27 Apr 1993 11:25:08 GLENN
+Added Search tapes with password, Search subdirs, log file prefix.
+
+ Rev 1.38 19 Apr 1993 15:14:34 GLENN
+Fixed FontCaseFAT default, RestoreExistingFiles default.
+
+ Rev 1.37 05 Apr 1993 13:35:04 GLENN
+Changed debug msgs kept from 35 to 150 for MikeP.
+
+ Rev 1.36 28 Jan 1993 16:02:16 STEVEN
+added erase_format
+
+ Rev 1.35 06 Jan 1993 10:19:44 GLENN
+Changed prototype name.
+
+ Rev 1.34 04 Jan 1993 14:40:04 GLENN
+Added File Details and Search Limit items.
+
+ Rev 1.33 23 Dec 1992 15:42:38 GLENN
+Added all file details, runtime dlg pos saving, search limit, FAT drive lower case display.
+
+ Rev 1.32 18 Nov 1992 13:28:12 GLENN
+Changed the INT16 in WINSIZE to INT.
+
+ Rev 1.31 01 Nov 1992 16:31:30 DAVEV
+Unicode changes
+
+ Rev 1.30 30 Oct 1992 15:48:30 GLENN
+Added Frame and MDI Doc window size and position saving and restoring.
+
+ Rev 1.29 14 Oct 1992 15:54:50 GLENN
+Added Font selection to Config and INI.
+
+ Rev 1.28 04 Oct 1992 19:48:10 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.27 02 Oct 1992 16:27:42 STEVEN
+Added BACKUP_DAILY ID.
+
+ Rev 1.26 06 Aug 1992 22:00:30 MIKEP
+add support for tape drive name for nt
+
+ Rev 1.25 29 Jul 1992 14:25:38 GLENN
+ChuckB checked in after NT fixes.
+
+ Rev 1.24 30 Jun 1992 13:01:58 JOHNWT
+added Enable Statistics
+
+ Rev 1.23 19 May 1992 09:27:36 MIKEP
+mo changes
+
+ Rev 1.22 17 Apr 1992 09:20:20 JOHNWT
+added set of BE catalog level
+
+ Rev 1.21 23 Mar 1992 11:54:34 GLENN
+Added bad data and catalog path warning support.
+
+ Rev 1.20 20 Mar 1992 17:21:52 GLENN
+Added std mode warning config option.
+
+ Rev 1.19 27 Feb 1992 11:17:38 JOHNWT
+wait/skip files change
+
+ Rev 1.18 27 Feb 1992 08:15:16 GLENN
+Added SetupExePath and ChangeToExeDir.
+
+ Rev 1.17 23 Feb 1992 14:02:22 GLENN
+Converted GetString/SaveString macros to functions.
+
+ Rev 1.16 18 Feb 1992 18:49:44 GLENN
+Added support routines for auto min/max/restore of MDI docs before/after an operation/
+
+ Rev 1.15 11 Feb 1992 17:35:46 GLENN
+Rearranged variables in conf stuct - to make more sense.
+
+ Rev 1.14 03 Feb 1992 14:35:30 GLENN
+Removed debug flag min/max range limits. It is amask of flags.
+
+ Rev 1.13 03 Feb 1992 14:12:12 JOHNWT
+corrected skip min/max
+
+ Rev 1.12 31 Jan 1992 15:05:26 GLENN
+In process of changing to consolidate skipped files/wait time.
+
+ Rev 1.11 24 Jan 1992 13:48:20 JOHNWT
+changed def launcher timeout to 60
+
+ Rev 1.10 20 Jan 1992 09:43:20 GLENN
+Moved some defines to appdefs.h.
+
+ Rev 1.9 16 Jan 1992 16:48:40 JOHNWT
+added min/max macros
+
+ Rev 1.8 16 Jan 1992 14:59:38 GLENN
+Added restore types.
+
+ Rev 1.7 14 Jan 1992 08:14:00 GLENN
+Added Sort BSD support.
+
+ Rev 1.6 07 Jan 1992 17:27:04 GLENN
+Added catalog data path support
+
+ Rev 1.5 04 Dec 1991 18:17:12 GLENN
+Added machine type macros.
+
+ Rev 1.4 03 Dec 1991 16:32:30 JOHNWT
+added CDS_GetFastFileRestore
+
+ Rev 1.3 22 Nov 1991 13:35:38 DAVEV
+Removed 16-32 bit changes for now - there is a problem with the order in which files are included
+
+ Rev 1.2 22 Nov 1991 11:29:22 DAVEV
+removed $end from muiconf.h
+
+ Rev 1.1 22 Nov 1991 09:42:46 DAVEV
+Added prototype for CDS_SaveCDS. Also changes for 16-32-bit Windows port.
+
+ Rev 1.0 20 Nov 1991 19:40:22 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+
+#ifndef _muiconf_h_
+#define _muiconf_h_
+
+#include <stdio.h>
+
+#include "appdefs.h"
+#include "proddefs.h"
+#include "beconfig.h"
+
+// Since some systems define max and min as functions instead of macros,
+// define a macro for our own max and min macros here.
+
+#define CDS_MIN(x,y) ((x) < (y) ? (x) : (y))
+#define CDS_MAX(x,y) ((x) > (y) ? (x) : (y))
+
+#define DLL_EXTENSION TEXT(".DLL")
+
+// SKIP open files IDs
+
+#define SKIP_NO 0
+#define SKIP_YES 1
+#define SKIP_NO_TIMED 2
+
+#define CDS_STRLEN 255
+
+
+#define MAXTAPEDRIVENAME 80
+
+#define MAXFILENAME 14
+#define MAXDIRNAME 64
+#define MAX_MAYN_FOLDER_SIZE 84
+
+/* enable/disable values */
+#define CDS_DISABLE 0
+#define CDS_ENABLE 1
+#define CDS_UNKNOWN -1
+
+/* erase flag values */
+#define ERASE_OFF 0
+#define ERASE_ON 1
+#define ERASE_LONG 2
+#define ERASE_FMARK 3
+#define ERASE_FORMAT 4
+
+/* log mode options */
+#define LOG_OVERWRITE 0
+#define LOG_APPEND 1
+
+/* output dest */
+#define LOG_NOWHERE 0
+#define LOG_TO_PRINTER 1
+#define LOG_TO_FILE 2
+
+/* log print options */
+#define LOG_PRINT_OFF 0
+#define LOG_PRINT_ON 1
+#define LOG_PRINT_PROMPT 2
+
+/* Log levels */
+#define LOG_DISABLED 0
+#define LOG_ERRORS 1
+#define LOG_DIRS 2
+#define LOG_FILES 3
+#define LOG_DETAIL 4
+
+/* Hardware compression type */ // chs:05-04-93
+#define HW_COMP_DISABLE 0 // chs:05-04-93
+#define HW_COMP_ENABLE 1 // chs:05-04-93
+
+/* Software compression type */ // chs:05-04-93
+#define SW_COMP_DISABLE 0 // chs:05-04-93
+#define SW_COMP_ENABLE 1 // chs:05-04-93
+
+/* Number of sessions to keep */
+#define LOG_DEF_LOGFILES 5
+#define LOG_MIN_LOGFILES 0
+#define LOG_MAX_LOGFILES 100
+
+/* yes flags */
+#define NO_FLAG 0
+#define YES_FLAG 1
+#define YESYES_FLAG 2
+
+/* Auto verify types */
+#define NO_VERIFY_AFTER 0
+#define DO_VERIFY_AFTER 1
+#define PROMPT_VERIFY_AFTER 2
+
+/* command line values */
+#define TMENU_COMMAND_LINE_PROCESSED 0
+#define TMENU_SAVE_MODE 1
+
+/* cataloging levels */
+#define CATALOGS_NONE 0
+#define CATALOGS_PARTIAL 1
+#define CATALOGS_FULL 2
+
+/* network types */
+#define NO_NETWORK 0
+#define NOVELL_NET 1
+#define THREE_COM_NET 2
+#define IBM_PC_NET 3
+#define SOME_NET 4
+
+/* restore types */
+#define RESTORE_OVER_EXISTING 0
+#define NO_RESTORE_OVER_EXISTING 1
+#define PROMPT_RESTORE_OVER_EXISTING 2
+#define NO_RESTORE_OVER_RECENT 3
+#define PROMPT_RESTORE_OVER_RECENT 4
+
+/* backup types */
+#define BACKUP_NORMAL 1
+#define BACKUP_COPY 2
+#define BACKUP_DIFF 3
+#define BACKUP_INCR 4
+#define BACKUP_DAILY 5
+
+/* pwdb min/default */
+#define PWDB_MIN_ENTRIES 5
+#define PWDB_DEF_ENTRIES 50
+
+/* skip wait time min/def */
+#define SKIP_MIN_TIME 0
+#define SKIP_DEF_TIME 30
+
+/* launcher min/def time-out */
+#define LAUNCHER_MIN_TIME 30
+#define LAUNCHER_DEF_TIME 60
+
+/* Poll drive min frequency */
+#define POLL_MIN_FREQ 1
+#define POLL_DEF_FREQ 1
+
+#define MIN_DRIVE_SETTLING_TIME 1
+#define MAX_DRIVE_SETTLING_TIME 300
+#define DEF_DRIVE_SETTLING_TIME 60
+
+
+/* tape defaults */
+#define TAPE_BUFS_DEFAULT 9
+#define TAPE_FORMAT_DEFAULT 0
+
+/* Definition of Special Word values */
+#define NOTHING_SPECIAL 0x0000
+#define CREATE_FLOPPY_DLES 0x0002
+#define IGNORE_MAYNARD_ID 0x0020
+#define FAST_TDEMO 0x4000
+
+#define MAX_CONTRLS 5
+#define MAX_DEF 2
+
+/* DEVICE DRIVER BUFFER SIZE */
+
+#define DRIVER_SIZE 9
+
+/* BUFFER SIZE DEFAULTS */
+
+#define BUFF_SIZE_TFL 9216
+#define BUFF_SIZE_SMB 512
+
+/* debug window */
+#define DEBUG_DEF_LINES 150
+#define DEBUG_FILE TEXT("debug.log")
+
+/* DISPLAY DEFAULTS - RANGES */
+
+#define MIN_FONT_SIZE 5
+#define MAX_FONT_SIZE 100
+#define MIN_FONT_WEIGHT 0
+#define MAX_FONT_WEIGHT 1200
+#define MIN_FONT_CASE 0
+#define MAX_FONT_CASE 0x0008
+
+BOOLEAN IS_JAPAN( void ) ;
+
+#define FONT_NAME (IS_JAPAN()?TEXT("SYSTEM"):TEXT("MS Sans Serif"))
+#define FONT_SIZE (IS_JAPAN()?10:8)
+
+#define FONT_WEIGHT 400
+#define FONT_LOWERCASE 0x0001
+#define FONT_ITALICS 0x0005
+
+// SORT OPTIONS
+
+#define ID_SORTMIN ID_SORTNAME
+#define ID_SORTMAX ID_SORTDATE
+
+// SEARCH LIMIT DEFINES
+
+#define SEARCH_MIN 1
+#define SEARCH_AVG 250
+#define SEARCH_MAX 5000
+
+// Hardware Parameters Structure
+
+typedef struct HWPARMS *HWPARMS_PTR;
+typedef struct HWPARMS {
+
+ WORD wStatus;
+ WORD wCardID;
+ WORD wDrives;
+ WORD wSlot;
+ WORD wTargets;
+ ULONG ulAddr;
+ ULONG ulIRQ;
+ ULONG ulDMA;
+ ULONG ulSettlingTime;
+ INT16 nNumParms;
+ ULONG ulParms[10];
+ struct HWPARMS *pNext;
+
+} HWPARMS;
+
+// Special Structure for Default Drive Definition
+
+typedef struct DEF_DRIVE_ENTRY {
+ struct DEF_DRIVE_ENTRY *next ;
+ CHAR_PTR drive_name ;
+} DEF_DRIVE_ENTRY, *DEF_DRIVE_ENTRY_PTR ;
+
+
+// WINDOW POSITION AND SHOW STYLE STRUCTURE
+
+typedef struct WINSIZE *PWINSIZE;
+typedef struct WINSIZE {
+
+ INT x; // x-coordinate of upper-left corner
+ INT y; // y-coordinate of upper-left corner
+ INT cx; // width
+ INT cy; // height
+ INT nSize; // minimized, maximized, or normal
+ INT nSliderPos; // the slider position
+
+} WINSIZE ;
+
+
+// Configuration Data Structure
+
+typedef struct CDS *CDS_PTR;
+typedef struct CDS {
+
+#ifdef OS_WIN32
+
+ CHAR drive_name[MAXTAPEDRIVENAME + 1]; // tape drive name
+#endif
+ INT16 hardware_compress_mode; // 0/1 - disable/enable hardware compression // chs:05-04-93
+ INT16 software_compress_mode; // 0/1 - disable/enable software compression // chs:05-04-93
+ INT drive_settling_time; // number of seconds until tape drive settles
+
+ CHAR data_path[MAX_UI_PATH_SIZE] ; // users data path
+ CHAR cat_path[MAX_UI_PATH_SIZE]; // catalog data path
+ CHAR group_name[MAX_GROUPNAME_SIZE]; // program manager group name
+
+ INT16 output_dest ; // 0=monitor, 1=printer or 2=file
+ INT16 files_flg ; // list filename as processed
+ INT16 password_flg ; // password on flag
+
+ CHAR log_file_root[MAX_UI_LOGFILEROOT_SIZE];
+ // max log file root name
+ INT16 log_mode ; // log file open mode
+ INT16 log_level ; // logging level 0-4
+ INT16 num_log_sessions ; // number of log sessions to keep
+ BOOL print_log_session ; // print log session
+ CHAR active_driver[DRIVER_SIZE] ; // root portion of driver name
+
+ INT16 create_skipped ; // create skipped script?
+ INT16 show_netware_servers ; // flag for mapped drive vs. server
+ DEF_DRIVE_ENTRY *default_drives ; // default backup drives
+ INT16 auto_verify_backup ; // auto verify on backup
+ INT16 auto_verify_restore ; // auto verify on restore
+
+ INT16 enable_password_dbase ; // Enable password data base
+ INT16 max_pwdbase_recs ; // maximum #of pwdbase records
+
+ INT16 catalog_level ; // Catalog level, 0=none, 1=partial, 2=full
+ BOOL backup_catalogs ; // backup catalogs
+ BOOL use_tape_catalogs ; // backup catalogs
+
+ INT16 std_mode_warning ; // display standard mode warning
+ INT16 wait_time ; // in seconds
+
+ INT16 restore_existing_files ; // restore over existing files
+
+ UINT32 debug_flg ; // debug flag
+ BOOL debug_to_file ; // save debug info to a file
+ CHAR debug_file_name[MAX_UI_FILENAME_SIZE]; // debug info file name
+ BOOL debug_to_window ; // display debug info in a window
+ BOOL debug_window_show_all ; // keep all debug info in the window
+ INT16 debug_window_num_lines ; // keep most recent # of debug lines
+
+ BOOL show_main_ribbon ; // display the ribbon bar
+ BOOL show_status_line ; // display the status line
+
+ WINSIZE frame_info ; // frame window size and position
+ WINSIZE disk_info ; // disk window size and position
+ WINSIZE tape_info ; // tape window size and position
+ WINSIZE server_info ; // server window size and position
+ WINSIZE log_info ; // log window size and position
+ WINSIZE debug_info ; // debug window size and position
+ WINSIZE runtime_info ; // debug window size and position
+
+#ifdef OEM_EMS
+ WINSIZE exchange_info ; // exchange window size and position
+ INT16 show_exchange ; // flag for showing exchange window.
+#endif
+
+ UINT16 launcher_flag ; // launcher settings flag
+ BOOL include_subdirs_flag ; // include subdirs in selections
+ UINT16 backup_type ; // default backup type - incremental, etc...
+ BOOL eject_tape_flag ; // eject tape on exit flag
+ BOOL enable_stats_flag ; // enable statistics flag
+ INT search_limit; // number of records to limit search to
+ BOOL search_pwd_tapes; // skip passworded tapes in search
+ BOOL search_subdirs; // include subdirectories in search
+ INT poll_frequency; // poll drive frequency
+
+ BYTE font_name[LF_FULLFACESIZE]; // font face name
+ INT font_size; // font face size
+ INT font_weight; // font face weight
+ BOOL font_case; // lower/upper for ALL drives
+ BOOL font_case_fat; // lower/upper for FAT drives
+ BOOL font_italics; // normal/italic
+
+ INT file_details ; // file details or file name or future...
+ INT sort_options ; // sort options or file characteristics
+
+ HWPARMS_PTR pHWParms; // ptr to hardware parameters list
+
+ // The following elements are not specified within the config file
+ // but are used either internally or at run time only
+
+ BOOLEAN changed_config ; // altered config, but not saved
+ INT16 append_flg ; // append flag
+ INT16 yes_flag ; // yes and yesyes flag
+ INT16 erase_flg ; // erase flag, can be OFF, ERASE, or LONG_ERASE
+ CHAR pwdbase_fname[MAX_UI_FILENAME_SIZE] ; // password database filename
+ INT16 transfer_flag ; // true if TBACKUP transfer opper
+ INT16 advance_to_config ; // true if TMENU is to startup at config menu
+ INT16 cmd_line_restrict_access; // true if passed on the command line /R to // chs:06-07-93
+ // restrict access to user // chs:06-07-93
+
+ // The backup engine configuration pointer.
+
+ BE_CFG_PTR pPermBEC; // ptr to permanent Backup Engine Config
+
+ UINT32 temp1 ;
+ UINT32 temp2 ;
+
+} CDS;
+
+
+
+// FUNCTION PROTOTYPES
+
+VOID CDS_Init( VOID ) ;
+VOID CDS_Deinit ( VOID );
+CDS_PTR CDS_GetPerm( VOID ) ;
+BE_CFG_PTR CDS_GetPermBEC( VOID );
+CDS_PTR CDS_GetCopy( VOID ) ;
+VOID CDS_SetPerm( CDS_PTR ) ;
+VOID CDS_UpdateCopy( VOID ) ;
+CHAR_PTR CDS_GetDefaultDrive( CDS_PTR conf_ptr, INT16 device_num ) ;
+
+VOID CDS_LoadIniFileName ( VOID );
+VOID CDS_GetIniFileName ( LPSTR, INT );
+VOID CDS_SetIniFileName ( LPSTR );
+BOOL CDS_UsingCmdLineINI ( VOID );
+
+CHAR_PTR CDS_GetMaynFolder( VOID ) ;
+VOID CDS_SetMaynFolder( CHAR_PTR ) ;
+
+CHAR_PTR CDS_GetUserDataPath ( VOID );
+VOID CDS_SetUserDataPath ( CHAR_PTR );
+BOOL CDS_ValidateUserDataPath ( CHAR_PTR );
+
+CHAR_PTR CDS_GetCatDataPath ( VOID );
+VOID CDS_SetCatDataPath ( CHAR_PTR );
+BOOL CDS_ValidateCatDataPath ( CHAR_PTR );
+
+CHAR_PTR CDS_GetExePath ( VOID );
+VOID CDS_SetExePath ( CHAR_PTR );
+VOID CDS_SetupExePath ( VOID );
+VOID CDS_ChangeToExeDir ( VOID );
+
+VOID CDS_SaveLoggingConfig ( VOID );
+VOID CDS_SaveDebugConfig ( VOID );
+
+BOOL CDS_GetHardwareConfig ( LPSTR, HWPARMS_PTR );
+VOID CDS_SaveHardwareConfig ( LPSTR, HWPARMS_PTR, LPSTR );
+
+VOID CDS_SaveCDS ( VOID );
+
+DWORD CDS_GetLongInt ( LPSTR, LPSTR, DWORD );
+BOOL CDS_SaveInt ( LPSTR, LPSTR, DWORD );
+BOOL CDS_SaveHexInt ( LPSTR, LPSTR, DWORD );
+
+INT CDS_GetString ( LPSTR, LPSTR, LPSTR, LPSTR, INT );
+BOOL CDS_SaveString ( LPSTR, LPSTR, LPSTR );
+
+
+BOOL CDS_GetWinSize ( LPSTR, PWINSIZE );
+VOID CDS_SaveWinSize ( LPSTR, HWND );
+VOID CDS_SaveDlgWinSize ( LPSTR, HWND );
+VOID CDS_SaveMDIWinSize ( LPSTR, HWND );
+
+VOID CDS_CheckForBadPaths ( VOID );
+VOID CDS_SaveDisplayConfig ( VOID );
+
+// FUNCTION MACROS
+
+#define CDS_GetInt( x, y, z ) ( (WORD)CDS_GetLongInt( x, y, (DWORD)z ) )
+#define CDS_SkipBlanks(x) for( ; *x == TEXT(' '); x ++ )
+
+// CONFIG USER INTERFACE MACROS
+
+#define CDS_GetTapeDriveName( x ) ( (x)->drive_name )
+#define CDS_SetTapeDriveName( x, name ) ( strncpy( (x)->drive_name, name, MAXTAPEDRIVENAME ), \
+ (x)->drive_name[ MAXTAPEDRIVENAME ] = 0 )
+
+#define CDS_GetTapeDriveSettlingTime( x ) ( (x)->drive_settling_time )
+#define CDS_SetTapeDriveSettlingTime( x, v ) ( (x)->drive_settling_time = CDS_MAX( CDS_MIN( (v), MAX_DRIVE_SETTLING_TIME ), MIN_DRIVE_SETTLING_TIME ) )
+
+#define CDS_GetOutputDest( x ) ( (x)->output_dest )
+#define CDS_SetOutputDest( x, v ) ( (x)->output_dest = CDS_MAX( CDS_MIN( (v), LOG_TO_FILE ), LOG_NOWHERE ) )
+
+#define CDS_GetFilesFlag( x ) ( (x)->files_flg )
+#define CDS_SetFilesFlag( x, v ) ( (x)->files_flg = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#define CDS_GetPasswordFlag( x ) ( (x)->password_flg )
+#define CDS_SetPasswordFlag( x, v ) ( (x)->password_flg = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#define CDS_GetDebugFlag( x ) ( (x)->debug_flg )
+#define CDS_SetDebugFlag( x, v ) ( (x)->debug_flg = ( v ) )
+
+#define CDS_GetLogFileRoot( x ) ( (x)->log_file_root )
+#define CDS_SetLogFileRoot( x, name ) ( strncpy( (x)->log_file_root, name, MAX_UI_LOGFILEROOT_LEN ), \
+ (x)->log_file_root[ MAX_UI_LOGFILEROOT_LEN ] = TEXT('\0') )
+
+#define CDS_GetLogMode( x ) ( (x)->log_mode )
+#define CDS_SetLogMode( x, v ) ( (x)->log_mode = CDS_MAX( CDS_MIN( (v), LOG_APPEND ), LOG_OVERWRITE ) )
+
+#define CDS_GetLogLevel( x ) ( (x)->log_level )
+#define CDS_SetLogLevel( x, v ) ( (x)->log_level = CDS_MAX( CDS_MIN( (v), LOG_DETAIL ), LOG_DISABLED ) )
+
+#define CDS_GetHWCompMode( x ) ( (x)->hardware_compress_mode ) // chs:05-04-93
+#define CDS_SetHWCompMode( x, v ) ( (x)->hardware_compress_mode = CDS_MAX( CDS_MIN( (v), HW_COMP_ENABLE ), HW_COMP_DISABLE ) ) // chs:05-04-93
+
+#define CDS_GetSWCompMode( x ) ( (x)->software_compress_mode ) // chs:05-04-93
+#define CDS_SetSWCompMode( x, v ) ( (x)->software_compress_mode = CDS_MAX( CDS_MIN( (v), SW_COMP_ENABLE ), SW_COMP_DISABLE ) ) // chs:05-04-93
+
+#define CDS_GetNumLogSessions( x ) ( (x)->num_log_sessions )
+#define CDS_SetNumLogSessions( x, v ) ( (x)->num_log_sessions = CDS_MAX( CDS_MIN( (v), LOG_MAX_LOGFILES ), LOG_MIN_LOGFILES ) )
+
+#define CDS_GetPrintLogSession( x ) ( (x)->print_log_session )
+#define CDS_SetPrintLogSession( x, v ) ( (x)->print_log_session = CDS_MAX( CDS_MIN( (v), LOG_PRINT_PROMPT ), LOG_PRINT_OFF ) )
+
+#define CDS_GetActiveDriver( x ) ( (x)->active_driver )
+#define CDS_SetActiveDriver( x, name ) ( strncpy( (x)->active_driver, name, 8 ), \
+ (x)->active_driver[8] = TEXT('\0') )
+
+#define CDS_GetDosDriveList( x ) ( (x)->dos_drive_list )
+#define CDS_SetDosDriveList( x, v ) ( (x)->dos_drive_list = ( v ) )
+
+#define CDS_GetCreateSkipped( x ) ( (x)->create_skipped )
+#define CDS_SetCreateSkipped( x, v ) ( (x)->create_skipped = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#define CDS_GetDisplayNetwareServers( x ) ( (x)->show_netware_servers )
+#define CDS_SetDisplayNetwareServers( x, v ) ( (x)->show_netware_servers = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#define CDS_GetDefaultDriveList( x ) ( (x)->default_drives )
+#define CDS_SetDefaultDriveList( x, v ) ( (x)->default_drives = (v) )
+
+#define CDS_GetAutoVerifyBackup( x ) ( (x)->auto_verify_backup )
+#define CDS_SetAutoVerifyBackup( x, v ) ( (x)->auto_verify_backup = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#define CDS_GetCmdLineRestrictAccess( x ) ( (x)->cmd_line_restrict_access ) // chs:06-07-93
+#define CDS_SetCmdLineRestrictAccess( x, v ) ( (x)->cmd_line_restrict_access = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) ) // chs:06-07-93
+
+#define CDS_GetAutoVerifyRestore( x ) ( (x)->auto_verify_restore )
+#define CDS_SetAutoVerifyRestore( x, v ) ( (x)->auto_verify_restore = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#define CDS_GetEnablePasswordDbase( x ) ( (x)->enable_password_dbase )
+#define CDS_SetEnablePasswordDbase( x, v ) ( (x)->enable_password_dbase = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#define CDS_GetMaxPwDbaseSize( x ) ( (x)->max_pwdbase_recs )
+#define CDS_SetMaxPwDbaseSize( x, v ) ( (x)->max_pwdbase_recs = CDS_MAX( (v), PWDB_MIN_ENTRIES ) )
+
+#define CDS_GetCatalogLevel( x ) ( (x)->catalog_level )
+#define CDS_SetCatalogLevel( x, v ) ( ( (x)->catalog_level = CDS_MAX( CDS_MIN( (v), CATALOGS_FULL ), CATALOGS_PARTIAL ) ) , \
+ ( BEC_SetCatalogLevel( (x)->pPermBEC, CDS_MAX( CDS_MIN( (v), CATALOGS_FULL ), CATALOGS_PARTIAL ) ) ) )
+
+#define CDS_GetBackupCatalogs( x ) ( (x)->backup_catalogs )
+#define CDS_SetBackupCatalogs( x, v ) ( (x)->backup_catalogs = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#define CDS_GetUseTapeCatalogs( x ) ( (x)->use_tape_catalogs )
+#define CDS_SetUseTapeCatalogs( x, v ) ( (x)->use_tape_catalogs = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#define CDS_GetWaitTime( x ) ( (x)->wait_time )
+#define CDS_SetWaitTime( x, v ) ( (x)->wait_time = CDS_MAX( (v), SKIP_MIN_TIME ) )
+
+#define CDS_GetStdModeWarning( x ) ( (x)->std_mode_warning )
+#define CDS_SetStdModeWarning( x, v ) ( (x)->std_mode_warning = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#define CDS_GetRestoreExistingFiles( x ) ( (x)->restore_existing_files )
+#define CDS_SetRestoreExistingFiles( x, v ) ( (x)->restore_existing_files = CDS_MAX( CDS_MIN( (v), PROMPT_RESTORE_OVER_RECENT ), RESTORE_OVER_EXISTING ) )
+
+#define CDS_GetShowMainRibbon( x ) ( (x)->show_main_ribbon )
+#define CDS_SetShowMainRibbon( x, v ) ( (x)->show_main_ribbon = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#define CDS_GetShowStatusLine( x ) ( (x)->show_status_line )
+#define CDS_SetShowStatusLine( x, v ) ( (x)->show_status_line = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#define CDS_GetFontFace( x ) ( (CHAR_PTR)(x)->font_name )
+#define CDS_SetFontFace( x, v ) ( strcpy( (CHAR_PTR)((x)->font_name), (v) ) )
+
+#define CDS_GetFontSize( x ) ( (x)->font_size )
+#define CDS_SetFontSize( x, v ) ( (x)->font_size = CDS_MAX( CDS_MIN( (v), MAX_FONT_SIZE ), MIN_FONT_SIZE ) )
+
+#define CDS_GetFontWeight( x ) ( (x)->font_weight )
+#define CDS_SetFontWeight( x, v ) ( (x)->font_weight = CDS_MAX( CDS_MIN( (v), MAX_FONT_WEIGHT ), MIN_FONT_WEIGHT ) )
+
+#define CDS_GetFontCase( x ) ( (x)->font_case )
+#define CDS_SetFontCase( x, v ) ( (x)->font_case = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#define CDS_GetFontCaseFAT( x ) ( (x)->font_case_fat )
+#define CDS_SetFontCaseFAT( x, v ) ( (x)->font_case_fat = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#define CDS_GetFontItalics( x ) ( (x)->font_italics )
+#define CDS_SetFontItalics( x, v ) ( (x)->font_italics = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#define CDS_GetFileDetails( x ) ( (x)->file_details )
+#define CDS_SetFileDetails( x, v ) ( (x)->file_details = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#define CDS_GetSortOptions( x ) ( (x)->sort_options )
+#define CDS_SetSortOptions( x, v ) ( (x)->sort_options = CDS_MAX( CDS_MIN( (v), ID_SORTMAX ), ID_SORTMIN ) )
+
+#define CDS_GetDebugToFile( x ) ( (x)->debug_to_file )
+#define CDS_SetDebugToFile( x, v ) ( (x)->debug_to_file = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#define CDS_GetDebugFileName( x ) ( (CHAR_PTR)(x)->debug_file_name )
+#define CDS_SetDebugFileName( x, v ) ( strcpy( (CHAR_PTR)(x)->debug_file_name, (v) ) )
+
+#define CDS_GetDebugToWindow( x ) ( (x)->debug_to_window )
+#define CDS_SetDebugToWindow( x, v ) ( (x)->debug_to_window = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#define CDS_GetDebugWindowShowAll( x ) ( (x)->debug_window_show_all )
+#define CDS_SetDebugWindowShowAll( x, v ) ( (x)->debug_window_show_all = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#define CDS_GetDebugWindowNumLines( x ) ( (x)->debug_window_num_lines )
+#define CDS_SetDebugWindowNumLines( x, v ) ( (x)->debug_window_num_lines = ( v ) )
+
+#define CDS_GetFrameInfo( x ) ( (x)->frame_info )
+#define CDS_SetFrameInfo( x, v ) ( (x)->frame_info = ( v ) )
+#define CDS_GetFrameSize( x ) ( (x)->frame_info.nSize )
+#define CDS_SetFrameSize( x, v ) ( (x)->frame_info.nSize = ( v ) )
+
+#define CDS_GetDiskInfo( x ) ( (x)->disk_info )
+#define CDS_SetDiskInfo( x, v ) ( (x)->disk_info = ( v ) )
+#define CDS_GetDiskSize( x ) ( (x)->disk_info.nSize )
+#define CDS_SetDiskSize( x, v ) ( (x)->disk_info.nSize = ( v ) )
+
+#define CDS_GetTapeInfo( x ) ( (x)->tape_info )
+#define CDS_SetTapeInfo( x, v ) ( (x)->tape_info = ( v ) )
+#define CDS_GetTapeSize( x ) ( (x)->tape_info.nSize )
+#define CDS_SetTapeSize( x, v ) ( (x)->tape_info.nSize = ( v ) )
+
+#define CDS_GetServerInfo( x ) ( (x)->server_info )
+#define CDS_SetServerInfo( x, v ) ( (x)->server_info = ( v ) )
+#define CDS_GetServerSize( x ) ( (x)->server_info.nSize )
+#define CDS_SetServerSize( x, v ) ( (x)->server_info.nSize = ( v ) )
+
+#ifdef OEM_EMS
+#define CDS_GetDisplayExchange( x ) ( (x)->show_exchange )
+#define CDS_SetDisplayExchange( x, v ) ( (x)->show_exchange = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#define CDS_GetExchangeInfo( x ) ( (x)->exchange_info )
+#define CDS_SetExchangeInfo( x, v ) ( (x)->exchange_info = ( v ) )
+#define CDS_GetExchangeSize( x ) ( (x)->exchange_info.nSize )
+#define CDS_SetExchangeSize( x, v ) ( (x)->exchange_info.nSize = ( v ) )
+#endif
+
+#define CDS_GetLogInfo( x ) ( (x)->log_info )
+#define CDS_SetLogInfo( x, v ) ( (x)->log_info = ( v ) )
+#define CDS_GetLogSize( x ) ( (x)->log_info.nSize )
+#define CDS_SetLogSize( x, v ) ( (x)->log_info.nSize = ( v ) )
+
+#define CDS_GetDebugInfo( x ) ( (x)->debug_info )
+#define CDS_SetDebugInfo( x, v ) ( (x)->debug_info = ( v ) )
+#define CDS_GetDebugSize( x ) ( (x)->debug_info.nSize )
+#define CDS_SetDebugSize( x, v ) ( (x)->debug_info.nSize = ( v ) )
+
+#define CDS_GetRuntimeInfo( x ) ( (x)->runtime_info )
+#define CDS_SetRuntimeInfo( x, v ) ( (x)->runtime_info = ( v ) )
+#define CDS_GetRuntimeSize( x ) ( (x)->runtime_info.nSize )
+#define CDS_SetRuntimeSize( x, v ) ( (x)->runtime_info.nSize = ( v ) )
+
+#define CDS_GetGroupName( x ) ( (CHAR_PTR)(x)->group_name )
+#define CDS_SetGroupName( x, v ) ( strcpy( (CHAR_PTR)(x)->group_name, (v) ) )
+
+#define CDS_GetLauncherFlag( x ) ( (x)->launcher_flag )
+#define CDS_SetLauncherFlag( x, v ) ( (x)->launcher_flag = CDS_MAX( (v), LAUNCHER_MIN_TIME ) )
+
+#define CDS_GetIncludeSubdirs( x ) ( (x)->include_subdirs_flag )
+#define CDS_SetIncludeSubdirs( x, v ) ( (x)->include_subdirs_flag = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#define CDS_GetDefaultBackupType( x ) ( (x)->backup_type )
+#define CDS_SetDefaultBackupType( x, v ) ( (x)->backup_type = CDS_MAX( CDS_MIN( (v), BACKUP_INCR ), BACKUP_NORMAL ) )
+
+#define CDS_GetHWParms( x ) ( (x)->pHWParms )
+#define CDS_SetHWParms( x, v ) ( (x)->pHWParms = (v) )
+
+#define CDS_GetEjectTapeFlag( x ) ( (x)->eject_tape_flag )
+#define CDS_SetEjectTapeFlag( x, v ) ( (x)->eject_tape_flag = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#define CDS_GetEnableStatsFlag( x ) ( (x)->enable_stats_flag )
+#define CDS_SetEnableStatsFlag( x, v ) ( (x)->enable_stats_flag = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#ifdef OEM_EMS
+#define CDS_GetUsrShareFlag( x ) ( (x)->usr_share_flag )
+#define CDS_GetSysShareFlag( x ) ( (x)->sys_share_flag )
+#endif
+
+#define CDS_GetSearchLimit( x ) ( (x)->search_limit )
+#define CDS_SetSearchLimit( x, v ) ( (x)->search_limit = CDS_MAX( CDS_MIN( (v), SEARCH_MAX ), SEARCH_MIN ) )
+
+#define CDS_GetSearchPwdTapes( x ) ( (x)->search_pwd_tapes )
+#define CDS_SetSearchPwdTapes( x, v ) ( (x)->search_pwd_tapes = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#define CDS_GetSearchSubdirs( x ) ( (x)->search_subdirs )
+#define CDS_SetSearchSubdirs( x, v ) ( (x)->search_subdirs = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#define CDS_GetPollFrequency( x ) ( (x)->poll_frequency )
+#define CDS_SetPollFrequency( x, v ) ( (x)->poll_frequency = CDS_MAX( (v), POLL_MIN_FREQ ) )
+
+#define CDS_GetAppendFlag( x ) ( (x)->append_flg )
+#define CDS_SetAppendFlag( x, v ) ( (x)->append_flg = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+
+// RUN TIME MACROS
+
+#define CDS_GetChangedConfig( x ) ( (x)->changed_config )
+#define CDS_SetChangedConfig( x, v ) ( (x)->changed_config = (v) )
+
+#define CDS_GetYesFlag( x ) ( (x)->yes_flag )
+#define CDS_SetYesFlag( x, v ) ( (x)->yes_flag = CDS_MAX( CDS_MIN( (v), YESYES_FLAG ), NO_FLAG ) )
+
+#define CDS_GetEraseFlag( x ) ( (x)->erase_flg )
+#define CDS_SetEraseFlag( x, v ) ( (x)->erase_flg = CDS_MAX( CDS_MIN( (v), ERASE_FORMAT ), ERASE_OFF ) )
+
+#define CDS_GetPwDbaseFname( x ) ( (CHAR_PTR)(x)->pwdbase_fname )
+#define CDS_SetPwDbaseFname( x, v ) ( strcpy ( (CHAR_PTR)(x)->pwdbase_fname, (v) ) )
+
+#define CDS_GetTransferFlag( x ) ( (x)->transfer_flag )
+#define CDS_SetTransferFlag( x, v ) ( (x)->transfer_flag = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+#define CDS_GetAdvToConfig( x ) ( (x)->advance_to_config )
+#define CDS_SetAdvToConfig( x, v ) ( (x)->advance_to_config = CDS_MAX( CDS_MIN( (v), CDS_ENABLE ), CDS_DISABLE ) )
+
+
+// CONFIG to BACKUP ENGINE CONFIG MACROS
+
+#define CDS_GetSkipOpenFiles( x ) BEC_GetSkipOpenFiles( (x)->pPermBEC )
+#define CDS_SetSkipOpenFiles( x, v ) BEC_SetSkipOpenFiles( (x)->pPermBEC, v )
+
+#define CDS_GetBackupFilesInUse( x ) BEC_GetBackupFilesInUse( (x)->pPermBEC )
+#define CDS_SetBackupFilesInUse( x, v ) BEC_SetBackupFilesInUse( (x)->pPermBEC, v )
+
+#define CDS_GetHiddenFlag( x ) BEC_GetHiddenFlag( (x)->pPermBEC )
+#define CDS_SetHiddenFlag( x, v ) BEC_SetHiddenFlag( (x)->pPermBEC, v )
+
+#define CDS_GetSpecialFlag( x ) BEC_GetSpecialFlag( (x)->pPermBEC )
+#define CDS_SetSpecialFlag( x, v ) BEC_SetSpecialFlag( (x)->pPermBEC, v )
+
+#define CDS_GetSetArchiveFlag( x ) BEC_GetSetArchiveFlag( (x)->pPermBEC )
+#define CDS_SetSetArchiveFlag( x, v ) BEC_SetSetArchiveFlag( (x)->pPermBEC, v )
+
+#define CDS_GetExistFlag( x ) BEC_GetExistFlag( (x)->pPermBEC )
+#define CDS_SetExistFlag( x, v ) BEC_SetExistFlag( (x)->pPermBEC, v )
+
+#define CDS_GetPromptFlag( x ) BEC_GetPromptFlag( (x)->pPermBEC )
+#define CDS_SetPromptFlag( x, v ) BEC_SetPromptFlag( (x)->pPermBEC, v )
+
+#define CDS_GetTFLBuffSize( x ) BEC_GetTFLBuffSize( (x)->pPermBEC )
+#define CDS_SetTFLBuffSize( x, v ) BEC_SetTFLBuffSize( (x)->pPermBEC, v )
+
+#define CDS_GetAFPSupport( x ) BEC_GetAFPSupport( (x)->pPermBEC )
+#define CDS_SetAFPSupport( x, v ) BEC_SetAFPSupport( (x)->pPermBEC, v )
+
+#define CDS_GetExtendedDateSupport( x ) BEC_GetExtendedDateSupport( (x)->pPermBEC )
+#define CDS_SetExtendedDateSupport( x, v ) BEC_SetExtendedDateSupport( (x)->pPermBEC, v )
+
+#define CDS_GetProcEmptyFlag( x ) BEC_GetProcEmptyFlag( (x)->pPermBEC )
+#define CDS_SetProcEmptyFlag( x, v ) BEC_SetProcEmptyFlag( (x)->pPermBEC, v )
+
+#define CDS_GetFastFileRestore( x ) BEC_GetFastFileRestore( (x)->pPermBEC )
+#define CDS_SetFastFileRestore( x, v ) BEC_SetFastFileRestore( (x)->pPermBEC, v )
+
+#define CDS_GetConfiguredMachineType( x ) BEC_GetConfiguredMachineType( (x)->pPermBEC )
+#define CDS_SetConfiguredMachineType( x, v ) BEC_SetConfiguredMachineType( (x)->pPermBEC, v )
+
+#define CDS_GetSpecialWord( x ) BEC_GetSpecialWord( (x)->pPermBEC )
+#define CDS_SetSpecialWord( x, v ) BEC_SetSpecialWord( (x)->pPermBEC, v )
+
+#define CDS_GetMaxTapeBuffers( x ) BEC_GetMaxTapeBuffers( (x)->pPermBEC )
+#define CDS_SetMaxTapeBuffers( x, v ) BEC_SetMaxTapeBuffers( (x)->pPermBEC, v )
+
+#define CDS_GetMaxBufferSize( x ) BEC_GetMaxBufferSize( (x)->pPermBEC )
+#define CDS_SetMaxBufferSize( x, v ) BEC_SetMaxBufferSize( (x)->pPermBEC, v )
+
+#define CDS_GetNetNum( x ) BEC_GetNetNum( (x)->pPermBEC )
+#define CDS_SetNetNum( x, v ) BEC_SetNetNum( (x)->pPermBEC, v )
+
+#define CDS_GetSortBSD( x ) BEC_GetSortBSD( (x)->pPermBEC )
+#define CDS_SetSortBSD( x, v ) BEC_SetSortBSD( (x)->pPermBEC, v )
+
+#define CDS_GetRestoreSecurity( x ) BEC_GetRestoreSecurity( (x)->pPermBEC )
+#define CDS_SetRestoreSecurity( x, v ) BEC_SetRestoreSecurity( (x)->pPermBEC, v )
+
+#define CDS_GetRemoteDriveBackup( x ) BEC_GetRemoteDriveBackup( (x)->pPermBEC )
+#define CDS_SetRemoteDriveBackup( x, v ) BEC_SetRemoteDriveBackup( (x)->pPermBEC, v )
+
+#define CDS_GetWriteFormat( x ) BEC_GetWriteFormat( (x)->pPermBEC )
+#define CDS_SetWriteFormat( x, v ) BEC_SetWriteFormat( (x)->pPermBEC, v )
+
+#define CDS_GetNRLDosVector( x ) BEC_GetNRLDosVector( (x)->pPermBEC )
+#define CDS_SetNRLDosVector( x, v ) BEC_SetNRLDosVector( (x)->pPermBEC, v )
+
+#define CDS_GetReserveMem( x ) BEC_GetReserveMem( (x)->pPermBEC )
+#define CDS_SetReserveMem( x, v ) BEC_SetReserveMem( (x)->pPermBEC, v )
+
+#define CDS_GetPartList( x ) BEC_GetPartList( (x)->pPermBEC )
+#define CDS_SetPartList( x, v ) BEC_SetPartList( (x)->pPermBEC, v )
+
+// ENABLE THIS WHEN THE BENGINE SUPPORTS IT
+
+//#define CDS_GetOTCLevel( x ) BEC_GetOTCLevel( (x)->pPermBEC )
+//#define CDS_SetOTCLevel( x, v ) BEC_SetOTCLevel( (x)->pPermBEC, v )
+
+#define CDS_GetOTCLevel( x ) ( (x)==(x) )
+#define CDS_SetOTCLevel( x, v ) ( (x)==(x) && (v)==(v) )
+
+#define CDS_GetProcessSytronECCFlag( x ) BEC_GetProcessSytronECCFlag( (x)->pPermBEC )
+#define CDS_SetProcessSytronECCFlag( x, v ) BEC_SetProcessSytronECCFlag( (x)->pPermBEC, v )
+
+
+/******************************************************************************/
+
+
+// MAYNARD.INI CONFIGURATION STRINGS
+
+// USER INTERFACE
+
+#define CMS_UI TEXT("User Interface")
+
+#define CMS_DATAPATH TEXT("Data Path")
+#define CMS_CATALOGPATH TEXT("Catalog Path")
+#define CMS_OUTPUT TEXT("Output Dest")
+#define CMS_LISTFILES TEXT("List Files")
+#define CMS_PWDFLAG TEXT("Use Password")
+#define CMS_PASSWORD TEXT("Backup Password")
+#define CMS_SKIPPED TEXT("Create Skipped")
+#define CMS_SHOWSERVERS TEXT("Display NetWare Servers")
+#define CMS_DEFDRIVES TEXT("Default Drive List")
+#define CMS_AUTOVBACKUP TEXT("Auto Verify Backup")
+#define CMS_AUTOVRESTORE TEXT("Auto Verify Restore")
+#define CMS_PWDDBASE TEXT("Use Server PDBase")
+#define CMS_PWDDBASERECS TEXT("Max PDBase Entries")
+#define CMS_APPENDFLAG TEXT("Append Flag")
+#define CMS_CATALOGLEVEL TEXT("Catalog Level")
+#define CMS_SKIP_OPEN_FILES TEXT("Skip open files")
+#define CMS_WAITTIME TEXT("Wait time")
+#define CMS_STDMODEWARNING TEXT("Show Mode Warning")
+#define CMS_RESTOREEXIST TEXT("Restore existing files")
+#define CMS_BACKUPCAT TEXT("Backup Catalogs")
+#define CMS_GROUPNAME TEXT("Group Name")
+#define CMS_LAUNCHERFLAG TEXT("Launcher Flag")
+#define CMS_SUBDIRS TEXT("Include Subdirs")
+#define CMS_BACKUPTYPE TEXT("Backup Type")
+#define CMS_EJECTTAPE TEXT("Eject Tape Flag")
+#define CMS_ENABLESTATS TEXT("Enable Statistics")
+#define CMS_SEARCHLIMIT TEXT("Search Limit")
+#define CMS_SEARCHPWDTAPES TEXT("Search Tapes With Password")
+#define CMS_SEARCHSUBDIRS TEXT("Search Subdirectories")
+#define CMS_USETAPECAT TEXT("Use Tape Catalogs")
+
+
+// DISPLAY
+
+#define CMS_DISPLAY TEXT("Display")
+
+#define CMS_MAINRIB TEXT("Selection Bar")
+#define CMS_STATLINE TEXT("Status line")
+#define CMS_FONTFACE TEXT("Font Face")
+#define CMS_FONTSIZE TEXT("Font Size")
+#define CMS_FONTWEIGHT TEXT("Font Weight")
+#define CMS_FONTCASE TEXT("Font Case")
+#define CMS_FONTCASEFAT TEXT("Font Case FAT")
+#define CMS_FONTITALICS TEXT("Font Italics")
+#define CMS_FILEDETAILS TEXT("File Details")
+#define CMS_SORTOPTIONS TEXT("Sort Options")
+#define CMS_FRAMEWINDOW TEXT("Frame Window")
+#define CMS_DISKWINDOW TEXT("Disk Window")
+#define CMS_TAPEWINDOW TEXT("Tape Window")
+#define CMS_SERVERWINDOW TEXT("Server Window")
+#define CMS_LOGWINDOW TEXT("Log Window")
+#define CMS_DEBUGWINDOW TEXT("Debug Window")
+#define CMS_RUNTIMEDLG TEXT("Run Time Dialog")
+
+// LOGGING
+
+#define CMS_LOGGING TEXT("Logging")
+
+#define CMS_LOGFILEROOT TEXT("Log File Root")
+#define CMS_NUMSESSIONS TEXT("Number of sessions")
+#define CMS_LOGLEVEL TEXT("Log Level")
+#define CMS_LOGMODE TEXT("Log Mode")
+#define CMS_PRINTLEVEL TEXT("Print Level")
+#define CMS_PRINTSESSION TEXT("Print log session")
+
+// HARDWARE
+
+#define CMS_AUTO TEXT("")
+
+#define CMS_HARDWARE TEXT("Hardware")
+
+#define CMS_TAPEDRIVE TEXT("Tape Drive")
+#define CMS_DRIVER TEXT("Driver")
+#define CMS_CONTROLLER TEXT("Controller")
+#define CMS_POLLFREQ TEXT("Poll Frequency")
+#define CMS_HWCOMPMODE TEXT("Hardware Compression") // chs:05-04-93
+#define CMS_SWCOMPMODE TEXT("Software Compression") // chs:05-04-93
+#define CMS_SETTLINGTIME TEXT("Drive Settling Time")
+
+
+#define CMS_STATUS TEXT("Status")
+#define CMS_CARDID TEXT("Card ID")
+#define CMS_DRIVES TEXT("Drives")
+#define CMS_SLOT TEXT("Slot")
+#define CMS_TARGETS TEXT("Target_IDs")
+#define CMS_ADDR TEXT("IO_Address")
+#define CMS_IRQ TEXT("IRQ_Number")
+#define CMS_DMA TEXT("DMA_Channel")
+
+// NT HARDWARE
+
+//#define CMS_CARD "Card"
+//#define CMS_TARGET "Target"
+//#define CMS_BUS "Bus"
+//#define CMS_LUN "LUN"
+
+// DEBUG
+
+#define CMS_DEBUG TEXT("Debug")
+
+#define CMS_DEBUGFLAG TEXT("Flag")
+#define CMS_TOFILE TEXT("To File")
+#define CMS_DEBUGFILE TEXT("File Name")
+#define CMS_TOWINDOW TEXT("To Window")
+#define CMS_SHOWALL TEXT("Show All")
+#define CMS_DEBUGLINES TEXT("Num Debug Lines")
+
+// BENGINE
+
+#define CMS_BENGINE TEXT("Backup Engine")
+
+#define CMS_SPECIAL_WORD TEXT("Special word")
+#define CMS_MAX_NUM_TAPE_BUFS TEXT("Max Num Tape Buffers")
+#define CMS_TFL_BUFF_SIZE TEXT("Tape Buffer Size")
+#define CMS_MAX_BUFFER_SIZE TEXT("Max Buffer Size")
+#define CMS_BACKUP_FILES_INUSE TEXT("Backup files inuse")
+#define CMS_SUPPORT_AFP_SERVER TEXT("Process Macintosh files")
+#define CMS_EXTENDED_DATE_SUPPORT TEXT("Extended Date Support")
+#define CMS_HIDDEN_FLAG TEXT("Hidden files")
+#define CMS_SPECIAL_FLAG TEXT("Special files")
+#define CMS_SET_ARCHIVE_FLAG TEXT("Set archive")
+#define CMS_PROC_EMPTY_FLAG TEXT("Process empty dirs")
+#define CMS_EXIST_FLAG TEXT("Restore existing files")
+#define CMS_PROMPT_FLAG TEXT("Prompt mode")
+#define CMS_NET_NUM TEXT("Network ID")
+#define CMS_SORT_BSD TEXT("Sort BSD List")
+#define CMS_REMOTE_DRIVE_BACKUP TEXT("Remote Drive Backup")
+#define CMS_USE_FFR TEXT("Use fast file restore")
+#define CMS_WRITE_FORMAT TEXT("Tape Format")
+#define CMS_NRL_DOS_VECTOR TEXT("NRL dos vector")
+#define CMS_MACHINE_TYPE TEXT("Machine Type")
+#define CMS_OTC_LEVEL TEXT("OTC Level")
+
+
+// TRANSLATORS
+
+#define CMS_TRANSLATORS TEXT("Translators")
+
+#ifdef OEM_MSOFT
+#define CMS_PROC_SYTRON_ECC TEXT("Sytos Plus ECC Flag")
+#else
+#define CMS_PROC_SYTRON_ECC TEXT("SYPL ECC Flag")
+#endif
+
+// CDS UI READ/WRITE MACROS
+
+#define CDS_ReadUserDataPath( x ) CDS_GetString( CMS_UI, CMS_DATAPATH, TEXT(""), (x)->data_path, MAX_UI_PATH_SIZE )
+#define CDS_WriteUserDataPath( x ) CDS_SaveString( CMS_UI, CMS_DATAPATH, (x)->data_path )
+
+#define CDS_ReadCatDataPath( x ) CDS_GetString( CMS_UI, CMS_CATALOGPATH, TEXT(""), (x)->cat_path, MAX_UI_PATH_SIZE )
+#define CDS_WriteCatDataPath( x ) CDS_SaveString( CMS_UI, CMS_CATALOGPATH, (x)->cat_path )
+
+#define CDS_ReadGroupName( x ) CDS_GetString( CMS_UI, CMS_GROUPNAME, TEXT(""), CDS_GetGroupName( x ), MAX_GROUPNAME_SIZE )
+#define CDS_WriteGroupName( x ) CDS_SaveString( CMS_UI, CMS_GROUPNAME, CDS_GetGroupName( x ) )
+
+#define CDS_ReadOutputDest( x ) CDS_SetOutputDest( x, CDS_GetInt( CMS_UI, CMS_OUTPUT, LOG_TO_FILE ) )
+#define CDS_WriteOutputDest( x ) CDS_SaveInt( CMS_UI, CMS_OUTPUT, CDS_GetOutputDest( x ) )
+
+#define CDS_ReadFilesFlag( x ) CDS_SetFilesFlag( x, CDS_GetInt( CMS_UI, CMS_LISTFILES, CDS_ENABLE ) )
+#define CDS_WriteFilesFlag( x ) CDS_SaveInt( CMS_UI, CMS_LISTFILES, CDS_GetFilesFlag( x ) )
+
+#define CDS_ReadCreateSkipped( x ) CDS_SetCreateSkipped( x, CDS_GetInt ( CMS_UI, CMS_SKIPPED, CDS_ENABLE ) )
+#define CDS_WriteCreateSkipped( x ) CDS_SaveInt( CMS_UI, CMS_SKIPPED, CDS_GetCreateSkipped( x ) )
+
+#define CDS_ReadDisplayNetwareServers( x ) CDS_SetDisplayNetwareServers( x, CDS_GetInt ( CMS_UI, CMS_SHOWSERVERS, CDS_ENABLE ) )
+#define CDS_WriteDisplayNetwareServers( x ) CDS_SaveInt( CMS_UI, CMS_SHOWSERVERS, CDS_GetDisplayNetwareServers( x ) )
+
+#define CDS_ReadAutoVerifyBackup( x ) CDS_SetAutoVerifyBackup( x, CDS_GetInt ( CMS_UI, CMS_AUTOVBACKUP, CDS_DISABLE ) )
+#define CDS_WriteAutoVerifyBackup( x ) CDS_SaveInt( CMS_UI, CMS_AUTOVBACKUP, CDS_GetAutoVerifyBackup( x ) )
+
+#define CDS_ReadAutoVerifyRestore( x ) CDS_SetAutoVerifyRestore( x, CDS_GetInt ( CMS_UI, CMS_AUTOVRESTORE, CDS_DISABLE ) )
+#define CDS_WriteAutoVerifyRestore( x ) CDS_SaveInt( CMS_UI, CMS_AUTOVRESTORE, CDS_GetAutoVerifyRestore( x ) )
+
+
+#define CDS_ReadPasswordFlag( x ) CDS_SetPasswordFlag( x, CDS_GetInt( CMS_UI, CMS_PWDFLAG, CDS_DISABLE ) )
+#define CDS_WritePasswordFlag( x ) CDS_SaveInt( CMS_UI, CMS_PWDFLAG, CDS_GetPasswordFlag( x ) )
+
+#define CDS_ReadEnablePasswordDbase( x ) CDS_SetEnablePasswordDbase( x, CDS_GetInt ( CMS_UI, CMS_PWDDBASE, CDS_DISABLE ) )
+#define CDS_WriteEnablePasswordDbase( x ) CDS_SaveInt( CMS_UI, CMS_PWDDBASE, CDS_GetEnablePasswordDbase( x ) )
+
+#define CDS_ReadMaxPwDbaseSize( x ) CDS_SetMaxPwDbaseSize( x, CDS_GetInt ( CMS_UI, CMS_PWDDBASERECS, PWDB_DEF_ENTRIES ) )
+#define CDS_WriteMaxPwDbaseSize( x ) CDS_SaveInt( CMS_UI, CMS_PWDDBASERECS, CDS_GetMaxPwDbaseSize( x ) )
+
+
+#define CDS_ReadAppendFlag( x ) CDS_SetAppendFlag( x, CDS_GetInt( CMS_UI, CMS_APPENDFLAG, CDS_DISABLE ) )
+#define CDS_WriteAppendFlag( x ) CDS_SaveInt( CMS_UI, CMS_APPENDFLAG, CDS_GetAppendFlag( x ) )
+
+#define CDS_ReadCatalogLevel( x ) CDS_SetCatalogLevel( x, CDS_GetInt ( CMS_UI, CMS_CATALOGLEVEL, CATALOGS_FULL ) )
+#define CDS_WriteCatalogLevel( x ) CDS_SaveInt( CMS_UI, CMS_CATALOGLEVEL, CDS_GetCatalogLevel( x ) )
+
+#define CDS_ReadBackupCatalogs( x ) CDS_SetBackupCatalogs( x, CDS_GetInt ( CMS_UI, CMS_BACKUPCAT, CDS_DISABLE ) )
+#define CDS_WriteBackupCatalogs( x ) CDS_SaveInt( CMS_UI, CMS_BACKUPCAT, CDS_GetBackupCatalogs( x ) )
+
+#define CDS_ReadUseTapeCatalogs( x ) CDS_SetUseTapeCatalogs( x, CDS_GetInt ( CMS_UI, CMS_USETAPECAT, CDS_ENABLE ) )
+#define CDS_WriteUseTapeCatalogs( x ) CDS_SaveInt( CMS_UI, CMS_USETAPECAT, CDS_GetUseTapeCatalogs( x ) )
+
+#define CDS_ReadWaitTime( x ) CDS_SetWaitTime( x, CDS_GetInt ( CMS_UI, CMS_WAITTIME, SKIP_DEF_TIME ) )
+#define CDS_WriteWaitTime( x ) CDS_SaveInt( CMS_UI, CMS_WAITTIME, CDS_GetWaitTime( x ) )
+
+#define CDS_ReadStdModeWarning( x ) CDS_SetStdModeWarning( x, CDS_GetInt ( CMS_UI, CMS_STDMODEWARNING, CDS_ENABLE ) )
+#define CDS_WriteStdModeWarning( x ) CDS_SaveInt( CMS_UI, CMS_STDMODEWARNING, CDS_GetStdModeWarning( x ) )
+
+#define CDS_ReadRestoreExistingFiles( x ) CDS_SetRestoreExistingFiles( x, CDS_GetInt ( CMS_UI, CMS_RESTOREEXIST, PROMPT_RESTORE_OVER_RECENT ) )
+#define CDS_WriteRestoreExistingFiles( x ) CDS_SaveInt( CMS_UI, CMS_RESTOREEXIST, CDS_GetRestoreExistingFiles( x ) )
+
+#define CDS_ReadLauncherFlag( x ) CDS_SetLauncherFlag( x, CDS_GetInt ( CMS_UI, CMS_LAUNCHERFLAG, LAUNCHER_DEF_TIME ) )
+#define CDS_WriteLauncherFlag( x ) CDS_SaveInt( CMS_UI, CMS_LAUNCHERFLAG, CDS_GetLauncherFlag( x ) )
+
+#define CDS_ReadIncludeSubdirs( x ) CDS_SetIncludeSubdirs( x, CDS_GetInt ( CMS_UI, CMS_SUBDIRS, CDS_ENABLE ) )
+#define CDS_WriteIncludeSubdirs( x ) CDS_SaveInt( CMS_UI, CMS_SUBDIRS, CDS_GetIncludeSubdirs( x ) )
+
+#define CDS_ReadDefaultBackupType( x ) CDS_SetDefaultBackupType( x, CDS_GetInt ( CMS_UI, CMS_BACKUPTYPE, BACKUP_NORMAL ) )
+#define CDS_WriteDefaultBackupType( x ) CDS_SaveInt( CMS_UI, CMS_BACKUPTYPE, CDS_GetDefaultBackupType( x ) )
+
+#define CDS_ReadEjectTapeFlag( x ) CDS_SetEjectTapeFlag( x, CDS_GetInt ( CMS_UI, CMS_EJECTTAPE, CDS_DISABLE ) )
+#define CDS_WriteEjectTapeFlag( x ) CDS_SaveInt( CMS_UI, CMS_EJECTTAPE, CDS_GetEjectTapeFlag( x ) )
+
+#define CDS_ReadEnableStatsFlag( x ) CDS_SetEnableStatsFlag( x, CDS_GetInt ( CMS_UI, CMS_ENABLESTATS, CDS_DISABLE ) )
+#define CDS_WriteEnableStatsFlag( x ) CDS_SaveInt( CMS_UI, CMS_ENABLESTATS, CDS_GetEnableStatsFlag( x ) )
+
+#define CDS_ReadSearchLimit( x ) CDS_SetSearchLimit( x, CDS_GetInt ( CMS_UI, CMS_SEARCHLIMIT, SEARCH_AVG ) )
+#define CDS_WriteSearchLimit( x ) CDS_SaveInt( CMS_UI, CMS_SEARCHLIMIT, CDS_GetSearchLimit( x ) )
+
+#define CDS_ReadSearchPwdTapes( x ) CDS_SetSearchPwdTapes( x, CDS_GetInt ( CMS_UI, CMS_SEARCHPWDTAPES, CDS_DISABLE ) )
+#define CDS_WriteSearchPwdTapes( x ) CDS_SaveInt( CMS_UI, CMS_SEARCHPWDTAPES, CDS_GetSearchPwdTapes( x ) )
+
+#define CDS_ReadSearchSubdirs( x ) CDS_SetSearchSubdirs( x, CDS_GetInt ( CMS_UI, CMS_SEARCHSUBDIRS, CDS_ENABLE ) )
+#define CDS_WriteSearchSubdirs( x ) CDS_SaveInt( CMS_UI, CMS_SEARCHSUBDIRS, CDS_GetSearchSubdirs( x ) )
+
+
+// CDS DEBUG READ/WRITE MACROS
+
+#define CDS_ReadDebugFlag( x ) CDS_SetDebugFlag( x, CDS_GetInt ( CMS_DEBUG, CMS_DEBUGFLAG, CDS_DISABLE ) )
+#define CDS_WriteDebugFlag( x ) CDS_SaveHexInt( CMS_DEBUG, CMS_DEBUGFLAG, CDS_GetDebugFlag( x ) )
+
+#define CDS_ReadDebugToFile( x ) CDS_SetDebugToFile( x, CDS_GetInt ( CMS_DEBUG, CMS_TOFILE, CDS_DISABLE ) )
+#define CDS_WriteDebugToFile( x ) CDS_SaveInt( CMS_DEBUG, CMS_TOFILE, CDS_GetDebugToFile( x ) )
+
+#define CDS_ReadDebugFileName( x ) CDS_GetString( CMS_DEBUG, CMS_DEBUGFILE, DEBUG_FILE, CDS_GetDebugFileName( x ), MAX_UI_FILENAME_SIZE )
+#define CDS_WriteDebugFileName( x ) CDS_SaveString( CMS_DEBUG, CMS_DEBUGFILE, CDS_GetDebugFileName( x ) )
+
+#define CDS_ReadDebugToWindow( x ) CDS_SetDebugToWindow( x, CDS_GetInt ( CMS_DEBUG, CMS_TOWINDOW, CDS_ENABLE ) )
+#define CDS_WriteDebugToWindow( x ) CDS_SaveInt( CMS_DEBUG, CMS_TOWINDOW, CDS_GetDebugToWindow( x ) )
+
+#define CDS_ReadDebugWindowShowAll( x ) CDS_SetDebugWindowShowAll( x, CDS_GetInt ( CMS_DEBUG, CMS_SHOWALL, CDS_DISABLE ) )
+#define CDS_WriteDebugWindowShowAll( x ) CDS_SaveInt( CMS_DEBUG, CMS_SHOWALL, CDS_GetDebugWindowShowAll( x ) )
+
+#define CDS_ReadDebugWindowNumLines( x ) CDS_SetDebugWindowNumLines( x, CDS_GetInt ( CMS_DEBUG, CMS_DEBUGLINES, DEBUG_DEF_LINES ) )
+#define CDS_WriteDebugWindowNumLines( x ) CDS_SaveInt( CMS_DEBUG, CMS_DEBUGLINES, CDS_GetDebugWindowNumLines( x ) )
+
+#define CDS_ReadPollFrequency( x ) CDS_SetPollFrequency( x, CDS_GetInt ( CMS_DEBUG, CMS_POLLFREQ, POLL_DEF_FREQ ) )
+#define CDS_WritePollFrequency( x ) CDS_SaveInt( CMS_DEBUG, CMS_POLLFREQ, CDS_GetPollFrequency( x ) )
+
+
+// CDS DISPLAY READ/WRITE MACROS
+
+#define CDS_ReadShowMainRibbon( x ) CDS_SetShowMainRibbon( x, CDS_GetInt ( CMS_DISPLAY, CMS_MAINRIB, CDS_ENABLE ) )
+#define CDS_WriteShowMainRibbon( x ) CDS_SaveInt( CMS_DISPLAY, CMS_MAINRIB, CDS_GetShowMainRibbon( x ) )
+
+#define CDS_ReadShowStatusLine( x ) CDS_SetShowStatusLine( x, CDS_GetInt ( CMS_DISPLAY, CMS_STATLINE, CDS_ENABLE ) )
+#define CDS_WriteShowStatusLine( x ) CDS_SaveInt( CMS_DISPLAY, CMS_STATLINE, CDS_GetShowStatusLine( x ) )
+
+#define CDS_ReadFontFace( x ) CDS_GetString( CMS_DISPLAY, CMS_FONTFACE, FONT_NAME, CDS_GetFontFace( x ), LF_FULLFACESIZE )
+#define CDS_WriteFontFace( x ) CDS_SaveString( CMS_DISPLAY, CMS_FONTFACE, CDS_GetFontFace( x ) )
+
+#define CDS_ReadFontSize( x ) CDS_SetFontSize( x, CDS_GetInt ( CMS_DISPLAY, CMS_FONTSIZE, FONT_SIZE ) )
+#define CDS_WriteFontSize( x ) CDS_SaveInt( CMS_DISPLAY, CMS_FONTSIZE, CDS_GetFontSize( x ) )
+
+#define CDS_ReadFontWeight( x ) CDS_SetFontWeight( x, CDS_GetInt ( CMS_DISPLAY, CMS_FONTWEIGHT, FONT_WEIGHT ) )
+#define CDS_WriteFontWeight( x ) CDS_SaveInt( CMS_DISPLAY, CMS_FONTWEIGHT, CDS_GetFontWeight( x ) )
+
+#define CDS_ReadFontCase( x ) CDS_SetFontCase( x, CDS_GetInt ( CMS_DISPLAY, CMS_FONTCASE, CDS_DISABLE ) )
+#define CDS_WriteFontCase( x ) CDS_SaveInt( CMS_DISPLAY, CMS_FONTCASE, CDS_GetFontCase( x ) )
+
+#define CDS_ReadFontCaseFAT( x ) CDS_SetFontCaseFAT( x, CDS_GetInt ( CMS_DISPLAY, CMS_FONTCASEFAT, CDS_ENABLE ) )
+#define CDS_WriteFontCaseFAT( x ) CDS_SaveInt( CMS_DISPLAY, CMS_FONTCASEFAT, CDS_GetFontCaseFAT( x ) )
+
+#define CDS_ReadFontItalics( x ) CDS_SetFontItalics( x, CDS_GetInt ( CMS_DISPLAY, CMS_FONTITALICS, CDS_DISABLE ) )
+#define CDS_WriteFontItalics( x ) CDS_SaveInt( CMS_DISPLAY, CMS_FONTITALICS, CDS_GetFontItalics( x ) )
+
+#define CDS_ReadFileDetails( x ) CDS_SetFileDetails( x, CDS_GetInt ( CMS_DISPLAY, CMS_FILEDETAILS, CDS_DISABLE ) )
+#define CDS_WriteFileDetails( x ) CDS_SaveInt( CMS_DISPLAY, CMS_FILEDETAILS, CDS_GetFileDetails( x ) )
+
+#define CDS_ReadSortOptions( x ) CDS_SetSortOptions( x, CDS_GetInt ( CMS_DISPLAY, CMS_SORTOPTIONS, ID_SORTNAME ) )
+#define CDS_WriteSortOptions( x ) CDS_SaveInt( CMS_DISPLAY, CMS_SORTOPTIONS, CDS_GetSortOptions( x ) )
+
+#define CDS_ReadWindowSize( x, y ) CDS_GetString( CMS_DISPLAY, x, TEXT(""), y, MAX_UI_RESOURCE_SIZE )
+#define CDS_WriteWindowSize( x, y ) CDS_SaveString( CMS_DISPLAY, x, y )
+
+#define CDS_ReadFrameWinSize( x ) CDS_GetWinSize( CMS_FRAMEWINDOW, &(x)->frame_info )
+#define CDS_WriteFrameWinSize( x ) CDS_SaveWinSize( CMS_FRAMEWINDOW, x )
+
+#define CDS_ReadDiskWinSize( x ) CDS_GetWinSize( CMS_DISKWINDOW, &(x)->disk_info )
+#define CDS_WriteDiskWinSize( x ) CDS_SaveMDIWinSize( CMS_DISKWINDOW, x )
+
+#define CDS_ReadServerWinSize( x ) CDS_GetWinSize( CMS_SERVERWINDOW, &(x)->server_info )
+#define CDS_WriteServerWinSize( x ) CDS_SaveMDIWinSize( CMS_SERVERWINDOW, x )
+
+#define CDS_ReadTapeWinSize( x ) CDS_GetWinSize( CMS_TAPEWINDOW, &(x)->tape_info )
+#define CDS_WriteTapeWinSize( x ) CDS_SaveMDIWinSize( CMS_TAPEWINDOW, x )
+
+#define CDS_ReadLogWinSize( x ) CDS_GetWinSize( CMS_LOGWINDOW, &(x)->log_info )
+#define CDS_WriteLogWinSize( x ) CDS_SaveMDIWinSize( CMS_LOGWINDOW, x )
+
+#define CDS_ReadDebugWinSize( x ) CDS_GetWinSize( CMS_DEBUGWINDOW, &(x)->debug_info )
+#define CDS_WriteDebugWinSize( x ) CDS_SaveMDIWinSize( CMS_DEBUGWINDOW, x )
+
+#define CDS_ReadRuntimeWinSize( x ) CDS_GetWinSize( CMS_RUNTIMEDLG, &(x)->runtime_info )
+#define CDS_WriteRuntimeWinSize( x ) CDS_SaveDlgWinSize( CMS_RUNTIMEDLG, x )
+
+// CDS LOG READ/WRITE MACROS
+
+#define CDS_ReadLogFileRoot( x ) CDS_GetString( CMS_LOGGING, CMS_LOGFILEROOT, SHORTAPPNAME, CDS_GetLogFileRoot( x ), MAX_UI_LOGFILEROOT_SIZE )
+#define CDS_WriteLogFileRoot( x ) CDS_SaveString( CMS_LOGGING, CMS_LOGFILEROOT, CDS_GetLogFileRoot( x ) )
+
+#define CDS_ReadLogMode( x ) CDS_SetLogMode( x, CDS_GetInt ( CMS_LOGGING, CMS_LOGMODE, LOG_TO_FILE ) )
+#define CDS_WriteLogMode( x ) CDS_SaveInt( CMS_LOGGING, CMS_LOGMODE, CDS_GetLogMode( x ) )
+
+#define CDS_ReadLogLevel( x ) CDS_SetLogLevel( x, CDS_GetInt ( CMS_LOGGING, CMS_LOGLEVEL, LOG_ERRORS ) )
+#define CDS_WriteLogLevel( x ) CDS_SaveInt( CMS_LOGGING, CMS_LOGLEVEL, CDS_GetLogLevel( x ) )
+
+#define CDS_ReadHWCompMode( x ) CDS_SetHWCompMode( x, CDS_GetInt ( CMS_HARDWARE, CMS_HWCOMPMODE, HW_COMP_DISABLE ) ) // chs:05-04-93
+#define CDS_WriteHWCompMode( x ) CDS_SaveInt( CMS_HARDWARE, CMS_HWCOMPMODE, CDS_GetHWCompMode( x ) ) // chs:05-04-93
+
+#define CDS_ReadSWCompMode( x ) CDS_SetSWCompMode( x, CDS_GetInt ( CMS_HARDWARE, CMS_SWCOMPMODE, SW_COMP_DISABLE ) ) // chs:05-04-93
+#define CDS_WriteSWCompMode( x ) CDS_SaveInt( CMS_HARDWARE, CMS_SWCOMPMODE, CDS_GetSWCompMode( x ) ) // chs:05-04-93
+
+#define CDS_ReadNumLogSessions( x ) CDS_SetNumLogSessions( x, CDS_GetInt ( CMS_LOGGING, CMS_NUMSESSIONS, LOG_DEF_LOGFILES ) )
+#define CDS_WriteNumLogSessions( x ) CDS_SaveInt( CMS_LOGGING, CMS_NUMSESSIONS, CDS_GetNumLogSessions( x ) )
+
+#define CDS_ReadPrintLogSession( x ) CDS_SetPrintLogSession( x, CDS_GetInt ( CMS_LOGGING, CMS_PRINTSESSION, LOG_PRINT_OFF ) )
+#define CDS_WritePrintLogSession( x ) CDS_SaveInt( CMS_LOGGING, CMS_PRINTSESSION, CDS_GetPrintLogSession( x ) )
+
+
+// CDS HARDWARE READ/WRITE MACROS
+
+#define CDS_ReadActiveDriver( x ) CDS_GetString( CMS_HARDWARE, CMS_DRIVER, CMS_AUTO, CDS_GetActiveDriver( x ), DRIVER_SIZE )
+#define CDS_WriteActiveDriver( x ) CDS_SaveString( CMS_HARDWARE, CMS_DRIVER, CDS_GetActiveDriver( x ) )
+
+#define CDS_ReadTapeDriveName( x ) CDS_GetString( CMS_HARDWARE, CMS_TAPEDRIVE, CMS_AUTO, CDS_GetTapeDriveName( x ), MAXTAPEDRIVENAME )
+#define CDS_WriteTapeDriveName( x ) CDS_SaveString( CMS_HARDWARE, CMS_TAPEDRIVE, CDS_GetTapeDriveName( x ) )
+
+#define CDS_ReadTapeDriveSettlingTime( x ) CDS_SetTapeDriveSettlingTime( x, CDS_GetInt ( CMS_HARDWARE, CMS_SETTLINGTIME, DEF_DRIVE_SETTLING_TIME ) )
+#define CDS_WriteTapeDriveSettlingTime( x ) CDS_SaveInt( CMS_HARDWARE, CMS_SETTLINGTIME, CDS_GetTapeDriveSettlingTime( x ) )
+
+// CDS NT HARDWARE READ/WRITE MACROS
+
+// #define CDS_ReadTapeDriveCard( ) CDS_GetInt( CMS_HARDWARE, CMS_CARD, CDS_UNKNOWN )
+// #define CDS_WriteTapeDriveCard( x ) CDS_SaveInt( CMS_HARDWARE, CMS_CARD, ( x ) )
+//
+// #define CDS_ReadTapeDriveBus( ) CDS_GetInt( CMS_HARDWARE, CMS_BUS, CDS_UNKNOWN )
+// #define CDS_WriteTapeDriveBus( x ) CDS_SaveInt( CMS_HARDWARE, CMS_BUS, ( x ) )
+//
+// #define CDS_ReadTapeDriveTarget( ) CDS_GetInt( CMS_HARDWARE, CMS_TARGET, CDS_UNKNOWN )
+// #define CDS_WriteTapeDriveTarget( x ) CDS_SaveInt( CMS_HARDWARE, CMS_TARGET, ( x ) )
+//
+// #define CDS_ReadTapeDriveLUN( ) CDS_GetInt( CMS_HARDWARE, CMS_LUN, CDS_UNKNOWN )
+// #define CDS_WriteTapeDriveLUN( x ) CDS_SaveInt( CMS_HARDWARE, CMS_LUN, ( x ) )
+
+// CDS BACKUP ENGINE READ/WRITE MACROS
+
+#define CDS_ReadSkipOpenFiles( x ) CDS_SetSkipOpenFiles( x, (INT16)CDS_GetInt( CMS_UI, CMS_SKIP_OPEN_FILES, CDS_DISABLE ) )
+#define CDS_WriteSkipOpenFiles( x ) CDS_SaveInt( CMS_UI, CMS_SKIP_OPEN_FILES, CDS_GetSkipOpenFiles( x ) )
+
+#define CDS_ReadBackupFilesInUse( x ) CDS_SetBackupFilesInUse( x, (INT16)CDS_GetInt( CMS_BENGINE, CMS_BACKUP_FILES_INUSE, CDS_DISABLE ) )
+#define CDS_WriteBackupFilesInUse( x ) CDS_SaveInt( CMS_BENGINE, CMS_BACKUP_FILES_INUSE, CDS_GetBackupFilesInUse( x ) )
+
+#define CDS_ReadHiddenFlag( x ) CDS_SetHiddenFlag( x, (INT16)CDS_GetInt( CMS_BENGINE, CMS_HIDDEN_FLAG, CDS_ENABLE ) )
+#define CDS_WriteHiddenFlag( x ) CDS_SaveInt( CMS_BENGINE, CMS_HIDDEN_FLAG, CDS_GetHiddenFlag( x ) )
+
+#define CDS_ReadSpecialFlag( x ) CDS_SetSpecialFlag( x, (INT16)CDS_GetInt( CMS_BENGINE, CMS_SPECIAL_FLAG, CDS_ENABLE ) )
+#define CDS_WriteSpecialFlag( x ) CDS_SaveInt( CMS_BENGINE, CMS_SPECIAL_FLAG, CDS_GetSpecialFlag( x ) )
+
+#define CDS_ReadSetArchiveFlag( x ) CDS_SetSetArchiveFlag( x, (INT16)CDS_GetInt( CMS_BENGINE, CMS_SET_ARCHIVE_FLAG, CMI_ARCBIT ) )
+#define CDS_WriteSetArchiveFlag( x ) CDS_SaveInt( CMS_BENGINE, CMS_SET_ARCHIVE_FLAG, CDS_GetSetArchiveFlag( x ) )
+
+#define CDS_ReadExistFlag( x ) CDS_SetExistFlag( x, (INT16)CDS_GetInt( CMS_BENGINE, CMS_EXIST_FLAG, CDS_ENABLE ) )
+#define CDS_WriteExistFlag( x ) CDS_SaveInt( CMS_BENGINE, CMS_EXIST_FLAG, CDS_GetExistFlag( x ) )
+
+#define CDS_ReadPromptFlag( x ) CDS_SetPromptFlag( x, (INT16)CDS_GetInt( CMS_BENGINE, CMS_PROMPT_FLAG, CDS_DISABLE ) )
+#define CDS_WritePromptFlag( x ) CDS_SaveInt( CMS_BENGINE, CMS_PROMPT_FLAG, CDS_GetPromptFlag( x ) )
+
+#define CDS_ReadTFLBuffSize( x ) CDS_SetTFLBuffSize( x, (INT16)CDS_GetInt( CMS_BENGINE, CMS_TFL_BUFF_SIZE, BUFF_SIZE_TFL ) )
+#define CDS_WriteTFLBuffSize( x ) CDS_SaveInt( CMS_BENGINE, CMS_TFL_BUFF_SIZE, CDS_GetTFLBuffSize( x ) )
+
+#define CDS_ReadAFPSupport( x ) CDS_SetAFPSupport( x, (INT16)CDS_GetInt( CMS_BENGINE, CMS_SUPPORT_AFP_SERVER, CDS_ENABLE ) )
+#define CDS_WriteAFPSupport( x ) CDS_SaveInt( CMS_BENGINE, CMS_SUPPORT_AFP_SERVER, CDS_GetAFPSupport( x ) )
+
+#define CDS_ReadExtendedDateSupport( x ) CDS_SetExtendedDateSupport( x, (INT16)CDS_GetInt( CMS_BENGINE, CMS_EXTENDED_DATE_SUPPORT, CDS_ENABLE ) )
+#define CDS_WriteExtendedDateSupport( x ) CDS_SaveInt( CMS_BENGINE, CMS_EXTENDED_DATE_SUPPORT, CDS_GetExtendedDateSupport( x ) )
+
+#define CDS_ReadProcEmptyFlag( x ) CDS_SetProcEmptyFlag( x, (INT16)CDS_GetInt( CMS_BENGINE, CMS_PROC_EMPTY_FLAG, CDS_ENABLE ) )
+#define CDS_WriteProcEmptyFlag( x ) CDS_SaveInt( CMS_BENGINE, CMS_PROC_EMPTY_FLAG, CDS_GetProcEmptyFlag( x ) )
+
+#define CDS_ReadFastFileRestore( x ) CDS_SetFastFileRestore( x, (BOOLEAN)CDS_GetInt( CMS_BENGINE, CMS_USE_FFR, CDS_ENABLE ) )
+#define CDS_WriteFastFileRestore( x ) CDS_SaveInt( CMS_BENGINE, CMS_USE_FFR, CDS_GetFastFileRestore( x ) )
+
+#define CDS_ReadConfiguredMachineType( x ) CDS_SetConfiguredMachineType( x, (UINT16)CDS_GetInt( CMS_BENGINE, CMS_MACHINE_TYPE, UNKNOWN_MACHINE ) )
+#define CDS_WriteConfiguredMachineType( x ) CDS_SaveInt( CMS_BENGINE, CMS_MACHINE_TYPE, CDS_GetConfiguredMachineType( x ) )
+
+
+#define CDS_ReadSpecialWord( x ) CDS_SetSpecialWord( x, (INT16)CDS_GetInt( CMS_BENGINE, CMS_SPECIAL_WORD, NOTHING_SPECIAL ) )
+#define CDS_WriteSpecialWord( x ) CDS_SaveHexInt( CMS_BENGINE, CMS_SPECIAL_WORD, CDS_GetSpecialWord( x ) )
+
+#define CDS_ReadMaxTapeBuffers( x ) CDS_SetMaxTapeBuffers( x, (UINT16)CDS_GetLongInt( CMS_BENGINE, CMS_MAX_NUM_TAPE_BUFS, TAPE_BUFS_DEFAULT ) )
+#define CDS_WriteMaxTapeBuffers( x ) CDS_SaveInt( CMS_BENGINE, CMS_MAX_NUM_TAPE_BUFS, CDS_GetMaxTapeBuffers( x ) )
+
+#define CDS_ReadMaxBufferSize( x ) CDS_SetMaxBufferSize( x, (INT16)CDS_GetInt( CMS_BENGINE, CMS_MAX_BUFFER_SIZE, BUFF_SIZE_SMB ) )
+#define CDS_WriteMaxBufferSize( x ) CDS_SaveInt( CMS_BENGINE, CMS_MAX_BUFFER_SIZE, CDS_GetMaxBufferSize( x ) )
+
+#define CDS_ReadNetNum( x ) CDS_SetNetNum( x, (INT16)CDS_GetInt( CMS_BENGINE, CMS_NET_NUM, NO_NETWORK ) )
+#define CDS_WriteNetNum( x ) CDS_SaveInt( CMS_BENGINE, CMS_NET_NUM, CDS_GetNetNum( x ) )
+
+#define CDS_ReadSortBSD( x ) CDS_SetSortBSD( x, (INT16)CDS_GetInt( CMS_BENGINE, CMS_SORT_BSD, CDS_ENABLE ) )
+#define CDS_WriteSortBSD( x ) CDS_SaveInt( CMS_BENGINE, CMS_SORT_BSD, CDS_GetSortBSD( x ) )
+
+#define CDS_ReadRemoteDriveBackup( x ) CDS_SetRemoteDriveBackup( x, (INT16)CDS_GetInt( CMS_BENGINE, CMS_REMOTE_DRIVE_BACKUP, CMI_REMOTE ) )
+#define CDS_WriteRemoteDriveBackup( x ) CDS_SaveInt( CMS_BENGINE, CMS_REMOTE_DRIVE_BACKUP, CDS_GetRemoteDriveBackup( x ) )
+
+#define CDS_ReadWriteFormat( x ) CDS_SetWriteFormat( x, (UINT16)CDS_GetInt( CMS_BENGINE, CMS_WRITE_FORMAT, TAPE_FORMAT_DEFAULT ) )
+#define CDS_WriteWriteFormat( x ) CDS_SaveInt( CMS_BENGINE, CMS_WRITE_FORMAT, CDS_GetWriteFormat( x ) )
+
+#define CDS_ReadNRLDosVector( x ) CDS_SetNRLDosVector( x, (UINT16)CDS_GetInt( CMS_BENGINE, CMS_NRL_DOS_VECTOR, 0x60 ) )
+#define CDS_WriteNRLDosVector( x ) CDS_SaveHexInt( CMS_BENGINE, CMS_NRL_DOS_VECTOR, CDS_GetNRLDosVector( x ) )
+
+#define CDS_ReadOTCLevel( x ) CDS_SetOTCLevel( x, (UINT16)CDS_GetInt( CMS_BENGINE, CMS_OTC_LEVEL, CATALOGS_FULL ) )
+#define CDS_WriteOTCLevel( x ) CDS_SaveInt( CMS_BENGINE, CMS_OTC_LEVEL, CDS_GetNRLDosVector( x ) )
+
+#define CDS_ReadProcessSytronECCFlag( x ) CDS_SetProcessSytronECCFlag( x, (INT16)CDS_GetInt( CMS_TRANSLATORS, CMS_PROC_SYTRON_ECC, SYPL_ECC_AUTO ) )
+#define CDS_WriteProcessSytronECCFlag( x ) CDS_SaveInt( CMS_TRANSLATORS, CMS_PROC_SYTRON_ECC, CDS_GetProcessSytronECCFlag( x ) )
+
+#endif // end _muiconf_h_
+
diff --git a/private/utils/ntbackup/inc/muiutil.h b/private/utils/ntbackup/inc/muiutil.h
new file mode 100644
index 000000000..45f0ef2c6
--- /dev/null
+++ b/private/utils/ntbackup/inc/muiutil.h
@@ -0,0 +1,136 @@
+
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: muiutil.h
+
+ Description: header file for mui utilities
+
+ $Log: G:\ui\logfiles\muiutil.h_v $
+
+ Rev 1.11 24 Jun 1993 17:06:50 CARLS
+added UI_CurrentDateLeadingZero and UI_CurrentTimeLeadingZero prototypes
+
+ Rev 1.10 23 Jun 1993 09:21:32 GLENN
+Added WM_IsMultiTaskBusy().
+
+ Rev 1.9 01 Nov 1992 16:31:52 DAVEV
+Unicode changes
+
+ Rev 1.8 04 Oct 1992 19:48:16 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.7 12 Feb 1992 18:04:40 CHUCKB
+Removed prototype for ValidatePath.
+
+ Rev 1.6 12 Feb 1992 16:29:58 CHUCKB
+Added prototype for ValidatePath.
+
+ Rev 1.5 10 Feb 1992 10:39:32 CHUCKB
+Moved prototype for BuildNumeralWithCommas from details.h to muiutil.h.
+
+ Rev 1.4 03 Jan 1992 17:53:54 CHUCKB
+Added prototype for UI_MakeShortTimeString.
+
+ Rev 1.3 10 Dec 1991 09:45:14 CHUCKB
+Changed prototype for makeautojobs.
+
+ Rev 1.2 09 Dec 1991 17:04:16 CHUCKB
+Added prototype for MakeAutoJobs.
+
+ Rev 1.1 03 Dec 1991 16:01:28 GLENN
+Changed UI_ParseShortDate and UI_ParseTime to UI_InitDate and UI_InitTime.
+
+ Rev 1.0 20 Nov 1991 19:42:02 SYSTEM
+Initial revision.
+
+*****************************************************/
+
+#ifndef MUIUTIL_H
+#define MUIUTIL_H
+
+// defines for string conversions
+
+#ifdef UNICODE
+# undef AnsiLower
+# undef AnsiLowerBuff
+# undef AnsiUpper
+# undef AnsiUpperBuff
+
+# define AnsiLower CharLowerW
+# define AnsiLowerBuff CharLowerBuffW
+# define AnsiUpper CharUpperW
+# define AnsiUpperBuff CharUpperBuffW
+#endif
+
+#ifdef tolower
+#undef tolower
+#define tolower(x) UI_AnsiLowerChar(x)
+#endif
+
+#ifdef toupper
+#undef toupper
+#define toupper(x) UI_AnsiUpperChar(x)
+#endif
+
+#ifdef strlwr
+#undef strlwr
+#define strlwr(x) UI_AnsiLowerString(x)
+#endif
+
+#ifdef strupr
+#undef strupr
+#define strupr(x) UI_AnsiUpperString(x)
+#endif
+
+#define ThreadSwitch() WM_MultiTask()
+
+// defines for short date formats
+
+#define MDY 1
+#define DMY 2
+#define YMD 3
+
+#define UI_COMMA_SPACING ( 3 )
+
+// international date/time function prototypes
+
+INT16 UI_AnsiLowerChar ( INT16 ) ;
+CHAR_PTR UI_AnsiLowerString ( CHAR_PTR ) ;
+INT16 UI_AnsiUpperChar ( INT16 ) ;
+CHAR_PTR UI_AnsiUpperString ( CHAR_PTR ) ;
+VOID UI_BuildNumeralWithCommas ( CHAR_PTR ) ;
+VOID UI_CurrentDateLeadingZero ( LPSTR ) ;
+VOID UI_CurrentDate ( LPSTR ) ;
+VOID UI_CurrentTimeLeadingZero ( LPSTR ) ;
+VOID UI_CurrentTime ( LPSTR ) ;
+VOID UI_GetAMString ( LPSTR ) ;
+INT UI_GetDateFormat ( VOID ) ;
+CHAR UI_GetDateSeparator ( VOID ) ;
+VOID UI_GetPMString ( LPSTR ) ;
+CHAR UI_GetTimeSeparator ( VOID ) ;
+
+VOID UI_IntToDate ( LPSTR, UINT16 ) ;
+VOID UI_IntToTime ( LPSTR, UINT16 ) ;
+VOID UI_LongToDate ( LPSTR, LONG ) ;
+VOID UI_LongToTime ( LPSTR, LONG ) ;
+
+VOID UI_MakeDateString ( LPSTR, INT, INT, INT ) ;
+VOID UI_MakeShortTimeString ( LPSTR, INT, INT ) ;
+VOID UI_MakeTimeString ( LPSTR, INT, INT, INT ) ;
+VOID UI_MakeAutoJobs ( INT ) ;
+VOID UI_InitIntl ( VOID ) ;
+VOID UI_InitDate ( VOID ) ;
+VOID UI_InitThousandsChar ( VOID ) ;
+VOID UI_InitTime ( VOID ) ;
+
+BOOL UI_UseLeadCentury ( VOID ) ;
+BOOL UI_UseLeadDays ( VOID ) ;
+BOOL UI_UseLeadMonth ( VOID ) ;
+BOOL UI_UseLeadTime ( VOID ) ;
+BOOL UI_Use24Hour ( VOID ) ;
+
+VOID WM_MultiTask ( VOID ) ;
+BOOL WM_IsMultiTaskBusy ( VOID ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/nets.h b/private/utils/ntbackup/inc/nets.h
new file mode 100644
index 000000000..ed4d5e968
--- /dev/null
+++ b/private/utils/ntbackup/inc/nets.h
@@ -0,0 +1,40 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: nets.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+ Location:
+
+
+ $Log: N:/LOGFILES/NETS.H_V $
+ *
+ * Rev 1.1 11 Sep 1991 09:58:44 DON
+ * changed 'far' to PTR_SIZE - defined in stdtypes.h for portability
+ *
+ * Rev 1.0 09 May 1991 13:31:54 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef _nets_h_
+#define _nets_h_
+
+typedef struct NET_TABLE PTR_SIZE *NET_TABLE_PTR;
+typedef struct NET_ROUTE PTR_SIZE *NET_ROUTE_PTR;
+
+extern NET_TABLE_PTR NETS_AllocateTable( UINT16 max_nets );
+
+extern INT16 NETS_Initialize( VOID ) ;
+extern VOID NETS_DeInitialize( VOID );
+
+extern VOID NETS_LoadInternetwork( NET_TABLE_PTR cur_table, PF_VOID func );
+
+extern NET_ROUTE_PTR NETS_AddNetwork( NET_TABLE_PTR net_table, UINT32 new_net_num );
+
+#endif
diff --git a/private/utils/ntbackup/inc/network.h b/private/utils/ntbackup/inc/network.h
new file mode 100644
index 000000000..b1b2fcb80
--- /dev/null
+++ b/private/utils/ntbackup/inc/network.h
@@ -0,0 +1,35 @@
+
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1992
+
+ Name: network.h
+
+ Description: Contains dialog control id's for the network settings dialog
+
+ $Log: G:/UI/LOGFILES/NETWORK.H_V $
+
+ Rev 1.1 04 Oct 1992 19:48:16 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.0 06 Apr 1992 04:05:00 CHUCKB
+Initial revision.
+
+*****************************************************/
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_SETTINGSNETWORK 17
+#else
+#include "dlg_ids.h"
+#endif
+
+
+/* network controls */
+
+#define IDD_NET_MAPPED 101
+#define IDD_NET_SERVVOL 102
+#define IDD_NET_DBGROUPBOX 103
+#define IDD_NET_USEDB 104
+#define IDD_NET_ENTERPW 105
+#define IDD_NET_HELP 106
+#define IDD_NET_REMOVEPW 107
diff --git a/private/utils/ntbackup/inc/nextset.h b/private/utils/ntbackup/inc/nextset.h
new file mode 100644
index 000000000..c889eb91c
--- /dev/null
+++ b/private/utils/ntbackup/inc/nextset.h
@@ -0,0 +1,37 @@
+
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1992
+
+ Name: nextset.h
+
+ Description: Contains dialog control id's for the next set dialog,
+ which starts a search to the next set on a cataloged tape
+
+ $Log: G:/UI/LOGFILES/NEXTSET.H_V $
+
+ Rev 1.2 04 Oct 1992 19:48:18 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.1 07 Apr 1992 08:57:48 CARLS
+removed HELP ID for translate
+
+ Rev 1.0 06 Apr 1992 04:05:00 CHUCKB
+Initial revision.
+
+
+*****************************************************/
+
+
+#ifdef TRANSLATE
+#define IDD_NEXT_SET 42
+#else
+#include "dlg_ids.h"
+#endif
+
+
+/* next set dialog box defines */
+
+#define IDD_NEXT_TEXT 100
+#define IDD_NEXT_OK 101
+#define IDD_NEXT_ABORT 102
+#define IDD_NEXT_HELP 103
diff --git a/private/utils/ntbackup/inc/nonafp.h b/private/utils/ntbackup/inc/nonafp.h
new file mode 100644
index 000000000..f444ac0ed
--- /dev/null
+++ b/private/utils/ntbackup/inc/nonafp.h
@@ -0,0 +1,179 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: nonafp.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Prototypes for the NON AFP novell file system support
+ functions.
+
+
+ $Log: N:/LOGFILES/NONAFP.H_V $
+ *
+ * Rev 1.8 03 Dec 1992 13:30:22 CARLS
+ * added NOV_IsBlkComplete
+ *
+ * Rev 1.7 15 Oct 1992 13:21:48 CARLS
+ * added active_stream_id to NOV_FILE_HAND for MTF 4.0
+ *
+ * Rev 1.6 22 Sep 1992 17:14:46 CHUCKB
+ * Removed references to fs_GetTotalSizeDBLK().
+ *
+ * Rev 1.5 15 Sep 1992 10:17:20 CARLS
+ * updated read,write,verifyObj prototypes
+ *
+ * Rev 1.4 28 Aug 1992 16:26:00 BARRY
+ * Updated prototypes for formerly common functions.
+ *
+ * Rev 1.3 08 Jul 1992 15:20:02 BARRY
+ * Added NOV_SetTempHandle prototype.
+ *
+ * Rev 1.2 20 Dec 1991 09:12:08 STEVEN
+ * move common functions into tables
+ *
+ * Rev 1.1 23 May 1991 16:46:06 BARRY
+ * Changes for FindFirst/Next to scan for dirs only
+ *
+ * Rev 1.0 09 May 1991 13:32:32 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef NONAFP_H
+#define NONAFP_H
+
+
+typedef struct NOV_FILE_HAND_STRUCT {
+ INT16 dos_data_hand ; /* DOS handle for the file */
+ UINT32 data_size ; /* Number of bytes needed for file data */
+ UINT32 data_offset ; /* Offset to normal file data */
+ UINT32 trust_size ; /* Number of bytes needed for trustees */
+ UINT32 trust_offset ; /* Offset to trustee info */
+ UINT8 trust_format ; /* Format specifier for trustee fork */
+ UINT16 trust_index ; /* Holds trust read index between calls */
+ CHAR file_name[14] ; /* File name for subsequent trust calls */
+ UINT32 active_stream_id ; /* ID of stream being processed */
+} NOV_FILE_HAND_STRUCT, *NOV_FILE_HAND;
+
+
+INT16 NOV_FindDrives( DLE_HAND hand, BE_CFG_PTR cfg, UINT32 mask );
+
+INT16 NOV_AttachToDLE( FSYS_HAND fsh, GENERIC_DLE_PTR dle,
+ CHAR_PTR uname, CHAR_PTR pswd ) ;
+
+INT16 NOV_DetachDLE( FSYS_HAND fsh ) ;
+
+INT16 NOV_MatchDBLK( FSYS_HAND fsh, DBLK_PTR ddb1, DBLK_PTR fdb1,
+ BOOLEAN disp_flag, struct FSE *fse ) ;
+
+INT16 NOV_GetCurrentDDB( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+INT16 NOV_GetCurrentPath( FSYS_HAND fsh, CHAR_PTR path, INT16 *size ) ;
+
+INT16 NOV_GetBasePath( FSYS_HAND fsh, CHAR_PTR path, INT16 *size ) ;
+
+INT16 NOV_ChangeDir( FSYS_HAND fsh, CHAR_PTR path, INT16 psize ) ;
+
+INT16 NOV_UpDir( FSYS_HAND fsh ) ;
+
+
+INT16 NOV_CreateObj( FSYS_HAND fsh, DBLK_PTR dblk );
+
+INT16 NOV_OpenObj( FSYS_HAND fsh, FILE_HAND *hand, DBLK_PTR dblk,
+ OPEN_MODE Mode ) ;
+
+INT16 NOV_SeekObj( FILE_HAND hand, UINT32 *offset ) ;
+
+INT16 NOV_ReadObj( FILE_HAND hand, CHAR_PTR buffer, UINT16 *size, UINT16 *blk_size, STREAM_INFO_PTR s_info ) ;
+
+INT16 NOV_WriteObj( FILE_HAND hand, CHAR_PTR buffer, UINT16 *size, UINT16 *blk_size, STREAM_INFO_PTR s_info ) ;
+
+INT16 NOV_VerObj( FILE_HAND hand, CHAR_PTR buffer, CHAR_PTR data,
+ UINT16 *size, UINT16 *blk_size, STREAM_INFO_PTR s_info ) ;
+
+INT16 NOV_CloseObj( FILE_HAND hand ) ;
+
+INT16 NOV_DeleteObj( FSYS_HAND fsh, DBLK_PTR dblk );
+
+INT16 NOV_GetObjInfo( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+
+INT16 NOV_SetObjInfo( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+
+INT16 NOV_VerObjInfo( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+
+INT16 NOV_FindFirst( FSYS_HAND fsh, DBLK_PTR ddb, CHAR_PTR os_name, UINT16 find_type ) ;
+
+INT16 NOV_FindNext( FSYS_HAND fsh, DBLK_PTR Info ) ;
+
+INT16 NOV_PushMinDDB( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+INT16 NOV_PopMinDDB( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+INT16 NOV_GetSpecDBLKS( FSYS_HAND fsh, DBLK_PTR cblock, INT32 *index );
+
+INT16 NOV_ModFnameFDB( FSYS_HAND fsh, BOOLEAN set_it, DBLK_PTR fdb, CHAR_PTR buf, INT16 *size );
+
+INT16 NOV_ModPathDDB( FSYS_HAND fsh, BOOLEAN set_it, DBLK_PTR fdb, CHAR_PTR buf, INT16 *size );
+
+INT16 NOV_GetOSFnameFDB( DBLK_PTR fdb, CHAR_PTR buf );
+
+INT16 NOV_GetOSPathDDB( FSYS_HAND fsh, DBLK_PTR fdb, CHAR_PTR buf );
+
+INT16 NOV_GetCdateDBLK( DBLK_PTR dblk, DATE_TIME *buf ) ;
+
+INT16 NOV_ModBdateDBLK( BOOLEAN set_it, DBLK_PTR dblk, DATE_TIME *buf ) ;
+
+INT16 NOV_GetMdateDBLK( DBLK_PTR dblk, DATE_TIME *buf ) ;
+
+INT16 NOV_ModAdateDBLK( BOOLEAN set_it, DBLK_PTR dblk, DATE_TIME *buf ) ;
+
+UINT64 NOV_GetDispSizeDBLK( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+
+// UINT64 NOV_GetTotalSizeDBLK( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+
+INT16 NOV_ModAttribDBLK( BOOLEAN get_set, DBLK_PTR dblk, UINT32 *attrib) ;
+
+INT16 NOV_GetFileVerFDB( DBLK_PTR dblk, UINT32 *ver ) ;
+
+INT16 NOV_GetObjTypeDBLK( DBLK_PTR dblk, OBJECT_TYPE *type ) ;
+
+INT16 NOV_GetOS_InfoDBLK( DBLK_PTR dblk, CHAR_PTR os_info, INT16 *size ) ;
+
+INT16 NOV_GetActualSizeDBLK( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+
+INT16 NOV_SizeofFname( FSYS_HAND fsh, DBLK_PTR fdb ) ;
+
+INT16 NOV_SizeofOSFname( FSYS_HAND fsh, DBLK_PTR fdb ) ;
+
+INT16 NOV_SizeofOSPath( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+INT16 NOV_SizeofPath( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+INT16 NOV_SizeofOSInfo( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+INT16 NOV_CreateFDB( FSYS_HAND fsh, GEN_FDB_DATA_PTR data ) ;
+
+INT16 NOV_CreateDDB( FSYS_HAND fsh, GEN_DDB_DATA_PTR data ) ;
+
+VOID NOV_SetOwnerId( FSYS_HAND fsh, DBLK_PTR dblk, UINT32 id ) ;
+
+INT16 NOV_ChangeIntoDDB( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+UINT16 NOV_SpecExcludeObj( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR ddb, /* I - Descriptor block of ddb */
+ DBLK_PTR fdb ) ; /* I - Descriptor block of fdb */
+
+UINT16 NOV_SetDataSize( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR ddb, /* I - Descriptor block of ddb */
+ UINT32 size ) ; /* I - new size */
+
+VOID NOV_CheckBindClose( FSYS_HAND fsh, DBLK_PTR fdb ) ;
+
+INT16 NOV_SetTempHandle( FSYS_HAND fsh );
+
+BOOLEAN NOV_IsBlkComplete( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/nov386.h b/private/utils/ntbackup/inc/nov386.h
new file mode 100644
index 000000000..8eaf642f5
--- /dev/null
+++ b/private/utils/ntbackup/inc/nov386.h
@@ -0,0 +1,67 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: nov386.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Definitions/macros for NetWare 386.
+
+
+
+ $Log: G:/LOGFILES/NOV386.H_V $
+ *
+ * Rev 1.0 09 May 1991 13:32:26 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef nov386_h
+#define nov386_h
+
+
+/*
+ * These bits have been added in NetWare 386 and reside in the new additional
+ * 16-bits of attributes kept for '386 files and directories. (Stored in the
+ * "attributes_386" field of the NetWare 386 info for FDBs and DDBs.)
+ */
+#define NOV_IMM_PURGE 0x0001 /* Purge immediate */
+#define NOV_REN_INHIBIT 0x0002 /* Rename inhibit */
+#define NOV_DEL_INHIBIT 0x0004 /* Delete inhibit */
+#define NOV_CPY_INHIBIT 0x0008 /* Copy inhibit */
+
+
+/*
+ * Additional information kept by NetWare 386 for directories that
+ * we'll add to the DDB.
+ */
+typedef struct NOVELL_386_DIR {
+ BOOLEAN info_valid ; /* TRUE when info below is valid */
+ UINT32 maximum_space ; /* Max disk space allowed for dir */
+ UINT16 attributes_386 ; /* Most sig 16 bits of 32-bit attr */
+ UINT8 extend_attr ; /* Most sig byte of low 16 bits */
+ UINT8 inherited_rights ; /* Most sig byte of rights mask */
+} NOVELL_386_DIR ;
+
+
+/*
+ * Additional information kept by NetWare 386 for files that we'll keep
+ * in the FDB.
+ */
+typedef struct NOVELL_386_FILE {
+ BOOLEAN info_valid ; /* TRUE when info below is valid */
+ UINT16 creation_time ;
+ UINT32 archiver_id ;
+ UINT16 attributes_386 ; /* Most sig 16 bits of 32-bit attr */
+ UINT32 last_modifier_id ;
+ UINT32 trust_fork_size ; /* Trustee info */
+ UINT32 trust_fork_offset ;
+ UINT8 trust_fork_format ; /* See NOVCOM.H for trust formats */
+ UINT16 inherited_rights ; /* Rights mask--new for files */
+} NOVELL_386_FILE ;
+
+
+
+#endif
diff --git a/private/utils/ntbackup/inc/novcom.h b/private/utils/ntbackup/inc/novcom.h
new file mode 100644
index 000000000..a879a0998
--- /dev/null
+++ b/private/utils/ntbackup/inc/novcom.h
@@ -0,0 +1,315 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: novcom.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This header file contians prototypes for internal
+ common novell funcitons.
+
+
+ $Log: N:/LOGFILES/NOVCOM.H_V $
+ *
+ * Rev 1.11 15 Oct 1992 13:20:48 CARLS
+ * added active_stream_id to DIR_HAND for MTF 4.0
+ *
+ * Rev 1.10 25 Sep 1992 15:13:56 CARLS
+ * spelling error
+ *
+ * Rev 1.9 28 Aug 1992 16:27:06 BARRY
+ * Added prototypes for new functions.
+ *
+ * Rev 1.8 14 Aug 1992 09:52:18 BARRY
+ * Fixed error in prototype.
+ *
+ * Rev 1.7 08 Jul 1992 15:20:50 BARRY
+ * Fold branched fixes for UTF back to trunk.
+ *
+ * Rev 1.6 21 May 1992 15:31:18 BARRY
+ * Added max volumes/server info structs/protos.
+ *
+ * Rev 1.5 19 Dec 1991 15:13:24 STEVEN
+ * move common functions to bables
+ *
+ * Rev 1.4 17 Dec 1991 10:19:42 BARRY
+ * Added defines and structures to support the UTF tape format translator.
+ *
+ * Rev 1.3 20 Aug 1991 09:31:12 STEVEN
+ * minor code review changes
+ *
+ * Rev 1.2 23 May 1991 18:20:20 BARRY
+ * Lose access_date & create_date from the private area.
+ *
+ * Rev 1.1 23 May 1991 16:46:28 BARRY
+ * Changes for FindFirst/Next to scan for dirs only
+ *
+ * Rev 1.0 09 May 1991 13:32:24 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef novcom_h
+#define novcom_h
+
+#define SUPERVISOR 1
+#define TTS_SUPPORTED 2
+#define SUPPORT_386 4
+
+#define NORMAL_FILE 0
+#define NET286_BIND 1
+#define NET386_BIND 2
+
+
+/* Attribute bit definitions */
+#define ATTR_READ_ONLY 0x01 /* DOS attributes */
+#define ATTR_HIDDEN 0x02
+#define ATTR_SYSTEM 0x04
+#define ATTR_EXEC_ONLY 0x08
+#define ATTR_SUB_DIR 0x10
+#define ATTR_ARCHIVE 0x20
+#define ATTR_SHAREABLE 0x80
+
+#define ATTR_TRANSACTION 0x10 /* NetWare extended attributes */
+#define ATTR_INDEXED 0x20
+#define ATTR_READ_AUDIT 0x40
+#define ATTR_WRITE_AUDIT 0x80
+
+
+/* NetWare 386 Trustee rights */
+#define TR_386_READ 0x01
+#define TR_386_WRITE 0x02
+#define TR_386_CREATE 0x08
+#define TR_386_ERASE 0x10
+#define TR_386_ACCESS 0x20
+#define TR_386_FILE 0x40
+#define TR_386_MODIFY 0x80
+#define TR_386_NORMAL 0xff
+
+#define TR_386_SUPERVISOR 0x01
+
+
+/* NONAFP-specific reserved info */
+
+typedef struct {
+ UINT16 find_type ; /* type of FindFirst/Next scan */
+} NOV_RES_INFO ;
+
+
+/* AFP-specific reserved info */
+
+typedef struct {
+ UINT8 dir_hand ; /* AFP temporary directory handle */
+ UINT32 entry_id ; /* Entry id of current file/dir */
+ UINT16 path_size ; /* Size of long_path below */
+ CHAR_PTR long_path ; /* Current long path */
+ UINT16 find_type ; /* type of FindFirst/Next scan */
+} AFP_RES_INFO ;
+
+
+/*
+ * Reserved information (referenced by the reserved field in the file
+ * system handle) for AFP and non-AFP file systems.
+ */
+
+typedef struct {
+ UINT16 bindery_flags ; /* Status of bindery */
+ UINT8 temp_dir_handle ; /* Handle for NetWare 386 */
+ UINT32 user_object_id ; /* Bindery object id of user */
+ union {
+ NOV_RES_INFO nov ; /* NONAFP reserved info */
+ AFP_RES_INFO afp ; /* AFP reserved info */
+ } info ;
+} NOVELL_RES, *NOVELL_RES_PTR ;
+
+
+typedef struct DIR_HAND_STRUCT {
+ INT16 index ;
+ UINT32 trust_fork_offset ;
+ UINT32 trust_fork_size ;
+ UINT8 trust_fork_format ;
+ CHAR path[ 256 ] ;
+ UINT32 active_stream_id ;
+} DIR_HAND_STRUCT, *DIR_HAND;
+
+typedef struct TRUSTEE286 {
+ UINT32 object_id ;
+ UINT8 rights ;
+} TRUSTEE286, *TRUSTEE286_PTR ;
+
+typedef struct TRUST386 {
+ UINT32 object_id ;
+ UINT16 rights ;
+} TRUST386, *TRUST386_PTR ;
+
+typedef struct TRUST286_UTF {
+ UINT32 object_id ;
+ UINT8 rights ;
+ UINT8 reserved ; /* Unused on UTF 286 tapes */
+} TRUST286_UTF, *TRUST286_UTF_PTR ;
+
+
+#define TRUSTEES286_PER_CALL 5 /* Number of trustees returned per call */
+#define TRUSTEE286_SIZE 5 /* Size of a NetWare 286 trustee entry */
+#define TRUSTEE286_BLOCK_SIZE 25 /* Size needed for 1 call for trustees */
+
+#define TRUST386_PER_CALL 20 /* Number of trustees returned per call */
+#define TRUST386_SIZE 6 /* Size of a NetWare 386 trustee entry */
+#define TRUST386_BLOCK_SIZE 120 /* Size needed for 1 call for trustees */
+
+#define TRUST286_UTF_SIZE 6 /* Size of Netware 286 trustee from UTF */
+#define TRUST286_UTF_BLOCK_SIZE 30 /* Size of block of UTF 286 trustees */
+
+#define TRUST286_BLOCK 500 /* size of 100 TRUSTEEs in bytes */
+#define TRUST_BLOCK_386 600 /* size of 100 TRUST386s in bytes */
+#define TRUST_BLOCK_286_UTF 600 /* size of 100 TRUST386s in bytes */
+
+
+typedef struct {
+ UINT16 length;
+ CHAR serverName[48];
+ UINT8 verMajor;
+ UINT8 verMinor;
+ UINT16 maxConnect;
+ UINT16 usedConnect;
+ UINT16 maxVolumes;
+ UINT8 osRevision;
+ UINT8 sftLevel;
+ UINT8 ttsLevel;
+ UINT16 peakConnectUsed;
+ UINT8 accountVer;
+ UINT8 vapVer;
+ UINT8 queueVer;
+ UINT8 printVer;
+ UINT8 consoleVer;
+ UINT8 securityLevel;
+ UINT8 bridgeVer;
+ UINT8 reserved[60];
+} NOVELL_SERVER_INFO, *NOVELL_SERVER_INFO_PTR;
+
+
+UINT8 GetDirHand( CHAR drive ) ;
+
+UINT8 GetServSupp( UINT16 os_version ) ;
+
+VOID GetNovNetPath( UINT8 drive_hand, CHAR_PTR vol, CHAR_PTR path ) ;
+
+VOID GetNovServ( CHAR drive, CHAR_PTR serv_name, UINT8 *serv_num ) ;
+
+VOID SetPreferredServer( UINT8 server_num ) ;
+
+UINT8 GetPreferredServer( VOID ) ;
+
+INT16 GetFileServerInformation( NOVELL_SERVER_INFO_PTR info );
+
+INT16 NOV_GetMaxVolumes( VOID );
+
+VOID GetVolNum( CHAR_PTR vol_name, UINT8 *vol_num ) ;
+
+VOID CloseBind( UINT8 server_num ) ;
+
+VOID OpenBind( UINT8 server_num ) ;
+
+VOID DeAllocateDirHand( UINT8 dir_hand ) ;
+
+INT16 ScanTrustee( UINT8 drive_handle, CHAR_PTR path, INT16 index,
+ TRUSTEE286 *trust_list ) ;
+
+INT16 ScanTrustee386( UINT8 drive_handle, CHAR_PTR path, INT16 index,
+ TRUST386 *trust_list, INT16 *count ) ;
+
+INT16 AddTrustee( UINT16 hand, CHAR_PTR path, TRUSTEE286_PTR trust_data ) ;
+
+INT16 AddTrustee386( UINT16 hand, CHAR_PTR path, TRUST386_PTR trust_data ) ;
+
+INT16 CountTrustee( UINT8 drive_handle, CHAR_PTR path, INT16 *count ) ;
+
+INT16 CountTrustee386( UINT8 drive_handle, CHAR_PTR path, INT16 *count ) ;
+
+INT16 ReadTrustees( FILE_HAND hand, UINT8 dir_handle, CHAR *path,
+ INT16 *index, CHAR *buf, UINT16 *size,
+ UINT16 *blk_size ) ;
+
+INT16 ReadTrustees386( FILE_HAND hand, UINT8 dir_handle,
+ CHAR *path, INT16 *index, CHAR *buf,
+ UINT16 *size, UINT16 *blk_size ) ;
+
+INT16 WriteTrustees( FILE_HAND hand, UINT8 drive_hand, CHAR_PTR path,
+ UINT8 format, CHAR_PTR buf, UINT16 *size,
+ UINT16 *blk_size ) ;
+
+INT16 CompareTrust( FILE_HAND hand, UINT8 dir_handle, CHAR_PTR data, INT16 size, INT16 fmt) ;
+
+INT16 CompareTrust386( FILE_HAND hand, UINT8 dir_hand, CHAR_PTR path,
+ CHAR_PTR data, INT16 size) ;
+
+INT16 NOV_GetNumEntries( UINT8 nov_dir_hand ) ;
+
+VOID NOV_MakePath( CHAR_PTR dest, INT16 dest_size, CHAR_PTR source, INT16 leng, UINT8 os_id, UINT8 os_ver ) ;
+
+BOOLEAN NOV_ProcessDDB( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+INT16 NOV_DetBindAction( GENERIC_DLE_PTR dle, CHAR_PTR name ) ;
+
+INT16 CreateDirNOV( CHAR_PTR path, UINT8 drive_hand ) ;
+
+INT16 SRV_AttachToDLE( FSYS_HAND fsh, /* I - File system handle */
+ GENERIC_DLE_PTR dle, /*I/O- drive to attach to. list element expanded */
+ CHAR_PTR u_name, /* I - user name */
+ CHAR_PTR pswd); /* I - passowrd */
+
+INT16 SRV_DetachDLE( FSYS_HAND fsh ) ;
+
+INT16 SRV_LoginToServer( CHAR_PTR s_name, CHAR_PTR u_name, CHAR_PTR password,
+ UINT8_PTR server_num ) ;
+
+INT16 SRV_LogoutFromServer( GENERIC_DLE_PTR dle_ptr ) ;
+
+INT16 SRV_DetachFromServer( UINT8 server_num ) ;
+
+INT16 GetConnectionInfo( UINT8 server_num ) ;
+
+UINT32 GetUserObjectID( VOID ) ;
+
+UINT8 GetTemporaryDirectoryHandle( CHAR_PTR volume, UINT8 current_drive,
+ CHAR *mapped_drive ) ;
+
+UINT16 SetDirHandle( UINT8 dst_hand, UINT8 src_hand, CHAR_PTR src_path ) ;
+
+INT16 NOV_EnumSpecFiles( GENERIC_DLE_PTR del, UINT16 *index, CHAR_PTR *path, INT16 *psize, CHAR_PTR *fname ) ;
+
+UINT16 NOV_CalcForkDelta( UINT32 current_pos, INT16 num_args, UINT32 offsets, ... ) ;
+
+INT16 NOV_DeviceDispName(
+GENERIC_DLE_PTR dle,
+CHAR_PTR dev_name,
+INT16 size,
+INT16 type ) ;
+
+VOID NOV_GetVolName( GENERIC_DLE_PTR dle,CHAR_PTR buffer ) ;
+
+INT16 NOV_SizeofVolName( GENERIC_DLE_PTR dle ) ;
+
+INT16 NOV_MakeParsablePath(
+CHAR_PTR buf,
+INT16 bsize,
+GENERIC_DLE_PTR dle,
+CHAR_PTR path,
+INT16 psize,
+CHAR_PTR fname ) ;
+
+BOOLEAN NOV_NetworkError( VOID );
+
+BOOLEAN NOV_IsNetworkDrive( CHAR drive );
+INT16 NOV_IdentifyDrive( CHAR drive, BE_CFG_PTR cfg, UINT16 *version );
+
+INT16 CheckNovell( CHAR drive_num, UINT16 *version );
+
+INT16 NOV_DeviceDispName( GENERIC_DLE_PTR dle,
+ CHAR_PTR dev_name,
+ INT16 size,
+ INT16 type );
+
+#endif
diff --git a/private/utils/ntbackup/inc/novdblk.h b/private/utils/ntbackup/inc/novdblk.h
new file mode 100644
index 000000000..be294937d
--- /dev/null
+++ b/private/utils/ntbackup/inc/novdblk.h
@@ -0,0 +1,150 @@
+/** :IH1: Copyright (C) Maynard Electronics, Inc 1984-89
+
+:Name: novcblk.h
+
+:Description: This file contains the definition of the Novell
+ file and directory control blocks.
+
+:Units: Novell < 2.15 File System
+
+
+ $Log: N:/LOGFILES/NOVDBLK.H_V $
+ *
+ * Rev 1.2 11 Dec 1992 11:00:38 CARLS
+ * removed tape_attribs for MTF 4.0
+ *
+ * Rev 1.1 28 Aug 1992 16:27:32 BARRY
+ * No longer need nov386.h.
+ *
+ * Rev 1.0 09 May 1991 13:32:22 HUNTER
+ * Initial revision.
+
+
+
+**/
+
+#ifndef novdblk_h
+#define novdblk_h
+
+/* miximum Novell string lengths */
+#define NOV_MAX_FSIZE 16
+#define NOV_MAX_DSIZE (255 - NOV_MAX_FSIZE)
+
+
+#define NOV_READ_ONLY 1
+#define NOV_HIDDEN 2
+#define NOV_SYSTEM 4
+#define NOV_EXECUTE 8
+#define NOV_SUBDIR 0x10
+#define NOV_ARCHIVE 0x20
+#define NOV_SHARE 0x80
+#define NOV_TRANS 0x10
+#define NOV_INDEX 0x20
+
+#define CONVERT_DOS_ATTRIB( atrib ) ((UINT32)(attrib) << 16 )
+
+/* defines used for FSYS_HAND reserved space */
+#define BIND_CLOSED 0x80
+#define BIND_FILE1 0x01 /* NET$BIND or NET$OBJ */
+#define BIND_FILE2 0x02 /* NET$BVAL or NET$VAL */
+#define BIND_FILE3 0x04 /* NET$PROP */
+#define BIND_ALL_286 0x03
+#define BIND_ALL_386 0x07
+
+
+/* defines used for find first/next */
+typedef enum {
+ NORM_DOS,
+ DIR_14_FOUND,
+ NOV_14_DIR
+} SCAN_STATE;
+
+
+typedef struct NOVELL_COMMON {
+/*
+ standard DOS DTA
+*/
+ UINT8 reserved[ 21 ] ; /* reserved for dos */
+ UINT8 attrib ; /* file attribute */
+ UINT16 time ; /* file update time */
+ UINT16 date ; /* file date */
+ UINT32 size ; /* file size */
+ CHAR name[NOV_MAX_FSIZE] ; /* file name */
+
+ SCAN_STATE scan ; /* flag used to determin if novell */
+
+ BOOLEAN min_dblk ; /* TRUE if DBLK not completly initialized */
+
+/*
+ additional space for novell calls required to support the above flag
+*/
+ UINT16 seq_num ; /* info for novell's scan dir info */
+ CHAR filespec[NOV_MAX_FSIZE] ; /* search path */
+
+} NOVELL_COMMON ;
+
+typedef struct NOV_FDB {
+ UINT8 blk_type ; /* block id = FDB_ID */
+ COM_DBLK fs_reserved ;
+
+ NOVELL_COMMON com ;
+
+ UINT16 handle ; /* DOS file handle of created file */
+
+/*
+ OS specific file information
+*/
+ UINT8 extend_attr ;
+ UINT16 creat_date ;
+ UINT16 backup_date ;
+ UINT16 backup_time ;
+
+ UINT32 owner ;
+ UINT16 access_date ;
+
+ UINT16 os_name ;
+
+ UINT32 data_fork_offset ;
+ NOVELL_386_FILE info_386;
+
+} NOV_FDB, *NOV_FDB_PTR ;
+
+
+
+typedef struct NOV_DDB {
+ UINT8 blk_type ; /* block id = DDB_ID */
+ COM_DBLK fs_reserved ;
+
+ NOVELL_COMMON com ;
+
+/*
+ OS specific file information
+*/
+ CHAR path[ NOV_MAX_DSIZE ] ; /* \Fred\sue */
+ UINT8 max_rights ;
+
+ UINT16 os_path;
+ INT16 os_path_leng ;
+ UINT32 owner ;
+ UINT32 trust_fork_offset ;
+ UINT32 trust_fork_size ;
+ UINT8 trust_fork_format ;
+
+ NOVELL_386_DIR info_386;
+
+} NOV_DDB, *NOV_DDB_PTR;
+
+/*
+ Minimal DDB
+*/
+typedef struct NOV_MIN_DDB {
+ Q_ELEM q ;
+ UINT8 reserved[ 21 ] ; /* reserved for dos */
+ UINT16 seq_num ; /* info for novell's scan dir info */
+ SCAN_STATE scan ; /* flag used to determin if novell */
+ CHAR filespec[ NOV_MAX_FSIZE ] ; /* search path */
+ UINT16 psize ; /* size of path string */
+ CHAR_PTR path; /* build from "name" and current dir */
+} NOV_MIN_DDB, *NOV_MIN_DDB_PTR;
+
+#endif
diff --git a/private/utils/ntbackup/inc/novinit.h b/private/utils/ntbackup/inc/novinit.h
new file mode 100644
index 000000000..213566c06
--- /dev/null
+++ b/private/utils/ntbackup/inc/novinit.h
@@ -0,0 +1,60 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: novinit.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Include file for Novell Server/Volume DLE init
+
+ Location: BE_PRIVATE
+
+
+ $Log: M:/LOGFILES/NOVINIT.H_V $
+ *
+ * Rev 1.3 08 Jul 1992 15:21:50 BARRY
+ * Removed temp mapped drive #defines.
+ *
+ * Rev 1.2 20 Dec 1991 09:12:40 STEVEN
+ * move common functions into tables
+ *
+ * Rev 1.1 31 Jul 1991 18:49:46 DON
+ * added new prototype for NLMSRV_AddNovellServerDLEs
+ *
+ * Rev 1.0 09 May 1991 13:31:14 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef novinit_h
+#define novinit_h
+
+/*
+ Defines for server/volume support
+*/
+#define BINDERY_GET_SERVER_NAMES 0x04
+
+#define BINDERY_READ_SUCCESS 0x00
+#define BINDERY_NO_MORE_OBJECTS 0xFC
+#define VOLUME_DOES_NOT_EXIST 0x98
+
+INT16 AddNovellServerDLEs(
+DLE_HAND hand,
+BE_CFG_PTR cfg,
+UINT32 fsys_mask ) ;
+
+INT16 NLMSRV_AddNovellServerDLEs( DLE_HEAD_PTR hand ) ;
+
+INT16 GetConnectionInfo( UINT8 server_num ) ;
+
+VOID DeallocateLoginMapping( UINT8 server_num ) ;
+
+BOOLEAN IsMaynstreamDirOnServer( UINT8 server_num ) ;
+
+INT16 AsmLoginToFileServer ( CHAR_PTR u_name, UINT16 type , CHAR_PTR pswd ) ;
+
+extern UINT8 lw_preferred_server ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/nrl.h b/private/utils/ntbackup/inc/nrl.h
new file mode 100644
index 000000000..d3cf4a2fa
--- /dev/null
+++ b/private/utils/ntbackup/inc/nrl.h
@@ -0,0 +1,588 @@
+/**
+ :IH1: Copyright (C) Maynard Electronics, Inc. 1984-89
+
+ :Name: nrl.h
+
+ :Description: Public header file for nrl module
+
+$Header: O:/LOGFILES/NRL.H_V 1.3 24 Feb 1992 09:44:22 DOUG $
+
+$Log: O:/LOGFILES/NRL.H_V $
+ *
+ * Rev 1.3 24 Feb 1992 09:44:22 DOUG
+ * Added standard NRL resource type for RMFS servers NRL_RMFS_SERVER 0x20
+ *
+ *
+ * Rev 1.2 23 Feb 1992 16:57:56 DOUG
+ * The typedefs of functions with no parameters needed an explicit
+ * VOID added to their definitions. IE instead of:
+ * typedef UINT16 ( EXPORT_DLL *PF_function ) ( )
+ * the correct thing was:
+ * typedef UINT16 ( EXPORT_DLL *PF_function ) ( VOID )
+ *
+ *
+ *
+ *
+ * Rev 1.1 21 Feb 1992 16:26:34 DOUG
+ * This version is the initial version which is used for the SPX versions
+ * of the NRL.
+ *
+
+**/
+
+/*****************************************************************************
+** **
+** Note: This module contains the prototypes and macros for applications to **
+** use the NRL entry points through the TSR. For documentation on how to **
+** add NRL entry points to this list, please see the header comments on **
+** module NRLSTUBS.ASM, which handles the actual entry conditions. **
+** **
+*****************************************************************************/
+
+#ifndef NRL
+#define NRL
+
+#if defined( OS_WIN )
+#define EXPORT_DLL FAR PASCAL _loadds
+#elif defined( OS_OS2 )
+#define EXPORT_DLL far _export _loadds
+#else
+#define EXPORT_DLL far
+#endif
+
+#define NRL_MAX_RSRC_INFO 20
+#define NRL_MAX_MACHINE_NAME 21
+#define NRL_MAX_RESOURCE_NAME 21
+#define NRL_MAX_SIGNATURE 10
+#define NRL_ALLOC_DATA_SIZE 512
+#define NRL_SIGNATURE_VALUE "NRL TABLE\0"
+
+typedef VOID *(NRL_PF_ERROR)(VOID) ;
+
+/* A structure of the following type must be completely initialized and */
+/* passed to the NRLInitialize. */
+
+typedef struct NRL_DEFINITION {
+ BOOLEAN tsr; /* 1 if the application will terminate and stay resident */
+ UINT8 dos_vector; /* dos interrupt vector used for function table address */
+ VOID far *network_table; /* defined in nets.h */
+ UINT16 socket; /* dedicated socket number */
+ BOOLEAN check_summing;
+ UINT16 max_local_resources; /* maximum value of resources added minus resources removed */
+ UINT16 max_remote_resources; /* cumulative sum of all remote resource buffers added */
+ UINT8 max_concurrent_sessions; /* maximum value of sessions allocated minus sessions deallocated */
+ UINT16 max_packet_retries; /* Number of times to have the nvl retry sending a packet and wait for an ack */
+ VOID far * error_func; /* function to call when a NRL critical error occurs such as duplicat resource names */
+ BOOLEAN display_msgs ; /* Display incoming text messages? */
+ UINT16 broadcast_interval ; /* How many seconds between beacons */
+} NRL_DEFINITION;
+
+/* Macros to extract the configuration values from the pointer returned by */
+/* M_NRLConfigPointer(). For example, */
+/* cfg = M_NRLConfigPointer() */
+/* local = NRLMaxLocalRsrcs( cfg ) */
+
+#define NRLDosVector(x) ( (x)->dos_vector )
+#define NRLNetworkTable(x) ( (x)->network_table )
+#define NRLSocket(x) ( (x)->socket )
+#define NRLChecksumming(x) ( (x)->check_summing )
+#define NRLMaxLocalRsrcs(x) ( (x)->max_local_resources )
+#define NRLMaxRemoveRsrcs(x) ( (x)->max_remote_resources )
+#define NRLMaxConcurrentSess(x) ( (x)->max_concurrent_sessions )
+#define NRLMaxPacketRetries(x) ( (x)->max_packet_retries )
+
+#ifdef OS_DOS
+typedef struct NRL_RESOURCE far *NRL_RESOURCE_PTR;
+typedef NRL_RESOURCE_PTR far *NRL_RESOURCE_PTR_PTR;
+typedef struct NRL_SESSION far *NRL_SESSION_PTR;
+typedef struct NRL_RESOURCE far *NRL_REMOTE_RESOURCE_ARRAY;
+typedef struct NRL_RESOURCE far *NRL_LOCAL_RESOURCE_PTR;
+#else
+typedef struct RES_Q_ELEM NRL_RESOURCE;
+typedef struct RES_Q_ELEM far * NRL_RESOURCE_PTR;
+typedef struct SES_Q_ELEM far * NRL_SESSION_PTR;
+typedef NRL_RESOURCE NRL_LOCAL_RESOURCE;
+typedef NRL_RESOURCE_PTR NRL_LOCAL_RESOURCE_PTR;
+typedef NRL_RESOURCE far * NRL_REMOTE_RESOURCE_ARRAY;
+#endif
+
+typedef NRL_DEFINITION far *NRL_DEFINITION_PTR ;
+
+
+/***********************************************/
+/* TYPEDEFS OF THE NRL COMPLETION ROUTINES */
+/***********************************************/
+
+typedef VOID (far * NRL_PF_NOTIFY_DEALLOC)(
+ NRL_SESSION_PTR dying_session_ptr,
+ UINT16 reason );
+
+
+typedef UINT16 (far * NRL_PF_NOTIFY_ALLOC)(
+ NRL_RESOURCE_PTR rsrc_ptr,
+ NRL_SESSION_PTR new_session_ptr,
+ UINT8 far * alloc_data_ptr,
+ UINT8 far * far *alloc_complete_data_ptr_ptr,
+ NRL_PF_NOTIFY_DEALLOC far *dealloc_func_ptr_ptr );
+
+typedef VOID (far * NRL_PF_ALLOC_COMPLETE)(
+ NRL_RESOURCE_PTR resource_ptr,
+ UINT8 far * alloc_complete_data_ptr,
+ NRL_SESSION_PTR new_session_ptr,
+ UINT16 reason,
+ NRL_PF_NOTIFY_DEALLOC far *dealloc_func_ptr_ptr );
+
+typedef VOID (far * NRL_PF_DEALLOC_COMPLETE)(
+ NRL_SESSION_PTR dying_session_ptr,
+ UINT16 completion_code );
+
+
+typedef VOID (far *NRL_PF_SND_COMPLETE)( NRL_SESSION_PTR s_ptr, UINT16 reason,
+ UINT8 far *data_ptr, UINT16 bytes_not_sent);
+
+
+typedef VOID (far *NRL_PF_RCV_COMPLETE)( NRL_SESSION_PTR s_ptr, UINT16 reason,
+ UINT8 far *buffer_ptr, UINT16 bytes_rcvd);
+
+typedef VOID (far *NRL_PF_RECEIVE_BROADCAST)( UINT16 message_type,
+ VOID far * data_ptr,
+ UINT16 data_size );
+
+
+/***************************************************/
+/* PROTOTYPES OF THE NRL ENTRY POINT FUNCTIONS */
+/***************************************************/
+
+UINT16 EXPORT_DLL NRLInitialize( NRL_DEFINITION *nrl_def_ptr );
+
+UINT16 EXPORT_DLL NRLResourceSize( VOID );
+
+UINT16 EXPORT_DLL NRLSessionSize( VOID );
+
+UINT16 EXPORT_DLL NRLAddRemoteResourceBuffers( UINT16 numbuffers,
+ NRL_REMOTE_RESOURCE_ARRAY resource_buffers,
+ UINT16 buf_filter );
+
+UINT16 EXPORT_DLL NRLRemoveRemoteResourceBuffers( UINT16 numbuffers,
+ NRL_REMOTE_RESOURCE_ARRAY resource_buffers );
+
+UINT16 EXPORT_DLL NRLUnUsedResourceBuffers( VOID );
+UINT16 EXPORT_DLL NRLAvailResourceBufferSlots( VOID );
+
+UINT16 EXPORT_DLL NRLRemove( VOID );
+
+UINT16 EXPORT_DLL NRLAddResource( NRL_LOCAL_RESOURCE_PTR resource_ptr,
+ CHAR_FAR_PTR machine_name,
+ CHAR_FAR_PTR resource_name,
+ UINT16 resource_type,
+ NRL_PF_NOTIFY_ALLOC RcvdAllocSessionRoutine );
+
+UINT16 EXPORT_DLL NRLRemoveResource( NRL_LOCAL_RESOURCE_PTR resource_ptr );
+
+UINT16 EXPORT_DLL NRLRequestRemoteRsrcNames( VOID );
+
+NRL_RESOURCE_PTR EXPORT_DLL NRLScanResourceList( UINT32 far * sequence_ptr );
+
+BOOLEAN EXPORT_DLL NRLRsrcLocal( NRL_RESOURCE_PTR rsrc_ptr );
+
+CHAR_FAR_PTR EXPORT_DLL NRLRsrcMachineName( NRL_RESOURCE_PTR rsrc_ptr );
+
+CHAR_FAR_PTR EXPORT_DLL NRLRsrcName( NRL_RESOURCE_PTR rsrc_ptr );
+
+UINT16 EXPORT_DLL NRLRsrcType( NRL_RESOURCE_PTR rsrc_ptr );
+
+VOID EXPORT_DLL NRLSetSessionApplicationPtr( NRL_SESSION_PTR session_ptr,
+ VOID far * new_application_ptr );
+
+VOID_FAR_PTR EXPORT_DLL NRLGetSessionApplicationPtr( NRL_SESSION_PTR session_ptr );
+
+VOID EXPORT_DLL NRLSetResourceApplicationPtr( NRL_RESOURCE_PTR resource_ptr,
+ VOID far * new_application_ptr );
+
+VOID_FAR_PTR EXPORT_DLL NRLGetResourceApplicationPtr( NRL_RESOURCE_PTR resource_ptr );
+
+UINT16 EXPORT_DLL NRLAllocSession( NRL_RESOURCE_PTR resource_ptr,
+ UINT8_FAR_PTR alloc_data_ptr,
+ NRL_PF_ALLOC_COMPLETE AllocSessionCompleteRoutine,
+ BOOLEAN sequenced
+ );
+
+UINT16 EXPORT_DLL NRLDeAllocSession( NRL_SESSION_PTR session_ptr,
+ UINT16 reason,
+ NRL_PF_DEALLOC_COMPLETE DeAllocComplete_ptr );
+
+UINT16 EXPORT_DLL NRLSendMessage( NRL_SESSION_PTR session_ptr,
+ BOOLEAN error_falg,
+ UINT8_FAR_PTR data_ptr,
+ UINT16 data_size,
+ NRL_PF_SND_COMPLETE complete_ptr );
+
+UINT16 EXPORT_DLL NRLReceiveMessage( NRL_SESSION_PTR session_ptr,
+ UINT8_FAR_PTR data_buf_ptr,
+ UINT16 buffer_size,
+ UINT32 timeout_length,
+ NRL_PF_RCV_COMPLETE complete_ptr );
+
+INT16 EXPORT_DLL NRLSendBroadcastMessage( UINT16 message_type,
+ VOID_FAR_PTR data_ptr,
+ UINT16 data_size,
+ BOOLEAN_FAR_PTR sending_msg);
+
+VOID EXPORT_DLL NRLReceiveBroadcastMessages( struct Q_ELEM far * control,
+ NRL_PF_RECEIVE_BROADCAST notify_broadcast_rcvd,
+ UINT16 message_types );
+
+VOID EXPORT_DLL NRLCancelReceiveBroadcast( struct Q_ELEM far * control );
+
+INT16 EXPORT_DLL NRLSendTextMessage( CHAR_FAR_PTR msg,
+ NRL_RESOURCE_PTR resource,
+ BOOLEAN_FAR_PTR sending_msg ) ;
+
+INT16 EXPORT_DLL NRLBroadcastTextMessage( CHAR_FAR_PTR msg,
+ UINT16 resource_type,
+ BOOLEAN_FAR_PTR sending_msg ) ;
+
+// VOID EXPORT_DLL NRLSetErrorHandler( NRL_PF_ERROR errfun ) ;
+
+NRL_DEFINITION_PTR EXPORT_DLL NRLConfigPointer( VOID ) ;
+
+VOID EXPORT_DLL NRLSetExternalInfo( VOID_FAR_PTR info ) ;
+
+VOID_FAR_PTR EXPORT_DLL NRLGetExternalInfo( VOID ) ;
+
+UINT16 EXPORT_DLL NRLAddRemoteResource(
+ CHAR_FAR_PTR resource_name,
+ UINT16 resource_type ) ;
+
+VOID EXPORT_DLL NRLSetDisplayMsgFlag( BOOLEAN ) ;
+
+BOOLEAN EXPORT_DLL NRLGetDisplayMsgFlag( VOID ) ;
+
+VOID EXPORT_DLL NRLLockResource( NRL_RESOURCE_PTR rsrc_ptr );
+
+VOID EXPORT_DLL NRLUnlockResource( NRL_RESOURCE_PTR rsrc_ptr );
+
+/**************************************************/
+/* TYPEDEFS FOR EACH NRL ENTRY POINT FUNCTION */
+/**************************************************/
+
+typedef CHAR NRL_SIGNATURE[ NRL_MAX_SIGNATURE ] ;
+
+typedef UINT16 ( EXPORT_DLL *PF_NRLInitialize )
+( NRL_DEFINITION *nrl_def_ptr ) ;
+
+typedef UINT16 ( EXPORT_DLL *PF_NRLAddRemoteResourceBuffers )
+( UINT16 numbuffers,
+ NRL_REMOTE_RESOURCE_ARRAY resource_buffers,
+ UINT16 buf_filter ) ;
+
+typedef UINT16 ( EXPORT_DLL *PF_NRLRemoveRemResourceBuffers )
+( UINT16 numbuffers,
+ NRL_REMOTE_RESOURCE_ARRAY resource_buffers ) ;
+
+typedef UINT16 ( EXPORT_DLL *PF_NRLUnUsedResourceBuffers )
+( VOID ) ;
+
+typedef UINT16 ( EXPORT_DLL *PF_NRLAvailResourceBufferSlots )
+( VOID );
+
+typedef UINT16 ( EXPORT_DLL *PF_NRLRemove )
+( VOID );
+
+typedef UINT16 ( EXPORT_DLL *PF_NRLAddResource )
+( NRL_LOCAL_RESOURCE_PTR resource_ptr,
+ CHAR_FAR_PTR machine_name,
+ CHAR_FAR_PTR resource_name,
+ UINT16 resource_type,
+ NRL_PF_NOTIFY_ALLOC RcvdAllocSessionRoutine ) ;
+
+typedef UINT16 ( EXPORT_DLL *PF_NRLRemoveResource )
+( NRL_LOCAL_RESOURCE_PTR resource_ptr ) ;
+
+typedef UINT16 ( EXPORT_DLL *PF_NRLRequestRemoteRsrcNames )
+( VOID ) ;
+
+typedef NRL_RESOURCE_PTR ( EXPORT_DLL *PF_NRLScanResourceList )
+( UINT32 far * sequence_ptr ) ;
+
+typedef BOOLEAN ( EXPORT_DLL *PF_NRLRsrcLocal )
+( NRL_RESOURCE_PTR rsrc_ptr ) ;
+
+typedef CHAR far * ( EXPORT_DLL *PF_NRLRsrcMachineName )
+( NRL_RESOURCE_PTR rsrc_ptr ) ;
+
+typedef CHAR far * ( EXPORT_DLL *PF_NRLRsrcName )
+( NRL_RESOURCE_PTR rsrc_ptr ) ;
+
+typedef UINT16 ( EXPORT_DLL *PF_NRLRsrcType )
+( NRL_RESOURCE_PTR rsrc_ptr ) ;
+
+typedef VOID ( EXPORT_DLL *PF_NRLSetSessionApplicationPtr )
+( NRL_SESSION_PTR session_ptr,
+ VOID far * new_application_ptr ) ;
+
+typedef VOID far * ( EXPORT_DLL *PF_NRLGetSessionApplicationPtr )
+( NRL_SESSION_PTR session_ptr ) ;
+
+typedef VOID ( EXPORT_DLL *PF_NRLSetResourceApplicationPtr )
+( NRL_RESOURCE_PTR resource_ptr,
+ VOID far * new_application_ptr ) ;
+
+typedef VOID far * ( EXPORT_DLL *PF_NRLGetResourceApplicationPtr )
+( NRL_RESOURCE_PTR resource_ptr ) ;
+
+typedef UINT16 ( EXPORT_DLL *PF_NRLAllocSession )
+( NRL_RESOURCE_PTR resource_ptr,
+ UINT8_FAR_PTR alloc_data_ptr,
+ NRL_PF_ALLOC_COMPLETE AllocSessionCompleteRoutine,
+ BOOLEAN sequenced ) ;
+
+typedef UINT16 ( EXPORT_DLL *PF_NRLDeAllocSession )
+( NRL_SESSION_PTR session_ptr,
+ UINT16 reason,
+ NRL_PF_DEALLOC_COMPLETE DeAllocComplete_ptr ) ;
+
+typedef UINT16 ( EXPORT_DLL *PF_NRLSendMessage )
+( NRL_SESSION_PTR session_ptr,
+ BOOLEAN error_flag,
+ UINT8_FAR_PTR data_ptr,
+ UINT16 data_size,
+ NRL_PF_SND_COMPLETE complete_ptr ) ;
+
+typedef UINT16 ( EXPORT_DLL *PF_NRLReceiveMessage )
+( NRL_SESSION_PTR session_ptr,
+ UINT8_FAR_PTR data_buf_ptr,
+ UINT16 buffer_size,
+ UINT32 timeout_length,
+ NRL_PF_RCV_COMPLETE complete_ptr ) ;
+
+typedef UINT16 ( EXPORT_DLL *PF_NRLResourceSize )
+( VOID ) ;
+
+typedef UINT16 ( EXPORT_DLL *PF_NRLSessionSize )
+( VOID ) ;
+
+typedef UINT16 ( EXPORT_DLL *PF_NRLSendBroadcastMessage )
+( UINT16 message_type,
+ VOID_FAR_PTR data_ptr,
+ UINT16 data_size,
+ BOOLEAN_FAR_PTR sending_msg ) ;
+
+typedef VOID ( EXPORT_DLL *PF_NRLReceiveBroadcastMessages )
+( struct Q_ELEM far * control,
+ NRL_PF_RECEIVE_BROADCAST notify_broadcast_rcvd,
+ UINT16 message_types ) ;
+
+typedef UINT16 ( EXPORT_DLL *PF_NRLCancelReceiveBroadcast )
+( struct Q_ELEM far * control ) ;
+
+typedef VOID ( EXPORT_DLL *PF_NRLFreeInvalidResources )
+( VOID ) ;
+
+
+typedef INT16 ( EXPORT_DLL *PF_NRLSendTextMessage )
+( CHAR_FAR_PTR msg,
+ NRL_RESOURCE_PTR resource,
+ BOOLEAN_FAR_PTR sending_msg ) ;
+
+typedef INT16 ( EXPORT_DLL *PF_NRLBroadcastTextMessage )
+( CHAR_FAR_PTR msg,
+ UINT16 resource_type,
+ BOOLEAN_FAR_PTR sending_msg ) ;
+
+typedef VOID ( EXPORT_DLL *PF_NRLSetErrorHandler )
+( NRL_PF_ERROR errfun ) ;
+
+typedef NRL_DEFINITION_PTR ( EXPORT_DLL *PF_NRLConfigPointer )
+( VOID ) ;
+
+typedef VOID ( EXPORT_DLL *PF_NRLSetExternalInfo )
+( VOID_FAR_PTR info ) ;
+
+typedef VOID_FAR_PTR ( EXPORT_DLL *PF_NRLGetExternalInfo )
+( VOID ) ;
+
+typedef UINT16 ( EXPORT_DLL *PF_NRLAddRemoteResource )
+ ( CHAR_FAR_PTR resource_name,
+ UINT16 resource_type ) ;
+
+typedef VOID ( EXPORT_DLL *PF_NRLSetDisplayMsgFlag )
+ ( BOOLEAN flag ) ;
+
+typedef BOOLEAN ( EXPORT_DLL *PF_NRLGetDisplayMsgFlag )
+ ( VOID ) ;
+
+typedef VOID ( EXPORT_DLL *PF_NRLLockResource )
+ ( NRL_RESOURCE_PTR rsrc_ptr );
+
+typedef VOID ( EXPORT_DLL *PF_NRLUnlockResource )
+ ( NRL_RESOURCE_PTR rsrc_ptr );
+
+
+/*************************************************/
+/* FUNCTION TABLE OF ENTRY POINTS TO THE NRL */
+/*************************************************/
+
+typedef struct NRL_FUNCTION_TABLE_STRUCT {
+
+ NRL_SIGNATURE signature ;
+
+ PF_NRLInitialize T_NRLInitialize ;
+ PF_NRLAddRemoteResourceBuffers T_NRLAddRemoteResourceBuffers ;
+ PF_NRLRemoveRemResourceBuffers T_NRLRemoveRemResourceBuffers ;
+ PF_NRLUnUsedResourceBuffers T_NRLUnUsedResourceBuffers ;
+ PF_NRLRemove T_NRLRemove ;
+ PF_NRLAddResource T_NRLAddResource ;
+ PF_NRLRemoveResource T_NRLRemoveResource ;
+ PF_NRLRequestRemoteRsrcNames T_NRLRequestRemoteRsrcNames;
+ PF_NRLScanResourceList T_NRLScanResourceList ;
+ PF_NRLRsrcLocal T_NRLRsrcLocal ;
+ PF_NRLRsrcMachineName T_NRLRsrcMachineName ;
+ PF_NRLRsrcName T_NRLRsrcName ;
+ PF_NRLRsrcType T_NRLRsrcType ;
+ PF_NRLSetSessionApplicationPtr T_NRLSetSessionApplicationPtr ;
+ PF_NRLGetSessionApplicationPtr T_NRLGetSessionApplicationPtr ;
+ PF_NRLSetResourceApplicationPtr T_NRLSetResourceApplicationPtr ;
+ PF_NRLGetResourceApplicationPtr T_NRLGetResourceApplicationPtr ;
+ PF_NRLAllocSession T_NRLAllocSession ;
+ PF_NRLDeAllocSession T_NRLDeAllocSession ;
+ PF_NRLSendMessage T_NRLSendMessage ;
+ PF_NRLReceiveMessage T_NRLReceiveMessage ;
+ PF_NRLResourceSize T_NRLResourceSize ;
+ PF_NRLSessionSize T_NRLSessionSize ;
+ PF_NRLAvailResourceBufferSlots T_NRLAvailResourceBufferSlots;
+ PF_NRLSendBroadcastMessage T_NRLSendBroadcastMessage ;
+ PF_NRLReceiveBroadcastMessages T_NRLReceiveBroadcastMessages ;
+ PF_NRLCancelReceiveBroadcast T_NRLCancelReceiveBroadcast ;
+ PF_NRLFreeInvalidResources T_NRLFreeInvalidResources ;
+ PF_NRLSendTextMessage T_NRLSendTextMessage ;
+ PF_NRLBroadcastTextMessage T_NRLBroadcastTextMessage ;
+ PF_NRLSetErrorHandler T_NRLSetErrorHandler ;
+ PF_NRLConfigPointer T_NRLConfigPointer ;
+ PF_NRLSetExternalInfo T_NRLSetExternalInfo ;
+ PF_NRLGetExternalInfo T_NRLGetExternalInfo ;
+ PF_NRLAddRemoteResource T_NRLAddRemoteResource ;
+ PF_NRLSetDisplayMsgFlag T_NRLSetDisplayMsgFlag ;
+ PF_NRLGetDisplayMsgFlag T_NRLGetDisplayMsgFlag ;
+ PF_NRLLockResource T_NRLLockResource ;
+ PF_NRLUnlockResource T_NRLUnlockResource ;
+} NRL_FUNCTION_TABLE,
+far *NRL_FUNCTION_TABLE_PTR ;
+
+NRL_FUNCTION_TABLE_PTR NRLGetFunctionTablePtr( UINT8 dos_vector ) ;
+
+/**********************************************/
+/* The global NRL function table */
+/**********************************************/
+
+extern NRL_FUNCTION_TABLE_PTR gb_NRL_function_table_ptr ; /* set by NRLInitialize. reset by NRLRemove */
+
+
+/**********************************************/
+/* MACRO REFERENCES TO NRL FUNCTION TABLE */
+/**********************************************/
+
+#define M_NRLAddRemoteResourceBuffers ( gb_NRL_function_table_ptr -> T_NRLAddRemoteResourceBuffers )
+#define M_NRLRemoveRemResourceBuffers ( gb_NRL_function_table_ptr -> T_NRLRemoveRemResourceBuffers )
+#define M_NRLUnUsedResourceBuffers ( gb_NRL_function_table_ptr -> T_NRLUnUsedResourceBuffers )
+#ifdef OS_OS2
+#define M_NRLRemove NRLRemove
+#else
+#define M_NRLRemove ( gb_NRL_function_table_ptr -> T_NRLRemove )
+#endif
+#define M_NRLAddResource ( gb_NRL_function_table_ptr -> T_NRLAddResource )
+#define M_NRLRemoveResource ( gb_NRL_function_table_ptr -> T_NRLRemoveResource )
+#define M_NRLRequestRemoteRsrcNames ( gb_NRL_function_table_ptr -> T_NRLRequestRemoteRsrcNames )
+#define M_NRLScanResourceList ( gb_NRL_function_table_ptr -> T_NRLScanResourceList )
+#define M_NRLRsrcLocal ( gb_NRL_function_table_ptr -> T_NRLRsrcLocal )
+#define M_NRLRsrcMachineName ( gb_NRL_function_table_ptr -> T_NRLRsrcMachineName )
+#define M_NRLRsrcName ( gb_NRL_function_table_ptr -> T_NRLRsrcName )
+#define M_NRLRsrcType ( gb_NRL_function_table_ptr -> T_NRLRsrcType )
+#define M_NRLSetSessionApplicationPtr ( gb_NRL_function_table_ptr -> T_NRLSetSessionApplicationPtr )
+#define M_NRLGetSessionApplicationPtr ( gb_NRL_function_table_ptr -> T_NRLGetSessionApplicationPtr )
+#define M_NRLSetResourceApplicationPtr ( gb_NRL_function_table_ptr -> T_NRLSetResourceApplicationPtr )
+#define M_NRLGetResourceApplicationPtr ( gb_NRL_function_table_ptr -> T_NRLGetResourceApplicationPtr )
+#define M_NRLAllocSession ( gb_NRL_function_table_ptr -> T_NRLAllocSession )
+#define M_NRLDeAllocSession ( gb_NRL_function_table_ptr -> T_NRLDeAllocSession )
+#define M_NRLSendMessage ( gb_NRL_function_table_ptr -> T_NRLSendMessage )
+#define M_NRLReceiveMessage ( gb_NRL_function_table_ptr -> T_NRLReceiveMessage )
+#define M_NRLResourceSize ( gb_NRL_function_table_ptr -> T_NRLResourceSize )
+#define M_NRLSessionSize ( gb_NRL_function_table_ptr -> T_NRLSessionSize )
+#define M_NRLAvailResourceBufferSlots ( gb_NRL_function_table_ptr -> T_NRLAvailResourceBufferSlots )
+#define M_NRLSendBroadcastMessage ( gb_NRL_function_table_ptr -> T_NRLSendBroadcastMessage )
+#define M_NRLReceiveBroadcastMessages ( gb_NRL_function_table_ptr -> T_NRLReceiveBroadcastMessages )
+#define M_NRLCancelReceiveBroadcast ( gb_NRL_function_table_ptr -> T_NRLCancelReceiveBroadcast )
+#define M_NRLFreeInvalidResources ( gb_NRL_function_table_ptr -> T_NRLFreeInvalidResources )
+#define M_NRLSendTextMessage ( gb_NRL_function_table_ptr -> T_NRLSendTextMessage )
+#define M_NRLBroadcastTextMessage ( gb_NRL_function_table_ptr -> T_NRLBroadcastTextMessage )
+#define M_NRLSetErrorHandler ( gb_NRL_function_table_ptr -> T_NRLSetErrorHandler )
+#define M_NRLConfigPointer ( gb_NRL_function_table_ptr -> T_NRLConfigPointer )
+#define M_NRLSetExternalInfo ( gb_NRL_function_table_ptr -> T_NRLSetExternalInfo )
+#define M_NRLGetExternalInfo ( gb_NRL_function_table_ptr -> T_NRLGetExternalInfo )
+#define M_NRLAddRemoteResource ( gb_NRL_function_table_ptr -> T_NRLAddRemoteResource )
+#define M_NRLSetDisplayMsgFlag ( gb_NRL_function_table_ptr -> T_NRLSetDisplayMsgFlag )
+#define M_NRLGetDisplayMsgFlag ( gb_NRL_function_table_ptr -> T_NRLGetDisplayMsgFlag )
+#define M_NRLLockResource ( gb_NRL_function_table_ptr -> T_NRLLockResource )
+#define M_NRLUnlockResource ( gb_NRL_function_table_ptr -> T_NRLUnlockResource )
+
+#define NRL_BASE_ERROR (-1024)
+#define NRL_ALREADY_INSTALLED (NRL_BASE_ERROR - 0)
+#define NRL_NOT_INSTALLED (NRL_BASE_ERROR - 1)
+#define NRL_NO_MORE_SESSIONS (NRL_BASE_ERROR - 2)
+#define NRL_COMMUNICATION_FAILURE (NRL_BASE_ERROR - 3)
+#define NRL_RESOURCE_REMOVED (NRL_BASE_ERROR - 4)
+#define NRL_PEER_RESOURCE_REMOVED (NRL_BASE_ERROR - 5)
+#define NRL_LAYER_REMOVED (NRL_BASE_ERROR - 6)
+#define NRL_PEER_LAYER_REMOVED (NRL_BASE_ERROR - 7)
+#define NRL_SESSION_DEALLOCATED (NRL_BASE_ERROR - 8)
+#define NRL_DUPLICATE_RSRC_ID (NRL_BASE_ERROR - 9)
+#define NRL_RESOURCE_FILTERED (NRL_BASE_ERROR - 10)
+#define NRL_VECTOR_IN_USE (NRL_BASE_ERROR - 11)
+#define NRL_NO_IPX (NRL_BASE_ERROR - 12)
+#define NRL_OUT_OF_MEMORY (NRL_BASE_ERROR - 13)
+#define NRL_NO_FREE_RECEIVE_BUFFS (NRL_BASE_ERROR - 14)
+#define NRL_RESOURCE_LOCKED (NRL_BASE_ERROR - 15)
+
+/*** These return codes are supported by the OS2 NRL ***/
+#define NRL_INVALID_NAME (NRL_BASE_ERROR - 16)
+#define NRL_NO_SPX (NRL_BASE_ERROR - 17)
+#define NRL_NOMORE_THREADS (NRL_BASE_ERROR - 18)
+#define NRL_INVALID_PARAM (NRL_BASE_ERROR - 19)
+
+
+/**
+ completion routine reasons
+**/
+#define NRL_TRANSMIT_ERROR 1
+#define NRL_TIME_OUT_ERROR 2
+#define NRL_DATA_OVERFLOW 3
+#define NRL_IMPOSSIBLE 4
+#define NRL_ERROR_MESSAGE 5
+#define NRL_DEAD_SESSION 6
+
+
+/**
+ registered resource types
+**/
+#define NRL_ALL_RESOURCES 0xFFFF
+#define NRL_LANBACK_DRIVE 0x01
+#define NRL_MBS_DRIVE 0x02
+#define NRL_MBS_SERVER 0x04
+#define NRL_MBS_ADMINISTRATOR 0x08
+#define NRL_TMENU 0x10
+#define NRL_RMFS_SERVER 0x20
+
+
+/**
+ registered broadcast message types
+**/
+#define NRL_ALL_MESSAGES 0xFFFF
+#define NRL_MBS_WS_BC 1
+#define NRL_MBS_BS_BC 2
+#define NRL_MBS_ADMIN_BC 4
+
+
+#endif
+
+
+
diff --git a/private/utils/ntbackup/inc/ntfs_fs.h b/private/utils/ntbackup/inc/ntfs_fs.h
new file mode 100644
index 000000000..b90c969e9
--- /dev/null
+++ b/private/utils/ntbackup/inc/ntfs_fs.h
@@ -0,0 +1,495 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: ntfs_fs.h
+
+ Description: This file contains the prototypes for the NTFS
+ file system functions.
+
+ $Log: M:/LOGFILES/NTFS_FS.H_V $
+
+ Rev 1.30.1.2 23 Jan 1994 14:26:02 BARRY
+Added debug and utility functions
+
+ Rev 1.30.1.1 19 Jan 1994 12:51:40 BARRY
+Supress warnings
+
+ Rev 1.30.1.0 04 Jan 1994 10:59:24 BARRY
+Added init entry points and temp-name function prototypes
+
+ Rev 1.30 30 Jul 1993 13:20:38 STEVEN
+if dir too deep make new one
+
+ Rev 1.29 26 Jul 1993 17:05:26 STEVEN
+fixe restore active file with registry
+
+ Rev 1.28 15 Jun 1993 09:18:32 MIKEP
+warning fixes
+
+ Rev 1.27 11 Mar 1993 12:10:42 BARRY
+Changes to stream structures for alternate data streams.
+
+ Rev 1.26 18 Jan 1993 13:17:18 BARRY
+Added proto for error translation function.
+
+ Rev 1.25 07 Dec 1992 16:30:42 STEVEN
+fixes from microsoft
+
+ Rev 1.24 23 Nov 1992 09:33:20 STEVEN
+fix support for event log
+
+ Rev 1.23 09 Nov 1992 17:41:22 BARRY
+Add stream ID vector to reserved info (for use in Verify).
+
+ Rev 1.22 22 Oct 1992 13:35:52 STEVEN
+added excludeSpecial
+
+ Rev 1.21 21 Oct 1992 19:38:52 BARRY
+Added queue of linked files to NTFS reserved area.
+Added protos for NTFS linked file queue functions.
+
+ Rev 1.20 19 Oct 1992 15:10:50 MIKEP
+fix REG_Restore
+
+ Rev 1.19 16 Oct 1992 14:59:06 STEVEN
+added support for backing up registry
+
+ Rev 1.18 15 Oct 1992 10:38:46 BARRY
+Got rid of my stupid struct on a windows pointer.
+
+ Rev 1.17 07 Oct 1992 14:47:46 STEVEN
+fix typo in macro
+
+ Rev 1.16 07 Oct 1992 14:39:42 BARRY
+Added NTFS_FillOutDBLK proto; got rid of IN specifiers.
+
+ Rev 1.15 06 Oct 1992 10:53:00 BARRY
+Added stream header ID translation functions.
+
+ Rev 1.14 05 Oct 1992 13:36:10 STEVEN
+added registry stuff
+
+ Rev 1.13 23 Sep 1992 10:35:54 BARRY
+Added NTFS_SetupFileNameInFDB.
+
+ Rev 1.12 22 Sep 1992 15:35:50 BARRY
+Got rid of GetTotalSizeDBLK.
+
+ Rev 1.11 21 Sep 1992 16:49:14 BARRY
+Updated NTFS_CompleteBlk prototype.
+
+ Rev 1.10 04 Sep 1992 17:15:56 STEVEN
+fix warnings
+
+ Rev 1.9 03 Sep 1992 17:07:28 STEVEN
+add support for volume name
+
+ Rev 1.7 29 Jul 1992 15:34:52 STEVEN
+fix warnings
+
+ Rev 1.6 22 May 1992 16:28:58 STEVEN
+
+
+ Rev 1.5 21 May 1992 13:38:46 STEVEN
+added more long path support
+
+ Rev 1.4 04 May 1992 09:39:22 LORIB
+Changes for variable length paths and fixes for prototype definitions.
+
+ Rev 1.3 03 Mar 1992 16:17:56 STEVEN
+added functions for long paths
+
+ Rev 1.2 28 Feb 1992 13:04:38 STEVEN
+step one for varible length paths
+
+ Rev 1.1 23 Jan 1992 13:18:14 STEVEN
+
+ Rev 1.0 17 Jan 1992 17:51:06 STEVEN
+Initial revision.
+
+**/
+
+#include "fsys.h"
+#include "queues.h"
+#include "ntfsdblk.h"
+
+#define REG_FNAME "<REGISTRY>"
+
+typedef struct _NTFS_STREAM_ID {
+ UINT32 streamID;
+ UINT32 nameLength;
+ UINT8 name[ NT_MAX_STREAM_NAME_LENG ];
+} NTFS_STREAM_ID;
+
+typedef struct _NTFS_FSYS_RESERVED {
+ UINT16 file_scan_mode ;
+ Q_HEADER scan_q;
+ Q_HEADER linkq; /* q of linked files */
+ CHAR_PTR work_buf ;
+ UINT16 work_buf_size ;
+ BOOLEAN work_buf_in_use ;
+ NTFS_STREAM_ID *streamIDs; /* Vector of visited stream IDs */
+ UINT16 streamIDBufferSize;
+ INT16 streamIDCount;
+} NTFS_FSYS_RESERVED, *NTFS_FSYS_RESERVED_PTR ;
+
+
+INT16 NTFS_AttachToDLE( FSYS_HAND fsh, /* I - File system handle */
+ GENERIC_DLE_PTR dle, /*I/O- drive to attach to. list element expanded */
+ CHAR_PTR u_name, /* I - user name NOT USED */
+ CHAR_PTR pswd); /* I - passowrd NOT USED */
+
+INT16 NTFS_DetachDLE( FSYS_HAND fsh ); /* I - */
+
+INT32 NTFS_EndOperationOnDLE( FSYS_HAND fsh ); /* I - */
+
+INT16 NTFS_CreateObj( FSYS_HAND fsh, /* I - File system to create object one */
+ DBLK_PTR dblk); /* I - Describes object to create */
+
+INT16 NTFS_OpenObj( FSYS_HAND fsh, /* I - file system that the file is opened on */
+ FILE_HAND *hand, /* O - allocated handle */
+ DBLK_PTR dblk, /*I/O- describes the file to be opened */
+ OPEN_MODE mode); /* I - open mode */
+
+INT16 NTFS_ReadObj( FILE_HAND hand, /* I - handle of object to read from */
+ BYTE_PTR buf, /* O - buffer to place data into */
+ UINT16 *size, /*I/O- Entry: size of buf; Exit: number of bytes read */
+ UINT16 *blk_size, /* O - Block size needed for next read */
+ STREAM_INFO_PTR s_info); /* O - Stream information for the data returned */
+
+
+INT16 NTFS_WriteObj( FILE_HAND hand, /* I - handle of object to read from */
+ BYTE_PTR buf, /* O - buffer to place data into */
+ UINT16 *size, /*I/O- Entry: size of buf; Exit: number of bytes read */
+ UINT16 *blk_size, /* O - Block size need for next read */
+ STREAM_INFO_PTR s_info); /* I - Stream information for the data passed in */
+
+INT16 NTFS_VerObj( FILE_HAND hand, /* I - file handle to verify data with */
+ BYTE_PTR buf, /* I - buffer needed to perform verify */
+ BYTE_PTR data, /* I - data to verify against */
+ UINT16 *size, /*I/O- size of buffers / amount verified */
+ UINT16 *blk_size, /* O - minum size of block for next call */
+ STREAM_INFO_PTR s_info); /* I - Stream information for the data passed in */
+
+
+INT16 NTFS_CloseObj( FILE_HAND hand ); /* I - handle of object to close */
+
+INT16 NTFS_DeleteObj( FSYS_HAND fsh,
+ DBLK_PTR dblk );
+
+INT16 NTFS_FindFirst( FSYS_HAND fsh, /* I - file system handle */
+ DBLK_PTR dblk, /* O - pointer to place to put the dblk data */
+ CHAR_PTR sname, /* I - search name */
+ UINT16 obj_type); /* I - object type (all objs, dirs, etc.) */
+
+INT16 NTFS_FindNext( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ); /* O - Discriptor block */
+
+INT16 NTFS_GetObjInfo( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ); /*I/O- On entry it is minimal on exit Complete */
+
+INT16 NTFS_VerObjInfo( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ); /* I - DBLK to compare OS against */
+
+INT16 NTFS_ChangeDir( FSYS_HAND fsh, /* I - file system to changing directories on */
+ CHAR_PTR path, /* I - describes the path of the new directory */
+ INT16 psize); /* I - specifies the length of the path */
+
+INT16 NTFS_UpDir( FSYS_HAND fsh ); /* I - file system to change directories in */
+
+INT16 NTFS_GetCurrentPath( FSYS_HAND fsh, /* I - file system to get current path from */
+ CHAR_PTR path, /* O - buffer to place this path */
+ INT16 *size); /*I/O- size of buffer on entry & on exit */
+
+INT16 NTFS_SeekObj( FILE_HAND hand, /* I - Opened object to seek into */
+ UINT32 *offset ); /*I/O- Offset to seek; Number of bytes actualy seeked */
+
+INT16 NTFS_GetMaxSizeDBLK( FSYS_HAND fsh /* not used */ );
+
+INT16 NTFS_GetBasePath( FSYS_HAND fsh, /* I - file system to get base path from */
+ CHAR_PTR full_path, /* O - buffer to place this path */
+ INT16 *size ); /*I/O- size of buffer on entry & on exit */
+
+INT16 NTFS_GetCurrentDDB( FSYS_HAND fsh, /* I - file system to get DDB from */
+ DBLK_PTR dblk ); /* O - place to put the DDB data */
+
+INT16 NTFS_SetObjInfo( FSYS_HAND fsh, /* I - file system handle */
+ DBLK_PTR dblk); /* I - data to write to disk */
+
+INT16 NTFS_ModFnameFDB( FSYS_HAND fsh, /* I - File system handle */
+ BOOLEAN set_it, /* I - TRUE if setting file name, FALSE if getting */
+ DBLK_PTR dblk, /* I - Descriptor block to get file name from */
+ CHAR_PTR buf, /*I/O- file name to read (or to write) */
+ INT16 *size ) ; /*I/O- size buffer on entry and exit */
+
+INT16 NTFS_ModPathDDB( FSYS_HAND fsh, /* I - File system handle */
+ BOOLEAN set_it , /* I - TRUE if setting path, FALSE if getting */
+ DBLK_PTR dblk, /* I - Descriptor block to get path from */
+ CHAR_PTR buf, /*I/O- path to read (or to write) */
+ INT16 *size ); /*I/O- size of buffer on entry and exit */
+
+INT16 NTFS_GetOSFnameFDB( DBLK_PTR dblk , /* I - Descriptor block to get path from */
+ CHAR_PTR buf ); /*I/O- path to read (or to write) */
+
+INT16 NTFS_GetOSPathDDB(
+ FSYS_HAND fsh, /* I - File System handle */
+ DBLK_PTR dblk , /* I - Descriptor block to get path from */
+ CHAR_PTR buf ); /*I/O- path to read (or to write) */
+
+INT16 NTFS_GetFileVerFDB( DBLK_PTR dblk ,
+ UINT32 *version ) ;
+
+INT16 NTFS_GetCdateDBLK( DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ); /*I/O- createion date to read (or to write) */
+
+INT16 NTFS_GetMdateDBLK( DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ) ; /* O - modify date to write */
+
+INT16 NTFS_ModBdateDBLK( BOOLEAN set_it , /* I - TRUE if setting creation date, FALSE if getting */
+ DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ) ; /*I/O- createion date to read (or to write) */
+
+INT16 NTFS_ModAdateDBLK( BOOLEAN set_it , /* I - TRUE if setting creation date, FALSE if getting */
+ DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ) ; /*I/O- createion date to read (or to write) */
+
+UINT64 NTFS_GetDisplaySizeDBLK( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ) ; /* I - Descriptor block to get generic data size for */
+
+INT16 NTFS_GetOS_InfoDBLK( DBLK_PTR dblk, /* I - DBLK to get the info from */
+ BYTE_PTR os_info, /* O - Buffer to place data */
+ INT16 *size ); /*I/O- Buffer size / data length */
+
+
+INT16 NTFS_ModAttribDBLK( BOOLEAN set_it ,
+ DBLK_PTR dblk ,
+ UINT32_PTR attr );
+
+
+INT16 NTFS_GetObjTypeDBLK( DBLK_PTR dblk,
+ OBJECT_TYPE *type );
+
+
+INT16 NTFS_GetActualSizeDBLK( FSYS_HAND fsh,
+ DBLK_PTR dblk ) ;
+
+INT16 NTFS_SizeofFname( FSYS_HAND fsh, /* I - file system in use */
+ DBLK_PTR fdb ); /* I - dblk to get fname from */
+
+INT16 NTFS_SizeofOSFname( FSYS_HAND fsh, /* I - file system in use */
+ DBLK_PTR fdb ) ; /* I - dblk to get fname from */
+
+INT16 NTFS_SizeofPath( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR ddb ) ; /* I - DBLK to get path size from */
+
+INT16 NTFS_SizeofOSPath( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR ddb ) ; /* I - DBLK to get path size from */
+
+INT16 NTFS_SizeofOSInfo( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ); /* I - DBLK to get size of OS info for */
+
+
+INT16 NTFS_PushMinDDB( FSYS_HAND fsh,
+ DBLK_PTR dblk );
+
+INT16 NTFS_PopMinDDB( FSYS_HAND fsh ,
+ DBLK_PTR dblk );
+
+INT16 NTFS_CreateFDB( FSYS_HAND fsh,
+ GEN_FDB_DATA_PTR dat ) ;
+
+INT16 NTFS_CreateDDB( FSYS_HAND fsh,
+ GEN_DDB_DATA_PTR dat ) ;
+
+INT16 NTFS_CreateIDB( FSYS_HAND fsh,
+ GEN_IDB_DATA_PTR dat ) ;
+
+VOID NTFS_SetOwnerId( FSYS_HAND fsh, DBLK_PTR dblk, UINT32 id ) ;
+
+BOOLEAN NTFS_ProcessDDB( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+INT16 NTFS_ChangeIntoDDB( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+VOID NTFS_GetRealBasePath( FSYS_HAND fsh, CHAR_PTR path ) ;
+
+INT16 NTFS_FindClose( FSYS_HAND fsh,
+ DBLK_PTR dblk ) ;
+
+INT16 NTFS_GetSpecDBLKS(
+ FSYS_HAND fsh,
+ DBLK_PTR dblk,
+ INT32 *index );
+
+INT16 NTFS_DeviceDispName(
+GENERIC_DLE_PTR dle,
+CHAR_PTR dev_name,
+INT16 size,
+INT16 type ) ;
+
+INT16 NTFS_FindDrives( DLE_HAND hand, BE_CFG_PTR cfg, UINT32 fsys_mask );
+
+VOID NTFS_RemoveDLE( GENERIC_DLE_PTR dle ) ;
+
+VOID NTFS_GetVolName( GENERIC_DLE_PTR dle, CHAR_PTR buffer ) ;
+
+INT16 NTFS_SizeofVolName( GENERIC_DLE_PTR dle ) ;
+
+VOID NTFS_EmptyFindHandQ( FSYS_HAND fsh ) ;
+
+INT16 NTFS_EnumSpecFiles(
+ GENERIC_DLE_PTR dle,
+ UINT16 *index,
+ CHAR_PTR *path,
+ INT16 *psize,
+ CHAR_PTR *fname ) ;
+
+INT16 NTFS_GetSpecDBLKS(
+ FSYS_HAND fsh,
+ DBLK_PTR dblk,
+ INT32 *index );
+
+VOID NTFS_InitMakeData( FSYS_HAND fsh, INT16 blk_type, CREATE_DBLK_PTR data ) ;
+BOOLEAN NTFS_IsBlkComplete( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+INT16 NTFS_CompleteBlk( FSYS_HAND fsh, DBLK_PTR dblk, BYTE_PTR buffer, UINT16 *size, STREAM_INFO *sinfo ) ;
+VOID NTFS_ReleaseBlk( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+
+INT16 NTFS_DupBlk( FSYS_HAND fsh, DBLK_PTR db_org, DBLK_PTR db_dup );
+
+INT16 NTFS_SpecExcludeObj( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR ddb, /* I - Descriptor block of ddb */
+ DBLK_PTR fdb ) ; /* I - Descriptor block of fdb */
+
+
+INT16 NTFS_SetupPathInDDB(
+ FSYS_HAND fsh,
+ DBLK_PTR ddblk,
+ CHAR_PTR cur_dir,
+ CHAR_PTR sub_dir_name,
+ UINT16 buf_req_size ) ;
+
+INT16 NTFS_SetupFileNameInFDB( FSYS_HAND fsh,
+ DBLK_PTR dblk,
+ CHAR_PTR fname,
+ UINT16 bufMinSize );
+
+INT16 NTFS_SetupWorkPath(
+ FSYS_HAND fsh,
+ CHAR_PTR cur_dir,
+ CHAR_PTR sname,
+ CHAR_PTR *path_string ) ;
+
+VOID NTFS_ReleaseWorkPath( FSYS_HAND fsh ) ;
+
+VOID NTFS_FixPath( CHAR_PTR path, INT16_PTR size, INT16 fname_size ) ;
+
+//
+// Private Registry API functions
+//
+
+// Call backup for backup operations and both for restore operations.
+
+INT REG_AssertBackupPrivilege( VOID );
+INT REG_AssertRestorePrivilege( VOID );
+
+// Given a drive, path, and file name I'll tell you if it
+// is an active registry file.
+
+INT REG_IsRegistryFile(
+ GENERIC_DLE_PTR dle,
+ CHAR_PTR FileSpec );
+
+INT REG_IsEventFile(
+ GENERIC_DLE_PTR dle,
+ CHAR_PTR FileSpec,
+ CHAR_PTR buffer );
+
+// Called by the file system to determine if/where the
+// registry is for each drive.
+// Everyone else can get the info from the DLE's.
+
+INT REG_GetRegistryPath(
+CHAR *Machine,
+CHAR Drive,
+CHAR_PTR Path,
+INT *PathSize );
+
+// Try to backup up an active registry file.
+
+INT REG_BackupRegistryFile(
+GENERIC_DLE_PTR dle,
+CHAR_PTR RegFileSpec,
+CHAR_PTR TempFileSpec );
+
+// Most dangerous of all. Try to restore an active registry file.
+
+INT REG_RestoreRegistryFile(
+GENERIC_DLE_PTR dle,
+CHAR_PTR RegFileSpec,
+CHAR_PTR NewFileSpec,
+CHAR_PTR OldFileSpec );
+
+INT REG_IsCurDirRegistryPath(
+IN FSYS_HAND fsh ) ;
+
+VOID REG_MoveActiveRenameKey(
+GENERIC_DLE_PTR dle,
+CHAR_PTR RegFileSpec ) ;
+
+
+#define NTFS_GetRegistryPath( dle ) ((dle)->info.ntfs->registry_path )
+#define NTFS_GetRegistryPathSize( dle ) ((dle)->info.ntfs->registry_path_size )
+
+
+UINT32 NTFS_MSoftToMayn( UINT32 msoftID );
+UINT32 NTFS_MaynToMSoft( UINT32 maynID );
+
+INT16 NTFS_FillOutDBLK( FSYS_HAND fsh,
+ DBLK_PTR dblk,
+ WIN32_FIND_DATA *find_data );
+
+CHAR_PTR NTFS_MakeTempName( CHAR_PTR path,
+ CHAR_PTR prefix) ;
+
+NTFS_LINK_Q_ELEM_PTR NTFS_SearchLinkQueue( FSYS_HAND fsh,
+ DWORD idHi,
+ DWORD idLo );
+
+INT16 NTFS_EnqueueLinkInfo( FSYS_HAND fsh,
+ DWORD idHi,
+ DWORD idLo,
+ CHAR_PTR path,
+ CHAR_PTR name );
+
+INT16 NTFS_LinkFileToFDB( FILE_HAND hand ) ;
+
+INT16 NTFS_TranslateBackupError( DWORD backupError );
+
+/*
+ * Init/Deinit for one-time work in TINITFS.C
+ */
+INT16 NTFS_InitFileSys( DLE_HAND hand, BE_CFG_PTR cfg, UINT32 fsys_mask );
+VOID NTFS_DeInitFileSys( DLE_HAND hand );
+
+/*
+ * Operations on temporary file names (for active restores)
+ */
+VOID NTFS_InitTemp( VOID );
+VOID NTFS_DeinitTemp( VOID );
+BOOLEAN NTFS_SaveTempName( CHAR_PTR tapeName, CHAR_PTR diskName );
+CHAR_PTR NTFS_GetTempName( CHAR_PTR tapeName );
+
+
+/*
+ * Utility and debug functions
+ */
+
+#if defined( FS_DEBUG )
+#define NTFS_DebugPrint NTFS_DebugPrintFunction
+#else
+#define NTFS_DebugPrint
+#endif
+
+VOID NTFS_DebugPrintFunction( CHAR *fmt, ... );
+CHAR_PTR NTFS_DuplicateString( CHAR_PTR src );
+
diff --git a/private/utils/ntbackup/inc/ntfsdblk.h b/private/utils/ntbackup/inc/ntfsdblk.h
new file mode 100644
index 000000000..f9f5096a1
--- /dev/null
+++ b/private/utils/ntbackup/inc/ntfsdblk.h
@@ -0,0 +1,235 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: ntfsdblk.h
+
+ Description: This file contains the definition of the DOS
+ file and directory control blocks.
+
+
+ $Log: M:/LOGFILES/NTFSDBLK.H_V $
+
+ Rev 1.26.1.0 24 Mar 1994 20:20:56 BARRY
+Added a flag for alt streams names being complete
+
+ Rev 1.26 01 Dec 1993 13:05:00 STEVEN
+Path in strem should start at 600
+
+ Rev 1.25 15 Jun 1993 09:17:28 MIKEP
+warning fixes
+
+ Rev 1.24 19 May 1993 13:58:18 BARRY
+Added Steve's changes for OS/2 EA support.
+
+ Rev 1.23 11 Mar 1993 12:10:44 BARRY
+Changes to stream structures for alternate data streams.
+
+ Rev 1.22 24 Feb 1993 15:38:08 BARRY
+Fixed restore of active files when write errors occur.
+
+ Rev 1.21 15 Jan 1993 13:18:30 BARRY
+added support for new error messages and backup priviladge
+
+ Rev 1.20 07 Dec 1992 16:31:56 STEVEN
+added support for posix
+
+ Rev 1.19 24 Nov 1992 11:02:34 BARRY
+Changes to make LINK streams null-impregnated.
+
+ Rev 1.18 10 Nov 1992 08:12:38 STEVEN
+move os path to common part of dblk
+
+ Rev 1.17 09 Nov 1992 09:55:04 BARRY
+Added stuff for verify.
+
+ Rev 1.16 29 Oct 1992 16:55:04 BARRY
+Added a buffer for link data to obj_hand.
+
+ Rev 1.15 22 Oct 1992 13:40:48 BARRY
+Added link q goodies.
+
+ Rev 1.14 19 Oct 1992 17:57:12 BARRY
+Added the needStreamHeader flag for backup.
+
+ Rev 1.13 16 Oct 1992 14:59:10 STEVEN
+added support for backing up registry
+
+ Rev 1.12 09 Oct 1992 16:10:42 BARRY
+Corrected name of structure member.
+
+ Rev 1.11 24 Sep 1992 13:45:40 BARRY
+Changes for huge file name support.
+
+ Rev 1.10 23 Sep 1992 10:37:06 BARRY
+Changed name of PATH_Q_ELEM structure to NAME_Q_ELEM, added this structure to FDBs.
+
+ Rev 1.9 21 Sep 1992 16:50:16 BARRY
+Removed path_complete from DDB_INFO and added common name_complete field.
+
+ Rev 1.8 18 Sep 1992 15:52:02 BARRY
+Added NT_STREAM_HEADER structure; updated NTFS_OBJ_HAND for
+Stream Header redesign.
+
+ Rev 1.7 20 Aug 1992 14:07:16 BURT
+fix warnings
+
+ Rev 1.6 23 Jul 1992 10:08:28 STEVEN
+added short filename to osinfo
+
+ Rev 1.5 21 May 1992 13:38:44 STEVEN
+added more long path support
+
+ Rev 1.4 04 May 1992 09:35:18 LORIB
+Changes for variable length paths.
+
+ Rev 1.3 28 Feb 1992 13:04:40 STEVEN
+step one for varible length paths
+
+ Rev 1.2 07 Feb 1992 16:42:06 STEVEN
+changed dta structure for attribute
+
+ Rev 1.1 28 Jan 1992 14:46:50 STEVEN
+fix min ddb for NTFS
+
+ Rev 1.0 17 Jan 1992 17:51:04 STEVEN
+Initial revision.
+
+**/
+/* $end$ include list */
+
+#ifndef ntfsdblk_h
+#define ntfsdblk_h
+
+#include "queues.h"
+
+#define NTFS_MAX_DSIZE ( 600 )
+#define NTFS_MAX_FSIZE ( 600 )
+#define DA_DIRECTORY 0x10
+
+/* CBN -- These are temporary until the definitions are in MSoft headers */
+#if !defined( BACKUP_DATA )
+#define BACKUP_DATA 0x00000001
+#define BACKUP_EA_DATA 0x00000002
+#define BACKUP_SECURITY_DATA 0x00000003
+#define BACKUP_ALTERNATE_DATA 0x00000004
+#define BACKUP_LINK 0x00000005
+#endif
+
+/* Backup API stream headers */
+#define NT_MAX_STREAM_NAME_LENG 524
+
+typedef struct _NT_STREAM_HEADER {
+ UINT32 id ;
+ UINT32 attrib ;
+ UINT32 size_lo ;
+ UINT32 size_hi ;
+ UINT32 name_leng ;
+ UINT8 name[ NT_MAX_STREAM_NAME_LENG ] ;
+} NT_STREAM_HEADER, *NT_STREAM_HEADER_PTR ;
+
+/* Matches bottom portion of NT stream headers */
+typedef struct _NT_STREAM_NAME {
+ UINT32 name_leng ;
+ UINT8 name[ NT_MAX_STREAM_NAME_LENG ] ;
+} NT_STREAM_NAME, *NT_STREAM_NAME_PTR;
+
+#define NT_SIZEOF_NAMELESS_STREAM_HEAD \
+ (sizeof(NT_STREAM_HEADER) - NT_MAX_STREAM_NAME_LENG)
+
+typedef struct _NTFS_LINK_Q_ELEM {
+ Q_ELEM q; /* queue element structure for Q calls */
+ DWORD idHi; /* file's unique ID -- hi 32 bits */
+ DWORD idLo; /* file's unique ID -- low 32 bits */
+ UINT16 linkNameLen; /* length of string below */
+ CHAR_PTR linkName; /* path and name of "original" file */
+} NTFS_LINK_Q_ELEM, *NTFS_LINK_Q_ELEM_PTR ;
+
+
+typedef struct _NTFS_OBJ_HAND {
+ HANDLE fhand;
+ VOID_PTR context;
+ NT_STREAM_HEADER streamHeader;
+ UINT64 nextStreamHeaderPos;
+ UINT64 curPos;
+ BOOLEAN needStreamHeader; /* Ready for SH on backup */
+ NTFS_LINK_Q_ELEM_PTR linkPtr;
+ BOOLEAN nameComplete;
+ BOOLEAN registry_file ;
+ CHAR_PTR temp_file;
+ UINT16 linkBufferSize;
+ CHAR_PTR linkBuffer;
+ UINT16 linkNameLen;
+ BOOLEAN streamsAllVisited;
+ BOOLEAN altNameComplete; /* TRUE if on verify alt name complete */
+ INT16 verifyStreamPos;
+ BYTE_PTR os2_ea_buffer ;
+ BOOLEAN processing_os2_ea ;
+ BOOLEAN sawSecurity; /* NACL stream seen on backup */
+ BOOLEAN writeError; /* True if we had write error */
+} NTFS_OBJ_HAND, *NTFS_OBJ_HAND_PTR;
+
+
+typedef struct _NTFS_FDB_INFO *NTFS_FDB_INFO_PTR;
+
+typedef struct _NTFS_DTA {
+ HANDLE scan_hand ;
+ UINT64 size ;
+ UINT32 os_attr ;
+ FILETIME create_time ;
+ FILETIME access_time ;
+ FILETIME modify_time ;
+} NTFS_DTA, *NTFS_DTA_PTR ;
+
+
+typedef struct _NTFS_FDB_INFO {
+ HANDLE handle ; /* set: NTFS_CreateFile */
+ CHAR_PTR hand_temp_name ;
+ BOOLEAN hand_registry ;
+ UINT32 fdb_attrib ;
+ CHAR alt_name[14] ;
+ DWORD idHi;
+ DWORD idLo;
+ DWORD linkCount;
+ BOOLEAN linkOnly; /* Already backed up */
+ BOOLEAN PosixFile ;
+} NTFS_FDB_INFO ;
+
+
+typedef struct _NTFS_DDB_INFO {
+ UINT32 ddb_attrib ;
+} NTFS_DDB_INFO, *NTFS_DDB_INFO_PTR ;
+
+
+typedef struct _NTFS_DBLK *NTFS_DBLK_PTR;
+
+typedef struct _NTFS_DBLK {
+ UINT8 blk_type; /* values: DDB_ID, FDB_ID set: DOS */
+ COM_DBLK fs_reserved ;
+ NTFS_DTA dta;
+ BOOLEAN os_info_complete; /* TRUE if GetObjInfo doesn't have to do anything */
+ BOOLEAN name_complete; /* TRUE if name/path is restored to DBLK */
+ FS_NAME_Q_ELEM_PTR full_name_ptr ;
+ union {
+ NTFS_DDB_INFO d;
+ NTFS_FDB_INFO f; /* last member in structure */
+ } b;
+} NTFS_DBLK;
+
+
+typedef struct _NTFS_MIN_DDB *NTFS_MIN_DDB_PTR;
+
+typedef struct _NTFS_MIN_DDB {
+ Q_ELEM q ;
+ HANDLE scan_hand; /* windows handle for scan */
+ BOOLEAN path_in_stream ;
+ UINT16 psize ; /* size of path string */
+ CHAR_PTR path; /* build from "name" and current dir */
+} NTFS_MIN_DDB;
+
+typedef struct _NTFS_SCAN_Q_ELEM {
+ Q_ELEM q ;
+ HANDLE scan_hand ;
+} NTFS_SCAN_Q_ELEM, *NTFS_SCAN_Q_ELEM_PTR ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/nw386.h b/private/utils/ntbackup/inc/nw386.h
new file mode 100644
index 000000000..073cbd479
--- /dev/null
+++ b/private/utils/ntbackup/inc/nw386.h
@@ -0,0 +1,257 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: nw386.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains prototypes and defines for the NetWare
+ 386 specific functions. Most of the information in this file
+ was obtained by examining the source to the preliminary
+ NetWare 386 C interface functions. Each of these functions was
+ designed to impliment only one API. The Novell library tries to
+ releive the developer of some of the complexity of these functions
+ by combining APIs into a single function. However, this is not
+ desirable when trying to maximize performance.
+
+
+ Location:
+
+
+ $Log: G:/LOGFILES/NW386.H_V $
+ *
+ * Rev 1.0 09 May 1991 13:31:56 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef _nw386_h_
+#define _nw386_h_
+
+
+#define DOS_NAME_SPACE 0
+#define MAC_NAME_SPACE 1
+
+#define NW_MAX_NAME_SPACE_ENTRY_SIZE 127 /* @@@ ??? */
+#define NW_MAX_NCP_PATH 255
+#define NW_MAX_DIR_RESTRICTIONS 33
+#define NW_MAX_VOL_NAME 48
+
+
+#define NW_CHANGE_DOS_NAME 0x0001
+#define NW_CHANGE_DOS_ATTRIBUTES 0x0002
+#define NW_CHANGE_DOS_CREATE_DATE 0x0004
+#define NW_CHANGE_DOS_CREATE_TIME 0x0008
+#define NW_CHANGE_DOS_OWNER 0x0010
+#define NW_CHANGE_DOS_ARCHIVE_DATE 0x0020
+#define NW_CHANGE_DOS_ARCHIVE_TIME 0x0040
+#define NW_CHANGE_DOS_ARCHIVER_ID 0x0080
+#define NW_CHANGE_DOS_MODIFY_DATE 0x0100
+#define NW_CHANGE_DOS_MODIFY_TIME 0x0200
+#define NW_CHANGE_DOS_MODIFIER_ID 0x0400 /* for files only */
+#define NW_CHANGE_DOS_NEXT_TRUSTEE 0x0400 /* for directories only */
+#define NW_CHANGE_DOS_ACCESS_DATE 0x0800 /* for files only */
+#define NW_CHANGE_DOS_INHERITED_RIGHTS 0x1000
+#define NW_CHANGE_DOS_MAXIMUM_SPACE 0x2000 /* for dirs only */
+
+#define NW_CHANGE_MAC_NAME 0x0001
+#define NW_CHANGE_MAC_FINDER_INFO 0x0002
+#define NW_CHANGE_MAC_PRODOS_INFO 0x0004
+
+#define NW_CHANGE_EVERYTHING 0xFFFFFFFF
+
+#define NW_NORMAL_ATTR 0x00000000L
+#define NW_READ_ONLY_ATTR 0x00000001L
+#define NW_HIDDEN_ATTR 0x00000002L
+#define NW_SYSTEM_ATTR 0x00000004L
+#define NW_EXECUTE_ONLY_ATTR 0x00000008L
+#define NW_DIRECTORY_ATTR 0x00000010L
+#define NW_NEEDS_ARCHIVED_ATTR 0x00000020L
+#define NW_EXECUTE_CONFIRM_ATTR 0X00000040L
+#define NW_SHAREABLE_ATTR 0x00000080L
+
+#define NW_LOW_SEARCH_ATTR 0x00000100L
+#define NW_MID_SEARCH_ATTR 0x00000200L
+#define NW_HI_SEARCH_ATTR 0x00000400L
+#define NW_PRIVATE_ATTR 0x00000800L
+#define NW_TRANSACTIONAL_ATTR 0x00001000L
+#define NW_INDEXED_ATTR 0x00002000L
+#define NW_READ_AUDIT_ATTR 0x00004000L
+#define NW_WRITE_AUDIT_ATTR 0x00008000L
+
+#define NW_PURGE_ATTR 0x000010000L
+#define NW_RENAME_INHIBIT_ATTR 0x000020000L
+#define NW_DELETE_INHIBIT_ATTR 0x000040000L
+#define NW_COPY_INHIBIT_ATTR 0x000080000L
+
+
+typedef struct DOS_NAME_SPACE_FILE_INFO {
+ UINT32 last_modifier_id ; /* 57 */
+ UINT32 data_fork_size ; /* 61 */
+ UINT8 reserved1[44]; /* 65 */
+ UINT16 inherited_rights_mask; /* 109 */
+ UINT16 last_access_date ; /* 111 */
+ UINT8 reserved2[20]; /* 113 */
+ UINT32 primary_entry; /* 133 */
+ UINT32 name_list ; /* 137 */
+ } DOS_NAME_SPACE_FILE_INFO ;
+
+
+typedef struct DOS_NAME_SPACE_DIR_INFO {
+ UINT32 next_trustee_entry; /* 57 */
+ UINT8 reserved1[48]; /* 61 */
+ UINT32 maximum_space; /* 109 */
+ UINT16 inherited_rights_mask; /* 113 */
+ } DOS_NAME_SPACE_DIR_INFO ;
+
+
+
+typedef struct DOS_NAME_SPACE_INFO {
+ UINT8 name_length;
+ CHAR name[12]; /* no '\0' */
+ UINT16 creation_time;
+ UINT16 creation_date;
+ UINT32 owner_id;
+ UINT16 archive_time;
+ UINT16 archive_date;
+ UINT32 archiver_id;
+ UINT16 modify_time;
+ UINT16 modify_date;
+ union {
+ DOS_NAME_SPACE_DIR_INFO dir ;
+ DOS_NAME_SPACE_FILE_INFO file ;
+ } info ;
+ } DOS_NAME_SPACE_INFO ;
+
+typedef struct MAC_NAME_SPACE_INFO {
+ UINT8 name_length;
+ CHAR name[32];
+ UINT32 resource_fork;
+ UINT32 resource_fork_size;
+ UINT8 finder_info[32];
+ UINT8 pro_dos_info[6];
+ } MAC_NAME_SPACE_INFO ;
+
+
+typedef struct UNKNOWN_NAME_SPACE_INFO {
+ UINT8 unknown[ NW_MAX_NAME_SPACE_ENTRY_SIZE ];
+ } UNKNOWN_NAME_SPACE_INFO ;
+
+
+typedef struct NAME_SPACE_ENTRY * NAME_SPACE_ENTRY_PTR ;
+
+typedef struct NAME_SPACE_ENTRY {
+ UINT8 unknown1[1];
+ UINT32 sub_directory;
+ UINT32 attributes;
+ INT32 entry_id; /* This field is dynamically created each time the file */
+ /* server is brought up. Do NOT back up this field. */
+ UINT8 flags;
+ UINT8 name_space_type;
+ union {
+ DOS_NAME_SPACE_INFO dos;
+ MAC_NAME_SPACE_INFO mac;
+ UNKNOWN_NAME_SPACE_INFO unknown;
+ } info;
+ } NAME_SPACE_ENTRY ;
+
+
+typedef struct TRUSTEE_REPLY * TRUSTEE_REPLY_PTR ;
+
+typedef struct TRUSTEE_REPLY {
+ UINT8 num_trustees_returned ;
+ UINT32 trustee_id[ 20 ];
+ UINT16 trustee_rights[ 20 ];
+ } TRUSTEE_REPLY ;
+
+typedef struct DIR_RESTRICTION {
+ UINT8 level;
+ UINT32 max;
+ UINT32 current;
+ } DIR_RESTRICTION ;
+
+
+typedef struct DIR_RESTRICTION_LIST * DIR_RESTRICTION_LIST_PTR ;
+
+typedef struct DIR_RESTRICTION_LIST {
+ UINT8 num_restrictions;
+ DIR_RESTRICTION restriction[ NW_MAX_DIR_RESTRICTIONS ] ; /* array of restrictions */
+ } DIR_RESTRICTION_LIST ;
+
+
+typedef struct DIR_INFO_REPLY * DIR_INFO_REPLY_PTR ;
+
+typedef struct DIR_INFO_REPLY {
+ UINT32 total_blocks;
+ UINT32 avail_blocks;
+ UINT32 total_dir_entries;
+ UINT32 avail_dir_entries;
+ UINT32 flags;
+ UINT8 sectors_per_block;
+ UINT8 vol_name_length;
+ CHAR vol_name[ NW_MAX_VOL_NAME ];
+ } DIR_INFO_REPLY;
+
+
+typedef struct DIR_ENTRY * DIR_ENTRY_PTR ;
+
+typedef struct DIR_ENTRY {
+ UINT32 sub_directory;
+ UINT32 attributes;
+ UINT8 unique_id;
+ UINT8 flags;
+ UINT8 name_space_type;
+ DOS_NAME_SPACE_INFO dinfo ;
+ } DIR_ENTRY ;
+
+
+typedef struct DIR_ENTRY_SCAN * DIR_ENTRY_SCAN_PTR ;
+
+typedef struct DIR_ENTRY_SCAN {
+ INT32 entry_id; /* This field is dynamically created each time the file */
+ /* server is brought up. Do NOT back up this field. */
+ DIR_ENTRY entry;
+ } DIR_ENTRY_SCAN ;
+
+
+
+INT16 GetNameSpaceEntry( UINT8 volume_number, INT32 sequence, UINT8 name_space_type,
+ NAME_SPACE_ENTRY_PTR entry_info_ptr ) ;
+
+INT16 FillNameSpaceBuffer( UINT8 volumeNum, NAME_SPACE_ENTRY_PTR ns_buf_ptr ) ;
+
+
+
+INT16 ScanEntryForTrustees386( UINT8 directory_handle, CHAR_PTR directory_path,
+ UINT8 seq_number, TRUSTEE_REPLY_PTR trustee_reply_buf ) ;
+
+INT16 GetDirRestrictions386( UINT8 dir_handle, DIR_RESTRICTION_LIST_PTR res_list ) ;
+
+
+INT16 GetDirInfo386( UINT8 dir_handle, DIR_INFO_REPLY_PTR dir_info_buf ) ;
+
+
+INT16 SetTrustee386( UINT8 directory_handle, CHAR_PTR directory_path,
+ UINT32 trustee_object_id, UINT16 trustee_rights_mask ) ;
+
+
+INT16 SetDirRestriction386( UINT8 dir_handle, INT32 restriction ) ;
+
+
+UINT16 ScanDirEntry386( UINT8 directory_handle, CHAR_PTR search_path,
+ UINT8 search_attributes, UINT32 prev_entry_id,
+ DIR_ENTRY_SCAN_PTR dir_entry_buf ) ;
+
+
+INT16 GetDirEntry386( UINT8 dir_handle, DIR_ENTRY_PTR dir_entry_ptr ) ;
+
+
+INT16 SetDirEntry386( UINT8 dir_handle, UINT8 search_attribute,
+ UINT32 entry_id, UINT32 change_bits,
+ DIR_ENTRY_PTR dir_entry_ptr ) ;
+
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/oem.h b/private/utils/ntbackup/inc/oem.h
new file mode 100644
index 000000000..2e4ec552a
--- /dev/null
+++ b/private/utils/ntbackup/inc/oem.h
@@ -0,0 +1,23 @@
+#ifndef _oem_h_
+#define _oem_h_
+
+
+
+#ifdef DO_OEM
+
+VOID show_oem_title( VOID );
+VOID set_oem_title_addition( CHAR_PTR addition );
+#define clear_oem_title_addition() set_oem_title_addition( NULL )
+
+#else
+
+#define show_oem_title() /* do nothing */
+#define set_oem_title_addition( x ) /* do nothing */
+#define clear_oem_title_addition() /* do nothing */
+
+#endif
+
+
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/ombatch.h b/private/utils/ntbackup/inc/ombatch.h
new file mode 100644
index 000000000..bbb825cae
--- /dev/null
+++ b/private/utils/ntbackup/inc/ombatch.h
@@ -0,0 +1,154 @@
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+DAVEV
+
+ Name: ombatch.h
+
+ Description: This file contains the definitions for the Microsoft
+ OEM version of Maynstream for Windows & Win32/NT to
+ support Command Line batch processing.
+
+ The following support is implemented for batch mode
+ processing (see the NT Backup/Restore Utility
+ Specification for more information.)
+
+ The batch command has the following parameters:
+
+ APPNAME [OPERATION PATHNAMES [OPTIONS]]
+
+ where:
+
+ OPERATION = "Backup"
+
+ PATHNAMES = [[drive:][path]filespec] ...
+
+ OPTIONS = {Mode, Verify, RestrictAccess,
+ Description, BackupType, Logfile,
+ Logmode }...
+
+ Mode = /A[ppend]
+ Verify = /V[erify]
+ Access = /R[estrict]
+ Description = /D[escription] "text"
+ BackupType = /T[ype] {Normal, Incremental,
+ Differential, Copy,
+ Incremental_Copy}
+ Logfile = /L[ogfile] "filename"
+ Logmode = /E[xceptions]
+
+ Note: In this implementation, options may appear
+ anywhere in the command line following the
+ 'Backup' operation key word - they are not
+ restricted to just following the list of
+ path names.
+
+ $Log: G:/UI/LOGFILES/OMBATCH.H_V $
+
+ Rev 1.5.1.0 26 Oct 1993 18:07:20 BARRY
+Added backupRegistry flag to options.
+
+ Rev 1.5 26 Jul 1993 17:40:48 MARINA
+enable c++
+
+ Rev 1.4 07 Dec 1992 16:36:14 STEVEN
+msoft fix
+
+ Rev 1.3 15 Oct 1992 13:04:02 DAVEV
+fix problem with batch mode /T option
+
+ Rev 1.2 04 Oct 1992 19:48:22 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.1 25 Sep 1992 15:23:18 DARRYLP
+Spelling fix - mismatch on BSD_BACKUP_DIFFERENTIAL
+
+ Rev 1.0 11 May 1992 14:28:50 DAVEV
+Initial revision.
+
+******************************************************************************/
+#ifndef OEMBATCH_H_INCL
+#define OEMBATCH_H_INCL
+
+typedef enum {
+ OEM_TYPE_UNKNOWN = -1,
+ OEM_TYPE_COMPATIBLE = BSD_BACKUP_COMPATIBLE,
+ OEM_TYPE_NORMAL = BSD_BACKUP_NORMAL,
+ OEM_TYPE_COPY = BSD_BACKUP_COPY,
+ OEM_TYPE_DIFFERENTIAL= BSD_BACKUP_DIFFERENTIAL,
+ OEM_TYPE_INCREMENTAL = BSD_BACKUP_INCREMENTAL,
+ OEM_TYPE_DAILY = BSD_BACKUP_DAILY
+
+ } OEMTYPE ;
+
+typedef enum {
+ OEM_MODE_OVERWRITE,
+ OEM_MODE_APPEND
+
+ } OEMMODE ;
+
+typedef enum {
+ OEM_VERIFY_OFF,
+ OEM_VERIFY_ON
+
+ } OEMVERIFY ;
+
+typedef enum {
+ OEM_ACCESS_NO_RESTRICT,
+ OEM_ACCESS_RESTRICTED
+
+ } OEMACCESS ;
+
+typedef enum {
+ OEM_LOG_FULLDETAIL,
+ OEM_LOG_SUMMARY_ONLY
+
+ } OEMLOGOPT ;
+
+typedef struct OEMOPTS_STRUCT {
+
+ OEMMODE eMode;
+ OEMVERIFY eVerify;
+ OEMACCESS eAccess;
+ OEMTYPE eType;
+ OEMLOGOPT eLogOpt;
+ LPSTR pszLogName;
+ LPSTR pszDescription;
+ BOOLEAN backupRegistry;
+
+} OEMOPTS, FAR * OEMOPTS_PTR;
+
+OEMOPTS_PTR OEM_DefaultBatchOptions ( VOID );
+VOID OEM_UpdateBatchBSDOptions ( BSD_HAND hbsd, OEMOPTS_PTR pOpts );
+VOID OEM_DeleteBatchOptions ( OEMOPTS_PTR * pOpts );
+OEMTYPE OEM_LookupTypeOption ( LPSTR pszType );
+INT OEM_ProcessBatchCmdOption (
+ OEMOPTS_PTR pOpts, //IO - Pointer to the options buffer to update
+ LPSTR pszOption, //I - Pointer to option string
+ LPSTR pszTokens, //I - Token seperators between cmd line options
+ LPSTR pszCmdLine); //IO - Pointer to partially tokenized command line
+ // ( not really needed, but may be modified
+ // as a side effect of strtok () )
+INT OEM_LookupBatchOption (
+ LPSTR pszOption ); //I - Targe option string to look for
+BOOL OEM_AddPathToBackupSets (
+ BSD_HAND hbsd, //IO - list of backup sets to update
+ DLE_HAND hdle, //I - list of drives
+ LPSTR pszPath ); //I - Path to insert into backup set
+
+BOOL OEM_AddEMSServerToBackupSets (
+ BSD_HAND hbsd, //IO - list of backup sets to update
+ DLE_HAND hdle, //I - list of drives
+ LPSTR pszPath, //I - Path to insert into backup set
+ UINT8 uType ); //I - FS_EMS_MDB_ID (Monolithic) or
+ // FS_EMS_DSA_ID (DSA)
+
+INT OEM_CharInSet ( CHAR chTarg, LPSTR pszSet );
+
+INT16 DLE_FindByEMSServerName (
+ DLE_HAND hand, /* I - DLE list handle */
+ LPSTR name, /* I - name to search for */
+ UINT8 uType, /* I - type of dle to search for */
+ GENERIC_DLE_PTR *dle ); /* O - pointer to matched DLE */
+
+
+#endif //OEMBATCH_H_INCL
diff --git a/private/utils/ntbackup/inc/ombkup.h b/private/utils/ntbackup/inc/ombkup.h
new file mode 100644
index 000000000..56fd48a3e
--- /dev/null
+++ b/private/utils/ntbackup/inc/ombkup.h
@@ -0,0 +1,80 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: ombkup.h
+
+ Description: OEM Microsoft version of bkup.h
+
+
+ $Log: J:\ui\logfiles\ombkup.h_v $
+
+ Rev 1.6 24 Nov 1993 19:25:08 GLENN
+Added hardware compression option to backup dialog and config.
+
+ Rev 1.5 04 Oct 1992 19:48:24 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.4 19 Aug 1992 14:21:50 CHUCKB
+Added id's for new controls.
+
+ Rev 1.3 10 Aug 1992 14:18:20 CHUCKB
+Added id's for new fields in NT utility.
+
+ Rev 1.2 24 Mar 1992 16:35:38 DAVEV
+Minor changes
+
+
+ Rev 1.1 20 Mar 1992 12:41:46 DAVEV
+Changes for OEM_MSOFT product alternate functionality
+
+ Rev 1.0 18 Mar 1992 14:39:56 DAVEV
+Initial revision.
+
+ Rev 1.0 18 Mar 1992 14:37:50 DAVEV
+Initial revision.
+
+*******************************************************************************/
+
+#ifndef BKUP_H
+#define BKUP_H
+
+#define IDM_BACKUPSET 228
+
+#define IDD_BKUP_INFO_TITLE 101
+#define IDD_BKUP_OK_BUTTON 102
+#define IDD_BKUP_SCROLLBAR 103
+#define IDD_BKUP_CANCEL_BUTTON 104
+#define IDD_BKUP_DESCRIPTION 106
+#define IDD_BKUP_HELP_BUTTON 107
+#define IDD_BKUP_APPEND 108
+#define IDD_BKUP_REPLACE 109
+#define IDD_BKUP_NEXT_BUTTON 110
+#define IDD_BKUP_DRIVE_NAME 111
+#define IDD_BKUP_AUTO_VERIFY 112
+#define IDD_BKUP_TAPE_NAME 113
+//#define IDD_BKUP_PASSWORD 114
+#define IDD_BKUP_RESTRICT_ACCESS 115 //DLGDVC
+#define IDD_BKUP_CREATION_DATE 116
+#define IDD_BKUP_OWNER 117
+#define IDD_BKUP_REGISTRY 118
+#define IDD_XCHG_BKUP_METHOD 215
+#define IDD_BKUP_METHOD 216
+#define IDD_BKUP_TAPE_TEXT 217
+#define IDD_BKUP_TAPE_NAME_TEXT 218
+#define IDD_BKUP_CURRENT_TAPE_NAME 219
+#define IDD_BKUP_LOG_FILENAME 220 //DLGDVC
+#define IDD_BKUP_LOG_BROWSE 221 //DLGDVC
+/* The following radio button ids MUST BE CONSECUTIVE ! */
+#define IDD_BKUP_LOG_FULL 222 //DLGDVC
+#define IDD_BKUP_LOG_SUMMARY 223 //DLGDVC
+#define IDD_BKUP_LOG_NONE 224 //DLGDVC
+
+#define IDD_BKUP_HARDCOMP 242
+#define IDD_BKUP_DRIVE_NAME_TEXT 243
+#define IDD_BKUP_DESC_TEXT 244
+#define IDD_BKUP_TYPE_TEXT 245
+#define IDD_BKUP_XCHG_NAME_TEXT 246
+#define IDD_BKUP_XCHG_NAME 247
+
+#endif
diff --git a/private/utils/ntbackup/inc/omevent.h b/private/utils/ntbackup/inc/omevent.h
new file mode 100644
index 000000000..fc6a86c1c
--- /dev/null
+++ b/private/utils/ntbackup/inc/omevent.h
@@ -0,0 +1,39 @@
+
+void OMEVENT_LogEvent ( DWORD dwEventId, //id of event message
+ WORD wEventType, //type of event
+ INT cStrings, //number of replement strings
+ ... ); //replacement strings
+
+void OMEVENT_LogBeginBackup (
+ CHAR_PTR szDrive, //Drive name
+ INT16 verify, //VERIFY ON or OFF
+ INT16 mode, //APPEND or REPLACE
+ INT16 type ); //NORMAL, COPY, etc.
+void OMEVENT_LogEndBackup (
+ BOOL bError );//Did an error occur?
+void OMEVENT_LogBeginRestore (
+ CHAR_PTR szDrive, //Drive name
+ INT16 verify ); //VERIFY ON or OFF
+void OMEVENT_LogEndRestore (
+ BOOL bError );//Did an error occur?
+void OMEVENT_LogBeginErase ( VOID );
+void OMEVENT_LogEndErase (
+ BOOL bError );//Did an error occur?
+void OMEVENT_LogBeginRetension ( VOID );
+void OMEVENT_LogEndRetension (
+ BOOL bError );//Did an error occur?
+void OMEVENT_LogBeginVerify ( LPSTR );
+void OMEVENT_LogEndVerify ( LPSTR,
+ BOOL bError );//Did an error occur?
+void OMEVENT_LogEMSError (
+ CHAR_PTR function_name,
+ INT status,
+ CHAR_PTR additional_info ); //Did an error occur?
+void OMEVENT_LogEMSErrorText (
+ CHAR_PTR function_name,
+ CHAR_PTR status,
+ CHAR_PTR additional_info ); //Did an error occur?
+void OMEVENT_LogEMSToFewDbError (
+ INT num_found,
+ INT num_needed ) ;
+
diff --git a/private/utils/ntbackup/inc/omhelpid.h b/private/utils/ntbackup/inc/omhelpid.h
new file mode 100644
index 000000000..75aa947ff
--- /dev/null
+++ b/private/utils/ntbackup/inc/omhelpid.h
@@ -0,0 +1,339 @@
+/****************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+ Name: OMHELPIDS.H
+
+ Description: This header file contains helpids for the
+ help manager.
+
+ $Log: G:/UI/LOGFILES/OMHELPID.H_V $
+
+ Rev 1.13 26 Mar 1993 13:36:06 DARRYLP
+New IDS for Font, Format.
+
+ Rev 1.12 25 Mar 1993 15:49:38 ROBG
+Added IDH_MENU_OPERATIONSFORMAT to list to support the help
+with the new menu option.
+
+ Rev 1.9 12 Mar 1993 13:48:32 ROBG
+Changes to support font, split catalog, and drive tape windows.
+
+ Rev 1.7 22 Oct 1992 09:39:22 GLENN
+Found another incomplete ID change.
+
+ Rev 1.6 20 Oct 1992 16:54:00 GLENN
+You gotta change ribbon to toolbar in both places, Steve.
+
+ Rev 1.5 05 Oct 1992 10:36:08 STEVEN
+additions from peggy
+
+ Rev 1.4 04 Oct 1992 19:48:26 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.3 03 Sep 1992 16:15:52 ROBG
+Added OPERATIONSCATALOG for Peggy at Microsoft.
+
+ Rev 1.2 11 Jun 1992 11:00:04 GLENN
+Removed MEMORYTRACE references.
+
+ Rev 1.1 10 Jun 1992 16:12:48 GLENN
+Updated according to NT SPEC.
+
+ Rev 1.0 03 Mar 1992 12:25:28 DAVEV
+Initial revision.
+****************************************************************************/
+
+#ifndef helpids_h // Do not allow multiple inclusions of this file
+#define helpids_h
+
+
+#define IDH_MINIMIZE_ICON 1 // Minimize button on frame
+#define IDH_MAXIMIZE_ICON 2 // Maximize button on frame
+#define IDH_SYSTEM_MENU 3 // System menu frame
+#define IDH_TITLE_BAR 4 // Title bar on frame
+#define IDH_SIZING_BORDER 5 // Frame Border
+#define IDH_FRAME_WINDOW 6 // Frame Window
+#define IDH_STATUSLINE 7 // Status Bar
+#define IDH_CLIENT_WINDOW 8 // MDI Client Window
+#define IDH_DOC_WINDOW 9 // MDI Document Window
+#define IDH_RIBBON_WINDOW 10 // Tool Bar
+
+// MDI DOCUMENTS
+
+#define IDH_MDI_DISKS 20
+#define IDH_MDI_TAPES 21
+#define IDH_MDI_DISKTREE 22
+#define IDH_MDI_TAPETREE 23
+
+// These processed on a "listbox" control.
+// begin
+
+#define IDH_LB_DISKTREELEFT 50
+#define IDH_LB_DISKTREERIGHT 51
+#define IDH_LB_TAPETREELEFT 52
+#define IDH_LB_TAPETREERIGHT 53
+
+// end
+
+#define IDH_MENU_OPERATIONSBACKUP 100
+#define IDH_MENU_OPERATIONSRESTORE 102
+#define IDH_MENU_OPERATIONSERASE 103
+#define IDH_MENU_OPERATIONSRETENSION 104
+#define IDH_MENU_OPERATIONSEJECT 105
+#define IDH_MENU_OPERATIONSHARDWARE 106
+#define IDH_MENU_OPERATIONSEXIT 107
+#define IDH_MENU_OPERATIONSCATALOG 108
+#define IDH_MENU_OPERATIONSFORMAT 109
+#ifdef OEM_EMS
+#define IDH_MENU_OPERATIONSEXCHANGE 110
+#endif
+
+#define IDH_MENU_TREEEXPANDONE 200
+#define IDH_MENU_TREEEXPANDBRANCH 201
+#define IDH_MENU_TREEEXPANDALL 202
+#define IDH_MENU_TREECOLLAPSEBRANCH 203
+
+#define IDH_MENU_VIEWTREEANDDIR 300
+#define IDH_MENU_VIEWTREEONLY 301
+#define IDH_MENU_VIEWDIRONLY 302
+#define IDH_MENU_VIEWNAMEONLY 303
+#define IDH_MENU_VIEWALLFILEDETAILS 304
+#define IDH_MENU_VIEWSTATUS 305
+#define IDH_MENU_VIEWTOOLBAR 306
+#define IDH_MENU_VIEWFONT 2410 // Was 307. Microsoft wants the dialog
+#define IDH_MENU_VIEWSPLIT 308
+
+#define IDH_MENU_SELECTCHECK 400
+#define IDH_MENU_SELECTUNCHECK 401
+
+#define IDH_MENU_WINDOWSCASCADE 500
+#define IDH_MENU_WINDOWSTILE 501
+#define IDH_MENU_WINDOWSARRANGEICONS 502
+#define IDH_MENU_WINDOWSREFRESH 503
+#define IDH_MENU_WINDOWSCLOSEALL 504
+
+#define IDH_MENU_HELPINDEX 900
+#define IDH_MENU_HELPKEYBOARD 901
+#define IDH_MENU_HELPSEARCH 902
+#define IDH_MENU_HELPCOMMANDS 903
+#define IDH_MENU_HELPPROCEDURES 904
+#define IDH_MENU_HELPUSINGHELP 905
+#define IDH_MENU_HELPABOUTNOSTRADOMUS 906
+
+#define IDH_MENU_WINDOWSNAMES 505 // Generic for 1. drives and 2. tapes
+#define IDH_SYSMENU 800 // generic for move, restore, ...
+
+#define IDH_DB_BACKUPSET 3000 // Backup setup
+#define IDH_DB_RESTORESET 3010 // Restore setup
+#define IDH_DB_ERASE 3020 // Erase
+#define IDH_DB_TENSION 2030 // Retension
+#define IDH_DB_STATUS 2040 // Runtime status for BU and RS
+#define IDH_DB_INSERTTAPE 2050 // Insert the specified tape'
+#define IDH_DB_INSERTNEXTTAPE 2051 // Insert the next tape in seq.
+#define IDH_DB_ABORT 2060 // Tape operation aborted
+#define IDH_DB_TAPEREWOUND 2070 // Tape is rewound
+#define IDH_DB_CATNOTAVAILABLE 2080 // Catalog not available
+#define IDH_DB_HARDWARESETUP 2090 // Hardware config.
+#define IDH_DB_VIEWFONT 2410 // Font dialog.
+#define IDH_DB_FORMAT 2415 // Font dialog.
+#define IDH_DB_BATCHHELP 2420 // batch command help
+
+#ifdef OEM_EMS
+#define IDH_DB_XCHG_BACKUPSET 3001 // Exchange Backup set
+#define IDH_DB_XCHG_RESTORESET 3011 // Exchange Restore set
+#define IDH_DB_XCHG_CONNECT 2430 // Exchange Connect dialog
+#define IDH_DB_XCHG_BROWSE 2431 // Exchange connect browse
+#endif
+
+
+// THE FOLLOWING HELP IDs ARE NOT USED IN THE MICROSOFT NT BACKUP.EXE
+// IGNORE THESE.
+
+#define IDH_MDI_MACROS 23
+#define IDH_MDI_JOBS 24
+#define IDH_MDI_SERVERS 27
+#define IDH_MDI_LOGFILES 28
+#define IDH_MDI_DEBUG 29
+#define IDH_MDI_SEARCH 30
+
+#define IDH_LB_SERVERLEFT 54
+#define IDH_LB_SERVERRIGHT 55
+
+#define IDH_DB_ABOUT 2000
+#define IDH_DB_SELECTADVANCED 2010
+#define IDH_DB_SELECTSAVE 2020
+#define IDH_DB_SELECTUSE 2030
+#define IDH_DB_SELECTDELETE 2040
+#define IDH_DB_ADVRESTORE 2050
+#define IDH_DB_JOBEDIT 2060
+#define IDH_DB_JOBNEW 2070
+#define IDH_DB_JOBMAINTENANCE 2080
+#define IDH_DB_JOBOPTS 2090
+#define IDH_DB_JOBSCHEDULE 2100
+#define IDH_DB_SCHEDOPTS 2110
+#define IDH_DB_SETTINGSOPTIONS 2120
+#define IDH_DB_SETTINGSBACKUP 2130
+#define IDH_DB_SETTINGSRESTORE 2140
+#define IDH_DB_SETTINGSLOGGING 2150
+#define IDH_DB_SETTINGSNETWORK 2160
+#define IDH_DB_SETTINGSCATALOG 2170
+#define IDH_DB_SETTINGSHARDWARE 2180
+#define IDH_DB_SETTINGSDEBUG 2190
+#define IDH_DB_LOGINPSWD 2200
+#define IDH_DB_SEARCHTAPE 2210
+#define IDH_DB_PRINTERSETUP 2220
+#define IDH_DB_PRINT 2230
+#define IDH_DB_CATMAINT 2240
+#define IDH_DB_CATTAPE 2250
+#define IDH_DB_TAPEPSWD 2260
+#define IDH_DB_LANTAPEPSWD 2270
+#define IDH_DB_JOBPROGRAMITEM 2280
+#define IDH_DB_VERIFYSET 2310
+#define IDH_DB_REENTERPASSWORD 2320
+#define IDH_DB_SKIPOPEN 2330
+#define IDH_DB_FILEREPLACE 2340
+#define IDH_DB_NEXTSET 2380
+#define IDH_DB_PWDBPASSWORD 2390
+#define IDH_DB_TRANSFER 2400
+
+// Defines for the three topics for the launcher.
+
+#define IDH_LAUNCHMAINSCREEN 2460
+#define IDH_LAUNCHRUNDELAY 2470
+#define IDH_LAUNCHSCHEDDELAY 2480
+
+
+//
+// THESE ARE THE OLD STYLE DEFINES -- THEY SHOULD HAVE STARTED WITH IDH
+//
+
+
+#define HELPID_MINIMIZE_ICON IDH_MINIMIZE_ICON
+#define HELPID_MAXIMIZE_ICON IDH_MAXIMIZE_ICON
+#define HELPID_SYSTEM_MENU IDH_SYSTEM_MENU
+#define HELPID_TITLE_BAR IDH_TITLE_BAR
+#define HELPID_SIZING_BORDER IDH_SIZING_BORDER
+#define HELPID_FRAME_WINDOW IDH_FRAME_WINDOW
+#define HELPID_STATUSLINE IDH_STATUSLINE
+#define HELPID_CLIENT_WINDOW IDH_CLIENT_WINDOW
+#define HELPID_DOC_WINDOW IDH_DOC_WINDOW
+#define HELPID_RIBBON_WINDOW IDH_RIBBON_WINDOW
+
+#define HELPID_DISKS IDH_MDI_DISKS
+#define HELPID_TAPES IDH_MDI_TAPES
+#define HELPID_MACROS IDH_MDI_MACROS
+#define HELPID_JOBS IDH_MDI_JOBS
+#define HELPID_DISKTREE IDH_MDI_DISKTREE
+#define HELPID_TAPETREE IDH_MDI_TAPETREE
+#define HELPID_SERVERS IDH_MDI_SERVERS
+#define HELPID_LOGFILES IDH_MDI_LOGFILES
+#define HELPID_DEBUG IDH_MDI_DEBUG
+#define HELPID_SEARCH IDH_MDI_SEARCH
+
+// These processed on a "listbox" control.
+// begin
+
+#define HELPID_DISKTREELEFT IDH_LB_DISKTREELEFT
+#define HELPID_DISKTREERIGHT IDH_LB_DISKTREERIGHT
+#define HELPID_TAPETREELEFT IDH_LB_TAPETREELEFT
+#define HELPID_TAPETREERIGHT IDH_LB_TAPETREERIGHT
+#define HELPID_SERVERLEFT IDH_LB_SERVERLEFT
+#define HELPID_SERVERRIGHT IDH_LB_SERVERRIGHT
+
+// end
+
+#define HELPID_OPERATIONSBACKUP IDH_MENU_OPERATIONSBACKUP
+#define HELPID_OPERATIONSRESTORE IDH_MENU_OPERATIONSRESTORE
+#define HELPID_OPERATIONSCATALOG IDH_MENU_OPERATIONSCATALOG
+#define HELPID_OPERATIONSERASE IDH_MENU_OPERATIONSERASE
+#define HELPID_OPERATIONSRETENSION IDH_MENU_OPERATIONSRETENSION
+#define HELPID_OPERATIONSEJECT IDH_MENU_OPERATIONSEJECT
+#define HELPID_OPERATIONSHARDWARE IDH_MENU_OPERATIONSHARDWARE
+#define HELPID_OPERATIONSEXIT IDH_MENU_OPERATIONSEXIT
+#define HELPID_OPERATIONSFORMAT IDH_MENU_OPERATIONSFORMAT
+#ifdef OEM_EMS
+#define HELPID_OPERATIONSEXCHANGE IDH_MENU_OPERATIONSEXCHANGE
+#endif
+
+#define HELPID_TREEEXPANDONE IDH_MENU_TREEEXPANDONE
+#define HELPID_TREEEXPANDBRANCH IDH_MENU_TREEEXPANDBRANCH
+#define HELPID_TREEEXPANDALL IDH_MENU_TREEEXPANDALL
+#define HELPID_TREECOLLAPSEBRANCH IDH_MENU_TREECOLLAPSEBRANCH
+
+#define HELPID_VIEWTREEANDDIR IDH_MENU_VIEWTREEANDDIR
+#define HELPID_VIEWTREEONLY IDH_MENU_VIEWTREEONLY
+#define HELPID_VIEWDIRONLY IDH_MENU_VIEWDIRONLY
+#define HELPID_VIEWNAMEONLY IDH_MENU_VIEWNAMEONLY
+#define HELPID_VIEWALLFILEDETAILS IDH_MENU_VIEWALLFILEDETAILS
+#define HELPID_VIEWSTATUS IDH_MENU_VIEWSTATUS
+#define HELPID_VIEWURIBBON IDH_MENU_VIEWTOOLBAR
+#define HELPID_VIEWFONTS IDH_MENU_VIEWFONT
+#define HELPID_VIEWSPLIT IDH_MENU_VIEWSPLIT
+
+#define HELPID_SELECTCHECK IDH_MENU_SELECTCHECK
+#define HELPID_SELECTUNCHECK IDH_MENU_SELECTUNCHECK
+
+#define HELPID_WINDOWSCASCADE IDH_MENU_WINDOWSCASCADE
+#define HELPID_WINDOWSTILE IDH_MENU_WINDOWSTILE
+#define HELPID_WINDOWSARRANGEICONS IDH_MENU_WINDOWSARRANGEICONS
+#define HELPID_WINDOWSREFRESH IDH_MENU_WINDOWSREFRESH
+#define HELPID_WINDOWSCLOSEALL IDH_MENU_WINDOWSCLOSEALL
+
+#define HELPID_HELPINDEX IDH_MENU_HELPINDEX
+#define HELPID_HELPKEYBOARD IDH_MENU_HELPKEYBOARD
+#define HELPID_HELPSEARCH IDH_MENU_HELPSEARCH
+#define HELPID_HELPCOMMANDS IDH_MENU_HELPCOMMANDS
+#define HELPID_HELPPROCEDURES IDH_MENU_HELPPROCEDURES
+#define HELPID_HELPUSINGHELP IDH_MENU_HELPUSINGHELP
+#define HELPID_HELPABOUTNOSTRADOMUS IDH_MENU_HELPABOUTNOSTRADOMUS
+
+#define HELPID_DIALOGABOUT IDH_DB_ABOUT
+#define HELPID_DIALOGSELECTADVANCED IDH_DB_SELECTADVANCED
+#define HELPID_DIALOGSELECTSAVE IDH_DB_SELECTSAVE
+#define HELPID_DIALOGSELECTUSE IDH_DB_SELECTUSE
+#define HELPID_DIALOGSELECTDELETE IDH_DB_SELECTDELETE
+#define HELPID_DIALOGADVRESTORE IDH_DB_ADVRESTORE
+#define HELPID_DIALOGJOBEDIT IDH_DB_JOBEDIT
+#define HELPID_DIALOGJOBNEW IDH_DB_JOBNEW
+#define HELPID_DIALOGJOBMAINTENANCE IDH_DB_JOBMAINTENANCE
+#define HELPID_DIALOGJOBOPTS IDH_DB_JOBOPTS
+#define HELPID_DIALOGJOBSCHEDULE IDH_DB_JOBSCHEDULE
+#define HELPID_DIALOGSCHEDOPTS IDH_DB_SCHEDOPTS
+#define HELPID_DIALOGSETTINGSOPTIONS IDH_DB_SETTINGSOPTIONS
+#define HELPID_DIALOGSETTINGSBACKUP IDH_DB_SETTINGSBACKUP
+#define HELPID_DIALOGSETTINGSRESTORE IDH_DB_SETTINGSRESTORE
+#define HELPID_DIALOGSETTINGSLOGGING IDH_DB_SETTINGSLOGGING
+#define HELPID_DIALOGSETTINGSNETWORK IDH_DB_SETTINGSNETWORK
+#define HELPID_DIALOGSETTINGSCATALOG IDH_DB_SETTINGSCATALOG
+#define HELPID_DIALOGSETTINGSHARDWARE IDH_DB_SETTINGSHARDWARE
+#define HELPID_DIALOGSETTINGSDEBUG IDH_DB_SETTINGSDEBUG
+#define HELPID_DIALOGLOGINPSWD IDH_DB_LOGINPSWD
+#define HELPID_DIALOGSEARCHTAPE IDH_DB_SEARCHTAPE
+#define HELPID_DIALOGPRINTERSETUP IDH_DB_PRINTERSETUP
+#define HELPID_DIALOGPRINT IDH_DB_PRINT
+#define HELPID_DIALOGCATMAINT IDH_DB_CATMAINT
+#define HELPID_DIALOGCATTAPE IDH_DB_CATTAPE
+#define HELPID_DIALOGTAPEPSWD IDH_DB_TAPEPSWD
+#define HELPID_DIALOGLANTAPEPSWD IDH_DB_LANTAPEPSWD
+#define HELPID_DIALOGJOBPROGRAMITEM IDH_DB_JOBPROGRAMITEM
+#define HELPID_DIALOGBACKUPSET IDH_DB_BACKUPSET
+#define HELPID_DIALOGRESTORESET IDH_DB_RESTORESET
+#define HELPID_DIALOGVERIFYSET IDH_DB_VERIFYSET
+#define HELPID_DIALOGREENTERPASSWORD IDH_DB_REENTERPASSWORD
+#define HELPID_DIALOGSKIPOPEN IDH_DB_SKIPOPEN
+#define HELPID_DIALOGFILEREPLACE IDH_DB_FILEREPLACE
+#define HELPID_DIALOGERASE IDH_DB_ERASE
+#define HELPID_DIALOGRUNTIME IDH_DB_STATUS
+#define HELPID_DIALOGTENSION IDH_DB_TENSION
+#define HELPID_DIALOGNEXTSET IDH_DB_NEXTSET
+#define HELPID_DIALOGPWDBPASSWORD IDH_DB_PWDBPASSWORD
+#define HELPID_DIALOGTRANSFER IDH_DB_TRANSFER
+#define HELPID_DIALOGFORMAT IDH_DB_FORMAT
+
+// Defines for the three topics for the launcher.
+
+#define HELPID_LAUNCHMAINSCREEN IDH_LAUNCHMAINSCREEN
+#define HELPID_LAUNCHRUNDELAY IDH_LAUNCHRUNDELAY
+#define HELPID_LAUNCHSCHEDDELAY IDH_LAUNCHSCHEDDELAY
+
+#endif
diff --git a/private/utils/ntbackup/inc/ommenus.h b/private/utils/ntbackup/inc/ommenus.h
new file mode 100644
index 000000000..5e4b5e8d4
--- /dev/null
+++ b/private/utils/ntbackup/inc/ommenus.h
@@ -0,0 +1,105 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+DAVEV
+
+ Name: ommenus.h
+
+ Description: This file contains the MENU IDs for the OEM Microsoft
+ version of the Maynstream GUI project.
+
+ $Log: G:/UI/LOGFILES/OMMENUS.H_V $
+
+ Rev 1.6 27 Apr 1993 11:49:36 GLENN
+Added SORT defines to prevent compiler error in VLM and DOCPROC.
+
+ Rev 1.5 10 Mar 1993 13:49:18 CARLS
+Changes for Format tape
+
+ Rev 1.4 04 Oct 1992 19:48:28 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.3 20 Aug 1992 08:58:10 GLENN
+Added operations catalog support.
+
+ Rev 1.2 10 Jun 1992 16:12:36 GLENN
+Updated according to NT SPEC.
+
+ Rev 1.1 30 Apr 1992 14:40:50 DAVEV
+OEM_MSOFT: Fix View-All File Details
+
+ Rev 1.0 03 Mar 1992 12:25:30 DAVEV
+Initial revision.
+
+******************************************************************************/
+
+#ifndef MENUS_H_INCL // Do not allow multiple inclusions of this file
+#define MENUS_H_INCL
+
+
+#define WINDOWSMENUPOSITION 4 // position of Nostradamus window menu.
+#define JOBSMENUPOSITION 5 // position of the jobs menu
+#define JOBSMENUSEPARATORPOS 1 // position of the jobs menu job names separator
+
+// MENU ID RANGES
+
+#define MM_ID_MIN 1000
+#define MM_ID_MAX 2999
+
+#define IDM_WINDOWSFIRSTCHILD 2000 // menu ID of the first MDI Child
+
+// MENU ID's
+
+#define IDRM_MAINMENU ID(1)
+
+
+#define IDM_OPERATIONSBACKUP 1001
+#define IDM_OPERATIONSRESTORE 1002
+#define IDM_OPERATIONSCATALOG 1003
+#define IDM_OPERATIONSERASE 1004
+#define IDM_OPERATIONSRETENSION 1005
+#define IDM_OPERATIONSEJECT 1006
+#define IDM_OPERATIONSHARDWARE 1007
+#define IDM_OPERATIONSEXIT 1008
+#define IDM_OPERATIONSFORMAT 1009
+#define IDM_OPERATIONSEXCHANGE 1010
+
+#define IDM_TREEEXPANDONE 1020
+#define IDM_TREEEXPANDBRANCH 1021
+#define IDM_TREEEXPANDALL 1022
+#define IDM_TREECOLLAPSEBRANCH 1023
+
+#define IDM_VIEWTREEANDDIR 1030
+#define IDM_VIEWTREEONLY 1031
+#define IDM_VIEWDIRONLY 1032
+#define IDM_VIEWNAMEONLY 1033
+#define IDM_VIEWALLFILEDETAILS 1034
+#define IDM_VIEWSTATUS 1035
+#define IDM_VIEWURIBBON 1036
+#define IDM_VIEWFONT 1037
+#define IDM_VIEWSPLIT 1038
+#define IDM_VIEWSORTNAME 1039
+#define IDM_VIEWSORTTYPE 1040
+#define IDM_VIEWSORTSIZE 1041
+#define IDM_VIEWSORTDATE 1042
+
+#define IDM_SELECTCHECK 1050
+#define IDM_SELECTUNCHECK 1051
+
+#define IDM_WINDOWSCASCADE 1080
+#define IDM_WINDOWSTILE 1081
+#define IDM_WINDOWSARRANGEICONS 1082
+#define IDM_WINDOWSREFRESH 1083
+#define IDM_WINDOWSCLOSEALL 1084
+
+#define IDM_HELPINDEX 1090
+#define IDM_HELPSEARCH 1091
+#define IDM_HELPKEYBOARD 1092
+#define IDM_HELPCOMMANDS 1093
+#define IDM_HELPPROCEDURES 1094
+#define IDM_HELPUSINGHELP 1095
+#define IDM_HELPABOUTNOSTRADOMUS 1096
+
+
+#endif // MENUS_H_INCL
+
diff --git a/private/utils/ntbackup/inc/omrset.h b/private/utils/ntbackup/inc/omrset.h
new file mode 100644
index 000000000..6a3a74b3f
--- /dev/null
+++ b/private/utils/ntbackup/inc/omrset.h
@@ -0,0 +1,97 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: rset.h
+
+ Description: include file for the rset.dlg dialog
+
+
+ $Log: G:/UI/LOGFILES/OMRSET.H_V $
+
+ Rev 1.5 08 Mar 1993 15:49:22 DARRYLP
+Brought the IDD_RSET_BINDERY define back in.
+
+ Rev 1.4 04 Oct 1992 19:48:30 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.3 03 Sep 1992 10:51:12 CHUCKB
+Added IDD_RSET_REGISTRY.
+
+ Rev 1.2 19 Aug 1992 14:21:44 CHUCKB
+Added id's for new controls.
+
+ Rev 1.1 20 Mar 1992 12:41:48 DAVEV
+Changes for OEM_MSOFT product alternate functionality
+
+ Rev 1.0 18 Mar 1992 14:39:04 DAVEV
+Initial revision.
+
+ Rev 1.0 18 Mar 1992 14:37:44 DAVEV
+alternate OEM_MSOFT dialog header
+
+ Rev 1.1 06 Feb 1992 10:10:52 CARLS
+added ID for security info
+
+ Rev 1.0 20 Nov 1991 19:34:42 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifndef RSET_H
+#define RSET_H
+
+#define IDM_RESTORESET 303
+#define IDM_VERIFYSET 304
+#define IDD_RSET_INFO_TAPE 305
+
+#define IDD_RSET_INFO_TITLE 101
+#define IDD_RSET_NEXT_BUTTON 102
+#define IDD_RSET_TAPE_NAME 103
+#define IDD_RSET_PREV_BUTTON 104
+#define IDD_RSET_DRIVE_BOX 105
+#define IDD_RSET_RESTORE_PATH 110
+#define IDD_RSET_VERIFY_AFTER 106
+#define IDD_RSET_BINDERY 107
+#define IDD_RSET_CANCEL_BUTTON 109
+#define IDD_RSET_DRIVE_TEXT 111
+#define IDD_RSET_SET_TEXT 112
+#define IDD_RSET_PATH_TEXT 113
+#define IDD_RSET_TAPE_NAME_TEXT 114
+#define IDD_RSET_SCROLLBAR 115
+#define IDD_RSET_SET_LINE_1 116
+#define IDD_RSET_SET_LINE_2 117
+#define IDD_RSET_SET_LINE_3 118
+#define IDD_RSET_OK_BUTTON 119
+#define IDD_RSET_SET_INFO 120
+#define IDD_RSET_HELP_BUTTON 121
+#define IDD_RSET_BROWSE_BUTTON 122
+#define IDD_RSET_SECURITY_INFO 123
+#define IDD_RSET_LOG_FILENAME 124
+#define IDD_RSET_LOG_BROWSE 125
+/* Note: the following radio button id's MUST BE CONSECUTIVE! */
+#define IDD_RSET_LOG_FULL 126
+#define IDD_RSET_LOG_SUMMARY 127
+#define IDD_RSET_LOG_NONE 128
+
+#define IDD_RSET_REGISTRY 129
+
+#define IDD_RSET_CREATION_DATE 130
+#define IDD_RSET_OWNERS_NAME 131
+
+/* The following controls are for Exchange backups */
+#define IDD_RSET_DEST_NAME 132
+#define IDD_RSET_DEST_TEXT 133
+
+/* These have to be consecutive */
+#define IDD_RSET_ORG_TEXT 134
+#define IDD_RSET_WIPE_DATA 135
+
+#define IDD_RSET_PRIV_IS 136
+#define IDD_RSET_PUB_IS 137
+#define IDD_RSET_ORG_NAME 138
+#define IDD_RSET_DSA_DEST_NAME 139
+#define IDD_RSET_START_EMS 140
+
+#define IDD_RSET_DS_DEST_TEXT 141
+#endif
diff --git a/private/utils/ntbackup/inc/omstring.h b/private/utils/ntbackup/inc/omstring.h
new file mode 100644
index 000000000..0013bbb2b
--- /dev/null
+++ b/private/utils/ntbackup/inc/omstring.h
@@ -0,0 +1,1033 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+DAVEV
+
+ Name: omstring.h
+
+ Description: This file contains the STRING IDs for the Microsoft OEM
+ GUI project for NT.
+
+ This file was created by copying and modifying
+ STRINGS.H from the standard Maynstream GUI project.
+
+ $Log: G:/UI/LOGFILES/OMSTRING.H_V $
+
+ Rev 1.42 04 Mar 1994 17:36:02 STEVEN
+prompt if disk full
+
+ Rev 1.41 06 Jan 1994 16:12:12 GREGG
+Added extended error reporting string defines.
+
+ Rev 1.40 01 Dec 1993 14:13:36 mikep
+add SQL recognition support to poll drive
+
+ Rev 1.39 26 Oct 1993 18:09:42 BARRY
+Added backupRegistry option
+
+ Rev 1.38 16 Aug 1993 13:47:56 BARRY
+Added new strings to bring Nostradamus to UI tips.
+
+ Rev 1.37 29 Jun 1993 17:34:48 GLENN
+Added new style about box support.
+
+ Rev 1.36 25 May 1993 14:57:08 GLENN
+Added IDS_VLMDRIVESMSG.
+
+ Rev 1.35 21 May 1993 18:13:00 KEVINS
+Added browse strings.
+
+ Rev 1.34 05 May 1993 10:44:40 MIKEP
+cd ..\res
+add message for trying to catalog with full hard drive.
+
+ Rev 1.33 16 Apr 1993 14:33:42 MIKEP
+add tape drive name
+
+ Rev 1.32 16 Apr 1993 09:47:58 MIKEP
+add stings for cataloging
+
+ Rev 1.31 13 Mar 1993 16:26:28 MIKEP
+foreign tape prompt
+
+ Rev 1.30 12 Mar 1993 14:46:50 CARLS
+changes for format tape
+
+ Rev 1.29 10 Mar 1993 12:53:12 CARLS
+Changes to move Format tape to the Operations menu
+
+ Rev 1.28 03 Mar 1993 14:15:14 DARRYLP
+Added read only drive strings.
+
+ Rev 1.27 18 Feb 1993 13:32:20 BURT
+Changes for Cayman
+
+
+ Rev 1.26 09 Feb 1993 09:37:28 chrish
+Added string for abort title during backup and restore operation.
+
+ Rev 1.25 18 Jan 1993 14:46:04 GLENN
+Added Stream Error Reporting Strings and IDs.
+
+ Rev 1.24 06 Jan 1993 15:10:16 chrish
+Added constants for new security strings.
+
+ Rev 1.23 17 Nov 1992 20:02:04 MIKEP
+add unformat display
+
+ Rev 1.22 13 Nov 1992 17:43:46 chrish
+Added some stuff for Tape Security - NT.
+
+ Rev 1.21 15 Oct 1992 13:03:52 DAVEV
+fix problem with batch mode /T option
+
+ Rev 1.20 09 Oct 1992 13:20:48 MIKEP
+add daily copy
+
+ Rev 1.19 04 Oct 1992 19:48:34 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.18 18 Sep 1992 08:15:38 STEVEN
+fix IDs from steve's last change
+
+ Rev 1.17 17 Sep 1992 16:52:38 STEVEN
+added support for daily backup
+
+ Rev 1.16 04 Sep 1992 18:09:44 CHUCKB
+Added new id's, etc., for sales pitch string.
+
+ Rev 1.15 26 Aug 1992 14:58:38 DAVEV
+Event Logging
+
+ Rev 1.14 24 Aug 1992 15:36:10 DAVEV
+string ids for event logging
+
+ Rev 1.13 20 Aug 1992 08:27:36 GLENN
+Added catalog and about box string support.
+
+ Rev 1.12 23 Jun 1992 17:36:34 DAVEV
+added ids from strings.h
+
+ Rev 1.11 11 Jun 1992 13:36:10 STEVEN
+fix define for OMEVENT... to OEMEVENT...
+
+ Rev 1.10 11 Jun 1992 11:00:14 GLENN
+Removed MEMORYTRACE references.
+
+ Rev 1.9 05 Jun 1992 12:49:12 DAVEV
+Added default log file name strings
+
+ Rev 1.8 28 May 1992 11:17:30 DAVEV
+added IDS_OEMEVENT_SOURCE_NAME
+
+ Rev 1.7 15 May 1992 13:37:40 MIKEP
+added conglomerate
+
+ Rev 1.6 11 May 1992 14:27:00 DAVEV
+Batch command line option strings added
+
+ Rev 1.5 23 Apr 1992 10:12:20 DAVEV
+added strings from strings.h
+
+ Rev 1.4 27 Mar 1992 11:57:34 DAVEV
+Added new ids from WinterPark.
+
+ Rev 1.3 25 Mar 1992 17:01:26 chrish
+Added new strings id's from WinterPark strings.h
+
+ Rev 1.2 20 Mar 1992 12:40:54 DAVEV
+Changes for OEM_MSOFT product alternate functionality
+
+ Rev 1.1 11 Mar 1992 17:04:54 DAVEV
+integrated winterpark strings.h changes
+
+ Rev 1.0 03 Mar 1992 12:25:32 DAVEV
+Initial revision.
+
+******************************************************************************/
+
+#ifndef STRINGS_H_INCL // Do not allow multiple inclusions of this file
+#define STRINGS_H_INCL
+
+
+// STRING RESOURCE IDs -- RANGE: 1 - 32000
+
+#define IDS_APPNAME 1
+#define IDS_EXEFILENAME 2
+#define IDS_INIFILENAME 3
+#define IDS_PWDFILENAME 4
+
+#define IDS_CANTOPEN 5
+#define IDS_CANTREAD 6
+#define IDS_CANTCREATE 7
+#define IDS_CANTWRITE 8
+#define IDS_ILLFNM 9
+#define IDS_ADDEXT 10
+#define IDS_CLOSESAVE 11
+#define IDS_CANTFIND 12
+#define IDS_HELPNOTAVAIL 13
+#define IDS_CANTCLOSE 14
+#define IDS_CLIENTTITLE 16
+#define IDS_UNTITLED 17
+#define IDS_STDMODEWARNING 18
+#define IDS_APPVERSION 19
+#define IDS_STARTUPTEXT 20
+#define IDS_COPYRIGHT 21
+#define IDS_COMPANY 22
+#define IDS_APPMSGNAME 23
+#define IDS_APPEXEVER 24
+#define IDS_APPRESVER 25
+#define IDS_APPENGREL 26
+#define IDS_CONGLOMERATE 27
+#define IDS_SALESPITCH 28
+#define IDS_LONGAPPNAME 29
+
+#define IDS_BADUSERDATAPATH 30
+#define IDS_BADCATDATAPATH 31
+
+#define IDS_UNDERSCOREMARKER 32
+#define IDS_FONTHELV 33
+#define IDS_FONTSYSTEM 34
+#define IDS_FONTCOURIER 35
+
+#define IDS_BADRESVER 40
+#define IDS_NORESFILE 41
+
+
+// STATUS LINE TEXT RANGE IS 50 to 99
+
+#define IDS_READY 50 // STATUS LINE text IDs
+#define IDS_INITIALIZING 51
+#define IDS_BACKINGUP 52
+#define IDS_TRANSFERRING 53
+#define IDS_RESTORING 54
+#define IDS_VERIFYING 55
+#define IDS_RETENSIONING 56
+#define IDS_ERASING 57
+#define IDS_CATALOGING 58
+#define IDS_REWINDING 59
+#define IDS_EJECTING 60
+#define IDS_INITFILESYS 61
+#define IDS_INITHARDWARE 62
+#define IDS_DIRSCANNED 63
+#define IDS_CATMAINT 64
+#define IDS_NEXTSETTING 65
+#define IDS_INITCATALOGS 66
+#define IDS_INITUI 67
+#define IDS_FORMATING 68
+
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+//
+// DO NOT EVER CHANGE THE ID NUMBERING BELOW 100.
+// BELOW 100 CONTAINS STRINGS THAT WILL NEVER CHANGE FROM VERSION
+// TO VERSION, THIS IS WHERE ALL VERSION STAMPS ARE KEPT FOR ALL
+// FUTURE RELEASES.
+//
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+// RIBBON TEXT RANGE IS 300 to 399
+
+#define IDS_RIB_BACKUP 300 // RIBBON text IDs
+#define IDS_RIB_RESTORE 301
+#define IDS_RIB_ERASE 302
+#define IDS_RIB_RETENSION 303
+#define IDS_RIB_JOBSTATUS 304
+#define IDS_RIB_CHECK 305
+#define IDS_RIB_UNCHECK 306
+#define IDS_RIB_MODIFIED 307
+#define IDS_RIB_ADVANCED 308
+#define IDS_RIB_UNDO 309
+#define IDS_RIB_INCLUDE 310
+#define IDS_RIB_EXCLUDE 311
+#define IDS_RIB_TRANSFER 312
+#define IDS_RIB_VERIFY 313
+#define IDS_RIB_CATALOG 314
+#define IDS_RIB_SEARCH 315
+#define IDS_RIB_NEXTSET 316
+#define IDS_RIB_EJECT 317
+#define IDS_RIB_REWIND 318
+#define IDS_RIB_EXIT 319
+
+#define IDS_RIB_MEMDEBUG 350
+#define IDS_RIB_STATLINE 351
+
+/* BUTTON TEXT RANGE IS 400 to 410 */
+
+#define IDS_BUT_OK 400
+#define IDS_BUT_CANCEL (IDS_BUT_OK+1)
+#define IDS_BUT_RETRY (IDS_BUT_CANCEL+1)
+#define IDS_BUT_YES (IDS_BUT_RETRY+1)
+#define IDS_BUT_NO (IDS_BUT_YES+1)
+#define IDS_BUT_CONTINUE (IDS_BUT_NO+1)
+#define IDS_BUT_ABORT (IDS_BUT_CONTINUE+1)
+#define IDS_BUT_HELP (IDS_BUT_ABORT+1)
+#define IDS_BUT_DISABLE (IDS_BUT_HELP+1)
+#define IDS_BUT_IGNORE (IDS_BUT_DISABLE+1)
+
+// MENU STRING RANGE is 1000 to 2999
+
+#define IDS_OPERATIONSBACKUP (IDM_OPERATIONSBACKUP)
+#define IDS_OPERATIONSRESTORE (IDM_OPERATIONSRESTORE)
+#define IDS_OPERATIONSCATALOG (IDM_OPERATIONSCATALOG)
+#define IDS_OPERATIONSERASE (IDM_OPERATIONSERASE)
+#define IDS_OPERATIONSRETENSION (IDM_OPERATIONSRETENSION)
+#define IDS_OPERATIONSEJECT (IDM_OPERATIONSEJECT)
+#define IDS_OPERATIONSHARDWARE (IDM_OPERATIONSHARDWARE)
+#define IDS_OPERATIONSEXIT (IDM_OPERATIONSEXIT)
+#define IDS_OPERATIONSFORMAT (IDM_OPERATIONSFORMAT)
+#define IDS_OPERATIONSEXCHANGE (IDM_OPERATIONSEXCHANGE)
+
+#define IDS_TREEEXPANDONE (IDM_TREEEXPANDONE)
+#define IDS_TREEEXPANDBRANCH (IDM_TREEEXPANDBRANCH)
+#define IDS_TREEEXPANDALL (IDM_TREEEXPANDALL)
+#define IDS_TREECOLLAPSEBRANCH (IDM_TREECOLLAPSEBRANCH)
+
+#define IDS_VIEWTREEANDDIR (IDM_VIEWTREEANDDIR)
+#define IDS_VIEWTREEONLY (IDM_VIEWTREEONLY)
+#define IDS_VIEWDIRONLY (IDM_VIEWDIRONLY)
+#define IDS_VIEWALLFILEDETAILS (IDM_VIEWALLFILEDETAILS)
+#define IDS_VIEWSTATUS (IDM_VIEWSTATUS)
+#define IDS_VIEWURIBBON (IDM_VIEWURIBBON)
+#define IDS_VIEWSPLIT (IDM_VIEWSPLIT)
+#define IDS_VIEWFONT (IDM_VIEWFONT)
+
+#define IDS_SELECTCHECK (IDM_SELECTCHECK)
+#define IDS_SELECTUNCHECK (IDM_SELECTUNCHECK)
+#define IDS_SELECTADVANCED (IDM_SELECTADVANCED)
+
+#define IDS_WINDOWSCASCADE (IDM_WINDOWSCASCADE)
+#define IDS_WINDOWSTILE (IDM_WINDOWSTILE)
+#define IDS_WINDOWSREFRESH (IDM_WINDOWSREFRESH)
+#define IDS_WINDOWSCLOSEALL (IDM_WINDOWSCLOSEALL)
+#define IDS_WINDOWSARRANGEICONS (IDM_WINDOWSARRANGEICONS)
+
+#define IDS_HELPINDEX (IDM_HELPINDEX)
+#define IDS_HELPSEARCH (IDM_HELPSEARCH)
+#define IDS_HELPKEYBOARD (IDM_HELPKEYBOARD)
+#define IDS_HELPCOMMANDS (IDM_HELPCOMMANDS)
+#define IDS_HELPPROCEDURES (IDM_HELPPROCEDURES)
+#define IDS_HELPUSINGHELP (IDM_HELPUSINGHELP)
+#define IDS_HELPABOUTNOSTRADOMUS (IDM_HELPABOUTNOSTRADOMUS)
+
+// DEFINES for the RUNTIME DIALOGS
+
+#define IDS_DLGTITLESTART 500
+#define IDS_DLGTITLEJOBSTATBACKUP (IDS_DLGTITLESTART+0)
+#define IDS_DLGTITLEJOBSTATRESTORE (IDS_DLGTITLESTART+1)
+#define IDS_DLGTITLEJOBSTATTRANSFER (IDS_DLGTITLESTART+2)
+#define IDS_DLGTITLEJOBSTATVERIFY (IDS_DLGTITLESTART+3)
+#define IDS_DLGTITLEJOBSTATCATALOG (IDS_DLGTITLESTART+4)
+#define IDS_DLGTITLEJOBSTATTENSION (IDS_DLGTITLESTART+5)
+#define IDS_DLGTITLEJOBSTATERASE (IDS_DLGTITLESTART+6)
+#define IDS_DLGTITLEJOBSTATDELETE (IDS_DLGTITLESTART+7)
+#define IDS_DLGTITLEJOBSTATFORMAT (IDS_DLGTITLESTART+8)
+
+// DEFINES for the HELP MANAGER
+
+#define IDS_HMSTART 510
+#define IDS_HMHELPFILENAME (IDS_HMSTART+0)
+#define IDS_HMKEYWORDKEYS (IDS_HMSTART+1)
+#define IDS_HMKEYWORDCOMMANDS (IDS_HMSTART+2)
+#define IDS_HMKEYWORDPROCS (IDS_HMSTART+3)
+#define IDS_HMUSINGHELPFILENAME (IDS_HMSTART+4)
+#define IDS_HMNOHELPFILE (IDS_HMSTART+5)
+
+// Defines for About
+
+#define IDS_ABOUT_ENHANCED_MODE 520
+#define IDS_ABOUT_STANDARD_MODE (IDS_ABOUT_ENHANCED_MODE+1)
+#define IDS_ABOUT_MEMORY (IDS_ABOUT_ENHANCED_MODE+2)
+#define IDS_ABOUT_MEM_FORMAT (IDS_ABOUT_ENHANCED_MODE+3)
+#define IDS_ABOUT_RESOURCES (IDS_ABOUT_ENHANCED_MODE+4)
+#define IDS_ABOUT_RES_FORMAT (IDS_ABOUT_ENHANCED_MODE+5)
+#define IDS_APPTEXTSTRING (IDS_ABOUT_ENHANCED_MODE+6)
+#define IDS_LICENSEINFOKEY (IDS_ABOUT_ENHANCED_MODE+7)
+#define IDS_CURRENTVERSION (IDS_ABOUT_ENHANCED_MODE+8)
+#define IDS_REGUSER (IDS_ABOUT_ENHANCED_MODE+9)
+#define IDS_REGORGANIZATION (IDS_ABOUT_ENHANCED_MODE+10)
+#define IDS_VERSIONMSG (IDS_ABOUT_ENHANCED_MODE+11)
+#define IDS_DEBUG (IDS_ABOUT_ENHANCED_MODE+12)
+#define IDS_PROCESSORINFOKEY (IDS_ABOUT_ENHANCED_MODE+13)
+#define IDS_PROCESSORIDENTIFIER (IDS_ABOUT_ENHANCED_MODE+14)
+#define IDS_IDENTIFIERIDENTIFIER (IDS_ABOUT_ENHANCED_MODE+15)
+#define IDS_PRODUCTIDINFOKEY (IDS_ABOUT_ENHANCED_MODE+16)
+#define IDS_PRODUCTIDENTIFIER (IDS_ABOUT_ENHANCED_MODE+17)
+
+// defines for launcher
+
+#define IDS_LCHAPPNAME 540
+#define IDS_LCHEXITAPP (IDS_LCHAPPNAME+1)
+#define IDS_LCHDELAYTITLE (IDS_LCHEXITAPP+1)
+#define IDS_LCHEXECUTIONERROR (IDS_LCHDELAYTITLE+1)
+#define IDS_LCHCANNOTEXECUTE (IDS_LCHEXECUTIONERROR+1)
+#define IDS_LCHONHOLD (IDS_LCHCANNOTEXECUTE+1)
+#define IDS_LCHACTIVE (IDS_LCHONHOLD+1)
+#define IDS_LCHTOOMANYCLOCKS (IDS_LCHACTIVE+1)
+#define IDS_LCHRUNNING (IDS_LCHTOOMANYCLOCKS+1)
+#define IDS_LCHABORTED (IDS_LCHRUNNING+1)
+#define IDS_LCHDELAYED (IDS_LCHABORTED+1)
+#define IDS_LCHMISSED (IDS_LCHDELAYED+1)
+#define IDS_LCHSKIPMSG (IDS_LCHMISSED+1)
+
+#define IDS_RESTOREPATHINVALID 560
+#define IDS_DONT_SPECIFY_DRIVE (IDS_RESTOREPATHINVALID+1)
+#define IDS_DONT_SPECIFY_FNAME (IDS_DONT_SPECIFY_DRIVE+1)
+#define IDS_RESTOREEMSSERVERINVALID (IDS_DONT_SPECIFY_FNAME+1)
+#define IDS_RESTOREEMSNOWIPE (IDS_RESTOREEMSSERVERINVALID +1)
+#define IDS_RESTOREEMSWARNING (IDS_RESTOREEMSNOWIPE +1)
+#define IDS_RESTORESTOPEXCHANGE (IDS_RESTOREEMSWARNING +1)
+#define IDS_RESTORESTARTEXCHANGE (IDS_RESTORESTOPEXCHANGE +1)
+#define IDS_STARTEXCHANGE (IDS_RESTORESTARTEXCHANGE +1)
+#define IDS_RESTOREBEGINEXCHANGE (IDS_STARTEXCHANGE+1)
+#define RES_EMS_COMM_FAILURE (IDS_RESTOREBEGINEXCHANGE+1)
+#define RES_EMS_BKU_ACCESS_FAILURE (RES_EMS_COMM_FAILURE+1)
+#define RES_EMS_RST_ACCESS_FAILURE (RES_EMS_BKU_ACCESS_FAILURE+1)
+#define IDS_EMS_MUST_PUB_OR_PRI ( RES_EMS_RST_ACCESS_FAILURE +1)
+#define IDS_EMS_NO_DEST_DRIVE ( IDS_EMS_MUST_PUB_OR_PRI +1)
+#define IDS_EMS_CIRC_LOGS_DS ( IDS_EMS_NO_DEST_DRIVE +1)
+#define IDS_EMS_CIRC_LOGS_IS ( IDS_EMS_CIRC_LOGS_DS +1)
+#define IDS_EMS_NO_INC_DS_BACKUP ( IDS_EMS_CIRC_LOGS_IS +1)
+#define IDS_EMS_NO_INC_IS_BACKUP ( IDS_EMS_NO_INC_DS_BACKUP +1)
+#define IDS_EMS_NOT_RESPONDING_DS ( IDS_EMS_NO_INC_IS_BACKUP +1)
+#define IDS_EMS_NOT_RESPONDING_IS ( IDS_EMS_NOT_RESPONDING_DS +1)
+
+#define IDS_BACKUP_TYPE ( IDS_EMS_NOT_RESPONDING_IS +1)
+#define IDS_WIPE_SPECIFIED ( IDS_BACKUP_TYPE +1)
+#define IDS_RESTOREEMSMUSTWIPE ( IDS_WIPE_SPECIFIED +1)
+#define IDS_EMS_NO_PUBLIC_SERVICE ( IDS_RESTOREEMSMUSTWIPE +1)
+#define IDS_EMS_NO_PRIVATE_SERVICE ( IDS_EMS_NO_PUBLIC_SERVICE +1)
+
+// DEFINES FOR CREATING/EDITING/SCHEDULING JOBS
+
+#define IDS_JOBS_START 600
+
+#define IDS_JOBWARNING (IDS_JOBS_START+0)
+#define IDS_SCHWARNING (IDS_JOBS_START+1)
+#define IDS_JOBAREYOUSURE (IDS_JOBS_START+2)
+#define IDS_SCHAREYOUSURE (IDS_JOBS_START+3)
+#define IDS_NOJOBSELECTED (IDS_JOBS_START+4)
+#define IDS_PLSSELECTJOBRUN (IDS_JOBS_START+5)
+#define IDS_PLSSELECTJOBEDIT (IDS_JOBS_START+6)
+#define IDS_NEWJOBCAPTION (IDS_JOBS_START+7)
+#define IDS_JOBNAMEINUSE (IDS_JOBS_START+8)
+#define IDS_NOMORESPACE (IDS_JOBS_START+9)
+#define IDS_JOBNOTINLIST (IDS_JOBS_START+10)
+#define IDS_JOBNAMENOTVALID (IDS_JOBS_START+11)
+#define IDS_PLSSELECTVALIDJOB (IDS_JOBS_START+12)
+#define IDS_PLSENTERVALIDJOB (IDS_JOBS_START+13)
+#define IDS_EDITJOB (IDS_JOBS_START+14)
+
+// DEFINES FOR JOB OPERATIONS
+
+#define IDS_OPERATIONBACKUP (IDS_JOBS_START+15)
+#define IDS_OPERATIONTRANSFER (IDS_JOBS_START+16)
+
+// DEFINES FOR JOB PROCESSING
+
+#define IDS_JOBPROGMAN 620
+#define IDS_JOBPMGROUP (IDS_JOBPROGMAN+1)
+#define IDS_JOBDEFAULTGROUP (IDS_JOBPMGROUP+1)
+#define IDS_JOBNOPROGMAN (IDS_JOBDEFAULTGROUP+1)
+#define IDS_JOBPROGMANTITLE (IDS_JOBNOPROGMAN+1)
+#define IDS_JOBPROGMANCONFIRM (IDS_JOBPROGMANTITLE+1)
+#define IDS_JOBPROGMANFORMATLINE (IDS_JOBPROGMANCONFIRM+1)
+#define IDS_JOBFILENAME (IDS_JOBPROGMANFORMATLINE+1)
+#define IDS_JOBPROGMANCREATEGROUP (IDS_JOBFILENAME+1)
+#define IDS_JOBBACKUPICONVALUE (IDS_JOBPROGMANCREATEGROUP+1)
+#define IDS_JOBTRANSFERICONVALUE (IDS_JOBBACKUPICONVALUE+1)
+#define IDS_JOBRESTOREICONVALUE (IDS_JOBTRANSFERICONVALUE+1)
+#define IDS_JOBCOMMANDLINE (IDS_JOBRESTOREICONVALUE+1)
+#define IDS_JOBSTARTEDLOGMSG (IDS_JOBCOMMANDLINE+1)
+#define IDS_JOBFINISHEDLOGMSG (IDS_JOBSTARTEDLOGMSG+1)
+#define IDS_JOBNOTFOUNDLOGMSG (IDS_JOBFINISHEDLOGMSG+1)
+#define IDS_JOBMOREJOBS (IDS_JOBNOTFOUNDLOGMSG+1)
+#define IDS_JOBSCHEDULEDJOB (IDS_JOBMOREJOBS+1)
+#define IDS_JOBEXECERROR (IDS_JOBSCHEDULEDJOB+1)
+#define IDS_JOBWRONGMETHOD (IDS_JOBEXECERROR+1)
+
+// defines for automatic jobs (to go with verify.bks and skipped.bks)
+
+#define IDS_VERIFY_JOBNAME 640
+#define IDS_SKIPPED_JOBNAME (IDS_VERIFY_JOBNAME+1)
+
+#ifdef CAYMAN
+#define IDS_FULLBACKUP_JOBNAME (IDS_VERIFY_JOBNAME+2)
+#define IDS_INCBACKUP_JOBNAME (IDS_VERIFY_JOBNAME+3)
+#define IDS_DIFFBACKUP_JOBNAME (IDS_VERIFY_JOBNAME+4)
+#define IDS_FM_SCRIPTNAME (IDS_VERIFY_JOBNAME+5)
+#define IDS_FM_APPEND_JOBNAME (IDS_VERIFY_JOBNAME+6)
+#define IDS_FM_REPLACE_JOBNAME (IDS_VERIFY_JOBNAME+7)
+#endif
+
+// define for selection file not found/valid by job
+
+#define IDS_JOB_SELNOTFOUNDLOGMSG (IDS_SKIPPED_JOBNAME+1)
+#define IDS_JOB_SELNOTVALIDLOGMSG (IDS_JOB_SELNOTFOUNDLOGMSG+1)
+
+// defines for Schedule processing
+
+#define IDS_SCHEXTENSION 650
+#define IDS_SCHFILENAME (IDS_SCHEXTENSION+1)
+#define IDS_SCHCOMMANDLINE (IDS_SCHFILENAME+1)
+#define IDS_SCHUNIQUEKEY (IDS_SCHCOMMANDLINE+1)
+
+// defines for Job/Schedule error messages
+
+#define IDS_JOBIOERR 700
+#define IDS_SCHEDULEIOERR (IDS_JOBIOERR+1)
+#define IDS_JOBISSCHEDULED (IDS_JOBIOERR+2)
+
+// SCHEDULER Errors with days/times/time intervals
+
+#define IDS_SCH_ERRORS_START 710
+
+#define IDS_NODAYCHECKED (IDS_SCH_ERRORS_START+0)
+#define IDS_PLSSELECTDAY (IDS_SCH_ERRORS_START+1)
+#define IDS_NOWEEKCHECKED (IDS_SCH_ERRORS_START+2)
+#define IDS_PLSSELECTWEEK (IDS_SCH_ERRORS_START+3)
+#define IDS_FILENAMENOTVALID (IDS_SCH_ERRORS_START+4)
+#define IDS_INTERVALNOTVALID (IDS_SCH_ERRORS_START+5)
+
+
+// defines for days of the week
+
+#define IDS_MONDAY 750
+#define IDS_TUESDAY (IDS_MONDAY+1)
+#define IDS_WEDNESDAY (IDS_TUESDAY+1)
+#define IDS_THURSDAY (IDS_WEDNESDAY+1)
+#define IDS_FRIDAY (IDS_THURSDAY+1)
+#define IDS_SATURDAY (IDS_FRIDAY+1)
+#define IDS_SUNDAY (IDS_SATURDAY+1)
+#define IDS_DAYOFTHEWEEK (IDS_SUNDAY+1)
+
+// and defines for days of the week hot keys
+
+#define IDS_MONDAYKEY (IDS_DAYOFTHEWEEK+1)
+#define IDS_TUESDAYKEY (IDS_DAYOFTHEWEEK+2)
+#define IDS_WEDNESDAYKEY (IDS_DAYOFTHEWEEK+3)
+#define IDS_THURSDAYKEY (IDS_DAYOFTHEWEEK+4)
+#define IDS_FRIDAYKEY (IDS_DAYOFTHEWEEK+5)
+#define IDS_SATURDAYKEY (IDS_DAYOFTHEWEEK+6)
+#define IDS_SUNDAYKEY (IDS_DAYOFTHEWEEK+7)
+
+// Weeks of the month
+
+#define IDS_FIRSTWEEK (IDS_SUNDAYKEY+1)
+#define IDS_SECONDWEEK (IDS_SUNDAYKEY+2)
+#define IDS_THIRDWEEK (IDS_SUNDAYKEY+3)
+#define IDS_FOURTHWEEK (IDS_SUNDAYKEY+4)
+#define IDS_LASTWEEK (IDS_SUNDAYKEY+5)
+#define IDS_WEEKOFTHEMONTH (IDS_SUNDAYKEY+6)
+
+// Backup set description dialog method text
+
+#define IDS_METHOD_NORMAL 780
+#define IDS_METHOD_COPY (IDS_METHOD_NORMAL+1)
+#define IDS_METHOD_INCREMENTAL (IDS_METHOD_NORMAL+2)
+#define IDS_METHOD_DIFFERENTIAL (IDS_METHOD_NORMAL+3)
+#define IDS_METHOD_DAILY (IDS_METHOD_NORMAL+4)
+
+#define IDS_DEFAULT_TAPE_NAME (IDS_METHOD_NORMAL+5)
+#define IDS_BKUP_PASSWORD_ERROR (IDS_METHOD_NORMAL+6)
+#define IDS_BKUP_SHORT_PASSWORD_ERROR (IDS_METHOD_NORMAL+7)
+#define IDS_BKUP_PASSWORD_ERROR_TITLE (IDS_METHOD_NORMAL+8)
+#define IDS_SET_INFORMATION (IDS_METHOD_NORMAL+9)
+#define IDS_NO_BSET_NAME (IDS_METHOD_NORMAL+10)
+
+// Erase dialog defines
+
+#define IDS_TAPE_PASSWORD_PROTECTED (IDS_METHOD_NORMAL+11)
+
+//
+// Tape Security for NT
+//
+
+#define IDS_BKUP_TAPE_SECURITY (IDS_METHOD_NORMAL+12)
+#define IDS_REST_TAPE_SECURITY (IDS_METHOD_NORMAL+13)
+#define IDS_TAPE_SECURITY_TITLE (IDS_METHOD_NORMAL+14)
+#define IDS_GENERAL_TAPE_SECURITY (IDS_METHOD_NORMAL+15)
+#define IDS_ERASE_TAPE_SECURITY (IDS_METHOD_NORMAL+16)
+#define IDS_XCHG_BKUP_NAME (IDS_METHOD_NORMAL+17)
+
+// Catalog defines
+
+#define IDS_TAPEOUTOFSEQUENCE 800
+#define IDS_ALLTAPES (IDS_TAPEOUTOFSEQUENCE+1)
+#define IDS_ALLFILES (IDS_TAPEOUTOFSEQUENCE+2)
+#define IDS_CATALOGSETNAME (IDS_TAPEOUTOFSEQUENCE+3)
+#define IDS_CANTDELTAPEINDRIVECAPTION (IDS_TAPEOUTOFSEQUENCE+4)
+#define IDS_CANTDELTAPEINDRIVE (IDS_TAPEOUTOFSEQUENCE+5)
+#define IDS_CATINFOTITLE (IDS_TAPEOUTOFSEQUENCE+6)
+#define IDS_NOSETSADDED (IDS_TAPEOUTOFSEQUENCE+7)
+#define IDS_CHANGETOPARTIAL (IDS_TAPEOUTOFSEQUENCE+8)
+#define IDS_REALLYCHANGETOPARTIAL (IDS_TAPEOUTOFSEQUENCE+9)
+#define IDS_DELETEFROMCATALOG (IDS_TAPEOUTOFSEQUENCE+10)
+#define IDS_REALLYDELETEFROMCATALOG (IDS_TAPEOUTOFSEQUENCE+11)
+#define IDS_CATLOADERROR (IDS_TAPEOUTOFSEQUENCE+12)
+#define IDS_BACKUPERRORTITLE (IDS_TAPEOUTOFSEQUENCE+13)
+#define IDS_BACKUPWRONGFAMILY (IDS_TAPEOUTOFSEQUENCE+14)
+#define IDS_DISKFULL_TITLE (IDS_TAPEOUTOFSEQUENCE+15)
+#define IDS_DISKFULL (IDS_TAPEOUTOFSEQUENCE+16)
+#define IDS_DISKFULL_INSTR (IDS_TAPEOUTOFSEQUENCE+17)
+
+
+// Attach-to-server defines
+
+#define IDS_LOGINTOSERVERCAPTION 830
+
+// SELECTION FILE DEFINES
+
+#define IDS_SELECTION_START 831
+
+#define IDS_ALLSELECTIONFILES (IDS_SELECTION_START+0)
+#define IDS_SELECTIONEXTENSION (IDS_SELECTION_START+1)
+#define IDS_NETWORKERRORCAPTION (IDS_SELECTION_START+2)
+#define IDS_MAPPEDFOUND (IDS_SELECTION_START+3)
+#define IDS_SERVERSFOUND (IDS_SELECTION_START+4)
+#define IDS_SERVOLUMES (IDS_SELECTION_START+5)
+#define IDS_MAPPEDDRIVES (IDS_SELECTION_START+6)
+#define IDS_SELECTCAPTION (IDS_SELECTION_START+7)
+#define IDS_NOSERVERSFOUND (IDS_SELECTION_START+8)
+#define IDS_NOFILESSELECTED (IDS_SELECTION_START+9)
+#define IDS_SELECTWARNING (IDS_SELECTION_START+10)
+#define IDS_SELECTAREYOUSURE (IDS_SELECTION_START+11)
+#define IDS_SELECTUSEDBYJOB (IDS_SELECTION_START+12)
+#define IDS_SELECTNAMEINUSE (IDS_SELECTION_START+13)
+#define IDS_SELECTREPLACE (IDS_SELECTION_START+14)
+#define IDS_SELECTNAMENOTVALID (IDS_SELECTION_START+15)
+#define IDS_SELECTENTERVALID (IDS_SELECTION_START+16)
+
+// ADVANCED SELECTION STRINGS
+
+#define IDS_ADVANCEDDATESCAPTION (IDS_SELECTION_START+18)
+#define IDS_ADVANCEDDATESMESSAGE (IDS_SELECTION_START+19)
+#define IDS_ADVNOTAPESCATALOGED (IDS_SELECTION_START+20)
+#define IDS_ADVNOTAPESCATALOGEDCAPTION (IDS_SELECTION_START+21)
+#define IDS_SELECTNOTFOUND (IDS_SELECTION_START+22)
+#define IDS_NONETWORKFOUND (IDS_SELECTION_START+23)
+
+// EXCHANGE SERVER SELECTION STRINGS
+#define IDS_XCHNG_NO_CONNECT (IDS_SELECTION_START+24)
+#define IDS_XCHNG_STOP_RECOVER (IDS_SELECTION_START+25)
+#define IDS_XCHNG_RECOVER_TITLE (IDS_SELECTION_START+26)
+#define IDS_XCHNG_DIR (IDS_SELECTION_START+27)
+#define IDS_XCHNG_INFO_STORE (IDS_SELECTION_START+28)
+#define IDS_XCHNG_NO_SERVICE (IDS_SELECTION_START+29)
+#define IDS_XCHNG_NO_SERVER (IDS_SELECTION_START+30)
+#define IDS_XCHNG_NO_SERVICE_RUNNING (IDS_SELECTION_START+31)
+#define IDS_XCHNG_BKUP_IN_PROG (IDS_SELECTION_START+32)
+#define IDS_XCHNG_NO_SERVICE_ACCESS (IDS_SELECTION_START+33)
+#define IDS_XCHNG_SERVICE_NO_START (IDS_SELECTION_START+34)
+#define IDS_XCHNG_SERVICE_RUNNING (IDS_SELECTION_START+35)
+
+// selection error messages
+
+#define IDS_SELECT_WRITE_ERROR 870
+
+
+// dates/times for advanced backup
+
+#define IDS_NEXTTIMEINVALID 880
+#define IDS_CHECKMINUTES (IDS_NEXTTIMEINVALID+2)
+#define IDS_CHECKHOURS (IDS_NEXTTIMEINVALID+3)
+#define IDS_CHECKAMPM (IDS_NEXTTIMEINVALID+4)
+#define IDS_CHECKDAY (IDS_NEXTTIMEINVALID+5)
+#define IDS_CHECKMONTH (IDS_NEXTTIMEINVALID+6)
+#define IDS_CHECKYEAR (IDS_NEXTTIMEINVALID+7)
+
+#define IDS_ALLBSETS (IDS_NEXTTIMEINVALID+8)
+
+// DEBUG MANAGER STRING DEFINES
+
+#define IDS_DEBUGSTART 890
+#define IDS_DEBUGWARNING (IDS_DEBUGSTART+0)
+#define IDS_DEBUGMESSAGESTOOLOW (IDS_DEBUGSTART+1)
+#define IDS_DEBUGMESSAGESTOOHIGH (IDS_DEBUGSTART+2)
+#define IDS_DEBUGBADFILENAME (IDS_DEBUGSTART+3)
+
+// LOG FILE MANAGER STRING DEFINES
+
+#define IDS_LOGFILESWINDOWNAME 900
+#define IDS_LOGVIEWMINWINDOWNAME (IDS_LOGFILESWINDOWNAME+1)
+#define IDS_LOGHEADERFILENAME (IDS_LOGFILESWINDOWNAME+2)
+#define IDS_LOGHEADERDATE (IDS_LOGFILESWINDOWNAME+3)
+#define IDS_LOGHEADERTIME (IDS_LOGFILESWINDOWNAME+4)
+#define IDS_LOGLOGGEDON (IDS_LOGFILESWINDOWNAME+7)
+#define IDS_LOG_BKS (IDS_LOGFILESWINDOWNAME+8)
+#define IDS_LOG_TKS (IDS_LOGFILESWINDOWNAME+9)
+#define IDS_LOG_RSS (IDS_LOGFILESWINDOWNAME+10)
+#define IDS_LOG_LST (IDS_LOGFILESWINDOWNAME+11)
+#define IDS_LOGSTRINGAT (IDS_LOGFILESWINDOWNAME+12)
+#define IDS_LOGLENGTHOFFILE (IDS_LOGFILESWINDOWNAME+13)
+#define IDS_LOGFILENAMEPREFIX (IDS_LOGFILESWINDOWNAME+14)
+#define IDS_LOGPREFIX (IDS_LOGFILESWINDOWNAME+15)
+#define IDS_LOGEXTENSION (IDS_LOGFILESWINDOWNAME+16)
+#define IDS_LOGSCANNINGFILE (IDS_LOGFILESWINDOWNAME+17)
+#define IDS_LOGMAXLINES (IDS_LOGFILESWINDOWNAME+18)
+#define IDS_LOGMAXSUPPORT (IDS_LOGFILESWINDOWNAME+19)
+
+
+
+// PRINT MANAGER STRINGS
+
+#define IDS_PRTHEADERFORMAT 970
+#define IDS_PRTSESSIONLOGQUESTION (IDS_PRTHEADERFORMAT+1)
+#define IDS_PRTSETUPALREADYOPEN (IDS_PRTHEADERFORMAT+2)
+#define IDS_PRTPMTITLE (IDS_PRTHEADERFORMAT+3)
+#define IDS_PRTDEFAULT (IDS_PRTHEADERFORMAT+4)
+#define IDS_PRTNOLOGSSELECTED (IDS_PRTHEADERFORMAT+5)
+#define IDS_PRTPRINTINGABORTED (IDS_PRTHEADERFORMAT+6)
+#define IDS_PRTPRINTINGCOMPLETE (IDS_PRTHEADERFORMAT+7)
+#define IDS_PRTNUMOFLOGFILES (IDS_PRTHEADERFORMAT+8)
+#define IDS_PRTONELOGFILE (IDS_PRTHEADERFORMAT+9)
+#define IDS_PRTSTARTERROR (IDS_PRTHEADERFORMAT+10)
+#define IDS_PRTDRIVERNOTFOUND (IDS_PRTHEADERFORMAT+11)
+#define IDS_PRTCANNOTACCESSDRIVER (IDS_PRTHEADERFORMAT+12)
+#define IDS_PRTPRINTSTATUS (IDS_PRTHEADERFORMAT+13)
+#define IDS_PRTPRINTCOMPLETE (IDS_PRTHEADERFORMAT+14)
+#define IDS_PRTPRINTERDRIVERERROR (IDS_PRTHEADERFORMAT+15)
+#define IDS_PRTNOPRINTERSAVAILABLE (IDS_PRTHEADERFORMAT+16)
+#define IDS_PRTONSTRING (IDS_PRTHEADERFORMAT+17)
+#define IDS_PRTUNACCESSABLE (IDS_PRTHEADERFORMAT+18)
+
+
+// EJECT STRING DEFINES
+
+#define IDS_EJECTTAPESTART 938
+#define IDS_EJECTTAPEMESSAGE (IDS_EJECTTAPESTART+0)
+#define IDS_EJECTTAPEMANUALEJECT (IDS_EJECTTAPESTART+1)
+#define IDS_EJECTTAPENOTAPE (IDS_EJECTTAPESTART+2)
+#define IDS_EJECTTAPEBIGPROBLEM (IDS_EJECTTAPESTART+3)
+
+// MEMORY MANAGER STRING DEFINES
+
+#define IDS_MEMSTART 957
+#define IDS_MEMNORUNAPP (IDS_MEMSTART+0)
+#define IDS_MEMRETRY (IDS_MEMSTART+1)
+#define IDS_MEMFAILED (IDS_MEMSTART+2)
+
+// Browse string defines
+
+#define IDS_BROWSESTART 10100
+#define IDS_BROWSETITLE (IDS_BROWSESTART+0)
+#define IDS_BROWSELOGFILES (IDS_BROWSESTART+1)
+#define IDS_BROWSELOGFILESEXT (IDS_BROWSESTART+2)
+#define IDS_BROWSEALLFILES (IDS_BROWSESTART+3)
+#define IDS_BROWSEALLFILESEXT (IDS_BROWSESTART+4)
+
+
+
+#define IDS_GENERR_TIMEOUT 10200
+#define IDS_GENERR_EOM (IDS_GENERR_TIMEOUT+1)
+#define IDS_GENERR_BAD_DATA (IDS_GENERR_TIMEOUT+2)
+#define IDS_GENERR_NO_MEDIA (IDS_GENERR_TIMEOUT+3)
+#define IDS_GENERR_ENDSET (IDS_GENERR_TIMEOUT+4)
+#define IDS_GENERR_NO_DATA (IDS_GENERR_TIMEOUT+5)
+#define IDS_GENERR_INVALID_CMD (IDS_GENERR_TIMEOUT+6)
+#define IDS_GENERR_RESET (IDS_GENERR_TIMEOUT+7)
+#define IDS_GENERR_WRT_PROTECT (IDS_GENERR_TIMEOUT+8)
+#define IDS_GENERR_HARDWARE (IDS_GENERR_TIMEOUT+9)
+#define IDS_GENERR_UNDETERMINED (IDS_GENERR_TIMEOUT+10)
+#define IDS_GENERR_EOM_OVERFLOW (IDS_GENERR_TIMEOUT+11)
+#define IDS_GENERR_WRONG_BLOCK_SIZE (IDS_GENERR_TIMEOUT+12)
+#define IDS_GENERR_UNRECOGNIZED_MEDIA (IDS_GENERR_TIMEOUT+13)
+#define IDS_GENFUNC_INIT (IDS_GENERR_TIMEOUT+14)
+#define IDS_GENFUNC_OPEN (IDS_GENERR_TIMEOUT+15)
+#define IDS_GENFUNC_NRCLOSE (IDS_GENERR_TIMEOUT+16)
+#define IDS_GENFUNC_RCLOSE (IDS_GENERR_TIMEOUT+17)
+#define IDS_GENFUNC_READ (IDS_GENERR_TIMEOUT+18)
+#define IDS_GENFUNC_WRITE (IDS_GENERR_TIMEOUT+19)
+#define IDS_GENFUNC_WRITE_ENDSET (IDS_GENERR_TIMEOUT+20)
+#define IDS_GENFUNC_SPACE_FWD_FMK (IDS_GENERR_TIMEOUT+21)
+#define IDS_GENFUNC_SPACE_BKWD_FMK (IDS_GENERR_TIMEOUT+22)
+#define IDS_GENFUNC_SPACE_EOD (IDS_GENERR_TIMEOUT+23)
+#define IDS_GENFUNC_SPACE_FWD_BLK (IDS_GENERR_TIMEOUT+24)
+#define IDS_GENFUNC_SPACE_BKWD_BLK (IDS_GENERR_TIMEOUT+25)
+#define IDS_GENFUNC_ERASE (IDS_GENERR_TIMEOUT+26)
+#define IDS_GENFUNC_REWIND (IDS_GENERR_TIMEOUT+27)
+#define IDS_GENFUNC_REWINDI (IDS_GENERR_TIMEOUT+28)
+#define IDS_GENFUNC_RETEN (IDS_GENERR_TIMEOUT+29)
+#define IDS_GENFUNC_STATUS (IDS_GENERR_TIMEOUT+30)
+#define IDS_GENFUNC_RELEASE (IDS_GENERR_TIMEOUT+31)
+#define IDS_GENFUNC_SEEK (IDS_GENERR_TIMEOUT+32)
+#define IDS_GENFUNC_GETPOS (IDS_GENERR_TIMEOUT+33)
+#define IDS_GENFUNC_MOUNT (IDS_GENERR_TIMEOUT+34)
+#define IDS_GENFUNC_DISMOUNT (IDS_GENERR_TIMEOUT+35)
+#define IDS_GENFUNC_SPECIAL_GET_INFO (IDS_GENERR_TIMEOUT+36)
+#define IDS_GENFUNC_SPECIAL_CHNG_BLK_SIZE (IDS_GENERR_TIMEOUT+37)
+#define IDS_GENFUNC_SPECIAL_SET_COMPRESS (IDS_GENERR_TIMEOUT+38)
+#define IDS_GENFUNC_EJECT (IDS_GENERR_TIMEOUT+39)
+#define IDS_GENERR_DRIVER_FAIL1 (IDS_GENERR_TIMEOUT+40)
+#define IDS_GENERR_DRIVER_FAIL2 (IDS_GENERR_TIMEOUT+41)
+#define IDS_GENERR_DRIVE_FAILED (IDS_GENERR_TIMEOUT+42)
+#define IDS_GENERR_ERROR_REPORTED (IDS_GENERR_TIMEOUT+43)
+#define IDS_GENERR_TITLE (IDS_GENERR_TIMEOUT+44)
+
+
+// VLM string defines
+
+#define IDS_VLMSTART 10960
+#define IDS_VLMDISKTITLE (IDS_VLMSTART+0)
+#define IDS_VLMSERVERTITLE (IDS_VLMSTART+1)
+#define IDS_VLMTAPETITLE (IDS_VLMSTART+2)
+#define IDS_VLMSEARCHTITLE (IDS_VLMSTART+3)
+#define IDS_VLMSRCHOOPS (IDS_VLMSTART+4)
+#define IDS_VLMSRCHNOFILESFOUND (IDS_VLMSTART+5)
+#define IDS_VLMSRCHNOMATCHINGSETS (IDS_VLMSTART+6)
+#define IDS_VLMSRCHTOOMANY (IDS_VLMSTART+7)
+#define IDS_VLMSRCHNOCATALOGS (IDS_VLMSTART+8)
+#define IDS_VLMSRCHBADFILENAME (IDS_VLMSTART+9)
+#define IDS_VLMSRCHINGWHAT (IDS_VLMSTART+10)
+#define IDS_VLMFILESSCANNED (IDS_VLMSTART+11)
+#define IDS_VLMCATWARNING (IDS_VLMSTART+12)
+#define IDS_VLMSETINCOMPLETE (IDS_VLMSTART+13)
+#define IDS_VLMSETPARTIAL (IDS_VLMSTART+14)
+#define IDS_LOOPSOUTOFSEQUENCE (IDS_VLMSTART+15)
+#define IDS_VLMSETIMAGE (IDS_VLMSTART+16)
+#define IDS_VLMCATERROR (IDS_VLMSTART+17)
+#define IDS_VLMCATREADERROR (IDS_VLMSTART+18)
+#define IDS_VLMCATWRITEERROR (IDS_VLMSTART+19)
+#define IDS_VLMCATOPENERROR (IDS_VLMSTART+20)
+#define IDS_VLMCATHANDLEERROR (IDS_VLMSTART+21)
+#define IDS_VLMCATSEEKERROR (IDS_VLMSTART+22)
+#define IDS_VLMCATMEMERROR (IDS_VLMSTART+23)
+#define IDS_VLMCATFULLERROR (IDS_VLMSTART+24)
+#define IDS_VLMCATUNKNOWNERROR (IDS_VLMSTART+25)
+#define IDS_VLMLOGERROR (IDS_VLMSTART+26)
+#define IDS_VLMLOGFULLERROR (IDS_VLMSTART+27)
+#define IDS_VLMDEVICEERRORTITLE (IDS_VLMSTART+28)
+#define IDS_VLMDEVICEERRORMSG (IDS_VLMSTART+29)
+#define IDS_VLMSETNUMBER (IDS_VLMSTART+30)
+#define IDS_VLMNORM (IDS_VLMSTART+31)
+#define IDS_VLMDIFF (IDS_VLMSTART+32)
+#define IDS_VLMINCR (IDS_VLMSTART+33)
+#define IDS_VLMIMAGE (IDS_VLMSTART+34)
+#define IDS_VLMCOPY (IDS_VLMSTART+35)
+#define IDS_VLMSERVERNOTLOGGEDIN (IDS_VLMSTART+36)
+#define IDS_VLMSTARTUPBKS (IDS_VLMSTART+37)
+#define IDS_VLMTAPENAME (IDS_VLMSTART+38)
+#define IDS_VLMAFPTITLE (IDS_VLMSTART+39)
+#define IDS_VLMAFPTEXT (IDS_VLMSTART+40)
+#define IDS_TITLEERASEWARNING (IDS_VLMSTART+41)
+#define IDS_TEXTERASEWARNING (IDS_VLMSTART+42)
+#define IDS_VLMDAILY (IDS_VLMSTART+43)
+#define IDS_VLMONTAPES (IDS_VLMSTART+44)
+#define IDS_VLMONTAPE (IDS_VLMSTART+45)
+#define IDS_VLMFOREIGNTITLE (IDS_VLMSTART+46)
+#define IDS_VLMFOREIGNTEXT (IDS_VLMSTART+47)
+#define IDS_VLMUNFORMATEDTITLE (IDS_VLMSTART+48)
+#define IDS_VLMUNFORMATEDTEXT (IDS_VLMSTART+49)
+#define IDS_VLMDRIVEMSG (IDS_VLMSTART+50)
+#define IDS_VLMGOOFYTITLE (IDS_VLMSTART+51)
+#define IDS_VLMGOOFYTEXT (IDS_VLMSTART+52)
+#define IDS_VLMSETCOMPRESSED (IDS_VLMSTART+53)
+#define IDS_VLMSETENCRYPT (IDS_VLMSTART+54)
+#define IDS_VLMSETFUTURE (IDS_VLMSTART+55)
+#define IDS_VLMSETSMS (IDS_VLMSTART+56)
+#define IDS_VLMECCTEXT (IDS_VLMSTART+57)
+#define IDS_VLMFUTURETEXT (IDS_VLMSTART+58)
+#define IDS_VLMACCESSDENIEDMSG (IDS_VLMSTART+59)
+#define IDS_VLMSQLTEXT (IDS_VLMSTART+60)
+#define IDS_VLMNAME_EXCHANGE (IDS_VLMSTART+61)
+#define IDS_VLMEMSTITLE (IDS_VLMSTART+62)
+#define IDS_VLMEMSMINTITLE IDS_VLMEMSTITLE
+#define IDS_VLMMSG_SELECTVOLSFAILED (IDS_VLMSTART+63)
+#define IDS_VLMMSG_SELECTVOLFAILED (IDS_VLMSTART+64)
+#define IDS_VLMSCANNETWORK (IDS_VLMSTART+65)
+#define IDS_VLMSCANDEVICE (IDS_VLMSTART+66)
+#define IDS_VLMSCANSTATUS (IDS_VLMSTART+67)
+#define IDS_VLMMSG_SCANCANCEL (IDS_VLMSTART+68)
+#define IDS_VLMSCANEXPAND (IDS_VLMSTART+69)
+#define IDS_VLMSCANSELECT (IDS_VLMSTART+70)
+#define IDS_VLMMSG_SELECTNOVOLS (IDS_VLMSTART+71)
+
+
+/* RES_ strings start at 3000 (eng_msg.h) */
+/* 3500 (eng_err.h) */
+/* 3800 (eng_dbug.h) */
+
+/* MessageBox titles */
+
+#define IDS_MSGTITLE_VERIFY 4000
+#define IDS_MSGTITLE_INSERT (IDS_MSGTITLE_VERIFY + 1)
+#define IDS_MSGTITLE_REPLACE (IDS_MSGTITLE_INSERT + 1)
+#define IDS_MSGTITLE_APPEND (IDS_MSGTITLE_REPLACE + 1)
+#define IDS_MSGTITLE_INUSE (IDS_MSGTITLE_APPEND + 1)
+#define IDS_MSGTITLE_CONTINUE (IDS_MSGTITLE_INUSE + 1)
+#define IDS_MSGTITLE_COPY (IDS_MSGTITLE_CONTINUE + 1)
+#define IDS_MSGTITLE_ERASE (IDS_MSGTITLE_COPY + 1)
+#define IDS_MSGTITLE_CORRUPT (IDS_MSGTITLE_ERASE + 1)
+#define IDS_MSGTITLE_RESTORE (IDS_MSGTITLE_CORRUPT + 1)
+#define IDS_MSGTITLE_MACNAMES (IDS_MSGTITLE_RESTORE + 1)
+#define IDS_MSGTITLE_BINDFILES (IDS_MSGTITLE_MACNAMES + 1)
+#define IDS_MSGTITLE_SECURITY (IDS_MSGTITLE_BINDFILES + 1)
+#define IDS_MSGTITLE_ERROR (IDS_MSGTITLE_SECURITY + 1)
+#define IDS_MSGTITLE_NEXT (IDS_MSGTITLE_ERROR + 1)
+#define IDS_MSGTITLE_RETENSION (IDS_MSGTITLE_NEXT + 1)
+#define IDS_MSGTITLE_KEEP_SETTINGS (IDS_MSGTITLE_RETENSION + 1)
+#define IDS_MSGTITLE_WARNING (IDS_MSGTITLE_KEEP_SETTINGS + 1)
+#define IDS_MSGTITLE_TAPEPSWD (IDS_MSGTITLE_WARNING + 1)
+#define IDS_MSGTITLE_XFERMETHOD (IDS_MSGTITLE_TAPEPSWD + 1)
+#define IDS_MSGTITLE_ABORT (IDS_MSGTITLE_XFERMETHOD + 1) // chs:02-05-93
+#define IDS_MSGTITLE_BADEXCHNG (IDS_MSGTITLE_ABORT + 1) // kmw:09-21-94
+#define IDS_MSGTITLE_SELECT (IDS_MSGTITLE_BADEXCHNG + 1) // kmw:09-22-94
+#define IDS_MSGTITLE_EXPANDBRANCH (IDS_MSGTITLE_SELECT + 1) // kmw:09-23-94
+
+// International defaults
+
+#define IDS_DEFAULT_SHORTDATE 4200
+#define IDS_DEFAULT_TIME (IDS_DEFAULT_SHORTDATE + 1)
+#define IDS_DEFAULT_1159 (IDS_DEFAULT_TIME + 1)
+#define IDS_DEFAULT_2359 (IDS_DEFAULT_1159 + 1)
+#define IDS_DEFAULT_THOUSAND (IDS_DEFAULT_2359 + 1)
+
+
+// Tape strings, do_*.c files
+
+#define IDS_CAT_LOADING_SM 4400
+#define IDS_CAT_LOADING_FDD (IDS_CAT_LOADING_SM + 1)
+#define IDS_CAT_TAPENAME (IDS_CAT_LOADING_SM + 2)
+#define IDS_TAPEDRIVENAME (IDS_CAT_LOADING_SM + 3)
+
+
+
+// Hardware Configuration Strings start at 5000
+
+#include "hwctext.h"
+
+// Microsoft OEM Batch Mode Command Line strings start at 6000
+// Reserve 100 id's for OEM Batch support (next available id is 6100)
+// Each of these strings may be no longer than IDS_OEM_MAX_LEN - 1
+// See OMBATCH.C and MUI_ProcessCommandLine in MUI.C for more information.
+
+#define IDS_OEM_MAX_LEN 32 //max length of a res string including
+ // NULL terminator
+
+#define IDS_OEMBATCH_FIRST 6000
+#define IDS_OEMBATCH_RESERVED 100 //100 ids reserved for Batch
+
+ // Batch mode operation - the only operation allowed is 'Backup'.
+
+#define IDS_OEMBATCH_BACKUP IDS_OEMBATCH_FIRST
+#define IDS_OEMBATCH_EJECT (IDS_OEMBATCH_FIRST+1)
+
+ // This string holds the list of prefix chars which must be used to
+ // to mark an option (eg. the slash and dash in /APPEND and -D).
+
+#define IDS_OEMOPT_PREFIXES (IDS_OEMBATCH_FIRST+2)
+
+ // This string holds the list of tokens (characters) which seperate
+ // one command line item from another - eg. spaces, tabs, commas, etc.
+
+#define IDS_OEMOPT_TOKENSEPS (IDS_OEMBATCH_FIRST+3)
+
+ // These strings specify DSA or Monolithic backup of Exchange servers.
+
+#define IDS_OEMOPT_DSA (IDS_OEMBATCH_FIRST+4)
+#define IDS_OEMOPT_MONOLITHIC (IDS_OEMBATCH_FIRST+5)
+
+ // Batch mode command options. NOTE: These must be consecutive and
+ // there must be *exactly* IDS_OEMOPT_COUNT number of them.
+
+#define IDS_OEMOPT_FIRST (IDS_OEMBATCH_FIRST + 10)
+#define IDS_OEMOPT_COUNT 8
+
+#define IDS_OEMOPT_UNKNOWN -1 //special id - NOT A STRING!
+#define IDS_OEMOPT_NOTANOPTION -2 //special id - NOT A STRING!
+#define IDS_OEMOPT_VALIDGUIOPTION -3 //special id - NOT A STRING!
+#define IDS_OEMOPT_USAGE -4 //special id - NOT A STRING!
+#define IDS_OEMOPT_NOPOLLOPTION -5 //special id - NOT A STRING!
+
+#define IDS_OEMOPT_APPEND (IDS_OEMOPT_FIRST+0)
+#define IDS_OEMOPT_VERIFY (IDS_OEMOPT_FIRST+1)
+#define IDS_OEMOPT_RESTRICT (IDS_OEMOPT_FIRST+2)
+#define IDS_OEMOPT_DESCRIPTION (IDS_OEMOPT_FIRST+3)
+#define IDS_OEMOPT_TYPE (IDS_OEMOPT_FIRST+4)
+#define IDS_OEMOPT_LOGFILENAME (IDS_OEMOPT_FIRST+5)
+#define IDS_OEMOPT_LOGEXCEPTIONS (IDS_OEMOPT_FIRST+6)
+#define IDS_OEMOPT_BACKUP_REGISTRY (IDS_OEMOPT_FIRST+7)
+
+ // Allowable types given with the IDS_OEMOPT_TYPE option
+ // These must be consecutive and there must be exactly IDS_OEMTYPE_COUNT
+ // number of them.
+
+#define IDS_OEMTYPE_FIRST (IDS_OEMOPT_FIRST + IDS_OEMOPT_COUNT)
+#define IDS_OEMTYPE_COUNT 5
+
+#define IDS_OEMTYPE_UNKNOWN -1 //special id - NOT A STRING!
+
+#define IDS_OEMTYPE_NORMAL (IDS_OEMTYPE_FIRST+0)
+#define IDS_OEMTYPE_COPY (IDS_OEMTYPE_FIRST+1)
+#define IDS_OEMTYPE_DIFFERENTIAL (IDS_OEMTYPE_FIRST+2)
+#define IDS_OEMTYPE_INCREMENTAL (IDS_OEMTYPE_FIRST+3)
+#define IDS_OEMTYPE_DAILY (IDS_OEMTYPE_FIRST+4)
+#define IDS_OEMTYPE_COMPATIBLE (IDS_OEMTYPE_FIRST+5)
+
+// Microsoft OEM NT Event Logging strings.
+#ifdef OS_WIN32
+
+# define IDS_OEMEVENT_FIRST (IDS_OEMBATCH_FIRST+IDS_OEMBATCH_RESERVED)
+# define IDS_OEMEVENT_RESERVED 10 //10 ids reserved for Event Logging
+
+# define IDS_OEMEVENT_MAX_SOURCE_LEN 80
+
+# define IDS_OEMEVENT_SOURCE_NAME (IDS_OEMEVENT_FIRST+0)
+
+#endif //OS_WIN32
+
+// Read Only drive titles
+
+#define IDS_RDONLY_DRV_ENCOUNTER 4220
+
+// Read Only drive warnings
+
+#define IDS_RDONLY_COPY 4225
+#define IDS_RDONLY_DIFFERENTIAL 4226
+
+// Microsoft OEM Backup and Restore Log file default names, etc.
+
+#ifdef IDS_OEMEVENT_FIRST
+# define IDS_OEMLOG_FIRST (IDS_OEMEVENT_FIRST+IDS_OEMEVENT_RESERVED)
+#else
+# define IDS_OEMLOG_FIRST (IDS_OEMBATCH_FIRST+IDS_OEMBATCH_RESERVED)
+#endif
+
+#define IDS_OEMLOG_RESERVED 10 //reserve 10 ids for log files
+
+#define IDS_OEMLOG_BACKUP_DEF_NAME (IDS_OEMLOG_FIRST+0)
+#define IDS_OEMLOG_RESTORE_DEF_NAME (IDS_OEMLOG_FIRST+1)
+#define IDS_OEMLOG_ERROR_REPORTEVENT (IDS_OEMLOG_FIRST+2)
+#define IDS_OEMLOG_ERROR_EVENTSTRING (IDS_OEMLOG_FIRST+3)
+
+
+#define IDS_RTD_START 9000
+
+#define IDS_RTD_ACCESSDENIED_FILE (IDS_RTD_START+0)
+#define IDS_RTD_ACCESSDENIED_DIR (IDS_RTD_START+1)
+
+#define IDS_RTD_WRITEERROR_FILE (IDS_RTD_START+2)
+#define IDS_RTD_WRITEERROR_DIR (IDS_RTD_START+3)
+
+#define IDS_RTD_READERROR_STREAM (IDS_RTD_START+4)
+#define IDS_RTD_WRITEERROR_STREAM (IDS_RTD_START+5)
+
+#define IDS_RTD_READERROR_SECURITYSTREAM (IDS_RTD_START+6)
+#define IDS_RTD_WRITEERROR_SECURITYSTREAM (IDS_RTD_START+7)
+
+#define IDS_RTD_READERROR_EA (IDS_RTD_START+8)
+#define IDS_RTD_WRITEERROR_EA (IDS_RTD_START+9)
+#define IDS_RTD_VERIFYERROR_EA (IDS_RTD_START+10)
+
+#define IDS_RTD_READERROR_ALTSTREAM (IDS_RTD_START+11)
+#define IDS_RTD_WRITEERROR_ALTSTREAM (IDS_RTD_START+12)
+
+#define IDS_RTD_READERROR_LINK (IDS_RTD_START+13)
+#define IDS_RTD_CREATEERROR_LINK (IDS_RTD_START+14)
+
+#define IDS_RTD_VERIFYERROR_DATA (IDS_RTD_START+15)
+#define IDS_RTD_VERIFYERROR_SECURITYSTREAM (IDS_RTD_START+16)
+#define IDS_RTD_VERIFYERROR_ALTSTREAM (IDS_RTD_START+17)
+
+#endif //STRINGS_H_INCL
+
diff --git a/private/utils/ntbackup/inc/omxchng.h b/private/utils/ntbackup/inc/omxchng.h
new file mode 100644
index 000000000..fd0beffb0
--- /dev/null
+++ b/private/utils/ntbackup/inc/omxchng.h
@@ -0,0 +1,33 @@
+#ifndef XCHG_H
+#define XCHG_H
+
+#define MAX_EMS_SERVER_LEN 32
+
+// Exchange Connect dialog
+
+#define IDD_XCNCT_OK 101
+#define IDD_XCNCT_CANCEL 102
+#define IDD_XCNCT_SVR_NAME 103
+#define IDD_XCNCT_PICKER 104
+
+/* These have to be together in this order */
+#define IDD_XCNCT_CONNECT 105
+#define IDD_XCNCT_ONLINE 106
+
+#define IDD_XCNCT_SERVICE 107
+#define IDD_XCNCT_HELP 108
+
+// Exchange Recovery Status dialog
+#define IDD_XCHG_RCVR_TEXT 101
+#define IDD_XCHG_RCVR_PCT 102
+#define IDD_XCHG_RCVR_CANCEL 103
+#define IDD_XCHG_RCVR_STATUS 104
+#define IDD_XCHG_RCVR_PHASE 105
+#define IDD_XCHG_RCVR_STATUS_BORDER 106
+
+/* Resources storing the number of phases for the IS and DS.
+ Look in omxchng.dlg for the actual values. */
+#define IDR_XCHG_RCVR_IS_PHASE 201
+#define IDR_XCHG_RCVR_DS_PHASE 202
+
+#endif
diff --git a/private/utils/ntbackup/inc/os2_fs.h b/private/utils/ntbackup/inc/os2_fs.h
new file mode 100644
index 000000000..20165afd9
--- /dev/null
+++ b/private/utils/ntbackup/inc/os2_fs.h
@@ -0,0 +1,377 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: os2_fs.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains the prototypes for the OS2
+ file system functions.
+
+ $Log: O:/LOGFILES/OS2_FS.H_V $
+ *
+ * Rev 1.5 15 Jan 1993 17:31:46 TIMN
+ * Added support to OS2 FSYS for MTF
+ *
+ * Rev 1.4 26 Feb 1992 13:15:54 DOUG
+ * Added FSYS_HAND parameter to OS2_GetOSPathDDB() prototype
+ *
+ *
+ * Rev 1.3 16 Dec 1991 18:11:36 STEVEN
+ * move common functions into table
+ *
+ * Rev 1.2 21 Jun 1991 13:21:16 BARRY
+ * Changes for new config.
+ *
+ * Rev 1.1 23 May 1991 16:46:22 BARRY
+ * Changes for FindFirst/Next to scan for dirs only
+ *
+ * Rev 1.0 09 May 1991 13:31:24 HUNTER
+ * Initial revision.
+
+**/
+#ifndef _os2_fs_h_
+#define _os2_fs_h_
+
+/* $begin$ include list */
+
+#include "fsys.h"
+#include "os2dblk.h"
+
+/* $end$ include list */
+
+#define OS2_MAX_PSIZE 264
+#define OS2_MAX_DSIZE 256
+#define OS2_MAX_FSIZE 256
+
+
+#define MAX_REALLOC_SIZE 65536L /* largest block of mem to alloc */
+
+#define GENERIC2OS_ATTRIB_OFFSET 8 /* attrib offset between GENERIC & OS */
+
+
+ /* EA specific defines */
+#define SIZEOF_GEALIST_CBLIST_SIZE sizeof( ULONG ) /* sizeof( eaop.fpGEAList->cbList ) */
+#define SIZEOF_GEALIST ( sizeof( GEA ) + SIZEOF_GEALIST_CBLIST_SIZE )
+#define SIZEOF_FEALIST_CBLIST_SIZE sizeof( ULONG ) /* sizeof( eaop.fpFEAList->cbList ) */
+#define SIZEOF_FEALIST ( sizeof( FEA ) + SIZEOF_FEALIST_CBLIST_SIZE )
+#define EA_BUFF_SIZE 300 /* gea_data buffer size */
+
+enum {
+ REALLOC_EA, /* indicate EA stream for realloc */
+ REALLOC_ACL /* indicate ACL stream for realloc */
+} ;
+
+
+ /* used for RESTORE/VERIFY to indicate what stream is being processed */
+#define ENDOF_FORK STRM_INVALID /* end of current stream */
+#define DATA_FORK STRM_GENERIC_DATA /* data stream, not ea's or acl's */
+#define EA_FORK STRM_OS2_EA /* ea stream */
+#define ACL_FORK STRM_OS2_ACL /* acl stream */
+
+
+typedef struct OS2_FSYS_HAND {
+ HDIR hdir ;
+ INT16 lpath_allocated ;
+ CHAR_PTR long_path ;
+ UINT16 find_type ; /* type of FindFirst/Next scan */
+} *OS2_FSYS_HAND_PTR ;
+
+typedef struct OS2_EA_HAND_STRUCT {
+ HFILE data_hand ;
+ UINT16 ea_space_size ;
+ VOID_PTR ea_space ;
+ UINT32 space_pos ;
+ BOOLEAN skip_flag ;
+ UINT32 next_ea_offset ;
+ UINT32 ea_size ;
+ UINT32 ea_offset ;
+ CHAR_PTR long_name ; /* pascall format string */
+ UINT32 data_size ;
+ UINT32 data_offset ;
+ CHAR path[ OS2_MAX_PSIZE ] ;
+ UINT16 acl_space_size ;
+ VOID_PTR acl_space ;
+ UINT32 acl_space_pos ;
+ UINT32 acl_size ;
+ UINT32 acl_offset ;
+ UINT32 stream_active ; /* is stream being processed */
+} OS2_EA_HAND_STRUCT, *OS2_EA_HAND;
+
+#define OS2_SIZEOF_FILE_HAND ( sizeof(FILE_HAND_STRUCT) + sizeof(OS2_EA_HAND_STRUCT) )
+#define OS2_FILE_HAND_EA_OFFSET ( sizeof(FILE_HAND_STRUCT) )
+
+#define _OS2_GetEAHandPtr(hand) ( (OS2_EA_HAND)((CHAR_PTR)(hand) + OS2_FILE_HAND_EA_OFFSET ) )
+
+ /* for msasserts, are s_info id's correct */
+ /*
+ when s_info->id identifies the stream, the active Id must be INVALID
+ when s_info->id is INVALID, the active Id identifies the stream
+ being processed. Therefore, s_info->id != active id whenever
+ a stream is being received correctly. Since there are many
+ s_info->id's possible, we need to convert !0 values to 1 to
+ properly determine if a new stream is being sent at the right time.
+ ( STRM_OS2_EA != STRM_OS2_ACL is True, but not correct.)
+ */
+#define _OS2_dblNegate(v) ( (v) ? 1 : 0 ) /* 1 if !0, else 0; avoid !!v - compiler dependant values */
+#define _OS2_GetActiveId(hand) ( (_OS2_GetEAHandPtr( hand ))->stream_active )
+
+#define _OS2_GotStrmWhenExpected(sinfoId, activeId) \
+ ( _OS2_dblNegate( sinfoId ) != _OS2_dblNegate( activeId ) )
+
+
+ /* process the s_info id or s_info's data during BACKUP */
+#define _OS2_ExpectStrm(ea_hand) ( (ea_hand)->stream_active == ENDOF_FORK )
+#define _OS2_ExpectData(ea_hand) ( _OS2_ExpectStrm(ea_hand) )
+#define _OS2_SetExpectStrmOff(ea_hand) ( (ea_hand)->stream_active = !ENDOF_FORK )
+#define _OS2_SetExpectDataOn(ea_hand) ( (ea_hand)->stream_active = ENDOF_FORK )
+
+
+ /* type of stream being processed during RESTORE/VERIFY */
+#define _OS2_GetEAHandActiveStrm(ea_hand) ( (ea_hand)->stream_active )
+#define _OS2_SetEAHandActiveStrm(ea_hand,v) ( (ea_hand)->stream_active = (v) )
+
+
+INT16 OS2_AttachToDLE( FSYS_HAND fsh, /* I - File system handle */
+ GENERIC_DLE_PTR dle, /*I/O- drive to attach to. list element expanded */
+ CHAR_PTR u_name, /* I - user name NOT USED */
+ CHAR_PTR pswd); /* I - passowrd NOT USED */
+
+INT16 OS2_DetachDLE( FSYS_HAND fsh ); /* I - */
+
+INT16 OS2_AllocFileHand( FILE_HAND *file_hand ) ; /* I/O - */
+VOID OS2_MemsetFileHand( FILE_HAND *file_hand ) ; /* I/O - */
+
+INT16 OS2_CreateObj( FSYS_HAND fsh, /* I - File system to create object one */
+ DBLK_PTR dblk); /* I - Describes object to create */
+
+INT16 OS2_OpenObj( FSYS_HAND fsh, /* I - file system that the file is opened on */
+ FILE_HAND *hand, /* O - allocated handle */
+ DBLK_PTR dblk, /*I/O- describes the file to be opened */
+ OPEN_MODE mode); /* I - open mode */
+
+INT16 OS2_ReadObj( FILE_HAND hand, /* I - handle of object to read from */
+ CHAR_PTR buf, /* O - buffer to place data into */
+ UINT16 *size, /*I/O- Entry: size of buf; Exit: number of bytes read */
+ UINT16 *blk_size, /* O - Block size needed for next read */
+ STREAM_INFO_PTR s_info ) ; /*I/O- struct to place stream header info */
+
+
+INT16 OS2_WriteObj( FILE_HAND hand, /* I - handle of object to read from */
+ CHAR_PTR buf, /* O - buffer to place data into */
+ UINT16 *size, /*I/O- Entry: size of buf; Exit: number of bytes read */
+ UINT16 *blk_size, /* O - Block size need for next read */
+ STREAM_INFO_PTR s_info ) ; /*I/O- struct to place stream header info */
+
+INT16 OS2_VerObj( FILE_HAND hand, /* I - file handle to verify data with */
+ CHAR_PTR buf, /* I - buffer needed to perform verify */
+ CHAR_PTR data, /* I - data to verify against */
+ UINT16 *size, /*I/O- size of buffers / amount verified */
+ UINT16 *blk_size, /* O - minum size of block for next call */
+ STREAM_INFO_PTR s_info ) ; /*I/O- struct to place stream header info */
+
+
+INT16 OS2_CloseObj( FILE_HAND hand ); /* I - handle of object to close */
+
+INT16 OS2_DeleteObj( FSYS_HAND fsh,
+ DBLK_PTR dblk );
+
+INT16 OS2_FindFirst( FSYS_HAND fsh, /* I - file system handle */
+ DBLK_PTR dblk, /* O - pointer to place to put the dblk data */
+ CHAR_PTR sname, /* I - serach name */
+ UINT16 find_type);/* I - objects to search for (dirs, all, etc)*/
+
+INT16 OS2_FindNext( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ); /* O - Discriptor block */
+
+INT16 OS2_GetObjInfo( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ); /*I/O- On entry it is minimal on exit Complete */
+
+INT16 OS2_VerObjInfo( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ); /* I - DBLK to compare OS against */
+
+INT16 OS2_ChangeDir( FSYS_HAND fsh, /* I - file system to changing directories on */
+ CHAR_PTR path, /* I - describes the path of the new directory */
+ INT16 psize); /* I - specifies the length of the path */
+
+INT16 OS2_UpDir( FSYS_HAND fsh ); /* I - file system to change directories in */
+
+INT16 OS2_GetCurrentPath( FSYS_HAND fsh, /* I - file system to get current path from */
+ CHAR_PTR path, /* O - buffer to place this path */
+ INT16 *size); /*I/O- size of buffer on entry & on exit */
+
+INT16 OS2_SeekObj( FILE_HAND hand, /* I - Opened object to seek into */
+ UINT32 *offset ); /*I/O- Offset to seek; Number of bytes actualy seeked */
+
+INT16 OS2_GetMaxSizeDBLK( FSYS_HAND fsh /* not used */ );
+
+INT16 OS2_GetBasePath( FSYS_HAND fsh, /* I - file system to get base path from */
+ CHAR_PTR full_path, /* O - buffer to place this path */
+ INT16 *size ); /*I/O- size of buffer on entry & on exit */
+
+INT16 OS2_GetCurrentDDB( FSYS_HAND fsh, /* I - file system to get DDB from */
+ DBLK_PTR dblk ); /* O - place to put the DDB data */
+
+INT16 OS2_SetObjInfo( FSYS_HAND fsh, /* I - file system handle */
+ DBLK_PTR dblk); /* I - data to write to disk */
+
+
+INT16 OS2_ModFnameFDB( FSYS_HAND fsh, /* I - File system handle */
+ BOOLEAN set_it, /* I - TRUE if setting file name, FALSE if getting */
+ DBLK_PTR dblk, /* I - Descriptor block to get file name from */
+ CHAR_PTR buf, /*I/O- file name to read (or to write) */
+ INT16 *size ) ; /*I/O- size buffer on entry and exit */
+
+INT16 OS2_ModPathDDB( FSYS_HAND fsh, /* I - File system handle */
+ BOOLEAN set_it , /* I - TRUE if setting path, FALSE if getting */
+ DBLK_PTR dblk, /* I - Descriptor block to get path from */
+ CHAR_PTR buf, /*I/O- path to read (or to write) */
+ INT16 *size ); /*I/O- size of buffer on entry and exit */
+
+INT16 OS2_GetOSFnameFDB( DBLK_PTR dblk , /* I - Descriptor block to get path from */
+ CHAR_PTR buf ); /*I/O- path to read (or to write) */
+
+INT16 OS2_GetOSPathDDB( FSYS_HAND fsh, /* I - File System Handle */
+ DBLK_PTR dblk , /* I - Descriptor block to get path from */
+ CHAR_PTR buf ); /*I/O- path to read (or to write) */
+
+INT16 OS2_GetFileVerFDB( DBLK_PTR dblk ,
+ UINT32 *version ) ;
+
+INT16 OS2_GetCdateDBLK( DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ); /*I/O- createion date to read (or to write) */
+
+INT16 OS2_GetMdateDBLK( DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ) ; /* O - modify date to write */
+
+INT16 OS2_ModBdateDBLK( BOOLEAN set_it , /* I - TRUE if setting creation date, FALSE if getting */
+ DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ) ; /*I/O- createion date to read (or to write) */
+
+INT16 OS2_ModAdateDBLK( BOOLEAN set_it , /* I - TRUE if setting creation date, FALSE if getting */
+ DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ) ; /*I/O- createion date to read (or to write) */
+
+UINT64 OS2_DisplaySizeDBLK( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ) ; /* I - Descriptor block to get generic data size for */
+
+INT16 OS2_GetOS_InfoDBLK( DBLK_PTR dblk, /* I - DBLK to get the info from */
+ CHAR_PTR os_info, /* O - Buffer to place data */
+ INT16 *size ); /*I/O- Buffer size / data length */
+
+
+INT16 OS2_ModAttribDBLK( BOOLEAN set_it ,
+ DBLK_PTR dblk ,
+ UINT32_PTR attr );
+
+
+INT16 OS2_GetObjTypeDBLK( DBLK_PTR dblk,
+ OBJECT_TYPE *type );
+
+
+INT16 OS2_GetActualSizeDBLK( FSYS_HAND fsh,
+ DBLK_PTR dblk ) ;
+
+INT16 OS2_SizeofFname( FSYS_HAND fsh, /* I - file system in use */
+ DBLK_PTR fdb ); /* I - dblk to get fname from */
+
+INT16 OS2_SizeofOSFname( FSYS_HAND fsh, /* I - file system in use */
+ DBLK_PTR fdb ) ; /* I - dblk to get fname from */
+
+INT16 OS2_SizeofPath( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR ddb ) ; /* I - DBLK to get path size from */
+
+INT16 OS2_SizeofOSPath( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR ddb ) ; /* I - DBLK to get path size from */
+
+INT16 OS2_SizeofOSInfo( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ); /* I - DBLK to get size of OS info for */
+
+
+INT16 OS2_MatchDBLK( FSYS_HAND fsh , /* I - file system used to do comparison */
+ DBLK_PTR dblk1, /* I - DDB, IDB, or UDB just not FDB */
+ DBLK_PTR dblk2, /* I - FDB if above is DDB else unused */
+ BOOLEAN disp_flag,/* I - TRUE if match DIR for display purpose */
+ struct FSE *fse ); /* I - FSE to compare against */
+
+INT16 OS2_PushMinDDB( FSYS_HAND fsh,
+ DBLK_PTR dblk );
+
+INT16 OS2_PopMinDDB( FSYS_HAND fsh ,
+ DBLK_PTR dblk );
+
+INT16 OS2_CreateFDB( FSYS_HAND fsh,
+ GEN_FDB_DATA_PTR dat ) ;
+
+INT16 OS2_CreateDDB( FSYS_HAND fsh,
+ GEN_DDB_DATA_PTR dat ) ;
+
+INT16 OS2_CreateIDB( FSYS_HAND fsh,
+ GEN_IDB_DATA_PTR dat ) ;
+
+VOID OS2_SetOwnerId( FSYS_HAND fsh, DBLK_PTR dblk, UINT32 id ) ;
+
+BOOLEAN OS2_ProcessDDB( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+INT16 OS2_ChangeIntoDDB( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+VOID OS2_GetRealBasePath( FSYS_HAND fsh, CHAR_PTR path ) ;
+
+INT16 OS2_SaveLongPath( FSYS_HAND fsh, CHAR_PTR path, INT16 path_len ) ;
+
+INT16 OS2_AppendLongPath( FSYS_HAND fsh, CHAR_PTR path, INT16 path_len ) ;
+
+UINT16 OS2_SetDataSize( FSYS_HAND fsh, DBLK_PTR ddb, UINT32 size ) ;
+
+INT16 OS2_DeviceDispName(
+GENERIC_DLE_PTR dle,
+CHAR_PTR dev_name,
+INT16 size,
+INT16 type );
+
+VOID OS2_GetVolName( GENERIC_DLE_PTR dle, CHAR_PTR buffer ) ;
+
+INT16 OS2_SizeofVolName( GENERIC_DLE_PTR dle ) ;
+
+INT16 OS2_FindDrives( DLE_HAND hand, BE_CFG_PTR cfg, UINT32 fsys_mask ) ;
+
+UINT16 OS2_CalcForkDelta( UINT32, INT16, UINT32, ... ) ;
+
+BOOLEAN OS2_IsBlkComplete( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+INT16 OS2_CompleteBlk( FSYS_HAND fsh, DBLK_PTR dblk, CHAR_PTR buffer, UINT16 *size, STREAM_INFO_PTR sinfo ) ;
+VOID OS2_ReleaseBlk( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+
+
+INT16 OS2_OpenEA(
+ FILE_HAND hand,
+ OS2_DBLK_PTR fdb
+) ;
+
+INT16 OS2_OpenACL(
+ FSYS_HAND fsh,
+ FILE_HAND hand,
+ OS2_DBLK_PTR fdb,
+ UINT16 size
+) ;
+
+INT16 OS2_OpenEAforVerifyDir(
+ FILE_HAND hand, /* O - allocated handle */
+ STREAM_INFO_PTR s_info /* I - stream info */
+) ;
+
+INT16 OS2_OpenACLforVerifyDir(
+ FILE_HAND hand, /* O - allocated handle */
+ STREAM_INFO_PTR s_info /* I - stream info */
+) ;
+
+INT16 OS2_ReallocSpace(
+ FILE_HAND hand, /* I/O - allocated handle */
+ UINT32 size, /* I - number of bytes to alloc */
+ INT16 spaceType /* I - type of buffer to alloc (EA or ACL) */
+) ;
+
+#define _ReallocEA(hand,v) ( OS2_ReallocSpace( hand, v, REALLOC_EA ) )
+#define _ReallocACL(hand,v) ( OS2_ReallocSpace( hand, v, REALLOC_ACL ) )
+
+#endif
diff --git a/private/utils/ntbackup/inc/os2com.h b/private/utils/ntbackup/inc/os2com.h
new file mode 100644
index 000000000..90b1e6566
--- /dev/null
+++ b/private/utils/ntbackup/inc/os2com.h
@@ -0,0 +1,142 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: os2com.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: OS2 utility functions.
+
+
+ $Log: Q:/LOGFILES/OS2COM.H_V $
+ *
+ * Rev 1.2 14 Jan 1993 16:22:54 DAVEV
+ * chg PULONG to UINT32_PTR
+ *
+ * Rev 1.1 30 Oct 1991 10:56:34 LORIB
+ * Changes for ACL.
+ *
+ * Rev 1.0 09 May 1991 13:32:26 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef _os2com_h_
+#define _os2com_h_
+
+/* The following macros convert a dos format date or time UINT16 into */
+/* a UINT16 suitable for placing in a DATE_TIME structure. */
+
+#define GET_OS2_YEAR( os2_date ) ( 1980 + ( (UINT16)(os2_date) >> 9 ) )
+#define GET_OS2_MONTH( os2_date ) (((os2_date) & 0x1ff) >> 5)
+#define GET_OS2_DAY( os2_date ) ( (os2_date) & 0x1f )
+#define GET_OS2_HOUR( os2_time ) ( ((UINT16)(os2_time)) >> 11 )
+#define GET_OS2_MINUTE( os2_time ) ( ( (os2_time) & 0x7e0 ) >> 5 )
+#define GET_OS2_SECOND( os2_time ) ( ( (os2_time) & 0x1f ) << 1 )
+
+
+#define DA_READONLY 0x01
+#define DA_HIDDEN 0x02
+#define DA_SYSTEM 0x04
+#define DA_DIRECTORY 0x10
+#define DA_MODIFIED 0x20
+
+#define SET_INFO_MODE 0x80
+#define DENY_NONE_MODE 0x40
+#define DENY_WRITE_MODE 0x20
+#define DENY_ALL_MODE 0
+#define SHARE_MODE 0xF0
+
+#define READ_ACCESS 0
+#define WRITE_ACCESS 1
+#define ACCESS_MODE 0xf
+
+
+/* defines for ordinals of functions for OS/2 1.2 */
+#define DOS_OPEN2 "#95"
+#define DOS_QPATHINFO "#98"
+#define DOS_SETPATHINFO "#104"
+#define DOS_QFSATTACH "#182"
+#define DOS_FINDFIRST2 "#184"
+#define DOS_MKDIR2 "#185"
+#define DOS_ENUMATTRIB "#204"
+
+extern UINT16 ( APIENTRY *Dos_Open2 )( CHAR_PTR, PHFILE, UINT16 *, UINT32, UINT16, UINT16, UINT32, PEAOP, UINT32 );
+extern UINT16 ( APIENTRY *Dos_QPathInfo )( CHAR_PTR, UINT16, UINT8 *, UINT16, UINT32);
+extern UINT16 ( APIENTRY *Dos_SetPathInfo )( CHAR_PTR, UINT16, UINT8 *, UINT16, UINT16, UINT32);
+extern UINT16 ( APIENTRY *Dos_QFSAttach )( CHAR_PTR, UINT16, UINT16, UINT8 *, UINT16 *, UINT32);
+extern UINT16 ( APIENTRY *Dos_FindFirst2 )( CHAR_PTR, PHDIR, UINT16, VOID_PTR, UINT16, UINT16 *, UINT16, UINT32 ) ;
+extern UINT16 ( APIENTRY *Dos_MkDir2 )( CHAR_PTR, PEAOP, UINT32 ) ;
+extern UINT16 ( APIENTRY *Dos_EnumAttribute )( UINT16, VOID_PTR, UINT32, VOID_PTR, UINT32, UINT32 *, UINT32, UINT32 ) ;
+
+extern UINT16 ( APIENTRY *Net_AccessAdd )( CHAR_PTR, INT16, CHAR_PTR, UINT16 ) ;
+extern UINT16 ( APIENTRY *Net_AccessGetInfo )( CHAR_PTR, CHAR_PTR, INT16, CHAR_PTR, UINT16, UINT16 * ) ;
+extern UINT16 ( APIENTRY *Net_AccessSetInfo )( CHAR_PTR, CHAR_PTR, INT16, CHAR_PTR, UINT16, INT16 ) ;
+
+/* internal functions for OS/2 Tmenu File system */
+
+INT16 DeleteFileOS2( CHAR_PTR path ) ;
+
+INT16 DeleteDirOS2( CHAR_PTR path );
+
+INT16 SetAttribOS2( CHAR_PTR path, INT16 attrib );
+
+INT16 SetFileInfoOS2( CHAR_PTR drive, HFILE hand, FILESTATUS *finfo ) ;
+
+INT16 SetPathInfoOS2( CHAR_PTR path, FILESTATUS *finfo ) ;
+
+INT16 GetVolumeLabel( UCHAR drive_number, CHAR_PTR volume_name ) ;
+
+INT16 FindFirstOS2( PHDIR hdir, CHAR_PTR path, FILEFINDBUF2 *dta ) ;
+
+INT16 FindNextOS2( CHAR_PTR device_name, HDIR hdir, FILEFINDBUF2 *dta ) ;
+
+VOID OS2_MakeName( CHAR_PTR dest, CHAR_PTR source, INT16 fmt ) ;
+
+VOID OS2_MakePath( CHAR_PTR dest, CHAR_PTR source, INT16 leng, INT16 fmt ) ;
+
+INT16 OpenFileOS2( CHAR_PTR path, UINT16 open_mode, HFILE *hand, UINT32 *dsize, UINT32 *asize ) ;
+
+INT16 CloseFileOS2( CHAR_PTR device_name, HFILE hand ) ;
+
+INT16 LockFileOS2( CHAR_PTR device_name, HFILE hand );
+
+INT16 UnlockFileOS2( CHAR_PTR device_name, HFILE hand );
+
+INT16 CreateDirOS2( CHAR_PTR path );
+
+INT16 WriteFileOS2( CHAR_PTR dev_name, HFILE hand, CHAR_PTR buf, UINT16 *size ) ;
+
+INT16 ReadFileOS2( CHAR_PTR dev_name, HFILE hand, UINT32 pos, CHAR_PTR buf, UINT16 *size ) ;
+
+UINT16 OS2_LoadEAbuffer( FILE_HAND hand ) ;
+
+UINT16 OS2_FlushEAsForDir( CHAR_PTR path );
+
+VOID OS2_GetLongName( FSYS_HAND fsh, CHAR_PTR path, CHAR_PTR long_name ) ;
+
+/* APIs replaced for Critical error support */
+UINT16 CE_DosEnumAttribute( CHAR_PTR, USHORT, PVOID, ULONG, PVOID,
+ ULONG, UINT32_PTR, ULONG, ULONG);
+
+UINT16 CE_DosQFileInfo(CHAR_PTR dev_name, HFILE hf, USHORT usInfoLevel,
+ PVOID pInfoBuf, USHORT cbInfoBuf);
+
+UINT16 CE_DosQPathInfo(PSZ pszPath, USHORT usInfoLevel, PBYTE pInfoBuf,
+ USHORT cbInfoBuf, ULONG ulReserved);
+
+UINT16 CE_DosSetPathInfo(PSZ pszPath, USHORT usInfoLevel, PBYTE pInfoBuf,
+ USHORT cbInfoBuf, USHORT usFlags,
+ ULONG ulReserved);
+
+UINT16 CE_DosSetFileInfo(CHAR_PTR dev_name, HFILE hand, USHORT usInfoLevel,
+ PBYTE pInfoBuf, USHORT cbInfoBuf ) ;
+
+VOID OS2_SetupPath( struct OS2_DBLK *ddblk, CHAR_PTR path, UINT16 leng, UINT16 fmt ) ;
+
+VOID OS2_InitFS( VOID ) ;
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/os2dblk.h b/private/utils/ntbackup/inc/os2dblk.h
new file mode 100644
index 000000000..27cb3db94
--- /dev/null
+++ b/private/utils/ntbackup/inc/os2dblk.h
@@ -0,0 +1,97 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: os2dblk.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains the definition of the OS2
+ file and directory control blocks.
+
+
+ $Log: O:/LOGFILES/OS2DBLK.H_V $
+ *
+ * Rev 1.3 15 Jan 1993 17:31:28 TIMN
+ * Added support to OS2 FSYS for MTF
+ *
+ * Rev 1.2 30 Jan 1992 17:56:42 BARRY
+ * Added acl_info_complete so os info calls could be separated from ACL calls.
+ * (Purely a performance change.)
+ *
+ * Rev 1.1 30 Oct 1991 10:57:58 LORIB
+ * Changes for ACL.
+ *
+ * Rev 1.0 09 May 1991 13:31:32 HUNTER
+ * Initial revision.
+
+**/
+#ifndef os2dblk_h
+#define os2dblk_h
+#include "queues.h"
+#include "os2com.h"
+/* $end$ include list */
+
+#define EA_LONG_NAME ".LONGNAME"
+
+typedef struct STD_OBJ_INFO {
+ FDATE cdate ;
+ FTIME ctime ;
+ FDATE adate ;
+ FTIME atime ;
+ FDATE date ;
+ FTIME time ;
+ UINT32 size ;
+ UINT32 alloc_size ;
+ UINT16 attr;
+ UINT16 ea_size ;
+ UINT16 acl_size ;
+ } STD_OBJ_INFO;
+
+
+typedef struct OS2_FDB_INFO {
+ BOOLEAN inuse_attrib ;
+ HFILE handle ; /* set by: OS2_CreateFile */
+ UINT16 lname_leng ;
+ UINT16 long_name ; /* used for backup only */
+ UINT16 os_name ;
+ UINT16 name ;
+} OS2_FDB_INFO, *OS2_FDB_INFO_PTR;
+
+
+typedef struct OS2_DDB_INFO {
+ BOOLEAN empty_attrib ;
+ UINT16 os_path ;
+ UINT16 os_path_leng ;
+ UINT16 path_leng ; /* does not count \0 */
+ UINT16 path ;
+ UINT16 lpath_leng ; /* only used for backup */
+ UINT16 long_path ; /* */
+} OS2_DDB_INFO, *OS2_DDB_INFO_PTR;
+
+
+
+typedef struct OS2_DBLK {
+ UINT8 blk_type; /* values: DDB_ID, FDB_ID */
+ COM_DBLK fs_reserved ;
+ STD_OBJ_INFO dta;
+ BOOLEAN os_info_complete; /* TRUE if GetObjInfo doesn't have to do anything */
+ BOOLEAN acl_info_complete; /* TRUE if GetObjInfo doesn't have to call ACL code */
+ UINT32 data_fork_offset ;
+ UINT32 ea_fork_offset ;
+ UINT32 acl_fork_offset ;
+ union {
+ OS2_DDB_INFO d;
+ OS2_FDB_INFO f;
+ } b;
+} OS2_DBLK, *OS2_DBLK_PTR;
+
+
+typedef struct OS2_MIN_DDB {
+ Q_ELEM q ;
+ HDIR handle ;
+ UINT16 psize ; /* size of path string */
+ CHAR_PTR path; /* build from "name" and current dir */
+} OS2_MIN_DDB, *OS2_MIN_DDB_PTR;
+
+#endif
diff --git a/private/utils/ntbackup/inc/osinfo.h b/private/utils/ntbackup/inc/osinfo.h
new file mode 100644
index 000000000..90a244fd0
--- /dev/null
+++ b/private/utils/ntbackup/inc/osinfo.h
@@ -0,0 +1,157 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: osinfo.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains the OS info structures for all of
+ the file systems.
+
+ Location:
+
+
+ $Log: J:/LOGFILES/OSINFO.H_V $
+ *
+ * Rev 1.15 01 Oct 1993 12:43:16 DON
+ * Changed the typedef struct for SMS_OS_INFO
+ *
+ * Rev 1.14 21 Jul 1993 10:27:20 DON
+ * Forgot the volume name requires an extra byte for the ':'
+ *
+ * Rev 1.13 16 Jul 1993 08:51:18 DON
+ * Removed #ifdef's for SMS
+ *
+ * Rev 1.12 17 May 1993 12:21:30 DON
+ * Second checkin for Creator Path updates. Only MAC isn't working
+ *
+ * Rev 1.11 29 Oct 1992 16:55:24 BARRY
+ * Added linkOnly BOOLEAN to NTFS osinfo.
+ *
+ * Rev 1.10 14 Aug 1992 11:42:34 BARRY
+ * Changes for MTF 4.0.
+ *
+ * Rev 1.9 23 Jul 1992 10:08:40 STEVEN
+ * added short filename to osinfo
+ *
+ * Rev 1.8 08 Jul 1992 15:22:46 BARRY
+ * Updated SMS OS info for encapsulated 4.0 support.
+ *
+ * Rev 1.7 28 Feb 1992 13:04:42 STEVEN
+ * step one for varible length paths
+ *
+ * Rev 1.6 06 Feb 1992 09:36:22 BARRY
+ * Don't need to always include SMSCONST.H and always define SMS os info.
+ *
+ * Rev 1.5 29 Jan 1992 13:44:38 BARRY
+ * Added volume name to SMS os info.
+ *
+ * Rev 1.4 12 Dec 1991 16:14:26 BARRY
+ * Update SMS OS info structure.
+ *
+ * Rev 1.3 13 Nov 1991 15:29:30 BARRY
+ * SMS OS info changes.
+ *
+ * Rev 1.2 31 Oct 1991 16:29:32 BARRY
+ * TRICYCLE: Added SMS OS info and LoriB's changes to OS/2 OS info for ACL.
+ *
+ * Rev 1.1 14 Aug 1991 14:20:52 DAVIDH
+ * Added proDosInfo to AFP file and directory structure.
+ *
+ * Rev 1.0 09 May 1991 13:31:16 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef osinfo_h
+#define osinfo_h
+
+typedef struct NOV_FILE_OS_INFO {
+ UINT32 ownerID; /* File owner, default = 0 */
+ UINT32 fileAttribs; /* All attribs in one long word */
+ UINT32 lastModifierID; /* Bindery ID of last file writer */
+ UINT32 archiverID; /* Bindery ID of backup operator */
+ UINT16 inheritedRights; /* Inherited rights, default=ffff */
+} NOV_FILE_OS_INFO, *NOV_FILE_OS_INFO_PTR;
+
+
+typedef struct NOV_DIR_OS_INFO {
+ UINT32 owner_id; /* Dir owner, default = 0 */
+ UINT32 dirAttribs; /* All attribs in one long word */
+ UINT32 maxSpace; /* Max dir space, default = 0 */
+ UINT16 inheritedRights; /* Inherited rights, default=ffff */
+} NOV_DIR_OS_INFO, *NOV_DIR_OS_INFO_PTR;
+
+
+typedef struct AFP_FILE_OS_INFO {
+ UINT8 finder[32]; /* Finder info, default=all zeros */
+ CHAR longName[32]; /* Mac name (Pascal-style string) */
+ UINT32 ownerID; /* Bindery ID of file owner */
+ UINT32 fileAttribs; /* All attribs in one long word */
+ CHAR proDosInfo[6]; /* ProDos info, default=all zeros */
+ UINT32 lastModifierID; /* Bindery ID of last file writer */
+ UINT32 archiverID; /* Bindery ID of backup operator */
+ UINT16 inheritedRights; /* Inherited rights, default=ffff */
+} AFP_FILE_OS_INFO, *AFP_FILE_OS_INFO_PTR;
+
+
+typedef struct AFP_DIR_OS_INFO {
+ UINT8 finder[32]; /* Finder info, default=all zeros */
+ UINT32 ownerID; /* Bindery ID of directory owner */
+ UINT16 longPath; /* Mac path */
+ UINT16 longPathLength; /* Length of Mac path */
+ CHAR proDosInfo[6]; /* ProDos info, default=all zeros */
+ UINT32 maxSpace; /* Max dir space, default = 0 */
+ UINT32 dirAttribs; /* All attribs in one long word */
+ UINT16 inheritedRights; /* Inherited rights, default=ffff */
+} AFP_DIR_OS_INFO, *AFP_DIR_OS_INFO_PTR;
+
+
+/* OS2's File system info */
+typedef struct OS2_FILE_OS_INFO {
+ UINT16 fileAttributes; /* OS/2 attributes */
+ UINT32 allocSize; /* Disk space allocated for file */
+ UINT16 longName; /* HPFS or other long name */
+ UINT16 longNameLength; /* Length of above */
+}OS2_FILE_OS_INFO, *OS2_FILE_OS_INFO_PTR;
+
+
+typedef struct OS2_DIR_OS_INFO {
+ UINT16 dirAttributes; /* OS/2 attributes */
+ UINT16 path; /* HPFS or other long path */
+ UINT16 pathLength; /* length of above */
+} OS2_DIR_OS_INFO, *OS2_DIR_OS_INFO_PTR;
+
+
+/*
+ * Info for SMS FDBs and DDBs.
+ */
+typedef struct _SMS_OS_INFO *SMS_OS_INFO_PTR;
+typedef struct _SMS_OS_INFO {
+ UINT32 attrib; /* SMS attributes (can't be mapped) */
+ BOOLEAN modified; /* Is the object's modified bit set? */
+ UINT32 creator_name_space; /* SMS value for the creator name space */
+ /* Novell's imposed max volume length */
+ CHAR volume[ 17 ]; /* (the extra character is for the ':') */
+} SMS_OS_INFO;
+
+
+/* NT's File system info */
+typedef struct NT_FILE_OS_INFO {
+ UINT32 file_attributes;
+ UINT16 short_name_offset;
+ UINT16 short_name_size;
+ BOOLEAN linkOnly;
+}NT_FILE_OS_INFO, *NT_FILE_OS_INFO_PTR;
+
+
+typedef struct NT_DIR_OS_INFO {
+ UINT32 dir_attributes ;
+} NT_DIR_OS_INFO, *NT_DIR_OS_INFO_PTR;
+
+
+#endif
+
+
diff --git a/private/utils/ntbackup/inc/overwrit.h b/private/utils/ntbackup/inc/overwrit.h
new file mode 100644
index 000000000..db39d509d
--- /dev/null
+++ b/private/utils/ntbackup/inc/overwrit.h
@@ -0,0 +1,29 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: overwrit.h
+
+ Description:
+
+ Location:
+
+
+ $Log: G:/UI/LOGFILES/OVERWRIT.H_V $
+
+ Rev 1.1 04 Oct 1992 19:48:38 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.0 20 Nov 1991 19:36:50 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifndef _overwrit_h_
+#define _overwrit_h_
+
+VOID UI_OverwriteTape(
+ DBLK_PTR vcb_ptr ) ;
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/parstab.h b/private/utils/ntbackup/inc/parstab.h
new file mode 100644
index 000000000..72d7eb457
--- /dev/null
+++ b/private/utils/ntbackup/inc/parstab.h
@@ -0,0 +1,333 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: parstab.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+ Location:
+
+
+ $Log: J:/LOGFILES/PARSTAB.H_V $
+ *
+ * Rev 1.4 23 Sep 1993 14:08:44 DON
+ * Define the '[' character as IMAGE_START only if FS_IMAGE is defined else ANY_CHAR
+ *
+ * Rev 1.3 13 Aug 1993 15:01:34 TIMN
+ * Changed ALPHA define to ALETTER due to DECs ALPHA machine conflicts
+ *
+ * Rev 1.2 09 Feb 1993 13:54:18 MARILYN
+ * for the nlm, '=' must be an alpha for the directory services path to
+ * parse correctly.
+ *
+ * Rev 1.1 02 Apr 1992 10:58:06 CARLS
+ * changed SPACE from ANY_CHAR to GRAPHIC
+ *
+ * Rev 1.0 09 May 1991 13:31:18 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+
+/* states */
+#define INITIAL 0
+#define DRV_REL 1
+#define MAC_SPC 2
+#define DOS 3
+#define IM_NAME 4
+#define OS2 5
+#define IM_DONE 6
+#define DRVDONE 7
+#define FILEDON 8
+#define ALLDON 9
+#define ERROR 10
+#define REM_DRV 11
+#define UNKNOWN 12
+
+#define COLEN 0
+#define PERIOD 1
+#define BK_SLASH 2
+#define END_OS 3
+#define ALETTER 4
+#define NUMERIC 5
+#define SPECIAL 6
+#define GRAPHIC 7
+#define ANY_CHAR 8
+#define REMOT_CHAR 9
+#define IMAGE_START 10
+#define DRV_DONE 11
+
+static CHAR ascii[] = {
+/* 0 */ END_OS ,
+/* 1 */ GRAPHIC,
+/* 2 */ GRAPHIC,
+/* 3 */ GRAPHIC,
+/* 4 */ GRAPHIC,
+/* 5 */ GRAPHIC,
+/* 6 */ GRAPHIC,
+/* 7 */ GRAPHIC,
+/* 8 */ GRAPHIC,
+/* 9 */ GRAPHIC,
+/* 10 */ GRAPHIC,
+/* 11 */ GRAPHIC,
+/* 12 */ GRAPHIC,
+/* 13 */ GRAPHIC,
+/* 14 */ GRAPHIC,
+/* 15 */ GRAPHIC,
+/* 16 */ GRAPHIC,
+/* 17 */ GRAPHIC,
+/* 18 */ GRAPHIC,
+/* 19 */ GRAPHIC,
+/* 20 */ GRAPHIC,
+/* 21 */ GRAPHIC,
+/* 22 */ GRAPHIC,
+/* 23 */ GRAPHIC,
+/* 24 */ GRAPHIC,
+/* 25 */ GRAPHIC,
+/* 26 */ GRAPHIC,
+/* 27 */ GRAPHIC,
+/* 28 */ GRAPHIC,
+/* 29 */ GRAPHIC,
+/* 30 */ GRAPHIC,
+/* 31 */ GRAPHIC,
+/* SPACE*/ GRAPHIC,
+/* ! */ SPECIAL,
+/* " */ ANY_CHAR,
+/* # */ SPECIAL,
+/* $ */ SPECIAL,
+/* % */ SPECIAL,
+/* & */ SPECIAL,
+/* ' */ SPECIAL,
+/* ( */ SPECIAL,
+/* ) */ SPECIAL,
+/* * */ SPECIAL, /* removed after token grabed */
+/* + */ REMOT_CHAR,
+/* , */ ANY_CHAR,
+/* - */ SPECIAL,
+/* . */ PERIOD,
+/* / */ ANY_CHAR ,
+/* 0 */ NUMERIC ,
+/* 1 */ NUMERIC ,
+/* 2 */ NUMERIC ,
+/* 3 */ NUMERIC ,
+/* 4 */ NUMERIC ,
+/* 5 */ NUMERIC ,
+/* 6 */ NUMERIC ,
+/* 7 */ NUMERIC ,
+/* 8 */ NUMERIC ,
+/* 9 */ NUMERIC ,
+/* : */ COLEN,
+/* ; */ ANY_CHAR,
+/* < */ ANY_CHAR,
+#ifdef OS_NLM
+/* = */ ALETTER,
+#else
+/* = */ ANY_CHAR,
+#endif
+/* > */ ANY_CHAR,
+/* ? */ SPECIAL, /* removed after token grabbed */
+/* @ */ SPECIAL,
+/* A */ ALETTER,
+/* B */ ALETTER,
+/* C */ ALETTER,
+/* D */ ALETTER,
+/* E */ ALETTER,
+/* F */ ALETTER,
+/* G */ ALETTER,
+/* H */ ALETTER,
+/* I */ ALETTER,
+/* J */ ALETTER,
+/* K */ ALETTER,
+/* L */ ALETTER,
+/* M */ ALETTER,
+/* N */ ALETTER,
+/* O */ ALETTER,
+/* P */ ALETTER,
+/* Q */ ALETTER,
+/* R */ ALETTER,
+/* S */ ALETTER,
+/* T */ ALETTER,
+/* U */ ALETTER,
+/* V */ ALETTER,
+/* W */ ALETTER,
+/* X */ ALETTER,
+/* Y */ ALETTER,
+/* Z */ ALETTER,
+#if defined(FS_IMAGE)
+/* [ */ IMAGE_START,
+#else
+/* [ */ ANY_CHAR,
+#endif
+/* \ */ BK_SLASH,
+/* ] */ ANY_CHAR,
+/* ^ */ SPECIAL,
+/* _ */ SPECIAL,
+/* ` */ SPECIAL,
+/* a */ ALETTER,
+/* b */ ALETTER,
+/* c */ ALETTER,
+/* d */ ALETTER,
+/* e */ ALETTER,
+/* f */ ALETTER,
+/* g */ ALETTER,
+/* h */ ALETTER,
+/* i */ ALETTER,
+/* j */ ALETTER,
+/* k */ ALETTER,
+/* l */ ALETTER,
+/* m */ ALETTER,
+/* n */ ALETTER,
+/* o */ ALETTER,
+/* p */ ALETTER,
+/* q */ ALETTER,
+/* r */ ALETTER,
+/* s */ ALETTER,
+/* t */ ALETTER,
+/* u */ ALETTER,
+/* v */ ALETTER,
+/* w */ ALETTER,
+/* x */ ALETTER,
+/* y */ ALETTER,
+/* z */ ALETTER,
+/* { */ SPECIAL,
+/* | */ ANY_CHAR,
+/* } */ SPECIAL,
+/* ~ */ SPECIAL,
+/* 127 */ ALETTER,
+/* 128 */ ALETTER,
+/* 129 */ ALETTER,
+/* 130 */ ALETTER,
+/* 131 */ ALETTER,
+/* 132 */ ALETTER,
+/* 133 */ ALETTER,
+/* 134 */ ALETTER,
+/* 135 */ ALETTER,
+/* 136 */ ALETTER,
+/* 137 */ ALETTER,
+/* 138 */ ALETTER,
+/* 139 */ ALETTER,
+/* 140 */ ALETTER,
+/* 141 */ ALETTER,
+/* 142 */ ALETTER,
+/* 143 */ ALETTER,
+/* 144 */ ALETTER,
+/* 145 */ ALETTER,
+/* 146 */ ALETTER,
+/* 147 */ ALETTER,
+/* 148 */ ALETTER,
+/* 149 */ ALETTER,
+/* 150 */ ALETTER,
+/* 151 */ ALETTER,
+/* 152 */ ALETTER,
+/* 153 */ ALETTER,
+/* 154 */ ALETTER,
+/* 155 */ ALETTER,
+/* 156 */ ALETTER,
+/* 157 */ ALETTER,
+/* 158 */ ALETTER,
+/* 159 */ ALETTER,
+/* 160 */ ALETTER,
+/* 161 */ ALETTER,
+/* 162 */ ALETTER,
+/* 163 */ ALETTER,
+/* 164 */ ALETTER,
+/* 165 */ ALETTER,
+/* 166 */ ALETTER,
+/* 167 */ ALETTER,
+/* 168 */ ALETTER,
+/* 169 */ ALETTER,
+/* 170 */ ALETTER,
+/* 171 */ ALETTER,
+/* 172 */ ALETTER,
+/* 173 */ ALETTER,
+/* 174 */ ALETTER,
+/* 175 */ ALETTER,
+/* 176 */ ALETTER,
+/* 177 */ ALETTER,
+/* 178 */ ALETTER,
+/* 179 */ ALETTER,
+/* 180 */ ALETTER,
+/* 181 */ ALETTER,
+/* 182 */ ALETTER,
+/* 183 */ ALETTER,
+/* 184 */ ALETTER,
+/* 185 */ ALETTER,
+/* 186 */ ALETTER,
+/* 187 */ ALETTER,
+/* 188 */ ALETTER,
+/* 189 */ ALETTER,
+/* 190 */ ALETTER,
+/* 191 */ ALETTER,
+/* 192 */ ALETTER,
+/* 193 */ ALETTER,
+/* 194 */ ALETTER,
+/* 195 */ ALETTER,
+/* 196 */ ALETTER,
+/* 197 */ ALETTER,
+/* 198 */ ALETTER,
+/* 199 */ ALETTER,
+/* 200 */ ALETTER,
+/* 201 */ ALETTER,
+/* 202 */ ALETTER,
+/* 203 */ ALETTER,
+/* 204 */ ALETTER,
+/* 205 */ ALETTER,
+/* 206 */ ALETTER,
+/* 207 */ ALETTER,
+/* 208 */ ALETTER,
+/* 209 */ ALETTER,
+/* 210 */ ALETTER,
+/* 211 */ ALETTER,
+/* 212 */ ALETTER,
+/* 213 */ ALETTER,
+/* 214 */ ALETTER,
+/* 215 */ ALETTER,
+/* 216 */ ALETTER,
+/* 217 */ ALETTER,
+/* 218 */ ALETTER,
+/* 219 */ ALETTER,
+/* 220 */ ALETTER,
+/* 221 */ ALETTER,
+/* 222 */ ALETTER,
+/* 223 */ ALETTER,
+/* 224 */ ALETTER,
+/* 225 */ ALETTER,
+/* 226 */ ALETTER,
+/* 227 */ ALETTER,
+/* 228 */ ALETTER,
+/* 229 */ ALETTER,
+/* 230 */ ALETTER,
+/* 231 */ ALETTER,
+/* 232 */ ALETTER,
+/* 233 */ ALETTER,
+/* 234 */ ALETTER,
+/* 235 */ ALETTER,
+/* 236 */ ALETTER,
+/* 237 */ ALETTER,
+/* 238 */ ALETTER,
+/* 239 */ ALETTER,
+/* 240 */ ALETTER,
+/* 241 */ ALETTER,
+/* 242 */ ALETTER,
+/* 243 */ ALETTER,
+/* 244 */ ALETTER,
+/* 245 */ ALETTER,
+/* 246 */ ALETTER,
+/* 247 */ ALETTER,
+/* 248 */ ALETTER,
+/* 249 */ ALETTER,
+/* 250 */ ALETTER,
+/* 251 */ ALETTER,
+/* 252 */ ALETTER,
+/* 253 */ ALETTER,
+/* 254 */ ALETTER,
+/* 255 */ ALETTER
+};
+
+
+
+
diff --git a/private/utils/ntbackup/inc/part.h b/private/utils/ntbackup/inc/part.h
new file mode 100644
index 000000000..cfd7398a6
--- /dev/null
+++ b/private/utils/ntbackup/inc/part.h
@@ -0,0 +1,75 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: part.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+ Location:
+
+
+ $Log: G:/LOGFILES/PART.H_V $
+ *
+ * Rev 1.0 09 May 1991 13:32:22 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef _part_h_
+#define _part_h_
+
+
+#define BAD_SECTOR_PATTERN_SIZE 16
+#define PART_NAME_SIZE 16
+
+extern CHAR bad_sector_pattern[];
+
+INT16 PartitionOperation( INT16 mode,
+ INT16 drive,
+ LOCAL_IMAGE_DLE_INFO_PTR part_info,
+ UINT32 offset, /* from the start of the partition */
+ UINT8_PTR buff,
+ UINT8_PTR split_buf,
+ UINT16 length,
+ UINT16_PTR bytes_done );
+
+#define READ_PARTITION_MODE 0
+#define WRITE_PARTITION_MODE 1
+
+
+typedef struct PART_TAB {
+ UINT8 boot ;
+ UINT8 head_start ;
+ UINT8 sec_start ;
+ UINT8 cyl_start ;
+ UINT8 sys_ind ;
+ UINT8 head_end ;
+ UINT8 sec_end ;
+ UINT8 cyl_end ;
+ UINT32 start_rel ;
+ UINT32 num_sectors ;
+} PART_TAB, *PART_TAB_PTR;
+
+#define MAX_BUF_SIZE (4*1024)
+#define SMALLEST_SECTOR_SIZE 128
+
+CHAR d_info( INT16 *no_flop, INT16 *no_hard, INT16 *no_dos ) ;
+INT16 GetPartitionTable( CHAR drive, UINT16 *sector_size, PART_TAB_PTR part_tab ) ;
+VOID GetDriveParm( CHAR drive, INT16 *num_heads, INT16 *num_cyl, INT16 *num_sect ) ;
+UINT16 Find64KBound( CHAR_PTR buf, UINT16 size );
+UINT16 OffsetLocation( UINT32 offset,
+ LOCAL_IMAGE_DLE_INFO_PTR part_info,
+ UINT16_PTR sector,
+ UINT16_PTR head,
+ UINT16_PTR cyl );
+
+#define BAD_BLOCK_MAP 1
+#define GOOD_BLOCK 2
+#define BAD_BLOCK 3
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/password.h b/private/utils/ntbackup/inc/password.h
new file mode 100644
index 000000000..d712857b7
--- /dev/null
+++ b/private/utils/ntbackup/inc/password.h
@@ -0,0 +1,84 @@
+/************************
+Copyright (c) Maynard, an Archive Company. 1991
+
+ Name: password.h
+
+ Description: This file contains the definitions, macros, and function
+ for passwords for tapes and backup sets.
+
+ $Log: G:/UI/LOGFILES/PASSWORD.H_V $
+
+ Rev 1.10 20 Jan 1993 19:55:38 MIKEP
+fix nt warning
+
+ Rev 1.9 04 Oct 1992 19:48:38 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.8 30 Sep 1992 10:46:52 DAVEV
+Unicode strlen verification, MikeP's chgs from MS
+
+ Rev 1.7 06 Feb 1992 17:43:40 JOHNWT
+moved pwdb things to appdefs.h
+
+ Rev 1.6 06 Jan 1992 13:50:16 JOHNWT
+changes for remove pw protecton
+
+ Rev 1.5 23 Dec 1991 15:50:34 JOHNWT
+PW for PWDB II
+
+ Rev 1.4 16 Dec 1991 15:54:22 JOHNWT
+added parent window to EnterDBPassword
+
+ Rev 1.3 14 Dec 1991 13:48:30 JOHNWT
+changes for pw to enable pwdb
+
+ Rev 1.2 04 Dec 1991 17:54:50 MIKEP
+add fid to password queue
+
+**************************/
+
+#ifndef PSWD_H
+#define PSWD_H
+
+// defines login password database
+
+#define DBPW_NOT_VERIFIED 0 /* PWDB lock pw has not been verified */
+#define DBPW_VERIFIED 1 /* PWDB lock pw verified or no lock */
+#define DBPW_LOCKOUT 2 /* exceeded max attempts at lock pw */
+
+#define DBPW_ALLOW_NEW 0 /* allow input of new lock password */
+#define DBPW_NO_NEW 1 /* do not allow new lock password */
+
+#define MAX_ATTEMPTS 3 /* allow max of 3 bad entries */
+
+// The structure for tape passwords.
+
+typedef struct pswd_object {
+ Q_ELEM q_elem;
+ UINT32 tape_fid;
+ UINT16 encrypt_algor;
+ UINT16 cbPasswordSize; /* byte length of password w/o NULL term*/
+ CHAR achPassword[ MAX_TAPE_PASSWORD_LEN ]; /* NOT NULL TERMINATED!*/
+} PSWD_OBJECT, *PSWD_OBJECT_PTR;
+
+PSWD_OBJECT_PTR PSWD_GetFirstPSWD( VOID );
+PSWD_OBJECT_PTR PSWD_GetNextPSWD( PSWD_OBJECT_PTR );
+
+INT16 PSWD_CheckForPassword( UINT32, INT16 );
+
+INT16 PSWD_AddPassword( INT8_PTR, INT16, UINT16, UINT32 );
+INT16 PSWD_InitPSWDList( VOID );
+INT16 PSWD_FreePSWDList( VOID );
+
+VOID SaveDLEPassword( CDS_PTR, GENERIC_DLE_PTR, CHAR_PTR, CHAR_PTR ) ;
+INT16 CheckThePWDBase( CDS_PTR, GENERIC_DLE_PTR );
+INT16 EnterDBPassword( CDS_PTR, HWND, INT );
+BOOLEAN IsThereADBPassword( VOID );
+INT16 SavePassword( CDS_PTR, CHAR_PTR, CHAR_PTR );
+
+BOOLEAN CollectTapePassword( INT8_PTR, INT16_PTR, UINT16, INT8_PTR, INT16 ) ;
+BOOLEAN VerifyTapePassword( CHAR_PTR, CHAR_PTR, CHAR_PTR, UINT16, INT8_PTR, INT16, INT8_PTR, INT16, UINT32 ) ;
+VOID CryptPassword( INT16, UINT16, INT8_PTR, INT16 ) ;
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/pchstop.h b/private/utils/ntbackup/inc/pchstop.h
new file mode 100644
index 000000000..aede1d3d9
--- /dev/null
+++ b/private/utils/ntbackup/inc/pchstop.h
@@ -0,0 +1,25 @@
+
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: pchstop.h
+
+ Description: Precompiled Header terminator
+
+ $Log: G:/UI/LOGFILES/PCHSTOP.H_V $
+
+ Rev 1.0 20 Oct 1992 14:21:04 GLENN
+Initial revision.
+
+******************************************************************************/
+
+
+
+#ifndef PCHSTOP_H
+
+#define PCHSTOP_H
+
+
+#endif
diff --git a/private/utils/ntbackup/inc/pdtypes.h b/private/utils/ntbackup/inc/pdtypes.h
new file mode 100644
index 000000000..65ebca5b8
--- /dev/null
+++ b/private/utils/ntbackup/inc/pdtypes.h
@@ -0,0 +1,79 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: pdtypes.h
+
+ Description: Defines and prototypes for Password Database Unit
+
+
+ $Log: G:/UI/LOGFILES/PDTYPES.H_V $
+
+ Rev 1.2 04 Oct 1992 19:48:40 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.1 18 Mar 1992 16:58:58 JOHNWT
+changes for new passdb.c
+
+ Rev 1.0 20 Nov 1991 19:37:34 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifndef PDTYPES
+
+#define PDTYPES
+
+#include "StdTypes.H"
+
+
+/* Define Maximum sizes */
+
+#define MINIMUM_RECORD_LEN 4
+#define MAX_KEY_LEN 96
+#define MAX_PSWD_LEN 176
+#define MAX_KEY_SIZE MAX_KEY_LEN +1
+#define MAX_PSWD_SIZE MAX_PSWD_LEN +1
+#define MAX_PSWD_RECORD_SIZE MAX_KEY_SIZE + MAX_PSWD_SIZE +1
+
+
+/* The Password Database Record format */
+/*
+** key_name'\0'password_sizepassword_namepadding to max_pswd_record_size
+*/
+
+/* Define error codes returned by the Password Database Interface */
+
+#define PD_NO_ERROR 0
+#define PD_FILE_OPEN_ERROR -300
+#define PD_READ_ERROR -301
+#define PD_NOT_FOUND -302
+#define PD_FULL -303
+#define PD_NULL_HANDLE -304
+#define PD_CLOSE_ERROR -305
+#define PD_WRITE_ERROR -306
+#define PD_MEMORY_ERROR -307
+#define PD_EXCEEDED_RECORD_LENGTH -308
+
+
+/* Structures for the Password Database Interface */
+typedef struct {
+ FILE *fhand ; /* file handle for PWD file */
+ INT32 record_number ; /* record number to seek */
+ CHAR buffer[MAX_PSWD_RECORD_SIZE] ; /* current buffer */
+} DB_HAND, *DB_HAND_PTR ;
+
+
+/* The following prototypes are for the entry points to the Password Database */
+
+/* Open and Close the password database */
+UINT16 PD_Open( DB_HAND_PTR fhand, CHAR_PTR db_name ) ;
+UINT16 PD_Close( DB_HAND_PTR fhand ) ;
+
+/* Read a password from the database and pass it back to the caller */
+INT16 PD_Read( DB_HAND_PTR fhand, CHAR_PTR key, CHAR_PTR pswd ) ;
+
+/* Update the database with a new password */
+UINT16 PD_Write( DB_HAND_PTR fhand, CHAR_PTR key, CHAR_PTR pswd ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/polldrv.h b/private/utils/ntbackup/inc/polldrv.h
new file mode 100644
index 000000000..99e3680ce
--- /dev/null
+++ b/private/utils/ntbackup/inc/polldrv.h
@@ -0,0 +1,71 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: polldrv.h
+
+ Description: This file contains the definitions, macros, and function
+ prototypes for the poll drive manager (PD).
+
+ $Log: G:/UI/LOGFILES/POLLDRV.H_V $
+
+ Rev 1.6 23 Sep 1993 15:49:52 GLENN
+Changed return type on stop polling.
+
+ Rev 1.5 21 Jul 1993 17:02:50 GLENN
+Added PD_WaitUntilSettled () function to wait until poll drive is in a settled state.
+
+ Rev 1.4 16 Jun 1993 16:37:58 GLENN
+Added PD_IsPollDriveBusy().
+
+ Rev 1.3 05 Nov 1992 15:32:36 GLENN
+Changed the default timer delay to 1 second.
+
+ Rev 1.2 04 Oct 1992 19:48:42 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.1 31 Jan 1992 12:53:54 GLENN
+Added polldrive and eject retry stuff.
+
+ Rev 1.0 20 Nov 1991 19:37:54 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+
+#ifndef _POLLDRIVE_H
+#define _POLLDRIVE_H
+
+
+
+#define PD_TIMERDELAY 1 // 1 second
+#define PD_MAX_EJECT_ATTEMPTS 5
+#define PD_MAX_RESTART_ATTEMPTS 2
+
+#define PD_SETTLE_NOCALLBACK 0
+#define PD_SETTLE_NOWAIT 0
+
+#define PD_SETTLE_OK 0
+#define PD_SETTLE_TIMEOUT 1
+#define PD_SETTLE_ERROR 2
+#define PD_SETTLE_NOTINITIALIZED 3
+#define PD_SETTLE_ALREADYWAITING 4
+#define PD_SETTLE_UNKNOWN 5
+
+// FUNCTION PROTOTYPES
+
+BOOL PD_Init ( VOID );
+BOOL PD_Deinit ( VOID );
+BOOL PD_StartPolling ( VOID );
+VOID PD_PollDrive ( VOID );
+BOOL PD_StopPolling ( VOID );
+BOOL PD_AttemptRestart ( VOID );
+VOID PD_EjectTape ( VOID );
+INT PD_SetFrequency ( INT );
+BOOL PD_AttemptRestart ( VOID );
+BOOL PD_IsPollDriveBusy ( VOID );
+INT PD_WaitUntilSettled ( PF_VOID, INT );
+
+
+#endif
diff --git a/private/utils/ntbackup/inc/portdefs.h b/private/utils/ntbackup/inc/portdefs.h
new file mode 100644
index 000000000..1bcc97f27
--- /dev/null
+++ b/private/utils/ntbackup/inc/portdefs.h
@@ -0,0 +1,478 @@
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+DAVEV
+
+ Name: portdefs.h
+
+ Description: This file contains common types, etc., necessary for
+ modules to compile with the GUI sub-system
+ in a maner portable between 16 and 32 bit versions
+ of MS-Windows. It is included by the header file:
+ ss_gui.h.
+
+ This file will include the following header files:
+
+ stdtypes.h - Maynard's standard type defines
+
+ *** win3216 has been removed for Einstein ***
+
+ win3216.h - Microsoft's declarations for using
+ 32-bit Windows compatible functions,
+ etc., in a 16-bit application. Only
+ included for 16-bit compiles.
+
+ Note: Much of the definitions in this file are expected
+ to be included in a later release of WIN3216.H or in
+ the next release of the Windows 3.1 beta by Microsoft.
+ If this is the case, all duplicate definitions should
+ be removed from this file to avoid compiler warnings or
+ incorrect definitions.
+
+ $Log: G:/UI/LOGFILES/PORTDEFS.H_V $
+
+ Rev 1.24 05 Mar 1993 09:18:38 MIKEP
+remove macros now defined in NT
+
+ Rev 1.23 12 Feb 1993 15:35:44 STEVEN
+fix the last fix
+
+ Rev 1.22 09 Feb 1993 09:23:52 STEVEN
+remove extra define for MENUSELECT_FLAG
+
+ Rev 1.21 17 Nov 1992 21:42:34 DAVEV
+unicode changes
+
+ Rev 1.20 10 Nov 1992 09:31:42 STEVEN
+fix warnings
+
+ Rev 1.19 01 Nov 1992 16:32:08 DAVEV
+Unicode changes
+
+ Rev 1.18 26 Oct 1992 13:39:10 DAVEV
+fixes for typedefs
+
+ Rev 1.17 15 May 1992 09:00:38 MIKEP
+byte_ptr addition
+
+ Rev 1.16 14 May 1992 18:39:04 STEVEN
+moved _PTR type to stdtypes.h
+
+ Rev 1.15 04 May 1992 15:22:28 JOHNWT
+removed win3216.h for Einstein
+
+ Rev 1.14 28 Apr 1992 14:30:46 MIKEP
+_PTR additions
+
+ Rev 1.13 23 Apr 1992 10:13:22 DAVEV
+Added add'l Unicode/ASCII transparent types
+
+ Rev 1.12 29 Jan 1992 17:58:16 GLENN
+Fixed SET_WM_COMMAND... macro for windows.
+
+ Rev 1.11 15 Jan 1992 15:21:42 DAVEV
+16/32 bit port-2nd pass
+
+ Rev 1.10 14 Jan 1992 11:37:28 DAVEV
+removed hacks of dos_findfirst,etc.
+
+ Rev 1.9 08 Jan 1992 12:21:32 CHUCKB
+Took out include for win3216.h.
+
+ Rev 1.8 23 Dec 1991 16:34:36 DAVEV
+Latest NT changes
+
+ Rev 1.7 18 Dec 1991 12:01:50 DAVEV
+Added HACK dummy macros for _dos_findfirst/next
+
+ Rev 1.6 12 Dec 1991 17:11:30 DAVEV
+16/32 bit port -2nd pass
+
+ Rev 1.5 12 Dec 1991 11:37:02 DAVEV
+fixed WM_MDIACTIVATE macros
+
+ Rev 1.4 05 Dec 1991 17:39:38 GLENN
+Added VSCROLL and HSCROLL send messages
+
+ Rev 1.3 02 Dec 1991 17:58:06 DAVEV
+added WM_* msg macros
+
+ Rev 1.2 26 Nov 1991 09:26:22 DAVEV
+Added SEND_EM_SETSET_MSG & SEND_EM_LINESCROLL_MSG macros
+
+ Rev 1.1 22 Nov 1991 13:17:58 DAVEV
+Added MP1 & MP2 types for convience - less typing
+
+ Rev 1.6 20 Nov 1991 17:09:40 DAVEV
+Added definition of WNDPROC (FARPROC)
+
+ Rev 1.5 20 Nov 1991 15:08:08 DAVEV
+Added PM-style macros for packing MPARAM2 parameter values.
+
+ Rev 1.4 19 Nov 1991 12:50:20 DAVEV
+First revision.
+
+******************************************************************************/
+#ifndef PORTDEFS_INCL
+#define PORTDEFS_INCL
+
+/***************************************************************************/
+/* 16-BIT APPLICATION DEFINITIONS */
+/*-------------------------------------------------------------------------*/
+/* The following code is included ONLY if compiling 16-bit */
+/* application version. */
+/***************************************************************************/
+
+#ifndef OS_WIN32 //start of non-OS_WIN32 stuff -----------------------------
+
+//
+// Macros used to eliminate compiler warning generated when formal
+// parameters or local variables are not declared.
+//
+// Use DBG_UNREFERENCED_PARAMETER() when a parameter is not yet
+// referenced but will be once the module is completely developed.
+//
+// Use DBG_UNREFERENCED_LOCAL_VARIABLE() when a local variable is not yet
+// referenced but will be once the module is completely developed.
+//
+// Use UNREFERENCED_PARAMETER() if a parameter will never be referenced.
+//
+// DBG_UNREFERENCED_PARAMETER and DBG_UNREFERENCED_LOCAL_VARIABLE will
+// eventually be made into a null macro to help determine whether there
+// is unfinished work.
+//
+
+#define UNREFERENCED_PARAMETER(p) ((p)=(p))
+#define DBG_UNREFERENCED_PARAMETER(p) ((p)=(p))
+#define DBG_UNREFERENCED_LOCAL_VARIABLE(p) ((p)=(p))
+
+#include "stdtypes.h"
+
+
+
+//---------------------------------------------------------
+// The following are new type defines to simplify porting
+//---------------------------------------------------------
+
+//Window and Dialog procedure parameter and return types
+
+#define MSGID UINT //Message identifier
+#define MPARAM1 UINT //First parameter (previously a WORD type param)
+#define MPARAM2 LONG //Second parameter (previously a LONG type param)
+#define WINRESULT LONG //Window proc return value
+#define DLGRESULT INT //Dialog proc return value
+
+#define MP1 MPARAM1 //Convience type - less typing
+#define MP2 MPARAM2 //Convience type - less typing
+
+
+// Macros for stuffing data into window message parameters...
+
+// Only macros for MP2 are supported for Win 3.x
+
+#define MP2FROMPVOID(p) ((MP2)(p))
+#define MP2FROMHWND(p) ((MP2)(p))
+#define MP2FROMLONG(l) (l)
+#define MP2FROMSHORT(s) ((MP2)(s))
+#define MP2FROM2SHORT(s1,s2) MAKELONG(s1,s2)
+//
+// Macros used to access message parameters for messages which
+// use different parameter packing between 32-bit and 16-bit versions
+// of Windows.
+// These will (hopefully) be provided by future releases of Win32 &
+// Win 3.1. However, the macro name may be different since only the
+// names of the WM_COMMAND macros where explicitly stated in the
+// Microsoft Win 3.0 to Win32 porting document.
+//
+#define GET_WM_ACTIVE_STATE(mp1,mp2) LOWORD(mp1)
+#define GET_WM_ACTIVE_FMINIMIZED(mp1,mp2) LOWORD(mp2)
+#define GET_WM_ACTIVE_HWND(mp1,mp2) HIWORD(mp2)
+
+#define GET_WM_CHARTOITEM_CHAR(mp1,mp2) LOWORD(mp1)
+#define GET_WM_CHARTOITEM_POS(mp1,mp2) LOWORD(mp2)
+#define GET_WM_CHARTOITEM_HWND(mp1,mp2) HIWORD(mp2)
+
+#define GET_WM_COMMAND_ID(mp1,mp2) LOWORD(mp1)
+#define GET_WM_COMMAND_CMD(mp1,mp2) HIWORD(mp2)
+#define GET_WM_COMMAND_HWND(mp1,mp2) LOWORD(mp2)
+
+#define SET_WM_COMMAND_PARAMS(id,cmd,hwnd,mp1,mp2) ((mp1=(MP1)(id)),(mp2=(MP2)MAKELONG(hwnd,cmd)))
+
+#define GET_WM_MENUSELECT_ID(mp1,mp2) LOWORD(mp1)
+#define GET_WM_MENUSELECT_FLAGS(mp1,mp2) LOWORD(mp2)
+
+#define GET_WM_MDISETMENU_HMENUFRAME(mp1,mp2) LOWORD(mp2)
+#define GET_WM_MDISETMENU_HMENUWINDOW(mp1,mp2) HIWORD(mp2)
+
+#define GET_WM_MENUCHAR_CHAR(mp1,mp2) LOWORD(mp1)
+#define GET_WM_MENUCHAR_HMENU(mp1,mp2) LOWORD(mp2)
+#define GET_WM_MENUCHAR_FMENU(mp1,mp2) HIWORD(mp2)
+
+#define GET_WM_PARENTNOTIFY_MSG(mp1,mp2) LOWORD(mp1)
+// The following 2 are only used if msg is WM_CREATE or WM_DESTROY
+#define GET_WM_PARENTNOTIFY_ID(mp1,mp2) LOWORD(mp2)
+#define GET_WM_PARENTNOTIFY_HWNDCHILD(mp1,mp2) HIWORD(mp2)
+// otherwise use these 2 macros to extract x & y cursor coords.
+#define GET_WM_PARENTNOTIFY_X(mp1,mp2) LOWORD(mp2)
+#define GET_WM_PARENTNOTIFY_Y(mp1,mp2) HIWORD(mp2)
+
+
+#define GET_WM_VKEYTOITEM_CODE(mp1,mp2) LOWORD(mp1)
+#define GET_WM_VKEYTOITEM_ITEM(mp1,mp2) LOWORD(mp2)
+#define GET_WM_VKEYTOITEM_HWND(mp1,mp2) HIWORD(mp2)
+
+//Note: Under Windows 3.x, WM_GETSEL both of the following
+// parameters will always be NULL. Under NT, these may
+// be NULL or valid pointers to double word (LONG) values
+#define GET_WM_GETSEL_PSTART(mp1,mp2) NULL
+#define GET_WM_GETSEL_PEND(mp1,mp2) NULL
+
+#define GET_WM_LINESCROLL_NLINESVERT(mp1,mp2) LOWORD(mp2)
+#define GET_WM_LINESCROLL_NLINESHORZ(mp1,mp2) HIWORD(mp2)
+
+#define GET_WM_SETSEL_START(mp1,mp2) LOWORD(mp2)
+#define GET_WM_SETSEL_END(mp1,mp2) HIWORD(mp2)
+
+
+#define GET_WM_HSCROLL_CODE(mp1,mp2) LOWORD(mp1)
+#define GET_WM_HSCROLL_POS(mp1,mp2) LOWORD(mp2)
+#define GET_WM_HSCROLL_HWND(mp1,mp2) HIWORD(mp2)
+
+#define GET_WM_VSCROLL_CODE(mp1,mp2) LOWORD(mp1)
+#define GET_WM_VSCROLL_POS(mp1,mp2) LOWORD(mp2)
+#define GET_WM_VSCROLL_HWND(mp1,mp2) HIWORD(mp2)
+
+#define GET_WM_MDIACTIVATE_DEACTIVATE(mp1,mp2) HIWORD(mp2)
+#define GET_WM_MDIACTIVATE_ACTIVATE(mp1,mp2) LOWORD(mp2)
+
+// DDE message parameters - NOTE: DDE is not supported in the current
+// release of NT. Therefore, these macros may be coded but should not
+// be allowed to executed in the NT version until a DDE supporting
+// release is recieved.
+
+#define GET_WM_DDE_ACK_HWND(mp1,mp2) LOWORD(mp1)
+//TOPIC and APPL are recieved as a response to a WM_DDE_INITIATE only.
+#define GET_WM_DDE_ACK_APPL(mp1,mp2) LOWORD(mp2)
+#define GET_WM_DDE_ACK_TOPIC(mp1,mp2) HIWORD(mp2)
+
+//STATUS is recieved as a response to all other messages
+#define GET_WM_DDE_ACK_STATUS(mp1,mp2) LOWORD(mp2)
+
+//COMMANDS is recieved as a response to WM_DDE_EXECUTE only.
+#define GET_WM_DDE_ACK_COMMANDS(mp1,mp2) HIWORD(mp2)
+
+//ITEM is recieved as a response to all other messages
+#define GET_WM_DDE_ACK_ITEM(mp1,mp2) HIWORD(mp2)
+//---------------------------------------------------------------
+
+#define GET_WM_DDE_ADVISE_HWND(mp1,mp2) LOWORD(mp1)
+#define GET_WM_DDE_ADVISE_OPTIONS(mp1,mp2) LOWORD(mp2)
+#define GET_WM_DDE_ADVISE_ITEM(mp1,mp2) HIWORD(mp2)
+
+#define GET_WM_DDE_DATA_HWND(mp1,mp2) LOWORD(mp1)
+#define GET_WM_DDE_DATA_DATA(mp1,mp2) LOWORD(mp2)
+#define GET_WM_DDE_DATA_ITEM(mp1,mp2) HIWORD(mp2)
+
+#define GET_WM_DDE_POKE_HWND(mp1,mp2) LOWORD(mp1)
+#define GET_WM_DDE_POKE_DATA(mp1,mp2) LOWORD(mp2)
+#define GET_WM_DDE_POKE_ITEM(mp1,mp2) HIWORD(mp2)
+
+
+// Use these macros to send or post the appropriate message:
+// Example:
+//
+// Old 16-bit code:
+// SendDlgItemMessage( hDlg, id, EM_SETSEL, 0, MAKELONG ( start,end ));
+//
+// New portable code:
+// SEND_EM_SETSEL_MSG( hDlg, id, start, end );
+//
+
+#define SEND_EM_SETSEL_MSG(hDlg,id,nStart,nEnd) \
+ SendDlgItemMessage(hDlg,id,EM_SETSEL,0,MAKELONG(nStart,nEnd))
+
+#define SEND_EM_LINESCROLL_MSG(hDlg,id,nLinesVert,nLinesHorz) \
+ SendDlgItemMessage(hDlg,id,EM_LINESCROLL,0,MAKELONG(nLinesVert,nLinesHorz))
+
+#define SEND_WM_MENUSELECT_MSG(hwnd,item,flags,hMenu) \
+ SendMessage (hwnd,WM_MENUSELECT,item,MAKELONG (flags,hMenu))
+
+#define POST_WM_COMMAND_MSG(hwndTo,idFrom,hwndFrom,cmd) \
+ PostMessage (hwndTo,WM_COMMAND,idFrom,MAKELONG(hwndFrom,cmd))
+
+#define SEND_WM_VSCROLL_MSG(hwndTo,code,pos,hwndFrom) \
+ SendMessage (hwndTo,WM_VSCROLL,code,MAKELONG(pos,hwndFrom))
+
+#define SEND_WM_HSCROLL_MSG(hwndTo,code,pos,hwndFrom) \
+ SendMessage (hwndTo,WM_HSCROLL,code,MAKELONG(pos,hwndFrom))
+
+/***************************************************************************/
+/* 32-BIT APPLICATION DEFINITIONS */
+/*-------------------------------------------------------------------------*/
+/* The following code is included ONLY if compiling 32-bit */
+/* application version. (Win32 or NT) */
+/***************************************************************************/
+
+// NOTE: the following marcos are now available in PTYPES32.H
+// - which is now being included - and are now commented out below:
+/*
+ GET_WM_CHARTOITEM_CHAR
+ GET_WM_CHARTOITEM_HWND
+ GET_WM_COMMAND_HWND
+ GET_WM_MENUCHAR_CHAR
+ GET_WM_MENUCHAR_HMENU
+ GET_WM_MENUCHAR_FMENU
+ GET_WM_PARENTNOTIFY_MSG
+ GET_WM_PARENTNOTIFY_ID
+ GET_WM_PARENTNOTIFY_HWNDCHILD
+ GET_WM_PARENTNOTIFY_X
+ GET_WM_PARENTNOTIFY_Y
+ GET_WM_VKEYTOITEM_CODE
+ GET_WM_VKEYTOITEM_HWND
+ GET_WM_HSCROLL_HWND
+ GET_WM_VSCROLL_HWND
+ GET_WM_DDE_ACK_STATUS
+ GET_WM_DDE_ACK_ITEM
+ GET_WM_DDE_ADVISE_ITEM
+ GET_WM_DDE_DATA_ITEM
+ GET_WM_DDE_POKE_ITEM
+*/
+
+#else //OS_WIN32
+
+#include "stdtypes.h"
+
+
+//---------------------------------------------------------
+// The following are new type defines to simplify porting
+//---------------------------------------------------------
+
+//Window and Dialog procedure parameter and return types
+
+#define MSGID UINT //Message identifier
+#define MPARAM1 WPARAM //First parameter (previously a WORD type param)
+#define MPARAM2 LPARAM //Second parameter (previously a LONG type param)
+#define WINRESULT LRESULT //Window proc return value
+#define DLGRESULT INT //Dialog proc return value
+
+#define MP1 MPARAM1 //Convience type - less typing
+#define MP2 MPARAM2 //Convience type - less typing
+
+
+// Macros for stuffing data into window message parameters...
+
+#define MP1FROM2SHORT(a,b) \
+ ((MP1)(((WORD)(a)) | ((UINT)((WORD)(b))) << 16))
+
+#define MP2FROMPVOID(p) ((MP2)(p))
+#define MP2FROMHWND(p) ((MP2)(p))
+#define MP2FROMLONG(l) (l)
+#define MP2FROMSHORT(s) ((MP2)(s))
+#define MP2FROM2SHORT(s1,s2) MAKELONG(s1,s2)
+//
+// Macros used to access message parameters for messages which
+// use different parameter packing between 32-bit and 16-bit versions
+// of Windows.
+// These will (hopefully) be provided by future releases of Win32 &
+// Win 3.1. However, the macro name may be different since only the
+// names of the WM_COMMAND macros where explicitly stated in the
+// Microsoft Win 3.0 to Win32 porting document.
+//
+#define GET_WM_ACTIVE_STATE(mp1,mp2) LOWORD(mp1)
+#define GET_WM_ACTIVE_FMINIMIZED(mp1,mp2) HIWORD(mp1)
+#define GET_WM_ACTIVE_HWND(mp1,mp2) ((HWND)(mp2))
+
+#define SET_WM_COMMAND_PARAMS(id,cmd,hwnd,mp1,mp2) (mp1=(MP1)(id|cmd<<16),mp2=(MP2)hwnd)
+
+#define GET_WM_MENUSELECT_ID(mp1,mp2) LOWORD(mp1)
+
+#define GET_WM_MDIACTIVATE_DEACTIVATE(mp1,mp2) ((HWND)(mp1))
+#define GET_WM_MDIACTIVATE_ACTIVATE(mp1,mp2) ((HWND)(mp2))
+
+#define GET_WM_MDISETMENU_HMENUFRAME(mp1,mp2) ((HWND)(mp1))
+#define GET_WM_MDISETMENU_HMENUWINDOW(mp1,mp2) ((HWND)(mp2))
+
+//Note: Under Windows 3.x, WM_GETSEL both of the following
+// parameters will always be NULL. Under NT, these may
+// be NULL or valid pointers to double word (LONG) values
+#define GET_WM_GETSEL_PSTART(mp1,mp2) ((LPLONG)(mp1))
+#define GET_WM_GETSEL_PEND(mp1,mp2) ((LPLONG)(mp2))
+
+#define GET_WM_LINESCROLL_NLINESVERT(mp1,mp2) ((INT)(mp1))
+#define GET_WM_LINESCROLL_NLINESHORZ(mp1,mp2) ((INT)(mp2))
+
+#define GET_WM_SETSEL_START(mp1,mp2) ((INT)(mp1))
+#define GET_WM_SETSEL_END(mp1,mp2) ((INT)(mp2))
+
+
+// DDE message parameters - NOTE: DDE is not supported in the current
+// release of NT. Therefore, these macros may be coded but should not
+// be allowed to executed in the NT version until a DDE supporting
+// release is recieved.
+
+#define GET_WM_DDE_ACK_HWND(mp1,mp2) ((HWND)(mp1))
+//TOPIC and APPL are recieved as a response to a WM_DDE_INITIATE only.
+#define GET_WM_DDE_ACK_APPL(mp1,mp2) LOWORD(mp2)
+#define GET_WM_DDE_ACK_TOPIC(mp1,mp2) HIWORD(mp2)
+
+//STATUS is recieved as a response to all other messages
+/*#define GET_WM_DDE_ACK_STATUS(mp1,mp2) \
+ ((PDDEACKSTRUCT)(mp2)->wStatus)*/
+
+//COMMANDS is recieved as a response to WM_DDE_EXECUTE only.
+#define GET_WM_DDE_ACK_COMMANDS(mp1,mp2) \
+ ((PDDEACKSTRUCT)(mp2)->aItemORhCommands)
+
+//ITEM is recieved as a response to all other messages
+/*#define GET_WM_DDE_ACK_ITEM(mp1,mp2) \
+ ((PDDEACKSTRUCT)(mp2)->aItemORhCommands)*/
+//---------------------------------------------------------------
+
+#define GET_WM_DDE_ADVISE_HWND(mp1,mp2) ((HWND)(mp1))
+#define GET_WM_DDE_ADVISE_OPTIONS(mp1,mp2) \
+ ((PDDEADVISESTRUCT)(mp2)->hOptions)
+/*#define GET_WM_DDE_ADVISE_ITEM(mp1,mp2) \
+ ((PDDEADVISESTRUCT)(mp2)->aItem)*/
+
+#define GET_WM_DDE_DATA_HWND(mp1,mp2) ((HWND)(mp1))
+#define GET_WM_DDE_DATA_DATA(mp1,mp2) \
+ ((PDDEDATASTRUCT)(mp2)->hData)
+/*#define GET_WM_DDE_DATA_ITEM(mp1,mp2) \
+ ((PDDEDATASTRUCT)(mp2)->hItem)*/
+
+#define GET_WM_DDE_POKE_HWND(mp1,mp2) ((HWND)(mp1))
+#define GET_WM_DDE_POKE_DATA(mp1,mp2) \
+ ((PDDEPOKESTRUCT)(mp2)->hData)
+/*#define GET_WM_DDE_POKE_ITEM(mp1,mp2) \
+ ((PDDEPOKESTRUCT)(mp2)->hItem)*/
+
+
+// Use these macros to send or post the appropriate message:
+// Example:
+//
+// Old 16-bit code:
+// SendDlgItemMessage( hDlg, id, EM_SETSEL, 0, MAKELONG ( start,end ));
+//
+// New portable code:
+// SEND_EM_SETSEL_MSG( hDlg, id, start, end );
+//
+#define SEND_EM_SETSEL_MSG(hDlg,id,nStart,nEnd) \
+ SendDlgItemMessage(hDlg,id,EM_SETSEL,(MP1)(nStart),(MP2)(nEnd))
+
+#define SEND_EM_LINESCROLL_MSG(hDlg,id,nLinesVert,nLinesHorz) \
+ SendDlgItemMessage(hDlg,id,EM_LINESCROLL,(MP1)(nLinesVert),(MP2)(nLinesHorz))
+
+#define SEND_WM_MENUSELECT_MSG(hwnd,item,flags,hMenu) \
+ SendMessage (hwnd,WM_MENUSELECT,MP1FROM2SHORT (item,flags),(MP2)(hMenu))
+
+#define POST_WM_COMMAND_MSG(hwndTo,idFrom,hwndFrom,cmd) \
+ PostMessage (hwndTo,WM_COMMAND,MP1FROM2SHORT(idFrom,cmd),(MP2)(hwndFrom))
+
+#define SEND_WM_VSCROLL_MSG(hwndTo,code,pos,hwndFrom) \
+ SendMessage (hwndTo,WM_VSCROLL,MP1FROM2SHORT(code,pos),(MP2)(hwndFrom))
+
+#define SEND_WM_HSCROLL_MSG(hwndTo,code,pos,hwndFrom) \
+ SendMessage (hwndTo,WM_HSCROLL,MP1FROM2SHORT(code,pos),(MP2)(hwndFrom))
+
+#endif //OS_WIN32
+
+#endif //PORTDEFS_INCL
diff --git a/private/utils/ntbackup/inc/proddefs.h b/private/utils/ntbackup/inc/proddefs.h
new file mode 100644
index 000000000..ca15c1264
--- /dev/null
+++ b/private/utils/ntbackup/inc/proddefs.h
@@ -0,0 +1,368 @@
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: PRODDEFS.h
+
+ Description: This file includes PRODUCT SPECIFIC definitions.
+
+ $Log: G:\UI\LOGFILES\PRODDEFS.H_V $
+
+ Rev 1.68 14 Jan 1994 14:42:20 Glenn
+Name changes once again.
+
+ Rev 1.67 07 Jan 1994 11:00:06 mikep
+change CAYMAN ifdef to os_win32
+
+ Rev 1.66 22 Dec 1993 15:11:42 GLENN
+The names were changed to protect the innocent.
+
+ Rev 1.65 17 Dec 1993 15:31:28 KEVINS
+Added the loader DLL.
+
+ Rev 1.64 22 Nov 1993 11:42:34 BARRY
+Unicode fixes: added TEXT macros around all literals
+
+ Rev 1.63 22 Aug 1993 20:26:28 MIKEP
+fix WFW redef warning
+
+ Rev 1.62 16 Aug 1993 13:57:08 BARRY
+Don't turn on WFW unconditionally (and for the lack of a better way now,
+made it based on OEM_MSOFT). Added long app name for NTBackup.
+
+
+ Rev 1.61 11 Aug 1993 11:39:44 Aaron
+Moved Bimini version info to separate "version.h"
+
+ Rev 1.60 22 Jul 1993 17:48:02 GLENN
+Added LONGAPPNAME, RESFILENAME, READMEFILENAME, LCHFILENAME for support of INSTALL and TAPE SOFTWARE ID.
+
+ Rev 1.59 08 Jun 1993 09:10:02 DARRYLP
+Added email support.
+
+ Rev 1.58 10 May 1993 14:06:08 MIKEP
+chnage ntbackup.hlp to backup.hlp because microsoft is lazy.
+
+ Rev 1.57 29 Apr 1993 18:19:26 Aaron
+Cleaned up
+
+ Rev 1.56 27 Apr 1993 16:31:30 CHUCKB
+Changed occurrances of ntbackup back to backup (except for file names).
+
+ Rev 1.55 27 Apr 1993 14:59:14 CHUCKB
+1. Made name of applet NTBackup
+2. Took out all references to the word 'beta'
+3. Changed any file names in the form BACKUP.xxx to NTBACKUP.xxx
+
+ Rev 1.54 09 Apr 1993 14:13:40 GLENN
+Added BETA to the title, menu, aboutbox strings.
+
+ Rev 1.53 05 Apr 1993 16:19:54 GLENN
+Added elipses to all about menu item strings.
+
+ Rev 1.52 01 Apr 1993 17:00:22 GLENN
+Changed the name to Conner Backup Exec. Updated the copyright stuff.
+
+ Rev 1.51 25 Mar 1993 13:04:12 chrish
+Made changes for the new naming convention for bewinnt.
+
+ Rev 1.50 25 Feb 1993 13:44:40 STEVEN
+fix copyright for nost
+
+ Rev 1.49 22 Feb 1993 11:35:02 chrish
+Added stuff for CAYMAN NT. Also added a minor change received from MikeP (
+Added the "..." to the menu item for "About backup", so it reads
+"About backup ...".
+
+ Rev 1.48 18 Feb 1993 13:48:14 BURT
+Changes for Cayman
+
+
+ Rev 1.47 11 Dec 1992 17:34:30 GLENN
+Changed Tape Backup to just Backup for NT.
+
+ Rev 1.46 19 Nov 1992 14:40:42 GLENN
+Removed sales pitch stuff.
+
+ Rev 1.45 12 Nov 1992 15:00:58 MIKEP
+remove text macro
+
+ Rev 1.44 05 Nov 1992 17:23:58 DAVEV
+fix ts
+
+ Rev 1.42 30 Oct 1992 15:50:42 GLENN
+Fixed the WFW problem. NOTE: add defines only to the product section. (BIMINI, CAYMAN, etc...)
+
+ Rev 1.41 28 Oct 1992 10:12:36 DARRYLP
+Added WFW define.
+
+ Rev 1.40 16 Oct 1992 15:59:48 GLENN
+Changed ER to Rev.
+
+ Rev 1.39 06 Oct 1992 15:50:54 DARRYLP
+Added WFW define.
+
+ Rev 1.38 04 Oct 1992 19:48:46 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.37 30 Sep 1992 10:50:44 GLENN
+Updated
+
+ Rev 1.36 29 Sep 1992 11:04:12 GLENN
+Split out the version stuff for Microsoft and Archive.
+
+ Rev 1.35 22 Sep 1992 10:56:54 GLENN
+Removed the .BKS extension from FM_SCRIPT. The extension is now pulled from the common resources.
+
+ Rev 1.34 18 Sep 1992 17:28:44 GLENN
+Added file manager text support.
+
+ Rev 1.33 04 Sep 1992 18:09:34 CHUCKB
+Added new id's, etc., for sales pitch string.
+
+ Rev 1.32 06 Jul 1992 12:53:10 JOHNWT
+changed default name to Bimini
+
+ Rev 1.31 21 May 1992 15:04:36 MIKEP
+name changes
+
+ Rev 1.30 04 May 1992 15:21:24 JOHNWT
+update res ver
+
+ Rev 1.29 04 May 1992 13:09:50 JOHNWT
+update for Einstein
+
+ Rev 1.28 27 Apr 1992 16:21:00 JOHNWT
+added conglomerate
+
+ Rev 1.27 22 Apr 1992 17:58:14 GLENN
+Updated rev and took out BETA.
+
+ Rev 1.26 15 Apr 1992 16:48:08 GLENN
+Updated rev.
+
+ Rev 1.25 09 Apr 1992 11:35:52 GLENN
+Added support for exe/resource version stamping.
+
+ Rev 1.24 07 Apr 1992 15:47:10 GLENN
+Separated APP exe version, res version, eng release strings.
+
+ Rev 1.23 06 Apr 1992 13:55:32 GLENN
+Updated.
+
+ Rev 1.22 06 Apr 1992 12:36:44 CHUCKB
+Fixed company name per tech pubs.
+
+ Rev 1.21 02 Apr 1992 16:56:36 GLENN
+Updated.
+
+ Rev 1.20 30 Mar 1992 17:16:16 GLENN
+Updated.
+
+ Rev 1.19 25 Mar 1992 17:44:26 DAVEV
+OEM_MSOFT: Added product specific defines section
+
+ Rev 1.18 24 Mar 1992 09:43:40 GLENN
+Updated
+
+ Rev 1.17 23 Mar 1992 14:04:00 GLENN
+Updated rev.
+
+ Rev 1.16 22 Mar 1992 12:54:46 JOHNWT
+added APPMSGNAME
+
+ Rev 1.15 19 Mar 1992 15:45:20 GLENN
+Updated ER and added copyright and version defs.
+
+ Rev 1.14 16 Mar 1992 14:01:58 GLENN
+Upped rev.
+
+ Rev 1.13 10 Mar 1992 15:21:08 JOHNWT
+removed prebeta
+
+ Rev 1.12 10 Mar 1992 14:01:52 JOHNWT
+added TAPEPSWDTITLE
+
+ Rev 1.11 04 Mar 1992 11:43:54 GLENN
+Updated.
+
+ Rev 1.10 03 Mar 1992 16:14:42 JOHNWT
+added LCHDELAYTITLE
+
+ Rev 1.9 26 Feb 1992 17:29:58 JOHNWT
+add APPGROUP
+
+ Rev 1.8 25 Feb 1992 21:35:36 GLENN
+Updated.
+
+ Rev 1.7 23 Feb 1992 14:00:12 GLENN
+Overhauled.
+
+ Rev 1.6 18 Feb 1992 20:38:28 GLENN
+Updated.
+
+ Rev 1.5 10 Feb 1992 09:10:18 GLENN
+Updated.
+
+ Rev 1.4 02 Feb 1992 15:53:06 GLENN
+Updated.
+
+ Rev 1.3 31 Jan 1992 12:52:22 GLENN
+Update.
+
+ Rev 1.2 27 Jan 1992 12:51:40 GLENN
+Updated rev.
+
+ Rev 1.1 22 Jan 1992 12:21:38 GLENN
+Updated revision.
+
+ Rev 1.0 17 Jan 1992 15:04:06 GLENN
+Initial revision.
+
+******************************************************************************/
+
+#if !defined( PRODDEFS_H )
+
+#define PRODDEFS_H
+
+// Product specific definitions
+
+#if !defined( OEM_MSOFT )
+#if !defined( WFW )
+#define WFW
+#endif
+#endif
+
+
+// THIS FILE CONTAINS TEXT THAT MUST BE TRANSLATED!!!!!
+// The following is a list of RELEASE specific Text definitions.
+
+#define ABOUTVERSION TEXT("Version %s Rev. %s")
+
+#if defined( OEM_MSOFT )
+ #define COPYRIGHT TEXT("Copyright © 1993-1994 Arcada Software, Inc.\012All Rights Reserved")
+ #define COMPANY TEXT("\012")
+ #define CONGLOMERATE TEXT("Call Arcada Software's 1-800 number for\012additional information on software products.")
+#else
+ #define COPYRIGHT TEXT("Copyright © 1993-1994")
+ #define COMPANY TEXT("Arcada Software, Inc.")
+ #define CONGLOMERATE TEXT("All Rights Reserved")
+#endif
+
+#define SALESPITCH TEXT("")
+#define FM_JOBAPPEND TEXT("File Manager-Append")
+#define FM_JOBREPLACE TEXT("File Manager-Replace")
+#define FM_SCRIPT TEXT("WINFILE")
+
+#if defined( OEM_MSOFT )
+
+ // MICROSOFT STUFF - NOSTRADAMUS
+
+ #define APP_EXEVER TEXT("1.0")
+ #define APP_RESVER TEXT("1.0")
+ #define APP_ENGREL TEXT("3.41")
+
+#elif defined( BIMINI )
+
+ // Version info in separate private file
+ #include "version.h"
+
+#else
+
+ // OUR COMPANY STUFF - FIJI
+
+ #define APP_EXEVER TEXT("5.0")
+ #define APP_RESVER TEXT("2.0")
+ #define APP_ENGREL TEXT("3.41")
+
+#endif
+
+
+#if defined ( OEM_MSOFT ) //OEM Microsoft version
+
+ #define SHORTAPPNAME TEXT("BKUP")
+ #define EXEFILENAME TEXT("NTBACKUP.EXE")
+ #define INIFILENAME TEXT("NTBACKUP.INI")
+ #define HLPFILENAME TEXT("BACKUP.HLP")
+ #define JOBFILENAME TEXT("NTBACKUP.JOB") //?? need this?
+ #define SCHFILENAME TEXT("NTBACKUP.SCH") //?? need this?
+
+ #if defined( OS_WIN32 )
+ #define APPMSGNAME TEXT("NTBackup")
+ #else
+ #define APPMSGNAME TEXT("Windows Backup") //?? right name?
+ #endif
+
+ #define APPERROR TEXT("Backup Error")
+ #define APPABORT TEXT("Backup Abort")
+ #define APPGROUP TEXT("Backup")
+
+ #if defined( MAYN_REL ) && defined( MAYN_DEMO )
+
+ #define APPLICATIONNAME TEXT("Backup Demo")
+ #define ABOUTAPPLICATIONNAME TEXT("About Backup Demo")
+ #define AABOUTAPPLICATIONNAME TEXT("&About Backup Demo...")
+
+ #else
+ #define APPLICATIONNAME TEXT("Backup")
+ #define ABOUTAPPLICATIONNAME TEXT("About Backup")
+ #define AABOUTAPPLICATIONNAME TEXT("&About Backup...")
+ #define LONGAPPNAME TEXT("Microsoft Windows NT Backup")
+
+ #endif
+
+#else // not OEM Microsoft
+
+ #if defined( OS_WIN32 )
+ #define SHORTAPPNAME TEXT("BEX") // chs:03-25-93
+ #define EXEFILENAME TEXT("BEWINNT.EXE") // chs:03-25-93
+ #define INIFILENAME TEXT("BEWINNT.INI") // chs:03-25-93
+ #define PWDFILENAME TEXT("BEWINNT.PWD") // chs:03-25-93
+ #define HLPFILENAME TEXT("BEWINNT.HLP") // chs:03-25-93
+ #define JOBFILENAME TEXT("BEWINNT.JOB") // chs:03-25-93
+ #define SCHFILENAME TEXT("BEWINNT.SCH") // chs:03-25-93
+ #define LCHFILENAME TEXT("LAUNCHNT.EXE") // GSH:07-22-93
+ #define RESFILENAME TEXT("BERESNT.DLL") // GSH:07-22-93
+ #define READMEFILENAME TEXT("READMENT.TXT") // GSH:07-22-93
+ #define LONGAPPNAME TEXT("Backup Exec for Windows NT")
+ #define LOADERFILENAME "LDRDLL.DLL"
+ #else
+ #define SHORTAPPNAME TEXT("BE")
+ #define EXEFILENAME TEXT("BEWINS.EXE")
+ #define INIFILENAME TEXT("BEWINS.INI")
+ #define PWDFILENAME TEXT("BEWINS.PWD")
+ #define HLPFILENAME TEXT("BEWINS.HLP")
+ #define JOBFILENAME TEXT("BEWINS.JOB")
+ #define SCHFILENAME TEXT("BEWINS.SCH")
+ #define LCHFILENAME TEXT("LAUNCHWN.EXE") // GSH:07-22-93
+ #define RESFILENAME TEXT("BERESWN.DLL") // GSH:07-22-93
+ #define READMEFILENAME TEXT("READMEWN.TXT") // GSH:07-22-93
+ #define LONGAPPNAME TEXT("Backup Exec for Windows")
+ #endif
+
+ #define APPMSGNAME TEXT("Backup Exec") // GSH:07-22-93
+ #define APPERROR TEXT("Backup Exec Error") // GSH:07-22-93
+ #define APPABORT TEXT("Backup Exec Abort") // GSH:07-22-93
+ #define APPGROUP TEXT("Backup Exec") // GSH:07-22-93
+
+ #if defined( MAYN_DEMO )
+
+ #define APPLICATIONNAME TEXT("Backup Exec Demo")
+ #define LCHAPPLICATIONNAME TEXT("Backup Exec Launcher Demo")
+ #define ABOUTAPPLICATIONNAME TEXT("About Backup Exec Demo")
+ #define AABOUTAPPLICATIONNAME TEXT("&About Backup Exec Demo...")
+
+ #else
+
+ #define APPLICATIONNAME TEXT("Backup Exec") // GSH:04-08-93
+ #define LCHAPPLICATIONNAME TEXT("Backup Exec Launcher") // GSH:04-08-93
+ #define ABOUTAPPLICATIONNAME TEXT("About Backup Exec") // chs:02-18-93
+ #define AABOUTAPPLICATIONNAME TEXT("&About Backup Exec...") // chs:02-18-93
+
+ #endif
+
+#endif
+
+
+
+#endif /* end PRODDEFS_H */
diff --git a/private/utils/ntbackup/inc/prtmang.h b/private/utils/ntbackup/inc/prtmang.h
new file mode 100644
index 000000000..3ba0ace4b
--- /dev/null
+++ b/private/utils/ntbackup/inc/prtmang.h
@@ -0,0 +1,40 @@
+/****************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+ Name: prtmang.h
+
+ Description: This header file contains prototypes for print manager.
+
+ $Log: G:/UI/LOGFILES/PRTMANG.H_V $
+
+ Rev 1.3 04 Oct 1992 19:48:48 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.2 13 May 1992 16:32:08 MIKEP
+fixes for NT
+
+ Rev 1.1 04 Dec 1991 16:36:06 DAVEV
+16/32 bit Windows port changes-1st pass
+
+ Rev 1.0 20 Nov 1991 19:41:04 SYSTEM
+Initial revision.
+
+****************************************************************************/
+
+#ifndef prtmang_h
+#define prtmang_h
+
+
+VOID PM_FilePrint ( VOID ) ;
+VOID PM_FileSetup ( VOID ) ;
+VOID PM_SendFileToPrinter( LPSTR szFileName, BOOLEAN fPrompt ) ;
+BOOLEAN PM_PrinterExists ( VOID ) ;
+VOID PM_CheckSessionLogPrint ( VOID ) ;
+DLGRESULT APIENTRY PM_SetupWndProc (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY PM_PrintWndProc (HWND, MSGID, MP1, MP2);
+DLGRESULT APIENTRY PM_SearchWndProc (HWND, MSGID, MP1, MP2);
+
+#endif
+
+
+
diff --git a/private/utils/ntbackup/inc/pwinstal.h b/private/utils/ntbackup/inc/pwinstal.h
new file mode 100644
index 000000000..9c6eef297
--- /dev/null
+++ b/private/utils/ntbackup/inc/pwinstal.h
@@ -0,0 +1,33 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: pwinstal.h
+
+ Description:
+
+ Location:
+
+
+ $Log: G:/UI/LOGFILES/PWINSTAL.H_V $
+
+ Rev 1.1 04 Oct 1992 19:48:50 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.0 20 Nov 1991 19:35:54 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifndef PWINSTAL_H
+#define PWINSTAL_H
+
+/*
+ Define the subfunctions of password installation
+*/
+
+#define EXE_LRL 8092 /* password function defines */
+
+INT16 install_password( VOID ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/qtc.h b/private/utils/ntbackup/inc/qtc.h
new file mode 100644
index 000000000..a04495f96
--- /dev/null
+++ b/private/utils/ntbackup/inc/qtc.h
@@ -0,0 +1,915 @@
+
+/************************
+Copyright (c) Maynard, an Archive Company. 1991
+
+ Name: qtc.h
+
+ Description: This file contains the definitions, macros, and function
+ prototypes for the Quick Tape Catalogs (QTC).
+
+ $Log: N:\LOGFILES\QTC.H_V $
+
+ Rev 1.34 06 Dec 1993 09:47:20 mikep
+Very deep path support & unicode fixes
+
+ Rev 1.33 02 Nov 1993 17:48:46 MIKEP
+delete unused parameter
+
+ Rev 1.32 02 Nov 1993 17:14:00 MIKEP
+add fsys.h for non dll builds
+
+ Rev 1.31 28 Oct 1993 17:32:34 MIKEP
+qtc dll
+
+ Rev 1.30 19 Jul 1993 21:21:06 MIKEP
+add new status bits for ecc tapes
+
+ Rev 1.29 17 Jun 1993 09:08:46 Stefan
+Added ifdef around function that used FSYS_HAND and DBLKS.
+
+ Rev 1.28 15 Jun 1993 11:22:02 ChuckS
+Added new QTC errors QTC_TAPE_TAGGED_DELETED and QTC_CATALOG_FILE_IN_USE for
+Endeavour client/server environment. Added QTC_NON_VOLUME and QTC_TAPE_DELETED
+status-bit defines for QTC_HEADER statuses.
+
+P_CLINET || OS_NLM only: Added prototype for QTC_TagTapeForDeletion.
+
+
+ Rev 1.27 09 Jun 1993 19:29:30 MIKEP
+enable c++
+
+ Rev 1.26 01 Jun 1993 18:17:14 DON
+Added status bit for bset doesn't support redirected restore
+
+ Rev 1.25 20 May 1993 19:48:18 ChuckS
+Enclosed prototype for QTC_LookForFiles with #if defined( BECONFIG_H ),
+so including qtc.h doesn't force include of beconfig.h also
+
+ Rev 1.24 19 May 1993 16:08:02 ChuckS
+OS_NLM only: made cat_user stuff available for the NLM as well
+
+ Rev 1.23 18 May 1993 17:01:36 ChuckS
+P_CLIENT only: Added cat_user field to QTC_CATALOG structure and prototype
+of function to set the cat_user.
+
+ Rev 1.22 13 May 1993 13:25:00 ChuckS
+Changes for revamped QTC usage of virtual memory. Changed Q_ELEM's to
+VQ_ELEM's and moved to start of QTC_BSET and QTC_TAPE structures; changed
+Q_HEADER to VQ_HEADER. Changed arguments to QTC_NewBset and QTC_RemoveBset
+to take VQ_HDL instead of QTC_BSET_PTR for the bset to act upon.
+
+
+ Rev 1.21 01 May 1993 19:13:18 MIKEP
+add fatdrive bit to status
+
+ Rev 1.20 29 Apr 1993 11:30:52 MIKEP
+add call to get on tape cat ver
+
+ Rev 1.19 27 Apr 1993 16:08:00 ChuckS
+Added prototype for function QTC_ForgetTape, which is just part of
+QTC_RemoveTape moved to a seperate function so the client(s) can
+discard the memory allocated for a tape without attempting to remove
+a file. Also added prototype for QTC_FindTape, which is in the new
+file qtc_ftap.c
+
+
+
+ Rev 1.18 23 Apr 1993 10:35:38 MIKEP
+Add new on tape catalog version parameter to catalogs.
+Add prototype for new call in qtc_util.c to delete
+entries if files can't be accessed anymore.
+
+ Rev 1.17 14 Apr 1993 13:03:44 Stefan
+Changed if !defined( P_CLIENT ) by adding "|| defined(OS_WIN) because
+the windows client needs this code.
+
+ Rev 1.16 24 Mar 1993 11:11:54 ChuckS
+Added enclosing #ifndef _qtc_h_. Changed use of obsolete MAYN_DOS to OS_DOS.
+Enclosed typedef of QTC_BUILD, QTC_ZOMBIE within #if !defined( P_CLIENT ).
+Same for prototypes referencing QTC_BUILD and QTC_ZOMBIE. Enclosed protos
+using FSYS_HAND with #if defined( FSYS_H ), and those using DBLK_PTR with
+#if defined( DBLKS_H ).
+
+ Rev 1.15 23 Mar 1993 18:00:58 ChuckS
+Added arg to QTC_OpenFile indicating if need to open for writes
+
+ Rev 1.14 23 Mar 1993 10:32:32 BRYAN
+Changed return type for GetFileNameOnly.
+
+ Rev 1.13 19 Mar 1993 11:34:42 ChuckS
+Fixed syntax error in prototype for QTC_GetFileNameOnly.
+
+ Rev 1.12 18 Mar 1993 11:35:44 TIMN
+Added two f(x)s to get catalog info: get data path and get filename only
+
+ Rev 1.11 26 Jan 1993 17:10:04 MIKEP
+vcb changes
+
+ Rev 1.10 20 Jan 1993 19:21:18 MIKEP
+add floppy flag
+
+ Rev 1.9 04 Jan 1993 09:41:14 MIKEP
+unicode support changes
+
+ Rev 1.8 14 Dec 1992 12:37:06 DAVEV
+Enabled for Unicode compile
+
+ Rev 1.7 25 Nov 1992 16:13:38 ChuckS
+P_CLIENT only: Added field to QTC_BSET for volume ref, mod time for QTC_TAPE
+
+ Rev 1.6 23 Nov 1992 14:20:56 MIKEP
+fix continuation vcb for MTF only
+
+ Rev 1.5 20 Nov 1992 13:52:16 CHARLIE
+JAGUAR: Move to SRM based QTC code
+
+ENDEAVOR: Modified QTC_AbortCataloging prototype to include BOOLEAN keep_items
+
+ENDEAVOR: Modified QTC_Init prototype to include VM_HDL vm_hdl
+
+ Rev 1.4 22 Oct 1992 16:51:54 MIKEP
+otc fixes
+
+ Rev 1.3 22 Oct 1992 09:27:44 MIKEP
+second pass otc changes
+
+ Rev 1.2 22 Oct 1992 08:46:22 MIKEP
+add otc status bits
+
+ Rev 1.1 14 Oct 1992 10:19:50 MIKEP
+add OTC fields to QTC VCB
+
+ Rev 1.0 03 Sep 1992 16:56:12 STEVEN
+Initial revision.
+
+ Rev 1.33 01 Sep 1992 11:14:06 MIKEP
+added UNALIGNED for NT compiling on x86 machines
+
+ Rev 1.32 18 Aug 1992 14:52:40 DAVEV
+MikeP's changes from Microsoft
+
+ Rev 1.31 04 Aug 1992 10:08:20 MIKEP
+delete cats flag
+
+ Rev 1.30 29 Jul 1992 09:54:58 MIKEP
+ChuckB checked in after NT warnings were fixed.
+
+ Rev 1.29 10 Jul 1992 10:05:44 MIKEP
+add getfirstitem
+
+ Rev 1.28 09 Jul 1992 10:25:46 MIKEP
+standard product changes
+
+
+**************************/
+
+#ifndef _qtc_h_
+#define _qtc_h_
+
+// *************************************
+// CATALOG INCLUDES
+// *************************************
+
+#include "vm.h"
+#include "vqueue.h"
+
+// *************************************
+// CATALOG GLOBAL DATA EXTERNS
+// *************************************
+
+extern VM_HDL qtc_vmem_hand;
+extern VM_PTR v_bset_item;
+extern VM_PTR v_tape_item;
+
+
+// *************************************
+// CATALOG DEFINES
+// *************************************
+
+#ifndef UNALIGNED
+#define UNALIGNED
+#endif
+
+
+// magic number is used to tell if we have inited properly
+
+#define QTC_MAGIC_NUMBER 6942
+
+
+#define NO_CARE_FID 0xffffffff
+#define NO_CARE_BSET 0xffff
+#define NO_CARE_SEQNO 0xffff
+
+
+// used in the status fields for record entries
+
+#define QTC_FILE 0x0001 // is entry a file
+#define QTC_DIRECTORY 0x0002 // is entry a directory
+#define QTC_AFP 0x0004 // is entry an apple file
+#define QTC_EMPTY 0x0008 // is this directory empty
+#define QTC_CORRUPT 0x0010 // is this entry corrupt
+#define QTC_SPLIT 0x0020 // does this entry continue on next tape
+#define QTC_CONTINUATION 0x0040 // did this entry start on a previous tape
+#define QTC_MANUFACTURED 0x0080 // entry was created
+
+// End of record item status defines
+// Bset defines continue ...
+
+#define QTC_ERASED 0x00000100 // if bset was erased or recat'd
+#define QTC_INCOMPLETE 0x00000200 // is this bset incompletely cataloged
+#define QTC_PARTIAL 0x00000400 // is this a partially cat'd bset
+#define QTC_IMAGE 0x00000800 // set is an image backup
+#define QTC_UNICODE 0x00001000 // is this set in unicode
+#define QTC_FDDEXISTS 0x00002000 // does this set have FDD on tape
+#define QTC_SMEXISTS 0x00004000 // does this tape have an SM
+#define QTC_OTCVALID 0x00008000 // are our OTC bits valid
+#define QTC_FLOPPY 0x00010000 // a backup to floppies, not tape
+#define QTC_FATDRIVE 0x00020000 // a backup of a FAT drive
+#define QTC_NO_REDIRECT 0x00040000 // if bset does NOT support redirected restore
+#define QTC_NON_VOLUME 0x00080000 // if bset is a non-volume object (eg, SMS Bindery or Directory Services)
+#define QTC_TAPE_DELETED 0x00100000 // if tape is tagged for deletion
+#define QTC_COMPRESSED 0x00200000 // a compressed data set
+#define QTC_ENCRYPTED 0x00400000 // an encrypted data set
+#define QTC_FUTURE_VER 0x00800000 // a future version data set
+
+
+// Catalog building state defines
+
+#define QTC_WAITING_STATE 3 // waiting on a continuation tape
+#define QTC_ERROR_STATE 2 // something bad happened
+#define QTC_ACTIVE_STATE 1 // Is a backup/catalog a tape in progress
+#define QTC_IDLE_STATE 0 // Are we not building/cataloging a tape
+
+// Backup types
+
+#define QTC_COPY_BACKUP 1
+#define QTC_DIFF_BACKUP 2
+#define QTC_INCR_BACKUP 3
+#define QTC_NORM_BACKUP 4
+#define QTC_DAIL_BACKUP 5
+
+// The internal buffer size used by the catalogs. Increasing the size
+// will directly improve catalog performance. Adding disk caching will
+// improve performance the best.
+
+// Suggested buffer sizes are:
+
+// DOS 512
+// All others 1024
+
+#if defined( OS_DOS )
+ #define QTC_BUF_SIZE 512
+#else
+ #define QTC_BUF_SIZE 1024
+#endif
+
+
+#ifdef UNICODE
+ #define QTC_FILE_SPEC "????????.U??"
+#else
+ #define QTC_FILE_SPEC "????????.D??"
+#endif
+
+// We keep an offset to the parent directory during builds, if the depth
+// goes deeper, we bump this value by another 10 levels.
+
+#define QTC_START_DEPTH 10
+
+
+#define QTC_MAX_FILE_SIZE 256
+#define QTC_MAX_PATH_SIZE 256
+
+
+#define QTC_NO_MORE 1
+#define QTC_SUCCESS 0
+#define QTC_FAILURE -1
+
+#define QTC_DISK_FULL -2
+#define QTC_TAPE_NOT_FOUND -3
+#define QTC_BSET_NOT_FOUND -4
+#define QTC_NO_INIT -5
+#define QTC_OPEN_FAILED -6
+#define QTC_WRITE_FAILED -7
+#define QTC_READ_FAILED -8
+#define QTC_SEEK_FAILED -9
+#define QTC_NO_MEMORY -10
+#define QTC_NO_FILE_HANDLES -11
+#define QTC_NO_HEADER -12
+#define QTC_INVALID_FILE -13
+#define QTC_TAPE_TAGGED_DELETED -14
+#define QTC_CATALOG_FILE_IN_USE -15 // returned by Client/Server "wrapper" for QTC_RemoveTape
+
+// Any catalog files created with a different version will be ignored.
+
+#define QTC_MAJOR_VERSION 2 // Version control for catalogs
+#define QTC_MINOR_VERSION 0 // Version control for catalogs
+
+
+#define QTC_SKIP_TO_NEXT_ITEM 1
+#define QTC_SKIP_TO_NEXT_BSET 2
+#define QTC_OPERATION_COMPLETE 3
+
+
+/*******************************************
+
+ XTRA BYTE DEFINES
+
+ There are ( 255 / 5 ) extra byte fields that can be in the catalogs
+ appended to any file or directory item. Each field is 5 bytes long.
+ It starts with a 1 byte code word, followed by 4 data bytes. If it
+ ain't defined here, it better not be in the extra bytes.
+
+********************************************/
+
+
+#define QTC_MAX_XTRA_BYTES 255
+
+// The only ones currently defined.
+
+#define QTC_XTRA_64BIT_SIZE 0 // Top 32 bits of 64 bit file size
+
+// This info is saved on directories only.
+
+#define QTC_FILE_COUNT 1 // files in this dir
+#define QTC_BYTE_COUNT_MSW 2 // bytes in this dir
+#define QTC_BYTE_COUNT_LSW 3 // bytes in this dir
+
+// The combo count saves space over the three above.
+
+#define QTC_COMBO_COUNT 4 // 8 bit file count, 24 bit bytes count
+
+
+// *****************************************
+// CATALOG STRUCTURES
+// *****************************************
+
+#define QTC_SIGNATURE "CONNER SOFTWARE - CATALOG FILE"
+
+typedef struct _QTC_TAPE_HEADER *QTC_TAPE_HEADER_PTR;
+typedef struct _QTC_TAPE_HEADER {
+
+ INT32 major_version; // catalog version
+ INT32 minor_version;
+ BYTE signature[ 52 ]; // must be longer than signature
+
+} QTC_TAPE_HEADER;
+
+
+// the info we keep live on each backup set
+
+typedef struct _QTC_BSET *QTC_BSET_PTR;
+typedef struct _QTC_BSET {
+
+ VQ_ELEM q_elem ;
+
+ UINT32 tape_fid; // who is it
+ INT32 tape_seq_num;
+ INT32 bset_num;
+
+ UINT32 offset; // where is it
+
+ UINT32 status; // what is it
+
+ VOID_PTR v_volume ; // reference to volume record
+
+} QTC_BSET;
+
+
+// information we keep on disk for each bset.
+
+typedef struct _QTC_HEADER *QTC_HEADER_PTR;
+typedef struct _QTC_HEADER {
+
+ UINT32 header_size; // num bytes on disk, probably 512
+ UINT32 string_offset; // offset in bytes to string data
+ UINT32 catalog_version; // of this backup set
+ UINT32 backup_type; // normal, copy, inc, diff
+ UINT32 OS_id; // type of OS the bset is from
+ UINT32 OS_ver; // version of OS the bset is from
+ UINT32 tape_fid; // tape family id
+ INT32 bset_num; // 1, 2, ...
+ INT32 tape_seq_num; // 1, 2, ...
+ UINT32 offset; // where in data file is this guy
+ UINT32 next_bset; // where is next bset in data file
+ UINT32 status; // partial, image, unicode, etc.
+ UINT32 status2; // even more status bits
+ UINT32 dir_start; // offset in data file of directory info
+ UINT32 dir_size; // bytes of directory info
+ UINT32 fil_start; // offset in data file of file info
+ UINT32 fil_size; // bytes of file info
+ UINT32 rec_start; // offset in data file of records
+ UINT32 rec_size; // bytes of record info
+ UINT32 num_dirs; // number of dirs
+ UINT32 num_files; // number of files
+ UINT32 num_bytes; // 64 bit number of bytes low
+ UINT32 num_bytes_msw; // 64 bit number of bytes high
+ UINT32 num_corrupt_files; // number of corrupt files
+ UINT32 num_files_in_use; // number of files that were in use
+ UINT32 backup_date; // when this backup actually started
+ UINT32 backup_time;
+ UINT32 PBA_VCB; // physical block address of the volume control block
+ UINT32 LBA; // logical block address 0,1
+ UINT32 VCB_attributes;
+ UINT32 compress_algor;
+ UINT32 encrypt_algor; // encryption algorithm for passwords
+ UINT32 FDD_SeqNum; // Seq Num that FDD resides on.
+ UINT32 FDD_PBA; // PBA of FDD stuff
+
+ UINT32 loader_id; // loader stuff
+ UINT32 slot_number;
+ UINT32 loader_stuff1;
+ UINT32 loader_stuff2;
+
+ UINT32 FDD_Version; // OTC Version Number
+
+ UINT32 spare2; // spare space all init'd to 0.
+ UINT32 spare3;
+ UINT32 spare4;
+ UINT32 spare5;
+ UINT32 spare6;
+ UINT32 spare7;
+ UINT32 spare8;
+ UINT32 spare9;
+ UINT32 spare10;
+ UINT32 spare11;
+ UINT32 spare12;
+ UINT32 spare13;
+ UINT32 spare14;
+ UINT32 spare15;
+ UINT32 spare16;
+ UINT32 spare17;
+ UINT32 spare18;
+ UINT32 spare19;
+ UINT32 spare20;
+
+ // String Sizes
+
+ UINT32 tape_password_size; // non zero if there is one
+ UINT32 bset_password_size; // non zero if there is one
+ UINT32 bset_description_size;
+ UINT32 bset_name_size;
+ UINT32 tape_name_size;
+ UINT32 volume_name_size;
+ UINT32 user_name_size;
+
+ // String Pointers
+
+ CHAR_PTR tape_name;
+ CHAR_PTR bset_name;
+ CHAR_PTR volume_name;
+ CHAR_PTR user_name;
+ CHAR_PTR bset_description;
+ CHAR_PTR tape_password;
+ CHAR_PTR bset_password;
+
+} QTC_HEADER;
+
+// The info we keep on each tape
+
+typedef struct _QTC_TAPE *QTC_TAPE_PTR;
+typedef struct _QTC_TAPE {
+
+ VQ_ELEM q_elem;
+
+ UINT32 status;
+
+ UINT32 tape_fid;
+ INT16 tape_seq_num;
+
+ VQ_HEADER bset_list;
+
+ UINT32 wr_time ; // tape-file's modified date as of last refresh of in-memory tape queue
+
+} QTC_TAPE;
+
+
+// This is what is kept in the records file.
+
+typedef struct _QTC_RECORD *QTC_RECORD_PTR;
+typedef struct _QTC_RECORD {
+
+ UINT32 date:16; // dos format date and time
+ UINT32 time:16;
+ union {
+ UINT32 size; // file size
+ struct {
+ UINT32 file_start:24; // start offset of file names for this dir
+ UINT32 height:8; // 0 = root, ...
+ } common;
+ } common;
+ UINT32 lba; // logical block address on tape
+ UINT32 status:8; // file or directory
+ UINT32 name_offset:24; // offset in name file
+ UINT32 attribute; // maynard FS_ attribute field
+
+} QTC_RECORD;
+
+
+// This is what is kept in the name files. After each structure is a null
+// terminated name. The structures are packed togather in the files.
+
+typedef struct _QTC_NAME *QTC_NAME_PTR;
+typedef struct _QTC_NAME {
+
+ INT32 size; // size of QTC_NAME + name string + xtra bytes
+ UINT32 xtra_size:8; // size of xtra bytes
+ UINT32 mom_offset:24; // parent directory name file offset
+ UINT32 record; // data record number
+
+ // CHAR name[?]; // item name with no terminating zero
+ // CHAR xtra_bytes[?]; // xtra bytes with no terminating zero
+
+} QTC_NAME;
+
+
+#if !defined( P_CLIENT ) || defined( OS_WIN )
+
+/*
+ Used for doing builds.
+*/
+
+typedef struct _QTC_BUILD *QTC_BUILD_PTR;
+typedef struct _QTC_BUILD {
+
+ INT error; // has error occurred
+
+ UCHAR state; // state of catalogs
+
+ INT files_in_dir; // files in last dir processed
+ UINT64 bytes_in_dir; // bytes in files in last dir
+
+ QTC_HEADER_PTR header; // current building bset
+
+ QTC_HEADER_PTR old_header; // used when partially cataloging
+ // and you cross tapes, to go back
+ // and adjust the flags.
+
+ CHAR_PTR rec_file; // file names + paths
+ CHAR_PTR dir_file; // 256 should be enough
+ CHAR_PTR fil_file; // for anybody
+
+ BOOLEAN continuation_tape;
+
+ BOOLEAN fake_root_added; // do we need to patch his lba
+
+ BOOLEAN do_full_cataloging; // else do partial
+
+ INT fh_dir; // file handles
+ INT fh_rec;
+ INT fh_fil;
+
+ INT files_open; // are the temp files open ?
+
+ INT dir_offset; // current index into buffer
+ UINT32 curr_dir_off; // current length of file
+
+ INT fil_offset;
+ UINT32 curr_fil_off;
+
+ INT rec_offset;
+ UINT32 curr_rec_off;
+
+ INT current_level; // depth in tree we are processing
+
+ // offsets to all subdirs in current path
+
+ UINT32 *mom_offset; // saves pointers to all active parents
+ INT mom_depth; // how deep can we go with current allocation
+
+ UINT32 last_mom_offset; // offset of last mom
+
+ UINT32 record_cnt; // number of records in catalog
+
+ INT last_record; // last record processed - file/dir ?
+
+ BYTE fil_buffer[ QTC_BUF_SIZE ]; // used during building
+ BYTE dir_buffer[ QTC_BUF_SIZE ];
+ BYTE rec_buffer[ QTC_BUF_SIZE ];
+
+ CHAR *curr_build_path;
+
+ INT curr_build_path_size; // bytes allocated
+
+ INT build_path_len; // number of characters in use
+
+ QTC_RECORD record; // used during building
+
+ BOOLEAN end_of_media; // did we hit end of media
+
+ UINT32 num_dirs; // number of dirs
+ UINT32 num_files; // number of files
+ UINT32 num_corrupt_files; // number of corrupt files
+
+} QTC_BUILD;
+
+#endif
+
+
+// This structure is used to access the catalogs.
+
+typedef struct _QTC_QUERY *QTC_QUERY_PTR;
+typedef struct _QTC_QUERY {
+
+ // USER FIELDS
+
+ UINT32 tape_fid; // where I should look, cannot be -1
+ INT16 tape_seq_num; // may be -1
+ INT16 bset_num; // cannot be -1
+
+ BOOLEAN subdirs; // traverse subdirs in search
+
+ UINT16 predate; // non-zero if active
+ UINT16 postdate;
+
+ // Where the file/dir results are found
+
+ CHAR_PTR path; // with embedded 0's
+ INT path_size; // in bytes and including last zero
+ CHAR_PTR item; // file or dir name found
+
+ // Also you can check empty bit in status word for file count.
+
+ INT file_count; // files located in this dir
+ UINT64 byte_count; // bytes in files in this dir
+
+ UINT32 attrib; // characteristics of found item
+ UINT16 date;
+ UINT16 time;
+ UINT64 size;
+ UINT32 lba;
+
+ INT xtra_size;
+ BYTE xtra_bytes[ QTC_MAX_XTRA_BYTES ];
+
+ UINT8 status; // FIL_TYPE, DIR_TYPE, etc.
+ // see QTC_* above for defines
+
+ INT return_code; // why was the request unsuccessful
+
+ // QTC PRIVATE FIELDS, UI CODE SHOULD NOT ACCESS THESE DIRECTLY
+
+ CHAR_PTR search_path; // where to look
+
+ CHAR_PTR search_name; // what to look for
+
+ INT search_path_size; // in bytes
+
+ BOOLEAN error; // has a major error occurred
+
+ INT size_of_path; // bytes allocated for path, private qtc use
+ INT size_of_item; // bytes allocated for name, private qtc use
+
+ BOOLEAN file_open; // Is there an active file handle
+
+ UINT16 search_size;
+
+ UINT32 search_start;
+ UINT32 search_stop;
+ UINT16 search_index; // used by QTC_FastFindFile
+
+ UINT16 search_max;
+ UINT32 search_base;
+
+ BYTE buff1[ QTC_BUF_SIZE ]; // processed data
+ BYTE buff2[ QTC_BUF_SIZE ]; // straight out of file
+
+ QTC_HEADER_PTR header; // current working header
+ QTC_BSET_PTR bset; // current working bset
+
+ UINT32 curr_mom_offset; // current active parent dir
+ UINT32 fil_dir_offset; // current child dir for GetNextFile
+
+ INT fh; // data file handle
+
+ UINT32 dir_offset; // current offsets
+ UINT32 rec_offset;
+ UINT32 fil_offset;
+
+ // GetNextDir( ) buffer current index and size
+ // GetNextObj( )
+
+ INT data_index;
+ INT data_max;
+
+ // GetNextItem( ) record number
+
+ UINT32 record_number;
+
+ CHAR_PTR last_path; // with embedded 0's
+ INT last_path_size; // in bytes and including zero
+ INT size_of_last_path; // bytes allocated
+
+} QTC_QUERY;
+
+
+
+// There is ONE of these, it is THE catalog.
+
+typedef struct _QTC_CATALOG *QTC_CATALOG_PTR;
+typedef struct _QTC_CATALOG {
+
+ BOOLEAN unicode; // are we compiled for unicode
+
+ INT inited; // see if init was successful
+
+ CHAR_PTR data_path;
+
+ VQ_HEADER tape_list; // list of tapes known about
+
+ CHAR_PTR cat_user ;
+
+} QTC_CATALOG;
+
+
+extern QTC_CATALOG gb_QTC; // Definition of global catalog
+
+
+// **********************************
+// USER APPLICATION CALLS & QUERY MACROS
+// **********************************
+
+#define QTC_SetTapeFID( q, x ) ( (q)->tape_fid = ( x ) )
+#define QTC_SetTapeSeq( q, x ) ( (q)->tape_seq_num = ( x ) )
+#define QTC_SetBsetNum( q, x ) ( (q)->bset_num = ( x ) )
+#define QTC_SetSubdirs( q, x ) ( (q)->subdirs = ( x ) )
+#define QTC_SetPreDate( q, x ) ( (q)->predate = ( x ) )
+#define QTC_SetPostDate( q, x ) ( (q)->postdate = ( x ) )
+#define QTC_SetBuildHandle( q, x ) ( (q)->build = ( x ) )
+
+// QTC_SetSearchName() is a function listed below
+// QTC_SetSearchPath() is a function listed below
+// QTC_GetSearchPathLength() is a function listed below
+// QTC_GetSearchPath() is a function listed below
+
+#define QTC_GetPreDate( q ) ( (q)->predate )
+#define QTC_GetPostDate( q ) ( (q)->postdate )
+#define QTC_GetSubdirs( q ) ( (q)->subdirs )
+#define QTC_GetPath( q ) ( (q)->path )
+#define QTC_GetPathLength( q ) ( (q)->path_size )
+#define QTC_GetItemName( q ) ( (q)->item )
+#define QTC_GetItemDate( q ) ( (q)->date )
+#define QTC_GetItemTime( q ) ( (q)->time )
+#define QTC_GetItemSize( q ) ( (q)->size )
+#define QTC_GetItemAttrib( q ) ( (q)->attrib )
+#define QTC_GetItemLBA( q ) ( (q)->lba )
+#define QTC_GetItemStatus( q ) ( (q)->status )
+#define QTC_GetSizeExtraBytes( q ) ( (q)->xtra_size )
+#define QTC_GetExtraBytes( q ) ( (q)->xtra_bytes )
+#define QTC_GetTapeFID( q ) ( (q)->bset->tape_fid )
+#define QTC_GetTapeSeq( q ) ( (q)->bset->tape_seq_num )
+#define QTC_GetBsetNum( q ) ( (q)->bset->bset_num )
+#define QTC_GetPBAVCB( q ) ( (q)->bset->PBA_VCB )
+#define QTC_GetBset( q ) ( (q)->bset )
+#define QTC_GetReturnCode( q ) ( (q)->return_code )
+#define QTC_GetFileCount( q ) ( (q)->file_count )
+#define QTC_GetByteCount( q ) ( (q)->byte_count )
+
+#define QTC_DoFullCataloging( q, flag ) ( (q)->do_full_cataloging = ( flag ) )
+#define QTC_ContinuationTape( q ) ( (q)->continuation_tape = ( TRUE ) )
+#define QTC_GetErrorCondition( q ) ( (q)->error )
+
+QTC_TAPE *QTC_GetFirstTape( VOID );
+QTC_TAPE *QTC_GetNextTape( QTC_TAPE_PTR );
+QTC_TAPE *QTC_GetPrevTape( QTC_TAPE_PTR );
+
+QTC_BSET *QTC_GetFirstBset( QTC_TAPE_PTR );
+QTC_BSET *QTC_GetLastBset( QTC_TAPE_PTR );
+QTC_BSET *QTC_GetNextBset( QTC_BSET_PTR );
+QTC_BSET *QTC_GetPrevBset( QTC_BSET_PTR );
+
+QTC_QUERY_PTR QTC_InitQuery( VOID );
+INT QTC_CloseQuery( QTC_QUERY_PTR );
+
+// get a list of just the directories
+
+INT QTC_GetFirstDir( QTC_QUERY_PTR );
+INT QTC_GetNextDir( QTC_QUERY_PTR );
+
+// get a list of the files and dirs for one directory
+
+INT QTC_GetFirstObj( QTC_QUERY_PTR );
+INT QTC_GetNextObj( QTC_QUERY_PTR );
+
+// get a list of items ordered as they were backed up
+
+INT QTC_GetFirstItem( QTC_QUERY_PTR );
+INT QTC_GetNextItem( QTC_QUERY_PTR );
+
+// get items based on search criteria
+
+INT QTC_SearchFirstItem( QTC_QUERY_PTR );
+INT QTC_SearchNextItem( QTC_QUERY_PTR );
+
+
+// OTHER CATALOG CALLS
+
+#if !defined( P_CLIENT ) || defined( OS_WIN )
+
+ // Comment out anything related to building catalogs, clients don't do that.
+
+ VOID QTC_AbortCataloging( QTC_BUILD_PTR, BOOLEAN );
+ VOID QTC_AbortBackup( QTC_BUILD_PTR );
+ VOID QTC_AddDirectoryToCatalog( QTC_BUILD_PTR, UINT64, CHAR_PTR, INT, UINT16, UINT16, UINT32, UINT32, BYTE_PTR, UINT );
+ VOID QTC_AddFileToCatalog( QTC_BUILD_PTR, UINT64, CHAR_PTR, UINT16, UINT16, UINT32, UINT32, UINT32, BYTE_PTR, UINT );
+ VOID QTC_EndOfTapeReached( QTC_BUILD_PTR, CHAR_PTR, CHAR_PTR, INT );
+ VOID QTC_PatchVCB( QTC_BUILD_PTR, UINT32, UINT32 );
+ INT QTC_StartNewBackup( QTC_BUILD_PTR, CHAR_PTR, CHAR_PTR, CHAR_PTR, CHAR_PTR, CHAR_PTR, CHAR_PTR, CHAR_PTR, CHAR_PTR,
+ INT, INT, UINT32, UINT16, UINT16, UINT32, UINT32, UINT32, INT, INT, INT,
+ UINT32, UINT32, INT, INT, INT, INT,
+ INT, INT, INT, INT, INT, INT, INT, UINT16, UINT16, INT );
+ INT QTC_BlockBad( QTC_BUILD_PTR );
+ INT QTC_FinishBackup( QTC_BUILD_PTR );
+ INT QTC_FreeBuildHandle( QTC_BUILD_PTR );
+ QTC_BUILD_PTR QTC_GetBuildHandle( VOID );
+ INT QTC_ImageScrewUp( QTC_BUILD_PTR );
+ VOID QTC_AddDir( QTC_BUILD_PTR, CHAR_PTR, INT, BYTE_PTR, INT );
+ VOID QTC_AddFile( QTC_BUILD_PTR, CHAR_PTR, BYTE_PTR, INT );
+ VOID QTC_AddRecord( QTC_BUILD_PTR );
+ INT QTC_BuildNewPath( QTC_BUILD_PTR, UINT32 );
+ INT QTC_ErrorCleanup( QTC_BUILD_PTR );
+ INT QTC_FlushInternalBuffers( QTC_BUILD_PTR );
+ INT QTC_GetLastRecordEntered( QTC_BUILD_PTR, QTC_RECORD_PTR, BYTE_PTR, BYTE_PTR, INT * );
+ INT QTC_IsThisBsetKnown( QTC_BUILD_PTR, QTC_HEADER_PTR );
+ INT QTC_OpenTempFiles( QTC_BUILD_PTR );
+ INT QTC_RestartBackup( QTC_BUILD_PTR, QTC_HEADER_PTR, Q_HEADER_PTR );
+ VOID QTC_SaveDirRecord( QTC_BUILD_PTR, CHAR_PTR, INT, UINT32, BYTE_PTR, INT );
+ INT QTC_SetCountsForLastDir( QTC_BUILD_PTR );
+
+#endif
+
+BOOLEAN QTC_AnyCatalogFiles( VOID );
+INT QTC_AnySearchableBsets( VOID );
+INT QTC_TagTapeForDeletion( UINT32, INT16 );
+INT QTC_CloseFile( INT );
+INT QTC_Open( CHAR_PTR, INT, INT, INT * );
+INT QTC_ReadFile( INT, BYTE_PTR, INT, INT * );
+INT QTC_WriteFile( INT, BYTE_PTR, INT, INT * );
+INT QTC_SeekFile( INT, INT );
+INT QTC_CheckFilesAccess( VOID );
+INT QTC_CompressFile( UINT32, INT16 );
+INT QTC_CouldThisSetCrossTapes( UINT32, INT16, INT16 );
+VOID QTC_Deinit( INT );
+INT QTC_DumpBsetInfo( QTC_TAPE_PTR );
+QTC_BSET_PTR QTC_FindBset( UINT32, INT16, INT16 );
+UINT32 QTC_GetKiloBytesWasted( UINT32, UINT16 );
+BOOLEAN QTC_GetDataPath( CHAR_PTR path, INT16 pathSize );
+VOID QTC_GetFileName( UINT32, INT16, CHAR_PTR );
+CHAR_PTR QTC_GetFileNameOnly( UINT32, INT16, CHAR_PTR );
+INT32 QTC_GetMeTheVCBPBA( UINT32, INT16, INT16 );
+UINT8 QTC_GetMeTheTapeCatVer( UINT32, INT16, INT16 );
+INT QTC_GetSearchPathLength( QTC_QUERY_PTR );
+INT QTC_GetSearchPath( QTC_QUERY_PTR, CHAR_PTR );
+INT QTC_Init( CHAR_PTR, VM_HDL );
+VOID QTC_SetCatUserName( CHAR_PTR ) ;
+INT QTC_LoadBsetInfo( CHAR_PTR, QTC_TAPE_PTR );
+QTC_HEADER_PTR QTC_LoadHeader( QTC_BSET_PTR );
+INT QTC_Partialize( UINT32, INT16, INT16 );
+INT QTC_PurgeAllFiles( VOID );
+INT QTC_SetSearchPath( QTC_QUERY_PTR, CHAR_PTR, INT );
+INT QTC_SetSearchName( QTC_QUERY_PTR, CHAR_PTR );
+INT QTC_LoadDLL( CHAR_PTR );
+INT QTC_UnLoadDLL( VOID );
+
+// Semi private stuff
+
+INT QTC_AdjustFlagsOnOtherPieces( UINT32, INT16, INT16 );
+INT QTC_BuildWholePath( QTC_QUERY_PTR, UINT32 );
+INT QTC_ChangeBsetFlags( QTC_HEADER_PTR, INT );
+INT QTC_CopyFile( INT, INT, UINT32, BYTE_PTR );
+INT QTC_CompAsciiNames( ACHAR_PTR srch_name, ACHAR_PTR file_name );
+INT QTC_CompNormalNames( CHAR_PTR srch_name, CHAR_PTR file_name );
+INT QTC_CompUnicodeNames( WCHAR_PTR srch_name, WCHAR_PTR file_name );
+INT QTC_FastSearchForDir( QTC_QUERY_PTR, UINT32_PTR, UINT32, INT, INT );
+INT QTC_FastSearchForFile( QTC_QUERY_PTR );
+INT QTC_FindDirRec( QTC_QUERY_PTR, QTC_RECORD_PTR );
+INT QTC_FindNextDirRec( QTC_QUERY_PTR, QTC_RECORD_PTR );
+INT QTC_FindStoppingOffset( QTC_QUERY_PTR, QTC_RECORD_PTR );
+INT QTC_GetNameFromBuff( BYTE_PTR, QTC_NAME UNALIGNED *, INT );
+QTC_NAME UNALIGNED * QTC_GetNextItemFromBuffer( QTC_QUERY_PTR, QTC_RECORD_PTR, INT );
+QTC_BSET_PTR QTC_GetLowerTapeBset( UINT32, INT16, INT16 );
+QTC_BSET_PTR QTC_GetHigherTapeBset( UINT32, INT16, INT16 );
+INT QTC_IsThereAnotherBset( QTC_BSET_PTR );
+INT QTC_LookForChildDirs( QTC_QUERY_PTR );
+INT QTC_MoveToNextTapeInFamily( QTC_QUERY_PTR );
+INT QTC_NewBset( VQ_HDL ) ;
+INT QTC_OpenFile( UINT32, INT16, INT, INT );
+VOID QTC_RemoveBset( QTC_TAPE_PTR, VQ_HDL ) ;
+VOID QTC_ReadInBsetInfo( CHAR_PTR );
+VOID QTC_RemoveTape( UINT32, INT16 );
+QTC_HEADER_PTR QTC_SetUpStrings( QTC_HEADER_PTR );
+INT QTC_TryToLocateFile( QTC_QUERY_PTR );
+INT QTC_TryToMatchFile( QTC_QUERY_PTR, BYTE_PTR );
+INT QTC_UnlinkFile( UINT32, INT16 );
+INT QTC_UpdateOTCInfo( QTC_HEADER_PTR );
+VOID QTC_ForgetTape( QTC_TAPE_PTR ) ;
+QTC_TAPE_PTR QTC_FindTape( UINT32 fid, INT16 seq_no ) ;
+
+// If not building as a DLL then include the rest of the prototypes.
+
+#ifndef QTCDLL
+#include "FSYS.H"
+#include "QTCXFACE.H"
+#endif
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/qtcxface.h b/private/utils/ntbackup/inc/qtcxface.h
new file mode 100644
index 000000000..a3d8c2111
--- /dev/null
+++ b/private/utils/ntbackup/inc/qtcxface.h
@@ -0,0 +1,37 @@
+/***************************************************
+Copyright (C) Conner Software 1994
+
+ Name: QTCXFACE.H
+
+ Description:
+
+ This file contains all of the interface functions to the catalog unit. It prevents the
+ catalog unit froming having to understand tape format, file systems, or loops. It also
+ contains the function interfaces to the catalog dll.
+
+ $Log: N:\logfiles\qtcxface.h_v $
+
+ Rev 1.0 28 Oct 1993 14:49:46 MIKEP
+Initial revision.
+
+ Rev 1.0 28 Oct 1993 14:46:20 MIKEP
+Initial revision.
+
+****************************************************/
+
+//
+// QTCXFACE.H
+//
+
+#ifndef _qtcxface_h_
+
+#define _qtcxface_h_
+
+// Prototypes that require other header files.
+
+VOID QTC_AddToCatalog( QTC_BUILD_PTR, DBLK_PTR, FSYS_HAND, BOOLEAN, BYTE_PTR, UINT );
+VOID QTC_EndOfTape( QTC_BUILD_PTR, DBLK_PTR, DBLK_PTR, DBLK_PTR, FSYS_HAND );
+VOID QTC_PatchContinuationVCB( QTC_BUILD_PTR, DBLK_PTR );
+INT QTC_StartBackup( QTC_BUILD_PTR, DBLK_PTR );
+
+#endif
diff --git a/private/utils/ntbackup/inc/queues.h b/private/utils/ntbackup/inc/queues.h
new file mode 100644
index 000000000..1121ed510
--- /dev/null
+++ b/private/utils/ntbackup/inc/queues.h
@@ -0,0 +1,157 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: queues.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the fabulous queues routines ( actually these are
+ linked lists ) written by the Gods of DD.
+
+
+ $Log: M:/LOGFILES/QUEUES.H_V $
+ *
+ * Rev 1.5 24 Nov 1993 14:51:58 BARRY
+ * Unicode fixes
+ *
+ * Rev 1.4 07 Sep 1993 12:35:32 JOHNES
+ * Added prototype for TopOfStack_with_0_values.
+ *
+ *
+ * Rev 1.3 09 Jun 1993 08:15:08 Stefan
+ * Add back in a typedef for STACK_ELEM that was removed in the previous fix.
+ *
+ *
+ * Rev 1.2 08 Jun 1993 13:58:50 MIKEP
+ * Enable C++ compile.
+ *
+ * Rev 1.1 17 Jul 1991 11:21:38 STEVEN
+ * changed FAR references to use env var FAR_Q_POINTERS
+ *
+ * Rev 1.0 09 May 1991 13:32:32 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ include list */
+
+#ifndef QUEUES
+#define QUEUES
+
+#ifdef FAR_Q_POINTERS
+#define Q_PTR_SIZE far
+#endif
+
+#ifndef Q_PTR_SIZE
+#define Q_PTR_SIZE
+#endif
+
+/** This structure is for a single queue element. All structures that
+ you wish to enqueue must have this structure contained in it.
+*/
+
+typedef struct Q_ELEM Q_PTR_SIZE *Q_ELEM_PTR ;
+typedef struct Q_ELEM {
+ Q_ELEM_PTR q_prev ; /* previous queue element */
+ Q_ELEM_PTR q_next ; /* next element */
+ INT32 q_priority ; /* priority of queue */
+ INT16 q_element ; /* element number */
+ VOID Q_PTR_SIZE * q_ptr ; /* a ptr to something */
+} Q_ELEM;
+
+
+/** This is the header of a queue. There needs to be one of these allocated
+ for every queue you wish to use.
+*/
+
+typedef struct Q_HEADER Q_PTR_SIZE *Q_HEADER_PTR;
+typedef struct Q_HEADER {
+ Q_ELEM_PTR q_head ; /* head element of the queue */
+ Q_ELEM_PTR q_tail ; /* tail element of the queue */
+ INT16 q_count ; /* count of elements */
+ BOOLEAN q_active ; /* Is this queue active */
+ INT16 q_magic ; /* for q_element number */
+} Q_HEADER ;
+
+#define BEFORE 0
+#define AFTER 1
+
+/** Here are some useful macros for the queues
+*/
+
+/* Returns the head element of the queue */
+#define QueueHead( queue ) ( (queue)->q_head )
+
+/* Returns the tail element of the queue */
+#define QueueTail( queue ) ( (queue)->q_tail )
+
+/* Returns the number of elements in the queue */
+#define QueueCount( queue ) ( (queue)->q_count )
+
+/* Returns the queue element number for an element */
+#define QueueElemNo( element ) ( (element)->q_element )
+
+/* Returns the next queue element in the chain */
+#define QueueNext( element ) ( (element)->q_next )
+
+/* Returns the previous queue element in the chain */
+#define QueuePrev( element ) ( (element)->q_prev )
+
+/* Returns the queue ptr field */
+#define QueuePtr( element ) ( (element)->q_ptr )
+
+#define GetQueueElemPriority( elem_ptr ) ( (elem_ptr)->q_priority )
+#define SetQueueElemPriority( elem_ptr, value ) ( ( (elem_ptr)->q_priority ) = (value) )
+
+#define GetQueueElemPtr( elem_ptr ) ( (elem_ptr)->q_ptr )
+#define SetQueueElemPtr( elem_ptr, value ) ( ( (elem_ptr)->q_ptr ) = (value) )
+
+
+/* Function Prototypes for the Queue Functions */
+
+VOID InitQueue( Q_HEADER_PTR ) ;
+VOID InitQElem( Q_ELEM_PTR ) ;
+Q_ELEM_PTR EnQueueElem( Q_HEADER_PTR queue, Q_ELEM_PTR element, BOOLEAN wpriority ) ;
+Q_ELEM_PTR DeQueueElem( Q_HEADER_PTR queue ) ;
+Q_ELEM_PTR InsertElem( Q_HEADER_PTR queue, Q_ELEM_PTR cur_elem, Q_ELEM_PTR ins_elem , UINT16 boa ) ;
+BOOLEAN RemoveQueueElem( Q_HEADER_PTR queue, Q_ELEM_PTR element ) ;
+VOID RemoveElem( Q_HEADER_PTR queue, Q_ELEM_PTR element ) ;
+Q_ELEM_PTR FindQueueElem( Q_HEADER_PTR queue, Q_ELEM_PTR element ) ;
+VOID PushElem( Q_HEADER_PTR queue, Q_ELEM_PTR element ) ;
+Q_ELEM_PTR PopElem( Q_HEADER_PTR queue ) ;
+VOID SortQueue( Q_HEADER_PTR , INT16 ( * )( Q_ELEM_PTR, Q_ELEM_PTR ) ) ;
+
+Q_ELEM_PTR SearchQueue( Q_HEADER_PTR,
+ BOOLEAN ( * )( VOID_PTR, VOID_PTR ),
+ VOID_PTR,
+ BOOLEAN );
+
+VOID MoveQueue( Q_HEADER_PTR from_queue, Q_HEADER_PTR to_queue ) ;
+Q_HEADER_PTR SplitQueue( Q_HEADER_PTR old_Q, Q_ELEM_PTR split, Q_HEADER_PTR new_Q ) ;
+
+/* Stacks ? */
+
+/*
+ Define Stack Definitions
+*/
+
+typedef struct STACK_ELEM Q_PTR_SIZE *STACK_ELEM_PTR;
+typedef struct STACK_ELEM {
+ Q_ELEM link ;
+ UINT32 item ;
+} STACK_ELEM ;
+
+typedef Q_HEADER STACK_HDR;
+typedef Q_HEADER_PTR STACK_HDR_PTR;
+
+VOID InitStack( STACK_HDR_PTR ) ;
+UINT16 Push( STACK_HDR_PTR, UINT32 ) ;
+UINT32 Pop( STACK_HDR_PTR ) ;
+UINT32 TopOfStack( STACK_HDR_PTR ) ;
+
+UINT16 TopOfStack_with_0_values(
+ STACK_HDR_PTR stk_ptr ,
+ UINT32_PTR stk_elem
+) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/rem_fs.h b/private/utils/ntbackup/inc/rem_fs.h
new file mode 100644
index 000000000..9a9d50acd
--- /dev/null
+++ b/private/utils/ntbackup/inc/rem_fs.h
@@ -0,0 +1,246 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: rem_fs.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains the prototypes for the REMOTE
+ file system functions.
+
+ $Log: P:/LOGFILES/REM_FS.H_V $
+ *
+ * Rev 1.2 16 Dec 1991 18:11:12 STEVEN
+ * move common functions into table
+ *
+ * Rev 1.1 23 May 1991 16:45:54 BARRY
+ * Changes for FindFirst/Next to scan for dirs only
+ *
+ * Rev 1.0 09 May 1991 13:32:16 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ include list */
+
+#include "fsys.h"
+
+/* Functions for the tiny file system to handle remote workstation/drive hierchy */
+
+INT16 RWS_AttachToDLE( FSYS_HAND fsh, /* I - File system handle */
+ GENERIC_DLE_PTR dle, /*I/O- drive to attach to. list element expanded */
+ CHAR_PTR u_name, /* I - user name NOT USED */
+ CHAR_PTR pswd); /* I - passowrd NOT USED */
+
+INT16 RWS_DetachDLE( FSYS_HAND fsh ); /* I - */
+
+
+
+
+INT16 REM_AttachToDLE( FSYS_HAND fsh, /* I - File system handle */
+ GENERIC_DLE_PTR dle, /*I/O- drive to attach to. list element expanded */
+ CHAR_PTR u_name, /* I - user name NOT USED */
+ CHAR_PTR pswd); /* I - passowrd NOT USED */
+
+INT16 REM_DetachDLE( FSYS_HAND fsh ); /* I - */
+
+INT16 REM_CreateObj( FSYS_HAND fsh, /* I - File system to create object one */
+ DBLK_PTR dblk); /* I - Describes object to create */
+
+INT16 REM_OpenObj( FSYS_HAND fsh, /* I - file system that the file is opened on */
+ FILE_HAND *hand, /* O - allocated handle */
+ DBLK_PTR dblk, /*I/O- describes the file to be opened */
+ OPEN_MODE mode); /* I - open mode */
+
+INT16 REM_ReadObj( FILE_HAND hand, /* I - handle of object to read from */
+ CHAR_PTR buf, /* O - buffer to place data into */
+ UINT16 *size, /*I/O- Entry: size of buf; Exit: number of bytes read */
+ UINT16 *blk_size); /* O - Block size needed for next read */
+
+
+INT16 REM_WriteObj( FILE_HAND hand, /* I - handle of object to read from */
+ CHAR_PTR buf, /* O - buffer to place data into */
+ UINT16 *size, /*I/O- Entry: size of buf; Exit: number of bytes read */
+ UINT16 *blk_size); /* O - Block size need for next read */
+
+INT16 REM_VerObj( FILE_HAND hand, /* I - file handle to verify data with */
+ CHAR_PTR buf, /* I - buffer needed to perform verify */
+ CHAR_PTR data, /* I - data to verify against */
+ UINT16 *size, /*I/O- size of buffers / amount verified */
+ UINT16 *blk_size); /* O - minum size of block for next call */
+
+
+INT16 REM_CloseObj( FILE_HAND hand ); /* I - handle of object to close */
+
+INT16 REM_DeleteObj( FSYS_HAND fsh,
+ DBLK_PTR dblk );
+
+INT16 REM_FindFirst( FSYS_HAND fsh, /* I - file system handle */
+ DBLK_PTR dblk, /* O - pointer to place to put the dblk data */
+ CHAR_PTR sname, /* I - serach name */
+ UINT16 find_type); /* I - type of find (dirs only, all, etc.) */
+
+INT16 REM_FindNext( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ); /* O - Discriptor block */
+
+INT16 REM_GetObjInfo( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ); /*I/O- On entry it is minimal on exit Complete */
+
+INT16 REM_VerObjInfo( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ); /* I - On entry it is minimal on exit Complete */
+
+INT16 REM_ChangeDir( FSYS_HAND fsh, /* I - file system to changing directories on */
+ CHAR_PTR path, /* I - describes the path of the new directory */
+ INT16 psize); /* I - specifies the length of the path */
+
+INT16 REM_UpDir( FSYS_HAND fsh ); /* I - file system to change directories in */
+
+INT16 REM_GetCurrentPath( FSYS_HAND fsh, /* I - file system to get current path from */
+ CHAR_PTR path, /* O - buffer to place this path */
+ INT16 *size); /*I/O- size of buffer on entry & on exit */
+
+INT16 REM_SeekObj( FILE_HAND hand, /* I - Opened object to seek into */
+ UINT32 *offset ); /*I/O- Offset to seek; Number of bytes actualy seeked */
+
+INT16 REM_GetMaxSizeDBLK( FSYS_HAND fsh /* not used */ );
+
+INT16 REM_GetBasePath( FSYS_HAND fsh, /* I - file system to get base path from */
+ CHAR_PTR full_path, /* O - buffer to place this path */
+ INT16 *size ); /*I/O- size of buffer on entry & on exit */
+
+INT16 REM_GetCurrentDDB( FSYS_HAND fsh, /* I - file system to get DDB from */
+ DBLK_PTR dblk ); /* O - place to put the DDB data */
+
+INT16 REM_SetObjInfo( FSYS_HAND fsh, /* I - file system handle */
+ DBLK_PTR dblk); /* I - data to write to disk */
+
+INT16 REM_ModFnameFDB( FSYS_HAND fsh, /* I - File system handle */
+ BOOLEAN set_it, /* I - TRUE if setting file name, FALSE if getting */
+ DBLK_PTR dblk, /* I - Descriptor block to get file name from */
+ CHAR_PTR buf, /*I/O- file name to read (or to write) */
+ INT16 *size ) ; /*I/O- size buffer on entry and exit */
+
+INT16 REM_ModPathDDB( FSYS_HAND fsh, /* I - File system handle */
+ BOOLEAN set_it , /* I - TRUE if setting path, FALSE if getting */
+ DBLK_PTR dblk, /* I - Descriptor block to get path from */
+ CHAR_PTR buf, /*I/O- path to read (or to write) */
+ INT16 *size ); /*I/O- size of buffer on entry and exit */
+
+INT16 REM_GetOSFnameFDB( DBLK_PTR dblk , /* I - Descriptor block to get path from */
+ CHAR_PTR buf ) ; /*I/O- path to read (or to write) */
+
+INT16 REM_GetOSPathDDB(
+ FSYS_HAND fsh,
+ DBLK_PTR dblk , /* I - Descriptor block to get path from */
+ CHAR_PTR buf ) ; /*I/O- path to read (or to write) */
+
+INT16 REM_GetFileVerFDB( DBLK_PTR dblk ,
+ UINT32 *version ) ;
+
+INT16 REM_GetCDateDBLK( DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ); /*I/O- createion date to read (or to write) */
+
+INT16 REM_GetMDateDBLK( DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ) ; /* O - modify date to write */
+
+INT16 REM_ModBDateDBLK( BOOLEAN set_it , /* I - TRUE if setting creation date, FALSE if getting */
+ DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ) ; /*I/O- createion date to read (or to write) */
+
+INT16 REM_ModADateDBLK( BOOLEAN set_it , /* I - TRUE if setting creation date, FALSE if getting */
+ DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+ DATE_TIME_PTR buf ) ; /*I/O- createion date to read (or to write) */
+
+INT16 REM_ModAttribDBLK( BOOLEAN set_it ,
+ DBLK_PTR dblk ,
+ UINT32_PTR attr );
+
+
+INT16 REM_GetObjTypeDBLK( DBLK_PTR dblk,
+ OBJECT_TYPE *type );
+
+
+UINT32 REM_GetGenSizeDBLK( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ) ; /* I - Descriptor block to get generic data size for */
+
+
+UINT32 REM_GetGenOffsetDBLK( FSYS_HAND fsh, /* I - File system handle - not used */
+ DBLK_PTR dblk ) ; /* I - Descriptor block to get generic data size for */
+
+INT16 REM_GetOS_InfoDBLK( DBLK_PTR dblk, /* I - DBLK to get the info from */
+ CHAR_PTR os_info, /* O - Buffer to place data */
+ INT16 *size ); /*I/O- Buffer size / data length */
+
+INT16 REM_GetActualSizeDBLK( FSYS_HAND fsh,
+ DBLK_PTR dblk ) ;
+
+INT16 REM_SizeofFname( FSYS_HAND fsh, /* I - file system in use */
+ DBLK_PTR fdb ); /* I - dblk to get fname from */
+
+INT16 REM_SizeofOSFname( FSYS_HAND fsh, /* I - file system in use */
+ DBLK_PTR fdb ) ; /* I - dblk to get fname from */
+
+INT16 REM_SizeofPath( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR ddb ) ; /* I - DBLK to get path size from */
+
+INT16 REM_SizeofOSPath( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR ddb ) ; /* I - DBLK to get path size from */
+
+INT16 REM_SizeofOSInfo( FSYS_HAND fsh, /* I - File system handle */
+ DBLK_PTR dblk ); /* I - DBLK to get size of OS info for */
+
+
+INT16 REM_MatchDBLK( FSYS_HAND fsh , /* I - file system used to do comparison */
+ DBLK_PTR dblk1, /* I - DDB, IDB, or UDB just not FDB */
+ DBLK_PTR dblk2, /* I - FDB if above is DDB else unused */
+ BOOLEAN disp_flag,/* I - TRUE if match DIR for display purpose */
+ struct FSE *fse ); /* I - FSE to compare against */
+
+INT16 REM_PushMinDDB( FSYS_HAND fsh,
+ DBLK_PTR dblk );
+
+INT16 REM_PopMinDDB( FSYS_HAND fsh ,
+ DBLK_PTR dblk );
+
+
+INT16 REM_CreateFDB( FSYS_HAND fsh,
+ GEN_FDB_DATA_PTR dat ) ;
+
+INT16 REM_CreateDDB( FSYS_HAND fsh,
+ GEN_DDB_DATA_PTR dat ) ;
+
+VOID REM_SetOwnerId( FSYS_HAND fsh, DBLK_PTR dblk, UINT32 id ) ;
+
+UINT16 AddRemoteDriveDLEs( GENERIC_DLE_PTR parent_dle ) ;
+
+BOOLEAN REM_ProcessDDB( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+INT16 REM_ChangeIntoDDB( FSYS_HAND fsh, DBLK_PTR ddb ) ;
+
+INT16 REM_Initialize(
+DLE_HAND dle_hand,
+BE_CFG_PTR cfg,
+UINT32 file_sys_mask ) ;
+
+VOID REM_DeInit( DLE_HAND dle_hand ) ;
+
+INT16 AddRemoteWorkStationDLEs(
+DLE_HAND hand,
+BE_CFG_PTR cfg,
+UINT32 file_sys_mask ) ;
+
+INT16 REM_DeviceDispName(
+GENERIC_DLE_PTR dle,
+CHAR_PTR dev_name,
+INT16 size ,
+INT16 type ) ;
+
+INT16 REM_MakePath(
+CHAR_PTR buf,
+INT16 bsize,
+GENERIC_DLE_PTR dle,
+CHAR_PTR path,
+INT16 psize,
+CHAR_PTR fname ) ;
+
+
diff --git a/private/utils/ntbackup/inc/remdblk.h b/private/utils/ntbackup/inc/remdblk.h
new file mode 100644
index 000000000..7c8482a7f
--- /dev/null
+++ b/private/utils/ntbackup/inc/remdblk.h
@@ -0,0 +1,76 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: remdblk.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains the definition of the Remote DOS
+ file systems' file and directory control blocks.
+
+
+ $Log: G:/LOGFILES/REMDBLK.H_V $
+ *
+ * Rev 1.0 09 May 1991 13:33:02 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ include list */
+
+
+#ifndef remdblk_h
+#define remdblk_h
+
+
+#include "queues.h"
+#include "doscom.h"
+#include "smb.h"
+
+
+typedef struct REM_FDB_INFO *REM_FDB_INFO_PTR;
+
+typedef struct REM_FDB_INFO {
+ BOOLEAN inuse_attrib ;
+ UINT16 handle ;
+ UINT16 os_name ;
+} REM_FDB_INFO ;
+
+
+typedef struct REM_DDB_INFO *REM_DDB_INFO_PTR;
+
+typedef struct REM_DDB_INFO {
+ BOOLEAN empty_attrib ;
+ CHAR path[ DOS_MAX_DSIZE ] ; /* build from "name" and current dir */
+ UINT16 os_path ;
+ UINT16 os_path_leng ;
+} REM_DDB_INFO;
+
+
+
+typedef struct REM_DBLK *REM_DBLK_PTR;
+
+typedef struct REM_DBLK {
+ UINT8 blk_type; /* values: DDB_ID, FDB_ID set: DOS */
+ COM_DBLK fs_reserved ;
+ SMB_DTA dta;
+ UINT16 tape_attribs ;
+ BOOLEAN os_info_complete; /* TRUE if GetObjInfo doesn't have to do anything */
+ union {
+ REM_DDB_INFO d;
+ REM_FDB_INFO f;
+ } b;
+} REM_DBLK;
+
+
+typedef struct REM_MIN_DDB *REM_MIN_DDB_PTR;
+
+typedef struct REM_MIN_DDB {
+ Q_ELEM q ;
+ UINT8 reserved[ 21 ] ; /* reserved for dos */
+ UINT16 psize ; /* size of path string */
+ CHAR_PTR path; /* build from "name" and current dir */
+} REM_MIN_DDB;
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/reqrep.h b/private/utils/ntbackup/inc/reqrep.h
new file mode 100644
index 000000000..07bcab044
--- /dev/null
+++ b/private/utils/ntbackup/inc/reqrep.h
@@ -0,0 +1,159 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+$name$
+.module information
+
+$paths$
+headers\reqrep.h
+subsystem\TAPE FORMAT\reqrep.h
+$0$
+
+ Name: reqrep.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the interface structure between the TFL and the
+ Loops. Called the Request/Reply Structure.
+
+ Location: BE_PRIVATE
+
+$Header: T:/LOGFILES/REQREP.H_V 1.5 19 Oct 1992 14:15:56 HUNTER $
+
+$Log: T:/LOGFILES/REQREP.H_V $
+ *
+ * Rev 1.5 19 Oct 1992 14:15:56 HUNTER
+ * Corrected Steve's typo in the defines ...
+ *
+ * Rev 1.4 15 Oct 1992 09:45:06 HUNTER
+ * Added new stream messages
+ *
+ * Rev 1.3 16 Sep 1992 14:08:18 HUNTER
+ * Added STREAM element and add LRR_SKIP_STREAM message.
+ *
+ * Rev 1.2 15 Oct 1991 14:53:24 STEVEN
+ * added end data message for variable length files
+ *
+ * Rev 1.1 10 May 1991 17:22:44 GREGG
+ * Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:15:48 GREGG
+Initial revision.
+
+ Rev 2.1 19 Jun 1990 16:06:16 HUNTER
+ Fast File Retrieval
+
+ Rev 2.0 21 May 1990 14:19:44 PAT
+ Baseline Maynstream 3.1
+
+$-4$
+**/
+#ifndef REQREP_JUNK
+#define REQREP_JUNK
+
+#include "fsys.h" /* The FileSystem Standard Interface */
+#include "tflstats.h" /* Statistics structure */
+#include "tloc.h" /* Tape Location Structure */
+
+/* $end$ include list */
+
+typedef struct {
+ UINT16 channel ;
+ UINT16 lp_message ; /* Loops Messages */
+ UINT16 tf_message ; /* Tape Format Message */
+ DBLK_PTR cur_dblk ; /* For loops to store dblk */
+ UINT8_PTR buff_ptr ; /* Buffer Pointer */
+ UINT16 buff_size ; /* Size of Buffer */
+ UINT16 buff_used ; /* How much was used */
+ UINT16 requested_size ; /* The Loops demands this much buffer space */
+ TLOC tape_loc ; /* The tape location position */
+ UINT16 filter_to_use ; /* Apply this filter */
+ UINT32 attributes ; /* Attributes to apply */
+ DBLK_PTR vcb_ptr ; /* Last VCB */
+ DBLK_PTR ddb_ptr ; /* Last DDB */
+ DBLK_PTR fdb_ptr ; /* Last FDB */
+ DBLK_PTR idb_ptr ; /* Last IDB */
+ TF_STATS eov_stats ; /* Statistics for this tape */
+ INT16 error_locus ; /* What the error was */
+ UINT32 error_file_offset ; /* Where in the file the error occurred */
+ UINT16 error_data_loss ; /* How much data was lost */
+ DBLK_PTR cfdb_ptr ; /* CFDB used during backup */
+ GEN_CFDB_DATA_PTR cfdb_data_ptr ; /* CFDB data used during backup */
+ STREAM_INFO stream ; /* Stream info */
+} RR, *RR_PTR ;
+
+/* Loops WRITE Messages */
+
+#define LRW_START 0x0001
+#define LRW_ABORT 0x0002
+#define LRW_VCB 0x0003
+#define LRW_DDB 0x0004
+#define LRW_FDB 0x0005
+#define LRW_IDB 0x0006
+#define LRW_CFDB 0x0007
+#define LRW_NEW_STREAM 0x0008
+#define LRW_DATA 0x0009
+#define LRW_CATALOG 0x000a
+#define LRW_EOM_ACK 0x000b
+#define LRW_END 0x000c
+#define LRW_DATA_END 0x000d
+
+/* Loops READ Messages */
+
+#define LRR_START 0x8001
+#define LRR_CATALOG 0x8002
+#define LRR_GOTO_LBA 0x8003
+#define LRR_STUFF 0x8004
+#define LRR_ABORT 0x8005
+#define LRR_SKIP 0x8006
+#define LRR_SKIP_STREAM 0x8007
+#define LRR_RETRY 0x8008
+#define LRR_EOM_ACK 0x8009
+#define LRR_FINISHED 0x800A
+
+/* TFL WRITE Messages */
+
+#define TRW_DB 0x0001
+#define TRW_DATA 0x0002
+#define TRW_FATAL_ERR 0x0003
+#define TRW_DONE 0x0004
+#define TRW_EOM 0x0005
+#define TRW_CATALOG 0x0006
+#define TRW_CALL_AGAIN 0x0007
+
+/* TLF READ Messages */
+
+#define TRR_VCB 0x8001
+#define TRR_DDB 0x8002
+#define TRR_FDB 0x8003
+#define TRR_IDB 0x8004
+#define TRR_CFDB 0x8005
+#define TRR_UDB 0x8006
+#define TRR_NEW_STREAM 0x8007
+#define TRR_CATALOG 0x8008
+#define TRR_DATA 0x8009
+#define TRR_CALL_AGAIN 0x800a
+#define TRR_DATA_END 0x800b
+
+/* Can't Recover */
+#define TRR_FATAL_ERR 0x800c
+/* Possible To Recover */
+#define TRR_RECV_ERR 0x800d
+/* Hit an EOM */
+#define TRR_EOM 0x800e
+/* All Done */
+#define TRR_END 0x800f
+
+/* Error Locus Field */
+#define TF_ERROR_IN_DATA_PORTION 0x1
+#define TF_ERROR_IN_DBLK 0x2
+#define TF_ERROR_BLK_WAS_FDB 0x3
+#define TF_ERROR_BLK_WAS_DDB 0x4
+#define TF_ERROR_IN_UNKNOWN_AREA 0x5
+
+#endif
+
+
+
+
+
diff --git a/private/utils/ntbackup/inc/res_io.h b/private/utils/ntbackup/inc/res_io.h
new file mode 100644
index 000000000..475a91898
--- /dev/null
+++ b/private/utils/ntbackup/inc/res_io.h
@@ -0,0 +1,5 @@
+#ifdef MBS
+#include "mbs_res.h"
+#else
+#include "msii.h"
+#endif
diff --git a/private/utils/ntbackup/inc/resmang.h b/private/utils/ntbackup/inc/resmang.h
new file mode 100644
index 000000000..1f23136da
--- /dev/null
+++ b/private/utils/ntbackup/inc/resmang.h
@@ -0,0 +1,130 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: resmang.h
+
+ Description: This file contains the definitions, macros and function
+ prototypes for the Maynstream GUI Resource Manager (RSM).
+
+ $Log: G:/UI/LOGFILES/RESMANG.H_V $
+
+ Rev 1.15 03 Aug 1993 19:44:32 MARINA
+RSM_GetBitmapSize(), RSM_GetFontSize(): changed params to LPINT
+
+ Rev 1.14 27 Jul 1993 10:37:14 GLENN
+Now using the resource file defined in proddefs.h
+
+ Rev 1.13 24 Feb 1993 13:57:36 chrish
+Changed for CAYMAN NT.
+
+ Rev 1.12 18 Feb 1993 13:48:04 BURT
+Changes for Cayman
+
+
+ Rev 1.11 01 Nov 1992 16:32:38 DAVEV
+Unicode changes
+
+ Rev 1.10 04 Oct 1992 19:48:54 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.9 25 Jun 1992 12:24:12 STEVEN
+LPCSTR was not defined
+
+ Rev 1.8 30 Mar 1992 18:05:22 GLENN
+Added support for pulling resources from .DLL
+
+ Rev 1.7 27 Mar 1992 17:34:38 GLENN
+Changed cursor and icon load macros to functions.
+
+ Rev 1.6 02 Mar 1992 17:21:22 DAVEV
+Rev 1.3 was somehow lost. Put it back in
+
+ Rev 1.5 02 Mar 1992 17:10:36 DAVEV
+fixed mistake in previous rev. change
+
+ Rev 1.4 02 Mar 1992 11:32:14 DAVEV
+Conditionally include OMSTRING.H instead of STRINGS.H if OEM_MSOFT defined
+
+ Rev 1.3 25 Feb 1992 21:35:06 GLENN
+Created RSM_Sprintf().
+
+ Rev 1.2 22 Jan 1992 12:23:38 GLENN
+Added RSM_IsResourceID() macro.
+
+ Rev 1.1 10 Dec 1991 13:49:54 GLENN
+Added prototypes for get bitmap, font, font string sizes
+
+ Rev 1.0 20 Nov 1991 19:38:52 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+
+
+#ifndef SS_RSM_H
+
+#define SS_RSM_H
+
+
+// Windows internal CURSOR and ICON resources are between
+// WIN_RES_MIN and WIN_RES_MAX.
+
+#define WIN_RES_MIN ID(32000)
+#define WIN_RES_MAX ID(33000)
+
+#define ID_NOTDEFINED 0x7FFF
+
+#define RSM_MAGICCOLOR 0x000000FF // PURE BLUE - DIB FORMAT
+
+#define RSM_RESFILE RESFILENAME
+
+// ICON, CURSOR, BITMAP, STRING, RIBBON KEY definitions are included here.
+
+#include "icons.h"
+#include "cursors.h"
+#include "bitmaps.h"
+#include "ctl3d.h"
+
+#if defined ( OEM_MSOFT ) // include product specific files // chs: 02-24-93
+# include "omstring.h"
+#else // Include standard Maynstream product files
+# include "strings.h"
+#endif
+
+#include "keys.h"
+
+
+// STRUCTURE DEFINITIONS
+
+// MACROS
+
+#define BTNFACE_BACKGND ((WORD)200 )
+
+#define RSM_CursorSet( x ) SetCursor( x )
+#define RSM_IconDraw( w, x, y, z ) DrawIcon( z, x, y, w )
+#define RSM_IsResourceID( x ) (BOOL)( ( x ) && ! HIWORD( x ) )
+#define RSM_StringCopy( x, y, z ) RSM_StringLoad( ((VOID_PTR)((DWORD)(x))), y, z )
+
+
+// FUNCTION PROTOTYPES
+
+BOOL RSM_BitmapDraw ( WORD, INT, INT, INT, INT, HDC );
+BOOL RSM_BitmapDrawCentered ( WORD, INT, INT, INT, INT, HDC );
+BOOL RSM_BitmapFree ( WORD );
+VOID RSM_BitmapFreeAll ( VOID );
+VOID RSM_BitmapInit ( VOID );
+HBITMAP RSM_BitmapLoad ( WORD, COLORREF );
+VOID RSM_BitmapStretch ( HDC, WORD, INT, INT );
+HCURSOR RSM_CursorLoad ( LPSTR );
+BOOL RSM_GetBitmapSize ( WORD, LPINT, LPINT );
+BOOL RSM_GetFontSize ( HFONT, LPINT, LPINT, LPINT );
+BOOL RSM_GetFontStringWidth ( HFONT, LPSTR, INT );
+HICON RSM_IconLoad ( LPSTR );
+INT RSM_StringLoad ( VOID_PTR, LPSTR, INT );
+INT RSM_Sprintf ( LPSTR, LPSTR, ... );
+
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/resource.h b/private/utils/ntbackup/inc/resource.h
new file mode 100644
index 000000000..ccae66a0c
--- /dev/null
+++ b/private/utils/ntbackup/inc/resource.h
@@ -0,0 +1,114 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-91
+
+ Name: resource.h
+
+ Description: Contains the function prototypes for the resource layer.
+
+ $Log: J:/LOGFILES/RESOURCE.H_V $
+
+ Rev 1.6 27 Aug 1992 10:31:32 CLIFF
+Changed MAYN_OS2 to OS_OS2.
+
+ Rev 1.5 02 Mar 1992 09:22:48 NED
+finally got MemFill prototype right (!)
+
+ Rev 1.4 02 Mar 1992 09:08:58 NED
+re-added OS2_DMA_xfer() prototype for OS/2
+
+ Rev 1.3 28 Feb 1992 19:28:14 CHARLIE
+Did a VDEL on the previous Rev 1.3
+
+Added prototype for SetIntVectors
+
+Cannot add prototype for OS2_DMA_xfer because TDD_PTR is not yet defined
+when this file is included
+
+ Rev 1.2 28 Feb 1992 11:17:04 NED
+fixed prototype for MemFill()
+
+ Rev 1.1 25 Feb 1992 14:27:04 NED
+fixed prototype
+
+ Rev 1.0 17 Jul 1991 15:33:06 ED
+Initial revision.
+**/
+
+#ifndef RESOURCES
+
+#define RESOURCES
+
+
+/* Memory Prototypes ( Memory.c )
+*/
+
+VOID_PTR MemAlloc( UINT16, UINT16 ) ;
+VOID MemFree( VOID_PTR ) ;
+VOID_PTR MemFill( VOID_PTR, UINT16, UINT32 ) ;
+
+/* Port IO prototypes ( InOuts.c )
+*/
+
+UINT8 InByte( UINT16 ) ;
+UINT16 InWord( UINT16 ) ;
+VOID OutByte( UINT16, UINT8 ) ;
+VOID OutWord( UINT16, UINT16 ) ;
+
+#ifdef DEBUG_IO
+#include <stdio.h>
+VOID DumpIOTable( FILE * ) ;
+VOID DumpIOTraceSTD( void ) ;
+VOID DumpIOTraceFile( void ) ;
+#endif
+
+PF_VOID SetIntVec( UINT8, PF_VOID ) ;
+BOOLEAN UnMaskHwInt( INT16 ) ;
+VOID MaskHwInt( INT16 ) ;
+INT16 intstat( INT16 ) ;
+VOID int_proc( void ) ;
+VOID TestIntHandler( void );
+VOID Cli( void );
+VOID Sti( void );
+
+/* EOI Functions */
+VOID SendEOI( void ) ;
+
+/* The string prototypes */
+INT16 StringLength( CHAR_PTR ) ;
+VOID StringCopy( CHAR_PTR, CHAR_PTR ) ;
+VOID StringNCopy( CHAR_PTR, CHAR_PTR, INT16 ) ;
+INT16 StringNCompare( CHAR_PTR, CHAR_PTR, INT16 ) ;
+
+/* The dma routines */
+
+BOOLEAN DMA_Transfer( INT16, XBLK_PTR, INT16, UINT16 ) ;
+UINT8_PTR DMA_Calculate( XBLK_PTR ) ;
+VOID DMA_Disable( INT16 ) ;
+UINT16 DMA_Bytes_Left( INT16 ) ;
+BOOLEAN DMA_TerminalCount( INT16 ) ;
+VOID DMA2_Setup( void ) ;
+VOID DMA2_Reset( void ) ;
+
+#if defined(OS_OS2)
+
+struct TDD;
+struct TCB;
+BOOLEAN OS2_DMA_xfer( struct TCB *curTCB, struct TDD *curTDD ) ;
+
+#endif
+
+/* determine machine */
+INT16 DetermineMachine( void ) ;
+
+/*
+** Where to get driver files from
+*/
+
+extern CHAR_PTR GetDriverPath( VOID ) ;
+
+/* PS/2 info */
+UINT16 get_ps2_info( UINT16, UINT8_PTR ) ;
+
+PF_VOID SetIntVectors( UINT16 drive, UINT16 install ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/retbuf.h b/private/utils/ntbackup/inc/retbuf.h
new file mode 100644
index 000000000..f20748bba
--- /dev/null
+++ b/private/utils/ntbackup/inc/retbuf.h
@@ -0,0 +1,44 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: retbuf.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: The return buffer. Contains the definition for the return
+ information buffer.
+
+ Location: BE_PUBLIC
+
+
+ $Log: T:/LOGFILES/RETBUF.H_V $
+ *
+ * Rev 1.2 18 Jan 1993 16:15:42 BobR
+ * Deleted ESA info that is now found in "esa.h"
+
+**/
+/* $end$ include list */
+
+#include "esa.h"
+
+#ifndef _RETBUF
+
+#define _RETBUF
+
+
+typedef struct {
+ UINT8_PTR buffer ; /* The pointer to the buffer ( if applicable ) */
+ UINT32 len_req ; /* The transfer requested length */
+ UINT32 len_got ; /* What the driver actually got */
+ INT16 gen_error ; /* If non-zero, the GENERIC ERROR */
+ INT16 call_type ; /* The GENERIC FUNCTION CODE */
+ UINT32 status ; /* The Status Word, valid if "call_type" is GEN_STATUS or if "gen_error is set" */
+ UINT32 misc ; /* Miscellaneous Field -- see DIL functions for values */
+ UINT16 readerrs ; /* The number of read errors */
+ UINT16 underruns ; /* The number of underruns */
+ ESA the ; /* The Extended Status Array */
+} RET_BUF, *RET_BUF_PTR ;
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/ribmang.h b/private/utils/ntbackup/inc/ribmang.h
new file mode 100644
index 000000000..eb84feee6
--- /dev/null
+++ b/private/utils/ntbackup/inc/ribmang.h
@@ -0,0 +1,222 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: ribmang.h
+
+ Description: This file contains the definitions, macros, and function
+ prototypes for the Maynstream GUI Ribbon Manager (RIB).
+
+ $Log: G:\ui\logfiles\ribmang.h_v $
+
+ Rev 1.11 29 Jun 1993 13:26:46 KEVINS
+Decreased RIB_TIMERDELAY from 150 ms. to 50 ms.
+
+ Rev 1.10 09 Apr 1993 14:14:18 GLENN
+Added RIB_ItemEnable, RIB_Init, RIB_Deinit, RIB_IsItemEnabled routines.
+
+ Rev 1.9 03 Mar 1993 16:40:02 ROBG
+Added function prototype for RIB_ItemEnableState
+
+ Rev 1.8 02 Mar 1993 15:19:58 ROBG
+Added function RIB_UpPosition to support WIN32 applications.
+
+ Rev 1.7 18 Nov 1992 13:33:52 GLENN
+Added microsoft 3D button enhancement.
+
+ Rev 1.6 04 Oct 1992 19:48:56 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.5 02 Apr 1992 15:38:06 GLENN
+Added bitmap and text rectangles for buttons - drawing is faster. Supports NT better now.
+
+ Rev 1.4 12 Dec 1991 17:11:02 DAVEV
+16/32 bit port -2nd pass
+
+ Rev 1.3 10 Dec 1991 13:57:20 GLENN
+Added RIB_AutoCalcSize() stuff
+
+ Rev 1.2 05 Dec 1991 17:37:10 GLENN
+Fixed RIB_IsDownMessage() macro NT changes
+
+ Rev 1.1 04 Dec 1991 16:36:28 DAVEV
+16/32 bit Windows port changes-1st pass
+
+ Rev 1.0 20 Nov 1991 19:39:30 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+
+#ifndef SS_RIB_H
+
+#define SS_RIB_H
+
+
+// SEE BITMAPS.H FOR BITMAP RESOURCE DEFINITIONS.
+// SEE SS_RSM.H -- RESOURCE HEADER FILE -- FOR BITMAP RESOURCE ID's.
+
+#define RIB_AUTOCALCSIZE 0x7FFF
+#define RIB_ITEMUNKNOWN 0x7FFF
+#define RIB_KEYUSED TRUE
+
+#define RIB_DOWNMESSAGE 0x01
+#define RIB_DOWNREPEAT 0x02
+#define RIB_DOWNNOSTATUSTEXT 0x04
+
+#define RIB_ITEM_STYLECHICKLET 0x01
+
+#define RIB_TIMERID 1
+#define RIB_TIMERDELAY 50 // In milliseconds.
+
+#define RIB_ITEM_BORDER_WIDTH 4
+
+#define RIB_ITEM_UP 0x01
+#define RIB_ITEM_DOWN 0x00
+#define RIB_ITEM_ENABLED 0x02
+#define RIB_ITEM_DISABLED 0x00
+#define RIB_ITEM_POSITIONAL 0x04
+#define RIB_ITEM_MOMEMTARY 0x00
+#define RIB_ITEM_NOMENUITEM 0x08
+#define RIB_ITEM_MENUITEM 0x00
+
+#define RIB_RIBBON_HORIZONTAL 0x01
+#define RIB_RIBBON_VERTICAL 0x00
+#define RIB_RIBBON_ENABLED 0x02
+#define RIB_RIBBON_DISABLED 0x00
+
+#define RIB_APPEND 0xF000
+#define RIB_KEYBOARD 1
+#define RIB_MOUSE 2
+
+#define MAIN_RIBBON 1
+#define DOC_RIBBON 2
+
+#define MAIN_RIBBON_MAXITEMS 16
+#define MAIN_RIBBON_ITEMWIDTH 60
+#define MAIN_RIBBON_HEIGHT 40
+#define DOC_RIBBON_MAXITEMS 10
+#define DOC_RIBBON_ITEMWIDTH 70
+#define DOC_RIBBON_HEIGHT 24
+
+#define RIB_ITEM_TEXT_SIZE 30
+
+#define RIB_TEXT_TOP 0x0001
+#define RIB_TEXT_BOTTOM 0x0002
+#define RIB_TEXT_LEFT 0x0004
+#define RIB_TEXT_RIGHT 0x0008
+#define RIB_TEXT_HLEFT 0x0010
+#define RIB_TEXT_HRIGHT 0x0020
+#define RIB_TEXT_HCENTER 0x0040
+#define RIB_TEXT_VTOP 0x0100
+#define RIB_TEXT_VBOTTOM 0x0200
+#define RIB_TEXT_VCENTER 0x0400
+
+// STRUCTURE DEFINITIONS
+
+typedef struct {
+
+ RECT Rect; // Item rectangle.
+ RECT rcBM; // Bitmap rectangle.
+ RECT rcText; // Text rectangle.
+ WORD wStyle; // Style of displaying the item (3D, etc...)
+ WORD wEnabledID; // Enabled bitmap ID.
+ WORD wDisabledID; // Disabled bitmap ID.
+ WORD wStringID; // Item text or string ID.
+ WORD wAccelKey; // Item accelerator key.
+ WORD wState; // Current item state:
+ // bit 0, 0/1 = button DOWN/UP
+ // bit 1, 0/1 = button DISABLED/ENABLED
+ // bit 2, 0/1 = button MOMENTARY/POSITIONAL
+ // bit 3, 0/1 = button MENUITEM/NO MENUITEM
+ WORD wMessage; // Message to send to the current owner.
+ HFONT hFont; // Font handle for text.
+ WORD wTextStyle; // Text Style:
+ // bit 0, 0/1 = text on top
+ // bit 1, 0/1 = text on bottom
+ // bit 2, 0/1 = text on left
+ // bit 3, 0/1 = text on right
+ // bit 4, 0/1 = text left justified
+ // bit 5, 0/1 = text right justified
+ // bit 6, 0/1 = text horizontally centered
+ // bit 7, 0/1 = text vertically centered
+
+} DS_RIBITEMINFO, far *PDS_RIBITEMINFO;
+
+typedef struct {
+
+ HWND hWnd; // Ribbon window handle.
+ WORD wStatus; // Status:
+ // bit 0, 0/1 = ribbon VERTICAL/HORIZONTAL
+ // bit 1, 0/1 = ribbon DISABLED/ENABLED
+ WORD wType; // Type of ribbon:
+ // bit 0, 0/1 = BUTTON DOWN MESSAGE SENT
+ // bit 1, 0/1 = BUTTON DOWN WITH REPEATING DOWN
+ // bit 2, 0/1 = BUTTON DOWN WITH NO STATUS LINE MESSAGE
+ // bit 3, 0/1 = MICROSOFT TYPE 3-D
+ INT nItemWidth; // Item or button width.
+ INT nItemHeight; // Item or button height.
+ HWND hWndCurOwner; // Current window to send resulting messages to.
+ INT nMaxItems; // Maximum number of items in the ribbon.
+ INT nNumItems; // Current number of items in the ribbon.
+ INT nCurItem; // Current number of action item in the ribbon.
+ PDS_RIBITEMINFO pdsItemList; // Pointer to the ribbon item list.
+
+} DS_RIBINFO, far *PDS_RIBINFO, far *HRIBBON;
+
+typedef struct {
+
+ HRIBBON hRib; // handle to a spinner ribbon
+ WORD wIncrementMsg; // spinner increment message
+ WORD wDecrementMsg; // spinner decrement message
+
+} DS_SPINNER, far *HSPINNER;
+
+
+// MACROS
+
+#define RIB_Draw( x ) InvalidateRect( (x)->hWnd, NULL, TRUE )
+#define RIB_ItemAppend( x, y ) RIB_ItemInsert( x, RIB_APPEND, y )
+#define RIB_SetOwner( x, y ) ( (x)->hWndCurOwner = y )
+#define RIB_IsDownMessage( mp1, mp2 ) ( GET_WM_COMMAND_CMD ( mp1, mp2 ) == RIB_ITEM_DOWN )
+
+// FUNCTION PROTOTYPES
+
+WINRESULT APIENTRY WM_RibbonWndProc (HWND, MSGID, MP1, MP2);
+
+BOOL RIB_Init ( HANDLE, HANDLE );
+VOID RIB_Deinit ( VOID );
+VOID RIB_SystemChange ( VOID );
+
+BOOL RIB_Activate ( HRIBBON );
+INT RIB_AutoCalcSize ( HRIBBON );
+HRIBBON RIB_Create( HWND, WORD, INT, INT, INT );
+BOOL RIB_Deactivate ( HRIBBON );
+BOOL RIB_Destroy( HRIBBON );
+BOOL RIB_Disable( HRIBBON, LPSTR );
+BOOL RIB_Enable( HRIBBON, LPSTR );
+BOOL RIB_GetInfo( HRIBBON, PDS_RIBINFO );
+HWND RIB_GetOwner( HRIBBON );
+BOOL RIB_GetState( HRIBBON, LPSTR );
+HRIBBON RIB_Load( WORD );
+BOOL RIB_SetState ( HRIBBON, LPSTR );
+BOOL RIB_KeyUp ( HWND, WORD, MP1, MP2 );
+BOOL RIB_KeyDown ( HWND, WORD, MP1, MP2 );
+VOID RIB_UpPosition ( HRIBBON );
+
+BOOL RIB_ItemDelete ( HRIBBON, UINT );
+VOID RIB_ItemDraw ( HRIBBON, HDC, PDS_RIBITEMINFO );
+BOOL RIB_ItemEnable ( HRIBBON, WORD, BOOL );
+BOOL RIB_ItemInsert ( HRIBBON, UINT, PDS_RIBITEMINFO );
+BOOL RIB_ItemGetState ( HRIBBON, UINT, PDS_RIBITEMINFO );
+BOOL RIB_ItemReplace ( HRIBBON, WORD, PDS_RIBITEMINFO );
+BOOL RIB_ItemSetState ( HRIBBON, WORD, WORD );
+
+BOOL RIB_IsItemEnabled ( HRIBBON, WORD );
+
+HSPINNER RIB_CreateSpinner ( HWND, WORD, INT, INT, WORD, WORD );
+VOID RIB_DestroySpinner ( HSPINNER );
+BOOL RIB_EnableSpinner ( HSPINNER, BOOL );
+
+#endif
diff --git a/private/utils/ntbackup/inc/rinitfs.h b/private/utils/ntbackup/inc/rinitfs.h
new file mode 100644
index 000000000..c00ffeab0
--- /dev/null
+++ b/private/utils/ntbackup/inc/rinitfs.h
@@ -0,0 +1,30 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: rinitfs.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+ Location:
+
+
+ $Log: N:/LOGFILES/RINITFS.H_V $
+ *
+ * Rev 1.1 21 Jun 1991 13:21:06 BARRY
+ * Changes for new config.
+ *
+ * Rev 1.0 09 May 1991 13:33:32 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+INT16 AddRemoteWorkStationDLEs( DLE_HAND hand );
+
+INT16 InitializeRemote( DLE_HAND dle_hand, struct BE_CFG *cfg ) ;
+
+VOID RemoveRemote( DLE_HAND dle_hand ) ;
+
diff --git a/private/utils/ntbackup/inc/rm.h b/private/utils/ntbackup/inc/rm.h
new file mode 100644
index 000000000..da11c2a99
--- /dev/null
+++ b/private/utils/ntbackup/inc/rm.h
@@ -0,0 +1,101 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: rm.h
+
+ Description: RM.H contains the return error codes and the five entry
+ points/prototypes for the Resource Manager.
+
+ Location: RM_PUBLIC
+
+
+ $Log: G:/UI/LOGFILES/RM.H_V $
+
+ Rev 1.5 09 Jun 1993 15:06:00 MIKEP
+enable c++
+
+ Rev 1.4 01 Nov 1992 16:32:52 DAVEV
+Unicode changes
+
+ Rev 1.3 04 Oct 1992 19:48:58 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.2 28 Jul 1992 14:55:22 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.1 27 Jul 1992 14:53:16 JOHNWT
+ChuckB fixed references for NT.
+
+ Rev 1.0 20 Nov 1991 19:41:58 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifndef _rm_h_
+
+#define _rm_h_
+
+/* definitions */
+typedef struct RES_MAP *RES_MAP_PTR;
+typedef struct RES_MAP {
+ UINT16 resource_offset ; /* offset to start of data information */
+ UINT16 resource_size ; /* size of resource data within session */
+ UINT16 num_items_in_resource ; /* number of items within a given resource */
+ UINT16 offset_to_first_fixup ; /* offset to first indirect address to TEXT("fixup") */
+} RES_MAP ;
+
+typedef struct SES_INFO SES_INFO_PTR;
+typedef struct SES_INFO {
+ UINT32 session_offset ; /* offset from top of resource file */
+ UINT16 session_size ; /* size of entire session, data and map included */
+ UINT16 resource_map_offset ; /* offset to resource map from top of session */
+ UINT16 num_of_resources ; /* number of resources for this session */
+ UINT16 application_flags ; /* not used by manager at this time... */
+ RES_MAP_PTR res_map ; /* pointer to calloced array of resource map info */
+ UINT32_PTR res_data ; /* pointer to calloced block of resource data */
+} SES_INFO ;
+
+typedef struct RM_HDL *RM_HDL_PTR;
+typedef struct RM_HDL {
+ FILE *res_file_hdl ; /* source resource file handle */
+ UINT16 num_sessions ; /* number of session contained w/in Resource file */
+ SES_INFO_PTR sessions ; /* pointer to malloced array of session hdr info */
+} RM_HDL;
+
+
+/*
+ Define the error codes returned by the Resource Manager
+*/
+#define RM_NO_ERROR 0 /* need to check w/Bryan on error# ranges */
+#define RM_ERROR 200
+#define RM_FILE_NOT_FOUND 201
+#define RM_ERROR_OPENING_FILE 202
+#define RM_INSUFFICIENT_MEMORY 203
+#define RM_NULL_HDL 204
+#define RM_SESSION_NOT_FOUND 205
+#define RM_SESSION_ALREADY_OPEN 206
+#define RM_CORRUPT_SESSION 207
+#define RM_RESOURCE_NOT_FOUND 208
+
+/*
+ Open and close Resource prototypes
+*/
+RM_HDL_PTR RM_OpenResourceFile( CHAR_PTR filename, UINT16_PTR error ) ;
+VOID RM_CloseResourceFile( RM_HDL_PTR res_mgr_hdl ) ;
+
+/*
+ Load and unload Sessions prototypes
+*/
+UINT16 RM_OpenResourceSession( RM_HDL_PTR res_mgr_hdl, UINT16 session ) ;
+UINT16 RM_CloseResourceSession( RM_HDL_PTR res_mgr_hdl, UINT16 session ) ;
+
+/*
+ Return pointer to a Resource within a Loaded Session
+*/
+VOID_PTR RM_GetResource( RM_HDL_PTR res_mgr_hdl, UINT session, UINT resource,
+ UINT16_PTR num_items, UINT16_PTR error ) ;
+
+extern RM_HDL_PTR rm ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/rset.h b/private/utils/ntbackup/inc/rset.h
new file mode 100644
index 000000000..7e5b884e5
--- /dev/null
+++ b/private/utils/ntbackup/inc/rset.h
@@ -0,0 +1,71 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: rset.h
+
+ Description: include file for the rset.dlg and vset.dlg dialog
+
+
+ $Log: G:/UI/LOGFILES/RSET.H_V $
+
+ Rev 1.6 26 Feb 1993 17:18:08 STEVEN
+add registry
+
+ Rev 1.5 04 Oct 1992 19:49:00 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.4 24 Jun 1992 09:13:26 DAVEV
+added 'browse to path' button to dialog
+
+ Rev 1.3 03 Apr 1992 14:01:24 CARLS
+added vset dialog define for translate
+
+ Rev 1.2 03 Apr 1992 13:06:18 CARLS
+added translate defines
+
+ Rev 1.1 06 Feb 1992 10:10:52 CARLS
+added ID for security info
+
+ Rev 1.0 20 Nov 1991 19:34:42 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_RESTORESET 34
+#define IDD_VERIFYSET 35
+#endif
+
+#ifndef RSET_H
+#define RSET_H
+
+#define IDM_RESTORESET 303
+#define IDM_VERIFYSET 304
+#define IDD_RSET_INFO_TITLE 101
+#define IDD_RSET_INFO_TAPE 305
+#define IDD_RSET_NEXT_BUTTON 102
+#define IDD_RSET_TAPE_NAME 103
+#define IDD_RSET_PREV_BUTTON 104
+#define IDD_RSET_DRIVE_BOX 105
+#define IDD_RSET_RESTORE_PATH 110
+#define IDD_RSET_VERIFY_AFTER 106
+#define IDD_RSET_BINDERY 107
+#define IDD_RSET_REGISTRY 107
+#define IDD_RSET_OK_BUTTON 119
+#define IDD_RSET_CANCEL_BUTTON 109
+#define IDD_RSET_DRIVE_TEXT 111
+#define IDD_RSET_SET_TEXT 112
+#define IDD_RSET_PATH_TEXT 113
+#define IDD_RSET_TAPE_NAME_TEXT 114
+#define IDD_RSET_SET_LINE_1 116
+#define IDD_RSET_SET_LINE_2 117
+#define IDD_RSET_SET_LINE_3 118
+#define IDD_RSET_SCROLLBAR 115
+#define IDD_RSET_SET_INFO 120
+#define IDD_RSET_HELP_BUTTON 121
+#define IDD_RSET_BROWSE_BUTTON 122
+#define IDD_RSET_SECURITY_INFO 123
+
+#endif
diff --git a/private/utils/ntbackup/inc/rt_dlg.h b/private/utils/ntbackup/inc/rt_dlg.h
new file mode 100644
index 000000000..ffff99ebc
--- /dev/null
+++ b/private/utils/ntbackup/inc/rt_dlg.h
@@ -0,0 +1,69 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: rt_dlg.h
+
+ Description: include file for the runtime.dlg dialog
+
+
+ $Log: G:/UI/LOGFILES/RT_DLG.H_V $
+
+ Rev 1.7 04 Oct 1992 19:49:02 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.6 20 Jul 1992 10:01:30 JOHNWT
+added gas gauge display
+
+ Rev 1.5 06 Apr 1992 13:21:58 CARLS
+removed unused IDs
+
+ Rev 1.4 03 Apr 1992 13:12:06 CARLS
+didn't change the dialog ID
+
+ Rev 1.3 03 Apr 1992 13:09:50 CARLS
+added translate defines
+
+ Rev 1.0 20 Nov 1991 19:34:42 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_RUNTIME 40
+#endif
+
+#ifndef RT_DLG_H
+#define RT_DLG_H
+
+
+#define IDD_JS_DP 139
+#define IDD_JS_DP_LABEL 301
+#define IDD_JS_FP 122
+#define IDD_JS_FP_LABEL 115
+#define IDD_JS_BP 119
+#define IDD_JS_BP_LABEL 114
+#define IDD_JS_ET 121
+#define IDD_JS_ET_LABEL 113
+#define IDD_JS_CF 136
+#define IDD_JS_CF_LABEL 133
+#define IDD_JS_SF 137
+#define IDD_JS_SF_LABEL 135
+#define IDD_JS_OK 120
+#define IDD_JS_ABORT 123
+#define IDD_JS_LISTBOX 131
+#define IDD_JS_FOLDER 138
+#define IDD_JS_FILE 141
+#define IDD_JS_LINE1 125
+#define IDD_JS_LINE2 126
+#define IDD_JS_SOURCE_DRIVE 127
+#define IDD_JS_DEST_DRIVE 310
+#define IDD_JS_ARROW 312
+#define IDD_JS_SOURCE_NAME 130
+#define IDD_JS_DEST_NAME 311
+#define IDD_JS_HELP 116
+#define IDD_JS_N_OF_N 303
+#define IDD_JS_SUMMARY 305
+#define IDD_STATUS_BAR 201
+
+#endif
diff --git a/private/utils/ntbackup/inc/save_sel.h b/private/utils/ntbackup/inc/save_sel.h
new file mode 100644
index 000000000..679ea8ba3
--- /dev/null
+++ b/private/utils/ntbackup/inc/save_sel.h
@@ -0,0 +1,35 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: save_sel.h
+
+ Description: include file for the save_sel.dlg dialog
+
+
+ $Log: G:/UI/LOGFILES/SAVE_SEL.H_V $
+
+ Rev 1.3 04 Oct 1992 19:49:04 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.2 03 Apr 1992 13:15:16 CARLS
+added translate defines
+
+ Rev 1.0 20 Nov 1991 19:34:42 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_SELECTSAVE 4
+#else
+#include "dlg_ids.h"
+#endif
+
+#define IDD_DS_LIST 0x0065
+#define IDD_SS_FILENAME 0x0068
+#define IDD_SS_LIST 0x006A
+#define IDD_SAVE_FNAME 0x006B
+#define IDD_SAVE_FLIST 0x006C
+
diff --git a/private/utils/ntbackup/inc/sch_opts.h b/private/utils/ntbackup/inc/sch_opts.h
new file mode 100644
index 000000000..e448aae58
--- /dev/null
+++ b/private/utils/ntbackup/inc/sch_opts.h
@@ -0,0 +1,93 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: sch_opts.h
+
+ Description: include file for the sch_opts.dlg dialog
+
+
+ $Log: G:/UI/LOGFILES/SCH_OPTS.H_V $
+
+ Rev 1.5 04 Oct 1992 19:49:10 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.4 08 Sep 1992 15:39:16 DARRYLP
+Added new IDs for Email - Windows for Workgroups...
+
+ Rev 1.3 03 Apr 1992 13:38:12 CARLS
+wrong dialog ID for translate
+
+ Rev 1.2 03 Apr 1992 13:20:22 CARLS
+added translate defines
+
+ Rev 1.0 20 Nov 1991 19:34:42 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_SCHEDOPTS 12
+#else
+#include "dlg_ids.h"
+#endif
+
+#define IDD_J_SNAME 501
+#define IDD_J_SMONTH 502
+#define IDD_J_SDAY 503
+#define IDD_J_SYEAR 504
+#define IDD_J_SHOUR 505
+#define IDD_J_SMINUTE 506
+#define IDD_J_SDATEL 507
+#define IDD_J_SDATER 508
+#define IDD_J_STIME 509
+#define IDD_J_SINTERVAL 510
+#define IDD_J_SEVERY 511
+#define IDD_J_SREPEAT 512
+#define IDD_J_SACTIVE 513
+#define IDD_J_SCURTIME 514
+#define IDD_J_SJOBLIST 515
+#define IDD_J_SDATEBOX 516
+#define IDD_J_STIMEBOX 517
+
+#define IDD_DATE_UP 520
+#define IDD_DATE_DOWN 521
+#define IDD_TIME_UP 522
+#define IDD_TIME_DOWN 523
+#define IDD_NUMBER_UP 524
+#define IDD_NUMBER_DOWN 525
+
+#define IDD_J_SMON 531
+#define IDD_J_STUE 532
+#define IDD_J_SWED 533
+#define IDD_J_STHU 534
+#define IDD_J_SFRI 535
+#define IDD_J_SSAT 536
+#define IDD_J_SSUN 537
+#define IDD_J_SRONCE 539
+#define IDD_J_SRHOURS 540
+#define IDD_J_SRDAYSOFWEEK 541
+#define IDD_J_SRWEEKSOFMONTH 542
+#define IDD_J_SRDAYSOFMONTH 543
+#define IDD_J_SNEXT 544
+
+#define IDD_J_SWEEKDAYS 555
+#define IDD_J_SDAYOFWEEKSTRING 556
+#define IDD_J_SDAYOFWEEK 557
+#define IDD_J_SDAYOFMONTH 558
+#define IDD_J_SSHOWWEEKORMONTH 559
+#define IDD_J_SDAYOFMONTHSTRING 561
+#define IDD_J_GEMAIL 562
+#define IDD_J_EMAILENABLE 563
+#define IDD_J_EMAILSETUP 564
+
+#define IDD_J_SDATEOFMONTH 0x0068
+#define IDD_J_SNUMHOURS 0x0089
+#define IDD_J_DATEOFMONTHBOX 0x008A
+#define IDD_J_NUMHOURSBOX 0x0081
+#define IDD_J_AM 0x1112
+#define IDD_J_PM 0x1113
+#define IDD_J_SSHOWDAYS 0x021A
+#define IDD_J_RIGHTEDGE 0x1114
+#define IDD_J_BOTTOMEDGE 0x1115
diff --git a/private/utils/ntbackup/inc/sched.h b/private/utils/ntbackup/inc/sched.h
new file mode 100644
index 000000000..10738010f
--- /dev/null
+++ b/private/utils/ntbackup/inc/sched.h
@@ -0,0 +1,44 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: sched.h
+
+ Description: Dialog item IDs for scheduling.
+
+ $Log: G:/UI/LOGFILES/SCHED.H_V $
+
+ Rev 1.4 04 Oct 1992 19:49:04 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.3 06 Apr 1992 04:14:40 CHUCKB
+Fixed job list id.
+
+ Rev 1.2 06 Apr 1992 09:56:38 CHUCKB
+Added define for translation.
+
+ Rev 1.1 03 Apr 1992 13:17:26 CARLS
+added translate defines
+
+ Rev 1.0 27 Jan 1992 13:41:32 GLENN
+Initial revision.
+
+*******************************************************************************/
+
+#ifndef _sched_h_
+
+#define _sched_h_
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_JOBSCHEDULE 11
+#else
+#include "dlg_ids.h"
+#endif
+
+#define IDD_J_SLIST 0x1116
+#define IDD_J_SADD 0x1118
+#define IDD_J_SREMOVE 0x1119
+#define IDD_J_SUPDATE 0x111A
+
+#endif
diff --git a/private/utils/ntbackup/inc/schedule.h b/private/utils/ntbackup/inc/schedule.h
new file mode 100644
index 000000000..dea336310
--- /dev/null
+++ b/private/utils/ntbackup/inc/schedule.h
@@ -0,0 +1,374 @@
+/****************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+ Name: SS_DM.H
+
+ Description: This header file contains prototypes for the
+ SCHEDULE related operations.
+
+ $Log: G:/UI/LOGFILES/SCHEDULE.H_V $
+
+ Rev 1.25 01 Nov 1992 16:33:08 DAVEV
+Unicode changes
+
+ Rev 1.24 12 Oct 1992 17:33:04 DARRYLP
+Increased the size of the name field.
+
+ Rev 1.23 12 Oct 1992 17:31:58 DARRYLP
+Update to allow for multiple addressees.
+
+ Rev 1.22 09 Oct 1992 10:31:54 DARRYLP
+upgraded email password handling.
+
+ Rev 1.21 04 Oct 1992 19:49:08 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.20 28 Sep 1992 17:10:12 DARRYLP
+Additional defines for WFW email.
+
+ Rev 1.19 22 Sep 1992 15:10:40 DARRYLP
+Added prototypes for email functions.
+
+ Rev 1.18 21 Sep 1992 16:50:44 DARRYLP
+Updates to WFW email routines.
+
+ Rev 1.17 17 Sep 1992 18:04:58 DARRYLP
+New additions for WFW email.
+
+ Rev 1.16 08 Sep 1992 15:42:18 DARRYLP
+Added new structure items and associated Macros for WFW email.
+
+ Rev 1.15 08 Apr 1992 11:37:44 JOHNWT
+changed SCH_GetLongTime params
+
+ Rev 1.14 26 Mar 1992 15:20:52 JOHNWT
+fixed defs
+
+ Rev 1.13 20 Feb 1992 14:08:54 ROBG
+Changed for NT disk format.
+
+ Rev 1.12 29 Jan 1992 12:33:14 ROBG
+Added two #defines to support launcher.
+
+ Rev 1.11 25 Jan 1992 19:15:00 GLENN
+Updated
+
+ Rev 1.10 22 Jan 1992 09:31:06 ROBG
+Added parameter to SCH_StartJob.
+
+ Rev 1.9 17 Jan 1992 17:06:18 ROBG
+Added more macros.
+
+ Rev 1.8 17 Jan 1992 16:35:50 ROBG
+Added more macros.
+
+ Rev 1.7 16 Jan 1992 14:16:18 ROBG
+Changes to support new launcher.
+
+ Rev 1.6 16 Jan 1992 11:59:46 ROBG
+Added some macros and changed field 'fAbort' to 'fStatus'.
+This field will hold up to 8 status bits.
+
+ Rev 1.5 15 Jan 1992 09:35:04 ROBG
+Added define for SCH_VER_NUM and a new field to schedule record.
+
+ Rev 1.4 14 Jan 1992 15:42:32 ROBG
+Added fAborted field in schedule record.
+
+ Rev 1.3 14 Jan 1992 12:21:44 ROBG
+Added fields to support delaying the running of an instance of a job.
+
+ Rev 1.2 10 Jan 1992 17:27:42 ROBG
+Added SCH_IsLauncherRunning.
+
+ Rev 1.1 04 Dec 1991 17:12:38 CHUCKB
+Added new id's for int'l stuff.
+
+ Rev 1.0 20 Nov 1991 19:40:32 SYSTEM
+Initial revision.
+
+****************************************************************************/
+
+#ifndef SCHEDULE_H
+
+#define SCHEDULE_H
+
+#include "jobs.h"
+
+// Structure for Schedule Database
+
+// Email Send Codes
+
+#define SCH_EMAIL_ALWAYS 0x0001
+#define SCH_EMAIL_NEVER 0x0002
+#define SCH_EMAIL_ERROR 0x0004
+
+// Email bit fields
+
+#define SCH_EMAIL_ACTIVE 0x01
+#define SCH_EMAIL_INC_LOG 0x02
+
+// Repeat Modes
+
+#define SCH_ONCEONLY 0x01
+#define SCH_HOURS 0x02
+#define SCH_DAYS 0x04
+#define SCH_MONTHS_BY_WEEK 0x08
+#define SCH_MONTHS_BY_DAY 0x10
+
+// Interval values for SCH_DAYS
+
+#define SCH_MONDAY 0x01
+#define SCH_TUESDAY 0x02
+#define SCH_WEDNESDAY 0x04
+#define SCH_THURSDAY 0x08
+#define SCH_FRIDAY 0x10
+#define SCH_SATURDAY 0x20
+#define SCH_SUNDAY 0x40
+
+// Interval values for week in month
+
+#define SCH_FIRSTWEEK 0x01
+#define SCH_SECONDWEEK 0x02
+#define SCH_THIRDWEEK 0x04
+#define SCH_FOURTHWEEK 0x08
+#define SCH_LASTWEEK 0x10
+
+// Internal values for wDelayValue.
+
+#define SCH_JOBONHOLD 0xffff
+#define SCH_JOBACTIVE 0
+
+// Bit positions of the status byte.
+
+#define SCH_ABORTSTATUS 0x80
+#define SCH_MISSEDSTATUS 0x40
+#define SCH_RUNSTATUS 0x20
+#define SCH_DELAYEDSTATUS 0x10
+#define SCH_HOLDSTATUS 0x08
+
+// Values to pass in WM_PUBLISHRUNNINGJOBS message in the unique key field
+// to indicate ( no jobs or job just completed ) .
+
+#define SCH_NOJOBSFOUND 0L
+#define SCH_JOBCOMPLETE 1L
+
+
+#define SCH_NAME_SIZE 41
+#define SCH_NAME_LEN 40
+#define SCH_PASSWORD_SIZE 41
+#define SCH_PASSWORD_LEN 40
+#define SCH_ADDRESSEES_SIZE 101
+#define SCH_ADDRESSEES_LEN 100
+#define SCH_SUBJECT_SIZE 53
+#define SCH_SUBJECT_LEN 52
+#define SCH_MESSAGE_SIZE 257
+#define SCH_MESSAGE_LEN 256
+
+typedef struct {
+ // Internal
+ // Definition
+
+ INT32 fActive; // BOOL -- Tells if job is active or not.
+ INT32 bMinute; // BYTE -- Minute of next execution.
+ INT32 bHour; // BYTE -- Hour of next execution
+ INT32 bDay; // BYTE -- Day of next execution.
+ INT32 bMonth; // BYTE -- Month of next execution.
+ UINT32 wYear; // WORD -- Year of next execution.
+
+ INT32 lDateKey ; // LONG -- Creation date used as unique key.
+ INT32 fStatus ; // BYTE -- Holds status flags.
+ INT32 fInstTime; // BYTE -- Tells whether this time is to be used.
+ INT32 bInstMinute; // BYTE -- Minute of next execution for job instance.
+ INT32 bInstHour; // BYTE -- Hour of next execution for job instance.
+ INT32 bInstDay; // BYTE -- Day of next execution for job instance.
+ INT32 bInstMonth; // BYTE -- Month of next execution for job instance.
+ UINT32 wInstYear; // WORD -- Year of next execution for job instance.
+
+ INT32 bRepeatMode; // BYTE -- Repeat mode to determine next time.
+ INT32 bPrimaryInterval ; // BYTE -- Primary interval.
+ INT32 bSecondaryInterval ;// BYTE -- Used only for SCH_MONTHS_BY_WEEK.
+ // -- (day of the week of the month)
+ UINT32 wDelayValue ; // WORD -- Delay value, Hours, minutes
+
+ // Name of job. Allocated on a 4 byte boundary.
+
+ CHAR szJobname[MAX_JOBNAME_SIZE + 4-( (MAX_JOBNAME_SIZE)%4 ) ];
+
+ ULONG fEmailMisc; // Miscellaneous bit fields
+ ULONG bEmailSend; // Email setup: Always, On Err, Never
+ CHAR szName[SCH_MESSAGE_SIZE]; // Addressee names
+ CHAR szSubject[SCH_SUBJECT_SIZE]; // 52 CHAR subject
+ CHAR szMessage[SCH_MESSAGE_SIZE]; // In addition to the log file - extra message
+
+ Q_ELEM dsQElem ;
+
+} SCHEDREC, *SCHEDREC_PTR ;
+
+// Version of schedule records
+
+#define SCH_VER_NUM 3
+
+
+// macros for schedules
+
+#define SCH_SetEmailMisc( x, y ) ( (x)->fEmailMisc |= y )
+#define SCH_UnSetEmailMisc( x, y ) ( (x)->fEmailMisc &= !y )
+
+#define SCH_GetEmailActive( x ) ( (x)->fEmailMisc & SCH_EMAIL_ACTIVE )
+#define SCH_GetEmailIncLog( x ) ( (x)->fEmailMisc & SCH_EMAIL_INC_LOG )
+
+#define SCH_SetEmailAlways( x ) ( (x)->bEmailSend = SCH_EMAIL_ALWAYS )
+#define SCH_SetEmailNever( x ) ( (x)->bEmailSend = SCH_EMAIL_NEVER )
+#define SCH_SetEmailError( x ) ( (x)->bEmailSend = SCH_EMAIL_ERROR )
+#define SCH_GetEmailType( x ) ( (x)->bEmailSend )
+
+#define SCH_GetAddNames( x ) ( (x)->szName )
+#define SCH_SetAddNames( x, y ) ( lstrcpy( (x)->szName, (y) ) )
+
+#define SCH_GetMessage( x ) ( (x)->szMessage )
+#define SCH_SetMessage( x,y ) ( lstrcpy( (x)->szMessage, (y) ) )
+
+#define SCH_GetSubject( x ) ( (x)->szSubject )
+#define SCH_SetSubject( x, y ) ( lstrcpy( (x)->szSubject, (y) ) )
+
+#define SCH_GetQElem( x ) ( (x)->dsQElem )
+#define SCH_SetQElem( x, y ) ( (x)->dsQElem = (y) )
+
+#define SCH_GetActive( x ) ( (BOOL)(x)->fActive )
+#define SCH_SetActive( x, y ) ( (x)->fActive = (INT32)(y) )
+
+#define SCH_GetMinute( x ) ( (BYTE)(x)->bMinute )
+#define SCH_SetMinute( x, y ) ( (x)->bMinute = (INT32)(y) )
+
+#define SCH_GetHour( x ) ( (BYTE)(x)->bHour )
+#define SCH_SetHour( x, y ) ( (x)->bHour = (INT32)(y) )
+
+#define SCH_GetDay( x ) ( (BYTE)(x)->bDay )
+#define SCH_SetDay( x, y ) ( (x)->bDay = (INT32)(y) )
+
+#define SCH_GetMonth( x ) ( (BYTE)(x)->bMonth )
+#define SCH_SetMonth( x, y ) ( (x)->bMonth = (INT32)(y) )
+
+#define SCH_GetYear( x ) ( (WORD)(x)->wYear )
+#define SCH_SetYear( x, y ) ( (x)->wYear = (UINT32)(y) )
+
+#define SCH_GetDateKey( x ) ( (LONG)(x)->lDateKey )
+#define SCH_SetDateKey( x, y ) ( (x)->lDateKey = (INT32)(y) )
+
+#define SCH_GetStatusByte( x ) ( (BYTE)(x)->fStatus )
+#define SCH_SetStatusByte( x, y ) ( (x)->fStatus = (INT32)(y) )
+
+#define SCH_GetAbortFlag( x ) ( ((BYTE)(x)->fStatus) & SCH_ABORTSTATUS )
+#define SCH_SetAbortFlagOn( x ) ( (x)->fStatus |= SCH_ABORTSTATUS )
+#define SCH_SetAbortFlagOff( x ) ( (x)->fStatus &= ~((INT32)SCH_ABORTSTATUS) )
+
+#define SCH_GetMissedFlag( x ) ( ((BYTE)(x)->fStatus) & SCH_MISSEDSTATUS )
+#define SCH_SetMissedFlagOn( x ) ( (x)->fStatus |= SCH_MISSEDSTATUS )
+#define SCH_SetMissedFlagOff( x ) ( (x)->fStatus &= ~((INT32)SCH_MISSEDSTATUS) )
+
+#define SCH_GetRunFlag( x ) ( ((BYTE)(x)->fStatus) & SCH_RUNSTATUS )
+#define SCH_SetRunFlagOn( x ) ( (x)->fStatus |= SCH_RUNSTATUS )
+#define SCH_SetRunFlagOff( x ) ( (x)->fStatus &= ~((INT32)SCH_RUNSTATUS) )
+
+#define SCH_GetDelayedFlag( x ) ( ((BYTE)(x)->fStatus) & SCH_DELAYEDSTATUS )
+#define SCH_SetDelayedFlagOn( x ) ( (x)->fStatus |= SCH_DELAYEDSTATUS )
+#define SCH_SetDelayedFlagOff( x ) ( (x)->fStatus &= ~((INT32)SCH_DELAYEDSTATUS) )
+
+#define SCH_GetHoldFlag( x ) ( ((BYTE)(x)->fStatus) & SCH_HOLDSTATUS )
+#define SCH_SetHoldFlagOn( x ) ( (x)->fStatus |= SCH_HOLDSTATUS )
+#define SCH_SetHoldFlagOff( x ) ( (x)->fStatus &= ~((INT32)SCH_HOLDSTATUS) )
+
+#define SCH_GetUseInstTime( x ) ( (BYTE)(x)->fInstTime )
+#define SCH_SetUseInstTime( x, y ) ( (x)->fInstTime = (INT32)(y) )
+
+#define SCH_GetInstMinute( x ) ( (BYTE)(x)->bInstMinute )
+#define SCH_SetInstMinute( x, y ) ( (x)->bInstMinute = (INT32)(y) )
+
+#define SCH_GetInstHour( x ) ( (BYTE)(x)->bInstHour )
+#define SCH_SetInstHour( x, y ) ( (x)->bInstHour = (INT32)(y) )
+
+#define SCH_GetInstDay( x ) ( (BYTE)(x)->bInstDay )
+#define SCH_SetInstDay( x, y ) ( (x)->bInstDay = (INT32)(y) )
+
+#define SCH_GetInstMonth( x ) ( (BYTE)(x)->bInstMonth )
+#define SCH_SetInstMonth( x, y ) ( (x)->bInstMonth = (INT32)(y) )
+
+#define SCH_GetInstYear( x ) ( (WORD)(x)->wInstYear )
+#define SCH_SetInstYear( x, y ) ( (x)->wInstYear = (UINT32)(y) )
+
+#define SCH_GetRepeatMode( x ) ( (BYTE)(x)->bRepeatMode )
+#define SCH_SetRepeatMode( x, y ) ( (x)->bRepeatMode = (INT32)(y) )
+
+#define SCH_GetPrimaryInterval( x ) ( (BYTE)(x)->bPrimaryInterval )
+#define SCH_SetPrimaryInterval( x, y ) ( (x)->bPrimaryInterval = (INT32)(y) )
+
+#define SCH_GetSecondaryInterval( x ) ( (BYTE)(x)->bSecondaryInterval )
+#define SCH_SetSecondaryInterval( x, y ) ( (x)->bSecondaryInterval = (INT32)(y) )
+
+#define SCH_GetJobname( x ) ( (x)->szJobname )
+#define SCH_SetJobname( x, y ) ( lstrcpy ( (x)->szJobname, (y) ) )
+
+#define SCH_GetDelayValue( x ) ( (WORD)(x)->wDelayValue )
+#define SCH_SetDelayValue( x, y ) ( (x)->wDelayValue = (UINT32)(y) )
+
+/* Defines used when accessing the JOB and SCHEDULE files */
+
+#define FOPEN_ERR -1
+#define FREAD_ERR -2
+#define FWRITE_ERR -3
+#define FCLOSE_ERR -4
+
+// schedule function prototypes
+
+BOOL SCH_AnySchedFiles ( VOID ) ;
+INT SCH_Compare ( SCHEDREC_PTR, SCHEDREC_PTR ) ;
+VOID SCH_DeInitQueue ( VOID ) ;
+VOID SCH_EnQueueJob ( SCHEDREC_PTR ) ;
+SCHEDREC_PTR SCH_FindSched ( INT ) ;
+INT SCH_GetCount ( VOID ) ;
+SCHEDREC_PTR SCH_GetNextJob ( SCHEDREC_PTR ) ;
+VOID SCH_InitQueue ( VOID ) ;
+SCHEDREC_PTR SCH_InitSched ( VOID ) ;
+BOOL SCH_IsJobIconic ( INT ) ;
+INT SCH_ReadList ( VOID ) ;
+VOID SCH_Refresh ( VOID ) ;
+VOID SCH_Remove ( SCHEDREC_PTR ) ;
+INT SCH_SaveList ( VOID ) ;
+
+void SCH_AskForRunningJob ( HWND hWnd ) ;
+void SCH_NotifyLauncher ( void ) ;
+void SCH_RegisterJob ( LPSTR szJobName, INT nSchedIndex ) ;
+void SCH_StartJob ( WORD , LONG ) ;
+void SCH_UnRegisterJob ( LPSTR szJobName ) ;
+
+VOID SCH_GetTimeDateStruct ( TIME_PTR time_struct ) ;
+LONG SCH_GetLongTime ( SCHEDREC_PTR pSchedRec ) ;
+void SCH_UpdateTime ( SCHEDREC_PTR pSchedRec, TIME_PTR ptmNewTime ) ;
+BOOL SCH_IsLeapYear ( UINT usYear ) ;
+void SCH_BuildMonthCalendar ( TIME_PTR ptmDate, SCHEDREC_PTR pSchedRec ) ;
+BOOL SCH_FindNextDate ( TIME_PTR ptmStartTime, TIME_PTR ptmNewTime ) ;
+void SCH_UpdateAfterRun ( SCHEDREC_PTR ) ;
+BOOL SCH_IsLauncherRunning ( void ) ;
+VOID SCH_PublishRunningJob ( void ) ;
+SCHEDREC_PTR SCH_FindSchedByKey ( LONG lDateKey, LPINT nIndex ) ;
+
+// Email functions
+
+BOOL EM_GetUserFromINI(LPSTR lpUserName);
+BOOL EM_IsMailAvailable(void);
+BOOL EM_IsMAPIAvailable(void);
+void EM_SetMAPIAvailable(BOOL);
+BOOL EM_SendEmail(SCHEDREC_PTR, UINT);
+LPSTR EM_GetPswd(void);
+BOOL EM_SavePswd(LPSTR lpPassword);
+
+
+INT iTime ; // indicators for international date field positions
+INT iDate ;
+INT cyChildHeight ;
+CHAR sDate[2] ;
+CHAR sTime[2] ;
+CHAR sAMPM[2][5] ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/screen.h b/private/utils/ntbackup/inc/screen.h
new file mode 100644
index 000000000..44d140843
--- /dev/null
+++ b/private/utils/ntbackup/inc/screen.h
@@ -0,0 +1,74 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: screen.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+ Location:
+
+
+ $Log: W:/LOGFILES/SCREEN.H_V $
+ *
+ * Rev 1.4 24 Jun 1992 15:00:52 JOHNW
+ * Changed prototype for DebugChar
+ *
+ * Rev 1.4 23 Jun 1992 15:44:18 JOHNW
+ * Changed DebugChar prototype.
+ *
+ * Rev 1.3 07 May 1992 18:38:02 CHARLIE
+ * No change.
+ *
+ * Rev 1.2 20 Dec 1991 13:23:44 STEVEN
+ * screen macros invalid for NT also
+ *
+ * Rev 1.1 26 Jul 1991 15:03:08 STEVEN
+ * change MAYN_OS2 to OS_OS2
+ *
+ * Rev 1.0 09 May 1991 13:32:14 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef _screen_h_
+#define _screen_h_
+
+#if ( ! defined(MS_RELEASE) && defined(OS_DOS) )
+
+typedef int far *FAR_PTR;
+#define monomem ((FAR_PTR) 0xB0000000L)
+#define scrnmem ((FAR_PTR) 0xB8000000L)
+#define vid_typ_flag ((FAR_PTR) 0x400063L)
+
+#define ReadScreen( offset, ptr ) (*(ptr) = scrnmem[(offset)])
+#define WriteScreen(offset, value) \
+ ( *vid_typ_flag == 0x3b4 ? (monomem[(offset)] = (value)) : (scrnmem[(offset)] = (value)) )
+#define WriteChar( offset, ch ) WriteScreen( offset, (0x0F<<8) + ch )
+void Pulse( void );
+void DebugString( int line, char * message );
+void DebugNum( int line, unsigned long num );
+void DebugMem( int line, void * data, int size );
+void DebugSetCursor( int line, int column );
+void DebugHexNum( int ln, unsigned long num );
+void DebugChar( int ln, int ch ) ;
+
+#else
+
+#define Pulse()
+#define DebugString( l, m )
+#define DebugNum( l, n )
+#define DebugMem( l, d, s )
+#define DebugSetCursor( l, c )
+#define DebugHexNum( l, n )
+#define WriteChar( o, c)
+#define DebugChar( l, c )
+
+#endif
+
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/scriperr.h b/private/utils/ntbackup/inc/scriperr.h
new file mode 100644
index 000000000..6099af6e9
--- /dev/null
+++ b/private/utils/ntbackup/inc/scriperr.h
@@ -0,0 +1,51 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: scriperr.h
+
+ Description:
+
+
+ $Log: G:/UI/LOGFILES/SCRIPERR.H_V $
+
+ Rev 1.1 04 Oct 1992 19:49:12 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.0 20 Nov 1991 19:33:54 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifndef _scriperr_h_
+#define _scriperr_h_
+
+#define SCRIPT_ERR_BASE -0x7f00
+
+#define SCR_INVALID_SWITCH ( SCRIPT_ERR_BASE + 1 )
+#define SCR_TOO_MANY_PARMS ( SCRIPT_ERR_BASE + 2 )
+#define SCR_BAD_LIST_DIR ( SCRIPT_ERR_BASE + 3 )
+#define SCR_BAD_LOG_LEVEL ( SCRIPT_ERR_BASE + 4 )
+#define SCR_BAD_SWITCH_FLAG ( SCRIPT_ERR_BASE + 5 )
+#define SCR_BAD_DATE ( SCRIPT_ERR_BASE + 6 )
+#define SCR_CANNOT_CREATE_FSE ( SCRIPT_ERR_BASE + 7 )
+#define SCR_NO_IMAGE_FOR_DRIVE ( SCRIPT_ERR_BASE + 8 )
+#define SCR_BAD_IO_CHAN ( SCRIPT_ERR_BASE + 9 )
+#define SCR_BAD_IO_ADDR ( SCRIPT_ERR_BASE + 10 )
+#define SCR_BAD_SET_LABEL ( SCRIPT_ERR_BASE + 11 )
+#define SCR_BAD_NUM_TAPE ( SCRIPT_ERR_BASE + 12 )
+
+#define SCR_ERROR_IN_SCRIPT ( SCRIPT_ERR_BASE + 13 )
+#define SCR_ERROR_IN_CMD_LINE ( SCRIPT_ERR_BASE + 14 )
+#define SCR_CANNOT_OPEN_SCRIPT ( SCRIPT_ERR_BASE + 15 )
+#define SCR_NEST_TOO_DEEP ( SCRIPT_ERR_BASE + 16 )
+#define SCR_INVALID_PATH ( SCRIPT_ERR_BASE + 17 )
+#define SCR_INVALID_TARGET_PATH ( SCRIPT_ERR_BASE + 19 )
+#define SCR_ERROR_PRINTED ( SCRIPT_ERR_BASE + 20 )
+
+#define SCR_SCRIPT_FILE_EXISTS ( SCRIPT_ERR_BASE + 21 )
+#define SCR_ERROR_WRITING_SCRIPT ( SCRIPT_ERR_BASE + 22 )
+
+
+
+#endif
diff --git a/private/utils/ntbackup/inc/script.h b/private/utils/ntbackup/inc/script.h
new file mode 100644
index 000000000..f0487de3c
--- /dev/null
+++ b/private/utils/ntbackup/inc/script.h
@@ -0,0 +1,94 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: script.h
+
+ Description:
+
+
+ $Log: G:\ui\logfiles\script.h_v $
+
+ Rev 1.5 21 Jul 1993 17:13:16 CARLS
+added bsd_ptr parameter to tbrparse function
+
+ Rev 1.4 04 Oct 1992 19:49:12 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.3 11 Sep 1992 11:17:34 DAVEV
+MikeP's changes from Microsoft
+
+ Rev 1.2 12 Aug 1992 18:25:14 STEVEN
+fix warnings
+
+ Rev 1.1 28 Jul 1992 14:55:16 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.0 20 Nov 1991 19:39:16 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifndef _script_h_
+#define _script_h_
+
+/*
+ Define the operations to be performed
+*/
+
+#define TBACKUP 0
+#define TRESTORE 1
+#define TVERIFY 2
+#define TDIR 3
+#define TARCHIVE 4
+#define TENSION 5
+#define TERASE 6
+#define TBACKUP_CONT 7
+#define TARCHIVE_VERIFY 8
+#define TVERIFY_LAST 9
+#define TARCHIVE_DELETE 10
+#define TBACKUP_MAC 11
+
+#define MAX_SCRIPTS 12
+
+VOID build_script_menu(
+ UINT16 menu_type ) ;
+
+VOID add_script_item_to_backup(
+ CHAR_PTR script_name,
+ UINT16 menu_type ) ;
+
+#ifndef OS_WIN32
+ struct M_POSITION ;
+
+ VOID del_script_item_from_backup(
+ struct M_POSITION *select_ptr,
+ UINT16_PTR menu_item ) ;
+
+ VOID execute_script(
+ struct M_POSITION *select_ptr,
+ UINT16_PTR menu_item ) ;
+#endif
+
+VOID end_script_process(
+ INT16 error ) ;
+
+BOOLEAN script_file_exists(
+ CHAR_PTR script_name,
+ CHAR_PTR script_ext ) ;
+
+INT tbrparse(
+ struct CDS **cfg,
+ struct HEAD_DLE *dle_hand,
+ struct BSD_LIST *bsd_hand,
+ CHAR_PTR src_string,
+ INT mode,
+ BSD_PTR bsd_ptr ) ;
+
+INT16 WriteScriptFile(
+ struct BSD_LIST *bsd_hand,
+ CHAR_PTR fname ) ;
+
+INT16 SCR_ProcessBSD( FILE *fptr, struct BSD *bsd ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/script_p.h b/private/utils/ntbackup/inc/script_p.h
new file mode 100644
index 000000000..03b64e849
--- /dev/null
+++ b/private/utils/ntbackup/inc/script_p.h
@@ -0,0 +1,241 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+$name$
+.module information
+
+$paths$
+headers\script_p.h
+subsystem\USER INTERFACE\script_p.h
+$0$
+
+ Name: script_p.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+ Location:
+
+$Header: G:\ui\logfiles\script_p.h_v 1.5 21 Jul 1993 17:13:42 CARLS $
+
+$Log: G:\ui\logfiles\script_p.h_v $
+
+ Rev 1.5 21 Jul 1993 17:13:42 CARLS
+added bsd_ptr parameter to tbparse function
+
+ Rev 1.4 01 Nov 1992 16:33:22 DAVEV
+Unicode changes
+
+ Rev 1.3 04 Oct 1992 19:49:14 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.2 28 Jul 1992 14:56:56 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.1 15 May 1992 13:38:34 MIKEP
+nt pass 2
+
+ Rev 1.0 20 Nov 1991 19:35:58 SYSTEM
+Initial revision.
+
+**/
+/* $end$ */
+
+
+#ifndef SCRIPT_P_H
+#define SCRIPT_P_H
+
+#include "script_s.h"
+
+/*
+ Define the switch actions for backup
+*/
+
+#define SW_MINUS_A 0
+#define SW_APPEND 1
+#define SW_CSR 2
+#define SW_DATE 3
+#define SW_EMPTY 4
+#define SW_FILES 5
+#define SW_IOCHAN 6
+#define SW_IRQ 7
+#define SW_LABEL 8
+#define SW_MODIFIED 9
+#define SW_NONDOS 10
+#define SW_PASSWORD 11
+#define SW_STDIN 12
+#define SW_SUBDIR 13
+#define SW_EXCLUDE 14
+#define SW_YES 15
+#define SW_DEBUG 16
+#define SW_MINUS_H 17
+#define SW_MINUS_S 18
+#define SW_DOS_IMAGE 19
+#define SW_WIDE 20
+#define SW_PAUSE 21
+#define SW_P 22
+#define SW_Q 23
+#define SW_SETNO 24
+#define SW_LIST 25
+#define SW_ERASE_TAPE 26
+#define SW_ENTIRE 27
+#define SW_3270 28
+#define SW_REV 29
+#define SW_NTAPE 30
+#define SW_B_INUSE 31
+#define SW_LOG_LEVEL 32
+#define SW_AFP 33
+#define SW_NDATE 34
+#define SW_LONG 35
+#define SW_AUTO_VER 36
+#define SW_BACK_NAME 37
+#define SW_TAPE_NAME 38
+
+#ifdef MBS
+
+#define SW_ALL_VERSIONS 39
+#define SW_DELETED_ONLY 40
+#define SW_NON_DELETED_ONLY 41
+#define SW_BKUP_DATE 42
+
+#endif
+
+#define SW_ACCESS_DATE 43
+#define SW_FMARK 44
+#define SW_TRANSFER 45
+#define SW_TPNUM 46
+#define SW_BSNUM 47
+#define SW_TPSEQ 48
+
+
+/**
+ Inputs for tbsyntab FSM tbrparse
+**/
+
+#define T_AT_SIGN 0
+#define T_BAD_TOKEN 1
+#define T_EARLY_EOF1 2
+#define T_EARLY_EOF2 3
+#define T_EOF 4
+#define T_EQUALS 5
+#define T_FILESPEC 6
+#define T_NONDOS 7
+#define T_SWITCH 8
+#define T_TOKEN_TOO_LONG 9
+
+/**/
+/**
+ Actions for tbsyntab FSM
+**/
+
+#define SYN_ERROR 0
+#define TB_DO_NOTHING 1
+#define TB_ERROR_EXIT 2
+#define TB_NORMAL_RETURN 3
+#define TB_PROCESS_INCLUDE 4
+#define TB_PROCESS_NONDOS 5
+#define TB_PROCESS_SOURCE 6
+#define TB_PROCESS_SWITCH 7
+#define TB_PROCESS_TARGET 8
+
+/**/
+/**
+ States for tbsyntab FSM
+**/
+
+#define TB_EXPECT_INC1 0
+#define TB_EXPECT_INC2 1
+#define TB_EXPECT_SOURCE 2
+#define TB_READY1 3
+#define TB_READY2 4
+
+#define TBSYNTAB_N_INPUTS 10
+#define TBSYNTAB_N_STATES 5
+
+/**/
+/**
+ States for tblextab FSM
+**/
+
+#define EMBEDDED_SLASH1 0
+#define EMBEDDED_SLASH2 1
+#define IN_COMMENT 2
+#define IN_LITERAL1 3
+#define IN_LITERAL2 4
+#define IN_NONDOS 5
+#define IN_NONDOS2 6
+#define IN_OP1 7
+#define IN_OP2 8
+#define IN_SWITCH 9
+#define IN_WHITESPACE 10
+#define PATH_NAME 11
+#define PATH_OR_NDOS 12
+
+typedef enum {
+ DEFAULT_EARLY_MORNING,
+ DEFAULT_LATE_NIGHT
+} DATE_DEFAULT ;
+
+
+INT16 GetNumBkuSwitches( VOID ) ;
+INT16 GetNumDirSwitches( VOID ) ;
+INT16 GetNumRestSwitches( VOID ) ;
+INT16 GetNumVerSwitches( VOID ) ;
+INT16 GetNumTenSwitches( VOID ) ;
+
+
+VOID rlstok( TOKEN_PTR *tok_ptr );
+VOID rlsmem( CHAR_PTR *mem_ptr ) ;
+
+CHAR filgetc( CHAR *fin, INT16 *kludge ) ;
+VOID filpushc( CHAR c, CHAR *fin, INT16 *kludge);
+CHAR strgetc( CHAR *s, INT16 *i );
+VOID strpushc( CHAR c, CHAR *src_ptr, INT16 *i );
+TOKEN_PTR nexttok(
+ CHAR ( * nextc ) ( CHAR_PTR , INT16_PTR ),
+ VOID ( * prevc ) ( CHAR, CHAR_PTR , INT16_PTR ) ,
+ INT16_PTR curr_state,
+ INT16_PTR curr_line,
+ INT16_PTR curr_col,
+ CHAR_PTR src_ptr,
+ INT16_PTR cmd_i ) ;
+
+INT16 tbdpars( CHAR_PTR , struct DATE_TIME *, DATE_DEFAULT ) ;
+
+INT16 process_switch(
+ struct CDS **cfg, /* configuration stucture */
+ struct HEAD_DLE *dle_hand, /* Drive list handle */
+ struct BSD_LIST *bsd_hand, /* BSD list */
+ CUR_DEF_PTR cur_def, /* current FSE and BSD */
+ SW_TAB_PTR sw_tab, /* switch table */
+ INT16 n_switches, /* number of elements in sw_tab */
+ CHAR_PTR sw_name, /* switch label */
+ CHAR_PTR sw_op1, /* 1st operand or NULL */
+ CHAR_PTR sw_op2 ) ; /* 2nd operand or NULL */
+
+
+INT16 tbbuild_def_drives(
+ struct HEAD_DLE *dle_hand,
+ struct BSD_LIST *bsd_hand,
+ CHAR_PTR path,
+ INT16 path_size,
+ CHAR_PTR fspec,
+ struct CDS *cfg,
+ CUR_DEF_PTR *cur_def ) ;
+
+INT tbparse(
+ struct CDS **cfg,
+ struct HEAD_DLE *dle_hand,
+ struct BSD_LIST *bsd_hand ,
+ CHAR ( *inchar ) ( CHAR_PTR , INT16_PTR ) ,
+ VOID ( *pushchar ) ( CHAR, CHAR_PTR , INT16_PTR ),
+ CHAR_PTR src_ptr ,
+ INT16_PTR cmd_i ,
+ SW_TAB_PTR sw_tab ,
+ INT n_switches,
+ INT init_state,
+ BSD_PTR bsd_ptr ) ;
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/script_s.h b/private/utils/ntbackup/inc/script_s.h
new file mode 100644
index 000000000..6440d6135
--- /dev/null
+++ b/private/utils/ntbackup/inc/script_s.h
@@ -0,0 +1,94 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: script_s.h
+
+ Description:
+
+ Location:
+
+
+ $Log: G:/UI/LOGFILES/SCRIPT_S.H_V $
+
+ Rev 1.2 09 Jun 1993 15:10:52 MIKEP
+enable c++
+
+ Rev 1.1 04 Oct 1992 19:49:16 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.0 20 Nov 1991 19:38:42 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+
+#ifndef SCRIPT_S_H
+#define SCRIPT_S_H
+/**
+ Define the structures used by the tbackup parser
+**/
+
+/*
+ Equates
+*/
+#define MAX_DRIVE_SIZE 8 /* maximum length of drive name */
+
+/* maximum length of a single token */
+#define MAX_TOKEN_LEN ( 270 ) /* 270 = Max HPFS full-path (and then some */
+
+#define MAX_MSG_LEN 256 /* maximum length of an error message */
+#define MAX_NESTING 4 /* maximum depth of include file nesting */
+
+
+typedef struct TOKEN *TOKEN_PTR;
+typedef struct TOKEN {
+ INT16 tok_typ ; /* type of token */
+ CHAR tok_spelling[MAX_TOKEN_LEN + 1] ; /* token as given in source */
+ INT16 src_line_no ; /* line in the source file where it began */
+ INT16 src_col_no ; /* column in the source file where it began */
+ CHAR_PTR op_ptrs[2] ; /* pointers to spelling of operands in switches */
+} TOKEN;
+
+/*
+ Define what each element of a state table contains
+*/
+typedef struct STATE_TAB_TYPE *STATE_TAB_PTR;
+typedef struct STATE_TAB_TYPE {
+ UCHAR action ;
+ UCHAR next_state ;
+} STATE_TAB_TYPE;
+
+/*
+ Define a switch table
+*/
+typedef struct SW_TAB_TYPE *SW_TAB_PTR;
+typedef struct SW_TAB_TYPE {
+ CHAR_PTR sw_label ;
+ INT16 sw_action ;
+ INT16 sw_min_len ;
+ INT16 sw_num_ops ;
+} SW_TAB_TYPE;
+
+typedef struct CUR_DEF *CUR_DEF_PTR;
+typedef struct CUR_DEF{
+ BOOLEAN unused ;
+ struct FSE *cur_fse ;
+ struct BSD *cur_bsd ;
+ struct CUR_DEF *next_def ;
+} CUR_DEF;
+
+typedef
+INT16 ( * PR_FUNC ) ( ) ; /* used to indirectly invoke display routine */
+
+typedef
+CHAR ( * PFC ) ( ) ;
+
+/*
+ Define allocation functions
+*/
+
+#define allop( x ) malloc( x )
+#define alltok( ) ( TOKEN_PTR ) malloc( sizeof( TOKEN ) ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/set_cat.h b/private/utils/ntbackup/inc/set_cat.h
new file mode 100644
index 000000000..b43409f2d
--- /dev/null
+++ b/private/utils/ntbackup/inc/set_cat.h
@@ -0,0 +1,41 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: set_cat.h
+
+ Description: include file for the set_cat.dlg dialog
+
+
+ $Log: G:/UI/LOGFILES/SET_CAT.H_V $
+
+ Rev 1.5 06 May 1993 17:50:56 KEVINS
+Added catalog drive and path option.
+
+ Rev 1.4 31 Mar 1993 13:01:32 CHUCKB
+Added id for ignore OTC.
+
+ Rev 1.3 04 Oct 1992 19:49:18 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.2 03 Apr 1992 13:25:52 CARLS
+added translate defines
+
+ Rev 1.0 20 Nov 1991 19:34:42 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_SETTINGSCATALOG 18
+#else
+#include "dlg_ids.h"
+#endif
+
+#define IDD_CFULL 0x0068
+#define IDD_CIGNOREOTC 0x0069
+#define IDD_CPATH 0x006C
+#define IDD_CDRIVE 0x006A
+#define IDD_CBROWSE 0x006B
+#define IDD_CCURRENT 0x006D
diff --git a/private/utils/ntbackup/inc/set_dbug.h b/private/utils/ntbackup/inc/set_dbug.h
new file mode 100644
index 000000000..c491a733a
--- /dev/null
+++ b/private/utils/ntbackup/inc/set_dbug.h
@@ -0,0 +1,43 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: set_dbug.h
+
+ Description: include file for the set_dbug.dlg dialog
+
+
+ $Log: G:/UI/LOGFILES/SET_DBUG.H_V $
+
+ Rev 1.3 04 Oct 1992 19:49:20 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.2 03 Apr 1992 13:28:46 CARLS
+added translate defines
+
+ Rev 1.0 20 Nov 1991 19:34:42 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_SETTINGSDEBUGWINDOW 20
+#else
+#include "dlg_ids.h"
+#endif
+
+#define IDD_DB_TOWIN 0x0067
+#define IDD_DB_TOFILE 0x0068
+#define IDD_DB_RALL 0x006A
+#define IDD_DB_RFILE 0x006E
+#define IDD_DB_RNUM 0x006F
+#define IDD_DB_M 0x0070
+#define IDD_DB_WMSGS 0x0071
+#define IDD_DB_FMSGS 0x0072
+#define IDD_DB_FNAMELABEL 0x0073
+#define IDD_DB_FNAME 0x0074
+#define IDD_DB_MEMTRACE 0x0079
+#define IDD_DB_POLLDRIVEON 0x007A
+#define IDD_DB_RMEM 0x007F
+#define IDD_DB_RLAST 0x0069
diff --git a/private/utils/ntbackup/inc/set_log.h b/private/utils/ntbackup/inc/set_log.h
new file mode 100644
index 000000000..779375968
--- /dev/null
+++ b/private/utils/ntbackup/inc/set_log.h
@@ -0,0 +1,40 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: set_log.h
+
+ Description: include file for the set_log.dlg dialog
+
+
+ $Log: G:/UI/LOGFILES/SET_LOG.H_V $
+
+ Rev 1.4 10 May 1993 17:13:42 KEVINS
+Allow user to specify log file base name.
+
+ Rev 1.3 04 Oct 1992 19:49:22 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.2 03 Apr 1992 13:31:10 CARLS
+added translate defines
+
+ Rev 1.0 20 Nov 1991 19:34:42 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_SETTINGSLOGGING 16
+#else
+#include "dlg_ids.h"
+#endif
+
+#define IDD_LSUMONLY 0x006B
+#define IDD_LSUMFIL 0x006C
+#define IDD_LDETAIL 0x006D
+#define IDD_LYES 0x006F
+#define IDD_LNO 0x0070
+#define IDD_LPROMPT 0x0071
+#define IDD_LNUMKEEP 0x0069
+#define IDD_LBASENAME 0x0060
diff --git a/private/utils/ntbackup/inc/set_opts.h b/private/utils/ntbackup/inc/set_opts.h
new file mode 100644
index 000000000..cc0b288b8
--- /dev/null
+++ b/private/utils/ntbackup/inc/set_opts.h
@@ -0,0 +1,32 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: set_opts.h
+
+ Description: include file for the set_opts.dlg dialog
+
+
+ $Log: G:/UI/LOGFILES/SET_OPTS.H_V $
+
+ Rev 1.3 04 Oct 1992 19:49:22 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.2 03 Apr 1992 13:36:26 CARLS
+added translate defines
+
+ Rev 1.0 20 Nov 1991 19:34:42 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_SETTINGSOPTIONS 13
+#else
+#include "dlg_ids.h"
+#endif
+
+#define IDD_O_EJECT 0x0066
+#define IDD_O_DISPSTATUS 0x0067
+#define IDD_O_DISPSELECT 0x0068
diff --git a/private/utils/ntbackup/inc/set_prt.h b/private/utils/ntbackup/inc/set_prt.h
new file mode 100644
index 000000000..bb19cb67b
--- /dev/null
+++ b/private/utils/ntbackup/inc/set_prt.h
@@ -0,0 +1,32 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: set_prt.h
+
+ Description: include file for the set_prt.dlg dialog
+
+
+ $Log: G:/UI/LOGFILES/SET_PRT.H_V $
+
+ Rev 1.4 04 Oct 1992 19:49:24 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.3 03 Apr 1992 13:41:08 CARLS
+added translate defines
+
+ Rev 1.0 20 Nov 1991 19:34:42 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifdef TRANSLATE
+#define IDD_FILESETUP 25
+#else
+#include "dlg_ids.h"
+#endif
+
+#define IDD_TEXT1 0x0065
+#define IDD_PRINTERS 0x0066
+#define IDD_SETUP 0x0069
+#define IDHELP 100
diff --git a/private/utils/ntbackup/inc/set_rest.h b/private/utils/ntbackup/inc/set_rest.h
new file mode 100644
index 000000000..16bacc939
--- /dev/null
+++ b/private/utils/ntbackup/inc/set_rest.h
@@ -0,0 +1,38 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: set_rest.h
+
+ Description: include file for the set_rest.dlg dialog
+
+
+ $Log: G:/UI/LOGFILES/SET_REST.H_V $
+
+ Rev 1.4 04 Oct 1992 19:49:26 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.3 06 Apr 1992 09:56:26 CHUCKB
+Added define for translation.
+
+ Rev 1.2 03 Apr 1992 13:45:08 CARLS
+added translate defines
+
+ Rev 1.0 20 Nov 1991 19:34:42 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_SETTINGSRESTORE 15
+#else
+#include "dlg_ids.h"
+#endif
+
+#define IDD_RAUTOV 105
+#define IDD_RYES 0x006A
+#define IDD_RNO 0x006B
+#define IDD_RPROMPT 0x006C
+#define IDD_RNMREC 0x006D
+#define IDD_RPMREC 0x006E
diff --git a/private/utils/ntbackup/inc/setback.h b/private/utils/ntbackup/inc/setback.h
new file mode 100644
index 000000000..7328ffdf3
--- /dev/null
+++ b/private/utils/ntbackup/inc/setback.h
@@ -0,0 +1,44 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: setback.h
+
+ Description: include file for the setback.dlg dialog
+
+
+ $Log: G:/UI/LOGFILES/SETBACK.H_V $
+
+ Rev 1.4 06 May 1993 17:52:16 KEVINS
+Added h/w compression check box.
+
+ Rev 1.3 04 Oct 1992 19:49:18 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.2 03 Apr 1992 13:23:10 CARLS
+added translate defines
+
+ Rev 1.0 20 Nov 1991 19:34:42 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_SETTINGSBACKUP 14
+#else
+#include "dlg_ids.h"
+#endif
+
+#define IDD_BAUTOV 0x0065
+#define IDD_BINCLCAT 0x0066
+#define IDD_BREPLACE 0x0067
+#define IDD_BAPPEND 0x0068
+#define IDD_BSKIPYES 0x006F
+#define IDD_BSKIPNO 0x0070
+#define IDD_BSKIPWAIT 0x0071
+#define IDD_BNUMSECS 0x0075
+#define IDD_BMETHOD 0x0069
+#define IDD_BSPINNERBOX 0x0076
+#define IDD_BCOMPHW 0x0078
+#define IDD_BCOMPSW 0x0079
diff --git a/private/utils/ntbackup/inc/sio.h b/private/utils/ntbackup/inc/sio.h
new file mode 100644
index 000000000..fd7ca91f2
--- /dev/null
+++ b/private/utils/ntbackup/inc/sio.h
@@ -0,0 +1,80 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-92
+
+ Name: sio.h
+
+ Description: Additional compatibility functions
+
+ $Log: J:/LOGFILES/SIO.H_V $
+ *
+ * Rev 1.1 11 Dec 1992 14:39:46 CHARLIE
+ * Eliminated warning when building NRL for NB
+
+**/
+
+int _putch(int c);
+int _putchar(int c);
+int _puts(char *str);
+int _printf(char *fmt,...);
+int _sprintf(char *out_str,char *fmt,...);
+void _gotoxy(int x,int y);
+int _getx(void);
+int _gety(void);
+void _textattr(int newattr);
+int _bioskey(int cmd);
+char * _strcat(char *str1, char *str2);
+int _strnicmp(char *str1, char *str2, size_t length);
+
+#undef putch
+#undef putchar
+#undef puts
+#undef cputs
+#undef printf
+#undef cprintf
+#undef sprintf
+#undef gotoxy
+#undef getx
+#undef gety
+#undef textattr
+#undef bioskey
+#undef strlen
+
+#undef strcat
+#undef strncat
+#undef strcpy
+#undef strncpy
+#undef strcmp
+#undef strncmp
+#undef stricmp
+#undef strnicmp
+#undef strcmpi
+#undef strncmpi
+#undef clrscr
+
+#define putch _putch
+#define putchar _putchar
+#define puts _puts
+#define cputs _puts
+#define printf _printf
+#define cprintf _printf
+#define sprintf _sprintf
+#define gotoxy _gotoxy
+#define getx _getx
+#define gety _gety
+#define textattr _textattr
+#define bioskey _bioskey
+#define strlen str_len
+#define clrscr() clr_scr();crs_x=crs_y=0;
+
+#define strcat _strcat
+#define strncat _strncat
+#define strcpy _strcpy
+#define strncpy _strncpy
+#define strcmp _strcmp
+#define strncmp _strncmp
+#define stricmp _stricmp
+#define strnicmp _strnicmp
+#define strcmpi _stricmp
+#define strncmpi _strnicmp
+
+
diff --git a/private/utils/ntbackup/inc/skipno.h b/private/utils/ntbackup/inc/skipno.h
new file mode 100644
index 000000000..48691ddab
--- /dev/null
+++ b/private/utils/ntbackup/inc/skipno.h
@@ -0,0 +1,25 @@
+/***************************************************
+Copyright (c) Maynard, an Archive Company. 1993
+
+ Name: skipno.h
+
+ Description: This file contains the definitions, macros, and function
+ prototypes for the SKIPNO code.
+
+ $Log: G:\ui\logfiles\skipno.h_v $
+
+ Rev 1.0 13 Jul 1993 17:04:40 CARLS
+Initial revision
+
+****************************************************/
+
+#ifndef skipno_h
+#define skipno_h
+
+#define SKIPNO_YES_BUTTON 1
+#define SKIPNO_YES_TO_ALL_BUTTON 2
+#define SKIPNO_NO_BUTTON 3
+#define SKIPNO_CANCEL_BUTTON 4
+#define SKIPNO_ABORT 5
+
+#endif
diff --git a/private/utils/ntbackup/inc/skipopen.h b/private/utils/ntbackup/inc/skipopen.h
new file mode 100644
index 000000000..8ebc14a14
--- /dev/null
+++ b/private/utils/ntbackup/inc/skipopen.h
@@ -0,0 +1,37 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: skipopen.h
+
+ Description:
+
+ $Log: G:/UI/LOGFILES/SKIPOPEN.H_V $
+
+ Rev 1.3 04 Oct 1992 19:49:26 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.2 06 Apr 1992 08:38:14 CARLS
+removed unused ID
+
+ Rev 1.1 03 Apr 1992 13:47:14 CARLS
+added translate defines
+
+ Rev 1.0 20 Nov 1991 19:39:06 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifndef SKIPOPEN_H
+#define SKIPOPEN_H
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_SKIPOPEN 37
+#endif
+
+#define IDD_SKIP_OPEN_WAIT_TIME 120
+#define IDD_SKIP_CANCEL_BUTTON 103
+#define IDD_SKIP_FILE_NAME 104
+
+#endif
diff --git a/private/utils/ntbackup/inc/sleep.h b/private/utils/ntbackup/inc/sleep.h
new file mode 100644
index 000000000..b8e1d3692
--- /dev/null
+++ b/private/utils/ntbackup/inc/sleep.h
@@ -0,0 +1,29 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: sleep.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains prototypes for
+ the functions in sleep.c
+
+ Location:
+
+
+ $Log: G:/LOGFILES/SLEEP.H_V $
+ *
+ * Rev 1.0 09 May 1991 13:33:04 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+
+#ifndef _sleep_h_
+#define _sleep_h_
+
+VOID sleep( UINT32 thousandths ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/smb.h b/private/utils/ntbackup/inc/smb.h
new file mode 100644
index 000000000..7dfdf8dd6
--- /dev/null
+++ b/private/utils/ntbackup/inc/smb.h
@@ -0,0 +1,191 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: smb.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Public header file for the SMB workstation.
+
+ Location: SMB_PUBLIC
+
+
+ $Log: J:/LOGFILES/SMB.H_V $
+ *
+ * Rev 1.1 25 Sep 1992 16:47:32 DOUG
+ * Fixes found during REMSPX integration
+ *
+ * Rev 1.0 09 May 1991 13:32:00 HUNTER
+ * Initial revision.
+
+**/
+
+#ifndef SMB
+#define SMB
+
+/*********************/
+/* SMB CONSTANTS */
+/*********************/
+
+/* begin include list */
+
+#include "smb_c.h" /* common public header for the SMB workstation and server */
+#include "smb_s.h" /* public header file of structures for the SMB workstation */
+
+/* $end$ include list */
+
+/*******************************************/
+/* SMB Entry Point Function Prototypes */
+/*******************************************/
+
+SMB_APPLICATION_PTR SMB_GetConnectedApplication(
+ SMB_CONNECTION_PTR connection_ptr ) ;
+
+INT16 SMB_GetCriticalErrorValue(
+ SMB_CONNECTION_PTR connection_ptr ) ;
+
+SMB_DEVICE_PTR SMB_GetBoundDevice(
+ SMB_CONNECTION_PTR connection_ptr ) ;
+
+SMB_APPLICATION_PTR SMB_ScanPublishedApplications(
+ UINT16_PTR sequence_ptr ) ;
+
+CHAR_PTR SMB_GetPublishedApplicationName(
+ SMB_APPLICATION_PTR application_ptr ) ;
+
+VOID SMB_GetPublishedApplicationType(
+ SMB_APPLICATION_PTR application_ptr,
+ UINT16_PTR status_type ) ;
+
+BOOLEAN SMB_ApplicationPublishedLocally(
+ SMB_APPLICATION_PTR application_ptr ) ;
+
+SMB_CONNECTION_PTR SMB_ConnectApplication(
+ SMB_APPLICATION_PTR application_ptr ) ;
+
+SMB_DEVICE_PTR SMB_ScanDeclaredDevices(
+ SMB_CONNECTION_PTR connection_ptr,
+ UINT16_PTR sequence_ptr ) ;
+
+CHAR_PTR SMB_GetDeclaredDeviceName(
+ SMB_CONNECTION_PTR connection_ptr,
+ SMB_DEVICE_PTR device_ptr ) ;
+
+VOID SMB_GetDeclaredDeviceType(
+ SMB_CONNECTION_PTR connection_ptr,
+ SMB_DEVICE_PTR device_ptr,
+ UINT16_PTR type_ptr ) ;
+
+BOOLEAN SMB_DeclaredDeviceWriteEnabled(
+ SMB_CONNECTION_PTR connection_ptr,
+ SMB_DEVICE_PTR device_ptr ) ;
+
+BOOLEAN SMB_DeclaredDeviceVerified(
+ SMB_CONNECTION_PTR connection_ptr,
+ SMB_DEVICE_PTR device_ptr ) ;
+
+SMB_DEVICE_PTR SMB_GetCurrentBoundDevice(
+ SMB_CONNECTION_PTR connection_ptr ) ;
+
+UINT16 SMB_BindDevice(
+ SMB_CONNECTION_PTR connection_ptr,
+ SMB_DEVICE_PTR device_ptr,
+ CHAR_PTR password ) ;
+
+UINT16 SMB_ReleaseDevice(
+ SMB_CONNECTION_PTR connection_ptr ) ;
+
+UINT16 SMB_DisconnectApplication(
+ SMB_CONNECTION_PTR connection_ptr ) ;
+
+INT16 SMB_GetDiskFreeSpace(
+ SMB_CONNECTION_PTR connection_ptr,
+ UINT16_PTR available_clusters_ptr ) ;
+
+INT16 SMB_CreateSubdirectory(
+ SMB_CONNECTION_PTR connection_ptr,
+ CHAR_PTR subdirectory ) ;
+
+INT16 SMB_RemoveSubdirectory(
+ SMB_CONNECTION_PTR connection_ptr,
+ CHAR_PTR subdirectory ) ;
+
+INT16 SMB_CreateFileHandle(
+ SMB_CONNECTION_PTR connection_ptr,
+ CHAR_PTR file_name,
+ CHAR mode,
+ UINT16 attribute,
+ UINT16_PTR file_handle_ptr ) ;
+
+INT16 SMB_OpenFileHandle(
+ SMB_CONNECTION_PTR connection_ptr,
+ CHAR_PTR file_name,
+ CHAR mode,
+ UINT16_PTR file_handle_ptr,
+ UINT32_PTR file_size_ptr ) ;
+
+INT16 SMB_CloseFileHandle(
+ SMB_CONNECTION_PTR connection_ptr,
+ UINT16 file_handle ) ;
+
+INT16 SMB_ReadFile(
+ SMB_CONNECTION_PTR connection_ptr,
+ UINT16 file_handle,
+ CHAR_PTR buffer,
+ UINT16_PTR length_ptr ) ;
+
+INT16 SMB_WriteFile(
+ SMB_CONNECTION_PTR connection_ptr,
+ UINT16 file_handle,
+ CHAR_PTR buffer,
+ UINT16_PTR length_ptr ) ;
+
+INT16 SMB_DeleteFile(
+ SMB_CONNECTION_PTR connection_ptr,
+ CHAR_PTR file_name ) ;
+
+INT16 SMB_MoveFilePointer(
+ SMB_CONNECTION_PTR connection_ptr,
+ UINT16 file_handle,
+ CHAR mode,
+ UINT32 position ) ;
+
+INT16 SMB_FindFirstMatchingFile(
+ SMB_CONNECTION_PTR connection_ptr,
+ SMB_DTA_PTR dta_ptr,
+ CHAR_PTR file_name,
+ UINT16 attribute ) ;
+
+INT16 SMB_FindNextMatchingFile(
+ SMB_CONNECTION_PTR connection_ptr,
+ SMB_DTA_PTR dta_ptr ) ;
+
+INT16 SMB_FileAttribute(
+ SMB_CONNECTION_PTR connection_ptr,
+ CHAR_PTR file_name,
+ CHAR mode,
+ UINT8_PTR attribute_ptr ) ;
+
+INT16 SMB_RenameFile(
+ SMB_CONNECTION_PTR connection_ptr,
+ CHAR_PTR file_name,
+ CHAR_PTR file_rename ) ;
+
+INT16 SMB_FileDateTime(
+ SMB_CONNECTION_PTR connection_ptr,
+ UINT16 file_handle,
+ CHAR mode,
+ UINT16_PTR date_ptr,
+ UINT16_PTR time_ptr ) ;
+
+INT16 SMB_FileAccessControl(
+ SMB_CONNECTION_PTR connection_ptr,
+ UINT16 file_handle,
+ CHAR mode,
+ UINT32 offset,
+ UINT32 length ) ;
+
+#endif
+
+
diff --git a/private/utils/ntbackup/inc/smb_c.h b/private/utils/ntbackup/inc/smb_c.h
new file mode 100644
index 000000000..23e78edd1
--- /dev/null
+++ b/private/utils/ntbackup/inc/smb_c.h
@@ -0,0 +1,67 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: smb_c.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Common public header file for the SMB workstation and server.
+
+ Location: SMB_PUBLIC
+
+
+ $Log: W:/LOGFILES/SMB_C.H_V $
+ *
+ * Rev 1.1 23 Jun 1992 15:33:48 JOHNW
+ * Added LOST_CONNECTION define.
+ *
+ * Rev 1.0 09 May 1991 13:32:02 HUNTER
+ * Initial revision.
+
+**/
+
+#ifndef SMB_C
+#define SMB_C
+
+/* begin include list */
+
+#include "smb_cs.h" /* public header file of structures for the SMB server */
+#include "fartypes.h"
+
+/* $end$ include list */
+
+#ifdef DEDICATED
+VOID SMB_FinalInitialize( VOID ) ;
+
+UINT16 SMB_Remove(
+ VOID ) ;
+#endif
+
+VOID SMB_SetMachineNamePtr(
+ CHAR_PTR machine_name_ptr ) ;
+
+UINT16 SMB_Initialize(
+ SMB_DEFINITION_PTR SMB_definition_ptr ) ;
+
+UINT16 SMB_MemoryRequired(
+ VOID ) ;
+
+UINT16 SMB_PublishApplication(
+ CHAR_FAR_PTR application_name,
+ UINT16 type ) ;
+
+UINT16 SMB_WithdrawApplication(
+ SMB_APPLICATION_PTR application_ptr ) ;
+
+INT16 SMB_ApplicationSize(
+ VOID ) ;
+
+INT16 SMB_ConnectionSize(
+ VOID ) ;
+
+#define SMB_LOST_CONNECTION ( 0xfffd )
+
+#endif
+
+
diff --git a/private/utils/ntbackup/inc/smb_cs.h b/private/utils/ntbackup/inc/smb_cs.h
new file mode 100644
index 000000000..1036bd199
--- /dev/null
+++ b/private/utils/ntbackup/inc/smb_cs.h
@@ -0,0 +1,138 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: smb_cs.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Common public header file of structures for the SMB workstation and server.
+
+ Location: SMB_PUBLIC
+
+
+ $Log: W:/LOGFILES/SMB_CS.H_V $
+ *
+ * Rev 1.1 30 Jul 1992 12:21:38 JOHNW
+ * Added dos_busy_timeout field to SMB_DEFINITION structure.
+ *
+ * Rev 1.0 09 May 1991 13:33:30 HUNTER
+ * Initial revision.
+
+**/
+
+#ifndef SMB_CS
+#define SMB_CS
+
+/* begin include list */
+#include "fartypes.h"
+/* $end$ include list */
+
+#define SMB_VALUE_BASE ( 0x1000 )
+#define SMB_ERROR_BASE ( 0 - SMB_VALUE_BASE )
+
+enum SMB_ERROR_VALUES {
+
+ INVALID = ( SMB_ERROR_BASE ),
+ INSTALLED,
+ NRL_NOT_FOUND,
+ DISABLED,
+ OUT_OF_NRL_RESOURCES,
+ OUT_OF_CONNECTIONS,
+ OUT_OF_APPLICATIONS,
+ INCOMPATIBLE_DOS
+ } ;
+
+enum SMB_VALUES {
+
+ PRISTINE = ( SMB_VALUE_BASE ),
+ WAITING,
+ IN_USE,
+
+ IDLE,
+ WRITING_BLOCK,
+ DISCONNECTING,
+ } ;
+
+#define SERVER ( 0x1 )
+#define WORKSTATION ( 0x2 )
+
+#define GETTING ( 0x0 )
+#define SETTING ( 0x1 )
+
+#define LOCKING ( 0x0 )
+#define UNLOCKING ( 0x1 )
+
+#define SEEK_FROM_BOF ( 0x0 )
+#define SEEK_FROM_CURRENT_LOCATION ( 0x1 )
+#define SEEK_FROM_EOF ( 0x2 )
+
+#define MAX_SIGNATURE_NAME ( 13 )
+
+#define ALL_AVAILABLE_BUFFERS ( 65535U )
+
+typedef struct CONNECTION_STRUCT
+SMB_CONNECTION,
+far *SMB_CONNECTION_PTR,
+far * far *SMB_CONNECTION_TABLE ;
+
+typedef struct APPLICATION_STRUCT
+SMB_APPLICATION,
+far *SMB_APPLICATION_PTR,
+far * far *SMB_APPLICATION_TABLE ;
+
+typedef struct DEVICE_STRUCT
+SMB_DEVICE,
+far *SMB_DEVICE_PTR,
+far * far *SMB_DEVICE_TABLE ;
+
+typedef BOOLEAN ( *SMB_PF_ERROR_HANDLER )
+( INT16 crit_err_code,
+ SMB_CONNECTION_PTR connect_ptr ) ;
+
+typedef struct SMB_DEFINITION_STRUCT {
+
+ CHAR_FAR_PTR signature_name ;
+ UINT16 type ;
+ UINT16 max_local_applications ;
+ UINT16 max_remote_applications ;
+ UINT16 max_local_devices ;
+ UINT16 max_remote_devices ;
+ UINT16 max_concurrent_connections ;
+ UINT16 max_buffer_size ;
+ UINT16 preread_buffers ;
+ UINT32 max_receive_timeout ;
+ SMB_PF_ERROR_HANDLER error_handler ;
+ UINT16 remote_resource_filter ;
+ UINT16 dos_busy_timeout ;
+
+} far *SMB_DEFINITION_PTR,
+SMB_DEFINITION ;
+
+/* Macros to extract the configuration values from a pointer to an SMB */
+/* defintion ( as from NRL ) */
+
+#define SMBType(x) ( (x)->type )
+#define SMBMaxLocalApps(x) ( (x)->max_local_applications )
+#define SMBMaxRemoteApps(x) ( (x)->max_remote_applications )
+#define SMBMaxLocalDevices(x) ( (x)->max_local_devices )
+#define SMBMaxRemoteDevices(x) ( (x)->max_remote_devices )
+#define SMBMaxConcurrentConns(x) ( (x)->max_concurrent_connections )
+#define SMBMaxBufferSize(x) ( (x)->max_buffer_size )
+#define SMBPrereadBuffers(x) ( (x)->preread_buffers )
+#define SMBMaxReceiveTimeout(x) ( (x)->max_receive_timeout )
+#define SMBRemoteRsrcFilter(x) ( (x)->remote_resource_filter )
+
+typedef struct SMB_DTA_STRUCT {
+
+ CHAR DOS_reserved[ 21 ] ;
+ UINT8 attribute ;
+ UINT16 time ;
+ UINT16 date ;
+ UINT32 length ;
+ CHAR name[ 13 ] ;
+
+} *SMB_DTA_PTR,
+SMB_DTA ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/smb_s.h b/private/utils/ntbackup/inc/smb_s.h
new file mode 100644
index 000000000..cf4bd7f87
--- /dev/null
+++ b/private/utils/ntbackup/inc/smb_s.h
@@ -0,0 +1,37 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: smb_s.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Public header file of structures for the SMB workstation.
+
+ Location: SMB_PUBLIC
+
+
+ $Log: W:/LOGFILES/SMB_S.H_V $
+ *
+ * Rev 1.1 23 Jun 1992 15:35:28 JOHNW
+ * Moved LOST_CONNECTION define to smb_c.h
+ *
+ * Rev 1.0 09 May 1991 13:33:34 HUNTER
+ * Initial revision.
+
+**/
+
+#ifndef SMB_S
+#define SMB_S
+
+/* begin include list */
+
+#include "smb_cs.h" /* common public header file of structures for the SMB workstation and server */
+
+/* $end$ include list */
+
+#define CREATING_CLOSED_FILE ( 0x0 )
+#define CREATING_OPENED_FILE ( 0x1 )
+
+#define SMB_CRITICAL_ERROR ( 0xfffe )
+#endif
diff --git a/private/utils/ntbackup/inc/some.h b/private/utils/ntbackup/inc/some.h
new file mode 100644
index 000000000..2b6fb89d0
--- /dev/null
+++ b/private/utils/ntbackup/inc/some.h
@@ -0,0 +1,3 @@
+#include "ss_gui.h"
+#include "mui.h"
+
diff --git a/private/utils/ntbackup/inc/special.h b/private/utils/ntbackup/inc/special.h
new file mode 100644
index 000000000..c9576b16d
--- /dev/null
+++ b/private/utils/ntbackup/inc/special.h
@@ -0,0 +1,61 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: special.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the special function definitions.
+
+ Location: BE_PUBLIC
+
+
+ $Log: T:\logfiles\special.h_v $
+ *
+ * Rev 1.4 17 Dec 1993 16:40:10 GREGG
+ * Extended error reporting.
+ *
+ * Rev 1.3 16 Apr 1993 14:22:54 chrish
+ * Added define for HW compression.
+ *
+ * Rev 1.2 17 Mar 1993 14:59:40 GREGG
+ * This is Terri Lynn. Added Gregg's changes to switch the tape drive's block mode
+ * to match the block size of the current tape.
+ *
+ * Rev 1.1 28 Aug 1991 09:59:44 ED
+ * Roll in Bonoman's changes (Panther). Fixed log token.
+
+**/
+/* $end$ include list */
+
+#ifndef SPECIALS
+
+#define SPECIALS
+
+
+#define SS_ERROR_RESTORE 1
+#define SS_FLUSH_BUFFER 2
+#define SS_KILL_DEVICE 3
+#define SS_KILL_ERROR_Q 4
+#define SS_KILL_IN_Q 5
+#define SS_SET_STEP 6
+#define SS_CLR_STEP 7
+#define SS_LAST_STATUS 8
+#define SS_GET_DRV_INF 9
+#define SS_IS_ERROR 10
+#define SS_POP_ERROR_Q 11
+#define SS_IS_INQ_EMPTY 12
+#define SS_LOAD_UNLOAD 13
+#define SS_NO_MAY_ID 14
+#define SS_NO_1ST_REQ 15
+#define SS_DUMP_DVR_DATA 16
+#define SS_FIND_BLOCK 17
+#define SS_SHOW_BLOCK 18
+#define SS_PHYS_BLOCK 19
+#define SS_FORCE_MACHINE_TYPE 20
+#define SS_CHANGE_BLOCK_SIZE 21
+#define SS_SET_DRV_COMPRESSION 22
+#define SS_GET_LAST_ERROR 23
+
+#endif
diff --git a/private/utils/ntbackup/inc/srvlogin.h b/private/utils/ntbackup/inc/srvlogin.h
new file mode 100644
index 000000000..f86944b1e
--- /dev/null
+++ b/private/utils/ntbackup/inc/srvlogin.h
@@ -0,0 +1,39 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1992
+
+ Name: srvlogin.h
+
+ Description: Contains dialog control id's for attach-to-server
+ dialog.
+
+ $Log: G:/UI/LOGFILES/SRVLOGIN.H_V $
+
+ Rev 1.2 04 Oct 1992 19:49:28 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.1 03 Apr 1992 13:48:54 CARLS
+added translate defines
+
+ Rev 1.0 29 Jan 1992 11:58:50 CHUCKB
+Initial revision.
+
+*****************************************************/
+
+#ifndef srvlogin_h
+#define srvlogin_h
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_PSWD 21
+#else
+#include "dlg_ids.h"
+#endif
+
+#define IDD_SERVERNAME 101
+#define IDD_USERNAME 102
+#define IDD_PASSWORD 103
+#define IDD_LOGIN_TIMEBOX 104
+#define IDD_LOGIN_TIMEOUT 105
+#define IDD_LOGIN_HELP 106
+
+#endif
diff --git a/private/utils/ntbackup/inc/ss_gui.h b/private/utils/ntbackup/inc/ss_gui.h
new file mode 100644
index 000000000..206d3c863
--- /dev/null
+++ b/private/utils/ntbackup/inc/ss_gui.h
@@ -0,0 +1,103 @@
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: ss_gui.h
+
+ Description: This file includes the header files necessary for
+ other modules to compile with the GUI sub-system.
+ It also contains the function prototypes for
+ initializing and deinitializing the GUI sub-system.
+
+ $Log: G:/UI/LOGFILES/SS_GUI.H_V $
+
+ Rev 1.9 27 Apr 1993 21:43:50 DARRYLP
+Removed ifdef's Glenn put around CBEMON.H to eliminate unresolved externals in Nostradamus.
+
+ Rev 1.8 27 Apr 1993 16:26:40 DARRYLP
+Changed DDEMANG.H to CBEMON.H
+
+ Rev 1.7 09 Apr 1993 15:42:02 GLENN
+Ifdef'd the include of DDEMANG.H to not include it in OEM_MSOFT.
+
+ Rev 1.6 09 Apr 1993 14:12:08 GLENN
+Added ddemang.h
+
+ Rev 1.5 04 Oct 1992 19:49:30 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.4 07 Jan 1992 17:42:58 GLENN
+Added muiutil.h
+
+ Rev 1.3 03 Dec 1991 16:12:32 GLENN
+Changed the ID() macro not to use the MAKEINTRESOURCE supplied with windows
+3.1 -- temporary.
+
+ Rev 1.2 03 Dec 1991 09:54:34 GLENN
+Removed CDECL def.
+
+ Rev 1.1 27 Nov 1991 13:37:32 GLENN
+Added resource compiler dependent ifdef.
+
+ Rev 1.0 20 Nov 1991 19:41:34 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+#ifndef SS_GUI
+
+#define SS_GUI
+
+#include <windows.h>
+#include <drivinit.h>
+
+#ifdef RC_INVOKED
+
+// IF INVOKED BY THE RESOURCE COMPILER SKIP THE FUNCTION HEADERS
+
+#define ID(id) id
+
+#else
+
+// IF NOT INVOKED BY THE RESOURCE COMPILER INCLUDE THE FUNCTION HEADERS
+
+// #define ID(id) MAKEINTRESOURCE(id) // ????? took out for winstric.h
+
+#define ID(id) (LPSTR)((DWORD)((WORD)(id)))
+
+#include "portdefs.h"
+#include "stdtypes.h"
+#include "appdefs.h"
+#include "queues.h"
+#include "timers.h"
+#include "muiconf.h"
+#include "muiutil.h"
+#include "memmang.h"
+#include "menumang.h"
+#include "ribmang.h"
+#include "dialmang.h"
+#include "resmang.h"
+#include "statline.h"
+#include "dlm.h"
+#include "winmang.h"
+#include "debug.h"
+#include "prtmang.h"
+#include "helpmang.h"
+#include "msgbox.h"
+
+#include "cbemon.h"
+
+#include "global.h"
+
+#include "ctl3d.h"
+
+
+// FUNCTION PROTOTYPES
+
+BOOL GUI_Init ( LPSTR, INT );
+BOOL GUI_InitGlobals ( VOID );
+VOID GUI_Deinit ( VOID );
+
+#endif // RC_INVOKED
+
+#endif // SS_GUI
diff --git a/private/utils/ntbackup/inc/statline.h b/private/utils/ntbackup/inc/statline.h
new file mode 100644
index 000000000..dbb27981b
--- /dev/null
+++ b/private/utils/ntbackup/inc/statline.h
@@ -0,0 +1,55 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: statline.h
+
+ Description: This file contains the definitions, macros, and function
+ prototypes for the Maynstream GUI Status Line Manager (STM).
+
+ $Log: G:/UI/LOGFILES/STATLINE.H_V $
+
+ Rev 1.4 04 Oct 1992 19:49:32 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.3 10 Jul 1992 10:29:24 GLENN
+Changed the status line to be identical to the new file manager.
+
+ Rev 1.2 10 Jun 1992 16:12:42 GLENN
+Updated according to NT SPEC.
+
+ Rev 1.1 20 Apr 1992 13:52:40 GLENN
+Added status line get/set capability.
+
+ Rev 1.0 20 Nov 1991 19:35:14 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+
+#ifndef SS_STM_H
+
+#define SS_STM_H
+
+#define STATUS_LINE_HEIGHT 23
+#define STATUS_BORDER 2
+#define STATUS_INDENT 6
+#define STATUS_TEXT 500
+#define STATUS_TEXT_MARGIN 8
+#define STATUS_HIGHLIGHT_WIDTH 1
+
+// MACROS
+
+#define STM_DrawIdle( ) STM_DrawText ( gszStatusLine )
+
+// FUNCTION PROTOTYPES
+
+VOID STM_DrawBorder( VOID );
+VOID STM_DrawMemory( VOID );
+VOID STM_DrawText( LPSTR );
+VOID STM_SetIdleText( WORD );
+LPSTR STM_GetStatusLineText( VOID );
+VOID STM_SetStatusLineText( LPSTR );
+
+#endif
diff --git a/private/utils/ntbackup/inc/stats.h b/private/utils/ntbackup/inc/stats.h
new file mode 100644
index 000000000..fe95f836c
--- /dev/null
+++ b/private/utils/ntbackup/inc/stats.h
@@ -0,0 +1,299 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: stats.h
+
+ Description:
+
+
+ $Log: G:/UI/LOGFILES/STATS.H_V $
+
+ Rev 1.7 09 Jun 1993 15:06:38 MIKEP
+enable c++
+
+ Rev 1.6 20 Oct 1992 14:20:26 MIKEP
+add support for getcurrentoperation
+
+ Rev 1.5 04 Oct 1992 19:49:34 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.4 29 Jun 1992 10:38:42 MIKEP
+add hours to time display
+
+ Rev 1.3 21 May 1992 19:25:26 MIKEP
+fixes
+
+ Rev 1.2 11 May 1992 10:05:08 STEVEN
+added 64 bit support
+
+ Rev 1.1 18 Dec 1991 11:57:48 DAVEV
+16/32 bit port - 2nd pass
+
+ Rev 1.0 20 Nov 1991 19:42:18 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifndef _stats_h_
+#define _stats_h_
+
+#include "datetime.h"
+
+#ifndef max
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+typedef struct BS_STATS *BS_STATS_PTR;
+typedef struct BS_STATS {
+
+ /* These stats are for a single backup set */
+ /* Example: The operation is backing up several volumes, */
+ /* BS_STATS apply to each volume one at a time */
+
+ /* Overview stats */
+ UINT64 bs_bytes_to_be_processed ;
+ UINT32 bs_files_to_be_processed ;
+ UINT32 bs_dirs_to_be_processed ;
+
+ /* Loops stats ( does not include tape format overhead such as padding etc. ) */
+ UINT64 bs_bytes_processed ;
+ UINT32 bs_files_processed ;
+ UINT32 bs_dirs_processed ;
+
+ /* Skipped stats */
+ UINT64 bs_bytes_skipped ;
+ UINT32 bs_files_skipped ;
+ UINT32 bs_dirs_skipped ;
+
+ /* Bad stats */
+ UINT64 bs_bytes_bad ;
+ UINT32 bs_files_bad ;
+ UINT32 bs_dirs_bad ;
+
+ /* AFP stats */
+ UINT32 bs_afp_files_processed ;
+
+ /* In-use stats */
+ UINT32 bs_in_use_files_processed ;
+
+ /* Deleted stats */
+ UINT64 bs_bytes_deleted ;
+ UINT32 bs_files_deleted ;
+ UINT32 bs_dirs_deleted ;
+
+ /* Time stats */
+ UINT32 bs_start_time ;
+ UINT32 bs_end_time ;
+ UINT32 bs_start_idle ;
+ UINT32 bs_total_idle ;
+ UINT16 bs_idle_level ;
+
+ /* Verify statistics */
+ UINT32 num_security_differences ;
+ UINT32 files_different ;
+ UINT32 files_not_found ;
+ UINT32 directories_different ;
+ UINT32 directories_not_found ;
+
+ /* Tape Format Layer Statistics */
+ UINT32 soft_errs ;
+ UINT64 raw_bytes ;
+ UINT32 raw_fdbs ;
+ UINT32 raw_ddbs ;
+ UINT32 raw_idbs ;
+
+} BS_STATS;
+
+typedef struct STATS *STATS_PTR;
+typedef struct STATS {
+
+ /* backup set stats */
+ BS_STATS bs_stats ;
+
+ /* U64 space */
+ UINT64 U64space;
+ BOOLEAN U64stat;
+
+ UINT64 current_file_size; // num bytes in file
+ UINT64 current_file_done; // num bytes of file processed
+
+ /* Time stats */
+ UINT32 op_start_time ;
+ UINT32 op_end_time ;
+ UINT32 op_start_idle ;
+ UINT32 op_total_idle ;
+ UINT16 op_idle_level ;
+
+} STATS ;
+
+/*
+ Prototypes
+*/
+VOID ST_StartOperation( STATS_PTR ) ;
+VOID ST_EndOperation( STATS_PTR ) ;
+VOID ST_StartOperationIdle( STATS_PTR ) ;
+VOID ST_EndOperationIdle( STATS_PTR ) ;
+VOID ST_StartBackupSet( STATS_PTR ) ;
+VOID ST_EndBackupSet( STATS_PTR ) ;
+VOID ST_StartBackupSetIdle( STATS_PTR ) ;
+VOID ST_EndBackupSetIdle( STATS_PTR ) ;
+
+/*
+ Set Macros
+*/
+#define ST_SetBSStartTime( s, v ) ( ( VOID )( ( s )->bs_stats.bs_start_time = v ) )
+#define ST_SetBSEndTime( s, v ) ( ( VOID )( ( s )->bs_stats.bs_end_time = v ) )
+#define ST_SetBSStartIdle( s, v ) ( ( VOID )( ( s )->bs_stats.bs_start_idle = v ) )
+
+#define ST_SetOPStartTime( s, v ) ( ( VOID )( ( s )->op_start_time = v ) )
+#define ST_SetOPEndTime( s, v ) ( ( VOID )( ( s )->op_end_time = v ) )
+#define ST_SetOPStartIdle( s, v ) ( ( VOID )( ( s )->op_start_idle = v ) )
+
+#define ST_SetCFSize( s, v ) ( ( s )->current_file_size = ( v ) )
+#define ST_SetCFDone( s, v ) ( ( s )->current_file_done = ( v ) )
+
+/*
+ Get Macros
+*/
+
+#define ST_GetBSStartIdle( s ) ( ( s )->bs_stats.bs_start_idle )
+#define ST_GetOPStartIdle( s ) ( ( s )->op_start_idle )
+
+#define ST_BSIdleLevel( s ) ( ( s )->bs_stats.bs_idle_level )
+#define ST_OPIdleLevel( s ) ( ( s )->op_idle_level )
+
+#define ST_GetBSBytesToBeProcessed( s ) ( ( s )->bs_stats.bs_bytes_to_be_processed )
+#define ST_GetBSFilesToBeProcessed( s ) ( ( s )->bs_stats.bs_files_to_be_processed )
+#define ST_GetBSDirsToBeProcessed( s ) ( ( s )->bs_stats.bs_dirs_to_be_processed )
+
+#define ST_GetBSBytesProcessed( s ) ( ( s )->bs_stats.bs_bytes_processed )
+#define ST_GetBSFilesProcessed( s ) ( ( s )->bs_stats.bs_files_processed )
+#define ST_GetBSDirsProcessed( s ) ( ( s )->bs_stats.bs_dirs_processed )
+
+#define ST_GetBSBytesSkipped( s ) ( ( s )->bs_stats.bs_bytes_skipped )
+#define ST_GetBSFilesSkipped( s ) ( ( s )->bs_stats.bs_files_skipped )
+#define ST_GetBSDirsSkipped( s ) ( ( s )->bs_stats.bs_dirs_skipped )
+
+#define ST_GetBSBytesBad( s ) ( ( s )->bs_stats.bs_bytes_bad )
+#define ST_GetBSFilesBad( s ) ( ( s )->bs_stats.bs_files_bad )
+#define ST_GetBSDirsBad( s ) ( ( s )->bs_stats.bs_dirs_bad )
+
+#define ST_GetBSAFPFilesProcessed( s ) ( ( s )->bs_stats.bs_afp_files_processed )
+
+#define ST_GetBSInUseFilesProcessed( s ) ( ( s )->bs_stats.bs_in_use_files_processed )
+
+#define ST_GetBSBytesDeleted( s ) ( ( s )->bs_stats.bs_bytes_deleted )
+#define ST_GetBSFilesDeleted( s ) ( ( s )->bs_stats.bs_files_deleted )
+#define ST_GetBSDirsDeleted( s ) ( ( s )->bs_stats.bs_dirs_deleted )
+
+#define ST_GetBSStartTime( s ) ( ( s )->bs_stats.bs_start_time )
+#define ST_GetBSEndTime( s ) ( ( s )->bs_stats.bs_end_time )
+
+#define ST_GetBSElapsedHours( s ) ( ( INT16 )( ( ( ( s )->bs_stats.bs_end_time ) - ( ( s )->bs_stats.bs_start_time + \
+ ( s )->bs_stats.bs_total_idle ) ) / 3600 ) )
+#define ST_GetBSElapsedMinutes( s ) ( ( INT16 )( ( ( ( ( s )->bs_stats.bs_end_time ) - ( ( s )->bs_stats.bs_start_time + \
+ ( s )->bs_stats.bs_total_idle ) ) % 3600 ) / 60 ) )
+#define ST_GetBSElapsedSeconds( s ) ( ( INT16 )( ( ( ( s )->bs_stats.bs_end_time ) - ( ( s )->bs_stats.bs_start_time + \
+ ( s )->bs_stats.bs_total_idle ) ) % 60 ) )
+
+#define ST_GetNumSecurityDifferences( s ) ( ( s )->bs_stats.num_security_differences )
+#define ST_GetFilesDifferent( s ) ( ( s )->bs_stats.files_different )
+#define ST_GetFilesNotFound( s ) ( ( s )->bs_stats.files_not_found )
+#define ST_GetDirectoriesDifferent( s ) ( ( s )->bs_stats.directories_different )
+#define ST_GetDirectoriesNotFound( s ) ( ( s )->bs_stats.directories_not_found )
+
+#define ST_GetFilesVerified( s ) ( ( ( s )->bs_stats.bs_files_processed ) - \
+ ( ( ( s )->bs_stats.files_different ) + ( ( s )->bs_stats.files_not_found ) ) )
+
+#define ST_GetBSRate( s ) U64_Div( ( ( s )->bs_stats.bs_bytes_processed ), \
+ U64_Init(( ( max( 1L,( ( s )->bs_stats.bs_end_time ) - ( ( s )->bs_stats.bs_start_time + ( s )->bs_stats.bs_total_idle ) ) ) ),0), \
+ &((s)->U64space), &((s)->U64stat) )
+
+#define ST_GetCFSize( s ) ( ( s )->current_file_size )
+#define ST_GetCFDone( s ) ( ( s )->current_file_done )
+
+#define ST_GetSoftErrs( s ) ( ( s )->bs_stats.soft_errs )
+#define ST_GetRawBytes( s ) ( ( s )->bs_stats.raw_bytes )
+#define ST_GetRawFDBs( s ) ( ( s )->bs_stats.raw_fdbs )
+#define ST_GetRawDDBs( s ) ( ( s )->bs_stats.raw_ddbs )
+#define ST_GetRawIDBs( s ) ( ( s )->bs_stats.raw_idbs )
+
+#define ST_GetOPStartTime( s ) ( ( s )->op_start_time )
+#define ST_GetOPEndTime( s ) ( ( s )->op_end_time )
+
+#define ST_GetOPElapsedMinutes( s ) ( ( INT16 )( ( ( ( s )->op_end_time ) - ( ( s )->op_start_time + \
+ ( s )->op_total_idle ) ) / 60 ) )
+#define ST_GetOPElapsedSeconds( s ) ( ( INT16 )( ( ( ( s )->op_end_time ) - ( ( s )->op_start_time + \
+ ( s )->op_total_idle ) ) % 60 ) )
+/*
+ Add Macros
+*/
+#define ST_AddBSIdle( s, v ) ( ( VOID )( ( s )->bs_stats.bs_total_idle += v ) )
+#define ST_AddOPIdle( s, v ) ( ( VOID )( ( s )->op_total_idle += v ) )
+
+#define ST_AddBSBytesToBeProcessed( s, v ) ( ( s )->bs_stats.bs_bytes_to_be_processed = \
+ U64_Add( ( ( s )->bs_stats.bs_bytes_to_be_processed, \
+ ( v ), &((s)->U64stat ) ) )
+#define ST_AddBSFilesToBeProcessed( s, v ) ( ( VOID )( ( s )->bs_stats.bs_files_to_be_processed += v ) )
+#define ST_AddBSDirsToBeProcessed( s, v ) ( ( VOID )( ( s )->bs_stats.bs_dirs_to_be_processed += v ) )
+
+#define ST_AddBSBytesProcessed( s, v ) ( ( s )->bs_stats.bs_bytes_processed = \
+ U64_Add( ( s )->bs_stats.bs_bytes_processed, \
+ ( v ), &((s)->U64stat) ) )
+
+#define ST_AddBSFilesProcessed( s, v ) ( ( VOID )( ( s )->bs_stats.bs_files_processed += v ) )
+#define ST_AddBSDirsProcessed( s, v ) ( ( VOID )( ( s )->bs_stats.bs_dirs_processed += v ) )
+
+#define ST_AddBSBytesSkipped( s, v ) ( ( s )->bs_stats.bs_bytes_skipped = \
+ U64_Add( ( s )->bs_stats.bs_bytes_skipped, \
+ ( v ), &((s)->U64stat )) )
+
+#define ST_AddBSFilesSkipped( s, v ) ( ( VOID )( ( s )->bs_stats.bs_files_skipped += v ) )
+#define ST_AddBSDirsSkipped( s, v ) ( ( VOID )( ( s )->bs_stats.bs_dirs_skipped += v ) )
+
+#define ST_AddBSBytesBad( s, v ) ( ( s )->bs_stats.bs_bytes_bad = \
+ U64_Add( ( s )->bs_stats.bs_bytes_bad, \
+ ( v ), &((s)->U64stat ) ) )
+
+#define ST_AddBSFilesBad( s, v ) ( ( VOID )( ( s )->bs_stats.bs_files_bad += v ) )
+#define ST_AddBSDirsBad( s, v ) ( ( VOID )( ( s )->bs_stats.bs_dirs_bad += v ) )
+
+#define ST_AddBSAFPFilesProcessed( s, v ) ( ( VOID )( ( s )->bs_stats.bs_afp_files_processed += v ) )
+
+#define ST_AddBSInUseFilesProcessed( s, v ) ( ( VOID )( ( s )->bs_stats.bs_in_use_files_processed += v ) )
+
+#define ST_AddBSBytesDeleted( s, v ) ( ( s )->bs_stats.bs_bytes_deleted = \
+ U64_Add( ( s )->bs_stats.bs_bytes_deleted, \
+ ( v ), &((s)->U64stat ) ) )
+
+#define ST_AddBSFilesDeleted( s, v ) ( ( VOID )( ( s )->bs_stats.bs_files_deleted += v ) )
+#define ST_AddBSDirsDeleted( s, v ) ( ( VOID )( ( s )->bs_stats.bs_dirs_deleted += v ) )
+
+#define ST_AddBSSecondsWasted( s, v ) ( ( VOID )( ( s )->bs_stats.bs_seconds_wasted += v ) )
+#define ST_AddBSStartSecondsWasted( s, v ) ( ( VOID )( ( s )->bs_stats.bs_start_seconds_wasted += v ) )
+
+#define ST_AddNumSecurityDifferences( s, v ) ( ( VOID )( ( s )->bs_stats.num_security_differences += v ) )
+#define ST_AddFilesDifferent( s, v ) ( ( VOID )( ( s )->bs_stats.files_different += v ) )
+#define ST_AddFilesNotFound( s, v ) ( ( VOID )( ( s )->bs_stats.files_not_found += v ) )
+#define ST_AddDirectoriesDifferent( s, v ) ( ( VOID )( ( s )->bs_stats.directories_different += v ) )
+#define ST_AddDirectoriesNotFound( s, v ) ( ( VOID )( ( s )->bs_stats.directories_not_found += v ) )
+
+#define ST_AddSoftErrs( s, v ) ( ( VOID )( ( s )->bs_stats.soft_errs += v ) )
+#define ST_AddRawBytes( s, v ) ( ( s )->bs_stats.bs_raw_bytes = \
+ U64_Add( ( s )->bs_stats.bs_raw_bytes, \
+ ( v ), &((s)->U64stat ) ) )
+#define ST_AddRawFDBs( s, v ) ( ( VOID )( ( s )->bs_stats.raw_fdbs += v ) )
+#define ST_AddRawDDBs( s, v ) ( ( VOID )( ( s )->bs_stats.raw_ddbs += v ) )
+#define ST_AddRawIDBs( s, v ) ( ( VOID )( ( s )->bs_stats.raw_idbs += v ) )
+
+#define ST_AddCFDone( s, v ) ( ( s )->current_file_done = \
+ U64_Add( ( s )->current_file_done, \
+ ( v ), &((s)->U64stat ) ) )
+
+#define ST_PushBSIdleLevel( s ) ( ( ( s )->bs_stats.bs_idle_level ) ++ )
+#define ST_PopBSIdleLevel( s ) ( ( ( s )->bs_stats.bs_idle_level ) -- )
+#define ST_PushOPIdleLevel( s ) ( ( ( s )->op_idle_level ) ++ )
+#define ST_PopOPIdleLevel( s ) ( ( ( s )->op_idle_level ) -- )
+
+#endif
diff --git a/private/utils/ntbackup/inc/status.h b/private/utils/ntbackup/inc/status.h
new file mode 100644
index 000000000..16e414f12
--- /dev/null
+++ b/private/utils/ntbackup/inc/status.h
@@ -0,0 +1,43 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: status.h
+
+ Description:
+
+
+ $Log: G:/UI/LOGFILES/STATUS.H_V $
+
+ Rev 1.4 04 Oct 1992 19:49:36 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.3 28 Jul 1992 14:55:28 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.2 09 Dec 1991 17:46:32 JOHNWT
+removed yprompt
+
+ Rev 1.1 09 Dec 1991 17:09:04 DAVEV
+fixed prototype of yprompt()
+
+ Rev 1.0 20 Nov 1991 19:40:50 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifndef _status_h_
+#define _status_h_
+
+#include <stdarg.h>
+
+VOID yresprintf( INT res_id, ... ) ;
+VOID yprintf( CHAR_PTR fmt, ... ) ;
+VOID yvprintf( CHAR_PTR fmt, va_list arg_ptr ) ;
+VOID tprintf( CHAR_PTR fmt, va_list arg_ptr ) ;
+VOID typrintf( CHAR_PTR fmt, ... ) ;
+UINT16 tstatus( BOOLEAN wrap_flag ) ;
+VOID ysave_cursor_position( VOID ) ;
+VOID yrestore_cursor_position( VOID ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/std_err.h b/private/utils/ntbackup/inc/std_err.h
new file mode 100644
index 000000000..7e14ceec6
--- /dev/null
+++ b/private/utils/ntbackup/inc/std_err.h
@@ -0,0 +1,30 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: std_err.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: this file contains the standard error
+
+
+ $Log: G:/LOGFILES/STD_ERR.H_V $
+ *
+ * Rev 1.0 09 May 1991 13:32:10 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef _std_err_h_
+#define _std_err_h_
+
+#define NO_ERR 0
+
+/* standard errors: range -1 to -255 */
+
+#define OUT_OF_MEMORY -1
+#define USER_ABORT -2
+
+#endif
diff --git a/private/utils/ntbackup/inc/stdhooks.h b/private/utils/ntbackup/inc/stdhooks.h
new file mode 100644
index 000000000..ec45c6eca
--- /dev/null
+++ b/private/utils/ntbackup/inc/stdhooks.h
@@ -0,0 +1,48 @@
+
+/******************************************************************************
+
+Copyright(c) Maynard, an Archive Company 1991
+GSH
+
+ Name: stdhooks.h
+
+ Description: Contains the GUI standard hooks definitions.
+
+
+ $Log: P:/GUIWIN4/VCS/STDHOOKS.H_V $
+ *
+ * Rev 1.0 28 Jan 1993 10:47:26 STEVEN
+ * Initial revision.
+ *
+ * Rev 1.6 16 Nov 1992 15:27:00 GREGG
+ * Conditionally include unic_io.h.
+ *
+ * Rev 1.5 11 Nov 1992 18:27:34 DAVEV
+ * unicode fixes
+ *
+ * Rev 1.3 07 Oct 1992 13:57:40 STEVEN
+ * added stdwcs.h
+ *
+ * Rev 1.2 01 Sep 1992 13:10:52 STEVEN
+ * fix unaligned problem
+ *
+ * Rev 1.1 12 Aug 1992 17:50:42 STEVEN
+ * fixes at MSOFT
+ *
+ * Rev 1.0 10 Jun 1992 17:17:44 STEVEN
+ * Initial revision.
+******************************************************************************/
+
+#ifndef STDHOOKS
+#define STDHOOKS
+
+#include "memmang.h"
+#include "stdwcs.h"
+
+#ifdef UNICODE
+ #include "unic_io.h"
+#endif
+
+#include "muiutil.h"
+
+#endif
diff --git a/private/utils/ntbackup/inc/stdmacro.h b/private/utils/ntbackup/inc/stdmacro.h
new file mode 100644
index 000000000..fdff3c913
--- /dev/null
+++ b/private/utils/ntbackup/inc/stdmacro.h
@@ -0,0 +1,53 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: stdmacro.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the standard macro definitions.
+
+
+ $Log: P:/LOGFILES/STDMACRO.H_V $
+ *
+ * Rev 1.1 23 Jan 1992 17:37:42 STEVEN
+ * fix swap long
+ *
+ * Rev 1.0 09 May 1991 13:31:58 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ include list */
+
+
+#ifndef _stdmacro_h_
+#define _stdmacro_h_
+
+#define BSwapWord( x ) \
+ (0xffff & ( ((x) << 8) | (0xff & ((x) >> 8) ) ) )
+
+#define BSwapLong( x ) \
+ ( ( ( (UINT32)(BSwapWord(x) ) ) << 16L ) | \
+ ( (UINT32)(BSwapWord( (UINT16)((x) >> 16L) )) ) )
+
+/* Pointer & Address Manipulation Functions */
+
+#define ToSeg(fp) (*((unsigned *)&(fp) + 1))
+#define ToOff(fp) (*((unsigned *)&(fp)))
+
+#define MakePtr( seg, off ) (( CHAR_PTR ) (((( UINT32 ) (seg) ) << 16 ) | (( UINT32 ) (off) )))
+#define PtrToAddr(x) (( ( UINT32 ) ToSeg( (x) ) << 4 ) + (( UINT32 ) ToOff( (x) )))
+#define PtrToPage(x) ( PtrToAddr( (x) ) >> 16 )
+#define GetEnd( p, l ) ( (p) + (l) )
+#define AddrToPtr( p ) ( MakePtr( ( ( ( UINT32 ) (p) ) >> 4 ), ( ( ( UINT32 ) (p) ) & 0x0000f ) ) )
+
+
+#define UpDiv( x, y ) \
+ ( ((x)+(y)-1L) / (y) )
+
+#define WordSizeEquivalent( siz ) \
+ UpDiv( (siz), 2L )
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/stdmath.h b/private/utils/ntbackup/inc/stdmath.h
new file mode 100644
index 000000000..a7ec5dfd6
--- /dev/null
+++ b/private/utils/ntbackup/inc/stdmath.h
@@ -0,0 +1,229 @@
+/**
+$Header: T:/LOGFILES/STDMATH.H_V 1.9 05 Mar 1993 17:23:38 GREGG $
+Copyright(c) Maynard Electronics, Inc. 1984-92
+
+ Name: stdmath.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: To provide a common header for extended number numbers.
+ Currently only 64 bit manipulation functions are supported.
+ $Log: T:/LOGFILES/STDMATH.H_V $
+
+ Rev 1.9 05 Mar 1993 17:23:38 GREGG
+Removed prototypes for functions which are now macros.
+
+ Rev 1.8 27 Oct 1992 17:51:06 GREGG
+Added macros for many of the trivial functions.
+
+ Rev 1.7 12 Aug 1992 17:57:14 BARRY
+Added max and min functions. Fixed U64_Btop prototype.
+
+ Rev 1.6 23 Jul 1992 12:20:30 STEVEN
+fix warnings
+
+ Rev 1.5 29 May 1992 13:03:30 BURT
+Fixed Octal conversion from UINT64 to ASCII string for greater than 32 bit
+numbers. Added U64_Commas() function to allow commas to be placed in the
+converted ASCII string for decimal conversions.
+
+
+ Rev 1.4 28 May 1992 11:58:42 BURT
+Additions for true 64 bit division and multiplication.
+
+
+ Rev 1.3 18 Mar 1992 10:28:34 BURT
+Changed INT and INT_PTR to INT16 and INT16_PTR to ease porting to NT
+
+
+ Rev 1.2 25 Feb 1992 09:40:00 BURT
+Oops, just noticed that there's no Header and Log in this file.
+
+ Rev 1.0 02 Feb 1992 16:52:00 BURT
+ Initial revision.
+**/
+
+#ifndef STDMATH
+#define STDMATH
+
+
+/* Stuff for the true 64 bit division and multiplication operations */
+#include <stddef.h>
+
+
+#ifndef SItype
+#define SItype long int
+#endif
+
+#ifdef BIG_ENDIAN
+
+ struct long64 {
+ long high ;
+ long low ;
+} ;
+#else
+ struct long64 {
+ long low ;
+ long high ;
+} ;
+#endif
+
+/* This union is used to unpack/pack 64 bit numbers.
+ * Incoming 64 bit parameters are stored into the big_long field,
+ * and the unpacked result is read from the structure long64.
+*/
+
+typedef union
+{
+ struct long64 s ;
+ UINT64 big_long ;
+ SItype i[2] ;
+ unsigned SItype ui[2] ;
+} long_64 ;
+
+/*
+ * Internally, 64 bit ints are structures of unsigned shorts in the
+ * order determined by BIG_ENDIAN.
+*/
+
+/*
+ * Some constants for masking.
+*/
+#define B 0x10000
+#define mask_low16 (B - 1)
+
+#ifdef BIG_ENDIAN
+
+/* Note that HIGH and LOW do not describe the order
+ of words in a 64 bit number. They describe the order of words
+ in vectors ordered according to the byte order. */
+
+#define HIGH 0
+#define LOW 1
+
+#define big_end(n) 0
+#define little_end(n) ((n) - 1)
+#define next_msd(i) ((i) - 1)
+#define next_lsd(i) ((i) + 1)
+#define not_msd(i,n) ((i) >= 0)
+#define not_lsd(i,n) ((i) < (n))
+
+#else
+
+/* Intel ordering */
+#define LOW 0
+#define HIGH 1
+
+#define big_end(n) ((n) - 1)
+#define little_end(n) 0
+#define next_msd(i) ((i) + 1)
+#define next_lsd(i) ((i) - 1)
+#define not_msd(i,n) ((i) < (n))
+#define not_lsd(i,n) ((i) >= 0)
+
+#endif
+
+
+/* Function prototypes for stdmath.c */
+
+UINT64 U64_Atoli( CHAR_PTR arg, BOOLEAN_PTR status );
+CHAR_PTR U64_Litoa( UINT64 arg, CHAR_PTR string, INT16 base, BOOLEAN_PTR status );
+UINT64 U64_Add( UINT64 arg1, UINT64 arg2, BOOLEAN_PTR status );
+UINT64 U64_Sub(UINT64 arg1, UINT64 arg2, BOOLEAN_PTR status );
+UINT64 U64_Init( UINT32 lsw, UINT32 msw );
+BOOLEAN U64_To_32Bit( UINT64 arg1, UINT32_PTR lsw, UINT32_PTR msw );
+UINT64 U32_To_U64( UINT32 arg );
+UINT32 U64_Test( UINT64 arg, UINT32 lsw_mask, UINT32 msw_mask );
+UINT32 U64_Stest( UINT64 arg, CHAR_PTR mask );
+UINT64 U64_Div(UINT64 arg1, UINT64 arg2, UINT64_PTR remainder, INT16_PTR status );
+UINT64 U64_Mod(UINT64 arg1, UINT64 arg2, INT16_PTR status );
+UINT64 U64_Mult(UINT64 arg1, UINT64 arg2 ) ;
+VOID U64_Commas( BOOLEAN action ) ;
+
+/* Macros for external use */
+#define U64_Lsw( arg ) ( (arg).lsw )
+
+#define U64_Msw( arg ) ( (arg).msw )
+
+#define U64_EQ( arg1, arg2 ) ( (arg1).msw == (arg2).msw && \
+ (arg1).lsw == (arg2).lsw )
+
+#define U64_NE( arg1, arg2 ) ( ! U64_EQ( (arg1), (arg2) ) )
+
+#define U64_GT( arg1, arg2 ) ( ( (arg1).msw > (arg2).msw ) || \
+ ( (arg1).msw == (arg2).msw && \
+ (arg1).lsw > (arg2).lsw ) )
+
+#define U64_LT( arg1, arg2 ) U64_GT( (arg2), (arg1) )
+
+#define U64_GE( arg1, arg2 ) ( U64_GT( (arg1), (arg2) ) || \
+ U64_EQ( (arg1), (arg2) ) )
+
+#define U64_LE( arg1, arg2 ) ( U64_LT( (arg1), (arg2) ) || \
+ U64_EQ( (arg1), (arg2) ) )
+
+#define U64_Min( arg1, arg2 ) ( U64_GT( (arg1), (arg2) ) ? (arg2) : (arg1) )
+
+#define U64_Max( arg1, arg2 ) ( U64_GT( (arg1), (arg2) ) ? (arg1) : (arg2) )
+
+
+
+/* Defines for bitwise operations used by U64_Btop() but are hidden
+ from the user by the various macros.
+*/
+#define CLR_64BIT 0
+#define SET_64BIT 1
+#define XOR_64BIT 2
+#define OR_64BIT 3
+#define AND_64BIT 4
+#define NOT_64BIT 5
+/* Shift operations */
+#define SHL_64BIT 6
+#define SHR_64BIT 7
+
+UINT64 U64_Btop( UINT64 arg, UINT32 lsw_mask, UINT32 msw_mask,
+ INT operation, INT shift_count );
+
+/* Some macros to make life easier for the different bit wise functions.
+ All of these macros use U64_btop() to do the real work.
+*/
+#define U64_CLR( arg, mask ) \
+ U64_Btop( (arg), ( U64_Lsw( mask ) ), ( U64_Msw( mask ) ), CLR_64BIT, 0 )
+
+#define U64_SET( arg, mask ) \
+ U64_Btop( (arg), ( U64_Lsw( mask ) ), ( U64_Msw( mask ) ), SET_64BIT, 0 )
+
+#define U64_XOR( arg, mask ) \
+ U64_Btop( (arg), ( U64_Lsw( mask ) ), ( U64_Msw( mask ) ), XOR_64BIT, 0 )
+
+#define U64_OR( arg, mask ) \
+ U64_Btop( (arg), ( U64_Lsw( mask ) ), ( U64_Msw( mask ) ), OR_64BIT, 0 )
+
+#define U64_AND( arg, mask ) \
+ U64_Btop( (arg), ( U64_Lsw( mask ) ), ( U64_Msw( mask ) ), AND_64BIT, 0 )
+
+#define U64_NOT( arg, mask ) \
+ U64_Btop( (arg), ( U64_Lsw( mask ) ), ( U64_Msw( mask ) ), NOT_64BIT, 0 )
+
+
+/* Shift operations */
+/* Shift left the specified number of bits */
+#define U64_SHL( arg, shift_count ) \
+ U64_Btop( (arg), 0L, 0L, SHL_64BIT, (shift_count) )
+
+/* Shift right the specified number of bits */
+#define U64_SHR( arg, shift_count ) \
+ U64_Btop( (arg), 0L, 0L, SHR_64BIT, (shift_count) )
+
+
+/* Defines for math errors (specifically division) */
+#define U64_OK 0 /* No errors, everything's fine */
+#define U64_BAD_DIV 1 /* Attempted to divide by other than power of 2,
+ or one of the other supported cases.
+ */
+#define U64_OVRFL 2 /* Overflow error */
+#define U64_UNDFL 3 /* Underflow error */
+#define U64_DIVZ 4 /* Tried to divide by 0 */
+
+
+#endif
diff --git a/private/utils/ntbackup/inc/stdstruc.h b/private/utils/ntbackup/inc/stdstruc.h
new file mode 100644
index 000000000..9b4428720
--- /dev/null
+++ b/private/utils/ntbackup/inc/stdstruc.h
@@ -0,0 +1,25 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: stdstruc.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the universally used structures for Maynard
+ Electronics.
+
+
+ $Log: G:/LOGFILES/STDSTRUC.H_V $
+ *
+ * Rev 1.0 09 May 1991 13:32:38 HUNTER
+ * Initial revision.
+
+**/
+#ifndef _STD_STRUCT_JUNK
+#define _STD_STRUCT_JUNK
+
+/* $end$ include list */
+
+
+#endif
diff --git a/private/utils/ntbackup/inc/stdtypes.h b/private/utils/ntbackup/inc/stdtypes.h
new file mode 100644
index 000000000..2ccd9b284
--- /dev/null
+++ b/private/utils/ntbackup/inc/stdtypes.h
@@ -0,0 +1,351 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: stdtypes.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the standard type definitions.
+
+
+ $Log: P:/GUIWIN4/VCS/STDTYPES.H_V $
+ *
+ * Rev 1.1 09 Feb 1993 09:32:42 STEVEN
+ * fixed text macro it was defined twice
+ *
+ * Rev 1.0 28 Jan 1993 10:47:24 STEVEN
+ * Initial revision.
+ *
+/* $end$ include list */
+
+
+#ifndef STDTYPES
+#define STDTYPES
+
+#include <stddef.h> /* include the ANSI standard definition file */
+
+#ifdef FAR_POINTERS
+# define PTR_SIZE
+#endif
+
+#ifdef OS_WIN32
+
+# undef NEAR
+# undef FAR
+# define far
+# define near
+# define _near
+# define _far
+# define FAR
+# define NEAR
+
+# if defined(_MIPS_) || defined(_ALPHA_) || defined(_PPC_)
+# define UNALIGNED __unaligned
+# else
+# define UNALIGNED
+# endif
+
+#else
+
+# define UNALIGNED
+
+# ifndef FAR
+# define FAR far
+# endif
+
+# ifndef NEAR
+# define NEAR near
+# endif
+
+#endif
+
+#ifndef PASCAL
+# define PASCAL pascal
+#endif
+
+#ifndef CDECL
+# define CDECL cdecl
+#endif
+
+#ifndef APIENTRY
+# define APIENTRY FAR PASCAL
+#endif
+
+
+#ifndef PTR_SIZE
+#define PTR_SIZE
+#endif
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+/* Added LOCALFN to allow easy debugging of NT applications.
+ If a function is declared to be static the NT debugger doesn't
+ show local data. Oops.., Argh..., Braindeath is a terrible thing.
+ I typedef'd LOCALFN (yech!#$!) and then to compound the felony I
+ didn't test the "simple" change for the addition of LOCALFN.
+ Oh well, LABATYD. (BBB)
+*/
+
+#define LOCALFN static
+
+/* LOCALVAR is only to be used for module wide static variables.
+ It is NOT to be used for variables that are to be declared static
+ within a function. If you should use this for static vars within
+ a function the great Kahuna of bugs will descend upon on you
+ and cause much grief in your life.
+*/
+#define LOCALVAR static
+
+
+
+/** Begin ANSI/UNICODE support **/
+/*
+ UNICODE (wide character) types
+*/
+
+#define VOID void
+
+typedef VOID PTR_SIZE * VOID_PTR ;
+#define PVOID VOID_PTR
+typedef VOID ( PTR_SIZE *PF_VOID )() ;
+
+typedef char INT8 ;
+typedef char PTR_SIZE * INT8_PTR ;
+typedef INT8 ( PTR_SIZE *PF_INT8 )() ;
+typedef INT8_PTR ( PTR_SIZE *PF_INT8_PTR )() ;
+
+#define BYTE UINT8
+typedef unsigned char UINT8 ;
+typedef unsigned char PTR_SIZE * UINT8_PTR ;
+typedef UINT8 ( PTR_SIZE *PF_UINT8 )() ;
+typedef UINT8_PTR ( PTR_SIZE *PF_UINT8_PTR )() ;
+
+/* Added a generic INT type that eases porting to new platforms
+ This type should be used for all integers that do not require
+ a specific size. NOTE: The test for INT being defined was added
+ because of a conflict with os2def.h which already defines INT.
+*/
+#ifndef _WINDEF_
+typedef int INT ;
+#endif
+
+typedef int PTR_SIZE * INT_PTR ;
+typedef INT ( PTR_SIZE *PF_INT )() ;
+typedef INT_PTR ( PTR_SIZE *PF_INT_PTR )() ;
+
+#ifndef _WINDEF_
+typedef unsigned int UINT;
+#endif
+
+typedef unsigned int PTR_SIZE * UINT_PTR ;
+typedef UINT ( PTR_SIZE *PF_UINT )() ;
+typedef UINT_PTR ( PTR_SIZE *PF_UINT_PTR )() ;
+
+
+typedef short int INT16 ;
+#define SHORT INT16
+typedef short int PTR_SIZE * INT16_PTR ;
+typedef INT16 ( PTR_SIZE *PF_INT16 )() ;
+typedef INT16_PTR ( PTR_SIZE *PF_INT16_PTR )() ;
+#define PSHORT INT16_PTR
+#define NPSHORT INT16_PTR
+#define LPSHORT INT16_PTR
+
+typedef unsigned short UINT16 ;
+#define WORD UINT16
+#define USHORT UINT16
+typedef unsigned short PTR_SIZE * UINT16_PTR ;
+typedef UINT16 ( PTR_SIZE *PF_UINT16 )() ;
+typedef UINT16_PTR ( PTR_SIZE *PF_UINT16_PTR )() ;
+#define PUSHORT UINT16_PTR
+#define NPUSHORT UINT16_PTR
+#define LPUSHORT UINT16_PTR
+
+typedef long int INT32 ;
+typedef long int PTR_SIZE * INT32_PTR ;
+typedef INT32 ( PTR_SIZE *PF_INT32 )() ;
+typedef INT32_PTR ( PTR_SIZE *PF_INT32_PTR )() ;
+#define PLONG INT32_PTR
+#define NPLONG INT32_PTR
+#define LPLONG INT32_PTR
+
+typedef unsigned long UINT32 ;
+#define DWORD UINT32
+#define ULONG UINT32
+typedef unsigned long PTR_SIZE * UINT32_PTR ;
+typedef UINT32 ( PTR_SIZE *PF_UINT32 )() ;
+typedef UINT32_PTR ( PTR_SIZE *PF_UINT32_PTR )() ;
+#define PULONG UINT32_PTR
+#define NPULONG UINT32_PTR
+#define LPULONG UINT32_PTR
+
+typedef INT16 BOOLDUDE ;
+typedef INT16_PTR BOOLEAN_PTR ;
+typedef BOOLDUDE ( PTR_SIZE *PF_BOOLEAN )() ;
+typedef BOOLEAN_PTR ( PTR_SIZE *PF_BOOLEAN_PTR )() ;
+#define BOOLEAN BOOLDUDE
+#define BOOL int
+
+
+#ifndef LONG
+# define LONG INT32
+#endif
+
+
+#ifndef WNDPROC
+#define WNDPROC FARPROC
+#endif
+
+
+#define BYTE_PTR UINT8_PTR
+#define LPBYTE BYTE_PTR
+#define NPBYTE BYTE_PTR
+
+#define ACHAR BYTE
+#define ACH BYTE
+#define ACHAR_PTR BYTE_PTR
+#define PACH BYTE_PTR
+#define LPACH BYTE_PTR
+#define NPACH BYTE_PTR
+#define PACHAR BYTE_PTR
+#define LPACHAR BYTE_PTR
+#define NPACHAR BYTE_PTR
+#define PASTR BYTE_PTR
+#define LPASTR BYTE_PTR
+#define NPASTR BYTE_PTR
+
+
+#if defined ( OS_WIN32 )
+ typedef wchar_t * WCHAR_PTR;
+# define WCHAR wchar_t
+#else
+# define WCHAR UINT16
+# define WCHAR_PTR UINT16_PTR
+#endif
+
+
+#define WCH WCHAR
+#define PWCH WCHAR_PTR
+#define LPWCH WCHAR_PTR
+#define NPWCH WCHAR_PTR
+#define PWCHAR WCHAR_PTR
+#define LPWCHAR WCHAR_PTR
+#define NPWCHAR WCHAR_PTR
+#define PWSTR WCHAR_PTR
+#define LPWSTR WCHAR_PTR
+#define NPWSTR WCHAR_PTR
+
+
+
+#if defined( UNICODE )
+# if !defined( TEXT )
+# define TEXT(quote) L##quote
+# endif
+
+# define CHAR WCHAR
+# define CHAR_PTR WCHAR_PTR
+# define UCHAR UINT16
+# define UCHAR_PTR UINT16_PTR
+#else
+# if !defined( TEXT )
+# define TEXT(quote) quote
+# endif
+
+# define CHAR INT8
+# define CHAR_PTR INT8_PTR
+# define UCHAR UINT8
+# define UCHAR_PTR UINT8_PTR
+
+#endif
+
+#define CH CHAR
+#define PCHAR CHAR_PTR
+#define LPCHAR CHAR_PTR
+#define NPCHAR CHAR_PTR
+#define PCH CHAR_PTR
+#define LPCH CHAR_PTR
+#define NPCH CHAR_PTR
+
+#define TCH CHAR
+#define TCHAR CHAR
+#define PTCHAR CHAR_PTR
+#define LPTCHAR CHAR_PTR
+#define NPTCHAR CHAR_PTR
+#define PTCH CHAR_PTR
+#define LPTCH CHAR_PTR
+#define NPTCH CHAR_PTR
+
+#define PSTR CHAR_PTR
+#define LPSTR CHAR_PTR
+#define NPSTR CHAR_PTR
+
+#undef FALSE
+#define FALSE ((BOOLEAN)(0))
+#undef TRUE
+#define TRUE ((BOOLEAN)(!FALSE))
+
+#undef SUCCESS
+#define SUCCESS ((BOOLEAN)(0))
+#undef FAILURE
+#define FAILURE ((BOOLEAN)(!SUCCESS))
+
+
+
+/* Structure definition for unsigned 64 bit integers */
+typedef struct {
+ UINT32 lsw; /* Least significant 32 bits */
+ UINT32 msw; /* Most significnant 32 bits */
+} UINT64, *UINT64_PTR;
+
+
+#define BIT0 0x00000001L
+#define BIT1 0x00000002L
+#define BIT2 0x00000004L
+#define BIT3 0x00000008L
+#define BIT4 0x00000010L
+#define BIT5 0x00000020L
+#define BIT6 0x00000040L
+#define BIT7 0x00000080L
+#define BIT8 0x00000100L
+#define BIT9 0x00000200L
+#define BIT10 0x00000400L
+#define BIT11 0x00000800L
+#define BIT12 0x00001000L
+#define BIT13 0x00002000L
+#define BIT14 0x00004000L
+#define BIT15 0x00008000L
+#define BIT16 0x00010000L
+#define BIT17 0x00020000L
+#define BIT18 0x00040000L
+#define BIT19 0x00080000L
+#define BIT20 0x00100000L
+#define BIT21 0x00200000L
+#define BIT22 0x00400000L
+#define BIT23 0x00800000L
+#define BIT24 0x01000000L
+#define BIT25 0x02000000L
+#define BIT26 0x04000000L
+#define BIT27 0x08000000L
+#define BIT28 0x10000000L
+#define BIT29 0x20000000L
+#define BIT30 0x40000000L
+#define BIT31 0x80000000L
+
+UINT16 nothing( VOID ) ;
+
+#if !defined(_SIZE_T_DEFINED) && !defined(_SIZE_T_DEFINED_)
+typedef unsigned int size_t;
+#define _SIZE_T_DEFINED
+#define _SIZE_T_DEFINED_
+#endif
+
+#ifndef NO_STD_HOOKS
+#include "stdhooks.h"
+#endif
+
+
+#endif /* STDTYPES */
+
diff --git a/private/utils/ntbackup/inc/stdwcs.h b/private/utils/ntbackup/inc/stdwcs.h
new file mode 100644
index 000000000..9101efde3
--- /dev/null
+++ b/private/utils/ntbackup/inc/stdwcs.h
@@ -0,0 +1,219 @@
+/** Copyright (C) Maynard Electronics, An Archive Company. 1992
+
+ Name: STDWCS.H
+
+ Description:
+
+ Contains header information for wide strings, unicode mapping,
+ unicode comparison and memory functions. The file
+ is divided into the sections as outline here.
+
+ MIKEP - note,
+ Wide string functions for using unicode strings under MSC 6.0
+ and not having a library to use. If you add a function, add
+ it to STDWCS.C, STDWCS.H, and MAPPINGS.H
+
+
+ $Log: M:/LOGFILES/STDWCS.H_V $
+
+ Rev 1.11 15 Jan 1994 19:15:12 BARRY
+Change memorycmp functions to take VOID_PTR args
+
+ Rev 1.10 18 Aug 1993 18:19:26 BARRY
+Added strcspn/wcscspn
+
+ Rev 1.9 12 Aug 1993 16:24:50 DON
+Put back DEBBIEs change in Rev 1.7 which got lost with STEVEs change in Rev 1.8
+
+ Rev 1.8 11 Aug 1993 18:01:20 STEVEN
+fix read of unicode tape with ansi app
+
+ Rev 1.6 25 Nov 1992 14:22:20 STEVEN
+
+
+ Rev 1.5 17 Nov 1992 22:30:56 DAVEV
+unicode fixes
+
+ Rev 1.4 12 Nov 1992 10:59:18 DAVEV
+comment out strlwr & strupr
+
+ Rev 1.3 11 Nov 1992 18:17:50 DAVEV
+UNICODE changes
+
+ Rev 1.2 17 Jul 1992 14:58:42 STEVEN
+fix NT bugs
+
+ Rev 1.0 10 Jun 1992 16:11:26 TIMN
+Initial Revision (UNICODE)
+
+
+
+**/
+
+#ifndef _stdwcs_h_
+#define _stdwcs_h_
+
+/* remap str functions to wide string functions */
+
+
+#if defined( UNICODE ) && !defined( NO_STRING_REMAPPING )
+
+# define strlen(x) wcslen( (x) )
+# define strcpy(x,y) wcscpy( (x), (y) )
+# define strncpy(x,y,z) wcsncpy( (x), (y), (z) )
+# define strcat(x,y) wcscat( (x), (y) )
+# define strncat(x,y,z) wcsncat( (x), (y), (z) )
+# define strcmp(x,y) wcscmp( (x), (y) )
+# define strncmp(x,y,z) wcsncmp( (x), (y), (z) )
+# define strrchr(x,y) wcsrchr( (x), (y) )
+# define strchr(x,y) wcschr( (x), (y) )
+# define strpbrk(x,y) wcspbrk( (x), (y) )
+# define strstr(x,y) wcsstr( (x), (y) )
+# define strcspn(x,y) wcscspn( (x), (y) )
+
+# define strtok(x,y) wcstok( (x), (y) )
+# define sscanf swscanf
+# define sprintf swprintf
+# define vsprintf vswprintf
+
+# define fprintf fwprintf
+# define vfprintf vfwprintf
+
+//# if !__STDC__
+# define _strrev(x) wcsrev( (x) )
+# define _stricmp(x,y) wcsicmp( (x), (y) )
+# define _strnicmp(x,y,z) wcsnicmp( (x), (y), (z) )
+# define _strlwr(x) wcslwr( (x) )
+# define _strupr(x) wcsupr( (x) )
+# define _strcmpi stricmp
+//# else
+# define strrev(x) wcsrev( (x) )
+# define stricmp(x,y) wcsicmp( (x), (y) )
+# define strnicmp(x,y,z) wcsnicmp( (x), (y), (z) )
+# define strlwr(x) wcslwr( (x) )
+# define strupr(x) wcsupr( (x) )
+# define strcmpi stricmp
+//# endif //__STDC__
+
+#endif //STRING REMAPPING
+
+
+/* Unicode string functions. */
+#if !defined( OS_WIN32 )
+
+INT wcslen( WCHAR_PTR s );
+WCHAR_PTR wcscpy( WCHAR_PTR s, WCHAR_PTR t );
+WCHAR_PTR wcsncpy( WCHAR_PTR s, WCHAR_PTR t, INT i );
+WCHAR_PTR wcscat( WCHAR_PTR s, WCHAR_PTR t );
+WCHAR_PTR wcsncat( WCHAR_PTR s, WCHAR_PTR t, INT i );
+INT wcscmp( WCHAR_PTR s, WCHAR_PTR t );
+INT wcsncmp( WCHAR_PTR s, WCHAR_PTR t, INT i );
+INT wcsicmp( WCHAR_PTR s, WCHAR_PTR t );
+INT wcsnicmp( WCHAR_PTR s, WCHAR_PTR t, INT i );
+WCHAR_PTR wcsrchr( WCHAR_PTR s, INT c );
+WCHAR_PTR wcschr( WCHAR_PTR s, INT c );
+WCHAR_PTR wcspbrk( WCHAR_PTR s, WCHAR_PTR t );
+WCHAR_PTR wcslwr( WCHAR_PTR s );
+WCHAR_PTR wcsupr( WCHAR_PTR s );
+WCHAR_PTR wcsstr( WCHAR_PTR s, WCHAR_PTR t );
+size_t wcscspn( WCHAR_PTR s, WCHAR_PTR t );
+
+
+#endif
+
+/* ANSI Strings for use if UNICODE is defined. */
+
+#if defined (UNICODE)
+
+INT strlenA( ACHAR_PTR s );
+ACHAR_PTR strcpyA( ACHAR_PTR s, ACHAR_PTR t );
+ACHAR_PTR strncpyA( ACHAR_PTR s, ACHAR_PTR t, INT i );
+ACHAR_PTR strcatA( ACHAR_PTR s, ACHAR_PTR t );
+ACHAR_PTR strncatA( ACHAR_PTR s, ACHAR_PTR t, INT i );
+INT strcmpA( ACHAR_PTR s, ACHAR_PTR t );
+INT strncmpA( ACHAR_PTR s, ACHAR_PTR t, INT i );
+INT stricmpA( ACHAR_PTR s, ACHAR_PTR t );
+INT strnicmpA( ACHAR_PTR s, ACHAR_PTR t, INT i );
+ACHAR_PTR strrchrA( ACHAR_PTR s, INT c );
+ACHAR_PTR strchrA( ACHAR_PTR s, INT c );
+ACHAR_PTR strpbrkA( ACHAR_PTR s, ACHAR_PTR t );
+//ACHAR_PTR strlwrA( ACHAR_PTR s );
+//ACHAR_PTR struprA( ACHAR_PTR s );
+ACHAR_PTR strstrA( ACHAR_PTR s, ACHAR_PTR t );
+
+#else // !defined (UNICODE) -- map to standard string routines
+
+#define strlenA strlen
+#define strcpyA strcpy
+#define strncpyA strncpy
+#define strcatA strcat
+#define strncatA strncat
+#define strcmpA strcmp
+#define strncmpA strncmp
+#define stricmpA stricmp
+#define strnicmpA strnicmp
+#define strrchrA strrchr
+#define strchrA strchr
+#define strpbrkA strpbrk
+//#define strlwrA strlwr
+//#define struprA strupr
+#define strstrA strstr
+
+#endif //defined(UNICODE)
+
+/**
+ begin unicode mapping stuff *****
+**/
+
+
+/* mapping function error return values */
+
+#define MAP_NULL_SRCSTR 1 /* NULL src string to map */
+#define MAP_DST_OVERFLOW -1 /* to small of a destination size */
+
+INT mapAnsiToUnic( ACHAR_PTR src, WCHAR_PTR dst, INT *dstStrSize ) ;
+INT mapUnicToAnsi( WCHAR_PTR src, ACHAR_PTR dst, const ACHAR rplCh, INT *dstStrSize ) ;
+INT mapAnsiToUnicNoNull( ACHAR_PTR src, WCHAR_PTR dst, INT srcStrSize, INT *dstStrSize ) ;
+INT mapUnicToAnsiNoNull( WCHAR_PTR src, ACHAR_PTR dst, const ACHAR rplCh, INT srcStrSize, INT *dstStrSize ) ;
+
+
+
+
+/**
+ begin unicode comparison stuff *****
+**/
+
+#define CMP_TO_CASE_OFFSET 0x0020 /* case offset to ANSI mappable chars */
+
+
+ /* upper case ANSI mappable characters */
+#define _isUpperW(ch) ( \
+ (( (ch) > 0x0040 ) && ( (ch) < 0x005B )) || (( (ch) > 0x00C3 ) && ( (ch) < 0x00C8 )) || \
+ ( (ch) == 0x00C9 ) || ( (ch) == 0x00D1 ) || ( (ch) == 0x00D6 ) || \
+ ( (ch) == 0x00DC ) || ( (ch) == 0x0393 ) || ( (ch) == 0x0398 ) || \
+ ( (ch) == 0x03A3 ) || ( (ch) == 0x03A6 ) || ( (ch) == 0x03A9 ) )
+
+ /* lower case ANSI mappable characters */
+#define _isLowerW(ch) ( \
+ (( (ch) > 0x0060 ) && ( (ch) < 0x007B )) || (( (ch) > 0x00E3 ) && ( (ch) < 0x00E8 )) || \
+ ( (ch) == 0x00E9 ) || ( (ch) == 0x00F1 ) || ( (ch) == 0x00F6 ) || \
+ ( (ch) == 0x00FC ) || ( (ch) == 0x03B3 ) || ( (ch) == 0x03B8 ) || \
+ ( (ch) == 0x03C3 ) || ( (ch) == 0x03C6 ) || ( (ch) == 0x03C9 ) )
+
+#define _toUpperW(ch) ( _isLowerW(ch) ? ((ch) - CMP_TO_CASE_OFFSET) : (ch) )
+#define _toLowerW(ch) ( _isUpperW(ch) ? ((ch) + CMP_TO_CASE_OFFSET) : (ch) )
+
+INT cmpiUnicToUnic( WCHAR_PTR ws1, WCHAR_PTR ws2 ) ;
+
+
+
+
+/**
+ begin memory stuff *****
+**/
+
+INT memorycmp( const VOID_PTR s1, const INT s1len, const VOID_PTR s2, const INT s2len ) ;
+INT memoryicmp( const VOID_PTR s1, const INT s1len, const VOID_PTR s2, const INT s2len ) ;
+#define strsize( x ) ((strlen(x) + 1) * sizeof(CHAR))
+#define strlength( x ) (strlen(x) * sizeof(CHAR))
+#endif /* end header file */
diff --git a/private/utils/ntbackup/inc/sx.h b/private/utils/ntbackup/inc/sx.h
new file mode 100644
index 000000000..ce7b92dae
--- /dev/null
+++ b/private/utils/ntbackup/inc/sx.h
@@ -0,0 +1,230 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-91
+
+ Name: sx.h
+
+ Date Updated:
+
+ Description: Contains the constants, typedefs, structures and entry points to functions
+ specific to the EXABYTE 8200SX - MaynStream 2200+
+
+
+ $Log: Q:/LOGFILES/SX.H_V $
+
+ Rev 1.4 17 Nov 1992 22:30:52 DAVEV
+unicode fixes
+
+ Rev 1.3 11 Nov 1992 18:17:54 DAVEV
+UNICODE changes
+
+ Rev 1.2 17 Aug 1992 09:09:10 GREGG
+Changes to deal with block sizeing scheme.
+
+ Rev 1.1 23 Apr 1992 08:09:02 IAN
+Changed prototype for SX_FindBlock() to match changes made in sx.c by NED.
+
+ Rev 1.0 30 Sep 1991 11:03:28 HUNTER
+Initial revision.
+
+**/
+
+#ifndef _SX_H
+#define _SX_H
+
+#include <fcntl.h>
+#include <sys\types.h>
+#include <sys\stat.h>
+//#include <io.h>
+
+#include "tbe_defs.h"
+#include "sxtf.h"
+#include "channel.h"
+
+
+/*
+ * CONSTANTS
+ */
+
+#define SX_TMP_FILE ( 0 )
+#define SX_FILE ( 1 )
+
+#define SX_FINDING_SET ( 0 )
+#define SX_CHECKING_FOR_SET ( 1 )
+
+#define SX_TMP_FILE_NAME TEXT ("_PLUS_._")
+
+#define SX_WRITE_FLAG ( O_CREAT | O_RDWR | O_BINARY )
+#define SX_WRITE_PMODE ( S_IREAD | S_IWRITE )
+
+#define SX_READ_FLAG ( O_RDONLY | O_BINARY )
+#define SX_READ_PMODE ( S_IREAD )
+
+#define SX_TMP_FLAG ( O_TRUNC | SX_WRITE_FLAG )
+#define SX_TMP_PMODE ( SX_WRITE_PMODE )
+
+#define SX_SAMPLE_RATE ( 0x2000 ) /* 1 MByte == 0x800 */
+#define SX_NEARBY ( 0x2000 ) /* 1 MByte == 0x800 */
+#define SX_DO_NOT_MOVE ( 0 )
+#define SX_INITIALIZER ( -1 )
+#define SX_FIRST_LBA ( 0L )
+#define SX_LAST_LBA ( 0xffffffff )
+
+/*
+ * FUNCTION PROTOTYPES
+ */
+
+VOID SX_Begin( /* called by: TFOPEN TF_OpenSet() */
+ CHANNEL_PTR channel,
+ UINT16 tf_mode
+) ;
+
+VOID SX_End( /* called by: TFCLOSE TF_CloseSet() */
+ CHANNEL_PTR channel
+) ;
+
+BOOLEAN SX_OpenFile( /* called by: POSATSET PositionAtSet() */
+ CHANNEL_PTR channel, /* READ StartRead() */
+ UINT32 tape_id,
+ UINT16 ts_num
+) ;
+
+BOOLEAN SX_CloseFile( /* called by: POSATSET PositionAtSet() */
+ CHANNEL_PTR channel /* READ StartRead() */
+) ; /* SX SX_OpenFile() */
+ /* SX SX_End() */
+ /* SX SX_EndSampling() */
+
+INT16 SX_DeleteFile( /* called by: POSATSET PositionAtSet() */
+ UINT32 tape_id, /* TFERASE TF_EraseChannel() */
+ UINT16 ts_num
+) ;
+
+BOOLEAN SX_WriteTmpFile( /* called by: READ AcquireReadBuffer() */
+ CHANNEL_PTR channel /* READ CleanUpDriverQ() */
+) ; /* WRITE AcquireWriteBuffer() */
+ /* WRITE FinishWrite() */
+ /* SX SX_ShowBlock() */
+ /* SX SX_StartSampling() */
+
+BOOLEAN SX_SeekSetInFile( /* called by: POSATSET PositionAtSet() */
+ CHANNEL_PTR channel, /* READ StartRead() */
+ INT16 set,
+ INT16 mode
+) ;
+
+INT16 SX_FindBlock( /* called by: READ StartRead() */
+ CHANNEL_PTR channel, /* READ DoRead() */
+ UINT32 lba,
+ TPOS_PTR ui_tpos,
+ INT16 tf_message
+) ;
+
+INT16 SX_ShowBlock( /* called by: DRIVES ReadNextSet() */
+ CHANNEL_PTR channel, /* SX SX_SamplingProcessing() */
+ UINT16 mode /* SX SX_EndSampling() */
+) ;
+
+VOID SX_StartSampling( /* called by: READ StartRead() */
+ CHANNEL_PTR channel /* WRITE WriteDBLK() */
+) ; /* WRITE EOM_Write() */
+
+VOID SX_SamplingProcessing( /* called by: READ ReadRequest() */
+ CHANNEL_PTR channel, /* WRITE WriteRequest() */
+ UINT32 bytes
+) ;
+
+VOID SX_EndSampling( /* called by: READ AcquireReadBuffer() */
+ CHANNEL_PTR channel /* WRITE FinishWrite() */
+) ; /* WRITE EOMWrite() */
+
+#ifdef SX_DEBUG
+VOID SX_InfoDump(
+ CHANNEL_PTR channel,
+ CHAR_PTR message
+) ;
+#endif
+
+/*
+ * STATUS BITS -
+ */
+
+#define SX_OPEN_FOR_READ ( 0x0001 ) /* open for read */
+#define SX_OPEN_FOR_WRITE ( 0x0002 ) /* open for write */
+#define SX_TMP_OPEN_FOR_WRITE ( 0x0004 ) /* tmp open for write */
+#define SX_OPEN ( 0x0007 ) /* open mask */
+#define SX_AT_BOF ( 0x0010 ) /* at beginning of file */
+#define SX_AT_EOF ( 0x0020 ) /* at end of file */
+#define SX_AT_SET ( 0x0040 ) /* at the first record in a set */
+#define SX_AT ( 0x0070 ) /* at mask */
+#define SX_VCB_PENDING ( 0x0100 ) /* could be at BOT, VCB etc */
+#define SX_VCB_CONFIRMED ( 0x0200 ) /* at VCB */
+#define SX_TYPE ( 0x0300 ) /* type mask */
+#define SX_FOUND_BLOCK ( 0x0400 ) /* found block */
+#define SX_SCAN_ACTIVE ( 0x1000 ) /* scanning tape for positioning info */
+#define SX_SCAN_INOPERATIVE ( 0x2000 ) /* not scanning tape for positioning info */
+#define SX_SCAN ( 0x3000 ) /* scanning tape mask */
+#define SX_LIST_TAPE_IN_PROGRESS ( 0x4000 ) /* doing a list tape operation */
+#define SX_ERROR ( 0x8000 ) /* something's wrong */
+#define SX_STATUS ( 0xffff ) /* status mask */
+
+/*
+ * SHOW BLOCK MODES
+ */
+
+#define SX_SHOW_QUEUED ( 0x0001 ) /* call to TpReceive will be made elsewhere */
+#define SX_SHOW_IMMEDIATE ( 0x0002 ) /* call to TpReceive should follow immediately */
+#define SX_SHOW_WRITE ( 0x0004 ) /* update the SX tmp file now */
+#define SX_SHOW_VCB_PENDING ( 0x0008 ) /* we think this could be a VCB */
+
+/*
+ * STATUS MACROS
+ */
+
+#define SX_SetStatus( c, x ) ( ( c )->sx_info.status |= ( x ) )
+#define SX_ClearStatus( c, x ) ( ( c )->sx_info.status &= ~( x ) )
+#define SX_IsStatusSet( c, x ) ( ( c )->sx_info.status & ( x ) )
+
+#define SX_ClearAt( c ) SX_ClearStatus( ( c ), SX_AT )
+#define SX_SetAt( c, x ) SX_ClearAt( ( c ) ) ; SX_SetStatus( ( c ), x )
+#define SX_ClearType( c ) SX_ClearStatus( ( c ), SX_TYPE )
+#define SX_SetType( c, x ) SX_ClearType( ( c ) ) ; SX_SetStatus( ( c ), x )
+
+/*
+ * FUNCTION MACROS
+ */
+
+#define SX_Drive( c ) ( ( CurDrvAttribs( ( c ) ) & TDI_SHOW_BLK ) || ( CurDrvAttribs( ( c ) ) & TDI_FIND_BLK ) )
+#define SX_IsOK( c ) SX_Drive( ( c ) ) && !( SX_IsStatusSet( ( c ), SX_ERROR ) )
+#define SX_FileIsOpen( c ) ( SX_IsStatusSet( ( c ), SX_OPEN_FOR_READ | SX_OPEN_FOR_WRITE ) )
+#define SX_TmpFileIsOpen( c ) ( SX_IsStatusSet( ( c ), SX_TMP_OPEN_FOR_WRITE ) )
+#define SX_FileIsOK( c ) ( SX_FileIsOpen( ( c ) ) && SX_IsOK( ( c ) ) )
+#define SX_TmpFileIsOK( c ) ( SX_TmpFileIsOpen( ( c ) ) && SX_IsOK( ( c ) ) )
+#define SX_AbleToFindBlock( c ) SX_FileIsOK( ( c ) ) && SX_IsStatusSet( ( c ), SX_AT_SET )
+#define SX_IsNotAlreadyAtLBA( c, x ) ( ( ( x ) - SX_GetLBANow( ( c ) ) ) != 0 )
+#define SX_IsNearbyLBA( c, x ) ( SX_IsStatusSet( channel, SX_FOUND_BLOCK ) && ( ( ( x ) - SX_GetLBANow( ( c ) ) ) < SX_NEARBY ) )
+
+#define SX_GetBackupSetNumber( c ) ( c )->sx_info.sx_record.set
+#define SX_SetBackupSetNumber( c ) SX_GetBackupSetNumber( ( c ) ) = ( c )->bs_num
+#define SX_GetRecord( c ) ( c )->sx_info.sx_record
+#define SX_SetRecord( c, x ) SX_GetRecord( ( c ) ) = ( x )
+#define SX_GetPosition( c ) ( c )->sx_info.sx_record.sx_position
+#define SX_FileHandle( c ) ( c )->sx_info.sx_hdl
+#define SX_TmpFileHandle( c ) ( c )->sx_info.sx_tmp
+#define SX_GetLBANow( c ) ( c )->sx_info.lba_now
+#define SX_SetLBANow( c, x ) SX_GetLBANow( ( c ) ) = ( UINT32 )( x )
+#define SX_AdjustLBANow( c, x ) SX_GetLBANow( ( c ) ) += ( UINT32 )( ( x ) / c->lb_size )
+#define SX_GetLBA( c ) ( c )->sx_info.sx_record.lba
+#define SX_SetLBA( c ) SX_GetLBA( ( c ) ) = SX_GetLBANow( ( c ) )
+#define SX_GetMisc( c ) ( c )->sx_info.misc
+#define SX_SetMisc( c, x ) SX_GetMisc( ( c ) ) = ( UINT32 )( x )
+#define SX_SampleNeeded( c ) SX_TmpFileIsOK( ( c ) ) && ( SX_GetLBANow( ( c ) ) >= SX_GetMisc( c ) )
+#define SX_NextSample( c ) SX_GetMisc( c ) += SX_SAMPLE_RATE
+#define SX_OffsetFile( c ) SX_SeekFile( ( c ), SX_GetMisc( c ), SEEK_SET, SX_FILE )
+
+#if defined( MAYN_OS2 )
+#define SX_GetLock( c ) ( c )->sx_info.lock
+#endif
+
+#endif
+
+
diff --git a/private/utils/ntbackup/inc/sxdd.h b/private/utils/ntbackup/inc/sxdd.h
new file mode 100644
index 000000000..d6a1160b7
--- /dev/null
+++ b/private/utils/ntbackup/inc/sxdd.h
@@ -0,0 +1,39 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-91
+
+ Name: sxdd.h
+
+ Description: Structures and constants unique to the EXABYTE 8200SX - MaynStream 2200+ at the device driver level
+
+ $Log: Q:/LOGFILES/SXDD.H_V $
+
+ Rev 1.0 17 Jul 1991 15:35:12 ED
+Initial revision.
+**/
+
+#ifndef _SXDD_H
+#define _SXDD_H
+
+
+/*
+ * TYPEDEFS & STRUCTURES
+ */
+
+typedef struct {
+
+ UINT8 data[ 10 ] ; /* we never look into this data so it is not broken down
+ into any component fields such as tach count, pba, lba etc ...
+ Essentially, this is a 10 byte "block address" */
+} SX_POSITION, *SX_POSITION_PTR ;
+
+typedef struct {
+
+ SX_POSITION sx_position ; /* set by SHOW BLOCK & used by FIND BLOCK */
+ UINT32 lba ; /* related "block address" in application software */
+ INT16 set ; /* set number in application software */
+
+} SX_RECORD, *SX_RECORD_PTR ; /* record format of the SX file */
+
+#endif
+
+
diff --git a/private/utils/ntbackup/inc/sxtf.h b/private/utils/ntbackup/inc/sxtf.h
new file mode 100644
index 000000000..e7979295f
--- /dev/null
+++ b/private/utils/ntbackup/inc/sxtf.h
@@ -0,0 +1,63 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+$name$
+.module information
+
+$paths$
+headers\sxtf.h
+subsystem\TAPE FORMAT\sxtf.h
+$0$
+
+ Name: sxtf.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the typedefs and structures specific to the EXABYTE 8200SX - MaynStream 2200+ for
+ Tape Format
+
+$Header: N:/LOGFILES/SXTF.H_V 1.2 20 Jan 1992 18:57:28 GREGG $
+
+$Log: N:/LOGFILES/SXTF.H_V $
+
+ Rev 1.2 20 Jan 1992 18:57:28 GREGG
+Changed INT16 file handles to int (Watcom strikes again!)
+
+ Rev 1.1 17 Oct 1991 01:08:44 GREGG
+Added cat_enabled to SX_INFO.
+
+ Rev 1.0 10 Oct 1991 08:55:10 GREGG
+Initial revision.
+
+$-1$
+**/
+
+#ifndef _SXTF_H
+#define _SXTF_H
+
+#include "sxdd.h"
+/* $end$ include list */
+
+/*
+ * TYPEDEFS & STRUCTURES
+ */
+
+typedef struct {
+
+ SX_RECORD sx_record ; /* record read/written to/from SX file */
+ int sx_hdl ; /* file handle of SX file opened for read/write */
+ int sx_tmp ; /* file handle of temp file opened for write */
+ UINT32 misc ; /* next sample for SHOW when writing SX file and
+ and desired "block address" for FIND during searches */
+ UINT32 lba_now ; /* running lba for next call of SX_SamplingProcessing */
+ UINT16 status ; /* indicates various things */
+ BOOLEAN cat_enabled ; /* true if catalog level is full or partial */
+
+#if defined( MAYN_OS2 )
+ UINT32 lock ; /* lock for device driver access */
+#endif
+
+} SX_INFO, *SX_INFO_PTR ;
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/sypl10.h b/private/utils/ntbackup/inc/sypl10.h
new file mode 100644
index 000000000..c7fc5e649
--- /dev/null
+++ b/private/utils/ntbackup/inc/sypl10.h
@@ -0,0 +1,248 @@
+/**
+Copyright(c) Archive Software Division 1984-89
+
+
+ Name: sypl10.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Defines the environment structures for the Sytos Plus Format
+
+ $Log: T:\logfiles\sypl10.h_v $
+
+ Rev 1.10 16 Jan 1994 14:32:04 GREGG
+Unicode bug fixes.
+
+ Rev 1.9 22 Nov 1993 18:09:10 BARRY
+Unicode fixes; got rid of tabs
+
+ Rev 1.8 15 Jul 1993 14:21:10 STEVEN
+fix volume header
+
+ Rev 1.6 19 May 1993 13:13:52 TerriLynn
+Steve got the correct location of the ECC flag
+
+ Rev 1.5 11 May 1993 21:55:30 GREGG
+Moved Sytos translator stuff from layer-wide area to translator.
+
+ Rev 1.4 10 May 1993 15:12:56 Terri_Lynn
+Added Steve's changes and My changes for EOM processing
+
+ Rev 1.3 03 May 1993 16:22:10 TERRI
+General clean up
+Moved pragma pack statement to shorten effect
+
+ Rev 1.2 26 Apr 1993 11:30:22 GREGG
+Sixth in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Redefined attribute bits to match the spec.
+ - Eliminated unused/undocumented bits.
+ - Added code to translate bits on tapes that were written wrong.
+
+Matches MAYN40RD.C 1.59, DBLKS.H 1.15, MAYN40.H 1.34, OTC40RD.C 1.26,
+ SYPL10RD.C 1.8, BACK_VCB.C 1.17, MAYN31RD.C 1.44, SYPL10.H 1.2
+
+ Rev 1.1 17 Mar 1993 14:28:32 TERRI
+Initial CAYMAN beta release
+**
+*/
+
+#if !defined SYPL10_H
+#define SYPL10_H
+
+#include "fsstream.h"
+#include "osinfo.h"
+
+#define UNQ_HDR_ID_LEN 9
+#define MAX_ACL_INFO_LEN 0x980
+#define MAX_EA_DATA_LEN 0x10000
+#define SHORT_NAME_LEN 20
+#define LONG_NAME_LEN 261
+#define DESCRPT_LEN 256
+
+#define FAT_FILE_SYSTEM 0xa000
+#define PWD_CRYPT_CHAR 0x0069 /* password encryption character */
+
+#define DRIVEROOT_TYPE 0x003c /* set in drive indicator for drive/root */
+#define DIRECTORY_TYPE 0x0041 /* set in drive indicator for directory */
+
+#define SYPL_MAX_STREAMS 4
+
+#define S10_UNIQ_ID { 0xa2, 0x2a, 0x2a, 0xa2, 0xa2, 0x2a, 0x2a, 0xa2, 0x00 }
+
+typedef struct sypl_vcb SYPL_VCB, *SYPL_VCB_PTR ;
+
+
+struct sypl_vcb {
+ UINT16 bset_num ;
+ DATE_TIME backup_date_time ; /* from first block */
+ ACHAR drive[4] ;
+ UINT32 attrib ;
+} ;
+
+typedef struct sypl_env {
+ UINT8 volname[SHORT_NAME_LEN+1]; /* null terminated */
+ UINT8 password[SHORT_NAME_LEN+1] ; /* tape password null terminated */
+ UINT32 family_id ; /* from tape header UINT32 date */
+ UINT16 tape_seq_num ; /* sequence number */
+ DATE_TIME tape_date ; /* tape creation date */
+ INT8 tape_descrpt[DESCRPT_LEN+1] ; /* tape description */
+ INT8 bset_name[SHORT_NAME_LEN+1] ; /* backup set name */
+ INT8 bset_descrpt[DESCRPT_LEN+1] ; /* backup set description */
+ DATE_TIME bset_date ; /* backup set date */
+ UINT16 dir_attribs ; /* directory attributes */
+ DATE_TIME dir_date ; /* directory date */
+ UINT16 path_len ; /* length of path */
+ INT8 path_name[LONG_NAME_LEN+1] ; /* path name */
+ UINT16 file_attribs ; /* file attributes */
+ UINT32 file_size ; /* size of file */
+ UINT16 file_name_len ; /* length of file name */
+ INT8 file_name[LONG_NAME_LEN+1] ; /* file name */
+ DATE_TIME file_create_date ; /* file creation date */
+ DATE_TIME last_access_date ; /* file last access date */
+ DATE_TIME last_modified_date ; /* file last modified date */
+ SYPL_VCB current_vcb ; /* current vcb */
+ UINT16 block_size ; /* block size */
+ BOOLEAN bytes_left ; /* of header or ECC */
+ UINT32 prior_blocks_used ; /* copied from CHANNEL::blocks_used */
+ BOOLEAN continuing; /* TRUE if continuing */
+ UINT16 destination_tape_seq_num; /* sequence number */
+ BOOLEAN using_ecc ; /* TRUE if current tape has ECC */
+ BOOLEAN in_ecc ; /* TRUE if still processing ECC */
+ BOOLEAN processed_ddb ; /* TRUE if the drive root directory header has been processed */
+ UINT16 no_streams ; /* number of streams */
+ UINT16 currentStream ; /* current stream */
+ STREAM_INFO streams[SYPL_MAX_STREAMS] ; /* array of streams for this block type */
+ UINT32 pad_size ; /* pad */
+ BOOLEAN streamMode ; /* yeah or nay */
+ INT32 next_retrans_size ;
+} S10_ENV, *S10_ENV_PTR ;
+
+typedef enum s10_header_types {
+ tape_header_type = 0x00,
+ file_header_type = 0x02,
+ ecc_header_type = 0x04,
+ backup_set_header_type = 0x05,
+ unknown_header_type = 0x08,
+ directory_header_type = 0x15,
+} s10_header_types ;
+
+#pragma pack(1)
+
+typedef struct hdr_common {
+ UINT16 drive_indicator; /* 0 drive or sub directory indicated */
+ UINT8 uniq_tape_id[UNQ_HDR_ID_LEN]; /* 2 unique header id defined above */
+ UINT8 type; /* 10 type of header */
+} S10_COMMON_HEADER, *S10_COMMON_HEADER_PTR ;
+
+typedef struct tape_header_ts {
+ S10_COMMON_HEADER common; /* 0 common to all headers */
+ INT8 tape_name[SHORT_NAME_LEN]; /* 12 null terminated */
+ INT8 tape_descrpt[DESCRPT_LEN]; /* 32 tape description */
+ INT8 password[SHORT_NAME_LEN]; /* 288 tape password */
+ UINT32 tape_date; /* 308 date of tape creation */
+ UINT16 tape_seq_num; /* 312 Tape number 1 based */
+ UINT16 exp_date ;
+ UINT16 MaVevnum ;
+ UINT16 MiVevnum ;
+ UINT16 qfa_flag; /* 322 Quick File Access */
+ UINT16 ecc_flag; /* 323 if 1 HARDWARE ECC present, 0 otherwise */
+ UINT8 unkown2[186]; /* 323 unkown */
+} S10_TAPE_HEADER, *S10_TAPE_HEADER_PTR ;
+
+typedef struct unknown_header_u {
+ S10_COMMON_HEADER common; /* 0 common to all headers */
+ UINT8 unknown[500]; /* 12 usually zeros or junk */
+} S10_UNKOWN_HEADER, *S10_UNKOWN_HEADER_PTR ;
+
+typedef struct backup_set_header_b {
+ S10_COMMON_HEADER common; /* 0 common to all headers */
+ UINT16 end_of_backup; /* 12 if 1 this is end of set 0 for start */
+ INT8 bset_name[SHORT_NAME_LEN]; /* 14 backup set name */
+ INT8 bset_descrpt[DESCRPT_LEN]; /* 34 backup set description */
+ UINT32 bset_date; /* 290 backup set date */
+ UINT8 unkown1[2]; /* 294 unkown */
+ UINT8 compression; /* 296 1=compressed, 0=no compression */
+ UINT8 unkown[31]; /* 297 unknown */
+ UINT8 eom_identifier[16]; /* 328 EOM identifier */
+ UINT8 unkown2[168]; /* 344 unkown */
+} S10_BACKUP_SET_HEADER, *S10_BACKUP_SET_HEADER_PTR ;
+
+typedef struct directory_header_d {
+ S10_COMMON_HEADER common; /* 0 common to all headers */
+ UINT16 dir_attribs; /* 12 attributes of the directory */
+ UINT8 unkown1[6]; /* 14 unkown */
+ UINT32 dir_date; /* 20 41 = date of sub directory; 3C = backup date */
+ UINT8 unkown2[2]; /* 24 unkown */
+ UINT16 ea_data_len; /* 26 length of extended attrib data */
+ UINT8 unkown3[4]; /* 28 unkown */
+ INT16 acl_info_len; /* 32 length of acl info */
+ UINT8 unkown4[22]; /* 34 unkown */
+ UINT16 path_len; /* 56 length of path */
+ INT8 path_name[261]; /* 58 path name */
+ UINT8 unkown5[193]; /* 319 unkown */
+} S10_DIRECTORY_HEADER, *S10_DIRECTORY_HEADER_PTR ;
+
+typedef struct file_header_f {
+ S10_COMMON_HEADER common; /* 0 common to all headers */
+ UINT16 file_attribs; /* 12 attributes of the file */
+ UINT8 unkown[2]; /* 14 unkown */
+ UINT16 ea_data_len; /* 16 length of ea data */
+ UINT8 unkown1[4]; /* 18 unkown */
+ UINT32 file_size; /* 22 size of file */
+ UINT8 unkown2[12]; /* 26 unkown */
+ UINT32 file_create_date; /* 38 file creation date - HPFS */
+ UINT32 last_access_date; /* 42 last access date - HPFS */
+ UINT32 last_modified_date; /* 46 last modified date - HPFS */
+ UINT32 file_last_access; /* 50 same as file_last access - HPFS */
+ UINT8 unkown3[6]; /* 54 unkown */
+ INT16 acl_info_len; /* 60 length of ACL info */
+ UINT8 unkown4[24]; /* 62 unkown */
+ UINT16 filename_len; /* 86 length of file name */
+ INT8 filename[261]; /* 88 path and file name */
+ UINT8 unkown5[163]; /* 349 unkown */
+} S10_FILE_HEADER, *S10_FILE_HEADER_PTR ;
+
+typedef struct ecc_header_e {
+ S10_COMMON_HEADER common; /* 0 common to all headers */
+ UINT8 unkown1[500]; /* 12 unkown */
+} S10_ECC_HEADER, *S10_ECC_HEADER_PTR;
+
+typedef struct acl_info_a {
+ UINT8 far *resource_name; /* 0 not used contains garbarge */
+ UINT16 audit_attribs; /* 1 audit attributes none if 0 */
+ UINT16 num_of_structs; /* 3 count of acl info structs to follow */
+} S10_ACL_INFO, *S10_ACL_INFO_PTR;
+
+typedef struct acl_data_a {
+ INT8 usergrp_name[22]; /* User or Group name, null terminated */
+ UINT16 access_rights; /* bits that define the user/goup access rights */
+} S10_ACL_DATA, *S10_ACL_DATA_PTR;
+
+typedef struct os2_dir_info_m {
+ OS2_DIR_OS_INFO os2_dir_info ; /* Inorder to handoff the dir name */
+ INT8 string[261] ; /* as well as the ea, or acl info */
+} OS2_DIR_INFO, *OS2_DIR_INFO_PTR ; /* to the file system */
+
+typedef struct os2_file_info_m {
+ OS2_FILE_OS_INFO os2_file_info ; /* Inorder to handoff the file name */
+ INT8 string[261] ; /* as well as the ea, acl and data */
+} OS2_FILE_INFO, *OS2_FILE_INFO_PTR ; /* info to the file system */
+
+typedef struct date_field_d {
+ unsigned day : 5 ; /* Extracts the correct number of */
+ unsigned month : 4 ; /* bits for the "Motorola" type */
+ unsigned year : 7 ; /* DOS date/time */
+} S10_DATE_FIELD, *S10_DATE_FIELD_PTR ;
+
+typedef struct time_field_t {
+ unsigned second : 5 ; /* Extracts the correct number of */
+ unsigned minute : 6 ; /* bits for the "Motorola" type */
+ unsigned hour : 5 ; /* DOS date/time */
+} S10_TIME_FIELD, *S10_TIME_FIELD_PTR ;
+
+#pragma pack()
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/syplpto.h b/private/utils/ntbackup/inc/syplpto.h
new file mode 100644
index 000000000..ae44fb592
--- /dev/null
+++ b/private/utils/ntbackup/inc/syplpto.h
@@ -0,0 +1,37 @@
+/**
+Copyright(c) Archive Software Division 1984-89
+
+
+ Name: syplpto.h
+
+ Description: Prototypes for Sytos Plus' Translator Entry Points
+
+ $Log: T:/LOGFILES/SYPLPTO.H_V $
+
+ Rev 1.2 16 Feb 1994 19:16:56 GREGG
+Changed prototypes to match translator function table.
+
+ Rev 1.1 17 Mar 1993 14:28:42 TERRI
+Initial CAYMAN beta release
+**
+*/
+#if !defined SYPLPTO_H
+#define SYPLPTO_H
+
+BOOLEAN SYPL_DetermineFormat( VOID_PTR ) ;
+INT16 SYPL_Initialize( CHANNEL_PTR ) ;
+VOID SYPL_DeInitialize( VOID_PTR * ) ;
+INT16 SYPL_Parse( CHANNEL_PTR, BUF_PTR, UINT16_PTR ) ;
+UINT16 SYPL_RdException( CHANNEL_PTR, INT16 ) ;
+INT16 SYPL_NewTape( CHANNEL_PTR, BUF_PTR, BOOLEAN_PTR ) ;
+INT16 SYPL_MoveToVCB( CHANNEL_PTR, INT16, BOOLEAN_PTR, BOOLEAN ) ;
+INT16 SYPL_GetCurrentVCB( CHANNEL_PTR, BUF_PTR ) ;
+BOOLEAN SYPL_ReTranslate( CHANNEL_PTR, BUF_PTR ) ;
+INT16 SYPL_ReadMakeDDB( CHANNEL_PTR, BUF_PTR ) ;
+INT16 SYPL_ReadMakeFDB( CHANNEL_PTR, BUF_PTR ) ;
+INT16 SYPL_ReadMakeUDB( CHANNEL_PTR, BUF_PTR ) ;
+INT16 SYPL_ReadMakeMDB( CHANNEL_PTR, BUF_PTR ) ;
+INT16 SYPL_ReadMakeStreams( CHANNEL_PTR, BUF_PTR ) ;
+
+#endif /* SYPLPTO_H */
+
diff --git a/private/utils/ntbackup/inc/tape.h b/private/utils/ntbackup/inc/tape.h
new file mode 100644
index 000000000..559b2ea76
--- /dev/null
+++ b/private/utils/ntbackup/inc/tape.h
@@ -0,0 +1,107 @@
+
+
+/************************
+Copyright (c) Maynard, an Archive Company. 1991
+
+ Name: tape.h
+
+ Description: This file contains the definitions, macros, and function
+ prototypes for the tape operation code.
+
+ $Log: G:/UI/LOGFILES/TAPE.H_V $
+
+ Rev 1.5 08 Jun 1993 11:10:44 CARLS
+added prototype for IsTransferTape
+
+ Rev 1.4 08 Apr 1993 17:32:44 chrish
+Added function prototype WhoPasswordedTape.
+
+ Rev 1.3 22 Mar 1993 13:43:26 chrish
+Added prototype for catalog password check.
+
+ Rev 1.2 15 Dec 1992 11:24:24 chrish
+Modified IsUserValid prototype.
+
+ Rev 1.1 13 Nov 1992 17:42:04 chrish
+Added prototype for function used in Tape Securit for NT.
+
+ Rev 1.0 20 Oct 1992 17:01:48 MIKEP
+Initial revision.
+
+
+
+**************************/
+
+#ifndef TAPE_H
+#define TAPE_H
+
+// defines for gbCurrentOperation
+
+#define OPERATION_NONE 0
+#define OPERATION_BACKUP 1
+#define OPERATION_RESTORE 2
+#define OPERATION_VERIFY 3
+#define OPERATION_CATALOG 4
+#define OPERATION_TENSION 5
+#define OPERATION_ERASE 6
+#define OPERATION_NEXTSET 7
+
+
+//
+// Defines to tell what type of password we have
+// NOSTRADAMOUS_APP - Tape secured by Nostradamous app
+// OTHER_APP - Tape passworded by some other app
+// NO_APP - Tape is neither secured or passworded
+//
+
+#define NOSTRADAMOUS_APP 1 // chs: 04-08-93
+#define OTHER_APP 2 // chs: 04-08-93
+#define NO_APP 3 // chs: 04-08-93
+
+
+// Do Commands, I don't know why these are here ?
+
+INT do_backup( INT16 );
+INT do_restore( INT16 );
+INT do_verify( INT16 );
+INT do_catalog( UINT32, INT16, INT16 );
+INT do_tension( INT16 );
+INT do_delete( INT16 );
+INT do_nextset( VOID );
+
+// Returns the current status of the operation.
+
+INT UI_GetCurrentStatus(
+INT *Operation,
+STATS *Stats,
+CHAR *Path,
+INT PathSize );
+
+
+INT UI_GetBackupCurrentStatus ( STATS *,CHAR *,INT );
+INT UI_GetRestoreCurrentStatus( STATS *,CHAR *,INT );
+INT UI_GetVerifyCurrentStatus ( STATS *,CHAR *,INT );
+INT UI_GetCatalogCurrentStatus( STATS *,CHAR *,INT );
+
+// Tells the current operation to abort after current file is done.
+
+INT UI_AbortAtEndOfFile( VOID );
+
+
+CHAR_PTR GetCurrentMachineNameUserName( VOID );
+BOOLEAN DoesUserHaveThisPrivilege( CHAR_PTR );
+BOOLEAN IsCurrentTapeSecured( DBLK_PTR vcb_ptr );
+BOOLEAN IsUserValid ( DBLK_PTR vcb_ptr, // current VCB
+ INT8_PTR inputtapepasswd, // tape password
+ INT16 inputtapepasswdlength // length of password
+ );
+
+BOOLEAN CatalogPasswordCheck ( DBLK_PTR ) ; // chs:03-22-93
+
+INT16 WhoPasswordedTape ( INT8_PTR tape_password, // chs:04-08-93
+ INT16 tape_password_size ); // chs:04-08-93
+
+
+BOOLEAN IsTransferTape( UINT32 TapeInDriveFID ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/tapepswd.h b/private/utils/ntbackup/inc/tapepswd.h
new file mode 100644
index 000000000..47349e4de
--- /dev/null
+++ b/private/utils/ntbackup/inc/tapepswd.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+ Name: TAPEPSWD.H
+
+ Description: This header file contains defines and structure for
+ tape password processing.
+
+ $Log: G:/UI/LOGFILES/TAPEPSWD.H_V $
+
+ Rev 1.8 09 Jun 1993 15:05:22 MIKEP
+enable c++.
+
+ Rev 1.7 04 Oct 1992 19:49:44 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.6 06 Apr 1992 14:30:24 CARLS
+ID error for translate
+
+ Rev 1.5 03 Apr 1992 13:50:46 CARLS
+added translate defines
+
+ Rev 1.4 27 Jan 1992 00:42:02 CHUCKB
+Updated dialog id's.
+
+ Rev 1.3 10 Dec 1991 13:36:22 CHUCKB
+Fixed control id's.
+
+ Rev 1.2 10 Dec 1991 11:35:00 CHUCKB
+No change.
+
+ Rev 1.1 03 Dec 1991 20:43:48 CHUCKB
+Nothing changed.
+
+ Rev 1.0 20 Nov 1991 19:36:14 SYSTEM
+Initial revision.
+
+****************************************************************************/
+
+#ifndef tapepswd_h
+#define tapepswd_h
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_TAPEPSWD 30
+#else
+#include "dlg_ids.h"
+#endif
+
+#define IDD_T_TAPESTR 0x0065
+#define IDD_T_BKSTR 0x0066
+#define IDD_T_USTR 0x0067
+#define IDD_T_PSWDSTR 0x006A
+#define IDD_T_PSWD 0x006B
+#define IDD_T_TAPENAME 0x006C
+#define IDD_T_BSNAME 0x006D
+#define IDD_T_UNAME 0x006E
+
+typedef struct DS_TAPE_PSWD *DS_TAPE_PSWD_PTR;
+typedef struct DS_TAPE_PSWD {
+
+ LPSTR lpszTapeName ;
+ LPSTR lpszBsetName ;
+ LPSTR lpszUserName ;
+ LPSTR lpszTapePswd ;
+ BOOL fValid ;
+
+} DS_TAPE_PSWD;
+
+#endif
diff --git a/private/utils/ntbackup/inc/tbe_defs.h b/private/utils/ntbackup/inc/tbe_defs.h
new file mode 100644
index 000000000..43bf1c5fb
--- /dev/null
+++ b/private/utils/ntbackup/inc/tbe_defs.h
@@ -0,0 +1,124 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tbe_defs.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+ Location: BE_PUBLIC
+
+
+ $Log: J:/LOGFILES/TBE_DEFS.H_V $
+ *
+ * Rev 1.8 05 Feb 1993 22:32:18 MARILYN
+ * removed copy/move functionality
+ *
+ * Rev 1.7 18 Jan 1993 14:11:00 GREGG
+ * Changes to allow format command passed to driver through TpErase.
+ *
+ * Rev 1.6 04 Jan 1993 15:27:02 ANDY
+ * Added CATALOG_BSET_OPER for Graceful Red
+ *
+ * Rev 1.5 07 Dec 1992 16:49:36 DON
+ * added Marilyns operation types for copy/move
+ *
+ * Rev 1.4 11 Nov 1992 22:09:50 GREGG
+ * Unicodeized literals.
+ *
+ * Rev 1.3 29 Jul 1992 15:28:46 STEVEN
+ * fix warnings
+ *
+ * Rev 1.2 19 Sep 1991 14:32:08 HUNTER
+ * 8200SX - Added new defines for SX Fast File.
+ *
+ * Rev 1.1 17 Sep 1991 14:22:36 GREGG
+ * Added TENSION_NO_READ_OPER.
+ *
+ * Rev 1.0 09 May 1991 13:32:48 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef _tbe_defs_h_
+#define _tbe_defs_h_
+
+/* Revision Numbers */
+#define BE_MAJ_VERSION 1
+#ifdef MBS
+#define MBS_VERSION_INDICATOR 0x80
+#endif
+#define BE_MIN_VERSION 0
+
+
+/* constants for the SX file for EXABYTE 8200SX - MaynStream 2200+ support */
+#define SX_FILE_FORMAT TEXT("%08lx.%03x")
+#define SX_FILE_NAME_LENGTH 13
+
+/* indicate fast file support for EXABYTE 8200SX - MaynStream 2200+ drives */
+#define MANUFACTURED_PBA ( 0xffffffff )
+
+
+/* These are the maximum lengths of the name fields in the vcb */
+
+#define TAPE_NAME 32 /* WARNING: $$$ some of these same constants */
+#define BACKUPSET_NAME 32 /* are defined in the user interface ui_defs.h */
+#define VOLUME_NAME 16 /* using different names. If you change */
+#define MACHINE_NAME 20 /* any of these defines, please check those */
+#define SHORT_MACHINE_NAME 4 /* defines. */
+#define USER_NAME 10
+#define TAPE_PASSWORD 8
+#define BACKUP_SET_PASSWORD 8
+#define SERVER_NAME 48
+
+/* These are the buffer sizes for the field listed above */
+/* They account for the null byte at the end of the string */
+/* when declaring a buffer using one of the above fields, */
+/* these sizes should be used */
+#define TAPE_NAME_BUF_LEN TAPE_NAME + 1
+#define BACKUPSET_NAME_BUF_LEN BACKUPSET_NAME + 1
+#define VOLUME_NAME_BUF_LEN VOLUME_NAME + 1
+#define MACHINE_NAME_BUF_LEN MACHINE_NAME + 1
+#define SHORT_MACHINE_NAME_BUF_LEN SHORT_MACHINE_NAME + 1
+#define USER_NAME_BUF_LEN USER_NAME + 1
+#define SERVER_NAME_BUF_LEN SERVER_NAME + 1
+
+/* define operation types to set in LIS */
+#define BACKUP_OPER (UINT16)1
+#define ARCHIVE_BACKUP_OPER (UINT16)2
+#define ARCHIVE_VERIFY_OPER (UINT16)3
+#define ARCHIVE_DELETE_OPER (UINT16)4
+#define RESTORE_OPER (UINT16)5
+#define VERIFY_OPER (UINT16)6
+#define VERIFY_LAST_BACKUP_OPER (UINT16)7
+#define VERIFY_LAST_RESTORE_OPER (UINT16)8
+#define TDIR_OPER (UINT16)9
+#define TENSION_OPER (UINT16)10
+#define TENSION_NO_READ_OPER (UINT16)11
+#define ERASE_OPER (UINT16)12
+#define ERASE_NO_READ_OPER (UINT16)13
+#define SECURITY_ERASE_OPER (UINT16)14
+#define SEC_ERASE_NO_READ_OPER (UINT16)15
+#define ERASE_FMARK_ONLY (UINT16)16
+#define PREPARE_OPER (UINT16)17
+#define CATALOG_TAPE_OPER (UINT16)18
+#define CATALOG_COMPACT_OPER (UINT16)19
+#define CATALOG_CLEANUP_OPER (UINT16)20
+#define RETIRE_OPER (UINT16)21
+#define ROTATE_OPER (UINT16)22
+#define CATALOG_BSET_OPER (UINT16)28
+#define FORMAT_OPER (UINT16)29
+
+/* Encryption algorithm types */
+#define NO_ENCRYPTION 0
+#define MAYNARD 1
+#define DES 2
+
+/* Compression algorithm types */
+#define NO_COMPRESSION 0
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/tbe_err.h b/private/utils/ntbackup/inc/tbe_err.h
new file mode 100644
index 000000000..b6e6c4e27
--- /dev/null
+++ b/private/utils/ntbackup/inc/tbe_err.h
@@ -0,0 +1,38 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tbe_err.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+ Location: BE_PUBLIC
+
+
+ $Log: N:/LOGFILES/TBE_ERR.H_V $
+ *
+ * Rev 1.1 30 May 1991 11:59:18 STEVEN
+ * bsdu_err.h no longer exists
+ *
+ * Rev 1.0 09 May 1991 13:33:20 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef _tbe_err_h_
+#define _tbe_err_h_
+
+/* general -1 -255 */
+/* file system -256 -511 */
+/* tape format -512 -767 */
+/* loops -768 -1023 */
+/* bsdu 0xfbff 0xfb00*/
+
+#include <std_err.h>
+#include "fsys_err.h"
+#include "tfl_err.h"
+
+#endif
diff --git a/private/utils/ntbackup/inc/tble_prv.h b/private/utils/ntbackup/inc/tble_prv.h
new file mode 100644
index 000000000..3bd06e0d0
--- /dev/null
+++ b/private/utils/ntbackup/inc/tble_prv.h
@@ -0,0 +1,35 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tble_prv.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+ Location: BE_PRIVATE
+
+
+ $Log: Q:/LOGFILES/TBLE_PRV.H_V $
+ *
+ * Rev 1.1 18 Jun 1993 09:24:32 MIKEP
+ * enable C++
+ *
+ * Rev 1.0 09 May 1991 13:30:56 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ include list */
+
+#ifndef ENC_TABLES
+
+#define ENC_TABLES
+
+#include "StdTypes.H"
+
+/* Arrays are now filled in ENC_TAB.CPP */
+extern UINT8 enc_table[256] ;
+extern UINT8 dec_table[256] ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/tdemo.h b/private/utils/ntbackup/inc/tdemo.h
new file mode 100644
index 000000000..1ac71155a
--- /dev/null
+++ b/private/utils/ntbackup/inc/tdemo.h
@@ -0,0 +1,52 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tdemo.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This function contains the prototypes for the functions in
+ devdrv\tdemo\tdemdd.c
+
+ Location: BE_PUBLIC
+
+
+ $log$
+
+**/
+/* $end$ */
+
+#ifndef _tdemo_h_
+#define _tdemo_h_
+
+
+
+#ifdef TDEMO
+
+VOID TdemoNewTape( UINT32 new_tape_id ) ;
+
+UINT32 TdemoGeneratedTapeId( VOID ) ;
+
+BOOLEAN TdemoInit( CHAR_PTR demo_directory,
+ INT16 num_tapes,
+ VOID_PTR workstation_resource,
+ VOID_PTR alias_resource,
+ BOOLEAN fast );
+
+/* used by the UI DO_*.C routines to request the correct tape
+ to be inserted for the demo driver */
+VOID NtDemoChangeTape( UINT16 tape_number ) ;
+
+#else
+
+#define TdemoNewTape( n ) /* do nothing */
+#define TdemoInit( d, n, w, a, f) FALSE
+#define NtDemoChangeTape( t ) /* do nothing */
+
+#endif
+
+
+
+
+#endif
diff --git a/private/utils/ntbackup/inc/tension.h b/private/utils/ntbackup/inc/tension.h
new file mode 100644
index 000000000..7e3a7bf76
--- /dev/null
+++ b/private/utils/ntbackup/inc/tension.h
@@ -0,0 +1,30 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: tension.h
+
+ Description: include file for the tension.dlg dialog
+
+
+ $Log: G:/UI/LOGFILES/TENSION.H_V $
+
+ Rev 1.3 04 Oct 1992 19:49:46 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.2 03 Apr 1992 13:52:44 CARLS
+added translate defines
+
+ Rev 1.0 20 Nov 1991 19:34:42 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_TENSION 41
+#endif
+
+#define IDD_JST_LISTBOX 67
+#define IDD_JST_OK 220
+
diff --git a/private/utils/ntbackup/inc/text.h b/private/utils/ntbackup/inc/text.h
new file mode 100644
index 000000000..9fc6e3371
--- /dev/null
+++ b/private/utils/ntbackup/inc/text.h
@@ -0,0 +1,45 @@
+
+/**************************************************
+Copyright (C) Maynard, An Archive Company. 1992
+
+ Name: text.h
+
+ Description:
+
+ Unicode mappings for the string functions. Should have no
+ effect on winter park, only NT.
+
+ $Log: G:/UI/LOGFILES/TEXT.H_V $
+
+ Rev 1.0 04 May 1992 13:33:32 MIKEP
+Initial revision.
+
+
+****************************************************/
+
+
+#ifndef TEXT_MAPPINGS
+
+#define TEXT_MAPPINGS
+
+#ifdef UNICODE
+
+# define strlen( (x) ) wcslen( (x) )
+# define strcpy( (x), (y) ) wcscpy( (x) )
+# define strncpy( (x), (y), (z) ) wcsncpy( (x), (y), (z) )
+# define strcat( (x), (y) ) wcscat( (x), (y) )
+# define strncat( (x), (y), (z) ) wcsncat( (x), (y), (z) )
+# define strcmp( (x), (y) ) wcscmp( (x), (y) )
+# define strncmp( (x), (y), (z) ) wcsncmp( (x), (y), (z) )
+# define stricmp( (x), (y) ) wcsicmp( (x), (y) )
+# define strnicmp( (x), (y), (z) ) wcsnicmp( (x), (y), (z) )
+# define strrchr( (x), (y) ) wcsrchr( (x), (y) )
+# define strchr( (x), (y) ) wcschr( (x), (y) )
+# define strpbrk( (x), (y) ) wcspbrk( (x), (y) )
+# define strlwr( (x) ) wcslwr( (x) )
+# define strupr( (x) ) wcsupr( (x) )
+# define strstr( (x), (y) ) wcsstr( (x), (y) )
+
+#endif
+
+#endif
diff --git a/private/utils/ntbackup/inc/tfl_err.h b/private/utils/ntbackup/inc/tfl_err.h
new file mode 100644
index 000000000..6ed2a77c5
--- /dev/null
+++ b/private/utils/ntbackup/inc/tfl_err.h
@@ -0,0 +1,126 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+$name$
+.module information
+
+$paths$
+headers\tfl_err.h
+subsystem\TAPE FORMAT\tfl_err.h
+$0$
+
+ Name: tfl_err.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the Tape Format Layer error codes.
+
+ Location: BE_PUBLIC
+
+$Header: Q:/LOGFILES/TFL_ERR.H_V 1.10 02 Aug 1993 17:11:00 TerriLynn $
+
+$Log: Q:/LOGFILES/TFL_ERR.H_V $
+ *
+ * Rev 1.10 02 Aug 1993 17:11:00 TerriLynn
+ * Added Use SYPL ECC FLAG for Sytos Plus
+ * ECC translation error
+ *
+ * Rev 1.9 22 Apr 1993 03:31:18 GREGG
+ * Third in a series of incremental changes to bring the translator in line
+ * with the MTF spec:
+ *
+ * - Removed all references to the DBLK element 'string_storage_offset',
+ * which no longer exists.
+ * - Check for incompatable versions of the Tape Format and OTC and deals
+ * with them the best it can, or reports tape as foreign if they're too
+ * far out. Includes ignoring the OTC and not allowing append if the
+ * OTC on tape is a future rev, different type, or on an alternate
+ * partition.
+ * - Updated OTC "location" attribute bits, and changed definition of
+ * CFIL to store stream number instead of stream ID.
+ *
+ * Matches: TFL_ERR.H 1.9, MTF10WDB.C 1.7, TRANSLAT.C 1.39, FMTINF.H 1.11,
+ * OTC40RD.C 1.24, MAYN40RD.C 1.56, MTF10WT.C 1.7, OTC40MSC.C 1.20
+ * DETFMT.C 1.13, MTF.H 1.4
+ *
+ * Rev 1.8 30 Mar 1993 16:19:10 GREGG
+ * Handle Unrecognized Media error (unformatted DC2000).
+ *
+ * Rev 1.7 04 Feb 1993 14:58:00 ZEIR
+ * Brought forward Loader errors from Mama Cass revision (1.4.1.0)
+ *
+ * Rev 1.6 09 Nov 1992 10:48:52 GREGG
+ * Added TFLE_BAD_SET_MAP.
+ *
+ * Rev 1.5 05 Apr 1992 17:51:58 GREGG
+ * ROLLER BLADES - Initial OTC integration.
+ *
+ * Rev 1.4 17 Sep 1991 14:17:36 GREGG
+ * Added TFLE_INCOMPATIBLE_DRIVE.
+ *
+ * Rev 1.3 05 Aug 1991 16:43:48 GREGG
+ * Added TFLE_CHANNEL_IN_USE error definition for TF_RewindAllDrives.
+ *
+ * Rev 1.2 05 Jun 1991 18:16:28 NED
+ * added TFLE_UNEXPECTED_EOM
+ *
+ * Rev 1.1 10 May 1991 17:26:32 GREGG
+ * Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:15:40 GREGG
+Initial revision.
+
+$-4$
+**/
+#ifndef _TFL_ERRORS
+#define _TFL_ERRORS
+
+
+/* $end$ include list */
+
+
+#define TFLE_NO_ERR 0 /* Everything Hunkie-Dorie */
+#define TFLE_UNKNOWN_FMT -512 /* We don't understand this format */
+#define TFLE_DRIVER_FAILURE -513 /* The driver won't Init */
+#define TFLE_NO_CONTROLLERS -514 /* No Controllers present */
+#define TFLE_NO_DRIVES -515 /* No Drives detected */
+#define TFLE_NO_MEMORY -516 /* Can't Allocate Memory */
+#define TFLE_NO_FREE_CHANNELS -517 /* There are no free channels */
+#define TFLE_CANNOT_OPEN_DRIVE -518 /* Can't open the drive */
+#define TFLE_BAD_TAPE -519 /* The tape is hosed -- physically */
+#define TFLE_DRIVE_FAILURE -520 /* The drive failed */
+#define TFLE_USER_ABORT -521 /* The user told us quit */
+#define TFLE_TAPE_INCONSISTENCY -522 /* The format is understood, but the layout is screwed up */
+#define TFLE_NO_MORE_DRIVES -523 /* No More Drives in a Channel */
+#define TFLE_NO_FREE_BUFFERS -524 /* No more free buffers */
+#define TFLE_TRANSLATION_FAILURE -525 /* I can't translate a dblk */
+#define TFLE_NO_TAPE -526 /* No Tape in drive */
+#define TFLE_UI_HAPPY_ABORT -527 /* The User Interface Happy Aborted */
+#define TFLE_HW_CONFIG_PROBLEM -528 /* Some error occurred with Board Setup */
+#define TFLE_BAD_SET_MAP -529 /* EOD encountered with no Set Map */
+#define TFLE_WRITE_PROTECT -530 /* The tape is write protected */
+#define TFLE_DRIVER_LOAD_FAILURE -531 /* We could't load driver */
+#define TFLE_UNEXPECTED_EOS -532 /* We have encounted an unExpected End of Set */
+#define TFLE_PROGRAMMER_ERROR1 -533 /* Instead of an assert... */
+#define TFLE_UNEXPECTED_EOM -534 /* tried to MoveFileMarks past BOT/EOM */
+#define TFLE_CHANNEL_IN_USE -535 /* Call to RewindAllDrives while a channel was in use */
+#define TFLE_INCOMPATIBLE_DRIVE -536 /* Drive doesn't have capabilities required to support translator */
+#define TFLE_OTC_FAILURE -537 /* On Tape Catalog Failure */
+
+#define TFLE_DOOR_AJAR -538 /* The Loader door has been opened when the CHM was not in motion */
+#define TFLE_NO_CARTRIDGE -539 /* No cartridge was detected in the loader */
+#define TFLE_WRONG_MODE -540 /* The loader was manually placed in sequential mode */
+#define TFLE_LOAD_UNLOAD -541 /* An error occured during a load CHM movement (tape may still be in CHM) */
+#define TFLE_DEST_FULL -542 /* Cannot return tape to original cartridge position */
+#define TFLE_EMPTY_SRC -543 /* The source selected for a tape is empty */
+#define TFLE_DRIVE_CLOSED -544 /* The drive door is closed and must be manually opened */
+#define TFLE_ARM_FULL -545 /* Attempt to get new tape with arm full */
+#define TFLE_DRIVE_FULL -546 /* Cannot put the requested tape in the drive because drive is full */
+#define TFLE_UNEXPECTED_TAPE -547 /* Encountered a tape in the drive when the driver thought it was empty */
+
+#define TFLE_UNRECOGNIZED_MEDIA -548 /* DC2000 unformatted or unrecognized format tape */
+#define TFLE_APPEND_NOT_ALLOWED -549 /* Cannot read catalogs on tape */
+#define TFLE_USE_SYPL_ECC_FLAG -550 /* Cannot read catalogs on tape */
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/tfldefs.h b/private/utils/ntbackup/inc/tfldefs.h
new file mode 100644
index 000000000..df91ebec8
--- /dev/null
+++ b/private/utils/ntbackup/inc/tfldefs.h
@@ -0,0 +1,204 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+$name$
+.module information
+
+$paths$
+headers\tfldefs.h
+subsystem\TAPE FORMAT\tfldefs.h
+$0$
+
+ Name: tfldefs.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+ Location: BE_PUBLIC
+
+$Header: J:/LOGFILES/TFLDEFS.H_V 1.21 31 Mar 1993 08:51:30 MARILYN $
+
+$Log: J:/LOGFILES/TFLDEFS.H_V $
+ *
+ * Rev 1.21 31 Mar 1993 08:51:30 MARILYN
+ * added a definition for STREAM_CHECKSUMED
+ *
+ * Rev 1.20 18 Jan 1993 14:10:56 GREGG
+ * Changes to allow format command passed to driver through TpErase.
+ *
+ * Rev 1.19 09 Nov 1992 10:48:56 GREGG
+ * Added tape catalog level defines.
+ *
+ * Rev 1.18 13 Oct 1992 11:55:14 HUNTER
+ * Added defines for Stream Stuff
+ *
+ * Rev 1.17 16 Sep 1992 16:51:24 HUNTER
+ * Added TF_SKIP_DATA_STREAM
+ *
+ *
+ * Rev 1.16 17 Aug 1992 09:22:04 GREGG
+ * Removed defines for TF_SKIP_TO_NEXT_DIRECTORY and TF_KEEP_GEN_DATA_ONLY.
+ *
+ * Rev 1.15 27 Jul 1992 14:06:14 GREGG
+ * Fixed more warnings...
+ *
+ * Rev 1.14 27 Jul 1992 12:28:34 GREGG
+ * Cast constants.
+ *
+ * Rev 1.13 09 Jun 1992 19:34:10 GREGG
+ * Removed a bunch of defines which are no longer needed or moved elsewhere.
+ *
+ * Rev 1.12 22 May 1992 12:53:12 GREGG
+ * Added TF_SCAN_OPERATION and TF_SCAN_CONTINUE.
+ *
+ * Rev 1.11 15 May 1992 08:55:48 STEVEN
+ * added VCB_LBA_BIT
+ *
+ * Rev 1.10 12 Mar 1992 15:53:14 STEVEN
+ * 64 bit changes
+ *
+ * Rev 1.9 28 Feb 1992 13:06:46 STEVEN
+ * step one for 4.0 tape format
+ *
+ * Rev 1.8 17 Nov 1991 17:11:02 GREGG
+ * TRICYCLE - VBLK - Added VAR_BLKS_BIT for VCB BSDB DDB and FDB.
+ *
+ * Rev 1.7 17 Nov 1991 16:37:28 GREGG
+ * Added BSDB_ABORTED_SET_BIT.
+ *
+ * Rev 1.6 06 Nov 1991 13:19:30 STEVEN
+ * TRYCYCLE added support for notifying APP to not use a continuation set
+ *
+ * Rev 1.5 19 Sep 1991 10:06:50 HUNTER
+ * 8200SX - Added defines for "TF_LIST_TAPE_OPERATION" and "TF_OPERATION_MASK".
+ *
+ * Rev 1.4 17 Sep 1991 14:21:10 GREGG
+ * I modified the definitions of the Erase and Retension types and added a
+ * Retension with no read option. Steve added four new VCB bits for GUI.
+ *
+ * Rev 1.3 22 Jul 1991 11:51:32 GREGG
+ * Added EOS_AT_EOM attribute bit.
+ *
+ * Rev 1.2 21 May 1991 10:24:48 NED
+ * Added VCB_UNSUPPORTED_BIT for QicStream 1.9x and Sy-TOS sets
+ * which we can't (or won't) restore, directory, etc.
+ *
+ * Rev 1.1 10 May 1991 17:26:46 GREGG
+ * Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:15:40 GREGG
+Initial revision.
+
+$-1$
+**/
+/* $end$ */
+
+#ifndef _TFL_DEFS
+#define _TFL_DEFS
+
+/* The valid operation modes for TF_OpenSet() */
+#define TF_READ_OPERATION 0x1
+#define TF_WRITE_OPERATION 0x2
+#define TF_WRITE_APPEND 0x3 /* This is only for multiple sequential sets */
+#define TF_DESTROY_OPERATION 0x4
+#define TF_WATCHING 0x5
+#define TF_SCAN_OPERATION 0x6
+
+#define TF_READ_CONTINUE 0x8001
+#define TF_WRITE_CONTINUE 0x8002
+#define TF_DESTROY_CONTINUE 0x8003
+#define TF_SCAN_CONTINUE 0x8006
+
+/* to be set in LOOPS and masked out in TF_OpenSet() */
+#define TF_LIST_TAPE_OPERATION 0x0100
+#define TF_OPERATION_MASK 0x0f00 /* NOTE: 0x0f00 will support 4 bit defined operations */
+
+
+/* These are the valid filters for all operations */
+#define TF_KEEP_ALL_DATA 0x0 /* FS, LOOPS, PERM */
+#define TF_SKIP_ALL_DATA 0x1 /* FS, LOOPS, PERM */
+#define TF_SKIP_TO_NEXT_DIRECTORY 0x2 /* LOOPS */
+#define TF_SKIP_DATA_STREAM 0x3 /* FS, LOOPS */
+
+/* Tension and Erase Values */
+
+#define TF_NO_RD 0x1
+
+#define TF_ER 0x0
+#define TF_S_ER 0x2
+#define TF_F_ER 0x4
+#define TF_RET 0x8
+#define TF_FMT 0x10
+
+#define TF_ERASE_READ (TF_ER) /* Erase with read */
+#define TF_ERASE_NO_READ (TF_ER|TF_NO_RD) /* Don't read normal erase */
+#define TF_ERASE_SECURITY (TF_S_ER) /* Security erase with read */
+#define TF_ERASE_SEC_NO_READ (TF_S_ER|TF_NO_RD) /* Security erase no read */
+#define TF_RETENSION_READ (TF_RET) /* Retension with read */
+#define TF_RETENSION_NO_READ (TF_RET|TF_NO_RD) /* Retension no read */
+#define TF_FORMAT_READ (TF_FMT) /* Format (DC 2000) */
+
+/* This case is used for Maynard production facility as is specified
+ via the /FM undocumented switch for tension */
+#define TF_ERASE_FMARK (TF_F_ER) /* Write filemark to erase with read */
+
+
+
+/* The following 'block_type's are defined.
+*/
+
+#define BT_UDB ((UINT8)0)
+#define BT_VCB ((UINT8)1)
+#define BT_CVCB ((UINT8)2)
+#define BT_BSDB ((UINT8)3)
+#define BT_DDB ((UINT8)8)
+#define BT_FDB ((UINT8)9)
+#define BT_IDB ((UINT8)10)
+#define BT_CFDB ((UINT8)11)
+#define BT_STREAM ((UINT8)39)
+
+
+
+/* Tape format Stream Attributes */
+
+#define STREAM_CONTINUE BIT0 /* This is a continuation Stream */
+#define STREAM_VARIABLE BIT1 /* The data size for this stream is variable */
+#define STREAM_VAR_END BIT2 /* Last piece of this Variable length data */
+#define STREAM_CHECKSUMED BIT5 /* A standard MTF checksum stream follows */
+
+
+/* WARNING: The value "256" decimal cannot be defined as a block type
+ This is is used inside the Tape Format Layer.
+*/
+
+#define BT_HOSED ((UINT16)0xffff)
+
+/* Process Type Defines */
+
+#define INTEL 0x0000
+#define MOTOROLA 0xffff
+
+#define CUR_PROCESSOR INTEL
+
+/* The following constitute the set of known OS ID's.
+ OS versions belong to the file system, with the exception of th
+ generic one (See GOS.h).
+*/
+
+#define MOS_PC_DOS 0
+#define MOS_PC_NOVELL 1
+#define MOS_OS2 2
+#define MOS_MAC_FINDER 3
+#define MOS_MAC_TOPS 4
+#define MOS_MAC_APPLESHARE 5
+#define MOS_MAC_AUX 6
+#define MOS_GENERIC -1 /* GOS be with you brother... */
+
+/* Tape Catalog Level Defines */
+#define TCL_FULL 2
+#define TCL_PARTIAL 1
+#define TCL_NONE 0
+
+
+#endif
diff --git a/private/utils/ntbackup/inc/tflopen.h b/private/utils/ntbackup/inc/tflopen.h
new file mode 100644
index 000000000..89b722bf0
--- /dev/null
+++ b/private/utils/ntbackup/inc/tflopen.h
@@ -0,0 +1,63 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+$name$
+.module information
+
+$paths$
+headers\tflopen.h
+subsystem\TAPE FORMAT\tflopen.h
+$0$
+
+ Name: tflopen.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the parameter block for the TF_OpenSet() call.
+
+ Location: BE_PRIVATE
+
+$Header: N:/LOGFILES/TFLOPEN.H_V 1.2 17 Oct 1991 01:42:58 ED $
+
+$Log: N:/LOGFILES/TFLOPEN.H_V $
+ *
+ * Rev 1.2 17 Oct 1991 01:42:58 ED
+ * BIGWHEEL - 8200sx - Added cat_enabled boolean to open struct.
+ *
+ * Rev 1.1 10 May 1991 17:22:30 GREGG
+ * Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:15:52 GREGG
+Initial revision.
+
+ Rev 2.0 21 May 1990 14:19:46 PAT
+ Baseline Maynstream 3.1
+
+$-4$
+**/
+#ifndef _PB_OPENSET
+#define _PB_OPENSET
+
+#include "thw.h"
+#include "fsys.h"
+#include "tpos.h"
+
+/* $end$ include list */
+
+typedef struct {
+ THW_PTR sdrv ; /* Starting Drive */
+ BOOLEAN ignore_clink ; /* Ignore Channel list */
+ BOOLEAN rewind_sdrv ; /* Rewind the Starting drive */
+ INT16 channel ; /* the channel number */
+ UINT16 mode ; /* the operation mode */
+ FSYS_HAND fsh ; /* The filesystem pointer */
+ UINT16 perm_filter ; /* The permanent filter */
+ UINT32 attributes ; /* Open Attributes */
+ TPOS_PTR tape_position ; /* For a specified position */
+ UINT16 wrt_format ; /* For writes, what format */
+ BOOLEAN (*idle_call)( UINT32 ) ; /* function I'll call while I'm idling */
+ UINT32 reference ; /* To pass to the idle call */
+ BOOLEAN cat_enabled ; /* Catalog Eanbled? From LIS */
+} TFL_OPBLK, *TFL_OPBLK_PTR ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/tflproto.h b/private/utils/ntbackup/inc/tflproto.h
new file mode 100644
index 000000000..364fecff4
--- /dev/null
+++ b/private/utils/ntbackup/inc/tflproto.h
@@ -0,0 +1,134 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+$name$
+.module information
+
+$paths$
+headers\tflproto.h
+subsystem\TAPE FORMAT\tflproto.h
+$0$
+
+ Name: tflproto.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the prototypes for the Tape Format Layer entry
+ points.
+
+ Location: BE_PRIVATE
+
+$Header: T:\logfiles\tflproto.h_v 1.18 17 Dec 1993 16:40:08 GREGG $
+
+$Log: T:\logfiles\tflproto.h_v $
+ *
+ * Rev 1.18 17 Dec 1993 16:40:08 GREGG
+ * Extended error reporting.
+ *
+ * Rev 1.17 22 Jul 1993 12:09:46 ZEIR
+ * add'd software_name param to OpenTapeFormat
+ *
+ * Rev 1.16 22 Jun 1993 18:28:34 GREGG
+ * Added prototype for TF_SetHWCompression.
+ *
+ * Rev 1.15 22 Jun 1993 10:53:30 GREGG
+ * Added API to change the catalog directory path.
+ *
+ * Rev 1.14 06 Jun 1993 21:11:44 GREGG
+ * Added abort flag parameter to protos for TF_CloseSetMap and TF_CloseSetCat.
+ *
+ * Rev 1.13 09 Nov 1992 10:49:10 GREGG
+ * Added tape catalog API prototypes.
+ *
+ * Rev 1.12 24 Feb 1992 15:09:52 GREGG
+ * Added protos for TF_OpenTape and TF_CloseTape.
+ *
+ * Rev 1.11 19 Feb 1992 16:04:32 GREGG
+ * Added vcb_only parameter to prototype for TF_OpenSet.
+ *
+ * Rev 1.10 04 Feb 1992 21:38:06 GREGG
+ * Changed protos for TF_OpenTapeFormat and TF_AllocateTapeBuffers.
+ *
+ * Rev 1.9 07 Jan 1992 14:21:54 NED
+ * added is_write parameter to TF_AllocateTapeBuffers and TF_FreeTapeBuffers
+ *
+ * Rev 1.8 17 Oct 1991 01:34:26 GREGG
+ * BIGWHEEL - -8200sx - Added catalog_directory parameter to TF_OpenTapeFormat.
+ *
+ * Rev 1.7 02 Oct 1991 14:10:36 GREGG
+ * BigW - Soft Eject - Added prototype for TF_EjectTape.
+ *
+ * Rev 1.6 19 Sep 1991 14:51:06 HUNTER
+ * 8200SX - Added parameter for Forced machine type.
+ *
+ * Rev 1.5 17 Sep 1991 14:14:14 GREGG
+ * Changed proto for TF_Reten to include mode, and removed proto for TF_EraseChannel.
+ *
+ * Rev 1.4 05 Aug 1991 16:48:48 GREGG
+ * Added prototype for new API: TF_RewindAllDrives.
+ *
+ * Rev 1.3 27 Jun 1991 16:29:58 NED
+ * added parameter to TF_OpenTapeFormat() declaration.
+ *
+ * Rev 1.2 21 May 1991 16:59:30 NED
+ * moved declarations of TF_GetTapeFormatInfo(), etc. to
+ * bengine/xface/fmtinf.h where they probably belong.
+ *
+ * Rev 1.1 10 May 1991 17:22:56 GREGG
+ * Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:15:42 GREGG
+Initial revision.
+
+$-4$
+**/
+#ifndef TFL_PROTOS
+#define TFL_PROTOS
+
+#include "thw.h"
+#include "tpos.h"
+#include "reqrep.h"
+#include "tflopen.h"
+#include "fmtinf.h"
+#include "dilhwd.h"
+
+/* $end$ include list */
+
+INT16 TF_OpenTapeFormat(
+ CHAR_PTR drv_file , /* The device driver file to load */
+ DIL_HWD_PTR cards , /* The array of cards */
+ UINT16 no_cards , /* The number of cards */
+ THW_PTR *thw_ptr , /* Where to build the THW list */
+ INT16 max_channels , /* The maximum number of channels */
+ BOOLEAN use_fast_file, /* FALSE if FF to be suppressed */
+ BOOLEAN ignore_id , /* Operate on non Maynard Drives */
+ CHAR_PTR directory_name, /* for TDH */
+ INT16 forced_machine_type, /* 8200SX stuff */
+ CHAR_PTR catalog_directory, /* for SX files */
+ UINT16 initial_buff_alloc, /* DOS memory allocated at init */
+ CHAR_PTR software_name ) ; /* Name of software we're running */
+
+INT16 TF_SetHWCompression( THW_PTR thw, BOOLEAN enable ) ;
+VOID TF_CloseTapeFormat( VOID ) ;
+INT16 TF_AllocateTapeBuffers( UINT16 mem_save, UINT16 max_buffs, UINT16 buff_size ) ;
+INT16 TF_FreeTapeBuffers( VOID ) ;
+INT16 TF_OpenSet( TFL_OPBLK_PTR open_info, BOOLEAN vcb_only ) ;
+VOID TF_CloseSet( UINT16 channel_no, TF_STATS_PTR setstats ) ;
+INT16 TF_OpenTape( INT16_PTR channel_no, THW_PTR sdrv, TPOS_PTR tape_position ) ;
+VOID TF_CloseTape( UINT16 channel_no ) ;
+INT16 TF_GetNextTapeRequest( RR_PTR req ) ;
+THW_PTR TF_GetCurrentDevice( UINT16 channel_no ) ;
+INT16 TF_RetensionChannel( TFL_OPBLK_PTR open_blk, UINT16 mode ) ;
+INT16 TF_RewindAllDrives( VOID ) ;
+INT16 TF_EjectTape( THW_PTR thw, TPOS_HANDLER ui_tpos ) ;
+INT TF_OpenSetMap( THW_PTR thw, FSYS_HAND fsh, TPOS_PTR tpos,
+ BOOLEAN_PTR complete, BOOLEAN get_best ) ;
+INT TF_OpenSetCat( THW_PTR thw, FSYS_HAND fsh, TPOS_PTR tpos ) ;
+VOID TF_CloseSetMap( BOOLEAN abort ) ;
+VOID TF_CloseSetCat( BOOLEAN abort ) ;
+INT TF_GetNextSMEntry( FSYS_HAND fsh, DBLK_PTR vcb ) ;
+INT TF_GetNextSCEntry( FSYS_HAND fsh, DBLK_PTR dblk ) ;
+INT TF_ChangeCatPath( CHAR_PTR new_path ) ;
+BOOLEAN TF_GetLastDriveError( THW_PTR thw, INT16_PTR gen_func, INT16_PTR gen_err, INT32_PTR gen_misc ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/tflstats.h b/private/utils/ntbackup/inc/tflstats.h
new file mode 100644
index 000000000..2b8138b1f
--- /dev/null
+++ b/private/utils/ntbackup/inc/tflstats.h
@@ -0,0 +1,48 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+$name$
+.module information
+
+$paths$
+headers\tflstats.h
+subsystem\TAPE FORMAT\tflstats.h
+$0$
+
+ Name: tflstats.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Defines the Statistics structure for the TFL.
+
+ Location: BE_PRIVATE
+
+$Header: W:/LOGFILES/TFLSTATS.H_V 1.1 10 May 1991 17:22:16 GREGG $
+
+$Log: W:/LOGFILES/TFLSTATS.H_V $
+ *
+ * Rev 1.1 10 May 1991 17:22:16 GREGG
+ * Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:15:44 GREGG
+Initial revision.
+
+ Rev 2.0 21 May 1990 14:19:46 PAT
+ Baseline Maynstream 3.1
+
+$-4$
+**/
+#ifndef _STATS_STUFF
+#define _STATS_STUFF
+
+/* $end$ include list */
+
+typedef struct {
+ UINT32 underruns ; /* Number of Underruns */
+ UINT32 dataerrs ; /* Number of Data Errors */
+ UINT32 bytes_processed ; /* Number of bytes processed */
+} TF_STATS, *TF_STATS_PTR ;
+
+#endif
+
+
diff --git a/private/utils/ntbackup/inc/tflwatch.h b/private/utils/ntbackup/inc/tflwatch.h
new file mode 100644
index 000000000..0f6e4935e
--- /dev/null
+++ b/private/utils/ntbackup/inc/tflwatch.h
@@ -0,0 +1,60 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+$name$
+.module information
+
+$paths$
+headers\tflwatch.h
+subsystem\TAPE FORMAT\tflwatch.h
+$0$
+
+ Name: tflwatch.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the Prototypes for the Watch stuff.
+
+ Location: BE_PUBLIC
+
+$Header: W:/LOGFILES/TFLWATCH.H_V 1.1 10 May 1991 17:26:06 GREGG $
+
+$Log: W:/LOGFILES/TFLWATCH.H_V $
+ *
+ * Rev 1.1 10 May 1991 17:26:06 GREGG
+ * Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:15:46 GREGG
+Initial revision.
+
+ Rev 2.1 01 Oct 1990 17:29:34 STEVEN
+ Watch needs file system handle
+
+ Rev 2.0 21 May 1990 14:19:50 PAT
+ Baseline Maynstream 3.1
+
+$-4$
+**/
+#ifndef _WATCH_DRIVE
+#define _WATCH_DRIVE
+
+#include "thw.h"
+
+/* $end$ include list */
+
+
+#define TFL_WATCH_SUCCESS 0
+#define TFL_WATCH_UNCHANGED 1
+#define TFL_WATCH_NOTAPE 2
+#define TFL_WATCH_FORIEGN_TAPE 3
+#define TFL_BLANK_TAPE 4
+#define TFL_BUSY_DRIVE 5
+#define TFL_WATCH_DRIVE_FAILURE 6
+
+INT16 TF_InitiateWatch( THW_PTR drive, FSYS_HAND fsh, DBLK_PTR vcb_dblk, BOOLEAN rewind ) ;
+INT16 TF_WatchDrive( INT16 watch_handle ) ;
+INT16 TF_EndWatch( INT16 watch_handle) ;
+
+#endif
+
+
diff --git a/private/utils/ntbackup/inc/tfpoll.h b/private/utils/ntbackup/inc/tfpoll.h
new file mode 100644
index 000000000..aca7e6506
--- /dev/null
+++ b/private/utils/ntbackup/inc/tfpoll.h
@@ -0,0 +1,76 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-91
+
+
+ Name: tfpoll.h
+
+ Description: API for TF_PollDrive.
+
+ $Log: T:\logfiles\tfpoll.h_v $
+
+ Rev 1.7.1.1 17 Dec 1993 16:39:56 GREGG
+Extended error reporting.
+
+ Rev 1.7.1.0 30 Nov 1993 18:27:42 GREGG
+Added message PD_SQL_TAPE.
+
+ Rev 1.7 13 Jul 1993 19:13:06 GREGG
+Added new PD messages to report future rev and ECC tapes.
+
+ Rev 1.6 27 Mar 1993 17:34:08 GREGG
+Removed PD_UNFORMATTED_TAPE.
+
+ Rev 1.5 22 Mar 1993 17:10:12 chrish
+Added define for PD_UNRECOGNIZED_MEDIA
+
+ Rev 1.4 12 Mar 1993 14:59:08 MIKEP
+add unformated msg
+
+ Rev 1.3 27 Jul 1992 12:23:16 GREGG
+Cast constants.
+
+ Rev 1.2 25 Nov 1991 14:33:10 GREGG
+Added PD_BAD_TAPE message.
+
+ Rev 1.1 17 Sep 1991 14:24:42 GREGG
+Changed TPOS_PTR parameter to TPOS_HANDLER.
+
+ Rev 1.0 09 Sep 1991 21:09:32 GREGG
+Initial revision.
+
+**/
+
+/* Return Codes: */
+
+#define PD_NO_CHANGE ((UINT16)0x00)
+#define PD_BLANK_TAPE ((UINT16)0x01)
+#define PD_NO_TAPE ((UINT16)0x02)
+#define PD_FOREIGN_TAPE ((UINT16)0x03)
+#define PD_BUSY ((UINT16)0x04)
+#define PD_NEW_TAPE ((UINT16)0x05)
+#define PD_VALID_VCB ((UINT16)0x06)
+#define PD_FUBAR ((UINT16)0x07)
+#define PD_NO_FREE_CHANNELS ((UINT16)0x08)
+#define PD_OUT_OF_MEMORY ((UINT16)0x09)
+#define PD_DRIVE_FAILURE ((UINT16)0x0a)
+#define PD_OUT_OF_SEQUENCE ((UINT16)0x0b)
+#define PD_BAD_TAPE ((UINT16)0x0c)
+#define PD_UNRECOGNIZED_MEDIA ((UINT16)0x0d)
+#define PD_FUTURE_REV_MTF ((UINT16)0x0e)
+#define PD_MTF_ECC_TAPE ((UINT16)0x0f)
+#define PD_SQL_TAPE ((UINT16)0x10)
+#define PD_DRIVER_FAILURE ((UINT16)0x11)
+
+/* Input Messages: */
+
+#define PDMSG_CONTINUE ((UINT16)0)
+#define PDMSG_START ((UINT16)1)
+#define PDMSG_END ((UINT16)2)
+
+/* Prototype: */
+
+INT16 TF_PollDrive( THW_PTR thw, /* Target Drive */
+ DBLK_PTR vcb, /* Pointer to ALLOCATED DBLK */
+ FSYS_HAND fsh, /* File System Handle */
+ TPOS_HANDLER ui_tpos, /* Tape Positioning Routine */
+ INT16 msg ) ; /* Input Message */
diff --git a/private/utils/ntbackup/inc/thw.h b/private/utils/ntbackup/inc/thw.h
new file mode 100644
index 000000000..b364fdd38
--- /dev/null
+++ b/private/utils/ntbackup/inc/thw.h
@@ -0,0 +1,80 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+$name$
+.module information
+
+$paths$
+headers\thw.h
+subsystem\TAPE FORMAT\thw.h
+$0$
+
+ Name: thw.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the drive description structure used by the
+ upper layers. A list of these structus is returned on
+ TF_OpenTapeLayer( ).
+
+ Location: BE_PUBLIC
+
+$Header: T:/LOGFILES/THW.H_V 1.4 18 Jan 1993 16:18:28 BobR $
+
+$Log: T:/LOGFILES/THW.H_V $
+ *
+ * Rev 1.4 18 Jan 1993 16:18:28 BobR
+ * Added ESA structure to THW
+ *
+ * Rev 1.3 29 Sep 1992 14:07:10 DON
+ * LOADER - Added Macro to determine whether or not the drive supports a
+ * LOADER device - requires updated 'drvinf.h'.
+ *
+ * Rev 1.2 19 Sep 1991 10:08:02 HUNTER
+ * 8200SX - Added Macro to determine whether or not the drive supports SX
+ * FIND command.
+ *
+ * Rev 1.1 10 May 1991 17:25:40 GREGG
+ * Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:15:46 GREGG
+Initial revision.
+
+ Rev 2.1 08 Oct 1990 15:03:54 HUNTER
+ Added macro for fast file.
+
+ Rev 2.0 21 May 1990 14:19:44 PAT
+ Baseline Maynstream 3.1
+
+$-4$
+**/
+#ifndef THW_STUFF
+#define THW_STUFF
+
+#include <queues.h>
+
+#include "drvinf.h"
+#include "esa.h"
+
+/* $end$ include list */
+
+#define MAX_DRV_NAME 15
+
+typedef struct THW {
+ Q_ELEM link ; /* Defines the linked list */
+ Q_ELEM channel_link ; /* User Configurable Channel links */
+ BOOLEAN status_changed ; /* Has the Status Changed */
+ UINT32 drv_status ; /* Current drive status */
+ UINT16 card_no ; /* Index into controller array */
+ DRV_INF drv_info ; /* Information about the drive */
+ CHAR drv_name[MAX_DRV_NAME] ; /* The Drive Name */
+ ESA the ; /* Extended Status Array */
+} THW, *THW_PTR ;
+
+#define SupportFastFile( x ) ( x->drv_info.drv_features & TDI_FAST_NBLK )
+#define SupportSXFastFile( x ) ( x->drv_info.drv_features & TDI_FIND_BLK )
+#define SupportLoaderDevice( x ) ( x->drv_info.drv_features & TDI_LOADER )
+
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/timers.h b/private/utils/ntbackup/inc/timers.h
new file mode 100644
index 000000000..cb68675d9
--- /dev/null
+++ b/private/utils/ntbackup/inc/timers.h
@@ -0,0 +1,66 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: timers.h
+
+ Description: This file contains the definitions, macros, and function
+ prototypes for the timers manager.
+
+ $Log: G:/UI/LOGFILES/TIMERS.H_V $
+
+ Rev 1.4 18 Nov 1992 13:27:06 GLENN
+Increased the speed as an enhancement for the callers.
+
+ Rev 1.3 04 Oct 1992 19:49:48 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.2 12 May 1992 21:23:00 MIKEP
+NT pass 1
+
+ Rev 1.1 12 Dec 1991 17:12:50 DAVEV
+16/32 bit port -2nd pass
+
+ Rev 1.0 20 Nov 1991 19:33:58 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+
+#ifndef _TIMERS_H
+#define _TIMERS_H
+
+#ifndef OS_WIN32
+#define HTIMER WORD
+#else
+#define HTIMER UINT
+#endif
+
+#define INVALID_TIMER_HANDLE 0xFFFF // All timers IN USE bitmask
+
+#define TIMER_BASE 1000
+#define TIMER_FREQUENCY 100
+#define TIMER_RESOLUTION (TIMER_BASE/TIMER_FREQUENCY)
+
+#define ONE_SECOND ( 1 * TIMER_RESOLUTION )
+#define TWO_SECONDS ( 2 * TIMER_RESOLUTION )
+#define THREE_SECONDS ( 3 * TIMER_RESOLUTION )
+#define FOUR_SECONDS ( 4 * TIMER_RESOLUTION )
+#define FIVE_SECONDS ( 5 * TIMER_RESOLUTION )
+#define SIX_SECONDS ( 6 * TIMER_RESOLUTION )
+#define SEVEN_SECONDS ( 7 * TIMER_RESOLUTION )
+#define EIGHT_SECONDS ( 8 * TIMER_RESOLUTION )
+#define NINE_SECONDS ( 9 * TIMER_RESOLUTION )
+#define TEN_SECONDS (10 * TIMER_RESOLUTION )
+
+// FUNCTION PROTOTYPES
+
+BOOL WM_InitTimer ( VOID );
+BOOL WM_DeinitTimer ( VOID );
+HTIMER WM_HookTimer ( PF_VOID, INT );
+BOOL WM_UnhookTimer ( HTIMER );
+INT WM_SetTimerFrequency ( HTIMER, INT );
+
+
+#endif
diff --git a/private/utils/ntbackup/inc/tloc.h b/private/utils/ntbackup/inc/tloc.h
new file mode 100644
index 000000000..b9f7e1b4a
--- /dev/null
+++ b/private/utils/ntbackup/inc/tloc.h
@@ -0,0 +1,57 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+$name$
+.module information
+
+$paths$
+headers\tloc.h
+subsystem\TAPE FORMAT\tloc.h
+$0$
+
+ Name: tloc.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the definition for the Tape Location Descriptor.
+
+ Location: BE_PUBLIC
+
+$Header: W:/LOGFILES/TLOC.H_V 1.1 10 May 1991 17:26:58 GREGG $
+
+$Log: W:/LOGFILES/TLOC.H_V $
+ *
+ * Rev 1.1 10 May 1991 17:26:58 GREGG
+ * Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:15:52 GREGG
+Initial revision.
+
+ Rev 2.1 19 Jun 1990 16:05:36 HUNTER
+ Fast File Retrieval additions.
+
+ Rev 2.0 21 May 1990 14:19:50 PAT
+ Baseline Maynstream 3.1
+
+$-4$
+**/
+#ifndef _TLOC_STUFF
+#define _TLOC_STUFF
+
+
+/* $end$ include list */
+
+
+
+typedef struct {
+ INT16 tape_seq ; /* The Tape Sequeunce number */
+ UINT32 pba_vcb ; /* physical block address of the VCB for this set */
+ UINT32 lba_vcb ; /* The LOGICAL BLOCK ADDRESS of the current VCB */
+ UINT32 fmks ; /* number of filemarks */
+ UINT32 lba ; /* logical block address */
+} TLOC, *TLOC_PTR ;
+
+#endif
+
+
+
diff --git a/private/utils/ntbackup/inc/tpos.h b/private/utils/ntbackup/inc/tpos.h
new file mode 100644
index 000000000..67ff3921a
--- /dev/null
+++ b/private/utils/ntbackup/inc/tpos.h
@@ -0,0 +1,189 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+$name$
+.module information
+
+$paths$
+headers\tpos.h
+subsystem\TAPE FORMAT\tpos.h
+$0$
+
+ Name: tpos.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the communication structure between the User
+ interface Tape positioning routine and the the TFL tape
+ positioning unit.
+
+ Location: BE_PUBLIC
+
+$Header: T:/LOGFILES/TPOS.H_V 1.19 30 Nov 1993 19:00:40 GREGG $
+
+$Log: T:/LOGFILES/TPOS.H_V $
+ *
+ * Rev 1.19 30 Nov 1993 19:00:40 GREGG
+ * Added new message TF_SQL_TAPE.
+ *
+ * Rev 1.18 13 Jul 1993 19:04:04 GREGG
+ * Added new TF messages to report future rev and ECC tapes.
+ *
+ * Rev 1.17 19 May 1993 12:48:14 GREGG
+ * Added logic to prevent using tape with same family id to continue a backup.
+ *
+ * Rev 1.16 19 Apr 1993 18:01:54 GREGG
+ * Second in a series of incremental changes to bring the translator in line
+ * with the MTF spec:
+ *
+ * Changes to write version 2 of OTC, and to read both versions.
+ *
+ * Matches: mayn40rd.c 1.55, otc40msc.c 1.19, otc40rd.c 1.23, otc40wt.c 1.23,
+ * makevcb.c 1.15, fsys.h 1.32, fsys_str.h 1.46, tpos.h 1.16,
+ * mayn40.h 1.32, mtf.h 1.3.
+ *
+ * NOTE: There are additional changes to the catalogs needed to save the OTC
+ * version and put it in the tpos structure before loading the OTC
+ * File/Directory Detail. These changes are NOT listed above!
+ *
+ * Rev 1.15 30 Mar 1993 16:19:04 GREGG
+ * Handle Unrecognized Media error (unformatted DC2000).
+ *
+ * Rev 1.14 12 Mar 1993 14:07:30 DON
+ * Added new tape format message, TF_FAST_SEEK_EOD
+ *
+ * Rev 1.13 26 Jan 1993 18:27:22 GREGG
+ * Added Fast Append functionality.
+ *
+ * Rev 1.12 18 Jan 1993 16:18:04 BobR
+ * Added ESA structure to TPOS.
+ *
+ * Rev 1.11 09 Nov 1992 10:49:24 GREGG
+ * Added location of set catalog to tpos structure and defined new TF_ messages.
+ *
+ * Rev 1.10 04 Aug 1992 17:18:14 GREGG
+ * Added define UI_NON_OTC_SCAN.
+ *
+ * Rev 1.9 23 Jul 1992 10:10:00 GREGG
+ * Fixed warning.
+ *
+ * Rev 1.8 13 May 1992 12:32:42 TIMN
+ * Deleted tapename and backup_set_name for TPOS_STRUCT. Not used.
+ *
+ * Rev 1.7 05 Apr 1992 17:43:14 GREGG
+ * ROLLER BLADES - Initial OTC integration.
+ *
+ * Rev 1.6 17 Sep 1991 14:15:26 GREGG
+ * Added TF_MOUNTING message.
+ *
+ * Rev 1.5 24 Jul 1991 11:31:38 DAVIDH
+ * Changed TPOS_HANDLER to UNIT16. (Don)
+ *
+ * Rev 1.4 12 Jun 1991 14:38:08 JOHNW
+ * Added some TF_ msgs.
+ *
+ * Rev 1.3 06 Jun 1991 17:55:10 JOHNW
+ * Moved typedef for TPOS_HANDLER from lis.h to this file.
+ *
+ * Rev 1.2 05 Jun 1991 19:11:40 NED
+ * added TF_NEED_REWIND_FIRST
+ *
+ * Rev 1.1 10 May 1991 17:26:20 GREGG
+ * Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:15:50 GREGG
+Initial revision.
+
+$-4$
+**/
+#ifndef TPOS_JUNK
+#define TPOS_JUNK
+
+#include "tbe_defs.h" /* The Global Defines */
+#include "fsys.h" /* File System Stuff */
+#include "tloc.h"
+#include "esa.h"
+
+/* $end$ include list */
+
+struct TPOS_STRUCT ;
+
+typedef UINT16 ( *TPOS_HANDLER )( UINT16 message, struct TPOS_STRUCT * tpos, BOOLEAN curr_valid_vcb, DBLK_PTR cur_vcb, UINT16 mode ) ;
+
+typedef struct TPOS_STRUCT {
+ INT32 tape_id ; /* Tape ID number */
+ INT16 tape_seq_num ; /* Sequeunce number */
+ INT16 backup_set_num ; /* Set Number */
+ INT16 set_cat_seq_num ; /* Seq num where set catalog starts */
+ INT32 set_cat_pba ; /* PBA of start of set catalog */
+ UINT8 tape_cat_ver ; /* Version of OTC */
+ TLOC tape_loc ; /* Address on Tape */
+ INT16 channel ; /* Channel ID */
+ UINT32 reference ; /* Temp Storage */
+ UINT16 format ; /* Tape Format Type */
+ BOOLEAN write_protect ; /* Is the tape write protected */
+ BOOLEAN encryption_supported ;
+ UINT16 (*TF_PassWordMatch)( CHAR_PTR, DBLK_PTR ) ; /* TFL match the pass word */
+ TPOS_HANDLER UI_TapePosRoutine ; /* The UI entry point */
+ ESA the ; /* Extended Status Array */
+} TPOS, *TPOS_PTR ;
+
+/* The tape format messages */
+
+#define TF_VCB_BOT 0x0001 /* at VCB and at BOT */
+#define TF_VCB_EOD 0x0002 /* at EOD and returning last VCB */
+#define TF_POSITIONED_AT_A_VCB 0x0003 /* at a VCB but not the requested one */
+#define TF_REQUESTED_VCB_FOUND 0x0004 /* found the right VCB */
+#define TF_ACCIDENTAL_VCB 0x0005 /* found a VCB but not the right one */
+#define TF_NO_MORE_DATA 0x0006 /* at EOD */
+#define TF_EMPTY_TAPE 0x0007 /* tape is empty */
+#define TF_AT_EOT 0x0008 /* at EOT */
+#define TF_NO_TAPE_PRESENT 0x0009
+#define TF_INVALID_VCB 0x000a
+#define TF_POSITIONED_FOR_WRITE 0x000b /* response to TPOS_OVERWRITE */
+#define TF_REWINDING 0x000c /* busy with rewind */
+#define TF_SEARCHING 0x000d /* busy with spacing */
+#define TF_ERASING 0x000e /* busy with erasing */
+#define TF_RETENSIONING 0x000f /* busy with retension */
+#define TF_IDLE 0x0010 /* still doing whatever it was */
+#define TF_DRIVE_BUSY 0x0011 /* busy with some other operation */
+#define TF_NEED_NEW_TAPE 0x0012 /* needs a new tape in current drive */
+#define TF_END_CHANNEL 0x0013 /* hit head or tail of drive list */
+#define TF_IDLE_NOBREAK 0x0014
+#define TF_READ_ERROR 0x0015
+#define TF_WRONG_TAPE 0x0016 /* wanted new tape, got wrong one */
+#define TF_NEED_REWIND_FIRST 0x0017 /* have to handle this motion forward */
+#define TF_TAPE_OUT_OF_ORDER 0x0018 /* tapes cannot be read in this order */
+#define TF_SKIPPING_DATA 0x0019 /* busy with skipping data */
+#define TF_MOUNTING 0x001a /* busy mounting the tape */
+#define TF_NO_SM_ON_TAPE 0x001b /* no set map on current tape */
+#define TF_NO_SC_FOR_SET 0x001c /* no set cat for current set */
+#define TF_NO_SM_FOR_FAMILY 0x001d /* no set map for current tape family */
+#define TF_NO_MORE_ENTRIES 0x001e /* end of tape catalog encountered */
+#define TF_END_POSITIONING 0x001f /* stop positioning, but don't abort operation */
+#define TF_FAST_SEEK_EOD 0x0020 /* fast seek to EOD because UI_FAST_APPEND */
+#define TF_UNRECOGNIZED_MEDIA 0x0021 /* DC2000 tape is unformatted or written in unrecognized format */
+#define TF_CONT_TAPE_IN_FAMILY 0x0022 /* Cont backup requested on a tape with the same family id */
+#define TF_FUTURE_REV_MTF 0x0023
+#define TF_MTF_ECC_TAPE 0x0024
+#define TF_SQL_TAPE 0x0025
+
+/* The user interface messages */
+
+#define UI_ACKNOWLEDGED 0x8001 /* acknowledged ACCIDENTAL_VCB */
+#define UI_END_POSITIONING 0x8002 /* enough already */
+#define UI_OVERWRITE 0x8003 /* overwrite set */
+#define UI_BOT 0x8004 /* rewind to BOT */
+#define UI_EOD 0x8005 /* append at EOD */
+#define UI_CONTINUE_POSITIONING 0x8006 /* not at the right one yet */
+#define UI_ABORT_POSITIONING 0x8007 /* quit */
+#define UI_NEW_TAPE_INSERTED 0x8008 /* we got a new tape */
+#define UI_NEW_POSITION_REQUESTED 0x8009 /* destination position has changed */
+#define UI_SEARCH_CHANNEL 0x800a
+#define UI_NEXT_DRIVE 0x800b
+#define UI_PREVIOUS_DRIVE 0x800c
+#define UI_HAPPY_ABORT 0x800d
+#define UI_BEGINNING_OF_CHANNEL 0x800e
+#define UI_FAST_APPEND 0x800f
+
+#endif
diff --git a/private/utils/ntbackup/inc/translat.h b/private/utils/ntbackup/inc/translat.h
new file mode 100644
index 000000000..3767cc742
--- /dev/null
+++ b/private/utils/ntbackup/inc/translat.h
@@ -0,0 +1,176 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: translat.h
+
+ Date Updated: $./FDT$ $./FTM$
+ 7/21/1989 14:4:121
+
+ Description: Contains the entry points to Translators.
+
+
+ $Log: T:/LOGFILES/TRANSLAT.H_V $
+ *
+ * Rev 1.22 17 Jul 1993 17:56:52 GREGG
+ * Changed write translator functions to return INT16 TFLE_xxx errors instead
+ * of BOOLEAN TRUE/FALSE. Files changed:
+ * MTF10WDB.C 1.23, TRANSLAT.H 1.22, F40PROTO.H 1.30, FMTENG.H 1.23,
+ * TRANSLAT.C 1.43, TFWRITE.C 1.68, MTF10WT.C 1.18
+ *
+ * Rev 1.21 22 Jun 1993 10:53:28 GREGG
+ * Added API to change the catalog directory path.
+ *
+ * Rev 1.20 09 Mar 1993 18:13:58 GREGG
+ * Initial changes for new stream and EOM processing.
+ *
+ * Rev 1.19 26 Jan 1993 01:30:44 GREGG
+ * Added Fast Append functionality.
+ *
+ * Rev 1.18 09 Nov 1992 10:49:02 GREGG
+ * Added tape catalog entry points.
+ *
+ * Rev 1.17 03 Nov 1992 09:26:18 HUNTER
+ * Added prototype for end data stream.
+ *
+ * Rev 1.16 22 Oct 1992 10:54:56 HUNTER
+ * Changes for new streams
+ *
+ * Rev 1.15 22 Sep 1992 09:15:32 GREGG
+ * Initial changes to handle physical block sizes greater than 1K.
+ *
+ * Rev 1.14 17 Aug 1992 09:09:00 GREGG
+ * Changes to deal with block sizeing scheme.
+ *
+ * Rev 1.13 21 May 1992 16:31:14 GREGG
+ * Changed protos for GetCurrentVCB, RD_TranslateDBLK and DetBlockType. Added proto for StartRead.
+ *
+ * Rev 1.12 29 Apr 1992 13:10:48 GREGG
+ * ROLLER BLADES - Added prototype for DetBlockType.
+ *
+ * Rev 1.11 25 Mar 1992 18:29:24 GREGG
+ * ROLLER BLADES - Added prototype for SizeForTapeEomBlk().
+ *
+ * Rev 1.10 11 Feb 1992 17:10:14 NED
+ * changed types of parameters in buffman interface
+ *
+ * Rev 1.9 04 Feb 1992 20:59:00 NED
+ * Changes to Buffer Management translator hooks.
+ *
+ * Rev 1.8 16 Jan 1992 18:37:42 NED
+ * Skateboard: buffer manager changes
+ *
+ * Rev 1.7 02 Jan 1992 15:06:40 NED
+ * Buffer Manager/UTF translator integration.
+ *
+ * Rev 1.6 10 Dec 1991 16:40:10 GREGG
+ * SKATEBOARD - New Buf. Mgr. - Initial integration.
+ *
+ * Rev 1.5 18 Nov 1991 20:03:40 GREGG
+ * Added BOOLEAN abort parameter to WT_EndSet.
+ *
+ * Rev 1.4 09 Nov 1991 10:44:44 HUNTER
+ * VBLK - Changes for Variable length block.
+ *
+ * Rev 1.3 17 Sep 1991 13:55:32 GREGG
+ * Changed prototype for SetupFormatEnv to return INT16.
+ *
+ * Rev 1.2 03 Jun 1991 10:31:22 NED
+ * Changed declarations of FreeFormatEnv()
+ *
+ * Rev 1.1 10 May 1991 17:09:16 GREGG
+ * Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:13:02 GREGG
+Initial revision.
+
+**/
+
+#ifndef _TRANSLATOR_ENT
+#define _TRANSLATOR_ENT
+
+#include "buffman.h"
+#include "channel.h"
+
+/* routines in translat.c */
+
+UINT16 DetermineFormat( VOID_PTR, UINT32 ) ; /* returns format */
+INT16 SetupFormatEnv( CHANNEL_PTR ) ;
+VOID FreeFormatEnv( UINT16_PTR, VOID_PTR * ) ;
+INT16 MoveToVCB( CHANNEL_PTR, INT16, BOOLEAN_PTR, BOOLEAN ) ;
+INT16 SeekEOD( CHANNEL_PTR ) ;
+INT16 NewTape( CHANNEL_PTR, BOOLEAN_PTR ) ;
+INT16 GetCurrentVCB( CHANNEL_PTR, BUF_PTR ) ;
+BOOLEAN VerifyVCB( CHANNEL_PTR, BUF_PTR ) ;
+INT16 StartRead( CHANNEL_PTR channel ) ;
+
+BOOLEAN RD_ReTranslateDBLK( CHANNEL_PTR, BUF_PTR ) ;
+BOOLEAN RD_ContinuationTape( CHANNEL_PTR, BUF_PTR ) ;
+
+/* buffer manager type stuff */
+
+VOID TF_GetVCBBufferRequirements(
+ BUF_REQ_PTR reqs, /* O - destination structure */
+ Q_ELEM_PTR drive_list, /* I - master drive list */
+ UINT16 suggested_buff_size ) ; /* I - size from config */
+
+VOID TF_GetPreferredBufferSpace(
+ Q_ELEM_PTR drive_list, /* I - master drive list */
+ UINT16 suggested_number_of_buffers, /* I -- from config */
+ UINT32 suggested_buffer_size, /* I -- from config */
+ UINT32_PTR preferred_memory ) ; /* O - preferred total memory size */
+
+VOID TF_ReadBufferHook( CHANNEL_PTR, BUF_PTR ) ;
+
+/* these return block types */
+INT16 RD_TranslateDBLK( CHANNEL_PTR, BUF_PTR, UINT16_PTR ) ;
+INT16 DetBlockType( CHANNEL_PTR, BUF_PTR, UINT16_PTR ) ;
+INT16 RD_Exception( CHANNEL_PTR, INT16, UINT16_PTR ) ;
+
+INT16 WT_WriteInit( CHANNEL_PTR, UINT16, BUF_PTR ) ;
+INT16 WT_TranslateDBLK( CHANNEL_PTR, BUF_PTR, UINT16_PTR ) ;
+
+/* Stream Header processing functions */
+
+#define NEED_NEW_BUFFER 1
+
+INT16 WT_NewDataStream( CHANNEL_PTR, BUF_PTR, STREAM_INFO_PTR ) ;
+INT16 WT_EndData( CHANNEL_PTR, BUF_PTR ) ;
+INT16 WT_ContVarStream( CHANNEL_PTR, BUF_PTR ) ;
+VOID WT_EndVarStream( CHANNEL_PTR, BUF_PTR, UINT16 ) ;
+
+VOID WT_EOSPadBlk( CHANNEL_PTR ) ;
+INT16 WT_EndSet( CHANNEL_PTR, BOOLEAN ) ;
+INT16 WT_EndTape( CHANNEL_PTR ) ;
+INT16 WT_ContinueSet( CHANNEL_PTR ) ;
+
+VOID WT_ParseWrittenBuffer( CHANNEL_PTR, BUF_PTR, UINT16 ) ;
+
+/* these two take the format id as their first argument */
+
+UINT16 SizeofTapeBlock( UINT16, VOID_PTR ) ;
+
+#define MinSizeForTapeBlk( fmt ) lw_fmtdescr[ ( fmt ) ].min_size_for_tblk
+#define MinSizeForStream( fmt ) lw_fmtdescr[ ( fmt ) ].min_size_for_stream
+
+/* Tape Based Catalog APIs */
+
+INT LoadSetMap( CHANNEL_PTR channel, BOOLEAN_PTR complete, BOOLEAN get_best ) ;
+INT LoadSetCat( CHANNEL_PTR channel ) ;
+
+INT GetNextSMEntry( CHANNEL_PTR channel ) ;
+INT GetNextSCEntry( CHANNEL_PTR channel ) ;
+
+VOID CloseTapeCatalogs( INT16 cur_fmt, VOID_PTR env_ptr ) ;
+
+#define UNKNOWN_FORMAT 0xFFFF
+
+#define BT_MDB 256
+
+/* Return Codes for Exception Actions */
+#define FMT_EXC_EOS 0x01
+#define FMT_EXC_EOM 0x02
+#define FMT_EXC_IGNORE 0x03
+#define FMT_EXC_HOSED 0xff
+
+#endif
diff --git a/private/utils/ntbackup/inc/transprt.h b/private/utils/ntbackup/inc/transprt.h
new file mode 100644
index 000000000..170955edd
--- /dev/null
+++ b/private/utils/ntbackup/inc/transprt.h
@@ -0,0 +1,74 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: transprt.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the prototypes for the stupid translators
+
+ Location:
+
+
+ $Log: G:/LOGFILES/TRANSPRT.H_V $
+ *
+ * Rev 1.5 17 Mar 1993 15:32:32 TERRI
+ * Added Prototype include file for Sytos Plus.
+ *
+ * Rev 1.4 24 Jul 1992 13:54:52 GREGG
+ * Defined out inclusion of prototype headers for unsupported translators.
+ *
+ * Rev 1.3 25 Mar 1992 20:45:04 GREGG
+ * ROLLER BLADES - Included f40proto.h.
+ *
+ * Rev 1.2 06 Jan 1992 17:28:58 ZEIR
+ * Added UTF support.
+ *
+ * Rev 1.1 10 May 1991 14:24:28 GREGG
+ * Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:17:44 GREGG
+Initial revision.
+
+**/
+/* $end$ include list */
+
+
+#ifndef _TRANS_PROTOS
+#define _TRANS_PROTOS
+
+#ifdef MY40_TRANS
+#include "f40proto.h"
+#endif
+
+#ifdef MY31_TRANS
+#include "f31proto.h"
+#endif
+
+#ifdef MY30_TRANS
+#include "f30proto.h"
+#endif
+
+#ifdef MY25_TRANS
+#include "f25proto.h"
+#endif
+
+#ifdef QS19_TRANS
+#include "fqproto.h"
+#endif
+
+#ifdef SY31_TRANS
+#include "fsyproto.h"
+#endif
+
+#ifdef SYPL10_TRANS
+#include "syplpto.h"
+#endif
+
+#ifdef UTF_TRANS
+#include "utfproto.h"
+#endif
+
+#endif
+
diff --git a/private/utils/ntbackup/inc/transutl.h b/private/utils/ntbackup/inc/transutl.h
new file mode 100644
index 000000000..49cc2b749
--- /dev/null
+++ b/private/utils/ntbackup/inc/transutl.h
@@ -0,0 +1,69 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: util.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+
+ $Log: T:/LOGFILES/TRANSUTL.H_V $
+ *
+ * Rev 1.5 22 Sep 1992 09:01:32 GREGG
+ * Initial changes to handle physical block sizes greater than 1K.
+ *
+ * Rev 1.4 14 Aug 1992 16:22:32 GREGG
+ * Added prototype for AllocChannelTmpBlks.
+ *
+ * Rev 1.3 24 Jul 1992 14:36:46 NED
+ * Incorporated Skateboard and BigWheel changed into Graceful Red code,
+ * including MTF4.0 translator support, adding 3.1 file-system structures
+ * support to the 3.1 translator, additions to GOS to support non-4.0 translators.
+ *
+ * Rev 1.2 25 Mar 1992 20:47:24 GREGG
+ * ROLLER BLADES - Changed prototype for ProcessDataFilter.
+ *
+ * Rev 1.1 10 May 1991 14:25:26 GREGG
+ * Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:17:46 GREGG
+Initial revision.
+
+**/
+
+#ifndef FMT_UTILS
+#define FMT_UTILS
+
+/* A Useful Macro */
+
+/* Size required to pad the size x to the boundary bnd */
+#define PadToBoundary( x, bnd ) ( ( (bnd) - ( (x) % (bnd) ) ) % (bnd) )
+
+/* Define constants used in block conversion */
+#define NO_MORE_CNV 0
+#define CNV 0x8000
+
+#define SIZE_WORD 0x4000
+#define SIZE_DWORD 0x2000
+#define SIZE_DATE_TIME 0x1000
+#define MASK_UNUSED ( CNV | SIZE_WORD | SIZE_DWORD | SIZE_DATE_TIME )
+
+/* Prototypes for the Translate Utilities */
+
+UINT16 CalcChecksum( UINT16_PTR start_ptr, UINT16 length ) ;
+VOID SwapBlock( UINT16_PTR fmt_blk, UINT8_PTR data_blk ) ;
+VOID ProcessDataFilter( CHANNEL_PTR, UINT16 ) ;
+UINT16 F25_Chksm( CHAR_PTR ptr, UINT16 siz ) ;
+INT16 AllocChannelTmpBlks( CHANNEL_PTR channel, UINT size ) ;
+
+/* string replacement routines */
+INT16 cstrcmp( UINT8_PTR, UINT8_PTR );
+UINT8_PTR cstrcpy( UINT8_PTR, UINT8_PTR );
+UINT16 cstrlen( UINT8_PTR );
+UINT8_PTR cstrncat( UINT8_PTR, UINT8_PTR, UINT16 );
+INT16 cstrncmp( UINT8_PTR, UINT8_PTR, UINT16 );
+UINT8_PTR cstrncpy( UINT8_PTR, UINT8_PTR, UINT16 );
+
+#endif
diff --git a/private/utils/ntbackup/inc/tsearch.h b/private/utils/ntbackup/inc/tsearch.h
new file mode 100644
index 000000000..3d4f06224
--- /dev/null
+++ b/private/utils/ntbackup/inc/tsearch.h
@@ -0,0 +1,44 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: tsearch.h
+
+ Description: include file for the tsearch.dlg dialog
+
+
+ $Log: G:/UI/LOGFILES/TSEARCH.H_V $
+
+ Rev 1.5 27 Apr 1993 18:04:04 KEVINS
+Enhanced catalog searching with password, subdirectories, and max number of hits.
+
+ Rev 1.4 04 Oct 1992 19:49:48 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.3 06 Apr 1992 09:53:40 CHUCKB
+Added define for translation.
+
+ Rev 1.2 03 Apr 1992 13:56:42 CARLS
+added translate defines
+
+ Rev 1.0 20 Nov 1991 19:34:42 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_SEARCHTAPE 24
+#else
+#include "dlg_ids.h"
+#endif
+
+#define IDD_ST_TAPE 0x00C9
+#define IDD_ST_PATH 0x006B
+#define IDD_ST_FILE 0x006C
+#define IDD_ST_PROMPT_PASSW 0x006E
+#define IDD_ST_MAX_RESULTS 0x006D
+#define IDD_ST_SPINNERBOX 0x0076
+#define IDD_ST_SKIP_PASSW_PROT_TAPES 0x001A
+#define IDD_ST_SRCH_SUBDIRS 0x001C
+#define IDD_ST_SRCH_PASSW_PROT_TAPES 0x001D
diff --git a/private/utils/ntbackup/inc/unic_io.h b/private/utils/ntbackup/inc/unic_io.h
new file mode 100644
index 000000000..ef1f49218
--- /dev/null
+++ b/private/utils/ntbackup/inc/unic_io.h
@@ -0,0 +1,883 @@
+/***
+*unic_io.h - Function prototypes for unicode-supporting io functions
+*
+* Copyright (c) 1985-1991, Microsoft Corporation. All rights reserved.
+* Copyright (c) 1992, Archive Software Division. All rights reserved.
+*
+*Purpose:
+* This file contains the funtion prototypes for unicode versions of various
+* MS C library file io routines. Each of these functions works identially
+* to thier MS library counterpart with the only exception that all char
+* and char * parameters and return values have been changed to wchar_t
+* and wchar_t *, respectively, except as otherwise noted.
+*
+* Also, if the UNICODE flag is set for transparent unicode support,
+* then for each of the function prototyped in this file, a mapping
+* macro is defined to map the standard ascii io routines to these
+* unicode versions. Eg.:
+*
+* #define fopen fopenW
+*
+* The following routines are prototyped in this file:
+*
+* _fsopenW
+* fopenW
+* _openfileW
+* _openW
+* _sopenW
+* _tempnamW
+* _chdir
+* _accessW
+* removeW
+* _unlinkW
+* _getcwdW
+* _getdcwdW
+* _getdcwdW_lk
+* _chmodW
+* _mkdirW
+* fgetsW
+* renameW
+* OpenFileW
+*
+*Revision History:
+* 10-12-92 DVC Archive Sofware Division. Created this file.
+*
+ $Log: N:/LOGFILES/UNIC_IO.H_V $
+
+ Rev 1.10 11 Jan 1993 08:48:48 STEVEN
+fix bugs from microsoft
+
+ Rev 1.9 21 Dec 1992 12:28:22 DAVEV
+Enabled for Unicode - IT WORKS!!
+
+ Rev 1.8 14 Dec 1992 12:37:22 DAVEV
+Enabled for Unicode compile
+
+ Rev 1.7 15 Nov 1992 17:42:46 MIKEP
+fixes
+
+ Rev 1.0 15 Nov 1992 17:42:36 MIKEP
+fixes
+
+ Rev 1.6 13 Nov 1992 16:36:14 DAVEV
+fixes, remove dependency on MS internal headers
+
+ Rev 1.5 12 Nov 1992 12:17:16 DAVEV
+added mapping macro for OpenFile
+
+ Rev 1.4 12 Nov 1992 12:10:02 DAVEV
+only define OpenFileW if WINBASE.H is included
+
+ Rev 1.3 12 Nov 1992 10:13:10 DAVEV
+added OpenFileW
+
+ Rev 1.2 12 Nov 1992 09:58:14 DAVEV
+added removeW
+
+ Rev 1.1 11 Nov 1992 18:18:00 DAVEV
+UNICODE changes
+
+ Rev 1.0 16 Oct 1992 16:33:26 DAVEV
+Initial revision.
+
+*******************************************************************************/
+
+#ifndef UNIC_IO_INCL
+#define UNIC_IO_INCL
+
+#ifndef _CRTAPI1
+#define _CRTAPI1
+#endif
+
+#ifndef _CRTAPI2
+#define _CRTAPI2
+#endif
+
+#if !defined( WCHAR_T_DEFINED ) && !defined( OS_WIN32 )
+typedef unsigned short wchar_t;
+#define WCHAR_T_DEFINED
+#endif
+
+/***
+*FILE *_fsopenW(file, mode, shflag) - open a file
+*
+*Purpose:
+* Opens the file specified as a stream. mode determines file mode:
+* "r": read "w": write "a": append
+* "r+": read/write "w+": open empty for read/write
+* "a+": read/append
+* Append "t" or "b" for text and binary mode. shflag determines the
+* sharing mode. Values are the same as for sopen().
+*
+*Entry:
+* wchar_t *file - file name to open
+* wchar_t *mode - mode of file access
+*
+*Exit:
+* returns pointer to stream
+* returns NULL if fails
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#ifdef _INC_STDIO
+
+FILE * _CRTAPI1 _fsopenW (
+ const wchar_t *file,
+ const wchar_t *mode
+#ifndef _POSIX_
+ ,int shflag
+#endif
+ );
+
+#endif //_INC_STDIO
+
+/***
+*FILE *fopenW(file, mode) - open a file
+*
+*Purpose:
+* Opens the file specified as a stream. mode determines file mode:
+* "r": read "w": write "a": append
+* "r+": read/write "w+": open empty for read/write
+* "a+": read/append
+* Append "t" or "b" for text and binary mode
+*
+*Entry:
+* wchar_t *file - file name to open
+* wchar_t *mode - mode of file access
+*
+*Exit:
+* returns pointer to stream
+* returns NULL if fails
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#ifdef _INC_STDIO
+FILE * UNI_fopen( wchar_t *fname, unsigned long flags ) ;
+#endif // _INC_STDIO
+
+/***
+*FILE *_openfileW(filename, mode, shflag, stream) - open a file with string
+* mode and file sharing flag.
+*
+*Purpose:
+* parse the string, looking for exactly one of {rwa}, at most one '+',
+* at most one of {tb} and at most one of {cn}. pass the result on as
+* an int containing flags of what was found. open a file with proper
+* mode if permissions allow. buffer not allocated until first i/o call
+* is issued. intended for use inside library only
+*
+*Entry:
+* wchar_t *filename - file to open
+* wchar_t *mode - mode to use (see above)
+* int shflag - file sharing flag
+* FILE *stream - stream to use for file
+*
+*Exit:
+* set stream's fields, and causes system file management by system calls
+* returns stream or NULL if fails
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#ifdef _INC_STDIO
+
+FILE * _CRTAPI1 _openfileW (
+ const wchar_t *filename,
+ const wchar_t *mode,
+#ifndef _POSIX_
+ int shflag,
+#endif
+ FILE *str
+ );
+#endif // _INC_STDIO
+
+/***
+*int _openW(path, flag, pmode) - open or create a file
+*
+*Purpose:
+* Opens the file and prepares for subsequent reading or writing.
+* the flag argument specifies how to open the file:
+* _O_APPEND - reposition file ptr to end before every write
+* _O_BINARY - open in binary mode
+* _O_CREAT - create a new file* no effect if file already exists
+* _O_EXCL - return error if file exists, only use with O_CREAT
+* _O_RDONLY - open for reading only
+* _O_RDWR - open for reading and writing
+* _O_TEXT - open in text mode
+* _O_TRUNC - open and truncate to 0 length (must have write permission)
+* _O_WRONLY - open for writing only
+* _O_NOINHERIT -handle will not be inherited by child processes.
+* exactly one of _O_RDONLY, _O_WRONLY, _O_RDWR must be given
+*
+* The pmode argument is only required when _O_CREAT is specified. Its
+* flag settings:
+* _S_IWRITE - writing permitted
+* _S_IREAD - reading permitted
+* _S_IREAD | _S_IWRITE - both reading and writing permitted
+* The current file-permission maks is applied to pmode before
+* setting the permission (see umask).
+*
+* The oflag and mode parameter have different meanings under DOS. See
+* the A_xxx attributes in msdos.inc
+*
+* Note, the _creat() function also uses this function but setting up the
+* correct arguments and calling _openW(). _creat() sets the __creat_flag
+* to 1 prior to calling _openW() so _openW() can return correctly. _openW()
+* returns the file handle in eax in this case.
+*
+*Entry:
+* wchar_t *path - file name
+* int flag - flags for _openW()
+* int pmode - permission mode for new files
+*
+*Exit:
+* returns file handle of open file if successful
+* returns -1 (and sets errno) if fails
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int _CRTAPI2 _openW (
+ const wchar_t *path,
+ int oflag,
+ ...
+ );
+
+/***
+*int _sopenW(path, oflag, shflag, pmode) - opne a file with sharing
+*
+*Purpose:
+* Opens the file with possible file sharing.
+* shflag defines the sharing flags:
+* _SH_COMPAT - set compatability mode
+* _SH_DENYRW - deny read and write access to the file
+* _SH_DENYWR - deny write access to the file
+* _SH_DENYRD - deny read access to the file
+* _SH_DENYNO - permit read and write access
+*
+* Other flags are the same as _openW().
+*
+* SOPEN is the routine used when file sharing is desired.
+*
+*Entry:
+* wchar_t *path - file to open
+* int oflag - open flag
+* int shflag - sharing flag
+* int pmode - permission mode (needed only when creating file)
+*
+*Exit:
+* returns file handle for the opened file
+* returns -1 and sets errno if fails.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int _CRTAPI2 _sopenW (
+ const wchar_t *path,
+ int oflag,
+ int shflag,
+ ...
+ );
+
+
+/***
+*wchar_t *_tempnamW(dir, prefix) - create unique file name using Unicode strings
+*
+*Purpose:
+* Create a file name that is unique in the specified directory.
+* The semantics of directory specification is as follows:
+* Use the directory specified by the TMP environment variable
+* if that exists, else use the dir argument if non-NULL, else
+* use _P_tmpdir if that directory exists, else use the current
+* working directory), else return NULL.
+*
+*Entry:
+* wchar_t *dir - directory to be used for temp file if TMP env var
+* not set
+* wchar_t *prefix - user provided prefix for temp file name
+*
+*Exit:
+* returns ptr to constructed file name if successful
+* returns NULL if unsuccessful
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+wchar_t * _CRTAPI1 _tempnamW (
+ wchar_t *dir,
+ wchar_t *pfx
+ );
+/***
+*int _chdirW(path) - change current directory
+*
+*Purpose:
+* Changes the current working directory to that given in path.
+*
+*Entry:
+* wchar_t *path - directory to change to
+*
+*Exit:
+* returns 0 if successful,
+* returns -1 and sets errno if unsuccessful
+*
+*Exceptions:
+* This function updates the environment with a MBCS string rather than a
+* unicode string because the C environ[] does not support unicode. This
+* needs to be fixed in the future
+*
+*******************************************************************************/
+
+int _CRTAPI1 _chdirW(
+ const wchar_t *path
+ );
+
+/***
+*int _accessW(path, amode) - check whether file can be accessed under mode
+*
+*Purpose:
+* Checks to see if the specified file exists and can be accessed
+* in the given mode.
+*
+*Entry:
+* wchar_t *path - pathname
+* int amode - access mode
+* (0 = exist only, 2 = write, 4 = read, 6 = read/write)
+*
+*Exit:
+* returns 0 if file has given mode
+* returns -1 and sets errno if file does not have given mode or
+* does not exist
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int _CRTAPI1 _accessW (
+ const wchar_t *path,
+ int amode
+ );
+
+/***
+*int _unlinkW(path) - unlink(delete) the given file
+*
+*Purpose:
+* This version deletes the given file because there are no
+* links under OS/2.
+*
+* NOTE: removeW() is an alternative entry point to the _unlinkW()
+* routine* interface is identical.
+*
+*Entry:
+* wchar_t *path - file to unlink/delete
+*
+*Exit:
+* returns 0 if successful
+* returns -1 and sets errno if unsuccessful
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int _CRTAPI1 removeW (
+ const wchar_t *path
+ );
+
+int _CRTAPI1 _unlinkW (
+ const wchar_t *path
+ );
+
+
+/***
+*wchar_t *_getcwdW(pnbuf, maxlen) - get current working directory of default drive
+*
+*Purpose:
+* _getcwdW gets the current working directory for the user,
+* placing it in the buffer pointed to by pnbuf. It returns
+* the length of the string put in the buffer. If the length
+* of the string exceeds the length of the buffer, maxlen,
+* then NULL is returned. If pnbuf = NULL, maxlen is ignored.
+* An entry point "_getdcwd()" is defined with takes the above
+* parameters, plus a drive number. "_getcwd()" is implemented
+* as a call to "_getcwd()" with the default drive (0).
+*
+* If pnbuf = NULL, maxlen is ignored, and a buffer is automatically
+* allocated using malloc() -- a pointer to which is returned by
+* _getcwd().
+*
+* side effects: no global data is used or affected
+*
+*Entry:
+* wchar_t *pnbuf = pointer to a buffer maintained by the user;
+* int maxlen = character length of the buffer pointed to by pnbuf;
+*
+*Exit:
+* Returns pointer to the buffer containing the c.w.d. name
+* (same as pnbuf if non-NULL; otherwise, malloc is
+* used to allocate a buffer)
+* or NULL and set errno if not sucessfull
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+
+wchar_t * _CRTAPI1 _getcwdW (
+ wchar_t *pnbuf,
+ int maxlen
+ );
+
+/***
+*wchar_t *_getdcwdW(drive, pnbuf, maxlen) - get c.w.d. for given drive
+*
+*Purpose:
+* _getdcwdW gets the current working directory for the user,
+* placing it in the buffer pointed to by pnbuf. It returns
+* the length of the string put in the buffer. If the length
+* of the string exceeds the length of the buffer, maxlen,
+* then NULL is returned. If pnbuf = NULL, maxlen is ignored,
+* and a buffer is automatically allocated using malloc() --
+* a pointer to which is returned by _getdcwdW().
+*
+* side effects: no global data is used or affected
+*
+*Entry:
+* int drive - number of the drive being inquired about
+* 0 = default, 1 = 'a:', 2 = 'b:', etc.
+* wchar_t *pnbuf - pointer to a buffer maintained by the user;
+* int maxlen - length in characters of the buffer pointed to by pnbuf;
+*
+*Exit:
+* Returns pointer to the buffer containing the c.w.d. name
+* (same as pnbuf if non-NULL; otherwise, malloc is
+* used to allocate a buffer)
+* or NULL and set errno if not sucessfull
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+
+wchar_t * _CRTAPI1 _getdcwdW (
+ int drive,
+ wchar_t *pnbuf,
+ int maxlen
+ );
+
+#ifdef MTHREAD
+
+wchar_t * _CRTAPI1 _getdcwdW_lk (
+ int drive,
+ wchar_t *pnbuf,
+ int maxlen
+ );
+
+#else
+
+#define _getdcwdW_lk _getdcwdW
+
+#endif //MTHREAD
+/***
+*int _chmodW(path, mode) - change file mode
+*
+*Purpose:
+* Changes file mode permission setting to that specified in
+* mode. The only XENIX mode bit supported is user write.
+*
+*Entry:
+* wchar_t *path - file name
+* int mode - mode to change to
+*
+*Exit:
+* returns 0 if successful
+* returns -1 and sets errno if not successful
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int _CRTAPI1 _chmodW (
+ const wchar_t *path,
+ int mode
+ );
+
+/***
+*int _mkdirW(path) - make a directory
+*
+*Purpose:
+* creates a new directory with the specified name
+*
+*Entry:
+* wchar_t *path - name of new directory
+*
+*Exit:
+* returns 0 if successful
+* returns -1 and sets errno if unsuccessful
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int _CRTAPI1 _mkdirW (
+ const wchar_t *path
+ );
+
+/***
+*long atolW(wchar_t *nptr) - Convert a unicode string to long
+*
+*Purpose:
+* Converts Unicode string pointed to by nptr to binary.
+* Overflow is not detected.
+* Only works with Latin digits
+*
+*Entry:
+* nptr = ptr to string to convert
+*
+*Exit:
+* return long int value of the string
+*
+*Exceptions:
+* None - overflow is not detected.
+*
+*******************************************************************************/
+
+long _CRTAPI1 atolW(
+ const wchar_t *nptr
+ );
+
+/***
+*int atoiW(wchar_t *nptr) - Convert a Unicode string to long
+*
+*Purpose:
+* Converts Unicode string pointed to by nptr to binary.
+* Overflow is not detected. Because of this, we can just use
+* atolW().
+*
+*Entry:
+* nptr = ptr to string to convert
+*
+*Exit:
+* return int value of the string
+*
+*Exceptions:
+* None - overflow is not detected.
+*
+*******************************************************************************/
+
+int _CRTAPI1 atoiW(
+ const wchar_t *nptr
+ );
+
+/***
+*wchar_t *fgetsW(string, count, stream) - input string from a stream
+*
+*Purpose:
+* get a string, up to count-1 chars or '\n', whichever comes first,
+* append '\0' and put the whole thing into string. the '\n' IS included
+* in the string. if count<=1 no input is requested. if WEOF is found
+* immediately, return NULL. if WEOF found after chars read, let WEOF
+* finish the string as '\n' would.
+*
+*Entry:
+* wchar_t *string - pointer to place to store string
+* int count - max characters to place at string (include \0)
+* FILE *stream - stream to read from
+*
+*Exit:
+* returns string with text read from file in it.
+* if count <= 0 return NULL
+* if count == 1 put null string in string
+* returns NULL if error or end-of-file found immediately
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#ifdef _INC_STDIO
+
+wchar_t * _CRTAPI1 fgetsW (
+ wchar_t *string,
+ int count,
+ FILE *str
+ );
+
+#endif // _INC_STDIO
+
+/***
+*int renameW(oldname, newname) - rename a file
+*
+*Purpose:
+* Renames a file to a new name -- no file with new name must
+* currently exist.
+*
+*Entry:
+* wchar_t *oldname - name of file to rename
+* wchar_t *newname - new name for file
+*
+*Exit:
+* returns 0 if successful
+* returns not 0 and sets errno if not successful
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int _CRTAPI1 renameW (
+ const wchar_t *oldname,
+ const wchar_t *newname
+ );
+
+/***
+*HFILE OpenFileW ( lpFileName, lpReOpenBuff, uStyle )
+*
+*Purpose:
+* Kludged Unicode version of OpenFile. Do not use unless necessary.
+*
+*Entry:
+* LPCWSTR lpFileName - name of file to open
+* LPOPSTRUCT lpReOpenBuff - open file info buffer
+* UINT uStyle - style flags - See docs on OpenFile for more info
+*
+*Exit:
+* returns NULL if not successful. Use GetLastError for error code.
+* returns HFILE file handle on success.
+*
+*Exceptions:
+*
+* Will not handle all unicode characters properly due to mapping
+* problems between ANSI multibyte chars and Unicode. Use CreateFile,
+* fopenW(), etc., instead of this function if at all possible.
+*
+*******************************************************************************/
+#ifdef _WINBASE_ //already integrated into version control!!
+HFILE WINAPI OpenFileW(
+ LPCWSTR lpFileName,
+ LPOFSTRUCT lpReOpenBuff,
+ UINT uStyle
+ );
+#endif
+
+/***
+*char *_itoax, *_ltoax, *_ultoax(val, buf, radix) - convert binary int to Unicode
+* string
+*
+*Purpose:
+* Converts an int to a character string.
+*
+*Entry:
+* val - number to be converted (int, long or unsigned long)
+* int radix - base to convert into
+* wchar_t *buf - ptr to buffer to place result
+*
+*Exit:
+* fills in space pointed to by buf with string result
+* returns a pointer to this buffer
+*
+*Exceptions:
+*
+*******************************************************************************/
+wchar_t * _CRTAPI1 _itoaW (
+ int val,
+ wchar_t *buf,
+ int radix
+ );
+
+wchar_t * _CRTAPI1 _ltoaW (
+ long val,
+ wchar_t *buf,
+ int radix
+ );
+
+wchar_t * _CRTAPI1 _ultoaW (
+ unsigned long val,
+ wchar_t *buf,
+ int radix
+ );
+
+/*********************************************************************/
+/* TRANSPARENT UNICODE I/O FUNCTION MAPPINGS */
+/*********************************************************************/
+
+#if defined( UNICODE ) && !defined( NO_STRING_REMAPPING )
+
+#define atoi atoiW
+#define atol atolW
+#define _fsopen _fsopenW
+#define fopen fopenW
+#define fgets fgetsW
+#define _openfile _openfileW
+#define _open _openW
+#define _sopen _sopenW
+#define _tempnam _tempnamW
+#define _chdir _chdirW
+#define _access _accessW
+#define remove removeW
+#define _unlink _unlinkW
+#define _getcwd _getcwdW
+#define _getdcwd _getdcwdW
+#define _getdcwd_lk _getdcwdW_lk
+#define _chmod _chmodW
+#define _mkdir _mkdirW
+#define rename renameW
+#define OpenFile OpenFileW // already integrated to vcs
+#define _itoa _itoaW
+#define _ltoa _ltoaW
+#define _ultoa _ultoaW
+
+#define openfile _openfileW
+#define open _openW
+#define sopen _sopenW
+#define tempnam _tempnamW
+#define chdir _chdirW
+#define access _accessW
+#define remove removeW
+#define unlink _unlinkW
+#define getcwd _getcwdW
+#define getdcwd _getdcwdW
+#define getdcwd_lk _getdcwdW_lk
+#define chmod _chmodW
+#define mkdir _mkdirW
+#define itoa _itoaW
+#define ltoa _ltoaW
+#define ultoa _ultoaW
+
+#endif // UNICODE
+
+/*********************************************************************/
+/* DEFINES FROM MS INTERNAL HEADERS WHICH WE REQUIRE */
+/*********************************************************************/
+
+#ifdef INCL_MS_INTERNALS
+
+// from MS's internal version of IO.H....
+
+#ifdef MTHREAD /* _MTHREAD_ONLY */
+int _CRTAPI1 _chsize_lk(int,long); /* _MTHREAD_ONLY */
+int _CRTAPI1 _close_lk(int); /* _MTHREAD_ONLY */
+long _CRTAPI1 _lseek_lk(int, long, int); /* _MTHREAD_ONLY */
+int _CRTAPI1 _setmode_lk(int, int); /* _MTHREAD_ONLY */
+int _CRTAPI1 _read_lk(int, void *, unsigned int); /* _MTHREAD_ONLY */
+int _CRTAPI1 _write_lk(int, const void *, unsigned int); /* _MTHREAD_ONLY */
+#else /* not MTHREAD */ /* _MTHREAD_ONLY */
+#define _chsize_lk(fh,size) _chsize(fh,size) /* _MTHREAD_ONLY */
+#define _close_lk(fh) _close(fh) /* _MTHREAD_ONLY */
+#define _lseek_lk(fh,offset,origin) _lseek(fh,offset,origin) /* _MTHREAD_ONLY */
+#define _setmode_lk(fh,mode) _setmode(fh,mode) /* _MTHREAD_ONLY */
+#define _read_lk(fh,buff,count) _read(fh,buff,count) /* _MTHREAD_ONLY */
+#define _write_lk(fh,buff,count) _write(fh,buff,count) /* _MTHREAD_ONLY */
+#endif /* _MTHREAD_ONLY */
+
+// from MS's internal version of STDIO.H...
+#define _getc_lk(_stream) (--(_stream)->_cnt >= 0 ? 0xff & *(_stream)->_ptr++ : _filbuf(_stream)) /* _MTHREAD_ONLY */
+
+/// from MS's internal version of STDLIB.H
+
+#ifdef MTHREAD /* _MTHREAD_ONLY */
+char * _CRTAPI1 _getenv_lk(const char *); /* _MTHREAD_ONLY */
+int _CRTAPI1 _putenv_lk(const char *); /* _MTHREAD_ONLY */
+#else /* _MTHREAD_ONLY */
+#define _getenv_lk(envvar) getenv(envvar) /* _MTHREAD_ONLY */
+#define _putenv_lk(envvar) _putenv(envvar) /* _MTHREAD_ONLY */
+#endif
+
+// from OS2DLL.H...
+#define _ENV_LOCK 12 /* lock for environment variables */
+#define _TMPNAM_LOCK 3 /* lock global tempnam variables */
+
+#ifdef MTHREAD
+void _CRTAPI2 _lock(int);
+void _CRTAPI2 _unlock_stream(int);
+#define _STREAM_LOCKS 29 /* Table of stream locks */
+#define _lock_str(s) _lock(s+_STREAM_LOCKS)
+#define _unlock_str(s) _unlock_stream(s)
+#define _mlock(l) _lock(l)
+#define _munlock(l) _unlock(l)
+#define _lock_fh(fh) _lock(fh+_FH_LOCKS)
+#define _unlock_fh(fh) _unlock(fh+_FH_LOCKS)
+#else
+#define _lock_str(s)
+#define _unlock_str(s)
+#define _mlock(l)
+#define _munlock(l)
+#define _lock_fh(fh)
+#define _unlock_fh(fh)
+#endif
+
+
+// from FILE2.H...
+#define _IOCOMMIT 0x4000
+
+// from INTERNAL.H...
+#ifdef _DLL
+#define _commode (*_commode_dll)
+extern int * _commode_dll;
+#else
+#ifdef CRTDLL
+#define _commode _commode_dll
+#endif
+extern int _commode;
+#endif
+extern int _cflush;
+extern int _umaskval; /* the umask value */
+extern char _osfile[];
+extern unsigned int _old_pfxlen;
+extern unsigned int _tempoff;
+extern void _CRTAPI1 _dosmaperr(unsigned long);
+
+#ifdef _INC_STDIO
+FILE * _CRTAPI1 _getstream(void);
+#endif //_INC_STDIO
+
+extern int _CRTAPI1 _ValidDrive(unsigned);
+int _CRTAPI1 _alloc_osfhnd(void);
+int _CRTAPI1 _free_osfhnd(int);
+int _CRTAPI1 _set_osfhnd(int,long);
+
+// from MSDOS.H...
+#define FOPEN 0x01 /* file handle open */
+#define FEOFLAG 0x02 /* end of file has been encountered */
+#define FCRLF 0x04 /* CR-LF across read buffer (in text mode) */
+#define FPIPE 0x08 /* file handle refers to a pipe */
+
+#ifndef _WIN32_
+#define FRDONLY 0x10 /* file handle associated with read only file */
+#endif
+
+#define FAPPEND 0x20 /* file handle opened O_APPEND */
+#define FDEV 0x40 /* file handle refers to device */
+#define FTEXT 0x80 /* file handle is in text mode */
+
+/* DOS errno values for setting __doserrno in C routines */
+
+#define E_ifunc 1 /* invalid function code */
+#define E_nofile 2 /* file not found */
+#define E_nopath 3 /* path not found */
+#define E_toomany 4 /* too many open files */
+#define E_access 5 /* access denied */
+#define E_ihandle 6 /* invalid handle */
+#define E_arena 7 /* arena trashed */
+#define E_nomem 8 /* not enough memory */
+#define E_iblock 9 /* invalid block */
+#define E_badenv 10 /* bad environment */
+#define E_badfmt 11 /* bad format */
+#define E_iaccess 12 /* invalid access code */
+#define E_idata 13 /* invalid data */
+#define E_unknown 14 /* ??? unknown error ??? */
+#define E_idrive 15 /* invalid drive */
+#define E_curdir 16 /* current directory */
+#define E_difdev 17 /* not same device */
+#define E_nomore 18 /* no more files */
+#define E_maxerr2 19 /* unknown error - Version 2.0 */
+#define E_sharerr 32 /* sharing violation */
+#define E_lockerr 33 /* locking violation */
+#define E_maxerr3 34 /* unknown error - Version 3.0 */
+
+#endif // INCL_MS_INTERNALS
+#endif //UNIC_IO_INCL
diff --git a/private/utils/ntbackup/inc/use_sel.h b/private/utils/ntbackup/inc/use_sel.h
new file mode 100644
index 000000000..a7e725c8d
--- /dev/null
+++ b/private/utils/ntbackup/inc/use_sel.h
@@ -0,0 +1,30 @@
+/*******************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+
+ Name: use_sel.h
+
+ Description: include file for the use_sel.dlg dialog
+
+
+ $Log: G:/UI/LOGFILES/USE_SEL.H_V $
+
+ Rev 1.5 04 Oct 1992 19:49:50 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.4 03 Apr 1992 13:58:38 CARLS
+added translate defines
+
+ Rev 1.0 20 Nov 1991 19:34:42 SYSTEM
+Initial revision.
+
+*******************************************************************************/
+
+#ifdef TRANSLATE
+#define IDHELP 100
+#define IDD_SELECTUSE 5
+#else
+#include "dlg_ids.h"
+#endif
+
+#define IDD_SAVE_FLIST 0x006C
diff --git a/private/utils/ntbackup/inc/vlm.h b/private/utils/ntbackup/inc/vlm.h
new file mode 100644
index 000000000..6697bbe0c
--- /dev/null
+++ b/private/utils/ntbackup/inc/vlm.h
@@ -0,0 +1,805 @@
+/************************
+Copyright (c) Maynard, an Archive Company. 1991
+
+ Name: vlm.h
+
+ Description: This file contains the definitions, macros, and function
+ prototypes for the VLM code.
+
+ $Log: G:\UI\LOGFILES\VLM.H_V $
+
+ Rev 1.73.1.1 08 Dec 1993 10:48:32 MikeP
+very deep path support
+
+ Rev 1.73.1.0 01 Dec 1993 14:11:20 mikep
+add SQL recognition support to poll drive
+
+ Rev 1.73 29 Jul 1993 15:02:24 MIKEP
+add sms bit
+
+ Rev 1.72 23 Jul 1993 15:34:32 MIKEP
+
+ Rev 1.71 19 Jul 1993 21:07:20 MIKEP
+
+ Rev 1.70 08 Jun 1993 11:13:34 CARLS
+removed prototype for VLM_GetFirstSSETAttribute
+
+ Rev 1.69 27 May 1993 15:37:40 CARLS
+Added prototype for VLM_GetFirstSSETonTapeAttribute
+called by DO_BACK.C
+
+ Rev 1.68 20 May 1993 17:22:18 KEVINS
+Removed VLM_RefreshDLE. Use VLM_Refresh which already existed.
+
+ Rev 1.67 12 May 1993 17:58:52 KEVINS
+Added VLM_RefreshDLE.
+
+ Rev 1.66 12 May 1993 08:25:26 MIKEP
+Add a tape macro.
+
+ Rev 1.65 03 May 1993 16:12:22 MIKEP
+Put focus on tape that is currently in drive.
+
+ Rev 1.64 02 May 1993 17:37:10 MIKEP
+add call to support catalog data path changing.
+
+ Rev 1.63 01 May 1993 16:27:56 MIKEP
+Fix case support for trees. Add SLM_GetOriginalName() macros. Goes with
+vlm_refr.c and vlm_tree.c
+
+ Rev 1.62 28 Apr 1993 16:27:26 CARLS
+added VLM_DRIVE_FAILURE
+
+ Rev 1.61 26 Apr 1993 08:33:50 MIKEP
+Changed calls and added new ones to support the refresh tapes window
+stuff needed for cayman. These changes require you to pick up the
+following files: vlm_bset, vlm_cat, vlm_menu, vlm_poll, vlm_strt,
+d_cmaint, ..., you get the idea.
+
+ Rev 1.59 23 Apr 1993 10:21:08 MIKEP
+Add call prototype for refreshing sort of files window.
+
+ Rev 1.58 05 Apr 1993 13:57:14 DARRYLP
+Initial prep work to add Email into Cayman.
+
+ Rev 1.57 01 Apr 1993 17:59:40 GLENN
+Added VLM_IsInfoAvailable().
+
+ Rev 1.56 01 Apr 1993 16:12:40 MIKEP
+add display info call
+
+ Rev 1.55 10 Mar 1993 12:54:52 CARLS
+Changes to move Format tape to the Operations menu
+
+
+**************************/
+
+#ifndef VLM_H
+#define VLM_H
+
+
+
+#define VLM_MAX_VOL_LABEL 50
+
+// NOT the file name size, refers to the length of the string that the
+// file size number is stored in.
+
+#define FLM_MAX_FILE_SIZE 15
+
+// max string for storing the bset number in.
+
+#define BSET_MAX_NUM_SIZE 10
+
+// Create typedefs I can spell
+
+#define WININFO_PTR PDS_WMINFO
+#define WININFO DS_WMINFO
+
+// Used for path and title construction
+
+#define VLM_BUFFER_SIZE 512
+
+// GetDriveStatus defines
+
+#define VLM_VALID_TAPE 0
+#define VLM_DRIVE_BUSY 1
+#define VLM_FOREIGN_TAPE 2
+#define VLM_BLANK_TAPE 3
+#define VLM_NO_TAPE 4
+#define VLM_BUSY 5
+#define VLM_BAD_TAPE 6
+#define VLM_GOOFY_TAPE 7 // QicStream tape, info at end of data
+#define VLM_DISABLED 8
+#define VLM_UNFORMATED 9 // DC2000 tape
+#define VLM_DRIVE_FAILURE 10
+#define VLM_FUTURE_VER 11
+#define VLM_ECC_TAPE 12
+#define VLM_SQL_TAPE 13
+
+
+// VLM status bytes defines
+
+#define INFO_VALID 0x00000001 // have we checked for subdirectories
+#define INFO_EXPAND 0x00000002 // is it expanded
+#define INFO_TAGGED 0x00000004 // is it tagged
+#define INFO_SELECT 0x00000008 // is it selected
+#define INFO_DISPLAY 0x00000010 // is it displayed
+#define INFO_SUBS 0x00000020 // does he have subdirectories
+#define INFO_PARTIAL 0x00000040 // partially selected
+#define INFO_OPEN 0x00000080 // current open directory
+#define INFO_ISADIR 0x00000100 // is a directory
+#define INFO_EXEFILE 0x00000200 // icon type for flm
+#define INFO_TAPE 0x00000400 // flm/slm is from a tape
+#define INFO_CORRUPT 0x00000800 // it's corrupt
+#define INFO_IMAGE 0x00008000 // image backup set
+#define INFO_OLD 0x00004000 // used during refresh call only
+#define INFO_NEW 0x00002000 // used during refresh call only
+#define INFO_EMPTY 0x00001000 // no files in this directory
+#define INFO_FLOPPY 0x00010000 // a floppy backup
+#define INFO_FATDRIVE 0x00020000 // set is from a FAT drive
+#define INFO_FUTURE_VER 0x00040000 // set is from future version of software
+#define INFO_ENCRYPTED 0x00080000 // set is encrypted on tape
+#define INFO_COMPRESSED 0x00100000 // set is compressed on tape
+#define INFO_SMS 0x00200000 // set is from SMS
+
+
+
+// Drive definitions
+
+#define DRIVE_NOT_THERE 0
+#define DRIVE_GONE 1
+#define DRIVE_THERE 2
+#define DRIVE_READONLY 3
+#define DRIVE_WRITEABLE 4
+
+// Network shared drive error list...
+
+#define VLM_NET_GOOD 0x01 // Good, consistent connection
+#define VLM_NOT_ALL_THERE 0x02 // Not all connections were available at initiation
+#define VLM_DROPPED_LINE 0x04 // Connections were dropped during a backup
+#define VLM_NET_READONLY 0x08 // One or more of the connections is readonly
+#define VLM_BACKUP_ABORTED 0x10 // The backup was aborted prior to completion
+
+#ifdef OEM_EMS
+// ... MSNET specific
+
+#define NET_NONE 0x0000
+
+#define MAIL_TYPE_UNKNOWN 0x0000
+
+#define VLM_XCHG_ROOT 0x0001
+#define VLM_XCHG_ENTERPRISE 0x0002
+#define VLM_XCHG_SITE 0x0003
+#define VLM_XCHG_SERVER 0x0004
+#define VLM_XCHG_DSA 0x0005
+#define VLM_XCHG_MDB 0x0006
+
+// Mail family values
+
+#define VIEWXCHG_UNKNOWN 0
+#define VIEWXCHG_EXCHANGE 1
+
+#endif
+
+// A fast way to get at the Primary windows
+
+extern HWND gb_tapes_win;
+extern HWND gb_disks_win;
+extern HWND gb_servers_win;
+extern HWND gb_search_win;
+
+#ifdef OEM_EMS
+extern Q_HEADER gq_exchange_win;
+#endif
+
+// VLM Macros
+
+#define VLM_GetLabel( x ) ( ( x )->label )
+#define VLM_GetName( x ) ( ( x )->name )
+#define VLM_GetStatus( x ) ( ( x )->status )
+#define VLM_GetParent( x ) ( ( x )->parent )
+#define VLM_GetChildren( x ) ( ( x )->children )
+#define VLM_GetXtraBytes( x ) ( ( x )->XtraBytes )
+
+#define VLM_SetLabel( x, y ) ( strcpy( ( x )->label, ( y ) ) )
+#define VLM_SetName( x, y ) ( strcpy( ( x )->name, ( y ) ) )
+#define VLM_SetStatus( x, y ) ( ( x )->status = ( y ) )
+#define VLM_SetParent( x, y ) ( ( x )->parent = ( y ) )
+#define VLM_SetXtraBytes( x, y ) ( ( x )->XtraBytes = ( y ) )
+
+// SLM Macros
+
+#define SLM_GetName( x ) ( ( x )->name )
+#define SLM_GetOriginalName( x ) ( ( x )->original_name )
+#define SLM_GetStatus( x ) ( ( x )->status )
+#define SLM_GetDate( x ) ( ( x )->date )
+#define SLM_GetTime( x ) ( ( x )->time )
+#define SLM_GetLevel( x ) ( ( x )->level )
+#define SLM_GetAttribute( x ) ( ( x )->attrib )
+#define SLM_GetXtraBytes( x ) ( ( x )->XtraBytes )
+#define SLM_GetBrothers( x ) ( ( x )->brothers )
+#define SLM_GetNextBrother( x ) ( ( x )->next_brother )
+
+#define SLM_SetName( x, y ) ( strcpy( ( x )->name, ( y ) ) )
+#define SLM_SetOriginalName( x, y ) ( strcpy( ( x )->original_name, ( y ) ) )
+#define SLM_SetStatus( x, y ) ( ( x )->status = ( y ) )
+#define SLM_SetDate( x, y ) ( ( x )->date = ( y ) )
+#define SLM_SetTime( x, y ) ( ( x )->time = ( y ) )
+#define SLM_SetLevel( x, y ) ( ( x )->level = ( y ) )
+#define SLM_SetAttribute( x, y ) ( ( x )->attrib = ( y ) )
+#define SLM_SetXtraBytes( x, y ) ( ( x )->XtraBytes = ( y ) )
+#define SLM_SetBrothers( x, y, n ) ( memcpy( ( x )->brothers, ( y ), ( n ) )
+#define SLM_SetNextBrother( x, y ) ( ( x )->next_brother = ( y ) )
+
+#ifdef OEM_EMS
+
+// Added to support the Exchange hierarchical window.
+
+#define SLM_GetFlags( x ) ( ( x )->flags )
+#define SLM_GetMailType( x ) ( ( x )->type )
+#define SLM_GetLabel( x ) ( ( x )->label )
+#define SLM_GetParent( x ) ( ( x )->parent )
+#define SLM_GetChildren( x ) ( ( x )->children )
+#define SLM_GetDle( x ) ( ( x )->dle )
+
+#define SLM_SetFlags( x, y ) ( ( x )->flags = ( y ) )
+#define SLM_SetMailType( x, y ) ( ( x )->type = ( y ) )
+#define SLM_SetLabel( x, y ) ( strcpy( ( x )->label, ( y ) ) )
+#define SLM_SetParent( x, y ) ( ( x )->parent = ( y ) )
+#define SLM_SetChildren( x, y ) ( ( x )->children = ( y ) )
+#define SLM_SetDle( x, y ) ( ( x )->dle = ( y ) )
+
+#endif // OEM_EMS
+
+// FLM Macros
+
+#define FLM_GetName( x ) ( ( x )->name )
+#define FLM_GetStatus( x ) ( ( x )->status )
+#define FLM_GetModDate( x ) ( ( x )->mod_date )
+#define FLM_GetModTime( x ) ( ( x )->mod_time )
+#define FLM_GetAccDate( x ) ( ( x )->acc_date )
+#define FLM_GetAccTime( x ) ( ( x )->acc_time )
+#define FLM_GetLevel( x ) ( ( x )->level )
+#define FLM_GetSize( x ) ( ( x )->size )
+#define FLM_GetAttribute( x ) ( ( x )->attrib )
+#define FLM_GetXtraBytes( x ) ( ( x )->XtraBytes )
+#define FLM_GetSizeString( x ) ( ( x )->size_str )
+#define FLM_GetAttribString( x ) ( ( x )->attrib_str )
+#define FLM_GetTimeString( x ) ( ( x )->time_str )
+#define FLM_GetDateString( x ) ( ( x )->date_str )
+#define FLM_GetMaxName( x ) ( ( x )->max_name )
+#define FLM_GetMaxDate( x ) ( ( x )->max_time )
+#define FLM_GetMaxTime( x ) ( ( x )->max_date )
+#define FLM_GetMaxAttr( x ) ( ( x )->max_attr )
+#define FLM_GetMaxSize( x ) ( ( x )->max_size )
+
+
+#define FLM_SetName( x, y ) ( strcpy( ( x )->name, ( y ) ) )
+#define FLM_SetStatus( x, y ) ( ( x )->status = ( y ) )
+#define FLM_SetModDate( x, y ) ( ( x )->mod_date = ( y ) )
+#define FLM_SetModTime( x, y ) ( ( x )->mod_time = ( y ) )
+#define FLM_SetAccDate( x, y ) ( ( x )->acc_date = ( y ) )
+#define FLM_SetAccTime( x, y ) ( ( x )->acc_time = ( y ) )
+#define FLM_SetLevel( x, y ) ( ( x )->level = ( y ) )
+#define FLM_SetSize( x, y ) ( ( x )->size = ( y ) )
+#define FLM_SetAttribute( x, y ) ( ( x )->attrib = ( y ) )
+#define FLM_SetXtraBytes( x, y ) ( ( x )->XtraBytes = ( y ) )
+#define FLM_SetSizeString( x, y ) ( strcpy( ( x )->size_str, ( y ) ) )
+#define FLM_SetAttribString( x, y ) ( strcpy( ( x )->attrib_str, ( y ) ) )
+#define FLM_SetDateString( x, y ) ( strcpy( ( x )->date_str, ( y ) ) )
+#define FLM_SetTimeString( x, y ) ( strcpy( ( x )->time_str, ( y ) ) )
+#define FLM_SetMaxName( x, y ) ( ( x )->max_name = ( y ) )
+#define FLM_SetMaxAttr( x, y ) ( ( x )->max_attr = ( y ) )
+#define FLM_SetMaxTime( x, y ) ( ( x )->max_time = ( y ) )
+#define FLM_SetMaxDate( x, y ) ( ( x )->max_date = ( y ) )
+#define FLM_SetMaxSize( x, y ) ( ( x )->max_size = ( y ) )
+
+// Tape Macros
+
+#define TAPE_GetBsetQueue( x ) ( ( x )->bset_list )
+#define TAPE_GetName( x ) ( ( x )->name )
+#define TAPE_GetFake( x ) ( ( x )->fake_tape )
+#define TAPE_GetCurrent( x ) ( ( x )->current )
+#define TAPE_GetStatus( x ) ( ( x )->status )
+#define TAPE_GetFID( x ) ( ( x )->tape_fid )
+#define TAPE_GetXtraBytes( x ) ( ( x )->XtraBytes )
+#define TAPE_GetMultiTape( x ) ( ( x )->multitape )
+#define TAPE_GetIsFloppy( x ) ( ( x )->status & INFO_FLOPPY )
+
+
+#define TAPE_SetName( x, y ) ( strcpy( ( x )->name, ( y ) ) )
+#define TAPE_SetFake( x, y ) ( ( x )->fake_tape = ( y ) )
+#define TAPE_SetCurrent( x, y ) ( ( x )->current = ( y ) )
+#define TAPE_SetStatus( x, y ) ( ( x )->status = ( y ) )
+#define TAPE_SetFID( x, y ) ( ( x )->tape_fid = ( y ) )
+#define TAPE_SetTapeNum( x, y ) ( ( x )->tape_num = ( y ) )
+#define TAPE_SetXtraBytes( x, y ) ( ( x )->XtraBytes = ( y ) )
+#define TAPE_SetMultiTape( x, y ) ( ( x )->multitape = ( y ) )
+
+
+// Bset Macros
+
+#define BSET_GetName( x ) ( ( x )->name )
+#define BSET_GetUserName( x ) ( ( x )->user_name )
+#define BSET_GetVolName( x ) ( ( x )->volume_name )
+#define BSET_GetTapeNumStr( x ) ( ( x )->tape_num_str )
+#define BSET_GetDateStr( x ) ( ( x )->date_str )
+#define BSET_GetTimeStr( x ) ( ( x )->time_str )
+#define BSET_GetBsetNumStr( x ) ( ( x )->bset_num_str )
+#define BSET_GetPassword( x ) ( ( x )->password )
+#define BSET_GetStatus( x ) ( ( x )->status )
+#define BSET_GetDate( x ) ( ( x )->backup_date )
+#define BSET_GetTime( x ) ( ( x )->backup_time )
+#define BSET_GetIncomplete( x ) ( ( x )->incomplete )
+#define BSET_GetFull( x ) ( ( x )->full )
+#define BSET_GetMissing( x ) ( ( x )->missing )
+#define BSET_GetBsetPswd( x ) ( ( x )->bset_password )
+#define BSET_GetBackupType( x ) ( ( x )->backup_type )
+#define BSET_GetPswdSize( x ) ( ( x )->password_size )
+#define BSET_GetEncryptAlgor( x ) ( ( x )->encrypt_algor )
+#define BSET_GetBsetNum( x ) ( ( x )->bset_num )
+#define BSET_GetTapeNum( x ) ( ( x )->tape_num )
+#define BSET_GetBaseTape( x ) ( ( x )->base_tape )
+#define BSET_GetFID( x ) ( ( x )->tape_fid )
+#define BSET_GetXtraBytes( x ) ( ( x )->XtraBytes )
+#define BSET_GetMaxName( x ) ( ( x )->max_name )
+#define BSET_GetMaxUser( x ) ( ( x )->max_user )
+#define BSET_GetMaxDate( x ) ( ( x )->max_date )
+#define BSET_GetMaxTime( x ) ( ( x )->max_time )
+#define BSET_GetMaxSet( x ) ( ( x )->max_set )
+#define BSET_GetMaxVolName( x ) ( ( x )->max_volume )
+#define BSET_GetTapeMask( x ) ( ( x )->tape_mask )
+#define BSET_GetFullMask( x ) ( ( x )->full_mask )
+#define BSET_GetIncoMask( x ) ( ( x )->inco_mask )
+#define BSET_GetNumTapes( x ) ( ( x )->num_tapes )
+#define BSET_GetOTC( x ) ( ( x )->otc )
+
+#define BSET_SetName( x, y ) ( strcpy( ( x )->name, ( y ) ) )
+#define BSET_SetUserName( x, y ) ( strcpy( ( x )->user_name, ( y ) ) )
+#define BSET_SetVolName( x, y ) ( strcpy( ( x )->volume_name, ( y ) ) )
+#define BSET_SetTapeNumStr( x, y ) ( strcpy( ( x )->tape_num_str, ( y ) ) )
+#define BSET_SetDateStr( x, y ) ( strcpy( ( x )->date_str, ( y ) ) )
+#define BSET_SetTimeStr( x, y ) ( strcpy( ( x )->time_str, ( y ) ) )
+#define BSET_SetPassword( x, y, z ) ( memcpy( ( x )->password, ( y ), ( z ) )
+#define BSET_SetBsetNumStr( x, y ) ( strcpy( ( x )->bset_num_str, ( y ) ) )
+#define BSET_SetStatus( x, y ) ( ( x )->status = ( y ) )
+#define BSET_SetDate( x, y ) ( ( x )->backup_date = ( y ) )
+#define BSET_SetTime( x, y ) ( ( x )->backup_time = ( y ) )
+#define BSET_SetIncomplete( x, y ) ( ( x )->incomplete = ( y ) )
+#define BSET_SetFull( x, y ) ( ( x )->full = ( y ) )
+#define BSET_SetMissing( x, y ) ( ( x )->missing = ( y ) )
+#define BSET_SetBsetPswd( x, y ) ( ( x )->bset_password = ( y ) )
+#define BSET_SetBackupType( x, y ) ( ( x )->backup_type = ( y ) )
+#define BSET_SetPswdSize( x, y ) ( ( x )->password_size = ( y ) )
+#define BSET_SetEncryptAlgor( x, y ) ( ( x )->encrypt_algor = ( y ) )
+#define BSET_SetBsetNum( x, y ) ( ( x )->bset_num = ( y ) )
+#define BSET_SetTapeNum( x, y ) ( ( x )->tape_num = ( y ) )
+#define BSET_SetBaseTape( x, y ) ( ( x )->base_tape = ( y ) )
+#define BSET_SetFID( x, y ) ( ( x )->tape_fid = ( y ) )
+#define BSET_SetXtraBytes( x, y ) ( ( x )->XtraBytes = ( y ) )
+#define BSET_SetMaxName( x, y ) ( ( x )->max_name = ( y ) )
+#define BSET_SetMaxUser( x, y ) ( ( x )->max_user = ( y ) )
+#define BSET_SetMaxDate( x, y ) ( ( x )->max_date = ( y ) )
+#define BSET_SetMaxTime( x, y ) ( ( x )->max_time = ( y ) )
+#define BSET_SetMaxSet( x, y ) ( ( x )->max_set = ( y ) )
+#define BSET_SetMaxVolName( x, y ) ( ( x )->max_volume = ( y ) )
+#define BSET_SetTapeMask( x, y ) ( ( x )->tape_mask = ( y ) )
+#define BSET_SetFullMask( x, y ) ( ( x )->full_mask = ( y ) )
+#define BSET_SetIncoMask( x, y ) ( ( x )->inco_mask = ( y ) )
+#define BSET_SetNumTapes( x, y ) ( ( x )->num_tapes = ( y ) )
+#define BSET_SetOTC( x, y ) ( ( x )->otc = ( y ) )
+
+
+// VLM_CatalogSync() defines
+
+#define VLM_SYNCMORE 0x01 // sets may have been added to the catalogs
+#define VLM_SYNCLESS 0x02 // sets may have been removed from the catalogs
+
+
+// Selection defines
+
+#define SLM_SEL_ALL 1
+#define SLM_SEL_NONE 2
+
+#define FLM_SEL_ALL 1
+#define FLM_SEL_NONE 2
+
+
+// The structure for servers/volumes/disks
+
+typedef struct vlm_object {
+
+ Q_ELEM q_elem; // queue stuff
+ Q_HEADER children;
+ CHAR_PTR name; // drive name C:
+ CHAR_PTR label; // G: [ENG1/SYS2] or \\mickey\public
+ UINT32 status; // Uses INFO_??? defines above
+ WININFO_PTR XtraBytes; // pointer to xtrabytes
+ struct vlm_object *parent;
+
+} VLM_OBJECT, *VLM_OBJECT_PTR;
+
+
+//
+// The structure for a subdirectory in the hierarchical tree
+//
+
+typedef struct slm_object {
+
+ Q_ELEM q_elem; // queue stuff
+ CHAR_PTR name; // directory name
+ CHAR_PTR original_name; // directory name in original case
+ UINT16 date; // date & time
+ UINT16 time;
+ UINT32 status; // Uses INFO_???? defines above
+ INT level; // hieght in tree
+ UINT32 attrib; // attributes
+ BYTE_PTR brothers;
+ WININFO_PTR XtraBytes; // pointer to xtrabytes
+
+ struct slm_object *next_brother;
+
+#ifdef OEM_EMS // Info used by Exchange
+ UINT16 type; // Type of exchange object.
+ UINT16 flags; // Attribute bits of network object.
+ struct slm_object *parent;
+ GENERIC_DLE_PTR dle ;
+#endif // OEM_EMS
+
+} SLM_OBJECT, *SLM_OBJECT_PTR;
+
+//
+// The structure for a file in the flat list
+//
+
+typedef struct flm_object {
+
+ Q_ELEM q_elem; // queue stuff
+ CHAR_PTR name; // name
+ UINT32 status; // Uses INFO_???? defines above
+ UINT32 attrib; // attributes
+ UINT16 mod_date; // modified date & time
+ UINT16 mod_time;
+ UINT16 acc_date; // accessed date & time
+ UINT16 acc_time;
+ UINT64 size; // size in bytes
+ CHAR size_str[ FLM_MAX_FILE_SIZE ]; // size in text
+ CHAR_PTR attrib_str; // time, date, attr text
+ CHAR_PTR date_str; // time, date, attr text
+ CHAR_PTR time_str; // time, date, attr text
+ INT level; // height in tree
+ WININFO_PTR XtraBytes; // pointer to xtrabytes
+
+ // This is really wasteful of space and I wish someone would move this
+ // info to the appinfo structure so it is not repeated a million times
+ // in memory.
+
+ INT max_name; // max file name length in list
+ INT max_attr; // etc.
+ INT max_date;
+ INT max_time;
+ INT max_size;
+
+} FLM_OBJECT, *FLM_OBJECT_PTR;
+
+//
+// The structure for a tape in the TAPES window
+//
+
+typedef struct tape_object {
+ Q_ELEM q_elem; // queue stuff
+ Q_HEADER bset_list; // queue of bsets on this tape
+ CHAR_PTR name; // name
+ INT fake_tape:1; // blank or foreign
+ INT current:1; // is it in the drive ?
+ UINT32 status; // Uses INFO_???? defines above
+ INT tape_num; // tape sequence number 1,2,3,...
+ UINT32 tape_fid; // tape family id
+ WININFO_PTR XtraBytes; // pointer to xtrabytes
+ INT cataloged; // have we read in all the sets on tape
+ INT multitape; // is there > 1 tapes in this family
+} TAPE_OBJECT, *TAPE_OBJECT_PTR;
+
+// The structure for a BSET in the TAPES window
+
+typedef struct bset_object {
+
+ Q_ELEM q_elem; // queue stuff
+
+ CHAR_PTR name; // name
+ CHAR_PTR user_name; // MIKEP
+ CHAR_PTR volume_name; // C: SICK CAT'S
+ CHAR_PTR password; // ????
+ CHAR_PTR tape_num_str; // Tapes 1..2
+ CHAR_PTR time_str; // 12:24:56pm
+ CHAR_PTR date_str; // 10/16/61
+ CHAR_PTR kbytes_str; // size string
+
+ UINT32 status; // Uses INFO_???? defines above
+ INT16 backup_date; // dos format date
+ INT16 backup_time; // dos format time
+
+ INT incomplete:1; // everything known but something partial
+ INT full:1; // nothing cataloged
+ INT missing:1; // all present are full, but some missing
+ INT bset_password:1; // password for bset or tape ?
+ INT backup_type:4;
+
+ INT password_size; // 0 = no password
+ INT encrypt_algor;
+
+ INT num_tapes; // how many tapes is bset on
+
+ INT16 bset_num; // exactly which bset is this
+ INT16 tape_num;
+ UINT32 tape_fid;
+
+ WININFO_PTR XtraBytes; // pointer to xtrabytes
+
+ // This is also very wasteful of memory and
+ // should be moved to the tape structure.
+
+ INT max_name; // max string sizes for column alignment
+ INT max_date;
+ INT max_time;
+ INT max_user;
+ INT max_volume;
+ INT max_set;
+ INT max_tapes;
+ INT max_kbytes;
+
+ UINT32 tape_mask; // is piece present
+ UINT32 full_mask; // is piece fully cataloged
+ UINT32 inco_mask; // is piece incompletely cataloged
+ INT16 base_tape; // guess at first tape in this set
+
+ INT selected_dirs;
+ INT selected_files;
+ UINT64 selected_bytes;
+
+ CHAR bset_num_str[ BSET_MAX_NUM_SIZE ];
+
+ INT otc; // Is OTC available for this set
+
+ INT os_id;
+ INT os_ver ;
+ INT num_files ;
+ INT num_corrupt ;
+ INT num_dirs ;
+
+ UINT64 total_bytes; // bytes in set
+
+} BSET_OBJECT, *BSET_OBJECT_PTR;
+
+//
+// The user application area associated with each window. This structure
+// contains many fields. Only some of which are used for each window type.
+//
+
+typedef struct appinfo {
+
+ HWND win; // this window
+ HWND parent; // parent primary window
+
+ SLM_OBJECT_PTR open_slm; // current open slm
+ TAPE_OBJECT_PTR open_tape; // current open tape
+
+ GENERIC_DLE_PTR dle; // dle for this window
+
+ // Used if it's a tape selection window
+
+ UINT32 tape_fid; // tape this window is from
+ INT16 bset_num; // bset this window is from
+ INT16 tape_num;
+
+ // Used if it's a disk selection window
+
+ FSYS_HAND fsh; // file system handle
+
+ // Used if it's a server/volume selection
+
+ FSYS_HAND server_fsh; // file system handle for servers
+
+ BOOLEAN fFatDrive; // Is this a FAT drive or
+ // a backup of a FAT drive ?
+
+} APPINFO, *APPINFO_PTR;
+
+//
+// General functions for processing the endless queues in the VLM
+//
+
+VLM_OBJECT_PTR VLM_GetFirstVLM( Q_HEADER_PTR );
+VLM_OBJECT_PTR VLM_GetNextVLM( VLM_OBJECT_PTR );
+VLM_OBJECT_PTR VLM_GetPrevVLM( VLM_OBJECT_PTR );
+
+SLM_OBJECT_PTR VLM_GetFirstSLM( Q_HEADER_PTR );
+SLM_OBJECT_PTR VLM_GetLastSLM( Q_HEADER_PTR );
+SLM_OBJECT_PTR VLM_GetNextSLM( SLM_OBJECT_PTR );
+SLM_OBJECT_PTR VLM_GetPrevSLM( SLM_OBJECT_PTR );
+SLM_OBJECT_PTR VLM_GetNextBrotherSLM( SLM_OBJECT_PTR );
+SLM_OBJECT_PTR VLM_GetParentSLM( SLM_OBJECT_PTR );
+
+FLM_OBJECT_PTR VLM_GetFirstFLM( Q_HEADER_PTR );
+FLM_OBJECT_PTR VLM_GetLastFLM( Q_HEADER_PTR );
+FLM_OBJECT_PTR VLM_GetNextFLM( FLM_OBJECT_PTR );
+FLM_OBJECT_PTR VLM_GetPrevFLM( FLM_OBJECT_PTR );
+
+TAPE_OBJECT_PTR VLM_GetFirstTAPE( VOID );
+TAPE_OBJECT_PTR VLM_GetNextTAPE( TAPE_OBJECT_PTR );
+TAPE_OBJECT_PTR VLM_GetPrevTAPE( TAPE_OBJECT_PTR );
+
+BSET_OBJECT_PTR VLM_GetFirstBSET( Q_HEADER_PTR );
+BSET_OBJECT_PTR VLM_GetLastBSET( Q_HEADER_PTR );
+BSET_OBJECT_PTR VLM_GetNextBSET( BSET_OBJECT_PTR );
+BSET_OBJECT_PTR VLM_GetPrevBSET( BSET_OBJECT_PTR );
+
+// Misc. Functions in Alphabetical order, sort of ...
+
+VOID VLM_AddAdvancedSelection( HWND, DS_ADVANCED_PTR );
+VOID VLM_AddBset( UINT32, INT16, INT16, VOID_PTR, BOOLEAN );
+INT VLM_AddFileForInclude( UINT32, INT16, BOOLEAN );
+VOID VLM_AddInServerChildren( VLM_OBJECT_PTR );
+INT VLM_AddPartials( CHAR_PTR, INT16, BSD_PTR, UINT32, INT16, INT_PTR, UINT64_PTR );
+INT VLM_AnySelFiles( VOID );
+INT VLM_AnyDiskSelections( VOID );
+INT VLM_AnyTapeSelections( VOID );
+VOID VLM_BlowOutDir( SLM_OBJECT_PTR );
+VOID VLM_BsetFillInDLM( VOID_PTR );
+VOID_PTR VLM_BsetSetSelect( BSET_OBJECT_PTR, BYTE );
+BOOLEAN VLM_BsetSetObjects( BSET_OBJECT_PTR, WORD, WORD );
+INT VLM_BuildFileList( FSYS_HAND, CHAR_PTR, Q_HEADER_PTR, WININFO_PTR );
+CHAR_PTR VLM_BuildPath( SLM_OBJECT_PTR );
+VOID VLM_BuildVolumeList( Q_HEADER_PTR, WININFO_PTR );
+VOID VLM_BuildServerList( Q_HEADER_PTR, WININFO_PTR );
+INT VLM_BuildTapeFileList( CHAR_PTR, Q_HEADER_PTR, UINT32, INT16, WININFO_PTR );
+VOID VLM_CatalogMaintenance( VOID );
+INT VLM_CatalogDataPathChanged( VOID );
+INT VLM_CatalogSet( UINT32, INT16, INT16 );
+VOID VLM_CatalogSync( INT );
+INT VLM_CheckForCatalogError( QTC_BUILD_PTR );
+INT VLM_CheckForChildren( Q_HEADER_PTR, SLM_OBJECT_PTR, CHAR_PTR, INT, BOOLEAN );
+VOID VLM_ClearAllSelections( VOID );
+VOID VLM_ClearAllDiskSelections( VOID );
+VOID VLM_ClearAllTapeSelections( VOID );
+VOID VLM_ClearAllSearchSelections( VOID );
+VOID VLM_ClearAllServerSelections( VOID );
+VOID VLM_ClearAllTreeSelections( VOID );
+VOID VLM_ClearCurrentTape( UINT32, BOOLEAN );
+VOID VLM_CloseAll( VOID );
+VOID VLM_CloseWin( HWND );
+VOID VLM_ChangeSettings( INT16, INT32 );
+TAPE_OBJECT_PTR VLM_CreateTAPE( INT16 );
+VLM_OBJECT_PTR VLM_CreateVLM( INT16, INT16 );
+VOID VLM_CollapseBranch( HWND );
+VOID VLM_Deinit( VOID );
+VOID VLM_DeselectAll( WININFO_PTR, BOOLEAN );
+BOOLEAN VLM_DisksListCreate( VOID );
+VOID VLM_DisksSync( VOID );
+INT VLM_DisplayInfo( VOID );
+VOID VLM_DownOneDir( HWND );
+VOID VLM_ExpandTree( HWND );
+VOID VLM_ExpandOne( HWND );
+VOID VLM_ExpandBranch( HWND );
+INT VLM_FileListReuse( HWND, CHAR_PTR );
+VOID VLM_FileListManager( HWND, WORD );
+VOID VLM_FillInBSD( BSD_PTR );
+INT16 VLM_FindScannedBset( GENERIC_DLE_PTR );
+BSET_OBJECT_PTR VLM_FindBset( UINT32, INT16 );
+INT VLM_FindServerChildren( VLM_OBJECT_PTR );
+SLM_OBJECT_PTR VLM_FindSLM( Q_HEADER_PTR, CHAR_PTR, INT );
+VLM_OBJECT_PTR VLM_FindVLMByName( Q_HEADER_PTR, CHAR_PTR );
+VOID VLM_FlmFillInDLM( VOID_PTR );
+VOID VLM_FontCaseChange( VOID );
+VOID VLM_FreeVLMList( Q_HEADER_PTR );
+#ifdef OEM_EMS
+VOID SLM_EMSFreeSLMList( Q_HEADER_PTR );
+#endif
+INT VLM_GetDriveLabel( GENERIC_DLE_PTR, CHAR_PTR, INT );
+INT VLM_GetDriveStatus( DBLK_PTR * );
+VOID VLM_AddTapeIfUnknown( BOOLEAN );
+BOOLEAN VLM_GetTapeCreationDate( UINT32, INT16 *, INT16 * );
+BOOLEAN VLM_GetSetCreationDate( UINT32, INT16, INT16 *, INT16 * );
+BOOLEAN VLM_GetTapeOwnersName( UINT32, CHAR_PTR );
+BOOLEAN VLM_GetSetOwnersName( UINT32, INT16, CHAR_PTR );
+CHAR_PTR VLM_GetVolumeName( UINT32, INT16 );
+CHAR_PTR VLM_GetBsetName( UINT32, INT16 );
+CHAR_PTR VLM_GetTapeName( UINT32 );
+CHAR_PTR VLM_GetUserName( UINT32, INT16 );
+UINT16 VLM_GetBackupDate( UINT32, INT16 );
+UINT16 VLM_GetBackupTime( UINT32, INT16 );
+INT VLM_GetBackupType( UINT32, INT16 );
+VOID VLM_GetSortDate( UINT32, INT16, DATE_TIME_PTR );
+INT VLM_HandleFSError( INT );
+INT VLM_IncludeCatalogs( VOID );
+BOOL VLM_Init( BOOL );
+INT VLM_InsertTapeInQueue( Q_HEADER_PTR, TAPE_OBJECT_PTR );
+BOOL VLM_IsInfoAvailable ( VOID );
+VOID VLM_LoadDefaultSelections( VOID );
+VOID VLM_LookForCatalogFiles( VOID );
+VOID VLM_MarkAllSLMChildren( SLM_OBJECT_PTR, INT16, INT_PTR, INT_PTR, UINT64_PTR );
+VOID VLM_MakeSLMActive( SLM_OBJECT_PTR );
+VOID VLM_MakeAllParentsPartial( SLM_OBJECT_PTR );
+VOID VLM_MatchSLMList( WININFO_PTR, BSD_PTR, BOOLEAN );
+VOID VLM_NetConnect ( VOID );
+VOID VLM_NetDisconnect ( VOID );
+INT VLM_NewTapeInserted( VOID );
+VOID VLM_NextBrotherDir( HWND );
+VOID VLM_PartializeTape( UINT32 );
+VOID VLM_PrevBrotherDir( HWND );
+VOID VLM_Refresh( VOID );
+INT VLM_RefreshTapesWindow( VOID );
+VOID VLM_RematchAllLists( VOID );
+VOID VLM_RematchList( HWND );
+VOID VLM_RemoveBset( UINT32, INT16, INT16, BOOLEAN );
+VOID VLM_RemoveTape( UINT32, INT16, BOOLEAN );
+VOID VLM_RemoveUnusedBSDs( BSD_HAND ) ;
+INT VLM_ResortFileList( HWND );
+SLM_OBJECT_PTR VLM_RetrieveSLM( CHAR_PTR, HWND );
+INT16 VLM_ScanDrive( GENERIC_DLE_PTR );
+INT VLM_SearchRemoveSet( UINT32, INT16 );
+VOID VLM_SelectDisks( BYTE );
+VOID VLM_SelectVolumes( BYTE );
+VOID VLM_SelectBsets( BYTE );
+VOID VLM_SelectTree( HWND, BYTE );
+VOID VLM_SelectFiles( HWND, BYTE );
+VOID VLM_SelectSearch( BYTE );
+VOID VLM_ServerListCreate( VOID );
+VOID VLM_ServersSync( VOID );
+VOID VLM_SetMaxVolumeLabelLength( Q_HEADER_PTR );
+BOOLEAN VLM_ShowServers( BOOLEAN );
+VOID VLM_SortServers( VOID );
+INT VLM_StartBackup( VOID );
+INT VLM_StartTransfer( VOID );
+INT VLM_StartCatalog( VOID );
+INT VLM_StartVerify( VOID );
+VOID VLM_StartErase( VOID );
+VOID VLM_StartFormat( VOID );
+INT VLM_StartRestore( VOID );
+VOID VLM_StartTension( VOID );
+VOID VLM_StartSearch( CHAR_PTR );
+INT VLM_SubdirListCreate( GENERIC_DLE_PTR, UINT32, INT16, INT16, HWND );
+VOID VLM_SubdirListManager( HWND, WORD );
+VOID VLM_TapeChanged( INT16, DBLK_PTR, FSYS_HAND );
+BOOLEAN VLM_TapesListCreate( VOID );
+BOOLEAN VLM_TapeSetObjects( TAPE_OBJECT_PTR, WORD, WORD );
+VOID_PTR VLM_TapeSetSelect( TAPE_OBJECT_PTR, BYTE );
+VOID VLM_UpdateRoot( HWND );
+VOID VLM_UpdateBrothers( Q_HEADER_PTR );
+VOID VLM_UpdateDisks( VOID );
+VOID VLM_UpdateDiskStatus( VLM_OBJECT_PTR );
+VOID VLM_UpdateFLMItem( HWND, SLM_OBJECT_PTR );
+VOID VLM_UpdateSearchSelections( UINT32, INT16 );
+VOID VLM_UpdateServers( VOID );
+VOID VLM_UpdateServerStatus( VLM_OBJECT_PTR );
+VOID VLM_UpdateTapes( VOID );
+VOID VLM_UpdateTapeStatus( TAPE_OBJECT_PTR, BOOLEAN );
+VOID VLM_UpOneDir( HWND );
+INT VLM_ValidatePath( CHAR_PTR, BOOLEAN, BOOLEAN );
+INT16 VLM_VlmCompare( Q_ELEM_PTR, Q_ELEM_PTR );
+
+#ifdef OEM_EMS
+VOID SLM_EMSExpandTree( HWND );
+VOID SLM_EMSExpandOne( HWND );
+VOID SLM_EMSExpandBranch( HWND );
+VOID SLM_EMSCollapseBranch( HWND );
+VOID SLM_EMSPrevBrotherDir( HWND );
+VOID SLM_EMSNextBrotherDir( HWND win ) ;
+VOID SLM_EMSDownOneDir( HWND win ) ;
+VOID SLM_EMSUpOneDir( HWND );
+
+BOOLEAN VLM_ExchangeInit ( VOID );
+VOID VLM_ExchangeSync( VOID );
+VOID VLM_UpdateExchange( HWND );
+VOID VLM_ClearAllExchangeSelections( VOID );
+BOOLEAN VLM_ExchangeListCreate( CHAR_PTR );
+BOOLEAN SLM_DisplayExchangeDLE( GENERIC_DLE_PTR );
+VOID VLM_SelectExchangeShares( BYTE, WININFO_PTR );
+GENERIC_DLE_PTR DLE_GetEnterpriseDLE( GENERIC_DLE_PTR );
+#endif //OEM_EMS
+
+// General functions for processing the endless queues in the SLM
+
+SLM_OBJECT_PTR VLM_CreateSlm( INT, INT, BOOLEAN, BOOLEAN );
+
+#endif
diff --git a/private/utils/ntbackup/inc/vlm_find.h b/private/utils/ntbackup/inc/vlm_find.h
new file mode 100644
index 000000000..1f21491df
--- /dev/null
+++ b/private/utils/ntbackup/inc/vlm_find.h
@@ -0,0 +1,344 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: VLM_FIND.H
+
+ Description:
+
+ This file contains file find routines which use the file
+ manager for searching directories.
+
+ The following public functions are implemented in this file:
+
+ VLM_FindFirst - Find first matching file or subdirectory
+ VLM_FindNext - Find next file in set
+ VLM_FindClose - Terminate a FindFirst/FindNext sequence
+
+ $Log: G:/UI/LOGFILES/VLM_FIND.H_V $
+
+ Rev 1.9 18 Feb 1993 13:28:58 BURT
+Change for Cayman
+
+
+ Rev 1.8 01 Nov 1992 16:33:36 DAVEV
+Unicode changes
+
+ Rev 1.7 04 Oct 1992 19:49:58 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.6 06 May 1992 14:44:32 MIKEP
+unicode pass 2
+
+ Rev 1.5 04 May 1992 14:39:28 MIKEP
+unicode pass 1
+
+ Rev 1.4 04 Feb 1992 16:11:58 STEVEN
+added support for NT
+
+ Rev 1.3 15 Jan 1992 15:22:06 DAVEV
+16/32 bit port-2nd pass
+
+ Rev 1.2 08 Jan 1992 11:16:44 DAVEV
+minor bug fix
+
+ Rev 1.1 07 Jan 1992 15:36:40 DAVEV
+bug fixes
+
+ Rev 1.0 23 Dec 1991 14:10:02 DAVEV
+first revision
+
+
+*****************************************************/
+/**********************
+
+ NAME : VLM_FindFirst, VLM_FindNext, VLM_FindClose
+
+ PROTOTYPE:
+
+ #include <stdtypes.h>
+ #include <vlm.h> - or - #include <vlm_find.h>
+
+ VLM_FIND_PTR VLM_FindFirst (
+ LPSTR pszFile, // I - name of file or subdirectory
+ // may contain (OS specific) wildcards
+ VLM_FINDATTR findAttr, // I - search criteria flags
+ LPSTR pszFirst); // O - First matching file name found
+ // (without drive or path)
+
+ BOOL VLM_FindNext (
+ VLM_FIND_PTR pFind, // IO- Find data structure returned from
+ // a previous VLM_FindFirst
+ LPSTR pszNext); // O - File name of next file found
+
+ VOID VLM_FindClose (
+ VLM_FIND_PTR FAR * pFind); // IO- Find data structure returned from
+ // a previous VLM_FindFirst
+
+ DESCRIPTION :
+
+ Find all files or subdirectories in a set specified using
+ an Operating Sysytem specific file name path which may contain any wild
+ cards normally allowed by the operating system.
+
+ VLM_FindFirst must be called first to get the first file found in
+ the set. VLM_FindNext may then be repeatedly called to obtain all
+ subsequent files in the set. The order of the file names returned
+ may be arbitrary.
+
+ VLM_FindClose MUST be called to free system resources after the program
+ has finished.
+
+ VLM_FindFirst RETURNS :
+
+ NULL - if an error occurred, otherwise
+ VLM_FIND_PTR - pointer to an internal data structure required for
+ subsequent calls to VLM_FindNext and VLM_FindClose.
+
+ NOTE: This pointer should never be accessed by the
+ calling program!
+
+ pszFile - The buffer provided by the caller is filled with the
+ file name (sans path or drive) of the first file
+ found matching the specifications.
+
+ VLM_FindNext RETURNS:
+
+ TRUE - A matching file was found and placed in the pszNext
+ buffer.
+ FALSE - The list of matching files is exhausted. VLM_FindClose
+ should now be called to free system resources.
+
+ pszNext - The buffer provided by the caller is filled with the
+ next file found in the set specified by the initial
+ VLM_FindFirst call.
+
+ VLM_FindClose RETURNS:
+
+ Nothing. The VLM_FIND_PTR pointed to in the function parameter is
+ set to NULL.
+
+ NOTES:
+
+ pszFile - The form used to specify the filename pattern is
+ operating system dependant.
+ For DOS, OS/2 and NT, it is a standard drive, path and
+ file name string:
+ [d:][path]fname
+
+ The path must utilize backslashes as unit seperators,
+ like normal. The file name may contain ? and * wildcards
+ in the normal maner.
+
+ findAttr - This parameter may contain one or more of the following
+ flags logically or'd together:
+
+ VLMFIND_NORMAL - Include matching files
+ VLMFIND_SUBDIR - Include matching subdirs
+
+ VLMFIND_NORDONLY - Exclude read-only files/subdirs
+ VLMFIND_NOARCH - Exclude archived files/subdirs
+
+ VLMFIND_HIDDEN - Include hidden files/subdirs
+ VLMFIND_SYSTEM - Include system files/subdirs
+
+ Notice that these flags are divided into three groups.
+ The first group (NORMAL and SUBDIR) determine whether
+ (normal) files, subdirectories or both are to be
+ retrieved. If neither of these flags are specified,
+ VLMFIND_NORMAL is presumed (only files will be
+ retrieved - no subdirectories.)
+
+ The second group specifies whether read-only and/or
+ archive files or subdirectories should be excluded from
+ the retrieved list. These types will be included
+ unless otherwise specified.
+
+ Finally, the last group determines whether hidden or
+ system files or subdirectories are to be included.
+ These types will be excluded unless specified.
+
+ Examples:
+ VLMFIND_NORMAL | VLMFIND_SUBDIR
+ This will find all files and subdirectories which
+ do not have thier hidden or system flags set.
+
+ VLMFIND_NORMAL | VLMFIND_NORDONLY | VLMFIND_NOARCH
+ This will find only those files (no subdirectories)
+ which have no flags set at all.
+
+
+ VLMFIND_SUBDIR
+ This will only find subdirectories (no files)
+ which are neither hidden nor system.
+
+ pszFirst - These must point to a character buffer which MUST be
+ long enough to hold the largest possible returned
+ pszNext file name. This length is defined by VLM_MAXFNAME
+ in VLM_FIND.H. The following declaration is
+ recommended:
+
+ CHAR szName [VLM_MAXFNAME];
+
+**********************/
+#ifndef VLM_FIND_INCL //Avoid multiple includes
+#define VLM_FIND_INCL
+
+#ifdef OS_WIN32
+# define VLM_MAXFNAME MAX_PATH /*max length of a file name */
+ #define VLM_MAXPATH MAX_PATH /*max length of full path name */
+#else
+# define VLM_MAXFNAME _MAX_FNAME /*max length of a file name */
+# define VLM_MAXPATH _MAX_PATH /*max length of full path name */
+#endif
+
+
+// Note: we use our own file matching flags because we need a slot for
+// specifying what types of files are desired.
+
+typedef enum {
+
+ VLMFIND_NORMAL = 0x01, // Include non-hidden, non-system files
+ VLMFIND_SUBDIR = 0x02, // Include non-hidden/system subdirectories
+ VLMFIND_NORDONLY = 0x04, // Exclude read-only files or subdirs
+ VLMFIND_NOARCH = 0x08, // Exclude archived files or subdirs
+ VLMFIND_HIDDEN = 0x10, // Include hidden files or subdirectories
+ VLMFIND_SYSTEM = 0x20 // Include system files or subdirectories
+
+} VLM_FINDATTR;
+
+typedef struct VLM_FIND_STRUC {
+
+ VLM_FINDATTR attr;
+
+# ifdef OS_WIN32 // NT specific data elements
+
+ HANDLE hFind;
+ WIN32_FIND_DATA nt_findbuf;
+
+# else //MS-DOS specific data elements
+
+ struct find_t dos_findbuf;
+
+# endif
+
+} VLM_FIND, FAR * VLM_FIND_PTR;
+
+
+/************************************************************************/
+/* VLM_FIND_PTR DATA ACCESS MACROS */
+/************************************************************************/
+#ifdef OS_WIN32 //32 bit Windows/NT versions of macros
+
+# define VLM_FindName(pVlm) TEXT("")
+
+ // Get File size - NOTE: under DOS (and, presumably, OS/2 & UNIX) this is
+ // a LONG. Under NT, however, file size is 2 LONG's (8 BYTES)!!
+ // We have a PORTING PROBLEM HERE!!!
+
+// Defined for now 11/10/92 BBB to use low 4 bytes. Need to enhance
+// structures and code to support 64-bit UINT64 stuff later
+# define VLM_FindSize(pVlm) \
+ (pVlm->nt_findbuf.nFileSizeLow)
+
+ USHORT VLM_FindDosTime(FILETIME ft);
+# define VLM_FindWriteTime(pVlm) \
+ VLM_FindDosTime((pVlm)->nt_findbuf.ftLastWriteTime)
+# define VLM_FindWriteHour(pVlm) \
+ (VLM_FindWriteTime(pVlm) >> 11) //24 hour time
+# define VLM_FindWriteMinute(pVlm) \
+ ((VLM_FindWriteTime(pVlm) & 0x07e0)>>5)
+
+ USHORT VLM_FindDosDate(FILETIME ft);
+# define VLM_FindWriteDate(pVlm) \
+ VLM_FindDosDate((pVlm)->nt_findbuf.ftLastWriteTime)
+# define VLM_FindWriteMonth(pVlm) \
+ ((VLM_FindWriteDate(pVlm) & 0x01e0)>>5)
+# define VLM_FindWriteDay(pVlm) \
+ (VLM_FindWriteDate(pVlm) & 0x001f)
+# define VLM_FindWriteYear(pVlm) \
+ ((VLM_FindWriteDate(pVlm) >> 9) + 1980)
+
+ // File creation date & time: not available under DOS so return last write
+ // time & date info instead
+ // Note: this info may be available under NT - these macros need to be
+ // changed to return the proper values when available.
+
+# define VLM_FindCreatTime(pVlm) VLM_FindWriteTime(pVlm)
+# define VLM_FindCreatHour(pVlm) VLM_FindWriteHour(pVlm)
+# define VLM_FindCreatMinute(pVlm) VLM_FindWriteMinute(pVlm)
+
+# define VLM_FindCreatDate(pVlm) VLM_FindWriteDate(pVlm)
+# define VLM_FindCreatMonth(pVlm) VLM_FindWriteMonth(pVlm)
+# define VLM_FindCreatDay(pVlm) VLM_FindWriteDay(pVlm)
+# define VLM_FindCreatYear(pVlm) VLM_FindWriteYear(pVlm)
+
+ // The following macro really should return the appropriate VLMFILE_* flags
+ // this implementation is NOT PORTABLE!!
+
+# define VLM_FindAttr(pVlm) ((pVlm)->dwFileAttributes)
+
+
+#else // 16-bit Windows/DOS versions of macros:
+
+
+# define VLM_FindName(pVlm) ((pVlm)->dos_findbuf.name)
+
+ // Get File size - NOTE: under DOS (and, presumably, OS/2 & UNIX) this is
+ // a LONG. Under NT, however, file size is 2 LONG's (8 BYTES)!!
+ // We have a PORTING PROBLEM HERE!!!
+
+# define VLM_FindSize(pVlm) ((pVlm)->dos_findbuf.size)
+
+# define VLM_FindWriteTime(pVlm) ((pVlm)->dos_findbuf.wr_time)
+# define VLM_FindWriteHour(pVlm) \
+ (VLM_FindWriteTime(pVlm) >> 11) //24 hour time
+# define VLM_FindWriteMinute(pVlm) \
+ ((VLM_FindWriteTime(pVlm) & 0x07e0)>>5)
+
+# define VLM_FindWriteDate(pVlm) ((pVlm)->dos_findbuf.wr_date)
+# define VLM_FindWriteMonth(pVlm) \
+ ((VLM_FindWriteDate(pVlm) & 0x01e0)>>5)
+# define VLM_FindWriteDay(pVlm) \
+ (VLM_FindWriteDate(pVlm) & 0x001f)
+# define VLM_FindWriteYear(pVlm) \
+ ((VLM_FindWriteDate(pVlm) >> 9) + 1980)
+
+ // File creation date & time: not available under DOS so return last write
+ // time & date info instead
+
+# define VLM_FindCreatTime(pVlm) VLM_FindWriteTime(pVlm)
+# define VLM_FindCreatHour(pVlm) VLM_FindWriteHour(pVlm)
+# define VLM_FindCreatMinute(pVlm) VLM_FindWriteMinute(pVlm)
+
+# define VLM_FindCreatDate(pVlm) VLM_FindWriteDate(pVlm)
+# define VLM_FindCreatMonth(pVlm) VLM_FindWriteMonth(pVlm)
+# define VLM_FindCreatDay(pVlm) VLM_FindWriteDay(pVlm)
+# define VLM_FindCreatYear(pVlm) VLM_FindWriteYear(pVlm)
+
+ // The following macro really should return the appropriate VLMFILE_* flags
+ // this implementation is NOT PORTABLE!!
+
+# define VLM_FindAttr(pVlm) ((pVlm)->dos_findbuf.attrib)
+
+#endif
+
+/************************************************************************/
+/* PUBLIC FUNCTION PROTOTYPES */
+/************************************************************************/
+VLM_FIND_PTR VLM_FindFirst (
+ CHAR_PTR pszFile, // I - name of file or subdirectory
+ // may contain (OS specific) wildcards
+ VLM_FINDATTR findAttr, // I - search criteria flags
+ CHAR_PTR pszFirst); // O - First matching file name found
+ // (without drive or path)
+
+BOOLEAN VLM_FindNext (
+ VLM_FIND_PTR pFind, // IO- Find data structure returned from
+ // a previous VLM_FindFirst
+ CHAR_PTR pszNext); // O - File name of next file found
+
+VOID VLM_FindClose (
+ VLM_FIND_PTR FAR * pFind); // IO- Find data structure returned from
+ // a previous VLM_FindFirst
+
+#endif //VLM_FIND_INCL
diff --git a/private/utils/ntbackup/inc/vm.h b/private/utils/ntbackup/inc/vm.h
new file mode 100644
index 000000000..ffb270584
--- /dev/null
+++ b/private/utils/ntbackup/inc/vm.h
@@ -0,0 +1,117 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: vm.h
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains all the necessary constant definitions,
+ and prototypes required to use the Virtual Memory Manager.
+
+ There are six routines provided. These include:
+ VM_InitVM - Initialize Virtual Memory Manager
+ VM_RemoveVM - Terminate Virtual Memory Manager
+ VM_Alloc - Allocate Virtual Memory Block
+ VM_Free - Release Virtual Memory Block
+ VM_MemLock - Lock VM block in memory
+ VM_MemUnLock - Unlock VM block in memory
+
+
+ $Log: J:/LOGFILES/VM.H_V $
+ *
+ * Rev 1.2 19 Nov 1992 16:29:50 CHARLIE
+ * Changed PSIZE to PAGESIZE to avoid NT conflict
+ *
+ * Rev 1.1 23 Jul 1992 08:47:08 STEVEN
+ * fix warnings
+ *
+ * Rev 1.0 09 May 1991 13:33:26 HUNTER
+ * Initial revision.
+
+**/
+/* $end$ */
+
+#ifndef _VM_H
+
+#define _VM_H
+
+/*
+ The following critical errors are defined
+*/
+#define VM_ERRORS 1000
+
+#define VM_READ_ERROR VM_ERRORS + 1
+#define VM_SEEK_ERROR VM_ERRORS + 2
+#define VM_WRITE_ERROR VM_ERRORS + 3
+#define VM_ALL_PAGES_LOCKED VM_ERRORS + 4
+#define VM_UNABLE_TO_LOAD_PAGE VM_ERRORS + 5
+#define VM_UNBALANCED_LOCKS VM_ERRORS + 6
+#define VM_EMS_ERROR VM_ERRORS + 7
+
+/* define vm handle */
+typedef struct VM_STR *VM_HDL ;
+
+/*
+ Virtual Memory Function & Definitions
+*/
+typedef UINT32 VM_PTR ;
+
+/*
+ You can change the number of pages of Virtual Memory available by
+ changing the size of the PAGE field. Current Maximum is 32K pages.
+
+ You can change the maximum size of the page by changing the PAGESIZE field.
+ Current maximum is a 32K page. Although pages can be any size, they
+ must be at least as big as the largest structure + sizeof( PAGESIZE ).
+ Memory will not be allocated across page boundaries.
+
+*/
+typedef INT16 PAGE ;
+typedef INT16 PAGESIZE ;
+
+
+/* Define function prototype for critical error routine */
+typedef VOID ( *VM_PF_CERR ) ( VOID_PTR, INT16 ) ;
+
+/*
+ To create a Virtual Memory session call VM_InitVM(). To terminate a
+ Virtual Memory session call VM_RemoveVM().
+*/
+VM_HDL VM_InitVM( PAGE num_pages, PAGESIZE page_size, PAGE num_pages_in_mem,
+ CHAR_PTR vm_filename, VM_PF_CERR critical_error,
+ VOID_PTR app_ptr ) ;
+
+VOID VM_RemoveVM( VM_HDL vm_hdl ) ;
+/*
+ Note: When a critical error occurs, the "critical_error" routine
+ shall be called (See VM_InitVM()). The critical error routine shall
+ not call "VM_RemoveVM()" unless it will not return from the "critical_
+ error" routine. There may be multiple "critical_error" messages
+ when an error is detected. When a critical error occurs, the
+ VM manager is in an unstable state. The application should either
+ abort, or, once the call to the VM Manager that caused the error has
+ returned close the VM Manager.
+
+ To allocate a block of virtual memory the user calls VM_Alloc(). To
+ free the block call VM_Free.
+*/
+VM_PTR VM_Alloc( VM_HDL vm_hdl, UINT16 size ) ;
+
+VOID VM_Free( VM_HDL vm_hdl, VM_PTR vm_buf ) ;
+
+/*
+ Before accessing the data block, the user must call "VM_MemLock". Once
+ the user has finished using the block call "VM_MemUnLock()".
+
+ There are two different VM_MemLock() modes. If you are writing to the
+ memory after it is locked, then use "VM_READ_WRITE". If you will
+ only be reading from the locked block use "VM_READ_ONLY".
+*/
+#define VM_READ_ONLY ((UINT16)0)
+#define VM_READ_WRITE ((UINT16)1)
+
+VOID_PTR VM_MemLock( VM_HDL vm_hdl, VM_PTR vm_buf, INT16 mode ) ;
+VOID VM_MemUnLock( VM_HDL vm_hdl, VM_PTR vm_buf ) ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/vqueue.h b/private/utils/ntbackup/inc/vqueue.h
new file mode 100644
index 000000000..e3bf1064d
--- /dev/null
+++ b/private/utils/ntbackup/inc/vqueue.h
@@ -0,0 +1,119 @@
+/************************
+Copyright(c) 1993, Conner Software Products Group. All Rights Reserved.
+
+
+ Name: vqueue.h
+
+ Description: Under OS_DOS, these routines perform queue operations
+ on queues where: the Q_HEADER is in conventional
+ memory ( or locked virtual ), and the queue itself
+ consists of virtual memory objects.
+
+ For any other OS, where VM stuff is stubbed out,
+ all vm- calls actually map to the corresponding regular
+ queue calls (with casts out the wazoo to prevent
+ compiler warnings)
+
+ It is VERY, VERY, VERY important that the VQ_HEADER keep
+ 'in-synch' with Q_HEADER, and likewise with VQ_ELEM and
+ Q_ELEM. Field names should be the same, and must be in
+ the same position and the same size (although not the
+ same type).
+
+ $Log: M:/LOGFILES/VQUEUE.H_V $
+
+ Rev 1.5 03 Aug 1993 09:13:08 JOHNES
+Got rid of a ; that was causing Watcomm errors. Got rid of type casts in
+some #defines.
+
+ Rev 1.4 21 Jul 1993 09:04:32 DON
+Cast fake define to avoid compiler noise
+
+ Rev 1.3 08 Jul 1993 10:47:36 ChuckS
+Added prototypes for vmLockVQueuePtr and vmUnlockVQueuePtr. Also
+added Q_PTR_SIZE modifier to typedef for VQ_ELEM_PTR.
+
+ Rev 1.2 09 Jun 1993 15:57:06 MIKEP
+enable c++
+
+ Rev 1.1 13 May 1993 18:24:42 Stefan
+Fixup the IFDEFs for the strangeness that is OS_WIN.
+
+ Rev 1.0 13 May 1993 14:10:40 ChuckS
+Initial revision
+
+**************************/
+
+#ifndef _vqueue_h_
+#define _vqueue_h_
+
+#ifndef QUEUES
+#include "queues.h"
+#endif
+
+#ifndef _VM_H
+#include "vm.h"
+#endif
+
+typedef VM_PTR VQ_HDL ;
+
+typedef struct VQ_HEADER Q_PTR_SIZE *VQ_HEADER_PTR;
+typedef struct VQ_HEADER {
+ VQ_HDL q_head ; /* head element of the queue */
+ VQ_HDL q_tail ; /* tail element of the queue */
+ INT16 q_count ; /* count of elements */
+ BOOLEAN q_active ; /* Is this queue active */
+ INT16 q_magic ; /* for q_element number */
+} VQ_HEADER ;
+
+
+typedef struct VQ_ELEM Q_PTR_SIZE *VQ_ELEM_PTR;
+typedef struct VQ_ELEM {
+ VQ_HDL q_prev ; /* previous queue element */
+ VQ_HDL q_next ; /* next element */
+ INT32 q_priority ; /* priority of queue */
+ INT16 q_element ; /* element number */
+ VQ_HDL q_ptr ; /* VM handle of current element */
+} VQ_ELEM ;
+
+#if defined( OS_DOS ) && !defined( OS_WIN )
+
+
+VM_PTR vmEnQueueElem( VQ_HEADER_PTR queue, VM_PTR element, BOOLEAN wpriority ) ;
+VM_PTR vmDeQueueElem( VQ_HEADER_PTR queue ) ;
+VM_PTR vmInsertElem( VQ_HEADER_PTR queue, VM_PTR cur_elem, VM_PTR ins_elem , UINT16 boa ) ;
+BOOLEAN vmRemoveQueueElem( VQ_HEADER_PTR queue, VM_PTR element ) ;
+VOID vmSetVMHandle( VM_HDL vm_hdl ) ;
+VOID vmInitQueue( VQ_HEADER_PTR queue ) ;
+VOID vmInitQElem( VQ_ELEM_PTR elem ) ;
+INT vmLockVQueuePtr( VQ_ELEM_PTR pElem, BOOLEAN for_write ) ;
+VOID vmUnlockVQueuePtr( VQ_ELEM_PTR pElem ) ;
+
+#else
+
+#define vmEnQueueElem( queue, elem, wpriority ) ( (VQ_HDL) EnQueueElem( (Q_HEADER_PTR) queue, (Q_ELEM_PTR) elem, wpriority ) )
+#define vmDeQueueElem( queue ) ( (VQ_HDL) DeQueueElem( (Q_HEADER_PTR) queue ) )
+#define vmInsertElem( queue, cur_el, new_el, boa ) ( (VQ_HDL) InsertElem( (Q_HEADER_PTR) queue, (Q_ELEM_PTR) cur_el, (Q_ELEM_PTR) new_el, boa ) )
+#define vmRemoveQueueElem( queue, elem ) RemoveQueueElem( (Q_HEADER_PTR) queue, (Q_ELEM_PTR) elem )
+#define vmSetVMHandle( vm_hdl ) /* -- this space intentionally blank -- */
+#define vmInitQueue( queue ) InitQueue( (Q_HEADER_PTR) queue )
+#define vmInitQElem( elem ) InitQElem( (Q_ELEM_PTR) elem )
+#define vmLockVQueuePtr( pElem, for_write ) (VOID)( SUCCESS ) // fake return SUCCESS from function
+#define vmUnlockVQueuePtr( pElem ) /* -- this space intentionally blank -- */
+
+#endif
+
+#define vmQueueHead( queue ) ( (VQ_HDL) QueueHead( (Q_HEADER_PTR) queue ) )
+#define vmQueueTail( queue ) ( (VQ_HDL) QueueTail( (Q_HEADER_PTR) queue ) )
+#define vmQueueNext( element ) ( (VQ_HDL) QueueNext( (Q_ELEM_PTR) element ) )
+#define vmQueuePrev( element ) ( (VQ_HDL) QueuePrev( (Q_ELEM_PTR) element ) )
+#define vmQueuePtr( element ) ( (VQ_HDL) QueuePtr( (Q_ELEM_PTR) element ) )
+#define vmQueueCount( queue ) ( QueueCount( (Q_HEADER_PTR) queue ) )
+#define vmQueueElemNo( element ) ( QueueElemNo( (Q_ELEM_PTR) element ) )
+
+#define vmGetQueueElemPriority( elem_ptr ) GetQueueElemPriority( (Q_ELEM_PTR) elem_ptr )
+#define vmSetQueueElemPriority( elem_ptr, value ) SetQueueElemPriority( (Q_ELEM_PTR) elem_ptr, (VQ_HDL) value )
+#define vmGetQueueElemPtr( elem_ptr ) GetQueueElemPtr( (Q_ELEM_PTR) elem_ptr )
+#define vmSetQueueElemPtr( elem_ptr, value ) SetQueueElemPtr( (Q_ELEM_PTR) elem_ptr, (VQ_HDL) value )
+
+#endif
diff --git a/private/utils/ntbackup/inc/wcs.h b/private/utils/ntbackup/inc/wcs.h
new file mode 100644
index 000000000..cbcf4a5e1
--- /dev/null
+++ b/private/utils/ntbackup/inc/wcs.h
@@ -0,0 +1,63 @@
+/**************************************************
+Copyright (C) Maynard, An Archive Company. 1992
+
+ Name: WCS.H
+
+ Description:
+
+ Wide string functions for using unicode strings under MSC 6.0
+ and not having a library to use. If you add a function, add
+ it to WCS.C, WCS.H, and MAPPINGS.H
+
+ $Log: G:/UI/LOGFILES/WCS.H_V $
+
+ Rev 1.1 10 Jun 1992 17:52:14 STEVEN
+not needed for win32
+
+ Rev 1.0 04 May 1992 13:33:40 MIKEP
+Initial revision.
+
+
+****************************************************/
+
+// Unicode string functions.
+
+#ifndef OS_WIN32
+
+INT wcslen( WCHAR_PTR s );
+WCHAR_PTR wcscpy( WCHAR_PTR s, WCHAR_PTR t );
+WCHAR_PTR wcsncpy( WCHAR_PTR s, WCHAR_PTR t, INT i );
+WCHAR_PTR wcscat( WCHAR_PTR s, WCHAR_PTR t );
+WCHAR_PTR wcsncat( WCHAR_PTR s, WCHAR_PTR t, INT i );
+INT wcscmp( WCHAR_PTR s, WCHAR_PTR t );
+INT wcsncmp( WCHAR_PTR s, WCHAR_PTR t, INT i );
+INT wcsicmp( WCHAR_PTR s, WCHAR_PTR t );
+INT wcsnicmp( WCHAR_PTR s, WCHAR_PTR t, INT i );
+WCHAR_PTR wcsrchr( WCHAR_PTR s, INT c );
+WCHAR_PTR wcschr( WCHAR_PTR s, INT c );
+WCHAR_PTR wcspbrk( WCHAR_PTR s, WCHAR_PTR t );
+WCHAR_PTR wcslwr( WCHAR_PTR s );
+WCHAR_PTR wcsupr( WCHAR_PTR s );
+WCHAR_PTR wcsstr( WCHAR_PTR s, WCHAR_PTR t );
+
+// ANSI Strings for use if UNICODE is defined.
+
+INT strlenA( ACHAR_PTR s );
+ACHAR_PTR strcpyA( ACHAR_PTR s, ACHAR_PTR t );
+ACHAR_PTR strncpyA( ACHAR_PTR s, ACHAR_PTR t, INT i );
+ACHAR_PTR strcatA( ACHAR_PTR s, ACHAR_PTR t );
+ACHAR_PTR strncatA( ACHAR_PTR s, ACHAR_PTR t, INT i );
+INT strcmpA( ACHAR_PTR s, ACHAR_PTR t );
+INT strncmpA( ACHAR_PTR s, ACHAR_PTR t, INT i );
+INT stricmpA( ACHAR_PTR s, ACHAR_PTR t );
+INT strnicmpA( ACHAR_PTR s, ACHAR_PTR t, INT i );
+ACHAR_PTR strrchrA( ACHAR_PTR s, INT c );
+ACHAR_PTR strchrA( ACHAR_PTR s, INT c );
+ACHAR_PTR strpbrkA( ACHAR_PTR s, ACHAR_PTR t );
+ACHAR_PTR strlwrA( ACHAR_PTR s );
+ACHAR_PTR struprA( ACHAR_PTR s );
+ACHAR_PTR strstrA( ACHAR_PTR s, ACHAR_PTR t );
+
+#endif
+
+
diff --git a/private/utils/ntbackup/inc/win3216.h b/private/utils/ntbackup/inc/win3216.h
new file mode 100644
index 000000000..42cfaea51
--- /dev/null
+++ b/private/utils/ntbackup/inc/win3216.h
@@ -0,0 +1,54 @@
+/* NOTE: The SIZE type is new to 16 bit Windows and will soon be incorporated
+ into the distributed Windows 3.1 header file. You must include this
+ typedef in your code until this change is made.
+*/
+typedef struct tagSIZE
+ {
+ int cx;
+ int cy;
+ } SIZE;
+typedef SIZE *PSIZE;
+typedef SIZE NEAR *NPSIZE;
+typedef SIZE FAR *LPSIZE;
+
+// MACROS
+
+
+#if (WINVER < 0x030a)
+
+#ifdef RectVisible
+
+#undef RectVisible
+#undef RectVisibleOld
+#define RectVisible RectVisible
+#define RectVisibleOld RectVisible
+
+#endif
+
+BOOL WINAPI RectVisible(HDC, RECT FAR*);
+
+#endif
+
+// FUNCTION PROTOTYPES
+
+BOOL FAR PASCAL DlgDirSelectEx(HWND, LPSTR, int, int);
+BOOL FAR PASCAL DlgDirSelectComboBoxEx(HWND, LPSTR, int, int);
+BOOL FAR PASCAL GetAspectRatioFilterEx(HDC, LPSIZE);
+BOOL FAR PASCAL GetBitmapDimensionEx(HBITMAP, LPSIZE);
+BOOL FAR PASCAL GetBrushOrgEx(HDC, LPPOINT);
+BOOL FAR PASCAL GetCurrentPositionEx(HDC, LPPOINT);
+BOOL FAR PASCAL GetTextExtentPoint(HDC, LPSTR, int, LPSIZE);
+BOOL FAR PASCAL GetViewportExtEx(HDC, LPSIZE);
+BOOL FAR PASCAL GetViewportOrgEx(HDC, LPPOINT);
+BOOL FAR PASCAL GetWindowExtEx(HDC, LPSIZE);
+BOOL FAR PASCAL GetWindowOrgEx(HDC, LPPOINT);
+BOOL FAR PASCAL OffsetViewportOrgEx(HDC, int, int, LPPOINT);
+BOOL FAR PASCAL OffsetWindowOrgEx(HDC, int, int, LPPOINT);
+BOOL FAR PASCAL MoveToEx(HDC, int, int, LPPOINT);
+BOOL FAR PASCAL ScaleViewportExtEx(HDC, int, int, int, int, LPSIZE);
+BOOL FAR PASCAL ScaleWindowExtEx(HDC, int, int, int, int, LPSIZE);
+BOOL FAR PASCAL SetBitmapDimensionEx(HBITMAP, int, int, LPSIZE);
+BOOL FAR PASCAL SetViewportExtEx(HDC, int, int, LPSIZE);
+BOOL FAR PASCAL SetViewportOrgEx(HDC, int, int, LPPOINT);
+BOOL FAR PASCAL SetWindowExtEx(HDC, int, int, LPSIZE);
+BOOL FAR PASCAL SetWindowOrgEx(HDC, int, int, LPPOINT);
diff --git a/private/utils/ntbackup/inc/winmang.h b/private/utils/ntbackup/inc/winmang.h
new file mode 100644
index 000000000..242a7f0a9
--- /dev/null
+++ b/private/utils/ntbackup/inc/winmang.h
@@ -0,0 +1,550 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: winmang.h
+
+ Description: This file contains the definitions, macros, and function
+ prototypes for the Maynstream GUI Window Manager (WM).
+
+ $Log: G:/UI/LOGFILES/WINMANG.H_V $
+
+ Rev 1.33 23 Sep 1993 15:52:46 GLENN
+Added poll drive user message ID.
+
+ Rev 1.32 13 Aug 1993 15:22:20 GLENN
+Removed ifdef around sort IDs.
+
+ Rev 1.31 09 Jun 1993 15:09:22 MIKEP
+enable c++
+
+
+ Rev 1.30 07 May 1993 14:23:26 DARRYLP
+Added Rob's changes for delete key trappings
+
+ Rev 1.29 26 Apr 1993 08:36:30 MIKEP
+Added ID_VIEWFONT to call vlm_changesettings with. This allows
+the vlm area to refresh all windows in case the font changed case
+for FAT drives.
+
+ Rev 1.28 22 Apr 1993 16:01:10 GLENN
+Added file SORT option support.
+
+ Rev 1.27 21 Apr 1993 16:07:06 GLENN
+Changed window classes to be unique for Nostradamus and Cayman.
+
+ Rev 1.26 07 Apr 1993 16:28:30 GLENN
+Changed APP specific class names to have a prefix of CBE - Conner Backup Exec.
+
+ Rev 1.25 01 Nov 1992 16:33:52 DAVEV
+Unicode changes
+
+ Rev 1.24 14 Oct 1992 15:56:44 GLENN
+Added Wait Cursor HIDE, SHOW, PAUSE, RESUME, features to guarantee Hourglass when our App is busy.
+
+ Rev 1.23 04 Oct 1992 19:50:04 DAVEV
+UNICODE AWK PASS
+
+ Rev 1.22 02 Oct 1992 16:51:32 GLENN
+Added WM_SetCursor().
+
+ Rev 1.21 10 Jul 1992 10:14:24 GLENN
+In process of adding font selection support.
+
+ Rev 1.20 19 Mar 1992 11:45:12 JOHNWT
+added WM_MakeAppActive
+
+ Rev 1.19 16 Mar 1992 15:37:22 JOHNWT
+fixed WM_TerminateApp
+
+ Rev 1.18 10 Mar 1992 16:39:50 GLENN
+Added WM_MoveWindow().
+
+ Rev 1.17 09 Mar 1992 09:20:52 GLENN
+Added logo bitmap support.
+
+ Rev 1.16 03 Mar 1992 17:27:48 GLENN
+Added new view window support.
+
+ Rev 1.15 20 Feb 1992 11:21:24 GLENN
+Removed WM_IsActiveDocMax... different way of doing it now to support NT.
+
+ Rev 1.14 18 Feb 1992 20:48:40 GLENN
+Changed WMSIZE types.
+
+ Rev 1.13 18 Feb 1992 18:48:44 GLENN
+Added support routines for auto min/max/restore of MDI docs before/after an operation/
+
+ Rev 1.12 11 Feb 1992 17:32:16 GLENN
+Added support for MDI client subclassing.
+
+ Rev 1.11 10 Feb 1992 09:15:10 GLENN
+Moved the WM_USER IDs to a common location.
+
+ Rev 1.10 04 Feb 1992 15:01:28 STEVEN
+added macro for point conversion
+
+ Rev 1.9 29 Jan 1992 17:57:08 GLENN
+DLM command ID.
+
+ Rev 1.8 21 Jan 1992 13:34:02 GLENN
+Added WM_AnimateAppIcon() proto.
+
+ Rev 1.7 07 Jan 1992 17:24:02 GLENN
+Added MDI split/slider support
+
+ Rev 1.6 10 Dec 1991 13:55:44 GLENN
+Added defines for the creation of single column flat list boxes
+
+ Rev 1.5 05 Dec 1991 17:43:54 GLENN
+Changed get active doc macro
+
+ Rev 1.4 05 Dec 1991 11:25:18 DAVEV
+16/32 bit Windows port changes - 1st pass
+
+ Rev 1.3 04 Dec 1991 18:15:46 GLENN
+Added terminate app macro.
+
+ Rev 1.2 03 Dec 1991 16:03:00 GLENN
+Added a bunch of IDs for Keyboard character support.
+
+ Rev 1.1 27 Nov 1991 13:36:22 GLENN
+Added macros for filling out the window manager data structure.
+
+ Rev 1.0 20 Nov 1991 19:40:16 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+
+
+#ifndef WINMANG_H
+
+#define WINMANG_H
+
+
+// Window Creation Types
+
+#define WM_TYPE_BITS 0x00FF
+#define WM_MINMAX_BITS 0x0300
+#define WM_STYLE_BITS 0x3C00
+#define WM_MENU_BITS 0xC000
+
+#define WM_FRAME 0
+#define WM_CLIENT 1
+#define WM_RIBBON 2
+#define WM_MDIPRIMARY 3
+#define WM_MDISECONDARY 4
+#define WM_DDECLIENT 5
+#define WM_DDESERVER 6
+#define WM_SERVER 7
+#define WM_DEBUG 8
+#define WM_DUMB 9
+
+#define WM_MIN 0x0100
+#define WM_MAX 0x0200
+
+#define WM_VIEWWIN 0x0000
+#define WM_FLATLISTMC 0x1000 // FLAT LIST MULTI-COLUMN
+#define WM_TREELISTSC 0x2000 // TREE LIST SINGLE-COLUMN
+#define WM_FLATLISTSC 0x0400 // FLAT LIST SINGLE-COLUMN -- ODD TYPES
+#define WM_TREELISTMC 0x0800 // TREE LIST MULTI-COLUMN -- ODD TYPES
+#define WM_FLATLIST WM_FLATLISTMC
+#define WM_TREELIST WM_TREELISTSC
+#define WM_TREEANDFLATMC ( WM_TREELISTSC | WM_FLATLISTMC )
+#define WM_TREEANDFLATSC ( WM_TREELISTSC | WM_FLATLISTSC )
+
+#define WM_MENUS 0x4000
+
+// Undocumented Windows Messages
+
+#define WM_LBTRACKPOINT 0x0131
+
+// Window Sizes
+
+#define WMSIZE_NORMAL 0
+#define WMSIZE_MIN 1
+#define WMSIZE_MAX 2
+#define WMSIZE_IGNORE 3
+#define WMSIZE_UNKNOWN -1
+
+// Application Window Types
+
+#define WMTYPE_DISKS 0
+#define WMTYPE_TAPES 1
+#define WMTYPE_MACROS 2
+#define WMTYPE_JOBS 3
+#define WMTYPE_DISKTREE 4
+#define WMTYPE_TAPETREE 5
+#define WMTYPE_DISKFILES 6
+#define WMTYPE_TAPEFILES 7
+#define WMTYPE_SERVERS 8
+#define WMTYPE_LOGFILES 9
+#define WMTYPE_DEBUG 10
+#define WMTYPE_SEARCH 11
+#define WMTYPE_LOGVIEW 12
+#ifdef OEM_EMS
+#define WMTYPE_EXCHANGE 13
+#endif
+
+// Application message IDs
+
+#define ID_FLATONLY IDM_VIEWDIRONLY
+#define ID_TREEONLY IDM_VIEWTREEONLY
+#define ID_TREEANDFLAT IDM_VIEWTREEANDDIR
+#define ID_FILEDETAILS IDM_VIEWALLFILEDETAILS
+#define ID_EXPANDALL IDM_TREEEXPANDALL
+#define ID_EXPANDBRANCH IDM_TREEEXPANDBRANCH
+#define ID_EXPANDONE IDM_TREEEXPANDONE
+#define ID_COLLAPSEBRANCH IDM_TREECOLLAPSEBRANCH
+#define ID_INDICATORS IDM_TREESHOWINDICATORS
+#define ID_SELECT IDM_SELECTCHECK
+#define ID_DESELECT IDM_SELECTUNCHECK
+#define ID_MODIFIED IDM_SELECTMODIFIEDFILES
+#define ID_ADVANCED IDM_SELECTADVANCED
+#define ID_REFRESH IDM_WINDOWSREFRESH
+#define ID_CLOSEALL IDM_WINDOWSCLOSEALL
+#define ID_VIEWFONT IDM_VIEWFONT
+#define ID_SORTNAME IDM_VIEWSORTNAME
+#define ID_SORTTYPE IDM_VIEWSORTTYPE
+#define ID_SORTSIZE IDM_VIEWSORTSIZE
+#define ID_SORTDATE IDM_VIEWSORTDATE
+
+#define ID_SERVERS 1
+#define ID_RESTORETODRIVE 2
+#define ID_CTRLARROWUP 3
+#define ID_CTRLARROWDOWN 4
+#define ID_ARROWLEFT 5
+#define ID_ARROWRIGHT 6
+#define ID_NAMEONLY 7
+#define ID_FONTCASECHANGE 8
+#define ID_DELETE 9
+
+#define WM_CLIENT_ID 0xCAC // The Client Window ID.
+
+#define WM_DEFAULT CW_USEDEFAULT // Use default window size.
+#define GWL_PDSWININFO 0 // The offset of the Window Info struct.
+#define GWW_HWNDEDIT 0
+#define GWW_CHANGED 2
+#define GWW_WORDWRAP 4
+#define GWW_UNTITLED 6
+#define DEBUG_EXTRA 8
+
+// APPLICATION DEFINED CLASS NAMES
+
+#ifdef OEM_MSOFT
+
+ #define WMCLASS_FRAME TEXT("NTBframe") // Class name for the frame window.
+ #define WMCLASS_DOC TEXT("NTBdoc") // Class name for MDI document windows.
+ #define WMCLASS_RIBBON TEXT("NTBribbon") // Class name for the ribbon windows.
+ #define WMCLASS_DDECLIENT TEXT("NTBddeclient") // Class name for the ddeclient windows.
+ #define WMCLASS_LAUNCHER TEXT("NTBlauncher") // Class name for the launcher window.
+ #define WMCLASS_VIEWWIN TEXT("NTBviewwin") // Class name for the dumb window.
+ #define WMCLASS_LOGO TEXT("NTBlogo") // Class name for the logo window.
+
+#else
+
+ #define WMCLASS_FRAME TEXT("CBEframe") // Class name for the frame window.
+ #define WMCLASS_DOC TEXT("CBEdoc") // Class name for MDI document windows.
+ #define WMCLASS_RIBBON TEXT("CBEribbon") // Class name for the ribbon windows.
+ #define WMCLASS_DDECLIENT TEXT("CBEddeclient") // Class name for the ddeclient windows.
+ #define WMCLASS_LAUNCHER TEXT("CBElauncher") // Class name for the launcher window.
+ #define WMCLASS_VIEWWIN TEXT("CBEviewwin") // Class name for the dumb window.
+ #define WMCLASS_LOGO TEXT("CBElogo") // Class name for the logo window.
+
+#endif
+
+// WINDOWS INTERNAL CLASS NAMES
+
+#define WMCLASS_CLIENT TEXT("mdiclient") // Class name for the MDI client window.
+#define WMCLASS_LISTBOX TEXT("listbox") // Class name for the list box windows.
+
+
+#define WMIDC_TREELISTBOX 1
+#define WMIDC_FLATLISTBOX 2
+
+#define WM_TREELISTBOX ( WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_BORDER | \
+ LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT | \
+ WS_VSCROLL )
+#define WM_FLATLISTBOXMC ( WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_BORDER | \
+ LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT | \
+ LBS_EXTENDEDSEL | LBS_MULTICOLUMN )
+#define WM_FLATLISTBOXSC ( WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | WS_BORDER | \
+ LBS_NOTIFY | LBS_OWNERDRAWFIXED | LBS_NOINTEGRALHEIGHT | \
+ LBS_EXTENDEDSEL )
+
+#define WMSTYLE_VIEWWIN ( WS_CHILD | WS_BORDER | WS_VISIBLE | CS_HREDRAW | CS_VREDRAW )
+#define WMSTYLE_LOGO ( WS_POPUP | WS_BORDER | WS_VISIBLE )
+
+// DOC WINDOW AND LIST BOX BIT MASKS
+
+#define WMDOC_VIEWWIN 0x0000
+#define WMDOC_TREEANDFLAT 0x0001
+#define WMDOC_TREESC 0x0002
+#define WMDOC_TREEMC 0x0020
+#define WMDOC_FLATMC 0x0004
+#define WMDOC_FLATSC 0x0040
+#define WMDOC_SLIDER 0x0008
+#define WMDOC_TREE WMDOC_TREESC
+#define WMDOC_FLAT WMDOC_FLATMC
+
+#define WM_SLIDERUNKNOWN 0x7FF0
+#define WM_SLIDERMAX 0x7FF1
+#define WM_SLIDERMIN 0x7FF2
+
+// DOC SLIDER DEFINITIONS
+
+#define WMDOC_SLIDERON 0x0001
+#define WMDOC_SLIDERMOVE 0x0002
+#define WMDOC_SLIDEROFF 0x0004
+#define WMDOC_SLIDERCANCEL 0x0008
+
+#define DOC_N_STATUS_HEIGHT (DOC_RIBBON_HEIGHT+STATUS_LINE_HEIGHT)
+#define NONMDICLIENT_HEIGHT (DOC_N_STATUS_HEIGHT+MAIN_RIBBON_HEIGHT)
+
+// SHOW WAIT CURSOR IDs
+
+#define SWC_HIDE FALSE
+#define SWC_SHOW TRUE
+#define SWC_PAUSE ((BOOL)2)
+#define SWC_RESUME ((BOOL)3)
+
+// EXTRA WINDOWS FRAME MESSAGE IDs -- WM_USER+200 through WM_USER+209
+
+#define WM_SETTINGSCHANGED (WM_USER+201)
+#define WM_INITAPPLICATION (WM_USER+203)
+#define WM_DEVICEDRIVERMSG (WM_USER+204)
+
+#define WM_PUBLISHRUNNINGJOB (WM_USER+206) // Used by Winter Park to
+ // tell the launcher which
+ // job is running.
+#define WM_SCHEDULESUPDATED (WM_USER+207) // Used by Winter Park to
+ // tell the launcher to update
+ // it's list of scheduled jobs.
+#define WM_QUERYRUNNINGJOB (WM_USER+208) // Used by Launcher only
+#define WM_POLLDRIVEMSG (WM_USER+209) // Used when poll drive exits
+ // timer callback.
+
+#define WM_DLMDBCLK (WM_USER+300)
+#define WM_DLMDOWN (WM_USER+301)
+#define WM_DLMCLICK (WM_USER+302)
+#define WM_DLMUPDATEITEM (WM_USER+303)
+#define WM_DLMUPDATELIST (WM_USER+304)
+#define WM_DLMDELETEITEMS (WM_USER+305)
+#define WM_DLMADDITEMS (WM_USER+306)
+#define WM_DLMCHAR (WM_USER+307)
+
+#ifdef NTKLUG
+#define WM_DLMGETTEXT (WM_USER+399)
+#endif
+
+#define WM_MSGBOXDRAWTXT (WM_USER+400)
+
+
+typedef struct DS_WMINFO far *DS_WMINFO_PTR;
+typedef struct DS_WMINFO far *PDS_WMINFO;
+typedef struct DS_WMINFO {
+
+ WORD wType;
+ HWND hWnd;
+ HWND hWndTreeList;
+ HWND hWndFlatList;
+ HWND hWndActiveList;
+ HRIBBON hRibbon;
+ HCURSOR hCursor;
+ HCURSOR hDragCursor;
+ HICON hIcon;
+ DWORD dwRibbonState;
+ DWORD dwMenuState;
+ DWORD dwWindowState;
+ INT nSliderPos;
+ DLM_HEADER_PTR pTreeDisp;
+ DLM_HEADER_PTR pFlatDisp;
+ Q_HEADER_PTR pTreeList;
+ Q_HEADER_PTR pFlatList;
+ PVOID pAppInfo;
+ WORD wClosable;
+ BOOL fChanged;
+ WORD wHelpID;
+ WORD wStatusLineID;
+ CHAR_PTR pTitle;
+ CHAR_PTR pMinTitle;
+ INT nSize;
+
+} DS_WMINFO;
+
+// WINDOW MANAGER DATA STRUCTURE GET AND SET MACROS
+
+
+#define WMDS_GetWinType( x ) ( (x)->wType )
+#define WMDS_SetWinType( x, v ) ( (x)->wType = ( v ) )
+
+#define WMDS_GetWin( x ) ( (x)->hWnd )
+#define WMDS_SetWin( x, v ) ( (x)->hWnd = ( v ) )
+
+#define WMDS_GetWinTreeList( x ) ( (x)->hWndTreeList )
+#define WMDS_SetWinTreeList( x, v ) ( (x)->hWndTreeList = ( v ) )
+
+#define WMDS_GetWinFlatList( x ) ( (x)->hWndFlatList )
+#define WMDS_SetWinFlatList( x, v ) ( (x)->hWndFlatList = ( v ) )
+
+#define WMDS_GetWinActiveList( x ) ( (x)->hWndActiveList )
+#define WMDS_SetWinActiveList( x, v ) ( (x)->hWndActiveList = ( v ) )
+
+#define WMDS_GetRibbon( x ) ( (x)->hRibbon )
+#define WMDS_SetRibbon( x, v ) ( (x)->hRibbon = ( v ) )
+
+#define WMDS_GetCursor( x ) ( (x)->hCursor )
+#define WMDS_SetCursor( x, v ) ( (x)->hCursor = ( v ) )
+
+#define WMDS_GetDragCursor( x ) ( (x)->hDragCursor )
+#define WMDS_SetDragCursor( x, v ) ( (x)->hDragCursor = ( v ) )
+
+#define WMDS_GetIcon( x ) ( (x)->hIcon )
+#define WMDS_SetIcon( x, v ) ( (x)->hIcon = ( v ) )
+
+#define WMDS_GetRibbonState( x ) ( (x)->dwRibbonState )
+#define WMDS_SetRibbonState( x, v ) ( (x)->dwRibbonState = ( v ) )
+
+#define WMDS_GetMenuState( x ) ( (x)->dwMenuState )
+#define WMDS_SetMenuState( x, v ) ( (x)->dwMenuState = ( v ) )
+
+#define WMDS_GetWindowState( x ) ( (x)->dwWindowState )
+#define WMDS_SetWindowState( x, v ) ( (x)->dwWindowState = ( v ) )
+
+#define WMDS_GetSliderPos( x ) ( (x)->nSliderPos )
+#define WMDS_SetSliderPos( x, v ) ( (x)->nSliderPos = ( v ) )
+
+#define WMDS_GetTreeDisp( x ) ( (x)->pTreeDisp )
+#define WMDS_SetTreeDisp( x, v ) ( (x)->pTreeDisp = ( v ) )
+
+#define WMDS_GetFlatDisp( x ) ( (x)->pFlatDisp )
+#define WMDS_SetFlatDisp( x, v ) ( (x)->pFlatDisp = ( v ) )
+
+#define WMDS_GetTreeList( x ) ( (x)->pTreeList )
+#define WMDS_SetTreeList( x, v ) ( (x)->pTreeList = ( v ) )
+
+#define WMDS_GetFlatList( x ) ( (x)->pFlatList )
+#define WMDS_SetFlatList( x, v ) ( (x)->pFlatList = ( v ) )
+
+#define WMDS_GetAppInfo( x ) ( (x)->pAppInfo )
+#define WMDS_SetAppInfo( x, v ) ( (x)->pAppInfo = ( v ) )
+
+#define WMDS_GetWinClosable( x ) ( (x)->wClosable )
+#define WMDS_SetWinClosable( x, v ) ( (x)->wClosable = ( v ) )
+
+#define WMDS_GetWinChanged( x ) ( (x)->fChanged )
+#define WMDS_SetWinChanged( x, v ) ( (x)->fChanged = ( v ) )
+
+#define WMDS_GetWinHelpID( x ) ( (x)->wHelpID )
+#define WMDS_SetWinHelpID( x, v ) ( (x)->wHelpID = ( v ) )
+
+#define WMDS_GetStatusLineID( x ) ( (x)->wStatusLineID )
+#define WMDS_SetStatusLineID( x, v ) ( (x)->wStatusLineID = ( v ) )
+
+#define WMDS_GetWinTitle( x ) ( (x)->pTitle )
+
+#define WMDS_GetWinMinTitle( x ) ( (x)->pMinTitle )
+
+#define WMDS_GetSize( x ) ( (x)->nSize )
+#define WMDS_SetSize( x, v ) ( (x)->nSize = ( v ) )
+
+
+// MACROS
+
+#define WM_Destroy( x ) (BOOL)SendMessage( ghWndMDIClient, WM_MDIDESTROY, (MP1)x, (MP2)0 )
+#define WM_GetActive( ) ( GetActiveWindow( ) )
+#define WM_GetActiveDoc( ) ( ( ghWndActiveDoc ) ? ghWndActiveDoc : (HWND)SendMessage( ghWndMDIClient, WM_MDIGETACTIVE, (MP1)0, (MP2)0 ) )
+#define WM_GetAppPtr( x ) ( (PDS_WMINFO)GetWindowLong( x, GWL_PDSWININFO ) )->pAppInfo
+#define WM_GetDC( x ) GetDC( x )
+#define WM_GetInfoPtr( x ) (PDS_WMINFO)GetWindowLong( x, GWL_PDSWININFO )
+#define WM_Hide( x ) ShowWindow( x, SW_HIDE )
+#define WM_IsActive( x ) ( x == GetActiveWindow () )
+#define WM_IsActiveDoc( x ) ( x == WM_GetActiveDoc () )
+#define WM_IsChildOf( x, y ) (BOOL)( IsChild( x, y ) )
+#define WM_IsFlatActive( x ) ( (x)->hWndFlatList == (x)->hWndActiveList )
+#define WM_IsMaximized( x ) (BOOL)( IsZoomed( x ) )
+#define WM_IsMinimized( x ) (BOOL)( IsIconic( x ) )
+#define WM_IsTreeActive( x ) ( (x)->hWndTreeList == (x)->hWndActiveList )
+#define WM_MaximizeDoc( x ) SendMessage( ghWndMDIClient, WM_MDIMAXIMIZE, (MP1)x, (MP2)0 )
+#define WM_MinimizeDoc( x ) ShowWindow( x, SW_SHOWMINNOACTIVE )
+#define WM_Minimize( x ) ShowWindow( x, SW_SHOWMINNOACTIVE )
+#define WM_Notify( x, y ) PostMessage( ghWndFrame, WM_SETTINGSCHANGED, (MP1)x, (MP2)y )
+#define WM_Restore( x ) ShowWindow( x, SW_SHOWNORMAL )
+#define WM_RestoreDoc( x ) SendMessage( ghWndMDIClient, WM_MDIRESTORE, (MP1)x, (MP2)0 )
+#define WM_SetActive( x ) SetActiveWindow( x )
+#define WM_SetActiveDoc( x ) SendMessage( ghWndMDIClient, WM_MDIACTIVATE, (MP1)x, (MP2)0 )
+#define WM_SetInfoPtr( x, y ) SetWindowLong( x, GWL_PDSWININFO, (DWORD)y )
+#define WM_Show( x ) ShowWindow( x, SW_SHOW )
+#define WM_TerminateApp( ) DestroyWindow( ghWndFrame )
+#define WM_Update( x ) UpdateWindow( x )
+
+#define WM_FromMP2toPOINT( a, b ) \
+ ( (a.y = (int)((b) >> 16)), (a.x = (int)((b) & 0xffff)) )
+
+// MACROS FOR PORTING
+
+#ifndef OS_WIN32
+#define EXTRACT_RIBBON_PARENT_HWND( x ) (LOWORD((DWORD)(x)))
+#define WM_GetClassCursor( x ) (HCURSOR)GetClassWord( x, GCW_HCURSOR )
+#define WM_GetClassIcon( x ) (HICON)GetClassWord( x, GCW_HICON )
+#define WM_SetClassCursor( x, y ) (HCURSOR)SetClassWord( x, GCW_HCURSOR, (WORD) y )
+#define WM_SetClassIcon( x, y ) (HICON)SetClassWord( x, GCW_HICON, (WORD) y )
+#else
+#define EXTRACT_RIBBON_PARENT_HWND( x ) ((HWND)(x))
+#define WM_GetClassCursor( x ) (HCURSOR)GetClassLong( x, GCL_HCURSOR )
+#define WM_GetClassIcon( x ) (HICON)GetClassLong( x, GCL_HICON )
+#define WM_SetClassCursor( x, y ) (HCURSOR)SetClassLong( x, GCL_HCURSOR,(LONG) y )
+#define WM_SetClassIcon( x, y ) (HICON)SetClassLong( x, GCL_HICON, (LONG) y )
+#endif
+
+
+
+// FUNCTION PROTOTYPES
+
+BOOL WM_AnimateAppIcon ( WORD, BOOL );
+VOID WM_CloseAllDocs ( VOID );
+BOOL WM_ChangeFont ( VOID );
+HWND WM_Create ( WORD, LPSTR, LPSTR, INT, INT, INT, INT, PDS_WMINFO );
+BOOL WM_CreateObjects ( VOID );
+VOID WM_CreatePrimDocs ( VOID );
+VOID WM_Deinit ( VOID );
+VOID WM_DeleteObjects ( VOID );
+VOID WM_DocActivate ( HWND );
+WORD WM_DocIsMenuChange ( HWND, WORD );
+BOOL WM_DocKeyDown ( HWND hWnd, WORD wKey );
+VOID WM_DocSetSliderMode ( HWND, WORD );
+VOID WM_FrameUpdate ( VOID );
+HICON WM_GetAppIcon ( VOID );
+HWND WM_GetNext ( HWND );
+BOOL WM_GetRect ( HWND );
+INT WM_GetTitle ( HWND, LPSTR, INT );
+BOOL WM_Init ( LPSTR, INT );
+VOID WM_LogoShow ( VOID );
+VOID WM_LogoDestroy ( VOID );
+VOID WM_MinimizeDocs ( VOID );
+VOID WM_MoveWindow ( HWND, INT, INT, INT, INT, BOOL );
+BOOL WM_QueryCloseAllDocs ( VOID );
+VOID WM_RestoreDocs ( VOID );
+HICON WM_SetAppIcon ( HICON );
+BOOL WM_SetCursor ( HWND );
+VOID WM_SetDocSizes ( VOID );
+VOID WM_SetMinTitle ( HWND, LPSTR );
+VOID WM_SetTitle ( HWND, LPSTR );
+VOID WM_SubClassListBox ( HWND );
+VOID WM_SubClassMDIClient ( HWND );
+VOID WM_ShowWaitCursor ( BOOL );
+VOID WM_MakeAppActive( VOID );
+
+// EXPORTED FUNCTIONS
+
+WINRESULT APIENTRY WM_FrameWndProc ( HWND, MSGID, MP1, MP2 );
+WINRESULT APIENTRY WM_MDIDocWndProc ( HWND, MSGID, MP1, MP2 );
+WINRESULT APIENTRY WM_RibbonWndProc ( HWND, MSGID, MP1, MP2 );
+WINRESULT APIENTRY WM_MDIClientWndProc ( HWND, MSGID, MP1, MP2 );
+WINRESULT APIENTRY WM_DocListWndProc ( HWND, MSGID, MP1, MP2 );
+WINRESULT APIENTRY WM_DDEClientWndProc ( HWND, MSGID, MP1, MP2 );
+WINRESULT APIENTRY WM_ViewWndProc ( HWND, MSGID, MP1, MP2 );
+
+#endif
diff --git a/private/utils/ntbackup/inc/xferblk.h b/private/utils/ntbackup/inc/xferblk.h
new file mode 100644
index 000000000..7995c8d01
--- /dev/null
+++ b/private/utils/ntbackup/inc/xferblk.h
@@ -0,0 +1,26 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-91
+
+ Name: xferblk.h
+
+ Description: Contains the global description for a transfer block
+
+ $Log: Q:/LOGFILES/XFERBLK.H_V $
+
+ Rev 1.0 17 Jul 1991 15:39:04 ED
+Initial revision.
+**/
+
+#ifndef XFERB
+
+#define XFERB
+
+typedef struct {
+ UINT8_PTR buffer ; /* buffer address */
+ UINT32 tcount ; /* total count */
+ UINT32 acount ; /* already transfered */
+ UINT16 count ; /* this transfer's req. count */
+ UINT16 xcount ; /* the amount transfered */
+} XBLK, *XBLK_PTR ;
+
+#endif
diff --git a/private/utils/ntbackup/inc/yes_no.h b/private/utils/ntbackup/inc/yes_no.h
new file mode 100644
index 000000000..15fe4c51c
--- /dev/null
+++ b/private/utils/ntbackup/inc/yes_no.h
@@ -0,0 +1,5 @@
+#define ID_YN_LINE_1 105
+#define ID_YN_LINE_2 106
+#define ID_YN_NO 108
+#define ID_YN_YES 107
+
diff --git a/private/utils/ntbackup/src/3dcheck.bmp b/private/utils/ntbackup/src/3dcheck.bmp
new file mode 100644
index 000000000..23d739342
--- /dev/null
+++ b/private/utils/ntbackup/src/3dcheck.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/addbsd.c b/private/utils/ntbackup/src/addbsd.c
new file mode 100644
index 000000000..de5baed6a
--- /dev/null
+++ b/private/utils/ntbackup/src/addbsd.c
@@ -0,0 +1,579 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: addbsd.c
+
+ Description: This file contains code to add and remove a Backup Set
+ Descriptor(BSD) from a BSD list.
+
+
+ $Log: J:/LOGFILES/ADDBSD.C_V $
+
+ Rev 1.26 21 Jul 1993 18:45:20 DON
+If NLM and SMS Object then insert in order presented by the SMDR!
+
+ Rev 1.25 19 Jul 1993 10:30:14 BARRY
+BSD_GetDLE changed to function call -- no longer have ptr to DLE.
+
+ Rev 1.24 08 Jun 1993 13:57:52 MIKEP
+Enable C++ compile.
+
+ Rev 1.23 18 Sep 1992 15:51:26 STEVEN
+fix spelling
+
+ Rev 1.22 17 Sep 1992 11:11:50 STEVEN
+add support for daily backup
+
+ Rev 1.21 09 Jul 1992 14:00:20 STEVEN
+BE_Unicode updates
+
+ Rev 1.20 10 Jun 1992 15:51:54 TIMN
+Changed drive letter length or UNIC
+
+ Rev 1.19 26 May 1992 11:20:40 TIMN
+Cleaned up memory fx calls
+
+ Rev 1.18 21 May 1992 17:05:22 TIMN
+Changed maxByteLen to memorycmp calls
+
+ Rev 1.17 19 May 1992 13:18:04 MIKEP
+mips changes
+
+ Rev 1.16 19 May 1992 12:58:26 TIMN
+Replaced strlen with DeviceNameLeng macro
+
+ Rev 1.15 18 May 1992 16:04:10 TIMN
+Changed str functions to mem
+
+ Rev 1.14 08 May 1992 16:24:18 STEVEN
+added volume label to BSD
+
+ Rev 1.13 16 Apr 1992 10:54:08 HUNTER
+Add new BSDs to tail if not sorting
+
+ Rev 1.12 18 Feb 1992 17:27:06 BARRY
+Fixed destruction of comp_val after volume number comparison.
+
+ Rev 1.11 11 Feb 1992 12:42:46 BARRY
+Fixed problem sorting Novell mapped drives.
+
+ Rev 1.10 05 Feb 1992 15:31:44 BARRY
+Don't sort IMAGE DLEs by drive letters alone.
+
+ Rev 1.9 14 Jan 1992 16:35:18 DON
+needed to sort novell/server dle's by volume if sorting
+
+ Rev 1.8 14 Jan 1992 10:23:34 STEVEN
+fix warnings for WIN32
+
+ Rev 1.7 13 Jan 1992 18:36:34 STEVEN
+added config switch for BSD sort
+
+ Rev 1.6 27 Aug 1991 17:30:28 STEVEN
+added BSD target dir support
+
+ Rev 1.5 23 Aug 1991 17:00:14 STEVEN
+added support for NORMAL/COPY/DIFERENTIAL/INCREMENTAL
+
+ Rev 1.4 21 Jun 1991 08:41:14 STEVEN
+new config unit
+
+ Rev 1.3 12 Jun 1991 16:03:02 STEVEN
+BSDU code review
+
+ Rev 1.2 29 May 1991 17:20:56 STEVEN
+Re-Design of BSDU for New Fast File Restore
+
+ Rev 1.1 13 May 1991 13:21:16 STEVEN
+If the DLE was NULL the Insert sort would cause a protection exception.
+
+
+ Rev 1.0 09 May 1991 13:41:10 HUNTER
+Initial revision.
+
+**/
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+
+#include "msassert.h"
+#include "std_err.h"
+#include "queues.h"
+#include "stdwcs.h"
+
+#include "fsys.h"
+#include "bsdu.h"
+#include "beconfig.h"
+
+static VOID SortInsertBSD( BSD_HAND bsdh, BSD_PTR bsd ) ;
+
+
+/**/
+/**
+
+ Name: BSD_Add()
+
+ Description: This function allocates memory for a BSD element. It
+ then initializes this element with the data provided. Finally it
+ is added to the current oper QUEUE of the BSD handle.
+
+ Modified: 8/7/1989
+
+ Returns: Error codes:
+ OUT_OF_MEMORY
+ SUCCESS
+
+ Notes: A sort date of NULL is considered 0-0-0 0:0:0
+
+ See also: $/SEE( BSD_Remove() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 BSD_Add(
+BSD_HAND bsdh, /* I - BSD List to add the new bsd to */
+BSD_PTR *bsd, /* O - return pointer to new bsd */
+struct BE_CFG *cfg, /* I - configuration to use during oper */
+VOID_PTR stats, /* I - statistics struct to use during oper */
+struct GENERIC_DLE *dle, /* I - Disk drive to process on */
+UINT32 tap_id, /* I - Specifies the tape to process with */
+UINT16 tap_num, /* I - Specifies which tape in family */
+INT16 set_num, /* I - Specifies which set on the tape */
+struct THW *thw, /* I - Specifies which tape drive to process*/
+DATE_TIME_PTR sort_date ) /* I - used to sort the BSDs in the list */
+{
+ INT16 ret_val = SUCCESS ;
+
+ msassert( bsd != NULL );
+
+ *bsd = (BSD_PTR)calloc( 1, sizeof( **bsd ) ) ;
+
+ if ( *bsd != NULL ) {
+
+ (*bsd)->tape_id = tap_id ;
+ (*bsd)->tape_num = tap_num ;
+ (*bsd)->set_num = set_num ;
+ (*bsd)->stats = stats ;
+ (*bsd)->thw = thw ;
+ (*bsd)->cfg = cfg ;
+
+ BSD_SetDLE( *bsd, dle );
+ BEC_UseConfig( cfg ) ;
+
+ SetQueueElemPtr( &((*bsd)->q), bsdh ) ;
+
+ (*bsd)->flags.tp_name_chg = TRUE ;
+ (*bsd)->flags.bs_name_chg = TRUE ;
+ (*bsd)->flags.bs_dscr_chg = TRUE ;
+
+ if ( (sort_date != NULL) && (sort_date->date_valid) ) {
+ (*bsd)->sort_date = *sort_date ;
+ } else {
+ memset( &((*bsd)->sort_date), 0, sizeof( DATE_TIME ) ) ;
+ }
+
+ if( dle != NULL ) {
+ DLE_IncBSDCount( dle ) ;
+ }
+
+ SortInsertBSD( bsdh, *bsd ) ;
+
+ } else {
+
+ ret_val = OUT_OF_MEMORY ;
+ }
+
+ return ret_val ;
+}
+/**/
+/**
+
+ Name: BSD_Remove()
+
+ Description: This function releases all FSEs for the BSD specified. It
+ Then releases the memory for the BSD itself.
+
+
+ Modified: 8/7/1989
+
+ Returns: None
+
+ Notes: Released BSDs should not be accessed by application.
+
+ See also: $/SEE( BSD_Add() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID BSD_Remove(
+BSD_PTR bsd ) /* I - specific BSD to delete from list */
+{
+ BSD_HAND bsdh ;
+
+ msassert( bsd != NULL );
+
+ bsdh = (BSD_HAND)GetQueueElemPtr( &(bsd->q) ) ;
+
+ if ( RemoveQueueElem( &(bsdh->current_q_hdr), &(bsd->q) ) == SUCCESS ) {
+
+ GENERIC_DLE_PTR dle = BSD_GetDLE( bsd );
+
+ if ( dle != NULL ) {
+ DLE_DecBSDCount( dle ) ;
+ }
+
+ BEC_ReleaseConfig( bsd->cfg ) ;
+ BSD_ClearAllLBA( bsd ) ;
+ BSD_ClearAllFSE( bsd ) ;
+
+ free( bsd->vol_label ) ;
+ free( bsd->tape_label ) ;
+ free( bsd->tape_pswd ) ;
+ free( bsd->set_label ) ;
+ free( bsd->set_descript ) ;
+ free( bsd->set_pswd ) ;
+ free( bsd->user_name ) ;
+ free( bsd->target_path ) ;
+ free( bsd->match_buffer ) ;
+ free( bsd->dle_name );
+
+ free( bsd ) ;
+
+ } else {
+ msassert( NULL == TEXT("bsd not in queue") );
+ }
+}
+/**/
+/**
+
+ Name: SortInsertBSD()
+
+ Description: This function performs an insersion sort on the BSD
+ list. The list is sorted using the following criteria:
+ sort_date,
+ tape_number,
+ set_number,
+ device_type,
+ device_name,
+
+ Modified: 6/11/1991 13:8:51
+
+ Returns: None
+
+ Notes: This function is called only by BSD_Add()
+
+ See also: $/SEE( BSD_Add() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+static VOID SortInsertBSD(
+BSD_HAND bsdh, /* I - BSD list to insert the new BSD into */
+BSD_PTR bsd ) /* I - points to the new BSD */
+{
+ INT16 comp_val ;
+ BSD_PTR current_bsd ;
+ UINT8 new_vol_num = 0 ;
+ UINT8 curr_vol_num = 0 ;
+ GENERIC_DLE_PTR dle = BSD_GetDLE( bsd );
+ GENERIC_DLE_PTR currDLE;
+
+ current_bsd = (BSD_PTR)QueueHead( &(bsdh->current_q_hdr) ) ;
+
+ while ( current_bsd != NULL ) {
+
+ currDLE = BSD_GetDLE( current_bsd );
+
+ comp_val = CompDate( &(bsd->sort_date), &(current_bsd->sort_date) ) ;
+
+ if ( comp_val == 0 ) {
+ comp_val = bsd->tape_num - current_bsd->tape_num ;
+ }
+
+ if ( comp_val == 0 ) {
+ comp_val = (INT16)(abs( bsd->set_num ) - abs( current_bsd->set_num )) ;
+ }
+
+ if ( comp_val == 0 ) {
+ if ( !BEC_GetSortBSD( bsd->cfg ) ) {
+ comp_val = 0 ;
+ current_bsd = (BSD_PTR)QueueTail( &(bsdh->current_q_hdr) ) ;
+ currDLE = BSD_GetDLE( current_bsd );
+
+ } else if ( (dle == NULL) && (currDLE == NULL) ) {
+ comp_val = 0;
+ } else if ( (dle != NULL) && (currDLE == NULL) ) {
+ comp_val = 1;
+ } else if ( (dle == NULL) && (currDLE != NULL) ) {
+ comp_val = -1;
+ } else {
+
+ /* Check for inserting BSD for Novell server/volume and handle accordingly */
+#if defined(OS_NLM)
+ if ( DLE_GetDeviceType( dle ) == SMS_OBJECT )
+ {
+ /*
+ If it's SMS then just process them in the order
+ there picked up by the SMDR!
+ */
+ comp_val = 1;
+ }
+ else
+ {
+ if ( ( DLE_GetDeviceType( dle ) == NLM_AFP_VOLUME ) ||
+ ( DLE_GetDeviceType( dle ) == NLM_VOLUME ) ) {
+
+ /* If the current BSD is also a server/volume... */
+ if ( ( DLE_GetDeviceType( currDLE ) == NLM_AFP_VOLUME ) ||
+ ( DLE_GetDeviceType( currDLE ) == NLM_VOLUME ) ) {
+
+ /* Now check to see if these BSDs refer to the same server (same parent) */
+ if( DLE_GetParent( dle ) == DLE_GetParent( currDLE ) ) {
+
+ /* Now let's make sure that we sort by the volume number... */
+ new_vol_num = DLE_GetDeviceType( dle ) == NLM_AFP_VOLUME ?
+ dle->info.nlm_afp->vol_num : dle->info.nlm->vol_num ;
+ curr_vol_num = DLE_GetDeviceType( currDLE ) == NOVELL_AFP_DRV ?
+ currDLE->info.nlm_afp->vol_num : currDLE->info.nlm->vol_num ;
+ comp_val = new_vol_num - curr_vol_num ;
+
+ } else {
+
+ comp_val = memoryicmp( DLE_GetDeviceName( dle ),
+ DLE_GetDeviceNameLeng( dle ),
+ DLE_GetDeviceName( currDLE ),
+ DLE_GetDeviceNameLeng( currDLE ) ) ;
+ }
+ }
+ }
+ }
+#else
+ if ( (DLE_GetParent( dle ) != NULL) &&
+ ((DLE_GetDeviceType( dle ) == NOVELL_AFP_DRV) ||
+ (DLE_GetDeviceType( dle ) == NOVELL_DRV)) ) {
+
+ /* If the current BSD is also a server/volume... */
+ if ( (DLE_GetParent( currDLE ) != NULL) &&
+ ((DLE_GetDeviceType( currDLE ) == NOVELL_AFP_DRV) ||
+ (DLE_GetDeviceType( currDLE ) == NOVELL_DRV)) ) {
+
+ /* Now check to see if these BSDs refer to the same server (same parent) */
+ if( DLE_GetParent( dle ) == DLE_GetParent( currDLE ) ) {
+
+ /* Now let's make sure that we sort by the volume number... */
+ new_vol_num = DLE_GetDeviceType( dle ) == NOVELL_AFP_DRV ?
+ dle->info.afp->vol_num : dle->info.nov->vol_num ;
+ curr_vol_num = DLE_GetDeviceType( currDLE ) == NOVELL_AFP_DRV ?
+ currDLE->info.afp->vol_num : currDLE->info.nov->vol_num ;
+ comp_val = new_vol_num - curr_vol_num ;
+
+ } else {
+
+ comp_val = memoryicmp( DLE_GetDeviceName( dle ),
+ DLE_GetDeviceNameLeng( dle ),
+ DLE_GetDeviceName( currDLE ),
+ DLE_GetDeviceNameLeng( currDLE ) ) ;
+ }
+
+ }
+
+ }
+
+ if ( comp_val == 0 ) {
+ /*
+ * If the DLEs are both named "x:" (where x is some drive
+ * letter) then don't sort on the DLE type unless one
+ * of them is an IMAGE DLE. We don't want these mixed
+ * in with the other drive letters.
+ */
+
+ if ( !DLE_HasFeatures( dle, DLE_FEAT_MAPPED_DRIVE ) ) {
+
+ comp_val = (INT16)(DLE_GetDeviceType( dle )
+ - DLE_GetDeviceType( currDLE ) ) ;
+ }
+ }
+#endif
+ if ( comp_val == 0 ) {
+ comp_val = memoryicmp( DLE_GetDeviceName( dle ),
+ DLE_GetDeviceNameLeng( dle ),
+ DLE_GetDeviceName( currDLE ),
+ DLE_GetDeviceNameLeng( currDLE ) ) ;
+ }
+ }
+
+ }
+
+ if ( comp_val <= 0 ) {
+ break ;
+ }
+
+ current_bsd = (BSD_PTR)QueueNext( &(current_bsd->q) ) ;
+ }
+
+ if ( current_bsd != NULL ) {
+
+ if ( comp_val == 0 ) {
+ InsertElem( &(bsdh->current_q_hdr), &(current_bsd->q), &(bsd->q), AFTER ) ;
+
+ } else {
+
+ InsertElem( &(bsdh->current_q_hdr), &(current_bsd->q), &(bsd->q), BEFORE ) ;
+ }
+
+ } else {
+
+ EnQueueElem( &(bsdh->current_q_hdr), &(bsd->q), FALSE ) ;
+
+ }
+
+}
+
+/**/
+/**
+
+ Name: BSD_SetDLE
+
+ Description: This function sets the DLE in a BSD. It increments
+ the BSD count in the new DLE. If the BSD was attached to an
+ old DLE then the old DLE BSD count is decremented.
+
+ Modified: 11/21/1989
+
+ Returns: None
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID BSD_SetDLE( BSD_PTR bsd,
+ GENERIC_DLE_PTR newDLE )
+{
+ GENERIC_DLE_PTR oldDLE = BSD_GetDLE( bsd );
+
+ if ( oldDLE != NULL )
+ {
+ DLE_DecBSDCount( oldDLE ) ;
+ }
+
+ bsd->dle_head = NULL;
+ if ( newDLE == NULL )
+ {
+ free( bsd->dle_name );
+ bsd->dle_name = NULL;
+ }
+ else
+ {
+ DLE_IncBSDCount( newDLE ) ;
+ bsd->dle_name = realloc( bsd->dle_name, strsize( DLE_GetDeviceName( newDLE ) ) );
+ if ( bsd->dle_name != NULL )
+ {
+ bsd->dle_head = DLE_GetHandle( newDLE );
+ strcpy( bsd->dle_name, DLE_GetDeviceName( newDLE ) );
+ }
+ }
+}
+
+/**/
+/**
+
+ Name: BSD_GetDLE()
+
+ Description: Returns the DLE for the specified BSD.
+
+ Modified: 18-Jul-93
+
+ Returns: DLE ptr or NULL if DLE has disappeared.
+
+ Notes:
+
+**/
+GENERIC_DLE_PTR BSD_GetDLE( BSD_PTR bsd )
+{
+ GENERIC_DLE_PTR dle = NULL;
+
+ if ( bsd->dle_head != NULL && bsd->dle_name != NULL )
+ {
+ DLE_FindByName( bsd->dle_head,
+ bsd->dle_name,
+ -1,
+ &dle );
+
+ }
+ return dle;
+}
+
+
+/**/
+/**
+
+ Name: BSD_SetBackupType()
+
+ Description: This function sets the backup type for a BSD.
+ The types are defined as follows:
+
+ NORMAL -> backup all selected files & clear modified bit
+ COPY -> backup all selected files & DON'T clear modified bit
+ DIFERENTIAL -> backup modified files & DON't clear modified bit
+ INCREMENTAL -> backup modified files & clear modified bit
+ COMPATIBLE -> look at CFG and FSE for functionality
+
+
+ Modified: 11/21/1989
+
+ Returns: None
+
+**/
+VOID BSD_SetBackupType(
+BSD_PTR bsd,
+INT16 backup_type )
+{
+
+ bsd->flags.backup_type = backup_type ;
+ switch( backup_type ) {
+
+ case BSD_BACKUP_NORMAL:
+ bsd->flags.sup_back_type = TRUE ;
+ bsd->flags.modify_only = FALSE ;
+ bsd->flags.set_mod_flag = TRUE ;
+ break ;
+
+ case BSD_BACKUP_DAILY:
+ case BSD_BACKUP_COPY:
+ bsd->flags.sup_back_type = TRUE ;
+ bsd->flags.modify_only = FALSE ;
+ bsd->flags.set_mod_flag = FALSE ;
+ break ;
+
+ case BSD_BACKUP_DIFFERENTIAL:
+ bsd->flags.sup_back_type = TRUE ;
+ bsd->flags.modify_only = TRUE ;
+ bsd->flags.set_mod_flag = FALSE ;
+ break ;
+
+ case BSD_BACKUP_INCREMENTAL:
+ bsd->flags.sup_back_type = TRUE ;
+ bsd->flags.modify_only = TRUE ;
+ bsd->flags.set_mod_flag = TRUE ;
+ break ;
+
+ case BSD_BACKUP_COMPATIBLE :
+ default:
+ bsd->flags.sup_back_type = FALSE ;
+ bsd->flags.modify_only = FALSE ;
+ bsd->flags.set_mod_flag = FALSE ;
+ break ;
+ }
+}
+
+
+
diff --git a/private/utils/ntbackup/src/addfse.c b/private/utils/ntbackup/src/addfse.c
new file mode 100644
index 000000000..5535438ab
--- /dev/null
+++ b/private/utils/ntbackup/src/addfse.c
@@ -0,0 +1,633 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: addfse.c
+
+ Description: This file contains code to add and remove FSEs from
+ a BSD
+
+ $Log: N:\LOGFILES\ADDFSE.C_V $
+
+ Rev 1.22 24 Mar 1994 13:21:24 MIKEP
+change 1 to sizeof(CHAR)
+
+ Rev 1.21 10 Mar 1994 17:37:08 MARINA
+FSE_UpdateMark/unicode: change 1 to sizeof(CHAR)
+
+ Rev 1.20 17 Jan 1994 17:17:44 BARRY
+Got rid of TEXT macros in msasserts
+
+ Rev 1.19 16 Dec 1993 10:20:10 BARRY
+Change INT8_PTRs to VOID_PTRs
+
+ Rev 1.18 04 Aug 1993 15:26:16 JOHNES
+803EPR0592 - When in FSE_CompareForSub, if one FSE has complex data and the
+other doesn't, if the complex data is empty, pretend it doesn't exist.
+
+This will fix the particular way this problem showed up. There are still
+ways it could happen. A better fix would require more complexity in
+FSE_CompareForSub and how it deals with include/exclude complex info. This
+is more than I can do right now.
+
+
+
+ Rev 1.17 27 Jul 1993 14:42:16 MARILYN
+changed || to && in FSE_CheckForSub
+
+ Rev 1.16 09 Jun 1993 19:21:28 MIKEP
+enable c++ build
+
+ Rev 1.15 09 Oct 1992 11:44:02 DAVEV
+Unicode (CHAR_PTR) pointer cast validation
+
+ Rev 1.14 10 Jun 1992 15:49:18 TIMN
+changed header name
+
+ Rev 1.13 26 May 1992 11:19:24 TIMN
+Cleaned up memory fx calls
+
+ Rev 1.12 21 May 1992 17:03:26 TIMN
+Changed maxByteLen to memoryCMP
+
+ Rev 1.11 19 May 1992 15:18:56 TIMN
+Changed asterisks to define's
+
+ Rev 1.10 18 May 1992 16:03:00 TIMN
+Changed str functions to mem
+
+ Rev 1.9 14 May 1992 12:13:06 TIMN
+Changed CHARs to INT8, strcpy to memcpy
+
+ Rev 1.8 13 May 1992 11:41:12 TIMN
+Added TEXT() macro to literals, but not msassert literals
+
+ Rev 1.7 28 Feb 1992 09:22:40 STEVEN
+partial excludes being full excludes
+
+ Rev 1.6 14 Jan 1992 10:23:48 STEVEN
+fix warnings for WIN32
+
+ Rev 1.5 02 Oct 1991 15:32:06 STEVEN
+selection type ENTIRE DIR when should be PARTIAL
+
+ Rev 1.4 30 Sep 1991 09:36:38 STEVEN
+Needed to update status when removing an FSE
+
+ Rev 1.3 23 Aug 1991 16:58:56 STEVEN
+now checks to see if in queue before it removes it
+
+ Rev 1.2 12 Jun 1991 16:02:14 STEVEN
+BSDU code review
+
+ Rev 1.1 29 May 1991 17:21:34 STEVEN
+Re-Design of BSDU for New Fast File Restore
+
+ Rev 1.0 09 May 1991 13:41:12 HUNTER
+Initial revision.
+
+**/
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "msassert.h"
+
+#include "std_err.h"
+#include "queues.h"
+#include "stdwcs.h"
+
+#include "bsdu.h"
+
+#define DateAfter( date1, date2 ) (-DateBefore( (date1), (date2) ))
+
+static VOID FSE_UpdateMark( FSE_PTR fse ) ;
+static BOOLEAN FSE_CompareForSub( FSE_PTR fse1, FSE_PTR fse2 );
+static BOOLEAN DateBefore( DATE_TIME_PTR date1, DATE_TIME_PTR date2 ) ;
+static BOOLEAN DateEqual( DATE_TIME_PTR date1, DATE_TIME_PTR date2 ) ;
+static BOOLEAN FSE_ComplexDataEmpty( FSE_COMPLEX_PTR cplx );
+/**/
+/**
+
+ Name: BSD_RemoveFSE()
+
+ Description: This function removes an FSE from the specified
+ BSD.
+
+ Modified: 5/17/1991 14:43:52
+
+ Returns: None
+
+ Notes:
+
+ See also: $/SEE( BSD_AddFSE() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID BSD_RemoveFSE(
+FSE_PTR fse ) /* I - specifies which FSE to remove */
+{
+ BSD_PTR bsd ;
+ INT16 ret_val = SUCCESS ;
+
+ msassert( fse != NULL );
+
+ bsd = (BSD_PTR)GetQueueElemPtr( &(fse->q) ) ;
+
+ if ( bsd != NULL ) {
+
+ ret_val = RemoveQueueElem( &(bsd->fse_q_hdr), &(fse->q) ) ;
+ }
+
+ if ( ret_val == SUCCESS ) {
+
+ if( fse->tgt != NULL ) {
+ bsd->tgt_fse_exist-- ;
+ free( fse->tgt ) ;
+ }
+
+ if( fse->cplx != NULL ) {
+ free( fse->cplx->pre_m_date ) ;
+ free( fse->cplx->post_m_date ) ;
+ free( fse->cplx->access_date ) ;
+ free( fse->cplx->backup_date ) ;
+ free( fse->cplx ) ;
+ }
+
+ free( fse ) ;
+
+ } else {
+ msassert( ("FSE NOT found in BSD", 0) );
+ }
+
+ if ( bsd != NULL ) {
+ fse = BSD_GetFirstFSE( bsd ) ;
+ if ( fse == NULL ) {
+ bsd->select_status = NONE_SELECTED ;
+ }
+ }
+}
+/**/
+/**
+
+ Name: BSD_CreateFSE()
+
+ Description: This function allocates memory for an FSE. It then
+ initializes the allocated memory with the data provided. This
+ function only initializes the simple selection data. To set
+ the complex selection data( dates & attributes) other FSE
+ function calls must be made.
+
+ Modified: 8/9/1989
+
+ Returns: Error codes:
+ OUT_OF_MEMORY
+ SUCCESS
+
+ Notes:
+
+ See also: $/SEE( BSD_AddFSE(), FSE_SetComplexInfo() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 BSD_CreatFSE(
+FSE_PTR *fse, /* O - The FSE which is craeted */
+INT16 oper, /* I - The operation type .i.e INCLUDE/EXCLUDE */
+VOID_PTR dname, /* I - The directory name (NULL impregnated) */
+INT16 dsize, /* I - The size of the directory name */
+VOID_PTR fname, /* I - The file name */
+INT16 fnsize, /* I - size of file name */
+BOOLEAN wilds, /* I - TRUE if the '?' and '*' are wildcards */
+BOOLEAN subs ) /* I - TRUE if selection should include subdirectories */
+{
+ INT16 ret_val ;
+
+ msassert( fse != NULL ) ;
+ msassert( dsize > 0 ) ;
+ msassert( fnsize > 0 ) ;
+
+ *fse = (FSE_PTR)calloc( 1, sizeof( **fse ) + dsize + fnsize ) ;
+
+ if ( *fse != NULL ) {
+
+ (*fse)->flgs.inc_exc = oper ;
+
+ FSE_SetIncSubFlag( *fse, subs ) ;
+ FSE_SetWildFlag( *fse, wilds ) ;
+
+ (*fse)->dir = (*fse + 1);
+ (*fse)->dir_leng = dsize ;
+ (*fse)->fname = (BYTE_PTR)(*fse)->dir + dsize ;
+ (*fse)->fname_leng = fnsize ;
+ (*fse)->flgs.del_files = NON_DELETED_FILES_ONLY ;
+ memcpy( (*fse)->dir, dname, dsize ) ;
+ memcpy( (*fse)->fname, fname, fnsize ) ;
+
+ ret_val = SUCCESS ;
+
+ } else {
+
+ ret_val = OUT_OF_MEMORY ;
+ }
+
+ return ret_val ;
+}
+/**/
+/**
+
+ Name: BSD_AddFSE()
+
+ Description: This function adds an fse to the queue of FSE. Before
+ the element is added to the QUEUE, a check is made to see if
+ this fse is a subset or superset of an element already in the
+ FSL. If it is, then the queue is optimized by removing the
+ the appropriate element.
+
+
+ Modified: 8/9/1989
+
+ Returns: None
+
+ Notes:
+
+ See also: $/SEE( BSD_RemoveFSE(), BSD_CreatFSE() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID BSD_AddFSE(
+BSD_PTR bsd, /* I - What BSD to add the FSE to */
+FSE_PTR fse ) /* I - The FSE to add */
+{
+ FSE_PTR node ;
+ FSE_PTR node2;
+ BOOLEAN include_found = FALSE ;
+
+ msassert( fse != NULL );
+ msassert( bsd != NULL );
+
+ /* make sure the FSE is not already enqueued */
+ msassert( GetQueueElemPtr( &(fse->q) ) == NULL ) ;
+
+ node = (FSE_PTR)QueueHead( &(bsd->fse_q_hdr) ) ;
+
+ while ( node != NULL ) {
+
+ if ( FSE_CompareForSub( fse, node ) ) {
+ /* the new FSE supersedes the older FSE */
+
+ node2 = (FSE_PTR)QueueNext( &(node->q) ) ;
+
+ BSD_RemoveFSE( node ) ;
+ node = node2 ;
+
+ } else {
+
+ if ( FSE_GetOperType( node ) == INCLUDE ) {
+ include_found = TRUE ;
+ }
+ node = (FSE_PTR)QueueNext( &(node->q) ) ;
+
+ }
+ }
+
+ if ( !include_found ) {
+ BSD_ClearAllFSE( bsd ) ;
+ }
+
+ if ( FSE_HasTargetInfo( fse ) ) {
+ bsd->tgt_fse_exist ++ ;
+ }
+
+ SetQueueElemPtr( &(fse->q), bsd ) ;
+
+ EnQueueElem( &(bsd->fse_q_hdr), &(fse->q), FALSE ) ;
+
+ FSE_UpdateMark( fse ) ;
+
+}
+/**/
+/**
+
+ Name: FSE_UpdateMark()
+
+ Description: This function updates the mark status of the fse and the
+ bsd which contains the fse.
+
+
+ Modified: 8/10/1989
+
+ Returns: none
+
+ Notes: This function is only called by BSD_AddFSE()
+
+ See also: $/SEE( BSD_AddFSE() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+static VOID FSE_UpdateMark(
+FSE_PTR fse ) /*I - Fse to update the mark status in */
+{
+ BSD_PTR bsd ;
+ FSE_COMPLEX_PTR cplx ;
+ FSE_PTR temp_fse ;
+
+ bsd = (BSD_PTR)GetQueueElemPtr( &(fse->q) ) ;
+ cplx = fse->cplx ;
+
+ if ( FSE_GetOperType( fse ) == INCLUDE ) {
+
+ fse->flgs.select_type = PARTIAL_SELECTION ;
+ bsd->select_status = SOME_SELECTED ;
+
+ if( FSE_GetIncSubFlag( fse ) && ( fse->dir_leng == sizeof( CHAR ) ) ) {
+ bsd->select_status = ALL_SELECTED ;
+ }
+
+ if ( ( !memorycmp( fse->fname, fse->fname_leng, ALL_FILES, ALL_FILES_LENG ) ||
+ !memorycmp( fse->fname, fse->fname_leng, ALL_FILES2, ALL_FILES2_LENG ) ) &&
+ FSE_GetWildFlag( fse ) &&
+ ( cplx == NULL ) &&
+ FSE_GetIncSubFlag( fse ) &&
+ (FSE_GetDeletedVersionFlg( fse ) != DELETED_FILES_ONLY) ) {
+
+ fse->flgs.select_type = ENTIRE_DIR_SELECTION ;
+
+ } else {
+ fse->flgs.select_type = PARTIAL_SELECTION ;
+ bsd->select_status = SOME_SELECTED ;
+ }
+
+ if ( !FSE_GetIncSubFlag( fse ) ) {
+
+ if ( !FSE_GetWildFlag( fse ) ||
+ (!strchr(fse->fname, TEXT('?')) && !strchr(fse->fname, TEXT('*')) ) ) {
+
+ fse->flgs.select_type = SINGLE_FILE_SELECTION ;
+ }
+ }
+
+ } else { /* fse is an exclude */
+
+ fse->flgs.select_type = PARTIAL_SELECTION ;
+
+ if ( !FSE_GetIncSubFlag( fse ) ) {
+
+ if ( !FSE_GetWildFlag( fse ) ||
+ (!strchr(fse->fname, TEXT('?')) && !strchr(fse->fname, TEXT('*')) ) ) {
+
+ fse->flgs.select_type = SINGLE_FILE_SELECTION ;
+ }
+ }
+
+ if ( FSE_GetIncSubFlag( fse ) && ( fse->dir_leng == sizeof(CHAR) ) &&
+ ( !memorycmp( fse->fname, fse->fname_leng, ALL_FILES, ALL_FILES_LENG ) ||
+ !memorycmp( fse->fname, fse->fname_leng, ALL_FILES2, ALL_FILES2_LENG ) ) &&
+ FSE_GetWildFlag( fse ) && (fse->cplx == NULL) ) {
+
+ bsd->select_status = NONE_SELECTED ;
+
+ } else if ( bsd->select_status == ALL_SELECTED ) {
+
+ bsd->select_status = SOME_SELECTED ;
+
+ }
+
+ temp_fse = BSD_GetFirstFSE( bsd ) ;
+
+ while ( temp_fse != NULL ) {
+
+ if ( temp_fse->flgs.select_type == ENTIRE_DIR_SELECTION ) {
+ if ( (fse->dir_leng >= temp_fse->dir_leng) &&
+ !memicmp( fse->dir, temp_fse->dir, temp_fse->dir_leng ) ) {
+
+ temp_fse->flgs.select_type = PARTIAL_SELECTION ;
+
+ } else if ( (fse->dir_leng < temp_fse->dir_leng) &&
+ FSE_GetIncSubFlag( fse ) &&
+ !memicmp( fse->dir, temp_fse->dir, fse->dir_leng ) ) {
+
+ temp_fse->flgs.select_type = PARTIAL_SELECTION ;
+ }
+ }
+
+ temp_fse = BSD_GetNextFSE( fse ) ;
+ }
+ }
+}
+/**/
+/**
+
+ Name: FSE_CompareForSub()
+
+ Description: This function compares two FSEs to see if one is a
+ subset of the other. The possibilities are fse1 < fse2,
+ fse1 > fse2, fse1 = fse2, no comparison.
+
+
+ Modified: 8/10/1989
+
+ Returns: TRUE if FSE2 <= FSE1
+
+ Notes: This function is only called by BSD_AddFSE() for
+ optimization purposes.
+
+ See also: $/SEE( BSD_AddFSE() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+static BOOLEAN FSE_CompareForSub(
+FSE_PTR fse1, /* I - File Selection Element to compare */
+FSE_PTR fse2 ) /* I - File Selection Element to compare */
+{
+ INT16 ret_val = FALSE ;
+ FSE_COMPLEX_PTR cplx1;
+ FSE_COMPLEX_PTR cplx2;
+ FSE_TGT_INFO_PTR tgt1 ;
+ FSE_TGT_INFO_PTR tgt2 ;
+
+ cplx1 = fse1->cplx ;
+ cplx2 = fse2->cplx ;
+ tgt1 = fse1->tgt ;
+ tgt2 = fse2->tgt ;
+
+ if( fse1->dir_leng <= fse2->dir_leng ) {
+ /* fse2 could be a subset of fse1 */
+ ret_val = TRUE ;
+
+ if( memicmp( fse1->dir, fse2->dir, fse1->dir_leng ) ) {
+ ret_val = FALSE ;
+
+ } else if( !FSE_GetIncSubFlag( fse1 ) && ( fse1->dir_leng != fse2->dir_leng ) ) {
+ ret_val = FALSE ;
+
+ } else if( FSE_GetIncSubFlag( fse2 ) && !FSE_GetIncSubFlag( fse1 ) ) {
+ ret_val = FALSE ;
+
+ /* If we made it this far then The directory matches */
+
+ } else if( memorycmp( fse1->fname, fse1->fname_leng, fse2->fname, fse2->fname_leng ) &&
+ ( memorycmp( fse1->fname, fse1->fname_leng, ALL_FILES, ALL_FILES_LENG ) &&
+ memorycmp( fse1->fname, fse1->fname_leng, ALL_FILES2, ALL_FILES2_LENG ) ) ||
+ !FSE_GetWildFlag(fse1) ) {
+ ret_val = FALSE ;
+
+ } else if ( (cplx2 != NULL) || (cplx1 != NULL) ) {
+ if ( cplx2 == NULL ) {
+ /* if the complex data struture isn't empty then */
+ /* these two FSE's can't be equal. */
+ if ( FSE_ComplexDataEmpty( cplx1 ) == FALSE ) {
+ ret_val = FALSE ;
+
+ }
+ } else if ( cplx1 == NULL ) {
+ /* if the complex data struture isn't empty then */
+ /* these two FSE's can't be equal. */
+ if ( FSE_ComplexDataEmpty( cplx2 ) == FALSE ) {
+ ret_val = FALSE ;
+
+ }
+ } else {
+
+ if( DateAfter( cplx2->pre_m_date, cplx1->pre_m_date ) ) {
+ ret_val = FALSE ;
+
+ } else if( DateBefore( cplx2->post_m_date, cplx1->post_m_date ) ) {
+ ret_val = FALSE ;
+
+ } else if( DateBefore( cplx2->access_date, cplx1->access_date ) ) {
+ ret_val = FALSE ;
+
+ } else if( !DateEqual( cplx2->backup_date, cplx1->backup_date ) ) {
+ ret_val = FALSE ;
+
+ /* more bits means less files */
+ } else if( ( (cplx1->attr_on_mask | cplx2->attr_on_mask) != cplx2->attr_on_mask ) ||
+ ( (cplx1->attr_off_mask & cplx2->attr_off_mask) != cplx2->attr_off_mask ) ) {
+ ret_val = FALSE ;
+ }
+ }
+ }
+ }
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Name: FSE_ComplexDataEmpty()
+
+ Description: This function checks to see if all parts of an FSE's
+ complex data structure are EMPTY. By EMPTY, I mean not
+ effecting the files selections.
+
+ This comes in handy when comparing a simple FSE and
+ a complex FSE. If there is no data in the complex field
+ of the one, then you might as well ignore it.
+
+
+ Modified: 8/4/1993 (JES)
+
+ Returns: TRUE - the structure is empty.
+ FALSE - the structure isn't empty.
+
+
+ Notes: This function is only called by BSD_AddFSE() for
+ optimization purposes.
+
+ See also:
+
+ Declaration:
+
+**/
+static BOOLEAN FSE_ComplexDataEmpty( FSE_COMPLEX_PTR cplx )
+{
+
+ BOOLEAN ret_val = TRUE ;
+
+ msassert( cplx != NULL ) ;
+
+ if ( cplx->pre_m_date != NULL ) {
+ ret_val = FALSE ;
+ }
+
+ if ( cplx->post_m_date != NULL ) {
+ ret_val = FALSE ;
+ }
+
+ if ( cplx->access_date != NULL ) {
+ ret_val = FALSE ;
+ }
+
+ if ( cplx->backup_date != NULL ) {
+ ret_val = FALSE ;
+ }
+
+ if ( cplx->attr_on_mask != 0 ) {
+ ret_val = FALSE ;
+ }
+
+ if ( cplx->attr_off_mask != 0 ) {
+ ret_val = FALSE ;
+ }
+
+ return ret_val ;
+
+} /* FSE_ComplexDataEmpty */
+
+
+
+static BOOLEAN DateBefore(
+DATE_TIME_PTR date1,
+DATE_TIME_PTR date2 )
+{
+ INT16 ret_val ;
+
+ if ( ( date1 == NULL ) || ( !date1->date_valid ) ) {
+ ret_val = FALSE ;
+
+ } else if ( ( date2 == NULL ) || ( !date2->date_valid ) ) {
+ ret_val = TRUE ;
+
+ } else {
+ ret_val = (INT16)( CompDate( date1, date2 ) < 0 ) ;
+ }
+
+ return ( ret_val ) ;
+}
+
+static BOOLEAN DateEqual(
+DATE_TIME_PTR date1,
+DATE_TIME_PTR date2 )
+{
+ INT16 ret_val ;
+
+ if ( ( date1 == NULL ) || ( !date1->date_valid ) ) {
+
+ if ( ( date2 == NULL ) || ( !date2->date_valid ) ) {
+ ret_val = TRUE ;
+ } else {
+ ret_val = FALSE ;
+ }
+
+ } else if ( ( date2 == NULL ) || ( !date2->date_valid ) ) {
+ ret_val = FALSE ;
+
+ } else {
+ ret_val = (INT16)( !memcmp( date1, date2, sizeof( DATE_TIME ) ) ) ;
+ }
+
+ return ( ret_val ) ;
+
+}
diff --git a/private/utils/ntbackup/src/addlba.c b/private/utils/ntbackup/src/addlba.c
new file mode 100644
index 000000000..b112b5873
--- /dev/null
+++ b/private/utils/ntbackup/src/addlba.c
@@ -0,0 +1,308 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: addlba.c
+
+ Description: This file contains the functions for accessing the
+ LBA Queue.
+
+
+ $Log: J:/LOGFILES/ADDLBA.C_V $
+
+ Rev 1.9 30 Jan 1993 11:10:16 DON
+ifdef'd out static function not used
+
+ Rev 1.8 25 Oct 1991 10:37:22 STEVEN
+was unlocking a mem pointer again -- fixed
+
+ Rev 1.7 16 Oct 1991 08:51:24 STEVEN
+was ulocking wrong pointer
+
+ Rev 1.6 10 Oct 1991 15:16:28 STEVEN
+was not updateing tail pointer
+
+ Rev 1.5 04 Sep 1991 16:51:10 STEVEN
+fix VM queue insert to be ordered by LBA #
+
+ Rev 1.4 20 Aug 1991 16:04:24 BRYAN
+refrencing unallocated space
+
+ Rev 1.3 13 Jun 1991 14:01:30 STEVEN
+need version # in LBA for FFR
+
+ Rev 1.2 12 Jun 1991 16:05:36 STEVEN
+added virtual memory for LBAs
+
+ Rev 1.1 29 May 1991 17:21:00 STEVEN
+Re-Design of BSDU for New Fast File Restore
+
+ Rev 1.0 09 May 1991 13:41:14 HUNTER
+Initial revision.
+
+**/
+#include <malloc.h>
+#include <stdlib.h>
+
+#include "stdtypes.h"
+#include "queues.h"
+#include "vm.h"
+#include "std_err.h"
+#include "bsdu.h"
+
+#if defined(OBSOLETE_CODE)
+static INT16 BSD_GetLastLBA( BSD_PTR bsd, LBA_ELEM_PTR lba ) ;
+#endif
+
+/**/
+/**
+
+ Name: BSD_AddLBAElem()
+
+ Description: This function Adds an LBA to the LBA Queue.
+ If the LBA is already in the Queue then no net change
+ occurs and we return SUCCESS
+
+ Modified: 5/17/1991 13:48:46
+
+ Returns: SUCCESS or OUT_OF_MEMORY
+
+ Notes: Comments provided by Mike Payne.
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 BSD_AddLBAElem(
+BSD_PTR bsd, /* I - BSD to add the LBA structure to */
+UINT32 lba, /* I - The logical block address */
+UINT16 tape_num, /* I - The Tape Number of the block */
+UINT16 lba_type, /* I - The type of LBA element */
+UINT16 file_ver ) /* I - The file version for AllVersions */
+{
+ BSD_HAND bsdh = (BSD_HAND)GetQueueElemPtr( &bsd->q ) ;
+ VM_HDL vm_hand = bsdh->vm_hand ;
+ INT16 ret_val = SUCCESS ;
+ LBA_ELEM tmp1_lba;
+ LBA_ELEM tmp2_lba;
+ LBA_ELEM tmp3_lba;
+ LBA_ELEM_PTR new_lba ;
+ LBA_ELEM_PTR old_lba ;
+ VM_PTR new_vm_lba ;
+ LBA_ELEM_PTR tail_lba ;
+ LBA_ELEM_PTR head_lba ;
+ BOOLEAN tmp1_null ;
+ BOOLEAN tmp2_null = TRUE;
+
+
+ /* It's a singly linked list so travel two pointers */
+
+
+ if ( BSD_GetFirstLBA( bsd, &tmp1_lba ) == SUCCESS ) {
+ tmp1_null = FALSE;
+ } else {
+ tmp1_null = TRUE;
+ }
+
+ while ( !tmp1_null ) {
+ if ( lba <= LBA_GetLBA( &tmp1_lba ) ) {
+ break ;
+ }
+ tmp2_null = FALSE;
+ tmp2_lba = tmp1_lba;
+
+ if ( BSD_GetNextLBA( bsd, &tmp1_lba ) == SUCCESS ) {
+ tmp1_null = FALSE;
+ } else {
+ tmp1_null = TRUE;
+ }
+ }
+
+ if ( ( !tmp1_null ) &&
+ ( lba == LBA_GetLBA( &tmp1_lba ) ) ) {
+
+ /* We found one that has the same LBA # already in the queue */
+
+ if ( (lba_type == LBA_BEGIN_POSITION) &&
+ (tmp1_lba.type != LBA_BEGIN_POSITION) ) {
+
+ /* The current one was a SINGLE_OBJECT so make */
+ /* it a BEGIN_POSITION and don't insert the new one. */
+
+ new_lba = (LBA_ELEM_PTR)VM_MemLock( vm_hand, (VM_PTR)tmp1_lba.vm_ptr, VM_READ_WRITE ) ;
+
+ if ( new_lba != NULL ) {
+
+ new_lba->type = LBA_BEGIN_POSITION ;
+ VM_MemUnLock( vm_hand, (VM_PTR)tmp1_lba.vm_ptr ) ;
+
+ } else {
+ ret_val = OUT_OF_MEMORY ;
+ }
+ }
+
+ } else {
+
+ new_vm_lba = VM_Alloc( vm_hand, sizeof( LBA_ELEM ) ) ;
+
+ if ( new_vm_lba == 0 ) {
+
+ ret_val = OUT_OF_MEMORY ;
+
+ } else {
+
+ new_lba = (LBA_ELEM_PTR)VM_MemLock( vm_hand, new_vm_lba, VM_READ_WRITE ) ;
+ if ( new_lba != NULL ) {
+ new_lba->lba_val = lba ;
+ new_lba->next = 0L ;
+ new_lba->vm_ptr = new_vm_lba ;
+ new_lba->tape_num = (UINT8)tape_num ;
+ new_lba->type = (UINT8)lba_type ;
+ new_lba->file_ver_num = (UINT8)file_ver ;
+ VM_MemUnLock( vm_hand, new_vm_lba ) ;
+
+ /* empty queue install as head & tail */
+ /* tmp1 is NULL install as tail */
+ /* tmp2 is NULL install as head */
+ /* else install after tmp2 no head/tail changes */
+
+ ret_val = OUT_OF_MEMORY ;
+
+ if ( BSD_GetFirstLBA( bsd, &tmp3_lba ) != SUCCESS ) {
+ bsd->lba_vm_q_head = new_vm_lba ;
+ bsd->lba_vm_q_tail = new_vm_lba ;
+ ret_val = SUCCESS ;
+
+ } else if ( tmp1_null ) {
+ tail_lba = (LBA_ELEM_PTR)VM_MemLock( vm_hand, (VM_PTR)bsd->lba_vm_q_tail, VM_READ_WRITE ) ;
+
+ if ( tail_lba != NULL ) {
+
+ tail_lba->next = new_vm_lba ;
+ VM_MemUnLock( vm_hand, (VM_PTR)bsd->lba_vm_q_tail ) ;
+ bsd->lba_vm_q_tail = new_vm_lba ;
+
+ ret_val = SUCCESS ;
+ }
+
+ } else if ( tmp2_null ) {
+ head_lba = (LBA_ELEM_PTR)VM_MemLock( vm_hand, (VM_PTR)new_vm_lba, VM_READ_WRITE ) ;
+ if ( head_lba != NULL ) {
+ head_lba->next = bsd->lba_vm_q_head;
+ bsd->lba_vm_q_head = new_vm_lba ;
+ VM_MemUnLock( vm_hand, (VM_PTR)new_vm_lba ) ;
+ ret_val = SUCCESS ;
+ }
+ } else {
+ old_lba = (LBA_ELEM_PTR)VM_MemLock( vm_hand, (VM_PTR)tmp2_lba.vm_ptr, VM_READ_WRITE ) ;
+ if ( old_lba != NULL ) {
+
+ new_lba = (LBA_ELEM_PTR)VM_MemLock( vm_hand, (VM_PTR)new_vm_lba, VM_READ_WRITE ) ;
+ if ( new_lba != NULL ) {
+
+ old_lba->next = new_vm_lba ;
+ new_lba->next = tmp1_lba.vm_ptr;
+ VM_MemUnLock( vm_hand, (VM_PTR)new_vm_lba ) ;
+ ret_val = SUCCESS ;
+
+ }
+ VM_MemUnLock( vm_hand, (VM_PTR)tmp2_lba.vm_ptr ) ;
+ }
+ }
+
+ } else {
+ ret_val = OUT_OF_MEMORY ;
+ }
+ }
+ }
+
+ return ret_val ;
+}
+
+
+INT16 BSD_GetFirstLBA(
+BSD_PTR bsd, /* I - BSD to process off of */
+LBA_ELEM_PTR lba ) /* O - The first LBA in the Queue */
+{
+ BSD_HAND bsdh = (BSD_HAND)GetQueueElemPtr( &bsd->q ) ;
+ VM_HDL vmem_hand = bsdh->vm_hand ;
+ LBA_ELEM_PTR tmp_lba ;
+ VM_PTR vm_lba_ptr ;
+
+ vm_lba_ptr = (VM_PTR)bsd->lba_vm_q_head ;
+
+ if ( vm_lba_ptr != 0 ) {
+
+ tmp_lba = (LBA_ELEM_PTR)VM_MemLock( vmem_hand, vm_lba_ptr, VM_READ_ONLY ) ;
+
+ if ( tmp_lba != NULL ) {
+
+ *lba = *tmp_lba ;
+ VM_MemUnLock( vmem_hand, vm_lba_ptr ) ;
+
+ return SUCCESS ;
+ }
+
+ }
+ return FAILURE ;
+}
+
+
+#if defined(OBSOLETE_CODE)
+static INT16 BSD_GetLastLBA(
+BSD_PTR bsd, /* I - BSD to process off of */
+LBA_ELEM_PTR lba ) /* O - The first LBA in the Queue */
+{
+ BSD_HAND bsdh = (BSD_HAND)GetQueueElemPtr( &bsd->q ) ;
+ VM_HDL vmem_hand = bsdh->vm_hand ;
+ LBA_ELEM_PTR tmp_lba ;
+ VM_PTR vm_lba_ptr ;
+
+ vm_lba_ptr = (VM_PTR)bsd->lba_vm_q_tail ;
+
+ if ( vm_lba_ptr != 0 ) {
+
+ tmp_lba = (LBA_ELEM_PTR)VM_MemLock( vmem_hand, vm_lba_ptr, VM_READ_ONLY ) ;
+
+ if ( tmp_lba != NULL ) {
+
+ *lba = *tmp_lba ;
+ VM_MemUnLock( vmem_hand, vm_lba_ptr ) ;
+
+ return SUCCESS ;
+ }
+
+ }
+ return FAILURE ;
+}
+#endif
+
+
+INT16 BSD_GetNextLBA( BSD_PTR bsd, LBA_ELEM_PTR lba )
+{
+ BSD_HAND bsdh = (BSD_HAND)GetQueueElemPtr( &bsd->q ) ;
+ VM_HDL vmem_hand = bsdh->vm_hand ;
+ LBA_ELEM_PTR tmp_lba ;
+ VM_PTR vm_lba_ptr ;
+
+ vm_lba_ptr = (VM_PTR)lba->next ;
+
+ if ( vm_lba_ptr != 0 ) {
+
+ tmp_lba = (LBA_ELEM_PTR)VM_MemLock( vmem_hand, vm_lba_ptr, VM_READ_ONLY ) ;
+
+ if ( tmp_lba != NULL ) {
+
+ *lba = *tmp_lba ;
+ VM_MemUnLock( vmem_hand, vm_lba_ptr ) ;
+
+ return SUCCESS ;
+ }
+
+ }
+ return FAILURE ;
+}
+
+
diff --git a/private/utils/ntbackup/src/atachdle.c b/private/utils/ntbackup/src/atachdle.c
new file mode 100644
index 000000000..e52403c8a
--- /dev/null
+++ b/private/utils/ntbackup/src/atachdle.c
@@ -0,0 +1,237 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: atachdle.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file changes the default drive to the
+ specified drive.
+
+
+ $Log: Q:/LOGFILES/ATACHDLE.C_V $
+
+ Rev 1.9 18 Jun 1993 09:28:06 MIKEP
+enable C++
+
+ Rev 1.8 11 Nov 1992 09:52:26 GREGG
+Unicodeized literals.
+
+ Rev 1.7 10 Nov 1992 08:17:48 STEVEN
+move os path and os name into common part of dblk
+
+ Rev 1.6 16 Mar 1992 10:07:28 LORIB
+Added InitQueue() for path_q.
+
+ Rev 1.5 09 Jan 1992 09:27:38 STEVEN
+remove detnet.h from header list -- NOT USED
+
+ Rev 1.4 18 Aug 1991 15:55:40 BARRY
+ret_val not initialized in FS_DetachDLE().
+
+ Rev 1.3 06 Aug 1991 18:26:36 DON
+added NLM File System support
+
+ Rev 1.2 21 Jun 1991 13:34:04 BARRY
+Changes for new config.
+
+ Rev 1.1 03 Jun 1991 13:26:22 BARRY
+Remove product defines from conditional compilation.
+
+ Rev 1.0 09 May 1991 13:41:44 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include "stdtypes.h"
+#include "std_err.h"
+
+#include "fsys.h"
+#include "beconfig.h"
+#include "be_debug.h"
+/* $end$ include list */
+/**/
+/**
+
+ Name: FS_AttachToDLE()
+
+ Description: This function makes the default drive for the specified
+ file system handle the drive specified by dle. If the file system
+ is not opened, then this routine will open it. If the provided
+ file system handle is currently attached to a different drive, then
+ this routine will detach it and re-use the handle for the new type of
+ drive.
+
+
+ Modified: 7/17/1989
+
+ Returns: Error Codes:
+ ACCESS_DENIED
+ OUT_OF_MEMORY
+ INVALID_DLE
+ SUCCESS
+
+ Notes: It is considered good practice to Detach from one
+ DLE prior to attaching to another.
+
+ See also: $/SEE( FS_DetachDLE(), FS_OpenFileSys() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 FS_AttachToDLE(
+FSYS_HAND *fsh, /*I/O- file system handle */
+GENERIC_DLE_PTR dle, /* I - Drive to attach to */
+BE_CFG_PTR cfg, /* I - confuration struct to use */
+CHAR_PTR user_name, /* I - user name for login */
+CHAR_PTR pswd) /* I - password for login */
+{
+ INT16 fs_error = SUCCESS ;
+ UINT8 type ;
+#if ( defined(FS_AFP) || defined(FS_NONAFP) )
+ NOV_DRV_DLE_PTR nov_dle;
+#elif ( defined(FS_NLMAFP) || defined(FS_NLMNOV) )
+ NLM_DLE_PTR nlm_dle;
+#endif
+
+/* if ( (dle->type < MAX_DRV_TYPES) && (dle->type >= 0) ) { */
+
+ if ( dle->type < MAX_DRV_TYPES ) {
+
+ fs_error = FS_OpenFileSys( fsh, dle->type, cfg );
+
+ if ( fs_error == SUCCESS ) {
+
+ (*fsh)->attached_dle = dle ;
+ (*fsh)->dle_hand = dle->handle ;
+ (*fsh)->cur_dir[0] = TEXT('\\') ;
+ (*fsh)->cur_dir[1] = TEXT('\0') ;
+ (*fsh)->cfg = cfg ;
+
+ type = dle->type;
+
+ #if ( defined(FS_AFP) && defined(FS_NONAFP) )
+ if ( ( type == NOVELL_AFP_DRV ) && !BEC_GetAFPSupport( cfg ) ) {
+ type = NOVELL_DRV ;
+ }
+ #endif
+
+ #if ( defined(FS_NLMAFP) && defined(FS_NLMNOV) )
+ if ( ( type == NLM_AFP_VOLUME ) && !BEC_GetAFPSupport( cfg ) ) {
+ type = NLM_VOLUME ;
+ }
+ #endif
+
+ (*fsh)->f_type = type ;
+
+ (*fsh)->tab_ptr = &func_tab[ (*fsh)->f_type ] ;
+
+ InitQueue( &((*fsh)->min_ddb_stk) ) ;
+
+ InitQueue( &((*fsh)->in_use_name_q) ) ;
+
+ InitQueue( &((*fsh)->avail_name_q) ) ;
+
+ fs_error = (*fsh)->tab_ptr->AttachToDLE( *fsh, dle, user_name, pswd );
+
+ if ( fs_error ) {
+ (*fsh)->attached_dle = NULL ;
+ FS_CloseFileSys( *fsh );
+ *fsh = NULL ;
+ } else {
+
+ /* Print out some debug stuff */
+
+ BE_Zprintf( DEBUG_FILE_SYSTEM, RES_ATTACH_TO_DLE, dle->device_name ) ;
+
+ #if ( defined(FS_AFP) || defined(FS_NONAFP) )
+ if ( (type == NOVELL_DRV) || (type == NOVELL_AFP_DRV) ) {
+ nov_dle = dle->info.nov ;
+ BE_Zprintf( DEBUG_FILE_SYSTEM, RES_NOVELL_SERVER_INFO,
+ ( (type == NOVELL_AFP_DRV) ? 1 : 0 ),
+ nov_dle->ser_name,
+ nov_dle->volume,
+ nov_dle->server_support ) ;
+ BE_Zprintf( DEBUG_FILE_SYSTEM, RES_DLE_BASE_PATH, nov_dle->base_path ) ;
+ }
+ #endif
+
+ #if ( defined(FS_NLMAFP) || defined(FS_NLMNOV) )
+ if ( (type == NLM_VOLUME) || (type == NLM_AFP_VOLUME) ) {
+ nlm_dle = dle->info.nlm ;
+ BE_Zprintf( DEBUG_FILE_SYSTEM, RES_NOVELL_SERVER_INFO,
+ ( (type == NLM_AFP_VOLUME) ? 1 : 0 ),
+ nlm_dle->ser_name,
+ nlm_dle->volume,
+ nlm_dle->server_support ) ;
+ }
+ #endif
+ }
+ }
+
+ if ( fs_error == SUCCESS ) {
+ dle->attach_count ++ ;
+ }
+
+ } else {
+ fs_error = FS_INVALID_DLE ;
+ }
+
+ return fs_error ;
+}
+/**/
+/**
+
+ Name: FS_DetachDLE()
+
+ Description: This function releases the attachment between a fse and
+ it's DLE. This must be done in order to do a DLE_ResetList( )
+ function.
+
+ Modified: 7/19/1989
+
+ Returns: none
+
+ Notes: It is considered good practice to Detach from one
+ DLE prior to attaching to another.
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 FS_DetachDLE( FSYS_HAND fsh )
+{
+ GENERIC_DLE_PTR dle;
+ INT16 ret_val = SUCCESS;
+
+ if ( fsh == NULL ) {
+ return FS_DLE_NOT_ATTACHED ;
+ }
+
+ dle = fsh->attached_dle ;
+ if ( dle != NULL ) {
+
+ BE_Zprintf( DEBUG_FILE_SYSTEM, RES_DETACH_FROM_DLE, dle->device_name ) ;
+
+ fsh->tab_ptr->DetachDLE( fsh ) ;
+
+ dle->attach_count -- ;
+
+ fsh->attached_dle = NULL ;
+
+ }
+ else {
+ ret_val = FS_DLE_NOT_ATTACHED ;
+ }
+
+ FS_CloseFileSys( fsh );
+
+ return ret_val ;
+}
+
+
+
diff --git a/private/utils/ntbackup/src/att_drv.c b/private/utils/ntbackup/src/att_drv.c
new file mode 100644
index 000000000..ace55f8c6
--- /dev/null
+++ b/private/utils/ntbackup/src/att_drv.c
@@ -0,0 +1,318 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-92
+
+ Name: att_drv.c
+
+ Description:
+
+ $Log: G:/UI/LOGFILES/ATT_DRV.C_V $
+
+ Rev 1.16 09 Jun 1993 19:30:58 MIKEP
+enable c++
+
+ Rev 1.15 07 Oct 1992 14:53:48 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.14 04 Oct 1992 19:32:20 DAVEV
+Unicode Awk pass
+
+ Rev 1.13 06 Aug 1992 13:20:48 CHUCKB
+Changes for NT.
+
+ Rev 1.12 14 May 1992 17:23:52 MIKEP
+nt pass 2
+
+ Rev 1.11 24 Mar 1992 14:45:34 DAVEV
+OEM_MSOFT: Removed Servers windows and associated code
+
+ Rev 1.10 17 Mar 1992 11:53:44 MIKEP
+add silently but deadly feature
+
+ Rev 1.9 12 Mar 1992 09:55:46 MIKEP
+refresh fixes
+
+ Rev 1.8 20 Feb 1992 16:51:04 MIKEP
+no handles error
+
+ Rev 1.7 12 Jan 1992 18:23:48 MIKEP
+error message for attach failure
+
+ Rev 1.6 20 Dec 1991 09:32:22 DAVEV
+16/32 bit port - 2nd pass
+
+ Rev 1.5 18 Dec 1991 14:08:00 GLENN
+Added windows.h
+
+ Rev 1.4 14 Dec 1991 13:44:56 JOHNWT
+changes for pw to enable db
+
+ Rev 1.3 12 Dec 1991 11:05:30 JOHNWT
+added pwdb support
+
+ Rev 1.2 02 Dec 1991 14:07:30 MIKEP
+fix attach problem
+
+ Rev 1.1 01 Dec 1991 16:01:40 MIKEP
+check if password was saved
+
+ Rev 1.0 20 Nov 1991 19:16:56 SYSTEM
+Initial revision.
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+#define NONE_SUPPLIED 0 /* no password supplied */
+#define FROM_PWDB 1 /* password came from password data base */
+#define FROM_USER 2 /* password came from user prompt */
+
+/*****************************************************************************
+
+ Name: UI_AttachDrive
+
+ Description: This function will attach the mapped drive specified
+ by the DLE specified. If a user name or password
+ is required, a pop up window will prompt the user
+ for the appropiate information.
+
+ Returns: One of the following statuses :
+
+ SUCCESS
+ FS_ACCESS_DENIED
+ FS_NO_MORE_CONNECTIONS
+ RES_ERROR_DURING_ATTACH ( error codes )
+ USER_ABORT
+ FS_SERVER_ADDR_NOT_FOUND
+ FS_MAX_SERVER_CONNECTIONS
+ FS_BAD_ATTACH_TO_SERVER
+ FS_BAD_SERVER_LOGIN
+*****************************************************************************/
+
+INT16 UI_AttachDrive(
+FSYS_HAND *tmp_fsh,
+GENERIC_DLE_PTR dle_ptr,
+BOOLEAN silent_login_only )
+{
+ CHAR_PTR name_buf = NULL;
+ CHAR_PTR pswd_buf = NULL;
+ INT16 name_len;
+ INT16 pswd_len;
+ BOOLEAN passwd_source = NONE_SUPPLIED;
+ BOOLEAN attempt_attach = TRUE;
+ INT16 result = USER_ABORT;
+ Q_HEADER_PTR srv_list;
+ WININFO_PTR wininfo;
+ VLM_OBJECT_PTR server_vlm;
+
+
+ *tmp_fsh = NULL;
+
+ // If silent mode, only login if no password required, password has
+ // already been entered or password database is active and contains
+ // a matching entry for this dle.
+
+ if ( silent_login_only ) {
+
+ if ( DLE_PswdRequired( dle_ptr ) ) {
+
+ if ( DLE_PswdSaved( dle_ptr ) ) {
+ // go ahead with login
+ }
+ else {
+ if ( CheckThePWDBase( CDS_GetPerm(), dle_ptr ) == SUCCESS ) {
+ // go ahead with login
+ }
+ else {
+ return( FAILURE );
+ }
+ }
+ }
+ }
+
+ /* First check to see if this DLE requires a user name or a password.
+ If so, allocate the space for them (required in FS_AttachToDLE). */
+
+ name_len = DLE_UserRequired( dle_ptr );
+ pswd_len = DLE_PswdRequired( dle_ptr );
+
+ if ( name_len != 0 ) {
+ name_buf = (CHAR_PTR)malloc( name_len );
+ if ( name_buf == NULL ) {
+ return FAILURE;
+ }
+ }
+
+ if ( pswd_len != 0 ) {
+ pswd_buf = (CHAR_PTR)malloc( pswd_len );
+ if ( pswd_buf == NULL ) {
+ if ( name_buf != NULL ) {
+ free( name_buf );
+ }
+ return FAILURE;
+ }
+ }
+
+ /* check to see if we need to get the username/pswd for a server,
+ right now, all we support are Novell server logins */
+
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ if ( DLE_GetDeviceType( dle_ptr ) == NOVELL_SERVER_ONLY ) {
+
+ /* If we are not alreay logged into the server and we do not already
+ have the password, first check the pwdb and then prompt the user
+ for the attach info. */
+
+ if ( ! DLE_ServerLoggedIn( dle_ptr ) &&
+ ( ! DLE_PswdSaved( dle_ptr ) && DLE_PswdRequired( dle_ptr ) ) ) {
+
+ if ( CheckThePWDBase( CDS_GetPerm(), dle_ptr ) == SUCCESS ) {
+
+ passwd_source = FROM_PWDB;
+
+ } else {
+
+ if ( DM_AttachToServer( DLE_GetDeviceName( dle_ptr ),
+ name_buf, name_len,
+ pswd_buf, pswd_len ) == SUCCESS ) {
+
+ passwd_source = FROM_USER;
+
+ } else {
+
+ attempt_attach = FALSE;
+ }
+ }
+ }
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ /* if we have not failed to get a password from the user, attempt to
+ attach to the DLE */
+
+ while ( attempt_attach ) {
+
+ WM_ShowWaitCursor( TRUE );
+
+ result = FS_AttachToDLE( tmp_fsh, dle_ptr,
+ CDS_GetPermBEC( ), name_buf,
+ pswd_buf );
+
+ WM_ShowWaitCursor( FALSE );
+
+ attempt_attach = FALSE;
+
+ switch ( result ) {
+
+ case SUCCESS:
+
+ /* if there is currently a servers window displayed, add the
+ children (volumes) to the window */
+
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ if ( gb_servers_win != (HWND)NULL ) {
+
+ wininfo = WM_GetInfoPtr( gb_servers_win );
+ srv_list = WMDS_GetTreeList( wininfo );
+ server_vlm = VLM_FindVLMByName( srv_list,
+ DLE_GetDeviceName( dle_ptr ) );
+
+ if ( server_vlm != NULL ) {
+
+ // If we already know about some children don't do this.
+ // It screws up the refresh calls kludges for the backup
+ // engines call to dle_update().
+
+ if ( QueueCount( &server_vlm->children ) == 0 ) {
+ VLM_AddInServerChildren( server_vlm );
+ }
+ }
+ }
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ /* if the user was prompted for the name/pswd, save it in pwdbase */
+
+ if ( passwd_source == FROM_USER ) {
+ SaveDLEPassword( CDS_GetPerm(), dle_ptr, pswd_buf, name_buf );
+ }
+
+ break;
+
+ case FS_MAX_SERVER_CONNECTIONS:
+ case FS_NO_MORE_CONNECTIONS:
+ if ( ! silent_login_only ) {
+ eresprintf( RES_NO_MORE_CONNECTIONS );
+ }
+ break;
+
+ case FS_SERVER_ADDR_NOT_FOUND:
+ if ( ! silent_login_only ) {
+ eresprintf( RES_SERVER_ADDR_NOT_FOUND, DLE_GetDeviceName ( dle_ptr ) );
+ }
+ break;
+
+ case FS_BAD_ATTACH_TO_SERVER:
+ if ( ! silent_login_only ) {
+ eresprintf( RES_BAD_ATTACH_TO_SERVER, DLE_GetDeviceName ( dle_ptr ) );
+ }
+ break;
+
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ case FS_ACCESS_DENIED:
+ case FS_BAD_SERVER_LOGIN:
+
+ if ( ! silent_login_only ) {
+ /* we had a bad login, so let the user try again */
+
+ if ( passwd_source != NONE_SUPPLIED ) {
+
+ eresprintf( RES_BAD_SERVER_LOGIN, DLE_GetDeviceName ( dle_ptr ) );
+
+ if ( DM_AttachToServer( DLE_GetDeviceName( dle_ptr ),
+ name_buf, name_len,
+ pswd_buf, pswd_len ) == SUCCESS ) {
+
+ passwd_source = FROM_USER;
+ attempt_attach = TRUE;
+ }
+
+ break;
+ }
+ else {
+
+ if ( result == FS_ACCESS_DENIED ) {
+ eresprintf( RES_ERROR_ATTACHING, DLE_GetDeviceName( dle_ptr ) );
+ break;
+ }
+ }
+ }
+ /* FALL THROUGH TO GENERAL ERROR MESSAGE */
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ default:
+ if ( ! silent_login_only ) {
+ eresprintf( RES_ERROR_DURING_ATTACH, result,
+ DLE_GetDeviceName( dle_ptr ) );
+ }
+ break;
+ }
+
+ } /* end while */
+
+ /* free any allocated memory */
+
+ if ( name_buf != NULL ) {
+ free( name_buf );
+ }
+ if ( pswd_buf != NULL ) {
+ free( pswd_buf );
+ }
+
+ return result;
+}
+
diff --git a/private/utils/ntbackup/src/back_dle.c b/private/utils/ntbackup/src/back_dle.c
new file mode 100644
index 000000000..2c3e6e0ea
--- /dev/null
+++ b/private/utils/ntbackup/src/back_dle.c
@@ -0,0 +1,231 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: back_dle.c
+
+ Description: this file contains the routines responsible for backing up a single volume.
+
+ $Log: N:\logfiles\back_dle.c_v $
+
+ Rev 1.15.1.0 26 Apr 1994 18:59:38 STEVEN
+fix dissconect bug
+
+ Rev 1.15 14 Jan 1993 13:33:28 STEVEN
+added stream_id to error message
+
+ Rev 1.14 24 Feb 1992 09:54:54 GREGG
+Call TF_OpenTape at beginning of loop, Open/Close Set in loop, CloseTape at end.
+
+ Rev 1.13 19 Feb 1992 15:59:42 GREGG
+Added vcb_only parameter to call to TF_OpenSet.
+
+ Rev 1.12 31 Jan 1992 14:55:44 STEVEN
+do not send message if did not backup VCB
+
+ Rev 1.11 06 Nov 1991 18:24:56 GREGG
+BIGWHEEL - 8200sx - Get cat_enabled from lp instead of lis.
+
+ Rev 1.10 17 Oct 1991 01:50:16 ED
+BIGWHEEL - 8200sx - Initial integration.
+
+ Rev 1.9 25 Jul 1991 11:32:48 GREGG
+Added logic to handle EOM encountered during close-out of write operation.
+
+ Rev 1.8 22 Jul 1991 10:20:10 DAVIDH
+Corrected type mismatch warnings.
+
+ Rev 1.7 24 Jun 1991 17:20:40 STEVEN
+remove date time from StartBS
+
+ Rev 1.6 21 Jun 1991 09:28:28 STEVEN
+new config unit
+
+ Rev 1.5 30 May 1991 09:12:34 STEVEN
+bsdu_err.h no longer exists
+
+ Rev 1.4 24 May 1991 14:42:48 STEVEN
+complete changes for new getnext
+
+ Rev 1.3 23 May 1991 16:34:02 STEVEN
+backup date should be set by messager handler
+
+ Rev 1.2 23 May 1991 16:18:54 STEVEN
+update for BSD redesign
+
+ Rev 1.1 14 May 1991 13:32:06 DAVIDH
+Resolved pointer mismatch warnings under Watcom compiler
+
+ Rev 1.0 09 May 1991 13:39:14 HUNTER
+Initial revision.
+
+**/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "tbe_defs.h"
+#include "tbe_err.h"
+#include "bsdu.h"
+#include "fsys.h"
+#include "tflproto.h"
+#include "loops.h"
+#include "loop_prv.h"
+#include "lis.h"
+#include "get_next.h"
+#include "tfldefs.h"
+#include "tfl_err.h"
+#include "msassert.h"
+
+/**/
+/**
+
+ Name: LP_BackupDLE()
+
+ Description: this routine backs up all selections on a single dle.
+
+ Modified: 5/23/1991 16:2:28
+
+ Returns: tape backup engine error
+
+ Notes: na
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+INT16 LP_BackupDLE(
+BSD_PTR bsd_ptr, /* I - Backup selections */
+register LP_ENV_PTR lp, /* I - Loop Environment structure */
+UINT16 tfl_open_mode, /* I - what mode, WRITE or APPEND */
+INT16 channel_no, /* I - channel we're using */
+THW_PTR sdrv ) /* I - strating tape drive */
+{
+ INT16 return_status = SUCCESS ;
+ DBLK_PTR curr_blk ;
+ TFL_OPBLK pb ;
+ DATA_FRAGMENT data_frag ;
+
+ /* set up for tape positioning */
+
+ pb.tape_position = &lp->tpos ;
+ pb.rewind_sdrv = FALSE ;
+ pb.sdrv = sdrv ;
+ pb.perm_filter = TF_KEEP_ALL_DATA ;
+ pb.attributes = 0L ;
+ pb.fsh = lp->curr_fsys ;
+ pb.mode = tfl_open_mode ;
+ pb.ignore_clink = FALSE ;
+ pb.wrt_format = 0 ;
+ pb.idle_call = NULL ;
+ pb.cat_enabled = lp->cat_enabled ;
+ pb.channel = channel_no ;
+ data_frag.buffer_used = 0 ;
+ data_frag.buffer_size = 0 ;
+ data_frag.memory_allocated = 0 ;
+ data_frag.buffer = NULL ;
+
+ /* Now open the backup set */
+ if( ( return_status = TF_OpenSet( &pb, FALSE ) ) == SUCCESS ) {
+
+ /* Set current channel in LP, and update BSD for this THW */
+ lp->channel = pb.channel ;
+ LP_DetermineCurrentTPDrv( bsd_ptr, pb.channel ) ;
+
+ GetCurrentDate( &lp->backup_dt ) ;
+
+ /* Init operation and send vcb down the wire */
+ return_status = LP_BackupVCB( bsd_ptr, lp ) ;
+
+ /* log start of backup set */
+ if ( return_status == SUCCESS ) {
+ LP_MsgStartBS( lp->lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, lp->curr_blk ) ;
+ }
+
+ /* Now we have the GetNextItemLoop */
+ while( return_status == SUCCESS ) {
+
+ if( ( return_status = LP_GetNextDLEBlock( lp, &curr_blk ) ) == SUCCESS ) {
+
+ if ( curr_blk != NULL ) {
+ return_status = LP_BackupOBJ( lp, curr_blk, &data_frag ) ;
+ } else {
+ break ;
+ }
+
+ } else {
+ if ( return_status != FS_NO_MORE ) {
+ LP_MsgError( lp->lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, return_status, NULL, NULL, 0L ) ;
+ }
+ }
+
+
+ /* check for abort conditions */
+ switch( LP_GetAbortFlag( lp->lis_ptr ) ) {
+
+ case CONTINUE_PROCESSING:
+ break ;
+
+ case ABORT_CTRL_BREAK:
+ LP_MsgError( lp->lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, LP_USER_ABORT_ERROR, NULL, NULL, 0L ) ;
+
+ /* falling through */
+
+ case ABORT_PROCESSED:
+ return_status = USER_ABORT ;
+ break ;
+
+ case ABORT_AT_EOM:
+ return_status = USER_ABORT ;
+ break ;
+ }
+ }
+
+ /* Process last tape format request as long as no fatal error occurred */
+ switch( return_status ) {
+
+ case SUCCESS:
+ case USER_ABORT:
+ case FS_COMM_FAILURE:
+ if( return_status == SUCCESS ) {
+ lp->rr.lp_message = LRW_END ;
+ } else {
+ lp->rr.lp_message = LRW_ABORT ;
+ }
+ if( LP_GetAbortFlag( lp->lis_ptr ) != ABORT_AT_EOM ) {
+ if( ( return_status = TF_GetNextTapeRequest( &lp->rr ) ) != SUCCESS ) {
+ LP_MsgError( lp->lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, return_status, NULL, NULL, 0L ) ;
+ } else {
+ if( lp->rr.tf_message == TRW_EOM ) {
+ return_status = LP_ProcessEOM( lp, TRW_EOM ) ;
+ }
+ }
+ }
+ break ;
+
+ default:
+ /* don't care about these conditions */
+ break ;
+
+ }
+
+ /* Log end of backup set (being optimistic that the last buffer goes to tape) */
+ LP_MsgEndBS( lp->lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos ) ;
+
+ /* Close set, save current tape device and post tape stats */
+ LP_CloseSet( pb.channel ) ;
+
+ }
+ else {
+ TF_CloseSet( pb.channel, NULL ) ;
+ LP_MsgError( lp->lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, return_status, NULL, NULL, 0L ) ;
+ }
+
+ free( data_frag.buffer ) ;
+
+ return( return_status ) ;
+
+}
+
diff --git a/private/utils/ntbackup/src/back_obj.c b/private/utils/ntbackup/src/back_obj.c
new file mode 100644
index 000000000..b2a3bdab5
--- /dev/null
+++ b/private/utils/ntbackup/src/back_obj.c
@@ -0,0 +1,847 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: back_obj.c
+
+ Description: this module contains the backup obj
+ routine.
+
+
+ $Log: N:\logfiles\back_obj.c_v $
+
+ Rev 1.44.1.4 26 Apr 1994 19:00:08 STEVEN
+fix dissconnect bug
+
+ Rev 1.44.1.3 28 Mar 1994 14:28:24 GREGG
+Pass STRM_INVALID instead of -1 on ACCESS_DENIED_ERROR.
+
+ Rev 1.44.1.2 28 Jan 1994 11:06:44 GREGG
+More Warning Fixes
+
+ Rev 1.44.1.1 19 Jan 1994 12:51:14 BARRY
+Supress warnings
+
+ Rev 1.44.1.0 16 Nov 1993 19:33:18 STEVEN
+move message for corrupt to top of pad code
+
+ Rev 1.44 17 Aug 1993 03:38:22 GREGG
+Fixed handling of corrupt streams.
+
+ Rev 1.43 12 Aug 1993 15:57:38 BARRY
+Only log bad block once on mult bad streams.
+
+ Rev 1.42 05 Aug 1993 20:09:34 BARRY
+Needed to log bad block on corrupt stream and send stream number to
+LP_PadToEndEndOfStream so CFIL is made correctly.
+
+ Rev 1.41 19 Jul 1993 13:44:58 BARRY
+Log bad blocks for corrupt files.
+
+ Rev 1.40 17 Jul 1993 14:58:58 GREGG
+Set buff_used in LP_PadToEndOfStream.
+
+ Rev 1.39 09 Jun 1993 19:38:14 MIKEP
+enable c++ compile
+
+ Rev 1.38 11 May 1993 13:08:04 DON
+Need to check for COMM_FAILURE during read/write operations. May lose attachment!
+
+ Rev 1.37 28 Apr 1993 12:57:16 MARILYN
+fixed per Steve D. Should not have been updated amount_read with
+the amount in the frag buffer since we haven't actually processed
+it.
+
+ Rev 1.36 25 Apr 1993 20:13:48 GREGG
+Fifth in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Store the corrupt stream number in the CFIL tape struct and the CFDB.
+
+Matches: MTF10WDB.C 1.9, FSYS.H 1.33, FSYS_STR.H 1.47, MAKECFDB.C 1.2,
+ BACK_OBJ.C 1.36, MAYN40RD.C 1.58
+
+ Rev 1.35 31 Mar 1993 08:54:30 MARILYN
+changed over to MTF checksums. If we are generating a checksum for a
+data stream, we now update the stream header to say so.
+
+ Rev 1.34 25 Mar 1993 17:52:12 CHUCKB
+No longer treat the skip files flag as a boolean. Only skip if the user has asked to skip; if he
+wants to wait before he skips, let him.
+
+ Rev 1.33 16 Mar 1993 13:37:00 MARILYN
+The checksum for a buffer needed to be computed before the LP_Send
+because once TF got it's grubby little hands on it the data was no
+good.
+
+ Rev 1.32 13 Mar 1993 17:10:48 GREGG
+Back to calling LP_Send before LP_SendDataEnd.
+
+ Rev 1.31 11 Mar 1993 12:43:54 STEVEN
+fix bugs found by GREGG
+
+ Rev 1.30 01 Mar 1993 17:33:52 MARILYN
+If BEC_GetProcChecksumStrms is true, write a checksum stream to tape
+each object.
+
+ Rev 1.29 13 Feb 1993 14:03:30 MARILYN
+amount_read was not being updated properly
+
+ Rev 1.28 01 Feb 1993 19:46:28 STEVEN
+bug fixes
+
+ Rev 1.27 30 Jan 1993 14:36:10 MARILYN
+It is now acceptable for read to send back data with FS_EOF_REACHED.
+
+ Rev 1.26 27 Jan 1993 13:50:42 STEVEN
+updates from msoft
+
+ Rev 1.25 18 Jan 1993 16:46:48 STEVEN
+fix bug, we did not save the file handle in LP
+
+ Rev 1.24 14 Jan 1993 16:40:08 STEVEN
+fix bugs in last checkin
+
+ Rev 1.23 14 Jan 1993 13:34:06 STEVEN
+added stream_id to error message
+
+ Rev 1.22 28 Oct 1992 16:41:10 STEVEN
+send end for CFDB
+
+ Rev 1.21 26 Oct 1992 10:53:40 STEVEN
+allways read even if buffer size= 0
+
+ Rev 1.20 05 Oct 1992 10:29:18 STEVEN
+remove TotalSize
+
+ Rev 1.19 16 Sep 1992 16:55:02 STEVEN
+added support for stream info struct for Tpfmt
+
+ Rev 1.18 01 Sep 1992 16:11:56 STEVEN
+added stream headers to fsys API
+
+ Rev 1.17 23 Jul 1992 09:06:24 STEVEN
+fix warnings
+
+ Rev 1.16 29 May 1992 13:57:40 STEVEN
+if EOF on var length then SUCCESS
+
+ Rev 1.15 28 May 1992 16:36:06 TIMN
+Changed CHAR to INT8
+
+ Rev 1.14 05 May 1992 17:19:18 STEVEN
+fixed typos and misc bugs
+
+ Rev 1.13 16 Mar 1992 16:48:08 STEVEN
+more 64 bit support for format 40
+
+ Rev 1.12 13 Mar 1992 09:23:34 STEVEN
+4.0 tape format 64 bit
+
+ Rev 1.11 16 Jan 1992 15:45:18 STEVEN
+fix warnings for WIN32
+
+ Rev 1.10 12 Dec 1991 10:00:42 STEVEN
+change read to FS_READ
+
+ Rev 1.9 21 Nov 1991 19:17:14 BARRY
+Got rid of Steve's temporary FS_OBJECT_CORRUPT #define.
+
+ Rev 1.8 07 Nov 1991 12:42:30 STEVEN
+TRYCYCLE - added support for varible length files
+
+ Rev 1.7 21 Jun 1991 09:28:10 STEVEN
+new config unit
+
+ Rev 1.6 17 Jun 1991 16:28:08 STEVEN
+LP_PadData is called from lptools.c so it was moved to there
+
+ Rev 1.5 30 May 1991 09:11:58 STEVEN
+bsdu_err.h no longer exists
+
+ Rev 1.4 29 May 1991 14:55:04 DAVIDH
+Corrected assignment statement using '==' instead of '='.
+
+ Rev 1.3 24 May 1991 14:42:18 STEVEN
+complete changes for new getnext
+
+ Rev 1.2 23 May 1991 16:19:14 STEVEN
+update for BSD redesign
+
+ Rev 1.1 23 May 1991 16:03:02 BARRY
+Cleaned up code per first LOOPS code review.
+
+ Rev 1.0 09 May 1991 13:39:16 HUNTER
+Initial revision.
+
+**/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "beconfig.h"
+#include "msassert.h"
+#include "tbe_defs.h"
+#include "tbe_err.h"
+#include "bsdu.h"
+#include "fsys.h"
+#include "datetime.h"
+#include "tflproto.h"
+#include "loops.h"
+#include "tfldefs.h"
+#include "loop_prv.h"
+#include "lis.h"
+#include "checksum.h"
+
+
+
+INT16 LP_PadToEndOfStream( LP_ENV_PTR lp, UINT32 attrib, UINT16 streamNumber ) ;
+
+/**/
+/**
+
+ Name: LP_BackupOBJ()
+
+ Description: this routine processes a single object,
+ by calling the appropriate file system
+ and tape format layer routines.
+
+ Modified: 5/23/1991 16:6:52
+
+ Returns: tape backup engine error.
+
+ Notes: na
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+INT16 LP_BackupOBJ(
+LP_ENV_PTR lp,
+DBLK_PTR blk_ptr,
+DATA_FRAGMENT_PTR frag_ptr )
+{
+ UINT32 space_fwd ;
+ INT16 return_status = SUCCESS ;
+ BOOLEAN opened_in_use = FALSE ;
+ UINT16 amount_read ;
+ UINT64 bytes_skipped ;
+ UINT32 file_offset ;
+ BSD_PTR bsd_ptr;
+ FSYS_HAND fsh ;
+ UINT32 pid ;
+ BE_CFG_PTR cfg ;
+ BOOLEAN math_stat ;
+ INT16 close_status ;
+ UINT32 checksum ;
+ BOOLEAN insertChecksum = FALSE ;
+ UINT16 streamNumber = 0;
+
+ lp->corrupt_file = FALSE ;
+
+ fsh = lp->curr_fsys ;
+ bsd_ptr = lp->lis_ptr->curr_bsd_ptr ;
+ pid = lp->lis_ptr->pid ;
+ cfg = BSD_GetConfigData( lp->lis_ptr->curr_bsd_ptr ) ;
+
+ /* Opening files in use, now check for this case */
+ lp->f_hand = &lp->file_hand ;
+ switch( ( return_status = FS_OpenObj( fsh, &lp->file_hand, blk_ptr, FS_READ ) ) ) {
+
+ case FS_OPENED_INUSE:
+ opened_in_use = TRUE ;
+ break;
+
+ case FS_BAD_ATTACH_TO_SERVER:
+ case FS_ACCESS_DENIED:
+
+ if ( return_status == FS_ACCESS_DENIED ) {
+ return_status = LP_ACCESS_DENIED_ERROR ;
+ }
+
+ LP_MsgError( lp->lis_ptr->pid,
+ lp->lis_ptr->curr_bsd_ptr,
+ lp->curr_fsys,
+ &lp->tpos,
+ return_status,
+ lp->curr_ddb,
+ blk_ptr,
+ STRM_INVALID ) ;
+
+ LP_MsgBlockSkipped( pid, bsd_ptr, fsh, &lp->tpos, blk_ptr, lp->curr_ddb ) ;
+ bytes_skipped = FS_GetDisplaySizeFromDBLK( fsh, blk_ptr ) ;
+ LP_MsgBytesSkipped( pid, bsd_ptr, fsh, &lp->tpos, bytes_skipped ) ;
+
+ return SUCCESS ;
+
+ case SUCCESS: /* Nothing special */
+ break ;
+
+ case FS_IN_USE_ERROR:
+ if( BEC_GetSkipOpenFiles( cfg ) == BEC_SKIP_OPEN_FILES ) {
+
+ LP_MsgBlockSkipped( pid, bsd_ptr, fsh, &lp->tpos, blk_ptr, lp->curr_ddb ) ;
+ bytes_skipped = FS_GetDisplaySizeFromDBLK( fsh, blk_ptr ) ;
+ LP_MsgBytesSkipped( pid, bsd_ptr, fsh, &lp->tpos, bytes_skipped ) ;
+
+ return SUCCESS ;
+
+ } else {
+ switch( LP_MsgObjectInUse( pid, bsd_ptr, fsh, &lp->tpos,
+ blk_ptr, LP_CheckForOpen, ( UINT32 )lp ) ) {
+
+ case OBJECT_OPENED_INUSE:
+ opened_in_use = TRUE ;
+
+ /* falling through */
+
+ case OBJECT_OPENED_SUCCESSFULLY:
+ LP_MsgBlockProcessed( pid, bsd_ptr, fsh, &lp->tpos, blk_ptr ) ;
+ break ;
+
+ case SKIP_OBJECT:
+ LP_MsgBlockInuse( pid, bsd_ptr, fsh, &lp->tpos, blk_ptr, lp->curr_ddb ) ;
+ bytes_skipped = FS_GetDisplaySizeFromDBLK( fsh, blk_ptr ) ;
+ LP_MsgBytesSkipped( pid, bsd_ptr, fsh, &lp->tpos, bytes_skipped ) ;
+
+ return SUCCESS ;
+
+ }
+ }
+ break ;
+
+ case FS_COMM_FAILURE:
+
+ if ( DLE_GetDeviceType( BSD_GetDLE( bsd_ptr) ) == FS_EMS_DRV ) {
+ LP_MsgError( pid,
+ bsd_ptr,
+ fsh,
+ &lp->tpos,
+ FS_COMM_FAILURE,
+ lp->curr_ddb,
+ blk_ptr,
+ 0L ) ;
+ return SUCCESS ;
+
+ } else {
+
+ LP_MsgCommFailure( pid,
+ bsd_ptr,
+ fsh,
+ &lp->tpos,
+ lp->curr_ddb,
+ blk_ptr,
+ 0L );
+
+
+ return (return_status) ;
+ }
+
+
+ case FS_NOT_FOUND:
+ case FS_NO_MORE:
+
+ return SUCCESS ;
+
+ break ;
+
+ default: /* skipped */
+ LP_MsgBlockSkipped( pid, bsd_ptr, fsh, &lp->tpos, blk_ptr, lp->curr_ddb ) ;
+ bytes_skipped = FS_GetDisplaySizeFromDBLK( fsh, blk_ptr ) ;
+ LP_MsgBytesSkipped( pid, bsd_ptr, fsh, &lp->tpos, bytes_skipped ) ;
+
+ return SUCCESS ;
+
+ }
+
+ /* Now do tape format loop */
+ lp->rr.cur_dblk = blk_ptr ; /* set up current DBLK */
+ return_status = LP_Send( lp , FALSE ) ; /* data_flag FALSE to send DBLK */
+
+ /* Log the block after tape format set the LBA */
+ opened_in_use ? LP_MsgOpenedInUse( pid, bsd_ptr, fsh, &lp->tpos, blk_ptr ) :
+ LP_MsgLogBlock( pid, bsd_ptr, fsh, &lp->tpos, blk_ptr ) ;
+
+ file_offset = 0 ;
+
+ /* if checksum processing is enabled, initialize */
+ /* the checksum for this object */
+ if ( BEC_GetProcChecksumStrm( cfg ) ) {
+ Checksum_Init( &checksum ) ;
+ }
+
+ while ( !return_status && lp->rr.tf_message == TRW_DATA ) {
+
+ amount_read = 0 ;
+ lp->read_size = lp->rr.buff_size ;
+ lp->buf_start = (INT8_PTR)lp->rr.buff_ptr ;
+
+ if( frag_ptr->buffer_used != 0 ) {
+
+ if( lp->read_size < (UINT16)(frag_ptr->buffer_size - frag_ptr->buffer_used) ) {
+ memcpy( lp->buf_start,
+ frag_ptr->buffer + frag_ptr->buffer_used,
+ lp->read_size ) ;
+
+ lp->buf_start += lp->read_size ;
+ amount_read = lp->read_size ;
+ frag_ptr->buffer_used += lp->read_size ;
+ lp->read_size = 0 ;
+ } else {
+ memcpy( lp->buf_start,
+ frag_ptr->buffer + frag_ptr->buffer_used,
+ frag_ptr->buffer_size - frag_ptr->buffer_used ) ;
+
+ lp->buf_start += ( frag_ptr->buffer_size - frag_ptr->buffer_used ) ;
+ lp->read_size -= ( frag_ptr->buffer_size - frag_ptr->buffer_used ) ;
+ amount_read = ( frag_ptr->buffer_size - frag_ptr->buffer_used ) ;
+ frag_ptr->buffer_used = 0 ;
+ }
+ return_status = SUCCESS ;
+ lp->read_size = 0 ;
+ } else {
+
+ return_status = FS_ReadObj( lp->file_hand, lp->buf_start, &lp->read_size, &lp->blk_size, &lp->rr.stream ) ;
+ }
+
+ if ( lp->rr.stream.id != STRM_INVALID ) {
+
+ streamNumber++;
+
+ if ( BEC_GetProcChecksumStrm( cfg ) ) {
+ insertChecksum = TRUE ;
+ lp->rr.stream.tf_attrib |= STREAM_CHECKSUMED ;
+ }
+
+ // lets log the stream header name
+ switch( lp->rr.stream.id ) {
+ case STRM_EMS_MONO_DB:
+ case STRM_EMS_MONO_LOG:
+ {
+ CHAR strm_name[256] ;
+ UINT16 size = (UINT16)sizeof(strm_name) ;
+
+ EMS_GetStreamName( lp->file_hand, (BYTE_PTR)strm_name, &size ) ;
+ LP_MsgLogStream( pid, bsd_ptr, fsh, &lp->tpos, strm_name ) ;
+
+ break ;
+ }
+ }
+ }
+
+ /* update the amount_read to reflect that which was just read in */
+ amount_read += lp->read_size ;
+
+ if ( return_status == SUCCESS ) {
+
+ if( ( lp->rr.buff_size - amount_read != 0 ) &&
+ ( (UINT16)(lp->rr.buff_size - amount_read) < lp->blk_size ) ) {
+
+ if( frag_ptr->memory_allocated < lp->blk_size ) {
+
+ if( frag_ptr->buffer != NULL ) {
+ free( frag_ptr->buffer ) ;
+ }
+
+ frag_ptr->buffer = calloc( 1, lp->blk_size ) ;
+ if( frag_ptr->buffer == NULL ) {
+
+ LP_MsgError( pid, bsd_ptr, fsh, &lp->tpos, LP_OUT_OF_MEMORY_ERROR, NULL, NULL, 0L ) ;
+
+ FS_CloseObj( lp->file_hand ) ;
+
+ return LP_OUT_OF_MEMORY_ERROR ;
+
+ }
+
+ frag_ptr->memory_allocated = lp->blk_size ;
+ }
+
+ frag_ptr->buffer_size = lp->blk_size ;
+ frag_ptr->buffer_used = lp->blk_size ;
+
+
+ return_status = FS_ReadObj( lp->file_hand, frag_ptr->buffer, &frag_ptr->buffer_used, &lp->blk_size, &lp->rr.stream ) ;
+
+ if ( return_status == FS_EOF_REACHED ) {
+
+ /* we need to handle any data that was sent */
+ /* back from the read */
+ frag_ptr->buffer_used = lp->rr.buff_size - amount_read ;
+
+ memcpy( lp->rr.buff_ptr + amount_read,
+ frag_ptr->buffer,
+ frag_ptr->buffer_used ) ;
+
+ amount_read += frag_ptr->buffer_used ;
+ frag_ptr->buffer_used = 0 ;
+
+ lp->current_stream_size = U64_Sub( lp->current_stream_size, U32_To_U64( lp->read_size ), &math_stat ) ;
+ LP_MsgBytesProcessed( pid, bsd_ptr, fsh, &lp->tpos, U64_Init((INT32)amount_read, 0 ) ) ;
+
+ /* if checksum processing is enabled, */
+ /* compute the checksum for this object */
+ if ( insertChecksum ) {
+ Checksum_Block( &checksum, lp->buf_start, amount_read ) ;
+ }
+
+ file_offset += amount_read ;
+ lp->rr.buff_used = amount_read ;
+ if( ( return_status = LP_Send( lp, TRUE ) ) != SUCCESS ) {
+ amount_read = 0 ;
+ break ;
+ }
+
+ /* if a checksum stream is to follow the */
+ /* current data stream write it */
+ if ( insertChecksum ) {
+
+ if( ( return_status = LP_InsertChecksumStream( checksum, lp ) ) != SUCCESS ) {
+ amount_read = 0 ;
+ break ;
+ }
+ }
+
+ amount_read = 0 ;
+
+ /* we are all done with this object, tell TF */
+ return_status = LP_SendDataEnd( lp ) ;
+ break;
+
+ } else if ( ( return_status == FS_OBJECT_CORRUPT ) ||
+ ( return_status == FS_COMM_FAILURE ) ) {
+ LP_SendDataEnd( lp ) ;
+ if ( lp->corrupt_file == FALSE ) {
+ FS_SetDefaultDBLK( fsh, CFDB_ID, ( CREATE_DBLK_PTR )lp->rr.cfdb_data_ptr ) ;
+ lp->rr.cfdb_data_ptr->std_data.dblk = lp->rr.cfdb_ptr ;
+ lp->rr.cfdb_data_ptr->corrupt_offset = file_offset ;
+ lp->rr.cfdb_data_ptr->stream_number = streamNumber ;
+ FS_CreateGenCFDB( fsh, lp->rr.cfdb_data_ptr ) ;
+ lp->corrupt_file = TRUE ;
+ LP_MsgBlockBad( pid, bsd_ptr, fsh, &lp->tpos, blk_ptr, lp->curr_ddb ) ;
+ }
+ return_status = SUCCESS ;
+
+ } else if ( return_status != SUCCESS ) {
+
+ space_fwd = frag_ptr->buffer_size - frag_ptr->buffer_used ;
+
+ LP_PadData( frag_ptr->buffer + frag_ptr->buffer_used, space_fwd );
+ FS_SeekObj( lp->file_hand, &space_fwd );
+ amount_read += (UINT16)space_fwd ;
+ if ( lp->corrupt_file == FALSE ) {
+ FS_SetDefaultDBLK( fsh, CFDB_ID, ( CREATE_DBLK_PTR )lp->rr.cfdb_data_ptr ) ;
+ lp->rr.cfdb_data_ptr->std_data.dblk = lp->rr.cfdb_ptr ;
+ lp->rr.cfdb_data_ptr->corrupt_offset = file_offset ;
+ FS_CreateGenCFDB( fsh, lp->rr.cfdb_data_ptr ) ;
+ lp->corrupt_file = TRUE ;
+ LP_MsgBlockBad( pid, bsd_ptr, fsh, &lp->tpos, blk_ptr, lp->curr_ddb ) ;
+ }
+ frag_ptr->buffer_used += (UINT16)space_fwd ;
+ }
+
+
+ if( !return_status && ( frag_ptr->buffer_used == frag_ptr->buffer_size ) ) {
+
+ frag_ptr->buffer_used = lp->rr.buff_size - amount_read ;
+
+ memcpy( lp->rr.buff_ptr + amount_read,
+ frag_ptr->buffer,
+ frag_ptr->buffer_used ) ;
+
+ amount_read += frag_ptr->buffer_used ;
+ }
+ }
+ }
+
+
+ if ( return_status == FS_EOF_REACHED ) {
+
+ /* we need to handle any data that was sent */
+ /* back from the read */
+ lp->current_stream_size = U64_Sub( lp->current_stream_size, U32_To_U64( lp->read_size ), &math_stat ) ;
+ LP_MsgBytesProcessed( pid, bsd_ptr, fsh, &lp->tpos, U64_Init((INT32)amount_read, 0 ) ) ;
+
+ /* if a checksum stream is to follow the current data */
+ /* stream, compute the checksum for the object */
+ if ( insertChecksum ) {
+ Checksum_Block( &checksum, lp->buf_start, amount_read ) ;
+ }
+
+ file_offset += amount_read ;
+ lp->rr.buff_used = amount_read ;
+ if( ( return_status = LP_Send( lp, TRUE ) ) != SUCCESS ) {
+ amount_read = 0 ;
+ break ;
+ }
+
+ /* if a checksum stream is to follow the */
+ /* current stream, we had better write it */
+ if ( insertChecksum ) {
+
+ if( ( return_status = LP_InsertChecksumStream( checksum, lp ) ) != SUCCESS ) {
+ amount_read = 0 ;
+ break ;
+ }
+ }
+
+ amount_read = 0 ;
+
+ /* we are all done with this object, tell TF */
+ return_status = LP_SendDataEnd( lp ) ;
+ break ;
+
+ } else if ( return_status == FS_STREAM_CORRUPT ) {
+
+ return_status = LP_PadToEndOfStream( lp, CFDB_UNREADABLE_BLK_BIT, streamNumber ) ;
+ continue ;
+
+ } else if ( return_status == FS_UNABLE_TO_LOCK ) {
+
+ switch( LP_MsgObjectInUse( pid, bsd_ptr, fsh, &lp->tpos,
+ blk_ptr, LP_CheckForReadLock, ( UINT32 )lp ) ) {
+
+ case SKIP_OBJECT:
+// LP_MsgBlockInuse( pid, bsd_ptr, fsh, &lp->tpos, blk_ptr, lp->curr_ddb ) ;
+
+ /* skip the whole stream */
+ return_status = LP_PadToEndOfStream( lp, CFDB_DEADLOCK_BIT, streamNumber ) ;
+ continue ;
+
+ default:
+ return_status = SUCCESS ;
+
+ }
+
+ } else if( ( return_status == FS_OBJECT_CORRUPT ) ||
+ ( return_status == FS_IN_USE_ERROR ) ||
+ ( return_status == FS_COMM_FAILURE ) ) {
+
+
+ LP_SendDataEnd( lp ) ;
+ if( lp->corrupt_file == FALSE ) {
+ FS_SetDefaultDBLK( fsh, CFDB_ID, ( CREATE_DBLK_PTR )lp->rr.cfdb_data_ptr ) ;
+ lp->rr.cfdb_data_ptr->std_data.dblk = lp->rr.cfdb_ptr ;
+ lp->rr.cfdb_data_ptr->corrupt_offset = file_offset ;
+ FS_CreateGenCFDB( fsh, lp->rr.cfdb_data_ptr ) ;
+ if ( return_status == FS_IN_USE_ERROR ) {
+ LP_MsgBlockInuse( pid, bsd_ptr, fsh, &lp->tpos, blk_ptr, lp->curr_ddb ) ;
+ } else {
+ LP_MsgBlockBad( pid, bsd_ptr, fsh, &lp->tpos, blk_ptr, lp->curr_ddb ) ;
+ }
+ }
+
+ return_status = SUCCESS ;
+ lp->corrupt_file = TRUE ;
+
+
+ } else if( ((return_status == FS_ACCESS_DENIED) || (return_status == FS_BAD_ATTACH_TO_SERVER)) &&
+ (DLE_GetDeviceType( BSD_GetDLE( bsd_ptr) ) == FS_EMS_DRV ) ) {
+
+ if ( return_status == FS_ACCESS_DENIED ) {
+ return_status = LP_ACCESS_DENIED_ERROR ;
+ }
+
+ LP_SendDataEnd( lp ) ;
+ if( lp->corrupt_file == FALSE ) {
+ LP_MsgError( lp->lis_ptr->pid,
+ lp->lis_ptr->curr_bsd_ptr,
+ lp->curr_fsys,
+ &lp->tpos,
+ return_status,
+ lp->curr_ddb,
+ blk_ptr,
+ STRM_INVALID ) ;
+
+ FS_SetDefaultDBLK( fsh, CFDB_ID, ( CREATE_DBLK_PTR )lp->rr.cfdb_data_ptr ) ;
+ lp->rr.cfdb_data_ptr->std_data.dblk = lp->rr.cfdb_ptr ;
+ lp->rr.cfdb_data_ptr->corrupt_offset = file_offset ;
+ FS_CreateGenCFDB( fsh, lp->rr.cfdb_data_ptr ) ;
+ LP_MsgBlockBad( pid, bsd_ptr, fsh, &lp->tpos, blk_ptr, lp->curr_ddb ) ;
+ }
+
+ return_status = SUCCESS ;
+ lp->corrupt_file = TRUE ;
+
+
+ } else if( return_status != SUCCESS ) {
+
+ space_fwd = min( 512, lp->rr.buff_size - amount_read ) ;
+ FS_SeekObj( lp->file_hand, &space_fwd ) ;
+
+ LP_PadData( (INT8_PTR)(lp->rr.buff_ptr + amount_read), space_fwd ) ;
+ amount_read += ( UINT16 )space_fwd ;
+
+ if( lp->corrupt_file == FALSE ) {
+ FS_SetDefaultDBLK( fsh, CFDB_ID, ( CREATE_DBLK_PTR )lp->rr.cfdb_data_ptr ) ;
+ lp->rr.cfdb_data_ptr->std_data.dblk = lp->rr.cfdb_ptr ;
+ lp->rr.cfdb_data_ptr->corrupt_offset = file_offset ;
+ FS_CreateGenCFDB( fsh, lp->rr.cfdb_data_ptr ) ;
+ LP_MsgBlockBad( pid, bsd_ptr, fsh, &lp->tpos, blk_ptr, lp->curr_ddb ) ;
+ }
+
+ lp->corrupt_file = TRUE ;
+ return_status = SUCCESS ;
+ }
+
+ lp->current_stream_size = U64_Sub( lp->current_stream_size, U32_To_U64( amount_read ), &math_stat ) ;
+ LP_MsgBytesProcessed( pid, bsd_ptr, fsh, &lp->tpos, U64_Init((INT32)amount_read, 0 ) ) ;
+
+ /* if a checksum stream is to follow the current */
+ /* data stream we need to compute the checksum */
+ if ( insertChecksum ) {
+ Checksum_Block( &checksum, lp->buf_start, amount_read ) ;
+ }
+
+ file_offset += amount_read ;
+ lp->rr.buff_used = amount_read ;
+ return_status = LP_Send( lp, TRUE ) ; /* data_flag TRUE to send data */
+
+ /* check for abort conditions */
+ switch( LP_GetAbortFlag( lp->lis_ptr ) ) {
+
+ case CONTINUE_PROCESSING:
+ break ;
+
+ case ABORT_CTRL_BREAK:
+ LP_MsgError( pid, bsd_ptr, fsh, &lp->tpos, LP_USER_ABORT_ERROR, NULL, NULL, 0L ) ;
+
+ /* falling through */
+
+ case ABORT_PROCESSED:
+ return_status = USER_ABORT ;
+ break ;
+
+ case ABORT_AT_EOM:
+ return_status = USER_ABORT ;
+ break ;
+ }
+ }
+
+ /* If there was no problem, set the backup date before closing */
+ if( (return_status == SUCCESS ) &&
+ (FS_GetBlockType( blk_ptr ) == FDB_ID) &&
+ (BEC_GetSetArchiveFlag( cfg )) ) {
+
+ FS_SetBDateInDBLK( fsh, blk_ptr, &lp->backup_dt ) ;
+ }
+
+ /* Problems on close for backup aren't expected--ignore return value. */
+
+ close_status = FS_CloseObj( lp->file_hand ) ;
+
+ if( return_status == SUCCESS ) {
+
+ if ( close_status == FS_NO_SECURITY ) {
+ LP_MsgError( lp->lis_ptr->pid,
+ lp->lis_ptr->curr_bsd_ptr,
+ lp->curr_fsys,
+ &lp->tpos,
+ LP_ACCESS_DENIED_ERROR,
+ lp->curr_ddb,
+ blk_ptr,
+ STRM_NT_ACL ) ;
+ }
+
+ LP_MsgBlockProcessed( pid, bsd_ptr, fsh, &lp->tpos, blk_ptr ) ;
+
+ /* If it was a corrupt file, then handle as normal */
+ if( lp->corrupt_file ) {
+ lp->rr.cur_dblk = lp->rr.cfdb_ptr ; /* Send the cfdb */
+ return_status = LP_Send( lp , FALSE ) ; /* data_flag FALSE to send DBLK */
+ lp->rr.buff_used = 0 ;
+ LP_SendDataEnd( lp ) ;
+
+ }
+
+ }
+
+ return( return_status ) ;
+
+}
+
+INT16 LP_PadToEndOfStream(
+ LP_ENV_PTR lp,
+ UINT32 attrib,
+ UINT16 streamNumber )
+{
+ UINT64 amount_to_skip = lp->current_stream_size ;
+ UINT32 space_fwd;
+ INT16 return_status = SUCCESS ;
+ BOOLEAN math_stat ;
+
+
+ if( (return_status == SUCCESS) && (lp->corrupt_file == FALSE) ) {
+ FS_SetDefaultDBLK( lp->curr_fsys, CFDB_ID, ( CREATE_DBLK_PTR )lp->rr.cfdb_data_ptr ) ;
+ lp->rr.cfdb_data_ptr->std_data.dblk = lp->rr.cfdb_ptr ;
+ lp->rr.cfdb_data_ptr->corrupt_offset = 0 ;
+ lp->rr.cfdb_data_ptr->std_data.attrib = attrib ;
+ lp->rr.cfdb_data_ptr->stream_number = streamNumber ;
+ FS_CreateGenCFDB( lp->curr_fsys, lp->rr.cfdb_data_ptr ) ;
+ LP_MsgBlockBad( lp->lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, lp->curr_fsys, &lp->tpos, lp->rr.cur_dblk, lp->curr_ddb ) ;
+ }
+
+ while( (return_status == SUCCESS) &&
+ !U64_EQ( amount_to_skip, U32_To_U64( 0L ) ) ) {
+
+ space_fwd = U64_Lsw( amount_to_skip ) ;
+
+ if ( U64_Lsw( amount_to_skip ) == 0 ) {
+ space_fwd = 0x7ffffff ;
+ }
+
+ if ( (UINT32)((UINT16)lp->rr.buff_size) < space_fwd ) {
+ space_fwd = lp->rr.buff_size ;
+ }
+
+ lp->rr.buff_used = (UINT16)space_fwd ;
+
+ amount_to_skip = U64_Sub( amount_to_skip, U32_To_U64( space_fwd ), &math_stat ) ;
+
+ FS_SeekObj( lp->file_hand, &space_fwd ) ;
+ LP_PadData( (INT8_PTR)lp->rr.buff_ptr, space_fwd ) ;
+ LP_MsgBytesProcessed( lp->lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, lp->curr_fsys, &lp->tpos, U32_To_U64( space_fwd ) ) ;
+ lp->current_stream_size = U64_Sub( lp->current_stream_size, U32_To_U64( space_fwd ), &math_stat ) ;
+
+ return_status = LP_Send( lp, TRUE ) ; /* data_flag TRUE to send data */
+
+ /* check for abort conditions */
+ switch( LP_GetAbortFlag( lp->lis_ptr ) ) {
+
+ case CONTINUE_PROCESSING:
+ break ;
+
+ case ABORT_CTRL_BREAK:
+ LP_MsgError( lp->lis_ptr->pid,
+ lp->lis_ptr->curr_bsd_ptr,
+ lp->curr_fsys, &lp->tpos,
+ LP_USER_ABORT_ERROR,
+ NULL,
+ NULL,
+ 0L ) ;
+
+ /* falling through */
+
+ case ABORT_PROCESSED:
+ return_status = USER_ABORT ;
+ break ;
+
+ case ABORT_AT_EOM:
+ return_status = USER_ABORT ;
+ break ;
+ }
+ }
+
+ lp->read_size = 0 ;
+
+// This assert will not be true if user aborts....
+// msassert( U64_EQ( lp->current_stream_size, U64_Init( 0L, 0L ) ) ) ;
+
+ lp->corrupt_file = TRUE ;
+
+ return return_status ;
+
+}
diff --git a/private/utils/ntbackup/src/back_vcb.c b/private/utils/ntbackup/src/back_vcb.c
new file mode 100644
index 000000000..c5d55fa22
--- /dev/null
+++ b/private/utils/ntbackup/src/back_vcb.c
@@ -0,0 +1,240 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: back_vcb.c
+
+ Description: Function to backup the VCB
+
+ $Log: T:/LOGFILES/BACK_VCB.C_V $
+
+ Rev 1.17 26 Apr 1993 02:43:44 GREGG
+Sixth in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Redefined attribute bits to match the spec.
+ - Eliminated unused/undocumented bits.
+ - Added code to translate bits on tapes that were written wrong.
+
+Matches MAYN40RD.C 1.59, DBLKS.H 1.15, MAYN40.H 1.34, OTC40RD.C 1.26,
+ SYPL10RD.C 1.8, BACK_VCB.C 1.17, MAYN31RD.C 1.44, SYPL10.H 1.2
+
+ Rev 1.16 04 Nov 1992 10:17:08 STEVEN
+fix typeo
+
+ Rev 1.15 03 Nov 1992 10:34:54 STEVEN
+fix typo
+
+ Rev 1.14 02 Nov 1992 17:13:10 STEVEN
+fix string types
+
+ Rev 1.13 09 Oct 1992 15:57:40 STEVEN
+added Daily backup set support
+
+ Rev 1.12 18 Sep 1992 15:52:50 STEVEN
+fix spelling
+
+ Rev 1.11 23 Jul 1992 09:23:14 STEVEN
+fix warnings
+
+ Rev 1.10 21 Jul 1992 14:25:44 STEVEN
+added support for user name in VCB
+
+ Rev 1.9 09 Jul 1992 14:00:08 STEVEN
+BE_Unicode updates
+
+ Rev 1.8 16 Jan 1992 15:45:42 STEVEN
+fix warnings for WIN32
+
+ Rev 1.7 06 Nov 1991 18:25:28 GREGG
+BIGWHEEL - 8200sx - Get cat_enabled from lp instead of lis.
+
+ Rev 1.6 17 Oct 1991 01:50:44 ED
+BIGWHEEL - 8200sx - Initial integration.
+
+ Rev 1.5 20 Sep 1991 16:43:02 STEVEN
+added vcb attribute for backup type
+
+ Rev 1.4 26 Aug 1991 13:19:14 STEVEN
+BE should not mess with the FullyCataloged attribute of a BSD
+
+ Rev 1.3 21 Jun 1991 09:27:50 STEVEN
+new config unit
+
+ Rev 1.2 30 May 1991 09:12:50 STEVEN
+bsdu_err.h no longer exists
+
+ Rev 1.1 23 May 1991 16:34:24 STEVEN
+changes for new bsdu
+
+ Rev 1.0 09 May 1991 13:39:18 HUNTER
+Initial revision.
+
+**/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "tbe_defs.h"
+#include "tbe_err.h"
+#include "bsdu.h"
+#include "fsys.h"
+#include "tflproto.h"
+#include "tfldefs.h"
+#include "loops.h"
+#include "loop_prv.h"
+#include "lis.h"
+#include "enc_pub.h"
+/**/
+/**
+
+ Name: LP_BackupVCB()
+
+ Description: Function to backup the VCB
+
+ Modified: 7/20/1989
+
+ Returns: any lower layer errors
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 LP_BackupVCB(
+BSD_PTR bsd_ptr,
+register LP_ENV_PTR lp )
+{
+ GEN_VCB_DATA vcb_data ;
+ INT16 return_status ;
+ GENERIC_DLE_PTR dle;
+
+ if( ( return_status = LP_StartTPEDialogue( lp, TRUE ) ) != NO_ERR ) {
+
+ return( return_status ) ;
+
+ }
+
+ /* build the vcb and send it to the tape format layer */
+
+ vcb_data.date = &lp->backup_dt ;
+
+ /* set labels fields */
+ FS_SetDefaultDBLK( lp->curr_fsys, VCB_ID, (CREATE_DBLK_PTR)&vcb_data ) ;
+
+ vcb_data.std_data.dblk = lp->curr_blk ;
+
+ dle = BSD_GetDLE( bsd_ptr ) ;
+ vcb_data.user_name = DLE_ViewUserName( dle ) ;
+ vcb_data.user_name_size = DLE_SizeofUserName( dle ) ;
+
+
+ if ( BSD_GetTapeLabel( bsd_ptr ) != NULL ) {
+ vcb_data.tape_name = BSD_GetTapeLabel( bsd_ptr ) ;
+ vcb_data.tape_name_size = BSD_SizeofTapeLabel( bsd_ptr ) ;
+ }
+ else {
+ vcb_data.tape_name_size = 0 ;
+ }
+
+ if ( BSD_GetBackupLabel( bsd_ptr ) != NULL ) {
+ vcb_data.bset_name = BSD_GetBackupLabel( bsd_ptr ) ;
+ vcb_data.bset_name_size = BSD_SizeofBackupLabel( bsd_ptr ) ;
+ }
+ else {
+ vcb_data.bset_name_size = 0 ;
+ }
+
+
+ if ( BSD_GetBackupDescript( bsd_ptr ) != NULL ) {
+ vcb_data.bset_descript = BSD_GetBackupDescript( bsd_ptr ) ;
+ vcb_data.bset_descript_size = BSD_SizeofBackupDescript( bsd_ptr ) ;
+ }
+ else {
+ vcb_data.bset_descript_size = 0 ;
+ }
+
+
+ /* set password fields */
+
+ if ( BSD_GetBackupPswd( bsd_ptr ) != NULL ) {
+ vcb_data.bset_password = BSD_GetBackupPswd( bsd_ptr );
+ vcb_data.bset_password_size = BSD_GetBackupPswdSize( bsd_ptr );
+ }
+ else {
+ vcb_data.bset_password_size = 0 ;
+ }
+
+ if ( BSD_GetTapePswd( bsd_ptr ) != NULL ) {
+ vcb_data.tape_password = BSD_GetTapePswd( bsd_ptr ) ;
+ vcb_data.tape_password_size = BSD_GetTapePswdSize( bsd_ptr ) ;
+ }
+ else {
+ vcb_data.tape_password_size = 0 ;
+ }
+
+ if( vcb_data.tape_password_size || vcb_data.bset_password_size ) {
+ vcb_data.password_encrypt_alg = ENC_ALGOR_3 ;
+ }
+
+ if( lp->lis_ptr->oper_type == ARCHIVE_BACKUP_OPER ) {
+ vcb_data.std_data.attrib |= VCB_ARCHIVE_BIT ;
+ }
+
+ switch( BSD_GetBackupType( bsd_ptr ) ) {
+ case BSD_BACKUP_NORMAL :
+ vcb_data.std_data.attrib |= VCB_NORMAL_SET ;
+ break ;
+ case BSD_BACKUP_COPY :
+ vcb_data.std_data.attrib |= VCB_COPY_SET ;
+ break ;
+ case BSD_BACKUP_DIFFERENTIAL :
+ vcb_data.std_data.attrib |= VCB_DIFFERENTIAL_SET ;
+ break ;
+ case BSD_BACKUP_INCREMENTAL :
+ vcb_data.std_data.attrib |= VCB_INCREMENTAL_SET ;
+ break ;
+ case BSD_BACKUP_DAILY :
+ vcb_data.std_data.attrib |= VCB_DAILY_SET ;
+ break ;
+ default:
+ break ;
+ }
+
+ vcb_data.std_data.string_type = BEC_GetStringTypes( BSD_GetConfigData( bsd_ptr ) ) ;
+
+ FS_CreateGenVCB( lp->curr_fsys, &vcb_data ) ;
+
+ /* set tape ID, tape sequence number and backup set number */
+ FS_SetTapeIDInVCB( lp->curr_blk, BSD_GetTapeID( bsd_ptr ) ) ;
+ FS_SetTSNumInVCB( lp->curr_blk, BSD_GetTapeNum( bsd_ptr ) ) ;
+ FS_SetBSNumInVCB( lp->curr_blk, BSD_GetSetNum( bsd_ptr ) ) ;
+
+ /* send DBLK to tape format layer */
+ lp->rr.cur_dblk = lp->curr_blk ; /* Send the DBLK */
+
+ if( ( return_status = LP_Send( lp, FALSE ) ) == NO_ERR ) { /* data_flag FALSE to send DBLK */
+
+ /* Set backup set tape position info, backup set date and fully catalog indicator */
+
+ BSD_SetTapePos( bsd_ptr, FS_ViewTapeIDInVCB( lp->curr_blk ),
+ FS_ViewTSNumInVCB( lp->curr_blk ),
+ FS_ViewBSNumInVCB( lp->curr_blk ) ) ;
+ BSD_SetDate( bsd_ptr, FS_ViewBackupDateInVCB( lp->curr_blk ) );
+
+ /* Set PBA in current BSD if this drive supports FFR -OR- is an SX and we are cataloguing so that
+ verify last will block seek straight to VCB */
+ if( SupportFastFile( BSD_GetTHW( bsd_ptr ) ) ) {
+ BSD_SetPBA( bsd_ptr, FS_ViewPBAinVCB( lp->curr_blk ) ) ;
+ } else if( SupportSXFastFile( BSD_GetTHW( bsd_ptr ) ) &&
+ lp->cat_enabled ) {
+ BSD_SetPBA( bsd_ptr, MANUFACTURED_PBA ) ;
+ }
+ }
+ return( return_status ) ;
+}
+
diff --git a/private/utils/ntbackup/src/be_debug.c b/private/utils/ntbackup/src/be_debug.c
new file mode 100644
index 000000000..7cc519833
--- /dev/null
+++ b/private/utils/ntbackup/src/be_debug.c
@@ -0,0 +1,65 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: be_debug.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains code to call the debug printf
+
+
+ $Log: N:/LOGFILES/BE_DEBUG.C_V $
+
+ Rev 1.1 19 May 1992 13:09:00 MIKEP
+mips changes
+
+ Rev 1.0 09 May 1991 13:39:18 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <process.h>
+#include <stdarg.h>
+
+#include "stdtypes.h"
+#include "be_debug.h"
+
+VOID (*z_printf)( UINT16, va_list ) = NULL ;
+
+/* $end$ include list */
+/**/
+/**
+
+ Name: debug_printf()
+
+ Description: This function alls the user interface
+ to print debug data.
+
+ Modified: 1/5/1990
+
+ Returns: none
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID BE_Zprintf( UINT16 mask_bits, ... )
+{
+ va_list arg_ptr ;
+
+ if ( z_printf != NULL ) {
+ va_start( arg_ptr, mask_bits ) ;
+ z_printf( mask_bits, arg_ptr ) ;
+ va_end( arg_ptr ) ;
+ }
+
+}
diff --git a/private/utils/ntbackup/src/be_dinit.c b/private/utils/ntbackup/src/be_dinit.c
new file mode 100644
index 000000000..a59cf558a
--- /dev/null
+++ b/private/utils/ntbackup/src/be_dinit.c
@@ -0,0 +1,105 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: be_dinit.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains the deinitialization routine and the
+ control break handler.
+
+
+ $Log: Q:/LOGFILES/BE_DINIT.C_V $
+
+ Rev 1.8 18 Jun 1993 08:52:24 MIKEP
+C++ enable
+
+ Rev 1.7 17 May 1993 17:38:22 TIMN
+Added prototype to avoid warning message.
+Added NT conditional to fix compiling for non-Windows projects.
+
+ Rev 1.6 14 May 1993 14:40:14 TIMN
+Added multiple instance support for releasing the device claimed during
+startup via HWC_InitTapeDevice. No impact to NOST to take change. Cayman
+requires dil_nt.c hwconfnt.c mui.c global.c global.h hwconf.h backup.c
+
+ Rev 1.5 16 Mar 1993 14:55:14 MARILYN
+Clients do not need to deinit the tape format layer since they
+don't ever init it.
+
+ Rev 1.4 21 Jun 1991 13:24:56 BARRY
+Changes for new config.
+
+ Rev 1.3 04 Jun 1991 19:11:56 BARRY
+Removed ControlBreak stuff. Now resides in os-specific modules.
+
+ Rev 1.2 30 May 1991 09:15:42 STEVEN
+bsdu_err.h no longer exists
+
+ Rev 1.1 17 May 1991 08:49:52 DAVIDH
+No control-break handling in NLM.
+
+ Rev 1.0 09 May 1991 13:39:20 HUNTER
+Initial revision.
+
+**/
+
+#include "stdtypes.h"
+#include "fsys.h"
+#include "bsdu.h"
+#include "lis.h"
+#include "tflproto.h"
+#include "tfl_err.h"
+#include "be_init.h"
+#include "ld_dvr.h"
+
+
+#if defined( OS_WIN32 ) && !defined( OEM_MSOFT )
+/**
+ Need a prototype from hwconf.h for HWC_. Including only the prototype
+ because the header file would require many other header files. Used
+ with multiple instance support which was added to CAYMAN.
+**/
+ INT HWC_DeInitTapeDevice( VOID ) ;
+#endif
+
+
+/**/
+
+/**
+
+ Name: BE_Deinit()
+
+ Description:
+
+ Modified: 11/14/1989
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID BE_Deinit( DLE_HAND dle_list )
+{
+
+#if !defined( P_CLIENT )
+
+ TF_CloseTapeFormat( ) ;
+
+# if defined( OS_WIN32 ) && !defined( OEM_MSOFT )
+ HWC_DeInitTapeDevice() ; // release claimed device
+# endif
+
+#endif
+
+ FS_RemoveFileSys( dle_list ) ;
+
+ BE_RemoveCtrlBreakHandler( ) ;
+
+}
diff --git a/private/utils/ntbackup/src/be_init.c b/private/utils/ntbackup/src/be_init.c
new file mode 100644
index 000000000..cab85bb2e
--- /dev/null
+++ b/private/utils/ntbackup/src/be_init.c
@@ -0,0 +1,232 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: be_init.c
+
+ Description: Primary entry point provided is BE_Init which is called
+ from the user interface to initialize various parts of
+ the backup engine (File Systems, BSDU, or Tape Format).
+
+
+ $Log: Q:/LOGFILES/BE_INIT.C_V $
+
+ Rev 1.16 26 Jul 1993 14:47:28 TerriLynn
+Added global for Sytron ECC. Unable to keep it
+hidden because the Enterprise team needs it to
+compile
+
+ Rev 1.15 23 Jul 1993 11:54:48 GLENN
+Added the setting of the gnProcessSytronECC flag.
+
+ Rev 1.14 22 Jul 1993 11:38:40 ZEIR
+Add'd software_name arg to OpenTapeFormat
+
+ Rev 1.13 18 Jun 1993 08:52:34 MIKEP
+C++ enable
+
+ Rev 1.12 16 Mar 1993 14:54:06 MARILYN
+Client applications don't need to initialize the tape format layer.
+
+ Rev 1.11 04 Feb 1992 21:43:40 GREGG
+Changed parameters in call to TF_OpenTapeFormat.
+
+ Rev 1.10 23 Jan 1992 15:21:50 CLIFF
+Added BE_InitLW function
+
+ Rev 1.9 17 Jan 1992 17:21:40 STEVEN
+fix warnings for WIN32
+
+ Rev 1.8 24 Oct 1991 14:59:24 BARRY
+TRICYCLE: Pass new bit-mask field of BE_INIT_STR to FS_InitFileSys()
+to support dynamically selectable file systems.
+
+ Rev 1.7 17 Oct 1991 01:44:44 ED
+BIGWHEEL -8200sx - Added catalog_directory parameter to TF_OpenTapeFormat call.
+
+ Rev 1.6 23 Sep 1991 13:37:14 GREGG
+8200SX - TF_OpenTapeFormat now is passed the machine type.
+
+ Rev 1.5 27 Jun 1991 15:40:56 JOHNW
+Pass driver directory to OpenTapeFormat
+
+ Rev 1.4 21 Jun 1991 13:24:46 BARRY
+Changes for new config.
+
+ Rev 1.3 04 Jun 1991 19:10:56 BARRY
+Removed ControlBreak handler stuff. Now resides in os-specific modules.
+
+ Rev 1.2 30 May 1991 09:15:26 STEVEN
+bsdu_err.h no longer exists
+
+ Rev 1.1 17 May 1991 08:49:08 DAVIDH
+No control-break handling in NLM.
+
+ Rev 1.0 09 May 1991 13:39:22 HUNTER
+Initial revision.
+
+**/
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "beconfig.h"
+#include "fsys.h"
+#include "bsdu.h"
+#include "lis.h"
+#include "tflproto.h"
+#include "tfl_err.h"
+#include "be_init.h"
+#include "loops.h"
+
+extern VOID (*z_printf)( UINT16, CHAR_PTR, va_list ) ;
+
+/* Global for Sytos */
+INT16 gnProcessSytronECC ;
+
+/**/
+
+/**
+
+ Name: BE_Init()
+
+ Description: BE_Init is called from the user interface to initialize
+ the various backup engine units, namely, File Systems,
+ BSDU and Tape Format. This 3.1 backup engine version
+ of this entry point is not responsible for loading the
+ device driver as in the 3.0 version. That responsibility
+ is handled by Tape Format proper (since for the DOS
+ application device drivers can be unloaded and loaded
+ while within the application).
+
+ A control break handler is installed at this time if one
+ has not already be installed. In addition, the debug
+ printf function pointer is initialized so that debug
+ printf calls can be performed from within the backup
+ engine.
+
+ Modified: 11/14/1989
+
+ Returns: various backup engine errors (see BE_INIT.h)
+
+ Notes:
+
+ See also: $/SEE(be_init.h)$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 BE_Init(
+BE_INIT_STR_PTR be_ptr,
+BE_CFG_PTR conf_ptr )
+{
+ INT16 error ;
+
+ /*
+ * define debug print function for backup engine to call,
+ * if one has not already been defined
+ */
+
+ if ( z_printf == NULL ) {
+ z_printf = be_ptr->debug_print ;
+ }
+
+ // Set up the Process Sytron ECC global.
+
+ gnProcessSytronECC = BEC_GetProcessSytronECCFlag ( conf_ptr );
+
+ BE_InstallCtrlBreakHandler( );
+
+ /* Now open the file system */
+ if( be_ptr->units_to_init & BE_INIT_FSYS ) {
+ if( error = FS_InitFileSys( be_ptr->dle_list_ptr,
+ be_ptr->critical_error_handler,
+ conf_ptr,
+ be_ptr->remote_filter,
+ be_ptr->file_systems ) ) {
+
+ msassert( error == OUT_OF_MEMORY );
+ return BE_FILE_SYS_FAIL ;
+
+ }
+ }
+
+ /* Init the BSD Unit */
+ if( be_ptr->units_to_init & BE_INIT_BSDU ) {
+ if( error = BSD_OpenList( be_ptr->bsd_list_ptr, be_ptr->vm_hand ) ) {
+ FS_RemoveFileSys( *be_ptr->dle_list_ptr ) ;
+ msassert( error == OUT_OF_MEMORY );
+ return BE_BSDU_FAIL ;
+ }
+ }
+
+
+ /* Init the Tape Format Layer */
+#if !defined( P_CLIENT )
+ if( be_ptr->units_to_init & BE_INIT_TFL ) {
+
+ /* continue with Tape Format Layer init */
+ if( ( error = TF_OpenTapeFormat( be_ptr->driver_name,
+ be_ptr->dhwd_ptr,
+ be_ptr->number_of_cards,
+ be_ptr->thw_list_ptr,
+ be_ptr->max_channels,
+ BEC_GetFastFileRestore( conf_ptr ),
+ (BOOLEAN)( ( BEC_GetSpecialWord( conf_ptr ) & IGNORE_MAYNARD_ID ) ? TRUE : FALSE ),
+ be_ptr->driver_directory,
+ BEC_GetConfiguredMachineType( conf_ptr ),
+ be_ptr->catalog_directory,
+ BEC_GetInitialBuffAlloc( conf_ptr ),
+ be_ptr->software_name
+
+ ) ) != TFLE_NO_ERR ) {
+ return( error ) ;
+
+ } else {
+
+ /* Init Layer wide global thw pointers */
+ lw_toc_tpdrv = *be_ptr->thw_list_ptr ;
+ lw_last_tpdrv = *be_ptr->thw_list_ptr ;
+
+ }
+ }
+#endif
+
+ return BE_INIT_SUCCESS ;
+}
+
+
+
+
+/**/
+
+/**
+
+ Name: BE_InitLW()
+
+ Description: BE_InitLW is called from the user interface to initialize
+ the layer wide variables that define the channel. The call
+ is made after the call BE_Init or BE_ReinitTFLayer after
+ the UI validates the channel list.
+
+ Modified: 2/22/92
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE(be_init.h)$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID BE_InitLW( BE_INIT_STR_PTR be_ptr )
+{
+
+ /* Init Layer wide global thw pointers */
+ lw_toc_tpdrv = *be_ptr->thw_list_ptr ;
+ lw_last_tpdrv = *be_ptr->thw_list_ptr ;
+ return ;
+}
+
diff --git a/private/utils/ntbackup/src/be_tfutl.c b/private/utils/ntbackup/src/be_tfutl.c
new file mode 100644
index 000000000..e62ad2239
--- /dev/null
+++ b/private/utils/ntbackup/src/be_tfutl.c
@@ -0,0 +1,277 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: be_tfutl.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This module contains entry points to be used by the
+ user interface to re-init the tape format with new
+ controller configuration information, get current tape
+ device from tape format layer and get current tape format
+ type from tape format layer.
+
+
+ $Log: Q:/LOGFILES/BE_TFUTL.C_V $
+
+ Rev 1.11 22 Jul 1993 11:40:50 ZEIR
+Add'd software_name arg to OpenTapeFormat
+
+ Rev 1.10 17 Jun 1993 17:49:46 MIKEP
+C++ enable
+
+ Rev 1.9 28 Jan 1993 09:25:38 DON
+Removed BE_EjectTape function
+
+ Rev 1.8 09 Nov 1992 15:25:10 DON
+Added a function to allow UI to eject a tape and brought forward charlies 1.6.1.0 changes
+
+ Rev 1.7 18 Aug 1992 09:48:58 BURT
+fix warnings
+
+ Rev 1.6 04 Feb 1992 21:44:10 GREGG
+Changed parameters in call to TF_OpenTapeFormat.
+
+ Rev 1.5 17 Jan 1992 17:21:08 STEVEN
+fix warnings for WIN32
+
+ Rev 1.4 17 Oct 1991 01:36:24 GREGG
+BIGWHEEL -8200sx - Added catalog_directory parameter to TF_OpenTapeFormat call.
+
+ Rev 1.3 23 Sep 1991 13:38:54 GREGG
+8200SX - TF_OpenTapeFormat now is passed the machine type.
+
+ Rev 1.2 28 Jun 1991 12:08:22 JOHNW
+Changes for new TPFMT unit
+
+ Rev 1.1 27 Jun 1991 08:42:20 STEVEN
+new config unit
+
+ Rev 1.0 09 May 1991 13:39:22 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "stdtypes.h"
+#include "tflproto.h"
+#include "tfl_err.h"
+#include "loops.h"
+#include "be_tfutl.h"
+#include "genstat.h"
+#include "beconfig.h"
+/* $end$ include list */
+
+/**/
+/**
+
+ Name: BE_GetCurrentDeviceName
+
+ Description: Used to get a CHAR_PTR to the device name in the THW
+ structure. This is called by the user interface since
+ it doesn't know have access to TF_CheckDeviceStatus.
+
+ Modified: 2/14/1990
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+CHAR_PTR BE_GetCurrentDeviceName( UINT16 channel )
+{
+ THW_PTR thw_ptr ;
+
+ thw_ptr = TF_GetCurrentDevice( channel ) ;
+ return( thw_ptr->drv_name ) ;
+}
+/**/
+/**
+
+ Name: BE_GetCurrentDevice
+
+ Description: Used to get a THW_PTR for the current active drive in
+ the channel
+
+ Modified: 4/19/1990
+
+ Returns: THW_PTR
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+THW_PTR BE_GetCurrentDevice( UINT16 channel )
+{
+ return( TF_GetCurrentDevice( channel ) ) ;
+}
+/**/
+/**
+
+ Name: BE_ReinitTFLayer
+
+ Description: Entry point in Backup Engine for User Interface to
+ force a reinitialization of the Tape Format Layer. This
+ is likely used if the user makes a run-time change to
+ the hardware configuration information which requires
+ the Tape Format to be re-initialized
+
+ Modified: 8/15/1990
+
+ Returns: various be_init errors (see be_init.h)
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 BE_ReinitTFLayer(
+BE_INIT_STR_PTR be_ptr,
+BE_CFG_PTR conf_ptr )
+{
+ INT16 tfl_error ;
+
+ TF_CloseTapeFormat( ) ;
+
+ if( ( tfl_error = TF_OpenTapeFormat( be_ptr->driver_name,
+ be_ptr->dhwd_ptr,
+ be_ptr->number_of_cards,
+ be_ptr->thw_list_ptr,
+ be_ptr->max_channels,
+ BEC_GetFastFileRestore( conf_ptr ),
+ (BOOLEAN)( ( BEC_GetSpecialWord( conf_ptr ) & IGNORE_MAYNARD_ID ) ? TRUE : FALSE ),
+ be_ptr->driver_directory,
+ BEC_GetConfiguredMachineType( conf_ptr ),
+ be_ptr->catalog_directory,
+ BEC_GetInitialBuffAlloc( conf_ptr ),
+ be_ptr->software_name
+
+ ) ) == TFLE_NO_ERR ) {
+
+ /* Init Layer wide global thw pointers */
+ lw_toc_tpdrv = *be_ptr->thw_list_ptr ;
+ lw_last_tpdrv = *be_ptr->thw_list_ptr ;
+
+ }
+
+ return( tfl_error ) ;
+}
+/**/
+/**
+
+ Name: BE_CheckMultiDrive
+
+ Description: Given the current channel specification, this function
+ returns an indicator of where the current drive is
+ located within the channel. This function is called
+ by the User Interface Tape Positioner and Message
+ Handler in order to determine what user interaction
+ is necessary for multi-tape drive environments.
+
+ Modified: 2/6/1990
+
+ Returns: BE_NO_MULTI_DRIVE for N/A multi-drive channel
+ BE_END_OF_CHANNEL when positioned at end of channel in
+ multi-drive environment
+ BE_MULTI_DRIVE when positioned within the channel
+ of a multi-drive environment but not
+ located at the end
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+UINT8 BE_CheckMultiDrive( UINT16 channel )
+{
+ THW_PTR thw_ptr ;
+ UINT8 status ;
+
+ thw_ptr = TF_GetCurrentDevice( channel ) ;
+ if( ( thw_ptr->channel_link.q_next == NULL ) && ( thw_ptr->link.q_prev == NULL ) ) {
+ status = BE_NO_MULTI_DRIVE ;
+ } else if( thw_ptr->channel_link.q_next == NULL ) {
+ status = BE_END_OF_CHANNEL ;
+ } else {
+ status = BE_MULTI_DRIVE ;
+ }
+ return( status ) ;
+
+}
+/**/
+/**
+
+ Name: BE_DeviceWriteProtected
+
+ Description: Return BOOLEAN indication of whether current device is
+ write protected or not.
+
+ Modified: 2/14/1990
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+BOOLEAN BE_DeviceWriteProtected( UINT16 channel )
+{
+ THW_PTR thw_ptr ;
+
+ thw_ptr = TF_GetCurrentDevice( channel ) ;
+ return( (BOOLEAN)(thw_ptr->drv_status & TPS_WRITE_PROTECT) ) ;
+}
+
+
+/**/
+/**
+
+ Name: BE_NonNativeFormat
+
+ Description: Return BOOLEAN indication of whether current device is
+ contains a tape which is non native format or native.
+
+ Modified: 2/14/1990
+
+ Returns: TRUE - non-native format
+ FALSE - native format
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+BOOLEAN BE_NonNativeFormat( UINT16 channel )
+{
+ THW_PTR thw_ptr ;
+
+ thw_ptr = TF_GetCurrentDevice( channel ) ;
+ return( (BOOLEAN)(thw_ptr->drv_status & TPS_NON_NATIVE_FORMAT) ) ;
+}
+
+
diff --git a/private/utils/ntbackup/src/bec_init.c b/private/utils/ntbackup/src/bec_init.c
new file mode 100644
index 000000000..a667544c0
--- /dev/null
+++ b/private/utils/ntbackup/src/bec_init.c
@@ -0,0 +1,360 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: bec_init.c
+
+ Date Updated: 14-Jun-91
+
+ Description: Code to initialize and close the Backup Engine
+ configuration unit.
+
+ $Log: Q:/LOGFILES/BEC_INIT.C_V $
+
+ Rev 1.41 12 Aug 1993 17:22:26 TerriLynn
+Changed Min Sytron ECC to SYPL_ECC_OFF
+
+ Rev 1.40 27 Jul 1993 15:05:50 TerriLynn
+Changed hard coded values to defined values.
+
+ Rev 1.39 23 Jul 1993 12:14:38 TerriLynn
+Updated SYPL ECC default value per
+LANMAN upgrade requirements.
+
+ Rev 1.38 22 Jul 1993 10:30:20 DON
+Increased the maximum value for max_buffers to 16
+
+ Rev 1.37 21 Jul 1993 17:29:04 TerriLynn
+Added Process Sytron ECC flag
+
+ Rev 1.36 30 Jun 1993 15:27:20 BARRY
+Add process_special_files
+
+ Rev 1.35 30 Jun 1993 15:22:34 DOUG
+Changed nrl_max_spx_ipx_packet_size to 0x5B4 (1460)
+
+ Rev 1.34 17 Jun 1993 16:43:56 DEBBIE
+Changed backup compressed files without expanding to backup compressed files
+as expanded files.
+
+ Rev 1.33 10 May 1993 15:52:20 MARILYN
+different GRFS & NRL default values for windows
+
+ Rev 1.32 05 May 1993 16:31:10 BRYAN
+Valid range for nrl_dos_vector is now 60-ff.
+
+ Rev 1.31 03 May 1993 15:26:46 Aaron
+Changed #ifdefs on last three items in BE_CFG structures from P_CLIENT to
+OS_NLM (as per declaration in BECONFIG.H).
+
+ Rev 1.30 30 Apr 1993 16:42:46 DOUG
+Moved NRL_SPX_MaxIpxPacketSize out of CLient only #ifdef
+
+ Rev 1.29 19 Apr 1993 16:58:36 DOUG
+Added new NRL/TLI fields
+
+ Rev 1.28 30 Mar 1993 18:07:32 DON
+Changed migrated/compressed stuff!
+
+ Rev 1.27 24 Mar 1993 15:45:50 DEBBIE
+added fields to min & max configs for migrated files and for uncompressing files
+
+ Rev 1.26 22 Mar 1993 16:46:34 JOHNES
+Ifdef'ed out initializations not needed in P_CLIENT.
+
+ Rev 1.25 19 Mar 1993 11:31:54 JOHNES
+Ifdef'ed backup_server_name out of P_CLIENT.
+
+ Rev 1.24 16 Mar 1993 14:26:14 JOHNES
+If def'ed OUT initializations for keep_drive_list (for P_CLIENT only).
+
+ Rev 1.23 11 Mar 1993 20:29:22 BRYAN
+(added needed commas)
+
+ Rev 1.22 11 Mar 1993 11:37:02 ANDY
+Added GRFS and NRL parameters for ENDEAVOUR
+
+ Rev 1.21 01 Mar 1993 17:39:28 MARILYN
+set min and max values for the process checksum streams option
+
+ Rev 1.20 09 Feb 1993 10:00:54 DOUG
+Added Client supervisor mode flag
+
+ Rev 1.19 07 Feb 1993 11:50:18 DON
+Removed references to copy/move
+
+ Rev 1.18 11 Jan 1993 16:59:52 DON
+Made the minimum value for string_type BEC_ANSI_STR
+
+ Rev 1.17 08 Dec 1992 14:24:10 DON
+Integrated Move/Copy into tips
+
+ Rev 1.16 08 Dec 1992 11:45:34 DOUG
+Added new GRFS and NRL parameters
+
+ Rev 1.15 14 Oct 1992 16:33:24 STEVEN
+fix typos
+
+ Rev 1.14 13 Oct 1992 12:34:14 STEVEN
+added otc level
+
+ Rev 1.13 04 May 1992 12:25:42 STEVEN
+NT_STUFF added string types
+
+ Rev 1.12 02 Feb 1992 15:52:32 GREGG
+Removed utf_supported boolean from config, and added UINT16 initial_buff_alloc.
+
+ Rev 1.11 27 Jan 1992 18:14:32 GREGG
+Changes for new config element: utf_supported.
+
+ Rev 1.10 13 Jan 1992 18:36:28 STEVEN
+added config switch for BSD sort
+
+ Rev 1.9 19 Nov 1991 13:10:06 STEVEN
+allow a value of 2 for skip_open_files
+
+ Rev 1.8 14 Nov 1991 10:19:06 BARRY
+TRICYCLE: Added restore_security.
+
+ Rev 1.7 06 Nov 1991 18:52:54 GREGG
+BIGWHEEL - 8200sx - Added catalog_level to BE config.
+
+ Rev 1.6 24 Oct 1991 11:19:32 BARRY
+Free memory after dequeue.
+
+ Rev 1.5 16 Oct 1991 14:12:24 STEVEN
+need to allow for 2 in exist flag
+
+ Rev 1.4 19 Sep 1991 13:03:46 STEVEN
+added Machine type to config
+
+ Rev 1.3 12 Aug 1991 15:57:34 BARRY
+DisplayNetwareServers no longer in config.
+
+ Rev 1.2 01 Jul 1991 17:34:56 STEVEN
+added min and max
+
+ Rev 1.1 19 Jun 1991 17:27:52 BARRY
+Forgot to include (of all things) stdlib.h.
+
+ Rev 1.0 19 Jun 1991 10:38:06 BARRY
+Initial revision.
+
+**/
+
+#include <stdlib.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "queues.h"
+
+#include "beconfig.h"
+#include "bec_prv.h"
+
+/* Global queue of active configuration elements */
+
+Q_HEADER uw_config_queue ;
+BE_CFG uw_min_cfg = {
+ 0, /* special_word */
+ 2, /* max_buffers */
+ 0, /* reserve_mem */
+ 2, /* tfl_buff_size */
+ 512, /* max_buffer_size */
+ 0, /* skip_open_files */
+ 0, /* backup_files_inuse */
+ 0, /* support_afp_server */
+ 0, /* extended_date_support */
+ 0, /* hidden_flg */
+ 0, /* special_flg */
+ 0, /* set_archive_flg */
+ 0, /* modified_only_flg */
+ 0, /* proc_empty_flg */
+ 0, /* exist_flg */
+ 0, /* prompt_flg */
+ NULL, /* part_list */
+#if !defined(P_CLIENT)
+ {0}, /* keep_drive_list*/
+#endif /* !P_CLIENT */
+ 0, /* net_num */
+ 0, /* remote_drive_backup */
+ 0, /* use_ffr */
+ 0, /* write_format */
+ 0x60, /* nrl_dos_vector */
+ 0, /* lock */
+ 0, /* machine type */
+ 0, /* catalog level */
+ FALSE, /* Restore security info */
+ FALSE, /* bsd sort */
+ 0, /* initial_buff_alloc */
+ BEC_ANSI_STR, /* string types ASCII */
+ 0, /* otc catalog level */
+ 0x10, /* 16 max remote resources */
+#if !defined(P_CLIENT)
+ {0}, /* backup_server_name */
+#endif /* !P_CLIENT */
+ 0, /* NRL type: 0=SPX, 1=NetBIOS */
+ 0, /* GRFS timeout seconds: 0=wait forever */
+ 0x240, /* NRL max allowable packet size */
+#if !defined(P_CLIENT)
+ 200, /* NRL callback stack size */
+ 1, /* NRL cumulative local resources */
+ 1, /* NRL maximum allowed connections */
+#endif /* !P_CLIENT */
+ {0}, /* NRL string of backup servers space delimited */
+#if !defined(P_CLIENT)
+ 1, /* NRL number of listen ecbs per session */
+ 0, /* NRL spx number of times to retry a packet */
+ 0, /* NRL NetBios number of times to retry a packet */
+#endif /* !P_CLIENT */
+ 0, /* NRL adapter number for LAN */
+ {0}, /* NRL name of LAN device */
+#if !defined(P_CLIENT)
+ 1, /* GRFS maximum number of agents allowed */
+#endif /* !P_CLIENT */
+ FALSE, /* Client supervisor mode */
+ FALSE, /* Process checksum streams */
+#if !defined(P_CLIENT)
+ FALSE, /* Backup migrated files */
+ FALSE, /* Backup compressed files as expanded files */
+#endif /* !P_CLIENT */
+#if defined(OS_NLM)
+ 0, /* NRL Protocols supported (None) */
+ 5, /* TCP Resource cleaner interval (seconds) */
+ 0, /* TCP port for resource listener thread */
+#endif /* OS_NLM */
+ FALSE, /* Process special files */
+SYPL_ECC_OFF, /* Process Sytron ECC */
+ FALSE, /* ems public private */
+ FALSE, /* EMS kick restore */
+ FALSE /* ems clean restore */
+ } ;
+
+BE_CFG uw_max_cfg = {
+ 0xffff, /* special_word */
+ 16, /* max_buffers */
+ 0x3000, /* reserve_mem */
+ 32, /* tfl_buff_size */
+#if defined( OS_DOS ) && !defined( OS_WIN )
+ 4096, /* max_buffer_size */
+#else
+ 32768, /* max_buffer_size */
+#endif
+ 2, /* skip_open_files */
+ 1, /* backup_files_inuse */
+ 1, /* support_afp_server */
+ 1, /* extended_date_support */
+ 1, /* hidden_flg */
+ 1, /* special_flg */
+ 1, /* set_archive_flg */
+ 1, /* modified_only_flg */
+ 1, /* proc_empty_flg */
+ 2, /* exist_flg */
+ 1, /* prompt_flg */
+ NULL, /* part_list */
+#if !defined(P_CLIENT)
+ {0}, /* keep_drive_list*/
+#endif /* !P_CLIENT */
+ 4, /* net_num */
+ 1, /* remote_drive_backup */
+ 1, /* use_ffr */
+ 1, /* write_format */
+ 0xff, /* nrl_dos_vector */
+ 1, /* lock */
+ 0xffff, /* machine type */
+ 2, /* catalog level */
+ TRUE, /* Restore security info */
+ TRUE, /* bsd sort */
+ 32, /* initial_buff_alloc */
+ 0xffff, /* string types ASCII */
+ 2, /* otc catalog level */
+#ifdef OS_NLM
+ 0xfa, /* 250 max remote resources */
+#else
+#if defined( OS_WIN )
+ 0xffff, /* max remote resources */
+#else
+ 0x40, /* max remote resources */
+#endif
+#endif
+#if !defined(P_CLIENT)
+ {0}, /* backup_server_name */
+#endif /* !P_CLIENT */
+ 1, /* NRL type: 0=SPX, 1=NetBios */
+ 32768, /* GRFS timeout seconds: == 9.1 days */
+ 0x5B4, /* NRL max allowable packet size */
+#if !defined(P_CLIENT)
+ 0x3fff, /* NRL callback stack size */
+ 8, /* NRL cumulative local resources */
+ 0x10, /* NRL maximum allowed connections */
+#endif /* !P_CLIENT */
+ {0}, /* NRL string of backup servers space delimited */
+#if !defined(P_CLIENT)
+ 0xff, /* NRL number of listen ecbs per session */
+ 0xff, /* NRL spx number of times to retry a packet */
+ 255, /* NRL NetBios number of times to retry a packet */
+#endif /* !P_CLIENT */
+ 15, /* NRL adapter number for LAN */
+ {0}, /* NRL name of LAN device */
+#if !defined(P_CLIENT)
+ 4, /* GRFS maximum number of agents allowed */
+#endif /* !P_CLIENT */
+ TRUE, /* Client supervisor mode */
+ TRUE, /* Process checksum streams */
+#if !defined(P_CLIENT)
+ TRUE, /* Backup migrated files */
+ TRUE, /* Backup compressed files as expanded files */
+#endif /* !P_CLIENT */
+#if defined(OS_NLM)
+ 7, /* NRL Protocols supported (SPX,TCP,ADSP) */
+ 60, /* TCP Resource cleaner interval (seconds) */
+ 0xffff, /* TCP port for resource listener thread */
+#endif /* OS_NLM */
+ TRUE, /* Process special files */
+SYPL_ECC_AUTO, /* Process Sytron ECC */
+BEC_EMS_BOTH, /* ems PUBLIC private */
+ TRUE, /* ems Kick restore */
+ TRUE /* clean restore */
+ } ;
+
+/**/
+
+/**
+
+ Name: BEC_Init
+
+ Description: Initialize the Backup Engine configuration unit.
+
+ Modified: 14-Jun-91
+
+ Returns: Nothing
+
+**/
+VOID BEC_Init( VOID )
+{
+ InitQueue( &uw_config_queue ) ;
+}
+
+
+
+/**
+
+ Name: BEC_Close
+
+ Description: Close the configuration unit by freeing the queue.
+
+ Modified: 14-Jun-91
+
+ Returns: Nothing
+
+**/
+VOID BEC_Close( VOID )
+{
+ Q_ELEM_PTR qelem ;
+
+ while ( (qelem = QueueHead(&uw_config_queue)) != NULL ) {
+ RemoveQueueElem( &uw_config_queue, qelem ) ;
+ free( GetQueueElemPtr( qelem ) ) ;
+ }
+}
+
+
diff --git a/private/utils/ntbackup/src/bec_mem.c b/private/utils/ntbackup/src/bec_mem.c
new file mode 100644
index 000000000..0b4730002
--- /dev/null
+++ b/private/utils/ntbackup/src/bec_mem.c
@@ -0,0 +1,514 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: becmem.c
+
+ Date Updated: 17-Jun-91
+
+ Description: Code to clone/free Backup Engine config structures.
+
+ $Log: M:/LOGFILES/BEC_MEM.C_V $
+
+ Rev 1.34 09 Jul 1993 14:38:56 ChuckS
+Made CompareConfigPtrs non-static BEC_CompareConfigPtrs, because it is
+passed as a function pointer to function SearchQueue in another module.
+Aside from being a semi-sleazoid programming practice, handing other
+modules function pointers to static functions is hazardous for the
+health of overlaid DOS programs.
+
+ Rev 1.33 30 Jun 1993 15:25:28 BARRY
+Add process_special_files
+
+ Rev 1.32 10 Jun 1993 07:46:38 MIKEP
+enable c++
+
+ Rev 1.31 19 May 1993 09:25:44 DON
+Fixed Nested Comment for NRL default packet size
+
+ Rev 1.30 14 May 1993 15:42:58 MARILYN
+NRL_spx_max_ipx_packet_size not initialized. Corrected grfs values for windows
+
+ Rev 1.29 20 Apr 1993 09:46:36 ChuckS
+Dougie added several fields to the BE_CFG, and ifdefed the definitions
+in "#if defined(OS_NLM)..." It would probably be a good idea to ifdef
+references to the fields as well. Just a thought....
+
+ Rev 1.28 19 Apr 1993 16:58:38 DOUG
+Added new NRL/TLI fields
+
+ Rev 1.27 19 Mar 1993 11:32:44 JOHNES
+Ifdef'ed backup_server_name out of P_CLIENT.
+
+ Rev 1.26 16 Mar 1993 14:53:56 JOHNES
+Ifdef'ed OUT set default for keep_drive_list for P_CLIENT.
+
+ Rev 1.25 01 Mar 1993 17:38:56 MARILYN
+set process checksum streams option off by default
+
+ Rev 1.24 09 Feb 1993 10:24:56 DOUG
+Changed supervisor_mode to TRUE by default.
+
+ Rev 1.23 09 Feb 1993 10:00:54 DOUG
+Added Client supervisor mode flag
+
+ Rev 1.22 05 Feb 1993 22:23:10 MARILYN
+removed copy/move functionality
+
+ Rev 1.21 08 Dec 1992 14:24:12 DON
+Integrated Move/Copy into tips
+
+ Rev 1.20 08 Dec 1992 11:45:36 DOUG
+Added new GRFS and NRL parameters
+
+ Rev 1.19 02 Nov 1992 17:15:06 STEVEN
+added init of string type
+
+ Rev 1.18 13 Oct 1992 12:34:22 STEVEN
+added otc level
+
+ Rev 1.17 14 May 1992 12:46:04 TIMN
+Changed compareConfigPtr CHAR's to INT8
+
+ Rev 1.16 13 May 1992 12:46:58 TIMN
+Added TEXT() macro to literals, but not msassert literals
+
+ Rev 1.15 04 May 1992 12:32:42 STEVEN
+NT_STUFF added string types
+
+ Rev 1.14 02 Feb 1992 15:52:54 GREGG
+Removed utf_supported boolean from config, and added UINT16 initial_buff_alloc.
+
+ Rev 1.13 27 Jan 1992 18:14:58 GREGG
+Changes for new config element: utf_supported.
+
+ Rev 1.12 13 Jan 1992 18:36:30 STEVEN
+added config switch for BSD sort
+
+ Rev 1.11 14 Nov 1991 10:19:16 BARRY
+TRICYCLE: Added restore_security.
+
+ Rev 1.10 06 Nov 1991 18:53:24 GREGG
+BIGWHEEL - 8200sx - Added catalog_level to BE config.
+
+ Rev 1.9 24 Oct 1991 11:20:08 BARRY
+CloneConfig() was cloning xlock flag as well--not good.
+
+ Rev 1.8 18 Oct 1991 14:23:32 BARRY
+Wasn't freeing all memory.
+
+ Rev 1.7 10 Sep 1991 18:19:16 DON
+got rid of pointer type mismatches
+
+ Rev 1.6 12 Aug 1991 15:54:16 BARRY
+DisplayNetwareServers() doesn't belong any more.
+
+ Rev 1.5 23 Jul 1991 18:09:20 BARRY
+Made the "reasonable" config defaults a little more reasonable.
+
+ Rev 1.4 23 Jul 1991 16:22:16 BARRY
+Added BEC_UpdateConfig functions.
+
+ Rev 1.3 01 Jul 1991 19:20:50 BARRY
+Initialize ret_val.
+
+ Rev 1.2 01 Jul 1991 19:03:56 BARRY
+Added code for exclusive lock on config structures.
+
+ Rev 1.1 30 Jun 1991 14:47:24 BARRY
+Got rid of default drive stuff.
+
+ Rev 1.0 19 Jun 1991 10:38:08 BARRY
+Initial revision.
+
+**/
+
+#include <stdlib.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "queues.h"
+#include "msassert.h"
+
+#include "beconfig.h"
+#include "bec_prv.h"
+
+
+extern Q_HEADER uw_config_queue ;
+
+BOOLEAN BEC_CompareConfigPtrs( INT8_PTR p1, INT8_PTR p2 ) ;
+
+/* Prototypes for static functions */
+static INT16 ClonePartList( PART_ENTRY *src, PART_ENTRY **dst ) ;
+static VOID FreeConfigStructure( BE_CFG_PTR cfg ) ;
+static VOID FreePartList( PART_ENTRY *p ) ;
+static VOID SetConfigDefaults( BE_CFG_PTR cfg ) ;
+
+/**/
+
+/**
+
+ Name: BEC_UseConfig
+
+ Description: Increments counting semaphore for the config.
+
+ Note: If the config structure is not already in the queue,
+ it is enqueued here.
+
+ Modified: 14-Jun-91
+
+ Returns: SUCCESS
+ OUT_OF_MEMORY
+
+**/
+INT16 BEC_UseConfig( BE_CFG_PTR cfg )
+{
+ BE_CFG_QITEM_PTR item ;
+ Q_ELEM_PTR qelem ;
+ INT16 ret_val = SUCCESS ;
+
+ msassert( cfg != NULL ) ;
+
+ qelem = SearchQueue( &uw_config_queue, BEC_CompareConfigPtrs, (INT8_PTR)cfg, FALSE ) ;
+
+ if ( qelem != NULL ) {
+
+ item = (BE_CFG_QITEM_PTR)qelem->q_ptr ;
+ item->use_count++;
+
+ } else {
+ ret_val = OUT_OF_MEMORY ;
+ if ( (item = (BE_CFG_QITEM_PTR)malloc(sizeof(Q_ELEM) + sizeof(BE_CFG_QITEM))) != NULL ) {
+ qelem = (Q_ELEM_PTR)(item + 1);
+ item->cfg = cfg ;
+ item->use_count = 1 ;
+ InitQElem( qelem ) ;
+ SetQueueElemPtr( qelem, item ) ;
+ EnQueueElem( &uw_config_queue, qelem, FALSE );
+ ret_val = SUCCESS ;
+ }
+ }
+ return( ret_val ) ;
+}
+
+
+/**/
+
+/**
+
+ Name: BEC_ReleaseConfig
+
+ Description: Decrements counting semaphore for the config. If
+ the count falls to zero, the config structure is
+ removed from the queue and freed.
+ If the config is not in the queue, it is freed
+ anyway.
+
+ Modified: 17-Jun-91
+
+ Returns: SUCCESS
+ BEC_NOT_IN_QUEUE
+
+**/
+INT16 BEC_ReleaseConfig( BE_CFG_PTR cfg )
+{
+ BE_CFG_QITEM_PTR item ;
+ Q_ELEM_PTR qelem ;
+ INT16 ret_val = SUCCESS ;
+
+ msassert( cfg != NULL ) ;
+
+ qelem = SearchQueue( &uw_config_queue, BEC_CompareConfigPtrs, (INT8_PTR)cfg, FALSE ) ;
+
+ if ( qelem != NULL ) {
+
+ item = (BE_CFG_QITEM_PTR)GetQueueElemPtr( qelem );
+ msassert( item != NULL );
+
+ item->use_count--;
+
+ if ( (cfg->xlock == FALSE) && (item->use_count <= 0) ) {
+ RemoveQueueElem( &uw_config_queue, qelem ) ;
+ FreeConfigStructure( cfg );
+ free( item ) ;
+ }
+
+ } else {
+
+ ret_val = (INT16)BEC_NOT_IN_QUEUE ;
+
+ if ( cfg->xlock == FALSE ) {
+ FreeConfigStructure( cfg );
+ }
+ }
+
+ return( ret_val ) ;
+
+}
+
+/**/
+
+/**
+
+ Name: BEC_CloneConfig
+
+ Description: Creates an new config structure and copies all
+ of the values from the source config to it.
+ The copy is not enqueued here: it will only get
+ enqueued if it is "used."
+
+ Modified: 14-Jun-91
+
+ Returns: Pointer to new config, or
+ NULL if any of the allocations fail.
+
+**/
+BE_CFG_PTR BEC_CloneConfig( BE_CFG_PTR cfg )
+{
+ BE_CFG_PTR new_cfg ;
+ INT16 status ;
+
+ if ( (new_cfg = (BE_CFG_PTR)malloc(sizeof(BE_CFG))) != NULL ) {
+
+ if ( cfg == NULL ) {
+
+ SetConfigDefaults( new_cfg ) ;
+
+ } else {
+
+ *new_cfg = *cfg ;
+ new_cfg->part_list = NULL ;
+ new_cfg->xlock = FALSE ;
+
+ status = ClonePartList( cfg->part_list, &new_cfg->part_list ) ;
+
+ if ( status != SUCCESS ) {
+ FreeConfigStructure( new_cfg ) ;
+ new_cfg = NULL ;
+ }
+ }
+ }
+ return( new_cfg );
+}
+
+
+/**
+
+ Name: BEC_UpdateConfig()
+
+ Description: Copies one config's values to another.
+
+ Modified: 23-Jul-91
+
+ Returns: SUCCESS
+ OUT_OF_MEMORY
+
+ Notes: Mainly for use by the BSD's RefreshConfig function.
+
+**/
+INT16 BEC_UpdateConfig( BE_CFG_PTR dst, BE_CFG_PTR src )
+{
+ *dst = *src ;
+
+ return( ClonePartList( src->part_list, &dst->part_list ) );
+
+}
+
+
+/**
+
+ Name: ClonePartList
+
+ Description: Makes a copy of a partition list
+
+ Modified: 14-Jun-91
+
+ Returns: SUCCESS
+ OUT_OF_MEMORY
+
+**/
+static INT16 ClonePartList( PART_ENTRY *src, PART_ENTRY **dst )
+{
+ PART_ENTRY *new_head = NULL ; /* head of new list */
+ PART_ENTRY *cur_part = NULL ; /* walks down new list */
+ PART_ENTRY *tmp_part ;
+ INT16 ret_val = SUCCESS ;
+
+ while ( (src != NULL) && (ret_val == SUCCESS) ) {
+ if ( (tmp_part = (PART_ENTRY *)malloc(sizeof(PART_ENTRY))) != NULL ) {
+ *tmp_part = *src;
+ tmp_part->next = NULL ;
+
+ if ( new_head == NULL ) {
+ new_head = tmp_part ;
+ } else {
+ cur_part->next = tmp_part ;
+ }
+ cur_part = tmp_part ;
+ } else {
+ ret_val = OUT_OF_MEMORY ;
+ }
+ src = src->next ;
+ }
+
+ *dst = new_head ;
+ return( ret_val );
+}
+
+
+/**
+
+ Name: FreeConfigStructure
+
+ Description: Frees a config structure after freeing its elements
+
+ Modified: 14-Jun-91
+
+ Returns: Nothing
+
+**/
+static VOID FreeConfigStructure( BE_CFG_PTR cfg )
+{
+ if ( cfg != NULL ) {
+ FreePartList( cfg->part_list ) ;
+ free( cfg );
+ }
+}
+
+
+/**
+
+ Name: FreePartList
+
+ Description: Frees a partition list
+
+ Modified: 14-Jun-91
+
+ Returns: Nothing
+
+**/
+static VOID FreePartList( PART_ENTRY *p )
+{
+ PART_ENTRY *tmp ;
+
+ while ( p != NULL ) {
+ tmp = p ;
+ p = p->next ;
+ free( tmp ) ;
+ }
+}
+
+
+/**
+
+ Name: CompareConfigPointers
+
+ Description: Called by QueueSearch to find a particular config
+ in the config queue.
+
+ Modified: 14-Jun-91
+
+ Returns: TRUE if pointers match
+
+**/
+BOOLEAN BEC_CompareConfigPtrs( INT8_PTR p1, INT8_PTR p2 )
+{
+ BE_CFG_QITEM_PTR qcfg ;
+
+ qcfg = (BE_CFG_QITEM_PTR)GetQueueElemPtr((Q_ELEM_PTR)p1) ;
+
+ return( (INT8_PTR)(qcfg->cfg) == p2 ) ;
+}
+
+
+/**
+
+ Name: SetConfigDefaults
+
+ Description: Initializes a config structure with reasonable
+ default values. Probably shouldn't be used much
+ since the UI should initialize a config.
+
+ Modified: 18-Jun-91
+
+ Returns: Nothing
+
+**/
+static VOID SetConfigDefaults( BE_CFG_PTR cfg )
+{
+ msassert( cfg != NULL );
+
+ cfg->special_word = 0 ; /* special flags */
+ cfg->max_buffers = 3 ; /* max # of TF buffers */
+ cfg->reserve_mem = 0 ; /* after getting TF buffs */
+ cfg->tfl_buff_size = 9216 ; /* size of TF buffers */
+#ifdef OS_NLM
+ cfg->max_buffer_size = 32768 ; /* NLMs default SMB max buffer size */
+#else
+#if defined( OS_WIN )
+ cfg->max_buffer_size = 4096 ; /* Window's def. SMB max buff size */
+#else
+ cfg->max_buffer_size = 512 ; /* SMB max buffer size */
+#endif
+#endif
+ cfg->skip_open_files = FALSE ; /* if true, skip; false, wait */
+ cfg->backup_files_inuse = TRUE ; /* ignore sharing problems? */
+ cfg->support_afp_server = TRUE ; /* backup Mac resource info? */
+ cfg->extended_date_support = TRUE ; /* reset last access dates? */
+ cfg->hidden_flg = TRUE ; /* don't process hidden files */
+ cfg->special_flg = FALSE ; /* don't process special files*/
+ cfg->set_archive_flg = TRUE ; /* clear the modified bit? */
+ cfg->proc_empty_flg = TRUE ; /* process empty subdirs */
+ cfg->exist_flg = TRUE ; /* replace existing files */
+ cfg->prompt_flg = FALSE ; /* prompt before replace files*/
+ cfg->part_list = NULL ; /* partition list */
+ cfg->net_num = 0 ; /* network type */
+#if !defined(P_CLIENT)
+ cfg->keep_drive_list[0] = TEXT('\0') ; /* drives to keep */
+#endif /* !P_CLIENT */
+ cfg->remote_drive_backup = FALSE ; /* backup remote WS drives? */
+ cfg->use_ffr = TRUE ; /* use FFR for restore/verify?*/
+ cfg->write_format = 0 ; /* format which TF is to write*/
+ cfg->nrl_dos_vector = 0x60 ;
+ cfg->xlock = FALSE ; /* Config locked--don't free */
+ cfg->catalog_level = 0 ; /* NONE */
+ cfg->restore_security = TRUE ; /* Restore security info */
+ cfg->sort_bsd_by_dle = TRUE ; /* sort bsds by DLE as default*/
+ cfg->initial_buff_alloc = 32 ; /* mem allocated for tape buffers at init */
+#ifdef UNICODE
+ cfg->string_types = 0 ; /* work with ASCII by default */
+ cfg->string_types = BEC_UNIC_STR ; /* work with ASCII by default */
+#else
+ cfg->string_types = BEC_ANSI_STR ; /* work with ASCII by default */
+#endif
+ cfg->otc_cat_level = 0 ; /* on tape catalog default level */
+#ifdef OS_NLM
+ cfg->max_remote_resources = 0x64 ; /* max remote resources */
+#else
+#if defined( OS_WIN )
+ cfg->max_remote_resources = 0x20 ;
+#else
+ cfg->max_remote_resources = 0x10 ; /* max remote resources */
+#endif
+#endif
+#if !defined(P_CLIENT)
+ cfg->backup_server_name[0] ='\0'; /* no name by default */
+#endif /* !P_CLIENT */
+ cfg->NRL_transport_type = 0 ; /* default to NRL SPX */
+ cfg->GRFS_timeout_seconds = 30 ; /* default 30 seconds */
+ cfg->NRL_spx_max_ipx_packet = 0x240 ; /* default packet size */
+ cfg->supervisor_mode = TRUE ; /* in supervisor mode */
+ cfg->process_checksum_streams = FALSE ; /* don't process checksum strms */
+
+#ifdef OS_NLM
+ cfg->NRL_protocols = NRL_PROT_SPX ; /* SPX protocol by default */
+ cfg->TCP_cleanup_interval = 30 ; /* tcp resource cleaner interval (secs) */
+ cfg->TCP_listen_port = 6101 ; /* tcp resource listener port */
+#endif
+ cfg->process_special_files = FALSE ; /* don't process special files */
+ cfg->ems_pub_pri = BEC_EMS_BOTH ;
+ cfg->ems_rip_kick = FALSE ;
+ cfg->ems_wipe_clean = FALSE ;
+}
+
+
diff --git a/private/utils/ntbackup/src/bec_misc.c b/private/utils/ntbackup/src/bec_misc.c
new file mode 100644
index 000000000..4fc3eff75
--- /dev/null
+++ b/private/utils/ntbackup/src/bec_misc.c
@@ -0,0 +1,320 @@
+
+
+
+
+
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: bec_misc.c
+
+ Date Updated: 18-Jun-91
+
+ Description: Miscellaneous functions for the Backup Engine
+ configuration unit.
+
+ $Log: N:/LOGFILES/BEC_MISC.C_V $
+
+ Rev 1.9 10 Jun 1993 07:47:44 MIKEP
+enable c++
+
+ Rev 1.8 06 Oct 1992 13:25:04 DAVEV
+Unicode strlen verification
+
+ Rev 1.7 20 May 1992 15:02:34 TIMN
+Fixed syntax error.
+
+ Rev 1.6 19 May 1992 12:33:14 TIMN
+Changed str's to mem calls
+Changed part_name type
+Introduced part_name_size
+
+ Rev 1.5 13 May 1992 12:47:26 TIMN
+Added TEXT() macro to literals, but not msassert literals
+
+ Rev 1.4 13 Aug 1991 10:15:42 DON
+added include CTYPE.H to prototype TOUPPER
+
+ Rev 1.3 30 Jun 1991 12:36:00 BARRY
+Added parition routines, clean up removal of default drive stuff.
+
+ Rev 1.2 28 Jun 1991 16:52:06 BARRY
+Added BEC_AddKeepDrive().
+
+ Rev 1.1 26 Jun 1991 10:59:44 BARRY
+Made KeepDrive case-insensitive.
+
+ Rev 1.0 19 Jun 1991 10:38:10 BARRY
+Initial revision.
+
+**/
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "msassert.h"
+#include "beconfig.h"
+#include "bec_prv.h"
+
+/**/
+
+/**
+
+ Name: BEC_GetPartitionName()
+
+ Description: Get name of a specific partition from a given drive
+
+ Modified: 18-Jun-91
+
+ Returns: Pointer to partition name
+
+**/
+INT8_PTR BEC_GetPartitionName( BE_CFG_PTR cfg, INT16 drv_num, INT16 part_num )
+{
+ PART_ENTRY *part_entry ;
+
+ msassert( cfg != NULL ) ;
+
+ part_entry = BEC_GetPartList( cfg );
+
+ while ( part_entry != NULL ) {
+ if ( part_entry->drv_num == drv_num && part_entry->partition_num == part_num ) {
+ break;
+ }
+ part_entry = part_entry->next ;
+ }
+
+ if ( part_entry == NULL ) {
+ return( NULL ) ;
+ } else {
+ return( part_entry->partition_name ) ;
+ }
+}
+
+/**/
+
+/**
+
+ Name: BEC_GetFirstPartition
+
+ Description: Returns the first partition from the config's partition
+ list
+
+ Modified: 30-Jun-91
+
+ Returns: Pointer to partition -or- NULL
+
+**/
+PART_ENTRY *BEC_GetFirstPartition( BE_CFG_PTR cfg )
+{
+ msassert( cfg != NULL ) ;
+
+ return( cfg->part_list ) ;
+}
+
+/**
+
+ Name: BEC_GetNextPartition
+
+ Description: Returns the first partition from the config's partition
+ list.
+
+ Modified: 30-Jun-91
+
+ Returns: Pointer to partition -or- NULL
+
+**/
+PART_ENTRY *BEC_GetNextPartition( BE_CFG_PTR cfg, PART_ENTRY *curr_part )
+{
+ (VOID) cfg ;
+
+ msassert( cfg != NULL ) ;
+ msassert( curr_part != NULL ) ;
+
+ return( curr_part->next ) ;
+}
+
+
+/**
+
+ Name: BEC_AddPartition
+
+ Description: Adds a partition the the config's partition list.
+
+ Modified: 30-Jun-91
+
+ Returns: SUCCESS
+ OUT_OF_MEMORY
+**/
+INT16 BEC_AddPartition( BE_CFG_PTR cfg, INT16 drv_num, INT16 part_num, INT8_PTR name, INT16 name_size )
+{
+ INT16 ret_val = OUT_OF_MEMORY ;
+ PART_ENTRY *p ;
+ PART_ENTRY *new_part ;
+
+ msassert( cfg != NULL ) ;
+ msassert( ( name_size > 0 ) && ( name_size < 13 * sizeof (CHAR) ) ) ;
+
+ p = cfg->part_list ;
+
+ if ( p != NULL ) {
+ while ( p->next != NULL ) {
+ p = p->next ;
+ }
+ }
+
+ if ( (new_part = (PART_ENTRY *)malloc(sizeof(PART_ENTRY))) != NULL ) {
+ new_part->next = NULL ;
+ new_part->drv_num = drv_num ;
+ new_part->partition_num = part_num ;
+ new_part->partition_name_size = name_size ;
+ memcpy( new_part->partition_name, name, name_size ) ;
+ if ( p != NULL ) {
+ p->next = new_part ;
+ }
+ ret_val = SUCCESS ;
+ }
+ return( ret_val ) ;
+}
+
+
+/**
+
+ Name: BEC_SetPartitionName()
+
+ Description: Return name of a specific partition from a given drive
+
+ Modified: 18-Jun-91
+
+ Returns: SUCCESS
+ FAILURE
+ OUT_OF_MEMORY
+
+**/
+INT16 BEC_SetPartitionName(
+ BE_CFG_PTR cfg, /* configuration to use */
+ INT16 drv_num, /* desired source drive */
+ INT16 part_num, /* partition table entry to use */
+ INT8_PTR part_name, /* place to put name */
+ INT16 part_name_size ) /* length of part_name */
+{
+ INT16 ret_val = FAILURE ;
+ PART_ENTRY *new_part ;
+ PART_ENTRY *last_part = NULL ;
+ PART_ENTRY *next_part ;
+
+ msassert( cfg != NULL ) ;
+ msassert( ( part_name_size > 0 ) && ( part_name_size < 13 * sizeof (CHAR) ) ) ;
+
+ next_part = BEC_GetPartList( cfg );
+
+ while( ( next_part != NULL ) && ( ret_val == FAILURE ) ) {
+ if( ( next_part->drv_num == drv_num ) && ( next_part->partition_num == part_num ) ) {
+ memcpy( next_part->partition_name, part_name, part_name_size ) ;
+ next_part->partition_name_size = part_name_size ;
+ ret_val = SUCCESS ;
+ }
+ last_part = next_part ;
+ next_part = next_part->next ;
+ }
+
+ if ( ret_val != SUCCESS ) {
+
+ new_part = (PART_ENTRY *)malloc( sizeof( PART_ENTRY ) ) ;
+
+ if ( new_part != NULL ) {
+
+ memcpy( new_part->partition_name, part_name, part_name_size ) ;
+ next_part->partition_name_size = part_name_size ;
+
+ new_part->drv_num = drv_num ;
+ new_part->partition_num = part_num ;
+
+ new_part->next = cfg->part_list ;
+ cfg->part_list = new_part ;
+
+ ret_val = SUCCESS ;
+
+ } else {
+ ret_val = OUT_OF_MEMORY ;
+ }
+ }
+
+ return( ret_val ) ;
+}
+
+/**/
+
+/**
+
+ Name: BEC_KeepDrive()
+
+ Description: Examines the configuration's "keep drive list" (that
+ is not normally part of the configuration file) to
+ determine if the user has blocked out the display
+ of a certain drive.
+
+ Modified: 18-Jun-91
+
+ Returns: TRUE if drive should be in DLE list (or "kept")
+
+**/
+BOOLEAN BEC_KeepDrive( BE_CFG_PTR cfg, CHAR drv_letter )
+{
+ BOOLEAN result ;
+ CHAR_PTR p ;
+
+ msassert( cfg != NULL ) ;
+
+ if ( (cfg->keep_drive_list != NULL) && (*(cfg->keep_drive_list) != TEXT('\0') ) ) {
+
+ result = FALSE ;
+ drv_letter = (CHAR)toupper( drv_letter ) ;
+ p = cfg->keep_drive_list ;
+ while ( *p ) {
+ if ( toupper( *p ) == drv_letter ) {
+ result = TRUE ;
+ break ;
+ }
+ p++ ;
+ }
+ } else {
+ result = TRUE ;
+ }
+
+ return( result ) ;
+}
+
+/**/
+
+/**
+
+ Name: BEC_AddKeepDrive()
+
+ Description: Adds a drive to the keep drive list.
+
+ Modified: 27-Jun-91
+
+ Returns: SUCCESS
+ FAILURE
+
+**/
+BOOLEAN BEC_AddKeepDrive( BE_CFG_PTR cfg, CHAR_PTR drive )
+{
+ BOOLEAN result = FAILURE ;
+
+ msassert( cfg != NULL ) ;
+ msassert( strlen( drive ) <= sizeof (CHAR) ) ;
+
+ if ( strlen( cfg->keep_drive_list ) < 25*sizeof (CHAR) ) {
+ strcat( cfg->keep_drive_list, drive ) ;
+ result = SUCCESS ;
+ }
+ return( result ) ;
+}
+
+
diff --git a/private/utils/ntbackup/src/bitmaps.rc b/private/utils/ntbackup/src/bitmaps.rc
new file mode 100644
index 000000000..e7aa332a5
--- /dev/null
+++ b/private/utils/ntbackup/src/bitmaps.rc
@@ -0,0 +1,218 @@
+/******************************************************************************
+Copyright (c) Conner Software Products Group, 1993
+GSH
+
+ Name: wntrpark.rc
+
+ Description: This file contains the references to bitmap resources for
+ the Windows GUI Project Resource File.
+
+ $Log: G:\ui\logfiles\bitmaps.rcv $
+
+ Rev 1.16 12 Jul 1993 09:25:12 GLENN
+ Said goodbye to the diver and shark.
+
+ Rev 1.15 29 Apr 1993 15:49:36 Aaron
+ Changed startup logo for non-Cayman app
+
+ Rev 1.14 02 Apr 1993 14:02:12 GLENN
+ Added info and gray info bitmaps.
+
+ Rev 1.13 18 Feb 1993 12:57:52 chrish
+ Added bitmap logo caymlogo.bmp for CAYMAN.
+
+ Rev 1.12 20 Jan 1993 20:57:16 MIKEP
+ floppy
+
+ Rev 1.11 10 Sep 1992 17:22:06 GLENN
+ Updated to support common disk bitmaps.
+
+ Rev 1.10 09 Sep 1992 17:08:52 GLENN
+ Updated for NEW LOOK BIMINI.
+
+ Rev 1.9 03 Sep 1992 15:57:50 GLENN
+ Updated the NT disk bitmaps.
+
+ Rev 1.8 20 Aug 1992 08:45:26 GLENN
+ Added TAPES and TAPESINDRIVE bitmap stuff.
+
+ Rev 1.7 06 Jul 1992 10:32:18 MIKEP
+ added ram and cdrom bitmaps
+
+ Rev 1.6 10 Jun 1992 16:11:02 GLENN
+ Updated according to NT SPEC.
+
+ Rev 1.5 22 Apr 1992 17:58:46 GLENN
+ Added shark and diver bitmap stuff.
+
+ Rev 1.4 09 Mar 1992 09:19:08 GLENN
+ Added logo bitmap support.
+
+ Rev 1.3 03 Mar 1992 18:03:32 GLENN
+ Changed red checkmark bitmaps to black checkmarks.
+
+ Rev 1.2 16 Dec 1991 17:06:58 GLENN
+ Added exit button stuff.
+
+ Rev 1.1 15 Dec 1991 10:21:48 MIKEP
+ hidden files
+
+ Rev 1.0 20 Nov 1991 19:16:46 SYSTEM
+ Initial revision.
+
+******************************************************************************/
+
+// BITMAPS -- ID's are defined in the Resource Manager header file 'ss_rsm.h'
+
+ IDRBM_BACKUP BITMAP ombackup.bmp // CHS:03-27-92 Backup bitmap.
+ IDRBM_BACKUP_GRAY BITMAP omgbacku.bmp // CHS:03-27-92 Backup bitmap - gray.
+ IDRBM_RESTORE BITMAP omrestor.bmp // CHS:03-27-92 Restore bitmap.
+ IDRBM_RESTORE_GRAY BITMAP omgresto.bmp // CHS:03-27-92 Restore bitmap - gray.
+ IDRBM_ERASE BITMAP omerase.bmp // CHS:03-27-92 Erase bitmap.
+ IDRBM_ERASE_GRAY BITMAP omgerase.bmp // CHS:03-27-92 Erase bitmap - gray.
+ IDRBM_RETENSION BITMAP omtensio.bmp // CHS:03-27-92 Retension bitmap.
+ IDRBM_RETENSION_GRAY BITMAP omgtensi.bmp // CHS:03-27-92 Retension bitmap - gray.
+ IDRBM_EJECT BITMAP omeject.bmp // CHS:03-27-92 Eject ribbon item bitmap.
+ IDRBM_EJECT_GRAY BITMAP omgeject.bmp // CHS:03-27-92 Eject ribbon item bitmap - gray.
+ IDRBM_CATALOG BITMAP omcat.bmp // Catalog ribbon item bitmap.
+ IDRBM_CATALOG_GRAY BITMAP omgcat.bmp // Catalog ribbon item bitmap - gray.
+ IDRBM_CHECK BITMAP omcheck.bmp // CHS:03-27-92 Check ribbon item bitmap.
+ IDRBM_CHECK_GRAY BITMAP omgcheck.bmp // CHS:03-27-92 Check ribbon item bitmap - gray.
+ IDRBM_UNCHECK BITMAP omunchec.bmp // CHS:03-27-92 Uncheck ribbon item bitmap.
+ IDRBM_UNCHECK_GRAY BITMAP omgunche.bmp // CHS:03-27-92 Uncheck ribbon item bitmap - gray.
+ IDRBM_SEL_NONE BITMAP omselnon.bmp // Not selected bitmap.
+ IDRBM_SEL_PART BITMAP omselpar.bmp // Partial selected bitmap.
+ IDRBM_SEL_ALL BITMAP omselall.bmp // All selected bitmap.
+
+ IDRBM_FLOPPYDRIVE BITMAP omfdisk.bmp // Floppy drive bitmap.
+ IDRBM_HARDDRIVE BITMAP omhdisk.bmp // Hard drive bitmap.
+ IDRBM_NETDRIVE BITMAP omndisk.bmp // Network drive bitmap.
+ IDRBM_RAMDRIVE BITMAP omrdisk.bmp // RAM drive bitmap.
+ IDRBM_CDROM BITMAP omcdisk.bmp // CD ROM drive bitmap.
+
+# if !defined ( OEM_MSOFT )
+
+// IDRBM_CHECK BITMAP check3.bmp // Check ribbon item bitmap.
+// IDRBM_CHECK_GRAY BITMAP gcheck.bmp // Check ribbon item bitmap - gray.
+// IDRBM_UNCHECK BITMAP uncheck3.bmp // Uncheck ribbon item bitmap.
+// IDRBM_UNCHECK_GRAY BITMAP guncheck.bmp // Uncheck ribbon item bitmap - gray.
+// IDRBM_SEL_NONE BITMAP sel_none.bmp // Not selected bitmap.
+// IDRBM_SEL_PART BITMAP sel_part.bmp // Partial selected bitmap.
+// IDRBM_SEL_ALL BITMAP sel_all3.bmp // All selected bitmap.
+// IDRBM_FLOPPYDRIVE BITMAP floppy.bmp // Floppy drive bitmap.
+// IDRBM_HARDDRIVE BITMAP hard.bmp // Hard drive bitmap.
+// IDRBM_RAMDRIVE BITMAP ram.bmp // ram drive bitmap.
+// IDRBM_CDROM BITMAP cdrom.bmp // cdrom drive bitmap.
+// IDRBM_NETDRIVE BITMAP netdrv.bmp // Network drive bitmap.
+
+ IDRBM_NETCONNECT BITMAP netcon.bmp
+ IDRBM_NETCONNECT_GRAY BITMAP gnetcon.bmp
+ IDRBM_NETDISCON BITMAP netdcon.bmp
+ IDRBM_NETDISCON_GRAY BITMAP gnetdcon.bmp
+
+ IDRBM_INFO BITMAP info.bmp
+ IDRBM_INFO_GRAY BITMAP ginfo.bmp
+
+ IDRBM_FOLDER_EN BITMAP fol_en.bmp //folder - empty
+ IDRBM_FOLDER_EM BITMAP fol_em.bmp //folder - empty, minus
+ IDRBM_FOLDER_EP BITMAP fol_ep.bmp //folder - empty, plus
+ IDRBM_FOLDER_EON BITMAP fol_eon.bmp //folder - empty, open
+ IDRBM_FOLDER_EOM BITMAP fol_eom.bmp //folder - empty, open, minus
+ IDRBM_FOLDER_EOP BITMAP fol_eop.bmp //folder - empty, open, plus
+ IDRBM_FOLDER_ECN BITMAP fol_ecn.bmp //folder - empty, corrupt
+ IDRBM_FOLDER_ECM BITMAP fol_ecm.bmp //folder - empty, corrupt, minus
+ IDRBM_FOLDER_ECP BITMAP fol_ecp.bmp //folder - empty, corrupt, plus
+ IDRBM_FOLDER_EOCN BITMAP fol_eocn.bmp //folder - empty, open, corrupt
+ IDRBM_FOLDER_EOCM BITMAP fol_eocm.bmp //folder - empty, open, corrupt, minus
+ IDRBM_FOLDER_EOCP BITMAP fol_eocp.bmp //folder - empty, open, corrupt, plus
+
+ IDRBM_TRANSFER BITMAP omtrans.bmp // Transfer bitmap.
+ IDRBM_TRANSFER_GRAY BITMAP omgtrans.bmp // Transfer bitmap - gray.
+ IDRBM_MODIFIED BITMAP mod3.bmp // Modified ribbon item bitmap.
+ IDRBM_MODIFIED_GRAY BITMAP gmod.bmp // Modified ribbon item bitmap - gray.
+ IDRBM_ADVANCED BITMAP adv3.bmp // Advanced ribbon item bitmap.
+ IDRBM_ADVANCED_GRAY BITMAP gadv3.bmp // Advanced ribbon item bitmap - gray.
+ IDRBM_MEMORY BITMAP memory.bmp // Memory trace ribbon item bitmap.
+ IDRBM_LOGFILE BITMAP logfile.bmp // Log File bitmap.
+ IDRBM_UPARROW BITMAP uparrow.bmp // Up arrow bitmap.
+ IDRBM_UPARROW_GRAY BITMAP guparrow.bmp // Up arrow bitmap. - gray
+ IDRBM_DNARROW BITMAP dnarrow.bmp // Down arrow bitmap.
+ IDRBM_DOWNARROW_GRAY BITMAP gdnarrow.bmp // Down arrow bitmap. - gray
+ IDRBM_VERIFY BITMAP verify.bmp // Verify ribbon item bitmap.
+ IDRBM_VERIFY_GRAY BITMAP gverify.bmp // Verify ribbon item bitmap - gray.
+ IDRBM_EXIT BITMAP exit.bmp // Exit ribbon item bitmap.
+ IDRBM_EXIT_GRAY BITMAP gexit.bmp // Exit ribbon item bitmap - gray.
+ IDRBM_SERVER BITMAP server.bmp // Server bitmap.
+ IDRBM_SERVERDETACHED BITMAP serverd.bmp // Detached server bitmap.
+ IDRBM_SEARCH BITMAP search.bmp // Search ribbon item bitmap.
+ IDRBM_SEARCH_GRAY BITMAP gsearch.bmp // Search ribbon item bitmap - gray.
+ IDRBM_NEXTSET BITMAP nextset.bmp // Next Set ribbon item bitmap.
+ IDRBM_NEXTSET_GRAY BITMAP gnextset.bmp // Next Set ribbon item bitmap - gray.
+ IDRBM_REWIND BITMAP rewind.bmp // REWIND ribbon item bitmap.
+ IDRBM_REWIND_GRAY BITMAP grewind.bmp // REWIND ribbon item bitmap - gray.
+ IDRBM_RT_ARROW BITMAP rt_arrow.bmp // Destination arrow for job status box.
+
+ IDRBM_SEL_ALL_RED BITMAP sel_all2.bmp // Red select all
+ IDRBM_CHECK_RED BITMAP check2.bmp // Red check button
+ IDRBM_UNCHECK_RED BITMAP uncheck2.bmp // Red uncheck button
+ IDRBM_ADVANCED_RED BITMAP adv2.bmp // Red advanced button
+
+ // Define appropriate logo bitmap
+ #ifdef CAYMAN
+ IDRBM_LOGO BITMAP caymlogo.bmp
+ #else
+ IDRBM_LOGO BITMAP start.bmp
+ #endif
+
+# else // defined ( OEM_MSOFT )
+ IDRBM_EMS_SERVER BITMAP om_servs.bmp // Server bitmap.
+ IDRBM_EMS_ENTERPRISE BITMAP om_entrs.bmp // Exchange Enterprise bitmap
+ IDRBM_EMS_SITE BITMAP om_sites.bmp // Exchange site bitmap
+ IDRBM_EMS_MDB BITMAP om_mdbs.bmp // Exchange MDB volume
+ IDRBM_EMS_DSA BITMAP om_dsas.bmp // Exchange DSA volume
+ IDRBM_EMS_MDBX BITMAP om_mdbx.bmp // Exchange MDB volume bad
+ IDRBM_EMS_DSAX BITMAP om_dsax.bmp // Exchange DSA volume bad
+ IDRBM_EMS_DSAP BITMAP om_dsap.bmp // Exchange DSA volume bad
+ IDRBM_EMS_MDBP BITMAP om_mdbp.bmp // Exchange MDB volume bad
+ IDRBM_RCVR_STATUS BITMAP om_stats.bmp // Recover status bar brush pattern
+
+/* The ID for this control is defined in ctl3d.h as 26567 */
+ CTL3D_3DCHECK BITMAP 3dcheck.bmp // 3-D Check box for 3-D dialogs
+
+# endif // defined ( OEM_MSOFT ) // CHS:03-27-92
+
+// COMMON BITMAPS
+
+IDRBM_BLANK16x16 BITMAP om_blank.bmp // blank 16x16 bit map
+IDRBM_EXE BITMAP exe.bmp // Executable bitmap.
+IDRBM_FILE BITMAP file.bmp // File bitmap.
+IDRBM_FOLDER BITMAP folder.bmp // Folder bitmap.
+IDRBM_FOLDERPLUS BITMAP folder_p.bmp // Folder with plus bitmap.
+IDRBM_FOLDERMINUS BITMAP folder_m.bmp // Folder with minus bitmap.
+IDRBM_FOLDEROPEN BITMAP fold_on.bmp // Open Folder bitmap.
+IDRBM_FOLDERPLUSOPEN BITMAP fold_op.bmp // Open Folder with plus bitmap.
+IDRBM_FOLDERMINUSOPEN BITMAP fold_om.bmp // Open Folder with minus bitmap.
+IDRBM_FOLDERC BITMAP fol_cn.bmp // Corrupt Folder bitmap.
+IDRBM_FOLDERPLUSC BITMAP fol_cp.bmp // Corrupt Folder with plus bitmap.
+IDRBM_FOLDERMINUSC BITMAP fol_cm.bmp // Corrupt Folder with minus bitmap.
+IDRBM_FOLDEROPENC BITMAP fol_ocn.bmp // Corrupt Open Folder bitmap.
+IDRBM_FOLDERPLUSOPENC BITMAP fol_ocp.bmp // Corrupt Open Folder with plus bitmap.
+IDRBM_FOLDERMINUSOPENC BITMAP fol_ocm.bmp // Corrupt Open Folder with minus bitmap.
+IDRBM_PARENTDIR BITMAP pdir2.bmp // Parent directory bitmap.
+IDRBM_TAPE BITMAP tape2.bmp // Tape bitmap.
+IDRBM_TAPEINDRIVE BITMAP tapein2.bmp // Tape in drive bitmap.
+IDRBM_TAPES BITMAP tapes2.bmp // Tape bitmap.
+IDRBM_TAPESINDRIVE BITMAP tapesin2.bmp // Tape in drive bitmap.
+IDRBM_SDISK BITMAP sdisk.bmp // Small disk bitmap.
+IDRBM_BSET BITMAP bset.bmp // Backup set bitmap.
+IDRBM_BSETPART BITMAP bsetpart.bmp // Partial backup set bitmap.
+IDRBM_LTAPE BITMAP ltape.bmp // Large tape bitmap.
+IDRBM_CORRUPTFILE BITMAP crptfile.bmp // corrupt file.
+IDRBM_HCRPTFILE BITMAP hcrpfile.bmp // hidden corrupt file
+IDRBM_HFILE BITMAP hfile.bmp // hidden normal file
+IDRBM_HEXEFILE BITMAP hexefile.bmp // hidden exe file
+IDRBM_FLOPPY BITMAP floppy1.bmp // floppy bitmap.
+IDRBM_FLOPPYINDRIVE BITMAP floppy2.bmp // floppy in drive bitmap.
+IDRBM_FLOPPYS BITMAP floppy3.bmp // floppys bitmap.
+IDRBM_FLOPPYSINDRIVE BITMAP floppy4.bmp // floppys in drive bitmap.
+
diff --git a/private/utils/ntbackup/src/bkuevent.mc b/private/utils/ntbackup/src/bkuevent.mc
new file mode 100644
index 000000000..fb4ab8bb4
--- /dev/null
+++ b/private/utils/ntbackup/src/bkuevent.mc
@@ -0,0 +1,99 @@
+;/*
+;Copyright (c) 1992 Maynard Electrionics, Inc.
+;
+;Module Name:
+;
+; bkuevent.h
+;
+;Abstract:
+;
+; Definitions for ntbackup events.
+;
+;Author:
+;
+; David Van Camp
+;
+;Revision History:
+;
+;Notes:
+;
+; This file is generated by the MC tool from the bkuevent.mc file.
+;
+;--*/
+;
+;#ifndef _BKUEVENT_
+;#define _BKUEVENT_
+;
+
+;
+;
+;/////////////////////////////////////////////////////////////////////////
+;//
+;// NT Backup Events
+;//
+;// Codes 8000 - 8008
+;//
+;/////////////////////////////////////////////////////////////////////////
+;
+;
+;
+MessageId=8000 SymbolicName=EVENT_BKUP_BEGINBACKUP
+Language=English
+Begin Backup of '%1'
+ Verify: %2
+ Mode: %3
+ Type: %4
+.
+MessageId=+1 SymbolicName=EVENT_BKUP_ENDBACKUP
+Language=English
+End Backup of '%1'
+ Verify: %2
+ Mode: %3
+ Type: %4
+.
+MessageId=+1 SymbolicName=EVENT_BKUP_BEGINRESTORE
+Language=English
+Begin Restore to '%1'
+ Verify: %2
+.
+MessageId=+1 SymbolicName=EVENT_BKUP_ENDRESTORE
+Language=English
+End Restore to '%1'
+ Verify: %2
+.
+MessageId=+1 SymbolicName=EVENT_BKUP_BEGINERASE
+Language=English
+Begin Erase
+.
+MessageId=+1 SymbolicName=EVENT_BKUP_ENDERASE
+Language=English
+End Erase
+.
+MessageId=+1 SymbolicName=EVENT_BKUP_BEGINRETENSION
+Language=English
+Begin Retension
+.
+MessageId=+1 SymbolicName=EVENT_BKUP_ENDRETENSION
+Language=English
+End Retension
+.
+MessageId=+1 SymbolicName=EVENT_BKUP_BEGINVERIFY
+Language=English
+Begin Verify to '%1'
+.
+MessageId=+1 SymbolicName=EVENT_BKUP_ENDVERIFY
+Language=English
+End Verify to '%1'
+.
+MessageId=+1 SymbolicName=EVENT_BKUP_EMS_ERROR
+Language=English
+Microsoft Exchange services returned '%1' from a call to '%2' additional data '%3'
+.
+MessageId=+1 SymbolicName=EVENT_BKUP_EMS_DB_ERROR
+Language=English
+Microsoft Exchange services returned too few databases for backup
+Only %1 databases was retured but Backup expected %2
+.
+
+;#endif // _BKUEVENT_
+
diff --git a/private/utils/ntbackup/src/bsdlasto.c b/private/utils/ntbackup/src/bsdlasto.c
new file mode 100644
index 000000000..1753a3b90
--- /dev/null
+++ b/private/utils/ntbackup/src/bsdlasto.c
@@ -0,0 +1,290 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: bsdlasto.c
+
+ Description: This file contains code to save / restore / clear the
+ BSD for the last operation. This can be used for Verify Last Backup
+ and Verify Last Restore.
+
+
+ $Log: Q:/LOGFILES/BSDLASTO.C_V $
+
+ Rev 1.5 18 Jun 1993 08:58:10 MIKEP
+enable C++
+
+ Rev 1.4 25 Mar 1993 15:57:36 JOHNES
+Added some msasserts to make sure a BSD handle is being passed in.
+
+ Rev 1.3 18 Aug 1992 10:10:22 STEVEN
+fix warnings
+
+ Rev 1.2 12 Jun 1991 16:01:44 STEVEN
+BSDU code review
+
+ Rev 1.1 29 May 1991 17:21:20 STEVEN
+Re-Design of BSDU for New Fast File Restore
+
+ Rev 1.0 09 May 1991 13:36:46 HUNTER
+Initial revision.
+
+**/
+#include "stdtypes.h"
+
+#include "msassert.h"
+#include "bsdu.h"
+
+/**/
+/**
+
+ Name: BSD_SaveLastOper()
+
+ Description: This function goes clears the 'old' Last Oper BSD list.
+ It then goes thru the current BSD list and unmarks all "deleted"
+ FSEs. It then copy's the queue header to the last oper queue
+ header and re-initializes the current queue header.
+
+
+ Modified: 5/17/1991 14:10:51
+
+ Returns: VOID
+
+ Notes:
+
+ See also: $/SEE( BSD_ClearLastOper(), BSD_ProcLastOper() )$
+
+ Declaration:
+
+**/
+VOID BSD_SaveLastOper(
+BSD_HAND bsdh ) /* I - The BSD handle to save the last operation for */
+{
+ BSD_PTR bsd ;
+
+ msassert( bsdh != NULL ) ;
+
+ BSD_ClearLastOper( bsdh ) ;
+
+ bsd = (BSD_PTR)QueueHead( &(bsdh->current_q_hdr) ) ;
+
+ while( bsd != NULL ) {
+
+ BSD_ClearDelete( bsd ) ;
+
+ bsd = (BSD_PTR)QueueNext( &(bsd->q) ) ;
+
+ }
+
+ BSD_SwapOper ( bsdh ) ;
+
+}
+/**/
+/**
+
+ Name: BSD_ClearLastOper()
+
+ Description: This function release all resources held by the last
+ operation BSD queue.
+
+
+ Modified: 5/17/1991 14:12:26
+
+ Returns: None
+
+ Notes:
+
+ See also: $/SEE( BSD_SaveLastOper(), BSD_ProcLastOper() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID BSD_ClearLastOper(
+BSD_HAND bsdh )
+{
+ msassert( bsdh != NULL ) ;
+
+ BSD_SwapOper ( bsdh ) ;
+ BSD_ClearCurrOper( bsdh ) ;
+ BSD_SwapOper ( bsdh ) ;
+}
+/**/
+/**
+
+ Name: BSD_ClearCurrOper()
+
+ Description: This function release all resources held by the current
+ operation BSD queue.
+
+
+ Modified: 8/8/1989
+
+ Returns: Error code:
+ BAD_BSD_HAND
+ SUCCESS
+
+ Notes:
+
+ See also: $/SEE( BSD_SaveLastOper(), BSD_ProcLastOper() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID BSD_ClearCurrOper(
+BSD_HAND bsdh )
+{
+ BSD_PTR bsd ;
+
+ msassert( bsdh != NULL ) ;
+
+ bsd = (BSD_PTR)QueueHead( &(bsdh->current_q_hdr) ) ;
+
+ while( bsd != NULL ) {
+
+ BSD_Remove( bsd ) ;
+
+ bsd = (BSD_PTR)QueueHead( &(bsdh->current_q_hdr) ) ;
+ }
+}
+
+/**/
+/**
+
+ Name: BSD_ProcLastOper()
+
+ Description: This function releases any resources held by the current
+ BSD and makes the last oper BSD the current BSD.
+
+
+ Modified: 5/17/1991 14:14:6
+
+ Returns: None
+
+ Notes:
+
+ See also: $/SEE( BSD_SaveLastOper(), BSD_ClearLastOper() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID BSD_ProcLastOper(
+BSD_HAND bsdh )
+{
+ msassert( bsdh != NULL ) ;
+
+ BSD_ClearCurrOper( bsdh ) ;
+ BSD_SwapOper ( bsdh ) ;
+ bsdh->function_code = BSD_ANY_FUNC ;
+
+}
+/**/
+/**
+
+ Name: BSD_ClearDelete()
+
+ Description: This function scans the FSE list and clears the deleted
+ flag on all elements.
+
+ Modified: 5/29/1991 12:56:8
+
+ Returns: None
+
+ Notes:
+
+ See also: $/SEE( BSD_SaveLastOper() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID BSD_ClearDelete( BSD_PTR bsd )
+{
+ FSE_PTR fse ;
+
+ msassert( bsd != NULL ) ;
+
+ fse = (FSE_PTR)QueueHead( &(bsd->fse_q_hdr) );
+
+ while( fse != NULL ) {
+
+ msassert( (BSD_PTR)GetQueueElemPtr( &(fse->q)) == bsd ) ;
+
+ fse->flgs.proced_fse = FALSE ;
+
+ fse = (FSE_PTR)QueueNext( &(fse->q) ) ;
+ }
+
+}
+
+/**/
+/**
+
+ Name: BSD_SwapOper()
+
+ Description: This function swaps the the last oper BSD queue and
+ the BSD current queue.
+
+
+ Modified: 5/29/1991 12:56:25
+
+ Returns: None
+
+ Notes:
+
+ See also: $/SEE( BSD_SaveLastOper(), BSD_ClearLastOper() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID BSD_SwapOper(
+BSD_HAND bsdh )
+{
+ Q_HEADER temp ;
+
+ msassert( bsdh != NULL ) ;
+
+ temp = bsdh->last_q_hdr ;
+
+ bsdh->last_q_hdr = bsdh->current_q_hdr ;
+ bsdh->current_q_hdr = temp ;
+
+}
+
+
+/**/
+/**
+
+ Name: BSD_BeginFunction()
+
+ Description: This funciton clears the BSD list if the old BSD function
+ does not equal the new function
+
+ Modified: 5/17/1991 14:26:59
+
+ Returns: None
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID BSD_BeginFunction(
+BSD_HAND bsdh, /* I - head of the BSD list */
+INT16 function ) /* I - Function to begin */
+{
+ msassert( bsdh != NULL ) ;
+
+ if ( ( bsdh->function_code != function ) && ( bsdh->function_code != BSD_ANY_FUNC ) ) {
+
+ BSD_ClearCurrOper( bsdh ) ;
+ }
+
+ bsdh->function_code = function ;
+}
diff --git a/private/utils/ntbackup/src/bsdmatch.c b/private/utils/ntbackup/src/bsdmatch.c
new file mode 100644
index 000000000..bda5a0c51
--- /dev/null
+++ b/private/utils/ntbackup/src/bsdmatch.c
@@ -0,0 +1,889 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: bsdmatch.c
+
+ Description: This file contains code to match a single file with
+ The FSEs in the BSD list.
+
+
+ $Log: T:/LOGFILES/BSDMATCH.C_V $
+
+ Rev 1.36 11 Feb 1994 16:38:54 GREGG
+Allow for separator character in match buffer allocation.
+
+ Rev 1.35 17 Jan 1994 17:17:20 BARRY
+Got rid of TEXT macros in msasserts
+
+ Rev 1.34 16 Dec 1993 10:20:12 BARRY
+Change INT8_PTRs to VOID_PTRs
+
+ Rev 1.33 06 Dec 1993 11:35:42 BARRY
+Unicode fixes
+
+ Rev 1.32 16 Jul 1993 11:42:00 BARRY
+Changed MatchFname to use allocated memory on really large file names.
+
+ Rev 1.31 15 Jul 1993 10:38:06 BARRY
+Steve's changes to match fred.* with fred
+
+ Rev 1.30 10 Jun 1993 07:48:44 MIKEP
+enable c++
+
+ Rev 1.29 16 Mar 1993 10:57:14 STEVEN
+was munging memory
+
+ Rev 1.28 30 Jan 1993 11:14:40 DON
+Removed compiler warnings
+
+ Rev 1.27 04 Jan 1993 09:39:48 MIKEP
+temporary unicode fix
+
+ Rev 1.26 06 Oct 1992 13:24:06 DAVEV
+Unicode strlen verification
+
+ Rev 1.25 18 Sep 1992 15:21:38 STEVEN
+fix compiler error
+
+ Rev 1.24 17 Sep 1992 11:12:08 STEVEN
+add support for daily backup
+
+ Rev 1.23 30 Jul 1992 19:15:26 STEVEN
+fix bugg a boo
+
+ Rev 1.22 09 Jul 1992 13:59:08 STEVEN
+BE_Unicode updates
+
+ Rev 1.21 26 May 1992 11:24:18 TIMN
+Added text macro of msassert
+
+ Rev 1.20 22 May 1992 14:06:44 STEVEN
+would crash if FSL_EMPTY returned
+
+ Rev 1.19 21 May 1992 09:41:10 STEVEN
+do not match parrent dir if target info is present
+
+ Rev 1.18 13 May 1992 11:39:38 TIMN
+Added TEXT() macro to literals, but not msassert literals
+
+ Rev 1.17 13 May 1992 10:27:16 STEVEN
+changes in attributes
+
+ Rev 1.16 28 Feb 1992 09:22:28 STEVEN
+partial excludes being full excludes
+
+ Rev 1.15 16 Jan 1992 08:44:02 STEVEN
+fix bug for partial dir selection
+
+ Rev 1.14 14 Jan 1992 10:24:06 STEVEN
+fix warnings for WIN32
+
+ Rev 1.13 18 Oct 1991 14:23:04 STEVEN
+BIGWHEEL-fix bug in entire dir support
+
+ Rev 1.12 07 Oct 1991 10:47:34 STEVEN
+was not properly matching directories
+
+ Rev 1.11 23 Aug 1991 17:00:56 STEVEN
+added support for NORMAL/COPY/DIFERENTIAL/INCREMENTAL
+
+ Rev 1.10 24 Jul 1991 09:05:04 DAVIDH
+Corrected compiler warnings under Watcom.
+
+ Rev 1.9 15 Jul 1991 17:17:36 STEVEN
+was not matching root dir
+
+ Rev 1.8 02 Jul 1991 11:01:10 STEVEN
+FnameMatch was borken
+
+ Rev 1.7 02 Jul 1991 09:54:24 STEVEN
+fix date stuff
+
+ Rev 1.6 21 Jun 1991 15:58:52 STEVEN
+compairing invalid dates
+
+ Rev 1.5 21 Jun 1991 08:40:54 STEVEN
+new config unit
+
+ Rev 1.4 20 Jun 1991 10:59:00 STEVEN
+modifications for matching directories
+
+ Rev 1.3 13 Jun 1991 10:17:32 STEVEN
+Match code was looking at DLE which could be NULL
+
+ Rev 1.2 12 Jun 1991 16:03:30 STEVEN
+BSDU code review
+
+ Rev 1.1 29 May 1991 17:21:24 STEVEN
+Re-Design of BSDU for New Fast File Restore
+
+ Rev 1.0 09 May 1991 13:36:46 HUNTER
+Initial revision.
+
+**/
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+
+#include "msassert.h"
+
+#include "tfldefs.h"
+#include "beconfig.h"
+#include "fsys.h"
+#include "fsys_err.h"
+#include "bsdu.h"
+
+#define BSD_PROCESS_PARENT 10
+
+static BOOLEAN FSE_ListIsEmpty( BSD_PTR bsd ) ;
+
+static INT16 MatchSelectData( CHAR_PTR fname,
+ CHAR_PTR path,
+ INT16 psize,
+ UINT32 attrib,
+ DATE_TIME_PTR date,
+ DATE_TIME_PTR adate,
+ DATE_TIME_PTR bdate,
+ BOOLEAN del_flag,
+ BOOLEAN disp_flag,
+ FSE_PTR fse1,
+ BOOLEAN *entireable ) ;
+
+static BOOLEAN BSD_MatchForParent(
+ BSD_PTR bsd,
+ FSE_PTR fse,
+ CHAR_PTR ipath,
+ INT16 isize ) ;
+
+static INT16 MatchFname(
+ CHAR_PTR name1, /* I - file name (with wildcards) */
+ CHAR_PTR name2 ); /* I - file name (without wildcards ) */
+
+/**/
+/**
+
+ Name: BSD_MatchFile()
+
+ Description: This function returns SUCCESS if a specified file is
+ included by a BSD. All FSEs in the BSD are compared agains a
+ DDB and a FDB pair. A pointer to the last FSE which includes
+ this file is also returned.
+
+
+ Modified: 5/17/1991 15:59:9
+
+ Returns: FSE_EMPTY
+ BSD_SKIP_OBJECT
+ BSD_PROCESS_OBJECT
+ BSD_PROCESS_ELEMENTS
+
+ Notes: If the DBLK is a single block (i.e. no associated FDB)
+ then the DBLK should be passed as the DDB parameter.
+
+ For DDBs we will look for the most powerfull FSE which matches.
+ If Target names exist then we will check for TARGET FSES
+
+ See also: $/SEE( FS_DBLKMatch() )$
+
+ Declaration:
+
+**/
+INT16 BSD_MatchObj(
+BSD_PTR bsd, /* I - BSD to scan for matching FSE */
+FSE_PTR *fse, /* O - Last matching INCLUDE FSE in list */
+FSYS_HAND fsh, /* I - File system Handle needed to call FS */
+DBLK_PTR ddb, /* I - DBLK to match DDB, IDB, UDB or other */
+DBLK_PTR fdb, /* I - File Descriptor Block if ddb is DDB */
+BOOLEAN disp_flag ) /* I - True if Parent directories match */
+{
+ INT16 ret_val = BSD_SKIP_OBJECT ;
+ CHAR_PTR temp_buf = bsd->match_buffer ;
+ CHAR_PTR path = NULL ;
+ CHAR_PTR fname = NULL;
+ INT16 cb_size; //string buffer size in bytes incl NULL term
+ DATE_TIME date ;
+ DATE_TIME a_date ;
+ UINT32 attrib = 0;
+ INT16 spec_file ;
+ INT16 cb_alloc_size ; //string buffer size in bytes incl NULL term
+
+ *fse = NULL ;
+ date.date_valid = FALSE ;
+
+ switch( FS_GetBlockType( ddb ) ) {
+
+ case UDB_ID:
+ ret_val = BSD_SKIP_OBJECT ;
+ break;
+
+ case CFDB_ID:
+ case IDB_ID:
+ ret_val = BSD_PROCESS_OBJECT ;
+ break ;
+
+ case DDB_ID:
+
+ spec_file = FS_SpecExcludeObj ( fsh, ddb, fdb ) ;
+
+ if ( spec_file == FS_EXCLUDE_FILE ) {
+ ret_val = BSD_SKIP_OBJECT ;
+
+ } else if ( spec_file == FS_SPECIAL_FILE ) {
+ ret_val = BSD_SPECIAL_OBJECT ;
+
+ } else {
+
+
+ cb_alloc_size = cb_size = FS_SizeofOSPathInDDB( fsh, ddb ) ;
+ cb_alloc_size += sizeof( CHAR ) ;
+
+ if ( fdb != NULL ) {
+ msassert( FS_GetBlockType(fdb) == FDB_ID ) ;
+
+ cb_alloc_size += FS_SizeofOSFnameInFDB( fsh, fdb ) ;
+
+ }
+
+ if ( cb_alloc_size > bsd->match_buffer_size ) {
+ bsd->match_buffer_size = (UINT16)(cb_alloc_size + (64 * sizeof(CHAR)) ) ;
+ bsd->match_buffer = realloc( bsd->match_buffer, bsd->match_buffer_size ) ;
+ temp_buf = bsd->match_buffer ;
+ }
+
+ if ( temp_buf == NULL ) {
+ return OUT_OF_MEMORY ;
+ }
+
+ path = temp_buf ;
+
+ FS_GetOSPathFromDDB( fsh, ddb, path ) ;
+
+ if ( fdb !=NULL ) {
+
+ fname = path + cb_size / sizeof (CHAR) ;
+
+ FS_GetOSFnameFromFDB( fsh, fdb, fname ) ;
+
+ attrib = FS_GetAttribFromDBLK( fsh, fdb ) ;
+
+ FS_GetMDateFromDBLK( fsh, fdb, &date ) ;
+ FS_GetADateFromDBLK( fsh, fdb, &a_date ) ;
+ }
+
+ ret_val = BSD_MatchPathAndFile( bsd, fse, fname, path,
+ cb_size, attrib, &date, &a_date, NULL, FALSE,
+ disp_flag ) ;
+
+
+ if ( (*fse != NULL) &&
+ BSD_MatchForParent( bsd, *fse, path, cb_size ) &&
+ ( (*fse)->tgt != NULL ) ) {
+
+ ret_val = BSD_SKIP_OBJECT ;
+ }
+
+ if ( ( ret_val == BSD_SKIP_OBJECT ) &&
+ ( spec_file == FS_SPECIAL_DIR ) ) {
+
+ ret_val = BSD_SPECIAL_OBJECT ;
+
+ }
+
+ if ( ( fdb == NULL ) && ( ret_val != BSD_SKIP_OBJECT) ) {
+
+ if ( BSD_GetProcElemOnlyFlg( bsd ) || !FS_ProcessDDB( fsh, ddb ) ) {
+ ret_val = BSD_PROCESS_ELEMENTS ;
+ }
+ }
+ }
+
+ break;
+
+ default:
+ msassert( ("INVALID BLOCK type", 0) ) ;
+ break;
+
+ }
+
+ return ret_val ;
+}
+
+/**/
+/**
+
+ Name: BSD_MatchPathAndFile()
+
+ Description: This function scans through the FSE list looking
+ for a match with the provided data. The scan is from tail
+ to head. The return value specifies how the data should be
+ handled.
+
+
+ Modified: 5/17/1991 16:12:49
+
+ Returns: FSE_EMPTY
+ BSD_SKIP_OBJECT
+ BSD_PROCESS_OBJECT
+
+ Notes: If the the caller wishes to match the directory only
+ then the file name input parameter should be NULL.
+
+ See also: $/SEE( BSD_MatchObj() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 BSD_MatchPathAndFile(
+BSD_PTR bsd, /* I - BSD to scan for matching FSE */
+FSE_PTR *fse, /* O - Last matching INCLUDE FSE in list */
+CHAR_PTR fname, /* I - file name to match */
+CHAR_PTR path, /* I - path name to match - generic format */
+INT16 psize, /* I - size of path string */
+UINT32 attr, /* I - attribute to match - generic format */
+DATE_TIME_PTR date, /* I - date to match - generic format */
+DATE_TIME_PTR a_date, /* I - date of last access */
+DATE_TIME_PTR b_date, /* I - date of last backup */
+BOOLEAN del_flag, /* I - True if the object has been deleted */
+BOOLEAN disp_flag ) /* I - True if Parent directories should match */
+{
+ FSE_PTR fse1 ;
+ INT16 ret_val = BSD_SKIP_OBJECT ;
+ INT16 match ;
+ INT16 looking_for_more = FALSE ;
+ BOOLEAN entireable = TRUE ;
+
+ *fse = NULL;
+
+ fse1 = BSD_GetLastFSE( bsd ) ;
+
+ while ( fse1 != NULL ) {
+
+ if ( !FSE_GetDeleteMark( fse1 ) ) {
+
+ match = MatchSelectData( fname, path, psize, attr, date,
+ a_date, b_date, del_flag, disp_flag, fse1, &entireable ) ;
+
+ if ( match != BSD_SKIP_OBJECT ) {
+
+ if( FSE_GetOperType( fse1 ) == INCLUDE ) {
+
+ if ( !looking_for_more ) {
+ *fse = fse1 ;
+ }
+
+ if ( match == BSD_PROCESS_PARENT ) {
+ looking_for_more = TRUE ;
+ ret_val = BSD_PROCESS_OBJECT ;
+
+ } else {
+
+ ret_val = BSD_PROCESS_OBJECT ;
+
+ if ( (fname == NULL) && disp_flag &&
+ (fse1->flgs.select_type != ENTIRE_DIR_SELECTION) ) {
+ looking_for_more = TRUE ;
+
+ } else {
+
+ *fse = fse1 ;
+ if ( entireable && disp_flag &&
+ (fname == NULL) &&
+ (fse1->flgs.select_type == ENTIRE_DIR_SELECTION) ) {
+
+ ret_val = BSD_PROCESS_ENTIRE_DIR ;
+ }
+ break ;
+ }
+ }
+
+ } else {
+ if ( !looking_for_more ) {
+ *fse = NULL ;
+ }
+ break ;
+ }
+ }
+ }
+
+ fse1 = BSD_GetPrevFSE( fse1 ) ;
+
+ }
+ if ( *fse == NULL ) {
+ if ( FSE_ListIsEmpty( bsd ) ) {
+ ret_val = FSL_EMPTY ;
+
+ } else {
+ ret_val = BSD_SKIP_OBJECT ;
+ }
+ }
+
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Name: FSE_ListIsEmpty()
+
+ Description: This function returns TRUE if the FSE list is empty.
+
+ Modified: 5/20/1991 9:5:6
+
+ Returns: TRUE if list is empty
+
+ See also: $/SEE( BSD_MatcjObj() NSD_MatchPathAndFile() )$
+
+**/
+/* begin declaration */
+static BOOLEAN FSE_ListIsEmpty(
+BSD_PTR bsd )
+{
+ FSE_PTR fse ;
+
+ fse = BSD_GetFirstFSE( bsd ) ;
+
+ while( fse != NULL ) {
+
+ if ( !FSE_GetDeleteMark( fse ) && ( FSE_GetOperType( fse ) == INCLUDE ) ) {
+ return FALSE ;
+ }
+
+ fse = BSD_GetNextFSE( fse ) ;
+ }
+
+ return TRUE ;
+}
+
+/**/
+/**
+
+ Name: MatchSelectData()
+
+ Description: This function matches an FSE with a file name, path, attribute, and
+ modify date.
+
+ Modified: 9/21/1989
+
+ Returns: BSD_SKIP_OBJECT or BSD_PROCESS_OBJECT ;
+
+ Notes:
+
+ See also: $/SEE( BSD_MatcjObj() NSD_MatchPathAndFile() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+static INT16 MatchSelectData(
+CHAR_PTR ofname, /* I - file name to match */
+CHAR_PTR opath, /* I - path name to match */
+INT16 opsize, /* I - size of above path */
+UINT32 attrib, /* I - attribute to match */
+DATE_TIME_PTR odate, /* I - date to match */
+DATE_TIME_PTR adate, /* I - access date to match */
+DATE_TIME_PTR bdate, /* I - backup date to match */
+BOOLEAN del_flag, /* I - True if object is deleted */
+BOOLEAN disp_flag, /* I - True if match parrent dir requested */
+FSE_PTR fse, /* I - The fse to compare against */
+BOOLEAN *entireable ) /* O - Set to false if we run into an exclude */
+{
+ INT16 ret_val = FAILURE ;
+ BOOLEAN path_match = FALSE ;
+ BOOLEAN name_match = FALSE ;
+ CHAR_PTR fname;
+ CHAR_PTR path ;
+ INT16 cb_psize ;
+ DATE_TIME_PTR date_pre ;
+ DATE_TIME_PTR date_post ;
+ DATE_TIME today_date ;
+ UINT32 a_on ;
+ UINT32 a_off ;
+ BE_CFG_PTR cfg ;
+ BSD_PTR bsd ;
+
+ /* reference parameter to prevent compiler warnings */
+ (VOID) disp_flag ;
+
+ bsd = (BSD_PTR)GetQueueElemPtr( &(fse->q) ) ;
+ cfg = bsd->cfg ;
+/*
+** match the directory
+*/
+
+ FSE_GetPath( fse, &path, &cb_psize ) ;
+
+ if ( ( cb_psize > opsize ) &&
+ ( ofname == NULL ) &&
+ ( FSE_GetOperType( fse ) == INCLUDE ) &&
+ ( ( opsize == sizeof (CHAR) ) || !memicmp( path, opath, opsize ) ) ) {
+
+
+ return BSD_PROCESS_PARENT ;
+
+
+ } else if ( ( cb_psize >=opsize ) &&
+ ( FSE_GetOperType( fse ) == EXCLUDE ) &&
+ ( ( opsize == sizeof (CHAR) ) || !memicmp( path, opath, opsize ) ) ) {
+
+ *entireable = FALSE ;
+
+ }
+
+ if ( (cb_psize == sizeof (CHAR) ) && FSE_GetIncSubFlag( fse ) ) {
+ path_match = TRUE ;
+
+ } else if ( (cb_psize == opsize) && !memicmp( path, opath, cb_psize ) ) {
+ path_match = TRUE ;
+
+ } else if ( (cb_psize < opsize) && FSE_GetIncSubFlag( fse ) &&
+ !memicmp( path, opath, cb_psize ) ) {
+
+ path_match = TRUE ;
+
+ }
+
+ if( path_match ) {
+
+ ret_val = SUCCESS ;
+
+ fname = FSE_GetFname( fse ) ;
+
+ if ( ofname == NULL ) { /* just matching the directory */
+
+ if ( FSE_GetOperType( fse ) == EXCLUDE ) {
+ ret_val = FAILURE ;
+
+ if ( FSE_GetIncSubFlag( fse ) && ( cb_psize <= opsize ) ) {
+ *entireable = FALSE ;
+
+ if ( !strcmp( fname, ALL_FILES ) && FSE_GetWildFlag( fse ) &&
+ ( fse->cplx == NULL ) ) {
+ ret_val = SUCCESS ;
+ }
+ }
+ }
+
+ } else {
+/*
+** match the file
+*/
+ if ( FSE_GetWildFlag( fse ) ) {
+ if ( !MatchFname( fname, ofname ) ) { /* success if match */
+ name_match = TRUE ;
+ }
+ } else {
+ if ( !stricmp( fname, ofname ) ) {
+ name_match = TRUE ;
+ }
+ }
+
+ if ( !name_match ) {
+ ret_val = FAILURE ;
+
+ } else if ( del_flag && (fse->flgs.del_files == NON_DELETED_FILES_ONLY) ) {
+ ret_val = FAILURE ;
+
+ } else if ( !del_flag && (fse->flgs.del_files == DELETED_FILES_ONLY) ) {
+ ret_val = FAILURE ;
+
+ } else if ( fse->flgs.select_type != SINGLE_FILE_SELECTION ) {
+
+ /* ... if NOT processing hidden files AND it is hidden then return */
+
+ if( ( !BEC_GetHiddenFlag( cfg ) ) && ( attrib & OBJ_HIDDEN_BIT ) ) {
+
+ ret_val = FAILURE ;
+ }
+
+ if( !BEC_GetSpecialFlag( cfg ) &&
+ ( ( attrib & OBJ_READONLY_BIT) || ( attrib & OBJ_SYSTEM_BIT) ) ) {
+
+ ret_val = FAILURE ;
+ }
+ }
+
+
+ if ( ret_val != SUCCESS ) {
+ ret_val = FAILURE ; /* redundant but reads better */
+
+ } else if ( (fse->cplx == NULL) &&
+ (BSD_CompatibleBackup(bsd) || !BSD_ModFilesOnly(bsd)) ) {
+
+ ret_val = SUCCESS ;
+
+ if ( BSD_GetBackupType( bsd ) == BSD_BACKUP_DAILY ) {
+
+ today_date = bsd->sort_date ;
+ today_date.hour = 0 ;
+ today_date.minute = 0 ;
+ today_date.second = 0 ;
+
+ if ( CompDate( odate, &today_date ) < 0 ) {
+ ret_val = FAILURE ;
+ }
+ }
+
+ } else {
+
+ if ( BSD_GetBackupType( bsd ) != BSD_BACKUP_DAILY ) {
+
+ FSE_GetModDate( fse, &date_pre, &date_post ) ;
+
+ if ( date_pre != NULL ) {
+
+ if ( CompDate( odate, date_pre ) < 0 ) {
+ ret_val = FAILURE ;
+ }
+ }
+
+ if ( date_post != NULL ) {
+ if ( CompDate( odate, date_post ) > 0 ) {
+ ret_val = FAILURE ;
+ }
+ }
+ }
+
+ FSE_GetAccDate( fse, &date_pre ) ;
+
+ if ( date_pre != NULL ) {
+
+ /* if no access date specified then do not match */
+ if ( ( adate == NULL ) || ( !adate->date_valid ) ) {
+ ret_val = FAILURE ;
+
+ } else if ( CompDate( adate, date_pre ) > 0 ) {
+ ret_val = FAILURE ;
+ }
+ }
+
+
+ FSE_GetBakDate( fse, &date_pre ) ;
+
+ if ( date_pre != NULL ) {
+
+ /* if no backup date specified then do not compare dates */
+ if ( ( bdate != NULL ) && ( bdate->date_valid ) ) {
+ if ( CompDate( bdate, date_pre ) != 0 ) {
+ ret_val = FAILURE ;
+ }
+ }
+ }
+
+ FSE_GetAttribInfo( fse, &a_on, &a_off ) ;
+
+ if ( !BSD_CompatibleBackup( bsd ) &&
+ BSD_ModFilesOnly( bsd ) ) {
+
+ a_on |= OBJ_MODIFIED_BIT ;
+ }
+ if( (attrib & a_on) != a_on ) {
+
+ ret_val = FAILURE ;
+ }
+
+ if( ((~attrib) & a_off) != a_off ) {
+ ret_val = FAILURE ;
+ }
+
+ }
+
+ }
+ }
+
+ if ( ret_val == SUCCESS ) {
+ ret_val = BSD_PROCESS_OBJECT;
+ } else {
+ ret_val = BSD_SKIP_OBJECT ;
+ }
+
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Name: MatchName()
+
+ Description: This function matches a wildcard file name with
+ a normal (non wildcard) file name.
+
+ Modified: 8/2/1989
+
+ Returns: SUCCESS if names are the same. Otherwise FAILURE
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+static INT16 MatchFname(
+CHAR_PTR wild_name, /* I - file name (with wildcards) */
+CHAR_PTR file_name ) /* I - file name (without wildcards ) */
+{
+ INT16 pos ; /* index for file_name */
+ INT16 i ; /* index for wild_name */
+ INT16 ret_val = SUCCESS;
+ CHAR_PTR p ;
+ CHAR save_char ;
+ INT16 ptrn_len ;
+ CHAR sname_buff[256]; /* static temp name buffer */
+ CHAR_PTR aname_buff = NULL; /* allocated temp name buffer */
+ CHAR_PTR temp_fname; /* pointer to one of the above */
+
+ pos = 0 ;
+
+ if( strcmp( wild_name, ALL_FILES ) ) {
+
+ BOOLEAN try_with_dot = FALSE ;
+
+ do {
+
+ if ( try_with_dot ) {
+
+ /*
+ * Size of name_buff minus a null, minus a dot for the
+ * "try_with_dot" code below. If the name is longer than the
+ * static buffer, allocate one from the heap.
+ */
+ if ( (strsize(file_name) + sizeof(CHAR)) > sizeof(sname_buff) )
+ {
+ aname_buff = malloc( strsize( file_name ) +
+ sizeof( CHAR ) );
+ temp_fname = aname_buff;
+ }
+ else
+ {
+ temp_fname = sname_buff;
+ }
+
+ if ( temp_fname != NULL ) {
+ strcpy( temp_fname, file_name ) ;
+ strcat( temp_fname, TEXT(".") ) ;
+ file_name = temp_fname ;
+ pos = 0 ;
+ ret_val = SUCCESS ;
+ }
+ try_with_dot = FALSE ;
+
+ } else if ( strchr( file_name, TEXT('.') ) == NULL ) {
+ try_with_dot = TRUE ;
+ }
+
+ for( i = 0; (wild_name[i] != 0) && (ret_val == SUCCESS) ; i++ ) {
+
+ switch( wild_name[i] ) {
+
+ case TEXT('*'):
+
+ while( wild_name[i+1] != TEXT('\0') ) {
+
+ if ( wild_name[i+1] == TEXT('?') ) {
+ if ( file_name[ ++pos ] == TEXT('\0') ) {
+ break ;
+ }
+
+ } else if ( wild_name[i+1] != TEXT('*') ) {
+ break ;
+ }
+ i++ ;
+ }
+
+ p = strpbrk( &wild_name[i+1], TEXT("*?") ) ;
+
+ if ( p != NULL ) {
+ save_char = *p ;
+ *p = TEXT('\0') ;
+
+ ptrn_len = (INT16)strlen( &wild_name[i+1] ) ;
+
+ while ( file_name[pos] &&
+ strnicmp( &file_name[pos], &wild_name[i+1], ptrn_len ) ) {
+ pos++;
+ }
+
+ i += ptrn_len ;
+
+ *p = save_char ;
+
+ if ( file_name[pos] == TEXT('\0') ) {
+ ret_val = FAILURE ;
+ } else {
+ pos++ ;
+ }
+ } else {
+ if (wild_name[i+1] == TEXT('\0') ) {
+ pos = (INT16)strlen( file_name ) ;
+ break ;
+ } else {
+ p = strchr( &file_name[pos], wild_name[i+1] ) ;
+ if ( p != NULL ) {
+ pos += p - &file_name[pos];
+ } else {
+ ret_val = FAILURE ;
+ }
+ }
+ }
+ break;
+
+ case TEXT('?') :
+ if ( file_name[pos] != TEXT('\0') ) {
+ pos++ ;
+ }
+ break;
+
+ default:
+ if( ( file_name[pos] == TEXT('\0') ) || ( toupper(file_name[pos]) != toupper(wild_name[i]) ) ){
+ ret_val = FAILURE;
+ } else {
+ pos++ ;
+ }
+ }
+ }
+
+ if ( file_name[pos] != TEXT('\0') ) {
+ ret_val = FAILURE ;
+ }
+
+ } while( (ret_val == FAILURE) && (try_with_dot) ) ;
+ }
+
+ if ( aname_buff != NULL ) {
+ free( aname_buff );
+ }
+ return( ret_val ) ;
+}
+static BOOLEAN BSD_MatchForParent(
+ BSD_PTR bsd,
+ FSE_PTR fse,
+ CHAR_PTR ipath,
+ INT16 isize ) //size of path buffer in bytes incl NULL term
+{
+ CHAR_PTR path ;
+ INT16 cb_psize ; //size of path buffer in bytes incl NULL term
+
+/*
+** match the directory
+*/
+
+ FSE_GetPath( fse, &path, &cb_psize ) ;
+
+ if ( ( cb_psize > isize ) &&
+ ( FSE_GetOperType( fse ) == INCLUDE ) &&
+ ( ( isize == sizeof (CHAR) ) || !memicmp( path, ipath, isize ) ) ) {
+
+ return TRUE ;
+ }
+
+ return FALSE ;
+ (VOID)bsd;
+}
diff --git a/private/utils/ntbackup/src/bsdsinfo.c b/private/utils/ntbackup/src/bsdsinfo.c
new file mode 100644
index 000000000..675b99a5c
--- /dev/null
+++ b/private/utils/ntbackup/src/bsdsinfo.c
@@ -0,0 +1,417 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: bsdsinfo.c
+
+ Description: This file contains a "bunch" of functions used
+ to initialize the fields of a BSD.
+
+
+ $Log: O:/LOGFILES/BSDSINFO.C_V $
+
+ Rev 1.4 14 May 1992 08:57:26 TIMN
+Converted CHAR byte data types to INT8.
+
+ Rev 1.3 13 May 1992 19:12:40 TIMN
+Added size parameter for tape,vol and backup label functions.
+Added size parameter for userName function
+Converted strcpy calls to memcpy calls
+
+ Rev 1.2 08 May 1992 16:24:20 STEVEN
+added volume label to BSD
+
+ Rev 1.1 29 May 1991 17:21:04 STEVEN
+Re-Design of BSDU for New Fast File Restore
+
+ Rev 1.0 09 May 1991 13:36:50 HUNTER
+Initial revision.
+
+**/
+#include <malloc.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+
+#include "bsdu.h"
+#include "msassert.h"
+
+/**/
+/**
+
+ Name: BSD_SetTapeLabel()
+
+ Description: This function allocates memory for the tape
+ label and coppies the passed label into this memory. This
+ memory is then pointed to by the bsd ;
+
+ Modified: 5/17/1991 14:58:19
+
+ Returns: Error Codes:
+ OUT_OF_MEMORY
+ SUCCESS
+
+ Notes: If the bsd pointer passed in is garbage then memory
+ will be "klobered".
+
+ See also: $/SEE( BSD_SetBackupLabel() )$
+
+ Declaration:
+
+**/
+INT16 BSD_SetTapeLabel(
+BSD_PTR bsd, /* I - BSD to modify */
+INT8_PTR label, /* I - string to place in BSD */
+INT16 size ) /* I - size of label */
+{
+ INT8_PTR name ;
+ INT16 ret_val ;
+
+ msassert( bsd != NULL );
+
+ name = (INT8_PTR) malloc( size ) ;
+
+ if ( name != NULL ) {
+ free( bsd->tape_label ) ;
+
+ memcpy( name, label, size ) ;
+ bsd->tape_label = name ;
+ bsd->tape_label_size = size ;
+ ret_val = SUCCESS ;
+
+ } else {
+
+ ret_val = OUT_OF_MEMORY ;
+ }
+
+ return( ret_val ) ;
+}
+/**/
+/**
+
+ Name: BSD_SetVolumeLabel()
+
+ Description: This function allocates memory for the tape
+ label and coppies the passed label into this memory. This
+ memory is then pointed to by the bsd ;
+
+ Modified: 5/17/1991 14:58:19
+
+ Returns: Error Codes:
+ OUT_OF_MEMORY
+ SUCCESS
+
+ Notes: If the bsd pointer passed in is garbage then memory
+ will be "klobered".
+
+ See also: $/SEE( BSD_SetBackupLabel() )$
+
+ Declaration:
+
+**/
+INT16 BSD_SetVolumeLabel(
+BSD_PTR bsd, /* I - BSD to modify */
+INT8_PTR label, /* I - string to place in BSD */
+INT16 size ) /* I - size of label */
+{
+ INT8_PTR name ;
+ INT16 ret_val ;
+
+ msassert( bsd != NULL );
+
+ name = (INT8_PTR) malloc( size ) ;
+
+ if ( name != NULL ) {
+ free( bsd->vol_label ) ;
+
+ memcpy( name, label, size ) ;
+ bsd->vol_label = name ;
+ bsd->vol_label_size = size ;
+ ret_val = SUCCESS ;
+
+ } else {
+
+ ret_val = OUT_OF_MEMORY ;
+ }
+
+ return( ret_val ) ;
+}
+/**/
+/**
+
+ Name: BSD_SetBackupLabel()
+
+ Description: This function allocates memory for the backup set
+ label and coppies the passed label into this memory. This
+ memory is then pointed to by the bsd ;
+
+ Modified: 5/17/1991 14:58:25
+
+ Returns: Error Codes:
+ OUT_OF_MEMORY
+ SUCCESS
+
+ Notes: If the bsd pointer passed in is garbage then memory
+ will be "klobered".
+
+ See also: $/SEE( BSD_SetBackupLabel() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 BSD_SetBackupLabel(
+BSD_PTR bsd, /* I - BSD to modify */
+INT8_PTR label, /* I - string to place in BSD */
+INT16 size ) /* I - size of label */
+{
+ INT8_PTR name ;
+ INT16 ret_val ;
+
+ name = (INT8_PTR) malloc( size ) ;
+
+ if ( name != NULL ) {
+
+ free( bsd->set_label ) ;
+ memcpy( name, label, size ) ;
+ bsd->set_label = name ;
+ bsd->set_label_size = size ;
+ ret_val = SUCCESS ;
+
+ } else {
+
+ ret_val = OUT_OF_MEMORY ;
+ }
+
+ return( ret_val ) ;
+}
+/**/
+/**
+
+ Name: BSD_SetBackupDescript()
+
+ Description: This function allocates memory for the backup set
+ description and coppies the passed descriptoin into this memory.
+ This memory is then pointed to by the bsd ;
+
+ Modified: 5/17/1991 14:58:31
+
+ Returns: Error Codes:
+ OUT_OF_MEMORY
+ SUCCESS
+
+ Notes: If the bsd pointer passed in is garbage then memory
+ will be "klobered".
+
+ See also: $/SEE( BSD_SetBackupLabel() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 BSD_SetBackupDescript(
+BSD_PTR bsd, /* I - BSD to modify */
+INT8_PTR descript, /* I - string to place in BSD */
+INT16 size ) /* I - size of label */
+{
+ INT8_PTR name ;
+ INT16 ret_val ;
+
+ name = (INT8_PTR) malloc( size ) ;
+
+ if ( name != NULL ) {
+
+ free( bsd->set_descript ) ;
+ memcpy( name, descript, size ) ;
+ bsd->set_descript = name ;
+ bsd->set_descript_size = size ;
+ ret_val = SUCCESS ;
+
+ } else {
+
+ ret_val = OUT_OF_MEMORY ;
+ }
+
+ return( ret_val ) ;
+}
+/**/
+/**
+
+ Name: BSD_SetTapePswd()
+
+ Description: This function allocates memory for the tape password
+ and coppies the passed password into this memory.
+ This memory is then pointed to by the bsd ;
+
+ Modified: 5/17/1991 14:58:36
+
+ Returns: Error Codes:
+ OUT_OF_MEMORY
+ SUCCESS
+
+ Notes: If the bsd pointer passed in is garbage then memory
+ will be "klobered".
+
+ See also: $/SEE( BSD_SetBackupLabel() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 BSD_SetTapePswd(
+BSD_PTR bsd, /* I - BSD to modify */
+INT8_PTR pswd, /* I - string to place in BSD */
+INT16 leng ) /* I - size of passowrd */
+{
+ INT8_PTR name ;
+ INT16 ret_val ;
+
+ name = (INT8_PTR) malloc( leng ) ;
+
+ if ( name != NULL ) {
+
+ free( bsd->tape_pswd ) ;
+ memcpy( name, pswd, leng ) ;
+ bsd->tape_pswd = name ;
+ bsd->tape_pswd_size = leng ;
+ ret_val = SUCCESS ;
+
+ } else {
+
+ ret_val = OUT_OF_MEMORY ;
+ }
+
+ return( ret_val ) ;
+}
+/**/
+/**
+
+ Name: BSD_SetBackupPswd()
+
+ Description: This function allocates memory for the backp set
+ password and coppies the passed password into this memory.
+ This memory is then pointed to by the bsd ;
+
+ Modified: 5/17/1991 14:58:41
+
+ Returns: Error Codes:
+ OUT_OF_MEMORY
+ SUCCESS
+
+ Notes: If the bsd pointer passed in is garbage then memory
+ will be "klobered".
+
+ See also: $/SEE( BSD_SetBackupLabel() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 BSD_SetBackupPswd(
+BSD_PTR bsd, /* I - BSD to modify */
+INT8_PTR pswd, /* I - string to place in BSD */
+INT16 leng ) /* I - size of set password */
+{
+ INT8_PTR name ;
+ INT16 ret_val ;
+
+ name = (INT8_PTR) malloc( leng ) ;
+
+ if ( name != NULL ) {
+
+ free( bsd->set_pswd ) ;
+ memcpy( name, pswd, leng ) ;
+ bsd->set_pswd = name ;
+ bsd->set_pswd_size = leng ;
+ ret_val = SUCCESS ;
+
+ } else {
+
+ ret_val = OUT_OF_MEMORY ;
+ }
+
+ return( ret_val ) ;
+}
+/**/
+/**
+
+ Name: BSD_SetUserName()
+
+ Description: This function allocates memory for the user name
+ and coppies the passed name into this memory.
+ This memory is then pointed to by the bsd ;
+
+ Modified: 5/17/1991 14:58:45
+
+ Returns: Error Codes:
+ OUT_OF_MEMORY
+ SUCCESS
+
+ Notes: If the bsd pointer passed in is garbage then memory
+ will be "klobered".
+
+ See also: $/SEE( BSD_SetBackupLabel() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 BSD_SetUserName(
+BSD_PTR bsd, /* I - BSD to modify */
+INT8_PTR user_name, /* I - string to place in BSD */
+INT16 size ) /* I - size of user name */
+{
+ INT8_PTR name ;
+ INT16 ret_val ;
+
+ name = (INT8_PTR) malloc( size ) ;
+
+ if ( name != NULL ) {
+
+ free( bsd->user_name ) ;
+ memcpy( name, user_name, size ) ;
+ bsd->user_name = name ;
+ bsd->user_name_size = size ;
+ ret_val = SUCCESS ;
+
+ } else {
+
+ ret_val = OUT_OF_MEMORY ;
+ }
+
+ return( ret_val ) ;
+}
+/**/
+/**
+
+ Name: BSD_SetTapePos()
+
+ Description: This function initilizes the tape id, tape number,
+ and set number fields in the BSD
+
+ Modified: 5/17/1991 14:58:50
+
+ Returns: none
+
+ Notes: If the bsd pointer passed in is garbage then memory
+ will be "klobered".
+
+ See also: $/SEE( BSD_SetTapeLabel() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID BSD_SetTapePos(
+BSD_PTR bsd, /* I - BSD to modify */
+UINT32 tape_id, /* I - tape ID to place in BSD */
+UINT16 tape_num, /* I - tape number to place in BSD */
+UINT16 set_num ) /* I - set number to place in BSD */
+{
+ bsd->tape_id = tape_id ;
+ bsd->tape_num = tape_num ;
+ bsd->set_num = set_num ;
+}
+
+
diff --git a/private/utils/ntbackup/src/bsdthw.c b/private/utils/ntbackup/src/bsdthw.c
new file mode 100644
index 000000000..4478abe1b
--- /dev/null
+++ b/private/utils/ntbackup/src/bsdthw.c
@@ -0,0 +1,93 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: bsdthw.c
+
+ Description: This file contains a functions used
+ to reference the hardware specific aspects of a BSD.
+
+
+ $Log: Q:/LOGFILES/BSDTHW.C_V $
+
+ Rev 1.1 18 Jun 1993 09:11:26 MIKEP
+enable C++
+
+ Rev 1.0 19 Sep 1991 11:02:54 STEVEN
+Initial revision.
+
+**/
+#include "stdtypes.h"
+
+#include "bsdu.h"
+#include "thw.h"
+
+/**/
+/**
+
+ Name: BSD_HardwareSupportsFeature()
+
+ Description: This function dtermine if the feature specified is supported by one or more drives in the
+ in the hardware list.
+
+ Modified: 6/3/91
+
+ Returns: TRUE - feature supported somewhere in the channel
+ FALSE - feature not supported at all in the channel
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+BOOLEAN BSD_HardwareSupportsFeature(
+BSD_PTR bsd , /* I - BSD of inquiry */
+UINT32 feature ) /* I - feature */
+{
+ BOOLEAN ret_val = FALSE ;
+ THW_PTR drive ;
+ THW_PTR other ;
+
+ /* dtermine the current drive */
+ drive = BSD_GetTHW( bsd ) ;
+
+ /* see if the current drive supports the feature */
+ if( drive->drv_info.drv_features & feature ) {
+ ret_val = TRUE ;
+ }
+
+ if( !ret_val ) {
+
+ /* start looking with the current drive */
+ other = drive ;
+
+ /* see if any subsequent drives linked in the channel support the feature */
+ while( !ret_val && other->channel_link.q_next ) {
+
+ other = ( THW_PTR )( ( other->channel_link.q_next )->q_ptr ) ;
+
+ if( other->drv_info.drv_features & feature ) {
+ ret_val = TRUE ;
+ }
+ }
+ }
+
+ if( !ret_val ) {
+
+ /* start looking with the current drive */
+ other = drive ;
+
+ /* see if any previous drives linked in the channel support the feature */
+ while( !ret_val && other->channel_link.q_prev ) {
+
+ other = ( THW_PTR )( ( other->channel_link.q_prev )->q_ptr ) ;
+
+ if( other->drv_info.drv_features & feature ) {
+ ret_val = TRUE ;
+ }
+ }
+ }
+
+ return( ret_val ) ;
+
+}
diff --git a/private/utils/ntbackup/src/bset.bmp b/private/utils/ntbackup/src/bset.bmp
new file mode 100644
index 000000000..39f713415
--- /dev/null
+++ b/private/utils/ntbackup/src/bset.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/bsetpart.bmp b/private/utils/ntbackup/src/bsetpart.bmp
new file mode 100644
index 000000000..c1742f27a
--- /dev/null
+++ b/private/utils/ntbackup/src/bsetpart.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/buffman.c b/private/utils/ntbackup/src/buffman.c
new file mode 100644
index 000000000..eaf268bd4
--- /dev/null
+++ b/private/utils/ntbackup/src/buffman.c
@@ -0,0 +1,942 @@
+/**
+
+ Name: buffman.c
+
+ Description: This unit provides the functions needed for
+ allocation, de-allocation, and other manipulations
+ on the buffers used by Tape Format routines for
+ transfers to and from the device drivers.
+
+ $Log: N:/LOGFILES/BUFFMAN.C_V $
+
+ Rev 1.16 10 Jun 1993 08:05:00 MIKEP
+enable c++
+
+ Rev 1.15 19 May 1993 19:02:56 DON
+Actually got the assert in BM_InitBuf. Changed so if buf_ptr is NULL we won't use it!
+
+ Rev 1.14 09 Mar 1993 18:15:28 GREGG
+Initial changes for new stream and EOM processing.
+
+ Rev 1.13 26 Feb 1992 08:58:36 STEVEN
+added include for buffnt.h
+
+ Rev 1.12 04 Feb 1992 19:53:40 GREGG
+Changes for dealing with new config parameters.
+
+ Rev 1.11 16 Jan 1992 21:02:40 GREGG
+Changed InitList to return INT16 not UINT16.
+
+ Rev 1.10 14 Jan 1992 19:43:34 NED
+Added call to BM_OS_CleanupListTuesday, January 28, 1992
+
+ Rev 1.9 14 Jan 1992 02:03:44 GREGG
+InitList and OS_InitList now return TFLEs.
+
+ Rev 1.8 13 Jan 1992 19:42:56 NED
+Changed vcb requirements to a uw_ variable
+
+ Rev 1.7 13 Jan 1992 13:44:52 GREGG
+Skateboard - Bug fixes.
+
+ Rev 1.6 03 Jan 1992 11:39:50 GREGG
+Modifications to allow for a special VCB buffer.
+
+ Rev 1.5 05 Dec 1991 13:50:06 GREGG
+SKATEBOARD - New Buff Mgt - Initial Integration.
+
+ Rev 1.4 07 Jun 1991 16:20:20 NED
+removed static attribute from definition of uw_bpool
+
+ Rev 1.3 04 Jun 1991 11:21:08 BARRY
+Fix OS-specific memory allocation problems by relocating BM_Alloc() and
+BM_Free() to separate source files. Tuesday, December 17, 1991
+
+ Rev 1.2 03 Jun 1991 15:22:18 CARLS
+added changes for Windows
+
+ Rev 1.1 10 May 1991 16:17:36 GREGG
+Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:12:14 GREGG
+Initial revision.
+
+**/
+
+#include <string.h>
+#include "stdtypes.h"
+#include "queues.h"
+#include "buffman.h"
+#include "buff_prv.h"
+#include "minmax.h"
+#include "msassert.h"
+#include "tfl_err.h"
+
+#if defined( OS_NLM )
+#include "buffnlm.h"
+#elif defined( OS_WIN )
+#include "buffwin.h"
+#elif defined( OS_DOS )
+#include "buffdos.h"
+#elif defined( OS_OS2 )
+#include "buffos2.h"
+#elif defined( OS_WIN32 )
+#include "buffnt.h"
+#endif
+
+static BUF_REQ mw_default_reqs; /* to reset requirements to */
+Q_HEADER uw_bm_master_list; /* list of all the lists ??? */
+BUF_REQ_PTR uw_vcb_requirements; /* passed via BM_SetVCBRequirements() */
+
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: BM_InitList
+ *
+ * Modified: Tuesday, January 28, 1992
+ *
+ * Description: Initialize an empty list
+ *
+ * Notes:
+ *
+ * Returns: TFLE_xxx
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ ** initialize list header
+ **
+ ** add the list to our list of lists
+ **
+ ** Let the OS do it's stuff
+ **
+ **/
+
+INT16 BM_InitList(
+ BUF_LIST_PTR list_ptr,
+ UINT16 initial_buff_alloc )
+{
+/*
+** initialize list header
+*/
+ InitQueue( &list_ptr->list_header );
+ list_ptr->max_memory = 0L;
+ list_ptr->memory_used = 0L;
+ BM_ClearRequirements( &list_ptr->requirements_context );
+/*
+** add the list to our list of lists
+*/
+ InitQElem( &list_ptr->q_elem );
+ SetQueueElemPtr( &list_ptr->q_elem, list_ptr );
+ EnQueueElem( &uw_bm_master_list, &list_ptr->q_elem, FALSE );
+/*
+** Let the OS do it's stuff
+*/
+ return( BM_OS_InitList( list_ptr, initial_buff_alloc ) ) ;
+}
+
+/**/
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: BM_DeInitList
+ *
+ * Modified: Tuesday, January 28, 1992
+ *
+ * Description: De-initialize a list: free all the buffers on the list
+ *
+ * Notes: Ignores whether the buffers have been marked as
+ * gotten
+ *
+ * Returns: VOID
+ *
+ * Global Data: removes list from uw_bm_master_list
+ *
+ * Processing:
+ *
+ ** remove the list from our list of lists
+ **
+ ** For each buffer on pool list
+ **
+ ** Free the buffer
+ **
+ ** Free the vcb buffer
+ **
+ ** Let the OS do it's stuff
+ **
+ **/
+
+VOID BM_DeInitList(
+ BUF_LIST_PTR list_ptr ) /* IO - list to de-initialize */
+{
+ BUF_PTR buf_ptr ;
+ Q_ELEM_PTR qe_ptr = QueueHead( &list_ptr->list_header );
+/*
+** remove the list from our list of lists
+*/
+ RemoveQueueElem( &uw_bm_master_list, &list_ptr->q_elem );
+/*
+** For each buffer on pool list
+*/
+ while ( qe_ptr != NULL ) {
+ buf_ptr = (BUF_PTR)QueuePtr( qe_ptr );
+ qe_ptr = QueueNext( qe_ptr ); /* get it before we free it! */
+ msassert( buf_ptr != NULL );
+/*
+** Free the buffer
+*/
+ BM_Free( list_ptr, buf_ptr ) ;
+ }
+
+/*
+** Free the vcb buffer
+*/
+ if( list_ptr->vcb_buff ) {
+ BM_FreeVCB( list_ptr, list_ptr->vcb_buff ) ;
+ }
+/*
+** Let the OS do it's stuff
+*/
+ BM_OS_DeInitList( list_ptr ) ;
+}
+
+/**/
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: BM_Init
+ *
+ * Modified: Tuesday, January 28, 1992
+ *
+ * Description: Initialize Buffer Manager
+ *
+ * Notes:
+ *
+ * Returns: VOID
+ *
+ * Global Data: initializes uw_bm_master_list
+ * initializes mw_default_reqs
+ *
+ * Processing:
+ *
+ ** initialize our master list
+ **
+ ** set harmless default requirements
+ **
+ **/
+
+VOID BM_Init( VOID )
+{
+/*
+** initialize our master list
+*/
+ InitQueue( &uw_bm_master_list );
+/*
+** set harmless default requirements
+*/
+ mw_default_reqs.a.min_size =
+ mw_default_reqs.a.max_size =
+ mw_default_reqs.b.min_size =
+ mw_default_reqs.b.max_size =
+ mw_default_reqs.b.incr_size =
+ mw_default_reqs.tf_size =
+ mw_default_reqs.rw_size = BR_DONT_CARE ;
+
+ mw_default_reqs.b.align =
+ mw_default_reqs.a.align =
+ mw_default_reqs.b.block =
+ mw_default_reqs.a.block = 1 ;
+
+ uw_vcb_requirements = NULL ;
+}
+
+/**/
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: BM_DeInit
+ *
+ * Modified: Tuesday, January 28, 1992
+ *
+ * Description: De-Initialize Buffer manager: free all buffers
+ *
+ * Notes: Ignores whether buffers have been marked as
+ * gotten
+ *
+ * Returns: VOID
+ *
+ * Global Data: removes all lists from uw_bm_master_list
+ *
+ * Processing:
+ *
+ ** for each remaining list on our list of lists
+ **
+ ** free all the buffers on the list
+ **
+ **/
+
+VOID BM_DeInit( VOID )
+{
+ Q_ELEM_PTR qe_ptr ;
+/*
+** for each remaining list on our list of lists
+*/
+ while ( ( qe_ptr = DeQueueElem( &uw_bm_master_list ) ) != NULL ) {
+ BUF_LIST_PTR list_ptr = (BUF_LIST_PTR)QueuePtr( qe_ptr );
+/*
+** free all the buffers on the list
+*/
+ BM_DeInitList( list_ptr );
+ }
+}
+
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: BM_ClearRequirements
+ *
+ * Modified: Tuesday, January 28, 1992
+ *
+ * Description: Set a requirements context to default values
+ *
+ * Notes:
+ *
+ * Returns: VOID
+ *
+ * Global Data: reads mw_default_reqs
+ *
+ * Processing:
+ *
+ ** copy default requirements to given context
+ **
+ **/
+
+VOID BM_ClearRequirements(
+ BUF_REQ_PTR context_ptr ) /* O - context to clear */
+{
+/*
+** copy default requirements to given context
+*/
+ *context_ptr = mw_default_reqs;
+}
+
+/**/
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: AddBlockRequirements
+ *
+ * Modified: Tuesday, January 28, 1992
+ *
+ * Description: Attempt to add requested requirements to dest
+ *
+ * Notes:
+ *
+ * Returns: BR_ERR
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ ** Copy dest to temp
+ **
+ ** Check new requirement for consistency
+ **
+ ** Combine alignment requirements (no LCM yet)
+ **
+ ** Combine block size requirements (no LCM yet)
+ **
+ ** Combine minimum sizes: use maximum of old, new
+ **
+ ** Combine maximum sizes: use minimum of old, new
+ **
+ ** Combine realloc increment sizes: use maximum of old, new
+ **
+ ** Check for final size consistency: min_size <= max_size?
+ **
+ ** If all OK, copy to destination
+ **
+ **/
+
+static BR_ERR _near AddBlockRequirements(
+ BLOCK_REQ_PTR dest, /* IO - add requirements to this */
+ BLOCK_REQ_PTR src ) /* I - requirements to add */
+{
+/*
+** Copy dest to temp
+*/
+ BLOCK_REQ old_br = *dest;
+/*
+** Check new requirement for consistency
+*/
+ if ( src->max_size != BR_DONT_CARE
+ && src->min_size != BR_DONT_CARE
+ && src->min_size > src->max_size ) {
+ return BR_ERR_BAD_REQUIREMENT;
+ }
+/*
+** Combine alignment requirements (no LCM yet)
+*/
+ if ( src->align != old_br.align ) {
+ if ( src->align < old_br.align ) {
+ if ( old_br.align % src->align != 0 ) {
+ return BR_ERR_INCOMPATIBLE;
+ }
+ /* else do nothing; alignment already compatible */
+ } else { /* src alignment > dest alignment */
+ if ( src->align % old_br.align != 0 ) {
+ return BR_ERR_INCOMPATIBLE;
+ } else {
+ old_br.align = src->align;
+ }
+ }
+ }
+/*
+** Combine block size requirements (no LCM yet)
+*/
+ if ( src->block != old_br.block ) {
+ if ( src->block < old_br.block ) {
+ if ( old_br.block % src->block != 0 ) {
+ return BR_ERR_INCOMPATIBLE;
+ }
+ /* else do nothing; block size already compatible */
+ } else { /* src block size > dest block size */
+ if ( src->block % old_br.block != 0 ) {
+ return BR_ERR_INCOMPATIBLE;
+ } else {
+ old_br.block = src->block;
+ }
+ }
+ }
+/*
+** Combine minimum sizes: use maximum of old, new
+*/
+ if ( src->min_size != BR_DONT_CARE ) {
+ if ( old_br.min_size == BR_DONT_CARE ) {
+ old_br.min_size = src->min_size;
+ } else {
+ old_br.min_size = MAX( old_br.min_size, src->min_size );
+ }
+ }
+/*
+** Combine maximum sizes: use minimum of old, new
+*/
+ if ( src->max_size != BR_DONT_CARE ) {
+ if ( old_br.max_size == BR_DONT_CARE ) {
+ old_br.max_size = src->max_size;
+ } else {
+ old_br.max_size = MIN( old_br.max_size, src->max_size );
+ }
+ }
+/*
+** Combine realloc increment sizes: use maximum of old, new
+*/
+ if ( src->incr_size != BR_DONT_CARE ) {
+ if ( old_br.incr_size == BR_DONT_CARE ) {
+ old_br.incr_size = src->incr_size;
+ } else {
+ old_br.incr_size = MAX( old_br.incr_size, src->incr_size );
+ }
+ }
+/*
+** Check for final size consistency: min_size <= max_size?
+*/
+ if ( old_br.max_size != BR_DONT_CARE
+ && old_br.min_size != BR_DONT_CARE
+ && old_br.min_size > old_br.max_size ) {
+ return BR_ERR_INCOMPATIBLE;
+ }
+/*
+** If all OK, copy to destination
+*/
+ *dest = old_br;
+ return BR_NO_ERR;
+}
+/**/
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: BM_AddRequirements
+ *
+ * Modified: Tuesday, January 28, 1992
+ *
+ * Description: Add a set of requirements to an existing context
+ *
+ * Notes:
+ *
+ * Returns: BR_ERR
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ ** Copy context to temp BUF_REQ
+ **
+ ** Add requirements for block "a"
+ **
+ ** If successful
+ **
+ ** add requirements for block "b"
+ **
+ ** If successful
+ **
+ ** combine tf_size
+ **
+ ** combine rw_size
+ **
+ ** update target context from temp
+ **
+ **/
+
+BR_ERR BM_AddRequirements(
+ BUF_REQ_PTR context, /* IO - context to add requirements to */
+ BUF_REQ_PTR newreqs ) /* I - new requirements */
+{
+/*
+** Copy context to temp BUF_REQ
+*/
+ BUF_REQ temp_br = *context;
+/*
+** Add requirements for block "a"
+*/
+ BR_ERR ret_val = AddBlockRequirements( &temp_br.a, &newreqs->a );
+/*
+** If successful
+*/
+ if ( ret_val == BR_NO_ERR ) {
+/*
+** add requirements for block "b"
+*/
+ ret_val = AddBlockRequirements( &temp_br.b, &newreqs->b );
+/*
+** If successful
+*/
+ if ( ret_val == BR_NO_ERR ) {
+/*
+** combine tf_size
+*/
+ if ( temp_br.tf_size != newreqs->tf_size ) {
+ if ( newreqs->tf_size != BR_DONT_CARE ) {
+ if ( temp_br.tf_size != BR_DONT_CARE ) {
+ return BR_ERR_INCOMPATIBLE;
+ } else {
+ temp_br.tf_size = newreqs->tf_size;
+ }
+ }
+ }
+/*
+** combine rw_size
+*/
+ if ( temp_br.rw_size != newreqs->rw_size ) {
+ if ( newreqs->rw_size != BR_DONT_CARE ) {
+ if ( temp_br.rw_size != BR_DONT_CARE ) {
+ return BR_ERR_INCOMPATIBLE;
+ } else {
+ temp_br.rw_size = newreqs->rw_size;
+ }
+ }
+ }
+/*
+** update target context from temp
+*/
+ *context = temp_br;
+ }
+ }
+
+ return ret_val;
+}
+
+/**/
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: BM_Get
+ *
+ * Modified: Tuesday, January 28, 1992
+ *
+ * Description: Get a buffer from the buffer pool
+ * which meets the pool's current requirements.
+ *
+ * Notes:
+ *
+ * Returns: BUF_PTR
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ ** For each buffer on pool list
+ **
+ ** If the buffer hasn't been gotten
+ **
+ ** then mark the buffer as gotten and return the buffer
+ **
+ **/
+
+BUF_PTR BM_Get(
+ BUF_LIST_PTR list_ptr ) /* I - describes buffer to Get */
+{
+ BUF_PTR buf_ptr = NULL;
+ Q_ELEM_PTR qe_ptr = QueueHead( &list_ptr->list_header );
+/*
+** For each buffer on pool list
+*/
+ for ( ; qe_ptr != NULL ; qe_ptr = QueueNext( qe_ptr ) ) {
+/*
+** If the buffer hasn't been gotten
+*/
+ if ( !( buf_ptr = (BUF_PTR)QueuePtr( qe_ptr ) )->gotten ) {
+/*
+** then mark the buffer as gotten and return the buffer
+*/
+ BM_InitBuf( buf_ptr );
+ buf_ptr->gotten = TRUE;
+ break;
+ }
+ }
+
+ if ( qe_ptr == NULL ) {
+ return NULL;
+ } else {
+ return buf_ptr;
+ }
+}
+
+/**/
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: BM_GetVCBBuff
+ *
+ * Modified: Tuesday, January 28, 1992
+ *
+ * Description: Returns a pointer to the lists VCB buffer if has not
+ * already been gotten.
+ *
+ * Notes:
+ *
+ * Returns: BUF_PTR or NULL
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ ** If the vcb buff hasn't been gotten
+ **
+ ** then mark the buffer as gotten and return the buffer
+ **
+ ** else return NULL
+ **
+ **/
+
+BUF_PTR BM_GetVCBBuff(
+ BUF_LIST_PTR list_ptr ) /* I - describes buffer to Get */
+{
+/*
+** If the vcb buff hasn't been gotten
+*/
+ if ( !list_ptr->vcb_buff->gotten ) {
+/*
+** then mark the buffer as gotten and return the buffer
+*/
+ BM_InitBuf( list_ptr->vcb_buff );
+ list_ptr->vcb_buff->gotten = TRUE;
+ return list_ptr->vcb_buff;
+ } else {
+/*
+** else return NULL
+*/
+ msassert( FALSE );
+ return NULL;
+ }
+}
+
+/**/
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: BM_InitBuf
+ *
+ * Modified: Monday, October 7, 1991
+ *
+ * Description: clear out the TF fields (counts and offsets) in a buffer
+ *
+ * Notes:
+ *
+ * Returns: VOID
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ **/
+
+VOID BM_InitBuf(
+ BUF_PTR buf_ptr ) /* I - buffer to initialize */
+{
+ msassert( buf_ptr != NULL );
+
+ if ( buf_ptr != NULL ) {
+
+ BM_SetBytesFree( buf_ptr, BM_TFSize( buf_ptr ) );
+ BM_SetNoDblks( buf_ptr, 0 );
+ BM_SetNextByteOffset( buf_ptr, 0 );
+ BM_SetBeginningLBA( buf_ptr, 0 );
+ BM_SetReadError( buf_ptr, 0 );
+ BM_UnReserve( buf_ptr );
+
+ memset( BM_NextBytePtr( buf_ptr ), '\0', BM_TFSize( buf_ptr ) ) ;
+
+ SetQueueElemPtr( &buf_ptr->tf_qe, buf_ptr );
+ SetQueueElemPtr( &buf_ptr->bm_qe, buf_ptr );
+ }
+}
+
+/**/
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: BM_UpdCnts
+ *
+ * Modified: Monday, October 7, 1991
+ *
+ * Description: Use some of the remaining bytes in a buffer.
+ *
+ * Notes:
+ *
+ * Returns: VOID
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ **/
+
+VOID BM_UpdCnts(
+ BUF_PTR buf_ptr , /* (IO) - The current buffer */
+ UINT16 amount ) /* (I) - The amount of space used */
+{
+ if ( buf_ptr ) {
+ buf_ptr->bytes_free -= amount ;
+ buf_ptr->next_byte += amount ;
+ }
+}
+
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: BM_UseAll
+ *
+ * Modified: Monday, October 7, 1991
+ *
+ * Description: consume all the remaining bytes in a buffer
+ *
+ * Notes:
+ *
+ * Returns: VOID
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ **/
+
+VOID BM_UseAll(
+ BUF_PTR buf_ptr ) /* IO - the buffer to use up */
+{
+ msassert( buf_ptr != NULL );
+
+ if ( buf_ptr != NULL ){
+ BM_UpdCnts( buf_ptr, buf_ptr->bytes_free ) ;
+ }
+}
+
+/**/
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: BM_PutAll
+ *
+ * Modified: Tuesday, January 28, 1992
+ *
+ * Description: Do a BM_Put on all buffers in a pool
+ *
+ * Notes: This should replace all the many loops in TF where
+ * we put all the buffers.
+ *
+ * Returns: VOID
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ ** For each buffer on pool list
+ **
+ **/
+
+VOID BM_PutAll(
+ BUF_LIST_PTR list_ptr ) /* I/O - list to Put */
+{
+ BUF_PTR buf_ptr ;
+ Q_ELEM_PTR qe_ptr = QueueHead( &list_ptr->list_header );
+/*
+** For each buffer on pool list
+*/
+ for ( ; qe_ptr != NULL ; qe_ptr = QueueNext( qe_ptr ) ) {
+ buf_ptr = (BUF_PTR)QueuePtr( qe_ptr );
+ msassert( buf_ptr != NULL );
+ BM_Put( buf_ptr ) ;
+ }
+
+ BM_Put( list_ptr->vcb_buff ) ;
+}
+/**/
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: BM_FreeAll
+ *
+ * Modified: Tuesday, January 28, 1992
+ *
+ * Description: Do a BM_Free on all buffers in a pool;
+ *
+ * Notes: This should replace all the many loops in TF where
+ * we put all the buffers.
+ *
+ * Returns: VOID
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ ** For each buffer on pool list
+ **
+ ** If the buffer is not reserved
+ **
+ ** Free the buffer
+ **
+ ** call OS-specific (DOS, of course) code to reserve
+ ** any buffers which may be left
+ **
+ **/
+
+VOID BM_FreeAll(
+ BUF_LIST_PTR list_ptr ) /* I/O - list to Free */
+{
+ BUF_PTR buf_ptr ;
+ Q_ELEM_PTR qe_ptr = QueueHead( &list_ptr->list_header );
+/*
+** For each buffer on pool list
+*/
+ while ( qe_ptr != NULL ) {
+ buf_ptr = (BUF_PTR)QueuePtr( qe_ptr );
+ qe_ptr = QueueNext( qe_ptr ); /* get it before we free it! */
+ msassert( buf_ptr != NULL );
+/*
+** If the buffer is not reserved
+*/
+ if ( !buf_ptr->reserved ) {
+/*
+** Free the buffer
+*/
+ BM_Free( list_ptr, buf_ptr ) ;
+
+ }
+ }
+
+/*
+** call OS-specific (DOS, of course) code to reserve
+** any buffers which may be left
+*/
+ BM_OS_CleanupList( list_ptr );
+}
+/**/
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: BM_SetVCBRequirements
+ *
+ * Modified: Friday, December 20, 1991
+ *
+ * Description: Set the buffer manager's idea of the VCB requirements
+ *
+ * Notes: Argument must point to statically allocated memory
+ * (no copying is done)
+ *
+ * Returns: VOID
+ *
+ * Global Data: sets uw_vcb_requirements
+ *
+ * Processing:
+ *
+ **/
+
+VOID BM_SetVCBRequirements(
+ BUF_REQ_PTR vcb_reqs ) /* I - points to vcb requirements structure */
+{
+ uw_vcb_requirements = vcb_reqs;
+}
+
+
+
+
+/**/
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: BM_RequiredSize
+ *
+ * Modified: Friday, October 18, 1991
+ *
+ * Description: Returns the amount of memory required for a buffer
+ * given specific requirements
+ *
+ * Notes:
+ *
+ * Returns: UINT32 (size of allocation)
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ **/
+
+UINT32 BM_RequiredSize(
+ BUF_REQ_PTR br_ptr ) /* I - requirements pointer */
+{
+ return
+ sizeof( BUF )
+ + br_ptr->a.min_size
+ + BM_RESERVED_SIZE
+ + ( ( br_ptr->b.min_size == BR_DONT_CARE ) ? 0 : br_ptr->b.min_size );
+}
+
+
+/**/
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: BM_BufferOverhead
+ *
+ * Modified: Friday, October 18, 1991
+ *
+ * Description: Return the amount of memory used by a (hypothetical) buffer
+ * if it has 0 bytes of main and auxiliary allocation.
+ *
+ *
+ * Notes:
+ *
+ * Returns: UINT16 (size of overhead)
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ **/
+
+UINT16 BM_BufferOverhead( VOID )
+{
+ return sizeof( BUF ) + BM_RESERVED_SIZE ;
+}
+
diff --git a/private/utils/ntbackup/src/buffnt.c b/private/utils/ntbackup/src/buffnt.c
new file mode 100644
index 000000000..5389bbdb1
--- /dev/null
+++ b/private/utils/ntbackup/src/buffnt.c
@@ -0,0 +1,569 @@
+/**
+
+ Name: buffnt.c
+
+ Description: This unit provides the operating-system specific
+ functions needed for allocation, de-allocation,
+ and resizing of the buffers used by Tape Format
+ routines for transfers to and from the device drivers.
+
+ $Log: T:\logfiles\buffnt.c_v $
+
+ Rev 1.13 28 Jan 1994 18:25:12 GREGG
+Fixed MIPS 16 byte alignment requirement bug.
+
+ Rev 1.12 25 Jan 1994 14:21:28 STEVEN
+add support for non aligned allocations on mips
+
+ Rev 1.11 10 Jun 1993 08:06:06 MIKEP
+enable c++
+
+ Rev 1.10 17 Mar 1993 14:52:50 GREGG
+This is Terri Lynn. Added Gregg's changes to switch a tape drive's block mode
+to match the block size of the current tape.
+
+ Rev 1.9 09 Mar 1993 18:14:18 GREGG
+Initial changes for new stream and EOM processing.
+
+ Rev 1.8 14 Jan 1993 16:21:52 DAVEV
+chg PUSHORT to UINT16_PTR
+
+ Rev 1.7 11 Nov 1992 11:01:06 GREGG
+Removed #error message.
+
+ Rev 1.6 18 Aug 1992 09:51:44 BURT
+fix warnings
+
+ Rev 1.5 23 Jul 1992 09:36:42 STEVEN
+fix warnings.
+
+ Rev 1.4 28 Apr 1992 10:45:52 STEVEN
+parallel buffos2
+
+ Rev 1.3 26 Feb 1992 09:25:26 STEVEN
+fix warnings
+
+ Rev 1.2 26 Feb 1992 09:12:20 STEVEN
+added buffnt.h
+
+ Rev 1.1 23 Jan 1992 13:16:42 STEVEN
+typeo for Unlock
+
+ Rev 1.0 21 Jan 1992 12:25:40 STEVEN
+Initial revision.
+
+**/
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "queues.h"
+#include "tfl_err.h"
+#include "buffman.h"
+#include "buff_prv.h"
+#include "buffnt.h"
+#include "msassert.h"
+#include "dilhwd.h"
+#include "retbuf.h"
+#include "dil.h"
+
+
+/* For buffer allignment */
+static INT mw_buffer_alignment ;
+
+
+/**
+ * Name: AllocBufferGuts
+ *
+ * Description: allocate internal chunks of BUF
+ * and lock down primary allocation
+ *
+ * Notes:
+ *
+ * Returns: UINT16 error code
+ *
+ **/
+
+static UINT16 _near AllocBufferGuts(
+ BUF_REQ_PTR br_ptr,
+ BUF_PTR buf_ptr )
+{
+ UINT8 remainder ;
+
+ buf_ptr->ptr2 = buf_ptr->ptr1 = NULL ;
+
+ // allocate chunk "a"
+
+ buf_ptr->alloc_size = (UINT16)( br_ptr->a.min_size +
+ BM_RESERVED_SIZE +
+ mw_buffer_alignment * 2 ) ;
+
+ if( ( buf_ptr->ptr1 = calloc( 1, buf_ptr->alloc_size ) ) == NULL ) {
+ return( (UINT16)OUT_OF_MEMORY ) ;
+ }
+
+ // allocate chunk "b" (if any)
+ if( br_ptr->b.min_size != BR_DONT_CARE ) {
+ buf_ptr->aux_size = br_ptr->b.min_size ;
+ if( ( buf_ptr->ptr2 = calloc( 1, buf_ptr->aux_size ) ) == NULL ) {
+ free( buf_ptr->ptr1 ) ;
+ return( (UINT16)OUT_OF_MEMORY ) ;
+ }
+ } else {
+ buf_ptr->aux_size = 0 ;
+ }
+
+ // align buffer as required
+
+ remainder = (UINT8)( ( (DWORD)buf_ptr->ptr1 ) &
+ ( mw_buffer_alignment - 1 ) ) ;
+ (BYTE_PTR)( buf_ptr->ptr1 ) += mw_buffer_alignment - remainder ;
+ *( (UINT8_PTR)( buf_ptr->ptr1 ) ) = mw_buffer_alignment - remainder ;
+ (BYTE_PTR)( buf_ptr->ptr1 ) += mw_buffer_alignment ;
+
+ return( (UINT16)SUCCESS ) ;
+}
+
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: FreeBufferGuts
+ *
+ * Description: free chunks of memory lurking
+ * inside BUF and unlock primary allocation
+ *
+ * Notes:
+ *
+ * Returns: VOID
+ *
+ **/
+
+static VOID _near FreeBufferGuts( BUF_PTR buf_ptr )
+{
+ // Deallocate chunk "b"
+ if( buf_ptr->ptr2 != NULL ) {
+ free( buf_ptr->ptr2 ) ;
+ }
+
+ // Undo byte alignment and deallocate chunk "a"
+ if( buf_ptr->ptr1 != NULL ) {
+ (BYTE_PTR)( buf_ptr->ptr1 ) -= mw_buffer_alignment ;
+ (BYTE_PTR)( buf_ptr->ptr1 ) -= *( (UINT8_PTR)( buf_ptr->ptr1 ) ) ;
+ free( buf_ptr->ptr1 ) ;
+ }
+}
+
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: AllocBuffer
+ *
+ * Modified: Monday, January 13, 1992
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Returns: BUF_PTR
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ ** allocate BUF structure
+ **
+ ** allocate internal chunks of BUF and lock down primary allocation
+ **
+ ** Init other fields
+ **
+ **/
+
+static BUF_PTR _near AllocBuffer(
+ BUF_LIST_PTR pool_ptr,
+ BUF_REQ_PTR br_ptr )
+{
+ BUF_PTR buf_ptr = NULL;
+
+/*
+** allocate BUF structure
+*/
+ if ( ( buf_ptr = (BUF_PTR)calloc(1, sizeof(BUF) ) ) == NULL ) {
+ return NULL ;
+ }
+
+/*
+** allocate internal chunks of BUF and lock down primary allocation
+*/
+ if ( AllocBufferGuts( br_ptr, buf_ptr ) != SUCCESS ) {
+ free( buf_ptr ) ;
+ return NULL;
+ }
+/*
+** Init other fields
+*/
+ InitQElem( &buf_ptr->tf_qe );
+ InitQElem( &buf_ptr->bm_qe );
+ BM_InitBuf( buf_ptr );
+ buf_ptr->tf_size = br_ptr->tf_size;
+ buf_ptr->rw_size = br_ptr->rw_size;
+ buf_ptr->gotten = FALSE;
+ buf_ptr->reserved = FALSE;
+ buf_ptr->list_ptr = pool_ptr;
+
+ return buf_ptr;
+}
+
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: BM_Alloc
+ *
+ * Modified: Monday, January 13, 1992
+ *
+ * Description: Allocate a buffer for the given list
+ *
+ * Notes: there is no attempt here to guarantee
+ * any physical alignment
+ *
+ * Returns: BUF_PTR
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ ** allocate buffer
+ **
+ ** add new BUF to pool
+ **
+ ** update pool memory count
+ **
+ **/
+
+BUF_PTR BM_Alloc(
+ BUF_LIST_PTR pool_ptr ) /* list we're allocating it for */
+{
+ BUF_REQ_PTR br_ptr = &pool_ptr->requirements_context;
+/*
+** allocate buffer
+*/
+ BUF_PTR buf_ptr = AllocBuffer( pool_ptr, br_ptr );
+/*
+** add new BUF to pool
+*/
+ if ( buf_ptr ) {
+ EnQueueElem( &pool_ptr->list_header, &BM_BMQElem( buf_ptr ), FALSE );
+/*
+** update pool memory count
+*/
+ pool_ptr->memory_used += BM_RequiredSize( br_ptr );
+ }
+
+ return buf_ptr;
+}
+
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: BM_AllocVCB
+ *
+ * Modified: Monday, January 13, 1992
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Returns: BUF_PTR
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ ** allocate buffer
+ **
+ ** add to list
+ **
+ ** update pool memory count
+ **
+ **/
+
+BUF_PTR BM_AllocVCB(
+ BUF_LIST_PTR pool_ptr ) /* I - list to allocate from */
+{
+ BUF_REQ_PTR br_ptr = uw_vcb_requirements;
+/*
+** allocate buffer
+*/
+ BUF_PTR buf_ptr = AllocBuffer( pool_ptr, br_ptr );
+/*
+** add to list
+*/
+ pool_ptr->vcb_buff = buf_ptr ;
+
+ return buf_ptr;
+}
+
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: BM_Free
+ *
+ * Modified: Monday, January 13, 1992
+ *
+ * Description: Return a buffer to the OS free pool
+ *
+ * Notes:
+ *
+ * Returns: VOID
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ ** update pool memory count
+ **
+ ** remove buffer from pool
+ **
+ ** free chunks of memory lurking inside BUF
+ **
+ ** de-allocate BUF structure itself
+ **
+ **/
+
+VOID BM_Free(
+ BUF_LIST_PTR pool_ptr, /* list we're freeing it from */
+ BUF_PTR buf_ptr ) /* the buffer to free */
+{
+/*
+** update pool memory count
+*/
+ pool_ptr->memory_used -= sizeof( BUF )
+ + buf_ptr->alloc_size
+ + buf_ptr->aux_size ;
+/*
+** remove buffer from pool
+*/
+ RemoveQueueElem( &pool_ptr->list_header, &buf_ptr->bm_qe );
+/*
+** free chunks of memory lurking inside BUF
+*/
+ FreeBufferGuts( buf_ptr );
+/*
+** de-allocate BUF structure itself
+*/
+ free( buf_ptr ) ;
+}
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: BM_FreeVCB
+ *
+ * Modified: Monday, January 13, 1992
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Returns: VOID
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ **/
+
+VOID BM_FreeVCB(
+ BUF_LIST_PTR pool_ptr,
+ BUF_PTR buf_ptr )
+{
+
+ if ( buf_ptr != NULL ) {
+/*
+** check to see if this is really the VCB buffer
+*/
+ msassert( pool_ptr->vcb_buff == buf_ptr ) ;
+/*
+** update pool memory count
+*/
+ pool_ptr->memory_used -= sizeof( BUF )
+ + buf_ptr->alloc_size
+ + buf_ptr->aux_size ;
+/*
+** remove buffer from pool
+*/
+ pool_ptr->vcb_buff = NULL;
+/*
+** free chunks of memory lurking inside BUF
+*/
+ FreeBufferGuts( buf_ptr );
+/*
+** de-allocate BUF structure itself
+*/
+ free( buf_ptr ) ;
+ }
+}
+
+
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: BM_ReSizeList
+ *
+ * Modified: Wednesday, November 13, 1991
+ *
+ * Description: Re-sizes every buffer on the given list.
+ *
+ * Notes: This may not have to be OS specific...
+ *
+ * Returns: INT16, TFLE_xxx
+ *
+ * Global Data: Nope!
+ *
+ * Processing:
+ *
+ **/
+
+INT16 BM_ReSizeList(
+ BUF_LIST_PTR pool_ptr ) /* I/O -- list to re-size */
+{
+ BUF_PTR buf_ptr ;
+ Q_ELEM_PTR qe_ptr = QueueHead( &pool_ptr->list_header );
+ UINT32 total_memory = 0L;
+
+ /* free all we can, total memory usage of the rest */
+ while ( qe_ptr != NULL ) {
+ buf_ptr = (BUF_PTR)QueuePtr( qe_ptr );
+ qe_ptr = QueueNext( qe_ptr ); /* get it before we free it! */
+ msassert( buf_ptr != NULL );
+ if ( !buf_ptr->gotten ) {
+ BM_Free( pool_ptr, buf_ptr ) ;
+ } else {
+ total_memory += buf_ptr->alloc_size + buf_ptr->aux_size + sizeof( BUF );
+ }
+ }
+
+ /* correct the memory usage of the list */
+ pool_ptr->memory_used = total_memory;
+
+ /* allocate as many buffers as we can given the memory limits */
+ while ( pool_ptr->memory_used + BM_RequiredSize( &pool_ptr->requirements_context )
+ <= pool_ptr->max_memory ) {
+ if ( ( buf_ptr = BM_Alloc( pool_ptr ) ) == NULL ) {
+ return TFLE_NO_MEMORY ;
+ }
+ }
+
+ return TFLE_NO_ERR;
+}
+
+
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: BM_ReSizeBuffer
+ *
+ * Description: Re-sizes the given buffer.
+ *
+ * Notes: This may not have to be OS specific...
+ *
+ * Returns: INT16, TFLE_xxx
+ *
+ * Global Data: Nope!
+ *
+ * Processing:
+ *
+ **/
+
+INT16 BM_ReSizeBuff(
+ BUF_PTR buf_ptr,
+ BUF_LIST_PTR pool_ptr )
+{
+ if( BM_IsVCBBuff( buf_ptr ) ) {
+ BM_FreeVCB( pool_ptr, buf_ptr ) ;
+ if ( ( buf_ptr = BM_AllocVCB( pool_ptr ) ) == NULL ) {
+ return TFLE_NO_MEMORY ;
+ }
+ } else {
+ BM_Free( pool_ptr, buf_ptr ) ;
+ if ( ( buf_ptr = BM_Alloc( pool_ptr ) ) == NULL ) {
+ return TFLE_NO_MEMORY ;
+ }
+ }
+
+ return TFLE_NO_ERR;
+}
+
+
+/**/
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: BM_ReallocAux
+ *
+ * Description: Increases the size of the auxiliary buffer based on an
+ * increment value specified in the requirements context.
+ *
+ * Notes:
+ *
+ * Returns: TFLE_xxx error code.
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ **/
+
+INT16 BM_ReallocAux(
+ BUF_LIST_PTR list_ptr,
+ BUF_PTR buf_ptr )
+{
+ UINT16 incr = list_ptr->requirements_context.b.incr_size ;
+ VOID_PTR temp ;
+ INT16 ret_val = TFLE_NO_ERR ;
+
+ if( ( temp = realloc( buf_ptr->ptr2, buf_ptr->aux_size + incr ) ) != NULL ) {
+ buf_ptr->aux_size += incr ;
+ buf_ptr->ptr2 = temp ;
+ } else {
+ ret_val = TFLE_NO_MEMORY ;
+ }
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+ * Unit: Buffer Manager
+ *
+ * Name: BM_OS_InitList
+ *
+ * Description: OS's shot at initialization
+ *
+ * Notes:
+ *
+ * Returns: TFLE_xxx error code.
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ **/
+
+INT16 BM_OS_InitList(
+ BUF_LIST_PTR list_ptr,
+ UINT16 initial_buff_alloc )
+{
+ // Get data transfer buffer alignment requirements
+
+ if( TpGetTapeBuffAlignment( &mw_buffer_alignment ) == SUCCESS ) {
+ if( mw_buffer_alignment == 0 ) {
+ mw_buffer_alignment = BM_NT_DEFAULT_BUF_ALGN_SZ ;
+ }
+ } else {
+ mw_buffer_alignment = BM_NT_DEFAULT_BUF_ALGN_SZ ;
+ }
+
+ return( TFLE_NO_ERR ) ;
+
+ (void)list_ptr ;
+ (void)initial_buff_alloc ;
+}
+
diff --git a/private/utils/ntbackup/src/checksum.c b/private/utils/ntbackup/src/checksum.c
new file mode 100644
index 000000000..ba4b48275
--- /dev/null
+++ b/private/utils/ntbackup/src/checksum.c
@@ -0,0 +1,269 @@
+/**
+Copyright(c) Connor Software, 1984-1993
+
+ Name: checksum.c
+
+ Date Updated: 08-Feb-93
+
+ Description: MTF checksum algorithm
+
+ $Log: N:/LOGFILES/CHECKSUM.C_V $
+
+ Rev 1.6 10 Jun 1993 08:06:58 MIKEP
+enable c++
+
+ Rev 1.5 26 May 1993 14:41:12 DON
+VDEL'd previous changes! The problem was we were overwriting the buff ptr
+during a InsertChecksum - by as little as 3 bytes. There was no guarantee
+tpfmt would give us a buffer with at least 4 bytes left so implemented a
+type of frag logic to deal with this. Also, changed VerifyChecksum to deal
+with the problem of not receiving all 4 bytes at once. My GOD, this was a
+tough bug to find!
+
+ Rev 1.4 31 Mar 1993 08:50:28 MARILYN
+changed over to the MTF checksum algorithm
+
+ Rev 1.3 17 Mar 1993 16:34:36 MARILYN
+made CHECKSUM_32_BITS an external symbolic constant
+
+ Rev 1.2 13 Mar 1993 17:07:40 GREGG
+Expect error return on ALL calls to LP_Send.
+
+ Rev 1.1 01 Mar 1993 17:30:40 MARILYN
+added functions to insert/consume checksum streams
+
+**/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "datetime.h"
+#include "assert.h"
+#include "dle_str.h"
+#include "queues.h"
+#include "tflproto.h"
+#include "loops.h"
+#include "fsstream.h"
+#include "loop_prv.h"
+#include "checksum.h"
+
+INT16 mwChecksumBytesNeeded ;
+
+/**/
+/**
+ Name: Checksum_Init( checksum_ptr )
+
+ Description: sets checksum_ptr to a 0 and mwChecksumBytesNeeded to 0
+
+ Modified: 12/11/92 Don C
+
+ Returns: Nothing.
+
+ Notes:
+
+**/
+VOID Checksum_Init ( UINT32_PTR checksum_ptr )
+{
+ *checksum_ptr = 0x00000000;
+ mwChecksumBytesNeeded = 0 ;
+}
+
+
+/**/
+/**
+ Name: Checksum_Block( checksum_ptr, data_ptr, data_len )
+
+ Description: updates checksum_ptr with a running checksum of the data
+ provided by data_ptr.
+
+ Modified: 12/11/92
+
+ Returns: The checksum computed.
+
+ Notes:
+
+**/
+UINT32 Checksum_Block ( UINT32_PTR checksum_optr,
+ VOID_PTR data_ptr,
+ UINT32 data_len )
+{
+ UINT32 UNALIGNED * checksum_ptr = (UINT32 UNALIGNED *)checksum_optr ;
+ UINT32 checksum = *checksum_ptr ;
+ UINT32 UNALIGNED * p ; /* data pointer */
+ UINT8_PTR rp ; /* Remainder pointer */
+ UINT32 len ; /* Number of 4-byte chunks */
+
+ rp = ( UINT8_PTR )data_ptr ;
+
+ while( mwChecksumBytesNeeded && data_len ) {
+
+ p = ( UINT32 UNALIGNED *)rp ;
+
+ checksum ^= (*p & 0xFF) << ( ( 4 - mwChecksumBytesNeeded ) << 3 ) ;
+ mwChecksumBytesNeeded -- ;
+ data_len -- ;
+ rp ++ ;
+ }
+
+ p = ( UINT32 UNALIGNED *)rp ;
+ len = data_len >> 2 ;
+
+ while ( len ) {
+
+ checksum ^= *p ;
+ len -- ;
+ p ++ ;
+ }
+
+ data_len &= 3 ;
+ if ( data_len ) {
+
+ mwChecksumBytesNeeded = 4 ;
+ rp = ( UINT8_PTR )p ;
+
+ while ( data_len ) {
+
+ p = ( UINT32 UNALIGNED *)rp ;
+ checksum ^= (*p & 0xFF) << ( ( 4 - mwChecksumBytesNeeded ) << 3 ) ;
+ mwChecksumBytesNeeded -- ;
+ data_len -- ;
+ rp ++ ;
+
+ }
+ }
+
+ return *checksum_ptr = checksum ;
+
+}
+
+
+/**/
+/**
+ Name: LP_InsertChecksumStream( checksum, lp )
+
+ Description: Puts a stream on the tape with checksum as the only stream
+ data.
+
+ Modified: 02/08/93 Marilyn P.
+
+ Returns: the return value of the LP_Send
+
+ Notes:
+
+**/
+INT16 LP_InsertChecksumStream(
+ UINT32 checksum, /* I - the checksum to be place on tape */
+ LP_ENV_PTR lp ) /* I - the environment struct for the loop */
+{
+ INT16 ret_val;
+ INT16 size_diff ;
+
+ lp->rr.stream.id = STRM_CHECKSUM_DATA ;
+ lp->rr.stream.fs_attrib = 0 ;
+ lp->rr.stream.tf_attrib = 0 ;
+ lp->rr.stream.size = U64_Init( 4, 0 ) ;
+ lp->rr.buff_used = 0 ;
+
+ if ( ( ret_val = LP_Send( lp, TRUE ) ) == SUCCESS ) {
+
+ /* only copy amount left in buffer */
+ memcpy( lp->rr.buff_ptr, (BYTE *)&checksum, lp->rr.buff_size ) ;
+
+ lp->rr.stream.id = STRM_INVALID ;
+ lp->buf_start = (INT8_PTR)lp->rr.buff_ptr ;
+ lp->rr.buff_used = lp->rr.buff_size ;
+
+ /* save difference in case we couldn't write the whole buffer */
+ size_diff = 4 - lp->rr.buff_size;
+
+ ret_val = LP_Send( lp, TRUE ) ;
+
+ /* if we couldn't actually write the whole 4 bytes */
+ if ( size_diff && ( ret_val == SUCCESS ) )
+ {
+ /* insure tpfmt returned what we expected */
+ msassert ( size_diff == lp->rr.buff_size );
+
+ /* copy the remainder into buffer */
+ memcpy( lp->rr.buff_ptr,
+ (BYTE *)&checksum + ( 4 - size_diff ), size_diff ) ;
+
+ lp->rr.stream.id = STRM_INVALID ;
+ lp->buf_start = (INT8_PTR)lp->rr.buff_ptr ;
+ lp->rr.buff_used = size_diff ;
+
+ /* send the rest of the buffer */
+ ret_val = LP_Send( lp, TRUE ) ;
+ }
+ }
+
+ return ret_val ;
+}
+
+
+/**/
+/**
+ Name: LP_VerifyChecksumStream( checksum, lp )
+
+ Description: Consumes a checksum stream off the tape and compares the
+ checksum value stored within it to checksum value passed in.
+
+ Modified: 02/08/93 Marilyn P.
+
+ Returns: FS_CRC_FAILURE
+ FS_STREAM_NOT_FOUND
+
+ Notes:
+
+**/
+INT16 LP_VerifyChecksumStream(
+ UINT32 checksum, /* I - the checksum data to match */
+ LP_ENV_PTR lp ) /* I - the loop environment structure */
+{
+ INT16 ret_val = SUCCESS;
+ UINT32 tapeChecksum = 0;
+ INT16 size_diff;
+ UINT8 frag_buff[4];
+
+ /* if the size of the stream data is larger than the size of the */
+ /* checksum data or if this is not a checksum stream, we have a prob */
+ if ( lp->rr.stream.id != STRM_CHECKSUM_DATA ) {
+ ret_val = FS_STREAM_NOT_FOUND ;
+ } else {
+
+ /* get the checksum data itself */
+ ret_val = LP_ReceiveData( lp, 0L ) ;
+
+ if ( lp->rr.buff_size != 4 ) {
+
+ size_diff = 4 - lp->rr.buff_size;
+ memcpy( frag_buff, lp->rr.buff_ptr, lp->rr.buff_size );
+
+ ret_val = LP_ReceiveData( lp, lp->rr.buff_size );
+
+ msassert( size_diff == lp->rr.buff_size );
+
+ memcpy( &frag_buff[ 4 - size_diff], lp->rr.buff_ptr, size_diff );
+
+ memcpy( (BYTE *)&tapeChecksum, frag_buff, 4 );
+
+ } else {
+
+ /* simply copy the date to the tape checksum */
+ memcpy( (BYTE *)&tapeChecksum, lp->rr.buff_ptr, lp->rr.buff_size ) ;
+
+ }
+ /* compare the two checksums */
+ if ( tapeChecksum != checksum ) {
+ ret_val = FS_CRC_FAILURE ;
+ }
+ }
+
+ return ret_val ;
+}
+
+
+
+/*--- end of file checksum.c ---*/
diff --git a/private/utils/ntbackup/src/clearfsl.c b/private/utils/ntbackup/src/clearfsl.c
new file mode 100644
index 000000000..72d3f957f
--- /dev/null
+++ b/private/utils/ntbackup/src/clearfsl.c
@@ -0,0 +1,136 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: clearfsl.c
+
+ Description: This file contains code to release all FSEs associated
+ resources held by a BSD.
+
+
+ $Log: N:/LOGFILES/CLEARFSL.C_V $
+
+ Rev 1.4 10 Jun 1993 08:07:54 MIKEP
+enable c++
+
+ Rev 1.3 12 Aug 1991 16:00:14 STEVEN
+do not want to VM_Free NULL
+
+ Rev 1.2 12 Jun 1991 16:02:38 STEVEN
+BSDU code review
+
+ Rev 1.1 29 May 1991 17:21:30 STEVEN
+Re-Design of BSDU for New Fast File Restore
+
+ Rev 1.0 09 May 1991 13:36:54 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include <malloc.h>
+
+#include "stdtypes.h"
+#include "queues.h"
+#include "vm.h"
+
+#include "bsdu.h"
+#include "msassert.h"
+/* $end$ include list */
+
+
+/**/
+/**
+
+ Name: BSD_ClearALLFSE()
+
+ Description: This function removes all File Selection Elements from
+ a BSD. All memory allocated for every FSE in the list is released.
+
+ Modified: 5/17/1991 14:59:52
+
+ Returns: None
+
+ Notes:
+
+ See also: $/SEE( BSD_AddFSE(), BSD_RemoveFSE() )$
+
+ Declaration:
+
+**/
+VOID BSD_ClearAllFSE(
+BSD_PTR bsd ) /* I - BSD to remove FSEs from */
+{
+ FSE_PTR fse ;
+
+ msassert( bsd != NULL );
+
+ fse = (FSE_PTR)QueueHead( &(bsd->fse_q_hdr) ) ;
+
+ while ( fse != NULL ) {
+
+ BSD_RemoveFSE( fse ) ;
+ fse = (FSE_PTR)QueueHead( &(bsd->fse_q_hdr) ) ;
+
+ }
+
+ bsd->select_status = NONE_SELECTED ;
+
+}
+
+/**/
+/**
+
+ Name: BSD_ClearAllLBA()
+
+ Description: This function removes all File Selection Elements from
+ a BSD. All memory allocated for every FSE in the list is released.
+
+ Modified: 5/17/1991 15:1:58
+
+ Returns: None
+
+ Notes:
+
+ See also: $/SEE( BSD_AddFSE(), BSD_RemoveFSE() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID BSD_ClearAllLBA(
+BSD_PTR bsd ) /* I - BSD to remove FSEs from */
+{
+ BSD_HAND bsdh ;
+ VM_HDL vm_hand ;
+ VM_PTR vm_lba ;
+ VM_PTR vm_lba_next ;
+ LBA_ELEM_PTR lba ;
+
+ msassert( bsd != NULL );
+
+ bsdh = (BSD_HAND)GetQueueElemPtr( &bsd->q ) ;
+ vm_hand = bsdh->vm_hand ;
+
+ vm_lba_next = bsd->lba_vm_q_head ;
+
+ while ( vm_lba_next != 0 ) {
+
+ vm_lba = vm_lba_next ;
+
+ lba = (LBA_ELEM_PTR)VM_MemLock( vm_hand, vm_lba, VM_READ_ONLY ) ;
+ if ( lba != 0 ) {
+ vm_lba_next = lba->next ;
+ VM_MemUnLock( vm_hand, vm_lba ) ;
+
+ } else {
+ vm_lba_next = 0 ;
+ }
+
+ VM_Free( vm_hand, vm_lba ) ;
+
+ }
+
+ bsd->lba_vm_q_head = 0 ;
+ bsd->lba_vm_q_tail = 0 ;
+
+}
diff --git a/private/utils/ntbackup/src/cli_stub.c b/private/utils/ntbackup/src/cli_stub.c
new file mode 100644
index 000000000..41fabaa9d
--- /dev/null
+++ b/private/utils/ntbackup/src/cli_stub.c
@@ -0,0 +1,72 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: cli_stub.c
+
+ Description: Functions to handle critical sections
+
+ $Log: P:/LOGFILES/CLI_STUB.C_V $
+
+ Rev 1.0 17 Jan 1992 17:18:00 STEVEN
+Initial revision.
+
+**/
+/* begin include list */
+#include "stdtypes.h"
+#include "cli.h"
+/* $end$ include list */
+
+/**/
+/**
+
+ Name: EnableInterrupts
+
+ Description: This routine calls DosExitCritSec( )
+
+ Modified: 5/21/1990
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+BOOLEAN EnableInterrupts( )
+{
+
+ return( TRUE ) ;
+
+}
+
+/**/
+/**
+
+ Name: DisableInterrupts
+
+ Description: This routine calls DosEnterCritSec( )
+
+ Modified: 5/21/1990
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+BOOLEAN DisableInterrupts( )
+{
+
+
+ return( TRUE ) ;
+
+}
+
diff --git a/private/utils/ntbackup/src/confmisc.c b/private/utils/ntbackup/src/confmisc.c
new file mode 100644
index 000000000..da83a18b2
--- /dev/null
+++ b/private/utils/ntbackup/src/confmisc.c
@@ -0,0 +1,828 @@
+/******************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: confmisc.c
+
+ Description:
+
+ $Log: G:\ui\logfiles\confmisc.c_v $
+
+ Rev 1.19 13 Aug 1993 16:06:52 GLENN
+Ifdef'd out the catalog and data path setting part of validation for Microsoft.
+
+ Rev 1.18 08 Jul 1993 17:59:50 GLENN
+Added auto detection of DATA and CATALOG paths.
+
+ Rev 1.17 10 Jun 1993 08:16:24 MIKEP
+enable c++
+
+ Rev 1.16 07 Jun 1993 10:07:56 GLENN
+Writing out default User and Catalog data paths if none are present in INI file.
+
+ Rev 1.15 18 May 1993 14:58:02 GLENN
+Now initializing the INI file name.
+
+ Rev 1.14 30 Apr 1993 15:40:32 GLENN
+Added CDS_SetUserDataPath(), CDS_SetCatDataPath(),
+CDS_GetIniFileName(), CDS_SetIniFileName(), CDS_UsingCmdLineIni()
+for Command line INI support.
+
+ Rev 1.13 01 Nov 1992 15:44:34 DAVEV
+Unicode changes
+
+ Rev 1.12 07 Oct 1992 14:12:16 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.11 04 Oct 1992 19:32:24 DAVEV
+Unicode Awk pass
+
+ Rev 1.10 10 Sep 1992 17:50:08 DAVEV
+Integrate MikeP's changes from Microsoft
+
+ Rev 1.9 29 May 1992 15:59:16 JOHNWT
+PCH updates
+
+ Rev 1.8 23 Mar 1992 11:53:38 GLENN
+Added bad data and catalog path warning support.
+
+ Rev 1.7 09 Mar 1992 09:31:54 GLENN
+Fixed a bug in change to exe dir.
+
+ Rev 1.6 27 Feb 1992 08:38:26 GLENN
+Added SetupExePath and ChangeToExeDir functions.
+
+ Rev 1.5 23 Feb 1992 13:46:18 GLENN
+Moved INI util functions to confmisc.c
+
+ Rev 1.4 20 Jan 1992 09:28:44 GLENN
+Rewrote Set calls for user and catalog data paths.
+
+ Rev 1.3 10 Jan 1992 11:19:08 DAVEV
+16/32 bit port-2nd pass
+
+ Rev 1.2 07 Jan 1992 17:29:22 GLENN
+Added catalog data path support
+
+ Rev 1.1 26 Nov 1991 13:28:40 DAVEV
+
+ Rev 1.0 20 Nov 1991 19:19:44 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+extern CDS PermCDS;
+extern CDS TempCDS;
+
+// MODULE-WIDE VARIABLES
+
+static CHAR mwszIniFileName[ MAX_UI_SMALLRES_SIZE ] = { TEXT('\0') };
+static CHAR mwszMaynDir[ MAX_MAYN_FOLDER_SIZE ] = { TEXT('\0') };
+static LPSTR mwpBadUserPath = (LPSTR)NULL;
+static LPSTR mwpBadCatPath = (LPSTR)NULL;
+static BOOL mwfUsingCmdLineINI = FALSE;
+
+
+#define def_drv( ) TEXT('C')
+
+
+// FUNCTIONS
+
+/******************************************************************************
+
+ Name: CDS_LoadIniFileName()
+
+ Description: Load the INI file name from the resource string table.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID CDS_LoadIniFileName ( VOID )
+{
+ RSM_StringCopy ( IDS_INIFILENAME, mwszIniFileName, sizeof ( mwszIniFileName ) );
+}
+
+
+/******************************************************************************
+
+ Name: CDS_GetIniFileName()
+
+ Description: Get the INI file name from the module wide variable.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID CDS_GetIniFileName (
+
+LPSTR pszDestString,
+INT nDestStringLen )
+
+{
+ strncpy ( pszDestString, mwszIniFileName, nDestStringLen );
+}
+
+
+/******************************************************************************
+
+ Name: CDS_SetIniFileName()
+
+ Description: Set the INI file name from the passed string.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID CDS_SetIniFileName (
+
+LPSTR pszNewFileName )
+
+{
+ // Validate the file name.
+
+ if ( TRUE ) {
+ mwfUsingCmdLineINI = TRUE;
+ }
+ else {
+ mwfUsingCmdLineINI = FALSE;
+ CDS_LoadIniFileName ();
+ }
+
+ strncpy ( mwszIniFileName, pszNewFileName, sizeof ( mwszIniFileName ) );
+}
+
+
+/******************************************************************************
+
+ Name: CDS_UsingCmdLineINI()
+
+ Description: Says if we are using a command line INI.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+BOOL CDS_UsingCmdLineINI ( VOID )
+
+{
+ return mwfUsingCmdLineINI;
+}
+
+
+/******************************************************************************
+
+ Name: CDS_GetPerm()
+
+ Description: Returns address of permanent configuration structure
+ to the caller
+
+ Returns: Returns a pointer to the permanent config
+
+******************************************************************************/
+
+CDS_PTR CDS_GetPerm( )
+{
+ return &PermCDS ;
+}
+
+
+/******************************************************************************
+
+ Name: CDS_GetPermBEC()
+
+ Description: Returns address of permanent configuration structure
+ of the BACKUP ENGINE CONFIGURATION STRUCTURE.
+
+ Returns: Returns a pointer to the permanent BEC.
+
+******************************************************************************/
+
+BE_CFG_PTR CDS_GetPermBEC( )
+{
+ return PermCDS.pPermBEC ;
+}
+
+
+/******************************************************************************
+
+ Name: CDS_GetCopy()
+
+ Description: Returns a pointer to the config runtime structure
+
+ Returns: Returns a pointer to the config runtime structure
+
+******************************************************************************/
+
+CDS_PTR CDS_GetCopy( )
+{
+ return &TempCDS ;
+}
+
+
+/******************************************************************************
+
+ Name: CDS_UpdateCopy
+
+ Description: Updates the runtime config structure from the permanent
+ config
+
+ Returns: VOID
+
+******************************************************************************/
+
+VOID CDS_UpdateCopy( )
+{
+ TempCDS = PermCDS ;
+ return ;
+}
+
+
+/******************************************************************************
+
+ Name: CDS_GetDefaultDrive
+
+ Description: Returns character pointer to desired default drive
+ device name from the specified config structure
+
+ Returns: CHAR_PTR to desired device name
+
+******************************************************************************/
+
+CHAR_PTR CDS_GetDefaultDrive(
+
+ CDS_PTR conf_ptr,
+ INT16 device_num )
+
+{
+ DEF_DRIVE_ENTRY *def_drive = CDS_GetDefaultDriveList( conf_ptr ) ;
+ INT16 i = 0 ;
+
+ while ( def_drive != NULL ) {
+
+ if ( i == device_num ) {
+
+ return ( def_drive->drive_name ) ;
+ }
+
+ def_drive = def_drive->next ;
+ i++ ;
+ }
+
+ return NULL;
+}
+
+
+/******************************************************************************
+
+ Name: CDS_SetMaynFolder()
+
+ Description:
+
+ Returns:
+
+******************************************************************************/
+
+VOID CDS_SetMaynFolder( CHAR_PTR name )
+
+{
+ INT i;
+
+ strcpy( mwszMaynDir, name ) ;
+ i = strlen( name ) ;
+ if ( name[i-1] != TEXT('\\') ) {
+ strcat( mwszMaynDir, TEXT("\\") ) ;
+ }
+}
+
+
+/******************************************************************************
+
+ Name: CDS_GetMaynFolder()
+
+ Description:
+
+ Returns:
+
+******************************************************************************/
+
+CHAR_PTR CDS_GetMaynFolder( )
+
+{
+ return mwszMaynDir ;
+}
+
+
+/******************************************************************************
+
+ Name: CDS_ValidateUserDataPath ()
+
+ Description:
+
+ Returns: SUCCESS, if the path passed in was valid. Otherwise,
+ FAILURE.
+
+******************************************************************************/
+
+BOOL CDS_ValidateUserDataPath (
+
+CHAR_PTR szPath )
+
+{
+ INT i;
+ CHAR szTempPath[MAX_UI_PATH_SIZE];
+
+
+ if ( strlen ( szPath ) ) {
+ strcpy ( szTempPath, szPath ) ;
+ }
+ else {
+
+ strcpy ( CDS_GetUserDataPath (), CDS_GetExePath () );
+
+# ifndef OEM_MSOFT
+ {
+ RSM_StringCopy ( IDS_DEFDATAPATH, szTempPath, sizeof ( szTempPath ) );
+
+ strcat ( CDS_GetUserDataPath (), szTempPath );
+
+ // If the path is invalid, set the data path to the EXE path.
+
+ if ( _chdir ( CDS_GetUserDataPath () ) ) {
+
+ strcpy ( CDS_GetUserDataPath (), CDS_GetExePath () );
+ }
+
+ CDS_WriteUserDataPath ( &PermCDS );
+ }
+# endif
+
+ strcpy ( szTempPath, CDS_GetUserDataPath () );
+ }
+
+ strupr ( szTempPath );
+
+ i = strlen( szTempPath ) ;
+
+ // Now, slap a backslash on the end of the path, if there isn't one.
+
+ if ( szTempPath[i-1] != TEXT('\\') ) {
+ strcat( szTempPath, TEXT("\\") ) ;
+ }
+
+ strcpy ( CDS_GetUserDataPath (), szTempPath );
+
+ i = strlen ( szTempPath );
+
+ // If need be, temporarily remove the backslash for checking for a valid
+ // path.
+
+ if ( i > 1 && szTempPath[i-1] == TEXT('\\') && szTempPath[i-2] != TEXT(':') ) {
+ szTempPath[i-1] = TEXT('\0');
+ }
+
+ // If the path is invalid, set the data path to the EXE path.
+
+ if ( _chdir ( szTempPath ) ) {
+
+ mwpBadUserPath = (CHAR_PTR)calloc ( sizeof ( CHAR ), strlen ( CDS_GetUserDataPath () ) + 1 );
+ strcpy ( mwpBadUserPath, CDS_GetUserDataPath () );
+ strcpy ( CDS_GetUserDataPath (), CDS_GetExePath () );
+ return FAILURE;
+ }
+
+ return SUCCESS;
+
+}
+
+
+/******************************************************************************
+
+ Name: CDS_GetUserDataPath()
+
+ Description:
+
+ Returns:
+
+******************************************************************************/
+
+CHAR_PTR CDS_GetUserDataPath ( VOID )
+
+{
+ return PermCDS.data_path;
+}
+
+
+/******************************************************************************
+
+ Name: CDS_SetUserDataPath()
+
+ Description:
+
+ Returns:
+
+******************************************************************************/
+
+VOID CDS_SetUserDataPath (
+
+CHAR_PTR pszNewPath )
+
+{
+ strncpy ( PermCDS.data_path, pszNewPath, sizeof ( PermCDS.data_path ) );
+}
+
+
+/******************************************************************************
+
+ Name: CDS_ValidateCatDataPath ()
+
+ Description:
+
+ Returns: SUCCESS, if the path passed in was valid. Otherwise,
+ FAILURE.
+
+******************************************************************************/
+
+BOOL CDS_ValidateCatDataPath (
+
+CHAR_PTR szPath )
+
+{
+ INT i;
+ CHAR szTempPath[MAX_UI_PATH_SIZE];
+
+ if ( strlen ( szPath ) ) {
+ strcpy ( szTempPath, szPath ) ;
+ }
+ else {
+
+ strcpy ( CDS_GetCatDataPath (), CDS_GetExePath () );
+
+# ifndef OEM_MSOFT
+ {
+ RSM_StringCopy ( IDS_DEFCATPATH, szTempPath, sizeof ( szTempPath ) );
+
+ strcat ( CDS_GetCatDataPath (), szTempPath );
+
+ // If the path is invalid, set the data path to the DATA path.
+
+ if ( _chdir ( CDS_GetCatDataPath () ) ) {
+
+ strcpy ( CDS_GetCatDataPath (), CDS_GetUserDataPath () );
+ }
+
+ CDS_WriteCatDataPath ( &PermCDS );
+ }
+# endif
+
+ strcpy ( szTempPath, CDS_GetCatDataPath () );
+ }
+
+ strcpy ( szTempPath, szPath ) ;
+ strupr ( szTempPath );
+
+ i = strlen( szTempPath ) ;
+
+ // Now, slap a backslash on the end of the path, if there isn't one.
+
+ if ( szTempPath[i-1] != TEXT('\\') ) {
+ strcat( szTempPath, TEXT("\\") ) ;
+ }
+
+ strcpy ( CDS_GetCatDataPath (), szTempPath );
+
+ i = strlen ( szTempPath );
+
+ // If need be, temporarily remove the backslash for checking for a valid
+ // path.
+
+ if ( i > 1 && szTempPath[i-1] == TEXT('\\') && szTempPath[i-2] != TEXT(':') ) {
+ szTempPath[i-1] = TEXT('\0');
+ }
+
+ // If the path is invalid, set the data path to the User Data path.
+
+ if ( _chdir ( szTempPath ) ) {
+
+ mwpBadCatPath = (CHAR_PTR)calloc ( sizeof ( CHAR ), strlen ( CDS_GetCatDataPath () ) + 1 );
+ strcpy ( mwpBadCatPath, CDS_GetCatDataPath () );
+ strcpy ( CDS_GetCatDataPath (), CDS_GetUserDataPath () );
+ return FAILURE;
+ }
+
+ return SUCCESS;
+
+}
+
+
+/******************************************************************************
+
+ Name: CDS_GetCatDataPath()
+
+ Description:
+
+ Returns:
+
+******************************************************************************/
+
+CHAR_PTR CDS_GetCatDataPath ( VOID )
+
+{
+ return PermCDS.cat_path;
+}
+
+
+/******************************************************************************
+
+ Name: CDS_SetCatDataPath()
+
+ Description:
+
+ Returns:
+
+******************************************************************************/
+
+VOID CDS_SetCatDataPath (
+
+CHAR_PTR pszNewPath )
+
+{
+ strncpy ( PermCDS.cat_path, pszNewPath, sizeof ( PermCDS.cat_path ) );
+}
+
+
+/******************************************************************************
+
+ Name: CDS_GetExePath()
+
+ Description:
+
+ Returns:
+
+******************************************************************************/
+
+CHAR_PTR CDS_GetExePath ( VOID )
+
+{
+ return gb_exe_path;
+}
+
+
+/*****************************************************************************
+
+ Name: CDS_SetupExePath ()
+
+ Description: This function initializes the global exe path and the
+ gb_exe_fname globals.
+
+ Returns: Nothing.
+
+*****************************************************************************/
+
+VOID CDS_SetupExePath ( VOID )
+
+{
+ LPSTR pIndex ;
+
+ // Get the .EXE path
+
+ GetModuleFileName ( (HMODULE)ghInst, CDS_GetExePath (), MAX_UI_PATH_LEN );
+
+ pIndex = strrchr ( CDS_GetExePath (), TEXT('\\') );
+ pIndex++;
+ strcpy( gb_exe_fname, pIndex ) ;
+ *pIndex = TEXT('\0');
+
+ if (GetTempPath( MAX_UI_PATH_LEN, gb_exe_path ) > MAX_UI_PATH_LEN ) {
+ GetCurrentDirectory( MAX_UI_PATH_LEN, gb_exe_path ) ;
+ }
+
+
+} /* end CDS_SetupExePath() */
+
+
+/*****************************************************************************
+
+ Name: CDS_ChangeToExeDir ()
+
+ Description: This function sets the current directory to the executable
+ directory.
+
+ Returns: Nothing.
+
+*****************************************************************************/
+
+VOID CDS_ChangeToExeDir ( VOID )
+
+{
+ CHAR szTempPath[MAX_UI_PATH_SIZE];
+ LPSTR pIndex ;
+
+
+ // Get the .EXE path
+
+ GetModuleFileName ( (HMODULE)ghInst, szTempPath, sizeof ( szTempPath ) );
+
+ pIndex = strrchr ( szTempPath, TEXT('\\') );
+ *pIndex = TEXT('\0');
+
+ _chdir ( szTempPath );
+
+} /* end CDS_ChangeToExeDir() */
+
+
+/******************************************************************************
+
+ Name: CDS_CheckForBadPaths()
+
+ Description:
+
+ Returns:
+
+******************************************************************************/
+
+VOID CDS_CheckForBadPaths ( VOID )
+
+{
+ CHAR szMessage[MAX_UI_RESOURCE_SIZE];
+
+
+ if ( mwpBadUserPath ) {
+
+ RSM_Sprintf ( szMessage, ID(IDS_BADUSERDATAPATH), mwpBadUserPath, CDS_GetUserDataPath () );
+ WM_MsgBox ( ID(IDS_APPNAME), szMessage, WMMB_OK, WMMB_ICONEXCLAMATION );
+ free ( mwpBadUserPath );
+ }
+
+ if ( mwpBadCatPath ) {
+
+ RSM_Sprintf ( szMessage, ID(IDS_BADCATDATAPATH), mwpBadCatPath, CDS_GetCatDataPath () );
+ WM_MsgBox ( ID(IDS_APPNAME), szMessage, WMMB_OK, WMMB_ICONEXCLAMATION );
+ free ( mwpBadCatPath );
+ }
+
+} /* end CDS_CheckForBadPaths() */
+
+
+/******************************************************************************
+
+ Name: CDS_GetLongInt ()
+
+ Description: Gets a 32-bit integer or hexidecimal number from the
+ private profile file.
+
+ Returns: The integer or the default value.
+
+******************************************************************************/
+
+DWORD CDS_GetLongInt (
+
+LPSTR pAppName, // I - application name
+LPSTR pKeyName, // I - key name
+DWORD dwDefault ) // I - default value
+
+{
+ CHAR pLine[20];
+ INT nBytes;
+ LPSTR p;
+
+ nBytes = GetPrivateProfileString( pAppName, pKeyName, TEXT(""), pLine, 20, mwszIniFileName );
+
+ if ( nBytes > 0 ) {
+
+ p = strlwr ( pLine );
+
+ CDS_SkipBlanks ( p );
+
+ if ( strstr ( p, TEXT("0x") ) ) {
+ p++;p++;
+ sscanf ( p, TEXT("%lx"), &dwDefault );
+ }
+ else {
+ sscanf ( p, TEXT("%lu"), &dwDefault );
+ }
+ }
+
+ return dwDefault;
+
+
+} /* end CDS_GetLongInt() */
+
+
+/******************************************************************************
+
+ Name: CDS_SaveInt ()
+
+ Description: Saves an integer in decimal format to the private
+ profile file.
+
+ Returns: FALSE, if successful. Otherwise, TRUE.
+
+******************************************************************************/
+
+BOOL CDS_SaveInt (
+
+LPSTR pAppName, // I - application name
+LPSTR pKeyName, // I - key name
+DWORD dwValue ) // I - value to save
+
+{
+ CHAR pLine[20];
+
+ sprintf ( pLine, TEXT("%lu"), dwValue );
+
+ return WritePrivateProfileString( pAppName, pKeyName, pLine, mwszIniFileName );
+
+
+} /* end CDS_SaveHexInt() */
+
+
+/******************************************************************************
+
+ Name: CDS_SaveHexInt ()
+
+ Description: Saves an integer in hexadecimal format to the private
+ profile file.
+
+ Returns: FALSE, if successful. Otherwise, TRUE.
+
+******************************************************************************/
+
+BOOL CDS_SaveHexInt (
+
+LPSTR pAppName, // I - application name
+LPSTR pKeyName, // I - key name
+DWORD dwValue ) // I - value to save
+
+{
+ CHAR pLine[20];
+
+ sprintf ( pLine, TEXT("0x%lx"), dwValue );
+
+ return WritePrivateProfileString( pAppName, pKeyName, pLine, mwszIniFileName );
+
+
+} /* end CDS_SaveHexInt() */
+
+
+/******************************************************************************
+
+ Name: CDS_GetString ()
+
+ Description: Saves an integer in hexadecimal format to the private
+ profile file.
+
+ Returns: The number of characters copied into the buffer.
+
+******************************************************************************/
+
+INT CDS_GetString (
+
+LPSTR pAppName, // I - application name
+LPSTR pKeyName, // I - key name
+LPSTR pDefault, // I - default string
+LPSTR pString, // I - destination string
+INT nSize ) // I - destination string size
+
+{
+ return GetPrivateProfileString ( pAppName,
+ pKeyName,
+ pDefault,
+ pString,
+ nSize,
+ mwszIniFileName
+ );
+
+} /* end CDS_GetString() */
+
+
+/******************************************************************************
+
+ Name: CDS_SaveString ()
+
+ Description: Saves an string to the private profile file.
+
+ Returns: FALSE, if successful. Otherwise, TRUE.
+
+******************************************************************************/
+
+BOOL CDS_SaveString (
+
+LPSTR pAppName, // I - application name
+LPSTR pKeyName, // I - key name
+LPSTR pString ) // I - string to save
+
+{
+ return WritePrivateProfileString ( pAppName,
+ pKeyName,
+ pString,
+ mwszIniFileName
+ );
+
+} /* end CDS_SaveString() */
diff --git a/private/utils/ntbackup/src/critstub.c b/private/utils/ntbackup/src/critstub.c
new file mode 100644
index 000000000..c28a6552a
--- /dev/null
+++ b/private/utils/ntbackup/src/critstub.c
@@ -0,0 +1,65 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: critstub.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Stubs out critical error functions.
+
+ $Log: N:/LOGFILES/CRITSTUB.C_V $
+
+ Rev 1.0 04 Jun 1991 19:19:16 BARRY
+Initial revision.
+
+
+**/
+/* begin include list */
+
+#include "stdtypes.h"
+#include "crit_err.h"
+
+/**
+
+ Name: InitCritErrorHandler()
+
+ Description: Makes any initializations neccessary for the
+ critical error handler.
+
+ Modified:
+
+ Returns: Nothing
+
+ Notes:
+
+**/
+/* begin declaration */
+VOID InitCritErrorHandler( BOOLEAN (*crit_err)( CHAR_PTR, UINT16 ) )
+{
+ uw_crit_err = crit_err ; /* Go ahead and assign UI function ptr */
+ uw_critical_error = FALSE ;
+}
+
+/**/
+
+/**
+
+ Name: DeInitCritErrorHandler()
+
+ Description: Does anything necessary to remove the critical
+ error handler.
+
+ Modified:
+
+ Returns: Nothing
+
+ Notes:
+
+**/
+/* begin declaration */
+VOID DeInitCritErrorHandler( VOID )
+{
+ uw_crit_err = NULL ;
+}
+
diff --git a/private/utils/ntbackup/src/crptfile.bmp b/private/utils/ntbackup/src/crptfile.bmp
new file mode 100644
index 000000000..7683f5a70
--- /dev/null
+++ b/private/utils/ntbackup/src/crptfile.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/ctbrkstb.c b/private/utils/ntbackup/src/ctbrkstb.c
new file mode 100644
index 000000000..a400c35c7
--- /dev/null
+++ b/private/utils/ntbackup/src/ctbrkstb.c
@@ -0,0 +1,69 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: ctbrkdos.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Stubbed control-break handler.
+
+ $Log: N:/LOGFILES/CTBRKSTB.C_V $
+
+ Rev 1.0 04 Jun 1991 19:19:20 BARRY
+Initial revision.
+
+
+**/
+/* begin include list */
+
+#include "stdtypes.h"
+
+/* $end$ include list */
+
+
+/**/
+/**
+
+ Name: BE_InstallCtrlBreakHandler()
+
+ Description: Installs the control-break and control-c handlers.
+
+ Modified:
+
+ Notes:
+
+ See also: $/SEE(be_init.c)$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID BE_InstallCtrlBreakHandler( VOID )
+{
+ /* Do nothing */
+}
+
+/**/
+
+/**
+
+ Name: BE_RemoveCtrlBreakHandler()
+
+ Description: Removes the control-break and control-c handlers.
+
+ Modified:
+
+ Notes:
+
+ See also: $/SEE(be_init.c)$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID BE_RemoveCtrlBreakHandler( VOID )
+{
+ /* Do nothing */
+}
+
diff --git a/private/utils/ntbackup/src/cursors.rc b/private/utils/ntbackup/src/cursors.rc
new file mode 100644
index 000000000..24ec35ff3
--- /dev/null
+++ b/private/utils/ntbackup/src/cursors.rc
@@ -0,0 +1,40 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: cursors.rc
+
+ Description: This file contains the references to cursor resources for
+ the Windows GUI Project Resource File.
+
+ $Log: G:/UI/LOGFILES/CURSORS.RCV $
+
+ Rev 1.2 20 Aug 1992 08:58:42 GLENN
+ ifdef'd unused NT cursors.
+
+ Rev 1.1 26 Mar 1992 08:52:50 GLENN
+ Added new pen.
+
+ Rev 1.0 20 Nov 1991 19:17:22 SYSTEM
+ Initial revision.
+
+******************************************************************************/
+
+// CURSORS -- ID's are defined in the Resource Manager header file 'ss_rsm.h'
+
+
+# if !defined ( OEM_MSOFT )
+
+ IDRC_PEN CURSOR pen.cur // Pen cursor.
+ IDRC_PEN2 CURSOR pen2.cur // Pen cursor up-side-down.
+ IDRC_HAND CURSOR hand.cur // Hand cursor.
+
+# endif // !defined ( OEM_MSOFT )
+
+// COMMON CURSORS
+
+IDRC_HSLIDER CURSOR hslider.cur // Horizontal slider cursor.
+IDRC_HELP CURSOR help.cur // Help's question mark cursor.
+
+
diff --git a/private/utils/ntbackup/src/d_about.c b/private/utils/ntbackup/src/d_about.c
new file mode 100644
index 000000000..15f372686
--- /dev/null
+++ b/private/utils/ntbackup/src/d_about.c
@@ -0,0 +1,1200 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: d_about.c
+
+ Description: Contains dialog proc for about box.
+
+ $Log: J:\ui\logfiles\d_about.c_v $
+
+ Rev 1.28.1.3 14 Jan 1994 14:37:26 GREGG
+Changed Conner to Arcada.
+
+ Rev 1.28.1.2 03 Dec 1993 11:36:54 GREGG
+Removed TEXT macro from around string defines which already have TEXT macro.
+
+ Rev 1.28.1.1 17 Sep 1993 16:37:52 BARRY
+Put Unicode/Ascii in our internal builds so we can tell the difference.
+
+ Rev 1.28.1.0 18 Aug 1993 19:36:32 BARRY
+Added our version/er information to about box when we build it.
+
+ Rev 1.28 29 Jun 1993 17:34:02 GLENN
+Added new style about box support.
+
+ Rev 1.27 11 Jun 1993 14:10:00 MIKEP
+c++ enable
+
+ Rev 1.25 09 Apr 1993 14:09:04 GLENN
+Commented out credit scroll.
+
+ Rev 1.24 01 Nov 1992 15:50:50 DAVEV
+Unicode changes
+
+ Rev 1.23 07 Oct 1992 13:31:46 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.22 04 Oct 1992 19:34:54 DAVEV
+Unicode Awk pass
+
+ Rev 1.21 28 Sep 1992 17:06:26 GLENN
+MikeP changes (ifdef stuff).
+
+ Rev 1.20 09 Sep 1992 17:05:44 GLENN
+Commented out sales pitch stuff - NOT yet defined.
+
+ Rev 1.19 04 Sep 1992 18:08:42 CHUCKB
+Added new string (sales pitch).
+
+ Rev 1.18 02 Sep 1992 13:56:48 GLENN
+Added the TDH revision to the about box.
+
+ Rev 1.17 25 Aug 1992 13:12:06 CHUCKB
+Checked in by GLENN for CHUCKB.
+
+ Rev 1.16 19 Aug 1992 14:12:20 CHUCKB
+Added memory/resources/etc. feature.
+
+ Rev 1.15 17 Aug 1992 13:16:34 DAVEV
+MikeP's changes at Microsoft
+
+ Rev 1.14 10 Jun 1992 10:22:58 JOHNWT
+removed easter egg for oem
+
+ Rev 1.13 29 May 1992 15:47:20 JOHNWT
+PCH update
+
+ Rev 1.12 27 Apr 1992 17:32:06 JOHNWT
+alphabetized names
+
+ Rev 1.11 27 Apr 1992 16:19:14 JOHNWT
+added more names & alt+f4
+
+ Rev 1.10 24 Apr 1992 16:49:36 GLENN
+Maked kooler.
+
+ Rev 1.9 22 Apr 1992 18:02:40 GLENN
+Added shark and diver sprites.
+
+ Rev 1.8 15 Apr 1992 18:50:18 GLENN
+Added Easter Egg.
+
+ Rev 1.7 09 Apr 1992 17:51:56 GLENN
+Using global exe version and eng release versions now.
+
+ Rev 1.6 07 Apr 1992 15:41:14 GLENN
+Added code to show icon in upper left corner.
+
+ Rev 1.5 27 Mar 1992 11:20:34 GLENN
+Updated temp.
+
+ Rev 1.4 26 Mar 1992 17:03:34 GLENN
+Still going...
+
+ Rev 1.3 23 Mar 1992 15:56:12 GLENN
+In process of making kool...
+
+ Rev 1.2 20 Jan 1992 09:38:12 CARLS
+added a call to DM_CenterDialog
+
+ Rev 1.1 16 Dec 1991 11:56:58 CHUCKB
+Added include windows.h.
+
+ Rev 1.0 20 Nov 1991 19:26:58 SYSTEM
+Initial revision.
+
+*****************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+#define TRIGGER_PULLED 4
+#define SPIN_FORWARD 1
+#define SPIN_BACKWARD 2
+#define SPIN_CYCLES 4
+#define LINE_HEIGHT 16
+#define NUM_LINES 37
+#define NUM_LINES_TO_SCROLL ( NUM_LINES + 6 )
+#define TAIL_DELAY 3
+#define FEET_HAUL_BUTT 1
+#define FEET_CRUISE 2
+#define FEET_TAKE_IT_EASY 3
+
+#define ICONX 12
+#define ICONY 5
+#define ICONSIZE 42
+
+#define MAX_REG_VALUE 128
+
+// MODULE WIDE VARIABLES
+
+static INT mwnTrigger = 0;
+static BOOL mwfHotMouse = FALSE;
+static BOOL mwfAnimating = FALSE;
+static INT mwnLine = 0;
+static INT mwnVScroll = 0;
+static WORD mwwType = 0;
+static INT mwnLastSlideNumber = 0;
+static INT mwnCycles = 0;
+static CHAR_PTR mwszHackCode = TEXT("SHARK");
+static LPSTR mwpHackChar;
+static RECT mwrcClient;
+static RECT mwrcOcean;
+static RECT mwrcShark;
+static RECT mwrcIcon;
+static INT mwnLastSharkNumber = 0;
+static BOOL mwfMoveShark;
+static BOOL mwfMoveSharkTail;
+static INT mwnSharkPos;
+static INT mwnTailDelay;
+static WORD mwwSharkID = IDRBM_SHARK1;
+
+static INT mwnLastDiverNumber = 0;
+static BOOL mwfMoveDiver;
+static BOOL mwfMoveDiverFeet;
+static INT mwnDiverPos;
+static INT mwnFeetDelay;
+static INT mwnFeetSpeed;
+static WORD mwwDiverID = IDRBM_DIVER1;
+
+static HBRUSH mwhBrushBlue;
+
+// PRIVATE FUNCTIONS
+
+static VOID AB_InitVersionBox ( HWND );
+static VOID AB_AnimateBox ( HWND );
+static VOID AB_KillAnimation ( HWND );
+static VOID AB_SpinIcon ( HWND );
+static BOOL AB_ScrollCredits ( HWND );
+static LPSTR AddCommas ( LPSTR, DWORD );
+static VOID BytesToK ( DWORD * );
+
+
+
+VOID WM_ConvertToDialogRect ( LPRECT );
+
+#if !defined ( OEM_MSOFT ) //unsupported feature
+
+static CHAR_PTR Credits[NUM_LINES] =
+{
+ TEXT(""),
+ TEXT(""),
+ TEXT(""),
+ TEXT(""),
+ TEXT("* Design *"),
+ TEXT(""),
+ TEXT(""),
+ TEXT("P"),
+ TEXT(""),
+ TEXT(""),
+ TEXT(""),
+ TEXT("* Software Engineers *"),
+ TEXT(""),
+ TEXT(""),
+ TEXT(""),
+ TEXT(""),
+ TEXT(""),
+ TEXT(""),
+ TEXT("* Testing and Quality *"),
+ TEXT(""),
+ TEXT(""),
+ TEXT(""),
+ TEXT(""),
+ TEXT("* Help and Documentation *"),
+ TEXT(""),
+ TEXT(""),
+ TEXT(""),
+ TEXT("* Graphics *"),
+ TEXT(""),
+ TEXT(""),
+ TEXT("* Special Thanks To *"),
+ TEXT(""),
+ TEXT(""),
+ TEXT(""),
+ TEXT(""),
+ TEXT(""),
+ TEXT("")
+};
+
+#endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+/***************************************************
+
+ Name: DM_AboutWinter ()
+
+ Description: Dialog proc for the About dialog.
+
+ Modified:
+
+ Returns: Boolean true if message was processed.
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+DLGRESULT APIENTRY DM_AboutWinter (
+ HWND hDlg, //I - window handle
+ MSGID wMsg, //I - message id
+ MPARAM1 mp1, //I - message parameter
+ MPARAM2 mp2 ) //I - message paramerer
+{
+
+ switch ( wMsg ) {
+
+ case WM_INITDIALOG: {
+
+ DM_CenterDialog( hDlg );
+
+ mwnTrigger = 0;
+ mwfHotMouse = FALSE;
+ mwnLine = 0;
+ mwnVScroll = 0;
+
+#if !defined ( OEM_MSOFT ) //unsupported feature
+
+ RSM_BitmapLoad ( IDRBM_SHARK1, RSM_MAGICCOLOR );
+ RSM_BitmapLoad ( IDRBM_SHARK2, RSM_MAGICCOLOR );
+ RSM_BitmapLoad ( IDRBM_SHARK3, RSM_MAGICCOLOR );
+ RSM_BitmapLoad ( IDRBM_DIVER1, RSM_MAGICCOLOR );
+ RSM_BitmapLoad ( IDRBM_DIVER2, RSM_MAGICCOLOR );
+ RSM_BitmapLoad ( IDRBM_DIVER3, RSM_MAGICCOLOR );
+
+#endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ mwhBrushBlue = CreateSolidBrush ( RGB(0,0,0xFF) );
+
+ AB_InitVersionBox ( hDlg );
+
+ break;
+ }
+
+ case WM_SETFOCUS:
+
+ if ( mwfHotMouse ) {
+ return 1;
+ }
+
+ SetFocus ( GetDlgItem ( hDlg, IDOK ) );
+
+ break;
+
+#if !defined ( OEM_MSOFT ) //unsupported feature
+
+// case WM_KEYDOWN:
+//
+// // Look for the SHARK.
+//
+// if ( mwfHotMouse ) {
+//
+// if ( LOWORD(mp1) == (WORD)( LOBYTE ( VkKeyScan ( *mwpHackChar ) ) ) ) {
+// mwpHackChar++;
+// }
+// else {
+// mwpHackChar = mwszHackCode;
+// }
+//
+// if ( ! *mwpHackChar ) {
+// mwnTrigger = TRIGGER_PULLED;
+// mwpHackChar = mwszHackCode;
+// }
+// }
+//
+// break;
+//
+// case WM_LBUTTONUP:
+//
+// if ( mwfHotMouse ) {
+//
+// mwpHackChar = mwszHackCode;
+// mwfHotMouse = FALSE;
+// SetFocus ( hDlg );
+// }
+//
+// break;
+//
+// case WM_LBUTTONDOWN: {
+//
+// RECT Rect;
+// POINT Point;
+//
+// Point.x = LOWORD( mp2 );
+// Point.y = HIWORD( mp2 );
+//
+// GetClientRect ( hDlg, &Rect );
+//
+// Rect.top = Rect.bottom - 20;
+// Rect.right = Rect.left + 20;
+//
+// if ( Point.x >= Rect.left && Point.x <= Rect.right &&
+// Point.y >= Rect.top && Point.y <= Rect.bottom ) {
+//
+// mwpHackChar = mwszHackCode;
+// mwfHotMouse = TRUE;
+// SetFocus ( hDlg );
+// }
+//
+// break;
+// }
+//
+// case WM_LBUTTONDBLCLK: {
+//
+// RECT Rect;
+// POINT Point;
+//
+// Point.x = LOWORD( mp2 );
+// Point.y = HIWORD( mp2 );
+//
+// Rect = mwrcIcon;
+//
+// if ( Point.x >= Rect.left && Point.x <= Rect.right &&
+// Point.y >= Rect.top && Point.y <= Rect.bottom ) {
+//
+// if ( TRUE ) { // if ( mwnTrigger == TRIGGER_PULLED ) {
+//
+// AB_AnimateBox ( hDlg );
+// }
+// }
+//
+//
+// break;
+// }
+
+#endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ case WM_PAINT: {
+
+ HDC hDC;
+ PAINTSTRUCT ps;
+
+ hDC = BeginPaint( hDlg, &ps );
+ // DrawIcon ( hDC, mwrcIcon.left, mwrcIcon.top, RSM_IconLoad ( IDRI_WNTRPARK ) );
+ EndPaint( hDlg, &ps );
+
+ break;
+ }
+
+ case WM_TIMER:
+
+ AB_SpinIcon ( hDlg );
+
+ break;
+
+ case WM_COMMAND:
+
+ switch ( GET_WM_COMMAND_ID ( mp1, mp2 ) ) {
+
+ case IDOK:
+ case IDCANCEL:
+
+ AB_KillAnimation ( hDlg );
+ EndDialog ( hDlg, 0 );
+
+#if !defined ( OEM_MSOFT ) //unsupported feature
+
+ RSM_BitmapFree ( IDRBM_SHARK1 );
+ RSM_BitmapFree ( IDRBM_SHARK2 );
+ RSM_BitmapFree ( IDRBM_SHARK3 );
+ RSM_BitmapFree ( IDRBM_DIVER1 );
+ RSM_BitmapFree ( IDRBM_DIVER2 );
+ RSM_BitmapFree ( IDRBM_DIVER3 );
+
+#endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ DeleteObject ( mwhBrushBlue );
+
+ return TRUE;
+ break;
+
+
+ default:
+ return FALSE;
+ }
+
+ break;
+
+ default:
+
+ return FALSE;
+ }
+
+ return FALSE;
+}
+
+
+LPSTR AddCommas (
+
+LPSTR szBuf,
+DWORD dw )
+
+{
+ CHAR szTemp[40];
+ LPSTR pTemp;
+ INT count, len;
+ LPSTR p;
+
+ len = wsprintf(szTemp, TEXT("%ld"), dw);
+
+ pTemp = szTemp + len - 1;
+
+ p = szBuf + len + ((len - 1) / 3);
+
+ *p-- = 0;
+
+ count = 1;
+
+ while (pTemp >= szTemp) {
+ *p-- = *pTemp--;
+ if (count == 3) {
+ count = 1;
+ if (p > szBuf)
+ *p-- = TEXT(',');
+ } else
+ count++;
+ }
+
+ return szBuf;
+}
+
+
+VOID BytesToK (
+
+DWORD *pDW )
+
+{
+ *pDW = *pDW / 1024 ;
+// *((WORD *)pDW) = (LOWORD(*pDW) >> 10) + (HIWORD(*pDW) << 6);
+// *(((WORD *)pDW)+1) >>= 10;
+}
+
+
+
+static VOID AB_InitVersionBox (
+
+HWND hDlg )
+
+{
+#ifdef OS_WIN32
+
+
+ CHAR szBuffer[64];
+ CHAR szMessage[128];
+ CHAR szNumBuf1[32];
+ LPSTR lpRegInfoValue = NULL;
+ CHAR szRegInfo[MAX_PATH];
+ DWORD cb;
+ HKEY hkey;
+ DWORD err;
+
+ // Set the icon.
+
+ SendDlgItemMessage ( hDlg, IDD_ABOUTICON, STM_SETICON, (WPARAM)RSM_IconLoad(IDRI_WNTRPARK), 0L );
+
+ // Set the Application Title Text string.
+
+ RSM_StringCopy ( IDS_APPNAME, szBuffer, sizeof ( szBuffer ) );
+ RSM_Sprintf ( szMessage, ID(IDS_APPTEXTSTRING), szBuffer );
+ SetDlgItemText ( hDlg, IDD_ABOUTAPPNAME, szMessage );
+
+ // Get the VERSION and LICENSE information.
+
+ {
+ RSM_StringCopy ( IDS_LICENSEINFOKEY, szRegInfo, sizeof(szRegInfo) );
+
+ if ( ! RegOpenKeyEx ( HKEY_LOCAL_MACHINE, szRegInfo, 0, KEY_READ, &hkey ) ) {
+
+ CHAR szRegItem[16];
+ CHAR szVerPart1[64];
+ CHAR szVerPart2[64];
+
+ RSM_StringCopy ( IDS_VERSIONMSG, szBuffer, sizeof(szBuffer) );
+
+ {
+ // THE MICROSOFT VERSION
+
+ RSM_StringCopy ( IDS_CURRENTVERSION, szRegInfo, sizeof(szRegInfo) );
+
+ if ( hkey ) {
+ cb = sizeof ( szVerPart1 );
+ RegQueryValueEx ( hkey, szRegInfo, 0, 0, (LPBYTE)szVerPart1, &cb );
+ }
+
+ *szVerPart2 = 0;
+
+ if ( GetSystemMetrics ( SM_DEBUG ) ) {
+ RSM_StringCopy ( IDS_DEBUG, szVerPart2, sizeof(szVerPart2) );
+ }
+ }
+
+ wsprintf ( szMessage, szBuffer, (LPSTR)szVerPart1, (LPSTR)szVerPart2 );
+
+
+// If this is the NTBACKUP application and it is an internal build (ie,
+// Microsoft is not building it) then put our version/er in the box.
+
+#if defined( OEM_MSOFT ) && defined( CONNER_SOFTWARE_BUILD )
+ wsprintf( szBuffer,
+ TEXT(" (Arcada %s build %s - %s)"),
+#if defined( UNICODE )
+ TEXT("Unicode"),
+#else
+ TEXT("ASCII"),
+#endif
+ APP_EXEVER,
+ APP_ENGREL );
+ strcat( szMessage, szBuffer );
+#endif
+
+
+ SetDlgItemText ( hDlg, IDD_ABOUTVERSION, szMessage );
+
+ cb = MAX_REG_VALUE;
+
+ if ( lpRegInfoValue = (LPSTR)LocalAlloc(LPTR, cb) ) {
+
+ // Display the User name.
+
+ RSM_StringCopy ( IDS_REGUSER, szRegInfo, sizeof(szRegInfo) );
+
+ err = RegQueryValueEx(hkey, szRegInfo, 0, 0, (LPBYTE)lpRegInfoValue, &cb);
+
+ if ( err == ERROR_MORE_DATA ) {
+ LocalFree(lpRegInfoValue);
+ lpRegInfoValue = (LPSTR)LocalAlloc(LPTR, cb);
+ err = RegQueryValueEx(hkey, szRegInfo, 0, 0, (LPBYTE)lpRegInfoValue, &cb);
+ }
+
+ if ( ! err ) {
+ SetDlgItemText ( hDlg, IDD_ABOUTUSERNAME, lpRegInfoValue );
+ }
+
+ // Display the Organization name.
+
+ RSM_StringCopy ( IDS_REGORGANIZATION, szRegInfo, sizeof(szRegInfo));
+
+ err = RegQueryValueEx(hkey, szRegInfo, 0, 0, (LPBYTE)lpRegInfoValue, &cb);
+
+ if ( err == ERROR_MORE_DATA ) {
+ LocalFree(lpRegInfoValue);
+ lpRegInfoValue = (LPSTR)LocalAlloc(LPTR, cb);
+ err = RegQueryValueEx(hkey, szRegInfo, 0, 0, (LPBYTE)lpRegInfoValue, &cb);
+ }
+
+ if ( ! err ) {
+ SetDlgItemText ( hDlg, IDD_ABOUTCOMPANYNAME, lpRegInfoValue );
+ }
+
+ LocalFree(lpRegInfoValue);
+ }
+
+ RegCloseKey ( hkey );
+ }
+ }
+
+ // The PROCESSOR stuff.
+
+ RSM_StringCopy ( IDS_PROCESSORINFOKEY, szRegInfo, sizeof(szRegInfo) );
+
+ if ( ! RegOpenKeyEx ( HKEY_LOCAL_MACHINE, szRegInfo, 0, KEY_READ, &hkey ) ) {
+
+ cb = MAX_REG_VALUE;
+
+ if ( lpRegInfoValue = (LPSTR)LocalAlloc ( LPTR, cb ) ) {
+
+ RSM_StringCopy ( IDS_PROCESSORIDENTIFIER, szRegInfo, sizeof(szRegInfo));
+
+ err = RegQueryValueEx ( hkey, szRegInfo, 0, 0, (LPBYTE)lpRegInfoValue, &cb );
+
+ if ( err == ERROR_MORE_DATA ) {
+ LocalFree ( lpRegInfoValue );
+ lpRegInfoValue = (LPSTR)LocalAlloc ( LPTR, cb );
+ err = RegQueryValueEx ( hkey, szRegInfo, 0, 0, (LPBYTE)lpRegInfoValue, &cb );
+ }
+
+ if ( ! err ) {
+ SetDlgItemText(hDlg, IDD_ABOUTPROCESSOR, lpRegInfoValue);
+ }
+
+ LocalFree ( lpRegInfoValue );
+ }
+
+ RegCloseKey ( hkey );
+ }
+
+ RSM_StringCopy ( IDS_IDENTIFIERIDENTIFIER, szRegInfo, sizeof(szRegInfo) );
+
+ if ( ! RegOpenKeyEx ( HKEY_LOCAL_MACHINE, szRegInfo, 0, KEY_READ, &hkey ) ) {
+
+ cb = MAX_REG_VALUE;
+
+ if ( lpRegInfoValue = (LPSTR)LocalAlloc ( LPTR, cb ) ) {
+
+ RSM_StringCopy ( IDS_PROCESSORIDENTIFIER, szRegInfo, sizeof(szRegInfo));
+
+ err = RegQueryValueEx ( hkey, szRegInfo, 0, 0, (LPBYTE)lpRegInfoValue, &cb );
+
+ if ( err == ERROR_MORE_DATA ) {
+ LocalFree ( lpRegInfoValue );
+ lpRegInfoValue = (LPSTR)LocalAlloc ( LPTR, cb );
+ err = RegQueryValueEx ( hkey, szRegInfo, 0, 0, (LPBYTE)lpRegInfoValue, &cb );
+ }
+
+ if ( ! err ) {
+ SetDlgItemText(hDlg, IDD_ABOUTIDENT, lpRegInfoValue);
+ }
+
+ LocalFree ( lpRegInfoValue );
+ }
+
+ RegCloseKey ( hkey );
+ }
+
+ RSM_StringCopy ( IDS_PRODUCTIDINFOKEY, szRegInfo, sizeof(szRegInfo) );
+
+ if ( ! RegOpenKeyEx ( HKEY_LOCAL_MACHINE, szRegInfo, 0, KEY_READ, &hkey ) ) {
+
+ if ( lpRegInfoValue = (LPSTR)LocalAlloc ( LPTR, cb ) ) {
+
+ RSM_StringCopy ( IDS_PRODUCTIDENTIFIER, szRegInfo, sizeof(szRegInfo));
+
+ err = RegQueryValueEx ( hkey, szRegInfo, 0, 0, (LPBYTE)lpRegInfoValue, &cb );
+
+ if ( err == ERROR_MORE_DATA ) {
+ LocalFree ( lpRegInfoValue );
+ lpRegInfoValue = (LPSTR)LocalAlloc ( LPTR, cb );
+ err = RegQueryValueEx ( hkey, szRegInfo, 0, 0, (LPBYTE)lpRegInfoValue, &cb );
+ }
+
+ if ( ! err ) {
+ SetDlgItemText(hDlg, IDD_ABOUTPRODID, lpRegInfoValue);
+ }
+
+ LocalFree ( lpRegInfoValue );
+ }
+
+ RegCloseKey ( hkey );
+ }
+
+
+ // The MEMORY stuff.
+
+ {
+ MEMORYSTATUS MemoryStatus;
+ DWORD dwTotalPhys;
+ DWORD dwAvailPhys;
+
+ MemoryStatus.dwLength = sizeof(MemoryStatus);
+ GlobalMemoryStatus(&MemoryStatus);
+ dwTotalPhys = MemoryStatus.dwTotalPhys;
+ dwAvailPhys = MemoryStatus.dwAvailPhys;
+ BytesToK(&dwTotalPhys);
+ BytesToK(&dwAvailPhys);
+
+ GetDlgItemText ( hDlg, IDD_ABOUTMEMORY, szBuffer, sizeof(szBuffer) );
+ wsprintf ( szMessage, szBuffer, AddCommas ( szNumBuf1, dwTotalPhys ) );
+ SetDlgItemText ( hDlg, IDD_ABOUTMEMORY, szMessage );
+ }
+
+#else
+
+ CHAR szString[MAX_UI_RESOURCE_SIZE*2];
+ CHAR szTemp1[MAX_UI_RESOURCE_SIZE];
+ RECT rcScroll;
+ HWND hWndText = GetDlgItem ( hDlg, IDD_ABOUT_VERSION );
+ DWORD dwFlags;
+ DWORD dwFreeMem ;
+ DWORD dwFreeMemB ;
+
+
+ // Determine the Icon location and size.
+
+ mwrcIcon.left = ICONX;
+ mwrcIcon.top = ICONY;
+ mwrcIcon.right = ICONSIZE;
+ mwrcIcon.bottom = ICONSIZE;
+
+ WM_ConvertToDialogRect( &mwrcIcon );
+
+ // Determine the shark's ocean size.
+
+ GetWindowRect ( hDlg, &mwrcClient );
+ GetWindowRect ( hWndText, &rcScroll );
+
+ mwrcOcean.top = rcScroll.bottom - mwrcClient.top - 17;
+ mwrcOcean.bottom = mwrcOcean.top + 25;
+
+ GetClientRect ( hDlg, &mwrcClient );
+
+ mwrcOcean.left = mwrcClient.left;
+ mwrcOcean.right = mwrcClient.right;
+
+ RSM_StringCopy ( ID(IDS_APPNAME), szString, sizeof ( szString ) );
+ strcat ( szString, TEXT("\012") );
+
+ RSM_Sprintf ( szTemp1, ID(IDS_APPVERSION), gszExeVer, gszEngRel );
+ strcat ( szString, szTemp1 );
+ strcat ( szString, TEXT("\012") );
+
+ if ( gb_dhw_ptr ) {
+
+ if ( gb_dhw_ptr[0].driver_label[0] == TEXT(',') ) {
+ strcat ( szString, &gb_dhw_ptr[0].driver_label[1] );
+ }
+ else {
+ strcat ( szString, &gb_dhw_ptr[0].driver_label[0] );
+ }
+
+ strcat ( szString, TEXT("\012") );
+ }
+ else {
+ strcat ( szString, TEXT("\012\012") );
+ }
+
+ strcat ( szString, TEXT("\012") );
+
+ RSM_StringCopy ( ID(IDS_COMPANY), szTemp1, sizeof ( szTemp1 ) );
+ strcat ( szString, szTemp1 );
+ strcat ( szString, TEXT("\012") );
+
+ RSM_StringCopy ( ID(IDS_COPYRIGHT), szTemp1, sizeof ( szTemp1 ) );
+ strcat ( szString, szTemp1 );
+ strcat ( szString, TEXT("\012") );
+
+ RSM_StringCopy ( ID(IDS_CONGLOMERATE), szTemp1, sizeof ( szTemp1 ) );
+ strcat ( szString, szTemp1 );
+ strcat ( szString, TEXT("\012") );
+
+ // Put in the sales pitch
+
+// RSM_StringCopy ( ID(IDS_SALESPITCH), szTemp1, sizeof ( szTemp1 ) );
+// strcat ( szString, szTemp1 );
+// strcat ( szString, "\012" );
+
+ SetDlgItemText ( (HWND)hDlg, IDD_ABOUT_VERSION, szString );
+
+ // Init the mode, memory usage, and system resources strings
+
+ dwFlags = GetWinFlags ();
+ if ( dwFlags & WF_ENHANCED ) {
+
+ RSM_StringCopy ( ID(IDS_ABOUT_ENHANCED_MODE), szTemp1, sizeof ( szTemp1 ) );
+
+ } else {
+
+ RSM_StringCopy ( ID(IDS_ABOUT_STANDARD_MODE), szTemp1, sizeof ( szTemp1 ) );
+ }
+
+ SetDlgItemText ( (HWND)hDlg, IDD_ABOUT_MODE_STR, szTemp1 );
+
+ RSM_StringCopy ( ID(IDS_ABOUT_MEMORY), szTemp1, sizeof ( szTemp1 ) );
+ SetDlgItemText ( (HWND)hDlg, IDD_ABOUT_MEM_STR, szTemp1 );
+
+ dwFreeMem = GetFreeSpace( 0 ) ;
+ dwFreeMemB = dwFreeMem / 1024 ;
+ dwFreeMemB = dwFreeMemB % 1000 ;
+
+ RSM_StringCopy ( ID(IDS_ABOUT_MEM_FORMAT), szTemp1, sizeof ( szTemp1 ) );
+ sprintf ( szString, szTemp1, (INT)(dwFreeMem / 1024000), (INT)(dwFreeMemB) ) ;
+ SetDlgItemText ( (HWND)hDlg, IDD_ABOUT_MEM_SIZ, szString );
+
+ RSM_StringCopy ( ID(IDS_ABOUT_RESOURCES), szTemp1, sizeof ( szTemp1 ) );
+ SetDlgItemText ( (HWND)hDlg, IDD_ABOUT_RES_STR, szTemp1 );
+
+ RSM_StringCopy ( ID(IDS_ABOUT_RES_FORMAT), szTemp1, sizeof ( szTemp1 ) );
+ sprintf ( szString, szTemp1, GetFreeSystemResources ( GFSR_SYSTEMRESOURCES ) ) ;
+ SetDlgItemText ( (HWND)hDlg, IDD_ABOUT_RES_SIZ, szString );
+
+#endif //!defined ( OM_WIN32 ) //unsupported feature
+}
+
+
+static VOID AB_AnimateBox (
+
+HWND hDlg )
+
+{
+ UINT hTimer;
+ HDC hDC;
+
+ if ( ! mwfAnimating ) {
+
+ mwwType = SPIN_FORWARD;
+ mwnLastSlideNumber = 0;
+ mwnCycles = 0;
+ mwnVScroll = 0;
+ mwnLine = 0;
+ mwnLastSharkNumber = 0;
+ mwfMoveShark = FALSE;
+ mwfMoveSharkTail = FALSE;
+ mwnTailDelay = 0;
+ mwnSharkPos = mwrcOcean.right;
+ mwwSharkID = IDRBM_SHARK1;
+ mwnLastDiverNumber = 0;
+ mwfMoveDiver = TRUE;
+ mwfMoveDiverFeet = FALSE;
+ mwnFeetDelay = 0;
+ mwnDiverPos = mwrcOcean.right;
+ mwwDiverID = IDRBM_DIVER1;
+ mwnFeetSpeed = FEET_CRUISE;
+
+ hDC = GetDC ( hDlg );
+ FillRect ( hDC, &mwrcOcean, mwhBrushBlue );
+ ReleaseDC ( hDlg, hDC );
+
+ hTimer = SetTimer( hDlg, (UINT)1, (UINT)80, (TIMERPROC)NULL );
+ mwfAnimating = TRUE;
+ }
+
+}
+
+
+static VOID AB_KillAnimation (
+
+HWND hDlg )
+
+{
+ HDC hDC;
+
+ if ( mwfAnimating ) {
+
+ KillTimer ( hDlg, 1 );
+ mwfAnimating = FALSE;
+
+ hDC = GetDC ( hDlg );
+ FillRect ( hDC, &mwrcOcean, ghBrushWhite );
+ ReleaseDC ( hDlg, hDC );
+
+ AB_InitVersionBox ( hDlg );
+ }
+}
+
+
+
+static VOID AB_SpinIcon (
+
+HWND hDlg )
+
+{
+ LPSTR lpIconID = IDRI_BKUP0;
+ HDC hDC;
+ HWND hWndText = GetDlgItem ( hDlg, IDD_ABOUT_VERSION );
+
+
+ switch ( mwwType ) {
+
+ case SPIN_FORWARD:
+
+ switch ( mwnLastSlideNumber ) {
+
+ case 0:
+
+ lpIconID = IDRI_BKUP0;
+ break;
+
+ case 1:
+ lpIconID = IDRI_BKUP1;
+ break;
+
+ case 2:
+ lpIconID = IDRI_BKUP2;
+ break;
+
+ case 3:
+ lpIconID = IDRI_BKUP3;
+ break;
+
+ case 4:
+ lpIconID = IDRI_BKUP4;
+ break;
+
+ case 5:
+ lpIconID = IDRI_BKUP5;
+ break;
+
+ case 6:
+ lpIconID = IDRI_BKUP6;
+ break;
+
+ case 7:
+ lpIconID = IDRI_BKUP7;
+
+ mwnCycles++;
+
+ if ( mwnCycles >= SPIN_CYCLES ) {
+
+ mwnCycles = 0;
+ mwwType = SPIN_BACKWARD;
+ }
+
+ break;
+
+ }
+
+ break;
+
+ case SPIN_BACKWARD:
+
+ switch ( mwnLastSlideNumber ) {
+
+ case 0:
+
+ lpIconID = IDRI_BKUP0;
+ break;
+
+ case 1:
+ lpIconID = IDRI_BKUP7;
+ break;
+
+ case 2:
+ lpIconID = IDRI_BKUP6;
+ break;
+
+ case 3:
+ lpIconID = IDRI_BKUP5;
+ break;
+
+ case 4:
+ lpIconID = IDRI_BKUP4;
+ break;
+
+ case 5:
+ lpIconID = IDRI_BKUP3;
+ break;
+
+ case 6:
+ lpIconID = IDRI_BKUP2;
+ break;
+
+ case 7:
+ lpIconID = IDRI_BKUP1;
+
+ mwnCycles++;
+
+ if ( mwnCycles >= SPIN_CYCLES ) {
+
+ mwnCycles = 0;
+ mwwType = SPIN_FORWARD;
+ }
+
+ break;
+
+ }
+
+ break;
+
+ }
+
+ mwnLastSlideNumber = ++mwnLastSlideNumber % 8;
+
+ if ( AB_ScrollCredits ( hWndText ) ) {
+
+ AB_KillAnimation ( hDlg );
+ lpIconID = IDRI_WNTRPARK;
+ }
+
+
+ hDC = GetDC ( hDlg );
+
+
+ // Do the Shark Thing.
+
+ if ( mwfMoveShark ) {
+
+ mwnSharkPos--;
+
+ if ( mwnSharkPos < mwrcOcean.left + 20 ) {
+// mwnSharkPos--;
+ }
+ }
+
+ if ( mwfMoveSharkTail ) {
+
+ switch ( mwnLastSharkNumber ) {
+ case 0:
+ mwwSharkID = IDRBM_SHARK1;
+ break;
+
+ case 1:
+ mwwSharkID = IDRBM_SHARK2;
+ break;
+
+ case 2:
+ mwwSharkID = IDRBM_SHARK3;
+ break;
+
+ case 3:
+ mwwSharkID = IDRBM_SHARK2;
+ break;
+
+ }
+
+ mwnLastSharkNumber = ++mwnLastSharkNumber % 4;
+
+ mwfMoveSharkTail = FALSE;
+ }
+
+
+
+ mwnTailDelay = ++mwnTailDelay % TAIL_DELAY;
+
+ if ( ! mwnTailDelay ) {
+
+ mwfMoveSharkTail = TRUE;
+ }
+
+ if ( mwnSharkPos < ( mwrcOcean.right - 100 ) ) {
+ mwfMoveDiver = TRUE;
+ mwnFeetSpeed = FEET_HAUL_BUTT;
+ mwnDiverPos--;
+ }
+
+ if ( mwfMoveShark || mwfMoveSharkTail ) {
+ RSM_BitmapDraw ( mwwSharkID, mwnSharkPos, mwrcOcean.top, 0, 0, hDC );
+ }
+
+
+ // Do the Diver Thing.
+
+ if ( mwfMoveDiver ) {
+ mwnDiverPos--;
+ }
+
+ if ( mwfMoveDiverFeet ) {
+
+ switch ( mwnLastDiverNumber ) {
+ case 0:
+ mwwDiverID = IDRBM_DIVER1;
+ break;
+
+ case 1:
+ mwwDiverID = IDRBM_DIVER2;
+ break;
+
+ case 2:
+ mwwDiverID = IDRBM_DIVER3;
+ break;
+
+ case 3:
+ mwwDiverID = IDRBM_DIVER2;
+ break;
+
+ }
+
+ mwnLastDiverNumber = ++mwnLastDiverNumber % 4;
+
+ mwfMoveDiverFeet = FALSE;
+ }
+
+ mwnFeetDelay = ++mwnFeetDelay % mwnFeetSpeed;
+
+ if ( ! mwnFeetDelay ) {
+
+ mwfMoveDiverFeet = TRUE;
+ }
+
+ if ( mwfMoveDiver || mwfMoveDiverFeet ) {
+ RSM_BitmapDraw ( mwwDiverID, mwnDiverPos, mwrcOcean.top, 0, 0, hDC );
+ }
+
+ if ( mwnDiverPos < ( mwrcOcean.right / 2 ) ) {
+ mwfMoveShark = TRUE;
+ mwfMoveDiver = FALSE;
+ mwnFeetSpeed = FEET_TAKE_IT_EASY;
+ }
+
+
+
+
+
+ FillRect ( hDC, &mwrcIcon, ghBrushWhite );
+// FillRect ( hDC, &mwrcOcean, ghBrushWhite );
+
+ DrawIcon ( hDC, mwrcIcon.left, mwrcIcon.top, RSM_IconLoad ( lpIconID ) );
+
+ ReleaseDC ( hDlg, hDC );
+ hDC = GetDC ( hDlg );
+ ReleaseDC ( hDlg, hDC );
+
+
+} /* end AB_SpinIcon() */
+
+
+static BOOL AB_ScrollCredits (
+
+HWND hWndText )
+
+{
+ RECT rcText;
+ HDC hDC;
+
+ GetClientRect ( hWndText, &rcText );
+
+ ScrollWindow ( hWndText, 0, -1, &rcText, &rcText );
+
+ mwnVScroll++;
+
+ if ( mwnVScroll == LINE_HEIGHT ) {
+
+ if ( mwnLine < NUM_LINES ) {
+
+ INT nOldBkMode;
+
+ rcText.bottom -= 5;
+ rcText.top = rcText.bottom - LINE_HEIGHT;
+
+
+ hDC = GetDC ( hWndText );
+
+ nOldBkMode = SetBkMode( hDC, TRANSPARENT );
+ SetTextColor( hDC, gColorForeGnd );
+
+#if !defined ( OEM_MSOFT ) //unsupported feature
+
+ DrawText ( hDC,
+ Credits[mwnLine],
+ -1,
+ &rcText,
+ DT_SINGLELINE | DT_VCENTER | DT_CENTER | DT_NOCLIP
+ );
+
+#endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ SetBkMode( hDC, nOldBkMode );
+
+ ReleaseDC ( hWndText, hDC );
+
+ }
+
+ mwnVScroll = 0;
+ mwnLine++;
+ }
+
+
+ return ( ( mwnLine >= NUM_LINES_TO_SCROLL ) ? TRUE : FALSE );
+
+} /* end AB_ScrollCredits() */
+
+
+VOID WM_ConvertToDialogRect (
+
+LPRECT pRect )
+
+{
+ LONG lDlgBaseUnits = GetDialogBaseUnits ();
+
+ if ( ! pRect ) {
+ return;
+ }
+
+ pRect->left = ( ( pRect->left * LOWORD(lDlgBaseUnits) ) / 4 );
+ pRect->top = ( ( pRect->top * HIWORD(lDlgBaseUnits) ) / 8 );
+
+ pRect->right = ( ( pRect->right * LOWORD(lDlgBaseUnits) ) / 4 ) + 10;
+ pRect->bottom = ( ( pRect->bottom * HIWORD(lDlgBaseUnits) ) / 8 ) + 18;
+
+} /* end WM_ConvertToDialogRect() */
+
diff --git a/private/utils/ntbackup/src/d_adv_us.c b/private/utils/ntbackup/src/d_adv_us.c
new file mode 100644
index 000000000..0043f195a
--- /dev/null
+++ b/private/utils/ntbackup/src/d_adv_us.c
@@ -0,0 +1,393 @@
+
+/***************************************************
+
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: d_adv_us.c
+
+ Description: Contains dialog proc for using file selections.
+
+ $Log: G:\ui\logfiles\d_adv_us.c_v $
+
+ Rev 1.22 21 Jul 1993 17:09:46 CARLS
+change to tbrparse call
+
+ Rev 1.21 07 Jun 1993 15:46:10 DARRYLP
+Added a wait cursor for selection processing.
+
+ Rev 1.20 05 Nov 1992 17:05:18 DAVEV
+fix ts
+
+ Rev 1.18 20 Oct 1992 10:13:42 GLENN
+Removed hardcoded APPLICATIONNAME from message boxes.
+
+ Rev 1.17 07 Oct 1992 13:33:30 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.16 04 Oct 1992 19:35:28 DAVEV
+Unicode Awk pass
+
+ Rev 1.15 15 May 1992 14:53:50 MIKEP
+nt pass 2
+
+ Rev 1.14 14 May 1992 16:42:26 MIKEP
+nt pass 2
+
+ Rev 1.13 14 Apr 1992 11:34:32 CHUCKB
+Fixed selection logging messages.
+
+ Rev 1.12 07 Apr 1992 10:56:20 CHUCKB
+Moved DM_DisplayModesMatch prototype.
+
+ Rev 1.11 23 Mar 1992 15:43:48 CHUCKB
+Fixed mapped drives found warning.
+
+ Rev 1.10 25 Feb 1992 11:35:06 JOHNWT
+handle attach error and serv/map mode
+
+ Rev 1.9 08 Feb 1992 13:38:36 MIKEP
+func name change
+
+ Rev 1.8 05 Feb 1992 09:23:18 CHUCKB
+Removed tabs and EOF's.
+
+ Rev 1.7 20 Jan 1992 10:34:34 CARLS
+added a call to DM_CenterDialog
+
+ Rev 1.6 10 Jan 1992 09:29:46 ROBG
+Modified HELPID.
+
+ Rev 1.5 09 Jan 1992 18:08:20 DAVEV
+16/32 bit port 2nd pass
+
+ Rev 1.4 08 Jan 1992 09:13:06 CHUCKB
+Fixed initialization of list box.
+
+ Rev 1.3 07 Jan 1992 15:08:14 DAVEV
+replace dos_findfirst,etc with VLM_FindFirst,etc.
+
+ Rev 1.2 16 Dec 1991 11:59:18 CHUCKB
+Added include windows.h.
+
+ Rev 1.1 25 Nov 1991 14:55:00 DAVEV
+Changes for 32-16 bit Windows port
+
+ Rev 1.0 18 Sep 1991 11:34:28 ROBG
+Initial revision.
+
+*****************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+/***************************************************
+
+ Name: DM_AdvUse ()
+
+ Description: Dialog proc for using file selections.
+
+ Modified:
+
+ Returns:
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+#ifndef OEM_MSOFT // The only user of DM_AdvUse is in dialmang.c...
+
+DLGRESULT APIENTRY DM_AdvUse (
+
+ HWND hDlg,
+ MSGID msg,
+ MPARAM1 mp1,
+ MPARAM2 mp2 )
+
+{
+ INT16 i ;
+ DWORD dRetVal ;
+ CHAR szFileName[VLM_MAXFNAME] ;
+ CHAR szPathSpec[VLM_MAXFNAME] ;
+ VLM_FIND_PTR pVlmFind = NULL;
+ CDS_PTR pPermCDS ;
+ PDS_WMINFO wininfo ;
+ HWND hwndTemp ;
+
+ UNREFERENCED_PARAMETER ( mp2 );
+
+
+ switch ( msg ) {
+
+ case WM_INITDIALOG :
+
+ DM_CenterDialog( hDlg ) ;
+
+ wsprintf ( szPathSpec, TEXT("%s%s"),
+ CDS_GetUserDataPath (), TEXT("*.bks") ) ;
+
+ // get the names of all selection files;
+ // We don't use DlgDirList because we want to truncate the file
+ // extensions. It's much easier this way.
+
+ if ( pVlmFind = VLM_FindFirst( szPathSpec, VLMFIND_NORMAL,
+ szFileName ) )
+ {
+ do {
+
+ for ( i = 0; i < 9; ++i )
+ {
+ if ( szFileName[i] == TEXT('.') ) {
+ szFileName[i] = TEXT('\0') ;
+ }
+ }
+ SendDlgItemMessage ( hDlg, IDD_SAVE_FLIST, LB_ADDSTRING,
+ (MPARAM1) 0,
+ MP2FROMPVOID (szFileName) ) ;
+
+ // once we have one, look for the next one
+
+ } while ( VLM_FindNext ( pVlmFind, szFileName ) );
+
+ VLM_FindClose ( &pVlmFind );
+ }
+ SendDlgItemMessage ( hDlg, IDD_SAVE_FLIST, LB_SETCURSEL,
+ (MPARAM1) 0, (MPARAM2) NULL ) ;
+ dRetVal = SendDlgItemMessage ( hDlg, IDD_SAVE_FLIST,
+ LB_GETTEXT,
+ (MPARAM1) 0,
+ MP2FROMPVOID ( szFileName ) ) ;
+
+ return TRUE ;
+ break ;
+
+
+ case WM_COMMAND : {
+
+ WORD wId = GET_WM_COMMAND_ID (mp1, mp2);
+ WORD wCmd = GET_WM_COMMAND_CMD (mp1, mp2);
+
+ switch ( wId ) {
+
+ case IDHELP:
+
+ HM_DialogHelp( HELPID_DIALOGSELECTUSE ) ;
+ return( TRUE ) ;
+
+ case IDD_SAVE_FNAME :
+ return TRUE ;
+
+ case IDD_SAVE_FLIST :
+
+ if ( wCmd != LBN_DBLCLK ) {
+
+ dRetVal = SendDlgItemMessage ( hDlg,
+ IDD_SAVE_FLIST,
+ LB_GETCURSEL,
+ (MPARAM1) NULL,
+ (MPARAM2) NULL ) ;
+ if ( dRetVal != LB_ERR ) {
+
+ dRetVal = SendDlgItemMessage ( hDlg,
+ IDD_SAVE_FLIST,
+ LB_GETTEXT,
+ (MPARAM1) dRetVal,
+ MP2FROMPVOID ( szFileName ) ) ;
+ }
+
+ return TRUE ;
+ }
+
+ case IDOK : {
+ WM_ShowWaitCursor( TRUE );
+ // get the name of the selection file
+
+ dRetVal = SendDlgItemMessage ( hDlg, IDD_SAVE_FLIST,
+ LB_GETCURSEL,
+ (MPARAM1) NULL,
+ (MPARAM2) NULL ) ;
+
+ // if we have a selection, parse it
+
+ if ( dRetVal != LB_ERR ) {
+
+ // get the actual text of the selection
+
+ SendDlgItemMessage ( hDlg, IDD_SAVE_FLIST,
+ LB_GETTEXT,
+ (MPARAM1) dRetVal,
+ MP2FROMPVOID ( szFileName ) ) ;
+
+ // if the user supplied an extension, null it
+
+ i = 0 ;
+ while ( i < 8 ) {
+
+ if ( szFileName[i] == TEXT('.') ) {
+ szFileName[i] = TEXT('\0') ;
+ }
+ i++ ;
+ }
+
+ // create the fully qualified path name
+
+ wsprintf ( szPathSpec, TEXT("@%s%s%s"),
+ CDS_GetUserDataPath(),
+ szFileName, TEXT(".bks") ) ;
+
+ // call the parser to do its thing
+
+ pPermCDS = CDS_GetPerm () ;
+ tbrparse ( &pPermCDS, dle_list, bsd_list, szPathSpec, TBACKUP, NULL ) ;
+
+ // remove any unused bsds and then make sure
+ // we don't have mixed mapped/server selections
+
+ VLM_RemoveUnusedBSDs ( bsd_list ) ;
+ DM_DisplayModesMatch( );
+
+ // now go through the windows to see if one needs
+ // its check marks updated.
+
+ hwndTemp = WM_GetNext ( (HWND) NULL ) ;
+
+ while ( hwndTemp != (HWND) NULL ) {
+ wininfo = WM_GetInfoPtr ( hwndTemp ) ;
+ if ( wininfo->wType == WMTYPE_DISKTREE ) {
+ VLM_RematchList ( hwndTemp ) ;
+ }
+ hwndTemp = WM_GetNext ( hwndTemp ) ;
+ }
+
+ VLM_UpdateDisks () ;
+ VLM_UpdateServers () ;
+
+#ifdef OEM_EMS // Exchange Enterprise View
+// VLM_XchgAdvSelections () ;
+#endif
+ }
+ else {
+
+ // no file selected, inform the confused user
+
+ WM_MsgBox ( NULL, (LPSTR) IDS_NOFILESSELECTED,
+ WMMB_OK, WMMB_ICONEXCLAMATION ) ;
+ }
+ WM_ShowWaitCursor( FALSE );
+ }
+
+
+ case IDCANCEL :
+
+ EndDialog (hDlg, TRUE) ;
+ return TRUE ;
+ break ;
+
+
+ default :
+
+ return FALSE ;
+ }
+ break ;
+ }
+
+ case WM_CLOSE :
+
+ EndDialog ( hDlg, (INT16) NULL ) ;
+ return TRUE ;
+ break ;
+
+ default :
+
+ return FALSE ;
+ }
+}
+
+#endif
+
+/***************************************************
+
+ Name: DM_DisplayModesMatch ( )
+
+ Description: Checks to see if mapped drives were added to the BSD
+ list when we are in server/volume mode. If so, they
+ are removed and the user informed.
+
+ Returns: VOID
+
+ Notes: If we are in mapped mode, and a selection file
+ uses server/volume connections, it is caught in
+ the parser before they log in.
+
+
+*****************************************************/
+
+VOID DM_DisplayModesMatch ( VOID )
+
+{
+ BSD_PTR pBSD ;
+ BSD_PTR pRemove_BSD ;
+ GENERIC_DLE_PTR pDLE ;
+ BOOL fPrompt = FALSE ;
+ CHAR szError[255] ;
+
+
+ // if we are in server mode, make sure no mapped drives are selected
+
+ if ( gfServers ) {
+
+ // look at each BSD and see if it is a mapped drive
+
+ pBSD = BSD_GetFirst ( bsd_list ) ;
+
+ while ( pBSD != NULL ) {
+
+ pDLE = BSD_GetDLE ( pBSD ) ;
+
+ // If it is a Novell server, and it has no parent, then it is
+ // a mapped drive
+
+ if ( ( ( DLE_GetDeviceType ( pDLE ) == NOVELL_DRV ) ||
+ ( DLE_GetDeviceType ( pDLE ) == NOVELL_AFP_DRV ) ) &&
+ ( DLE_GetParent ( pDLE ) == NULL ) ) {
+
+ pRemove_BSD = pBSD;
+ pBSD = BSD_GetNext ( pBSD ) ;
+ BSD_Remove( pRemove_BSD );
+ fPrompt = TRUE;
+
+ } else {
+
+ pBSD = BSD_GetNext ( pBSD ) ;
+
+ }
+
+ } //endwhile
+
+ // if we found a mapped drive, inform the user that those selections
+ // were invalid.
+
+ if ( fPrompt ) {
+
+ CHAR szAppName[50] ;
+
+ RSM_StringCopy( IDS_APPNAME, szAppName, sizeof ( szAppName ) ) ;
+ RSM_Sprintf( szError, ID(IDS_MAPPEDFOUND), szAppName ) ;
+
+ WM_MsgBox ( ID( IDS_NETWORKERRORCAPTION ),
+ szError,
+ WMMB_OK, WMMB_ICONEXCLAMATION ) ;
+
+ // log the error
+
+ lresprintf( LOGGING_FILE, LOG_START, FALSE ) ;
+ lprintf( LOGGING_FILE, szError ) ;
+ lresprintf( LOGGING_FILE, LOG_END ) ;
+ }
+ }
+
+ return;
+}
diff --git a/private/utils/ntbackup/src/d_attach.c b/private/utils/ntbackup/src/d_attach.c
new file mode 100644
index 000000000..eaf4eccdf
--- /dev/null
+++ b/private/utils/ntbackup/src/d_attach.c
@@ -0,0 +1,332 @@
+
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: d_attach.c
+
+ Description: Contains entry point and dialog proc for application
+ to attach to a server that is not currently attached.
+ Intended for use with restore operation when specifying
+ target drive.
+
+ $Log: G:/UI/LOGFILES/D_ATTACH.C_V $
+
+ Rev 1.24 01 Nov 1992 15:52:32 DAVEV
+Unicode changes
+
+ Rev 1.23 07 Oct 1992 13:33:44 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.22 04 Oct 1992 19:35:32 DAVEV
+Unicode Awk pass
+
+ Rev 1.21 06 Aug 1992 13:17:48 CHUCKB
+Changes for NT.
+
+ Rev 1.20 07 Jul 1992 15:31:58 MIKEP
+unicode changes
+
+ Rev 1.19 29 May 1992 15:52:32 JOHNWT
+PCH update
+
+ Rev 1.18 14 May 1992 16:40:20 MIKEP
+Nt pass 2
+
+ Rev 1.17 22 Mar 1992 12:56:20 JOHNWT
+added appname to dialog title
+
+ Rev 1.16 03 Feb 1992 14:28:04 JOHNWT
+force username entry
+
+ Rev 1.15 30 Jan 1992 09:53:38 JOHNWT
+disable help during YY
+
+ Rev 1.14 29 Jan 1992 18:22:44 CHUCKB
+Send server name to dialog instead of group box.
+
+ Rev 1.13 29 Jan 1992 11:22:42 MIKEP
+cation string to small
+
+ Rev 1.12 27 Jan 1992 00:29:12 CHUCKB
+Updated dialog id's.
+
+ Rev 1.11 20 Jan 1992 10:13:28 CARLS
+added a call to DM_CenterDialog
+
+ Rev 1.10 10 Jan 1992 09:17:42 ROBG
+Modified HELPID.
+
+ Rev 1.9 10 Jan 1992 08:36:00 JOHNWT
+fixed help logic
+
+ Rev 1.8 09 Jan 1992 18:08:46 DAVEV
+16/32 bit port 2nd pass
+
+ Rev 1.7 06 Jan 1992 11:42:04 CHUCKB
+Added help.
+
+ Rev 1.6 17 Dec 1991 17:55:00 CHUCKB
+Fixed initialization of return code.
+
+ Rev 1.5 16 Dec 1991 15:29:28 JOHNWT
+added YY countdown timer
+
+ Rev 1.4 16 Dec 1991 12:13:28 CHUCKB
+Added include windows.h.
+
+ Rev 1.3 04 Dec 1991 18:24:10 CHUCKB
+Tried to fix blank password.
+
+ Rev 1.2 01 Dec 1991 15:57:56 MIKEP
+make pointer static
+
+ Rev 1.1 25 Nov 1991 14:55:46 DAVEV
+Changes for 32-16 bit Windows port
+
+ Rev 1.0 ?? ??? 1991 ??:??:?? ??????
+Initial revision.
+
+*****************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+#define TIME_OUT_VAL 61 /* time out period for YY ops */
+
+static VOID clock_routine( VOID );
+static DS_LOGIN_PTR pdsLogin;
+
+HTIMER mw_timer_handle; /* timer used when in YY operation */
+HWND mw_hDlg; /* our dialog's handle */
+INT mw_time_out; /* time-out counter */
+
+/****************************************************************************
+
+ Name: DM_AttachToServer
+
+ Description: Entry point for the application to attach to a server
+
+ Modified: 06/10/91
+
+ Returns: 0 if user name and password has been provided and is OK.
+ 1 if password not provided.
+
+ Notes:
+
+ See also:
+
+****************************************************************************/
+
+
+BOOL DM_AttachToServer (
+
+LPSTR szServerName, // I - server name
+LPSTR szUserName, // I - user name
+INT UserNameLen, // I - length of user name
+LPSTR szPswd, // I - passWord
+INT PswdLen ) // I - length of password
+
+{
+ INT nStatus;
+ DS_LOGIN_PTR pLogin;
+
+ // put all of the input args into a structure to pass it to the dialog
+
+ pLogin = (DS_LOGIN_PTR) calloc ( 1, sizeof (struct DS_LOGIN) );
+ if ( pLogin == NULL) {
+ return FALSE;
+ }
+
+ pLogin->Server_Name = szServerName;
+ pLogin->User_Name = szUserName;
+ pLogin->User_Name_Len = UserNameLen;
+ pLogin->Password = szPswd;
+ pLogin->Password_Len = PswdLen;
+ pLogin->Ok = FALSE;
+
+ nStatus = DM_ShowDialog ( ghWndFrame, IDD_PSWD, (PVOID) pLogin );
+
+ free ( pLogin );
+
+ return ( nStatus != DM_SHOWOK ); // return false for success
+}
+
+/****************************************************************************
+
+ Name: DM_Attach
+
+ Description: This Dialog procedure allows the user to attach to
+ a server that is not currently attached
+
+ Modified:
+
+ Returns: TRUE if message was processed.
+ FALSE if message was not processed.
+
+ Notes: If the user hits Enter while the focus is on the username
+ focus gets passed to the password, and the dialog continues
+
+ See also:
+
+****************************************************************************/
+
+
+DLGRESULT APIENTRY DM_Attach (
+
+HWND hDlg , // I - Handle of the dialog.
+MSGID msg , // I - Message Infomation.
+MPARAM1 mp1 , // I - Additional message information.
+MPARAM2 mp2 ) // I - Additional message information.
+
+{
+ CHAR szCaption[ 80 ];
+ HWND hTemp;
+ INT nRetVal = DM_SHOWCANCEL;
+
+ switch ( msg ) {
+
+ case WM_INITDIALOG :
+
+ DM_CenterDialog( hDlg );
+
+ pdsLogin = (DS_LOGIN_PTR) mp2;
+
+ SendDlgItemMessage ( hDlg, IDD_USERNAME, EM_LIMITTEXT,
+ (MPARAM1) pdsLogin->User_Name_Len,
+ (MPARAM2) NULL );
+
+ SendDlgItemMessage ( hDlg, IDD_PASSWORD, EM_LIMITTEXT,
+ (MPARAM1) pdsLogin->Password_Len,
+ (MPARAM2) NULL );
+
+ // set the title of the dialog
+
+ if ( WM_IsMinimized ( ghWndFrame ) ) {
+ RSM_StringCopy ( IDS_APPMSGNAME, szCaption, 80 );
+ strcat ( szCaption, TEXT(": ") );
+ } else {
+ RSM_StringCopy ( IDS_LOGINTOSERVERCAPTION, szCaption, 80 );
+ }
+ strcat ( szCaption, pdsLogin->Server_Name );
+ SendMessage ( hDlg, WM_SETTEXT, 0, (MPARAM2) (LPSTR) szCaption );
+
+ // set username if available
+
+ SetDlgItemText ( hDlg, IDD_USERNAME, pdsLogin->User_Name );
+
+ SetFocus ( GetDlgItem ( hDlg, IDD_USERNAME ) );
+
+ /* if the YY flag is set, set up a time-out timer, disable
+ the help button since we don't monitor the help process */
+
+ if ( CDS_GetYesFlag ( CDS_GetCopy() ) == YESYES_FLAG ) {
+ mw_hDlg = hDlg;
+ mw_time_out = TIME_OUT_VAL;
+ ShowWindow( GetDlgItem( hDlg, IDD_LOGIN_TIMEBOX ), SW_SHOWNOACTIVATE );
+ ShowWindow( GetDlgItem( hDlg, IDD_LOGIN_TIMEOUT ), SW_SHOWNOACTIVATE );
+ mw_timer_handle = WM_HookTimer( clock_routine, 1 );
+ EnableWindow( GetDlgItem( hDlg, IDHELP ), FALSE ) ;
+ }
+
+ return TRUE;
+
+ case WM_COMMAND :
+
+ switch ( GET_WM_COMMAND_ID (mp1, mp2) ) {
+
+ case IDHELP :
+
+ HM_DialogHelp( HELPID_DIALOGLOGINPSWD );
+
+ return( TRUE );
+
+ case IDD_PASSWORD :
+ case IDD_USERNAME :
+
+ return TRUE;
+
+ case IDOK :
+
+ hTemp = GetFocus ( ); // if user hit enter on u-name, get pswd
+
+ if ( hTemp == GetDlgItem ( hDlg, IDD_USERNAME ) ) {
+
+ SetFocus ( GetDlgItem ( hDlg, IDD_PASSWORD ) );
+ return TRUE;
+
+ } else { // this is the 'real' OK case
+
+ // fill in the fields that get passed back to attach
+
+ if ( GetDlgItemText ( hDlg, IDD_USERNAME,
+ pdsLogin->User_Name,
+ pdsLogin->User_Name_Len ) == 0 ) {
+
+ SetFocus ( GetDlgItem ( hDlg, IDD_USERNAME ) );
+ return TRUE;
+
+ }
+
+ GetDlgItemText ( hDlg, IDD_PASSWORD,
+ pdsLogin->Password,
+ pdsLogin->Password_Len );
+
+ nRetVal = DM_SHOWOK;
+ pdsLogin->Ok = TRUE;
+
+ }
+
+ case IDCANCEL :
+
+ if ( CDS_GetYesFlag ( CDS_GetCopy() ) == YESYES_FLAG ) {
+ WM_UnhookTimer( mw_timer_handle );
+ }
+
+ EndDialog ( hDlg, nRetVal );
+ return TRUE;
+
+ default :
+ return FALSE;
+ }
+
+ break;
+ }
+
+ return FALSE;
+}
+
+
+/******************************************************************************
+
+ Name: clock_routine
+
+ Modified: 12/16/91
+
+ Description: This procedure is called to process the count-down timer.
+ The timeout text is updated with the time as it changes.
+ When the time runs out, a cancel message is sent to the
+ dialog.
+
+ Returns: none
+
+******************************************************************************/
+
+VOID clock_routine( VOID )
+{
+
+ CHAR time_remaining[3];
+
+ mw_time_out--;
+
+ if ( mw_time_out == 0 ) {
+ SendMessage( mw_hDlg, WM_COMMAND, IDCANCEL, 0L );
+ } else {
+ sprintf( time_remaining, TEXT("%d"), mw_time_out );
+ SetDlgItemText( mw_hDlg, IDD_LOGIN_TIMEOUT, time_remaining );
+ }
+
+ return;
+}
diff --git a/private/utils/ntbackup/src/d_browse.c b/private/utils/ntbackup/src/d_browse.c
new file mode 100644
index 000000000..7628ddbaa
--- /dev/null
+++ b/private/utils/ntbackup/src/d_browse.c
@@ -0,0 +1,644 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: D_BROWSE.C
+
+ Description:
+
+ $Log: G:\UI\LOGFILES\D_BROWSE.C_V $
+
+ Rev 1.28 02 Feb 1994 11:30:24 Glenn
+Added log file browse support.
+
+ Rev 1.27 17 Jan 1994 15:53:44 MIKEP
+remove unicode warnings
+
+ Rev 1.26 12 Jan 1994 21:20:20 STEVEN
+browse did not have drives that did not have labels
+
+ Rev 1.25 24 Nov 1993 15:33:04 BARRY
+Fix Unicode warning
+
+ Rev 1.24 15 Oct 1993 16:30:42 GLENN
+Eliminated drives that are not in our DLE list from common browse dlg.
+
+ Rev 1.23 21 Jul 1993 16:18:48 KEVINS
+Corrected problem with displaying of browse dialog.
+
+ Rev 1.22 18 Jun 1993 10:24:04 Aaron
+Ifdef'd ofn.Flags setting: OFN_NONETWORKBUTTON only defined for NT
+
+ Rev 1.21 11 Jun 1993 14:12:30 MIKEP
+enable c++
+
+ Rev 1.20 09 Jun 1993 11:49:38 DARRYLP
+Removed network button from browse dialog.
+
+ Rev 1.19 21 May 1993 18:15:46 KEVINS
+Replaced hard coded browse dialog box title with ID_BROWSETITLE usage.
+
+ Rev 1.18 19 May 1993 10:47:56 KEVINS
+Changed name of dialog box to just "Browse".
+
+ Rev 1.17 12 May 1993 17:57:54 KEVINS
+Correct some drive designator logic.
+
+ Rev 1.16 04 May 1993 10:54:10 DARRYLP
+Fixed browsing directory search.
+
+ Rev 1.15 03 May 1993 10:29:36 DARRYLP
+Changed browse path in search dialog to match given path in combobox.
+
+ Rev 1.14 23 Feb 1993 16:41:32 ROBG
+Removed double click exit so double clicking on a directory
+selects it for further browsing, instead of the target.
+
+ Rev 1.13 12 Nov 1992 14:19:00 MIKEP
+fix cast for 16bit brain dead os
+
+ Rev 1.12 01 Nov 1992 15:52:46 DAVEV
+Unicode changes
+
+ Rev 1.11 07 Oct 1992 13:44:28 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.10 04 Oct 1992 19:35:34 DAVEV
+Unicode Awk pass
+
+ Rev 1.9 17 Sep 1992 17:39:34 DAVEV
+minor fix (strsiz->strsize)
+
+ Rev 1.8 17 Sep 1992 15:50:52 DAVEV
+UNICODE modifications: strlen usage check
+
+ Rev 1.7 17 Aug 1992 13:17:00 DAVEV
+MikeP's changes at Microsoft
+
+ Rev 1.6 30 Jul 1992 09:50:22 STEVEN
+fix warnings
+
+ Rev 1.5 28 Jul 1992 14:45:20 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.4 26 Jun 1992 15:52:08 DAVEV
+
+
+ Rev 1.3 29 May 1992 16:01:04 JOHNWT
+PCH updates
+
+ Rev 1.2 15 May 1992 14:55:30 MIKEP
+changes
+
+ Rev 1.1 23 Apr 1992 10:14:44 DAVEV
+d_browse only compiled if OEM_MSOFT defined
+
+ Rev 1.0 06 Apr 1992 15:19:02 DAVEV
+Initial revision.
+
+*****************************************************/
+
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+#ifndef LOCALVAR
+# define LOCALVAR static
+#endif
+
+# define DRIVENAMEFORMAT TEXT("%s %s")
+
+#define DUMMY_FILE TEXT("dummy.fil")
+#define DUMMY_DRIVE TEXT("c:\\")
+#define DUMMY_PATH DUMMY_DRIVE DUMMY_FILE
+#define MAX_BROWSE_PATH_LEN 1024
+
+BOOL APIENTRY DM_BrowsePathDialogHook (HWND, MSGID, MP1, MP2);
+BOOL DM_RemoveUnknownVolumes ( HWND, INT );
+BOOL APIENTRY DM_BrowseLogPathDialogHook (HWND, MSGID, MP1, MP2);
+
+/***************************************************
+
+ Name: DM_GetBrowsePath
+
+ Description: Put up a dialog to allow the user
+ to select a drive + directory
+ path.
+
+ Parameters: hWndOwner is the window to use
+ as the owner of the dialog or NULL.
+
+ pszPath contains the initial directory.
+ If pszPath points to an empty string,
+ or contains NULL, the current working
+ directory is used.
+
+ nPathLen is the length of the buffer
+ pointed to by pszPath.
+
+ Returns: TRUE - the user selected Enter
+ If pszPath is not NULL, then the
+ selected drive+path is copied into
+ the provided buffer.
+
+ FALSE - the user selected Cancel or an error
+ occurred. CommDlgExtendedError () may
+ be called to determine the error condition.
+
+ Note: The current working directory will
+ be changed to the user selected drive
+ and directory.
+
+*****************************************************/
+
+BOOL DM_GetBrowsePath (
+
+HWND hWndOwner, // I - handle dialog owner or NULL
+HINSTANCE hInstance, // I - Application Instance handle
+LPSTR pszPath, // I - Initial directory O - User selected directory
+UINT nPathLen ) // I - sizeof of pszPath buffer
+
+{
+ static INT nLenDummyFile = 0;
+ static INT nLenDummyDrive;
+ static INT nLenDummyPath;
+ static CHAR szTitle [128];
+
+ INT nLenPath;
+ INT nCurrentDrive;
+ INT nNewDrive;
+ CHAR pCurrentDir[MAX_BROWSE_PATH_LEN];
+ CHAR pNewDir[MAX_BROWSE_PATH_LEN];
+ CHAR *pTemp;
+ OPENFILENAME ofn; // struct. passed to GetSaveFileName
+ LPSTR pszInitPath = NULL; // Initial path
+
+ FARPROC lpfnFileOpenHook = (FARPROC)MakeProcInstance( DM_BrowsePathDialogHook, hInstance );
+
+ // Dialog box title
+
+ RSM_StringCopy ( IDS_BROWSETITLE, (LPSTR) szTitle, sizeof (szTitle) );
+
+ if ( !nLenDummyFile )
+ {
+ nLenDummyFile = strlen ( DUMMY_FILE );
+ nLenDummyDrive = strlen ( DUMMY_DRIVE );
+ nLenDummyPath = strlen ( DUMMY_PATH );
+ }
+
+ memset (&ofn, 0, sizeof (ofn) );
+
+ if ( pszPath && *pszPath ) //if an initial directory specified...
+ {
+ pszInitPath = (CHAR_PTR)calloc ( sizeof ( CHAR ), strlen ( pszPath ) + 1 ); //make a copy
+ strcpy ( pszInitPath, pszPath );
+
+ // Attempt to set our current drive and path to our log directory
+ // Store current path and drive so that we may reset back when done.
+
+ nCurrentDrive = _getdrive();
+ _getdcwd ( nCurrentDrive, pCurrentDir, MAX_BROWSE_PATH_LEN );
+
+ strcpy(pNewDir, pszInitPath);
+
+ for (pTemp = pNewDir+strlen(pNewDir);
+ ((*pTemp != '\\') && (pTemp > pNewDir));pTemp--);
+
+ *pTemp = 0;
+
+ nNewDrive = (INT)( toupper(*pszInitPath) - 'A' ) + 1 ;
+
+ _chdrive ( nNewDrive );
+ _chdir ( pNewDir );
+
+ //NOTE: May need test to determine if the initial path is valid
+ // If the init path is not valid, we should use the current
+ // directory on the specified drive - if one is specified.
+ // Otherwise, use the current working directory and drive, and
+ // totally ignore the init path.
+ // OpenSaveFileName currently ignores the init path if any part
+ // of it is not valid, which is not quite right.
+ }
+
+ *pszPath = TEXT('\0');
+
+ // Fill in the OPENFILENAME struct. and show dialog box
+
+ ofn.hInstance = ghResInst;
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.hwndOwner = hWndOwner;
+ ofn.lpstrFile = pszPath;
+ ofn.nMaxFile = nPathLen;
+ ofn.lpstrInitialDir = pszInitPath;
+ ofn.lpstrTitle = szTitle;
+ ofn.lpTemplateName = IDD_BROWSE;
+
+
+# ifdef OS_WIN32
+
+ ofn.Flags = OFN_HIDEREADONLY
+ | OFN_NOREADONLYRETURN
+ | OFN_ENABLETEMPLATE
+ | OFN_NONETWORKBUTTON
+ | OFN_ENABLEHOOK;
+
+ ofn.lpfnHook = (LPOFNHOOKPROC)lpfnFileOpenHook;
+
+# else
+
+ ofn.Flags = OFN_HIDEREADONLY
+ | OFN_NOREADONLYRETURN
+ | OFN_ENABLETEMPLATE
+ | OFN_ENABLEHOOK;
+
+ ofn.lpfnHook = lpfnFileOpenHook;
+
+# endif
+
+
+ if ( GetSaveFileName ((LPOPENFILENAME)&ofn) )
+ {
+ nLenPath = strlen ( pszPath );
+
+ if ( nLenPath == nLenDummyPath )
+ {
+ // Root directory selected, so chop off dummy filename only.
+
+ pszPath [ nLenDummyDrive ] = TEXT('\0');
+ }
+ else
+ {
+ // Path to a subdirectory selected, so chop off the dummy
+ // filename & trailing backslash
+
+ pszPath [ nLenPath - nLenDummyFile - 1 ] = TEXT('\0');
+ }
+
+ // Reset Drive and path.
+
+ _chdrive ( nCurrentDrive );
+
+ if ( pCurrentDir != NULL )
+ {
+ _chdir (pCurrentDir );
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+BOOL APIENTRY DM_BrowsePathDialogHook (
+
+HWND hDlg,
+MSGID msg,
+MP1 mp1,
+MP2 mp2 )
+
+{
+ static BOOL fProcessingUserSelection = FALSE;
+
+ UNREFERENCED_PARAMETER ( mp2 );
+
+ switch (msg) {
+
+ case WM_INITDIALOG:
+ {
+ HWND hWndChild;
+
+ DM_CenterDialog ( hDlg );
+
+ // Set the focus to the drive tree list box
+
+ if ( hWndChild = GetDlgItem ( hDlg, lst2 ) )
+ {
+ SetFocus ( hWndChild );
+ }
+
+ DM_RemoveUnknownVolumes ( hDlg, cmb2 );
+
+ SendMessage ( GetDlgItem ( hDlg, lst2 ), LB_SETHORIZONTALEXTENT, (MP1)600, (MP2)0 );
+
+ }
+ break;
+
+ case WM_COMMAND:
+ {
+ WORD wID = GET_WM_COMMAND_ID ( mp1, mp2 );
+ WORD wCmd = GET_WM_COMMAND_CMD ( mp1, mp2 );
+
+ if ( ( ! fProcessingUserSelection ) && ( wID == IDOK && wCmd == BN_CLICKED ) )
+ {
+ HWND hWndOkButton = GetDlgItem ( hDlg, IDOK );
+ HWND hWndFileEdit = GetDlgItem ( hDlg, edt1 );
+
+ fProcessingUserSelection = TRUE;
+ SET_WM_COMMAND_PARAMS ( IDOK, BN_CLICKED, hWndOkButton, mp1, mp2);
+
+ SendMessage ( hDlg, WM_COMMAND, mp1, mp2 );
+
+ SetWindowText ( hWndFileEdit, (LPSTR)DUMMY_FILE );
+
+ SendMessage ( hDlg, WM_COMMAND, mp1, mp2 );
+
+
+ fProcessingUserSelection = FALSE;
+
+ return TRUE; // We processed the message, so Windows should not
+ }
+
+ if ( wID == cmb2 && wCmd == CBN_SETFOCUS ) {
+ DM_RemoveUnknownVolumes ( hDlg, cmb2 );
+ }
+
+ }
+ break;
+
+ }
+
+ return FALSE; // did not process message, or, for WM_INITDIALOG, we
+ // set the focus, so Windows must not change it.
+}
+
+
+BOOL DM_RemoveUnknownVolumes (
+
+HWND hDlg,
+INT nItemID )
+
+{
+ VLM_OBJECT_PTR pVLM;
+ CHAR szTempBuf[80];
+ VOID_PTR pServerList = NULL;
+ VOID_PTR pDriverList = NULL;
+ PDS_WMINFO pWinInfo;
+ BOOL fReadOnlyDrive;
+ BOOL fDriveInList;
+ GENERIC_DLE_PTR pDLE;
+ INT nNumDrives;
+ INT nCurSel;
+ INT i;
+ INT nLen;
+ LPSTR *pszDrivesList;
+
+ HWND hWndCB = GetDlgItem ( hDlg, nItemID );
+
+ // Get the currently selected drive.
+
+ nCurSel = SendMessage ( GetDlgItem ( hDlg, nItemID ), CB_GETCURSEL, (MP1)0, (MP2)0 );
+
+ // Get the number if drives in the common dialog list.
+
+ nNumDrives = SendMessage ( GetDlgItem ( hDlg, nItemID ), CB_GETCOUNT, (MP1)0, (MP2)0 );
+
+ pszDrivesList = calloc ( nNumDrives, sizeof ( LPSTR ) );
+
+ if ( ! pszDrivesList ) {
+ return FALSE;
+ }
+
+ // Get all of the drives in the restore browse drives list box and
+ // save the drives list in a temporary array.
+
+ for ( i = 0; i < nNumDrives; i++ ) {
+
+ nLen = SendMessage ( GetDlgItem ( hDlg, nItemID ), CB_GETLBTEXTLEN, (MP1)i, (MP2)0 );
+
+ if ( nLen == CB_ERR ) {
+ return FALSE;
+ }
+
+ pszDrivesList[i] = calloc ( nLen+1, sizeof ( CHAR ) );
+
+ if ( ! pszDrivesList[i] ) {
+ return FALSE;
+ }
+
+ SendMessage ( GetDlgItem ( hDlg, nItemID ), CB_GETLBTEXT, (MP1)i, (MP2)pszDrivesList[i] );
+ }
+
+
+ // Throw out any of them that are not in our DLE list - starting
+ // at the bottom of the list - so the indexes can still be used.
+
+ if ( gb_disks_win != (HWND)NULL ) {
+
+ pWinInfo = WM_GetInfoPtr( gb_disks_win );
+ pDriverList = pWinInfo->pFlatList;
+
+ // Toss out the ones in the common dialog that are not in
+ // our list - and get rid of the ones that cannot be written to.
+
+ for ( i = ( nNumDrives - 1 ); i >= 0; i-- ) {
+
+ fReadOnlyDrive = FALSE;
+ fDriveInList = FALSE;
+
+ pVLM = VLM_GetFirstVLM ( (Q_HEADER_PTR) pDriverList );
+
+ while ( pVLM && ! fDriveInList ) {
+
+ // Make our drive string to compare with.
+
+ if ( strlen ( pVLM->label ) && strcmpi(pVLM->label, pVLM->name) ) {
+ sprintf ( szTempBuf, DRIVENAMEFORMAT, pVLM->name, pVLM->label );
+ }
+ else {
+ sprintf ( szTempBuf, DRIVENAMEFORMAT, pVLM->name, TEXT(" ") );
+ }
+
+ if ( ! strcmpi ( szTempBuf, pszDrivesList[i] ) ) {
+
+ fDriveInList = TRUE;
+
+ DLE_FindByName ( dle_list, pVLM->name, (INT16)-1, &pDLE );
+
+ if ( DLE_DriveWriteable(pDLE) == FALSE ) {
+ fReadOnlyDrive = TRUE;
+ } else {
+ fReadOnlyDrive = FALSE;
+ }
+ }
+
+ pVLM = VLM_GetNextVLM ( pVLM );
+ }
+
+ if ( fReadOnlyDrive || ! fDriveInList ) {
+
+ SendDlgItemMessage ( hDlg, nItemID, CB_DELETESTRING, i, (MP2)0 );
+
+ }
+ }
+ }
+
+ // Reselect the previously selected drive.
+
+ SendMessage ( GetDlgItem ( hDlg, nItemID ), CB_SELECTSTRING, (MP1)-1, (MP2)pszDrivesList[nCurSel] );
+
+ for ( i = 0; i < nNumDrives; i++ ) {
+
+ free ( pszDrivesList[i] );
+ }
+
+ free ( pszDrivesList );
+
+ return TRUE;
+
+} /* end DM_RemoveUnknownVolumes () */
+
+
+/******************************************************************************
+
+ Name: DM_BrowseForLogFilePath
+
+ Description: Put up a dialog to allow the user
+ to select a drive + directory
+ path.
+
+******************************************************************************/
+
+BOOL DM_BrowseForLogFilePath (
+
+HWND hWndOwner, // I - handle dialog owner or NULL
+HINSTANCE hInstance, // I - Application Instance handle
+LPSTR pszPath, // I - Initial directory O - User selected directory
+UINT nPathLen ) // I - sizeof of pszPath buffer
+
+{
+ INT nCurrentDrive;
+ INT nNewDrive;
+ UINT nTotal;
+ CHAR pCurrentDir[MAX_BROWSE_PATH_LEN];
+ CHAR pNewDir[MAX_BROWSE_PATH_LEN];
+ CHAR *pTemp;
+ CHAR szTitle[128];
+ CHAR szFilter[128];
+ BOOL fRC = FALSE;
+ OPENFILENAME ofn;
+ FARPROC lpfnFileOpenHook = (FARPROC)MakeProcInstance( DM_BrowseLogPathDialogHook, hInstance );
+
+ // Create the filter list.
+
+ {
+ CHAR szLoad[128];
+
+ RSM_StringCopy ( IDS_BROWSELOGFILES, (LPSTR) szLoad, 128 );
+ strcpy ( szFilter, szLoad );
+ nTotal = strlen(szLoad) + 1;
+
+ RSM_StringCopy ( IDS_BROWSELOGFILESEXT, (LPSTR) szLoad, 128 );
+ strcpy( &szFilter[nTotal], szLoad);
+ nTotal += strlen(szLoad) + 1;
+
+ RSM_StringCopy ( IDS_BROWSEALLFILES, (LPSTR) szLoad, 128 );
+ strcpy( &szFilter[nTotal], szLoad);
+ nTotal += strlen(szLoad) + 1;
+
+ RSM_StringCopy ( IDS_BROWSEALLFILESEXT, (LPSTR) szLoad, 128 );
+ strcpy( &szFilter[nTotal], szLoad);
+ nTotal += strlen(szLoad) + 1;
+
+ // Add the extra NULL at the end of the string for double
+ // NULL terminated string.
+
+ szFilter[nTotal] = 0;
+ }
+
+
+ RSM_StringCopy ( IDS_BROWSETITLE, (LPSTR) szTitle, sizeof (szTitle) / sizeof (CHAR) );
+
+ memset (&ofn, 0, sizeof (ofn) );
+
+ // Attempt to set our current drive and path to our log directory
+ // Store current path and drive so that we may reset back when done.
+
+ nCurrentDrive = _getdrive();
+ _getdcwd(nCurrentDrive, pCurrentDir, MAX_BROWSE_PATH_LEN);
+
+ strcpy ( pNewDir, pszPath );
+
+ pTemp = strrchr ( pNewDir, TEXT('\\') );
+
+ if ( pTemp ) {
+ pTemp++;
+ *pTemp = TEXT('\0');
+ }
+
+ nNewDrive = (INT)(toupper(*pszPath) - 'A') + 1;
+
+ _chdrive ( nNewDrive );
+ _chdir ( pNewDir );
+
+ // Fill in the OPENFILENAME struct. and show dialog box
+
+ ofn.hInstance = ghResInst;
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.hwndOwner = hWndOwner;
+ ofn.lpstrFilter = (LPSTR)szFilter;
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFile = pszPath;
+ ofn.nMaxFile = BROWSE_MAXPATH;
+ ofn.lpstrTitle = (LPSTR) szTitle;
+ ofn.lpTemplateName = IDD_LOGFILEBROWSE;
+ ofn.lpfnHook = (LPOFNHOOKPROC)lpfnFileOpenHook;
+ ofn.Flags = OFN_HIDEREADONLY | OFN_NOREADONLYRETURN |
+ OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST |
+ OFN_ENABLETEMPLATE | OFN_ENABLEHOOK;
+
+
+ if ( GetSaveFileName ( (LPOPENFILENAME)&ofn ) ) {
+
+ fRC = TRUE;
+ }
+ else {
+ DWORD dwErr = CommDlgExtendedError ();
+ }
+
+ // Need to change drive as well, so reset Drive and path.
+
+ _chdrive ( nCurrentDrive );
+
+ if ( pCurrentDir != NULL ) {
+ _chdir ( pCurrentDir );
+ }
+
+ return fRC;
+}
+
+
+BOOL APIENTRY DM_BrowseLogPathDialogHook (
+
+HWND hDlg,
+MSGID msg,
+MP1 mp1,
+MP2 mp2 )
+
+{
+ UNREFERENCED_PARAMETER ( mp1 );
+ UNREFERENCED_PARAMETER ( mp2 );
+
+ switch (msg) {
+
+ case WM_INITDIALOG:
+ {
+ DM_CenterDialog ( hDlg );
+
+ SendMessage ( GetDlgItem ( hDlg, lst2 ), LB_SETHORIZONTALEXTENT, (MP1)600, (MP2)0 );
+
+ }
+ break;
+
+ case WM_COMMAND:
+ break;
+
+ }
+
+ return FALSE;
+
+}
+
+
diff --git a/private/utils/ntbackup/src/d_ctape.c b/private/utils/ntbackup/src/d_ctape.c
new file mode 100644
index 000000000..6b205993c
--- /dev/null
+++ b/private/utils/ntbackup/src/d_ctape.c
@@ -0,0 +1,497 @@
+
+/***************************************************
+
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: d_ctape.c
+
+ Description: dialog proc for dialog for cataloging an entire tape
+
+ $Log: G:\UI\LOGFILES\D_CTAPE.C_V $
+
+ Rev 1.27 01 Dec 1993 14:21:40 mikep
+add SQL recognition support to poll drive
+
+ Rev 1.26 30 Jul 1993 08:55:52 CARLS
+added VLM_ECC_TAPE & VLM_FUTURE_VER
+
+ Rev 1.25 11 Jun 1993 14:13:24 MIKEP
+enable c++
+
+ Rev 1.24 05 Apr 1993 16:57:46 chrish
+Added one line "gbCurrentOperation = OPERATION_CATALOG" for security
+on tape cataloging.
+
+ Rev 1.23 07 Oct 1992 13:34:18 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.22 04 Oct 1992 19:35:40 DAVEV
+Unicode Awk pass
+
+ Rev 1.21 26 Aug 1992 14:12:40 DAVEV
+Fixed NT compile error
+
+ Rev 1.21 26 Aug 1992 14:11:00 DAVEV
+Fixed NT compile error
+
+ Rev 1.20 06 Aug 1992 13:23:58 CHUCKB
+Changes for NT.
+
+ Rev 1.18 15 May 1992 14:53:54 MIKEP
+nt pass 2
+
+ Rev 1.17 14 May 1992 16:38:08 MIKEP
+NT pass 2
+
+ Rev 1.16 12 May 1992 21:21:26 MIKEP
+NT pass 1
+
+ Rev 1.15 27 Mar 1992 10:26:26 DAVEV
+OEM_MSOFT: add user name to tape info string
+
+ Rev 1.14 16 Mar 1992 15:09:06 ROBG
+added help
+
+ Rev 1.13 30 Jan 1992 14:06:30 CARLS
+added a call to check for password
+
+ Rev 1.12 27 Jan 1992 00:29:30 CHUCKB
+Updated dialog id's.
+
+ Rev 1.11 24 Jan 1992 11:55:30 CARLS
+added a call to DM_CenterDialog
+
+ Rev 1.10 16 Jan 1992 09:22:24 CARLS
+disabled the continue button for blank tape
+
+ Rev 1.9 13 Jan 1992 09:30:42 CARLS
+added a call to the clock routine at init time
+
+ Rev 1.8 10 Jan 1992 13:38:10 JOHNWT
+internationalization round 2
+
+ Rev 1.7 10 Jan 1992 13:02:26 JOHNWT
+internationalized dates
+
+ Rev 1.6 10 Jan 1992 09:35:04 ROBG
+Modified HELPID.
+
+ Rev 1.5 09 Jan 1992 18:10:34 DAVEV
+16/32 bit port 2nd pass
+
+ Rev 1.4 06 Jan 1992 15:01:14 CHUCKB
+Added help.
+
+ Rev 1.3 14 Dec 1991 11:20:48 CARLS
+changes for full/partial catalog
+
+ Rev 1.2 07 Dec 1991 12:27:08 CARLS
+added poll drive to dialog
+
+ Rev 1.1 25 Nov 1991 14:57:14 DAVEV
+Changes for 32-16 bit Windows port
+
+ Rev 1.0 24 Sep 1991 13:50:38 CHUCKB
+Initial revision.
+
+*****************************************************/
+
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+typedef struct CAT_INFO *CAT_INFO_PTR;
+typedef struct CAT_INFO {
+ TCHAR szTapeName[255];
+ BOOL IsOutOfSeq;
+} CAT_INFO;
+
+struct cattape_temp {
+ WORD dialog_return_status;
+ HTIMER timer_handle;
+ HWND ghDlg; /* window handle of the dialog box */
+ UINT32 tape_id;
+ INT16 bset_num;
+ WORD display_status;
+ INT poll_drive_freq;
+ INT catalog_flag;
+};
+
+static struct cattape_temp *cattape_temp_ptr;
+
+
+static VOID clock_routine( VOID );
+
+/****************************************************************************
+
+ Name: DM_CatTape ()
+
+ Description: Entry point for the application to catalog a tape.
+
+ Modified: 6/17/91
+
+ Returns: INT telling whether the user chose to:
+ cancel the operation,
+ re-read the tape (user swapped the tape in the drive), or
+ catalog the tape
+
+ Notes:
+
+ See also:
+
+****************************************************************************/
+
+
+INT DM_CatTape ( INT * catalog_flag_ptr )
+
+{
+INT status;
+struct cattape_temp temp_data;
+
+ cattape_temp_ptr = &temp_data;
+
+ status = DM_ShowDialog ( ghWndFrame, IDD_CATTAPE, NULL );
+ *catalog_flag_ptr = cattape_temp_ptr->catalog_flag;
+
+ return( status );
+}
+
+/***************************************************
+
+ Name: DM_CatalogTape ()
+
+ Description: dialog proc for dialog for cataloging an entire tape
+
+ Modified:
+
+ Returns: true if message was processed
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+DLGRESULT APIENTRY DM_CatalogTape (
+HWND hDlg , /* window handle of the dialog box */
+MSGID message , /* type of message */
+MP1 mp1 , /* message-specific information */
+MP2 mp2
+)
+{
+ PAINTSTRUCT ps;
+ HDC hDC;
+ HDC hDCBitmap;
+ HWND hWnd;
+ HICON hIcon;
+ BOOL button_state;
+ CDS_PTR cds_ptr;
+ WORD catalog_mode;
+ WORD status;
+
+
+ gbCurrentOperation = OPERATION_CATALOG; // chs:04-05-93
+ UNREFERENCED_PARAMETER ( mp2 );
+ switch ( message )
+ {
+ case WM_INITDIALOG: /* message: initialize dialog box */
+
+ cattape_temp_ptr->ghDlg = hDlg;
+ cattape_temp_ptr->tape_id = 0;
+
+ DM_CenterDialog( hDlg );
+
+ /* read POLL DRIVE data */
+ clock_routine( );
+
+ cattape_temp_ptr->poll_drive_freq = PD_SetFrequency( 1 );
+ cattape_temp_ptr->timer_handle = WM_HookTimer( (PF_VOID)clock_routine, 1 );
+
+ cds_ptr = CDS_GetCopy();
+
+ /* Catalog check box */
+ catalog_mode = CDS_GetCatalogLevel( cds_ptr );
+ if( catalog_mode == CATALOGS_FULL ) {
+ CheckRadioButton( hDlg, IDD_CATTAPE_CATALOG_FULL, IDD_CATTAPE_CATALOG_PARTIAL, IDD_CATTAPE_CATALOG_FULL );
+ }
+ else {
+ CheckRadioButton( hDlg, IDD_CATTAPE_CATALOG_FULL, IDD_CATTAPE_CATALOG_PARTIAL, IDD_CATTAPE_CATALOG_PARTIAL );
+ }
+
+ return ( TRUE );
+
+ case WM_PAINT:
+
+ hDC = BeginPaint( hDlg, &ps );
+ EndPaint( hDlg, &ps );
+ UpdateWindow( hDlg ); /* force the dialog to be displayed now */
+
+ /* display the exclamation bitmap in the dialog */
+ hIcon = LoadIcon( 0, IDI_EXCLAMATION );
+ hWnd = GetDlgItem( hDlg, IDD_CATTAPE_EXCLAMATION_BITMAP );
+ hDCBitmap = GetDC( hWnd );
+ DrawIcon( hDCBitmap, 0, 0, hIcon );
+ ReleaseDC( hWnd, hDCBitmap );
+
+ return ( TRUE );
+
+ case WM_COMMAND: /* message: received a command */
+ switch( GET_WM_COMMAND_ID ( mp1, mp2 ) )
+ {
+/****************************************************************************
+ Continue button
+/***************************************************************************/
+ case IDD_CATTAPE_CONTINUE_BUTTON:
+
+ /* save the state of the catalog(full/partial) */
+ button_state = IsDlgButtonChecked( hDlg, IDD_CATTAPE_CATALOG_FULL );
+
+ if( button_state ) {
+ cattape_temp_ptr->catalog_flag = TRUE; /* = full */
+ }
+ else {
+ cattape_temp_ptr->catalog_flag = FALSE; /* = partial */
+ }
+
+ /* check for a password */
+ status = PSWD_CheckForPassword( cattape_temp_ptr->tape_id ,
+ cattape_temp_ptr->bset_num );
+
+ if( status == SUCCESS) /* if passwords matched - set return code to SUCCESS */
+ status = TRUE;
+ else
+ status = FALSE;
+
+ WM_UnhookTimer( cattape_temp_ptr->timer_handle );
+ PD_SetFrequency( cattape_temp_ptr->poll_drive_freq );
+
+ EndDialog( hDlg, status ); /* Exits the dialog box */
+
+ return ( TRUE );
+ break;
+/****************************************************************************
+ Help button
+/***************************************************************************/
+ case IDD_CATTAPE_HELP_BUTTON:
+ case IDHELP :
+
+ HM_DialogHelp( HELPID_DIALOGCATTAPE );
+
+ return ( TRUE );
+ break;
+/****************************************************************************
+ Cancel button
+/***************************************************************************/
+ case IDD_CATTAPE_CANCEL_BUTTON:
+ case IDCANCEL:
+
+ WM_UnhookTimer( cattape_temp_ptr->timer_handle );
+ PD_SetFrequency( cattape_temp_ptr->poll_drive_freq );
+ EndDialog( hDlg, FALSE ); /* Exits the dialog box */
+ return ( TRUE );
+ break;
+
+ }
+ break;
+ }
+ return ( FALSE ); /* Didn't process a message */
+}
+
+
+/***************
+
+ GetDriveStatus
+ possible return values
+ SEE VLM.H
+
+ VLM_VALID_TAPE 0
+ VLM_DRIVE_BUSY 1
+ VLM_FOREIGN_TAPE 2
+ VLM_BLANK_TAPE 3
+ VLM_NO_TAPE 4
+ VLM_BUSY 5
+ VLM_BAD_TAPE 6
+ VLM_GOOFY_TAPE 7
+ VLM_DISABLED 8
+ VLM_UNFORMATED 9
+ VLM_DRIVE_FAILURE 10
+ VLM_FUTURE_VER 11
+ VLM_ECC_TAPE 12
+ VLM_SQL_TAPE 13
+
+
+***************/
+/***************************************************
+
+ Name: clock_routine
+
+ Description: poll drive status routine
+
+ Returns: void
+
+*****************************************************/
+static VOID clock_routine( VOID )
+{
+ DBLK_PTR vcb_ptr;
+ DATE_TIME_PTR dt;
+ INT status;
+ UINT32 current_tape_id;
+ CHAR date_str[MAX_UI_DATE_SIZE];
+ CHAR time_str[MAX_UI_TIME_SIZE];
+
+ status = VLM_GetDriveStatus( &vcb_ptr );
+
+ switch( status ) {
+
+ case VLM_VALID_TAPE:
+
+ /* get this tape ID */
+ current_tape_id = FS_ViewTapeIDInVCB( vcb_ptr );
+
+ /* if this ID not equal to the last ID, then must be a new tape */
+ if( cattape_temp_ptr->tape_id != current_tape_id )
+ {
+ /* save this tape ID */
+ cattape_temp_ptr->tape_id = current_tape_id;
+ cattape_temp_ptr->bset_num = FS_ViewBSNumInVCB( vcb_ptr );
+
+ /* display name, date and time of this tape */
+ dt = FS_ViewBackupDateInVCB( vcb_ptr );
+ UI_MakeDateString( date_str, dt->month, dt->day, dt->year % 100 );
+ UI_MakeShortTimeString( time_str, dt->hour, dt->minute );
+
+# if defined ( OEM_MSOFT ) //alternate feature
+ {
+ yresprintf( (INT16) RES_ERASE_TAPE_INFO1 ,
+ FS_ViewTapeNameInVCB( vcb_ptr ) ,
+ FS_ViewUserNameInVCB( vcb_ptr ) ,
+ date_str ,
+ time_str );
+ }
+# else //if defined ( OEM_MSOFT ) //alternate feature
+ {
+ yresprintf( (INT16) RES_ERASE_TAPE_INFO1 ,
+ FS_ViewTapeNameInVCB( vcb_ptr ) ,
+ date_str ,
+ time_str );
+ }
+# endif //defined ( OEM_MSOFT ) //alternate feature
+
+
+ SetDlgItemText( cattape_temp_ptr->ghDlg, IDD_CATTAPE_MESSAGE, gszTprintfBuffer );
+
+ /* turn the CONTINUE button on */
+ EnableWindow ( GetDlgItem ( cattape_temp_ptr->ghDlg, IDD_ERASE_CONTINUE_BUTTON ), TRUE );
+ }
+ break;
+
+ case VLM_FUTURE_VER:
+ case VLM_SQL_TAPE:
+ case VLM_ECC_TAPE:
+ case VLM_FOREIGN_TAPE:
+
+ if(cattape_temp_ptr->display_status != VLM_FOREIGN_TAPE ) {
+
+ cattape_temp_ptr->display_status = VLM_FOREIGN_TAPE;
+ yresprintf( (INT16) RES_ERASE_FOREIGN_TAPE );
+ SetDlgItemText( cattape_temp_ptr->ghDlg, IDD_CATTAPE_MESSAGE, gszTprintfBuffer );
+
+ /* turn the CONTINUE button OFF */
+ EnableWindow ( GetDlgItem ( cattape_temp_ptr->ghDlg, IDD_ERASE_CONTINUE_BUTTON ), FALSE );
+ cattape_temp_ptr->tape_id = 0;
+ }
+ break;
+
+ case VLM_BLANK_TAPE:
+
+ if(cattape_temp_ptr->display_status != VLM_BLANK_TAPE ) {
+
+ cattape_temp_ptr->display_status = VLM_BLANK_TAPE;
+ yresprintf( (INT16) RES_ERASE_BLANK_TAPE );
+ SetDlgItemText( cattape_temp_ptr->ghDlg, IDD_CATTAPE_MESSAGE, gszTprintfBuffer );
+
+ /* turn the CONTINUE button off for blank tape */
+ EnableWindow ( GetDlgItem ( cattape_temp_ptr->ghDlg, IDD_ERASE_CONTINUE_BUTTON ), FALSE );
+ cattape_temp_ptr->tape_id = 0;
+ }
+ break;
+
+ case VLM_NO_TAPE:
+
+ if(cattape_temp_ptr->display_status != VLM_NO_TAPE ) {
+
+ cattape_temp_ptr->display_status = VLM_NO_TAPE;
+ yresprintf( (INT16) RES_ERASE_NO_TAPE );
+ SetDlgItemText( cattape_temp_ptr->ghDlg, IDD_CATTAPE_MESSAGE, gszTprintfBuffer );
+
+ /* turn the CONTINUE button OFF for no tape */
+ EnableWindow ( GetDlgItem ( cattape_temp_ptr->ghDlg, IDD_ERASE_CONTINUE_BUTTON ), FALSE );
+ cattape_temp_ptr->tape_id = 0;
+ }
+ break;
+
+ case VLM_BUSY:
+
+ if(cattape_temp_ptr->display_status != VLM_BUSY ) {
+
+ cattape_temp_ptr->display_status = VLM_BUSY;
+ yresprintf( (INT16) RES_ERASE_DRIVE_BUSY );
+ SetDlgItemText( cattape_temp_ptr->ghDlg, IDD_CATTAPE_MESSAGE, gszTprintfBuffer );
+
+ /* turn the CONTINUE button off when busy */
+ EnableWindow ( GetDlgItem ( cattape_temp_ptr->ghDlg, IDD_ERASE_CONTINUE_BUTTON ), FALSE );
+ cattape_temp_ptr->tape_id = 0;
+ }
+ break;
+
+ case VLM_DISABLED:
+
+ if(cattape_temp_ptr->display_status != VLM_DISABLED ) {
+
+ cattape_temp_ptr->display_status = VLM_DISABLED;
+ yresprintf( (INT16) RES_ERASE_POLL_DRIVE_DISABLED );
+ SetDlgItemText( cattape_temp_ptr->ghDlg, IDD_CATTAPE_MESSAGE, gszTprintfBuffer );
+
+ /* turn the CONTINUE button OFF */
+ EnableWindow ( GetDlgItem ( cattape_temp_ptr->ghDlg, IDD_ERASE_CONTINUE_BUTTON ), FALSE );
+ cattape_temp_ptr->tape_id = 0;
+ }
+ break;
+
+ case VLM_BAD_TAPE:
+
+ if(cattape_temp_ptr->display_status != VLM_BAD_TAPE ) {
+
+ cattape_temp_ptr->display_status = VLM_BAD_TAPE;
+ yresprintf( (INT16) RES_POLL_DRIVE_BAD_TAPE );
+ SetDlgItemText( cattape_temp_ptr->ghDlg, IDD_CATTAPE_MESSAGE, gszTprintfBuffer );
+
+ /* turn the CONTINUE button off */
+ EnableWindow ( GetDlgItem ( cattape_temp_ptr->ghDlg, IDD_ERASE_CONTINUE_BUTTON ), FALSE );
+ cattape_temp_ptr->tape_id = 0;
+ }
+ break;
+
+ case VLM_GOOFY_TAPE:
+
+ if(cattape_temp_ptr->display_status != VLM_GOOFY_TAPE ) {
+
+ cattape_temp_ptr->display_status = VLM_GOOFY_TAPE;
+ yresprintf( (INT16) RES_POLL_DRIVE_GOOFY_TAPE );
+ SetDlgItemText( cattape_temp_ptr->ghDlg, IDD_CATTAPE_MESSAGE, gszTprintfBuffer );
+
+ /* turn the CONTINUE button off */
+ EnableWindow ( GetDlgItem ( cattape_temp_ptr->ghDlg, IDD_ERASE_CONTINUE_BUTTON ), FALSE );
+ cattape_temp_ptr->tape_id = 0;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+
diff --git a/private/utils/ntbackup/src/d_date.c b/private/utils/ntbackup/src/d_date.c
new file mode 100644
index 000000000..1c1596335
--- /dev/null
+++ b/private/utils/ntbackup/src/d_date.c
@@ -0,0 +1,145 @@
+
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: d_date.c
+
+ Description: date utilities for dialogs
+
+ $Log:
+
+ Rev 1.0 ?? ??? 1991 ??:??:?? ??????
+Initial revision.
+
+*****************************************************/
+
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+/***************************************************
+
+ Name: DM_IsLeapYear ()
+
+ Description:
+
+ Modified:
+
+ Returns: boolean true if message was processed
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+
+BOOL DM_IsLeapYear ( INT year )
+
+{
+ if ( year % 4 == 0 && year % 100 != 0 || year % 400 == 0 )
+ return TRUE ;
+ else
+ return FALSE ;
+}
+
+
+
+/***************************************************
+
+ Name: DM_DaysInMonth ( )
+
+ Description: determines how many days are in the given month
+ in the given year; if year is a leap year Feb changes
+
+ Modified:
+
+ Returns: WORD number of days in the month given
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+INT DM_DaysInMonth ( INT month, INT year )
+
+{
+ switch ( month ) {
+
+ case 1 :
+ case 3 :
+ case 5 :
+ case 7 :
+ case 8 :
+ case 10 :
+ case 12 :
+ return 31 ;
+
+ case 4 :
+ case 6 :
+ case 9 :
+ case 11 :
+ return 30 ;
+
+ case 2 :
+
+ if ( DM_IsLeapYear ( year ) )
+ return 29;
+ else
+ return 28 ;
+
+ default :
+ return 0 ;
+ }
+}
+
+
+/***************************************************
+
+ Name: DM_IsDateValid ( )
+
+ Description: compares two dates that are supposed to come in
+ order; if the one that is supposed to be first is
+ not before the one that is supposed to be second,
+ something is wrong;
+ also checks the number of days in a month
+
+ Modified:
+
+ Returns: BOOL true if the second date is after the first
+ false otherwise
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+BOOL DM_IsDateValid ( INT bmonth, INT bday, INT byear,
+ INT amonth, INT aday, INT ayear )
+
+{
+ // first check the numbers of days in the months
+
+ if ( ( bday > DM_DaysInMonth ( bmonth, byear ) ) ||
+ ( aday > DM_DaysInMonth ( amonth, ayear ) ) ) {
+
+ return FALSE ;
+ }
+
+ // the numbers of days are kosher; now see if they are in order
+
+ if ( byear < ayear )
+ return FALSE ;
+ else if ( byear == ayear ) {
+ if ( bmonth < amonth ) return FALSE ;
+ else if ( bmonth == amonth )
+ return ( bday >= aday ) ;
+ }
+ return TRUE ;
+}
+
diff --git a/private/utils/ntbackup/src/d_dbug.c b/private/utils/ntbackup/src/d_dbug.c
new file mode 100644
index 000000000..e1c1f4938
--- /dev/null
+++ b/private/utils/ntbackup/src/d_dbug.c
@@ -0,0 +1,329 @@
+
+/***************************************************
+
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: d_dbug.c
+
+ Description: dialog proc for debug window settings dialog
+
+ $Log: G:/UI/LOGFILES/D_DBUG.C_V $
+
+ Rev 1.17 01 Nov 1992 15:53:00 DAVEV
+Unicode changes
+
+ Rev 1.16 14 Oct 1992 15:50:28 GLENN
+Added /ZL debug logging command line support.
+
+ Rev 1.15 07 Oct 1992 13:34:48 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.14 04 Oct 1992 19:35:44 DAVEV
+Unicode Awk pass
+
+ Rev 1.13 28 Jul 1992 15:04:46 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.12 07 Jul 1992 15:51:26 MIKEP
+unicode changes
+
+ Rev 1.11 15 May 1992 16:48:04 MIKEP
+incl_cds removal
+
+ Rev 1.10 15 May 1992 14:53:56 MIKEP
+nt pass 2
+
+ Rev 1.9 14 May 1992 16:40:10 MIKEP
+Nt pass 2
+
+ Rev 1.8 19 Mar 1992 09:30:32 MIKEP
+enable debug to file
+
+ Rev 1.7 04 Feb 1992 15:28:22 CHUCKB
+Removed EOF char.
+
+ Rev 1.6 09 Jan 1992 18:11:36 DAVEV
+16/32 bit port 2nd pass
+
+ Rev 1.5 06 Jan 1992 15:00:52 CHUCKB
+Added help.
+
+ Rev 1.4 03 Jan 1992 19:18:06 CHUCKB
+Put in new CDS calls.
+
+ Rev 1.3 19 Dec 1991 13:37:36 CHUCKB
+Put in display memory and poll drive options.
+
+ Rev 1.2 16 Dec 1991 11:45:04 CHUCKB
+Added include windows.h.
+
+ Rev 1.1 25 Nov 1991 14:58:40 DAVEV
+Changes for 32-16 bit Windows port
+
+ Rev 1.0 07 Aug 1991 14:12:50 CHUCKB
+Initial revision.
+
+*****************************************************/
+
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+/***************************************************
+
+ Name: DM_SettingsDebug ()
+
+ Description: contains dialog proc for debug window settings dialog
+
+ Modified:
+
+ Returns: true if message was processed
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+DLGRESULT APIENTRY DM_SettingsDebug (
+
+ HWND hDlg,
+ MSGID msg ,
+ MPARAM1 mp1 ,
+ MPARAM2 mp2 )
+
+{
+ CDS_PTR pPermCDS = CDS_GetPerm ();
+
+ INT nNumToKeep ;
+ INT iLoopIndex ;
+ CHAR szFileName[20] ;
+
+ UNREFERENCED_PARAMETER ( mp2 );
+
+ switch ( msg ) {
+
+ case WM_INITDIALOG :
+
+ // EnableWindow( GetDlgItem( hDlg, IDD_DB_TOFILE), FALSE ) ;
+
+ CheckDlgButton( hDlg, IDD_DB_POLLDRIVEON, gfPollDrive ) ;
+ CheckDlgButton( hDlg, IDD_DB_MEMTRACE, gfShowMemory ) ;
+
+ CheckRadioButton( hDlg, IDD_DB_RLAST, IDD_DB_RALL,
+ ( CDS_GetDebugWindowShowAll( pPermCDS ) ? IDD_DB_RALL : IDD_DB_RLAST ) ) ;
+
+ SetDlgItemInt ( hDlg, IDD_DB_RNUM, CDS_GetDebugWindowNumLines( pPermCDS ), FALSE ) ;
+
+ strcpy ( szFileName, CDS_GetDebugFileName( pPermCDS ) ) ;
+ SetDlgItemText ( hDlg, IDD_DB_FNAME, szFileName ) ;
+ SendDlgItemMessage ( hDlg, IDD_DB_FNAME, EM_LIMITTEXT,
+ (MPARAM1) 8, (MPARAM2) NULL ) ;
+
+ SetDlgItemInt ( hDlg, IDD_DB_WMSGS, DBM_GetMsgCount ( DBM_WINDOW ), FALSE ) ;
+ SetDlgItemInt ( hDlg, IDD_DB_FMSGS, DBM_GetMsgCount ( DBM_FILE ), FALSE ) ;
+
+ CheckDlgButton ( hDlg, IDD_DB_TOFILE, CDS_GetDebugToFile( pPermCDS ) ) ;
+ CheckDlgButton ( hDlg, IDD_DB_TOWIN, CDS_GetDebugToWindow( pPermCDS ) ) ;
+
+ EnableWindow ( GetDlgItem ( hDlg, IDD_DB_RFILE ),
+ IsDlgButtonChecked ( hDlg, IDD_DB_TOFILE ) ) ;
+ EnableWindow ( GetDlgItem ( hDlg, IDD_DB_FNAME ),
+ IsDlgButtonChecked ( hDlg, IDD_DB_TOFILE ) ) ;
+ EnableWindow ( GetDlgItem ( hDlg, IDD_DB_FMSGS ),
+ IsDlgButtonChecked ( hDlg, IDD_DB_TOFILE ) ) ;
+
+ EnableWindow ( GetDlgItem ( hDlg, IDD_DB_RMEM ),
+ IsDlgButtonChecked ( hDlg, IDD_DB_TOWIN ) ) ;
+ EnableWindow ( GetDlgItem ( hDlg, IDD_DB_RALL ),
+ IsDlgButtonChecked ( hDlg, IDD_DB_TOWIN ) ) ;
+ EnableWindow ( GetDlgItem ( hDlg, IDD_DB_RLAST ),
+ IsDlgButtonChecked ( hDlg, IDD_DB_TOWIN ) ) ;
+ EnableWindow ( GetDlgItem ( hDlg, IDD_DB_RNUM ),
+ IsDlgButtonChecked ( hDlg, IDD_DB_TOWIN ) ) ;
+ EnableWindow ( GetDlgItem ( hDlg, IDD_DB_WMSGS ),
+ IsDlgButtonChecked ( hDlg, IDD_DB_TOWIN ) ) ;
+ EnableWindow ( GetDlgItem ( hDlg, IDD_DB_M ),
+ IsDlgButtonChecked ( hDlg, IDD_DB_TOWIN ) ) ;
+
+ return TRUE ;
+
+ case WM_COMMAND :
+
+ switch ( GET_WM_COMMAND_ID ( mp1, mp2 ) ) {
+
+ case IDHELP:
+
+ HM_DialogHelp( HELPID_DIALOGSETTINGSDEBUG ) ;
+ return( TRUE ) ;
+
+ case IDD_DB_TOWIN :
+
+ EnableWindow ( GetDlgItem ( hDlg, IDD_DB_RMEM ),
+ IsDlgButtonChecked ( hDlg, IDD_DB_TOWIN ) ) ;
+ EnableWindow ( GetDlgItem ( hDlg, IDD_DB_RALL ),
+ IsDlgButtonChecked ( hDlg, IDD_DB_TOWIN ) ) ;
+ EnableWindow ( GetDlgItem ( hDlg, IDD_DB_RLAST ),
+ IsDlgButtonChecked ( hDlg, IDD_DB_TOWIN ) ) ;
+ EnableWindow ( GetDlgItem ( hDlg, IDD_DB_RNUM ),
+ IsDlgButtonChecked ( hDlg, IDD_DB_TOWIN ) ) ;
+ EnableWindow ( GetDlgItem ( hDlg, IDD_DB_WMSGS ),
+ IsDlgButtonChecked ( hDlg, IDD_DB_TOWIN ) ) ;
+ EnableWindow ( GetDlgItem ( hDlg, IDD_DB_M ),
+ IsDlgButtonChecked ( hDlg, IDD_DB_TOWIN ) ) ;
+ return TRUE ;
+
+ case IDD_DB_RLAST :
+ case IDD_DB_RALL :
+
+ CheckRadioButton ( hDlg, IDD_DB_RLAST, IDD_DB_RALL,
+ GET_WM_COMMAND_ID ( mp1, mp2 ) ) ;
+ return TRUE ;
+
+ case IDD_DB_RNUM :
+ case IDD_DB_WMSGS :
+ case IDD_DB_FNAME :
+ case IDD_DB_FMSGS :
+ return TRUE ;
+
+ case IDD_DB_RMEM :
+
+ DBM_Reset ( DBM_WINDOW ) ;
+ SetDlgItemInt ( hDlg, IDD_DB_WMSGS, DBM_GetMsgCount ( DBM_WINDOW ), FALSE ) ;
+ return TRUE ;
+
+ case IDD_DB_TOFILE :
+
+ EnableWindow ( GetDlgItem ( hDlg, IDD_DB_RFILE ),
+ IsDlgButtonChecked ( hDlg, IDD_DB_TOFILE ) ) ;
+ EnableWindow ( GetDlgItem ( hDlg, IDD_DB_FNAME ),
+ IsDlgButtonChecked ( hDlg, IDD_DB_TOFILE ) ) ;
+ EnableWindow ( GetDlgItem ( hDlg, IDD_DB_FMSGS ),
+ IsDlgButtonChecked ( hDlg, IDD_DB_TOFILE ) ) ;
+ return TRUE ;
+
+ case IDD_DB_RFILE :
+
+ DBM_Reset ( DBM_FILE ) ;
+ SetDlgItemInt ( hDlg, IDD_DB_FMSGS, DBM_GetMsgCount ( DBM_FILE ), FALSE ) ;
+ return TRUE ;
+
+ case IDOK : {
+
+ BOOL fResult ;
+
+ if ( IsDlgButtonChecked ( hDlg, IDD_DB_RLAST ) &&
+ IsDlgButtonChecked ( hDlg, IDD_DB_TOWIN ) ) {
+
+ if ( GetDlgItemInt ( hDlg, IDD_DB_RNUM, NULL, FALSE ) < DBM_MIN_LINES ) {
+ WM_MsgBox ( ID(IDS_DEBUGWARNING),
+ ID(IDS_DEBUGMESSAGESTOOLOW),
+ WMMB_OK,
+ WMMB_ICONEXCLAMATION ) ;
+ return TRUE ;
+ }
+
+ if ( GetDlgItemInt ( hDlg, IDD_DB_RNUM, NULL, FALSE ) > DBM_MAX_LINES ) {
+ WM_MsgBox ( ID(IDS_DEBUGWARNING),
+ ID(IDS_DEBUGMESSAGESTOOHIGH),
+ WMMB_OK,
+ WMMB_ICONEXCLAMATION ) ;
+ return TRUE ;
+ }
+ }
+
+ if ( IsDlgButtonChecked ( hDlg, IDD_DB_TOFILE ) ) {
+
+ GetDlgItemText ( hDlg, IDD_DB_FNAME, szFileName, 19 ) ;
+
+ for ( iLoopIndex = 0; iLoopIndex < (INT) strlen ( szFileName ); iLoopIndex++ ) {
+ if ( szFileName[iLoopIndex] == TEXT(' ') ) {
+
+ WM_MsgBox ( ID(IDS_DEBUGWARNING),
+ ID(IDS_DEBUGBADFILENAME),
+ WMMB_OK,
+ WMMB_ICONEXCLAMATION ) ;
+ return TRUE ;
+ }
+ }
+
+ if ( strlen ( szFileName ) < 1 ) {
+ strcpy ( szFileName, TEXT("debug") ) ;
+ }
+ CDS_SetDebugFileName ( pPermCDS, szFileName ) ;
+ CDS_WriteDebugFileName ( pPermCDS ) ;
+ }
+
+ gfPollDrive = IsDlgButtonChecked( hDlg, IDD_DB_POLLDRIVEON ) ;
+
+ // Turn on or off Poll Drive.
+
+ if ( ! gfOperation ) {
+
+ if ( ! gfPollDrive ) {
+
+ PD_StopPolling ();
+
+ } else {
+
+ PD_StartPolling ();
+ }
+ }
+
+ fResult = IsDlgButtonChecked ( hDlg, IDD_DB_RALL ) ;
+
+ if ( fResult != CDS_GetDebugWindowShowAll ( pPermCDS ) ) {
+ CDS_SetDebugWindowShowAll ( pPermCDS, fResult ) ;
+ CDS_WriteDebugWindowShowAll ( pPermCDS ) ;
+ }
+
+ fResult = IsDlgButtonChecked ( hDlg, IDD_DB_TOFILE ) ;
+
+ if ( fResult != CDS_GetDebugToFile ( pPermCDS ) ) {
+ DBM_SetDebugToFile ( fResult ) ;
+ CDS_SetDebugToFile ( pPermCDS, fResult ) ;
+ CDS_WriteDebugToFile ( pPermCDS ) ;
+ }
+
+ fResult = IsDlgButtonChecked ( hDlg, IDD_DB_TOWIN ) ;
+
+ if ( fResult != CDS_GetDebugToWindow ( pPermCDS ) ) {
+ CDS_SetDebugToWindow ( pPermCDS, fResult ) ;
+ CDS_WriteDebugToWindow ( pPermCDS ) ;
+ }
+
+ gfShowMemory = IsDlgButtonChecked( hDlg, IDD_DB_MEMTRACE ) ;
+
+ nNumToKeep = GetDlgItemInt ( hDlg, IDD_DB_RNUM, NULL, FALSE ) ;
+
+ if ( IsDlgButtonChecked ( hDlg, IDD_DB_TOWIN ) &&
+ ( nNumToKeep != CDS_GetDebugWindowNumLines ( pPermCDS ) ) ) {
+
+ CDS_SetDebugWindowNumLines ( pPermCDS, (INT16)nNumToKeep ) ;
+ CDS_WriteDebugWindowNumLines ( pPermCDS ) ;
+ }
+
+ }
+
+ case IDCANCEL :
+
+ EndDialog ( hDlg, 0 ) ;
+ return TRUE ;
+
+ default:
+ return FALSE ;
+ }
+ break ;
+
+ case WM_CLOSE :
+ EndDialog ( hDlg, 0 ) ;
+ break ;
+
+ default :
+ return FALSE ;
+ }
+ return TRUE ;
+}
diff --git a/private/utils/ntbackup/src/d_erase.c b/private/utils/ntbackup/src/d_erase.c
new file mode 100644
index 000000000..ef2399e07
--- /dev/null
+++ b/private/utils/ntbackup/src/d_erase.c
@@ -0,0 +1,166 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: d_erase.c
+
+ Description: dialog proc for erase operation settings
+
+ $Log: G:/UI/LOGFILES/D_ERASE.C_V $
+
+ Rev 1.14 15 Jun 1993 08:30:32 MIKEP
+enable c++
+
+ Rev 1.13 07 Oct 1992 13:35:16 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.12 04 Oct 1992 19:35:50 DAVEV
+Unicode Awk pass
+
+ Rev 1.11 15 May 1992 14:53:58 MIKEP
+nt pass 2
+
+ Rev 1.10 14 May 1992 16:40:18 MIKEP
+Nt pass 2
+
+ Rev 1.9 03 Mar 1992 17:04:24 GLENN
+Removed the dialog table loop call and just used DM_ShowDialog.
+
+ Rev 1.8 04 Feb 1992 15:28:08 CHUCKB
+Removed EOF char.
+
+ Rev 1.7 27 Jan 1992 12:47:42 GLENN
+Changed dialog support calls.
+
+ Rev 1.6 20 Jan 1992 10:36:16 CARLS
+added a call to DM_CenterDialog
+
+ Rev 1.5 10 Jan 1992 09:07:40 ROBG
+Changed HELPID
+
+ Rev 1.4 09 Jan 1992 18:12:26 DAVEV
+16/32 bit port 2nd pass
+
+ Rev 1.3 07 Jan 1992 12:40:44 CHUCKB
+Added help.
+
+ Rev 1.2 16 Dec 1991 11:57:14 CHUCKB
+Added include windows.h.
+
+ Rev 1.1 25 Nov 1991 15:00:02 DAVEV
+Changes for 32-16 bit Windows port
+
+ Rev 1.0 07 Jun 1991 16:22:22 GLENN
+Initial revision.
+
+*****************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+/***************************************************
+
+ Name: DM_ProceedWithErase ()
+
+ Description: dialog proc for erase operation settings
+
+ Modified:
+
+ Returns: boolean true if user wants to continue
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+BOOL DM_ProceedWithErase ( VOID )
+
+{
+ CDS_PTR pTempCDS = CDS_GetCopy() ;
+
+ DM_ShowDialog ( ghWndFrame, IDD_OPERATIONSERASE, (PVOID)0 );
+
+ return ( CDS_GetEraseFlag ( pTempCDS ) != ERASE_OFF ) ;
+}
+
+
+/***************************************************
+
+ Name: DM_EraseTape
+
+ Description: dialog proc for erase operation settings
+
+ Modified:
+
+ Returns: boolean true if message was processed
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+DLGRESULT APIENTRY DM_EraseTape (
+
+ HWND hDlg,
+ MSGID msg ,
+ MPARAM1 mp1 ,
+ MPARAM2 mp2 )
+
+{
+ CDS_PTR pPermCDS = CDS_GetPerm() ;
+ CDS_PTR pTempCDS = CDS_GetCopy() ;
+ INT16 nTemp ;
+
+ UNREFERENCED_PARAMETER ( mp2 );
+
+ switch ( msg ) {
+
+ case WM_INITDIALOG :
+
+ DM_CenterDialog( hDlg ) ;
+
+ // fill in the backup sets on the tape, etc.
+
+ // SetDlgItemText ( hDlg, IDD_TAPENAME, "Tape Name" ) ;
+
+ // while there are more sets on the tape
+
+ // SendDlgItemMessage ( hDlg, IDD_SETSONTAPE, LB_ADDSTRING,
+ // 0, (LONG) "A Set on the Tape" ) ;
+
+ nTemp = CDS_GetEraseFlag( pPermCDS ) ;
+ CheckDlgButton ( hDlg, IDD_SECERASE, ( nTemp == ERASE_LONG ) ) ;
+
+ return TRUE ;
+
+ case WM_COMMAND :
+
+ switch ( GET_WM_COMMAND_ID ( mp1, mp2 ) ) {
+
+ case IDHELP:
+
+ HM_DialogHelp( HELPID_DIALOGERASE ) ;
+ return( TRUE ) ;
+
+ case IDOK :
+
+ CDS_SetEraseFlag(pTempCDS,ERASE_ON);
+ if ( IsDlgButtonChecked ( hDlg,
+ GET_WM_COMMAND_ID ( mp1, mp2 ) ) ) {
+
+ CDS_SetEraseFlag(pTempCDS,ERASE_LONG);
+ }
+
+ case IDCANCEL :
+
+ EndDialog ( hDlg, 0 ) ;
+ return TRUE ;
+ }
+ break ;
+ }
+ return FALSE;
+}
diff --git a/private/utils/ntbackup/src/d_o_bkup.c b/private/utils/ntbackup/src/d_o_bkup.c
new file mode 100644
index 000000000..3d9003c37
--- /dev/null
+++ b/private/utils/ntbackup/src/d_o_bkup.c
@@ -0,0 +1,2590 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: D_O_BKUP.C
+
+ Description: Runtime backup set description dialog
+
+ $Log: G:\ui\logfiles\d_o_bkup.c_v $
+
+ Rev 1.96.1.15 02 Feb 1994 17:57:44 chrish
+Added changes for UNICODE app to handle ANSI secured created tapes.
+
+ Rev 1.96.1.14 02 Feb 1994 11:28:56 Glenn
+Overhauled log file browse support - now a separate function in d_browse.c.
+
+ Rev 1.96.1.13 25 Jan 1994 08:40:38 MIKEP
+fix warnings for orcas
+
+ Rev 1.96.1.12 17 Jan 1994 15:19:14 MIKEP
+fix more unicoe warnings
+
+ Rev 1.96.1.11 08 Jan 1994 14:58:56 MikeP
+fix string internationalization characteristics
+
+ Rev 1.96.1.10 14 Dec 1993 12:26:00 BARRY
+Don't write to gszTprintfBuffer, use yprintf
+
+ Rev 1.96.1.9 02 Dec 1993 15:58:18 mikep
+add sql tape recognition
+
+ Rev 1.96.1.8 24 Nov 1993 19:14:00 GREGG
+Added hardware compression option to backup dialog and config.
+
+ Rev 1.96.1.7 04 Nov 1993 15:45:22 STEVEN
+japanese changes
+
+ Rev 1.96.1.6 16 Jun 1993 17:08:28 GLENN
+Fixed CANCEL bug while being called in MultiTask.
+
+ Rev 1.96.1.5 11 Jun 1993 14:25:38 BARRY
+Use dle features for backup of special files instead of FS_PromptForBindery.
+
+ Rev 1.96.1.4 02 Jun 1993 15:49:16 KEVINS
+Corrected logic error when calculating new drive to change to during browse.
+
+ Rev 1.96.1.3 26 May 1993 15:12:42 BARRY
+Got rid of hard-coded strings.
+
+ Rev 1.96.1.2 24 May 1993 15:19:24 BARRY
+Unicode fixes.
+
+ Rev 1.96.1.1 22 May 1993 18:41:00 BARRY
+Fixed to compile for MIPs
+
+ Rev 1.96.1.0 22 May 1993 16:11:04 BARRY
+Changed hard-coded strings to IDs.
+
+ Rev 1.96 12 May 1993 09:38:02 DARRYLP
+Cleared owner field when tape is ejected. It needs to be re-read, and
+displayed fresh for a new tape.
+
+ Rev 1.95 07 May 1993 18:36:38 MIKEP
+Check in kludge to allow turning hardware compression off. We will
+do this cleaner later, I promise.
+
+ Rev 1.94 04 May 1993 10:55:40 DARRYLP
+Fixed browse path search.
+
+ Rev 1.93 03 May 1993 11:23:22 CHUCKB
+Update to my last change: took out function InitiallyCheckRegistry that we don't use any more.
+
+ Rev 1.92 03 May 1993 11:18:56 CHUCKB
+Changed the way we evaluate whether or not to check the backup registry box.
+Before, we used a number of things, including defaulting to ON and looking for
+ALL_FILES_SELECTED. Now, we only use the BSD_xxxProcSpecialFlg.
+
+ Rev 1.91 03 May 1993 10:30:26 DARRYLP
+Changed browse path to reflect combobox.
+
+ Rev 1.90 28 Apr 1993 16:58:48 CARLS
+fix for drive failure
+
+ Rev 1.89 23 Apr 1993 16:09:54 CARLS
+fix for drive busy message displayed, but tape window shows a valid tape name
+
+ Rev 1.88 22 Apr 1993 17:40:00 chrish
+Fix for Cayman: EPR 0173 - Made change to the default tape label name
+to append the time. Per MikeP suggestion for giving the default tape name
+some default uniqueness.
+
+ Rev 1.87 13 Apr 1993 17:20:30 CHUCKB
+If running a job that has 'Backup Registry' set, check it.
+
+ Rev 1.86 08 Apr 1993 17:14:28 chrish
+Added change to prevent backup a tape passworded by the CAYMAN app.
+
+ Rev 1.85 08 Apr 1993 13:29:28 MIKEP
+fix for partial catalog button
+
+ Rev 1.84 29 Mar 1993 11:34:38 TIMN
+Expand user supplied log filename to full path
+
+ Rev 1.83 26 Mar 1993 13:15:50 STEVEN
+Ifdef'ed skip files stuff out for Nostro.
+
+ Rev 1.82 25 Mar 1993 17:25:18 CHUCKB
+Dealing with skipped files had been #ifdef'ed out for any 32-bit op. sys. Now it works for Cayman
+.
+
+ Rev 1.81 17 Mar 1993 16:17:38 chrish
+Changed detection of backup privilege to "SeBackupPrivilege".
+
+ Rev 1.80 16 Mar 1993 12:40:12 CARLS
+LOG file changes
+
+ Rev 1.79 11 Mar 1993 17:22:12 CHUCKB
+Gray compression controls for beta.
+
+ Rev 1.78 10 Mar 1993 12:43:40 CARLS
+Changes to move Format tape to the Operations menu
+
+ Rev 1.77 09 Mar 1993 11:17:18 DARRYLP
+Fixed my new bug.
+
+ Rev 1.76 08 Mar 1993 14:41:30 DARRYLP
+Added support for read only drives.
+
+ Rev 1.75 22 Feb 1993 17:07:42 CHUCKB
+Fixed bug: ignore OK message of OK button is grey.
+
+ Rev 1.74 22 Feb 1993 11:29:30 chrish
+Added changes received from MikeP.
+Fixed the password that was put on tape. It was encrypting one copy,
+but putting a nonencrypted copy on tape.
+
+ Rev 1.73 18 Feb 1993 10:50:40 BURT
+Changes for Cayman
+
+
+ Rev 1.72 11 Feb 1993 14:42:42 CARLS
+disable append operation to tape that does not support it
+
+ Rev 1.71 07 Jan 1993 09:46:54 CARLS
+defined out InitiallyActivateRegistryBox for non NT
+
+ Rev 1.70 15 Dec 1992 11:19:50 chrish
+Corrected logic to handle possible NULL returned from
+GetCurrentMachineNameUserName routine.
+
+ Rev 1.69 14 Dec 1992 12:17:00 DAVEV
+Enabled for Unicode compile
+
+ Rev 1.68 16 Nov 1992 15:15:06 chrish
+Minor changes to clean-up warning messages on build.
+
+ Rev 1.68 16 Nov 1992 12:23:46 chrish
+Minor changes to clean-up warning messages on buildin.
+
+ Rev 1.67 13 Nov 1992 17:24:10 chrish
+Added backup for Secure Tape and change for registry check box - NT.
+
+ Rev 1.66 11 Nov 1992 16:32:00 DAVEV
+UNICODE: remove compile warnings
+
+ Rev 1.65 01 Nov 1992 15:55:02 DAVEV
+Unicode changes
+
+ Rev 1.64 29 Oct 1992 16:41:30 STEVEN
+added rules for default on registry
+
+ Rev 1.63 27 Oct 1992 17:42:14 STEVEN
+enable registry support
+
+ Rev 1.62 21 Oct 1992 17:12:44 MIKEP
+last time
+
+ Rev 1.61 21 Oct 1992 13:42:16 MIKEP
+fix steve changes
+
+ Rev 1.60 21 Oct 1992 13:39:46 MIKEP
+fix steve changes
+
+ Rev 1.59 21 Oct 1992 12:46:38 STEVEN
+added support for registry
+
+ Rev 1.58 07 Oct 1992 13:37:38 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.57 04 Oct 1992 19:36:18 DAVEV
+Unicode Awk pass
+
+ Rev 1.56 30 Sep 1992 10:38:58 DAVEV
+Unicode strlen verification, MikeP's chgs from MS
+
+ Rev 1.55 17 Sep 1992 16:54:38 STEVEN
+added support for daily backup
+
+ Rev 1.54 17 Sep 1992 15:49:54 DAVEV
+UNICODE modifications: strlen usage check
+
+ Rev 1.53 09 Sep 1992 10:08:58 CHUCKB
+Changed ifdef's to include browse features used only in Nostrodamus.
+
+ Rev 1.51 03 Sep 1992 10:43:38 CHUCKB
+Took out some unreferenced locals.
+
+ Rev 1.50 19 Aug 1992 14:29:18 CHUCKB
+Added new stuff for NT.
+
+ Rev 1.49 28 Jul 1992 15:04:52 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.48 08 Jul 1992 15:35:46 STEVEN
+Unicode BE changes
+
+ Rev 1.47 29 Jun 1992 09:05:48 CARLS
+added changes for TDEMO
+
+ Rev 1.46 26 Jun 1992 15:52:52 DAVEV
+
+
+ Rev 1.45 18 Jun 1992 11:25:36 DAVEV
+OEM_MSOFT:fixed logging bug
+
+ Rev 1.44 11 Jun 1992 15:22:08 DAVEV
+do not display status message 'Examine <log file> for more info' if not logging
+
+ Rev 1.43 05 Jun 1992 12:42:42 DAVEV
+OEM_MSOFT: Init log file name to default
+
+ Rev 1.42 04 Jun 1992 14:56:56 davev
+OEM_MSOFT: Kludge-disable 'Restrict Access..' checkbox in dialog
+
+ Rev 1.41 14 May 1992 16:37:22 MIKEP
+NT pass 2
+
+ Rev 1.40 12 May 1992 15:52:58 DAVEV
+OEM_MSOFT: fixed problem with tape name not being saved
+
+
+*****************************************************/
+
+#include "all.h"
+#include "ctl3d.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+//
+// Kludged for now to test the HW compression stuff. The proper way is
+// for the compression stuff to be placed in tape format.
+//
+#ifndef OEM_MSOFT
+#include "special.h" // chs:04-23-93
+#include "dddefs.h" // chs:04-23-93
+#endif
+
+#define ON 1
+#define OFF 0
+#define SECONDS_SIZE 2
+#define NO_SHOW 0
+#define SHOW 1
+#define REDRAW 1
+#define NO_REDRAW 0
+
+// Initial security state of the tape
+#define ORIGINALLYUNSECURED 0
+#define ORIGINALLYSECURED 1
+#define ORIGINALLYDONTKNOW 2
+#define MAX_BROWSE_PATH_LEN 1024
+
+WORD RT_BSD_index;
+WORD RT_max_BSD_index;
+#ifdef OEM_EMS
+INT32 RT_BSD_OsId;
+#endif
+
+static BOOL mwfCancelRequestDelayed;
+
+static WORD OriginalTapeSecured; // Tells the original security
+ // state of the tape
+
+static WORD EnableSecurityDlgFlag; // Flag to tell whether to Enable
+ // security dialog
+
+static VOID clock_routine( VOID );
+static VOID ScrollLineDown( VOID );
+static VOID ScrollLineUp( VOID );
+
+static BOOL bTransfer;
+
+struct backup_set_temp {
+ WORD mode_flag;
+ WORD dialog_return_status;
+ WORD BSD_index;
+ WORD max_BSD_index;
+ HTIMER timer_handle;
+ HWND ghDlg; /* global window handle of the dialog box */
+ UINT32 tape_id;
+ WORD display_status;
+ INT poll_drive_freq;
+ INT16 tape_password_leng;
+ CHAR job_password[ MAX_TAPE_PASSWORD_SIZE ];
+};
+
+static struct backup_set_temp *backup_set_temp_ptr;
+static VOID_PTR reenter_password_ptr;
+/***************************************************
+
+ Name: DM_StartBackupSet()
+
+ Description: Starts the Runtime backup set description dialog
+
+ Returns: Returns the status from the
+ Runtime backup set description dialog.
+
+*****************************************************/
+INT DM_StartBackupSet(
+ INT oper_type )
+{
+INT status;
+struct backup_set_temp temp_data;
+
+ backup_set_temp_ptr = &temp_data;
+ backup_set_temp_ptr->mode_flag = oper_type;
+
+ /* set the display_status to a value not returned by VLM_GetDriveStatus */
+ backup_set_temp_ptr->display_status = 0x7fff ;
+ backup_set_temp_ptr->tape_id = 0 ;
+
+ status = DM_ShowDialog( ghWndFrame, IDD_BACKUPSET, NULL );
+
+ return( backup_set_temp_ptr->dialog_return_status );
+}
+/***************************************************
+
+ Name: DM_BackupSet()
+
+ Description: Runtime backup set description dialog.
+
+ Returns:
+
+*****************************************************/
+DLGRESULT APIENTRY DM_BackupSet(
+ HWND hDlg , /* window handle of the dialog box */
+ MSGID message , /* type of message */
+ MPARAM1 mp1 , /* message-specific information */
+ MPARAM2 mp2 )
+{
+ HWND hScrollbar;
+ WORD thumbposition;
+ WORD button_state;
+ LPSTR generic_str_ptr;
+ BSD_PTR bsd_ptr;
+ CDS_PTR cds_ptr;
+ GENERIC_DLE_PTR dle_ptr;
+ BE_CFG_PTR be_cfg_ptr;
+ CHAR buffer[ MAX_UI_RESOURCE_SIZE ];
+ CHAR buffer2[ MAX_UI_RESOURCE_SIZE ];
+ DBLK_PTR vcb_ptr;
+#if !defined ( OEM_MSOFT ) // unused variables
+ INT16 pswd_size;
+ WORD wait_time;
+ CHAR reenter_password[ MAX_TAPE_PASSWORD_SIZE ];
+#endif // unused variables
+
+#ifdef OEM_EMS
+ static DLG_CTRL_ENTRY DefaultCtrlTable[] = {
+ { IDD_BKUP_XCHG_NAME_TEXT, 0, CM_HIDE },
+ { IDD_BKUP_XCHG_NAME, 0, CM_HIDE },
+ { IDD_XCHG_BKUP_METHOD, 0, CM_HIDE },
+ { IDD_BKUP_DRIVE_NAME_TEXT, 0, CM_ENABLE },
+ { IDD_BKUP_DRIVE_NAME, 0, CM_ENABLE },
+ { IDD_BKUP_METHOD, 0, CM_ENABLE }
+ };
+
+ static DLG_CTRL_ENTRY EMSCtrlTable[] = {
+ { IDD_BKUP_DRIVE_NAME_TEXT, 0, CM_HIDE },
+ { IDD_BKUP_DRIVE_NAME, 0, CM_HIDE },
+ { IDD_BKUP_METHOD, 0, CM_HIDE },
+ { IDD_BKUP_XCHG_NAME_TEXT, 0, CM_ENABLE },
+ { IDD_BKUP_XCHG_NAME, 0, CM_ENABLE },
+ { IDD_XCHG_BKUP_METHOD, 0, CM_ENABLE }
+ };
+
+ // FS_UNKNOWN_OS must be last w/ no other iDispType == FS_UNKNOWN_OS (or its value).
+ static DLG_DISPLAY_ENTRY BkupDispTable[] = {
+ { FS_EMS_MDB_ID, EMSCtrlTable,
+ sizeof(EMSCtrlTable)/sizeof(EMSCtrlTable[0]), IDH_DB_XCHG_BACKUPSET },
+ { FS_EMS_DSA_ID, EMSCtrlTable,
+ sizeof(EMSCtrlTable)/sizeof(EMSCtrlTable[0]), IDH_DB_XCHG_BACKUPSET },
+ { FS_UNKNOWN_OS, DefaultCtrlTable,
+ sizeof(DefaultCtrlTable)/sizeof(DefaultCtrlTable[0]), HELPID_DIALOGBACKUPSET }
+ };
+
+ static DLG_DISPLAY_ENTRY ArchDispTable[] = {
+ { FS_EMS_MDB_ID, EMSCtrlTable,
+ sizeof(EMSCtrlTable)/sizeof(EMSCtrlTable[0]), IDH_DB_XCHG_BACKUPSET },
+ { FS_EMS_DSA_ID, EMSCtrlTable,
+ sizeof(EMSCtrlTable)/sizeof(EMSCtrlTable[0]), IDH_DB_XCHG_BACKUPSET },
+ { FS_UNKNOWN_OS, DefaultCtrlTable,
+ sizeof(DefaultCtrlTable)/sizeof(DefaultCtrlTable[0]), HELPID_DIALOGTRANSFER }
+ };
+
+ static DLG_MODE ModeTable[] = {
+ { ARCHIVE_BACKUP_OPER, ArchDispTable,
+ sizeof(ArchDispTable)/sizeof(ArchDispTable[0]), &(ArchDispTable[2]) },
+ { BACKUP_OPER, BkupDispTable,
+ sizeof(BkupDispTable)/sizeof(BkupDispTable[0]), &(ArchDispTable[2]) },
+ { 0, BkupDispTable,
+ sizeof(BkupDispTable)/sizeof(BkupDispTable[0]), &(ArchDispTable[2]) }
+ };
+
+ static UINT16 cModeTblSize = sizeof( ModeTable ) / sizeof( ModeTable[0] );
+ static DLG_MODE *pCurMode;
+ DWORD help_id;
+
+#endif
+
+ switch ( message )
+ {
+/****************************************************************************
+ INIT THE DIALOG
+/***************************************************************************/
+ case WM_INITDIALOG: /* message: initialize dialog box */
+
+ // Let's go 3-D!!
+ Ctl3dSubclassDlgEx( hDlg, CTL3D_ALL );
+
+ DM_CenterDialog( hDlg );
+
+ backup_set_temp_ptr->ghDlg = hDlg;
+ backup_set_temp_ptr->tape_id = 0;
+ OriginalTapeSecured = ORIGINALLYDONTKNOW;
+ EnableSecurityDlgFlag = 0;
+ mwfCancelRequestDelayed = FALSE;
+
+#ifdef OEM_EMS
+ pCurMode = DM_InitCtrlTables( hDlg, ModeTable, cModeTblSize,
+ backup_set_temp_ptr->mode_flag );
+#endif
+
+ EnableWindow( GetDlgItem( hDlg, IDD_BKUP_HARDCOMP ) , // chs: 04-22-93
+ ( thw_list->drv_info.drv_features & TDI_DRV_COMPRESSION ) ? ON : OFF ); // chs: 04-22-93
+ CheckDlgButton ( hDlg, IDD_BKUP_HARDCOMP, CDS_GetHWCompMode ( CDS_GetCopy() ) ) ;
+
+ /* set the length of the text fields */
+# if !defined ( OEM_MSOFT ) // unsupported feature
+ {
+ SendDlgItemMessage( hDlg, IDD_BKUP_PASSWORD, EM_LIMITTEXT,
+ MAX_TAPE_PASSWORD_LEN, 0 );
+ }
+# endif
+
+ SendDlgItemMessage( hDlg, IDD_BKUP_TAPE_NAME, EM_LIMITTEXT,
+ MAX_TAPE_NAME_LEN, 0 );
+ SendDlgItemMessage( hDlg, IDD_BKUP_DESCRIPTION, EM_LIMITTEXT,
+ MAX_BSET_NAME_LEN, 0 );
+
+ /* Normal not allowed with Transfer operation */
+ if( backup_set_temp_ptr->mode_flag != ARCHIVE_BACKUP_OPER ) {
+
+ RSM_StringCopy( IDS_METHOD_NORMAL, buffer, sizeof(buffer) );
+ SendDlgItemMessage( hDlg, IDD_BKUP_METHOD, CB_ADDSTRING,
+ 0, MP2FROMPVOID ( buffer ) );
+#ifdef OEM_EMS
+ SendDlgItemMessage( hDlg, IDD_XCHG_BKUP_METHOD, CB_ADDSTRING,
+ 0, MP2FROMPVOID ( buffer ) );
+#endif
+ }
+
+ RSM_StringCopy( IDS_METHOD_COPY, buffer, sizeof(buffer) );
+ SendDlgItemMessage( hDlg, IDD_BKUP_METHOD, CB_ADDSTRING,
+ 0, MP2FROMPVOID ( buffer ) );
+#ifdef OEM_EMS
+ SendDlgItemMessage( hDlg, IDD_XCHG_BKUP_METHOD, CB_ADDSTRING,
+ 0, MP2FROMPVOID ( buffer ) );
+#endif
+
+ /* Differential/Incremental not allowed with Transfer operation */
+ if( backup_set_temp_ptr->mode_flag != ARCHIVE_BACKUP_OPER ) {
+
+ RSM_StringCopy( IDS_METHOD_DIFFERENTIAL, buffer, sizeof(buffer) );
+ SendDlgItemMessage( hDlg, IDD_BKUP_METHOD, CB_ADDSTRING,
+ 0, MP2FROMPVOID ( buffer ) );
+#ifdef OEM_EMS
+ SendDlgItemMessage( hDlg, IDD_XCHG_BKUP_METHOD, CB_ADDSTRING,
+ 0, MP2FROMPVOID ( buffer ) );
+#endif
+
+ RSM_StringCopy( IDS_METHOD_INCREMENTAL, buffer, sizeof(buffer) );
+ SendDlgItemMessage( hDlg, IDD_BKUP_METHOD, CB_ADDSTRING,
+ 0, MP2FROMPVOID ( buffer ) );
+#ifdef OEM_EMS
+ SendDlgItemMessage( hDlg, IDD_XCHG_BKUP_METHOD, CB_ADDSTRING,
+ 0, MP2FROMPVOID ( buffer ) );
+#endif
+
+ RSM_StringCopy( IDS_METHOD_DAILY, buffer, sizeof(buffer) );
+ SendDlgItemMessage( hDlg, IDD_BKUP_METHOD, CB_ADDSTRING,
+ 0, MP2FROMPVOID ( buffer ) );
+ }
+ else {
+ /* Transfer operation - disable the combo box */
+ EnableWindow( GetDlgItem( hDlg, IDD_BKUP_METHOD ) , OFF );
+#ifdef OEM_EMS
+ EnableWindow( GetDlgItem( hDlg, IDD_XCHG_BKUP_METHOD ) , OFF );
+#endif
+ }
+
+ /* select the first item in the list */
+ SendDlgItemMessage( hDlg, IDD_BKUP_METHOD, CB_SETCURSEL, 0, 0 );
+#ifdef OEM_EMS
+ SendDlgItemMessage( hDlg, IDD_XCHG_BKUP_METHOD, CB_SETCURSEL, 0, 0 );
+#endif
+
+#if defined ( TDEMO )
+
+ /* if a NORMAL backup, only enable the COPY method to prevent */
+ /* the archive bit from being reset */
+
+ if( backup_set_temp_ptr->mode_flag != ARCHIVE_BACKUP_OPER ) {
+
+ /* select copy from the list */
+ SendDlgItemMessage( hDlg, IDD_BKUP_METHOD, CB_SETCURSEL, 1, 0 );
+#ifdef OEM_EMS
+ SendDlgItemMessage( hDlg, IDD_XCHG_BKUP_METHOD, CB_SETCURSEL, 1, 0 );
+#endif
+
+ /* tdemo exe - disable the combo box */
+ EnableWindow( GetDlgItem( hDlg, IDD_BKUP_METHOD ) , OFF );
+#ifdef OEM_EMS
+ EnableWindow( GetDlgItem( hDlg, IDD_XCHG_BKUP_METHOD ) , OFF );
+#endif
+ }
+#endif
+
+ /* start at the first BSD */
+ backup_set_temp_ptr->BSD_index = 0;
+ bsd_ptr = GetBSDPointer( backup_set_temp_ptr->BSD_index );
+
+ BackupSetDefaultSettings( );
+
+ cds_ptr = CDS_GetCopy();
+ be_cfg_ptr = BSD_GetConfigData( bsd_ptr );
+
+ /* generate the default names for the tape and description fields */
+ /* return the max number of BSD's for this backup */
+ backup_set_temp_ptr->max_BSD_index = BackupSetDefaultDescription();
+
+
+ /* set the global BSD index used for the "Set information N of N" dialogs title */
+ RT_BSD_index = (WORD)(backup_set_temp_ptr->BSD_index + 1);
+ RT_max_BSD_index = (WORD)(backup_set_temp_ptr->max_BSD_index + 1);
+
+ hScrollbar = GetDlgItem( hDlg, IDD_BKUP_SCROLLBAR );
+
+ /* if only one backup set, turn off the scrollbar */
+ if( backup_set_temp_ptr->max_BSD_index == backup_set_temp_ptr->BSD_index )
+ ShowScrollBar( hScrollbar, SB_CTL, NO_SHOW );
+ else {
+ SetScrollRange( hScrollbar, SB_CTL, backup_set_temp_ptr->BSD_index, backup_set_temp_ptr->max_BSD_index, NO_REDRAW );
+ SetScrollPos( hScrollbar, SB_CTL, backup_set_temp_ptr->BSD_index, NO_REDRAW );
+ }
+
+ /* add "1 of n" to backup set info title */
+ RSM_StringCopy( IDS_SET_INFORMATION, buffer, sizeof(buffer) );
+ wsprintf( buffer2, buffer, backup_set_temp_ptr->BSD_index + 1, backup_set_temp_ptr->max_BSD_index + 1 );
+ SetDlgItemText( hDlg, IDD_BKUP_INFO_TITLE, buffer2 );
+
+ /* display the default tape name */
+ generic_str_ptr = (LPSTR)BSD_GetTapeLabel( bsd_ptr );
+
+ SetDlgItemText( hDlg, IDD_BKUP_TAPE_NAME, generic_str_ptr );
+
+ /* display the default tape password */
+# if !defined ( OEM_MSOFT )
+ {
+ generic_str_ptr = BSD_GetTapePswd( bsd_ptr );
+ if( generic_str_ptr) {
+
+ strcpy( buffer, generic_str_ptr );
+ pswd_size = (INT16)(strlen ( generic_str_ptr ) * sizeof (CHAR));
+ if( pswd_size ) {
+
+ CryptPassword( DECRYPT, ENC_ALGOR_3, buffer, pswd_size );
+ }
+ SetDlgItemText( hDlg, IDD_BKUP_PASSWORD, buffer );
+ }
+
+ /* Include catalogs check box */
+ CheckDlgButton( hDlg, IDD_BKUP_INCLUDE_CATALOGS, CDS_GetBackupCatalogs( cds_ptr ) );
+ }
+# endif //!defined ( OEM_MSOFT ) // unsupported feature
+
+ /* Append/replace radio check box */
+ if( CDS_GetAppendFlag( cds_ptr ) ) {
+
+ /* if append operation, clear the tape name field */
+ /* and the password field */
+ buffer[0] = 0;
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ SetDlgItemText( hDlg, IDD_BKUP_PASSWORD, buffer ); /* clear password field */
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ SetDlgItemText( hDlg, IDD_BKUP_TAPE_NAME, buffer ); /* clear tape name field */
+
+ /* disable password & tape name fields */
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ EnableWindow( GetDlgItem( hDlg, IDD_BKUP_PASSWORD ) , OFF );
+ EnableWindow( GetDlgItem( hDlg, IDD_BKUP_PASSWORD_TEXT ) , OFF );
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ EnableWindow( GetDlgItem( hDlg, IDD_BKUP_TAPE_NAME ) , OFF );
+ EnableWindow( GetDlgItem( hDlg, IDD_BKUP_TAPE_NAME_TEXT ) , OFF );
+
+ CheckRadioButton( hDlg, IDD_BKUP_APPEND, IDD_BKUP_REPLACE, IDD_BKUP_APPEND );
+ }
+ else
+ CheckRadioButton( hDlg, IDD_BKUP_APPEND, IDD_BKUP_REPLACE, IDD_BKUP_REPLACE );
+
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ wait_time = CDS_GetWaitTime( cds_ptr );
+ wsprintf( buffer, TEXT("%d"), wait_time );
+ SetDlgItemText( hDlg, IDD_BKUP_SKIP_TIME, buffer );
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ /* Auto verify check box */
+ /* if this operation is a transfer ? */
+ if( backup_set_temp_ptr->mode_flag == ARCHIVE_BACKUP_OPER ) {
+ yresprintf( (INT16) RES_TARGET_TRANSFER_TITLE );
+ SetWindowText( hDlg, gszTprintfBuffer );
+
+ bTransfer = TRUE;
+
+ /* if transfer, check the auto verify box */
+ CheckDlgButton( hDlg, IDD_BKUP_AUTO_VERIFY, 1 );
+ EnableWindow( GetDlgItem( hDlg, IDD_BKUP_AUTO_VERIFY ) , OFF );
+ }
+ else {
+ CheckDlgButton( hDlg, IDD_BKUP_AUTO_VERIFY, CDS_GetAutoVerifyBackup( cds_ptr ) );
+ bTransfer = FALSE;
+
+ }
+
+ /* display the state of the first BSD */
+#ifndef OEM_EMS
+ BackupSetRetrieve( hDlg );
+#else
+ BackupSetRetrieve( hDlg, pCurMode );
+#endif
+
+ /* retrieve any password that a job may have passed in */
+ generic_str_ptr = &backup_set_temp_ptr->job_password[0];
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ GetDlgItemText( hDlg, IDD_BKUP_PASSWORD, generic_str_ptr, MAX_TAPE_PASSWORD_SIZE );
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ /* read POLL DRIVE data */
+ clock_routine( );
+
+ backup_set_temp_ptr->poll_drive_freq = PD_SetFrequency( 1 );
+ backup_set_temp_ptr->timer_handle = WM_HookTimer( clock_routine, 1 );
+
+# if defined ( OEM_MSOFT ) // special feature
+ {
+# define OEMLOG_MAX_FILEPATH 512 //NTKLUG
+
+ CHAR szLogFilePath[ OEMLOG_MAX_FILEPATH ];
+ INT len;
+
+ if ( len = GetWindowsDirectory ( szLogFilePath,
+ OEMLOG_MAX_FILEPATH ) )
+ {
+ if ( szLogFilePath[ len-1 ] != TEXT('\\') //NTKLUG
+ && len < OEMLOG_MAX_FILEPATH )
+ {
+ strcat ( szLogFilePath, TEXT("\\") );
+ ++len;
+ }
+ if ( len < OEMLOG_MAX_FILEPATH
+ && RSM_StringCopy( IDS_OEMLOG_BACKUP_DEF_NAME,
+ szLogFilePath+len,
+ OEMLOG_MAX_FILEPATH - len ) > 0 )
+ {
+ SetDlgItemText( hDlg, IDD_BKUP_LOG_FILENAME,
+ szLogFilePath );
+ }
+ }
+ /* Check default log file radio button */
+
+ CheckRadioButton ( hDlg, IDD_BKUP_LOG_FULL,
+ IDD_BKUP_LOG_NONE,
+ IDD_BKUP_LOG_SUMMARY );
+
+// CheckDlgButton( hDlg, IDD_BKUP_LOG_SUMMARY, 1 );
+
+ }
+# endif //defined ( OEM_MSOFT ) // special feature
+
+ return ( TRUE );
+
+ case WM_VSCROLL:
+
+ hScrollbar = GetDlgItem( hDlg, IDD_BKUP_SCROLLBAR );
+ if( GET_WM_VSCROLL_HWND ( mp1, mp2 ) == hScrollbar ) {
+
+ thumbposition = GET_WM_VSCROLL_POS ( mp1,mp2 );
+
+ switch( GET_WM_VSCROLL_CODE ( mp1, mp2 ) )
+ {
+ case SB_THUMBPOSITION:
+
+ SetScrollPos( hScrollbar, SB_CTL, thumbposition, REDRAW );
+ return ( TRUE );
+
+ case SB_THUMBTRACK:
+
+ if(thumbposition > backup_set_temp_ptr->max_BSD_index )
+ thumbposition = backup_set_temp_ptr->max_BSD_index;
+
+ if( thumbposition >= backup_set_temp_ptr->BSD_index ) {
+ BackupSetSave( hDlg );
+ while( thumbposition != backup_set_temp_ptr->BSD_index ) {
+ ScrollLineUp( );
+ }
+#ifndef OEM_EMS
+ BackupSetRetrieve( hDlg );
+#else
+ BackupSetRetrieve( hDlg, pCurMode );
+#endif
+ }
+ else {
+ BackupSetSave( hDlg );
+ while( thumbposition != backup_set_temp_ptr->BSD_index ) {
+ ScrollLineDown( );
+ }
+#ifndef OEM_EMS
+ BackupSetRetrieve( hDlg );
+#else
+ BackupSetRetrieve( hDlg, pCurMode );
+#endif
+ }
+ return ( TRUE );
+
+ case SB_PAGEUP:
+ case SB_LINEUP:
+
+ BackupSetSave( hDlg );
+ ScrollLineDown( );
+#ifndef OEM_EMS
+ BackupSetRetrieve( hDlg );
+#else
+ BackupSetRetrieve( hDlg, pCurMode );
+#endif
+ SetScrollPos( hScrollbar, SB_CTL, backup_set_temp_ptr->BSD_index, REDRAW );
+ return ( TRUE );
+
+ case SB_PAGEDOWN:
+ case SB_LINEDOWN:
+
+ BackupSetSave( hDlg );
+ ScrollLineUp( );
+#ifndef OEM_EMS
+ BackupSetRetrieve( hDlg );
+#else
+ BackupSetRetrieve( hDlg, pCurMode );
+#endif
+ SetScrollPos( hScrollbar, SB_CTL, backup_set_temp_ptr->BSD_index, REDRAW );
+ return ( TRUE );
+
+ default:
+ break;
+ }
+ }
+ break;
+
+#if defined (OEM_MSOFT) // special feature
+ case WM_KEYDOWN:
+ {
+ if ( ( GET_WM_COMMAND_ID( mp1, mp2 ) == VK_DOWN ) &&
+ ( ( GetFocus() == GetDlgItem( hDlg, IDD_BKUP_LOG_FILENAME ) ) ) ) {
+
+ SendMessage( hDlg, WM_COMMAND, IDD_BKUP_LOG_BROWSE, (MPARAM2) NULL ) ;
+ }
+ return(0) ;
+ }
+#endif // special feature
+
+
+/****************************************************************************
+ WM COMMAND
+/***************************************************************************/
+ case WM_COMMAND: /* message: received a command */
+ {
+ WORD wId = GET_WM_COMMAND_ID ( mp1, mp2 );
+ cds_ptr = CDS_GetCopy();
+
+ switch( wId )
+ {
+ case IDD_BKUP_REPLACE:
+
+ /* if the user selects replace operation , */
+ /* place the default name into the field */
+
+ {
+ CHAR tmp_buf1[ MAX_TAPE_NAME_LEN ];
+ CHAR tmp_buf2[ MAX_TAPE_NAME_LEN ];
+ RSM_StringCopy( IDS_DEFAULT_TAPE_NAME, tmp_buf1, MAX_TAPE_NAME_LEN );
+ UI_CurrentDate( tmp_buf2 );
+ wsprintf( buffer, tmp_buf1, tmp_buf2 ) ;
+ }
+
+ bsd_ptr = GetBSDPointer( 0 );
+
+ /* if the Tape name field is blank - set default name */
+ /* else use the name passed in */
+ if( ! BSD_GetTapeLabel( bsd_ptr ) ) {
+
+ SetDlgItemText( hDlg, IDD_BKUP_TAPE_NAME, buffer );
+ }
+
+ /* if the dialog tape name field is blank - set default name */
+ GetDlgItemText( hDlg, IDD_BKUP_TAPE_NAME, buffer2, MAX_TAPE_NAME_SIZE );
+ if( strlen( buffer2 ) == 0 ) {
+
+ generic_str_ptr = (LPSTR)BSD_GetTapeLabel( bsd_ptr );
+ SetDlgItemText( hDlg, IDD_BKUP_TAPE_NAME, generic_str_ptr );
+ }
+
+ /* enable password & tape name fields */
+ EnableWindow( GetDlgItem( hDlg, IDD_BKUP_TAPE_NAME ) , ON );
+ EnableWindow( GetDlgItem( hDlg, IDD_BKUP_TAPE_NAME_TEXT ) , ON );
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ EnableWindow( GetDlgItem( hDlg, IDD_BKUP_PASSWORD ) , ON );
+ EnableWindow( GetDlgItem( hDlg, IDD_BKUP_PASSWORD_TEXT ) , ON );
+ }
+# else
+ {
+ if ( EnableSecurityDlgFlag ) {
+ EnableWindow( GetDlgItem( hDlg, IDD_BKUP_RESTRICT_ACCESS ),
+ ON );
+ } else {
+ EnableWindow( GetDlgItem( hDlg, IDD_BKUP_RESTRICT_ACCESS ),
+ OFF );
+ }
+ if ( CDS_GetPasswordFlag( cds_ptr ) ) {
+ CheckDlgButton( hDlg, IDD_BKUP_RESTRICT_ACCESS, 1 );
+ }
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ /* check the REPLACE button */
+ CheckRadioButton( hDlg, IDD_BKUP_APPEND, IDD_BKUP_REPLACE, IDD_BKUP_REPLACE );
+
+ return ( TRUE );
+
+ case IDD_BKUP_APPEND:
+
+ /* if the user selects append operation, clear the tape name field */
+ /* and the password field */
+ buffer[0] = 0;
+
+
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ SetDlgItemText( hDlg, IDD_BKUP_PASSWORD, buffer ); /* clear password field */
+ }
+# else
+ {
+ if ( OriginalTapeSecured == ORIGINALLYSECURED ) {
+ CheckDlgButton( hDlg, IDD_BKUP_RESTRICT_ACCESS, 1 );
+
+ } else {
+ CheckDlgButton( hDlg, IDD_BKUP_RESTRICT_ACCESS, 0 );
+ }
+ EnableWindow( GetDlgItem( hDlg, IDD_BKUP_RESTRICT_ACCESS ),
+ OFF );
+ }
+
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+
+ SetDlgItemText( hDlg, IDD_BKUP_TAPE_NAME, buffer ); /* clear tape name field */
+
+ /* disable password & tape name fields */
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ EnableWindow( GetDlgItem( hDlg, IDD_BKUP_PASSWORD ) , OFF );
+ EnableWindow( GetDlgItem( hDlg, IDD_BKUP_PASSWORD_TEXT ) , OFF );
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ EnableWindow( GetDlgItem( hDlg, IDD_BKUP_TAPE_NAME ) , OFF );
+ EnableWindow( GetDlgItem( hDlg, IDD_BKUP_TAPE_NAME_TEXT ) , OFF );
+ return ( TRUE );
+
+#ifdef OEM_MSOFT //special feature
+
+ case IDD_BKUP_LOG_NONE:
+ case IDD_BKUP_LOG_SUMMARY:
+ case IDD_BKUP_LOG_FULL:
+
+ CheckRadioButton ( hDlg, IDD_BKUP_LOG_NONE,
+ IDD_BKUP_LOG_FULL, wId );
+ return TRUE;
+
+ case IDD_BKUP_RESTRICT_ACCESS:
+
+ button_state = (WORD)IsDlgButtonChecked( hDlg, IDD_BKUP_RESTRICT_ACCESS );
+ CDS_SetPasswordFlag( cds_ptr, button_state );
+
+ return TRUE;
+
+
+#endif //OEM_MSOFT //special feature
+
+/****************************************************************************
+ Cancel button
+/***************************************************************************/
+ case IDD_BKUP_CANCEL_BUTTON:
+ case IDCANCEL:
+
+ EnableWindow ( GetDlgItem ( hDlg, IDD_BKUP_CANCEL_BUTTON ), OFF );
+
+ // If poll drive is busy, we have been called from
+ // within poll drive multi-task - do not kill off the
+ // dialog.
+
+ if ( PD_IsPollDriveBusy () ) {
+
+ mwfCancelRequestDelayed = TRUE;
+ return TRUE;
+ }
+
+ backup_set_temp_ptr->dialog_return_status = TRUE;
+
+ bsd_ptr = GetBSDPointer( 0 );
+ cds_ptr = CDS_GetCopy();
+ be_cfg_ptr = BSD_GetConfigData( bsd_ptr );
+
+ /* save the state of "auto verify" */
+ button_state = (WORD)IsDlgButtonChecked( hDlg, IDD_BKUP_AUTO_VERIFY );
+ CDS_SetAutoVerifyBackup( cds_ptr, button_state );
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+ {
+ /* save the state of "include catalogs" */
+ button_state = (WORD)IsDlgButtonChecked( hDlg,IDD_BKUP_INCLUDE_CATALOGS );
+ CDS_SetBackupCatalogs( cds_ptr, button_state );
+ }
+# endif //!defined ( OEM_MSOFT ) // unsupported feature
+
+ /* save the state of "append/replace" operation */
+ button_state = (WORD)IsDlgButtonChecked( hDlg, IDD_BKUP_APPEND );
+ CDS_SetAppendFlag( cds_ptr, button_state );
+
+ /* if replace then save the tape name */
+ if( IsDlgButtonChecked( hDlg, IDD_BKUP_REPLACE ) ) {
+
+ /* save the Tape name */
+ GetDlgItemText( hDlg, IDD_BKUP_TAPE_NAME, buffer, MAX_TAPE_NAME_SIZE );
+ BSD_SetTapeLabel( bsd_ptr, (INT8_PTR)buffer,
+ (INT16) strsize( buffer ) );
+ PropagateTapeName();
+
+ }
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+ {
+ /* save the skip open wait time */
+ GetDlgItemText( hDlg, IDD_BKUP_SKIP_TIME, buffer, 5 );
+ wait_time = (WORD)atoi( buffer );
+ CDS_SetWaitTime( cds_ptr, wait_time );
+ }
+# endif //!defined ( OEM_MSOFT ) // unsupported feature
+
+ /* save the BSD items for the current BSD */
+ BackupSetSave( hDlg );
+
+ WM_UnhookTimer( backup_set_temp_ptr->timer_handle );
+ PD_SetFrequency( backup_set_temp_ptr->poll_drive_freq );
+ EndDialog( hDlg, FALSE ); /* Exits the dialog box */
+
+ return ( TRUE );
+
+/****************************************************************************
+ OK button
+/***************************************************************************/
+ case IDOK:
+ case IDD_BKUP_OK_BUTTON:
+
+ {
+ INT response;
+
+ if ( thw_list->drv_info.drv_features & TDI_DRV_COMPRESSION ) {
+ if ( IsDlgButtonChecked( hDlg, IDD_BKUP_HARDCOMP ) ) {
+ if( TF_SetHWCompression( thw_list, TRUE ) != TFLE_NO_ERR ) {
+ RSM_StringCopy( RES_HW_COMP_FAILURE, buffer, sizeof(buffer) );
+ response = WM_MsgBox( NULL, buffer, WMMB_YESNO, WMMB_ICONEXCLAMATION );
+ if ( response == WMMB_IDNO )
+ return( TRUE );
+ }
+ } else {
+
+ if( TF_SetHWCompression( thw_list, FALSE ) != TFLE_NO_ERR ) {
+ RSM_StringCopy( RES_HW_UNCOMP_FAILURE, buffer, sizeof(buffer) );
+ response = WM_MsgBox( NULL, buffer, WMMB_YESNO, WMMB_ICONEXCLAMATION );
+ if ( response == WMMB_IDNO )
+ return( TRUE );
+ }
+ }
+ }
+ }
+
+ if ( IsWindowEnabled( GetDlgItem( hDlg, IDD_BKUP_OK_BUTTON ) ) ) {
+ bsd_ptr = GetBSDPointer( 0 );
+ cds_ptr = CDS_GetCopy();
+ be_cfg_ptr = BSD_GetConfigData( bsd_ptr );
+ backup_set_temp_ptr->dialog_return_status = FALSE;
+
+// Run through all of our selected drives
+// If any of them are read-only
+// if the operation is full backup, prompt the user of the copy change
+// elseif the operation is incremental, prompt the user of the differential change
+// For all of the selected drives...
+// Do some checking to make sure the readonly drives.
+
+ BackupSetSave( hDlg );
+
+ bsd_ptr = BSD_GetFirst(bsd_list);
+ while(bsd_ptr != NULL)
+ {
+ dle_ptr = BSD_GetDLE(bsd_ptr);
+ if (!DLE_DriveWriteable(dle_ptr))
+ {
+ CHAR szTemp[ MAX_UI_RESOURCE_SIZE ];
+
+ if ( (BSD_GetBackupType(bsd_ptr) == BSD_BACKUP_NORMAL ) ||
+ (BSD_GetBackupType(bsd_ptr) == BSD_BACKUP_INCREMENTAL) )
+ {
+ // Inform user that this bsd will have type COPY
+
+ RSM_StringCopy( IDS_RDONLY_COPY, buffer, 80);
+ wsprintf( szTemp, buffer, DLE_GetDeviceName(dle_ptr) );
+
+ RSM_StringCopy( IDS_RDONLY_DRV_ENCOUNTER, buffer2, 80);
+
+ WM_MsgBox( buffer2, szTemp, WMMB_OK, WMMB_ICONEXCLAMATION ) ;
+ }
+
+ }
+ if ( ((BSD_GetOsId( bsd_ptr )== FS_EMS_DSA_ID) ||
+ (BSD_GetOsId( bsd_ptr )== FS_EMS_MDB_ID)) &&
+ ((BSD_GetBackupType(bsd_ptr) == BSD_BACKUP_DIFFERENTIAL ) ||
+ (BSD_GetBackupType(bsd_ptr) == BSD_BACKUP_INCREMENTAL) ) )
+ {
+ INT16 return_status ;
+ FSYS_HAND fsh ;
+ CHAR buf1[ MAX_UI_RESOURCE_SIZE ];
+ CHAR buf2[ MAX_UI_RESOURCE_SIZE ];
+
+ be_cfg_ptr = BSD_GetConfigData( bsd_ptr );
+
+ BEC_SetModifiedOnlyFlag( be_cfg_ptr, TRUE ) ;
+
+ return_status = FS_AttachToDLE( &fsh, dle_ptr, be_cfg_ptr, NULL, NULL ) ;
+
+ BEC_SetModifiedOnlyFlag( be_cfg_ptr, FALSE ) ;
+
+ switch( return_status ) {
+ case SUCCESS:
+ FS_DetachDLE( fsh ) ;
+ break ;
+ case FS_EMS_CIRC_LOG:
+ if (BSD_GetOsId( bsd_ptr )== FS_EMS_DSA_ID ) {
+ RSM_StringCopy( IDS_EMS_CIRC_LOGS_DS, buf1, sizeof(buf1) );
+ } else {
+ RSM_StringCopy( IDS_EMS_CIRC_LOGS_IS, buf1, sizeof(buf1) );
+ }
+
+ wsprintf( buf2, buf1, DLE_GetDeviceName(DLE_GetParent(dle_ptr)));
+ RSM_StringCopy( IDS_BACKUPERRORTITLE, buf1, sizeof(buf1) );
+
+ break;
+
+ case FS_EMS_NO_LOG_BKUP:
+ if (BSD_GetOsId( bsd_ptr )== FS_EMS_DSA_ID ) {
+ RSM_StringCopy( IDS_EMS_NO_INC_DS_BACKUP, buf1, sizeof(buf1) );
+ } else {
+ RSM_StringCopy( IDS_EMS_NO_INC_IS_BACKUP, buf1, sizeof(buf1) );
+ }
+
+ wsprintf( buf2, buf1, DLE_GetDeviceName(DLE_GetParent(dle_ptr)));
+ RSM_StringCopy( IDS_BACKUPERRORTITLE, buf1, sizeof(buf1) );
+
+ break;
+
+ case FS_ACCESS_DENIED:
+
+ RSM_StringCopy( RES_EMS_BKU_ACCESS_FAILURE, buf1, sizeof(buf1) );
+
+ wsprintf( buf2, buf1, DLE_GetDeviceName(DLE_GetParent(dle_ptr)));
+ RSM_StringCopy( IDS_BACKUPERRORTITLE, buf1, sizeof(buf1) );
+
+ break;
+
+ default:
+ if (BSD_GetOsId( bsd_ptr )== FS_EMS_DSA_ID ) {
+ RSM_StringCopy( IDS_EMS_NOT_RESPONDING_DS, buf1, sizeof(buf1) );
+ } else {
+ RSM_StringCopy( IDS_EMS_NOT_RESPONDING_IS, buf1, sizeof(buf1) );
+ }
+
+ wsprintf( buf2, buf1, DLE_GetDeviceName(DLE_GetParent(dle_ptr)));
+ RSM_StringCopy( IDS_BACKUPERRORTITLE, buf1, sizeof(buf1) );
+
+ break;
+ }
+ if ( return_status ) {
+ WM_MsgBox( buf1, buf2, WMMB_OK, WMMB_ICONEXCLAMATION );
+ return ( TRUE );
+ }
+
+ }
+ bsd_ptr = BSD_GetNext(bsd_ptr);
+ }
+
+ VLM_GetDriveStatus( &vcb_ptr );
+ generic_str_ptr = buffer;
+ bsd_ptr = GetBSDPointer( 0 );
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ GetDlgItemText( hDlg, IDD_BKUP_PASSWORD, generic_str_ptr, MAX_TAPE_PASSWORD_SIZE );
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ /* if user entered a password - verify the password */
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ if( strlen( buffer ) ) {
+
+ /* convert to upper case */
+ AnsiUpper( buffer );
+
+ /* if job password is unchanged, don't reconfirm password */
+ if(! strcmp( buffer, &backup_set_temp_ptr->job_password[0] ) ) {
+ strcpy( reenter_password, &backup_set_temp_ptr->job_password[0] );
+ }
+ else {
+
+ /* display the reenter password dialog */
+ DM_ShowDialog( hDlg, IDD_REENTER_PASSWORD, reenter_password );
+ }
+
+ if( strlen( reenter_password ) ) {
+ /* convert to upper case */
+ AnsiUpper( reenter_password );
+ }
+
+ if( strcmp( buffer, reenter_password ) ) {
+
+ RSM_StringCopy( IDS_BKUP_SHORT_PASSWORD_ERROR, buffer, sizeof(buffer) );
+ RSM_StringCopy( IDS_BKUP_PASSWORD_ERROR_TITLE, buffer2, sizeof(buffer2) );
+ WM_MsgBox( buffer2, buffer, WMMB_OK, WMMB_ICONEXCLAMATION );
+ buffer[0] = 0;
+ SetDlgItemText( hDlg, IDD_BKUP_PASSWORD, buffer ); /* clear password field */
+ SetFocus( GetDlgItem( hDlg, IDD_BKUP_PASSWORD ) );
+ return ( TRUE );
+ }
+ }
+ }
+# else
+ {
+ CHAR_PTR passwdbuffer1;
+ INT16 passwordlength;
+
+ // Check if original tape was secured
+
+ if ( OriginalTapeSecured ) {
+
+ //
+ // Check to see if is a valid user or not
+ //
+
+ generic_str_ptr = GetCurrentMachineNameUserName( );
+ passwdbuffer1 = ( CHAR_PTR )calloc( 1, ( 3 + strlen( generic_str_ptr ) ) * sizeof( CHAR ) );
+
+ if ( passwdbuffer1 ) {
+ *passwdbuffer1 = NTPASSWORDPREFIX;
+ if ( generic_str_ptr ) {
+ strcat( passwdbuffer1, generic_str_ptr );
+ }
+
+ passwordlength = strlen( passwdbuffer1 ); // chs:03-10-93
+// chs: 02-01-94 CryptPassword( ( INT16 ) ENCRYPT, ENC_ALGOR_3, (INT8_PTR)passwdbuffer1, ( INT16 ) ( passwordlength * sizeof( CHAR ) ) ); // chs:03-10-93
+
+ if( ( WhoPasswordedTape ( (BYTE_PTR)FS_ViewTapePasswordInVCB( vcb_ptr ), FS_SizeofTapePswdInVCB( vcb_ptr ) ) == OTHER_APP) ||
+ ( ! IsUserValid( vcb_ptr, (BYTE *)passwdbuffer1, ( INT16 )( passwordlength * sizeof( CHAR ) ) ) &&
+ ! DoesUserHaveThisPrivilege( TEXT ( "SeBackupPrivilege" ) ) ) ) { // chs:04-08-93
+
+ //
+ // Popup dialog box message if
+ // not a valid user
+ //
+
+ RSM_StringCopy( IDS_BKUP_TAPE_SECURITY, buffer, sizeof(buffer) );
+ RSM_StringCopy( IDS_TAPE_SECURITY_TITLE, buffer2, sizeof(buffer2) );
+ WM_MsgBox( buffer2, buffer, WMMB_OK, WMMB_ICONEXCLAMATION );
+ buffer[0] = 0;
+ free( passwdbuffer1 );
+ return ( TRUE );
+ }
+ free( passwdbuffer1 );
+ }
+ }
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ /* save the state of "auto verify" */
+ button_state = (WORD)IsDlgButtonChecked( hDlg, IDD_BKUP_AUTO_VERIFY );
+ CDS_SetAutoVerifyBackup( cds_ptr, button_state );
+
+
+# if defined ( OEM_MSOFT ) // special feature
+ {
+ CHAR szLogFile[ MAX_UI_FULLPATH_SIZE ];
+ FILE * fpLog = NULL;
+ INT nLogLevel = LOG_DISABLED;
+
+ // Get the log file name from the edit field
+ GetDlgItemText( hDlg, IDD_BKUP_LOG_FILENAME,
+ szLogFile, MAX_UI_FULLPATH_SIZE );
+
+ // if no log file named, cannot log!
+ if (*szLogFile)
+ {
+ if ( IsDlgButtonChecked( hDlg,
+ IDD_BKUP_LOG_SUMMARY ) )
+ {
+ nLogLevel = LOG_ERRORS;
+ }
+ else
+ if ( IsDlgButtonChecked( hDlg,
+ IDD_BKUP_LOG_FULL ) )
+ {
+ nLogLevel = LOG_DETAIL;
+ }
+ }
+ CDS_SetLogLevel ( cds_ptr, nLogLevel );
+
+ if ( nLogLevel != LOG_DISABLED && *szLogFile )
+ {
+ CHAR szFullLogFile[ MAX_UI_FULLPATH_SIZE ] ;
+ DWORD dwFullLogSize = MAX_UI_FULLPATH_SIZE ;
+ CHAR_PTR pLogFname ; // address of log filename
+
+ // expand user supplied log file name to a
+ // complete path and name.
+
+ dwFullLogSize = GetFullPathName( szLogFile,
+ dwFullLogSize, szFullLogFile, &pLogFname ) ;
+
+ // make sure the log file can be opened for
+ // writting.
+
+ if ( fpLog = UNI_fopen ( szFullLogFile, _O_TEXT|_O_APPEND ) )
+ {
+ LOG_SetCurrentLogName ( szFullLogFile );
+ fclose ( fpLog );
+ }
+ else
+ {
+ ShowWindow ( GetDlgItem( hDlg,
+ IDD_BKUP_LOG_FILENAME ),
+ FALSE );
+ MessageBeep ( 0 ); //NTKLUG - Need error message!!
+ ShowWindow ( GetDlgItem( hDlg,
+ IDD_BKUP_LOG_FILENAME ),
+ TRUE );
+ ShowWindow ( GetDlgItem( hDlg,
+ IDD_BKUP_LOG_FILENAME ),
+ FALSE );
+ MessageBeep ( 0 ); //NTKLUG - Need error message!!
+ ShowWindow ( GetDlgItem( hDlg,
+ IDD_BKUP_LOG_FILENAME ),
+ TRUE );
+ SetFocus( GetDlgItem( hDlg,
+ IDD_BKUP_LOG_FILENAME ) );
+
+ return ( TRUE ); // user must re-enter name!
+ }
+ }
+ else // if no file name, then cannot log!
+ {
+ CDS_SetLogLevel ( cds_ptr, LOG_DISABLED );
+ }
+ }
+# endif //defined ( OEM_MSOFT ) // special feature
+
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ /* save the state of "include catalogs" */
+ button_state = (WORD)IsDlgButtonChecked( hDlg,IDD_BKUP_INCLUDE_CATALOGS );
+ CDS_SetBackupCatalogs( cds_ptr, button_state );
+ /* if including catalogs, add one to count for catalog BSD */
+ if( button_state ) {
+ RT_max_BSD_index++;
+ }
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ /* save the state of "append/replace" operation */
+ button_state = (WORD)IsDlgButtonChecked( hDlg, IDD_BKUP_APPEND );
+ CDS_SetAppendFlag( cds_ptr, button_state );
+
+ /* if replace then save the password and tape name */
+ if( IsDlgButtonChecked( hDlg, IDD_BKUP_REPLACE ) ) {
+
+ /* save the Tape name */
+ GetDlgItemText( hDlg, IDD_BKUP_TAPE_NAME, buffer, MAX_TAPE_NAME_SIZE );
+ BSD_SetTapeLabel( bsd_ptr, (INT8_PTR)buffer,
+ (INT16) strsize( buffer ) );
+ PropagateTapeName();
+
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ /* save the Tape password */
+ generic_str_ptr = buffer;
+ GetDlgItemText( hDlg, IDD_BKUP_PASSWORD, generic_str_ptr, MAX_TAPE_PASSWORD_SIZE );
+ pswd_size = (INT16)(strlen( generic_str_ptr ) * sizeof (CHAR));
+ if( pswd_size ) {
+
+ CryptPassword( ENCRYPT, ENC_ALGOR_3, buffer, pswd_size );
+ }
+ BSD_SetTapePswd( bsd_ptr, generic_str_ptr, pswd_size );
+ PropagateTapePassword();
+
+ /* save the skip open wait time */
+ GetDlgItemText( hDlg, IDD_BKUP_SKIP_TIME, buffer, 5 );
+ wait_time = (WORD)atoi( buffer );
+ CDS_SetWaitTime( cds_ptr, wait_time );
+ }
+# else
+ {
+ CHAR_PTR passwdbuffer1;
+ INT16 passwordlength;
+
+ //
+ // If secure box checked
+ //
+
+ if ( CDS_GetPasswordFlag( cds_ptr ) ) {
+ generic_str_ptr = GetCurrentMachineNameUserName( );
+ passwdbuffer1 = ( CHAR_PTR )calloc( 1, ( 3 + strlen( generic_str_ptr ) ) * sizeof( CHAR ) );
+ if ( passwdbuffer1 ) {
+ *passwdbuffer1 = NTPASSWORDPREFIX; // chs:04-08-93
+ if ( generic_str_ptr ) {
+ strcat( passwdbuffer1, generic_str_ptr );
+ }
+ passwordlength = strlen( passwdbuffer1 ); // chs:03-10-93
+ CryptPassword( ( INT16 ) ENCRYPT, ENC_ALGOR_3, (INT8_PTR)passwdbuffer1, ( INT16 ) ( passwordlength * sizeof( CHAR ) ) ); // chs:03-10-93
+ BSD_SetTapePswd( bsd_ptr, (INT8_PTR)passwdbuffer1,( INT16 ) ( passwordlength * sizeof( CHAR ) ) ); // chs:03-10-93
+ PropagateTapePassword();
+ free( passwdbuffer1 );
+ }
+ }
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+ }
+
+ /* save the BSD items for the current BSD */
+ BackupSetSave( hDlg );
+
+ WM_UnhookTimer( backup_set_temp_ptr->timer_handle );
+ PD_SetFrequency( backup_set_temp_ptr->poll_drive_freq );
+
+ EndDialog( hDlg, TRUE ); /* Exits the dialog box */
+ }
+
+ return ( TRUE );
+
+/****************************************************************************
+ Help button
+/***************************************************************************/
+ case IDD_BKUP_HELP_BUTTON:
+ case IDHELP:
+
+#ifndef OEM_EMS
+ if ( bTransfer ) {
+ HM_DialogHelp( HELPID_DIALOGTRANSFER );
+ } else {
+ HM_DialogHelp( HELPID_DIALOGBACKUPSET );
+ }
+#else
+ help_id = DM_ModeGetHelpId( pCurMode );
+ HM_DialogHelp( help_id );
+#endif
+ return( TRUE );
+
+#ifdef OEM_MSOFT //special feature
+
+ case IDD_BKUP_LOG_BROWSE: //Log file browse button
+ {
+ CHAR szFile[ BROWSE_MAXPATH ] = TEXT("");
+
+ GetDlgItemText ( hDlg, IDD_BKUP_LOG_FILENAME, szFile, BROWSE_MAXPATH );
+
+ if ( DM_BrowseForLogFilePath ( hDlg, ghInst, szFile, strlen ( szFile ) ) ) {
+
+ SetDlgItemText ( hDlg, IDD_BKUP_LOG_FILENAME, szFile );
+ SetFocus ( GetDlgItem ( hDlg, IDD_BKUP_LOG_FILENAME ) );
+ }
+ }
+
+ break;
+
+#endif //OEM_MSOFT //special feature
+
+ default:
+ break;
+
+ } /* switch ( wId ) */
+
+ } /* case WM_COMMAND */
+ break;
+
+ } /* switch ( message ) */
+
+ return ( FALSE ); /* Didn't process a message */
+}
+/***************************************************
+
+ Name: BackupSetSave()
+
+ Description: Saves the state of the dialog
+ backup set information
+ into the current BSD.
+
+ Returns: VOID
+
+*****************************************************/
+VOID BackupSetSave(
+HWND hDlg ) /* window handle of the dialog box */
+{
+ WORD button_state;
+ WORD backup_type;
+ LPSTR generic_str_ptr;
+ BSD_PTR bsd_ptr;
+ CDS_PTR cds_ptr;
+ BE_CFG_PTR be_cfg_ptr;
+ CHAR buffer[ MAX_BSET_NAME_SIZE ];
+
+ bsd_ptr = GetBSDPointer( backup_set_temp_ptr->BSD_index );
+ cds_ptr = CDS_GetCopy();
+ be_cfg_ptr = BSD_GetConfigData( bsd_ptr );
+
+ GetDlgItemText( hDlg, IDD_BKUP_DESCRIPTION, buffer, MAX_BSET_NAME_SIZE );
+ generic_str_ptr = (LPSTR)BSD_GetBackupLabel( bsd_ptr );
+
+ if ( !generic_str_ptr ) {
+
+ BSD_SetBackupLabel( bsd_ptr, (INT8_PTR)TEXT(""), (INT16) sizeof(CHAR) );
+
+ } else if( strcmp( generic_str_ptr, buffer ) ) {
+
+ /* if new label different from old label - update label */
+
+ BSD_SetBackupLabel( bsd_ptr, (INT8_PTR)buffer,
+ (INT16) strsize( buffer) );
+ }
+
+#if !defined( OEM_MSOFT )
+ /* save the state of the "Skip open files" flag */
+ button_state = (WORD) IsDlgButtonChecked( hDlg, IDD_BKUP_SKIP_YES );
+ if( button_state ) {
+
+ BEC_SetSkipOpenFiles( be_cfg_ptr, (INT16)SKIP_YES );
+ }
+
+ button_state = (WORD)IsDlgButtonChecked( hDlg, IDD_BKUP_SKIP_NO );
+ if( button_state ) {
+
+ BEC_SetSkipOpenFiles( be_cfg_ptr, (INT16)SKIP_NO );
+ }
+
+ button_state = (WORD)IsDlgButtonChecked( hDlg, IDD_BKUP_SKIP_WAIT );
+ if( button_state ) {
+
+ BEC_SetSkipOpenFiles( be_cfg_ptr, (INT16)SKIP_NO_TIMED );
+ }
+
+
+ /* save the state of the catalog(full/partial) */
+ button_state = (WORD)IsDlgButtonChecked( hDlg, IDD_BKUP_CATALOG_FULL );
+ if( button_state ) {
+
+ BSD_SetFullyCataloged( bsd_ptr, TRUE ); /* = full */
+ }
+ else {
+
+ BSD_SetFullyCataloged( bsd_ptr, FALSE ); /* = partial */
+ }
+
+#endif
+
+# if defined ( OS_WIN32 )
+ {
+ BSD_PTR temp_bsd ;
+
+ /* if this is a normal backup */
+ if( backup_set_temp_ptr->mode_flag != ARCHIVE_BACKUP_OPER ) {
+
+ /* save the state of the bindery flag */
+
+ /* if backup bindery allowed, save the bindery flay for this BSD */
+
+ button_state = (WORD)IsDlgButtonChecked( hDlg, IDD_BKUP_REGISTRY );
+ temp_bsd = BSD_GetFirst( bsd_list );
+
+ while( temp_bsd != NULL ) {
+
+ if ( DLE_HasFeatures( BSD_GetDLE( bsd_ptr ),
+ DLE_FEAT_BKUP_SPECIAL_FILES ) ) {
+
+ UI_AddSpecialIncOrExc( bsd_ptr, button_state ) ;
+ BSD_SetProcSpecialFlg( bsd_ptr, button_state );
+
+ } else {
+ BSD_SetProcSpecialFlg( bsd_ptr, FALSE );
+
+ }
+ temp_bsd = BSD_GetNext( temp_bsd ) ;
+ }
+ }
+ }
+# else
+ {
+
+
+ /* if this is a normal backup */
+ if( backup_set_temp_ptr->mode_flag != ARCHIVE_BACKUP_OPER ) {
+
+ /* save the state of the bindery flag */
+
+ /* if backup bindery allowed, save the bindery flay for this BSD */
+ if ( DLE_HasFeatures( BSD_GetDLE( bsd_ptr ),
+ DLE_FEAT_BKUP_SPECIAL_FILES ) ) {
+
+ button_state = (WORD)IsDlgButtonChecked( hDlg, IDD_BKUP_BACKUP_BINDERY );
+ BSD_SetProcSpecialFlg( bsd_ptr, button_state );
+ }
+ }
+ }
+# endif //!defined ( OS_WIN32 ) //unsupported feature -- skipped files
+
+
+ /* save the method of backup type */
+ /* defined in BSDU.H */
+ /* methods are: BSD_BACKUP_NORMAL 1 */
+ /* BSD_BACKUP_COPY 2 */
+ /* BSD_BACKUP_DIFFERENTIAL 3 */
+ /* BSD_BACKUP_INCREMENTAL 4 */
+ /* entries in the combo box start at 0 */
+
+ switch( BSD_GetOsId( bsd_ptr ) ) {
+
+#ifdef OEM_EMS
+ case FS_EMS_DSA_ID:
+ case FS_EMS_MDB_ID:
+ backup_type = (WORD)SendDlgItemMessage( hDlg, IDD_XCHG_BKUP_METHOD,
+ CB_GETCURSEL, 0, 0 );
+ break;
+#endif
+
+ default:
+
+ backup_type = (WORD)SendDlgItemMessage( hDlg, IDD_BKUP_METHOD,
+ CB_GETCURSEL, 0, 0 );
+ }
+
+ if( backup_set_temp_ptr->mode_flag == ARCHIVE_BACKUP_OPER ) {
+ backup_type += 2;
+ }
+ else {
+ backup_type += 1;
+ }
+ BSD_SetBackupType( bsd_ptr, (INT16)( backup_type ) );
+}
+/***************************************************
+
+ Name: BackupSetRetrieve()
+
+ Description: Retrieves the state of the current BSD
+ backup set information and updates
+ the fields in the dialog.
+
+ Returns: VOID
+
+*****************************************************/
+#ifndef OEM_EMS
+VOID BackupSetRetrieve(
+ HWND hDlg ) /* window handle of the dialog box */
+#else
+VOID BackupSetRetrieve(
+ HWND hDlg,
+ DLG_MODE * pModeTable )
+#endif
+{
+ WORD status;
+ WORD backup_type;
+ LPSTR generic_str_ptr;
+ CHAR buffer[ MAX_UI_RESOURCE_SIZE ];
+ CHAR buffer2[ MAX_UI_RESOURCE_SIZE ];
+ BSD_PTR bsd_ptr;
+ CDS_PTR cds_ptr;
+ BE_CFG_PTR be_cfg_ptr;
+ GENERIC_DLE_PTR dle_ptr;
+ GENERIC_DLE_PTR parent_dle;
+ CHAR szFormat[ MAX_UI_RESOURCE_SIZE ];
+ CHAR szName[ MAX_DEVICE_NAME_SIZE ];
+
+ bsd_ptr = GetBSDPointer( backup_set_temp_ptr->BSD_index );
+ cds_ptr = CDS_GetCopy();
+ be_cfg_ptr = BSD_GetConfigData( bsd_ptr );
+ dle_ptr = BSD_GetDLE( bsd_ptr );
+
+ generic_str_ptr = (LPSTR)BSD_GetBackupLabel( bsd_ptr );
+ SetDlgItemText( hDlg, IDD_BKUP_DESCRIPTION, generic_str_ptr );
+
+ DLE_GetVolName( dle_ptr, buffer );
+ SetDlgItemText( hDlg, IDD_BKUP_DRIVE_NAME, buffer );
+
+ // Create the string for the Exchange Component field.
+ DLE_DeviceDispName( dle_ptr, buffer, MAX_DEVICE_NAME_LEN, 0 );
+
+ parent_dle = DLE_GetParent( dle_ptr );
+
+ if ( NULL != parent_dle ) {
+
+ DLE_DeviceDispName( parent_dle, buffer2, MAX_DEVICE_NAME_LEN, 0 );
+
+ } else {
+
+ buffer2[0] = TEXT( '\0' );
+
+ }
+
+ RSM_StringCopy( IDS_XCHG_BKUP_NAME, szFormat, MAX_UI_RESOURCE_LEN );
+ wsprintf( szName, szFormat, buffer, buffer2 );
+
+ SetDlgItemText( hDlg, IDD_BKUP_XCHG_NAME, szName );
+
+# if defined ( OS_WIN32 )
+ {
+ if( backup_set_temp_ptr->mode_flag != ARCHIVE_BACKUP_OPER ) {
+
+ EnableWindow( GetDlgItem( hDlg, IDD_BKUP_REGISTRY ),
+ DLE_HasFeatures( BSD_GetDLE( bsd_ptr ),
+ DLE_FEAT_BKUP_SPECIAL_FILES ) );
+
+ CheckDlgButton( hDlg, IDD_BKUP_REGISTRY,
+ BSD_GetProcSpecialFlg( bsd_ptr ) || gfIsJobRunning );
+ }
+ else {
+
+ /* transfer operation - disable bindery check box */
+ EnableWindow( GetDlgItem( hDlg, IDD_BKUP_REGISTRY ), FALSE );
+ }
+ }
+# else
+ {
+
+# if defined ( TDEMO )
+ /* tdemo exe - disable bindery check box */
+ EnableWindow( GetDlgItem( hDlg, IDD_BKUP_BACKUP_BINDERY ), FALSE );
+# else
+ /* Bindery check box */
+ /* if this is a normal backup */
+ if( backup_set_temp_ptr->mode_flag != ARCHIVE_BACKUP_OPER ) {
+
+ /* enable bindery check box */
+ EnableWindow( GetDlgItem( hDlg, IDD_BKUP_BACKUP_BINDERY ), TRUE );
+
+ status = BSD_GetProcSpecialFlg( bsd_ptr );
+ CheckDlgButton( hDlg, IDD_BKUP_BACKUP_BINDERY, status );
+
+ /* check for backup bindery, enable/disable the control */
+ status = DLE_HasFeatures( BSD_GetDLE( bsd_ptr ),
+ DLE_FEAT_BKUP_SPECIAL_FILES );
+
+ EnableWindow( GetDlgItem( hDlg, IDD_BKUP_BACKUP_BINDERY ), status );
+ }
+ else {
+
+ /* transfer operation - disable bindery check box */
+ EnableWindow( GetDlgItem( hDlg, IDD_BKUP_BACKUP_BINDERY ), FALSE );
+ }
+# endif // defined TDEMO
+
+ }
+# endif //defined ( OEM_MSOFT ) //unsupported feature
+
+# if !defined ( OEM_MSOFT )
+ /* Catalog check box */
+ if( BSD_GetFullyCataloged( bsd_ptr ) ) {
+
+ CheckRadioButton( hDlg, IDD_BKUP_CATALOG_FULL, IDD_BKUP_CATALOG_PARTIAL, IDD_BKUP_CATALOG_FULL );
+ }
+ else {
+
+ CheckRadioButton( hDlg, IDD_BKUP_CATALOG_FULL, IDD_BKUP_CATALOG_PARTIAL, IDD_BKUP_CATALOG_PARTIAL );
+ }
+
+ /* Skip open files check box */
+ status = BEC_GetSkipOpenFiles( be_cfg_ptr );
+
+ if( status == SKIP_YES ) {
+
+ CheckRadioButton( hDlg, IDD_BKUP_SKIP_YES, IDD_BKUP_SKIP_WAIT, IDD_BKUP_SKIP_YES );
+ }
+ else if( status == SKIP_NO ) {
+
+ CheckRadioButton( hDlg, IDD_BKUP_SKIP_YES, IDD_BKUP_SKIP_WAIT, IDD_BKUP_SKIP_NO );
+ }
+ else if( status == SKIP_NO_TIMED ) {
+
+ CheckRadioButton( hDlg, IDD_BKUP_SKIP_YES, IDD_BKUP_SKIP_WAIT, IDD_BKUP_SKIP_WAIT );
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ /* add "1 of n" to backup set info title */
+ RSM_StringCopy( IDS_SET_INFORMATION, buffer, sizeof(buffer) );
+ wsprintf( buffer2, buffer, backup_set_temp_ptr->BSD_index + 1, backup_set_temp_ptr->max_BSD_index + 1 );
+ SetDlgItemText( hDlg, IDD_BKUP_INFO_TITLE, buffer2 );
+
+ /* set the method of backup type */
+ /* defined in BSDU.H */
+ /* methods are: BSD_BACKUP_NORMAL 1 */
+ /* BSD_BACKUP_COPY 2 */
+ /* BSD_BACKUP_DIFFERENTIAL 3 */
+ /* BSD_BACKUP_INCREMENTAL 4 */
+ /* entries in the combo box start at 0 */
+
+ backup_type = BSD_GetBackupType( bsd_ptr );
+ if( backup_set_temp_ptr->mode_flag == ARCHIVE_BACKUP_OPER ) {
+ backup_type -= 2;
+ }
+ else {
+ backup_type -= 1;
+ }
+ SendDlgItemMessage( hDlg, IDD_BKUP_METHOD, CB_SETCURSEL,
+ backup_type , 0 );
+
+#ifdef OEM_EMS
+ SendDlgItemMessage( hDlg, IDD_XCHG_BKUP_METHOD, CB_SETCURSEL,
+ backup_type , 0 );
+
+#endif
+
+#ifdef OEM_EMS
+ BSD_SetOsId( bsd_ptr, DLE_GetOsId( dle_ptr ) );
+ DM_DispShowControls( hDlg, pModeTable, (INT)DLE_GetOsId( dle_ptr ) );
+#endif
+
+}
+/***************************************************
+
+ Name: BackupSetDefaultDescription()
+
+ Description: Fills in all of the default data for
+ each BSD of this backup operation.
+
+ Returns: Returns with the max count of BSD's for
+ this backup operation.
+
+*****************************************************/
+INT BackupSetDefaultDescription( VOID )
+{
+ BSD_PTR bsd_ptr;
+ CDS_PTR cds_ptr;
+ GENERIC_DLE_PTR dle_ptr;
+ BE_CFG_PTR be_cfg_ptr;
+ CHAR buffer[MAX_UI_RESOURCE_SIZE];
+ CHAR_PTR s;
+ WORD BSD_index_counter;
+#if !defined ( OEM_MSOFT )
+ INT16 lngth; // chs:04-22-93
+#endif
+
+ cds_ptr = CDS_GetCopy();
+
+ BSD_index_counter = 0;
+ bsd_ptr = BSD_GetFirst( bsd_list );
+
+ while( bsd_ptr != NULL ) {
+
+ /* if tape label equal null, set up the default data for this bsd */
+ if( ! BSD_GetTapeLabel( bsd_ptr ) ) {
+
+ /* get this BSDs config pointer */
+ be_cfg_ptr = BSD_GetConfigData( bsd_ptr );
+
+ /* set default tape name */
+
+ {
+ CHAR tmp_buf1[ MAX_TAPE_NAME_LEN ];
+ CHAR tmp_buf2[ MAX_TAPE_NAME_LEN ];
+ RSM_StringCopy( IDS_DEFAULT_TAPE_NAME, tmp_buf1, MAX_TAPE_NAME_LEN );
+ UI_CurrentDate( tmp_buf2 );
+ wsprintf( buffer, tmp_buf1, tmp_buf2 ) ;
+ }
+ //
+ // Append the time to the tape label to give it uniqueness
+ //
+
+# if !defined ( OEM_MSOFT ) // chs:04-22-93
+ { // chs:04-22-93
+ strcat( buffer, TEXT( " at " ) ); // chs:04-22-93
+ lngth = strlen( buffer ); // chs:04-22-93
+ UI_CurrentTime ( &buffer[ lngth ] ); // chs:04-22-93
+ } // chs:04-22-93
+# endif //!defined ( OEM_MSOFT ) // chs:04-22-93
+
+ BSD_SetTapeLabel( bsd_ptr, (INT8_PTR)buffer,
+ (INT16) strsize( buffer ) );
+
+ /* set default backup label */
+ buffer[0] = 0;
+ BSD_SetBackupLabel( bsd_ptr, (INT8_PTR)buffer,
+ (INT16) strsize( buffer) );
+
+ /* set the default description name */
+ dle_ptr = BSD_GetDLE( bsd_ptr );
+
+ DLE_GetVolName( dle_ptr, buffer );
+
+ s = buffer;
+ while ( *s )
+ s++;
+ *s++ = TEXT(' ');
+ UI_CurrentDate( s );
+
+ buffer[ MAX_BSET_DESC_SIZE ] = 0;
+
+ BSD_SetBackupDescript( bsd_ptr, (INT8_PTR)buffer,
+ (INT16) strsize( buffer ) );
+
+ }
+ /* count the total BSD's */
+ BSD_index_counter++;
+
+ bsd_ptr = BSD_GetNext( bsd_ptr );
+ }
+ return( --BSD_index_counter );
+}
+/***************************************************
+
+ Name: BackupSetDefaultSettings()
+
+ Description: Fills in all of the default settings data for
+ each BSD of this backup operation.
+
+ Returns: VOID
+
+*****************************************************/
+VOID BackupSetDefaultSettings( VOID )
+{
+ BSD_PTR bsd_ptr;
+ CDS_PTR cds_ptr;
+ BE_CFG_PTR be_cfg_ptr;
+ WORD backup_type;
+ WORD catalog_mode;
+ INT16 skip_open_files;
+
+ cds_ptr = CDS_GetCopy();
+
+ backup_type = CDS_GetDefaultBackupType( cds_ptr );
+
+ /* Copy is the only method allowed with Transfer operation */
+ if( backup_set_temp_ptr->mode_flag == ARCHIVE_BACKUP_OPER ) {
+ backup_type = BSD_BACKUP_COPY;
+ }
+
+#if defined ( TDEMO )
+
+ /* if a NORMAL backup, only allow the COPY method to prevent */
+ /* the achived bit from beening reset */
+
+ if( backup_set_temp_ptr->mode_flag != ARCHIVE_BACKUP_OPER ) {
+
+ backup_type = BSD_BACKUP_COPY;
+ }
+#endif
+
+ skip_open_files = CDS_GetSkipOpenFiles( cds_ptr );
+
+ catalog_mode = CDS_GetCatalogLevel( cds_ptr );
+ if( catalog_mode == CATALOGS_FULL ) {
+
+ catalog_mode = TRUE;
+ }
+ else {
+
+ catalog_mode = FALSE;
+ }
+
+ bsd_ptr = BSD_GetFirst( bsd_list );
+
+ while( bsd_ptr != NULL ) {
+
+ /* get this BSDs config pointer */
+ be_cfg_ptr = BSD_GetConfigData( bsd_ptr );
+
+ /*set the default backup type */
+ BSD_SetBackupType( bsd_ptr, backup_type );
+
+ /* set the default catalog mode(full/partial) */
+ BSD_SetFullyCataloged( bsd_ptr, catalog_mode );
+
+ /* set the skip open files for all BSD's */
+ BEC_SetSkipOpenFiles( be_cfg_ptr, skip_open_files );
+
+#ifdef OS_WIN32
+ /* always default not to back up registry files */
+ BSD_SetProcSpecialFlg( bsd_ptr, FALSE ) ;
+#else
+ /* if backup bindery allowed, set the bindery flay on for this BSD */
+
+ if ( DLE_HasFeatures( BSD_GetDLE( bsd_ptr ),
+ DLE_FEAT_BKUP_SPECIAL_FILES ) ) {
+
+
+ /* if this is a normal backup, set the bindery flag */
+ if( backup_set_temp_ptr->mode_flag != ARCHIVE_BACKUP_OPER ) {
+ BSD_SetProcSpecialFlg( bsd_ptr, TRUE );
+ }
+ else {
+ BSD_SetProcSpecialFlg( bsd_ptr, FALSE );
+ }
+ }
+#endif
+
+ bsd_ptr = BSD_GetNext( bsd_ptr );
+ }
+}
+/***************************************************
+
+ Name: GetBSDPointer()
+
+ Description: Finds the current BSD pointer
+
+ Returns: Returns the requested BSD pointer
+
+*****************************************************/
+BSD_PTR GetBSDPointer(
+WORD current_BSD_index ) /* I - current BSD index */
+{
+ BSD_PTR bsd_ptr;
+
+ if( !current_BSD_index ) {
+
+ bsd_ptr = BSD_GetFirst( bsd_list );
+ }
+ else {
+
+ bsd_ptr = BSD_GetFirst( bsd_list );
+ current_BSD_index--;
+ do {
+
+ bsd_ptr = BSD_GetNext( bsd_ptr );
+ } while( current_BSD_index-- );
+ }
+ return( bsd_ptr );
+}
+/***************************************************
+
+ Name: PropagateTapeName()
+
+ Description: Propagate the tape name to all of ths BSD's
+
+ Returns: VOID
+
+*****************************************************/
+VOID PropagateTapeName( VOID )
+{
+ BSD_PTR bsd_ptr;
+ CHAR buffer[ MAX_TAPE_NAME_SIZE ];
+ LPSTR generic_str_ptr;
+ WORD character_counter = 0;
+ CHAR_PTR s;
+
+ bsd_ptr = BSD_GetFirst( bsd_list );
+ generic_str_ptr = (LPSTR)BSD_GetTapeLabel( bsd_ptr );
+ strcpy( buffer, generic_str_ptr );
+
+ generic_str_ptr = buffer;
+ while( *generic_str_ptr ) {
+
+ if( *generic_str_ptr != TEXT(' ') ) {
+
+ character_counter++;
+ break;
+ }
+ *generic_str_ptr++;
+ }
+
+ /* if tape name field blank or all spaces - replace with the default name */
+ if( *generic_str_ptr == 0 && character_counter == 0 ) {
+ CHAR tmp_buf1[ MAX_TAPE_NAME_LEN ];
+ CHAR tmp_buf2[ MAX_TAPE_NAME_LEN ];
+ RSM_StringCopy( IDS_DEFAULT_TAPE_NAME, tmp_buf1, MAX_TAPE_NAME_LEN );
+ UI_CurrentDate( tmp_buf2 );
+ wsprintf( buffer, tmp_buf1, tmp_buf2 ) ;
+ }
+
+ while( bsd_ptr != NULL ) {
+
+ BSD_SetTapeLabel( bsd_ptr, (INT8_PTR)buffer,
+ (INT16) strsize( buffer ) );
+ bsd_ptr = BSD_GetNext( bsd_ptr );
+ }
+}
+/***************************************************
+
+ Name: PropagateTapePassword()
+
+ Description: Propagate the tape password to all of ths BSD's
+
+ Returns: VOID
+
+*****************************************************/
+VOID PropagateTapePassword( VOID )
+{
+ BSD_PTR bsd_ptr;
+ LPSTR generic_str_ptr;
+ INT16 pswd_size;
+
+ bsd_ptr = BSD_GetFirst( bsd_list );
+ generic_str_ptr = (LPSTR)BSD_GetTapePswd( bsd_ptr );
+ pswd_size = BSD_GetTapePswdSize( bsd_ptr );
+
+ bsd_ptr = BSD_GetNext( bsd_ptr );
+ while( bsd_ptr != NULL ) {
+
+ BSD_SetTapePswd( bsd_ptr, (INT8_PTR)generic_str_ptr, pswd_size );
+ bsd_ptr = BSD_GetNext( bsd_ptr );
+ }
+}
+/***************************************************
+
+ Name: DM_ReenterPassword()
+
+ Description: Reenter password dialog
+
+ Returns:
+
+*****************************************************/
+DLGRESULT APIENTRY DM_ReenterPassword(
+ HWND hDlg , /* window handle of the dialog box */
+ MSGID message , /* type of message */
+ MPARAM1 mp1 , /* message-specific information */
+ MPARAM2 mp2 )
+{
+
+ switch ( message )
+ {
+ case WM_INITDIALOG: /* message: initialize dialog box */
+
+ DM_CenterDialog( hDlg );
+
+ reenter_password_ptr = (VOID_PTR)mp2;
+ SendDlgItemMessage( hDlg, IDD_PASSWORD_EDIT, EM_LIMITTEXT,
+ MAX_TAPE_PASSWORD_LEN, 0 );
+ return ( TRUE );
+
+ case WM_COMMAND: /* message: received a command */
+ {
+ WORD wId = GET_WM_COMMAND_ID ( mp1, mp2 );
+
+ if ( wId == IDOK || wId == IDD_PASSWORD_OK ) { /* System menu close command? */
+
+ GetDlgItemText( hDlg, IDD_PASSWORD_EDIT, (LPSTR)reenter_password_ptr, MAX_TAPE_PASSWORD_SIZE );
+ EndDialog( hDlg, TRUE ); /* Exits the dialog box */
+ return ( TRUE );
+ }
+ }
+ break;
+ }
+ return ( FALSE ); /* Didn't process a message */
+}
+
+/***************************************************
+
+ Name: clock_routine
+
+ Description: poll drive status routine
+
+ Returns: void
+
+*****************************************************/
+static VOID clock_routine( VOID )
+{
+ DBLK_PTR vcb_ptr;
+ WORD status;
+ CDS_PTR cds_ptr;
+ UINT32 current_tape_id;
+ TFINF_PTR fmt_info ;
+#if defined ( OEM_MSOFT )
+ INT16 tape_time;
+ INT16 tape_date;
+ CHAR creation_str[MAX_UI_DATE_SIZE+MAX_UI_TIME_SIZE] ;
+ CHAR creation_time_str[MAX_UI_TIME_SIZE] ;
+#endif
+
+ cds_ptr = CDS_GetCopy();
+
+ // If the user requested that we cancel and the request was delayed,
+ // kill off the dialog.
+
+ if ( mwfCancelRequestDelayed ) {
+
+ SendMessage ( backup_set_temp_ptr->ghDlg, WM_COMMAND, IDCANCEL, (MP2) NULL );
+ mwfCancelRequestDelayed = FALSE;
+ return;
+ }
+
+ status = VLM_GetDriveStatus( &vcb_ptr );
+
+ switch( status ) {
+
+ case VLM_VALID_TAPE:
+
+ /* get tape ID */
+ current_tape_id = FS_ViewTapeIDInVCB( vcb_ptr );
+
+ /* if this ID not equal to the last ID, then must be a new tape */
+ if( backup_set_temp_ptr->tape_id != current_tape_id ) {
+
+ backup_set_temp_ptr->tape_id = current_tape_id;
+
+ /* get the new tape tape name */
+ yprintf( TEXT("%s"), FS_ViewTapeNameInVCB( vcb_ptr ) );
+ backup_set_temp_ptr->tape_password_leng = FS_SizeofTapePswdInVCB( vcb_ptr );
+
+ SetDlgItemText( backup_set_temp_ptr->ghDlg, IDD_BKUP_CURRENT_TAPE_NAME, gszTprintfBuffer );
+
+ /* turn the OK button on */
+ EnableWindow ( GetDlgItem ( backup_set_temp_ptr->ghDlg, IDD_BKUP_OK_BUTTON ), ON );
+
+ /* if normal tape and archive operation, or append not allowed
+ to this format ...
+ */
+ fmt_info = TF_GetTapeFormat( 0 ) ;
+ if( ( ! ( FS_GetAttribFromVCB( vcb_ptr ) & VCB_ARCHIVE_BIT ) &&
+ ( backup_set_temp_ptr->mode_flag == ARCHIVE_BACKUP_OPER ) ) ||
+ ( fmt_info == NULL ) ||
+ ( !( fmt_info->attributes & APPEND_SUPPORTED ) ) ) {
+
+ /* change the mode to replace and disable the append button */
+ SendMessage( backup_set_temp_ptr->ghDlg, WM_COMMAND, IDD_BKUP_REPLACE, (LONG)NULL );
+ EnableWindow( GetDlgItem( backup_set_temp_ptr->ghDlg, IDD_BKUP_APPEND ), OFF );
+ }
+ else {
+ /* enable the append button */
+ EnableWindow( GetDlgItem( backup_set_temp_ptr->ghDlg, IDD_BKUP_APPEND ), ON );
+ }
+# if defined ( OEM_MSOFT ) //unsupported feature
+ // Get the creation date of this tape if there is one
+
+ VLM_GetTapeOwnersName( current_tape_id, gszTprintfBuffer );
+
+ SetDlgItemText( backup_set_temp_ptr->ghDlg, IDD_BKUP_OWNER, gszTprintfBuffer );
+
+ VLM_GetTapeCreationDate( current_tape_id, &tape_date, &tape_time );
+
+ UI_IntToDate( creation_str, tape_date ) ;
+ UI_IntToTime( creation_time_str, tape_time ) ;
+
+ strcat( creation_str, TEXT(" ") ) ;
+ strcat( creation_str, creation_time_str ) ;
+ SetDlgItemText( backup_set_temp_ptr->ghDlg, IDD_BKUP_CREATION_DATE, creation_str ) ;
+
+ // Check to see if tape was previously secured, check to
+ // see if Tape has any password.
+ if ( IsCurrentTapeSecured( vcb_ptr ) ) {
+ // check the secure check box
+ CheckDlgButton( backup_set_temp_ptr->ghDlg, IDD_BKUP_RESTRICT_ACCESS, 1 );
+ OriginalTapeSecured = ORIGINALLYSECURED;
+ CDS_SetPasswordFlag( cds_ptr, CDS_ENABLE );
+ }
+ else {
+ OriginalTapeSecured = ORIGINALLYUNSECURED;
+ }
+
+ EnableWindow( GetDlgItem( backup_set_temp_ptr->ghDlg, IDD_BKUP_RESTRICT_ACCESS ),
+ ON );
+
+ EnableSecurityDlgFlag = 1;
+
+# endif
+ }
+ break;
+
+ case VLM_GOOFY_TAPE:
+ case VLM_FUTURE_VER:
+ case VLM_SQL_TAPE:
+ case VLM_ECC_TAPE:
+ case VLM_BAD_TAPE:
+ case VLM_FOREIGN_TAPE:
+
+ if(backup_set_temp_ptr->display_status != VLM_FOREIGN_TAPE ) {
+
+ backup_set_temp_ptr->display_status = VLM_FOREIGN_TAPE;
+ backup_set_temp_ptr->tape_id = 0;
+ backup_set_temp_ptr->tape_password_leng = 0;
+ yresprintf( (INT16) RES_ERASE_FOREIGN_TAPE );
+ SetDlgItemText( backup_set_temp_ptr->ghDlg, IDD_BKUP_CURRENT_TAPE_NAME, gszTprintfBuffer );
+
+ /* turn the OK button OFF */
+ EnableWindow ( GetDlgItem ( backup_set_temp_ptr->ghDlg, IDD_BKUP_OK_BUTTON ), OFF );
+ }
+# if defined ( OEM_MSOFT ) //unsupported feature
+ // Blank out the creation date
+ SetDlgItemText( backup_set_temp_ptr->ghDlg, IDD_BKUP_CREATION_DATE, TEXT(" ") ) ;
+
+ EnableWindow( GetDlgItem( backup_set_temp_ptr->ghDlg, IDD_BKUP_RESTRICT_ACCESS ),
+ OFF );
+
+ // uncheck the secure box
+ CheckDlgButton( backup_set_temp_ptr->ghDlg, IDD_BKUP_RESTRICT_ACCESS, 0 );
+# endif
+ break;
+
+ case VLM_BLANK_TAPE:
+
+ if(backup_set_temp_ptr->display_status != VLM_BLANK_TAPE ) {
+
+ backup_set_temp_ptr->display_status = VLM_BLANK_TAPE;
+ backup_set_temp_ptr->tape_id = 0;
+ backup_set_temp_ptr->tape_password_leng = 0;
+ yresprintf( (INT16) RES_ERASE_BLANK_TAPE );
+ SetDlgItemText( backup_set_temp_ptr->ghDlg, IDD_BKUP_CURRENT_TAPE_NAME, gszTprintfBuffer );
+
+ /* turn the OK button on */
+ EnableWindow ( GetDlgItem ( backup_set_temp_ptr->ghDlg, IDD_BKUP_OK_BUTTON ), ON );
+
+ /* change the mode to replace and disable the append button */
+ SendMessage( backup_set_temp_ptr->ghDlg, WM_COMMAND, IDD_BKUP_REPLACE, (LONG)NULL );
+ EnableWindow( GetDlgItem( backup_set_temp_ptr->ghDlg, IDD_BKUP_APPEND ), OFF );
+ }
+# if defined ( OEM_MSOFT ) //unsupported feature
+
+ EnableWindow( GetDlgItem( backup_set_temp_ptr->ghDlg, IDD_BKUP_RESTRICT_ACCESS ),
+ ON );
+
+ EnableSecurityDlgFlag = 1;
+
+ // Blank out the creation date
+ SetDlgItemText( backup_set_temp_ptr->ghDlg, IDD_BKUP_CREATION_DATE, TEXT(" ") ) ;
+
+ OriginalTapeSecured = ORIGINALLYUNSECURED;
+# endif
+ break;
+
+ case VLM_DRIVE_FAILURE:
+
+ if(backup_set_temp_ptr->display_status != VLM_DRIVE_FAILURE ) {
+
+ backup_set_temp_ptr->display_status = VLM_DRIVE_FAILURE;
+ backup_set_temp_ptr->tape_id = 0;
+ backup_set_temp_ptr->tape_password_leng = 0;
+ yresprintf( (INT16) RES_DRIVE_ERROR_DETECTED );
+ SetDlgItemText( backup_set_temp_ptr->ghDlg, IDD_BKUP_CURRENT_TAPE_NAME, gszTprintfBuffer );
+ SetDlgItemText( backup_set_temp_ptr->ghDlg, IDD_BKUP_TAPE_NAME, TEXT(" ") ) ;
+
+ /* turn the OK button off when no tape */
+ EnableWindow ( GetDlgItem ( backup_set_temp_ptr->ghDlg, IDD_BKUP_OK_BUTTON ), OFF );
+ }
+# if defined ( OEM_MSOFT ) //unsupported feature
+ // Blank out the creation date
+ SetDlgItemText( backup_set_temp_ptr->ghDlg, IDD_BKUP_CREATION_DATE, TEXT(" ") ) ;
+
+ EnableWindow( GetDlgItem( backup_set_temp_ptr->ghDlg, IDD_BKUP_RESTRICT_ACCESS ),
+ OFF );
+
+ // uncheck the secure box
+ CheckDlgButton( backup_set_temp_ptr->ghDlg, IDD_BKUP_RESTRICT_ACCESS, 0 );
+# endif
+ break;
+
+ case VLM_NO_TAPE:
+
+ if(backup_set_temp_ptr->display_status != VLM_NO_TAPE ) {
+
+ backup_set_temp_ptr->display_status = VLM_NO_TAPE;
+ backup_set_temp_ptr->tape_id = 0;
+ backup_set_temp_ptr->tape_password_leng = 0;
+ yresprintf( (INT16) RES_ERASE_NO_TAPE );
+ SetDlgItemText( backup_set_temp_ptr->ghDlg, IDD_BKUP_CURRENT_TAPE_NAME, gszTprintfBuffer );
+
+ /* turn the OK button off when no tape */
+ EnableWindow ( GetDlgItem ( backup_set_temp_ptr->ghDlg, IDD_BKUP_OK_BUTTON ), OFF );
+ }
+# if defined ( OEM_MSOFT ) //unsupported feature
+ // Blank out the creation date
+ SetDlgItemText( backup_set_temp_ptr->ghDlg, IDD_BKUP_OWNER, TEXT(" ") );
+ SetDlgItemText( backup_set_temp_ptr->ghDlg, IDD_BKUP_CREATION_DATE, TEXT(" ") ) ;
+
+ EnableWindow( GetDlgItem( backup_set_temp_ptr->ghDlg, IDD_BKUP_RESTRICT_ACCESS ),
+ OFF );
+
+ // uncheck the secure box
+ CheckDlgButton( backup_set_temp_ptr->ghDlg, IDD_BKUP_RESTRICT_ACCESS, 0 );
+# endif
+ break;
+
+#ifdef OS_WIN32
+ case VLM_UNFORMATED:
+
+ if(backup_set_temp_ptr->display_status != VLM_UNFORMATED ) {
+
+ backup_set_temp_ptr->display_status = VLM_UNFORMATED;
+ backup_set_temp_ptr->tape_id = 0;
+ backup_set_temp_ptr->tape_password_leng = 0;
+ yresprintf( (INT16) RES_VLM_UNFORMATED_TAPE );
+ SetDlgItemText( backup_set_temp_ptr->ghDlg, IDD_BKUP_CURRENT_TAPE_NAME, gszTprintfBuffer );
+
+ /* turn the OK button off when tape not formated */
+ EnableWindow ( GetDlgItem ( backup_set_temp_ptr->ghDlg, IDD_BKUP_OK_BUTTON ), OFF );
+ }
+# if defined ( OEM_MSOFT ) //unsupported feature
+ // Blank out the creation date
+ SetDlgItemText( backup_set_temp_ptr->ghDlg, IDD_BKUP_CREATION_DATE, TEXT(" ") ) ;
+
+ EnableWindow( GetDlgItem( backup_set_temp_ptr->ghDlg, IDD_BKUP_RESTRICT_ACCESS ),
+ OFF );
+
+ // uncheck the secure box
+ CheckDlgButton( backup_set_temp_ptr->ghDlg, IDD_BKUP_RESTRICT_ACCESS, 0 );
+# endif
+ break;
+#endif // OS_WIN32
+
+ case VLM_BUSY:
+
+ if(backup_set_temp_ptr->display_status != VLM_BUSY ) {
+
+ backup_set_temp_ptr->display_status = VLM_BUSY;
+ backup_set_temp_ptr->tape_id = 0;
+ backup_set_temp_ptr->tape_password_leng = 0;
+ yresprintf( (INT16) RES_ERASE_DRIVE_BUSY );
+ SetDlgItemText( backup_set_temp_ptr->ghDlg, IDD_BKUP_CURRENT_TAPE_NAME, gszTprintfBuffer );
+
+ /* turn the OK button off when busy */
+ EnableWindow ( GetDlgItem ( backup_set_temp_ptr->ghDlg, IDD_BKUP_OK_BUTTON ), OFF );
+ }
+# if defined ( OEM_MSOFT ) //unsupported feature
+ // Blank out the creation date
+ SetDlgItemText( backup_set_temp_ptr->ghDlg, IDD_BKUP_CREATION_DATE, TEXT(" ") ) ;
+
+ EnableWindow( GetDlgItem( backup_set_temp_ptr->ghDlg, IDD_BKUP_RESTRICT_ACCESS ),
+ OFF );
+
+ // uncheck the secure box
+ CheckDlgButton( backup_set_temp_ptr->ghDlg, IDD_BKUP_RESTRICT_ACCESS, 0 );
+# endif
+ break;
+ default:
+# if defined ( OEM_MSOFT ) //unsupported feature
+ // Blank out the creation date
+ SetDlgItemText( backup_set_temp_ptr->ghDlg, IDD_BKUP_CREATION_DATE, TEXT(" ") ) ;
+
+ EnableWindow( GetDlgItem( backup_set_temp_ptr->ghDlg, IDD_BKUP_RESTRICT_ACCESS ),
+ OFF );
+
+ // uncheck the secure box
+ CheckDlgButton( backup_set_temp_ptr->ghDlg, IDD_BKUP_RESTRICT_ACCESS, 0 );
+
+# endif
+ break;
+ } /* end switch statment */
+} /* end clock routine */
+
+/***************************************************
+
+ Name: ScrollLineDown
+
+ Description: decrements the index counter
+
+ Returns: void
+
+*****************************************************/
+static VOID ScrollLineDown( VOID )
+{
+ if( backup_set_temp_ptr->BSD_index > 0 ) {
+
+ backup_set_temp_ptr->BSD_index--;
+ }
+}
+
+/***************************************************
+
+ Name: ScrollLineUp
+
+ Description: increments the index counter
+
+ Returns: void
+
+*****************************************************/
+static VOID ScrollLineUp( VOID )
+{
+ if( backup_set_temp_ptr->BSD_index < backup_set_temp_ptr->max_BSD_index ) {
+
+ backup_set_temp_ptr->BSD_index++;
+ }
+}
+
+#ifdef OEM_EMS
+/***************************************************
+ ** These functions are used to display multiple sets
+ ** of controls in the Backup dialog.
+
+/***************************************************
+
+ Name: DM_InitCtrlTables
+
+ Description: sets up the control window handles in the tables
+
+ Returns: A DLG_MODE pointer to the DLG_MODE Table entry that has the
+ matching value to mode. NULL if no entry exists.
+
+*****************************************************/
+DLG_MODE *DM_InitCtrlTables (
+ HWND hDlg,
+ DLG_MODE *ModeTable,
+ UINT16 cModeTblSize,
+ WORD mode )
+{
+
+ DLG_DISPLAY_ENTRY *pDispEntry;
+ DLG_MODE *pMode;
+ UINT16 uModeTable;
+ UINT16 uDispTable;
+ DLG_CTRL_ENTRY *pCtlTable;
+ UINT16 uCtrl;
+ HWND hDlgCtl;
+ DLG_MODE *pCurMode = NULL;
+
+ for ( uModeTable = 0; uModeTable < cModeTblSize; uModeTable++ ) {
+
+ if ( ModeTable[uModeTable].wModeType == mode ) {
+
+ pCurMode = &(ModeTable[uModeTable]);
+ }
+
+ pMode = &(ModeTable[uModeTable]);
+ pDispEntry = pMode->DispTable;
+
+ for (uDispTable = 0; uDispTable < pMode->ucDispTables; uDispTable++) {
+
+ pCtlTable = pDispEntry[uDispTable].CtlTable;
+
+ if ( NULL != pCtlTable ) {
+
+ for ( uCtrl = 0; uCtrl < pDispEntry[uDispTable].ucCtrls; uCtrl++, pCtlTable++ ) {
+
+ hDlgCtl = GetDlgItem( hDlg, pCtlTable->iCtlId );
+
+ pCtlTable->hCtlWnd = hDlgCtl;
+
+ if( hDlgCtl ) {
+
+ ShowWindow( hDlgCtl, SW_HIDE );
+ }
+ }
+ }
+ }
+ }
+
+ return ( pCurMode );
+
+}
+
+
+/***************************************************
+
+ Name: DM_BSDShowControls
+
+ Description: Displays the correct controls based on the Os ID of the BSD
+
+ Returns: void
+
+*****************************************************/
+VOID DM_DispShowControls (
+ HWND hDlg,
+ DLG_MODE * pCurMode,
+ INT iType
+)
+{
+ UINT16 uDispTable;
+ DLG_CTRL_ENTRY *pCtlTable;
+ UINT16 uCtrl;
+ DLG_DISPLAY_ENTRY *pDispTable;
+
+ // Get the right display table for the mode.
+ pDispTable = pCurMode->DispTable;
+
+ // Find the control table for the new BSD.
+
+ for ( uDispTable = 0; uDispTable < pCurMode->ucDispTables; uDispTable++ ) {
+
+ if ( pDispTable[uDispTable].iDispType == iType )
+
+ break;
+ }
+
+ uDispTable = ( uDispTable < pCurMode->ucDispTables ) ? uDispTable : (pCurMode->ucDispTables - 1) ;
+
+ pCurMode->pCurDisp = &(pDispTable[uDispTable]);
+
+ pCtlTable = pDispTable[uDispTable].CtlTable;
+
+ if ( NULL != pCtlTable ) {
+
+ for ( uCtrl = 0; uCtrl < pDispTable[uDispTable].ucCtrls; uCtrl++, pCtlTable++ ) {
+
+ if ( pCtlTable->hCtlWnd ) {
+
+ switch ( pCtlTable->iCtlDispStyle ) {
+
+ case CM_HIDE:
+ ShowWindow( pCtlTable->hCtlWnd, SW_HIDE );
+ break;
+
+ case CM_ENABLE:
+ ShowWindow( pCtlTable->hCtlWnd, SW_SHOW );
+ EnableWindow( pCtlTable->hCtlWnd, TRUE );
+ break;
+
+ case CM_DISABLE:
+ ShowWindow( pCtlTable->hCtlWnd, SW_SHOW );
+ EnableWindow( pCtlTable->hCtlWnd, FALSE );
+ break;
+
+ default:
+ ;
+ }
+ }
+ }
+ }
+}
+
+
+/***************************************************
+
+ Name: DM_ModeGetHelpId
+
+ Description: Returns the correct Help ID for the current mode and BSD
+
+ Returns: DWORD ( Help ID )
+
+*****************************************************/
+DWORD DM_ModeGetHelpId(
+ DLG_MODE * pCurMode
+)
+{
+
+ if ( NULL != pCurMode->pCurDisp ) {
+
+ return pCurMode->pCurDisp->help_id;
+
+ } else {
+
+ return 0;
+ }
+}
+
+#endif OEM_EMS
diff --git a/private/utils/ntbackup/src/d_o_rset.c b/private/utils/ntbackup/src/d_o_rset.c
new file mode 100644
index 000000000..d510319c7
--- /dev/null
+++ b/private/utils/ntbackup/src/d_o_rset.c
@@ -0,0 +1,2742 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: D_O_RSET.C
+
+ Description:
+
+ $Log: G:\ui\logfiles\d_o_rset.c_v $
+
+ Rev 1.83.1.8 16 Jun 1994 15:17:50 STEVEN
+Read-Only are not restore devices
+
+ Rev 1.83.1.7 02 Feb 1994 18:11:06 chrish
+Took out un-need codes dealing with restricted access secured tapes.
+Logic is not needed here, is basically dead codes.
+
+ Rev 1.83.1.6 02 Feb 1994 11:29:10 Glenn
+Overhauled log file browse support - now a separate function in d_browse.c.
+
+ Rev 1.83.1.5 28 Jan 1994 16:35:32 MIKEP
+reset the restore security flag when changing destination drives
+
+ Rev 1.83.1.4 17 Jan 1994 16:00:28 MIKEP
+fix unicode warnings
+
+ Rev 1.83.1.3 16 Dec 1993 19:50:08 STEVEN
+fixed unicode bo bo
+
+ Rev 1.83.1.2 02 Dec 1993 12:52:16 STEVEN
+Fixes bug with target path being garbaged.
+
+ Rev 1.83.1.1 04 Nov 1993 16:16:44 STEVEN
+japanese fixes
+
+ Rev 1.83 20 Jul 1993 16:16:42 KEVINS
+Clear out browse combo box before updating it.
+
+ Rev 1.82 12 Jul 1993 16:04:32 MARINA
+enable c++
+
+ Rev 1.81 29 Jun 1993 16:11:16 BARRY
+Now set ProcessSpecialFiles in config as well as BSD. Requires updated config.
+
+ Rev 1.80 16 Jun 1993 21:36:04 GREGG
+If we're not prompting for security, default to not restoring security, and
+set the process element only flag in the BSD to TRUE.
+
+ Rev 1.79 11 Jun 1993 14:27:46 BARRY
+Use dle features for restore of special files instead of FS_PromptForBindery.
+
+ Rev 1.78 02 Jun 1993 14:19:16 KEVINS
+Correct logic error when calculating new drive to change to in browse.
+
+ Rev 1.77 27 May 1993 08:22:50 CARLS
+fixed tape power off - restore problem
+
+ Rev 1.76 22 May 1993 18:38:44 BARRY
+Fixed to compile for MIPs
+
+ Rev 1.75 21 May 1993 18:15:16 KEVINS
+Replaced hard coded strings with ID's.
+
+ Rev 1.74 14 May 1993 16:34:12 CHUCKB
+See if NO_EXT_KEYS is already defined before defining it. Fixes a warningfrom Microsoft.
+
+ Rev 1.73 12 May 1993 17:56:46 KEVINS
+Refresh DLE when user goes browsing for drives.
+
+ Rev 1.72 12 May 1993 16:51:42 CHUCKB
+Make sure wListIndex is initialized before being used (fixes a warning from
+Microsoft).
+
+ Rev 1.71 04 May 1993 10:54:42 DARRYLP
+Fixed browsing directory search.
+
+ Rev 1.70 03 May 1993 10:32:50 DARRYLP
+Made changes to browse dialog to reflect path given in combobox.
+
+ Rev 1.69 29 Apr 1993 17:27:26 CARLS
+changed strncmp to _strnicmp for mixed case drive letters
+
+ Rev 1.68 21 Apr 1993 18:55:50 CHUCKB
+1. Changed commented-out ifdef's on lines 989 and 1003 to real ifdef's for
+ OS_WIN32, so this change will affect (fix) both Cayman and Nostradamus.
+2. Changed line 999 from
+ nStatus = ( BSD_GetMarkStatus( pBSD ) == ALL_SELECTED ) ;
+ to
+ nStatus = BSD_GetProcSpecialFlg( pBSD ) ;
+to initialize and maintain the Restore Registry checkbox correctly. This
+fixed a C2P2 EPR against Nostradamus.
+
+
+ Rev 1.67 08 Apr 1993 17:30:08 chrish
+Minor change for cleaning up warning message.
+
+ Rev 1.66 22 Mar 1993 12:30:40 chrish
+Changeed "SeSecurityPrivilege" to "SeRestorePrivilege" for checking for tape security.
+
+ Rev 1.65 16 Mar 1993 12:48:20 CARLS
+changed log file name
+
+ Rev 1.64 16 Mar 1993 12:41:16 CARLS
+LOG file changes
+
+ Rev 1.63 08 Mar 1993 14:44:28 DARRYLP
+Added read only drive support.
+
+ Rev 1.62 26 Feb 1993 09:56:06 STEVEN
+we ignored the registry button
+
+ Rev 1.61 11 Feb 1993 09:01:32 CARLS
+remove code to invalidate combobox
+
+ Rev 1.60 09 Feb 1993 17:42:08 STEVEN
+setting the wrong thing
+
+ Rev 1.59 09 Feb 1993 09:23:10 STEVEN
+fix drive pull down windows
+
+ Rev 1.58 27 Jan 1993 14:23:38 STEVEN
+updates from msoft
+
+ Rev 1.57 15 Dec 1992 11:22:10 chrish
+Corrected logic to handle possible NULL returned from
+GetCurrentMachineNameUserName routine.
+
+ Rev 1.56 14 Dec 1992 12:17:22 DAVEV
+Enabled for Unicode compile
+
+ Rev 1.55 07 Dec 1992 15:06:26 STEVEN
+updates from msoft
+
+ Rev 1.54 20 Nov 1992 16:54:20 GLENN
+Completely overhauled so that this code could be readable, also added drive and volume name.
+
+ Rev 1.53 16 Nov 1992 12:21:42 chrish
+Minor changes to clean-up warining messages on building.
+
+ Rev 1.52 13 Nov 1992 17:19:06 chrish
+Changes for restoring Secured Tapes - NT
+
+ Rev 1.51 11 Nov 1992 16:32:28 DAVEV
+UNICODE: remove compile warnings
+
+ Rev 1.50 01 Nov 1992 15:55:50 DAVEV
+Unicode changes
+
+ Rev 1.49 07 Oct 1992 13:40:00 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.48 04 Oct 1992 19:36:46 DAVEV
+Unicode Awk pass
+
+ Rev 1.47 17 Sep 1992 15:50:30 DAVEV
+UNICODE modifications: strlen usage check
+
+ Rev 1.46 10 Sep 1992 17:45:14 DAVEV
+Integrate MikeP's changes from Microsoft
+
+ Rev 1.45 03 Sep 1992 10:44:18 CHUCKB
+Took out some unreferenced locals.
+
+ Rev 1.44 19 Aug 1992 14:28:54 CHUCKB
+Added new stuff for NT.
+
+ Rev 1.43 28 Jul 1992 15:05:08 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.42 26 Jun 1992 15:51:58 DAVEV
+
+
+ Rev 1.41 24 Jun 1992 09:20:06 DAVEV
+Browse to path is no longer just an OEM_MSOFT feature
+
+ Rev 1.40 18 Jun 1992 11:25:18 DAVEV
+OEM_MSOFT:fixed logging bug
+
+ Rev 1.39 11 Jun 1992 15:22:28 DAVEV
+do not display status message 'Examine <log file> for more info' if not logging
+
+ Rev 1.38 05 Jun 1992 12:43:04 DAVEV
+OEM_MSOFT: Init log file name to default
+
+ Rev 1.37 14 May 1992 16:37:36 MIKEP
+NT pass 2
+
+ Rev 1.36 24 Apr 1992 08:28:00 CARLS
+added Mac delimiter support for SetTargetPath
+
+
+*****************************************************/
+
+#ifndef NO_EXT_KEYS
+#define NO_EXT_KEYS
+#endif
+
+#include "all.h"
+#include "ctl3d.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+
+#define ON 1
+#define OFF 0
+#define NO_SHOW 0
+#define SHOW 1
+#define REDRAW 1
+#define NO_REDRAW 0
+#define RESTORE_MODE 0
+#define VERIFY_MODE 1
+
+#define MAX_BROWSE_PATH_LEN 1024
+
+extern WORD RT_BSD_index;
+extern WORD RT_max_BSD_index;
+
+struct temp {
+ WORD wDlgStatus;
+ WORD BSD_index;
+ WORD max_BSD_index;
+ WORD fMode;
+ HWND ghDlg; /* global window handle of the dialog box */
+ WORD display_status;
+ HTIMER timer_handle;
+ INT poll_drive_freq;
+};
+
+static struct temp *mwpStatus;
+
+
+LOCALFN VOID clock_routine( VOID );
+LOCALFN VOID ScrollLineDown( VOID );
+LOCALFN VOID ScrollLineUp( VOID );
+LOCALFN VOID SetTargetPath( BSD_PTR, CHAR_PTR );
+LOCALFN VOID GetTargetPath( BSD_PTR, CHAR_PTR );
+LOCALFN VOID SeeIfWeCanSilentlyLogin( VOID );
+LOCALFN INT ConfirmXchgBsdServers( WORD * );
+#define EMS_SERVER_NOT_FOUND 1
+#define EMS_XCHG_FOUND 2
+#define EMS_NO_DEST 3
+#define EMS_NO_STORE 4
+#define EMS_MUST_WIPE_TO_ALT 5
+#define EMS_NO_WIPE_IF_NOT_BOTH 6
+
+/***************************************************
+
+ Name: DM_StartRestoreBackupSet
+
+ Description: Start the restore target dialog
+
+ Returns:
+
+*****************************************************/
+INT DM_StartRestoreBackupSet(VOID)
+{
+ struct temp temp_data;
+
+ mwpStatus = &temp_data;
+
+ mwpStatus->fMode = RESTORE_MODE;
+
+ DM_ShowDialog( ghWndFrame, IDD_RESTORESET, NULL );
+
+ return( mwpStatus->wDlgStatus );
+}
+/***************************************************
+
+ Name: DM_StartVerifyBackupSet
+
+ Description: Start the verify target dialog
+
+ Returns:
+
+*****************************************************/
+INT DM_StartVerifyBackupSet(VOID)
+{
+ struct temp temp_data;
+
+ mwpStatus = &temp_data;
+
+ mwpStatus->fMode = VERIFY_MODE;
+
+ DM_ShowDialog( ghWndFrame, IDD_VERIFYSET, NULL );
+
+ return( mwpStatus->wDlgStatus );
+}
+/***************************************************
+
+ Name: DM_RestoreSet
+
+ Description: Restore dialog procedure
+
+ Returns:
+
+*****************************************************/
+DLGRESULT APIENTRY DM_RestoreSet (
+
+HWND hDlg, /* window handle of the dialog box */
+MSGID message, /* type of message */
+MP1 mp1, /* message-specific information */
+MP2 mp2 )
+
+{
+ HWND hWndScrollBar;
+ WORD wThumbPosition;
+ INT nButtonState;
+ CHAR_PTR pszTemp;
+ BSD_PTR pBSD;
+ CDS_PTR pCDS;
+ BE_CFG_PTR pBEConfig;
+ CHAR szBuffer1[80];
+ CHAR szBuffer2[80];
+ HDC hDC;
+ HWND hComboWnd;
+ WORD wIndex;
+ TEXTMETRIC tm;
+ CHAR szText[80];
+ COLORREF crColor;
+ LPDRAWITEMSTRUCT lpDIS;
+ LPMEASUREITEMSTRUCT lpMIS;
+ BSD_PTR bsd_ptr ;
+#ifdef OEM_EMS
+
+ static DLG_CTRL_ENTRY DefaultCtrlTable[] = {
+ { IDD_RSET_DEST_NAME, 0, CM_HIDE },
+ { IDD_RSET_DSA_DEST_NAME, 0, CM_HIDE },
+ { IDD_RSET_DEST_TEXT, 0, CM_HIDE },
+ { IDD_RSET_DS_DEST_TEXT, 0, CM_HIDE },
+ { IDD_RSET_ORG_TEXT, 0, CM_HIDE },
+ { IDD_RSET_WIPE_DATA, 0, CM_HIDE },
+ { IDD_RSET_PRIV_IS, 0, CM_HIDE },
+ { IDD_RSET_PUB_IS, 0, CM_HIDE },
+ { IDD_RSET_ORG_NAME, 0, CM_HIDE },
+ { IDD_RSET_START_EMS, 0, CM_HIDE },
+ { IDD_RSET_DRIVE_TEXT, 0, CM_ENABLE },
+ { IDD_RSET_DRIVE_BOX, 0, CM_ENABLE },
+ { IDD_RSET_PATH_TEXT, 0, CM_ENABLE },
+ { IDD_RSET_RESTORE_PATH, 0, CM_ENABLE },
+ { IDD_RSET_BROWSE_BUTTON, 0, CM_ENABLE },
+ { IDD_RSET_REGISTRY, 0, CM_ENABLE },
+ { IDD_RSET_SECURITY_INFO, 0, CM_ENABLE }
+ };
+
+ static DLG_CTRL_ENTRY EMS_MDBCtrlTable[] = {
+ { IDD_RSET_DRIVE_TEXT, 0, CM_HIDE },
+ { IDD_RSET_DRIVE_BOX, 0, CM_HIDE },
+ { IDD_RSET_PATH_TEXT, 0, CM_HIDE },
+ { IDD_RSET_RESTORE_PATH, 0, CM_HIDE },
+ { IDD_RSET_BROWSE_BUTTON, 0, CM_HIDE },
+ { IDD_RSET_REGISTRY, 0, CM_HIDE },
+ { IDD_RSET_SECURITY_INFO, 0, CM_HIDE },
+ { IDD_RSET_DSA_DEST_NAME, 0, CM_HIDE },
+ { IDD_RSET_DS_DEST_TEXT, 0, CM_HIDE },
+ { IDD_RSET_DEST_NAME, 0, CM_ENABLE },
+ { IDD_RSET_DEST_TEXT, 0, CM_ENABLE },
+ { IDD_RSET_ORG_TEXT, 0, CM_ENABLE },
+ { IDD_RSET_WIPE_DATA, 0, CM_ENABLE },
+ { IDD_RSET_PRIV_IS, 0, CM_ENABLE },
+ { IDD_RSET_PUB_IS, 0, CM_ENABLE },
+ { IDD_RSET_START_EMS, 0, CM_ENABLE },
+ { IDD_RSET_ORG_NAME, 0, CM_ENABLE }
+ };
+
+ static DLG_CTRL_ENTRY EMS_DSACtrlTable[] = {
+ { IDD_RSET_DRIVE_TEXT, 0, CM_HIDE },
+ { IDD_RSET_DRIVE_BOX, 0, CM_HIDE },
+ { IDD_RSET_PATH_TEXT, 0, CM_HIDE },
+ { IDD_RSET_RESTORE_PATH, 0, CM_HIDE },
+ { IDD_RSET_BROWSE_BUTTON, 0, CM_HIDE },
+ { IDD_RSET_REGISTRY, 0, CM_HIDE },
+ { IDD_RSET_SECURITY_INFO, 0, CM_HIDE },
+ { IDD_RSET_PRIV_IS, 0, CM_HIDE },
+ { IDD_RSET_PUB_IS, 0, CM_HIDE },
+ { IDD_RSET_DEST_NAME, 0, CM_HIDE },
+ { IDD_RSET_DEST_TEXT, 0, CM_HIDE },
+ { IDD_RSET_ORG_TEXT, 0, CM_ENABLE },
+ { IDD_RSET_DSA_DEST_NAME, 0, CM_ENABLE },
+ { IDD_RSET_DS_DEST_TEXT, 0, CM_ENABLE },
+ { IDD_RSET_WIPE_DATA, 0, CM_ENABLE },
+ { IDD_RSET_START_EMS, 0, CM_ENABLE },
+ { IDD_RSET_ORG_NAME, 0, CM_ENABLE }
+ };
+
+
+ // GENERIC_DATA must be last w/ no other iBsdType == GENERIC_DATA (or its value).
+ static DLG_DISPLAY_ENTRY RestBsdTable[] = {
+ { FS_EMS_MDB_ID, EMS_MDBCtrlTable,
+ sizeof(EMS_MDBCtrlTable)/sizeof(EMS_MDBCtrlTable[0]), IDH_DB_XCHG_RESTORESET },
+ { FS_EMS_DSA_ID, EMS_DSACtrlTable,
+ sizeof(EMS_DSACtrlTable)/sizeof(EMS_DSACtrlTable[0]), IDH_DB_XCHG_RESTORESET },
+ { FS_UNKNOWN_OS, DefaultCtrlTable,
+ sizeof(DefaultCtrlTable)/sizeof(DefaultCtrlTable[0]), IDH_DB_RESTORESET }
+ };
+
+ static DLG_DISPLAY_ENTRY VerifyBsdTable[] = {
+ { FS_EMS_MDB_ID, EMS_MDBCtrlTable,
+ sizeof(EMS_MDBCtrlTable)/sizeof(EMS_MDBCtrlTable[0]), IDH_DB_XCHG_RESTORESET },
+ { FS_EMS_DSA_ID, EMS_DSACtrlTable,
+ sizeof(EMS_DSACtrlTable)/sizeof(EMS_DSACtrlTable[0]), IDH_DB_XCHG_RESTORESET },
+ { FS_UNKNOWN_OS, DefaultCtrlTable,
+ sizeof(DefaultCtrlTable)/sizeof(DefaultCtrlTable[0]), IDH_DB_VERIFYSET }
+ };
+
+ static DLG_MODE ModeTable[] = {
+ { VERIFY_MODE, VerifyBsdTable,
+ sizeof(VerifyBsdTable)/sizeof(VerifyBsdTable[0]), &(VerifyBsdTable[2]) },
+ { RESTORE_MODE, RestBsdTable,
+ sizeof(RestBsdTable)/sizeof(RestBsdTable[0]), &(VerifyBsdTable[2]) },
+ };
+
+ static UINT16 cModeTblSize = sizeof( ModeTable ) / sizeof( ModeTable[0] );
+ static DLG_MODE *pCurMode;
+ DWORD help_id;
+
+#endif
+
+ switch ( message ) {
+
+ case WM_DRAWITEM:
+ lpDIS = (LPDRAWITEMSTRUCT)mp2;
+ if (lpDIS->CtlID == IDD_RSET_DRIVE_BOX)
+ {
+ hComboWnd = lpDIS->hwndItem;
+ hDC = lpDIS->hDC;
+ switch(lpDIS->itemAction)
+ {
+ case ODA_DRAWENTIRE:
+ SendMessage(hComboWnd,
+ CB_GETLBTEXT,
+ lpDIS->itemID,
+ (LONG)(LPSTR)szText);
+
+ if (lpDIS->itemData == TRUE)
+ {
+ // Text should be gray, read only drive...
+ crColor = GetSysColor(COLOR_GRAYTEXT);
+ } else
+ {
+ // Text should be normal, read/write drive...
+ crColor = GetSysColor(COLOR_WINDOWTEXT);
+ }
+ SetTextColor(hDC, crColor);
+ DrawText(hDC,
+ szText,
+ strlen(szText),
+ (LPRECT)&lpDIS->rcItem,
+ DT_LEFT|DT_SINGLELINE);
+ switch(lpDIS->itemState)
+ {
+ case ODS_FOCUS:
+ DrawFocusRect(hDC, &lpDIS->rcItem);
+ break;
+
+ case ODS_SELECTED:
+ InvertRect(hDC, &lpDIS->rcItem);
+ break;
+ }
+ break;
+
+ case ODA_FOCUS:
+ DrawFocusRect(hDC, &lpDIS->rcItem);
+ break;
+
+ case ODA_SELECT:
+ InvertRect(hDC, &lpDIS->rcItem);
+ break;
+ }
+ }
+ break;
+
+ case WM_MEASUREITEM:
+ lpMIS = (LPMEASUREITEMSTRUCT)mp2;
+ if (lpMIS->CtlID == IDD_RSET_DRIVE_BOX)
+ {
+ hComboWnd = GetDlgItem(hDlg, IDD_RSET_DRIVE_BOX);
+ hDC = GetDC(hComboWnd);
+ GetTextMetrics(hDC, &tm);
+ lpMIS->itemHeight = tm.tmHeight;
+ ReleaseDC(hComboWnd, hDC);
+ }
+ break;
+
+ case WM_INITDIALOG: /* message: initialize dialog box */
+
+ // Let's go 3-D!!
+ Ctl3dSubclassDlgEx( hDlg, CTL3D_ALL );
+
+#ifdef OEM_EMS
+ pCurMode = DM_InitCtrlTables( hDlg, ModeTable, cModeTblSize,
+ mwpStatus->fMode );
+#endif
+
+ DM_CenterDialog( hDlg );
+
+ /* set the length of the text fields */
+ SendDlgItemMessage( hDlg, IDD_RSET_TAPE_NAME, EM_LIMITTEXT, MAX_TAPE_NAME_LEN, 0 );
+
+ SendDlgItemMessage( hDlg, IDD_RSET_SET_LINE_1, EM_LIMITTEXT, MAX_UI_PATH_LEN, 0 );
+
+ /* return the max number of BSD's for this backup */
+ mwpStatus->max_BSD_index = GetMaxBSDCount();
+
+ /* start at the first BSD */
+ mwpStatus->BSD_index = 0;
+ pBSD = GetTapeBSDPointer( mwpStatus->BSD_index );
+
+ /* get the backup engine config for this BSD */
+ pBEConfig = BSD_GetConfigData( pBSD );
+
+ /* set the global BSD index used for the "Set information N of N" dialogs title */
+ RT_BSD_index = (WORD) (mwpStatus->BSD_index + 1);
+ RT_max_BSD_index = (WORD) (mwpStatus->max_BSD_index + 1);
+
+ hWndScrollBar = GetDlgItem( hDlg, IDD_RSET_SCROLLBAR );
+
+ /* if only one backup set, turn off the scrollbar */
+ if ( mwpStatus->max_BSD_index == mwpStatus->BSD_index ) {
+ ShowScrollBar( hWndScrollBar, SB_CTL, NO_SHOW );
+ }
+ /* show the scrollbar and set the max range for the scrollbar */
+ else {
+ SetScrollRange( hWndScrollBar, SB_CTL, mwpStatus->BSD_index, mwpStatus->max_BSD_index, NO_REDRAW );
+ SetScrollPos( hWndScrollBar, SB_CTL, mwpStatus->BSD_index, NO_REDRAW );
+ }
+
+ /* add "1 of n" to backup set info title */
+ RSM_StringCopy( IDS_SET_INFORMATION, szBuffer1, 80 );
+ wsprintf( szBuffer2, szBuffer1, mwpStatus->BSD_index + 1, mwpStatus->max_BSD_index + 1 );
+
+ /* show the "Set information n of n" */
+ SetDlgItemText( hDlg, IDD_RSET_INFO_TITLE, szBuffer2 );
+
+
+ /* display the default tape name */
+ pszTemp = (LPSTR)BSD_GetTapeLabel( pBSD );
+ SetDlgItemText( hDlg, IDD_RSET_TAPE_NAME, pszTemp );
+
+ /* see if we can add a few more restore destinations */
+ SeeIfWeCanSilentlyLogin( );
+
+ /* get the drive list */
+ GetCurrentRestoreDriveList( hDlg );
+
+ /* set all BSD's DLEs to the default drive */
+ SetDefaultDLE( hDlg );
+
+
+ pCDS = CDS_GetCopy();
+ /* Auto verify check box */
+ if ( mwpStatus->fMode == RESTORE_MODE ) {
+ CheckDlgButton( hDlg, IDD_RSET_VERIFY_AFTER, CDS_GetAutoVerifyRestore( pCDS ) );
+ }
+
+ /* display the state of the first BSD */
+#ifndef OEM_EMS
+ RestoreSetRetrieve( hDlg );
+#else
+ RestoreSetRetrieve( hDlg, pCurMode );
+#endif
+
+# if defined ( OEM_MSOFT ) // special feature
+ {
+# define OEMLOG_MAX_FILEPATH 512 //NTKLUG
+
+ CHAR szLogFilePath[ OEMLOG_MAX_FILEPATH ];
+ INT nLen;
+
+ if ( nLen = GetWindowsDirectory ( szLogFilePath, OEMLOG_MAX_FILEPATH ) ) {
+
+ // NT KLUDGE
+
+ if ( szLogFilePath[ nLen-1 ] != TEXT('\\') && nLen < OEMLOG_MAX_FILEPATH ) {
+
+ strcat ( szLogFilePath, TEXT("\\") );
+ nLen++;
+ }
+
+ if ( nLen < OEMLOG_MAX_FILEPATH &&
+ RSM_StringCopy( IDS_OEMLOG_BACKUP_DEF_NAME,
+ szLogFilePath + nLen,
+ OEMLOG_MAX_FILEPATH - nLen ) > 0 ) {
+
+ SetDlgItemText ( hDlg, IDD_RSET_LOG_FILENAME, szLogFilePath ) ;
+ }
+
+ }
+
+ /* Check default log file radio button */
+ CheckRadioButton ( hDlg, IDD_RSET_LOG_FULL,
+ IDD_RSET_LOG_NONE,
+ IDD_RSET_LOG_SUMMARY );
+
+// CheckDlgButton( hDlg, IDD_RSET_LOG_SUMMARY, 1 ) ;
+ }
+# endif //defined ( OEM_MSOFT ) // special feature
+
+ mwpStatus->ghDlg = hDlg;
+ /* set the display_status to a value not returned by VLM_GetDriveStatus */
+ mwpStatus->display_status = 0x7fff ;
+ clock_routine( );
+ mwpStatus->poll_drive_freq = PD_SetFrequency( 1 );
+ mwpStatus->timer_handle = WM_HookTimer( clock_routine, 1 );
+
+ return ( TRUE );
+
+
+ case WM_VSCROLL:
+
+ hWndScrollBar = GetDlgItem( hDlg, IDD_RSET_SCROLLBAR );
+
+ if ( GET_WM_VSCROLL_HWND ( mp1, mp2 ) == hWndScrollBar ) {
+
+ wThumbPosition = GET_WM_VSCROLL_POS ( mp1, mp2 );
+
+ switch ( GET_WM_VSCROLL_CODE ( mp1, mp2 ) ) {
+
+ case SB_THUMBPOSITION:
+
+ SetScrollPos( hWndScrollBar, SB_CTL, wThumbPosition, REDRAW );
+ return ( TRUE );
+
+ case SB_THUMBTRACK:
+
+ if ( wThumbPosition > mwpStatus->max_BSD_index ) {
+ wThumbPosition = mwpStatus->max_BSD_index;
+ }
+
+ if ( wThumbPosition >= mwpStatus->BSD_index ) {
+
+ /* save this BSDs information */
+ if ( !RestoreSetSave( hDlg ) ) {
+
+ // something was wrong, so don't do anything
+ // put up a message box and return
+
+#ifdef OEM_EMS
+ pBSD = GetTapeBSDPointer( mwpStatus->BSD_index );
+ switch ( BSD_GetOsId( pBSD ) ) {
+
+ case FS_EMS_MDB_ID:
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_RESTOREEMSSERVERINVALID),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ SEND_EM_SETSEL_MSG (hDlg, IDD_RSET_DEST_NAME, 0, 32767);
+ SetFocus( GetDlgItem( hDlg, IDD_RSET_DEST_NAME ) );
+ break;
+
+ case FS_EMS_DSA_ID:
+
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_RESTOREEMSSERVERINVALID),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ SEND_EM_SETSEL_MSG (hDlg, IDD_RSET_DSA_DEST_NAME, 0, 32767);
+ SetFocus( GetDlgItem( hDlg, IDD_RSET_DSA_DEST_NAME ) );
+ break;
+
+ default:
+
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_RESTOREPATHINVALID),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ SEND_EM_SETSEL_MSG (hDlg, IDD_RSET_RESTORE_PATH, 0, 32767);
+ SetFocus( GetDlgItem( hDlg, IDD_RSET_RESTORE_PATH ) );
+ }
+#else
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_RESTOREPATHINVALID),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+#endif
+
+ return ( TRUE );
+ }
+
+ while ( wThumbPosition != mwpStatus->BSD_index ) {
+ ScrollLineUp( );
+ }
+
+ /* restore the next BSDs information */
+#ifndef OEM_EMS
+ RestoreSetRetrieve( hDlg );
+#else
+ RestoreSetRetrieve( hDlg, pCurMode );
+#endif
+ }
+ else {
+
+ // save this BSDs information
+
+ if ( ! RestoreSetSave( hDlg ) ) {
+
+ // put up message box & split
+
+#ifdef OEM_EMS
+ pBSD = GetTapeBSDPointer( mwpStatus->BSD_index );
+ switch ( BSD_GetOsId( pBSD ) ) {
+
+ case FS_EMS_MDB_ID:
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_RESTOREEMSSERVERINVALID),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ SEND_EM_SETSEL_MSG (hDlg, IDD_RSET_DEST_NAME, 0, 32767);
+ SetFocus( GetDlgItem( hDlg, IDD_RSET_DEST_NAME ) );
+ break;
+
+
+ case FS_EMS_DSA_ID:
+
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_RESTOREEMSSERVERINVALID),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ SEND_EM_SETSEL_MSG (hDlg, IDD_RSET_DSA_DEST_NAME, 0, 32767);
+ SetFocus( GetDlgItem( hDlg, IDD_RSET_DSA_DEST_NAME ) );
+ break;
+
+ default:
+
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_RESTOREPATHINVALID),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ SEND_EM_SETSEL_MSG (hDlg, IDD_RSET_RESTORE_PATH, 0, 32767);
+ SetFocus( GetDlgItem( hDlg, IDD_RSET_RESTORE_PATH ) );
+ }
+#else
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_RESTOREPATHINVALID),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+#endif
+
+ return( TRUE );
+ }
+
+ while ( wThumbPosition != mwpStatus->BSD_index ) {
+ ScrollLineDown( );
+ }
+
+ /* restore the next BSDs information */
+#ifndef OEM_EMS
+ RestoreSetRetrieve( hDlg );
+#else
+ RestoreSetRetrieve( hDlg, pCurMode );
+#endif
+ }
+
+ return ( TRUE );
+
+ case SB_PAGEUP:
+ case SB_LINEUP:
+
+ // save this BSDs information
+
+ if ( ! RestoreSetSave( hDlg ) ) {
+
+ // put up message box and leave town
+
+#ifdef OEM_EMS
+ pBSD = GetTapeBSDPointer( mwpStatus->BSD_index );
+ switch ( BSD_GetOsId( pBSD ) ) {
+
+ case FS_EMS_MDB_ID:
+
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_RESTOREEMSSERVERINVALID),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ SEND_EM_SETSEL_MSG (hDlg, IDD_RSET_DEST_NAME, 0, 32767);
+ SetFocus( GetDlgItem( hDlg, IDD_RSET_DEST_NAME ) );
+ break;
+
+ case FS_EMS_DSA_ID:
+
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_RESTOREEMSSERVERINVALID),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ SEND_EM_SETSEL_MSG (hDlg, IDD_RSET_DSA_DEST_NAME, 0, 32767);
+ SetFocus( GetDlgItem( hDlg, IDD_RSET_DSA_DEST_NAME ) );
+ break;
+
+ default:
+
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_RESTOREPATHINVALID),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ SEND_EM_SETSEL_MSG (hDlg, IDD_RSET_RESTORE_PATH, 0, 32767);
+ SetFocus( GetDlgItem( hDlg, IDD_RSET_RESTORE_PATH ) );
+ }
+#else
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_RESTOREPATHINVALID),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+#endif
+
+ return( TRUE );
+ }
+
+ ScrollLineDown( );
+
+ /* restore the next BSDs information */
+#ifndef OEM_EMS
+ RestoreSetRetrieve( hDlg );
+#else
+ RestoreSetRetrieve( hDlg, pCurMode );
+#endif
+
+ SetScrollPos( hWndScrollBar, SB_CTL, mwpStatus->BSD_index, REDRAW );
+ return ( TRUE );
+
+ case SB_PAGEDOWN:
+ case SB_LINEDOWN:
+
+ // save this BSDs information
+
+ if ( ! RestoreSetSave( hDlg ) ) {
+
+ // put up message box and quit
+
+#ifdef OEM_EMS
+ pBSD = GetTapeBSDPointer( mwpStatus->BSD_index );
+ switch ( BSD_GetOsId( pBSD ) ) {
+
+ case FS_EMS_MDB_ID:
+
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_RESTOREEMSSERVERINVALID),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ SEND_EM_SETSEL_MSG (hDlg, IDD_RSET_DEST_NAME, 0, 32767);
+ SetFocus( GetDlgItem( hDlg, IDD_RSET_DEST_NAME ) );
+ break;
+
+ case FS_EMS_DSA_ID:
+
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_RESTOREEMSSERVERINVALID),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ SEND_EM_SETSEL_MSG (hDlg, IDD_RSET_DSA_DEST_NAME, 0, 32767);
+ SetFocus( GetDlgItem( hDlg, IDD_RSET_DSA_DEST_NAME ) );
+ break;
+
+ default:
+
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_RESTOREPATHINVALID),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ SEND_EM_SETSEL_MSG (hDlg, IDD_RSET_RESTORE_PATH, 0, 32767);
+ SetFocus( GetDlgItem( hDlg, IDD_RSET_RESTORE_PATH ) );
+ }
+#else
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_RESTOREPATHINVALID),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+#endif
+
+ return( TRUE );
+ }
+
+ ScrollLineUp( );
+
+ /* restore the next BSDs information */
+#ifndef OEM_EMS
+ RestoreSetRetrieve( hDlg );
+#else
+ RestoreSetRetrieve( hDlg, pCurMode );
+#endif
+
+ SetScrollPos( hWndScrollBar, SB_CTL, mwpStatus->BSD_index, REDRAW );
+ return ( TRUE );
+
+ case SB_BOTTOM:
+
+ return ( TRUE );
+
+ case SB_ENDSCROLL:
+
+ return ( TRUE );
+
+ case SB_TOP:
+
+ return ( TRUE );
+
+ default:
+ break;
+ }
+ }
+
+ return ( FALSE );
+ break;
+
+ case WM_COMMAND: { /* message: received a command */
+
+ WORD wId = GET_WM_COMMAND_ID ( mp1, mp2 );
+ WORD wCmd = GET_WM_COMMAND_CMD ( mp1, mp2 );
+
+ switch( wId ) {
+
+# ifdef OEM_MSOFT //special feature
+
+ case IDD_RSET_LOG_NONE:
+ case IDD_RSET_LOG_SUMMARY:
+ case IDD_RSET_LOG_FULL:
+
+ CheckRadioButton ( hDlg, IDD_RSET_LOG_NONE, IDD_RSET_LOG_FULL, wId ) ;
+ return TRUE ;
+
+# endif //OEM_MSOFT //special feature
+
+ case IDD_RSET_DRIVE_BOX : {
+
+ if ( wCmd == CBN_SELCHANGE ) {
+
+ /* get the defaults for the drive that's highlighted */
+
+ SetRestoreDrive( hDlg ) ;
+#ifndef OEM_EMS
+ RestoreSetRetrieve( hDlg );
+#else
+ RestoreSetRetrieve( hDlg, pCurMode );
+#endif
+
+ return TRUE;
+ }
+
+ return( FALSE ) ;
+ }
+
+ case IDD_RSET_CANCEL_BUTTON:
+ case IDCANCEL:
+
+ pBSD = GetTapeBSDPointer( (INT16) 0 );
+ pCDS = CDS_GetCopy();
+
+ mwpStatus->wDlgStatus = TRUE;
+
+ WM_UnhookTimer( mwpStatus->timer_handle );
+ PD_SetFrequency( mwpStatus->poll_drive_freq );
+
+ EndDialog( hDlg, FALSE ); /* Exits the dialog box */
+ return ( TRUE );
+
+ case IDOK:
+ case IDD_RSET_OK_BUTTON:
+ hComboWnd = GetDlgItem(hDlg, IDD_RSET_OK_BUTTON);
+ wIndex = (WORD)SendMessage(hComboWnd,
+ CB_GETCURSEL,
+ 0,
+ 0L);
+
+ if (SendMessage(hComboWnd,
+ CB_GETITEMDATA,
+ wIndex,
+ 0L) == TRUE)
+ {
+ CHAR szBuffer[80];
+ CHAR szBuffer2[80];
+ CHAR szTemp[80];
+
+ // Drive is read only, warn user that this is not possible
+
+ SendDlgItemMessage(hDlg,
+ IDD_RSET_DRIVE_BOX,
+ CB_GETLBTEXT,
+ wIndex,
+ (MP2)szBuffer2 );
+
+ RSM_StringCopy( IDS_RTD_ACCESSDENIED_DIR, szBuffer, 80);
+ wsprintf(szTemp, szBuffer, szBuffer2);
+ RSM_StringCopy( IDS_RDONLY_DRV_ENCOUNTER, szBuffer2, 80);
+ WM_MsgBox( szBuffer2, szTemp, WMMB_OK, WMMB_ICONEXCLAMATION ) ;
+ return FALSE;
+ }
+
+ pBSD = GetTapeBSDPointer( (INT16) 0 );
+ pCDS = CDS_GetCopy();
+
+ /* save the state of "auto verify" */
+ if ( mwpStatus->fMode == RESTORE_MODE ) {
+
+ nButtonState = IsDlgButtonChecked( hDlg,IDD_RSET_VERIFY_AFTER );
+ CDS_SetAutoVerifyRestore( pCDS, (INT16)nButtonState );
+ }
+
+# if defined ( OEM_MSOFT ) // special feature
+ {
+ CHAR szLogFile[ MAX_UI_FULLPATH_SIZE ];
+ FILE * fpLog = NULL;
+ INT nLogLevel = LOG_DISABLED;
+
+ // Get the log file name from the edit field
+ GetDlgItemText( hDlg, IDD_RSET_LOG_FILENAME, szLogFile, MAX_UI_FULLPATH_SIZE ) ;
+
+ // can only log if a log file name provided!
+ if ( *szLogFile ) {
+
+ if ( IsDlgButtonChecked( hDlg,IDD_RSET_LOG_SUMMARY ) ) {
+ nLogLevel = LOG_ERRORS;
+ }
+ else if ( IsDlgButtonChecked( hDlg,IDD_RSET_LOG_FULL ) ) {
+ nLogLevel = LOG_DETAIL;
+ }
+ }
+
+ CDS_SetLogLevel ( pCDS, nLogLevel ) ;
+
+ if ( nLogLevel != LOG_DISABLED && *szLogFile ) {
+
+ // make sure the log file can be opened for
+ // writting.
+
+ if ( fpLog = UNI_fopen ( szLogFile, _O_TEXT|_O_APPEND ) ) {
+
+ LOG_SetCurrentLogName ( szLogFile );
+ fclose ( fpLog );
+ }
+ else {
+
+ ShowWindow ( GetDlgItem( hDlg, IDD_RSET_LOG_FILENAME ), FALSE );
+ MessageBeep ( 0 ); //NTKLUG - Need error message!!
+ ShowWindow ( GetDlgItem( hDlg, IDD_RSET_LOG_FILENAME ), TRUE );
+ ShowWindow ( GetDlgItem( hDlg, IDD_RSET_LOG_FILENAME ), FALSE );
+ MessageBeep ( 0 ); //NTKLUG - Need error message!!
+ ShowWindow ( GetDlgItem( hDlg, IDD_RSET_LOG_FILENAME ), TRUE );
+ SetFocus( GetDlgItem( hDlg, IDD_RSET_LOG_FILENAME ) );
+
+ return ( TRUE ) ; // user must re-enter name!
+ }
+ }
+ else // if no file name, then cannot log!
+ {
+ CDS_SetLogLevel ( pCDS, LOG_DISABLED ) ;
+ }
+ }
+# endif //defined ( OEM_MSOFT ) // special feature
+
+ /* save this BSDs information */
+
+ if ( ! RestoreSetSave( hDlg ) ) {
+
+ // set focus on the path
+
+#ifdef OEM_EMS
+ pBSD = GetTapeBSDPointer( mwpStatus->BSD_index );
+ switch ( BSD_GetOsId( pBSD ) ) {
+
+ case FS_EMS_MDB_ID:
+
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_RESTOREEMSSERVERINVALID),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ SEND_EM_SETSEL_MSG (hDlg, IDD_RSET_DEST_NAME, 0, 32767);
+ SetFocus( GetDlgItem( hDlg, IDD_RSET_DEST_NAME ) );
+ break;
+
+ case FS_EMS_DSA_ID:
+
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_RESTOREEMSSERVERINVALID),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ SEND_EM_SETSEL_MSG (hDlg, IDD_RSET_DSA_DEST_NAME, 0, 32767);
+ SetFocus( GetDlgItem( hDlg, IDD_RSET_DSA_DEST_NAME ) );
+ break;
+
+ default:
+
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_RESTOREPATHINVALID),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ SEND_EM_SETSEL_MSG (hDlg, IDD_RSET_RESTORE_PATH, 0, 32767);
+ SetFocus( GetDlgItem( hDlg, IDD_RSET_RESTORE_PATH ) );
+ }
+#else
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_RESTOREPATHINVALID),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ SEND_EM_SETSEL_MSG (hDlg, IDD_RSET_RESTORE_PATH, 0, 32767);
+#endif
+
+ return( TRUE );
+ }
+
+ /* save the info for the registry and security */
+
+ /* get the backup engine config for this BSD */
+ pBEConfig = BSD_GetConfigData( pBSD );
+
+ BEC_SetRestoreSecurity( pBEConfig,
+ IsDlgButtonChecked( hDlg, IDD_RSET_SECURITY_INFO ) );
+
+ UI_AddSpecialIncOrExc( pBSD,
+ IsDlgButtonChecked( hDlg, IDD_RSET_REGISTRY ) ) ;
+
+ BSD_SetProcSpecialFlg( pBSD,
+ IsDlgButtonChecked( hDlg, IDD_RSET_REGISTRY ) ) ;
+
+ BEC_SetProcSpecialFiles( pBEConfig,
+ IsDlgButtonChecked( hDlg, IDD_RSET_REGISTRY ) ) ;
+
+ mwpStatus->wDlgStatus = FALSE;
+
+ WM_UnhookTimer( mwpStatus->timer_handle );
+ PD_SetFrequency( mwpStatus->poll_drive_freq );
+#ifdef OEM_EMS
+ wThumbPosition = mwpStatus->BSD_index ;
+ switch ( ConfirmXchgBsdServers( &wThumbPosition ) ) {
+
+ case EMS_SERVER_NOT_FOUND :
+
+ mwpStatus->BSD_index = wThumbPosition ;
+ RestoreSetRetrieve( hDlg, pCurMode );
+
+ SetScrollPos( hDlg, SB_CTL, (INT)wThumbPosition, TRUE );
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_RESTOREEMSSERVERINVALID),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ SEND_EM_SETSEL_MSG (hDlg, IDD_RSET_DEST_NAME, 0, 32767);
+ SetFocus( GetDlgItem( hDlg, IDD_RSET_DEST_NAME ) );
+
+ return( TRUE );
+
+
+ case EMS_NO_WIPE_IF_NOT_BOTH :
+
+ mwpStatus->BSD_index = wThumbPosition ;
+ RestoreSetRetrieve( hDlg, pCurMode );
+
+ SetScrollPos( hDlg, SB_CTL, (INT)wThumbPosition, TRUE );
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_RESTOREEMSNOWIPE),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ SetFocus( GetDlgItem( hDlg, IDD_RSET_WIPE_DATA ) );
+
+ return( TRUE );
+
+ case EMS_MUST_WIPE_TO_ALT:
+
+ mwpStatus->BSD_index = wThumbPosition ;
+ RestoreSetRetrieve( hDlg, pCurMode );
+
+ SetScrollPos( hDlg, SB_CTL, (INT)wThumbPosition, TRUE );
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_RESTOREEMSMUSTWIPE),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ SetFocus( GetDlgItem( hDlg, IDD_RSET_WIPE_DATA ) );
+
+ return( TRUE );
+ case EMS_XCHG_FOUND:
+ mwpStatus->BSD_index = wThumbPosition ;
+ RestoreSetRetrieve( hDlg, pCurMode );
+
+ if( WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_RESTOREEMSWARNING),
+ WMMB_OKCANCEL, WMMB_ICONEXCLAMATION ) == WMMB_IDCANCEL ) {
+
+ return( TRUE );
+ }
+ break ;
+
+ case EMS_NO_DEST:
+ mwpStatus->BSD_index = wThumbPosition ;
+ RestoreSetRetrieve( hDlg, pCurMode );
+
+ SetScrollPos( hDlg, SB_CTL, (INT)wThumbPosition, TRUE );
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_EMS_NO_DEST_DRIVE),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ SEND_EM_SETSEL_MSG (hDlg, IDD_RSET_DEST_NAME, 0, 32767);
+ SetFocus( GetDlgItem( hDlg, IDD_RSET_DEST_NAME ) );
+
+ return( TRUE );
+
+ case EMS_NO_STORE:
+
+ mwpStatus->BSD_index = wThumbPosition ;
+ RestoreSetRetrieve( hDlg, pCurMode );
+
+ SetScrollPos( hDlg, SB_CTL, (INT)wThumbPosition, TRUE );
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE), ID(IDS_EMS_MUST_PUB_OR_PRI),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ SEND_EM_SETSEL_MSG (hDlg, IDD_RSET_DEST_NAME, 0, 32767);
+ SetFocus( GetDlgItem( hDlg, IDD_RSET_PUB_IS ) );
+
+ return( TRUE );
+ }
+
+#endif
+
+ EndDialog( hDlg, TRUE ); /* Exits the dialog box */
+ return ( TRUE );
+
+
+ case IDD_RSET_HELP_BUTTON:
+ case IDHELP :
+
+#ifndef OEM_EMS
+ if (mwpStatus->fMode == RESTORE_MODE ) {
+ HM_DialogHelp( HELPID_DIALOGRESTORESET );
+ } else {
+ HM_DialogHelp( HELPID_DIALOGVERIFYSET );
+ }
+#else
+ help_id = DM_ModeGetHelpId( pCurMode );
+ HM_DialogHelp( help_id );
+#endif
+
+ return( TRUE );
+
+# ifdef OEM_MSOFT //special feature
+
+ case IDD_RSET_LOG_BROWSE: //Log file browse button
+
+ {
+ CHAR szFile[ BROWSE_MAXPATH ] = TEXT("");
+
+ GetDlgItemText ( hDlg, IDD_RSET_LOG_FILENAME, szFile, BROWSE_MAXPATH );
+
+ if ( DM_BrowseForLogFilePath ( hDlg, ghInst, szFile, strlen ( szFile ) ) ) {
+
+ SetDlgItemText ( hDlg, IDD_RSET_LOG_FILENAME, szFile );
+ SetFocus ( GetDlgItem ( hDlg, IDD_RSET_LOG_FILENAME ) );
+ }
+ }
+
+ break;
+
+# endif //OEM_MSOFT //special feature
+
+ case IDD_RSET_BROWSE_BUTTON:
+ {
+ CHAR szPath[ BROWSE_MAXPATH ];
+ CHAR szDrive[ BROWSE_MAXPATH ];
+ DWORD dwErr;
+
+ GetDlgItemText( hDlg, IDD_RSET_RESTORE_PATH,
+ szPath, BROWSE_MAXPATH );
+
+ hComboWnd = GetDlgItem(hDlg, IDD_RSET_DRIVE_BOX);
+
+ wIndex = (WORD)SendMessage(hComboWnd,
+ CB_GETCURSEL,
+ 0,
+ 0L);
+ SendDlgItemMessage(hDlg,
+ IDD_RSET_DRIVE_BOX,
+ CB_GETLBTEXT,
+ wIndex,
+ (MP2)szDrive);
+ szDrive [2] = TEXT ('\0');
+
+ // If no path is specified, but a drive is selected...
+
+ if ( !szPath[ 0 ] && szDrive[ 0 ] ) {
+
+ // Get the current directory of the selected drive
+
+ _getdcwd ( ( toupper( szDrive[ 0 ] ) - TEXT('A') + 1), szPath, BROWSE_MAXPATH );
+ }
+
+ // else, use the current drive and path by default
+
+ EnableWindow ( hDlg, FALSE );
+
+ if ( DM_GetBrowsePath ( hDlg, ghInst, szPath, BROWSE_MAXPATH ) ) {
+
+ LPSTR psz = szPath;
+
+ //Note: Would it be safer for NT to use _splitpath()
+ // and _makepath() rather than just stripping
+ // the drive specifier out like this ?NTKLUG?
+
+ if ( strlen ( szPath ) >= BROWSE_MAXDRIVE-1 && szPath[ 1 ] == TEXT(':') ) {
+
+ // Strip the drive specifier out of the path and
+ // place it in a seperate buffer.
+
+ psz = &szPath[ 2 ]; //point to the path sans drive
+ strncpy ( szDrive, szPath, BROWSE_MAXDRIVE-1 );
+ szDrive[ BROWSE_MAXDRIVE-1 ] = TEXT('\0');
+
+ // perform a refresh just in case user connected to a
+ // network drive
+
+ VLM_Refresh ();
+
+ /* get the drive list */
+ GetCurrentRestoreDriveList( hDlg );
+
+ // Find this drive entry in the Drives combobox
+ // and make it the current selected item.
+ SendDlgItemMessage ( hDlg,
+ IDD_RSET_DRIVE_BOX,
+ CB_SELECTSTRING,
+ (MP1) -1,
+ (MP2) szDrive );
+ }
+
+ //place the selected path in the restore path edit field
+ SetDlgItemText( hDlg, IDD_RSET_RESTORE_PATH, psz );
+ }
+ else if ( dwErr = CommDlgExtendedError () ) {
+
+ dwErr;// NTKLUG : if an error occurred handle it here
+ }
+
+ EnableWindow ( hDlg, TRUE );
+ SetFocus ( GetDlgItem ( hDlg, IDD_RSET_RESTORE_PATH ) );
+
+ return TRUE;
+ }
+
+ default:
+
+ return FALSE;
+
+ } /* end switch for Command ID */
+
+ } /* end WM_COMMAND case */
+
+ break;
+
+ case WM_SETCURSOR:
+
+ if ( WM_SetCursor ( hDlg ) ) {
+ return 1;
+ }
+
+ break;
+
+ default:
+
+ return FALSE; /* Didn't process a message */
+ }
+
+ return TRUE;
+}
+
+/***************************************************
+
+ Name: RestoreSetSave
+
+ Description: Save the current BSDs information
+
+ Returns:
+
+*****************************************************/
+BOOL RestoreSetSave(
+
+HWND hDlg ) /* window handle of the dialog box */
+
+{
+ INT nButtonState;
+ CHAR szTargetPath[ MAX_UI_PATH_SIZE ];
+ BSD_PTR pBSD;
+ BSD_PTR bsd_ptr ;
+ CDS_PTR pCDS;
+ BE_CFG_PTR pBEConfig;
+
+ /******************************************************** */
+ /* Retrieve the current BSD data */
+ /******************************************************** */
+
+ pBSD = GetTapeBSDPointer( mwpStatus->BSD_index );
+ pCDS = CDS_GetCopy();
+ pBEConfig = BSD_GetConfigData( pBSD );
+
+
+ switch ( BSD_GetOsId( pBSD ) ){
+
+ case FS_EMS_MDB_ID:
+ case FS_EMS_DSA_ID:
+
+ nButtonState = 0;
+
+ nButtonState |= (IsDlgButtonChecked( hDlg, IDD_RSET_PRIV_IS )) ? BEC_EMS_PRIVATE:0;
+ nButtonState |= (IsDlgButtonChecked( hDlg, IDD_RSET_PUB_IS )) ? BEC_EMS_PUBLIC:0;
+
+ BEC_SetEmsPubPri( pBEConfig, nButtonState );
+
+ BEC_SetEmsRipKick( pBEConfig, FALSE );
+
+ if ( BSD_GetOsId( pBSD ) == FS_EMS_DSA_ID ) {
+ GetDlgItemText( hDlg, IDD_RSET_DSA_DEST_NAME, (CHAR_PTR)szTargetPath, MAX_UI_PATH_LEN );
+ } else {
+ GetDlgItemText( hDlg, IDD_RSET_DEST_NAME, (CHAR_PTR)szTargetPath, MAX_UI_PATH_LEN );
+ }
+
+ if ( BSD_GetOsId(pBSD) == FS_EMS_MDB_ID ) {
+ CHAR_PTR vol_name ;
+
+ vol_name = calloc( strsize( szTargetPath ), 1 ) ;
+ if ( vol_name ) {
+ strcpy( vol_name, szTargetPath ) ;
+
+ free( BSD_GetLogicalSourceDevice( pBSD ) ) ;
+
+ BSD_SetLogicalSourceDevice( pBSD, vol_name ) ;
+ }
+ }
+
+ if ( !IsDlgButtonChecked( hDlg, IDD_RSET_WIPE_DATA ) ) {
+ BEC_SetEmsWipeClean( pBEConfig, FALSE );
+ } else {
+ BEC_SetEmsWipeClean( pBEConfig, TRUE );
+ }
+
+ if ( !IsDlgButtonChecked( hDlg, IDD_RSET_START_EMS ) ) {
+ BEC_SetEmsRipKick( pBEConfig, FALSE );
+ } else {
+ BEC_SetEmsRipKick( pBEConfig, TRUE );
+ }
+
+ // copy the dest and start bit to every BSD with the same
+ // source.
+
+ bsd_ptr = BSD_GetFirst( tape_bsd_list );
+ while (bsd_ptr ) {
+ CHAR_PTR dest_name ;
+ CHAR_PTR dest_name1 ;
+ CHAR_PTR new_dest_name ;
+ CHAR_PTR src_name ;
+ CHAR_PTR src_name1 ;
+ BOOLEAN kick_it ;
+
+ src_name = BSD_GetVolumeLabel( pBSD ) ;
+ src_name1 = BSD_GetVolumeLabel( bsd_ptr ) ;
+
+ if ( (bsd_ptr != pBSD ) &&
+ (BSD_GetOsId( bsd_ptr ) == FS_EMS_MDB_ID ) &&
+ src_name1 && src_name &&
+ !stricmp( src_name1, src_name) ) {
+
+ dest_name = BSD_GetLogicalSourceDevice( pBSD ) ;
+ if (dest_name && (*dest_name != TEXT('\0') ) ) {
+
+ new_dest_name = calloc( strsize( dest_name ), 1 ) ;
+ strcpy( new_dest_name, dest_name ) ;
+
+ dest_name = BSD_GetLogicalSourceDevice( bsd_ptr ) ;
+ free( dest_name ) ;
+ BSD_SetLogicalSourceDevice( bsd_ptr, new_dest_name ) ;
+ }
+
+ }
+
+ dest_name = BSD_GetLogicalSourceDevice( pBSD ) ;
+ if ( ( dest_name== NULL ) || (*dest_name == TEXT('\0') ) ) {
+ dest_name = src_name ;
+ }
+ dest_name1 = BSD_GetLogicalSourceDevice( bsd_ptr ) ;
+ if ( ( dest_name1== NULL ) || (*dest_name1 == TEXT('\0') ) ) {
+ dest_name1 = src_name1 ;
+ }
+
+ if ( dest_name1 && dest_name &&
+ !stricmp( dest_name1, dest_name) ) {
+
+ kick_it = BEC_GetEmsRipKick(pBEConfig) ;
+ BEC_SetEmsRipKick( BSD_GetConfigData( bsd_ptr ) , kick_it ) ;
+
+ }
+
+ bsd_ptr = BSD_GetNext( bsd_ptr ) ;
+ }
+
+ break;
+
+ default:
+
+ /* Get the path and make sure it's valid. If it isn't, let him try again. */
+
+ GetDlgItemText( hDlg, IDD_RSET_RESTORE_PATH, (CHAR_PTR)szTargetPath, MAX_UI_PATH_LEN );
+
+ if ( !VLM_ValidatePath( szTargetPath, FALSE, TRUE ) ) {
+
+ return( FALSE ) ; // the path was not valid
+ }
+
+ SetTargetPath( pBSD, szTargetPath );
+
+ // if the mode is restore - save the state of the bindery flag
+
+ if ( mwpStatus->fMode == RESTORE_MODE ) {
+
+ /* save the state of the bindery flag */
+ /* if backup bindery allowed, save the bindery flay for this BSD */
+
+ if ( DLE_HasFeatures( BSD_GetDLE( pBSD ),
+ DLE_FEAT_REST_SPECIAL_FILES ) ) {
+
+# if defined ( OS_WIN32 ) //unsupported feature
+ nButtonState = IsDlgButtonChecked( hDlg, IDD_RSET_REGISTRY );
+ BSD_SetProcSpecialFlg( pBSD, (INT16)nButtonState );
+ BEC_SetProcSpecialFiles( pBEConfig, nButtonState );
+ UI_AddSpecialIncOrExc( pBSD, nButtonState ) ;
+# else
+ nButtonState = IsDlgButtonChecked( hDlg, IDD_RSET_BINDERY );
+ BSD_SetProcSpecialFlg( pBSD, (INT16)nButtonState );
+ BEC_SetProcSpecialFiles( pBEConfig, nButtonState );
+# endif
+ }
+
+ /* if restore security information allowed, save the flay for this BSD */
+ if ( FS_PromptForSecure( BSD_GetDLE( pBSD ) ) ) {
+
+ nButtonState = IsDlgButtonChecked( hDlg, IDD_RSET_SECURITY_INFO );
+ BEC_SetRestoreSecurity( pBEConfig, nButtonState );
+ BSD_SetProcElemOnlyFlg( pBSD, !nButtonState ) ;
+ } else {
+ BEC_SetRestoreSecurity( pBEConfig, FALSE );
+ BSD_SetProcElemOnlyFlg( pBSD, TRUE ) ;
+ }
+ }
+# ifdef OS_WIN32
+ BSD_SetProcElemOnlyFlg( pBSD, FALSE ) ;
+# endif
+ // save the target drive
+
+ SetRestoreDrive( hDlg );
+
+ break;
+
+ } // switch ( BSD_GetOsId( pBSD ) )
+
+ return( TRUE );
+}
+/***************************************************
+
+ Name: RestoreSetRetrieve
+
+ Description: Retrieve this BSDs information
+
+ Returns:
+
+*****************************************************/
+VOID RestoreSetRetrieve (
+#ifndef OEM_EMS
+ HWND hDlg ) /* window handle of the dialog box */
+#else
+ HWND hDlg,
+ DLG_MODE * pModeTable )
+#endif
+
+{
+ INT16 nStatus;
+ UINT32 unTapeID;
+ INT16 nTapeSetNum;
+ CHAR_PTR pszTemp;
+ CHAR szBuffer1[ 80 ];
+ CHAR szBuffer2[ 80 ];
+ CHAR szTime[ 20 ];
+ CHAR szDate[ 20 ];
+ BSD_PTR pBSD;
+ CDS_PTR pCDS;
+ BE_CFG_PTR pBEConfig;
+#ifdef OEM_EMS
+ GENERIC_DLE_PTR pDLE;
+ INT16 nButtonState;
+#endif // OEM_EMS
+ INT16 nTapeType;
+ INT16 nTapeDate;
+ INT16 nTapeTime;
+ CHAR szTargetPath[ MAX_UI_PATH_SIZE ];
+ CHAR szTempBuf[ MAX_UI_RESOURCE_SIZE ];
+
+
+ /******************************************************** */
+ /* Set the current BSD data */
+ /******************************************************** */
+ pBSD = GetTapeBSDPointer( mwpStatus->BSD_index );
+ pCDS = CDS_GetCopy();
+ pBEConfig = BSD_GetConfigData( pBSD );
+#ifdef OEM_EMS
+ pDLE = BSD_GetDLE( pBSD );
+#endif
+
+ pszTemp = (LPSTR)BSD_GetBackupDescript( pBSD );
+ SetDlgItemText( hDlg, IDD_RSET_SET_LINE_1, pszTemp );
+
+ /* display the default tape name */
+ pszTemp = (LPSTR)BSD_GetTapeLabel( pBSD );
+ SetDlgItemText( hDlg, IDD_RSET_TAPE_NAME, pszTemp );
+
+
+ switch ( BSD_GetOsId ( pBSD ) ) {
+
+#ifdef OEM_EMS
+ case FS_EMS_MDB_ID:
+ case FS_EMS_DSA_ID:
+
+ nButtonState = BEC_GetEmsPubPri( pBEConfig );
+
+ if ( BEC_EMS_PRIVATE & nButtonState ) {
+ CheckDlgButton( hDlg, IDD_RSET_PRIV_IS, TRUE );
+ } else {
+ CheckDlgButton( hDlg, IDD_RSET_PRIV_IS, FALSE);
+ }
+
+ if ( BEC_EMS_PUBLIC & nButtonState ) {
+ CheckDlgButton( hDlg, IDD_RSET_PUB_IS, TRUE );
+ } else {
+ CheckDlgButton( hDlg, IDD_RSET_PUB_IS, FALSE );
+ }
+
+
+ if ( BEC_GetEmsWipeClean( pBEConfig ) ) {
+ CheckDlgButton( hDlg, IDD_RSET_WIPE_DATA, TRUE );
+
+ } else {
+ CheckDlgButton( hDlg, IDD_RSET_WIPE_DATA, FALSE );
+ }
+
+ if ( BEC_GetEmsRipKick( pBEConfig ) ) {
+ CheckDlgButton( hDlg, IDD_RSET_START_EMS, TRUE );
+
+ } else {
+ CheckDlgButton( hDlg, IDD_RSET_START_EMS, FALSE );
+ }
+
+ if ( ( BSD_GetOsId(pBSD) == FS_EMS_MDB_ID ) &&
+ ( BSD_GetLogicalSourceDevice( pBSD ) == NULL ) ) {
+
+ CHAR_PTR vol_name ;
+
+ vol_name = calloc( sizeof(CHAR),1 ) ;
+ BSD_SetLogicalSourceDevice( pBSD, vol_name ) ;
+
+ }
+
+ SetDlgItemText( hDlg, IDD_RSET_DEST_NAME, BSD_GetLogicalSourceDevice( pBSD ) );
+ SetDlgItemText( hDlg, IDD_RSET_ORG_NAME, BSD_GetVolumeLabel( pBSD ) );
+ SetDlgItemText( hDlg, IDD_RSET_DSA_DEST_NAME, BSD_GetVolumeLabel( pBSD ) );
+
+ break;
+#endif //OEM_EMS
+ default:
+
+ /* get this restore path information */
+ szTargetPath[0] = 0;
+ GetTargetPath( pBSD, szTargetPath );
+ SetDlgItemText( hDlg, IDD_RSET_RESTORE_PATH, (CHAR_PTR)szTargetPath );
+
+ /* if the mode flag is set for a restore then get the Bindery check box */
+ if ( mwpStatus->fMode == RESTORE_MODE ) {
+
+# ifdef OS_WIN32
+ {
+ CheckDlgButton(hDlg, IDD_RSET_REGISTRY, FALSE );
+
+ /* check for backup bindery, enable/disable the control */
+ nStatus = DLE_HasFeatures( BSD_GetDLE( pBSD ),
+ DLE_FEAT_REST_SPECIAL_FILES );
+
+ EnableWindow( GetDlgItem( hDlg, IDD_RSET_REGISTRY ), nStatus );
+
+ if ( nStatus ) {
+ /* set the state of the bindery flag */
+ nStatus = BSD_GetProcSpecialFlg( pBSD ) ;
+ CheckDlgButton(hDlg, IDD_RSET_REGISTRY, nStatus );
+ }
+ }
+# endif
+
+ /* check for restore security information, enable/disable the control */
+
+ nStatus = FS_PromptForSecure( BSD_GetDLE( pBSD ) );
+
+ if ( ! nStatus ) {
+ BEC_SetRestoreSecurity( pBEConfig, nStatus );
+ }
+
+ // Turn checkbox off before we disable the window.
+
+ if ( ! nStatus ) {
+ CheckDlgButton(hDlg, IDD_RSET_SECURITY_INFO, nStatus );
+ }
+
+ EnableWindow( GetDlgItem( hDlg, IDD_RSET_SECURITY_INFO ), nStatus );
+
+ if ( nStatus ) {
+ /* restore security allowed, get the state of flag */
+ nStatus = BEC_GetRestoreSecurity( pBEConfig );
+ CheckDlgButton(hDlg, IDD_RSET_SECURITY_INFO, nStatus );
+ }
+
+ }
+
+ /* get the current drive selected */
+ GetRestoreDrive ( hDlg );
+
+ break;
+
+ } // switch ( BSD_GetOsId ( pBSD ) )
+
+
+ /* add "1 of n" to backup set info title */
+ RSM_StringCopy( IDS_SET_INFORMATION, szBuffer1, 80 );
+ wsprintf( szBuffer2, szBuffer1,mwpStatus->BSD_index + 1, mwpStatus->max_BSD_index + 1 );
+ SetDlgItemText( hDlg, IDD_RSET_INFO_TITLE, szBuffer2 );
+
+ /* display the backup set name */
+ pszTemp = VLM_GetBsetName( BSD_GetTapeID( pBSD ), BSD_GetSetNum( pBSD ) );
+
+ if ( !strlen( pszTemp ) ) {
+ RSM_StringCopy( IDS_NO_BSET_NAME, szBuffer1, 80 );
+ pszTemp = szBuffer1;
+ }
+ SetDlgItemText( hDlg, IDD_RSET_SET_LINE_1, pszTemp );
+
+ unTapeID = BSD_GetTapeID( pBSD );
+ nTapeSetNum = BSD_GetSetNum( pBSD );
+
+ /* get the backup method */
+ nTapeType = VLM_GetBackupType( unTapeID, nTapeSetNum );
+
+ switch( nTapeType ) {
+
+ case QTC_NORM_BACKUP:
+ RSM_StringCopy( IDS_METHOD_NORMAL, szBuffer1, 80 );
+ break;
+ case QTC_COPY_BACKUP:
+ RSM_StringCopy( IDS_METHOD_COPY, szBuffer1, 80 );
+ break;
+ case QTC_DIFF_BACKUP:
+ RSM_StringCopy( IDS_METHOD_DIFFERENTIAL, szBuffer1, 80 );
+ BEC_SetEmsWipeClean( pBEConfig, FALSE );
+ BEC_SetEmsPubPri( pBEConfig, BEC_EMS_PUBLIC | BEC_EMS_PRIVATE );
+ break;
+ case QTC_INCR_BACKUP:
+ RSM_StringCopy( IDS_METHOD_INCREMENTAL, szBuffer1, 80 );
+ BEC_SetEmsWipeClean( pBEConfig, FALSE );
+ BEC_SetEmsPubPri( pBEConfig, BEC_EMS_PUBLIC | BEC_EMS_PRIVATE );
+ break;
+
+ }
+
+ /* get the volume name */
+ pszTemp = VLM_GetVolumeName( unTapeID, nTapeSetNum );
+
+ /* get the backup date */
+ nTapeDate = VLM_GetBackupDate( unTapeID, nTapeSetNum );
+
+ /* get the backup time */
+ nTapeTime = VLM_GetBackupTime( unTapeID, nTapeSetNum );
+
+ /* convert date & time to international form */
+ UI_IntToTime( szTime, nTapeTime );
+ UI_IntToDate( szDate, nTapeDate );
+
+ /* display the backup set description information */
+
+//??????? inconsistant
+# if defined ( OEM_MSOFT ) //alternate feature
+ {
+ RSM_Sprintf ( szTempBuf,
+ ID(RES_RESTORE_DESC_1),
+ szBuffer1,
+ pszTemp,
+ szDate,
+ szTime,
+ BSD_GetUserName ( pBSD )
+ );
+
+// yresprintf( (INT16) RES_RESTORE_DESC_1,
+// szBuffer1,
+// pszTemp,
+// szDate,
+// szTime,
+// BSD_GetUserName ( pBSD ) );
+ }
+# else // if defined ( OEM_MSOFT ) //alternate feature
+ {
+
+ RSM_Sprintf ( szTempBuf,
+ ID(RES_RESTORE_DESC_1),
+ szBuffer1,
+ pszTemp,
+ szDate,
+ szTime
+ );
+
+// yresprintf( RES_RESTORE_DESC_1,
+// szBuffer1,
+// pszTemp,
+// szDate,
+// szTime );
+ }
+# endif //defined ( OEM_MSOFT ) //alternate feature
+
+ SetDlgItemText( hDlg, IDD_RSET_SET_LINE_2, szTempBuf );
+
+
+#ifdef OEM_MSOFT
+
+
+ VLM_GetSetCreationDate( unTapeID, nTapeSetNum, &nTapeDate, &nTapeTime );
+
+ UI_IntToTime ( szTime, nTapeTime );
+ UI_IntToDate ( szDate, nTapeDate );
+
+ strcpy ( szTempBuf, szDate );
+ strcat ( szTempBuf, TEXT(" ") );
+ strcat ( szTempBuf, szTime );
+
+ SetDlgItemText ( hDlg, IDD_RSET_CREATION_DATE, szTempBuf );
+
+ VLM_GetSetOwnersName( unTapeID, nTapeSetNum, szTempBuf );
+
+ SetDlgItemText ( hDlg, IDD_RSET_OWNERS_NAME, szTempBuf );
+
+#endif
+
+
+#ifdef OEM_EMS
+ DM_DispShowControls( hDlg, pModeTable, BSD_GetOsId( pBSD ) );
+#endif
+
+ nTapeType = VLM_GetBackupType( unTapeID, nTapeSetNum );
+
+ switch( nTapeType ) {
+
+ case QTC_NORM_BACKUP:
+ case QTC_COPY_BACKUP:
+ EnableWindow( GetDlgItem( hDlg, IDD_RSET_PUB_IS ), TRUE );
+ EnableWindow( GetDlgItem( hDlg, IDD_RSET_PRIV_IS ), TRUE );
+ EnableWindow( GetDlgItem( hDlg, IDD_RSET_WIPE_DATA ), TRUE );
+ break;
+ case QTC_DIFF_BACKUP:
+ case QTC_INCR_BACKUP:
+ EnableWindow( GetDlgItem( hDlg, IDD_RSET_PUB_IS ), FALSE );
+ EnableWindow( GetDlgItem( hDlg, IDD_RSET_PRIV_IS ), FALSE );
+ EnableWindow( GetDlgItem( hDlg, IDD_RSET_WIPE_DATA ), FALSE );
+ break;
+
+ }
+
+
+// pszTemp = BSD_GetLogicalSourceDevice( pBSD ) ;
+// if ( (BSD_GetOsId( pBSD )== FS_EMS_MDB_ID ) &&
+// ( ( pszTemp == NULL ) ||
+// ( *pszTemp == TEXT('\0') ) ) ) {
+//
+// EnableWindow( GetDlgItem( hDlg, IDD_RSET_START_EMS ), FALSE );
+// } else {
+// EnableWindow( GetDlgItem( hDlg, IDD_RSET_START_EMS ), TRUE );
+// }
+//
+
+}
+/***************************************************
+
+ Name: GetMaxBSDCount
+
+ Description: Get the max number of BSD's for this operation
+
+ Returns: max BSD count
+
+*****************************************************/
+INT GetMaxBSDCount( VOID )
+{
+ BSD_PTR pBSD;
+ INT nBSDCounter;
+
+ nBSDCounter = 0;
+ pBSD = BSD_GetFirst( tape_bsd_list );
+
+ while ( pBSD != NULL ) {
+
+ nBSDCounter++;
+ pBSD = BSD_GetNext( pBSD );
+ }
+ return( --nBSDCounter );
+}
+/***************************************************
+
+ Name: GetTapeBSDPointer
+
+ Description: Return the current BSD pointer
+
+ Returns: Returns a pointer to the requested BSD
+
+*****************************************************/
+BSD_PTR GetTapeBSDPointer(
+INT index )
+{
+ BSD_PTR pBSD;
+
+ if ( !index )
+ pBSD = BSD_GetFirst( tape_bsd_list );
+ else {
+
+ pBSD = BSD_GetFirst( tape_bsd_list );
+ index--;
+ do
+ pBSD = BSD_GetNext( pBSD );
+ while ( index-- );
+ }
+ return( pBSD );
+}
+/***************************************************
+
+ Name: GetCurrentRestoreDriveList
+
+ Description:
+
+ Returns: void
+
+*****************************************************/
+VOID GetCurrentRestoreDriveList (
+
+HWND hDlg ) /* window handle of the dialog box */
+
+{
+ VLM_OBJECT_PTR pVLM;
+ CHAR szTempBuf[80];
+ VOID_PTR pServerList = NULL;
+ VOID_PTR pDriverList = NULL;
+ PDS_WMINFO pWinInfo;
+ WORD wListBoxCount;
+ LONG ListIndex;
+ GENERIC_DLE_PTR pDLE;
+
+# if !defined ( OEM_MSOFT ) // unused variable
+ BOOL bIsGrayed;
+ VLM_OBJECT_PTR pServerVLM;
+# endif // unused variable
+
+ SendDlgItemMessage ( hDlg, IDD_RSET_DRIVE_BOX, CB_RESETCONTENT, (MPARAM1)0, (MPARAM2) 0 ) ;
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+ {
+ if ( gb_servers_win != (HWND)NULL ) {
+
+ pWinInfo = WM_GetInfoPtr( gb_servers_win );
+ pServerList = pWinInfo->pTreeList;
+ pServerVLM = VLM_GetFirstVLM( (Q_HEADER_PTR) pServerList );
+
+ while ( pServerVLM != NULL ) {
+
+ pVLM = VLM_GetFirstVLM ( &pServerVLM->children );
+
+ while ( pVLM != NULL ) {
+
+ sprintf ( szTempBuf, TEXT("%s"), pVLM->name );
+
+ ListIndex = SendDlgItemMessage(hDlg,
+ IDD_RSET_DRIVE_BOX,
+ CB_ADDSTRING,
+ (MP1)0,
+ (MP2)szTempBuf );
+ DLE_FindByName(dle_list,
+ pVLM->name,
+ (INT16)-1,
+ &pDLE);
+ if (DLE_DriveWriteable(pDLE) == FALSE)
+ {
+ bIsGrayed = TRUE;
+ } else
+ {
+ bIsGrayed = FALSE;
+ }
+ SendDlgItemMessage(hDlg,
+ IDD_RSET_DRIVE_BOX,
+ CB_SETITEMDATA,
+ ListIndex,
+ (MP2)bIsGrayed);
+
+ pVLM = VLM_GetNextVLM ( pVLM );
+ }
+
+ pServerVLM = VLM_GetNextVLM ( pServerVLM );
+ }
+ }
+ }
+# endif //!defined ( OEM_MSOFT ) // unsupported feature
+
+ if ( gb_disks_win != (HWND)NULL ) {
+
+ pWinInfo = WM_GetInfoPtr( gb_disks_win );
+ pDriverList = pWinInfo->pFlatList;
+ pVLM = VLM_GetFirstVLM( (Q_HEADER_PTR) pDriverList );
+
+ while ( pVLM != NULL ) {
+
+ if ( strlen ( pVLM->label ) ) {
+ sprintf ( szTempBuf, TEXT("%s [%s]"), pVLM->name, pVLM->label );
+ }
+ else {
+ strcpy ( szTempBuf, pVLM->name );
+ }
+
+ DLE_FindByName(dle_list,
+ pVLM->name,
+ (INT16)-1,
+ &pDLE);
+ if (DLE_DriveWriteable(pDLE) )
+ {
+ ListIndex = SendDlgItemMessage ( hDlg, IDD_RSET_DRIVE_BOX, CB_ADDSTRING, (MP1)0, (MP2)szTempBuf );
+ SendDlgItemMessage(hDlg,
+ IDD_RSET_DRIVE_BOX,
+ CB_SETITEMDATA,
+ ListIndex,
+ (MP2)FALSE);
+
+ }
+
+ pVLM = VLM_GetNextVLM ( pVLM );
+ }
+ }
+
+ wListBoxCount = (WORD)SendDlgItemMessage ( hDlg, IDD_RSET_DRIVE_BOX, CB_GETCOUNT, 0, (MP2) 0 );
+
+ SendDlgItemMessage ( hDlg, IDD_RSET_DRIVE_BOX, CB_SETCURSEL, wListBoxCount - 1, (MP2) 0 );
+
+}
+/***************************************************
+
+ Name: SetRestoreDrive
+
+ Description:
+
+ Returns: void
+
+*****************************************************/
+VOID SetRestoreDrive(
+
+HWND hDlg ) /* window handle of the dialog box */
+
+{
+ WORD wListboxIndex;
+ BSD_PTR pBSD;
+ CHAR szTempBuf[80];
+ CHAR szTempBuf2[80];
+ CHAR_PTR pszTemp;
+ BOOL fDone = FALSE;
+ VLM_OBJECT_PTR pVLM;
+ VOID_PTR pServerList = NULL;
+ VOID_PTR pDriverList = NULL;
+ PDS_WMINFO pWinInfo;
+ GENERIC_DLE_PTR pDLE;
+
+# if !defined ( OEM_MSOFT ) // unused variable
+ VLM_OBJECT_PTR pServerVLM;
+ CHAR_PTR pszDriveName;
+# endif // unused variable
+
+
+ wListboxIndex = (WORD)SendDlgItemMessage ( hDlg, IDD_RSET_DRIVE_BOX, CB_GETCURSEL, 0, (MP2) 0 );
+
+ SendDlgItemMessage ( hDlg, IDD_RSET_DRIVE_BOX, CB_GETLBTEXT, wListboxIndex, (MP2) szTempBuf2 );
+
+ pszTemp = szTempBuf2;
+
+ if ( gb_disks_win != (HWND)NULL ) {
+
+ pWinInfo = WM_GetInfoPtr( gb_disks_win );
+ pDriverList = pWinInfo->pFlatList;
+ pVLM = VLM_GetFirstVLM( (Q_HEADER_PTR) pDriverList );
+
+ while ( pVLM != NULL ) {
+
+ if ( strlen ( pVLM->label ) ) {
+ sprintf ( szTempBuf, TEXT("%s [%s]"), pVLM->name, pVLM->label );
+ }
+ else {
+ strcpy ( szTempBuf, pVLM->name );
+ }
+
+
+ if ( ! stricmp( szTempBuf, pszTemp ) ) {
+ break;
+ }
+
+ pVLM = VLM_GetNextVLM( pVLM );
+ }
+ }
+
+ if ( pVLM == NULL ) {
+
+ fDone = FALSE;
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+ {
+ if ( gb_servers_win != (HWND)NULL ) {
+
+ pWinInfo = WM_GetInfoPtr ( gb_servers_win );
+ pServerList = pWinInfo->pTreeList;
+ pServerVLM = VLM_GetFirstVLM ( (Q_HEADER_PTR) pServerList );
+
+ while ( pServerVLM != NULL && !fDone) {
+
+ pVLM = VLM_GetFirstVLM ( &pServerVLM->children );
+
+ while ( pVLM != NULL && !fDone ) {
+
+ pszDriveName = pVLM->name;
+
+ if ( ! stricmp( pszDriveName, pszTemp ) ) {
+ fDone = TRUE;
+ }
+ else {
+ pVLM = VLM_GetNextVLM ( pVLM );
+ }
+ }
+
+ pServerVLM = VLM_GetNextVLM ( pServerVLM );
+ }
+ }
+ }
+# endif //!defined ( OEM_MSOFT ) // unsupported feature
+ }
+
+ pBSD = GetTapeBSDPointer( mwpStatus->BSD_index );
+
+ if ( ! pVLM ) {
+ pVLM = VLM_GetFirstVLM( (Q_HEADER_PTR) pDriverList );
+ }
+
+ /* if we found a VLM for this selection, set the BSD's DLE */
+ if ( pVLM ) {
+
+ DLE_FindByName( dle_list, pVLM->name, (INT16) -1, &pDLE );
+ BSD_SetDLE( pBSD, pDLE );
+ BSD_SetTHW( pBSD, thw_list );
+ }
+
+}
+/***************************************************
+
+ Name: GetRestoreDrive
+
+ Description:
+
+ Returns: void
+
+*****************************************************/
+VOID GetRestoreDrive(
+
+HWND hDlg ) /* window handle of the dialog box */
+
+{
+ WORD wListboxIndex;
+ WORD wMaxListboxIndex;
+ BSD_PTR pBSD;
+ CHAR szBuffer1[80];
+ CHAR szBuffer2[80];
+ CHAR_PTR pszTemp;
+ GENERIC_DLE_PTR pDLE;
+ CHAR_PTR pszDriveName;
+ INT nSize;
+
+
+ wListboxIndex = 0;
+ wMaxListboxIndex = (WORD)SendDlgItemMessage ( hDlg, IDD_RSET_DRIVE_BOX, CB_GETCOUNT, 0, (MP2) 0 );
+
+ pBSD = GetTapeBSDPointer( mwpStatus->BSD_index );
+ pDLE = BSD_GetDLE( pBSD );
+
+ /* if device name has been set, retrieve it */
+ if ( pDLE ) {
+
+ /* get the current selected name */
+ pszDriveName = DLE_GetDeviceName( pDLE );
+ nSize = strlen( pszDriveName );
+
+ while ( wListboxIndex <= wMaxListboxIndex ) {
+
+ pszTemp = szBuffer1;
+ SendDlgItemMessage ( hDlg, IDD_RSET_DRIVE_BOX, CB_GETLBTEXT, wListboxIndex,(MP2) pszTemp );
+ if ( !strnicmp( pszDriveName, pszTemp, nSize ) ) {
+
+ SendDlgItemMessage ( hDlg, IDD_RSET_DRIVE_BOX, CB_SETCURSEL, wListboxIndex, (MP2) 0 );
+ break;
+ }
+ wListboxIndex++;
+ }
+ }
+ else { /* show the default drive from the tape */
+
+ pszTemp = VLM_GetVolumeName( BSD_GetTapeID( pBSD), BSD_GetSetNum( pBSD ) );
+ strcpy( szBuffer2, pszTemp );
+ szBuffer2[2] = 0;
+ nSize = strlen( szBuffer2 );
+ while ( wListboxIndex <= wMaxListboxIndex ) {
+
+ pszTemp = szBuffer1;
+ pszDriveName = szBuffer2;
+ SendDlgItemMessage ( hDlg, IDD_RSET_DRIVE_BOX, CB_GETLBTEXT, wListboxIndex,(MP2) pszTemp );
+ if ( !strnicmp( pszDriveName, pszTemp, nSize ) ) {
+
+ SendDlgItemMessage ( hDlg, IDD_RSET_DRIVE_BOX, CB_SETCURSEL, wListboxIndex, (MP2) 0 );
+ break;
+ }
+ wListboxIndex++;
+ }
+ }
+}
+/***************************************************
+
+ Name: SetTargetPath
+
+ Description:
+
+ Returns: void
+
+*****************************************************/
+static VOID SetTargetPath (
+BSD_PTR pBSD,
+CHAR_PTR p )
+{
+ CHAR szBuffer1[ MAX_UI_PATH_SIZE ];
+ CHAR_PTR p1;
+ CHAR_PTR p2;
+ INT16 nSize1;
+ INT16 nSize2;
+
+ nSize1 = (INT16) strlen( p ) ;
+
+ if ( nSize1 ) {
+ strcpy( szBuffer1, p ) ;
+
+
+ p1 = szBuffer1;
+
+ while ( *p1 == TEXT(' ') ) /* remove leading spaces */
+ *p1++;
+
+ if ( *p1 == 0x5c || *p1 == TEXT(':')) /* remove leading '\' or TEXT(':') CHAR */
+ *p1++;
+
+ p2 = p1; /* start of the path name */
+
+ nSize1 = 0;
+ while ( *p2 ) { /* find end of line */
+ *p2++;
+ nSize1++ ;
+ }
+
+ /* don't remove leading '\' */
+ if ( nSize1 > 1 ) {
+
+ *p2--;
+ if ( *p2 == 0x5c || *p2 == TEXT(':') ) /* remove ending '\' or TEXT(':') character */
+ *p2 = 0 ;
+
+ }
+
+ p2 = p1; /* save the start of the path name for a later compare */
+
+ nSize1 = 0;
+
+ /* change any '\' or ':' characters to '0' */
+ while ( *p1 ) {
+
+ if ( *p1 == 0x5c || *p1 == TEXT(':'))
+ *p1 = 0;
+
+ nSize1++;
+ *p1++;
+ }
+
+ nSize1++; /* count the ending zero */
+ nSize1 *= sizeof (CHAR); /* cvt to byte count */
+
+ BSD_GetTargetInfo( pBSD, (INT8_PTR *)&p1, &nSize2 );
+
+ /* if the sizes are the same, compare the path strings */
+ if ( nSize1 == nSize2 ) {
+
+ if ( memcmp( p2, p1, nSize2) ) {
+
+ /* the strings are different, save the string */
+ BSD_SetTargetInfo( pBSD, (INT8_PTR)p2, nSize1 ) ;
+ }
+ }
+ else {
+
+ /* the sizes are different, so the strings must be different */
+ BSD_SetTargetInfo( pBSD, (INT8_PTR)p2, nSize1 ) ;
+ }
+
+ } else { // the user wants a blank path, so give it to him
+
+ BSD_SetTargetInfo( pBSD, NULL, (INT16) NULL ) ;
+ }
+}
+/***************************************************
+
+ Name: GetTargetPath
+
+ Description:
+
+ Returns: void
+
+*****************************************************/
+static VOID GetTargetPath(
+BSD_PTR pBSD ,
+CHAR_PTR p )
+{
+ CHAR szBuffer1[ MAX_UI_PATH_SIZE ];
+ CHAR_PTR p1;
+ INT16 nSize1;
+ INT16 nSize2;
+
+ BSD_GetTargetInfo( pBSD, (INT8_PTR *)&p1, &nSize1 );
+
+ if ( nSize1 ) {
+ nSize2 = nSize1;
+ nSize1 /= sizeof(CHAR) ;
+ szBuffer1[0] = 0x5c;
+ memcpy( &szBuffer1[1], p1, nSize2 );
+
+ p1 = szBuffer1;
+ while ( nSize1-- ) {
+
+ if ( *p1 == 0 )
+ *p1 = 0x5c;
+ *p1++;
+ }
+ *p1++ = 0;
+ memcpy( p, szBuffer1, (nSize2 + sizeof(CHAR) ) );
+ }
+}
+/***************************************************
+
+ Name: SetDefaultDLE
+
+ Description: This functon will set up any default data
+ that is required for the restore/verify operation.
+ It will search the volume list box to find a match for
+ the volume name of the BSD. If a match is found, the
+ BSDs DLE will be set to that volume, else the default
+ drive (C:) will be used.
+
+ Returns: void
+
+*****************************************************/
+VOID SetDefaultDLE (
+
+HWND hDlg ) /* window handle of the dialog box */
+
+{
+ INT16 fRestoreExistingFiles;
+ WORD wDefaultDrive = 0;
+ WORD wListboxIndex;
+ WORD wMaxListboxIndex;
+ WORD nSize;
+ BSD_PTR pBSD;
+ CHAR szBuffer1[280];
+ CHAR szBuffer2[280];
+ CHAR_PTR pszListboxString;
+ CDS_PTR pCDS;
+ BE_CFG_PTR pBEConfig;
+ CHAR_PTR pszVolumeName;
+ CHAR_PTR p;
+
+ mwpStatus->BSD_index = 0;
+
+ wMaxListboxIndex = (WORD)SendDlgItemMessage ( hDlg, IDD_RSET_DRIVE_BOX, CB_GETCOUNT, 0, (MP2) 0 );
+
+ pCDS = CDS_GetCopy();
+
+ fRestoreExistingFiles = CDS_GetRestoreExistingFiles( pCDS );
+
+ switch ( fRestoreExistingFiles ) {
+
+ case RESTORE_OVER_EXISTING :
+
+ fRestoreExistingFiles = BEC_REST_OVER_EXIST;
+ break;
+
+ case NO_RESTORE_OVER_EXISTING :
+
+ fRestoreExistingFiles = BEC_PROMPT_REST_OVER_EXIST;
+ break;
+
+ case PROMPT_RESTORE_OVER_EXISTING :
+ case NO_RESTORE_OVER_RECENT :
+ case PROMPT_RESTORE_OVER_RECENT :
+
+ fRestoreExistingFiles = BEC_PROMPT_REST_OVER_EXIST;
+ break;
+
+ default:
+
+ fRestoreExistingFiles = BEC_NO_REST_OVER_EXIST;
+ break;
+ }
+
+
+ /* look for the default drive - the 'C:' drive */
+ szBuffer2[0] = TEXT('C');
+ szBuffer2[1] = TEXT(':');
+ szBuffer2[2] = 0;
+
+ /* buffer is setup for 'C:' */
+ pszVolumeName = szBuffer2;
+ nSize = strlen( szBuffer2 );
+
+ pszListboxString = szBuffer1;
+
+ wListboxIndex = 0;
+ while ( wListboxIndex <= wMaxListboxIndex ) {
+
+ /* read the selection from the list box */
+ SendDlgItemMessage ( hDlg, IDD_RSET_DRIVE_BOX, CB_GETLBTEXT, wListboxIndex, (MP2) pszListboxString );
+
+ /* does list box entry match the search name? */
+ if ( !strnicmp( pszVolumeName, pszListboxString, nSize ) ) {
+
+ /* a match was found */
+ wDefaultDrive = wListboxIndex;
+ break;
+ }
+
+ wListboxIndex++;
+ }
+
+ /* try to match a volume name in the list box for each volume name */
+ /* of the BSDs */
+
+ while ( mwpStatus->BSD_index <= mwpStatus->max_BSD_index ) {
+
+ pBSD = GetTapeBSDPointer( mwpStatus->BSD_index );
+ pBEConfig = BSD_GetConfigData( pBSD );
+
+ /* Set the restore extisting files flag for this BSD */
+ BEC_SetExistFlag( pBEConfig, fRestoreExistingFiles );
+
+ /* set the default drive for no match */
+ SendDlgItemMessage ( hDlg, IDD_RSET_DRIVE_BOX, CB_SETCURSEL, wDefaultDrive, (MP2) 0 );
+
+ /* get the volume name for this BSD */
+ pszVolumeName = VLM_GetVolumeName( BSD_GetTapeID( pBSD), BSD_GetSetNum( pBSD ) );
+ strcpy( szBuffer2, pszVolumeName );
+
+ /* volume name on tape */
+ pszVolumeName = szBuffer2;
+ p = strchr( szBuffer2, TEXT(':') );
+
+ if ( p ) {
+ nSize = (INT16)(( p + 1 ) - pszVolumeName); /* used by the strnicmp call later */
+ }
+ else {
+ nSize = 0;
+ }
+
+ wListboxIndex = 0;
+
+ while ( wListboxIndex <= wMaxListboxIndex ) {
+
+ /* read the volume from the list box for comparison */
+ pszListboxString = szBuffer1;
+ SendDlgItemMessage ( hDlg, IDD_RSET_DRIVE_BOX, CB_GETLBTEXT, wListboxIndex, (MP2) pszListboxString );
+
+ if ( nSize ) {
+
+ if ( !strnicmp( pszVolumeName, pszListboxString, nSize ) ) {
+
+ SendDlgItemMessage ( hDlg, IDD_RSET_DRIVE_BOX, CB_SETCURSEL, wListboxIndex, (MP2) 0 );
+ break;
+ }
+ }
+
+ wListboxIndex++;
+ }
+
+ /* this function will set up the DLE for this BSD */
+ /* it uses the current selection in the list box for this purpose */
+ SetRestoreDrive( hDlg );
+
+ mwpStatus->BSD_index++;
+ }
+
+ mwpStatus->BSD_index = 0;
+}
+
+/***************************************************
+
+ Name: ScrollLineDown
+
+ Description: decrements the index counter
+
+ Returns: void
+
+*****************************************************/
+static VOID ScrollLineDown( VOID )
+{
+ if ( mwpStatus->BSD_index > 0 )
+ {
+ mwpStatus->BSD_index--;
+ }
+}
+
+/***************************************************
+
+ Name: ScrollLineUp
+
+ Description: increments the index counter
+
+ Returns: void
+
+*****************************************************/
+static VOID ScrollLineUp( VOID )
+{
+ if ( mwpStatus->BSD_index < mwpStatus->max_BSD_index ) {
+
+ mwpStatus->BSD_index++;
+ }
+}
+
+
+
+
+/***************************************************
+
+ Name: SeeIfWeCanSilentlyLogin
+
+ Description:
+
+ The dialog only lets us restore/verify to server volumes that we
+ know about. If we haven't attached we don't know about them. So
+ if we see one that it looks like it should be the one to use and
+ we can attach silently, then do it.
+
+ Returns: void
+
+*****************************************************/
+VOID SeeIfWeCanSilentlyLogin( )
+{
+#if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ BSD_PTR pBSD;
+ VLM_OBJECT_PTR pVLM;
+ FSYS_HAND fsh;
+ GENERIC_DLE_PTR pDLE;
+ WININFO_PTR pWinInfo;
+ CHAR_PTR pszVolumeName;
+
+ // look through tape_bsd_list at every bsd
+ if ( gb_servers_win == (HWND)NULL ) {
+ return;
+ }
+ pWinInfo = WM_GetInfoPtr( gb_servers_win );
+
+ pBSD = BSD_GetFirst( tape_bsd_list );
+
+ while ( pBSD != NULL ) {
+
+ pszVolumeName = VLM_GetVolumeName( BSD_GetTapeID( pBSD), BSD_GetSetNum( pBSD ) );
+
+ pVLM = VLM_GetFirstVLM( (Q_HEADER_PTR)pWinInfo->pTreeList );
+
+ while ( pVLM != NULL ) {
+
+ if ( ! strnicmp( pszVolumeName, pVLM->name, strlen( pVLM->name ) ) ) {
+
+ if ( QueueCount( &pVLM->children ) == 0 ) {
+
+ DLE_FindByName( dle_list, pVLM->name, -1, &pDLE );
+
+ if ( ! UI_AttachDrive( &fsh, pDLE, TRUE ) ) {
+ VLM_AddInServerChildren( pVLM );
+ FS_DetachDLE( fsh );
+ }
+ }
+ }
+
+ pVLM = VLM_GetNextVLM( pVLM );
+ }
+
+ pBSD = BSD_GetNext( pBSD );
+ }
+ }
+#endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+}
+
+/***************************************************
+
+ Name: clock_routine
+
+ Description: poll drive status routine
+
+ Returns: void
+
+*****************************************************/
+LOCALFN VOID clock_routine( VOID )
+{
+ DBLK_PTR vcb_ptr;
+ WORD status;
+
+ status = VLM_GetDriveStatus( &vcb_ptr );
+
+ switch( status ) {
+
+ case VLM_VALID_TAPE:
+
+ if(mwpStatus->display_status != VLM_VALID_TAPE ) {
+
+ mwpStatus->display_status = VLM_VALID_TAPE;
+
+ /* turn the OK button ON */
+ EnableWindow ( GetDlgItem ( mwpStatus->ghDlg, IDD_RSET_OK_BUTTON ), ON ) ;
+ }
+ break;
+
+ case VLM_DRIVE_FAILURE:
+
+ if(mwpStatus->display_status != VLM_DRIVE_FAILURE ) {
+
+ mwpStatus->display_status = VLM_DRIVE_FAILURE;
+
+ /* turn the OK button off when no tape */
+ EnableWindow ( GetDlgItem ( mwpStatus->ghDlg, IDD_RSET_OK_BUTTON ), OFF ) ;
+ }
+ break;
+
+ } /* end switch statment */
+
+} /* end clock routine */
+
+#ifdef OEM_EMS
+
+/***************************************************
+
+ Name: ConfirmXchgBsdServers
+
+ Description: Confirms and sets DLEs for Exchange servers
+
+ Returns: BOOLEAN
+
+*****************************************************/
+LOCALFN INT ConfirmXchgBsdServers(
+ WORD * pwPosition
+)
+{
+
+ WORD wIndex;
+ BSD_PTR pBSD;
+ BE_CFG_PTR pBEConfig;
+ CHAR_PTR pszTemp;
+ GENERIC_DLE_PTR pDLE;
+ GENERIC_DLE_PTR pChildDLE;
+ BOOLEAN xchg_found = FALSE ;
+
+ for( wIndex = 0; wIndex <= mwpStatus->max_BSD_index; wIndex++ ) {
+
+ pBSD = GetTapeBSDPointer( wIndex );
+
+ if ( ( BSD_GetOsId( pBSD ) != FS_EMS_MDB_ID ) &&
+ ( BSD_GetOsId( pBSD ) != FS_EMS_DSA_ID ) ) {
+ continue;
+ }
+
+ pBEConfig = BSD_GetConfigData( pBSD );
+
+ if ( BSD_GetOsId( pBSD ) == FS_EMS_MDB_ID ) {
+
+ pszTemp = BSD_GetLogicalSourceDevice(pBSD) ;
+ if ( (BEC_GetEmsPubPri( pBEConfig ) != (BEC_EMS_PUBLIC | BEC_EMS_PRIVATE)) ) {
+ if ( BEC_GetEmsWipeClean( pBEConfig ) ) {
+ *pwPosition = wIndex;
+ return EMS_NO_WIPE_IF_NOT_BOTH ;
+ }
+ }
+
+ } else {
+
+ pszTemp = BSD_GetVolumeLabel( pBSD ); // We're using the volume label to store the server name
+ }
+
+ if ( ( pszTemp == NULL ) || ( *pszTemp == TEXT('\0') ) ) {
+ *pwPosition = wIndex;
+ return EMS_NO_DEST ;
+ }
+
+ if ( ( BSD_GetOsId( pBSD ) == FS_EMS_MDB_ID ) &&
+ !BEC_GetEmsWipeClean(pBEConfig) &&
+ stricmp( BSD_GetLogicalSourceDevice(pBSD),
+ BSD_GetVolumeLabel(pBSD)) ) {
+
+ UINT32 unTapeID;
+ INT16 nTapeSetNum;
+ INT16 nTapeType;
+
+ unTapeID = BSD_GetTapeID( pBSD );
+ nTapeSetNum = BSD_GetSetNum( pBSD );
+
+
+ /* get the backup method */
+ nTapeType = VLM_GetBackupType( unTapeID, nTapeSetNum );
+
+ switch( nTapeType ) {
+
+ case QTC_NORM_BACKUP:
+ case QTC_COPY_BACKUP:
+ *pwPosition = wIndex;
+ return EMS_MUST_WIPE_TO_ALT ;
+ }
+ }
+
+ // Extract off the leading '\'s from the server name.
+ while ( TEXT ('\\') == *pszTemp ) pszTemp++;
+
+ if ( ( !pszTemp ) || ( TEXT ( '\0' ) == *pszTemp ) ) {
+ *pwPosition = wIndex;
+ return EMS_SERVER_NOT_FOUND;
+ }
+
+ if ( BEC_GetEmsPubPri( pBEConfig ) == 0 ) {
+ *pwPosition = wIndex;
+ return EMS_NO_STORE;
+ }
+
+ WM_ShowWaitCursor( TRUE );
+
+ // Things that have to happen in order. First, add name to EMS server list.
+ if ( SUCCESS == EMS_AddToServerList ( dle_list, pszTemp ) ) {
+
+ if ( SUCCESS != FS_FindDrives( FS_EMS_DRV, dle_list, pBEConfig, 0 ) ) {
+ *pwPosition = wIndex;
+ WM_ShowWaitCursor( FALSE );
+ return EMS_SERVER_NOT_FOUND;
+
+ }
+ }
+
+ WM_ShowWaitCursor( FALSE );
+
+ // Next, find the DLE for the server name and type.
+ if ( SUCCESS != DLE_FindByName( dle_list, pszTemp, FS_EMS_DRV, &pDLE ) ) {
+ *pwPosition = wIndex;
+ return EMS_SERVER_NOT_FOUND;
+ }
+
+ DLE_GetFirstChild( pDLE, &pChildDLE );
+
+ while( pChildDLE ) {
+
+ if ( DLE_GetOsId( pChildDLE ) == BSD_GetOsId( pBSD ) ) {
+
+ xchg_found = TRUE ;
+
+ BSD_SetDLE ( pBSD, pChildDLE );
+
+// free( BSD_GetLogicalSourceDevice(pBSD) );
+// BSD_SetLogicalSourceDevice(pBSD, NULL) ;
+
+ break;
+ }
+
+ DLE_GetNext( &pChildDLE );
+ }
+
+ if ( NULL == pChildDLE ) {
+ *pwPosition = wIndex;
+ return EMS_SERVER_NOT_FOUND;
+ }
+
+ }
+
+ if ( xchg_found ) {
+ return EMS_XCHG_FOUND ;
+ } else {
+ return SUCCESS;
+ }
+}
+
+#endif
diff --git a/private/utils/ntbackup/src/d_o_xchg.c b/private/utils/ntbackup/src/d_o_xchg.c
new file mode 100644
index 000000000..74dd61430
--- /dev/null
+++ b/private/utils/ntbackup/src/d_o_xchg.c
@@ -0,0 +1,732 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: D_O_BKUP.C
+
+ Description: Exchange server backup dialogs
+
+ $Log: $
+
+
+*****************************************************/
+
+#ifdef OEM_EMS //For entire file
+
+#include "all.h"
+#include "uiexport.h"
+#include "ctl3d.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+#define ON TRUE
+#define OFF FALSE
+
+typedef long EC;
+typedef EC (*GET_PCT_PTR) ( PVOID Instance, INT * piCur, INT * piTotal );
+
+INT DLG_StartEmsService( CHAR_PTR pszTemp, UINT8 uService ) ;
+
+typedef struct XCHG_RECOVER {
+
+ PVOID Instance;
+ GENERIC_DLE_PTR dle;
+ GET_PCT_PTR pfnPct;
+ INT *status ;
+
+} XCHG_RECOVER, *XCHG_RECOVER_PTR;
+
+/***************************************************
+
+ Name: DM_XchngConnect()
+
+ Description: Runtime Connect to Microsoft Exchange dialog.
+
+ Returns:
+
+*****************************************************/
+DLGRESULT APIENTRY DM_ExchgConnect(
+ HWND hDlg , /* window handle of the dialog box */
+ MSGID message , /* type of message */
+ MPARAM1 mp1 , /* message-specific information */
+ MPARAM2 mp2 )
+{
+ static CHAR szDir[ MAX_EMS_SERVER_LEN + 1 ];
+ static CHAR szIS[ MAX_EMS_SERVER_LEN + 1 ];
+ CHAR szTitle[ MAX_UI_WIN_TITLE_SIZE ];
+ CHAR szMsg[ MAX_UI_RESOURCE_SIZE ];
+ CHAR szBuffer[ MAX_UI_RESOURCE_SIZE ];
+ CHAR szServer[ MAX_EMS_SERVER_LEN + 1 ];
+ CHAR_PTR pszTemp;
+ GENERIC_DLE_PTR dle ;
+ BE_CFG_PTR pbeConfig;
+ BOOL bOkPressed ;
+ BOOL iDleExists;
+ FSYS_HAND fsh;
+ UINT8 uService;
+ INT16 iResult;
+
+ switch ( message )
+ {
+ /****************************************************************************
+ INIT THE DIALOG
+ /***************************************************************************/
+ case WM_INITDIALOG: /* message: initialize dialog box */
+
+ /* Let's go 3-D! */
+ Ctl3dSubclassDlgEx( hDlg, CTL3D_ALL );
+
+ DM_CenterDialog( hDlg );
+
+ /* set the length of the text field */
+ SendDlgItemMessage( hDlg, IDD_XCNCT_SVR_NAME, EM_LIMITTEXT,
+ MAX_EMS_SERVER_LEN, 0 );
+
+ /* Add the elements to the list box. */
+ RSM_StringCopy( IDS_XCHNG_DIR, szDir, sizeof( szBuffer ) );
+ SendDlgItemMessage( hDlg, IDD_XCNCT_SERVICE, CB_ADDSTRING,
+ 0, MP2FROMPVOID( szDir ) );
+
+ RSM_StringCopy( IDS_XCHNG_INFO_STORE, szIS, sizeof( szBuffer ) );
+ SendDlgItemMessage( hDlg, IDD_XCNCT_SERVICE, CB_ADDSTRING,
+ 0, MP2FROMPVOID( szIS ) );
+
+ SendDlgItemMessage( hDlg, IDD_XCNCT_SERVICE, CB_SETCURSEL, 0, 0 );
+
+ /* Make Connect the default option */
+ CheckRadioButton( hDlg, IDD_XCNCT_CONNECT, IDD_XCNCT_ONLINE, IDD_XCNCT_CONNECT );
+ EnableWindow( GetDlgItem( hDlg, IDD_XCNCT_SERVICE ), OFF );
+
+ EnableWindow( GetDlgItem( hDlg, IDD_XCNCT_OK ) , OFF );
+
+ return ( TRUE ) ;
+
+ /* Messages for setting the background color.
+ case WM_CTLCOLORSTATIC:
+ SetBkMode( (HDC)mp1, TRANSPARENT ) ;
+
+ case WM_CTLCOLORDLG:
+ case WM_CTLCOLORBTN:
+ case WM_CTLCOLORMSGBOX:
+
+ return ( (DLGRESULT)hBkgdBrush ) ; */
+
+
+ /****************************************************************************
+ WM COMMAND
+ /***************************************************************************/
+ case WM_COMMAND: /* message: received a command */
+ {
+ WORD wId = GET_WM_COMMAND_ID ( mp1, mp2 );
+
+ switch( wId )
+ {
+ case IDD_XCNCT_CONNECT:
+ EnableWindow( GetDlgItem( hDlg, IDD_XCNCT_SERVICE ), OFF );
+ return ( TRUE );
+
+ case IDD_XCNCT_ONLINE:
+ EnableWindow( GetDlgItem( hDlg, IDD_XCNCT_SERVICE ), ON );
+ return ( TRUE );
+
+ case IDD_XCNCT_PICKER:
+ {
+ CHAR *szFname[NAME_MAX_SIZE+1] ;
+
+ HM_MakeHelpPathName( szFname ) ;
+
+ EnableWindow( GetDlgItem( hDlg, IDD_XCNCT_OK ) , ON );
+ I_SystemFocusDialog( hDlg,
+ FOCUSDLG_SERVERS_ONLY | FOCUSDLG_BROWSE_ALL_DOMAINS ,
+ (LPTSTR)&szServer ,
+ MAX_EMS_SERVER_LEN ,
+ &bOkPressed ,
+ szFname ,
+ IDH_DB_XCHG_BROWSE );
+
+ if ( bOkPressed ) {
+
+ SetDlgItemText( hDlg, IDD_XCNCT_SVR_NAME, (LPTSTR)&szServer );
+ }
+
+ SendMessage( hDlg, DM_SETDEFID, IDD_XCNCT_OK, 0 );
+ SetFocus ( GetDlgItem ( hDlg, IDD_XCNCT_SVR_NAME ) );
+
+ return ( TRUE );
+ }
+
+/****************************************************************************
+ Help button
+/***************************************************************************/
+ case IDD_XCNCT_HELP:
+ case IDHELP:
+
+ HM_DialogHelp( IDH_DB_XCHG_CONNECT );
+
+ return( TRUE );
+
+ case IDD_XCNCT_SVR_NAME:
+
+ switch ( HIWORD( mp1 ) )
+ {
+ case EN_CHANGE:
+
+ /* Turn on OK if there is anything in the only edit field. */
+ if ( 0 == SendDlgItemMessage( hDlg, IDD_XCNCT_SVR_NAME, WM_GETTEXTLENGTH, 0, 0 ) ) {
+ EnableWindow( GetDlgItem( hDlg, IDD_XCNCT_OK ), OFF );
+
+ } else {
+ EnableWindow( GetDlgItem( hDlg, IDD_XCNCT_OK ), ON );
+ }
+
+ return ( TRUE );
+ }
+
+ return ( FALSE ); // Didn't process notification
+
+/****************************************************************************
+ Cancel button
+/***************************************************************************/
+ case IDD_XCNCT_CANCEL:
+ case IDCANCEL:
+
+ EndDialog( hDlg, FALSE ); /* Exits the dialog box */
+
+ return ( TRUE );
+
+/****************************************************************************
+ OK button
+/***************************************************************************/
+ case IDOK:
+ case IDD_XCNCT_OK:
+
+ WM_ShowWaitCursor( TRUE );
+
+ SetFocus ( GetDlgItem ( hDlg, IDD_XCNCT_OK ) );
+
+ SendDlgItemMessage( hDlg, IDD_XCNCT_SVR_NAME, EM_SETREADONLY, (MP1) TRUE, (MP2) 0 );
+
+ GetDlgItemText( hDlg, IDD_XCNCT_SVR_NAME, (LPTSTR)&szServer, MAX_EMS_SERVER_LEN );
+ GetDlgItemText( hDlg, IDD_XCNCT_SERVICE, (LPTSTR)&szBuffer, MAX_UI_RESOURCE_LEN );
+
+ uService = stricmp( szBuffer, szDir ) ? FS_EMS_MDB_ID : FS_EMS_DSA_ID;
+
+ pszTemp = (CHAR_PTR)&szServer;
+ dle = NULL;
+
+ // Remove leading '\'s
+ while ( TEXT ('\\') == *pszTemp ) pszTemp++;
+
+ if ( IsDlgButtonChecked( hDlg, IDD_XCNCT_ONLINE ) ) {
+
+ INT status ;
+
+ status = DLG_StartEmsService( pszTemp, uService ) ;
+
+ WM_ShowWaitCursor( FALSE );
+ if ( status == SUCCESS ) {
+
+ WM_MsgBox( ID(IDS_XCHNG_RECOVER_TITLE), ID( IDS_STARTEXCHANGE),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+
+ EndDialog( hDlg, TRUE ); /* Exits the dialog box */
+ }
+ SendDlgItemMessage( hDlg, IDD_XCNCT_SVR_NAME, EM_SETREADONLY, (MP1) FALSE, (MP2) 0 );
+ return TRUE; // Window was created and new server added.
+ break;
+ }
+
+ // from here down this case only deals with conecting
+
+ // See if server already exists in dle list and add it if it doesn't
+ if ( SUCCESS != (iDleExists = DLE_FindByEMSServerName( dle_list, pszTemp, uService, &dle ) ) ||
+ (NULL == DLE_GetParent(dle)) ||
+ (NULL == DLE_GetParent(DLE_GetParent(dle))) ) {
+
+ EMS_AddToServerList( dle_list, pszTemp );
+
+ if ( SUCCESS == FS_FindDrives( FS_EMS_DRV, dle_list, CDS_GetPermBEC(), 0 ) ) {
+
+ // if it doesn't exist now then show an error to the user.
+ iResult = DLE_FindByEMSServerName( dle_list, pszTemp, uService, &dle );
+ if ( SUCCESS != iResult ) {
+ CHAR machine[256];
+ SC_HANDLE mach_hand ;
+
+ WM_ShowWaitCursor( FALSE );
+ SendDlgItemMessage( hDlg, IDD_XCNCT_SVR_NAME, EM_SETREADONLY, (MP1) FALSE, (MP2) 0 );
+ RSM_StringCopy ( IDS_MSGTITLE_BADEXCHNG, szTitle, sizeof ( szTitle ) );
+
+ strcpy(machine, TEXT("\\\\") ) ;
+ strcat( machine, pszTemp ) ;
+
+ mach_hand = OpenSCManager( machine, NULL, SC_MANAGER_ENUMERATE_SERVICE ) ;
+ if (mach_hand == NULL ) {
+
+ RSM_StringCopy ( IDS_XCHNG_NO_SERVER, szMsg, sizeof ( szMsg ) );
+ } else {
+ CloseHandle( mach_hand ) ;
+ RSM_StringCopy ( IDS_XCHNG_NO_CONNECT, szMsg, sizeof ( szMsg ) );
+
+ }
+ wsprintf ( (LPTSTR)&szBuffer, szMsg, pszTemp );
+ MessageBox( hDlg, szBuffer, szTitle, MB_ICONASTERISK | MB_OK );
+
+ // Remove the name from the server list.
+ EMS_RemoveFromServerList( pszTemp );
+
+ SetFocus ( GetDlgItem ( hDlg, IDD_XCNCT_SVR_NAME ) );
+ SendDlgItemMessage( hDlg, IDD_XCNCT_SVR_NAME, EM_SETSEL, 0, -1 ) ;
+
+ return ( TRUE );
+ }
+ }
+
+ }
+
+
+ if ( NULL == DLE_GetEnterpriseDLE( dle ) ) {
+
+ // The server dle has no enterprise dle and shouldn't be handled.
+
+ WM_ShowWaitCursor( FALSE );
+ SendDlgItemMessage( hDlg, IDD_XCNCT_SVR_NAME, EM_SETREADONLY, (MP1) FALSE, (MP2) 0 );
+ RSM_StringCopy ( IDS_MSGTITLE_BADEXCHNG, szTitle, sizeof ( szTitle ) );
+
+ RSM_StringCopy ( IDS_XCHNG_NO_CONNECT, szMsg, sizeof ( szMsg ) );
+
+ wsprintf ( (LPTSTR)&szBuffer, szMsg, pszTemp );
+ MessageBox( hDlg, szBuffer, szTitle, MB_ICONASTERISK | MB_OK );
+
+ // Remove the name from the server list.
+ EMS_RemoveFromServerList( pszTemp );
+
+ SetFocus ( GetDlgItem ( hDlg, IDD_XCNCT_SVR_NAME ) );
+ SendDlgItemMessage( hDlg, IDD_XCNCT_SVR_NAME, EM_SETSEL, 0, -1 ) ;
+
+ return ( TRUE );
+ }
+
+ if ( iDleExists != SUCCESS ) {
+
+ // Create a window for a new connection or add the server to an existing one.
+ VLM_ExchangeListCreate( pszTemp );
+
+ } else {
+
+ // DLE already existed in a tree and must be in a window somewhere.
+ // Let's find it and set the anchor to it.
+ if ( !SLM_DisplayExchangeDLE( DLE_GetParent( dle ) ) ) {
+
+ // DLE exists but doesn't have a window so create the window.
+ VLM_ExchangeListCreate( pszTemp );
+ }
+ }
+
+
+ WM_ShowWaitCursor( FALSE );
+ EndDialog( hDlg, TRUE ); /* Exits the dialog box */
+
+ return TRUE; // Window was created and new server added.
+ break;
+
+ default:
+
+ return( FALSE );
+ break;
+
+ } /* switch ( wId ) */
+
+ } /* case WM_COMMAND */
+ break;
+
+ } /* switch ( message ) */
+
+ return ( FALSE ); /* Didn't process a message */
+}
+
+
+/***************************************************
+
+ Name: XchgKickPct ()
+
+ Description: Displays the Exchange Recovering Dialog.
+
+ Returns:
+
+*****************************************************/
+
+VOID XchgKickPct(
+ VOID_PTR pVoid,
+ GENERIC_DLE_PTR dle,
+ EC (* pfnPct)( PVOID, INT *, INT * ),
+ INT *status )
+{
+ XCHG_RECOVER EMSRecover;
+
+ EMSRecover.Instance = pVoid;
+ EMSRecover.dle = dle;
+ EMSRecover.pfnPct = pfnPct;
+ EMSRecover.status = status;
+
+}
+
+/***************************************************
+
+ Name: DM_ExchgRecover()
+
+ Description: Runtime Connect to Microsoft Exchange dialog.
+
+ Returns:
+
+*****************************************************/
+DLGRESULT APIENTRY DM_ExchgRecover(
+ HWND hDlg , /* window handle of the dialog box */
+ MSGID message , /* type of message */
+ MPARAM1 mp1 , /* message-specific information */
+ MPARAM2 mp2 )
+{
+ static HANDLE hBkgdBrush; // Background brush for dialog.
+ static HBRUSH hStatusBrush; // Brush for filling in status window.
+ static XCHG_RECOVER_PTR recoverdata; // Passed in during WM_INITDIALOG
+ static CHAR szPctComplete[ MAX_UI_RESOURCE_SIZE ];
+ static CHAR szPhase[ MAX_UI_RESOURCE_SIZE ];
+ static GET_PCT_PTR pfnGetPct;
+ static PVOID pInstance;
+ static UINT uTimer;
+ static INT iCur;
+ static INT iTotal;
+ static INT iStatus;
+ static INT fPct;
+ static HPEN hPenBevel;
+ static HWND hStatusBar;
+ static RECT rcFrame;
+ static RECT rcStatus;
+ static INT iPhase;
+ static HFONT hFont;
+ static INT iPct = 0;
+ static UINT16 ucPhases;
+
+ HWND hStatusText;
+ LOGFONT logfont;
+ CHAR szTitle[ MAX_UI_WIN_TITLE_SIZE ];
+ CHAR szMsg[ MAX_UI_RESOURCE_SIZE ];
+ CHAR szBuffer[ MAX_UI_RESOURCE_SIZE ];
+ CHAR szComponent[ MAX_DEVICE_NAME_LEN + 1 ];
+ GENERIC_DLE_PTR dle = NULL ;
+ LPDRAWITEMSTRUCT lpdis;
+ HDC hDC;
+ POINT ptStatus;
+ INT iNewPct;
+ HANDLE hResource;
+ HGLOBAL hMem;
+
+ switch ( message )
+ {
+ /****************************************************************************
+ INIT THE DIALOG
+ /***************************************************************************/
+ case WM_INITDIALOG: /* message: initialize dialog box */
+
+ // Let's go 3-D!!
+ Ctl3dSubclassDlgEx( hDlg, CTL3D_ALL );
+
+ recoverdata = (XCHG_RECOVER_PTR)mp2;
+ dle = recoverdata->dle;
+ pfnGetPct = recoverdata->pfnPct;
+ pInstance = recoverdata->Instance;
+
+ GetDlgItemText( hDlg, IDD_XCHG_RCVR_TEXT, (LPTSTR)szBuffer, MAX_UI_RESOURCE_LEN );
+
+ // Set up a resource ID value in case there's no dle.
+ ucPhases = IDR_XCHG_RCVR_DS_PHASE;
+
+ if ( NULL != dle ) {
+ DLE_DeviceDispName( dle, szComponent, MAX_DEVICE_NAME_LEN, 0 );
+ dle = DLE_GetParent( dle );
+
+ // Use the correct Resource ID based on the Os type.
+ switch ( DLE_GetOsId( dle ) ) {
+ case EMS_MDB:
+ ucPhases = IDR_XCHG_RCVR_IS_PHASE;
+ case EMS_DSA:
+ ucPhases = IDR_XCHG_RCVR_DS_PHASE;
+ }
+
+ }
+ wsprintf( szMsg, szBuffer, szComponent );
+ SetDlgItemText( hDlg, IDD_XCHG_RCVR_TEXT, (LPTSTR)szMsg );
+
+ /* Create the brush for status bar. */
+ hStatusBrush = CreatePatternBrush( RSM_BitmapLoad( IDRBM_RCVR_STATUS, RSM_MAGICCOLOR ) );
+
+ /* Get the format string for percent complete text from the control */
+ GetDlgItemText( hDlg, IDD_XCHG_RCVR_PCT, (LPTSTR)szPctComplete, MAX_UI_RESOURCE_LEN );
+ SetDlgItemText( hDlg, IDD_XCHG_RCVR_PCT, TEXT( "\0") );
+
+ /* Get the format string for phase text from the control */
+ GetDlgItemText( hDlg, IDD_XCHG_RCVR_PHASE, (LPTSTR)szPhase, MAX_UI_RESOURCE_LEN );
+ SetDlgItemText( hDlg, IDD_XCHG_RCVR_PHASE, TEXT( "\0") );
+
+ /* Get window handles for controls that will be dynamically updated. */
+ hStatusBar = GetDlgItem( hDlg, IDD_XCHG_RCVR_STATUS );
+ hStatusText = GetDlgItem( hDlg, IDD_XCHG_RCVR_PCT );
+
+ /* Set the font of the Percent text to a lighter font of the same type */
+ hFont = (HFONT)SendMessage( hStatusText, WM_GETFONT, 0, 0 );
+ GetObject( hFont, sizeof( LOGFONT ), &logfont );
+ logfont.lfWeight >>= 1;
+ hFont = CreateFontIndirect ( &logfont );
+ SendMessage( hStatusText, WM_SETFONT, (MPARAM1)hFont, (MPARAM2)FALSE );
+
+ // Now set the Phase text to the same font
+ hStatusText = GetDlgItem( hDlg, IDD_XCHG_RCVR_PHASE );
+ SendMessage( hStatusText, WM_SETFONT, (MPARAM1)hFont, (MPARAM2)FALSE );
+
+ // Load the values for the number of phases
+ hResource = FindResource( ghResInst, MAKEINTRESOURCE( ucPhases ), RT_RCDATA );
+ hMem = LoadResource( ghResInst, hResource );
+ ucPhases = ( hMem ) ? *((UINT16*)LockResource( hMem )) : 1;
+
+ /* Resize the status frame to be 13 units high. */
+ GetWindowRect( GetDlgItem( hDlg, IDD_XCHG_RCVR_STATUS_BORDER ), &rcFrame );
+ ptStatus.x = rcFrame.left;
+ ptStatus.y = rcFrame.top;
+ ScreenToClient( hDlg, &ptStatus );
+ MoveWindow( GetDlgItem( hDlg, IDD_XCHG_RCVR_STATUS_BORDER ),
+ ptStatus.x, ptStatus.y, rcFrame.right - rcFrame.left, 13, TRUE );
+
+ /* Resize the window for the status bar to fit inside the status frame. */
+ MoveWindow( hStatusBar, ptStatus.x + 1, ptStatus.y + 1,
+ rcFrame.right - rcFrame.left - 2, 11, TRUE );
+ rcStatus.top = rcFrame.top = 0;
+ rcStatus.bottom = rcFrame.bottom = 11;
+ rcFrame.right = rcFrame.right - rcFrame.left;
+ rcStatus.left = 0;
+
+ /* Create the timer for updating the status. */
+ uTimer = SetTimer( hDlg, 1, 100, NULL );
+
+ DM_CenterDialog( hDlg );
+
+ // First Phase
+ iPhase = 1;
+
+ return ( TRUE ) ;
+
+ case WM_TIMER:
+
+ // This call will update recoverdata->status also
+ (* pfnGetPct)( recoverdata->Instance, &iTotal, &iCur );
+
+ switch ( *(recoverdata->status) ) {
+
+ case EMS_PCT_CONTINUE:
+
+ fPct = ( (iCur*100) / iTotal );
+ iNewPct = fPct ;
+
+ if ( iPct > iNewPct + 10 ) {
+
+ iPhase++;
+ iPct = iNewPct;
+ InvalidateRect( hStatusBar, NULL, TRUE );
+
+ } else if ( iPct < iNewPct ) {
+
+ iPct = iNewPct;
+ InvalidateRect( hStatusBar, NULL, FALSE );
+ }
+
+ wsprintf( szBuffer, szPctComplete, iPct );
+ SetDlgItemText( hDlg, IDD_XCHG_RCVR_PCT, szBuffer );
+
+ wsprintf( szBuffer, szPhase, iPhase,
+ ( ucPhases >= iPhase) ? ucPhases : iPhase );
+ SetDlgItemText( hDlg, IDD_XCHG_RCVR_PHASE, szBuffer );
+
+ break;
+
+ default:
+ SendMessage( hDlg, WM_COMMAND, (MPARAM1)IDOK, (MPARAM2)NULL );
+
+ }
+
+ return ( 0 );
+
+ case WM_DRAWITEM:
+
+ lpdis = (LPDRAWITEMSTRUCT)mp2;
+ hDC = lpdis->hDC;
+
+ switch ( lpdis->CtlID )
+ {
+ case IDD_XCHG_RCVR_STATUS:
+
+ SetBkColor( hDC, GetSysColor( COLOR_BTNFACE ) ) ;
+
+ // Fill in the status part.
+ rcStatus.right = rcStatus.left + (INT)( lpdis->rcItem.right * fPct/100 );
+ FillRect( hDC, &rcStatus, hStatusBrush );
+
+ // Fill the rest in background color
+ rcFrame.left = rcStatus.right + 1;
+ FillRect( hDC, &rcFrame, Ctl3dCtlColorEx( WM_CTLCOLORBTN,
+ (MPARAM1) hDC,
+ (MPARAM2) lpdis->hwndItem ) );
+
+ return TRUE;
+ }
+
+
+ /****************************************************************************
+ WM COMMAND
+ /***************************************************************************/
+ case WM_COMMAND: /* message: received a command */
+ {
+ WORD wId = GET_WM_COMMAND_ID ( mp1, mp2 );
+
+ switch( wId )
+ {
+
+ /****************************************************************************
+ Cancel button
+ /***************************************************************************/
+ case IDOK:
+
+ if ( uTimer ) KillTimer( hDlg, uTimer );
+
+ DeleteObject( hStatusBrush );
+ DeleteObject( hFont );
+
+ EndDialog( hDlg, TRUE );
+
+ return ( TRUE );
+
+ case IDD_XCHG_RCVR_CANCEL:
+ case IDCANCEL:
+
+// RSM_StringCopy( IDS_XCHNG_STOP_RECOVER, szBuffer, MAX_UI_RESOURCE_LEN );
+// RSM_StringCopy( IDS_XCHNG_STOP_RECOVER_TITLE, szTitle, MAX_UI_WIN_TITLE_LEN );
+
+// if ( WMMB_IDOK == WM_MsgBox( szTitle,
+// szBuffer,
+// WMMB_OKCANCEL,
+// WMMB_ICONINFORMATION ) ) {
+//
+// if ( uTimer ) KillTimer( hDlg, uTimer );
+
+// DeleteObject( hStatusBrush );
+// DeleteObject( hFont );
+
+// EndDialog( hDlg, TRUE ); /* Exits the dialog box */
+
+// }
+
+ return ( TRUE );
+
+ default:
+ break;
+
+ } /* switch ( wId ) */
+
+ } /* case WM_COMMAND */
+ break;
+
+ } /* switch ( message ) */
+
+ return ( FALSE ); /* Didn't process a message */
+}
+
+INT DLG_StartEmsService( CHAR_PTR server_name, UINT8 uService )
+{
+ SC_HANDLE mach_hand ;
+ SC_HANDLE serv_hand ;
+ SERVICE_STATUS serv_status ;
+ INT last_error = 0 ;
+ CHAR machine[256];
+ LPSTR msg_title ;
+ LPSTR msg_text ;
+ INT ret_val = SUCCESS ;
+
+ msg_title = ID(IDS_XCHNG_RECOVER_TITLE) ;
+
+ strcpy( machine, TEXT("\\\\") ) ;
+ strcat( machine, server_name ) ;
+
+
+ mach_hand = OpenSCManager( machine, NULL, SC_MANAGER_ALL_ACCESS ) ;
+ if ( mach_hand == NULL ) {
+
+ last_error = GetLastError();
+ switch( last_error ) {
+ case ERROR_ACCESS_DENIED:
+ msg_text = ID( IDS_XCHNG_NO_SERVICE_ACCESS ) ;
+ break ;
+ default:
+ msg_text = ID( IDS_XCHNG_NO_SERVER ) ;
+ break ;
+ }
+ WM_MsgBox( msg_title, msg_text,
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ return FAILURE ;
+ }
+
+ if ( uService == FS_EMS_MDB_ID ) {
+ serv_hand = OpenService( mach_hand, TEXT("MSExchangeIS"),
+ SERVICE_START | SERVICE_QUERY_STATUS ) ;
+ } else {
+ serv_hand = OpenService( mach_hand, TEXT("MSExchangeDS"),
+ SERVICE_START | SERVICE_QUERY_STATUS ) ;
+ }
+ if ( serv_hand == NULL ) {
+
+ CloseHandle( mach_hand ) ;
+
+ last_error = GetLastError();
+ switch( last_error ) {
+ case ERROR_SERVICE_NOT_FOUND:
+ case ERROR_INVALID_HANDLE:
+ msg_text = ID( IDS_XCHNG_NO_SERVICE ) ;
+ break;
+ case ERROR_ACCESS_DENIED:
+ msg_text = ID( IDS_XCHNG_NO_SERVICE_ACCESS ) ;
+ break ;
+ default:
+ msg_text = ID( IDS_XCHNG_SERVICE_NO_START ) ;
+ break ;
+ }
+ WM_MsgBox( msg_title, msg_text,
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ return FAILURE ;
+ }
+
+ if ( !StartService( serv_hand, 0, NULL ) ) {
+ last_error = GetLastError();
+ switch( last_error ) {
+ case ERROR_SERVICE_ALREADY_RUNNING:
+ msg_text = ID( IDS_XCHNG_SERVICE_RUNNING ) ;
+ break ;
+ case ERROR_ACCESS_DENIED:
+ msg_text = ID( IDS_XCHNG_NO_SERVICE_ACCESS ) ;
+ break ;
+ default:
+ msg_text = ID( IDS_XCHNG_SERVICE_NO_START ) ;
+ break ;
+ }
+ WM_MsgBox( msg_title, msg_text,
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+
+ ret_val = FAILURE ;
+ }
+
+ CloseHandle( serv_hand ) ;
+ CloseHandle( mach_hand ) ;
+
+ return ret_val ;
+
+}
+
+
+#endif OEM_EMS
diff --git a/private/utils/ntbackup/src/d_r_path.c b/private/utils/ntbackup/src/d_r_path.c
new file mode 100644
index 000000000..5d15509d5
--- /dev/null
+++ b/private/utils/ntbackup/src/d_r_path.c
@@ -0,0 +1,240 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: d_r_path.c
+
+ Description: contains dialog proc to specify restore target drive
+
+ $Log: G:/UI/LOGFILES/D_R_PATH.C_V $
+
+ Rev 1.13 11 Jun 1993 14:17:40 MIKEP
+enable c++
+
+ Rev 1.12 01 Nov 1992 15:56:10 DAVEV
+Unicode changes
+
+ Rev 1.11 07 Oct 1992 13:41:36 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.10 04 Oct 1992 19:36:54 DAVEV
+Unicode Awk pass
+
+ Rev 1.9 28 Jul 1992 14:49:14 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.8 14 May 1992 16:40:08 MIKEP
+Nt pass 2
+
+ Rev 1.7 12 May 1992 21:21:16 MIKEP
+NT pass 1
+
+ Rev 1.6 27 Jan 1992 00:30:50 CHUCKB
+Updated dialog id's.
+
+ Rev 1.5 20 Jan 1992 10:02:52 CARLS
+added a call to DM_CenterDialog
+
+ Rev 1.4 10 Jan 1992 09:33:20 ROBG
+Modified HELPIDs.
+
+ Rev 1.3 07 Jan 1992 12:40:26 CHUCKB
+Added help.
+
+ Rev 1.2 16 Dec 1991 11:45:44 CHUCKB
+Added include windows.h.
+
+ Rev 1.1 25 Nov 1991 15:04:48 DAVEV
+Changes for 32-16 bit Windows port
+
+ Rev 1.0 ?? ??? 1991 ??:??:?? ??????
+Initial revision.
+
+
+*****************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+#define DRIVENAME_CALLOC_SIZE 37 //NOTE: this should NOT be hard coded!!!
+
+/****************************************************************************
+
+ Name: DM_GetRestoreDestination
+
+ Description: Entry point for the application to request a
+ restore target drive. That drive may be a
+ server/volume or a mapped drive.
+
+ Modified:
+
+ Returns: A pointer to a DLE.
+
+ Notes:
+
+ See also:
+
+****************************************************************************/
+
+
+PVOID DM_GetRestoreDestination (
+
+LPSTR lpszBackupSetName, // I - Pointer to the backup set name.
+PVOID vlpServerList, // I - Pointer to server list.
+PVOID vlpDriveList ) // I - Pointer to drive list.
+
+{
+ static DS_RESTORE dsRestore ;
+
+ dsRestore.lpszBackupSetName = lpszBackupSetName ;
+ dsRestore.vlpServerList = vlpServerList ;
+ dsRestore.vlpDriveList = vlpDriveList ;
+
+ if ( DM_ShowDialog ( ghWndFrame, IDD_RESTORE, (PVOID) &dsRestore ) == DM_SHOWOK ) {
+
+ return ( dsRestore.dle ) ;
+
+ } else {
+
+ return NULL ;
+ }
+}
+
+/***************************************************
+
+ Name: DM_RestoreTarget ()
+
+ Description: dialog proc to specify restore target drive
+
+ Modified:
+
+ Returns: boolean true if message was processed
+
+ Notes:
+
+ See also: Windows SDK
+
+*****************************************************/
+
+DLGRESULT APIENTRY DM_RestoreTarget (
+
+ HWND hDlg,
+ MSGID msg,
+ MPARAM1 mp1,
+ MPARAM2 mp2 )
+
+{
+ static DS_RESTORE_PTR pdsRestore ;
+ DWORD dResult ;
+ VLM_OBJECT_PTR vlm;
+ VLM_OBJECT_PTR server_vlm;
+ LPSTR lpszDriveName ;
+ BOOL bIsNull = TRUE ;
+ INT nRetCode ;
+ GENERIC_DLE_PTR dle;
+
+ switch ( msg ) {
+
+ case WM_INITDIALOG :
+
+ DM_CenterDialog( hDlg ) ;
+
+ nRetCode = DM_SHOWCANCEL ;
+
+ pdsRestore = (DS_RESTORE_PTR) mp2 ;
+
+ // put the backup set name and list of disk drives in
+
+ SetDlgItemText ( hDlg, IDD_BSETNAME, (pdsRestore->lpszBackupSetName) ) ;
+
+ vlm = VLM_GetFirstVLM( (Q_HEADER_PTR) pdsRestore->vlpDriveList ) ;
+ while ( vlm != NULL ) {
+
+ SendDlgItemMessage ( hDlg, IDD_DRIVELIST, LB_ADDSTRING,
+ (MP1) 0, (MP2) vlm->name ) ;
+ vlm = VLM_GetNextVLM( vlm ) ;
+ }
+
+ server_vlm = VLM_GetFirstVLM( (Q_HEADER_PTR) pdsRestore->vlpServerList );
+ while ( server_vlm != NULL ) {
+
+ vlm = VLM_GetFirstVLM ( &server_vlm->children ) ;
+ while ( vlm != NULL ) {
+
+ SendDlgItemMessage ( hDlg, IDD_DRIVELIST, LB_ADDSTRING,
+ (MP1) 0, (MP2)vlm->name ) ;
+ vlm = VLM_GetNextVLM ( vlm ) ;
+ }
+ server_vlm = VLM_GetNextVLM ( server_vlm ) ;
+ }
+
+ SendDlgItemMessage ( hDlg, IDD_DRIVELIST, LB_SETCURSEL,
+ (MP1) 0, (MP2) 0 ) ;
+
+ lpszDriveName = (LPSTR) calloc ( DRIVENAME_CALLOC_SIZE, sizeof ( CHAR ) ) ;
+ dResult = SendDlgItemMessage ( hDlg, IDD_DRIVELIST, LB_GETCURSEL, 0, (MP2) 0 ) ;
+ SendDlgItemMessage ( hDlg, IDD_DRIVELIST, LB_GETTEXT, (MP1) dResult, (MP2) lpszDriveName ) ;
+ SetDlgItemText ( hDlg, IDD_CURDRIVE, lpszDriveName ) ;
+
+ free ( lpszDriveName ) ;
+
+ return FALSE ;
+
+ case WM_COMMAND :
+
+ switch ( GET_WM_COMMAND_ID ( mp1, mp2 ) ) {
+
+ case IDHELP:
+
+ HM_DialogHelp( HELPID_DIALOGRESTORESET ) ;
+ return( TRUE ) ;
+
+ case IDD_DRIVELIST :
+
+ lpszDriveName = (LPSTR) calloc ( DRIVENAME_CALLOC_SIZE, sizeof ( CHAR ) ) ;
+
+ dResult = SendDlgItemMessage ( hDlg, IDD_DRIVELIST, LB_GETCURSEL, 0, (MP2) 0 ) ;
+ SendDlgItemMessage ( hDlg, IDD_DRIVELIST, LB_GETTEXT, (MP1) dResult, (MP2) lpszDriveName ) ;
+ SetDlgItemText ( hDlg, IDD_CURDRIVE, lpszDriveName ) ;
+
+ free ( lpszDriveName ) ;
+
+ return TRUE ;
+ break;
+
+ case IDOK : {
+
+ BOOL done = FALSE ;
+
+ nRetCode = DM_SHOWOK ;
+
+ // search the VLM list for one with a dle device name that matches the
+ // string in IDD_CURDRIVE and return a pointer to that dle
+
+ lpszDriveName = (LPSTR) calloc ( DRIVENAME_CALLOC_SIZE, sizeof ( CHAR ) ) ;
+
+ GetDlgItemText ( hDlg, IDD_CURDRIVE, lpszDriveName, 50 ) ;
+
+ DLE_FindByName( dle_list, lpszDriveName, (INT16) -1, &dle );
+
+ pdsRestore->dle = (VOID_PTR)dle ;
+ bIsNull = FALSE ;
+
+ free ( lpszDriveName ) ;
+ }
+
+ case IDCANCEL :
+
+ if ( bIsNull ) {
+ pdsRestore->dle = (VOID_PTR) NULL ;
+ }
+ EndDialog ( hDlg, nRetCode ) ;
+ return TRUE ;
+ }
+ break ;
+ }
+ return FALSE ;
+}
diff --git a/private/utils/ntbackup/src/d_t_pswd.c b/private/utils/ntbackup/src/d_t_pswd.c
new file mode 100644
index 000000000..087f5bc69
--- /dev/null
+++ b/private/utils/ntbackup/src/d_t_pswd.c
@@ -0,0 +1,355 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: d_t_pswd.c
+
+ Description: Contains dialog proc and related function for
+ obtaining a password for a tape
+
+ $Log: G:/UI/LOGFILES/D_T_PSWD.C_V $
+
+ Rev 1.31 06 Aug 1993 18:13:48 chrish
+Made fix such that Cayman can read tape secured by Nostradamus under the same
+user logged in.
+
+ Rev 1.30 15 Jul 1993 10:31:20 KEVINS
+Corrected wait cursor problem when user entered wrong password.
+
+ Rev 1.29 28 Jun 1993 15:11:00 KEVINS
+Temporarily disable displaying of wait cursor when displaying password dialog box.
+
+ Rev 1.28 06 Apr 1993 17:37:36 chrish
+Added fix to TestForAlternatePassword routine to skip check
+for YY flag when calling WM_MsgBox routine.
+
+ Rev 1.28 06 Apr 1993 17:34:24 chrish
+
+ Rev 1.27 22 Mar 1993 13:45:08 chrish
+Added detection of gbCurrentOperation flag in TestForAlternatePassword routine.
+
+ Rev 1.26 19 Mar 1993 16:39:44 chrish
+Deleted decrypting password line in dm_gettapepswd routine.
+
+ Rev 1.25 10 Mar 1993 17:22:08 chrish
+Added stuff for CAYMAN NT to detect tapes secured by the Nostradamous backup
+app.
+
+ Rev 1.24 01 Nov 1992 15:57:12 DAVEV
+Unicode changes
+
+ Rev 1.23 07 Oct 1992 13:43:06 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.22 04 Oct 1992 19:37:16 DAVEV
+Unicode Awk pass
+
+ Rev 1.21 14 May 1992 16:40:22 MIKEP
+Nt pass 2
+
+ Rev 1.20 15 Apr 1992 17:38:00 CHUCKB
+Fixed LANStream tape info bug.
+
+
+*****************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+static DS_TAPE_PSWD_PTR pdsPswd ;
+
+#ifdef CAYMAN // chs:03-22-93
+ static BOOL TestForAlternatePassword ( CHAR_PTR, INT16 ); // chs:03-22-93
+#endif // chs:03-22-93
+
+static BOOL TestForAlternatePassword ( CHAR_PTR, INT16 );
+
+/***************************************************
+
+ Name: DM_TapePswd ()
+
+ Description: dialog proc for obtaining a tape password
+
+ Modified: 9-11-91
+
+ Returns: BOOL: TRUE if a valid password was entered;
+ FALSE otherwise
+
+ Notes: called by DM_GetTapePswd
+
+ See also:
+
+*****************************************************/
+
+DLGRESULT APIENTRY DM_TapePswd (
+ HWND hdlg, // I - handle to the dialog
+ MSGID msg, // I - message to be examined
+ MP1 mp1, // I - word parameter of message
+ MP2 mp2 ) // I - long parameter of message
+{
+ CHAR szUserPswd[MAX_TAPE_PASSWORD_SIZE] ;
+
+ switch ( msg ) {
+
+ case WM_INITDIALOG :
+ {
+
+ CHAR szDlgTitle[MAX_UI_WIN_TITLE_SIZE];
+ CHAR szTemp[ MAX_UI_WIN_TITLE_SIZE ] ;
+
+ DM_CenterDialog( hdlg ) ;
+
+ pdsPswd = ( DS_TAPE_PSWD_PTR ) mp2 ;
+ pdsPswd->fValid = FALSE ;
+
+ // set the dialog title
+
+ RSM_StringCopy( IDS_APPMSGNAME, szDlgTitle, MAX_UI_WIN_TITLE_SIZE ) ;
+ RSM_StringCopy( IDS_MSGTITLE_TAPEPSWD, szTemp, MAX_UI_WIN_TITLE_LEN ) ;
+
+ lstrcat( szDlgTitle, TEXT(" ") );
+ lstrcat( szDlgTitle, szTemp );
+
+ SetWindowText( hdlg, szDlgTitle );
+
+ SetDlgItemText ( hdlg, IDD_T_TAPENAME, pdsPswd->lpszTapeName ) ;
+ SetDlgItemText ( hdlg, IDD_T_BSNAME, pdsPswd->lpszBsetName ) ;
+ SetDlgItemText ( hdlg, IDD_T_UNAME, pdsPswd->lpszUserName ) ;
+
+ SendDlgItemMessage( hdlg, IDD_T_PSWD, EM_LIMITTEXT, MAX_TAPE_PASSWORD_LEN, 0 ) ;
+
+ SetFocus( GetDlgItem( hdlg, IDD_T_PSWD ) ) ;
+
+ }
+
+ return TRUE ;
+
+ case WM_COMMAND : {
+
+ INT nRetVal = DM_SHOWCANCEL ;
+
+ switch ( GET_WM_COMMAND_ID ( mp1, mp1) ) {
+
+ case IDHELP:
+
+ HM_DialogHelp( HELPID_DIALOGTAPEPSWD ) ;
+ return( TRUE ) ;
+
+ case IDOK :
+
+ GetDlgItemText ( hdlg, IDD_T_PSWD, szUserPswd, MAX_TAPE_PASSWORD_SIZE ) ;
+
+ if ( !stricmp ( szUserPswd, pdsPswd->lpszTapePswd ) ) {
+
+ pdsPswd->fValid = TRUE ;
+ nRetVal = DM_SHOWOK ;
+ }
+ else { // let him try again
+
+ if ( WM_MsgBox ( ID( IDS_BKUP_PASSWORD_ERROR_TITLE ),
+ ID( IDS_BKUP_PASSWORD_ERROR ),
+ ( WMMB_YESNO | WMMB_NOYYCHECK ),
+ WMMB_ICONQUESTION ) == WMMB_IDYES ) {
+
+ SetDlgItemText ( hdlg, IDD_T_PSWD, TEXT("") ) ;
+ SetFocus ( GetDlgItem ( hdlg, IDD_T_PSWD ) ) ;
+ WM_ShowWaitCursor ( SWC_PAUSE );
+
+ return TRUE ;
+ }
+ }
+
+ // On OK, fall through to cancel case to clean up/end the dialog
+
+ case IDCANCEL :
+
+ EndDialog ( hdlg, nRetVal ) ;
+ return TRUE ;
+ }
+ }
+
+ default :
+
+ return FALSE ;
+ break ;
+ }
+}
+
+/***************************************************
+
+ Name: DM_GetTapePswd
+
+ Description: Entry point for the app to get a tape password;
+ decides if the tape is a LANStream tape or not,
+ and chooses which dialog to display to get the
+ password for that tape. If the tape is a LANStream
+ tape, the user name and backup set name will need
+ to be displayed; if not, don't leave huge and
+ unsightly empty spaces on the screen.
+
+ Modified: 12-10-91
+
+ Returns: BOOL TRUE if the user hit the OK button;
+ FALSE otherwise
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+BOOL DM_GetTapePswd ( LPSTR lpszName, // I - name of the tape
+ LPSTR lpszBset, // I - name of a backup set
+ LPSTR lpszUser, // I - user name for this password
+ LPSTR lpszPswd, // I - the real password for this tape
+ INT16 passwdlength ) // I - length of password
+
+{
+ BOOL fRetVal ;
+ DS_TAPE_PSWD_PTR pdsTapePswd ;
+ INT nFound = FALSE ;
+ CHAR passwdbuffer[2]; // chs: 03-09-93
+
+
+ // allocate and initialize the data structure for the dialog
+
+ pdsTapePswd = (DS_TAPE_PSWD_PTR) calloc ( 1, sizeof ( DS_TAPE_PSWD ) ) ;
+ pdsTapePswd->lpszBsetName = lpszBset ;
+ pdsTapePswd->lpszUserName = lpszUser ;
+ pdsTapePswd->lpszTapeName = lpszName ;
+ pdsTapePswd->lpszTapePswd = lpszPswd ;
+
+ //
+ // Check the first character of the password for that special character
+ // to see if it was backed up by the MicroSoft backup app.
+ //
+
+#ifdef CAYMAN
+ passwdbuffer[0] = *lpszPswd; // chs: 03-10-93
+ passwdbuffer[1] = 0; // chs: 03-10-93
+
+ if ( passwdbuffer[0] == ( CHAR ) NTPASSWORDPREFIX ) {
+ return( TestForAlternatePassword ( lpszPswd, passwdlength ) );
+ }
+#endif
+
+ WM_ShowWaitCursor ( SWC_PAUSE );
+
+ // identify the entry for this dialog in the dialog callback table, then
+ // start the dialog to get the password from the user, and
+ // save the result of his attempt
+
+ if ( lpszBset ) { // this is a LANStream tape
+
+ nFound = DM_ShowDialog ( ghWndFrame, IDD_LANTAPEPSWD, pdsTapePswd ) ;
+
+ } else {
+
+ nFound = DM_ShowDialog ( ghWndFrame, IDD_TAPEPSWD, pdsTapePswd ) ;
+ }
+
+ WM_ShowWaitCursor ( SWC_RESUME );
+
+ fRetVal = ( nFound == DM_SHOWOK ) ;
+
+ // clean up and exit
+
+ free ( pdsTapePswd ) ;
+ return fRetVal ;
+}
+
+
+
+#ifdef CAYMAN
+/***************************************************************************
+
+ Name: TestForAlternatePassword
+
+ Description: The password created by the Nostradamous app. always
+ has a prefix character at the beginning of the tape
+ password. If this encountered we must check for the
+ appropriate tape password.
+
+ Returns: BOOL TRUE - password OK
+ FALSE - Password failed
+
+ Notes:
+
+ See also:
+
+****************************************************************************/
+BOOL TestForAlternatePassword ( CHAR_PTR tapepswd,
+ INT16 passwdlength ) // password length from tape selected
+
+{
+ CHAR passwdbuffer1[MAX_TAPE_PASSWORD_LEN + 1];
+ CHAR passwdbuffer2[MAX_TAPE_PASSWORD_LEN + 1];
+ LPSTR generic_str_ptr;
+ DBLK_PTR vcb_ptr;
+ INT16 currentpswdlength;
+ CHAR buffer[ MAX_UI_RESOURCE_SIZE ];
+ CHAR buffer2[ MAX_UI_RESOURCE_SIZE ];
+
+ switch ( gbCurrentOperation ) {
+
+ case OPERATION_BACKUP:
+
+ if ( DoesUserHaveThisPrivilege( TEXT( "SeBackupPrivilege" ) ) ) {
+ return( TRUE );
+ }
+ break;
+
+ case OPERATION_RESTORE:
+ case OPERATION_CATALOG:
+ if ( DoesUserHaveThisPrivilege( TEXT( "SeRestorePrivilege" ) ) ) {
+ return( TRUE );
+ }
+ break;
+
+ default:
+ return( TRUE );
+ break;
+
+ }
+
+ generic_str_ptr = GetCurrentMachineNameUserName( );
+ currentpswdlength = ( INT16 ) strlen( generic_str_ptr ) + 1;
+
+ passwdbuffer1[0] = ( CHAR ) NTPASSWORDPREFIX;
+ passwdbuffer1[1] = 0;
+ strcat( passwdbuffer1, generic_str_ptr ); // don't forget to add that
+ // special prefix character
+
+ //
+ // If password length is not equal to the length of the machine name
+ // user name, then we know right away that they are no the same
+ //
+
+ if ( passwdlength != currentpswdlength ) {
+ RSM_StringCopy( IDS_GENERAL_TAPE_SECURITY, buffer, sizeof(buffer) );
+ RSM_StringCopy( IDS_TAPE_SECURITY_TITLE, buffer2, sizeof(buffer2) );
+ WM_MsgBox( buffer2, buffer, WMMB_OK | WMMB_NOYYCHECK, WMMB_ICONEXCLAMATION ); // chs:04-06-93
+ return( FALSE ); // lengths are not equalled, thus passwords
+ // are not equalled.
+ }
+
+// chs:08-06-93 CryptPassword( ( INT16 ) ENCRYPT, ENC_ALGOR_3, (INT8_PTR)passwdbuffer1, passwdlength );
+
+ if ( ! memcmp( passwdbuffer1, tapepswd, passwdlength ) ) {
+ return( TRUE ); // match found
+ }
+
+ //
+ // Popup dialog box message if
+ // not a valid user
+ //
+
+ RSM_StringCopy( IDS_GENERAL_TAPE_SECURITY, buffer, sizeof(buffer) );
+ RSM_StringCopy( IDS_TAPE_SECURITY_TITLE, buffer2, sizeof(buffer2) );
+ WM_MsgBox( buffer2, buffer, WMMB_OK | WMMB_NOYYCHECK, WMMB_ICONEXCLAMATION ); // chs:04-06-93
+ return ( FALSE );
+
+}
+#endif
diff --git a/private/utils/ntbackup/src/d_v_path.c b/private/utils/ntbackup/src/d_v_path.c
new file mode 100644
index 000000000..5346c92e2
--- /dev/null
+++ b/private/utils/ntbackup/src/d_v_path.c
@@ -0,0 +1,239 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: d_v_path.c
+
+ Description: contains dialog proc to specify restore target drive
+
+ $Log: G:/UI/LOGFILES/D_V_PATH.C_V $
+
+ Rev 1.14 11 Jun 1993 14:18:22 MIKEP
+enable c++
+
+ Rev 1.13 01 Nov 1992 15:57:38 DAVEV
+Unicode changes
+
+ Rev 1.12 07 Oct 1992 13:41:48 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.11 04 Oct 1992 19:37:20 DAVEV
+Unicode Awk pass
+
+ Rev 1.10 14 Sep 1992 14:26:22 DAVEV
+Transparent Unicode changes (AWK pass and strlen check)
+
+ Rev 1.9 28 Jul 1992 14:43:22 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.8 14 May 1992 16:40:16 MIKEP
+Nt pass 2
+
+ Rev 1.7 12 May 1992 21:20:52 MIKEP
+NT pass 1
+
+ Rev 1.6 27 Jan 1992 00:31:02 CHUCKB
+Updated dialog id's.
+
+ Rev 1.5 20 Jan 1992 13:55:54 CARLS
+added a call to DM_CenterDialog
+
+ Rev 1.4 10 Jan 1992 09:13:44 ROBG
+Modified HELPID.
+
+ Rev 1.3 07 Jan 1992 12:41:02 CHUCKB
+Added help.
+
+ Rev 1.2 16 Dec 1991 11:45:26 CHUCKB
+Added include windows.h.
+
+ Rev 1.1 25 Nov 1991 15:06:24 DAVEV
+Changes for 32-16 bit Windows port
+
+ Rev 1.0 ?? ??? 1991 ??:??:?? ??????
+Initial revision.
+
+*****************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+/****************************************************************************
+
+ Name: DM_GetVerifyDestination
+
+ Description: Entry point for the application to request a
+ verify target drive. That drive may be a
+ server/volume or a mapped drive.
+
+ Modified:
+
+ Returns: A pointer to a DLE.
+
+ Notes:
+
+ See also:
+
+****************************************************************************/
+
+
+PVOID DM_GetVerifyDestination (
+
+LPSTR lpszBackupSetName, // I - Pointer to the backup set name.
+PVOID vlpServerList, // I - Pointer to server list.
+PVOID vlpDriveList ) // I - Pointer to drive list.
+
+{
+ INT16 i = 0;
+ BOOL fFound = FALSE;
+static DS_RESTORE lTemp;
+
+ lTemp.lpszBackupSetName = lpszBackupSetName;
+ lTemp.vlpServerList = vlpServerList;
+ lTemp.vlpDriveList = vlpDriveList;
+
+ if ( DM_ShowDialog ( ghWndFrame, IDD_VERIFY, (PVOID) &lTemp ) == DM_SHOWOK ) {
+
+ return ( lTemp.dle );
+
+ } else {
+
+ return NULL;
+ }
+}
+
+/***************************************************
+
+ Name: DM_VerifyTarget ()
+
+ Description: dialog proc to specify verify target drive
+
+ Modified:
+
+ Returns: boolean true if message was processed
+
+ Notes:
+
+ See also: Windows SDK
+
+*****************************************************/
+
+DLGRESULT APIENTRY DM_VerifyTarget (
+
+ HWND hDlg,
+ MSGID msg,
+ MP1 mp1,
+ MP2 mp2 )
+
+{
+ static DS_RESTORE_PTR pdsRestore;
+ DWORD dResult;
+ VLM_OBJECT_PTR vlm;
+ VLM_OBJECT_PTR server_vlm;
+ LPSTR lpszDriveName;
+ BOOL bIsNull = TRUE;
+ INT nRetCode;
+ GENERIC_DLE_PTR dle;
+
+ switch ( msg ) {
+
+ case WM_INITDIALOG :
+
+ pdsRestore = (DS_RESTORE_PTR) mp2;
+
+ nRetCode = DM_SHOWCANCEL;
+
+ DM_CenterDialog( hDlg );
+
+ // put the backup set name and list of disk drives in
+
+ SetDlgItemText ( hDlg, IDD_BSETNAME, (pdsRestore->lpszBackupSetName) );
+
+ vlm = VLM_GetFirstVLM( (Q_HEADER_PTR) pdsRestore->vlpDriveList );
+ while ( vlm != NULL ) {
+
+ SendDlgItemMessage ( hDlg, IDD_DRIVELIST, LB_ADDSTRING,
+ 0, (MP2)vlm->name );
+ vlm = VLM_GetNextVLM( vlm );
+ }
+
+ server_vlm = VLM_GetFirstVLM( (Q_HEADER_PTR) pdsRestore->vlpServerList );
+ while ( server_vlm != NULL ) {
+
+ vlm = VLM_GetFirstVLM ( &server_vlm->children );
+ while ( vlm != NULL ) {
+
+ SendDlgItemMessage ( hDlg, IDD_DRIVELIST, LB_ADDSTRING,
+ 0, (MP2)vlm->name );
+ vlm = VLM_GetNextVLM ( vlm );
+ }
+ server_vlm = VLM_GetNextVLM ( server_vlm );
+ }
+
+ SendDlgItemMessage ( hDlg, IDD_DRIVELIST, LB_SETCURSEL, 0, (MP2) 0 );
+
+ lpszDriveName = (LPSTR) calloc ( 37, sizeof ( CHAR ) );
+
+ dResult = SendDlgItemMessage ( hDlg, IDD_DRIVELIST, LB_GETCURSEL, 0, (MP2) 0 );
+ SendDlgItemMessage ( hDlg, IDD_DRIVELIST, LB_GETTEXT, (MP1) dResult, (MP2) lpszDriveName );
+ SetDlgItemText ( hDlg, IDD_CURDRIVE, lpszDriveName );
+
+ free ( lpszDriveName );
+
+ return FALSE;
+
+ case WM_COMMAND :
+
+ switch ( GET_WM_COMMAND_ID ( mp1, mp2 ) ) {
+
+ case IDHELP:
+
+ HM_DialogHelp( HELPID_DIALOGVERIFYSET );
+ return( TRUE );
+
+ case IDD_DRIVELIST :
+
+ lpszDriveName = (LPSTR) calloc ( 37, sizeof ( CHAR ) );
+
+ dResult = SendDlgItemMessage ( hDlg, IDD_DRIVELIST, LB_GETCURSEL, 0, (MP2) 0 );
+ SendDlgItemMessage ( hDlg, IDD_DRIVELIST, LB_GETTEXT, (MP1) dResult, (MP2) lpszDriveName );
+ SetDlgItemText ( hDlg, IDD_CURDRIVE, lpszDriveName );
+
+ free ( lpszDriveName );
+
+ return TRUE;
+ break;
+
+ case IDOK : {
+
+ BOOL done = FALSE;
+
+ nRetCode = DM_SHOWOK;
+
+ // search the VLM list for one with a dle device name that matches the
+ // string in IDD_CURDRIVE and return a pointer to that dle
+
+ lpszDriveName = (LPSTR) calloc ( 37, sizeof ( CHAR ) );
+
+ GetDlgItemText ( hDlg, IDD_CURDRIVE, lpszDriveName, 50 );
+ DLE_FindByName( dle_list, lpszDriveName, (INT16) -1, &dle );
+ pdsRestore->dle = (VOID_PTR)dle;
+ bIsNull = FALSE;
+
+ free ( lpszDriveName );
+ }
+
+ case IDCANCEL :
+
+ if ( bIsNull ) pdsRestore->dle = (VOID_PTR) NULL;
+
+ EndDialog ( hDlg, nRetCode );
+ return TRUE;
+ }
+ break;
+ }
+ return FALSE;
+}
diff --git a/private/utils/ntbackup/src/datetime.c b/private/utils/ntbackup/src/datetime.c
new file mode 100644
index 000000000..7041acef1
--- /dev/null
+++ b/private/utils/ntbackup/src/datetime.c
@@ -0,0 +1,383 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: datetime.c
+
+ Description: This file contains date time utilities.
+
+
+ $Log: M:/LOGFILES/DATETIME.C_V $
+
+ Rev 1.9 21 Jul 1993 16:08:46 BARRY
+Check for NULL return from localtime; use Win32 API for on NT in GetCurrentDate
+
+ Rev 1.8 17 Jun 1993 17:49:26 MIKEP
+C++ enable
+
+ Rev 1.7 11 Nov 1992 22:27:28 GREGG
+Removed string to date and date to string functions which are no longer used.
+
+ Rev 1.6 18 Aug 1992 09:52:54 BURT
+fix warnings
+
+ Rev 1.5 14 May 1992 12:53:20 TIMN
+msassert for dead functions, StringToDateTime CurrentDateTimetoString remove later
+
+ Rev 1.4 17 Jan 1992 17:20:56 STEVEN
+fix warnings for WIN32
+
+ Rev 1.3 06 Jan 1992 09:07:34 STEVEN
+if a date is invalid then they compare to equal
+
+ Rev 1.2 26 Jul 1991 16:14:42 STEVEN
+remove bios_time_of_day
+
+ Rev 1.1 23 Jul 1991 16:34:40 DAVIDH
+Removed warnings found by Watcom compiler.
+
+ Rev 1.0 09 May 1991 13:34:54 HUNTER
+Initial revision.
+
+**/
+#include <time.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dos.h>
+
+#if defined( OS_WIN32 )
+#include <windows.h>
+#endif
+
+#include "stdtypes.h"
+#include "datetime.h"
+#include "msassert.h"
+#include "stdmacro.h"
+
+/**/
+/**
+
+ Name: GetCurrentDate()
+
+ Description: This function gets the current date and time
+ and places it in the provided DATETIME structure.
+
+ Modified: 8/23/1989
+
+ Returns: none
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID GetCurrentDate( DATE_TIME_PTR date_time )
+{
+#if !defined( OS_WIN32 )
+ time_t ztime ;
+ struct tm *ltime;
+
+ time( &ztime ) ;
+
+ ltime = localtime( &ztime ) ;
+ if ( ltime != NULL )
+ {
+ date_time->year = (INT16)(1900 + ltime->tm_year) ;
+ date_time->month = (INT16)(ltime->tm_mon + 1 );
+ date_time->day = (INT16)(ltime->tm_mday) ;
+ date_time->hour = (INT16)(ltime->tm_hour) ;
+ date_time->minute = (INT16)(ltime->tm_min) ;
+ date_time->second = (INT16)(ltime->tm_sec) ;
+ date_time->day_of_week = (INT16)(ltime->tm_wday + 1) ;
+ date_time->date_valid = (BOOLEAN)TRUE ;
+ }
+ else
+ {
+ /*
+ * localtime() was confused by current date and time.
+ * We'll take the cheap way out and call the date 1/1/80.
+ */
+ date_time->year = 1980;
+ date_time->month = 1;
+ date_time->day = 1;
+ date_time->hour = 0;
+ date_time->minute = 0;
+ date_time->second = 0;
+ date_time->day_of_week = 3; /* 1/1/80 was a Tuesday */
+ date_time->date_valid = TRUE ;
+ }
+#else /* !defined( OS_WIN32 ) */
+
+ SYSTEMTIME localTime;
+
+ GetLocalTime( &localTime ); /* No error return */
+
+ date_time->year = (INT16)localTime.wYear;
+ date_time->month = (INT16)localTime.wMonth;
+ date_time->day = (INT16)localTime.wDay;
+ date_time->hour = (INT16)localTime.wHour;
+ date_time->minute = (INT16)localTime.wMinute;
+ date_time->second = (INT16)localTime.wSecond;
+ date_time->day_of_week = (INT16)(localTime.wDayOfWeek + 1);
+ date_time->date_valid = (BOOLEAN)TRUE ;
+
+#endif
+}
+
+
+
+/**/
+/**
+
+ Name: DOSDateTime()
+
+ Description: This function converts a DATETIME structure to DOS's
+ DTA date and time structures.
+
+ Modified: 8/23/1989
+
+ Returns: none
+
+ Notes: added -1980, ccs
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID DOSDateTime( DATE_TIME_PTR date_time, UINT16_PTR date, UINT16_PTR time )
+{
+ msassert( date != NULL );
+ msassert( time != NULL );
+
+ * date = (UINT16)(((date_time->year-1980) << 9) |
+ (date_time->month << 5) |
+ date_time->day);
+
+ * time = (UINT16)((date_time->hour << 11) |
+ (date_time->minute << 5) |
+ (date_time->second >> 1) ) ;
+}
+
+
+
+/**/
+/**
+
+ Name: datecmp()
+
+ Description: This function compares two DATE_TIME structures and returns:
+
+ zero if they are the same
+ < 0 if date_time1 < date_time2
+ > 0 if date_time1 > date_time2
+
+ Modified: 8/23/1989
+
+ Returns: none
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT32 datecmp(
+DATE_TIME_PTR dt1,
+DATE_TIME_PTR dt2 )
+{
+ INT32 diff;
+
+ diff = ( ( (INT32) dt1->year << 12) | (dt1->month << 8) | dt1->day ) -
+ ( ( (INT32) dt2->year << 12) | (dt2->month << 8) | dt2->day ) ;
+
+ if ( diff == 0 ) {
+ diff = ( ( (INT32) dt1->hour << 16) | (dt1->minute << 8) | dt1->second ) -
+ ( ( (INT32) dt2->hour << 16) | (dt2->minute << 8) | dt2->second ) ;
+ }
+
+ return diff ;
+}
+
+
+
+/**/
+/**
+
+ Name: ConvertDateDOS()
+
+ Description: Converts a DATE_TIME structure date into
+ a DOS style date.
+
+ Modified: 9/12/1989
+
+ Returns: DOS format DATE
+
+ Notes:
+
+ See also: $/SEE( ConvertTimeDOS() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+UINT16 ConvertDateDOS( DATE_TIME_PTR date )
+{
+ UINT16 ret_val ;
+
+ if (date->date_valid) {
+
+ ret_val = (UINT16)((date->year - 1980) << 9) ;
+ ret_val |= (UINT16)(date->month << 5) ;
+ ret_val |= date->day ;
+
+ } else {
+
+ ret_val = (1 << 5) | 1 ;
+ }
+
+ return ret_val ;
+}
+/**/
+/**
+
+ Name: ConvertTimeDOS
+
+ Description: Converts a DATE_TIME structure time into a
+ DOS style time.
+
+ Modified: 9/12/1989
+
+ Returns: DOS format Time
+
+ Notes:
+
+ See also: $/SEE( ConvertDateDOS() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+UINT16 ConvertTimeDOS( DATE_TIME_PTR date )
+{
+ UINT16 ret_val ;
+
+ if (date->date_valid) {
+
+ ret_val = date->hour << 11 ;
+ ret_val |= date->minute << 5 ;
+ ret_val |= date->second >> 1 ;
+
+ } else {
+
+ ret_val = 0;
+ }
+
+ return ret_val ;
+}
+
+
+
+
+
+
+
+/**/
+/**
+
+ Name: DateTimeDOS()
+
+ Description:
+ Convert DOS date to DATE_TIME structure.
+
+ Modified: 9/21/1989
+
+ Returns:
+
+ Notes:
+ The DATE_TIME.day_of_week field is not calculated.
+
+ See also: $/SEE( DOSDateTime() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+
+VOID DateTimeDOS(
+ UINT16 DOS_date,
+ UINT16 DOS_time,
+ DATE_TIME_PTR date_time )
+
+{
+ date_time -> year = (INT16)(( DOS_date >> 9 ) + 1980) ;
+ date_time -> month = (INT16)(( DOS_date >> 5 ) & 0x000f) ;
+ date_time -> day = (INT16)(DOS_date & 0x001f) ;
+
+ date_time -> hour = (INT16)(DOS_time >> 11) ;
+ date_time -> minute = (INT16)(( DOS_time >> 5 ) & 0x003f) ;
+ date_time -> second = (INT16)(( DOS_time & 0x001f ) << 1) ;
+
+ date_time -> day_of_week = 0 ;
+ date_time -> date_valid = TRUE ;
+}
+
+
+/**/
+/**
+
+ Name: CompDate()
+
+ Description: This function compares two date.
+
+ Modified: 2/7/1990
+
+ Returns: simular to strcmp. i.e ret_val = d1 - d2
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 CompDate( DATE_TIME_PTR d1, DATE_TIME_PTR d2 )
+{
+ INT16 ret_val = 0 ;
+
+ if ( !d1->date_valid || !d2->date_valid ) {
+ ret_val = 0 ;
+
+ } else {
+
+ ret_val = d1->year - d2->year ;
+
+ if ( !ret_val ) {
+ ret_val = d1->month - d2->month ;
+ }
+ if ( !ret_val ) {
+ ret_val = d1->day - d2->day ;
+ }
+ if ( !ret_val ) {
+ ret_val = d1->hour - d2->hour ;
+ }
+ if ( !ret_val ) {
+ ret_val = d1->minute - d2->minute ;
+ }
+ if ( !ret_val ) {
+ ret_val = d1->second - d2->second ;
+ }
+ }
+
+ return ret_val;
+}
+
+
diff --git a/private/utils/ntbackup/src/dateutil.c b/private/utils/ntbackup/src/dateutil.c
new file mode 100644
index 000000000..40a80ea0b
--- /dev/null
+++ b/private/utils/ntbackup/src/dateutil.c
@@ -0,0 +1,506 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: dateutil.c
+
+ Description:
+
+ $Log: G:/UI/LOGFILES/DATEUTIL.C_V $
+
+ Rev 1.5 07 Oct 1992 14:51:12 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.4 04 Oct 1992 19:32:28 DAVEV
+Unicode Awk pass
+
+ Rev 1.3 17 Aug 1992 13:03:48 DAVEV
+MikeP's changes at Microsoft
+
+ Rev 1.2 18 May 1992 09:06:46 MIKEP
+header
+
+ Rev 1.1 19 Dec 1991 17:42:00 DAVEV
+16/32 bit port - 2nd pass
+
+ Rev 1.0 20 Nov 1991 19:26:14 SYSTEM
+Initial revision.
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+/*****************************************************************************
+
+ Name: DU_IsLeapYear()
+
+ Description: This routine accepts a year and determines if it is a leap year.
+
+*****************************************************************************/
+BOOLEAN DU_IsLeapYear( INT16 year )
+{
+ BOOLEAN leap_year = FALSE ;
+
+ if ( ! ( year % 100 )) {
+ if ( ! ( year % 400 )) { /* if the year is the turn of the century and it is */
+ /* is divisible by 400 then it is a leap year. */
+ leap_year = TRUE ;
+ }
+ }
+ else if ( ! ( year % 4 )) { /* if not divisible by 100 then is it divisible by 4 */
+ leap_year = TRUE ;
+ }
+ return ( leap_year ) ;
+}
+/*****************************************************************************
+
+ Name: DU_TmToDateTime()
+
+ Description: This routine will accept a tm structure and build the DATE_TIME structure.
+
+ Returns: SUCCESS / FAILURE
+
+*****************************************************************************/
+INT16 DU_TmToDateTime(
+struct tm *ms_date_ptr , /* I - structure to be used to fill the new structure */
+DATE_TIME_PTR start_date ) /* IO - structure to receive the new date */
+{
+ INT16 ret_val = FAILURE ;
+
+ if ( ms_date_ptr != NULL ) {
+ ret_val = SUCCESS ;
+ start_date->date_valid = TRUE ;
+ start_date->second = ( UINT16 ) ms_date_ptr->tm_sec ;
+ start_date->minute = ( UINT16 ) ms_date_ptr->tm_min ;
+ start_date->hour = ( UINT16 ) ms_date_ptr->tm_hour ;
+ start_date->day_of_week = ( UINT16 ) (ms_date_ptr->tm_wday + 1);
+ start_date->day = ( UINT16 ) ms_date_ptr->tm_mday ;
+ start_date->month = ( UINT16 ) (ms_date_ptr->tm_mon + 1);
+ start_date->year = ( UINT16 ) ms_date_ptr->tm_year ;
+ }
+ return ( ret_val ) ;
+}
+/*****************************************************************************
+
+ Name: DU_DateTimeToTm()
+
+ Description: This routine will accept the DATE_TIME structure and build a tm structure.
+
+ Returns: SUCCESS / FAILURE
+
+*****************************************************************************/
+INT16 DU_DateTimeToTm(
+struct tm *ms_date_ptr , /* IO - structure to receive the new date */
+DATE_TIME_PTR start_date ) /* I - structure to be used to fill the new structure */
+{
+ INT16 ret_val = FAILURE ;
+ INT32 rc ;
+
+ memset( ms_date_ptr, 0 , sizeof( struct tm ) );
+ ms_date_ptr->tm_sec = ( int ) start_date->second ;
+ ms_date_ptr->tm_min = ( int ) start_date->minute ;
+ ms_date_ptr->tm_hour = ( int ) start_date->hour ;
+ ms_date_ptr->tm_wday = ( int ) start_date->day_of_week -1 ;
+ ms_date_ptr->tm_mday = ( int ) start_date->day ;
+ ms_date_ptr->tm_mon = ( int ) start_date->month - 1 ;
+ ms_date_ptr->tm_year = ( int ) start_date->year ;
+ rc = mktime( ms_date_ptr ) ;
+ if ( rc != -1 ) {
+ ret_val = SUCCESS ;
+ }
+ return ( ret_val ) ;
+}
+/*****************************************************************************
+
+ Name: DU_DateTimeToTime_T()
+
+ Description: This routine takes a pointer to a structure of type DATE_TIME
+ and converts it to the number of seconds passed since 00:00:00
+ Jan 1, 1970 (GMT) and assigns that value to the time_t pointer.
+
+ Notes: MS-DOS does not understand dates prior to Jan 1, 1980.
+
+ Returns: SUCCESS / FAILURE
+
+*****************************************************************************/
+INT16 DU_DateTimeToTime_T(
+time_t *timet , /* O - returns the converted value of date_time struct */
+DATE_TIME_PTR datetime ) /* I - contains the value to be converted */
+{
+ struct tm temptime ;
+ INT16 ret_val = FAILURE ;
+ INT32 rc ;
+
+
+ if ( !( rc= DU_DateTimeToTm( &temptime, datetime ))) {
+ if ( ( *timet = mktime( &temptime )) != -1 ) {
+ ret_val = SUCCESS ;
+ }
+ }
+ return ( ret_val ) ;
+}
+/*****************************************************************************
+
+ Name: DU_Time_TToDateTime()
+
+ Description: This routine takes a time_t pointer which contains a date and time
+ represented as the number of seconds passed since 00:00:00 Jan 1, 1970 (GMT),
+ and converts it to a structure of type DATE_TIME pointed to by datetime.
+ .
+ Notes: MS-DOS does not understand dates prior to Jan 1, 1980.
+
+ Returns: SUCCESS / FAILURE
+
+*****************************************************************************/
+INT16 DU_Time_TToDateTime(
+time_t *timet , /* O - returns the converted value of date_time struct */
+DATE_TIME_PTR datetime ) /* I - contains the value to be converted */
+{
+ struct tm *temptime_ptr ;
+ INT16 ret_val = FAILURE ;
+ INT16 rc ;
+
+ if ( ( temptime_ptr = localtime( timet )) != NULL ) {
+
+ if ( !( rc= DU_TmToDateTime( temptime_ptr, datetime ))) {
+ ret_val = SUCCESS ;
+ }
+ }
+ return ( ret_val ) ;
+
+}
+/*****************************************************************************
+
+ Name: DU_CalcTargetDateBackwd()
+
+ Description: This routine when passed a date_time structure by reference, and the
+ number of days to go back, it will accordingly update the date_time
+ Notes: structure.
+
+ Returns: SUCCESS / FAILURE
+
+*****************************************************************************/
+INT16 DU_CalcTargetDateBackwd(
+DATE_TIME_PTR start_date , /* IO - DATE_TIME structure containing start date, updated to target date */
+INT16 days_to_go_back ) /* I - integer containing number of days to go back (to calc target date) */
+{
+
+ struct tm ms_date ;
+ INT16 j_date ;
+ INT16 ret_val = FAILURE ;
+ INT16 year ;
+ INT16 rc ;
+ BOOLEAN leap_year ;
+
+
+/*
+** convert the target date to the standard day of the year ( i.e. the 232 nd day of the year )
+*/
+ if ( !( rc= DU_DateTimeToTm( &ms_date, start_date ))) {
+
+ j_date = (INT16) ms_date.tm_yday ;
+ year = start_date->year ;
+ leap_year = DU_IsLeapYear( year ) ;
+ j_date -= days_to_go_back;
+
+
+/*
+** while ( the new julian date > days in the year )
+*/
+
+ while ( j_date < 1 ) {
+
+/*
+** subtract 1 from the year
+*/
+
+ year--;
+ leap_year = DU_IsLeapYear( year ) ;
+
+/*
+** j_date += days in year
+*/
+
+ j_date += ( leap_year ? 366 : 365 ) ;
+
+
+ } /* while */
+
+
+
+ if ( !( rc= DU_JulianToDateTime( j_date, year, start_date ))) {
+ ret_val = SUCCESS ;
+ }
+
+/*
+** end if
+*/
+
+ }
+
+
+
+ return ( ret_val ) ;
+/*
+** end
+*/
+
+
+}
+/*****************************************************************************
+
+ Name: DU_CalcTargetDateFwd()
+
+ Description: This routine when passed a date_time structure by reference, and the
+ number of days to go forward, it will accordingly update the date_time
+ Notes: structure.
+
+ Returns: SUCCESS / FAILURE
+
+*****************************************************************************/
+INT16 DU_CalcTargetDateFwd(
+DATE_TIME_PTR start_date , // IO - DATE_TIME structure containing start date, updated to target date
+INT16 days_to_go_fwd ) // I - integer containing number of days to go fwd (to calc target date)
+{
+
+ struct tm ms_date ;
+ INT16 j_date ;
+ INT16 ret_val = FAILURE ;
+ INT16 year ;
+ INT16 rc ;
+ BOOLEAN leap_year ;
+
+/*
+** convert the target date to the standard day of the year ( i.e. the 232 nd day of the year )
+*/
+ if ( !( rc= DU_DateTimeToTm( &ms_date, start_date ))) {
+
+ j_date = (INT16) ms_date.tm_yday ;
+ year = start_date->year ;
+ leap_year = DU_IsLeapYear( year ) ;
+ j_date += days_to_go_fwd;
+
+
+/*
+** while ( the new julian date > days in the year )
+*/
+
+ while ( j_date > (INT16) ( leap_year ? 366 : 365 )) {
+
+/*
+** j_date -= days in year
+*/
+
+ j_date -= ( leap_year ? 366 : 365 ) ;
+
+/*
+** add 1 to the year
+*/
+
+ year++ ;
+ leap_year = DU_IsLeapYear( year ) ;
+
+ } /* while */
+
+
+
+ if ( !( rc= DU_JulianToDateTime( j_date, year, start_date ))) {
+ ret_val = SUCCESS ;
+ }
+
+/*
+** end if
+*/
+
+ }
+
+
+
+ return ( ret_val ) ;
+/*
+** end
+*/
+
+}
+/*****************************************************************************
+
+ Name: DU_JuliantoDateTime()
+
+ Description: This routine takes a julian date [0-365] and a year and updates
+ the DATE_TIME structure.
+
+ Returns: SUCCESS / FAILURE
+
+*****************************************************************************/
+INT16 DU_JulianToDateTime(
+INT16 j_date , /* I - contains the julian date */
+INT16 year , /* I - contains the current year */
+DATE_TIME_PTR dt ) /* O - the DATE_TIME structue to be updated */
+{
+ INT8 x ;
+ INT16 ret_val = FAILURE ;
+ struct tm temp_tm;
+ time_t tt;
+ /* J F M A M J J A S O N D */
+ static INT8 month_list[12] = {31,28,31,30,31,30,31,31,30,31,30,31} ;
+
+ if ( dt->hour > 23) {
+ dt->hour = 0;
+ }
+ if ( dt->minute > 59) {
+ dt->minute = 0;
+ }
+ if ( dt->second > 59) {
+ dt->second = 0;
+ }
+
+ if ( j_date <= 366 ) {
+ ret_val = SUCCESS ;
+
+ if ( DU_IsLeapYear( year ) ) {
+ month_list [1] = 29 ; /* if leap year, the second month (February) has 29 days */
+ }
+ for ( x=0 ; x<12 ; x++ ) {
+ if ( ( j_date - month_list [x] ) < 0 ) {
+ break ;
+ }
+ else {
+ j_date -= month_list [x] ;
+ }
+ } /* for */
+
+ dt->date_valid = TRUE ;
+ dt->year = year ;
+ dt->day = (UINT16) (j_date + 1);
+ dt->month = (UINT16) (x + 1);
+
+ DU_DateTimeToTm( &temp_tm, dt );
+
+ tt = mktime( &temp_tm );
+
+ DU_Time_TToDateTime( &tt, dt );
+
+ } /* if */
+ else {
+ dt->date_valid = FALSE ;
+ }
+ return( ret_val ) ;
+}
+/*****************************************************************************
+
+ Name: DU_CalcNumDaysFromToday()
+
+ Description: The given DATE_TIME structure is converted into a time_t
+ value. Then the current time_t is read from the system
+ clock. This routine will then calculate the difference
+ in days between the current date and the given date.
+
+ Notes: This routine will return FAILURE if the given date occurs
+ sometime in the future from the current date.
+
+ Returns: SUCCESS, FAILURE.
+
+*****************************************************************************/
+INT16 DU_CalcNumDaysFromToday(
+DATE_TIME date_time , /* I - date time to be subtracted from today's date */
+INT16_PTR days_from_today ) /* O - difference in days from given date and today's date */
+{
+ INT16 ret = FAILURE ;
+ DATE_TIME current_dt ;
+ time_t todays_time_t, tmp_time_t ;
+ INT32 seconds ;
+/*
+** Get today's date and time from the system clock and subtract 1900 from
+** the number of years.
+*/
+ GetCurrentDate( &current_dt ) ;
+ current_dt.year -= 1900 ;
+/*
+** make sure that both date_time structures are valid
+*/
+ if( date_time.date_valid && current_dt.date_valid ) {
+/*
+** get the time_t values for both DATE_TIME stuctures
+*/
+ if( DU_DateTimeToTime_T( &todays_time_t, &current_dt ) ) {
+ return FAILURE ;
+ } else {
+ if( DU_DateTimeToTime_T( &tmp_time_t, &date_time ) ) {
+ return FAILURE ;
+ }
+ }
+/*
+** calculate the number of days in the difference
+*/
+ seconds = ( INT32 ) ( todays_time_t - tmp_time_t ) ;
+ if( seconds > -1 ) {
+
+ /* 60 seconds/minute and 60 minutes/hour and 24 hours/day
+ thus 60*60*24 = the number of seconds/day or 86400 */
+ *days_from_today = (INT16 ) ((INT32 )seconds / 86400L ) ;
+ ret = SUCCESS ;
+ }
+ }
+/*
+** return SUCCESS/FAILURE
+*/
+ return ret ;
+}
+/*****************************************************************************
+
+ Name: DU_CalcNumberDaysBackwd()
+
+ Description: This routine when passed a date_time structure by reference, will calculate the
+ number of days that date is back from the current date. It will not update the
+ date_time structure at all.
+
+ Returns: SUCCESS / FAILURE
+
+*****************************************************************************/
+INT16 DU_CalcNumberDaysBackwd(
+DATE_TIME_PTR input_date , /* I - DATE_TIME structure containing input date */
+INT16_PTR days_back_ptr ) /* O - integer containing number of days back (from input date) */
+{
+ time_t input_timet ;
+ time_t today_timet ;
+ INT32 difference ;
+ INT16 ret_val = FAILURE ;
+
+ if( input_date->date_valid ) { ;
+
+/*
+** convert the input date to t_time
+*/
+ DU_DateTimeToTime_T( &input_timet, input_date ) ;
+
+/*
+** convert today's date to t_time
+*/
+ time( &today_timet ) ;
+
+/*
+** calculate the difference
+*/
+ difference = ( INT32 )( today_timet - input_timet ) ;
+
+/*
+** convert the difference to a number of days
+*/
+ *days_back_ptr = ( INT16 )( difference / 86400L ) ;
+
+ ret_val = SUCCESS ;
+
+ }
+
+ return ( ret_val ) ;
+
+
+/*
+** end
+*/
+
+
+}
diff --git a/private/utils/ntbackup/src/dblksize.c b/private/utils/ntbackup/src/dblksize.c
new file mode 100644
index 000000000..12d0e0b9f
--- /dev/null
+++ b/private/utils/ntbackup/src/dblksize.c
@@ -0,0 +1,89 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: dblksize.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains code to determine the size of a DBLK
+
+
+ $Log: T:/LOGFILES/DBLKSIZE.C_V $
+
+ Rev 1.3 26 Oct 1993 21:07:16 GREGG
+Got rid of problematic VCB actual size calculation since no one cares what
+the "actual" size is (or even calls this function any more). It's a
+leftover from DOS days when memory was in short supply. If anyone does
+decide to call it again, be aware that it returns sizeof( DBLK ) for VCBs.
+
+ Rev 1.2 11 Aug 1993 15:07:28 DON
+Someone forgot to add the dev_name_leng to the size of the VCB!
+
+ Rev 1.1 18 Jun 1993 09:29:50 MIKEP
+enable C++
+
+ Rev 1.0 09 May 1991 13:34:58 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include "stdtypes.h"
+#include "msassert.h"
+
+#include "fsys.h"
+/* $end$ include list */
+/**/
+/**
+
+ Name: FS_GetActualSizeDBLK()
+
+ Description: This function returns the actual size of a DBLK
+
+ Modified: 11/1/1989
+
+ Returns: the size ;
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+UINT16 FS_GetActualSizeDBLK(
+FSYS_HAND fsh , /* I - File system handle */
+DBLK_PTR dblk ) /* I - block to get size from */
+{
+ UINT16 size ;
+
+ switch( dblk->blk_type ) {
+
+ case UDB_ID:
+ case VCB_ID:
+ size = sizeof( DBLK ) ;
+ break ;
+
+ case DDB_ID:
+ case FDB_ID:
+ case IDB_ID:
+ size = fsh->tab_ptr->GetActualSizeDBLK( fsh, dblk ) ;
+ break ;
+
+ case CFDB_ID:
+ size = sizeof( CFDB ) ;
+ break ;
+
+ default :
+ msassert( FALSE ) ;
+ size = sizeof( DBLK ) ;
+ break ;
+
+ }
+
+ return size ;
+}
+
+
+
diff --git a/private/utils/ntbackup/src/ddeproc.c b/private/utils/ntbackup/src/ddeproc.c
new file mode 100644
index 000000000..97b9fec72
--- /dev/null
+++ b/private/utils/ntbackup/src/ddeproc.c
@@ -0,0 +1,142 @@
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+RCG
+
+ Name: ddeproc.c
+
+ Description: This file contains the functions for processing messages
+ sent by Windows to a DDE Client windows.
+
+ The following routines are in this module:
+
+ WM_DDEClientWndProc
+
+ $Log: G:/UI/LOGFILES/DDEPROC.C_V $
+
+ Rev 1.9 07 Oct 1992 15:11:50 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.8 04 Oct 1992 19:32:30 DAVEV
+Unicode Awk pass
+
+ Rev 1.7 07 Jul 1992 15:52:54 MIKEP
+unicode changes
+
+ Rev 1.6 29 May 1992 15:59:30 JOHNWT
+PCH updates
+
+ Rev 1.5 29 Jan 1992 18:13:18 DAVEV
+fixed mistake
+
+ Rev 1.4 29 Jan 1992 18:00:20 DAVEV
+
+
+ * No changes
+
+ Rev 1.3 19 Dec 1991 15:24:58 GLENN
+Added windows.h
+
+ Rev 1.2 12 Dec 1991 17:09:34 DAVEV
+16/32 bit port -2nd pass
+
+ Rev 1.1 02 Dec 1991 17:48:28 DAVEV
+16/32 bit Windows port changes
+
+ Rev 1.0 20 Nov 1991 19:27:22 SYSTEM
+Initial revision.
+
+**************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+/****************************************************************************
+
+ Name: WM_DDEClientWndProc
+
+ Description: This function will handle the DDE processing
+ to and from the Program Manager
+
+ Modified: 8/02/1991
+
+ Returns: none
+
+ Notes: The DDEACK structure is defined as follows:
+
+ See also: d_j_prog.c
+
+****************************************************************************/
+
+BOOL mwbInInitiate ; // All there are used in d_j_prog.c
+HANDLE mwhWndServerDDE ;
+LPSTR mwszProgMan ;
+
+WINRESULT APIENTRY WM_DDEClientWndProc(
+
+ HWND hWnd, // I - Handle to window
+ MSGID message, // I - Message
+ MP1 mp1, // I - Additional Information
+ MP2 mp2 ) // I - Additional Information
+{
+
+ HWND hWndClientDDE ;
+ HWND hWndServerDDE ;
+ LPSTR pszAtom ;
+ LPSTR pszApplication ;
+
+ hWndClientDDE = hWnd ;
+
+ switch (message) {
+
+ case WM_DDE_ACK:
+ // Processing from a WM_DDE_INITIATE
+
+ hWndServerDDE = GET_WM_DDE_ACK_HWND ( mp1, mp2 );
+
+ if ( mwbInInitiate ) {
+
+ // Verify that the atom names are correct.
+
+ // mwhWndServerDDE will be checked by function
+ // 'AddJobToProgManWindow'.
+
+ pszAtom = (LPSTR) calloc ( 256, sizeof ( CHAR ) ) ;
+ pszApplication = (LPSTR) calloc ( 256, sizeof ( CHAR ) ) ;
+
+ GlobalGetAtomName( GET_WM_DDE_ACK_APPL( mp1, mp2 ),
+ pszApplication, 255 ) ;
+ GlobalGetAtomName( GET_WM_DDE_ACK_TOPIC ( mp1, mp2 ),
+ pszAtom, 255 ) ;
+
+ if ( ( strcmpi( pszAtom, mwszProgMan ) == 0 ) &&
+ ( strcmpi( pszApplication, mwszProgMan) == 0 ) ) {
+ mwhWndServerDDE = hWndServerDDE ;
+ }
+ }
+
+ return (0L);
+ break ;
+
+ case WM_DDE_TERMINATE:
+
+ hWndServerDDE = (HWND) mp1;
+
+ // Server has requested terminate: respond with a terminate
+ // when hWndClientDDE exists.
+
+ if ( IsWindow( hWndClientDDE ) ) {
+ PostMessage( hWndServerDDE, WM_DDE_TERMINATE, (MP1)hWndClientDDE, (MP2)0 ) ;
+ }
+
+ return (0L);
+ break ;
+
+ default:
+ return (DefWindowProc(hWnd, message, mp1, mp2 ) );
+ }
+}
+
+
diff --git a/private/utils/ntbackup/src/debug.c b/private/utils/ntbackup/src/debug.c
new file mode 100644
index 000000000..2e1b09458
--- /dev/null
+++ b/private/utils/ntbackup/src/debug.c
@@ -0,0 +1,754 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: debug.c
+
+ Description: This file contains the functions for the GUI Debug
+ Manager (DBM). The functions handle displaying the debug
+ window. The Debug Manager uses the Display List Manager
+ to list and display the debug messages.
+
+ $Log: G:/UI/LOGFILES/DEBUG.C_V $
+
+ Rev 1.23 11 Jun 1993 14:19:14 MIKEP
+enable c++
+
+ Rev 1.22 06 Jan 1993 10:18:58 GLENN
+Miscellaneous window validations.
+
+ Rev 1.21 14 Dec 1992 12:17:38 DAVEV
+Enabled for Unicode compile
+
+ Rev 1.20 11 Nov 1992 16:29:44 DAVEV
+UNICODE: remove compile warnings
+
+ Rev 1.19 05 Nov 1992 16:56:34 DAVEV
+fix ts
+
+ Rev 1.18 01 Nov 1992 15:44:52 DAVEV
+Unicode changes
+
+ Rev 1.17 30 Oct 1992 15:46:36 GLENN
+Added Frame and MDI Doc window size and position saving and restoring.
+
+ Rev 1.16 14 Oct 1992 15:50:22 GLENN
+Added /ZL debug logging command line support.
+
+ Rev 1.15 07 Oct 1992 15:09:30 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.14 04 Oct 1992 19:32:32 DAVEV
+Unicode Awk pass
+
+ Rev 1.13 28 Jul 1992 14:41:46 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.12 19 May 1992 11:58:40 MIKEP
+mips changes
+
+ Rev 1.11 15 May 1992 13:35:40 MIKEP
+nt pass 2
+
+ Rev 1.10 01 Apr 1992 14:37:10 ROBG
+Fixed problem with resetting the debug window.
+
+ Rev 1.9 30 Mar 1992 11:12:58 MIKEP
+change debug log to append
+
+ Rev 1.8 20 Mar 1992 14:48:32 GLENN
+Fixed debug to file problems.
+
+ Rev 1.7 19 Mar 1992 09:30:00 MIKEP
+debug to file
+
+ Rev 1.6 11 Feb 1992 17:26:24 GLENN
+Removed multitask call.
+
+ Rev 1.5 27 Jan 1992 00:30:24 CHUCKB
+Updated dialog id's.
+
+ Rev 1.4 19 Dec 1991 15:26:10 GLENN
+Added windows.h
+
+ Rev 1.3 12 Dec 1991 17:08:38 DAVEV
+16/32 bit port -2nd pass
+
+ Rev 1.2 10 Dec 1991 14:24:48 GLENN
+Changed the WM_Create to create a listbox with a single column
+
+ Rev 1.1 04 Dec 1991 18:45:38 GLENN
+Added window create macros
+
+ Rev 1.0 20 Nov 1991 19:24:58 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+// MODULE WIDE VARIABLES
+
+Q_HEADER_PTR mwpDebugQueue;
+
+FILE *mwhDebugFile = NULL;
+
+// PRIVATE FUNCTION PROTOTYPES
+
+VOID DBM_InsertStartMsg ( VOID );
+BOOL DBM_DeleteItem ( VOID );
+VOID_PTR DBM_SetTag ( DEBUGITEM_PTR, BYTE );
+BYTE DBM_GetTag ( DEBUGITEM_PTR );
+UINT DBM_GetItemCount ( Q_HEADER_PTR );
+VOID_PTR DBM_GetFirstItem ( Q_HEADER_PTR );
+VOID_PTR DBM_GetPrevItem ( DEBUGITEM_PTR );
+VOID_PTR DBM_GetNextItem ( DEBUGITEM_PTR );
+VOID_PTR DBM_GetObjects ( DEBUGITEM_PTR );
+VOID_PTR DBM_SetObjects ( DEBUGITEM_PTR, WORD, BYTE );
+
+
+// FUNCTIONS
+
+/******************************************************************************
+
+ Name: DBM_Init()
+
+ Description: This function initializes and creates the debug window.
+
+ Returns: SUCCESS if successful, otherwise FAILURE.
+
+******************************************************************************/
+
+BOOL DBM_Init ( VOID )
+
+{
+ WININFO_PTR pWinInfo;
+ DLM_INIT dsDLM;
+ CDS_PTR pCDS = CDS_GetPerm ();
+ CHAR szBuffer[ 100 ];
+
+ // If the debug config stuff is not initialized, set it to the defaults.
+
+ if ( ! CDS_GetDebugWindowShowAll ( pCDS ) ) {
+
+ if ( ! CDS_GetDebugWindowNumLines ( pCDS ) ) {
+ CDS_SetDebugWindowNumLines ( pCDS, DBM_NUM_LINES );
+ }
+ else if ( CDS_GetDebugWindowNumLines ( pCDS ) < DBM_MIN_LINES ) {
+ CDS_SetDebugWindowNumLines ( pCDS, DBM_MIN_LINES );
+ }
+ else if ( CDS_GetDebugWindowNumLines ( pCDS ) > DBM_MAX_LINES ) {
+ CDS_SetDebugWindowNumLines ( pCDS, DBM_MAX_LINES );
+ }
+
+ }
+
+ // Open debug file
+
+ if ( CDS_GetDebugToFile ( pCDS ) ) {
+
+ strcpy( szBuffer, pCDS->data_path );
+ strcat( szBuffer, pCDS->debug_file_name );
+
+ mwhDebugFile = UNI_fopen( szBuffer, _O_TEXT|_O_APPEND );
+ }
+
+ mwpDebugQueue = (Q_HEADER_PTR)calloc ( 1, sizeof ( Q_HEADER ) );
+
+ InitQueue( mwpDebugQueue );
+
+ // Insert the start message into the debug queue.
+
+ DBM_InsertStartMsg ();
+
+ // Create the debug window.
+
+ pWinInfo = (WININFO_PTR)calloc ( 1, sizeof ( DS_WMINFO ) );
+
+ WMDS_SetWinType ( pWinInfo, WMTYPE_DEBUG );
+ WMDS_SetWinClosable ( pWinInfo, FALSE );
+ WMDS_SetCursor ( pWinInfo, RSM_CursorLoad ( ID(IDRC_ARROW) ) );
+ WMDS_SetIcon ( pWinInfo, RSM_IconLoad ( IDRI_DEBUG ) );
+ WMDS_SetRibbon ( pWinInfo, ghRibbonMain );
+ WMDS_SetFlatList ( pWinInfo, mwpDebugQueue );
+
+ DLM_ListBoxType ( &dsDLM, DLM_FLATLISTBOX );
+ DLM_Mode ( &dsDLM, DLM_SINGLECOLUMN );
+ DLM_Display ( &dsDLM, DLM_SMALL_BITMAPS );
+ DLM_DispHdr ( &dsDLM, mwpDebugQueue );
+ DLM_TextFont ( &dsDLM, DLM_SYSTEM_FONT );
+ DLM_GetItemCount ( &dsDLM, DBM_GetItemCount );
+ DLM_GetFirstItem ( &dsDLM, DBM_GetFirstItem );
+ DLM_GetNext ( &dsDLM, DBM_GetNextItem );
+ DLM_GetPrev ( &dsDLM, DBM_GetPrevItem );
+ DLM_GetObjects ( &dsDLM, DBM_GetObjects );
+ DLM_SetObjects ( &dsDLM, DBM_SetObjects );
+ DLM_GetTag ( &dsDLM, DBM_GetTag );
+ DLM_SetTag ( &dsDLM, DBM_SetTag );
+ DLM_GetSelect ( &dsDLM, NULL );
+ DLM_SetSelect ( &dsDLM, NULL );
+ DLM_SSetItemFocus ( &dsDLM, NULL );
+ DLM_MaxNumObjects ( &dsDLM, 6 );
+
+ DLM_DispListInit ( pWinInfo, &dsDLM );
+
+ ghWndDebug = WM_Create( (WORD)(WM_MDIPRIMARY | WM_FLATLISTSC | CDS_GetDebugInfo ( pCDS ).nSize),
+ TEXT("Debug Window"),
+ (LPSTR)NULL,
+ (INT)CDS_GetDebugInfo ( pCDS ).x,
+ (INT)CDS_GetDebugInfo ( pCDS ).y,
+ (INT)CDS_GetDebugInfo ( pCDS ).cx,
+ (INT)CDS_GetDebugInfo ( pCDS ).cy,
+ pWinInfo );
+
+ DLM_DispListProc( pWinInfo->hWndFlatList, 0, NULL );
+
+ WM_Show( ghWndDebug );
+
+ return( SUCCESS );
+
+} /* DBM_Init() */
+
+
+/******************************************************************************
+
+ Name: DBM_InsertStartMsg()
+
+ Description: This function inserts a start message in the debug window.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID DBM_InsertStartMsg( VOID )
+
+{
+ DEBUGITEM_PTR pDebugItem;
+
+ pDebugItem = (DEBUGITEM_PTR) malloc ( sizeof ( DS_DEBUGITEM ) );
+ pDebugItem->pQElem.q_ptr = pDebugItem;
+ strncpy ( (CHAR_PTR)pDebugItem->szMsg, TEXT("Start of Debug Messages..."), DBM_LINELENGTH );
+ EnQueueElem ( mwpDebugQueue, &pDebugItem->pQElem, FALSE );
+
+ if ( mwhDebugFile ) {
+ fprintf( mwhDebugFile, TEXT("%s\n"), pDebugItem->szMsg );
+ }
+
+} /* end DBM_InsertStartMsg() */
+
+
+/******************************************************************************
+
+ Name: DBM_InsertItem()
+
+ Description: This function inserts a message in the debug window.
+
+ Returns: SUCCESS if successful, otherwise FAILURE.
+
+******************************************************************************/
+
+BOOL DBM_InsertItem (
+
+CHAR_PTR szMsg ) // I - pointer to a message string
+
+{
+ DEBUGITEM_PTR pDebugItem;
+ Q_ELEM_PTR q;
+ HWND hWnd;
+ CDS_PTR pCDS = CDS_GetPerm ();
+
+ if ( ! gfDebug || ! CDS_GetDebugToWindow ( pCDS ) || ! ghWndDebug ) {
+ return SUCCESS;
+ }
+
+ if ( mwhDebugFile ) {
+ fprintf( mwhDebugFile, TEXT("%s\n"), szMsg );
+ }
+
+ // If there is a limit on the number of messages and the limit has been
+ // reached, just recycle the queue element, then tell the Display List
+ // Manager to delete the first item in the list. Otherwise, add the new
+ // item.
+
+ if ( ! CDS_GetDebugWindowShowAll ( pCDS ) &&
+ QueueCount ( mwpDebugQueue ) >= CDS_GetDebugWindowNumLines ( pCDS ) ) {
+
+ q = DeQueueElem ( mwpDebugQueue );
+ pDebugItem = (DEBUGITEM_PTR)QueuePtr ( q );
+ DLM_Update ( ghWndDebug, DLM_FLATLISTBOX, WM_DLMDELETEITEMS, (LMHANDLE)NULL, 1 ) ;
+ }
+ else {
+ // Create the item structure.
+
+ pDebugItem = (DEBUGITEM_PTR) calloc ( 1, sizeof ( DS_DEBUGITEM ) );
+
+ if ( ! pDebugItem ) {
+ return SUCCESS;
+ }
+
+ pDebugItem->pQElem.q_ptr = pDebugItem;
+ }
+
+ strncpy ( (CHAR_PTR)pDebugItem->szMsg, szMsg, DBM_LINELENGTH );
+
+ // Insert message into the debug queue.
+
+ EnQueueElem ( mwpDebugQueue, &pDebugItem->pQElem, FALSE );
+
+ q = QueuePrev ( &(pDebugItem->pQElem) );
+
+ DLM_Update ( ghWndDebug, DLM_FLATLISTBOX, WM_DLMADDITEMS, (LMHANDLE)QueuePtr( q ), 1 ) ;
+
+ // Now set the anchor to the newly inserted item.
+
+ hWnd = (WM_GetInfoPtr ( ghWndDebug ))->hWndFlatList ;
+
+ DLM_ScrollListBox ( hWnd, DLM_SCROLLBOTTOM );
+
+ return( SUCCESS );
+
+} /* end DBM_InsertItem() */
+
+/******************************************************************************
+
+ Name: DBM_Deinit()
+
+ Description: This function closes the debug file if open.
+
+ Returns: SUCCESS if successful, otherwise FAILURE.
+
+******************************************************************************/
+
+BOOL DBM_Deinit( )
+{
+ CDS_PTR pCDS = CDS_GetPerm ();
+
+ gfDebug = FALSE;
+
+ if ( mwhDebugFile ) {
+ fclose( mwhDebugFile );
+ }
+
+ mwhDebugFile = NULL;
+
+ if ( IsWindow ( ghWndDebug ) ) {
+ CDS_WriteDebugWinSize ( ghWndDebug );
+ }
+
+ return SUCCESS;
+}
+
+
+/******************************************************************************
+
+ Name: DBM_Reset()
+
+ Description: This function clears out all messages in the debug window
+ or the debug file.
+
+ Returns: SUCCESS if successful, otherwise FAILURE.
+
+******************************************************************************/
+
+BOOL DBM_Reset (
+
+WORD wType ) // I - Type of reset
+
+{
+ Q_ELEM_PTR pQElem;
+ CHAR szBuffer[ 100 ];
+ CDS_PTR pCDS = CDS_GetPerm ();
+
+ switch ( wType ) {
+
+ case DBM_WINDOW: // Clear all the messages in the debug window.
+
+ pQElem = DeQueueElem( mwpDebugQueue );
+
+ while ( pQElem != NULL ) {
+
+ free ( QueuePtr ( pQElem ) );
+ pQElem = DeQueueElem( mwpDebugQueue ); // get next item
+ }
+
+ DBM_InsertStartMsg ();
+
+ DLM_Update ( ghWndDebug, DLM_FLATLISTBOX, WM_DLMUPDATELIST, (LMHANDLE)NULL, 0 );
+
+ break;
+
+ case DBM_FILE: // Rewind the debug recording file.
+
+ if ( mwhDebugFile ) {
+ fclose( mwhDebugFile );
+
+ strcpy( szBuffer, pCDS->data_path );
+ strcat( szBuffer, pCDS->debug_file_name );
+
+ mwhDebugFile = UNI_fopen( szBuffer, _O_TEXT );
+ }
+
+ break;
+ }
+
+ return SUCCESS;
+
+} /* end DBM_Reset() */
+
+
+/******************************************************************************
+
+ Name: DBM_SetDebugToFile()
+
+ Description: This function turns debugging to file on and off.
+
+ Returns: TRUE if turned on, otherwise FALSE.
+
+******************************************************************************/
+
+BOOL DBM_SetDebugToFile (
+
+BOOL fOn ) // I - on or off
+
+{
+ CHAR szBuffer[ 100 ];
+ CDS_PTR pCDS = CDS_GetPerm ();
+
+ // Turn debugging off only if it is on and we are told to do so.
+
+ if ( ! fOn && mwhDebugFile ) {
+
+ fclose ( mwhDebugFile );
+ mwhDebugFile = NULL;
+ }
+ else if ( fOn && ! mwhDebugFile ) {
+
+ strcpy ( szBuffer, pCDS->data_path );
+ strcat ( szBuffer, pCDS->debug_file_name );
+
+ mwhDebugFile = UNI_fopen ( szBuffer, _O_TEXT|_O_APPEND );
+ }
+
+ return (BOOL) ( mwhDebugFile != NULL );
+
+} /* end DBM_SetDebugToFile() */
+
+
+/******************************************************************************
+
+ Name: DBM_GetMsgCount()
+
+ Description: This function gets the number of window or file messages
+ depending on the type specified.
+
+ Returns: The number of messages.
+
+******************************************************************************/
+
+INT DBM_GetMsgCount (
+
+WORD wType ) // I - Type of messages to count
+
+{
+ switch ( wType ) {
+
+ case DBM_WINDOW: // Get the number of messages in the debug window.
+
+ return( QueueCount( mwpDebugQueue ) );
+
+ break;
+
+ case DBM_FILE:
+
+ break;
+ }
+
+
+ return 0;
+
+} /* end DBM_GetMsgCount () */
+
+
+/******************************************************************************
+
+ Name: DBM_SetMsgCount()
+
+ Description: This function sets the number of window or file messages
+ depending on the type specified.
+
+ Returns: SUCCESS if successful, otherwise FAILURE.
+
+******************************************************************************/
+
+BOOL DBM_SetMsgCount (
+
+WORD wType, // I - Type of message to set the max count for
+INT count ) // I - Number of messages to keep
+
+{
+ CDS_PTR pCDS = CDS_GetCopy ();
+
+ switch ( wType ) {
+
+ case DBM_WINDOW: // Set the number of messages in the debug window.
+
+ // Save count to configuration.
+
+ CDS_SetDebugWindowNumLines ( pCDS, (INT16)count );
+
+
+ break;
+
+ case DBM_FILE:
+
+ break;
+ }
+
+
+ return SUCCESS;
+
+} /* end DBM_SetMsgCount() */
+
+
+/******************************************************************************
+
+ Name: DBM_DeleteItem()
+
+ Description: This function deletes something. UNDETERMINED
+
+ Returns: SUCCESS if successful, otherwise FAILURE.
+
+******************************************************************************/
+
+BOOL DBM_DeleteItem ( VOID )
+
+{
+ // Get the number of log files to keep.
+
+ // How many log files do we have?
+
+ // Delete any extra log files starting with the oldest, etc...
+
+ return SUCCESS;
+
+} /* end DBM_DeleteItem() */
+
+
+// DISPLAY LIST MANAGER CALL BACK FUNCTIONS.
+
+
+/******************************************************************************
+
+ Name: DBM_SetTag()
+
+ Description: This function sets the tag status of an item structure.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID_PTR DBM_SetTag (
+
+DEBUGITEM_PTR pDebugItem, // I - pointer to a list item
+BYTE bState ) // I - state to set the item to
+
+{
+ pDebugItem->bTag = bState;
+ return( (VOID_PTR)NULL );
+}
+
+
+/******************************************************************************
+
+ Name: DBM_GetTag()
+
+ Description: This function gets the tag status for the
+ Display List Manager.
+
+ Returns: The tag status of the item.
+
+******************************************************************************/
+
+BYTE DBM_GetTag (
+
+DEBUGITEM_PTR pDebugItem ) // I - pointer to a list item
+
+{
+ return( pDebugItem->bTag );
+}
+
+
+/******************************************************************************
+
+ Name: DBM_GetItemCount()
+
+ Description: This function gets the item count in our list for the
+ Display List Manager.
+
+ Returns: The number of items in the list.
+
+******************************************************************************/
+
+UINT DBM_GetItemCount (
+
+Q_HEADER_PTR queue ) // I - pointer to a debug queue.
+
+{
+ return( QueueCount( queue ) );
+}
+
+
+/******************************************************************************
+
+ Name: DBM_GetFirstItem()
+
+ Description: This function returns the first item for the
+ Display List Manager.
+
+ Returns: The first item in the list.
+
+******************************************************************************/
+
+VOID_PTR DBM_GetFirstItem (
+
+Q_HEADER_PTR queue ) // I - pointer to a debug queue.
+
+{
+ Q_ELEM_PTR q;
+
+ q = QueueHead( queue );
+
+ return( (q) ? (VOID_PTR)QueuePtr(q) : (VOID_PTR)NULL );
+}
+
+
+/******************************************************************************
+
+ Name: DBM_GetPrevItem()
+
+ Description: This function returns the previous list item for the
+ Display List Manager.
+
+ Returns: The previous item in the list.
+
+******************************************************************************/
+
+VOID_PTR DBM_GetPrevItem (
+
+DEBUGITEM_PTR pDebugItem ) // I - pointer to a list item
+
+{
+ Q_ELEM_PTR q;
+
+ q = QueuePrev( &(pDebugItem->pQElem) );
+
+ return( (q) ? (VOID_PTR)QueuePtr(q) : (VOID_PTR)NULL );
+}
+
+
+/******************************************************************************
+
+ Name: DBM_GetNextItem()
+
+ Description: This function returns the next list item for the
+ Display List Manager.
+
+ Returns: The next item in the list.
+
+******************************************************************************/
+
+VOID_PTR DBM_GetNextItem (
+
+DEBUGITEM_PTR pDebugItem ) // I - pointer to a list item
+
+{
+ Q_ELEM_PTR q;
+
+ q = QueueNext( &(pDebugItem->pQElem) );
+
+ return( (q) ? (VOID_PTR)QueuePtr(q) : (VOID_PTR)NULL );
+}
+
+
+/******************************************************************************
+
+ Name: DBM_GetObjects()
+
+ Description: This function returns a given object and gets the
+ information that needs to be displayed by Display List
+ Manager.
+
+ Returns: The list of objects to be displayed.
+
+******************************************************************************/
+
+VOID_PTR DBM_GetObjects (
+
+DEBUGITEM_PTR pDebugItem ) // I - pointer to a list item
+
+{
+ INT8_PTR memblk;
+ DLM_ITEM_PTR pItem;
+ WININFO_PTR pWinInfo;
+
+ pWinInfo = WM_GetInfoPtr( ghWndDebug );
+ memblk = (INT8_PTR)DLM_GetObjectsBuffer( pWinInfo->hWndFlatList );
+
+ // Store the number of items in the first two bytes.
+
+ *memblk = 1;
+
+ pItem = (DLM_ITEM_PTR)( memblk + 6 );
+
+ // Set up the text string to be displayed.
+
+ DLM_ItemcbNum( pItem ) = 1;
+ DLM_ItembType( pItem ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( pItem ) = 0;
+ DLM_ItembMaxTextLen( pItem ) = DBM_LINELENGTH;
+ DLM_ItembLevel( pItem ) = 0;
+ DLM_ItembTag( pItem ) = 0;
+ strncpy( (CHAR_PTR)DLM_ItemqszString( pItem ), (CHAR_PTR)pDebugItem->szMsg, DBM_LINELENGTH );
+
+ return memblk;
+}
+
+
+/******************************************************************************
+
+ Name: DBM_SetObjects()
+
+ Description: This function performs an action based on a click or
+ double-click on an item that is in the list.
+
+ Returns: NULL.
+
+******************************************************************************/
+
+VOID_PTR DBM_SetObjects (
+
+DEBUGITEM_PTR pDebugItem, // I - pointer to a list item
+WORD wEvent, // I - type of event
+BYTE bSubItem ) // I - sub item
+
+{
+ DBG_UNREFERENCED_PARAMETER ( pDebugItem ); // dvc - I presume these will
+ DBG_UNREFERENCED_PARAMETER ( bSubItem ); // be used in the future
+
+ // Let's show the debug settings dialog if the user double clicks on
+ // a debug message.
+
+ if ( wEvent == WM_DLMDBCLK ) {
+ DM_ShowDialog ( ghWndDebug, IDD_SETTINGSDEBUGWINDOW, (VOID_PTR)0 );
+ }
+
+ return (VOID_PTR)NULL;
+
+} /* end DBM_SetObjects() */
+
+
diff --git a/private/utils/ntbackup/src/debug.ico b/private/utils/ntbackup/src/debug.ico
new file mode 100644
index 000000000..b3c663b78
--- /dev/null
+++ b/private/utils/ntbackup/src/debug.ico
Binary files differ
diff --git a/private/utils/ntbackup/src/defchan.c b/private/utils/ntbackup/src/defchan.c
new file mode 100644
index 000000000..ec8537f91
--- /dev/null
+++ b/private/utils/ntbackup/src/defchan.c
@@ -0,0 +1,63 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: defchan.c
+
+ Description:
+
+ $Log: G:/UI/LOGFILES/DEFCHAN.C_V $
+
+ Rev 1.7 26 Jul 1993 18:01:32 MARINA
+enable c++
+
+ Rev 1.6 07 Oct 1992 14:51:24 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.5 04 Oct 1992 19:32:36 DAVEV
+Unicode Awk pass
+
+ Rev 1.4 17 Aug 1992 13:04:12 DAVEV
+MikeP's changes at Microsoft
+
+ Rev 1.3 28 Jul 1992 14:43:38 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.2 18 May 1992 09:06:48 MIKEP
+header
+
+ Rev 1.1 18 Dec 1991 14:07:18 GLENN
+Added windows.h
+
+ Rev 1.0 20 Nov 1991 19:24:42 SYSTEM
+Initial revision.
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+VOID DefineChannel(
+BE_INIT_STR_PTR be_ptr )
+{
+ THW_PTR cur_thw ;
+ INT16 i ;
+ UINT16 num_resources ;/* number of items in resource */
+ UINT16 error ; /* resource manager error */
+ Q_HEADER tmp_q ;
+
+ /* Set Up the Head of the list */
+ cur_thw = *be_ptr->thw_list_ptr ;
+ i = 1 ;
+
+ InitQueue( &tmp_q ) ;
+
+ while( cur_thw != NULL ) {
+ EnQueueElem( &tmp_q, ( Q_ELEM_PTR ) &cur_thw->channel_link, FALSE ) ;
+ sprintf( &cur_thw->drv_name[0], (LPSTR)RM_GetResource( rm, (UINT)SES_ENG_MSG, (UINT)RES_TAPE_DRIVE_NAME, &num_resources, &error ), i++ ) ;
+ cur_thw = ( THW_PTR ) QueueNext( &cur_thw->link ) ;
+ }
+ return ;
+}
diff --git a/private/utils/ntbackup/src/defltblk.c b/private/utils/ntbackup/src/defltblk.c
new file mode 100644
index 000000000..72dcccfc7
--- /dev/null
+++ b/private/utils/ntbackup/src/defltblk.c
@@ -0,0 +1,167 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: defltblk.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains code to set the defaults
+ for the Create request structures.
+
+
+ $Log: J:/LOGFILES/DEFLTBLK.C_V $
+
+ Rev 1.12 21 Jan 1993 18:41:50 DON
+Added access_date to fix read page fault
+
+ Rev 1.11 11 Nov 1992 09:52:30 GREGG
+Unicodeized literals.
+
+ Rev 1.10 18 Aug 1992 10:12:00 STEVEN
+fix warnings
+
+ Rev 1.9 12 Mar 1992 15:51:08 STEVEN
+64 bit changes
+
+ Rev 1.8 24 Feb 1992 17:37:16 STEVEN
+added support for NTFS
+
+ Rev 1.7 05 Dec 1991 15:30:06 BARRY
+Added SMS object to FS_CreateDefaultDBLK().
+
+ Rev 1.6 30 Oct 1991 10:26:22 LORIB
+Changes for ACL. Changed the OS version for OS/2 to FS_PC_OS2_ACL_VER.
+
+ Rev 1.5 01 Oct 1991 11:14:42 BARRY
+Include standard headers.
+
+ Rev 1.4 12 Aug 1991 13:40:18 DON
+fixes for NLM
+
+ Rev 1.3 24 Jul 1991 09:11:46 DAVIDH
+Corrected warning found by Watcom.
+
+ Rev 1.2 27 Jun 1991 09:42:16 STEVEN
+fix typeo
+
+ Rev 1.1 24 Jun 1991 09:19:10 STEVEN
+need to initialize version
+
+ Rev 1.0 09 May 1991 13:39:56 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include <string.h>
+
+#include "stdtypes.h"
+
+#include "msassert.h"
+#include "fsys.h"
+#include "novcom.h"
+#include "tbe_defs.h"
+
+/* $end$ include list */
+
+static DATE_TIME today_date = { 0, 1980, 1, 1, 1, 0, 0 } ;
+static DATE_TIME dummy_date = { 1, 1980, 1, 1, 1, 0, 0 } ;
+
+static CHAR dummy_fname[] = TEXT("NO_NAME") ;
+static INT16 dummy_fname_size = sizeof( dummy_fname ) ;
+
+static CHAR dummy_path[] = TEXT("") ;
+static INT16 dummy_path_size = sizeof( dummy_path ) ;
+
+static CHAR dummy_part_name[] = TEXT("PARTITION") ;
+static INT16 dummy_part_name_size = sizeof( dummy_part_name ) ;
+
+/**/
+/**
+
+ Name: FS_SetDefaultDBLK()
+
+ Description: This function initializes the structure passed to the
+ DBLK create routines.
+
+ Modified: 9/13/1989
+
+ Returns: none
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID FS_SetDefaultDBLK(
+FSYS_HAND fsh, /* I - file system handle */
+INT8 blk_type, /* I - type of block to create */
+CREATE_DBLK_PTR data ) /* O - structure to initialize */
+{
+
+ (VOID) fsh ;
+
+ msassert( fsh != NULL ) ;
+
+ if( !today_date.date_valid ) {
+ GetCurrentDate( &today_date ) ;
+ }
+
+ switch ( blk_type ) {
+
+ case UDB_ID:
+ memset( &(data->u), 0, sizeof(data->u) ) ;
+ break ;
+
+ case VCB_ID:
+ memset( &(data->v), 0, sizeof(data->v) ) ;
+ data->v.date = &today_date ;
+ data->v.sw_major_ver = BE_MAJ_VERSION ;
+ data->v.sw_minor_ver = BE_MIN_VERSION ;
+ break ;
+
+ case DDB_ID:
+ memset( &(data->d), 0, sizeof(data->d) ) ;
+ data->d.path_name = dummy_path ;
+ data->d.path_size = dummy_path_size ;
+ data->d.creat_date = &today_date ;
+ data->d.mod_date = &today_date ;
+ data->d.backup_date = &dummy_date ;
+ data->d.access_date = &dummy_date ;
+ break ;
+
+ case FDB_ID:
+ memset( &(data->f), 0, sizeof(data->f) ) ;
+ data->f.fname = dummy_fname ;
+ data->f.fname_size = dummy_fname_size ;
+ data->f.creat_date = &dummy_date ;
+ data->f.mod_date = &today_date ;
+ data->f.backup_date = &dummy_date ;
+ data->f.access_date = &dummy_date ;
+ break ;
+
+ case IDB_ID:
+ memset( &(data->i), 0, sizeof(data->i) ) ;
+ data->i.pname = dummy_part_name;
+ data->i.pname_size = dummy_part_name_size ;
+
+ break ;
+
+ case CFDB_ID:
+ memset( &(data->c), 0, sizeof(data->c) ) ;
+ break ;
+
+ default:
+ msassert( ("Bad block type ", FALSE) ) ;
+ break ;
+ }
+
+ if ( fsh->tab_ptr->InitMakeData != NULL ) {
+ fsh->tab_ptr->InitMakeData( fsh, blk_type, data ) ;
+ }
+
+ return ;
+}
diff --git a/private/utils/ntbackup/src/details.c b/private/utils/ntbackup/src/details.c
new file mode 100644
index 000000000..71c3c0cdc
--- /dev/null
+++ b/private/utils/ntbackup/src/details.c
@@ -0,0 +1,1756 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: details.c
+
+ Description: This module contains miscellaneous functions within the USER INTERFACE for displaying information.
+ Most of the functions found here were at one time in-line code which needed to be shared by several
+ functions/modules.
+
+ $Log: J:/UI/LOGFILES/DETAILS.C_V $
+
+ Rev 1.44.1.5 06 Jul 1994 18:30:14 GREGG
+Fixed routine that checks for write protect and write protect error handling.
+
+ Rev 1.44.1.4 20 Feb 1994 10:51:44 MIKEP
+make extended error reportin cleaner in logfile
+
+ Rev 1.44.1.3 07 Feb 1994 02:06:32 GREGG
+Fixed and expanded 'extended error reporting'.
+
+ Rev 1.44.1.2 28 Jan 1994 18:09:32 MIKEP
+Display extended error messages in the logfile
+
+ Rev 1.44.1.1 24 Jan 1994 14:02:58 GREGG
+Fixed GEN_ERR_UNDETERMINED string.
+
+ Rev 1.44.1.0 17 Jan 1994 15:22:26 MIKEP
+fix warnings
+
+ Rev 1.44 05 Jan 1994 20:19:50 GREGG
+Changed string defines for extended error reporting.
+
+ Rev 1.43 05 Jan 1994 11:35:36 GREGG
+Added support for extended error reporting.
+
+ Rev 1.42 15 Dec 1993 16:57:52 GREGG
+Fixed buffer overflow problem.
+
+ Rev 1.41 29 Sep 1993 17:10:20 MIKEP
+handle LP_ACCESS_DENIED better
+
+ Rev 1.40 15 Sep 1993 13:49:42 CARLS
+added UI_BuildFullPathFromDDB2 to build the full path for Log files
+
+ Rev 1.39 03 Aug 1993 14:52:46 MIKEP
+add sypl flag
+
+ Rev 1.38 23 Jul 1993 13:07:52 MIKEP
+
+ Rev 1.37 14 Jun 1993 20:37:36 MIKEP
+enable c++
+
+ Rev 1.36 02 Jun 1993 16:00:38 CARLS
+set BOOLEAN trunc_last to FALSE at start up in routine UI_FixPath
+
+ Rev 1.35 14 May 1993 15:09:58 MIKEP
+Change the num seconds operation took to 1 if it was 0.
+
+ Rev 1.34 02 Apr 1993 15:51:50 CARLS
+changes for DC2000 unformatted tape
+
+ Rev 1.33 18 Mar 1993 11:11:32 chrish
+Added change to routines StripLastItem and UI_FixPath ... was causing an
+infinite loop problem.
+
+ Rev 1.32 31 Dec 1992 12:15:42 MIKEP
+use resources for strings
+
+ Rev 1.31 23 Dec 1992 12:42:18 MIKEP
+half done fix
+
+ Rev 1.30 14 Dec 1992 12:17:48 DAVEV
+Enabled for Unicode compile
+
+ Rev 1.29 17 Nov 1992 21:21:26 DAVEV
+unicode fixes
+
+ Rev 1.28 05 Nov 1992 16:59:48 DAVEV
+fix ts
+
+ Rev 1.26 07 Oct 1992 14:52:06 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.25 04 Oct 1992 19:32:40 DAVEV
+Unicode Awk pass
+
+ Rev 1.24 17 Aug 1992 13:04:44 DAVEV
+MikeP's changes at Microsoft
+
+ Rev 1.23 28 Jul 1992 14:50:32 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.22 29 May 1992 10:14:28 MIKEP
+total to display change
+
+ Rev 1.21 21 May 1992 19:25:10 MIKEP
+fixes
+
+ Rev 1.20 19 May 1992 09:26:20 MIKEP
+mo changes
+
+ Rev 1.19 14 May 1992 17:23:58 MIKEP
+nt pass 2
+
+ Rev 1.18 11 May 1992 19:45:02 STEVEN
+64bit and large path sizes
+
+
+*****************************************************************************/
+
+#include "all.h"
+#include "generr.h"
+#include "genfuncs.h"
+#include "special.h"
+#include "dddefs.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+static CHAR mw_tape_created[ MAX_TAPE_NAME_LEN + 1 ];
+static INT16 mw_spaces;
+static INT16 mw_dots;
+static UINT32 mw_ticks;
+static UINT32 mw_search_ticks;
+
+extern BOOLEAN lw_search_first_time = TRUE;
+
+static BOOLEAN StripLastItem( CHAR_PTR buffer, CHAR delim ); // chs:03-18-93
+static CHAR_PTR LoadGenErrStr( INT16 gen_err ) ;
+static CHAR_PTR LoadGenFuncStr( INT16 gen_func, INT32 gen_misc ) ;
+
+/*****************************************************************************
+
+ Name: UI_SetResources
+
+ Description: Sets the mw variables
+
+ Returns: VOID
+
+*****************************************************************************/
+VOID UI_SetResources( )
+{
+ UINT16 num_resources; /* number of items in resource */
+ UINT16 error; /* resource manager error */
+
+ /* establish any module wide references to the resources */
+
+ strcpy( mw_tape_created, (CHAR_PTR)RM_GetResource( rm, (UINT)SES_ENG_MSG, (UINT)RES_TAPE_CREATED, &num_resources, &error ) );
+}
+/*****************************************************************************
+
+ Name: UI_BuildDelimitedPathFromDDB
+
+ Description: Builds a properly delimited path from a NULL-impregnated path
+ truncates/inserts ... into long paths
+
+ Returns: VOID
+
+*****************************************************************************/
+VOID UI_BuildDelimitedPathFromDDB(
+CHAR_PTR *buffer, /* O - buffer in which to build the path */
+FSYS_HAND fsh, /* I - file system handle */
+DBLK_PTR ddb_dblk_ptr, /* I - dblk for the specified directory */
+CHAR delimiter, /* I - delimiter to be used */
+BOOLEAN OS_flag ) /* I - flag to determine whether or not to use OS Path */
+{
+
+ UI_BuildFullPathFromDDB( buffer, fsh, ddb_dblk_ptr, delimiter, OS_flag );
+
+ /* truncate/insert ... into long paths */
+ UI_FixPath( *buffer, UI_MaxDirectoryLength( ), delimiter );
+
+ return;
+
+}
+
+/*****************************************************************************
+
+ Name: UI_AllocPathBuffer
+
+ Description: Allocates a block of memory to be used as a path container
+
+ Returns: VOID
+
+*****************************************************************************/
+CHAR_PTR UI_AllocPathBuffer( CHAR_PTR *buffer, UINT16 leng )
+{
+ UINT16_PTR buf_size ;
+ CHAR_PTR real_buf_ptr ;
+
+ if ( *buffer == NULL ) {
+ *buffer = (CHAR_PTR)calloc( 1024, 1 ) ;
+ if ( *buffer != NULL ) {
+ buf_size = (UINT16_PTR)(*buffer) ;
+ *buf_size++ = 1024 - sizeof( UINT16 ) ;
+ *buffer = (CHAR_PTR)buf_size;
+ }
+ }
+ if ( *buffer != NULL ) {
+ real_buf_ptr = (CHAR_PTR)((INT8_PTR)(*buffer) - sizeof( UINT16 ));
+ buf_size = (UINT16_PTR)(real_buf_ptr) ;
+ if ( *buf_size < leng + sizeof( CHAR ) ) {
+ leng += 64 ;
+ *buffer = (CHAR_PTR)realloc( real_buf_ptr, leng ) ;
+ if ( *buffer != NULL ) {
+ buf_size = (UINT16_PTR)(*buffer) ;
+ *buf_size++ = leng - sizeof( UINT16 ) ;
+ *buffer = (CHAR_PTR)buf_size;
+ }
+ }
+ }
+ return( *buffer ) ;
+}
+/*****************************************************************************
+
+ Name: UI_FreePathBuffer
+
+ Description: Allocates a block of memory to be used as a path container
+
+ Returns: VOID
+
+*****************************************************************************/
+VOID UI_FreePathBuffer( CHAR_PTR *buffer )
+{
+ CHAR_PTR real_buf_ptr ;
+
+ if ( *buffer != NULL ) {
+ real_buf_ptr = (CHAR_PTR)((INT8_PTR)(*buffer) - sizeof( UINT16 ));
+ free( real_buf_ptr ) ;
+ *buffer = NULL ;
+ }
+}
+/*****************************************************************************
+
+ Name: UI_BuildFullPathFromDDB
+
+ Description: Builds a properly delimited path from a NULL-impregnated path,
+ and fixes up the path length by inserting "..."
+
+ Returns: VOID
+
+*****************************************************************************/
+VOID UI_BuildFullPathFromDDB(
+CHAR_PTR *buffer, /* O - buffer in which to build the path */
+FSYS_HAND fsh, /* I - file system handle */
+DBLK_PTR ddb_dblk_ptr, /* I - dblk for the specified directory */
+CHAR delimiter, /* I - delimiter to be used */
+BOOLEAN OS_flag ) /* I - flag to determine whether or not to use OS Path */
+{
+
+ UI_BuildFullPathFromDDB2( buffer, fsh, ddb_dblk_ptr, delimiter, OS_flag );
+ if ( *buffer != NULL ) {
+
+ /* truncate/insert ... into long paths */
+ UI_FixPath( *buffer, UI_MaxDirectoryLength( ), delimiter );
+
+ }
+ return;
+
+}
+/*****************************************************************************
+
+ Name: UI_BuildFullPathFromDDB2
+
+ Description: Builds a properly delimited path from a NULL-impregnated path.
+ This function is called by the DO routines to display the full
+ path for Log file detail.
+
+ Returns: VOID
+
+*****************************************************************************/
+//FULL DETAIL
+VOID UI_BuildFullPathFromDDB2(
+CHAR_PTR *buffer, /* O - buffer in which to build the path */
+FSYS_HAND fsh, /* I - file system handle */
+DBLK_PTR ddb_dblk_ptr, /* I - dblk for the specified directory */
+CHAR delimiter, /* I - delimiter to be used */
+BOOLEAN OS_flag ) /* I - flag to determine whether or not to use OS Path */
+{
+ CHAR_PTR p;
+ INT16 size;
+
+
+ if( OS_flag ) {
+ size = FS_SizeofOSPathInDDB( fsh, ddb_dblk_ptr );
+ if ( UI_AllocPathBuffer( buffer, size ) != NULL ) {
+ FS_GetOSPathFromDDB( fsh, ddb_dblk_ptr, &((*buffer)[1]) );
+ }
+ }
+ else {
+ size = FS_SizeofPathInDDB( fsh, ddb_dblk_ptr );
+ if ( UI_AllocPathBuffer( buffer, size ) != NULL ) {
+ FS_GetPathFromDDB( fsh, ddb_dblk_ptr, &((*buffer)[1]) );
+ }
+ }
+
+ if ( *buffer != NULL ) {
+ UINT idx;
+ **buffer = TEXT('\\');
+ /* substitute the delimiter */
+ for ( idx=0, p=*buffer; idx < size/sizeof (CHAR); ++idx )
+ {
+ if ( p [idx] == TEXT ('\0') )
+ {
+ p [idx] = delimiter;
+ }
+ }
+ /* UNICODE NOTE: the above for loop replaces the following */
+ /* while loop, which is no longer allowed for Unicode */
+ /* since memchr looks at one BYTE at a time. */
+ /*while( p = memchr( *buffer, TEXT('\0'), size ) ) { */
+ /* *p = delimiter; */
+ /*} */
+
+ }
+
+ return;
+
+}
+/*****************************************************************************
+
+ Name: UI_AppendDelimiter
+
+ Description: Ensures a properly terminated delimited path
+
+ Returns: VOID
+
+*****************************************************************************/
+VOID UI_AppendDelimiter(
+CHAR_PTR buffer, /* I/O - buffer in which to build the path */
+CHAR delimiter ) /* I - delimiter to be used */
+{
+ CHAR_PTR p = &buffer[ strlen( buffer ) - 1 ];
+
+ if( *p++ != delimiter ) {
+ *p++ = delimiter;
+ *p = TEXT('\0');
+ }
+
+ return;
+}
+/*****************************************************************************
+
+ Name: UI_BuildFileDetail
+
+ Description: Builds file detail information for display purposes
+
+ Returns: VOID
+
+*****************************************************************************/
+VOID UI_BuildFileDetail(
+CHAR_PTR buffer, /* O - buffer in which to build the detail */
+FSYS_HAND fsh, /* I - file system handle */
+DBLK_PTR fdb_dblk_ptr, /* I - dblk for the specified file */
+BOOLEAN OS_flag ) /* I - flag to determine whether or not to use OS Name */
+{
+ CHAR fname[ UI_MAX_FILENAME_LENGTH ]; /* temporary filename */
+ UINT64 fsize; /* filesize */
+ DATE_TIME fdate; /* file date / time */
+ UINT32 attribs; /* file attributes */
+ OBJECT_TYPE fdb_type; /* Object type e.g. AFP */
+
+ buffer[ 0 ] = TEXT('\0');
+ fsize = FS_GetDisplaySizeFromDBLK( fsh, fdb_dblk_ptr );
+
+ if( OS_flag ) {
+ FS_GetOSFnameFromFDB( fsh, fdb_dblk_ptr, fname );
+ } else {
+ FS_GetFnameFromFDB( fsh, fdb_dblk_ptr, fname );
+ }
+
+ FS_GetMDateFromDBLK( fsh, fdb_dblk_ptr, &fdate );
+
+ FS_GetObjTypeDBLK( fsh, fdb_dblk_ptr, &fdb_type );
+
+ attribs = FS_GetAttribFromDBLK( fsh, fdb_dblk_ptr );
+
+ UI_BuildFileSelectLine( buffer, fname, (INT16) UI_MAX_FILE_DISPLAY, FALSE,
+ attribs, fdb_type, fsize, &fdate );
+
+ return;
+
+}
+/*****************************************************************************
+
+ Name: UI_BuildFileSelectLine
+
+ Description: This routine will format a line for file selection
+
+ Returns: Nothing. Will set "buffer" to the formated line.
+
+*****************************************************************************/
+VOID UI_BuildFileSelectLine(
+CHAR_PTR buffer, /* O - resultant formatted line */
+CHAR_PTR name, /* I - File file or directory name */
+/* O - File/Dir name truncated */
+INT16 name_len, /* I - Length of name to be displayed */
+BOOLEAN dir, /* I - TRUE if name is directory */
+UINT32 attr, /* I - File System attributes */
+OBJECT_TYPE obj_type, /* I - File System object */
+UINT64 size, /* I - size of file */
+DATE_TIME *date) /* I - pointer to date/time struct */
+{
+ CHAR numeral[40] ;
+ BOOLEAN stat ;
+ CHAR attrib_buf[UI_MAX_ATTRIBS_LENGTH]; /* attribs to display */
+ CHAR date_str[MAX_UI_DATE_SIZE];
+ CHAR time_str[MAX_UI_TIME_SIZE];
+
+ /* truncate filename (and insert ...) if name too long */
+ UI_TruncateString( name, name_len, FALSE );
+
+ /* Build attributes string */
+ if( dir ) {
+ strlwr( name );
+ UI_BuildDirAttribs( attrib_buf, attr, obj_type );
+ } else {
+ UI_BuildFileAttribs( attrib_buf, attr, obj_type );
+ }
+
+ /* Format display string */
+ if( dir ) {
+ sprintf( buffer, TEXT("%-*s %s\n"),
+ name_len,
+ name,
+ attrib_buf );
+ } else {
+
+ UI_MakeDateString( date_str, date->month, date->day,
+ date->year % 100 );
+ UI_MakeShortTimeString( time_str, date->hour, date->minute );
+
+ if ( U64_Msw( size ) == 0 ) {
+ sprintf( buffer, TEXT("%-*s %s %10lu %11s %11s\n"),
+ name_len,
+ name,
+ attrib_buf,
+ U64_Lsw( size ),
+ date_str,
+ time_str );
+
+ } else {
+
+ U64_Litoa( size, numeral, (INT16) 10, &stat ) ;
+ sprintf( buffer, TEXT("%-*s %s %s %11s %11s\n"),
+ name_len,
+ name,
+ attrib_buf,
+ numeral,
+ date_str,
+ time_str );
+
+ }
+ }
+
+
+
+ return;
+}
+/*****************************************************************************
+
+ Name: UI_BuildFileAttribs
+
+ Description: Builds file attribute information for display purposes
+
+ Returns: VOID
+
+*****************************************************************************/
+VOID UI_BuildFileAttribs(
+CHAR_PTR buffer, /* O - buffer in which to build the attribute */
+UINT32 attribs, /* I - file attributes */
+OBJECT_TYPE fdb_type) /* I - Object type e.g. AFP */
+{
+ INT16 len; /* used to pad fill buffer with spaces */
+
+ buffer[ 0 ] = TEXT('\0');
+
+ if( attribs & OBJ_READONLY_BIT ||
+ attribs & OBJ_HIDDEN_BIT ||
+ attribs & OBJ_SYSTEM_BIT ||
+ attribs & OBJ_MODIFIED_BIT ||
+ attribs & OBJ_CORRUPT_BIT ||
+ ( fdb_type == AFP_OBJECT ) ) {
+
+ len = UI_ATTRIBS_PADDING;
+
+ strcat( buffer, TEXT("<") );
+
+ if( attribs & OBJ_READONLY_BIT ) {
+ strcat( buffer, TEXT("R") );
+ len--;
+ }
+
+ if( attribs & OBJ_HIDDEN_BIT ) {
+ strcat( buffer, TEXT("H") );
+ len--;
+ }
+
+ if( attribs & OBJ_SYSTEM_BIT ) {
+ strcat( buffer, TEXT("S") );
+ len--;
+ }
+ if( attribs & OBJ_MODIFIED_BIT ) {
+ strcat( buffer, TEXT("A") );
+ len--;
+ }
+ if( attribs & OBJ_CORRUPT_BIT ) {
+ strcat( buffer, TEXT("C") );
+ len--;
+ }
+ if( fdb_type == AFP_OBJECT ) {
+ if( len != UI_ATTRIBS_PADDING ) {
+ strcat( buffer, TEXT("><") );
+ len -= 2;
+ }
+ strcat( buffer, TEXT("AFP") );
+ len -= 3;
+ }
+ strcat( buffer, TEXT(">") );
+ if( len ) {
+ strncat( buffer, TEXT(" "), len );
+ }
+
+ } else {
+ strcat( buffer, TEXT(" ") );
+ }
+
+ return;
+
+}
+/*****************************************************************************
+
+ Name: UI_BuildDirAttribs
+
+ Description: Builds file attribute information for display purposes
+
+ Returns: VOID
+
+*****************************************************************************/
+VOID UI_BuildDirAttribs(
+CHAR_PTR buffer, /* O - buffer in which to build the attribute */
+UINT32 attribs, /* I - file attributes */
+OBJECT_TYPE fdb_type) /* I - Object type e.g. AFP */
+{
+ INT16 len; /* used to pad fill buffer with spaces */
+
+ buffer[ 0 ] = TEXT('\0');
+
+ strcat( buffer, TEXT("<DIR>") );
+ if( attribs & OBJ_HIDDEN_BIT ||
+ attribs & OBJ_SYSTEM_BIT ||
+ attribs & OBJ_READONLY_BIT ||
+ attribs & OBJ_CORRUPT_BIT ||
+ ( fdb_type == AFP_OBJECT ) ) {
+
+ len = UI_ATTRIBS_PADDING;
+
+ strcat( buffer, TEXT("<") );
+
+ if( attribs & OBJ_HIDDEN_BIT ) {
+ strcat( buffer, TEXT("H") );
+ len--;
+ }
+ if( attribs & OBJ_READONLY_BIT ) {
+ strcat( buffer, TEXT("R") );
+ len--;
+ }
+ if( attribs & OBJ_SYSTEM_BIT ) {
+ strcat( buffer, TEXT("S") );
+ len--;
+ }
+ if( attribs & OBJ_CORRUPT_BIT ) {
+ strcat( buffer, TEXT("C") );
+ len--;
+ }
+ if( fdb_type == AFP_OBJECT ) {
+ if( len != UI_ATTRIBS_PADDING ) {
+ strcat( buffer, TEXT("><") );
+ len -= 2;
+ }
+ strcat( buffer, TEXT("AFP") );
+ len -= 3;
+ }
+ strcat( buffer, TEXT(">") );
+ if( len ) {
+ strncat( buffer, TEXT(" "), ( len - 5 ) ); /* to account for <dir> */
+ }
+
+ } else {
+ strcat( buffer, TEXT(" ") );
+ }
+
+ return;
+
+}
+/*****************************************************************************
+
+ Name: UI_BytesProcessed
+
+ Description: Processes the display/log of bytes processed for an operation
+
+ Returns: VOID
+
+*****************************************************************************/
+VOID UI_BytesProcessed(
+STATS_PTR op_stats_ptr ) /* I - operation level statistics */
+{
+
+ INT16 num_minutes = 0 ;
+ INT16 num_seconds = 0 ;
+ INT16 num_hours = 0;
+ UINT64 num_bytes;
+ BOOLEAN stat ;
+ CHAR *p;
+ CHAR numeral[ UI_MAX_NUMERAL_LENGTH ];
+ CHAR buffer[ 256 ];
+ CHAR temp[ 256 ];
+
+ /************
+
+ options:
+
+ processed X bytes in X hours, X minutes, and X seconds.
+ processed X bytes in 1 hour, X minutes, and X seconds.
+ processed X bytes in X hours, 1 minute, and X seconds.
+ processed X bytes in X hours, X minutes, and 1 second.
+ processed X bytes in 1 hour, 1 minute, and 1 second.
+ processed X bytes in X minutes and X seconds.
+ processed X bytes in X seconds.
+ etc.
+
+ *************/
+
+ num_bytes = ST_GetBSBytesProcessed( op_stats_ptr );
+
+ U64_Litoa( num_bytes, numeral, (INT16) 10, &stat );
+
+ UI_BuildNumeralWithCommas( numeral );
+
+ if ( ST_GetBSStartTime( op_stats_ptr ) ) {
+ num_minutes = ST_GetBSElapsedMinutes( op_stats_ptr );
+ num_seconds = ST_GetBSElapsedSeconds( op_stats_ptr );
+ num_hours = ST_GetBSElapsedHours( op_stats_ptr );
+ }
+
+
+ // Make tony happy by displaying 1 second, rather than 0.
+
+ if ( ( num_hours == 0 ) && ( num_minutes == 0 ) && ( num_seconds == 0 ) ) {
+ num_seconds = 1;
+ }
+
+ p = ( CHAR_PTR )RM_GetResource( rm, SES_ENG_MSG, RES_BYTES_PROCESSED, NULL, NULL );
+ sprintf( buffer, p, numeral );
+
+ // Really long operation, took hours to complete.
+
+ if ( num_hours > 0 ) {
+
+ if ( num_hours == 1 ) {
+
+ p = ( CHAR_PTR )RM_GetResource( rm, SES_ENG_MSG, RES_BYTES_PROCESSED_HOUR, NULL, NULL );
+ sprintf( temp, p, num_hours );
+ }
+ else {
+
+ p = ( CHAR_PTR )RM_GetResource( rm, SES_ENG_MSG, RES_BYTES_PROCESSED_HOURS, NULL, NULL );
+ sprintf( temp, p, num_hours );
+ }
+ strcat( buffer, temp );
+ }
+
+ // Display minutes
+
+ if ( num_hours > 0 || num_minutes > 0 ) {
+
+ if ( num_hours > 0 ) {
+
+ // With comma's
+
+ if ( num_minutes == 1 ) {
+
+ p = ( CHAR_PTR )RM_GetResource( rm, SES_ENG_MSG, RES_BYTES_PROCESSED_MINUTE1, NULL, NULL );
+ sprintf( temp, p, num_minutes );
+ }
+ else {
+
+ p = ( CHAR_PTR )RM_GetResource( rm, SES_ENG_MSG, RES_BYTES_PROCESSED_MINUTES1, NULL, NULL );
+ sprintf( temp, p, num_minutes );
+ }
+ }
+ else {
+
+ // With out comma's
+
+ if ( num_minutes == 1 ) {
+
+ p = ( CHAR_PTR )RM_GetResource( rm, SES_ENG_MSG, RES_BYTES_PROCESSED_MINUTE2, NULL, NULL );
+ sprintf( temp, p, num_minutes );
+ }
+ else {
+
+ p = ( CHAR_PTR )RM_GetResource( rm, SES_ENG_MSG, RES_BYTES_PROCESSED_MINUTES2, NULL, NULL );
+ sprintf( temp, p, num_minutes );
+ }
+ }
+
+ strcat( buffer, temp );
+ }
+
+ if ( num_seconds == 1 ) {
+
+ p = ( CHAR_PTR )RM_GetResource( rm, SES_ENG_MSG, RES_BYTES_PROCESSED_SECOND, NULL, NULL );
+ sprintf( temp, p, num_seconds );
+ }
+ else {
+
+ p = ( CHAR_PTR )RM_GetResource( rm, SES_ENG_MSG, RES_BYTES_PROCESSED_SECONDS, NULL, NULL );
+ sprintf( temp, p, num_seconds );
+ }
+
+ strcat( buffer, temp );
+
+ yresprintf( (INT16) RES_NEW_PROCESSED_BYTES, buffer );
+
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+
+ lresprintf( (INT16)LOGGING_FILE,
+ (INT16)LOG_MSG,
+ SES_ENG_MSG,
+ RES_NEW_PROCESSED_BYTES,
+ buffer );
+
+ return;
+
+}
+/*****************************************************************************
+
+ Name: UI_RateProcessed
+
+ Description: Processes the display/log of the rate of an operation
+
+ Returns: VOID
+
+*****************************************************************************/
+VOID UI_RateProcessed(
+STATS_PTR op_stats_ptr ) /* I - operation level statistics */
+{
+
+ UINT32 rate ;
+
+ if( CDS_GetDebugFlag( CDS_GetCopy( ) ) & DEBUG_USER_INTERFACE ) {
+
+ rate = U64_Lsw( ST_GetBSRate ( op_stats_ptr ) ) ;
+ yresprintf( (INT16) RES_PROCESS_RATE, rate );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+ }
+
+ return;
+
+}
+
+/*****************************************************************************
+
+ Name: UI_Time
+
+ Description: Processes the display/log of a crucial time for an operation
+
+ Returns: VOID
+
+*****************************************************************************/
+
+VOID UI_Time(
+STATS_PTR op_stats_ptr, /* I - operation level statistics */
+INT res_id, /* I - resource to be displayed/logged */
+UI_TYPE type) /* I - type of crucial time */
+{
+ time_t t_time;
+ CHAR date_str[MAX_UI_DATE_SIZE];
+ CHAR time_str[MAX_UI_TIME_SIZE];
+
+ if( type == UI_START ) {
+ t_time = ST_GetBSStartTime( op_stats_ptr );
+ }
+ else if( type == UI_END ) {
+ t_time = ST_GetBSEndTime( op_stats_ptr );
+ }
+
+ UI_LongToDate( date_str, t_time );
+ UI_LongToTime( time_str, t_time );
+
+
+ yresprintf( (INT16)res_id, date_str, time_str );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+
+ lresprintf( (INT16) LOGGING_FILE, (INT16) LOG_MSG, SES_ENG_MSG, res_id, date_str,
+ time_str );
+
+ return;
+
+}
+
+
+static INT last_file_length;
+
+VOID UI_DisplayFile( CHAR_PTR filename )
+{
+ CHAR buffer[ UI_MAX_FILENAME_LENGTH ];
+ INT cur_file_length;
+ INT i;
+ INT wind_width;
+
+ wind_width = 50; // Fix this !!!!!!
+
+ strcpy( buffer, filename );
+ if ( strlen( buffer ) >= (size_t)wind_width ) {
+ buffer[ wind_width - 4 ] = TEXT('\0');
+ strcat( buffer, UI_TRUNCATION );
+ }
+
+ cur_file_length = strlen( buffer );
+ for ( i = cur_file_length; ( i < last_file_length ); i++ ) {
+ buffer[i] = TEXT(' ');
+ }
+ buffer[i]=TEXT('\0');
+
+ yprintf( TEXT("%s\r"), buffer );
+
+ last_file_length = cur_file_length;
+}
+
+/*****************************************************************************
+
+ Name: UI_ClearLastDisplayedFile
+
+ Description: Clears last displayed filename from status display, called at end of set, end of media, etc.
+
+ Returns: n/a
+
+*****************************************************************************/
+VOID UI_ClearLastDisplayedFile( )
+{
+ /* eliminate last item displayed on screen */
+ if( CDS_GetFilesFlag( CDS_GetCopy( ) ) ) {
+ UI_DisplayFile( TEXT("") );
+ }
+ return;
+}
+/*****************************************************************************
+
+ Name: UI_ConditionAtEnd
+
+ Description: Displays and Logs any appropriate message regarding the abort condition
+
+ Returns: n/a
+
+*****************************************************************************/
+VOID UI_ConditionAtEnd( )
+{
+ switch( gb_abort_flag ) {
+
+ case CONTINUE_PROCESSING:
+ default:
+ break;
+
+ case ABORT_CTRL_BREAK:
+ UI_DisplayBreakMsg();
+ break;
+
+ case ABORT_AT_EOM:
+ WM_MessageBox( ID( RES_ABORT_STRING ),
+ ID( RES_EOM_TAPE_ABORT ),
+ WMMB_OK,
+ WMMB_ICONEXCLAMATION,
+ NULL, 0, 0 );
+ lresprintf( (INT16) LOGGING_FILE, (INT16) LOG_MSG, SES_ENG_MSG, RES_EOM_TAPE_ABORT );
+ break;
+ }
+
+ return;
+
+}
+/*****************************************************************************
+
+ Name: UI_DisplayBreakMsg
+
+ Description: Displays user abort message
+
+ Returns: n/a
+
+*****************************************************************************/
+VOID UI_DisplayBreakMsg( VOID )
+{
+ if ( gb_abort_flag == ABORT_CTRL_BREAK ) {
+
+ gb_abort_flag = ABORT_PROCESSED;
+
+ WM_MessageBox( ID( RES_ABORT_STRING ),
+ ID( RES_USER_TAPE_ABORT ),
+ WMMB_OK,
+ WMMB_ICONEXCLAMATION,
+ NULL, 0, 0 );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_USER_TAPE_ABORT );
+ }
+
+ return;
+
+}
+/*****************************************************************************
+
+ Name: UI_ProcessErrorCode
+
+ Description: Processes Error Code
+
+ Returns: n/a
+
+*****************************************************************************/
+VOID UI_ProcessErrorCode(
+INT16 error,
+INT16_PTR disposition,
+INT16 channel )
+{
+ INT16 resource_id;
+ INT16 print_err_type = DETAIL_PRINT_VALUE;
+ BOOLEAN call_eresprintf_flag = TRUE;
+ CHAR text[MAX_UI_RESOURCE_SIZE];
+ BOOLEAN call_msgbox_flag = FALSE ;
+
+
+
+ switch ( error ) {
+
+ case LP_USER_ABORT_ERROR:
+ case TFLE_USER_ABORT:
+ UI_DisplayBreakMsg( );
+
+ /* falling through */
+
+ case TFLE_UI_HAPPY_ABORT:
+ call_eresprintf_flag = FALSE;
+ break;
+
+ case LP_OUT_OF_MEMORY_ERROR:
+ case TFLE_NO_MEMORY:
+ case TFLE_NO_FREE_BUFFERS:
+ gb_error_during_operation = TRUE;
+ resource_id = RES_OUT_OF_MEMORY;
+ print_err_type = DETAIL_PRINT_ERR_ONLY;
+ *disposition = ABORT_OPERATION;
+ break;
+
+ case TFLE_USE_SYPL_ECC_FLAG:
+ gb_error_during_operation = TRUE;
+ resource_id = RES_USESYPLFLAG;
+ print_err_type = DETAIL_PRINT_ERR_ONLY;
+ *disposition = ABORT_OPERATION;
+ break;
+
+ case TFLE_APPEND_NOT_ALLOWED:
+ case TFLE_BAD_SET_MAP:
+ gb_error_during_operation = TRUE;
+ resource_id = RES_NOAPPEND;
+ print_err_type = DETAIL_PRINT_ERR_ONLY;
+ *disposition = ABORT_OPERATION;
+ break;
+
+ case TFLE_OTC_FAILURE:
+ gb_error_during_operation = TRUE;
+ resource_id = RES_INSUFFICIENT_DISK_SPACE;
+ print_err_type = DETAIL_PRINT_ERR_ONLY;
+ *disposition = ABORT_OPERATION;
+ break;
+
+
+ case TFLE_UNRECOGNIZED_MEDIA:
+ gb_error_during_operation = TRUE;
+ resource_id = IDS_VLMUNFORMATEDTEXT;
+ print_err_type = DETAIL_PRINT_DEVICE;
+ *disposition = ABORT_OPERATION;
+ break;
+
+
+ case TFLE_UNKNOWN_FMT:
+ gb_error_during_operation = TRUE;
+ resource_id = RES_FOREIGN_TAPE_ERROR;
+ print_err_type = DETAIL_PRINT_DEVICE;
+ *disposition = ABORT_OPERATION;
+ break;
+
+ case LP_TAPE_POS_ERROR:
+ msassert( FALSE ) ; // This should be gone for good! GRH 2/5/94
+ gb_error_during_operation = TRUE;
+ resource_id = RES_ERROR_POSITIONING_TAPE;
+ print_err_type = DETAIL_PRINT_DEVICE;
+ *disposition = ABORT_OPERATION;
+ break;
+
+ case TFLE_NO_TAPE:
+ gb_error_during_operation = TRUE;
+ resource_id = RES_EMPTY_DRIVE_ERROR;
+ print_err_type = DETAIL_PRINT_DEVICE;
+ *disposition = ABORT_OPERATION;
+ break;
+
+ case TFLE_TAPE_INCONSISTENCY:
+ gb_error_during_operation = TRUE;
+ resource_id = RES_FATAL_TAPE_FMT_ERR;
+ print_err_type = DETAIL_PRINT_DEVICE;
+ *disposition = ABORT_OPERATION;
+ break;
+
+ case TFLE_TRANSLATION_FAILURE:
+ gb_error_during_operation = TRUE;
+ resource_id = RES_FATAL_TAPE_TRANS_ERR;
+ print_err_type = DETAIL_PRINT_DEVICE;
+ *disposition = ABORT_OPERATION;
+ break;
+
+ case TFLE_DRIVER_FAILURE:
+ case TFLE_DRIVE_FAILURE:
+ case TFLE_BAD_TAPE:
+ case LP_TAPE_READ_ERROR:
+ case LP_TAPE_WRITE_ERROR:
+ call_eresprintf_flag = FALSE;
+ gb_error_during_operation = TRUE;
+ *disposition = ABORT_OPERATION;
+ if( !UI_GetExtendedErrorString( error, text ) ) {
+ RSM_StringCopy( IDS_GENERR_UNDETERMINED, text, MAX_UI_RESOURCE_LEN );
+ }
+
+ // dump it to the log file.
+
+ lprintf( LOGGING_FILE, TEXT("\n" ) );
+ lprintf( LOGGING_FILE, text );
+ lprintf( LOGGING_FILE, TEXT("\n\n" ) );
+
+ // display it to the user.
+
+ WM_MsgBox( ID(IDS_GENERR_TITLE), text, WMMB_OK, WMMB_ICONSTOP );
+ break;
+
+ case TFLE_NO_CONTROLLERS:
+ case TFLE_NO_DRIVES:
+ case TFLE_NO_FREE_CHANNELS:
+ case TFLE_CANNOT_OPEN_DRIVE:
+ gb_error_during_operation = TRUE;
+ resource_id = RES_UNKNOWN_TF_MSG;
+ *disposition = ABORT_OPERATION;
+ break;
+
+ case TFLE_UNEXPECTED_EOS:
+ gb_error_during_operation = TRUE;
+ resource_id = RES_UNEXPECTED_EOS;
+ print_err_type = DETAIL_PRINT_DEVICE;
+ *disposition = ABORT_OPERATION;
+ break;
+
+ case LP_DRIVE_ATTACH_ERROR:
+ gb_error_during_operation = TRUE;
+ resource_id = RES_ERROR_DURING_ATTACH;
+ print_err_type = DETAIL_PRINT_ERROR_DEVICE;
+ *disposition = ABORT_OPERATION;
+ break;
+
+ case LP_END_OPER_FAILED:
+ gb_error_during_operation = TRUE;
+ call_msgbox_flag = TRUE ;
+ call_eresprintf_flag = FALSE ;
+ resource_id = RES_ERROR_EMS_RESTART ;
+ print_err_type = DETAIL_PRINT_ERROR_DEVICE;
+ break;
+
+ case LP_ACCESS_DENIED_ERROR:
+ case FS_BAD_ATTACH_TO_SERVER:
+ call_eresprintf_flag = FALSE;
+ *disposition = SKIP_OBJECT;
+ gb_error_during_operation = TRUE;
+ break;
+
+ case TFLE_WRITE_PROTECT:
+ gb_error_during_operation = TRUE;
+ resource_id = RES_WRITE_PROT;
+ print_err_type = DETAIL_PRINT_DEVICE;
+ *disposition = ABORT_OPERATION;
+ break;
+
+ case TFLE_NO_MORE_DRIVES:
+ case LP_FILE_READ_ERROR:
+ case LP_FILE_NOT_FOUND_ERROR:
+ case LP_FILE_IN_USE_ERROR:
+ case LP_FILE_OPEN_ERROR:
+ case LP_FILE_WRITE_ERROR:
+ case LP_FILE_CREATION_ERROR:
+ case LP_CHANGE_DIRECTORY_ERROR:
+ case LP_PRIVILEGE_ERROR:
+ case LP_OUT_OF_SPACE_ERROR:
+ gb_error_during_operation = TRUE;
+ resource_id = RES_UNKNOWN_LOOPS_ERR;
+ break;
+
+ default:
+
+// Keep customers from seeing -533 error message.
+
+#ifdef MS_RELEASE
+ call_eresprintf_flag = FALSE;
+#endif
+
+ resource_id = RES_UNKNOWN_LOOPS_ERR;
+ break;
+ }
+
+ if ( call_msgbox_flag ) {
+
+ switch( print_err_type ) {
+
+ case DETAIL_PRINT_ERR_ONLY:
+ if ( eresprintf_cancel( resource_id ) ) {
+ *disposition = ABORT_OPERATION;
+ }
+ break;
+
+ case DETAIL_PRINT_VALUE:
+ if ( eresprintf_cancel( resource_id, error ) ) {
+ *disposition = ABORT_OPERATION;
+ }
+ break;
+
+ case DETAIL_PRINT_DEVICE:
+ if( eresprintf_cancel( resource_id, BE_GetCurrentDeviceName( channel ) ) ) {
+ *disposition = ABORT_OPERATION;
+ }
+ break;
+
+ case DETAIL_PRINT_ERROR_DEVICE:
+ if ( eresprintf_cancel( resource_id, error, BE_GetCurrentDeviceName( channel ) ) ) {
+ *disposition = ABORT_OPERATION;
+ }
+ break;
+
+ }
+
+ }
+ if ( call_eresprintf_flag ) {
+
+ switch( print_err_type ) {
+
+ case DETAIL_PRINT_ERR_ONLY:
+ eresprintf( resource_id );
+ break;
+
+ case DETAIL_PRINT_VALUE:
+ eresprintf( resource_id, error );
+ break;
+
+ case DETAIL_PRINT_DEVICE:
+ eresprintf( resource_id, BE_GetCurrentDeviceName( channel ) );
+ break;
+
+ case DETAIL_PRINT_ERROR_DEVICE:
+ eresprintf( resource_id, error, BE_GetCurrentDeviceName( channel ) );
+ break;
+
+ }
+
+ }
+
+ return;
+}
+
+
+static CHAR_PTR LoadGenFuncStr( INT16 gen_func, INT32 gen_misc )
+{
+ CHAR_PTR s;
+
+ s = malloc( 512 * sizeof(CHAR) );
+
+ if ( s != NULL ) {
+
+ switch ( gen_func ) {
+
+ case GEN_INIT:
+ RSM_StringCopy( IDS_GENFUNC_INIT, s, 512 );
+ break;
+
+ case GEN_OPEN:
+ RSM_StringCopy( IDS_GENFUNC_OPEN, s, 512 );
+ break;
+
+ case GEN_NRCLOSE:
+ RSM_StringCopy( IDS_GENFUNC_NRCLOSE, s, 512 );
+ break;
+
+ case GEN_RCLOSE:
+ RSM_StringCopy( IDS_GENFUNC_RCLOSE, s, 512 );
+ break;
+
+ case GEN_READ:
+ RSM_StringCopy( IDS_GENFUNC_READ, s, 512 );
+ break;
+
+ case GEN_WRITE:
+ RSM_StringCopy( IDS_GENFUNC_WRITE, s, 512 );
+ break;
+
+ case GEN_WRITE_ENDSET:
+ RSM_StringCopy( IDS_GENFUNC_WRITE_ENDSET, s, 512 );
+ break;
+
+ case GEN_SPACE:
+
+ switch ( gen_misc ) {
+
+ case SPACE_FWD_FMK:
+ RSM_StringCopy( IDS_GENFUNC_SPACE_FWD_FMK, s, 512 );
+ break;
+
+ case SPACE_BKWD_FMK:
+ RSM_StringCopy( IDS_GENFUNC_SPACE_BKWD_FMK, s, 512 );
+ break;
+
+ case SPACE_EOD:
+ RSM_StringCopy( IDS_GENFUNC_SPACE_EOD, s, 512 );
+ break;
+
+ case SPACE_FWD_BLK:
+ RSM_StringCopy( IDS_GENFUNC_SPACE_FWD_BLK, s, 512 );
+ break;
+
+ case SPACE_BKWD_BLK:
+ RSM_StringCopy( IDS_GENFUNC_SPACE_BKWD_BLK, s, 512 );
+ break;
+
+ default:
+ strcpy( s, TEXT( "" ) );
+ break;
+ }
+ break;
+
+ case GEN_ERASE:
+ RSM_StringCopy( IDS_GENFUNC_ERASE, s, 512 );
+ break;
+
+ case GEN_REWIND:
+ case GEN_REWINDI:
+ RSM_StringCopy( IDS_GENFUNC_REWIND, s, 512 );
+ break;
+
+ case GEN_RETEN:
+ RSM_StringCopy( IDS_GENFUNC_RETEN, s, 512 );
+ break;
+
+ case GEN_STATUS:
+ RSM_StringCopy( IDS_GENFUNC_STATUS, s, 512 );
+ break;
+
+ case GEN_RELEASE:
+ RSM_StringCopy( IDS_GENFUNC_RELEASE, s, 512 );
+ break;
+
+ case GEN_SEEK:
+ RSM_StringCopy( IDS_GENFUNC_SEEK, s, 512 );
+ break;
+
+ case GEN_GETPOS:
+ RSM_StringCopy( IDS_GENFUNC_GETPOS, s, 512 );
+ break;
+
+ case GEN_MOUNT:
+ RSM_StringCopy( IDS_GENFUNC_MOUNT, s, 512 );
+ break;
+
+ case GEN_DISMOUNT:
+ RSM_StringCopy( IDS_GENFUNC_DISMOUNT, s, 512 );
+ break;
+
+ case GEN_SPECIAL:
+ if ( gen_misc == SS_GET_DRV_INF ) {
+ RSM_StringCopy( IDS_GENFUNC_SPECIAL_GET_INFO, s, 512 );
+ }
+ else {
+ if ( gen_misc == SS_CHANGE_BLOCK_SIZE ) {
+ RSM_StringCopy( IDS_GENFUNC_SPECIAL_CHNG_BLK_SIZE, s, 512 );
+ }
+ else {
+ RSM_StringCopy( IDS_GENFUNC_SPECIAL_SET_COMPRESS, s, 512 );
+ }
+ }
+ break;
+
+ case GEN_EJECT:
+ RSM_StringCopy( IDS_GENFUNC_EJECT, s, 512 );
+ break;
+
+ default:
+ strcpy( s, TEXT( "" ) );
+ break;
+
+ }
+ }
+
+ return( s );
+
+}
+
+
+static CHAR_PTR LoadGenErrStr( INT16 gen_err )
+{
+ CHAR_PTR s;
+
+ s = malloc( 512 * sizeof(CHAR) );
+
+ if ( s != NULL ) {
+
+ switch ( gen_err ) {
+
+ case GEN_ERR_TIMEOUT:
+ RSM_StringCopy( IDS_GENERR_TIMEOUT, s, 512 );
+ break;
+
+ case GEN_ERR_EOM:
+ RSM_StringCopy( IDS_GENERR_EOM, s, 512 );
+ break;
+
+ case GEN_ERR_BAD_DATA:
+ RSM_StringCopy( IDS_GENERR_BAD_DATA, s, 512 );
+ break;
+
+ case GEN_ERR_NO_MEDIA:
+ RSM_StringCopy( IDS_GENERR_NO_MEDIA, s, 512 );
+ break;
+
+ case GEN_ERR_ENDSET:
+ RSM_StringCopy( IDS_GENERR_ENDSET, s, 512 );
+ break;
+
+ case GEN_ERR_NO_DATA:
+ RSM_StringCopy( IDS_GENERR_NO_DATA, s, 512 );
+ break;
+
+ case GEN_ERR_INVALID_CMD:
+ RSM_StringCopy( IDS_GENERR_INVALID_CMD, s, 512 );
+ break;
+
+ case GEN_ERR_RESET:
+ RSM_StringCopy( IDS_GENERR_RESET, s, 512 );
+ break;
+
+ case GEN_ERR_WRT_PROTECT:
+ RSM_StringCopy( IDS_GENERR_WRT_PROTECT, s, 512 );
+ break;
+
+ case GEN_ERR_HARDWARE:
+ RSM_StringCopy( IDS_GENERR_HARDWARE, s, 512 );
+ break;
+
+ case GEN_ERR_EOM_OVERFLOW:
+ RSM_StringCopy( IDS_GENERR_EOM_OVERFLOW, s, 512 );
+ break;
+
+ case GEN_ERR_WRONG_BLOCK_SIZE:
+ RSM_StringCopy( IDS_GENERR_WRONG_BLOCK_SIZE, s, 512 );
+ break;
+
+ case GEN_ERR_UNRECOGNIZED_MEDIA:
+ RSM_StringCopy( IDS_GENERR_UNRECOGNIZED_MEDIA, s, 512 );
+ break;
+
+ case GEN_ERR_UNDETERMINED:
+ default:
+ RSM_StringCopy( IDS_GENERR_UNDETERMINED, s, 512 );
+ break;
+
+ }
+ }
+
+ return( s );
+
+}
+
+/*****************************************************************************
+
+ Name: UI_GetExtendedErrorString
+
+ Description: This function attempts to get a more detailed description
+ of tape drive errors from tape format, and fill out 'msg'
+ with an appropriate error message.
+
+ Returns: BOOLEAN - TRUE if successful
+
+ Note: The 'msg' parameter should point to a string of a least
+ MAX_UI_RESOURCE_SIZE in length.
+
+*****************************************************************************/
+BOOLEAN UI_GetExtendedErrorString( INT16 error, CHAR_PTR msg )
+{
+ CHAR format_string[MAX_UI_RESOURCE_SIZE] ;
+ CHAR_PTR func_string ;
+ CHAR_PTR error_string ;
+ INT16 gen_func ;
+ INT16 gen_err ;
+ INT32 gen_misc ;
+ BOOLEAN ret_val = FALSE ;
+
+ if( TF_GetLastDriveError( thw_list, &gen_func, &gen_err, &gen_misc ) ) {
+ if( ( func_string = LoadGenFuncStr( gen_func, gen_misc ) ) != NULL ) {
+ if ( error != TFLE_DRIVER_FAILURE && error != PD_DRIVER_FAILURE ) {
+ if( ( error_string = LoadGenErrStr( gen_err ) ) != NULL ) {
+ RSM_StringCopy( IDS_GENERR_DRIVE_FAILED, format_string, MAX_UI_RESOURCE_LEN ) ;
+ sprintf( msg, format_string, func_string, error_string ) ;
+ ret_val = TRUE ;
+ free( error_string ) ;
+ }
+ } else {
+ if ( gen_func == GEN_SPECIAL ) {
+ RSM_StringCopy( IDS_GENERR_DRIVER_FAIL2, format_string, MAX_UI_RESOURCE_LEN ) ;
+ } else {
+ RSM_StringCopy( IDS_GENERR_DRIVER_FAIL1, format_string, MAX_UI_RESOURCE_LEN ) ;
+ }
+ sprintf( msg, format_string, func_string ) ;
+ ret_val = TRUE ;
+ }
+ free( func_string ) ;
+ }
+ }
+
+ return( ret_val ) ;
+}
+
+
+
+/*****************************************************************************
+
+ Name: UI_TapeDriveCount
+
+ Description: This function returns a count of the number of tape
+ drives found within the current channel (global thw_list).
+ This function is used by the backup message handler to prompt
+ the user to insert tapes w-x in tape drives y-z.
+
+ Returns: INT8 count of tape drives
+
+*****************************************************************************/
+INT8 UI_TapeDriveCount( )
+{
+ Q_ELEM_PTR cur_thw = NULL;
+ INT8 num_drives = 0;
+
+ if ( thw_list->channel_link.q_next != NULL ) {
+ num_drives++;
+ cur_thw = (Q_ELEM_PTR) thw_list->channel_link.q_next;
+ }
+
+ while( cur_thw != NULL ) {
+ num_drives++;
+ cur_thw = (Q_ELEM_PTR) cur_thw->q_next;
+ }
+ return( num_drives );
+}
+/*****************************************************************************
+
+ Name: UI_CheckWriteProtectedDevice
+
+ Description: Returns BOOLEAN indication of whether media in current
+ device is write-protected or not. This function is
+ called by backup and tension/erase tape positioners.
+
+ Returns:
+
+*****************************************************************************/
+BOOLEAN UI_CheckWriteProtectedDevice(
+UINT16 tf_message,
+TPOS_PTR tpos,
+CHAR_PTR drive_name)
+{
+ BOOLEAN write_prot = FALSE;
+
+ switch( tf_message ) {
+
+ case TF_VCB_EOD:
+ case TF_VCB_BOT:
+ case TF_INVALID_VCB:
+ case TF_EMPTY_TAPE:
+ case TF_POSITIONED_AT_A_VCB:
+ case TF_REQUESTED_VCB_FOUND:
+ case TF_FUTURE_REV_MTF:
+ case TF_MTF_ECC_TAPE:
+ case TF_SQL_TAPE:
+ case TF_TAPE_OUT_OF_ORDER:
+ case TF_UNRECOGNIZED_MEDIA:
+ /* quality check device for write-protect and produce error if required */
+ if( ( write_prot = BE_DeviceWriteProtected( tpos->channel ) ) ) {
+ eresprintf( RES_WRITE_PROT, drive_name );
+ }
+
+ default:
+ break;
+
+ }
+
+ return( write_prot );
+}
+/*****************************************************************************
+
+ Name: UI_FixPath
+
+ Description: Shortens and inserts ... into path specified
+
+ Returns:
+
+*****************************************************************************/
+VOID UI_FixPath(
+CHAR_PTR path_ptr, /* Path to fix */
+INT16 len, /* What length? */
+CHAR delim) /* Path delimiter character */
+{
+ CHAR_PTR src;
+ CHAR_PTR dst;
+ CHAR last_item[ UI_MAX_FILENAME_LENGTH ];
+ CHAR_PTR begin_path = path_ptr;
+ INT last_item_len;
+ CHAR delimiter[ 2 ];
+ BOOLEAN trunc_last = FALSE ;
+ BOOLEAN leading_dots;
+
+ delimiter[ 1 ] = TEXT('\0');
+ delimiter[ 0 ] = delim;
+
+ if( (INT16)strlen( path_ptr ) >= len ) {
+
+ src = strrchr( path_ptr, delimiter[ 0 ] );
+ dst = last_item;
+
+ // quick kludge for macintosh paths.
+
+ if ( src == NULL ) {
+ path_ptr[ len - 3 ] = 0;
+ strcat( path_ptr, UI_TRUNCATION );
+ return;
+ }
+
+ if ( src == path_ptr ) {
+ leading_dots = FALSE;
+ } else {
+ leading_dots = TRUE;
+ }
+
+ while( *src ) {
+ *dst++ = *src++;
+ }
+
+ *dst = TEXT('\0');
+ last_item_len = strlen( last_item );
+ src = strrchr( path_ptr, delim );
+ *src = TEXT('\0');
+
+ /*
+ * If the last item is itself larger than than the window, we
+ * have to truncate the last_item, not the path...
+ */
+ if ( ( last_item_len + 4 ) >= len ) {
+
+ if ( leading_dots ) {
+ *(last_item + len - 7) = TEXT('\0');
+ } else {
+ *(last_item + len - 4) = TEXT('\0');
+ }
+
+ *path_ptr = TEXT('\0');
+ trunc_last = TRUE;
+
+ } else {
+
+// chs:03-18-93 while( (INT16)strlen( path_ptr ) + 4 + last_item_len >= len ) {
+// chs:03-18-93 StripLastItem( path_ptr, delim );
+// chs:03-18-93 }
+
+ while( ( (INT16)strlen( path_ptr ) + 4 + last_item_len >= len ) && // chs:03-18-93
+ StripLastItem( path_ptr, delim ) ); // chs:03-18-93
+ // chs:03-18-93
+ // // chs:03-18-93
+ // Just incase after stripping the file name is still too long // chs:03-18-93
+ // In NT file name can be 256 char long, this will never fit // chs:03-18-93
+ // in the display dialog box. FOR NOW just chop it-off. // chs:03-18-93
+ // // chs:03-18-93
+ // chs:03-18-93
+ if ( (INT16)strlen( path_ptr ) + 4 + last_item_len >= len ) { // chs:03-18-93
+ if ( last_item_len >= len ) { // chs:03-18-93
+ last_item_len = last_item_len - (INT16)strlen( path_ptr ) - 4 - 1; // chs:03-18-93
+ last_item[ last_item_len] = TEXT('\0'); // chs:03-18-93
+ } else { // chs:03-18-93
+ last_item_len = len - (INT16)strlen( path_ptr ) - 4 - 1; // chs:03-18-93
+ last_item[ len] = TEXT('\0'); // chs:03-18-93
+ } // chs:03-18-93
+ } // chs:03-18-93
+ }
+
+
+ if ( leading_dots ) {
+ strcat( path_ptr, delimiter );
+ strcat( path_ptr, UI_TRUNCATION );
+ }
+
+ strcat( path_ptr, last_item );
+
+ /* Put up trailing ellipses, if necessary */
+ if ( trunc_last ) {
+ strcat( path_ptr, UI_TRUNCATION );
+ }
+
+ }
+
+ return;
+
+}
+/*****************************************************************************
+
+ Name: StripLastItem
+
+ Description:
+
+ Returns: true - strip was successful
+ false - strip failed.
+
+ chs:03-18-93 - modified to return a boolean value.
+
+*****************************************************************************/
+static BOOLEAN StripLastItem(
+CHAR_PTR buffer,
+CHAR delim)
+{
+ CHAR_PTR src;
+
+ src = strrchr( buffer, delim );
+ if( src != NULL ) {
+ *src = TEXT('\0');
+ } else {
+ return( FALSE );
+ }
+
+ return ( TRUE );
+
+}
+/*****************************************************************************
+
+ Name: UI_TruncateString
+
+ Description: Truncates strings to a specified maximum length possible appending
+ UI_TRUNCATION. Spaces are turned into 0xff if replace_spaces is TRUE.
+
+ Returns: VOID
+
+*****************************************************************************/
+VOID UI_TruncateString(
+CHAR_PTR buffer, /* O - buffer in which to build the truncation */
+INT16 length, /* I - maximum strlen( buffer ) on return */
+BOOLEAN replace_spaces) /* I - replace spaces ? */
+{
+ CHAR_PTR p = buffer;
+
+ if( (INT16)strlen( buffer ) > length ) {
+ buffer[ length - strlen( UI_TRUNCATION ) ] = TEXT('\0');
+ strcat( buffer, UI_TRUNCATION );
+ }
+
+ if( replace_spaces ) {
+ while( *p != TEXT('\0') ) {
+ if( *p == 0x20 ) {
+ *p = (CHAR) 0xff;
+ }
+ p++;
+ }
+ }
+
+ return;
+
+}
+/*****************************************************************************
+
+ Name: UI_DisplayableTapeName
+
+ Description:
+
+ Returns:
+
+*****************************************************************************/
+CHAR_PTR UI_DisplayableTapeName(
+CHAR_PTR tape_name,
+DATE_TIME_PTR date)
+{
+ static CHAR return_name[ MAX_TAPE_NAME_LEN + 1 ];
+
+ if ( ( tape_name == NULL ) || ( * tape_name == TEXT('\0') ) ) {
+ strcpy( return_name, mw_tape_created );
+ if ( date != NULL ) {
+ DateTimeToDateString( date, return_name + strlen( mw_tape_created ) );
+ }
+ msassert( strlen( return_name ) <= MAX_TAPE_NAME_LEN );
+
+ return( return_name );
+
+ }
+ else {
+
+ return( tape_name );
+
+ }
+}
+/*****************************************************************************
+
+ Name: UI_MaxDirectoryLength
+
+ Description:
+
+ Returns:
+
+*****************************************************************************/
+INT16 UI_MaxDirectoryLength( VOID )
+{
+ CHAR_PTR p;
+ CHAR_PTR q;
+
+ p = ( CHAR_PTR )RM_GetResource( rm, SES_ENG_MSG, RES_DIRECTORY, NULL, NULL );
+ q = strstr( p, TEXT("%") );
+
+ return( 80 ); // Fix this too !!!!
+
+}
+
+/*****************************************************************************
+
+ Name: UI_GetTickCount
+
+ Description: gets the current tick count - only for OS/2
+
+ Returns: tick count - UINT32
+
+*****************************************************************************/
+#if defined( MAYN_OS2 )
+
+VOID UI_GetTickCount( UINT32 *tick_count_ptr )
+{
+ SEL global_seg_sel;
+ SEL local_seg_sel;
+ PGINFOSEG global_info_ptr;
+
+
+ DosGetInfoSeg( &global_seg_sel, &local_seg_sel );
+ global_info_ptr = MAKEPGINFOSEG(global_seg_sel );
+ *tick_count_ptr = ( ( global_info_ptr->msecs*18L )/1000L );
+
+ return;
+}
+#endif
diff --git a/private/utils/ntbackup/src/detfmt.c b/private/utils/ntbackup/src/detfmt.c
new file mode 100644
index 000000000..d4700e860
--- /dev/null
+++ b/private/utils/ntbackup/src/detfmt.c
@@ -0,0 +1,391 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: detfmt.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the format determiners.
+
+
+ $Log: T:/LOGFILES/DETFMT.C_V $
+
+ Rev 1.16 13 Jul 1993 19:17:42 GREGG
+Removed reporting of ECC and future rev tapes as foreign in MTF determiner.
+
+ Rev 1.15 04 Jun 1993 18:41:00 GREGG
+If the tape has ECC, report it as foreign.
+
+ Rev 1.14 11 May 1993 21:55:34 GREGG
+Moved Sytos translator stuff from layer-wide area to translator.
+
+ Rev 1.13 22 Apr 1993 03:31:36 GREGG
+Third in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Removed all references to the DBLK element 'string_storage_offset',
+ which no longer exists.
+ - Check for incompatable versions of the Tape Format and OTC and deals
+ with them the best it can, or reports tape as foreign if they're too
+ far out. Includes ignoring the OTC and not allowing append if the
+ OTC on tape is a future rev, different type, or on an alternate
+ partition.
+ - Updated OTC "location" attribute bits, and changed definition of
+ CFIL to store stream number instead of stream ID.
+
+Matches: TFL_ERR.H 1.9, MTF10WDB.C 1.7, TRANSLAT.C 1.39, FMTINF.H 1.11,
+ OTC40RD.C 1.24, MAYN40RD.C 1.56, MTF10WT.C 1.7, OTC40MSC.C 1.20
+ DETFMT.C 1.13, MTF.H 1.4
+
+ Rev 1.12 17 Mar 1993 15:18:58 TERRI
+Added changes for the Sytos Plus translator.
+
+ Rev 1.11 24 Nov 1992 18:16:24 GREGG
+Updates to match MTF document.
+
+ Rev 1.10 22 Oct 1992 10:45:34 HUNTER
+Changes for new stream headers
+
+
+ Rev 1.9 22 Sep 1992 08:58:46 GREGG
+Initial changes to handle physical block sizes greater than 1K.
+
+ Rev 1.8 24 Jul 1992 14:00:02 GREGG
+Moved include of translator header inside tranlator's ifdef.
+
+ Rev 1.7 09 Jun 1992 15:51:16 GREGG
+Call F40 specific CalcChecksum.
+
+ Rev 1.6 23 Apr 1992 10:54:08 BURT
+Added determiner for Sytos Plus read translator.
+
+
+ Rev 1.5 13 Apr 1992 15:37:40 BURT
+Standard'ified the code.
+
+
+ Rev 1.4 25 Mar 1992 19:26:42 GREGG
+ROLLER BLADES - Added 4.0 format determiner.
+
+ Rev 1.3 07 Jan 1992 14:00:18 ZEIR
+Added UTF support.
+
+ Rev 1.2 07 Jun 1991 00:09:16 GREGG
+Added compiler directives to allow selective inclusion of translators, and
+inherited the Sytos determiner from fsytrd.c.
+
+ Rev 1.1 10 May 1991 11:57:44 GREGG
+Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:18:54 GREGG
+Initial revision.
+
+**/
+/* begin include list */
+#include <string.h>
+#include <stdio.h>
+
+#include "stdtypes.h"
+#include "stdmacro.h"
+#include "tbe_defs.h"
+#include "datetime.h"
+
+#include "drive.h"
+#include "channel.h"
+#include "fmteng.h"
+#include "transutl.h"
+#include "fsys.h"
+#include "tloc.h"
+#include "lw_data.h"
+#include "tfldefs.h"
+
+#include "transprt.h"
+
+/* $end$ include list */
+
+#ifdef MY40_TRANS
+
+#include "mayn40.h"
+
+/**/
+/**
+
+ Name: F40_Determiner
+
+ Description: This function determines whether or not the buffer
+ contains a valid 4.0 format block
+
+ Returns: TRUE if the block is a valid 4.0 format, and FALSE if
+ it is not.
+
+ Notes: This routine assumes the buffer is at least
+ min_siz_for_dblk bytes long.
+
+**/
+
+BOOLEAN F40_Determiner(
+ VOID_PTR buf_ptr ) /* Current Buffer */
+{
+ BOOLEAN ret_val = FALSE ;
+ MTF_DB_HDR_PTR cur_hdr = (MTF_DB_HDR_PTR)buf_ptr ;
+ MTF_TAPE_PTR cur_tape = (MTF_TAPE_PTR)buf_ptr ;
+
+ /* If it check sums and the type is valid */
+ if( F40_CalcChecksum( (UINT16_PTR)cur_hdr, F40_HDR_CHKSUM_LEN ) == cur_hdr->hdr_chksm ) {
+ if( F40_GetBlkType( cur_hdr ) == F40_TAPE_IDI ) {
+ ret_val = TRUE ;
+ }
+ }
+
+ return( ret_val ) ;
+}
+#endif
+
+
+#ifdef MY31_TRANS
+
+#include "mayn31.h"
+
+/**/
+/**
+
+ Name: F31_Determiner
+
+ Description: This function determines whether or not the buffer
+ contains a valid 3.1 format block
+
+ Returns: TRUE if the block is a valid 3.1 format, and FALSE if
+ it is not.
+
+ Notes: This routine assumes the buffer is at least
+ min_siz_for_dblk bytes long.
+
+**/
+
+BOOLEAN F31_Determiner(
+ VOID_PTR buf_ptr ) /* Current Buffer */
+{
+ BOOLEAN ret_val = FALSE ;
+ DB_HDR_PTR cur_hdr = ( DB_HDR_PTR ) buf_ptr ;
+
+ /* If it check sums and the type is valid */
+ if( cur_hdr->hdr_chksm == ( CalcChecksum( ( UINT16_PTR ) cur_hdr, F31_HDR_CHKSUM_LEN ) ) ) {
+ if( cur_hdr->type == F31_VCB_ID ) {
+ ret_val = TRUE ;
+ }
+ }
+
+ return( ret_val ) ;
+}
+#endif
+
+#ifdef MY30_TRANS
+
+#include "mayn30.h"
+
+/**/
+/**
+
+ Name: F30_Determiner
+
+ Description: Determines if the current buffer contains a valid 3.0
+ format header block
+
+ Returns: TRUE if this is a valid 3.0 format, and FALSE if it is
+ not.
+
+ Notes: NONE
+
+**/
+
+BOOLEAN F30_Determiner(
+ VOID_PTR buffer )
+{
+ DB_HDR_30_PTR cur_hdr = ( DB_HDR_30_PTR ) buffer ;
+ BOOLEAN ret_val = FALSE ;
+
+ /* If the Check Sums match and there is a block type, then this is
+ format 3.1 */
+ if( CalcChecksum( ( UINT16_PTR ) cur_hdr, F30_HDR_CHKSUM_LEN ) == cur_hdr->hdr_chksm && cur_hdr->type == FMT30_VCB ) {
+ ret_val = TRUE ;
+ }
+
+ return( ret_val ) ;
+
+}
+#endif
+
+#ifdef MY25_TRANS
+
+#include "mayn25.h"
+
+/**/
+/**
+
+ Name: F25_Determiner
+
+ Description: Determines if this is a Maynard 2.0 - 2.5 Format tape.
+
+ Returns: TRUE if it is a 2.0 - 2.5 tape, and FALSE if it is not.
+
+ Notes: If the psycho ward isn't guarded closely, someday this
+ could be changed to support even early formats.
+
+**/
+
+BOOLEAN F25_Determiner(
+ VOID_PTR buf_ptr )
+{
+ F25_VCB_PTR v_ptr = (F25_VCB_PTR)buf_ptr ;
+ BOOLEAN ret = FALSE ;
+
+ /* See if format indicator is present */
+ if( ( v_ptr->vblkid == BLK_VCB ) ||
+ ( v_ptr->vblkid == BLK_EOV ) ||
+ ( v_ptr->vblkid == BLK_NEW_VCB ) ||
+ ( v_ptr->vblkid == BLK_NEW_EOV ) ) {
+
+ /* If >= 2.0 format then checksum */
+ if( ( v_ptr->vswlev >= 9 ) || ( v_ptr->vswver == 2 && v_ptr->vswlev == 5 ) ) {
+ if( ( F25_Chksm( (CHAR_PTR)v_ptr, siz_vcbs( *v_ptr ) ) == v_ptr->vcb_chksum ) ) {
+ ret = TRUE ;
+ }
+ }
+ }
+
+ return( ret ) ;
+}
+#endif
+
+#ifdef QS19_TRANS
+
+#include "fq.h"
+
+/**/
+/**
+
+ Name: FQ_DetermineFormat
+
+ Description: look at a buffered tape block (first block read from
+ a tape) and determine if it's QicStream.
+
+ Returns: BOOLEAN -- TRUE if this is QS1.92 or QS1.93 format.
+
+ Notes: NONE
+
+**/
+
+BOOLEAN FQ_DetermineFormat(
+ VOID_PTR buf )
+{
+ register FQ_HEADER_PTR hdr = ( FQ_HEADER_PTR ) buf ;
+
+ /* check for failure */
+ return (! (strncmp( (char *)hdr->signature, FQ_FPR_SIGNATURE, FQ_SIGNATURE_SIZE ) != 0
+ || hdr->format_code != 1
+ || hdr->first_logical_segment != 2
+ || strncmp( (char *)hdr->manufacturer_name, FQ_MFG_NAME, FQ_MFG_NAME_SIZE ) != 0
+ || hdr->manufacturer_name[ FQ_MFG_NAME_SIZE ] > '3'
+ || hdr->manufacturer_name[ FQ_MFG_NAME_SIZE ] < '2' ) ) ;
+}
+#endif
+
+#ifdef SY31_TRANS
+
+#include "fsytos.h"
+
+/**/
+/**
+
+ Name: FSYT_DetermineFormat
+
+ Description: Given a pointer to data from the beginning of a set,
+ determine if this format recognizes the data.
+
+ Returns: TRUE if the block is a valid Sytos 3.11 format, and
+ FALSE if it is not.
+
+ Notes: NONE
+
+**/
+
+BOOLEAN FSYT_DetermineFormat( VOID_PTR buffer )
+{
+ TAPE_HEADER_PTR header = buffer ;
+
+ return ( header->blkid == TAPE_HEADER_MARKER ) ;
+}
+#endif
+
+
+#ifdef SYPL10_TRANS
+
+#include "sypl10.h"
+
+/**/
+/**
+
+ Name: SYPL_DetermineFormat
+
+ Description: Given a pointer to data from the beginning of a set,
+ determine if this format recognizes the data.
+
+ Returns: TRUE if the block is a valid Sytos Plus 1.0 format, and
+ FALSE if it is not.
+
+ Notes: NONE
+
+**/
+
+BOOLEAN SYPL_DetermineFormat( VOID_PTR buffer )
+{
+ S10_COMMON_HEADER_PTR header = buffer ;
+ static UINT8 uniq_id[] = S10_UNIQ_ID ;
+
+ /* compare the unique id with the one on tape */
+ if( memicmp( header->uniq_tape_id, uniq_id, UNQ_HDR_ID_LEN ) ) {
+ return FALSE ;
+ }
+ /* return the results of the tape header check */
+ return( header->type == tape_header_type ) ;
+}
+#endif
+
+#ifdef UTF_TRANS
+
+#include "utf.h"
+
+/**
+ *
+ * Unit: Unit_X
+ *
+ * Name: UTF_Determiner
+ *
+ * Modified: 01/07/92
+ *
+ * Description: Determines whether the given buffer contains a valid UTF
+ * header signature
+ * Notes:
+ *
+ * Returns: TRUE - if buffer contains UTF information
+ * FALSE - otherwise
+ *
+ * Global Data: None
+ *
+**/
+
+
+BOOLEAN UTF_Determiner(
+
+ VOID_PTR buf_ptr
+)
+{
+ SIGNATURE_HEADER_T *shdr = (SIGNATURE_HEADER_T *)buf_ptr ;
+
+ return shdr->id == T_SIGNATURE &&
+ shdr->subtag == TS_TAPE_HEADER_SIGNATURE &&
+ shdr->size == 4 &&
+ !strncmp( shdr->string, "UTF ", 4 ) ;
+}
+#endif
diff --git a/private/utils/ntbackup/src/dettpdrv.c b/private/utils/ntbackup/src/dettpdrv.c
new file mode 100644
index 000000000..371d67ebb
--- /dev/null
+++ b/private/utils/ntbackup/src/dettpdrv.c
@@ -0,0 +1,205 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: dettpdrv.c
+
+ Description: Functions to determine starting tape drive for operations and
+ set the last tape drive used at close set time.
+
+ $Log: N:/LOGFILES/DETTPDRV.C_V $
+
+ Rev 1.2 18 Sep 1991 15:59:20 DON
+cast 'future use' tpos parm to void so we don't get warnings
+
+ Rev 1.1 24 May 1991 13:12:24 STEVEN
+changed to ANSI prototypes
+
+ Rev 1.0 09 May 1991 13:40:00 HUNTER
+Initial revision.
+
+**/
+#include "stdtypes.h"
+#include "loops.h"
+#include "bsdu.h"
+#include "tflproto.h"
+#include "tflstats.h"
+#include "genstat.h"
+#include "be_debug.h"
+
+THW_PTR lw_last_tpdrv = NULL ;
+THW_PTR lw_toc_tpdrv = NULL ;
+
+/**/
+/**
+
+ Name: LP_DetermineStartingTPDrv
+
+ Description: Given an operation type, a current BSD pointer and TPOS pointer,
+ this function determine whether to starting drive for the
+ operation should begin on the current drive or the Top Of Channel.
+
+
+ Modified: 3/29/1990
+
+ Returns: THW_PTR to starting device
+
+ Notes: Backup, restore, verify and directory operations will start
+ on the current device unless a specific device has already been
+ specified in the BSD and we are auto-determining the starting drive.
+
+ Tension, erase and catalog a tape operations will always
+ start at TOC.
+
+ MBS should have already set "auto_det_sdrv" in the LIS structure
+ to FALSE indicating that the THW_PTR in the current BSD should
+ ALWAYS be used instead of setting the current drive to the last
+ active drive. Note that MBS continually redefines the drive
+ channel, whereas, MaynStream for DOS specifies the drive channel
+ at init time and does not alter it.
+
+ It should also be noted that although restore and verify operations
+ simply use the last active drive, TF will auto-locate any specific tape
+ requested through specific position information and will set this
+ device to the starting drive. If the specific tape desired is not located
+ within the channel, TF will call the tape positioner requesting a new
+ tape in drive 1.
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+THW_PTR LP_DetermineStartingTPDrv(
+INT16 oper_type, /* I - Specifies what operation */
+BSD_PTR bsd_ptr, /* I - Specifies what backup set */
+TPOS_PTR tpos, /* I - Specifies the tape position */
+BOOLEAN auto_determine_sdrv ) /* I - TRUE if we should determine */
+{
+ THW_PTR sdrv ;
+
+ /* future use */
+ (VOID) tpos ;
+
+ /* If we are not to auto-determine starting drive based upon last active drive, and
+ a pre-specified starting device (THW_PTR) has already been defined
+ for this BSD, simply return this device as the starting device */
+ if( !auto_determine_sdrv && ( bsd_ptr != NULL ) && ( BSD_GetTHW( bsd_ptr ) != NULL ) ) {
+ return( BSD_GetTHW( bsd_ptr ) ) ;
+ }
+
+ /* Otherwise, define starting device based upon the operation type... */
+
+ switch( oper_type ) {
+
+ case BACKUP_OPER:
+ case ARCHIVE_BACKUP_OPER:
+ case TDIR_OPER:
+ case RESTORE_OPER:
+ case VERIFY_OPER:
+
+ /* Use last accessed device as starting drive */
+ sdrv = lw_last_tpdrv ;
+
+ /* Update current bsd to reflect starting drive */
+ if( bsd_ptr != NULL ) {
+ BSD_SetTHW( bsd_ptr, sdrv ) ;
+ }
+
+ break ;
+
+ case ARCHIVE_VERIFY_OPER:
+ case VERIFY_LAST_BACKUP_OPER:
+ case VERIFY_LAST_RESTORE_OPER:
+
+ /* Set starting drive to starting drive specified in BSD */
+ if( bsd_ptr != NULL ) {
+ sdrv = BSD_GetTHW( bsd_ptr ) ;
+ }
+ break ;
+
+ case TENSION_OPER:
+ case ERASE_OPER:
+ case ERASE_NO_READ_OPER:
+ case SECURITY_ERASE_OPER:
+ case CATALOG_TAPE_OPER:
+ default:
+
+ /* Always start these operations at the Top Of Channel */
+ sdrv = lw_toc_tpdrv ;
+ break ;
+
+ }
+
+ return( sdrv ) ;
+}
+/**/
+/**
+
+ Name: LP_DetermineCurrentTPDrv
+
+ Description: This function is called by LP_BackupDLE to determine what
+ the current device for the operation is. In this way, the
+ BSD is updated to reflect the actual drive where the write
+ operation started.
+
+ Modified: 3/29/1990
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( LP_BackupDLE() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID LP_DetermineCurrentTPDrv(
+BSD_PTR bsd_ptr, /* I - Specifies what backup set */
+INT16 channel ) /* I - Specifies which drive chain */
+{
+ BSD_SetTHW( bsd_ptr, TF_GetCurrentDevice( channel ) ) ;
+ return ;
+}
+/**/
+/**
+
+ Name: LP_CloseSet
+
+ Description: This function sets the layer wide "lw_last_tpdrv" variable
+ to reflect the last used device, calls TF to close the
+ current set and posts soft error and underrun stats in
+ the debug window.
+
+ Modified: 3/29/1990
+
+ Returns: N/A
+
+ Notes: This function is only called for "normal" close set
+ functionality. The specific loops functions that would
+ call this function will continue to call TF_CloseSet
+ directly in error conditions.
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID LP_CloseSet(
+INT16 channel ) /* I - Specifies the which drive chain */
+{
+ TF_STATS close_stats ;
+
+ /* Determine last drive in channel accessed */
+ lw_last_tpdrv = TF_GetCurrentDevice( channel ) ;
+
+ TF_CloseSet( channel, &close_stats ) ;
+ BE_Zprintf( DEBUG_LOOPS, RES_SOFT_ERRORS_UNDERRUNS,
+ close_stats.dataerrs, close_stats.underruns ) ;
+
+ return ;
+}
+
diff --git a/private/utils/ntbackup/src/dialmang.c b/private/utils/ntbackup/src/dialmang.c
new file mode 100644
index 000000000..836cac5d1
--- /dev/null
+++ b/private/utils/ntbackup/src/dialmang.c
@@ -0,0 +1,604 @@
+/****************************************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: dialmang.c
+
+ Description: Contains the Dialog Manager kernel.
+
+ $Log: G:\ui\logfiles\dialmang.c_v $
+
+ Rev 1.36 02 Aug 1993 17:08:24 CHUCKB
+Ifdef wait-for-device dialog for NT only.
+
+ Rev 1.35 30 Jul 1993 16:07:56 CHUCKB
+Added DM_WaitForDevice.
+
+ Rev 1.34 14 Jul 1993 09:23:38 CARLS
+added call for skipno dialog
+
+ Rev 1.33 13 Jul 1993 17:22:26 MARINA
+enable c++, correct DialogCallBackTable decl/init
+
+ Rev 1.32 25 May 1993 14:23:18 chrish
+Added new "DM_Abort" backup/restore abort dialog window procedure.
+
+ Rev 1.31 15 May 1993 13:41:26 MIKEP
+remove next set dialog
+
+ Rev 1.30 07 Mar 1993 10:57:04 MIKEP
+warning fixes for NT
+
+ Rev 1.29 18 Feb 1993 11:32:04 BURT
+Change for Cayman
+
+
+ Rev 1.28 01 Nov 1992 15:45:28 DAVEV
+Unicode changes
+
+ Rev 1.27 31 Oct 1992 14:56:20 MIKEP
+continue adding small catalog dialog
+
+ Rev 1.26 07 Oct 1992 15:37:00 MIKEP
+fix nt warnings
+
+ Rev 1.25 07 Oct 1992 13:43:36 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.24 04 Oct 1992 19:32:44 DAVEV
+Unicode Awk pass
+
+ Rev 1.23 21 Sep 1992 17:18:20 DARRYLP
+Updates for WFW email.
+
+ Rev 1.22 17 Sep 1992 18:20:16 DARRYLP
+New WFW email stuff...
+
+ Rev 1.21 09 Sep 1992 16:13:42 GLENN
+Updated castings for MikeP (NT).
+
+ Rev 1.20 06 Aug 1992 13:20:20 CHUCKB
+Changes for NT.
+
+ Rev 1.19 28 Jul 1992 14:49:20 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.18 29 May 1992 15:58:42 JOHNWT
+PCH updates
+
+ Rev 1.17 12 May 1992 21:20:56 MIKEP
+NT pass 1
+
+ Rev 1.16 30 Mar 1992 18:02:30 GLENN
+Added support for pulling resources from .DLL
+
+ Rev 1.15 09 Mar 1992 09:37:12 GLENN
+Fixed comparison in dialog table.
+
+ Rev 1.14 03 Mar 1992 17:00:06 GLENN
+Changed bad dialog table length to a calculated actual dialog table length.
+
+ Rev 1.13 31 Jan 1992 13:42:46 JOHNWT
+enhanced DM_CenterDialog
+
+ Rev 1.12 27 Jan 1992 00:28:56 CHUCKB
+Updated dialog id's.
+
+ Rev 1.11 24 Jan 1992 16:27:34 CHUCKB
+Took out cbt_job define.
+
+ Rev 1.10 20 Jan 1992 15:00:20 CARLS
+
+ Rev 1.9 09 Jan 1992 18:24:06 DAVEV
+16/32 bit port 2nd pass
+
+ Rev 1.8 07 Jan 1992 17:33:24 GLENN
+Updated the table
+
+ Rev 1.7 19 Dec 1991 13:36:26 CHUCKB
+Added line for settings/options dialog to callback table.
+
+ Rev 1.6 18 Dec 1991 11:35:20 JOHNWT
+changed RTDs to MODAL
+
+ Rev 1.5 13 Dec 1991 16:09:38 JOHNWT
+added DM_PWDBPassword
+
+ Rev 1.4 10 Dec 1991 13:32:12 CHUCKB
+Added table entry for advanced restore.
+
+ Rev 1.3 06 Dec 1991 15:55:46 JOHNWT
+added DM_NextSet
+
+ Rev 1.2 29 Nov 1991 16:39:18 CHUCKB
+Added dialog callback table entry for DM_AdvRestore.
+
+ Rev 1.1 25 Nov 1991 14:52:30 DAVEV
+Changes for 32-16 bit Windows port
+
+
+ Rev 1.0 07 Jun 1991 16:22:32 GLENN
+Initial revision.
+
+****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+#ifndef OEM_MSOFT
+
+DIALOG_TABLE DialogCallBackTable[] = {
+
+ { (FARPROC)DM_Abort, IDD_ABORT_BOX, MODAL }, // chs:05-25-93
+ { (FARPROC)DM_AboutWinter, IDD_HELPABOUTWINTERPARK, MODAL },
+
+ { (FARPROC)DM_EraseTape, IDD_OPERATIONSERASE, MODAL },
+
+ { (FARPROC)DM_AdvBackup, IDD_SELECTADVANCED, MODAL },
+ { (FARPROC)DM_AdvSave, IDD_SELECTSAVE, MODAL },
+ { (FARPROC)DM_AdvUse, IDD_SELECTUSE, MODAL },
+ { (FARPROC)DM_DeleteSelection, IDD_SELECTDELETE, MODAL },
+ { (FARPROC)DM_AdvRestore, IDD_ADVRESTORE, MODAL },
+
+ { (FARPROC)DM_New, IDD_JOBNEW, MODAL },
+ { (FARPROC)DM_Jobs, IDD_JOBMAINTENANCE, MODAL },
+ { (FARPROC)DM_JobOpt, IDD_JOBOPTS, MODAL },
+ { (FARPROC)DM_Schedule, IDD_JOBSCHEDULE, MODAL },
+ { (FARPROC)DM_SchedOpt, IDD_SCHEDOPTS, MODAL },
+#ifdef WFW
+ { (FARPROC)DM_Email, IDD_EMAIL, MODAL },
+ { (FARPROC)DM_EmailLogon, IDD_EMAILLOGON, MODAL },
+#endif
+ { (FARPROC)DM_SettingsOptions, IDD_SETTINGSOPTIONS, MODAL },
+ { (FARPROC)DM_OptionsBackup, IDD_SETTINGSBACKUP, MODAL },
+ { (FARPROC)DM_OptionRestore, IDD_SETTINGSRESTORE, MODAL },
+ { (FARPROC)DM_OptionsLogging, IDD_SETTINGSLOGGING, MODAL },
+ { (FARPROC)DM_OptionsNetwork, IDD_SETTINGSNETWORK, MODAL },
+ { (FARPROC)DM_OptionsCatalog, IDD_SETTINGSCATALOG, MODAL },
+ { (FARPROC)DM_OptionHardware, IDD_SETTINGSHARDWARE, MODAL },
+ { (FARPROC)DM_SettingsDebug, IDD_SETTINGSDEBUGWINDOW, MODAL },
+
+ { (FARPROC)DM_Attach, IDD_PSWD, MODAL },
+ { (FARPROC)DM_RestoreTarget, IDD_RESTORE, MODAL },
+ { (FARPROC)DM_VerifyTarget, IDD_VERIFY, MODAL },
+ { (FARPROC)DM_SearchTape, IDD_SEARCHTAPE, MODAL },
+
+// { (FARPROC)DM_OptionsTransfer, IDD_SETTINGSTRANSFER, MODAL },
+ { (FARPROC)PM_SetupWndProc, IDD_FILESETUP, MODAL },
+ { (FARPROC)PM_PrintWndProc, IDD_FILEPRINT, MODAL },
+
+ { (FARPROC)DM_CatalogMaint, IDD_OPERATIONSCATMAINT, MODAL },
+// { (FARPROC)DM_CatalogBset, IDD_CATBSET, MODAL },
+ { (FARPROC)DM_CatalogTape, IDD_CATTAPE, MODAL },
+ { (FARPROC)DM_TapePswd, IDD_TAPEPSWD, MODAL }, // these use
+ { (FARPROC)DM_TapePswd, IDD_LANTAPEPSWD, MODAL }, // the same proc
+
+ { (FARPROC)DM_ProgManItem, IDD_JOBPROGMANITEM, MODAL },
+
+ { (FARPROC)DM_BackupSet, IDD_BACKUPSET, MODAL },
+ { (FARPROC)DM_RestoreSet, IDD_RESTORESET, MODAL },
+ { (FARPROC)DM_RestoreSet, IDD_VERIFYSET, MODAL },
+ { (FARPROC)DM_ReenterPassword, IDD_REENTER_PASSWORD, MODAL },
+ { (FARPROC)DM_SkipOpen, IDD_SKIPOPEN, MODAL },
+ { (FARPROC)DM_SkipNo, IDD_SKIPNO, MODAL },
+ { (FARPROC)DM_FileReplace, IDD_FILEREPLACE, MODAL },
+ { (FARPROC)DM_Erase, IDD_ERASE, MODAL },
+ { (FARPROC)DM_Runtime, IDD_RUNTIME, MODELESS },
+ { (FARPROC)DM_Tension, IDD_TENSION, MODELESS },
+ { (FARPROC)DM_PWDBPassword, IDD_PWDB_PASSWORD, MODAL },
+#ifdef OS_WIN32
+ { (FARPROC)DM_WaitForDevice, IDD_WAITDEVICE, MODAL },
+#endif
+ { (FARPROC)DM_Runtime, IDD_CATALOG, MODELESS }
+};
+
+#else
+
+DIALOG_TABLE DialogCallBackTable[] = {
+
+ { (FARPROC)DM_AboutWinter, IDD_HELPABOUTWINTERPARK, MODAL },
+
+ { (FARPROC)DM_EraseTape, IDD_OPERATIONSERASE, MODAL },
+
+ { (FARPROC)DM_OptionHardware, IDD_SETTINGSHARDWARE, MODAL },
+ { (FARPROC)DM_SettingsDebug, IDD_SETTINGSDEBUGWINDOW, MODAL },
+
+ { (FARPROC)DM_RestoreTarget, IDD_RESTORE, MODAL },
+ { (FARPROC)DM_VerifyTarget, IDD_VERIFY, MODAL },
+
+ { (FARPROC)DM_BackupSet, IDD_BACKUPSET, MODAL },
+ { (FARPROC)DM_RestoreSet, IDD_RESTORESET, MODAL },
+ { (FARPROC)DM_RestoreSet, IDD_VERIFYSET, MODAL },
+ { (FARPROC)DM_SkipOpen, IDD_SKIPOPEN, MODAL },
+ { (FARPROC)DM_FileReplace, IDD_FILEREPLACE, MODAL },
+ { (FARPROC)DM_Erase, IDD_ERASE, MODAL },
+ { (FARPROC)DM_Runtime, IDD_RUNTIME, MODELESS },
+ { (FARPROC)DM_Tension, IDD_TENSION, MODELESS },
+ { (FARPROC)DM_PWDBPassword, IDD_PWDB_PASSWORD, MODAL },
+#ifdef OEM_EMS
+ { (FARPROC)DM_ExchgConnect, IDD_CONNECT_XCHNG, MODAL },
+ { (FARPROC)DM_ExchgRecover, IDD_XCHG_RECOVER, MODAL },
+#endif
+ { (FARPROC)DM_Runtime, IDD_CATALOG, MODELESS }
+};
+
+#endif
+
+#define NUM_DIALOGS ( sizeof (DialogCallBackTable) / sizeof (DialogCallBackTable[0]) )
+
+/****************************************************************************
+
+ Name: BeginDialogProcess
+
+ Description: Chooses a dialog proc & template, initializes a proc
+ instance, and calls DialogBoxParam().
+
+ Modified: 6/01/91
+
+ Returns: none
+
+ Notes:
+
+ See also:
+
+****************************************************************************/
+
+
+INT APIENTRY DM_BeginDialogProcess (
+
+HWND hWnd, // I - Handle of window.
+HANDLE hInst, // I - Instance of application.
+WORD wDialogNum, // I - Resource number of dialog.
+PVOID pDatain, // I/O - Pointer to data area being passed to dialog.
+PVOID pDataout ) // - Currently not being used.
+
+
+{
+ WNDPROC lpProc;
+ INT nRetCode = DM_SHOWNOTFOUND;
+
+ DBG_UNREFERENCED_PARAMETER ( pDataout );
+
+ // Get information from the dialog procedure callback definition table
+ // to instantiate and begin specified dialog.
+
+ // Is dialog_num in range of valid dialogs ?
+
+ if ( wDialogNum >= NUM_DIALOGS ) {
+
+ return ( nRetCode );
+ }
+
+ lpProc = (WNDPROC)MakeProcInstance ( DialogCallBackTable[ wDialogNum].proc, ghInst );
+
+ switch ( DialogCallBackTable[wDialogNum].type ) {
+
+ case MODAL:
+
+ if ( ghModelessDialog ) {
+
+ hWnd = ghModelessDialog;
+ }
+
+ nRetCode = DialogBoxParam ( ghResInst,
+ MAKEINTRESOURCE ( DialogCallBackTable[wDialogNum].proc_num ) ,
+ hWnd,
+ (DLGPROC)lpProc,
+ MP2FROMPVOID ( pDatain )
+ );
+
+ FreeProcInstance (lpProc);
+
+ break;
+
+ case MODELESS:
+
+ ghModelessDialog = CreateDialogParam ( ghResInst,
+ MAKEINTRESOURCE ( DialogCallBackTable[ wDialogNum ].proc_num ) ,
+ hWnd,
+ (DLGPROC)lpProc,
+ (LONG) pDatain
+ );
+
+ break;
+
+ }
+
+ return ( nRetCode );
+}
+
+
+/****************************************************************************
+
+ Name: DM_IsInDialogTable
+
+ Description: Searches the dialog callback table for a dialog
+ identified by a unique resource number.
+
+ This function provides an entry point to the Dialog
+ Manager for other functions to use.
+
+ Modified: 06/12/91
+
+ Returns: TRUE if dialog was found and processed.
+ FALSE if dialog not found.
+
+ Notes:
+ Uses the global variable 'ghInst' for define instance
+ handle.
+ See also:
+
+****************************************************************************/
+
+
+BOOL APIENTRY DM_IsInDlgTable (
+
+HWND hWnd , // I - Handle to window
+WORD wResNum ) // I - Unique resource number of dialog.
+
+{
+
+ BOOL fFound = FALSE;
+ WORD i = 0;
+
+
+ while ( ( i < NUM_DIALOGS ) && (!fFound) ) {
+
+ if ( wResNum == DialogCallBackTable[i].proc_num ) {
+
+ DM_BeginDialogProcess ( hWnd, ghResInst, i, NULL, NULL );
+ fFound = TRUE;
+ }
+
+ i++;
+ }
+
+ return fFound;
+}
+
+/****************************************************************************
+
+ Name: DM_ShowDialog
+
+ Description: Searches the dialog callback table for a dialog
+ identified by a unique resource number.
+
+
+ Modified: 10/25/91
+
+ Returns: INT DM_SHOWNOTFOUND if the dialog was not found;
+ DM_SHOWCANCEL if the dialog was found,
+ but the user cancelled;
+ DM_SHOWOK if the dialog was found
+ and the user entered valid data
+
+ Notes: Uses the global variable 'ghInst' for define instance
+ handle.
+
+ See also:
+
+****************************************************************************/
+
+
+INT APIENTRY DM_ShowDialog (
+
+HWND hWnd , // I - Handle to window
+WORD wResNum, // I - Unique resource number of dialog.
+PVOID lParam ) // I - Initialization parameter for dialog
+
+{
+ BOOL fFound = FALSE;
+ WORD i = 0;
+ INT nRetCode = DM_SHOWNOTFOUND;
+
+
+ while ( ( i < NUM_DIALOGS ) && (!fFound) ) {
+
+ if ( wResNum == DialogCallBackTable[i].proc_num ) {
+
+ nRetCode = DM_BeginDialogProcess ( hWnd, ghResInst, i, (PVOID) lParam, NULL );
+ fFound = TRUE;
+ }
+
+ i++;
+ }
+
+ return nRetCode;
+}
+
+/***********************************************************************
+
+ Name: DM_DialogOnError
+
+ Description: Displays error message using WM_MsgBox
+ according to error classification
+
+ Modified: 8/6/1991
+
+ Returns: INT Error code given to the function
+
+ Notes:
+ Currently JOBIO, SCHEDULEIO defined types
+
+ See also:
+
+***********************************************************************/
+
+
+INT DM_DialogOnError (
+
+INT nError,
+WORD wType )
+
+{
+ LPSTR szString;
+ LPSTR szTitle ;
+ LPSTR szFormat;
+ LPSTR szFullFileName;
+
+ if ( nError == 0 ) {
+ return ( nError );
+ }
+
+ szString = (LPSTR) calloc ( 256, sizeof ( CHAR ) );
+ szFormat = (LPSTR) calloc ( 256, sizeof ( CHAR ) );
+ szTitle = (LPSTR) calloc ( 256, sizeof ( CHAR ) );
+ szFullFileName = (LPSTR) calloc ( 256, sizeof ( CHAR ) );
+
+ lstrcpy( szFullFileName, CDS_GetUserDataPath () );
+
+ switch( wType ) {
+
+ case JOBIO :
+
+ RSM_StringCopy( IDS_JOBIOERR, (LPSTR) szTitle, 255 );
+ RSM_StringCopy( IDS_JOBFILENAME, (LPSTR) szString, 255 );
+
+ lstrcat( szFullFileName, szString );
+
+ switch ( nError ) {
+
+ case FOPEN_ERR :
+ RSM_StringCopy( IDS_CANTOPEN, (LPSTR) szFormat, 255 );
+ break;
+
+ case FREAD_ERR :
+ RSM_StringCopy( IDS_CANTREAD, (LPSTR) szFormat, 255 );
+ break;
+
+ case FWRITE_ERR :
+ RSM_StringCopy( IDS_CANTWRITE, (LPSTR) szFormat, 255 );
+ break;
+
+ case FCLOSE_ERR :
+ RSM_StringCopy( IDS_CANTCLOSE, (LPSTR) szFormat, 255 );
+ break;
+
+
+ default :
+ RSM_StringCopy( IDS_CANTCREATE, (LPSTR) szFormat, 255 );
+ }
+
+ lstrcpy( szString, TEXT("")); // Clear out szString
+
+ wsprintf ( szString, szFormat, szFullFileName );
+
+ break;
+
+ case SCHEDULEIO :
+
+ RSM_StringCopy( IDS_SCHEDULEIOERR, (LPSTR) szTitle, 255 );
+ RSM_StringCopy( IDS_SCHFILENAME , (LPSTR) szString, 255 );
+
+ lstrcat( szFullFileName, szString );
+
+ switch ( nError ) {
+
+ case FOPEN_ERR :
+ RSM_StringCopy( IDS_CANTOPEN, (LPSTR) szFormat, 255 );
+ break;
+
+ case FREAD_ERR :
+ RSM_StringCopy( IDS_CANTREAD, (LPSTR) szFormat, 255 );
+ break;
+
+ case FWRITE_ERR :
+ RSM_StringCopy( IDS_CANTWRITE, (LPSTR) szFormat, 255 );
+ break;
+
+ case FCLOSE_ERR :
+ RSM_StringCopy( IDS_CANTCLOSE, (LPSTR) szFormat, 255 );
+ break;
+
+ default :
+ RSM_StringCopy( IDS_CANTCREATE,(LPSTR) szFormat, 255 );
+ }
+
+ lstrcpy( szString, TEXT("")); // Clear out szString
+
+ wsprintf ( szString, szFormat, szFullFileName );
+
+ }
+
+ WM_MsgBox( szTitle, szString, WMMB_OK, WMMB_ICONEXCLAMATION );
+
+ free ( szString );
+ free ( szFormat );
+ free ( szTitle );
+ free ( szFullFileName );
+
+ return( nError );
+}
+
+/***********************************************************************
+
+ Name: DM_CenterDialog
+
+ Description: Centers the dialog on the frame window. If the
+ resulting position is off the screen, center it on
+ the screen. If we are still off the screen, set
+ the top/left to 0,0.
+
+ Modified: 1/31/92
+
+ Returns: VOID
+
+***********************************************************************/
+
+VOID DM_CenterDialog( HWND hDlg)
+
+{
+
+ RECT Rect, DlgRect;
+ INT nDlgHigh, nDlgWid, nFrameWid, nFrameHigh;
+
+
+ /* first get the rectangles of the frame window and dialog and then
+ calculate their sizes */
+
+ GetWindowRect( ghWndFrame, &Rect );
+ GetWindowRect( hDlg, &DlgRect );
+
+ nFrameWid = Rect.right - Rect.left;
+ nFrameHigh = Rect.bottom - Rect.top;
+ nDlgWid = DlgRect.right - DlgRect.left;
+ nDlgHigh = DlgRect.bottom - DlgRect.top;
+
+ /* calculate the new top and left positions */
+
+ Rect.left += ( nFrameWid - nDlgWid ) / 2;
+ Rect.top += ( nFrameHigh - nDlgHigh ) / 2;
+
+ /* if any part of the dlg is off the screen, center on the screen */
+
+ if ( ( Rect.left < 0 ) ||
+ ( Rect.top < 0 ) ||
+ ( Rect.left + nDlgWid > GetSystemMetrics( SM_CXSCREEN ) ) ||
+ ( Rect.top + nDlgHigh > GetSystemMetrics( SM_CYSCREEN ) ) ) {
+
+ Rect.left = ( GetSystemMetrics( SM_CXSCREEN ) - nDlgWid ) / 2;
+ Rect.top = ( GetSystemMetrics( SM_CYSCREEN ) - nDlgHigh ) / 2;
+
+ /* if we are on some bizarre monitor and the top of the dialog is
+ not on the screen, make the top/left 0/0 so they can at least
+ move it around with the mouse. */
+
+ if ( Rect.left < 0 ) {
+ Rect.left = 0;
+ }
+
+ if ( Rect.top < 0 ) {
+ Rect.top = 0;
+ }
+
+ }
+
+ /* position the dialog */
+
+ MoveWindow( hDlg, Rect.left, Rect.top, nDlgWid, nDlgHigh, TRUE );
+
+ return;
+}
+
diff --git a/private/utils/ntbackup/src/dialogs.rc b/private/utils/ntbackup/src/dialogs.rc
new file mode 100644
index 000000000..05abcefd3
--- /dev/null
+++ b/private/utils/ntbackup/src/dialogs.rc
@@ -0,0 +1,261 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: dialogs.rc
+
+ Description: This file contains the references to dialog resources for
+ the Windows GUI Project Resource File.
+
+ $Log: G:/UI/LOGFILES/DIALOGS.RCV $
+
+ Rev 1.35 10 Aug 1993 13:52:24 Aaron
+ Moved waitdev.dlg into an OS_WIN32 ifdef
+
+ Rev 1.34 04 Aug 1993 18:00:58 chrish
+ Ifdef dummyad.dlg for CAYMAN.
+
+ Rev 1.33 30 Jul 1993 16:01:12 CHUCKB
+ Added include for waitdev.dlg.
+
+ Rev 1.32 27 Jul 1993 13:21:10 chrish
+ CAYMAN EPR 0638: Added new "dummyab.dlg" for printer aborting.
+
+ Rev 1.31 19 Jul 1993 14:22:58 CARLS
+ added skipno.h & skipno.dlg
+
+ Rev 1.30 12 Jul 1993 11:00:16 MIKEP
+ change it back again.
+
+ Rev 1.29 06 Jul 1993 10:03:04 MIKEP
+ ifdef about box based on oem_msoft rather than os_win32.
+
+ Rev 1.28 30 Jun 1993 16:38:02 Aaron
+ Ifdef'd about box dialog inclusion on OS_WIN32
+
+ Rev 1.27 29 Jun 1993 17:33:58 GLENN
+ Added new style about box support.
+
+ Rev 1.26 25 May 1993 14:22:34 chrish
+ Added new backup/restore abort dialog box.
+
+ Rev 1.25 15 Apr 1993 13:35:26 CLIFF
+ Added dummy device driver stuff.
+
+ Rev 1.24 22 Mar 1993 14:50:16 DARRYLP
+ Added Browse dialog.
+
+ Rev 1.23 16 Mar 1993 15:27:18 ROBG
+ Changed the reference of OM_FONT.DLG in OEM_SOFT to FONT.DLG.
+
+ Rev 1.22 10 Mar 1993 13:42:28 DARRYLP
+ Added Catalog.dlg
+
+ Rev 1.21 17 Feb 1993 09:37:36 BURT
+ Changes to support Cayman
+
+
+ Rev 1.20 18 Dec 1992 11:24:42 chrish
+ Consolidate all the dialogs.
+
+ Rev 1.19 02 Oct 1992 16:56:40 GLENN
+ Added the DLGINCLUDE to the top of the file. Should be removed from all dialogs.
+
+ Rev 1.18 21 Sep 1992 16:54:10 DARRYLP
+ Updates for WFW email.
+
+ Rev 1.17 17 Sep 1992 18:11:38 DARRYLP
+ New dialog for WFW email.
+
+ Rev 1.16 09 Sep 1992 17:58:10 CHUCKB
+ Fixed my backwards ifdefs (oops).
+
+ Rev 1.15 03 Sep 1992 11:08:06 CHUCKB
+ Changed some stuff for Microsoft.
+
+ Rev 1.14 02 Sep 1992 15:03:14 GLENN
+ Added the new font dialog.
+
+ Rev 1.13 19 Aug 1992 14:27:54 CHUCKB
+ #ifdef'ed out unused dialogs.
+
+ Rev 1.12 26 Jun 1992 15:57:08 DAVEV
+
+
+ Rev 1.11 22 Feb 1992 15:33:22 ROBG
+ Added prtabort.dlg for print manager/.
+
+ Rev 1.10 07 Feb 1992 16:07:50 CHUCKB
+ Added ltappswd.dlg.
+
+ Rev 1.9 29 Jan 1992 17:54:08 GLENN
+ Updated dialog IDs.
+
+ Rev 1.8 26 Jan 1992 16:37:46 CHUCKB
+ Fixed some includes.
+
+ Rev 1.7 06 Jan 1992 18:35:24 CHUCKB
+ Put catalog settings dialog in an include file. There should be no more dialogs in this file.
+
+ Rev 1.6 02 Jan 1992 12:49:24 CHUCKB
+ Put dialogs in separate .dlg files.
+
+ Rev 1.5 14 Dec 1991 13:50:38 JOHNWT
+ added network.dlg
+
+ Rev 1.4 13 Dec 1991 16:10:50 JOHNWT
+ added loginpw.dlg
+
+ Rev 1.3 07 Dec 1991 12:23:30 CARLS
+ added include for cattape.dlg
+
+ Rev 1.2 06 Dec 1991 15:54:52 JOHNWT
+ added include for nextset.dlg
+
+ Rev 1.1 04 Dec 1991 16:50:20 CHUCKB
+ Put some hot keys in.
+
+ Rev 1.0 20 Nov 1991 19:17:06 SYSTEM
+ Initial revision.
+
+******************************************************************************/
+
+DLGINCLUDE RCDATA DISCARDABLE
+BEGIN
+ "ADD_ICON.H\0"
+ "ADV_REST.H\0"
+ "ADV_SEL.H\0"
+ "BKUP.H\0"
+ "CATMAINT.H\0"
+ "CATTAPE.H\0"
+ "DEL_SEL.H\0"
+ "DLGS.H\0"
+ "EMAIL.H\0"
+ "EMLLOGON.H\0"
+ "ERASE.H\0"
+ "FREPLACE.H\0"
+ "HWDLG.H\0"
+ "JOB_NEW.H\0"
+ "JOBSETUP.H\0"
+ "JOB_OPTS.H\0"
+ "LTAPPSWD.H\0"
+ "LOGINPW.H\0"
+ "MSGBOXID.H\0"
+ "NEXTSET.H\0"
+ "NETWORK.H\0"
+ "OMBKUP.H\0"
+ "OMRSET.H\0"
+ "RT_DLG.H\0"
+ "RSET.H\0"
+ "RSETNEW.H\0"
+ "SAVE_SEL.H\0"
+ "SCHED.H\0"
+ "SET_CAT.H\0"
+ "SET_DBUG.H\0"
+ "SET_LOG.H\0"
+ "SET_OPTS.H\0"
+ "SET_PRT.H\0"
+ "SET_REST.H\0"
+ "SETBACK.H\0"
+ "SKIPNO.H\0"
+ "SKIPOPEN.H\0"
+ "SRVLOGIN.H\0"
+ "TAPEPSWD.H\0"
+ "TENSION.H\0"
+ "TSEARCH.H\0"
+ "USE_SEL.H\0"
+ "ABORTDLG.H\0" // chs:05-25-93
+ "OMEXCHNG.H\0"
+#ifdef DUMMY_DD
+ "DDD_DLG.H\0"
+#endif
+END
+
+#include "msgbox.dlg"
+#include "set_dbug.dlg"
+#include "skipno.dlg"
+#include "skipopen.dlg"
+#include "tension.dlg"
+#include "vset.dlg"
+
+#if !defined ( OEM_MSOFT )
+#ifdef CAYMAN // chs:08-04-93
+ #include "dummyab.dlg" // chs:07-27-93
+#endif // chs:08-04-93
+ #include "abortdlg.dlg" // chs:05-25-93
+ #include "font.dlg"
+ #include "add_icon.dlg"
+ #include "adv_rest.dlg"
+ #include "adv_sel.dlg"
+ #include "bkup.dlg"
+ #include "catalog.dlg"
+ #include "catmaint.dlg"
+ #include "cattape.dlg"
+ #include "del_sel.dlg"
+ #include "erase.dlg"
+#if defined( WFW )
+ #include "email.dlg"
+ #include "emllogon.dlg"
+#endif
+ #include "freplace.dlg"
+
+#ifdef OS_WIN32
+ #include "omabout.dlg" // yes, we use the OM version now.
+ #include "omhwconf.dlg"
+ #include "waitdev.dlg"
+#else
+ #include "about.dlg" // no, we don't use the OM version yet.
+ #include "hwconf.dlg"
+#endif
+
+ #include "job_new.dlg"
+ #include "d_browse.dlg"
+ #include "job_opts.dlg"
+ #include "jobsetup.dlg"
+ #include "ltappswd.dlg"
+ #include "loginpw.dlg"
+ #include "network.dlg"
+ #include "nextset.dlg"
+ #include "password.dlg"
+ #include "print.dlg"
+ #include "printlog.dlg"
+ #include "rset.dlg"
+ #include "runtime.dlg"
+ #include "save_sel.dlg"
+ #include "sch_opts.dlg"
+ #include "schedule.dlg"
+ #include "tsearch.dlg"
+ #include "set_cat.dlg"
+ #include "set_log.dlg"
+ #include "set_opts.dlg"
+ #include "set_prt.dlg"
+ #include "set_rest.dlg"
+ #include "setback.dlg"
+ #include "srvlogin.dlg"
+ #include "tapepswd.dlg"
+ #include "use_sel.dlg"
+ #include "prtabort.dlg"
+#else
+ #include "omabout.dlg"
+ #include "ombrowse.dlg"
+ #include "omfiler.dlg"
+ #include "ombkup.dlg"
+ #include "omerase.dlg"
+ #include "omxchng.dlg"
+#ifdef OS_WIN32
+ #include "omhwconf.dlg"
+#else
+ #include "hwconf.dlg"
+#endif
+
+ #include "omruntim.dlg"
+ #include "omcatlog.dlg"
+ #include "font.dlg"
+ #include "omrset.dlg"
+#endif
+
+#ifdef DUMMY_DD
+ #include "ddd_dum.dlg"
+#endif
+
diff --git a/private/utils/ntbackup/src/dilntmsc.c b/private/utils/ntbackup/src/dilntmsc.c
new file mode 100644
index 000000000..e5ca71883
--- /dev/null
+++ b/private/utils/ntbackup/src/dilntmsc.c
@@ -0,0 +1,1747 @@
+/**
+Copyright(c) Conner Software Products Group 1993
+
+ Name: dilntmsc.c
+
+ Description: Contains all the async support code for dilnttp.c.
+
+ $Log: T:/LOGFILES/DILNTMSC.C_V $
+
+ Rev 1.3.1.10 12 Aug 1994 14:56:16 GREGG
+If the drive is an Anaconda, issue a rewind before setting the block size.
+
+ Rev 1.3.1.9 16 Mar 1994 19:27:22 GREGG
+Added support for two more DEC DLT drives: tz86 and tz87.
+
+ Rev 1.3.1.8 16 Feb 1994 19:16:42 GREGG
+Report num fmks NOT skipped on SPACE error, and ignore ERROR_FILEMARK.
+
+ Rev 1.3.1.7 14 Feb 1994 16:49:58 GREGG
+Make sure we don't change any other drive parameters when setting HW Comp.
+
+ Rev 1.3.1.6 07 Feb 1994 01:24:30 GREGG
+Only get drive id string once at init (EPR 139).
+
+ Rev 1.3.1.5 28 Jan 1994 18:22:30 GREGG
+Added EXB-5601 to list of drives that don't eject.
+
+ Rev 1.3.1.4 07 Jan 1994 15:34:12 GREGG
+Treat DEC's DLT2000 and DLT2700 the same as the THZ02.
+
+ Rev 1.3.1.3 08 Dec 1993 20:31:02 GREGG
+Merged in all the fixes Orcas needed from past it's branch.
+
+ Rev 1.3.1.2 29 Nov 1993 12:38:40 GREGG
+Check for TAPE_DRIVE_SET_COMPRESSION instead of TAPE_DRIVE_COMPRESSION.
+
+ Rev 1.3.1.1 21 Nov 1993 23:27:16 GREGG
+Make TpSpecial call run on their own thread.
+
+ Rev 1.3.1.0 21 May 1993 11:35:48 GREGG
+Added ERROR_CRC for bug in NT error mapping per Steve.
+
+ Rev 1.3 18 May 1993 13:29:42 TIMN
+Removed extern reference to TapeDevice.
+Changes from rev1.0 to this rev require DIL.h DDDEFS.h GENFUNCS.h
+
+ Rev 1.2 17 May 1993 18:17:26 GREGG
+Added function TpSpace, which is a super set of TpReadEndSet, and will
+eventually replace it, but for now, they map to the same gen func code
+(defined as both GEN_ERR_ENDSET and GEN_SPACE), have identical arguments,
+and have the same value for equivalent defined values for their parameters.
+Also changed the case in ProcessRequest to handle both functions.
+
+ Rev 1.1 17 May 1993 16:53:48 GREGG
+Added ERROR_NOT_DOS_DISK for bug in NT error mapping per Steve.
+
+ Rev 1.0 17 May 1993 16:49:56 GREGG
+DILNTTP.C, DILNTMSC.C and DILNTPRV.H replace DIL_NT.C at rev. 1.44.
+
+**/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "windows.h"
+
+#include "stdtypes.h"
+#include "queues.h"
+#include "dilhwd.h"
+#include "mslreq.h"
+#include "retbuf.h"
+#include "genfuncs.h"
+#include "generr.h"
+#include "drvinf.h"
+#include "special.h"
+#include "genstat.h"
+#include "dddefs.h"
+#include "ld_dvr.h"
+#include "debug.h"
+#include "msassert.h"
+#include "be_debug.h"
+#include "dilntprv.h"
+#include "muiconf.h"
+
+#ifndef MS_RELEASE
+#define DEBUG_DIL 1
+#endif
+
+// ------------------------------------
+
+LARGE_INTEGER gb_drv_features ;
+
+// In this circular queue implementation one node is wasted, thus actually
+// use N-1 nodes.
+
+static FAKE_TCB tcbs[NUM_TCBS + 1] = { NULL } ;
+
+
+/*------------------------------------------------------------------------
+ Circular queue header
+------------------------------------------------------------------------*/
+// Physicall there is only one circular queue. Logically it appears like
+// two queues. The CQueue pointer is used as an in queue and also keep
+// track of the last request executed. The OutCQueue pointer is used
+// as an out queue pointer. The TpReceives uses this pointer to get
+// requests that have been executed and waiting to be retrieved.
+
+Q_HEADER DILNT_CQueue = { NULL } ; // Circular queue (in and process)
+Q_HEADER DILNT_OutCQueue = { NULL } ; // Pointer into the circular queue
+ // this is used by the TpReceive
+ // proc to pop the element off.
+
+/*------------------------------------------------------------------------
+ Some globals declarations
+------------------------------------------------------------------------*/
+
+INT DILNT_ProcessErrorFlag; // Flag to notify Tp calls that an error
+ // was encountered. Flag is set in
+ // the ProcessRequest proc and reset
+ // int the TpReceive proc.
+
+INT DILNT_FOREVER = FOREVER_FOREVER;
+
+HANDLE DILNT_deviceHandle = INVALID_HANDLE_VALUE ;
+
+HANDLE DILNT_OKToProcessSemaphore; // global semaphore to release
+ // the thread for processing
+HANDLE DILNT_QThread_0 = NULL; // global thread handle for
+ // the queue manager
+HANDLE DILNT_CQueueSemaphore; // Semaphore to control the
+ // circular queue
+
+// Globals for TpSpecial Thread
+
+CRITICAL_SECTION DILNT_SpecialCriticalSection ;
+INT16 DILNT_SpecialCode ;
+UINT32 DILNT_SpecialMisc ;
+BOOLEAN DILNT_SpecialDone ;
+BOOLEAN DILNT_SpecialEnd ;
+BOOLEAN DILNT_SpecialReturn ;
+CHAR DILNT_SpecialDriveName[81] ;
+HANDLE DILNT_SpecialThread = NULL ;
+
+// For storing drive registry string
+CHAR DILNT_DriveName[81] ;
+
+
+/*------------------------------------------------------------------------
+ Function Declaration
+------------------------------------------------------------------------*/
+
+VOID InitializeTapeBlockSize( void ) ;
+
+static BOOLEAN IsCQueueFull( Q_HEADER_PTR queue,
+ Q_HEADER_PTR outqueue
+);
+
+static BOOLEAN
+IsCOutQueueEmpty( Q_HEADER_PTR outqueue,
+ Q_HEADER_PTR CQueue
+);
+
+static BOOLEAN
+CDequeue( Q_HEADER_PTR queue,
+ FAKE_TCB_PTR tmpTCB
+);
+
+static BOOLEAN
+IsCQueueEmpty( Q_HEADER_PTR queue
+);
+
+static VOID
+ProcessRequest(); // Thread to process request
+
+static VOID StoreRetBufInfo( IN FAKE_TCB_PTR tmpTCB,
+ IN DWORD status
+);
+
+static VOID ProcessSpecial( VOID ) ;
+
+
+/**/
+VOID StoreRetBufInfo( FAKE_TCB_PTR tmpTCB,
+ DWORD status
+)
+{
+ TAPE_GET_MEDIA_PARAMETERS parms ;
+ DWORD buffsize;
+ DWORD lst_err ;
+
+ tmpTCB->ret_stuff.call_type = tmpTCB->dil_request.gen_func_code ;
+ tmpTCB->ret_stuff.gen_error = GEN_NO_ERR ;
+ tmpTCB->ret_stuff.status = 0L ;
+
+ switch ( tmpTCB->ret_stuff.call_type ) {
+ case GEN_READ:
+ case GEN_WRITE:
+ if ( status == TRUE ) {
+ return ;
+ }
+ break ;
+
+ default:
+ if ( status == NO_ERROR ) {
+ return ;
+ }
+ break ;
+ }
+
+ switch( ( lst_err = GetLastError( ) ) ) {
+
+ case ERROR_FILEMARK_DETECTED: // 1101
+ case ERROR_SETMARK_DETECTED: // 1103
+ case ERROR_END_OF_MEDIA: // 1100
+ case ERROR_NO_MEDIA_IN_DRIVE: // 1112
+ case ERROR_NO_DATA: // 0232
+ case ERROR_NO_DATA_DETECTED: // 1104
+ case ERROR_BEGINNING_OF_MEDIA: // 1102
+
+ buffsize = sizeof( TAPE_GET_MEDIA_PARAMETERS ) ;
+ if( GetTapeParameters( DILNT_deviceHandle,
+ GET_TAPE_MEDIA_INFORMATION,
+ &buffsize, &parms ) == SUCCESS ) {
+
+ if( parms.WriteProtected == TRUE) {
+ tmpTCB->ret_stuff.status |= TPS_WRITE_PROTECT ;
+ }
+ }
+ break ;
+
+ default:
+ break ;
+ }
+
+ switch( lst_err ) {
+ case ERROR_FILEMARK_DETECTED: // 1101
+ case ERROR_SETMARK_DETECTED: // 1103
+ tmpTCB->ret_stuff.gen_error = GEN_ERR_ENDSET ;
+ tmpTCB->ret_stuff.status |= TPS_FMK ;
+ break ;
+
+ case ERROR_END_OF_MEDIA: // 1100
+ tmpTCB->ret_stuff.gen_error = GEN_ERR_EOM ;
+ tmpTCB->ret_stuff.status |= TPS_EOM ;
+ break ;
+
+ case ERROR_SUCCESS: // 0000
+ break ;
+
+ case ERROR_NO_MEDIA_IN_DRIVE: // 1112
+ if( tmpTCB->ret_stuff.call_type != GEN_STATUS ) {
+ tmpTCB->ret_stuff.gen_error = GEN_ERR_NO_MEDIA ;
+ }
+ tmpTCB->ret_stuff.status |= TPS_NO_TAPE ;
+ break ;
+
+ case ERROR_BAD_LENGTH: // 0024
+ case ERROR_CRC: // 0023
+ case ERROR_NOT_DOS_DISK: // 0026
+ tmpTCB->ret_stuff.gen_error = GEN_ERR_BAD_DATA ;
+ tmpTCB->ret_stuff.status |= TPS_DRV_FAILURE ;
+ break ;
+
+ case ERROR_IO_DEVICE: // 1117
+ tmpTCB->ret_stuff.gen_error = GEN_ERR_HARDWARE ;
+ tmpTCB->ret_stuff.status |= TPS_DRV_FAILURE ;
+ break ;
+
+ case ERROR_INVALID_FUNCTION: // 0001
+ case ERROR_FILE_NOT_FOUND: // 0002
+ case ERROR_SECTOR_NOT_FOUND: // 0027
+ case ERROR_INVALID_PARAMETER: // 0087
+ tmpTCB->ret_stuff.gen_error = GEN_ERR_INVALID_CMD ;
+ tmpTCB->ret_stuff.status |= TPS_ILL_CMD ;
+ break ;
+
+ case ERROR_WRITE_PROTECT: // 0019
+ tmpTCB->ret_stuff.gen_error = GEN_ERR_WRT_PROTECT ;
+ tmpTCB->ret_stuff.status |= TPS_WRITE_PROTECT ;
+ break;
+
+ case ERROR_NO_DATA: // 0232
+ case ERROR_NO_DATA_DETECTED: // 1104
+ tmpTCB->ret_stuff.gen_error = GEN_ERR_NO_DATA ;
+ tmpTCB->ret_stuff.status |= TPS_NO_DATA ;
+ break;
+
+ case ERROR_SEM_TIMEOUT: // 0121
+ tmpTCB->ret_stuff.gen_error = GEN_ERR_TIMEOUT ;
+ tmpTCB->ret_stuff.status |= TPS_DRV_FAILURE ;
+ break;
+
+ case ERROR_MEDIA_CHANGED: // 1110
+ if ( tmpTCB->ret_stuff.call_type != GEN_MOUNT &&
+ tmpTCB->ret_stuff.call_type != GEN_OPEN ) {
+ tmpTCB->ret_stuff.gen_error = GEN_ERR_RESET ;
+ }
+ tmpTCB->ret_stuff.status |= TPS_NEW_TAPE ;
+ break ;
+
+ case ERROR_BUS_RESET: // 1129
+ if ( tmpTCB->ret_stuff.call_type != GEN_MOUNT &&
+ tmpTCB->ret_stuff.call_type != GEN_OPEN ) {
+ tmpTCB->ret_stuff.gen_error = GEN_ERR_RESET ;
+ }
+ tmpTCB->ret_stuff.status |= TPS_RESET ;
+ break ;
+
+ case ERROR_BEGINNING_OF_MEDIA: // 1102
+ tmpTCB->ret_stuff.gen_error = GEN_ERR_EOM ;
+ tmpTCB->ret_stuff.status |= TPS_BOT ;
+ break ;
+
+ case ERROR_EOM_OVERFLOW: // 1130
+ tmpTCB->ret_stuff.gen_error = GEN_ERR_EOM_OVERFLOW ;
+ tmpTCB->ret_stuff.status |= TPS_EOM ;
+ break ;
+
+ case ERROR_NOT_READY: // 0021
+ if( tmpTCB->ret_stuff.call_type != GEN_STATUS ) {
+ tmpTCB->ret_stuff.gen_error = GEN_ERR_NO_MEDIA ;
+ }
+ tmpTCB->ret_stuff.status |= TPS_NO_TAPE | TPS_NOT_READY ;
+ break ;
+
+ case ERROR_UNRECOGNIZED_MEDIA:
+ tmpTCB->ret_stuff.gen_error = GEN_ERR_UNRECOGNIZED_MEDIA ;
+ break ;
+
+ case ERROR_INVALID_BLOCK_LENGTH:
+ tmpTCB->ret_stuff.gen_error = GEN_ERR_WRONG_BLOCK_SIZE ;
+ break ;
+
+ default:
+ tmpTCB->ret_stuff.gen_error = GEN_ERR_UNDETERMINED ;
+ tmpTCB->ret_stuff.status |= TPS_DRV_FAILURE ;
+ break ;
+ }
+
+ return ;
+}
+
+/**
+
+ Name: ProcessRequest
+
+ Description: This function is threaded and acts as a queue manager.
+ Monitors the in_q, if request found then performs the
+ request and places the result in the out_q
+
+ Parameters : None
+
+ Returns:
+
+**/
+
+VOID ProcessRequest ( )
+{
+ FAKE_TCB_PTR tmpTCB;
+ FAKE_TCB dummyTCB;
+ Q_ELEM_PTR element;
+ BOOLEAN dretcode;
+
+ while ( DILNT_FOREVER == FOREVER_FOREVER) {
+
+ // check to see if anything request is in the in_q to process
+
+ while ( WaitForSingleObject( DILNT_OKToProcessSemaphore, NOWAIT ) ) {
+ if ( DILNT_FOREVER == FOREVER_STOP ) {
+ ExitThread( FOREVER_STOP );
+ }
+ ThreadSwitch( ) ;
+ }
+
+ // ---------------------------------------------------------------
+ // Check to make sure that the TpReceive did not clear the queue
+ // out when it got an error from a request
+ // ---------------------------------------------------------------
+
+ while ( WaitForSingleObject( DILNT_CQueueSemaphore, NOWAIT ) ) {
+ if ( DILNT_FOREVER == FOREVER_STOP ) {
+ ExitThread( FOREVER_STOP );
+ }
+ ThreadSwitch( ) ;
+ }
+
+ if ( DILNT_ProcessErrorFlag || IsCQueueEmpty( &DILNT_CQueue ) ) {
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ continue;
+ }
+ // ---------------------------------------------------------------
+
+ element = ( Q_ELEM_PTR )DILNT_CQueue.q_head->q_next;
+ tmpTCB = (FAKE_TCB_PTR) element;
+
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ switch( tmpTCB->dil_request.gen_func_code ) {
+
+ // TpClose
+ case GEN_NRCLOSE:
+ {
+ DWORD status = NO_ERROR ;
+
+ /* This is a kludge for the DLT drive. The drive won't
+ write a directory track on the tape until an unload
+ is done, so we do an unload before we exit the app.
+ This will also cause a rewind, which isn't the
+ desired effect when calling NR_CLOSE, but we have to
+ do it in this case. The call is made to return
+ immediately (last param TRUE) rather than waiting
+ for the rewind to complete, so there won't be any
+ noticeable delay in the app exit.
+ */
+ if( strstr( DILNT_DriveName, TEXT( "cipher" ) ) != NULL ||
+ ( strstr( DILNT_DriveName, TEXT( "dec" ) ) != NULL &&
+ ( strstr( DILNT_DriveName, TEXT( "thz02" ) ) != NULL ||
+ strstr( DILNT_DriveName, TEXT( "tz86" ) ) != NULL ||
+ strstr( DILNT_DriveName, TEXT( "tz87" ) ) != NULL ||
+ strstr( DILNT_DriveName, TEXT( "dlt2700" ) ) != NULL ||
+ strstr( DILNT_DriveName, TEXT( "dlt2000" ) ) != NULL ) ) ) {
+
+ status = PrepareTape( DILNT_deviceHandle,
+ TAPE_UNLOAD,
+ TRUE ) ;
+ }
+ StoreRetBufInfo( tmpTCB, status ) ;
+ CloseHandle( DILNT_deviceHandle ) ;
+ DILNT_deviceHandle = INVALID_HANDLE_VALUE ;
+ break ;
+ }
+
+ // TpCloseRewind
+ case GEN_RCLOSE:
+ {
+ DWORD status = NO_ERROR ;
+
+ /* This is a kludge for the DLT drive. The drive won't
+ write a directory track on the tape until an unload
+ is done, so we do an unload before we exit the app.
+ This will also rewind the drive, and it is called
+ for immediate return (last param TRUE) so the outward
+ effect is the same as the rewind immediate called for
+ all other drives.
+ */
+ if( strstr( DILNT_DriveName, TEXT( "cipher" ) ) != NULL ||
+ ( strstr( DILNT_DriveName, TEXT( "dec" ) ) != NULL &&
+ ( strstr( DILNT_DriveName, TEXT( "thz02" ) ) != NULL ||
+ strstr( DILNT_DriveName, TEXT( "tz86" ) ) != NULL ||
+ strstr( DILNT_DriveName, TEXT( "tz87" ) ) != NULL ||
+ strstr( DILNT_DriveName, TEXT( "dlt2700" ) ) != NULL ||
+ strstr( DILNT_DriveName, TEXT( "dlt2000" ) ) != NULL ) ) ) {
+
+ status = PrepareTape( DILNT_deviceHandle,
+ TAPE_UNLOAD,
+ TRUE ) ;
+ } else {
+
+ status = SetTapePosition( DILNT_deviceHandle,
+ TAPE_REWIND,
+ 0,
+ 0,
+ 0,
+ TRUE ) ;
+ }
+ StoreRetBufInfo( tmpTCB, status ) ;
+ CloseHandle( DILNT_deviceHandle ) ;
+ DILNT_deviceHandle = INVALID_HANDLE_VALUE ;
+ break ;
+ }
+
+ // TpRead
+ case GEN_READ:
+ {
+ DWORD amount_read = 0L ;
+ BOOLEAN status ;
+ UINT8_PTR baddr = tmpTCB->dil_request.baddr;
+ UINT32 length = tmpTCB->dil_request.length;
+
+ status = ReadFile( DILNT_deviceHandle,
+ (PVOID)baddr,
+ (DWORD)length,
+ &amount_read,
+ NULL ) ;
+
+ StoreRetBufInfo( tmpTCB, status ) ;
+ tmpTCB->ret_stuff.len_req = length ;
+ tmpTCB->ret_stuff.buffer = baddr ;
+ tmpTCB->ret_stuff.len_got = amount_read ;
+ break;
+ }
+
+ // TpRelease
+ case GEN_RELEASE:
+ {
+ StoreRetBufInfo( tmpTCB, NO_ERROR ) ;
+ break;
+ }
+
+ // TpReset
+ case GEN_RESET:
+ {
+ StoreRetBufInfo( tmpTCB, NO_ERROR ) ;
+ break;
+ }
+
+ // TpWrite
+ case GEN_WRITE:
+ {
+ BOOLEAN status ;
+ DWORD written ;
+ UINT8_PTR baddr = tmpTCB->dil_request.baddr;
+ UINT32 length = tmpTCB->dil_request.length;
+
+ status = WriteFile( DILNT_deviceHandle,
+ (PVOID)baddr,
+ (DWORD)length,
+ &written,
+ NULL ) ;
+
+ StoreRetBufInfo( tmpTCB, status ) ;
+ tmpTCB->ret_stuff.len_req = length ;
+ tmpTCB->ret_stuff.buffer = baddr ;
+ tmpTCB->ret_stuff.len_got = written ;
+ break;
+ }
+
+ // TpRewind
+ case GEN_REWIND:
+ {
+ DWORD status ;
+ BOOLEAN immediate = (BOOLEAN)tmpTCB->dil_request.parm1;
+
+ if (immediate) {
+ status = SetTapePosition( DILNT_deviceHandle,
+ TAPE_REWIND,
+ 0,
+ 0,
+ 0,
+ TRUE ) ;
+ } else {
+ status = SetTapePosition( DILNT_deviceHandle,
+ TAPE_REWIND,
+ 0,
+ 0,
+ 0,
+ FALSE ) ;
+ }
+
+ StoreRetBufInfo( tmpTCB, status ) ;
+ break;
+ }
+
+ // TpRetension
+ case GEN_RETEN:
+ {
+ DWORD status ;
+
+ status = PrepareTape( DILNT_deviceHandle,
+ TAPE_TENSION,
+ FALSE ) ;
+
+ StoreRetBufInfo( tmpTCB, status ) ;
+ break;
+ }
+
+ // TpErase
+ case GEN_ERASE:
+ {
+ DWORD status ;
+ ULONG lowpart = gb_drv_features.LowPart;
+
+ switch( tmpTCB->dil_request.misc ) {
+
+ case ERASE_TYPE_FORMAT:
+ status = PrepareTape( DILNT_deviceHandle,
+ TAPE_FORMAT,
+ FALSE ) ;
+ break;
+
+ default:
+ if ( lowpart & TAPE_DRIVE_ERASE_LONG ) {
+ status = EraseTape( DILNT_deviceHandle,
+ TAPE_ERASE_LONG,
+ FALSE ) ;
+ } else {
+
+ status = EraseTape( DILNT_deviceHandle,
+ TAPE_ERASE_SHORT,
+ FALSE ) ;
+ }
+ break;
+ }
+
+ StoreRetBufInfo( tmpTCB, status ) ;
+ break;
+ }
+
+ // TpWriteEndSet
+ case GEN_WRITE_ENDSET:
+ {
+ DWORD status ;
+ LONG highpart = gb_drv_features.HighPart;
+
+ if ( highpart & TAPE_DRIVE_WRITE_FILEMARKS ) {
+ status = WriteTapemark( DILNT_deviceHandle,
+ TAPE_FILEMARKS,
+ 1,
+ FALSE ) ;
+ } else if ( highpart & TAPE_DRIVE_WRITE_SHORT_FMKS ) {
+ status = WriteTapemark( DILNT_deviceHandle,
+ TAPE_SHORT_FILEMARKS,
+ 1,
+ FALSE ) ;
+ } else {
+ status = WriteTapemark( DILNT_deviceHandle,
+ TAPE_LONG_FILEMARKS,
+ 1,
+ FALSE ) ;
+ }
+
+ StoreRetBufInfo( tmpTCB, status ) ;
+ break;
+ }
+
+ // TpReadEndSet and TpSpace
+
+ // Note: TpSpace is a super set of TpReadEndSet, and will
+ // eventually replace it all together. The following
+ // code uses the new defines, but the values match
+ // those of the old defines so both are supported.
+
+ case GEN_SPACE: // Was GEN_READ_ENDSET
+ {
+ DWORD status = NO_ERROR ;
+ DWORD offset_hi ;
+ DWORD lst_err ;
+ INT16 incr ;
+ INT16 count = tmpTCB->dil_request.misc;
+ INT16 type = (INT16)tmpTCB->dil_request.parm1;
+
+ if ( type == SPACE_BKWD_FMK || type == SPACE_BKWD_BLK ) {
+ offset_hi = 0xffffffff ;
+ count = -count ;
+ incr = -1 ;
+ } else {
+ offset_hi = 0 ;
+ incr = 1 ;
+ }
+
+ switch( type ) {
+
+ case SPACE_EOD: // Was TO_EOD
+
+ /* The following is a kludge to deal with the fact
+ that the Wangtek 5150ES has to be at BOT when
+ you issue a seek to EOD, or it will crawl up and
+ down the whole tape looking for it.
+ */
+ if( strstr( DILNT_DriveName, TEXT( "wangtek" ) ) != NULL &&
+ strstr( DILNT_DriveName, TEXT( "5150es" ) ) != NULL ) {
+
+ status = SetTapePosition( DILNT_deviceHandle,
+ TAPE_REWIND,
+ 0,
+ 0,
+ 0,
+ FALSE ) ;
+ }
+
+ if( status == NO_ERROR ) {
+ status = SetTapePosition( DILNT_deviceHandle,
+ TAPE_SPACE_END_OF_DATA,
+ 0,
+ 0,
+ 0,
+ FALSE ) ;
+ }
+ break ;
+
+ case SPACE_BKWD_FMK: // Was BACKWARD
+ case SPACE_FWD_FMK: // Was FORWARD
+
+ do {
+ status = SetTapePosition( DILNT_deviceHandle,
+ TAPE_SPACE_FILEMARKS,
+ 0,
+ incr,
+ offset_hi,
+ FALSE ) ;
+
+ if( status != NO_ERROR ) {
+ lst_err = GetLastError( ) ;
+ if( lst_err == ERROR_FILEMARK_DETECTED ||
+ lst_err == ERROR_SETMARK_DETECTED ) {
+
+ status = NO_ERROR ;
+ count -= incr ;
+ }
+ } else {
+ count -= incr ;
+ }
+ } while( count != 0 && status == NO_ERROR ) ;
+
+ if( count < 0 ) {
+ tmpTCB->ret_stuff.misc = -count ;
+ } else {
+ tmpTCB->ret_stuff.misc = count ;
+ }
+ break ;
+
+ case SPACE_BKWD_BLK: // New
+ case SPACE_FWD_BLK: // New
+
+ status = SetTapePosition( DILNT_deviceHandle,
+ TAPE_SPACE_RELATIVE_BLOCKS,
+ 0,
+ count,
+ offset_hi,
+ FALSE ) ;
+ break ;
+
+ }
+
+ StoreRetBufInfo( tmpTCB, status ) ;
+ break;
+ }
+
+ // TpStatus
+ case GEN_STATUS:
+ {
+ DWORD status ;
+ TAPE_GET_MEDIA_PARAMETERS parms ;
+ DWORD buffsize;
+
+ status = GetTapeStatus( DILNT_deviceHandle );
+
+ StoreRetBufInfo( tmpTCB, status ) ;
+
+ buffsize = sizeof( TAPE_GET_MEDIA_PARAMETERS );
+
+ status = GetTapeParameters( DILNT_deviceHandle,
+ GET_TAPE_MEDIA_INFORMATION,
+ &buffsize,
+ &parms ) ;
+
+ if ( status == SUCCESS && parms.WriteProtected == TRUE) {
+ tmpTCB->ret_stuff.status |= TPS_WRITE_PROTECT ;
+ }
+
+ break;
+ }
+
+ // TpSeek
+ case GEN_SEEK:
+ {
+ DWORD status ;
+ UINT32 block = tmpTCB->dil_request.parm1;
+
+ // Make it zero relative
+ block-- ;
+
+ status = SetTapePosition( DILNT_deviceHandle,
+ TAPE_LOGICAL_BLOCK,
+ 0,
+ block,
+ 0,
+ FALSE ) ;
+
+ StoreRetBufInfo( tmpTCB, status ) ;
+ break;
+ }
+
+ case GEN_GETPOS:
+ {
+ DWORD partition = 0 ;
+ DWORD block = 0 ;
+ DWORD block_hi = 0 ;
+ DWORD status ;
+
+ status = GetTapePosition( DILNT_deviceHandle,
+ TAPE_LOGICAL_POSITION,
+ &partition,
+ &block,
+ &block_hi ) ;
+
+ StoreRetBufInfo( tmpTCB, status ) ;
+
+ // Increment block address to make it 1 based
+ block++ ;
+ tmpTCB->ret_stuff.misc = block ;
+ break;
+ }
+
+ // TpMount
+ case GEN_MOUNT:
+ {
+ DWORD status;
+ TAPE_GET_MEDIA_PARAMETERS parms ;
+ DWORD buffsize;
+ TAPE_GET_DRIVE_PARAMETERS drivebuff;
+ TAPE_SET_MEDIA_PARAMETERS mediabuff;
+
+ if ( gb_drv_features.HighPart & TAPE_DRIVE_LOCK_UNLOCK ) {
+ PrepareTape( DILNT_deviceHandle,
+ TAPE_LOCK,
+ FALSE ) ;
+ }
+
+ status = GetTapeStatus( DILNT_deviceHandle );
+
+ StoreRetBufInfo( tmpTCB, status ) ;
+
+ if ( tmpTCB->ret_stuff.gen_error != GEN_NO_ERR) {
+ if (gb_drv_features.HighPart & TAPE_DRIVE_LOCK_UNLOCK) {
+
+ status = PrepareTape( DILNT_deviceHandle,
+ TAPE_UNLOCK,
+ FALSE ) ;
+ }
+
+ break ;
+ }
+
+
+ buffsize = sizeof( TAPE_GET_MEDIA_PARAMETERS );
+
+ status = GetTapeParameters( DILNT_deviceHandle,
+ GET_TAPE_MEDIA_INFORMATION,
+ &buffsize,
+ &parms ) ;
+
+ StoreRetBufInfo( tmpTCB, status ) ;
+
+ if ( status != NO_ERROR ) {
+ if ( ( tmpTCB->ret_stuff.gen_error != GEN_NO_ERR) &&
+ (gb_drv_features.HighPart & TAPE_DRIVE_LOCK_UNLOCK) ) {
+
+ status = PrepareTape( DILNT_deviceHandle,
+ TAPE_UNLOCK,
+ FALSE ) ;
+ }
+ break ;
+ }
+
+
+ if (parms.WriteProtected == TRUE) {
+ tmpTCB->ret_stuff.status |= TPS_WRITE_PROTECT ;
+ }
+
+ buffsize = sizeof( TAPE_GET_DRIVE_PARAMETERS );
+
+ status = GetTapeParameters( DILNT_deviceHandle,
+ GET_TAPE_DRIVE_INFORMATION,
+ &buffsize,
+ &drivebuff );
+
+ StoreRetBufInfo( tmpTCB, status ) ;
+
+ if (status != NO_ERROR) {
+ if ( ( tmpTCB->ret_stuff.gen_error != GEN_NO_ERR) &&
+ (gb_drv_features.HighPart & TAPE_DRIVE_LOCK_UNLOCK) ) {
+
+ status = PrepareTape( DILNT_deviceHandle,
+ TAPE_UNLOCK,
+ FALSE ) ;
+ }
+ break ;
+ }
+
+
+ // Store drive features
+ gb_drv_features.LowPart = drivebuff.FeaturesLow;
+ gb_drv_features.HighPart = drivebuff.FeaturesHigh;
+
+ if (parms.BlockSize == 0) {
+ mediabuff.BlockSize = drivebuff.DefaultBlockSize;
+
+ SetTapeParameters( DILNT_deviceHandle,
+ SET_TAPE_MEDIA_INFORMATION,
+ &mediabuff );
+ }
+
+ break;
+ }
+
+ case GEN_DISMOUNT:
+ {
+ DWORD status;
+
+ if ( gb_drv_features.HighPart & TAPE_DRIVE_LOCK_UNLOCK ) {
+ status = PrepareTape( DILNT_deviceHandle,
+ TAPE_UNLOCK,
+ FALSE ) ;
+ StoreRetBufInfo( tmpTCB, status ) ;
+ } else {
+ StoreRetBufInfo( tmpTCB, NO_ERROR ) ;
+ }
+
+ break;
+ }
+
+ case GEN_EJECT:
+ {
+ DWORD status = NO_ERROR;
+
+
+ if ( gb_drv_features.HighPart & TAPE_DRIVE_LOCK_UNLOCK ) {
+ status = PrepareTape( DILNT_deviceHandle,
+ TAPE_UNLOCK,
+ FALSE ) ;
+ }
+
+ if ( status == NO_ERROR ) {
+ status = PrepareTape( DILNT_deviceHandle,
+ TAPE_UNLOAD,
+ FALSE );
+ }
+
+ StoreRetBufInfo( tmpTCB, status ) ;
+ break;
+ }
+
+ default:
+ continue;
+
+ } // END - switch( tmpTCB->dil_request.gen_func_code )
+
+ while ( WaitForSingleObject( DILNT_CQueueSemaphore, NOWAIT ) ) {
+ ThreadSwitch( ) ;
+ }
+ dretcode = CDequeue( &DILNT_CQueue, &dummyTCB );
+ if ( dummyTCB.ret_stuff.gen_error ) {
+
+ // Reset the queue to empty, EXCEPT the OutCQueue pointer,
+ // the TpReceive must have a chance to let the app get the
+ // last processed request in error
+ DILNT_CQueue.q_tail = DILNT_CQueue.q_head;
+ DILNT_ProcessErrorFlag = 1;
+
+ // reset the DILNT_OKToProcessSemaphore to non-signaled state
+ while ( WaitForSingleObject( DILNT_OKToProcessSemaphore, 0L ) == SIGNALEDSTATE ) ;
+ }
+
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+
+ } // END - while ( FOREVER_FOREVER )
+
+ ExitThread( FOREVER_STOP );
+
+}
+
+/**
+
+ Name: CreateAThread
+
+ Description: Creates a thread
+
+ Returns: HANDLE to the thread created
+
+**/
+
+HANDLE CreateAThread( VOID )
+{
+ HANDLE hthread;
+ DWORD pdword;
+
+ hthread = CreateThread( NULL, // security descriptor
+ (DWORD) 0, // stack size
+ (LPVOID)ProcessRequest, // ptr to a function
+ NULL, // ptr to argument
+ 0, // creation flag
+ &pdword ); // thread id
+ return ( hthread ) ;
+}
+
+
+/**
+
+ Name: InitSpecialThread
+
+ Description: Creates the TpSpecial Thread
+
+ Returns: HANDLE to the thread created
+
+**/
+
+HANDLE InitSpecialThread( VOID )
+{
+ HANDLE hthread;
+ DWORD pdword;
+
+ InitializeCriticalSection( &DILNT_SpecialCriticalSection ) ;
+ DILNT_SpecialCode = 0 ;
+ DILNT_SpecialDone = TRUE ;
+ DILNT_SpecialEnd = FALSE ;
+
+ hthread = CreateThread( NULL, // security descriptor
+ (DWORD) 0, // stack size
+ (LPVOID)ProcessSpecial, // ptr to a function
+ NULL, // ptr to argument
+ 0, // creation flag
+ &pdword ); // thread id
+ return ( hthread ) ;
+}
+
+/**/
+/**
+
+ Name: ProcessSpecial
+
+ Description: This function runs on a separate thread and processes
+ TpSpecial commands.
+
+ Returns: Nothing
+
+ Notes:
+
+**/
+
+static VOID ProcessSpecial( VOID )
+{
+ DRV_INF_PTR drvinf ;
+ UINT16 ret_val ;
+ TAPE_GET_DRIVE_PARAMETERS getdrive ;
+ TAPE_GET_MEDIA_PARAMETERS getmedia ;
+ TAPE_SET_MEDIA_PARAMETERS setmedia ;
+ TAPE_SET_DRIVE_PARAMETERS setdrive ;
+ DWORD buffsize ;
+ DWORD reply ;
+ INT16 i ;
+ INT16 j ;
+ INT16 sp_serv ;
+ UINT32 misc ;
+ BOOLEAN kill_myself = FALSE ;
+ BOOLEAN done ;
+
+ while( 1 + 1 == 2 ) {
+
+ sp_serv = 0 ;
+
+ while( !sp_serv ) {
+ EnterCriticalSection( &DILNT_SpecialCriticalSection ) ;
+ if( DILNT_SpecialEnd ) {
+ kill_myself = TRUE ;
+ }
+ else if( sp_serv = DILNT_SpecialCode ) {
+ DILNT_SpecialCode = 0 ;
+ misc = DILNT_SpecialMisc ;
+ }
+ LeaveCriticalSection( &DILNT_SpecialCriticalSection ) ;
+ if( kill_myself ) {
+ ExitThread( 0 ) ;
+ }
+ Sleep( 5 ) ;
+ }
+
+ ret_val = SUCCESS ;
+
+ switch( sp_serv ) {
+
+ case SS_GET_DRV_INF:
+ buffsize = sizeof( TAPE_GET_DRIVE_PARAMETERS ) ;
+ for( i = 0, reply = !NO_ERROR; reply != NO_ERROR && i < 8; i++ ) {
+ reply = GetTapeParameters( DILNT_deviceHandle,
+ GET_TAPE_DRIVE_INFORMATION,
+ &buffsize,
+ &getdrive ) ;
+ }
+ if( reply != NO_ERROR ) {
+ ret_val = FAILURE ;
+ break ;
+ }
+
+ // Store drive features
+ gb_drv_features.LowPart = getdrive.FeaturesLow;
+ gb_drv_features.HighPart = getdrive.FeaturesHigh;
+
+ buffsize = sizeof( TAPE_GET_MEDIA_PARAMETERS );
+
+ getmedia.BlockSize = 0;
+ reply = GetTapeParameters( DILNT_deviceHandle,
+ GET_TAPE_MEDIA_INFORMATION,
+ &buffsize,
+ &getmedia );
+
+ if( reply != NO_ERROR ) {
+ getmedia.BlockSize = getdrive.DefaultBlockSize ;
+ }
+
+ if( getmedia.BlockSize == 0 ) {
+ setmedia.BlockSize = getmedia.BlockSize = getdrive.DefaultBlockSize ;
+
+ if ( SetTapeParameters( DILNT_deviceHandle,
+ SET_TAPE_MEDIA_INFORMATION,
+ &setmedia ) ) {
+
+ setmedia.BlockSize = getmedia.BlockSize = 0x200 ;
+
+ if ( SetTapeParameters( DILNT_deviceHandle,
+ SET_TAPE_MEDIA_INFORMATION,
+ &setmedia ) ) {
+ getmedia.BlockSize = 0;
+ }
+ }
+
+ }
+
+
+ drvinf = (DRV_INF_PTR)misc ;
+
+ strcpy( drvinf->drv_vendor, TEXT("") ) ;
+ strcpy( drvinf->drv_product, TEXT("") ) ;
+ strcpy( drvinf->drv_firmrev, TEXT("") ) ;
+
+ drvinf->drv_media = UNKNOWN ;
+ drvinf->drv_bsize = (UINT16)getmedia.BlockSize ;
+ drvinf->drv_features &= TDI_DRV_COMPRES_INIT ;
+ drvinf->drv_features |= TDI_NODATA | TDI_NODATA_FMK ;
+
+ if ( getdrive.Compression ) {
+ drvinf->drv_features |= TDI_DRV_COMPRESS_ON ;
+ }
+
+ if( gb_drv_features.HighPart & TAPE_DRIVE_SET_COMPRESSION ) {
+ drvinf->drv_features |= TDI_DRV_COMPRESSION ;
+ }
+
+ if( gb_drv_features.HighPart & TAPE_DRIVE_FILEMARKS ) {
+ drvinf->drv_features |= TDI_FAST_FMK ;
+ }
+
+ if( gb_drv_features.HighPart & TAPE_DRIVE_LOGICAL_BLK ) {
+ drvinf->drv_features |= TDI_FAST_NBLK ;
+ }
+
+ if( gb_drv_features.HighPart & TAPE_DRIVE_END_OF_DATA ) {
+ drvinf->drv_features |= TDI_FAST_EOD ;
+ }
+
+ if( gb_drv_features.HighPart & TAPE_DRIVE_REVERSE_POSITION ) {
+
+ if ( gb_drv_features.HighPart & TAPE_DRIVE_RELATIVE_BLKS ) {
+ drvinf->drv_features |= TDI_REV_FMK ;
+ }
+ }
+
+ if( ( gb_drv_features.LowPart & TAPE_DRIVE_FIXED ) ||
+ ( gb_drv_features.LowPart & TAPE_DRIVE_SELECT ) ||
+ ( gb_drv_features.LowPart & TAPE_DRIVE_INITIATOR ) ) {
+
+ drvinf->drv_features |= TDI_DIR_TRACK ;
+ }
+
+ if( gb_drv_features.LowPart & TAPE_DRIVE_GET_LOGICAL_BLK ) {
+ drvinf->drv_features |= TDI_BLK_POS ;
+ }
+
+ if( gb_drv_features.LowPart & TAPE_DRIVE_ERASE_SHORT ) {
+ drvinf->drv_features |= TDI_SHORT_ERASE ;
+ }
+
+ if( gb_drv_features.LowPart & TAPE_DRIVE_ERASE_LONG ) {
+ drvinf->drv_features |= TDI_LONG_ERASE ;
+ }
+
+ if( ( gb_drv_features.HighPart & TAPE_DRIVE_WRITE_FILEMARKS ) ||
+ ( gb_drv_features.HighPart & TAPE_DRIVE_WRITE_SHORT_FMKS ) ||
+ ( gb_drv_features.HighPart & TAPE_DRIVE_WRITE_LONG_FMKS ) ) {
+
+ drvinf->drv_features |= TDI_FMK;
+ }
+
+ if( gb_drv_features.HighPart & TAPE_DRIVE_TENSION ) {
+ drvinf->drv_features |= TDI_RETENSION;
+ }
+
+ if( gb_drv_features.HighPart & TAPE_DRIVE_FORMAT ) {
+ drvinf->drv_features |= TDI_FORMAT;
+ }
+
+ if( gb_drv_features.HighPart & TAPE_DRIVE_SET_BLOCK_SIZE ) {
+ drvinf->drv_features |= TDI_CHNG_BLK_SIZE ;
+ }
+
+ /* The following is a kludge to deal with the fact that many
+ drives support "Load/Unload" commands, but we only want to
+ set the TDI_ feature bit on those drives which actually
+ eject the tape from the drive automatically. In future
+ versions of NT, the drivers will have a separate feature
+ bit for this, and this kludge can and should be removed.
+ */
+ if( strstr( DILNT_SpecialDriveName, TEXT( "scsi" ) ) != NULL &&
+ strstr( DILNT_SpecialDriveName, TEXT( "exb-2501" ) ) == NULL &&
+ strstr( DILNT_SpecialDriveName, TEXT( "wangtek" ) ) == NULL &&
+ ( strstr( DILNT_SpecialDriveName, TEXT( "tandberg" ) ) == NULL ||
+ ( strstr( DILNT_SpecialDriveName, TEXT( " TDC 3500" ) ) == NULL &&
+ strstr( DILNT_SpecialDriveName, TEXT( " TDC 3700" ) ) == NULL ) ) &&
+
+ strstr( DILNT_SpecialDriveName, TEXT( "cipher" ) ) == NULL &&
+ ( strstr( DILNT_SpecialDriveName, TEXT( "dec" ) ) == NULL ||
+ ( strstr( DILNT_SpecialDriveName, TEXT( "thz02" ) ) == NULL &&
+ strstr( DILNT_SpecialDriveName, TEXT( "tz86" ) ) == NULL &&
+ strstr( DILNT_SpecialDriveName, TEXT( "tz87" ) ) == NULL &&
+ strstr( DILNT_SpecialDriveName, TEXT( "dlt2000" ) ) == NULL &&
+ strstr( DILNT_SpecialDriveName, TEXT( "dlt2700" ) ) == NULL ) ) &&
+ strstr( DILNT_SpecialDriveName, TEXT( "viper" ) ) == NULL ) {
+
+ }
+ if( gb_drv_features.HighPart & TAPE_DRIVE_LOAD_UNLOAD ) {
+ if ( gb_drv_features.HighPart & TAPE_DRIVE_EJECT_MEDIA) {
+ drvinf->drv_features |= TDI_UNLOAD ;
+ }
+ }
+ break ;
+
+
+ case SS_SET_DRV_COMPRESSION:
+
+ // Get drive info to see if it supports hardware compression
+
+ buffsize = sizeof( TAPE_GET_DRIVE_PARAMETERS ) ;
+
+ for( i = 0, reply = !NO_ERROR; reply != NO_ERROR && i < 8; i++ ) {
+ reply = GetTapeParameters( DILNT_deviceHandle,
+ GET_TAPE_DRIVE_INFORMATION,
+ &buffsize,
+ &getdrive ) ;
+ }
+
+ if( reply != NO_ERROR ) {
+ ret_val = FAILURE ;
+ break ;
+ }
+
+ // If the doesn't support hardware compression, get out.
+
+ if( !( getdrive.FeaturesHigh & TAPE_DRIVE_SET_COMPRESSION ) ) {
+ ret_val = FAILURE ;
+ break ;
+ }
+
+ // Set up setdrive buffer
+
+ setdrive.ECC = getdrive.ECC ;
+ setdrive.DataPadding = getdrive.DataPadding ;
+ setdrive.ReportSetmarks = getdrive.ReportSetmarks ;
+ setdrive.EOTWarningZoneSize = getdrive.EOTWarningZoneSize ;
+
+ switch ( misc ) {
+
+ case ENABLE_DRV_COMPRESSION:
+ setdrive.Compression = TRUE ;
+ break ;
+
+ case DISABLE_DRV_COMPRESSION:
+ setdrive.Compression = FALSE ;
+ break ;
+
+ default:
+ msassert( FALSE ) ;
+ ret_val = FAILURE ;
+ break ;
+ }
+
+ if( ret_val == FAILURE ) {
+ break ;
+ }
+
+ // If we're already in the requested mode, we're done.
+
+ if( ( getdrive.Compression && setdrive.Compression ) ||
+ ( !getdrive.Compression && !setdrive.Compression ) ) {
+
+ break ;
+ }
+
+ // Request the mode change
+
+ reply = SetTapeParameters( DILNT_deviceHandle,
+ SET_TAPE_DRIVE_INFORMATION,
+ &setdrive ) ;
+
+ if( reply != NO_ERROR ) {
+ ret_val = FAILURE ;
+ break ;
+ }
+
+ /* Here we're going to try five times to get the tape
+ parameters and verify that we're in the right mode.
+ If after 5 trys we're still not in the requested mode,
+ we're going to quit and call it a failure.
+ */
+ buffsize = sizeof( TAPE_GET_DRIVE_PARAMETERS ) ;
+ done = FALSE ;
+
+ for( j = 0; !done && j < 5; j++ ) {
+ reply = !NO_ERROR ;
+
+ for( i = 0; reply != NO_ERROR && i < 8; i++ ) {
+ reply = GetTapeParameters( DILNT_deviceHandle,
+ GET_TAPE_DRIVE_INFORMATION,
+ &buffsize,
+ &getdrive ) ;
+ }
+
+ if( reply != NO_ERROR ) {
+ ret_val = FAILURE ;
+ done = TRUE ;
+ } else {
+ if( misc == ENABLE_DRV_COMPRESSION ) {
+ if( getdrive.Compression ) {
+ done = TRUE ;
+ }
+ } else {
+ if( !getdrive.Compression ) {
+ done = TRUE ;
+ }
+ }
+ }
+ }
+
+ // Finally, we check to see if we did it
+
+ if( !done ) {
+ ret_val = FAILURE ;
+ }
+ break ;
+
+
+ case SS_CHANGE_BLOCK_SIZE:
+ /* Check if tape format wants to set drive to its default
+ block size, or set drive to the value passed in thru misc. */
+ if( misc == DEFAULT_BLOCK_SIZE ) {
+ buffsize = sizeof( TAPE_GET_DRIVE_PARAMETERS ) ;
+
+ reply = GetTapeParameters( DILNT_deviceHandle,
+ GET_TAPE_DRIVE_INFORMATION,
+ &buffsize,
+ &getdrive ) ;
+
+ if ( reply ) {
+ switch( reply ) {
+ case ERROR_BUS_RESET:
+ case ERROR_MEDIA_CHANGED:
+ if ( GetTapeParameters( DILNT_deviceHandle,
+ GET_TAPE_DRIVE_INFORMATION,
+ &buffsize,
+ &getdrive ) ) {
+ ret_val = FAILURE ;
+ }
+ break;
+
+ default:
+ ret_val = FAILURE ;
+ }
+ }
+ setmedia.BlockSize = getdrive.DefaultBlockSize ;
+
+ } else {
+ setmedia.BlockSize = (ULONG) misc ;
+ }
+
+ if( ret_val == SUCCESS ) {
+ if( strstr( DILNT_SpecialDriveName, TEXT( "archive" ) ) != NULL &&
+ strstr( DILNT_SpecialDriveName, TEXT( "ancda" ) ) != NULL ) {
+
+ /* This is a kludge for the stupid Anaconda drive
+ because you can't set the block size unless
+ you're at BOT.
+ */
+
+ if( SetTapePosition( DILNT_deviceHandle,
+ TAPE_REWIND,
+ 0,
+ 0,
+ 0,
+ FALSE ) != NO_ERROR ) {
+ ret_val = FAILURE ;
+ }
+ }
+
+ if( ret_val == SUCCESS ) {
+ /* Change the block size */
+ if( SetTapeParameters( DILNT_deviceHandle,
+ SET_TAPE_MEDIA_INFORMATION,
+ &setmedia ) ) {
+
+ if( misc == DEFAULT_BLOCK_SIZE ) {
+
+ /* this is a kludge for a stupid 1/4 in
+ drive that won't except its default
+ blk size */
+
+ setmedia.BlockSize = 0x200 ;
+
+ if( SetTapeParameters( DILNT_deviceHandle,
+ SET_TAPE_MEDIA_INFORMATION,
+ &setmedia ) ) {
+
+ ret_val = FAILURE ;
+ }
+ }
+ }
+ }
+ }
+ break ;
+
+
+ default:
+ ret_val = FAILURE ;
+ break ;
+ }
+
+ EnterCriticalSection( &DILNT_SpecialCriticalSection ) ;
+ DILNT_SpecialReturn = (BOOLEAN)ret_val ;
+ DILNT_SpecialDone = TRUE ;
+ LeaveCriticalSection( &DILNT_SpecialCriticalSection ) ;
+ }
+}
+
+
+
+/*------------------------------------------------------------------------
+
+ NOTES on implemetation of a circular queue
+
+ Below routines pertains to a singular linked circular queue.
+ The previous data structures have been used unmodified.
+
+ To enqueue an element, move the tail pointer one position clockwise
+ and write the element in that position.
+
+ To dequeue an element, move the head pointer one position clockwise.
+
+ An empty queue is detected by the head equalling the tail. The queue
+ is full if the tail->next is equalled to the head.
+
+ The queue does not ever get filled. There is always one unused node
+ in the circular queue. Thus if you want N number of nodes to hold
+ elements, you should have N+1 number of linked list nodes.
+
+------------------------------------------------------------------------*/
+
+/**
+
+ Name: IsCQueueEmpty
+
+ Description: Test to see if the circular queue is empty
+
+ Returns:
+ FAILURE - if queue is empty
+ SUCCESS - if queue is not empty
+
+**/
+
+BOOLEAN IsCQueueEmpty( Q_HEADER_PTR queue )
+{
+ if ( queue->q_tail == queue->q_head ) {
+ return( FAILURE );
+ }
+
+ return( SUCCESS );
+
+}
+
+/**
+
+ Name: IsCOutQueueEmpty
+
+ Description: Test to see if the circular out queue is empty
+
+ Returns:
+ FAILURE - if queue is empty
+ SUCCESS - if queue is not empty
+
+**/
+
+BOOLEAN IsCOutQueueEmpty( Q_HEADER_PTR outqueue,
+ Q_HEADER_PTR CQueue
+)
+{
+
+ if ( outqueue->q_head == CQueue->q_head ) {
+ return( FAILURE );
+ }
+
+ return( SUCCESS );
+
+}
+
+
+/**
+
+ Name: IsCQueueFull
+
+ Description: Test to see if the circular queue is full
+
+ Returns:
+ FAILURE - if queue is full
+ SUCCESS - if queue is not not full
+
+**/
+
+BOOLEAN IsCQueueFull( Q_HEADER_PTR queue,
+ Q_HEADER_PTR outqueue
+)
+{
+
+ Q_ELEM_PTR element;
+ Q_ELEM_PTR outelement;
+
+ outelement = (Q_ELEM_PTR) outqueue->q_head;
+ element = (Q_ELEM_PTR) queue->q_tail->q_next;
+
+ if ( element == outelement ) {
+ return( FAILURE );
+ }
+
+ return( SUCCESS );
+
+}
+
+/**
+
+ Name: CEnqueue
+
+ Description: Place an element to the circular queue.
+
+ Advance the rear pointer one position and add the
+ element.
+
+ Returns:
+ SUCCESS - if queue is empty
+ FAILURE - if queue is not empty
+
+**/
+BOOLEAN CEnqueue( Q_HEADER_PTR queue,
+ Q_HEADER_PTR outqueue,
+ FAKE_TCB tmpTCB
+)
+{
+
+ BOOLEAN retcode;
+ Q_ELEM_PTR element;
+ FAKE_TCB_PTR loadTCB;
+
+ retcode = IsCQueueFull( queue, outqueue );
+ if ( retcode ) { // queue is full
+ return( FAILURE );
+ }
+
+ element = (Q_ELEM_PTR) queue->q_tail;
+ element = element->q_next;
+
+ loadTCB = (FAKE_TCB_PTR)element;
+ queue->q_tail = (Q_ELEM_PTR)element;
+
+ memcpy( &(loadTCB->dil_request), &(tmpTCB.dil_request), sizeof(MSL_REQUEST) );
+ memcpy( &(loadTCB->ret_stuff), &( tmpTCB.ret_stuff ), sizeof( RET_BUF ) );
+ queue->q_count++; // number of elements in the queue
+
+ return( SUCCESS ); // queue was not full
+}
+
+/**
+
+ Name: CDequeue
+
+ Description: remove an element from the circular queue.
+ Advance the front pointer one position
+ element.
+
+ Returns:
+ SUCCESS - Queue dequeued successful
+ FAILURE - Queue dequeued failed
+
+**/
+
+BOOLEAN CDequeue( Q_HEADER_PTR queue,
+ FAKE_TCB_PTR tmpTCB
+)
+{
+
+ BOOLEAN retcode;
+ FAKE_TCB_PTR loadTCB;
+ Q_ELEM_PTR element;
+
+ retcode = IsCQueueEmpty( queue );
+ if ( retcode ) { // queue is empty
+ return( FAILURE );
+ }
+
+ element = (Q_ELEM_PTR) queue->q_head;
+ element = element->q_next;
+
+ queue->q_head = ( Q_ELEM_PTR ) element;
+ loadTCB = (FAKE_TCB_PTR)queue->q_head;
+ memcpy( tmpTCB, loadTCB, sizeof( FAKE_TCB ) );
+
+ return( SUCCESS ); // queue was not empty
+}
+
+/**
+
+ Name: COutDequeue
+
+ Description: remove an element from the circular out queue.
+ Advance the front pointer one position.
+
+ Returns: SUCCESS - Queue dequeued successful
+ FAILURE - Queue dequeued failed
+
+**/
+
+BOOLEAN COutDequeue( Q_HEADER_PTR outqueue,
+ Q_HEADER_PTR CQueue
+)
+{
+
+ BOOLEAN retcode;
+ Q_ELEM_PTR element;
+
+ retcode = IsCOutQueueEmpty( outqueue, CQueue );
+ if ( retcode ) { // queue is empty
+ return( FAILURE );
+ }
+
+ element = (Q_ELEM_PTR) outqueue->q_head;
+ element = element->q_next;
+
+ outqueue->q_head = ( Q_ELEM_PTR ) element;
+ CQueue->q_count--;
+
+ return( SUCCESS ); // queue was not empty
+}
+
+
+/**
+
+ Name: CreateCQueue
+
+ Description: Create a circular queue. The number of elements in
+ a circular is always one more than needed. Because
+ one element is always left unused.
+
+ Returns:
+
+**/
+
+BOOLEAN CreateCQueue( Q_HEADER_PTR queue,
+ Q_HEADER_PTR outqueue // out queue
+)
+{
+ INT16 i ;
+ Q_ELEM_PTR elementptr;
+
+ if ( NUM_TCBS <= 0 ) {
+ queue->q_head = queue->q_tail = NULL;
+ return( FAILURE );
+ }
+
+ // initialize the contents to NULLs
+ for( i = 0 ; i < NUM_TCBS + 1; i++ ) {
+ memset( &tcbs[i], 0, sizeof( FAKE_TCB ) );
+ }
+
+ queue->q_count = 0;
+
+ // set up the single linked circular queue
+ for( i = 0 ; i < NUM_TCBS ; i++ ) {
+ elementptr = ( Q_ELEM_PTR )( &tcbs[i] );
+ elementptr->q_element = i; // number the elements in the queue
+ // used for debugging aid
+ elementptr->q_next = ( Q_ELEM_PTR )( &tcbs[i + 1] );
+ }
+
+ elementptr = ( Q_ELEM_PTR )( &tcbs[NUM_TCBS] );
+ elementptr->q_element = NUM_TCBS;
+ elementptr->q_next = ( Q_ELEM_PTR )( &tcbs[0] );
+
+ // start with an empty circular queue
+ // let the head equal the tail
+ queue->q_head = queue->q_tail = elementptr;
+
+ // Start with an empty out queue for the TpReceive calls
+ // let the out queue equal the head
+ outqueue->q_head = elementptr;
+
+ return( SUCCESS );
+}
+
+VOID InitializeTapeBlockSize( )
+{
+ static DWORD TapeBlockSize = 0 ;
+ if ( TapeBlockSize == 0 ) {
+ // read the block size from the registry
+ HKEY key ;
+
+ if ( !RegOpenKeyEx( HKEY_CURRENT_USER,
+ TEXT("Software\\Microsoft\\Ntbackup\\Backup Engine"),
+ 0,
+ KEY_QUERY_VALUE,
+ &key ) ) {
+
+ DWORD type ;
+ CHAR buffer[20] ;
+ DWORD num_bytes = sizeof(buffer) ;
+ if ( RegQueryValueEx( key, TEXT("Tape Block Size"),
+ NULL, &type,
+ (char *)buffer,
+ &num_bytes ) ) {
+ TapeBlockSize = 1 ;
+ } else {
+ TapeBlockSize = atoi(buffer) ;
+ }
+ RegCloseKey( key ) ;
+ }
+
+ }
+
+ if ( TapeBlockSize < 512 ) {
+ TAPE_GET_DRIVE_PARAMETERS drivebuff;
+ DWORD buffsize ;
+
+ buffsize = sizeof( TAPE_GET_DRIVE_PARAMETERS );
+
+ if (!GetTapeParameters( DILNT_deviceHandle,
+ GET_TAPE_DRIVE_INFORMATION,
+ &buffsize,
+ &drivebuff ) ) {
+
+ TapeBlockSize = drivebuff.DefaultBlockSize;
+ }
+ }
+
+
+ if ( TapeBlockSize >= 512 ) {
+ TAPE_SET_MEDIA_PARAMETERS mediabuff;
+
+ mediabuff.BlockSize = TapeBlockSize ;
+
+ SetTapeParameters( DILNT_deviceHandle,
+ SET_TAPE_MEDIA_INFORMATION,
+ &mediabuff );
+ }
+}
+
diff --git a/private/utils/ntbackup/src/dilnttp.c b/private/utils/ntbackup/src/dilnttp.c
new file mode 100644
index 000000000..600919d24
--- /dev/null
+++ b/private/utils/ntbackup/src/dilnttp.c
@@ -0,0 +1,1621 @@
+/**
+Copyright(c) Conner Software Products Group 1993
+
+ Name: dilnttp.c
+
+ Description: Contains all the Tp... device independent layer functions.
+
+ $Log: T:/LOGFILES/DILNTTP.C_V $
+
+ Rev 1.1.1.10 16 Mar 1994 19:27:06 GREGG
+Added support for two more DEC DLT drives: tz86 and tz87.
+
+ Rev 1.1.1.9 01 Mar 1994 15:24:20 GREGG
+Store last error on failed TpSpecial calls.
+
+ Rev 1.1.1.8 07 Feb 1994 01:24:10 GREGG
+Only get drive id string once at init (EPR 139).
+
+ Rev 1.1.1.7 01 Feb 1994 15:12:08 GREGG
+Put TEXT macros debug print format strings.
+
+ Rev 1.1.1.6 28 Jan 1994 18:25:20 GREGG
+Fixed MIPS 16 byte alignment requirement bug.
+
+ Rev 1.1.1.5 07 Jan 1994 15:34:02 GREGG
+Treat DEC's DLT2000 and DLT2700 the same as the THZ02.
+
+ Rev 1.1.1.4 05 Jan 1994 20:42:22 GREGG
+Handle some TpSpecial requests as no-ops instead of errors.
+
+ Rev 1.1.1.3 17 Dec 1993 16:40:04 GREGG
+Extended error reporting.
+
+ Rev 1.1.1.2 08 Dec 1993 20:30:38 GREGG
+Merged in all the fixes Orcas needed from past it's branch.
+
+ Rev 1.1.1.1 29 Nov 1993 12:35:12 GREGG
+Don't de-init the special thread if it wasn't inited.
+
+ Rev 1.1.1.0 21 Nov 1993 23:27:18 GREGG
+Make TpSpecial call run on their own thread.
+
+ Rev 1.1 17 May 1993 18:17:24 GREGG
+Added function TpSpace, which is a super set of TpReadEndSet, and will
+eventually replace it, but for now, they map to the same gen func code
+(defined as both GEN_ERR_ENDSET and GEN_SPACE), have identical arguments,
+and have the same value for equivalent defined values for their parameters.
+Also changed the case in ProcessRequest to handle both functions.
+
+ Rev 1.0 17 May 1993 17:16:24 GREGG
+DILNTTP.C, DILNTMSC.C and DILNTPRV.H replace DIL_NT.C at rev. 1.44.
+
+**/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "windows.h"
+#include "winioctl.h"
+#include "ntddscsi.h"
+
+#include "stdtypes.h"
+#include "queues.h"
+#include "dilhwd.h"
+#include "mslreq.h"
+#include "retbuf.h"
+#include "genfuncs.h"
+#include "generr.h"
+#include "drvinf.h"
+#include "special.h"
+#include "genstat.h"
+#include "dddefs.h"
+#include "ld_dvr.h"
+#include "debug.h"
+#include "muiconf.h"
+#include "msassert.h"
+#include "be_debug.h"
+#include "dilntprv.h"
+
+#ifndef MS_RELEASE
+#define DEBUG_DIL 1
+#endif
+
+extern INT DILNT_ProcessErrorFlag ; // Flag to notify Tp calls that an error
+ // was encountered. Flag is set in
+ // the ProcessRequest proc and reset
+ // int the TpReceive proc.
+
+extern LARGE_INTEGER gb_drv_features ;
+extern INT TapeDevice ;
+extern HANDLE DILNT_deviceHandle ;
+extern HANDLE DILNT_CQueueSemaphore ; // Semaphore to control the
+ // circular queue
+extern HANDLE DILNT_OKToProcessSemaphore ; // global semaphore to release
+ // the thread for processing
+extern HANDLE DILNT_QThread_0 ; // global thread handle for
+ // the queue manager
+
+extern Q_HEADER DILNT_CQueue ; // Circular queue (in and process)
+extern Q_HEADER DILNT_OutCQueue ; // Pointer into the circular queue
+ // this is used by the TpReceive
+ // proc to pop the element off.
+
+extern INT DILNT_FOREVER ;
+
+
+// Externed Globals and Init Prototype for TpSpecial Thread
+
+extern INT16 DILNT_SpecialCode ;
+extern UINT32 DILNT_SpecialMisc ;
+extern BOOLEAN DILNT_SpecialDone ;
+extern BOOLEAN DILNT_SpecialEnd ;
+extern BOOLEAN DILNT_SpecialReturn ;
+extern HANDLE DILNT_SpecialThread ;
+extern CHAR DILNT_SpecialDriveName[] ;
+extern CRITICAL_SECTION DILNT_SpecialCriticalSection ;
+
+HANDLE InitSpecialThread( VOID ) ;
+
+// For storing drive registry string
+extern CHAR DILNT_DriveName[] ;
+
+// For SS_GET_LAST_ERROR
+
+static RET_BUF last_error_info ;
+static BOOLEAN last_error_valid ;
+
+
+/**/
+/**
+
+ Name: TpInit
+
+ Description: Initializes the driver
+
+ Returns: SUCCESS if the driver was initialized successfully, or
+ FAILURE if it wasn't.
+
+ Notes: THIS MUST BE CALLED BEFORE ANYTHING ELSE.
+
+**/
+
+BOOLEAN TpInit( DIL_HWD_PTR tapedevs,
+ INT16 no_cntls
+)
+{
+ CHAR buffer[50] ;
+ BOOLEAN retcode ;
+
+ // initialize flag to no error
+ DILNT_ProcessErrorFlag = 0;
+ last_error_valid = FALSE ;
+
+ sprintf( buffer, TEXT("\\\\.\\Tape%d"), TapeDevice );
+
+ DILNT_deviceHandle = CreateFile( buffer,
+ GENERIC_READ|GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL ) ;
+
+ // Check to see if there is a tape drive present
+ // If not, then fail the TpInit() call
+ if ( DILNT_deviceHandle != INVALID_HANDLE_VALUE ) {
+ retcode = CloseHandle( DILNT_deviceHandle ) ;
+
+ strcpy( tapedevs->driver_label, TEXT("SCSI Tape 1.0") ) ;
+ tapedevs->no_attached_drives = 1 ;
+ tapedevs->init_error = 0 ;
+
+ // Create the TpSpecial Thread
+ if( DILNT_SpecialThread == NULL ) {
+ if( ( DILNT_SpecialThread = InitSpecialThread( ) ) == NULL ) {
+ return( FAILURE ) ;
+ }
+ }
+
+ // Create the semaphore for managing the queue
+ DILNT_CQueueSemaphore = CreateSemaphore( NULL, 1L, 1L, NULL );
+ if ( !DILNT_CQueueSemaphore ) {
+ return( FAILURE );
+ }
+
+ // Create semaphore to be used as a counter of the number of
+ // requests in the queue to be processed. This is used by the
+ // thread to determine if there is anything in the queue to
+ // process. Counter is incremented whenever any requests have been
+ // queued successfully.
+ DILNT_OKToProcessSemaphore = CreateSemaphore( NULL, 0L, (LONG) NUM_TCBS , NULL );
+ if ( !DILNT_OKToProcessSemaphore ) {
+ CloseHandle( DILNT_CQueueSemaphore );
+ return( FAILURE );
+ }
+
+ // Create and initialize the queue elements into a single linked
+ // circular queue.
+ retcode = CreateCQueue( &DILNT_CQueue, &DILNT_OutCQueue ); // Create the Circular queue
+ if ( retcode ) {
+ CloseHandle( DILNT_CQueueSemaphore );
+ CloseHandle( DILNT_OKToProcessSemaphore );
+ return( FAILURE );
+ }
+
+
+ // Create the thread to process request
+ if ( DILNT_QThread_0 == NULL ) {
+ DILNT_QThread_0 = CreateAThread( ) ;
+ }
+
+ if ( !DILNT_QThread_0 ) {
+ CloseHandle( DILNT_CQueueSemaphore );
+ CloseHandle( DILNT_OKToProcessSemaphore );
+ return( FAILURE );
+ }
+
+ } else {
+ tapedevs->no_attached_drives = 0 ;
+ tapedevs->init_error = DD_INIT_ERR_NO_DRIVES;
+ }
+
+#ifdef DEBUG_DIL
+ zprintf( DEBUG_TEMPORARY, TEXT("TpInit(): Drives found = %d\n"),
+ tapedevs->no_attached_drives ) ;
+#endif
+
+ return( SUCCESS );
+}
+
+/**/
+/**
+
+ Name: TpAuto
+
+ Description: Determines hardware information
+
+ Returns: SUCCESS if function complete
+ FAILURE if it wasn't.
+
+ Notes:
+
+**/
+
+BOOLEAN TpAuto( DIL_HWD_PTR tapedevs,
+ INT16 no_cntls
+)
+{
+ return( SUCCESS ) ;
+}
+
+/**/
+/**
+
+ Name: TpRelease
+
+ Description: Release the driver and frees its memory.
+
+ Returns: Nothing
+
+ Notes: MAKE SURE THERE ARE NO PENDING REQUESTS BEFORE RELEASING,
+ AS TpRelease() DOES NO CHECKING.
+
+**/
+
+VOID TpRelease( )
+{
+
+ DWORD retstatus;
+
+ // Tell the TpSpecial thread to kill itself.
+ if( DILNT_SpecialThread != NULL ) {
+ EnterCriticalSection( &DILNT_SpecialCriticalSection ) ;
+ DILNT_SpecialEnd = TRUE ;
+ LeaveCriticalSection( &DILNT_SpecialCriticalSection ) ;
+ do {
+ ThreadSwitch( ) ;
+ if( !GetExitCodeThread( DILNT_SpecialThread, &retstatus ) ) break ;
+ Sleep( 5 ) ;
+ } while ( retstatus == STILL_ACTIVE ) ;
+
+ DILNT_SpecialThread = NULL ;
+ }
+
+ DILNT_FOREVER = FOREVER_STOP;
+
+ do {
+ ThreadSwitch( ) ;
+ if ( !GetExitCodeThread( DILNT_QThread_0, &retstatus ) ) break;
+ Sleep( 5 ) ;
+ } while ( retstatus == STILL_ACTIVE );
+
+ //
+ // Kill the thread, semaphores and close the tape device
+ //
+
+// retcode = CloseHandle( DILNT_QThread_0 );
+// generalerror = GetLastError( );
+
+ CloseHandle( DILNT_CQueueSemaphore );
+
+ CloseHandle( DILNT_OKToProcessSemaphore );
+
+ CloseHandle( DILNT_deviceHandle ) ;
+
+ if ( retstatus == FOREVER_STOP ) {
+ DILNT_QThread_0 = NULL;
+ }
+
+ DILNT_FOREVER = FOREVER_FOREVER;
+
+ return;
+}
+
+/**/
+/**
+
+ Name: TpReset
+
+ Description: Resets the specified drive, aborting all requests on
+ the queue, and physically resetting the drive.
+
+ Returns: SUCCESS if function complete
+ FAILURE if it wasn't.
+
+ Notes:
+
+**/
+
+BOOLEAN TpReset( INT16 tape_hdl
+)
+{
+ if ( DILNT_ProcessErrorFlag ) {
+ return( FAILURE );
+ }
+
+ return( SUCCESS ) ;
+
+}
+
+/**/
+/**
+
+ Name: TpOpen
+
+ Description: Opens the drive specified by the hardware controller, and
+ the drive number.
+
+ Returns: An INT16. 0 if the drive was not opened, a positive value
+ if it was successfully opened.
+
+ Notes:
+
+**/
+
+INT16 TpOpen( DIL_HWD_PTR hwd,
+ INT16 drvno
+)
+{
+ INT16 status ;
+ CHAR buffer[50] ;
+ CHAR_PTR tstr ;
+
+ sprintf( buffer, TEXT("\\\\.\\Tape%d"), TapeDevice );
+
+ DILNT_deviceHandle = CreateFile( buffer,
+ GENERIC_READ|GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL ) ;
+
+ if ( DILNT_deviceHandle == INVALID_HANDLE_VALUE ) {
+ status = FALSE ;
+ } else {
+ status = TRUE ;
+
+ /* This is a kludge for the DLT drive. The drive won't write a
+ directory track on the tape until an unload is done, so we do
+ an unload before we exit the app. As a result, we need to
+ attempt to reload the tape when we start the app. The call is
+ made to return immediately (last param TRUE) rather than
+ waiting for the rewind to complete, so there won't be any
+ noticeable delay in the app startup, but TpStatus will report
+ that there isn't a tape in the drive until the load completes
+ (about 1-2 minutes). We don't check this call for an error,
+ because we just inited the drive a few milliseconds ago so
+ the only possible error is a load failure because the tape
+ is already loaded or there is no tape (either way we don't
+ care).
+ */
+ tstr = (CHAR_PTR)CDS_GetTapeDriveName( CDS_GetPerm( ) ) ;
+ if( tstr != NULL ) {
+ strncpy( DILNT_DriveName, tstr, 80 ) ;
+ DILNT_DriveName[80] = TEXT( '\0' ) ;
+ strlwr( DILNT_DriveName ) ;
+ strcpy( DILNT_SpecialDriveName, DILNT_DriveName ) ;
+ if( strstr( DILNT_DriveName, TEXT( "cipher" ) ) != NULL ||
+ ( strstr( DILNT_DriveName, TEXT( "dec" ) ) != NULL &&
+ ( strstr( DILNT_DriveName, TEXT( "thz02" ) ) != NULL ||
+ strstr( DILNT_DriveName, TEXT( "tz86" ) ) != NULL ||
+ strstr( DILNT_DriveName, TEXT( "tz87" ) ) != NULL ||
+ strstr( DILNT_DriveName, TEXT( "dlt2700" ) ) != NULL ||
+ strstr( DILNT_DriveName, TEXT( "dlt2000" ) ) != NULL ) ) ) {
+
+ PrepareTape( DILNT_deviceHandle, TAPE_LOAD, TRUE ) ;
+ }
+ } else {
+ DILNT_DriveName[0] = TEXT( '\0' ) ;
+ DILNT_SpecialDriveName[0] = TEXT( '\0' ) ;
+ }
+ }
+
+#ifdef DEBUG_DIL
+ zprintf( DEBUG_TEMPORARY, TEXT("TpOpen(): %s\n"), ( status ) ? TEXT("Success") : TEXT("Failed") ) ;
+#endif
+
+ return( status ) ;
+
+}
+
+/**/
+/**
+
+ Name: TpClose
+
+ Description: Close the specifed handle.
+
+ Returns: A SUCCESS if the request was enqueue'd and a FAILURE if
+ it was not.
+
+ Notes:
+
+**/
+
+
+BOOLEAN TpClose( INT16 tape_hdl )
+{
+
+ BOOLEAN retcode;
+ FAKE_TCB tmpTCB;
+
+ while ( WaitForSingleObject( DILNT_CQueueSemaphore, NOWAIT ) ) {
+ ThreadSwitch( ) ;
+ }
+
+ if ( DILNT_ProcessErrorFlag ) {
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ retcode = FAILURE ;
+ } else {
+
+ // set up function to perform
+ tmpTCB.dil_request.gen_func_code = GEN_NRCLOSE ;
+ tmpTCB.dil_request.baddr = NULL ;
+ tmpTCB.dil_request.length = 0 ;
+ tmpTCB.dil_request.parm1 = 0L ;
+ tmpTCB.dil_request.misc = 0 ;
+
+ retcode = CEnqueue( &DILNT_CQueue, &DILNT_OutCQueue, tmpTCB );
+ if ( retcode == SUCCESS ) {
+ ReleaseSemaphore( DILNT_OKToProcessSemaphore, 1L, NULL );
+ }
+
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ }
+ if( retcode == FAILURE ) {
+ last_error_valid = TRUE ;
+ last_error_info.call_type = GEN_NRCLOSE ;
+ }
+
+ return( retcode ) ;
+}
+
+
+/**/
+/**
+
+ Name: TpCloseRewind
+
+ Description: Closes the specified handle, and rewinds the tape in
+ the drive.
+
+ Returns: A SUCCESS if the request was enqueue'd and a FAILURE if
+ it was not.
+
+ Notes:
+
+**/
+
+BOOLEAN TpCloseRewind( INT16 tape_hdl )
+{
+ BOOLEAN retcode;
+ FAKE_TCB tmpTCB;
+
+ while ( WaitForSingleObject( DILNT_CQueueSemaphore, NOWAIT ) ) {
+ ThreadSwitch( ) ;
+ }
+
+ if ( DILNT_ProcessErrorFlag ) {
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ retcode = FAILURE ;
+ } else {
+
+ // set up function to perform
+ tmpTCB.dil_request.gen_func_code = GEN_RCLOSE ;
+ tmpTCB.dil_request.baddr = NULL ;
+ tmpTCB.dil_request.length = 0 ;
+ tmpTCB.dil_request.parm1 = 0L ;
+ tmpTCB.dil_request.misc = 0 ;
+
+ retcode = CEnqueue( &DILNT_CQueue, &DILNT_OutCQueue, tmpTCB );
+ if ( retcode == SUCCESS ) {
+ ReleaseSemaphore( DILNT_OKToProcessSemaphore, 1L, NULL );
+ }
+
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ }
+
+ if( retcode == FAILURE ) {
+ last_error_valid = TRUE ;
+ last_error_info.call_type = GEN_RCLOSE ;
+ }
+
+ return( retcode ) ;
+
+}
+
+/**/
+/**
+
+ Name: TpWrite
+
+ Description: Writes the specified number of bytes from the specified
+ buffer to the specified drive.
+
+ Returns: A SUCCESS if the request was enqueue'd and a FAILURE if
+ it was not.
+
+ Notes: The requested number of bytes MUST ALWAYS BE A MULTIPLE
+ of the BLOCK SIZE OF the device.
+
+**/
+
+BOOLEAN TpWrite( INT16 tape_hdl,
+ UINT8_PTR baddr,
+ UINT32 length
+)
+{
+ BOOLEAN retcode;
+ FAKE_TCB tmpTCB;
+
+ while ( WaitForSingleObject( DILNT_CQueueSemaphore, NOWAIT ) ) {
+ ThreadSwitch( ) ;
+ }
+
+ if ( DILNT_ProcessErrorFlag ) {
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ retcode = FAILURE ;
+ } else {
+
+ // set up function to perform
+ tmpTCB.dil_request.gen_func_code = GEN_WRITE ;
+ tmpTCB.dil_request.baddr = baddr ;
+ tmpTCB.dil_request.length = length ;
+ tmpTCB.dil_request.parm1 = 0L ;
+ tmpTCB.dil_request.misc = 0 ;
+
+ retcode = CEnqueue( &DILNT_CQueue, &DILNT_OutCQueue, tmpTCB );
+ if ( retcode == SUCCESS ) {
+ ReleaseSemaphore( DILNT_OKToProcessSemaphore, 1L, NULL );
+ }
+
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ }
+
+ if( retcode == FAILURE ) {
+ last_error_valid = TRUE ;
+ last_error_info.call_type = GEN_WRITE ;
+ }
+
+ return( retcode ) ;
+
+}
+
+/**/
+/**
+
+ Name: TpRead
+
+ Description: Reads the specified number of bytes from the tape.
+
+ Returns: A SUCCESS if the request was enqueue'd and a FAILURE if
+ it was not.
+
+ Notes: The requested number of bytes MUST ALWAYS BE A MULTIPLE
+ of the BLOCK SIZE OF the device.
+
+**/
+
+BOOLEAN TpRead( INT16 tape_hdl,
+ UINT8_PTR baddr,
+ UINT32 length
+)
+{
+ BOOLEAN retcode;
+ FAKE_TCB tmpTCB;
+
+ while ( WaitForSingleObject( DILNT_CQueueSemaphore, NOWAIT ) ) {
+ ThreadSwitch( ) ;
+ }
+
+ if ( DILNT_ProcessErrorFlag ) {
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ retcode = FAILURE ;
+ } else {
+
+ // set up function to perform
+ tmpTCB.dil_request.gen_func_code = GEN_READ ;
+ tmpTCB.dil_request.baddr = baddr ;
+ tmpTCB.dil_request.length = length ;
+ tmpTCB.dil_request.parm1 = 0L ;
+ tmpTCB.dil_request.misc = 0 ;
+
+ retcode = CEnqueue( &DILNT_CQueue, &DILNT_OutCQueue, tmpTCB );
+ if ( retcode == SUCCESS ) {
+ ReleaseSemaphore( DILNT_OKToProcessSemaphore, 1L, NULL );
+ }
+
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ }
+
+ if( retcode == FAILURE ) {
+ last_error_valid = TRUE ;
+ last_error_info.call_type = GEN_READ ;
+ }
+
+ return( retcode ) ;
+}
+
+/**/
+/**
+
+ Name: TpRewind
+
+ Description: Rewinds the Tape in the specified drive.
+
+ Returns: A SUCCESS if the request was enqueue'd and a FAILURE if
+ it was not.
+
+ Notes:
+
+**/
+
+BOOLEAN TpRewind( INT16 tape_hdl,
+ BOOLEAN immediate
+)
+{
+ BOOLEAN retcode;
+ FAKE_TCB tmpTCB;
+
+ while ( WaitForSingleObject( DILNT_CQueueSemaphore, NOWAIT ) ) {
+ ThreadSwitch( ) ;
+ }
+
+ if ( DILNT_ProcessErrorFlag ) {
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ retcode = FAILURE ;
+ } else {
+
+ // set up function to perform
+ tmpTCB.dil_request.gen_func_code = GEN_REWIND ;
+ tmpTCB.dil_request.baddr = NULL ;
+ tmpTCB.dil_request.length = 0 ;
+ tmpTCB.dil_request.parm1 = ( UINT32 ) immediate ;
+ tmpTCB.dil_request.misc = 0 ;
+
+ retcode = CEnqueue( &DILNT_CQueue, &DILNT_OutCQueue, tmpTCB );
+ if ( retcode == SUCCESS ) {
+ ReleaseSemaphore( DILNT_OKToProcessSemaphore, 1L, NULL );
+ }
+
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ }
+
+ if( retcode == FAILURE ) {
+ last_error_valid = TRUE ;
+ last_error_info.call_type = GEN_REWIND ;
+ }
+
+ return( retcode ) ;
+}
+
+/**/
+/**
+
+ Name: TpRetension
+
+ Description: Retensions a tape in the specified tape drive.
+
+ Returns: A SUCCESS if the request was enqueue'd and a FAILURE if
+ it was not.
+
+ Notes:
+
+**/
+
+BOOLEAN TpRetension( INT16 tape_hdl )
+{
+ BOOLEAN retcode;
+ FAKE_TCB tmpTCB;
+
+ while ( WaitForSingleObject( DILNT_CQueueSemaphore, NOWAIT ) ) {
+ ThreadSwitch( ) ;
+ }
+
+ if ( DILNT_ProcessErrorFlag ) {
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ retcode = FAILURE ;
+ } else {
+
+ // set up function to perform
+ tmpTCB.dil_request.gen_func_code = GEN_RETEN ;
+ tmpTCB.dil_request.baddr = NULL ;
+ tmpTCB.dil_request.length = 0 ;
+ tmpTCB.dil_request.parm1 = 0L ;
+ tmpTCB.dil_request.misc = 0 ;
+
+ retcode = CEnqueue( &DILNT_CQueue, &DILNT_OutCQueue, tmpTCB );
+ if ( retcode == SUCCESS ) {
+ ReleaseSemaphore( DILNT_OKToProcessSemaphore, 1L, NULL );
+ }
+
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ }
+
+ if( retcode == FAILURE ) {
+ last_error_valid = TRUE ;
+ last_error_info.call_type = GEN_RETEN ;
+ }
+
+ return( retcode ) ;
+
+}
+
+/**/
+/**
+
+ Name: TpErase
+
+ Description: Erase the tape in the specified drive.
+
+ Returns: A SUCCESS if the request was enqueue'd and a FAILURE if
+ it was not.
+
+ Notes:
+
+**/
+
+BOOLEAN TpErase( INT16 tape_hdl, INT16 type )
+{
+ BOOLEAN retcode;
+ FAKE_TCB tmpTCB;
+
+ while ( WaitForSingleObject( DILNT_CQueueSemaphore, NOWAIT ) ) {
+ ThreadSwitch( ) ;
+ }
+
+ if ( DILNT_ProcessErrorFlag ) {
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ retcode = FAILURE ;
+ } else {
+
+ // set up function to perform
+ tmpTCB.dil_request.gen_func_code = GEN_ERASE ;
+ tmpTCB.dil_request.baddr = NULL ;
+ tmpTCB.dil_request.length = 0 ;
+ tmpTCB.dil_request.parm1 = 0L ;
+ tmpTCB.dil_request.misc = type ;
+
+ retcode = CEnqueue( &DILNT_CQueue, &DILNT_OutCQueue, tmpTCB );
+ if ( retcode == SUCCESS ) {
+ ReleaseSemaphore( DILNT_OKToProcessSemaphore, 1L, NULL );
+ }
+
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ }
+
+ if( retcode == FAILURE ) {
+ last_error_valid = TRUE ;
+ last_error_info.call_type = GEN_ERASE ;
+ }
+
+ return( retcode ) ;
+
+}
+
+/**/
+/**
+
+ Name: TpWriteEndSet
+
+ Description: Writes a filemark to the specified tape.
+
+
+ Returns: A SUCCESS if the request was enqueue'd and a FAILURE if
+ it was not.
+
+ Notes:
+
+**/
+
+BOOLEAN TpWriteEndSet( INT16 tape_hdl )
+{
+ BOOLEAN retcode;
+ FAKE_TCB tmpTCB;
+
+ while ( WaitForSingleObject( DILNT_CQueueSemaphore, NOWAIT ) ) {
+ ThreadSwitch( ) ;
+ }
+
+ if ( DILNT_ProcessErrorFlag ) {
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ retcode = FAILURE ;
+ } else {
+
+ // set up function to perform
+ tmpTCB.dil_request.gen_func_code = GEN_WRITE_ENDSET ;
+ tmpTCB.dil_request.baddr = NULL ;
+ tmpTCB.dil_request.length = 0 ;
+ tmpTCB.dil_request.parm1 = 0L ;
+ tmpTCB.dil_request.misc = 0 ;
+
+ retcode = CEnqueue( &DILNT_CQueue, &DILNT_OutCQueue, tmpTCB );
+ if ( retcode == SUCCESS ) {
+ ReleaseSemaphore( DILNT_OKToProcessSemaphore, 1L, NULL );
+ }
+
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ }
+
+ if( retcode == FAILURE ) {
+ last_error_valid = TRUE ;
+ last_error_info.call_type = GEN_WRITE_ENDSET ;
+ }
+
+ return( retcode ) ;
+}
+
+/**/
+/**
+
+ Name: TpReadEndSet
+
+ Description: This function spaces to the specified number of filemarks,
+ in the specified direction. If it cannot space the full number
+ of filemarks, the misc field in the return buffer will contain
+ the number of filemarks it didn't space.
+
+ Returns: A SUCCESS if the request was enqueue'd and a FAILURE if
+ it was not.
+
+ Notes: IT IS THE CALLER'S RESPONSIBLITY TO MAKE SURE THE REQUESTED
+ DRIVE SUPPORTS BACKWARD SPACING.
+
+**/
+
+BOOLEAN TpReadEndSet( INT16 tape_hdl, // The drive handle
+ INT16 fmks, // The number of filemarks to space
+ INT16 dir // the direction to space
+)
+{
+ BOOLEAN retcode;
+ FAKE_TCB tmpTCB;
+
+ while ( WaitForSingleObject( DILNT_CQueueSemaphore, NOWAIT ) ) {
+ ThreadSwitch( ) ;
+ }
+
+ if ( DILNT_ProcessErrorFlag ) {
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ retcode = FAILURE ;
+ } else {
+
+ // set up function to perform
+ tmpTCB.dil_request.gen_func_code = GEN_READ_ENDSET ;
+ tmpTCB.dil_request.baddr = NULL ;
+ tmpTCB.dil_request.length = 0L ;
+ tmpTCB.dil_request.parm1 = ( UINT32 ) dir ;
+ tmpTCB.dil_request.misc = fmks ;
+
+ retcode = CEnqueue( &DILNT_CQueue, &DILNT_OutCQueue, tmpTCB );
+ if ( retcode == SUCCESS ) {
+ ReleaseSemaphore( DILNT_OKToProcessSemaphore, 1L, NULL );
+ }
+
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ }
+
+ if( retcode == FAILURE ) {
+ last_error_valid = TRUE ;
+ last_error_info.call_type = GEN_READ_ENDSET ;
+ }
+
+ return( retcode ) ;
+}
+
+/**/
+/**
+
+ Name: TpSpace
+
+ Description: This function spaces the specified number of filemarks or
+ blocks in the specified direction, or to End Of Data,
+ depending on the 'space_type' parameter. In the case of
+ spacing filemarks, if it cannot space the full number
+ of filemarks, the misc field in the return buffer will
+ contain the number of filemarks it didn't space.
+
+ Returns: A SUCCESS if the request was enqueue'd and a FAILURE if
+ it was not.
+
+ Notes: It is the caller's responsiblity to make sure the drive
+ supports the type of spacing requested.
+
+ This function is a super set of TpReadEndSet! The
+ function code is defined to the same value, and it will
+ eventually replace TpReadEndSet completely.
+
+**/
+
+BOOLEAN TpSpace( INT16 tape_hdl, // The drive handle
+ INT16 count, // The number to space
+ INT16 space_type // What to space past, and which direction
+)
+{
+ BOOLEAN retcode;
+ FAKE_TCB tmpTCB;
+
+ while ( WaitForSingleObject( DILNT_CQueueSemaphore, NOWAIT ) ) {
+ ThreadSwitch( ) ;
+ }
+
+ if ( DILNT_ProcessErrorFlag ) {
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ retcode = FAILURE ;
+ } else {
+
+ // set up function to perform
+ tmpTCB.dil_request.gen_func_code = GEN_SPACE ; // Same as GEN_READ_ENDSET
+ tmpTCB.dil_request.baddr = NULL ;
+ tmpTCB.dil_request.length = 0L ;
+ tmpTCB.dil_request.parm1 = (UINT32)space_type ;
+ tmpTCB.dil_request.misc = count ;
+
+ retcode = CEnqueue( &DILNT_CQueue, &DILNT_OutCQueue, tmpTCB );
+ if ( retcode == SUCCESS ) {
+ ReleaseSemaphore( DILNT_OKToProcessSemaphore, 1L, NULL );
+ }
+
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ }
+
+ if( retcode == FAILURE ) {
+ last_error_valid = TRUE ;
+ last_error_info.call_type = GEN_SPACE ;
+ }
+
+ return( retcode ) ;
+}
+
+/**/
+/**
+
+ Name: TpReceive
+
+ Description: Gets the return information for the drive.
+
+ Returns: A SUCCESS if the return buffer is valid and filled, and
+ FAILURE if there was nothing on the return buffer.
+
+ Notes:
+
+**/
+BOOLEAN TpReceive( INT16 tape_hdl,
+ RET_BUF_PTR retpck
+)
+{
+ BOOLEAN retcode;
+ FAKE_TCB_PTR tmpTCB;
+
+ while ( WaitForSingleObject( DILNT_CQueueSemaphore, NOWAIT ) ) {
+ ThreadSwitch( ) ;
+ }
+ retcode = COutDequeue( &DILNT_OutCQueue, &DILNT_CQueue );
+
+ if ( retcode ) {
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+
+ ThreadSwitch();
+ Sleep( 5 ) ;
+
+ return( retcode );
+ }
+
+ tmpTCB = (FAKE_TCB_PTR) DILNT_OutCQueue.q_head;
+ *retpck = tmpTCB->ret_stuff;
+
+ if ( tmpTCB->ret_stuff.gen_error ) {
+ last_error_valid = TRUE ;
+ last_error_info = tmpTCB->ret_stuff ;
+ DILNT_CQueue.q_count = 0; // reset queue counter to 0
+ DILNT_ProcessErrorFlag = 0; // reset error flag to 0
+ BE_Zprintf( 0, TEXT("TpRecieve Exception: gen_error = %d call_type = %d len_req = %d\n"),
+ retpck->gen_error, retpck->call_type, retpck->len_req ) ;
+ BE_Zprintf( 0, TEXT(" len_got = %d status = 0x%04X\n"),
+ retpck->len_got, retpck->status ) ;
+ }
+
+ memset( &tmpTCB->dil_request, 0, sizeof( MSL_REQUEST ) );
+ memset( &tmpTCB->ret_stuff, 0, sizeof( RET_BUF ) );
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ return( retcode ) ;
+
+}
+
+/**/
+/**
+
+ Name: TpSpecial
+
+ Description: This function is the back door ( War Games ? ) to the
+ device driver.
+
+ Returns: Various Things for Various Calls.
+
+ Notes:
+
+**/
+
+BOOLEAN TpSpecial( INT16 tape_hdl,
+ INT16 sp_serv,
+ UINT32 misc
+)
+{
+ BOOLEAN done = FALSE ;
+ BOOLEAN ret_val = SUCCESS ;
+
+ /* Take care of some quick stuff we don't want to ask the
+ TpSpecial thread to do.
+ */
+ switch( sp_serv ) {
+
+ case SS_ERROR_RESTORE :
+ case SS_FLUSH_BUFFER :
+ case SS_KILL_DEVICE :
+ case SS_KILL_ERROR_Q :
+ case SS_KILL_IN_Q :
+ case SS_SET_STEP :
+ case SS_CLR_STEP :
+ case SS_POP_ERROR_Q :
+ case SS_LOAD_UNLOAD :
+ case SS_DUMP_DVR_DATA :
+ case SS_FIND_BLOCK :
+ case SS_SHOW_BLOCK :
+ case SS_PHYS_BLOCK :
+ case SS_FORCE_MACHINE_TYPE :
+ /* We don't currently get any of these. This is just here
+ to keep the app sane if someone decides to send one down.
+ */
+ msassert( FALSE ) ;
+ last_error_valid = TRUE ;
+ last_error_info.call_type = GEN_SPECIAL ;
+ last_error_info.gen_error = 0 ; // Field not valid for TpSpecial
+ last_error_info.misc = sp_serv ;
+ ret_val = FAILURE ;
+ break ;
+
+ case SS_GET_LAST_ERROR :
+ if( !last_error_valid ) {
+ ret_val = FAILURE ;
+ } else {
+ last_error_valid = FALSE ;
+ *((RET_BUF_PTR)misc) = last_error_info ;
+ ret_val = SUCCESS ;
+ }
+ break ;
+
+ case SS_NO_MAY_ID :
+ case SS_NO_1ST_REQ :
+ case SS_LAST_STATUS :
+ /* These are no-ops under NT */
+ ret_val = SUCCESS ;
+ break ;
+
+ case SS_IS_ERROR :
+ ret_val = FALSE ;
+ break ;
+
+ case SS_IS_INQ_EMPTY :
+ while ( WaitForSingleObject( DILNT_CQueueSemaphore, NOWAIT ) ) {
+ ThreadSwitch( ) ;
+ }
+ ret_val = DILNT_CQueue.q_count ;
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL ) ;
+ ret_val = ret_val ;
+ break ;
+
+ case SS_GET_DRV_INF :
+ case SS_CHANGE_BLOCK_SIZE :
+ case SS_SET_DRV_COMPRESSION :
+
+ // These go to the thread.
+
+ // Make sure we have our thread.
+
+ if( DILNT_SpecialThread == NULL ) {
+ BE_Zprintf( 0, TEXT("TpSpecial: DILNT_SpecialThread == NULL\n") ) ;
+ msassert( DILNT_SpecialThread != NULL ) ;
+ ret_val = FAILURE ;
+ } else {
+
+ /* If the threads in the middle of processing a command
+ alreay, this is a BAD thing. Otherwise set the global
+ to tell him what to do.
+ */
+ EnterCriticalSection( &DILNT_SpecialCriticalSection ) ;
+ if( DILNT_SpecialDone == FALSE ) {
+ BE_Zprintf( 0, TEXT("TpSpecial called while active!!!\n") ) ;
+ msassert( DILNT_SpecialThread != NULL ) ;
+ ret_val = FAILURE ;
+ } else {
+ DILNT_SpecialCode = sp_serv ;
+ DILNT_SpecialMisc = misc ;
+ DILNT_SpecialDone = FALSE ;
+ }
+ LeaveCriticalSection( &DILNT_SpecialCriticalSection ) ;
+
+ // Wait for the TpSpecial to finish.
+
+ if( ret_val == SUCCESS ) {
+ while( !done ) {
+ EnterCriticalSection( &DILNT_SpecialCriticalSection ) ;
+ if( done = DILNT_SpecialDone ) {
+ ret_val = DILNT_SpecialReturn ;
+ }
+ LeaveCriticalSection( &DILNT_SpecialCriticalSection ) ;
+ ThreadSwitch( ) ;
+ Sleep( 5 ) ;
+ }
+ }
+ }
+
+ if( ret_val == FAILURE ) {
+ last_error_valid = TRUE ;
+ last_error_info.call_type = GEN_SPECIAL ;
+ last_error_info.gen_error = 0 ; // Field not valid for TpSpecial
+ last_error_info.misc = sp_serv ;
+ }
+
+ break ;
+
+ default:
+ msassert( FALSE ) ;
+ last_error_valid = TRUE ;
+ last_error_info.call_type = GEN_SPECIAL ;
+ last_error_info.gen_error = 0 ; // Field not valid for TpSpecial
+ last_error_info.misc = sp_serv ;
+ ret_val = FAILURE ;
+ break ;
+ }
+
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Name: TpStatus
+
+ Description: Gets the current status of drive and returns it via a
+ return buffer.
+
+ Returns: A SUCCESS if the request was enqueue'd, and a FAILURE
+ if the request was not.
+
+ Notes:
+
+**/
+
+BOOLEAN TpStatus( INT16 hdl )
+{
+ BOOLEAN retcode;
+ FAKE_TCB tmpTCB;
+
+ while ( WaitForSingleObject( DILNT_CQueueSemaphore, NOWAIT ) ) {
+ ThreadSwitch( ) ;
+ }
+
+ if ( DILNT_ProcessErrorFlag ) {
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ retcode = FAILURE ;
+ } else {
+
+ // set up function to perform
+ tmpTCB.dil_request.gen_func_code = GEN_STATUS ;
+ tmpTCB.dil_request.baddr = NULL ;
+ tmpTCB.dil_request.length = 0 ;
+ tmpTCB.dil_request.parm1 = 0L ;
+ tmpTCB.dil_request.misc = 0 ;
+
+ retcode = CEnqueue( &DILNT_CQueue, &DILNT_OutCQueue, tmpTCB );
+ if ( retcode == SUCCESS ) {
+ ReleaseSemaphore( DILNT_OKToProcessSemaphore, 1L, NULL );
+ }
+
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ }
+
+ if( retcode == FAILURE ) {
+ last_error_valid = TRUE ;
+ last_error_info.call_type = GEN_STATUS ;
+ }
+
+ return( retcode ) ;
+
+}
+
+/**/
+/**
+
+ Name: TpSeek
+
+ Description: Seeks to the specified block on Tape. The first block
+ on any tape device is 1. Only the first 24 bits are
+ significant of the "block" parameter.
+
+ Returns: A SUCCESS if the request was enqueue'd, and a FAILURE
+ if the request was not.
+
+ Notes: IT IS THE PROGRAMMER'S RESPONSIBILITY TO DETERMINE
+ WHETHER OR NOT THE DRIVE SUPPORTS BLOCK POSITIONING.
+ USE THE drive information call TO FIND OUT.
+
+ DON'T CALL THIS IF THE DRIVE DOESN'T SUPPORT IT.
+
+ PHYSICAL boolean in parameter list means to go to the
+ physical block position on tape. This should only be set
+ TRUE to seek to a true physical location. For example, in
+ the QicStream 1.92 tape format, the header at the end of the
+ tape set contains the actual block position of the volume
+ table. A physical block seek must be performed to assure
+ correct positioning on all drives.
+
+**/
+
+BOOLEAN TpSeek( INT16 hdl, // The drive handle
+ UINT32 block, // The desired position
+ BOOLEAN physical // Seek to a physical tape position
+)
+{
+ BOOLEAN retcode;
+ FAKE_TCB tmpTCB;
+
+ while ( WaitForSingleObject( DILNT_CQueueSemaphore, NOWAIT ) ) {
+ ThreadSwitch( ) ;
+ }
+
+ if ( DILNT_ProcessErrorFlag ) {
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ retcode = FAILURE ;
+ } else {
+
+ // set up function to perform
+ tmpTCB.dil_request.gen_func_code = GEN_SEEK ;
+ tmpTCB.dil_request.baddr = NULL ;
+ tmpTCB.dil_request.length = 0 ;
+ tmpTCB.dil_request.parm1 = block ;
+ tmpTCB.dil_request.misc = (INT16) physical ;
+
+ retcode = CEnqueue( &DILNT_CQueue, &DILNT_OutCQueue, tmpTCB );
+ if ( retcode == SUCCESS ) {
+ ReleaseSemaphore( DILNT_OKToProcessSemaphore, 1L, NULL );
+ }
+
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ }
+
+ if( retcode == FAILURE ) {
+ last_error_valid = TRUE ;
+ last_error_info.call_type = GEN_SEEK ;
+ }
+
+ return( retcode ) ;
+
+}
+
+
+/**/
+/**
+
+ Name: TpGetPosition
+
+ Description: Gets the current block position on tape. The block numbering
+ starts at 1. The block position is returned in the misc field
+ of the return buffer.
+
+ Returns: A SUCCESS if the request was enqueue'd, and a FAILURE
+ if the request was not.
+
+ Notes: IT IS THE PROGRAMMER'S RESPONSIBILITY TO DETERMINE
+ WHETHER OR NOT THE DRIVE SUPPORTS BLOCK POSITIONING.
+ USE THE drive information call TO FIND OUT.
+
+ PHYSICAL boolean in parameter list means to return the
+ physical block position on tape. This should only be set
+ TRUE to get the true physical location.
+
+**/
+
+BOOLEAN TpGetPosition(
+ INT16 hdl,
+ BOOLEAN physical ) // Seek to a physical tape position
+{
+ BOOLEAN retcode;
+ FAKE_TCB tmpTCB;
+
+ while ( WaitForSingleObject( DILNT_CQueueSemaphore, NOWAIT ) ) {
+ ThreadSwitch( ) ;
+ }
+
+ if ( DILNT_ProcessErrorFlag ) {
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ retcode = FAILURE ;
+ } else {
+
+ // set up function to perform
+ tmpTCB.dil_request.gen_func_code = GEN_GETPOS ;
+ tmpTCB.dil_request.baddr = NULL ;
+ tmpTCB.dil_request.length = 0 ;
+ tmpTCB.dil_request.parm1 = 0L ;
+ tmpTCB.dil_request.misc = (INT16) physical ;
+
+ retcode = CEnqueue( &DILNT_CQueue, &DILNT_OutCQueue, tmpTCB );
+ if ( retcode == SUCCESS ) {
+ ReleaseSemaphore( DILNT_OKToProcessSemaphore, 1L, NULL );
+ }
+
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ }
+
+ if( retcode == FAILURE ) {
+ last_error_valid = TRUE ;
+ last_error_info.call_type = GEN_GETPOS ;
+ }
+
+ return( retcode ) ;
+
+}
+
+/**/
+/**
+
+ Name: TpMount
+
+ Description: Performs a mount of the tape media, testing to be sure
+ that the tape drive is ready for media access .
+
+ Returns: A SUCCESS if the request was enqueue'd, and a FAILURE
+ if the request was not.
+
+ Notes:
+
+**/
+
+BOOLEAN TpMount( INT16 tape_handle )
+{
+ BOOLEAN retcode;
+ FAKE_TCB tmpTCB;
+
+ while ( WaitForSingleObject( DILNT_CQueueSemaphore, NOWAIT ) ) {
+ ThreadSwitch( ) ;
+ }
+
+ if ( DILNT_ProcessErrorFlag ) {
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ retcode = FAILURE ;
+ } else {
+
+ // set up function to perform
+ tmpTCB.dil_request.gen_func_code = GEN_MOUNT ;
+ tmpTCB.dil_request.baddr = NULL;
+ tmpTCB.dil_request.length = 0 ;
+ tmpTCB.dil_request.parm1 = (UINT32) 0 ;
+ tmpTCB.dil_request.misc = 0 ;
+
+ retcode = CEnqueue( &DILNT_CQueue, &DILNT_OutCQueue, tmpTCB );
+ if ( retcode == SUCCESS ) {
+ ReleaseSemaphore( DILNT_OKToProcessSemaphore, 1L, NULL );
+ }
+
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ }
+
+ if( retcode == FAILURE ) {
+ last_error_valid = TRUE ;
+ last_error_info.call_type = GEN_MOUNT ;
+ }
+
+ return( retcode ) ;
+
+}
+
+/**/
+/**
+
+ Name: TpDismount
+
+ Description: Performs a dismount of the tape media.
+
+ Returns: A SUCCESS if the request was enqueue'd, and a FAILURE
+ if the request was not.
+
+ Notes:
+
+**/
+
+BOOLEAN TpDismount( INT16 tape_handle )
+{
+ BOOLEAN retcode;
+ FAKE_TCB tmpTCB;
+
+ while ( WaitForSingleObject( DILNT_CQueueSemaphore, NOWAIT ) ) {
+ ThreadSwitch( ) ;
+ }
+
+ if ( DILNT_ProcessErrorFlag ) {
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ retcode = FAILURE ;
+ } else {
+
+ // set up function to perform
+ tmpTCB.dil_request.gen_func_code = GEN_DISMOUNT ;
+ tmpTCB.dil_request.baddr = NULL;
+ tmpTCB.dil_request.length = 0 ;
+ tmpTCB.dil_request.parm1 = (UINT32) 0 ;
+ tmpTCB.dil_request.misc = 0 ;
+
+ retcode = CEnqueue( &DILNT_CQueue, &DILNT_OutCQueue, tmpTCB );
+ if ( retcode == SUCCESS ) {
+ ReleaseSemaphore( DILNT_OKToProcessSemaphore, 1L, NULL );
+ }
+
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ }
+
+ if( retcode == FAILURE ) {
+ last_error_valid = TRUE ;
+ last_error_info.call_type = GEN_DISMOUNT ;
+ }
+
+ return( retcode ) ;
+
+}
+
+/**/
+/**
+
+ Name: TpEject
+
+ Description: Performs an eject of the tape media.
+
+ Returns: A SUCCESS if the request was enqueue'd, and a FAILURE
+ if the request was not.
+
+ Notes:
+
+**/
+
+BOOLEAN TpEject( INT16 unused )
+{
+ BOOLEAN retcode;
+ FAKE_TCB tmpTCB;
+
+ while ( WaitForSingleObject( DILNT_CQueueSemaphore, NOWAIT ) ) {
+ ThreadSwitch( ) ;
+ }
+
+ if ( DILNT_ProcessErrorFlag ) {
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ retcode = FAILURE ;
+ } else {
+
+ // set up function to perform
+ tmpTCB.dil_request.gen_func_code = GEN_EJECT ;
+ tmpTCB.dil_request.baddr = NULL;
+ tmpTCB.dil_request.length = 0 ;
+ tmpTCB.dil_request.parm1 = (UINT32) 0 ;
+ tmpTCB.dil_request.misc = 0 ;
+
+ retcode = CEnqueue( &DILNT_CQueue, &DILNT_OutCQueue, tmpTCB );
+ if ( retcode == SUCCESS ) {
+ ReleaseSemaphore( DILNT_OKToProcessSemaphore, 1L, NULL );
+ }
+
+ ReleaseSemaphore( DILNT_CQueueSemaphore, 1L, NULL );
+ }
+
+ if( retcode == FAILURE ) {
+ last_error_valid = TRUE ;
+ last_error_info.call_type = GEN_EJECT ;
+ }
+
+ return( retcode );
+}
+
+/**/
+/**
+
+ Name: TpGetTapeBuffAlignment
+
+ Description: NT only. Makes an IOCTL call to get the byte alignment
+ requirements (if any) of data transfer buffers.
+
+ Returns: SUCCESS or FAILURE
+
+ Notes:
+
+**/
+
+BOOLEAN TpGetTapeBuffAlignment( INT_PTR alignment )
+{
+ IO_SCSI_CAPABILITIES scsi_stuff ;
+ INT bytes_out ;
+ BOOLEAN retcode = FAILURE ;
+
+ *alignment = 0 ;
+
+ if ( DILNT_deviceHandle != INVALID_HANDLE_VALUE ) {
+ if( DeviceIoControl( DILNT_deviceHandle,
+ IOCTL_SCSI_GET_CAPABILITIES,
+ NULL,
+ 0,
+ &scsi_stuff,
+ sizeof( scsi_stuff ),
+ &bytes_out,
+ NULL ) ) {
+
+ retcode = SUCCESS ;
+ if( scsi_stuff.AlignmentMask ) {
+ *alignment = scsi_stuff.AlignmentMask + 1 ;
+ }
+ }
+ }
+
+ return( retcode ) ;
+}
+
+/**/
+/**
+
+ Name: TpLock
+
+ Description: OS/2 only code for "locking" the DMA data buffer for all
+ data transfers with the installed device driver.
+
+ Returns: SUCCESS or FAILURE
+
+ Notes:
+
+**/
+
+BOOLEAN TpLock( INT8_PTR unused1,
+ INT32_PTR unused2
+)
+{
+ return( SUCCESS );
+}
+
+/**/
+/**
+
+ Name: TpUnlock
+
+ Description: OS/2 specific code for unlocking a locked data buffer
+
+ Returns: SUCCESS or FAILURE
+
+ Notes:
+
+**/
+
+BOOLEAN TpUnlock( INT32_PTR unused )
+{
+ return( SUCCESS );
+}
+
+
+/**/
+VOID SetActiveMSL( DRIVERHANDLE unused )
+{
+ return ;
+}
+
+
+/**/
+UINT8_PTR DriverLoad( CHAR_PTR library_name, DRIVERHANDLE *driver_handle, VOID_PTR unused_ptr, UINT16 unused_int )
+{
+
+ return (UINT8_PTR)1 ;
+
+}
+
+
+/**/
+VOID DriverUnLoad( UINT8_PTR unused_ptr )
+{
+
+ return ;
+}
+
diff --git a/private/utils/ntbackup/src/disks.ico b/private/utils/ntbackup/src/disks.ico
new file mode 100644
index 000000000..fde70ef8e
--- /dev/null
+++ b/private/utils/ntbackup/src/disks.ico
Binary files differ
diff --git a/private/utils/ntbackup/src/dledelet.c b/private/utils/ntbackup/src/dledelet.c
new file mode 100644
index 000000000..e6fd923ae
--- /dev/null
+++ b/private/utils/ntbackup/src/dledelet.c
@@ -0,0 +1,84 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: dledelete.c
+
+ Description: This file contains code used to delete specified DLEs
+ from the DLE list. The children of the DLEs will be
+ also be released as well, including those that are
+ pointed by BSD's and are attached. All OS specific data
+ for DLEs is also released.
+
+
+ $Log: Q:/LOGFILES/DLEDELET.C_V $
+
+ Rev 1.7 18 Jun 1993 09:35:34 MIKEP
+enable C++
+
+ Rev 1.6 18 Aug 1992 10:14:18 STEVEN
+fix warnings
+
+ Rev 1.5 13 Jan 1992 18:45:34 STEVEN
+changes for WIN32 compile
+
+ Rev 1.4 20 Dec 1991 10:42:02 STEVEN
+redesign function for common functions into tables
+
+ Rev 1.3 01 Oct 1991 11:14:52 BARRY
+Include standard headers.
+
+ Rev 1.2 14 Jun 1991 17:13:26 STEVEN
+DLE_DeleteList() is no longer supported
+
+ Rev 1.1 30 May 1991 08:46:32 STEVEN
+changes to support new BSDU
+
+ Rev 1.0 09 May 1991 13:40:10 HUNTER
+Initial revision.
+
+**/
+#include <stdlib.h>
+
+#include "stdtypes.h"
+
+#include "fsys.h"
+#include "fsys_err.h"
+#include "dle.h"
+#include "dle_str.h"
+#include "fsys_prv.h"
+
+INT16 DLE_Remove(
+DLE_HAND hand , /* I - Handle to DLE list */
+GENERIC_DLE_PTR dle ) /* I - pointer to dle to remove */
+{
+ (VOID)hand ;
+
+ DLE_RemoveRecurse( dle, FALSE ) ;
+
+ return SUCCESS ;
+}
+
+
+VOID DLE_RemoveRecurse(
+GENERIC_DLE_PTR dle, /* I - dle to remove */
+BOOLEAN ignore_use ) /* I - TRUE if we should ignore use counts */
+{
+ GENERIC_DLE_PTR child_dle ;
+
+ if ( ignore_use || (!dle->attach_count && !dle->bsd_use_count) ) {
+
+ DLE_GetFirstChild( dle, &child_dle ) ;
+
+ while ( child_dle != NULL ) {
+
+ DLE_RemoveRecurse( child_dle, ignore_use ) ;
+ DLE_GetFirstChild( dle, &child_dle ) ;
+ }
+
+ func_tab[dle->type].RemoveDrive( dle ) ;
+
+ } /* if */
+
+}
+
diff --git a/private/utils/ntbackup/src/dleget.c b/private/utils/ntbackup/src/dleget.c
new file mode 100644
index 000000000..63208e209
--- /dev/null
+++ b/private/utils/ntbackup/src/dleget.c
@@ -0,0 +1,499 @@
+/**/
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: dleget.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file defines functions used to scan the Drive List.
+ Functions are provide to get the first element, then all the next
+ elements. Also functions are provided to get the first child
+ element under a specified element. And a function is provided
+ to return the number of children.
+
+
+
+ $Log: Q:/LOGFILES/DLEGET.C_V $
+
+ Rev 1.14 18 Jun 1993 09:41:42 MIKEP
+enable C++
+
+ Rev 1.13 09 Jun 1993 13:28:20 ChuckS
+Changed RecurseSearchName to match a GRFS dle if the supplied name to match
+doesn't have the flag characters. A slightly more generic solution, but
+not used because of the overhead, would be to call DLE_DeviceDispName and
+do a strcmp against that.
+
+ Rev 1.12 04 Jun 1993 17:35:02 ChuckS
+P_CLIENT & OS_DOS only: added functional form of DLE_GetDefaultDrive which
+returns the first non-remote GRFS dle as the default drive (if one exists),
+or the first dle in the list if otherwise.
+
+ Rev 1.11 26 Apr 1993 20:00:02 DON
+needed SMS_OBJECT in addition to SMS_SERVICE for getting user names/passwords
+
+ Rev 1.10 13 Apr 1993 17:07:20 JOHNES
+Put switch statements into DLE_ServerPswd and DLE_ServerUserName so that
+these would properly handle GRFS DLE types.
+
+Threw in a few msasserts to make sure we were'nt working with DLE types
+we don't support or a NULL pointer.
+
+ Rev 1.9 16 Dec 1992 11:52:40 DON
+Changed file system specific Server/Volume macros into functions - dle.h
+
+ Rev 1.8 11 Nov 1992 22:27:10 GREGG
+Unicodeized literals.
+
+ Rev 1.7 18 Aug 1992 10:16:20 STEVEN
+fix warnings
+
+ Rev 1.6 13 Jan 1992 18:46:50 STEVEN
+changes for WIN32 compile
+
+ Rev 1.5 11 Dec 1991 14:32:48 BARRY
+SMS devices have access date support.
+
+ Rev 1.4 06 Aug 1991 18:27:52 DON
+added NLM File System support
+
+ Rev 1.3 24 Jul 1991 09:41:44 DAVIDH
+Corrected warnings under Watcom compiler.
+
+ Rev 1.2 22 Jul 1991 08:33:24 BARRY
+Change strcmpi to stricmp.
+
+ Rev 1.1 03 Jun 1991 13:26:28 BARRY
+Remove product defines from conditional compilation.
+
+ Rev 1.0 09 May 1991 13:40:10 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include <string.h>
+
+#include "stdtypes.h"
+
+#include "msassert.h"
+#include "fsys.h"
+#include "fsys_err.h"
+#include "part.h"
+/* $end$ include list */
+
+/* File System specific functions which were macros in dle.h */
+
+INT16 DLE_ServerLoggedIn( GENERIC_DLE_PTR server_dle )
+{
+#if defined(FS_NLMSERVER)
+ return( server_dle->info.nlm_server->login_status );
+#elif defined( FS_SMS ) || defined( FS_GRFS )
+
+ msassert( server_dle != NULL ) ;
+
+ return( 0 );
+ (void)server_dle;
+#else
+ return( server_dle->info.server->login_status );
+#endif
+}
+
+CHAR_PTR DLE_GetServerPswd( GENERIC_DLE_PTR server_dle )
+{
+#if defined(FS_NLMSERVER)
+ return( server_dle->info.nlm_server->pswd );
+#elif defined( FS_SMS ) || defined( FS_GRFS )
+ CHAR_PTR ret_ptr=NULL ;
+
+ msassert( server_dle != NULL ) ;
+
+ /* send back a pointer to the field appropriate for this DLE type */
+ switch( DLE_GetDeviceType( server_dle ) ) {
+ case GRFS_SERVER:
+ ret_ptr = server_dle->info.grfs->password ;
+ break ;
+ case SMS_SERVICE:
+ case SMS_OBJECT:
+ ret_ptr = server_dle->info.sms_ts->password ;
+ break ;
+ default:
+ /* We're not set up for this type of DLE, yet */
+ msassert( FALSE ) ;
+ break ;
+ } /* end switch */
+
+ return( ret_ptr ) ;
+#else
+ return( server_dle->info.server->pswd );
+#endif
+}
+
+CHAR_PTR DLE_GetServerUserName( GENERIC_DLE_PTR server_dle )
+{
+#if defined(FS_NLMSERVER)
+ return( server_dle->info.nlm_server->user_name );
+#elif defined( FS_SMS ) || defined( FS_GRFS )
+ CHAR_PTR ret_ptr=NULL ;
+
+ msassert( server_dle != NULL ) ;
+
+ /* send back a pointer to the field appropriate for this DLE type */
+ switch( DLE_GetDeviceType( server_dle ) ) {
+ case GRFS_SERVER:
+ ret_ptr = server_dle->info.grfs->user_name ;
+ break ;
+ case SMS_SERVICE:
+ case SMS_OBJECT:
+ ret_ptr = server_dle->info.sms_ts->user_name ;
+ break ;
+ default:
+ /* We're not set up for this type of DLE, yet */
+ msassert( FALSE ) ;
+ break ;
+ } /* end switch */
+
+ return( ret_ptr ) ;
+#else
+ return( server_dle->info.server->user_name );
+#endif
+}
+
+UINT8 DLE_GetServerNum( GENERIC_DLE_PTR server_dle )
+{
+#if defined(FS_NLMSERVER)
+ return( server_dle->info.nlm_server->server_num );
+#elif defined( FS_SMS ) || defined( FS_GRFS )
+
+ msassert( server_dle != NULL ) ;
+
+ return( 0 );
+ (void)server_dle;
+#else
+ return( server_dle->info.server->server_num );
+#endif
+}
+
+static VOID RecurseSearchName ( GENERIC_DLE_PTR, GENERIC_DLE_PTR *, CHAR_PTR, INT16 ) ;
+
+/**/
+/**
+
+ Name: DLE_GetFirst()
+
+ Description: This function modifies the dle pointer passed in to
+ point to the first DLE in the list pointed to by the DLE handle.
+
+
+ Modified: 7-12-1989
+
+ Returns: Error codes:
+ BAD_DLE_HAND
+ NO_MORE_DLE
+ SUCCESS
+
+ Notes:
+
+ See also: $/SEE( DLE_GetNext() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 DLE_GetFirst(
+DLE_HAND hand,
+GENERIC_DLE_PTR *dle )
+{
+ *dle = (GENERIC_DLE_PTR) QueueHead( &(hand->q_hdr) ) ;
+
+ if ( *dle !=NULL ) {
+ return SUCCESS ;
+ } else {
+ return FS_NO_MORE_DLE ;
+ }
+}
+/**/
+/**
+
+ Name: DLE_GetNext()
+
+ Description: This function get the next DLE in the list. It must be
+ passed a pointer to a valid DLE. On exit the pointer is modified
+ to point to the next DLE in the list.
+
+ Modified: 7/12/1989
+
+ Returns: Error code:
+ NO_MORE_DLE
+ SUCCESS
+
+ Notes:
+
+ See also: $/SEE( DLE_GetFirst(), DLE_GetFirstChild() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 DLE_GetNext( GENERIC_DLE_PTR *dle )
+{
+ *dle = (GENERIC_DLE_PTR)QueueNext( &((*dle)->q) ) ;
+
+ if ( *dle != NULL ) {
+ return SUCCESS ;
+
+ } else {
+ return FS_NO_MORE_DLE ;
+
+ }
+}
+/**/
+/**
+
+ Name: DLE_GetPrev()
+
+ Description: This function get the previous DLE in the list. It
+ must be passed a pointer to a valid DLE. On exit the pointer
+ is modified to point to the next DLE in the list.
+
+ Modified: 7/12/1989
+
+ Returns: Error code:
+ NO_MORE_DLE
+ SUCCESS
+
+ Notes:
+
+ See also: $/SEE( DLE_GetFirst(), DLE_GetFirstChild() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 DLE_GetPrev( GENERIC_DLE_PTR *dle )
+{
+ GENERIC_DLE_PTR temp ;
+
+ temp = (GENERIC_DLE_PTR)QueuePrev( &((*dle)->q) ) ;
+
+ if ( temp != NULL ) {
+ *dle = temp ;
+
+ return SUCCESS ;
+
+ } else {
+
+ return FS_NO_MORE_DLE ;
+
+ }
+}
+/**/
+/**
+
+ Name: DLE_GetFirstChild()
+
+ Description: This function returns the first sub DLE under a
+ specified DLE. For example, Novell servers have children DLEs,
+ which are the volumes. These DLEs are created when an attachment
+ is made to the DLE. This function can be used to get a list of
+ volumes for the purpose of drive select.
+
+ Modified: 7/12/1989
+
+ Returns: An error code:
+ NO_MORE_DLE
+ SUCCESS
+
+ Notes:
+
+ See also: $/SEE( DLE_GetFirst(), DLE_GetNext() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 DLE_GetFirstChild(
+GENERIC_DLE_PTR parent_dle ,
+GENERIC_DLE_PTR *child_dle )
+{
+ *child_dle = (GENERIC_DLE_PTR)QueueHead( &(parent_dle->child_q) ) ;
+
+ if ( *child_dle == NULL ) {
+ return FS_NO_MORE_DLE ;
+ } else {
+ return SUCCESS ;
+ }
+}
+/**/
+/**
+
+ Name: DLE_FindByName()
+
+ Description: This function scans through the DLE tree looking for the
+ DLE with the spcified device name. If the specified device name is
+ NULL then this function will return the DLE for the default drive.
+
+ Modified: 7/14/1989
+
+ Returns: NOT_FOUND
+ SUCCESS
+
+ Notes: If no dle can be found then NULL is returned as the
+ DLE pointer.
+
+ A wild card for the type is -1.
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 DLE_FindByName(
+DLE_HAND hand, /* I - DLE list handle */
+CHAR_PTR name, /* I - name to search for */
+INT16 type, /* I - type of dle to search for */
+GENERIC_DLE_PTR *dle ) /* O - pointer to matched DLE */
+{
+ GENERIC_DLE_PTR temp_dle ;
+ GENERIC_DLE_PTR found_dle ;
+
+ if ( dle != NULL ) {
+ *dle = NULL ;
+ }
+
+ if ( (name == NULL) && (dle != NULL) ) {
+ *dle = hand->default_drv ;
+ } else {
+
+ temp_dle = (GENERIC_DLE_PTR)QueueHead( &(hand->q_hdr) ) ;
+
+ found_dle = NULL ;
+
+ RecurseSearchName( temp_dle, &found_dle, name, type ) ;
+
+ if ( (found_dle != NULL) && (dle != NULL) ) {
+ *dle = found_dle ;
+ }
+
+ if ( found_dle == NULL ) {
+ return FS_NOT_FOUND ;
+ }
+ }
+ return SUCCESS ;
+}
+
+#define TMP_XCH_DLE( dle ) ( ((dle)->type == FS_EMS_DRV)&&\
+ (((dle)->subtype==EMS_MDB)||((dle)->subtype==EMS_DSA))&&\
+ (((dle)->parent == NULL) || ((dle)->parent->parent == NULL)) )
+
+static VOID RecurseSearchName (
+GENERIC_DLE_PTR dle_tree,
+GENERIC_DLE_PTR *dle,
+CHAR_PTR name,
+INT16 type )
+{
+ while ( (dle_tree != NULL) &&
+ ((*dle == NULL) || TMP_XCH_DLE( *dle ) ) ) {
+
+ if ( QueueCount( &(dle_tree->child_q) ) != 0 ) {
+ RecurseSearchName ( (GENERIC_DLE_PTR)QueueHead( &(dle_tree->child_q) ) ,
+ dle, name, type ) ;
+ }
+
+ if ( ( *dle == NULL ) || TMP_XCH_DLE( *dle ) ) {
+
+ if ( !stricmp( name, dle_tree->device_name ) ) {
+ if ( ( type == ANY_DRIVE_TYPE ) || ( (UINT16)type == dle_tree->type ) ) {
+ *dle = dle_tree ;
+ }
+
+#if defined( FS_GRFS )
+ } else if ( ( type == ANY_DRIVE_TYPE || (UINT16)type == dle_tree->type )
+ && dle_tree->type == GRFS_SERVER && !stricmp( name, dle_tree->device_name + 4 * sizeof( CHAR ) ) ) {
+ *dle = dle_tree ;
+ }
+#else
+ } // matches first if ( !stricmp... ) if FS_GRFS not defined
+#endif
+ }
+ dle_tree = (GENERIC_DLE_PTR)QueueNext( &(dle_tree->q) ) ;
+ }
+}
+
+
+
+#if defined( FS_IMAGE )
+/**/
+/**
+
+ Name: DLE_SetPartName()
+
+ Description: This function sets the partition name in the specified
+ DLE.
+
+ Modified: 7/14/1989
+
+ Returns: NONE
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID DLE_SetPartName(
+DLE_HAND dle_hand , /* I - pointer to DLE list */
+UINT16 drive_num , /* I - drive number */
+UINT16 part_num , /* I - partition number */
+CHAR_PTR name ) /* I - New name */
+{
+ GENERIC_DLE_PTR dle ;
+
+ dle = (GENERIC_DLE_PTR) QueueHead( &(dle_hand->q_hdr) ) ;
+
+ while( dle != NULL ) {
+
+ if ( dle->type == LOCAL_IMAGE ) {
+
+ if ( ( (dle->info.image->drive_num & 0x7f) == (INT8)drive_num ) &&
+ ( dle->info.image->partition == (INT8)part_num ) ) {
+
+ strncpy( dle->device_name, name, PART_NAME_SIZE - 1 ) ;
+ dle->device_name[ PART_NAME_SIZE - 1 ] = TEXT('\0') ;
+ strupr( dle->device_name ) ;
+ break ;
+ }
+
+ }
+
+ dle = (GENERIC_DLE_PTR)QueueNext( &(dle->q) ) ;
+ }
+
+}
+#endif
+
+
+
+#if defined( P_CLIENT ) && defined( OS_DOS )
+
+GENERIC_DLE_PTR DLE_GetDefaultDrive( DLE_HAND dle_hand )
+{
+ GENERIC_DLE_PTR dle ;
+
+ dle = (GENERIC_DLE_PTR) QueueHead( &(dle_hand->q_hdr) ) ;
+
+ while ( dle != NULL ) {
+ if ( dle->type == GRFS_SERVER && !DLE_HasFeatures( dle, DLE_FEAT_REMOTE_DRIVE ) ) {
+ return dle ;
+ }
+
+ dle = (GENERIC_DLE_PTR)QueueNext( &(dle->q) ) ;
+ }
+ return (GENERIC_DLE_PTR) QueueHead( &(dle_hand->q_hdr ) ) ;
+}
+
+#endif
diff --git a/private/utils/ntbackup/src/dlereset.c b/private/utils/ntbackup/src/dlereset.c
new file mode 100644
index 000000000..5714c7638
--- /dev/null
+++ b/private/utils/ntbackup/src/dlereset.c
@@ -0,0 +1,153 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: dlereset.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains code used to reset the DLE list to
+ it's minimum state. The children of all DLEs which are not pointed
+ to by BSD's and are not attaced are released. All OS specific data
+ for DLEs which are not pointed to by BSD's or attached is released.
+
+
+ $Log: Q:/LOGFILES/DLERESET.C_V $
+
+ Rev 1.2 18 Jun 1993 09:44:08 MIKEP
+enable C++
+
+ Rev 1.1 01 Oct 1991 11:15:02 BARRY
+Include standard headers.
+
+ Rev 1.0 09 May 1991 13:39:02 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include <stdlib.h>
+
+#include "stdtypes.h"
+
+#include "fsys.h"
+#include "fsys_err.h"
+/* $end$ include list */
+
+static INT16 RemoveChildren( GENERIC_DLE_PTR dle );
+
+/**/
+/**
+
+ Name: DLE_ResetList()
+
+ Description: This function scans through the DLE list. For every
+ DLE which is not pointed to by any BSD's, this function will
+ remove the children and OS specific information contained in
+ the DLE. This function can be used after a TMENU selections
+ or after TMENU operations to release any unused memory.
+
+
+ Modified: 7/14/1989
+
+ Returns: Error codes as follows:
+ BAD_DLE_HAND
+ DRIVE_LIST_ERROR
+ SUCCESS
+
+ Notes:
+
+ See also: $/SEE( RemoveChildren(), DLE_GetFirst(), DLE_GetNext() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 DLE_ResetList( DLE_HAND hand )
+{
+ GENERIC_DLE_PTR dle ;
+
+ if ( DLE_GetFirst( hand, &dle ) ) {
+ return ( FS_BAD_DLE_HAND ) ;
+ }
+
+ while ( dle != NULL ) {
+
+ if ( QueueCount( &(dle->child_q) ) > 0 ) {
+ RemoveChildren( dle );
+ }
+
+ if ( dle->dynamic_info &&
+ (dle->bsd_use_count == 0) &&
+ (dle->attach_count == 0 ) &&
+ (QueueCount ( &(dle->child_q) ) == 0 ) ) {
+
+ free( dle->info.dos ) ;
+ }
+
+ if ( DLE_GetNext( &dle ) != SUCCESS ) {
+ return FS_DRIVE_LIST_ERROR ;
+ }
+
+ }
+ return SUCCESS ;
+}
+/**/
+/**
+
+ Name: RemoveChildren()
+
+ Description: This function releases all children DLSs which do not
+ have a BSD which points to them.
+
+ Modified: 7/17/1989
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+static INT16 RemoveChildren( GENERIC_DLE_PTR dle )
+{
+ GENERIC_DLE_PTR child_dle, old_dle ;
+ INT16 err_code ;
+
+ DLE_GetFirstChild ( dle, &child_dle ) ;
+
+ while ( child_dle != NULL ) {
+
+ if ( (dle->attach_count == 0) &&
+ (child_dle->bsd_use_count == 0) ) {
+
+ if ( QueueCount( &(child_dle->child_q) ) > 0 ) {
+ RemoveChildren( child_dle ) ;
+ }
+ if ( child_dle->dynamic_info &&
+ (QueueCount( &(child_dle->child_q) ) == 0 ) ) {
+
+ free( child_dle->info.dos ) ;
+
+ old_dle = child_dle ;
+
+ err_code = DLE_GetNext( &child_dle ) ;
+
+ free( old_dle ) ;
+
+ } else {
+
+ err_code = DLE_GetNext( &child_dle ) ;
+ }
+ }
+
+ if ( (err_code != SUCCESS) && (err_code != FS_NO_MORE) ) {
+ return FS_DRIVE_LIST_ERROR ;
+ }
+ }
+
+ return SUCCESS ;
+}
+
diff --git a/private/utils/ntbackup/src/dleupdat.c b/private/utils/ntbackup/src/dleupdat.c
new file mode 100644
index 000000000..269a7f1c3
--- /dev/null
+++ b/private/utils/ntbackup/src/dleupdat.c
@@ -0,0 +1,180 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: dleupdat.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains functions to update the list of
+ DLEs. Some DLEs may be dynamic in nature. For example
+ file servers and remote workstations may come and go as
+ these machines are turned on and off. These functions
+ should update the drive list to reflect the current state
+ of accessible drives.
+
+
+ $Log: M:/LOGFILES/DLEUPDAT.C_V $
+
+ Rev 1.18 04 Jan 1994 14:30:14 BARRY
+Now call fs init entry points from FS_InitFileSys, not DLE_UpdateList
+
+ Rev 1.17 03 Aug 1993 13:34:14 DOUG
+Don't flush child DLEs unless all sibling DLEs will be flushed.
+
+ Rev 1.16 18 Jun 1993 09:46:24 MIKEP
+enable C++
+
+ Rev 1.15 11 May 1993 08:19:50 BRYAN
+Fixed signed/unsigned and type mismatch warnings.
+
+ Rev 1.14 08 May 1993 14:27:58 DOUG
+Added GEN_FlushDLEs()
+
+ Rev 1.13 13 Jan 1992 18:45:24 STEVEN
+changes for WIN32 compile
+
+ Rev 1.12 07 Jan 1992 11:58:52 STEVEN
+move common routines to tables
+
+ Rev 1.11 11 Dec 1991 17:55:14 JOHNB
+Remove DLE's for Novell servers that are no longer on the NET
+
+
+ Rev 1.10 11 Dec 1991 14:37:32 BARRY
+Need to update SMS TSAs.
+
+ Rev 1.9 01 Oct 1991 11:15:12 BARRY
+Include standard headers.
+
+ Rev 1.8 06 Aug 1991 18:28:34 DON
+added NLM File System support
+
+ Rev 1.7 24 Jul 1991 09:53:20 DAVIDH
+Corrected warnings under Watcom compiler.
+
+ Rev 1.6 25 Jun 1991 09:34:44 BARRY
+Changes for new config.
+
+ Rev 1.5 18 Jun 1991 13:00:34 STEVEN
+should be defined not define
+
+ Rev 1.4 04 Jun 1991 19:39:36 BARRY
+No longer call SMB_Init() for MBS. InitializeRemote() will be
+changed to work properly for both MaynStream and LanStream.
+
+ Rev 1.3 04 Jun 1991 12:25:24 BARRY
+Forgot to remove dle_selector parameter.
+
+ Rev 1.2 30 May 1991 13:52:18 BARRY
+No longer delete DLEs in update; it will be up to the UI to pick and choose.
+
+ Rev 1.1 23 May 1991 16:40:12 BARRY
+Changed FSYSs to be conditional on FS_XXX defines instead of product defines.
+
+ Rev 1.0 09 May 1991 13:37:14 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include <stdlib.h>
+#include "stdtypes.h"
+#include "queues.h"
+#include "fsys.h"
+#include "beconfig.h"
+#include "msassert.h"
+#include "dle.h"
+#include "fsys_prv.h"
+#include "gen_fs.h"
+/* $end$ include list */
+
+
+INT16 DLE_UpdateList(
+DLE_HAND hand, /* I - Drive list to modify */
+BE_CFG_PTR cfg ) /* I - config to use to modify drive list */
+{
+ INT16 i ;
+ INT16 ret_val ;
+ UINT32 file_sys_mask ;
+
+ file_sys_mask = hand->file_sys_mask ;
+
+/*
+ Find all drives ;
+*/
+
+ for( i = 0; i < MAX_DRV_TYPES; i++ ) {
+ if ( func_tab[i].FindDrives != NULL ) {
+ ret_val = func_tab[i].FindDrives( hand, cfg, file_sys_mask ) ;
+
+ if ( ret_val != SUCCESS ) {
+ return ret_val ;
+ }
+ }
+ }
+
+
+ return ret_val ;
+}
+
+
+void GEN_FlushDLEs( DLE_HAND dle_hand, UINT8 flush_dle_type )
+{
+ GENERIC_DLE_PTR dle;
+ GENERIC_DLE_PTR next_dle;
+ GENERIC_DLE_PTR child_dle;
+ GENERIC_DLE_PTR next_child;
+ BOOLEAN ChildrenStay;
+
+ dle = (GENERIC_DLE_PTR) QueueHead( &dle_hand->q_hdr );
+
+ while ( dle != NULL )
+ {
+ next_dle = (GENERIC_DLE_PTR) QueueNext( &dle->q );
+
+ if ( dle->type == flush_dle_type )
+ {
+ ChildrenStay = FALSE;
+
+ if ( DLE_GetNumChild( dle ) != 0 )
+ {
+ DLE_GetFirstChild( dle, &child_dle );
+ while ( child_dle != NULL )
+ {
+ if ( ( child_dle->bsd_use_count != 0 ) ||
+ ( child_dle->attach_count != 0 ) )
+ {
+ ChildrenStay = TRUE;
+ }
+ child_dle = (GENERIC_DLE_PTR) QueueNext( &child_dle->q );
+ }
+
+ if ( ChildrenStay == FALSE )
+ {
+ DLE_GetFirstChild( dle, &child_dle );
+ while ( child_dle != NULL )
+ {
+ next_child = (GENERIC_DLE_PTR) QueueNext( &child_dle->q );
+
+ RemoveQueueElem( &dle->child_q, &child_dle->q );
+ free( child_dle );
+
+ child_dle = next_child;
+ }
+ }
+ }
+
+ if ( ( ChildrenStay == FALSE ) &&
+ ( dle->bsd_use_count == 0 ) &&
+ ( dle->attach_count == 0 ) )
+ {
+ RemoveQueueElem( &dle_hand->q_hdr, &dle->q );
+ free( dle );
+ }
+ }
+
+ dle = next_dle;
+ }
+
+ return;
+}
diff --git a/private/utils/ntbackup/src/dlg_util.c b/private/utils/ntbackup/src/dlg_util.c
new file mode 100644
index 000000000..9ea5a2796
--- /dev/null
+++ b/private/utils/ntbackup/src/dlg_util.c
@@ -0,0 +1,295 @@
+
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: dlg_util.c
+
+ Description: contains functions that the dialog procs use,
+ but these are not dialog procs
+
+ this file includes
+
+ DM_ParseShortDate()
+ DM_CountLetters()
+ DM_ParseTime()
+ $Log: G:/UI/LOGFILES/DLG_UTIL.C_V $
+
+ Rev 1.7 14 Jun 1993 21:01:32 MIKEP
+enable c++
+
+ Rev 1.6 01 Nov 1992 15:45:42 DAVEV
+Unicode changes
+
+ Rev 1.5 07 Oct 1992 13:43:22 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.4 04 Oct 1992 19:32:48 DAVEV
+Unicode Awk pass
+
+ Rev 1.3 28 Jul 1992 14:41:12 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.2 29 May 1992 15:58:34 JOHNWT
+PCH updates
+
+ Rev 1.1 09 Jan 1992 18:23:40 DAVEV
+16/32 bit port 2nd pass
+
+ Rev 1.0 20 Nov 1991 19:26:48 SYSTEM
+Initial revision.
+
+*****************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+// globals that are not global yet
+
+INT16 gnOrder ;
+BOOL gfLeadMonth ;
+BOOL gfLeadDay ;
+BOOL gfLeadYear ;
+BOOL glpszFormat ;
+
+BOOL gfIs24Hour ;
+CHAR glpszAMString[6] ;
+CHAR glpszPMString[9] ;
+BOOL gfLeadTime ;
+CHAR gcSeparator ;
+
+
+/***************************************************
+
+ Name: DM_ParseShortDate
+
+ Description: Parses the short date key field in win.ini
+ determines the date format, separator character,
+ whether or not the month and day have leading 0's,
+ and whether or not the year has a leading century
+
+ Modified:
+
+ Returns: void
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+VOID DM_ParseShortDate ( )
+
+{
+ CHAR lpszDateBuffer[11] ;
+ INT nTemp, nTemp2 ;
+
+ GetProfileString ( TEXT("Intl"), TEXT("sShortDate"), NULL, lpszDateBuffer, 11 ) ;
+
+ // the year field will tell us the separator,
+ // because it must have either 2 or 4 y's;
+ // there cannot be 3 or 5 y's in a valid year
+ // the year is either the first or last field in the string
+
+ if ( lpszDateBuffer[0] == TEXT('y') ) {
+
+ // this is ymd format, so the y's are first, followed by the separator
+
+ gnOrder = YMD ;
+ gfLeadYear = FALSE ;
+
+ if ( lpszDateBuffer[2] != TEXT('y') ) {
+
+ gcSeparator = lpszDateBuffer[2] ;
+
+ } else {
+
+ if ( lpszDateBuffer[3] == TEXT('y') ) { // buffer[4] is the separator;
+ // it may be a y
+ gfLeadYear = TRUE ;
+
+ } else { // the separator is a y (dirty trick)
+
+ gcSeparator = TEXT('y') ;
+ }
+ }
+
+ } else {
+
+ // the year is not the first field, so it is the last field
+ // count backward from the end to find the separator
+
+ nTemp = lstrlen ( lpszDateBuffer ) ;
+ nTemp2 = 0 ;
+ while ( lpszDateBuffer[nTemp] == TEXT('y') ) {
+
+ nTemp-- ;
+ nTemp2++ ;
+ }
+
+ if ( nTemp2 > 4 ) {
+
+ gcSeparator = lpszDateBuffer[nTemp] ;
+
+ } else {
+
+ gcSeparator = TEXT('y') ;
+ }
+ }
+
+ //
+ // after the separator has been identified, parse the d's and M's
+ //
+
+ if ( lpszDateBuffer[0] == TEXT('d') ) { // the order is DMY
+
+ gnOrder = DMY ;
+
+ // days are followed by months so count d's first
+ // count the d's
+
+ nTemp = DM_CountLetters ( lpszDateBuffer, 0 ) ;
+ gfLeadDay = ( ( nTemp == 3 ) ||
+ ( ( gcSeparator != TEXT('d') ) &&
+ ( nTemp > 1 ) ) ) ;
+
+ // followed by either 1 or 2 M's, followed by one separator,
+
+ if ( gcSeparator != TEXT('d') ) {
+
+ nTemp++ ;
+ }
+
+ gfLeadMonth = ( (INT)DM_CountLetters ( lpszDateBuffer, (INT16)nTemp ) == 2 ) ;
+
+ nTemp++ ;
+ if ( gfLeadMonth ) {
+
+ nTemp++ ;
+ }
+
+ // followed by either 2 or 4 y's
+
+ gfLeadYear = ( (INT)DM_CountLetters ( lpszDateBuffer, (INT16)nTemp ) == 4 ) ;
+
+ } else {
+
+ // see what the order is: if it isn't YMD it is MDY
+
+ if ( gnOrder != YMD ) {
+
+ gnOrder = MDY ;
+ }
+
+ // find the first M
+
+ nTemp = 2 ;
+ if ( gfLeadYear ) {
+
+ nTemp += 2 ;
+ }
+
+ nTemp = DM_CountLetters ( lpszDateBuffer, (INT16)nTemp ) ;
+ gfLeadMonth = ( ( nTemp == 3 ) ||
+ ( ( gcSeparator != TEXT('M') ) &&
+ ( nTemp > 1 ) ) ) ;
+
+ // followed by either 1 or 2 d's, followed by one separator
+
+ if ( gcSeparator != TEXT('d') ) {
+
+ nTemp++ ;
+ }
+
+ gfLeadDay = ( DM_CountLetters ( lpszDateBuffer, (INT16)nTemp ) == 2 ) ;
+
+ // if the order is MDY, count the y's
+
+ if ( gnOrder == MDY ) {
+
+ nTemp++ ;
+ if ( gfLeadDay ) {
+
+ nTemp++ ;
+ }
+ // followed by either 2 or 4 y's
+
+ gfLeadYear = ( (INT)DM_CountLetters ( lpszDateBuffer, (INT16)nTemp ) == 4 ) ;
+ }
+ }
+}
+
+/***************************************************
+
+ Name: DM_CountLetters
+
+ Description: counts the number of consecutive occurences
+ of a given letter in a given string;
+ the letter is specified by its index in the string
+
+ Modified:
+
+ Returns: INT16 the number of consecutive occurrences of the letter
+ at the given position of the given string starting
+ at the given position
+
+ Notes: index is not passed in as a pointer, so changing it here
+ does not affect the calling function's value
+
+ See also:
+
+*****************************************************/
+
+INT DM_CountLetters ( CHAR string[], INT index )
+
+{
+ INT nCount = 1 ; // the character at least matches itself
+
+ while ( string[index] == string[index+1] ) {
+
+ index++ ;
+ nCount++ ;
+ }
+
+ return ( nCount ) ;
+}
+
+
+/***************************************************
+
+ Name: DM_ParseTime
+
+ Description: Determines important international things about the
+ Windows time settings.
+
+ Modified:
+
+ Returns:
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+VOID DM_ParseTime ( )
+
+{
+ // This guy is much easier to parse than the bloody date
+
+ CHAR lpszBuffer[2] ;
+
+ gfIs24Hour = (BOOL) GetProfileInt ( TEXT("Intl"), TEXT("iTime"), 0 ) ;
+
+ GetProfileString ( TEXT("Intl"), TEXT("s1159"), NULL, glpszAMString, 6 ) ;
+ GetProfileString ( TEXT("Intl"), TEXT("s2359"), NULL, glpszPMString, 9 ) ;
+
+ gfLeadTime = (BOOL) GetProfileInt ( TEXT("Intl"), TEXT("iTLZero"), 0 ) ;
+
+ GetProfileString ( TEXT("Intl"), TEXT("sTime"), NULL, lpszBuffer, 2 ) ;
+ gcSeparator = lpszBuffer[0] ;
+}
+
+
diff --git a/private/utils/ntbackup/src/dlm_draw.c b/private/utils/ntbackup/src/dlm_draw.c
new file mode 100644
index 000000000..8cde1912f
--- /dev/null
+++ b/private/utils/ntbackup/src/dlm_draw.c
@@ -0,0 +1,1605 @@
+/****************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+ Name: dlm_draw.c
+
+ Description: This file contains routines for display list manager.
+
+ The following routines are in this module:
+
+
+ DLM_WMDrawItem
+ DLM_DrawLMapLText
+ DLM_DrawSMapLText
+ DLM_DrawTree
+ DLM_SetFont
+
+ $Log: G:/UI/LOGFILES/DLM_DRAW.C_V $
+
+ Rev 1.44.1.0 26 Jan 1994 15:20:22 Glenn
+Fixed text clobbering problem in file list box.
+
+ Rev 1.44 02 Aug 1993 15:09:28 GLENN
+Returning NULL pointer in DLM_GetFocusItem() if an error has occurred.
+
+ Rev 1.43 15 Jun 1993 09:59:06 MIKEP
+enable c++
+
+ Rev 1.42 14 Jun 1993 20:16:42 MIKEP
+enable c++
+
+ Rev 1.41 18 May 1993 15:20:26 GLENN
+Added check for valid display list in DLM_SetFont().
+
+ Rev 1.40 28 Apr 1993 15:36:42 GLENN
+Added DLM_GetPixelStringWidth() for column width calculations.
+
+ Rev 1.39 06 Apr 1993 17:53:12 GLENN
+Now restoring old bitmap widths and heights when there is a font change.
+
+ Rev 1.38 02 Apr 1993 15:54:26 ROBG
+Changed FocusItem to be UINT for both NT and WINDOWS.
+
+ Rev 1.37 03 Mar 1993 17:27:30 ROBG
+Fixed problem with drawing focus bars around items in a multicolumn
+list.
+
+ Rev 1.36 22 Feb 1993 13:45:40 ROBG
+Corrected the focus box by computing the horizontal extent for a flat list.
+
+ Rev 1.35 18 Jan 1993 14:24:06 GLENN
+Added DLM_DrawBorderOnItem() to draw border on all selected objects in a window without focus.
+
+ Rev 1.34 04 Jan 1993 09:26:36 MIKEP
+unicode fix LPSTR->BYTE_PTR
+
+ Rev 1.33 11 Dec 1992 18:25:36 GLENN
+Added selection frame rectangle support based on horizontal extent of a list box.
+
+ Rev 1.32 18 Nov 1992 13:19:42 GLENN
+Fixed highlight and emply list focus problems.
+
+ Rev 1.31 01 Nov 1992 15:46:02 DAVEV
+Unicode changes
+
+ Rev 1.30 14 Oct 1992 15:48:40 GLENN
+Added Selection Framing Support for List Boxes without the FOCUS.
+
+ Rev 1.29 07 Oct 1992 13:48:54 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.28 04 Oct 1992 19:32:52 DAVEV
+Unicode Awk pass
+
+ Rev 1.27 08 Sep 1992 10:12:30 ROBG
+Changed the logic in the volume window to highlight all text fields
+in the highlight color. Special logic to cut down on column width.
+
+ Rev 1.26 08 Sep 1992 09:58:00 ROBG
+Fixed problem with cyBeforeCheckBox and cyBeforeBitMap.
+
+ Rev 1.25 03 Sep 1992 15:28:34 ROBG
+Added conditional for OS_WIN32.
+
+ Rev 1.24 03 Sep 1992 13:32:28 ROBG
+Add defines to limit scope of drive description.
+
+ Rev 1.23 25 Aug 1992 09:17:46 ROBG
+Fixed the problem of setting the height of a checkbox and
+bitmaps to be the height of the column.
+
+ Rev 1.22 21 Aug 1992 16:02:10 ROBG
+Changes to support font changes.
+
+ Rev 1.21 20 Aug 1992 15:51:58 ROBG
+Added support to use Window highlight colors for selected items in the
+listboxes.
+
+ Rev 1.20 19 Aug 1992 14:33:52 ROBG
+Modified to properly handle the more compact listboxes.
+
+ Rev 1.19 07 Jul 1992 16:03:52 MIKEP
+unicode changes
+
+ Rev 1.18 12 Jun 1992 11:37:18 STEVEN
+another unaligned brother
+
+ Rev 1.17 10 Jun 1992 10:50:14 STEVEN
+added UNALIGNED for Mips build
+
+ Rev 1.16 15 May 1992 13:35:36 MIKEP
+nt pass 2
+
+ Rev 1.15 20 Mar 1992 09:07:30 ROBG
+Took out the setting of the horizontal extent when drawing flat lists.
+
+ Rev 1.14 20 Mar 1992 09:05:20 ROBG
+
+ Rev 1.13 18 Mar 1992 13:35:36 ROBG
+Made to use full rect item when multicolumn
+
+ Rev 1.12 18 Mar 1992 09:50:38 GLENN
+Fixed tree list focus problems.
+
+ Rev 1.11 17 Mar 1992 16:10:42 ROBG
+no change
+
+ Rev 1.10 10 Mar 1992 17:00:10 GLENN
+Remove tabs.
+
+ Rev 1.9 25 Jan 1992 12:43:38 MIKEP
+fix deep directories again
+
+ Rev 1.8 24 Jan 1992 16:18:00 MIKEP
+bump brothers pointer correctly
+
+ Rev 1.7 10 Jan 1992 13:58:08 DAVEV
+16/32 bit port-2nd pass
+
+ Rev 1.6 09 Jan 1992 14:26:20 ROBG
+Added logic to pad length of strings 1-3 to length of 4 in flat list boxes.
+
+ Rev 1.5 26 Dec 1991 17:23:16 ROBG
+New and Improved.
+
+ Rev 1.4 06 Dec 1991 17:37:18 GLENN
+Added code to call the APP set focus when item gets the focus, and not looses it
+
+ Rev 1.3 03 Dec 1991 13:20:48 DAVEV
+Modifications for 16/32-bit Windows port - 1st pass.
+
+
+ Rev 1.2 26 Nov 1991 15:21:54 ROBG
+Added validity checks for the window handle, info structure, and the
+dlm display header.
+
+ Rev 1.1 25 Nov 1991 13:44:52 ROBG
+Added check for valid window handle in DLM_DrawItem.
+
+ Rev 1.0 20 Nov 1991 19:17:50 SYSTEM
+Initial revision.
+
+****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+static UINT32 LevelMaskTbl[ 32 ] = {
+ 0x80000000, 0x40000000, 0x20000000, 0x10000000,
+ 0x08000000, 0x04000000, 0x02000000, 0x01000000,
+ 0x00800000, 0x00400000, 0x00200000, 0x00100000,
+ 0x00080000, 0x00040000, 0x00020000, 0x00010000,
+ 0x00008000, 0x00004000, 0x00002000, 0x00001000,
+ 0x00000800, 0x00000400, 0x00000200, 0x00000100,
+ 0x00000080, 0x00000040, 0x00000020, 0x00000010,
+ 0x00000008, 0x00000004, 0x00000002, 0x00000001,
+ };
+
+static VOID DLM_DrawBorderOnItem ( HWND hWnd, DLM_HEADER_PTR pHdr, LPDRAWITEMSTRUCT lpdis );
+
+
+/****************************************************************************
+
+ Name: DLM_WMDrawItem
+
+ Description: Function handles Draw_item messages from the list box
+ control.
+
+ Modified: 6/1/1991
+
+
+ Returns: Always zero.
+
+ Notes: Called by docproc.c
+
+****************************************************************************/
+
+
+
+WORD DLM_WMDrawItem (
+
+HWND hWnd , // I - Handle to Parent Window of list box.
+LPDRAWITEMSTRUCT lpdis ) // I - Pointer to information about item.
+
+
+{
+ DLM_HEADER_PTR pHdr ;
+
+ // lpdis->hwndItem must be a valid window.
+
+ if ( ! IsWindow( lpdis->hwndItem ) ) {
+ return(0);
+ }
+
+ // Parent window must exist.
+
+ if ( ! IsWindow( hWnd ) ) {
+ return(0);
+ }
+
+ pHdr = DLM_GetDispHdr( lpdis->hwndItem );
+
+ // DLM display header must be defined.
+
+ if ( ! pHdr ) {
+ return ( 0 );
+ }
+
+ switch ( DLM_GDisplay( pHdr ) ) {
+
+ case DLM_LARGEBITMAPSLTEXT :
+ return( DLM_DrawLMapLText ( hWnd, lpdis ) );
+
+ case DLM_SMALL_BITMAPS :
+ default:
+
+ if ( DLM_GMode( pHdr ) == DLM_HIERARCHICAL ) {
+
+ return( DLM_DrawTree ( hWnd, lpdis ) );
+ } else {
+ return( DLM_DrawSMapLText ( hWnd, lpdis ) );
+ }
+
+ break ;
+ }
+
+}
+
+
+/****************************************************************************
+
+ Name: DLM_DrawLMapLText
+
+ Description: This function will draw Large Bitmaps with
+ large text to the right side of bitmap.
+
+ Modified: 3/25/1991
+
+ Returns: Always zero
+
+ Notes: WM_DrawItem has validated hWnd and lpdis.
+
+****************************************************************************/
+
+WORD DLM_DrawLMapLText(
+
+HWND hWnd, // I - Handle to Parent Window of list box.
+LPDRAWITEMSTRUCT lpdis ) // I - Pointer to information about item.
+
+{
+
+ short cxPos, cyPos ;
+ RECT rc ;
+ RECT rcNew ;
+ BOOL fHighLightText ;
+ BOOL fFirstTextItem = TRUE;
+ BOOL fFocusChange ;
+
+ DLM_HEADER_PTR pHdr ;
+ PDS_WMINFO pWinInfo ;
+ GET_OBJECTS_PTR pfnGetObjects ;
+
+ LPBYTE lpObjLst;
+ LMHANDLE dhListItem ;
+ DLM_ITEM_PTR lpDispItem ;
+ BYTE bObjCnt ;
+
+ short height ;
+ LONG lLen ;
+
+ DWORD OldBkColor ;
+ DWORD OldTextColor ;
+
+ HANDLE hSaveObject ;
+
+
+ switch ( lpdis->itemAction ) {
+
+ case ODA_DRAWENTIRE:
+ case ODA_SELECT:
+
+ fFocusChange = FALSE;
+ break;
+
+ case ODA_FOCUS:
+ fFocusChange = TRUE;
+ break;
+
+ }
+
+ pHdr = DLM_GetDispHdr( lpdis->hwndItem );
+
+ if ( ! fFocusChange ) {
+
+ pWinInfo = (PDS_WMINFO) WM_GetInfoPtr( hWnd );
+
+ pfnGetObjects = (GET_OBJECTS_PTR) DLM_GGetObjects( pHdr );
+
+ dhListItem = (LMHANDLE) lpdis->itemData ;
+
+ rc = lpdis->rcItem;
+
+ // Wipe out any old focus stuff.
+
+ FrameRect ( lpdis->hDC, &rc, ghBrushWhite );
+
+ InflateRect( (LPRECT) &rc, mwDLMInflate, mwDLMInflate );
+
+ fHighLightText = FALSE;
+
+ if ( DLM_IsFocusInWindow ( hWnd, lpdis->hwndItem ) ) {
+
+ if ( lpdis->itemState & ODS_SELECTED ) {
+
+ fHighLightText = TRUE ;
+ }
+ }
+
+ /* Ready now to display item */
+
+ lpObjLst = (LPBYTE) ( (*pfnGetObjects) (dhListItem) );
+ lpDispItem = DLM_GetFirstObject( (LPBYTE)lpObjLst, &bObjCnt ) ;
+
+ cxPos = (short)rc.left ;
+ cyPos = (short)rc.top ;
+
+ height = (short)(rc.bottom - rc.top + 1);
+
+ while ( bObjCnt ) {
+
+ switch ( DLM_ItembType ( lpDispItem ) ) {
+
+ case DLM_CHECKBOX:
+
+ cxPos += pHdr->cxBeforeCheckBox ;
+ RSM_BitmapDraw( DLM_ItemwId ( lpDispItem ), cxPos, cyPos+pHdr->cyBeforeCheckBox,
+ pHdr->cxCheckBoxWidth, pHdr->cyCheckBoxHeight, lpdis->hDC );
+ cxPos += pHdr->cxCheckBoxWidth;
+ break;
+
+ case DLM_BITMAP:
+
+ cxPos += pHdr->cxBeforeBitMap ;
+ RSM_BitmapDraw( DLM_ItemwId ( lpDispItem ), cxPos, cyPos+pHdr->cyBeforeBitMap,
+ pHdr->cxBitMapWidth, pHdr->cyBitMapHeight, lpdis->hDC );
+ cxPos += pHdr->cxBitMapWidth;
+ break;
+
+
+ case DLM_TEXT_ONLY:
+
+ cxPos += pHdr->cxBeforeText ;
+
+ rcNew.top = rc.top ;
+ rcNew.bottom= rc.bottom ;
+
+ rcNew.left = cxPos ;
+ rcNew.right = rc.right ;
+
+ // If this is the first text item, fill in the
+ // remaining region with the proper color,
+ // all the way to the end.
+
+ if ( fFirstTextItem ) {
+
+ RECT rcTemp = lpdis->rcItem;
+
+ rcTemp.left = cxPos;
+
+ if ( fHighLightText ) {
+ FillRect( lpdis->hDC, &rcTemp, ghBrushHighLight );
+ } else {
+ FillRect( lpdis->hDC, &rcTemp, ghBrushWhite );
+ }
+
+ fFirstTextItem = FALSE;
+ }
+
+ if (fHighLightText ) {
+ OldBkColor = SetBkColor ( lpdis->hDC, gColorHighLight ) ;
+ OldTextColor = SetTextColor( lpdis->hDC, gColorHighLightText ) ;
+ } else {
+ OldBkColor = SetBkColor ( lpdis->hDC, gColorBackGnd ) ;
+ OldTextColor = SetTextColor( lpdis->hDC, gColorForeGnd ) ;
+ }
+
+
+
+ hSaveObject = SelectObject( lpdis->hDC, ghFontFiles );
+
+ // Fill in background between fields.
+ // Assume text fields are next to one another.
+
+ if ( bObjCnt != 1 ) {
+ rcNew.right = rcNew.left +
+ ( DLM_ItembMaxTextLen( lpDispItem ) * pHdr->cxTextWidth );
+ rcNew.right += pHdr->cxBeforeText ;
+
+ if ( fHighLightText ) {
+ FillRect( lpdis->hDC, &rcNew, ghBrushHighLight );
+ } else {
+ FillRect( lpdis->hDC, &rcNew, ghBrushWhite );
+ }
+ }
+
+ lLen = strlen( (CHAR_PTR)DLM_ItemqszString( lpDispItem ) );
+
+ TextOut ( lpdis->hDC, cxPos, cyPos+pHdr->cyBeforeText,
+ (CHAR_PTR)DLM_ItemqszString( lpDispItem ), (int) lLen );
+
+ SelectObject( lpdis->hDC, hSaveObject );
+
+ cxPos += ( DLM_ItembMaxTextLen( lpDispItem ) * pHdr->cxTextWidth );
+
+ break ;
+ }
+
+ bObjCnt-- ;
+ lpDispItem++ ;
+ }
+
+ }
+// else {
+//
+// if ( lpdis->itemState & ODS_FOCUS ) {
+//
+// zprintf ( 0, "FOCUS-ON - Item: %d", lpdis->itemID );
+// }
+// else {
+// zprintf ( 0, "FOCUS-OFF - Item: %d", lpdis->itemID );
+// }
+// }
+
+
+ DLM_DrawBorderOnItem ( hWnd, pHdr, lpdis );
+
+ DLM_SetFocusItem ( lpdis, &lpdis->rcItem );
+
+ return ( 0 );
+
+}
+
+
+/****************************************************************************
+
+ Name: DLM_DrawSMapLText
+
+ Description: This function will draw small Bitmaps with
+ large text to the right side of bitmap.
+
+ Modified: 3/25/1991
+
+ Returns: none
+
+ Notes: WM_DrawItem has validated hWnd and lpdis.
+
+ The column width is calculated by the cxTextWidth *
+ maximum length of string in column.
+
+ The cxTextWidth is an approximation of the text width,
+ based on the maximum width of a character in the font and
+ the average font width.
+
+****************************************************************************/
+
+WORD DLM_DrawSMapLText(
+
+HWND hWnd, // I - Handle to Parent Window of list box.
+LPDRAWITEMSTRUCT lpdis ) // I - Pointer to information about item.
+
+{
+
+ short cxPos, cyPos ;
+ RECT rc ;
+ RECT rcAll ;
+ RECT rcNew ;
+ WORD fHighLightText ;
+ BOOL fFocusChange ;
+
+ DLM_HEADER_PTR pHdr ;
+ PDS_WMINFO pWinInfo ;
+ GET_OBJECTS_PTR pfnGetObjects ;
+
+ LPBYTE lpObjLst;
+ LMHANDLE dhListItem ;
+ DLM_ITEM_PTR lpDispItem ;
+ BYTE bObjCnt ;
+ HANDLE hSaveObject ;
+
+ USHORT unHeight ;
+ POINT pt; //dvc - GetWindowOrgEx return value
+
+
+
+ switch ( lpdis->itemAction ) {
+
+ case ODA_DRAWENTIRE:
+ case ODA_SELECT:
+
+ fFocusChange = FALSE;
+ break;
+
+ case ODA_FOCUS:
+ fFocusChange = TRUE;
+ break;
+
+ }
+
+
+ pHdr = DLM_GetDispHdr( lpdis->hwndItem );
+
+ if ( ! fFocusChange ) {
+
+ BOOL fTextBkGndErased = FALSE;
+
+ GetWindowOrgEx( lpdis->hDC, &pt );
+ pHdr->xOrigin = (WORD)pt.x;
+
+ pWinInfo = (PDS_WMINFO) WM_GetInfoPtr( hWnd );
+
+ pfnGetObjects = (GET_OBJECTS_PTR) DLM_GGetObjects( pHdr );
+
+ dhListItem = (LMHANDLE) lpdis->itemData ;
+
+ rc = lpdis->rcItem;
+ rcAll = lpdis->rcItem;
+
+
+ // Wipe out any old focus stuff.
+
+// FrameRect ( lpdis->hDC, &rc, ghBrushWhite );
+
+ // Blow away anything that was there.
+
+ FillRect ( lpdis->hDC, &rc, ghBrushWhite );
+
+ InflateRect( (LPRECT) &rc, mwDLMInflate, mwDLMInflate );
+
+ fHighLightText = FALSE;
+
+ if ( DLM_IsFocusInWindow ( hWnd, lpdis->hwndItem ) ) {
+
+ if ( lpdis->itemState & ODS_SELECTED ) {
+
+ fHighLightText = TRUE ;
+ }
+ }
+
+ /* Ready now to display item */
+
+ lpObjLst = (LPBYTE)( (*pfnGetObjects) (dhListItem) );
+ lpDispItem = DLM_GetFirstObject( lpObjLst, &bObjCnt ) ;
+
+ cxPos = (short)rc.left ;
+ cyPos = (short)rc.top ;
+
+ unHeight = (short)(rc.bottom - rc.top + 1);
+
+ while ( bObjCnt ) {
+
+ switch ( DLM_ItembType ( lpDispItem ) ) {
+
+ case DLM_CHECKBOX:
+
+ cxPos += pHdr->cxBeforeCheckBox ;
+
+ if ( DLM_ItemwId( lpDispItem ) ) {
+ RSM_BitmapDraw( DLM_ItemwId ( lpDispItem ), cxPos, cyPos+pHdr->cyBeforeCheckBox,
+ pHdr->cxCheckBoxWidth, pHdr->cyCheckBoxHeight, lpdis->hDC );
+ }
+
+ cxPos += pHdr->cxCheckBoxWidth;
+ break;
+
+ case DLM_BITMAP:
+
+ cxPos += pHdr->cxBeforeBitMap ;
+
+ RSM_BitmapDraw( DLM_ItemwId ( lpDispItem ), cxPos, cyPos+pHdr->cyBeforeBitMap,
+ pHdr->cxBitMapWidth, pHdr->cyBitMapHeight, lpdis->hDC );
+
+ cxPos += pHdr->cxBitMapWidth;
+ break;
+
+
+ case DLM_TEXT_ONLY:
+
+ rcNew = rcAll;
+
+ cxPos += pHdr->cxBeforeText ;
+
+ rcNew.left = cxPos ;
+
+ if ( ! fTextBkGndErased ) {
+
+ if ( fHighLightText ) {
+
+ FillRect( lpdis->hDC, &rcNew, ghBrushHighLight );
+ SetBkColor ( lpdis->hDC, gColorHighLight ) ;
+ SetTextColor( lpdis->hDC, gColorHighLightText ) ;
+
+ }
+ else {
+
+ FillRect( lpdis->hDC, &rcNew, ghBrushWhite );
+ SetBkColor ( lpdis->hDC, gColorBackGnd ) ;
+ SetTextColor( lpdis->hDC, gColorForeGnd ) ;
+ }
+
+ SetBkMode ( lpdis->hDC, TRANSPARENT );
+
+ fTextBkGndErased = TRUE;
+ }
+
+ // If the font is DLM_ANSI_FIXED_FONT, select ghFontLog.
+ // is DLM_SYSTEM_FONT, select ghFontIconLabels
+
+ if ( DLM_GTextFont( pHdr ) == DLM_ANSI_FIXED_FONT ) {
+
+ hSaveObject = SelectObject( lpdis->hDC, ghFontLog );
+ }
+ else {
+
+ hSaveObject = SelectObject( lpdis->hDC, ghFontIconLabels );
+ }
+
+ rcNew.top = cyPos ;
+
+ rcNew.left++;
+
+ if ( DLM_ItembTextMode( lpDispItem ) == DLM_RIGHT_JUSTIFY ) {
+
+ rcNew.right = rcNew.left + ( DLM_ItembMaxTextLen( lpDispItem ) * pHdr->cxTextWidth );
+
+// FrameRect ( lpdis->hDC, &rcNew, ghBrushBlack );
+
+ DrawText ( lpdis->hDC,
+ (CHAR_PTR)DLM_ItemqszString( lpDispItem ),
+ strlen( (CHAR_PTR)DLM_ItemqszString( lpDispItem ) ),
+ &rcNew,
+ DT_NOCLIP | DT_RIGHT | DT_NOPREFIX | DT_SINGLELINE );
+
+// cxPos += pHdr->cxTextWidth ;
+ rcNew.right += pHdr->cxTextWidth ;
+
+ }
+ else {
+
+ // If it is not a Multicolumn listbox,
+ // then do not use the default right.
+
+ if ( DLM_GMode( pHdr ) != DLM_MULTICOLUMN ) {
+ rcNew.right = rcNew.left + ( DLM_ItembMaxTextLen( lpDispItem ) * pHdr->cxTextWidth );
+ }
+
+// FrameRect ( lpdis->hDC, &rcNew, ghBrushBlack );
+
+ DrawText ( lpdis->hDC,
+ (CHAR_PTR)DLM_ItemqszString( lpDispItem ),
+ strlen( (CHAR_PTR)DLM_ItemqszString( lpDispItem ) ),
+ &rcNew,
+ DT_NOCLIP | DT_LEFT | DT_NOPREFIX | DT_SINGLELINE );
+ }
+
+ SelectObject( lpdis->hDC, hSaveObject );
+
+// cxPos += ( DLM_ItembMaxTextLen( lpDispItem ) * pHdr->cxTextWidth );
+ cxPos = (short)rcNew.right;
+
+ // Create a little more space for strings less than 5 characters long.
+
+ if ( ( (int) DLM_ItembMaxTextLen( lpDispItem ) > 0 ) &&
+ ( (int) DLM_ItembMaxTextLen( lpDispItem ) < 5 ) ) {
+
+ cxPos += pHdr->cxTextWidth ;
+ }
+
+ // Need to set the horizontal extent.
+
+ if ( cxPos > (short) pHdr->wHorizontalExtent ) {
+
+ pHdr->wHorizontalExtent = cxPos ;
+ SendMessage ( lpdis->hwndItem, LB_SETHORIZONTALEXTENT,
+ cxPos + 4*mwcxDLMIconLabelsWidth , 0L );
+ }
+
+ }
+
+ bObjCnt-- ;
+ lpDispItem++ ;
+
+ } /* end while */
+
+ } /* end if */
+
+ DLM_DrawBorderOnItem ( hWnd, pHdr, lpdis );
+
+ DLM_SetFocusItem ( lpdis, &lpdis->rcItem );
+
+ return ( 0 );
+}
+
+
+/****************************************************************************
+
+ Name: DLM_DrawTree
+
+ Description: This function will draw small Bitmaps with
+ large text to the right side of bitmap in a
+ tree fashion.
+
+ Modified: 3/25/1991
+
+ Returns: Always 0
+
+ Notes: WM_DrawItem has validated hWnd and lpdis.
+
+****************************************************************************/
+
+WORD DLM_DrawTree(
+
+HWND hWnd , // I - Handle to Parent Window of list box.
+LPDRAWITEMSTRUCT lpdis ) // I - Pointer to information about item.
+
+{
+ INT cxPos, cyPos ;
+ short cxString ;
+ RECT rc ;
+ RECT rcAll ;
+ RECT rcNew ;
+
+ WORD fHighLightText ;
+
+ DLM_HEADER_PTR pHdr ;
+ PDS_WMINFO pWinInfo ;
+ GET_OBJECTS_PTR pfnGetObjects ;
+ SET_TAG_PTR pfnSetTag ;
+
+ BYTE *lpObjLst;
+ LMHANDLE dhListItem ;
+ DLM_ITEM_PTR lpDispItem ;
+ BYTE bObjCnt ;
+ BYTE bLevel ;
+ DWORD dwBrothers ;
+ LPDWORD pFirstDword ;
+ USHORT unHeight ;
+ BYTE i ;
+ HANDLE hSaveObject ;
+ POINT pt; //dvc - GetWindowOrgEx return value
+ SIZE sizeRect ; //dvc - GetTextExtentPoint return val
+
+
+ if ( (lpdis->itemAction == ODA_SELECT ) ||
+ (lpdis->itemAction == ODA_DRAWENTIRE ) )
+ {
+ pHdr = DLM_GetDispHdr( lpdis->hwndItem );
+
+ GetWindowOrgEx( lpdis->hDC, &pt );
+ pHdr->xOrigin = (WORD)pt.x;
+
+ pWinInfo = (PDS_WMINFO) WM_GetInfoPtr( hWnd );
+
+ pfnGetObjects = (GET_OBJECTS_PTR) DLM_GGetObjects( pHdr );
+ pfnSetTag = (SET_TAG_PTR) DLM_GSetTag ( pHdr );
+
+ dhListItem = (LMHANDLE) lpdis->itemData ;
+
+ CopyRect ( (LPRECT)&rc, (LPRECT) &lpdis->rcItem );
+ CopyRect ( (LPRECT)&rcAll, (LPRECT) &lpdis->rcItem );
+
+ InflateRect( (LPRECT) &rc, mwDLMInflate, mwDLMInflate );
+
+ if ( lpdis->itemState & ODS_SELECTED )
+ {
+ (*pfnSetTag) (dhListItem, 1 );
+ fHighLightText = TRUE ;
+
+ }
+ else
+ {
+ (*pfnSetTag) (dhListItem, 0 );
+ fHighLightText = FALSE ;
+ }
+
+ /* Ready now to display item */
+
+ lpObjLst = (BYTE *) ( (*pfnGetObjects) (dhListItem) );
+ lpDispItem = DLM_GetFirstObject( lpObjLst, &bObjCnt ) ;
+
+
+ /* Draw lines before checkbox */
+
+ cxPos = (short)rc.left ;
+ cyPos = (short)rc.top ;
+ unHeight = (short)(rc.bottom - rc.top + 1);
+ bLevel = DLM_ItembLevel( lpDispItem );
+
+ hSaveObject = SelectObject( lpdis->hDC, ghPenForeGnd );
+
+ pFirstDword = (LPDWORD) ( lpObjLst + 2 ) ;
+
+ for( i=1; i<bLevel; i++ ) {
+
+ // Index to the appropiate DWORD that describes the levels
+ // First DWORD is for levels 0-31, Second DWORD is for levels 32-63 ...
+
+ dwBrothers = *( (DWORD UNALIGNED *) ( pFirstDword + (i/32) ) ) ;
+
+ if ( dwBrothers & LevelMaskTbl[ i % 32 ] ) {
+ cxPos += pHdr->cxHierHorzLine ;
+ MoveToEx ( lpdis->hDC, cxPos, (INT)rcAll.top, NULL );
+ LineTo ( lpdis->hDC, cxPos, (INT)rcAll.bottom );
+ cxPos -= pHdr->cxHierHorzLine ;
+ }
+ cxPos += pHdr->cxHierTab;
+ }
+
+ /* Draw full length line directly before the checkbox
+ if a brother exists right after */
+
+ if ( bLevel ) {
+
+ // Index to the appropiate DWORD that describes the levels
+ // First DWORD is for levels 0-31, Second DWORD is for levels 32-63 ...
+
+ dwBrothers = *( (DWORD UNALIGNED *) ( pFirstDword + (bLevel/32) ) ) ;
+
+ if ( dwBrothers & LevelMaskTbl [bLevel % 32] ) {
+
+ cxPos += pHdr->cxHierHorzLine ;
+ MoveToEx ( lpdis->hDC, cxPos, (INT)rcAll.top, NULL);
+ LineTo ( lpdis->hDC, cxPos, (INT)rcAll.bottom );
+
+ // rcAll.top_height/2+1 will place line to point to middle of checkbox
+
+ MoveToEx ( lpdis->hDC, cxPos, (INT)(rcAll.top+unHeight/2+1), NULL );
+ LineTo ( lpdis->hDC, cxPos + pHdr->cxHierHorzLen,
+ (INT)(rcAll.top+unHeight/2+1) );
+ } else {
+
+ // rcAll.top_height/2+1 will place line to point to middle of checkbox
+
+ cxPos += pHdr->cxHierHorzLine ;
+ MoveToEx ( lpdis->hDC, cxPos, (INT)rcAll.top, NULL );
+ LineTo ( lpdis->hDC, cxPos, (INT)rcAll.top+unHeight/2+1 );
+ LineTo ( lpdis->hDC, cxPos + pHdr->cxHierHorzLen,
+ (INT)(rcAll.top+unHeight/2+1) );
+ }
+ }
+
+ SelectObject( lpdis->hDC, hSaveObject );
+
+ cxPos = (short)rc.left ;
+ cxPos += (short)( DLM_ItembLevel( lpDispItem ) * pHdr->cxHierTab );
+ cyPos = (short)rc.top ;
+
+ while ( bObjCnt ) {
+
+ switch ( DLM_ItembType ( lpDispItem ) ) {
+
+ case DLM_CHECKBOX:
+
+ cxPos += pHdr->cxBeforeCheckBox ;
+
+ RSM_BitmapDraw( DLM_ItemwId ( lpDispItem ),
+ cxPos,
+ cyPos+pHdr->cyBeforeCheckBox,
+ pHdr->cxCheckBoxWidth,
+ pHdr->cyCheckBoxHeight,
+ lpdis->hDC );
+ cxPos += pHdr->cxCheckBoxWidth;
+ break;
+
+ case DLM_BITMAP:
+
+ cxPos += pHdr->cxBeforeBitMap ;
+
+ rcNew.left = cxPos ;
+ rcNew.top = rcAll.top ;
+ rcNew.right= cxPos+pHdr->cxBitMapWidth+pHdr->cxBeforeBitMap;
+ rcNew.bottom= rcAll.bottom ;
+
+ RSM_BitmapDraw( DLM_ItemwId ( lpDispItem ),
+ cxPos,
+ cyPos+pHdr->cyBeforeBitMap,
+ pHdr->cxBitMapWidth,
+ pHdr->cyBitMapHeight,
+ lpdis->hDC );
+ cxPos += pHdr->cxBitMapWidth;
+ break;
+
+
+ case DLM_TEXT_ONLY:
+
+ /* Assume bitmap before text */
+
+ cxPos += pHdr->cxBeforeText ;
+
+ hSaveObject = SelectObject( lpdis->hDC, ghFontIconLabels );
+
+ GetTextExtentPoint ( lpdis->hDC,
+ (CHAR_PTR)DLM_ItemqszString ( lpDispItem ),
+ strlen( (CHAR_PTR)DLM_ItemqszString( lpDispItem ) ),
+ &sizeRect);
+
+ cxString = (short)sizeRect.cx;
+ rcNew.left = cxPos ;
+ rcNew.right = rcNew.left + cxString ;
+
+ if ( fHighLightText ) {
+
+ FillRect( lpdis->hDC, &rcNew, ghBrushHighLight );
+
+ } else {
+ // Increment right of region by 2 to clear out the
+ // previous high light brush.
+
+ rcNew.right += 3 ;
+ FillRect( lpdis->hDC, &rcNew, ghBrushWhite );
+
+ }
+
+ if (fHighLightText ) {
+
+ SetBkColor ( lpdis->hDC, gColorHighLight ) ;
+ SetTextColor( lpdis->hDC, gColorHighLightText ) ;
+
+ } else {
+
+ SetBkColor ( lpdis->hDC, gColorBackGnd ) ;
+ SetTextColor( lpdis->hDC, gColorForeGnd ) ;
+ }
+
+ TextOut ( lpdis->hDC, cxPos+1, cyPos+pHdr->cyBeforeText,
+ (CHAR_PTR)DLM_ItemqszString( lpDispItem ),
+ strlen( (CHAR_PTR)DLM_ItemqszString ( lpDispItem ) ) );
+
+ SelectObject( lpdis->hDC, hSaveObject );
+
+
+ cxPos += cxString ;
+
+ if ( cxPos > (short) pHdr->wHorizontalExtent ) {
+
+ pHdr->wHorizontalExtent = cxPos ;
+ SendMessage ( lpdis->hwndItem, LB_SETHORIZONTALEXTENT,
+ cxPos + 4*mwcxDLMIconLabelsWidth , 0L );
+ }
+
+ if ( ! DLM_IsFocusInWindow ( hWnd, lpdis->hwndItem ) ) {
+
+ if ( fHighLightText ) {
+ lpdis->itemAction = ODA_FOCUS ;
+ }
+ }
+
+ break ;
+
+ } //switch
+
+ bObjCnt-- ;
+ lpDispItem++ ;
+
+ } //while
+
+ } //if select or draw item
+
+ if ( lpdis->itemAction == ODA_FOCUS ) { /* Put box around item */
+
+ pHdr = DLM_GetDispHdr( lpdis->hwndItem );
+ pWinInfo = (PDS_WMINFO) WM_GetInfoPtr( hWnd );
+
+ pfnGetObjects = (GET_OBJECTS_PTR) DLM_GGetObjects( pHdr );
+
+ dhListItem = (LMHANDLE) lpdis->itemData ;
+
+ CopyRect ( (LPRECT)&rc, (LPRECT) &lpdis->rcItem );
+ CopyRect ( (LPRECT)&rcAll, (LPRECT) &lpdis->rcItem );
+
+ InflateRect( (LPRECT) &rc, mwDLMInflate, mwDLMInflate );
+
+ /* Ready now to display item */
+
+ if ( dhListItem == NULL ) /* It is possible that list box is empty */
+ {
+ return ( 0 ); /* Return OK since the list box is probably empty */
+ }
+
+ lpObjLst = (BYTE *) ( (*pfnGetObjects) (dhListItem) );
+ lpDispItem = DLM_GetFirstObject( lpObjLst, &bObjCnt ) ;
+
+ cxPos = (short)rc.left ;
+ cxPos += ( DLM_ItembLevel( lpDispItem ) * pHdr->cxHierTab );
+
+ cyPos = (short)rc.top ;
+
+ while ( bObjCnt )
+ {
+ switch ( DLM_ItembType ( lpDispItem ) )
+ {
+ case DLM_CHECKBOX:
+
+ cxPos += pHdr->cxBeforeCheckBox ;
+ cxPos += pHdr->cxCheckBoxWidth ;
+ break;
+
+ case DLM_BITMAP:
+
+ cxPos += pHdr->cxBeforeBitMap ;
+ cxPos += pHdr->cxBitMapWidth ;
+
+ rcNew.left = cxPos ;
+ rcNew.top = rcAll.top ;
+ rcNew.right= cxPos+pHdr->cxBitMapWidth+pHdr->cxBeforeBitMap;
+ rcNew.bottom= rcAll.bottom ;
+
+ break;
+
+
+ case DLM_TEXT_ONLY:
+
+
+ cxPos += pHdr->cxBeforeText ;
+
+ /* Assume bitmap before text */
+
+ hSaveObject = SelectObject( lpdis->hDC, ghFontIconLabels );
+
+ GetTextExtentPoint( lpdis->hDC,
+ (CHAR_PTR)DLM_ItemqszString ( lpDispItem ),
+ strlen( (CHAR_PTR)DLM_ItemqszString( lpDispItem ) ),
+ &sizeRect );
+
+ cxString = (short)sizeRect.cx;
+
+ SelectObject( lpdis->hDC, hSaveObject );
+
+ if ( ! DLM_IsFocusInWindow ( hWnd, lpdis->hwndItem ) ) {
+
+ /* Repaint text with normal background */
+
+ rcNew.left = cxPos ;
+ rcNew.right = rcNew.left + cxString + 3;
+
+ FillRect( lpdis->hDC, &rcNew, ghBrushWhite );
+
+ hSaveObject = SelectObject( lpdis->hDC, ghFontIconLabels );
+
+ SetBkColor ( lpdis->hDC, gColorBackGnd ) ;
+ SetTextColor( lpdis->hDC, gColorForeGnd ) ;
+
+ TextOut ( lpdis->hDC, cxPos+1, cyPos,
+ (CHAR_PTR)DLM_ItemqszString( lpDispItem ),
+ strlen( (CHAR_PTR)DLM_ItemqszString ( lpDispItem ) ) );
+
+ SelectObject( lpdis->hDC, hSaveObject );
+
+ } else {
+
+ /* Repaint text with high light background */
+
+ rcNew.left = cxPos ;
+ rcNew.right = rcNew.left + cxString + 3;
+
+
+ FillRect( lpdis->hDC, &rcNew, ghBrushHighLight );
+
+ hSaveObject = SelectObject( lpdis->hDC, ghFontIconLabels );
+
+ SetBkColor ( lpdis->hDC, gColorHighLight ) ;
+ SetTextColor ( lpdis->hDC, gColorHighLightText ) ;
+
+ TextOut ( lpdis->hDC, cxPos+1, cyPos,
+ (CHAR_PTR)DLM_ItemqszString( lpDispItem ),
+ strlen( (CHAR_PTR)DLM_ItemqszString ( lpDispItem ) ) );
+
+ SelectObject( lpdis->hDC, hSaveObject );
+
+ }
+
+ rcNew.left = cxPos ;
+ rcNew.top = rcAll.top ;
+ rcNew.bottom = rcAll.bottom ;
+ rcNew.right = rcNew.left + cxString + 3;
+
+
+ if ( ! DLM_IsFocusInWindow ( hWnd, lpdis->hwndItem ) ) {
+
+ FrameRect( lpdis->hDC, &rcNew, ghBrushHighLight );
+ }
+ else if ( ( lpdis->itemAction & ODA_FOCUS ) && ( lpdis->itemState & ODS_FOCUS ) ) {
+
+ SetBkColor ( lpdis->hDC, gColorHighLight ) ;
+ SetTextColor ( lpdis->hDC, gColorHighLightText ) ;
+ DLM_SetFocusItem ( lpdis, &rcNew );
+ }
+
+ break ;
+
+ } //switch
+
+ bObjCnt-- ;
+ lpDispItem++ ;
+ }
+
+ }
+
+ return ( 0 );
+}
+
+
+/****************************************************************************
+
+ Name: DLM_IsFocusOnWindow
+
+ Description: This function will check to see if current focus
+ is on either of the listboxes in the window.
+
+ Modified: 5/13/1991
+
+ Returns: TRUE if current focus is on one of the listboxes
+ in the window.s.
+
+ FALSE if not.
+
+****************************************************************************/
+
+BOOL DLM_IsFocusInWindow(
+
+HWND hWnd , //I - Handle to Parent window of list box.
+HWND hWndLB ) //I - Handle to list box.
+
+{
+
+ WORD wStatus ;
+ HWND hWndFocus ;
+ PDS_WMINFO pWinInfo ;
+
+ // Must be valid windows.
+
+ if ( ! IsWindow ( hWnd ) || ! IsWindow ( hWndLB ) ) {
+ return FALSE;
+ }
+
+ pWinInfo = (PDS_WMINFO) WM_GetInfoPtr( hWnd );
+
+ if ( ! pWinInfo ) {
+ return FALSE;
+ }
+
+ hWndFocus = GetFocus();
+
+ wStatus = FALSE ;
+
+ // If this list box is the active list box and the list box has the focus,
+ // then we have focus on the window.
+
+ if ( hWndLB == WMDS_GetWinActiveList ( pWinInfo ) && hWndLB == hWndFocus ) {
+
+ wStatus = TRUE;
+ }
+
+// What is this??? I think that the previous if statement will do the same thing.
+
+// if ( ( pWinInfo->hWndTreeList == hWndFocus ) ||
+// ( pWinInfo->hWndFlatList == hWndFocus ) ) {
+//
+// if ( hWndFocus != hWndLB ) {
+// wStatus = FALSE ;
+// } else {
+// wStatus = TRUE ;
+// }
+// } else {
+// if (pWinInfo->hWndActiveList == hWndLB ) {
+// wStatus = TRUE ;
+// } else {
+// wStatus = FALSE ;
+// }
+// }
+
+ return wStatus;
+}
+
+
+/****************************************************************************
+
+ Name: DLM_GetFocusItem
+
+ Description: This function will return an address of
+ the item that has the focus box.
+ tree fashion.
+
+ Modified: 10/08/1991
+
+ Returns: Pointer to the application's item as registered
+ by the list box.
+
+ Notes:
+
+****************************************************************************/
+
+PVOID DLM_GetFocusItem(
+
+HWND hWndLB ) // I - Handle to control list box.
+
+{
+
+ DLM_HEADER_PTR pHdr ;
+ PVOID lpResult = NULL ;
+
+ // Must be valid window.
+
+ if ( !IsWindow( hWndLB ) ) {
+ return( NULL );
+ }
+
+ if ( hWndLB ) {
+
+ pHdr = DLM_GetDispHdr( hWndLB );
+
+ // Attempt to return the address the of unFocusItem item
+ // in the list box.
+
+ // The header must exist and the list must have at least one
+ // item ( hence unFocusItem = -1 if list is empty ) .
+
+ if ( pHdr ) {
+
+ if ( pHdr->unFocusItem != -1 ) {
+
+ lpResult = (PVOID) SendMessage( hWndLB,
+ LB_GETITEMDATA,
+ pHdr->unFocusItem,
+ 0L );
+
+ if ( lpResult == (PVOID)LB_ERR ) {
+ lpResult = NULL;
+ }
+ }
+ }
+ }
+
+ return lpResult;
+}
+
+
+/****************************************************************************
+GSH
+ Name: DLM_SetFocusItem
+
+ Description: This function draw the focus box around an item.
+
+ Modified: 11/11/1991
+
+ Returns: Nothing.
+
+ Notes:
+
+****************************************************************************/
+
+VOID DLM_SetFocusItem (
+
+LPDRAWITEMSTRUCT lpdis, // I - Pointer to information about item.
+LPRECT prcItem ) // I - pointer to item rectangle to draw focus around.
+
+{
+ // Put the focus around the item if the control gains the focus and
+ // the item has the input focus. (it doesn't work that way, but it should)
+
+
+ if ( ( lpdis->itemAction & ODA_FOCUS ) ) {
+
+ DLM_HEADER_PTR pHdr = DLM_GetDispHdr( lpdis->hwndItem );
+
+ if ( pHdr ) {
+
+ // Put the focus box around the item.
+
+ DrawFocusRect ( lpdis->hDC, prcItem );
+
+ pHdr->unFocusItem = lpdis->itemID ;
+
+ // Now, call back the function that the application may have set
+ // up for us to call when the focus changes.
+
+ if ( DLM_GSetItemFocus ( pHdr ) && ( lpdis->itemState & ODS_FOCUS ) ) {
+
+ SET_FOCUS_PTR pfnSetItemFocus = (SET_FOCUS_PTR) DLM_GSetItemFocus ( pHdr );
+
+ (*pfnSetItemFocus) ( (LMHANDLE)lpdis->itemData );
+ }
+ }
+ }
+
+} /* end DLM_SetFocusItem() */
+
+
+/****************************************************************************
+GSH
+ Name: DLM_SetBorderOnItem ()
+
+ Description: This function draws the plain rectangle around an item.
+
+ Modified: 1/13/1992
+
+ Returns: Nothing.
+
+ Notes:
+
+****************************************************************************/
+
+static VOID DLM_DrawBorderOnItem (
+
+HWND hWnd,
+DLM_HEADER_PTR pHdr,
+LPDRAWITEMSTRUCT lpdis )
+
+{
+ RECT rcAll;
+ INT nPrevSelect;
+
+ // If the focus is not in this window and this item is selected and there
+ // is actually data for this item, just draw a rectangle around the item.
+
+ if ( ! DLM_IsFocusInWindow ( hWnd, lpdis->hwndItem ) &&
+ ( lpdis->itemState & ODS_SELECTED ) &&
+ ( lpdis->itemData ) ) {
+
+ CopyRect ( (LPRECT)&rcAll, (LPRECT) &lpdis->rcItem );
+
+ nPrevSelect = (INT)SendMessage ( lpdis->hwndItem, LB_GETSEL, (MP1)(lpdis->itemID - 1), (MP2)0 );
+
+ if ( rcAll.top > 0 && lpdis->itemID > 0 && nPrevSelect > 0 ) {
+ rcAll.top--;
+ }
+
+ // If the listbox is in the singlecolumn mode, then include
+ // the pHdr->wHorizonalExtent.
+
+ if ( DLM_GMode( pHdr ) == DLM_SINGLECOLUMN ) {
+ rcAll.right = rcAll.left + pHdr->wHorizontalExtent - 1 ;
+ } else {
+ rcAll.right -= 1 ;
+ }
+
+ FrameRect ( lpdis->hDC, &rcAll, ghBrushHighLight );
+ }
+
+} /* end DLM_DrawBorderOnItem() */
+
+
+/****************************************************************************
+
+ Name: DLM_SetFont
+
+ Description: This function will change the font for child list boxes
+ of a given DOC window.
+
+ Modified: 08/20/1992
+
+ Returns: none
+
+ Notes: The DOC windows' listboxes, both the tree and flat
+ will be rescaled to support the new font.
+
+****************************************************************************/
+
+VOID DLM_SetFont(
+
+HWND hWndParent ) // I - Handle to DOC window.
+
+{
+
+ DLM_HEADER_PTR pdsHdr;
+ PVOID lpResult = NULL;
+ PDS_WMINFO pWinInfo;
+
+
+ // Must be valid window.
+
+ if ( !IsWindow( hWndParent ) ) {
+ return;
+ }
+
+ pWinInfo = (PDS_WMINFO) WM_GetInfoPtr( hWndParent );
+
+ if ( !pWinInfo ) {
+ return;
+ }
+
+
+ // ghFontFiles and ghFontIconLabels have changed.
+
+
+ // Reset the module variables that effect fonts in listboxes.
+
+
+ {
+
+ BOOL fResult;
+ INT maxwidth;
+ INT width;
+ INT unHeight;
+
+ fResult = RSM_GetFontSize( ghFontFiles,
+ &maxwidth,
+ &width,
+ &unHeight );
+
+ mwcxDLMFontFilesMaxWidth = (USHORT) maxwidth;
+ mwcxDLMFontFilesWidth = (USHORT) width;
+ mwcyDLMFontFilesHeight = (USHORT) unHeight;
+
+ fResult = RSM_GetFontSize( ghFontIconLabels,
+ &maxwidth,
+ &width,
+ &unHeight );
+
+ mwcxDLMIconLabelsMaxWidth = (USHORT) maxwidth;
+ mwcxDLMIconLabelsWidth = (USHORT) width;
+ mwcyDLMIconLabelsHeight = (USHORT) unHeight;
+
+ }
+
+ // Redo the hierarchical window if it exists.
+
+ if ( pWinInfo->hWndTreeList && pWinInfo->pTreeDisp ) {
+
+ USHORT unOldWidthCB;
+ USHORT unOldHeightCB;
+ USHORT unOldWidthBM;
+ USHORT unOldHeightBM;
+ LPARAM lpmHeight;
+
+ pdsHdr = pWinInfo->pTreeDisp;
+
+ // With Windows 3.1 set the height of every row by
+ // sending LB_SETITEMHEIGHT with the appropiate height.
+
+ // BUT, we DON'T want to screw up the old bitmap sizes.
+ // So save the old ones and put them back.
+
+ unOldWidthCB = DLM_GetCheckBoxWidth ( pdsHdr );
+ unOldHeightCB = DLM_GetCheckBoxHeight ( pdsHdr );
+ unOldWidthBM = DLM_GetBitMapWidth ( pdsHdr );
+ unOldHeightBM = DLM_GetBitMapHeight ( pdsHdr );
+
+ DLM_InitScrnValues( pdsHdr );
+
+ DLM_SetCheckBoxWidth ( pdsHdr, (USHORT) unOldWidthCB );
+ DLM_SetCheckBoxHeight ( pdsHdr, (USHORT) unOldHeightCB );
+ DLM_SetBitMapWidth ( pdsHdr, (USHORT) unOldWidthBM );
+ DLM_SetBitMapHeight ( pdsHdr, (USHORT) unOldHeightBM );
+
+ lpmHeight = MAKELPARAM( pdsHdr->cyColHeight, 0 );
+ SendMessage( pWinInfo->hWndTreeList, LB_SETITEMHEIGHT, 0, lpmHeight );
+ InvalidateRect( pWinInfo->hWndTreeList, NULL, TRUE );
+
+ }
+
+ if ( pWinInfo->hWndFlatList && pWinInfo->pFlatDisp ) {
+
+ USHORT unOldWidthCB;
+ USHORT unOldHeightCB;
+ USHORT unOldWidthBM;
+ USHORT unOldHeightBM;
+ LPARAM lpmHeight;
+ MEASUREITEMSTRUCT dsMeasureItem;
+
+ pdsHdr = pWinInfo->pFlatDisp;
+
+ // With Windows 3.1 set the height of every row by
+ // sending LB_SETITEMHEIGHT with the appropiate height.
+
+ // BUT, we DON'T want to screw up the old bitmap sizes.
+ // So save the old ones and put them back.
+
+ unOldWidthCB = DLM_GetCheckBoxWidth ( pdsHdr );
+ unOldHeightCB = DLM_GetCheckBoxHeight ( pdsHdr );
+ unOldWidthBM = DLM_GetBitMapWidth ( pdsHdr );
+ unOldHeightBM = DLM_GetBitMapHeight ( pdsHdr );
+
+ DLM_InitScrnValues( pdsHdr );
+
+ DLM_SetCheckBoxWidth ( pdsHdr, (USHORT) unOldWidthCB );
+ DLM_SetCheckBoxHeight ( pdsHdr, (USHORT) unOldHeightCB );
+ DLM_SetBitMapWidth ( pdsHdr, (USHORT) unOldWidthBM );
+ DLM_SetBitMapHeight ( pdsHdr, (USHORT) unOldHeightBM );
+
+ lpmHeight = MAKELPARAM( pdsHdr->cyColHeight, 0 );
+ SendMessage( pWinInfo->hWndFlatList, LB_SETITEMHEIGHT, 0, lpmHeight );
+
+
+ // Need to recalculate a new column width if multiple-column.
+
+ // If the mode is multicolumn, then switch to single-column and
+ // then back to multicolumn.
+
+ dsMeasureItem.CtlID = WMIDC_FLATLISTBOX;
+ DLM_WMMeasureItem( hWndParent, &dsMeasureItem );
+
+ SendMessage( pWinInfo->hWndFlatList, LB_SETCOLUMNWIDTH, pdsHdr->cxColWidth, 0L );
+
+ InvalidateRect( pWinInfo->hWndFlatList, NULL, TRUE );
+
+ }
+
+ // Update the document window once again.
+
+ InvalidateRect( hWndParent, NULL, TRUE );
+
+}
+
+
+/******************************************************************************
+
+ Name: DLM_GetPixelStringWidth()
+
+ Description: This function gets the pixel width of a string based on
+ the font associated with the window handle passed.
+
+ Returns: The width of the string in pixels.
+
+******************************************************************************/
+
+INT DLM_GetPixelStringWidth (
+
+HWND hWndLB, // I - handle to a list box window
+LPSTR lpString, // I - string ID or a pointer to the string
+INT nStringLen ) // I - string length
+
+{
+ HFONT hFont;
+ DLM_HEADER_PTR pHdr;
+
+ // The list box window must exist.
+
+ if ( ! IsWindow ( hWndLB ) ) {
+ return 0;
+ }
+
+ pHdr = DLM_GetDispHdr ( hWndLB );
+
+ // DLM display header must be defined.
+
+ if ( ! pHdr ) {
+ return 0;
+ }
+
+ switch ( DLM_GDisplay( pHdr ) ) {
+
+ case DLM_LARGEBITMAPSLTEXT:
+
+ hFont = ghFontFiles;
+ break;
+
+ case DLM_SMALL_BITMAPS:
+ default:
+
+ if ( DLM_GMode( pHdr ) == DLM_HIERARCHICAL ) {
+ hFont = ghFontIconLabels;
+ }
+ else {
+
+ // If the font is DLM_ANSI_FIXED_FONT, select ghFontLog.
+ // is DLM_SYSTEM_FONT, select ghFontIconLabels
+
+ if ( DLM_GTextFont( pHdr ) == DLM_ANSI_FIXED_FONT ) {
+ hFont = ghFontLog;
+ }
+ else {
+ hFont = ghFontIconLabels;
+ }
+ }
+
+ break;
+ }
+
+ return RSM_GetFontStringWidth ( hFont, lpString, nStringLen );
+
+} /* end DLM_GetPixelStringWidth() */
+
+
diff --git a/private/utils/ntbackup/src/dlm_init.c b/private/utils/ntbackup/src/dlm_init.c
new file mode 100644
index 000000000..83b2c28aa
--- /dev/null
+++ b/private/utils/ntbackup/src/dlm_init.c
@@ -0,0 +1,937 @@
+/****************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+ Name: DLM_INIT.C
+
+ Description: This file contains routines for display list manager.
+
+ The following routines are in this module:
+
+
+ DLM_Deinit
+ DLM_DispListInit
+ DLM_GetDispHdr
+ DLM_InitScrnValues
+ DLM_GetObjectsBuffer
+ DLM_Init
+ DLM_DispListTerm
+ DLM_WMDeleteItem
+ DLM_WMMeasureItem
+
+ $Log: G:/UI/LOGFILES/DLM_INIT.C_V $
+
+ Rev 1.26 15 Jun 1993 11:06:04 MIKEP
+enable c++
+
+ Rev 1.25 14 Jun 1993 20:17:48 MIKEP
+enable c++
+
+ Rev 1.24 23 Feb 1993 15:23:36 ROBG
+Added setting wHorizontalExtent to 0 to support the redefinition
+of a font for a listbox.
+
+ Rev 1.23 01 Nov 1992 15:46:38 DAVEV
+Unicode changes
+
+ Rev 1.21 16 Oct 1992 15:53:44 GLENN
+Changed default small bitmap back to IDRBM_EXE - closer to the text now. Also naming cleanup.
+
+ Rev 1.20 07 Oct 1992 13:47:32 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.19 04 Oct 1992 19:32:58 DAVEV
+Unicode Awk pass
+
+ Rev 1.18 28 Sep 1992 17:02:32 GLENN
+MikeP changes - casting stuff.
+
+ Rev 1.17 09 Sep 1992 10:28:10 GLENN
+Updated the max size of the folder bitmap.
+
+ Rev 1.16 08 Sep 1992 11:46:52 ROBG
+Changed cxPos from USHORT to short.
+
+ Rev 1.15 08 Sep 1992 10:08:18 ROBG
+Modified to solve the clipping bitmap problem.
+
+ Rev 1.14 04 Sep 1992 17:48:16 GLENN
+Fixed bitmap display clipping.
+
+ Rev 1.13 03 Sep 1992 15:30:48 ROBG
+Added conditionals for OS_WIN32.
+
+ Rev 1.12 21 Aug 1992 16:00:36 ROBG
+Changes to support change of font.
+
+ Rev 1.11 19 Aug 1992 14:32:34 ROBG
+Make modifications to use actual bitmap sizes and for the listboxes
+to be shorter and more compact.
+
+ Rev 1.10 21 May 1992 10:53:42 MIKEP
+fix my typo
+
+ Rev 1.9 19 May 1992 13:01:50 MIKEP
+mips changes
+
+ Rev 1.8 15 May 1992 13:35:28 MIKEP
+nt pass 2
+
+ Rev 1.7 14 May 1992 18:37:02 STEVEN
+40Format changes
+
+ Rev 1.6 29 Jan 1992 18:01:14 DAVEV
+
+
+ * No changes
+
+ Rev 1.5 10 Jan 1992 13:58:40 DAVEV
+16/32 bit port-2nd pass
+
+ Rev 1.4 26 Dec 1991 17:24:22 ROBG
+New and Improved.
+
+ Rev 1.3 27 Nov 1991 12:09:54 ROBG
+Modified parameters to DLM_DispListTerm and logic as well.
+
+ Rev 1.2 27 Nov 1991 09:27:46 ROBG
+Modified DLM_DispListTerm to support validity checks and
+deallocating the memory in the display list header and buffer.
+
+ Rev 1.1 26 Nov 1991 13:31:36 ROBG
+Added validity checks for the window handle, info structure, and the
+dlm display header.
+
+ Rev 1.0 20 Nov 1991 19:16:34 SYSTEM
+Initial revision.
+
+****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+/****************************************************************************
+
+ Name: DLM_Deinit
+
+ Description: This function will deinitialize the display list manager.
+
+ Modified: 12/19/1991
+
+ Returns: none.
+
+****************************************************************************/
+
+VOID DLM_Deinit( void )
+
+{
+ // Deallocate the temporary object buffer used when creating
+ // multi-column listboxes.
+
+ if ( mwpTempObjBuff ) {
+ free( mwpTempObjBuff ) ;
+ }
+}
+
+/****************************************************************************
+
+ Name: DLM_DispListInit
+
+ Description: This function will initialize the display list for a
+ window.
+
+ Modified: 2/07/1991
+
+ Returns: 0 if successful.
+
+ Valid error returns:
+
+ DLMERR_OUT_OF_MEMORY
+
+ Notes:
+
+ See also:
+
+****************************************************************************/
+
+WORD DLM_DispListInit(
+
+PVOID void_ptr, // I - Pointer to extra-bytes of a window
+DLM_INIT_PTR pdsInit ) // I - Pointer to initialization values
+
+{
+ WORD wStatus ;
+ DLM_HEADER_PTR pdsHdr ;
+ LMHANDLE pdsListHdr ;
+ PDS_WMINFO pWinInfo;
+ GET_COUNT_PTR pfnGetItemCount ;
+
+ pWinInfo = (PDS_WMINFO)void_ptr;
+
+ wStatus = 0 ;
+
+ switch ( pdsInit->bListBoxType ) {
+
+ case DLM_FLATLISTBOX :
+ pWinInfo->pFlatDisp = ( DLM_HEADER_PTR) calloc( 1, sizeof( DLM_HEADER) ) ;
+ if ( pWinInfo->pFlatDisp == NULL ) {
+ return( DLMERR_OUT_OF_MEMORY ) ;
+ }
+
+ memcpy( (LPSTR) (pWinInfo->pFlatDisp), pdsInit, sizeof( DLM_INIT ) ) ;
+ pdsHdr = pWinInfo->pFlatDisp ;
+ break ;
+
+ case DLM_TREELISTBOX :
+
+ pWinInfo->pTreeDisp = ( DLM_HEADER_PTR) calloc( 1, sizeof( DLM_HEADER) ) ;
+ if ( pWinInfo->pTreeDisp == NULL ) {
+ return( DLMERR_OUT_OF_MEMORY ) ;
+ }
+
+ memcpy( (LPSTR) (pWinInfo->pTreeDisp), pdsInit, sizeof( DLM_INIT ) ) ;
+ pdsHdr = pWinInfo->pTreeDisp ;
+ break ;
+
+ default :
+ return ( DLMERR_INIT_FAILED ) ;
+ break ;
+ }
+
+ pdsListHdr = ( LMHANDLE ) DLM_GDispHdr ( pdsHdr ) ;
+
+ pfnGetItemCount = (GET_COUNT_PTR) DLM_GGetItemCount( pdsHdr ) ;
+ pdsHdr->usItemCount = (USHORT) ( (*pfnGetItemCount) (pdsListHdr) ) ;
+
+ pdsHdr->fFocus = FALSE ;
+
+ DLM_InitScrnValues ( pdsHdr ) ;
+
+ /* Allocate DLM_ITEM area for list */
+
+ if ( DLM_GMaxNumObjects( pdsHdr ) == 0 ) {
+ DLM_GMaxNumObjects( pdsHdr ) = 6 ;
+ }
+
+ // Supports up to 159 levels deep.
+
+ pdsHdr->pGetObjBuffer = calloc( 1, 2 + 5*sizeof(DWORD) +
+ DLM_GMaxNumObjects(pdsHdr)*(sizeof(DLM_ITEM)) );
+
+ return ( 0 ) ;
+ }
+
+
+/****************************************************************************
+
+ Name: DLM_InitScrnValues
+
+ Description: This function will set the screen values for
+ displaying objects in the display manager's list
+ boxes.
+
+ Modified: 3/25/1991
+
+ Returns: none
+
+ Notes: A call to DLM_Init must have done before this routine
+ to set up the following variables:
+
+ mwcxDLMFontFilesWidth
+ mwcyDLMFontFilesHeight
+ mwcxDLMIconLabelsWidth
+ mwcyDLMIconLabelsHeight
+ See also:
+
+****************************************************************************/
+
+void DLM_InitScrnValues(
+
+DLM_HEADER_PTR pdsHdr ) //I - Pointer to DLM header values
+
+{
+
+ BOOL fResult ;
+ INT nWidth ;
+ INT nHeight ;
+
+ // There are currently two possibilities
+ //
+ // DLM_SMALL_BITMAPS
+ // DLM_LARGEBITMAPSLTEXT with text right of item.
+
+
+ switch ( DLM_GDisplay( pdsHdr ) ) {
+
+ case DLM_LARGEBITMAPSLTEXT :
+
+
+ fResult = RSM_GetBitmapSize( IDRBM_SEL_NONE, &nWidth, &nHeight ) ;
+
+ DLM_SetCheckBoxWidth ( pdsHdr, (USHORT) nWidth ) ;
+ DLM_SetCheckBoxHeight( pdsHdr, (USHORT) nHeight ) ;
+
+
+ fResult = RSM_GetBitmapSize( IDRBM_HARDDRIVE, &nWidth, &nHeight ) ;
+
+ DLM_SetBitMapWidth ( pdsHdr , (USHORT) nWidth ) ;
+ DLM_SetBitMapHeight( pdsHdr, (USHORT) nHeight ) ;
+
+
+ // Current checkbox is 12 wide.
+ // Current harddrive is 24 wide.
+
+ pdsHdr->cyTextHeight = mwcyDLMFontFilesHeight ;
+
+ pdsHdr->cxTextWidth = (USHORT)(mwcxDLMFontFilesWidth +
+ ( mwcxDLMFontFilesMaxWidth -
+ mwcxDLMFontFilesWidth)/2 );
+
+
+ pdsHdr->cxTextWidth = mwcxDLMFontFilesMaxWidth ;
+
+ // Offsets to place the objects horizontally. Magic numbers.
+
+ pdsHdr->cxBeforeCheckBox = 3 ; // Leave space before checkbox
+ pdsHdr->cxBeforeBitMap = 7 ; // Leave space before bitmap
+ pdsHdr->cxBeforeText = 6 ; // Leave space before text
+
+ pdsHdr->cxColWidth = 60 ; /* Calculated */
+
+ pdsHdr->cyColHeight = (USHORT)(mwcyDLMFontFilesHeight+4 );
+
+ // Offsets to place the objects vertically.
+
+ pdsHdr->cyBeforeText = 0 ;
+ pdsHdr->cyBeforeCheckBox = 1 ;
+ pdsHdr->cyBeforeBitMap = 1 ; // Adjust downwards 1
+
+ // The minimum height of an item is 20 pixels.
+ // This is the initial font with mwcyDLMFontFilesHeight(16) + 4
+
+ if ( pdsHdr->cyColHeight < 20 ) {
+ pdsHdr->cyColHeight = 20 ;
+ }
+
+ // If height of item is larger than 20, offset objects vertically.
+
+ if ( pdsHdr->cyColHeight > 20 ) {
+ pdsHdr->cyBeforeCheckBox += ( (pdsHdr->cyColHeight-21)/2 + 1 ) ;
+ pdsHdr->cyBeforeBitMap += ( (pdsHdr->cyColHeight-21)/2 + 1 ) ;
+
+ }
+
+ break ;
+
+
+ case DLM_SMALL_BITMAPS :
+ default :
+
+ fResult = RSM_GetBitmapSize( IDRBM_SEL_NONE, &nWidth, &nHeight ) ;
+
+ DLM_SetCheckBoxWidth ( pdsHdr, (USHORT) nWidth ) ;
+ DLM_SetCheckBoxHeight( pdsHdr, (USHORT) nHeight ) ;
+
+
+ fResult = RSM_GetBitmapSize( IDRBM_EXE, &nWidth, &nHeight ) ;
+
+ DLM_SetBitMapWidth ( pdsHdr, (USHORT) nWidth ) ;
+ DLM_SetBitMapHeight( pdsHdr, (USHORT) nHeight ) ;
+
+ // Current checkbox is 12 wide.
+ // Current folders are 16 wide.
+
+
+ pdsHdr->cyTextHeight = mwcyDLMIconLabelsHeight ;
+
+ pdsHdr->cxTextWidth = (USHORT)(mwcxDLMIconLabelsWidth +
+ ( mwcxDLMIconLabelsMaxWidth -
+ mwcxDLMIconLabelsWidth )/2 );
+
+ // Offsets to place the objects Horizontally.
+
+ pdsHdr->cxBeforeCheckBox = 3 ; // Leave space before checkbox
+ pdsHdr->cxBeforeBitMap = 2 ; // Leave space before bitmap
+ pdsHdr->cxBeforeText = 6 ; // Leave space before text
+
+
+ pdsHdr->cxColWidth = 60 ; /* Calculated */
+
+
+ pdsHdr->cyColHeight = (USHORT)(mwcyDLMIconLabelsHeight+3 );
+
+ /* These used by hierarchical only */
+
+ pdsHdr->cxHierHorzLine = pdsHdr->cxBeforeCheckBox +
+ (USHORT)(pdsHdr->cxCheckBoxWidth +
+ pdsHdr->cxBeforeBitMap + pdsHdr->cxBitMapWidth/2);
+
+ pdsHdr->cxHierHorzLen = (USHORT)(pdsHdr->cyTextHeight - 4) ;
+
+ pdsHdr->cxHierTab = pdsHdr->cxHierHorzLine +
+ pdsHdr->cxHierHorzLen ;
+
+ // Offsets to place the objects vertically.
+
+ pdsHdr->cyBeforeCheckBox = 0 ; // wrong for now, but works.
+ // Problem with short, ushort, int
+ pdsHdr->cyBeforeBitMap = -1 ;
+ pdsHdr->cyBeforeText = 0 ;
+
+ // Offset the CheckBox and Bitmap accordingly.
+
+ // The minimum height of an item is 16 pixels.
+ // This is the initial font with mwcyDLMIconLabelsHeight(13) + 3.
+
+ if ( pdsHdr->cyColHeight < 16 ) {
+ pdsHdr->cyColHeight = 16 ;
+ }
+
+ // If height of item is larger than 16, offset objects vertically.
+
+ if ( pdsHdr->cyColHeight > 16 ) {
+ pdsHdr->cyBeforeCheckBox += ( (pdsHdr->cyColHeight-17)/2 + 1 ) ;
+ pdsHdr->cyBeforeBitMap += ( (pdsHdr->cyColHeight-17)/2 + 1 ) ;
+
+ }
+
+ break ;
+ }
+
+ // Reset the Horizontal Extent
+
+ pdsHdr->wHorizontalExtent = 0 ;
+}
+
+
+
+/****************************************************************************
+
+ Name: DLM_GetDispHdr
+
+ Description: This function will select the appropiate DLM_HEADER
+ area specified by the handle to the control .
+
+ Modified: 3/22/1991
+
+ Returns: 0 if successful.
+
+ Valid error returns:
+
+ DLMERR_LIST_NOT_FOUND
+
+ Notes:
+
+ See also:
+
+****************************************************************************/
+
+DLM_HEADER_PTR DLM_GetDispHdr(
+
+HWND hWndCtl ) //I - Handle of a list box
+
+{
+
+ HWND hParentWnd ;
+ PDS_WMINFO pWinInfo ;
+ DLM_HEADER_PTR pdsHdr ;
+
+ // Check validity of window handle.
+
+ if ( !IsWindow( hWndCtl ) ) {
+ return ( NULL ) ;
+ }
+
+ hParentWnd = GetParent( hWndCtl ) ;
+
+ // Check validity of window handle.
+
+ if ( !IsWindow( hParentWnd ) ) {
+ return( NULL ) ;
+ }
+
+ pWinInfo = (PDS_WMINFO) WM_GetInfoPtr( hParentWnd ) ;
+
+ pdsHdr = NULL ;
+
+ // Check to see which control box it is by comparing handles */
+
+ if ( !pWinInfo ) {
+ return ( pdsHdr ) ;
+ }
+
+ if ( pWinInfo->hWndTreeList == hWndCtl ) {
+
+ pdsHdr = pWinInfo->pTreeDisp ;
+
+ } else {
+ if ( pWinInfo->hWndFlatList == hWndCtl ) {
+
+ pdsHdr = pWinInfo->pFlatDisp ;
+ }
+ }
+
+ return( pdsHdr ) ;
+}
+
+
+
+/****************************************************************************
+
+ Name: DLM_GetObjectsBuffer
+
+ Description: This function returns the buffer reserved for
+ the list box specified. It will initialize the
+ buffer to zero.
+
+ Modified: 11/19/1991
+
+ Returns: 0 if successful.
+
+ Valid error returns:
+
+ DLMERR_LIST_NOT_FOUND
+
+ Notes:
+
+ See also:
+
+****************************************************************************/
+
+PVOID DLM_GetObjectsBuffer(
+
+HWND hWndCtl ) //I - Handle of a list box
+
+{
+ DLM_HEADER_PTR pHdr ;
+
+ // Check validity of window handle.
+
+ if ( !IsWindow( hWndCtl ) ) {
+
+ // Since the hWndCtl is invalid, it is most likely the application
+ // is responding to a GetObjects call during the creation
+ // of a multi-column listbox. Use the special temporary buffer.
+
+ if ( mwpTempObjBuff ) {
+ return( mwpTempObjBuff ) ;
+ } else {
+ return( NULL ) ;
+ }
+ }
+
+ pHdr = DLM_GetDispHdr( hWndCtl ) ;
+
+ if ( pHdr ) {
+
+ return ( (PVOID) DLM_GGetObjBuffer( pHdr ) ) ;
+ }
+
+ return ( NULL ) ;
+
+}
+
+
+/****************************************************************************
+
+ Name: DLM_Init
+
+ Description: This function will initialize the display list for
+ the system.
+
+ Modified: 3/27/1991
+
+ Returns: 0 if successful.
+
+ Valid error returns:
+
+ DLMERR_OUT_OF_MEMORY
+
+****************************************************************************/
+
+WORD DLM_Init(
+
+HWND hWnd ) //I - Handle to a Window
+
+{
+
+ BOOL fResult ;
+ INT nMaxWidth ;
+ INT nWidth ;
+ INT nHeight ;
+
+ if ( !mwfFontSizesSet ) {
+
+ fResult = RSM_GetFontSize( ghFontFiles,
+ &nMaxWidth,
+ &nWidth,
+ &nHeight ) ;
+
+ mwcxDLMFontFilesMaxWidth = (USHORT) nMaxWidth ;
+ mwcxDLMFontFilesWidth = (USHORT) nWidth ;
+ mwcyDLMFontFilesHeight = (USHORT) nHeight ;
+
+ {
+
+ HDC hDC ;
+ int temp ;
+ HFONT hOldFont;
+ WORD wHeight ;
+ WORD wWidth ;
+
+ hDC = GetDC( hWnd ) ;
+ hOldFont = (HFONT)SelectObject ( hDC, ghFontFiles );
+
+ temp = GetTextCharacterExtra ( hDC ) ;
+ {
+ SIZE size;
+ GetTextExtentPoint( hDC, TEXT("C:"), 2, &size ) ;
+ wWidth = (WORD)size.cx;
+ wHeight = (WORD)size.cy;
+ }
+
+ // Put back the old font.
+
+ SelectObject ( hDC, hOldFont );
+ ReleaseDC ( hWnd, hDC );
+
+ }
+
+ fResult = RSM_GetFontSize( ghFontIconLabels,
+ &nMaxWidth,
+ &nWidth,
+ &nHeight ) ;
+
+ mwcxDLMIconLabelsMaxWidth = (USHORT) nMaxWidth ;
+ mwcxDLMIconLabelsWidth = (USHORT) nWidth ;
+ mwcyDLMIconLabelsHeight = (USHORT) nHeight ;
+
+ fResult = RSM_GetFontSize( ghFontLog,
+ &nMaxWidth,
+ &nWidth,
+ &nHeight ) ;
+
+ mwcxDLMFontLogMaxWidth = (USHORT) nMaxWidth ;
+ mwcxDLMFontLogWidth = (USHORT) nWidth ;
+ mwcyDLMFontLogHeight = (USHORT) nHeight ;
+
+
+ mwfFontSizesSet = 1;
+
+ mwDLMInflate = -2 ;
+
+ // Allocate temporary object buffer used when any listbox
+ // is created with multi-columns specified.
+ // The WM_MeasureItem message needs to do a GetObjects
+ // during the creation of the window and and the application
+ // hasn't yet returned from the WM_Create call.
+
+ // Supports up to 10 objects and 159 levels deep.
+
+ mwpTempObjBuff = (CHAR_PTR)calloc( 1, 2 + 5*sizeof(DWORD) +
+ 10*(sizeof(DLM_ITEM)) );
+
+ }
+
+ return ( 0 ) ;
+}
+
+
+/****************************************************************************
+
+ Name: DLM_DispListTerm
+
+ Description: De-initializes the display list for a control window. This
+ function is called by the application when all references
+ to the display information are to be discarded and freed.
+
+ Modified: 2/07/1991
+
+ Returns: 0 if successful.
+
+ Valid error returns:
+
+ DLMERR_TERMINATE_FAILED
+
+****************************************************************************/
+
+WORD DLM_DispListTerm(
+
+PVOID void_ptr, // I - Pointer to WinInfo of parent.
+HWND hWndCtl ) // I - Handle to a listbox.
+
+{
+ DLM_HEADER_PTR pHdr ;
+ WORD wStatus ;
+ PDS_WMINFO pWinInfo;
+
+ pWinInfo = (PDS_WMINFO)void_ptr;
+
+ wStatus = 0 ;
+
+ // Check to see which control box it is by comparing handles */
+
+ pHdr = NULL ;
+
+ if ( pWinInfo ) {
+
+ if ( pWinInfo->hWndTreeList == hWndCtl ) {
+
+ pHdr = pWinInfo->pTreeDisp ;
+ }
+
+ if ( pWinInfo->hWndFlatList == hWndCtl ) {
+
+ pHdr = pWinInfo->pFlatDisp ;
+ }
+ }
+
+ if( pHdr ) {
+
+ if ( DLM_GGetObjBuffer (pHdr) ) {
+ free( DLM_GGetObjBuffer (pHdr) ) ;
+ }
+
+ free( pHdr ) ;
+ } else {
+
+ return ( DLMERR_TERMINATE_FAILED ) ;
+ }
+
+
+ return( wStatus ) ;
+
+}
+
+/****************************************************************************
+
+ Name: DLM_WMDeleteItem
+
+ Description: Not Used any more. Called by DOCPROC.C
+
+ Modified: 2/07/1991
+
+ Returns: Always TRUE.
+
+ Notes:
+
+ See also:
+
+****************************************************************************/
+
+
+WORD DLM_WMDeleteItem(
+
+HWND hWnd , // I - Handle to a window
+LPDELETEITEMSTRUCT lParam ) // I - Additional Information
+
+{
+ DBG_UNREFERENCED_PARAMETER ( hWnd );
+ DBG_UNREFERENCED_PARAMETER ( lParam );
+
+ return TRUE;
+}
+
+
+/****************************************************************************
+
+ Name: DLM_WMMeasureItem()
+
+ Description: This function returns the height and width of an item
+ in a list box.
+
+ Modified: 2/15/1991
+
+ Returns: 0 if successful.
+
+
+****************************************************************************/
+
+
+WORD DLM_WMMeasureItem(
+
+HWND hWnd , // I - Handle of parent window of a listbox.
+LPMEASUREITEMSTRUCT lParam ) // I/O - Pointer to data structure to return
+ // measurement values to Windows 3.0.
+
+{
+ PDS_WMINFO pWinInfo ;
+ DLM_HEADER_PTR pdsHdr ;
+ WORD wCtlID ;
+ LPMEASUREITEMSTRUCT pMeasItem ;
+ GET_COUNT_PTR pfnGetItemCount ;
+ GET_FIRST_PTR pfnGetFirstItem ;
+ GET_OBJECTS_PTR pfnGetObjects ;
+ WORD wType ;
+
+ LMHANDLE pdsListHdr ;
+ LMHANDLE dhListItem = (LMHANDLE)0;
+ DLM_ITEM_PTR lpDispItem ;
+ BYTE_PTR lpObjLst ;
+ BOOL fSetZeroValues ;
+ USHORT usCnt ;
+ BYTE bObjCnt ;
+ short cxPos ;
+
+ pMeasItem = (LPMEASUREITEMSTRUCT) lParam ;
+
+ wCtlID = (WORD)pMeasItem->CtlID ;
+
+ if ( !IsWindow( hWnd ) ) {
+
+ // Set the width and height to 0 to indicate error.
+ // This should never happen.
+
+ pMeasItem->itemWidth = 0 ;
+ pMeasItem->itemHeight = 0 ;
+
+ return(0) ;
+ }
+
+ pWinInfo = WM_GetInfoPtr( hWnd ) ;
+
+ msassert( pWinInfo != (VOID_PTR) NULL ) ;
+
+ switch ( wCtlID ) {
+
+ case WMIDC_TREELISTBOX :
+
+ pdsHdr = pWinInfo->pTreeDisp ;
+
+ if ( pdsHdr ) {
+
+ pMeasItem->itemWidth = pdsHdr->cxColWidth ;
+ pMeasItem->itemHeight = pdsHdr->cyColHeight ;
+
+ } else {
+
+ // Set the width and height to 0 to indicate error.
+ // This should never happen.
+
+ pMeasItem->itemWidth = 0 ;
+ pMeasItem->itemHeight = 0 ;
+
+ }
+
+ // Do not attempt to appropiately set the values for
+ // width and height because tree list boxes are
+ // immediately switched to single column listboxes.
+
+ break ;
+
+ case WMIDC_FLATLISTBOX :
+ default :
+
+ pdsHdr = pWinInfo->pFlatDisp ;
+ pdsListHdr = ( LMHANDLE ) WMDS_GetFlatList ( pWinInfo );
+
+ wType = WMDS_GetWinType( pWinInfo ) ;
+
+ /* The following steps are taken to set up the appropiate
+ ** width and height.
+ **
+ ** IF pdsHdr exists and pdsListHdr exists and count > 0
+ ** BEGIN
+ ** Get the first item on the queue.
+ ** IF item exists
+ ** BEGIN
+ ** . Get the objects of the item.
+ ** . Calculate the width and height based on the objects found.
+ ** END
+ ** END
+ ** ELSE
+ ** set width and height to defaults ;
+ */
+
+ pMeasItem->itemWidth = pdsHdr->cxColWidth ;
+ pMeasItem->itemHeight = pdsHdr->cyColHeight ;
+
+ fSetZeroValues = TRUE ;
+
+ // Some window type are never multi-column
+ // Just reset the global reference of window handle.
+
+ switch ( wType ) {
+
+ case WMTYPE_JOBS :
+ case WMTYPE_MACROS :
+ case WMTYPE_TAPES :
+ case WMTYPE_DEBUG :
+ case WMTYPE_LOGFILES :
+ case WMTYPE_SERVERS :
+ case WMTYPE_LOGVIEW :
+ case WMTYPE_SEARCH :
+#ifdef OEM_EMS
+ case WMTYPE_EXCHANGE :
+#endif
+ pdsHdr = NULL ;
+ break ;
+ }
+
+ if ( pdsHdr ) {
+ pfnGetItemCount = (GET_COUNT_PTR) DLM_GGetItemCount( pdsHdr ) ;
+ pfnGetFirstItem = (GET_FIRST_PTR) DLM_GGetFirstItem( pdsHdr ) ;
+ pfnGetObjects = (GET_OBJECTS_PTR) DLM_GGetObjects ( pdsHdr ) ;
+
+ if ( pdsListHdr ) {
+ usCnt = (USHORT) ( (*pfnGetItemCount) (pdsListHdr) );
+ if ( usCnt ) {
+ dhListItem = (LMHANDLE) ( (*pfnGetFirstItem) (pdsListHdr) ) ;
+ if ( dhListItem ) {
+ lpObjLst = (BYTE_PTR) ( (*pfnGetObjects) (dhListItem) ) ;
+ lpDispItem = DLM_GetFirstObject( (BYTE_PTR)lpObjLst, &bObjCnt ) ;
+
+ // Calculate the width by spanning
+ // the object list, adding up the widths
+ // of the objects.
+
+ cxPos = 0 ;
+
+ while (bObjCnt) {
+
+ DLM_GetWidth ( hWnd, pdsHdr, &cxPos, lpDispItem ) ;
+
+ // Special Logic for long strings.
+ // If the string is greater than 5, then take off 33%.
+
+
+ if ( ( DLM_ItembType ( lpDispItem ) == DLM_TEXT_ONLY ) &&
+ ( DLM_GDisplay( pdsHdr ) == DLM_LARGEBITMAPSLTEXT ) ){
+
+ LONG lLen ;
+ lLen = strlen( (CHAR_PTR)DLM_ItemqszString( lpDispItem ) );
+
+ if ( lLen > 5 ) {
+ cxPos -= ( pdsHdr->cxBeforeText +
+ ( DLM_ItembMaxTextLen( lpDispItem )*( pdsHdr->cxTextWidth ) ) ) / 3 ;
+ }
+ }
+
+ lpDispItem++;
+ bObjCnt--;
+ }
+
+ fSetZeroValues = TRUE ;
+
+ // Added left and right 2 pixel area for focus and add 5 for right margin
+
+ pMeasItem->itemWidth = (int) ( cxPos + 2*(-mwDLMInflate ) + 5 ) ;
+
+ pdsHdr->cxColWidth = (USHORT)pMeasItem->itemWidth ;
+ }
+
+ }
+ }
+ }
+
+ break ;
+
+ }
+
+ return ( TRUE ) ;
+
+}
+
diff --git a/private/utils/ntbackup/src/dlm_lbn.c b/private/utils/ntbackup/src/dlm_lbn.c
new file mode 100644
index 000000000..4701376d2
--- /dev/null
+++ b/private/utils/ntbackup/src/dlm_lbn.c
@@ -0,0 +1,843 @@
+/****************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+ Name: DLM_LBN.C
+
+ Description: This file contains routines for display list manager.
+
+ The following routines are in this module:
+
+
+ DLM_LBNmessages
+ DLM_LBNflatmsgs
+ DLM_ProcessButton
+ DLM_GetFirstObject
+
+ $Log: G:/UI/LOGFILES/DLM_LBN.C_V $
+
+ Rev 1.20 15 Jun 1993 10:57:08 MIKEP
+enable c++
+
+ Rev 1.19 14 Jun 1993 20:20:10 MIKEP
+enable c++
+
+ Rev 1.18 25 Feb 1993 13:24:56 STEVEN
+fixes from mikep and MSOFT
+
+ Rev 1.17 21 Dec 1992 12:25:18 DAVEV
+Enabled for Unicode - IT WORKS!!
+
+ Rev 1.16 07 Oct 1992 13:46:52 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.15 04 Oct 1992 19:33:04 DAVEV
+Unicode Awk pass
+
+ Rev 1.14 09 Sep 1992 16:13:34 GLENN
+Updated castings for MikeP (NT).
+
+ Rev 1.13 08 Sep 1992 11:48:58 ROBG
+Changed cxPos, cyPos from USHORT to short.
+
+ Rev 1.12 10 Jun 1992 10:57:24 STEVEN
+NULL would not compile for mips
+
+ Rev 1.11 15 May 1992 13:32:22 MIKEP
+nt pass 2
+
+ Rev 1.10 20 Mar 1992 17:22:32 GLENN
+Fixed VK_RETURN to work on key down instead of key up.
+
+ Rev 1.9 17 Mar 1992 18:27:46 GLENN
+Removed unnecessary invalidate rects.
+
+ Rev 1.8 09 Mar 1992 10:48:56 GLENN
+Added VK_RETURN checking for keyboard processing.
+
+ Rev 1.7 03 Mar 1992 18:22:02 GLENN
+Put in error handling.
+
+ Rev 1.6 11 Feb 1992 12:19:36 DAVEV
+steve is brain-dead fix bug in NT_KLUG
+
+ Rev 1.5 04 Feb 1992 16:07:26 STEVEN
+various bug fixes for NT
+
+ Rev 1.4 15 Jan 1992 15:16:36 DAVEV
+16/32 bit port-2nd pass
+
+ Rev 1.3 26 Dec 1991 17:22:10 ROBG
+New and Improved.
+
+ Rev 1.2 03 Dec 1991 13:21:20 DAVEV
+Modifications for 16/32-bit Windows port - 1st pass.
+
+ Rev 1.1 26 Nov 1991 13:21:28 ROBG
+Added validity checks for the window handle, info structure, and the
+dlm display header.
+
+ Rev 1.0 20 Nov 1991 19:18:10 SYSTEM
+Initial revision.
+
+****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+/****************************************************************************
+
+ Name: DLM_LBNmessages
+
+ Description: This function will process a mouse button.
+
+ Modified: 2/15/1991
+
+ Returns: SUCCESS if successful, otherwise FAILURE.
+
+****************************************************************************/
+
+
+WORD DLM_LBNmessages(
+
+ HWND hWnd, // I - Handle of parent window of a listbox.
+ MP1 mp1, // I - Additional information
+ MP2 mp2 ) // I - Additional information
+
+{
+ RECT rectItem ;
+ RECT rectTest ;
+ LMHANDLE pListItem ;
+ WORD wCurSel, wTopSel ;
+ LRESULT Error;
+ DLM_HEADER_PTR pHdr ;
+ PDS_WMINFO pWinInfo ;
+ short cxPos, cyPos ;
+ DLM_ITEM_PTR lpDispItem ;
+ GET_OBJECTS_PTR pfnGetObjects ;
+ BYTE bObjCnt ;
+ BYTE_PTR lpObjLst ;
+ POINT pt ;
+ WORD wLbnValue ;
+ BYTE fButtonProcessed = FALSE ;
+ WORD wId = GET_WM_COMMAND_ID ( mp1, mp2 );
+ WORD wCmd = GET_WM_COMMAND_CMD ( mp1, mp2 );
+ HWND hwndLB = GET_WM_COMMAND_HWND ( mp1, mp2 );
+
+ // Must be valid window.
+
+ if ( !IsWindow( hWnd ) ) {
+ return FAILURE;
+ }
+
+ pWinInfo = WM_GetInfoPtr( hWnd ) ;
+
+ // Extra Bytes for window must be defined.
+
+ if ( !pWinInfo ) {
+ return FAILURE;
+ }
+
+ switch (wId) {
+
+ case WMIDC_TREELISTBOX :
+
+ pHdr = pWinInfo->pTreeDisp ;
+ break ;
+
+ case WMIDC_FLATLISTBOX :
+ default :
+
+ pHdr = pWinInfo->pFlatDisp ;
+ break ;
+ }
+
+ // DLM display header must be defined.
+
+ if ( !pHdr ) {
+ return FAILURE;
+ }
+
+ if ( ( DLM_GMode( pHdr ) == DLM_HIERARCHICAL ) &&
+ ( DLM_GDisplay( pHdr ) == DLM_SMALL_BITMAPS ) ) {
+
+ /* Hierarchical, small bitmaps, large text */
+
+ switch ( wCmd ) {
+
+ case LBN_SELCHANGE :
+ case LBN_DBLCLK :
+
+ pWinInfo = WM_GetInfoPtr( hWnd ) ;
+ pHdr = (WM_GetInfoPtr( hWnd ))->pTreeDisp ;
+
+ /* Look at gDLMpt for current mouse position */
+
+ wCurSel = (WORD) SendMessage (hwndLB,
+ LB_GETCURSEL, 0L, 0L ) ;
+
+ Error = SendMessage (hwndLB, LB_GETITEMRECT, wCurSel,
+ (LONG) ( LPRECT ) &rectItem ) ;
+
+# ifdef NTKLUG
+ Error = SendMessage (hwndLB, WM_DLMGETTEXT, wCurSel,
+ (LONG) &pListItem ) ;
+# else
+ Error = SendMessage (hwndLB, LB_GETTEXT, wCurSel,
+ (LONG) &pListItem ) ;
+# endif
+
+
+ // ERROR CHECKING
+
+ if ( Error == LB_ERR ) {
+ return FAILURE;
+ }
+
+
+ wTopSel = (WORD) SendMessage (hwndLB, LB_GETTOPINDEX, 0,
+ (LONG) 0L ) ;
+
+
+ /* Origin of control */
+
+ /* It is known that x,y is in the rectangle */
+
+ pfnGetObjects = (GET_OBJECTS_PTR) DLM_GGetObjects( pHdr ) ;
+
+ lpObjLst = (BYTE_PTR) ( (*pfnGetObjects) (pListItem) ) ;
+ lpDispItem = DLM_GetFirstObject( lpObjLst, &bObjCnt ) ;
+
+ cxPos = (short) rectItem.left ;
+ cyPos = (short) rectItem.top ;
+
+ cxPos += ( ( DLM_ItembLevel( lpDispItem ) )* pHdr->cxHierTab ) ;
+
+ pt = gDLMpt ;
+ pt.x = gDLMpt.x + pHdr->xOrigin ;
+
+
+ while (bObjCnt) {
+
+ DLM_GetRect( pWinInfo->hWndTreeList, pHdr, (LPSHORT)&cxPos, cyPos, &rectTest, lpDispItem ) ;
+
+ if ( pHdr->fKeyDown == TRUE ) { /* When a key down occurs, wait until */
+ /* a key up sequence is encountered. */
+ if ( pHdr->fKeyUp == TRUE ) {
+
+ /* Initiated by key stroke. Signal last object in string */
+
+ pHdr->cLastTreeSelect = wCurSel ;
+
+ lpDispItem += bObjCnt-1 ;
+
+
+// if ( pHdr->wKeyValue == VK_RETURN ) {
+// wLbnValue = LBN_DBLCLK ;
+// } else {
+// wLbnValue = LBN_SELCHANGE ;
+// }
+
+ wLbnValue = wCmd ;
+
+ DLM_ProcessButton ( pWinInfo->hWndTreeList,
+ pHdr,
+ wLbnValue,
+ &rectTest,
+ wCurSel,
+ pListItem,
+ lpDispItem
+ ) ;
+
+ fButtonProcessed = TRUE ;
+
+ }
+
+ break ;
+ }
+
+ if ( PtInRect ( &rectTest, pt ) ) {
+ pHdr->cLastTreeSelect = wCurSel ;
+
+ DLM_ProcessButton( pWinInfo->hWndTreeList, pHdr, wCmd, &rectTest,
+ wCurSel, pListItem, lpDispItem ) ;
+ fButtonProcessed = TRUE ;
+
+ break ;
+ }
+
+ lpDispItem++;
+ bObjCnt--;
+ }
+
+ /* The following section of logic has been added to handle the case
+ when the user drags the mouse when making a selection and
+ does not release the button over an object.
+
+ Under normal conditions the processing of button would be
+ ignored. In this case, however, the application needs to
+ know that a new selection in the list has been selected.
+
+ If a LBN_SELCHANGE ( single click ) message occurs
+ If the button has not been processed and
+ the item selected was initiated by the mouse and
+ the listbox's current selection has changed
+ then process button for last object.
+
+
+ Note: When a user double-clicks in the hierarchical listbox,
+ a LBN_SELCHANGE message is sent before a LBN_DBLCLK.
+ However, since the current selection has not changed
+ ( pHdr->cLastTreeSelect = wCurSel ), the button
+ is not processed.
+ */
+
+
+ if ( ( wCmd == LBN_SELCHANGE ) &&
+ ( fButtonProcessed == FALSE ) &&
+ ( pHdr->fKeyDown == FALSE ) &&
+ ( pHdr->cLastTreeSelect != wCurSel ) ) {
+
+ lpDispItem -- ;
+
+ pHdr->cLastTreeSelect = wCurSel ;
+
+ DLM_ProcessButton( pWinInfo->hWndTreeList, pHdr, wCmd, &rectTest,
+ wCurSel, pListItem, lpDispItem ) ;
+ }
+
+
+ return SUCCESS;
+ break ;
+
+ case LBN_SETFOCUS :
+
+ pHdr->fFocus = TRUE ;
+
+// InvalidateRect( hwndLB , NULL, FALSE ) ;
+
+ break ;
+
+ case LBN_KILLFOCUS :
+
+ pHdr->fFocus = FALSE ;
+
+// InvalidateRect( hwndLB , NULL, FALSE ) ;
+
+ break ;
+ }
+
+ } else {
+
+ return( (WORD) DLM_LBNflatmsgs( hWnd, mp1, mp2 ) ) ;
+ }
+
+ return SUCCESS;
+}
+
+/****************************************************************************
+
+ Name: DLM_LBNflatmsgs
+
+ Description: This function will process button operations on a
+ listbox with a flat list type.
+ in the list.
+
+ Modified: 2/15/1991
+
+ Returns: SUCCESS if successful, otherwise FAILURE.
+
+****************************************************************************/
+
+
+WORD DLM_LBNflatmsgs(
+
+ HWND hWnd , // I - Handle of parent window of a listbox.
+ MP1 mp1 , // I - Additional information
+ MP2 mp2 ) // I - Additional information
+
+{
+
+ RECT rectItem ;
+ RECT rectTest ;
+ LMHANDLE pListItem ;
+ WORD wCurSel;
+ LRESULT Error;
+ DLM_HEADER_PTR pHdr ;
+ PDS_WMINFO pWinInfo ;
+ short cxPos, cyPos ;
+ DLM_ITEM_PTR lpDispItem ;
+ GET_OBJECTS_PTR pfnGetObjects ;
+ BYTE bObjCnt ;
+ LPBYTE lpObjLst ;
+ POINT pt ;
+ WORD wLbnValue ;
+ WORD wId = GET_WM_COMMAND_ID ( mp1, mp2 );
+ WORD wCmd = GET_WM_COMMAND_CMD ( mp1, mp2 );
+ HWND hwndLB = GET_WM_COMMAND_HWND ( mp1, mp2 );
+
+ // Must be valid window.
+
+ if ( !IsWindow( hWnd ) ) {
+ return FAILURE;
+ }
+
+ pWinInfo = WM_GetInfoPtr( hWnd ) ;
+
+ // Extra Bytes for window must be defined.
+
+ if ( !pWinInfo ) {
+ return FAILURE;
+ }
+
+ switch (wId ) {
+
+ case WMIDC_TREELISTBOX :
+
+ pHdr = pWinInfo->pTreeDisp ;
+ break ;
+
+ case WMIDC_FLATLISTBOX :
+ default :
+
+ pHdr = pWinInfo->pFlatDisp ;
+ break ;
+ }
+
+ // DLM display header must be defined.
+
+ if ( !pHdr ) {
+ return FAILURE;
+ }
+
+ switch ( DLM_GDisplay( pHdr ) ) {
+
+ case DLM_LARGEBITMAPSLTEXT :
+
+ switch ( wCmd ) {
+
+ case LBN_SELCHANGE :
+ case LBN_DBLCLK :
+
+ /* Look at gDLMpt for current mouse position */
+
+ wCurSel = (WORD) SendMessage (hwndLB,
+ LB_GETCURSEL, 0L, 0L ) ;
+
+ Error = SendMessage (hwndLB, LB_GETITEMRECT, wCurSel,
+ (LONG) ( LPRECT ) &rectItem ) ;
+
+# ifdef NTKLUG
+ Error = SendMessage (hwndLB, WM_DLMGETTEXT, wCurSel,
+ (LONG) &pListItem ) ;
+# else
+ Error = SendMessage (hwndLB, LB_GETTEXT, wCurSel,
+ (LONG) &pListItem ) ;
+# endif
+
+ // ERROR CHECKING
+
+ if ( Error == LB_ERR ) {
+ return FAILURE;
+ }
+
+
+ // Ignore messages when the user initiates a double click and
+ // the mouse is not in the current selection rectangle.
+
+ pt = gDLMpt ;
+ pt.x = gDLMpt.x + pHdr->xOrigin ;
+
+ if ( pHdr->fKeyDown == FALSE ) {
+
+ if ( !PtInRect ( &rectItem, pt ) ) {
+ return SUCCESS;
+ }
+
+ }
+
+ /* Origin of control */
+
+ /* It is known that x,y is in the rectangle */
+
+ pfnGetObjects = (GET_OBJECTS_PTR) DLM_GGetObjects( pHdr ) ;
+
+ lpObjLst = (BYTE_PTR) ( (*pfnGetObjects) (pListItem) ) ;
+ bObjCnt = *lpObjLst ;
+ lpDispItem = (DLM_ITEM_PTR) ( lpObjLst + 2 + sizeof( DWORD ) );
+
+ cxPos = (WORD) rectItem.left ;
+ cyPos = (WORD) rectItem.top ;
+
+ while (bObjCnt) {
+
+ DLM_GetRect( pWinInfo->hWndFlatList, pHdr, (LPSHORT)&cxPos, cyPos, &rectTest, lpDispItem ) ;
+
+ if ( pHdr->fKeyDown == TRUE ) {
+
+ /* Initiated by key stroke. Signal last object in string */
+
+ lpDispItem += bObjCnt-1 ;
+
+// if ( pHdr->fKeyUp == TRUE && pHdr->wKeyValue == VK_RETURN ) {
+// wLbnValue = LBN_DBLCLK ;
+// } else {
+// wLbnValue = LBN_SELCHANGE ;
+// }
+
+ wLbnValue = wCmd ;
+
+ DLM_ProcessButton ( pWinInfo->hWndFlatList,
+ pHdr,
+ wLbnValue,
+ &rectTest,
+ wCurSel,
+ pListItem,
+ lpDispItem
+ ) ;
+ break ;
+
+ }
+
+
+ if ( !( ( DLM_ItemwId ( lpDispItem ) == 0 ) && /* Skip if checkbox is ignored */
+ ( DLM_ItembType( lpDispItem ) == DLM_CHECKBOX ) ) ) {
+
+ if ( PtInRect ( &rectTest, pt ) ) {
+ DLM_ProcessButton( pWinInfo->hWndFlatList, pHdr, wCmd, &rectTest,
+ wCurSel, pListItem, lpDispItem ) ;
+ break ;
+ }
+ }
+
+ lpDispItem++;
+ bObjCnt--;
+ }
+
+ return SUCCESS;
+ break ;
+
+
+ case LBN_SETFOCUS :
+ pHdr->fFocus = TRUE ;
+
+ break ;
+
+ case LBN_KILLFOCUS :
+ pHdr->fFocus = FALSE ;
+
+ break ;
+
+ }
+
+
+ break ;
+
+
+ case DLM_SMALL_BITMAPS :
+
+ switch ( wCmd ) {
+
+ case LBN_SELCHANGE :
+ case LBN_DBLCLK :
+
+ /* Look at gDLMpt for current mouse position */
+
+ wCurSel = (WORD) SendMessage (hwndLB,
+ LB_GETCURSEL, 0L, 0L ) ;
+
+ Error = SendMessage (hwndLB, LB_GETITEMRECT, wCurSel,
+ (LONG) ( LPRECT ) &rectItem ) ;
+
+# ifdef NTKLUG
+ Error = SendMessage (hwndLB, WM_DLMGETTEXT, wCurSel,
+ (LONG) &pListItem ) ;
+# else
+ Error = SendMessage (hwndLB, LB_GETTEXT, wCurSel,
+ (LONG) &pListItem ) ;
+# endif
+
+ // ERROR CHECKING
+
+ if ( Error == LB_ERR ) {
+ return FAILURE;
+ }
+
+
+ // Ignore messages when the user initiates a double click and
+ // the mouse is not in the current selection rectangle.
+
+ pt = gDLMpt ;
+ pt.x = gDLMpt.x + pHdr->xOrigin ;
+
+ if ( pHdr->fKeyDown == FALSE ) {
+
+ if ( !PtInRect ( &rectItem, pt ) ) {
+ return SUCCESS;
+ }
+ }
+
+ /* Origin of control */
+
+ /* It is known that x,y is in the rectangle */
+
+ pfnGetObjects = (GET_OBJECTS_PTR) DLM_GGetObjects( pHdr ) ;
+
+ lpObjLst = (BYTE_PTR) ( (*pfnGetObjects) (pListItem) ) ;
+ lpDispItem = DLM_GetFirstObject( lpObjLst, &bObjCnt ) ;
+
+ cxPos = (short) rectItem.left ;
+ cyPos = (short) rectItem.top ;
+
+ while (bObjCnt) {
+
+ DLM_GetRect( pWinInfo->hWndFlatList, pHdr, (LPSHORT)&cxPos, cyPos, &rectTest, lpDispItem ) ;
+
+ if ( pHdr->fKeyDown == TRUE ) {
+
+ /* Initiated by key stroke. Signal last object in string */
+
+ lpDispItem += bObjCnt-1 ;
+
+// if ( pHdr->fKeyUp == TRUE && pHdr->wKeyValue == VK_RETURN ) {
+// wLbnValue = LBN_DBLCLK ;
+// } else {
+// wLbnValue = LBN_SELCHANGE ;
+// }
+
+ wLbnValue = wCmd ;
+
+ DLM_ProcessButton( pWinInfo->hWndFlatList,
+ pHdr,
+ wLbnValue,
+ &rectTest,
+ wCurSel,
+ pListItem,
+ lpDispItem
+ ) ;
+ break ;
+ }
+
+ if ( PtInRect ( &rectTest, pt ) ) {
+ DLM_ProcessButton( pWinInfo->hWndFlatList, pHdr, wCmd, &rectTest,
+ wCurSel, pListItem, lpDispItem ) ;
+ break ;
+ }
+
+ lpDispItem++;
+ bObjCnt--;
+ }
+
+ return SUCCESS;
+ break ;
+
+ case LBN_SETFOCUS :
+
+ pHdr->fFocus = TRUE ;
+
+ break ;
+
+ case LBN_KILLFOCUS :
+
+ pHdr->fFocus = FALSE ;
+
+ break ;
+
+ }
+ }
+
+ return TRUE ;
+}
+
+
+/****************************************************************************
+
+ Name: DLM_ProcessButton
+
+ Description: This function will process a mouse action.
+ in the list.
+
+ Modified: 2/15/1991
+
+ Returns: Always 0.
+
+****************************************************************************/
+
+WORD DLM_ProcessButton(
+
+HWND hWnd , // I - Handle of listbox.
+DLM_HEADER_PTR pHdr , // I - Pointer to DLM header of listbox.
+WORD msg , // I - Windows Message
+LPRECT lpRect , // I - Pointer to rectangle on screen.
+USHORT wCurSel , // I - Listbox's current selection.
+LMHANDLE pListItem , // I - Pointer to the item.
+DLM_ITEM_PTR lpDispItem ) // I - Information on how to display item.
+
+{
+ BYTE fSelect ;
+ RECT rect ;
+ WORD wStatus ;
+
+ GET_SELECT_PTR pfnGetSelect ;
+ SET_SELECT_PTR pfnSetSelect ;
+ SET_OBJECTS_PTR pfnSetObjects ;
+
+ DBG_UNREFERENCED_PARAMETER ( wCurSel );
+
+ wStatus = 0 ;
+
+ // Must be valid window.
+
+ if ( !IsWindow( hWnd ) ) {
+ return SUCCESS;
+ }
+
+ // DLM display header must be defined.
+
+ if ( !pHdr ) {
+ return SUCCESS;
+ }
+
+
+ switch( msg ) {
+
+ case LBN_SELCHANGE:
+
+ switch ( DLM_ItembType( lpDispItem) ) {
+
+ case DLM_CHECKBOX:
+
+ /* Toggle the select status by:
+
+ Reset the select status of item.
+ Invalidate the item's region on screen.
+ */
+
+ pfnGetSelect = DLM_GGetSelect( pHdr ) ;
+
+ fSelect = (BYTE) ( (*pfnGetSelect) (pListItem ) ) ;
+ if (fSelect) fSelect = 0 ;
+ else fSelect = 1 ;
+
+ pfnSetSelect = DLM_GSetSelect( pHdr ) ;
+ wStatus = (WORD) ( (*pfnSetSelect) (pListItem, fSelect ) ) ;
+
+ memcpy( &rect, lpRect, sizeof ( RECT ) ) ;
+
+ rect.left -= pHdr->xOrigin ;
+
+ InvalidateRect ( hWnd, &rect, FALSE ) ;
+
+ wStatus = 1 ;
+
+ break ;
+
+ case DLM_BITMAP:
+ case DLM_TEXT_ONLY:
+ default:
+ wStatus = 1 ;
+ break ;
+ }
+
+ if (wStatus) {
+ pfnSetObjects = DLM_GSetObjects( pHdr ) ;
+
+ (*pfnSetObjects) (pListItem, (WORD) WM_DLMDOWN,
+ (BYTE) lpDispItem->cbNum ) ;
+ }
+
+ break ;
+
+
+ case LBN_DBLCLK :
+
+
+ switch ( DLM_ItembType( lpDispItem) ) {
+
+ case DLM_CHECKBOX:
+
+ break ;
+
+
+ case DLM_BITMAP :
+ case DLM_TEXT_ONLY :
+ default :
+
+ pfnSetObjects = DLM_GSetObjects( pHdr ) ;
+
+ (*pfnSetObjects) (pListItem, (WORD) WM_DLMDBCLK,
+ (BYTE) lpDispItem->cbNum ) ;
+
+ break ;
+ }
+
+
+ }
+
+ return SUCCESS;
+}
+
+
+
+/******************************************************************************
+
+ Name: DLM_GetFirstObject
+
+ Description: This function will return the address of the first object
+ associated with an item in a list box.
+ in the list.
+
+ Modified: 12/16/1991
+
+ Notes: The user provides an array of objects in the following
+ format:
+
+ Number of objects: 1 byte.
+ Number of DWORDs to
+ describe level detail 1 byte.
+ DWORDS .......
+ Object definition # 1 .......
+ Object definition # 2 .......
+ .......
+ Object definition # n .......
+
+
+
+
+ Returns: Pointer to Object definition #1.
+
+****************************************************************************/
+
+
+DLM_ITEM_PTR DLM_GetFirstObject(
+
+LPBYTE lpObjLst , // Pointer to array
+LPBYTE bpObjCnt ) // Pointer to object counter.
+
+{
+ BYTE bNumDwords ;
+ DLM_ITEM_PTR lpDispItem ;
+
+ // Set the Count of objects.
+
+ *bpObjCnt = *lpObjLst ;
+
+ bNumDwords = *(lpObjLst+1) ;
+
+ // The number of DWORDS must never be 0. It is an error if so.
+
+ if ( bNumDwords == 0 ) {
+ bNumDwords++ ;
+ }
+
+ if ( bNumDwords == 2 ) {
+ bNumDwords++ ;
+ bNumDwords-- ;
+ }
+
+ lpDispItem = (DLM_ITEM_PTR) ( lpObjLst + 2 + (bNumDwords) * sizeof( DWORD ) );
+
+ return( lpDispItem ) ;
+}
diff --git a/private/utils/ntbackup/src/dlm_proc.c b/private/utils/ntbackup/src/dlm_proc.c
new file mode 100644
index 000000000..fc895f21e
--- /dev/null
+++ b/private/utils/ntbackup/src/dlm_proc.c
@@ -0,0 +1,969 @@
+/****************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+ Name: wmupdate.c
+
+ Description: This file contains routines for display list manager.
+
+ The following routines are in this module:
+
+
+ DLM_DispListModeSet
+ DLM_DispListModeGet
+ DLM_DispListProc
+ DLM_WMTrackPoint
+ DLM_CursorInCheckBox
+ DLM_SetHorizontalExt
+
+ $Log: G:/UI/LOGFILES/DLM_PROC.C_V $
+
+ Rev 1.28 25 Oct 1993 10:54:38 GLENN
+Changed calloc casting - LPWORD to LPINT.
+
+ Rev 1.27 20 Aug 1993 08:56:10 GLENN
+Fixed multi to single column selection restoring problem for NT.
+
+ Rev 1.26 02 Aug 1993 15:07:42 GLENN
+Putting old items into new list box only if there were any.
+
+ Rev 1.25 13 Jul 1993 11:06:54 MIKEP
+fix item count on init.
+
+ Rev 1.24 15 Jun 1993 10:56:10 MIKEP
+enable c++
+
+ Rev 1.23 14 Jun 1993 20:19:22 MIKEP
+enable c++
+
+ Rev 1.22 25 Feb 1993 13:24:46 STEVEN
+fixes from mikep and MSOFT
+
+ Rev 1.21 11 Dec 1992 18:25:00 GLENN
+Added selection frame rectangle support based on horizontal extent of a list box.
+
+ Rev 1.20 07 Oct 1992 13:47:10 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.19 04 Oct 1992 19:33:08 DAVEV
+Unicode Awk pass
+
+ Rev 1.18 09 Sep 1992 16:13:26 GLENN
+Updated castings for MikeP (NT).
+
+ Rev 1.17 08 Sep 1992 11:52:28 ROBG
+Changed cxPos, cyPos from USHORT to short.
+
+ Rev 1.16 29 Jul 1992 14:14:00 GLENN
+ChuckB checked in after NT fixes.
+
+ Rev 1.15 10 Jun 1992 11:02:16 STEVEN
+NULL would not compile for mips
+
+ Rev 1.14 15 May 1992 13:32:44 MIKEP
+nt pass 2
+
+ Rev 1.13 20 Mar 1992 09:30:34 ROBG
+Added logic in DLM_SetHorizontalExtent to set maximum extent value in
+DLM header area.
+
+ Rev 1.12 19 Mar 1992 09:21:32 ROBG
+Added DLM_SetHorizontalExt to set Horz scroll bar
+
+ Rev 1.11 03 Mar 1992 18:21:16 GLENN
+Put in error handling.
+
+ Rev 1.10 07 Feb 1992 16:09:36 STEVEN
+fix casting of errors from sendmessage to WORD
+
+ Rev 1.9 06 Feb 1992 12:53:16 STEVEN
+fix typo in NT ifdef"
+
+ Rev 1.8 04 Feb 1992 16:07:36 STEVEN
+various bug fixes for NT
+
+ Rev 1.7 15 Jan 1992 15:16:10 DAVEV
+16/32 bit port-2nd pass
+
+ Rev 1.6 26 Dec 1991 17:21:04 ROBG
+New and Improved.
+
+ Rev 1.5 10 Dec 1991 12:58:24 GLENN
+Added window manager macros. msasserts(). Fixed DLM_DispListModeSet() to
+set the active window on creation of new window and eliminated unnecessary
+check for a non-null application pointer.
+
+ Rev 1.4 03 Dec 1991 13:21:50 DAVEV
+Modifications for 16/32-bit Windows port - 1st pass.
+
+
+ Rev 1.3 02 Dec 1991 11:09:14 ROBG
+Modified error returns in DLM_CursorInCheckBox to be 0 for FALSE.
+
+ Rev 1.2 26 Nov 1991 17:36:48 ROBG
+Fixed problem with cursor in checkbox.
+
+ Rev 1.1 26 Nov 1991 15:56:08 ROBG
+Added validity checks for the window handle, info structure, and the
+dlm display header.
+
+ Rev 1.0 20 Nov 1991 19:25:36 SYSTEM
+Initial revision.
+
+****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+/****************************************************************************
+
+ Name: DLM_DispListProc
+
+ Description: This function activates the display list manager working
+ on a window.
+
+ Modified: 2/07/1991
+
+ Returns: 0 if successful.
+
+ Valid error returns:
+
+ DLMERR_PROCESS_FAILED
+
+ Notes:
+
+****************************************************************************/
+
+WORD DLM_DispListProc(
+HWND hWndLB , // I - Handle of listbox.
+WORD iAnchorIndex , // I - Integer index to identify anchor.
+LMHANDLE dhAnchorAddr ) // I - Address of item that is to be the anchor.
+
+{
+ DLM_HEADER_PTR pHdr ;
+ LMHANDLE pdsListHdr ;
+ PDS_WMINFO pWinInfo ;
+
+ USHORT usCnt ;
+ LMHANDLE pListItem = (LMHANDLE)0;
+
+ GET_COUNT_PTR pfnGetItemCount ;
+ GET_FIRST_PTR pfnGetFirstItem ;
+ GET_NEXT_PTR pfnGetNext ;
+
+ DWORD dwStatus ;
+
+ // Must be valid window.
+
+ if ( !IsWindow( hWndLB ) ) {
+ return( 0 ) ;
+ }
+
+ pHdr = DLM_GetDispHdr( hWndLB ) ;
+
+ // DLM display header must be defined.
+
+ msassert ( pHdr != (VOID_PTR)NULL );
+
+ if ( DLM_GMode( pHdr ) == DLM_MULTICOLUMN ) {
+
+ dwStatus = SendMessage (hWndLB, LB_SETCOLUMNWIDTH, pHdr->cxColWidth, 0L ) ;
+ }
+
+ pWinInfo = WM_GetInfoPtr( GetParent( hWndLB ) ) ;
+
+ // Extra Bytes for window must be defined.
+
+ msassert ( pWinInfo != (VOID_PTR)NULL );
+
+ switch ( DLM_GMode( pHdr ) ) {
+
+ case DLM_HIERARCHICAL :
+ pdsListHdr = ( LMHANDLE ) WMDS_GetTreeList ( pWinInfo );
+ break ;
+
+ default :
+
+ pdsListHdr = ( LMHANDLE ) WMDS_GetFlatList ( pWinInfo );
+ break ;
+ }
+
+ pfnGetItemCount = (GET_COUNT_PTR) DLM_GGetItemCount( pHdr ) ;
+ pfnGetFirstItem = (GET_FIRST_PTR) DLM_GGetFirstItem( pHdr ) ;
+ pfnGetNext = (GET_NEXT_PTR) DLM_GGetNext ( pHdr ) ;
+
+ usCnt = (USHORT) ( (*pfnGetItemCount) (pdsListHdr) );
+
+ pHdr->usItemCount = usCnt ; // update item count.
+
+ if ( usCnt ) {
+ pListItem = (LMHANDLE) ( (*pfnGetFirstItem) (pdsListHdr) ) ;
+ }
+
+ dwStatus = SendMessage ( hWndLB, WM_SETREDRAW, FALSE, 0L ) ;
+
+ DLM_SetHorizontalExt( hWndLB, pHdr, pListItem ) ;
+
+ while ( pListItem && ( usCnt > 0 ) ) {
+
+ dwStatus = SendMessage( hWndLB, LB_ADDSTRING, 0, (LONG) pListItem ) ;
+
+ if ( !dwStatus ) {
+ dwStatus = 0 ;
+ }
+
+ pListItem = (LMHANDLE) ( (*pfnGetNext) (pListItem) ) ;
+ usCnt--;
+ }
+
+ dwStatus = SendMessage ( hWndLB, WM_SETREDRAW, TRUE, 0L ) ;
+
+ InvalidateRect ( hWndLB, NULL, TRUE ) ;
+
+ UpdateWindow ( hWndLB ) ;
+ SetFocus ( hWndLB ) ;
+ DLM_SetAnchor( hWndLB, iAnchorIndex, dhAnchorAddr ) ;
+ SendMessage( hWndLB, LB_SETTOPINDEX, 0, 0L ) ;
+
+ return( 0 ) ;
+}
+
+/****************************************************************************
+
+ Name: DLM_SetHorizontalExt
+
+ Description: This function gets the horizontal extent for
+ a single column listbox with items, based on
+ the first item.
+
+ Modified: 3/18/1992
+
+ Returns: VOID
+
+****************************************************************************/
+
+VOID DLM_SetHorizontalExt(
+
+HWND hWndCtl , // I - Handle of listbox.
+DLM_HEADER_PTR pHdr , // I - Pointer to DLM header.
+PVOID pListItem ) // I - Address of item.
+
+{
+ // If there is no window handle, header or list item, bug out.
+
+ if ( ! hWndCtl || ! pHdr || ! pListItem ) {
+ return;
+ }
+
+ if ( DLM_GMode( pHdr ) == DLM_SINGLECOLUMN ) {
+
+ BYTE_PTR lpObjLst ;
+ DLM_ITEM_PTR lpDispItem ;
+ BYTE bObjCnt ;
+ short cxPos ;
+ GET_OBJECTS_PTR pfnGetObjects ;
+ INT iStatus ;
+
+ pfnGetObjects = DLM_GGetObjects ( pHdr ) ;
+ lpObjLst = (BYTE_PTR) ( (*pfnGetObjects) ( (LMHANDLE) pListItem ) ) ;
+ lpDispItem = DLM_GetFirstObject( lpObjLst, &bObjCnt ) ;
+
+ // Calculate the width by spanning
+ // the object list, adding up the widths
+ // of the objects.
+
+ cxPos = 0 ;
+
+ while ( bObjCnt ) {
+
+ DLM_GetWidth ( hWndCtl, pHdr, (LPSHORT)&cxPos, lpDispItem ) ;
+ lpDispItem++;
+ bObjCnt--;
+ }
+
+ // Added left and right 2 pixel area for focus and add 5 for right margin
+
+ if ( cxPos > (short) pHdr->wHorizontalExtent ) {
+
+ pHdr->wHorizontalExtent = cxPos ;
+ iStatus = (INT) SendMessage( hWndCtl, LB_SETHORIZONTALEXTENT, cxPos+4+5, 0L ) ;
+ }
+ }
+ else {
+
+ pHdr->wHorizontalExtent = pHdr->cxColWidth;
+ }
+
+}
+
+
+/****************************************************************************
+
+ Name: DLM_DispListModeGet
+
+ Description: This function gets the mode that the display list is in.
+
+ Modified: 2/07/1991
+
+ Returns: 0 if successful.
+
+ Valid error returns:
+
+ DLMERR_LIST_NOT_FOUND
+
+ Notes:
+
+ See also: DLM_DispListModeSet()
+
+****************************************************************************/
+
+WORD DLM_DispListModeGet(
+
+HWND hWnd , // I - Handle of parent window of listbox.
+BYTE bType , // I - Type of list ( Tree or Flat ).
+LPBYTE lpbMode ) // I - Mode of list.
+
+{
+ WORD wStatus ;
+ DLM_HEADER_PTR pHdr ;
+ PDS_WMINFO pWinInfo ;
+
+ wStatus = 0 ;
+
+ // Must be valid window.
+
+ if ( !IsWindow( hWnd ) ) {
+ return( DLMERR_LIST_NOT_FOUND ) ;
+ }
+
+
+ pWinInfo = WM_GetInfoPtr( hWnd ) ;
+
+ // Extra Bytes for window must be defined.
+
+ msassert ( pWinInfo != (VOID_PTR)NULL );
+
+ switch ( bType ) {
+
+ case DLM_TREELISTBOX :
+
+ pHdr = WMDS_GetTreeDisp ( pWinInfo );
+ break ;
+
+ case DLM_FLATLISTBOX :
+ default :
+
+ pHdr = WMDS_GetFlatDisp ( pWinInfo );
+ break ;
+
+ }
+
+ if ( pHdr ) {
+ *lpbMode = DLM_GMode( pHdr ) ;
+ } else {
+ wStatus = DLMERR_LIST_NOT_FOUND ;
+ }
+
+ return( wStatus ) ;
+
+}
+
+
+
+/****************************************************************************
+
+ Name: DLM_DispListModeSet
+
+ Description: This function sets the mode that the display list is in.
+
+ Modes can be one of the following:
+
+ DLM_SINGLECOLUMN
+ DLM_MULTICOLUMN
+ DLM_HIERARCHICAL
+
+
+ Modified: 2/07/1991
+
+ Returns: 0 if successful.
+
+ Valid error returns:
+
+ DLMERR_LIST_NOT_FOUND
+
+ Notes:
+ This function only supports DLM_SMALL_BITMAPS displays.
+
+ If the new mode is DLM_SINGLECOLUMN and the existing
+ mode is DLM_MULTICOLUMN, then
+ the listbox is switched to a single column list box.
+
+ If the new mode is DLM_MULTICOLUMN and
+ the existing mode is DLM_SINGLECOLUMN, then
+ the listbox is switched to a multicolumn list box.
+
+ if the old mode or new mode is DLM_HIERARCHICAL, nothing
+ is done.
+
+
+
+ See also:
+
+****************************************************************************/
+
+WORD DLM_DispListModeSet(
+
+HWND hWnd , // I - Handle of parent window of listbox.
+BYTE bType , // I - Type of list ( Tree or Flat ).
+BYTE bMode ) // I - Mode of list.
+
+{
+
+ WORD wStatus ;
+ INT i ;
+ RECT ChildRect ;
+ INT nSelCnt ;
+ WORD wTopIndex ;
+ LPINT pnSelArray ;
+ DLM_HEADER_PTR pHdr ;
+ BYTE fMultiCol ;
+ BYTE fTreeList ;
+ PDS_WMINFO pWinInfo ;
+ HWND hWndNewList ;
+ LMHANDLE pdsListHdr ;
+ BYTE bControlID ;
+ USHORT usCnt ;
+ LMHANDLE pListItem ;
+ HWND hWndLB ;
+ HWND hWndFocus ;
+ HWND hWndActive ;
+
+ GET_COUNT_PTR pfnGetItemCount ;
+ GET_FIRST_PTR pfnGetFirstItem ;
+ GET_NEXT_PTR pfnGetNext ;
+ MP2 mp2 ;
+ POINT Point;
+
+ wStatus = 0 ;
+
+ // Must be valid window.
+
+ if ( !IsWindow( hWnd ) ) {
+ return( DLMERR_LIST_NOT_FOUND ) ;
+ }
+
+ pWinInfo = WM_GetInfoPtr( hWnd ) ;
+
+ // Extra Bytes for window must be defined.
+
+ msassert ( pWinInfo != (VOID_PTR)NULL );
+
+ switch ( bType ) {
+
+ case DLM_TREELISTBOX :
+
+ pHdr = WMDS_GetTreeDisp ( pWinInfo );
+ hWndLB = WMDS_GetWinTreeList ( pWinInfo );
+ bControlID = WMIDC_TREELISTBOX ;
+ fTreeList = TRUE ;
+ pdsListHdr = ( LMHANDLE ) WMDS_GetTreeList ( pWinInfo );
+
+ break ;
+
+ case DLM_FLATLISTBOX :
+ default :
+
+ pHdr = WMDS_GetFlatDisp ( pWinInfo );
+ hWndLB = WMDS_GetWinFlatList ( pWinInfo );
+ bControlID = WMIDC_FLATLISTBOX ;
+ fTreeList = FALSE ;
+ pdsListHdr = ( LMHANDLE ) WMDS_GetFlatList ( pWinInfo );
+ break ;
+
+ }
+
+ /* Exception Handling */
+
+ msassert ( pHdr != (VOID_PTR)NULL );
+
+ // Must be valid window.
+
+ if ( !IsWindow( hWndLB ) ) {
+ return( DLMERR_LIST_NOT_FOUND ) ;
+ }
+
+ if ( DLM_GDisplay( pHdr ) != DLM_SMALL_BITMAPS ) {
+ return ( 0 ) ;
+ }
+
+ if ( DLM_GMode( pHdr ) == bMode ) {
+ return( 0 ) ;
+ }
+
+ if ( ( DLM_GMode( pHdr ) != DLM_SINGLECOLUMN ) &&
+ ( DLM_GMode( pHdr ) != DLM_MULTICOLUMN ) &&
+ ( bMode != DLM_SINGLECOLUMN ) &&
+ ( bMode != DLM_MULTICOLUMN ) ) {
+ return( 0 ) ;
+ }
+
+ if ( bMode == DLM_SINGLECOLUMN ) {
+ fMultiCol = FALSE ;
+ } else {
+ fMultiCol = TRUE ;
+ }
+
+ wTopIndex = (WORD) SendMessage (hWndLB, LB_GETTOPINDEX, (MP1)0, (MP2)0 ) ;
+ nSelCnt = (INT) SendMessage (hWndLB, LB_GETSELCOUNT, (MP1)0, (MP2)0 ) ;
+
+ // Make sure that pnSelArray has at least been allocated 1 entry.
+
+ pnSelArray = (LPINT)calloc( nSelCnt+1, sizeof ( INT ) ) ;
+
+ if ( ! pnSelArray ) {
+ return FAILURE;
+ }
+
+ SendMessage ( hWndLB, LB_GETSELITEMS, (MP1)nSelCnt, (MP2) &pnSelArray[0] ) ;
+// SendMessage ( hWndLB, LB_RESETCONTENT, (MP1)0, (MP2)0 ) ;
+
+ hWndFocus = GetFocus() ;
+ hWndActive = WMDS_GetWinActiveList( pWinInfo ) ;
+
+ // Get the rectangle size of the old list box window.
+ // Adjust for the border.
+
+ GetWindowRect ( hWndLB, &ChildRect );
+
+ Point.x = ChildRect.left + 1;
+ Point.y = ChildRect.top + 1;
+
+ ScreenToClient ( hWnd, &Point );
+
+ // Trash the old window and make a new one.
+
+ DestroyWindow( hWndLB ) ;
+
+ hWndNewList = CreateWindow ( WMCLASS_LISTBOX,
+ NULL,
+ WS_BORDER |
+ ( fMultiCol ) ? WM_FLATLISTBOXMC : WM_FLATLISTBOXSC,
+ Point.x,
+ Point.y,
+ ChildRect.right - ChildRect.left - 2,
+ ChildRect.bottom - ChildRect.top - 2,
+ hWnd,
+ (HMENU)bControlID,
+ ghInst,
+ (LPSTR)NULL
+ );
+
+ if ( fMultiCol ) {
+ SendMessage ( hWndNewList, LB_SETCOLUMNWIDTH, pHdr->cxColWidth, 0L ) ;
+ }
+
+ DLM_Mode( pHdr, bMode ) ;
+
+ if ( fTreeList == TRUE ) {
+ WMDS_SetWinTreeList ( pWinInfo, hWndNewList );
+ } else {
+ WMDS_SetWinFlatList ( pWinInfo, hWndNewList );
+ }
+
+ if ( hWndActive == hWndLB ) {
+ WMDS_SetWinActiveList ( pWinInfo, hWndNewList ) ;
+ }
+
+ // Subclass the new list box for keyboard and mouse capturing.
+
+ WM_SubClassListBox ( hWndNewList );
+
+ if ( hWndFocus == hWndLB ) {
+ SetFocus( hWndNewList) ;
+ }
+
+ pHdr->wHorizontalExtent = 0 ;
+
+ pfnGetItemCount = (GET_COUNT_PTR) DLM_GGetItemCount( pHdr ) ;
+ pfnGetFirstItem = (GET_FIRST_PTR) DLM_GGetFirstItem( pHdr ) ;
+ pfnGetNext = (GET_NEXT_PTR) DLM_GGetNext ( pHdr ) ;
+
+ usCnt = (USHORT) ( (*pfnGetItemCount) (pdsListHdr) );
+
+ // Place the old items into the new list, if there were any.
+
+ if ( usCnt ) {
+
+ SendMessage ( hWndNewList, WM_SETREDRAW, FALSE, 0L ) ;
+
+ pListItem = (LMHANDLE) ( (*pfnGetFirstItem) (pdsListHdr) ) ;
+
+ DLM_SetHorizontalExt( hWndNewList, pHdr, pListItem ) ;
+
+ while ( ( pListItem ) && ( usCnt > 0 ) ) {
+
+ wStatus = (WORD) SendMessage( hWndNewList, LB_ADDSTRING, 0, (LONG) pListItem ) ;
+ pListItem = (LMHANDLE) ( (*pfnGetNext) (pListItem) ) ;
+ usCnt--;
+ }
+
+ // Process array of items to select.
+
+ for ( i = 0; i < nSelCnt; i++ ) {
+ wStatus = (WORD) SendMessage ( hWndNewList, LB_SETSEL, TRUE,
+ (MP2)pnSelArray[i] );
+ }
+
+ wStatus = (WORD) SendMessage (hWndNewList, LB_SETTOPINDEX, wTopIndex, (MP2)0 ) ;
+
+ SendMessage ( hWndNewList, WM_SETREDRAW, TRUE, 0L ) ;
+
+ InvalidateRect ( hWndNewList, NULL, TRUE ) ;
+ UpdateWindow ( hWndNewList ) ;
+ }
+
+ if ( pnSelArray ) {
+ free( pnSelArray ) ;
+ }
+
+ return SUCCESS;
+
+}
+
+/****************************************************************************
+
+ Name: DLM_WMTrackPoint
+
+ Description: This function test to see if mouse is within a validate
+ object on an item in a list box when the left button
+ is down.
+
+ Modified: 4/24/1991
+
+ Returns: 0 if mouse is over a valid object.
+ 1 if mouse is not over a valid object and the list box
+ should abort further processing.
+
+****************************************************************************/
+
+WORD DLM_WMTrackPoint(
+
+HWND hWnd , // I - Handle of parent window of listbox.
+MP1 mp1 , // I - Current selection.
+MP2 mp2 ) // I - Mouse position.
+
+{
+
+ PDS_WMINFO pWinInfo ;
+ DLM_HEADER_PTR pHdr ;
+ INT iCurSel, iOldSel, iError, iTopSel ;
+ RECT rectItem ;
+ RECT rectTest ;
+ LMHANDLE pListItem ;
+
+ short cxPos, cyPos ;
+ DLM_ITEM_PTR lpDispItem ;
+ GET_OBJECTS_PTR pfnGetObjects ;
+ SET_TAG_PTR pfnSetTag ;
+ BYTE bObjCnt ;
+ BYTE_PTR lpObjLst ;
+ POINT pt ;
+ HWND hWndLB ;
+ HWND hWndFocus = GetFocus ();
+
+ // Must be valid window.
+
+ if ( ! IsWindow ( hWnd ) ) {
+ return FAILURE;
+ }
+
+
+ pWinInfo = (PDS_WMINFO) WM_GetInfoPtr( hWnd ) ;
+
+ // Extra Bytes for window must be defined.
+
+ msassert ( pWinInfo != (VOID_PTR)NULL );
+
+
+ // If we're not in the tree list box, we don't care about this point.
+
+ if ( hWndFocus != WMDS_GetWinTreeList ( pWinInfo ) ) {
+ return SUCCESS;
+ }
+
+ hWndLB = WMDS_GetWinActiveList ( pWinInfo );
+
+ if ( hWndLB != hWndFocus ) {
+
+ // THIS SHOULD NEVER HAPPEN.
+
+ WMDS_SetWinActiveList ( pWinInfo, hWndFocus );
+ hWndLB = hWndFocus;
+ }
+
+
+ pHdr = DLM_GetDispHdr( hWndLB ) ;
+
+ // DLM display header must be defined.
+
+ msassert ( pHdr != (VOID_PTR)NULL );
+
+ /* if mouse is not over an object in the hierarchical tree, then
+ don't do anything */
+
+ // WHY DOESN'T THE CODE REFLECT THE ABOVE COMMENT.
+
+
+ iCurSel = (INT) mp1 ;
+
+ iError = (INT) SendMessage ( hWndLB, LB_GETITEMRECT, iCurSel,
+ (LONG) ( LPRECT ) &rectItem ) ;
+
+# ifdef NTKLUG
+ iError = (INT) SendMessage ( hWndLB, WM_DLMGETTEXT, iCurSel,
+ (LONG) &pListItem ) ;
+# else
+ iError = (INT) SendMessage ( hWndLB, LB_GETTEXT, iCurSel,
+ (LONG) &pListItem ) ;
+# endif
+
+ // ERROR CHECKING
+
+ if ( iError == LB_ERR ) {
+ return FAILURE;
+ }
+
+ iTopSel = (INT) SendMessage ( hWndLB, LB_GETTOPINDEX, 0,
+ (LONG) 0L ) ;
+
+ /* Origin of control */
+
+ /* It is known that x,y is in the rectangle */
+
+ pfnGetObjects = (GET_OBJECTS_PTR) DLM_GGetObjects( pHdr ) ;
+
+ lpObjLst = (BYTE_PTR) ( (*pfnGetObjects) (pListItem) ) ;
+ lpDispItem = DLM_GetFirstObject( lpObjLst, &bObjCnt ) ;
+
+ cxPos = (short) rectItem.left ;
+ cyPos = (short) rectItem.top ;
+
+ cxPos += ( ( DLM_ItembLevel( lpDispItem ) )* pHdr->cxHierTab ) ;
+
+ //pt = gDLMpt ;
+ //pt.x = gDLMpt.x + pHdr->xOrigin ;
+
+ pt.x = LOWORD( mp2 ) ; /* Has xOrigin added already */
+ pt.y = HIWORD( mp2 ) ;
+
+
+ iError = 1 ;
+
+ while (bObjCnt) {
+
+ DLM_GetRect( hWndLB, pHdr, (LPSHORT)&cxPos, cyPos, &rectTest, lpDispItem ) ;
+
+ if ( PtInRect ( &rectTest, pt ) ) {
+
+ // If the object is the check box, then
+ // process the checkbox without selecting the item.
+
+ if ( DLM_ItembType( lpDispItem) == DLM_CHECKBOX ) {
+
+ DLM_ProcessButton( hWndLB,
+ pHdr,
+ LBN_SELCHANGE,
+ &rectItem,
+ (WORD)iCurSel,
+ pListItem,
+ lpDispItem ) ;
+
+ iError = 1; // Do Not process the selection.
+ break ;
+ }
+
+ // If the list is hierarchical, then unselect tag of
+ // current selection.
+
+
+ if ( DLM_GMode( pHdr ) == DLM_HIERARCHICAL ) {
+
+ iOldSel = (INT) SendMessage ( hWndLB, LB_GETCURSEL, 0, 0L ) ;
+
+ if ( iOldSel != LB_ERR ) {
+
+ pfnSetTag = (SET_TAG_PTR) DLM_GSetTag ( pHdr ) ;
+# ifdef NTKLUG
+ iError = SendMessage ( hWndLB, WM_DLMGETTEXT, iOldSel,
+ (LONG) &pListItem ) ;
+# else
+ iError = SendMessage ( hWndLB, LB_GETTEXT, iOldSel,
+ (LONG) &pListItem ) ;
+# endif
+ (*pfnSetTag) (pListItem, 0 ) ;
+ }
+ }
+
+ iError = 0 ;
+ break ;
+ }
+
+ lpDispItem++;
+ bObjCnt--;
+ }
+
+
+ if ( iError ) {
+ iTopSel = (INT) SendMessage ( hWndLB, LB_SETTOPINDEX, iTopSel,
+ (LONG) 0L ) ;
+ }
+
+ DLM_SetTrkPtFailure( pHdr, iError ) ;
+
+ return( (WORD)iError ) ;
+}
+
+/****************************************************************************
+
+ Name: DLM_CursorInCheckBox
+
+ Description: This function test to see if mouse is within the checkbox
+ in a list box
+
+ Modified: 5/01/1991
+
+ Returns: 1 if mouse is within the checkbox.
+ 0 if mouse is not within the checkbox
+
+
+****************************************************************************/
+
+BOOL DLM_CursorInCheckBox(
+
+HWND hWndLB, // I - Handle of a listbox.
+POINT pt ) // I - Point where the mouse is currently at.
+
+{
+
+ INT wStatus ;
+ PDS_WMINFO pWinInfo ;
+ DLM_HEADER_PTR pHdr ;
+ RECT rcTest ;
+ LMHANDLE pListItem ;
+ WORD wTopIndex, wSel;
+ LRESULT SelCnt;
+ INT iError ;
+ short cxPos, cyPos ;
+ DLM_ITEM_PTR lpDispItem ;
+ GET_OBJECTS_PTR pfnGetObjects ;
+ BYTE bObjCnt ;
+ BYTE_PTR lpObjLst ;
+ POINT pt1 ;
+ RECT rcList ;
+
+ wStatus = 0 ;
+
+ // Must be valid window.
+
+ if ( !IsWindow( hWndLB ) ) {
+ return FALSE;
+ }
+
+ pWinInfo = (PDS_WMINFO) WM_GetInfoPtr( GetParent( hWndLB ) ) ;
+
+ // Extra Bytes for window must be defined.
+
+ msassert ( pWinInfo != (VOID_PTR)NULL );
+
+ pHdr = DLM_GetDispHdr( hWndLB ) ;
+
+ msassert ( pHdr != (VOID_PTR)NULL );
+
+ // Get the count of items in the LB.
+
+ SelCnt = SendMessage (hWndLB, LB_GETCOUNT, (MP1)0, (MP2)0 ) ;
+
+ if ( ! SelCnt || SelCnt == LB_ERR ) {
+
+ return FALSE;
+ }
+
+ wTopIndex = (WORD) SendMessage (hWndLB, LB_GETTOPINDEX, (MP1)0, (MP2)0 ) ;
+
+ GetClientRect ( hWndLB, &rcList ) ; /* Need listbox's bottom y position. */
+
+ pt1 = pt ;
+
+ pt1.x += (pHdr->xOrigin) ;
+
+ wSel = wTopIndex ;
+
+ while ( wSel < SelCnt ) {
+
+ iError = (INT) SendMessage ( hWndLB, LB_GETITEMRECT, wSel,
+ (LONG) ( LPRECT ) &rcTest ) ;
+
+ if ( iError == LB_ERR) {
+ break ;
+ }
+
+ if ( rcTest.top >= rcList.bottom ) {
+ break ;
+ }
+
+ if ( PtInRect ( &rcTest, pt1 ) ) {
+
+# ifdef NTKLUG
+ iError = (INT) SendMessage ( hWndLB, WM_DLMGETTEXT, wSel, (LONG) &pListItem ) ;
+# else
+ iError = (INT) SendMessage ( hWndLB, LB_GETTEXT, wSel, (LONG) &pListItem ) ;
+# endif
+
+ if ( iError == LB_ERR) {
+ break ;
+ }
+
+ /* Origin of control */
+
+ pfnGetObjects = DLM_GGetObjects( pHdr ) ;
+
+ lpObjLst = (BYTE_PTR) ( (*pfnGetObjects) (pListItem) ) ;
+ lpDispItem = DLM_GetFirstObject( lpObjLst, &bObjCnt ) ;
+
+ cxPos = (short) rcTest.left ;
+ cyPos = (short) rcTest.top ;
+
+ if ( DLM_GMode( pHdr ) == DLM_HIERARCHICAL ) {
+ cxPos += ( ( DLM_ItembLevel( lpDispItem ) )* pHdr->cxHierTab ) ;
+ }
+
+ while (bObjCnt) {
+
+ DLM_GetRect( hWndLB, pHdr, (LPSHORT)&cxPos, cyPos, &rcTest, lpDispItem ) ;
+
+ if ( DLM_ItembType( lpDispItem ) == DLM_CHECKBOX ) {
+ if ( DLM_ItemwId( lpDispItem ) ) {
+ if ( PtInRect ( &rcTest, pt1 ) ) {
+ wStatus = TRUE ;
+ break ;
+ }
+ }
+ }
+
+ lpDispItem++;
+ bObjCnt--;
+ }
+
+ break ;
+ }
+
+ wSel++;
+
+ } /* end while */
+
+ return (BOOL)wStatus;
+
+}
diff --git a/private/utils/ntbackup/src/dlm_scrn.c b/private/utils/ntbackup/src/dlm_scrn.c
new file mode 100644
index 000000000..7d384a98c
--- /dev/null
+++ b/private/utils/ntbackup/src/dlm_scrn.c
@@ -0,0 +1,868 @@
+/****************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+
+
+ Name: dlm_scrn.c
+
+ Creator: Rob Griffis
+
+ Description: This file contains routines for display list manager.
+
+ The following routines are in this module:
+
+
+ DLM_WMMeasureItem
+ DLM_GetRect
+ DLM_GetWidth
+ DLM_KeyDown
+ DLM_KeyUp
+
+ $Log: G:/UI/LOGFILES/DLM_SCRN.C_V $
+
+ Rev 1.26 15 Jun 1993 10:56:30 MIKEP
+enable c++
+
+ Rev 1.25 14 Jun 1993 20:15:12 MIKEP
+enable c++
+
+ Rev 1.24 02 Apr 1993 15:54:32 ROBG
+Changed FocusItem to be UINT for both NT and WINDOWS.
+
+ Rev 1.23 01 Nov 1992 15:46:56 DAVEV
+Unicode changes
+
+ Rev 1.22 07 Oct 1992 13:48:00 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.21 04 Oct 1992 19:33:14 DAVEV
+Unicode Awk pass
+
+ Rev 1.20 08 Sep 1992 10:39:02 ROBG
+
+ Rev 1.19 21 Aug 1992 16:01:18 ROBG
+Change to support change of font.
+
+ Rev 1.18 29 Jul 1992 14:23:44 GLENN
+ChuckB checked in after NT fixes.
+
+ Rev 1.17 07 Jul 1992 15:52:32 MIKEP
+unicode changes
+
+ Rev 1.16 15 May 1992 13:35:50 MIKEP
+nt pass 2
+
+ Rev 1.15 20 Mar 1992 17:22:54 GLENN
+Fixed VK_RETURN to work on key down instead of key up.
+
+ Rev 1.14 19 Mar 1992 15:50:30 GLENN
+Removed tabs.
+
+ Rev 1.13 09 Mar 1992 09:39:48 GLENN
+Fixed single click turning into a double click after a CR in list boxes.
+
+ Rev 1.12 03 Mar 1992 18:21:30 GLENN
+Put in error handling.
+
+ Rev 1.11 23 Feb 1992 13:50:30 GLENN
+Added check for valid list item to key char processing function.
+
+ Rev 1.10 11 Feb 1992 17:29:04 GLENN
+Changed return cast from SendMessage() from WORD to INT for NT.
+
+ Rev 1.9 06 Feb 1992 15:15:16 ROBG
+Added logic in DLM_GetWidth to add 3* average width to any
+column character count less than 5.
+
+ Rev 1.8 04 Feb 1992 16:07:46 STEVEN
+various bug fixes for NT
+
+ Rev 1.7 15 Jan 1992 15:15:16 DAVEV
+16/32 bit port-2nd pass
+
+ Rev 1.6 07 Jan 1992 17:27:46 GLENN
+Updated DLM_KeyDown().
+
+ Rev 1.5 26 Dec 1991 17:22:42 ROBG
+New and Improved.
+
+ Rev 1.4 05 Dec 1991 17:58:54 GLENN
+Changed stuff in the default case of key down.
+
+ Rev 1.3 04 Dec 1991 15:13:44 DAVEV
+Modifications for 16/32-bit Windows port - 1st pass.
+
+
+ Rev 1.2 03 Dec 1991 16:21:22 GLENN
+Added DLM_CharToItem function.
+
+ Rev 1.1 26 Nov 1991 16:12:12 ROBG
+Added validity checks for the window handles, info structure, and the
+dlm display header.
+
+ Rev 1.0 20 Nov 1991 19:31:56 SYSTEM
+Initial revision.
+
+****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+VOID DLM_ReturnKeyPressed ( HWND, DLM_HEADER_PTR, LPWORD );
+
+/****************************************************************************
+
+ Name: DLM_GetRect
+
+ Description: This function will return the rectangle of an object
+ in the list.
+
+ Modified: 2/15/1991
+
+ Returns: none
+
+****************************************************************************/
+
+void DLM_GetRect(
+
+HWND hWndCtl, // I - Handle to list box.
+DLM_HEADER_PTR pHdr , // I - Handle to DLM header for list box.
+LPSHORT pcxPos , // IO - Starting and ending of X position.
+short cyPos , // I - starting Y position.
+LPRECT lpRect , // O - Pointer to rectangle.
+DLM_ITEM_PTR lpDispItem ) // I - Pointer to display item.
+
+{
+ HDC hdc ;
+ LONG lLen ;
+ SIZE sizeRect; //dvc - for GetTextExtentEx return value
+ HANDLE hSaveObject ;
+
+ // Must be valid window.
+
+ if ( !IsWindow( hWndCtl ) ) {
+ return ;
+ }
+
+ // DLM display header must be defined.
+
+ if ( !pHdr ) {
+ return ;
+ }
+
+ switch ( DLM_ItembType( lpDispItem) ) {
+
+ case DLM_CHECKBOX:
+
+ *pcxPos += pHdr->cxBeforeCheckBox ;
+ lpRect->left = *pcxPos ;
+ lpRect->top = cyPos + pHdr->cyBeforeCheckBox ;
+ lpRect->right = lpRect->left + pHdr->cxCheckBoxWidth-1 ;
+ lpRect->bottom = lpRect->top + pHdr->cyCheckBoxHeight-1 ;
+ *pcxPos += pHdr->cxCheckBoxWidth ;
+
+ break;
+
+ case DLM_BITMAP:
+
+ *pcxPos += pHdr->cxBeforeBitMap ;
+ lpRect->left = *pcxPos ;
+ lpRect->top = cyPos + pHdr->cyBeforeBitMap ;
+ lpRect->right = lpRect->left + pHdr->cxBitMapWidth-1 ;
+ lpRect->bottom = lpRect->top + pHdr->cyBitMapHeight-1 ;
+ *pcxPos += pHdr->cxBitMapWidth ;
+
+ break ;
+
+ case DLM_TEXT_ONLY:
+ default :
+ /* If the list is not hierarchical, then assume text
+ is the last object item and return a match */
+
+ if ( DLM_GMode ( pHdr ) != DLM_HIERARCHICAL ) {
+
+ lpRect->left = 0 ;
+ lpRect->top = 0 ;
+ lpRect->right = 10000 ;
+ lpRect->bottom = 10000 ;
+
+ } else {
+
+
+ *pcxPos += pHdr->cxBeforeText ;
+ lpRect->left = *pcxPos ;
+ lpRect->top = cyPos + pHdr->cyBeforeText ;
+ *pcxPos += pHdr->cxTextWidth ; /* zero for now */
+
+ lLen = strlen( (CHAR_PTR)DLM_ItemqszString( lpDispItem ) ) ;
+
+ hdc = GetDC( hWndCtl ) ;
+
+ hSaveObject = SelectObject( hdc, ghFontIconLabels ) ;
+
+ GetTextExtentPoint( hdc, (CHAR_PTR)DLM_ItemqszString (lpDispItem ),
+ (INT) lLen, &sizeRect ) ;
+
+ hSaveObject = SelectObject ( hdc, hSaveObject ) ;
+
+ ReleaseDC( hWndCtl, hdc ) ;
+
+ lpRect->right = lpRect->left + sizeRect.cx + 1 ;
+
+ lpRect->bottom = lpRect->top + pHdr->cyTextHeight-1 ;
+
+ *pcxPos += pHdr->cxTextWidth ;
+
+ if ( DLM_GMode( pHdr ) == DLM_HIERARCHICAL ) {
+ lpRect->top += (mwDLMInflate);
+ lpRect->top += (mwDLMInflate);
+ lpRect->bottom += -(mwDLMInflate);
+ lpRect->bottom += -(mwDLMInflate);
+ }
+
+
+ }
+ }
+
+
+ lpRect->left += -(mwDLMInflate); /* Offset by 2 - look at wmdraw.c */
+ lpRect->top += -(mwDLMInflate); /* Offset by 2 - look at wmdraw.c */
+ lpRect->right += -(mwDLMInflate); /* Offset by 2 - look at wmdraw.c */
+ lpRect->bottom += -(mwDLMInflate); /* Offset by 2 - look at wmdraw.c */
+
+
+}
+
+/****************************************************************************
+
+ Name: DLM_GetWidth
+
+ Description: This function will return the width of an object
+ in the list.
+
+ Modified: 12/19/1991
+
+ Returns: The contents of pcxPos is updated.
+
+****************************************************************************/
+
+void DLM_GetWidth (
+
+HWND hWndCtl, // I - Handle to list box.
+DLM_HEADER_PTR pHdr , // I - Handle to DLM header for list box.
+LPSHORT pcxPos , // I/O - Starting and ending of X position.
+DLM_ITEM_PTR lpDispItem ) // I - Pointer to display item.
+
+{
+
+ // Must be valid window.
+
+ if ( !IsWindow( hWndCtl ) ) {
+ return ;
+ }
+
+ // DLM display header must be defined.
+
+ if ( !pHdr ) {
+ return ;
+ }
+
+ switch ( DLM_ItembType( lpDispItem) ) {
+
+ case DLM_CHECKBOX:
+
+ *pcxPos += ( pHdr->cxBeforeCheckBox +
+ pHdr->cxCheckBoxWidth ) ;
+
+ break;
+
+ case DLM_BITMAP:
+
+ *pcxPos += ( pHdr->cxBeforeBitMap +
+ pHdr->cxBitMapWidth ) ;
+ break ;
+
+ case DLM_TEXT_ONLY:
+ default :
+
+ // Create a little more space for strings less than 5 characters long.
+ // Same logic in dlm_draw.c when the items are drawn.
+
+ if ( ( (int) DLM_ItembMaxTextLen( lpDispItem ) > 0 ) &&
+ ( (int) DLM_ItembMaxTextLen( lpDispItem ) < 5 ) &&
+ ( DLM_GDisplay( pHdr) == DLM_SMALL_BITMAPS ) ) {
+
+ *pcxPos += pHdr->cxTextWidth ;
+ }
+
+ *pcxPos += ( pHdr->cxBeforeText +
+ ( DLM_ItembMaxTextLen( lpDispItem )*( pHdr->cxTextWidth ) ) ) ;
+
+ }
+
+}
+
+
+
+/****************************************************************************
+
+ Name: DLM_SetAnchor
+
+ Description: This function set the anchor point in a listbox.
+
+ Modified: 2/07/1991
+
+ Returns: TRUE if processed key.
+
+****************************************************************************/
+
+
+WORD DLM_SetAnchor (
+
+HWND hWndCtl , // I - Handle of a listbox.
+WORD iAnchorItem , // I - Integer value of item to be anchor pt.
+LMHANDLE dhAnchorItem ) // I - Address of item to be anchor pt.
+
+{
+ INT nStatus ;
+ INT nCurSel, nOldSel, nError ;
+ DLM_HEADER_PTR pdsHdr ;
+ SET_TAG_PTR pfnSetTag ;
+ LMHANDLE pListItem ;
+
+ // Must be valid window.
+
+ if ( !IsWindow( hWndCtl ) ) {
+ return TRUE ;
+ }
+
+ pdsHdr = DLM_GetDispHdr ( hWndCtl ) ;
+
+ // DLM display header must be defined.
+
+ if ( !pdsHdr ) {
+ return TRUE ;
+ }
+
+
+ pdsHdr->dhAnchorItem = dhAnchorItem ;
+ pdsHdr->iAnchorItem = iAnchorItem ;
+
+ /* Find it in the list. Usually the first item. */
+
+ if ( pdsHdr->dhAnchorItem ) {
+
+ nCurSel = (INT) SendMessage ( hWndCtl, LB_FINDSTRING, (MP1)-1, (LONG) dhAnchorItem ) ;
+
+ if ( nCurSel != LB_ERR ) {
+
+ if ( DLM_GMode( pdsHdr ) != DLM_HIERARCHICAL ) {
+
+ /* Check to see if item is displayed on the screen
+ ** If entire item is not found on the display, then
+ ** make it the top of the list displayed.
+ */
+
+ HDC hDC ;
+ RECT dsRect ;
+ POINT pt1 ;
+ POINT pt2 ;
+
+ hDC = GetDC( hWndCtl ) ;
+
+ nStatus = (INT) SendMessage ( hWndCtl, LB_GETITEMRECT, nCurSel, (LONG) &dsRect ) ;
+
+ pt1.x = dsRect.left ;
+ pt1.y = dsRect.top ;
+ pt2.x = dsRect.right ;
+ pt2.y = dsRect.bottom ;
+
+ if ( !PtVisible ( hDC, pt1.x, pt1.y ) ||
+ !PtVisible ( hDC, pt2.x, pt2.y ) ) {
+
+ // Set the item to top selection.
+
+ nStatus = (INT) SendMessage( hWndCtl, LB_SETTOPINDEX, nCurSel, 0 ) ;
+
+ }
+
+ ReleaseDC( hWndCtl, hDC ) ;
+
+ nStatus = (INT) SendMessage ( hWndCtl, LB_SETSEL, 0, -1 );
+ nStatus = (INT) SendMessage ( hWndCtl, LB_SETSEL, 1, nCurSel );
+
+ } else {
+
+ /* Reset tag field if new selection */
+
+ nOldSel = (INT) SendMessage ( hWndCtl, LB_GETCURSEL, 0, 0L ) ;
+
+ if ( ( nOldSel != LB_ERR ) && (nOldSel != nCurSel) ) {
+
+ pfnSetTag = (SET_TAG_PTR) DLM_GSetTag ( pdsHdr ) ;
+# ifdef NTKLUG
+ nError = (INT) SendMessage ( hWndCtl, WM_DLMGETTEXT, nOldSel,
+ (LONG) &pListItem ) ;
+# else
+ nError = (INT) SendMessage ( hWndCtl, LB_GETTEXT, nOldSel,
+ (LONG) &pListItem ) ;
+# endif
+ (*pfnSetTag) (pListItem, 0 ) ;
+ }
+
+ pdsHdr->cLastTreeSelect = (USHORT) nCurSel ;
+
+ nStatus = (INT) SendMessage( hWndCtl, LB_SETCURSEL, nCurSel, 0L ) ;
+ }
+
+ } else {
+ return ( DLMERR_PROCESS_FAILED ) ;
+ }
+
+
+ } else {
+
+ /* iAnchorItem must be between 0 and the count in listbox */
+
+ if ( DLM_GMode( pdsHdr ) == DLM_COLUMN_VECTOR ) {
+
+ nStatus = (INT) SendMessage (hWndCtl, LB_SETSEL, 1, iAnchorItem );
+
+ } else {
+
+ if ( DLM_GMode( pdsHdr ) == DLM_HIERARCHICAL ) {
+ pdsHdr->cLastTreeSelect = iAnchorItem ;
+ }
+
+ nStatus = (INT) SendMessage( hWndCtl, LB_SETCURSEL, iAnchorItem, 0L ) ;
+ }
+
+ }
+
+}
+
+
+/****************************************************************************
+
+ Name: DLM_KeyDown
+
+ Description: This function processes the tab key
+ key.
+
+ Modified: 2/07/1991
+
+ Returns: TRUE if processed key.
+
+
+****************************************************************************/
+
+BOOL DLM_KeyDown(
+
+HWND hWndCtl , // I - Handle of Listbox.
+LPWORD pwKey , // IO - Value of key
+MP2 mp2 ) // I - Ignored at this time.
+
+{
+
+ WORD fKeyUsed ;
+ HWND hParentWnd ;
+ PDS_WMINFO pWinInfo ;
+ DLM_HEADER_PTR pHdr ;
+
+ UNREFERENCED_PARAMETER ( mp2 );
+
+ fKeyUsed = FALSE ;
+
+
+ hParentWnd = GetParent( hWndCtl ) ;
+ pWinInfo = (PDS_WMINFO) WM_GetInfoPtr( hParentWnd ) ;
+ pHdr = DLM_GetDispHdr( hWndCtl ) ;
+
+ // Must be valid window.
+
+ if ( !IsWindow( hWndCtl ) ) {
+ return TRUE ;
+ }
+
+ // Extra Bytes for window must be defined.
+
+ if ( !pWinInfo ) {
+ return TRUE ;
+ }
+
+ // DLM display header must be defined.
+
+ if ( !pHdr ) {
+ return TRUE ;
+ }
+
+
+ switch ( *pwKey ) {
+
+ case VK_TAB :
+
+ /* If both exists, then reset focus */
+
+ if ( (pWinInfo->hWndTreeList ) && (pWinInfo->hWndFlatList) &&
+ (pWinInfo->pTreeDisp ) && (pWinInfo->pFlatDisp ) ) {
+
+ if (hWndCtl == pWinInfo->hWndTreeList) {
+ SetFocus ( pWinInfo->hWndFlatList ) ;
+ } else {
+ SetFocus ( pWinInfo->hWndTreeList ) ;
+ }
+ }
+
+ fKeyUsed = TRUE ;
+ break ;
+
+ case VK_RETURN :
+
+ DLM_ReturnKeyPressed ( hWndCtl, pHdr, pwKey );
+ break ;
+
+ case VK_SPACE :
+
+ DLM_SpaceBarPressed ( hWndCtl, pHdr, pwKey ) ;
+ break;
+
+ case VK_HOME :
+ case VK_END :
+ case VK_NEXT :
+ case VK_LEFT :
+ case VK_RIGHT :
+ case VK_UP :
+ case VK_DOWN :
+ case VK_PRIOR :
+ case VK_CONTROL :
+ case VK_SHIFT :
+ pHdr->wKeyValue = *pwKey ;
+ pHdr->fKeyDown = TRUE ;
+ break ;
+
+ default:
+
+ if ( DLM_CharToItem ( hWndCtl, pHdr, pwKey ) ) {
+ pHdr->wKeyValue = *pwKey ;
+ pHdr->fKeyDown = TRUE ;
+ fKeyUsed = TRUE ;
+ }
+
+ break ;
+
+ } /* end switch */
+
+ return ( fKeyUsed ) ;
+
+}
+
+
+/****************************************************************************
+
+ Name: DLM_KeyUp
+
+ Description: This function processes the WM_KEYUP messages
+
+ Modified: 2/07/1991
+
+ Returns: TRUE if processed key.
+
+****************************************************************************/
+
+BOOL DLM_KeyUp(
+
+HWND hWndCtl, // I - Handle of Listbox.
+LPWORD pwKey , // IO - Value of key
+MP2 mp2 ) // I - Ignored at this time.
+
+{
+ DLM_HEADER_PTR pHdr;
+ MP1 mpSend1;
+ MP2 mpSend2;
+ BOOL fKeyUsed = FALSE;
+ static BOOL fSemProcessing = FALSE; // sem to eliminate recursion.
+
+ UNREFERENCED_PARAMETER ( mp2 );
+
+ // THIS IS THE WRONG WAY TO DO IT, BUT, HEY, IT'S TOO LATE TO DO IT RIGHT.
+ // THE VLM IS CALLING A DIALOG IN THE MIDDLE OF THIS CALL TO TRY TO
+ // ATTACH TO A FILE SERVER. THIS TYPE OF PROCESSING SHOULD BE DONE
+ // WITH A POST MESSAGE OR SIMILAR -- BY THE VLM.
+
+ if ( fSemProcessing ) {
+ return TRUE;
+ }
+
+ // Must be valid window.
+
+ if ( ! IsWindow( hWndCtl ) ) {
+ return TRUE;
+ }
+
+ pHdr = DLM_GetDispHdr( hWndCtl );
+
+ // DLM display header must be defined and the key must be down.
+
+ if ( ( ! pHdr ) || ( ! pHdr->fKeyDown ) ) {
+ return TRUE;
+ }
+
+ fSemProcessing = TRUE;
+
+ // If this is a tree list box, we want to send the list box the key
+ // up message directly and not let the default list box process the
+ // message.
+
+ if ( pHdr->wKeyValue == *pwKey ) {
+
+ PDS_WMINFO pWinInfo;
+ WORD wListBoxIDC;
+
+ pWinInfo = (PDS_WMINFO) WM_GetInfoPtr ( GetParent ( hWndCtl ) );
+
+ if ( WMDS_GetWinActiveList ( pWinInfo ) == WMDS_GetWinTreeList ( pWinInfo ) ) {
+ wListBoxIDC = WMIDC_TREELISTBOX;
+ }
+ else {
+ wListBoxIDC = WMIDC_FLATLISTBOX;
+ }
+
+ pHdr->fKeyUp = TRUE;
+
+ SET_WM_COMMAND_PARAMS( wListBoxIDC, LBN_SELCHANGE, hWndCtl, mpSend1, mpSend2 );
+
+ DLM_LBNmessages ( GetParent ( hWndCtl), mpSend1, mpSend2 );
+
+ pHdr->fKeyDown = FALSE;
+ pHdr->fKeyUp = FALSE;
+ pHdr->wKeyValue = 0;
+
+ fKeyUsed = TRUE;
+
+ }
+
+ // Translate the return key to back to a space for the list box.
+
+ if ( *pwKey == VK_RETURN ) {
+
+ *pwKey = (WORD) VK_SPACE;
+ fKeyUsed = FALSE;
+ }
+
+ fSemProcessing = FALSE;
+
+ return fKeyUsed;
+
+}
+
+
+/****************************************************************************
+
+ Name: DLM_ScrollListBox()
+
+ Description: This function scrolls a list box using the type of scroll
+ specified.
+
+ SCROLL TYPE
+ -----------
+ DBM_SCROLLTOP Scrolls to the top of the list box
+ DBM_SCROLLBOTTOM Scrolls to the bottom of the list box
+
+ Returns: Nothing.
+
+****************************************************************************/
+
+VOID DLM_ScrollListBox (
+
+HWND hWnd, // I - handle of the list box window to scroll
+WORD wType ) // I - the type of scrolling to be done
+
+{
+
+ // Must be valid window.
+
+ if ( !IsWindow( hWnd ) ) {
+ return;
+ }
+
+ SEND_WM_VSCROLL_MSG ( hWnd, wType, 0, NULL );
+ SEND_WM_VSCROLL_MSG ( hWnd, SB_ENDSCROLL, 1, NULL );
+
+} /* end DLM_ScrollListBox() */
+
+
+/****************************************************************************
+GSH
+ Name: DLM_SpaceBarPressed()
+
+ Description: This function processes the space bar by checking or
+ unchecking the item in focus, then tagging and setting
+ the focus of the next item in the list.
+
+ Returns: Nothing.
+
+****************************************************************************/
+
+VOID DLM_SpaceBarPressed (
+
+HWND hWndListBox, // I - handle to the list box window.
+DLM_HEADER_PTR pHdr, // I - pointer to the header of the list to use.
+LPWORD pwKey ) // IO - pointer to the key value.
+
+{
+ BYTE fSelect;
+ RECT rcTemp;
+ GET_SELECT_PTR pfnGetSelect;
+ SET_SELECT_PTR pfnSetSelect;
+ LMHANDLE pListItem;
+
+
+ // Set the key information being careful to change the space key to
+ // to a down-arrow key to the list box so that the next item in the
+ // list gets highlighted (tagged).
+
+ pHdr->wKeyValue = *pwKey;
+ pHdr->fKeyDown = TRUE;
+ *pwKey = VK_DOWN;
+
+ // Get the list item handle.
+
+ pListItem = (LMHANDLE)SendMessage ( hWndListBox,
+ LB_GETITEMDATA,
+ pHdr->unFocusItem,
+ 0L
+ );
+
+ // Get the select callback functions.
+
+ pfnGetSelect = DLM_GGetSelect ( pHdr );
+ pfnSetSelect = DLM_GSetSelect( pHdr );
+
+ // If there are valid call back functions and the item is valid,
+ // toggle the selection status of the item.
+
+ if ( pfnGetSelect && pfnSetSelect && ( pListItem != (LMHANDLE)LB_ERR ) ) {
+
+ fSelect = (BYTE)( ! ( (*pfnGetSelect) ( pListItem ) ) );
+
+ (*pfnSetSelect) ( pListItem, fSelect );
+
+ // Now, grab the items rectangle and invalidate it.
+
+ SendMessage ( hWndListBox, LB_GETITEMRECT, pHdr->unFocusItem, (LONG)&rcTemp );
+ InvalidateRect ( hWndListBox, &rcTemp, FALSE );
+ }
+
+
+} /* end DLM_SpaceBarPressed() */
+
+
+/****************************************************************************
+GSH
+ Name: DLM_ReturnKeyPressed()
+
+ Description: This function processes the space bar by checking or
+ unchecking the item in focus, then tagging and setting
+ the focus of the next item in the list.
+
+ Returns: Nothing.
+
+****************************************************************************/
+
+VOID DLM_ReturnKeyPressed (
+
+HWND hWndListBox, // I - handle to the list box window.
+DLM_HEADER_PTR pHdr, // I - pointer to the header of the list to use.
+LPWORD pwKey ) // IO - pointer to the key value.
+
+{
+ WORD wListBoxIDC;
+ PDS_WMINFO pWinInfo;
+ MP1 mpSend1;
+ MP2 mpSend2;
+
+ // Set the key information being careful to change the return key to
+ // to a space key to the list box so that this item in the list is the
+ // only tagged item.
+
+ pHdr->wKeyValue = *pwKey;
+ pHdr->fKeyDown = TRUE ;
+ *pwKey = VK_SPACE ;
+
+ // Determine the list box to send the double-click message to.
+
+ pWinInfo = (PDS_WMINFO) WM_GetInfoPtr ( GetParent ( hWndListBox ) );
+
+ if ( WMDS_GetWinActiveList ( pWinInfo ) == WMDS_GetWinTreeList ( pWinInfo ) ) {
+ wListBoxIDC = WMIDC_TREELISTBOX;
+ }
+ else {
+ wListBoxIDC = WMIDC_FLATLISTBOX;
+ }
+
+ pHdr->fKeyUp = TRUE;
+
+ SET_WM_COMMAND_PARAMS( wListBoxIDC, LBN_DBLCLK, hWndListBox, mpSend1, mpSend2 );
+
+// DLM_LBNmessages ( GetParent ( hWndListBox ), mpSend1, mpSend2 );
+
+ PostMessage ( GetParent ( hWndListBox ), WM_COMMAND, mpSend1, mpSend2 );
+
+} /* end DLM_ReturnKeyPressed() */
+
+
+/****************************************************************************
+GSH
+ Name: DLM_CharToItem()
+
+ Description: Passes the character to a callback function to see if
+ an item can be selected based on that character.
+
+ Modified: 12-2-91
+
+ Returns: TRUE if the char was used to select an item in the list
+ box, otherwise, FALSE.
+
+****************************************************************************/
+
+BOOL DLM_CharToItem (
+
+HWND hWndListBox, // I - handle to the list box window.
+DLM_HEADER_PTR pHdr, // I - pointer to the header of the list to use.
+LPWORD pwKey ) // IO - pointer to the key value.
+
+{
+ BOOL rc;
+ SET_OBJECTS_PTR pfnSetObjects;
+ LMHANDLE pListItem;
+ WORD wAsciiKey;
+
+ // Determine the ASCII key code from the Virtual key code.
+
+ wAsciiKey = (WORD) MapVirtualKey ( *pwKey, 2 );
+
+ // Get the list item handle.
+
+ pListItem = (LMHANDLE)SendMessage ( hWndListBox,
+ LB_GETITEMDATA,
+ pHdr->unFocusItem,
+ 0L
+ );
+
+ if ( pListItem != (LMHANDLE)LB_ERR ) {
+
+ pfnSetObjects = (SET_OBJECTS_PTR) DLM_GSetObjects( pHdr );
+
+ // CALL BACK the application.
+
+ rc = (BOOL)( (*pfnSetObjects) ( pListItem, (WORD)WM_DLMCHAR, wAsciiKey ) );
+ }
+ else {
+ rc = FALSE;
+ }
+
+ return rc;
+
+} /* end DLM_WMCharToItem() */
diff --git a/private/utils/ntbackup/src/dlm_updt.c b/private/utils/ntbackup/src/dlm_updt.c
new file mode 100644
index 000000000..ff4f465e8
--- /dev/null
+++ b/private/utils/ntbackup/src/dlm_updt.c
@@ -0,0 +1,1014 @@
+/****************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+ Name: wmupdate.c
+
+ Description: This file contains routines for display list manager.
+
+ The following routines are in this module:
+
+
+ DLM_Update
+ DLM_UpdateTags
+
+ $Log: J:\ui\logfiles\dlm_updt.c_v $
+
+ Rev 1.29.1.0 21 Jan 1994 08:57:10 GREGG
+Changed MEM_Free calls to free.
+
+ Rev 1.29 15 Jun 1993 10:56:48 MIKEP
+enable c++
+
+ Rev 1.28 14 Jun 1993 20:13:12 MIKEP
+enable c++
+
+ Rev 1.27 14 May 1993 16:22:24 GLENN
+Removed if statement using bogus dhListItem.
+
+ Rev 1.26 06 May 1993 13:16:26 MIKEP
+Fix directories in right window blowing up. Rob Griffis fixed
+the file. I just checked it in.
+
+ Rev 1.25 11 Dec 1992 18:28:46 GLENN
+Added selection frame rectangle support based on horizontal extent of a list box.
+
+ Rev 1.24 11 Nov 1992 16:30:00 DAVEV
+UNICODE: remove compile warnings
+
+ Rev 1.23 01 Nov 1992 15:47:14 DAVEV
+Unicode changes
+
+ Rev 1.22 14 Oct 1992 15:48:28 GLENN
+Added Selection Framing Support for List Boxes without the FOCUS.
+
+ Rev 1.21 07 Oct 1992 13:48:34 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.20 04 Oct 1992 19:33:18 DAVEV
+Unicode Awk pass
+
+ Rev 1.19 29 Jul 1992 14:14:14 GLENN
+ChuckB checked in after NT fixes.
+
+ Rev 1.18 11 Jun 1992 10:19:52 JOHNWT
+fixed syntax error
+
+ Rev 1.17 10 Jun 1992 11:05:10 STEVEN
+NULL would not compile for mips
+
+ Rev 1.16 15 May 1992 13:32:12 MIKEP
+nt pass 2
+
+ Rev 1.15 19 Mar 1992 11:08:56 ROBG
+Added logic when adding an item to call DLM_SetHorizontalExt.
+
+ Rev 1.14 19 Mar 1992 10:44:00 ROBG
+Corrected problem with dhListItem to be initialized to NULL.
+
+ Rev 1.13 17 Mar 1992 16:19:42 ROBG
+Added logic to send out a HORIZONTALEXTENT
+
+ Rev 1.12 03 Mar 1992 18:21:44 GLENN
+Put in error handling.
+
+ Rev 1.11 07 Feb 1992 16:09:58 STEVEN
+fix casting of errors from sendmessage to WORD
+
+ Rev 1.10 06 Feb 1992 18:34:28 STEVEN
+wStatus should be INT not WORD
+
+ Rev 1.9 06 Feb 1992 11:00:50 ROBG
+Changed DLM_UPDATELIST to use RectVisible call to find the bottom
+item displayed in the listbox.
+
+ Rev 1.8 04 Feb 1992 16:08:08 STEVEN
+various bug fixes for NT
+
+ Rev 1.7 22 Jan 1992 12:29:56 GLENN
+Clean up.
+
+ Rev 1.6 15 Jan 1992 15:15:44 DAVEV
+16/32 bit port-2nd pass
+
+ Rev 1.5 07 Jan 1992 10:11:24 ROBG
+Changes to support variable-width multicolumn listboxes.
+
+ Rev 1.4 26 Dec 1991 17:23:48 ROBG
+New and Improved.
+
+ Rev 1.3 06 Dec 1991 17:31:02 GLENN
+Added code to allow adding a list item with a NULL dhStartItem passed
+
+ Rev 1.2 02 Dec 1991 10:40:38 ROBG
+Added logic to clear out a flat listbox in a DLM_WMUPDATELIST message.
+
+ Rev 1.1 26 Nov 1991 16:26:32 ROBG
+Added validity checks for the window handles, info structure, and the
+dlm display header.
+
+ Rev 1.0 20 Nov 1991 19:24:04 SYSTEM
+Initial revision.
+
+****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+static VOID DLM_ResetWidth( PDS_WMINFO pWinInfo ) ;
+
+/****************************************************************************
+
+ Name: DLM_Update
+
+ Description: This function will update the list according
+ to incoming parameters.
+
+ Modified: 4/30/1991
+
+ Returns: 0 if successful.
+
+ Valid error returns:
+
+ DLMERR_PROCESS_FAILED
+ DLMERR_OUT_OF_MEMORY
+
+****************************************************************************/
+
+WORD DLM_Update(
+
+HWND hWnd , // I - Handle of parent window
+BYTE bType , // I - Type of list ( Hierarchical or Flat )
+WORD wMsg , // I - Type of update operation
+LMHANDLE dhStartItem , // I - Address of item to start with
+USHORT unNumToUpdate ) // I - Number of items to update
+
+{
+
+ INT iStatus ;
+ DLM_HEADER_PTR pHdr ;
+ GET_COUNT_PTR pfnGetItemCount ;
+ GET_FIRST_PTR pfnGetFirstItem ;
+ GET_NEXT_PTR pfnGetNext ;
+
+ LMHANDLE pdsListHdr ;
+ PDS_WMINFO pWinInfo ;
+ HWND hWndLB ;
+ LMHANDLE dhListItem ;
+ INT iCurSel ;
+ INT iTstSel ;
+ INT iTopIndex ;
+ INT iBotIndex ;
+ INT iError ;
+ INT iCnt ;
+ RECT rect ;
+ RECT listrect ;
+ USHORT usIndex ;
+ WORD xNewOrigin ;
+ WORD wScrollPos ;
+ POINT Point ;
+ RECT ChildRect ;
+ HWND hWndNewList ;
+ HWND hWndFocus ;
+ HWND hWndActive ;
+ HDC hDC ;
+
+ iStatus = 0 ;
+
+ // Must be valid window.
+
+ if ( !IsWindow( hWnd ) ) {
+ return( DLMERR_PROCESS_FAILED ) ;
+ }
+
+
+ pWinInfo = WM_GetInfoPtr( hWnd ) ;
+
+ // Extra Bytes for window must be defined.
+
+ if ( !pWinInfo ) {
+ return ( DLMERR_PROCESS_FAILED ) ;
+ }
+
+
+ switch ( bType ) {
+
+ case DLM_TREELISTBOX :
+
+ pHdr = pWinInfo->pTreeDisp ;
+ hWndLB = pWinInfo->hWndTreeList ;
+ pdsListHdr = ( LMHANDLE ) pWinInfo->pTreeList ;
+ break ;
+
+ case DLM_FLATLISTBOX :
+ default :
+
+ pHdr = pWinInfo->pFlatDisp ;
+ hWndLB = pWinInfo->hWndFlatList ;
+ pdsListHdr = ( LMHANDLE ) pWinInfo->pFlatList ;
+
+ break ;
+
+ }
+
+ // Must be valid window.
+
+ if ( !IsWindow( hWndLB ) ) {
+ return( DLMERR_PROCESS_FAILED ) ;
+ }
+
+ // List header must be defined.
+
+ if ( !pdsListHdr ) {
+
+ // If the message is WM_DLMUPDATELIST and its the flat list, then
+ // initialize the list to having no items.
+
+ if ( ( wMsg == WM_DLMUPDATELIST ) && ( bType == DLM_FLATLISTBOX) ) {
+
+ pHdr->usItemCount = 0 ;
+ pHdr->wHorizontalExtent = 0 ;
+ SendMessage ( hWndLB, WM_SETREDRAW, FALSE, 0L ) ;
+ SendMessage ( hWndLB, LB_RESETCONTENT, (MP1)0, (MP2)0 ) ;
+ SendMessage ( hWndLB, WM_SETREDRAW, TRUE, 0L ) ;
+ return( 0 ) ;
+ }
+
+ return ( DLMERR_PROCESS_FAILED ) ;
+ }
+
+
+ switch ( wMsg ) {
+
+ case WM_DLMUPDATEITEM:
+
+ iCurSel = (INT) SendMessage ( hWndLB, LB_FINDSTRING, (MP1)-1, (LONG) dhStartItem ) ;
+
+ if ( iCurSel != LB_ERR ) {
+
+ iStatus = (INT) SendMessage ( hWndLB, LB_GETITEMRECT, iCurSel, (LONG) &rect ) ;
+
+ if (iStatus != LB_ERR) {
+ InvalidateRect( hWndLB, &rect, FALSE ) ;
+ UpdateWindow ( hWndLB ) ;
+
+ }
+
+ } else {
+ return ( DLMERR_PROCESS_FAILED ) ;
+ }
+
+ break ;
+
+ case WM_DLMUPDATELIST:
+
+
+ // This is only good for hierarchical lists because only
+ // the current selection is saved.
+
+ iStatus = (INT) SendMessage ( hWndLB, WM_SETREDRAW, FALSE, 0L ) ;
+
+ wScrollPos = (WORD) GetScrollPos( hWndLB, SB_HORZ ) ;
+
+ iCurSel = (INT) SendMessage( hWndLB, LB_GETCURSEL, 0, 0L ) ;
+ iTopIndex = (INT) SendMessage( hWndLB, LB_GETTOPINDEX, 0, 0L ) ;
+
+ {
+
+ /* Find last displayed line in listbox.*/
+
+ GetClientRect ( hWndLB, &listrect ) ;
+
+ iBotIndex = iTopIndex ;
+ iError = (WORD) SendMessage ( hWndLB, LB_GETITEMRECT, iBotIndex,
+ (LONG) ( LPRECT ) &rect ) ;
+
+ // Get the Device Context for the window.
+
+ hDC = GetDC( hWndLB ) ;
+
+ while( iError != LB_ERR ) {
+
+ // Find the last item's rectangle that is visible.
+
+ if ( !RectVisible ( hDC, &rect ) ) {
+
+ // Break out of the loop when an item is not displayed.
+
+ break ;
+ }
+
+ iError = (INT) SendMessage ( hWndLB, LB_GETITEMRECT, ++iBotIndex,
+ (LONG) ( LPRECT ) &rect ) ;
+ }
+
+ ReleaseDC( hWndLB, hDC ) ;
+
+ iBotIndex-- ;
+ }
+
+ iStatus = (INT) SendMessage ( hWndLB, WM_SETREDRAW, FALSE, 0L ) ;
+
+
+ SendMessage ( hWndLB, LB_RESETCONTENT, (MP1)0, (MP2)0 ) ;
+
+ // If the window is a DLM_FLATLISTBOX and the
+ // mode is multicolumn, then destroy the window and
+ // recreate it so the column width can be recalculated.
+
+ if ( ( bType == DLM_FLATLISTBOX ) &&
+ ( DLM_GMode( pHdr ) == DLM_MULTICOLUMN ) ) {
+
+ // We want to reset the width.
+
+ DLM_ResetWidth( pWinInfo ) ;
+ SendMessage( hWndLB, LB_SETCOLUMNWIDTH, pHdr->cxColWidth , 0L ) ;
+ }
+
+ pfnGetItemCount = (GET_COUNT_PTR) DLM_GGetItemCount( pHdr ) ;
+ pfnGetFirstItem = (GET_FIRST_PTR) DLM_GGetFirstItem( pHdr ) ;
+ pfnGetNext = (GET_NEXT_PTR) DLM_GGetNext ( pHdr ) ;
+
+ pHdr->usItemCount = (USHORT) ( (*pfnGetItemCount) (pdsListHdr) ) ;
+
+ pHdr->wHorizontalExtent = 0 ;
+
+ xNewOrigin = pHdr->xOrigin ;
+
+ usIndex = pHdr->usItemCount ;
+
+ iStatus = (INT) SendMessage ( hWndLB, WM_SETREDRAW, FALSE, 0L ) ;
+
+ if (usIndex) {
+ dhListItem = (LMHANDLE) ( (*pfnGetFirstItem) (pdsListHdr) ) ;
+ } else {
+ dhListItem = NULL ;
+ }
+
+ // Set the horizontal extent for the first object.
+
+ if ( bType == DLM_FLATLISTBOX ) {
+ DLM_SetHorizontalExt( hWndLB, pHdr, dhListItem ) ;
+ }
+
+ while( (dhListItem ) && ( usIndex > 0 ) ) {
+
+ iStatus = (INT) SendMessage( hWndLB, LB_ADDSTRING, 0, (LONG) dhListItem ) ;
+ dhListItem = (LMHANDLE) ( (*pfnGetNext) (dhListItem) ) ;
+ usIndex--;
+
+ }
+
+ if ( dhStartItem ) {
+
+ /* Redefine the CurSel if possible */
+
+ iTstSel = (INT) SendMessage ( hWndLB, LB_FINDSTRING, (MP1)-1, (LONG) dhStartItem ) ;
+ if ( iTstSel != LB_ERR ) {
+ iCurSel = iTstSel ;
+ }
+ }
+
+ if ( DLM_GMode( pHdr ) == DLM_COLUMN_VECTOR ) {
+
+ iStatus = (INT) SendMessage (hWndLB, LB_SETSEL, 1 , 0L );
+
+ } else {
+
+ if ( DLM_GMode( pHdr ) == DLM_HIERARCHICAL ) {
+ if ( iCurSel != LB_ERR ) {
+ pHdr->cLastTreeSelect = (WORD)iCurSel ;
+ }
+ }
+
+ if ( iCurSel != LB_ERR) {
+
+ iStatus = (INT) SendMessage( hWndLB, LB_SETCURSEL, iCurSel, 0L ) ;
+ }
+ }
+
+ // If the new current selection is less than the topindex,
+ // then set the top of the list to the cursel + iCnt/2.
+ // This logic should really put the current selection in
+ // middle of display list.
+
+ if ( iCurSel < iTopIndex ) {
+
+ iCnt = (INT) (iBotIndex - iTopIndex + 1);
+ iTopIndex = (INT) (iCurSel - iCnt/2);
+
+ iStatus = (INT) SendMessage( hWndLB, LB_SETTOPINDEX, iTopIndex, 0L ) ;
+
+ }
+
+ iStatus = (INT) SendMessage ( hWndLB, WM_SETREDRAW, TRUE, 0L ) ;
+
+ InvalidateRect ( hWndLB, NULL, TRUE ) ;
+ UpdateWindow ( hWndLB ) ;
+
+ break ;
+
+ case WM_DLMDELETEITEMS:
+
+ usIndex = unNumToUpdate ;
+
+ if ( usIndex ) {
+
+ if ( dhStartItem ) {
+
+ iCurSel = (INT) SendMessage ( hWndLB, LB_FINDSTRING, (MP1)-1, (LONG) dhStartItem ) ;
+
+ if ( iCurSel == LB_ERR ) {
+ return ( DLMERR_PROCESS_FAILED ) ;
+ }
+
+ iCurSel++ ;
+ }
+ else {
+ iCurSel = 0;
+ }
+
+ iCnt = (INT) SendMessage ( hWndLB, LB_GETCOUNT, (MP1)0, (MP2)0 ) ;
+
+ // If this is the last item, decrease the iCurSel by one so
+ // that the last item is deleted.
+
+ if ( iCurSel == iCnt ) iCurSel-- ;
+
+ iStatus = (INT) SendMessage ( hWndLB, WM_SETREDRAW, FALSE, 0L ) ;
+
+ while ( usIndex ) {
+
+ if ( usIndex == 1 ) {
+ iStatus = (INT) SendMessage ( hWndLB, WM_SETREDRAW, TRUE, 0L ) ;
+ }
+
+ iStatus = (INT) SendMessage ( hWndLB, LB_DELETESTRING, iCurSel, (MP2)0 ) ;
+
+ if ( iStatus == LB_ERR ) {
+ return( DLMERR_PROCESS_FAILED ) ;
+ }
+
+ usIndex--;
+ }
+
+ iStatus = (INT) SendMessage ( hWndLB, WM_SETREDRAW, TRUE, 0L ) ;
+ pHdr->usItemCount -= unNumToUpdate ; /* Trust the count */
+
+ }
+
+ break ;
+
+ case WM_DLMADDITEMS:
+
+ if ( unNumToUpdate ) {
+
+ // Get the GetFirstItem() and GetNext() function pointers
+ // to the app area.
+
+ pfnGetFirstItem = (GET_FIRST_PTR) DLM_GGetFirstItem( pHdr ) ;
+ pfnGetNext = (GET_NEXT_PTR) DLM_GGetNext ( pHdr ) ;
+
+ if ( ! dhStartItem ) {
+
+ // A NULL start item was passed.
+
+ dhListItem = (LMHANDLE) ( (*pfnGetFirstItem) (pdsListHdr) ) ;
+ iCurSel = 0 ;
+ }
+ else {
+
+ // A potentially valid item was passed.
+
+ iCurSel = (INT) SendMessage ( hWndLB, LB_FINDSTRING, (MP1)-1, (LONG) dhStartItem ) ;
+
+ if ( iCurSel == LB_ERR ) {
+ return ( DLMERR_PROCESS_FAILED ) ;
+ }
+
+ dhListItem = (LMHANDLE) ( (*pfnGetNext) (dhStartItem) ) ;
+ iCurSel++ ;
+ }
+
+ // Turn off the redraw. Don't forget to turn it back on
+ // right before inserting the last item.
+
+ if ( unNumToUpdate > 1 ) {
+ iStatus = (INT) SendMessage ( hWndLB, WM_SETREDRAW, FALSE, 0L ) ;
+ }
+
+ // If the current selection is at the end of the list,
+ // APPEND the item(s) to the end of the list. Otherwise,
+ // INSERT it in where it is supposed to go.
+
+ iCnt = (INT) SendMessage ( hWndLB, LB_GETCOUNT, (MP1)0, (MP2)0 ) ;
+
+ if ( iCurSel == iCnt ) {
+
+ // APPEND to end of list.
+
+ // Set the horizontal extent for an object.
+
+ if ( bType == DLM_FLATLISTBOX ) {
+ DLM_SetHorizontalExt( hWndLB, pHdr, dhListItem ) ;
+ }
+
+ for ( usIndex = 0; usIndex < unNumToUpdate; usIndex++ ) {
+
+ if ( ! dhListItem ) {
+ return( DLMERR_PROCESS_FAILED ) ;
+ }
+
+ iStatus = (INT) SendMessage ( hWndLB, LB_INSERTSTRING, (MP1)-1, (LONG) dhListItem ) ;
+ dhListItem = (LMHANDLE) ( (*pfnGetNext) (dhListItem) ) ;
+ }
+ }
+ else {
+
+ // INSERT in the list.
+
+ // Set the horizontal extent for an object.
+
+ if ( bType == DLM_FLATLISTBOX ) {
+ DLM_SetHorizontalExt( hWndLB, pHdr, dhListItem ) ;
+ }
+
+ for ( usIndex = 0; usIndex < unNumToUpdate; usIndex++ ) {
+
+ if ( ! dhListItem ) {
+ return( DLMERR_PROCESS_FAILED ) ;
+ }
+
+ iStatus = (INT) SendMessage ( hWndLB, LB_INSERTSTRING, iCurSel++, (LONG) dhListItem ) ;
+ dhListItem = (LMHANDLE) ( (*pfnGetNext) (dhListItem) ) ;
+ }
+ }
+
+ if ( unNumToUpdate > 1 ) {
+ iStatus = (INT) SendMessage ( hWndLB, WM_SETREDRAW, TRUE, 0L ) ;
+ InvalidateRect ( hWndLB, (LPRECT)NULL, TRUE );
+ }
+
+ pHdr->usItemCount += unNumToUpdate ;
+
+ }
+
+ break ;
+ }
+
+ return(0) ;
+}
+
+
+/****************************************************************************
+
+ Name: DLM_ResetWidth
+
+ Description: This function will reset the width of a multicolumn
+ flat list.
+
+ Modified: 5/06/1993
+
+ Returns: none
+
+ Notes:
+
+ See also:
+
+ Declaration:
+
+****************************************************************************/
+
+VOID DLM_ResetWidth(
+
+PDS_WMINFO pWinInfo )
+
+{
+
+ INT itemWidth ;
+ DLM_HEADER_PTR pdsHdr ;
+
+ GET_COUNT_PTR pfnGetItemCount ;
+ GET_FIRST_PTR pfnGetFirstItem ;
+ GET_OBJECTS_PTR pfnGetObjects ;
+
+ LMHANDLE pdsListHdr ;
+ LMHANDLE dhListItem = (LMHANDLE)0;
+ DLM_ITEM_PTR lpDispItem ;
+ LPBYTE lpObjLst ;
+ USHORT usCnt ;
+ BYTE bObjCnt ;
+ short cxPos ;
+ HWND hWndLB ;
+ HWND hWndParent ;
+ WORD wType ;
+
+ pdsHdr = pWinInfo->pFlatDisp ;
+ hWndLB = pWinInfo->hWndFlatList ;
+
+ hWndParent = GetParent( hWndLB ) ;
+
+ pdsListHdr = ( LMHANDLE ) WMDS_GetFlatList ( pWinInfo );
+
+ wType = WMDS_GetWinType( pWinInfo ) ;
+
+ /* The following steps are taken to set up the appropiate
+ ** width and height.
+ **
+ ** IF pdsHdr exists and pdsListHdr exists and count > 0
+ ** BEGIN
+ ** Get the first item on the queue.
+ ** IF item exists
+ ** BEGIN
+ ** . Get the objects of the item.
+ ** . Calculate the width and height based on the objects found.
+ ** END
+ ** END
+ ** ELSE
+ ** set width and height to defaults ;
+ */
+
+ // Some window type are never multi-column
+ // Just reset the global reference of window handle.
+
+ switch ( wType ) {
+
+ case WMTYPE_JOBS :
+ case WMTYPE_MACROS :
+ case WMTYPE_TAPES :
+ case WMTYPE_DEBUG :
+ case WMTYPE_LOGFILES :
+ case WMTYPE_SERVERS :
+ case WMTYPE_LOGVIEW :
+ case WMTYPE_SEARCH :
+#ifdef OEM_EMS
+ case WMTYPE_EXCHANGE :
+#endif
+
+ pdsHdr = NULL ;
+ break ;
+ }
+
+ if ( pdsHdr ) {
+ pfnGetItemCount = (GET_COUNT_PTR) DLM_GGetItemCount( pdsHdr ) ;
+ pfnGetFirstItem = (GET_FIRST_PTR) DLM_GGetFirstItem( pdsHdr ) ;
+ pfnGetObjects = (GET_OBJECTS_PTR) DLM_GGetObjects ( pdsHdr ) ;
+
+ if ( pdsListHdr ) {
+ usCnt = (USHORT) ( (*pfnGetItemCount) (pdsListHdr) );
+ if ( usCnt ) {
+ dhListItem = (LMHANDLE) ( (*pfnGetFirstItem) (pdsListHdr) ) ;
+ if ( dhListItem ) {
+ lpObjLst = (LPBYTE) ( (*pfnGetObjects) (dhListItem) ) ;
+ lpDispItem = DLM_GetFirstObject( lpObjLst, &bObjCnt ) ;
+
+ // Calculate the width by spanning
+ // the object list, adding up the widths
+ // of the objects.
+
+ cxPos = 0 ;
+
+ while (bObjCnt) {
+
+ DLM_GetWidth ( hWndParent, pdsHdr,
+ &cxPos, lpDispItem ) ;
+
+ // Special Logic for long strings.
+ // If the string is greater than 5, then take off 33%.
+
+
+ if ( ( DLM_ItembType ( lpDispItem ) == DLM_TEXT_ONLY ) &&
+ ( DLM_GDisplay( pdsHdr ) == DLM_LARGEBITMAPSLTEXT ) ){
+
+ LONG lLen ;
+ lLen = strlen( (CHAR_PTR)DLM_ItemqszString( lpDispItem ) );
+
+ if ( lLen > 5 ) {
+ cxPos -= ( pdsHdr->cxBeforeText +
+ ( DLM_ItembMaxTextLen( lpDispItem )*( pdsHdr->cxTextWidth ) ) ) / 3 ;
+ }
+ }
+
+ lpDispItem++;
+ bObjCnt--;
+ }
+
+ // Added left and right 2 pixel area for focus and add 5 for right margin
+
+ itemWidth = (int) ( cxPos + 2*(-mwDLMInflate ) + 5 ) ;
+
+ pdsHdr->cxColWidth = (USHORT) itemWidth ;
+ }
+
+ }
+ }
+ }
+
+ }
+
+/****************************************************************************
+
+ Name: DLM_UpdateTags
+
+ Description: This function will set the tag field of all the items
+ in the list.
+
+ Modified: 4/30/1991
+
+ Returns: 0 if successful.
+
+ Valid error returns:
+
+ DLMERR_OUT_OF_MEMORY
+ DLMERR_LIST_NOT_FOUND
+ Notes:
+
+ See also:
+
+ Declaration:
+
+****************************************************************************/
+
+WORD DLM_UpdateTags(
+
+HWND hWnd , // I - Handle of parent window of listbox.
+BYTE bType ) // I - Type of listbox ( Hierarchical or Flat )
+
+{
+
+ INT iStatus ;
+ WORD wSelCnt ;
+ LPINT pSelArray ;
+ DLM_HEADER_PTR pHdr ;
+ PDS_WMINFO pWinInfo ;
+ LMHANDLE pdsListHdr ;
+ USHORT usCnt ;
+ LMHANDLE dhListItem ;
+ HWND hWndLB ;
+ WORD wIndex ;
+
+ GET_FIRST_PTR pfnGetFirstItem ;
+ GET_NEXT_PTR pfnGetNext ;
+ SET_TAG_PTR pfnSetTag ;
+
+
+ iStatus = 0 ;
+
+ // Must be valid window.
+
+ if ( !IsWindow( hWnd ) ) {
+ return( DLMERR_PROCESS_FAILED ) ;
+ }
+
+
+ pWinInfo = WM_GetInfoPtr( hWnd ) ;
+
+ // Extra Bytes for window must be defined.
+
+ if ( !pWinInfo ) {
+ return ( DLMERR_PROCESS_FAILED ) ;
+ }
+
+
+ switch ( bType ) {
+
+ case DLM_TREELISTBOX :
+
+ pHdr = pWinInfo->pTreeDisp ;
+ hWndLB = pWinInfo->hWndTreeList ;
+ pdsListHdr = ( LMHANDLE ) pWinInfo->pTreeList ;
+
+ break ;
+
+ case DLM_FLATLISTBOX :
+ default :
+
+ pHdr = pWinInfo->pFlatDisp ;
+ hWndLB = pWinInfo->hWndFlatList ;
+ pdsListHdr = ( LMHANDLE ) pWinInfo->pFlatList ;
+
+ break ;
+
+ }
+
+ /* Exception Handling */
+
+ // Must be valid window.
+
+ if ( !IsWindow( hWndLB ) ) {
+ return( DLMERR_PROCESS_FAILED ) ;
+ }
+
+ if ( !pHdr ) {
+ return ( DLMERR_LIST_NOT_FOUND ) ;
+ }
+
+ // List header must be defined.
+
+ if ( !pdsListHdr ) {
+ return ( DLMERR_PROCESS_FAILED ) ;
+ }
+
+ if ( pHdr->usItemCount == 0 ) {
+ return (0) ;
+ }
+
+ /* Only multiselection lists are supported.
+ Only Hierarchical lists are single selection */
+
+
+ if ( DLM_GMode( pHdr ) == DLM_HIERARCHICAL ) {
+ return( 0 ) ;
+ }
+
+ wSelCnt = (WORD) SendMessage (hWndLB, LB_GETSELCOUNT, (MP1)0, (MP2)0 ) ;
+
+ if ( wSelCnt > 0 ) {
+ pSelArray = (LPINT)calloc( wSelCnt, sizeof( int ) ) ;
+ if ( pSelArray ) {
+
+ iStatus = (INT) SendMessage (hWndLB, LB_GETSELITEMS, wSelCnt, (LONG) &pSelArray[0] ) ;
+ } else {
+
+ return ( DLMERR_OUT_OF_MEMORY ) ;
+ }
+
+ } else {
+ pSelArray = NULL ;
+ }
+
+
+ /* Walk through the list and set all the tags to 0 */
+
+ pfnGetFirstItem = (GET_FIRST_PTR) DLM_GGetFirstItem( pHdr ) ;
+ pfnGetNext = (GET_NEXT_PTR) DLM_GGetNext ( pHdr ) ;
+ pfnSetTag = (SET_TAG_PTR) DLM_GSetTag ( pHdr ) ;
+
+ usCnt = pHdr->usItemCount ;
+
+ dhListItem = (LMHANDLE) ( (*pfnGetFirstItem) ( pdsListHdr ) ) ;
+
+ while( (dhListItem ) && ( usCnt > 0 ) ) {
+ (*pfnSetTag) (dhListItem, 0 ) ;
+ dhListItem = (LMHANDLE) ( (*pfnGetNext) (dhListItem) ) ;
+ usCnt--;
+
+ }
+
+
+ /* Now set the tags that are set */
+
+ for(wIndex=0; wIndex<wSelCnt; wIndex++ ) {
+
+ dhListItem = (LMHANDLE) SendMessage ( hWndLB, LB_GETITEMDATA,
+ (WORD) *(pSelArray+wIndex), 0L ) ;
+
+ if ( (LONG) dhListItem != LB_ERR ) {
+ (*pfnSetTag) (dhListItem, 1 ) ;
+ }
+ }
+
+ if( pSelArray ) {
+ free( pSelArray ) ;
+ }
+
+ return( 0 ) ;
+
+}
+
+
+/****************************************************************************
+GSH
+ Name: DLM_UpdateFocus
+
+ Description: This function will update the list box with the proper
+ selection and focus displays.
+
+ Returns: 0 if successful.
+
+****************************************************************************/
+
+WORD DLM_UpdateFocus (
+
+HWND hWndLB, // I - Handle of the listbox window.
+BOOL fSetFocus ) // I - Set the focus or Kill the focus.
+
+{
+
+ INT nStatus;
+ INT nSelCnt;
+ LPINT pSelArray;
+ DLM_HEADER_PTR pHdr;
+ PDS_WMINFO pWinInfo;
+ PVOID pdsListHdr;
+ INT nIndex;
+ RECT Rect;
+ BYTE bType;
+
+
+ nStatus = 0;
+ pWinInfo = WM_GetInfoPtr ( GetParent ( hWndLB ) );
+ pHdr = DLM_GetDispHdr ( hWndLB );
+
+
+ if ( ! pWinInfo || ! pHdr ) {
+ return DLMERR_PROCESS_FAILED;
+ }
+
+ bType = DLM_GMode ( pHdr );
+
+ if ( fSetFocus ) {
+
+ // Set the currently active list window.
+
+ WMDS_SetWinActiveList ( pWinInfo, hWndLB );
+ }
+ else {
+
+ pHdr->fKeyUp = FALSE;
+ pHdr->fKeyDown = FALSE;
+
+// WMDS_SetWinActiveList ( pWinInfo, (HWND)NULL );
+
+ }
+
+ switch ( bType ) {
+
+ case DLM_TREELISTBOX :
+
+ pdsListHdr = ( PVOID ) pWinInfo->pTreeList;
+
+ break;
+
+ case DLM_FLATLISTBOX :
+ default :
+
+ pdsListHdr = ( PVOID ) pWinInfo->pFlatList;
+
+ break;
+
+ }
+
+ /* Exception Handling */
+
+ if ( pHdr->usItemCount == 0 ) {
+ return 0;
+ }
+
+ // Only multiselection lists are supported.
+ // Only Hierarchical lists are single selection.
+
+
+ if ( DLM_GMode ( pHdr ) == DLM_HIERARCHICAL ) {
+ return 0;
+ }
+
+ nSelCnt = (INT) SendMessage ( hWndLB, LB_GETSELCOUNT, (MP1)0, (MP2)0 );
+
+ if ( nSelCnt <= 0 ) {
+
+ return 0;
+ }
+
+ pSelArray = (LPINT)calloc ( nSelCnt, sizeof( INT ) );
+
+ if ( ! pSelArray ) {
+
+ return DLMERR_OUT_OF_MEMORY;
+ }
+
+ nStatus = (INT) SendMessage ( hWndLB, LB_GETSELITEMS, nSelCnt, (LONG) &pSelArray[0] );
+
+ // Invalidate the rectangles of the selected items.
+
+ for ( nIndex = 0; nIndex < nSelCnt; nIndex++ ) {
+
+ nStatus = (INT) SendMessage ( hWndLB,
+ LB_GETITEMRECT,
+ (WORD) *(pSelArray+nIndex),
+ (LONG) (LPRECT) &Rect
+ );
+
+ if ( nStatus != LB_ERR ) {
+
+ // Make sure that the one just above this one gets repainted also.
+
+ if ( Rect.top > 0 ) {
+ Rect.top--;
+ }
+
+ InvalidateRect ( hWndLB, &Rect, FALSE );
+ }
+ }
+
+ if ( pSelArray ) {
+ free( pSelArray );
+ }
+
+ return 0;
+
+} /* end DLM_UpdateFocus() */
+
+
diff --git a/private/utils/ntbackup/src/do_back.c b/private/utils/ntbackup/src/do_back.c
new file mode 100644
index 000000000..9a2923e60
--- /dev/null
+++ b/private/utils/ntbackup/src/do_back.c
@@ -0,0 +1,3457 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: do_back.c
+
+ Description:
+
+ $Log: J:/UI/LOGFILES/DO_BACK.C_V $
+
+ Rev 1.144.1.17 16 Jun 1994 17:43:50 GREGG
+Fixed setting and clearing of YESYES flag.
+
+ Rev 1.144.1.16 24 May 1994 20:07:04 GREGG
+Improved handling of ECC, SQL, FUTURE_VER and OUT_OF_SEQUENCE tapes.
+
+ Rev 1.144.1.15 04 May 1994 14:13:22 STEVEN
+fix dlt settling time
+
+ Rev 1.144.1.14 28 Mar 1994 14:33:56 GREGG
+In MSG_TBE_ERROR, compare strm_id to STRM_INVALID instead of 0.
+
+ Rev 1.144.1.13 16 Mar 1994 15:42:06 chrish
+Fixed EPR# 0279 - During append operation a replace instead of an append
+mode was written to the event log.
+
+ Rev 1.144.1.12 23 Feb 1994 14:55:10 STEVEN
+remove corrupt.lst support from ntbackup
+
+ Rev 1.144.1.11 22 Feb 1994 17:38:56 GREGG
+From Mike P. : Disable abort during EOM processing.
+
+ Rev 1.144.1.10 01 Feb 1994 14:44:10 chrish
+Added another fix for EPR 0214 ( /R command line process ). Previous
+fix did not handle the case for an empty tape or an erased tape.
+
+ Rev 1.144.1.9 28 Jan 1994 14:04:18 MIKEP
+fix wait on file if file goes away
+
+ Rev 1.144.1.8 18 Jan 1994 18:08:26 chrish
+Added fix for EPR 0214. Added logic to handle command-line backup
+/R option (restrict access to owner ...). The flag was being set but
+no logic to handle the /R option.
+
+ Rev 1.144.1.7 17 Jan 1994 15:36:42 MIKEP
+fix unicode warnings
+
+ Rev 1.144.1.6 12 Jan 1994 10:23:00 MikeP
+add abort in middle of file handling
+
+ Rev 1.144.1.5 14 Dec 1993 12:19:48 BARRY
+Don't write to gszTprintfBuffer, use yprintf
+
+ Rev 1.144.1.4 01 Dec 1993 17:33:04 mikep
+added VLM_SQL_TAPE support
+
+ Rev 1.144.1.3 24 Nov 1993 19:12:28 GREGG
+Added hardware compression option to backup dialog and config.
+
+ Rev 1.144.1.2 04 Nov 1993 15:46:46 STEVEN
+japanese changes
+
+ Rev 1.144.1.1 29 Sep 1993 18:31:34 BARRY
+Handle access denied
+
+ Rev 1.144.1.0 15 Sep 1993 13:53:50 CARLS
+changes for displaying full path/file name detail if Log files
+
+ Rev 1.144 11 Aug 1993 15:57:18 GLENN
+Auto terminating runtime window only if there was an abnormal termination before auto verify.
+
+ Rev 1.143 05 Aug 1993 18:27:14 ZEIR
+fix .141, look at tpos if not -1, else look at cur_vcb
+
+ Rev 1.142 05 Aug 1993 17:21:02 CARLS
+added DidItOnce at TF_NEED_NEW_TAPE for append problem
+
+ Rev 1.141 03 Aug 1993 21:30:26 GREGG
+use tpos vs. vcb for seq req in NEED_NEW_TAPE
+
+ Rev 1.140 30 Jul 1993 14:21:40 CARLS
+fixed TF_WRONG_TAPE to check tape IDs before display message
+
+ Rev 1.139 30 Jul 1993 09:03:34 CARLS
+added VLM_ECC_TAPE & VLM_FUTURE_VER
+
+ Rev 1.138 26 Jul 1993 14:55:38 CARLS
+added code for MSG_COMM_FAILURE
+
+ Rev 1.137 22 Jul 1993 18:35:10 KEVINS
+Corrected macro name.
+
+ Rev 1.136 22 Jul 1993 18:28:16 KEVINS
+Added support for tape drive settling time.
+
+ Rev 1.135 14 Jul 1993 14:57:50 chrish
+Correction to the below fix for Rev 1.133:
+Cayman EPR 0542: added code to support hardware compression while running
+a batch mode job.
+
+Placed the code in wrong place.
+
+ Rev 1.134 14 Jul 1993 09:25:08 CARLS
+changed code to call skipno dialog for file open
+
+ Rev 1.133 06 Jul 1993 09:50:58 chrish
+Cayman EPR 0542: added code to support hardware compression while running
+a batch mode job.
+
+ Rev 1.132 28 Jun 1993 16:26:08 CARLS
+added call to VLM_RemoveUnusedBSDs
+
+ Rev 1.131 27 Jun 1993 14:06:22 MIKEP
+continue work on status monitor stuff
+
+ Rev 1.130 21 Jun 1993 17:14:30 Aaron
+Put ifdef around call to NtDemoChangeTape (for OS_WIN32)
+
+ Rev 1.129 19 Jun 1993 13:53:32 MIKEP
+add wrong tape family msg box
+
+ Rev 1.128 18 Jun 1993 17:34:50 Aaron
+Retry for tape-not-inserted only for OS_WIN32
+
+ Rev 1.127 18 Jun 1993 16:47:26 CARLS
+added NtDemoChangeTape calls for NtDemo
+
+ Rev 1.126 15 Jun 1993 13:15:40 DARRYLP
+More status monitor features
+
+ Rev 1.125 14 Jun 1993 20:22:42 MIKEP
+enable c++
+
+ Rev 1.124 10 Jun 1993 13:48:12 CARLS
+added WMMB_NOYYCHECK to insert new tape after write-prot message
+
+ Rev 1.123 09 Jun 1993 19:05:48 MIKEP
+support wrong tape message from gregg.
+
+ Rev 1.122 09 Jun 1993 09:01:42 chrish
+Backup logging information, added more info such as the drive where the
+files are located.
+
+ Rev 1.121 08 Jun 1993 11:06:24 CARLS
+added code to look in the catalogs to see if tape has a transfer set
+
+ Rev 1.120 07 Jun 1993 15:46:28 GLENN
+Moved the VLM_CloseAll to beginning of command line job section and after dialog section.
+
+ Rev 1.119 07 Jun 1993 08:22:22 MIKEP
+fix warnings.
+
+ Rev 1.118 03 Jun 1993 14:30:08 DARRYLP
+Removed excess \ from backup and restore directory field upon abort
+
+ Rev 1.117 03 Jun 1993 12:40:46 DARRYLP
+Fix for event logging erroneous text - replace only occurs for the first
+backup set - subsequent sets (in the same backup operation) are appended.
+
+ Rev 1.116 27 May 1993 15:41:34 CARLS
+added calls to VLM_GetSSETonTapeAttribute for Transfer problem
+
+ Rev 1.115 26 May 1993 17:49:48 MIKEP
+Fix directory and file names updating.
+
+ Rev 1.114 26 May 1993 15:43:48 BARRY
+Retry for no-tape situations.
+
+ Rev 1.113 23 May 1993 14:15:52 MIKEP
+Try to fix 294-507 ntfs error displaying the time. Also fix
+typo in last checkin.
+
+ Rev 1.112 23 May 1993 13:43:04 MIKEP
+fix epr 294-489, adjust foreign tape as continaution tape msg.
+
+ Rev 1.111 22 May 1993 14:24:48 MIKEP
+fix dangerous code when getting stats ptr and no backup in progress.
+
+ Rev 1.110 22 May 1993 13:44:04 MIKEP
+Fix nostradamus epr #504, update the status windows the same for
+all tape operations.
+
+ Rev 1.109 21 May 1993 10:30:52 chrish
+This fix is for both CAYMAN and NOSTRADAMUS.
+
+NOSTRADAMUS EPR 0407: Fixed problem when backing up across tape, it would
+allow backing up onto the same tape. Fixed it such that it will not backup
+across tape of the same family.
+
+Also fixed a problem when using a command line backing, that on the second
+tape it would not warn user if he was overwriting a good tape. Thus fixed
+it such that it does check the second tape and warn the user that he is going
+to replace over a good tape. This problem is also encountered in CAYMAN.
+
+ Rev 1.108 17 May 1993 13:59:10 CARLS
+change to DM_StartSkipOpen call
+
+ Rev 1.107 12 May 1993 12:03:14 DARRYLP
+The runtime status listbox now displays the number of files skipped in
+each backup set - this information is also included in the log file.
+Prior to this fix, only the last backup set information remained on the
+screen.
+
+ Rev 1.106 10 May 1993 09:10:48 chrish
+CAYMAN EPR 0247: Added fix to report the drive being backed-up in the log
+files.
+
+ Rev 1.105 03 May 1993 11:38:20 chrish
+Nostradamous EPR 0172 and 0400. Added fix to display proper message when
+spanning tape. Current message gives impression that tape is rewinding
+when in effect tape has completed rewinding.
+
+ Rev 1.104 30 Apr 1993 14:38:58 chrish
+NOSTRADAMOUS EPR 0021 - When tape is rewindind and you trigger a command
+line backup ... you get a "No tape in drive" message even though a tape is
+in the drive (but is rewinding). Solution was to increase the loop count
+from 5 to 10 for getting a no tape in drive status before determining
+that a tape is really not in the drive. Also we by passes the message, it
+appears that message "No tape in drive" is really not necessary, because
+poll drive will also display a pop up message depending on the drive
+status.
+
+ Rev 1.103 27 Apr 1993 18:02:26 DARRYLP
+
+ Rev 1.102 27 Apr 1993 17:35:06 DARRYLP
+Fixed missing decl.
+
+ Rev 1.101 27 Apr 1993 16:01:50 DARRYLP
+Added Status monitor "stuff".
+
+ Rev 1.100 26 Apr 1993 17:00:30 CARLS
+fixed abort problem I put in
+
+ Rev 1.99 26 Apr 1993 10:11:42 MIKEP
+Add support for trefreshing tapes window.
+
+ Rev 1.98 22 Apr 1993 13:31:18 chrish
+Nostradamous fix: EPR 0116 - Suspend the elapse time counter when
+user presses the abort button during a backup.
+
+Cayman fix: EPR 0094 - When launcher triggers a backup that spans across
+two tapes the app will now terminate and go back to the launcher. Before
+the fix the app would require user intervention after the backup was done,
+now it will terminate automatically and return back to the launcher.
+
+ Rev 1.97 21 Apr 1993 13:31:48 CARLS
+don't call Job_Status - Abort_off if doing a verify after backup
+
+ Rev 1.96 13 Apr 1993 16:27:14 GLENN
+Now clearing the directory buffer between sets.
+
+ Rev 1.95 07 Apr 1993 17:54:00 CARLS
+
+ Rev 1.94 02 Apr 1993 15:47:18 CARLS
+changes for DC2000 unformatted tape
+
+ Rev 1.93 13 Mar 1993 21:03:32 MIKEP
+speed up clock
+
+ Rev 1.91 09 Mar 1993 10:57:28 MIKEP
+update clock stats at end of set
+
+ Rev 1.90 07 Mar 1993 16:33:30 GREGG
+Call _sleep for OS_WIN32 only.
+
+ Rev 1.89 07 Mar 1993 16:10:28 MIKEP
+change display to change with clock
+
+ Rev 1.88 19 Feb 1993 11:00:44 TIMN
+Fixed display of proper in-use filename EPR(0222)
+
+ Rev 1.87 18 Feb 1993 09:53:38 STEVEN
+fix typo
+
+ Rev 1.86 17 Feb 1993 10:36:20 STEVEN
+changes from mikep
+
+ Rev 1.85 11 Feb 1993 14:40:54 CARLS
+don't allow append operation to a tape that does not support it
+
+ Rev 1.84 18 Jan 1993 16:05:04 STEVEN
+add support for stream id error message
+
+ Rev 1.83 08 Jan 1993 14:27:58 chrish
+Deleted one line ... ("... //chs")
+
+ Rev 1.82 29 Dec 1992 13:33:48 DAVEV
+unicode fixes (3)
+
+ Rev 1.81 23 Dec 1992 15:24:34 chrish
+Change focus point to abort & "Tape Name:" string in log file
+
+ Rev 1.80 15 Dec 1992 11:16:54 chrish
+Corrected SKIP OPEN WAITING DIALOG to display proper
+FULL-filename.
+
+
+
+ Rev 1.79 23 Nov 1992 14:30:14 MIKEP
+add call to patch continuation vcb
+
+ Rev 1.78 11 Nov 1992 16:30:24 DAVEV
+UNICODE: remove compile warnings
+
+ Rev 1.77 05 Nov 1992 17:00:30 DAVEV
+fix ts
+
+ Rev 1.75 27 Oct 1992 17:08:34 MIKEP
+add drive name to status call
+
+ Rev 1.74 23 Oct 1992 10:45:36 MIKEP
+abort stuff
+
+ Rev 1.73 20 Oct 1992 17:00:36 MIKEP
+getstatus calls
+
+ Rev 1.72 20 Oct 1992 16:27:52 MIKEP
+changes for abort
+
+ Rev 1.71 07 Oct 1992 14:47:50 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.70 04 Oct 1992 19:33:36 DAVEV
+Unicode Awk pass
+
+ Rev 1.69 02 Sep 1992 20:12:24 MIKEP
+timed wait for microsoft open files
+
+ Rev 1.68 24 Aug 1992 15:22:14 DAVEV
+NT Event Logging
+
+ Rev 1.67 20 Aug 1992 09:03:00 GLENN
+Added RTD bitmap update at init time.
+
+ Rev 1.66 28 Jul 1992 14:49:48 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.65 27 Jul 1992 14:51:02 JOHNWT
+ChuckB fixed references for NT.
+
+ Rev 1.64 27 Jul 1992 11:09:04 JOHNWT
+ChuckB checked in for John Wright, who is no longer with us.
+
+ Rev 1.63 20 Jul 1992 10:00:18 JOHNWT
+gas gauge display work
+
+ Rev 1.62 07 Jul 1992 16:04:30 MIKEP
+unicode changes
+
+ Rev 1.61 29 Jun 1992 10:39:00 MIKEP
+add hours to time display
+
+ Rev 1.60 25 Jun 1992 14:19:26 STEVEN
+used LOCAL_DOS to determin if not network
+
+ Rev 1.59 10 Jun 1992 11:12:22 DAVEV
+OS_WIN32:Start of changes for NT Event Logging-currently commented out
+
+ Rev 1.58 01 Jun 1992 15:26:54 GLENN
+Added tape name logging as done in 1.52.1.0 QIC release.
+
+ Rev 1.57 21 May 1992 19:24:56 MIKEP
+fixes
+
+ Rev 1.56 19 May 1992 13:01:36 MIKEP
+mips changes
+
+ Rev 1.55 14 May 1992 17:39:08 MIKEP
+nt pass 2
+
+ Rev 1.54 11 May 1992 19:32:08 STEVEN
+64bit and large path sizes
+
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+#define MAX_DISPLAY_FULL_FILENAME_LENGTH 20
+#define TRAN_START 0x01
+#define TRAN_CONT 0x02
+#define TRAN_END 0x00
+
+static UINT16 tpos_rout( UINT16, TPOS_PTR, BOOLEAN, DBLK_PTR, UINT16 );
+static UINT16 backup_msg_hndlr( UINT16, INT32, BSD_PTR, FSYS_HAND, TPOS_PTR, ... );
+static UINT16 WriteAbortOperation( CHAR_PTR drive_name );
+static UINT16 GetPasswordAndTapeName( BSD_PTR, DBLK_PTR, CHAR_PTR, CHAR_PTR, CHAR_PTR );
+static VOID CarryForwardPasswordTapeName( BSD_PTR, DBLK_PTR );
+static INT16 BlowOutBSDs( VOID );
+static VOID clock_routine( VOID );
+static VOID poll_drive_clock_routine( VOID );
+static VOID do_backup_init( VOID );
+static VOID do_backup_process( VOID );
+
+static BOOLEAN clock_ready_flag;
+static INT16 mwnTransaction;
+static HTIMER timer_handle;
+static STATS op_stats;
+static INT mw_oper_type;
+static INT16 mw_ret_val;
+static INT mw_rewind;
+static UINT16 mwTapeDriveStatus;
+static UINT16 mwPollDriveWaitTimer;
+static UINT16 mwNoTapeStatusCounter;
+static UINT16 mwReplaceTapeCount;
+static INT16 mwReplaceModeFlag;
+static INT16 mwSkipNoFlag;
+
+static CHAR mwCurrentDrive[ 512 ];
+static CHAR mwCurrentPath[ 512 ];
+static CHAR mwCurrentFile[ 512 ];
+static CHAR DrivePathFileName[ 512 ];
+
+static UINT16 mwTapeSettlingCount;
+
+static BOOLEAN mw_yes_flag_was_set = FALSE ;
+
+static INT mwfAbortDisabledForEOM;
+
+static QTC_BUILD_PTR mw_qtc_ptr;
+static INT DidItOnce = 0; // chs:05-20-93
+
+#ifdef OEM_EMS
+extern INT32 RT_BSD_OsId ;
+#endif
+
+#ifdef OS_WIN32
+
+ #define VLM_RETRY_COUNTER 10 // chs:04-29-93
+ static BOOL mwErrorDuringBackupSet = FALSE;
+
+#else
+
+ #define VLM_RETRY_COUNTER 5 // chs:04-29-93
+
+#endif
+
+/*****************************************************************************
+
+ Name: do_backup
+
+ Description: Main entry point to perform a backup operation. The
+ start backup dialog is first displayed to get the
+ user options. If successful, the runtime dialog is
+ displayed.
+
+ Returns: SUCCESS
+ ABNORMAL_TERMINATION
+
+ Notes: mw_ret_val is set in do_backup_process
+
+*****************************************************************************/
+
+INT do_backup( INT16 oper_type )
+{
+
+ gfAbortInMiddleOfFile = FALSE;
+ mwfAbortDisabledForEOM = FALSE;
+
+ mw_qtc_ptr = NULL;
+ mwnTransaction = TRAN_START;
+ mw_ret_val = SUCCESS;
+ mw_oper_type = oper_type;
+ mw_rewind = TRUE;
+ mwSkipNoFlag = 0 ;
+
+ mwCurrentPath[ 0 ] = TEXT( '\0' );
+ mwCurrentFile[ 0 ] = TEXT( '\0' );
+
+ gbAbortAtEOF = FALSE;
+ gbCurrentOperation = OPERATION_BACKUP;
+ SetStatusBlock(IDSM_OPERATIONSTATUS, STAT_OPER_BACKUP);
+
+ /* we will check for tape every 3 seconds, but prompt user by interval
+ specified in INI file */
+ mwTapeSettlingCount = CDS_GetTapeDriveSettlingTime ( CDS_GetPerm () ) / 3;
+
+ if ( CDS_GetTapeDriveName( CDS_GetPerm( ) ) ) {
+
+ CHAR DriveName[80] ;
+
+ strncpy( DriveName, (CHAR_PTR)CDS_GetTapeDriveName( CDS_GetPerm( ) ), 80 ) ;
+ DriveName[79] = '\0' ;
+ strlwr( DriveName ) ;
+ if( strstr( DriveName, TEXT( "cipher" ) ) != NULL ||
+ ( strstr( DriveName, TEXT( "dec" ) ) != NULL &&
+ ( strstr( DriveName, TEXT( "thz02" ) ) != NULL ||
+ strstr( DriveName, TEXT( "tz86" ) ) != NULL ||
+ strstr( DriveName, TEXT( "tz87" ) ) != NULL ||
+ strstr( DriveName, TEXT( "dlt2700" ) ) != NULL ||
+ strstr( DriveName, TEXT( "dlt2000" ) ) != NULL ) ) ) {
+ mwTapeSettlingCount *= 2 ;
+ }
+ }
+
+ /* display the first backup dialog */
+
+ if ( CDS_GetYesFlag ( CDS_GetCopy() ) != YESYES_FLAG ) {
+
+ if( DM_StartBackupSet( oper_type ) ) {
+ mw_ret_val = ABNORMAL_TERMINATION;
+ }
+ else {
+
+ VLM_CloseAll();
+ }
+
+ }
+ else {
+
+ //
+ // Hardware compression support
+ //
+ if ( thw_list->drv_info.drv_features & TDI_DRV_COMPRESSION ) {
+ if ( CDS_GetHWCompMode( CDS_GetCopy() ) ) {
+ TF_SetHWCompression( thw_list, TRUE ) ;
+ } else {
+ TF_SetHWCompression( thw_list, FALSE ) ;
+ }
+ }
+
+ VLM_CloseAll();
+
+ /* if running a minimized job, wait for poll drive */
+ /* to report the status of the drive */
+
+ mwTapeDriveStatus = VLM_BUSY;
+ mwNoTapeStatusCounter = 0 ;
+ mwPollDriveWaitTimer = 60 * 5; /* wait for 5 minutes */
+
+ timer_handle = WM_HookTimer( poll_drive_clock_routine, 1 );
+
+ while( mwPollDriveWaitTimer && !gfTerminateApp ) {
+
+ WM_MultiTask ( );
+
+ if( mwTapeDriveStatus == VLM_VALID_TAPE ||
+ mwTapeDriveStatus == VLM_NO_TAPE ||
+ mwTapeDriveStatus == VLM_FOREIGN_TAPE ||
+ mwTapeDriveStatus == VLM_FUTURE_VER ||
+ mwTapeDriveStatus == VLM_SQL_TAPE ||
+ mwTapeDriveStatus == VLM_ECC_TAPE ||
+ mwTapeDriveStatus == VLM_GOOFY_TAPE ||
+ mwTapeDriveStatus == VLM_BLANK_TAPE ) {
+
+ break;
+ }
+ }
+
+ // if the app was terminated, exit
+
+ if ( gfTerminateApp ) {
+
+ mw_ret_val = ABNORMAL_TERMINATION;
+
+ } else if( !mwPollDriveWaitTimer ||
+ mwTapeDriveStatus == VLM_NO_TAPE ||
+ mwTapeDriveStatus == VLM_FUTURE_VER ||
+ mwTapeDriveStatus == VLM_SQL_TAPE ||
+ mwTapeDriveStatus == VLM_ECC_TAPE ||
+ mwTapeDriveStatus == VLM_GOOFY_TAPE ||
+ mwTapeDriveStatus == VLM_FOREIGN_TAPE ) {
+
+ /* if timer elapsed or status = no or foreign tape */
+ /* display dialog with status message */
+
+ WORD MessageID = 0;
+
+ if( mwTapeDriveStatus == VLM_FOREIGN_TAPE ||
+ mwTapeDriveStatus == VLM_SQL_TAPE ||
+ mwTapeDriveStatus == VLM_FUTURE_VER ||
+ mwTapeDriveStatus == VLM_GOOFY_TAPE ||
+ mwTapeDriveStatus == VLM_ECC_TAPE ) {
+
+ MessageID = RES_ERASE_FOREIGN_TAPE ;
+#ifdef OS_WIN32
+ WM_MessageBox( ID( IDS_MSGTITLE_WARNING ), // chs:04-29-93
+ ID( MessageID ), // chs:04-29-93
+ WMMB_OK | WMMB_NOYYCHECK, // chs:04-29-93
+ WMMB_ICONEXCLAMATION, NULL, 0, 0 ); // chs:04-29-93
+#endif
+ }
+ else if( mwTapeDriveStatus == VLM_NO_TAPE ) {
+
+ MessageID = RES_ERASE_NO_TAPE ;
+ }
+ /* do we have a valid error to display? */
+ if( MessageID ) {
+
+ /* display the error message */
+
+#ifndef OS_WIN32
+ WM_MessageBox( ID( IDS_MSGTITLE_WARNING ),
+ ID( MessageID ),
+ WMMB_OK | WMMB_NOYYCHECK,
+ WMMB_ICONEXCLAMATION, NULL, 0, 0 );
+#endif
+ }
+ else {
+ /* no - terminate the operation */
+ mw_ret_val = ABNORMAL_TERMINATION;
+ }
+ }
+
+ WM_UnhookTimer( timer_handle );
+ }
+
+ /* if the user said continue, display the runtime dialog and
+ kick off the backup. */
+
+ if ( mw_ret_val == SUCCESS ) {
+
+ do_backup_init();
+ do_backup_process();
+
+ }
+
+ QTC_FreeBuildHandle( mw_qtc_ptr );
+
+ gbCurrentOperation = OPERATION_NONE;
+ SetStatusBlock(IDSM_OPERATIONSTATUS, STAT_OPER_IDLE);
+ mwnTransaction = TRAN_END;
+ return( mw_ret_val );
+
+}
+
+
+/*****************************************************************************
+
+ Name: do_backup_init
+
+ Description: This function is called to display the runtime dialog.
+ It sets up the text based on the operation type.
+
+ Returns: void
+
+*****************************************************************************/
+
+VOID do_backup_init( VOID )
+{
+ JobStatusBackupRestore( (WORD) JOB_STATUS_CREATE_DIALOG );
+
+ if( mw_oper_type == ARCHIVE_BACKUP_OPER ) {
+ yresprintf( (INT16) IDS_DLGTITLEJOBSTATTRANSFER );
+ }
+ else {
+ yresprintf( (INT16) IDS_DLGTITLEJOBSTATBACKUP );
+ }
+ JobStatusBackupRestore( (WORD) JOB_STATUS_BACKUP_TITLE );
+
+ /* display "Set information n of n " */
+ JobStatusBackupRestore( (WORD) JOB_STATUS_N_OF_N );
+
+ // display the disk drive bitmap
+ JobStatusBackupRestore( JOB_STATUS_VOLUME_HARDDRIVE );
+
+ yresprintf( (INT16) RES_TITLE_NEW_LINE );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+
+ yresprintf( (INT16) IDS_DLGTITLEJOBSTATBACKUP );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+
+ yresprintf( (INT16) RES_TITLE_NEW_LINE );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+
+
+ return;
+}
+
+
+/*****************************************************************************
+
+ Name: do_backup_process
+
+ Description: Does the actual backup process.
+
+ Returns: void
+
+ Notes: if error, mw_ret_val is set to ABNORMAL_TERMINATION
+
+*****************************************************************************/
+
+VOID do_backup_process( VOID )
+{
+ LIS lis;
+ BSD_PTR bsd_ptr;
+ CDS_PTR cds_ptr = CDS_GetCopy();
+
+ lis.bsd_list = bsd_list;
+ lis.curr_bsd_ptr = BSD_GetFirst( bsd_list );
+ lis.tape_pos_handler = tpos_rout; /* set tape positioner to call */
+ lis.message_handler = (MSG_HANDLER)backup_msg_hndlr; /* set message handler to call */
+ lis.oper_type = (INT16)mw_oper_type; /* set operation type */
+ lis.abort_flag_ptr = &gb_abort_flag; /* set abort flag address */
+ lis.pid = 0L;
+
+ // Only restart on last drive used if append and last operation
+ // was also a backup operation.
+
+ if ( ( gb_last_operation == mw_oper_type ) &&
+ ( CDS_GetAppendFlag( cds_ptr ) ) ) {
+ lis.auto_det_sdrv = TRUE;
+ }
+ else {
+ lis.auto_det_sdrv = FALSE;
+ }
+ gb_last_operation = mw_oper_type;
+ lis.vmem_hand = NULL;
+ if( CDS_GetAppendFlag( cds_ptr ) ) {
+ mwReplaceModeFlag = FALSE;
+ }
+ else {
+ mwReplaceModeFlag = TRUE;
+ mwReplaceTapeCount = 1;
+ }
+
+ UI_ExcludeInternalFiles( (INT16)mw_oper_type );
+
+ /* remove the unwanted BSD added by the parser */
+ VLM_RemoveUnusedBSDs( bsd_list ) ;
+
+ LP_SetAbortFlag( &lis, CONTINUE_PROCESSING );
+
+ /* clear the statistics before the operation starts */
+ ST_StartOperation( &op_stats );
+
+ /* set the Runtime abort flag pointer */
+ JobStatusAbort( lis.abort_flag_ptr );
+
+ /* enable the abort button for the runtime dialog */
+ JobStatusBackupRestore( (WORD) JOB_STATUS_ABORT_ENABLE );
+
+ if ( CDS_GetBackupCatalogs( CDS_GetCopy() ) ) {
+ VLM_IncludeCatalogs();
+ }
+
+ clock_ready_flag = FALSE; /* Wait on bset to start */
+
+ timer_handle = WM_HookTimer( clock_routine, 1 );
+
+ /* call backup engine */
+
+ PD_StopPolling();
+
+ if ( LP_Backup_Engine( &lis ) ) {
+
+ /* indicate which bsd had the problem for cataloging purposes */
+
+ BSD_SetOperStatus( lis.curr_bsd_ptr, ABNORMAL_TERMINATION );
+ }
+
+ PD_StartPolling();
+
+ WM_UnhookTimer( timer_handle );
+
+ /* set return value of success or failure of entire operation */
+
+ bsd_ptr = BSD_GetFirst( bsd_list );
+
+ while ( bsd_ptr != NULL ) {
+ mw_ret_val = BSD_GetOperStatus( bsd_ptr );
+ if ( mw_ret_val != SUCCESS ) {
+ break;
+ }
+ bsd_ptr = BSD_GetNext( bsd_ptr );
+ }
+
+ /* prompt for verify after if necessary */
+
+ if ( ( mw_ret_val == SUCCESS ) &&
+ ( CDS_GetAutoVerifyBackup( cds_ptr ) == PROMPT_VERIFY_AFTER ) &&
+ ( mw_oper_type != ARCHIVE_BACKUP_OPER ) ) {
+
+ if ( WM_MessageBox( ID( IDS_MSGTITLE_VERIFY ),
+ ID( RES_PROMPT_VERIFY_BACKUP ),
+ WMMB_YESNO,
+ WMMB_ICONQUESTION, NULL, 0, 0 ) ) {
+ CDS_SetAutoVerifyBackup( cds_ptr, DO_VERIFY_AFTER );
+ }
+ else {
+ CDS_SetAutoVerifyBackup( cds_ptr, NO_VERIFY_AFTER );
+ }
+ }
+
+ /* If we are doing a verify after backup, don't disable the abort button */
+ /* If we are running batch mode, JOB_STATUS_ABORT_OFF will destroy the runtime */
+ /* status window, so why call it */
+ /* If the user aborts turn the abort button off */
+
+ if ( ! CDS_GetAutoVerifyBackup( cds_ptr ) || mw_ret_val == ABNORMAL_TERMINATION ) {
+ JobStatusBackupRestore( (WORD) JOB_STATUS_ABORT_OFF );
+ }
+
+ return;
+}
+
+
+/*****************************************************************************
+
+ Name: tpos_rout
+
+ Description: Tape positioning routine passed to the Tape Format Layer.
+
+ Returns:
+
+*****************************************************************************/
+static UINT16 tpos_rout(
+UINT16 message,
+TPOS_PTR tpos,
+BOOLEAN curr_valid_vcb,
+DBLK_PTR cur_vcb,
+UINT16 mode )
+{
+ UINT16 response = UI_ACKNOWLEDGED;
+ LIS_PTR lis_ptr = (LIS_PTR)tpos->reference;
+ BSD_PTR bsd_ptr = (BSD_PTR)lis_ptr->curr_bsd_ptr;
+ CDS_PTR cds_ptr;
+ CHAR_PTR drive_name;
+ CHAR buffer[ UI_MAX_TAPENAME_LENGTH + 1 ];
+ CHAR password[ MAX_TAPE_PASSWORD_LEN + 1 ];
+ INT16 password_size = 0;
+ BOOLEAN pass_status;
+ static UINT32 old_tape_id;
+ static UINT16 old_seq_num;
+ static INT16 no_tape_retry = 0 ;
+ BOOLEAN archive_tape = FALSE;
+ INT16 msgresp;
+ INT8 num_drives;
+ TFINF_PTR fmt_info ;
+
+ cds_ptr = CDS_GetCopy();
+
+ if ( curr_valid_vcb ) {
+
+ old_tape_id = FS_ViewTapeIDInVCB( cur_vcb );
+ old_seq_num = FS_ViewTSNumInVCB( cur_vcb );
+
+ }
+
+ /* Check for needing to return to Top Of Channel in multi-drive channel */
+ if ( ( mode == TF_WRITE_OPERATION ) &&
+ ( UI_ReturnToTOC( tpos->channel, TRUE ) ) ) {
+ return UI_BEGINNING_OF_CHANNEL;
+ }
+
+ /* get a pointer to the name of the current tape device */
+ drive_name = BE_GetCurrentDeviceName( tpos->channel );
+
+ /* check for writing to write-protected tape */
+ if ( UI_CheckWriteProtectedDevice( message, tpos, drive_name ) ) {
+
+ /* instruct user to insert a new tape */
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_NEEDTAPE);
+ yresprintf( (INT16) RES_INSERT_NEW_TAPE, drive_name );
+
+ /* display the message and get a response */
+
+ if ( WM_MessageBox( ID( IDS_MSGTITLE_INSERT ),
+ gszTprintfBuffer,
+ WMMB_YESNO | WMMB_NOYYCHECK, WMMB_ICONQUESTION,
+ ID( RES_CONTINUE_QUEST ), 0, 0 ) ) {
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ no_tape_retry = 0 ;
+ return UI_NEW_TAPE_INSERTED;
+ }
+ else {
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+ QTC_BlockBad( mw_qtc_ptr );
+ QTC_AbortBackup( mw_qtc_ptr );
+ return UI_HAPPY_ABORT;
+ }
+
+ }
+
+ JobStatusBackupRestore( (WORD) JOB_STATUS_ABORT_CHECK );
+
+ /* Check for user abort */
+ if ( UI_CheckUserAbort( message ) ) {
+
+ if ( gfAbortInMiddleOfFile ) {
+
+ QTC_BlockBad( mw_qtc_ptr );
+ }
+ QTC_AbortBackup( mw_qtc_ptr);
+ return UI_ABORT_POSITIONING;
+ }
+
+ switch ( message ) {
+
+ case TF_IDLE_NOBREAK:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ WM_MultiTask();
+ break;
+
+ case TF_IDLE:
+ case TF_SKIPPING_DATA:
+ case TF_MOUNTING:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ break;
+
+ //
+ // User inserted a tape that is of the same tape family. Do not allow
+ // the user to over write this tape.
+ //
+
+ case TF_CONT_TAPE_IN_FAMILY: // chs:05-19-93
+ // chs:05-19-93
+ /* display the message and get a response */ // chs:05-19-93
+ // chs:05-19-93
+ response = (INT16)WM_MessageBox( ID( IDS_MSGTITLE_INSERT ), // chs:05-19-93
+ ID( RES_SAME_TAPE_FAMILY ), // chs:05-19-93
+ (WORD)( WMMB_OKCANCEL | WMMB_NOYYCHECK ), // chs:05-19-93
+ (WORD)WMMB_ICONQUESTION, // chs:05-19-93
+ NULL, 0, 0 ); // chs:05-19-93
+ // chs:05-19-93
+ // chs:05-19-93
+ if ( response ) { // chs:05-19-93
+ no_tape_retry = 0 ;
+ response = UI_NEW_TAPE_INSERTED; // chs:05-19-93
+ } // chs:05-19-93
+ else { // chs:05-19-93
+ QTC_AbortBackup( mw_qtc_ptr ); // chs:05-19-93
+ response = UI_HAPPY_ABORT; // chs:05-19-93
+ } // chs:05-19-93
+ // chs:05-19-93
+ break; // chs:05-19-93
+
+ case TF_VCB_EOD:
+
+ /* The tape in the current drive is positioned at NO DATE, */
+ /* and has a valid last read or last written VCB */
+ /* ( either way the VCB obtained will be the VCB */
+ /* of the last backup set on the tape). */
+
+ case TF_POSITIONED_AT_A_VCB:
+
+ WM_MultiTask();
+
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &op_stats );
+ mw_rewind = TRUE;
+
+ /* The tape in the current drive is positioned somewhere */
+ /* in the middle of the tape, and is at a valid VCB. */
+
+ /* save old tape name to use as default
+ new tape name if they choose to replace */
+ strcpy( buffer, (CHAR_PTR)FS_ViewTapeNameInVCB( cur_vcb ) );
+
+ archive_tape = IsTransferTape( FS_ViewTapeIDInVCB( cur_vcb ) );
+
+ /* If performing multi-set simultaneous backup,
+ carry forward VCB data and return to Tape Format */
+
+ /* Check for append mode */
+ if ( mode == TF_WRITE_APPEND || CDS_GetAppendFlag( cds_ptr ) ) {
+
+ /* if normal tape */
+ if ( ! archive_tape ) {
+
+ /* and this is not an archive operation */
+ if( lis_ptr->oper_type != ARCHIVE_BACKUP_OPER ) {
+ CarryForwardPasswordTapeName( bsd_ptr, cur_vcb );
+#ifdef OEM_MSOFT
+ response = (INT16)(( message == TF_VCB_EOD ) ? UI_END_POSITIONING : UI_EOD);
+#else
+ response = (INT16)(( message == TF_VCB_EOD ) ? UI_END_POSITIONING : UI_FAST_APPEND);
+#endif
+
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+ }
+ }
+ /* archive tape */
+ else {
+
+ CarryForwardPasswordTapeName( bsd_ptr, cur_vcb );
+#ifdef OEM_MSOFT
+ response = (INT16)(( message == TF_VCB_EOD ) ? UI_END_POSITIONING : UI_EOD);
+#else
+ response = (INT16)(( message == TF_VCB_EOD ) ? UI_END_POSITIONING : UI_FAST_APPEND);
+#endif
+
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+ }
+ }
+
+ /* Check for attempting to append an archive set to a "normal" backup */
+ /* Only allow user to OVERWRITE "normal" backups, no append allowed */
+
+ /* if normal tape and this is an archive operation */
+ /* and we are trying to append to this tape */
+ if ( ! archive_tape &&
+ ( lis_ptr->oper_type == ARCHIVE_BACKUP_OPER )
+ && CDS_GetAppendFlag( cds_ptr ) ) {
+
+ UI_DisplayVCB( cur_vcb );
+
+ /* tell user they can not append an archive set to a normal set */
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_NEEDTAPE);
+ yresprintf( (INT16) RES_NO_TRANSFER_APPEND );
+ if( WM_MessageBox( ID( IDS_MSGTITLE_REPLACE ),
+ gszTprintfBuffer,
+ (WORD)(WMMB_YESNO),
+ (WORD)WMMB_ICONQUESTION,
+ ID( RES_CONTINUE_QUEST ), 0, 0 ) ) {
+
+ /* if they want to continue, prompt for new tape */
+ yresprintf( (INT16) RES_INSERT_NEW_TAPE, drive_name );
+ WM_MessageBox( ID( IDS_MSGTITLE_INSERT ),
+ gszTprintfBuffer,
+ WMMB_OK,
+ WMMB_ICONEXCLAMATION, NULL, 0, 0 );
+ no_tape_retry = 0 ;
+ response = UI_NEW_TAPE_INSERTED;
+ }
+ else {
+ /* they did not want to continue */
+ response = UI_ABORT_POSITIONING;
+ }
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+
+ }
+
+ /* replace mode */
+ /* Otherwise, process as usual for write operation */
+ if ( mode != TF_WRITE_CONTINUE ) {
+
+ UI_DisplayVCB( cur_vcb );
+
+ /* if the abort flag is set, don't display any more messages */
+ if ( gb_abort_flag ) {
+ response = UI_ABORT_POSITIONING;
+
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+ }
+ else {
+ /* ask do you want to replace this tape */
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_NEEDTAPE);
+ yresprintf( (INT16) RES_REPLACE_WARNING,
+ drive_name,
+ FS_ViewTapeNameInVCB( cur_vcb ),
+ FS_ViewTSNumInVCB( cur_vcb ),
+ FS_ViewBSNumInVCB( cur_vcb ),
+ FS_ViewSetNameInVCB( cur_vcb ) );
+
+ if ( WM_MessageBox( ID( IDS_MSGTITLE_REPLACE ),
+ gszTprintfBuffer,
+ WMMB_YESNO, WMMB_ICONQUESTION,
+ NULL, 0, 0 ) ) {
+
+ /* Check if restarting to TOC is required */
+ if ( UI_ReturnToTOC( tpos->channel, FALSE ) ) {
+ response = UI_BEGINNING_OF_CHANNEL;
+
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+ }
+
+ /* display warning if attempt to replace an archive tape */
+ if ( archive_tape ) {
+ if ( ! WM_MessageBox( ID( IDS_MSGTITLE_REPLACE ),
+ ID( RES_ARCHIVE_REPLACE_WARNING ),
+ WMMB_YESNO,
+ WMMB_ICONQUESTION,
+ ID( RES_CONTINUE_QUEST ), 0, 0 ) ) {
+
+ /* user said no to replace tape */
+ /* if this is a normal tape - display can't append to a normal tape */
+ if ( ! archive_tape ) {
+ yresprintf( (INT16) RES_NO_TRANSFER_APPEND );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+ }
+ response = UI_ABORT_POSITIONING;
+
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+ }
+ }
+
+ /* Collect tape password and tape name */
+
+ response = GetPasswordAndTapeName( bsd_ptr, cur_vcb,
+ password, buffer,
+ drive_name );
+
+ if ( response == UI_OVERWRITE ) {
+ QTC_RemoveTape( old_tape_id, old_seq_num );
+ VLM_RemoveTape( old_tape_id, old_seq_num, TRUE );
+ }
+ }
+ else {
+ /* if normal tape and this is an archive operation */
+ /* don't ask the append question, prompt for a new tape */
+ if ( ! archive_tape &&
+ ( lis_ptr->oper_type == ARCHIVE_BACKUP_OPER ) ) {
+
+ response = WriteAbortOperation( drive_name );
+ }
+ else {
+ /* ask do you want to append to this tape */
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_NEEDTAPE);
+ if ( WM_MessageBox( ID( IDS_MSGTITLE_APPEND ),
+ ID( RES_APPEND_QUEST ),
+ WMMB_YESNO,
+ WMMB_ICONQUESTION,
+ NULL, 0, 0 ) ) {
+
+ CarryForwardPasswordTapeName( bsd_ptr, cur_vcb );
+#ifdef OEM_MSOFT
+ response = (INT16)(( message == TF_VCB_EOD ) ? UI_END_POSITIONING : UI_EOD);
+#else
+ response = (INT16)(( message == TF_VCB_EOD ) ? UI_END_POSITIONING : UI_FAST_APPEND);
+#endif
+
+ }
+ else {
+ response = WriteAbortOperation( drive_name );
+ }
+ }
+ }
+ }
+ }
+ else {
+
+ response = UI_BOT;
+ }
+
+ /* restart the clock with an end idle */
+ ST_EndBackupSetIdle( &op_stats );
+
+ break; /* end case TF_POSITIONED_AT_A_VCB: */
+
+ case TF_VCB_BOT:
+
+ /* The tape in the current drive is positioned at */
+ /* beginning of media, and has a valid VCB */
+
+ case TF_INVALID_VCB:
+ case TF_FUTURE_REV_MTF:
+ case TF_MTF_ECC_TAPE:
+ case TF_SQL_TAPE:
+ case TF_TAPE_OUT_OF_ORDER:
+
+ mw_rewind = TRUE;
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &op_stats );
+
+ /* The tape in the current drive is a foreign tape, */
+ /* and cannot be read. If you want you can erase the tape */
+ /* or simply overwrite it. The tape will be at the beginning */
+ /* of the tape at this point. */
+
+ buffer[0] = TEXT('\0');
+
+ if ( message == TF_VCB_BOT ) {
+
+ archive_tape = IsTransferTape( FS_ViewTapeIDInVCB( cur_vcb ) );
+
+ if ( FS_SizeofTapeNameInVCB( cur_vcb ) != 0 ) {
+ /* save old tape name to use as default new tape name if they choose to replace */
+ strcpy( buffer, (CHAR_PTR)FS_ViewTapeNameInVCB( cur_vcb ) );
+ }
+
+ UI_DisplayVCB( cur_vcb );
+
+ /* Check for append mode */
+ if ( CDS_GetAppendFlag( cds_ptr ) ) {
+
+ /* if there is a password prompt user */
+ if( FS_SizeofTapePswdInVCB( cur_vcb ) ) {
+
+ pass_status = VerifyTapePassword( (CHAR_PTR)FS_ViewTapeNameInVCB( cur_vcb ),
+ (CHAR_PTR)FS_ViewSetDescriptInVCB( cur_vcb ),
+ (CHAR_PTR)FS_ViewUserNameInVCB( cur_vcb ),
+ FS_ViewPswdEncryptInVCB( cur_vcb ),
+ (INT8_PTR)FS_ViewTapePasswordInVCB( cur_vcb ),
+ FS_SizeofTapePswdInVCB( cur_vcb ),
+ (INT8_PTR)FS_ViewSetPswdInVCB( cur_vcb ),
+ FS_SizeofSetPswdInVCB( cur_vcb ),
+ FS_ViewTapeIDInVCB( cur_vcb ) );
+
+ if ( pass_status == FALSE ) {
+ /* password was canceled */
+ response = WriteAbortOperation( drive_name );
+
+ /* restart the clock with an end idle */
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+ }
+ }
+
+ /* Before proceeding, check for attempting to append a
+ transfer backup to a non-transfer backup tape */
+
+ if ( ! archive_tape &&
+ lis_ptr->oper_type == ARCHIVE_BACKUP_OPER ) {
+
+ /* tell user they can not append an archive set to a normal set */
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_NEEDTAPE);
+ yresprintf( (INT16) RES_NO_TRANSFER_APPEND );
+ if( WM_MessageBox( ID( IDS_MSGTITLE_REPLACE ),
+ gszTprintfBuffer,
+ (WORD)( WMMB_NOYYCHECK | WMMB_YESNO ),
+ (WORD)WMMB_ICONQUESTION,
+ ID( RES_CONTINUE_QUEST ), 0, 0 ) ) {
+
+ /* if they want to continue, prompt for new tape */
+
+ yresprintf( (INT16) RES_INSERT_NEW_TAPE, drive_name );
+ WM_MessageBox( ID( IDS_MSGTITLE_INSERT ),
+ gszTprintfBuffer,
+ (WORD)(WMMB_OK | WMMB_NOYYCHECK ),
+ WMMB_ICONEXCLAMATION, NULL, 0, 0 );
+ no_tape_retry = 0 ;
+ response = UI_NEW_TAPE_INSERTED;
+ }
+ else {
+ /* they did not want to continue */
+ response = UI_ABORT_POSITIONING;
+ }
+ }
+ else {
+
+ CarryForwardPasswordTapeName( bsd_ptr, cur_vcb );
+#ifdef OEM_MSOFT
+ response = UI_EOD ;
+#else
+ response = UI_FAST_APPEND ;
+#endif
+ }
+
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+ }
+ else {
+
+ /* if the abort flag is set, don't display any more messages */
+ if ( gb_abort_flag ) {
+ response = UI_ABORT_POSITIONING;
+
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+ }
+ else {
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_NEEDTAPE);
+
+ yresprintf( (INT16) RES_REPLACE_WARNING,
+ drive_name,
+ FS_ViewTapeNameInVCB( cur_vcb ),
+ FS_ViewTSNumInVCB( cur_vcb ),
+ FS_ViewBSNumInVCB( cur_vcb ),
+ FS_ViewSetNameInVCB( cur_vcb ) );
+
+
+ if ( DidItOnce && CDS_GetYesFlag( cds_ptr ) == YESYES_FLAG ) { // chs:05-20-93
+ msgresp = (INT16)WM_MessageBox( ID( IDS_MSGTITLE_REPLACE ), // chs:05-20-93
+ gszTprintfBuffer, // chs:05-20-93
+ (WORD)WMMB_YESNO | WMMB_NOYYCHECK, // chs:05-20-93
+ (WORD)WMMB_ICONQUESTION, // chs:05-20-93
+ NULL, 0, 0 ); // chs:05-20-93
+ } else { // chs:05-20-93
+ msgresp = (INT16)WM_MessageBox( ID( IDS_MSGTITLE_REPLACE ),
+ gszTprintfBuffer,
+ (WORD)WMMB_YESNO,
+ (WORD)WMMB_ICONQUESTION,
+ NULL, 0, 0 );
+ DidItOnce = 1; // chs:05-20-93
+ } // chs:05-20-93
+ }
+ }
+ }
+ else {
+
+ /* display message that this is foreign tape format */
+ /* and disable "Yes" flag in config */
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_NEEDTAPE);
+ yresprintf( (INT16) RES_FOREIGN_TAPE_MSG2, drive_name );
+ CDS_SetYesFlag( cds_ptr, NO_FLAG );
+ msgresp = (INT16)WM_MessageBox( ID( IDS_MSGTITLE_REPLACE ),
+ gszTprintfBuffer,
+ (WORD)WMMB_YESNO,
+ (WORD)WMMB_ICONQUESTION,
+ ID( RES_REPLACE_TAPE ), 0, 0 );
+ }
+
+ /* prompt user if they wish to replace tape's contents */
+
+ if ( msgresp ) {
+
+ if ( message == TF_VCB_BOT ) {
+
+ /* display warning if attempt to replace an archive tape */
+
+ if ( archive_tape ) {
+
+ /* always prompt the user if trying to replace an archive tape */
+
+ if ( ! WM_MessageBox( ID( IDS_MSGTITLE_REPLACE ),
+ ID( RES_ARCHIVE_REPLACE_WARNING ),
+ WMMB_YESNO | WMMB_NOYYCHECK,
+ WMMB_ICONQUESTION,
+ ID( RES_CONTINUE_QUEST ), 0, 0 ) ) {
+
+ /* user said no to replace tape */
+ /* if this is a normal tape - display can't append to a normal tape */
+ if ( ! archive_tape ) {
+ yresprintf( (INT16) RES_NO_TRANSFER_APPEND );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+ }
+ response = WriteAbortOperation( drive_name );
+
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+ }
+ }
+ }
+
+ if ( mode != TF_WRITE_CONTINUE ) {
+
+ /* Check if restarting to TOC is required */
+ if ( UI_ReturnToTOC( tpos->channel, FALSE ) ) {
+ response = UI_BEGINNING_OF_CHANNEL;
+
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+ }
+
+ /* if starting a new tape, collect password and tape name */
+ response = GetPasswordAndTapeName( bsd_ptr, cur_vcb,
+ password, buffer,
+ drive_name );
+ if ( response == UI_OVERWRITE ) {
+#if defined ( OEM_MSOFT )
+{
+ INT16 passwordlength;
+ CDS_PTR cds_ptr = CDS_GetCopy();
+ CHAR passwdbuffer1[MAX_TAPE_PASSWORD_LEN + 1];
+ LPSTR generic_str_ptr;
+
+
+ if ( CDS_GetYesFlag ( CDS_GetCopy() ) == YESYES_FLAG ) {
+ if ( CDS_GetCmdLineRestrictAccess( cds_ptr ) ) {
+ generic_str_ptr = GetCurrentMachineNameUserName( );
+ passwdbuffer1[0] = NTPASSWORDPREFIX;
+ passwdbuffer1[1] = 0;
+ if ( generic_str_ptr ) {
+ strcat( passwdbuffer1, generic_str_ptr );
+ }
+ passwordlength = strlen( passwdbuffer1 ); // chs:03-10-93
+ CryptPassword( ( INT16 ) ENCRYPT, ENC_ALGOR_3, (INT8_PTR)passwdbuffer1, ( INT16 ) ( passwordlength * sizeof( CHAR ) ) ); // chs:03-10-93
+ BSD_SetTapePswd( bsd_ptr, (INT8_PTR)passwdbuffer1,( INT16 ) ( passwordlength * sizeof( CHAR ) ) ); // chs:03-10-93
+ PropagateTapePassword();
+ }
+ }
+}
+#endif
+ QTC_RemoveTape( old_tape_id, old_seq_num );
+ VLM_RemoveTape( old_tape_id, old_seq_num, TRUE );
+ }
+ }
+ else {
+
+ response = UI_OVERWRITE;
+ QTC_RemoveTape( old_tape_id, old_seq_num );
+ VLM_RemoveTape( old_tape_id, old_seq_num, TRUE );
+
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+ }
+
+ }
+ /* user decided to not replace the tape */
+ else if( mode != TF_WRITE_CONTINUE ) {
+
+ /* user can't append to foreign tape */
+
+ if ( message != TF_VCB_BOT ) {
+
+ response = WriteAbortOperation( drive_name );
+
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+ }
+
+ /* user not allowed to append an archive set
+ to a non-archive tape */
+
+ if ( ! archive_tape &&
+ lis_ptr->oper_type == ARCHIVE_BACKUP_OPER ) {
+
+ response = WriteAbortOperation( drive_name );
+
+// yresprintf( (INT16) RES_NO_TRANSFER_APPEND );
+// JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+// response = UI_ABORT_POSITIONING;
+
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+ }
+
+ fmt_info = TF_GetTapeFormat( 0 ) ;
+
+ /* if append allowed to this tape, prompt user */
+
+ if( ( fmt_info != NULL ) &&
+ ( fmt_info->attributes & APPEND_SUPPORTED ) ) {
+
+ /* prompt for append */
+
+ /* if writing to tape #1, continue to append question */
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_NEEDTAPE);
+ if ( WM_MessageBox( ID( IDS_MSGTITLE_APPEND ),
+ ID( RES_APPEND_QUEST ),
+ WMMB_YESNO,
+ WMMB_ICONQUESTION,
+ NULL, 0, 0 ) ) {
+
+ //
+ // set append flag on
+ //
+
+ CDS_PTR cds_ptr = CDS_GetCopy();
+ CDS_SetAppendFlag( cds_ptr, 1 );
+
+ if ( FS_SizeofTapePswdInVCB( cur_vcb ) != 0 ) {
+ pass_status = VerifyTapePassword( (CHAR_PTR)FS_ViewTapeNameInVCB( cur_vcb ),
+ (CHAR_PTR)FS_ViewSetDescriptInVCB( cur_vcb ),
+ (CHAR_PTR)FS_ViewUserNameInVCB( cur_vcb ),
+ FS_ViewPswdEncryptInVCB( cur_vcb ),
+ (INT8_PTR)FS_ViewTapePasswordInVCB( cur_vcb ),
+ FS_SizeofTapePswdInVCB( cur_vcb ),
+ (INT8_PTR)FS_ViewSetPswdInVCB( cur_vcb ),
+ FS_SizeofSetPswdInVCB( cur_vcb ),
+ FS_ViewTapeIDInVCB( cur_vcb ) );
+
+ if ( pass_status == FALSE ) {
+ /* password was canceled */
+ response = WriteAbortOperation( drive_name );
+
+ /* restart the clock with an end idle */
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+ }
+ }
+
+ CarryForwardPasswordTapeName( bsd_ptr, cur_vcb );
+
+#ifdef OEM_MSOFT
+ response = UI_EOD ;
+#else
+ response = UI_FAST_APPEND ;
+#endif
+ }
+ else {
+ response = WriteAbortOperation( drive_name );
+ }
+ }
+ else {
+ response = WriteAbortOperation( drive_name );
+ }
+ }
+ /* user does not wish to replace tape,
+ prompt for insert a new tape and continue */
+ else {
+
+ /* Check if restarting to TOC is required */
+
+ if ( UI_ReturnToTOC( tpos->channel, FALSE ) ) {
+ response = UI_BEGINNING_OF_CHANNEL;
+
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+ }
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_NEEDTAPE);
+ yresprintf( (INT16) RES_INSERT_NEW_TAPE, drive_name );
+
+ if ( ! WM_MessageBox( ID( IDS_MSGTITLE_INSERT ),
+ gszTprintfBuffer,
+ WMMB_YESNO | WMMB_NOYYCHECK, // chs:05-20-93
+ WMMB_ICONQUESTION,
+ ID( RES_CONTINUE_QUEST ), 0, 0 ) ) {
+ response = WriteAbortOperation( drive_name );
+
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+ }
+ no_tape_retry = 0 ;
+ response = UI_NEW_TAPE_INSERTED;
+ }
+
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+
+ case TF_ACCIDENTAL_VCB:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ mw_rewind = TRUE;
+
+ /* This message is a side effect of the the UI routine */
+ /* requesting a UI_BOT, UI_EOD, UI_NEW_POSITION_REQUESTED, */
+ /* and is just a way of saying to the UI routine, "Hey, we just */
+ /* passed a VCB, and I just thought that I would tell you about it!" */
+
+ UI_DisplayVCB( cur_vcb );
+
+ /* catalog it partial, if we've never seen it. */
+
+ if ( QTC_FindBset( FS_ViewTapeIDInVCB( cur_vcb ),
+ FS_ViewTSNumInVCB( cur_vcb ),
+ FS_ViewBSNumInVCB( cur_vcb ) ) == NULL ) {
+
+ mw_qtc_ptr = QTC_GetBuildHandle( );
+ QTC_DoFullCataloging( mw_qtc_ptr, FALSE );
+ QTC_StartBackup( mw_qtc_ptr, cur_vcb );
+ QTC_FreeBuildHandle( mw_qtc_ptr );
+ mw_qtc_ptr = NULL;
+ }
+ break;
+
+ case TF_WRONG_TAPE:
+
+ // Once we start an append they are not allowed to switch tape
+ // families on us. They did that, inserted a blank tape or used
+ // a tape of the same family, but wrong sequence number
+
+ // if tape IDs differ, display wrong family message,
+ // else ask for the next tape
+
+ // Note: when we Dismounted the tape, curr_valid_vcb became FALSE,
+ // but we can't NOT look at the last vcb if we want to make the
+ // following test
+
+ // One more thing: if we have a blank tape here, the vcb looked at
+ // belonged to whatever was in the drive prior to the blank tape.
+ // the test will pass or fail accordingly (ugh!)
+
+ if( FS_ViewTapeIDInVCB( cur_vcb ) != (UINT32)tpos->tape_id ) {
+
+ WM_MsgBox( ID( IDS_BACKUPERRORTITLE ),
+ ID( IDS_BACKUPWRONGFAMILY),
+ WMMB_OK,
+ WMMB_ICONEXCLAMATION );
+ }
+
+ // falling through ...
+
+ case TF_NEED_NEW_TAPE:
+
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &op_stats );
+ mw_rewind = TRUE;
+
+ /* This message is used to request that the UI routine prompt, or cause */
+ /* a new tape to be inserted in the tape drive. This message is sent */
+ /* as a side effect of UI_EOD, or UI_NEW_POSITION_REQUESTED. */
+
+ /* display user prompt as needed */
+
+ if( CDS_GetYesFlag( cds_ptr ) == YESYES_FLAG ) {
+ mw_yes_flag_was_set = TRUE ;
+ CDS_SetYesFlag( cds_ptr, NO_FLAG ) ;
+ }
+
+ if ( ( mode != TF_WRITE_OPERATION ) &&
+ ( BE_CheckMultiDrive( tpos->channel ) == BE_END_OF_CHANNEL ) ) {
+
+ num_drives = UI_TapeDriveCount( );
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_NEEDTAPE);
+ yresprintf( (INT16) RES_INSERT_MULTI_TAPES,
+ FS_ViewTSNumInVCB( cur_vcb ) + 1,
+ FS_ViewTSNumInVCB( cur_vcb ) + num_drives,
+ 1,
+ num_drives );
+
+ response = (INT16)WM_MessageBox( ID( IDS_MSGTITLE_INSERT ),
+ gszTprintfBuffer,
+ (WORD)WMMB_YESNO,
+ (WORD)WMMB_ICONQUESTION,
+ ID( RES_CONTINUE_QUEST ), 0, 0 );
+
+ } else {
+
+ if( mwReplaceModeFlag ) {
+ yresprintf( (INT16) RES_INSERT_NEXT_TAPE,
+ mwReplaceTapeCount += 1,
+ BE_GetCurrentDeviceName( tpos->channel ) );
+ }
+ else {
+ // if PositionAtSet knows what it wants, be sure to advertise
+ // what's in tpos (as with UI_FAST_APPEND & UI_EOD)
+ // otherwise, use the cur_vcb (as with overwrite)
+
+ INT16 tape_sequence = ( tpos->tape_seq_num != -1 ) ?
+ tpos->tape_seq_num :
+ (FS_ViewTSNumInVCB( cur_vcb ) + 1) ;
+
+
+ yresprintf( (INT16) RES_INSERT_NEXT_TAPE,
+ tape_sequence,
+ BE_GetCurrentDeviceName( tpos->channel ) );
+ }
+
+ //
+ // Just a note: at this point the tape in the current
+ // drive has already been rewound to the beginning
+ // of the tape. So we do not need to tell user to wait
+ // for tape to finish rewinding
+ //
+
+ response = (INT16)WM_MessageBox( ID( IDS_MSGTITLE_INSERT ),
+ ID( RES_TAPE_FULL_REWOUND ), // chs:05-03-93
+ (WORD)WMMB_OKCANCEL,
+ (WORD)WMMB_ICONQUESTION,
+ gszTprintfBuffer,
+ IDRBM_LTAPE, 0 );
+ }
+
+ if ( response ) {
+ no_tape_retry = 0 ;
+ response = UI_NEW_TAPE_INSERTED;
+ DidItOnce = 1; // chs:05-20-93
+
+#ifdef OS_WIN32
+ if( mwReplaceModeFlag ) {
+ NtDemoChangeTape( mwReplaceTapeCount ) ;
+ } else {
+ NtDemoChangeTape( (UINT16)(FS_ViewTSNumInVCB( cur_vcb ) + 1u ) ) ;
+ }
+#endif
+ }
+ else {
+
+ QTC_AbortBackup( mw_qtc_ptr );
+ response = UI_HAPPY_ABORT;
+ }
+
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+
+ case TF_NO_TAPE_PRESENT:
+
+ mw_rewind = TRUE;
+
+#ifdef OS_WIN32
+ if ( no_tape_retry <= mwTapeSettlingCount ) {
+ Sleep( 3000 ) ;
+ response = UI_NEW_TAPE_INSERTED ;
+ no_tape_retry ++ ;
+ break ;
+ }
+#endif
+
+ /* There is no tape present in the current drive */
+
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &op_stats );
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_NEEDTAPE);
+ SetStatusBlock(IDSM_DRIVESTATUS, STAT_DRIVE_EMPTY);
+ response = UI_InsertTape( drive_name );
+
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+
+ case TF_UNRECOGNIZED_MEDIA:
+
+ mw_rewind = TRUE;
+
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &op_stats );
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+ SetStatusBlock(IDSM_DRIVESTATUS, STAT_DRIVE_FOREIGN);
+ yresprintf( (INT16) IDS_VLMUNFORMATEDTEXT ) ;
+ WM_MessageBox( ID( IDS_VLMUNFORMATEDTITLE ) ,
+ gszTprintfBuffer ,
+ WMMB_OK,
+ WMMB_ICONEXCLAMATION, NULL, 0, 0 ) ;
+
+ /* instruct user to insert a new tape */
+ /* display the message and get a response */
+
+ yresprintf( (INT16) RES_INSERT_NEW_TAPE, drive_name );
+ if ( WM_MessageBox( ID( IDS_MSGTITLE_INSERT ),
+ gszTprintfBuffer,
+ WMMB_YESNO, WMMB_ICONQUESTION,
+ ID( RES_CONTINUE_QUEST ), 0, 0 ) ) {
+
+ no_tape_retry = 0 ;
+ return UI_NEW_TAPE_INSERTED;
+ }
+ else {
+
+ QTC_AbortBackup( mw_qtc_ptr );
+ return UI_HAPPY_ABORT;
+ }
+
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+
+ case TF_NO_MORE_DATA:
+
+ /* This is sent to the UI rountine as a result of doing a UI_EOD. */
+
+ case TF_POSITIONED_FOR_WRITE:
+
+ /* This message is returned in response to a UI_OVERWRITE message. */
+ /* when the tape pos routine has successfully positioned for overwrite */
+ /* of the requested backup set. */
+
+ case TF_EMPTY_TAPE:
+
+
+#if defined ( OEM_MSOFT )
+{
+ //
+ // Allows /R restrict access to owner on a blank tape when doing
+ // a batch command line backup
+ //
+
+ INT16 passwordlength;
+ CDS_PTR cds_ptr = CDS_GetCopy();
+ CHAR passwdbuffer1[MAX_TAPE_PASSWORD_LEN + 1];
+ LPSTR generic_str_ptr;
+
+
+ if ( CDS_GetYesFlag ( CDS_GetCopy() ) == YESYES_FLAG ) {
+ if ( CDS_GetCmdLineRestrictAccess( cds_ptr ) ) {
+ generic_str_ptr = GetCurrentMachineNameUserName( );
+ passwdbuffer1[0] = NTPASSWORDPREFIX;
+ passwdbuffer1[1] = 0;
+ if ( generic_str_ptr ) {
+ strcat( passwdbuffer1, generic_str_ptr );
+ }
+ passwordlength = strlen( passwdbuffer1 );
+ CryptPassword( ( INT16 ) ENCRYPT, ENC_ALGOR_3, (INT8_PTR)passwdbuffer1, ( INT16 ) ( passwordlength * sizeof( CHAR ) ) );
+ BSD_SetTapePswd( bsd_ptr, (INT8_PTR)passwdbuffer1,( INT16 ) ( passwordlength * sizeof( CHAR ) ) );
+ PropagateTapePassword();
+ }
+ }
+}
+#endif
+
+ SetStatusBlock(IDSM_DRIVESTATUS, STAT_DRIVE_EMPTY);
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_NEEDTAPE);
+ mw_rewind = TRUE;
+
+ /* The tape in the current drive is empty. */
+
+ response = UI_END_POSITIONING;
+ break;
+
+ case TF_READ_ERROR:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &op_stats );
+
+ mw_rewind = TRUE;
+ response = UI_HandleTapeReadError( drive_name );
+
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+
+ case TF_SEARCHING:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ mw_rewind = TRUE;
+
+ /* This message is sent to the UI routine to inform it that it is spacing */
+ /* the tape on the current drive. This message will only be sent once during */
+ /* the space operation. */
+
+ yresprintf( (INT16) RES_SEARCHING );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+ break;
+
+ case TF_REWINDING:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ /* This message is sent to the UI routine to inform it that it is rewinding */
+ /* the tape on the current drive. This message will only be sent once during */
+ /* the rewind operation. */
+
+ if ( mw_rewind ) {
+ yresprintf( (INT16) RES_REWINDING );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+ mw_rewind = FALSE;
+ }
+ break;
+
+ case TF_DRIVE_BUSY:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ SetStatusBlock(IDSM_DRIVESTATUS, STAT_DRIVE_BUSY);
+ break;
+
+ case TF_FAST_SEEK_EOD:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+#ifndef OEM_MSOFT
+ yresprintf( (INT16) RES_SEARCHING_FOR_EOD );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+#endif
+
+ break;
+
+ case TF_END_CHANNEL:
+
+ mw_rewind = TRUE;
+ eresprintf( RES_END_CHANNEL );
+ response = UI_ABORT_POSITIONING;
+ break;
+
+ default:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+ mw_rewind = TRUE;
+ eresprintf( RES_UNKNOWN_TF_MSG, message );
+ QTC_BlockBad( mw_qtc_ptr );
+ QTC_AbortBackup( mw_qtc_ptr );
+ response = UI_ABORT_POSITIONING;
+ break;
+ }
+
+ if( mw_yes_flag_was_set &&
+ ( response == UI_HAPPY_ABORT ||
+ response == UI_OVERWRITE ||
+ response == UI_END_POSITIONING ||
+ response == UI_ABORT_POSITIONING ) ) {
+
+ mw_yes_flag_was_set = FALSE ;
+ CDS_SetYesFlag( cds_ptr, YESYES_FLAG ) ;
+ }
+
+ return( response );
+}
+
+/*****************************************************************************
+
+ Name: backup_msg_hndlr
+
+ Description: Backup message handler called by the loops
+
+ Returns:
+
+*****************************************************************************/
+
+static UINT16 backup_msg_hndlr(
+UINT16 msg,
+INT32 pid,
+BSD_PTR bsd_ptr,
+FSYS_HAND fsh,
+TPOS_PTR tpos,
+... )
+{
+ static CHAR delimiter = TEXT('#'); /* = # for debug */
+ INT16 response = MSG_ACK;
+ va_list arg_ptr;
+ static CHAR_PTR buffer ;
+ CHAR_PTR buffer1; // chs:06-09-93
+ static CHAR_PTR file_buf ;
+ CHAR volume[ UI_MAX_VOLUME_LENGTH ];
+ INT16 size;
+ time_t t_time;
+ CHAR date_str[MAX_UI_DATE_SIZE];
+ CHAR time_str[MAX_UI_TIME_SIZE];
+ CHAR backup_method[MAX_UI_RESOURCE_SIZE] ;
+ DBLK_PTR dblk_ptr;
+ OBJECT_TYPE object_type;
+ UINT64 count;
+ GENERIC_DLE_PTR dle;
+ INT16 res_id;
+ INT16 error;
+ DBLK_PTR vcb_dblk_ptr;
+ DBLK_PTR ddb_dblk_ptr;
+ DBLK_PTR fdb_dblk_ptr;
+ CHK_OPEN TryOpen;
+ UINT32 parm;
+ CDS_PTR cds_ptr;
+ INT16 skip_open_files;
+ UINT64 num_bytes;
+ CHAR numeral[ UI_MAX_NUMERAL_LENGTH ];
+ BOOLEAN stat ;
+ UINT32 strm_id ;
+
+ DBG_UNREFERENCED_PARAMETER ( pid );
+
+ /* set up first argument */
+ cds_ptr = CDS_GetCopy();
+
+ va_start( arg_ptr, tpos );
+
+ JobStatusBackupRestore( (WORD) JOB_STATUS_ABORT_CHECK );
+
+ switch ( (INT16)msg ) {
+
+
+#ifdef MS_RELEASE
+ case -533:
+ // We are talking kludge city here. Keep the error
+ // message from being displayed to the user.
+ zprintf( DEBUG_TEMPORARY, TEXT("** -533 LOOPS ERROR **") );
+ break;
+#endif
+
+
+ case MSG_CONT_VCB:
+ // This message was added to support 4.0 tape format. The
+ // continuation vcb PBA & LBA cannot be assumed to be 0
+ // because a tape header is placed on the tape. The backup
+ // engine does not know them until it gets the next tape and
+ // writes them on it. This call allows you to go back and
+ // patch the catalogs.
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+
+ QTC_PatchContinuationVCB( mw_qtc_ptr, dblk_ptr );
+ break;
+
+
+ case MSG_LOG_STREAM_NAME:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ buffer1 = va_arg( arg_ptr, CHAR_PTR );
+
+ lresprintf( LOGGING_FILE, LOG_STREAM, fsh, buffer1 );
+
+ break;
+
+ case MSG_LOG_BLOCK:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+
+ switch( FS_GetBlockType( dblk_ptr ) ) {
+
+ case BT_VCB:
+ break;
+
+ case BT_DDB:
+
+ QTC_AddToCatalog( mw_qtc_ptr, dblk_ptr, fsh, FALSE, NULL, 0 );
+
+ /* clear last displayed filename from status display */
+
+ UI_BuildDelimitedPathFromDDB( &buffer, fsh, dblk_ptr, delimiter, FALSE );
+
+ if ( buffer != NULL ) {
+
+ strcpy( mwCurrentPath, buffer );
+ strcpy( mwCurrentFile, TEXT( "" ) );
+
+ if ( DLE_GetDeviceType(BSD_GetDLE( bsd_ptr) ) == FS_EMS_DRV ) {
+
+ yprintf( TEXT("%s"), mwCurrentPath+1 );
+ JobStatusBackupRestore( JOB_STATUS_DIRECTORY_NAMES );
+ } else {
+ yprintf( TEXT("%s"), mwCurrentPath );
+ JobStatusBackupRestore( JOB_STATUS_DIRECTORY_NAMES );
+
+ yprintf( TEXT("%s"), mwCurrentFile );
+ JobStatusBackupRestore( JOB_STATUS_FILE_NAMES );
+ }
+
+ SetStatusBlock(IDSM_OFFSETACTIVEDIR, (LONG)(LPSTR)mwCurrentPath);
+
+ // build the full path with no "..." inserted
+ UI_BuildFullPathFromDDB2( &buffer, fsh, dblk_ptr, delimiter, FALSE );
+
+ yprintf( TEXT("%s"), buffer );
+
+ ST_EndBackupSet( &op_stats );
+
+ dle = BSD_GetDLE( bsd_ptr ); // chs:06-09-93
+ if ( (DLE_GetDeviceType(BSD_GetDLE( bsd_ptr) ) != FS_EMS_DRV ) &&
+ ( dle->device_name_leng ) ) {
+ buffer1 = (CHAR_PTR)calloc( 1, ( strlen( buffer ) * sizeof( CHAR ) ) + ( ( dle->device_name_leng ) * sizeof( CHAR ) ) + sizeof( CHAR ) ); // chs:06-09-93
+ if ( buffer1 ) { // chs:06-09-93
+ strcpy( buffer1, dle->device_name ); // chs:06-09-93
+ strcat( buffer1, buffer ); // chs:06-09-93
+ // chs:06-09-93
+ lresprintf( LOGGING_FILE, LOG_DIRECTORY, SES_ENG_MSG, RES_DIRECTORY, buffer1 ); // chs:06-09-93
+ free( buffer1 ); // chs:06-09-93
+ } else { // chs:06-09-93
+ // chs:06-09-93
+ lresprintf( LOGGING_FILE, LOG_DIRECTORY, SES_ENG_MSG, RES_DIRECTORY, buffer ); // chs:06-09-93
+ } // chs:06-09-93
+ } else if (DLE_GetDeviceType(BSD_GetDLE( bsd_ptr) ) != FS_EMS_DRV ) {
+ lresprintf( LOGGING_FILE, LOG_DIRECTORY, SES_ENG_MSG, RES_DIRECTORY, buffer ); // chs:06-09-93
+ } // chs:06-09-93
+ }
+ break;
+
+ case BT_FDB:
+
+ QTC_AddToCatalog( mw_qtc_ptr, dblk_ptr, fsh, FALSE, NULL, 0 );
+
+ ST_SetCFSize( &op_stats, FS_GetDisplaySizeFromDBLK( fsh, dblk_ptr ) );
+ ST_SetCFDone( &op_stats, U64_Init( 0L, 0L ) );
+
+ if ( UI_AllocPathBuffer( &buffer, FS_SizeofFnameInFDB( fsh, dblk_ptr ) ) ) {
+ FS_GetFnameFromFDB( fsh, dblk_ptr, buffer );
+
+ // copy the full file name for the Log file
+ yprintf( TEXT("%s"), buffer );
+ lresprintf( LOGGING_FILE, LOG_FILE, fsh, dblk_ptr );
+
+ SetStatusBlock(IDSM_OFFSETACTIVEFILE, (DWORD)buffer );
+
+ // truncate the file name, if needed, for Runtime display
+ UI_DisplayFile( buffer );
+
+ strcpy( mwCurrentFile, gszTprintfBuffer );
+ JobStatusBackupRestore( JOB_STATUS_FILE_NAMES );
+
+ ST_EndBackupSet( &op_stats );
+ }
+ }
+ break;
+
+ /* statistics messages */
+ case MSG_BLOCK_PROCESSED:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+
+ switch( FS_GetBlockType( dblk_ptr ) ) {
+
+ case BT_DDB:
+
+ ST_AddBSDirsProcessed( &op_stats, 1 );
+ yprintf(TEXT("%ld\r"), ST_GetBSDirsProcessed( &op_stats ) );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_DIRECTORIES_PROCESS );
+
+ break;
+
+ case BT_FDB:
+
+ // Should we stop at the end of this file.
+
+ if ( gbAbortAtEOF ) {
+ gb_abort_flag = ABORT_PROCESSED;
+ }
+
+ // commented out because it screws up the file name
+ // display if timer goes off between files. mikep
+
+ // strcpy( mwCurrentFile, TEXT( "" ) );
+
+ ST_SetCFSize( &op_stats, U64_Init( 0L, 0L ) );
+ ST_SetCFDone( &op_stats, U64_Init( 0L, 0L ) );
+
+ ST_AddBSFilesProcessed( &op_stats, 1 );
+
+ yprintf(TEXT("%ld\r"), ST_GetBSFilesProcessed( &op_stats ) );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_FILES_PROCESSED );
+
+ FS_GetObjTypeDBLK( fsh, dblk_ptr, &object_type );
+ if ( object_type == AFP_OBJECT ) {
+ ST_AddBSAFPFilesProcessed( &op_stats, 1 );
+ }
+ break;
+ }
+ break;
+
+ case MSG_BYTES_PROCESSED:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ count = va_arg( arg_ptr, UINT64 );
+
+
+ if ( mwfAbortDisabledForEOM ) {
+
+ mwfAbortDisabledForEOM = FALSE;
+
+ /* enable the abort button for the runtime dialog */
+ JobStatusBackupRestore( (WORD) JOB_STATUS_ABORT_ENABLE );
+ }
+
+ ST_AddBSBytesProcessed( &op_stats, count );
+ ST_AddCFDone( &op_stats, count );
+
+ /* perform percentage completion calcs */
+
+ ST_EndBackupSet( &op_stats );
+ break;
+
+ case MSG_START_OPERATION:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ lresprintf( LOGGING_FILE, LOG_START, FALSE );
+
+ /* display operation title in log file */
+
+ if( mw_oper_type == ARCHIVE_BACKUP_OPER ) {
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, IDS_DLGTITLEJOBSTATTRANSFER ) ;
+ }
+ else {
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, IDS_DLGTITLEJOBSTATBACKUP ) ;
+ }
+
+ break;
+
+ case MSG_END_OPERATION:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ // See if an error occurred in the catalogs.
+
+ UI_FreePathBuffer( &buffer ) ;
+ UI_FreePathBuffer( &file_buf ) ;
+
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &op_stats );
+ VLM_CheckForCatalogError( mw_qtc_ptr );
+ ST_EndBackupSetIdle( &op_stats );
+
+ lresprintf( LOGGING_FILE, LOG_END );
+ UI_ChkDispGlobalError( );
+ break;
+
+ case MSG_START_BACKUP_SET:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+ dle = BSD_GetDLE( bsd_ptr );
+
+ strcpy( mwCurrentDrive, DLE_GetDeviceName( dle ) );
+ mwCurrentPath[ 0 ] = TEXT( '\0' );
+ mwCurrentFile[ 0 ] = TEXT( '\0' );
+
+ mw_qtc_ptr = QTC_GetBuildHandle( );
+ QTC_DoFullCataloging( mw_qtc_ptr, BSD_GetFullyCataloged( bsd_ptr ) );
+ QTC_StartBackup( mw_qtc_ptr, dblk_ptr );
+
+#ifdef OEM_EMS
+ RT_BSD_OsId = DLE_GetOsId( dle );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_FS_TYPE );
+#endif OEM_EMS
+
+ BSD_SetOperStatus( bsd_ptr, SUCCESS );
+
+ if ( DLE_HasFeatures( dle, DLE_FEAT_REMOTE_DRIVE ) ) {
+ JobStatusBackupRestore( (WORD) JOB_STATUS_VOLUME_NETDRIVE );
+ }
+ else {
+ JobStatusBackupRestore( (WORD) JOB_STATUS_VOLUME_HARDDRIVE );
+ }
+
+ yprintf(TEXT("%s\r"), FS_ViewVolNameInVCB( dblk_ptr ) );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_SOURCE_NAME );
+
+ yprintf(TEXT("%s\r"), BSD_GetTapeLabel( bsd_ptr) );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_DEST_NAME );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_DISPLAY_TAPE,
+ BSD_GetTapeLabel ( bsd_ptr) );
+
+ yresprintf( (INT16) RES_DISPLAY_VOLUME,
+ FS_ViewVolNameInVCB( dblk_ptr ),
+ FS_ViewBSNumInVCB( dblk_ptr ),
+ FS_ViewTSNumInVCB( dblk_ptr ),
+ FS_ViewSetNameInVCB( dblk_ptr ) );
+
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+
+#ifdef OEM_MSOFT // chs:05-06-93
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_DISPLAY_VOLUME_1, // chs:05-06-93
+#else // chs:05-06-93
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_DISPLAY_VOLUME, // chs:05-06-93
+#endif // chs:05-06-93
+ FS_ViewVolNameInVCB( dblk_ptr ),
+ FS_ViewBSNumInVCB( dblk_ptr ),
+ FS_ViewTSNumInVCB( dblk_ptr ),
+ FS_ViewSetNameInVCB( dblk_ptr ) );
+
+ res_id = 0 ;
+
+ switch (BSD_GetBackupType( bsd_ptr) ) {
+ case BSD_BACKUP_NORMAL:
+ res_id = 0 ;
+ break;
+ case BSD_BACKUP_COPY:
+ res_id = 1 ;
+ break;
+ case BSD_BACKUP_DIFFERENTIAL:
+ res_id = 3 ;
+ break;
+ case BSD_BACKUP_INCREMENTAL:
+ res_id = 2 ;
+ break;
+ case BSD_BACKUP_DAILY:
+ res_id = 4 ;
+ break;
+ }
+
+ RSM_StringCopy( IDS_METHOD_NORMAL + res_id,
+ backup_method, 255 );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, IDS_BACKUP_TYPE, backup_method) ;
+
+ SetStatusBlock( IDSM_TAPEFAMILY, (DWORD)FS_ViewTapeIDInVCB( dblk_ptr ) );
+ SetStatusBlock( IDSM_TAPESEQNUMBER, (DWORD)FS_ViewTSNumInVCB( dblk_ptr ) );
+ SetStatusBlock( IDSM_BACKUPSET, (DWORD)FS_ViewBSNumInVCB( dblk_ptr ) );
+
+ SetStatusBlock( IDSM_OFFSETDISKNAME, (DWORD)FS_ViewVolNameInVCB( dblk_ptr ) );
+
+# if defined ( OS_WIN32 ) //special feature-EventLogging
+ {
+ INT16 nAppendFlag;
+ cds_ptr = CDS_GetCopy();
+ mwErrorDuringBackupSet = FALSE;
+
+ if (mwnTransaction != TRAN_START)
+ {
+ nAppendFlag = 1;
+ } else
+ {
+ nAppendFlag = CDS_GetAppendFlag(cds_ptr);
+ mwnTransaction = TRAN_CONT;
+ }
+
+ OMEVENT_LogBeginBackup (
+ (CHAR_PTR)FS_ViewVolNameInVCB( dblk_ptr ),
+ CDS_GetAutoVerifyBackup ( cds_ptr ),
+ nAppendFlag,
+ BSD_GetBackupType ( bsd_ptr ) );
+ }
+# endif //defined ( OS_WIN32 ) //special feature-EventLogging
+
+ delimiter = (CHAR)DLE_GetPathDelim( dle );
+
+ /* If we are backing up the catalogs and this is a new tape */
+ /* family, add the QTC filename to the catalog include list. */
+
+ if ( CDS_GetBackupCatalogs( cds_ptr ) &&
+ ( BSD_GetTapeNum( bsd_ptr ) == 1 ) &&
+ ( BSD_GetSetNum( bsd_ptr ) == 1 ) ) {
+
+ VLM_AddFileForInclude( BSD_GetTapeID( bsd_ptr ), (UINT16)1,
+ USE_WILD_CARD );
+ }
+
+ ST_StartBackupSet( &op_stats );
+
+ UI_Time( &op_stats, RES_BACKUP_STARTED, UI_START );
+
+ clock_ready_flag = TRUE;
+
+ // Call the clock routine to clear out his directory buffers.
+
+ clock_routine();
+
+ break;
+
+
+ case MSG_END_BACKUP_SET:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+
+ // update stats
+ clock_routine();
+
+ mwCurrentPath[ 0 ] = TEXT( '\0' );
+ mwCurrentFile[ 0 ] = TEXT( '\0' );
+
+ /* turn off the real time clock */
+ clock_ready_flag = FALSE;
+
+ /* record the time that we finished */
+ ST_EndBackupSet( &op_stats );
+
+ SetStatusBlock(IDSM_DIRCOUNT, (DWORD)0 );
+ SetStatusBlock(IDSM_FILECOUNT, (DWORD)0 );
+ SetStatusBlock(IDSM_BYTECOUNTLO, (DWORD)0 );
+ SetStatusBlock(IDSM_BYTECOUNTHI, (DWORD)0 );
+ SetStatusBlock(IDSM_ELAPSEDSECONDS, (DWORD)0 );
+ SetStatusBlock(IDSM_CORRUPTFILECOUNT, (DWORD)0 );
+ SetStatusBlock(IDSM_SKIPPEDFILECOUNT, (DWORD)0 );
+
+ SetStatusBlock(IDSM_OFFSETACTIVEFILE, (DWORD)TEXT( "" ) );
+ SetStatusBlock(IDSM_OFFSETACTIVEDIR, (DWORD)TEXT("" ) );
+ SetStatusBlock(IDSM_OFFSETDISKNAME, (DWORD)TEXT("" ) );
+
+ /* force an update to the bytes counter */
+ num_bytes = ST_GetBSBytesProcessed ( &op_stats );
+
+ U64_Litoa( num_bytes, numeral, (UINT16)10, &stat ) ;
+ UI_BuildNumeralWithCommas( numeral );
+ yprintf(TEXT("%s\r"),numeral );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_BYTES_PROCESSED );
+
+ /* did the user abort or finish normal */
+
+ if ( gb_abort_flag ) {
+ if ( gfAbortInMiddleOfFile ) {
+ QTC_BlockBad( mw_qtc_ptr );
+ }
+ QTC_AbortBackup( mw_qtc_ptr );
+ }
+ else {
+ QTC_FinishBackup( mw_qtc_ptr );
+ }
+ QTC_FreeBuildHandle( mw_qtc_ptr );
+ mw_qtc_ptr = NULL;
+
+ if ( ST_GetBSFilesBad( &op_stats ) ||
+ ST_GetBSDirsBad( &op_stats ) ||
+ ST_GetBSFilesSkipped( &op_stats ) ||
+ ST_GetBSDirsSkipped( &op_stats ) ) {
+ BSD_SetOperStatus( bsd_ptr, FILES_SKIPPED );
+ }
+
+ /* display and log any abort conditions */
+ UI_ConditionAtEnd( );
+
+ UI_Time( &op_stats, RES_BACKUP_COMPLETED, UI_END );
+
+ /* produce stats for dirs & files */
+ /* display number of files / number of dirs */
+
+ dle = BSD_GetDLE( bsd_ptr );
+ if ( DLE_GetDeviceType( dle ) != FS_EMS_DRV ) {
+ if( ST_GetBSFilesProcessed( &op_stats ) == 1 &&
+ ST_GetBSDirsProcessed( &op_stats ) == 1) {
+ res_id = RES_BACKED_UP_DIR_FILE;
+ }
+ else if( ST_GetBSFilesProcessed( &op_stats ) == 1 &&
+ ST_GetBSDirsProcessed( &op_stats ) > 1) {
+ res_id = RES_BACKED_UP_DIRS_FILE;
+ }
+ else if( ST_GetBSDirsProcessed( &op_stats ) == 1 &&
+ ST_GetBSFilesProcessed( &op_stats ) > 1) {
+ res_id = RES_BACKED_UP_DIR_FILES;
+ }
+ else {
+ res_id = RES_BACKED_UP_DIRS_FILES;
+ }
+
+ yresprintf( res_id,
+ ST_GetBSFilesProcessed( &op_stats ),
+ ST_GetBSDirsProcessed( &op_stats ) );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, res_id,
+ ST_GetBSFilesProcessed( &op_stats ),
+ ST_GetBSDirsProcessed( &op_stats ) );
+ }
+
+# if defined ( OS_WIN32 ) //special feature-EventLogging
+ {
+ OMEVENT_LogEndBackup (
+ mwErrorDuringBackupSet );
+ }
+# endif //defined ( OS_WIN32 ) //special feature-EventLogging
+
+
+ /* display number of mac files backed up */
+ if ( ST_GetBSAFPFilesProcessed( &op_stats ) > 0 ) {
+
+ if ( ST_GetBSAFPFilesProcessed( &op_stats ) == 1 ) {
+ res_id = RES_BACKED_UP_MAC;
+ }
+ else {
+ res_id = RES_BACKED_UP_MACS;
+ }
+
+ yresprintf( res_id,
+ ST_GetBSAFPFilesProcessed( &op_stats ) );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, res_id,
+ ST_GetBSAFPFilesProcessed( &op_stats ) );
+ }
+
+ /* display number of corrupt files backed up */
+ if ( ST_GetBSFilesBad( &op_stats ) > 0 ) {
+
+// Remove this functionality (no-one liked it)
+ /* close the corrupt log file since it was used */
+// lresprintf( CORRUPT_FILE, LOG_END );
+
+ if ( ST_GetBSFilesBad( &op_stats ) == 1 ) {
+ res_id = RES_BACKED_UP_CORRUPT;
+ }
+ else {
+ res_id = RES_BACKED_UP_CORRUPTS;
+ }
+
+ yresprintf( res_id, ST_GetBSFilesBad( &op_stats ) );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, res_id,
+ ST_GetBSFilesBad( &op_stats ) );
+ }
+
+ /* display number of in-use files backed up */
+ if ( ST_GetBSInUseFilesProcessed( &op_stats ) > 0 ) {
+
+ if( ST_GetBSInUseFilesProcessed( &op_stats ) == 1 ) {
+ res_id = RES_BACKED_UP_IN_USE;
+ }
+ else {
+ res_id = RES_BACKED_UP_IN_USES;
+ }
+
+ yresprintf( res_id,
+ ST_GetBSInUseFilesProcessed( &op_stats ) );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, res_id,
+ ST_GetBSInUseFilesProcessed( &op_stats ) );
+ }
+
+ /* display number of files skipped backed up */
+ if ( ST_GetBSFilesSkipped( &op_stats ) > 0 ) {
+
+ /* close the skipped script log file if required since it was used */
+ if( CDS_GetCreateSkipped( cds_ptr ) ) {
+ lresprintf( SKIPPED_FILE, LOG_END );
+ }
+
+ if( ST_GetBSFilesSkipped( &op_stats ) == 1 ) {
+ res_id = RES_FILE_SKIPPED_STAT;
+ }
+ else {
+ res_id = RES_FILE_SKIPPEDS_STAT;
+ }
+
+ yresprintf( res_id, ST_GetBSFilesSkipped( &op_stats ) );
+
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, res_id,
+ ST_GetBSFilesSkipped( &op_stats ) );
+ }
+
+ /* display number of bytes processed */
+ UI_BytesProcessed( &op_stats );
+
+ /* display backup rate */
+ UI_RateProcessed( &op_stats );
+
+ delimiter = TEXT('#'); /* = # for debug */
+
+ break;
+
+ case MSG_BLOCK_SKIPPED:
+ case MSG_BLOCK_INUSE:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+ ddb_dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+
+ if ( (msg == MSG_BLOCK_INUSE ) &&
+ ( DLE_GetDeviceType(BSD_GetDLE( bsd_ptr) ) == FS_EMS_DRV ) ) {
+
+ QTC_BlockBad( mw_qtc_ptr );
+ yresprintf( (INT16)IDS_XCHNG_BKUP_IN_PROG );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+
+ lprintf( LOGGING_FILE, gszTprintfBuffer );
+ lprintf( LOGGING_FILE, TEXT("\n") );
+
+ return(response);
+
+ }
+
+
+ switch( FS_GetBlockType( dblk_ptr ) ) {
+
+ case BT_DDB:
+
+ ST_AddBSDirsSkipped( &op_stats, 1 );
+ break;
+
+ case BT_FDB:
+
+ /* if this is the first entry for this backup set AND if required then set up the file ... */
+ if ( ( ST_GetBSFilesSkipped( &op_stats ) == 0 ) &&
+ ( CDS_GetCreateSkipped( cds_ptr ) ) ) {
+ lresprintf( SKIPPED_FILE, LOG_START, FALSE );
+ size = DLE_SizeofVolName ( BSD_GetDLE( bsd_ptr ) );
+ DLE_GetVolName( BSD_GetDLE( bsd_ptr ), volume );
+
+ t_time = ST_GetBSStartTime( &op_stats );
+ UI_LongToDate( date_str, t_time );
+ UI_LongToTime( time_str, t_time );
+
+ lresprintf( SKIPPED_FILE, LOG_MSG, SES_ENG_MSG,
+ RES_SKIPPED_SCRIPT_HEADER,
+ volume,
+ DLE_GetDeviceName( BSD_GetDLE( bsd_ptr ) ),
+ date_str,
+ time_str );
+ }
+
+ ST_AddBSFilesSkipped( &op_stats, (UINT32) 1 );
+ UI_AllocPathBuffer( &file_buf, FS_SizeofFnameInFDB( fsh, dblk_ptr ) ) ;
+ UI_AllocPathBuffer( &buffer, (UINT16)(FS_SizeofFnameInFDB( fsh, dblk_ptr ) +
+ FS_SizeofPathInDDB( fsh, ddb_dblk_ptr ) + 5 ) ) ;
+
+ if ( buffer && file_buf ) {
+ FS_GetFnameFromFDB( fsh, dblk_ptr, file_buf );
+ UI_BuildDelimitedPathFromDDB( &buffer, fsh, ddb_dblk_ptr,
+ delimiter, FALSE );
+
+ UI_AppendDelimiter( buffer, delimiter );
+ strcat( buffer, file_buf );
+
+ if ( msg == MSG_BLOCK_INUSE ) {
+ yresprintf( (INT16) RES_FILE_SKIPPED, buffer );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG,
+ RES_FILE_SKIPPED, buffer );
+ }
+ else {
+
+#if defined ( OS_WIN32 )
+ mwErrorDuringBackupSet = TRUE;
+#endif
+
+ gb_error_during_operation = TRUE;
+ yresprintf( (INT16) RES_FILE_OPEN_ERROR, buffer );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG,
+ RES_FILE_OPEN_ERROR, buffer );
+ }
+
+ /* add the entry into the skipped script ... */
+
+ if ( CDS_GetCreateSkipped( cds_ptr ) ) {
+
+ CHAR szPlusPlus[3];
+
+ UI_BuildFullPathFromDDB( &buffer, fsh, ddb_dblk_ptr,
+ delimiter, FALSE );
+ UI_AppendDelimiter( buffer, delimiter );
+ strcat( buffer, file_buf );
+
+ /* if this bsd's dle is a Novell server, prefix the script line with ++ */
+
+ szPlusPlus[0] = TEXT('\0');
+ if ( ( ( DLE_GetDeviceType( BSD_GetDLE( bsd_ptr ) ) == NOVELL_DRV ) ||
+ ( DLE_GetDeviceType( BSD_GetDLE( bsd_ptr ) ) == NOVELL_AFP_DRV ) ) &&
+ ( DLE_GetParent( BSD_GetDLE( bsd_ptr ) ) != NULL ) ) {
+
+ strcpy( szPlusPlus, TEXT("++") );
+ }
+
+ lprintf( SKIPPED_FILE, TEXT("%s%s%s\n"),
+ szPlusPlus,
+ DLE_GetDeviceName( BSD_GetDLE( bsd_ptr ) ),
+ buffer );
+ }
+ }
+ break;
+ }
+ yprintf(TEXT("%ld\r"),ST_GetBSFilesSkipped( &op_stats ) );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_SKIPPED_FILES );
+ break;
+
+ case MSG_BYTES_SKIPPED:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ count = va_arg( arg_ptr, UINT64 );
+ ST_AddBSBytesSkipped( &op_stats, count );
+ break;
+
+ case MSG_BLOCK_BAD:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+
+ gb_error_during_operation = TRUE;
+
+ dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+ ddb_dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+
+ QTC_BlockBad( mw_qtc_ptr );
+
+ dle = BSD_GetDLE( bsd_ptr ) ;
+
+ if ( DLE_GetDeviceType(dle) == FS_EMS_DRV ) {
+
+ if (!mwErrorDuringBackupSet ) {
+ CHAR_PTR name;
+
+ name = mwCurrentDrive ;
+ if ( DLE_GetParent( dle ) ) {
+ name = DLE_GetDeviceName( DLE_GetParent(dle)) ;
+ }
+
+ yresprintf( (INT16) RES_EMS_COMM_FAILURE, name );
+
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_WARNING, SES_ENG_MSG, RES_EMS_COMM_FAILURE, mwCurrentDrive );
+
+ }
+
+ } else {
+ switch( FS_GetBlockType( dblk_ptr ) ) {
+
+ case BT_DDB:
+
+ ST_AddBSDirsBad( &op_stats, 1 );
+
+ UI_AllocPathBuffer( &buffer, (UINT16)(FS_SizeofPathInDDB( fsh, dblk_ptr ) + 5 ) ) ;
+
+ if ( buffer ) {
+ UI_BuildDelimitedPathFromDDB( &buffer, fsh, dblk_ptr, delimiter, FALSE );
+ yresprintf( (INT16) RES_BACKED_UP_CORRUPT_WARNING, buffer );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_WARNING, SES_ENG_MSG, RES_BACKED_UP_CORRUPT_WARNING, buffer );
+
+ yprintf(TEXT("%ld\r"),ST_GetBSFilesBad( &op_stats ) );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_CORRUPT_FILES );
+ }
+ break;
+
+ case BT_FDB:
+
+ ST_AddBSFilesBad( &op_stats, (UINT32) 1 );
+
+ UI_AllocPathBuffer( &file_buf, FS_SizeofFnameInFDB( fsh, dblk_ptr ) ) ;
+ UI_AllocPathBuffer( &buffer, (UINT16)(FS_SizeofFnameInFDB( fsh, dblk_ptr ) +
+ FS_SizeofPathInDDB( fsh, ddb_dblk_ptr ) + 5 ) ) ;
+
+ if ( buffer && file_buf ) {
+ FS_GetFnameFromFDB( fsh, dblk_ptr, file_buf );
+ UI_BuildDelimitedPathFromDDB( &buffer, fsh, ddb_dblk_ptr, delimiter, FALSE );
+ UI_AppendDelimiter( buffer, delimiter );
+ strcat( buffer, file_buf );
+ yresprintf( (INT16) RES_BACKED_UP_CORRUPT_WARNING, buffer );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_WARNING, SES_ENG_MSG, RES_BACKED_UP_CORRUPT_WARNING, buffer );
+
+ yprintf(TEXT("%ld\r"),ST_GetBSFilesBad( &op_stats ) );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_CORRUPT_FILES );
+ }
+ }
+ }
+
+# if defined ( OS_WIN32 )
+ {
+ mwErrorDuringBackupSet = TRUE;
+ }
+# endif //defined ( OS_WIN32 )
+
+ break;
+
+ case MSG_BYTES_BAD:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+# if defined ( OS_WIN32 )
+ {
+ mwErrorDuringBackupSet = TRUE;
+ }
+# endif //defined ( OS_WIN32 )
+
+ gb_error_during_operation = TRUE;
+
+ count = va_arg( arg_ptr, UINT64 );
+
+ ST_AddBSBytesBad( &op_stats, count );
+
+ break;
+
+ case MSG_IN_USE:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+
+ ST_AddBSInUseFilesProcessed( &op_stats, 1 );
+
+ if ( UI_AllocPathBuffer( &buffer, FS_SizeofFnameInFDB( fsh, dblk_ptr ) ) ) {
+ FS_GetFnameFromFDB( fsh, dblk_ptr, buffer );
+
+ yresprintf( (INT16) RES_BACKED_UP_IN_USE_WARNING, buffer );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_WARNING, SES_ENG_MSG,
+ RES_BACKED_UP_IN_USE_WARNING, buffer );
+ }
+ break;
+
+ case MSG_IN_USE_WAIT:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+ TryOpen = va_arg( arg_ptr, CHK_OPEN );
+ parm = va_arg( arg_ptr, UINT32 );
+
+ if ( DLE_GetDeviceType(BSD_GetDLE( bsd_ptr) ) == FS_EMS_DRV ) {
+
+ return SKIP_OBJECT;
+
+ }
+
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &op_stats );
+
+ skip_open_files = BEC_GetSkipOpenFiles( BSD_GetConfigData( bsd_ptr ) );
+ /* check for wait on open file */
+
+#ifdef OEM_MSOFT
+ skip_open_files = SKIP_NO_TIMED;
+#endif
+
+ response = SKIP_OBJECT ;
+
+ // Make sure we have enough space to at least store the fname
+ if ( UI_AllocPathBuffer( &buffer, FS_SizeofFnameInFDB( fsh, dblk_ptr ) ) ) {
+
+ // ...+ 1 is for a delimiter between the path and filename
+ if ( ( (( strlen( mwCurrentPath ) + strlen( mwCurrentDrive ) + 1 ) * sizeof( CHAR ) ) +
+ FS_SizeofFnameInFDB( fsh, dblk_ptr ) ) < sizeof( DrivePathFileName ) ) {
+
+ //
+ // Display full filename - drive:\path\filename
+ //
+ strcpy( DrivePathFileName, mwCurrentDrive ) ;
+ strcat( DrivePathFileName, mwCurrentPath ) ;
+ UI_AppendDelimiter( DrivePathFileName, delimiter ) ;
+ FS_GetFnameFromFDB( fsh, dblk_ptr, buffer ) ;
+ strcat( DrivePathFileName, buffer ) ;
+ UI_FixPath( DrivePathFileName, MAX_DISPLAY_FULL_FILENAME_LENGTH, TEXT('\\') ) ;
+ yresprintf( (INT16) RES_WAITING_FOR_OPEN, DrivePathFileName ) ;
+ }
+ else {
+ //
+ // Display filename only - filename
+ //
+ FS_GetFnameFromFDB( fsh, dblk_ptr, buffer ) ;
+ yresprintf( (INT16) RES_WAITING_FOR_OPEN, buffer ) ;
+ }
+
+ if ( skip_open_files == SKIP_NO_TIMED ) {
+
+ error = DM_StartSkipOpen( TryOpen, parm ) ;
+
+ if ( error == SUCCESS ) {
+ response = OBJECT_OPENED_SUCCESSFULLY ;
+ }
+ } else {
+
+ while( 1 ) {
+
+ if( mwSkipNoFlag == SKIPNO_YES_TO_ALL_BUTTON ) {
+ response = SKIP_OBJECT ;
+ break ;
+ }
+
+ // ask if they what to skip this file
+ mwSkipNoFlag = DM_StartSkipNo( ) ;
+
+ if( mwSkipNoFlag == SKIPNO_YES_BUTTON ) {
+ response = SKIP_OBJECT ;
+ break ;
+ }
+
+ if( mwSkipNoFlag == SKIPNO_CANCEL_BUTTON ) {
+ gb_abort_flag = ABORT_PROCESSED;
+ response = SKIP_OBJECT ;
+ break ;
+ }
+
+ // they answered No, try to open the file
+ error = TryOpen( parm ) ;
+
+ if ( error == SUCCESS ) {
+ response = OBJECT_OPENED_SUCCESSFULLY ;
+ break ;
+ }
+
+ if ( error == FS_OPENED_INUSE ) {
+ response = OBJECT_OPENED_INUSE ;
+ break ;
+ }
+
+ if ( error == FS_NOT_FOUND ) {
+ response = SKIP_OBJECT;
+ break;
+ }
+ }
+ }
+ }
+
+ /* restart the clock with an end idle */
+ ST_EndBackupSetIdle( &op_stats ) ;
+
+ break ;
+
+
+ case MSG_TBE_ERROR:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+ error = va_arg( arg_ptr, INT16 );
+ ddb_dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+ dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+ strm_id = va_arg( arg_ptr, UINT32 ) ;
+
+ dle = BSD_GetDLE( bsd_ptr ) ;
+ if (( error == FS_COMM_FAILURE) &&
+ (DLE_GetDeviceType( dle) ) == FS_EMS_DRV) {
+
+ yresprintf( (INT16) RES_EMS_COMM_FAILURE, DLE_GetDeviceName( dle ) );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_EMS_COMM_FAILURE, DLE_GetDeviceName( dle ) );
+ QTC_BlockBad( mw_qtc_ptr );
+ QTC_AbortBackup( mw_qtc_ptr );
+ break ;
+ }
+
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &op_stats );
+
+ /* special case for backup/transfer operation */
+ if( error == TFLE_TAPE_INCONSISTENCY ) {
+ QTC_BlockBad( mw_qtc_ptr );
+ QTC_AbortBackup( mw_qtc_ptr );
+
+# if defined ( OS_WIN32 )
+ {
+ mwErrorDuringBackupSet = TRUE;
+ }
+# endif //defined ( OS_WIN32 )
+
+ gb_error_during_operation = TRUE;
+ response = ABORT_OPERATION;
+ eresprintf( RES_FATAL_TAPE_FMT_NO_APPEND, BE_GetCurrentDeviceName( tpos->channel ) );
+
+ } else if ( strm_id == STRM_INVALID ) {
+
+# if defined ( OS_WIN32 )
+ {
+ mwErrorDuringBackupSet = TRUE;
+ }
+# endif //defined ( OS_WIN32 )
+
+ if ( ( error == LP_DRIVE_ATTACH_ERROR ) &&
+ ( DLE_GetDeviceType(dle) == FS_EMS_DRV ) ) {
+ yresprintf( (INT16) RES_EMS_COMM_FAILURE, DLE_GetDeviceName( dle ) );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_WARNING, SES_ENG_MSG, RES_COMM_FAILURE, mwCurrentDrive );
+
+ } else {
+ UI_ProcessErrorCode( error, &response, tpos->channel );
+ }
+
+ if ( response == SKIP_OBJECT ) {
+
+ JS_ReportStreamError( fsh, dle, strm_id, OPERATION_BACKUP, error, ddb_dblk_ptr, dblk_ptr ) ;
+ } else {
+
+ if ( gfAbortInMiddleOfFile ) {
+ QTC_BlockBad( mw_qtc_ptr );
+ }
+ QTC_AbortBackup( mw_qtc_ptr );
+ }
+
+ } else {
+ JS_ReportStreamError( fsh, dle, strm_id, OPERATION_BACKUP, error, ddb_dblk_ptr, dblk_ptr ) ;
+ if ( gfAbortInMiddleOfFile ) {
+ QTC_BlockBad( mw_qtc_ptr );
+ }
+ QTC_AbortBackup( mw_qtc_ptr );
+ }
+
+ /* Special case for handling device attach errors since we wish
+ to add this to the skipped script file */
+
+ if ( error == LP_DRIVE_ATTACH_ERROR ) {
+
+ /* Open skipped script and call write script funtion */
+
+ lresprintf( SKIPPED_FILE, LOG_START, FALSE );
+ DLE_GetVolName( BSD_GetDLE( bsd_ptr ), volume );
+
+ t_time = ST_GetBSStartTime( &op_stats );
+ UI_LongToDate( date_str, t_time );
+ UI_LongToTime( time_str, t_time );
+
+ lresprintf( SKIPPED_FILE, LOG_MSG, SES_ENG_MSG, RES_SKIPPED_DEVICE,
+ volume,
+ DLE_GetDeviceName( BSD_GetDLE( bsd_ptr ) ),
+ date_str,
+ time_str );
+
+ /* Write "script-like" selections to script file */
+ if ( output_dest[SKIPPED_FILE].fh &&
+ ( SCR_ProcessBSD( output_dest[ SKIPPED_FILE ].fh, bsd_ptr )!= SUCCESS) ) {
+
+ if ( UI_AllocPathBuffer( &buffer, UI_MAX_FILENAME_LENGTH * sizeof(CHAR) ) ) {
+ strcpy( buffer, SKIPPED_LOG );
+ strcat( buffer, BKS_EXT );
+ eresprintf( RES_ERROR_WRITING_SCRIPT, buffer );
+ }
+ }
+
+ lresprintf( SKIPPED_FILE, LOG_END );
+
+ }
+
+ /* restart the clock with an end idle */
+ ST_EndBackupSetIdle( &op_stats );
+
+ break;
+
+ case MSG_EOM:
+
+ mwfAbortDisabledForEOM = TRUE;
+
+ /* disable the abort button for the runtime dialog */
+ JobStatusBackupRestore( (WORD) JOB_STATUS_ABORT_DISABLE );
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_NEEDTAPE);
+ vcb_dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+ ddb_dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+ fdb_dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &op_stats );
+
+ QTC_EndOfTape( mw_qtc_ptr, vcb_dblk_ptr, ddb_dblk_ptr, fdb_dblk_ptr, fsh );
+
+ /* Clear current append mode flag */
+ CDS_SetAppendFlag( cds_ptr, 0 );
+
+ /* Prompt for new tape will be performed during TF_NEED_NEW_TAPE */
+
+ /* restart the clock with an end idle */
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+
+ case MSG_STOP_CLOCK:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &op_stats );
+ break;
+
+ case MSG_START_CLOCK:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ /* restart the clock with an end idle */
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+
+ case MSG_ACCIDENTAL_VCB:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+
+ break;
+
+ case MSG_ATTR_READ_ERROR:
+
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+# if defined ( OS_WIN32 )
+ {
+ mwErrorDuringBackupSet = TRUE;
+ }
+# endif //defined ( OS_WIN32 )
+
+ gb_error_during_operation = TRUE;
+
+ dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+ if ( UI_AllocPathBuffer( &buffer, FS_SizeofFnameInFDB( fsh, dblk_ptr ) ) ) {
+ FS_GetFnameFromFDB( fsh, dblk_ptr, buffer );
+
+ yresprintf( (INT16) RES_BAD_ATTR_READ, buffer );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_WARNING, SES_ENG_MSG, RES_BAD_ATTR_READ, buffer );
+ }
+ break;
+
+ case MSG_COMM_FAILURE:
+ dle = BSD_GetDLE( bsd_ptr ); // chs:06-09-93
+
+# if defined ( OS_WIN32 )
+ {
+ mwErrorDuringBackupSet = TRUE;
+ }
+# endif //defined ( OS_WIN32 )
+
+ gb_error_during_operation = TRUE;
+ if ( DLE_GetDeviceType(dle) == FS_EMS_DRV ) {
+ yresprintf( (INT16) RES_EMS_COMM_FAILURE, mwCurrentDrive );
+ } else {
+ yresprintf( (INT16) RES_COMM_FAILURE, mwCurrentDrive );
+ }
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_WARNING, SES_ENG_MSG, RES_COMM_FAILURE, mwCurrentDrive );
+ break;
+
+ /* ignore these messages */
+ case MSG_NOT_DELETED:
+ case MSG_IDLE:
+ case MSG_PROMPT:
+ case MSG_BLOCK_DELETED:
+ case MSG_BYTES_DELETED:
+ case MSG_TAPE_STATS:
+ case MSG_BLK_NOT_FOUND:
+ case MSG_BLK_DIFFERENT:
+ case MSG_LOG_DIFFERENCE:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ break;
+
+ default:
+
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+ QTC_BlockBad( mw_qtc_ptr );
+ QTC_AbortBackup( mw_qtc_ptr );
+
+# if defined ( OS_WIN32 )
+ {
+ mwErrorDuringBackupSet = TRUE;
+ }
+# endif //defined ( OS_WIN32 )
+
+ gb_error_during_operation = TRUE;
+
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &op_stats );
+
+ eresprintf( RES_UNKNOWN_MSG_HNDLR_MSG, msg );
+
+ /* restart the clock with an end idle */
+ ST_EndBackupSetIdle( &op_stats );
+
+ break;
+ }
+
+ return( response );
+}
+
+/*****************************************************************************
+
+ Name: WriteAbortOperation
+
+ Description: Ask the user if they want to continue the operation.
+ If the answer is yes, prompt for a new tape to be inserted.
+
+ Returns: (UINT16)response that is returned to Tape Positioning routine
+
+*****************************************************************************/
+UINT16 WriteAbortOperation( drive_name )
+CHAR_PTR drive_name;
+{
+ CHAR WarningTitle[255];
+
+ while ( TRUE ) {
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+ if ( CDS_GetYesFlag ( CDS_GetCopy() ) != YESYES_FLAG ) {
+
+ RSM_StringCopy( IDS_MSGTITLE_CONTINUE, WarningTitle, 255 );
+
+ } else {
+
+ RSM_StringCopy( IDS_APPNAME, WarningTitle, 255 );
+ }
+
+ if ( WM_MessageBox( WarningTitle,
+ ID( RES_CONTINUE_QUEST ),
+ WMMB_YESNO | WMMB_NOYYCHECK,
+ WMMB_ICONQUESTION, NULL, 0, 0 ) ) {
+
+ yresprintf( (INT16) RES_INSERT_NEW_TAPE, drive_name );
+
+ if ( ! WM_MessageBox( ID( IDS_MSGTITLE_INSERT ),
+ gszTprintfBuffer,
+ WMMB_OK | WMMB_NOYYCHECK,
+ WMMB_ICONEXCLAMATION, NULL, 0, 0 ) ) {
+ continue;
+ }
+
+#if defined( OS_WIN32 )
+ NtDemoChangeTape( 1 ) ; /* start with tape # 1 */
+#endif
+
+ return UI_NEW_TAPE_INSERTED;
+ }
+ else {
+ return UI_ABORT_POSITIONING;
+ }
+ }
+}
+
+/*****************************************************************************
+
+ Name: GetPasswordAndTapeName
+
+ Description: Common function to match/collect tape passwords and
+ new tape name in cases where a given tape is being
+ overwritten
+
+ Returns: (UINT16)response that is returned to Tape Format
+
+ Notes: Any operations that require calling the Message Handler
+ to update the catalog must be performed by the caller
+
+*****************************************************************************/
+UINT16 GetPasswordAndTapeName( bsd_ptr, cur_vcb, password, buffer, drive_name )
+BSD_PTR bsd_ptr;
+DBLK_PTR cur_vcb;
+CHAR_PTR password;
+CHAR_PTR buffer;
+CHAR_PTR drive_name;
+{
+ BOOLEAN pass_status;
+ INT16 password_size;
+ UINT16 response;
+
+ DBG_UNREFERENCED_PARAMETER ( bsd_ptr );
+ DBG_UNREFERENCED_PARAMETER ( buffer );
+
+ pass_status = CollectTapePassword( (INT8_PTR)password, &password_size,
+ FS_ViewPswdEncryptInVCB( cur_vcb ),
+ (INT8_PTR)FS_ViewTapePasswordInVCB( cur_vcb ),
+ FS_SizeofTapePswdInVCB( cur_vcb ) );
+ if ( pass_status == TRUE ) { /* password matched */
+ response = UI_OVERWRITE; /* overwrite this tape */
+ }
+ else { /* password mismatch
+ /* ask user if they want to continue with a new tape */
+ response = WriteAbortOperation( drive_name );
+ }
+ return( response );
+}
+/*****************************************************************************
+
+ Name: CarryForwardPasswordTapeName
+
+ Description: "Carries forward" to the current bsd the tape password
+ and tape name from the current vcb
+
+ Returns: VOID
+
+*****************************************************************************/
+VOID CarryForwardPasswordTapeName( bsd_ptr, vcb_ptr )
+BSD_PTR bsd_ptr;
+DBLK_PTR vcb_ptr;
+{
+ if ( FS_SizeofTapeNameInVCB( vcb_ptr ) != 0 ) {
+ BSD_SetTapeLabel( bsd_ptr, (INT8_PTR)FS_ViewTapeNameInVCB( vcb_ptr ),
+ FS_SizeofTapeNameInVCB( vcb_ptr ) );
+ }
+
+ if ( FS_SizeofTapePswdInVCB( vcb_ptr ) != 0 ) {
+ BSD_SetTapePswd( bsd_ptr,
+ (INT8_PTR)FS_ViewTapePasswordInVCB( vcb_ptr ),
+ FS_SizeofTapePswdInVCB( vcb_ptr ) );
+ }
+ else {
+ BSD_SetTapePswd( bsd_ptr, (INT8_PTR)TEXT(""), (UINT16)0 ) ;
+ }
+
+ return;
+
+}
+/*****************************************************************************
+
+ Name: poll_drive_clock_routine
+
+ Description: one second timer to check for VLM_VALID_TAPE
+ status from poll drive
+
+ Returns: void
+
+*****************************************************************************/
+
+static VOID poll_drive_clock_routine( VOID )
+{
+
+ DBLK_PTR vcb_ptr;
+
+ mwTapeDriveStatus = VLM_GetDriveStatus( &vcb_ptr ) ;
+
+ /* Some drives report NO_TAPE to poll drive when there is a tape */
+ /* in the drive, then on the next poll they report BUSY. Count VLM_RETRY_COUNTER */
+ /* consecutive NO_TAPE status before reporting a true NO_TAPE. */
+
+ if( mwTapeDriveStatus == VLM_NO_TAPE ) {
+
+ mwNoTapeStatusCounter++ ;
+ if( mwNoTapeStatusCounter > VLM_RETRY_COUNTER ) { // chs:04-29-93
+ mwTapeDriveStatus = VLM_NO_TAPE ;
+ }
+ else {
+ mwTapeDriveStatus = VLM_BUSY ;
+ }
+ }
+ else {
+ /* reset the counter */
+ mwNoTapeStatusCounter = 0 ;
+ }
+
+
+ if( mwTapeDriveStatus == VLM_VALID_TAPE ||
+ mwTapeDriveStatus == VLM_FOREIGN_TAPE ||
+ mwTapeDriveStatus == VLM_FUTURE_VER ||
+ mwTapeDriveStatus == VLM_SQL_TAPE ||
+ mwTapeDriveStatus == VLM_ECC_TAPE ||
+ mwTapeDriveStatus == VLM_GOOFY_TAPE ||
+ mwTapeDriveStatus == VLM_BLANK_TAPE ) {
+
+ mwPollDriveWaitTimer++;
+ }
+ else {
+ /* decrement the wait timer */
+ if( mwPollDriveWaitTimer ) {
+ mwPollDriveWaitTimer--;
+ }
+ }
+}
+
+
+/*****************************************************************************
+
+ Name: clock_routine
+
+ Description: one second timer to update the Runtime status
+ elapsed time.
+
+ Note: You must have a matched set of ST_StartBackupSetIdle and
+ ST_EndBackupSetIdle calls to start and stop the clock.
+
+ Returns: void
+
+*****************************************************************************/
+
+static VOID clock_routine( VOID )
+{
+ INT16 num_hours, num_minutes, num_seconds;
+ UINT64 num_bytes;
+ BOOLEAN stat ;
+ CHAR numeral[ 40 ];
+ static INT16 last_num_hours;
+ static INT16 last_num_minutes;
+ static INT16 last_num_seconds;
+ static UINT64 total_bytes;
+ static INT animate = 0;
+
+
+ if ( clock_ready_flag && ( ST_BSIdleLevel( &op_stats ) == 0 ) ) {
+
+
+ num_bytes = ST_GetBSBytesProcessed ( &op_stats );
+ if ( ! U64_EQ( num_bytes, total_bytes) ) {
+ total_bytes = num_bytes;
+ U64_Litoa( num_bytes, numeral, (UINT16)10, &stat ) ;
+ UI_BuildNumeralWithCommas( numeral );
+
+ yprintf(TEXT("%s\r"),numeral );
+
+ JobStatusBackupRestore( (WORD) JOB_STATUS_BYTES_PROCESSED );
+
+#ifndef OEM_MSOFT
+ JobStatusStats( num_bytes );
+#endif
+
+ }
+
+ WM_AnimateAppIcon ( IDM_OPERATIONSBACKUP, FALSE );
+
+ ST_EndBackupSet( &op_stats );
+
+ SetStatusBlock(IDSM_FILECOUNT, ST_GetBSFilesProcessed( &op_stats ));
+ SetStatusBlock(IDSM_DIRCOUNT, ST_GetBSDirsProcessed( &op_stats ));
+ SetStatusBlock(IDSM_CORRUPTFILECOUNT, ST_GetBSFilesBad( &op_stats ));
+ SetStatusBlock(IDSM_SKIPPEDFILECOUNT, ST_GetBSFilesSkipped( &op_stats ));
+ SetStatusBlock(IDSM_BYTECOUNTLO, U64_Lsw(num_bytes));
+ SetStatusBlock(IDSM_BYTECOUNTHI, U64_Msw(num_bytes));
+ SetStatusBlock(IDSM_ELAPSEDSECONDS, (ST_GetBSEndTime( &op_stats ) -
+ ST_GetBSStartTime( &op_stats ) -
+ op_stats.bs_stats.bs_total_idle));
+
+ num_hours = ST_GetBSElapsedHours( &op_stats );
+ num_minutes = ST_GetBSElapsedMinutes( &op_stats );
+ num_seconds = ST_GetBSElapsedSeconds( &op_stats );
+
+ if ( ( last_num_hours != num_hours ) ||
+ ( last_num_minutes != num_minutes ) ||
+ ( last_num_seconds != num_seconds ) ) {
+
+ last_num_hours = num_hours;
+ last_num_minutes = num_minutes;
+ last_num_seconds = num_seconds;
+
+ if ( num_hours ) {
+
+ yprintf( TEXT("%d%c%2.2d%c%2.2d\r"), num_hours, UI_GetTimeSeparator(),
+ num_minutes, UI_GetTimeSeparator(), num_seconds );
+
+
+ }
+ else {
+
+ yprintf( TEXT("%2.2d%c%2.2d\r"), num_minutes, UI_GetTimeSeparator(), num_seconds );
+
+ }
+
+ JobStatusBackupRestore( (WORD) JOB_STATUS_ELAPSED_TIME );
+
+ }
+
+
+
+ }
+}
+
+/**************************************************
+ Returns the current stats structure and path/file
+ name being processed.
+***************************************************/
+INT UI_GetBackupCurrentStatus(
+STATS *Stats,
+CHAR *Path,
+INT PathSize )
+{
+ INT SpaceNeeded = 2;
+
+
+ if ( gbCurrentOperation != OPERATION_BACKUP ) {
+ return( FAILURE );
+ }
+
+ if ( Stats != NULL ) {
+ memcpy( Stats, &op_stats, sizeof( STATS ) );
+ }
+
+ SpaceNeeded += strlen( mwCurrentDrive );
+ SpaceNeeded += strlen( mwCurrentPath );
+ SpaceNeeded += strlen( mwCurrentFile );
+
+ if ( Path == NULL || PathSize < 0 ) {
+ return( FAILURE );
+ }
+
+ strcpy( Path, TEXT( "" ) );
+
+ if ( (INT)SpaceNeeded < PathSize ) {
+ strcpy( Path, mwCurrentDrive );
+ strcat( Path, mwCurrentPath );
+ if (strcmp(mwCurrentPath, TEXT("\\")) != 0)
+ {
+ strcat( Path, TEXT( "\\" ) );
+ }
+ strcat( Path, mwCurrentFile );
+ }
+ else {
+ if ( (INT)strlen( mwCurrentFile ) < PathSize ) {
+ strcpy( Path, mwCurrentFile );
+ }
+ else {
+ return( FAILURE );
+ }
+ }
+
+ return( SUCCESS );
+}
+
+/**************************************************
+ Procedure: UI_GetBackupCopyOfStatsStructure
+ Purpose: Pass the actual pointer of the STATS
+ structure.
+ return pointer o the curent STATS structure.
+***************************************************/
+STATS_PTR UI_GetBackupPtrToStatsStructure ( )
+{
+ return( &op_stats );
+}
+/**************************************************
+
+ Procedure: IsTransferTape
+
+ Purpose: Tries to find the catalog for this tape ID
+ and looks at each backup set to determine
+ if the tape is a Transfer tape.
+
+ return TRUE = transfer tape
+ FALSE = not a tansfer tape
+
+***************************************************/
+BOOLEAN IsTransferTape(
+UINT32 TapeInDriveFID )
+{
+ BOOLEAN transfer_tape = FALSE ;
+ BOOLEAN done_flag = FALSE ;
+ QTC_TAPE_PTR tape ;
+ QTC_BSET_PTR bset ;
+ QTC_HEADER_PTR header ;
+
+ tape = QTC_GetFirstTape() ;
+
+ while ( tape ) {
+
+ if ( tape->tape_fid == TapeInDriveFID ) {
+
+ bset = QTC_GetFirstBset( tape ) ;
+
+ while ( bset && !transfer_tape ) {
+
+ header = QTC_LoadHeader( bset ) ;
+
+ if( header ) {
+
+ /* Check for a transfer tape */
+ if ( header->VCB_attributes & VCB_ARCHIVE_BIT ) {
+ transfer_tape = TRUE ;
+ }
+ free( header ) ;
+ }
+
+ /* On a transfer tape, the first backup set has to be
+ a transfer set. If a transfer continuation tape, then
+ look at all of the backup sets */
+ if ( bset->bset_num == 1 ) {
+ done_flag = TRUE ;
+ break ;
+ }
+
+ bset = QTC_GetNextBset( bset ) ;
+ }
+ }
+ if ( done_flag || transfer_tape ) {
+ break ;
+ }
+
+ tape = QTC_GetNextTape( tape ) ;
+ }
+ return( transfer_tape ) ;
+}
+
diff --git a/private/utils/ntbackup/src/do_cat.c b/private/utils/ntbackup/src/do_cat.c
new file mode 100644
index 000000000..dcec5259b
--- /dev/null
+++ b/private/utils/ntbackup/src/do_cat.c
@@ -0,0 +1,2948 @@
+
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-95
+
+ Name: do_cat.c
+
+ Description: Code to catalog a tape or a set. Handles a mixture of OTC
+ tapes/sets and non-OTC tapes/sets.
+
+ $Log: G:\ui\logfiles\do_cat.c_v $
+
+ Rev 1.141.1.8 16 Jun 1994 15:46:16 STEVEN
+forgot to sleep on retry
+
+ Rev 1.141.1.7 24 May 1994 20:09:10 GREGG
+Improved handling of ECC, SQL, FUTURE_VER and OUT_OF_SEQUENCE tapes.
+
+ Rev 1.141.1.6 04 May 1994 15:09:36 STEVEN
+fix dlt settling time
+
+ Rev 1.141.1.5 21 Apr 1994 10:17:16 GREGG
+Fixed memory leak.
+
+ Rev 1.141.1.4 02 Feb 1994 18:08:34 chrish
+Added change for UNICODE app to handle ANSI secured created tape.
+
+ Rev 1.141.1.3 25 Jan 1994 08:42:04 MIKEP
+fix warnings in orcas
+
+ Rev 1.141.1.2 17 Jan 1994 15:47:22 MIKEP
+fix unicode warnings
+
+ Rev 1.141.1.1 13 Jan 1994 18:13:22 STEVEN
+dirctory count bkup caused exception
+
+ Rev 1.141.1.0 14 Dec 1993 12:11:54 BARRY
+Don't write to gszTprintfBuffer, use yprintf
+
+ Rev 1.141 24 Nov 1993 15:26:30 BARRY
+Fix Unicode warning
+
+ Rev 1.140 11 Oct 1993 18:19:06 GREGG
+Mike Payne's fix for catalogging a continuation VCB.
+
+ Rev 1.139 29 Sep 1993 17:17:40 BARRY
+Unicode fix
+
+ Rev 1.138 10 Sep 1993 13:16:24 MIKEP
+Undo zeir's last check in. It caused the catalog operation
+to stop after set 1 if on tape catalogs were not being used.
+
+ Rev 1.137 17 Aug 1993 18:18:18 ZEIR
+Set BSD PBA for non-FDD sets
+
+ Rev 1.136 17 Aug 1993 16:55:44 MIKEP
+fix sytos plus error msg
+
+ Rev 1.135 22 Jul 1993 18:36:20 KEVINS
+Corrected macro name.
+
+ Rev 1.134 22 Jul 1993 18:30:00 KEVINS
+Added support for tape drive settling time.
+
+ Rev 1.133 12 Jul 1993 09:25:58 KEVINS
+Added support for status monitor.
+
+ Rev 1.132 07 Jul 1993 08:52:34 MIKEP
+fix epr 357-461. EOM statistics bug.
+
+ Rev 1.131 25 Jun 1993 09:39:48 GLENN
+fix bug when fully cataloging a tape and the crossing set is
+already fully cataloged. It use to stop and not continue on to
+the sets on the next tape.
+
+ Rev 1.130 25 Jun 1993 08:33:04 GLENN
+fix problem with asking for tape N+2, rather than N+1, if slow mode.
+
+ Rev 1.129 24 Jun 1993 14:18:36 GREGG
+Fixed conditional for returning aux error in MSG_TBE_ERROR case in msg handler.
+
+ Rev 1.128 19 Jun 1993 13:16:18 MIKEP
+try to fix logfile bug again.
+
+ Rev 1.127 19 Jun 1993 12:11:16 GLENN
+fix catalog message box bug 294-0549. trivial bug.
+
+ Rev 1.126 18 Jun 1993 16:48:34 CARLS
+added NtDemoChangeTape calls for NtDemo
+
+ Rev 1.125 14 Jun 1993 20:33:58 MIKEP
+fix eom catalog on 8200
+
+ Rev 1.124 11 Jun 1993 10:44:28 chrish
+Nostradamus EPR 0503 - Fixed display description during a catalog operation.
+Wrong information was being displayed in the description field.
+
+ Rev 1.123 08 Jun 1993 13:20:10 chrish
+Nostradamus EPR 0533 - Corrected incorrect string display when user tried
+to catalog a secured tape. The string was reversed ... text for title and
+title for text. Corrected by reversing the above.
+
+ Rev 1.122 07 Jun 1993 09:58:26 MIKEP
+warning fixes
+
+ Rev 1.121 07 Jun 1993 08:16:44 MIKEP
+Fix epr asking for tape 3 when there is no tape 3. Fix occasional blow
+up when changing tapes.
+
+ Rev 1.120 06 Jun 1993 02:08:14 GREGG
+Pass flag to SetMap and SetCat Close indicating if the operation was aborted.
+
+ Rev 1.119 26 May 1993 17:48:30 MIKEP
+fix directory and file display.
+
+ Rev 1.118 25 May 1993 12:55:22 MIKEP
+Fix user abort between tapes and full tape catalog problem.
+
+ Rev 1.116 22 May 1993 13:42:58 MIKEP
+Fix nostradamus epr #504, update displays the same for all
+tape operations.
+
+ Rev 1.115 17 May 1993 13:37:36 MIKEP
+Fix full catalog of non-otc tape.
+
+ Rev 1.114 14 May 1993 17:32:50 MIKEP
+fix full cataloging across multiple tapes
+
+ Rev 1.113 07 May 1993 17:47:22 MIKEP
+fix abort bug
+
+ Rev 1.112 06 May 1993 09:42:56 MIKEP
+Fix numerous abort bugs.
+Add more detection of full hard drive errors.
+Don't mark last file corrupt if user aborts.
+Mark set as incoomplete if user aborts.
+
+
+ Rev 1.111 05 May 1993 10:47:30 MIKEP
+add message to handle cataloging with full hard drive.
+
+ Rev 1.110 28 Apr 1993 16:31:06 MIKEP
+warning fixes only
+
+ Rev 1.109 23 Apr 1993 10:22:02 MIKEP
+Add greg's new on tape catalog version number support.
+
+ Rev 1.108 16 Apr 1993 16:12:46 MIKEP
+put strings in resources
+
+ Rev 1.107 14 Apr 1993 16:42:50 MIKEP
+fix start backup message
+
+ Rev 1.104 12 Apr 1993 22:09:58 MIKEP
+fix missingtape again
+
+ Rev 1.103 12 Apr 1993 09:52:32 MIKEP
+fix for end of catalog full
+
+ Rev 1.100 08 Apr 1993 17:21:38 chrish
+Made change to prevent Nostradamous from cataloging a tape secured by Cayman.
+
+ Rev 1.99 05 Apr 1993 18:50:54 MIKEP
+lots of fixes
+
+ Rev 1.98 04 Apr 1993 17:49:50 MIKEP
+fix set map loading during catalog full tape &&
+abort operation if failure or user aborts.
+
+ Rev 1.97 02 Apr 1993 15:50:46 CARLS
+changes for DC2000 unformatted tape
+
+ Rev 1.96 30 Mar 1993 22:31:20 MIKEP
+fixes
+
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+
+// SUPPORTED OPERATIONS
+
+#define OPER_NONE 0 // its being terminated
+#define OPER_TAPE_PART 1 // partially catalog whole tape
+#define OPER_TAPE_FULL 2 // fully catalog whole tape
+#define OPER_BSET_FULL 3 // fully catalog single set
+
+// LoadTheSetMap returns
+
+#define LSM_NO_TAPE 0 // user lost tape
+#define LSM_NO_SM_FID 1 // no set map this tape family
+#define LSM_NO_SM_TAPE 2 // no set map this tape
+#define LSM_SM_LOADED 3 // set map loaded ok
+#define LSM_USER_ABORT 4 // user aborted
+#define LSM_BIG_ERROR 5 // tape drive error
+#define LSM_OTC_FAILURE 6 // probably hard drive full
+
+
+// LoadFDD returns
+
+#define LFDD_NO_FDD 0 // No FDD on tape
+#define LFDD_LOADED 1 // FDD loaded ok
+#define LFDD_ERROR 2 // error loading FDD
+
+// Prompt for tape options
+
+#define ASK_NEXTTAPE 0
+#define ASK_FORTAPE 1
+
+// Runtime display style
+
+#define RUNTIME_NONE 0 // none displayed yet.
+#define RUNTIME_SMALL 1 // fast cataloging
+#define RUNTIME_LARGE 2 // slow cataloging
+
+
+
+// Module Wide Globals
+
+QTC_BUILD_PTR mwQTC = NULL;
+INT mwBeenHereBefore;
+INT16 mwTapeNum;
+INT16 mwSetNum;
+UINT32 mwTapeFID;
+INT mwOperation;
+INT mwRuntime;
+INT mwEnableClock;
+INT mwEOM;
+INT mwEOD;
+BOOLEAN mwEODSetMapRead;
+INT mwDisplayRewind;
+STATS mwOpStats;
+FSYS_HAND mwFsh = (FSYS_HAND)NULL;
+HTIMER mwTimerHandle;
+INT mwLoadSetMapCalled;
+INT mwOpenSetMapActive;
+INT mwOTCFailure;
+INT mwUserAbort;
+INT mwSetMapLoaded;
+INT mwAbortAtEOM;
+
+INT mwRetryCount = 0;
+
+INT mwSkipThisSet;
+INT mwSkipThisTape;
+
+CHAR mwDriveName[ MAX_UI_RESOURCE_SIZE ]; // Tape drive name
+
+static UINT16 mwTapeSettlingCount;
+
+// Local Function Prototypes
+
+INT CallLoops( INT FDD );
+VOID ClockRoutine( VOID );
+BSD_PTR CreateAndAddTempBSD( INT FDD, BSD_HAND TempBsdList );
+INT CreateVCBFromQTC( UINT32 TapeFID, INT16 TapeSeq, INT16 SetNum, DBLK_PTR dblk, FSYS_HAND fsh );
+INT DetermineNextSet( INT OTC, INT FDD );
+INT DetermineFirstSet( );
+INT DisplayRuntime( INT style );
+INT EndOfOperation( VOID );
+INT GetBestOTCFlags(UINT32 TapeFID, INT16 TapeNum, INT16 SetNum, UINT32 *flags );
+INT GetBestFDDInfo(UINT32 TapeFID, INT16 TapeNum, INT16 SetNum, INT16 *FDDSeqNum, UINT32 *FDDPBA, UINT8 *FDDVersion );
+INT16 GetLowestSetOnTape( UINT32 TapeFID, INT16 TapeSeq );
+INT16 GetLowestTapeWithSet( UINT32 TapeFID, INT16 TapeSeq, INT16 SetNum );
+INT LoadFDD( INT *LoadFDDCalled );
+INT LoadTheSetMap( VOID );
+INT16 PromptForTape(INT WhatToAsk, INT16 TapeNum, CHAR_PTR TapeName, CHAR_PTR DriveName );
+INT ReCheckSet( );
+INT ShouldWeLoadSetMap( INT *OTC );
+INT ShouldWeLoadFDD( VOID );
+UINT16 TapePositioner( UINT16, TPOS_PTR, BOOLEAN, DBLK_PTR, UINT16 );
+INT16 TapeMsgHandler( UINT16 msg, INT32 pid, BSD_PTR bsd_ptr, FSYS_HAND fsh, TPOS_PTR tpos, ... );
+
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT do_catalog(
+UINT32 tape_fid,
+INT16 tape_seq_num,
+INT16 bset_num )
+{
+ DBLK vcb;
+ DBLK_PTR vcb_ptr;
+ UINT32 TempFID;
+ INT16 TempSeq;
+ INT16 TempSet;
+ INT OTC = FALSE;
+ INT FDD = FALSE;
+ INT SetsAdded;
+ INT SetsChanged;
+ INT Status;
+ INT LoadFDDCalled;
+ INT CatalogFlag = TRUE ;
+
+ // Set global error flag, used at end of operation
+
+ gb_error_during_operation = FALSE;
+ gbAbortAtEOF = FALSE;
+
+ gb_abort_flag = CONTINUE_PROCESSING;
+
+ mwBeenHereBefore = FALSE;
+ mwDisplayRewind = TRUE;
+ mwEnableClock = FALSE;
+ mwRuntime = RUNTIME_NONE;
+ mwEOD = FALSE;
+ mwEOM = FALSE;
+ mwEODSetMapRead = FALSE;
+ mwQTC = NULL;
+ mwOTCFailure = FALSE;
+ mwUserAbort = FALSE;
+ mwOpenSetMapActive = FALSE;
+ mwSetMapLoaded = FALSE;
+ mwAbortAtEOM = FALSE;
+
+ /* we will check for tape every 3 seconds, but prompt user by interval
+ specified in INI file */
+ mwTapeSettlingCount = CDS_GetTapeDriveSettlingTime ( CDS_GetPerm () ) / 3;
+
+ if ( CDS_GetTapeDriveName( CDS_GetPerm( ) ) ) {
+
+ CHAR DriveName[80] ;
+
+ strncpy( DriveName, (CHAR_PTR)CDS_GetTapeDriveName( CDS_GetPerm( ) ), 80 ) ;
+ DriveName[79] = '\0' ;
+ strlwr( DriveName ) ;
+ if( strstr( DriveName, TEXT( "cipher" ) ) != NULL ||
+ ( strstr( DriveName, TEXT( "dec" ) ) != NULL &&
+ ( strstr( DriveName, TEXT( "thz02" ) ) != NULL ||
+ strstr( DriveName, TEXT( "tz86" ) ) != NULL ||
+ strstr( DriveName, TEXT( "tz87" ) ) != NULL ||
+ strstr( DriveName, TEXT( "dlt2700" ) ) != NULL ||
+ strstr( DriveName, TEXT( "dlt2000" ) ) != NULL ) ) ) {
+ mwTapeSettlingCount *= 2 ;
+ }
+ }
+
+
+ // Load tape drive name
+
+ RSM_StringCopy( IDS_TAPEDRIVENAME, mwDriveName, sizeof( mwDriveName ) );
+
+
+ if ( bset_num != -1 ) {
+
+ if ( gfIgnoreOTC ) {
+
+ // Use lowest tape sequence number that has been seen.
+
+ tape_seq_num = GetLowestTapeWithSet( tape_fid, tape_seq_num, bset_num );
+ }
+
+ mwOperation = OPER_BSET_FULL;
+ mwSetNum = bset_num;
+ mwTapeNum = tape_seq_num;
+ mwTapeFID = tape_fid;
+
+#ifdef OEM_MSOFT // chs:03-17-93
+ // // chs:03-17-93
+ // Test to see if user has rights to catalog the tape // chs:03-17-93
+ // // chs:03-17-93
+ // chs:03-17-93
+ if ( PSWD_CheckForPassword( tape_fid, bset_num ) ) { // chs:03-17-93
+ return( SUCCESS ); // password check failed // chs:03-17-93
+ } // chs:03-17-93
+#endif
+ }
+ else {
+
+ mwOperation = OPER_TAPE_PART;
+
+#ifndef OEM_MSOFT
+ if ( ! DM_CatTape( &CatalogFlag ) ) {
+ return( FAILURE );
+ }
+ if ( CatalogFlag == TRUE ) {
+ mwOperation = OPER_TAPE_FULL;
+ }
+#endif
+
+ // Try getting the fid from the vlm area so we can get the tape name.
+
+ if ( VLM_GetDriveStatus( &vcb_ptr ) == VLM_VALID_TAPE ) {
+
+#ifdef OEM_MSOFT
+
+ //
+ // Test to see if user has rights to catalog the tape
+ //
+
+ if ( !CatalogPasswordCheck ( vcb_ptr ) || // chs:04-08-93
+ ( WhoPasswordedTape ( (BYTE_PTR)FS_ViewTapePasswordInVCB( vcb_ptr ), FS_SizeofTapePswdInVCB( vcb_ptr ) ) == OTHER_APP) ) { // chs:04-08-93
+
+ // Popup dialog box message if
+ // not a valid user
+ //
+
+ WM_MsgBox( ID( IDS_TAPE_SECURITY_TITLE ),
+ ID( IDS_GENERAL_TAPE_SECURITY ), WMMB_OK, WMMB_ICONEXCLAMATION );
+ return( SUCCESS ); // return no rights to catalog
+ }
+#endif
+
+ // Start with the lowest numbered set on this tape.
+
+ mwTapeFID = FS_ViewTapeIDInVCB( vcb_ptr );
+ mwTapeNum = FS_ViewTSNumInVCB( vcb_ptr );
+ mwSetNum = GetLowestSetOnTape( mwTapeFID, mwTapeNum );
+ }
+ else {
+
+ // need error msg box here ?????
+
+ return( FAILURE );
+ }
+ }
+
+ if ( FS_OpenFileSys( &mwFsh, GENERIC_DATA, CDS_GetPermBEC() ) ) {
+ // need error msg box here ?????
+ return( FAILURE );
+ }
+
+ gbCurrentOperation = OPERATION_CATALOG;
+ SetStatusBlock(IDSM_OPERATIONSTATUS, STAT_OPER_CATALOG);
+
+ mwTimerHandle = WM_HookTimer( ClockRoutine, 1 );
+ PD_StopPolling();
+
+ // start logging and display operation title in log file.
+ lresprintf( LOGGING_FILE, LOG_START, TRUE );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, IDS_DLGTITLEJOBSTATCATALOG ) ;
+
+ // Determine starting tape to ask for.
+
+ mwOperation = DetermineFirstSet( );
+
+ do {
+
+ mwSkipThisTape = FALSE;
+ mwLoadSetMapCalled = FALSE;
+
+ if ( ShouldWeLoadSetMap( &OTC ) ) {
+
+ OTC = FALSE;
+
+ Status = LoadTheSetMap( );
+
+ // Indicate we have tried.
+
+ mwSetMapLoaded = TRUE;
+
+ switch ( Status ) {
+
+ case LSM_NO_TAPE:
+ // End operation, user refused to supply correct tape.
+ mwOperation = OPER_NONE;
+ break;
+
+ case LSM_NO_SM_FID:
+ // No SM format used on tape.
+ mwOTCFailure = TRUE;
+ break ;
+
+ case LSM_NO_SM_TAPE:
+ // This tape has no SM, but next one might.
+ break;
+
+ case LSM_SM_LOADED:
+ OTC = TRUE;
+ break;
+
+ case LSM_USER_ABORT:
+ mwOperation = OPER_NONE;
+ break;
+
+ case LSM_OTC_FAILURE:
+
+ // Need message box. Failed to load OTC,
+ // hard drive may be full.
+
+ WM_MsgBox( ID( IDS_CATINFOTITLE ),
+ ID( IDS_CATLOADERROR ),
+ WMMB_OK,
+ WMMB_ICONINFORMATION );
+ break;
+
+ case LSM_BIG_ERROR:
+ mwOperation = OPER_NONE;
+
+ WM_MsgBox( ID(IDS_POLLDRIVE_MESSAGE ),
+ ID(IDS_POLLDRIVE_MESSAGE ),
+ WMMB_OK,
+ WMMB_ICONINFORMATION );
+
+ break;
+
+ }
+
+ JobStatusBackupRestore( JOB_STATUS_ABORT_CHECK );
+
+ /* Check for user abort */
+
+ if ( UI_CheckUserAbort( 0 ) ) {
+ mwUserAbort = TRUE;
+ mwOperation = OPER_NONE;
+ }
+
+ if ( OTC && ! mwUserAbort && ( mwOperation != OPER_NONE ) ) {
+
+ // Set Map was loaded.
+ // Feed all the sets into the catalogs. The catalogs will
+ // ignore any it already has.
+
+ SetsChanged = FALSE;
+ SetsAdded = FALSE;
+
+ while ( TF_GetNextSMEntry( mwFsh, &vcb ) == TFLE_NO_ERR ) {
+
+ SetsChanged = TRUE;
+ UI_DisplayVCB( &vcb );
+
+ if ( mwOperation == OPER_TAPE_PART ) {
+
+ TempFID = FS_ViewTapeIDInVCB( &vcb );
+ TempSeq = FS_ViewTSNumInVCB( &vcb );
+ TempSet = FS_ViewBSNumInVCB( &vcb );
+
+ if ( VLM_FindBset( TempFID, TempSet ) == NULL ) {
+ SetsAdded = TRUE;
+ }
+ }
+
+ mwQTC = QTC_GetBuildHandle( );
+ QTC_DoFullCataloging( mwQTC, FALSE );
+ QTC_StartBackup( mwQTC, &vcb );
+ if ( VLM_CheckForCatalogError( mwQTC ) != SUCCESS ) {
+ QTC_FreeBuildHandle( mwQTC );
+ mwQTC = NULL;
+ mwUserAbort = TRUE;
+ mwOperation = OPER_NONE;
+ break;
+ }
+ QTC_FreeBuildHandle( mwQTC );
+ mwQTC = NULL;
+ }
+
+
+ if ( ! SetsAdded && mwOperation == OPER_TAPE_PART ) {
+
+ // Display message no new sets found.
+
+ WM_MsgBox( ID( IDS_CATINFOTITLE ),
+ ID( IDS_NOSETSADDED ),
+ WMMB_OK, WMMB_ICONINFORMATION );
+
+ }
+
+ if ( SetsChanged ) {
+ VLM_CatalogSync( VLM_SYNCMORE );
+ }
+
+ if ( mwOperation == OPER_TAPE_PART ) {
+ mwOperation = OPER_NONE;
+ }
+
+ mwOperation = ReCheckSet( );
+ }
+ }
+
+
+ if ( mwLoadSetMapCalled ) {
+ TF_CloseSetMap( (BOOLEAN)mwUserAbort );
+ mwLoadSetMapCalled = FALSE;
+ }
+
+ // Can we adjust the TapeNum field now ?
+
+ FDD = FALSE; // Assume worst.
+ mwSkipThisSet = FALSE; // Used if already fully cataloged.
+ LoadFDDCalled = FALSE;
+
+ if ( ShouldWeLoadFDD( ) && ( mwOperation != OPER_NONE ) ) {
+
+ // load fdd for a specific set
+
+ Status = LoadFDD( &LoadFDDCalled );
+
+ switch ( Status ) {
+
+ case LFDD_NO_FDD:
+ break;
+
+ case LFDD_LOADED:
+ FDD = TRUE;
+ break;
+
+ case LFDD_ERROR:
+ mwOperation = OPER_NONE;
+
+ WM_MsgBox( ID( IDS_CATINFOTITLE ),
+ ID( IDS_CATLOADERROR ),
+ WMMB_OK, WMMB_ICONINFORMATION );
+
+ break;
+ }
+ }
+
+ JobStatusBackupRestore( JOB_STATUS_ABORT_CHECK );
+
+ /* Check for user abort */
+
+ if ( UI_CheckUserAbort( 0 ) ) {
+ mwUserAbort = TRUE;
+ mwOperation = OPER_NONE;
+ }
+
+ if ( ! mwSkipThisSet && mwOperation != OPER_NONE ) {
+ CallLoops( FDD );
+ }
+
+ mwSkipThisSet = FALSE;
+
+ if ( LoadFDDCalled ) {
+ TF_CloseSetCat( (BOOLEAN)mwUserAbort );
+ }
+
+ if ( mwUserAbort ) {
+ mwOperation = OPER_NONE;
+ }
+
+ mwOperation = DetermineNextSet( OTC, FDD );
+
+ } while ( mwOperation != OPER_NONE );
+
+ EndOfOperation( );
+
+ return( SUCCESS );
+}
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT ShouldWeLoadFDD( )
+{
+ UINT32 flags;
+ BSET_OBJECT_PTR bset;
+
+ if ( gfIgnoreOTC || mwOTCFailure ) {
+ return( FALSE );
+ }
+
+
+ switch ( mwOperation ) {
+
+ case OPER_NONE:
+ break;
+
+ case OPER_TAPE_FULL:
+
+ // See if we have hit the end of the sets. Ie. we have loaded
+ // the set map for this tape and yet the one we want is unknown.
+
+ if ( mwSetMapLoaded ) {
+ if ( QTC_FindBset( mwTapeFID, mwTapeNum, mwSetNum ) == NULL ) {
+ mwTapeNum++; // bump the tape number.
+ if ( QTC_FindBset( mwTapeFID, mwTapeNum, mwSetNum ) == NULL ) {
+ mwOperation = OPER_NONE;
+ return( FALSE );
+ }
+ }
+ }
+
+ // See if this set is already cataloged full.
+
+ bset = VLM_FindBset( mwTapeFID, mwSetNum );
+ if ( bset != NULL ) {
+ if ( bset->full && ! bset->missing && ! bset->incomplete ) {
+ mwSkipThisSet = TRUE;
+ return( FALSE );
+ }
+ }
+
+ if ( GetBestOTCFlags( mwTapeFID, -1, mwSetNum, &flags ) == SUCCESS ) {
+ if ( flags & QTC_OTCVALID ) {
+ if ( flags & QTC_FDDEXISTS ) {
+ return( TRUE );
+ }
+ }
+ }
+ break;
+
+ case OPER_BSET_FULL:
+
+ bset = VLM_FindBset( mwTapeFID, mwSetNum );
+ if ( bset != NULL ) {
+ if ( bset->full && ! bset->incomplete && ! bset->missing ) {
+ return( FALSE );
+ }
+ }
+
+ if ( GetBestOTCFlags( mwTapeFID, -1, mwSetNum, &flags ) == SUCCESS ) {
+ if ( flags & QTC_OTCVALID ) {
+ if ( flags & QTC_FDDEXISTS ) {
+ return( TRUE );
+ }
+ }
+ }
+ break;
+
+ case OPER_TAPE_PART:
+ break;
+ }
+
+ return( FALSE );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT ShouldWeLoadSetMap( INT *OTC )
+{
+ UINT32 flags;
+
+ *OTC = FALSE;
+
+
+ if ( gfIgnoreOTC || mwOTCFailure ) {
+ return( FALSE );
+ }
+
+
+ switch ( mwOperation ) {
+
+ case OPER_NONE:
+ break;
+
+ case OPER_TAPE_PART:
+
+ // See if the sets on this tape have a setmap.
+
+ if ( GetBestOTCFlags( mwTapeFID, mwTapeNum, -1, &flags ) == SUCCESS ) {
+ if ( ! ( flags & QTC_SMEXISTS ) ) {
+ mwOTCFailure = TRUE;
+ return( FALSE );
+ }
+ }
+ return( TRUE );
+ break;
+
+
+ case OPER_TAPE_FULL:
+
+ // See if we have hit the end of the sets. Ie. we have loaded
+ // the set map for this tape and yet the one we want is unknown.
+
+ if ( mwSetMapLoaded ) {
+ if ( QTC_FindBset( mwTapeFID, mwTapeNum, mwSetNum ) == NULL ) {
+ mwTapeNum++; // bump tape number.
+ if ( QTC_FindBset( mwTapeFID, mwTapeNum, mwSetNum ) == NULL ) {
+ mwOperation = OPER_NONE;
+ }
+ }
+ return( FALSE );
+ }
+
+
+ // Set map has NOT been loaded.
+ // See if the sets on this tape have a setmap.
+
+ if ( GetBestOTCFlags( mwTapeFID, mwTapeNum, -1, &flags ) == SUCCESS ) {
+ if ( ! ( flags & QTC_SMEXISTS ) ) {
+ mwOTCFailure = TRUE;
+ return( FALSE );
+ }
+ else {
+ return( TRUE );
+ }
+ }
+ else {
+
+ // Some serious error occurred if we could not get
+ // BestOTCFlags()
+
+ return( FALSE );
+
+ }
+
+ break;
+
+
+ case OPER_BSET_FULL:
+
+
+ // See if we have a valid setmap vcb for this set.
+
+ if ( GetBestOTCFlags( mwTapeFID, mwTapeNum, mwSetNum, &flags ) == SUCCESS ) {
+ if ( flags & QTC_SMEXISTS ) {
+ if ( flags & QTC_OTCVALID ) {
+ *OTC = TRUE;
+ return( FALSE );
+ }
+ else {
+ return( TRUE );
+ }
+ }
+ else {
+
+ mwOTCFailure = TRUE;
+ }
+ }
+ break;
+ }
+
+ return( FALSE );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT DetermineFirstSet( )
+{
+ BSET_OBJECT_PTR VlmBsetPtr;
+ UINT32 flags;
+
+ // If we are fully cataloging a set with OTC and FDD
+ // Then use the TapeNum it ends on.
+ // But how do we know for sure until we load the SetMap ?
+
+ if ( ( mwOperation == OPER_BSET_FULL ) && ! (gfIgnoreOTC || mwOTCFailure) ) {
+
+ VlmBsetPtr = VLM_FindBset( mwTapeFID, mwSetNum );
+
+ if ( VlmBsetPtr != NULL ) {
+
+ mwTapeNum = VlmBsetPtr->base_tape;
+
+ if ( GetBestOTCFlags( mwTapeFID, mwTapeNum, mwSetNum, &flags ) == SUCCESS ) {
+
+ if ( flags & QTC_SMEXISTS ) {
+
+ mwTapeNum = VlmBsetPtr->base_tape + VlmBsetPtr->num_tapes - 1;
+ }
+ }
+ }
+ }
+
+ if ( ( mwOperation == OPER_TAPE_FULL ) && ! (gfIgnoreOTC||mwOTCFailure) ) {
+
+ // Always start with set 1, tape 1.
+
+ mwTapeNum = 1;
+ mwSetNum = 1;
+ }
+
+ return( mwOperation );
+}
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT DetermineNextSet(
+INT OTC,
+INT FDD )
+{
+ BSET_OBJECT_PTR bset;
+
+ if ( mwEOD ) {
+ return( OPER_NONE );
+ }
+
+ if ( mwEOM && ! (gfIgnoreOTC || mwOTCFailure) ) {
+ mwTapeNum++;
+ return( mwOperation );
+ }
+
+ switch ( mwOperation ) {
+
+ case OPER_BSET_FULL:
+ if ( FDD ) return( OPER_NONE );
+ else {
+ bset = VLM_FindBset( mwTapeFID, mwSetNum );
+ if ( mwTapeNum < bset->base_tape + bset->num_tapes - 1 ) {
+ mwTapeNum++;
+ }
+ else {
+ return( OPER_NONE );
+ }
+ }
+ break;
+
+ case OPER_TAPE_FULL:
+ mwSetNum++;
+ break;
+
+ case OPER_TAPE_PART:
+ mwSetNum++;
+ break;
+
+ default:
+ break;
+ }
+
+ return( mwOperation );
+}
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT ReCheckSet( )
+{
+ BSET_OBJECT_PTR VlmBsetPtr;
+ UINT32 flags;
+
+ if ( ! (gfIgnoreOTC || mwOTCFailure) ) {
+
+ if ( mwOperation == OPER_BSET_FULL || mwOperation == OPER_TAPE_FULL ) {
+
+ GetBestOTCFlags( mwTapeFID, mwTapeNum, mwSetNum, &flags );
+ VlmBsetPtr = VLM_FindBset( mwTapeFID, mwSetNum );
+
+ // Need to cover crossing sets. BUGBUG
+
+ if ( VlmBsetPtr != NULL ) {
+
+ mwTapeNum = VlmBsetPtr->base_tape;
+
+ if ( GetBestOTCFlags( mwTapeFID, mwTapeNum, mwSetNum, &flags ) == SUCCESS ) {
+
+ if ( ( flags & QTC_SMEXISTS ) && ( flags & QTC_OTCVALID ) ) {
+
+ mwTapeNum = VlmBsetPtr->base_tape + VlmBsetPtr->num_tapes - 1;
+ }
+ }
+ }
+ }
+ }
+
+ return( mwOperation );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT CallLoops(
+INT FDD )
+{
+ LIS lis;
+ BSD_HAND TempBsdList;
+ CHAR MsgBoxTitle[ MAX_UI_RESOURCE_SIZE ];
+ CHAR MsgBoxText[ MAX_UI_RESOURCE_SIZE ];
+
+ TempBsdList = (BSD_HAND)malloc( sizeof( BSD_LIST ) );
+
+ if ( TempBsdList == NULL ) {
+ return( FAILURE );
+ }
+
+ InitQueue( &(TempBsdList->current_q_hdr) );
+ InitQueue( &(TempBsdList->last_q_hdr) );
+
+ lis.curr_bsd_ptr = CreateAndAddTempBSD( FDD, TempBsdList );
+
+ if ( lis.curr_bsd_ptr == NULL ) {
+ return( FAILURE );
+ }
+
+ lis.vmem_hand = NULL;
+ lis.bsd_list = TempBsdList;
+ lis.tape_pos_handler = TapePositioner; /* set tape positioner to call */
+ lis.message_handler = TapeMsgHandler; /* set message handler to call */
+ lis.oper_type = CATALOG_TAPE_OPER; /* set operation type */
+ lis.abort_flag_ptr = &gb_abort_flag; /* set abort flag address */
+ lis.auto_det_sdrv = FALSE;
+ gb_last_operation = CATALOG_TAPE_OPER;
+
+ LP_SetAbortFlag( &lis, CONTINUE_PROCESSING );
+
+ /* set the Runtime abort flag pointer */
+ JobStatusAbort( lis.abort_flag_ptr );
+
+ if ( FDD ) {
+
+ if ( mwRuntime == RUNTIME_NONE ) {
+ DisplayRuntime( RUNTIME_SMALL );
+ }
+
+ if ( mwRuntime != RUNTIME_NONE ) {
+ mwDisplayRewind = FALSE;
+
+ RSM_StringCopy( IDS_CATINFOTITLE, MsgBoxTitle, MAX_UI_RESOURCE_LEN );
+ RSM_StringCopy( IDS_NOSETSADDED, MsgBoxText, MAX_UI_RESOURCE_LEN );
+
+ yresprintf( IDS_CAT_LOADING_FDD );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ }
+
+ /* enable the abort button for the runtime dialog */
+ JobStatusBackupRestore( JOB_STATUS_ABORT_ENABLE ) ;
+
+ LP_Tape_Cat_Engine( &lis );
+ }
+ else {
+
+ if ( mwRuntime != RUNTIME_LARGE ) {
+ DisplayRuntime( RUNTIME_LARGE );
+ }
+
+ /* enable the abort button for the runtime dialog */
+ JobStatusBackupRestore( JOB_STATUS_ABORT_ENABLE ) ;
+
+ LP_List_Tape_Engine( &lis );
+ }
+
+ if ( mwUserAbort ) {
+
+ mwOperation = OPER_NONE;
+ }
+
+ BSD_Remove( lis.curr_bsd_ptr );
+
+ free( TempBsdList );
+
+ return( SUCCESS );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+ Do one of:
+ 1. load the EOD SM.
+ { possibly prompting for and receiving continuation tapes }
+ 2. load the SM and any continuation sets on the tape .
+ { possibly prompting for and receiving continuation tapes }
+ 3. position the tape at the requested VCB for a slow operation.
+ { possibly prompting for and receiving continuation tapes }
+ 4. fail and abort the operation.
+
+ RETURNS :
+ LSM_NO_TAPE - user refused to supply desired tape.
+ LSM_NO_SM_FID - there is no setmap on this tape family.
+ LSM_NO_SM_TAPE - there is no set map on this tape of the family.
+ LSM_SM_LOADED - we loaded the desired set map, life is swell.
+ LSM_USER_ABORT - user aborted.
+ LSM_BIG_ERROR - tape drive error.
+ LSM_OTC_FAILURE - failed to load otc, hard drive may be full.
+
+**********************/
+
+INT LoadTheSetMap( )
+{
+ INT PromptNextTape = TRUE; // ask for continuation tapes.
+ INT Status = LSM_NO_SM_FID; // assume 3.1 tape.
+ TPOS Tpos;
+ UINT32 flags;
+
+ // Get VCB of tape and check to see if this tape has a SM.
+
+ if ( GetBestOTCFlags( mwTapeFID, -1, -1, &flags ) == SUCCESS ) {
+ if ( ! ( flags & QTC_SMEXISTS ) ) {
+ mwOTCFailure = TRUE;
+ return( LSM_NO_SM_FID );
+ }
+ }
+
+ // Display window to the user. Tell him we are busy loading the setmap.
+
+ if ( mwRuntime == RUNTIME_NONE ) {
+ DisplayRuntime( RUNTIME_SMALL );
+ /* enable the abort button for the runtime dialog */
+ JobStatusBackupRestore( JOB_STATUS_ABORT_ENABLE ) ;
+ }
+
+ if ( mwRuntime != RUNTIME_NONE ) {
+ mwDisplayRewind = FALSE;
+ yresprintf( IDS_CAT_LOADING_SM );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ }
+
+ // Initialize Tpos structure.
+
+ Tpos.tape_id = mwTapeFID;
+ Tpos.tape_seq_num = mwTapeNum;
+ Tpos.backup_set_num = mwSetNum;
+ Tpos.reference = 0L;
+ Tpos.UI_TapePosRoutine = TapePositioner;
+
+ gb_last_operation = CATALOG_TAPE_OPER;
+ gb_abort_flag = CONTINUE_PROCESSING;
+
+ /* set the Runtime abort flag pointer */
+ JobStatusAbort( &gb_abort_flag );
+
+ /* enable the abort button for the runtime dialog */
+ JobStatusBackupRestore( JOB_STATUS_ABORT_ENABLE ) ;
+
+ mwLoadSetMapCalled = TRUE;
+ mwOpenSetMapActive = TRUE;
+
+
+ Status = TF_OpenSetMap( thw_list, mwFsh, &Tpos,
+ (BOOLEAN *)&mwEODSetMapRead,
+ (BOOLEAN)PromptNextTape );
+
+ mwOpenSetMapActive = FALSE;
+
+ // Set Status
+
+ switch ( Status ) {
+
+ case TF_NO_SM_ON_TAPE :
+ case TFLE_OTC_FAILURE:
+ Status = LSM_NO_SM_TAPE ;
+ break ;
+
+ // case TFLE_OTC_FAILURE:
+ // mwOTCFailure = TRUE;
+ // Status = LSM_OTC_FAILURE;
+ // break;
+
+ case TFLE_BAD_SET_MAP:
+ mwOTCFailure = TRUE;
+ Status = LSM_NO_SM_FID;
+ break;
+
+ case TF_NO_SM_FOR_FAMILY:
+ Status = LSM_NO_SM_FID;
+ break;
+
+ case TFLE_NO_ERR:
+ Status = LSM_SM_LOADED;
+ break;
+
+ case TF_END_POSITIONING:
+ case TFLE_UI_HAPPY_ABORT:
+ Status = LSM_USER_ABORT;
+ mwUserAbort = TRUE;
+ break;
+
+
+ default:
+ Status = LSM_BIG_ERROR;
+ break;
+ }
+
+ return( Status );
+}
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+ Do one of:
+ 1. load the complete FDD for the requested set.
+ { possibly prompting for and receiving continuation tapes }
+ 2. position the tape at the requested VCB for a slow operation.
+ { possibly prompting for and receiving continuation tapes }
+ 3. fail and abort the operation.
+
+ RETURNS :
+ LFDD_NO_FDD - No FDD on tape for requested set.
+ LFDD_LOADED - FDD loaded correctly.
+ LFDD_ERROR - Error occurred, No FDD loaded.
+
+**********************/
+
+INT LoadFDD( INT *LoadFDDCalled )
+{
+
+ INT Status = LFDD_NO_FDD; // assume 3.1 tape.
+ TPOS Tpos;
+ INT PromptNextTape = TRUE;
+ INT16 FddSeqNum;
+ UINT8 FddVersion;
+ UINT32 FddPBA;
+
+ UINT32 flags;
+
+ *LoadFDDCalled = FALSE;
+
+ // Get VCB of tape and check to see if this tape has a SM.
+
+ flags = 0;
+
+ if ( GetBestOTCFlags( mwTapeFID, (INT16)-1, mwSetNum, &flags ) == SUCCESS ) {
+ if ( ! ( flags & QTC_SMEXISTS ) ) {
+ mwOTCFailure = TRUE;
+ return( LFDD_NO_FDD );
+ }
+ }
+
+ // Set mwTapeNum to highest numbered set.
+
+ if ( GetBestFDDInfo( mwTapeFID, (INT16)-1, mwSetNum, &FddSeqNum, &FddPBA, &FddVersion ) != SUCCESS ) {
+ return( LFDD_NO_FDD );
+ }
+
+ mwTapeNum = FddSeqNum;
+
+ // Display window to the user. Tell him we are busy loading the setmap.
+
+ if ( mwRuntime == RUNTIME_NONE ) {
+ mwDisplayRewind = FALSE;
+ DisplayRuntime( RUNTIME_SMALL );
+ }
+
+ if ( mwRuntime != RUNTIME_NONE ) {
+ yresprintf( IDS_CAT_LOADING_FDD );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ }
+
+ // Initialize Tpos structure.
+
+ Tpos.tape_id = mwTapeFID;
+ Tpos.tape_seq_num = FddSeqNum;
+ Tpos.backup_set_num = mwSetNum;
+ Tpos.reference = 0L;
+ Tpos.set_cat_seq_num = (INT16)FddSeqNum;
+ Tpos.set_cat_pba = FddPBA;
+ Tpos.tape_cat_ver = FddVersion;
+
+ Tpos.UI_TapePosRoutine = TapePositioner;
+
+ // If mwOperation is fully catalog tape, do not prompt for
+ // continuation tapes.
+
+ if ( mwOperation == OPER_TAPE_FULL ) {
+ PromptNextTape = FALSE;
+ }
+
+ gb_last_operation = CATALOG_TAPE_OPER;
+ gb_abort_flag = CONTINUE_PROCESSING;
+
+ /* set the Runtime abort flag pointer */
+ JobStatusAbort( &gb_abort_flag );
+
+ /* enable the abort button for the runtime dialog */
+ JobStatusBackupRestore( JOB_STATUS_ABORT_ENABLE ) ;
+
+ *LoadFDDCalled = TRUE;
+
+ Status = TF_OpenSetCat( thw_list, mwFsh, &Tpos );
+
+ // adjust status
+
+ if ( Status == TFLE_NO_ERR ) {
+ Status = LFDD_LOADED;
+ }
+ else {
+ Status = LFDD_ERROR;
+ mwOTCFailure = TRUE;
+ }
+
+
+ if ( gb_abort_flag != CONTINUE_PROCESSING ) {
+
+ mwUserAbort = TRUE;
+ }
+
+ return( Status );
+}
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT DisplayRuntime( INT Style )
+{
+ CHAR *s;
+
+ // If its not already up, then display it.
+
+ if ( mwRuntime == RUNTIME_SMALL && Style == RUNTIME_LARGE ) {
+
+ // close small dialog
+
+ JobStatusBackupRestore( JOB_STATUS_DESTROY_DIALOG );
+ mwRuntime = RUNTIME_NONE;
+ }
+
+ if ( mwRuntime == RUNTIME_NONE ) {
+
+ mwRuntime = Style;
+
+ VLM_CloseAll();
+
+ if ( Style == RUNTIME_LARGE ) {
+ JobStatusBackupRestore( JOB_STATUS_CREATE_DIALOG );
+ }
+ else {
+ JobStatusBackupRestore( JOB_STATUS_CREATE_SMALL_DIALOG );
+ }
+
+ // display the restore title for the dialog
+ yresprintf( IDS_DLGTITLEJOBSTATCATALOG );
+ JobStatusBackupRestore( JOB_STATUS_CATALOG_TITLE );
+
+ // display the volume tape bitmap
+ JobStatusBackupRestore( JOB_STATUS_VOLUME_TAPE );
+
+ yresprintf( RES_TITLE_NEW_LINE );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ yresprintf( IDS_DLGTITLEJOBSTATCATALOG );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ yresprintf( RES_TITLE_NEW_LINE );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ yprintf(TEXT("%s\r"), CDS_GetCatDataPath ( ) );
+ JobStatusBackupRestore( JOB_STATUS_DEST_NAME );
+
+ s = VLM_GetTapeName( mwTapeFID );
+
+ if ( s != NULL ) {
+ yprintf( TEXT("%s"), s );
+ JobStatusBackupRestore( JOB_STATUS_SOURCE_NAME ) ;
+ }
+
+ /* set the Runtime abort flag pointer */
+ JobStatusAbort( &gb_abort_flag );
+
+ /* enable the abort button for the runtime dialog */
+ JobStatusBackupRestore( JOB_STATUS_ABORT_ENABLE ) ;
+
+ }
+ return( SUCCESS );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT EndOfOperation()
+{
+ // Mark end of operation in log file.
+
+ lresprintf( LOGGING_FILE, LOG_END );
+
+ // See if any errors occurred.
+
+ UI_ChkDispGlobalError( );
+
+ // Unhook our clock timer.
+
+ WM_UnhookTimer( mwTimerHandle );
+
+ // Close the generic file system using the stored file system handle.
+
+ if ( mwFsh ) {
+ FS_CloseFileSys( mwFsh );
+ }
+
+ // Tell the world we are doing nothing.
+
+ gbCurrentOperation = OPERATION_NONE;
+ SetStatusBlock(IDSM_OPERATIONSTATUS, STAT_OPER_IDLE);
+
+ // Auto close dialog if simple, error free, single set catalog w/ otc.
+
+ if ( ( ! gb_error_during_operation ) &&
+ mwRuntime == RUNTIME_SMALL ) {
+
+ JobStatusBackupRestore( JOB_STATUS_DESTROY_DIALOG );
+ mwRuntime = RUNTIME_NONE;
+ }
+
+ if ( mwRuntime != RUNTIME_NONE ) {
+ JobStatusBackupRestore( JOB_STATUS_ABORT_OFF );
+ mwRuntime = RUNTIME_NONE;
+ }
+
+ // Restart poll drive.
+
+ PD_StartPolling( );
+
+ return( SUCCESS );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+BSD_PTR CreateAndAddTempBSD(
+INT FDD,
+BSD_HAND TempBsdList )
+{
+ CHAR_PTR s;
+ FSE_PTR fse_ptr;
+ BE_CFG_PTR bec_config;
+ DATE_TIME date;
+ BSD_PTR bsd_ptr;
+
+ /* check for a valid bsd first, set to search for first set if needed */
+
+ bec_config = BEC_CloneConfig( CDS_GetPermBEC() );
+ BEC_UnLockConfig( bec_config );
+
+
+ if ( ( gfIgnoreOTC || mwOTCFailure ) &&
+ ( ( mwOperation == OPER_TAPE_FULL ) ||
+ ( mwOperation == OPER_TAPE_PART ) ) ) {
+
+ // We'll catalog the entire tape family if they will provide it.
+
+ if ( BSD_Add( TempBsdList, &bsd_ptr,
+ bec_config,
+ NULL, NULL, (UINT32)-1, (UINT16)-1, (INT16)-1,
+ thw_list, NULL ) == OUT_OF_MEMORY ) {
+
+ return( NULL );
+ }
+
+ }
+ else {
+
+ if ( BSD_Add( TempBsdList, &bsd_ptr,
+ bec_config,
+ NULL, NULL, mwTapeFID, mwTapeNum, mwSetNum,
+ thw_list, NULL ) == OUT_OF_MEMORY ) {
+
+ return( NULL );
+ }
+ }
+
+ if ( VLM_GetTapeName( mwTapeFID ) ) {
+ s = VLM_GetTapeName( mwTapeFID );
+ BSD_SetTapeLabel( bsd_ptr, (INT8_PTR)s, (INT16)strsize( s ));
+ }
+
+ s = VLM_GetBsetName( mwTapeFID, mwSetNum );
+
+ if ( s != NULL ) {
+ BSD_SetBackupLabel( bsd_ptr,
+ (INT8_PTR)s,
+ (INT16)strsize( s ) );
+
+ BSD_SetBackupDescript( bsd_ptr,
+ (INT8_PTR)s,
+ (INT16)strsize( s ) );
+ }
+
+ DateTimeDOS( VLM_GetBackupDate( mwTapeFID, mwSetNum ),
+ VLM_GetBackupTime( mwTapeFID, mwSetNum ),
+ &date );
+
+ BSD_SetDate( bsd_ptr, &date );
+
+ // Jump to right set if we know it is all on one tape.
+ // set bsd pba only if non-otc tape
+
+ if ( ! FDD ) {
+
+
+ // If we set the pba for OPER_TAPE_FULL then it will catalog set 1
+ // and then stop. mikep
+
+ if ( mwOperation == OPER_BSET_FULL ) {
+ BSD_SetPBA( bsd_ptr, QTC_GetMeTheVCBPBA( mwTapeFID, mwTapeNum, mwSetNum ) );
+ }
+ }
+
+ if ( BSD_CreatFSE( &fse_ptr, INCLUDE, (INT8_PTR)TEXT("\0"), (UINT16)sizeof(CHAR),
+ (INT8_PTR)ALL_FILES, ALL_FILES_LENG,
+ USE_WILD_CARD, TRUE ) != SUCCESS ) {
+
+ return( NULL );
+ }
+
+ BSD_AddFSE( bsd_ptr, fse_ptr );
+
+ if ( ( gfIgnoreOTC || mwOTCFailure ) &&
+ ( ( mwOperation == OPER_TAPE_FULL ) ||
+ ( mwOperation == OPER_TAPE_PART ) ) ) {
+ BSD_SetTapePos( bsd_ptr, (UINT32)-1, (UINT16)-1, (UINT16)-1 );
+ }
+ else {
+ BSD_SetTapePos( bsd_ptr, mwTapeFID, mwTapeNum, mwSetNum );
+ }
+
+ return( bsd_ptr );
+}
+
+
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+UINT16 TapePositioner(
+UINT16 message,
+TPOS_PTR tpos,
+BOOLEAN curr_valid_vcb,
+DBLK_PTR cur_vcb,
+UINT16 mode )
+{
+ UINT16 response = UI_ACKNOWLEDGED;
+ LIS_PTR lis_ptr = ( LIS_PTR )tpos->reference;
+ BSD_PTR bsd_ptr = NULL;
+ CHAR_PTR TapeName;
+ CHAR Buffer[ MAX_UI_RESOURCE_SIZE ];
+
+ if ( lis_ptr != NULL ) {
+ bsd_ptr = (BSD_PTR)lis_ptr->curr_bsd_ptr;
+ }
+
+ JobStatusBackupRestore( JOB_STATUS_ABORT_CHECK );
+
+ /* Check for user abort */
+
+ if ( UI_CheckUserAbort( message ) ) {
+ QTC_AbortCataloging( mwQTC, TRUE );
+ mwUserAbort = TRUE;
+ mwOperation = OPER_NONE;
+ return( UI_ABORT_POSITIONING );
+ }
+
+ switch ( message ) {
+
+ case TF_VCB_BOT:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+
+ // if we've been here before
+ if ( ( gfIgnoreOTC || mwOTCFailure ) &&
+ ( ! mwBeenHereBefore ) ) {
+
+ mwBeenHereBefore = TRUE;
+ response = UI_UpdateTpos( tpos, cur_vcb, FALSE );
+
+ }
+ else {
+ response = UI_HAPPY_ABORT;
+ }
+ break;
+
+ case TF_POSITIONED_AT_A_VCB:
+ case TF_ACCIDENTAL_VCB:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+
+ if ( ( gfIgnoreOTC || mwOTCFailure ) &&
+ ( ( mwOperation == OPER_TAPE_FULL ) ||
+ ( mwOperation == OPER_TAPE_PART ) ) ) {
+
+ response = UI_UpdateTpos( tpos, cur_vcb, FALSE );
+
+ }
+ else {
+ UI_DisplayVCB( cur_vcb );
+ response = UI_CONTINUE_POSITIONING;
+ }
+ break;
+
+ case TF_REQUESTED_VCB_FOUND:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+
+ // Just do one set
+
+ if ( ( gfIgnoreOTC || mwOTCFailure ) &&
+ ( ( mwOperation == OPER_TAPE_FULL ) ||
+ ( mwOperation == OPER_TAPE_PART ) ) ) {
+
+ response = UI_UpdateTpos( tpos, cur_vcb, FALSE );
+
+ }
+ else {
+ if ( ( FS_ViewBSNumInVCB( cur_vcb ) == BSD_GetSetNum( bsd_ptr ) ) &&
+ ( FS_ViewTapeIDInVCB( cur_vcb ) == BSD_GetTapeID( bsd_ptr ) ) ) {
+
+ response = UI_UpdateTpos( tpos, cur_vcb, FALSE );
+ }
+ else {
+ response = UI_ABORT_POSITIONING;
+ }
+ }
+ break;
+
+ case TF_VCB_EOD:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+
+ // They just finished an append, and we are sitting at the EOD
+ // and TF was nice enough to send us the VCB for the last set.
+ mwDisplayRewind = TRUE;
+ response = UI_BOT;
+ break;
+
+ case TF_UNRECOGNIZED_MEDIA:
+
+ // display the unrecognizable tape - unformatted tape message
+ yresprintf( (INT16) IDS_VLMUNFORMATEDTEXT ) ;
+ WM_MessageBox( ID( IDS_VLMUNFORMATEDTITLE ) ,
+ gszTprintfBuffer ,
+ WMMB_OK,
+ WMMB_ICONEXCLAMATION, NULL, 0, 0 ) ;
+
+ // Note: allow this case to drop into the TF_NO_TAPE_PRESENT,
+ // to prompt for the tape again
+
+ case TF_NO_TAPE_PRESENT:
+
+ case TF_NEED_NEW_TAPE:
+ case TF_WRONG_TAPE:
+ case TF_INVALID_VCB:
+ case TF_EMPTY_TAPE:
+ case TF_FUTURE_REV_MTF:
+ case TF_MTF_ECC_TAPE:
+ case TF_SQL_TAPE:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+ SetStatusBlock(IDSM_DRIVESTATUS, STAT_DRIVE_FOREIGN);
+
+ if ( message == TF_NO_TAPE_PRESENT ) {
+ mwRetryCount++;
+ }
+ else {
+
+ mwRetryCount = 0;
+
+ // See if we can correct the sequence number we want.
+ if ( tpos->tape_seq_num != -1 ) {
+ mwTapeNum = tpos->tape_seq_num;
+ }
+ else {
+ if ( ( gfIgnoreOTC || mwOTCFailure ) &&
+ ( ( mwOperation == OPER_TAPE_PART ) ||
+ ( mwOperation == OPER_TAPE_FULL ) ) ) {
+
+ mwTapeNum++;
+ }
+ }
+ }
+
+ if ( ( mwRetryCount == 0 ) || ( mwRetryCount > mwTapeSettlingCount ) ) {
+
+ ST_StartBackupSetIdle( &mwOpStats );
+
+ // Try several things to get the right tape name.
+
+ TapeName = NULL;
+
+ if ( bsd_ptr != NULL ) {
+ TapeName = UI_DisplayableTapeName( (LPSTR)BSD_GetTapeLabel( bsd_ptr ),
+ BSD_ViewDate( bsd_ptr ) );
+
+ // Kludge on next line.
+ bsd_ptr->tape_num = tpos->tape_seq_num;
+ }
+ if ( TapeName == NULL && tpos->tape_id != (UINT32)-1 ) {
+ TapeName = VLM_GetTapeName( tpos->tape_id );
+ }
+
+ // Give up and just ask for "the tape".
+ if ( TapeName == NULL ) {
+ RSM_StringCopy( IDS_CAT_TAPENAME, Buffer, sizeof( Buffer ) );
+ TapeName = Buffer;
+ }
+
+ mwRetryCount = 0;
+ response = PromptForTape( ASK_FORTAPE,
+ mwTapeNum,
+ TapeName, mwDriveName );
+
+ ST_EndBackupSetIdle( &mwOpStats );
+ }
+ else {
+#ifdef OS_WIN32
+ NtDemoChangeTape( (UINT16)mwTapeNum ) ;
+#endif
+ Sleep( (DWORD)3000 );
+ response = UI_NEW_TAPE_INSERTED;
+ }
+
+ if ( response != UI_NEW_TAPE_INSERTED ) {
+ mwRetryCount = 0;
+ mwOperation = OPER_NONE;
+ mwUserAbort = TRUE;
+ mwAbortAtEOM = TRUE;
+ }
+ else {
+ mwBeenHereBefore = FALSE;
+ }
+
+ break;
+
+ case TF_NO_MORE_DATA:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+
+ mwEOD = TRUE;
+ mwDisplayRewind = TRUE;
+ response = UI_HAPPY_ABORT;
+ break;
+
+
+ case TF_READ_ERROR:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ response = UI_HandleTapeReadError( mwDriveName );
+ mwOperation = OPER_NONE;
+ break;
+
+ case TF_SEARCHING:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ yresprintf( RES_SEARCHING );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ break;
+
+ case TF_REWINDING:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ if ( mwDisplayRewind ) {
+ mwDisplayRewind = FALSE;
+ yresprintf( RES_REWINDING );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ }
+ break;
+
+ case TF_DRIVE_BUSY:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ SetStatusBlock(IDSM_DRIVESTATUS, STAT_DRIVE_BUSY);
+ yresprintf( RES_WAITING );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ break;
+
+ case TF_IDLE_NOBREAK:
+ case TF_IDLE:
+ case TF_SKIPPING_DATA:
+ case TF_MOUNTING:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ WM_MultiTask();
+ break;
+
+ // Should only happen with Sytos + tapes. User left tape >= 2
+ // in the drive. We can't continue.
+
+ case TF_TAPE_OUT_OF_ORDER:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+ eresprintf( RES_POLL_DRIVE_GOOFY_TAPE, message );
+ response = UI_ABORT_POSITIONING;
+ mwOperation = OPER_NONE;
+ QTC_AbortCataloging( mwQTC, TRUE );
+ break;
+
+ default:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+ eresprintf( RES_UNKNOWN_TF_MSG, message );
+ response = UI_ABORT_POSITIONING;
+ mwOperation = OPER_NONE;
+ QTC_AbortCataloging( mwQTC, TRUE );
+ break;
+ }
+
+ return( response );
+}
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT16 TapeMsgHandler(
+UINT16 msg,
+INT32 pid,
+BSD_PTR bsd_ptr,
+FSYS_HAND fsh,
+TPOS_PTR tpos,
+... )
+{
+ va_list arg_ptr;
+ DBLK_PTR dblk_ptr;
+ INT16 response = MSG_ACK;
+ BOOLEAN AlreadyCataloged;
+ OBJECT_TYPE object_type;
+ UINT64 count;
+ UINT16 os_id;
+ UINT16 os_ver;
+ INT16 error;
+
+ QTC_BSET_PTR qtc_bset_ptr; // handle for doing catalogs
+
+ static CHAR_PTR path = NULL; // pointer to space
+ static INT path_length; // bytes in use
+ static INT root_counted; // have we counted the root yet ?
+ static CHAR_PTR buffer = NULL;
+ static CHAR delimiter = TEXT('\\');
+ static DBLK SavedVCB;
+ static UINT NumTapesCrossed;
+
+ va_start( arg_ptr, tpos );
+
+ JobStatusBackupRestore( JOB_STATUS_ABORT_CHECK );
+
+
+ if ( gb_abort_flag != CONTINUE_PROCESSING ) {
+
+ mwUserAbort = TRUE;
+ }
+
+ switch ( (INT16)msg ) {
+
+// You know it !
+// We are talking kludge city here. Keep the error
+// message from being displayed to the user.
+
+#ifdef MS_RELEASE
+ case -533:
+ zprintf( DEBUG_TEMPORARY, TEXT("** -533 LOOPS ERROR **") );
+ break;
+#endif
+
+
+ case MSG_CONT_VCB:
+ // This message was added to support 4.0 tape format. The
+ // continuation vcb PBA & LBA cannot be assumed to be 0
+ // because a tape header is placed on the tape. The backup
+ // engine does not know them until it gets the next tape and
+ // writes them on it. This call allows you to go back and
+ // patch the catalogs.
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+
+ QTC_PatchContinuationVCB( mwQTC, dblk_ptr );
+ break;
+
+
+ case MSG_LOG_BLOCK:
+
+ dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+
+
+
+ if ( ! gfIgnoreOTC && ! mwOTCFailure ) {
+
+ // We must check the tape number of the dblk and if it is different
+ // then we must fake an eom operation and a restart operation in
+ // the catalogs. Its OTC and feeding us the whole thing.
+
+ // Make sure in QTC that we save the PBA of the VCB we had prviously.
+ // We won't be sending a QTC_PatchContinuationVCB Msg.
+
+ if ( (UINT)FS_GetBlockTapeSeqNumber( dblk_ptr ) !=
+ FS_ViewTSNumInVCB( &SavedVCB ) + NumTapesCrossed ) {
+ NumTapesCrossed++;
+ QTC_EndOfTape( mwQTC, NULL, NULL, NULL, fsh );
+ }
+
+ }
+
+ QTC_AddToCatalog( mwQTC, dblk_ptr, fsh, FALSE, NULL, 0 );
+
+ ST_StartBackupSetIdle( &mwOpStats );
+
+ if ( gb_abort_flag != ABORT_PROCESSED ) {
+ if ( VLM_CheckForCatalogError( mwQTC ) != SUCCESS ) {
+
+ // Trip the abort flag and get us outa here.
+ // If they can't catalog, don't continue cataloging.
+
+ gb_abort_flag = ABORT_PROCESSED;
+ mwOperation = OPER_NONE;
+ }
+ }
+
+ ST_EndBackupSetIdle( &mwOpStats );
+
+ if ( gb_abort_flag == CONTINUE_PROCESSING ) {
+ // yresprintf( RES_CATALOGING_ITEMS );
+ }
+
+ switch ( FS_GetBlockType( dblk_ptr ) ) {
+
+ /* process a directory or file in the current backup set */
+ case DDB_ID:
+ {
+ INT i;
+ INT item_size;
+
+ // Count all the new directories that showed up in
+ // this DDB.
+
+ // Only count the root once.
+
+ if ( ! root_counted ) {
+ ST_AddBSDirsProcessed( &mwOpStats, 1 );
+ root_counted = TRUE;
+ }
+
+ // Get the new path from the DDB.
+
+ item_size = FS_SizeofOSPathInDDB( fsh, dblk_ptr );
+
+ if ( UI_AllocPathBuffer( &buffer, (UINT16)item_size ) ) {
+ FS_GetOSPathFromDDB( fsh, dblk_ptr, buffer );
+
+ if ( item_size != sizeof(CHAR) ) {
+
+ i = 0;
+ while ( i < (INT)(item_size / sizeof(CHAR)) ) {
+
+ if ( i >= (INT)(path_length / sizeof(CHAR)) ) {
+
+ ST_AddBSDirsProcessed( &mwOpStats, 1 );
+ }
+ else {
+
+ if ( (path == NULL ) || stricmp( &buffer[ i ], &path[ i ] ) ) {
+
+ ST_AddBSDirsProcessed( &mwOpStats, 1 );
+ path_length = 0;
+ }
+ }
+ while ( buffer[ i++ ] );
+ }
+ }
+ }
+
+ // Set up for next time.
+ if ( UI_AllocPathBuffer( &path, (UINT16)item_size) ) {
+ memcpy( path, buffer, item_size );
+ }
+ path_length = item_size;
+
+ count = FS_GetDisplaySizeFromDBLK( fsh, dblk_ptr );
+ ST_AddBSBytesProcessed( &mwOpStats, count );
+
+ UI_BuildDelimitedPathFromDDB( &buffer, fsh, dblk_ptr, delimiter, TRUE );
+ yprintf( TEXT("%s"), buffer );
+
+
+ yprintf( TEXT("%s"), buffer );
+ JobStatusBackupRestore( JOB_STATUS_DIRECTORY_NAMES );
+
+ yprintf(TEXT("%ld\r"), ST_GetBSDirsProcessed( &mwOpStats ) );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_DIRECTORIES_PROCESS );
+
+ ST_EndBackupSet( &mwOpStats );
+ lresprintf( LOGGING_FILE, LOG_DIRECTORY, SES_ENG_MSG, RES_DIRECTORY, buffer );
+ break;
+ }
+
+ case BT_FDB:
+ count = FS_GetDisplaySizeFromDBLK( fsh, dblk_ptr );
+ ST_AddBSBytesProcessed( &mwOpStats, count );
+ ST_AddBSFilesProcessed( &mwOpStats, 1 );
+ FS_GetObjTypeDBLK( fsh, dblk_ptr, &object_type );
+ if ( object_type == AFP_OBJECT ) {
+ ST_AddBSAFPFilesProcessed( &mwOpStats, 1 );
+ }
+
+ if ( CDS_GetFilesFlag( CDS_GetCopy() ) ) {
+ if ( UI_AllocPathBuffer( &buffer, FS_SizeofOSFnameInFDB( fsh, dblk_ptr ) ) ) {
+ FS_GetOSFnameFromFDB( fsh, dblk_ptr, buffer );
+
+ UI_DisplayFile( buffer );
+
+ JobStatusBackupRestore( JOB_STATUS_FILE_NAMES );
+ ST_EndBackupSet( &mwOpStats );
+ }
+ }
+ yprintf(TEXT("%ld\r"), ST_GetBSFilesProcessed( &mwOpStats ));
+ JobStatusBackupRestore( (WORD) JOB_STATUS_FILES_PROCESSED );
+ lresprintf( LOGGING_FILE, LOG_FILE, fsh, dblk_ptr );
+ break;
+
+ /* the current file in the current backup set is corrupt */
+ case CFDB_ID:
+ QTC_BlockBad( mwQTC );
+ break;
+
+ /* image set slipped by us */
+ case BT_IDB:
+ QTC_ImageScrewUp( mwQTC );
+ gb_abort_flag = ABORT_PROCESSED;
+ break;
+
+ /* should not be anything else, so abort out ... */
+ default:
+ break;
+ }
+
+ break;
+
+ case MSG_START_BACKUP_SET:
+ {
+ UINT32 LocalFID;
+ INT16 LocalSeq;
+ INT16 LocalSet;
+ DBLK temp_dblk;
+ BSET_OBJECT_PTR bset;
+
+ dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+
+ NumTapesCrossed = 0;
+
+ // reset our directory counter stuff.
+
+ root_counted = FALSE;
+ path_length = 0;
+ UI_FreePathBuffer( & path );
+ path = NULL;
+
+ // see if this set is already in the catalogs
+
+ AlreadyCataloged = FALSE;
+
+ if ( dblk_ptr == NULL ) {
+
+ bset = VLM_FindBset( mwTapeFID, mwSetNum );
+
+ if ( bset != NULL ) {
+ LocalSeq = bset->base_tape;
+ }
+ else {
+ LocalSeq = mwTapeNum;
+ }
+
+ LocalFID = mwTapeFID;
+ LocalSet = mwSetNum;
+ dblk_ptr = &temp_dblk;
+ CreateVCBFromQTC( LocalFID, LocalSeq, LocalSet, &temp_dblk, mwFsh );
+ }
+ else {
+ LocalFID = FS_ViewTapeIDInVCB( dblk_ptr );
+ LocalSeq = FS_ViewTSNumInVCB( dblk_ptr );
+ LocalSet = FS_ViewBSNumInVCB( dblk_ptr );
+ }
+
+ qtc_bset_ptr = QTC_FindBset( LocalFID,
+ LocalSeq,
+ LocalSet );
+
+ if ( qtc_bset_ptr != NULL ) {
+ AlreadyCataloged = TRUE;
+ }
+
+ // Start cataloging operation
+
+ mwQTC = QTC_GetBuildHandle( );
+ if ( mwOperation == OPER_BSET_FULL ||
+ mwOperation == OPER_TAPE_FULL ) {
+ QTC_DoFullCataloging( mwQTC, TRUE );
+ }
+ else {
+ QTC_DoFullCataloging( mwQTC, FALSE );
+ }
+
+ response = QTC_StartBackup( mwQTC, dblk_ptr );
+
+ memcpy( &SavedVCB, dblk_ptr, sizeof( DBLK ) );
+
+ // See if we will be cataloging the files in this set.
+
+ ST_StartBackupSet( &mwOpStats );
+
+ UI_Time( &mwOpStats, RES_CATALOG_STARTED, UI_START );
+
+ if ( response == SKIP_TO_NEXT_BSET ) {
+
+ // Either set is already fully cataloged or
+ // we are partially cataloging the tape or both.
+
+ // maybe it was an image backup set
+
+ FS_GetOSid_verFromDBLK( fsh, dblk_ptr, &os_id, &os_ver );
+
+ if ( os_id == FS_PC_IMAGE ) {
+
+ yresprintf( RES_IMAGE_BACKUP,
+ LocalSet,
+ FS_ViewSetNameInVCB( dblk_ptr ) ) ;
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX ) ;
+ }
+ else {
+
+ if ( mwOperation == OPER_TAPE_FULL ) {
+
+ // Previously cataloged with file details.
+
+ yresprintf( RES_ALREADY_FULLY_CATALOGED,
+ LocalSet,
+ FS_ViewSetNameInVCB( dblk_ptr ) ) ;
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX ) ;
+
+ }
+ else {
+
+ // Previously partially or fully cataloged.
+
+ if ( AlreadyCataloged ) {
+
+ // Set was already in catalogs.
+
+ yresprintf( RES_ALREADY_CATALOGED_SET,
+ LocalSet,
+ FS_ViewSetNameInVCB( dblk_ptr ) ) ;
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX ) ;
+
+ }
+ else {
+
+ // Set was added, we are cataloging partial.
+
+ yresprintf( RES_NEWLY_CATALOGED_SET,
+ LocalSet,
+ FS_ViewSetNameInVCB( dblk_ptr ) );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ yresprintf( RES_DISPLAY_VOLUME,
+ FS_ViewVolNameInVCB( dblk_ptr ),
+ LocalSet,
+ LocalSeq,
+ FS_ViewSetNameInVCB( dblk_ptr ) ); // chs:06-11-93
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ }
+ }
+ }
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_DISPLAY_VOLUME,
+ FS_ViewVolNameInVCB( dblk_ptr ),
+ LocalSet,
+ LocalSeq,
+ FS_ViewSetNameInVCB( dblk_ptr ) ); // chs:06-11-93
+
+ }
+ else {
+
+ // Set was new to catalogs, cataloging full details.
+
+ mwEnableClock = TRUE;
+ error = SUCCESS;
+
+ yresprintf( RES_NEWLY_CATALOGED_SET,
+ LocalSet,
+ FS_ViewSetNameInVCB( dblk_ptr ) );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ yresprintf( RES_CATALOGING_ITEMS );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ yresprintf( RES_DISPLAY_VOLUME,
+ FS_ViewVolNameInVCB( dblk_ptr ),
+ LocalSet,
+ LocalSeq,
+ FS_ViewSetNameInVCB( dblk_ptr ) ); // chs:06-11-93
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_DISPLAY_VOLUME,
+ FS_ViewVolNameInVCB( dblk_ptr ),
+ LocalSet,
+ LocalSeq,
+ FS_ViewSetNameInVCB( dblk_ptr ) ); // chs:06-11-93
+
+ }
+ }
+ break;
+
+ case MSG_EOM:
+
+ mwEOM = TRUE;
+
+ if ( gfIgnoreOTC || mwOTCFailure ) {
+
+ QTC_EndOfTape( mwQTC, NULL, NULL, NULL, fsh );
+ }
+ break;
+
+ case MSG_END_BACKUP_SET:
+
+ // Help the tape positioner above out by letting him know that
+ // processing of the tape has begun.
+
+
+ if ( ! mwAbortAtEOM ) {
+
+ QTC_FinishBackup( mwQTC );
+ }
+
+ ST_StartBackupSetIdle( &mwOpStats );
+
+ if ( gb_abort_flag != ABORT_PROCESSED ) {
+ if ( VLM_CheckForCatalogError( mwQTC ) != SUCCESS ) {
+ gb_abort_flag = ABORT_PROCESSED;
+ }
+ }
+
+ QTC_FreeBuildHandle( mwQTC );
+ ST_EndBackupSetIdle( &mwOpStats );
+ ST_EndBackupSet( &mwOpStats );
+
+ ClockRoutine(); // one last time
+ mwEnableClock = FALSE;
+
+ /* display and log any abort conditions */
+ UI_ConditionAtEnd( );
+ UI_Time( &mwOpStats, RES_CATALOG_COMPLETED, UI_END );
+ break;
+
+ case MSG_TBE_ERROR:
+ error = va_arg( arg_ptr, INT16 );
+
+ mwOperation = OPER_NONE;
+
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &mwOpStats );
+
+ UI_ProcessErrorCode( error, &response, tpos->channel );
+
+ // Keep going don't abort.
+ response = MSG_ACK;
+
+ /* restart the clock with an end idle */
+ ST_EndBackupSetIdle( &mwOpStats );
+
+ if ( error != TFLE_USER_ABORT ) {
+ // Mark the last file as bad if not user abort.
+ QTC_BlockBad( mwQTC );
+ }
+
+ // Abort the catalog, marking the set as incomplete.
+ QTC_AbortCataloging( mwQTC, TRUE );
+
+ // If TapeFormat hits EOS unexpectedly, then we'll return what
+ // UI_ProcessErrorCode() says. (Namely, abort operation.)
+ if( error != TFLE_UNEXPECTED_EOS && error != LP_USER_ABORT_ERROR &&
+ error != TFLE_UI_HAPPY_ABORT && error != TFLE_USER_ABORT ) {
+
+ return AUXILARY_ERROR;
+ }
+ break;
+
+ case MSG_STOP_CLOCK:
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &mwOpStats );
+ break;
+
+ case MSG_START_CLOCK:
+ /* restart the clock with an end idle */
+ ST_EndBackupSetIdle( &mwOpStats );
+ break;
+
+ case MSG_END_OPERATION:
+ UI_FreePathBuffer( &path );
+ UI_FreePathBuffer( &buffer );
+ break;
+
+ /* ignore these messages */
+ case MSG_IDLE:
+ case MSG_BLOCK_BAD:
+ case MSG_BYTES_BAD:
+ case MSG_BLOCK_DELETED:
+ case MSG_BYTES_DELETED:
+ case MSG_TAPE_STATS:
+ case MSG_BLK_NOT_FOUND:
+ case MSG_BLK_DIFFERENT:
+ case MSG_LOG_DIFFERENCE:
+ case MSG_START_OPERATION:
+ break;
+
+ default:
+ gb_error_during_operation = TRUE;
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &mwOpStats );
+ eresprintf( RES_UNKNOWN_MSG_HNDLR_MSG, msg );
+ /* restart the clock with an end idle */
+ ST_EndBackupSetIdle( &mwOpStats );
+ mwOperation = OPER_NONE;
+ break;
+ }
+
+ return( response );
+
+}
+
+
+/*******************
+
+ Name: PromptNextTape
+
+ Description: Function to collect user response when a new tape is
+ required from the Tape Format/Tape positioner.
+
+ Returns: UI_ABORT_POSITIONING or UI_NEW_TAPE_INSERTED
+
+**********************/
+INT16 PromptForTape(
+INT WhatToAsk,
+INT16 TapeNum,
+CHAR_PTR TapeName,
+CHAR_PTR DriveName )
+{
+ INT response;
+
+ mwDisplayRewind = TRUE;
+
+ CDS_SetYesFlag( CDS_GetCopy(), NO_FLAG );
+
+ switch ( WhatToAsk ) {
+
+ case ASK_NEXTTAPE:
+ yresprintf( RES_INSERT_NEXT_TAPE, TapeNum, DriveName );
+
+ response = WM_MessageBox( ID( IDS_MSGTITLE_INSERT ),
+ ID( RES_NEED_NEXT_TAPE ),
+ WMMB_OKCANCEL,
+ WMMB_ICONQUESTION,
+ gszTprintfBuffer,
+ IDRBM_LTAPE, 0 );
+ break;
+
+ case ASK_FORTAPE:
+ yresprintf( RES_TAPE_REQUEST, DriveName, TapeName,
+ TapeNum );
+
+ response = (INT)WM_MessageBox( ID( IDS_MSGTITLE_INSERT ),
+ gszTprintfBuffer,
+ WMMB_YESNO,
+ WMMB_ICONQUESTION,
+ ID( RES_CONTINUE_QUEST ),
+ 0, 0 );
+
+ break;
+ }
+
+ if ( response ) {
+#ifdef OS_WIN32
+ Sleep( (DWORD)3000 );
+ NtDemoChangeTape( (UINT16)mwTapeNum );
+#endif
+ response = UI_NEW_TAPE_INSERTED;
+ }
+ else {
+ response = UI_HAPPY_ABORT;
+ }
+
+ return( (INT16)response );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+VOID ClockRoutine( VOID )
+{
+ INT16 NumHours;
+ INT16 NumMinutes;
+ INT16 NumSeconds;
+ UINT64 NumBytes;
+ BOOLEAN stat;
+ CHAR Numeral[ 40 ];
+ static UINT64 TotalBytes;
+
+
+ if ( mwRuntime && mwEnableClock && ( ST_BSIdleLevel( &mwOpStats ) == 0 ) ) {
+
+
+ NumBytes = ST_GetBSBytesProcessed ( &mwOpStats );
+
+ if ( !U64_EQ( NumBytes, TotalBytes ) ) {
+ TotalBytes = NumBytes;
+ U64_Litoa( NumBytes, Numeral, (UINT16)10, &stat ) ;
+ UI_BuildNumeralWithCommas( Numeral );
+ yprintf(TEXT("%s\r"),Numeral );
+ JobStatusBackupRestore( JOB_STATUS_BYTES_PROCESSED );
+ }
+
+
+ WM_AnimateAppIcon( IDM_OPERATIONSCATALOG, FALSE );
+
+ ST_EndBackupSet( &mwOpStats );
+
+ NumHours = ST_GetBSElapsedHours( &mwOpStats );
+ NumMinutes = ST_GetBSElapsedMinutes( &mwOpStats );
+ NumSeconds = ST_GetBSElapsedSeconds( &mwOpStats );
+
+ if ( NumHours ) {
+ yprintf( TEXT("%d%c%2.2d%c%2.2d\r"),
+ NumHours, UI_GetTimeSeparator(),
+ NumMinutes, UI_GetTimeSeparator(), NumSeconds );
+ }
+ else {
+ yprintf( TEXT("%2.2d%c%2.2d\r"),
+ NumMinutes, UI_GetTimeSeparator(), NumSeconds );
+ }
+
+ JobStatusBackupRestore(JOB_STATUS_ELAPSED_TIME);
+
+
+ }
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT UI_GetCatalogCurrentStatus(
+STATS *Stats,
+CHAR *Path,
+INT PathSize )
+{
+
+
+ return( SUCCESS );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT CreateVCBFromQTC(
+UINT32 TapeFID,
+INT16 TapeSeq,
+INT16 SetNum,
+DBLK_PTR vcb,
+FSYS_HAND fsh )
+{
+ DATE_TIME backup_date;
+ QTC_BSET_PTR qtc;
+ QTC_HEADER_PTR header;
+ GEN_VCB_DATA gvcb_data;
+ STD_DBLK_DATA_PTR std_data = &gvcb_data.std_data;
+
+ qtc = QTC_FindBset( TapeFID, TapeSeq, SetNum );
+ if ( qtc == NULL ) {
+ return( FAILURE );
+ }
+
+ header = QTC_LoadHeader( qtc );
+ if ( header == NULL ) {
+ return( FAILURE );
+ }
+
+ /* Initialize the file systems interface structure */
+
+ FS_SetDefaultDBLK( fsh, BT_VCB, (CREATE_DBLK_PTR)&gvcb_data );
+
+ std_data->dblk = vcb;
+ std_data->tape_seq_num = (UINT16)header->tape_seq_num;
+
+ std_data->attrib = header->VCB_attributes;
+ std_data->continue_obj = (BOOLEAN)( header->status & QTC_CONTINUATION );
+
+ std_data->os_id = (UINT8)header->OS_id;
+ std_data->os_ver = (UINT8)header->OS_ver;
+
+ std_data->os_info = NULL;
+ std_data->os_info_size = 0;
+
+ std_data->lba = header->LBA;
+ std_data->disp_size = U64_Init( 0L, 0L );
+
+#if defined( UNICODE )
+ std_data->string_type = BEC_UNIC_STR;
+#else
+ std_data->string_type = BEC_ANSI_STR;
+#endif
+
+ gvcb_data.set_cat_tape_seq_num = (UINT16)header->FDD_SeqNum;
+ if ( ( gvcb_data.set_cat_pba = header->FDD_PBA ) == 0L ) {
+ gvcb_data.set_cat_info_valid = FALSE;
+ gvcb_data.on_tape_cat_ver = (UINT8)header->FDD_Version;
+ gvcb_data.on_tape_cat_level = TCL_PARTIAL;
+ } else {
+ gvcb_data.set_cat_info_valid = TRUE;
+ gvcb_data.on_tape_cat_ver = (UINT8)header->FDD_Version;
+ gvcb_data.on_tape_cat_level = TCL_FULL;
+ }
+
+ gvcb_data.tape_id = TapeFID;
+ gvcb_data.tape_seq_num = TapeSeq;
+ gvcb_data.bset_num = SetNum;
+
+ gvcb_data.password_encrypt_alg = (UINT16)header->encrypt_algor;
+
+ gvcb_data.tape_name = header->tape_name;
+ gvcb_data.tape_name_size = (UINT16)header->tape_name_size;
+ gvcb_data.tape_password = header->tape_password;
+ gvcb_data.tape_password_size = (UINT16)header->tape_password_size;
+
+ gvcb_data.bset_name = header->bset_name;
+ gvcb_data.bset_name_size = (UINT16)header->bset_name_size;
+
+ gvcb_data.bset_password = header->bset_password;
+ gvcb_data.bset_password_size = (UINT16)header->bset_password_size;
+
+ gvcb_data.bset_descript = header->bset_description;
+ gvcb_data.bset_descript_size = (UINT16)header->bset_description_size;
+
+ gvcb_data.user_name = header->user_name;
+ gvcb_data.user_name_size = (UINT16)header->user_name_size;
+
+ gvcb_data.volume_name = header->volume_name;
+ gvcb_data.volume_name_size = (UINT16)header->volume_name_size;
+
+ DateTimeDOS( (INT16)header->backup_date,
+ (INT16)header->backup_time,
+ &backup_date );
+
+ gvcb_data.date = &backup_date;
+
+ gvcb_data.pba = header->PBA_VCB;
+
+ /* Tell the file system to do its thing. It returns a data filter
+ which we have no use for.
+ */
+ (void) FS_CreateGenVCB( fsh, &gvcb_data );
+
+ free( header );
+
+ return( SUCCESS );
+}
+
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT16 GetLowestTapeWithSet(
+UINT32 TapeFID,
+INT16 TapeSeq,
+INT16 SetNum )
+{
+ INT16 LowTape;
+ QTC_TAPE_PTR tape;
+ QTC_BSET_PTR bset;
+
+ LowTape = TapeSeq;
+
+ tape = QTC_GetFirstTape();
+
+ while ( tape != NULL ) {
+
+ if ( tape->tape_fid == TapeFID ) {
+
+ bset = QTC_GetFirstBset( tape );
+
+ while ( bset != NULL ) {
+
+ if ( bset->bset_num == SetNum ) {
+ if ( ( tape->tape_seq_num < LowTape ) || ( LowTape == (INT16)-1 ) ) {
+ LowTape = (INT16)tape->tape_seq_num;
+ }
+ }
+ bset = QTC_GetNextBset( bset );
+ }
+ }
+ tape = QTC_GetNextTape( tape );
+ }
+
+ return( LowTape );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT16 GetLowestSetOnTape(
+UINT32 TapeFID,
+INT16 TapeSeq )
+{
+ INT16 LowSet = -1;
+ QTC_TAPE_PTR tape;
+ QTC_BSET_PTR bset;
+
+ tape = QTC_GetFirstTape();
+ while ( tape != NULL ) {
+
+ if ( tape->tape_fid == TapeFID && tape->tape_seq_num == TapeSeq ) {
+
+ bset = QTC_GetFirstBset( tape );
+
+ while ( bset != NULL ) {
+
+ if ( bset->bset_num < LowSet || LowSet == -1 ) {
+ LowSet = (INT16)bset->bset_num;
+ }
+ bset = QTC_GetNextBset( bset );
+ }
+ }
+ tape = QTC_GetNextTape( tape );
+ }
+
+ return( LowSet );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT GetBestOTCFlags(
+UINT32 TapeFID,
+INT16 TapeNum,
+INT16 SetNum,
+UINT32 *flags )
+{
+ QTC_BSET_PTR bset;
+ QTC_TAPE_PTR tape;
+ INT ret_val = FAILURE;
+
+ *flags = 0;
+
+ if ( gfIgnoreOTC || mwOTCFailure ) {
+ return( ret_val );
+ }
+
+ tape = QTC_GetFirstTape( );
+
+ while ( tape != NULL ) {
+
+ if ( tape->tape_fid == TapeFID ) {
+
+ bset = QTC_GetFirstBset( tape );
+
+ while ( bset != NULL ) {
+
+ if ( bset->status & QTC_SMEXISTS ) {
+ *flags |= QTC_SMEXISTS;
+ }
+ if ( bset->status & QTC_FDDEXISTS ) {
+ *flags |= QTC_FDDEXISTS;
+ }
+ if ( bset->status & QTC_OTCVALID ) {
+ *flags |= QTC_OTCVALID;
+ }
+
+ ret_val = SUCCESS;
+
+ bset = QTC_GetNextBset( bset );
+ }
+
+ }
+ tape = QTC_GetNextTape( tape );
+ }
+
+ return( ret_val );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT GetBestFDDInfo(
+UINT32 TapeFID,
+INT16 TapeNum,
+INT16 SetNum,
+INT16 *FDDSeqNum,
+UINT32 *FDDPBA,
+UINT8 *FDDVersion )
+{
+ QTC_HEADER_PTR header;
+ QTC_BSET_PTR bset;
+ QTC_TAPE_PTR tape;
+ INT ret_val = FAILURE;
+
+
+ if ( gfIgnoreOTC || mwOTCFailure ) {
+ return( ret_val );
+ }
+
+ tape = QTC_GetFirstTape( );
+
+ while ( tape != NULL && ret_val == FAILURE ) {
+
+ if ( tape->tape_fid == TapeFID ) {
+
+ bset = QTC_GetFirstBset( tape );
+
+ while ( bset != NULL ) {
+
+ if ( bset->bset_num == SetNum ) {
+
+ if ( (bset->status & QTC_OTCVALID) && (bset->status & QTC_FDDEXISTS) ) {
+
+ header = QTC_LoadHeader( bset );
+
+ if ( header != NULL ) {
+
+ *FDDSeqNum = (UINT8)header->FDD_SeqNum;
+ *FDDPBA = header->FDD_PBA;
+ *FDDVersion = (UINT8)header->FDD_Version;
+
+ // Handle old catalogs which weren't set.
+
+ if ( *FDDVersion == (UINT8)0 ) {
+ *FDDVersion = (UINT8)1;
+ }
+ ret_val = SUCCESS;
+ free( header );
+ }
+ }
+ }
+
+ bset = QTC_GetNextBset( bset );
+ }
+ }
+ tape = QTC_GetNextTape( tape );
+ }
+
+ return( ret_val );
+}
+
+/**********************
+
+ NAME : CatalogPasswordCheck
+
+ DESCRIPTION : Check to see ifcurrent users has rights to catalog a tape.
+
+ RETURNS : TRUE - allowed access to catalog a tape
+ FALSE - not allowed access to catalog a tape
+
+**********************/
+
+BOOLEAN CatalogPasswordCheck ( DBLK_PTR vcb_ptr )
+{
+ CHAR_PTR currentloggedonuserpassword;
+ CHAR_PTR temppasswd; // hold the tape password from the VCB
+ // passwd on the tape.
+ INT16 tempsize; // length of password from tape.
+ CHAR_PTR buffer = NULL;
+ CHAR_PTR alteredtemppassword = NULL;
+ CHAR_PTR temppasswdbuffer = NULL;
+ INT16 currentpswdlength;
+ BOOLEAN retcode;
+
+
+ // If user has administrative access
+
+ if ( DoesUserHaveThisPrivilege( TEXT( "SeRestorePrivilege" ) ) ) {
+ return( TRUE );
+ }
+
+ //
+ // Get a current user-id-password
+ //
+
+ currentloggedonuserpassword = GetCurrentMachineNameUserName ();
+ if ( !currentloggedonuserpassword ) {
+ return( FALSE );
+ }
+
+ currentpswdlength = strlen( currentloggedonuserpassword );
+ alteredtemppassword = ( CHAR_PTR )calloc( 1, sizeof( CHAR ) * currentpswdlength + 2 * sizeof( CHAR ) );
+ if ( !alteredtemppassword ) return( FALSE );
+ *alteredtemppassword = NTPASSWORDPREFIX; // chs:04-08-93
+ strcat( alteredtemppassword, currentloggedonuserpassword );
+ currentpswdlength = strlen( alteredtemppassword ) * sizeof( CHAR );
+
+ //
+ // Verify if user tape password matches.
+ // Check the tape password from the current VCB
+ //
+
+ temppasswd = (CHAR_PTR)FS_ViewTapePasswordInVCB( vcb_ptr );
+ tempsize = FS_SizeofTapePswdInVCB( vcb_ptr );
+
+ //
+ // tempsize = 0 means no password on tape
+ //
+
+ if ( tempsize == 0 ) {
+ return( TRUE );
+ }
+
+ buffer = ( CHAR_PTR )calloc( 1, tempsize * sizeof( CHAR ) );
+ if ( !buffer ) {
+ free( alteredtemppassword );
+ return( FALSE );
+ }
+
+#ifdef UNICODE
+ if ( FS_ViewStringTypeinDBLK( vcb_ptr ) == BEC_ANSI_STR ) {
+
+ temppasswdbuffer = ( CHAR_PTR )calloc(1, sizeof( CHAR ) + tempsize );
+ if ( !temppasswdbuffer ) {
+ free( buffer );
+ free( alteredtemppassword );
+ return( FALSE );
+ }
+ memcpy( temppasswdbuffer, temppasswd, tempsize );
+ CryptPassword( ( INT16 ) DECRYPT, ENC_ALGOR_3, (INT8_PTR)temppasswdbuffer, tempsize );
+ tempsize *= sizeof( CHAR );
+ mapAnsiToUnicNoNull( ( ACHAR_PTR )temppasswdbuffer, ( WCHAR_PTR )buffer, ( INT )(tempsize / sizeof( CHAR ) ), ( INT * )&tempsize ) ;
+ if ( ( *temppasswdbuffer & 0xff ) == NTPASSWORDPREFIX ) {
+ *buffer = NTPASSWORDPREFIX;
+ }
+ free( temppasswdbuffer );
+
+ } else {
+ memcpy( buffer, temppasswd, tempsize );
+ CryptPassword( ( INT16 ) DECRYPT, ENC_ALGOR_3, (INT8_PTR)buffer, tempsize );
+ }
+#else
+ memcpy( buffer, temppasswd, tempsize );
+ CryptPassword( ( INT16 ) DECRYPT, ENC_ALGOR_3, (INT8_PTR)buffer, tempsize );
+#endif
+
+ if ( currentpswdlength == tempsize ) {
+
+ if ( !memcmp( buffer, alteredtemppassword, tempsize ) ) {
+
+ retcode = TRUE; // password match
+
+ } else {
+
+ retcode = FALSE; // password does not match
+ }
+
+ } else {
+
+ retcode = FALSE; // password lengths do not match
+ }
+
+ if ( alteredtemppassword ) free ( alteredtemppassword );
+ if ( buffer ) free( buffer );
+
+ return( retcode );
+}
+
diff --git a/private/utils/ntbackup/src/do_del.c b/private/utils/ntbackup/src/do_del.c
new file mode 100644
index 000000000..c1b236aeb
--- /dev/null
+++ b/private/utils/ntbackup/src/do_del.c
@@ -0,0 +1,638 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: do_del.c
+
+ Description:
+
+ $Log: G:\ui\logfiles\do_del.c_v $
+
+ Rev 1.33 26 Jul 1993 14:55:04 CARLS
+added code for MSG_NOT_DELETED
+
+ Rev 1.32 01 Jun 1993 16:30:32 chrish
+CAYMAN EPR 0385: Corrected delete phase of transfer process which had
+stated "Deleted 1 file in 2 directory".
+
+ Rev 1.31 18 Feb 1993 11:19:50 BURT
+For Cayman, fixed apparant bug that should also cause
+some problems under Windows. path[0] was being set to 0, but
+path pointed to NULL so kaboom under NT.
+
+
+ Rev 1.30 05 Nov 1992 17:01:58 DAVEV
+fix ts
+
+ Rev 1.28 07 Oct 1992 14:48:58 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.27 04 Oct 1992 19:34:02 DAVEV
+Unicode Awk pass
+
+ Rev 1.26 10 Sep 1992 17:44:42 DAVEV
+Integrate MikeP's changes from Microsoft
+
+ Rev 1.25 28 Jul 1992 14:52:52 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.24 27 Jul 1992 14:49:38 JOHNWT
+ChuckB fixed references for NT.
+
+ Rev 1.23 27 Jul 1992 11:08:18 JOHNWT
+ChuckB checked in for John Wright, who is no longer with us.
+
+ Rev 1.22 07 Jul 1992 15:31:18 MIKEP
+unicode changes
+
+ Rev 1.21 28 May 1992 15:20:18 MIKEP
+proto changes
+
+ Rev 1.20 19 May 1992 11:58:52 MIKEP
+mips changes
+
+ Rev 1.19 14 May 1992 17:39:36 MIKEP
+nt pass 2
+
+ Rev 1.18 11 May 1992 19:31:18 STEVEN
+64bit and large path sizes
+
+
+*****************************************************************************/
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+static INT16 msg_hndlr( UINT16 msg, INT32 pid, BSD_PTR bsd_ptr, FSYS_HAND fsh, TPOS_PTR tpos, ... );
+static VOID clock_routine( VOID );
+static VOID do_delete_init( VOID );
+static VOID do_delete_process( VOID );
+
+static BOOLEAN clock_ready_flag;
+static HTIMER timer_handle;
+static STATS op_stats;
+static INT mw_oper_type;
+static INT16 mw_ret_val;
+
+/*****************************************************************************
+
+ Name: do_delete
+
+ Description: Kicks off the delete function. It first prompts the user
+ to make sure they wish to delete the data and then
+ displays the RTD.
+
+ Returns: SUCCESS or error from delete engine.
+
+ Notes: mw_ret_val is set in do_delete_process().
+
+*****************************************************************************/
+
+INT do_delete(
+ INT16 oper_type )
+{
+
+ mw_oper_type = oper_type;
+ mw_ret_val = SUCCESS;
+
+ if ( WM_MessageBox( ID( IDS_MSGTITLE_ERASE ),
+ ID( RES_DELETE_QUEST ),
+ WMMB_YESNO | WMMB_BUT2DEFAULT,
+ WMMB_ICONQUESTION, NULL, 0, 0 ) ) {
+
+ /* set up call back functions, runtime dialog is app modal */
+
+ do_delete_init();
+ do_delete_process();
+
+ }
+
+ return( mw_ret_val );
+
+}
+
+
+/*****************************************************************************
+
+ Name: do_delete_init
+
+ Description: Initialize the text on the RTD.
+
+ Returns: none.
+
+*****************************************************************************/
+
+VOID do_delete_init( VOID )
+{
+ JobStatusBackupRestore( JOB_STATUS_CREATE_DIALOG );
+
+ yresprintf( (INT16) IDS_DLGTITLEJOBSTATDELETE );
+ JobStatusBackupRestore( JOB_STATUS_BACKUP_TITLE );
+
+ yresprintf( (INT16) RES_TITLE_NEW_LINE );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ yresprintf( (INT16) IDS_DLGTITLEJOBSTATDELETE );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ yresprintf( (INT16) RES_TITLE_NEW_LINE );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ yprintf(TEXT("%d\r"),0 );
+ JobStatusBackupRestore( JOB_STATUS_BYTES_PROCESSED );
+
+ return;
+}
+
+
+/*****************************************************************************
+
+ Name: do_delete_process
+
+ Description: Initialize the lis structure, etc and call the delete
+ engine to perform the operation.
+
+ Returns: none.
+
+ Notes: sets mw_ret_val to return from delete engine.
+
+*****************************************************************************/
+
+VOID do_delete_process( VOID )
+{
+ LIS lis;
+
+ lis.bsd_list = bsd_list;
+ lis.curr_bsd_ptr = BSD_GetFirst( bsd_list );
+ lis.tape_pos_handler = NULL;
+ lis.message_handler = msg_hndlr;
+ lis.oper_type = (INT16)mw_oper_type; /* set operation type */
+ lis.abort_flag_ptr = &gb_abort_flag; /* set abort flag address */
+ lis.auto_det_sdrv = TRUE; /* really a don't care value */
+
+ LP_SetAbortFlag( &lis, CONTINUE_PROCESSING );
+
+ /* set the Runtime abort flag pointer */
+ JobStatusAbort( lis.abort_flag_ptr );
+
+ /* enable the abort button for the runtime dialog */
+ JobStatusBackupRestore( JOB_STATUS_ABORT_ENABLE );
+
+ BSD_SaveLastOper( bsd_list );
+ BSD_ProcLastOper( bsd_list );
+
+ clock_ready_flag = FALSE; // Wait on bset to start
+
+ timer_handle = WM_HookTimer( clock_routine, 1 );
+
+ PD_StopPolling();
+
+ /* clear the statistics before the operation starts */
+ ST_StartOperation( &op_stats );
+
+ mw_ret_val = LP_Delete_Engine( &lis );
+
+ PD_StartPolling();
+
+ WM_UnhookTimer( timer_handle );
+
+ JobStatusBackupRestore( JOB_STATUS_ABORT_OFF );
+
+ return;
+}
+
+
+
+/*****************************************************************************
+
+ Name: clock_routine
+
+ Description: one second timer to update the Runtime status
+ elapsed time
+
+ Returns: void
+
+*****************************************************************************/
+
+static VOID clock_routine( VOID )
+{
+ INT16 num_min, num_seconds;
+
+ if ( clock_ready_flag ) {
+
+ ST_EndBackupSet( &op_stats );
+
+ num_min = ST_GetBSElapsedMinutes( &op_stats );
+ num_seconds = ST_GetBSElapsedSeconds( &op_stats );
+
+ yprintf( TEXT("%2.2d%c%2.2d\r"), num_min, UI_GetTimeSeparator(), num_seconds );
+
+ JobStatusBackupRestore( JOB_STATUS_ELAPSED_TIME );
+ }
+}
+
+/*****************************************************************************
+
+ Name: msg_hndlr
+
+ Description: Delete message handler called by the loops
+
+ Returns:
+
+*****************************************************************************/
+
+INT16 msg_hndlr(
+UINT16 msg,
+INT32 pid,
+BSD_PTR bsd_ptr,
+FSYS_HAND fsh,
+TPOS_PTR tpos, ... )
+{
+ static CHAR delimiter = TEXT('#'); /* = # for debug */
+ INT16 response = MSG_ACK;
+ va_list arg_ptr;
+ UINT64 num_bytes;
+ BOOLEAN stat;
+ CHAR numeral[ UI_MAX_NUMERAL_LENGTH + 1 ];
+ CDS_PTR cds_ptr;
+
+ static CHAR_PTR path_buf = NULL;
+ static CHAR_PTR path = NULL;
+ static INT path_length;
+ static INT root_counted;
+
+ /* for future use */
+ pid;
+
+ cds_ptr = CDS_GetCopy();
+
+ /* set up first argument */
+ va_start( arg_ptr, tpos );
+
+ JobStatusBackupRestore( JOB_STATUS_ABORT_CHECK );
+
+ switch( msg ) {
+
+ /* logging messages */
+ case MSG_LOG_BLOCK:
+ {
+ DBLK_PTR dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+
+ switch( FS_GetBlockType( dblk_ptr ) ) {
+
+ case BT_VCB:
+ break;
+
+ case BT_DDB:
+ UI_BuildDelimitedPathFromDDB( &path_buf, fsh, dblk_ptr, delimiter, FALSE );
+
+ yprintf( TEXT("%s"), path_buf );
+ JobStatusBackupRestore( JOB_STATUS_DIRECTORY_NAMES );
+
+ lresprintf( LOGGING_FILE, LOG_DIRECTORY, SES_ENG_MSG, RES_DIRECTORY, path_buf );
+ break;
+
+ case BT_FDB:
+ if( CDS_GetFilesFlag( cds_ptr ) ) {
+ UI_AllocPathBuffer( &path_buf, FS_SizeofFnameInFDB( fsh, dblk_ptr ) );
+ if ( path_buf != NULL ) {
+ FS_GetFnameFromFDB( fsh, dblk_ptr, path_buf );
+ }
+ UI_DisplayFile( path_buf );
+ JobStatusBackupRestore( JOB_STATUS_FILE_NAMES );
+
+ }
+ lresprintf( LOGGING_FILE, LOG_FILE, fsh, dblk_ptr );
+ break;
+ }
+ }
+ break;
+
+ /* statistics messages */
+ case MSG_BLOCK_PROCESSED:
+ {
+ DBLK_PTR dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+ OBJECT_TYPE object_type;
+ INT item_size;
+ INT i;
+
+ switch( FS_GetBlockType( dblk_ptr ) ) {
+
+ case BT_DDB:
+
+ // Count all the new directories that showed up in
+ // this DDB.
+
+ // Only count the root once.
+
+ if ( ! root_counted ) {
+ ST_AddBSDirsProcessed( &op_stats, 1 );
+ root_counted = TRUE;
+ }
+
+ // Get the new path from the DDB.
+
+ item_size = FS_SizeofOSPathInDDB( fsh, dblk_ptr );
+ if ( UI_AllocPathBuffer( &path_buf, (UINT16) item_size ) != NULL ) {
+ FS_GetOSPathFromDDB( fsh, dblk_ptr, path_buf );
+ }
+
+ if ( item_size != 1 ) {
+
+ i = 0;
+ while ( i < item_size ) {
+
+ if ( i >= path_length ) {
+
+ ST_AddBSDirsProcessed( &op_stats, 1 );
+ }
+ else {
+
+ if ( (path == NULL) ||
+ stricmp( &path_buf[ i ], &path[ i ] ) ) {
+
+ ST_AddBSDirsProcessed( &op_stats, 1 );
+ path_length = 0;
+ }
+ }
+ while ( path_buf[ i++ ] );
+ }
+ }
+
+ // Set up for next time.
+ UI_AllocPathBuffer( &path, (UINT16) item_size );
+
+ if ( path != NULL ) {
+ memcpy( path, path_buf, item_size );
+ }
+ path_length = item_size;
+
+ yprintf(TEXT("%ld\r"),ST_GetBSDirsProcessed( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_DIRECTORIES_PROCESS );
+ break;
+
+ case BT_FDB:
+ ST_AddBSFilesProcessed( &op_stats, 1 );
+ yprintf(TEXT("%ld\r"),ST_GetBSFilesProcessed( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_FILES_PROCESSED );
+ FS_GetObjTypeDBLK( fsh, dblk_ptr, &object_type );
+ if( object_type == AFP_OBJECT ) {
+ ST_AddBSAFPFilesProcessed( &op_stats, 1 );
+ }
+ break;
+ }
+ }
+ break;
+
+ case MSG_BYTES_PROCESSED:
+ {
+ INT32 count_lsw = va_arg( arg_ptr, INT32 );
+ INT32 count_msw = va_arg( arg_ptr, INT32 );
+
+ ST_AddBSBytesProcessed( &op_stats, U64_Init( count_lsw, count_msw ) );
+ num_bytes = ST_GetBSBytesProcessed ( &op_stats );
+ U64_Litoa( num_bytes, numeral, (UINT16)10 , &stat );
+ UI_BuildNumeralWithCommas( numeral );
+ yprintf(TEXT("%s\r"),numeral );
+ JobStatusBackupRestore( JOB_STATUS_BYTES_PROCESSED );
+
+ }
+ break;
+
+ case MSG_TBE_ERROR:
+ {
+ INT16 error = va_arg( arg_ptr, INT16 );
+ GENERIC_DLE_PTR dle_ptr;
+
+ dle_ptr = BSD_GetDLE( bsd_ptr );
+
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &op_stats );
+
+ UI_ProcessErrorCode( error, &response, tpos->channel );
+
+ /* restart the clock with an end idle */
+ ST_EndBackupSetIdle( &op_stats );
+ }
+ break;
+
+ /* general messages */
+ case MSG_START_OPERATION:
+
+ lresprintf( LOGGING_FILE, LOG_START, FALSE );
+
+ /* display operation title in log file */
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, IDS_DLGTITLEJOBSTATDELETE );
+
+ break;
+
+ case MSG_END_OPERATION:
+
+ UI_FreePathBuffer( &path_buf );
+ UI_FreePathBuffer( &path );
+
+ lresprintf( LOGGING_FILE, LOG_END );
+ UI_ChkDispGlobalError( );
+ break;
+
+ case MSG_START_BACKUP_SET:
+ {
+ DBLK_PTR vcb_ptr = va_arg( arg_ptr, DBLK_PTR );
+
+ path_length = 0;
+ // path[0] = 0; // path was never init'd, doesn't seem to be used.
+ root_counted = FALSE;
+
+ /* display local or net drive bitmap */
+ if ( DLE_HasFeatures( BSD_GetDLE( bsd_ptr ), DLE_FEAT_REMOTE_DRIVE ) ) {
+ JobStatusBackupRestore( JOB_STATUS_VOLUME_NETDRIVE );
+ }
+ else {
+ JobStatusBackupRestore( JOB_STATUS_VOLUME_HARDDRIVE );
+ }
+
+ /* volume name of disk drive */
+ if ( UI_AllocPathBuffer( &path_buf, UI_MAX_PATH_LENGTH ) != NULL ) {
+ DLE_GetVolName( BSD_GetDLE( bsd_ptr ), path_buf );
+ yprintf(TEXT("%s\r"),path_buf );
+ JobStatusBackupRestore( JOB_STATUS_SOURCE_NAME );
+
+ /* clear the destination name */
+ yprintf(TEXT(" \r"));
+ JobStatusBackupRestore( JOB_STATUS_DEST_NAME );
+
+ BSD_SetOperStatus( bsd_ptr, SUCCESS );
+
+ yresprintf( (INT16) RES_DISPLAY_VOLUME,
+ path_buf,
+ BSD_GetSetNum( bsd_ptr ),
+ BSD_GetTapeNum( bsd_ptr ),
+ BSD_GetBackupLabel( bsd_ptr ) );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_DISPLAY_VOLUME,
+ path_buf,
+ BSD_GetSetNum( bsd_ptr ),
+ BSD_GetTapeNum( bsd_ptr ),
+ BSD_GetBackupLabel( bsd_ptr ) );
+
+ }
+
+ ST_StartBackupSet( &op_stats );
+
+ UI_Time( &op_stats, RES_DELETE_STARTED, UI_START );
+
+ /* enable the real time clock */
+ clock_ready_flag = TRUE;
+
+ delimiter = DLE_GetPathDelim( BSD_GetDLE( bsd_ptr ) );
+ }
+ break;
+
+ case MSG_END_BACKUP_SET:
+ {
+ INT16 res_id;
+
+ /* turn off the real time clock */
+ clock_ready_flag = FALSE;
+
+ /* record the time that we finished */
+ ST_EndBackupSet( &op_stats );
+
+
+ /* clear last displayed filename from status display */
+ UI_ClearLastDisplayedFile( );
+
+ /* display and log any abort conditions */
+ UI_ConditionAtEnd( );
+
+ /* disable the real time clock */
+ clock_ready_flag = FALSE;
+
+ UI_Time( &op_stats, RES_DELETE_COMPLETED, UI_END );
+
+ /* display number of files / number of dirs */
+ if( ST_GetBSFilesProcessed( &op_stats ) <= 1 && ST_GetBSDirsProcessed( &op_stats ) <= 1 ) { // chs:05-26-93
+ res_id = RES_DELETE_DIR_FILE; // chs:05-26-93
+ } else if( ST_GetBSFilesProcessed( &op_stats ) <= 1 && ST_GetBSDirsProcessed( &op_stats ) > 1 ) { // chs:05-26-93
+ res_id = RES_DELETE_DIRS_FILE; // chs:05-26-93
+ } else if( ST_GetBSFilesProcessed( &op_stats ) > 1 && ST_GetBSDirsProcessed( &op_stats ) <= 1 ) { // chs:05-26-93
+ res_id = RES_DELETE_DIR_FILES; // chs:05-26-93
+ } else { // chs:05-26-93
+ res_id = RES_DELETE_DIRS_FILES; // chs:05-26-93
+ } // chs:05-26-93
+
+// chs:05-26-93 if( ST_GetBSFilesProcessed( &op_stats ) == 1 ) {
+// chs:05-26-93 res_id = RES_DELETE_DIR_FILE;
+// chs:05-26-93 } else if ( ST_GetBSDirsProcessed( &op_stats ) == 1 ) {
+// chs:05-26-93 res_id = RES_DELETE_DIR_FILES;
+// chs:05-26-93 } else {
+// chs:05-26-93 res_id = RES_DELETE_DIRS_FILES;
+// chs:05-26-93 }
+
+ yresprintf( res_id,
+ ST_GetBSFilesProcessed( &op_stats ),
+ ST_GetBSDirsProcessed( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, res_id,
+ ST_GetBSFilesProcessed( &op_stats ),
+ ST_GetBSDirsProcessed( &op_stats ) );
+
+ /* display number of mac files deleted */
+ if( ST_GetBSAFPFilesProcessed( &op_stats ) > 0 ) {
+
+ if( ST_GetBSAFPFilesProcessed( &op_stats ) == 1 ) {
+ res_id = RES_DELETE_MAC;
+ }
+ else {
+ res_id = RES_DELETE_MACS;
+ }
+
+ yresprintf( res_id,
+ ST_GetBSAFPFilesProcessed( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, res_id,
+ ST_GetBSAFPFilesProcessed( &op_stats ) );
+ }
+
+ delimiter = TEXT('#'); /* = # for debug */
+ }
+ break;
+
+ case MSG_NOT_DELETED:
+ {
+ DBLK_PTR dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+
+ switch( FS_GetBlockType( dblk_ptr ) ) {
+
+ case BT_VCB:
+ break;
+
+ case BT_DDB:
+ UI_BuildDelimitedPathFromDDB( &path_buf, fsh, dblk_ptr, delimiter, FALSE );
+ yprintf( TEXT("%s"), path_buf );
+ yresprintf( (INT16) RES_DIRECTORY_NOT_DELETED, path_buf );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_WARNING, SES_ENG_MSG, RES_DIRECTORY_NOT_DELETED, path_buf );
+ gb_error_during_operation = TRUE;
+ break;
+
+ case BT_FDB:
+ if( CDS_GetFilesFlag( cds_ptr ) ) {
+ UI_AllocPathBuffer( &path_buf, FS_SizeofFnameInFDB( fsh, dblk_ptr ) );
+ if ( path_buf != NULL ) {
+ FS_GetFnameFromFDB( fsh, dblk_ptr, path_buf );
+ yresprintf( (INT16) RES_FILE_NOT_DELETED, path_buf );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_WARNING, SES_ENG_MSG, RES_FILE_NOT_DELETED, path_buf );
+ gb_error_during_operation = TRUE;
+ }
+
+ }
+ break;
+ }
+ }
+ break;
+
+
+ /* ignore these messages */
+ case MSG_COMM_FAILURE:
+ case MSG_IDLE:
+ case MSG_PROMPT:
+ case MSG_EOM:
+ case MSG_BLOCK_DELETED:
+ case MSG_BYTES_DELETED:
+ case MSG_TAPE_STATS:
+ case MSG_STOP_CLOCK:
+ case MSG_START_CLOCK:
+ case MSG_BLK_NOT_FOUND:
+ case MSG_BLK_DIFFERENT:
+ case MSG_LOG_DIFFERENCE:
+ case MSG_BLOCK_BAD:
+ case MSG_BYTES_BAD:
+ case MSG_IN_USE:
+ case MSG_IN_USE_WAIT:
+ case MSG_BLOCK_SKIPPED:
+ case MSG_BYTES_SKIPPED:
+ break;
+
+ default:
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &op_stats );
+
+ eresprintf( RES_UNKNOWN_MSG_HNDLR_MSG, msg );
+
+ /* restart the clock with an end idle */
+ ST_EndBackupSetIdle( &op_stats );
+
+ break;
+ }
+
+ return( response );
+
+}
diff --git a/private/utils/ntbackup/src/do_excl.c b/private/utils/ntbackup/src/do_excl.c
new file mode 100644
index 000000000..3a5315cb8
--- /dev/null
+++ b/private/utils/ntbackup/src/do_excl.c
@@ -0,0 +1,829 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: do_excl.c
+
+ Description: This function contains the code which creates
+ the excludes for the inteneral files ;
+
+ $Log: G:\ui\logfiles\do_excl.c_v $
+
+ Rev 1.44.1.3 28 Mar 1994 14:23:18 STEVEN
+exclude eadata.sf
+
+ Rev 1.44.1.2 16 Mar 1994 18:07:14 STEVEN
+we were not excluding evt files for restore
+
+ Rev 1.44.1.1 24 Feb 1994 22:04:34 STEVEN
+exclude the catalog files
+
+ Rev 1.44.1.0 25 Oct 1993 15:46:12 GREGG
+Added new excludes for temporary OTC files.
+
+ Rev 1.44 21 Jul 1993 17:10:36 CARLS
+change to tbrparse call
+
+ Rev 1.43 30 Jun 1993 15:30:52 CARLS
+changed the name of the restore & backup exclude files
+
+ Rev 1.42 14 Jun 1993 20:26:18 MIKEP
+enable c++
+
+ Rev 1.41 28 May 1993 15:16:30 CARLS
+added backup.nks support
+
+ Rev 1.40 14 May 1993 14:30:02 MIKEP
+Fix compiler warning.
+
+ Rev 1.39 10 May 1993 08:35:32 MIKEP
+Fix exclude of logfiles for non-command line specified log files.
+
+ Rev 1.38 29 Apr 1993 18:12:08 MIKEP
+improve catalog exclude code
+
+ Rev 1.37 02 Apr 1993 15:41:04 TIMN
+Added code to exclude event files (*.EVT) from VERIFY operations only
+Added code to exclude log files only if logging is enabled
+
+ Rev 1.36 31 Mar 1993 18:15:58 TIMN
+Fixed bug, only exclude log file if log's BSD is selected
+
+ Rev 1.35 29 Mar 1993 11:27:12 TIMN
+Exclude user specified backup/restore log from operation EPR(0335)
+
+ Rev 1.34 18 Mar 1993 11:52:36 TIMN
+Excluded restore.log from backup/restore EPR(0327)
+
+
+*****************************************************************************/
+
+#include "all.h"
+
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+static VOID CreateExclude( CHAR_PTR path, CHAR_PTR file,
+ GENERIC_DLE_PTR drive, BOOLEAN wild_flag,
+ FSE_PTR *fse ) ;
+
+static VOID unimpregnatePath( CHAR_PTR pPath, INT16 nPathSize, CHAR cDelimiter ) ;
+
+/*****************************************************************************
+
+ Name: UI_ExcludeInternalFiles( )
+
+ Description: This function goes though the BSD list and adds
+ Exclude FSEs for internal Maynstream files.
+
+ Returns: NONE
+
+ Notes: The excluded files are :
+
+*****************************************************************************/
+
+static TCHAR szPlaceHolder1[] = TEXT("Placehol.der");
+static TCHAR szPlaceHolder2[] = TEXT("Placehol.der");
+
+INT16 UI_ExcludeInternalFiles( INT16 oper )
+{
+ BSD_HAND temp_bsd_list ;
+ INT16 ret_val = SUCCESS ;
+ CHAR_PTR data_path = NULL;
+ CHAR_PTR fname ; // fname from FS_ParsePath call
+ CHAR path[ UI_MAX_PATH_LENGTH ] ;
+ INT16 psize ;
+ BOOLEAN dummy = FALSE;
+ GENERIC_DLE_PTR dle = NULL;
+ BSD_PTR bsd = NULL;
+ FSE_PTR fse = NULL;
+ VLM_FIND_PTR pVlmFind = NULL;
+ CHAR szFile [VLM_MAXFNAME];
+ INT i ;
+ CHAR_PTR *exclude_list ;
+ BOOLEAN warning_printed = FALSE ;
+ CDS_PTR cfg = CDS_GetPerm();
+
+#ifdef OS_WIN32
+ INT bytes;
+ CHAR nt_drive[ 4 ];
+ CHAR nt_windows[ 256 ];
+#endif
+
+ static CHAR_PTR back_exclude_list[ ] = {
+ TEXT("SKIPPED.BKS"),
+ TEXT("VERIFY.BKS"),
+ TEXT("") } ;
+
+ static CHAR_PTR arch_exclude_list[ ] = {
+ TEXT("SKIPPED.BKS"),
+ TEXT("VERIFY.BKS"),
+ TEXT("") } ;
+
+ static CHAR_PTR ver_exclude_list[ ] = {
+ szPlaceHolder1, //will be replaced with job file
+ TEXT("") } ;
+
+ static CHAR_PTR ver_last_exclude_list[ ] = {
+ szPlaceHolder2, //will be replaced with schedule file
+ TEXT("") } ;
+
+ static CHAR_PTR empty_exclude_list[ ] = {
+ TEXT("") } ;
+
+
+#ifdef OS_WIN32
+
+ strcpy( nt_windows, TEXT( "" ) );
+ strcpy( nt_drive, TEXT( "" ) );
+
+ bytes = GetWindowsDirectory( (LPSTR)nt_windows, (DWORD)255 );
+
+ if ( bytes ) {
+
+ strcat( nt_windows, TEXT( "\\" ) );
+ }
+
+ if ( bytes && ! strlen( nt_drive ) ) {
+
+ nt_drive[ 0 ] = nt_windows[ 0 ]; // TEXT('C')
+ nt_drive[ 1 ] = nt_windows[ 1 ]; // TEXT(':')
+ nt_drive[ 2 ] = TEXT( '\0' );
+ }
+
+#endif
+
+ /* set up bsd list based on operation */
+
+ if ( ( oper == RESTORE_OPER ) ||
+ ( oper == VERIFY_OPER ) ) {
+ temp_bsd_list = tape_bsd_list ;
+ }
+ else {
+ temp_bsd_list = bsd_list ;
+ }
+
+ /* parse the NOVELL.NKS exclude script file AND add an exclude
+ for the Windows swap files to ALL BSDs */
+
+ if( ( oper == BACKUP_OPER ) || ( oper == ARCHIVE_BACKUP_OPER ) ) {
+
+ bsd = BSD_GetFirst( temp_bsd_list ) ;
+
+ while( bsd != NULL ) {
+
+ dle = BSD_GetDLE( bsd ) ;
+
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ if( !warning_printed ) {
+
+ if( ( DLE_GetDeviceType( dle ) == NOVELL_DRV ) ||
+ ( DLE_GetDeviceType( dle ) == NOVELL_AFP_DRV ) ) {
+
+ strcpy( path, CDS_GetUserDataPath( ) ) ;
+ strcat( path, TEXT("NOVELL.NKS") ) ;
+
+ if ( pVlmFind = VLM_FindFirst ( path,
+ VLMFIND_NORMAL, szFile ) )
+ {
+ VLM_FindClose ( &pVlmFind );
+
+ strcpy( path, TEXT("@") ) ;
+ strcat( path, CDS_GetUserDataPath( ) ) ;
+ strcat( path, TEXT("NOVELL.NKS") ) ;
+ dle = DLE_GetDefaultDrive( dle_list ) ;
+ DLE_SetDefaultDrive( dle_list, BSD_GetDLE( bsd ) ) ;
+ tbrparse( &cfg, dle_list, temp_bsd_list, path, TBACKUP, bsd ) ;
+ DLE_SetDefaultDrive( dle_list, dle ) ;
+
+ } else {
+
+ WM_MessageBox( ID( IDS_MSGTITLE_WARNING ),
+ ID( RES_MISSING_NKS ),
+ WMMB_OK,
+ WMMB_ICONEXCLAMATION, NULL, 0, 0 );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_MISSING_NKS ) ;
+ warning_printed = TRUE ;
+
+ }
+ }
+ }
+ }
+# else
+ {
+ // NT special excludes
+
+# if defined ( OS_WIN32 )
+ {
+ CreateExclude( TEXT(""), TEXT("$AttrDef"), dle, FALSE, &fse ) ;
+
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+
+ CreateExclude( TEXT(""), TEXT("$BadClus"), dle, FALSE, &fse ) ;
+
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+
+ CreateExclude( TEXT(""), TEXT("$Bitmap"), dle, FALSE, &fse ) ;
+
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+
+ CreateExclude( TEXT(""), TEXT("$Boot"), dle, FALSE, &fse ) ;
+
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+
+ CreateExclude( TEXT(""), TEXT("$LogFile"), dle, FALSE, &fse ) ;
+
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+
+ CreateExclude( TEXT(""), TEXT("$MFT"), dle, FALSE, &fse ) ;
+
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+
+ CreateExclude( TEXT(""), TEXT("$MFTMirr"), dle, FALSE, &fse ) ;
+
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+
+ CreateExclude( TEXT(""), TEXT("$Quota"), dle, FALSE, &fse ) ;
+
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+
+ CreateExclude( TEXT(""), TEXT("$UpCase"), dle, FALSE, &fse ) ;
+
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+
+ CreateExclude( TEXT(""), TEXT("$Volume"), dle, FALSE, &fse ) ;
+
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+ }
+# endif // OS_WIN32
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ /* parse the user BACKUP.XFS exclude script file */
+
+ strcpy( path, CDS_GetUserDataPath( ) ) ;
+ strcat( path, TEXT("BACKUP.XFS") ) ;
+
+ if ( pVlmFind = VLM_FindFirst ( path,
+ VLMFIND_NORMAL, szFile ) )
+ {
+ VLM_FindClose ( &pVlmFind );
+
+ strcpy( path, TEXT("@") ) ;
+ strcat( path, CDS_GetUserDataPath( ) ) ;
+ strcat( path, TEXT("BACKUP.XFS") ) ;
+ dle = DLE_GetDefaultDrive( dle_list ) ;
+ DLE_SetDefaultDrive( dle_list, BSD_GetDLE( bsd ) ) ;
+ tbrparse( &cfg, dle_list, temp_bsd_list, path, TBACKUP, bsd ) ;
+ DLE_SetDefaultDrive( dle_list, dle ) ;
+
+ }
+
+ /* exclude the Windows swap file names */
+
+ CreateExclude( TEXT(""), TEXT("WIN386.SWP"), dle, FALSE, &fse ) ;
+
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+
+ CreateExclude( TEXT(""), TEXT("PAGEFILE.SYS"), dle, FALSE, &fse ) ;
+
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+
+ CreateExclude( TEXT(""), TEXT("ea data. sf"), dle, FALSE, &fse ) ;
+
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+
+ CreateExclude( TEXT(""), TEXT("386SPART.PAR"), dle, FALSE, &fse ) ;
+
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+
+ bsd = BSD_GetNext( bsd ) ;
+ }
+ }
+
+ /* parse the RESTORE.XFS script file */
+
+ if( oper == RESTORE_OPER ) {
+
+ bsd = BSD_GetFirst( temp_bsd_list ) ;
+
+ while( bsd != NULL ) {
+
+ dle = BSD_GetDLE( bsd ) ;
+
+ strcpy( path, CDS_GetUserDataPath( ) ) ;
+ strcat( path, TEXT("RESTORE.XFS") ) ;
+
+ if ( pVlmFind = VLM_FindFirst( path, VLMFIND_NORMAL, szFile ) ) {
+
+ VLM_FindClose ( &pVlmFind );
+
+ strcpy( path, TEXT("@") ) ;
+ strcat( path, CDS_GetUserDataPath( ) ) ;
+ strcat( path, TEXT("RESTORE.XFS") ) ;
+ dle = DLE_GetDefaultDrive( dle_list ) ;
+ DLE_SetDefaultDrive( dle_list, BSD_GetDLE( bsd ) ) ;
+ tbrparse( &cfg, dle_list, temp_bsd_list, path, TRESTORE, bsd ) ;
+ DLE_SetDefaultDrive( dle_list, dle ) ;
+ bsd = BSD_GetNext( bsd ) ;
+
+ } else {
+
+ bsd = NULL;
+ }
+ }
+ }
+
+#if defined( OS_WIN32 )
+ {
+ /* Exclude EVENT (*.EVT) files from verify operation */
+
+ if ( ( oper == VERIFY_OPER ) ||
+ ( oper == VERIFY_LAST_BACKUP_OPER ) ||
+ ( oper == VERIFY_LAST_RESTORE_OPER ) ) {
+
+ CHAR szPath[ MAX_PATH ] ;
+ UINT16 index ; // used, not important except setting it to 0
+ CHAR_PTR pPath ; // address of special files path
+ INT16 nPathSize ; // size of NULL impregnated path
+ CHAR_PTR pFname ; // !used
+
+ bsd = BSD_GetFirst( temp_bsd_list ) ;
+
+ while ( bsd != NULL ) {
+ dle = BSD_GetDLE( bsd ) ;
+ index = 0 ;
+
+ if ( FS_EnumSpecialFiles( dle, &index, &pPath, &nPathSize, &pFname ) == SUCCESS ) {
+ INT16 deviceLeng = DLE_GetDeviceNameLeng( dle ) ;
+
+ // get the device name, unimpregnate the path and append to device name
+
+ strncpy( szPath, DLE_GetDeviceName( dle ), deviceLeng ) ;
+ memmove( &szPath[ deviceLeng/sizeof(CHAR) ], pPath, nPathSize ) ;
+ unimpregnatePath( szPath, (INT16)(nPathSize + deviceLeng), TEXT('\\') ) ;
+
+ CreateExclude( szPath, TEXT("*.EVT"), dle, USE_WILD_CARD, &fse ) ;
+
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+ }
+
+ bsd = BSD_GetNext( bsd ) ;
+ }
+ }
+ }
+#endif // OS_WIN32
+
+ /* setup the default exclude list */
+
+ switch ( oper ) {
+
+ case BACKUP_OPER :
+ case RESTORE_OPER :
+
+ exclude_list = back_exclude_list ;
+ break ;
+
+ case ARCHIVE_BACKUP_OPER :
+
+ exclude_list = arch_exclude_list ;
+ break ;
+
+ case VERIFY_OPER :
+
+ // copy in the job filename
+
+ exclude_list = ver_exclude_list ;
+ RSM_StringCopy ( IDS_JOBFILENAME, exclude_list[0], 13 );
+ break;
+
+ case VERIFY_LAST_BACKUP_OPER :
+ case ARCHIVE_VERIFY_OPER :
+
+ exclude_list = ver_last_exclude_list ;
+
+ // copy in the schedule filename
+
+ RSM_StringCopy ( IDS_SCHFILENAME, exclude_list[0], 13 );
+
+ data_path = CDS_GetCatDataPath( ) ;
+ psize = UI_MAX_PATH_LENGTH ;
+
+ if( FS_ParsePath( dle_list, data_path, &dle, path, &psize, NULL,
+ &dummy ) == SUCCESS ) {
+
+ bsd = BSD_FindByDLE( temp_bsd_list, dle );
+
+ if( bsd != NULL ) {
+
+ /* call QTC util which will return the full data path */
+ /* and filename of the catalog file being updated. */
+ /* Set the name to familyid.??? so only one exclude is */
+ /* needed (also takes care of possible 8200SX ffr files) */
+
+ QTC_GetFileName( BSD_GetTapeID( bsd ), (INT16)1, path );
+ i = strlen( path );
+ path[--i] = TEXT('?');
+ path[--i] = TEXT('?');
+ path[--i] = TEXT('?');
+
+ /* Add an exclude fse to ALL bsd's with the path dle. */
+ /* We can have more than one bsd for the dle since */
+ /* the catalogs can be included as a bset. */
+
+ while ( bsd != NULL ) {
+
+ if ( BSD_GetDLE( bsd ) == dle ) {
+
+ CreateExclude( data_path,
+ &path[ strlen( data_path ) ],
+ dle,
+ USE_WILD_CARD, &fse ) ;
+
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+ }
+
+ bsd = BSD_GetNext( bsd );
+ }
+ }
+ }
+ break ;
+
+ default:
+
+ exclude_list = empty_exclude_list ;
+ break ;
+
+ } // end SWITCH
+
+
+ /* exlcude the application and all DLL's in the EXE path */
+
+ psize = UI_MAX_PATH_LENGTH ;
+
+ if ( FS_ParsePath( dle_list, CDS_GetExePath (), &dle, path, &psize, NULL, &dummy ) == SUCCESS ) {
+
+ bsd = BSD_FindByDLE( temp_bsd_list, dle );
+
+ if( bsd != NULL ) {
+
+ CreateExclude( CDS_GetExePath (), gb_exe_fname, BSD_GetDLE( bsd ), FALSE, &fse ) ;
+
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+#ifndef OS_WIN32
+ CreateExclude( CDS_GetExePath (), TEXT("*.DLL"), BSD_GetDLE( bsd ), USE_WILD_CARD, &fse ) ;
+
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+#endif
+ }
+ }
+
+ /* exlcude the temporary catalog files in the catalog path */
+
+ psize = UI_MAX_PATH_LENGTH ;
+
+ if( FS_ParsePath( dle_list, CDS_GetCatDataPath(), &dle, path, &psize,
+ NULL, &dummy ) == SUCCESS ) {
+
+ bsd = BSD_FindByDLE( temp_bsd_list, dle );
+
+ if( bsd != NULL ) {
+
+ CreateExclude( CDS_GetCatDataPath(), TEXT("FD??????.FDD"), BSD_GetDLE( bsd ),
+ USE_WILD_CARD, &fse ) ;
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+
+ CreateExclude( CDS_GetCatDataPath(), TEXT("EM??????.FDD"), BSD_GetDLE( bsd ),
+ USE_WILD_CARD, &fse ) ;
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+
+ CreateExclude( CDS_GetCatDataPath(), TEXT("SM??????.SM"), BSD_GetDLE( bsd ),
+ USE_WILD_CARD, &fse ) ;
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+
+ CreateExclude( CDS_GetCatDataPath(), TEXT("QTC_TEMP.???"), BSD_GetDLE( bsd ),
+ USE_WILD_CARD, &fse ) ;
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+
+ CreateExclude( CDS_GetCatDataPath(), TEXT("_PLUS_._"), BSD_GetDLE( bsd ),
+ FALSE, &fse ) ;
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+
+#ifdef UNICODE
+ CreateExclude( CDS_GetCatDataPath(), TEXT("????????.U0?"), BSD_GetDLE( bsd ),
+ USE_WILD_CARD, &fse ) ;
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+
+ CreateExclude( CDS_GetCatDataPath(), TEXT("????????.U1?"), BSD_GetDLE( bsd ),
+ USE_WILD_CARD, &fse ) ;
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+#else
+ CreateExclude( CDS_GetCatDataPath(), TEXT("????????.D0?"), BSD_GetDLE( bsd ),
+ USE_WILD_CARD, &fse ) ;
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+
+ CreateExclude( CDS_GetCatDataPath(), TEXT("????????.D1?"), BSD_GetDLE( bsd ),
+ USE_WILD_CARD, &fse ) ;
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+#endif
+
+ }
+ }
+
+ /**
+ exclude the backup/restore log file
+
+ do not backup/restore the current log. Since the user can rename
+ the backup/restore log, we get the current log name and exclude it
+ UNC paths are supported as log names, but not excluded--yet.
+ **/
+
+ psize = UI_MAX_PATH_LENGTH ;
+
+ if ( FS_ParsePath( dle_list, LOG_GetCurrentLogName(), &dle,
+ path, &psize, &fname, &dummy ) == SUCCESS ) {
+
+ bsd = BSD_FindByDLE( temp_bsd_list, dle ) ;
+
+ if ( bsd != NULL ) {
+
+ LOG_GetCurrentLogPathOnly( path ) ;
+
+ // This one is needed for command line options, where
+ // the user can use any name they want.
+
+ CreateExclude( path, LOG_GetCurrentLogNameOnly(), dle,
+ FALSE, &fse ) ;
+
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse );
+ }
+ }
+ }
+
+ /* now exclude the files in the data path */
+
+ data_path = CDS_GetUserDataPath( ) ;
+ psize = UI_MAX_PATH_LENGTH ;
+
+ if( FS_ParsePath( dle_list, data_path, &dle, path, &psize, NULL,
+ &dummy ) == SUCCESS ) {
+
+ bsd = BSD_FindByDLE( temp_bsd_list, dle );
+
+ if( bsd != NULL ) {
+
+ CreateExclude( data_path, TEXT( "*.LOG" ),
+ BSD_GetDLE( bsd ), USE_WILD_CARD, &fse ) ;
+
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+
+ /* exclude all the files in the exclude array */
+
+ i = 0 ;
+ while ( *exclude_list[ i ] != TEXT('\0') ) {
+
+ CreateExclude( data_path, exclude_list[ i ],
+ BSD_GetDLE( bsd ), FALSE, &fse ) ;
+
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+
+ i ++ ;
+ }
+
+
+# if defined( TDEMO )
+ {
+ /* exlcude the TDEMO data files in the data path */
+
+ CreateExclude( data_path, TEXT("TDEMO?.DAT"), BSD_GetDLE( bsd ),
+ USE_WILD_CARD, &fse ) ;
+ if ( fse != NULL ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+ }
+# endif
+ }
+ }
+
+
+ return( ret_val ) ;
+}
+/*****************************************************************************
+
+ Name: CreateExclude
+
+ Description: This function creates an Exclude FSE for the specified path and file.
+
+ the format of the path must be
+ W:\eng\test\
+
+ if the fse pointer returned is NULL then no fse should be created.
+
+ Returns: none
+
+*****************************************************************************/
+VOID CreateExclude(
+CHAR_PTR path , /* I - path from root of device */
+CHAR_PTR file , /* I - file name to exclude */
+GENERIC_DLE_PTR drive , /* I - device to exclude from */
+BOOLEAN wild_flag , /* I - if file contains wild cards */
+FSE_PTR *fse ) /* O - fse created */
+{
+ GENERIC_DLE_PTR temp_dle ;
+ CHAR base_path[ MAX_UI_PATH_SIZE ] ;
+ CHAR vol_name[ UI_MAX_VOLUME_LENGTH ] ;
+ CHAR_PTR p ;
+ CHAR drive_name[ 3 ] ;
+ INT size ;
+ BOOLEAN sub_flag = FALSE ;
+
+ *fse = NULL ;
+
+ if ( path[ 0 ] != TEXT('\0') ) {
+
+ drive_name[ 0 ] = path[ 0 ] ;
+ drive_name[ 1 ] = path[ 1 ] ;
+ drive_name[ 2 ] = TEXT('\0') ;
+
+ if ( DLE_FindByName( dle_list, drive_name, ANY_DRIVE_TYPE, &temp_dle ) == SUCCESS ) {
+
+ if ( ( DLE_GetDeviceType( drive ) == NOVELL_DRV ) ||
+ ( DLE_GetDeviceType( drive ) == NOVELL_AFP_DRV ) ) {
+
+ DLE_GetVolName( drive, vol_name ) ;
+ DLE_GetVolName( temp_dle, base_path ) ;
+
+ p = strchr( vol_name, TEXT(':') ) ;
+ msassert( p != NULL ) ;
+ size = p - vol_name ;
+
+ if( !strncmp( vol_name, base_path, size ) ) {
+ /* same server/volume */
+
+ strcat( p++, TEXT("\\") ) ;
+
+ size = strlen( p ) ;
+ if( !strncmp( path + 3, p, size ) ) {
+ /* same base path */
+
+ strcpy( base_path, &path[ 3 + size ] ) ;
+ p = base_path ;
+ if ( p[ 0 ] == TEXT('\0') ) {
+ size = 1;
+ } else {
+ size = 0 ;
+ while( p[ size ] != TEXT('\0') ) {
+
+ if( p[ size ] == TEXT('\\') ) {
+ p[ size ] = TEXT('\0') ;
+ }
+
+ size++ ;
+ }
+ }
+
+ if( BSD_CreatFSE( fse, EXCLUDE, (INT8_PTR)p,
+ (INT16)(size * sizeof(CHAR)),
+ (INT8_PTR)file,
+ (INT16)strsize(file),
+ wild_flag, FALSE ) != SUCCESS ) {
+
+ *fse = NULL ;
+ }
+ }
+ }
+
+ } else {
+
+ if ( ! ( DLE_HasFeatures( drive, DLE_FEAT_REMOTE_DRIVE ) ) && /* substuted dirs */
+ ! ( DLE_HasFeatures( temp_dle, DLE_FEAT_REMOTE_DRIVE ) ) ) {
+
+ if ( drive == temp_dle ) {
+
+ strcpy( base_path, path+3 ) ;
+
+ p = base_path ;
+ if ( p[ 0 ] == TEXT('\0') ) {
+ size = 1;
+ } else {
+ size = 0 ;
+ while( p[ size ] != TEXT('\0') ) {
+
+ if( p[ size ] == TEXT('\\') ) {
+ p[ size ] = TEXT('\0') ;
+ }
+
+ size++ ;
+ }
+ }
+ } else {
+ size = 1 ;
+ p = TEXT("") ;
+ sub_flag = TRUE ;
+ }
+
+ if ( BSD_CreatFSE( fse, EXCLUDE, (INT8_PTR)p,
+ (INT16)(size * sizeof (CHAR)),
+ (INT8_PTR)file,
+ (INT16)strsize(file),
+ wild_flag, (BOOLEAN)sub_flag ) != SUCCESS ) {
+ *fse = NULL ;
+ }
+ }
+ }
+ }
+
+ } else {
+ if ( BSD_CreatFSE( fse, EXCLUDE, (INT8_PTR)TEXT(""), sizeof(CHAR),
+ (INT8_PTR)file,
+ (INT16)strsize( file ),
+ wild_flag, TRUE ) != SUCCESS ) {
+ *fse = NULL ;
+ }
+ }
+}
+
+
+/*****************************************************************************
+ Name: unimpregnatePath
+ Desc: Accepts a NULL impregnated path and the path's size and replaces
+ all impregnated NULLs with the delimiter character and NULL
+ terminates the path before ending.
+ Date: 04/01/93
+*****************************************************************************/
+
+VOID unimpregnatePath(
+CHAR_PTR pPath, /* I/O path to unimpregnate */
+INT16 nPathSize, /* I size of path */
+CHAR cDelimiter ) /* I path delimiter char */
+{
+ nPathSize /= 2 ;
+ for ( ; nPathSize; pPath++, nPathSize-- ) {
+ if ( *pPath == TEXT('\0') ) {
+ *pPath = cDelimiter ;
+ }
+ }
+
+ *pPath = TEXT('\0') ;
+}
diff --git a/private/utils/ntbackup/src/do_ffr.c b/private/utils/ntbackup/src/do_ffr.c
new file mode 100644
index 000000000..123682c0a
--- /dev/null
+++ b/private/utils/ntbackup/src/do_ffr.c
@@ -0,0 +1,602 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: do_ffr.c
+
+ Description: Function called from do_rest and do_very to pre-qualify
+ catalog backup sets and call loop to generated LBA
+ queue for each BSD.
+
+ $Log: G:/UI/LOGFILES/DO_FFR.C_V $
+
+ Rev 1.29 20 Jul 1994 19:33:36 STEVEN
+fix bad lba problem
+
+ Rev 1.28 17 Jan 1994 16:10:20 MIKEP
+fix unicode warnings
+
+ Rev 1.27 19 Jul 1993 10:10:42 BARRY
+Don't reference dle in BSD directly -- use BSD_GetDLE instead.
+
+ Rev 1.26 14 Jun 1993 20:27:02 MIKEP
+enable c++
+
+ Rev 1.25 29 Apr 1993 11:24:24 MIKEP
+try again at last fix
+
+ Rev 1.24 29 Apr 1993 11:09:08 MIKEP
+add on tape catalog version
+
+ Rev 1.23 08 Apr 1993 14:26:22 MIKEP
+Fix to allow user to restore files from the root of a set that has the
+registry backed up, ie. the root is in the catalogs twice. Requires a
+change to gtnxttpe.c to eliminate an assert.
+
+ Rev 1.22 26 Feb 1993 09:57:00 STEVEN
+we ignored the registry button
+
+ Rev 1.21 25 Feb 1993 13:25:04 STEVEN
+fixes from mikep and MSOFT
+
+ Rev 1.20 09 Feb 1993 17:18:38 STEVEN
+checkin for mikep
+
+ Rev 1.19 04 Feb 1993 16:12:22 STEVEN
+allow wildcards for exclude list
+
+ Rev 1.18 01 Nov 1992 15:49:16 DAVEV
+Unicode changes
+
+ Rev 1.17 07 Oct 1992 14:49:14 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.16 04 Oct 1992 19:34:10 DAVEV
+Unicode Awk pass
+
+ Rev 1.15 30 Sep 1992 10:43:46 DAVEV
+Unicode strlen verification, MikeP's chgs from MS
+
+ Rev 1.14 17 Aug 1992 13:16:04 DAVEV
+MikeP's changes at Microsoft
+
+ Rev 1.13 27 Jul 1992 14:49:56 JOHNWT
+ChuckB fixed references for NT.
+
+ Rev 1.12 27 Jul 1992 11:09:32 JOHNWT
+ChuckB checked in for John Wright, who is no longer with us.
+
+ Rev 1.11 08 Jul 1992 15:36:04 STEVEN
+Unicode BE changes
+
+ Rev 1.10 14 May 1992 17:39:20 MIKEP
+nt pass 2
+
+ Rev 1.9 11 May 1992 19:45:06 STEVEN
+64bit and large path sizes
+
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+typedef struct {
+
+ CHAR_PTR path; /* path for catalog query */
+ INT16 path_size; /* size of directory path */
+ CHAR itemname[256]; /* itemname for query */
+ INT16 item_size; /* size of itemname for search*/
+
+ FSE_PTR fse_ptr;
+ BSD_PTR bsd_ptr; /* bsd_ptr for this item */
+
+} LBA_QUERY, *LBA_QUERY_PTR;
+
+static INT16 GetLBAList( LIS_PTR );
+static INT16 GetLBAs( QTC_QUERY_PTR, BSD_PTR, FSE_PTR, UINT16 );
+static INT16 GetLBAForItem( QTC_QUERY_PTR, LBA_QUERY_PTR, UINT32_PTR, UINT16_PTR, INT16 );
+static BOOLEAN NewLBADirToProcess( LBA_QUERY_PTR );
+static INT16 TryToFindMoreMatchesInSameBSD( QTC_QUERY_PTR, LBA_QUERY_PTR, INT16 );
+
+INT16 mw_tape_num;
+
+/*****************************************************************************
+
+ Name: TryToCreateFFRQueue
+
+ Description: Set up the catalog and call routine to create an
+ LBA queue for a restore or a verify operation.
+
+ Returns: SUCCESS
+ FAILURE indicating that an empty bsd_list or catalog
+ error has resulted
+
+*****************************************************************************/
+INT16 TryToCreateFFRQueue(
+LIS_PTR lis,
+INT16 oper_type )
+{
+ INT16 ret_val = SUCCESS;
+
+ /* If the user does not want to use FFR or the tape drive does not
+ support FFR or we are about to perform a verify after or verify
+ last operation, simply return */
+
+ /* We generate the lba queue even if the drive doesn't support it
+ because the Teac 600 tells us it doesn't, then during the mount
+ it changes its mind. */
+
+ /* And because our catalogs are so fast no one notices anyway. */
+
+ if ( ! CDS_GetFastFileRestore( CDS_GetCopy() ) ||
+ ( oper_type == ARCHIVE_VERIFY_OPER ) ||
+ ( oper_type == VERIFY_LAST_BACKUP_OPER ) ||
+ ( oper_type == VERIFY_LAST_RESTORE_OPER ) ) {
+
+ // We were successful at not generating an LBA queue
+
+ return( SUCCESS );
+ }
+
+ /* Continue with calling loop to generated LBA Queue for the BSD list */
+
+ WM_ShowWaitCursor( TRUE );
+
+ ret_val = GetLBAList( lis );
+
+ WM_ShowWaitCursor( FALSE );
+
+ return( ret_val );
+}
+
+/**************************************************************************/
+/* */
+/* NOTES: */
+/* */
+/* (2) Wildcard filenames in a directory and entire directories (*.* */
+/* file specifications) will be treated as the same case for the */
+/* initial release of FFR support. */
+/* */
+/* (3) Since all single file processing is performed by examining the */
+/* FSL for each BSD, all desired files must have associated FSEs */
+/* in order to generate the corresponding LBA entries. Bindery */
+/* files will be individually handled by adding specific FSEs */
+/* to the FSL via File System calls (performed by the user */
+/* interface prior to calling the loops). */
+/* */
+/**************************************************************************/
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT16 GetLBAList( LIS_PTR lis_ptr )
+{
+ BSD_PTR bsd_ptr = lis_ptr->curr_bsd_ptr;
+ FSE_PTR fse_ptr;
+ QTC_QUERY_PTR query;
+ INT32 pba;
+ GENERIC_DLE_PTR dle_ptr;
+ UINT16 index = 0;
+ CHAR_PTR path;
+ INT16 path_size;
+ CHAR_PTR fname;
+ UINT8 TapeCatVer;
+
+ query = QTC_InitQuery( );
+ if ( query == NULL ) return( SUCCESS );
+
+ bsd_ptr = lis_ptr->curr_bsd_ptr;
+
+ /* Loop across all BSD elements in list */
+
+ while ( bsd_ptr != NULL ) {
+
+ /* Generate FSEs for the bindery files by getting names from FS */
+
+ index = 0;
+
+ mw_tape_num = -1;
+
+ dle_ptr = BSD_GetDLE( bsd_ptr );
+ if ( BSD_GetProcSpecialFlg( bsd_ptr ) ) {
+
+ while ( ( FS_EnumSpecialFiles( dle_ptr, &index, &path, &path_size, &fname ) ) != FS_NO_MORE ) {
+
+ BSD_CreatFSE( &fse_ptr, (INT16) INCLUDE, (INT8_PTR)path, (INT16) path_size,
+ (INT8_PTR)fname,
+ (INT16) strsize(fname),
+ TRUE, FALSE );
+
+ if ( fse_ptr != NULL ) {
+ BSD_AddFSE( bsd_ptr, fse_ptr );
+ }
+ }
+ }
+
+ QTC_SetTapeFID( query, BSD_GetTapeID( bsd_ptr ) );
+ QTC_SetTapeSeq( query, -1 );
+ QTC_SetBsetNum( query, BSD_GetSetNum( bsd_ptr ) );
+ QTC_SetSubdirs( query, FALSE );
+
+ /* Loop across all FSE attached to this BSD */
+
+ fse_ptr = BSD_GetFirstFSE( bsd_ptr );
+
+ while ( fse_ptr != NULL ) {
+
+ /* Process all INCLUDE FSEs */
+
+ if ( FSE_GetOperType( fse_ptr ) == INCLUDE ) {
+
+ /* Determine type of FSE and call appropriate function */
+
+ if ( FSE_GetSelectType( fse_ptr ) == SINGLE_FILE_SELECTION ) {
+
+ GetLBAs( query, bsd_ptr, fse_ptr, LBA_SINGLE_OBJECT );
+ } else {
+
+ GetLBAs( query, bsd_ptr, fse_ptr, LBA_BEGIN_POSITION );
+ }
+ }
+
+ /* Get next FSE for this BSD */
+
+ fse_ptr = BSD_GetNextFSE( fse_ptr );
+ }
+
+ // We need the PBA of the highest number tape seq which
+ // contains the first LBA we are going to restore.
+
+ pba = QTC_GetMeTheVCBPBA( BSD_GetTapeID( bsd_ptr ),
+ mw_tape_num,
+ BSD_GetSetNum( bsd_ptr ) );
+
+ /* if this is an 8200SX drive, we don't really have a pba
+ so set it to manufacture the pba in the beng */
+
+ if ( ( ! pba ) && SupportSXFastFile( thw_list ) ) {
+ pba = MANUFACTURED_PBA;
+ }
+
+ BSD_SetPBA( bsd_ptr, pba );
+
+ TapeCatVer = QTC_GetMeTheTapeCatVer( BSD_GetTapeID( bsd_ptr ),
+ mw_tape_num,
+ BSD_GetSetNum( bsd_ptr ) );
+
+ BSD_SetTapeCatVer( bsd_ptr, TapeCatVer );
+
+ bsd_ptr = BSD_GetNext( bsd_ptr );
+
+ }
+
+ QTC_CloseQuery( query );
+
+ return( SUCCESS );
+
+}
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static INT16 GetLBAs(
+QTC_QUERY_PTR query,
+BSD_PTR curr_bsd_ptr, /* I - pointer to the current BSD */
+FSE_PTR curr_fse_ptr, /* I - pointer to the current FSE */
+UINT16 type ) /* type of LBA to enqueue */
+{
+ INT16 ret_val; /* return value */
+ LBA_QUERY lba_query; /* query related info */
+ UINT32 lba; /* lba found by query */
+ INT16 tape_num;
+
+ /* Setup path and filename for search */
+
+ FSE_GetPath( curr_fse_ptr, (BYTE **)&lba_query.path, &lba_query.path_size );
+
+ lba_query.bsd_ptr = curr_bsd_ptr;
+ lba_query.fse_ptr = curr_fse_ptr;
+
+ if ( type != LBA_SINGLE_OBJECT ) {
+
+ /** It was just a path, so process path into itemname and path **/
+
+ strcpy( lba_query.itemname, TEXT("") );
+ lba_query.item_size = 0;
+
+ ret_val = GetLBAForItem( query, &lba_query, &lba, (UINT16_PTR)&tape_num, type );
+ }
+ else {
+
+ /* Get LBA for this file item */
+
+ strcpy( lba_query.itemname, (CHAR_PTR)FSE_GetFname( curr_fse_ptr ) );
+ lba_query.item_size = (INT16)(strsize( lba_query.itemname )-sizeof(CHAR)); //byte len w/o null term
+
+ /* a file must always be found on the lowest number tape first,
+ at least I hope ! */
+
+ ret_val = GetLBAForItem( query, &lba_query, &lba, (UINT16_PTR)&tape_num, type );
+
+ }
+
+ if ( ret_val == SUCCESS ) {
+
+ /* Save this LBA */
+
+ if ( BSD_AddLBAElem( curr_bsd_ptr, lba, tape_num, type, 0 ) == SUCCESS ) {
+
+ if ( tape_num < mw_tape_num || mw_tape_num == -1 ) {
+
+ mw_tape_num = tape_num;
+ }
+
+ /* Check for processing security information for this BSD */
+ /* and continue to adjust the dir of interest until the */
+ /* root is reached */
+
+ if ( BSD_GetProcElemOnlyFlg( curr_bsd_ptr ) == FALSE ) {
+
+ /* Continue for each subdir level until the root is reached */
+
+ do {
+ strcpy( lba_query.itemname, TEXT("") );
+ lba_query.item_size = 0;
+
+ ret_val = GetLBAForItem( query, &lba_query,
+ &lba, (UINT16_PTR)&tape_num, (INT16) -1 );
+
+ if ( ret_val == SUCCESS ) {
+
+ /* Save this LBA */
+ BSD_AddLBAElem( curr_bsd_ptr, lba,
+ (UINT16) tape_num,
+ (UINT16) LBA_SINGLE_OBJECT, (UINT16) 0 );
+
+ if ( tape_num < mw_tape_num ||
+ mw_tape_num == -1 ) {
+
+ mw_tape_num = tape_num;
+ }
+ }
+
+ } while ( NewLBADirToProcess( &lba_query ) );
+
+ } else {
+
+ /* If we're processing a single file selection then we */
+ /* need to find the LBA for its parent, otherwise we */
+ /* are processing a directory based selection so we're */
+ /* finished. */
+
+ if ( type == LBA_SINGLE_OBJECT ) {
+
+ /* Just do one directory LBA */
+
+ strcpy( lba_query.itemname, TEXT("") );
+ lba_query.item_size = 0;
+
+ ret_val = GetLBAForItem( query, &lba_query,
+ &lba, (UINT16_PTR)&tape_num,
+ (INT16) LBA_SINGLE_OBJECT );
+
+ if ( ret_val == SUCCESS ) {
+
+ /* Save this LBA */
+ BSD_AddLBAElem( curr_bsd_ptr, lba,
+ (UINT16) tape_num,
+ (UINT16) LBA_SINGLE_OBJECT, (UINT16) 0 );
+
+ if ( tape_num < mw_tape_num || mw_tape_num == -1 ) {
+
+ mw_tape_num = tape_num;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return( ret_val );
+}
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static INT16 GetLBAForItem(
+QTC_QUERY_PTR query,
+LBA_QUERY_PTR lba_query, /* criteria for catalog query */
+UINT32_PTR lba, /* lba to fill out */
+UINT16_PTR tape_num, /* tape lba is on */
+INT16 type )
+{
+
+ INT16 ret_val; /* return value */
+
+ /* First init LBA to not found condition */
+
+ *lba = 0;
+
+ /* Setup Catalog Query structure */
+
+ QTC_SetSearchPath( query, lba_query->path, lba_query->path_size );
+ QTC_SetSearchName( query, lba_query->itemname );
+ QTC_SetSubdirs( query, FALSE );
+
+ /* Find first occurance of matching item */
+
+ if ( ! QTC_SearchFirstItem( query ) ) {
+
+ *lba = QTC_GetItemLBA( query );
+
+ /* Setup to return this LBA */
+
+ *tape_num = (INT16)QTC_GetTapeSeq( query );
+
+ ret_val = SUCCESS;
+
+
+ TryToFindMoreMatchesInSameBSD( query, lba_query, type );
+
+ }
+ else {
+ ret_val = FAILURE;
+ }
+
+ return( ret_val );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+/*** We got an LBA for a directory and now we need to see if we can
+ find more matches in the same BSD. If we can, then they need to
+ be added to the LBA queue as well.
+***/
+
+static INT16 TryToFindMoreMatchesInSameBSD(
+QTC_QUERY_PTR query,
+LBA_QUERY_PTR lba_query,
+INT16 type )
+{
+ INT16 tape_num;
+
+ // If the directory found has duplicates than enter the lba's for
+ // all the duplicates.
+
+ while ( ! QTC_SearchNextItem( query ) ) {
+
+ tape_num = (INT16)QTC_GetTapeSeq( query );
+
+ if ( !( query->status & QTC_DIRECTORY ) ||
+ !( query->status & QTC_CONTINUATION ) ||
+ ( QTC_GetItemLBA(query) > 1 ) ) {
+
+ BSD_AddLBAElem( lba_query->bsd_ptr,
+ QTC_GetItemLBA( query ),
+ tape_num,
+ type, 0 );
+
+ }
+
+ if ( tape_num < mw_tape_num || mw_tape_num == -1 ) {
+
+ mw_tape_num = tape_num;
+ }
+ }
+
+ return( 0 );
+
+}
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+/***
+
+ 4 things to work with,
+ lba_query->path
+ lba_query->path_size - includes trailing null byte
+ lba_query->itemname
+ lba_query->item_size - excludes trailing null byte
+
+ Before
+ path = eng\proj\bengine
+ itemname = src
+
+ After
+ path = eng\proj
+ itemname = bengine
+
+***************/
+
+static BOOLEAN NewLBADirToProcess( lba_query )
+LBA_QUERY_PTR lba_query;
+{
+ INT i;
+ static CHAR_PTR empty = TEXT("");
+
+ /* Determine if a parent directory needs to be "extracted" */
+
+ if ( lba_query->path_size == 0 ) {
+ return FALSE;
+ }
+
+
+ if( lba_query->path_size != sizeof (CHAR) ) {
+
+ /* Make adjustments for new parent dir to process */
+
+ for( i = lba_query->path_size/sizeof (CHAR) - 2; i >= 0; i-- ) {
+
+ if ( lba_query->path[i] == TEXT('\0') ) {
+
+ strcpy( lba_query->itemname, &lba_query->path[i+1] );
+ lba_query->item_size = (INT16)(strsize( lba_query->itemname )-sizeof(CHAR));
+ lba_query->path_size = (INT16)(i * sizeof (CHAR));
+ return TRUE;
+ }
+ }
+
+ /* top subdirectory */
+
+ strcpy( lba_query->itemname, &lba_query->path[0] );
+ lba_query->item_size = (INT16)(strsize( lba_query->itemname )-sizeof(CHAR)); //byte size w/o null term
+ lba_query->path = empty;
+ lba_query->path_size = sizeof (CHAR);
+ return TRUE;
+
+ }
+ else {
+
+ /** Now do root **/
+
+ strcpy( lba_query->itemname, TEXT("") );
+ lba_query->item_size = sizeof (CHAR); //byte size (why does this one incl null term??)
+ lba_query->path_size = 0;
+ lba_query->path = empty;
+ return TRUE;
+ }
+}
diff --git a/private/utils/ntbackup/src/do_misc.c b/private/utils/ntbackup/src/do_misc.c
new file mode 100644
index 000000000..05425c31e
--- /dev/null
+++ b/private/utils/ntbackup/src/do_misc.c
@@ -0,0 +1,761 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: do_misc.c
+
+ Description:
+
+ $Log: J:/UI/LOGFILES/DO_MISC.C_V $
+
+ Rev 1.31 24 Mar 1994 15:29:32 GREGG
+Initialize temp size parameter passed into MapAnsiToUnicNoNull.
+
+ Rev 1.30 21 Mar 1994 12:40:08 STEVEN
+fix mapuin bugs
+
+ Rev 1.29 02 Feb 1994 17:30:34 chrish
+Added changes for UNICODE app to handle ANSI secured tapes.
+
+ Rev 1.28 17 Jan 1994 16:13:46 MIKEP
+fix unicode warnings
+
+ Rev 1.27 24 Nov 1993 15:32:04 BARRY
+Unicode fixes
+
+ Rev 1.26 26 Jul 1993 18:14:50 MARINA
+enable c++
+
+ Rev 1.25 30 Apr 1993 15:52:24 chrish
+NOSTRADAMOUS EPR 0391: Added logic to display when user aborts an operation
+to say "Operation completed" instead of "... operation completed successfully".
+
+ Rev 1.24 22 Apr 1993 15:54:48 chrish
+Fixs for Nostradamous: EPR 0403 - Added new function to get the user name
+from the catalog information of the first set on the tape. This is so as to
+display the original owner of the tape when the erase dialog box pops up.
+
+ Rev 1.23 08 Apr 1993 17:15:22 chrish
+Added new function WhoPasswordedTape to determine if the tape was secured
+by NTBackup or some other app ... ie Cayman app.
+
+
+ Rev 1.22 17 Mar 1993 16:14:22 chrish
+Added change to IsUserValid routine.
+
+ Rev 1.21 22 Feb 1993 11:18:26 chrish
+Added changes received from MikeP.
+Fix IsUserValid by non encrypting an already encypted password.
+
+ Rev 1.20 09 Feb 1993 09:41:54 chrish
+Minor change to UI_GetCurrentStatus routine for OPERATION_RESTORE case.
+
+ Rev 1.19 15 Dec 1992 11:23:16 chrish
+Modified IsUserValid routine, added another parameter passed to it.
+
+ Rev 1.18 14 Dec 1992 12:18:04 DAVEV
+Enabled for Unicode compile
+
+ Rev 1.17 18 Nov 1992 11:22:06 chrish
+Added IFDEF OS_WIN32 for NT specific stuff.
+
+ Rev 1.17 18 Nov 1992 10:27:34 chrish
+IFDEF functions used only for NT app.
+
+ Rev 1.16 16 Nov 1992 12:20:58 chrish
+Minor changes to clean-up warning messages on building.
+
+ Rev 1.15 13 Nov 1992 17:25:46 chrish
+Added some routine used for Tape Security for NT
+
+ Rev 1.14 01 Nov 1992 15:49:30 DAVEV
+Unicode changes
+
+ Rev 1.13 20 Oct 1992 17:18:14 MIKEP
+abort at eof
+
+ Rev 1.12 20 Oct 1992 15:44:30 MIKEP
+gbCurrentOperation
+
+ Rev 1.11 07 Oct 1992 14:53:38 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.10 04 Oct 1992 19:34:14 DAVEV
+Unicode Awk pass
+
+ Rev 1.9 27 Jul 1992 14:49:06 JOHNWT
+ChuckB fixed references for NT.
+
+ Rev 1.8 11 Jun 1992 15:20:50 DAVEV
+do not display status message 'Examine <log file> for more info' if not logging
+
+ Rev 1.7 14 May 1992 17:24:08 MIKEP
+nt pass 2
+
+ Rev 1.6 28 Jan 1992 12:08:48 CARLS
+
+
+ Rev 1.5 28 Jan 1992 12:04:36 CARLS
+coding error on comment
+
+ Rev 1.4 28 Jan 1992 11:59:10 CARLS
+fixed password problem
+
+ Rev 1.3 16 Dec 1991 11:45:04 CARLS
+added <windows.h>
+
+ Rev 1.2 12 Dec 1991 11:03:36 JOHNWT
+removed UI_GetPasswordsAndLabels
+
+ Rev 1.1 25 Nov 1991 15:32:50 JOHNWT
+removed mresprintf
+
+ Rev 1.0 20 Nov 1991 19:32:24 SYSTEM
+Initial revision.
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+/*****************************************************************************
+
+ Name: UI_AbortAtEndOfFile
+
+ Description: Abort current operation at the end of the current file.
+
+ Returns: SUCCESS
+
+*****************************************************************************/
+INT UI_AbortAtEndOfFile( )
+{
+ gbAbortAtEOF = TRUE;
+ return( SUCCESS );
+}
+
+
+
+/*****************************************************************************
+
+ Name: UI_GetCurrentStatus
+
+ Description: Get the current status of an on going operation.
+
+ Returns: SUCCESS
+
+*****************************************************************************/
+INT UI_GetCurrentStatus(
+INT *Operation,
+STATS *Stats,
+CHAR *Path,
+INT PathSize )
+{
+
+ *Operation = gbCurrentOperation;
+
+ switch ( gbCurrentOperation ) {
+
+ case OPERATION_BACKUP:
+ UI_GetBackupCurrentStatus( Stats, Path, PathSize );
+ break;
+
+ case OPERATION_RESTORE:
+ UI_GetRestoreCurrentStatus( Stats, Path, PathSize );
+ break;
+
+ case OPERATION_VERIFY:
+ UI_GetBackupCurrentStatus( Stats, Path, PathSize );
+ break;
+
+ case OPERATION_CATALOG:
+ UI_GetBackupCurrentStatus( Stats, Path, PathSize );
+ break;
+
+ default:
+ break;
+ }
+
+
+ return( SUCCESS );
+}
+
+
+/*****************************************************************************
+
+ Name: UI_CheckOldTapePassword
+
+ Description: Function called from Cat/Restore/Verify tape positioners to
+ validate a tape password.
+
+ Returns: (UINT16)response that is returned to Tape Format if an
+ error has occurred
+
+ Notes: If a given tape has had the password matched once, this
+ routine will "match" the current password automatically
+
+*****************************************************************************/
+UINT16 UI_CheckOldTapePassword(
+DBLK_PTR cur_vcb )
+{
+ UINT16 response ;
+
+ /* assume the password already has or will be matched */
+ response = UI_CONTINUE_POSITIONING ;
+
+ /* look for MaynStream Tape Passwords */
+
+ if ( ( FS_SizeofTapePswdInVCB( cur_vcb ) != 0 ) ||
+ ( FS_SizeofSetPswdInVCB( cur_vcb ) != 0 ) ) {
+
+ /* TRUE = passwords matched, FALSE = no match */
+ if ( !VerifyTapePassword( (CHAR_PTR)FS_ViewTapeNameInVCB( cur_vcb ),
+ (CHAR_PTR)FS_ViewSetDescriptInVCB( cur_vcb ),
+ (CHAR_PTR)FS_ViewUserNameInVCB( cur_vcb ),
+ FS_ViewPswdEncryptInVCB( cur_vcb ),
+ (INT8_PTR)FS_ViewTapePasswordInVCB( cur_vcb ),
+ FS_SizeofTapePswdInVCB( cur_vcb ),
+ (INT8_PTR)FS_ViewSetPswdInVCB( cur_vcb ),
+ FS_SizeofSetPswdInVCB( cur_vcb ),
+ FS_ViewTapeIDInVCB( cur_vcb ) ) ) {
+
+ response = UI_ABORT_POSITIONING ;
+ }
+ }
+
+ return response ;
+}
+/*****************************************************************************
+
+ Name: UI_ChkDispGlobalError
+
+ Description: Checks and displays error message if global variable
+ gb_error_during_operation is TRUE.
+
+ Returns: VOID
+
+*****************************************************************************/
+VOID UI_ChkDispGlobalError ( )
+{
+ if ( gb_error_during_operation == TRUE ) {
+
+ yresprintf( RES_ERROR_DURING_OPERATION ) ;
+ JobStatusBackupRestore(JOB_STATUS_LISTBOX);
+
+
+ if ( CDS_GetOutputDest( CDS_GetPerm() ) == (INT16) LOG_TO_FILE
+ && CDS_GetLogLevel ( CDS_GetPerm() ) != (INT16) LOG_DISABLED ) {
+ yresprintf( (INT16) RES_ERROR_FILE_TO_EXAMINE, LOG_GetCurrentLogName() ) ;
+ JobStatusBackupRestore(JOB_STATUS_LISTBOX);
+ }
+
+ } else {
+ if ( gb_abort_flag != CONTINUE_PROCESSING ) { // chs:04-30-93
+ yresprintf( (INT16) RES_OPERATION_COMPLETED ) ; // chs:04-30-93
+ } else { // chs:04-30-93
+ yresprintf( (INT16) RES_NOERROR_DURING_OPERATION ) ; // chs:04-30-93
+ } // chs:04-30-93
+ JobStatusBackupRestore(JOB_STATUS_LISTBOX);
+ }
+}
+
+
+/***************************************************
+
+ Name: GetCurrentMachineNameUserName
+
+ Description: Retrieves the Machine name and the
+ username as one string. Example
+ "machinename/username"
+
+ Returns: pointer to machine/user name
+
+*****************************************************/
+CHAR_PTR GetCurrentMachineNameUserName ( VOID )
+{
+ GENERIC_DLE_PTR dle_ptr;
+ CHAR_PTR machineusername;
+
+
+ machineusername = NULL;
+ DLE_GetFirst( dle_list, &dle_ptr );
+
+ if ( dle_ptr ) {
+ machineusername = DLE_ViewUserName( dle_ptr );
+ }
+
+ return( machineusername );
+}
+
+/***************************************************
+
+ Name: DoesUserHaveThisPrivileges
+
+ Description: Checks to see if current user
+ has administrative privileges.
+
+
+ Returns: TRUE - if has admin priv.
+ FALSE - if does not have admin. priv.
+
+
+*****************************************************/
+BOOLEAN DoesUserHaveThisPrivilege ( CHAR_PTR privilegestring )
+{
+
+#ifdef OS_WIN32
+
+ BOOLEAN ret_val = TRUE;
+ HANDLE ProcessHandle;
+ DWORD DesiredAccess;
+ HANDLE TokenHandle;
+ LUID BackupValue;
+ TOKEN_PRIVILEGES NewState;
+ DWORD error;
+
+
+ // get process handle
+
+ ProcessHandle = GetCurrentProcess();
+
+ // open process token
+
+ DesiredAccess = MAXIMUM_ALLOWED;
+
+ if ( ! OpenProcessToken( ProcessHandle, DesiredAccess, &TokenHandle ) ) {
+ return( FALSE );
+ }
+
+ // adjust backup token privileges
+
+ if ( ! LookupPrivilegeValue( NULL, privilegestring, &BackupValue ) ) {
+ ret_val = FALSE;
+ }
+
+ // Enable backup privilege for this process
+
+ NewState.PrivilegeCount = 1;
+ NewState.Privileges[0].Luid = BackupValue;
+ NewState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+ AdjustTokenPrivileges( TokenHandle, FALSE, &NewState, (DWORD)0, NULL, NULL );
+ error = GetLastError();
+
+ if ( error ) {
+ ret_val = FALSE;
+ }
+
+ // close process token
+
+ CloseHandle( TokenHandle );
+ return( ret_val );
+
+#else
+
+ return ( TRUE );
+
+#endif
+
+}
+
+/***************************************************
+
+ Name: IsCurrentTapeSecured
+
+ Description: Check to see if current tape has a
+ password.
+
+
+ Returns: TRUE - tape is secured
+ FALSE - tape in not secure
+
+
+*****************************************************/
+BOOLEAN IsCurrentTapeSecured (
+
+DBLK_PTR vcb_ptr ) // current vcb
+
+{
+ if ( !vcb_ptr ) return( FALSE );
+
+ // does the tape have a password, check the tape password length
+ // for the current vcb
+
+ if ( FS_SizeofTapePswdInVCB( vcb_ptr ) ) {
+ return( TRUE );
+ }
+
+ return( FALSE );
+}
+
+/***************************************************
+
+ Name: IsUserValid
+
+ Description: Check to see if user has permission
+ to do backup on the tape. Basically
+ see if user is administrator or matches
+ tape password.
+ The vcb passed will contain the tape passwd
+ that is on the tape. The inputtapepasswd is
+ the current "machine/username" password.
+
+
+ Returns: TRUE - User is valid, he/she has privilege
+ FALSE - User is NOT valid, he/she does not
+ have privilege
+
+
+*****************************************************/
+BOOLEAN IsUserValid ( DBLK_PTR vcb_ptr, // current VCB
+ INT8_PTR inputtapepasswd, // tape password
+ INT16 inputtapepasswdlength // length of password
+)
+{
+ CHAR_PTR temppasswd; // hold the tape password from the VCB
+ // passwd on the tape.
+ INT dummysize;
+ INT16 tempsize; // length of password from tape.
+ CHAR_PTR buffer = NULL;
+ CHAR_PTR temppasswdbuffer = NULL;
+ BOOLEAN retcode;
+
+ if ( !vcb_ptr ) return( FALSE );
+ //
+ // Verify if user tape password matches.
+ // Check the tape password from the current VCB
+ //
+
+ temppasswd = FS_ViewTapePasswordInVCB( vcb_ptr );
+ if ( !temppasswd ) return( TRUE ); // no password on tape
+
+ tempsize = FS_SizeofTapePswdInVCB( vcb_ptr );
+ if ( tempsize == 0 ) return( TRUE ); // no password on tape
+
+ buffer = ( CHAR_PTR )calloc(1, tempsize * sizeof( CHAR ) );
+ if ( !buffer ) return( FALSE );
+
+#ifdef UNICODE
+ if ( FS_ViewStringTypeinDBLK( vcb_ptr ) == BEC_ANSI_STR ) {
+
+ temppasswdbuffer = ( CHAR_PTR )calloc(1, tempsize );
+ if ( !temppasswdbuffer ) {
+ free( buffer );
+ return( FALSE );
+ }
+ memcpy( temppasswdbuffer, temppasswd, tempsize );
+ CryptPassword( ( INT16 ) DECRYPT, ENC_ALGOR_3, (INT8_PTR)temppasswdbuffer, tempsize );
+ tempsize *= sizeof( CHAR );
+ dummysize = (INT)tempsize ;
+ mapAnsiToUnicNoNull( ( ACHAR_PTR )temppasswdbuffer, ( WCHAR_PTR )buffer, ( INT )(tempsize / sizeof( CHAR ) ), &dummysize ) ;
+ tempsize = (INT16)dummysize;
+ if ( ( *temppasswdbuffer & 0xff ) == NTPASSWORDPREFIX ) {
+ *buffer = NTPASSWORDPREFIX;
+ }
+ free( temppasswdbuffer );
+ } else {
+ memcpy( buffer, temppasswd, tempsize );
+ CryptPassword( ( INT16 ) DECRYPT, ENC_ALGOR_3, (INT8_PTR)buffer, tempsize );
+ }
+#else
+ memcpy( buffer, temppasswd, tempsize );
+ CryptPassword( ( INT16 ) DECRYPT, ENC_ALGOR_3, (INT8_PTR)buffer, tempsize );
+#endif
+
+ if ( inputtapepasswdlength == tempsize ) {
+
+ if ( !memcmp( buffer, inputtapepasswd, tempsize ) ) {
+ retcode = TRUE;
+
+ } else {
+ retcode = FALSE;
+ }
+
+ } else {
+ retcode = FALSE;
+ }
+
+ if ( buffer ) free ( buffer );
+
+ return( retcode );
+}
+
+/***************************************************
+
+ Name: WhoPasswordedTape
+
+ Description: This routine will tell who passworded
+ the tape. Whether it was tape secured
+ by Nostradamous or passworded by Cayman or
+ if no password exist. A tape secured by
+ Nostradamous always has a prefix character
+ of NTPASSWORDPREFIX on the actual password.
+ All other will be considered non-Nostradamous.
+
+ Returns: NOSTRADAMOUS_APP - tape secured by Nostardamous
+ OTHER_APP - tape passworded by some other
+ application.
+ NO_APP - tape is NOT passworded or
+ secured by any application or
+ general error out condition.
+
+*****************************************************/
+INT16 WhoPasswordedTape ( INT8_PTR tape_password, // encrypted password
+ INT16 tape_password_size )
+{
+ CHAR_PTR buffer;
+
+
+ if ( !tape_password || tape_password_size <= 0) return( NO_APP );
+
+ buffer = ( CHAR_PTR )calloc(1, sizeof( CHAR ) * tape_password_size );
+ if ( !buffer ) return( NO_APP );
+
+ memcpy( buffer, tape_password, tape_password_size );
+
+ CryptPassword( ( INT16 ) DECRYPT, ENC_ALGOR_3, (INT8_PTR)buffer, ( INT16 ) ( tape_password_size ) );
+ if ( (*buffer & 0xff ) == NTPASSWORDPREFIX) {
+ free( buffer );
+ return( NOSTRADAMOUS_APP );
+ }
+
+ free( buffer );
+ return( OTHER_APP );
+}
+
+/**************************************************************************
+
+ Name: GetOriginalOwnerOfTape
+
+ Description: This routine will get the username from the first
+ tape and first set of the same family of tape from
+ the catalog information. If the first tape does
+ not exist the it will jsut return a NULL.
+
+
+ Returns: pointer to the username from the fisrt tape
+ first set from the tape family.
+
+ NULL - if the first tape does not exist.
+
+
+**************************************************************************/
+BOOLEAN GetOriginalOwnerOfTape( DBLK_PTR vcb_ptr,
+ CHAR_PTR user_name
+ )
+{
+ UINT32 tape_id;
+ QTC_TAPE_PTR tape;
+ QTC_BSET_PTR bset;
+ INT done = 0;
+ INT found = 0;
+ QTC_HEADER_PTR qtc_header;
+
+
+ // no vcb_ptr
+ if ( !vcb_ptr ) return( FALSE );
+
+ // get tape id from current vcb
+ tape_id = FS_ViewTapeIDInVCB( vcb_ptr );
+
+
+ tape = QTC_GetFirstTape( );
+
+ while ( tape != NULL && ! done ) {
+
+ if ( ( tape->tape_fid == tape_id ) ) {
+
+ bset = QTC_GetFirstBset( tape );
+
+ // There must be a bset from this tape.
+
+ if ( bset != NULL ) {
+
+ qtc_header = QTC_LoadHeader( bset );
+ if ( qtc_header ) {
+ strcpy( user_name, qtc_header->user_name );
+ free( qtc_header );
+ return( TRUE );
+ }
+ } else {
+
+ return( FALSE ); // no first set found on the tape
+ }
+
+ }
+
+ tape = QTC_GetNextTape( tape );
+ }
+
+ return( FALSE ); // no tape found
+
+}
+/*****************************************************************************
+
+ Name: UI_AddSpecialIncOrExc
+
+ Description: Abort current operation at the end of the current file.
+
+ Returns: SUCCESS
+
+*****************************************************************************/
+VOID UI_AddSpecialIncOrExc( BSD_PTR bsd, BOOLEAN IsInclude )
+{
+ INT index = 0;
+ CHAR *name;
+ LONG ret;
+ ULONG ulOptions = 0L ;
+ HKEY key2;
+ REGSAM samDesired = KEY_QUERY_VALUE;
+ CHAR data[ 512 ];
+ CHAR ValueKey[ 512 ];
+ INT value_size;
+ INT data_size;
+ FSE_PTR fse ;
+ INT16 dir_size ;
+ CHAR_PTR p;
+ CHAR_PTR q;
+ CHAR log_name[256] ;
+
+ ret = GetEnvironmentVariable( TEXT("SystemRoot"), &data, 256 ) ;
+
+ if ( ret && IsInclude ) {
+ strcat( data, TEXT("\\profiles") ) ;
+ p = strchr( data, TEXT('\\') ) ;
+ if ( p == NULL ) {
+ p = data ;
+ } else {
+ p++ ;
+ }
+ dir_size = strsize( p ) ;
+ q = p ;
+ while (*q ) {
+ if (*q == TEXT('\\') ) {
+ *q = 0;
+ }
+ q++ ;
+ }
+ if ( SUCCESS == BSD_CreatFSE ( &fse,
+ (IsInclude?INCLUDE:EXCLUDE),
+ p,
+ dir_size,
+ TEXT("*") ,
+ 2 * sizeof(CHAR),
+ TRUE,
+ TRUE ) ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+ }
+
+
+ ret = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+ TEXT("system\\currentcontrolset\\control\\hivelist"),
+ ulOptions, samDesired, &key2 ) ;
+
+ if ( ret ) {
+ return ;
+ }
+
+ do {
+
+ value_size = 512 ;
+ data_size = 512 ;
+
+ ret = RegEnumValue( key2,
+ index,
+ ValueKey,
+ (LPDWORD)&value_size,
+ NULL,
+ NULL,
+ (LPBYTE)
+ data,
+ (LPDWORD)&data_size );
+
+ if ( ! ret ) {
+
+ // separate file name from end of data.
+
+ data_size /= sizeof(CHAR);
+
+ data[ data_size ] = 0;
+
+ while ( ( data[ data_size ] != TEXT( '\\' ) ) && data_size )
+ {
+ data_size--;
+ }
+
+ if ( data_size )
+ {
+ name = &data[ data_size + 1 ];
+ data[data_size] = 0 ;
+ p = strchr( data, TEXT('\\') ) ;
+ if ( p ) {
+ p = strchr( p+1, TEXT('\\') ) ;
+ }
+ if ( p ) {
+ p = strchr( p+1, TEXT('\\') ) ;
+ }
+ if ( p ) {
+ p = strchr( p+1, TEXT('\\') ) ;
+ }
+ if ( p ) {
+ q = p + 1 ;
+ dir_size = strsize( q ) ;
+ while (*q ) {
+ if (*q == TEXT('\\') ) {
+ *q = 0;
+ }
+ q++ ;
+ }
+ if ( SUCCESS == BSD_CreatFSE ( &fse,
+ (IsInclude?INCLUDE:EXCLUDE),
+ p+1,
+ dir_size,
+ name,
+ strsize( name ),
+ FALSE,
+ FALSE ) ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+ strcpy( log_name, name ) ;
+ strcat( log_name, TEXT(".LOG") ) ;
+
+ if ( SUCCESS == BSD_CreatFSE ( &fse,
+ EXCLUDE,
+ p+1,
+ dir_size,
+ log_name,
+ strsize( log_name ),
+ FALSE,
+ FALSE ) ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+
+ strcpy( log_name, name ) ;
+ strcat( log_name, TEXT(".ALT") ) ;
+ if ( SUCCESS == BSD_CreatFSE ( &fse,
+ EXCLUDE,
+ p+1,
+ dir_size,
+ log_name,
+ strsize( log_name ),
+ FALSE,
+ FALSE ) ) {
+ BSD_AddFSE( bsd, fse ) ;
+ }
+ }
+
+
+ }
+ }
+
+ index++;
+
+ } while ( ! ret );
+
+ RegCloseKey( key2 );
+
+}
+
diff --git a/private/utils/ntbackup/src/do_next.c b/private/utils/ntbackup/src/do_next.c
new file mode 100644
index 000000000..6cc58cf83
--- /dev/null
+++ b/private/utils/ntbackup/src/do_next.c
@@ -0,0 +1,427 @@
+
+/******************************************************************************
+
+ Unit: Tape
+
+ Name: do_next.c
+
+ Description: This module contains the functions which perform the
+ next set search operation.
+
+ Copyright: (c) Maynard Electronics, Inc. 1984-92
+
+ $Log: G:/UI/LOGFILES/DO_NEXT.C_V $
+
+ Rev 1.17 20 Oct 1992 15:46:54 MIKEP
+gbCurrentOperation
+
+ Rev 1.16 07 Oct 1992 14:49:34 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.15 04 Oct 1992 19:34:16 DAVEV
+Unicode Awk pass
+
+ Rev 1.14 03 Sep 1992 13:30:38 MIKEP
+turn off polldrive
+
+ Rev 1.12.1.1 02 Sep 1992 20:13:02 MIKEP
+turn polldrive off and back on if microsoft
+
+ Rev 1.13 16 Jun 1992 16:02:04 MIKEP
+remove no more bsets msg for NT
+
+ Rev 1.12 02 Jun 1992 08:08:24 MIKEP
+remove no more tape msg
+
+ Rev 1.11 28 May 1992 10:10:14 MIKEP
+fix return type
+
+ Rev 1.10 19 May 1992 13:01:16 MIKEP
+mips changes
+
+ Rev 1.9 14 May 1992 17:39:04 MIKEP
+nt pass 2
+
+ Rev 1.8 11 May 1992 21:15:50 MIKEP
+catalog haandle based
+
+ Rev 1.7 27 Apr 1992 16:14:50 CHUCKB
+Fixed error message.
+
+ Rev 1.6 09 Apr 1992 08:47:42 MIKEP
+speed up lots of sets
+
+ Rev 1.5 21 Feb 1992 16:17:52 CARLS
+change to TF_IDLE_NOBREAK
+
+ Rev 1.4 29 Jan 1992 18:02:30 DAVEV
+
+
+ * No changes
+
+ Rev 1.3 16 Jan 1992 13:27:08 DAVEV
+16/32 bit port-2nd pass
+
+ Rev 1.2 16 Dec 1991 12:35:58 CARLS
+added <windows.h>
+
+ Rev 1.1 09 Dec 1991 16:39:02 JOHNWT
+the real initial revision
+
+ Rev 1.0 05 Dec 1991 16:11:46 STEVEN
+Initial revision.
+
+******************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+static UINT16 NextSet_TPos( UINT16, TPOS_PTR, BOOLEAN, DBLK_PTR, UINT16 );
+static INT16 NextSet_MsgHandler( UINT16, INT32, BSD_PTR, FSYS_HAND, TPOS_PTR, ... );
+
+static QTC_BUILD_PTR mw_qtc_ptr;
+
+INT16 mw_bset_found_flag; /* static flag to maintain result */
+
+
+/******************************************************************************
+ *
+ * Unit: Tape
+ *
+ * Name: do_nextset
+ *
+ * Modified: 12/09/91
+ *
+ * Description: This function calls LP_List_Tape_Engine to look for an
+ * unknown (uncataloged) backup set. It first gets the
+ * current vcb from poll drive. It then locates the first
+ * unknown/missing backup set number and calls the engine
+ * to position to the vcb.
+ *
+ * Notes: Requires poll drive.
+ *
+ * Returns: SUCCESS - an unknown vcb was located and added to the cats
+ * FAILURE - EOD encountered or error
+ *
+ * Global Data: gb_abort_flag
+ *
+ *****************************************************************************/
+
+INT do_nextset( VOID )
+{
+ LIS lis; /* lis structure for list eng */
+ BSD_HAND temp_bsd_list; /* pointer to our bsd list */
+ BE_CFG_PTR bec_cfg_ptr; /* pointer to our copy of the config */
+ DBLK_PTR vcb_ptr; /* ptr to vcb that poll drive rets */
+ QTC_BSET_PTR bset_ptr; /* used in search of QTC catalogs */
+ INT16 find_bset_num; /* first unknown bset number */
+
+
+ /* if poll drive does not know what tape is in the drive, we exit */
+
+ if ( VLM_GetDriveStatus( &vcb_ptr ) != VLM_VALID_TAPE ) {
+ return FAILURE;
+ }
+
+ /* We want to find the first unknown bset after the current vcb. We
+ loop until we find one that is not in the catalogs. We check the
+ bsets along the way to see if they are split which would mean there
+ are no more bsets on the tape. If poll drive knows what tape is
+ in the drive, we can assume that it is in the catalogs. */
+
+ find_bset_num = FS_ViewBSNumInVCB( vcb_ptr );
+
+ while ( ( bset_ptr = QTC_FindBset( FS_ViewTapeIDInVCB( vcb_ptr ),
+ FS_ViewTSNumInVCB( vcb_ptr ),
+ find_bset_num ) ) != NULL ) {
+
+ if ( bset_ptr->status & QTC_SPLIT ) {
+
+#ifndef OEM_MSOFT
+ WM_MessageBox( ID( IDS_MSGTITLE_NEXT ),
+ ID( RES_NO_MORE_TAPE_INFO ),
+ WMMB_OK, WMMB_ICONINFORMATION, NULL, 0, 0 );
+#endif
+
+ return FAILURE;
+ }
+
+ find_bset_num++;
+
+ }
+
+ gbCurrentOperation = OPERATION_NEXTSET;
+
+ PD_StopPolling();
+
+#ifdef OEM_MSOFT
+ do {
+#endif
+
+ mw_bset_found_flag = FAILURE;
+
+ /* we now set up for our call to the backup engine */
+
+ temp_bsd_list = (BSD_HAND)malloc( sizeof(BSD_LIST) );
+ if ( temp_bsd_list == NULL ) {
+ gbCurrentOperation = OPERATION_NEXTSET;
+ return FAILURE;
+ }
+
+ InitQueue( &(temp_bsd_list->current_q_hdr) );
+ InitQueue( &(temp_bsd_list->last_q_hdr) );
+
+ /* each bsd has its own config so we make a copy and then unlock it
+ so it will be free'ed when we free the bsd */
+
+ bec_cfg_ptr = BEC_CloneConfig( CDS_GetPermBEC() );
+ BEC_UnLockConfig( bec_cfg_ptr );
+
+ if ( BSD_Add( temp_bsd_list, &lis.curr_bsd_ptr, bec_cfg_ptr,
+ NULL, NULL, FS_ViewTapeIDInVCB( vcb_ptr ),
+ FS_ViewTSNumInVCB( vcb_ptr ), find_bset_num,
+ thw_list, NULL ) != SUCCESS ) {
+
+ free( temp_bsd_list );
+ BEC_ReleaseConfig( bec_cfg_ptr );
+ gbCurrentOperation = OPERATION_NEXTSET;
+ return FAILURE;
+ }
+
+ BSD_SetTapePos( lis.curr_bsd_ptr, FS_ViewTapeIDInVCB( vcb_ptr ),
+ FS_ViewTSNumInVCB( vcb_ptr ), find_bset_num );
+
+ /* set up the lis structure */
+
+ lis.bsd_list = temp_bsd_list; /* set bsd list */
+ lis.tape_pos_handler = NextSet_TPos; /* set tape positioner to call */
+ lis.message_handler = NextSet_MsgHandler; /* set message handler to call */
+ lis.oper_type = TDIR_OPER; /* set operation type */
+ lis.abort_flag_ptr = &gb_abort_flag; /* set abort flag address */
+ lis.auto_det_sdrv = TRUE;
+
+ LP_SetAbortFlag( &lis, CONTINUE_PROCESSING );
+
+ /* stop poll drive and call the list engine to look for the bset */
+
+ mw_bset_found_flag = FAILURE;
+
+ LP_List_Tape_Engine( &lis );
+
+ /* free our allocated memory */
+
+ BSD_Remove( lis.curr_bsd_ptr );
+ free( temp_bsd_list );
+
+ find_bset_num++;
+
+#ifdef OEM_MSOFT
+ } while ( mw_bset_found_flag == SUCCESS );
+#endif
+
+ PD_StartPolling();
+
+ gbCurrentOperation = OPERATION_NEXTSET;
+ return( mw_bset_found_flag );
+}
+
+
+/******************************************************************************
+ *
+ * Unit: Tape
+ *
+ * Name: NextSet_TPos
+ *
+ * Modified: 12/8/91
+ *
+ * Description: This is a simple tape positioner message handler. It
+ * adds the bset to the cats if the requested vcb is found,
+ * tells the user there is no more data, or displays an
+ * error message.
+ *
+ * Notes:
+ *
+ * Returns: Defined in tpos.h
+ *
+ * Global Data: none
+ *
+ *****************************************************************************/
+
+static UINT16 NextSet_TPos(
+UINT16 message,
+TPOS_PTR tpos,
+BOOLEAN curr_valid_vcb,
+DBLK_PTR cur_vcb,
+UINT16 mode )
+{
+ UINT16 response = UI_ACKNOWLEDGED;
+
+ DBG_UNREFERENCED_PARAMETER ( tpos );
+ DBG_UNREFERENCED_PARAMETER ( curr_valid_vcb );
+ DBG_UNREFERENCED_PARAMETER ( mode );
+
+ if ( UI_CheckUserAbort( message ) ) {
+ return UI_ABORT_POSITIONING;
+ }
+
+ switch( message ) {
+
+ CHAR_PTR drive_name;
+ TCHAR szErrorMsg[MAX_UI_RESOURCE_SIZE] ;
+
+ case TF_REQUESTED_VCB_FOUND:
+
+ /* The unknown bset has been located! Add it to the catalogs as
+ a partial bset and happily abort. */
+
+ mw_qtc_ptr = QTC_GetBuildHandle( );
+ QTC_DoFullCataloging( mw_qtc_ptr, FALSE );
+ QTC_StartBackup( mw_qtc_ptr, cur_vcb );
+ QTC_FreeBuildHandle( mw_qtc_ptr );
+ mw_qtc_ptr = NULL;
+
+ VLM_AddBset( FS_ViewTapeIDInVCB( cur_vcb ),
+ FS_ViewTSNumInVCB( cur_vcb ),
+ FS_ViewBSNumInVCB( cur_vcb ), NULL, TRUE );
+
+ mw_bset_found_flag = SUCCESS;
+
+ response = UI_HAPPY_ABORT;
+
+ break;
+
+ case TF_VCB_EOD:
+ case TF_NEED_NEW_TAPE:
+ case TF_NO_MORE_DATA:
+
+ /* nothing else on the tape, sorry dude */
+#ifndef OEM_MSOFT
+ WM_MessageBox( ID( IDS_MSGTITLE_NEXT ),
+ ID( RES_NO_MORE_TAPE_INFO ),
+ WMMB_OK, WMMB_ICONINFORMATION, NULL, 0, 0 );
+#endif
+
+ response = UI_HAPPY_ABORT;
+
+ break;
+
+ case TF_VCB_BOT:
+ case TF_ACCIDENTAL_VCB:
+ case TF_POSITIONED_AT_A_VCB:
+ response = UI_CONTINUE_POSITIONING;
+ break;
+
+ case TF_WRONG_TAPE:
+ case TF_INVALID_VCB:
+ case TF_EMPTY_TAPE:
+ case TF_READ_ERROR:
+ case TF_NO_TAPE_PRESENT:
+
+ /* get a pointer to the name of the current tape device */
+ drive_name = BE_GetCurrentDeviceName( tpos->channel );
+
+ /* put the drive name in the error message */
+ RSM_Sprintf( szErrorMsg, ID( RES_FATAL_TAPE_READ_ERR ), drive_name ) ;
+
+ /* display generic error message */
+
+ WM_MessageBox( ID( IDS_MSGTITLE_NEXT ),
+ szErrorMsg,
+ WMMB_OK, WMMB_ICONEXCLAMATION, NULL, 0, 0 );
+
+ response = UI_HAPPY_ABORT;
+
+ break;
+
+ case TF_IDLE_NOBREAK:
+ case TF_SEARCHING:
+ case TF_REWINDING:
+ case TF_DRIVE_BUSY:
+ case TF_IDLE:
+ case TF_SKIPPING_DATA:
+ case TF_MOUNTING:
+ break;
+
+ default:
+ eresprintf( RES_UNKNOWN_TF_MSG, message );
+ response = UI_ABORT_POSITIONING;
+ break;
+ }
+
+ return( response );
+}
+
+
+/******************************************************************************
+ *
+ * Unit: Tape
+ *
+ * Name: NextSet_MsgHandler
+ *
+ * Modified: 12/8/91
+ *
+ * Description: Message handler for the list engine. It displays any
+ * error messages and ignores all others.
+ *
+ * Notes:
+ *
+ * Returns: defined in lp_msg.h
+ *
+ * Global Data: none
+ *
+ *****************************************************************************/
+
+static INT16 NextSet_MsgHandler(
+UINT16 msg,
+INT32 pid,
+BSD_PTR bsd_ptr,
+FSYS_HAND fsh,
+TPOS_PTR tpos,
+... )
+{
+ va_list arg_ptr;
+ INT16 response = MSG_ACK;
+ static INT16 error;
+
+ DBG_UNREFERENCED_PARAMETER ( pid );
+ DBG_UNREFERENCED_PARAMETER ( bsd_ptr );
+ DBG_UNREFERENCED_PARAMETER ( fsh );
+
+ va_start( arg_ptr, tpos );
+
+ switch( msg ) {
+
+ case MSG_TBE_ERROR:
+
+ error = va_arg( arg_ptr, INT16 );
+ UI_ProcessErrorCode( error, &response, tpos->channel );
+ break;
+
+ case MSG_START_BACKUP_SET:
+ case MSG_START_OPERATION:
+ case MSG_END_OPERATION:
+ case MSG_LOG_BLOCK:
+ case MSG_END_BACKUP_SET:
+ case MSG_STOP_CLOCK:
+ case MSG_START_CLOCK:
+ case MSG_EOM:
+ case MSG_IDLE:
+ case MSG_BLOCK_BAD:
+ case MSG_BYTES_BAD:
+ case MSG_BLOCK_DELETED:
+ case MSG_BYTES_DELETED:
+ case MSG_TAPE_STATS:
+ case MSG_BLK_NOT_FOUND:
+ case MSG_BLK_DIFFERENT:
+ case MSG_LOG_DIFFERENCE:
+ break;
+
+ default:
+ eresprintf( RES_UNKNOWN_MSG_HNDLR_MSG, msg );
+ break;
+ }
+ return( response );
+}
diff --git a/private/utils/ntbackup/src/do_rest.c b/private/utils/ntbackup/src/do_rest.c
new file mode 100644
index 000000000..521ce4276
--- /dev/null
+++ b/private/utils/ntbackup/src/do_rest.c
@@ -0,0 +1,2438 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: do_rest.c
+
+ Description: Tape restore tape positioning and message handler
+
+ $Log: J:/UI/LOGFILES/DO_REST.C_V $
+
+ Rev 1.96.1.12 24 May 1994 20:10:52 GREGG
+Improved handling of ECC, SQL, FUTURE_VER and OUT_OF_SEQUENCE tapes.
+
+ Rev 1.96.1.11 04 May 1994 15:00:50 STEVEN
+fix dlt settling time
+
+ Rev 1.96.1.10 21 Apr 1994 10:34:26 GREGG
+Fixed memory leak.
+
+ Rev 1.96.1.9 04 Mar 1994 16:55:32 STEVEN
+prompt if disk full
+
+ Rev 1.96.1.8 23 Feb 1994 12:51:48 STEVEN
+remove corrupt.lst support from ntbackup
+
+ Rev 1.96.1.7 01 Feb 1994 19:18:44 ZEIR
+tuned tape settling logic for initial no_tape_in_drive situations
+
+ Rev 1.96.1.6 19 Jan 1994 10:57:40 MIKEP
+change happy_abort to abort_positioning to fix abort
+
+ Rev 1.96.1.5 13 Jan 1994 18:14:28 STEVEN
+fix directory count
+
+ Rev 1.96.1.4 27 Dec 1993 14:53:30 STEVEN
+counted root twice
+
+ Rev 1.96.1.3 14 Dec 1993 12:10:02 BARRY
+Don't write to gszTprintfBuffer, use yprintf
+
+ Rev 1.96.1.2 03 Dec 1993 02:07:30 GREGG
+Put back changes from lost rev 1.96.
+
+ Rev 1.96.1.1 02 Dec 1993 12:50:28 STEVEN
+Fixed number of directories processed bug.
+
+ Rev 1.96.1.0 05 Nov 1993 08:23:36 STEVEN
+fix clock over 1 hour
+
+ Rev 1.0 05 Nov 1993 08:23:18 STEVEN
+fix clock over 1 hour
+
+ Rev 1.95 15 Sep 1993 13:52:36 CARLS
+changes for displaying full path/file name detail if Log files
+
+ Rev 1.94 25 Jul 1993 12:55:18 MIKEP
+fix display of destination volume in runtime
+
+ Rev 1.93 22 Jul 1993 18:36:00 KEVINS
+Corrected macro name.
+
+ Rev 1.92 22 Jul 1993 18:29:22 KEVINS
+Added support for tape drive settling time.
+
+ Rev 1.91 19 Jul 1993 10:15:50 BARRY
+Don't reference dle in BSD directly -- use BSD_GetDLE instead.
+
+ Rev 1.90 12 Jul 1993 09:19:14 KEVINS
+Added support for status monitor.
+
+ Rev 1.89 23 Jun 1993 16:22:58 CARLS
+moved PROMPT_RESTORE_OVER_RECENT to display the confirm file replace dialog
+
+ Rev 1.88 18 Jun 1993 16:49:48 CARLS
+added NtDemoChangeTape calls for NtDemo
+
+ Rev 1.87 14 Jun 1993 20:23:56 MIKEP
+enable c++
+
+ Rev 1.86 07 Jun 1993 08:20:32 MIKEP
+fix warnings.
+
+ Rev 1.85 03 Jun 1993 14:31:02 DARRYLP
+Removed excess \ from backup and restore directory field upon abort
+
+ Rev 1.84 18 May 1993 14:34:18 DARRYLP
+Backed out my previous changes.
+
+ Rev 1.83 18 May 1993 12:07:44 GREGG
+Fix for EPR# 294-0419: Starting restore on continuation tape, files before
+first new DDB are restored to the root.
+
+ Rev 1.82 18 May 1993 12:04:12 DARRYLP
+Added line to update the status field with number of bytes processed for
+the operation.
+
+ Rev 1.81 14 May 1993 15:31:02 CHUCKB
+Added notification for restoring active registry files.
+
+ Rev 1.80 14 May 1993 14:40:30 DARRYLP
+Modified event logging text
+
+ Rev 1.79 10 May 1993 16:38:16 chrish
+NOSTRADAMUS EPR 0400 and 0172 - Did not catch the fixes in the verify and
+restore process of the backup app. When spanning tape it gave the user
+wrong message to wait for tape to rewind, when it had already completed
+rewinding. Corrected by display proper message to user.
+
+ Rev 1.78 18 Apr 1993 16:23:52 BARRY
+Don't use 'free' on buffers allocated with UI_AllocPathBuffer.
+
+ Rev 1.77 15 Apr 1993 15:33:16 CARLS
+added fix for abort when skipping files
+
+ Rev 1.76 13 Apr 1993 12:51:34 BARRY
+Don't do verify after on a happy abort.
+
+ Rev 1.75 02 Apr 1993 15:48:36 CARLS
+changes for DC2000 unformatted tape
+
+ Rev 1.74 09 Mar 1993 10:57:42 MIKEP
+update clock stats at end of set
+
+ Rev 1.73 07 Mar 1993 16:33:08 GREGG
+Call _sleep for OS_WIN32 only.
+
+ Rev 1.72 02 Mar 1993 12:36:10 CARLS
+fixed problem with confirm file replace
+
+ Rev 1.71 17 Feb 1993 10:39:26 STEVEN
+changes from mikep
+
+ Rev 1.70 10 Feb 1993 12:16:36 chrish
+Changes in msg_hndlr routine for display proper info during restore process.
+
+ Rev 1.69 09 Feb 1993 09:44:22 chrish
+Added logic for aborting during a restore process. This is identical to
+how the ctrl break handling for aborting during a backup. A file will be
+allowed to be completely restore before aborting.
+
+
+ Rev 1.68 01 Feb 1993 19:54:50 STEVEN
+bug fixes
+
+ Rev 1.67 27 Jan 1993 14:32:52 STEVEN
+handle MSG_CONT_VCB message
+
+ Rev 1.66 18 Jan 1993 16:05:42 STEVEN
+add support for stream id error message
+
+ Rev 1.65 08 Jan 1993 14:31:12 chrish
+Deleted one line ... (... //chs)
+
+ Rev 1.64 30 Dec 1992 14:12:56 STEVEN
+we did not display file name when we skipped file
+
+ Rev 1.63 23 Dec 1992 14:43:16 chrish
+Focus on Abort & restore log file added drive info
+
+ Rev 1.62 22 Dec 1992 14:19:20 MIKEP
+tab removal
+
+ Rev 1.61 22 Dec 1992 08:48:48 MIKEP
+changes from msoft
+
+ Rev 1.60 11 Nov 1992 16:31:08 DAVEV
+UNICODE: remove compile warnings
+
+ Rev 1.59 05 Nov 1992 17:02:34 DAVEV
+fix ts
+
+ Rev 1.57 20 Oct 1992 17:01:12 MIKEP
+getstatus calls
+
+ Rev 1.56 20 Oct 1992 15:44:10 MIKEP
+gbCurrentOperation
+
+ Rev 1.55 19 Oct 1992 14:34:28 STEVEN
+no more remaining size
+
+ Rev 1.54 07 Oct 1992 14:46:28 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.53 04 Oct 1992 19:34:24 DAVEV
+Unicode Awk pass
+
+ Rev 1.52 17 Sep 1992 17:40:10 DAVEV
+minor fix (strsiz->strsize)
+
+ Rev 1.51 17 Sep 1992 15:52:02 DAVEV
+UNICODE modifications: strlen usage check
+
+ Rev 1.50 24 Aug 1992 15:22:54 DAVEV
+NT Event Logging
+
+ Rev 1.49 27 Jul 1992 14:48:54 JOHNWT
+ChuckB fixed references for NT.
+
+ Rev 1.48 27 Jul 1992 11:10:00 JOHNWT
+ChuckB checked in for John Wright, who is no longer with us.
+
+ Rev 1.47 07 Jul 1992 16:03:22 MIKEP
+unicode changes
+
+ Rev 1.46 25 Jun 1992 14:17:32 STEVEN
+restore prompt did not specify path
+
+ Rev 1.45 10 Jun 1992 17:07:58 DAVEV
+Fixed file 2 name in message box (was date carried intemp buffer)
+
+ Rev 1.44 10 Jun 1992 09:34:32 BURT
+Fixed funcs to ANSI arg list
+
+ Rev 1.43 29 May 1992 10:14:36 MIKEP
+total to display change
+
+ Rev 1.42 28 May 1992 10:07:56 MIKEP
+fix return type
+
+ Rev 1.41 26 May 1992 10:30:54 MIKEP
+loop fixes
+
+ Rev 1.40 19 May 1992 13:01:24 MIKEP
+mips changes
+
+ Rev 1.39 14 May 1992 17:38:52 MIKEP
+nt pass 2
+
+ Rev 1.38 11 May 1992 19:31:40 STEVEN
+64bit and large path sizes
+
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+static UINT16 tpos_rout( UINT16 message, TPOS_PTR tpos, BOOLEAN curr_vcb_valid, DBLK_PTR cur_vcb, UINT16 mode );
+static INT16 msg_hndlr( UINT16 msg, INT32 pid, BSD_PTR bsd_ptr, FSYS_HAND fsh, TPOS_PTR tpos, ... );
+static BOOLEAN CorruptLSTFound( VOID );
+static VOID clock_routine( VOID );
+static VOID do_restore_init( VOID );
+static VOID do_restore_process( VOID );
+static INT16 PromptNextTape( TPOS_PTR, DBLK_PTR, BOOLEAN, UINT16, CHAR_PTR, CHAR_PTR );
+
+static BOOLEAN clock_ready_flag;
+static BOOLEAN restored_active_flag;
+static HTIMER timer_handle;
+static STATS op_stats;
+static FILE_REPLACE_TEMP_PTR mw_file_replace_ptr;
+static INT mw_oper_type;
+static INT16 mw_ret_val;
+static INT mw_rewind;
+static CHAR mwCurrentDrive[ 512 ]; // chs:02-08-93
+static CHAR mwCurrentPath[ 512 ]; // chs:02-08-93
+static CHAR mwCurrentFile[ 512 ]; // chs:02-08-93
+
+#ifdef OEM_EMS
+extern INT32 RT_BSD_OsId ;
+#endif
+
+#ifdef OS_WIN32
+static UINT16 mwTapeSettlingCount,
+ tape_retries;
+static BOOL mwErrorDuringBackupSet = FALSE;
+#endif
+
+
+INT16 TryToCreateFFRQueue( LIS_PTR, INT16 );
+
+
+/*****************************************************************************
+
+ Name: do_restore
+
+ Description: Main entry point for tape restore functions that
+ performs initialization and displays the runtime
+ dialog.
+
+ Returns: SUCCESS
+ ABNORMAL_TERMINATION
+
+ Notes: mw_ret_val is set in do_restore_process
+
+*****************************************************************************/
+
+INT do_restore( INT16 oper_type )
+{
+ mw_ret_val = SUCCESS;
+ mw_oper_type = oper_type;
+ mw_rewind = TRUE;
+
+ gbAbortAtEOF = FALSE;
+ gbCurrentOperation = OPERATION_RESTORE;
+ SetStatusBlock(IDSM_OPERATIONSTATUS, STAT_OPER_RESTORE);
+
+#ifdef OS_WIN32
+ /* we will check for tape every 3 seconds, but prompt user by interval
+ specified in INI file */
+ mwTapeSettlingCount = CDS_GetTapeDriveSettlingTime ( CDS_GetPerm () ) / 3;
+
+ if ( CDS_GetTapeDriveName( CDS_GetPerm( ) ) ) {
+
+ CHAR DriveName[80] ;
+
+ strncpy( DriveName, (CHAR_PTR)CDS_GetTapeDriveName( CDS_GetPerm( ) ), 80 ) ;
+ DriveName[79] = '\0' ;
+ strlwr( DriveName ) ;
+ if( strstr( DriveName, TEXT( "cipher" ) ) != NULL ||
+ ( strstr( DriveName, TEXT( "dec" ) ) != NULL &&
+ ( strstr( DriveName, TEXT( "thz02" ) ) != NULL ||
+ strstr( DriveName, TEXT( "tz86" ) ) != NULL ||
+ strstr( DriveName, TEXT( "tz87" ) ) != NULL ||
+ strstr( DriveName, TEXT( "dlt2700" ) ) != NULL ||
+ strstr( DriveName, TEXT( "dlt2000" ) ) != NULL ) ) ) {
+ mwTapeSettlingCount *= 2 ;
+ }
+ }
+
+ tape_retries = 0 ;
+#endif
+
+ /* collect the target drives and paths for restore */
+ /* display the target restore dialog */
+ if ( DM_StartRestoreBackupSet() ) {
+
+ /* user canceled the operation */
+ mw_ret_val = ABORT_OPERATION;
+
+ } else {
+
+ /* display warning for corrupt file if found, exit if user requests */
+// this functionality has been removed.
+
+// if ( LogFileExists( CORRUPT_FILE ) ) {
+//
+// if ( ! WM_MessageBox( ID( IDS_MSGTITLE_CORRUPT ),
+// ID( RES_CORRUPT_RESTORE_WARNING ),
+// WMMB_YESNO,
+// WMMB_ICONQUESTION,
+// ID( RES_CONTINUE_QUEST ), 0, 0 ) ) {
+//
+// mw_ret_val = ABORT_OPERATION;
+// }
+// }
+ }
+
+ if( mw_ret_val == SUCCESS ) {
+
+ do_restore_init();
+ do_restore_process();
+ if ( restored_active_flag ) {
+
+ WM_MsgBox( ID(IDS_APPNAME), ID(RES_ACTIVE_FILES_RESTORED),
+ WMMB_OK, WMMB_ICONINFORMATION ) ;
+ }
+ }
+
+ gbCurrentOperation = OPERATION_NONE;
+ SetStatusBlock(IDSM_OPERATIONSTATUS, STAT_OPER_IDLE);
+ return( mw_ret_val );
+}
+
+
+/*****************************************************************************
+
+ Name: do_restore_init
+
+ Description: Initializes the text on the runtime dialog.
+
+ Returns: none.
+
+*****************************************************************************/
+
+VOID do_restore_init ( VOID )
+{
+ VLM_CloseAll();
+
+ // create the Runtime status dialog
+ JobStatusBackupRestore( JOB_STATUS_CREATE_DIALOG );
+
+ // display the restore title for the dialog
+ yresprintf( (INT16) IDS_DLGTITLEJOBSTATRESTORE );
+ JobStatusBackupRestore( JOB_STATUS_RESTORE_TITLE );
+
+ // display "Set information n of n "
+ JobStatusBackupRestore( JOB_STATUS_N_OF_N );
+
+ // display the volume tape bitmap
+ JobStatusBackupRestore( JOB_STATUS_VOLUME_TAPE );
+
+ yresprintf( (INT16) RES_TITLE_NEW_LINE );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ // display the Restore status title in the list box
+ yresprintf( (INT16) IDS_DLGTITLEJOBSTATRESTORE );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ yresprintf( (INT16) RES_TITLE_NEW_LINE );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ // clear the number of bytes processed in the Runtime dialog
+ yprintf(TEXT("%d\r"),0 );
+ JobStatusBackupRestore( JOB_STATUS_BYTES_PROCESSED );
+
+ restored_active_flag = FALSE ;
+
+ return;
+}
+
+
+/*****************************************************************************
+
+ Name: do_restore_process
+
+ Description: Initializes and calls the restore engine. The verify
+ after operation is performed if needed.
+
+ Returns: none.
+
+ Notes: if error, mw_ret_val is set to ABNORMAL_TERMINATION
+
+*****************************************************************************/
+
+VOID do_restore_process( VOID )
+{
+ LIS lis;
+ BSD_PTR bsd_ptr;
+ INT16 ret_val;
+
+ UI_ExcludeInternalFiles( (INT16)mw_oper_type );
+
+ lis.curr_bsd_ptr = BSD_GetFirst( tape_bsd_list );
+ lis.tape_pos_handler = tpos_rout; /* set tape positioner to call */
+ lis.message_handler = msg_hndlr; /* set message handler to call */
+ lis.oper_type = (INT16)mw_oper_type; /* set operation type */
+ lis.abort_flag_ptr = &gb_abort_flag; /* set abort flag address */
+ lis.pid = 0L;
+ lis.auto_det_sdrv = FALSE;
+ lis.bsd_list = tape_bsd_list;
+ lis.vmem_hand = NULL ;
+
+ gb_last_operation = mw_oper_type;
+
+ LP_SetAbortFlag( &lis, CONTINUE_PROCESSING );
+
+ // pass the location of the abort flag to the Runtime status dialog
+ JobStatusAbort( lis.abort_flag_ptr );
+
+ /* enable the abort button for the runtime dialog */
+ JobStatusBackupRestore( JOB_STATUS_ABORT_ENABLE ) ;
+
+ TryToCreateFFRQueue( &lis, (INT16) RESTORE_OPER );
+
+ clock_ready_flag = FALSE; // Wait on bset to start
+
+ timer_handle = WM_HookTimer( clock_routine, 1 );
+
+ /* call restore engine */
+
+ PD_StopPolling();
+
+ mw_file_replace_ptr = (FILE_REPLACE_TEMP_PTR)malloc(sizeof(FILE_REPLACE_TEMP) );
+
+ ret_val = LP_Restore_Engine( &lis );
+
+ if ( ( ret_val != SUCCESS ) && ( ret_val != TFLE_UI_HAPPY_ABORT ) ) {
+ BSD_SetOperStatus( lis.curr_bsd_ptr, ABNORMAL_TERMINATION );
+ }
+
+ if(mw_file_replace_ptr) {
+ free(mw_file_replace_ptr);
+ }
+
+ PD_StartPolling();
+
+ WM_UnhookTimer( timer_handle );
+
+ /* set return value of success or failure of entire operation */
+
+ bsd_ptr = BSD_GetFirst( tape_bsd_list );
+
+ while( ( bsd_ptr != NULL ) && !mw_ret_val ) {
+
+ mw_ret_val = BSD_GetOperStatus( bsd_ptr );
+ bsd_ptr = BSD_GetNext( bsd_ptr );
+ }
+
+ /* Set up for verify after if necessary */
+
+ if ( (mw_ret_val == ABNORMAL_TERMINATION) ||
+ (ret_val == TFLE_UI_HAPPY_ABORT) ) {
+
+ /* Don't even bother with verify on an error or happy abort */
+ CDS_SetAutoVerifyRestore( CDS_GetCopy(), NO_VERIFY_AFTER );
+
+ if ( mw_ret_val == SUCCESS ) {
+ mw_ret_val = ret_val;
+ }
+
+ } else if ( CDS_GetAutoVerifyRestore( CDS_GetCopy() ) == PROMPT_VERIFY_AFTER ) {
+
+ if ( WM_MessageBox( ID( IDS_MSGTITLE_VERIFY ),
+ ID( RES_PROMPT_VERIFY_RESTORE ),
+ WMMB_YESNO,
+ WMMB_ICONQUESTION, NULL, 0, 0 ) ) {
+
+ CDS_SetAutoVerifyRestore( CDS_GetCopy(), DO_VERIFY_AFTER );
+ }
+ else {
+ CDS_SetAutoVerifyRestore( CDS_GetCopy(), NO_VERIFY_AFTER );
+ }
+ }
+
+ /* This call will disable the Runtime Abort button and */
+ /* enable the OK button */
+ JobStatusBackupRestore( JOB_STATUS_ABORT_OFF );
+
+ return;
+}
+
+
+/*****************************************************************************
+
+ Name: tpos_rout
+
+ Description: Tape positioning routine for Tape Restore functions called
+ from Tape Format
+
+ Returns:
+
+*****************************************************************************/
+static UINT16 tpos_rout(
+UINT16 message,
+TPOS_PTR tpos,
+BOOLEAN curr_vcb_valid,
+DBLK_PTR cur_vcb,
+UINT16 mode )
+{
+ UINT16 response = UI_ACKNOWLEDGED;
+ LIS_PTR lis_ptr = (LIS_PTR)tpos->reference;
+ BSD_PTR bsd_ptr = (BSD_PTR)lis_ptr->curr_bsd_ptr;
+ CHAR_PTR drive_name;
+ CHAR_PTR tape_name;
+ GENERIC_DLE_PTR dle_ptr = BSD_GetDLE( bsd_ptr );
+
+ /* get a pointer to the name of the current tape device */
+ drive_name = BE_GetCurrentDeviceName( tpos->channel );
+
+ JobStatusBackupRestore( JOB_STATUS_ABORT_CHECK );
+
+ /* Check for user abort */
+ if( UI_CheckUserAbort( message ) ) {
+ return UI_ABORT_POSITIONING ;
+ }
+
+ /* if we are positioned at the requested set, but on an uncataloged tape,
+ we want to dialog the user so make adjustments */
+
+ switch( message ) {
+
+ case TF_IDLE_NOBREAK:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ WM_MultiTask() ;
+ break;
+
+
+ case TF_IDLE:
+ case TF_SKIPPING_DATA:
+ case TF_MOUNTING:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ break;
+
+ case TF_REQUESTED_VCB_FOUND:
+ case TF_VCB_BOT:
+ case TF_POSITIONED_AT_A_VCB:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ mw_rewind = TRUE;
+ /* first check for read continuation */
+ if ( mode == TF_READ_CONTINUE ) {
+ response = UI_UpdateTpos( tpos, cur_vcb, FALSE );
+ break;
+ }
+
+ if ( message == TF_VCB_BOT ) {
+ if( FS_ViewTSNumInVCB( cur_vcb ) > 1 ) {
+ yresprintf( (INT16) RES_OUT_OF_SEQUENCE_WARNING,
+ FS_ViewTSNumInVCB( cur_vcb ) );
+ if ( ! WM_MessageBox( ID( IDS_MSGTITLE_CONTINUE ),
+ gszTprintfBuffer,
+ WMMB_YESNO,
+ WMMB_ICONQUESTION,
+ ID( RES_CONTINUE_QUEST ), 0, 0 ) ) {
+ response = UI_ReplaceTape( drive_name );
+#ifdef OS_WIN32
+ tape_retries = mwTapeSettlingCount ;
+#endif
+ break;
+ }
+ }
+ }
+
+ /* otherwise, display backup set info */
+ UI_DisplayVCB( cur_vcb );
+
+ /* have user validate tape password if necessary */
+ if( UI_CheckOldTapePassword( cur_vcb ) == UI_ABORT_POSITIONING ) {
+ response = UI_HAPPY_ABORT;
+ break;
+ }
+
+ response = UI_UpdateTpos( tpos, cur_vcb, FALSE );
+
+ break;
+
+ case TF_ACCIDENTAL_VCB:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ mw_rewind = TRUE;
+ UI_DisplayVCB( cur_vcb );
+
+ break;
+
+ case TF_VCB_EOD:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ mw_rewind = TRUE;
+ response = UI_ProcessVCBatEOD( tpos, drive_name );
+ break;
+
+ case TF_NEED_NEW_TAPE:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_NEEDTAPE);
+ mw_rewind = TRUE;
+ tape_name = UI_DisplayableTapeName( (CHAR_PTR)FS_ViewTapeNameInVCB( cur_vcb ),
+ FS_ViewBackupDateInVCB( cur_vcb ) );
+ response = PromptNextTape( tpos, cur_vcb, curr_vcb_valid,
+ mode, tape_name, drive_name );
+ break;
+
+ case TF_UNRECOGNIZED_MEDIA:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+ SetStatusBlock(IDSM_DRIVESTATUS, STAT_DRIVE_FOREIGN);
+
+ mw_rewind = TRUE;
+ yresprintf( (INT16) IDS_VLMUNFORMATEDTEXT ) ;
+ WM_MessageBox( ID( IDS_VLMUNFORMATEDTITLE ) ,
+ gszTprintfBuffer ,
+ WMMB_OK,
+ WMMB_ICONEXCLAMATION, NULL, 0, 0 ) ;
+
+ response = PromptNextTape( tpos, cur_vcb, curr_vcb_valid,
+ mode, NULL, drive_name );
+ break;
+
+ case TF_NO_TAPE_PRESENT:
+#ifdef OS_WIN32
+ if( tape_retries ){
+ Sleep( 3000 ) ;
+ response = UI_NEW_TAPE_INSERTED ;
+ --tape_retries ;
+ break ;
+ }
+ // NOTE: fall thru on implied else or !ifdef OS_WIN32
+#endif
+
+ case TF_EMPTY_TAPE:
+ case TF_INVALID_VCB:
+ case TF_WRONG_TAPE:
+ case TF_FUTURE_REV_MTF:
+ case TF_MTF_ECC_TAPE:
+ case TF_SQL_TAPE:
+ case TF_TAPE_OUT_OF_ORDER:
+
+ mw_rewind = TRUE;
+
+ SetStatusBlock(IDSM_DRIVESTATUS, STAT_DRIVE_EMPTY);
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_NEEDTAPE);
+
+ tape_name = UI_DisplayableTapeName( (LPSTR)BSD_GetTapeLabel( bsd_ptr ),
+ BSD_ViewDate( bsd_ptr ) );
+ response = PromptNextTape( tpos, cur_vcb, curr_vcb_valid,
+ mode, tape_name, drive_name );
+ break;
+
+ case TF_NO_MORE_DATA:
+ SetStatusBlock(IDSM_DRIVESTATUS, STAT_DRIVE_EMPTY);
+ mw_rewind = TRUE;
+ yresprintf( (INT16) RES_NO_MORE_TAPE_INFO );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ response = UI_HAPPY_ABORT;
+ break;
+
+ case TF_READ_ERROR:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+ mw_rewind = TRUE;
+ response = UI_HandleTapeReadError( drive_name );
+ break;
+
+ case TF_SEARCHING:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ mw_rewind = TRUE;
+ yresprintf( (INT16) RES_SEARCHING );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ break;
+
+ case TF_REWINDING:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ if ( mw_rewind ) {
+ mw_rewind = FALSE;
+ yresprintf( (INT16) RES_REWINDING );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ }
+ break;
+
+ case TF_DRIVE_BUSY:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ SetStatusBlock(IDSM_DRIVESTATUS, STAT_DRIVE_BUSY);
+ mw_rewind = TRUE;
+ yresprintf( (INT16) RES_WAITING );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ break;
+
+ default:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+ mw_rewind = TRUE;
+ eresprintf( RES_UNKNOWN_TF_MSG, message );
+ response = UI_ABORT_POSITIONING;
+ break;
+ }
+ return response;
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static VOID clock_routine( VOID )
+{
+ INT16 num_hours, num_min, num_seconds;
+ UINT64 num_bytes;
+ CHAR numeral[ 40 ];
+ BOOLEAN stat ;
+ static UINT64 total_bytes;
+
+ if ( clock_ready_flag && ( ST_BSIdleLevel( &op_stats ) == 0 ) ) {
+
+ num_bytes = ST_GetBSBytesProcessed ( &op_stats );
+
+ if ( !U64_EQ( num_bytes, total_bytes ) ) {
+ total_bytes = num_bytes;
+ U64_Litoa( num_bytes, numeral, (INT16) 10, &stat ) ;
+ UI_BuildNumeralWithCommas( numeral );
+ yprintf(TEXT("%s\r"),numeral );
+ JobStatusBackupRestore( JOB_STATUS_BYTES_PROCESSED );
+ }
+ WM_AnimateAppIcon ( IDM_OPERATIONSRESTORE, FALSE );
+
+ ST_EndBackupSet( &op_stats );
+
+ SetStatusBlock(IDSM_FILECOUNT, ST_GetBSFilesProcessed( &op_stats ));
+ SetStatusBlock(IDSM_DIRCOUNT, ST_GetBSDirsProcessed( &op_stats ));
+ SetStatusBlock(IDSM_CORRUPTFILECOUNT, ST_GetBSFilesBad( &op_stats ));
+ SetStatusBlock(IDSM_SKIPPEDFILECOUNT, ST_GetBSFilesSkipped( &op_stats ));
+ SetStatusBlock(IDSM_BYTECOUNTLO, U64_Lsw(num_bytes));
+ SetStatusBlock(IDSM_BYTECOUNTHI, U64_Msw(num_bytes));
+ SetStatusBlock(IDSM_ELAPSEDSECONDS, (ST_GetBSEndTime( &op_stats ) -
+ ST_GetBSStartTime( &op_stats ) -
+ op_stats.bs_stats.bs_total_idle));
+
+ num_hours = ST_GetBSElapsedHours( &op_stats );
+ num_min = ST_GetBSElapsedMinutes( &op_stats );
+ num_seconds = ST_GetBSElapsedSeconds( &op_stats );
+
+ if ( num_hours ) {
+
+ yprintf( TEXT("%d%c%2.2d%c%2.2d\r"), num_hours, UI_GetTimeSeparator(),
+ num_min, UI_GetTimeSeparator(), num_seconds );
+
+
+ }
+ else {
+
+ yprintf( TEXT("%2.2d%c%2.2d\r"), num_min, UI_GetTimeSeparator(), num_seconds );
+
+ }
+
+ JobStatusBackupRestore( JOB_STATUS_ELAPSED_TIME );
+ }
+}
+
+/*****************************************************************************
+
+ Name: msg_hndlr
+
+ Description: Message handler for Tape Restore functions
+
+ Returns:
+
+*****************************************************************************/
+static INT16 msg_hndlr(
+UINT16 msg,
+INT32 pid,
+BSD_PTR bsd_ptr,
+FSYS_HAND fsh,
+TPOS_PTR tpos,
+... )
+{
+ static BOOLEAN ems_db_stopping = FALSE ;
+ static CHAR delimiter = TEXT('#'); /* = # for debug */
+ static INT8 recover_seq = 0; /* sequence number used for tape read error recovery */
+ INT16 response = MSG_ACK;
+ va_list arg_ptr;
+ static UINT16 OS_id;
+ static UINT16 OS_ver;
+ GENERIC_DLE_PTR dle;
+ static CHAR_PTR buffer = NULL;
+ CHAR_PTR buffer1;
+ static CHAR_PTR buffer2 = NULL;
+ static CHAR_PTR path = NULL;
+ static CHAR_PTR last_file = NULL ;
+ INT16 res_id;
+ UINT64 num_bytes;
+ BOOLEAN stat ;
+ CHAR numeral[ UI_MAX_NUMERAL_LENGTH ];
+ CDS_PTR cds_ptr;
+ WORD restore_existing_files_flag;
+ DATE_TIME tape_date;
+ DATE_TIME_PTR tape_date_ptr;
+ DATE_TIME disk_date;
+ DATE_TIME_PTR disk_date_ptr;
+ BE_CFG_PTR be_cfg_ptr;
+ CHAR_PTR p;
+ BOOLEAN stat64;
+ static INT path_length;
+ static INT root_counted;
+ CHAR date_str1[40] ;
+ CHAR date_str2[40] ;
+
+ /* for future use */
+
+ pid;
+
+ /* set up first argument */
+ va_start( arg_ptr, tpos );
+
+ JobStatusBackupRestore( JOB_STATUS_ABORT_CHECK );
+
+ switch ( (INT16)msg ) {
+
+// You know it !
+// We are talking kludge city here. Keep the error
+// message from being displayed to the user.
+
+#ifdef MS_RELEASE
+ case -533:
+ zprintf( DEBUG_TEMPORARY, TEXT("** -533 LOOPS ERROR **") );
+ break;
+#endif
+
+ /* logging messages */
+ case MSG_LOG_STREAM_NAME:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ buffer1 = va_arg( arg_ptr, CHAR_PTR );
+
+ lresprintf( LOGGING_FILE, LOG_STREAM, fsh, buffer1 );
+
+ break;
+
+ case MSG_LOG_BLOCK:
+ {
+ DBLK_PTR dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+
+ dle = BSD_GetDLE( bsd_ptr ) ;
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+
+ if ( ( DLE_GetDeviceType(dle) == FS_EMS_DRV ) && ems_db_stopping ) {
+ ems_db_stopping = FALSE ;
+ yresprintf( IDS_RESTOREBEGINEXCHANGE ) ;
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ }
+
+ switch( FS_GetBlockType( dblk_ptr ) ) {
+
+ case BT_DDB:
+ /* clear last displayed filename from status display */
+ UI_DisplayFile( TEXT("") );
+ delimiter = FS_GetDelimiterFromOSID( OS_id, OS_ver );
+ UI_BuildDelimitedPathFromDDB( &buffer, fsh, dblk_ptr, delimiter, FALSE );
+
+ if ( DLE_GetDeviceType(BSD_GetDLE( bsd_ptr) ) == FS_EMS_DRV ) {
+ yprintf( TEXT("%s"), buffer+1 );
+ } else {
+ yprintf( TEXT("%s"), buffer );
+ }
+
+ if ( buffer ) { // chs:02-08-93
+ strcpy(mwCurrentPath, buffer ) ; // chs:02-08-93
+ strcpy( mwCurrentFile, TEXT("")) ; // chs:02-08-93
+ } // chs:02-08-93
+ SetStatusBlock(IDSM_OFFSETACTIVEDIR, (LONG)(LPSTR)mwCurrentPath);
+ if ( mw_file_replace_ptr ) {
+ UI_BuildDelimitedPathFromDDB( &buffer, fsh, dblk_ptr, delimiter, TRUE );
+ strcpy( mw_file_replace_ptr->source_path, buffer ) ;
+ UI_BuildDelimitedPathFromDDB( &buffer, fsh, dblk_ptr, delimiter, FALSE );
+ strcpy( mw_file_replace_ptr->destination_path, buffer ) ;
+ }
+
+ JobStatusBackupRestore( JOB_STATUS_DIRECTORY_NAMES );
+
+ ST_EndBackupSet( &op_stats );
+
+ // build the full path with no "..." inserted
+ UI_BuildFullPathFromDDB2( &buffer, fsh, dblk_ptr, delimiter, FALSE );
+
+ dle = BSD_GetDLE( bsd_ptr );
+
+ if ( ( DLE_GetDeviceType(dle) != FS_EMS_DRV ) && dle->device_name_leng ) {
+ buffer1 = (CHAR_PTR)calloc( 1, ( strlen( buffer ) * sizeof( CHAR ) ) + ( ( dle->device_name_leng ) * sizeof( CHAR ) ) + sizeof( CHAR ) );
+ if ( buffer1 ) {
+ strcpy( buffer1, dle->device_name );
+ strcat( buffer1, buffer );
+
+ lresprintf( LOGGING_FILE, LOG_DIRECTORY, SES_ENG_MSG, RES_DIRECTORY, buffer1 );
+ free( buffer1 );
+ } else {
+
+ lresprintf( LOGGING_FILE, LOG_DIRECTORY, SES_ENG_MSG, RES_DIRECTORY, buffer );
+ }
+ } else if ( DLE_GetDeviceType(dle) != FS_EMS_DRV ) {
+ lresprintf( LOGGING_FILE, LOG_DIRECTORY, SES_ENG_MSG, RES_DIRECTORY, buffer );
+ }
+
+ break;
+
+ case BT_FDB:
+ ST_SetCFSize( &op_stats, FS_GetDisplaySizeFromDBLK( fsh, dblk_ptr ) ); // chs:02-08-93
+ ST_SetCFDone( &op_stats, U64_Init( 0L, 0L ) ); // chs:02-08-93
+
+ if ( UI_AllocPathBuffer( &last_file, FS_SizeofFnameInFDB( fsh, dblk_ptr ) ) ) {
+ FS_GetFnameFromFDB( fsh, dblk_ptr, last_file );
+
+ // copy the full file name for the Log file
+ yprintf( TEXT("%s"), buffer );
+ lresprintf( LOGGING_FILE, LOG_FILE, fsh, dblk_ptr );
+
+ strcpy( mwCurrentFile, last_file ); // chs: 02-08-93
+ if ( CDS_GetFilesFlag( CDS_GetCopy() ) ) {
+
+ SetStatusBlock(IDSM_OFFSETACTIVEFILE, (DWORD)last_file );
+
+ // truncate the file name, if needed, for Runtime display
+ UI_DisplayFile( last_file );
+ JobStatusBackupRestore( JOB_STATUS_FILE_NAMES );
+ }
+ }
+ break;
+
+ case BT_CFDB:
+ ST_AddBSFilesBad( &op_stats, 1 );
+ yresprintf( (INT16) RES_RESTORED_CORRUPT_WARNING, last_file );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_RESTORED_CORRUPT_WARNING, buffer );
+ break;
+
+ }
+ }
+ break;
+
+ /* statistics messages */
+ case MSG_BLOCK_PROCESSED:
+ {
+ DBLK_PTR dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+ OBJECT_TYPE object_type;
+ INT item_size;
+ INT i;
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+
+ switch ( FS_GetBlockType( dblk_ptr ) ) {
+
+ case BT_DDB:
+
+ // Count all the new directories that showed up in
+ // this DDB.
+
+ // Only count the root once.
+
+ if ( ! root_counted ) {
+ ST_AddBSDirsProcessed( &op_stats, 1 );
+ root_counted = TRUE;
+ }
+
+ // Get the new path from the DDB.
+
+ item_size = FS_SizeofOSPathInDDB( fsh, dblk_ptr );
+ if ( UI_AllocPathBuffer( &buffer, (UINT16) item_size ) ) {
+ FS_GetOSPathFromDDB( fsh, dblk_ptr, buffer );
+
+ if ( item_size != sizeof(CHAR) ) {
+
+ i = 0;
+ while ( (INT)(i * sizeof(CHAR)) < item_size ) {
+
+ if ( i >= (INT)(path_length/sizeof(CHAR)) ) {
+
+ ST_AddBSDirsProcessed( &op_stats, 1 );
+ }
+ else {
+
+ if ( ( path == NULL ) || stricmp( &buffer[ i ], &path[ i ] ) ) {
+ ST_AddBSDirsProcessed( &op_stats, 1 );
+ path_length = 0;
+ }
+ }
+ while ( buffer[ i++ ] );
+ }
+ }
+ }
+ // Set up for next time.
+
+ if ( buffer && UI_AllocPathBuffer( &path, (UINT16) item_size ) ) {
+ memcpy( path, buffer, item_size );
+ path_length = item_size;
+
+ yprintf(TEXT("%ld\r"),ST_GetBSDirsProcessed( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_DIRECTORIES_PROCESS );
+ }
+ break;
+
+ case BT_FDB:
+
+ // Lines added to complete restoring a file // chs:02-05-93
+ // fully when aborted by user. // chs:02-05-93
+ // // chs:02-05-93
+ // Should we stop at the end of this file. // chs:02-05-93
+ // // chs:02-05-93
+ // chs:02-05-93
+ if ( gbAbortAtEOF ) { // chs:02-05-93
+ gb_abort_flag = ABORT_PROCESSED; // chs:02-05-93
+ } // chs:02-05-93
+ // chs:02-05-93
+ // // chs:02-05-93
+ // // chs:02-05-93
+ // // chs:02-05-93
+
+ strcpy( mwCurrentFile, TEXT( "" ) ) ; // chs:02-08-93
+ ST_SetCFSize( &op_stats, U64_Init( 0L, 0L ) ); // chs:02-08-93
+ ST_SetCFDone( &op_stats, U64_Init( 0L, 0L ) ); // chs:02-08-93
+
+
+ ST_AddBSFilesProcessed( &op_stats, 1 );
+ FS_GetObjTypeDBLK( fsh, dblk_ptr, &object_type );
+
+ if( object_type == AFP_OBJECT ) {
+
+ ST_AddBSAFPFilesProcessed( &op_stats, 1 );
+ }
+ yprintf(TEXT("%ld\r"),ST_GetBSFilesProcessed( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_FILES_PROCESSED );
+
+ break;
+
+ case BT_IDB:
+ break;
+ }
+ }
+ break;
+
+ case MSG_BYTES_PROCESSED:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ {
+ UINT64 count = va_arg( arg_ptr, UINT64 );
+
+ ST_AddBSBytesProcessed( &op_stats, count );
+ ST_AddCFDone( &op_stats, count ); // chs:02-08-93
+ }
+
+ ST_EndBackupSet( &op_stats );
+
+ break;
+
+ case MSG_BLOCK_SKIPPED:
+ {
+ DBLK_PTR dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+
+ switch( FS_GetBlockType( dblk_ptr ) ) {
+
+ case BT_DDB:
+ ST_AddBSDirsSkipped( &op_stats, 1 );
+ break;
+
+ case BT_FDB:
+ if ( gbAbortAtEOF ) { // CRS:04-15-93
+ gb_abort_flag = ABORT_PROCESSED; // CRS:04-15-93
+ } // CRS:04-15-93
+ ST_AddBSFilesSkipped( &op_stats, 1 );
+ yprintf(TEXT("%ld\r"),ST_GetBSFilesSkipped( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_SKIPPED_FILES );
+ break;
+ }
+ }
+ break;
+
+ case MSG_BYTES_SKIPPED:
+ {
+ UINT64 count = va_arg( arg_ptr, UINT64 );
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+
+ ST_AddBSBytesSkipped( &op_stats, count ) ;
+ }
+ break;
+
+ case MSG_IN_USE:
+ {
+ DBLK_PTR dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+
+ ST_AddBSInUseFilesProcessed( &op_stats, 1 );
+ if ( UI_AllocPathBuffer( &buffer, FS_SizeofFnameInFDB( fsh, dblk_ptr ) ) ) {
+ FS_GetFnameFromFDB( fsh, dblk_ptr, buffer );
+ yresprintf( (INT16) RES_RESTORED_IN_USE_WARNING, buffer );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_RESTORED_IN_USE_WARNING, buffer );
+ }
+ }
+ break;
+
+ case MSG_TBE_ERROR:
+ {
+ INT16 error = va_arg( arg_ptr, INT16 );
+ DBLK_PTR ddb_dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+ DBLK_PTR dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+ UINT32 strm_id = va_arg( arg_ptr, UINT32 ) ;
+
+ OBJECT_TYPE object_type;
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+
+ dle = BSD_GetDLE( bsd_ptr );
+
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &op_stats );
+
+ if ( strm_id != 0L ) {
+ if ( DLE_GetDeviceType(dle) == FS_EMS_DRV ) {
+ yresprintf( (INT16) RES_RESTOREWRITEERROR, DLE_GetDeviceName( dle ) );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_RESTOREWRITEERROR, DLE_GetDeviceName( dle ) );
+
+ } else {
+
+ JS_ReportStreamError( fsh, dle, strm_id, OPERATION_RESTORE, error, ddb_dblk_ptr, dblk_ptr ) ;
+ }
+
+ } else {
+
+ switch( error ) {
+
+ case LP_CHANGE_DIRECTORY_ERROR:
+# if defined ( OS_WIN32 )
+ {
+ mwErrorDuringBackupSet = TRUE;
+ }
+# endif //defined ( OS_WIN32 )
+
+ gb_error_during_operation = TRUE;
+ if ( FS_GetBlockType( dblk_ptr ) == BT_FDB ) {
+ if ( UI_AllocPathBuffer( &buffer, FS_SizeofFnameInFDB( fsh, dblk_ptr ) ) ) {
+ FS_GetFnameFromFDB( fsh, dblk_ptr, buffer );
+ FS_GetObjTypeDBLK( fsh, dblk_ptr, &object_type );
+ if ( object_type == AFP_OBJECT ) {
+ yresprintf( (INT16) RES_ERROR_RESTORING_AFP_FILE, buffer );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_ERROR_RESTORING_AFP_FILE, buffer );
+ }
+ else {
+ yresprintf( (INT16) RES_ERROR_RESTORING_FILE, buffer );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_ERROR_RESTORING_FILE, buffer );
+ }
+ }
+ }
+ else if( FS_GetBlockType( dblk_ptr ) == BT_DDB ) {
+ delimiter = FS_GetDelimiterFromOSID( OS_id, OS_ver );
+ UI_BuildDelimitedPathFromDDB( &buffer, fsh, dblk_ptr, delimiter, FALSE );
+ if ( buffer != NULL ) {
+ yresprintf( (INT16) RES_ERROR_RESTORING_DIR, buffer );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_ERROR_RESTORING_DIR, buffer );
+ }
+ }
+ break;
+
+ case FS_EMS_NO_PUBLIC:
+# if defined ( OS_WIN32 )
+ {
+ mwErrorDuringBackupSet = TRUE;
+ }
+# endif //defined ( OS_WIN32 )
+
+ gb_error_during_operation = TRUE;
+
+ yresprintf( (INT16) IDS_EMS_NO_PUBLIC_SERVICE );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, IDS_EMS_NO_PUBLIC_SERVICE );
+ break ;
+
+ case FS_EMS_NO_PRIVATE:
+# if defined ( OS_WIN32 )
+ {
+ mwErrorDuringBackupSet = TRUE;
+ }
+# endif //defined ( OS_WIN32 )
+
+ gb_error_during_operation = TRUE;
+
+ yresprintf( (INT16) IDS_EMS_NO_PRIVATE_SERVICE );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, IDS_EMS_NO_PUBLIC_SERVICE );
+ break ;
+
+ case LP_ACCESS_DENIED_ERROR:
+# if defined ( OS_WIN32 )
+ {
+ mwErrorDuringBackupSet = TRUE;
+ }
+# endif //defined ( OS_WIN32 )
+
+ gb_error_during_operation = TRUE;
+
+ if ( strm_id != 0L ) {
+ JS_ReportStreamError( fsh,
+ dle,
+ strm_id,
+ OPERATION_RESTORE,
+ error,
+ ddb_dblk_ptr,
+ dblk_ptr ) ;
+ }
+
+ if ( FS_GetBlockType( dblk_ptr ) == BT_FDB ) {
+ if ( UI_AllocPathBuffer( &buffer, FS_SizeofFnameInFDB( fsh, dblk_ptr ) ) ) {
+ FS_GetFnameFromFDB( fsh, dblk_ptr, buffer );
+ yresprintf( (INT16) RES_INSUFFICIENT_PRIVILEGE, buffer );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_INSUFFICIENT_PRIVILEGE, buffer );
+ }
+ }
+ else if( FS_GetBlockType( dblk_ptr ) == BT_DDB ) {
+ delimiter = FS_GetDelimiterFromOSID( OS_id, OS_ver );
+ UI_BuildDelimitedPathFromDDB( &buffer, fsh, dblk_ptr, delimiter, FALSE );
+ if ( buffer != NULL ) {
+ yresprintf( (INT16) RES_ERROR_RESTORING_DIR, buffer );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_ERROR_RESTORING_DIR, buffer );
+ }
+ }
+ break;
+
+ case LP_FILE_CREATION_ERROR:
+# if defined ( OS_WIN32 )
+ {
+ mwErrorDuringBackupSet = TRUE;
+ }
+# endif //defined ( OS_WIN32 )
+
+ gb_error_during_operation = TRUE;
+
+ if( FS_GetBlockType( dblk_ptr ) == BT_FDB ) {
+ if ( UI_AllocPathBuffer( &buffer, FS_SizeofFnameInFDB( fsh, dblk_ptr ) ) ) {
+ FS_GetFnameFromFDB( fsh, dblk_ptr, buffer );
+ yresprintf( (INT16) RES_ERROR_CREATING_FILE, buffer );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_ERROR_CREATING_FILE, buffer );
+ }
+ }
+ else if( FS_GetBlockType( dblk_ptr ) == BT_DDB ) {
+ delimiter = FS_GetDelimiterFromOSID( OS_id, OS_ver );
+ UI_BuildDelimitedPathFromDDB( &buffer, fsh, dblk_ptr, delimiter, FALSE );
+ if ( buffer != NULL ) {
+ yresprintf( (INT16) RES_ERROR_CREATING_DIR, buffer );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_ERROR_CREATING_DIR, buffer );
+ }
+ }
+ break;
+
+ case LP_OUT_OF_SPACE_ERROR:
+# if defined ( OS_WIN32 )
+ {
+ mwErrorDuringBackupSet = TRUE;
+ }
+# endif //defined ( OS_WIN32 )
+
+ gb_error_during_operation = TRUE;
+
+ yresprintf( (INT16) RES_INSUFFICIENT_DISK_SPACE );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_INSUFFICIENT_DISK_SPACE );
+
+ /* falling through */
+
+ case FS_COMPRES_RESET_FAIL:
+ case LP_FILE_WRITE_ERROR:
+ case LP_FILE_OPEN_ERROR:
+# if defined ( OS_WIN32 )
+ {
+ mwErrorDuringBackupSet = TRUE;
+ }
+# endif //defined ( OS_WIN32 )
+
+ gb_error_during_operation = TRUE;
+
+ if ( DLE_GetDeviceType(dle) == FS_EMS_DRV ) {
+ break ;
+ }
+
+ switch( FS_GetBlockType( dblk_ptr ) ) {
+ case BT_FDB :
+ if ( UI_AllocPathBuffer( &buffer, FS_SizeofFnameInFDB( fsh, dblk_ptr ) ) ) {
+ FS_GetFnameFromFDB( fsh, dblk_ptr, buffer );
+ FS_GetObjTypeDBLK( fsh, dblk_ptr, &object_type );
+ if ( error == FS_COMPRES_RESET_FAIL ) {
+ yresprintf( (INT16) RES_ERROR_COMPRESS_FILE_FAIL, buffer );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_ERROR_RESTORING_AFP_FILE, buffer );
+
+ } else if( object_type == AFP_OBJECT ) {
+ yresprintf( (INT16) RES_ERROR_RESTORING_AFP_FILE, buffer );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_ERROR_RESTORING_AFP_FILE, buffer );
+ }
+ else {
+ yresprintf( (INT16) RES_ERROR_RESTORING_FILE, buffer );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_ERROR_RESTORING_FILE, buffer );
+ }
+ }
+ break;
+
+ case BT_DDB :
+ delimiter = FS_GetDelimiterFromOSID( OS_id, OS_ver );
+ UI_BuildDelimitedPathFromDDB( &buffer, fsh, dblk_ptr, delimiter, FALSE );
+ if ( buffer != NULL ) {
+ res_id = (INT16) ( ( error == LP_FILE_OPEN_ERROR ) ? RES_ERROR_RESTORING_DIR
+ : RES_ERROR_RESTORING_TRUSTEE_SEC );
+ if ( error == FS_COMPRES_RESET_FAIL ) {
+ res_id = RES_ERROR_COMPRESS_FILE_FAIL ;
+ }
+ yresprintf( res_id, buffer );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, res_id, buffer );
+ }
+ break;
+
+ }
+ break;
+
+ case LP_PRIVILEGE_ERROR:
+# if defined ( OS_WIN32 )
+ {
+ mwErrorDuringBackupSet = TRUE;
+ }
+# endif //defined ( OS_WIN32 )
+
+ gb_error_during_operation = TRUE;
+
+ if ( DLE_GetDeviceType(dle) == FS_EMS_DRV ) {
+ yresprintf( (INT16) RES_RESTOREWRITEERROR, DLE_GetDeviceName( dle ) );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_RESTOREWRITEERROR, DLE_GetDeviceName( dle ) );
+
+ } else if( FS_GetBlockType( dblk_ptr ) == BT_FDB ) {
+ if ( UI_AllocPathBuffer( &buffer, FS_SizeofFnameInFDB( fsh, dblk_ptr ) ) ) {
+ FS_GetFnameFromFDB( fsh, dblk_ptr, buffer );
+ yresprintf( (INT16) RES_ERROR_RESTORING_FILE_SEC, buffer );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_ERROR_RESTORING_FILE_SEC, buffer );
+ }
+ }
+ else if( FS_GetBlockType( dblk_ptr ) == BT_DDB ) {
+ delimiter = FS_GetDelimiterFromOSID( OS_id, OS_ver );
+ UI_BuildDelimitedPathFromDDB( &buffer, fsh, dblk_ptr, delimiter, FALSE );
+ if ( buffer != NULL ) {
+ yresprintf( (INT16) RES_ERROR_RESTORING_DIR_SEC, buffer );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_ERROR_RESTORING_DIR_SEC, buffer );
+ }
+ }
+ break;
+
+ case LP_FILE_IN_USE_ERROR:
+ if ( UI_AllocPathBuffer( &buffer, FS_SizeofFnameInFDB( fsh, dblk_ptr ) ) ) {
+ FS_GetFnameFromFDB( fsh, dblk_ptr, buffer );
+ FS_GetObjTypeDBLK( fsh, dblk_ptr, &object_type );
+ if( object_type == AFP_OBJECT ) {
+ yresprintf( (INT16) RES_ERROR_RESTORING_AFP_FILE, buffer );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_ERROR_RESTORING_AFP_FILE, buffer );
+ }
+ else {
+ yresprintf( (INT16) RES_ERROR_RESTORING_FILE, buffer );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_ERROR_RESTORING_FILE, buffer );
+ }
+ }
+ break;
+
+ default:
+ if ( DLE_GetDeviceType(dle) == FS_EMS_DRV ) {
+ if ( ( error == FS_DEVICE_ERROR ) || ( error == FS_COMM_FAILURE ) ) {
+ mwErrorDuringBackupSet = TRUE;
+ gb_error_during_operation = TRUE;
+ yresprintf( (INT16) RES_RESTOREWRITEERROR, DLE_GetDeviceName( dle ) );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_RESTOREWRITEERROR, DLE_GetDeviceName( dle ) );
+ break ;
+ }
+ }
+
+ UI_ProcessErrorCode( error, &response, tpos->channel );
+ break;
+ }
+ }
+
+ /* restart the clock with an end idle */
+ ST_EndBackupSetIdle( &op_stats );
+ }
+ break;
+
+ /* general messages */
+ case MSG_START_OPERATION:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+
+ lresprintf( LOGGING_FILE, LOG_START, FALSE );
+
+ /* display operation title in log file */
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, IDS_DLGTITLEJOBSTATRESTORE ) ;
+
+ break;
+
+ case MSG_END_OPERATION:
+ {
+ BSD_PTR bsd_ptr ;
+ GENERIC_DLE_PTR dle_ptr ;
+ BE_CFG_PTR cfg;
+
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ /* first lets clear the kick bit on all but the last bsd for each dest */
+ bsd_ptr = BSD_GetFirst( tape_bsd_list );
+ while (bsd_ptr ) {
+ CHAR_PTR dest_name ;
+ CHAR_PTR dest_name1 ;
+ BSD_PTR temp_bsd ;
+
+ cfg = BSD_GetConfigData( bsd_ptr ) ;
+
+ dest_name = BSD_GetVolumeLabel( bsd_ptr ) ;
+ if ( BSD_GetOsId( bsd_ptr ) == FS_EMS_MDB_ID ) {
+ dest_name = BSD_GetLogicalSourceDevice( bsd_ptr ) ;
+ }
+ temp_bsd = BSD_GetNext(bsd_ptr) ;
+ while( temp_bsd ) {
+
+ dest_name1 = BSD_GetVolumeLabel( temp_bsd ) ;
+ if ( BSD_GetOsId( temp_bsd ) == FS_EMS_MDB_ID ) {
+ dest_name1 = BSD_GetLogicalSourceDevice( temp_bsd ) ;
+ }
+
+ if ( dest_name1 && dest_name &&
+ !strcmp( dest_name1, dest_name) ) {
+
+ if ( BEC_GetEmsRipKick(cfg) ) {
+
+ BEC_SetEmsRipKick( BSD_GetConfigData( bsd_ptr ) , FALSE ) ;
+ BEC_SetEmsRipKick( BSD_GetConfigData( temp_bsd ) , TRUE ) ;
+ break ;
+ }
+ }
+ temp_bsd = BSD_GetNext( temp_bsd ) ;
+ }
+
+ bsd_ptr = BSD_GetNext( bsd_ptr ) ;
+ }
+
+
+ /* lets go through the BSDs again and call end oper on all the dles */
+
+ bsd_ptr = BSD_GetFirst( tape_bsd_list );
+
+ while ( (gb_abort_flag == CONTINUE_PROCESSING) && bsd_ptr ) {
+ FSYS_HAND fsh ;
+ INT16 return_status ;
+
+ dle_ptr = BSD_GetDLE( bsd_ptr ) ;
+ cfg = BSD_GetConfigData( bsd_ptr ) ;
+
+ return_status = FS_AttachToDLE( &fsh, dle_ptr, cfg, NULL, NULL ) ;
+
+ if (!return_status ) {
+
+ if (BEC_GetEmsRipKick( cfg ) ) {
+ yresprintf( IDS_RESTORESTARTEXCHANGE, DLE_GetDeviceName(DLE_GetParent(dle_ptr)) );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ }
+
+ FS_EndOperationOnDLE( fsh ) ;
+ FS_DetachDLE( fsh ) ;
+ }
+ bsd_ptr = BSD_GetNext( bsd_ptr );
+
+ }
+ }
+
+ UI_FreePathBuffer( &buffer ) ;
+ UI_FreePathBuffer( &buffer2 ) ;
+ UI_FreePathBuffer( &path ) ;
+ UI_FreePathBuffer( &last_file ) ;
+
+ lresprintf( LOGGING_FILE, LOG_END );
+
+ /* force an update to the bytes counter */
+ num_bytes = ST_GetBSBytesProcessed ( &op_stats );
+
+ U64_Litoa( num_bytes, numeral, (INT16) 10, &stat );
+ UI_BuildNumeralWithCommas( numeral );
+ yprintf(TEXT("%s\r"),numeral );
+ JobStatusBackupRestore( JOB_STATUS_BYTES_PROCESSED );
+
+ UI_ChkDispGlobalError( );
+ break;
+
+ case MSG_START_BACKUP_SET:
+ {
+ CHAR szVolName[MAX_UI_FILENAME_LEN];
+ DBLK_PTR vcb_ptr = va_arg( arg_ptr, DBLK_PTR );
+
+ SetStatusBlock(IDSM_OPERATIONSTATUS, STAT_OPER_RESTORE);
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+
+ path_length = 0;
+ UI_FreePathBuffer( &path ) ;
+
+ root_counted = FALSE;
+
+ FS_GetOSid_verFromVCB( vcb_ptr, &OS_id, &OS_ver );
+
+ BSD_SetOperStatus( bsd_ptr, SUCCESS );
+
+ dle = BSD_GetDLE( bsd_ptr );
+
+#ifdef OEM_EMS
+ RT_BSD_OsId = DLE_GetOsId( dle );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_FS_TYPE );
+#endif OEM_EMS
+
+ strcpy( mwCurrentDrive, DLE_GetDeviceName( dle ) ) ; // chs:02-08-93
+ mwCurrentPath[0] = TEXT( '\0' ); // chs:02-08-93
+ mwCurrentFile[0] = TEXT( '\0' ); // chs:02-08-93
+
+ SetStatusBlock( IDSM_TAPEFAMILY, (DWORD)FS_ViewTapeIDInVCB( vcb_ptr ) );
+ SetStatusBlock( IDSM_TAPESEQNUMBER, (DWORD)FS_ViewTSNumInVCB( vcb_ptr ) );
+ SetStatusBlock( IDSM_BACKUPSET, (DWORD)FS_ViewBSNumInVCB( vcb_ptr ) );
+
+ SetStatusBlock( IDSM_OFFSETCURRENTTAPENAME, (DWORD)FS_ViewTapeNameInVCB( vcb_ptr ) );
+ SetStatusBlock( IDSM_OFFSETDISKNAME, (DWORD)FS_ViewVolNameInVCB( vcb_ptr ) );
+
+ if ( DLE_HasFeatures( dle, DLE_FEAT_REMOTE_DRIVE ) ) {
+ JobStatusBackupRestore( JOB_STATUS_VOLUME_NETDRIVE );
+ }
+ else {
+ JobStatusBackupRestore( JOB_STATUS_VOLUME_HARDDRIVE );
+ }
+
+ DLE_GetVolName( dle, szVolName );
+
+ yprintf(TEXT("%s"),BSD_GetTapeLabel( bsd_ptr ));
+ JobStatusBackupRestore( JOB_STATUS_SOURCE_NAME );
+
+ yprintf(TEXT("%s"), szVolName );
+ JobStatusBackupRestore( JOB_STATUS_DEST_NAME );
+
+ strcpy( mw_file_replace_ptr->destination_volume, DLE_GetDeviceName( dle ) );
+
+ UI_DisplayBSDVCB( bsd_ptr );
+
+ delimiter = (CHAR)DLE_GetPathDelim( dle );
+
+ ST_StartBackupSet( &op_stats );
+
+ if ( DLE_GetDeviceType(dle) == FS_EMS_DRV ) {
+ lresprintf( LOGGING_FILE, LOG_MSG,
+ SES_ENG_MSG,
+ RES_UNFORMATED_STRING,
+ DLE_GetDeviceName(dle) );
+
+ yresprintf( RES_UNFORMATED_STRING, DLE_GetDeviceName(dle) );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ }
+
+ UI_Time( &op_stats, RES_RESTORE_STARTED, UI_START );
+
+ clock_ready_flag = TRUE;
+
+#if defined ( OS_WIN32 ) //special feature-EventLogging
+ cds_ptr = CDS_GetCopy();
+ mwErrorDuringBackupSet = FALSE;
+
+ OMEVENT_LogBeginRestore( szVolName,
+ (INT16)(CDS_GetAutoVerifyBackup(cds_ptr) == 0 ? 1 : 0));
+#endif //defined ( OS_WIN32 ) //special feature-EventLogging
+
+ if ( DLE_GetDeviceType(dle) == FS_EMS_DRV ) {
+ ems_db_stopping = TRUE ;
+ if ( BEC_GetEmsWipeClean( BSD_GetConfigData( bsd_ptr ) ) ) {
+ yresprintf( IDS_WIPE_SPECIFIED ) ;
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, IDS_WIPE_SPECIFIED ) ;
+ }
+
+ yresprintf( IDS_RESTORESTOPEXCHANGE ) ;
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ }
+
+ }
+ break;
+
+ case MSG_END_BACKUP_SET:
+ {
+ INT16 res_id;
+
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ SetStatusBlock(IDSM_OPERATIONSTATUS, STAT_OPER_IDLE);
+
+ // update stats
+ clock_routine();
+
+ mwCurrentPath[0] = TEXT( '\0' ); // chs: 02-08-93
+ mwCurrentFile[0] = TEXT( '\0' ); // chs: 02-08-93
+
+ ST_EndBackupSet( &op_stats );
+
+ /* set backup set operation status to FILES_SKIPPED if necessary */
+ if ( ST_GetBSFilesBad( &op_stats ) ||
+ ST_GetBSDirsBad( &op_stats ) ||
+ ST_GetBSFilesSkipped( &op_stats ) ||
+ ST_GetBSDirsSkipped( &op_stats ) ) {
+
+ BSD_SetOperStatus( bsd_ptr, FILES_SKIPPED );
+ }
+
+ clock_ready_flag = FALSE;
+
+ /* clear last displayed filename */
+ UI_ClearLastDisplayedFile( );
+
+ /* display and log any abort conditions */
+ UI_ConditionAtEnd( );
+
+ UI_Time( &op_stats, RES_RESTORE_COMPLETED, UI_END );
+
+ SetStatusBlock(IDSM_DIRCOUNT, (DWORD)0 );
+ SetStatusBlock(IDSM_FILECOUNT, (DWORD)0 );
+ SetStatusBlock(IDSM_BYTECOUNTLO, (DWORD)0 );
+ SetStatusBlock(IDSM_BYTECOUNTHI, (DWORD)0 );
+ SetStatusBlock(IDSM_ELAPSEDSECONDS, (DWORD)0 );
+ SetStatusBlock(IDSM_CORRUPTFILECOUNT, (DWORD)0 );
+ SetStatusBlock(IDSM_SKIPPEDFILECOUNT, (DWORD)0 );
+
+ SetStatusBlock(IDSM_OFFSETACTIVEFILE, (DWORD)TEXT( "" ) );
+ SetStatusBlock(IDSM_OFFSETACTIVEDIR, (DWORD)TEXT("" ) );
+ SetStatusBlock(IDSM_OFFSETDISKNAME, (DWORD)TEXT("" ) );
+
+ /* display number of files / number of dirs */
+ if( ST_GetBSFilesProcessed( &op_stats ) <= 1 && ST_GetBSDirsProcessed( &op_stats ) <= 1 ) { // chs:02-11-93
+ res_id = RES_RESTORED_DIR_FILE; // chs:02-11-93
+ } // chs:02-11-93
+ else if( ST_GetBSFilesProcessed( &op_stats ) <= 1 && ST_GetBSDirsProcessed( &op_stats ) > 1 ) { // chs:02-11-93
+ res_id = RES_RESTORED_DIRS_FILE; // chs:02-11-93
+ } // chs:02-11-93
+ else if( ST_GetBSFilesProcessed( &op_stats ) > 1 && ST_GetBSDirsProcessed( &op_stats ) > 1 ) { // chs:02-11-93
+ res_id = RES_RESTORED_DIRS_FILES; // chs:02-11-93
+ } else { // chs:02-11-93
+ res_id = RES_RESTORED_DIR_FILES; // chs:02-11-93
+ } // chs:02-11-93
+
+// chs:02-11-93 if( ST_GetBSFilesProcessed( &op_stats ) == 1 ) {
+// chs:02-11-93 res_id = RES_RESTORED_DIR_FILE;
+// chs:02-11-93 }
+// chs:02-11-93 else if( ST_GetBSDirsProcessed( &op_stats ) == 1 ) {
+// chs:02-11-93 res_id = RES_RESTORED_DIR_FILES;
+// chs:02-11-93 }
+// chs:02-11-93 else {
+// chs:02-11-93 res_id = RES_RESTORED_DIRS_FILES;
+// chs:02-11-93 }
+
+ dle = BSD_GetDLE( bsd_ptr );
+ if ( DLE_GetDeviceType( dle ) != FS_EMS_DRV ) {
+ yresprintf( res_id,
+ ST_GetBSFilesProcessed( &op_stats ),
+ ST_GetBSDirsProcessed( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, res_id,
+ ST_GetBSFilesProcessed( &op_stats ),
+ ST_GetBSDirsProcessed( &op_stats ) );
+ }
+
+ /* display number of mac files restored */
+ if ( ST_GetBSAFPFilesProcessed( &op_stats ) > 0 ) {
+
+ if ( ST_GetBSAFPFilesProcessed( &op_stats ) == 1 ) {
+ res_id = RES_RESTORED_MAC;
+ }
+ else {
+ res_id = RES_RESTORED_MACS;
+ }
+
+ yresprintf( res_id,
+ ST_GetBSAFPFilesProcessed( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, res_id,
+ ST_GetBSAFPFilesProcessed( &op_stats ) );
+
+ }
+
+ /* display number of corrupt files */
+ if ( ST_GetBSFilesBad( &op_stats ) > 0 ) {
+
+ if ( ST_GetBSFilesBad( &op_stats ) == 1 ) {
+ res_id = RES_RESTORED_CORRUPT;
+ }
+ else {
+ res_id = RES_RESTORED_CORRUPTS;
+ }
+
+ yresprintf( res_id,
+ ST_GetBSFilesBad( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, res_id,
+ ST_GetBSFilesBad( &op_stats ) );
+ }
+
+ /* display number of in-use files */
+ if ( ST_GetBSInUseFilesProcessed( &op_stats ) > 0 ) {
+ if( ST_GetBSInUseFilesProcessed( &op_stats ) == 1 ) {
+ res_id = RES_RESTORED_IN_USE;
+ }
+ else {
+ res_id = RES_RESTORED_IN_USES;
+ }
+
+ yresprintf( res_id,
+ ST_GetBSInUseFilesProcessed( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, res_id,
+ ST_GetBSInUseFilesProcessed( &op_stats ) );
+ }
+
+ /* display number of files skipped */
+ if ( ST_GetBSFilesSkipped( &op_stats ) > 0 ) {
+
+ if( ST_GetBSFilesSkipped( &op_stats ) == 1 ) {
+ res_id = RES_FILE_SKIPPED_STAT;
+ }
+ else {
+ res_id = RES_FILE_SKIPPEDS_STAT;
+ }
+
+ yresprintf( res_id,
+ ST_GetBSFilesSkipped( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, res_id,
+ ST_GetBSFilesSkipped( &op_stats ) );
+
+ }
+
+ /* display number of Directories processed */
+ yprintf(TEXT("%ld\r"),ST_GetBSDirsProcessed( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_DIRECTORIES_PROCESS );
+
+ /* display number of Files processed */
+ yprintf(TEXT("%ld\r"),ST_GetBSFilesProcessed( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_FILES_PROCESSED );
+
+ /* display number of bytes processed */
+ UI_BytesProcessed( &op_stats );
+
+ /* display restore rate */
+ UI_RateProcessed( &op_stats );
+
+ delimiter = TEXT('#'); /* = # for debug */
+
+# if defined ( OS_WIN32 ) //special feature-EventLogging
+ {
+ OMEVENT_LogEndRestore ( mwErrorDuringBackupSet );
+ }
+# endif //defined ( OS_WIN32 ) //special feature-EventLogging
+ }
+ break;
+
+ case MSG_PROMPT:
+ {
+ INT16 type = va_arg( arg_ptr, INT16 );
+
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+
+ switch( type ) {
+
+ case ASK_TO_REPLACE_MODIFIED:
+ response = TRUE;
+ break;
+ case ASK_TO_REPLACE_EXISTING:
+ {
+
+ /* get filename from dblk and display prompt */
+ DBLK_PTR dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+ DBLK_PTR disk_dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+
+ tape_date_ptr = &tape_date;
+ disk_date_ptr = &disk_date;
+
+ /* get dates for a later comparison */
+
+ FS_GetMDateFromDBLK( fsh, dblk_ptr, tape_date_ptr );
+ FS_GetMDateFromDBLK( fsh, disk_dblk_ptr, disk_date_ptr );
+
+ cds_ptr = CDS_GetCopy();
+ restore_existing_files_flag = CDS_GetRestoreExistingFiles( cds_ptr );
+ if ( UI_AllocPathBuffer( &buffer, FS_SizeofOSFnameInFDB( fsh, dblk_ptr ) ) ) {
+ FS_GetFnameFromFDB( fsh, dblk_ptr, buffer );
+
+
+ switch( restore_existing_files_flag ) {
+ case NO_RESTORE_OVER_EXISTING :
+
+ ST_AddBSFilesSkipped( &op_stats, 1 );
+ yprintf(TEXT("%ld\r"),ST_GetBSFilesSkipped( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_SKIPPED_FILES );
+
+ yresprintf( (INT16) RES_FILE_WAS_SKIPPED_USER, buffer );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG,
+ RES_FILE_WAS_SKIPPED_USER, buffer );
+ break;
+
+ case PROMPT_RESTORE_OVER_RECENT :
+ case PROMPT_RESTORE_OVER_EXISTING :
+
+ if(mw_file_replace_ptr) {
+
+ UI_AllocPathBuffer( &buffer2,
+ (UINT16) ( FS_SizeofOSFnameInFDB( fsh, dblk_ptr ) +
+ strsize(mw_file_replace_ptr->destination_volume) +
+ strsize(mw_file_replace_ptr->destination_path) + 3 ) ) ;
+
+ if ( buffer2 ) {
+ FS_GetFnameFromFDB( fsh, dblk_ptr, buffer );
+ strcpy(buffer2, mw_file_replace_ptr->destination_volume);
+ strcat(buffer2, mw_file_replace_ptr->destination_path);
+ if ( strcmp( mw_file_replace_ptr->destination_path, TEXT( "\\" ) ) ) {
+ strcat(buffer2,TEXT("\\"));
+ }
+ strcat(buffer2,buffer);
+ yprintf(TEXT("%s\n"), buffer2 );
+ strcpy( mw_file_replace_ptr->line_1, gszTprintfBuffer );
+
+ disk_date_ptr->year -= 1900;
+ UI_MakeDateString( date_str1,
+ disk_date_ptr->month,
+ disk_date_ptr->day,
+ disk_date_ptr->year );
+ UI_MakeTimeString( date_str2,
+ disk_date_ptr->hour,
+ disk_date_ptr->minute,
+ disk_date_ptr->second );
+ yresprintf( (INT16) RES_FILE_DETAIL,
+ U64_Litoa( FS_GetDisplaySizeFromDBLK( fsh, disk_dblk_ptr ), // chs:02-09-93, per Carl.
+ numeral, (INT16) 10, &stat64 ),
+ date_str1,
+ date_str2 );
+ strcpy( mw_file_replace_ptr->line_2, gszTprintfBuffer );
+
+ strcpy(buffer2,(CHAR_PTR)VLM_GetVolumeName( BSD_GetTapeID( bsd_ptr), BSD_GetSetNum( bsd_ptr ) ));
+ p = strrchr( buffer2, TEXT(':') );
+ if(p) {
+ *++p = 0;
+ }
+ FS_GetOSFnameFromFDB( fsh, dblk_ptr, buffer );
+ strcpy(mw_file_replace_ptr->source_volume, buffer2 );
+ strcat(buffer2, mw_file_replace_ptr->source_path);
+ if ( strcmp( mw_file_replace_ptr->source_path, TEXT( "\\" ) ) ) {
+ strcat(buffer2,TEXT("\\"));
+ }
+ strcat(buffer2,buffer);
+ yprintf(TEXT("%s\n"), buffer2 );
+ strcpy( mw_file_replace_ptr->line_3, gszTprintfBuffer );
+
+ tape_date_ptr->year -= 1900;
+ UI_MakeDateString( date_str1,
+ tape_date_ptr->month,
+ tape_date_ptr->day,
+ tape_date_ptr->year );
+ UI_MakeTimeString( date_str2,
+ tape_date_ptr->hour,
+ tape_date_ptr->minute,
+ tape_date_ptr->second );
+ yresprintf( (INT16) RES_FILE_DETAIL,
+ U64_Litoa( FS_GetDisplaySizeFromDBLK( fsh, dblk_ptr ),
+ numeral, (INT16) 10, &stat64 ),
+ date_str1,
+ date_str2 );
+ strcpy( mw_file_replace_ptr->line_4, gszTprintfBuffer );
+
+
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &op_stats );
+
+ if( restore_existing_files_flag == PROMPT_RESTORE_OVER_RECENT ) {
+
+ /* if current disk file newer than tape file, prompt user */
+ if( CompDate(disk_date_ptr, tape_date_ptr ) > 0 ) {
+
+ response = DM_StartConfirmFileReplace( mw_file_replace_ptr );
+ }
+ else {
+ response = TRUE; /* restore file */
+ }
+ } else {
+
+ response = DM_StartConfirmFileReplace( mw_file_replace_ptr );
+ }
+
+ /* restart the clock with an end idle */
+ ST_EndBackupSetIdle( &op_stats );
+
+ if(response == FILE_REPLACE_NO_BUTTON ) {
+
+ response = FALSE; /* don't restore file */
+ }
+ else if(response == FILE_REPLACE_YES_BUTTON ) {
+
+ response = TRUE; /* restore file */
+ }
+ else if(response == FILE_REPLACE_CANCEL_BUTTON ) {
+ response = FALSE; /* don't restore file */
+ JobStatusBackupRestore( JOB_STATUS_ABORT );
+ }
+ else if(response == FILE_REPLACE_YES_TO_ALL_BUTTON )
+ {
+ be_cfg_ptr = BSD_GetConfigData(bsd_ptr);
+
+ /* Set the restore extisting files flag for this BSD */
+ BEC_SetExistFlag( be_cfg_ptr, (INT16)BEC_REST_OVER_EXIST );
+ response = TRUE; /* restore file */
+ }
+
+ if( response == FALSE ) {
+
+ ST_AddBSFilesSkipped( &op_stats, 1 );
+ yprintf(TEXT("%ld\r"),ST_GetBSFilesSkipped( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_SKIPPED_FILES );
+
+ yresprintf( (INT16) RES_FILE_WAS_SKIPPED_USER, buffer2 );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG,
+ RES_FILE_WAS_SKIPPED_USER, buffer2 );
+ }
+ }
+ }
+ break;
+
+ case NO_RESTORE_OVER_RECENT :
+
+ /* if current disk file newer than tape file, don't restore */
+ if( CompDate(disk_date_ptr, tape_date_ptr ) > 0 ) {
+
+ response = FALSE; /* don't restore file */
+ }
+ else {
+ response = TRUE; /* restore file */
+ }
+
+ if( response == FALSE ) {
+
+ ST_AddBSFilesSkipped( &op_stats, 1 );
+ yprintf(TEXT("%ld\r"),ST_GetBSFilesSkipped( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_SKIPPED_FILES );
+
+ FS_GetFnameFromFDB( fsh, dblk_ptr, buffer );
+ yresprintf( (INT16) RES_FILE_WAS_SKIPPED, buffer );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG,
+ RES_FILE_WAS_SKIPPED, buffer );
+ }
+ break;
+ }
+ }
+
+ }
+ break;
+
+ case ASK_TO_RESTORE_CONTINUE:
+ {
+ /* get filename from dblk and display prompt */
+ DBLK_PTR dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+
+ switch ( FS_GetBlockType( dblk_ptr ) ) {
+
+ case BT_FDB :
+
+ if ( CDS_GetYesFlag( CDS_GetPerm() ) == YESYES_FLAG ) {
+
+ response = FALSE;
+
+ } else {
+
+ /* prompt user for response */
+
+ if ( UI_AllocPathBuffer( &buffer, FS_SizeofFnameInFDB( fsh, dblk_ptr ) ) ) {
+
+ FS_GetFnameFromFDB( fsh, dblk_ptr, buffer );
+ yresprintf( (INT16) RES_CONTINU_FILE_WARNING, buffer );
+
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &op_stats );
+
+ response = (INT16)WM_MessageBox( ID( IDS_MSGTITLE_RESTORE ),
+ gszTprintfBuffer,
+ (WORD)WMMB_YESNO,
+ (WORD)WMMB_ICONQUESTION,
+ ID( RES_CONTINU_FILE_PROMPT ),
+ 0, 0 );
+
+ /* restart the clock with an end idle */
+ ST_EndBackupSetIdle( &op_stats );
+ }
+ }
+ break;
+
+ case BT_DDB :
+ response = TRUE;
+ break;
+
+ default:
+ response = FALSE;
+ break;
+ }
+ }
+ break;
+
+ case ASK_DISK_FULL :
+ {
+ /* get filename from dblk and display prompt */
+ INT string_size ;
+ DBLK_PTR dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+
+ dle = BSD_GetDLE( bsd_ptr ) ;
+
+ response = FALSE;
+
+ if ( CDS_GetYesFlag( CDS_GetPerm() ) == YESYES_FLAG ) {
+
+ break ;
+ }
+
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &op_stats );
+
+ string_size = strsize(mw_file_replace_ptr->destination_volume) +
+ strsize(mw_file_replace_ptr->destination_path) + 6 ;
+
+ if ( FS_GetBlockType( dblk_ptr ) == BT_FDB ) {
+ string_size += FS_SizeofOSFnameInFDB( fsh, dblk_ptr ) ;
+ }
+
+ UI_AllocPathBuffer( &buffer2, (UINT16)string_size ) ;
+
+ if ( !buffer2 ) {
+ return FALSE ;
+ }
+
+ strcpy(buffer2, mw_file_replace_ptr->destination_volume);
+ if ( DLE_GetDeviceType(dle) != FS_EMS_DRV ) {
+ strcat(buffer2, mw_file_replace_ptr->destination_path);
+ }
+
+ if ( FS_GetBlockType( dblk_ptr ) == BT_FDB ) {
+
+ FS_GetFnameFromFDB( fsh, dblk_ptr, buffer );
+ if ( strcmp( mw_file_replace_ptr->destination_path, TEXT( "\\" ) ) ) {
+ strcat(buffer2,TEXT("\\"));
+ }
+ strcat(buffer2,buffer);
+ }
+
+ yresprintf( (INT16) IDS_DISKFULL, buffer2 ) ;
+
+ response = WM_MessageBox( ID( IDS_DISKFULL_TITLE ),
+ gszTprintfBuffer,
+ WMMB_ABORTRETRYIGNOR,
+ WMMB_ICONEXCLAMATION,
+ NULL,
+ 0,
+ 0);
+
+ if ( response == WMMB_IDRETRY ) {
+ response = TRUE ;
+ } else if ( response == WMMB_IDABORT ) {
+ JobStatusBackupRestore( JOB_STATUS_ABORT );
+ response = FALSE ;
+ } else { /* must be ignore */
+ response = FALSE ;
+ }
+
+ /* restart the clock with an end idle */
+ ST_EndBackupSetIdle( &op_stats );
+
+ }
+ break;
+
+ case CORRUPT_BLOCK_PROMPT:
+ {
+ CHAR_PTR user_buff = va_arg( arg_ptr, CHAR_PTR );
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+
+ /* if user did not specify a filename, manufacture one */
+ recover_seq++;
+ sprintf( numeral, TEXT("%03d"), recover_seq );
+ strcpy( user_buff, TEXT("badfile.") );
+ strcat( user_buff, numeral );
+
+ /* log the fact that the tape read error occurred */
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_RESTORE_RECOVER, user_buff );
+ }
+ break;
+
+ default:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &op_stats );
+
+ eresprintf( RES_UNKNOWN_LOOPS_PROMPT, type );
+
+ /* restart the clock with an end idle */
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+ }
+
+
+ }
+ break;
+
+ case MSG_EOM:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_NEEDTAPE);
+ /* prompt for next tape is done during TF_NEED_NEW_TAPE? */
+ break;
+
+ case MSG_STOP_CLOCK:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &op_stats );
+ break;
+
+ case MSG_START_CLOCK:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ /* restart the clock with an end idle */
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+
+ case MSG_ACCIDENTAL_VCB:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ break;
+
+ /* miscellaneous messages */
+ case MSG_ACK_FDB_RECOVERED:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ yresprintf( (INT16) RES_RECOVERED_FILE );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_RECOVERED_FILE );
+ break;
+
+ case MSG_ACK_DDB_RECOVERED:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ yresprintf( (INT16) RES_RECOVERED_DIR );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_RECOVERED_DIR );
+ break;
+
+ case MSG_DATA_LOST:
+ {
+ UINT32 offset = va_arg( arg_ptr, UINT32 );
+ UINT16 size = va_arg( arg_ptr, UINT16 );
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+
+ yresprintf( (INT16) RES_DATA_LOST, offset, size );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_DATA_LOST, offset, size );
+
+# if defined ( OS_WIN32 )
+ {
+ mwErrorDuringBackupSet = TRUE;
+ }
+# endif //defined ( OS_WIN32 )
+
+ gb_error_during_operation = TRUE;
+ break;
+ }
+
+ case MSG_IDLE:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ break;
+
+ case MSG_RESTORED_ACTIVE:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ /* DDB/FDB are sent in if they're ever needed. */
+
+ restored_active_flag = TRUE ;
+
+ /* ignore these messages */
+ case MSG_BLOCK_BAD:
+ case MSG_BYTES_BAD:
+ case MSG_BLOCK_DELETED:
+ case MSG_BYTES_DELETED:
+ case MSG_TAPE_STATS:
+ case MSG_BLK_NOT_FOUND:
+ case MSG_BLK_DIFFERENT:
+ case MSG_LOG_DIFFERENCE:
+ case MSG_CONT_VCB:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ break;
+
+ default:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+
+# if defined ( OS_WIN32 )
+ {
+ mwErrorDuringBackupSet = TRUE;
+ }
+# endif //defined ( OS_WIN32 )
+
+ gb_error_during_operation = TRUE;
+
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &op_stats );
+
+ eresprintf( RES_UNKNOWN_MSG_HNDLR_MSG, msg );
+
+ /* restart the clock with an end idle */
+ ST_EndBackupSetIdle( &op_stats );
+
+ break;
+ }
+
+ return( response );
+
+}
+
+
+
+/*****************************************************************************
+
+ Name: PromptNextTape
+
+ Description: Function to collect user response when a new tape is
+ required from the Tape Format/Tape positioner.
+
+ Returns: UI_ABORT_POSITIONING or UI_NEW_TAPE_INSERTED
+
+*****************************************************************************/
+static INT16 PromptNextTape(
+TPOS_PTR tpos,
+DBLK_PTR cur_vcb,
+BOOLEAN valid_vcb_flag,
+UINT16 mode,
+CHAR_PTR tape,
+CHAR_PTR drive )
+{
+ INT response;
+ CHAR temp[ MAX_UI_RESOURCE_SIZE ];
+
+ zprintf( DEBUG_USER_INTERFACE, RES_UI_TPOS_TAPE_SET, tape, tpos->tape_seq_num, tpos->backup_set_num );
+
+ CDS_SetYesFlag( CDS_GetCopy(), NO_FLAG );
+
+ switch ( mode ) {
+
+ case TF_READ_CONTINUE:
+
+ if ( valid_vcb_flag &&
+ ( FS_ViewTapeIDInVCB( cur_vcb ) == (UINT32)( tpos->tape_id ) ) &&
+ ( FS_ViewTSNumInVCB( cur_vcb ) == (UINT16)( tpos->tape_seq_num - 1 ) ) ) {
+
+ response = WM_MessageBox( ID( IDS_MSGTITLE_CONTINUE ),
+ ID( RES_CONTINUE_QUEST ),
+ WMMB_YESNO,
+ WMMB_ICONQUESTION,
+ NULL, 0, 0 );
+ } else {
+
+ RSM_Sprintf( temp, ID(RES_INSERT_NEXT_TAPE),
+ tpos->tape_seq_num,
+ BE_GetCurrentDeviceName( tpos->channel ) );
+
+ response = WM_MessageBox( ID( IDS_MSGTITLE_INSERT ),
+ ID( RES_NEED_NEXT_TAPE_REWOUND ), // chs:05-10-93
+ WMMB_OKCANCEL,
+ WMMB_ICONQUESTION,
+ temp,
+ IDRBM_LTAPE, 0 );
+ }
+ break;
+
+ case TF_READ_OPERATION:
+ default:
+
+ if ( valid_vcb_flag &&
+ ( FS_ViewTapeIDInVCB( cur_vcb ) == (UINT32)( tpos->tape_id ) ) &&
+ ( FS_ViewTSNumInVCB( cur_vcb ) == (UINT16)( tpos->tape_seq_num - 1 ) ) ) {
+
+ RSM_Sprintf( temp, ID(RES_INSERT_NEXT_TAPE),
+ tpos->tape_seq_num,
+ BE_GetCurrentDeviceName( tpos->channel ) );
+
+ response = WM_MessageBox( ID( IDS_MSGTITLE_INSERT ),
+ ID( RES_NEED_NEXT_TAPE_REWOUND ), // chs:05-10-93
+ WMMB_OKCANCEL,
+ WMMB_ICONQUESTION,
+ temp,
+ IDRBM_LTAPE, 0 );
+ } else {
+
+ RSM_Sprintf( temp, ID(RES_TAPE_REQUEST), drive, tape,
+ ( tpos->tape_seq_num == -1) ? 1 : tpos->tape_seq_num );
+
+ response = WM_MessageBox( ID( IDS_MSGTITLE_INSERT ),
+ temp,
+ WMMB_YESNO,
+ WMMB_ICONQUESTION,
+ ID( RES_CONTINUE_QUEST ),
+ 0, 0 );
+ }
+ break;
+
+ }
+
+ if ( response ) {
+#ifdef OS_WIN32
+ NtDemoChangeTape( (UINT16)(( tpos->tape_seq_num == -1) ? 1u : tpos->tape_seq_num ) );
+ tape_retries = mwTapeSettlingCount ;
+#endif
+ response = UI_NEW_TAPE_INSERTED;
+ }
+ else {
+ response = UI_ABORT_POSITIONING;
+ }
+
+ return( (INT16)response );
+}
+
+/**************************************************
+ Returns the current stats structure and path/file
+ name being processed.
+***************************************************/
+INT UI_GetRestoreCurrentStatus(
+STATS *Stats,
+CHAR *Path,
+INT PathSize )
+{
+
+ INT SpaceNeeded = 2;
+
+ if ( Stats != NULL ) {
+ memcpy( Stats, &op_stats, sizeof( STATS ) );
+ }
+
+ SpaceNeeded += strlen( mwCurrentDrive );
+ SpaceNeeded += strlen( mwCurrentPath );
+ SpaceNeeded += strlen( mwCurrentFile );
+
+ if ( Path == NULL || PathSize < 0 ) {
+ return( FAILURE );
+ }
+
+ strcpy( Path, TEXT( "" ) );
+
+ if ( (INT)SpaceNeeded < PathSize ) {
+ strcpy( Path, mwCurrentDrive );
+ strcat( Path, mwCurrentPath );
+ if (strcmp(mwCurrentPath, TEXT("\\")) != 0)
+ {
+ strcat( Path, TEXT( "\\" ) );
+ }
+ strcat( Path, mwCurrentFile );
+ }
+ else {
+ if ( (INT)strlen( mwCurrentFile ) < PathSize ) {
+ strcpy( Path, mwCurrentFile );
+ }
+ else {
+ return( FAILURE );
+ }
+ }
+
+ return( SUCCESS );
+
+}
diff --git a/private/utils/ntbackup/src/do_tens.c b/private/utils/ntbackup/src/do_tens.c
new file mode 100644
index 000000000..a9ff13754
--- /dev/null
+++ b/private/utils/ntbackup/src/do_tens.c
@@ -0,0 +1,822 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: do_tens.c
+
+ Description: Functions for tape tension and erase including startup to call
+ LP_Tension_Engine, tape positioning and message handling
+
+ $Log: G:\ui\logfiles\do_tens.c_v $
+
+ Rev 1.40.2.3 20 Jul 1994 19:32:54 STEVEN
+fix format message
+
+ Rev 1.40.2.2 12 Jul 1994 19:34:06 STEVEN
+write protected tapes cause errors not success
+
+ Rev 1.40.2.1 24 May 1994 20:07:38 GREGG
+Improved handling of ECC, SQL, FUTURE_VER and OUT_OF_SEQUENCE tapes.
+
+ Rev 1.40.2.0 28 Jan 1994 18:30:54 GREGG
+Handle TF_UNRECOGNIZED_MEDIA.
+
+ Rev 1.40 14 Jul 1993 14:33:40 CARLS
+added check for transfer tape on erase operation
+
+ Rev 1.39 06 Jul 1993 16:19:20 KEVINS
+Status monitor additions.
+
+ Rev 1.38 28 Jun 1993 13:32:22 CARLS
+added VLM_CloseAll
+
+ Rev 1.37 22 Jun 1993 15:28:42 CARLS
+added clock routine for Icon animation
+
+ Rev 1.36 30 Apr 1993 15:53:32 chrish
+NOSTRADAMOUS EPR 0391: Added logic to display "Operation completed" instead of
+"... operation completed successfully" when user aborts an operation.
+
+ Rev 1.35 12 Mar 1993 14:42:14 CARLS
+changes for format tape
+
+ Rev 1.34 27 Jan 1993 14:24:16 STEVEN
+updates from msoft
+
+ Rev 1.33 20 Oct 1992 15:44:36 MIKEP
+gbCurrentOperation
+
+ Rev 1.32 07 Oct 1992 14:48:34 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.31 04 Oct 1992 19:34:38 DAVEV
+Unicode Awk pass
+
+ Rev 1.30 10 Sep 1992 17:44:56 DAVEV
+Integrate MikeP's changes from Microsoft
+
+ Rev 1.29 24 Aug 1992 15:27:22 DAVEV
+Event Logging
+
+ Rev 1.28 23 Jun 1992 17:35:46 DAVEV
+fix 'foreign tape' messgae
+
+ Rev 1.27 11 Jun 1992 15:20:42 DAVEV
+do not display status message 'Examine <log file> for more info' if not logging
+
+ Rev 1.26 10 Jun 1992 10:11:20 BURT
+Fix ANSI func lists
+
+ Rev 1.25 28 May 1992 10:10:16 MIKEP
+fix return type
+
+ Rev 1.24 19 May 1992 11:58:10 MIKEP
+mips changes
+
+ Rev 1.23 14 May 1992 17:39:18 MIKEP
+nt pass 2
+
+ Rev 1.22 08 Apr 1992 17:18:58 CARLS
+reset the gb_error_flag at start of operation
+
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+static UINT16 TensionTapePositioner( UINT16, TPOS_PTR, BOOLEAN, DBLK_PTR, UINT16 );
+static INT16 TensionMessageHandler( UINT16, INT32, BSD_PTR, FSYS_HAND, TPOS_PTR, ... );
+
+static VOID clock_routine( VOID );
+static VOID do_tension_init( VOID );
+static VOID do_tension_process( VOID );
+
+static BOOLEAN clock_ready_flag;
+static HTIMER timer_handle;
+static INT mw_oper_type;
+static INT16 mw_ret_val;
+static UINT16 mw_last_msg = 0xFFFF;
+
+
+/*****************************************************************************
+
+ Name: do_tension
+
+ Description: This procedure kicks off the tension/erase function.
+
+ Returns: SUCCESS
+ ABNORMAL_TERMINATION
+
+ Notes: The return value mw_ret_val is set in do_tension_process().
+
+*****************************************************************************/
+
+INT do_tension( INT16 oper_type )
+{
+ DBLK_PTR vcb;
+ BOOLEAN prompt;
+ CHAR title[ MAX_UI_RESOURCE_SIZE ];
+ CHAR text[ MAX_UI_RESOURCE_SIZE ];
+
+ SetStatusBlock(IDSM_OPERATIONSTATUS, STAT_OPER_TENSION);
+ gbCurrentOperation = OPERATION_TENSION;
+ mw_oper_type = oper_type;
+ mw_ret_val = SUCCESS;
+ mw_last_msg = 0xFFFF;
+
+ // If it's a bad tape then don't try to read the VCB.
+ // Or if poll drive is disabled.
+
+ if ( VLM_GetDriveStatus( &vcb ) == VLM_BAD_TAPE ) {
+
+ if ( mw_oper_type == SECURITY_ERASE_OPER ) {
+ mw_oper_type = SEC_ERASE_NO_READ_OPER;
+ }
+
+ if ( mw_oper_type == ERASE_OPER ) {
+ mw_oper_type = ERASE_NO_READ_OPER;
+ }
+
+ }
+
+ prompt = FALSE;
+
+ /* poll drive is disabled */
+ if ( VLM_GetDriveStatus( &vcb ) == VLM_DISABLED ) {
+
+ if ( mw_oper_type == SECURITY_ERASE_OPER ) {
+ prompt = TRUE;
+ mw_oper_type = SEC_ERASE_NO_READ_OPER;
+ }
+
+ if ( mw_oper_type == ERASE_OPER ) {
+ prompt = TRUE;
+ mw_oper_type = ERASE_NO_READ_OPER;
+ }
+ }
+
+ if ( prompt ) {
+
+ RSM_StringCopy( IDS_TITLEERASEWARNING, title, MAX_UI_RESOURCE_LEN );
+ RSM_StringCopy( IDS_TEXTERASEWARNING, text, MAX_UI_RESOURCE_LEN );
+
+ if ( WM_MsgBox ( title,
+ text,
+ WMMB_OKCANCEL,
+ WMMB_ICONQUESTION ) != WMMB_IDOK ) {
+
+ return( FALSE );
+ }
+ }
+
+ gb_error_during_operation = FALSE;
+
+ VLM_CloseAll();
+
+ do_tension_init();
+ do_tension_process();
+
+ gbCurrentOperation = OPERATION_NONE;
+ SetStatusBlock(IDSM_OPERATIONSTATUS, STAT_OPER_IDLE);
+ return( mw_ret_val );
+}
+
+
+/*****************************************************************************
+
+ Name: do_tension_init
+
+ Description: Initialize the text on the RTD.
+
+ Returns: none.
+
+*****************************************************************************/
+
+VOID do_tension_init( VOID )
+{
+ /* initialize the text for either a tension or erase operation */
+
+ JobStatusTension( JOB_TENSION_CREATE_DIALOG );
+
+ if ( mw_oper_type == TENSION_OPER ) { /* tension operation */
+ yresprintf( IDS_DLGTITLEJOBSTATTENSION );
+ }
+ else if ( mw_oper_type == FORMAT_OPER ) { /* format operation */
+ yresprintf( IDS_DLGTITLEJOBSTATFORMAT );
+ }
+ else { /* erase operation */
+ yresprintf( IDS_DLGTITLEJOBSTATERASE );
+ }
+ JobStatusTension( JOB_TENSION_TENSION_TITLE );
+
+ return;
+}
+
+
+/*****************************************************************************
+
+ Name: do_tension_process
+
+ Description: Performs the actual process. It sets up the lis structure,
+ etc. and calls the tension tape engine.
+
+ Returns: none.
+
+ Notes: sets mw_ret_val to SUCCESS or error.
+
+*****************************************************************************/
+
+VOID do_tension_process( VOID )
+{
+ LIS lis;
+ BSD_HAND temp_bsd_list;
+ Q_ELEM_PTR old_channel_link;
+
+
+ temp_bsd_list = (BSD_HAND)malloc( sizeof(BSD_LIST) );
+ if ( temp_bsd_list == NULL ) {
+ mw_ret_val = ABNORMAL_TERMINATION;
+ return;
+ }
+
+ InitQueue( &(temp_bsd_list->current_q_hdr) );
+ InitQueue( &(temp_bsd_list->last_q_hdr) );
+
+ lis.oper_type = (INT16)mw_oper_type;
+
+ lis.auto_det_sdrv = FALSE;
+ gb_last_operation = mw_oper_type;
+
+ lis.bsd_list = temp_bsd_list;
+
+ /* check for a valid bsd first, set to search for first set if needed */
+
+ mw_ret_val = BSD_Add( temp_bsd_list,
+ &lis.curr_bsd_ptr,
+ BEC_CloneConfig( CDS_GetPermBEC() ),
+ NULL, NULL,
+ (UINT32)-1L, (UINT16)-1, -1,
+ thw_list, NULL );
+
+ if ( mw_ret_val == OUT_OF_MEMORY ) {
+ mw_ret_val = ABNORMAL_TERMINATION;
+ return;
+ }
+ /* get the first bset on the tape */
+ BSD_SetTapePos( lis.curr_bsd_ptr, (UINT32)-1L, (UINT16)-1, (UINT16)-1 );
+
+ /* setup lis structure */
+ lis.tape_pos_handler = TensionTapePositioner; /* set tape positioner to call */
+ lis.message_handler = TensionMessageHandler; /* set message handler to call */
+ lis.abort_flag_ptr = &gb_abort_flag; /* set abort flag address */
+
+ LP_SetAbortFlag( &lis, CONTINUE_PROCESSING );
+ JobStatusAbort( lis.abort_flag_ptr );
+
+ clock_ready_flag = FALSE; // Wait on bset to start
+
+ timer_handle = WM_HookTimer( clock_routine, 1 );
+
+ PD_StopPolling();
+
+ // Do one drive only
+
+ old_channel_link = thw_list->channel_link.q_next;
+ thw_list->channel_link.q_next = NULL;
+
+ LP_Tension_Tape_Engine( &lis );
+
+ // reset multiple drives
+
+ thw_list->channel_link.q_next = old_channel_link;
+
+ PD_StartPolling();
+
+ WM_UnhookTimer( timer_handle );
+
+ JobStatusTension(JOB_TENSION_ABORT_OFF);
+
+ BSD_Remove( lis.curr_bsd_ptr );
+
+ free( temp_bsd_list );
+
+ return;
+}
+
+/*****************************************************************************
+
+ Name: TensionTapePositioner
+
+ Description: Tape positioning routine to be called by Tape Format Layer
+ during tension and erase operations
+
+ Returns:
+
+*****************************************************************************/
+static UINT16 TensionTapePositioner(
+UINT16 message,
+TPOS_PTR tpos,
+BOOLEAN curr_valid_vcb,
+DBLK_PTR cur_vcb,
+UINT16 mode )
+{
+ UINT16 response = UI_ACKNOWLEDGED;
+ LIS_PTR lis_ptr = ( LIS_PTR )tpos->reference;
+ CHAR_PTR drive_name;
+
+ curr_valid_vcb;
+ mode;
+
+ /* get a pointer to the name of the current tape device */
+ drive_name = BE_GetCurrentDeviceName( tpos->channel );
+
+ /* Check for user abort */
+ if ( UI_CheckUserAbort( message ) ) {
+ return UI_ABORT_POSITIONING ;
+ }
+
+ /* Discontinue dots if required */
+
+ /* check for writing to write-protected tape */
+ if ( lis_ptr->oper_type != TENSION_OPER ) {
+ if ( UI_CheckWriteProtectedDevice( message, tpos, drive_name ) ) {
+ gb_error_during_operation = TRUE ;
+ return UI_ABORT_POSITIONING ;
+ }
+ }
+
+ switch( (INT16)message ) {
+
+ case TF_IDLE_NOBREAK:
+ case TF_IDLE:
+ case TF_SKIPPING_DATA:
+ case TF_MOUNTING:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ break;
+
+ case TF_VCB_BOT:
+ case TF_POSITIONED_AT_A_VCB:
+ case TF_REQUESTED_VCB_FOUND:
+ case TF_VCB_EOD:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ /* if performing tension operation, simply return to TF layer */
+ if ( lis_ptr->oper_type == TENSION_OPER ) {
+ response = UI_END_POSITIONING;
+ break;
+ }
+ else {
+
+ /* prompt user if they really want to erase this tape */
+
+ /* Check for archive tape, and warn user */
+ if ( FS_GetAttribFromVCB( cur_vcb ) & VCB_ARCHIVE_BIT ||
+ IsTransferTape( FS_ViewTapeIDInVCB( cur_vcb ) ) ) {
+
+ CDS_SetYesFlag( CDS_GetCopy(), NO_FLAG );
+
+ if ( ! WM_MessageBox( ID( IDS_MSGTITLE_ERASE ),
+ ID( RES_ARCHIVE_REPLACE_WARNING ),
+ WMMB_YESNO,
+ WMMB_ICONQUESTION,
+ ID( RES_CONTINUE_QUEST ),
+ 0, 0 ) ) {
+ response = UI_ABORT_POSITIONING;
+ break;
+ }
+ }
+
+ QTC_RemoveTape( FS_ViewTapeIDInVCB( cur_vcb ),
+ FS_ViewTSNumInVCB( cur_vcb ) );
+ VLM_RemoveTape( FS_ViewTapeIDInVCB( cur_vcb ),
+ FS_ViewTSNumInVCB( cur_vcb ), TRUE );
+
+ response = UI_END_POSITIONING;
+ }
+ break;
+
+ case TF_RETENSIONING:
+ case TF_ERASING:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ TensionMessageHandler( MSG_START_BACKUP_SET, lis_ptr->pid, NULL, NULL, NULL, lis_ptr->oper_type );
+ break;
+
+ case TF_EMPTY_TAPE:
+ case TF_NO_MORE_DATA:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ response = UI_END_POSITIONING;
+ break;
+
+ case TF_INVALID_VCB:
+ case TF_FUTURE_REV_MTF:
+ case TF_MTF_ECC_TAPE:
+ case TF_SQL_TAPE:
+ case TF_TAPE_OUT_OF_ORDER:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ SetStatusBlock(IDSM_DRIVESTATUS, STAT_DRIVE_FOREIGN);
+
+ yresprintf( RES_FOREIGN_TAPE_MSG, drive_name );
+
+ // Fix 6/23: only one message box with 'Continue or Cancel' option
+ //WM_MessageBox( NULL,
+ // gszTprintfBuffer,
+ // WMMB_OK,
+ // WMMB_ICONINFORMATION,
+ // NULL, 0, 0 );
+
+ CDS_SetYesFlag( CDS_GetCopy(), NO_FLAG );
+
+ /* go ahead and retension foreign tapes */
+ if ( lis_ptr->oper_type == TENSION_OPER ) {
+ response = UI_END_POSITIONING;
+
+ /* prompt user before erasing foreign tapes */
+ }
+ else {
+ if ( WM_MessageBox( ID( IDS_MSGTITLE_ERASE ),
+ //ID( RES_ERASE_QUEST ),
+ gszTprintfBuffer,
+ WMMB_CONTCANCEL, //WMMB_YESNO,
+ WMMB_ICONQUESTION,
+ NULL, 0, 0 ) ) {
+ response = UI_END_POSITIONING;
+ } else {
+ response = UI_ABORT_POSITIONING;
+ }
+ }
+ break;
+
+ // Kludge to handle write protected tapes during erase_no_read
+ // operations.
+
+ case TFLE_WRITE_PROTECT:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ if ( lis_ptr->oper_type == TENSION_OPER ) {
+ response = UI_END_POSITIONING;
+ }
+ else {
+ eresprintf( RES_WRITE_PROT, drive_name );
+ response = UI_ABORT_POSITIONING;
+ }
+ break;
+
+ case TF_NO_TAPE_PRESENT:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_NEEDTAPE);
+ SetStatusBlock(IDSM_DRIVESTATUS, STAT_DRIVE_EMPTY);
+ response = UI_InsertTape( drive_name );
+ break;
+
+ case TF_READ_ERROR:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ if ( lis_ptr->oper_type == TENSION_OPER ) {
+ response = UI_END_POSITIONING;
+ }
+ else {
+ SetStatusBlock(IDSM_DRIVESTATUS, STAT_DRIVE_ERROR);
+ gb_error_during_operation = TRUE;
+
+ UI_ProcessErrorCode( TFLE_DRIVE_FAILURE, &response, tpos->channel );
+
+// response = UI_HandleTapeReadError( drive_name );
+ }
+ break;
+
+ case TF_UNRECOGNIZED_MEDIA:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ if ( lis_ptr->oper_type == TENSION_OPER ||
+ lis_ptr->oper_type == FORMAT_OPER ) {
+
+ response = UI_END_POSITIONING;
+ }
+ else {
+ SetStatusBlock(IDSM_DRIVESTATUS, STAT_DRIVE_FOREIGN);
+ yresprintf( (INT16) IDS_VLMUNFORMATEDTEXT );
+ WM_MessageBox( ID( IDS_VLMUNFORMATEDTITLE ) ,
+ gszTprintfBuffer ,
+ WMMB_OK,
+ WMMB_ICONEXCLAMATION, NULL, 0, 0 );
+ response = UI_ReplaceTape( drive_name );
+ }
+ break;
+
+ case TF_SEARCHING:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ if ( mw_last_msg != message ) {
+ yresprintf( (INT16)RES_SEARCHING );
+ JobStatusTension(JOB_TENSION_LISTBOX);
+ mw_last_msg = message;
+ }
+ break;
+
+ case TF_REWINDING:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ if ( mw_last_msg != message ) {
+ yresprintf( (INT16)RES_REWINDING );
+ JobStatusTension(JOB_TENSION_LISTBOX);
+ mw_last_msg = message;
+ }
+ break;
+
+ case TF_DRIVE_BUSY:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ SetStatusBlock(IDSM_DRIVESTATUS, STAT_DRIVE_BUSY);
+ if ( mw_last_msg != message ) {
+ yresprintf( (INT16)RES_WAITING );
+ JobStatusTension(JOB_TENSION_LISTBOX);
+ mw_last_msg = message;
+ }
+ break;
+
+ case TF_NEED_NEW_TAPE:
+ case TF_WRONG_TAPE:
+ case TF_ACCIDENTAL_VCB:
+ case TF_AT_EOT:
+ case TF_CONT_TAPE_IN_FAMILY:
+ case TF_END_CHANNEL:
+ case TF_END_POSITIONING:
+ case TF_FAST_SEEK_EOD:
+ case TF_NEED_REWIND_FIRST:
+ case TF_NO_MORE_ENTRIES:
+ case TF_NO_SC_FOR_SET:
+ case TF_NO_SM_FOR_FAMILY:
+ case TF_NO_SM_ON_TAPE:
+ case TF_POSITIONED_FOR_WRITE:
+
+ /* These should never be passed in by TF for Tension/Erase */
+ break;
+
+ default:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+ eresprintf( RES_UNKNOWN_TF_MSG, message );
+ response = UI_ABORT_POSITIONING;
+ break;
+ }
+
+ return( response );
+
+}
+
+/*****************************************************************************
+
+ Name: TensionMessageHandler
+
+ Description: Message handler for tension and erase operations
+
+ Returns:
+
+*****************************************************************************/
+static INT16 TensionMessageHandler(
+UINT16 msg,
+INT32 pid,
+BSD_PTR bsd_ptr,
+FSYS_HAND fsh,
+TPOS_PTR tpos,
+... )
+{
+ INT16 response = MSG_ACK;
+ static STATS op_stats;
+ INT16 res_id;
+ va_list arg_ptr;
+ INT16 oper_type;
+ DBLK_PTR vcb_ptr;
+ INT16 error;
+
+ /* future use */
+ pid;
+ bsd_ptr;
+ fsh;
+
+ /* set up first argument */
+ va_start( arg_ptr, tpos );
+
+ switch( msg ) {
+
+ case MSG_START_OPERATION:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+# if defined ( OS_WIN32 )
+ {
+ if ( mw_oper_type == TENSION_OPER )
+ {
+ OMEVENT_LogBeginRetension ();
+ }
+ else
+ {
+ OMEVENT_LogBeginErase ();
+ }
+ }
+# endif //defined ( OS_WIN32 )
+
+ lresprintf( LOGGING_FILE, LOG_START, FALSE );
+ break;
+
+ case MSG_END_OPERATION:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+# if defined ( OS_WIN32 )
+ {
+ if ( mw_oper_type == TENSION_OPER )
+ {
+ OMEVENT_LogEndRetension ( gb_error_during_operation );
+ }
+ else
+ {
+ OMEVENT_LogEndErase ( gb_error_during_operation );
+ }
+ }
+# endif //defined ( OS_WIN32 )
+
+ lresprintf( LOGGING_FILE, LOG_END );
+ if ( gb_error_during_operation == TRUE ) {
+
+ yresprintf( RES_ERROR_DURING_OPERATION );
+ JobStatusTension(JOB_TENSION_LISTBOX);
+
+
+ if ( CDS_GetOutputDest( CDS_GetPerm() ) == LOG_TO_FILE
+ && CDS_GetLogLevel ( CDS_GetPerm() ) != LOG_DISABLED ) {
+ yresprintf( RES_ERROR_FILE_TO_EXAMINE, LOG_GetCurrentLogName() );
+ JobStatusTension(JOB_TENSION_LISTBOX);
+ }
+
+ } else {
+
+ if ( gb_abort_flag != CONTINUE_PROCESSING ) { // chs:04-30-93
+ yresprintf( (INT16) RES_OPERATION_COMPLETED ) ; // chs:04-30-93
+ } else { // chs:04-30-93
+ yresprintf( RES_NOERROR_DURING_OPERATION ); // chs:04-30-93
+ } // chs:04-30-93
+
+ JobStatusTension(JOB_TENSION_LISTBOX);
+ }
+ break;
+
+ case MSG_START_BACKUP_SET:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+
+ oper_type = va_arg( arg_ptr, INT16 );
+
+ ST_StartBackupSet( &op_stats );
+
+ clock_ready_flag = TRUE;
+
+ /* set appropriate resource id for operation type for messages */
+ switch( oper_type ) {
+
+ case TENSION_OPER:
+ res_id = RES_TENSION_STARTED;
+ break;
+
+ case FORMAT_OPER:
+ res_id = RES_FORMAT_STARTED;
+ break;
+
+ case ERASE_OPER:
+ case ERASE_NO_READ_OPER:
+ case ERASE_FMARK_ONLY:
+ res_id = RES_ERASE_STARTED;
+ break;
+
+ case SEC_ERASE_NO_READ_OPER:
+ case SECURITY_ERASE_OPER:
+ res_id = RES_SEC_ERASE_STARTED;
+ break;
+
+ }
+
+ UI_Time( &op_stats, res_id, UI_START );
+ JobStatusTension(JOB_TENSION_LISTBOX);
+
+ break;
+
+ case MSG_END_BACKUP_SET:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+
+ oper_type = va_arg( arg_ptr, UINT16 );
+
+ ST_EndBackupSet( &op_stats );
+
+ /* display and log any abort conditions */
+ UI_ConditionAtEnd( );
+
+ clock_ready_flag = FALSE;
+
+ /* set appropriate resource id for operation type for messages */
+ switch( oper_type ) {
+
+ case TENSION_OPER:
+ res_id = RES_TENSION_COMPLETED;
+ break;
+
+ case FORMAT_OPER:
+ res_id = RES_FORMAT_COMPLETED;
+ break;
+
+ case ERASE_OPER:
+ case ERASE_NO_READ_OPER:
+ case ERASE_FMARK_ONLY:
+ res_id = RES_ERASE_COMPLETED;
+ break;
+
+ case SEC_ERASE_NO_READ_OPER:
+ case SECURITY_ERASE_OPER:
+ res_id = RES_SEC_ERASE_COMPLETED;
+ break;
+
+ }
+
+ UI_Time( &op_stats, res_id, UI_END );
+ JobStatusTension(JOB_TENSION_LISTBOX);
+
+ break;
+
+ case MSG_ACCIDENTAL_VCB:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+
+ vcb_ptr = va_arg( arg_ptr, DBLK_PTR );
+
+ QTC_RemoveTape( FS_ViewTapeIDInVCB( vcb_ptr ),
+ FS_ViewTSNumInVCB( vcb_ptr ) );
+ VLM_RemoveTape( FS_ViewTapeIDInVCB( vcb_ptr ),
+ FS_ViewTSNumInVCB( vcb_ptr ), TRUE );
+ break;
+
+ case MSG_TBE_ERROR:
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+
+ error = va_arg( arg_ptr, INT16 );
+
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &op_stats );
+
+ UI_ProcessErrorCode( error, &response, tpos->channel );
+
+ /* restart the clock with an end idle */
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+
+ /* ignore these messages */
+ case MSG_LOG_BLOCK :
+ case MSG_IDLE:
+ case MSG_BLOCK_BAD:
+ case MSG_BYTES_BAD:
+ case MSG_BLOCK_DELETED:
+ case MSG_BYTES_DELETED:
+ case MSG_TAPE_STATS:
+ case MSG_BLK_NOT_FOUND:
+ case MSG_BLK_DIFFERENT:
+ case MSG_LOG_DIFFERENCE:
+ case MSG_EOM:
+ case MSG_STOP_CLOCK:
+ case MSG_START_CLOCK:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ break;
+
+ default:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+ gb_error_during_operation = TRUE;
+
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &op_stats );
+
+ eresprintf( RES_UNKNOWN_MSG_HNDLR_MSG, msg );
+
+ /* restart the clock with an end idle */
+ ST_EndBackupSetIdle( &op_stats );
+
+ break;
+ }
+
+ return( response );
+
+}
+/*****************************************************************************
+
+ Name: clock_routine
+
+ Description: one second time to update the Runtime status
+ elapsed time
+
+ Returns: void
+
+*****************************************************************************/
+
+static VOID clock_routine( VOID )
+{
+
+ if ( clock_ready_flag ) {
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+ {
+ WM_AnimateAppIcon ( IDM_OPERATIONSVERIFY, FALSE );
+ }
+# endif // !defined ( OEM_MSOFT ) // unsupported feature
+
+ }
+}
diff --git a/private/utils/ntbackup/src/do_very.c b/private/utils/ntbackup/src/do_very.c
new file mode 100644
index 000000000..a90974426
--- /dev/null
+++ b/private/utils/ntbackup/src/do_very.c
@@ -0,0 +1,1859 @@
+
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: do_very.c
+
+ Description: Tape Verify tape positioning and message handler
+
+ $Log: J:/UI/LOGFILES/DO_VERY.C_V $
+
+ Rev 1.78.1.5 16 Jun 1994 17:44:56 GREGG
+Fixed setting and clearing of YESYES flag.
+
+ Rev 1.78.1.4 24 May 1994 20:08:20 GREGG
+Improved handling of ECC, SQL, FUTURE_VER and OUT_OF_SEQUENCE tapes.
+
+ Rev 1.78.1.3 04 May 1994 14:23:16 STEVEN
+fix dlt settlin timeime
+
+ Rev 1.78.1.2 26 Apr 1994 18:56:56 STEVEN
+fix net disconnect bug
+
+ Rev 1.78.1.1 01 Feb 1994 19:40:30 ZEIR
+tuned tape settling logic to work same as restore's
+
+ Rev 1.78.1.0 17 Jan 1994 15:30:56 MIKEP
+fix unicode warnings
+
+ Rev 1.78 15 Sep 1993 13:53:06 CARLS
+changes for displaying full path/file name detail if Log files
+
+ Rev 1.77 22 Jul 1993 18:35:40 KEVINS
+Corrected macro name.
+
+ Rev 1.76 22 Jul 1993 18:28:52 KEVINS
+Added support for tape drive settling time.
+
+ Rev 1.75 15 Jul 1993 16:32:10 CARLS
+changed response on TF_WRONG_TAPE
+
+ Rev 1.74 27 Jun 1993 14:07:08 MIKEP
+continue work on status monitor stuff
+
+ Rev 1.73 18 Jun 1993 16:49:14 CARLS
+added NtDemoChangeTape calls for NtDemo
+
+ Rev 1.72 14 Jun 1993 20:25:14 MIKEP
+enable c++
+
+ Rev 1.71 08 Jun 1993 10:58:30 chrish
+Verify logging information, added more info such as the drive where the
+files are located.
+
+ Rev 1.70 18 May 1993 16:44:54 chrish
+CAYMAN EPR 0259: Can also go into Nostradamus. During a command line backup
+with verify ... on the veryify the Tape label displayed a null pointer. This
+is because the BSD member is a null pointer and no check was made to test
+for it before displaying it. Made change to display a null string if we
+get a null pointer.
+
+
+
+
+ Rev 1.69 14 May 1993 14:39:50 DARRYLP
+Modified event logging text
+
+ Rev 1.68 10 May 1993 16:37:42 chrish
+NOSTRADAMUS EPR 0400 and 0172 - Did not catch the fixes in the verify and
+restore process of the backup app. When spanning tape it gave the user
+wrong message to wait for tape to rewind, when it had already completed
+rewinding. Corrected by display proper message to user.
+
+ Rev 1.67 27 Apr 1993 16:21:48 DARRYLP
+Added status monitor functionality.
+
+ Rev 1.66 18 Apr 1993 16:23:38 BARRY
+Don't use 'free' on buffers allocated with UI_AllocPathBuffer.
+
+ Rev 1.65 09 Apr 1993 11:36:32 BARRY
+Clear gbAbortAtEOF before starting operation.
+
+ Rev 1.64 02 Apr 1993 15:49:38 CARLS
+changes for DC2000 unformatted tape
+
+ Rev 1.63 09 Mar 1993 10:57:54 MIKEP
+update clock stats at end of set
+
+ Rev 1.62 07 Mar 1993 16:33:56 GREGG
+Call _sleep for OS_WIN32 only.
+
+ Rev 1.61 23 Feb 1993 14:05:02 TIMN
+Added code to abort a Verify Operation EPR(0241)
+
+ Rev 1.60 22 Feb 1993 11:00:20 chrish
+Added changes received from MikeP.
+Added the ability to display hours to the clock_routine so it matches
+the do_back.c, do_cat.c and do_rest.c if the backup takes longer than 59
+minutes.
+
+ Rev 1.60 22 Feb 1993 10:43:26 chrish
+
+ Rev 1.59 17 Feb 1993 10:40:30 STEVEN
+changes from mikep
+
+ Rev 1.58 27 Jan 1993 14:33:04 STEVEN
+handle MSG_CONT_VCB message
+
+ Rev 1.57 18 Jan 1993 16:05:58 STEVEN
+add support for stream id error message
+
+ Rev 1.56 14 Dec 1992 12:18:16 DAVEV
+Enabled for Unicode compile
+
+ Rev 1.55 11 Nov 1992 16:31:34 DAVEV
+UNICODE: remove compile warnings
+
+ Rev 1.54 05 Nov 1992 17:03:14 DAVEV
+fix ts
+
+ Rev 1.52 20 Oct 1992 17:01:04 MIKEP
+getstatus calls
+
+ Rev 1.51 20 Oct 1992 15:44:00 MIKEP
+gbCurrentOperation
+
+ Rev 1.50 07 Oct 1992 14:47:10 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.49 04 Oct 1992 19:34:46 DAVEV
+Unicode Awk pass
+
+ Rev 1.48 31 Aug 1992 09:42:36 DAVEV
+OEM_MSOFT: Added Event Logging
+
+ Rev 1.47 27 Jul 1992 14:50:10 JOHNWT
+ChuckB fixed references for NT.
+
+ Rev 1.46 27 Jul 1992 11:07:48 JOHNWT
+ChuckB checked in for John Wright, who is no longer with us.
+
+ Rev 1.45 07 Jul 1992 15:33:24 MIKEP
+unicode changes
+
+ Rev 1.44 10 Jun 1992 10:07:40 BURT
+Fix ANSI func lists
+
+ Rev 1.43 28 May 1992 10:08:02 MIKEP
+fix return type
+
+ Rev 1.42 26 May 1992 10:30:46 MIKEP
+loop fixes
+
+ Rev 1.41 19 May 1992 11:58:30 MIKEP
+mips changes
+
+ Rev 1.40 14 May 1992 17:39:24 MIKEP
+nt pass 2
+
+ Rev 1.39 11 May 1992 19:31:02 STEVEN
+64bit and large path sizes
+
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+static UINT16 tpos_rout( UINT16, TPOS_PTR, BOOLEAN, DBLK_PTR, UINT16 );
+static INT16 msg_hndlr( UINT16, INT32, BSD_PTR, FSYS_HAND, TPOS_PTR, ... );
+static VOID OpenVerifyScript( STATS_PTR, BSD_PTR, CHAR_PTR );
+static INT16 PromptNextTape( TPOS_PTR, DBLK_PTR, BOOLEAN, UINT16, CHAR_PTR, CHAR_PTR );
+
+static VOID clock_routine( VOID );
+static VOID do_verify_init( VOID );
+static VOID do_verify_process( VOID );
+
+static BOOLEAN clock_ready_flag;
+static HTIMER timer_handle;
+static STATS op_stats;
+static INT mw_oper_type;
+static INT mw_rewind;
+
+#ifdef OEM_EMS
+extern INT32 RT_BSD_OsId ;
+#endif
+
+#ifdef OS_WIN32
+static UINT16 mwTapeSettlingCount,
+ tape_retries;
+#endif
+
+/*****************************************************************************
+
+ Name: do_verify
+
+ Description: Main entry point for tape verification function.
+
+ Returns: SUCCESS
+ ABNORMAL_TERMINATION
+
+*****************************************************************************/
+
+INT do_verify( INT16 oper_type )
+{
+ INT16 ret_val = SUCCESS;
+ BSD_PTR bsd_ptr;
+
+ SetStatusBlock(IDSM_OPERATIONSTATUS, STAT_OPER_VERIFY);
+ gbCurrentOperation = OPERATION_VERIFY;
+ gbAbortAtEOF = FALSE;
+ gbAbortAtEOF = FALSE;
+ mw_oper_type = oper_type;
+ mw_rewind = TRUE;
+
+#ifdef OS_WIN32
+ /* we will check for tape every 3 seconds, but prompt user by interval
+ specified in INI file */
+ mwTapeSettlingCount = CDS_GetTapeDriveSettlingTime ( CDS_GetPerm () ) / 3;
+
+ if ( CDS_GetTapeDriveName( CDS_GetPerm( ) ) ) {
+
+ CHAR DriveName[80] ;
+
+ strncpy( DriveName, (CHAR_PTR)CDS_GetTapeDriveName( CDS_GetPerm( ) ), 80 ) ;
+ DriveName[79] = '\0' ;
+ strlwr( DriveName ) ;
+ if( strstr( DriveName, TEXT( "cipher" ) ) != NULL ||
+ ( strstr( DriveName, TEXT( "dec" ) ) != NULL &&
+ ( strstr( DriveName, TEXT( "thz02" ) ) != NULL ||
+ strstr( DriveName, TEXT( "tz86" ) ) != NULL ||
+ strstr( DriveName, TEXT( "tz87" ) ) != NULL ||
+ strstr( DriveName, TEXT( "dlt2700" ) ) != NULL ||
+ strstr( DriveName, TEXT( "dlt2000" ) ) != NULL ) ) ) {
+ mwTapeSettlingCount *= 2 ;
+ }
+ }
+
+ tape_retries = 0 ;
+#endif
+
+ do_verify_init();
+ do_verify_process();
+
+ /* set return value of success or failure of entire operation */
+
+ if( oper_type == VERIFY_LAST_BACKUP_OPER ||
+ oper_type == ARCHIVE_VERIFY_OPER ) {
+
+ bsd_ptr = BSD_GetFirst( bsd_list );
+ }
+ else {
+ bsd_ptr = BSD_GetFirst( tape_bsd_list );
+ }
+
+ while( ( bsd_ptr != NULL ) && !ret_val ) {
+
+ ret_val = BSD_GetOperStatus( bsd_ptr );
+ bsd_ptr = BSD_GetNext( bsd_ptr );
+ }
+
+ gbCurrentOperation = OPERATION_NONE;
+ SetStatusBlock(IDSM_OPERATIONSTATUS, STAT_OPER_IDLE);
+ return( ret_val );
+}
+
+
+/*****************************************************************************
+
+ Name: do_verify_init
+
+ Description: Initialize the RTD text.
+
+ Returns: none.
+
+*****************************************************************************/
+
+VOID do_verify_init( VOID )
+{
+ VLM_CloseAll();
+
+ JobStatusBackupRestore( JOB_STATUS_CREATE_DIALOG );
+
+ yresprintf( (INT16) IDS_DLGTITLEJOBSTATVERIFY );
+ JobStatusBackupRestore( JOB_STATUS_VERIFY_TITLE );
+
+ // display "Set information n of n "
+ JobStatusBackupRestore( JOB_STATUS_N_OF_N );
+
+ // display the tape bitmap
+ JobStatusBackupRestore( JOB_STATUS_VOLUME_TAPE );
+
+ yresprintf( (INT16) RES_TITLE_NEW_LINE );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ yresprintf( (INT16) IDS_DLGTITLEJOBSTATVERIFY );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ yresprintf( (INT16) RES_TITLE_NEW_LINE );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ /* clear the bytes processed field */
+ yprintf( TEXT("%d\r"), 0 );
+ JobStatusBackupRestore( JOB_STATUS_BYTES_PROCESSED );
+
+ return;
+}
+
+
+/*****************************************************************************
+
+ Name: do_verify_process
+
+ Description: Initializes the lis structure, etc and calls the verify
+ engine to perform the operation.
+
+ Returns: none.
+
+ Notes: If a failure occurs, the operation status is set to
+ ABNORMAL_TERMINATION
+
+*****************************************************************************/
+VOID do_verify_process( VOID )
+{
+ LIS lis;
+ BSD_PTR bsd_ptr;
+ BSD_HAND temp_bsd_list;
+ INT16 ret_val;
+
+
+ if( mw_oper_type == VERIFY_LAST_BACKUP_OPER ||
+ mw_oper_type == ARCHIVE_VERIFY_OPER ) {
+
+ temp_bsd_list = bsd_list;
+ }
+ else {
+ temp_bsd_list = tape_bsd_list;
+ }
+
+ lis.vmem_hand = NULL;
+ lis.curr_bsd_ptr = BSD_GetFirst( temp_bsd_list );
+ lis.tape_pos_handler = tpos_rout; /* set tape positioner to call */
+ lis.message_handler = msg_hndlr; /* set message handler to call */
+ lis.oper_type = (INT16)mw_oper_type; /* set operation type */
+ lis.abort_flag_ptr = &gb_abort_flag; /* set abort flag address */
+ lis.pid = 0L;
+ lis.auto_det_sdrv = FALSE;
+ lis.bsd_list = temp_bsd_list;
+ gb_last_operation = mw_oper_type;
+
+ LP_SetAbortFlag( &lis, CONTINUE_PROCESSING );
+
+ /* set the Runtime abort flag pointer */
+ JobStatusAbort( lis.abort_flag_ptr );
+
+ /* enable the abort button for the runtime dialg */
+ JobStatusBackupRestore( JOB_STATUS_ABORT_ENABLE );
+
+ /* Add additional excludes for catalog files if applicable. */
+ /* Note: don't care about return value here */
+
+ UI_ExcludeInternalFiles( (INT16)mw_oper_type );
+
+ if ( ( mw_oper_type | VERIFY_OPER ) &&
+ ( mw_oper_type & ~VERIFY_LAST_BACKUP_OPER ) &&
+ ( mw_oper_type & ~VERIFY_LAST_RESTORE_OPER ) ) {
+
+ /* Set the process-special flag if this is not */
+ /* a "verify-last" operation. */
+
+ bsd_ptr = BSD_GetFirst( temp_bsd_list );
+
+ while( bsd_ptr != NULL ) {
+ BSD_SetProcSpecialFlg( bsd_ptr, TRUE );
+ bsd_ptr = BSD_GetNext( bsd_ptr );
+ }
+
+ }
+
+ TryToCreateFFRQueue( &lis, (INT16)mw_oper_type );
+
+ clock_ready_flag = FALSE; // Wait on bset to start
+
+ timer_handle = WM_HookTimer( clock_routine, 1 );
+
+ PD_StopPolling();
+
+ /* call verify engine */
+ ret_val = LP_Verify_Engine( &lis );
+
+ PD_StartPolling();
+
+ WM_UnhookTimer( timer_handle );
+
+ /* This call will disable the Runtime Abort button and */
+ /* enable the OK button */
+ JobStatusBackupRestore( JOB_STATUS_ABORT_OFF );
+
+ if ( ( ret_val != SUCCESS ) && ( ret_val != TFLE_UI_HAPPY_ABORT ) ) {
+
+ BSD_SetOperStatus( lis.curr_bsd_ptr, ABNORMAL_TERMINATION );
+ }
+
+ return;
+}
+
+
+/*****************************************************************************
+
+ Name: tpos_rout
+
+ Description: Tape positioning routine for tape verification function
+ called from Tape Format
+
+ Returns:
+
+*****************************************************************************/
+static UINT16 tpos_rout(
+UINT16 message,
+TPOS_PTR tpos,
+BOOLEAN curr_vcb_valid,
+DBLK_PTR cur_vcb,
+UINT16 mode )
+{
+ UINT16 response = UI_ACKNOWLEDGED;
+ LIS_PTR lis_ptr = (LIS_PTR)tpos->reference;
+ BSD_PTR bsd_ptr = (BSD_PTR)lis_ptr->curr_bsd_ptr;
+ CHAR_PTR drive_name;
+ CHAR_PTR tape_name;
+
+ /* get a pointer to the name of the current tape device */
+ drive_name = BE_GetCurrentDeviceName( tpos->channel );
+
+ JobStatusBackupRestore( JOB_STATUS_ABORT_CHECK );
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+
+ /* Check for user abort */
+ if( UI_CheckUserAbort( message ) ) {
+ return UI_ABORT_POSITIONING;
+ }
+
+ switch( message ) {
+
+ case TF_IDLE_NOBREAK:
+
+ WM_MultiTask();
+ break;
+
+ case TF_IDLE:
+ case TF_SKIPPING_DATA:
+ case TF_MOUNTING:
+ break;
+
+ case TF_REQUESTED_VCB_FOUND:
+
+ mw_rewind = TRUE;
+
+ /* if continuing a read operation, simply continue */
+ if( mode == TF_READ_CONTINUE ) {
+ response = UI_UpdateTpos( tpos, cur_vcb, FALSE );
+ break;
+ }
+
+ /* check for "automatic style" verify first */
+ if ( ( lis_ptr->oper_type == ARCHIVE_VERIFY_OPER ) ||
+ ( lis_ptr->oper_type == VERIFY_LAST_BACKUP_OPER ) ||
+ ( lis_ptr->oper_type == VERIFY_LAST_RESTORE_OPER ) ) {
+
+ response = UI_UpdateTpos( tpos, cur_vcb, FALSE );
+ break;
+ }
+
+ /* Otherwise, check for positioning for catalog selected set... */
+ /* We're located at a request VCB (using from a catalog based selection) */
+ /* If we're processing a specific set, and we've located this set via */
+ /* FFR PBA positioning, simply return TF_END_POSITIONING since this set */
+ /* has been pre-qualified prior to calling the loop */
+
+ if ( ( tpos->tape_id != -1 ) &&
+ ( tpos->tape_seq_num != -1 ) &&
+ ( tpos->backup_set_num != -1 ) &&
+ ( tpos->tape_loc.pba_vcb != 0 ) ) {
+
+ response = UI_END_POSITIONING;
+ break;
+ }
+
+ /* otherwise, fall through into tape set qualification logic... */
+
+
+ case TF_VCB_BOT:
+ case TF_POSITIONED_AT_A_VCB:
+
+ mw_rewind = TRUE;
+
+ /* first check for read continuation */
+ if ( mode == TF_READ_CONTINUE ) {
+ response = UI_UpdateTpos( tpos, cur_vcb, FALSE );
+ break;
+ }
+
+ if ( message == TF_VCB_BOT ) {
+ if ( FS_ViewTSNumInVCB( cur_vcb ) > 1 ) {
+
+ yresprintf( (INT16) RES_OUT_OF_SEQUENCE_WARNING, FS_ViewTSNumInVCB( cur_vcb ) );
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+ if ( ! WM_MessageBox( ID( IDS_MSGTITLE_CONTINUE ),
+ gszTprintfBuffer,
+ WMMB_YESNO,
+ WMMB_ICONQUESTION,
+ ID( RES_CONTINUE_QUEST ), 0, 0 ) ) {
+ response = UI_ReplaceTape( drive_name );
+#ifdef OS_WIN32
+ tape_retries = mwTapeSettlingCount ;
+#endif
+ break;
+ }
+ }
+ }
+
+
+ /* have user validate tape password if necessary */
+ if ( ( lis_ptr->oper_type != ARCHIVE_VERIFY_OPER ) &&
+ ( lis_ptr->oper_type != VERIFY_LAST_BACKUP_OPER ) &&
+ ( lis_ptr->oper_type != VERIFY_LAST_RESTORE_OPER ) ) {
+
+ if ( UI_CheckOldTapePassword( cur_vcb ) == UI_ABORT_POSITIONING ) {
+ response = UI_HAPPY_ABORT;
+ break;
+ }
+ }
+
+ response = UI_UpdateTpos( tpos, cur_vcb, FALSE );
+ msg_hndlr( MSG_ACCIDENTAL_VCB, lis_ptr->pid, NULL, NULL, NULL, cur_vcb );
+
+ break;
+
+ case TF_ACCIDENTAL_VCB:
+ mw_rewind = TRUE;
+ UI_DisplayVCB( cur_vcb );
+
+ break;
+
+ case TF_VCB_EOD:
+ mw_rewind = TRUE;
+ response = UI_ProcessVCBatEOD( tpos, drive_name );
+ break;
+
+ case TF_NEED_NEW_TAPE:
+ mw_rewind = TRUE;
+ tape_name = UI_DisplayableTapeName( (CHAR_PTR) FS_ViewTapeNameInVCB( cur_vcb ),
+ FS_ViewBackupDateInVCB( cur_vcb ) );
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_NEEDTAPE);
+ response = PromptNextTape( tpos, cur_vcb, curr_vcb_valid,
+ mode, tape_name, drive_name );
+ break;
+
+ case TF_UNRECOGNIZED_MEDIA:
+ mw_rewind = TRUE;
+ yresprintf( (INT16) IDS_VLMUNFORMATEDTEXT ) ;
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+ SetStatusBlock(IDSM_DRIVESTATUS, STAT_DRIVE_UNFORMATTED);
+ WM_MessageBox( ID( IDS_VLMUNFORMATEDTITLE ) ,
+ gszTprintfBuffer ,
+ WMMB_OK,
+ WMMB_ICONEXCLAMATION, NULL, 0, 0 ) ;
+
+ response = PromptNextTape( tpos, cur_vcb, curr_vcb_valid,
+ mode, NULL, drive_name );
+ break;
+
+ case TF_NO_TAPE_PRESENT:
+#ifdef OS_WIN32
+ if( tape_retries ){
+ Sleep( 3000 ) ;
+ response = UI_NEW_TAPE_INSERTED ;
+ --tape_retries ;
+ break ;
+ }
+ // NOTE: fall thru on implied else or !ifdef OS_WIN32
+#endif
+
+ case TF_EMPTY_TAPE:
+ case TF_INVALID_VCB:
+ case TF_WRONG_TAPE:
+ case TF_FUTURE_REV_MTF:
+ case TF_MTF_ECC_TAPE:
+ case TF_SQL_TAPE:
+ case TF_TAPE_OUT_OF_ORDER:
+ mw_rewind = TRUE;
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+ SetStatusBlock(IDSM_DRIVESTATUS, STAT_DRIVE_EMPTY);
+ tape_name = UI_DisplayableTapeName( (LPSTR)BSD_GetTapeLabel( bsd_ptr ),
+ BSD_ViewDate( bsd_ptr ) );
+ response = PromptNextTape( tpos, cur_vcb, curr_vcb_valid,
+ mode, tape_name, drive_name );
+
+ // Change UI_HAPPY_ABORT to UI_ABORT_POSITIONING because
+ // the loops will ask for the next Bset if you answered No
+ // to Do you want to continue, on insert tape message.
+ // The new response will cause the operation to abort
+ if( response == UI_HAPPY_ABORT ) {
+ response = UI_ABORT_POSITIONING;
+ }
+ break;
+
+ case TF_NO_MORE_DATA:
+ mw_rewind = TRUE;
+ yresprintf( (INT16) RES_NO_MORE_TAPE_INFO );
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ response = UI_HAPPY_ABORT;
+ break;
+
+ case TF_READ_ERROR:
+ mw_rewind = TRUE;
+ response = UI_HandleTapeReadError( drive_name );
+ break;
+
+ case TF_SEARCHING:
+ mw_rewind = TRUE;
+ yresprintf( (INT16) RES_SEARCHING );
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ break;
+
+ case TF_REWINDING:
+ if ( mw_rewind ) {
+ mw_rewind = FALSE;
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ yresprintf( (INT16) RES_REWINDING );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ }
+ break;
+
+ case TF_DRIVE_BUSY:
+ mw_rewind = TRUE;
+ yresprintf( (INT16) RES_WAITING );
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ SetStatusBlock(IDSM_DRIVESTATUS, STAT_DRIVE_BUSY);
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ break;
+
+ default:
+ mw_rewind = TRUE;
+ eresprintf( RES_UNKNOWN_TF_MSG, message );
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+ response = UI_ABORT_POSITIONING;
+ break;
+ }
+
+ return( response );
+
+}
+
+
+/*****************************************************************************
+
+ Name: clock_routine
+
+ Description: one second time to update the Runtime status
+ elapsed time
+
+ Returns: void
+
+*****************************************************************************/
+
+static VOID clock_routine( VOID )
+{
+ INT16 num_hours, num_min, num_seconds; // chs:02-22-93 per mikep
+// chs:02-2-93 INT16 num_min, num_seconds;
+ UINT64 num_bytes;
+ BOOLEAN stat ;
+ CHAR numeral[ 40 ];
+ static UINT64 total_bytes;
+ UINT num_files;
+ UINT num_dirs;
+
+ if ( clock_ready_flag && ( ST_BSIdleLevel( &op_stats ) == 0 ) ) {
+
+ num_bytes = ST_GetBSBytesProcessed ( &op_stats );
+
+ if ( !U64_EQ( num_bytes, total_bytes ) ) {
+ total_bytes = num_bytes;
+ U64_Litoa( num_bytes, numeral, (INT16) 10, &stat ) ;
+ UI_BuildNumeralWithCommas( numeral );
+ yprintf(TEXT("%s\r"),numeral );
+ JobStatusBackupRestore( JOB_STATUS_BYTES_PROCESSED );
+ }
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+ {
+ WM_AnimateAppIcon ( IDM_OPERATIONSVERIFY, FALSE );
+ }
+# endif // !defined ( OEM_MSOFT ) // unsupported feature
+
+ ST_EndBackupSet( &op_stats );
+
+ num_dirs = ST_GetBSDirsProcessed( &op_stats );
+ num_files = ST_GetBSFilesProcessed( &op_stats );
+ SetStatusBlock(IDSM_FILECOUNT, num_files);
+ SetStatusBlock(IDSM_DIRCOUNT, num_dirs);
+ SetStatusBlock(IDSM_CORRUPTFILECOUNT, ST_GetBSFilesBad( &op_stats ));
+ SetStatusBlock(IDSM_SKIPPEDFILECOUNT, ST_GetBSFilesSkipped( &op_stats ));
+ SetStatusBlock(IDSM_BYTECOUNTLO, U64_Lsw(num_bytes));
+ SetStatusBlock(IDSM_BYTECOUNTHI, U64_Msw(num_bytes));
+ SetStatusBlock(IDSM_ELAPSEDSECONDS, (ST_GetBSEndTime( &op_stats ) -
+ ST_GetBSStartTime( &op_stats ) -
+ op_stats.bs_stats.bs_total_idle));
+ num_hours = ST_GetBSElapsedHours( &op_stats ); // chs:02-22-93 per mikep
+ num_min = ST_GetBSElapsedMinutes( &op_stats );
+ num_seconds = ST_GetBSElapsedSeconds( &op_stats );
+
+ if ( num_hours ) { // chs:02-22-93 per mikep
+ // chs:02-22-93 per mikep
+ yprintf( TEXT("%2.2d%c%2.2d%c%2.2d\r"), // chs:02-22-93 per mikep
+ num_hours, UI_GetTimeSeparator(), // chs:02-22-93 per mikep
+ num_min, UI_GetTimeSeparator(), // chs:02-22-93 per mikep
+ num_seconds ); // chs:02-22-93 per mikep
+ // chs:02-22-93 per mikep
+ // chs:02-22-93 per mikep
+ } // chs:02-22-93 per mikep
+ else { // chs:02-22-93 per mikep
+ // chs:02-22-93 per mikep
+ yprintf( TEXT("%2.2d%c%2.2d\r"), // chs:02-22-93 per mikep
+ num_min, UI_GetTimeSeparator(), // chs:02-22-93 per mikep
+ num_seconds ); // chs:02-22-93 per mikep
+
+ }
+
+// chs:02-22-93 per mikep yprintf( TEXT("%2.2d%c%2.2d\r"), num_min, UI_GetTimeSeparator(), num_seconds );
+
+ JobStatusBackupRestore( JOB_STATUS_ELAPSED_TIME );
+ }
+}
+
+
+/*****************************************************************************
+
+ Name: msg_hndlr
+
+ Description: Message handler for tape verification process
+
+ Returns:
+
+*****************************************************************************/
+static INT16 msg_hndlr(
+UINT16 msg,
+INT32 pid,
+BSD_PTR bsd_ptr,
+FSYS_HAND fsh,
+TPOS_PTR tpos,
+... )
+{
+ static CHAR delimiter = TEXT('#'); /* = # for debug */
+ INT16 response = MSG_ACK;
+ va_list arg_ptr;
+ static CHAR_PTR buffer = NULL;
+ static CHAR_PTR file_buf = NULL;
+ static CHAR_PTR path = NULL;
+ CHAR_PTR buffer1; // chs:06-08-93
+ static UINT16 OS_id;
+ static UINT16 OS_ver;
+ static BOOLEAN open_script;
+ static BOOLEAN open_brace = FALSE;
+ GENERIC_DLE_PTR dle;
+ BOOLEAN add_to_verify;
+ UINT64 num_bytes;
+ BOOLEAN stat ;
+ CHAR numeral[ UI_MAX_NUMERAL_LENGTH ];
+ QTC_BSET_PTR qtc_bset;
+ QTC_HEADER_PTR qtc_header;
+
+ // Accurate directory counts
+
+ static INT path_size;
+ static INT root_counted;
+
+ /* for future use */
+ pid;
+
+ /* set up first argument */
+ va_start( arg_ptr, tpos );
+
+ JobStatusBackupRestore( JOB_STATUS_ABORT_CHECK );
+
+ switch ( (INT16)msg ) {
+
+ /* logging messages */
+ case MSG_LOG_BLOCK:
+ {
+ DBLK_PTR dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ switch( FS_GetBlockType( dblk_ptr ) ) {
+
+ case BT_DDB:
+ /* clear last displayed filename from status display */
+ UI_DisplayFile( TEXT("") );
+ delimiter = FS_GetDelimiterFromOSID( OS_id, OS_ver );
+ UI_BuildDelimitedPathFromDDB( &buffer, fsh, dblk_ptr, delimiter, FALSE );
+ if ( buffer != NULL ) {
+ yprintf( TEXT("%s"), buffer );
+ JobStatusBackupRestore( JOB_STATUS_DIRECTORY_NAMES );
+
+ ST_EndBackupSet( &op_stats );
+
+ // build the full path with no "..." inserted
+ UI_BuildFullPathFromDDB2( &buffer, fsh, dblk_ptr, delimiter, FALSE );
+
+ dle = BSD_GetDLE( bsd_ptr ); // chs:06-08-93
+ if ( dle->device_name_leng ) { // chs:06-08-93
+ buffer1 = (CHAR_PTR)calloc( 1, ( strlen( buffer ) * sizeof( CHAR ) ) + ( ( dle->device_name_leng ) * sizeof( CHAR ) ) + sizeof( CHAR ) ); // chs:06-08-93
+ if ( buffer1 ) { // chs:06-08-93
+ strcpy( buffer1, dle->device_name ); // chs:06-08-93
+ strcat( buffer1, buffer ); // chs:06-08-93
+ // chs:06-08-93
+ lresprintf( LOGGING_FILE, LOG_DIRECTORY, SES_ENG_MSG, RES_DIRECTORY, buffer1 ); // chs:06-08-93
+ free( buffer1 ); // chs:06-08-93
+ } else { // chs:06-08-93
+ // chs:06-08-93
+ lresprintf( LOGGING_FILE, LOG_DIRECTORY, SES_ENG_MSG, RES_DIRECTORY, buffer ); // chs:06-08-93
+ } // chs:06-08-93
+ } else { // chs:06-08-93
+ lresprintf( LOGGING_FILE, LOG_DIRECTORY, SES_ENG_MSG, RES_DIRECTORY, buffer ); // chs:06-08-93
+ } // chs:06-08-93
+ }
+ break;
+
+ case BT_FDB:
+
+ if ( CDS_GetFilesFlag( CDS_GetCopy() ) ) {
+
+ if ( UI_AllocPathBuffer( &buffer, FS_SizeofFnameInFDB( fsh, dblk_ptr ) ) ) {
+ FS_GetFnameFromFDB( fsh, dblk_ptr, buffer );
+
+ // copy the full file name for the Log file
+ strcpy( gszTprintfBuffer, buffer );
+ lresprintf( LOGGING_FILE, LOG_FILE, fsh, dblk_ptr );
+
+ // truncate the file name, if needed, for Runtime display
+ UI_DisplayFile( buffer );
+ JobStatusBackupRestore( JOB_STATUS_FILE_NAMES );
+ }
+
+ } else {
+ lresprintf( LOGGING_FILE, LOG_FILE, fsh, dblk_ptr );
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ /* statistics messages */
+
+ case MSG_BLOCK_PROCESSED:
+ {
+ DBLK_PTR dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+ OBJECT_TYPE object_type;
+ INT i;
+ INT item_size;
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ switch( FS_GetBlockType( dblk_ptr ) ) {
+
+ case BT_DDB:
+
+ // Count all the new directories that showed up in
+ // this DDB.
+
+ // Only count the root once.
+
+ if ( ! root_counted ) {
+ ST_AddBSDirsProcessed( &op_stats, 1 );
+ root_counted = TRUE;
+ }
+
+ // Get the new path from the DDB.
+
+ item_size = FS_SizeofOSPathInDDB( fsh, dblk_ptr );
+ if ( UI_AllocPathBuffer( &buffer, (UINT16) item_size ) ) {
+
+ FS_GetOSPathFromDDB( fsh, dblk_ptr, buffer );
+
+ if ( item_size != sizeof (CHAR) ) {
+
+ i = 0;
+ while ( i < (INT)(item_size / sizeof (CHAR)) ) {
+
+ if ( i >= (INT)(path_size / sizeof (CHAR)) ) {
+
+ ST_AddBSDirsProcessed( &op_stats, 1 );
+ }
+ else if ( (path == NULL ) || stricmp( &buffer[ i ], &path[ i ] ) ) {
+
+ ST_AddBSDirsProcessed( &op_stats, 1 );
+ path_size = 0;
+ }
+ while ( buffer[ i++ ] );
+ }
+ }
+
+ // Set up for next time.
+ }
+ UI_AllocPathBuffer( &path, (UINT16) item_size ) ;
+ if ( buffer && path ) {
+ memcpy( path, buffer, item_size );
+ }
+
+ path_size = item_size;
+
+ yprintf(TEXT("%ld\r"),ST_GetBSDirsProcessed( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_DIRECTORIES_PROCESS );
+
+ break;
+
+ case BT_FDB:
+ ST_AddBSFilesProcessed( &op_stats, 1 );
+ FS_GetObjTypeDBLK( fsh, dblk_ptr, &object_type );
+ if( object_type == AFP_OBJECT ) {
+ ST_AddBSAFPFilesProcessed( &op_stats, 1 );
+ }
+
+ yprintf(TEXT("%ld\r"),ST_GetBSFilesProcessed( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_FILES_PROCESSED );
+
+ if ( gbAbortAtEOF ) {
+ gb_abort_flag = ABORT_PROCESSED ;
+ }
+
+ break;
+
+ case BT_IDB:
+ break;
+ }
+ }
+ break;
+
+ case MSG_BYTES_PROCESSED:
+ {
+ UINT64 count = va_arg( arg_ptr, UINT64 );
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ ST_AddBSBytesProcessed( &op_stats, count );
+
+ }
+ ST_EndBackupSet( &op_stats );
+
+ break;
+
+ case MSG_BLOCK_SKIPPED:
+ {
+ DBLK_PTR dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ switch( FS_GetBlockType( dblk_ptr ) ) {
+
+ case BT_DDB:
+ ST_AddBSDirsSkipped( &op_stats, 1 );
+ break;
+
+ case BT_FDB:
+ ST_AddBSFilesSkipped( &op_stats, 1 );
+ yprintf(TEXT("%ld\r"),ST_GetBSFilesSkipped( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_SKIPPED_FILES );
+ break;
+ }
+ }
+ break;
+
+ case MSG_BYTES_SKIPPED:
+ {
+ UINT64 count = va_arg( arg_ptr, UINT64 );
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ ST_AddBSBytesSkipped( &op_stats, count );
+ }
+ break;
+
+ case MSG_BLK_NOT_FOUND:
+ {
+ DBLK_PTR dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+ DBLK_PTR ddb_dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+ gb_error_during_operation = TRUE;
+
+ switch( FS_GetBlockType( dblk_ptr ) ) {
+
+ case BT_DDB:
+ ST_AddDirectoriesNotFound( &op_stats, 1 );
+
+ lprintf( LOGGING_FILE, TEXT("\n") );
+
+ delimiter = FS_GetDelimiterFromOSID( OS_id, OS_ver );
+ UI_BuildDelimitedPathFromDDB( &buffer, fsh, dblk_ptr, delimiter, FALSE );
+
+ if ( buffer != NULL ) {
+ yresprintf( (INT16) RES_DIRECTORY_NOT_FOUND_ON_DISK, buffer );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_DIRECTORY_NOT_FOUND_ON_DISK, buffer );
+ lprintf( LOGGING_FILE, TEXT("\n") );
+ }
+ break;
+
+ case BT_FDB:
+ ST_AddFilesNotFound( &op_stats, 1 );
+
+ lprintf( LOGGING_FILE, TEXT("\n") );
+
+ yresprintf( (INT16) RES_ON_TAPE );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_ON_TAPE );
+
+ UI_BuildFileDetail( buffer, fsh, dblk_ptr, FALSE );
+
+ if ( buffer != NULL ) {
+ yprintf( TEXT("%s"), buffer );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lprintf( LOGGING_FILE, TEXT(" %s"), buffer );
+ }
+
+ UI_AllocPathBuffer( &file_buf, FS_SizeofFnameInFDB( fsh, dblk_ptr ) ) ;
+ UI_AllocPathBuffer( &buffer, (UINT16) ( FS_SizeofFnameInFDB( fsh, dblk_ptr ) +
+ FS_SizeofOSPathInDDB( fsh, ddb_dblk_ptr ) + 5 ) ) ;
+
+ if ( buffer && file_buf ) {
+
+ FS_GetFnameFromFDB( fsh, dblk_ptr, file_buf );
+ delimiter = FS_GetDelimiterFromOSID( OS_id, OS_ver );
+
+ UI_BuildDelimitedPathFromDDB( &buffer, fsh, ddb_dblk_ptr, delimiter, FALSE );
+ UI_AppendDelimiter( buffer, delimiter );
+ strcat( buffer, file_buf );
+
+ yresprintf( (INT16) RES_FILE_NOT_FOUND_ON_DISK, buffer );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_FILE_NOT_FOUND_ON_DISK, buffer );
+ lprintf( LOGGING_FILE, TEXT("\n") );
+ }
+ break;
+
+ }
+ }
+ break;
+
+ case MSG_BLK_DIFFERENT:
+ {
+ DBLK_PTR tape_dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+ DBLK_PTR disk_dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+ BOOLEAN os_info_flag = va_arg( arg_ptr, BOOLEAN );
+ INT16 os_error_code = va_arg( arg_ptr, INT16 );
+
+ UI_AllocPathBuffer( &buffer, UI_MAX_PATH_LENGTH * sizeof (CHAR) ) ;
+
+ if ( buffer == NULL ) {
+ break ;
+ }
+
+ gb_error_during_operation = TRUE;
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+
+ /* if this is the first entry for this backup set set up the file ... */
+ if ( ! open_script ) {
+ OpenVerifyScript( &op_stats, bsd_ptr, buffer );
+ open_script = TRUE;
+ }
+
+ switch( FS_GetBlockType( tape_dblk_ptr ) ) {
+
+ case BT_DDB:
+ ST_AddDirectoriesDifferent( &op_stats, 1 );
+ ST_AddNumSecurityDifferences( &op_stats, 1 );
+
+ lprintf( LOGGING_FILE, TEXT("\n") );
+
+ delimiter = FS_GetDelimiterFromOSID( OS_id, OS_ver );
+ UI_BuildDelimitedPathFromDDB( &buffer, fsh, tape_dblk_ptr, delimiter, FALSE );
+
+ if ( buffer != NULL ) {
+ yresprintf( (INT16) RES_DIRECTORY_DIFFERENT, buffer );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_DIRECTORY, SES_ENG_MSG, RES_DIRECTORY_DIFFERENT, buffer );
+ lprintf( LOGGING_FILE, TEXT("\n") );
+ }
+ break;
+
+ case BT_FDB:
+
+ if ( UI_AllocPathBuffer( &file_buf, FS_SizeofFnameInFDB( fsh, disk_dblk_ptr ) ) ) {
+ FS_GetFnameFromFDB( fsh, disk_dblk_ptr, file_buf );
+
+ switch ( os_error_code ) {
+
+ case FS_SECURITY_DIFFERENT :
+ ST_AddNumSecurityDifferences( &op_stats, 1 );
+ yresprintf( (INT16) RES_FILE_SECURITY_DIFF, file_buf );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_FILE_SECURITY_DIFF, file_buf );
+ break;
+
+ case FS_EADATA_DIFFERENT :
+ yresprintf( (INT16) RES_FILE_EA_DIFF, file_buf );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_FILE_EA_DIFF, file_buf );
+ break;
+
+ case FS_RESDATA_DIFFERENT :
+ ST_AddFilesDifferent( &op_stats, 1 );
+ yresprintf( (INT16) RES_FILE_RES_DIFF, file_buf );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_FILE_RES_DIFF, file_buf );
+ break;
+
+ default:
+ ST_AddFilesDifferent( &op_stats, 1 );
+ lprintf( LOGGING_FILE, TEXT("\n") );
+ lprintf( VERIFY_FILE, TEXT("\n{\n") );
+ open_brace = TRUE;
+
+ if ( !os_info_flag ) {
+ yresprintf( (INT16) RES_ON_TAPE );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_ON_TAPE );
+ lresprintf( VERIFY_FILE, LOG_MSG, SES_ENG_MSG, RES_ON_TAPE );
+
+ UI_BuildFileDetail( buffer, fsh, tape_dblk_ptr, FALSE );
+
+ if ( buffer != NULL ) {
+ yprintf( TEXT("%s"), buffer );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lprintf( LOGGING_FILE, TEXT(" %s"), buffer );
+ lprintf( VERIFY_FILE, TEXT(" %s"), buffer );
+
+ yresprintf( (INT16) RES_ON_DISK );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_ON_DISK );
+ lresprintf( VERIFY_FILE, LOG_MSG, SES_ENG_MSG, RES_ON_DISK );
+ }
+
+ UI_BuildFileDetail( buffer, fsh, disk_dblk_ptr, FALSE );
+
+ if ( buffer != NULL ) {
+
+ yprintf( TEXT("%s"), buffer );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lprintf( LOGGING_FILE, TEXT(" %s"), buffer );
+ lprintf( VERIFY_FILE, TEXT(" %s"), buffer );
+
+ } else {
+ yresprintf( (INT16) RES_OS_FILE_INFO_DIFFERENT, file_buf );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_OS_FILE_INFO_DIFFERENT, file_buf );
+ lresprintf( VERIFY_FILE, LOG_MSG, SES_ENG_MSG, RES_OS_FILE_INFO_DIFFERENT, file_buf );
+ }
+ }
+ break;
+ }
+ }
+ break;
+
+ }
+ }
+ break;
+
+ case MSG_LOG_DIFFERENCE:
+ {
+ DBLK_PTR dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+ DBLK_PTR ddb_dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+ UINT32 strm_id = va_arg( arg_ptr, UINT32 );
+ INT16 os_error_code = va_arg( arg_ptr, INT16 );
+
+ UI_AllocPathBuffer( &buffer, UI_MAX_PATH_LENGTH * sizeof (CHAR)) ;
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+
+ if ( buffer == NULL ) {
+ break ;
+ }
+
+ /* if this is the first entry for this backup set set up the file ... */
+ if( !open_script ) {
+ OpenVerifyScript( &op_stats, bsd_ptr, buffer );
+ open_script = TRUE;
+ }
+
+ add_to_verify = TRUE;
+
+ if( FS_GetBlockType( dblk_ptr ) == BT_FDB ) {
+
+ if ( !UI_AllocPathBuffer( &file_buf, FS_SizeofFnameInFDB( fsh, dblk_ptr ) ) ) {
+ break ;
+ }
+ FS_GetFnameFromFDB( fsh, dblk_ptr, file_buf );
+
+ switch ( os_error_code ) {
+
+ /* These don't get put in the verify script. */
+ case FS_SECURITY_DIFFERENT :
+ case FS_EADATA_DIFFERENT :
+ add_to_verify = FALSE;
+ break;
+
+ case FS_RESDATA_DIFFERENT :
+ if( open_brace ) {
+ open_brace = FALSE;
+ } else {
+ lprintf( VERIFY_FILE, TEXT("\n{\n") );
+ }
+ lresprintf( VERIFY_FILE, LOG_MSG, SES_ENG_MSG, RES_FILE_RES_DIFF, file_buf );
+ lprintf( VERIFY_FILE, TEXT("\n}\n") );
+ break;
+
+ default:
+ if( open_brace ) {
+ open_brace = FALSE;
+ } else {
+ lprintf( LOGGING_FILE, TEXT("\n") );
+ lprintf( VERIFY_FILE, TEXT("\n{\n") );
+ }
+
+ switch( strm_id ) {
+
+ case LP_OPEN_ERROR :
+ yresprintf( (INT16) RES_VERIFY_OPEN_ERROR );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_VERIFY_OPEN_ERROR );
+ lresprintf( VERIFY_FILE, LOG_MSG, SES_ENG_MSG, RES_VERIFY_OPEN_ERROR );
+
+ break ;
+
+ case LP_DATA_VERIFIED :
+ yresprintf( (INT16) RES_VERIFY_DATA_VERIFIED );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_VERIFY_DATA_VERIFIED );
+ lresprintf( VERIFY_FILE, LOG_MSG, SES_ENG_MSG, RES_VERIFY_DATA_VERIFIED );
+ break ;
+
+ case STRM_NT_ACL: /* 'NACL' */
+ case STRM_NOV_TRUST_286: /* 'N286' */
+ case STRM_NOV_TRUST_386: /* 'N386' */
+
+ // print "difference encountered in security data stream"
+ yresprintf( (INT16) IDS_RTD_VERIFYERROR_SECURITYSTREAM );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, IDS_RTD_VERIFYERROR_SECURITYSTREAM );
+ lresprintf( VERIFY_FILE, LOG_MSG, SES_ENG_MSG, IDS_RTD_VERIFYERROR_SECURITYSTREAM );
+ break ;
+
+ case STRM_NT_EA: /* 'NTEA' */
+
+ // print "difference encountered in Extended Attribute information"
+ yresprintf( (INT16) IDS_RTD_VERIFYERROR_EA );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, IDS_RTD_VERIFYERROR_EA );
+ lresprintf( VERIFY_FILE, LOG_MSG, SES_ENG_MSG, IDS_RTD_VERIFYERROR_EA );
+ break ;
+
+ case STRM_MAC_RESOURCE: /* 'MRSC' */
+ case STRM_NTFS_ALT_DATA: /* 'ADAT' */
+
+ // print "difference encountered in alternate data stream"
+ yresprintf( (INT16) IDS_RTD_VERIFYERROR_ALTSTREAM );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, IDS_RTD_VERIFYERROR_ALTSTREAM );
+ lresprintf( VERIFY_FILE, LOG_MSG, SES_ENG_MSG, IDS_RTD_VERIFYERROR_ALTSTREAM );
+ break ;
+
+ case STRM_GENERIC_DATA: /* 'STAN' */
+ default:
+ yresprintf( (INT16) IDS_RTD_VERIFYERROR_DATA );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, IDS_RTD_VERIFYERROR_DATA );
+ lresprintf( VERIFY_FILE, LOG_MSG, SES_ENG_MSG, IDS_RTD_VERIFYERROR_DATA );
+ // print "difference encountered in data stream"
+ break ;
+
+ }
+
+ lprintf( VERIFY_FILE, TEXT("\n}\n") );
+ lprintf( LOGGING_FILE, TEXT("\n") );
+
+ break;
+
+ }
+
+ if ( add_to_verify ) {
+ delimiter = FS_GetDelimiterFromOSID( OS_id, OS_ver );
+ UI_AllocPathBuffer( &buffer, (UINT16) ( FS_SizeofFnameInFDB( fsh, dblk_ptr ) +
+ FS_SizeofOSPathInDDB( fsh, ddb_dblk_ptr ) + 5 ) ) ;
+ if ( buffer && file_buf ) {
+ UI_BuildDelimitedPathFromDDB( &buffer, fsh, ddb_dblk_ptr, delimiter, FALSE );
+
+ UI_AppendDelimiter( buffer, delimiter );
+ strcat( buffer, file_buf );
+
+ yresprintf( (INT16) RES_FILE_IS_DIFFERENT, buffer );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_FILE_IS_DIFFERENT, buffer );
+
+ UI_BuildFullPathFromDDB( &buffer, fsh, ddb_dblk_ptr, delimiter, FALSE );
+ UI_AppendDelimiter( buffer, delimiter );
+ strcat( buffer, file_buf );
+ lprintf( VERIFY_FILE, TEXT("%s%s%s\n"),
+ ( DLE_GetDeviceType( BSD_GetDLE( bsd_ptr ) ) == REMOTE_DOS_DRV ) ?
+ TEXT("+") : TEXT(""),
+ DLE_GetDeviceName( BSD_GetDLE( bsd_ptr ) ),
+ buffer );
+ }
+
+ }
+
+ }
+
+ }
+ break;
+
+ case MSG_TBE_ERROR:
+ {
+ INT16 error = va_arg( arg_ptr, INT16 );
+
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &op_stats );
+ SetStatusBlock(IDSM_APPSTATUS, STAT_ERROR);
+
+ UI_ProcessErrorCode( error, &response, tpos->channel );
+
+ /* restart the clock with an end idle */
+ ST_EndBackupSetIdle( &op_stats );
+ }
+ break;
+
+ /* general messages */
+ case MSG_START_OPERATION:
+
+ lresprintf( LOGGING_FILE, LOG_START, FALSE );
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+
+ /* display operation title in log file */
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, IDS_DLGTITLEJOBSTATVERIFY );
+
+ break;
+
+ case MSG_END_OPERATION: {
+
+ CHAR szPathSpec[MAX_UI_PATH_SIZE];
+ CHAR szFileName[MAX_UI_FILENAME_SIZE];
+
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ UI_FreePathBuffer( &path ) ;
+ UI_FreePathBuffer( &buffer ) ;
+ UI_FreePathBuffer( &file_buf ) ;
+
+ lresprintf( LOGGING_FILE, LOG_END );
+ UI_ChkDispGlobalError( );
+
+ /* force an update to the bytes counter */
+ num_bytes = ST_GetBSBytesProcessed ( &op_stats );
+
+ U64_Litoa( num_bytes, numeral, (INT16) 10, &stat ) ;
+ UI_BuildNumeralWithCommas( numeral );
+ yprintf(TEXT("%s\r"),numeral );
+ JobStatusBackupRestore( JOB_STATUS_BYTES_PROCESSED );
+
+ // If the verify worked, blow away VERIFY.BKS
+
+ if ( gb_error_during_operation != TRUE ) {
+
+ RSM_StringCopy( IDS_VERIFY_JOBNAME, szFileName, MAX_UI_FILENAME_LEN );
+
+ wsprintf ( szPathSpec, TEXT("%s%s%s"), CDS_GetUserDataPath(), szFileName, TEXT(".bks") );
+ remove ( szPathSpec ); // if not found, it was never there
+ }
+
+ break;
+ }
+
+ case MSG_START_BACKUP_SET:
+ {
+ DBLK_PTR vcb_ptr = va_arg( arg_ptr, DBLK_PTR );
+
+ UI_AllocPathBuffer( &buffer, UI_MAX_PATH_LENGTH * sizeof (CHAR) ) ;
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ root_counted = FALSE;
+ path_size = 0;
+ UI_FreePathBuffer( &path ) ;
+
+ FS_GetOSid_verFromVCB( vcb_ptr, &OS_id, &OS_ver );
+
+ BSD_SetOperStatus( bsd_ptr, SUCCESS );
+
+ dle = BSD_GetDLE( bsd_ptr );
+
+#ifdef OEM_EMS
+ RT_BSD_OsId = DLE_GetOsId( dle );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_FS_TYPE );
+#endif OEM_EMS
+
+ if ( DLE_HasFeatures( dle, DLE_FEAT_REMOTE_DRIVE ) ) {
+ JobStatusBackupRestore( JOB_STATUS_VOLUME_NETDRIVE );
+ }
+ else {
+ JobStatusBackupRestore( JOB_STATUS_VOLUME_HARDDRIVE );
+ }
+
+ yprintf(TEXT("%s\r"),BSD_GetTapeLabel( bsd_ptr ));
+ JobStatusBackupRestore( JOB_STATUS_SOURCE_NAME );
+
+ if ( buffer != NULL ) {
+
+ DLE_GetVolName( BSD_GetDLE( bsd_ptr ), buffer );
+ yprintf(TEXT("%s\r"), buffer );
+
+ JobStatusBackupRestore( JOB_STATUS_DEST_NAME );
+
+ qtc_bset = QTC_FindBset( BSD_GetTapeID( bsd_ptr ),
+ (INT16) -1 ,
+ BSD_GetSetNum( bsd_ptr ) );
+
+ if( qtc_bset ) {
+ qtc_header = QTC_LoadHeader( qtc_bset );
+ if ( qtc_header ) {
+ strcpy( buffer, qtc_header->volume_name );
+ free( qtc_header );
+ }
+ }
+ else {
+ strcpy( buffer, (CHAR_PTR)BSD_GetTapeLabel( bsd_ptr ) );
+ }
+
+ yresprintf( (INT16) RES_DISPLAY_VERIFY_INFO,
+ buffer ,
+ BSD_GetSetNum( bsd_ptr ),
+ BSD_GetTapeNum( bsd_ptr ),
+ (BSD_GetBackupLabel( bsd_ptr )!= NULL) ? (CHAR_PTR)BSD_GetBackupLabel( bsd_ptr ) : TEXT("\0") );
+
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_DISPLAY_VERIFY_INFO,
+ buffer ,
+ BSD_GetSetNum( bsd_ptr ),
+ BSD_GetTapeNum( bsd_ptr ),
+ (BSD_GetBackupLabel( bsd_ptr ) != NULL) ? (CHAR_PTR)BSD_GetBackupLabel( bsd_ptr ) : TEXT("\0") ); // chs:05-18-93
+
+ }
+
+ delimiter = (CHAR)DLE_GetPathDelim( BSD_GetDLE( bsd_ptr ) );
+
+ ST_StartBackupSet( &op_stats );
+ UI_Time( &op_stats, (INT16) RES_VERIFY_STARTED, UI_START );
+
+#if defined ( OS_WIN32 )
+ DLE_GetVolName( BSD_GetDLE( bsd_ptr ), buffer );
+ OMEVENT_LogBeginVerify (buffer);
+#endif //defined ( OS_WIN32 )
+
+ clock_ready_flag = TRUE;
+
+ /* Init "searching" logic */
+ lw_search_first_time = TRUE;
+
+ open_script = FALSE;
+ }
+ break;
+
+ case MSG_END_BACKUP_SET:
+ {
+ INT16 res_id;
+
+
+ // update stats
+ clock_routine();
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ ST_EndBackupSet( &op_stats );
+
+ /* set backup set operation status to FILES_DIFFERENT if necessary */
+ if ( ST_GetFilesNotFound( &op_stats ) ||
+ ST_GetDirectoriesNotFound( &op_stats ) ||
+ ST_GetFilesDifferent( &op_stats ) ||
+ ST_GetDirectoriesDifferent( &op_stats ) ) {
+
+ BSD_SetOperStatus( bsd_ptr, FILES_DIFFERENT );
+ }
+
+ /* clear last displayed filename */
+ UI_ClearLastDisplayedFile( );
+
+ /* display and log any abort conditions */
+ UI_ConditionAtEnd( );
+
+ UI_Time( &op_stats, (INT16) RES_VERIFY_COMPLETED, UI_END );
+
+#if defined ( OS_WIN32 )
+ DLE_GetVolName( BSD_GetDLE( bsd_ptr ), buffer );
+ OMEVENT_LogEndVerify ( buffer,
+ gb_error_during_operation);
+#endif //defined ( OS_WIN32 )
+
+
+ clock_ready_flag = FALSE;
+
+
+ /* produce stats for dirs & files */
+ /* display number of files / number of dirs */
+ dle = BSD_GetDLE( bsd_ptr );
+ if ( DLE_GetDeviceType( dle ) != FS_EMS_DRV ) {
+
+ if( ST_GetFilesVerified( &op_stats ) == 1 &&
+ ST_GetBSDirsProcessed( &op_stats ) == 1) {
+ res_id = RES_VERIFIED_DIR_FILE;
+ }
+ else if( ST_GetFilesVerified( &op_stats ) == 1 &&
+ ST_GetBSDirsProcessed( &op_stats ) > 1) {
+ res_id = RES_VERIFIED_DIRS_FILE;
+ }
+ else if( ST_GetBSDirsProcessed( &op_stats ) == 1 &&
+ ST_GetFilesVerified( &op_stats ) > 1) {
+ res_id = RES_VERIFIED_DIR_FILES;
+ }
+ else {
+ res_id = RES_VERIFIED_DIRS_FILES;
+ }
+
+ yresprintf( res_id,
+ ST_GetFilesVerified( &op_stats ),
+ ST_GetBSDirsProcessed( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, res_id,
+ ST_GetFilesVerified( &op_stats ),
+ ST_GetBSDirsProcessed( &op_stats ) );
+ }
+
+ /* display number of mac files verified */
+ if( ST_GetBSAFPFilesProcessed( &op_stats ) > 0 ) {
+
+ if ( ST_GetBSAFPFilesProcessed( &op_stats ) == 1 ) {
+ res_id = RES_VERIFIED_MAC;
+ }
+ else {
+ res_id = RES_VERIFIED_MACS;
+ }
+
+ yresprintf( res_id,
+ ST_GetBSAFPFilesProcessed( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, res_id,
+ ST_GetBSAFPFilesProcessed( &op_stats ) );
+
+ }
+
+ /* display number of files different */
+ if( ST_GetFilesDifferent( &op_stats ) == 1 ) {
+ res_id = RES_FILE_DIFFERENT;
+ }
+ else {
+ res_id = RES_FILES_DIFFERENT;
+ }
+
+ yresprintf( res_id, ST_GetFilesDifferent( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ /* log number of files different */
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, res_id,
+ ST_GetFilesDifferent( &op_stats ) );
+
+ /* display number of files not found */
+ if( ST_GetFilesNotFound( &op_stats ) > 0 ) {
+
+ if( ST_GetFilesNotFound( &op_stats ) == 1 ) {
+ res_id = RES_FILE_NOT_FOUND;
+ }
+ else {
+ res_id = RES_FILES_NOT_FOUND;
+ }
+
+ yresprintf( res_id,
+ ST_GetFilesNotFound( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, res_id,
+ ST_GetFilesNotFound( &op_stats ) );
+ }
+
+ /* display number of Directories not found */
+ if( ST_GetDirectoriesNotFound( &op_stats ) > 0 ) {
+
+ if( ST_GetDirectoriesNotFound( &op_stats ) == 1 ) {
+ res_id = RES_DIRECTORY_NOT_FOUND;
+ }
+ else {
+ res_id = RES_DIRECTORYS_NOT_FOUND;
+ }
+
+ yresprintf( res_id,
+ ST_GetDirectoriesNotFound( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, res_id,
+ ST_GetDirectoriesNotFound( &op_stats ) );
+ }
+
+ /* display number of security differences */
+ if( ST_GetNumSecurityDifferences( &op_stats ) > 0 ) {
+
+ if( ST_GetNumSecurityDifferences( &op_stats ) == 1 ) {
+ res_id = RES_SECURITY_DIFFERENCE;
+ }
+ else {
+ res_id = RES_SECURITY_DIFFERENCES;
+ }
+
+ yresprintf( res_id,
+ ST_GetNumSecurityDifferences( &op_stats ) );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, res_id,
+ ST_GetNumSecurityDifferences( &op_stats ) );
+ }
+
+ /* display number of bytes processed */
+ UI_BytesProcessed( &op_stats );
+
+ /* display verify rate */
+ UI_RateProcessed( &op_stats );
+
+ /* close the verify log file if it was used */
+ if( open_script ) {
+ lresprintf( VERIFY_FILE, LOG_END );
+ open_script = FALSE;
+ }
+
+ delimiter = TEXT('#'); /* = # for debug */
+ }
+ break;
+
+ case MSG_COMM_FAILURE:
+
+ gb_error_during_operation = TRUE;
+ yresprintf( (INT16) RES_COMM_FAILURE );
+ JobStatusBackupRestore( (WORD) JOB_STATUS_LISTBOX );
+ lresprintf( LOGGING_FILE, LOG_WARNING, SES_ENG_MSG, RES_COMM_FAILURE );
+ break;
+
+ case MSG_EOM:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_NEEDTAPE);
+ /* message for next tape is done during TF_NEED_NEW_TAPE */
+ break;
+
+ case MSG_STOP_CLOCK:
+ /* stop the clock with a start idle */
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ ST_StartBackupSetIdle( &op_stats );
+ break;
+
+ case MSG_START_CLOCK:
+ /* restart the clock with an end idle */
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ ST_EndBackupSetIdle( &op_stats );
+ break;
+
+ case MSG_ACCIDENTAL_VCB:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ break;
+
+ case MSG_IDLE:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ break;
+
+ /* ignore these messages */
+ case MSG_IN_USE:
+ case MSG_PROMPT:
+ case MSG_BLOCK_DELETED:
+ case MSG_BYTES_DELETED:
+ case MSG_TAPE_STATS:
+ case MSG_CONT_VCB:
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+ break;
+
+// You know it !
+// We are talking kludge city here. Keep the error
+// message from being displayed to the user.
+
+#ifdef MS_RELEASE
+ case -533:
+ zprintf( DEBUG_TEMPORARY, TEXT("** -533 LOOPS ERROR **") );
+ break;
+#endif
+
+ default:
+ gb_error_during_operation = TRUE;
+
+ /* stop the clock with a start idle */
+ ST_StartBackupSetIdle( &op_stats );
+
+ eresprintf( RES_UNKNOWN_MSG_HNDLR_MSG, msg );
+
+ /* restart the clock with an end idle */
+ ST_EndBackupSetIdle( &op_stats );
+
+ break;
+ }
+
+ return( response );
+
+}
+
+static VOID OpenVerifyScript( op_stats_ptr, bsd_ptr, buffer )
+STATS_PTR op_stats_ptr;
+BSD_PTR bsd_ptr;
+CHAR_PTR buffer;
+{
+ time_t t_time;
+ CHAR date_str[MAX_UI_DATE_SIZE];
+ CHAR time_str[MAX_UI_TIME_SIZE];
+
+ lresprintf( VERIFY_FILE, LOG_START, FALSE );
+ DLE_GetVolName( BSD_GetDLE( bsd_ptr ), buffer );
+
+ t_time = ST_GetBSStartTime( op_stats_ptr );
+ UI_LongToDate( date_str, t_time );
+ UI_LongToTime( time_str, t_time );
+
+ lresprintf( VERIFY_FILE, LOG_MSG, SES_ENG_MSG, RES_VERIFY_SCRIPT_HEADER,
+ buffer,
+ DLE_GetDeviceName( BSD_GetDLE( bsd_ptr ) ),
+ date_str,
+ time_str );
+
+ return;
+
+}
+
+
+/*****************************************************************************
+
+ Name: PromptNextTape
+
+ Description: Function to collect user response when a new tape is
+ required from the Tape Format/Tape positioner.
+
+ Returns: UI_ABORT_POSITIONING or UI_NEW_TAPE_INSERTED
+
+*****************************************************************************/
+static INT16 PromptNextTape(
+TPOS_PTR tpos,
+DBLK_PTR cur_vcb,
+BOOLEAN valid_vcb_flag,
+UINT16 mode,
+CHAR_PTR tape,
+CHAR_PTR drive )
+{
+ INT response;
+ CHAR temp[ MAX_UI_RESOURCE_SIZE ];
+ INT16 prev_yes_flag;
+
+ zprintf( DEBUG_USER_INTERFACE, RES_UI_TPOS_TAPE_SET, tape, tpos->tape_seq_num, tpos->backup_set_num );
+
+ prev_yes_flag = CDS_GetYesFlag( CDS_GetCopy() );
+ CDS_SetYesFlag( CDS_GetCopy(), NO_FLAG );
+
+ switch ( mode ) {
+
+ case TF_READ_CONTINUE:
+
+ if ( valid_vcb_flag &&
+ ( FS_ViewTapeIDInVCB( cur_vcb ) == (UINT32)( tpos->tape_id ) ) &&
+ ( FS_ViewTSNumInVCB( cur_vcb ) == (UINT16)( tpos->tape_seq_num - 1 ) ) ) {
+
+ response = WM_MessageBox( ID( IDS_MSGTITLE_CONTINUE ),
+ ID( RES_CONTINUE_QUEST ),
+ WMMB_YESNO,
+ WMMB_ICONQUESTION,
+ NULL, 0, 0 );
+ } else {
+
+ RSM_Sprintf( temp, ID(RES_INSERT_NEXT_TAPE),
+ tpos->tape_seq_num,
+ BE_GetCurrentDeviceName( tpos->channel ) );
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_NEEDTAPE);
+ response = WM_MessageBox( ID( IDS_MSGTITLE_INSERT ),
+ ID( RES_NEED_NEXT_TAPE_REWOUND ), // chs:05-10-93
+ WMMB_OKCANCEL,
+ WMMB_ICONQUESTION,
+ temp,
+ IDRBM_LTAPE, 0 );
+ }
+ break;
+
+ case TF_READ_OPERATION:
+ default:
+
+ if ( valid_vcb_flag &&
+ ( FS_ViewTapeIDInVCB( cur_vcb ) == (UINT32)( tpos->tape_id ) ) &&
+ ( FS_ViewTSNumInVCB( cur_vcb ) == (UINT16)( tpos->tape_seq_num - 1 ) ) ) {
+
+ RSM_Sprintf( temp, ID(RES_INSERT_NEXT_TAPE_REWOUND), // chs:05-10-93
+ tpos->tape_seq_num,
+ BE_GetCurrentDeviceName( tpos->channel ) );
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_NEEDTAPE);
+ response = WM_MessageBox( ID( IDS_MSGTITLE_INSERT ),
+ ID( RES_NEED_NEXT_TAPE_REWOUND ), // chs:05-10-93
+ WMMB_OKCANCEL,
+ WMMB_ICONQUESTION,
+ temp,
+ IDRBM_LTAPE, 0 );
+ } else {
+
+ RSM_Sprintf( temp, ID(RES_TAPE_REQUEST), drive, tape,
+ ( tpos->tape_seq_num == -1) ? 1 : tpos->tape_seq_num );
+
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_NEEDTAPE);
+ response = WM_MessageBox( ID( IDS_MSGTITLE_INSERT ),
+ temp,
+ WMMB_YESNO,
+ WMMB_ICONQUESTION,
+ ID( RES_CONTINUE_QUEST ),
+ 0, 0 );
+ }
+ break;
+
+ }
+
+ if ( response ) {
+#ifdef OS_WIN32
+ NtDemoChangeTape( (UINT16)(( tpos->tape_seq_num == -1) ? 1u : tpos->tape_seq_num ) );
+ tape_retries = mwTapeSettlingCount ;
+#endif
+ response = UI_NEW_TAPE_INSERTED;
+ }
+ else {
+ response = UI_HAPPY_ABORT;
+ }
+
+ CDS_SetYesFlag( CDS_GetCopy(), prev_yes_flag );
+
+ return( (INT16)response );
+}
+
+INT UI_GetVerifyCurrentStatus(
+STATS *Stats,
+CHAR *Path,
+INT PathSize )
+{
+
+
+ return( SUCCESS );
+}
diff --git a/private/utils/ntbackup/src/docproc.c b/private/utils/ntbackup/src/docproc.c
new file mode 100644
index 000000000..1b0e56273
--- /dev/null
+++ b/private/utils/ntbackup/src/docproc.c
@@ -0,0 +1,1561 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: docproc.c
+
+ Description: This file contains the functions for processing messages
+ sent by windows to MDI Document windows. It also handles
+ the resizing of listboxes and the slider within the
+ MDI Document.
+
+ The following routines are in this module:
+
+ WM_MDIDocWndProc
+ WM_DocListWndProc
+ WM_DocActivate
+ WM_DocCommandProc
+ WM_DocCreate
+ WM_DocIsMenuChange
+ WM_DocQueryClose
+ WM_DocSize
+ WM_DocKeyDown
+ WM_DocSplit
+
+ $Log: G:\UI\LOGFILES\DOCPROC.C_V $
+
+ Rev 1.41.1.1 10 Mar 1994 16:54:36 Glenn
+Added support for positioning MDI doc in viewing area if out of frame and desktop.
+
+ Rev 1.41.1.0 27 Jan 1994 13:36:48 Glenn
+Added F5 Refresh support.
+
+ Rev 1.41 28 Jul 1993 16:57:10 MARINA
+enable c++
+
+ Rev 1.40 07 May 1993 14:22:14 DARRYLP
+Added Rob's fixes for Windows double clicks and ID_DELETE key trappings.
+
+ Rev 1.39 27 Apr 1993 19:14:00 GLENN
+Ifdef'd the sort code.
+
+ Rev 1.38 22 Apr 1993 15:59:18 GLENN
+Added file SORT option support.
+
+ Rev 1.37 16 Oct 1992 15:48:18 GLENN
+Added pdsHdr stuff to list box proc kill focus.
+
+ Rev 1.36 14 Oct 1992 15:48:18 GLENN
+Added Selection Framing Support for List Boxes without the FOCUS.
+
+ Rev 1.35 04 Oct 1992 19:33:24 DAVEV
+Unicode Awk pass
+
+ Rev 1.34 02 Oct 1992 16:45:44 GLENN
+Fixed left hand side of slider for NT.
+
+ Rev 1.33 28 Sep 1992 17:05:10 GLENN
+Casted the MIN_LISTBOX_WIDTH define.
+
+ Rev 1.32 17 Aug 1992 13:05:24 DAVEV
+MikeP's changes at Microsoft
+
+ Rev 1.31 28 Jul 1992 14:53:04 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.30 10 Jun 1992 16:20:16 GLENN
+Took out ClipCursor() for NT.
+
+ Rev 1.29 15 May 1992 13:32:36 MIKEP
+nt pass 2
+
+ Rev 1.28 30 Apr 1992 14:40:06 DAVEV
+OEM_MSOFT: Fix View-All File Details
+
+ Rev 1.27 20 Apr 1992 13:57:50 GLENN
+Fixed dlm/list box problem. Renamed global variables to module wides.
+
+ Rev 1.26 08 Apr 1992 13:41:52 ROBG
+Exclude border when calculating the region of the listbox to capture mouse.
+
+ Rev 1.25 02 Apr 1992 14:52:54 JOHNWT
+fixed mouse trap
+
+ Rev 1.24 31 Mar 1992 11:53:20 GLENN
+NT change: do not change cursor to pen for NT only.
+
+ Rev 1.23 25 Mar 1992 08:37:24 ROBG
+Fixed the problem about UAEs when dragging the mouse outside a listbox.
+
+ Rev 1.22 19 Mar 1992 15:49:10 GLENN
+Removed temporary multi task.
+
+ Rev 1.21 17 Mar 1992 19:09:00 GLENN
+Still working on list proc and doc proc.
+
+ Rev 1.20 10 Mar 1992 16:45:08 GLENN
+Put some switch points in for debugging.
+
+ Rev 1.19 09 Mar 1992 16:59:20 ROBG
+changed
+
+ Rev 1.18 09 Mar 1992 09:45:44 GLENN
+Fixed bug in maximize.
+
+ Rev 1.17 03 Mar 1992 18:20:02 GLENN
+Overhauled the proc functions.
+
+ Rev 1.16 18 Feb 1992 20:43:36 GLENN
+Changed SetWindowText() to WM_SetTitle().
+
+ Rev 1.15 11 Feb 1992 17:25:52 GLENN
+Changed DLM_KeyUp() parameter for new prototype.
+
+ Rev 1.14 06 Feb 1992 18:35:00 STEVEN
+fix typeo in NTKLUG
+
+ Rev 1.13 04 Feb 1992 16:08:30 STEVEN
+various bug fixes for NT
+
+ Rev 1.12 02 Feb 1992 16:34:04 GLENN
+Fixed slider/keyboard focus problem.
+
+ Rev 1.11 29 Jan 1992 18:07:02 GLENN
+Checked tree list box type before processing keys.
+
+ Rev 1.10 22 Jan 1992 12:37:44 GLENN
+Updated KEYDOWN and FOCUS areas.
+
+ Rev 1.9 07 Jan 1992 17:25:50 GLENN
+Added MDI split/slider support
+
+ Rev 1.8 26 Dec 1991 13:48:54 GLENN
+Added ability to block a doc restore/maximize during an operation
+
+ Rev 1.7 17 Dec 1991 15:29:02 ROBG
+Added handling of unwanted double clicks in hierarchical list boxes.
+
+ Rev 1.6 12 Dec 1991 17:07:42 DAVEV
+16/32 bit port -2nd pass
+
+ Rev 1.5 10 Dec 1991 13:45:24 GLENN
+Added feature to create a single-column list box
+
+ Rev 1.4 05 Dec 1991 17:53:50 GLENN
+Changed Close/Destroy sequencing.
+
+ Rev 1.3 04 Dec 1991 15:16:20 DAVEV
+Modifications for 16/32-bit Windows port - 1st pass.
+
+
+ Rev 1.2 03 Dec 1991 16:16:18 GLENN
+Added WM_DocKeyDown() call.
+
+ Rev 1.1 27 Nov 1991 12:09:30 GLENN
+Added parameter to DLM_DispListTerm().
+
+ Rev 1.0 20 Nov 1991 19:18:44 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+// PRIVATE DEFINES
+
+#define MIN_LISTBOX_WIDTH ((INT)70)
+
+// MODULE WIDE GLOBAL VARIABLES.
+
+static RECT mwRectOldSlider;
+static BOOL mwfLButtonDown = FALSE;
+static BOOL mwfSliding = FALSE;
+static BOOL mwfInCheckBox = FALSE;
+
+
+// PRIVATE FUNCTION PROTOTYPES
+
+VOID WM_DocCreate ( HWND, LONG );
+VOID WM_DocSize ( HWND, INT, INT );
+BOOL WM_DocCommandProc ( HWND, MP1, MP2 );
+BOOL WM_DocQueryClose ( HWND );
+SHORT WM_DocSetSliderPos ( HWND hWnd, WORD wStyle, SHORT sNewSliderPos );
+
+
+
+
+// FUNCTIONS
+
+/******************************************************************************
+
+ Name: WM_MDIDocWndProc()
+
+ Description: This function is called internally by Windows when events
+ occur relating to MDI document windows.
+
+ Returns: NULL or a default message handler's return code.
+
+******************************************************************************/
+
+WINRESULT APIENTRY WM_MDIDocWndProc (
+
+HWND hWnd, // I - window handle of the list box
+MSGID msg, // I - message
+MP1 mp1, // I - another message parameter
+MP2 mp2 ) // I - yet another message parameter
+
+{
+
+ switch ( msg ) {
+
+ case WM_CREATE: // Do some creation initialization stuff.
+
+ WM_DocCreate ( hWnd, mp2 );
+ return 0;
+
+ case WM_MOVE:
+
+ if ( ! IsIconic ( ghWndFrame ) ) {
+
+ RECT rcIntersect;
+ RECT rcDesktop;
+ RECT rcFrame;
+ RECT rcWnd;
+
+ // Check for frame compliance, then for desktop window compliance.
+
+ GetWindowRect ( GetDesktopWindow(), &rcDesktop );
+ GetWindowRect ( ghWndFrame, &rcFrame );
+ GetWindowRect ( hWnd, &rcWnd );
+
+ if ( ! IntersectRect ( &rcIntersect, &rcFrame, &rcWnd ) &&
+ ! IntersectRect ( &rcIntersect, &rcDesktop, &rcWnd ) ) {
+
+ DM_CenterDialog( hWnd );
+ }
+ }
+
+ break;
+
+ case WM_MDIACTIVATE: { // If we're activating this child, remember it.
+
+ PDS_WMINFO pdsWinInfo;
+
+ pdsWinInfo = WM_GetInfoPtr ( hWnd );
+
+ if ( pdsWinInfo ) {
+
+ // If mp1 is TRUE, the child is being activated,
+ // else, deactivated.
+ // if ( mp1 ) { ** DVC - This is not true for portable code:
+ // ** we must compare the handle of the
+ // ** window being activated to our own
+ // ** (I think - it's worth a try!!
+
+ if (hWnd == GET_WM_MDIACTIVATE_ACTIVATE (mp1, mp2)) {
+
+ RIB_Activate ( pdsWinInfo->hRibbon );
+
+ MUI_ActivateDocument ( pdsWinInfo->wType );
+ ghWndActiveDoc = hWnd;
+
+ // SetFocus ( hWnd );
+
+ if ( ! IsIconic ( hWnd ) ) {
+ SetFocus ( pdsWinInfo->hWndActiveList );
+ }
+ }
+ }
+
+ // return 0;
+ }
+
+ case WM_QUERYDRAGICON: {
+
+ // Get the MDI Document so that windows will automatically use it
+ // to create a cursor for dragging this window unique icon.
+
+ PDS_WMINFO pdsWinInfo = WM_GetInfoPtr ( hWnd );
+
+ return (LONG)pdsWinInfo->hIcon;
+
+ }
+
+ case WM_QUERYOPEN:
+
+ // If an operation is going on, do not allow the user to open
+ // an icon.
+
+ if ( gfOperation ) {
+ return FALSE;
+ }
+
+ return TRUE;
+
+ case WM_SETCURSOR: // Set the right cursor for this window.
+
+ // In help mode it is necessary to reset the cursor in response
+ // to every WM_SETCURSOR message.Otherwise, by default, Windows
+ // will reset the cursor to that of the window class.
+
+ if ( HM_SetCursor ( hWnd ) ) {
+ return 0;
+ }
+
+ if ( ( hWnd == (HWND)mp1 ) && ( LOWORD(mp2) == HTCLIENT ) ) {
+
+ PDS_WMINFO pdsWinInfo = WM_GetInfoPtr ( hWnd );
+
+ RSM_CursorSet ( pdsWinInfo->hCursor );
+ return 0;
+ }
+
+ break;
+
+ case WM_KEYDOWN:
+
+ // This should only occur if there is sliding going on.
+
+ if ( mwfSliding ) {
+
+ POINT Point;
+ RECT Rect;
+
+ GetCursorPos ( &Point );
+ GetClientRect ( hWnd, &Rect );
+
+ switch ( LOWORD ( mp1 ) ) {
+
+ case VK_LEFT:
+
+ SetCursorPos ( Point.x - 1, Point.y );
+ break;
+
+ case VK_RIGHT:
+
+ SetCursorPos ( Point.x + 1, Point.y );
+ break;
+
+ case VK_RETURN:
+
+ WM_DocSetSliderMode ( hWnd, WMDOC_SLIDEROFF );
+ break;
+
+ case VK_ESCAPE:
+
+ WM_DocSetSliderMode ( hWnd, WMDOC_SLIDERCANCEL );
+ break;
+ }
+
+ return 0;
+
+ }
+
+ break;
+
+ case WM_LBUTTONDOWN:
+
+ if ( HM_ContextLbuttonDown( hWnd, mp1, mp2 ) == TRUE ) {
+ return 0 ;
+ }
+
+ // Fall through if Help is not called
+
+ case WM_LBUTTONDBLCLK:
+
+ WM_DocSetSliderMode ( hWnd, WMDOC_SLIDERON );
+ return 0;
+
+ case WM_LBUTTONUP:
+
+ WM_DocSetSliderMode ( hWnd, WMDOC_SLIDEROFF );
+ return 0;
+
+ case WM_LBTRACKPOINT:
+
+ return DLM_WMTrackPoint ( hWnd, mp1, mp2 );
+
+ case WM_MOUSEMOVE:
+
+ // If the cursor/mouse is being moved while the left button is down
+ // in the slider region, reposition a temporary slider to the new
+ // cursor/mouse position.
+
+ if ( mwfLButtonDown ) {
+
+ WM_DocSetSliderPos ( hWnd, WMDOC_SLIDERMOVE, (SHORT)LOWORD(mp2) );
+ }
+
+ return 0;
+
+ case WM_SIZE: {
+
+ PDS_WMINFO pdsWinInfo = WM_GetInfoPtr ( hWnd );
+
+ // Change the title if this window is minimized, maximized, or restored.
+
+ switch ( mp1 ) {
+
+ case SIZEICONIC:
+
+ if ( WMDS_GetWinMinTitle ( pdsWinInfo ) ) {
+ WM_SetMinTitle ( hWnd, WMDS_GetWinMinTitle ( pdsWinInfo ) );
+ }
+
+ // Hide the list boxes.
+
+ if ( IsWindow ( WMDS_GetWinTreeList ( pdsWinInfo ) ) ) {
+ ShowWindow ( WMDS_GetWinTreeList ( pdsWinInfo ), SW_HIDE );
+ }
+
+ if ( IsWindow ( WMDS_GetWinFlatList ( pdsWinInfo ) ) ) {
+ ShowWindow ( WMDS_GetWinFlatList ( pdsWinInfo ), SW_HIDE );
+ }
+
+ break;
+
+ case SIZENORMAL:
+ case SIZEFULLSCREEN:
+
+ if ( WMDS_GetWinTitle ( pdsWinInfo ) ) {
+ WM_SetTitle ( hWnd, WMDS_GetWinTitle ( pdsWinInfo ) );
+ }
+
+ // Show the list boxes.
+
+ if ( IsWindow ( WMDS_GetWinTreeList ( pdsWinInfo ) ) ) {
+ ShowWindow ( WMDS_GetWinTreeList ( pdsWinInfo ), SW_SHOWNA );
+ }
+
+ if ( IsWindow ( WMDS_GetWinFlatList ( pdsWinInfo ) ) ) {
+ ShowWindow ( WMDS_GetWinFlatList ( pdsWinInfo ), SW_SHOWNA );
+ }
+
+ // Size the list box(es).
+
+ WM_DocSize ( hWnd, LOWORD(mp2), HIWORD(mp2) );
+
+ break;
+ }
+
+ break;
+ }
+
+ case WM_PAINT: // Make sure that the paint is handled appropriately.
+
+ if ( IsIconic ( hWnd ) ) {
+
+ PDS_WMINFO pdsWinInfo;
+ PAINTSTRUCT ps;
+ HDC hDC;
+ INT nOldBkMode;
+
+ hDC = BeginPaint ( hWnd, &ps );
+
+ nOldBkMode = SetBkMode( hDC, TRANSPARENT );
+
+ pdsWinInfo = WM_GetInfoPtr ( hWnd );
+ RSM_IconDraw ( pdsWinInfo->hIcon, 0, 0, hDC );
+ SetBkMode( hDC, nOldBkMode );
+
+ EndPaint ( hWnd, &ps );
+
+ return 0;
+ }
+
+ break;
+
+ case WM_QUERYENDSESSION:
+
+ return WM_DocQueryClose ( hWnd );
+
+ case WM_CLOSE: { // Close or minimize the window.
+
+ PDS_WMINFO pdsWinInfo = WM_GetInfoPtr ( hWnd );
+
+ // Minimize the window if it is not closable (a primary doc).
+ // Otherwise, deinitialize and destroy the window.
+
+ if ( ! pdsWinInfo->wClosable ) {
+ PostMessage( hWnd, WM_SYSCOMMAND, SC_MINIMIZE, 0L );
+ }
+ else {
+ WM_Destroy ( hWnd );
+ }
+
+ return 0;
+ }
+
+ case WM_DESTROY: { // Destroy the window and any child windows.
+
+ PDS_WMINFO pdsWinInfo = WM_GetInfoPtr ( hWnd );
+
+ // Destroy any list boxes in the MDI doc window.
+
+ if ( pdsWinInfo->hWndTreeList ) {
+ DestroyWindow ( pdsWinInfo->hWndTreeList );
+ DLM_DispListTerm ( pdsWinInfo, pdsWinInfo->hWndTreeList );
+ }
+
+ if ( pdsWinInfo->hWndFlatList ) {
+ DestroyWindow ( pdsWinInfo->hWndFlatList );
+ DLM_DispListTerm ( pdsWinInfo, pdsWinInfo->hWndFlatList );
+ }
+
+ // Free up any memory associated with the win info structure.
+
+ if ( pdsWinInfo->pTitle ) {
+ free ( pdsWinInfo->pTitle );
+ }
+
+ if ( pdsWinInfo->pMinTitle ) {
+ free ( pdsWinInfo->pMinTitle );
+ }
+
+ // Now, call the application to free up any memory.
+
+ VLM_CloseWin ( hWnd );
+
+ return 0;
+ }
+
+ case WM_SETFOCUS:
+
+ if ( ! mwfSliding && ! IsIconic ( hWnd ) ) {
+
+ // Set the focus to the list box that had it previously for this
+ // MDI Document.
+
+ PDS_WMINFO pdsWinInfo = WM_GetInfoPtr ( hWnd );
+
+ if ( pdsWinInfo ) {
+ SetFocus ( pdsWinInfo->hWndActiveList );
+ }
+
+ return 0;
+ }
+
+ break;
+
+ case WM_DRAWITEM:
+
+ return DLM_WMDrawItem( hWnd, (LPDRAWITEMSTRUCT) mp2 );
+
+ case WM_MEASUREITEM:
+
+ return DLM_WMMeasureItem( hWnd, (LPMEASUREITEMSTRUCT) mp2 );
+
+ case WM_DELETEITEM:
+
+ return DLM_WMDeleteItem( hWnd, (LPDELETEITEMSTRUCT) mp2 );
+
+ case WM_COMMAND:
+
+ if ( ! WM_DocCommandProc ( hWnd, mp1, mp2 ) ) {
+
+ // The command was processed.
+
+ return 0;
+ }
+
+ break;
+
+ } /* end switch */
+
+ // Pass on through to the default proc.
+
+ return DefMDIChildProc ( hWnd, msg, mp1, mp2 );
+
+} /* end WM_MDIDocWndProc() */
+
+
+/******************************************************************************
+
+ Name: WM_DocListWndProc()
+
+ Description: This function is a SUB-CLASS function of LIST BOXES for
+ the GUI MDI documents. It is called internally by Windows.
+ Windows calls this function when list box messages must be
+ processed. Windows will only call this routine for
+ MDI documents in this application.
+
+ Returns: NULL or a default message handler's return code.
+
+******************************************************************************/
+
+WINRESULT APIENTRY WM_DocListWndProc (
+
+HWND hWnd, // I - window handle of the list box
+MSGID msg, // I - message
+MP1 mp1, // I - another message parameter
+MP2 mp2 ) // I - yet another message parameter
+
+{
+
+ switch ( msg ) {
+
+# ifdef NTKLUG
+ case WM_DLMGETTEXT:
+ msg = LB_GETTEXT;
+ break;
+# endif
+ case WM_KEYDOWN:
+
+ // Pass the key to the Ribbon Window(s) and the Display List Manager.
+ // Note: the key will not be passed to the next function if the
+ // previous function used it.
+
+ if ( HM_KeyDown ( hWnd, mp1 ) ||
+ RIB_KeyDown ( ghWndMainRibbon, RIB_KEYBOARD, mp1, mp2 ) ||
+ WM_DocKeyDown ( hWnd, LOWORD ( mp1 ) ) ||
+ DLM_KeyDown ( hWnd, (LPWORD)&mp1, mp2 ) ) {
+
+ return 0;
+ }
+
+ break;
+
+ case WM_KEYUP:
+
+ // Pass the key to the Ribbon Window(s) and the Display List Manager.
+ // Note: the key will not be passed to the next function if the
+ // previous function used it.
+
+ if ( RIB_KeyUp ( ghWndMainRibbon, RIB_KEYBOARD, mp1, mp2 ) ||
+ DLM_KeyUp ( hWnd, (LPWORD)&mp1, mp2 ) ) {
+
+ return 0;
+ }
+
+ break;
+
+ case WM_MOUSEMOVE:
+
+ // Store the point in a global variable for the DLM.
+
+ WM_FromMP2toPOINT( gDLMpt, mp2 );
+
+ if ( DLM_CursorInCheckBox ( hWnd, gDLMpt ) ) {
+
+ mwfInCheckBox = TRUE;
+
+ }
+ else {
+
+ mwfInCheckBox = FALSE;
+ }
+
+ break;
+
+ case WM_SETCURSOR:
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+
+ if ( mwfInCheckBox && ( hWnd == (HWND)mp1 ) && ( LOWORD(mp2) == HTCLIENT ) ) {
+
+ RSM_CursorSet ( ghCursorPen );
+ return 0;
+ }
+
+# endif
+
+ break;
+
+ case WM_SETFOCUS: {
+
+ mwfInCheckBox = FALSE;
+
+ DLM_UpdateFocus ( hWnd, TRUE );
+
+ break;
+ }
+
+ // When the left button goes down, keep the cursor within the listbox.
+ // Windows 3.0 and 3.1 have a problem when you drag the cursor
+ // outside of the listbox.
+
+ case WM_LBUTTONDOWN: {
+
+ DLM_HEADER_PTR pdsHdr = DLM_GetDispHdr( hWnd );
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+ {
+ if ( DLM_GMode( pdsHdr ) != DLM_HIERARCHICAL ) {
+
+ RECT dsRect;
+
+ // Take the borders and scroll bars out of the rectangle .
+
+ GetWindowRect( hWnd, &dsRect );
+
+ dsRect.top = dsRect.top + GetSystemMetrics( SM_CYBORDER );
+ dsRect.bottom = dsRect.bottom - GetSystemMetrics( SM_CYBORDER );
+ dsRect.left = dsRect.left + GetSystemMetrics( SM_CYBORDER );
+ dsRect.right = dsRect.right - GetSystemMetrics( SM_CXBORDER );
+
+ ClipCursor( &dsRect );
+
+ }
+ }
+# endif
+
+ break;
+ }
+
+ case WM_KILLFOCUS: {
+
+ DLM_UpdateFocus ( hWnd, FALSE );
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+ {
+
+ DLM_HEADER_PTR pdsHdr = DLM_GetDispHdr( hWnd );
+
+ if ( DLM_GMode( pdsHdr ) != DLM_HIERARCHICAL ) {
+
+ ClipCursor( NULL );
+ }
+ }
+# endif
+
+ break;
+ }
+
+ case WM_LBUTTONUP:
+ case WM_NCLBUTTONUP: {
+
+ // When the left button goes up, allow the cursor to move anywhere
+ // in the frame again.
+
+ DLM_HEADER_PTR pdsHdr = DLM_GetDispHdr( hWnd );
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+ {
+ if ( DLM_GMode( pdsHdr ) != DLM_HIERARCHICAL ) {
+
+ ClipCursor( NULL );
+ }
+ }
+# endif
+
+ break;
+
+ }
+
+
+ case WM_LBUTTONDBLCLK: {
+
+ DLM_HEADER_PTR pdsHdr = DLM_GetDispHdr( hWnd );
+
+ if ( pdsHdr ) {
+
+ if ( DLM_GetTrkPtFailure( pdsHdr ) ) {
+
+ // Ignore the double click. This field
+ // is set in DLM_WMTrackPoint to 1 if the
+ // double click should be ignored.
+
+ return TRUE;
+ }
+ }
+
+ break;
+
+ }
+
+ case WM_SYSCOMMAND:
+ break;
+
+ case WM_PAINT: {
+
+ HWND hWndParent = GetParent ( hWnd );
+
+ // If the parent is iconic/minimized, no need to repaint, because
+ // this window is not shown anyway.
+
+ if ( IsIconic ( hWndParent ) ) {
+
+ PAINTSTRUCT ps;
+ HDC hDC;
+
+ hDC = BeginPaint ( hWnd, &ps );
+
+ // Paint the parent (MDI Doc) icon, if iconic.
+
+ EndPaint ( hWnd, &ps );
+ return TRUE;
+ }
+
+ break;
+ }
+
+ case WM_NCPAINT:
+ break;
+
+ case WM_ERASEBKGND:
+
+ if ( IsIconic ( GetParent ( hWnd ) ) ) {
+ return 0;
+ }
+
+ break;
+
+ } /* end switch () */
+
+ return CallWindowProc ( (VOID *)glpfnOldListProc, hWnd, msg, mp1, mp2 );
+
+} /* end WM_DocListWndProc() */
+
+
+/******************************************************************************
+
+ Name: WM_DocActivate()
+
+ Description: This function tells the MDI client to activate the
+ specified MDI document. If the document is minimized or
+ iconic, the document will be resored to the size and
+ position that it was prior to minimization.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID WM_DocActivate (
+
+HWND hWnd ) // I - handle to a MDI document window
+
+{
+ if ( IsIconic ( hWnd ) ) {
+
+ SendMessage( ghWndMDIClient, WM_MDIRESTORE, (MP1)hWnd, 0L );
+ }
+
+ SendMessage( ghWndMDIClient, WM_MDIACTIVATE, (MP1)hWnd, 0L );
+
+} /* end WM_DocActivate() */
+
+
+/******************************************************************************
+
+ Name: WM_DocCommandProc()
+
+ Description: This function is called by WM_MDIDocWndProc when a
+ command message is sent by windows to a MDI document
+ window.
+
+ Returns: FALSE, if the command was processed. Otherwise, TRUE.
+
+******************************************************************************/
+
+BOOL WM_DocCommandProc (
+
+HWND hWnd, // I - handle to an MDI document window
+MP1 mp1, // I - the ID of the list box for the command
+MP2 mp2 ) // I - just another parameter to pass the DLM
+
+{
+ switch ( GET_WM_COMMAND_ID ( mp1, mp2 ) ) {
+
+ case WMIDC_TREELISTBOX:
+ case WMIDC_FLATLISTBOX:
+
+ return DLM_LBNmessages ( hWnd, mp1, mp2 );
+
+ default:
+ break;
+
+ } /* end switch */
+
+ return TRUE;
+
+} /* end WM_DocCommandProc() */
+
+
+/******************************************************************************
+
+ Name: WM_DocCreate()
+
+ Description: This function is called by WM_MDIDocWndProc when an
+ MDI document has been created. Depending on the type
+ of document window created, one or two list boxes will
+ be created inside the document. If there are two
+ list boxes created, a slider bar will separate them.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID WM_DocCreate (
+
+HWND hWnd, // I - handle to a MDI document window
+LONG mp2 ) // I - an indirect pointer to a WMINFO structure
+ // to be attached to the doc window's extra bytes
+
+{
+ PDS_WMINFO pdsWinInfo;
+ DWORD dwWindowState;
+
+ // Menu stuff.
+ // Ribbon stuff.
+ // Display List stuff.
+ // Cursor stuff.
+ // More stuff.
+ //
+
+ // Get and set the window information pointer.
+
+ pdsWinInfo = (PDS_WMINFO)((LPMDICREATESTRUCT)((LPCREATESTRUCT)mp2)->lpCreateParams)->lParam;
+ pdsWinInfo->hWnd = hWnd;
+ WM_SetInfoPtr ( hWnd, pdsWinInfo );
+ dwWindowState = WMDS_GetWindowState ( pdsWinInfo );
+
+ // Create the TREE list box ONLY SINGLE COLUMN AT THIS TIME.
+
+ if ( dwWindowState & WMDOC_TREESC ) {
+
+ pdsWinInfo->hWndTreeList = CreateWindow ( WMCLASS_LISTBOX,
+ NULL,
+ WM_TREELISTBOX,
+ 0,
+ 0,
+ 0,
+ 0,
+ hWnd,
+ (HMENU)WMIDC_TREELISTBOX,
+ ghInst,
+ (LPSTR)NULL
+ );
+
+ WM_SubClassListBox ( pdsWinInfo->hWndTreeList );
+ }
+
+ // Create the FILE list box.
+
+ if ( ( dwWindowState & WMDOC_FLATMC ) || ( dwWindowState & WMDOC_FLATSC ) ) {
+
+ pdsWinInfo->hWndFlatList = CreateWindow ( WMCLASS_LISTBOX,
+ NULL,
+ ( ( dwWindowState & WMDOC_FLATMC ) ? WM_FLATLISTBOXMC : WM_FLATLISTBOXSC ),
+ 0,
+ 0,
+ 0,
+ 0,
+ hWnd,
+ (HMENU)WMIDC_FLATLISTBOX,
+ ghInst,
+ (LPSTR)NULL
+ );
+
+ WM_SubClassListBox ( pdsWinInfo->hWndFlatList );
+ }
+
+ // Create a View Window.
+
+ if ( ( dwWindowState == WMDOC_VIEWWIN ) ) {
+
+ pdsWinInfo->hWndFlatList = CreateWindow ( WMCLASS_VIEWWIN,
+ NULL,
+ WMSTYLE_VIEWWIN,
+ 0,
+ 0,
+ 0,
+ 0,
+ hWnd,
+ (HMENU)WMIDC_FLATLISTBOX,
+ ghInst,
+ (LPSTR)NULL
+ );
+
+ }
+
+ if ( pdsWinInfo->hWndTreeList ) {
+ WMDS_SetWinActiveList ( pdsWinInfo, WMDS_GetWinTreeList ( pdsWinInfo ) );
+ }
+ else {
+ WMDS_SetWinActiveList ( pdsWinInfo, WMDS_GetWinFlatList ( pdsWinInfo ) );
+ }
+
+
+
+} /* end WM_DocCreate() */
+
+
+/******************************************************************************
+
+ Name: WM_DocIsMenuChange()
+
+ Description: This function is called by WM_FrameCmdHandler when a
+ menu message is sent by windows to the frame window that
+ affects the way an MDI document is displayed.
+
+ Returns: TRUE, if the message affected an MDI document.
+ Otherwise, FALSE.
+
+******************************************************************************/
+
+WORD WM_DocIsMenuChange (
+
+HWND hWnd,
+WORD mp1 )
+
+{
+ PDS_WMINFO pdsWinInfo;
+ RECT Rect;
+ WORD msg = 0;
+
+
+ pdsWinInfo = WM_GetInfoPtr ( hWnd );
+
+ GetClientRect ( hWnd, &Rect );
+
+ switch ( mp1 ) {
+
+ case IDM_VIEWTREEANDDIR:
+
+ if ( ! ( pdsWinInfo->dwMenuState & MMDOC_TREEANDDIR ) ) {
+
+ pdsWinInfo->dwMenuState = MMDOC_TREEANDDIR | ( pdsWinInfo->dwMenuState & ~MMDOC_TREEGROUP );
+ pdsWinInfo->nSliderPos = WM_SLIDERUNKNOWN;
+
+ WM_DocSize ( hWnd, Rect.right, Rect.bottom );
+ msg = ID_TREEANDFLAT;
+ }
+
+ break;
+
+ case IDM_VIEWTREEONLY:
+
+ if ( ! ( pdsWinInfo->dwMenuState & MMDOC_TREEONLY ) ) {
+
+ pdsWinInfo->dwMenuState = MMDOC_TREEONLY | ( pdsWinInfo->dwMenuState & ~MMDOC_TREEGROUP );
+ pdsWinInfo->nSliderPos = WM_SLIDERMAX;
+
+ WM_DocSize ( hWnd, Rect.right, Rect.bottom );
+ msg = ID_TREEONLY;
+ }
+
+ break;
+
+ case IDM_VIEWDIRONLY:
+
+ if ( ! ( pdsWinInfo->dwMenuState & MMDOC_DIRONLY ) ) {
+
+ pdsWinInfo->dwMenuState = MMDOC_DIRONLY | ( pdsWinInfo->dwMenuState & ~MMDOC_TREEGROUP );
+ pdsWinInfo->nSliderPos = WM_SLIDERMIN;
+
+ WM_DocSize ( hWnd, Rect.right, Rect.bottom );
+ msg = ID_FLATONLY;
+ }
+
+ break;
+
+ case IDM_VIEWALLFILEDETAILS:
+
+ if ( ! ( pdsWinInfo->dwMenuState & MMDOC_FILEDETAILS ) ) {
+
+ pdsWinInfo->dwMenuState = MMDOC_FILEDETAILS | ( pdsWinInfo->dwMenuState & ~MMDOC_FILEGROUP );
+ msg = ID_FILEDETAILS;
+ }
+ else {
+
+ pdsWinInfo->dwMenuState = MMDOC_NAMEONLY | ( pdsWinInfo->dwMenuState & ~MMDOC_FILEGROUP );
+ msg = ID_NAMEONLY;
+ }
+ break;
+
+# ifndef OEM_MSOFT
+ {
+ case IDM_VIEWSORTNAME:
+
+ if ( ! ( pdsWinInfo->dwMenuState & MMDOC_SORTNAME ) ) {
+
+ pdsWinInfo->dwMenuState = MMDOC_SORTNAME | ( pdsWinInfo->dwMenuState & ~MMDOC_SORTGROUP );
+ msg = ID_SORTNAME;
+ }
+ break;
+
+ case IDM_VIEWSORTTYPE:
+
+ if ( ! ( pdsWinInfo->dwMenuState & MMDOC_SORTTYPE ) ) {
+
+ pdsWinInfo->dwMenuState = MMDOC_SORTTYPE | ( pdsWinInfo->dwMenuState & ~MMDOC_SORTGROUP );
+ msg = ID_SORTTYPE;
+ }
+ break;
+
+ case IDM_VIEWSORTSIZE:
+
+ if ( ! ( pdsWinInfo->dwMenuState & MMDOC_SORTSIZE ) ) {
+
+ pdsWinInfo->dwMenuState = MMDOC_SORTSIZE | ( pdsWinInfo->dwMenuState & ~MMDOC_SORTGROUP );
+ msg = ID_SORTSIZE;
+ }
+ break;
+
+ case IDM_VIEWSORTDATE:
+
+ if ( ! ( pdsWinInfo->dwMenuState & MMDOC_SORTDATE ) ) {
+
+ pdsWinInfo->dwMenuState = MMDOC_SORTDATE | ( pdsWinInfo->dwMenuState & ~MMDOC_SORTGROUP );
+ msg = ID_SORTDATE;
+ }
+ break;
+
+ }
+# endif
+
+ } /* end switch */
+
+ return msg;
+
+} /* end WM_DocIsMenuChange() */
+
+
+/******************************************************************************
+
+ Name: WM_DocQueryClose()
+
+ Description: This function is called by WM_MDIDocWndProc when a
+ MDI document has been told to close.
+
+ Returns: TRUE, if it is OK to close. Otherwise, FALSE.
+
+******************************************************************************/
+
+BOOL WM_DocQueryClose (
+
+HWND hWnd )
+
+{
+ DBG_UNREFERENCED_PARAMETER ( hWnd );
+ return TRUE;
+
+} /* end WM_DocQueryClose() */
+
+
+/******************************************************************************
+
+ Name: WM_DocSize()
+
+ Description: This function is called by WM_MDIDocWndProc when an
+ MDI document has been resized. If there is a slider in
+ the window, it will be repositioned in the window.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID WM_DocSize (
+
+HWND hWnd, // I - handle to a MDI document window
+INT nWidth, // I - the width of the document
+INT nHeight ) // I - the height of the document
+
+{
+ PDS_WMINFO pdsWinInfo;
+ DWORD dwWindowState;
+ INT nSliderWidth;
+ INT nSliderPos;
+ HWND hWndOldFocus;
+
+
+ // Save the handle to the window that has the current focus. Then set the
+ // focus to no window.
+
+ hWndOldFocus = GetFocus ();
+
+ SetFocus ( (HWND)NULL );
+
+ pdsWinInfo = WM_GetInfoPtr ( hWnd );
+ dwWindowState = pdsWinInfo->dwWindowState;
+
+ // Determine status of TREE and VIEW menu items. Remember, if a slider
+ // is all the way to the left (MIN), there will be no tree list box
+ // displayed.
+ // If a slider is all the way to the right (MAX), there will be no flat
+ // list box displayed. However, both of these constraints are true only
+ // if the MDI Document window has both tree and flat list boxes.
+
+ // If there is a slider, reposition it's rectangle.
+
+ if ( dwWindowState & WMDOC_SLIDER ) {
+
+ nSliderWidth = gnBorderWidth;
+
+ switch ( pdsWinInfo->nSliderPos ) {
+
+ case WM_SLIDERMIN:
+
+ nSliderPos = 0;
+ break;
+
+ case WM_SLIDERMAX:
+
+ nSliderPos = nWidth - nSliderWidth;
+ break;
+
+ case WM_SLIDERUNKNOWN:
+
+ if (nWidth == 0 ) {
+ nSliderPos = 0;
+ nSliderWidth = 0;
+ break ;
+ }
+
+ pdsWinInfo->nSliderPos = ( dwWindowState & WMDOC_TREEANDFLAT ) ?
+ ( nWidth - nSliderWidth ) / 2 : 0;
+
+ default:
+
+ nSliderPos = pdsWinInfo->nSliderPos;
+ break;
+
+ }
+ }
+ else {
+ nSliderWidth = 0;
+ nSliderPos = 0;
+ }
+
+ // If there is a file list, resize it's list box.
+
+ if ( ( dwWindowState & WMDOC_FLATSC ) || ( dwWindowState & WMDOC_FLATMC ) ) {
+
+ // WM_Hide ( pdsWinInfo->hWndFlatList );
+
+ WM_MoveWindow ( pdsWinInfo->hWndFlatList,
+ nSliderPos + nSliderWidth,
+ 0,
+ nWidth - ( nSliderPos + nSliderWidth ),
+ nHeight,
+ TRUE
+ );
+
+ }
+
+ // If there is a tree list, resize it's list box.
+
+ if ( dwWindowState & WMDOC_TREESC ) {
+
+ // WM_Hide ( pdsWinInfo->hWndTreeList );
+
+ WM_MoveWindow ( pdsWinInfo->hWndTreeList,
+ 0,
+ 0,
+ nSliderPos,
+ nHeight,
+ TRUE
+ );
+
+ }
+
+ // For View window, flat listbox window handle is the handle.
+
+ if ( dwWindowState == WMDOC_VIEWWIN ) {
+
+ WM_MoveWindow ( pdsWinInfo->hWndFlatList,
+ 0,
+ 0,
+ nWidth,
+ nHeight,
+ TRUE
+ );
+ }
+
+// WM_MultiTask ();
+
+ SetFocus ( hWndOldFocus );
+
+} /* end WM_DocSize() */
+
+
+/******************************************************************************
+
+ Name: WM_DocKeyDown()
+
+ Description: This function processes a key down message if a keyboard
+ key was pressed.
+
+ Returns: TRUE, if the key was used. Otherwise, FALSE.
+
+******************************************************************************/
+
+BOOL WM_DocKeyDown (
+
+HWND hWnd, // I - list box window handle
+WORD wKey ) // I - key information parameter
+
+{
+ WORD wVirKey = wKey;
+ BOOL fKeyUsed = TRUE;
+ BOOL fControlDown = ( GetKeyState ( VK_CONTROL ) < 0 ) ? TRUE : FALSE;
+ BOOL fShiftDown = ( GetKeyState ( VK_SHIFT ) < 0 ) ? TRUE : FALSE;
+ BOOL fTreeWindow = WM_IsTreeActive ( WM_GetInfoPtr ( GetParent ( hWnd ) ) );
+ BOOL wType = WMDS_GetWinType ( WM_GetInfoPtr ( GetParent ( hWnd ) ) );
+
+ if ( wVirKey == VK_CONTROL || wVirKey == VK_SHIFT ) {
+ return FALSE;
+ }
+
+ if ( wVirKey == VK_DELETE ) {
+
+ wVirKey = 0;
+ VLM_ChangeSettings(wKey, 0L);
+ return TRUE;
+ }
+
+ // Do the refresh if F5.
+
+ if ( wVirKey == VK_F5 && ! fControlDown && ! fShiftDown ) {
+
+ VLM_Refresh ( );
+ return TRUE;
+ }
+
+ // Do this only if it is a Disk or Tape Tree.
+
+ if ( fTreeWindow && ( wType == WMTYPE_DISKTREE
+ || wType == WMTYPE_TAPETREE
+#ifdef OEM_EMS
+ || wType == WMTYPE_EXCHANGE
+#endif
+ ) ) {
+
+ switch ( wVirKey ) {
+
+ case VK_8:
+
+ if ( ! fShiftDown ) {
+ break;
+ }
+
+ // Just fall through, since it is a shifted '8' or a '*'
+
+ case VK_MULTIPLY:
+
+ if ( fControlDown ) {
+ wKey = ID_EXPANDALL;
+ }
+ else {
+ wKey = ID_EXPANDBRANCH;
+ }
+
+ break;
+
+ case VK_SUBTRACT:
+ case VK_OEM_MINUS:
+
+ wKey = ID_COLLAPSEBRANCH;
+ break;
+
+ case VK_ADD:
+ case VK_OEM_PLUS:
+
+ wKey = ID_EXPANDONE;
+ break;
+
+ case VK_UP:
+
+ if ( fControlDown ) {
+ wKey = ID_CTRLARROWUP;
+ }
+ else {
+ fKeyUsed = FALSE;
+ }
+
+ break;
+
+ case VK_DOWN:
+
+ if ( fControlDown ) {
+ wKey = ID_CTRLARROWDOWN;
+ }
+ else {
+ fKeyUsed = FALSE;
+ }
+
+ break;
+
+ case VK_LEFT:
+
+ wKey = ID_ARROWLEFT;
+ break;
+
+ case VK_RIGHT:
+
+ wKey = ID_ARROWRIGHT;
+ break;
+
+ default:
+
+ fKeyUsed = FALSE;
+
+ } /* end switch */
+
+
+ if ( fKeyUsed ) {
+ VLM_ChangeSettings ( wKey, 0L );
+ }
+
+ }
+ else {
+ fKeyUsed = FALSE;
+ }
+
+ return fKeyUsed;
+
+} /* end WM_DocKeyDown() */
+
+
+/******************************************************************************
+
+ Name: WM_DocSetSliderMode()
+
+ Description:
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID WM_DocSetSliderMode (
+
+HWND hWnd, // I - handle to a MDI document window
+WORD wSliderMode ) // I - mode turning on/off the split window slider
+
+{
+ PDS_WMINFO pdsWinInfo;
+ DWORD dwWindowState;
+ INT nSliderPos;
+ RECT Rect;
+ POINT Point;
+
+ pdsWinInfo = WM_GetInfoPtr ( hWnd );
+ dwWindowState = pdsWinInfo->dwWindowState;
+
+ // Determine status of TREE and VIEW menu items. Remember, if a slider
+ // is all the way to the left (MIN), there will be no tree list box
+ // displayed.
+ // If a slider is all the way to the right (MAX), there will be no flat
+ // list box displayed. However, both of these constraints are true only
+ // if the MDI Document window has both tree and flat list boxes.
+
+
+ if ( ! mwfSliding && ( dwWindowState & WMDOC_SLIDER ) && ( wSliderMode == WMDOC_SLIDERON ) ) {
+
+ GetCursorPos ( &Point );
+ ScreenToClient ( hWnd, &Point );
+
+ WM_DocSetSliderPos ( hWnd, WMDOC_SLIDERON, (SHORT)Point.x );
+
+ mwfLButtonDown = TRUE;
+ mwfSliding = TRUE;
+
+ SetCapture ( hWnd );
+ SetFocus ( hWnd );
+ }
+ else if ( mwfSliding && ( wSliderMode == WMDOC_SLIDEROFF || wSliderMode == WMDOC_SLIDERCANCEL ) ) {
+
+ nSliderPos = (INT)WM_DocSetSliderPos ( hWnd, WMDOC_SLIDEROFF, 0 );
+
+ // If the mouse position is different from the slider position,
+ // reset the slider position to the current mouse position and
+ // resize the MDI Document window.
+
+ if ( wSliderMode == WMDOC_SLIDEROFF && nSliderPos != pdsWinInfo->nSliderPos ) {
+
+ GetClientRect ( hWnd, &Rect );
+
+ if ( nSliderPos >= ( Rect.right - ( gnBorderWidth + MIN_LISTBOX_WIDTH ) ) ) {
+
+ VLM_ChangeSettings ( (INT16) ID_TREEONLY, 0L );
+ pdsWinInfo->dwMenuState = MMDOC_TREEONLY | ( pdsWinInfo->dwMenuState & ~MMDOC_TREEGROUP );
+ pdsWinInfo->nSliderPos = WM_SLIDERMAX;
+ }
+ else if ( nSliderPos <= ( gnBorderWidth + MIN_LISTBOX_WIDTH ) ) {
+
+ VLM_ChangeSettings ( (INT16) ID_FLATONLY, 0L );
+ pdsWinInfo->dwMenuState = MMDOC_DIRONLY | ( pdsWinInfo->dwMenuState & ~MMDOC_TREEGROUP );
+ pdsWinInfo->nSliderPos = WM_SLIDERMIN;
+ }
+ else {
+
+ VLM_ChangeSettings ( (INT16) ID_TREEANDFLAT, 0L );
+ pdsWinInfo->dwMenuState = MMDOC_TREEANDDIR | ( pdsWinInfo->dwMenuState & ~MMDOC_TREEGROUP );
+ pdsWinInfo->nSliderPos = nSliderPos;
+ }
+
+ WM_DocSize ( hWnd, Rect.right, Rect.bottom );
+
+ }
+
+ mwfLButtonDown = FALSE;
+ mwfSliding = FALSE;
+
+ ReleaseCapture ();
+
+ SetFocus ( WMDS_GetWinActiveList ( pdsWinInfo ) );
+ }
+
+} /* end WM_DocSetSliderMode() */
+
+
+/******************************************************************************
+
+ Name: WM_DocSetSliderPos()
+
+ Description:
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+SHORT WM_DocSetSliderPos (
+
+HWND hWnd, // I - handle to an MDI document window
+WORD wStyle, // I - mouse message
+SHORT sNewSliderPos ) // I - the new slider position
+
+{
+ HDC hDC;
+ RECT Rect;
+ SHORT sOldSliderPos;
+
+ hDC = GetDC ( hWnd );
+
+ // If we are turning on the slider, set the old position.
+ // Otherwise, remove the old slider.
+
+ if ( wStyle == WMDOC_SLIDERON ) {
+ sOldSliderPos = sNewSliderPos;
+ }
+ else {
+ InvertRect ( hDC, &mwRectOldSlider );
+ sOldSliderPos = (SHORT)mwRectOldSlider.left;
+ }
+
+ // If there is a new slider to be drawn, draw it.
+
+ if ( wStyle != WMDOC_SLIDEROFF ) {
+
+ GetClientRect ( hWnd, &Rect );
+
+ Rect.left = sNewSliderPos;
+ Rect.right = sNewSliderPos + 4;
+
+ mwRectOldSlider = Rect;
+
+// memcpy ( &mwRectOldSlider, &Rect, sizeof ( RECT ) );
+
+ InvertRect ( hDC, &Rect );
+ }
+
+ ReleaseDC ( hWnd, hDC );
+
+ return sOldSliderPos;
+
+} /* end WM_DocSetSliderPos() */
diff --git a/private/utils/ntbackup/src/drives.c b/private/utils/ntbackup/src/drives.c
new file mode 100644
index 000000000..12e7ecd56
--- /dev/null
+++ b/private/utils/ntbackup/src/drives.c
@@ -0,0 +1,1771 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: drives.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the most drive related functions.
+
+
+ $Log: T:/LOGFILES/DRIVES.C_V $
+
+ Rev 1.50.1.7 12 Aug 1994 14:54:22 GREGG
+Make sure the drive block size is one the app can deal with in SetupDriveList.
+
+ Rev 1.50.1.6 06 Jul 1994 18:34:30 GREGG
+In Erase, report no tape as a TFLE, not TF and ignore TF returns from Rewind.
+
+ Rev 1.50.1.5 17 Feb 1994 18:00:52 GREGG
+Stop sending TFLEs to the UI tpos routine in Erase and Rewind.
+
+ Rev 1.50.1.4 11 Feb 1994 16:42:20 GREGG
+Ignore GEN_ERR_NO_MEDIA return from TpDismount. EPR 948-0278
+
+ Rev 1.50.1.3 28 Jan 1994 11:27:00 GREGG
+Handle GEN_ERR_UNRECOGNIZED_MEDIA returned on reads as well as mounts.
+
+ Rev 1.50.1.2 17 Dec 1993 16:40:12 GREGG
+Extended error reporting.
+
+ Rev 1.50.1.1 16 Nov 1993 23:13:00 GREGG
+Modified the way we control hardware compression from software to work around
+a bug in Archive DAT DC firmware rev. 3.58 (we shipped a lot of them).
+Files Modified: lw_data.c, lw_data.h, tfstuff.c, mtf10wdb.c, mtf10wt.c and
+ drives.c
+
+ Rev 1.50.1.0 08 Nov 1993 21:22:52 GREGG
+Put fixes in revs 1.55-1.57 in branch for Orcas.
+
+ Rev 1.50 29 Jul 1993 14:08:04 DON
+NLM only! Make the NLM code act the same for GEN_ERR_NO_MEDIA
+and GEN_ERR_UNRECOGNIZED_MEDIA
+
+ Rev 1.49 07 Jun 1993 08:32:52 MIKEP
+warning fix.
+
+ Rev 1.48 04 Jun 1993 18:42:58 GREGG
+Check for GEN_ERR_ENDSET return when writing a filemark. This shouldn't
+happen, but tell that to the HP DAT!
+
+ Rev 1.47 19 May 1993 17:41:16 GREGG
+Check for failure of TpSpecial SS_GET_DRV_INFO.
+
+ Rev 1.46 12 Apr 1993 22:48:04 GREGG
+Removed 297 TABS!!! Also removed stupid stuff from function headers.
+
+ Rev 1.45 11 Apr 1993 17:50:26 GREGG
+Expect GEN_ERR_RESET return from format command in EraseDrive.
+
+ Rev 1.44 09 Apr 1993 11:44:54 GREGG
+Dismount and remount the tape after it is formatted.
+
+ Rev 1.43 08 Apr 1993 11:07:26 GREGG
+Added debug print to WriteEndSet.
+
+ Rev 1.42 07 Apr 1993 20:38:38 GREGG
+Don't rewind first in EraseDrive if command is 'format'.
+
+ Rev 1.41 30 Mar 1993 16:15:54 GREGG
+Handle Unrecognized Media error (unformatted DC2000).
+
+ Rev 1.40 04 Feb 1993 18:25:34 ZEIR
+Brought forward Loader changes (OS_NLM only)
+
+ Rev 1.39 30 Jan 1993 11:19:38 DON
+Removed compiler warnings
+
+ Rev 1.38 21 Jan 1993 16:12:56 GREGG
+Added parameter to calls to TpSeek and TpGetPosition.
+
+ Rev 1.37 20 Jan 1993 17:32:18 BobR
+Changes to MOVE_ESA macro calls
+
+ Rev 1.36 18 Jan 1993 15:11:36 BobR
+Added MOVE_ESA macro call(s)
+
+ Rev 1.35 18 Jan 1993 14:09:52 GREGG
+Changes to allow format command passed to driver through TpErase.
+
+ Rev 1.34 11 Nov 1992 22:27:22 GREGG
+Chanded EraseDrive to do only security or non-security erase.
+
+ Rev 1.33 23 Oct 1992 15:17:48 GREGG
+Removes msassert wrapped around UI tpos call. (oops)
+
+ Rev 1.32 02 Oct 1992 16:14:32 HUNTER
+Add check for TpOpen() failure in SetUpDriveList().
+
+ Rev 1.31 22 Sep 1992 09:13:54 GREGG
+Initial changes to handle physical block sizes greater than 1K.
+
+ Rev 1.30 17 Aug 1992 09:01:28 GREGG
+Changes to deal with block sizeing scheme.
+
+ Rev 1.29 23 Jul 1992 10:33:16 GREGG
+Fixed warnings.
+
+ Rev 1.28 28 Mar 1992 18:23:06 GREGG
+ROLLER BLADES - OTC - Initial integration.
+
+ Rev 1.27 25 Mar 1992 18:18:36 GREGG
+ROLLER BLADES - Fixed GotoBlock to work with any physical/logical block size combination.
+
+ Rev 1.26 25 Mar 1992 14:57:48 NED
+reset TPS_NEW_TAPE and TPS_RESET bits
+
+ Rev 1.25 20 Mar 1992 18:02:12 NED
+added exception updating after TpReceive calls
+
+ Rev 1.24 03 Mar 1992 12:24:16 GREGG
+DisMount if rewind flag set and there's more than one drive in
+ResetChannelList.
+
+ Rev 1.23 19 Feb 1992 16:13:00 NED
+added DON's changes from 1.19.1.0->1.19.1.1 to trunk (ThreadSwitch)
+
+ Rev 1.22 08 Feb 1992 14:34:34 GREGG
+Changed check for lst_oper == -1 to check for boolean force_rewind, since
+this is what the lst_oper field in the drive structure had been reduced to.
+Also set force_rewind in cases where we know we have a new tape, but it
+won't be deteced by the call to TpMount (it only gets reported once), or
+where the driver had to rewind on DisMount to take the drive out of read/
+write mode and we want to tell the caller this happened.
+
+ Rev 1.21 03 Jan 1992 13:30:18 NED
+added DumpDebug() call
+
+ Rev 1.20 05 Dec 1991 13:50:44 GREGG
+SKATEBOARD - New Buff Mgt - Initial Integration.
+
+ Rev 1.19 02 Dec 1991 13:45:20 GREGG
+Return a reasonable error code from RewindDrive.
+
+ Rev 1.18 25 Nov 1991 10:06:58 GREGG
+Added ThreadSwitches after TpInit and TpAuto calls to keep that silly NLM happy.
+
+ Rev 1.17 18 Oct 1991 14:06:46 GREGG
+BIGWHEEL - Added missing break in case in MountTape for PollDrive cleanup.
+
+ Rev 1.16 17 Oct 1991 01:25:06 GREGG
+BIGWHEEL - 8200sx - Initial integration.
+
+ Rev 1.15 15 Oct 1991 07:57:54 GREGG
+Added ThreadSwitch call in empty TpReceive loops.
+
+ Rev 1.14 14 Oct 1991 11:18:06 GREGG
+Modified MountTape's handling of busy poll state to deal with changes made to
+PollDrive. UpdateDriveStatus now returns INT16 and actually reports drive
+failures!
+
+ Rev 1.13 09 Oct 1991 12:02:12 GREGG
+If NextDriveInChannel hits the end of the channel list, and rewind is
+requested, dismount the tape. * * * NOTE: This is a KLUDGE FIX!!!
+It should be investigated and fixed correctly when time allows.
+
+ Rev 1.12 07 Oct 1991 22:15:34 GREGG
+Reset drive position after tension operation.
+
+ Rev 1.11 28 Sep 1991 21:47:04 GREGG
+Removed BE_Zprintf's from UpdateDriveStatus.
+
+ Rev 1.10 17 Sep 1991 13:34:20 GREGG
+Added TF_MOUNTING message to MountTape.
+
+ Rev 1.9 09 Sep 1991 23:05:40 GREGG
+Added init of new drive struct elements and modified MountTape for TF_PollDrive.
+
+ Rev 1.8 21 Aug 1991 14:40:50 GREGG
+Added RewindDriveImmediate for TF_RewindAllDrives.
+
+ Rev 1.7 22 Jul 1991 13:03:30 GREGG
+Added debug printf to drive init routine.
+
+ Rev 1.6 15 Jul 1991 15:13:12 NED
+Removed unnecessary rewinds.
+
+ Rev 1.5 01 Jul 1991 10:51:18 NED
+Removed CH_AT_EOM
+
+ Rev 1.4 06 Jun 1991 22:53:18 NED
+Moved all the positioning functions to tflutils.c, and added CAST to
+remove a warning.
+
+ Rev 1.3 03 Jun 1991 10:43:48 NED
+added parameter to MoveToVCB().
+
+ Rev 1.2 20 May 1991 15:41:42 DAVIDH
+Cleared up Watcom warnings for defined, but not referenced parameters.
+
+ Rev 1.1 10 May 1991 16:17:02 GREGG
+Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:11:52 GREGG
+Initial revision.
+
+**/
+/* begin include list */
+
+#include <memory.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "queues.h"
+
+#include "drive.h"
+#include "channel.h"
+#include "tfl_err.h"
+#include "lw_data.h"
+#include "lwprotos.h"
+#include "translat.h"
+#include "sx.h"
+
+/* Device Driver InterFace Headers */
+#include "retbuf.h"
+#include "special.h"
+#include "dilhwd.h"
+#include "drvinf.h"
+#include "generr.h"
+#include "genfuncs.h"
+#include "dil.h"
+#include "genstat.h"
+#include "dddefs.h"
+
+/* Debug Stuff */
+#include "be_debug.h"
+
+VOID InitializeTapeBlockSize( void ) ;
+
+/**/
+/**
+
+ Name: ResetChannelList
+
+ Description: Resets the current drive pointer to the head of the
+ channel list.
+
+ Returns: Returns an Error code, or Zero is successful.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+INT16 ResetChannelList( CHANNEL_PTR channel, /* The channel we want to reset */
+ BOOLEAN rew_cur_drv ) /* Rewind current Drive */
+{
+ INT16 ret_val = TFLE_NO_ERR ;
+ BOOLEAN is_tape_present ;
+ Q_ELEM_PTR prev_drive, drv_head ;
+
+ if ( rew_cur_drv ) {
+ (void) RewindDrive( channel->cur_drv, NULL, FALSE, TRUE, channel->mode ) ;
+ }
+
+ /* If there is actually more than one drive in the system */
+ if( channel->cur_drv->thw_inf.channel_link.q_next != NULL ||
+ channel->cur_drv->thw_inf.channel_link.q_prev != NULL ) {
+
+ if ( rew_cur_drv ) {
+ (void) DisMountTape( channel->cur_drv, NULL, FALSE ) ;
+ }
+
+ drv_head = prev_drive = ( Q_ELEM_PTR ) &channel->cur_drv->thw_inf.channel_link ;
+ while ( ( prev_drive = QueuePrev( prev_drive ) ) != NULL ) {
+ drv_head = prev_drive ;
+ }
+
+ if( drv_head ) {
+
+ channel->cur_drv = ( DRIVE_PTR ) GetQueueElemPtr( drv_head ) ;
+
+ ret_val = MountTape( channel->cur_drv, NULL, &is_tape_present ) ;
+
+ } else {
+ ret_val = TF_END_CHANNEL ;
+ }
+
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Name: NextDriveInChannel
+
+ Description: This closes the current drive in the channel. And then
+ opens the next drive in the channel.
+
+ Returns: An error code.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+INT16 NextDriveInChannel(
+ CHANNEL_PTR channel, /* The channel you want to use */
+ BOOLEAN rew_cur_drv ) /* Rewind the Current Drive */
+{
+ Q_ELEM_PTR nxt_elem ;
+ DRIVE_PTR nxt_drive ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ BOOLEAN is_tape_present ;
+
+ nxt_elem = QueueNext( ( Q_ELEM_PTR ) &channel->cur_drv->thw_inf.channel_link ) ;
+
+ if( nxt_elem ) {
+ nxt_drive = ( DRIVE_PTR ) GetQueueElemPtr( nxt_elem ) ;
+
+ /* DisMount This tape */
+ DisMountTape( channel->cur_drv, NULL, rew_cur_drv ) ;
+
+ if( ( ret_val = MountTape( nxt_drive, NULL, &is_tape_present ) ) == TFLE_NO_ERR ) {
+ channel->cur_drv = nxt_drive ;
+ /* Someone wanted a rewind */
+ if( is_tape_present && channel->cur_drv->force_rewind ) {
+ RewindDrive( channel->cur_drv, channel->ui_tpos, TRUE, TRUE, channel->mode ) ;
+ channel->cur_drv->force_rewind = FALSE ;
+ }
+ }
+ } else {
+ if( rew_cur_drv ) {
+ DisMountTape( channel->cur_drv, channel->ui_tpos, rew_cur_drv ) ;
+ }
+ ret_val = TF_END_CHANNEL ;
+ }
+
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Name: PrevDriveInChannel
+
+ Description: Switches to the previous drive in the channel.
+
+ Returns: An Error Code.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+
+INT16 PrevDriveInChannel(
+ CHANNEL_PTR channel, /* The channel you want to use */
+ BOOLEAN rew_cur_drv ) /* Rewind Current Drive */
+{
+ Q_ELEM_PTR prev_elem ;
+ DRIVE_PTR prev_drive ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ BOOLEAN is_tape_present ;
+
+ prev_elem = QueuePrev( ( Q_ELEM_PTR ) &channel->cur_drv->thw_inf.channel_link ) ;
+
+ if( prev_elem ) {
+
+ /* DisMount This tape */
+ DisMountTape( channel->cur_drv, NULL, rew_cur_drv ) ;
+
+ prev_drive = ( DRIVE_PTR ) GetQueueElemPtr( prev_elem ) ;
+
+ if( !( ret_val = MountTape( prev_drive, NULL, &is_tape_present ) ) ) {
+ channel->cur_drv = prev_drive ;
+ /* Someone wanted a rewind */
+ if( is_tape_present && channel->cur_drv->force_rewind ) {
+ RewindDrive( channel->cur_drv, channel->ui_tpos, TRUE, TRUE, channel->mode ) ;
+ channel->cur_drv->force_rewind = FALSE ;
+ }
+ }
+ } else {
+ ret_val = TF_END_CHANNEL ;
+ }
+
+ return( ret_val ) ;
+
+}
+
+/**/
+/**
+
+ Name: RewindDrive
+
+ Description: Rewinds the current drive in the channel and resets all the
+ appropriate fields.
+
+ Returns: An Error code if there is a problem.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+INT16 RewindDrive(
+ DRIVE_PTR curDRV , /* the current drive */
+ TPOS_PTR ui_tpos , /* To tell him i'ma workin' */
+ BOOLEAN call_ui , /* Should we call the user interface */
+ BOOLEAN reset_flg , /* Should we reset the counters */
+ UINT16 mode ) /* the mode we're in */
+{
+ INT16 drv_hdl = curDRV->drv_hdl ;
+ UINT16 i = 1 ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ RET_BUF myret ;
+
+ if ( ui_tpos == NULL ) {
+ call_ui = FALSE ;
+ }
+
+ BE_Zprintf(DEBUG_TAPE_FORMAT, RES_REWIND_DRIVE_HDL, drv_hdl ) ;
+
+ if( call_ui ) {
+ ui_tpos->UI_TapePosRoutine( TF_REWINDING, ui_tpos, curDRV->vcb_valid, &curDRV->cur_vcb, mode ) ;
+ }
+
+ myret.gen_error = GEN_NO_ERR ;
+
+ /* This logic is to handle the case that we have read exactly to the filemark
+ on tape, and since the last read did not fail, the filemark will be reported
+ on this rewind call. So if we get a filemark error on rewind ( I mean how
+ stupid are these drives ), kill the error queue, and recall TpRewind */
+ do {
+ if( TpRewind( drv_hdl, FALSE ) == SUCCESS ) {
+ while( TpReceive( drv_hdl, &myret ) == FAILURE ) {
+ if( call_ui ) {
+ /* Move ESA info directly to TPOS instead of going
+ through THW for optimal speed
+ */
+ MOVE_ESA( ui_tpos->the, myret.the ) ;
+
+ (*ui_tpos->UI_TapePosRoutine)( TF_IDLE_NOBREAK, ui_tpos, curDRV->vcb_valid, &curDRV->cur_vcb, mode ) ;
+ } else {
+ /* for non-preemptive operating systems: */
+ ThreadSwitch( ) ;
+ }
+ }
+ } else {
+ return( TFLE_DRIVER_FAILURE ) ;
+ }
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( curDRV->thw_inf.the, myret.the ) ;
+
+ /* This is to fix the Archive drives unwillingness to report an exception */
+ if( myret.gen_error == GEN_ERR_NO_MEDIA || myret.gen_error == GEN_RESET ) {
+ curDRV->vcb_valid = FALSE ;
+ }
+ BE_Zprintf(DEBUG_TAPE_FORMAT, RES_DRV_RET, myret.gen_error ) ;
+ if ( myret.gen_error != GEN_NO_ERR ) {
+ curDRV->thw_inf.drv_status = myret.status ;
+ DumpDebug( drv_hdl ) ;
+ }
+ } while( ret_val == TFLE_NO_ERR && myret.gen_error != GEN_NO_ERR && i-- ) ;
+
+ if( myret.gen_error ) {
+ ret_val = MapGenErr2UIMesg( myret.gen_error ) ;
+ if ( call_ui && !IsTFLE( ret_val ) ) {
+ (*ui_tpos->UI_TapePosRoutine)( ret_val, ui_tpos, curDRV->vcb_valid, &curDRV->cur_vcb, mode ) ;
+ }
+ }
+
+ if( reset_flg ) {
+ ResetDrivePosition( curDRV ) ;
+ }
+
+ SetPosBit( curDRV, AT_BOT ) ;
+
+ BE_Zprintf(DEBUG_TAPE_FORMAT, RES_RET_VAL_EQUALS, ret_val ) ;
+
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Name: EraseDrive
+
+ Description:
+
+ Modified: 11/10/1989 11:9:26
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+INT16 EraseDrive(
+ CHANNEL_PTR channel,
+ BOOLEAN security, /* as opposed to write a filemark only */
+ BOOLEAN format ) /* for DC 2000 */
+{
+ INT16 drv_hdl = channel->cur_drv->drv_hdl, ret_val = TFLE_NO_ERR ;
+ DRIVE_PTR curDRV = channel->cur_drv ;
+ RET_BUF myret ;
+ BOOLEAN is_tape_present = TRUE ;
+ BOOLEAN tp_ret ;
+
+ BE_Zprintf( 0, TEXT("EraseDrive() security=%d\n"), security ) ;
+
+ /* Make sure error condition is reset first */
+ myret.gen_error = GEN_NO_ERR ;
+
+ /* Rewind, as we are probably in a read state */
+ if( security && !format ) {
+ if( ( ret_val = RewindDrive( channel->cur_drv, channel->ui_tpos, TRUE,
+ TRUE, channel->mode ) ) != TFLE_NO_ERR ) {
+
+ /* If we get an error, we return it immediatly, otherwise
+ it's just a message and we ignore it.
+ */
+ if ( IsTFLE( ret_val ) ) {
+ return( ret_val ) ;
+ } else {
+ ret_val = TFLE_NO_ERR ;
+ }
+ }
+ }
+
+ /* Possible Write Protect Error! */
+ if( (*channel->ui_tpos->UI_TapePosRoutine)( TF_ERASING, channel->ui_tpos,
+ curDRV->vcb_valid,
+ &curDRV->cur_vcb,
+ channel->mode )
+ == UI_ABORT_POSITIONING ) {
+
+ return( TFLE_USER_ABORT ) ;
+ }
+
+ if( security ) {
+ BE_Zprintf(DEBUG_TAPE_FORMAT, RES_CALLING_ERASE );
+ if( format ) {
+ tp_ret = TpErase( drv_hdl, ERASE_TYPE_FORMAT ) ;
+ } else {
+ tp_ret = TpErase( drv_hdl, ERASE_TYPE_SECURITY ) ;
+ }
+ if( tp_ret == SUCCESS ) {
+ while( TpReceive( drv_hdl, &myret ) == FAILURE ) {
+ /* Move ESA info directly to TPOS instead of going
+ through THW for optimal speed
+ */
+ MOVE_ESA( channel->ui_tpos->the, myret.the ) ;
+
+ (*channel->ui_tpos->UI_TapePosRoutine)( TF_IDLE_NOBREAK,
+ channel->ui_tpos,
+ curDRV->vcb_valid,
+ &curDRV->cur_vcb,
+ channel->mode ) ;
+ }
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( channel->cur_drv->thw_inf.the, myret.the ) ;
+
+ if ( myret.gen_error != GEN_NO_ERR ) {
+ curDRV->thw_inf.drv_status = myret.status ;
+ }
+ } else {
+ return( TFLE_DRIVER_FAILURE ) ;
+ }
+ }
+
+ if( myret.gen_error != GEN_NO_ERR && myret.gen_error != GEN_ERR_RESET ) {
+ curDRV->thw_inf.drv_status = myret.status ;
+ if( myret.gen_error == GEN_ERR_NO_MEDIA ) {
+ ret_val = TFLE_NO_TAPE ;
+ } else {
+ ret_val = MapGenErr2UIMesg( myret.gen_error ) ;
+ }
+ if ( !IsTFLE( ret_val ) ) {
+ (*channel->ui_tpos->UI_TapePosRoutine)( ret_val,
+ channel->ui_tpos,
+ curDRV->vcb_valid,
+ &curDRV->cur_vcb,
+ channel->mode ) ;
+ ret_val = TFLE_UI_HAPPY_ABORT ;
+ }
+ return( ret_val ) ;
+ }
+
+ if( format ) {
+ /* Make sure the stupid thing has it's head on straight! */
+ (void) DisMountTape( channel->cur_drv, NULL, FALSE ) ;
+ ret_val = MountTape( channel->cur_drv, NULL, &is_tape_present ) ;
+ if( ret_val != TFLE_NO_ERR ) {
+
+ if ( !IsTFLE( ret_val ) ) {
+ (*channel->ui_tpos->UI_TapePosRoutine)( ret_val,
+ channel->ui_tpos,
+ curDRV->vcb_valid,
+ &curDRV->cur_vcb,
+ channel->mode ) ;
+ ret_val = TFLE_UI_HAPPY_ABORT ;
+ }
+ return( ret_val ) ;
+ }
+ }
+
+ if( ( ret_val = RewindDrive( channel->cur_drv, channel->ui_tpos, TRUE,
+ TRUE, channel->mode ) ) != TFLE_NO_ERR ) {
+
+ /* If we get an error, we return it immediatly, otherwise
+ it's just a message and we ignore it.
+ */
+ if ( IsTFLE( ret_val ) ) {
+ return( ret_val ) ;
+ } else {
+ ret_val = TFLE_NO_ERR ;
+ }
+ }
+
+ InitializeTapeBlockSize( ) ;
+
+ BE_Zprintf(DEBUG_TAPE_FORMAT, RES_CALLING_WRITE_END_SET );
+ if( TpWriteEndSet( drv_hdl ) != SUCCESS ) {
+ return( TFLE_DRIVER_FAILURE ) ;
+ }
+ while( TpReceive( drv_hdl, &myret ) == FAILURE ) {
+ /* Move ESA info directly to TPOS instead of going through
+ THW for optimal speed */
+ MOVE_ESA( channel->ui_tpos->the, myret.the ) ;
+
+ (*channel->ui_tpos->UI_TapePosRoutine)( TF_IDLE_NOBREAK,
+ channel->ui_tpos,
+ curDRV->vcb_valid,
+ &curDRV->cur_vcb,
+ channel->mode ) ;
+ }
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( channel->cur_drv->thw_inf.the, myret.the ) ;
+
+ if ( myret.gen_error != GEN_NO_ERR ) {
+ curDRV->thw_inf.drv_status = myret.status ;
+ ret_val = MapGenErr2UIMesg( myret.gen_error ) ;
+ if ( !IsTFLE( ret_val ) ) {
+ (*channel->ui_tpos->UI_TapePosRoutine)( ret_val,
+ channel->ui_tpos,
+ curDRV->vcb_valid,
+ &curDRV->cur_vcb,
+ channel->mode ) ;
+ ret_val = TFLE_UI_HAPPY_ABORT ;
+ }
+ return( ret_val ) ;
+ }
+
+ ret_val = RewindDrive( channel->cur_drv, channel->ui_tpos, TRUE, TRUE, channel->mode ) ;
+
+ /* If the return is just a message, ignore it. */
+ if ( !IsTFLE( ret_val ) ) {
+ ret_val = TFLE_NO_ERR ;
+ }
+
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Name: RetensionDrive
+
+ Description: Retension the tape in the current drive.
+
+ Returns: Nothing
+
+ Notes: THE ui_tpos ROUTINE MUST BE VALID BEFORE THIS IS CALLED.
+
+ Declaration:
+
+**/
+
+INT16 RetensionDrive( CHANNEL_PTR channel )
+{
+ INT16 drv_hdl = channel->cur_drv->drv_hdl ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ DRIVE_PTR curDRV = channel->cur_drv ;
+ RET_BUF myret ;
+
+ /* Inform Ernie of the Start */
+ channel->ui_tpos->UI_TapePosRoutine( TF_RETENSIONING, channel->ui_tpos, curDRV->vcb_valid,
+ &curDRV->cur_vcb, channel->mode ) ;
+
+ if( TpRetension( channel->cur_drv->drv_hdl ) == FAILURE ) {
+ return( TFLE_DRIVER_FAILURE ) ;
+ }
+ while( TpReceive( drv_hdl, &myret ) == FAILURE ) {
+ /* Move ESA info directly to TPOS instead of going through
+ THW for optimal speed */
+ MOVE_ESA( channel->ui_tpos->the, myret.the ) ;
+
+ if( (*channel->ui_tpos->UI_TapePosRoutine)( TF_IDLE_NOBREAK, channel->ui_tpos, curDRV->vcb_valid, &curDRV->cur_vcb, channel->mode )
+ == UI_ABORT_POSITIONING ) {
+ ret_val = TFLE_USER_ABORT ;
+ break ;
+ }
+ }
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( channel->cur_drv->thw_inf.the, myret.the ) ;
+
+ if ( myret.gen_error != GEN_NO_ERR ) {
+ curDRV->thw_inf.drv_status = myret.status ;
+ ret_val = TFLE_DRIVE_FAILURE ;
+ } else {
+ ResetDrivePosition( curDRV ) ;
+ SetPosBit( curDRV, AT_BOT ) ;
+ }
+
+ return ret_val ;
+}
+
+/**/
+/**
+
+ Name: CloseDrive
+
+ Description: Close the specified drive.
+
+ Returns: An error code.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+INT16 CloseDrive(
+ DRIVE_PTR drive ,
+ TPOS_PTR ui_tpos ,
+ UINT16 mode ,
+ BOOLEAN rewind )
+{
+ RET_BUF myret ;
+ INT16 ret_val = TFLE_NO_ERR ;
+
+ BE_Zprintf(DEBUG_TAPE_FORMAT, RES_CLOSE_DRIVE ) ;
+
+ if( drive->thw_inf.drv_info.drv_features
+ & TDI_DRV_COMPRES_INIT ) {
+ TpSpecial( drive->drv_hdl, SS_SET_DRV_COMPRESSION, ENABLE_DRV_COMPRESSION ) ;
+ } else {
+ TpSpecial( drive->drv_hdl, SS_SET_DRV_COMPRESSION, DISABLE_DRV_COMPRESSION ) ;
+ }
+
+ /* Somebody has told us not to really close the drive, We are
+ probably in the middle of a set */
+ if( !IsPosBitSet( drive, DONT_CLOSE ) ) {
+ if( rewind ) {
+ BE_Zprintf(DEBUG_TAPE_FORMAT, RES_REWIND ) ;
+ ResetDrivePosition( drive ) ;
+ TpCloseRewind( drive->drv_hdl ) ;
+ } else {
+ BE_Zprintf(DEBUG_TAPE_FORMAT, RES_NO_REWIND ) ;
+ TpClose( drive->drv_hdl ) ;
+ }
+ do {
+ while( TpReceive( drive->drv_hdl, &myret ) == FAILURE ) {
+ if( ui_tpos != NULL ) {
+ /* Move ESA info directly to TPOS instead of going through
+ THW for optimal speed */
+ MOVE_ESA( ui_tpos->the, myret.the ) ;
+
+ ui_tpos->UI_TapePosRoutine( TF_IDLE, ui_tpos, drive->vcb_valid, &drive->cur_vcb, mode ) ;
+
+ } else {
+ /* for non-preemptive operating systems: */
+ ThreadSwitch( ) ;
+ }
+ }
+ if ( myret.gen_error != GEN_NO_ERR ) {
+ drive->thw_inf.drv_status = myret.status ;
+ }
+ } while( myret.call_type != GEN_NRCLOSE && myret.call_type != GEN_RCLOSE ) ;
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( drive->thw_inf.the, myret.the ) ;
+
+ drive->drv_hdl = 0 ;
+ drive->trans_started = FALSE ;
+ }
+
+ /* reset our idea of one-shot drive status bits */
+ drive->thw_inf.drv_status &= ~( TPS_RESET | TPS_NEW_TAPE ) ;
+
+ BE_Zprintf(DEBUG_TAPE_FORMAT, RES_NEW_LINE ) ;
+
+ /* Reset It for latter, this ticket is only good for one ride */
+ ClrPosBit( drive, DONT_CLOSE ) ;
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Name: SetupDriveList
+
+ Description: This initializes the drivers allocates the tables for
+ it.
+
+ Returns:
+
+ Notes: IF THIS IS BEING CALLED MORE THAN ONCE, AFTER THE FIRST
+ TIME YOU MUST CALL "TpRelease()" and DEALLOCATE THE DRIVE
+ LIST.
+
+ Declaration:
+
+**/
+
+
+INT16 SetupDriveList(
+ DIL_HWD_PTR cards,
+ INT16 no_cards )
+{
+ UINT16 tdrives = 0 ;
+ INT16 i, thdl ;
+ UINT16 j ;
+ INT16 ret_val = TFLE_NO_ERR ;
+
+ /* Set up the pointer to the controller cards */
+ lw_tfl_control.cntl_cards = cards ;
+ InitQueue( &lw_drive_list ) ;
+
+
+ /* First, we need to predetermine the cards irqs & dma and see if there
+ are any conflicts */
+ TpAuto( cards, no_cards ) ;
+ ThreadSwitch( ) ;
+
+ ret_val = TpInit( cards, no_cards ) ;
+ ThreadSwitch( ) ;
+
+ BE_Zprintf( DEBUG_TAPE_FORMAT, RES_TPINIT_FAILURE, ret_val ) ;
+
+ if( ret_val == SUCCESS ) {
+
+ for( i = 0 ; i < no_cards ; i++ ) {
+ BE_Zprintf( DEBUG_TAPE_FORMAT, RES_PARM_BLK_DESCR, i ) ;
+ for( j = 0 ; j < 20 ; j+=5 ) {
+ BE_Zprintf( DEBUG_TAPE_FORMAT, RES_PARM_BLK,
+ cards[i].parameters[j],
+ cards[i].parameters[j+1],
+ cards[i].parameters[j+2],
+ cards[i].parameters[j+3],
+ cards[i].parameters[j+4] ) ;
+ }
+ }
+
+ lw_tfl_control.driver_inited = TRUE ;
+
+ for( i = 0, tdrives = 0 ; i < no_cards ; i++ ) {
+ tdrives += cards[i].no_attached_drives ;
+ }
+
+ if( tdrives ) {
+ /* This DISABLES the first request in the DRIVER, perhaps this should
+ not be done on NON MS/DOS Applications */
+ TpSpecial( (INT16)0, (INT16)SS_NO_1ST_REQ, 0L ) ;
+ if( ( lw_drives = calloc( tdrives, sizeof( DRIVE ) ) ) != NULL ) {
+ for( i = 0, tdrives = 0 ; i < no_cards ; i++ ) {
+ for( j = 0 ; j < cards[i].no_attached_drives ; j++, tdrives++ ) {
+ thdl = lw_drives[tdrives].drv_hdl = TpOpen( &cards[i], (INT16)( j + 1 ) ) ;
+ if( !thdl ) {
+ return( TFLE_DRIVER_FAILURE ) ;
+ }
+ if( TpSpecial( thdl, (INT16)SS_GET_DRV_INF, ( UINT32 ) &lw_drives[tdrives].thw_inf.drv_info ) == FAILURE ) {
+ return( TFLE_DRIVER_FAILURE ) ;
+ }
+
+ /* There is a limited set of physical block
+ sizes our app can deal with. So if the
+ current setting doesn't match any of these
+ we're going to force the drive to its
+ default size.
+ */
+ if( lw_drives[tdrives].thw_inf.drv_info.drv_features
+ & TDI_CHNG_BLK_SIZE ) {
+
+ BOOLEAN size_ok = FALSE ;
+ INT idx ;
+ UINT16 bsize = lw_drives[tdrives].thw_inf.drv_info.drv_bsize ;
+
+ for( idx = 0; idx < lw_num_blk_sizes; idx++ ) {
+ if( bsize == lw_blk_size_list[idx] ) {
+ size_ok = TRUE ;
+ break ;
+ }
+ }
+ if( !size_ok ) {
+ if( TpSpecial( thdl, SS_CHANGE_BLOCK_SIZE, DEFAULT_BLOCK_SIZE ) != SUCCESS ) {
+ return( TFLE_DRIVER_FAILURE ) ;
+ }
+ if( TpSpecial( thdl, (INT16)SS_GET_DRV_INF, ( UINT32 ) &lw_drives[tdrives].thw_inf.drv_info ) == FAILURE ) {
+ return( TFLE_DRIVER_FAILURE ) ;
+ }
+ }
+ }
+
+ /* If the drive supports hardware compression
+ we need to keep it in uncompressed mode
+ unless we're actually writing a compressed
+ set. This is a work-around for a firmware
+ bug in early Archive DAT DC drives.
+ */
+ if( lw_drives[tdrives].thw_inf.drv_info.drv_features
+ & TDI_DRV_COMPRESS_ON ) {
+
+ lw_drives[tdrives].thw_inf.drv_info.drv_features |=
+ TDI_DRV_COMPRES_INIT ;
+ } else {
+ lw_drives[tdrives].thw_inf.drv_info.drv_features &=
+ ~TDI_DRV_COMPRES_INIT ;
+ }
+
+ if( lw_drives[tdrives].thw_inf.drv_info.drv_features
+ & TDI_DRV_COMPRESSION ) {
+
+ if( TpSpecial( thdl, SS_SET_DRV_COMPRESSION, DISABLE_DRV_COMPRESSION ) != SUCCESS ) {
+ return( TFLE_DRIVER_FAILURE ) ;
+ }
+ }
+
+ lw_drives[tdrives].drv_no = ( j + 1 ) ;
+ /* Check to see if they have requested fast file to be active,
+ if not, unconditionally set any fast file bits off ( including the MaynStream 2200+ ) */
+ if( !lw_tfl_control.use_fast_file ) {
+ lw_drives[tdrives].thw_inf.drv_info.drv_features &= ~TDI_FAST_NBLK ;
+ lw_drives[tdrives].thw_inf.drv_info.drv_features &= ~TDI_FIND_BLK ;
+ }
+ /* Which controller card is it attached to */
+ lw_drives[tdrives].thw_inf.card_no = i ;
+ /* This forces a rewind in TF_OpenSet, since
+ we won't know we have a new tape.
+ */
+ lw_drives[tdrives].force_rewind = TRUE ;
+ /* Point back to the head of the structure, so when we reference
+ the channel link we can get the structure's address */
+ SetQueueElemPtr( &lw_drives[tdrives].thw_inf.channel_link,
+ ( VOID_PTR ) &lw_drives[tdrives].thw_inf ) ;
+ EnQueueElem( &lw_drive_list, &lw_drives[tdrives].thw_inf.link, FALSE ) ;
+ /* ensure that we don't know the format */
+ lw_drives[tdrives].last_cur_fmt = UNKNOWN_FORMAT ;
+ lw_drives[tdrives].last_fmt_env = NULL ;
+ lw_drives[tdrives].poll_stuff.state = st_CLOSED ;
+ lw_drives[tdrives].poll_stuff.channel = NULL ;
+ }
+ }
+ } else {
+ ret_val = TFLE_NO_MEMORY ;
+ }
+ }
+ } else {
+
+ ret_val = TFLE_DRIVER_FAILURE ;
+ }
+
+ for( i = 0; i < no_cards; i++ ) {
+ BE_Zprintf( 0, TEXT("card #%d: # of drives = %d; dd_init_err = %d\n"),
+ i, cards[i].no_attached_drives, cards[i].init_error ) ;
+ }
+
+ return( ret_val ) ;
+
+}
+
+
+/**/
+/**
+
+ Name: UpdateDriveStatus
+
+ Description: Takes the return information from the ret buf and updates
+ the drive stuff. If the status has changed, this flips the
+ boolean inside the drive struct.
+
+ Returns: TFLE_xxx
+
+ Notes:
+
+ Declaration:
+
+**/
+
+INT16 UpdateDriveStatus( DRIVE_PTR drive )
+{
+ RET_BUF myret ;
+ INT16 ret_val = TFLE_NO_ERR ;
+
+ if( TpStatus( drive->drv_hdl ) != SUCCESS ) {
+ return( TFLE_DRIVER_FAILURE ) ;
+ }
+ while( TpReceive( drive->drv_hdl, &myret ) == FAILURE ) {
+ /* for non-preemptive operating systems: */
+ ThreadSwitch( ) ;
+ }
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( drive->thw_inf.the, myret.the ) ;
+
+ /* We ignore the unrecognized media here and catch it in MountTape
+ or PollDrive Mount.
+ */
+ if( myret.gen_error != GEN_NO_ERR &&
+ myret.gen_error != GEN_ERR_UNRECOGNIZED_MEDIA ) {
+
+ ret_val = TFLE_DRIVE_FAILURE ;
+ } else {
+
+ /* Assume It hasn't */
+ drive->thw_inf.status_changed = FALSE ;
+
+ /* Set up Counters */
+ drive->cur_stats.underruns = myret.underruns ;
+ drive->cur_stats.dataerrs = myret.readerrs ;
+
+ /* If the status is different, set the flag and update it */
+ if( drive->thw_inf.drv_status != myret.status ) {
+ drive->thw_inf.status_changed = TRUE ;
+ drive->thw_inf.drv_status = myret.status ;
+ }
+
+ /* If the is a one of these conditions, turn off tape full */
+ if( drive->thw_inf.drv_status & ( TPS_RESET | TPS_NO_TAPE | TPS_NEW_TAPE ) ) {
+ ClrPosBit( drive, TAPE_FULL ) ;
+ /* Clear out counters */
+ drive->cur_stats.underruns = 0 ;
+ drive->cur_stats.dataerrs = 0 ;
+ }
+ }
+
+ return ret_val ;
+}
+
+
+/**/
+/**
+
+ Name: WriteEndSet
+
+ Description: Writes a filemark to tape and the updates the filemark
+ count.
+
+ Returns: Nothing
+
+ Notes:
+
+ Declaration:
+
+**/
+
+INT16 WriteEndSet( DRIVE_PTR curDRV )
+{
+ INT16 drv_hdl = curDRV->drv_hdl ;
+ RET_BUF myret ;
+ INT16 ret_val = TFLE_NO_ERR ;
+
+ if( TpWriteEndSet( drv_hdl ) == SUCCESS ) {
+ while( TpReceive( drv_hdl, &myret ) == FAILURE ) {
+ /* for non-preemptive operating systems: */
+ ThreadSwitch( ) ;
+ }
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( curDRV->thw_inf.the, myret.the ) ;
+
+ switch ( myret.gen_error ) {
+ case GEN_NO_ERR:
+ curDRV->cur_pos.fmks++ ;
+ break ;
+
+ case GEN_ERR_ENDSET:
+ curDRV->thw_inf.drv_status = myret.status ;
+ curDRV->cur_pos.fmks++ ;
+ break ;
+
+ case GEN_ERR_EOM:
+ curDRV->thw_inf.drv_status = myret.status ;
+ curDRV->cur_pos.fmks++ ;
+ SetPosBit( curDRV, ( AT_EOM | TAPE_FULL ) ) ;
+ break ;
+
+ default:
+ curDRV->thw_inf.drv_status = myret.status ;
+ ret_val = TFLE_DRIVE_FAILURE ;
+ break ;
+ }
+ } else {
+ ret_val = TFLE_DRIVER_FAILURE ;
+ }
+
+ BE_Zprintf( 0, TEXT("WriteEndSet() returning %d\n"), ret_val ) ;
+
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Name: ResetDrivePosition
+
+ Description: Resets the specified drive information to a virgin
+ ( I heard that ) state.
+
+ Returns:
+
+ Notes:
+
+ Declaration:
+
+**/
+
+VOID ResetDrivePosition( DRIVE_PTR drive )
+{
+ drive->vcb_valid = FALSE ;
+ ClrPosBit( drive, ( AT_EOD | AT_EOM | AT_EOS | AT_MOS ) ) ;
+ drive->cur_pos.fmks = 0 ;
+ drive->cur_stats.underruns = 0 ;
+ drive->cur_stats.dataerrs = 0 ;
+
+ /* reset 1-shot drive status bits */
+ drive->thw_inf.drv_status &= ~( TPS_NEW_TAPE | TPS_RESET ) ;
+}
+
+
+/**/
+/**
+
+ Name: GotoBlock
+
+ Description: Positions the tape to the physical block which is nearest
+ to the given logical block offset from the current SSET
+ (without going over) and sets the output parameter
+ 'offset' to the offset of the given LBA in the next
+ physical block.
+
+ Returns: TFLE_xxx error code.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+INT16 GotoBlock(
+ CHANNEL_PTR channel, /* I - God */
+ UINT32 lba, /* I - Desired Logical Block Address */
+ TPOS_PTR ui_tpos, /* I - For talking to the UI */
+ UINT16_PTR offset ) /* O - Offset of LBA in Physical Block */
+{
+ INT16 ret_val = TFLE_NO_ERR ;
+ DRIVE_PTR curDRV = channel->cur_drv ;
+ UINT32 real_blk ;
+ RET_BUF myret ;
+ UINT64 logical_bytes ;
+ UINT64 physical_bytes ;
+ UINT64 remainder ;
+ INT16 status ;
+
+ logical_bytes = U64_Mult( U64_Init( lba - curDRV->cur_pos.lba_vcb, 0L ),
+ U64_Init( (UINT32)channel->lb_size, 0L ) ) ;
+ physical_bytes = U64_Init( (UINT32)ChannelBlkSize( channel ), 0L ) ;
+ real_blk = curDRV->cur_pos.pba_vcb +
+ U64_Lsw( U64_Div( logical_bytes, physical_bytes,
+ &remainder, &status ) ) ;
+ msassert( status == U64_OK ) ;
+ *offset = (UINT16)U64_Lsw( remainder ) ;
+ BE_Zprintf( 0, TEXT("GotoBlock: VCB_PBA = %ld, VCB_LBA = %ld, LBA = %ld,\n"),
+ curDRV->cur_pos.pba_vcb,
+ curDRV->cur_pos.lba_vcb,
+ lba ) ;
+ BE_Zprintf( 0, TEXT(" PBA = %ld, offset = %d\n"), real_blk, *offset ) ;
+
+ if( ui_tpos != NULL ) {
+ ui_tpos->UI_TapePosRoutine( TF_SEARCHING, ui_tpos, curDRV->vcb_valid, &curDRV->cur_vcb, 0 ) ;
+ } else {
+ /* for non-preemptive operating systems: */
+ ThreadSwitch( ) ;
+ }
+ if( TpSeek( curDRV->drv_hdl, real_blk, FALSE ) == FAILURE ) {
+ return( TFLE_DRIVER_FAILURE ) ;
+ }
+ while( TpReceive( curDRV->drv_hdl, &myret ) == FAILURE ) {
+ if( ui_tpos != NULL ) {
+ /* Move ESA info directly to TPOS instead of going through
+ THW for optimal speed */
+ MOVE_ESA( ui_tpos->the, myret.the ) ;
+
+ if( (*ui_tpos->UI_TapePosRoutine)( TF_IDLE_NOBREAK, ui_tpos, curDRV->vcb_valid, &curDRV->cur_vcb, 0 )
+ == UI_ABORT_POSITIONING ) {
+ ret_val = TFLE_USER_ABORT ;
+ }
+ }
+ }
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( channel->cur_drv->thw_inf.the, myret.the ) ;
+
+ if ( myret.gen_error != GEN_NO_ERR ) {
+ curDRV->thw_inf.drv_status = myret.status ;
+ }
+
+ if( myret.gen_error && ( ret_val != TFLE_USER_ABORT ) ) {
+ ret_val = TFLE_DRIVE_FAILURE ;
+ }
+
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Name: GetCurrentPos
+
+ Description: Gets the current block position for the drive.
+
+ Returns: An error code
+
+ Notes: ABCDEFG
+
+ Declaration:
+
+**/
+
+INT16 GetCurrentPosition( DRIVE_PTR curDRV )
+{
+
+ RET_BUF myret ;
+ INT16 ret_val = TFLE_NO_ERR ;
+
+ if( TpGetPosition( curDRV->drv_hdl, FALSE ) == FAILURE ) {
+ return( TFLE_DRIVER_FAILURE ) ;
+ }
+ while( TpReceive( curDRV->drv_hdl, &myret ) == FAILURE ) {
+ /* for non-preemptive operating systems: */
+ ThreadSwitch( ) ;
+ }
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( curDRV->thw_inf.the, myret.the ) ;
+
+ if( myret.gen_error ) {
+ curDRV->thw_inf.drv_status = myret.status ;
+ ret_val = TFLE_DRIVE_FAILURE ;
+ } else {
+ BE_Zprintf(DEBUG_TAPE_FORMAT, RES_GET_CURRENT_POS_STAT, myret.misc ) ;
+ curDRV->cur_pos.pba_vcb = myret.misc ;
+ }
+
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Name: MountTape
+
+ Description: Mounts and readies a tape for IO.
+
+ Returns:
+
+ Notes: new_tape insures that mount will return with the NEW_TAPE
+ status bit set unless there is a NO_TAPE status returned
+ from the mount call itself.
+
+ Declaration:
+
+**/
+
+INT16 MountTape(
+ DRIVE_PTR cur_drv , /* The current Drive */
+ TPOS_PTR ui_tpos , /* The user interface tpos */
+ BOOLEAN_PTR tape_present ) /* Is there a tape present */
+{
+ INT16 ret_val = TFLE_NO_ERR ;
+ BOOLEAN first_call = TRUE ;
+ RET_BUF myret ;
+
+ /* Default to tape NOT present */
+ *tape_present = FALSE ;
+
+ /* Was this drive being polled, and if it was, is there a pending request */
+ if( cur_drv->poll_stuff.state != st_CLOSED ) {
+ if ( ui_tpos != NULL ) {
+ if( *ui_tpos->UI_TapePosRoutine ) {
+ ui_tpos->UI_TapePosRoutine( TF_REWINDING, ui_tpos, cur_drv->vcb_valid, &cur_drv->cur_vcb, 0 /* no specific mode */ ) ;
+ }
+ }
+ while( TpReceive( cur_drv->drv_hdl, &myret ) == FAILURE ) {
+ if( ui_tpos != NULL ) {
+ /* Move ESA info directly to TPOS instead of going through
+ THW for optimal speed */
+ MOVE_ESA( ui_tpos->the, myret.the ) ;
+
+ if( (*ui_tpos->UI_TapePosRoutine)( TF_IDLE_NOBREAK, ui_tpos, cur_drv->vcb_valid, &cur_drv->cur_vcb, 0 )
+ == UI_ABORT_POSITIONING ) {
+ ret_val = TFLE_USER_ABORT ;
+ break ;
+ }
+ } else {
+ /* for non-preemptive operating systems: */
+ ThreadSwitch( ) ;
+ }
+ }
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( cur_drv->thw_inf.the, myret.the ) ;
+ }
+
+
+ if( cur_drv->poll_stuff.state != st_CLOSED ) {
+
+ switch( myret.gen_error ) {
+
+ case GEN_ERR_NO_MEDIA :
+
+ cur_drv->tape_mounted = FALSE ;
+ if( cur_drv->poll_stuff.state != st_BSTAT ) {
+ cur_drv->force_rewind = TRUE ;
+ }
+ break ;
+
+ case GEN_ERR_UNRECOGNIZED_MEDIA :
+ case GEN_NO_ERR :
+ case GEN_ERR_NO_DATA :
+ case GEN_ERR_ENDSET :
+
+ switch( cur_drv->poll_stuff.state ) {
+
+ case st_BSTAT :
+
+ if( myret.gen_error == GEN_ERR_NO_DATA ||
+ myret.gen_error == GEN_ERR_ENDSET ) {
+
+ msassert( FALSE ) ;
+ ret_val = TFLE_DRIVE_FAILURE ;
+ break ;
+ }
+
+ cur_drv->thw_inf.drv_status = myret.status ;
+ if( myret.status & ( TPS_NEW_TAPE | TPS_RESET | TPS_NO_TAPE ) ) {
+ cur_drv->force_rewind = TRUE ;
+ }
+ break ;
+
+ case st_BMNT :
+
+ if( myret.gen_error == GEN_ERR_NO_DATA ||
+ myret.gen_error == GEN_ERR_ENDSET ) {
+
+ msassert( FALSE ) ;
+ ret_val = TFLE_DRIVE_FAILURE ;
+ break ;
+ }
+
+ cur_drv->thw_inf.drv_status = myret.status ;
+ if( myret.status & ( TPS_NEW_TAPE | TPS_RESET | TPS_NO_TAPE ) ) {
+ cur_drv->force_rewind = TRUE ;
+ }
+
+ /* Mount Succeeded check for status change */
+ if( ( ret_val = UpdateDriveStatus( cur_drv ) ) == TFLE_NO_ERR ) {
+ if( cur_drv->thw_inf.drv_status & ( TPS_NEW_TAPE | TPS_RESET | TPS_NO_TAPE ) ) {
+
+ /* New tape or no tape! Dismount and force mount */
+ cur_drv->tape_mounted = TRUE ;
+ ret_val = DisMountTape( cur_drv, NULL, FALSE ) ;
+ cur_drv->force_rewind = TRUE ;
+
+ } else {
+
+ /* Successful Mount! */
+ cur_drv->tape_mounted = TRUE ;
+ cur_drv->thw_inf.drv_status = myret.status ;
+ }
+ }
+ break ;
+
+ case st_BREW :
+ case st_BREAD :
+
+ if( cur_drv->poll_stuff.state == st_BREW &&
+ myret.gen_error == GEN_ERR_UNRECOGNIZED_MEDIA ) {
+
+ msassert( FALSE ) ;
+ ret_val = TFLE_DRIVE_FAILURE ;
+ break ;
+ }
+
+ /* check for status change */
+ if( ( ret_val = UpdateDriveStatus( cur_drv ) ) == TFLE_NO_ERR ) {
+ if( cur_drv->thw_inf.drv_status & ( TPS_NEW_TAPE | TPS_RESET | TPS_NO_TAPE ) ) {
+
+ /* New tape or no tape! Dismount and force mount */
+ cur_drv->tape_mounted = TRUE ;
+ ret_val = DisMountTape( cur_drv, NULL, FALSE ) ;
+ cur_drv->force_rewind = TRUE ;
+
+ } else {
+
+ /* Success! */
+ cur_drv->tape_mounted = TRUE ;
+ if( cur_drv->poll_stuff.state == st_BREAD &&
+ myret.gen_error != GEN_ERR_UNRECOGNIZED_MEDIA ) {
+
+ /* Set up the buffer */
+ BM_SetBytesFree( cur_drv->hold_buff, (UINT16)myret.len_got ) ;
+ BM_SetReadError( cur_drv->hold_buff, myret.gen_error ) ;
+ }
+ }
+ }
+ break ;
+
+ default :
+ msassert( FALSE ) ;
+ break ;
+ }
+ break ;
+
+ default :
+
+ ret_val = TFLE_DRIVE_FAILURE ;
+ break ;
+ }
+ }
+
+ cur_drv->poll_stuff.state = st_CLOSED ;
+
+ if( !cur_drv->tape_mounted && ret_val == TFLE_NO_ERR ) {
+
+ /* Mount the tape */
+ if( TpMount( cur_drv->drv_hdl ) != SUCCESS ) {
+ return( TFLE_DRIVER_FAILURE ) ;
+ }
+
+ while( TpReceive( cur_drv->drv_hdl, &myret ) == FAILURE ) {
+ if( ui_tpos != NULL && ui_tpos->UI_TapePosRoutine != NULL ) {
+ /* Move ESA info directly to TPOS instead of going through
+ THW for optimal speed */
+ MOVE_ESA( ui_tpos->the, myret.the ) ;
+
+ if( first_call ) {
+ ui_tpos->UI_TapePosRoutine( TF_MOUNTING, ui_tpos, cur_drv->vcb_valid, &cur_drv->cur_vcb, 0 /* no specific mode */ ) ;
+ first_call = FALSE ;
+ } else {
+ if( (*ui_tpos->UI_TapePosRoutine)( TF_IDLE_NOBREAK, ui_tpos, cur_drv->vcb_valid, &cur_drv->cur_vcb, 0 )
+ == UI_ABORT_POSITIONING ) {
+ ret_val = TFLE_USER_ABORT ;
+ break ;
+ }
+ }
+ } else {
+ /* for non-preemptive operating systems: */
+ ThreadSwitch( ) ;
+ }
+ }
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( cur_drv->thw_inf.the, myret.the ) ;
+
+ /* Set the status */
+ cur_drv->thw_inf.drv_status = myret.status ;
+
+ if( myret.gen_error ) {
+
+#ifdef OS_NLM
+ switch ( myret.gen_error ) {
+
+ case GEN_ERR_EMPTY_SRC:
+
+ /* loader could not find a tape at the requested location */
+
+ /* indicate requested source as empty */
+ ret_val = TFLE_EMPTY_SRC ;
+ break ;
+
+ case GEN_ERR_DEST_FULL :
+
+ /* loader could not place tape in desired location because */
+ /* location occupied by another tape */
+
+ /* indicate can't return tape to origin, tell user */
+ /* to manually remove tape */
+ ret_val = TFLE_DEST_FULL ;
+ break;
+
+ case GEN_ERR_ARM_FULL:
+
+ /* loader could not perform requested operation because */
+ /* loader arm is occupied with another tape */
+
+ /* there is already a tape in the loader arm */
+ ret_val = TFLE_ARM_FULL ;
+ break;
+
+ case GEN_ERR_DRIVE_FULL:
+
+ /* loader could not place requested tape in drive because */
+ /* there is something blocking the way (probably a tape in */
+ /* the open drive bay. */
+
+ /* there is already a tape in the drive */
+ ret_val = TFLE_DRIVE_FULL ;
+ break;
+
+ case GEN_ERR_NO_MEDIA:
+
+ /* no tape in slot */
+ ResetDrivePosition( cur_drv ) ;
+ /* Just to make sure... */
+ cur_drv->thw_inf.drv_status |= TPS_NO_TAPE ;
+ break ;
+
+ case GEN_ERR_UNRECOGNIZED_MEDIA:
+
+ *tape_present = TRUE ;
+ cur_drv->tape_mounted = TRUE ;
+ ret_val = TF_UNRECOGNIZED_MEDIA ;
+ break;
+
+ case GEN_ERR_DRIVE_CLOSED :
+
+ /* drive door is closed with no tape in the drive */
+
+ /* indicate drive door is closed and must be manually opened */
+ ret_val = TFLE_DRIVE_CLOSED ;
+ break;
+
+ case GEN_ERR_DOOR_AJAR :
+
+ /* the door has been opened during an operation */
+
+ ret_val = TFLE_DOOR_AJAR ;
+ break;
+
+ case GEN_ERR_NO_CARTRIDGE:
+
+ /* there is no cartridge in the loader to get tape from */
+
+ ret_val = TFLE_NO_CARTRIDGE ;
+ break;
+
+ case GEN_ERR_LOAD_UNLOAD:
+
+ /* loader arm movement interrupted (by loader door being opened) */
+
+ ret_val = TFLE_LOAD_UNLOAD ;
+ break;
+
+ case GEN_ERR_UNEXPECTED_TAPE:
+
+ /* The internal driver data indicates no tape in drive. Driver */
+ /* didn't expect a tape in the drive, yet one was found. Cannot */
+ /* proceed because we do not know where the tape belongs. */
+ /* */
+
+ ret_val = TFLE_UNEXPECTED_TAPE ;
+ break ;
+
+ case GEN_ERR_SW_REJECT_CMD:
+
+ /* the command never made it to the drive, we aborted it before hand */
+
+ /* what do we want to do with this ??? Right */
+ /* now it's a drive failure - falling through */
+
+ default :
+ ret_val = TFLE_DRIVE_FAILURE ;
+ break;
+
+ } /* switch */
+#else
+
+ /*
+ NOTE:A change within this 'conditional' needs to
+ be made for the NLM above!
+ */
+
+ if( myret.gen_error == GEN_ERR_NO_MEDIA ) {
+ ResetDrivePosition( cur_drv ) ;
+
+ /* Just to make sure... */
+ cur_drv->thw_inf.drv_status |= TPS_NO_TAPE ;
+
+ } else if( myret.gen_error == GEN_ERR_UNRECOGNIZED_MEDIA ) {
+ *tape_present = TRUE ;
+ cur_drv->tape_mounted = TRUE ;
+ ret_val = TF_UNRECOGNIZED_MEDIA ;
+
+ } else {
+ ret_val = TFLE_DRIVE_FAILURE ;
+ }
+#endif
+ } else if( myret.status & TPS_NO_TAPE ) {
+
+ /* Can this really happen??? */
+ ResetDrivePosition( cur_drv ) ;
+
+ } else {
+ *tape_present = TRUE ;
+ cur_drv->tape_mounted = TRUE ;
+
+ /* If we have a valid VCB but the drive says we are at BOT, */
+ /* it means the drive did a rewind behind our backs (QIC */
+ /* has to do this occasionally to keep itself sane). So we */
+ /* set the force_rewind flag. This will tell the caller to */
+ /* follow the normal rewind procedure, and eliminate */
+ /* any confusion as to where we are positioned on tape. */
+
+ if( cur_drv->thw_inf.drv_status & TPS_BOT ) {
+ cur_drv->force_rewind = TRUE ;
+ }
+ }
+
+ } else if( ret_val == TFLE_NO_ERR ) {
+ *tape_present = TRUE ;
+ if( myret.gen_error == GEN_ERR_UNRECOGNIZED_MEDIA ) {
+ /* We ignored this error up to this point because we want
+ the mount to complete in case they're trying to format
+ the tape. Now we have to tell them about it.
+ */
+ ret_val = TF_UNRECOGNIZED_MEDIA ;
+ }
+ }
+
+ /* If the tape has mounted reset the drive features */
+ if( cur_drv->tape_mounted && myret.gen_error == GEN_NO_ERR ) {
+ if( TpSpecial( cur_drv->drv_hdl, (INT16)SS_GET_DRV_INF, ( UINT32 )&cur_drv->thw_inf.drv_info ) == FAILURE ) {
+ ret_val = TFLE_DRIVE_FAILURE ;
+ }
+
+ /* Check to see if they have requested fast file to be active,
+ if not, unconditionally set any fast file bits off ( including the MaynStream 2200+ ) */
+ if( !lw_tfl_control.use_fast_file ) {
+ cur_drv->thw_inf.drv_info.drv_features &= ~TDI_FAST_NBLK ;
+ cur_drv->thw_inf.drv_info.drv_features &= ~TDI_FIND_BLK ;
+ }
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Name: DisMountTape
+
+ Description: Releases a tape.
+
+ Returns:
+
+ Notes:
+
+ Declaration:
+
+**/
+
+INT16 DisMountTape(
+ DRIVE_PTR cur_drv ,
+ TPOS_PTR ui_tpos ,
+ BOOLEAN rewind_tape )
+{
+ INT16 ret_val = TFLE_NO_ERR ;
+ RET_BUF myret ;
+
+ if( cur_drv->tape_mounted ) {
+
+ /* if a rewind was requested, do it */
+ if( rewind_tape ) {
+ if( ( ret_val = RewindDrive( cur_drv, ui_tpos, TRUE, TRUE, 0 ) ) != TFLE_NO_ERR ) {
+ return( ret_val ) ;
+ }
+ }
+
+ if( TpDismount( cur_drv->drv_hdl ) == FAILURE ) {
+ return( TFLE_DRIVER_FAILURE ) ;
+ }
+
+ while( TpReceive( cur_drv->drv_hdl, &myret ) == FAILURE ) {
+ /* for non-preemptive operating systems: */
+ ThreadSwitch( ) ;
+ }
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( cur_drv->thw_inf.the, myret.the ) ;
+
+ if( myret.gen_error != GEN_NO_ERR && myret.gen_error != GEN_ERR_NO_MEDIA ) {
+ cur_drv->thw_inf.drv_status = myret.status ;
+ ret_val = TFLE_DRIVE_FAILURE ;
+ }
+
+ cur_drv->tape_mounted = FALSE ;
+
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Name: RewindDriveImmediate
+
+ Description: Rewinds the current drive in the channel and resets all the
+ appropriate fields.
+
+ Returns: An Error code if there is a problem.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+VOID RewindDriveImmediate( DRIVE_PTR curDRV )
+{
+ UINT16 retry = 1 ;
+ RET_BUF myret ;
+
+ myret.gen_error = GEN_NO_ERR ;
+
+ /* This logic is to handle the case that we have read exactly to the filemark
+ on tape, and since the last read did not fail, the filemark will be reported
+ on this rewind call. So if we get a filemark error on rewind ( I mean how
+ stupid are these drives ), kill the error queue, and recall TpRewind */
+ do {
+ TpRewind( curDRV->drv_hdl, TRUE ) ;
+ while( TpReceive( curDRV->drv_hdl, &myret ) == FAILURE ) {
+ /* for non-preemptive operating systems: */
+ ThreadSwitch( ) ;
+ }
+ } while( myret.gen_error != GEN_NO_ERR && retry-- ) ;
+
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( curDRV->thw_inf.the, myret.the ) ;
+
+ if ( myret.gen_error != GEN_NO_ERR ) {
+ curDRV->thw_inf.drv_status = myret.status ;
+ }
+
+ /* Clean up the mess. */
+
+ ResetDrivePosition( curDRV ) ;
+ if( curDRV->hold_buff != NULL ) {
+ BM_UnReserve( curDRV->hold_buff ) ;
+ BM_Put( curDRV->hold_buff ) ;
+ curDRV->hold_buff = NULL ;
+ }
+ if ( curDRV->last_fmt_env != NULL ) {
+ FreeFormatEnv( & curDRV->last_cur_fmt, & curDRV->last_fmt_env ) ;
+ }
+
+ SetPosBit( curDRV, AT_BOT ) ;
+}
+
diff --git a/private/utils/ntbackup/src/ems_tab.c b/private/utils/ntbackup/src/ems_tab.c
new file mode 100644
index 000000000..2ba679efd
--- /dev/null
+++ b/private/utils/ntbackup/src/ems_tab.c
@@ -0,0 +1,138 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: ems_tab.c
+
+ Description: This file contains the DOS functon table.
+
+
+ $Log: M:/LOGFILES/EMS_TAB.C_V $
+
+**/
+/* begin include list */
+#include <windows.h>
+#include "stdtypes.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "emsdblk.h"
+#include "ems_fs.h"
+#include "gen_fs.h"
+/* $end$ include list */
+
+FUNC_LIST EMSFuncTab = {
+
+ NULL,
+ EMS_FindDrives,
+ GEN_RemoveDLE,
+ NULL,
+
+ EMS_DeviceDispName,
+ EMS_GetVolName,
+ EMS_SizeofVolName,
+ GEN_MakePath,
+ EMS_InitMakeData,
+
+ GEN_IsBlkComplete,
+ GEN_CompleteBlk,
+ EMS_DupBlk,
+ GEN_ReleaseBlk,
+
+ EMS_AttachToDLE,
+ EMS_DetachDLE,
+ EMS_EndOperationOnDLE,
+
+ EMS_ProcessDDB,
+ EMS_GetCurrentDDB,
+ EMS_GetCurrentPath,
+ NULL,
+ NULL,
+ NULL,
+ EMS_ChangeDir,
+ EMS_UpDir,
+
+#ifdef TDEMO
+ NULL,
+ EMS_OpenObj,
+ EMS_SeekObj,
+ EMS_ReadObj,
+ NULL,
+ NULL,
+ EMS_CloseObj,
+ NULL,
+ EMS_GetObjInfo,
+ NULL,
+ EMS_VerObjInfo,
+#else
+ EMS_CreateObj,
+ EMS_OpenObj,
+ EMS_SeekObj,
+ EMS_ReadObj,
+ EMS_WriteObj,
+ EMS_VerObj,
+ EMS_CloseObj,
+ NULL,// EMS_DeleteObj,
+ EMS_GetObjInfo,
+ EMS_SetObjInfo,
+ EMS_VerObjInfo,
+#endif
+
+ EMS_FindFirst,
+ EMS_FindNext,
+ NULL, //EMS_PushMinDDB,
+ NULL, //EMS_PopMinDDB,
+
+#if defined ( OEM_MSOFT )
+ NULL,
+ EMS_EnumSpecFiles,
+#else
+ DUMMY_GetSpecDBLKS,
+ DUMMY_EnumSpecFiles,
+#endif
+
+ EMS_ModFnameFDB,
+ EMS_ModPathDDB,
+ EMS_GetOSFnameFDB,
+ GEN_GetPartName,
+ EMS_GetOSPathDDB,
+ EMS_GetCdateDBLK,
+ EMS_GetMdateDBLK,
+ EMS_ModBdateDBLK,
+ EMS_ModAdateDBLK,
+ EMS_GetDisplaySizeDBLK,
+ EMS_ModAttribDBLK,
+ NULL,
+ EMS_SetOwnerId,
+
+ EMS_GetObjTypeDBLK,
+
+ EMS_SizeofFname,
+ EMS_SizeofPath,
+ NULL,
+ GEN_SizeofPartName, /* IMAGE size of part name */
+ EMS_SizeofOSPath,
+
+ EMS_SizeofOSInfo,
+
+ EMS_GetOS_InfoDBLK,
+ EMS_GetActualSizeDBLK,
+
+ DUMMY_InitGOS,
+
+ NULL, // EMS_CreateFDB,
+ GEN_CreateIDB,
+ EMS_CreateDDB,
+ EMS_ChangeIntoDDB,
+
+#if defined ( OEM_MSOFT )
+ EMS_SpecExcludeObj,
+#else
+ GEN_SpecExcludeObj,
+#endif
+ GEN_SetDataSize,
+ NULL, /* SetObjTypeDBLK, */
+ DUMMY_LogoutDevice,
+ EMS_FindClose,
+ NULL, /* SizeofDevName */
+ NULL /* GeneratedErrorLog */
+} ;
diff --git a/private/utils/ntbackup/src/enc_tab.c b/private/utils/ntbackup/src/enc_tab.c
new file mode 100644
index 000000000..571deab51
--- /dev/null
+++ b/private/utils/ntbackup/src/enc_tab.c
@@ -0,0 +1,77 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: enc_tab.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This module contains the encryption and decryption tables
+ for Encryption Standard 3 in ENCRYPT.C.
+
+
+
+ $Log: G:/LOGFILES/ENC_TAB.C_V $
+
+ Rev 1.0 09 May 1991 13:33:42 HUNTER
+Initial revision.
+
+**/
+
+#include "stdtypes.h"
+
+UINT8 enc_table[256] = { 53, 25, 81, 57, 6, 119, 173, 115, 215, 101,
+ 203, 9, 7, 254, 220, 167, 184, 187, 8, 163,
+ 24, 23, 67, 128, 192, 249, 175, 131, 213, 149,
+ 18, 240, 197, 37, 73, 158, 56, 246, 124, 17,
+ 61, 4, 174, 127, 253, 2, 147, 170, 183, 32,
+ 21, 84, 111, 150, 164, 42, 214, 94, 207, 91,
+ 235, 224, 222, 76, 153, 152, 89, 181, 43, 244,
+ 243, 27, 118, 68, 72, 31, 204, 219, 26, 247,
+ 144, 141, 156, 154, 47, 105, 143, 216, 179, 62,
+ 120, 59, 28, 13, 69, 65, 92, 231, 188, 245,
+ 234, 110, 121, 228, 36, 29, 135, 51, 3, 200,
+ 109, 178, 75, 40, 5, 50, 199, 195, 209, 46,
+ 165, 160, 177, 106, 182, 238, 19, 54, 86, 217,
+ 210, 103, 70, 138, 48, 191, 237, 133, 193, 16,
+ 196, 226, 229, 201, 55, 242, 88, 117, 148, 137,
+ 205, 80, 239, 49, 20, 140, 162, 185, 146, 10,
+ 223, 132, 227, 208, 85, 22, 166, 45, 99, 172,
+ 34, 77, 14, 232, 202, 176, 1, 251, 83, 96,
+ 33, 95, 71, 125, 104, 151, 35, 255, 66, 134,
+ 233, 225, 218, 39, 58, 186, 74, 161, 168, 100,
+ 190, 142, 157, 139, 212, 90, 79, 64, 248, 123,
+ 52, 145, 206, 87, 98, 221, 108, 122, 189, 60,
+ 15, 230, 211, 97, 116, 180, 136, 129, 44, 0,
+ 78, 38, 250, 102, 126, 241, 159, 107, 30, 93,
+ 236, 82, 155, 252, 194, 130, 41, 169, 11, 63,
+ 198, 113, 112, 171, 12, 114
+} ;
+/* decryption table */
+UINT8 dec_table[256] = { 229, 176, 45, 108, 41, 114, 4, 12, 18, 11,
+ 159, 248, 254, 93, 172, 220, 139, 39, 30, 126,
+ 154, 50, 165, 21, 20, 1, 78, 71, 92, 105,
+ 238, 75, 49, 180, 170, 186, 104, 33, 231, 193,
+ 113, 246, 55, 68, 228, 167, 119, 84, 134, 153,
+ 115, 107, 210, 0, 127, 144, 36, 3, 194, 91,
+ 219, 40, 89, 249, 207, 95, 188, 22, 73, 94,
+ 132, 182, 74, 34, 196, 112, 63, 171, 230, 206,
+ 151, 2, 241, 178, 51, 164, 128, 213, 146, 66,
+ 205, 59, 96, 239, 57, 181, 179, 223, 214, 168,
+ 199, 9, 233, 131, 184, 85, 123, 237, 216, 110,
+ 101, 52, 252, 251, 255, 7, 224, 147, 72, 5,
+ 90, 102, 217, 209, 38, 183, 234, 43, 23, 227,
+ 245, 27, 161, 137, 189, 106, 226, 149, 133, 203,
+ 155, 81, 201, 86, 80, 211, 158, 46, 148, 29,
+ 53, 185, 65, 64, 83, 242, 82, 202, 35, 236,
+ 121, 197, 156, 19, 54, 120, 166, 15, 198, 247,
+ 47, 253, 169, 6, 42, 26, 175, 122, 111, 88,
+ 225, 67, 124, 48, 16, 157, 195, 17, 98, 218,
+ 200, 135, 24, 138, 244, 117, 140, 32, 250, 116,
+ 109, 143, 174, 10, 76, 150, 212, 58, 163, 118,
+ 130, 222, 204, 28, 56, 8, 87, 129, 192, 77,
+ 14, 215, 62, 160, 61, 191, 141, 162, 103, 142,
+ 221, 97, 173, 190, 100, 60, 240, 136, 125, 152,
+ 31, 235, 145, 70, 69, 99, 37, 79, 208, 25,
+ 232, 177, 243, 44, 13, 187
+} ;
diff --git a/private/utils/ntbackup/src/encrypt.c b/private/utils/ntbackup/src/encrypt.c
new file mode 100644
index 000000000..b265a81e1
--- /dev/null
+++ b/private/utils/ntbackup/src/encrypt.c
@@ -0,0 +1,481 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: encrypt.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: The Encryption Unit Interface has the following functionality:
+ EU_Open, EU_ResetHand, EU_Close and EU_Encrypt. This interface
+ allows the user to encrypt and decrypt blocks of data.
+
+
+
+ $Log: M:/LOGFILES/ENCRYPT.C_V $
+
+ Rev 1.5 20 May 1993 17:27:06 BARRY
+Unicode fixes
+
+ Rev 1.4 30 Jan 1993 11:21:00 DON
+Removed compiler warnings
+
+ Rev 1.3 08 Oct 1992 12:47:06 DAVEV
+fixes for handling Unicode passwords
+
+ Rev 1.2 18 Aug 1992 09:58:26 BURT
+fix warnings
+
+ Rev 1.1 14 May 1991 12:12:58 JOHNW
+Added support for a "Do nothing" encryption algorithm.
+
+ Rev 1.0 09 May 1991 13:37:06 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+
+#ifndef CODERUNNER
+#include <io.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <string.h>
+#else
+#pragma check_stack-
+#include "cr.h"
+#include "farlib.h"
+#endif
+
+#include "stdtypes.h"
+#include "msassert.h"
+
+#include "enc_priv.h"
+#include "enc_pub.h"
+#include "tble_prv.h"
+/* $end$ include list */
+
+VOID EncryptData3( EU_HAND_PTR enc_hand, INT8_PTR data, INT16 dsize ) ;
+VOID DecryptData3( EU_HAND_PTR enc_hand, INT8_PTR data, INT16 dsize ) ;
+VOID EncryptData1( INT8_PTR data, INT16 dsize ) ;
+VOID DecryptData1( INT8_PTR data, INT16 dsize ) ;
+
+/**/
+/**
+
+ Name: EU_Open
+
+ Description: EU_Open allocates memory for an encryption unit handle.
+
+
+ Modified: 9/25/1989
+
+ Returns: The encryption unit handle is returned.
+
+ Notes: Error points to the error code.
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+EU_HAND_PTR EU_Open(
+ INT16 algor , /* Type of algorithm */
+ INT16 mode , /* Encrypt or Decrypt */
+ INT8_PTR key , /* Pointer to the key */
+ INT16 ksize , /* Size of the key in BYTES */
+ INT16_PTR block_size , /* Block size */
+ INT16_PTR error ) /* Pointer to an error code */
+{
+ EU_HAND_PTR euh ;
+
+ *error = EU_NO_ERROR ;
+
+ /* Verify parameter data */
+ msassert( key != NULL ) ;
+ msassert( ksize != 0 ) ;
+ msassert( ( ( mode == ENCRYPT ) || ( mode == DECRYPT ) ) ) ;
+
+ /* Allocate Memory */
+ if( ( euh = ( EU_HAND_PTR ) malloc( sizeof( EU_HAND ) ) ) != NULL ) {
+
+ /* fill in common part of the EU_HAND */
+ euh->algor= algor;
+ euh->mode = mode ;
+
+ switch( algor ) {
+
+ case ENC_ALGOR_3 : /* Maynard Encryption Standard (MES) */
+
+ /* Allocate space for the Encryption Key */
+ if( ( euh->algors.exor.key
+ = ( INT8 PTR_SIZE * ) malloc( ksize ) ) == NULL ) {
+ *error = EU_MEMORY_ERROR ;
+ free( euh ) ;
+ return NULL ;
+ }
+
+ /* Assign data to handle */
+ memcpy( euh->algors.exor.key, key, ksize );
+ euh->algors.exor.ksize = ksize ;
+ euh->algors.exor.feedback = 0 ;
+ euh->algors.exor.block_size = 1;
+ euh->algors.exor.bytes_processed = 0L ;
+ *block_size = 1;
+ break ;
+
+ case ENC_ALGOR_1 : /* Maynard Encryption Algorithm 2.0 */
+
+ /* Assign data to handle */
+ *block_size = 1;
+ break ;
+
+ case ENC_ALGOR_0 : /* Do nothing Algorithm */
+ break ;
+
+ default : /* Unknown Algorithm */
+ *error = EU_ALGORITHM_UNKNOWN ;
+ free( euh ) ;
+ return NULL ;
+ break ;
+
+ } /* End of Switch */
+ } else {
+ *error = EU_MEMORY_ERROR ;
+ }
+ return euh ;
+
+}
+
+/**/
+/**
+
+ Name: EU_Encrypt
+
+ Description: Encrypts or Decrypts a given block of data.
+
+ Modified: 9/25/1989
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 EU_Encrypt(
+ EU_HAND_PTR enc_hand , /* encryption unit handle from EU_Open */
+ INT8_PTR data , /* pointer to data to be en/decrypted */
+ INT16 dsize ) /* size of the data in BYTES */
+{
+ INT16 status = EU_NO_ERROR ;
+
+ /* Verify parameter data */
+ msassert( enc_hand != NULL ) ;
+ msassert( data != NULL ) ;
+
+ if( enc_hand->mode == ENCRYPT ) {
+ /* encryption requested */
+ switch( enc_hand->algor ) {
+ case ENC_ALGOR_3 : /* Call MES encryption routine */
+ msassert( ( dsize % enc_hand->algors.exor.block_size ) == 0 ) ;
+ EncryptData3( enc_hand, data, dsize ) ;
+ break ;
+
+ case ENC_ALGOR_1 : /* Call password encryption routine */
+ EncryptData1( data, dsize ) ;
+ break ;
+
+ case ENC_ALGOR_0 : /* Do nothing Algorithm */
+ break ;
+
+ default :
+ msassert( FALSE ) ;
+ break ;
+ }
+ } else {
+ /* decryption requested */
+ switch( enc_hand->algor ) {
+ case ENC_ALGOR_3 : /* Call MES decryption routine */
+ msassert( ( dsize % enc_hand->algors.exor.block_size ) == 0 ) ;
+ DecryptData3( enc_hand, data, dsize ) ;
+ break ;
+
+ case ENC_ALGOR_1 : /* Call password decryption routine */
+ DecryptData1( data, dsize ) ;
+ break ;
+
+ case ENC_ALGOR_0 : /* Do nothing Algorithm */
+ break ;
+
+ default :
+ msassert( FALSE ) ;
+ break ;
+ }
+ }
+
+ return status ;
+}
+
+/**/
+/**
+
+ Name: EncryptData3
+
+ Description: Encrypts a given block of data using MES.
+
+ Modified: 9/25/1989
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID EncryptData3(
+ EU_HAND_PTR enc_hand , /* encryption unit handle from EU_Open */
+ INT8_PTR data , /* data to be encrypted */
+ INT16 dsize ) /* size of data in BYTES */
+{
+
+ INT16 keypos ;
+ UINT8 enc_val ;
+
+ while( dsize-- ) {
+ keypos = (INT16) enc_hand->algors.exor.bytes_processed++
+ % enc_hand->algors.exor.ksize ;
+ enc_val = enc_hand->algors.exor.key[keypos] ^ *data
+ ^ enc_hand->algors.exor.feedback ;
+ enc_hand->algors.exor.feedback = *data++ = enc_table[enc_val] ;
+ }
+
+ return ;
+}
+/**/
+/**
+
+ Name: DecryptData3
+
+ Description: Decrypts a given block of data using MES
+
+ Modified: 9/25/1989
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+
+VOID DecryptData3(
+ EU_HAND_PTR enc_hand , /* encryption unit handle from EU_Open */
+ INT8_PTR data , /* data to be decrypted */
+ INT16 dsize ) /* size of data in BYTES */
+{
+
+ INT16 keypos ;
+ UINT8 temp ;
+
+ while( dsize-- ) {
+ keypos = (INT16) enc_hand->algors.exor.bytes_processed++
+ % enc_hand->algors.exor.ksize ;
+ temp = dec_table[(UINT8)*data] ^ enc_hand->algors.exor.feedback
+ ^ enc_hand->algors.exor.key[keypos] ;
+ enc_hand->algors.exor.feedback = (UINT8) *data ;
+ *data++ = temp ;
+ }
+ return ;
+}
+
+/**/
+/**
+
+ Name: EncryptData1
+
+ Description: EncryptData1 encyrpts the given data using the
+ password encryption algorithm from version 2.0.
+
+ Modified: 9/26/1989
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+
+VOID EncryptData1(
+ INT8_PTR data, /* data to be encrypted */
+ INT16 dsize ) /* size of data in BYTES */
+{
+ // old non-unicode compatible version
+ //INT16 i ;
+ //
+ //(VOID) strrev( data ) ;
+ //for( i=0; i < (INT16)strlen( data ); i++) {
+ // data[i] = data[i] - (CHAR)'+';
+ //}
+
+ // new unicode compatible version
+ // perform strrev and encryption in a single pass.
+
+ INT8_PTR right = data + dsize - 1;
+ INT8 temp;
+
+ while ( data < right )
+ {
+ temp = *data;
+ *data++ = *right + (INT8)'+';
+ *right-- = temp + (INT8)'+';
+ }
+ if ( right == data )
+ {
+ *data += (INT8)'+';
+ }
+
+ return ;
+}
+
+/**/
+/**
+
+ Name: DecryptData1
+
+ Description: DecryptData1 decrypts the given data using the
+ password encryption algorithm from version 2.0
+
+ Modified: 9/26/1989
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+
+VOID DecryptData1(
+ INT8_PTR data, /* data to be decrypted */
+ INT16 dsize ) /* size of data in BYTES */
+{
+ // old non-unicode compatible version
+ //INT16 i ;
+
+ //for( i=0; i < (INT16)strlen( data ); i++) {
+ // data[i] = data[i] + (CHAR)'+';
+ //}
+ //(VOID) strrev( data ) ;
+
+ // new unicode compatible version
+ // perform strrev and decryption in a single pass.
+
+ INT8_PTR right = data + dsize - 1;
+ INT8 temp;
+
+ while ( data < right )
+ {
+ temp = *data;
+ *data++ = *right - (INT8)'+';
+ *right-- = temp - (INT8)'+';
+ }
+ if ( right == data )
+ {
+ *data -= (INT8)'+';
+ }
+ return ;
+}
+
+/**/
+/**
+
+ Name: EU_ResetHand
+
+ Description: Resets the feedback so that the next encryption stands alone.
+
+ Modified: 9/25/1989
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+
+INT16 EU_ResetHand(
+ EU_HAND_PTR enc_hand )
+{
+ INT16 error = EU_NO_ERROR ;
+
+ msassert( enc_hand != NULL ) ;
+
+ switch( enc_hand->algor ) {
+ case ENC_ALGOR_3 : /* reset bytes processed and feedback */
+ enc_hand->algors.exor.feedback = 0 ;
+ enc_hand->algors.exor.bytes_processed = 0 ;
+ break ;
+ default :
+ break ;
+ }
+
+ return error ;
+}
+
+/**/
+/**
+
+ Name: EU_Close
+
+ Description: Frees the memory associated with the encryption unit handle.
+
+ Modified: 9/25/1989
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID EU_Close(
+ EU_HAND_PTR enc_hand )
+{
+ msassert( enc_hand != NULL ) ;
+
+ switch( enc_hand->algor ) {
+ case ENC_ALGOR_3 : /* free memory used for key and handle */
+ free( enc_hand->algors.exor.key ) ;
+ break ;
+ default :
+ break ;
+ }
+
+ /* Free Encryption structure */
+ free( enc_hand ) ;
+
+ return ;
+}
diff --git a/private/utils/ntbackup/src/entrpris.ico b/private/utils/ntbackup/src/entrpris.ico
new file mode 100644
index 000000000..1142368ad
--- /dev/null
+++ b/private/utils/ntbackup/src/entrpris.ico
Binary files differ
diff --git a/private/utils/ntbackup/src/eprintf.c b/private/utils/ntbackup/src/eprintf.c
new file mode 100644
index 000000000..a2729b4a5
--- /dev/null
+++ b/private/utils/ntbackup/src/eprintf.c
@@ -0,0 +1,174 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: eprintf.c
+
+ Description:
+
+ $Log: G:/UI/LOGFILES/EPRINTF.C_V $
+
+ Rev 1.15 10 Dec 1993 14:37:06 BARRY
+Use malloc for message instead of automatic variable
+
+ Rev 1.14 14 Jun 1993 20:36:42 MIKEP
+enable c++
+
+ Rev 1.13 02 Jun 1993 09:26:34 MIKEP
+Fix buffer being over written by clock when error occurs.
+
+ Rev 1.12 01 Nov 1992 15:57:52 DAVEV
+Unicode changes
+
+ Rev 1.11 07 Oct 1992 14:50:10 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.10 04 Oct 1992 19:37:22 DAVEV
+Unicode Awk pass
+
+ Rev 1.9 17 Aug 1992 13:17:24 DAVEV
+MikeP's changes at Microsoft
+
+ Rev 1.8 28 Jul 1992 14:41:18 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.7 27 Jul 1992 14:48:36 JOHNWT
+ChuckB fixed references for NT.
+
+ Rev 1.6 19 May 1992 13:01:22 MIKEP
+mips changes
+
+ Rev 1.5 14 May 1992 16:51:12 MIKEP
+nt pass 2
+
+ Rev 1.4 18 Feb 1992 11:00:14 ROBG
+Added logic to concatenate a CR/LF to any error message for
+the log file.
+
+ Rev 1.3 21 Jan 1992 16:51:28 JOHNWT
+added noyycheck flag
+
+ Rev 1.2 16 Jan 1992 11:23:10 DAVEV
+16/32 bit port-2nd pass
+
+ Rev 1.1 25 Nov 1991 15:31:54 JOHNWT
+removed eprintf, converted to WM_MessageBox
+
+ Rev 1.0 20 Nov 1991 19:18:28 SYSTEM
+Initial revision.
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+/*****************************************************************************
+
+ Name: eresrintf
+
+ Description: This function displays an error message from SES_ENG_ERR
+
+ THIS IS A SPECIAL FUNCTION SPECIFICALLY
+ FOR THE "T" COMMANDS...NO WINDOWS ARE USED
+
+ Returns: VOID
+
+*****************************************************************************/
+VOID eresprintf( INT res_id, ... )
+{
+ UINT16 error ;
+ CHAR_PTR fmt ;
+ UINT16 tmp ;
+ va_list arg_ptr ;
+
+ fmt = (CHAR_PTR)RM_GetResource( rm, (UINT) SES_ENG_ERR, res_id, &tmp, &error ) ;
+
+ if ( fmt )
+ {
+ CHAR_PTR messageBuffer;
+
+ msassert( fmt != NULL ) ;
+ msassert( error == RM_NO_ERROR ) ;
+
+ va_start( arg_ptr, res_id ) ;
+
+ tprintf( fmt, arg_ptr ) ;
+
+ messageBuffer = malloc( strsize( gszTprintfBuffer ) );
+
+ if ( messageBuffer != NULL )
+ {
+ strcpy( messageBuffer, gszTprintfBuffer );
+ }
+
+ lvprintf( LOGGING_FILE, fmt, arg_ptr ) ;
+
+ va_end( arg_ptr ) ;
+
+ // Concatenate CR/LF after string.
+
+ lprintf ( LOGGING_FILE, TEXT("\n") ) ;
+
+ WM_MessageBox( ID( IDS_MSGTITLE_ERROR ),
+ messageBuffer == NULL ? TEXT("") : messageBuffer,
+ WMMB_OK | WMMB_NOYYCHECK,
+ WMMB_ICONEXCLAMATION,
+ NULL, 0, 0 );
+
+ free( messageBuffer );
+ }
+ return ;
+}
+
+BOOLEAN eresprintf_cancel( INT res_id, ... )
+{
+ UINT16 error ;
+ CHAR_PTR fmt ;
+ UINT16 tmp ;
+ va_list arg_ptr ;
+ BOOLEAN ret_val = FALSE ;
+
+ fmt = (CHAR_PTR)RM_GetResource( rm, (UINT) SES_ENG_ERR, res_id, &tmp, &error ) ;
+
+ if ( fmt )
+ {
+ CHAR_PTR messageBuffer;
+
+ msassert( fmt != NULL ) ;
+ msassert( error == RM_NO_ERROR ) ;
+
+ va_start( arg_ptr, res_id ) ;
+
+ tprintf( fmt, arg_ptr ) ;
+
+ messageBuffer = malloc( strsize( gszTprintfBuffer ) );
+
+ if ( messageBuffer != NULL )
+ {
+ strcpy( messageBuffer, gszTprintfBuffer );
+ }
+
+ lvprintf( LOGGING_FILE, fmt, arg_ptr ) ;
+
+ va_end( arg_ptr ) ;
+
+ // Concatenate CR/LF after string.
+
+ lprintf ( LOGGING_FILE, TEXT("\n") ) ;
+
+ if ( WM_MessageBox( ID( IDS_MSGTITLE_ERROR ),
+ messageBuffer == NULL ? TEXT("") : messageBuffer,
+ WMMB_OKCANCEL | WMMB_NOYYCHECK,
+ WMMB_ICONEXCLAMATION,
+ NULL, 0, 0 ) != WMMB_IDOK ) {
+
+ ret_val = TRUE ;
+ }
+
+ free( messageBuffer );
+ }
+ return ret_val ;
+}
+
diff --git a/private/utils/ntbackup/src/erase.c b/private/utils/ntbackup/src/erase.c
new file mode 100644
index 000000000..aeb016f26
--- /dev/null
+++ b/private/utils/ntbackup/src/erase.c
@@ -0,0 +1,617 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: ERASE.C
+
+ Description: Erase tape dialog
+
+ $Log: J:/UI/LOGFILES/ERASE.C_V $
+
+ Rev 1.45.1.0 24 May 1994 20:07:34 GREGG
+Improved handling of ECC, SQL, FUTURE_VER and OUT_OF_SEQUENCE tapes.
+
+ Rev 1.45 02 Feb 1994 18:02:32 chrish
+Added change for UNICODE app to handle ANSI secured created tapes.
+
+ Rev 1.44 28 Jan 1994 17:22:34 Glenn
+Simplified and fixed Icon support.
+
+ Rev 1.43 25 Jan 1994 08:42:28 MIKEP
+fix warnings in orcas
+
+ Rev 1.42 01 Dec 1993 14:20:40 mikep
+add SQL recognition support to poll drive
+
+ Rev 1.41 30 Jul 1993 08:47:14 CARLS
+added VLM_ECC_TAPE & VLM_FUTURE_VER
+
+ Rev 1.40 03 May 1993 10:44:54 DARRYLP
+Changed help id to match existing format help id.
+
+ Rev 1.39 22 Apr 1993 15:50:12 chrish
+Fix for Nostradamous: EPR 0403 - When erasing a tape, the owner of the
+tape would be whoever it is in the current VCB got from poll drive. However
+the true owner is the person who first created the tape. Fix will now get
+the user name from the first set on the tape.
+
+ Rev 1.38 08 Apr 1993 17:18:34 chrish
+Made change to allow erasing a tape passworded by the Cayman app.
+
+ Rev 1.37 07 Apr 1993 17:59:20 CARLS
+changed dialog title for format operation
+
+ Rev 1.36 06 Apr 1993 16:16:10 GREGG
+Removed OEM_MSOFT ifdef around setting of secure erase radio button.
+
+ Rev 1.35 26 Mar 1993 15:08:30 chrish
+Corrected wrong privilege detection for erase.
+
+ Rev 1.34 25 Mar 1993 15:45:28 CARLS
+changed Format title ID
+
+ Rev 1.33 19 Mar 1993 17:08:00 chrish
+Cosmetic stuff for erase dialog display.
+
+ Rev 1.32 17 Mar 1993 16:37:40 chrish
+Changed security check to "SeBackupPrivilege"
+
+ Rev 1.31 10 Mar 1993 12:45:26 CARLS
+Changes to move Format tape to the Operations menu
+
+ Rev 1.30 25 Feb 1993 09:50:06 TIMN
+Disable SECURE erase button if drive doesn't support it EPR(0176)
+
+ Rev 1.29 12 Feb 1993 16:02:12 CARLS
+always set the focus to Cancel button
+
+ Rev 1.28 27 Jan 1993 14:23:50 STEVEN
+updates from msoft
+
+ Rev 1.27 06 Jan 1993 14:59:38 chrish
+Corrected tape security message displayed on illegal erase.
+
+ Rev 1.26 05 Jan 1993 09:23:02 chrish
+Fix for erasing a foreign tape
+
+ Rev 1.25 23 Dec 1992 11:34:00 chrish
+Added security erase.
+
+ Rev 1.24 13 Nov 1992 17:29:02 chrish
+Added partial stuff for formatting a tape.
+
+ Rev 1.23 07 Oct 1992 13:43:48 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.22 04 Oct 1992 19:37:24 DAVEV
+Unicode Awk pass
+
+ Rev 1.21 28 Jul 1992 15:06:54 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.20 07 Jul 1992 15:42:24 MIKEP
+unicode changes
+
+ Rev 1.19 14 May 1992 16:42:28 MIKEP
+nt pass 2
+
+ Rev 1.18 27 Mar 1992 10:27:52 DAVEV
+OEM_MSOFT: add user name to tape info string and chg Secure Erase chkbox to radio buttons
+
+
+
+*****************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+#define ERASE 1
+#define FORMAT 2
+
+struct erase_temp {
+ WORD dialog_return_status ;
+ HTIMER timer_handle ;
+ HWND ghDlg ; /* window handle of the dialog box */
+ UINT32 tape_id ;
+ WORD display_status ;
+ INT poll_drive_freq ;
+ WORD operation ;
+} ;
+
+static struct erase_temp *erase_temp_ptr ;
+
+static VOID clock_routine( VOID ) ;
+
+BOOLEAN GetOriginalOwnerOfTape( DBLK_PTR, CHAR_PTR ); // chs:04-22-93
+
+
+/***************************************************
+
+ Name: DM_StartErase
+
+ Description: Starts the Erase tape dialog
+
+ Returns: Returns the status from the dialog.
+
+*****************************************************/
+INT DM_StartErase( VOID )
+{
+INT status;
+struct erase_temp temp_data ;
+
+ erase_temp_ptr = &temp_data ;
+
+ erase_temp_ptr->operation = ERASE ;
+
+ status = DM_ShowDialog( ghWndFrame, IDD_ERASE, NULL ) ;
+
+ return( status ) ;
+}
+/***************************************************
+
+ Name: DM_StartFormat
+
+ Description: Starts the Format tape dialog
+
+ Returns: Returns the status from the dialog.
+
+*****************************************************/
+#ifdef OS_WIN32
+INT DM_StartFormat( VOID )
+{
+INT status;
+struct erase_temp temp_data ;
+
+ erase_temp_ptr = &temp_data ;
+
+ erase_temp_ptr->operation = FORMAT ;
+
+ status = DM_ShowDialog( ghWndFrame, IDD_ERASE, NULL ) ;
+
+ return( status ) ;
+}
+#endif // OS_WIN32
+/***************************************************
+
+ Name: DM_Erase
+
+ Description: Erase tape dialog procedure
+
+ Returns:
+
+*****************************************************/
+DLGRESULT APIENTRY DM_Erase(
+HWND hDlg , /* window handle of the dialog box */
+MSGID message , /* type of message */
+MP1 mp1 , /* message-specific information */
+MP2 mp2
+)
+{
+ PAINTSTRUCT ps ;
+ HDC hDC ;
+ HDC hDCBitmap ;
+ HWND hWnd ;
+ HICON hIcon ;
+
+
+ UNREFERENCED_PARAMETER ( mp2 );
+
+ switch ( message )
+ {
+ case WM_INITDIALOG: /* message: initialize dialog box */
+
+ erase_temp_ptr->ghDlg = hDlg ;
+ erase_temp_ptr->tape_id = 0 ;
+
+ DM_CenterDialog( hDlg ) ;
+
+ hIcon = LoadIcon( 0, IDI_EXCLAMATION );
+ SendDlgItemMessage ( hDlg, IDD_ERASE_EXCLAMATION_BITMAP, STM_SETICON, (MP1)hIcon, 0L );
+
+#ifdef OS_WIN32
+ if( erase_temp_ptr->operation == FORMAT ) {
+ yresprintf( (INT16) RES_FORMAT_DIALOG_TITLE ) ;
+ SetWindowText( hDlg, gszTprintfBuffer ) ;
+ }
+#endif // OS_WIN32
+
+ /* read POLL DRIVE data */
+ clock_routine( ) ;
+
+ erase_temp_ptr->poll_drive_freq = PD_SetFrequency( 1 ) ;
+ erase_temp_ptr->timer_handle = WM_HookTimer( clock_routine, 1 );
+#ifdef OS_WIN32
+
+ if( erase_temp_ptr->operation == FORMAT ) {
+ yresprintf( (INT16) RES_FORMAT_TAPE_WARNING ) ;
+ SetDlgItemText( hDlg, IDD_ERASE_LINE2, gszTprintfBuffer ) ;
+ ShowWindow( GetDlgItem( hDlg, IDD_ERASE_QUICK_BUTTON ), SW_HIDE ) ;
+ ShowWindow( GetDlgItem( hDlg, IDD_ERASE_SECURE_BUTTON ), SW_HIDE ) ;
+ }
+#endif // OS_WIN32
+
+ if( erase_temp_ptr->operation == ERASE ) {
+ /* Check default log file radio button */
+ CheckDlgButton( hDlg, IDD_ERASE_QUICK_BUTTON, 1 ) ;
+
+ /* Enable or Disable the Secure Erase radio button */
+ EnableWindow( GetDlgItem( hDlg, IDD_ERASE_SECURE_BUTTON ),
+ ( thw_list->drv_info.drv_features & TDI_LONG_ERASE ) ? TRUE : 0 ) ;
+ }
+
+ return ( TRUE ) ;
+
+ case WM_COMMAND: /* message: received a command */
+ {
+ WORD wId = GET_WM_COMMAND_ID ( mp1, mp2 );
+
+ switch( wId )
+ {
+
+#ifdef OEM_MSOFT //special feature
+
+ case IDD_ERASE_QUICK_BUTTON:
+ case IDD_ERASE_SECURE_BUTTON:
+
+ CheckRadioButton ( hDlg, IDD_ERASE_QUICK_BUTTON,
+ IDD_ERASE_SECURE_BUTTON, wId ) ;
+ return TRUE ;
+
+#endif //OEM_MSOFT //special feature
+
+/****************************************************************************
+ Continue button
+/***************************************************************************/
+ case IDD_ERASE_CONTINUE_BUTTON:
+
+#ifdef OEM_MSOFT
+{
+ CHAR_PTR passwdbuffer1;
+ LPSTR generic_str_ptr;
+ INT16 passwordlength;
+ DBLK_PTR vcb_ptr;
+ CHAR buffer[ MAX_UI_RESOURCE_SIZE ];
+ CHAR buffer2[ MAX_UI_RESOURCE_SIZE ];
+
+ //
+ // Check to see if is a valid user or not
+ //
+
+ if ( VLM_GetDriveStatus( &vcb_ptr ) == VLM_VALID_TAPE ) {
+ generic_str_ptr = GetCurrentMachineNameUserName( );
+ passwdbuffer1 = ( CHAR_PTR )calloc( 1, ( 3 + strlen( generic_str_ptr ) ) * sizeof( CHAR ) );
+
+ if ( passwdbuffer1 ) {
+ *passwdbuffer1 = NTPASSWORDPREFIX;
+ if ( generic_str_ptr ) {
+ strcat( passwdbuffer1, generic_str_ptr );
+ }
+
+ passwordlength = strlen( passwdbuffer1 );
+// chs:02-01-94 CryptPassword( ( INT16 ) ENCRYPT, ENC_ALGOR_3, (INT8_PTR)passwdbuffer1, ( INT16 ) ( strlen( passwdbuffer1 ) * sizeof( CHAR ) ) );
+ if ( ( WhoPasswordedTape ( (BYTE_PTR)FS_ViewTapePasswordInVCB( vcb_ptr ), FS_SizeofTapePswdInVCB( vcb_ptr ) ) != OTHER_APP ) && // chs:04-08-93
+ !IsUserValid( vcb_ptr, (BYTE_PTR)passwdbuffer1, ( INT16 )( passwordlength * sizeof( CHAR ) ) ) && !DoesUserHaveThisPrivilege( TEXT ( "SeBackupPrivilege" ) ) ) { // chs:04-08-93
+ //
+ // Popup dialog box message if
+ // not a valid user
+ //
+
+ RSM_StringCopy( IDS_ERASE_TAPE_SECURITY, buffer, sizeof(buffer) );
+ RSM_StringCopy( IDS_TAPE_SECURITY_TITLE, buffer2, sizeof(buffer2) );
+ WM_MsgBox( buffer2, buffer, WMMB_OK, WMMB_ICONEXCLAMATION );
+ buffer[0] = 0;
+ free( passwdbuffer1 );
+ return ( TRUE );
+ }
+
+ free( passwdbuffer1 );
+ }
+ }
+}
+#endif //OEM_MSOFT
+
+ /* if secure erase is checked - set for secure erase */
+ if( IsDlgButtonChecked( hDlg, IDD_ERASE_SECURE_BUTTON ) )
+ CDS_SetEraseFlag( CDS_GetCopy(), ERASE_LONG ) ;
+
+#ifdef OS_WIN32
+ if( erase_temp_ptr->operation == FORMAT ) {
+ CDS_SetEraseFlag( CDS_GetCopy(), ERASE_FORMAT ) ;
+ }
+#endif // OS_WIN32
+
+ WM_UnhookTimer( erase_temp_ptr->timer_handle );
+ PD_SetFrequency( erase_temp_ptr->poll_drive_freq ) ;
+ EndDialog( hDlg, TRUE ) ; /* Exits the dialog box */
+ return ( TRUE ) ;
+ break ;
+/****************************************************************************
+ Help button
+/***************************************************************************/
+ case IDD_ERASE_HELP_BUTTON:
+ case IDHELP :
+
+ if( erase_temp_ptr->operation == FORMAT ) {
+ HM_DialogHelp( HELPID_OPERATIONSFORMAT ) ;
+ } else {
+ HM_DialogHelp( HELPID_DIALOGERASE ) ;
+ }
+
+ return ( TRUE ) ;
+ break ;
+/****************************************************************************
+ Cancel button
+/***************************************************************************/
+ case IDD_ERASE_CANCEL_BUTTON:
+ case IDCANCEL:
+
+ WM_UnhookTimer( erase_temp_ptr->timer_handle );
+ PD_SetFrequency( erase_temp_ptr->poll_drive_freq ) ;
+ EndDialog( hDlg, FALSE ) ; /* Exits the dialog box */
+ return ( TRUE ) ;
+ break ;
+
+ }
+ }
+ break ;
+ }
+ return ( FALSE ) ; /* Didn't process a message */
+}
+
+
+/***************
+
+ GetDriveStatus
+ possible return values
+ SEE VLM.H
+
+ VLM_VALID_TAPE 0
+ VLM_DRIVE_BUSY 1
+ VLM_FOREIGN_TAPE 2
+ VLM_BLANK_TAPE 3
+ VLM_NO_TAPE 4
+ VLM_BUSY 5
+ VLM_BAD_TAPE 6
+ VLM_GOOFY_TAPE 7
+ VLM_DISABLED 8
+ VLM_UNFORMATED 9
+ VLM_DRIVE_FAILURE 10
+ VLM_FUTURE_VER 11
+ VLM_ECC_TAPE 12
+ VLM_SQL_TAPE 13
+
+
+***************/
+/***************************************************
+
+ Name: clock_routine
+
+ Description: poll drive status routine
+
+ Returns: void
+
+*****************************************************/
+static VOID clock_routine( VOID )
+{
+ DBLK_PTR vcb_ptr ;
+ DATE_TIME_PTR dt ;
+ WORD status ;
+ UINT32 current_tape_id ;
+ CHAR date_str[ MAX_UI_DATE_SIZE ] ;
+ CHAR time_str[ MAX_UI_TIME_SIZE ] ;
+ CHAR buffer[ 80 ] ;
+ CHAR temptapepswd[2]; // chs:03-19-93
+
+ status = VLM_GetDriveStatus( &vcb_ptr ) ;
+
+ switch( status ) {
+
+ case VLM_VALID_TAPE:
+
+ /* get this tape ID */
+ current_tape_id = FS_ViewTapeIDInVCB( vcb_ptr ) ;
+
+ /* if this ID not equal to the last ID, then must be a new tape */
+ if( erase_temp_ptr->tape_id != current_tape_id )
+ {
+ /* save this tape ID */
+ erase_temp_ptr->tape_id = current_tape_id ;
+
+ /* display name, date and time of this tape */
+ dt = FS_ViewBackupDateInVCB( vcb_ptr ) ;
+ UI_MakeDateString( date_str, dt->month, dt->day, dt->year % 100 );
+ UI_MakeShortTimeString( time_str, dt->hour, dt->minute );
+
+# if defined ( OEM_MSOFT ) //alternate feature
+ {
+ CHAR namebuffer[ MAX_UI_RESOURCE_SIZE ]; // chs:04-22-93
+ // chs:04-22-93
+ if ( !GetOriginalOwnerOfTape( vcb_ptr, namebuffer ) ) { // chs:04-22-93
+ strcpy( namebuffer, FS_ViewUserNameInVCB( vcb_ptr ) ); // chs:04-22-93
+ } // chs:04-22-93
+
+ yresprintf( (INT16) RES_ERASE_TAPE_INFO1 ,
+ FS_ViewTapeNameInVCB( vcb_ptr ) ,
+ // chs:04-22-93 FS_ViewUserNameInVCB( vcb_ptr ),
+ namebuffer, // chs:04-22-93
+ date_str ,
+ time_str ) ;
+ }
+# else //if defined ( OEM_MSOFT ) //alternate feature
+ {
+ yresprintf( RES_ERASE_TAPE_INFO1 ,
+ FS_ViewTapeNameInVCB( vcb_ptr ) ,
+ date_str ,
+ time_str ) ;
+ }
+# endif //defined ( OEM_MSOFT ) //alternate feature
+
+#ifndef OEM_MSOFT // chs:03-19-93
+ // // chs:03-19-93
+ // Just cosmetic stuff // chs:03-19-93
+ // // chs:03-19-93
+ // chs:03-19-93
+ if( FS_SizeofTapePswdInVCB( vcb_ptr ) ) { // chs:03-19-93
+ temptapepswd[0] = *( FS_ViewTapePasswordInVCB( vcb_ptr ) ); // chs:03-19-93
+ temptapepswd[1] = TEXT( '\0' ); // chs:03-19-93
+ CryptPassword( ( INT16 ) DECRYPT, FS_ViewPswdEncryptInVCB( vcb_ptr ), (INT8_PTR)temptapepswd, 1 * sizeof( CHAR ) ); // chs:03-19-93
+ if ( temptapepswd[0] != NTPASSWORDPREFIX ) { // chs:04-08-93
+ // chs:03-19-93
+ RSM_StringCopy( IDS_TAPE_PASSWORD_PROTECTED, buffer, 80 ) ; // chs:03-19-93
+ strcat( gszTprintfBuffer, buffer ) ; // chs:03-19-93
+ } // chs:03-19-93
+ } // chs:03-19-93
+#endif // chs:03-19-93
+
+// chs:03-19-93 if( FS_SizeofTapePswdInVCB( vcb_ptr ) ) {
+// chs:03-19-93
+// chs:03-19-93 RSM_StringCopy( IDS_TAPE_PASSWORD_PROTECTED, buffer, 80 ) ;
+// chs:03-19-93 strcat( gszTprintfBuffer, buffer ) ;
+// chs:03-19-93 }
+
+ SetDlgItemText( erase_temp_ptr->ghDlg, IDD_ERASE_LINE1, gszTprintfBuffer ) ;
+
+ /* turn the CONTINUE button on */
+ EnableWindow ( GetDlgItem ( erase_temp_ptr->ghDlg, IDD_ERASE_CONTINUE_BUTTON ), TRUE ) ;
+ }
+ break;
+
+ case VLM_FUTURE_VER:
+ case VLM_SQL_TAPE:
+ case VLM_ECC_TAPE:
+ case VLM_FOREIGN_TAPE:
+ case VLM_GOOFY_TAPE:
+
+ if ( erase_temp_ptr->display_status != VLM_FOREIGN_TAPE ) {
+
+ erase_temp_ptr->display_status = VLM_FOREIGN_TAPE ;
+
+ switch( status ) {
+
+ case VLM_FUTURE_VER:
+ yresprintf( IDS_VLMFUTURETEXT ) ;
+ break ;
+
+ case VLM_SQL_TAPE:
+ yresprintf( IDS_VLMSQLTEXT ) ;
+ break ;
+
+ case VLM_ECC_TAPE:
+ yresprintf( IDS_VLMECCTEXT ) ;
+ break ;
+
+ case VLM_FOREIGN_TAPE:
+ yresprintf( (INT16)RES_ERASE_FOREIGN_TAPE ) ;
+ break ;
+
+ case VLM_GOOFY_TAPE:
+ yresprintf( IDS_VLMGOOFYTEXT ) ;
+ break ;
+ }
+
+ SetDlgItemText( erase_temp_ptr->ghDlg, IDD_ERASE_LINE1, gszTprintfBuffer ) ;
+ /* turn the CONTINUE button on */
+ EnableWindow ( GetDlgItem ( erase_temp_ptr->ghDlg, IDD_ERASE_CONTINUE_BUTTON ), TRUE ) ;
+ erase_temp_ptr->tape_id = 0 ;
+ }
+ break ;
+
+ case VLM_BAD_TAPE:
+
+ if(erase_temp_ptr->display_status != VLM_BAD_TAPE ) {
+
+ erase_temp_ptr->display_status = VLM_BAD_TAPE ;
+ yresprintf( (INT16) RES_ERASE_BAD_TAPE ) ;
+ SetDlgItemText( erase_temp_ptr->ghDlg, IDD_ERASE_LINE1, gszTprintfBuffer ) ;
+ /* turn the CONTINUE button on */
+ EnableWindow ( GetDlgItem ( erase_temp_ptr->ghDlg, IDD_ERASE_CONTINUE_BUTTON ), TRUE ) ;
+ erase_temp_ptr->tape_id = 0 ;
+ }
+ break;
+
+ case VLM_BLANK_TAPE:
+
+ if(erase_temp_ptr->display_status != VLM_BLANK_TAPE ) {
+
+ erase_temp_ptr->display_status = VLM_BLANK_TAPE ;
+ yresprintf( (INT16) RES_ERASE_BLANK_TAPE ) ;
+ SetDlgItemText( erase_temp_ptr->ghDlg, IDD_ERASE_LINE1, gszTprintfBuffer ) ;
+ /* turn the CONTINUE button on */
+ EnableWindow ( GetDlgItem ( erase_temp_ptr->ghDlg, IDD_ERASE_CONTINUE_BUTTON ), TRUE ) ;
+ erase_temp_ptr->tape_id = 0 ;
+ }
+ break;
+
+#ifdef OS_WIN32
+ case VLM_UNFORMATED:
+
+ if(erase_temp_ptr->display_status != VLM_UNFORMATED ) {
+
+ erase_temp_ptr->display_status = VLM_UNFORMATED ;
+ yresprintf( (INT16) RES_VLM_UNFORMATED_TAPE ) ;
+ SetDlgItemText( erase_temp_ptr->ghDlg, IDD_ERASE_LINE1, gszTprintfBuffer ) ;
+ /* turn the CONTINUE button on */
+ EnableWindow ( GetDlgItem ( erase_temp_ptr->ghDlg, IDD_ERASE_CONTINUE_BUTTON ), TRUE ) ;
+ erase_temp_ptr->tape_id = 0 ;
+ }
+ break;
+#endif // OS_WIN32
+
+ case VLM_NO_TAPE:
+
+ if(erase_temp_ptr->display_status != VLM_NO_TAPE ) {
+
+ erase_temp_ptr->display_status = VLM_NO_TAPE ;
+ yresprintf( (INT16) RES_ERASE_NO_TAPE ) ;
+ SetDlgItemText( erase_temp_ptr->ghDlg, IDD_ERASE_LINE1, gszTprintfBuffer ) ;
+
+ /* turn the CONTINUE button off when busy */
+
+ if ( GetFocus() == GetDlgItem ( erase_temp_ptr->ghDlg, IDD_ERASE_CONTINUE_BUTTON ) ) {
+ SetFocus( GetDlgItem ( erase_temp_ptr->ghDlg, IDD_ERASE_CANCEL_BUTTON ) );
+ }
+ EnableWindow ( GetDlgItem ( erase_temp_ptr->ghDlg, IDD_ERASE_CONTINUE_BUTTON ), FALSE ) ;
+
+ erase_temp_ptr->tape_id = 0 ;
+ }
+ break;
+
+ case VLM_BUSY:
+
+ if(erase_temp_ptr->display_status != VLM_BUSY ) {
+
+ erase_temp_ptr->display_status = VLM_BUSY ;
+ yresprintf( (INT16) RES_ERASE_DRIVE_BUSY ) ;
+ SetDlgItemText( erase_temp_ptr->ghDlg, IDD_ERASE_LINE1, gszTprintfBuffer ) ;
+
+ /* turn the CONTINUE button off when busy */
+
+ if ( GetFocus() == GetDlgItem ( erase_temp_ptr->ghDlg, IDD_ERASE_CONTINUE_BUTTON ) ) {
+ SetFocus( GetDlgItem ( erase_temp_ptr->ghDlg, IDD_ERASE_CANCEL_BUTTON ) );
+ }
+ EnableWindow ( GetDlgItem ( erase_temp_ptr->ghDlg, IDD_ERASE_CONTINUE_BUTTON ), FALSE ) ;
+
+ erase_temp_ptr->tape_id = 0 ;
+ }
+ break;
+
+ case VLM_DISABLED:
+
+ if(erase_temp_ptr->display_status != VLM_DISABLED ) {
+
+ erase_temp_ptr->display_status = VLM_DISABLED ;
+ yresprintf( (INT16) RES_ERASE_POLL_DRIVE_DISABLED ) ;
+ SetDlgItemText( erase_temp_ptr->ghDlg, IDD_ERASE_LINE1, gszTprintfBuffer ) ;
+ /* turn the CONTINUE button on */
+ EnableWindow ( GetDlgItem ( erase_temp_ptr->ghDlg, IDD_ERASE_CONTINUE_BUTTON ), TRUE ) ;
+ erase_temp_ptr->tape_id = 0 ;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
diff --git a/private/utils/ntbackup/src/exe.bmp b/private/utils/ntbackup/src/exe.bmp
new file mode 100644
index 000000000..b1a9ea401
--- /dev/null
+++ b/private/utils/ntbackup/src/exe.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/file.bmp b/private/utils/ntbackup/src/file.bmp
new file mode 100644
index 000000000..286e4f89c
--- /dev/null
+++ b/private/utils/ntbackup/src/file.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/files.ico b/private/utils/ntbackup/src/files.ico
new file mode 100644
index 000000000..d746fddaf
--- /dev/null
+++ b/private/utils/ntbackup/src/files.ico
Binary files differ
diff --git a/private/utils/ntbackup/src/filgetc.c b/private/utils/ntbackup/src/filgetc.c
new file mode 100644
index 000000000..8b2848836
--- /dev/null
+++ b/private/utils/ntbackup/src/filgetc.c
@@ -0,0 +1,96 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: filgetc.c
+
+ Description: This file contains code to get & unget the next
+ character in the current file.
+
+ $Log: G:/UI/LOGFILES/FILGETC.C_V $
+
+ Rev 1.7 03 May 1993 09:46:42 MIKEP
+try again.
+
+ Rev 1.6 03 May 1993 08:59:10 MIKEP
+Fix last change so it would compile.
+
+ Rev 1.5 02 May 1993 19:37:26 BARRY
+Changed to properly detect EOF on MIPS machine.
+
+ Rev 1.4 07 Oct 1992 14:15:44 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.3 04 Oct 1992 19:37:26 DAVEV
+Unicode Awk pass
+
+ Rev 1.2 17 Aug 1992 13:17:48 DAVEV
+MikeP's changes at Microsoft
+
+ Rev 1.1 18 May 1992 09:06:36 MIKEP
+header
+
+ Rev 1.0 20 Nov 1991 19:19:34 SYSTEM
+Initial revision.
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+/*****************************************************************************
+
+ Name: filegetc()
+
+ Description: This function get the next character from an opened
+ file.
+
+ Returns: The character read from the file
+ ^Z if end of file.
+
+*****************************************************************************/
+CHAR filgetc(
+CHAR *fin , /* I - must come in as CHAR_PTR then cast as needed */
+INT16_PTR kludge ) /* U - here for consistency with string version */
+{
+ INT ch;
+ CHAR ret_val ;
+
+ ch = fgetc( (FILE * ) fin ) ;
+ ret_val = (CHAR)ch;
+
+ if ( ch == EOF ) {
+ if ( feof( (FILE *)fin ) || ferror( (FILE *)fin ) ) {
+ ret_val = 0x1a ;
+ }
+ }
+
+ return( ret_val ) ;
+
+ kludge ; /* so compiler won't complain ! */
+}
+/*****************************************************************************
+
+ Name: filpushc()
+
+ Description: This function places a character back into a file
+ by doing an ungetc()
+
+ Returns: nothing
+
+ Notes: The file pointer is passed as a character pointer
+ for conistancy with the string version.
+
+*****************************************************************************/
+VOID filpushc(
+CHAR c , /* I - character to palce back in fie */
+CHAR_PTR fin , /* I - File pointer */
+INT16_PTR kludge ) /* U - unused */
+{
+ INT16* dummy ;
+ dummy = kludge ; /* so compiler won't complain about unref locals */
+ ( VOID ) ungetc( c, (FILE *) fin ) ;
+ return ;
+}
diff --git a/private/utils/ntbackup/src/floppy1.bmp b/private/utils/ntbackup/src/floppy1.bmp
new file mode 100644
index 000000000..1b160782d
--- /dev/null
+++ b/private/utils/ntbackup/src/floppy1.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/floppy2.bmp b/private/utils/ntbackup/src/floppy2.bmp
new file mode 100644
index 000000000..1b160782d
--- /dev/null
+++ b/private/utils/ntbackup/src/floppy2.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/floppy3.bmp b/private/utils/ntbackup/src/floppy3.bmp
new file mode 100644
index 000000000..1b160782d
--- /dev/null
+++ b/private/utils/ntbackup/src/floppy3.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/floppy4.bmp b/private/utils/ntbackup/src/floppy4.bmp
new file mode 100644
index 000000000..1b160782d
--- /dev/null
+++ b/private/utils/ntbackup/src/floppy4.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/fmttab.c b/private/utils/ntbackup/src/fmttab.c
new file mode 100644
index 000000000..e2a0739ca
--- /dev/null
+++ b/private/utils/ntbackup/src/fmttab.c
@@ -0,0 +1,581 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: fmttab.c
+
+ Description: Contains the static table of tape format translator
+ entry points.
+
+ Note: To add a new translator, you must edit both this file
+ and "lwtfinf.c".
+
+
+ $Log: T:/LOGFILES/FMTTAB.C_V $
+
+ Rev 1.31 22 Jun 1993 10:53:20 GREGG
+Added API to change the catalog directory path.
+
+ Rev 1.30 29 Apr 1993 22:26:46 GREGG
+Added StartRead entry point for MTF translator.
+
+ Rev 1.29 17 Mar 1993 15:15:04 TERRI
+Added changes for the Sytos Plus translator.
+
+ Rev 1.28 09 Mar 1993 18:14:54 GREGG
+Initial changes for new stream and EOM processing.
+
+ Rev 1.27 26 Jan 1993 01:30:50 GREGG
+Added Fast Append functionality.
+
+ Rev 1.26 25 Jan 1993 22:11:48 GREGG
+Brought all translators up to date as far as number of entries in table.
+
+ Rev 1.25 23 Nov 1992 10:22:40 HUNTER
+Add F40_ParseEOM into table.
+
+ Rev 1.24 17 Nov 1992 22:17:42 DAVEV
+unicode fixes
+
+ Rev 1.23 11 Nov 1992 13:59:38 HUNTER
+Deleted reference to "F31_Recall"
+
+ Rev 1.22 11 Nov 1992 09:45:56 HUNTER
+Updated Maynard 3.1 table.
+NOTE: This translator no longer supports writing tapes, and no longer
+supports reading IMAGE DBs.
+
+ Rev 1.21 09 Nov 1992 11:00:52 GREGG
+Added entry points for accessing tape catalogs.
+
+ Rev 1.20 03 Nov 1992 09:30:46 HUNTER
+
+ Rev 1.19 22 Oct 1992 10:44:00 HUNTER
+Changes for new stream headers
+
+ Rev 1.18 25 Sep 1992 09:29:10 GREGG
+Changed rd_mk_mdb function in 40 format table from NULL to F40_RdEOSPadBlk.
+
+ Rev 1.17 22 Sep 1992 08:56:48 GREGG
+Initial changes to handle physical block sizes greater than 1K.
+
+ Rev 1.16 14 Aug 1992 16:23:56 GREGG
+Removed size fields in function table initialization.
+
+ Rev 1.15 04 Aug 1992 16:54:40 GREGG
+Burt's fixes for variable length block support.
+
+ Rev 1.14 20 May 1992 19:58:44 GREGG
+Added StartRead and removed verify_vcb for 40 format.
+
+ Rev 1.13 28 Apr 1992 16:15:30 GREGG
+ROLLER BLADES - Added new_tape entry for 4.0 format.
+
+ Rev 1.12 23 Apr 1992 10:54:54 BURT
+Added table entries for Sytos Plus 1.0 read translator.
+
+
+ Rev 1.11 05 Apr 1992 17:17:10 GREGG
+ROLLER BLADES - Initial OTC integration.
+
+ Rev 1.10 25 Mar 1992 19:40:54 GREGG
+ROLLER BLADES - Added 4.0 format and min_siz_for_dblk to all.
+
+ Rev 1.9 11 Feb 1992 15:33:22 ZEIR
+
+ - Ad'd UTF_PreferredSpace entry.
+
+ Rev 1.8 04 Feb 1992 21:31:36 NED
+Changes to Buffer Management translator hooks.
+
+ Rev 1.7 16 Jan 1992 18:43:44 ZEIR
+Latest BufferMan solution no longer requires StartReadHook.
+
+ Rev 1.6 06 Jan 1992 17:34:46 ZEIR
+Added UTF entry, and ReadStartHook
+
+ Rev 1.5 05 Dec 1991 14:01:54 GREGG
+SKATEBOARD - New Buff Mgt - Initial Integration.
+
+ Rev 1.4 19 Nov 1991 08:53:48 GREGG
+VBLK - Closed the comment that HUNTER OPENED!!! (how did it ever compile???)
+
+ Rev 1.3 07 Nov 1991 15:33:56 unknown
+VBLK - Added Variable Length Block Support
+
+ Rev 1.2 07 Jun 1991 00:39:46 NED
+Added compiler directives to allow selective inclusion of translators.
+
+ Rev 1.1 10 May 1991 11:54:56 GREGG
+Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:18:42 GREGG
+Initial revision.
+
+**/
+
+/* begin include list */
+#include <stdio.h>
+#include "stdtypes.h"
+#include "stdmacro.h"
+#include "tbe_defs.h"
+#include "datetime.h"
+
+#include "drive.h"
+#include "channel.h"
+#include "fmteng.h"
+#include "transutl.h"
+#include "fsys.h"
+#include "tloc.h"
+#include "lw_data.h"
+#include "tfldefs.h"
+
+#include "mayn40.h"
+#include "transprt.h" /* prototypes */
+
+/* $end$ include list */
+
+FMT supported_fmts[] = {
+
+#ifdef MY40_TRANS
+ /*
+ * Maynard Tape Format 4.0
+ */
+ {
+ F40_Determiner, /* determiner */
+ F40_Initialize, /* initializer */
+ F40_DeInitialize, /* deinitializer */
+ NULL, /* VCB buffer reqs */
+ NULL, /* get preferred space */
+ NULL, /* read buffer hook */
+ F40_DetBlkType, /* parser */
+ F40_SizeofTBLK, /* sizeof_tblk */
+ F40_RdException, /* exception_action */
+ F40_NewTape, /* new_tape, process tape header */
+ F40_WriteInit, /* post-positioning write init */
+ F40_InitTape, /* initialize new tape for write */
+ F40_StartRead, /* post-positioning read init */
+ F40_MoveToVCB, /* move_to_vcb */
+ F40_SeekEOD, /* seek_eod (for fast append) */
+ F40_RdSSET, /* get_current_vcb */
+ NULL, /* verify_vcb */
+ F40_RdContTape, /* rd_cont_tape */
+ NULL, /* rd_recall */
+ F40_RdSSET, /* rd_mk_vcb */
+ F40_RdDIRB, /* rd_mk_ddb */
+ F40_RdFILE, /* rd_mk_fdb */
+ F40_RdIMAG, /* rd_mk_idb */
+ F40_RdCFIL, /* rd_mk_cfdb */
+ F40_RdSSET, /* rd_mk_bsdb */
+ F40_RdUDB, /* rd_mk_osudb */
+ F40_RdMDB, /* rd_mk_mdb */
+ F40_RdStream, /* read stream */
+ F40_WtSSET, /* wt_mk_vcb */
+ F40_WtDIRB, /* wt_mk_ddb */
+ F40_WtFILE, /* wt_mk_fdb */
+ F40_WtStream, /* Write Stream */
+ F40_EndData, /* End Data */
+ F40_WtIMAG, /* wt_mk_idb */
+ F40_WtCFIL, /* wt_mk_cfdb */
+ F40_WtContVStream, /* Continue Variable Stream */
+ F40_WtEndVStream, /* End Variable Stream */
+ F40_ParseWrittenBuffer, /* Post processing of write buffer */
+ F40_WtCloseTape, /* wt_close_tape */
+ F40_WtContTape, /* wt_cont_set */
+ F40_WtCloseSet, /* wt_close_set */
+ F40_WtEOSPadBlk, /* wt_eos_pad_blk */
+ F40_LoadSM, /* load_set_map */
+ F40_LoadFDD, /* load_set_cat */
+ F40_GetNextSMEntry, /* get_next_sm_entry */
+ F40_GetNextFDDEntry, /* get_next_sc_entry */
+ F40_CloseCatalogs /* close_catalogs */
+ },
+#endif
+
+#ifdef MY31_TRANS
+ /*
+ * Maynard Tape Format 3.1
+ */
+ {
+ F31_Determiner, /* determiner */
+ F31_Initialize, /* initializer */
+ F31_DeInitialize, /* deinitializer */
+ NULL, /* VCB buffer reqs */
+ NULL, /* get preferred space */
+ NULL, /* read buffer hook */
+ F31_DetBlkType, /* parser */
+ F31_SizeofTBLK, /* sizeof_tblk */
+ F31_RdException, /* exception_action */
+ NULL, /* new_tape, process tape header */
+ NULL, /* post-positioning write init */
+ NULL, /* initialize new tape for write */
+ NULL, /* post-positioning read init */
+ F31_MoveToVCB, /* move_to_vcb */
+ NULL, /* seek_eod (for fast append) */
+ F31_RdVCB, /* get_current_vcb */
+ F31_Determiner, /* verify_vcb */
+ F31_RdContTape, /* rd_cont_tape */
+ NULL, /* rd_recall */
+ F31_RdVCB, /* rd_mk_vcb */
+ F31_RdDDB, /* rd_mk_ddb */
+ F31_RdFDB, /* rd_mk_fdb */
+ NULL, /* rd_mk_idb */
+ F31_RdCFDB, /* rd_mk_cfdb */
+ F31_RdVCB, /* rd_mk_bsdb */
+ F31_RdUDB, /* rd_mk_osudb */
+ NULL, /* rd_mk_mdb */
+ F31_RdStream, /* read stream */
+ NULL, /* wt_mk_vcb */
+ NULL, /* wt_mk_ddb */
+ NULL, /* wt_mk_fdb */
+ NULL, /* Write Stream */
+ NULL, /* End Data */
+ NULL, /* wt_mk_idb */
+ NULL, /* wt_mk_cfdb */
+ NULL, /* Continue Variable Stream */
+ NULL, /* End Variable Stream */
+ NULL, /* Post processing of write buffer */
+ NULL, /* wt_close_tape */
+ NULL, /* wt_cont_set */
+ NULL, /* wt_close_set */
+ NULL, /* wt_eos_pad_blk */
+ NULL, /* load_set_map */
+ NULL, /* load_set_cat */
+ NULL, /* get_next_sm_entry */
+ NULL, /* get_next_sc_entry */
+ NULL /* close_catalogs */
+ },
+#endif
+
+#ifdef MY30_TRANS
+ /*
+ * Maynard Tape Format 3.0
+ */
+ {
+ F30_Determiner, /* determiner */
+ F30_Initializer, /* initializer */
+ F30_DeInitialize, /* deinitializer */
+ NULL, /* VCB buffer reqs */
+ NULL, /* get preferred space */
+ NULL, /* read buffer hook */
+ F30_DetBlkType, /* parser */
+ NULL, /* sizeof_tblk */
+ F30_RdException, /* exception_action */
+ NULL, /* new_tape, process tape header */
+ NULL, /* post-positioning write init */
+ NULL, /* initialize new tape for write */
+ NULL, /* post-positioning read init */
+ F30_MoveToVCB, /* move_to_vcb */
+ NULL, /* seek_eod (for fast append) */
+ F30_RdVCB, /* get_current_vcb */
+ F30_Determiner, /* verify_vcb */
+ F30_RdContTape, /* rd_cont_tape */
+ NULL, /* rd_recall */
+ F30_RdVCB, /* rd_mk_vcb */
+ F30_RdDDB, /* rd_mk_ddb */
+ F30_RdFDB, /* rd_mk_fdb */
+ NULL, /* rd_mk_idb */
+ F30_RdCFDB, /* rd_mk_cfdb */
+ NULL, /* rd_mk_bsdb */
+ F30_RdUDB, /* rd_mk_osudb */
+ NULL, /* rd_mk_mdb */
+ NULL, /* read stream */
+ NULL, /* wt_mk_vcb */
+ NULL, /* wt_mk_ddb */
+ NULL, /* wt_mk_fdb */
+ NULL, /* Write Stream */
+ NULL, /* End Data */
+ NULL, /* wt_mk_idb */
+ NULL, /* wt_mk_cfdb */
+ NULL, /* Continue Variable Stream */
+ NULL, /* End Variable Stream */
+ NULL, /* Post processing of write buffer */
+ NULL, /* wt_close_tape */
+ NULL, /* wt_cont_set */
+ NULL, /* wt_close_set */
+ NULL, /* wt_eos_pad_blk */
+ NULL, /* load_set_map */
+ NULL, /* load_set_cat */
+ NULL, /* get_next_sm_entry */
+ NULL, /* get_next_sc_entry */
+ NULL /* close_catalogs */
+ },
+#endif
+
+#ifdef MY25_TRANS
+ /*
+ * Maynard Tape Format 2.5
+ */
+ {
+ F25_Determiner, /* determiner */
+ F25_Initializer, /* initializer */
+ F25_DeInitialize, /* deinitializer */
+ NULL, /* VCB buffer reqs */
+ NULL, /* get preferred space */
+ NULL, /* read buffer hook */
+ F25_DetBlkType, /* parser */
+ NULL, /* sizeof_tblk */
+ F25_RdException, /* exception_action */
+ NULL, /* new_tape, process tape header */
+ NULL, /* post-positioning write init */
+ NULL, /* initialize new tape for write */
+ NULL, /* post-positioning read init */
+ F25_MoveToVCB, /* move_to_vcb */
+ NULL, /* seek_eod (for fast append) */
+ F25_RdVCB, /* get_current_vcb */
+ F25_Determiner, /* verify_vcb */
+ F25_RdContTape, /* rd_cont_tape */
+ F25_Recall, /* rd_recall */
+ F25_RdVCB, /* rd_mk_vcb */
+ F25_RdDDB, /* rd_mk_ddb */
+ F25_RdFDB, /* rd_mk_fdb */
+ F25_RdIDB, /* rd_mk_idb */
+ F25_RdCFDB, /* rd_mk_cfdb */
+ NULL, /* rd_mk_bsdb */
+ F25_RdUDB, /* rd_mk_osudb */
+ F25_RdMDB, /* rd_mk_mdb */
+ NULL, /* read stream */
+ NULL, /* wt_mk_vcb */
+ NULL, /* wt_mk_ddb */
+ NULL, /* wt_mk_fdb */
+ NULL, /* Write Stream */
+ NULL, /* End Data */
+ NULL, /* wt_mk_idb */
+ NULL, /* wt_mk_cfdb */
+ NULL, /* Continue Variable Stream */
+ NULL, /* End Variable Stream */
+ NULL, /* Post processing of write buffer */
+ NULL, /* wt_close_tape */
+ NULL, /* wt_cont_set */
+ NULL, /* wt_close_set */
+ NULL, /* wt_eos_pad_blk */
+ NULL, /* load_set_map */
+ NULL, /* load_set_cat */
+ NULL, /* get_next_sm_entry */
+ NULL, /* get_next_sc_entry */
+ NULL /* close_catalogs */
+ },
+#endif
+
+#ifdef QS19_TRANS
+ /*
+ * QicStream 1.92/1.93
+ */
+ {
+ FQ_DetermineFormat, /* determiner */
+ FQ_Initialize, /* initializer */
+ FQ_DeInitialize, /* deinitializer */
+ NULL, /* VCB buffer reqs */
+ NULL, /* get preferred space */
+ NULL, /* read buffer hook */
+ FQ_Parse, /* parser */
+ NULL, /* sizeof_tblk */
+ FQ_RdException, /* exception_action */
+ FQ_NewTape, /* new_tape, process tape header */
+ NULL, /* post-positioning write init */
+ NULL, /* initialize new tape for write */
+ NULL, /* post-positioning read init */
+ FQ_MoveToVCB, /* move_to_vcb */
+ NULL, /* seek_eod (for fast append) */
+ FQ_GetCurrentVCB, /* get_current_vcb */
+ NULL, /* verify_vcb */
+ NULL, /* rd_cont_tape */
+ FQ_ReTranslate, /* rd_recall */
+ NULL, /* rd_mk_vcb */
+ FQ_ReadMakeDDB, /* rd_mk_ddb */
+ FQ_ReadMakeFDB, /* rd_mk_fdb */
+ NULL, /* rd_mk_idb */
+ NULL, /* rd_mk_cfdb */
+ NULL, /* rd_mk_bsdb */
+ FQ_ReadMakeUDB, /* rd_mk_osudb */
+ FQ_ReadMakeMDB, /* rd_mk_mdb */
+ NULL, /* read stream */
+ NULL, /* wt_mk_vcb */
+ NULL, /* wt_mk_ddb */
+ NULL, /* wt_mk_fdb */
+ NULL, /* Write Stream */
+ NULL, /* End Data */
+ NULL, /* wt_mk_idb */
+ NULL, /* wt_mk_cfdb */
+ NULL, /* Continue Variable Stream */
+ NULL, /* End Variable Stream */
+ NULL, /* Post processing of write buffer */
+ NULL, /* wt_close_tape */
+ NULL, /* wt_cont_set */
+ NULL, /* wt_close_set */
+ NULL, /* wt_eos_pad_blk */
+ NULL, /* load_set_map */
+ NULL, /* load_set_cat */
+ NULL, /* get_next_sm_entry */
+ NULL, /* get_next_sc_entry */
+ NULL /* close_catalogs */
+ },
+#endif
+
+#ifdef SY31_TRANS
+ /*
+ * SyTos 3.11 Read
+ */
+ {
+ FSYT_DetermineFormat, /* determiner */
+ FSYT_Initialize, /* initializer */
+ FSYT_DeInitialize, /* deinitializer */
+ NULL, /* VCB buffer reqs */
+ NULL, /* get preferred space */
+ NULL, /* read buffer hook */
+ FSYT_Parse, /* parser */
+ NULL, /* sizeof_tblk */
+ FSYT_RdException, /* exception_action */
+ FSYT_NewTape, /* new_tape, process tape header */
+ NULL, /* post-positioning write init */
+ NULL, /* initialize new tape for write */
+ NULL, /* post-positioning read init */
+ FSYT_MoveToVCB, /* move_to_vcb */
+ NULL, /* seek_eod (for fast append) */
+ FSYT_GetCurrentVCB, /* get_current_vcb */
+ NULL, /* verify_vcb */
+ NULL, /* rd_cont_tape */
+ FSYT_ReTranslate, /* rd_recall */
+ NULL, /* rd_mk_vcb */
+ FSYT_ReadMakeDDB, /* rd_mk_ddb */
+ FSYT_ReadMakeFDB, /* rd_mk_fdb */
+ NULL, /* rd_mk_idb */
+ NULL, /* rd_mk_cfdb */
+ NULL, /* rd_mk_bsdb */
+ FSYT_ReadMakeUDB, /* rd_mk_osudb */
+ FSYT_ReadMakeMDB, /* rd_mk_mdb */
+ NULL, /* read stream */
+ NULL, /* wt_mk_vcb */
+ NULL, /* wt_mk_ddb */
+ NULL, /* wt_mk_fdb */
+ NULL, /* Write Stream */
+ NULL, /* End Data */
+ NULL, /* wt_mk_idb */
+ NULL, /* wt_mk_cfdb */
+ NULL, /* Continue Variable Stream */
+ NULL, /* End Variable Stream */
+ NULL, /* Post processing of write buffer */
+ NULL, /* wt_close_tape */
+ NULL, /* wt_cont_set */
+ NULL, /* wt_close_set */
+ NULL, /* wt_eos_pad_blk */
+ NULL, /* load_set_map */
+ NULL, /* load_set_cat */
+ NULL, /* get_next_sm_entry */
+ NULL, /* get_next_sc_entry */
+ NULL /* close_catalogs */
+ },
+#endif
+
+#ifdef SYPL10_TRANS
+ /*
+ * SyTos Plus 1.0 Read
+ */
+ {
+ SYPL_DetermineFormat, /* determiner */
+ SYPL_Initialize, /* initializer */
+ SYPL_DeInitialize, /* deinitializer */
+ NULL, /* VCB buffer reqs */
+ NULL, /* get preferred space */
+ NULL, /* read buffer hook */
+ SYPL_Parse, /* parser */
+ NULL, /* sizeof_tblk */
+ SYPL_RdException, /* exception_action */
+ SYPL_NewTape, /* new_tape, process tape header */
+ NULL, /* post-positioning write init */
+ NULL, /* initialize new tape for write */
+ NULL, /* post-positioning read init */
+ SYPL_MoveToVCB, /* move_to_vcb */
+ NULL, /* seek_eod (for fast append) */
+ SYPL_GetCurrentVCB, /* get_current_vcb */
+ NULL, /* verify_vcb */
+ NULL, /* rd_cont_tape */
+ SYPL_ReTranslate, /* rd_recall */
+ NULL, /* rd_mk_vcb */
+ SYPL_ReadMakeDDB, /* rd_mk_ddb */
+ SYPL_ReadMakeFDB, /* rd_mk_fdb */
+ NULL, /* rd_mk_idb */
+ NULL, /* rd_mk_cfdb */
+ NULL, /* rd_mk_bsdb */
+ NULL, /* rd_mk_osudb */
+ SYPL_ReadMakeMDB, /* rd_mk_mdb */
+ SYPL_ReadMakeStreams, /* rd_mk_streams */
+ NULL, /* wt_mk_vcb */
+ NULL, /* wt_mk_ddb */
+ NULL, /* wt_mk_fdb */
+ NULL, /* Write Stream */
+ NULL, /* End Data */
+ NULL, /* wt_mk_idb */
+ NULL, /* wt_mk_cfdb */
+ NULL, /* Continue Variable Stream */
+ NULL, /* End Variable Stream */
+ NULL, /* Post processing of write buffer */
+ NULL, /* wt_close_tape */
+ NULL, /* wt_cont_set */
+ NULL, /* wt_close_set */
+ NULL, /* wt_eos_pad_blk */
+ NULL, /* load_set_map */
+ NULL, /* load_set_cat */
+ NULL, /* get_next_sm_entry */
+ NULL, /* get_next_sc_entry */
+ NULL /* close_catalogs */
+ },
+#endif
+
+#ifdef UTF_TRANS
+ /*
+ * Universal Tape Format (QicStream 2.0 && FasTape 5.0)
+ */
+ {
+ UTF_Determiner, /* determiner */
+ UTF_Initialize, /* initializer */
+ UTF_DeInitialize, /* deinitializer */
+ NULL, /* VCB buffer reqs */
+ UTF_PreferredSpace, /* get preferred space */
+ UTF_ReadBufferHook, /* read buffer hook */
+ UTF_DetBlkType, /* parser */
+ NULL, /* sizeof_tblk */
+ UTF_RdException, /* exception_action */
+ UTF_NewTape, /* new_tape, process tape header */
+ NULL, /* post-positioning write init */
+ NULL, /* initialize new tape for write */
+ NULL, /* post-positioning read init */
+ UTF_MoveToVCB, /* move_to_vcb */
+ NULL, /* seek_eod (for fast append) */
+ UTF_GetCurrentVCB, /* get_current_vcb */
+ NULL, /* verify_vcb */
+ UTF_RdContTape, /* rd_cont_tape */
+ UTF_ReadRecall, /* rd_recall */
+ NULL, /* rd_mk_vcb */
+ UTF_ReadMakeDDB, /* rd_mk_ddb */
+ UTF_ReadMakeFDB, /* rd_mk_fdb */
+ NULL, /* rd_mk_idb */
+ UTF_ReadMakeCFDB, /* rd_mk_cfdb */
+ NULL, /* rd_mk_bsdb */
+ NULL, /* rd_mk_osudb */
+ NULL, /* rd_mk_mdb */
+ NULL, /* read stream */
+ NULL, /* wt_mk_vcb */
+ NULL, /* wt_mk_ddb */
+ NULL, /* wt_mk_fdb */
+ NULL, /* Write Stream */
+ NULL, /* End Data */
+ NULL, /* wt_mk_idb */
+ NULL, /* wt_mk_cfdb */
+ NULL, /* Continue Variable Stream */
+ NULL, /* End Variable Stream */
+ NULL, /* Post processing of write buffer */
+ NULL, /* wt_close_tape */
+ NULL, /* wt_cont_set */
+ NULL, /* wt_close_set */
+ NULL, /* wt_eos_pad_blk */
+ NULL, /* load_set_map */
+ NULL, /* load_set_cat */
+ NULL, /* get_next_sm_entry */
+ NULL, /* get_next_sc_entry */
+ NULL /* close_catalogs */
+ }
+#endif
+
+} ;
+
diff --git a/private/utils/ntbackup/src/fol_cm.bmp b/private/utils/ntbackup/src/fol_cm.bmp
new file mode 100644
index 000000000..080b07f29
--- /dev/null
+++ b/private/utils/ntbackup/src/fol_cm.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/fol_cn.bmp b/private/utils/ntbackup/src/fol_cn.bmp
new file mode 100644
index 000000000..ac407051a
--- /dev/null
+++ b/private/utils/ntbackup/src/fol_cn.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/fol_cp.bmp b/private/utils/ntbackup/src/fol_cp.bmp
new file mode 100644
index 000000000..26c6c25fe
--- /dev/null
+++ b/private/utils/ntbackup/src/fol_cp.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/fol_ocm.bmp b/private/utils/ntbackup/src/fol_ocm.bmp
new file mode 100644
index 000000000..5ab59aa8c
--- /dev/null
+++ b/private/utils/ntbackup/src/fol_ocm.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/fol_ocn.bmp b/private/utils/ntbackup/src/fol_ocn.bmp
new file mode 100644
index 000000000..bc0187192
--- /dev/null
+++ b/private/utils/ntbackup/src/fol_ocn.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/fol_ocp.bmp b/private/utils/ntbackup/src/fol_ocp.bmp
new file mode 100644
index 000000000..7188f626d
--- /dev/null
+++ b/private/utils/ntbackup/src/fol_ocp.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/fold_om.bmp b/private/utils/ntbackup/src/fold_om.bmp
new file mode 100644
index 000000000..971e711d0
--- /dev/null
+++ b/private/utils/ntbackup/src/fold_om.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/fold_on.bmp b/private/utils/ntbackup/src/fold_on.bmp
new file mode 100644
index 000000000..da53e18cf
--- /dev/null
+++ b/private/utils/ntbackup/src/fold_on.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/fold_op.bmp b/private/utils/ntbackup/src/fold_op.bmp
new file mode 100644
index 000000000..28e341ffe
--- /dev/null
+++ b/private/utils/ntbackup/src/fold_op.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/folder.bmp b/private/utils/ntbackup/src/folder.bmp
new file mode 100644
index 000000000..a104786dc
--- /dev/null
+++ b/private/utils/ntbackup/src/folder.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/folder_m.bmp b/private/utils/ntbackup/src/folder_m.bmp
new file mode 100644
index 000000000..3e982e3b1
--- /dev/null
+++ b/private/utils/ntbackup/src/folder_m.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/folder_p.bmp b/private/utils/ntbackup/src/folder_p.bmp
new file mode 100644
index 000000000..7c1024d9c
--- /dev/null
+++ b/private/utils/ntbackup/src/folder_p.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/font.c b/private/utils/ntbackup/src/font.c
new file mode 100644
index 000000000..e56f5d501
--- /dev/null
+++ b/private/utils/ntbackup/src/font.c
@@ -0,0 +1,282 @@
+
+
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: font.c
+
+ Description: This file contains the functions for UI font change.
+
+ $Log: G:/UI/LOGFILES/FONT.C_V $
+
+ Rev 1.15 04 Nov 1993 15:21:52 STEVEN
+fixes from Wa
+
+ Rev 1.14 15 Jun 1993 11:11:46 MIKEP
+enable c++
+
+ Rev 1.13 27 Apr 1993 20:53:08 MIKEP
+fix typo by glenns block copy
+
+ Rev 1.12 27 Apr 1993 19:08:42 GLENN
+Now telling VLM when ther is a case change.
+
+ Rev 1.11 24 Mar 1993 14:51:48 DARRYLP
+Added fix for Help with Font Viewer, other common dialogs.
+
+ Rev 1.10 24 Mar 1993 10:33:52 DARRYLP
+Changed VIEWFONT to VIEWFONTS to resolve help link.
+
+ Rev 1.9 22 Feb 1993 13:55:40 ROBG
+Added pshhelp to handle the help button.
+
+ Rev 1.8 23 Dec 1992 13:37:54 GLENN
+Added FAT lower case font support.
+
+ Rev 1.7 22 Dec 1992 13:19:54 GLENN
+Placed size limits on font and now using ANSI fonts only.
+
+ Rev 1.6 14 Oct 1992 15:53:28 GLENN
+Added Font selection to Config and INI.
+
+ Rev 1.5 07 Oct 1992 15:12:12 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.4 04 Oct 1992 19:37:28 DAVEV
+Unicode Awk pass
+
+ Rev 1.3 29 Sep 1992 15:12:50 GLENN
+Changed and ifdef from OEM_MSOFT to OS_WIN32.
+
+ Rev 1.2 09 Sep 1992 17:01:22 GLENN
+Updated NEW LOOK font stuff for BIMINI and NT.
+
+ Rev 1.1 04 Sep 1992 17:45:32 GLENN
+Working on changing to support the lower case box.
+
+ Rev 1.0 02 Sep 1992 16:12:54 GLENN
+Initial revision.
+
+******************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+#define IDD_LOWERCASE chx4
+#define IDD_LOWERCASEFAT chx3
+
+static BOOL fLowerCase = FALSE;
+static BOOL fLowerCaseFAT = FALSE;
+
+INT APIENTRY WM_FontDlgHookProc(HWND hDlg, WORD wMsg, WPARAM wParam, LONG lParam);
+
+
+/******************************************************************************
+
+ Name: WM_ChangeFont()
+
+ Description: This allows us to change the MDI font.
+
+ Returns: SUCCESS, if successful. Otherwise, FAILURE.
+
+******************************************************************************/
+
+BOOL WM_ChangeFont ( VOID )
+
+{
+
+ HWND hWndNext;
+ LOGFONT lf;
+ CHOOSEFONT cf;
+ CDS_PTR pCDS = CDS_GetPerm ();
+
+
+ // Set up the existing font information.
+
+ GetObject ( ghFontFiles, sizeof( LOGFONT ), &lf ) ;
+
+ // Canned structure setup.
+
+ memset ( &cf, 0, sizeof(CHOOSEFONT ) );
+
+ cf.lStructSize = sizeof(CHOOSEFONT);
+ cf.hwndOwner = ghWndFrame;
+ cf.lpLogFont = &lf;
+ cf.hInstance = ghResInst;
+ cf.nSizeMin = 4;
+ cf.nSizeMax = 36;
+
+ if (IS_JAPAN() ) {
+ cf.Flags = CF_ENABLEHOOK | CF_ENABLETEMPLATE |
+ CF_SCREENFONTS | CF_SHOWHELP | CF_LIMITSIZE |
+ CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT ;
+ } else {
+
+ cf.Flags = CF_ENABLEHOOK | CF_ENABLETEMPLATE | CF_ANSIONLY |
+ CF_SCREENFONTS | CF_SHOWHELP | CF_LIMITSIZE |
+ CF_FORCEFONTEXIST | CF_INITTOLOGFONTSTRUCT ;
+ }
+
+ cf.rgbColors = RGB( 0, 0, 0 ); // black
+ cf.nFontType = SCREEN_FONTTYPE;
+
+# if !defined ( OS_WIN32 )
+ cf.lpfnHook = MakeProcInstance((FARPROC)WM_FontDlgHookProc, ghInst);
+# else
+ cf.lpfnHook = (LPCFHOOKPROC)MakeProcInstance((FARPROC)WM_FontDlgHookProc, ghInst);
+# endif
+
+ cf.lpTemplateName = ID(IDD_CHOOSEFONT);
+ cf.lCustData = TRUE;
+
+ // Set up the custom data with the upper/lower case setting.
+
+ if ( ChooseFont ( &cf ) ) {
+
+ BOOL fSendVLMChangeMsg = FALSE;
+
+ DeleteObject ( ghFontFiles );
+
+ ghFontFiles = ghFontIconLabels = CreateFontIndirect ( cf.lpLogFont );
+
+ // Save the font, style, size, case in the CDS and INI file.
+
+ if ( strcmp ( (CHAR_PTR)cf.lpLogFont->lfFaceName, (CHAR_PTR)CDS_GetFontFace ( pCDS ) ) ) {
+ CDS_SetFontFace ( pCDS, (CHAR_PTR)cf.lpLogFont->lfFaceName );
+ CDS_WriteFontFace ( pCDS );
+ }
+
+ if ( CDS_GetFontSize ( pCDS ) != ( cf.iPointSize / 10 ) ) {
+ CDS_SetFontSize ( pCDS, ( cf.iPointSize / 10 ) );
+ CDS_WriteFontSize ( pCDS );
+ }
+
+ if ( CDS_GetFontWeight ( pCDS ) != cf.lpLogFont->lfWeight ) {
+ CDS_SetFontWeight ( pCDS, cf.lpLogFont->lfWeight );
+ CDS_WriteFontWeight ( pCDS );
+ }
+
+ if ( CDS_GetFontItalics ( pCDS ) != (BOOL)cf.lpLogFont->lfItalic ) {
+ CDS_SetFontItalics ( pCDS, (BOOL)cf.lpLogFont->lfItalic );
+ CDS_WriteFontItalics ( pCDS );
+ }
+
+ if ( fLowerCase != CDS_GetFontCase ( pCDS ) ) {
+ CDS_SetFontCase ( pCDS, fLowerCase );
+ CDS_WriteFontCase ( pCDS );
+ fSendVLMChangeMsg = TRUE;
+ }
+
+ if ( fLowerCaseFAT != CDS_GetFontCaseFAT ( pCDS ) ) {
+ CDS_SetFontCaseFAT ( pCDS, fLowerCaseFAT );
+ CDS_WriteFontCaseFAT ( pCDS );
+ fSendVLMChangeMsg = TRUE;
+ }
+
+ // If there is a font case change, tell the VLM.
+
+ if ( fSendVLMChangeMsg ) {
+ VLM_ChangeSettings( ID_VIEWFONT, 0L );
+ }
+
+ // Now, invalidate the MDI child docs so that the FONT
+ // change gets displayed.
+
+ hWndNext = WM_GetNext ( (HWND)NULL );
+
+ while ( hWndNext ) {
+
+ DLM_SetFont ( hWndNext );
+
+ // InvalidateRect ( hWndNext, (LPRECT)NULL, TRUE );
+
+ hWndNext = WM_GetNext ( hWndNext );
+ }
+ }
+
+ return SUCCESS;
+
+} /* end WM_ChangeFont() */
+
+
+INT APIENTRY WM_FontDlgHookProc(HWND hDlg, WORD wMsg, WPARAM wParam, LONG lParam)
+{
+ static LPCHOOSEFONT lpcf;
+ static HWND hWndOldCommon;
+ TCHAR str[LF_FULLFACESIZE], sel[LF_FULLFACESIZE];
+ INT index;
+ INT cnt;
+
+ switch ( wMsg ) {
+
+ case WM_INITDIALOG:
+
+ if ( IS_JAPAN() ) {
+ // Remove the Vertical Font Face Name in Font Dialog Box
+ cnt = (INT)SendDlgItemMessage( hDlg, cmb1, CB_GETCOUNT, 0, 0L);
+ index = (INT)SendDlgItemMessage( hDlg, cmb1, CB_GETCURSEL, 0, 0L);
+ SendDlgItemMessage( hDlg, cmb1, CB_GETLBTEXT, index, (DWORD)sel);
+ for (index = 0; index < cnt; ) {
+ SendDlgItemMessage( hDlg, cmb1, CB_GETLBTEXT, index, (DWORD)str);
+ if (str[0] == TEXT('@')) {
+ cnt = (INT)SendDlgItemMessage( hDlg, cmb1, CB_DELETESTRING, index, 0L);
+ }else{
+ index++;
+ }
+ }
+ index = (INT)SendDlgItemMessage(hDlg, cmb1, CB_FINDSTRING, (WPARAM)-1, (DWORD)sel);
+ SendDlgItemMessage(hDlg, cmb1, CB_SETCURSEL, index, 0L);
+ }
+
+ lpcf = (LPCHOOSEFONT)lParam;
+
+ CheckDlgButton(hDlg, IDD_LOWERCASE, (WORD)( CDS_GetFontCase ( CDS_GetPerm () ) ) );
+ CheckDlgButton(hDlg, IDD_LOWERCASEFAT, (WORD)( CDS_GetFontCaseFAT ( CDS_GetPerm () ) ) );
+ hWndOldCommon = ghWndCommonDlg;
+ ghWndCommonDlg = hDlg;
+ break;
+
+ case WM_COMMAND:
+
+ switch (GET_WM_COMMAND_ID(wParam, lParam)) {
+
+ case IDOK:
+
+ fLowerCase = (BOOL)IsDlgButtonChecked (hDlg, IDD_LOWERCASE );
+ fLowerCaseFAT = (BOOL)IsDlgButtonChecked (hDlg, IDD_LOWERCASEFAT );
+
+ return FALSE;
+
+ case pshHelp:
+ case IDHELP:
+
+ HM_DialogHelp( HELPID_VIEWFONTS ) ;
+ return( TRUE ) ;
+
+ default:
+
+ return FALSE;
+
+ }
+ break;
+
+ case WM_DESTROY:
+ ghWndCommonDlg = hWndOldCommon;
+ break;
+
+ default:
+
+ return FALSE;
+
+ }
+
+ return TRUE;
+}
+
+
+
diff --git a/private/utils/ntbackup/src/font.dlg b/private/utils/ntbackup/src/font.dlg
new file mode 100644
index 000000000..b4ee58513
--- /dev/null
+++ b/private/utils/ntbackup/src/font.dlg
@@ -0,0 +1,36 @@
+
+
+IDD_CHOOSEFONT DIALOG 13, 54, 260, 152
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Font"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Font:", stc1, 6, 3, 40, 9
+ COMBOBOX cmb1, 6, 13, 94, 54, CBS_SIMPLE | CBS_AUTOHSCROLL | CBS_SORT | WS_VSCROLL | WS_TABSTOP | CBS_HASSTRINGS | CBS_OWNERDRAWFIXED | CBS_DISABLENOSCROLL
+
+ LTEXT "Font St&yle:", stc2, 108, 3, 44, 9
+ COMBOBOX cmb2, 108, 13, 64, 54, CBS_SIMPLE | WS_VSCROLL | CBS_DISABLENOSCROLL | WS_TABSTOP
+
+ LTEXT "&Size:", stc3, 179, 3, 30, 9
+ COMBOBOX cmb3, 179, 13, 32, 54, CBS_SIMPLE | WS_VSCROLL | WS_TABSTOP | CBS_HASSTRINGS | CBS_OWNERDRAWFIXED | CBS_SORT | CBS_DISABLENOSCROLL
+
+ DEFPUSHBUTTON "OK", IDOK, 218, 6, 40, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "Cancel", IDCANCEL, 218, 23, 40, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "&Apply", psh3, 218, 40, 40, 14, WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "&Help", pshHelp, 218, 57, 40, 14, WS_GROUP | WS_TABSTOP
+
+ GROUPBOX "Effects", grp1, 6, 72, 84, 34, WS_GROUP
+ CONTROL "Stri&keout", chx1, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 10, 82, 49, 10
+ CONTROL "&Underline", chx2, "Button", BS_AUTOCHECKBOX, 10, 94, 51, 10
+
+ LTEXT "&Color:", stc4, 6, 110, 30, 9
+ COMBOBOX cmb4, 6, 120, 84, 100, CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP
+
+ GROUPBOX "Sample", grp2, 6, 72, 252, 49, WS_GROUP
+ CTEXT "", stc6, 98, 124, 160, 20, SS_NOPREFIX | NOT WS_GROUP
+ CTEXT "AaBbYyZz", stc5, 12, 81, 240, 37, SS_NOPREFIX | NOT WS_VISIBLE
+
+ CONTROL "Display &Lowercase for FAT Drives", chx3, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 6, 126, 200, 10
+ CONTROL "Display Lowercase for All &Drives", chx4, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 6, 138, 200, 10
+END
+
diff --git a/private/utils/ntbackup/src/freplace.c b/private/utils/ntbackup/src/freplace.c
new file mode 100644
index 000000000..eb908dbe2
--- /dev/null
+++ b/private/utils/ntbackup/src/freplace.c
@@ -0,0 +1,282 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: FREPLACE.C
+
+ Description: Confirm file replace dialog
+
+ $Log: G:\UI\LOGFILES\FREPLACE.C_V $
+
+ Rev 1.18 28 Jan 1994 17:22:26 Glenn
+Simplified and fixed Icon support.
+
+ Rev 1.17 02 Jun 1993 16:03:56 CARLS
+change code in DisplayDirectory to fix displaying elipsis on long
+directory names
+
+ Rev 1.16 01 Nov 1992 15:58:04 DAVEV
+Unicode changes
+
+ Rev 1.15 07 Oct 1992 13:44:02 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.14 04 Oct 1992 19:37:30 DAVEV
+Unicode Awk pass
+
+ Rev 1.13 28 Jul 1992 14:52:32 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.12 14 May 1992 16:42:30 MIKEP
+nt pass 2
+
+ Rev 1.11 05 Feb 1992 17:05:42 CARLS
+fix for displaying driectory path
+
+ Rev 1.10 27 Jan 1992 12:48:06 GLENN
+Changed dialog support calls.
+
+ Rev 1.9 24 Jan 1992 10:08:50 GLENN
+Changed DM_Filereplace() to DM_FileReplace() to make it consistant with it's prototype.
+
+ Rev 1.8 20 Jan 1992 10:00:10 CARLS
+added a call to DM_CenterDialog
+
+ Rev 1.7 16 Jan 1992 14:39:58 CHUCKB
+Added help.
+
+ Rev 1.6 09 Jan 1992 18:24:58 DAVEV
+16/32 bit port 2nd pass
+
+ Rev 1.5 20 Dec 1991 16:53:56 JOHNWT
+return ghModelessDialog
+
+ Rev 1.4 18 Dec 1991 11:33:00 JOHNWT
+changed ghModelessDialog to ghRuntimeDialog
+
+ Rev 1.3 25 Nov 1991 15:56:04 CARLS
+fixed DisplayDirectory problem - wrong handle used with ReleaseDC call
+
+ Rev 1.2 25 Nov 1991 15:26:20 JOHNWT
+add title to msgbox
+
+ Rev 1.1 25 Nov 1991 15:07:52 DAVEV
+Changes for 32-16 bit Windows port
+
+ Rev 1.0 11 Nov 1991 09:38:48 CARLS
+Initial revision.
+
+
+*****************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+static FILE_REPLACE_TEMP_PTR file_replace_temp_ptr;
+
+/***************************************************
+
+ Name: DM_StartConfirmFileReplace
+
+ Description: Starts the Confirm file replace dialog
+
+ Returns: Returns the status from the dialog.
+
+*****************************************************/
+INT16 DM_StartConfirmFileReplace( FILE_REPLACE_TEMP_PTR temp_ptr )
+{
+
+ file_replace_temp_ptr = temp_ptr;
+ DM_ShowDialog( ghModelessDialog, IDD_FILEREPLACE, NULL );
+
+ return( temp_ptr->dialog_return_status );
+}
+/***************************************************
+
+ Name: DM_FileReplace
+
+ Description: File replace dialog procedure
+
+ Returns:
+
+*****************************************************/
+DLGRESULT APIENTRY DM_FileReplace(
+HWND hDlg , /* window handle of the dialog box */
+MSGID message , /* type of message */
+MP1 mp1 , /* message-specific information */
+MP2 mp2
+)
+{
+ PAINTSTRUCT ps;
+ HDC hDC;
+ HDC hDCBitmap;
+ HWND hWnd;
+ HICON hIcon;
+ WORD answer ;
+
+ UNREFERENCED_PARAMETER ( mp2 );
+
+ switch ( message )
+ {
+ case WM_INITDIALOG: /* message: initialize dialog box */
+
+ DM_CenterDialog( hDlg );
+
+ hIcon = LoadIcon( 0, IDI_EXCLAMATION );
+ SendDlgItemMessage ( hDlg, IDD_FILE_REPLACE_BITMAP, STM_SETICON, (MP1)hIcon, 0L );
+
+ DisplayDirectory( hDlg, file_replace_temp_ptr->line_1, IDD_FILE_REPLACE_LINE1 );
+ SetDlgItemText( hDlg, IDD_FILE_REPLACE_LINE2, file_replace_temp_ptr->line_2 );
+
+ DisplayDirectory( hDlg, file_replace_temp_ptr->line_3, IDD_FILE_REPLACE_LINE3 );
+ SetDlgItemText( hDlg, IDD_FILE_REPLACE_LINE4, file_replace_temp_ptr->line_4 );
+
+ return ( TRUE );
+
+ case WM_COMMAND: /* message: received a command */
+ switch( GET_WM_COMMAND_ID ( mp1, mp2 ) )
+ {
+/****************************************************************************
+ Yes button
+/***************************************************************************/
+ case IDD_FILE_REPLACE_YES:
+ file_replace_temp_ptr->dialog_return_status = FILE_REPLACE_YES_BUTTON;
+ EndDialog( hDlg, FALSE ); /* Exits the dialog box */
+ return ( TRUE );
+ break;
+/****************************************************************************
+ Yes to all button
+/***************************************************************************/
+ case IDD_FILE_REPLACE_ALL:
+ file_replace_temp_ptr->dialog_return_status = FILE_REPLACE_YES_TO_ALL_BUTTON;
+ EndDialog( hDlg, FALSE ); /* Exits the dialog box */
+ return ( TRUE );
+ break;
+/****************************************************************************
+ No button
+/***************************************************************************/
+ case IDD_FILE_REPLACE_NO:
+ file_replace_temp_ptr->dialog_return_status = FILE_REPLACE_NO_BUTTON;
+ EndDialog( hDlg, FALSE ); /* Exits the dialog box */
+ return ( TRUE );
+ break;
+/****************************************************************************
+ Help button
+/***************************************************************************/
+ case IDD_FILE_REPLACE_HELP:
+ HM_DialogHelp( HELPID_DIALOGFILEREPLACE );
+ return( TRUE );
+ break;
+/****************************************************************************
+ Cancel button
+/***************************************************************************/
+ case IDD_FILE_REPLACE_CANCEL:
+ case IDCANCEL:
+
+ /* Ask the user if an abort is really what they want? */
+
+ answer = (WORD)WM_MsgBox( ID( RES_ABORT_STRING ),
+ ID( RES_ABORT_QUESTION ),
+ (WORD)WMMB_YESNO, (WORD)WMMB_ICONQUESTION );
+ if( answer == WMMB_IDYES) {
+
+ yresprintf( (INT16) RES_PROCESS_ABORTED );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ lresprintf( (INT16) LOGGING_FILE ,
+ (INT16) LOG_MSG ,
+ SES_ENG_MSG ,
+ RES_PROCESS_ABORTED );
+
+ file_replace_temp_ptr->dialog_return_status = FILE_REPLACE_CANCEL_BUTTON;
+ EndDialog( hDlg, FALSE ); /* Exits the dialog box */
+
+ }
+ return ( TRUE );
+ break;
+
+ }
+ break;
+ }
+ return ( FALSE ); /* Didn't process a message */
+}
+
+/***************************************************
+
+ Name: DisplayDirectory
+
+ Description:
+
+ Returns:
+
+*****************************************************/
+VOID DisplayDirectory(
+ HWND hDlg,
+ LPSTR buffer_ptr,
+ WORD control_id )
+{
+ CHAR buffer[ FILE_REPLACE_VOLUME_NAME_LEN + MAX_UI_PATH_SIZE ];
+ CHAR_PTR p2;
+ WORD count;
+ HWND hControl;
+ RECT rect;
+ HDC hDC;
+ HDC hDCClient;
+ SIZE sizeRect;
+ WORD width;
+ WORD text_size;
+ WORD length = 60;
+
+ hControl = GetDlgItem( hDlg, control_id );
+ hDC = GetDC( hControl );
+ hDCClient = GetDC( hDlg );
+ GetWindowRect( hControl, &rect );
+ text_size = (WORD)( rect.right - rect.left );
+
+ strcpy( buffer, buffer_ptr );
+ UI_FixPath( buffer, (INT16) length, (CHAR)(TEXT('\\')) );
+ do
+ {
+
+ /* if truncation was added to the string, change the "..."
+ to "WWW" to take up more space in the string to determine
+ the width of the string */
+ p2 = strstr( buffer, UI_TRUNCATION ) ;
+ if( p2 ) {
+ *(p2 + 0 ) = 'W';
+ *(p2 + 1 ) = 'W';
+ *(p2 + 2 ) = 'W';
+ }
+
+ count = (WORD)strlen( buffer );
+ GetTextExtentPoint ( hDCClient, buffer, count, &sizeRect );
+ width = (WORD)sizeRect.cx;
+
+ if( width < text_size )
+ break;
+
+ /* the string is still too big to fit in the dialog control,
+ reduce the length count and try again */
+ length -= 1;
+ strcpy( buffer, buffer_ptr );
+ UI_FixPath( buffer, (INT16) length, (CHAR)(TEXT('\\')) );
+ }
+ while( 1 );
+
+ /* change the "WWW" back to "..." */
+ if( p2 ) {
+ *(p2 + 0 ) = '.';
+ *(p2 + 1 ) = '.';
+ *(p2 + 2 ) = '.';
+ }
+ /* display the string */
+ SetDlgItemText( hDlg, control_id, buffer );
+
+ ReleaseDC( hControl, hDC );
+ ReleaseDC( hDlg, hDCClient );
+
+ strupr ( buffer_ptr );
+}
diff --git a/private/utils/ntbackup/src/frmproc.c b/private/utils/ntbackup/src/frmproc.c
new file mode 100644
index 000000000..b699b238d
--- /dev/null
+++ b/private/utils/ntbackup/src/frmproc.c
@@ -0,0 +1,936 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: frmproc.c
+
+ Description: This file contains the functions for processing messages
+ sent by windows to MDI Frame window. It also contains
+ functions for directly manipulating the windows inside of
+ the frame window.
+
+ The following routines are in this module:
+
+ WM_FrameWndProc
+ WM_FrameUpdate
+ WM_FrameCmdHandler
+ WM_FrameCreate
+ WM_FrameSize
+
+ See Also: wm.c -- the Window Manager (WM) file.
+
+ $Log: G:/UI/LOGFILES/FRMPROC.C_V $
+
+ Rev 1.41.1.1 04 May 1994 14:24:46 STEVEN
+fix shutdown problem
+
+ Rev 1.41.1.0 15 Mar 1994 15:23:36 Glenn
+Added support to relocate frame window if it is not visible within the desktop window. Also restore Icon on RETURN key.
+
+ Rev 1.41 23 Sep 1993 15:52:06 GLENN
+Added signalling to Frame window when out of poll drive, if it was previously busy.
+
+ Rev 1.40 23 Jun 1993 09:16:54 GLENN
+Added code to delay WM_COMMAND messages if we are multitasking from within polldrive.
+
+ Rev 1.39 18 May 1993 20:15:28 GLENN
+1. Fixed MDI close on Maximized doc by placing the MDICLIENT create
+ before the RIBBON create.
+2. Removed unnecessary SC_MOUSEMENU stuff that was just added.
+3. Changed WM_QueryCloseApp() to not terminate if an active operation is
+ being performed.
+
+ Rev 1.38 14 May 1993 16:17:28 GLENN
+Reformatted last code added. Now passing unused WM_COMMAND messages to the currently active child
+.
+
+ Rev 1.37 10 May 1993 18:21:34 GLENN
+Added JS_OkToClose() to the QueryClose function to see if the Runtime Status Dialog was OK to clos
+e.
+
+ Rev 1.36 07 May 1993 14:21:46 DARRYLP
+Added Rob's fixes for Windows double clicks and ID_DELETE key trappings.
+
+ Rev 1.35 22 Apr 1993 16:00:22 GLENN
+Removed the old doc ribbon that was not used.
+
+ Rev 1.34 19 Apr 1993 15:28:24 GLENN
+Now returning global return code in the post quit message.
+
+ Rev 1.33 09 Apr 1993 14:06:30 GLENN
+Added parm to RIB_UpPosition. Beautified code.
+
+ Rev 1.32 15 Mar 1993 15:29:26 ROBG
+Corrected typing error.
+
+ Rev 1.31 15 Mar 1993 14:20:20 ROBG
+Added call in WM_SYSCOMMAND to the help subsystem for OEM_MSOFT.
+
+ Rev 1.30 12 Mar 1993 14:00:50 ROBG
+In NT applications, ignore WM_ERASEBKGND messages to the frame.
+
+ Rev 1.29 02 Mar 1993 15:16:22 ROBG
+Added logic for WIN32 apps when a WM_ACTIVATEAPP message is found.
+If the app is being deactivated, then get the capture off the
+ribbon bar and put the current depressed button in an upright position.
+
+ Rev 1.28 18 Jan 1993 14:26:56 GLENN
+Clean up.
+
+ Rev 1.27 18 Nov 1992 11:40:02 GLENN
+Added ability to move the modeless dialog when the frame is moved.
+
+ Rev 1.26 14 Oct 1992 15:57:36 GLENN
+Added some.h
+
+ Rev 1.25 04 Oct 1992 19:37:34 DAVEV
+Unicode Awk pass
+
+ Rev 1.24 02 Oct 1992 16:46:58 GLENN
+Got rid of goto's and fixed wait cursor - set cursor stuff.
+
+ Rev 1.23 03 Aug 1992 16:41:32 CHUCKB
+Ifdef call to schedule function.
+
+ Rev 1.22 15 May 1992 13:32:08 MIKEP
+nt pass 2
+
+ Rev 1.21 23 Apr 1992 14:37:10 ROBG
+Added last menu ID and state in call to HM_EnterIdle.
+
+ Rev 1.20 22 Apr 1992 17:22:30 GLENN
+Added mwwLastMenuID for Menu Help.
+
+ Rev 1.19 20 Apr 1992 13:55:32 GLENN
+Removed register declarations.
+
+ Rev 1.18 15 Apr 1992 16:45:08 GLENN
+Added MM_ShowMenuStatusHelp() call to show status help only for valid menu IDs.
+
+ Rev 1.17 07 Apr 1992 10:38:00 GLENN
+Added a call back to the MUI when there is a system change. (future)
+
+ Rev 1.16 03 Apr 1992 15:04:08 JOHNWT
+removed YY set in query close
+
+ Rev 1.15 19 Mar 1992 11:43:38 JOHNWT
+fixed QUERYENDSESSION
+
+ Rev 1.14 17 Mar 1992 18:25:40 GLENN
+Took out changes put in for the runtime focus problem.
+
+ Rev 1.13 10 Mar 1992 17:01:46 GLENN
+Changed paint.
+
+ Rev 1.12 03 Mar 1992 09:44:10 DAVEV
+Changes for Nostradamus unique features (OEM_MSOFT)
+
+ Rev 1.11 23 Feb 1992 14:09:42 GLENN
+Fixed abort/cancel case of QueryCloseApp.
+
+ Rev 1.10 18 Feb 1992 18:34:32 GLENN
+Reset YY flag if user cancelled the abort.
+
+ Rev 1.9 11 Feb 1992 17:30:02 GLENN
+Added support for MDI client subclassing.
+
+ Rev 1.8 05 Feb 1992 17:41:14 GLENN
+Fixed deinit problem for runtime jobs.
+
+ Rev 1.7 27 Jan 1992 12:46:08 GLENN
+Changed dialog support calls.
+
+ Rev 1.6 16 Jan 1992 09:47:26 ROBG
+Added SCH_PublishRunningJob call to the message WM_QUERYRUNNINGJOB.
+
+ Rev 1.5 26 Dec 1991 13:46:46 GLENN
+Changed show flags to use CDS calls
+
+ Rev 1.4 11 Dec 1991 14:53:56 DAVEV
+16/32 bit port - 2nd pass
+
+ Rev 1.3 10 Dec 1991 13:39:08 GLENN
+Added dynamic ribbon height support
+
+ Rev 1.2 04 Dec 1991 18:35:34 GLENN
+Updated for ALT-F4 termination
+
+ Rev 1.1 02 Dec 1991 17:49:56 DAVEV
+16/32 bit Windows port changes
+
+ Rev 1.0 20 Nov 1991 19:33:44 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+// PRIVATE MODULE-WIDE VARIABLES
+
+static WORD mwwLastMenuID;
+static WORD mwwLastMenuState;
+
+// PRIVATE FUNCTION HEADERS
+
+VOID WM_FrameCmdHandler ( HWND, MP1, MP2 );
+VOID WM_FrameCreate ( HWND );
+VOID WM_FrameSize ( VOID );
+BOOL WM_QueryCloseApp ( VOID );
+
+/******************************************************************************
+
+ Name: WM_FrameWndProc()
+
+ Description: This function is called internally by Windows. Windows
+ calls this function when messages related to the FRAME
+ window must be processed.
+
+ Returns: NULL or a default message handler's return code.
+
+******************************************************************************/
+
+WINRESULT APIENTRY WM_FrameWndProc (
+
+HWND hWnd, // I - Destination window handle
+MSGID msg, // I - message
+MP1 mp1, // I - parameter 1
+MP2 mp2 ) // I - parameter 2
+
+{
+
+ switch ( msg ) {
+
+# if defined ( OS_WIN32 )
+
+ case WM_ACTIVATEAPP: {
+
+ // If the application is being deactivated and
+ // a button is currently being held down by the mouse,
+ // put the ribbon button in the up position.
+
+ BOOL fActivated = (BOOL) mp1;
+
+ if ( ! fActivated ) {
+
+ if ( IsWindow ( WM_GetActiveDoc () ) ) {
+ RIB_UpPosition ( ghRibbonMain );
+ }
+ }
+
+ break;
+
+ }
+
+# endif /* OS_WIN32 */
+
+# if defined (OS_WIN32 )
+
+ // There appears to be a problem with NT. Any time a user
+ // moves a window from left to right over our app, an
+ // extra WM_ERASEBKGND gets sent to our frame after we
+ // paint our status bar. Use SPY and you will see this
+ // WM_ERASEBKGND. Make sure you scroll the NT SPY window
+ // down all the way.
+
+ // Since the status bar is the only portion of the frame
+ // we paint, we can ignore any WM_ERASEBKBND to the frame.
+
+ case WM_ERASEBKGND:
+
+ return 0;
+
+# endif /* OS_WIN32 */
+
+
+ case WM_CREATE:
+
+ WM_FrameCreate ( hWnd );
+ return 0;
+
+ case WM_MOVE:
+
+ if ( ! IsIconic ( ghWndFrame ) ) {
+
+ RECT rcIntersect;
+ RECT rcDesktop;
+ RECT rcWnd;
+
+ // For desktop window compliance.
+
+ GetWindowRect ( GetDesktopWindow (), &rcDesktop );
+ GetWindowRect ( hWnd, &rcWnd );
+
+ if ( ! IntersectRect ( &rcIntersect, &rcDesktop, &rcWnd ) ) {
+
+ DM_CenterDialog( hWnd );
+ }
+ }
+
+ break;
+
+ case WM_INITMENU:
+
+ // Set up the menu state.
+
+ MM_Init ( (HMENU)mp1 );
+
+ // If in Help-Context-Sensitive mode,
+ // then set cursor to Help cursor.
+
+ HM_InitMenu();
+
+ return 0;
+
+ case WM_WININICHANGE:
+ case WM_DEVMODECHANGE:
+
+ // Change the pens, brushes, and fonts to the newly selected colors.
+ // then update the frame, which will in effect, update all MDI
+ // Documents.
+
+ WM_DeleteObjects ();
+ WM_CreateObjects ();
+ UI_InitIntl ();
+ MUI_UISystemChange ();
+ WM_Update( hWnd );
+
+ return 0;
+
+ case WM_COMMAND:
+
+ // If the user is in the help context-sensitive mode,
+ // process the help associated with a menu selection.
+
+ if ( ! HM_WMCommandProcessing( hWnd, GET_WM_COMMAND_ID ( mp1, mp2 ) ) ) {
+
+ // Direct all menu selection or accelerator commands to the frame
+ // command handler function.
+
+ WM_FrameCmdHandler ( hWnd, mp1, mp2 );
+ }
+
+ return 0;
+
+ case WM_ENTERIDLE :
+
+ // If F1 is pressed while a menu item has been selected,
+ // then the help system is activated.
+
+ if ( HM_EnterIdle( hWnd, mp1, mwwLastMenuID, mwwLastMenuState ) ) {
+ return 0;
+ }
+
+ break;
+
+ case WM_INITAPPLICATION:
+
+ // Allow the GUI to fully initialize by multitasking for a moment.
+
+ WM_MultiTask ();
+
+ // Remove the WAIT cursor and release capture of all mouse messages
+ // from the frame window. Its complement is in WM_Init() after the
+ // frame window is created.
+
+ WM_ShowWaitCursor ( FALSE );
+
+ // GUI initialization is complete, ready to initialize the MUI.
+
+ if ( MUI_Init () ) {
+
+ // Exit the app if there was a command line job or there was
+ // an initialization error.
+
+# if defined ( OEM_MSOFT ) // OEM Microsoft special feature
+ {
+ PostMessage ( hWnd, WM_COMMAND, IDM_OPERATIONSEXIT, 0L );
+ }
+# else
+ {
+ if ( !gfTerminateApp ) {
+ PostMessage ( hWnd, WM_COMMAND, IDM_FILEEXIT, 0L );
+ }
+ }
+# endif // defined ( OEM_MSOFT ) // special feature
+ }
+
+ gfAppInitialized = TRUE;
+ return 0;
+
+ case WM_SETTINGSCHANGED:
+
+ // This is the way to delay the calling of a function from a dialog.
+
+ VLM_ChangeSettings ( (INT16)mp1, (INT32)mp2 );
+ return 0;
+
+ case WM_MENUSELECT:
+
+ // Display the menu help on the status line.
+
+ if ( MM_IS_MENU_CLOSED ( mp1, mp2 ) ) {
+
+ STM_SetIdleText ( IDS_READY );
+
+ }
+ else {
+
+ // Save the last menu select ID for help.
+
+ mwwLastMenuID = GET_WM_MENUSELECT_ID ( mp1, mp2 );
+ mwwLastMenuState = GET_WM_MENUSELECT_FLAGS( mp1, mp2 );
+
+ MM_ShowMenuStatusHelp ( mwwLastMenuID );
+ }
+
+ return 0;
+
+ case WM_SIZE:
+
+ if ( mp1 != SIZEICONIC ) {
+
+ gRectFrameClient.right = LOWORD(mp2);
+ gRectFrameClient.bottom = HIWORD(mp2);
+
+ WM_FrameSize ();
+ }
+
+ return 0;
+
+ case WM_PAINT:
+
+ if ( ! IsIconic ( hWnd ) ) {
+
+ // Take care of the status line.
+
+ STM_DrawBorder ();
+ STM_DrawIdle ();
+
+ }
+
+ // Continue to the default to validate any invalid rectangles.
+
+ break;
+
+ case WM_LBUTTONDOWN:
+
+ if ( HM_ContextLbuttonDown ( hWnd, mp1, mp2 ) ) {
+ return 0;
+ }
+
+ break;
+
+ case WM_KEYDOWN:
+
+ if ( HM_KeyDown ( hWnd, mp1 ) ) {
+ return 0;
+ }
+
+ break;
+
+ case WM_SETCURSOR:
+
+ // In help mode it is necessary to reset the cursor in response
+ // to every WM_SETCURSOR message.Otherwise, by default, Windows
+ // will reset the cursor to that of the window class.
+
+ if ( HM_SetCursor ( hWnd ) ) {
+ return 0;
+ }
+
+ if ( WM_SetCursor ( hWnd ) ) {
+ return 1;
+ }
+
+ break;
+
+#ifndef OEM_MSOFT
+ case WM_QUERYRUNNINGJOB:
+
+ // Publish the running job to the launcher.
+
+ SCH_PublishRunningJob();
+
+ return 0;
+
+#endif /* OEM_MSOFT */
+
+ case WM_QUERYENDSESSION:
+
+ // Don't end the session if any Docs cancel the operation or if
+ // there is a Runtime Dialog that doesn't want to quit.
+
+ return WM_QueryCloseApp ();
+
+ case WM_WINDOWPOSCHANGING:
+
+ if ( ghModelessDialog ) {
+
+ LPWINDOWPOS pdsNewPos = (LPWINDOWPOS)mp2;
+ RECT rcOldFrame;
+ RECT rcRuntime;
+ INT x;
+ INT y;
+
+ GetWindowRect ( ghWndFrame, &rcOldFrame );
+ GetWindowRect ( ghModelessDialog, &rcRuntime );
+
+ if ( ! ( pdsNewPos->flags & SWP_NOMOVE ) ) {
+
+ // Move the runtime window with the frame, but not
+ // vice versa.
+
+ x = rcRuntime.left + ( pdsNewPos->x - rcOldFrame.left );
+ y = rcRuntime.top + ( pdsNewPos->y - rcOldFrame.top );
+
+ SetWindowPos ( ghModelessDialog,
+ (HWND)NULL,
+ x,
+ y,
+ 0,
+ 0,
+ ( SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE )
+ );
+ }
+
+ }
+
+ break;
+
+ case WM_ENDSESSION:
+
+ if ( mp1 ) {
+
+ MUI_Deinit ();
+ }
+
+ return 0;
+
+ case WM_POLLDRIVEMSG:
+
+ if ( mp1 == (MP1)0 && gfTerminateApp && WM_QueryCloseApp () ) {
+
+ MUI_Deinit ();
+ DestroyWindow ( hWnd );
+ }
+
+ return 0;
+
+ case WM_CLOSE:
+
+ if ( WM_QueryCloseApp () ) {
+
+ MUI_Deinit ();
+ DestroyWindow ( hWnd );
+ }
+
+ return 0;
+
+ case WM_DESTROY:
+
+ PostQuitMessage ( gnReturnCode );
+ return 0;
+
+ case WM_SYSCOMMAND:
+
+# if defined ( OEM_MSOFT )
+
+ // If the user is in the help context-sensitive mode,
+ // process the help associated with a menu selection.
+
+ if ( HM_WMCommandProcessing( hWnd, GET_WM_COMMAND_ID ( mp1, mp2 ) ) ) {
+ return 0 ;
+ }
+
+# endif
+
+ switch ( mp1 ) {
+
+ case SC_MAXIMIZE:
+ case SC_RESTORE: {
+
+ HWND hWndTop;
+
+ // Take care of activating the proper window.
+
+ if ( ghModelessDialog ) {
+ hWndTop = GetLastActivePopup ( ghModelessDialog );
+ }
+ else {
+ hWndTop = GetLastActivePopup ( ghWndFrame );
+ }
+
+ SetActiveWindow ( hWndTop );
+
+ break;
+ }
+
+
+ } /* end switch */
+
+ break;
+
+ default:
+
+ break;
+
+ }
+
+ // Use DefFrameProc() instead of DefWindowProc() since there
+ // are things that have to be handled differently because of MDI.
+
+ return DefFrameProc ( hWnd, ghWndMDIClient, msg, mp1, mp2 );
+
+} /* end WM_FrameWndProc() */
+
+
+/******************************************************************************
+
+ Name: WM_FrameCmdHandler()
+
+ Description: This function is called by WM_FrameWndProc to handle
+ command specific messages such as MENU SELECTION messages.
+
+ Returns: NULL or a default message handler's return code.
+
+******************************************************************************/
+
+VOID WM_FrameCmdHandler (
+
+HWND hWnd, // I - Destination window handle
+MP1 mp1, // I - message parameter
+MP2 mp2 )
+
+{
+ WORD wId = GET_WM_COMMAND_ID ( mp1, mp2 );
+
+ // If we are being called from polldrive's multitask call, repost
+ // the message cause this is dangerous in some re-entrancy cases.
+
+ if ( PD_IsPollDriveBusy () ) {
+ PostMessage ( hWnd, WM_COMMAND, mp1, mp2 );
+ return;
+ }
+
+ // Pass the message on the menu command handler. If it is not a menu
+ // item, see if it is a dialog. If it is not a dialog, pass it to the
+ // default frame proc.
+
+ if ( ! MM_MenuCmdHandler ( hWnd, wId ) ) {
+
+ HWND hWndChild = WM_GetActiveDoc ();
+
+ // Pass to active child.
+
+ if ( IsWindow ( hWndChild ) ) {
+ SendMessage ( hWndChild, WM_COMMAND, mp1, mp2 );
+ }
+
+ // This is essential, since there are frame WM_COMMANDS generated
+ // by the MDI system for activating child windows via the
+ // window menu.
+
+ DefFrameProc( hWnd, ghWndMDIClient, WM_COMMAND, mp1, mp2 );
+
+ }
+
+} /* end WM_FrameCmdHandler() */
+
+
+/******************************************************************************
+
+ Name: WM_FrameCreate()
+
+ Description: This function is called by WM_FrameWndProc as part of the
+ frame window creation so that other frame dependent
+ functions, such as creation and initialization of child
+ windows, can be done.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID WM_FrameCreate (
+
+HWND hWnd // I - Destination window handle
+)
+{
+ // Set the global frame handle.
+
+ ghWndFrame = hWnd;
+
+ // Initialize the client area rectangle.
+
+ GetClientRect ( hWnd, &gRectFrameClient );
+
+ // Create the MAIN ribbon, DOC ribbon, and MDI client windows.
+
+ ghWndMDIClient = WM_Create ( WM_CLIENT, NULL, NULL, 0, 0, 0, 0, NULL );
+ ghWndMainRibbon = WM_Create ( WM_RIBBON, NULL, NULL, 0, 0, 0, 0, (PDS_WMINFO)(DWORD)ghWndFrame );
+
+ WM_Show( ghWndMDIClient );
+
+} /* end WM_FrameCreate() */
+
+
+/******************************************************************************
+
+ Name: WM_FrameSize()
+
+ Description: This function is called by WM_FrameWndProc as part of the
+ frame window sizing function. Upon receiving this message,
+ the ribbon, status line, and MDI client are resized to fit
+ the new frame size, depending on whether they are shown.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID WM_FrameSize ( VOID )
+
+{
+ INT nClientTop = 0;
+ INT nClientBottom = gRectFrameClient.bottom;
+ CDS_PTR pCDS = CDS_GetPerm();
+
+ if ( IsWindowVisible ( ghWndMainRibbon ) && ! CDS_GetShowMainRibbon ( pCDS ) ) {
+ WM_Hide ( ghWndMainRibbon );
+ }
+
+ if ( CDS_GetShowMainRibbon ( pCDS ) ) {
+ nClientTop = gnMainRibbonHeight;
+ }
+
+ if ( CDS_GetShowStatusLine ( pCDS ) ) {
+ nClientBottom -= STATUS_LINE_HEIGHT;
+ }
+
+ // Resize the MDI client window.
+
+ MoveWindow ( ghWndMDIClient,
+ 0,
+ nClientTop,
+ gRectFrameClient.right,
+ nClientBottom - nClientTop,
+ TRUE
+ );
+
+ if ( CDS_GetShowMainRibbon ( pCDS ) ) {
+
+ // Resize the MAIN Ribbon window.
+
+ MoveWindow ( ghWndMainRibbon,
+ 0,
+ 0,
+ gRectFrameClient.right,
+ nClientTop,
+ TRUE
+ );
+
+ if ( ! IsWindowVisible ( ghWndMainRibbon ) ) {
+ WM_Show ( ghWndMainRibbon );
+ }
+ }
+
+ WM_MultiTask ();
+
+ // Rearrange the MDI Document icons, if any.
+
+ PostMessage ( ghWndMDIClient, WM_MDIICONARRANGE, 0, 0L );
+
+ // Now, show the Runtime Dialog if there is one.
+
+ if ( ghModelessDialog ) {
+
+ if ( ! IsWindowVisible ( ghModelessDialog ) ) {
+ ShowWindow ( ghModelessDialog, SW_SHOWNORMAL );
+ }
+
+ SetActiveWindow ( ghModelessDialog );
+ }
+
+} /* end WM_FrameSize() */
+
+
+/******************************************************************************
+
+ Name: WM_FrameUpdate()
+
+ Description: This function is called whenever the user has changed a
+ preference showing or hiding the ribbon or status line.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID WM_FrameUpdate ( VOID )
+
+{
+ WM_FrameSize ();
+ InvalidateRect ( ghWndFrame, NULL, FALSE );
+
+} /* end WM_FrameUpdate() */
+
+
+/******************************************************************************
+
+ Name: WM_MDIClientWndProc()
+
+ Description: This function is a SUB-CLASS function of LIST BOXES for
+ the GUI MDI documents. It is called internally by Windows.
+ Windows calls this function when list box messages must be
+ processed. Windows will only call this routine for
+ MDI documents in this application.
+
+ Returns: NULL or a default message handler's return code.
+
+******************************************************************************/
+
+WINRESULT APIENTRY WM_MDIClientWndProc (
+
+HWND hWnd, // I - window handle of the list box
+MSGID msg, // I - message
+MP1 mp1, // I - another message parameter
+MP2 mp2 ) // I - yet another message parameter
+
+{
+ switch ( msg ) {
+
+ case WM_KEYDOWN: {
+
+ PDS_WMINFO pdsWinInfo;
+ HWND hWndList;
+
+ if ( ! IsWindow ( WM_GetActiveDoc () ) ) {
+ break;
+ }
+
+ if ( LOWORD ( mp1 ) == VK_RETURN && IsIconic ( WM_GetActiveDoc () ) ) {
+
+ WM_RestoreDoc ( WM_GetActiveDoc () );
+ return 0;
+ }
+
+ pdsWinInfo = WM_GetInfoPtr ( WM_GetActiveDoc () );
+
+ if ( ! pdsWinInfo ) {
+ break;
+ }
+
+ hWndList = WMDS_GetWinActiveList ( pdsWinInfo );
+
+ // Pass the key to the Ribbon Window(s).
+ // Note: the key will not be passed to the next function if the
+ // previous function used it.
+
+ if ( hWndList &&
+ ( HM_KeyDown ( hWndList, mp1 ) ||
+ RIB_KeyDown ( ghWndMainRibbon, RIB_KEYBOARD, mp1, mp2 ) ||
+ WM_DocKeyDown ( hWndList, LOWORD ( mp1 ) )
+ )
+ ) {
+
+ return 1;
+ }
+
+ break;
+ }
+
+ case WM_KEYUP: {
+
+ PDS_WMINFO pdsWinInfo;
+ HWND hWndList;
+
+ if ( ! IsWindow ( WM_GetActiveDoc () ) ) {
+ break;
+ }
+
+ pdsWinInfo = WM_GetInfoPtr ( WM_GetActiveDoc () );
+
+ if ( ! pdsWinInfo ) {
+ break;
+ }
+
+ hWndList = WMDS_GetWinActiveList ( pdsWinInfo );
+
+ // Pass the key to the Ribbon Window(s).
+ // Note: the key will not be passed to the next function if the
+ // previous function used it.
+
+ if ( hWndList && RIB_KeyUp ( ghWndMainRibbon, RIB_KEYBOARD, mp1, mp2 ) ) {
+
+ return 1;
+ }
+
+ break;
+ }
+
+ case WM_DESTROY:
+
+ ghWndMDIClient = (HWND) NULL;
+
+ break;
+
+ } /* end switch () */
+
+ return CallWindowProc ( (VOID *)glpfnOldMDIClientProc, hWnd, msg, mp1, mp2 );
+
+} /* end WM_MDIClientWndProc() */
+
+
+/******************************************************************************
+
+ Name: WM_QueryCloseApp()
+
+ Description: This function is called whenever the app is told to close.
+
+ Returns: TRUE, if OK to close, otherwise FALSE.
+
+******************************************************************************/
+
+BOOL WM_QueryCloseApp ( VOID )
+
+{
+ BOOL fResult;
+
+ gfTerminateApp = TRUE;
+
+ // If there is a RUN TIME STATUS DIALOG. Kill it off by sending it
+ // an abort.
+
+ if ( ghModelessDialog ) {
+
+ BOOL fCanCloseRuntime = JS_OkToClose ();
+
+ // If we cannot immediately close, don't terminate the app.
+
+ if ( ! fCanCloseRuntime ) {
+ gfTerminateApp = FALSE;
+ }
+
+ // Make sure we are displayed
+
+ WM_MakeAppActive( );
+
+ SendMessage ( ghModelessDialog, (MSGID)WM_COMMAND, (MPARAM1)IDCANCEL, (MPARAM2)NULL );
+
+ fResult = fCanCloseRuntime;
+ }
+ else if ( PD_IsPollDriveBusy () || gfOperation ) {
+
+// fResult = FALSE;
+ fResult = WM_QueryCloseAllDocs ();
+ }
+ else {
+
+ fResult = WM_QueryCloseAllDocs ();
+ }
+
+ return fResult;
+
+} /* end WM_QueryCloseApp() */
diff --git a/private/utils/ntbackup/src/fsecopy.c b/private/utils/ntbackup/src/fsecopy.c
new file mode 100644
index 000000000..555f9a916
--- /dev/null
+++ b/private/utils/ntbackup/src/fsecopy.c
@@ -0,0 +1,129 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: fsecopy.c
+
+ Description: This file contains code careate&copy an fse
+
+ $Log: M:/LOGFILES/FSECOPY.C_V $
+
+ Rev 1.4 16 Dec 1993 10:20:16 BARRY
+Change INT8_PTRs to VOID_PTRs
+
+ Rev 1.3 18 Jun 1993 09:08:26 MIKEP
+enable C++
+
+ Rev 1.2 09 Oct 1992 11:44:10 DAVEV
+Unicode (CHAR_PTR) pointer cast validation
+
+ Rev 1.1 14 May 1992 11:48:08 TIMN
+Changed CHARs to INT8\nstrcpy to memcpy
+
+ Rev 1.0 29 May 1991 17:11:34 STEVEN
+Initial revision.
+
+**/
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "msassert.h"
+
+#include "std_err.h"
+#include "queues.h"
+
+#include "bsdu.h"
+
+/**/
+/**
+
+ Name: FSE_Copy()
+
+ Description: This function allocates memory for an FSE. It then
+ initializes the allocated memory with the data in the provided FSE.
+
+ Modified: 5/29/1991 15:10:15
+
+ Returns: Error codes:
+ OUT_OF_MEMORY
+ SUCCESS
+
+ Notes:
+
+ See also: $/SEE( BSD_AddFSE(), FSE_SetComplexInfo() )$
+
+ Declaration:
+
+**/
+INT16 FSE_Copy(
+FSE_PTR fse, /* I - FSE to copy infor from */
+FSE_PTR *new_fse ) /* O - The newly created FSE */
+{
+ INT16 ret_val = SUCCESS ;
+ FSE_COMPLEX_PTR cplx ;
+ FSE_TGT_INFO_PTR tgt ;
+
+ msassert( new_fse != NULL );
+ msassert( fse != NULL );
+
+ cplx = fse->cplx ;
+ tgt = fse->tgt ;
+
+ *new_fse = (FSE_PTR)calloc( 1, sizeof( *fse ) + fse->dir_leng + fse->fname_leng );
+
+ if ( *new_fse != NULL ) {
+
+ (*new_fse)->flgs = fse->flgs ;
+ (*new_fse)->dir_leng = fse->dir_leng ;
+ (*new_fse)->dir = *new_fse + 1;
+ (*new_fse)->fname_leng = fse->fname_leng;
+ (*new_fse)->fname = (BYTE_PTR)(*new_fse)->dir + fse->dir_leng;
+ memcpy( (*new_fse)->dir, fse->dir, fse->dir_leng ) ;
+ memcpy( (*new_fse)->fname, fse->fname, fse->fname_leng ) ;
+
+ if ( cplx != NULL ) {
+
+ if ( ( FSE_SetAccDate( *new_fse, cplx->access_date ) != SUCCESS ) ||
+ ( FSE_SetBakDate( *new_fse, cplx->backup_date ) != SUCCESS ) ||
+ ( FSE_SetModDate( *new_fse, cplx->pre_m_date,
+ cplx->post_m_date ) != SUCCESS ) ||
+ ( FSE_SetAttribInfo( *new_fse, cplx->attr_on_mask,
+ cplx->attr_off_mask ) != SUCCESS ) ) {
+
+
+ if ( (*new_fse)->cplx != NULL ) {
+ free( (*new_fse)->cplx->pre_m_date ) ;
+ free( (*new_fse)->cplx->post_m_date ) ;
+ free( (*new_fse)->cplx->backup_date ) ;
+ free( (*new_fse)->cplx->access_date ) ;
+ free( (*new_fse)->cplx ) ;
+ }
+
+ ret_val = OUT_OF_MEMORY ;
+ }
+ }
+
+ if ( tgt != NULL ) {
+ if ( FSE_SetTargetInfo( *new_fse, tgt->path, tgt->psize, tgt->fname, tgt->fnsize ) != SUCCESS ) {
+
+ if ( (*new_fse)->tgt != NULL ) {
+ free( (*new_fse)->tgt ) ;
+ }
+
+ ret_val = OUT_OF_MEMORY ;
+ }
+ }
+
+ if ( ret_val != SUCCESS ) {
+ free( *new_fse ) ;
+ *new_fse = NULL ;
+ }
+ } else {
+ ret_val = OUT_OF_MEMORY ;
+ }
+
+ return ret_val ;
+}
+
diff --git a/private/utils/ntbackup/src/func_tab.c b/private/utils/ntbackup/src/func_tab.c
new file mode 100644
index 000000000..97a824913
--- /dev/null
+++ b/private/utils/ntbackup/src/func_tab.c
@@ -0,0 +1,25 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: func_tab.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains memory allocation for the
+ function table.
+
+
+ $Log: G:/LOGFILES/FUNC_TAB.C_V $
+
+ Rev 1.0 09 May 1991 13:35:02 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include "stdtypes.h"
+
+#include "fsys.h"
+/* $end$ include list */
+
+FUNC_LIST func_tab[ MAX_DRV_TYPES ] = {NULL} ;
diff --git a/private/utils/ntbackup/src/gen_tab.c b/private/utils/ntbackup/src/gen_tab.c
new file mode 100644
index 000000000..69edad7b9
--- /dev/null
+++ b/private/utils/ntbackup/src/gen_tab.c
@@ -0,0 +1,137 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: dos_tab.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains the DOS functon table.
+
+
+ $Log: L:/LOGFILES/GEN_TAB.C_V $
+
+ Rev 1.7 30 Jul 1993 13:18:22 STEVEN
+if dir too deep make new one
+
+ Rev 1.6 22 Sep 1992 17:21:56 CHUCKB
+Removed table entry for GetTotalSizeDBLK.
+
+ Rev 1.5 17 Mar 1992 09:05:34 STEVEN
+format 40 - added 64 bit support
+
+ Rev 1.4 03 Mar 1992 16:15:50 STEVEN
+added functions for long paths
+
+ Rev 1.3 16 Dec 1991 17:20:58 STEVEN
+move common functions to tables
+
+ Rev 1.2 27 Nov 1991 11:15:24 BARRY
+GEN table wrong.
+
+ Rev 1.1 14 Aug 1991 12:59:20 STEVEN
+added FindClose
+
+ Rev 1.0 09 May 1991 13:33:42 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include "stdtypes.h"
+#include "FSYS.H"
+#include "fsys_prv.h"
+#include "gen_fs.h"
+/* $end$ include list */
+
+FUNC_LIST GENFuncTab = {
+
+ GEN_InitFileSys,
+ GEN_FindDrives,
+ GEN_RemoveDLE,
+ GEN_DeInitFileSys,
+
+ GEN_DeviceDispName,
+ GEN_GetVolName,
+ GEN_SizeofVolName,
+ GEN_MakePath,
+ GEN_InitMakeData,
+
+ GEN_IsBlkComplete,
+ GEN_CompleteBlk,
+ GEN_DupBlk,
+ GEN_ReleaseBlk,
+
+ NULL, /* GEN_AttachToDLE, */
+ NULL, /* GEN_DetachDLE, */
+ NULL, /* GEN_EndOperationOnDLE */
+
+ GEN_ProcessDDB,
+ NULL, /* GEN_GetCurrentDDB, */
+ NULL, /* GEN_GetCurrentPath, */
+ NULL,
+ GEN_SizeofOSPath,
+ NULL, /* GEN_GetBasePath, */
+ NULL, /* GEN_ChangeDir, */
+ NULL, /* GEN_UpDir, */
+
+ NULL, /* GEN_CreateObj, */
+ NULL, /* GEN_OpenObj, */
+ NULL, /* GEN_SeekObj, */
+ NULL, /* GEN_ReadObj, */
+ NULL, /* GEN_WriteObj, */
+ NULL, /* GEN_VerObj, */
+ NULL, /* GEN_CloseObj, */
+ NULL, /* GEN_DeleteObj, */
+
+ NULL, /* GEN_GetObjInfo, */
+ NULL, /* GEN_SetObjInfo, */
+ NULL, /* GEN_VerObjInfo, */
+
+ NULL, /* GEN_FindFirst, */
+ NULL, /* GEN_FindNext, */
+ NULL, /* GEN_PushMinDDB, */
+ NULL, /* GEN_PopMinDDB, */
+ NULL, /* GEN_GetSpecDBLKS,*/
+ NULL, /* GEN_EnumSpecFiles,*/
+
+ NULL, /* GEN_ModFnameFDB, */
+ NULL, /* GEN_ModPathDDB, */
+ GEN_GetOSFnameFDB,
+ GEN_GetPartName,
+ GEN_GetOSPathDDB,
+ GEN_GetCdateDBLK,
+ GEN_GetMdateDBLK,
+ GEN_ModBdateDBLK,
+ GEN_ModAdateDBLK,
+ GEN_GetDisplaySizeDBLK,
+// GEN_GetTotalSizeDBLK,
+ GEN_ModAttribDBLK,
+ GEN_GetFileVerFDB,
+ GEN_SetOwnerId,
+
+ GEN_GetObjTypeDBLK,
+
+ NULL, /* GEN_SizeofFname, */
+ NULL, /* GEN_SizeofPath, */
+ GEN_SizeofOSFname,
+ GEN_SizeofPartName,
+ GEN_SizeofOSPath,
+
+ NULL, /* GEN_SizeofOSInfo, */
+
+ NULL, /* GEN_GetOS_InfoDBLK, */
+ GEN_GetActualSizeDBLK,
+
+ DUMMY_InitGOS,
+
+ GEN_CreateFDB,
+ GEN_CreateIDB,
+ GEN_CreateDDB,
+ NULL, /* GEN_ChangeIntoDDB, */
+ GEN_SpecExcludeObj,
+ GEN_SetDataSize,
+ GEN_SetObjTypeDBLK,
+ NULL, /* LogoutDevice */
+ GEN_FindClose,
+} ;
+
diff --git a/private/utils/ntbackup/src/gendblk.c b/private/utils/ntbackup/src/gendblk.c
new file mode 100644
index 000000000..b00336f2c
--- /dev/null
+++ b/private/utils/ntbackup/src/gendblk.c
@@ -0,0 +1,342 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: gendblk.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains code to performe the generic
+ operations on DBLKS.
+
+
+ $Log: M:/LOGFILES/GENDBLK.C_V $
+
+ Rev 1.12 24 Nov 1993 15:15:26 BARRY
+Changed CHAR_PTR in I/O function to BYTE_PTR
+
+ Rev 1.11 17 Nov 1993 15:19:24 DOUG
+Added cases for FS_GRFS_MAC, FS_GRFS_UNIX to FS_GetDelimeterFromOSID()
+
+ Rev 1.10 21 Oct 1993 13:25:20 DON
+Only use '/' delimiter for SMS if NOT building Client Application
+
+ Rev 1.9 14 Oct 1993 11:49:44 DON
+If FS_NOV_SMS OS_id then delimiter is '/'
+
+ Rev 1.8 18 Jun 1993 09:49:14 MIKEP
+enable c++
+
+ Rev 1.7 25 Jan 1993 08:57:56 DON
+Don't use any specific delimiter for SMS, use default
+
+ Rev 1.6 19 Jan 1993 16:18:06 DON
+Use a default of '/' as delimiter for SMS
+
+ Rev 1.5 11 Nov 1992 22:26:50 GREGG
+Unicodeized literals.
+
+ Rev 1.4 18 Aug 1992 10:17:14 STEVEN
+fix warnings
+
+ Rev 1.3 11 Mar 1992 18:53:48 STEVEN
+converted Get???SizeFromDBLK to macros
+
+ Rev 1.2 03 Nov 1991 15:02:14 BARRY
+TRICYCLE: Added delimiter for SMS file system.
+
+ Rev 1.1 24 Jul 1991 15:57:50 DAVIDH
+Cleared up warnings under Watcom.
+
+ Rev 1.0 09 May 1991 13:33:50 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include <string.h>
+
+#include "stdtypes.h"
+
+#include "msassert.h"
+#include "fsys.h"
+/* $end$ include list */
+
+/**/
+/**
+
+ Name: FS_GetOSid_verFromDBLK()
+
+ Description: This function returns the OS id and OS version for
+ a specified DBLK.
+
+ Modified: 9/12/1989
+
+ Returns: SUCCESS
+
+ Notes: This function is designed only for the purpose of BACKUP.
+ The tape format layer will call this function in order to fill
+ out its own DBLK structure.
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 FS_GetOSid_verFromDBLK(
+FSYS_HAND fsh, /* I - File system handle */
+DBLK_PTR dblk, /* I - DBLK to os id from */
+UINT16 *id, /* O - os id saved in DBLK */
+UINT16 *ver) /* O - os ver saved in DBLK */
+{
+ *id = dblk->com.os_id ;
+ *ver = dblk->com.os_ver ;
+
+ return SUCCESS ;
+
+ (VOID) fsh ;
+}
+
+
+/**/
+/**
+
+ Name: FS_GetAttribFromDBLK()
+
+ Description: This function gets the atttribute of a DBLK
+
+ Modified: 9/13/1989
+
+ Returns: Attribute of the DBLK
+
+ Notes:
+
+ See also: $/SEE( FS_GetGenOffsetFromDBLK() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+UINT32 FS_GetAttribFromDBLK(
+FSYS_HAND fsh, /* I - file system handle */
+DBLK_PTR dblk ) /* I - DBLK to get size of */
+{
+ UINT32 attrib;
+
+ switch ( dblk->blk_type ) {
+
+ case FDB_ID:
+ case DDB_ID:
+ case IDB_ID:
+
+ fsh->tab_ptr->ModAttribDBLK( FALSE, dblk, &attrib ) ;
+
+ break ;
+
+ case VCB_ID:
+ attrib = ((VCB_PTR)dblk)->vcb_attributes ;
+ break ;
+
+ case CFDB_ID:
+ attrib = ((CFDB_PTR)dblk)->attributes ;
+ break ;
+
+ default:
+ attrib = 0 ;
+ }
+
+ return attrib ;
+}
+/**/
+/**
+
+ Name: FS_SetAttribFromDBLK()
+
+ Description: This function sets the atttribute of a DBLK
+
+ Modified: 9/13/1989
+
+ Returns: Attribute of the DBLK
+
+ Notes:
+
+ See also: $/SEE( FS_GetGenOffsetFromDBLK() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+UINT32 FS_SetAttribFromDBLK(
+FSYS_HAND fsh, /* I - file system handle */
+DBLK_PTR dblk , /* I - DBLK to get size of */
+UINT32 attrib ) /* I - Attrib value to set */
+{
+
+ switch ( dblk->blk_type ) {
+
+ case FDB_ID:
+ case DDB_ID:
+
+ fsh->tab_ptr->ModAttribDBLK( TRUE, dblk, &attrib ) ;
+
+ break ;
+
+ case VCB_ID:
+ ((VCB_PTR)dblk)->vcb_attributes = attrib ;
+ break ;
+
+ case CFDB_ID:
+ ((CFDB_PTR)dblk)->attributes = attrib ;
+ break ;
+
+ default:
+ break ;
+
+ }
+
+ return SUCCESS ;
+}
+
+
+/**/
+/**
+
+ Name: FS_SizeofOS_InfoInDBLK()
+
+ Description: This function gets the size of OS Info for the DBLK.
+
+ Modified: 9/13/1989
+
+ Returns: Size of the OS info for the DBLK
+
+ Notes:
+
+ See also: $/SEE( FS_GetGenOffsetFromDBLK() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 FS_SizeofOS_InfoInDBLK(
+FSYS_HAND fsh, /* I - file system handle */
+DBLK_PTR dblk ) /* I - DBLK to get size from */
+{
+ INT16 size ;
+ switch ( dblk->blk_type ) {
+
+ case FDB_ID:
+ case DDB_ID:
+
+ size = fsh->tab_ptr->SizeofOSInfo( fsh, dblk ) ;
+
+ break ;
+
+ default:
+ size = 0 ;
+ }
+
+ return size ;
+}
+
+
+/**/
+/**
+
+ Name: FS_GetOS_InfoFromDBLK()
+
+ Description: This function gets the OS specific data for the DBLK.
+
+ Modified: 9/13/1989
+
+ Returns: SUCCESS
+
+ Notes:
+
+ See also: $/SEE( FS_SizeofOS_InfoInDBLK() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 FS_GetOS_InfoFromDBLK(
+FSYS_HAND fsh, /* I - file system handle */
+DBLK_PTR dblk, /* I - DBLK to get info from */
+BYTE_PTR data) /* O - buffer to place data in */
+{
+ INT16 size = 1024;
+
+ /* Why on earth are we not looking at the return code? */
+
+ switch ( dblk->blk_type )
+ {
+ case FDB_ID:
+ case DDB_ID:
+ fsh->tab_ptr->GetOS_InfoDBLK( dblk, data, &size ) ;
+ break;
+ }
+
+ return SUCCESS ;
+}
+
+/**/
+/**
+
+ Name: FS_GetDelimiterFromOSID
+
+ Description: This function switches on the OS Id to determine
+ the approprate delimiter character to be used to seperate
+ directory paths.
+
+ Modified: 11/22/1989
+
+ Returns: The dilimiter character
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+CHAR FS_GetDelimiterFromOSID(
+UINT16 id , /* I - OS Id to determine the delimiter for */
+UINT16 ver ) /* I - OS version. Not used */
+{
+ CHAR ret_val ;
+
+ (VOID) ver ;
+
+ switch( id ) {
+
+ case FS_MAC_FINDER:
+ case FS_MAC_TOPS:
+ case FS_MAC_APPLESHARE:
+ ret_val = TEXT(':') ;
+ break ;
+
+#if !defined(P_CLIENT)
+ /*
+ Until the CLIENT UI and FS_ParsePath can handle a '/' delimiter
+ we'll just have to use the default DOS style delimiter.
+ */
+ case FS_NOV_SMS :
+ case FS_GRFS_UNIX :
+ ret_val = TEXT('/');
+ break;
+
+ case FS_GRFS_MAC :
+ ret_val = TEXT(':');
+ break;
+
+#endif
+
+ default:
+ ret_val = TEXT('\\');
+ break ;
+
+ }
+
+ return ret_val ;
+}
+
diff --git a/private/utils/ntbackup/src/get_vcb.c b/private/utils/ntbackup/src/get_vcb.c
new file mode 100644
index 000000000..5aaec45fc
--- /dev/null
+++ b/private/utils/ntbackup/src/get_vcb.c
@@ -0,0 +1,131 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: get_vcb.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+
+ $Log: T:/LOGFILES/GET_VCB.C_V $
+
+ Rev 1.8 23 Mar 1992 14:27:14 GREGG
+Set rewind_sdrv in open info struct from same in getvcb struct.
+
+ Rev 1.7 28 Feb 1992 18:08:44 GREGG
+Added calls to TF_OpenTape and TF_CloseTape.
+
+ Rev 1.6 19 Feb 1992 16:02:28 GREGG
+Added vcb_only parameter to call to TF_OpenSet.
+
+ Rev 1.5 17 Oct 1991 01:57:52 ED
+BIGWHEEL - 8200sx - Initial integration.
+
+ Rev 1.4 22 Jul 1991 10:20:32 DAVIDH
+Corrected type mismatch warnings.
+
+ Rev 1.3 21 Jun 1991 13:51:16 STEVEN
+new config unit
+
+ Rev 1.2 23 May 1991 12:51:42 STEVEN
+Conversion to ansii prototypes
+
+ Rev 1.1 14 May 1991 14:13:42 DAVIDH
+Resolved pointer mismatch warning for Watcom compiler
+
+ Rev 1.0 09 May 1991 13:39:26 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "msassert.h"
+#include "datetime.h"
+#include "fsys.h"
+#include "thw.h"
+#include "drvinf.h"
+#include "bsdu.h"
+#include "tflproto.h"
+#include "loops.h"
+#include "tpos.h"
+#include "tfldefs.h"
+#include "tflstats.h"
+#include "tfl_err.h"
+/* $end$ include list */
+
+/**/
+/**
+
+ Name: LP_GetVCB
+
+ Description: This function Reads the VCB at the requested position.
+
+ Modified: 12/13/1989
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 LP_GetVCB(
+GETVCB_PTR getvcb_ptr, /* I - Specifies which backup set to read */
+TPOS_HANDLER ui_tpos_rout, /* I - The User Interface tape positioner */
+THW_PTR thw_list, /* I - Specifies the tape drive */
+VOID_PTR ref ) /* I - reference ptr returned to tpos rout */
+{
+ TFL_OPBLK tfl_opblk ;
+ TPOS tfl_pos ;
+ TF_STATS tf_stats ;
+ INT16 return_status ;
+ INT16 status ;
+
+ /* open the file system */
+ if( ( return_status = FS_OpenFileSys( &tfl_opblk.fsh, GENERIC_DATA, getvcb_ptr->cfg ) ) != SUCCESS ) {
+
+ return( return_status ) ;
+
+ }
+
+ /* save the fsh in the UI structure */
+ getvcb_ptr -> fsys_handle = tfl_opblk.fsh ;
+
+ tfl_opblk.sdrv = thw_list ;
+ tfl_opblk.ignore_clink = TRUE ;
+ tfl_opblk.mode = TF_READ_OPERATION ;
+ tfl_opblk.perm_filter = TF_KEEP_ALL_DATA ;
+ tfl_opblk.attributes = 0 ;
+ tfl_opblk.tape_position = &tfl_pos ;
+ tfl_opblk.tape_position->tape_id = getvcb_ptr->tape_fid ;
+ tfl_opblk.tape_position->tape_seq_num = getvcb_ptr->tape_seq_num ;
+ tfl_opblk.tape_position->backup_set_num = getvcb_ptr->backup_set_num ;
+ tfl_opblk.tape_position->reference = ( UINT32 )ref ;
+ tfl_opblk.tape_position->UI_TapePosRoutine = ui_tpos_rout ;
+ tfl_opblk.tape_position->tape_loc.pba_vcb = 0 ;
+ tfl_opblk.tape_position->tape_loc.lba_vcb = 0 ;
+ tfl_opblk.rewind_sdrv = getvcb_ptr->rewind_sdrv ;
+ tfl_opblk.cat_enabled = FALSE ; /* Doesn't matter for this */
+
+ if( ( return_status = TF_OpenTape( &tfl_opblk.channel, tfl_opblk.sdrv, tfl_opblk.tape_position ) ) == SUCCESS ) {
+ return_status = TF_OpenSet( &tfl_opblk, TRUE ) ;
+ TF_CloseSet( tfl_opblk.channel, &tf_stats ) ;
+ }
+ TF_CloseTape( tfl_opblk.channel ) ;
+
+ if( ( status = FS_CloseFileSys( tfl_opblk.fsh ) ) != SUCCESS ) {
+ msassert( status == SUCCESS ) ;
+ }
+
+ return( return_status ) ;
+
+}
diff --git a/private/utils/ntbackup/src/getres.c b/private/utils/ntbackup/src/getres.c
new file mode 100644
index 000000000..ebcc27278
--- /dev/null
+++ b/private/utils/ntbackup/src/getres.c
@@ -0,0 +1,76 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: getres.c
+
+ Description: Get a Resource
+
+ $Log: G:/UI/LOGFILES/GETRES.C_V $
+
+ Rev 1.10 07 Oct 1992 14:55:02 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.9 04 Oct 1992 19:37:36 DAVEV
+Unicode Awk pass
+
+ Rev 1.8 28 Jul 1992 14:45:32 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.7 27 Jul 1992 14:49:12 JOHNWT
+ChuckB fixed references for NT.
+
+ Rev 1.6 14 May 1992 17:24:12 MIKEP
+nt pass 2
+
+ Rev 1.5 05 Feb 1992 17:52:04 GLENN
+Set local variable to static.
+
+ Rev 1.4 20 Dec 1991 09:36:26 DAVEV
+16/32 bit port - 2nd pass
+
+ Rev 1.3 18 Dec 1991 14:08:54 GLENN
+Added windows.h
+
+ Rev 1.2 11 Dec 1991 13:55:44 CARLS
+check for NULL error pointer
+
+ Rev 1.1 10 Dec 1991 17:31:40 MIKEP
+fix error return code
+
+ Rev 1.0 20 Nov 1991 19:30:34 SYSTEM
+Initial revision.
+
+*****************************************************************************/
+/* begin include list */
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+static CHAR szResBuffer[ MAX_UI_RESOURCE_SIZE ];
+
+VOID_PTR RM_GetResource (
+
+RM_HDL_PTR hRes,
+UINT unSession,
+UINT unResNum,
+UINT16_PTR pNumItems,
+UINT16_PTR pError )
+
+{
+ DBG_UNREFERENCED_PARAMETER ( hRes );
+ DBG_UNREFERENCED_PARAMETER ( unSession );
+ DBG_UNREFERENCED_PARAMETER ( pNumItems );
+
+ // Check to see if calling function wants a return code.
+
+ if( pError ) {
+ *pError = RM_NO_ERROR;
+ }
+
+ RSM_StringCopy( unResNum, szResBuffer, MAX_UI_RESOURCE_LEN ) ;
+
+ return ( (VOID_PTR) szResBuffer ) ;
+}
diff --git a/private/utils/ntbackup/src/getstrm.c b/private/utils/ntbackup/src/getstrm.c
new file mode 100644
index 000000000..9a966ffa3
--- /dev/null
+++ b/private/utils/ntbackup/src/getstrm.c
@@ -0,0 +1,468 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: getstrm.c
+
+ Date Updated: 5/19/1992 14:28:59
+
+ Description: This file has common code to deal with path
+ names in streams.
+
+ $Log: T:\logfiles\getstrm.c_v $
+
+ Rev 1.24 24 Jan 1994 21:43:36 GREGG
+Warning fix.
+
+ Rev 1.23 15 Jan 1994 19:21:16 BARRY
+Change CHAR_PTR name parameter in FS_SetupOSPathOrNameInDBLK to
+BYTE_PTR since it takes data in either ANSI/Unicode at run-time.
+
+ Rev 1.22 12 Jan 1994 13:00:40 BARRY
+Added an msassert for something that shouldn't happen. Did this
+because the function's return value is probably never checked.
+
+ Rev 1.21 01 Dec 1993 13:10:06 STEVEN
+fill stream was returning -1 if size was 0
+
+ Rev 1.20 24 Nov 1993 15:17:46 BARRY
+Changed CHAR_PTR in I/O function to BYTE_PTR
+
+ Rev 1.19 19 Aug 1993 16:32:34 STEVEN
+fix unicode bugs
+
+ Rev 1.18 11 Aug 1993 18:01:02 STEVEN
+fix read of unicode tape with ansi app
+
+ Rev 1.17 17 Mar 1993 15:20:12 TERRI
+Added a NULL after name in name queue elem
+
+ Rev 1.16 30 Jan 1993 11:25:48 DON
+Removed compiler warnings
+
+ Rev 1.15 15 Jan 1993 13:19:06 BARRY
+added support for new error messages and backup priviladge
+
+ Rev 1.14 17 Dec 1992 15:26:28 TIMN
+Added size parameter to initial an s_info
+
+ Rev 1.13 07 Dec 1992 14:17:44 STEVEN
+updates from msoft
+
+ Rev 1.12 11 Nov 1992 22:49:10 STEVEN
+This is Gregg checking files in for Steve. I don't know what he did!
+
+ Rev 1.11 10 Nov 1992 14:03:50 STEVEN
+do not queue invalid stuff
+
+ Rev 1.10 10 Nov 1992 08:17:52 STEVEN
+move os path and os name into common part of dblk
+
+ Rev 1.9 16 Oct 1992 15:41:42 STEVEN
+fix stream size problem
+
+ Rev 1.8 07 Oct 1992 14:10:24 STEVEN
+need to init tf_attrib to 0
+
+ Rev 1.7 07 Oct 1992 13:50:10 TIMN
+Added fs attrib parameter to initialize stream info
+
+ Rev 1.6 25 Sep 1992 12:53:10 CARLS
+added FS_InitStrmInfo
+
+ Rev 1.5 24 Sep 1992 13:44:32 BARRY
+Changes for huge file name support.
+
+ Rev 1.4 14 Aug 1992 09:45:54 BARRY
+Fixed warning.
+
+ Rev 1.3 23 Jul 1992 11:34:24 STEVEN
+fix warning
+
+ Rev 1.2 22 May 1992 16:05:50 STEVEN
+
+
+ Rev 1.1 21 May 1992 10:30:36 STEVEN
+added write_stream_header function
+
+ Rev 1.0 20 May 1992 17:18:48 STEVEN
+Initial revision.
+
+**/
+/* begin include list */
+#include <string.h>
+#include <stdlib.h>
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "std_err.h"
+
+#include "fsys.h"
+#include "fsys_prv.h"
+
+static BOOLEAN StreamIdMatch( UINT32 id_found, UINT32 id_req ) ;
+static INT16 AppendStreamData(
+ FSYS_HAND fsh,
+ DBLK_PTR dblk,
+ VOID_PTR buffer,
+ UINT16 size ) ;
+
+
+/**/
+/**
+
+ Name: FS_FillBufferWithStream()
+
+ Description: This function will accept data and save it connected
+ to the FSYS_HAND. The data held is a sub-stream of the specified
+ type.
+
+ This function was designed for saveing the Pathname stream.
+
+ Modified: 5/20/1992 9:39:54
+
+ Returns: Error Codes:
+ SUCCESS or OUT_OF_MEMORY
+
+**/
+INT16 FS_FillBufferWithStream( FSYS_HAND fsh,
+ DBLK_PTR dblk,
+ VOID_PTR buffer,
+ UINT16 *size,
+ STREAM_INFO *sinfo )
+{
+ INT16 ret_val = SUCCESS ;
+ UINT16 tmp_size ;
+
+ /* if start of stream */
+ if ( sinfo->id != STRM_INVALID )
+ {
+ fsh->stream_info = *sinfo;
+ }
+
+ if (*size == 0 ) {
+ return SUCCESS ;
+ }
+
+ tmp_size = min( *size, (UINT16)(FS_GetStrmSizeLo(&fsh->stream_info) - dblk->com.stream_offset) ) ;
+
+ ret_val = AppendStreamData( fsh, dblk, buffer, tmp_size ) ;
+ *size = tmp_size ;
+
+ if ( ( ret_val == SUCCESS ) &&
+ ( dblk->com.stream_offset == (UINT16)FS_GetStrmSizeLo(&fsh->stream_info) ) )
+ {
+ ret_val = FS_STREAM_COMPLETE ;
+ }
+ return ret_val;
+}
+
+static INT16 AppendStreamData( FSYS_HAND fsh,
+ DBLK_PTR dblk,
+ VOID_PTR buffer,
+ UINT16 size )
+{
+ UINT16 needed_size ;
+
+ needed_size = size + dblk->com.stream_offset ;
+ if ( fsh->stream_buf_size < needed_size ) {
+
+ fsh->stream_ptr = realloc( fsh->stream_ptr, needed_size ) ;
+ fsh->stream_buf_size = needed_size ;
+ }
+
+ if ( fsh->stream_ptr != NULL ) {
+
+ memcpy( (INT8_PTR)fsh->stream_ptr + dblk->com.stream_offset, buffer, size ) ;
+ dblk->com.stream_offset += size ;
+ return SUCCESS ;
+
+ } else {
+
+ return OUT_OF_MEMORY ;
+
+ }
+}
+
+VOID FS_GetStreamInfo( FSYS_HAND fsh,
+ DBLK_PTR dblk,
+ STREAM_INFO_PTR *stream_info,
+ BYTE_PTR *stream_data )
+{
+ if ( dblk->com.stream_offset > 0 )
+ {
+ *stream_info = &fsh->stream_info;
+ *stream_data = fsh->stream_ptr;
+ }
+ else
+ {
+ *stream_info = NULL ;
+ *stream_data = NULL ;
+ }
+}
+
+/**/
+/**
+
+ Name: FS_WriteStreamHeader()
+
+ Description: This function copies a stream header to the provided
+ buffer. If the buffer is too small, the required size is
+ returned in the blk_size parameter.
+
+ Modified: 5/21/1992 10:29:27
+
+ Returns: Error codes:
+ none
+
+**/
+VOID FS_WriteStreamHeader(
+UINT32 strm_id, /* I - stream id to write */
+INT8_PTR strm_name, /* I - name of stream */
+UINT16 name_leng, /* I - length of stream name */
+UINT64 strm_size, /* I - length of data stream */
+UINT32 strm_attr, /* I - attribute of data stream */
+CHAR_PTR buf , /* O - buffer to place data into */
+UINT16 *size , /*I/O- Entry: size of buf; Exit: number of bytes read */
+UINT16 *blk_size ) /* O - Block size need for next read */
+{
+ msassert( FALSE );
+(VOID)strm_id;
+(VOID)strm_name;
+(VOID)name_leng;
+(VOID)strm_size;
+(VOID)strm_attr;
+(VOID)buf;
+(VOID)size;
+(VOID)blk_size;
+}
+
+/**/
+/**
+
+ Name: FS_InitStrmInfo()
+
+ Description: This function copies a stream id and file system attrib
+ into the stream header.
+
+ Modified: 9/25/1992 10:29:27
+
+ Returns: Void
+
+**/
+VOID FS_InitStrmInfo( STREAM_INFO_PTR s_info, UINT32 id, UINT16 fs_attrib, UINT32 size_lo )
+{
+ s_info->tf_attrib = 0U ; /* field used by TF */
+
+ FS_SetStrmId( s_info, id );
+ FS_SetStrmAttrib( s_info, fs_attrib );
+
+ FS_SetStrmSizeLo( s_info, size_lo );
+ FS_SetStrmSizeHi( s_info, 0U );
+}
+/**/
+/**
+
+ Name: FS_AllocOSPathOrNameInDBLK()
+
+ Description: This function will allocate memory for a name buffer.
+ This buffer is designed to be attached to a DBLK and
+ enqueued into a list of buffers pointed to by the
+ file system handle.
+
+ Modified: 11/9/1992
+
+ Returns: a pointer to the allocated name queue elem.
+ if NULL is returned then an OUT_OF_MEMORY error
+ should be assumed.
+
+**/
+FS_NAME_Q_ELEM_PTR FS_AllocPathOrName( FSYS_HAND fsh,
+ INT16 name_size )
+{
+ FS_NAME_Q_ELEM_PTR name_q_elem ;
+
+ name_q_elem = (FS_NAME_Q_ELEM_PTR)DeQueueElem( &fsh->avail_name_q ) ;
+ if ( name_q_elem == NULL ) {
+ name_q_elem = (FS_NAME_Q_ELEM_PTR)calloc( 1, sizeof( FS_NAME_Q_ELEM ) ) ;
+ }
+
+ if ( name_q_elem != NULL ) {
+
+ if ( name_q_elem->alloc_size < (UINT16)name_size ) {
+ name_q_elem->alloc_size = name_size + 100 ;
+ name_q_elem->name = realloc( name_q_elem->name, name_q_elem->alloc_size ) ;
+ }
+
+ if ( name_q_elem->name == NULL ) {
+ free( name_q_elem ) ;
+ name_q_elem = NULL ;
+ } else {
+ EnQueueElem( &fsh->in_use_name_q, &name_q_elem->q, FALSE ) ;
+ }
+
+ }
+
+ return name_q_elem ;
+}
+
+/**/
+/**
+
+ Name: FS_SetupOSPathOrNameInDBLK()
+
+ Description: This function will setup the os name field in the
+ common part of the dblk. This name is the file name as it
+ appeared on tape for a FDB or the path name as it appeared on
+ tape for a DDB.
+
+ This function should be shared between the OS's for seting up
+ the os path and os name inside the dblks.
+
+ Modified: 11/9/1992
+
+ Returns: Error Codes:
+ SUCCESS or OUT_OF_MEMORY
+
+**/
+INT16 FS_SetupOSPathOrNameInDBLK( FSYS_HAND fsh,
+ DBLK_PTR dblk,
+ BYTE_PTR name_ptr,
+ INT16 name_size )
+{
+ FS_NAME_Q_ELEM_PTR name_q_elem ;
+ BOOLEAN asci_to_uni = FALSE ;
+ BOOLEAN uni_to_asci = FALSE ;
+ INT16 ret_val ;
+ INT name_size_int ;
+
+ name_size_int = name_size ;
+
+# if defined( UNICODE )
+ if ( dblk->com.string_type == BEC_ANSI_STR ) {
+ name_size_int *= sizeof( WCHAR ) ;
+ asci_to_uni = TRUE ;
+ }
+# else
+ if ( dblk->com.string_type != BEC_ANSI_STR ) {
+ name_size_int /= sizeof( WCHAR ) ;
+ uni_to_asci = TRUE ;
+ }
+# endif
+
+ name_q_elem = FS_AllocPathOrName( fsh, (UINT16)name_size_int ) ;
+
+ if ( name_q_elem == NULL ) {
+ return OUT_OF_MEMORY ;
+ }
+
+ if ( uni_to_asci ) {
+ ret_val = mapUnicToAnsiNoNull( (WCHAR_PTR)name_ptr,
+ (ACHAR_PTR)name_q_elem->name,
+ (ACHAR)'_',
+ (INT)name_size,
+ &name_size_int ) ;
+ } else if ( asci_to_uni ) {
+ ret_val = mapAnsiToUnicNoNull( (ACHAR_PTR)name_ptr,
+ (WCHAR_PTR)name_q_elem->name,
+ (INT)name_size,
+ &name_size_int ) ;
+ } else {
+ memcpy ( name_q_elem->name, name_ptr, name_size_int ) ;
+ ret_val = SUCCESS ;
+ }
+
+ msassert( ret_val == SUCCESS ); // should no ever happen [sic]
+
+ if ( ret_val != SUCCESS ) { // should no ever happen
+ return OUT_OF_MEMORY ;
+ }
+
+ name_q_elem->name_size = name_size_int ;
+// *(name_q_elem->name + name_size_int ) = TEXT('\0') ;
+
+ dblk->com.os_name = name_q_elem ;
+
+ return SUCCESS ;
+
+}
+
+/**/
+/**
+
+ Name: FS_ReleaseOSPathOrNameInDBLK()
+
+ Description: This function release the os name field in the
+ common part of the dblk. This name is the file name as it
+ appeared on tape for a FDB or the path name as it appeared on
+ tape for a DDB.
+
+ This function should be shared between the OS's for releasing
+ the os path and os name inside the dblks.
+
+ Modified: 11/9/1992
+
+ Returns: Error Codes:
+ none
+
+**/
+VOID FS_ReleaseOSPathOrNameInDBLK( FSYS_HAND fsh,
+ DBLK_PTR dblk )
+{
+ FS_NAME_Q_ELEM_PTR name_q_elem ;
+
+ name_q_elem = dblk->com.os_name ;
+
+ if ( name_q_elem != NULL ) {
+ if ( RemoveQueueElem( &fsh->in_use_name_q,
+ &name_q_elem->q ) == SUCCESS ) {
+
+ EnQueueElem( &fsh->avail_name_q,
+ &name_q_elem->q,
+ FALSE ) ;
+ }
+ }
+
+ dblk->com.os_name = NULL ;
+}
+
+/**/
+/**
+
+ Name: FS_FreeOSPathOrNameQueueInHand()
+
+ Description: This function frees the memory associated with the
+ name queues attached to the file system handle.
+
+ Modified: 11/9/1992
+
+ Returns: Error Codes:
+ none
+
+**/
+VOID FS_FreeOSPathOrNameQueueInHand( FSYS_HAND fsh )
+{
+ FS_NAME_Q_ELEM_PTR name_q_elem ;
+
+ do {
+ name_q_elem = (FS_NAME_Q_ELEM_PTR)DeQueueElem( &fsh->avail_name_q ) ;
+
+ if ( name_q_elem != NULL ) {
+ if ( name_q_elem->name != NULL ) {
+ free( name_q_elem->name ) ;
+ }
+ free( name_q_elem ) ;
+ }
+ } while( name_q_elem != NULL ) ;
+
+ do {
+ name_q_elem = (FS_NAME_Q_ELEM_PTR)DeQueueElem( &fsh->in_use_name_q ) ;
+
+ if ( name_q_elem != NULL ) {
+ if ( name_q_elem->name != NULL ) {
+ free( name_q_elem->name ) ;
+ }
+ free( name_q_elem ) ;
+ }
+ } while( name_q_elem != NULL ) ;
+}
+
diff --git a/private/utils/ntbackup/src/ginitfs.c b/private/utils/ntbackup/src/ginitfs.c
new file mode 100644
index 000000000..8b3bf9861
--- /dev/null
+++ b/private/utils/ntbackup/src/ginitfs.c
@@ -0,0 +1,138 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: ginitfs.c
+
+
+ Description: This file contains code to initialize the specific
+ file system
+ volume name for the given DLE.
+
+
+ $Log: N:/LOGFILES/GINITFS.C_V $
+
+ Rev 1.2 16 Jul 1992 08:59:00 STEVEN
+fix default drive code
+
+ Rev 1.1 23 Jan 1992 13:01:06 STEVEN
+need a prototype for free
+
+ Rev 1.0 16 Dec 1991 17:26:36 STEVEN
+Initial revision.
+
+**/
+#include <string.h>
+#include <stdio.h>
+#include <malloc.h>
+
+#include "stdtypes.h"
+#include "msassert.h"
+#include "fsys.h"
+#include "beconfig.h"
+/**/
+/**
+
+ Name: GEN_InitFileSys()
+
+ Description: This function initializes the specific file system.
+
+ Modified: 9/13/1989
+
+ Returns: SUCCESS
+
+ Notes: The generic files system need no initialization
+
+ Declaration:
+
+**/
+INT16 GEN_InitFileSys(
+DLE_HAND hand,
+BE_CFG_PTR cfg,
+UINT32 fsys_mask )
+{
+ (VOID)cfg ;
+ (VOID)hand ;
+ (VOID) fsys_mask ;
+
+ return SUCCESS ;
+}
+/**/
+/**
+
+ Name: GEN_DeInitFileSys()
+
+ Description: This function deinitializes the specific file system.
+
+ Modified: 9/13/1989
+
+ Returns: SUCCESS
+
+ Notes: The generic files system need no deinitialization
+
+ Declaration:
+
+**/
+VOID GEN_DeInitFileSys( DLE_HAND hand )
+{
+ (VOID)hand ;
+ return ;
+}
+/**/
+/**
+
+ Name: GEN_FindDrives()
+
+ Description: This function finds all the devices for the
+ specific file system
+
+ Modified: 9/13/1989
+
+ Returns: SUCCESS
+
+ Notes: The generic files system need no devices
+
+ Declaration:
+
+**/
+INT16 GEN_FindDrives( DLE_HAND dle_hand, BE_CFG_PTR cfg, UINT32 fsys_mask )
+{
+ (VOID)dle_hand ;
+ (VOID)cfg ;
+ (VOID) fsys_mask ;
+
+ return SUCCESS ;
+}
+/**/
+/**
+
+ Name: GEN_RemoveDLE()
+
+ Description: This function removes the specified DLE ;
+
+ Modified: 12/2/1991 16:29:59
+
+ Returns: none
+
+**/
+VOID GEN_RemoveDLE( GENERIC_DLE_PTR dle )
+{ /* */
+ /* if this was the defalut drive then set the defalut driv to NULL */
+ /* */
+ if ( dle->handle->default_drv == dle ) {
+ dle->handle->default_drv = NULL ;
+ }
+
+ if (dle->parent == NULL ) {
+
+ RemoveQueueElem( &(dle->handle->q_hdr), &(dle->q) ) ;
+ } else {
+ RemoveQueueElem( &(dle->parent->child_q), &(dle->q) ) ;
+ }
+
+ if ( dle->dynamic_info ) {
+ free( dle->info.dos ) ;
+ }
+ free( dle ) ;
+
+}
diff --git a/private/utils/ntbackup/src/global.c b/private/utils/ntbackup/src/global.c
new file mode 100644
index 000000000..98e3f0c1f
--- /dev/null
+++ b/private/utils/ntbackup/src/global.c
@@ -0,0 +1,539 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: global.c
+
+ Description: This file contains the definitions for global variables and
+ the function(s) that initialize some of them.
+
+ See Also: gui.c.
+
+
+ $Log: G:/UI/LOGFILES/GLOBAL.C_V $
+
+ Rev 1.66 26 Jan 1994 15:16:50 STEVEN
+No sun makes the brain atrifee
+
+ Rev 1.65 26 Jan 1994 13:23:24 STEVEN
+protected ansi tapes read with unicode app
+
+ Rev 1.64 24 Jan 1994 15:58:50 GREGG
+Added option to tell mem debugger not to trap when consistency check fails.
+
+ Rev 1.63 12 Jan 1994 10:19:50 MikeP
+add abort in middle of file flag
+
+ Rev 1.62 07 Jan 1994 13:44:18 CARLS
+added loader default record name
+
+ Rev 1.61 20 Dec 1993 09:29:50 CARLS
+removed LOADER ifdef
+
+ Rev 1.60 16 Dec 1993 10:21:56 BARRY
+TEXT around literals
+
+ Rev 1.59 13 Dec 1993 14:56:38 CARLS
+loader changes
+
+ Rev 1.58 06 Dec 1993 15:46:46 CARLS
+init loader function pointers
+
+ Rev 1.57 06 Dec 1993 15:05:26 chrish
+Removed gb_swcompression = FALSE statement for previous software
+compression support.
+
+ Rev 1.56 01 Dec 1993 17:29:54 CARLS
+Added loader support
+
+ Rev 1.55 19 Oct 1993 14:57:02 MIKEP
+add lastopertotalbytes for gas guage
+
+ Rev 1.54 11 Oct 1993 09:26:28 MIKEP
+add gfNoCATS
+
+ Rev 1.53 23 Sep 1993 18:59:56 MARINA
+added network view globals
+
+ Rev 1.52 10 Sep 1993 17:48:44 chrish
+Added code for software compression support.
+
+ Rev 1.51 03 Aug 1993 20:54:24 CHUCKB
+Added global job name string.
+
+ Rev 1.50 15 Jun 1993 13:16:10 DARRYLP
+More status monitor features
+
+ Rev 1.49 14 Jun 1993 20:57:16 MIKEP
+enable c++
+
+ Rev 1.48 11 Jun 1993 15:50:26 GLENN
+Added gfDummyDriver flag. Rearranged status block global.
+
+ Rev 1.47 14 May 1993 14:09:36 TIMN
+Removed global variable TapeDevice for multiple instances. NOST only needs
+global.h (v1.38). Cayman needs hwconfnt.c dil_nt.c be_dinit.c mui.c
+backup.c global.h and hwconf.h.
+
+
+ Rev 1.46 14 May 1993 09:39:34 DARRYLP
+Moved SetStatusBlock to resolve compile warnings.
+
+ Rev 1.45 02 May 1993 18:27:20 MIKEP
+Fix to allow mips to build. INVALID_WINDOW_HANDLE may not be used
+with INT type variables.
+
+
+ Rev 1.44 30 Apr 1993 17:20:04 TIMN
+Changed initial tape device to an actual invalid value
+
+ Rev 1.43 27 Apr 1993 15:42:16 DARRYLP
+Added Status globals.
+
+ Rev 1.42 19 Apr 1993 15:21:12 GLENN
+Added tape name global.
+
+ Rev 1.41 13 Apr 1993 17:06:52 CHUCKB
+Added global flag to tell when a job is running.
+
+ Rev 1.40 09 Apr 1993 15:40:36 GLENN
+Ifdef'd the DDE status globals for not OEM_MSOFT so that they are included in future releases.
+
+ Rev 1.39 09 Apr 1993 14:10:12 GLENN
+Added ghReturnCode.
+
+ Rev 1.38 08 Apr 1993 13:43:02 DARRYLP
+Changes for STAT_SetStatus call.
+
+ Rev 1.37 24 Mar 1993 14:53:08 DARRYLP
+Added Help for Font viewer/other common dialogs.
+
+ Rev 1.36 22 Mar 1993 10:06:48 DARRYLP
+Added new DDE manager window.
+
+ Rev 1.35 12 Mar 1993 14:45:06 MIKEP
+add auto format call
+
+ Rev 1.34 12 Mar 1993 14:34:50 MIKEP
+auto call erase if foreign tape
+
+ Rev 1.33 07 Mar 1993 12:33:38 MIKEP
+add missing tape option
+
+ Rev 1.32 18 Feb 1993 13:01:22 chrish
+Added #ifdef CAYMAN for mapped file stuff.
+
+ Rev 1.31 01 Nov 1992 15:58:20 DAVEV
+Unicode changes
+
+ Rev 1.30 20 Oct 1992 14:27:08 MIKEP
+abort at EOF
+
+ Rev 1.29 20 Oct 1992 14:21:00 MIKEP
+add support for getcurrentoperation
+
+ Rev 1.28 07 Oct 1992 14:12:30 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.27 04 Oct 1992 19:37:38 DAVEV
+Unicode Awk pass
+
+ Rev 1.26 04 Sep 1992 10:34:02 MIKEP
+add tapedevice variable
+
+ Rev 1.25 02 Sep 1992 10:16:12 GLENN
+Added the highlight color stuff.
+
+ Rev 1.24 17 Aug 1992 13:18:12 DAVEV
+MikeP's changes at Microsoft
+
+ Rev 1.22 04 Aug 1992 10:04:44 MIKEP
+no cats flag
+
+ Rev 1.21 10 Jun 1992 16:14:22 GLENN
+Updated according to NT SPEC.
+
+ Rev 1.20 31 May 1992 11:12:20 MIKEP
+auto catalog changes
+
+ Rev 1.19 14 May 1992 18:00:32 MIKEP
+nt pass 2
+
+ Rev 1.18 20 Apr 1992 13:50:10 GLENN
+Added define for status line text size.
+
+ Rev 1.17 30 Mar 1992 18:06:02 GLENN
+Added support for pulling resources from .DLL
+
+ Rev 1.16 24 Mar 1992 11:45:00 DAVEV
+OEM_MSOFT: removed ghWndLogFiles and ghWndLogFileView & all references
+
+ Rev 1.15 25 Feb 1992 12:08:06 MIKEP
+multidrive
+
+ Rev 1.14 21 Feb 1992 14:16:00 GLENN
+Updated FrameClient rectangle name.
+
+ Rev 1.13 19 Feb 1992 11:18:48 MIKEP
+add free drive handles
+
+ Rev 1.12 11 Feb 1992 17:27:02 GLENN
+Added mdi client subclass globals.
+
+ Rev 1.11 22 Jan 1992 10:04:08 CARLS
+no change
+
+ Rev 1.10 20 Jan 1992 12:58:48 MIKEP
+disk full error
+
+ Rev 1.9 10 Jan 1992 11:19:34 DAVEV
+16/32 bit port-2nd pass
+
+ Rev 1.8 23 Dec 1991 11:43:10 JOHNWT
+forgot to change the type
+
+ Rev 1.7 23 Dec 1991 11:40:02 JOHNWT
+changed gfPWForPWDBVerfified to ...State
+
+ Rev 1.6 20 Dec 1991 17:01:48 JOHNWT
+removed ghRuntimeDialog!
+
+ Rev 1.5 18 Dec 1991 11:42:52 JOHNWT
+added ghRuntimeDialog
+
+ Rev 1.4 14 Dec 1991 13:46:56 JOHNWT
+added gfPWForPWDBVerified
+
+ Rev 1.3 12 Dec 1991 17:10:00 DAVEV
+16/32 bit port -2nd pass
+
+ Rev 1.2 06 Dec 1991 17:27:14 GLENN
+Added gnMainRibbonWidth
+
+ Rev 1.1 04 Dec 1991 18:36:16 GLENN
+Updated for ALT-F4 termination
+
+ Rev 1.0 20 Nov 1991 19:18:02 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+// SYSTEM GLOBAL VARIABLES
+
+INT gnReturnCode = 0;
+
+HINSTANCE ghInst;
+HINSTANCE ghResInst;
+HANDLE ghAccel;
+HWND ghWndFrame;
+HWND ghWndMDIClient;
+HWND ghWndActiveDoc;
+HWND ghWndMainRibbon;
+HWND ghWndDocRibbon;
+HWND ghWndCommonDlg = 0;
+void SetStatusBlock(INT, DWORD); // This must be defined!
+
+HWND ghWndDebug;
+HWND ghWndDiskVols; // TEMP
+HWND ghWndTapeVols; // TEMP
+HWND ghWndJobs; // TEMP
+HWND ghModelessDialog;
+
+HMENU ghMenuJobs;
+
+LPSTR glpCmdLine;
+CHAR gszStatusLine[MAX_STATUS_LINE_SIZE];
+CHAR gszTapeName[MAX_TAPE_NAME_SIZE];
+
+RECT gRectFrameClient;// Frame's client area rectangle.
+RECT gpStatusRect; // Status line rectangle.
+HPEN ghPenBlack; // Black pen.
+HPEN ghPenWhite; // White pen.
+HPEN ghPenGray; // Gray pen.
+HPEN ghPenBackGnd; // Background pen.
+HPEN ghPenForeGnd; // Foreground pen.
+HPEN ghPenBtnText; // Button text pen.
+HPEN ghPenLtGray; // Button face pen.
+HPEN ghPenDkGray; // Button shadow pen.
+HBRUSH ghBrushLtGray; // Light Gray brush.
+HBRUSH ghBrushGray; // Gray brush.
+HBRUSH ghBrushBlack; // Black brush.
+HBRUSH ghBrushDkGray; // Dark Gray brush.
+HBRUSH ghBrushWhite; // White brush.
+HBRUSH ghBrushHighLight; // High Light brush.
+
+HFONT ghFontStatus; // Status Line Font.
+HFONT ghFontMsgBox; // Message Box Font.
+HFONT ghFontRibbon; // Ribbon Button Font.
+HFONT ghFontFiles; // File Font.
+HFONT ghFontLog; // Log File Font.
+HFONT ghFontIconLabels;// Icon Label Font.
+
+COLORREF gColorForeGnd; // Foreground Color
+COLORREF gColorBackGnd; // Background Color
+
+COLORREF gColorHighLight;
+COLORREF gColorHighLightText;
+
+ULONG gulFiles;
+ULONG gulBytes;
+ULONG gulDirectories;
+
+HCURSOR ghCursorPen;
+BOOL gfOperation;
+BOOL gfHWInitialized;
+
+INT gnBorderWidth;
+INT gnMainRibbonHeight;
+
+INT16 gnNumJobs ;
+BOOL gfEditJob ;
+WORD gwCurrentJobIndex ;
+CHAR_PTR gpszJobName ;
+
+INT16 gnNumScheds ;
+INT16 gnEditSched ;
+
+// MENU ITEM/CONFIGURATION FLAGS
+
+BOOL gfDeleteCatalogs = TRUE;
+BOOL gfShowStatusLine;
+BOOL gfShowMainRibbon;
+BOOL gfShowDocRibbon;
+BOOL gfDebug;
+BOOL gfPollDrive;
+BOOL gfAppInitialized;
+BOOL gfTerminateApp;
+BOOL gfIsJobRunning;
+
+BOOL gfDummyDriver = FALSE;
+BOOL gfIndicators;
+BOOL gfReplace;
+BOOL gfServers;
+BOOL gfNetworks = FALSE;
+BOOL gfEnhanced;
+
+#ifdef OEM_EMS
+BOOL gfExchange;
+CHAR gszDleDsName[MAX_UI_RESOURCE_SIZE];
+CHAR gszDleIsName[MAX_UI_RESOURCE_SIZE];
+#endif
+
+HRIBBON ghRibbonMain;
+HRIBBON ghRibbonDoc;
+
+WNDPROC glpfnNewListProc;
+WNDPROC glpfnOldListProc;
+WNDPROC glpfnNewMDIClientProc;
+WNDPROC glpfnOldMDIClientProc;
+
+POINT gDLMpt;
+
+INT16 gCatMaintChoice;
+INT16 gCatBsetChoice;
+INT16 gCatTapeChoice;
+
+INT16 gViewNetChoices ;
+
+#ifdef OEM_EMS
+INT16 gViewXchgChoices ;
+#endif
+
+INT gfPWForPWDBState;
+
+INT gb_last_operation = -1;
+INT gbCurrentOperation = OPERATION_NONE;
+INT gbAbortAtEOF = FALSE;
+INT gb_new_tape_flag = 0;
+
+INT gfAbortInMiddleOfFile;
+INT gfNoCATS = FALSE;
+INT gfIgnoreOTC = FALSE;
+INT gfCallEraseTape = FALSE;
+INT gfCallFormatTape = FALSE;
+
+UINT64 gn64LastOperTotalBytes;
+
+// *************************** OLD TMENU GLOBAL ITEMS ************************
+
+AUTO_PASSWORD gb_auto_password = {
+// TEXT("­ì«%MÛì!>>"),
+ {0xad, 0xec, 0xab, 0x25, 1, 0x4d, 0xdb, 0xec, 0x21, 0x3e, 0x3e, 0},
+ {TEXT('\0'),TEXT('\0'),TEXT('\0'),TEXT('\0'),TEXT('\0'),TEXT('\0'),TEXT('\0'),TEXT('\0')}
+};
+
+// encryption_key to pass to the EU_Open.
+// pass strlen( gb_encryption_key ) for ksize.
+
+INT8 gb_encryption_key[ MAX_ENCRYPTION_KEY_SIZE ] = "MSII2.6->3.0";
+
+RM_HDL_PTR rm; // Resource file handle
+DLE_HAND dle_list = NULL; // Drive list
+BSD_HAND bsd_list = NULL; // BSD List
+BSD_HAND tape_bsd_list = NULL; // Tape BSD List
+THW_PTR thw_list = NULL; // THW List
+DIL_HWD_PTR gb_dhw_ptr = NULL; // DIL Hardware Pointer
+
+#ifdef OS_WIN32 // allocate one global dil for NT
+DIL_HWD gb_NTDIL;
+# ifdef OEM_MSOFT
+ INT TapeDevice = -1 ; // Multi-instance doesn't use this
+# endif
+#endif
+
+INT8 gb_abort_flag;
+CHAR gb_exe_fname[ MAX_UI_FILENAME_SIZE ];
+CHAR gb_exe_path[ MAX_UI_PATH_SIZE ];
+CHAR gb_tmp_string[GB_TMP_STRING_SIZE];
+INT16 gb_logging = NOT_LOGGING;
+INT gb_logging_error;
+BOOLEAN gb_error_during_operation = FALSE;
+
+
+// STATUS BLOCK STUFF
+
+void SetStatusBlock(INT, DWORD); // This must be defined!
+
+#ifndef OEM_MSOFT // NOT for MSOFT
+
+HWND ghWndLogFiles;
+HWND ghWndLogFileView;
+PSTAT_SETSTATUSBLOCK pSTAT_SetStatusBlock;
+ULONG (FAR PASCAL *glpfnSetStatus)(PSTAT_SETSTATUSBLOCK);
+void SendStatusMsg(PSTAT_SETSTATUSBLOCK pStatusBlk);
+void CALLBACK StatusTimerProc(void);
+
+LPSTR glpOffsetTapeDriveName = 0L;
+LPSTR glpOffsetCurrentTapeName = 0L;
+LPSTR glpOffsetServerVolume = 0L;
+LPSTR glpOffsetTapeDriveIdentifier = 0L;
+LPSTR glpOffsetTapeNeededName = 0L;
+LPSTR glpOffsetDiskName = 0L;
+LPSTR glpOffsetActiveFile = 0L;
+LPSTR glpOffsetErrorMsg = 0L;
+LPSTR glpOffsetActiveDir = 0L;
+
+#endif // ! OEM_MSOFT
+
+
+// LOADER
+BOOL gfLoaderEnabled = FALSE ;
+
+// This is a default magazine record entry name used to
+// display the "Default(from Setting)" string in the jobs hardward dialog.
+// This name should not be translated
+CHAR gLDR_DefaultMagName[] = TEXT("Default") ;
+
+#ifdef MEM_DEBUG
+BOOLEAN gb_no_abort_on_mem_check = FALSE;
+#endif
+
+// FUNCTIONS
+
+/******************************************************************************
+
+ Name: GUI_InitGlobals()
+
+ Description: This function initializes MUI and GUI global variables.
+
+ Returns: FALSE if successful, otherwise TRUE.
+
+******************************************************************************/
+
+
+BOOL GUI_InitGlobals ( VOID )
+
+{
+
+# if !defined (OS_WIN32) //16 bit Windows specific code...
+ {
+ // Get the Windows Mode (NOT SUPPORTED FOR NT).
+ DWORD dwFlags;
+ dwFlags = GetWinFlags ();
+
+ // If we are not running in protected mode, BUG OUT.
+ // This should never happen.
+
+ if ( ! ( dwFlags & WF_PMODE ) )
+ {
+ return TRUE;
+ }
+ gfEnhanced = (BOOL)( dwFlags & WF_ENHANCED );
+ }
+# else
+ {
+ gfEnhanced = TRUE; //OR SHOULD THIS BE FALSE?
+ }
+# endif //OS_WIN32 specific code
+
+ // Initialize any window handles that need to be.
+
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ ghWndLogFiles = (HWND)NULL;
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ ghWndDebug = (HWND)NULL;
+ ghWndActiveDoc = (HWND)NULL;
+ ghModelessDialog = (HWND)NULL;
+
+ // Initialize the selection values.
+
+ gulFiles = gulBytes = gulDirectories = 0L;
+
+ // Get and set the Show flags.
+
+ gfShowDocRibbon = FALSE;
+ gfIndicators = TRUE;
+ gfShowMemory = FALSE;
+
+ // MUI Globals
+
+ gfAppInitialized = FALSE;
+ gfTerminateApp = FALSE;
+ gfHWInitialized = FALSE;
+ gnMainRibbonHeight = 0;
+
+#ifdef OEM_EMS
+ gfExchange = FALSE ;
+ RSM_StringCopy( IDS_XCHNG_DIR, gszDleDsName, MAX_UI_RESOURCE_LEN );
+ RSM_StringCopy( IDS_XCHNG_INFO_STORE, gszDleIsName, MAX_UI_RESOURCE_LEN );
+#endif
+
+ // Clear out the SubClass proc function pointers.
+
+ glpfnNewListProc = NULL;
+ glpfnOldListProc = NULL;
+ glpfnNewMDIClientProc = NULL;
+ glpfnOldMDIClientProc = NULL;
+
+ // PWDB password flag
+
+ gfPWForPWDBState = DBPW_NOT_VERIFIED;
+
+ return FALSE;
+
+} /* end GUI_InitGlobals() */
+
+#ifdef OS_WIN32
+
+ //
+ // Gloabls variables used for the mapped file objects.
+ //
+
+ CHAR_PTR gbMappedObjName = TEXT("BOB_MARLEY"); // Name of mapping object
+ LPVOID gbMappedObjBuffer = NULL; // Global mapped object buffer
+ // used by the app and the Launcher
+
+#endif
+
+
diff --git a/private/utils/ntbackup/src/gmkdblk.c b/private/utils/ntbackup/src/gmkdblk.c
new file mode 100644
index 000000000..86a51b5a7
--- /dev/null
+++ b/private/utils/ntbackup/src/gmkdblk.c
@@ -0,0 +1,434 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: gmkdblk.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains functions for the tape format
+ layer to use to create DBLKs. The structure's passed
+ to the create functions includes generic information which
+ is common to most file systems and os specific information.
+ The os specific information was saved when the file system
+ for that os was used to make a backup. The information in
+ the os specific portion could potentially be translated into
+ a useable format for this file system. Each file system defines
+ the format for its os specific information in the header file
+ osinfo.h.
+
+
+ $Log: M:/LOGFILES/GMKDBLK.C_V $
+
+ Rev 1.17 15 Jan 1994 19:22:20 BARRY
+Change types and make casts to suppress Unicode warnings
+
+ Rev 1.16 24 Nov 1993 14:40:24 BARRY
+Unicode fixes (removed TEXT macros around byte characters)
+
+ Rev 1.15 05 Sep 1993 10:08:04 DOUG
+Changed FS_PC_OS2 to FS_PC_OS2_40 in GEN_CreateDDB()
+
+ Rev 1.14 15 Jul 1993 12:33:40 GREGG
+Added setting of 'compressed_obj' BOOLEAN in common portion of DBLK.
+
+ Rev 1.13 13 May 1993 20:41:06 BARRY
+Make sure gos pointer is inited before use.
+
+ Rev 1.12 01 Dec 1992 15:52:50 CHUCKB
+Took out unreferenced locals and C++-style comments.
+
+ Rev 1.11 29 Nov 1992 18:53:50 GREGG
+Added setting of tape_seq_num and continue_obj in common part of dblk.
+
+ Rev 1.10 11 Nov 1992 22:49:16 STEVEN
+This is Gregg checking files in for Steve. I don't know what he did!
+
+ Rev 1.8 11 Nov 1992 10:44:28 STEVEN
+fix os_name for gen_fs
+
+ Rev 1.7 09 Oct 1992 11:44:28 DAVEV
+Unicode (CHAR_PTR) pointer cast validation
+
+ Rev 1.6 29 Sep 1992 18:01:40 CHUCKB
+Took out references to TF_READ_GEN_DATA_ONLY.
+
+ Rev 1.5 24 Sep 1992 17:32:30 CHUCKB
+Commented out references to rem_size.
+
+ Rev 1.4 12 Aug 1992 15:56:48 BARRY
+Changes for MTF 4.0.
+
+ Rev 1.3 17 Mar 1992 09:05:30 STEVEN
+format 40 - added 64 bit support
+
+ Rev 1.2 21 Jan 1992 14:19:50 BARRY
+Added new gen_size to GEN_DBLK.
+
+ Rev 1.1 24 Jul 1991 11:38:40 DAVIDH
+Corrected compiler warnings under Watcom.
+
+ Rev 1.0 09 May 1991 13:39:28 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include <string.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "gendblk.h"
+#include "osinfo.h"
+#include "gen_fs.h"
+#include "tfldefs.h"
+/* $end$ include list */
+
+/**/
+/**
+
+ Name: GEN_CreateFDB
+
+ Description: This function creates a FDB based on the information
+ passed in the GEN_FDB_DATA structure. This function
+ allows the tape format layer to create DBLKs without
+ knowing their structure.
+
+ Modified: 8/24/1989
+
+ Returns: TF_KEEP_ALL_DATA
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+
+INT16 GEN_CreateFDB( fsh, dat )
+FSYS_HAND fsh;
+GEN_FDB_DATA_PTR dat;
+{
+ GEN_DBLK_PTR ddblk;
+ DBLK_PTR dblk;
+ INT16 i ;
+ GOS_PTR gos = (GOS_PTR)dat->std_data.os_info;
+ OS2_FILE_OS_INFO_PTR oinfo ;
+ INT16 ret_val ;
+
+ (VOID) fsh ;
+
+ dat->std_data.dblk->blk_type = FDB_ID ;
+ dat->std_data.dblk->com.blkid = dat->std_data.blkid;
+ dat->std_data.dblk->com.f_d.did = dat->std_data.did ;
+ dat->std_data.dblk->com.ba.lba = dat->std_data.lba ;
+ dat->std_data.dblk->com.os_id = dat->std_data.os_id ;
+ dat->std_data.dblk->com.os_ver = dat->std_data.os_ver ;
+ dat->std_data.dblk->com.continue_obj = dat->std_data.continue_obj ;
+ dat->std_data.dblk->com.tape_seq_num = dat->std_data.tape_seq_num ;
+ dat->std_data.dblk->com.compressed_obj = dat->std_data.compressed_obj ;
+
+ ddblk = (GEN_DBLK_PTR)dat->std_data.dblk;
+ dblk = dat->std_data.dblk;
+ dblk->com.string_type = dat->std_data.string_type ;
+
+ ddblk->blk_type = FDB_ID;
+ ddblk->obj_type = DOS_OBJECT ;
+ ddblk->tape_attribs = dat->std_data.attrib ;
+
+ ddblk->mdate = *dat->mod_date ;
+ ddblk->cdate = *dat->creat_date ;
+ ddblk->bdate = *dat->backup_date ;
+ ddblk->bdate = *dat->access_date ;
+
+ ddblk->disp_size = dat->std_data.disp_size;
+
+ if ( dat->std_data.attrib & FILE_NAME_IN_STREAM_BIT ) {
+ dblk->com.os_name = NULL ;
+ } else {
+
+ ret_val = FS_SetupOSPathOrNameInDBLK( fsh,
+ dblk,
+ (BYTE_PTR)dat->fname,
+ dat->fname_size ) ;
+ if ( ret_val != SUCCESS ) {
+ return ret_val ;
+ }
+ }
+
+ switch ( dat->std_data.os_id ) {
+
+ case FS_NON_AFP_NOV:
+ ddblk->obj_type = NOV_OBJECT ;
+ break ;
+
+ case FS_GOS:
+
+ for( i = 0 ; i < 32; i++ ) {
+ if ( gos->finder[i] != 0 ) {
+ ddblk->obj_type = AFP_OBJECT ;
+ }
+ }
+
+ if ( ( gos->finder[4] == 'm' ) &&
+ ( gos->finder[5] == 'd' ) &&
+ ( gos->finder[6] == 'o' ) &&
+ ( gos->finder[7] == 's' ) ) {
+
+ ddblk->obj_type = NOV_OBJECT ;
+ }
+
+ if ( ( gos->long_name[0] != '\0' ) && strcmpA( gos->long_name, (ACHAR_PTR)dat->fname ) ) {
+ ddblk->obj_type = AFP_OBJECT ;
+ }
+ break ;
+
+ case FS_AFP_NOVELL_40:
+ {
+ BYTE_PTR finfo;
+
+ finfo = ((AFP_FILE_OS_INFO_PTR)dat->std_data.os_info)->finder ;
+
+ for( i = 0 ; i < 32; i++ ) {
+ if ( finfo[i] != 0 ) {
+ ddblk->obj_type = AFP_OBJECT ;
+ }
+ }
+
+ if ( ( finfo[4] == 'm' ) &&
+ ( finfo[5] == 'd' ) &&
+ ( finfo[6] == 'o' ) &&
+ ( finfo[7] == 's' ) ) {
+
+ ddblk->obj_type = NOV_OBJECT ;
+ }
+
+ if ( strcmpA( (ACHAR_PTR)dat->fname, gos->long_name ) ) {
+ ddblk->obj_type = AFP_OBJECT ;
+ }
+ }
+ break ;
+
+ case FS_PC_OS2_40:
+ oinfo = (OS2_FILE_OS_INFO_PTR)(dat->std_data.os_info) ;
+ if ( oinfo->longNameLength != 0 ) {
+
+ FS_ReleaseOSPathOrNameInDBLK( fsh, dblk ) ;
+
+ ret_val = FS_SetupOSPathOrNameInDBLK( fsh,
+ dblk,
+ (INT8_PTR)dblk + oinfo->longName,
+ oinfo->longNameLength ) ;
+ if ( ret_val != SUCCESS ) {
+ return ret_val ;
+ }
+ }
+ break ;
+
+ default:
+ break ;
+ }
+
+ return TF_KEEP_ALL_DATA ;
+}
+
+
+/**/
+/**
+
+ Name: GEN_CreateDDB
+
+ Description: This function creates a DDB based on the information
+ passed in the GEN_DDB_DATA structure. This function
+ allows the tape format layer to create DBLKs without
+ knowing their structure.
+
+ Modified: 8/24/1989
+
+ Returns: TF_SKIP_ALL_DATA
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+
+INT16 GEN_CreateDDB( fsh, dat )
+FSYS_HAND fsh;
+GEN_DDB_DATA_PTR dat;
+
+{
+ GEN_DBLK_PTR ddblk;
+ DBLK_PTR dblk ;
+ INT16 i ;
+ BYTE_PTR finfo ;
+ GOS_PTR gos = (GOS_PTR)dat->std_data.os_info;
+ INT16 ret_val ;
+ OS2_DIR_OS_INFO_PTR oinfo ;
+
+ (VOID) fsh ;
+
+ dat->std_data.dblk->blk_type = DDB_ID ;
+ dat->std_data.dblk->com.blkid = dat->std_data.blkid;
+ dat->std_data.dblk->com.f_d.did = dat->std_data.did ;
+ dat->std_data.dblk->com.ba.lba = dat->std_data.lba ;
+ dat->std_data.dblk->com.os_id = dat->std_data.os_id ;
+ dat->std_data.dblk->com.os_ver = dat->std_data.os_ver ;
+
+ dat->std_data.dblk->com.continue_obj = dat->std_data.continue_obj ;
+ dat->std_data.dblk->com.tape_seq_num = dat->std_data.tape_seq_num ;
+
+ ddblk = (GEN_DBLK_PTR)dat->std_data.dblk;
+ dblk = dat->std_data.dblk;
+ dblk->com.string_type = dat->std_data.string_type ;
+
+ ddblk->blk_type = DDB_ID;
+ ddblk->obj_type = DOS_OBJECT ;
+ ddblk->tape_attribs = dat->std_data.attrib ;
+
+ ddblk->mdate = *dat->mod_date ;
+ ddblk->cdate = *dat->creat_date ;
+ ddblk->bdate = *dat->backup_date ;
+ ddblk->adate = *dat->access_date ;
+
+ ddblk->disp_size = dat->std_data.disp_size;
+
+ if ( dat->std_data.attrib & DIR_PATH_IN_STREAM_BIT ) {
+ dblk->com.os_name = NULL ;
+ } else {
+
+ ret_val = FS_SetupOSPathOrNameInDBLK( fsh,
+ dblk,
+ (BYTE_PTR)dat->path_name,
+ dat->path_size ) ;
+ if ( ret_val != SUCCESS ) {
+ return ret_val ;
+ }
+ }
+
+ switch ( dat->std_data.os_id ) {
+
+ case FS_NON_AFP_NOV:
+ ddblk->obj_type = NOV_OBJECT ;
+ break ;
+
+ case FS_GOS:
+
+ for( i = 0 ; i < 32; i++ ) {
+ if ( gos->finder[i] != 0 ) {
+ ddblk->obj_type = AFP_OBJECT ;
+ }
+ }
+
+ if ( ( gos->finder[4] == 'm' ) &&
+ ( gos->finder[5] == 'd' ) &&
+ ( gos->finder[6] == 'o' ) &&
+ ( gos->finder[7] == 's' ) ) {
+
+ ddblk->obj_type = NOV_OBJECT ;
+ }
+ break ;
+
+ case FS_AFP_NOVELL_40:
+
+ finfo = ((AFP_DIR_OS_INFO_PTR)dat->std_data.os_info)->finder ;
+
+ for( i = 0 ; i < 32; i++ ) {
+ if ( finfo[i] != 0 ) {
+ ddblk->obj_type = AFP_OBJECT ;
+ }
+ }
+
+ if ( ( finfo[4] == 'm' ) &&
+ ( finfo[5] == 'd' ) &&
+ ( finfo[6] == 'o' ) &&
+ ( finfo[7] == 's' ) ) {
+
+ ddblk->obj_type = NOV_OBJECT ;
+ }
+ break ;
+
+ case FS_PC_OS2_40:
+ oinfo = (OS2_DIR_OS_INFO_PTR)(dat->std_data.os_info) ;
+ if ( oinfo->pathLength != 0 ) {
+
+ ret_val = FS_SetupOSPathOrNameInDBLK( fsh,
+ dblk,
+ (INT8_PTR)dblk + oinfo->path,
+ oinfo->pathLength ) ;
+ if ( ret_val != SUCCESS ) {
+ return ret_val ;
+ }
+
+ }
+ break ;
+
+ default:
+ break ;
+ }
+
+ return TF_KEEP_ALL_DATA ;
+
+}
+
+
+/**/
+/**
+
+ Name: GEN_CreateIDB()
+
+ Description: This function looks for a GEN_IMAGE DLE with the same
+ name as the attached DOS DLE. If one is found then the File
+ System Handle is re-attached to the IMAGE DLE. If one is NOT
+ found then DUMMY_CreateIDB() is called.
+
+ Modified: 9/18/1989
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( DUMMY_CreateIDB(), FS_AttachToDLE() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+
+INT16 GEN_CreateIDB( fsh, dat )
+FSYS_HAND fsh;
+GEN_IDB_DATA_PTR dat;
+
+
+{
+ GEN_DBLK_PTR ddblk;
+
+ (VOID) fsh ;
+
+ dat->std_data.dblk->blk_type = IDB_ID ;
+ dat->std_data.dblk->com.blkid = dat->std_data.blkid;
+ dat->std_data.dblk->com.f_d.did = dat->std_data.did ;
+ dat->std_data.dblk->com.ba.lba = dat->std_data.lba ;
+
+ ddblk = (GEN_DBLK_PTR)dat->std_data.dblk;
+
+ ddblk->blk_type = IDB_ID;
+ ddblk->obj_type = IMAGE_OBJECT ;
+ ddblk->tape_attribs = dat->std_data.attrib ;
+ ddblk->disp_size = dat->std_data.disp_size;
+ ddblk->os_part_name = sizeof( *ddblk ) ;
+
+ memcpy( ((INT8_PTR)ddblk) + ddblk->os_part_name, dat->pname, dat->pname_size ) ;
+ if( *((CHAR_PTR)((INT8_PTR)ddblk) + (ddblk->os_part_name + dat->pname_size - 1 )) != TEXT('\0') ) {
+ *((CHAR_PTR)((INT8_PTR)ddblk) + (ddblk->os_part_name + dat->pname_size )) = TEXT('\0') ;
+ }
+
+ return TF_KEEP_ALL_DATA ;
+}
+
diff --git a/private/utils/ntbackup/src/gmoddblk.c b/private/utils/ntbackup/src/gmoddblk.c
new file mode 100644
index 000000000..d7b79322c
--- /dev/null
+++ b/private/utils/ntbackup/src/gmoddblk.c
@@ -0,0 +1,748 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: gmoddblk.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains code to get/set generic information
+ from/to a DOS FDB or DDB.
+
+
+ $Log: T:/LOGFILES/GMODDBLK.C_V $
+
+ Rev 1.20 17 Feb 1994 17:00:14 GREGG
+Fixed unicode pointer math bug causing memory hit.
+
+ Rev 1.19 15 Jan 1994 19:22:44 BARRY
+Call SetupOSPathOrName with BYTE_PTRs instead of CHAR_PTRs
+
+ Rev 1.18 24 Nov 1993 15:16:26 BARRY
+Unicode fixes
+
+ Rev 1.17 02 Aug 1993 08:44:32 DON
+Needed prototype for FS_SetupOSPathOrNameInDBLK
+
+ Rev 1.16 30 Jul 1993 13:19:06 STEVEN
+if dir too deep make new one
+
+ Rev 1.15 17 Mar 1993 15:27:38 TERRI
+Added a null to file name.
+
+ Rev 1.14 09 Mar 1993 11:37:24 MARILYN
+GEN_ProcessDDB should return TRUE (process DDBs always) not FALSE
+
+ Rev 1.13 07 Dec 1992 14:55:40 STEVEN
+Microsoft updates
+
+ Rev 1.12 01 Dec 1992 10:38:34 DON
+needed to use strNcpy instead of strcpy
+
+ Rev 1.11 11 Nov 1992 10:43:34 STEVEN
+fix os_name for gen_fs
+
+ Rev 1.10 06 Oct 1992 13:24:46 DAVEV
+Unicode strlen verification
+
+ Rev 1.9 22 Sep 1992 17:29:40 CHUCKB
+Took out references to GetTotalSizeDBLK().
+
+ Rev 1.8 10 Sep 1992 09:45:52 STEVEN
+fix warnings
+
+ Rev 1.7 18 Aug 1992 10:20:26 STEVEN
+fix warnings
+
+ Rev 1.6 17 Mar 1992 09:05:32 STEVEN
+format 40 - added 64 bit support
+
+ Rev 1.5 21 Jan 1992 14:20:34 BARRY
+Added GEN_GetGenSizeDBLK().
+
+ Rev 1.4 27 Nov 1991 10:34:28 BARRY
+Fixed GEN_GetOSPath parameters.
+
+ Rev 1.3 01 Oct 1991 11:19:36 BARRY
+Include standard headers.
+
+ Rev 1.2 14 Aug 1991 13:06:58 STEVEN
+added FindClose
+
+ Rev 1.1 24 Jul 1991 11:37:54 DAVIDH
+Corrected compiler warnings under Watcom.
+
+ Rev 1.0 09 May 1991 13:39:36 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include <string.h>
+
+#include "stdtypes.h"
+#include "tfldefs.h"
+#include "datetime.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "gendblk.h"
+#include "GEN_fs.h"
+#include "fsys_err.h"
+#include "msassert.h"
+/* $end$ include list */
+/**/
+/**
+
+ Name: GEN_GetOSFnameFDB()
+
+ Description: This function copies the OS file name in the specified
+ FDB to the specified buffer. The OS file name is the same as
+ the "normal" file name during backup. During restore, the
+ OS file name is the name stored on tape.
+
+ Modified: 8/15/1989
+
+ Returns: Error codes
+ FS_BUFFER_TO_SMALL
+ SUCCESS
+
+ Notes:
+
+ See also: $/SEE( GEN_ModFnameFDB() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 GEN_GetOSFnameFDB( dblk, buf )
+DBLK_PTR dblk ; /* I - Descriptor block to get path from */
+CHAR_PTR buf ; /* O - buffer to place path in */
+{
+ memcpy( buf, dblk->com.os_name->name, dblk->com.os_name->name_size ) ;
+
+ *( buf + ( dblk->com.os_name->name_size / sizeof( CHAR ) ) ) = TEXT('\0') ;
+
+ return SUCCESS ;
+}
+
+/**/
+/**
+
+ Name: GEN_GetPartName()
+
+ Description: This function copies the OS partition name in the specified
+ IDB to the specified buffer.
+
+ Modified: 8/15/1989
+
+ Returns: Error codes
+ SUCCESS
+
+ Notes:
+
+ See also: $/SEE( GEN_GetOSFnameFDB() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 GEN_GetPartName( fsh, dblk, buf )
+FSYS_HAND fsh ; /* I - file system handle */
+DBLK_PTR dblk ; /* I - Descriptor block to get path from */
+CHAR_PTR buf ; /* O - buffer to place path in */
+{
+ GEN_DBLK_PTR ddblk ;
+
+ (VOID) fsh;
+
+ ddblk = (GEN_DBLK_PTR) dblk;
+
+ strcpy( buf, (CHAR_PTR)(((INT8_PTR)ddblk) + ddblk->os_part_name) ) ;
+
+ return SUCCESS ;
+}
+
+/**/
+/**
+
+ Name: GEN_GetOSPathDDB()
+
+ Description: This function copies the OS path in the specified
+ DDB to the specified buffer. The OS path is the same as
+ the "normal" path during backup. During restore, the
+ OS path name is the name stored on tape.
+
+ Modified: 8/15/1989
+
+ Returns: Error codes:
+ FS_BUFFER_TO_SMALL
+ SUCCESS
+
+ Notes:
+
+ See also: $/SEE( GEN_GetOSFnameFDB() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 GEN_GetOSPathDDB(
+ FSYS_HAND fsh, /* I - file system handle */
+ DBLK_PTR dblk, /* I - Descriptor block to get path from */
+ CHAR_PTR buf ) /*I/O- path to read (or to write) */
+{
+ (void)fsh;
+
+ memcpy( buf, dblk->com.os_name->name, dblk->com.os_name->name_size ) ;
+
+ return SUCCESS ;
+}
+/**/
+/**
+
+ Name: GEN_GetFileVerFDB()
+
+ Description: Since DOS does not support file versions, this
+ function simply sets the version number to 0.
+
+ Modified: 8/15/1989
+
+ Returns: SUCCESS
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 GEN_GetFileVerFDB( dblk, version )
+DBLK_PTR dblk ;
+UINT32 *version ;
+{
+ (VOID) dblk ;
+ *version = 0 ;
+ return SUCCESS ;
+}
+/**/
+/**
+
+ Name: GEN_GetCdateDBLK()
+
+ Description: Pretend Creation date is same as Modify date
+
+ Modified: 8/15/1989
+
+ Returns: SUCCESS
+
+ Notes:
+
+
+ See also: $/SEE( GEN_ModBdate(), GEN_GetMdate(), GEN_ModAdate() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 GEN_GetCdateDBLK( dblk, buf )
+DBLK_PTR dblk ; /* I - Descriptor block to get creation date */
+DATE_TIME_PTR buf ; /*I/O- createion date to read (or to write) */
+{
+ GEN_DBLK_PTR ddblk ;
+
+ ddblk = (GEN_DBLK_PTR) dblk ;
+
+ *buf = ddblk->cdate ;
+
+ return SUCCESS ;
+}
+
+/**/
+/**
+
+ Name: GEN_GetMdateDBLK()
+
+ Description: This function copies the modified date/time into (or out of)
+ the provided buffer.
+
+ Modified: 8/15/1989
+
+ Returns: SUCCESS
+
+ Notes:
+
+ See also: $/SEE( GEN_GetCdate(), GEN_ModBdate(), GEN_ModAdate() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 GEN_GetMdateDBLK( dblk, buf )
+DBLK_PTR dblk ; /* I - Descriptor block to get creation date */
+DATE_TIME_PTR buf ; /* O - modify date to write */
+{
+ GEN_DBLK_PTR ddblk ;
+
+ ddblk = (GEN_DBLK_PTR) dblk ;
+
+ *buf = ddblk->mdate ;
+ return SUCCESS ;
+}
+
+
+/**/
+/**
+
+ Name: GEN_ModBdateDBLK()
+
+ Description: This function copies the backup date/time into (or out of)
+ the provided buffer.
+
+ Modified: 8/15/1989
+
+ Returns: SUCCESS
+
+ Notes:
+
+ See also: $/SEE( GEN_GetCdate(), GEN_GetMdate(), GEN_ModAdate() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 GEN_ModBdateDBLK(
+BOOLEAN set_it, /* I - TRUE if setting creation date, FALSE if getting */
+DBLK_PTR dblk, /* I - Descriptor block to get creation date */
+DATE_TIME_PTR buf ) /*I/O- createion date to read (or to write) */
+{
+
+ GEN_DBLK_PTR ddblk ;
+
+ ddblk = (GEN_DBLK_PTR) dblk ;
+
+ if ( set_it ) {
+ ddblk->cdate = *buf ;
+ } else {
+ *buf = ddblk->cdate ;
+ }
+ return SUCCESS ;
+}
+/**/
+/**
+
+ Name: GEN_ModAdateDBLK()
+
+ Description: This function copies the access date/time into (or out ot )
+ the provided buffer.
+
+ Modified: 8/15/1989
+
+ Returns: SUCCESS
+
+ Notes:
+
+ See also: $/SEE( GEN_GetCdate(), GEN_GetMdate(), GEN_ModBdate() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 GEN_ModAdateDBLK(
+BOOLEAN set_it, /* I - TRUE if setting creation date, FALSE if getting */
+DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+DATE_TIME_PTR buf ) /*I/O- createion date to read (or to write) */
+{
+ (VOID) dblk;
+
+ if ( ! set_it ) {
+ buf->date_valid = FALSE;
+ }
+
+ return SUCCESS ;
+}
+/**/
+/**
+
+ Name: GEN_GetTotalSizeDBLK()
+
+ Description: This function returns the total size of a DBLK. This is
+ the sum of the sizes of all the data forks for the object.
+
+
+ Modified: 8/15/1989
+
+ Returns: Total number of data bytes.
+
+**/
+/* begin declaration */
+// UINT64 GEN_GetTotalSizeDBLK( fsh, dblk )
+// FSYS_HAND fsh ; /* I - File system handle */
+// DBLK_PTR dblk ; /* I - Descriptor block to get generic data size for */
+// {
+// GEN_DBLK_PTR ddblk;
+//
+// (VOID) fsh ;
+//
+// ddblk = (GEN_DBLK_PTR) dblk;
+//
+// return ddblk->size ;
+//
+// }
+/**/
+
+/**
+
+ Name: GEN_GetDisplaySizeDBLK()
+
+ Description: This function returns the displayable size of a DBLK.
+ For a file, this is the file size. For a directory this is
+ always 0.
+
+ Modified: 21-Jan-92
+
+ Returns: Number of generic data bytes.
+
+**/
+/* begin declaration */
+UINT64 GEN_GetDisplaySizeDBLK( fsh, dblk )
+FSYS_HAND fsh ; /* I - File system handle */
+DBLK_PTR dblk ; /* I - Descriptor block to get generic data size for */
+{
+ GEN_DBLK_PTR ddblk = (GEN_DBLK_PTR)dblk;
+
+ (VOID)fsh ;
+
+ return ddblk->disp_size;
+}
+/**/
+/**
+
+ Name: GEN_ModAttribDBLK()
+
+ Description: This function copies the generic attributes into
+ (or out of) the specified DBLK.
+
+ Modified: 8/15/1989
+
+ Returns: SUCCESS
+
+ Notes: This only supports FDBs and DDBs. This should be called
+ by the FS_... function NOT by a macro.
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 GEN_ModAttribDBLK(
+BOOLEAN set_it, /* I - TRUE if we are seting data */
+DBLK_PTR dblk, /*I/O- dblk to read or write data from */
+UINT32 *attrib ) /*I/O- attributre read or written */
+{
+ GEN_DBLK_PTR ddblk ;
+
+ ddblk = (GEN_DBLK_PTR) dblk;
+
+ if ( set_it ) {
+ ddblk->tape_attribs = *attrib ;
+
+ } else {
+ *attrib = ddblk->tape_attribs ;
+ }
+ return SUCCESS ;
+}
+/**/
+/**
+
+ Name: GEN_GetObjTypeDBLK()
+
+ Description: This function looks at the os_id in the provided DBLK
+ and returns the type of the object.
+
+ Modified: 8/16/1989
+
+ Returns: SUCCESS
+
+ Notes: If the os_id is unknown then type is UNKNOWN_OBJECT
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 GEN_GetObjTypeDBLK( dblk, type )
+DBLK_PTR dblk ; /* I - Descriptor block to get type of */
+OBJECT_TYPE *type ; /* O - type of DBLK */
+{
+ GEN_DBLK_PTR ddblk ;
+
+ ddblk = (GEN_DBLK_PTR) dblk;
+
+ msassert( type != NULL );
+
+ *type = ddblk->obj_type ;
+
+ return( SUCCESS ) ;
+}
+
+/**/
+/**
+
+ Name: GEN_SetObjTypeDBLK()
+
+ Description: This function set the os_id in the provided DBLK
+
+ Modified: 8/16/1989
+
+ Returns: SUCCESS
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 GEN_SetObjTypeDBLK( dblk, type )
+DBLK_PTR dblk ; /* I - Descriptor block to set type of */
+OBJECT_TYPE type ; /* I - type of DBLK */
+{
+ GEN_DBLK_PTR ddblk ;
+
+ ddblk = (GEN_DBLK_PTR) dblk ;
+
+ ddblk->obj_type = type ;
+
+ return( SUCCESS ) ;
+}
+
+/**/
+/**
+
+ Name: GEN_GetOS_InfoDBLK()
+
+ Description: This function returns the OS info for the DOS
+ file system
+
+ Modified: 9/11/1989
+
+ Returns: Error Code
+ FS_BUFFER_TO_SMALL
+ SUCCESS
+
+ Notes: This file system has no OS info.
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+#ifdef GEN_FS_WRITE
+INT16 GEN_GetOS_InfoDBLK( dblk, os_info, size )
+DBLK_PTR dblk ; /* I - DBLK to get the info from */
+CHAR_PTR os_info ; /* O - Buffer to place data */
+INT16 *size ; /*I/O- Buffer size / data length */
+{
+ dblk ;
+ os_info ;
+
+ *size = 0 ;
+ return SUCCESS ;
+}
+#endif
+/**/
+/**
+
+ Name: GEN_GetActualSizeDBLK
+
+ Description: This function returns the actual size of a DBLK.
+
+ Modified: 9/11/1989
+
+ Returns: The number of bytes
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 GEN_GetActualSizeDBLK( fsh, dblk )
+FSYS_HAND fsh ;
+DBLK_PTR dblk ;
+{
+
+ GEN_DBLK *ddb ;
+ INT16 size ;
+
+ (VOID) fsh ;
+
+ size = sizeof( GEN_DBLK ) ;
+ ddb = (GEN_DBLK *)dblk ;
+
+ switch( dblk->blk_type ) {
+
+ case DDB_ID:
+ case FDB_ID :
+ break;
+
+ case IDB_ID :
+ size += ddb->os_part_name ;
+ break ;
+
+ default:
+ size = 0 ;
+ break ;
+
+ }
+
+ return size ;
+}
+
+/**/
+/**
+
+ Name: GEN_SetOwnerId()
+
+ Description: does nothing
+
+ Modified: 10/2/1989
+
+ Returns: none
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID GEN_SetOwnerId( fsh, dblk, id )
+FSYS_HAND fsh ; /* I - File system handle */
+DBLK_PTR dblk ; /* O - DBLK to modify */
+UINT32 id ; /* I - value to set it to */
+{
+ (VOID) fsh ;
+ (VOID) dblk ;
+ (VOID) id ;
+}
+
+/**/
+/**
+
+ Name: GEN_ProcessDDB()
+
+ Description: This function allways returns TRUE to
+ specify that directories should be restored even if
+ if there are no file to restore into the directory.
+
+ Modified: 10/23/1989
+
+ Returns: TRUE
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+BOOLEAN GEN_ProcessDDB( fsh, ddb )
+FSYS_HAND fsh; /* I - file system handle */
+DBLK_PTR ddb; /* I - Directory information */
+{
+ (VOID) fsh;
+ (VOID) ddb;
+ return TRUE ;
+}
+
+/**/
+/**
+
+ Name: GEN_SpecExcludeObj
+
+ Description: This function allways returns false to specify that
+ the object passed in should NOT be exclude.
+
+ Modified: 1/10/1990
+
+ Returns: FS_NORMAL_FILE because this file system has no special
+ files.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 GEN_SpecExcludeObj( fsh, ddb, fdb )
+FSYS_HAND fsh; /* I - File system handle */
+DBLK_PTR ddb; /* I - Descriptor block of ddb */
+DBLK_PTR fdb ; /* I - Descriptor block of fdb */
+{
+ (VOID) fsh ;
+ (VOID) ddb;
+ (VOID) fdb ;
+
+ return FS_NORMAL_FILE ;
+}
+/**/
+/**
+
+ Name: GEN_SetDataSize()
+
+ Description: Stub function
+
+ Modified: 1/12/1990
+
+ Returns: SUCCESS
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 GEN_SetDataSize( fsh, ddb, size )
+FSYS_HAND fsh ; /* I - File system handle */
+DBLK_PTR ddb ; /* I - Descriptor block of ddb */
+UINT32 size ; /* I - new size */
+{
+ (VOID) fsh;
+ (VOID) ddb;
+ (VOID) size ;
+
+ return SUCCESS ;
+}
+
+INT16 GEN_FindClose( fsh, dblk )
+FSYS_HAND fsh;
+DBLK_PTR dblk ;
+{
+ (VOID) fsh ;
+ (VOID) dblk ;
+
+ return SUCCESS ;
+}
+
+INT16 GEN_DupBlk( FSYS_HAND fsh, DBLK_PTR db_org, DBLK_PTR db_dup )
+{
+ *db_dup = *db_org ;
+
+ return FS_SetupOSPathOrNameInDBLK( fsh,
+ db_dup,
+ (BYTE_PTR)db_org->com.os_name->name,
+ db_org->com.os_name->name_size ) ;
+}
diff --git a/private/utils/ntbackup/src/gname.c b/private/utils/ntbackup/src/gname.c
new file mode 100644
index 000000000..67987071f
--- /dev/null
+++ b/private/utils/ntbackup/src/gname.c
@@ -0,0 +1,338 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: gname.c
+
+
+ Description: This file contains code to get the device name and
+ volume name for the given DLE.
+
+
+ $Log: M:/LOGFILES/GNAME.C_V $
+
+ Rev 1.20 15 Jan 1994 19:23:10 BARRY
+Call SetupOSPathOrName with BYTE_PTRs instead of CHAR_PTRs
+
+ Rev 1.19 24 Nov 1993 15:16:54 BARRY
+Changed CHAR_PTR in I/O function to BYTE_PTR
+
+ Rev 1.18 17 Aug 1993 01:23:18 GREGG
+Always return TRUE from IsBlkComplete if block type is CFDB.
+
+ Rev 1.17 24 Apr 1993 17:23:44 BARRY
+Added SizeofDevName function.
+
+ Rev 1.16 01 Mar 1993 16:43:28 TIMN
+Added header to resolve linking errors
+
+ Rev 1.15 29 Dec 1992 13:32:32 DAVEV
+unicode fixes (3)
+
+ Rev 1.14 07 Dec 1992 14:55:18 STEVEN
+Microsoft updates
+
+ Rev 1.13 02 Dec 1992 10:47:10 CHUCKB
+Took out unreferenced local.
+
+ Rev 1.12 11 Nov 1992 22:49:06 STEVEN
+This is Gregg checking files in for Steve. I don't know what he did!
+
+ Rev 1.10 11 Nov 1992 10:43:40 STEVEN
+fix os_name for gen_fs
+
+ Rev 1.9 06 Oct 1992 13:24:38 DAVEV
+Unicode strlen verification
+
+ Rev 1.8 25 Sep 1992 10:24:28 CHUCKB
+Added sinfo to GEN_CompleteBLK().
+
+ Rev 1.7 01 Sep 1992 11:25:00 TIMN
+Changed os_id and os_ver back
+
+ Rev 1.6 12 Aug 1992 14:57:26 BARRY
+Changed default os_id and os_ver.
+
+ Rev 1.5 05 Aug 1992 11:01:30 DON
+removed warnings
+
+ Rev 1.4 15 May 1992 16:39:04 STEVEN
+temp add block complete functions
+
+ Rev 1.3 05 May 1992 17:19:20 STEVEN
+fixed typos and misc bugs
+
+ Rev 1.2 03 Mar 1992 16:16:42 STEVEN
+added function for initializeing defalut make block
+
+ Rev 1.1 16 Dec 1991 17:26:48 STEVEN
+move common functions to tables
+
+ Rev 1.0 10 Dec 1991 09:06:54 STEVEN
+Initial revision.
+
+**/
+#include <string.h>
+#include <stdio.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "stdwcs.h"
+
+#include "msassert.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+
+/**/
+/**
+
+ Name: GEN_DeviceDispName()
+
+ Description: This function gets the displayable device name for
+ a DLE. This name is displayed for drive select.
+
+ Modified: 9/13/1989
+
+ Returns: SUCCESS
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+INT16 GEN_DeviceDispName( dle, dev_name, size, type )
+GENERIC_DLE_PTR dle;
+CHAR_PTR dev_name;
+INT16 size ;
+INT16 type ;
+{
+ (VOID)type;
+
+ if ( size < 6 * sizeof (CHAR) ) {
+ return FS_BUFFER_TO_SMALL ;
+ }
+
+ if ( ( dle->type & HAND_MADE_MASK ) ) {
+ strncpy ( dev_name, dle->info.user->vol_name, size / sizeof (CHAR) ) ;
+ dev_name[(size-1)/sizeof (CHAR)] = TEXT('\0') ;
+ return ( SUCCESS ) ;
+ }
+
+ strncpy( dev_name, dle->device_name, size / sizeof (CHAR) ) ;
+ dev_name[(size-1)/sizeof (CHAR)] = TEXT('\0') ;
+ return SUCCESS ;
+}
+/**/
+/**
+
+ Name: GEN_GetVolName()
+
+ Description: This function coppies the volume name
+ of the specified drive to the buffer provided.
+
+ Modified: 12/4/1991 9:45:49
+
+**/
+VOID GEN_GetVolName( dle, buffer )
+GENERIC_DLE_PTR dle;
+CHAR_PTR buffer ;
+{
+ if ( dle->type & HAND_MADE_MASK ) {
+ strcpy( buffer, dle->info.user->vol_name ) ;
+
+ } else {
+ sprintf( buffer, TEXT("%s"), dle->device_name ) ;
+ }
+}
+
+/**/
+/**
+
+ Name: GEN_SizeofVolName()
+
+ Description: This function returns the size of the volume name
+ which will be created by DLE_GetVolName()
+
+ Modified: 12/4/1991 11:14:25
+
+ Returns: size of string including \0;
+
+**/
+INT16 GEN_SizeofVolName( dle )
+GENERIC_DLE_PTR dle ;
+{
+ INT16 size ;
+
+ if ( dle->type & HAND_MADE_MASK ) {
+ size = (INT16)(strsize( dle->info.user->vol_name ) ) ;
+
+ } else {
+ size = (INT16)(strsize ( dle->device_name )) ;
+ }
+
+ return( size ) ;
+}
+
+/**/
+/**
+
+ Name: GEN_SizeofDevName()
+
+ Description: Returns the size of the device name returned
+ by DLE_GetDeviceName.
+
+ Modified: 20-Apr-93
+
+ Returns: size of device name string, in bytes, including
+ terminating null character.
+
+**/
+INT16 GEN_SizeofDevName( dle )
+GENERIC_DLE_PTR dle ;
+{
+ return strsize( dle->device_name );
+}
+
+/**/
+/**
+
+ Name: GEN_MakePath()
+
+ Description: This function is used to create a test string which
+ can be used as a path specifier in a script file.
+
+ Modified: 12/4/1991 14:57:3
+
+ Returns: Error code
+ FS_BUFFER_TO_SMALL
+ SUCCESS
+
+ Notes:
+
+**/
+INT16 GEN_MakePath( buf, bsize, dle, path, psize, fname )
+CHAR_PTR buf; /* O - buffer to place path string into */
+INT16 bsize ; /* I - size of above buffer */
+GENERIC_DLE_PTR dle ; /* I - Drive the selection is from */
+CHAR_PTR path ; /* I - path string in generic format */
+INT16 psize ; /* I - size of above path */
+CHAR_PTR fname ; /* I - null terminated file name */
+{
+ INT16 cb_dev_len = 0 ;
+ INT16 ret_val = SUCCESS ;
+ CHAR_PTR c_ptr ;
+
+ if( dle != NULL ) {
+ cb_dev_len = (INT16)strsize( dle->device_name ) ;
+ }
+
+ /* Check to see whether the buffer to store the path is large enough */
+ if( bsize < (INT16)( psize + strsize( fname ) + cb_dev_len ) ) {
+ ret_val = FS_BUFFER_TO_SMALL ;
+ } else {
+
+ if( dle != NULL ) {
+ strcpy( buf, dle->device_name ) ;
+ } else {
+ *buf = TEXT('\0') ;
+ }
+
+ if( psize != sizeof (CHAR) ) {
+ strcat( buf, TEXT("\\") ) ;
+ }
+
+ c_ptr = path ;
+ while( c_ptr < path + psize / sizeof (CHAR) ) {
+ strcat( buf, c_ptr ) ;
+ strcat( buf, TEXT("\\") ) ;
+ c_ptr += strlen( c_ptr ) + 1 ;
+ }
+
+ if ( fname != NULL ) {
+ strcat( buf, fname ) ;
+ }
+ }
+
+ return ret_val ;
+}
+
+/**/
+/**
+
+ Name: GEN_InitMakeData()
+
+ Description: This function is used to initialize the parameter block
+ which is passed to CreateDBLK.
+
+ Modified: 12/4/1991 14:57:3
+
+ Returns: NONE
+
+ Notes:
+
+**/
+VOID GEN_InitMakeData(
+FSYS_HAND fsh,
+INT16 blk_type,
+CREATE_DBLK_PTR data ) {
+
+ (VOID)fsh ;(VOID)blk_type;
+
+ data->v.std_data.os_id = FS_PC_DOS ;
+ data->v.std_data.os_ver = FS_PC_DOS_VER ;
+ return ;
+}
+
+
+BOOLEAN GEN_IsBlkComplete( FSYS_HAND fsh, DBLK_PTR dblk )
+{
+ (void)fsh;
+
+ if( dblk->blk_type != CFDB_ID && dblk->com.os_name == NULL ) {
+ return FALSE ;
+ } else {
+ return TRUE ;
+ }
+
+}
+
+INT16 GEN_CompleteBlk( FSYS_HAND fsh, DBLK_PTR dblk, BYTE_PTR buffer, UINT16 *size, STREAM_INFO_PTR s_info )
+{
+ INT16 ret_val ;
+ STREAM_INFO_PTR stream_info ;
+ BYTE_PTR stream_data ;
+
+ ret_val = FS_FillBufferWithStream( fsh, dblk, buffer, size, s_info );
+
+ if ( ret_val == FS_STREAM_COMPLETE )
+ {
+ /* buffer has been filled */
+ /* lets set up the buffers */
+
+ FS_GetStreamInfo( fsh, dblk, &stream_info, &stream_data ) ;
+
+ if ( FS_GetStrmSizeHi( stream_info ) != 0 )
+ {
+ ret_val = OUT_OF_MEMORY;
+ }
+ else
+ {
+
+ ret_val = FS_SetupOSPathOrNameInDBLK( fsh,
+ dblk,
+ stream_data,
+ (UINT16)FS_GetStrmSizeLo( stream_info ) ) ;
+ }
+ }
+
+ return ret_val ;
+}
+
+VOID GEN_ReleaseBlk( FSYS_HAND fsh, DBLK_PTR dblk ) {
+
+ FS_ReleaseOSPathOrNameInDBLK( fsh, dblk ) ;
+
+ return ;
+}
diff --git a/private/utils/ntbackup/src/gsize.c b/private/utils/ntbackup/src/gsize.c
new file mode 100644
index 000000000..a3746e9a6
--- /dev/null
+++ b/private/utils/ntbackup/src/gsize.c
@@ -0,0 +1,181 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: gsize.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains code to get the size of the
+ variable length fields in FDBs and DDBs
+
+
+ $Log: M:/LOGFILES/GSIZE.C_V $
+
+ Rev 1.7 24 Nov 1993 15:17:16 BARRY
+Unicode fixes
+
+ Rev 1.6 01 Mar 1993 16:43:44 TIMN
+Added header to resolve linking errors
+
+ Rev 1.5 02 Dec 1992 17:05:36 CHUCKB
+Fixed compiler warning.
+
+ Rev 1.4 11 Nov 1992 10:43:38 STEVEN
+fix os_name for gen_fs
+
+ Rev 1.3 06 Oct 1992 13:24:56 DAVEV
+Unicode strlen verification
+
+ Rev 1.2 22 Jan 1992 10:22:14 STEVEN
+fix warnings for WIN32
+
+ Rev 1.1 24 Jul 1991 11:38:18 DAVIDH
+Corrected compiler warnings under Watcom.
+
+ Rev 1.0 09 May 1991 13:39:44 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include <string.h>
+
+#include "stdtypes.h"
+#include "stdwcs.h"
+
+#include "msassert.h"
+#include "fsys.h"
+#include "gendblk.h"
+#include "gen_fs.h"
+/* $end$ include list */
+
+
+/**/
+/**
+
+ Name: GEN_SizeofOSFname()
+
+ Description: This function returns the size of the file
+ name (as it appears on tape) contained in the FDB bassed in
+
+ Modified: 9/11/1989
+
+ Returns: number of bytes including terminating NULL.
+
+ Notes:
+
+ See also: $/SEE( GEN_SizeofPath(), GEN_SizeofFname() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 GEN_SizeofOSFname( fsh, fdb )
+FSYS_HAND fsh; /* I - file system in use */
+DBLK_PTR fdb ; /* I - dblk to get fname from */
+{
+ (VOID) fsh ;
+
+ msassert( fdb->blk_type == FDB_ID ) ;
+
+ return ( fdb->com.os_name->name_size ) ;
+}
+
+/**/
+/**
+
+ Name: GEN_SizeofPartName()
+
+ Description: This function returns the size of the partition
+ name (as it appears on tape).
+
+ Modified: 3/15/1990
+
+ Returns: number of bytes including terminating NULL.
+
+ Notes:
+
+ See also: $/SEE( GEN_SizeofOSPath(), GEN_SizeofOSFname() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 GEN_SizeofPartName( fsh, idb )
+FSYS_HAND fsh; /* I - file system in use */
+DBLK_PTR idb ; /* I - dblk to get fname from */
+{
+ INT16 size ;
+
+ (VOID) fsh ;
+
+ msassert( idb->blk_type == IDB_ID ) ;
+
+ size = (INT16)strsize( (CHAR_PTR)(((INT8_PTR)idb) + ((GEN_DBLK *)idb)->os_part_name) );
+
+ return size ;
+}
+
+/**/
+/**
+
+ Name: GEN_SizeofOSPath()
+
+ Description: This function return the size of the path saved in the
+ DDB.
+
+ Modified: 9/11/1989
+
+ Returns: Number of bytes in path string
+
+ Notes:
+
+ See also: $/SEE( GEN_SizeofPath(), GEN_SizeofFname() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 GEN_SizeofOSPath( fsh, ddb )
+FSYS_HAND fsh ; /* I - File system handle */
+DBLK_PTR ddb ; /* I - DBLK to get path size from */
+{
+ (VOID) fsh ;
+ msassert( ddb->blk_type == DDB_ID ) ;
+
+ return ( ddb->com.os_name->name_size ) ;
+}
+
+
+/**/
+/**
+
+ Name: GEN_SizeofOSInfo()
+
+ Description: This function returns the size of the OS info for
+ an FDB or a DDB
+
+ Modified: 9/11/1989
+
+ Returns: Size in bytes.
+
+ Notes:
+
+ See also: $/SEE( GEN_SizeofFname(), GEN_SizeofPath() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+#ifdef GEN_FS_WRITE
+INT16 GEN_SizeofOSInfo( fsh, dblk)
+FSYS_HAND fsh ; /* I - File system handle */
+DBLK_PTR dblk; /* I - DBLK to get size of OS info for */
+{
+ fsh ;
+ dblk ;
+
+ return 0 ;
+}
+#endif
+
diff --git a/private/utils/ntbackup/src/gtnxtdle.c b/private/utils/ntbackup/src/gtnxtdle.c
new file mode 100644
index 000000000..136187f74
--- /dev/null
+++ b/private/utils/ntbackup/src/gtnxtdle.c
@@ -0,0 +1,1032 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: gtnxtdle.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: this file contains the
+
+
+ $Log: M:/LOGFILES/GTNXTDLE.C_V $
+
+ Rev 1.36 24 Nov 1993 14:38:24 BARRY
+Unicode fixes
+
+ Rev 1.35 28 Oct 1993 13:21:08 DON
+Fixed where calls to FS_FindObjClose on non-SUCCESSful returns values
+was called. The code was never being executed due to 'break' or
+'continue' directives above conditional.
+
+ Rev 1.34 29 Sep 1993 18:24:58 BARRY
+Send the DBLK with ACCESS_DENIED.
+
+ Rev 1.33 29 Sep 1993 16:59:12 BARRY
+Upon FS error in GetADir, send an access denied message to the UI.
+
+ Rev 1.32 29 Sep 1993 13:42:06 MARILYN
+We needed to call FS_FindObjClose on non-SUCCESSful returns values
+from FS_FindFirst and FS_FindNext
+
+ Rev 1.31 27 Jul 1993 17:34:24 BARRY
+Handle errors from FindFirst/Next a little differently.
+
+ Rev 1.30 26 Jul 1993 14:52:52 CARLS
+added code for comm failure
+
+ Rev 1.29 16 Jul 1993 09:05:22 DON
+We must set the name space in the file system handle before calling
+FS_ChangeDir so the file system has a clue as to what the current
+name space is for a Dir Path. It will be saved in the DIR_PATH structure
+along with the Dir Path.
+
+ Rev 1.28 23 Apr 1993 16:43:48 CHARLIE
+Initialize BOOLEANs find_error and getinfo_error
+
+ Rev 1.27 11 Mar 1993 16:06:10 STEVEN
+fix bug found by PLUNGER
+
+ Rev 1.26 14 Jan 1993 13:33:00 STEVEN
+added stream_id to error message
+
+ Rev 1.25 24 Nov 1992 16:39:42 STEVEN
+fix loose name structures
+
+ Rev 1.24 13 Nov 1992 10:06:44 STEVEN
+UNICODE !
+
+ Rev 1.23 11 Nov 1992 22:49:02 STEVEN
+This is Gregg checking files in for Steve. I don't know what he did!
+
+ Rev 1.22 02 Oct 1992 16:28:54 BARRY
+Fixes so we don't stop processing a directory when a GetInfo fails.
+
+ Rev 1.21 23 Jul 1992 16:44:12 STEVEN
+fix warnings
+
+ Rev 1.20 23 Jul 1992 11:58:16 STEVEN
+fix warnings
+
+ Rev 1.19 09 Jul 1992 13:59:46 STEVEN
+BE_Unicode updates
+
+ Rev 1.18 26 May 1992 15:37:14 TIMN
+LP_InitPDL hard coded for ANSI data
+
+ Rev 1.17 21 May 1992 17:16:58 TIMN
+Convert CHARs to INT8
+
+ Rev 1.16 13 May 1992 12:39:10 TIMN
+Added TEXT() macro to literals, but not msassert literals
+
+ Rev 1.15 13 May 1992 12:01:12 STEVEN
+40 format changes
+
+ Rev 1.14 16 Mar 1992 16:20:24 STEVEN
+added support to release DBLK for 40 format
+
+ Rev 1.13 10 Mar 1992 16:04:38 STEVEN
+make lp_add_a_dir faster
+
+ Rev 1.12 28 Feb 1992 10:37:10 GREGG
+Steve fixed bug involving backing up Image and nonimage sets from one BSD list.
+
+ Rev 1.11 16 Jan 1992 15:11:48 STEVEN
+fix warnings for WIN32
+
+ Rev 1.10 14 Nov 1991 17:18:50 STEVEN
+was incorrectly adding parent dirs
+
+ Rev 1.9 03 Sep 1991 15:46:08 STEVEN
+LP_PathComp() was returning >0 & <0 not +1 & -1
+
+ Rev 1.8 27 Aug 1991 10:18:32 STEVEN
+was only backing up bindery
+
+ Rev 1.7 23 Aug 1991 16:23:08 DON
+was never calling get info
+
+ Rev 1.6 15 Aug 1991 13:46:18 STEVEN
+special blocks returned as NULL
+
+ Rev 1.5 01 Aug 1991 17:07:56 STEVEN
+We backed up directories multiple times
+
+ Rev 1.4 21 Jun 1991 13:51:38 STEVEN
+new config unit
+
+ Rev 1.3 30 May 1991 09:13:26 STEVEN
+bsdu_err.h no longer exists
+
+ Rev 1.2 23 May 1991 12:50:58 STEVEN
+Changes due to changes from new BSDU
+
+ Rev 1.1 14 May 1991 14:28:04 DAVIDH
+Initialized 'pid' -- also cleared up Watcom compiler warning.
+
+ Rev 1.0 09 May 1991 13:39:46 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "msassert.h"
+#include "tbe_err.h"
+#include "tbe_defs.h"
+#include "tflproto.h"
+#include "bsdu.h"
+#include "fsys.h"
+#include "queues.h"
+#include "lis.h"
+#include "loops.h"
+#include "tfldefs.h"
+#include "loop_prv.h"
+#include "get_next.h"
+#include "vm.h"
+/* $end$ include list */
+
+/* declarations */
+typedef struct {
+ VM_PTR next ;
+ VM_PTR prev ;
+ BOOLEAN proc_dir_only ;
+ /* So we can tell FSYS what the name space is for a Dir Path */
+ UINT32 name_space;
+ INT16 psize ;
+ INT8 path[1] ;
+} DIR_PATH, *DIR_PATH_PTR ;
+
+
+static INT16 LP_PathComp( INT8_PTR, INT16, INT8_PTR, INT16 ) ;
+static INT16 LP_GetADir( LP_ENV_PTR, DBLK_PTR *, BOOLEAN * ) ;
+static INT16 LP_AddADir( LP_ENV_PTR, CHAR_PTR, INT16, BOOLEAN ) ;
+static INT16 LP_InitPDL( LP_ENV_PTR ) ;
+
+/**/
+/**
+
+ Name: LP_GetNextDLEBlock()
+
+ Description: this return uses the file system to obtain blocks to
+ match up against the fse list. blocks that match the
+ fse list are returned to the loops.
+
+ Modified: 5/20/1991 13:24:26
+
+ Returns: tape backup engine error
+ if no error is returned and bld_ptr == NULL then
+ there are no more files.
+
+ Notes:
+
+ See also: $/SEE( LP_BackupEngine() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 LP_GetNextDLEBlock(
+LP_ENV_PTR lp,
+DBLK_PTR *blk_ptr )
+{
+ INT16 error = SUCCESS ;
+ UINT16 finished = FALSE ;
+ FSE_PTR fse_ptr ;
+ FSYS_HAND fsh ;
+ UINT32 attrib ;
+ INT16 match_status ;
+ UINT32 pid ;
+ BSD_PTR bsd ;
+ INT16 find_error = SUCCESS ;
+ INT16 getinfo_error = SUCCESS ;
+
+ bsd = lp->lis_ptr->curr_bsd_ptr ;
+ *blk_ptr = NULL ;
+
+ fsh = lp->curr_fsys ;
+ pid = lp->lis_ptr->pid ;
+
+ /* start loop to find file */
+ while ( !finished ) {
+
+ /* this portion of the loop finds the special blocks to return */
+ if( lp->get_spcl && ( BSD_GetProcSpecialFlg( bsd ) ) ) {
+
+ if ( FS_GetBlockType( lp->curr_blk ) == FDB_ID ) {
+ FS_ReleaseDBLK( lp->curr_fsys, lp->curr_blk ) ;
+ }
+
+ if ( FS_GetSpecialDBLKS( fsh, lp->curr_blk, &lp->seq_num ) == FS_NO_MORE ) {
+ lp->get_spcl = FALSE ;
+ if( lp->after_bs ) {
+ break ;
+ }
+
+ } else {
+ *blk_ptr = lp->curr_blk ;
+ if ( FS_GetBlockType( lp->curr_blk ) == DDB_ID ) {
+ lp->empty_blk = lp->curr_ddb ;
+ lp->curr_ddb = lp->curr_blk ;
+ lp->curr_blk = lp->empty_blk ;
+
+ *blk_ptr = lp->curr_ddb ;
+ }
+ break ;
+ }
+
+ } else if( lp->get_spcl && lp->after_bs ) {
+ break ;
+ }
+
+
+ if( lp->start_new_dir ) {
+
+ if( lp->get_next_first_time ) {
+ /* build initial stack from fsl and sort it */
+
+ /*
+ NOTE:If this ever changes, the current way
+ were saving the name space for the
+ Dir Path must also change.
+ Assumptions are made as to the ordering
+ of the PDL Queue!
+ */
+ if ( (error = LP_InitPDL( lp )) != SUCCESS ) {
+ break ;
+ }
+ lp->get_next_first_time = FALSE ;
+ memset( lp->curr_ddb, 0, sizeof(DBLK) ) ;
+ }
+
+ if ( FS_GetBlockType( lp->curr_ddb ) == DDB_ID ) {
+
+ FS_ReleaseDBLK( lp->curr_fsys, lp->curr_ddb ) ;
+ }
+
+ if ( ( FS_GetBlockType( lp->curr_blk ) == DDB_ID ) ||
+ ( FS_GetBlockType( lp->curr_blk ) == FDB_ID ) ) {
+
+ FS_ReleaseDBLK( lp->curr_fsys, lp->curr_blk ) ;
+ }
+
+ error = LP_GetADir( lp, blk_ptr, &lp->start_new_dir ) ;
+
+ if( error == SUCCESS && *blk_ptr == NULL ) {
+
+ /* Now get special blocks to return back to loops */
+ lp->get_spcl = TRUE ;
+ lp->after_bs = TRUE ;
+ continue ;
+
+ }else if( error != SUCCESS ) {
+ /* break to return error */
+ break ;
+ }
+
+ if( FS_GetBlockType( lp->curr_blk ) == IDB_ID ) {
+ lp->get_first_file = FALSE ;
+ break ;
+ }
+
+ switch( BSD_MatchObj( bsd, &fse_ptr, fsh,
+ lp->curr_blk, NULL, FALSE ) ) {
+
+ case OUT_OF_MEMORY:
+ return OUT_OF_MEMORY ;
+
+ case BSD_PROCESS_OBJECT:
+ case BSD_PROCESS_ELEMENTS:
+ /* reset appropriate flags */
+ lp->start_new_dir = FALSE ;
+ lp->get_first_file = TRUE ;
+
+ /* copy directory into curr_ddb */
+ lp->empty_blk = lp->curr_ddb ;
+ lp->curr_ddb = lp->curr_blk ;
+ lp->curr_blk = lp->empty_blk ;
+ break ;
+
+ default:
+ lp->start_new_dir = TRUE ;
+ continue ;
+ }
+
+ }else{
+
+ find_error = SUCCESS;
+
+ if ( lp->send_saved_block ) {
+
+ lp->send_saved_block = FALSE ;
+
+ } else if( lp->get_first_file ) {
+
+ if ( ( FS_GetBlockType( lp->curr_blk ) == DDB_ID ) ||
+ ( FS_GetBlockType( lp->curr_blk ) == FDB_ID ) ) {
+
+ FS_ReleaseDBLK( lp->curr_fsys, lp->curr_blk ) ;
+ }
+
+ find_error = FS_FindFirstObj( fsh, lp->curr_blk, ALL_FILES );
+
+ if ( find_error == FS_COMM_FAILURE ) {
+
+ /* Send message to UI that we're stopping */
+ /* since the device is not responding. */
+
+ LP_MsgCommFailure( pid,
+ bsd,
+ fsh,
+ &lp->tpos,
+ lp->curr_ddb,
+ lp->curr_blk,
+ 0L );
+
+ *blk_ptr = NULL ;
+ error = SUCCESS ;
+ break ;
+ }
+
+ if ( (find_error == FS_NO_MORE) ||
+ ( find_error == FS_DEVICE_ERROR ) ||
+ (find_error == FS_ACCESS_DENIED) ) {
+
+ attrib = FS_GetAttribFromDBLK( fsh, lp->curr_ddb ) ;
+ attrib |= DIR_EMPTY_BIT ;
+ FS_SetAttribFromDBLK( fsh, lp->curr_ddb, attrib ) ;
+
+ if ( ( find_error == FS_DEVICE_ERROR ) ||
+ ( find_error == FS_ACCESS_DENIED ) ) {
+ LP_MsgError( pid,
+ bsd,
+ fsh,
+ &lp->tpos,
+ LP_ACCESS_DENIED_ERROR,
+ lp->curr_ddb,
+ NULL,
+ -1 ) ;
+ }
+
+ // Need to call find close to release find handles
+ FS_FindObjClose( fsh, lp->curr_blk ) ;
+
+ lp->start_new_dir = TRUE ;
+ *blk_ptr = lp->curr_ddb ;
+ break ;
+ }
+
+ if ( find_error != FS_DEVICE_ERROR ) {
+
+ attrib = FS_GetAttribFromDBLK( fsh, lp->curr_ddb ) ;
+ attrib &= ~(DIR_EMPTY_BIT) ;
+ FS_SetAttribFromDBLK( fsh, lp->curr_ddb, attrib ) ;
+
+ lp->send_saved_block = TRUE ;
+
+ break ;
+ }
+
+ } else {
+ if ( ( FS_GetBlockType( lp->curr_blk ) == DDB_ID ) ||
+ ( FS_GetBlockType( lp->curr_blk ) == FDB_ID ) ) {
+
+ FS_ReleaseDBLK( lp->curr_fsys, lp->curr_blk ) ;
+ }
+
+ find_error = FS_FindNextObj( fsh, lp->curr_blk ) ;
+
+ if ( find_error != SUCCESS ) {
+
+ if ( find_error == FS_COMM_FAILURE ) {
+
+ /* Send message to UI that we're stopping */
+ /* since the device is not responding. */
+
+ LP_MsgCommFailure( pid,
+ bsd,
+ fsh,
+ &lp->tpos,
+ lp->curr_ddb,
+ lp->curr_blk,
+ 0L );
+
+ *blk_ptr = NULL ;
+ error = SUCCESS ;
+ break ;
+
+ } else {
+
+ if ( find_error == FS_ACCESS_DENIED ) {
+ LP_MsgError( pid,
+ bsd,
+ fsh,
+ &lp->tpos,
+ LP_ACCESS_DENIED_ERROR,
+ lp->curr_ddb,
+ NULL,
+ -1 ) ;
+ }
+
+ // Need to call find close to release find handles
+ FS_FindObjClose( fsh, lp->curr_blk ) ;
+
+ lp->start_new_dir = TRUE ;
+ continue ;
+ }
+ }
+ }
+
+ lp->get_first_file = FALSE ;
+
+ if ( FS_GetBlockType( lp->curr_blk ) == DDB_ID ) {
+
+ switch( BSD_MatchObj( bsd, &fse_ptr, fsh,
+ lp->curr_blk, NULL, FALSE ) ) {
+
+ case OUT_OF_MEMORY:
+ return OUT_OF_MEMORY ;
+
+ case BSD_PROCESS_OBJECT:
+ case BSD_PROCESS_ELEMENTS:
+
+ if ( LP_AddADir( lp, NULL, (UINT16)0, FALSE ) != SUCCESS ) {
+ error = OUT_OF_MEMORY ;
+ finished = TRUE ;
+ } else {
+ FS_ReleaseDBLK( lp->curr_fsys, lp->curr_blk ) ;
+ }
+
+
+ break ;
+
+ case FSL_EMPTY:
+ return( FS_NO_MORE ) ;
+
+ case BSD_SKIP_OBJECT:
+ case BSD_SPECIAL_OBJECT:
+ break ;
+ }
+
+ } else {
+
+ if ( find_error == FS_DEVICE_ERROR )
+ {
+ getinfo_error = SUCCESS;
+ }
+ else
+ {
+ getinfo_error = FS_GetObjInfo( fsh, lp->curr_blk );
+ }
+
+ if ( (find_error != SUCCESS) || (getinfo_error != SUCCESS) )
+ {
+ INT16 theError = ((find_error != SUCCESS) ? find_error : getinfo_error);
+
+ if ( theError == FS_COMM_FAILURE )
+ {
+ /* Send message to UI that we're stopping */
+ /* since the device is not responding. */
+
+ LP_MsgCommFailure( pid,
+ bsd,
+ fsh,
+ &lp->tpos,
+ lp->curr_ddb,
+ lp->curr_blk,
+ 0L );
+
+ /* No point in trying any more for this dev. */
+ *blk_ptr = NULL;
+ error = SUCCESS;
+ break;
+ }
+ else
+ {
+ continue;
+ }
+
+ /**************************************************
+ In older backup engines, did something like:
+ LP_MsgAttrReadError( pid,
+ lp->curr_bsd_ptr,
+ fsh,
+ &lp->tpos,
+ lp->curr_blk ) ;
+ ***************************************************/
+ }
+
+ match_status = BSD_MatchObj( bsd, &fse_ptr, fsh,
+ lp->curr_ddb, lp->curr_blk, FALSE ) ;
+
+ switch( match_status ) {
+
+ case OUT_OF_MEMORY:
+ return OUT_OF_MEMORY ;
+
+ case BSD_PROCESS_OBJECT:
+ case BSD_PROCESS_ELEMENTS:
+
+ *blk_ptr = lp->curr_blk ;
+ finished = TRUE ;
+ break ;
+
+ case FSL_EMPTY:
+ return FS_NO_MORE ;
+
+ default:
+ break ;
+ }
+ }
+ }
+
+ }
+
+ return error ;
+}
+/**/
+/**
+
+ Name: LP_GetADir()
+
+ Description: this routine pulls a DIR_PATH off of the
+ pdl queue, changes into the directory,
+ and builds the ddb.
+
+ Modified: 7/14/1989
+
+ Returns: tape backup error
+
+ Notes: na
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 LP_GetADir(
+register LP_ENV_PTR lp,
+DBLK_PTR *blk_ptr,
+BOOLEAN *proc_dir_only )
+{
+ DIR_PATH_PTR dpath_ptr ;
+ INT16 error = SUCCESS ;
+ INT16 getError = SUCCESS ;
+ VM_PTR vm_temp ;
+ VM_HDL vmem_hand = lp->pdl_q->vm_hdl ;
+
+ *blk_ptr = NULL ;
+
+ while ( lp->pdl_q->pdl_head != NULL ) {
+
+ if ( lp->pdl_q->pdl_head == lp->pdl_q->vm_last_elem ) {
+ lp->pdl_q->vm_last_elem = (VM_PTR)NULL ;
+ }
+ dpath_ptr = VM_MemLock( vmem_hand, (VM_PTR)(lp->pdl_q->pdl_head), VM_READ_ONLY ) ;
+
+ *proc_dir_only = dpath_ptr->proc_dir_only ;
+
+ /* Tell FSYS what the name space is for this Dir Path */
+ FS_SetNameSpace( lp->curr_fsys, dpath_ptr->name_space );
+
+ error = FS_ChangeDir( lp->curr_fsys,
+ (CHAR_PTR)dpath_ptr->path,
+ dpath_ptr->psize ) ;
+
+ if ( error == SUCCESS ) {
+ getError = FS_GetCurrentDDB( lp->curr_fsys, lp->curr_blk ) ;
+ } else {
+ getError = SUCCESS;
+ }
+
+
+ vm_temp = dpath_ptr->next ;
+ VM_MemUnLock( vmem_hand, (VM_PTR)(lp->pdl_q->pdl_head ) ) ;
+
+ VM_Free( vmem_hand, (VM_PTR)(lp->pdl_q->pdl_head ) ) ;
+
+ lp->pdl_q->pdl_head = (VOID_PTR)vm_temp ;
+
+ if ( (error == SUCCESS) && (getError == SUCCESS) ) {
+ *blk_ptr = lp->curr_blk ;
+ break ;
+
+ } else {
+ if ( getError != SUCCESS ) {
+ LP_MsgError( lp->lis_ptr->pid,
+ lp->lis_ptr->curr_bsd_ptr,
+ lp->curr_fsys,
+ &lp->tpos,
+ LP_ACCESS_DENIED_ERROR,
+ lp->curr_blk,
+ NULL,
+ 0L );
+ }
+ error = SUCCESS ;
+ }
+
+ }
+
+ if (lp->pdl_q->pdl_head != NULL ) {
+ dpath_ptr = VM_MemLock( vmem_hand, (VM_PTR)(lp->pdl_q->pdl_head), VM_READ_WRITE ) ;
+
+ dpath_ptr->prev = (VM_PTR)NULL ;
+ VM_MemUnLock( vmem_hand, (VM_PTR)(lp->pdl_q->pdl_head ) ) ;
+ }
+
+ if( error != SUCCESS ) {
+ LP_MsgError( lp->lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr,
+ lp->curr_fsys, &lp->tpos, LP_OUT_OF_MEMORY_ERROR, NULL, NULL, 0L ) ;
+ }
+
+ return error ;
+}
+/**/
+/**
+
+ Name: LP_ClearPDL()
+
+ Description: this routine pulls all the DIR_PATHs off of the
+ pdl queue.
+
+ Modified: 7/14/1989
+
+ Returns: none
+
+ Notes: na
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID LP_ClearPDL(
+register LP_ENV_PTR lp )
+{
+ VM_PTR vm_dpath_ptr;
+ VM_PTR vm_temp;
+ DIR_PATH_PTR dpath_ptr ;
+ VM_HDL vmem_hand ;
+
+ if ( lp->pdl_q != NULL ) {
+ vmem_hand = lp->pdl_q->vm_hdl ;
+ vm_dpath_ptr = (VM_PTR)(lp->pdl_q->pdl_head);
+
+ while( vm_dpath_ptr != (VM_PTR)NULL ) {
+ dpath_ptr = VM_MemLock( vmem_hand, vm_dpath_ptr, VM_READ_ONLY ) ;
+ vm_temp = dpath_ptr->next;
+ VM_MemUnLock( vmem_hand, vm_dpath_ptr ) ;
+ VM_Free( vmem_hand, vm_dpath_ptr ) ;
+ vm_dpath_ptr = vm_temp;
+ }
+
+ free( lp->pdl_q ) ;
+ lp->pdl_q = NULL ;
+ }
+
+ return ;
+}
+
+
+static INT16 LP_InitPDL(
+LP_ENV_PTR lp )
+{
+ FSE_PTR fse ;
+ BOOLEAN first_include = TRUE ;
+ INT16 error = SUCCESS ;
+ CHAR_PTR path ;
+ INT8_PTR bp_path ;
+ INT16 psize ;
+ INT16 cchpsize ;
+
+ fse = BSD_GetFirstFSE( lp->lis_ptr->curr_bsd_ptr ) ;
+
+ while( !error && ( fse != NULL ) ) {
+
+ if ( FSE_GetOperType( fse ) == INCLUDE ) {
+
+ if ( first_include ) {
+ error = LP_AddADir( lp, TEXT(""), (UINT16)sizeof(CHAR), TRUE ) ;
+ first_include = FALSE ;
+ if ( error ) {
+ break ;
+ }
+ }
+
+ FSE_GetPath( fse, &bp_path, &psize ) ;
+ path = (CHAR_PTR)bp_path ;
+
+ error = LP_AddADir( lp, path, psize, FALSE ) ;
+
+ cchpsize = psize / sizeof(CHAR) ;
+
+ while ( (cchpsize > 0) && !error ) {
+ for ( cchpsize-=2 ;
+ (cchpsize > 0) && (path[cchpsize] != '\0');
+ cchpsize -- ) ;
+
+ if ( cchpsize > 0 ) {
+ error = LP_AddADir( lp,
+ path,
+ (INT16)( sizeof(CHAR) * (cchpsize + 1)),
+ TRUE ) ;
+ }
+ }
+ }
+
+ fse = BSD_GetNextFSE( fse ) ;
+ }
+
+ return error ;
+}
+/**/
+/**
+
+ Name: LP_AddADir()
+
+ Description: this routine adds a directory to the pdl,
+ checking for duplicates, inserts it in
+ inserts in the appropriate location.
+
+ Modified: 7/14/1989
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+BOOLEAN LP_AddADir(
+LP_ENV_PTR lp,
+CHAR_PTR path,
+INT16 size,
+BOOLEAN proc_dir_only )
+{
+ VM_PTR vm_pdl_elem ;
+ VM_PTR vm_prev_pdl_elem ;
+ DIR_PATH_PTR pdl_elem ;
+ DIR_PATH_PTR prev_pdl_elem ;
+ DIR_PATH_PTR new_dir_ptr ;
+ VM_PTR vm_new_dir_ptr ;
+ INT16 ret_val = SUCCESS ;
+ INT16 location ;
+ BOOLEAN done = FALSE ;
+ VM_HDL vmem_hand ;
+ DIR_PATH_PTR last_elem ;
+
+/**
+*** Open the VM manager
+***
+**/
+
+ if ( lp->pdl_q == NULL ) {
+
+ lp->pdl_q = malloc( sizeof( *(lp->pdl_q) ) ) ;
+
+ if ( lp->pdl_q != NULL ) {
+
+ lp->pdl_q->pdl_head = NULL ;
+ lp->pdl_q->vm_hdl = lp->lis_ptr->vmem_hand ;
+ lp->pdl_q->vm_last_elem = NULL ;
+
+ } else {
+ ret_val = OUT_OF_MEMORY ;
+ }
+ }
+
+ vmem_hand = lp->pdl_q->vm_hdl ;
+
+/**
+*** now create the new node
+***
+**/
+ if ( ret_val == SUCCESS ) {
+ if ( size == 0 ) {
+ size = FS_SizeofOSPathInDDB( lp->curr_fsys, lp->curr_blk ) ;
+ }
+
+ vm_new_dir_ptr = VM_Alloc( vmem_hand, (INT16)( sizeof(DIR_PATH) + size ) ) ;
+
+ if ( vm_new_dir_ptr == (VM_PTR)NULL ) {
+ ret_val = OUT_OF_MEMORY ;
+
+ } else {
+
+ new_dir_ptr = VM_MemLock( vmem_hand, vm_new_dir_ptr, VM_READ_WRITE ) ;
+ }
+ }
+
+ if ( ret_val == SUCCESS ) {
+
+ new_dir_ptr->next = new_dir_ptr->prev = (VM_PTR)NULL ;
+ new_dir_ptr->name_space = 0;
+ new_dir_ptr->psize = size ;
+ new_dir_ptr->proc_dir_only = proc_dir_only ;
+
+ if ( path == NULL ) {
+ FS_GetOSPathFromDDB( lp->curr_fsys, lp->curr_blk, (CHAR_PTR)new_dir_ptr->path ) ;
+ /* Save the name space for this Dir Path */
+ new_dir_ptr->name_space = FS_GetNameSpaceFromDBLK( lp->curr_blk );
+ } else {
+ memcpy( new_dir_ptr->path, path, size ) ;
+ }
+
+ path = (CHAR_PTR)new_dir_ptr->path ;
+
+ } else {
+
+ done = TRUE ;
+ }
+
+/**
+*** Enqueue the new node
+***
+**/
+ if ( ret_val == SUCCESS ) {
+
+ vm_pdl_elem = (VM_PTR)(lp->pdl_q->pdl_head) ;
+ vm_prev_pdl_elem = (VM_PTR)NULL ;
+
+ //
+ // if new item is > last item start at last item instead
+ // of first item.
+ //
+
+ if ( lp->pdl_q->vm_last_elem != NULL ) {
+
+ last_elem = VM_MemLock( vmem_hand,
+ (VM_PTR)(lp->pdl_q->vm_last_elem), VM_READ_WRITE ) ;
+
+ location = LP_PathComp( last_elem->path, last_elem->psize, (INT8_PTR)path, size ) ;
+
+ if ( location != PATH_AFTER ) {
+ vm_pdl_elem = (VM_PTR)lp->pdl_q->vm_last_elem ;
+ vm_prev_pdl_elem = last_elem->prev ;
+ }
+
+ VM_MemUnLock( vmem_hand, (VM_PTR)(lp->pdl_q->vm_last_elem) ) ;
+
+ }
+
+
+ while( !done ) {
+
+ ThreadSwitch() ;
+
+ if ( vm_pdl_elem == (VM_PTR)NULL ) {
+
+ if ( vm_prev_pdl_elem == (VM_PTR)NULL ) {
+ lp->pdl_q->pdl_head = (VOID_PTR)vm_new_dir_ptr ;
+
+ } else {
+ new_dir_ptr->prev = vm_prev_pdl_elem ;
+
+ prev_pdl_elem = VM_MemLock( vmem_hand, vm_prev_pdl_elem, VM_READ_WRITE ) ;
+ prev_pdl_elem->next = vm_new_dir_ptr ;
+
+ VM_MemUnLock( vmem_hand, vm_prev_pdl_elem ) ;
+ }
+
+ VM_MemUnLock( vmem_hand, vm_new_dir_ptr ) ;
+
+ break ;
+
+ } else {
+
+ pdl_elem = VM_MemLock( vmem_hand, vm_pdl_elem, VM_READ_WRITE ) ;
+
+ location = LP_PathComp( pdl_elem->path, pdl_elem->psize, (INT8_PTR)path, size ) ;
+
+ if( location == PATH_EQUAL ) {
+
+ if ( !proc_dir_only ) {
+ pdl_elem->proc_dir_only = FALSE ;
+ }
+ /*
+ We need the name space for the Dir Path in
+ the DBLK, not the path for the FSL!
+ */
+ pdl_elem->name_space = new_dir_ptr->name_space;
+
+ VM_MemUnLock( vmem_hand, vm_pdl_elem ) ;
+ VM_MemUnLock( vmem_hand, vm_new_dir_ptr ) ;
+ VM_Free ( vmem_hand, vm_new_dir_ptr ) ;
+ vm_new_dir_ptr = (VM_PTR)NULL ;
+
+ break ;
+
+ }else if( location == PATH_AFTER ) {
+
+ new_dir_ptr->next = vm_pdl_elem ;
+ new_dir_ptr->prev = pdl_elem->prev ;
+
+ pdl_elem->prev = vm_new_dir_ptr ;
+
+ if ( new_dir_ptr->prev != (VM_PTR)NULL ) {
+
+
+ prev_pdl_elem = VM_MemLock( vmem_hand, new_dir_ptr->prev,
+ VM_READ_WRITE ) ;
+
+ prev_pdl_elem->next = vm_new_dir_ptr ;
+
+ VM_MemUnLock( vmem_hand, new_dir_ptr->prev ) ;
+
+ } else {
+ lp->pdl_q->pdl_head = (VOID_PTR)vm_new_dir_ptr ;
+ }
+
+ VM_MemUnLock( vmem_hand, vm_pdl_elem ) ;
+
+ VM_MemUnLock( vmem_hand, vm_new_dir_ptr ) ;
+
+ break ;
+
+ } else {
+ vm_prev_pdl_elem = vm_pdl_elem ;
+ vm_pdl_elem = pdl_elem->next ;
+
+ if ( vm_prev_pdl_elem != (VM_PTR)NULL ) {
+ VM_MemUnLock( vmem_hand, vm_prev_pdl_elem ) ;
+ }
+ }
+ }
+ }
+ }
+ if ( vm_new_dir_ptr != (VM_PTR)NULL ) {
+ lp->pdl_q->vm_last_elem = (VOID_PTR)vm_new_dir_ptr ;
+ }
+
+ if ( ret_val != SUCCESS ) {
+ LP_MsgError( lp->lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, lp->curr_fsys, &lp->tpos, LP_OUT_OF_MEMORY_ERROR, NULL, NULL, 0L ) ;
+ LP_ClearPDL( lp ) ;
+ }
+ return ret_val ;
+}
+
+
+/**/
+/**
+
+ Name: LP_PathComp()
+
+ Desription: this routine compares two directory paths, and returns back whether they are equal,
+ less than, or greater than each other.
+
+ Modified: 7/14/1989
+
+ Returns: -1 is p1 is less than p2, 0 if equal, 1 if greater than
+
+ Notes: the path is a special format as follows:
+
+ \0[dir_spec]@
+
+ where:
+
+ dir_spec: directory_name\0
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 LP_PathComp(
+INT8_PTR p1,
+INT16 s1,
+INT8_PTR p2,
+INT16 s2 )
+{
+ INT16 result ;
+
+ result = (INT16)memicmp( p1, p2, ( ( s1 < s2 ) ? s1 : s2 ) ) ;
+
+ if ( result > 0 ) {
+ result = PATH_AFTER ;
+ } else if ( result < 0 ) {
+ result = PATH_BEFORE ;
+ } else {
+ result = PATH_EQUAL ;
+ }
+
+ if ( ( result == PATH_EQUAL ) && ( s1 != s2 ) ) {
+ result = (INT16)(( s1 > s2 ) ? PATH_AFTER : PATH_BEFORE) ;
+ }
+
+ return( result ) ;
+
+}
+
diff --git a/private/utils/ntbackup/src/gtnxttpe.c b/private/utils/ntbackup/src/gtnxttpe.c
new file mode 100644
index 000000000..0deae89d7
--- /dev/null
+++ b/private/utils/ntbackup/src/gtnxttpe.c
@@ -0,0 +1,1021 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: gtnxttpe.c
+
+ Date Updated: 5/22/1991 16:32:44
+
+ Description: this file contains the getnext routine
+ for Restore and Verify operations.
+
+
+ $Log: M:/LOGFILES/GTNXTTPE.C_V $
+
+ Rev 1.39.2.3 19 Jan 1994 12:49:56 BARRY
+Suppress warnings
+
+ Rev 1.39.2.2 11 Jan 1994 13:45:36 GREGG
+Changed asserts to mscasserts and fixed the code to deal with it.
+
+ Rev 1.39.2.1 15 Dec 1993 17:52:38 DON
+Save the DDB before we modify it. No files will match if we don't
+
+ Rev 1.39.2.0 01 Dec 1993 13:20:58 STEVEN
+Complete DBLK loop was not working correctly
+
+ Rev 1.39 08 Apr 1993 14:24:02 MIKEP
+Fix to remove assert that can now happen that QTC catalogs allow the
+root directory to be in them twice.
+
+
+ Rev 1.38 08 Mar 1993 18:32:26 DON
+Update for setting target ddb to allow redirected single file restore
+
+ Rev 1.37 14 Dec 1992 13:06:12 STEVEN
+failing on empty dirs
+
+ Rev 1.36 07 Dec 1992 14:18:12 STEVEN
+updates from msoft
+
+ Rev 1.35 24 Nov 1992 16:39:38 STEVEN
+fix loose name structures
+
+ Rev 1.34 04 Nov 1992 09:28:58 STEVEN
+fix initial receive
+
+ Rev 1.33 03 Nov 1992 10:09:10 STEVEN
+change the way we skip data
+
+ Rev 1.32 06 Oct 1992 13:23:52 DAVEV
+Unicode strlen verification
+
+ Rev 1.31 17 Sep 1992 09:26:42 STEVEN
+update for stream info
+
+ Rev 1.30 10 Sep 1992 09:30:18 STEVEN
+fix bugs in restore
+
+ Rev 1.29 23 Jul 1992 16:43:58 STEVEN
+fix warnings
+
+ Rev 1.28 23 Jul 1992 12:02:04 STEVEN
+fix warnings
+
+ Rev 1.27 09 Jul 1992 13:59:34 STEVEN
+BE_Unicode updates
+
+ Rev 1.26 09 Jun 1992 16:47:02 STEVEN
+was comparing aginst wrong block
+
+ Rev 1.25 27 May 1992 15:08:18 TIMN
+Fixed FFR_SUBS path compare
+
+ Rev 1.24 21 May 1992 17:18:06 TIMN
+Converted CHARs to INT8, str to mem
+
+ Rev 1.23 13 May 1992 11:54:12 TIMN
+Added TEXT() macro to literals, but not msassert literals
+
+ Rev 1.22 05 May 1992 17:19:12 STEVEN
+fixed typos and misc bugs
+
+ Rev 1.21 30 Apr 1992 16:32:16 BARRY
+Fixed setting of path in FDB.
+
+ Rev 1.20 16 Mar 1992 16:20:26 STEVEN
+added support to release DBLK for 40 format
+
+ Rev 1.19 13 Mar 1992 09:09:56 STEVEN
+40 tape format
+
+ Rev 1.18 11 Mar 1992 14:39:08 STEVEN
+was not properly restoring empty directories
+
+ Rev 1.17 16 Jan 1992 15:11:36 STEVEN
+fix warnings for WIN32
+
+ Rev 1.16 22 Oct 1991 15:44:02 STEVEN
+skip data for empty dir if process elements only
+
+ Rev 1.15 14 Oct 1991 11:31:08 STEVEN
+was trying to set path in FDB ?!?!
+
+ Rev 1.14 25 Sep 1991 20:42:54 GREGG
+Steve fixed read problem when last dir processed is empty.
+
+ Rev 1.13 04 Sep 1991 17:06:22 CARLS
+was appending root to path - bad idea
+
+ Rev 1.12 03 Sep 1991 15:36:12 CARLS
+ffr_last_fse was set to NULL before the end of operation
+
+ Rev 1.11 27 Aug 1991 17:28:34 STEVEN
+added BSD target dir support
+
+ Rev 1.10 27 Aug 1991 13:35:54 STEVEN
+would stop after one DDB
+
+ Rev 1.9 23 Aug 1991 16:17:44 STEVEN
+FFR error TRAP D ffr_last_fse uninitialized
+
+ Rev 1.8 27 Jun 1991 08:44:10 STEVEN
+fix return when LP_Finished called
+
+ Rev 1.7 21 Jun 1991 13:50:40 STEVEN
+new config unit
+
+ Rev 1.6 13 Jun 1991 15:23:24 STEVEN
+added support for ALL versions
+
+ Rev 1.5 11 Jun 1991 12:56:24 STEVEN
+LBAs now in virtual memory
+
+ Rev 1.4 30 May 1991 09:13:46 STEVEN
+bsdu_err.h no longer exists
+
+ Rev 1.3 24 May 1991 14:55:38 STEVEN
+complete changes for new getnext
+
+ Rev 1.2 23 May 1991 13:07:42 STEVEN
+Added New function headers
+
+ Rev 1.1 23 May 1991 12:52:18 STEVEN
+ReDesigned Target object processing
+
+ Rev 1.0 09 May 1991 13:39:48 HUNTER
+Initial revision.
+
+**/
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <string.h>
+#include <assert.h>
+#include "stdtypes.h"
+#include "std_err.h"
+#include "msassert.h"
+#include "tbe_err.h"
+#include "tbe_defs.h"
+#include "tflproto.h"
+#include "tfldefs.h"
+#include "beconfig.h"
+#include "bsdu.h"
+#include "fsys.h"
+#include "queues.h"
+#include "stdwcs.h"
+#include "loops.h"
+#include "loop_prv.h"
+#include "get_next.h"
+#include "be_debug.h"
+
+/***
+IDB - Image descriptor block
+ This data block contains a DOS disk image backup.
+DDB - Directory descriptor block
+ This data block contains a new directory path.
+FDB - File descriptor block
+ This data block contains a file in the current directory.
+CFDB - Corrupt file descriptor block
+ The previous data block was a file and was corrupt.
+***/
+
+#define FFR_NO_QUEUE 0
+#define FFR_POP 1
+#define FFR_SINGLE 2
+#define FFR_MULTI 3
+#define FFR_SUBS 4
+
+
+/****/
+static INT16 Get_an_FFR_DBLK( LP_ENV_PTR, INT16_PTR, FSE_PTR *, BOOLEAN_PTR );
+static INT16 LP_GetTheObject( LP_ENV_PTR lp, FSE_PTR *fse, BOOLEAN *match_val );
+static VOID LP_BuildTargetPath( LP_ENV_PTR lp, DBLK_PTR *dblk, BSD_PTR bsd, FSE_PTR fse ) ;
+static VOID ModifyFDB( LP_ENV_PTR lp, FSE_PTR fse, DBLK_PTR dblk ) ;
+static VOID ModifyDDB( LP_ENV_PTR lp, FSE_PTR fse, DBLK_PTR dblk ) ;
+static VOID ModifyDDBRoot( LP_ENV_PTR lp, CHAR_PTR path, INT16 psize, DBLK_PTR dblk ) ;
+static VOID CreateUniqueName( LP_ENV_PTR lp, DBLK_PTR dblk ) ;
+/**/
+/**
+
+ Name: LP_GetNextTPEBlock()
+
+ Description: this routine calls the tape
+
+ Modified: 7/18/1989
+
+ Returns: tape backup engine error
+
+ Notes: none
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 LP_GetNextTPEBlock(
+LP_ENV_PTR lp,
+DBLK_PTR *blk_ptr_ptr )
+{
+ INT16 error ;
+ DBLK_PTR temp_ptr ;
+ FSE_PTR fse_ptr ;
+ BOOLEAN end_of_lba = FALSE;
+ UINT32 attrib ;
+ INT16 match ;
+ BOOLEAN block_skipped = FALSE ;
+ BSD_PTR bsd_ptr;
+ FSYS_HAND fsh ;
+ UINT32 pid ;
+ BOOLEAN object_is_special ;
+ BE_CFG_PTR cfg ;
+
+ fsh = lp->curr_fsys ;
+ bsd_ptr = lp->lis_ptr->curr_bsd_ptr ;
+ pid = lp->lis_ptr->pid ;
+ cfg = BSD_GetConfigData( bsd_ptr ) ;
+ *blk_ptr_ptr = NULL ;
+
+ if( lp->rr.tf_message == TRR_END ) {
+ return NO_ERR ;
+ }
+
+ do {
+ *blk_ptr_ptr = NULL ;
+
+ /*** when we hit a new directory, we have to wait to see
+ if there are files in it before we restore it. By
+ then we have two blocks that need to be sent, the
+ directory and the file. So we send the directory
+ and queue up the file to be sent here. **/
+
+ if( lp->send_saved_block ) {
+
+ lp->send_saved_block = FALSE ;
+ lp->ignore_data_for_ddb = FALSE ;
+ *blk_ptr_ptr = lp->curr_blk ;
+ return NO_ERR ;
+ }
+
+ /** We have two data areas for holding blocks, one where
+ we throw new blocks and one which holds the directory
+ block for the current directory. If we got a new
+ directory block in our temp area, then swap the pointers
+ and make it our directory block. **/
+
+ if( FS_GetBlockType( lp->curr_blk ) == DDB_ID ) {
+
+ /** We have to release the old directory before we
+ can release our pointer to it. **/
+
+ if ( FS_GetBlockType( lp->curr_ddb ) == DDB_ID ) {
+ FS_ReleaseDBLK( fsh, lp->curr_ddb ) ;
+ }
+
+ temp_ptr = lp->curr_ddb ;
+ lp->curr_ddb = lp->curr_blk ;
+ lp->curr_blk = temp_ptr ;
+
+ }
+
+ /** get a new dblk from tape **/
+
+ error = Get_an_FFR_DBLK( lp, &match, &fse_ptr, &end_of_lba );
+ if ( error ) {
+ LP_FinishedOper( lp ) ;
+ *blk_ptr_ptr = NULL ;
+ return error ;
+ }
+
+ if ( end_of_lba == TRUE ) {
+ error = LP_FinishedOper( lp ) ;
+ *blk_ptr_ptr = NULL ;
+ return error ;
+ }
+
+
+ /** see if we hit end of tape **/
+
+ if( lp->rr.tf_message == TRR_END ) {
+ return NO_ERR ;
+ }
+
+ if( error == NO_ERR ) {
+ *blk_ptr_ptr = lp->curr_blk ;
+ }
+
+ if( error == NO_ERR ) {
+
+ /** set up pointers for matching **/
+
+
+ object_is_special = (INT16)(match == BSD_SPECIAL_OBJECT) ;
+
+ if ( ( match == BSD_SPECIAL_OBJECT ) && BSD_GetProcSpecialFlg( bsd_ptr ) ) {
+ match = BSD_PROCESS_OBJECT ;
+ }
+
+ switch( match ) {
+
+ /** our list of desired files is empty **/
+
+ case FSL_EMPTY:
+ error = LP_FinishedOper( lp ) ;
+ *blk_ptr_ptr = NULL ;
+ return error ;
+
+ /** stuff we don't want **/
+
+ case BSD_SKIP_OBJECT:
+ case BSD_SPECIAL_OBJECT:
+
+ LP_SkipData( lp ) ;
+ error = NO_ERR ;
+ block_skipped = TRUE ;
+ break ;
+
+
+ case BSD_PROCESS_ELEMENTS:
+
+ attrib = FS_GetAttribFromDBLK( fsh, lp->curr_blk ) ;
+
+ /** skip it if its an empty dir and we aren't proc'ing them **/
+ if( !(attrib & DIR_EMPTY_BIT) || !BEC_GetProcEmptyFlag( cfg ) ) {
+
+
+ LP_SkipData( lp ) ;
+ lp->ignore_data_for_ddb = TRUE ;
+
+ lp->proc_curr_dir = TRUE ;
+ error = NO_ERR ;
+ break ;
+
+ } else {
+ lp->proc_curr_dir = FALSE ;
+ lp->ignore_data_for_ddb = FALSE ;
+ }
+
+ /* fall through if we want it */
+
+ case BSD_PROCESS_OBJECT:
+
+ if( lp->proc_curr_dir ) {
+ lp->proc_curr_dir = FALSE ;
+ lp->send_saved_block = TRUE ;
+ *blk_ptr_ptr = lp->curr_ddb ;
+ *lp->saved_ddb = *lp->curr_ddb ;
+ }
+
+ if ( fse_ptr != NULL ) {
+
+ LP_BuildTargetPath( lp, blk_ptr_ptr, bsd_ptr, fse_ptr ) ;
+
+ if ( FS_GetBlockType( lp->curr_blk ) == FDB_ID ) {
+
+ if ( FSE_GetSelectType( fse_ptr ) == SINGLE_FILE_SELECTION ) {
+ FSE_MarkDeleted( fse_ptr ) ;
+ }
+ }
+ }
+
+ return( NO_ERR );
+
+ default:
+ msassert( FALSE ) ;
+ break ;
+ }
+ }
+
+ } while( error == NO_ERR ) ;
+
+ return( error ) ;
+
+}
+
+
+/**/
+/**
+
+ Name: Get_an_FFR_DBLK( lp )
+
+ Description: This routine calls the tape and attempts to do a
+ Fast File Restore by skipping over unneeded
+ blocks. There's a queue of items to be processed.
+ Each item includes a tape location, and a type.
+ The type indicates if it is a single or multi
+ item restore. The tape locations are all
+ sorted in increasing order.
+
+
+ Modified: 7/18/1989
+
+ Returns: tape backup engine error
+
+ Notes: none
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+static INT16 Get_an_FFR_DBLK(
+ LP_ENV_PTR lp, /* I - Loop Environment struct to access world */
+ INT16_PTR match_val, /* O - Specifies how the object should be proc */
+ FSE_PTR *fse_ptr, /* O - The FSE that was matched */
+ BOOLEAN_PTR end_of_lba ) /* O - Return TRUE if the lba queue is empty */
+{
+ INT16 error;
+ UINT32 current_lba;
+ INT8_PTR dirptr;
+ INT16 cb_size;
+ CHAR_PTR newpath = (CHAR_PTR)lp->newpath_buf ;
+ INT16 cb_newpath_size ;
+ BSD_PTR bsd ;
+ BOOLEAN finished = FALSE ;
+ BOOLEAN obj_skipped = FALSE ;
+
+ /****
+
+ lp->ffr_state
+
+ NO_QUEUE - no queue, do sequential block reads
+ POP - current operation is over pop queue
+ SINGLE - current operation is a single file restore
+ MULTI - current operation is a multi file restore
+ SUBS - current operation searches subdirectories
+
+ ****/
+
+ bsd = lp->lis_ptr->curr_bsd_ptr ;
+
+ if ( lp->ffr_inited != TRUE ) {
+
+ if ( BSD_GetFirstLBA( bsd, &lp->ffr_last_lba ) == SUCCESS ) {
+ lp->ffr_state = FFR_POP ;
+ } else {
+ lp->ffr_state = FFR_NO_QUEUE;
+ }
+
+ lp->ffr_inited = TRUE;
+ }
+
+ /** grab next sequential block **/
+
+ while ( !finished ) {
+ finished = TRUE ;
+ lp->rr.lp_message = LRR_STUFF;
+
+ error = LP_GetTheObject( lp, fse_ptr, match_val ) ;
+ if ( *fse_ptr != NULL ) {
+ lp->ffr_last_fse = *fse_ptr ;
+ }
+
+ if ( error || lp->rr.tf_message == TRR_END ) {
+ return error ;
+ }
+
+ switch ( lp->ffr_state ) {
+
+ case FFR_NO_QUEUE:
+ if ( match_val == BSD_SKIP_OBJECT ) {
+ obj_skipped = TRUE ;
+ finished = FALSE ;
+ }
+ if ( FS_GetBlockType( lp->curr_blk ) == CFDB_ID ) {
+ if ( obj_skipped ) {
+ LP_SkipData( lp ) ;
+ finished = FALSE ;
+ }
+ }
+
+ break;
+
+ case FFR_SINGLE:
+ /** ex. \FRED\PAUL.C **/
+
+ if ( FS_GetBlockType( lp->curr_blk ) != CFDB_ID ) {
+ lp->ffr_state = FFR_POP;
+ }
+ break;
+
+ case FFR_MULTI:
+ /** ex. \FRED\PAUL.* **/
+
+ if ( FS_GetBlockType( lp->curr_blk ) == DDB_ID ) {
+ lp->ffr_state = FFR_POP;
+
+ } else if ( match_val == BSD_SKIP_OBJECT ) {
+ obj_skipped = TRUE ;
+ finished = FALSE ;
+
+ } else if ( FS_GetBlockType( lp->curr_blk ) == CFDB_ID ) {
+ if ( obj_skipped ) {
+ finished = FALSE ;
+ }
+ }
+
+ break;
+
+ case FFR_SUBS:
+ /** ex. \FRED\PAUL.C /S **/
+ /** ex. \FRED\PAUL.* /S **/
+
+ if ( FS_GetBlockType( lp->curr_blk ) == DDB_ID ) {
+
+ /* compare root path of lp->curr_blk with fse */
+
+ FSE_GetPath( lp->ffr_last_fse, &dirptr, &cb_size );
+ cb_newpath_size = FS_SizeofOSPathInDDB( lp->curr_fsys, lp->curr_blk ) ;
+ if ( cb_newpath_size > lp->newpath_buf_sz ) {
+ lp->newpath_buf = realloc( lp->newpath_buf, cb_newpath_size ) ;
+ lp->newpath_buf_sz = cb_newpath_size ;
+ }
+ if ( lp->newpath_buf == NULL ) {
+ return OUT_OF_MEMORY ;
+ } else {
+ newpath = (CHAR_PTR)lp->newpath_buf ;
+ }
+
+ FS_GetOSPathFromDDB( lp->curr_fsys,
+ lp->curr_blk,
+ (CHAR_PTR)newpath );
+
+ if ( cb_newpath_size < cb_size ) {
+ cb_size = cb_newpath_size ;
+ }
+
+ if ( ( cb_size != sizeof (CHAR) ) &&
+ memoryicmp( dirptr, cb_size, newpath, cb_size ) ) {
+
+ lp->ffr_state = FFR_POP;
+ }
+ }
+ break;
+
+ case FFR_POP:
+ break;
+
+ default: msassert( FALSE );
+ }
+ }
+
+ if ( lp->ffr_state == FFR_POP ) {
+
+ current_lba = FS_ViewLBAinDBLK( lp->curr_blk ) ;
+
+ /** pop queue until unpassed request shows up **/
+
+ while ( LBA_GetLBA( &lp->ffr_last_lba ) < current_lba ) {
+
+ if ( BSD_GetNextLBA( bsd, &lp->ffr_last_lba ) != SUCCESS ) {
+ *end_of_lba = TRUE;
+ return( NO_ERR );
+ }
+ }
+
+ /** jump to right place on tape and grab a block **/
+
+ if ( current_lba != LBA_GetLBA( &lp->ffr_last_lba ) ) {
+
+ lp->rr.tape_loc.tape_seq = LBA_GetTapeNum( &lp->ffr_last_lba );
+ lp->rr.tape_loc.lba = LBA_GetLBA( &lp->ffr_last_lba );
+ lp->rr.lp_message = LRR_GOTO_LBA;
+ error = LP_GetTheObject( lp, &lp->ffr_last_fse, match_val ) ;
+ *fse_ptr = lp->ffr_last_fse ;
+
+ /* if there is an LBA the object better match */
+ }
+
+ /** determine new current status **/
+
+ if ( LBA_GetType( &lp->ffr_last_lba ) == LBA_SINGLE_OBJECT ) {
+ lp->ffr_state = FFR_SINGLE;
+
+ } else if ( LBA_GetType( &lp->ffr_last_lba ) == LBA_BEGIN_POSITION ) {
+
+ if ( (*fse_ptr != NULL) && FSE_GetIncSubFlag( lp->ffr_last_fse ) ) {
+ lp->ffr_state = FFR_SUBS;
+
+ } else {
+ lp->ffr_state = FFR_MULTI;
+ }
+
+ }
+ }
+
+ return( error );
+}
+
+/**/
+/**
+
+ Name: LP_GetTheObject()
+
+ Description: This function Calls to get a DBLK then calls the
+ BSD unit to match the DBLK.
+
+
+ Modified: 5/23/1991 9:55:59
+
+ Returns: Any error returned while reading DBLK.
+
+ Notes: If the Receive failed then the match_val is not set.
+
+ Declaration:
+
+**/
+static INT16 LP_GetTheObject(
+LP_ENV_PTR lp,
+FSE_PTR *fse,
+BOOLEAN *match_val )
+{
+ DBLK_PTR fdb ;
+ DBLK_PTR ddb ;
+ INT16 error ;
+ UINT16 cb_size ;
+
+ *fse = NULL ;
+
+ FS_ReleaseDBLK( lp->curr_fsys, lp->curr_blk ) ;
+ error = LP_ReceiveDBLK( lp );
+
+ if ( error || lp->rr.tf_message == TRR_END ) {
+ return error ;
+ }
+
+ if ( FS_GetBlockType( lp->curr_blk ) == FDB_ID ) {
+ fdb = lp->curr_blk ;
+ ddb = lp->saved_ddb ;
+ } else {
+ fdb = NULL ;
+ ddb = lp->curr_blk ;
+ }
+
+ cb_size = 0 ;
+ while ( !FS_IsBlkComplete( lp->curr_fsys, lp->curr_blk ) ) {
+ LP_ReceiveData( lp, (UINT32)cb_size ) ;
+ cb_size = lp->rr.buff_size ;
+ FS_CompleteBlk( lp->curr_fsys, lp->curr_blk, lp->rr.buff_ptr, &cb_size, &lp->rr.stream ) ;
+ }
+
+ lp->initial_tape_buf_used = cb_size ;
+
+ *match_val = BSD_MatchObj( lp->lis_ptr->curr_bsd_ptr, fse,
+ lp->curr_fsys, ddb, fdb, FALSE ) ;
+
+ if ( *match_val == OUT_OF_MEMORY ) {
+ return OUT_OF_MEMORY ;
+ } else {
+ return SUCCESS ;
+ }
+
+}
+
+/**/
+/**
+
+ Name: LP_BuildTargetPath()
+
+ Description: This function uses the FSE passed in to set the
+ path & file name in the provided DBLK. This
+ function provides the Target Directory/File
+ functionality.
+
+ Modified: 5/23/1991 9:55:59
+
+ Returns: none
+
+ Notes:
+
+ Declaration:
+
+**/
+static VOID LP_BuildTargetPath(
+LP_ENV_PTR lp, /* I - handle of file system to use */
+DBLK_PTR *dblk, /*I/O- DBLK to modify - must be ddb */
+BSD_PTR bsd, /* I - bsd which may contain target info */
+FSE_PTR fse ) /* I - matched selector - contains target info */
+{
+ CHAR_PTR bsd_tgt_path ;
+ INT16 cb_bsd_tgt_psize ;
+
+ BSD_GetTargetInfo( bsd, &bsd_tgt_path, &cb_bsd_tgt_psize ) ;
+
+ if ( ( FS_GetBlockType( *dblk ) == DDB_ID ) &&
+ ( bsd_tgt_path != NULL ) ) {
+
+ // Save it before we modify it! Otherwise no files will match!
+ *lp->saved_ddb = **dblk ;
+ ModifyDDBRoot( lp, bsd_tgt_path, cb_bsd_tgt_psize, *dblk ) ;
+
+ } else {
+
+ if ( FS_GetBlockType( *dblk ) == DDB_ID ) {
+ *lp->saved_ddb = **dblk ;
+ }
+
+ if ( FSE_HasTargetInfo( fse ) || (lp->tgt_info != NULL) ) {
+
+ if ( FS_GetBlockType( *dblk ) == DDB_ID ) {
+
+ if ( FSE_HasTargetInfo( fse ) ) {
+ ModifyDDB( lp, fse, *dblk ) ;
+ lp->tgt_info = fse ;
+
+ } else {
+ lp->tgt_info = NULL ;
+ }
+
+ } else if ( FS_GetBlockType( *dblk ) == FDB_ID ) {
+
+ if ( FSE_HasTargetInfo( fse ) ) {
+ if ( lp->tgt_info != fse ) {
+
+ *lp->curr_ddb = *lp->saved_ddb ;
+ ModifyDDB( lp, fse, lp->curr_ddb ) ;
+
+ *dblk = lp->curr_ddb ;
+ lp->send_saved_block = TRUE ;
+ lp->tgt_info = fse ;
+ }
+
+ if ( FSE_GetSelectType( fse ) == SINGLE_FILE_SELECTION ) {
+ ModifyFDB( lp, fse, *dblk ) ;
+ }
+
+ } else if ( lp->tgt_info ) {
+ *lp->curr_ddb = *lp->saved_ddb ;
+ *dblk = lp->curr_ddb ;
+ lp->send_saved_block = TRUE ;
+ lp->tgt_info = NULL ;
+ }
+
+ if ( ( LBA_GetFileVer( &lp->ffr_last_lba ) != 0 ) &&
+ ( FS_GetBlockType( *dblk ) == FDB_ID ) ) {
+
+ CreateUniqueName( lp, *dblk ) ;
+ }
+ }
+ }
+ }
+}
+
+
+/**/
+/**
+
+ Name: ModifyDDBRoot()
+
+ Description: This function calls the file system to set the
+ path in a DDB.
+
+ Modified: 5/23/1991 9:55:59
+
+ Returns: none
+
+ Notes:
+
+ Declaration:
+
+**/
+static VOID ModifyDDBRoot(
+LP_ENV_PTR lp,
+CHAR_PTR path,
+INT16 psize, //size of string buffer in bytes incl NULL term
+DBLK_PTR dblk )
+{
+ CHAR new_path[1024] ;
+ INT16 cb_path_size ; //size of string buffer in bytes incl NULL term
+ INT16 cb_old_psize ; //size of string buffer in bytes incl NULL term
+ FSYS_HAND fsh ;
+
+ fsh = lp->curr_fsys ;
+
+ cb_path_size = psize ;
+
+ memcpy( new_path, path, psize ) ;
+
+ FS_GetPathFromDDB( fsh, dblk, &new_path[psize/sizeof (CHAR)] ) ;
+
+ cb_old_psize = FS_SizeofPathInDDB( fsh, dblk ) ;
+
+ if ( cb_old_psize > sizeof (CHAR) ) {
+ cb_path_size = cb_old_psize + psize ;
+ }
+
+ FS_SetPathInDDB( fsh, dblk, new_path, &cb_path_size ) ;
+
+}
+
+
+
+/**/
+/**
+
+ Name: ModifyDDB()
+
+ Description: This function calls the file system to set the
+ path in a DDB.
+
+ Modified: 5/23/1991 9:55:59
+
+ Returns: none
+
+ Notes:
+
+ Declaration:
+
+**/
+static VOID ModifyDDB(
+LP_ENV_PTR lp,
+FSE_PTR fse,
+DBLK_PTR dblk )
+{
+ CHAR new_path[1024] ;
+ INT16 cb_path_size ; //size of buffer in bytes
+ INT8_PTR fse_src_path ;
+ INT16 cb_fse_src_psize ; //size of buffer in bytes
+ INT8_PTR fse_dest_path ;
+ INT16 cb_fse_dest_psize ; //size of buffer in bytes
+ INT8_PTR fse_dest_fname ;
+ INT16 cb_fse_dest_fnsize ; //size of buffer in bytes
+ INT16 depth ;
+ INT16 i;
+ FSYS_HAND fsh ;
+
+ fsh = lp->curr_fsys ;
+
+ FSE_GetTargetInfo( fse, &fse_dest_path, &cb_fse_dest_psize,
+ &fse_dest_fname, &cb_fse_dest_fnsize ) ;
+
+ if( cb_fse_dest_psize ) {
+
+ if( cb_fse_dest_psize == sizeof (CHAR) ) {
+ cb_fse_dest_psize = 0 ;
+ }
+
+ FSE_GetPath( fse, &fse_src_path, &cb_fse_src_psize ) ;
+
+ if( cb_fse_src_psize == sizeof (CHAR) ) {
+ cb_fse_src_psize = 0 ;
+ }
+
+ depth = 0 ;
+ for( i = 0 ; i < (INT16)(cb_fse_src_psize / sizeof (CHAR)); i ++ ) {
+ if( fse_src_path[i] == TEXT('\0') ) {
+ depth++ ;
+ }
+ }
+
+ FS_GetPathFromDDB( fsh, dblk, new_path ) ;
+ cb_path_size = FS_SizeofPathInDDB( fsh, dblk ) ;
+
+ if( cb_path_size == sizeof (CHAR) ) {
+ cb_path_size = 0 ;
+ }
+
+
+ cb_fse_src_psize = 0 ;
+ while( depth ) {
+ if( new_path[ cb_fse_src_psize / sizeof (CHAR) ] == TEXT('\0') ) {
+ depth -- ;
+ }
+ cb_fse_src_psize += sizeof (CHAR);
+ }
+
+ memmove( new_path + cb_fse_dest_psize, new_path + cb_fse_src_psize, cb_path_size ) ;
+
+ memcpy( new_path, fse_dest_path, cb_fse_dest_psize ) ;
+
+ cb_path_size = cb_path_size - cb_fse_src_psize + cb_fse_dest_psize ;
+
+ if ( cb_path_size > 0 ) {
+
+ FS_SetPathInDDB( fsh, dblk, new_path, &cb_path_size ) ;
+ }
+ }
+
+ return ;
+
+}
+
+/**/
+/**
+
+ Name: ModifyFDB()
+
+ Description: This function calls the file system to set the
+ file name in a FDB.
+
+ Modified: 5/23/1991 9:55:59
+
+ Returns: none
+
+ Notes:
+
+ Declaration:
+
+**/
+static VOID ModifyFDB(
+LP_ENV_PTR lp,
+FSE_PTR fse,
+DBLK_PTR dblk )
+{
+ CHAR_PTR fse_dest_path ;
+ INT16 cb_fse_dest_psize ;
+ CHAR_PTR fse_dest_fname ;
+ INT16 cb_fse_dest_fnsize ;
+ FSYS_HAND fsh ;
+
+ fsh = lp->curr_fsys ;
+
+ FSE_GetTargetInfo( fse, &fse_dest_path, &cb_fse_dest_psize, &fse_dest_fname, &cb_fse_dest_fnsize ) ;
+ if ( fse_dest_fname != NULL ) {
+ FS_SetFnameInFDB( fsh, dblk, fse_dest_fname, &cb_fse_dest_fnsize ) ;
+ }
+}
+
+
+/**/
+/**
+
+ Name: CreateUniqueName()
+
+ Description: This function calls the file system to set the
+ file name in a FDB. The new file name is created
+ form the file version number in the LBA.
+
+ Modified: 5/23/1991 9:55:59
+
+ Returns: none
+
+ Notes:
+
+ Declaration:
+
+**/
+
+static VOID CreateUniqueName(
+LP_ENV_PTR lp,
+DBLK_PTR dblk )
+{
+ CHAR fname[1024] ;
+ INT16 fnsize ;
+ CHAR ver_str[3] ;
+ LBA_ELEM_PTR lba ;
+ INT16 ver_num ;
+ FSYS_HAND fsh ;
+ CHAR_PTR p ;
+ INT16 cch_len ;
+
+ fsh = lp->curr_fsys ;
+ lba = &lp->ffr_last_lba ;
+
+ ver_num = LBA_GetFileVer( lba ) ;
+
+ if ( ver_num != 0 ) {
+
+ mscassert( ver_num < 0x100 ) ;
+
+ if( ver_num >= 0x100 ) {
+ ver_num = 0xFF ;
+ }
+
+ sprintf( ver_str, TEXT("%02X"), ver_num ) ;
+
+ FS_GetFnameFromFDB( fsh, dblk, fname ) ;
+
+ p = strchr(fname, TEXT('.') ) ;
+
+ if ( p == NULL ) {
+
+ cch_len = (INT16)strlen( fname ) ;
+ if ( cch_len < 7 ) {
+ strcat( fname, ver_str ) ;
+
+ } else {
+ strcpy( fname + 6, ver_str ) ;
+ }
+
+ } else {
+
+ cch_len = (INT16)((p - fname) / sizeof (CHAR)) ;
+ if ( cch_len < 7 ) {
+ memmove( p, p+2, strsize( p ) ) ;
+
+ fname[cch_len] = ver_str[0] ;
+ fname[cch_len + 1] = ver_str[1] ;
+
+ } else {
+ fname[cch_len - 2] = ver_str[0] ;
+ fname[cch_len - 1] = ver_str[1] ;
+ }
+ }
+
+ fnsize = strsize( fname ) ;
+
+ FS_SetFnameInFDB( fsh, dblk, fname, &fnsize ) ;
+ }
+}
diff --git a/private/utils/ntbackup/src/gui.c b/private/utils/ntbackup/src/gui.c
new file mode 100644
index 000000000..5f907064b
--- /dev/null
+++ b/private/utils/ntbackup/src/gui.c
@@ -0,0 +1,1750 @@
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+
+ Name: gui.c
+
+ Description: This file contains the functions for initializing and
+ deinitializing the GUI subsystem.
+
+ $Log: G:\ui\logfiles\gui.c_v $
+
+ Rev 1.61.1.8 01 Mar 1994 20:08:34 STEVEN
+uincode bug with memcpy on strings
+
+ Rev 1.61.1.7 11 Feb 1994 16:38:16 GREGG
+Changed command line switch to avoid conflict (two starting /MEM).
+
+ Rev 1.61.1.6 24 Jan 1994 15:59:00 GREGG
+Added option to tell mem debugger not to trap when consistency check fails.
+
+ Rev 1.61.1.5 14 Dec 1993 13:19:20 MikeP
+fix losing the ini filename
+
+ Rev 1.61.1.4 11 Dec 1993 12:17:02 MikeP
+fix cmdline buffer size bug
+
+ Rev 1.61.1.3 03 Dec 1993 01:02:42 GREGG
+Added HW Comp cmd line option and ifdefed KEEPCATS for MSDEBUG only.
+
+ Rev 1.61.1.2 30 Nov 1993 19:09:24 TIMN
+Added cmdline /tape:x option to NTJ
+
+ Rev 1.61.1.1 13 Sep 1993 15:51:24 BARRY
+Moved check for missing tape until after the GUI init -- only done for MSOFT.
+
+ Rev 1.61.1.0 17 Aug 1993 12:35:56 BARRY
+Put TEXT macros around hard-coded strings.
+
+ Rev 1.61 02 Aug 1993 16:20:54 chrish
+CAYMAN EPR 0645: Added #ifndef to handle log file passed on the command line
+backup for Nostradamus.
+
+ Rev 1.60 29 Jul 1993 23:09:32 MIKEP
+remove mapi.h
+
+ Rev 1.59 23 Jul 1993 15:26:32 GLENN
+Using data path for log file if a full path is not specified.
+
+ Rev 1.58 21 Jul 1993 17:05:36 GLENN
+Clarified the cmd line stuff by adding named mixed and upper case command line strings.
+
+ Rev 1.57 20 Jul 1993 16:15:44 GLENN
+Added AlterCmdLine stuff over from BACKUP.C - removed callocs and placed vars on stack.
+
+ Rev 1.56 15 Jul 1993 17:20:24 GLENN
+Added support for pulling resources from RESLIB.DLL
+
+ Rev 1.55 29 Jun 1993 11:39:08 TIMN
+Fixed Alpha build error with gszTapeName
+
+ Rev 1.54 23 Jun 1993 09:14:50 GLENN
+Placed limit on command line tape name copy to the size of the string.
+
+ Rev 1.53 17 Jun 1993 13:32:04 CARLS
+added code to delete catalogs if DEMO
+
+ Rev 1.52 15 Jun 1993 13:21:44 DARRYLP
+More status monitor features
+
+ Rev 1.51 18 May 1993 14:53:52 GLENN
+Added extra delimiter to INI cmd line check.
+
+ Rev 1.50 04 May 1993 11:37:30 DARRYLP
+Replaced unwanted OEM_MSOFT defines with CAYMAN defines.
+
+ Rev 1.49 30 Apr 1993 15:55:16 GLENN
+Added INI command line support. Modularized the Status Monitor code.
+
+ Rev 1.48 28 Apr 1993 15:42:22 DARRYLP
+Corrected typo.
+
+ Rev 1.47 28 Apr 1993 12:02:52 DARRYLP
+Updates to GUI.C to allow string printing in CBEMON.DLL
+
+ Rev 1.46 27 Apr 1993 22:35:48 MIKEP
+ifdef status code so nostrad can build
+
+ Rev 1.45 27 Apr 1993 19:12:06 GLENN
+Fixed module wide variable naming inconsistancy. Removed dead space.
+
+ Rev 1.44 27 Apr 1993 16:08:54 DARRYLP
+Updated Status monitor functionality
+
+ Rev 1.43 19 Apr 1993 15:27:08 GLENN
+Added tape name command line option - case preserving.
+
+ Rev 1.42 08 Apr 1993 13:42:42 DARRYLP
+Changes for STAT_SetStatus call.
+
+ Rev 1.41 06 Apr 1993 12:02:46 DARRYLP
+Changes to allow screwy mips machine to build.
+
+ Rev 1.40 02 Apr 1993 11:08:12 DARRYLP
+Changed the LoadLibrary result comparision to make allowances for the
+screwy MIPS machine.
+
+ Rev 1.39 25 Mar 1993 14:51:58 DARRYLP
+Conditional compile fix for Nostradamus.
+
+ Rev 1.38 23 Mar 1993 15:52:14 DARRYLP
+Added DDE-DLL loading modules for the special MS request allowing remote
+monitoring. This should be transparent without the associated DLL.
+
+ Rev 1.37 07 Mar 1993 12:33:40 MIKEP
+add missing tape option
+
+ Rev 1.36 02 Mar 1993 11:55:52 MIKEP
+fix delete catalogs on exit
+
+ Rev 1.35 18 Feb 1993 12:12:04 BURT
+Changes for Cayman
+
+
+ Rev 1.34 20 Jan 1993 20:25:04 MIKEP
+remove /T? kludge for NT
+
+ Rev 1.33 23 Dec 1992 14:30:42 GLENN
+Added /NOSERVERS option.
+
+ Rev 1.32 05 Nov 1992 17:07:40 DAVEV
+fix ts
+
+ Rev 1.30 14 Oct 1992 15:50:44 GLENN
+Added /ZL debug logging command line support.
+
+ Rev 1.29 07 Oct 1992 15:09:46 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.28 06 Oct 1992 15:55:28 DARRYLP
+Added new WFW definition.
+
+ Rev 1.27 04 Oct 1992 19:37:42 DAVEV
+Unicode Awk pass
+
+ Rev 1.26 28 Sep 1992 16:26:08 GLENN
+ifdef's email includes.
+
+ Rev 1.25 22 Sep 1992 15:05:52 DARRYLP
+Add calls to determine the validity of WFW Email option.
+
+ Rev 1.24 08 Sep 1992 17:30:50 DARRYLP
+
+ Rev 1.23 08 Sep 1992 17:00:32 DARRYLP
+
+ Rev 1.22 04 Sep 1992 10:35:54 MIKEP
+ifdef last change
+
+ Rev 1.21 04 Sep 1992 10:33:16 MIKEP
+add support for picking tape drive to command line.
+
+ Rev 1.20 04 Aug 1992 10:04:52 MIKEP
+no cats flag
+
+ Rev 1.19 26 Jun 1992 15:52:38 DAVEV
+
+
+ Rev 1.18 29 May 1992 16:00:20 JOHNWT
+PCH updates
+
+ Rev 1.17 09 Apr 1992 11:34:34 GLENN
+Added support for exe/resource version stamping.
+
+ Rev 1.16 07 Apr 1992 15:40:30 GLENN
+Specified complete resource library path.
+
+ Rev 1.15 07 Apr 1992 10:20:06 GLENN
+Change to exe dir before loading library.
+
+ Rev 1.14 02 Apr 1992 15:25:52 GLENN
+NT doesn't want to pull resources from .DLL
+
+ Rev 1.13 30 Mar 1992 18:02:56 GLENN
+Added support for pulling resources from .DLL
+
+ Rev 1.12 26 Mar 1992 08:51:40 GLENN
+Updated.
+
+ Rev 1.11 24 Mar 1992 14:41:36 DAVEV
+OEM_MSOFT: Removed Servers windows and associated code
+
+ Rev 1.10 10 Mar 1992 16:48:12 GLENN
+Update.
+
+ Rev 1.9 09 Mar 1992 09:36:08 GLENN
+Added Easter Egg - red checkmark command line support.
+
+ Rev 1.8 03 Mar 1992 18:45:46 GLENN
+Removed setup exe path function and changed the three UI_Init calls to a single UI_InitIntl call.
+
+ Rev 1.7 08 Feb 1992 11:57:02 CARLS
+added call to UI_InitThousandChar
+
+ Rev 1.6 04 Feb 1992 13:36:26 GLENN
+Changed gb_exe_path to CDS_GetExePath().
+
+ Rev 1.5 10 Jan 1992 16:37:42 JOHNWT
+moved set idle text into WM_Init
+
+ Rev 1.4 07 Jan 1992 17:41:32 GLENN
+Moved debug command line checking to here
+
+ Rev 1.3 19 Dec 1991 15:25:52 GLENN
+Added windows.h
+
+ Rev 1.2 04 Dec 1991 18:44:36 GLENN
+Added UI_InitDate and time calls
+
+ Rev 1.1 27 Nov 1991 12:14:32 GLENN
+Clean-up.
+
+ Rev 1.0 20 Nov 1991 19:29:54 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+#ifdef WFW
+#ifndef OEM_MSOFT
+ #include "mapinit.h"
+#endif
+#endif
+
+#ifdef OEM_EMS
+#include "ctl3d.h"
+BOOL mwf3dEnabled;
+#endif
+
+#define DDEMANG "CBEMON.DLL"
+#define SZ_DDEMANG "STAT_SetStatus"
+
+// TEMPORARY ?????
+
+BOOL gfRedChecks;
+BOOL gfMultiDrive;
+HTIMER mhStatusTimer = 0;
+
+
+#define MAX_COMMAND_LINE_SIZE 2048
+
+#define INITIAL_STRING_SIZE 1024
+#define MAX_NAME_SIZE 128
+
+HINSTANCE mwhLibInst;
+
+// PRIVATE FUNCTION PROTOTYPES
+
+static BOOL GUI_GetCmdLineSwitches ( LPSTR, LPSTR );
+static BOOL GUI_ValidateCmdLine( LPSTR ) ;
+static LPSTR GUI_AlterCmdLine ( LPSTR, LPSTR );
+static VOID parseblk( CHAR_PTR );
+
+static VOID MON_Init();
+static VOID MON_Deinit();
+static BOOL MON_FreeDDEManager();
+static BOOL MON_LoadDDEManager();
+static BOOL MON_CreateStringList();
+static INT MON_SetSize(LPSTR);
+static DWORD MON_StringToStatusBlock(LPSTR, LPSTR);
+
+static BOOL GUI_ValidAtoiResult( CHAR *pszChar, INT nTapeNumber ) ;
+static VOID GUI_ProcessQuotedString ( LPSTR,
+ LPSTR,
+ BOOLEAN * );
+
+
+
+
+
+/*****************************************************************************
+
+ Name: GUI_Init ()
+
+ Description: This funciton initializes the GUI.
+
+ Returns: SUCCESS if successful, otherwise FAILURE.
+
+*****************************************************************************/
+
+BOOL GUI_Init (
+
+LPSTR lpszCmdLine,
+INT nCmdShow )
+
+{
+ CDS_PTR pCDS = CDS_GetPerm ();
+ CHAR szMixedCmdLine[ MAX_COMMAND_LINE_SIZE ];
+ CHAR szUpperCmdLine[ MAX_COMMAND_LINE_SIZE ];
+
+ if ( lpszCmdLine ) {
+
+ CHAR szTempCmdLine[ MAX_COMMAND_LINE_SIZE ];
+ LPSTR pszNewCmdLine;
+
+ szTempCmdLine[0] = 0;
+ strcpy ( szMixedCmdLine, lpszCmdLine );
+
+ pszNewCmdLine = GUI_AlterCmdLine ( szMixedCmdLine, szTempCmdLine );
+
+ strcpy ( szMixedCmdLine, pszNewCmdLine );
+ strcpy ( szUpperCmdLine, pszNewCmdLine );
+ strupr ( szUpperCmdLine );
+
+ }
+ else {
+ szMixedCmdLine[0] = 0;
+ szUpperCmdLine[0] = 0;
+ }
+
+
+ // Initialize global variables.
+
+#ifdef OEM_EMS
+ mwf3dEnabled = Ctl3dRegister ( ghInst );
+#endif OEM_EMS
+
+ if ( GUI_InitGlobals () ) {
+ return FAILURE;
+ }
+
+ // NTKLUG: do NOT use external resource file for CAYMAN for now...
+# if ! (defined ( OEM_MSOFT ) ) //unsupported feature
+ {
+
+ CHAR szResFileName[ MAX_UI_PATH_SIZE ];
+ CHAR szTemp1[ MAX_UI_SMALLRES_SIZE ];
+ CHAR szTemp2[ MAX_UI_SMALLRES_SIZE ];
+
+ // Load the resource library using a fully specified path.
+
+ CDS_SetupExePath ();
+
+ strcpy ( szResFileName, CDS_GetExePath () );
+ strcat ( szResFileName, RSM_RESFILE );
+
+ ghResInst = LoadLibrary ( szResFileName );
+
+ // Bug out if the load failed.
+
+# ifdef OS_WIN32
+ if ( ghResInst == NULL ) {
+# else
+ if ( ghResInst < 32 ) {
+# endif
+
+ // This is the only place that actual text is allowed.
+ // UNTRANSLATED due to the failure to load the language specific
+ // resource file.
+
+ MessageBox ( (HWND)NULL,
+ TEXT("FATAL ERROR: The resource library is missing or invalid and could not be loaded. This application cannot continue executing. Please re-install the software."),
+ APPLICATIONNAME,
+ MB_OK | MB_ICONSTOP
+ );
+
+ return FAILURE;
+ }
+
+ // Check the EXE and RESOURCE DLL versions.
+
+ RSM_StringCopy ( IDS_APPRESVER, szTemp1, sizeof ( szTemp1 ) );
+ RSM_StringCopy ( IDS_APPEXEVER, szTemp2, sizeof ( szTemp2 ) );
+
+ // Bug out if either version is different.
+
+ if ( strcmp ( szTemp1, gszResVer ) || strcmp ( szTemp2, gszExeVer ) ) {
+
+ CHAR szAppName[ MAX_UI_PATH_SIZE ];
+ CHAR szString[ MAX_UI_PATH_SIZE ];
+
+ RSM_StringCopy ( IDS_APPNAME, szAppName, sizeof ( szAppName ) );
+ RSM_Sprintf ( szString, ID( IDS_BADRESVER ), szAppName );
+
+ MessageBox ( (HWND)NULL, szString, szAppName, MB_OK | MB_ICONSTOP );
+
+ return FAILURE;
+ }
+
+ }
+# else
+ {
+ ghResInst = ghInst;
+ }
+# endif
+
+
+ // Check for the memory debug switch.
+
+ if ( strstr ( szUpperCmdLine, TEXT("/MEM") ) ) {
+ gfShowMemory = TRUE;
+ }
+
+ // Check for command line INI file specification.
+
+# if ! (defined ( OEM_MSOFT ) ) //unsupported feature
+ {
+ LPSTR pSubString;
+ LPSTR pIndex;
+ CHAR szTemp[ 512 ];
+ CHAR szIniName[MAX_UI_FILENAME_SIZE];
+
+ strcpy ( szTemp, TEXT("/INI:") );
+
+ pSubString = strstr ( szUpperCmdLine, szTemp );
+
+ if ( pSubString ) {
+
+ INT nPos = pSubString - szUpperCmdLine;
+
+ pSubString = &szMixedCmdLine[nPos];
+
+ pSubString += strlen ( szTemp );
+ pIndex = szIniName;
+
+ // Extract the INI name from the command line. Search for the
+ // INI name terminators.
+
+ while ( ( *pSubString != TEXT(' ') ) &&
+ ( *pSubString != TEXT('.') ) &&
+ ( *pSubString != TEXT('/') ) &&
+ ( *pSubString != TEXT('\0') ) ) {
+
+ *pIndex++ = *pSubString++;
+ }
+
+ *pIndex = TEXT('\0');
+
+ strcat ( szIniName, TEXT(".INI") );
+
+ CDS_SetIniFileName ( szIniName );
+ }
+ else {
+
+ // Set the INI file to the APP default.
+
+ CDS_LoadIniFileName ();
+ }
+ }
+#else
+
+ CDS_LoadIniFileName();
+
+#endif
+
+ // Initialize Memory.
+
+ if ( MEM_Init () ) {
+ return FAILURE;
+ }
+
+ // Initialize permanent and run-time CDS's.
+
+ CDS_Init ();
+
+ // Get the Debug Command Line Switches.
+
+ GUI_GetCmdLineSwitches ( szMixedCmdLine, szUpperCmdLine );
+
+
+# if !defined ( OEM_MSOFT )
+ {
+ gfServers = CDS_GetDisplayNetwareServers ( pCDS );
+ }
+# else //if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ gfServers = FALSE;
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+# if defined ( OEM_EMS )
+ {
+ CDS_SetDisplayExchange( pCDS, gfExchange );
+ }
+# endif
+
+#if defined( CAYMAN )
+ gfServers = FALSE ;
+#endif
+
+ gfShowStatusLine = CDS_GetShowStatusLine ( pCDS );
+ gfShowMainRibbon = CDS_GetShowMainRibbon ( pCDS );
+
+ // Initialize the international date and time separators, etc...
+
+ UI_InitIntl ();
+
+ if ( WM_Init ( szMixedCmdLine, nCmdShow ) ) {
+
+ WM_Deinit ();
+ return FAILURE;
+ }
+
+#if defined ( OS_WIN32 ) //alternate feature - cmd line batch job
+
+ if ( GUI_ValidateCmdLine( szUpperCmdLine ) != SUCCESS ) {
+
+ WM_Deinit ();
+ return FAILURE;
+ }
+
+#endif // defined ( OS_WIN32 ) //alternate feature - cmd line batch job
+
+ CDS_UpdateCopy ();
+
+#ifdef WFW
+ if ( ( EM_IsMailAvailable () == TRUE) && ( InitMAPI () == 0))
+ {
+ EM_SetMAPIAvailable ( TRUE );
+ } else
+ {
+ EM_SetMAPIAvailable ( FALSE );
+ }
+#endif
+
+ MON_Init ();
+
+ return SUCCESS;
+
+} /* end GUI_Init() */
+
+
+/*****************************************************************************
+
+ Name: GUI_Deinit ()
+
+ Description: This funciton deinitializes the GUI.
+
+ Returns: Nothing.
+
+*****************************************************************************/
+
+VOID GUI_Deinit ( VOID )
+
+{
+ // Deinitialize the Window Manager.
+
+ WM_Deinit ();
+
+ // Now, nicely give back all of the memory that we used.
+
+ MEM_Deinit ();
+
+ // CAYKLUG: do NOT use external resource file for CAYMAN for now...
+# if ! (defined ( OEM_MSOFT ) || defined ( CAYKLUG )) //unsupported feature
+ {
+ // Free up the resource library.
+
+ FreeLibrary ( ghResInst );
+ }
+# endif
+
+ MON_Deinit ();
+
+ // Bye-Bye.
+
+#ifdef WFW
+ DeInitMAPI();
+#endif
+} /* end GUI_Deinit() */
+
+
+/*****************************************************************************
+
+ Name: GUI_GetCmdLineSwitches ()
+
+ Description: This function processes the command line.
+
+ Returns: SUCCESS, if successful. Otherwise FAILURE, if there was
+ a problem.
+
+*****************************************************************************/
+
+static BOOL GUI_GetCmdLineSwitches (
+
+LPSTR lpszMixedCmdLine, // I - pointer to the mixed case command line string
+LPSTR lpszUpperCmdLine ) // I - pointer to the upper case command line string
+
+{
+ CDS_PTR pCDS = CDS_GetPerm ();
+
+ // If the debug option is specified, set the debug flag.
+ // Otherwise, remove the debug menu option from the settings
+ // menu.
+
+ if ( strstr ( lpszUpperCmdLine, TEXT("/Z") ) ) {
+
+ gfDebug = TRUE;
+
+ CDS_SetDebugToWindow ( pCDS, TRUE );
+
+ // The debug window will use the flag in the config.
+
+ if ( ! CDS_GetDebugFlag ( pCDS ) ) {
+ CDS_SetDebugFlag ( pCDS, 0xFFFF );
+ }
+
+ }
+ else {
+
+ gfDebug = FALSE;
+
+ CDS_SetDebugToWindow ( pCDS, FALSE );
+ CDS_SetDebugFlag ( pCDS, 0x0000 );
+ }
+
+ if ( strstr ( lpszUpperCmdLine, TEXT("/ZL") ) ) {
+
+ if ( ! strlen ( CDS_GetDebugFileName ( pCDS ) ) ) {
+ CDS_SetDebugFileName ( pCDS, TEXT("debug") );
+ }
+
+ CDS_SetDebugToFile ( pCDS, TRUE ) ;
+ }
+
+
+#ifdef MEM_DEBUG
+ if ( strstr ( lpszUpperCmdLine, TEXT("/CONTONMEMERR") ) ) {
+ gb_no_abort_on_mem_check = TRUE;
+ }
+#endif
+
+#ifdef OEM_MSOFT
+
+ if ( strstr ( lpszUpperCmdLine, TEXT("/MISSINGTAPE") ) ) {
+ gfIgnoreOTC = TRUE;
+ }
+
+ // Only delete catalogs for microsoft version.
+
+#ifdef MSDEBUG
+ if ( strstr( lpszUpperCmdLine, TEXT("/KEEPCATS") ) ) {
+ gfDeleteCatalogs = FALSE;
+ }
+ else {
+ gfDeleteCatalogs = TRUE;
+ }
+#else
+ gfDeleteCatalogs = TRUE;
+#endif
+
+#else
+ gfDeleteCatalogs = FALSE;
+#endif
+
+#ifdef MAYN_DEMO
+
+ // Delete catalogs for DEMO version.
+ gfDeleteCatalogs = TRUE;
+
+#endif
+
+ if ( strstr ( lpszUpperCmdLine, TEXT("/CONFIG") ) ) {
+ CDS_SetAdvToConfig ( pCDS, TRUE );
+ }
+
+
+ if ( ! strstr ( lpszUpperCmdLine, TEXT("/NOPOLL") ) ) {
+ gfPollDrive = TRUE;
+ }
+ else {
+ gfPollDrive = FALSE;
+ }
+
+ if ( strstr ( lpszUpperCmdLine, TEXT("/RED") ) ) {
+ gfRedChecks = TRUE;
+ }
+ else {
+ gfRedChecks = FALSE;
+ }
+
+ if ( strstr ( lpszUpperCmdLine, TEXT("/PEN") ) ) {
+ ghCursorPen = RSM_CursorLoad ( IDRC_PEN );
+ }
+ else {
+ ghCursorPen = RSM_CursorLoad ( IDRC_PEN2 );
+ }
+
+ if ( strstr ( lpszUpperCmdLine, TEXT("/MD") ) ) {
+ gfMultiDrive = TRUE;
+ }
+ else {
+ gfMultiDrive = FALSE;
+ }
+
+ // If we were told not to display servers, make sure they
+ // are turned off.
+
+ if ( strstr ( lpszUpperCmdLine, TEXT("/NOSERVERS") ) ) {
+ CDS_SetDisplayNetwareServers ( pCDS, FALSE );
+ }
+
+ // Might as well make the following sections of code
+ // a single function to grab what is in the quotes.
+ // Of course, IN THE NEXT RELEASE when all of this is
+ // object oriented. Oh yeah, we should get rid of OMBATCH
+ // kludge code and place a simpler version here so that all of
+ // the command line stuff is done here.
+
+ // Figure out if there is a command line tape name.
+
+ {
+ CHAR *pSubString ;
+ CHAR *pIndex ;
+ CHAR szTapeNumber[ MAX_TAPE_NAME_SIZE ] ;
+ CHAR szTemp[ 10 ] ;
+
+ strcpy( szTemp, TEXT("/TAPE:") ) ;
+
+ pSubString = strstr( lpszUpperCmdLine, szTemp ) ;
+
+ if ( pSubString ) {
+
+ INT nMax = MAX_TAPE_NAME_SIZE ;
+ INT nPos = pSubString - lpszUpperCmdLine ;
+ INT nTapeNumber ;
+
+ pSubString = &lpszMixedCmdLine[ nPos ] ;
+
+ pSubString += strlen( szTemp ) ;
+ pIndex = szTapeNumber ;
+ nPos = 0;
+
+ while ( ( *pSubString != TEXT(' ') ) &&
+ ( *pSubString != TEXT('\0') ) &&
+ ( ++nPos < nMax ) ) {
+
+ *pIndex++ = *pSubString++ ;
+ }
+
+ *pIndex = TEXT('\0') ;
+
+ nTapeNumber = atoi( szTapeNumber ) ;
+
+ /* atoi returns 0 if the string is not numeric, so
+ let's make sure the result is correct */
+ if ( !GUI_ValidAtoiResult( szTapeNumber, nTapeNumber ) ) {
+ nTapeNumber = -1 ;
+ }
+
+ TapeDevice = HWC_SelectTapeDevice( nTapeNumber ) ;
+ }
+ }
+
+ //
+ // Check for hardware compression mode switch
+ //
+ // Looking for '/HC:ON' or '/HC:OFF'
+ //
+ {
+ CHAR *p ;
+
+ if ( p = strstr( lpszUpperCmdLine, TEXT("/HC:") ) ) {
+ p += 5 ; // skip "/HC:O"
+ if( *p == TEXT('N') ) {
+ CDS_SetHWCompMode( pCDS, TRUE ) ;
+ }
+ if( *p == TEXT('F') ) {
+ CDS_SetHWCompMode( pCDS, FALSE ) ;
+ }
+ }
+ }
+
+ // Look for a command line LOG file name.
+
+ {
+ LPSTR pSubString;
+ LPSTR pIndex;
+ CHAR szTemp[10];
+
+ strcpy ( szTemp, TEXT("/L \042") );
+
+ pSubString = strstr ( lpszUpperCmdLine, szTemp );
+
+ if ( pSubString ) {
+
+ CHAR chTerminator;
+ INT nPos = pSubString - lpszUpperCmdLine;
+ CHAR szLogName[MAX_UI_FILENAME_SIZE];
+ INT nMax = sizeof ( szLogName );
+
+ pSubString = &lpszMixedCmdLine[nPos];
+
+ pSubString += strlen ( szTemp );
+ pIndex = szLogName;
+ nPos = 0;
+
+ // Extract the log file name from the command line. Search for the
+ // lob file name terminator or the end of the command line string '\0'.
+ // The terminator is the same as the last character in the
+ // temporary string. In English it is the double-quote (").
+
+ chTerminator = *(pSubString - 1);
+
+ while ( ( *pSubString != chTerminator ) &&
+ ( *pSubString != TEXT('\0') ) &&
+ ( ++nPos < nMax ) ) {
+
+ *pIndex++ = *pSubString++;
+ }
+
+ *pIndex = TEXT('\0');
+
+ // Need to set the log file name so that we
+ // can write any invalid directories passed on
+ // the command line.
+
+#ifndef OEM_MSOFT // chs:08-02-93
+ {
+ CHAR szLogPathAndName[MAX_UI_FULLPATH_SIZE] = TEXT("");
+
+ // If a full path is not specified, append the log file
+ // name to the data path.
+
+ if ( ! ( strchr ( szLogName, TEXT(':') ) ||
+ strchr ( szLogName, TEXT('\\') ) ) ) {
+
+ strcpy ( szLogPathAndName, CDS_GetUserDataPath () );
+ }
+
+ strcat ( szLogPathAndName, szLogName );
+
+ LOG_SetCurrentLogName ( szLogPathAndName );
+ }
+#else // chs:08-02-93
+ LOG_SetCurrentLogName ( szLogName ); // chs:08-02-93
+ // chs:08-02-93
+#endif // chs:08-02-93
+ }
+ }
+
+ return SUCCESS;
+
+} /* end GUI_GetCmdLineSwitches() */
+
+
+/****************************************************************************
+NOTE : WHEN TRACING THE CODE FOR STRING PASSED ON THE COMMAND LINE,
+ THE DEBUGGER WILL NOT DISPLAY ANY QUOTES. THIS I BELIEVE TO
+ BE SOME SORT OF BUG WITH THE DEBUGGER. THE QUOTES MAYBE
+ THERE EVEN THOUGH YOU CANNOT SEE THEM WITH THE DEBUGGER.
+ SO BE CAREFUL WHEN DEBUGGING THE COMMAND LINE PASSED.
+
+Procedure : GUI_AlterCmdLine
+
+Description : Prepare the command line string passed to make some minor
+ corrections for the user. If quotes missing, then add the
+ quotes, make sure all the "/" are separated by a space ....
+
+ Patch the command line argument passed to the app.
+ 1. Separate all "/" command by a space.
+ 2. Make sure there are quotes around the strings that
+ are passed with the commands ... example:
+ /L "logfile", /D "Description" ...
+ 3. Make sure there is only one space between the "/"
+ command and any string passed. example:
+ /L"logfile" to /L "logfile"
+ 4. Force all single quotes to double quotes.
+
+Function : function returns the new altered string. NULL if failed.
+
+****************************************************************************/
+static CHAR_PTR GUI_AlterCmdLine (
+
+LPSTR pszCmdLine,
+LPSTR pszNewCmdLine )
+
+{
+
+ INT nLength = strlen( pszCmdLine );
+ CHAR szDelimiter[] = TEXT("/");
+ CHAR_PTR pszToken;
+ CHAR szTemp[200];
+ CHAR_PTR pszTemp;
+ CHAR szCmdString[2];
+ INT nFirstChar = 0;
+
+
+ LOG_SetCurrentLogName ( TEXT( "\0" ) );
+
+ if ( nLength <= 0 ) { // if no command line arg then return NULL
+ return( pszCmdLine );
+ }
+
+ if ( pszCmdLine[0] == szDelimiter[0] ) {
+ nFirstChar = 1;
+ }
+
+ if ( ! pszNewCmdLine ) {
+ return( pszCmdLine );
+ }
+
+ //
+ // Jump over the non "/" tokens command string
+ //
+
+ pszToken = strtok( pszCmdLine, szDelimiter );
+
+ if ( ! pszToken ) {
+ return( pszCmdLine );
+ }
+
+ if ( nFirstChar ) {
+ strcat( pszNewCmdLine, szDelimiter );
+ }
+
+ strcat( pszNewCmdLine, pszToken ); // start building new altered command line
+ parseblk( pszNewCmdLine );
+ strcat( pszNewCmdLine, TEXT(" ") );
+
+ //
+ // Get the first valid token command string
+ //
+
+ pszToken = strtok( NULL, szDelimiter );
+
+ if ( !pszToken ) {
+ return( pszCmdLine );
+ }
+
+ while ( pszToken ) {
+
+ pszTemp = szTemp;
+
+ strcpy ( pszTemp, pszToken );
+
+ if ( strlen( pszToken ) > 1 ) {
+
+ if ( toupper ( *pszToken ) == TEXT('D') || toupper ( *pszToken ) == TEXT('L') ) {
+
+ szCmdString[1] = TEXT('\0');
+ szCmdString[0] = *pszToken;
+ strcat( pszNewCmdLine, TEXT("/") );
+ strcat( pszNewCmdLine, szCmdString );
+
+ ++pszToken; // jump over command
+
+ // Jump over any spaces
+ while ( *pszToken && isspace ( *pszToken ) ) ++pszToken;
+
+ if ( *pszToken == TEXT('\'') || *pszToken == TEXT('"') ) {
+ strcat( pszNewCmdLine, TEXT(" ") );
+ strcat( pszNewCmdLine, pszToken );
+ } else {
+ strcat( pszNewCmdLine,TEXT(" ") );
+ strcat( pszNewCmdLine, TEXT("\"") );
+ parseblk( pszToken );
+ strcat( pszNewCmdLine, pszToken );
+ strcat( pszNewCmdLine, TEXT("\"") );
+ }
+ } else {
+ strcat( pszNewCmdLine, TEXT("/") );
+ parseblk( pszToken );
+ strcat( pszNewCmdLine, pszToken );
+ }
+
+ } else {
+ strcat( pszNewCmdLine, TEXT("/") );
+ parseblk( pszToken );
+ strcat( pszNewCmdLine, pszToken );
+ }
+
+ strcat( pszNewCmdLine, TEXT(" ") );
+
+ pszToken = strtok( NULL, szDelimiter );
+
+ }
+
+ parseblk ( pszNewCmdLine );
+
+ return ( pszNewCmdLine );
+
+}
+
+
+/****************************************************************************
+Procedure : parseblk
+Purpose : delete blanks from rights of string.
+Parm :
+ input : st (string to delete padded blanks)
+ output : st (new string without padded blanks)
+**************************************************************************** */
+
+static VOID parseblk( CHAR_PTR st)
+{
+ int i,j;
+
+ j = strlen( st ) - 1;
+
+ for (i = j; i >= 0 && *( st + i ) == TEXT(' ');i--);
+ ++i;
+ *( st + i ) = TEXT('\0');
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// STATUS MONITOR STUFF
+//
+/////////////////////////////////////////////////////////////////////////////
+
+VOID MON_Init ( VOID )
+
+{
+#ifdef CAYMAN
+
+ CHAR szDevName[MAX_NAME_SIZE];
+ CHAR szName[2*MAX_NAME_SIZE];
+ INT nNumChars = MAX_NAME_SIZE;
+
+ // Allocate a block for status if needed...
+
+ if ( MON_LoadDDEManager () )
+ {
+ DWORD dwCharBlock = INITIAL_STRING_SIZE * sizeof(CHAR);
+ DWORD dwSize = sizeof(STAT_SETSTATUSBLOCK) + dwCharBlock;
+
+ // Note - we are using an extra INITIAL_STRING_SIZE bytes block for strings. We
+ // will reallocate space as necessary.
+
+ pSTAT_SetStatusBlock = (PSTAT_SETSTATUSBLOCK)calloc(dwSize, 1);
+
+ SetStatusBlock(IDSM_DATASIZE, dwSize);
+ SetStatusBlock(IDSM_UNICODE, 0); // Unicode is off
+ SetStatusBlock(IDSM_OPERATIONSTATUS, STAT_OPER_IDLE);
+ SetStatusBlock(IDSM_APPSTATUS, STAT_APP_OK);
+
+ SetStatusBlock(IDSM_INSTANCE, (DWORD)ghInst);
+ GetComputerName((LPSTR)szDevName, (LPDWORD)&nNumChars);
+ strcpy(szName, TEXT("\\\\") );
+ strcat(szName, szDevName);
+
+ SetStatusBlock(IDSM_OFFSETSERVERVOLUME, (DWORD)szName);
+ SendStatusMsg(pSTAT_SetStatusBlock);
+ }
+
+#endif
+}
+
+
+VOID MON_Deinit ( VOID )
+
+{
+#ifdef CAYMAN
+ SendStatusMsg(NULL);
+
+ MON_FreeDDEManager();
+
+ if ( glpfnSetStatus == 0 )
+ {
+ // De-Allocate the block for status...
+
+ if (glpOffsetTapeDriveName != 0)
+ {
+ free(glpOffsetTapeDriveName);
+ }
+ if (glpOffsetCurrentTapeName != 0)
+ {
+ free(glpOffsetCurrentTapeName);
+ }
+ if (glpOffsetServerVolume != 0)
+ {
+ free(glpOffsetServerVolume);
+ }
+ if (glpOffsetTapeDriveIdentifier != 0)
+ {
+ free(glpOffsetTapeDriveIdentifier);
+ }
+ if (glpOffsetTapeNeededName != 0)
+ {
+ free(glpOffsetTapeNeededName);
+ }
+ if (glpOffsetDiskName != 0)
+ {
+ free(glpOffsetDiskName);
+ }
+ if (glpOffsetActiveFile != 0)
+ {
+ free(glpOffsetActiveFile);
+ }
+ if (glpOffsetErrorMsg != 0)
+ {
+ free(glpOffsetErrorMsg);
+ }
+ if (pSTAT_SetStatusBlock != 0)
+ {
+ free(pSTAT_SetStatusBlock);
+ }
+ pSTAT_SetStatusBlock = 0;
+ }
+
+#endif
+}
+
+
+BOOL MON_LoadDDEManager()
+{
+#ifdef CAYMAN
+
+ mwhLibInst = LoadLibrary(DDEMANG);
+
+ if (mwhLibInst != NULL)
+ {
+ glpfnSetStatus = (ULONG FAR PASCAL)GetProcAddress(mwhLibInst, (LPSTR)MAKELONG(2, 0)); //SZ_DDEMANG);
+
+ if (*glpfnSetStatus == NULL)
+ {
+ FreeLibrary(mwhLibInst);
+ mwhLibInst = 0;
+ return FALSE;
+ }
+ } else
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
+
+BOOL MON_FreeDDEManager()
+{
+#ifdef CAYMAN
+ if (mwhLibInst != NULL)
+ {
+ glpfnSetStatus = 0L;
+ FreeLibrary(mwhLibInst);
+ return TRUE;
+ }
+#endif
+ return FALSE;
+}
+
+void CALLBACK DDEManagerTimerProc()
+{
+#ifdef CAYMAN
+ static UINT uiOldInterval;
+ UINT uiNewInterval;
+
+ if ((glpfnSetStatus != 0) && (pSTAT_SetStatusBlock != NULL))
+ {
+ MON_CreateStringList();
+ if (gfHWInitialized == TRUE)
+ {
+ pSTAT_SetStatusBlock->DriveStatus = STAT_DRIVE_VALID;
+ } else
+ {
+ pSTAT_SetStatusBlock->DriveStatus = STAT_DRIVE_BAD;
+ }
+ uiNewInterval = (*glpfnSetStatus)(pSTAT_SetStatusBlock);
+ if (uiNewInterval != uiOldInterval)
+ {
+ WM_SetTimerFrequency(mhStatusTimer, uiNewInterval);
+ uiOldInterval = uiNewInterval;
+ }
+ }
+#endif
+ return;
+}
+
+
+void SendStatusMsg(PSTAT_SETSTATUSBLOCK pStatusBlk)
+{
+#ifdef CAYMAN
+ ULONG ulTimer;
+
+ if ((glpfnSetStatus != 0) && (pSTAT_SetStatusBlock != NULL))
+ {
+ if (mhStatusTimer == 0)
+ {
+ mhStatusTimer = WM_HookTimer( DDEManagerTimerProc, 1 );
+ ulTimer = (*glpfnSetStatus)(pSTAT_SetStatusBlock);
+ } else
+ if (pStatusBlk == NULL)
+ {
+ WM_UnhookTimer( mhStatusTimer );
+ ulTimer = (*glpfnSetStatus)(NULL);
+ } else
+ {
+ ulTimer = (*glpfnSetStatus)(pSTAT_SetStatusBlock);
+ }
+ }
+#endif
+ return;
+}
+
+static BOOL MON_CreateStringList()
+{
+#ifdef CAYMAN
+ LPSTR lpString;
+ INT iStrSize = 0;
+ PSTAT_SETSTATUSBLOCK pTempBlock;
+
+ iStrSize = MON_SetSize(glpOffsetTapeDriveName);
+ iStrSize += MON_SetSize(glpOffsetCurrentTapeName);
+ iStrSize += MON_SetSize(glpOffsetServerVolume);
+ iStrSize += MON_SetSize(glpOffsetCurrentTapeName);
+ iStrSize += MON_SetSize(glpOffsetTapeDriveIdentifier);
+ iStrSize += MON_SetSize(glpOffsetTapeNeededName);
+ iStrSize += MON_SetSize(glpOffsetDiskName);
+ iStrSize += MON_SetSize(glpOffsetActiveFile);
+ iStrSize += MON_SetSize(glpOffsetErrorMsg);
+ iStrSize += MON_SetSize(glpOffsetActiveDir)+1;
+ if (iStrSize > (sizeof(pSTAT_SetStatusBlock) - sizeof(STAT_SETSTATUSBLOCK)))
+ {
+ pTempBlock = (PSTAT_SETSTATUSBLOCK)realloc(pSTAT_SetStatusBlock,
+ sizeof(STAT_SETSTATUSBLOCK) + iStrSize);
+ if (pTempBlock == NULL)
+ {
+ // Unable to allocate memory, return out.
+ return FALSE;
+ }
+ pSTAT_SetStatusBlock = pTempBlock;
+ }
+ lpString = (LPSTR)pSTAT_SetStatusBlock + sizeof(STAT_SETSTATUSBLOCK);
+ // We got the additional memory, now add the strings and set the offsets
+
+ pSTAT_SetStatusBlock->OffsetTapeDriveName =
+ MON_StringToStatusBlock(glpOffsetTapeDriveName, lpString);
+ if (glpOffsetTapeDriveName != 0)
+ {
+ lpString += strlen(glpOffsetTapeDriveName) + 1;
+ }
+
+ pSTAT_SetStatusBlock->OffsetCurrentTapeName =
+ MON_StringToStatusBlock(glpOffsetCurrentTapeName, lpString);
+ if (glpOffsetCurrentTapeName != 0)
+ {
+ lpString += strlen(glpOffsetCurrentTapeName) + 1;
+ }
+
+ pSTAT_SetStatusBlock->OffsetServerVolume =
+ MON_StringToStatusBlock(glpOffsetServerVolume, lpString);
+ if (glpOffsetServerVolume != 0)
+ {
+ lpString += strlen(glpOffsetServerVolume) + 1;
+ }
+
+ pSTAT_SetStatusBlock->OffsetTapeDriveIdentifier =
+ MON_StringToStatusBlock(glpOffsetTapeDriveIdentifier, lpString);
+ if (glpOffsetTapeDriveIdentifier != 0)
+ {
+ lpString += strlen(glpOffsetTapeDriveIdentifier) + 1;
+ }
+
+ pSTAT_SetStatusBlock->OffsetTapeNeededName =
+ MON_StringToStatusBlock(glpOffsetTapeNeededName, lpString);
+ if (glpOffsetTapeNeededName != 0)
+ {
+ lpString += strlen(glpOffsetTapeNeededName) + 1;
+ }
+
+ pSTAT_SetStatusBlock->OffsetDiskName =
+ MON_StringToStatusBlock(glpOffsetDiskName, lpString);
+ if (glpOffsetDiskName != 0)
+ {
+ lpString += strlen(glpOffsetDiskName) + 1;
+ }
+
+ pSTAT_SetStatusBlock->OffsetActiveFile =
+ MON_StringToStatusBlock(glpOffsetActiveFile, lpString);
+ if (glpOffsetActiveFile != 0)
+ {
+ lpString += strlen(glpOffsetActiveFile) + 1;
+ }
+
+ pSTAT_SetStatusBlock->OffsetErrorMsg =
+ MON_StringToStatusBlock(glpOffsetErrorMsg, lpString);
+ if (glpOffsetErrorMsg != 0)
+ {
+ lpString += strlen(glpOffsetErrorMsg) + 1;
+ }
+
+ pSTAT_SetStatusBlock->OffsetActiveDir =
+ MON_StringToStatusBlock(glpOffsetActiveDir, lpString);
+ if (glpOffsetActiveDir != 0)
+ {
+ lpString += strlen(glpOffsetActiveDir) + 1;
+ }
+
+#endif
+ return TRUE;
+}
+
+void SetStatusBlock(INT iType, DWORD dwValue)
+{
+#ifdef CAYMAN
+ if ((glpfnSetStatus != 0) && (pSTAT_SetStatusBlock != NULL))
+ {
+ switch(iType)
+ {
+ case IDSM_INSTANCE:
+ pSTAT_SetStatusBlock->Instance = dwValue;
+ break;
+
+ case IDSM_DATASIZE:
+ pSTAT_SetStatusBlock->DataSize = dwValue;
+ break;
+
+ case IDSM_UNICODE:
+ pSTAT_SetStatusBlock->Unicode = dwValue;
+ break;
+
+ case IDSM_OPERATIONSTATUS:
+ pSTAT_SetStatusBlock->OperationStatus = dwValue;
+ break;
+
+ case IDSM_APPSTATUS:
+ pSTAT_SetStatusBlock->AppStatus = dwValue;
+ break;
+
+ case IDSM_DRIVESTATUS:
+ pSTAT_SetStatusBlock->DriveStatus = dwValue;
+ break;
+
+ case IDSM_TAPEFAMILY:
+ pSTAT_SetStatusBlock->TapeFamily = dwValue;
+ break;
+
+ case IDSM_TAPESEQNUMBER:
+ pSTAT_SetStatusBlock->TapeSeqNumber = dwValue;
+ break;
+
+ case IDSM_BACKUPSET:
+ pSTAT_SetStatusBlock->BackupSet = dwValue;
+ break;
+
+ case IDSM_DIRCOUNT:
+ pSTAT_SetStatusBlock->DirCount = dwValue;
+ break;
+
+ case IDSM_FILECOUNT:
+ pSTAT_SetStatusBlock->FileCount = dwValue;
+ break;
+
+ case IDSM_BYTECOUNTLO:
+ pSTAT_SetStatusBlock->ByteCountLo = dwValue;
+ break;
+
+ case IDSM_BYTECOUNTHI:
+ pSTAT_SetStatusBlock->ByteCountHi = dwValue;
+ break;
+
+ case IDSM_CORRUPTFILECOUNT:
+ pSTAT_SetStatusBlock->CorruptFileCount = dwValue;
+ break;
+
+ case IDSM_SKIPPEDFILECOUNT:
+ pSTAT_SetStatusBlock->SkippedFileCount = dwValue;
+ break;
+
+ case IDSM_ELAPSEDSECONDS:
+ pSTAT_SetStatusBlock->ElapsedSeconds = dwValue;
+ break;
+
+ case IDSM_TAPEFAMILYNEEDED:
+ pSTAT_SetStatusBlock->TapeFamilyNeeded = dwValue;
+ break;
+
+ case IDSM_TAPESEQNEEDED:
+ pSTAT_SetStatusBlock->TapeSeqNeeded = dwValue;
+ break;
+
+ case IDSM_OFFSETTAPEDRIVENAME:
+ if (glpOffsetTapeDriveName != 0)
+ {
+ free(glpOffsetTapeDriveName);
+ glpOffsetTapeDriveName = NULL;
+ }
+ glpOffsetTapeDriveName = (LPSTR)calloc(strlen((LPSTR)dwValue), sizeof(CHAR));
+ strcpy(glpOffsetTapeDriveName, (LPSTR)dwValue);
+ break;
+
+ case IDSM_OFFSETCURRENTTAPENAME:
+ if (glpOffsetCurrentTapeName != 0)
+ {
+ free(glpOffsetCurrentTapeName);
+ glpOffsetCurrentTapeName = NULL;
+ }
+ glpOffsetCurrentTapeName = (LPSTR)calloc(strlen((LPSTR)dwValue), sizeof(CHAR));
+ strcpy(glpOffsetCurrentTapeName, (LPSTR)dwValue);
+ break;
+
+ case IDSM_OFFSETSERVERVOLUME:
+ if (glpOffsetServerVolume != 0)
+ {
+ free(glpOffsetServerVolume);
+ glpOffsetServerVolume = NULL;
+ }
+ glpOffsetServerVolume = (LPSTR)calloc(strlen((LPSTR)dwValue), sizeof(CHAR));
+ strcpy(glpOffsetServerVolume, (LPSTR)dwValue);
+ break;
+
+ case IDSM_OFFSETTAPEDRIVEIDENTIFIER:
+ if (glpOffsetTapeDriveIdentifier != 0)
+ {
+ free(glpOffsetTapeDriveIdentifier);
+ glpOffsetTapeDriveIdentifier = NULL;
+ }
+ glpOffsetTapeDriveIdentifier = (LPSTR)calloc(strlen((LPSTR)dwValue), sizeof(CHAR));
+ strcpy(glpOffsetTapeDriveIdentifier, (LPSTR)dwValue);
+ break;
+
+ case IDSM_OFFSETTAPENEEDEDNAME:
+ if (glpOffsetTapeNeededName != 0)
+ {
+ free(glpOffsetTapeNeededName);
+ glpOffsetTapeNeededName = NULL;
+ }
+ glpOffsetTapeNeededName = (LPSTR)calloc(strlen((LPSTR)dwValue), sizeof(CHAR));
+ strcpy(glpOffsetTapeNeededName, (LPSTR)dwValue);
+ break;
+
+ case IDSM_OFFSETDISKNAME:
+ if (glpOffsetDiskName != 0)
+ {
+ free(glpOffsetDiskName);
+ glpOffsetDiskName = NULL;
+ }
+ glpOffsetDiskName = (LPSTR)calloc(strlen((LPSTR)dwValue), sizeof(CHAR));
+ strcpy(glpOffsetDiskName, (LPSTR)dwValue);
+ break;
+
+ case IDSM_OFFSETACTIVEFILE:
+ if (glpOffsetActiveFile != 0)
+ {
+ free(glpOffsetActiveFile);
+ glpOffsetActiveFile = NULL;
+ }
+ glpOffsetActiveFile = (LPSTR)calloc(strlen((LPSTR)dwValue), sizeof(CHAR));
+ strcpy(glpOffsetActiveFile, (LPSTR)dwValue);
+ break;
+
+ case IDSM_OFFSETERRORMSG:
+ if (glpOffsetErrorMsg != 0)
+ {
+ free(glpOffsetErrorMsg);
+ glpOffsetErrorMsg = NULL;
+ }
+ glpOffsetErrorMsg = (LPSTR)calloc(strlen((LPSTR)dwValue), sizeof(CHAR));
+ strcpy(glpOffsetErrorMsg, (LPSTR)dwValue);
+ break;
+
+ case IDSM_OFFSETACTIVEDIR:
+ if (glpOffsetActiveDir != 0)
+ {
+ free(glpOffsetActiveDir);
+ glpOffsetActiveDir = NULL;
+ }
+ glpOffsetActiveDir = (LPSTR)calloc(strlen((LPSTR)dwValue), sizeof(CHAR));
+ strcpy(glpOffsetActiveDir, (LPSTR)dwValue);
+ break;
+ }
+ }
+#endif
+ return;
+}
+
+
+/**
+
+ Name: GUI_ValidAtoiResult
+
+ Desc: Validates that atoi didn't fail to convert a string
+ to an integer because of an invalid character. atoi()
+ will return 0 if it fails.
+
+ Return: TRUE if string was zero.
+**/
+
+BOOL
+GUI_ValidAtoiResult( CHAR *pszChar, INT nTapeNumber )
+{
+BOOL fRetValu = TRUE ;
+CHAR *pStrStart = pszChar ;
+
+ if ( nTapeNumber == 0 )
+ {
+ while ( *pszChar == TEXT('0') )
+ {
+ pszChar++ ;
+ }
+
+ if ( ( *pszChar != TEXT('\0') ) || ( pStrStart == pszChar ) )
+ {
+ fRetValu = FALSE ;
+ }
+ }
+
+ return( fRetValu ) ;
+}
+
+
+#ifdef CAYMAN
+INT MON_SetSize(LPSTR lpString)
+{
+ INT iRet = 0;
+
+ if (lpString != 0)
+ {
+ iRet = strlen(lpString);
+ }
+ return iRet;
+}
+
+DWORD MON_StringToStatusBlock(LPSTR lpInString, LPSTR lpPlace)
+{
+ DWORD dwRet = 0;
+ INT iSize;
+
+ if (lpInString != 0)
+ {
+ dwRet = (DWORD)((LPSTR)lpPlace - (LPSTR)pSTAT_SetStatusBlock);
+ iSize = strlen(lpInString);
+ strncpy(lpPlace, lpInString, iSize);
+ *(lpPlace+iSize) = 0;
+ }
+ return dwRet;
+}
+
+
+#endif
+
+static BOOL GUI_ValidateCmdLine( LPSTR CmdLine )
+{
+ LPSTR pszNext = NULL; // Next command line item pointer
+ LPSTR pszCmdLine;
+ CHAR szBackup[ IDS_OEM_MAX_LEN ];
+ CHAR szEject[ IDS_OEM_MAX_LEN ];
+ CHAR szTokens[ IDS_OEM_MAX_LEN ];
+ OEMOPTS_PTR pOemOpts = NULL;
+ BSD_PTR bsd ;
+ LPSTR pszQuotedString;
+ BOOLEAN QuoteState = FALSE;
+ BOOL cmd_line_error;
+ BOOL oem_batch_mode;
+ BOOL oem_batch_eject_mode;
+ BOOL first_switch ;
+ INT opt_id ;
+ BOOL ret_val = SUCCESS;
+ BOOL path_specified = FALSE ;
+ BOOL switch_specified = FALSE ;
+
+ if ( CmdLine ) //global command line pointer
+ {
+
+ pszCmdLine = malloc( ( strlen( CmdLine ) + 1 ) * sizeof(CHAR) );
+
+ if ( pszCmdLine == NULL ) { //uh-oh - memory allocation problem!!
+
+ return FAILURE;
+ }
+
+ pszQuotedString = malloc( ( strlen( CmdLine ) + 1 ) * sizeof(CHAR) );
+
+ if ( pszQuotedString == NULL ) { //uh-oh - memory allocation problem!!
+
+ free( pszCmdLine );
+ return FAILURE;
+ }
+
+ strcpy( pszCmdLine, CmdLine );
+
+ RSM_StringCopy ( IDS_OEMBATCH_BACKUP,
+ szBackup, sizeof ( szBackup ) );
+
+ RSM_StringCopy ( IDS_OEMBATCH_EJECT,
+ szEject, sizeof ( szEject ) );
+
+ RSM_StringCopy ( IDS_OEMOPT_TOKENSEPS,
+ szTokens, sizeof ( szTokens ) );
+
+ pszNext = strtok ( pszCmdLine, szTokens ); //skip leading spaces
+
+ oem_batch_mode = cmd_line_error = FALSE ;
+ first_switch = TRUE ;
+
+ if ( pszNext &&
+ ( pOemOpts = OEM_DefaultBatchOptions () ) &&
+ ( (strnicmp ( pszNext, szBackup, strlen( pszNext ) ) == 0 ) ||
+ ( strnicmp ( pszNext, szEject, strlen( pszNext ) ) == 0 ) ) )
+ {
+ oem_batch_mode = TRUE ;
+ oem_batch_eject_mode = FALSE ;
+
+ if ( strnicmp ( pszNext, szEject, strlen( pszNext ) ) == 0 ) {
+ oem_batch_eject_mode = TRUE ;
+ }
+
+
+ // Process the command line: all following items in the command
+ // line must be one or more path specifiers with optional batch
+ // options mixed in.
+
+
+ if ( strlen( LOG_GetCurrentLogName( ) ) > 0 ) { // chs:07-16-93
+ lresprintf( LOGGING_FILE, LOG_START, FALSE ); // chs:07-16-93
+ lresprintf( LOGGING_FILE, LOG_END ); // chs:07-16-93
+ } // chs:07-16-93
+ }
+
+ while ( (first_switch && !oem_batch_mode ) ||
+ (pszNext = strtok ( NULL, szTokens ) ) ) {
+
+ first_switch = FALSE ;
+ opt_id = OEM_ProcessBatchCmdOption (
+ pOemOpts,
+ pszNext,
+ szTokens,
+ pszCmdLine ) ;
+
+ if ( oem_batch_mode && ( opt_id == IDS_OEMOPT_NOTANOPTION ) )
+
+ {
+
+ //
+ // Previous logic did not account for a directory name haveing spaces
+ // example ... "G:\SUB DIR WITH SPACE". This was the easiest way
+ // to fix this problem without changing the central logic of
+ // the codes.
+ //
+
+ if ( *pszNext == TEXT( '"' ) || QuoteState ) {
+ if ( !QuoteState ) strcpy( pszQuotedString, TEXT( "" ) );
+ QuoteState = TRUE;
+ if ( *pszNext == TEXT( '"' ) ) {
+ GUI_ProcessQuotedString ( pszQuotedString, ( pszNext + 1 ), &QuoteState );
+ } else {
+ GUI_ProcessQuotedString ( pszQuotedString, pszNext, &QuoteState );
+ }
+ if ( QuoteState ) {
+
+ strcat( pszQuotedString, TEXT( " " ) );
+ } else {
+
+ path_specified = TRUE ;
+ if ( switch_specified ||
+ ( (*(pszQuotedString+1) != ':') && *pszQuotedString != '\\' ) ) {
+ ret_val = FAILURE ;
+ cmd_line_error = TRUE ;
+ break ;
+ }
+
+ }
+ } else {
+
+ path_specified = TRUE ;
+ if ( switch_specified ||
+ ( (*(pszNext+1) != ':') && *pszNext != '\\' ) ) {
+
+ CHAR szDSA[ IDS_OEM_MAX_LEN ];
+ CHAR szMonolithic[ IDS_OEM_MAX_LEN ];
+
+ RSM_StringCopy ( IDS_OEMOPT_DSA,
+ szDSA, sizeof ( szDSA ) );
+
+ RSM_StringCopy ( IDS_OEMOPT_MONOLITHIC,
+ szMonolithic, sizeof ( szMonolithic ) );
+
+ if ( stricmp( szDSA, pszNext ) && stricmp(szMonolithic, pszNext) ) {
+
+ ret_val = FAILURE ;
+ cmd_line_error = TRUE ;
+ break ;
+ }
+
+ strtok ( NULL, szTokens ) ;
+ }
+ }
+
+ } else {
+
+ switch_specified = TRUE ;
+
+ if ( oem_batch_mode && (opt_id == IDS_OEMOPT_NOPOLLOPTION) ) {
+ cmd_line_error = TRUE ;
+ }
+
+ if ( opt_id == IDS_OEMOPT_USAGE ) {
+ /* help for usage */
+ HM_DialogHelp( IDH_DB_BATCHHELP );
+ cmd_line_error = FALSE ;
+ ret_val = FAILURE ;
+
+ } else if ((pszNext && ( opt_id == IDS_OEMOPT_UNKNOWN )) ||
+ (pszNext && !oem_batch_mode &&
+ ( opt_id != IDS_OEMOPT_NOPOLLOPTION) ) &&
+ ( opt_id != IDS_OEMOPT_VALIDGUIOPTION) ) {
+ cmd_line_error = TRUE ;
+
+ }
+ }
+ }
+
+ if ( cmd_line_error || ( !path_specified && oem_batch_mode && !oem_batch_eject_mode) ) {
+ yresprintf( (INT16) RES_INVALID_PARAMETER, CmdLine );
+
+ WM_MessageBox( ID( IDS_MSGTITLE_WARNING ), // chs:04-29-93
+ gszTprintfBuffer, // chs:04-29-93
+ WMMB_OK | WMMB_NOYYCHECK, // chs:04-29-93
+ WMMB_ICONEXCLAMATION, NULL, 0, IDH_DB_BATCHHELP ); // chs:04-29-93
+ ret_val = FAILURE ;
+ }
+ }
+ free( pszCmdLine );
+ free( pszQuotedString );
+ return ret_val ;
+}
+
+
+VOID GUI_ProcessQuotedString ( LPSTR OutPutString,
+ LPSTR InPutString,
+ BOOLEAN *QuoteState )
+{
+ UINT16 lngth;
+
+ lngth = strlen( InPutString );
+ if ( lngth < 1 ) {
+ return;
+ }
+
+ if ( *( InPutString + lngth - 1 ) == TEXT( '"' ) ) {
+ if ( *QuoteState ) {
+ *( InPutString + lngth - 1 ) = TEXT( '\0' );
+ strcat( OutPutString, InPutString );
+ *QuoteState = *QuoteState ? FALSE : TRUE;
+ }
+ }
+
+ if ( *QuoteState ) {
+ strcat( OutPutString, InPutString );
+ }
+}
+
+
diff --git a/private/utils/ntbackup/src/hcrpfile.bmp b/private/utils/ntbackup/src/hcrpfile.bmp
new file mode 100644
index 000000000..11d66ae45
--- /dev/null
+++ b/private/utils/ntbackup/src/hcrpfile.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/help.cur b/private/utils/ntbackup/src/help.cur
new file mode 100644
index 000000000..80b03e08f
--- /dev/null
+++ b/private/utils/ntbackup/src/help.cur
Binary files differ
diff --git a/private/utils/ntbackup/src/helpmang.c b/private/utils/ntbackup/src/helpmang.c
new file mode 100644
index 000000000..868f05dd8
--- /dev/null
+++ b/private/utils/ntbackup/src/helpmang.c
@@ -0,0 +1,1404 @@
+/****************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+ Name: helpmang.c
+
+ Description: This file contains routines for Help Manager.
+
+ The following routines are in this module:
+
+ HM_DialogFilter
+ HM_Init
+ HM_Deinit
+ HM_FindHelpId
+ HM_MakeHelpPathName
+ HM_WinHelp
+ HM_MenuCommands
+ HM_ContextLbuttonDown
+ HM_GetWindowClassHelpId
+ HM_KeyDown
+ HM_SetCursor
+ HM_InitMenu
+ HM_EnterIdle
+ HM_CloseHelpWindow
+
+
+ $Log: G:\UI\LOGFILES\HELPMANG.C_V $
+
+ Rev 1.43 11 Jan 1994 11:17:46 mikep
+change ifdef
+
+ Rev 1.42 22 Nov 1993 16:12:50 BARRY
+Unicode fixes: put TEXT around literals
+
+ Rev 1.41 19 Jul 1993 19:21:02 MARINA
+enable c++, move mw* vars from header
+
+ Rev 1.40 14 May 1993 14:32:58 DARRYLP
+Added help for operations info.
+
+ Rev 1.39 22 Apr 1993 15:58:20 GLENN
+Added file SORT option support.
+
+ Rev 1.38 02 Apr 1993 14:11:20 GLENN
+Changed to NT help menu style and IDs.
+
+ Rev 1.37 29 Mar 1993 10:11:32 DARRYLP
+Added context help for Operation.Format.
+
+ Rev 1.36 24 Mar 1993 14:52:40 DARRYLP
+Added Help for Font viewer/other common dialogs
+
+ Rev 1.35 18 Mar 1993 15:26:56 ROBG
+Fixed context-sensitive functionality for menu area for Cayman.
+
+ Rev 1.34 18 Mar 1993 11:43:00 ROBG
+Fixed the class name parameter in the GetClassName call.
+
+ Rev 1.33 15 Mar 1993 14:39:24 ROBG
+More changes to support OEM_MSOFT WM_SYSCOMMAND help.
+
+ Rev 1.32 15 Mar 1993 09:50:28 ROBG
+Took out context-sensitive HELP for OEM_MSOFT.
+
+ Rev 1.31 12 Mar 1993 17:53:58 ROBG
+More fixes.
+
+ Rev 1.29 18 Jan 1993 14:49:54 GLENN
+Changed HM_EnterIdle() return type.
+
+ Rev 1.28 01 Nov 1992 15:58:54 DAVEV
+Unicode changes
+
+ Rev 1.27 07 Oct 1992 14:07:34 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.26 04 Oct 1992 19:37:46 DAVEV
+Unicode Awk pass
+
+ Rev 1.25 08 Sep 1992 16:43:36 DARRYLP
+
+ Rev 1.24 17 Aug 1992 13:18:48 DAVEV
+MikeP's changes at Microsoft
+
+ Rev 1.23 11 Jun 1992 10:59:24 GLENN
+Now pulling in omhelpid.h. Fixed unresolved helpids.
+
+ Rev 1.22 29 May 1992 15:58:54 JOHNWT
+PCH updates
+
+ Rev 1.21 23 Apr 1992 14:35:12 ROBG
+Fixed problem with hitting F1 on a grayed out item.
+
+ Rev 1.20 22 Apr 1992 14:30:12 ROBG
+changed
+
+ Rev 1.19 23 Mar 1992 10:06:04 DAVEV
+changes for OEM_MSOFT
+
+ Rev 1.18 17 Mar 1992 13:12:02 ROBG
+changed
+
+ Rev 1.17 17 Mar 1992 11:55:20 ROBG
+changed
+
+ Rev 1.16 16 Mar 1992 16:35:36 ROBG
+changed
+
+ Rev 1.15 09 Mar 1992 16:19:44 ROBG
+changed
+
+ Rev 1.14 02 Mar 1992 17:09:36 DAVEV
+Added case for IDM_HELPSEARCH for Nostradamus
+
+ Rev 1.13 02 Mar 1992 14:56:12 DAVEV
+Changes for Nostradamus unique features
+
+ Rev 1.12 18 Feb 1992 20:40:38 GLENN
+Updated variables.
+
+ Rev 1.11 11 Feb 1992 17:24:54 GLENN
+Removed unnecessary menu related code.
+
+ Rev 1.10 05 Feb 1992 17:54:16 GLENN
+Replaced dialog string lookup table and supporting code with IDHELP call to specific dialog.
+
+ Rev 1.9 27 Jan 1992 00:32:26 CHUCKB
+Updated dialog id's.
+
+ Rev 1.8 24 Jan 1992 10:09:42 GLENN
+Matched the deinit call with it's prototype.
+
+ Rev 1.7 14 Jan 1992 11:39:52 ROBG
+Added "Job Status - " strings.
+
+ Rev 1.6 13 Jan 1992 15:29:44 ROBG
+Added HELPID_DIALOGTRANSFER.
+
+ Rev 1.5 09 Jan 1992 11:47:04 ROBG
+Updated IDs.
+
+ Rev 1.3 18 Dec 1991 15:52:12 DAVEV
+16/32 bit port - 2nd pass
+
+ Rev 1.2 05 Dec 1991 11:02:04 GLENN
+Changed WM_GetActive to WM_GetActiveDoc
+
+ Rev 1.1 04 Dec 1991 15:20:14 DAVEV
+Modifications for 16/32-bit Windows port - 1st pass.
+
+
+ Rev 1.0 20 Nov 1991 19:32:54 SYSTEM
+Initial revision.
+
+****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+static BOOL mwfHelp ; /* Help mode flag; TRUE = TEXT("ON") */
+static HCURSOR mwhHelpCursor; /* Cursor displayed when in help mode */
+static CHAR mwszHelpFilename[NAME_MAX_SIZE+1]; /* Help file name */
+static FARPROC mwlpfnNextHook ;
+static FARPROC mwlpFilterFunc ;
+
+HELPID_MENUID_TABLE HelpIdMenuIdTable[] = {
+
+#if defined ( OEM_MSOFT ) // OEM Microsoft product alternate help table
+
+ { IDM_OPERATIONSBACKUP ,HELPID_OPERATIONSBACKUP } ,
+ { IDM_OPERATIONSRESTORE ,HELPID_OPERATIONSRESTORE } ,
+ { IDM_OPERATIONSCATALOG ,HELPID_OPERATIONSCATALOG } ,
+ { IDM_OPERATIONSERASE ,HELPID_OPERATIONSERASE } ,
+ { IDM_OPERATIONSRETENSION ,HELPID_OPERATIONSRETENSION } ,
+ { IDM_OPERATIONSFORMAT ,HELPID_OPERATIONSFORMAT } ,
+ { IDM_OPERATIONSEJECT ,HELPID_OPERATIONSEJECT } ,
+ { IDM_OPERATIONSHARDWARE ,HELPID_OPERATIONSHARDWARE } ,
+ { IDM_OPERATIONSEXIT ,HELPID_OPERATIONSEXIT } ,
+#ifdef OEM_EMS
+ { IDM_OPERATIONSEXCHANGE ,HELPID_OPERATIONSEXCHANGE } ,
+#endif
+
+ { IDM_TREEEXPANDONE ,HELPID_TREEEXPANDONE } ,
+ { IDM_TREEEXPANDBRANCH ,HELPID_TREEEXPANDBRANCH } ,
+ { IDM_TREEEXPANDALL ,HELPID_TREEEXPANDALL } ,
+ { IDM_TREECOLLAPSEBRANCH ,HELPID_TREECOLLAPSEBRANCH } ,
+
+ { IDM_VIEWTREEANDDIR ,HELPID_VIEWTREEANDDIR } ,
+ { IDM_VIEWTREEONLY ,HELPID_VIEWTREEONLY } ,
+ { IDM_VIEWDIRONLY ,HELPID_VIEWDIRONLY } ,
+ { IDM_VIEWSPLIT ,HELPID_VIEWSPLIT } ,
+ { IDM_VIEWALLFILEDETAILS ,HELPID_VIEWALLFILEDETAILS } ,
+ { IDM_VIEWSTATUS ,HELPID_VIEWSTATUS } ,
+ { IDM_VIEWURIBBON ,HELPID_VIEWURIBBON } ,
+ { IDM_VIEWFONT ,HELPID_VIEWFONTS } ,
+
+ { IDM_SELECTCHECK ,HELPID_SELECTCHECK } ,
+ { IDM_SELECTUNCHECK ,HELPID_SELECTUNCHECK } ,
+
+ { IDM_WINDOWSCASCADE ,HELPID_WINDOWSCASCADE } ,
+ { IDM_WINDOWSTILE ,HELPID_WINDOWSTILE } ,
+ { IDM_WINDOWSARRANGEICONS ,HELPID_WINDOWSARRANGEICONS } ,
+ { IDM_WINDOWSREFRESH ,HELPID_WINDOWSREFRESH } ,
+ { IDM_WINDOWSCLOSEALL ,HELPID_WINDOWSCLOSEALL } ,
+
+ { IDM_HELPINDEX ,HELPID_HELPINDEX } ,
+ { IDM_HELPSEARCH ,HELPID_HELPSEARCH } ,
+ { IDM_HELPUSINGHELP ,HELPID_HELPUSINGHELP } ,
+ { IDM_HELPABOUTNOSTRADOMUS ,HELPID_HELPABOUTNOSTRADOMUS } ,
+ { 0 , 0 }
+
+#else // Standard Maynstream for Windows help table:
+
+ { IDM_FILEPRINT ,HELPID_FILEPRINT } ,
+ { IDM_FILESETUP ,HELPID_FILESETUP } ,
+ { IDM_FILEEXIT ,HELPID_FILEEXIT } ,
+
+ { IDM_JOBMAINTENANCE ,HELPID_JOBMAINTENANCE } ,
+
+ { IDM_TREEEXPANDONE ,HELPID_TREEEXPANDONE } ,
+ { IDM_TREEEXPANDBRANCH ,HELPID_TREEEXPANDBRANCH } ,
+ { IDM_TREEEXPANDALL ,HELPID_TREEEXPANDALL } ,
+ { IDM_TREECOLLAPSEBRANCH ,HELPID_TREECOLLAPSEBRANCH } ,
+
+ { IDM_VIEWTREEANDDIR ,HELPID_VIEWTREEANDDIR } ,
+ { IDM_VIEWTREEONLY ,HELPID_VIEWTREEONLY } ,
+ { IDM_VIEWDIRONLY ,HELPID_VIEWDIRONLY } ,
+ { IDM_VIEWSPLIT ,HELPID_VIEWSPLIT } ,
+ { IDM_VIEWALLFILEDETAILS ,HELPID_VIEWALLFILEDETAILS } ,
+ { IDM_VIEWSORTNAME ,HELPID_VIEWSORTNAME } ,
+ { IDM_VIEWSORTTYPE ,HELPID_VIEWSORTTYPE } ,
+ { IDM_VIEWSORTSIZE ,HELPID_VIEWSORTSIZE } ,
+ { IDM_VIEWSORTDATE ,HELPID_VIEWSORTDATE } ,
+ { IDM_VIEWFONT ,HELPID_VIEWFONTS } ,
+
+ { IDM_OPERATIONSBACKUP ,HELPID_OPERATIONSBACKUP } ,
+ { IDM_OPERATIONSRESTORE ,HELPID_OPERATIONSRESTORE } ,
+ { IDM_OPERATIONSTRANSFER ,HELPID_OPERATIONSTRANSFER } ,
+ { IDM_OPERATIONSVERIFY ,HELPID_OPERATIONSVERIFY } ,
+ { IDM_OPERATIONSINFO ,HELPID_OPERATIONSINFO } ,
+ { IDM_OPERATIONSCATALOG ,HELPID_OPERATIONSCATALOG } ,
+ { IDM_OPERATIONSCATMAINT ,HELPID_OPERATIONSCATMAINT } ,
+ { IDM_OPERATIONSSEARCH ,HELPID_OPERATIONSSEARCH } ,
+ { IDM_OPERATIONSNEXTSET ,HELPID_OPERATIONSNEXTSET } ,
+ { IDM_OPERATIONSEJECT ,HELPID_OPERATIONSEJECT } ,
+ { IDM_OPERATIONSERASE ,HELPID_OPERATIONSERASE } ,
+ { IDM_OPERATIONSRETENSION ,HELPID_OPERATIONSRETENSION } ,
+ { IDM_OPERATIONSCONNECT ,HELPID_OPERATIONSCONNECT } ,
+ { IDM_OPERATIONSDISCON ,HELPID_OPERATIONSDISCON } ,
+ { IDM_OPERATIONSFORMAT ,HELPID_OPERATIONSFORMAT } ,
+
+ { IDM_SELECTCHECK ,HELPID_SELECTCHECK } ,
+ { IDM_SELECTUNCHECK ,HELPID_SELECTUNCHECK } ,
+ { IDM_SELECTADVANCED ,HELPID_SELECTADVANCED } ,
+ { IDM_SELECTSUBDIRS ,HELPID_SELECTSUBDIRS } ,
+ { IDM_SELECTSAVE ,HELPID_SELECTSAVE } ,
+ { IDM_SELECTUSE ,HELPID_SELECTUSE } ,
+ { IDM_SELECTDELETE ,HELPID_SELECTDELETE } ,
+ { IDM_SELECTCLEAR ,HELPID_SELECTCLEAR } ,
+
+ { IDM_SETTINGSGENERAL ,HELPID_SETTINGSGENERAL } ,
+ { IDM_SETTINGSBACKUP ,HELPID_SETTINGSBACKUP } ,
+ { IDM_SETTINGSRESTORE ,HELPID_SETTINGSRESTORE } ,
+ { IDM_SETTINGSLOGGING ,HELPID_SETTINGSLOGGING } ,
+ { IDM_SETTINGSNETWORK ,HELPID_SETTINGSNETWORK } ,
+ { IDM_SETTINGSCATALOG ,HELPID_SETTINGSCATALOG } ,
+ { IDM_SETTINGSHARDWARE ,HELPID_SETTINGSHARDWARE } ,
+ { IDM_SETTINGSDEBUGWINDOW ,HELPID_SETTINGSDEBUGWINDOW } ,
+
+ { IDM_WINDOWSCASCADE ,HELPID_WINDOWSCASCADE } ,
+ { IDM_WINDOWSTILE ,HELPID_WINDOWSTILE } ,
+ { IDM_WINDOWSREFRESH ,HELPID_WINDOWSREFRESH } ,
+ { IDM_WINDOWSCLOSEALL ,HELPID_WINDOWSCLOSEALL } ,
+ { IDM_WINDOWSARRANGEICONS ,HELPID_WINDOWSARRANGEICONS } ,
+
+ { IDM_HELPINDEX ,HELPID_HELPINDEX } ,
+ { IDM_HELPSEARCH ,HELPID_HELPSEARCH } ,
+ { IDM_HELPUSINGHELP ,HELPID_HELPUSINGHELP } ,
+ { IDM_HELPABOUTWINTERPARK ,HELPID_HELPABOUTWINTERPARK } ,
+ { 0 , 0 }
+
+#endif // else !defined ( OEM_MSOFT ) - alternate help tables
+} ;
+
+
+/****************************************************************************
+
+ Name: HM_Init
+
+ Description: This function will establish a window hook to
+ the Winter Park task.
+
+ Modified: 6/25/1991
+
+ Returns: 0
+
+ Notes:
+ This function should only be called only once.
+ See also:
+
+****************************************************************************/
+
+VOID HM_Init ( VOID )
+
+{
+
+ mwfHelp = FALSE ;
+
+ HM_MakeHelpPathName(mwszHelpFilename);
+
+ mwhHelpCursor = RSM_CursorLoad( IDRC_HELP );
+
+ mwlpFilterFunc = (FARPROC)MakeProcInstance( (FARPROC)HM_DialogFilter, ghInst ) ;
+
+ mwlpfnNextHook = (FARPROC)SetWindowsHook( WH_MSGFILTER, (HOOKPROC)mwlpFilterFunc ) ;
+
+}
+
+
+
+
+/****************************************************************************
+
+ Name: HM_Deinit
+
+ Description: This function will unhook the help window hook to
+ the Winter Park task.
+
+ Modified: 6/25/1991
+
+ Returns: none
+
+****************************************************************************/
+
+VOID HM_Deinit ( VOID )
+
+{
+
+ UnhookWindowsHook( WH_MSGFILTER, (HOOKPROC)mwlpFilterFunc ) ;
+
+ FreeProcInstance( mwlpFilterFunc ) ;
+
+}
+
+
+
+/****************************************************************************
+
+ Name: HM_DialogFilter
+
+ Description: This function will filter all dialog messages, looking
+ for the pressing of a F1 key. If the F1 key has been
+ found to be pressed, then the help subsystem is called.
+
+ Modified: 6/25/1991
+
+ Returns: 1 if message was processed and should be discarded.
+ 0 if message was not processed and should be processed
+ by windows.
+
+ Notes:
+ This function is called by Windows 3.0 directly.
+
+ See also:
+
+****************************************************************************/
+
+INT APIENTRY HM_DialogFilter(
+
+ INT nCode , /* Specifies the type of message being processed.*/
+ MP1 mp1, /* Specifies a NULL value. */
+ MP2 mp2 ) /* Points to the message structure. */
+
+{
+ LPMSG lpMessage ;
+ WORD wMsgProcessed = FALSE ;
+ DWORD dwResult ;
+
+ /* Under Windows, nCode specifies whether the filter function
+ should process the message or call the DefHookProc function.
+ If this value is less than zero, the filter function should
+ pass the message to DefHookProc without further processing.
+ */
+
+ if ( nCode < 0 ) {
+ dwResult = DefHookProc ( nCode, (DWORD)mp1, (LONG)mp2, (VOID **)mwlpfnNextHook ) ;
+ return ( TRUE ) ;
+ }
+
+ /* If the message is for a dialogbox, intercept the processing
+ of a F1 key stroke to activate the help subsystem.
+ */
+
+ if ( nCode == MSGF_DIALOGBOX ) {
+
+ lpMessage = (LPMSG) mp2 ;
+
+ switch ( lpMessage->message ) {
+
+ case WM_KEYDOWN:
+
+ if (lpMessage->wParam == VK_F1) {
+
+ /* If F1 or shift F1, then call up the appropiate help
+ Post to frame procedure
+ */
+
+ mwfHelp = FALSE ;
+ wMsgProcessed = TRUE ;
+
+ // Post a Help button message to the dialog.
+ // The lpMessage->hwnd is the handle of the control that has focus
+ // in the dialog. Use the parent of this control to obtain the
+ // dialog's handle.
+ if (ghWndCommonDlg == 0)
+ {
+ PostMessage ( GetParent( lpMessage->hwnd ), WM_COMMAND, IDHELP, (MP2)NULL );
+ } else
+ {
+ PostMessage ( ghWndCommonDlg, WM_COMMAND, IDHELP, (MP2)NULL );
+ }
+ }
+
+ break ;
+ }
+
+ }
+
+ return( wMsgProcessed ) ;
+
+}
+
+
+
+/****************************************************************************
+
+ Name: HM_FindHelpId
+
+ Description: This function will return the HELPID value for
+ a given Menu item.
+
+ Modified: 6/25/1991
+
+ Returns: Non zero if the dialog has an associated HELPID.
+ 0 if the dialog has no associated HELPID.
+
+ Notes:
+ This function is called only by the Help Manager.
+
+ See also:
+
+****************************************************************************/
+
+WORD HM_FindHelpId(
+
+WORD wMenuId ) /* I - Menu Id */
+
+{
+
+ WORD wHelpId = 0 ;
+ BOOL fFound = FALSE ;
+ WORD i = 0 ;
+
+ /* Scan the MenuId Table for the MenuId
+ Last Entry is NULL to designate end of table
+ */
+
+ while ( ( HelpIdMenuIdTable[ i ].wMenuId ) && ( !fFound ) ) {
+
+ if ( HelpIdMenuIdTable[ i ].wMenuId == wMenuId ) {
+
+ wHelpId = HelpIdMenuIdTable[i].wHelpId ;
+ fFound = TRUE ;
+ }
+
+ i++ ;
+ }
+
+
+ // If not found, then check to see if it is a log file selection
+ // or an MDI document selection.
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ if ( fFound == FALSE ) {
+
+ if ( ( wMenuId >= IDM_WINDOWSFIRSTCHILD ) && ( wMenuId < IDM_JOBSFIRSTJOB ) ) {
+ wHelpId = HELPID_MDISELECT ;
+ }
+
+ if ( ( wMenuId >= IDM_JOBSFIRSTJOB ) && ( wMenuId <= IDM_JOBSLASTJOB ) ) {
+
+ wHelpId = HELPID_JOBSELECT ;
+ }
+ }
+ }
+# else //!defined ( OEM_MSOFT )
+
+ {
+ if ( fFound == FALSE ) {
+
+ // To identify the drives and tape windows.
+
+ if ( ( wMenuId >= IDM_WINDOWSFIRSTCHILD ) ) {
+ wHelpId = IDH_MENU_WINDOWSNAMES ;
+ }
+
+ }
+ }
+# endif
+
+
+ return ( wHelpId ) ;
+}
+
+
+/****************************************************************************
+
+ Name: HM_MakeHelpPathName
+
+ Description: This function will return the full path name
+ of the help file for Winter Park.
+
+ Modified: 6/25/1991
+
+ Returns: file name
+
+ Notes:
+ This function is called only by the Help Manager at
+ initialization time.
+
+ See also:
+
+****************************************************************************/
+
+
+VOID HM_MakeHelpPathName(
+
+LPSTR szFileName ) /* O - File name */
+
+{
+ CHAR * pcFileName;
+ INT nFileNameLen;
+ CHAR szFname[ NAME_MAX_SIZE+1 ] ;
+
+ nFileNameLen = GetModuleFileName( ghInst,szFileName,NAME_MAX_SIZE);
+ pcFileName = szFileName + nFileNameLen;
+
+
+ /* With the full directory name, traverse backwards to strip off
+ the file name.
+ */
+
+ while (pcFileName > szFileName) {
+ if (*pcFileName == TEXT('\\') || *pcFileName == TEXT(':')) {
+ *(++pcFileName) = TEXT('\0');
+ break;
+ }
+ nFileNameLen--;
+ pcFileName--;
+ }
+
+ /* Check to see if possible path name can fit into internal buffer
+ of NAME_MAX_SIZE size.
+ */
+
+ if ((nFileNameLen+13) < NAME_MAX_SIZE) {
+
+ RSM_StringCopy( IDS_HMHELPFILENAME , szFname, NAME_MAX_SIZE ) ;
+ lstrcat(szFileName, szFname ) ;
+ }
+
+ else { /* Set the Help file name to NULL */
+ /* if not found */
+ lstrcpy(szFileName, TEXT(""));
+ }
+
+ /* On return, szFileName will contain the full path name of help file
+ for WinterPark or will be NULL.
+ */
+
+ return;
+}
+
+
+/****************************************************************************
+
+ Name: HM_WMCommandProcessing
+
+ Description: This function will return TRUE if the ID specified
+ by the WM_COMMAND message is a menu item.
+
+
+ Modified: 7/12/1991
+
+ Returns: TRUE if selection was processed.
+ FALSE if selection was not processed.
+
+****************************************************************************/
+
+BOOL HM_WMCommandProcessing (
+
+ HWND hWnd, /* I - Window handle */
+ WORD wId ) /* I - Menu Id */
+
+{
+ BOOL fProcessedCommand ;
+ DWORD dwHelpContextId ;
+
+ fProcessedCommand = FALSE ;
+
+ /*
+ If mwfHelp is non-zero, then WinterPark is in the context sensitive
+ mode. Either the user has pressed the F1 key while making a menu selection
+ or the user pressed SHIFT-F1.
+
+ Under OEM_MSOFT, mwfHelp is non-zero only when the user has pressed
+ the F1 key while making a menu selection. Also the sysmenu help
+ is all in IDH_SYSMENU, so entries were not put in the menu id table.
+
+ */
+
+ if ( mwfHelp ) {
+
+ dwHelpContextId = (DWORD) HM_FindHelpId( wId ) ;
+
+ fProcessedCommand = TRUE ;
+ mwfHelp = FALSE ;
+
+# if defined ( OEM_MSOFT ) // Use IDH_SYSMENU if appropiate
+ {
+ WORD wSaveId ;
+ wSaveId = wId & 0xfff0 ;
+
+ if ( ( wSaveId >= SC_SIZE ) && ( wSaveId <= SC_HOTKEY ) ) {
+
+ HM_WinHelp ( hWnd, HELP_CONTEXT, IDH_SYSMENU );
+ return( fProcessedCommand ) ;
+ }
+
+ }
+# endif
+
+ // Bring up the Help Context if the ID was found in the table.
+ // Otherwise, bring up the Help Index.
+
+ if ( dwHelpContextId ) {
+ HM_WinHelp ( hWnd, HELP_CONTEXT, dwHelpContextId );
+ }
+ else {
+// HM_WinHelp ( hWnd, HELP_INDEX, 0L );
+ HM_WinHelp ( hWnd, HELP_FINDER, 0L );
+ }
+
+ }
+
+ return ( fProcessedCommand ) ;
+
+}
+
+
+/****************************************************************************
+
+ Name: HM_WinHelp
+
+ Description: This function will call 'WinHelp' if the help file
+ for WinterPark exists.
+
+ Modified: 7/15/1991
+
+ Returns: none
+
+ Notes: If WinterPark's help file does not exist, then the user
+ is notified by way of a message box.
+
+ See also:
+
+****************************************************************************/
+
+VOID HM_WinHelp (
+
+HWND hWnd , /* I - Window handle. */
+WORD wCommand, /* I - Type of Help requested. */
+DWORD dwData ) /* I - Context or key work of the help requested. */
+
+{
+ CHAR szFile [ NAME_MAX_SIZE + 1 ] ;
+ CHAR szString [ NAME_MAX_SIZE + 1 ] ;
+ CHAR szOutput [ NAME_MAX_SIZE + 1 ] ;
+
+ /* Check for existence of help file */
+
+ if ( access ( mwszHelpFilename, 0 ) == -1 ) {
+ RSM_StringCopy( IDS_HMHELPFILENAME, szFile, NAME_MAX_SIZE ) ;
+ strupr ( szFile ) ;
+ RSM_StringCopy( IDS_HMNOHELPFILE, szString, NAME_MAX_SIZE ) ;
+ wsprintf( szOutput, szString, szFile ) ;
+ MessageBox( hWnd, szOutput,NULL, MB_ICONINFORMATION | MB_OK ) ;
+ } else {
+
+ // Set the status bar to Ready.
+
+ WinHelp( hWnd, mwszHelpFilename,wCommand,dwData );
+ }
+}
+
+
+/****************************************************************************
+
+ Name: HM_MenuCommands
+
+ Description: This function will process one of the help
+ menu selections
+
+ IDM_HELPINDEX
+ IDM_HELPSEARCH
+ IDM_HELPUSINGHELP
+
+
+ Modified: 7/15/1991
+
+ Returns: none
+
+****************************************************************************/
+
+VOID HM_MenuCommands (
+
+ HWND hWnd , /* I - Window handle */
+ WORD wId ) /* I - Menu ID selection */
+
+{
+ CHAR szString[ NAME_MAX_SIZE + 1 ] ;
+
+ switch ( wId ) {
+
+ case IDM_HELPSEARCH :
+
+ strcpy( szString, TEXT("") ) ;
+ HM_WinHelp ( hWnd, HELP_PARTIALKEY, (DWORD) szString );
+
+ break;
+
+ case IDM_HELPINDEX :
+
+// HM_WinHelp ( hWnd, HELP_INDEX, 0L);
+ HM_WinHelp ( hWnd, HELP_FINDER, 0L);
+ break;
+
+
+ case IDM_HELPUSINGHELP :
+
+ {
+ CHAR szFormat [ NAME_MAX_SIZE + 1 ] ;
+ CHAR szOutput [ NAME_MAX_SIZE + 1 ] ;
+
+
+ GetSystemDirectory( szString, NAME_MAX_SIZE ) ;
+ strcat( szString,TEXT("\\") ) ;
+ RSM_StringCopy( IDS_HMUSINGHELPFILENAME,szOutput, NAME_MAX_SIZE ) ;
+ strcat( szString, szOutput ) ;
+
+ // Check for existence of supplied 'Using Help' .HLP file.
+
+ if ( access ( szString, 0 ) == -1 ) {
+ RSM_StringCopy( IDS_HMNOHELPFILE, szFormat, NAME_MAX_SIZE ) ;
+ strupr ( szString ) ;
+ wsprintf( szOutput, szFormat, szString ) ;
+ MessageBox( hWnd, szOutput,NULL, MB_ICONINFORMATION | MB_OK ) ;
+ } else {
+ WinHelp(hWnd, szString,HELP_INDEX,0L);
+ }
+ }
+
+ }
+
+}
+
+/****************************************************************************
+
+ Name: HM_ContextLbuttonDown
+
+ Description: This function will process the WM_LBUTTONDOWN
+ message from a window. If the user is in the
+ Help Context Sensitive Mode (Shift-F1), then the
+ message is processed.
+
+ Modified: 7/15/1991
+
+ Returns: TRUE if message processed
+ FALSE if message not processed
+
+ Notes:
+
+ See also:
+
+****************************************************************************/
+
+BOOL HM_ContextLbuttonDown (
+
+HWND hWnd , /* I - Window handle */
+MP1 mp1 , /* I - Virtual key down. */
+MP2 mp2 ) /* I - x-y coordinates of cursor, relative to */
+ /* the upper-left corner of the window */
+
+{
+
+ BOOL wMsgProcessed = FALSE ;
+ POINT pt ;
+ HWND hWindow ;
+ CHAR szClass[ NAME_MAX_SIZE + 1 ] ;
+ DWORD dwHelpContextId ;
+ BYTE fStatusLine ;
+
+ RECT FrameRect ;
+ RECT ClientRect ;
+
+ POINT ptFrameLeft ;
+ POINT ptFrameRight ;
+ POINT ptClient ;
+ POINT ptBelowCaption ;
+
+ WORD wCaptionHeight ;
+ WORD wMenuHeight ;
+ WORD wMenuIconWidth ;
+
+ INT nPosxFrame ;
+ INT nPosyFrame ;
+ RECT rectFrame ;
+
+ UNREFERENCED_PARAMETER ( mp1 );
+
+#if defined ( OEM_MSOFT )
+
+ // OEM_MSOFT does not support context-sensitive
+ // help processing.
+
+ // Return a FALSE always.
+
+ mwfHelp = FALSE ;
+
+#endif
+
+ if (mwfHelp) {
+
+ /* Get rid of all MOUSE messages. This will ignore
+ WM_LBUTTONDOWNs and WM_LBUTTONDBLCLKs.
+ */
+
+
+ {
+ MSG msg ;
+ PeekMessage( &msg, NULL, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE ) ;
+ }
+
+ mwfHelp = FALSE;
+ fStatusLine = FALSE ;
+
+ ReleaseCapture() ;
+
+ pt.x = LOWORD( mp2 ) ;
+ pt.y = HIWORD( mp2 ) ;
+
+ if ( CDS_GetShowStatusLine ( CDS_GetPerm () ) ) {
+ if ( PtInRect( &gpStatusRect, pt ) )
+ {
+ fStatusLine = TRUE ;
+ }
+ }
+
+
+ wCaptionHeight = (WORD)GetSystemMetrics( SM_CYCAPTION ) ;
+ wMenuHeight = (WORD)GetSystemMetrics( SM_CYMENU ) ;
+
+ wMenuIconWidth = (WORD)GetSystemMetrics( SM_CXSIZE ) ;
+
+ ClientToScreen( hWnd, &pt ) ;
+
+ hWindow = WindowFromPoint( pt ) ;
+
+ GetClassName ( hWindow, szClass, NAME_MAX_SIZE ) ;
+
+ /* Check to see the class of window it is.
+
+ WMCLASS_FRAME TEXT("frame") // Class name for the frame window.
+ WMCLASS_CLIENT TEXT("mdiclient") // Class name for the MDI client window.
+ WMCLASS_DOC TEXT("doc") // Class name for MDI document windows.
+ WMCLASS_RIBBON TEXT("ribbon") // Class name for the ribbon windows.
+ WMCLASS_LISTBOX TEXT("listbox") // Class name for the list box windows.
+ WMCLASS_VIEWWIN TEXT("Viewwin") // Class name for the log view window.
+
+
+ */
+
+#if defined ( OS_WIN32 )
+
+ if ( !hWindow ) {
+ strcpy( szClass, WMCLASS_FRAME ) ;
+
+ // With NT any pt in the menu area and above is 65535 +
+ // the real pt value in reference to the frame.
+
+ pt.y = pt.y - 65535 ; // Magic constant.
+ }
+#endif
+
+
+ dwHelpContextId = (DWORD) HELPID_FRAME_WINDOW ;
+
+ if ( !lstrcmpi( WMCLASS_FRAME, szClass ) ) {
+
+ GetClientRect ( ghWndMDIClient, &ClientRect ) ;
+ ptClient.x = ClientRect.left ;
+ ptClient.y = ClientRect.top ;
+ ClientToScreen( ghWndMDIClient, &ptClient ) ;
+
+ GetClientRect ( ghWndFrame, &FrameRect ) ;
+ ptFrameLeft.x = FrameRect.left ;
+ ptFrameLeft.y = FrameRect.top ;
+ ClientToScreen( ghWndFrame, &ptFrameLeft ) ;
+
+ ptFrameRight.x = FrameRect.right ;
+ ptFrameRight.y = FrameRect.bottom ;
+ ClientToScreen( ghWndFrame, &ptFrameRight ) ;
+
+ /* Get the screen position of the frame window. */
+
+ GetWindowRect( ghWndFrame, &rectFrame ) ;
+ nPosxFrame = rectFrame.left;
+ nPosyFrame = rectFrame.top ;
+
+ /* If application not zoomed, then add Frame height to
+ origin of frame.
+ */
+
+ if ( !IsZoomed( ghWndFrame ) ) {
+ nPosyFrame += ( INT ) GetSystemMetrics( SM_CYFRAME ) ;
+ }
+
+ /* Calculate the top point of the menu. */
+
+ ptBelowCaption = ptFrameLeft ;
+ ptBelowCaption.y = nPosyFrame+wCaptionHeight ;
+
+
+ // Check to see if in the Caption area.
+
+ if ( ( pt.x >= ptFrameLeft.x ) &&
+ ( pt.x <= ptFrameRight.x ) &&
+ ( pt.y >= nPosyFrame ) ) {
+
+
+ if ( pt.y < ptBelowCaption.y ) {
+
+ /* Must be in caption area.
+ Must not be in main icon and the minimize/maximize button
+ in the frame window.
+ */
+
+ if ( ( pt.x > (INT) (ptBelowCaption.x + (INT)wMenuIconWidth) ) &&
+ ( pt.x <= (INT) (ptFrameRight.x - 2*wMenuIconWidth ) ) ) {
+ dwHelpContextId = HELPID_TITLE_BAR ;
+ }
+
+ } else {
+
+ /* Check if in menu area.
+
+ When a DOC window is maximized, two bitmaps
+ reside on menu line
+ */
+
+ if ( pt.y < ptClient.y ) {
+
+ if ( IsZoomed( WM_GetActiveDoc() ) ) {
+ if ( ( pt.x <= (ptFrameRight.x - wMenuIconWidth) ) &&
+ ( pt.x > (INT) (ptBelowCaption.x + (INT) wMenuIconWidth ) ) ) {
+ dwHelpContextId = HELPID_SYSTEM_MENU ;
+ }
+ } else {
+ dwHelpContextId = HELPID_SYSTEM_MENU ;
+ }
+
+ } else {
+ if ( fStatusLine ) {
+ dwHelpContextId = (DWORD) HELPID_STATUSLINE ;
+ }
+ }
+ }
+ }
+ }
+
+ if ( !lstrcmpi( WMCLASS_CLIENT, szClass ) ) {
+ dwHelpContextId = (DWORD) HELPID_CLIENT_WINDOW ;
+ }
+
+# if !defined ( OEM_MSOFT )
+ {
+
+ if ( !lstrcmpi( WMCLASS_VIEWWIN, szClass ) ) {
+ dwHelpContextId = (DWORD) HELPID_LOGVIEW ;
+ }
+
+ }
+# endif
+
+ if ( !lstrcmpi( WMCLASS_DOC, szClass ) ) {
+ dwHelpContextId = (DWORD) HELPID_DOC_WINDOW ;
+
+ /* Get the window type */
+
+ HM_GetWindowClassHelpId( hWindow, (LPDWORD) &dwHelpContextId, (LPSTR) WMCLASS_DOC ) ;
+
+ }
+
+ if ( !lstrcmpi( WMCLASS_RIBBON, szClass ) ) {
+ dwHelpContextId = (DWORD) HELPID_RIBBON_WINDOW ;
+ }
+
+ if ( !lstrcmpi( WMCLASS_LISTBOX, szClass ) ) {
+
+ dwHelpContextId = (DWORD) HELPID_DOC_WINDOW ;
+
+ /* Get the window type */
+
+ HM_GetWindowClassHelpId( hWindow, (LPDWORD) &dwHelpContextId, (LPSTR) WMCLASS_LISTBOX ) ;
+
+
+ }
+
+ ClipCursor( NULL ) ;
+
+ HM_WinHelp( hWnd, HELP_CONTEXT, (DWORD) dwHelpContextId );
+
+ wMsgProcessed = TRUE ;
+
+ }
+
+ return ( wMsgProcessed ) ;
+}
+
+/****************************************************************************
+
+ Name: HM_GetDocWindowHelpId
+
+ Description: This function will return the Helpid associated
+ with the type of DOC window.
+
+
+ Modified: 7/15/1991
+
+ Returns: dwNewContextId if reassigned.
+
+ Notes: wClass will be either a DOC or LISTBOX.
+ Listboxes require extra processing to identify
+ the tree or flat part of the DOC window.
+
+ See also:
+
+****************************************************************************/
+
+VOID HM_GetWindowClassHelpId (
+
+HWND hWnd , /* I - Window handle */
+LPDWORD pdwNewContextId, /* O - Return value */
+LPSTR szClass ) /* I - Class of original window */
+
+{
+ PDS_WMINFO pWinInfo ;
+ HWND hParent ;
+ BYTE fWindowIsListbox = FALSE ;
+ WORD wType = 0 ;
+
+ wType = 0 ;
+
+ /* Supports only DOC and LISTBOX classes. */
+
+ if ( ( lstrcmpi( szClass, WMCLASS_DOC ) ) &&
+ ( lstrcmpi( szClass, WMCLASS_LISTBOX ) ) ) {
+
+ return ;
+ }
+
+ // If a listbox is clicked on, then get the parent DOC window
+
+ if ( lstrcmpi( szClass, WMCLASS_LISTBOX ) == 0 ) {
+ hParent = GetParent( hWnd ) ;
+ pWinInfo = (PDS_WMINFO) WM_GetInfoPtr( hParent ) ;
+ fWindowIsListbox = TRUE ;
+
+ } else {
+ pWinInfo = (PDS_WMINFO) WM_GetInfoPtr( hWnd ) ;
+ }
+
+ switch ( pWinInfo->wType ) {
+
+
+ case WMTYPE_DISKS :
+
+ wType = HELPID_DISKS ;
+ break ;
+
+ case WMTYPE_TAPES :
+ wType = HELPID_TAPES ;
+ break ;
+
+ case WMTYPE_MACROS :
+ wType = HELPID_MACROS ;
+ break ;
+
+ case WMTYPE_JOBS :
+ wType = HELPID_JOBS ;
+ break ;
+
+ case WMTYPE_DISKTREE :
+ case WMTYPE_TAPETREE :
+
+ wType = HELPID_DISKTREE ;
+
+ /* If the mouse was clicked in a listbox,
+ then select the left or right listbox in doc window.
+ */
+
+ if ( fWindowIsListbox ) {
+ if ( pWinInfo->hWndTreeList == hWnd ) {
+ wType = HELPID_DISKTREELEFT ;
+ } else {
+ wType = HELPID_DISKTREERIGHT ;
+ }
+ }
+ break ;
+
+
+ case WMTYPE_SERVERS :
+
+ wType = HELPID_SERVERS ;
+
+ /* If the mouse was clicked in a listbox,
+ then select the left or right listbox in doc window.
+ */
+
+ if ( fWindowIsListbox ) {
+ if ( pWinInfo->hWndTreeList == hWnd ) {
+ wType = HELPID_SERVERLEFT ;
+ } else {
+ wType = HELPID_SERVERRIGHT ;
+ }
+ }
+
+ break ;
+
+# if !defined ( OEM_MSOFT )
+ {
+ case WMTYPE_LOGVIEW :
+
+ wType = HELPID_LOGVIEW ;
+ break ;
+ }
+# endif
+
+ case WMTYPE_LOGFILES :
+
+ wType = HELPID_LOGFILES ;
+ break ;
+
+ case WMTYPE_DEBUG :
+ wType = HELPID_DEBUG ;
+ break ;
+
+ case WMTYPE_SEARCH :
+ wType = HELPID_SEARCH ;
+ break ;
+
+ }
+
+ if ( wType ) {
+ *pdwNewContextId = (DWORD) wType ;
+ }
+
+}
+
+/****************************************************************************
+
+ Name: HM_KeyDown
+
+ Description: This function will process the WM_KEYDOWN
+ message from a window. If Shift-F1, help mode is turned on
+ and the cursor is set to the help cursor.
+
+ Modified: 7/15/1991
+
+ Returns: TRUE if message processed
+ FALSE if message not processed
+
+****************************************************************************/
+
+BOOL HM_KeyDown (
+
+HWND hWnd , /* I - Window handle */
+MP1 mp1 ) /* I - Additional information of message */
+{
+ BOOL wMsgProcessed = FALSE ;
+ RECT rectFrame ;
+
+# if defined ( OEM_MSOFT )
+
+ // OEM_SOFT does not have context sensitive help
+
+ if (mp1 == VK_F1) {
+ wMsgProcessed = TRUE ;
+// HM_WinHelp(hWnd,HELP_INDEX,0L);
+ HM_WinHelp(hWnd,HELP_FINDER,0L);
+ }
+
+# else
+
+ if (mp1 == VK_F1) {
+
+ /* If Shift-F1, turn help mode on and set help cursor. */
+
+ wMsgProcessed = TRUE ;
+
+ if (GetKeyState(VK_SHIFT)<0) {
+ mwfHelp = TRUE;
+ RSM_CursorSet ( mwhHelpCursor);
+ SetCapture( ghWndFrame ) ;
+ GetWindowRect( ghWndFrame, &rectFrame ) ;
+ ClipCursor( &rectFrame ) ;
+ } else {
+
+ /* F1 is without shift.
+ Call up the help main index topic
+ */
+
+ HM_WinHelp(hWnd,HELP_INDEX,0L);
+ }
+ } else if (mp1 == VK_ESCAPE && mwfHelp) {
+
+ /* Escape during help mode: turn help mode off */
+
+ mwfHelp = FALSE;
+ ReleaseCapture() ;
+ ClipCursor( NULL ) ;
+ wMsgProcessed = TRUE ;
+
+ RSM_CursorSet ( WM_GetClassCursor ( hWnd ) );
+ }
+
+# endif
+
+ return ( wMsgProcessed ) ;
+}
+
+/****************************************************************************
+
+ Name: HM_SetCursor
+
+ Description: In help mode it is necessary to reset the cursor in response
+ to every WM_SETCURSOR message.Otherwise, by default, Windows
+ will reset the cursor to that of the window class.
+
+ Modified: 7/15/1991
+
+ Returns: TRUE if message processed
+ FALSE if message not processed
+
+ Notes: Under OEM_MSOFT never set the cursor.
+
+
+****************************************************************************/
+
+BOOL HM_SetCursor (
+
+ HWND hWnd ) /* I - Handle to window */
+
+{
+ BOOL wMsgProcessed = FALSE ;
+
+ DBG_UNREFERENCED_PARAMETER ( hWnd );
+
+# if defined ( OEM_MSOFT )
+# else
+
+ if (mwfHelp) {
+ wMsgProcessed = TRUE ;
+ RSM_CursorSet ( mwhHelpCursor);
+ }
+# endif
+
+ return ( wMsgProcessed ) ;
+
+}
+/****************************************************************************
+
+ Name: HM_InitMenu
+
+ Description: This function will set the cursor to the help cursor
+ if the help mode is set.
+
+ Modified: 7/15/1991
+
+ Returns: none
+
+ Notes: This function is called on a WM_INITMENU, a message sent
+ before windows displays a menu.
+
+ Under OEM_MSOFT never set the cursor.
+
+****************************************************************************/
+
+VOID HM_InitMenu ( VOID )
+
+{
+
+# if defined ( OEM_MSOFT )
+# else
+
+ if (mwfHelp) {
+ RSM_CursorSet ( mwhHelpCursor);
+ }
+# endif
+
+}
+
+/****************************************************************************
+
+ Name: HM_EnterIdle
+
+ Description: The function will bring up the help window when a
+ a menu item is selected and the F1 key is pressed.
+
+ Modified: 7/15/1991
+
+ Returns: none.
+
+ Notes: This function is called by the frame window's procedure.
+ when a HM_ENTERIDLE message is encountered.
+
+****************************************************************************/
+
+BOOL HM_EnterIdle (
+
+HWND hWnd , /* I - Handle to window */
+MP1 mp1 , /* I - Additional information of message */
+WORD wLastMenuID , /* I - Menu ID */
+WORD wLastMenuState ) /* I - Menu State (grayed or not) */
+
+{
+ BOOL wMsgProcessed = FALSE ;
+
+ if ((mp1 == MSGF_MENU) && (GetKeyState(VK_F1) & 0x8000)) {
+
+ wMsgProcessed = TRUE;
+ mwfHelp = TRUE;
+
+ /* IF the status of the menu ID is grayed,
+ ** BEGIN
+ ** .
+ ** . Call HM_WMCommandProcessing to simulate processing
+ ** . the menu command, since the system will not generate
+ ** . a message for a grayed selection.
+ ** .
+ ** . END
+ ** END
+ */
+
+ if ( wLastMenuState & MF_GRAYED ) {
+ HM_WMCommandProcessing( hWnd, wLastMenuID );
+ } else {
+ PostMessage(hWnd, WM_KEYDOWN, VK_RETURN, 0L);
+ }
+
+ }
+
+ return ( wMsgProcessed );
+}
+
+/****************************************************************************
+
+ Name: HM_CloseHelpWindow
+
+ Description: The function will close the Help application window.
+
+ Modified: 7/15/1991
+
+ Returns: none.
+
+ Notes: This function is called only once by the application when
+ exiting.
+
+****************************************************************************/
+
+VOID HM_CloseHelpWindow (
+
+HWND hWnd ) /* I - Handle to window */
+
+{
+ OFSTRUCT OfStruct ;
+
+ if ( access ( mwszHelpFilename, 0 ) != -1 ) {
+ HM_WinHelp(hWnd,HELP_QUIT,0L);
+ }
+}
+
diff --git a/private/utils/ntbackup/src/hexefile.bmp b/private/utils/ntbackup/src/hexefile.bmp
new file mode 100644
index 000000000..56b1726ca
--- /dev/null
+++ b/private/utils/ntbackup/src/hexefile.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/hfile.bmp b/private/utils/ntbackup/src/hfile.bmp
new file mode 100644
index 000000000..3a30de5d9
--- /dev/null
+++ b/private/utils/ntbackup/src/hfile.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/hslider.cur b/private/utils/ntbackup/src/hslider.cur
new file mode 100644
index 000000000..58e322884
--- /dev/null
+++ b/private/utils/ntbackup/src/hslider.cur
Binary files differ
diff --git a/private/utils/ntbackup/src/hwcheck.c b/private/utils/ntbackup/src/hwcheck.c
new file mode 100644
index 000000000..1add90812
--- /dev/null
+++ b/private/utils/ntbackup/src/hwcheck.c
@@ -0,0 +1,258 @@
+
+/*****************************************************************************
+Copyright(c) Maynard, an Archive Company. 1991
+
+ Name: hwcheck.c
+
+ Description: Functions used for checking hardware status prior to
+ starting a tape operation.
+
+ $Log: G:\UI\LOGFILES\HWCHECK.C_V $
+
+ Rev 1.6.1.0 27 Jan 1994 17:01:38 Glenn
+Expanded list box horiz extent by 5 percent.
+
+ Rev 1.6 01 Nov 1992 15:59:08 DAVEV
+Unicode changes
+
+ Rev 1.5 07 Oct 1992 14:08:54 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.4 04 Oct 1992 19:37:52 DAVEV
+Unicode Awk pass
+
+ Rev 1.3 14 May 1992 18:00:32 MIKEP
+nt pass 2
+
+ Rev 1.2 19 Mar 1992 16:48:12 GLENN
+Added enhanced status support.
+
+ Rev 1.1 04 Feb 1992 14:42:46 DAVEV
+fixes to insure proper types for NT
+
+ Rev 1.0 31 Jan 1992 17:58:42 GLENN
+Initial revision.
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+/*****************************************************************************
+
+ Name: HWC_TapeHWProblem()
+
+ Description: Checks the current status of each DIL_HWD structure for
+ any previous unsuccessful initialization attempts. If
+ any error is found, a generic message is displayed
+ informing the user that we will automatically retry
+ the tape related hardware. If an error is still found,
+ HWC_ReportDiagError is called to handle reporting the
+ error.
+
+ Returns: SUCCESS for no problem found
+ FAILURE for problems still found
+
+*****************************************************************************/
+
+BOOL HWC_TapeHWProblem (
+ BSD_HAND pBSDList )
+{
+ BOOL fResult = SUCCESS;
+ BE_INIT_STR pBE;
+ INT16 nErrorTFL;
+ INT16 nError;
+ BSD_PTR pBSD;
+ CDS_PTR pCDS = CDS_GetPerm ();
+
+ /* Check current init status and re-test tape controller hardware if necessary */
+
+ if ( ( thw_list == NULL ) ||
+ ( HWC_ProcessDILHWD ( HW_RET_ERROR, gb_dhw_ptr ) == HW_ERROR_DETECTED ) ||
+ ( CDS_GetAdvToConfig ( pCDS ) ) ||
+ ( ! gfHWInitialized ) ) {
+
+ // Guarantee that Poll Drive is turned off. Poll Drive
+ // cannot be turned on while reinitializing.
+
+ PD_StopPolling ();
+
+ // Re-init the Tape Format layer and check for potential return errors.
+
+ {
+ CHAR szTemp[MAX_STATUS_LINE_SIZE];
+
+ // Save the old status line, put up the init hardware
+ // status, init the hardware, then restore the old
+ // status line.
+
+ strcpy ( szTemp, STM_GetStatusLineText () );
+
+ nErrorTFL = UI_UnitsInit ( &pBE, REINIT_TFL );
+
+ STM_SetStatusLineText ( szTemp );
+ STM_DrawIdle ();
+ }
+
+ HWC_ReportDiagError ( &pBE, nErrorTFL, &nError );
+
+ if ( ( HWC_ProcessDILHWD ( HW_RET_ERROR, gb_dhw_ptr ) == HW_ERROR_DETECTED ) || nErrorTFL ) {
+
+ gfHWInitialized = FALSE;
+
+ fResult = FAILURE;
+
+ }
+ else {
+
+ gfHWInitialized = TRUE;
+
+ // Restart poll drive.
+
+ PD_StartPolling ();
+
+ // Make sure that any existing BSDs have a valid THW.
+
+ pBSD = BSD_GetFirst ( pBSDList );
+
+ while ( pBSD != NULL ) {
+ BSD_SetTHW ( pBSD, thw_list );
+ pBSD = BSD_GetNext ( pBSD );
+ }
+
+ fResult = SUCCESS;
+
+ CDS_SetAdvToConfig ( pCDS, FALSE );
+ CDS_UpdateCopy ( );
+
+ }
+
+ }
+
+ return fResult;
+
+} /* end HWC_TapeHWProblem() */
+
+/*****************************************************************************
+
+ Name: HWC_ReportDiagError()
+
+ Description: Produces "Help" based message on screen for Tmenu for
+ diagnostic errors reported by BE_Init. A call is made
+ to the HW config unit to process any errors he is
+ sensitive to. Any help related messages provided herein
+ are from error conditions directly determined by
+ UI_UnitsInit (such as no controllers located).
+
+
+ Returns: FAILURE for those conditions that should result in
+ immediate program termination
+
+*****************************************************************************/
+
+VOID HWC_ReportDiagError (
+
+BE_INIT_STR_PTR pBE,
+INT16 nErrorBE,
+INT16_PTR pnError )
+
+{
+
+ CDS_PTR pCDS = CDS_GetPerm( );
+
+ /* map returned error value to help message and display */
+
+ switch ( nErrorBE ) {
+
+ case TFLE_NO_MEMORY:
+ case BE_FILE_SYS_FAIL:
+ case BE_BSDU_FAIL:
+ *pnError = FAILURE;
+ /* falling through to report out of memory */
+ case OUT_OF_MEMORY :
+ eresprintf( RES_OUT_OF_MEMORY );
+ break;
+
+ case BENGINE_IN_USE:
+ *pnError = FAILURE;
+ eresprintf( RES_BENGINE_IN_USE );
+ break;
+
+ /* device driver load failure */
+ case TFLE_DRIVER_LOAD_FAILURE:
+ case TFLE_DRIVER_FAILURE:
+
+ HWC_ProcessError ( HW_DISP_ERROR, IDS_HWC_TESTED_BAD, DRIVER_LOAD_FAILURE, 0, pCDS );
+ break;
+
+ /* no controller found */
+ case UI_NO_CONTROLLERS:
+
+ HWC_ProcessError ( HW_DISP_ERROR, IDS_HWC_TESTED_BAD, UI_NO_CONTROLLERS, 0, pCDS );
+ break;
+
+ /* A hardware configuration error was found, handle it... */
+ case HW_ERROR_NO_RES_FILE:
+ eresprintf( RES_MISSING_HW_RESOURCE, CDS_GetActiveDriver( pCDS ), TEXT(".RES") );
+ break;
+
+ case HW_INVALID_PARM:
+ /* this should not happen, unless the HW resource and device
+ driver files get out of sync and new acceptable values
+ within the driver are defined that the resource file does
+ not know about */
+ eresprintf( RES_INCONSISTENT_HW_PARMS );
+ break;
+
+ case HW_UNKNOWN_ERROR:
+ eresprintf( RES_UNKNOWN_HW_ERR );
+ break;
+
+ case BE_INIT_SUCCESS:
+ default:
+
+ if ( gb_dhw_ptr != (DIL_HWD_PTR)NULL ) {
+
+ /* Backup engine was inited, process DIL info, and report any errors */
+ switch( HWC_ProcessDILHWD( HW_DISP_ERROR, gb_dhw_ptr ) ) {
+
+ case HW_NO_ERROR:
+ case HW_ERROR_DISPLAYED:
+ case HW_ERROR_DETECTED:
+ /* Any errors already processed by HW unit, and break... */
+ break;
+
+ case HW_ERROR_NO_RES_FILE:
+ eresprintf( RES_MISSING_HW_RESOURCE, CDS_GetActiveDriver( pCDS ), TEXT(".RES") );
+ break;
+
+ case HW_INVALID_PARM:
+ /* this should not happen, unless the HW resource and device
+ driver files get out of sync and new acceptable values
+ within the driver are defined that the resource file does
+ not know about */
+ eresprintf( RES_INCONSISTENT_HW_PARMS );
+ break;
+
+ case HW_UNKNOWN_ERROR:
+ eresprintf( RES_UNKNOWN_HW_ERR );
+ break;
+
+ case OUT_OF_MEMORY:
+ eresprintf( RES_OUT_OF_MEMORY );
+ break;
+
+ }
+ }
+
+ break;
+ }
+
+ return;
+
+ pBE;
+
+} /* end HWC_ReportDiagError() */
diff --git a/private/utils/ntbackup/src/hwconfnt.c b/private/utils/ntbackup/src/hwconfnt.c
new file mode 100644
index 000000000..2c5d48a27
--- /dev/null
+++ b/private/utils/ntbackup/src/hwconfnt.c
@@ -0,0 +1,1281 @@
+/******************************************************************************
+Copyright (c) Archive Software Division 1992
+
+
+ Name: nthwconf.c
+
+ Description: This file contains the functions for the Hardware
+ Settings Dialog and for controller card and tape drive
+ selections.
+
+
+
+ $Log: G:\ui\logfiles\hwconfnt.c_v $
+
+ Rev 1.11.2.7 29 Jun 1994 19:42:28 STEVEN
+save config when changed
+
+ Rev 1.11.2.6 25 Jan 1994 08:43:10 MIKEP
+fix warnings in orcas
+
+ Rev 1.11.2.5 13 Dec 1993 11:40:56 TIMN
+Saves device name in cfg settings
+
+ Rev 1.11.2.4 07 Dec 1993 10:41:04 TIMN
+Additional Unicode changes
+
+ Rev 1.11.2.3 03 Dec 1993 14:27:32 TIMN
+Unicode fixes Fixes EPR0203
+
+ Rev 1.11.2.2 30 Nov 1993 19:18:30 TIMN
+Added cmdline /tape:x option to NTJ
+
+ Rev 1.11.2.1 05 Jun 1993 14:00:54 BARRY
+Initialize variables before using them
+
+ Rev 1.11.2.0 04 Jun 1993 19:05:02 STEVEN
+added new error messages
+ *
+ * Rev 1.0 04 Jun 1993 19:04:38 STEVEN
+ * added new error messages
+
+ Rev 1.11 16 Apr 1993 14:42:14 DARRYLP
+Changed ID for HWCONFNT Help to resolve differences.
+
+ Rev 1.10 20 Jan 1993 21:38:30 MIKEP
+floppy support
+
+ Rev 1.9 04 Dec 1992 08:48:36 MIKEP
+fix tape drive switching
+
+ Rev 1.8 17 Nov 1992 21:25:12 DAVEV
+unicode fixes
+
+ Rev 1.7 11 Nov 1992 16:43:58 DAVEV
+UNICODE: remove compile warnings, use sizeof instead of array size for CHAR arrays
+
+ Rev 1.6 30 Oct 1992 17:58:56 MIKEP
+quick kludge for steve for weekend
+
+ Rev 1.5 27 Oct 1992 16:32:12 MIKEP
+device number support
+
+ Rev 1.0 27 Oct 1992 16:32:04 MIKEP
+device number support
+
+ Rev 1.4 08 Oct 1992 16:01:00 DAVEV
+Unicode Awk Pass
+
+ Rev 1.3 08 Oct 1992 15:51:56 MIKEP
+latest
+
+
+******************************************************************************/
+
+
+
+#include "all.h"
+
+
+
+// PRIVATE DEFINITIONS
+
+#define HWC_SIZE_INIT 0
+#define HWC_SIZE_NO_CONFIG 1
+#define HWC_SIZE_NO_TARGET_IDS 2
+#define HWC_SIZE_MAX 3
+
+#define HWC_NOTDEFINED 0xFFFF
+#define HWC_SHOWLASTMESSAGE 0xFFFF
+#define DISABLED 0
+#define ENABLED 1
+#define AUTO_ENABLED 2
+#define HW_NO_CARD_ERROR 10
+
+#define REGENUMKEYSIZE 100 // subkey name size
+#define TEMPBUFFSIZE 512 //
+
+
+// generic f(x) calls for determining if char is a digit
+#if defined( UNICODE )
+# define _HWC_IsDigit(ch) ( !IsCharAlpha( ch ) && IsCharAlphaNumeric( ch ) )
+#else
+# define _HWC_IsDigit(ch) ( isdigit( ch ) )
+#endif
+
+
+
+
+// PRIVATE STRUCTURES
+
+typedef struct HWDRIVE {
+
+ Q_ELEM q_elem;
+ CHAR_PTR drive_name;
+
+ INT floppy;
+ INT card;
+ INT bus;
+ INT target_id;
+ INT lun;
+ INT device;
+
+} HWDRIVE, *HWDRIVE_PTR;
+
+
+static HWDRIVE_PTR mwSelectedDrive = NULL;
+static Q_HEADER DriveQueue ;
+static BOOLEAN DriveFound = FALSE ;
+static BOOLEAN DriverLoaded = FALSE ;
+
+
+// PRIVATE MACRO DEFINITIONS
+
+#define PostDlgItemMessage( u, v, x, y, z ) PostMessage( GetDlgItem ( u, v ), x, y, z );
+
+
+// PRIVATE FUNCTION PROTOTYPES
+
+
+INT HWC_FindFloppyTape( CHAR * );
+INT HWC_AddFloppyTapeDrive( CHAR * );
+INT HWC_FindScsiCards( CHAR * );
+INT HWC_FindBuses( INT, CHAR * );
+INT HWC_FindTargets( INT, INT, CHAR * );
+INT HWC_FindLuns( INT, INT, INT, CHAR * );
+INT HWC_QueryValues( INT, INT, INT, INT, CHAR * );
+INT HWC_TestHardware( VOID );
+INT HWC_GetTapeDevice( VOID );
+BOOL HWC_InitDialog( HWND );
+VOID HWC_DeinitDialog( HWND, INT );
+DLGRESULT HWC_ProcessCommand( HWND, MP1, MP2 );
+BOOL HWC_BuildDriveList( VOID );
+BOOL HWC_AddToDriveList( INT, INT, INT, INT, INT, CHAR_PTR );
+HWDRIVE_PTR HWC_IsInDriveList( INT, INT, INT, INT, CHAR_PTR );
+HWDRIVE_PTR HWC_GetFirstDrive( );
+HWDRIVE_PTR HWC_GetNextDrive( HWDRIVE_PTR );
+BOOL HWC_BuildDriveComboBox( HWND );
+BOOL HWC_NewDriveSelected( HWND );
+VOID HWC_FreeDriveList( VOID );
+
+int
+HWC_SelectTapeDevice( int nTapeDevice ) ;
+VOID
+HWC_FlushDeviceList( Q_HEADER *mwpdsDeviceQueue ) ;
+HWDRIVE_PTR
+HWC_GetDeviceFromDeviceList( int nTapeDevice ) ;
+
+// Determine the tape drive to use at startup.
+
+INT HWC_GetTapeDevice( )
+{
+
+ INT card = -1;
+ INT bus = -1;
+ INT target = -1;
+ INT lun = -1;
+ INT device = 0;
+ CHAR_PTR driver_name;
+ CHAR_PTR s;
+
+ HWC_FlushDeviceList( &DriveQueue );
+
+ // Build the controller card list. If no configured is selected,
+ // do not show the whole dialog. Make sure that the user picks a
+ // controller first.
+
+ HWC_BuildDriveList();
+
+ driver_name = (CHAR_PTR)CDS_GetTapeDriveName( CDS_GetPerm() );
+ s = driver_name;
+
+ // skip to digits
+ while ( *s && ( *s < TEXT( '0' ) || *s > TEXT( '9' ) ) ) s++;
+ if ( *s ) card = atoi( s );
+ // skip over digits
+ while ( *s && *s >= TEXT( '0' ) && *s <= TEXT( '9' ) ) s++;
+
+ // skip to digits
+ while ( *s && ( *s < TEXT( '0' ) || *s > TEXT( '9' ) ) ) s++;
+ if ( *s ) bus = atoi( s );
+ // skip over digits
+ while ( *s && *s >= TEXT( '0' ) && *s <= TEXT( '9' ) ) s++;
+
+ // skip to digits
+ while ( *s && ( *s < TEXT( '0' ) || *s > TEXT( '9' ) ) ) s++;
+ if ( *s ) target = atoi( s );
+ // skip over digits
+ while ( *s && *s >= TEXT( '0' ) && *s <= TEXT( '9' ) ) s++;
+
+ // skip to digits
+ while ( *s && ( *s < TEXT( '0' ) || *s > TEXT( '9' ) ) ) s++;
+ if ( *s ) lun = atoi( s );
+
+ mwSelectedDrive = HWC_IsInDriveList( card, bus, target, lun,
+ driver_name );
+
+ if ( mwSelectedDrive ) {
+ device = mwSelectedDrive->device;
+
+ // Let's modify the configuration with the selected tape device
+ CDS_SetTapeDriveName( CDS_GetPerm(), mwSelectedDrive->drive_name ) ;
+ CDS_SetChangedConfig( CDS_GetPerm(), TRUE ) ;
+ }
+
+ HWC_FreeDriveList( );
+
+ return( device );
+}
+
+
+/**
+
+**/
+
+INT
+HWC_SelectTapeDevice( INT nTapeDevice )
+{
+INT nRetValu = (INT)INVALID_HANDLE_VALUE ;
+
+ InitQueue( &DriveQueue );
+ HWC_BuildDriveList();
+
+ mwSelectedDrive = HWC_GetDeviceFromDeviceList( nTapeDevice ) ;
+
+ if ( mwSelectedDrive )
+ {
+ CDS_SetTapeDriveName( CDS_GetPerm(), mwSelectedDrive->drive_name );
+ nRetValu = nTapeDevice ;
+ }
+
+ HWC_FreeDriveList() ;
+
+ return( nRetValu ) ;
+}
+
+
+/****************************************************************************
+
+ Name: HWC_FlushDeviceList
+
+ Description: Frees all allocated memory in the Device Queue before
+ calling InitQueue to rebuild the device list.
+
+ Note:
+
+ Returns: Nothing
+
+****************************************************************************/
+
+VOID
+HWC_FlushDeviceList( Q_HEADER *mwpdsDeviceQueue )
+{
+HWDRIVE_PTR pdsDevice ;
+HWDRIVE_PTR pdsNextDevice ;
+
+ pdsDevice = HWC_GetFirstDrive() ;
+
+ while ( pdsDevice != NULL )
+ {
+ pdsNextDevice = HWC_GetNextDrive( pdsDevice ) ;
+ free( (void *)pdsDevice->q_elem.q_ptr ) ;
+ pdsDevice = pdsNextDevice ;
+ }
+
+ InitQueue( mwpdsDeviceQueue ) ;
+
+} /* end HWC_FlushDeviceList */
+
+
+
+/****************************************************************************
+
+ Name: HWC_GetDeviceFromDeviceList
+
+ Description: Gets the specified device from the device list queue
+
+ Note:
+
+ Returns: Address of the device
+
+****************************************************************************/
+
+HWDRIVE_PTR
+HWC_GetDeviceFromDeviceList( int nTapeDevice )
+{
+HWDRIVE_PTR pdsDevice = HWC_GetFirstDrive() ;
+
+ while ( pdsDevice && pdsDevice->device != nTapeDevice )
+ {
+ pdsDevice = HWC_GetNextDrive( pdsDevice ) ;
+ }
+
+ return( pdsDevice ) ;
+}
+
+
+
+/******************************************************************************
+
+ Name: DM_OptionHardware ()
+
+ Description: Dialog proc for hardware settings.
+
+ Returns:
+
+******************************************************************************/
+
+DLGRESULT APIENTRY DM_OptionHardware (
+HWND hDlg, // I - handle to a dialog
+MSGID Msg, // I - message
+MPARAM1 Param1, // I - word parameter
+MPARAM2 Param2 ) // I - long parameter
+{
+ switch ( Msg ) {
+
+ case WM_INITDIALOG :
+
+ return HWC_InitDialog ( hDlg );
+
+ case WM_COMMAND :
+
+ return (DLGRESULT) HWC_ProcessCommand ( hDlg, Param1, Param2 );
+
+ case WM_CLOSE :
+
+ HWC_DeinitDialog ( hDlg, (INT)NULL );
+ return TRUE ;
+
+ default :
+ return FALSE ;
+ }
+
+ return TRUE ;
+}
+
+
+BOOL HWC_InitDialog (
+HWND hDlg ) // I - handle to the dialog
+{
+ CHAR_PTR s;
+ CHAR_PTR driver_name;
+ INT card = -1;
+ INT bus = -1;
+ INT target = -1;
+ INT lun = -1;
+ RECT rcDialog;
+
+
+ // Center the dialog and init the dialog size since it is a dynamically
+ // sized dialog.
+
+ HWC_FlushDeviceList( &DriveQueue );
+
+ DM_CenterDialog( hDlg );
+
+ GetWindowRect( hDlg, &rcDialog );
+
+
+ // Build the controller card list. If no configured is selected,
+ // do not show the whole dialog. Make sure that the user picks a
+ // controller first.
+
+ HWC_BuildDriveList();
+
+ driver_name = (CHAR_PTR)CDS_GetTapeDriveName( CDS_GetPerm() );
+ s = driver_name;
+
+ while ( *s && ( *s < TEXT( '0' ) || *s > TEXT( '9' ) ) ) s++;
+ if ( *s ) card = atoi( s );
+ while ( *s && *s >= TEXT( '0' ) && *s <= TEXT( '9' ) ) s++;
+
+ while ( *s && ( *s < TEXT( '0' ) || *s > TEXT( '9' ) ) ) s++;
+ if ( *s ) bus = atoi( s );
+ while ( *s && *s >= TEXT( '0' ) && *s <= TEXT( '9' ) ) s++;
+
+ while ( *s && ( *s < TEXT( '0' ) || *s > TEXT( '9' ) ) ) s++;
+ if ( *s ) target = atoi( s );
+ while ( *s && *s >= TEXT( '0' ) && *s <= TEXT( '9' ) ) s++;
+
+ while ( *s && ( *s < TEXT( '0' ) || *s > TEXT( '9' ) ) ) s++;
+ if ( *s ) lun = atoi( s );
+
+ mwSelectedDrive = HWC_IsInDriveList( card, bus, target, lun,
+ driver_name );
+
+ HWC_BuildDriveComboBox ( hDlg );
+
+ return( TRUE );
+}
+
+VOID HWC_DeinitDialog (
+HWND hDlg,
+INT nReturnValue )
+{
+ HWC_FreeDriveList( );
+
+ EndDialog ( hDlg, nReturnValue ) ;
+
+} /* HWC_DeinitDialog() */
+
+
+
+BOOL HWC_ProcessCommand (
+HWND hDlg, // I - handle to the dialog
+MPARAM1 Param1, // I - command parameter
+MPARAM2 Param2 ) // I - long parameter
+{
+ WORD wCmd = GET_WM_COMMAND_CMD ( Param1, Param2 );
+ WORD wID = GET_WM_COMMAND_ID ( Param1, Param2 );
+
+ UNREFERENCED_PARAMETER ( Param2 );
+
+ switch ( wID ) {
+
+ case IDOK: {
+
+ // actually change tape drives here !
+
+ if ( mwSelectedDrive != NULL ) {
+
+ CDS_SetTapeDriveName( CDS_GetPerm(), mwSelectedDrive->drive_name );
+ CDS_SetChangedConfig( CDS_GetPerm(), TRUE );
+ TapeDevice = mwSelectedDrive->device;
+ HWC_TestHardware();
+ }
+
+ STM_SetIdleText( IDS_READY );
+ HWC_DeinitDialog( hDlg, (INT)IDOK );
+ CDS_SaveCDS ();
+ return( TRUE );
+ }
+
+ case IDCANCEL:
+ STM_SetIdleText ( IDS_READY );
+ HWC_DeinitDialog ( hDlg, (INT)IDCANCEL );
+ return( TRUE );
+
+ case IDD_H_CONTROLLER:
+ // Get the selected drive. If it was different from the
+ // previous one, change the lists associated with them.
+
+ if ( wCmd == (WORD)LBN_SELCHANGE ) {
+
+ HWC_NewDriveSelected ( hDlg );
+ }
+ break;
+
+ case IDHELP:
+ HM_DialogHelp( HELPID_OPERATIONSHARDWARE ) ;
+ break;
+
+ default:
+ // Clear the tested flag if the target IDs change.
+ return(FALSE);
+ }
+
+ return( TRUE );
+}
+
+
+VOID HWC_EnableStatusGroup (
+HWND hDlg, // I - handle to a dialog
+BOOL fEnable ) // I - flag to enable or disable the group
+{
+ EnableWindow( GetDlgItem( hDlg, IDOK ), fEnable );
+}
+
+
+
+BOOL HWC_BuildDriveList( )
+{
+
+#ifdef FLOPPY
+
+ if ( GetDriveType( TEXT("A:") ) != 1 ) {
+ HWC_AddToDriveList( -1, -1, -1, -1, 255, TEXT("Floppy Drive A:") ) ;
+ }
+
+ if ( GetDriveType( TEXT("B:") ) != 1 ) {
+ HWC_AddToDriveList( -1, -1, -1, -1, 256, TEXT("Floppy Drive B:") ) ;
+ }
+
+#endif
+
+ HWC_FindScsiCards( TEXT("hardware\\devicemap\\scsi") ) ;
+ HWC_FindFloppyTape( TEXT("hardware\\devicemap\\tape") ) ;
+
+ return( TRUE );
+}
+
+
+
+INT HWC_FindFloppyTape( CHAR *key_name )
+{
+LONG ret;
+REGSAM samDesired;
+HKEY hkResult;
+ULONG key_index;
+FILETIME ftLastWrite;
+CHAR name[ REGENUMKEYSIZE ] ;
+ULONG name_size ;
+CHAR temp_buff[ TEMPBUFFSIZE ] ;
+
+ samDesired = KEY_READ;
+
+ ret = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+ key_name, 0UL, samDesired, &hkResult );
+
+ if ( ret ) {
+ return( FAILURE );
+ }
+
+ key_index = 0UL ;
+
+ do {
+ name_size = REGENUMKEYSIZE ;
+
+ ret = RegEnumKeyEx( hkResult, key_index, name, &name_size,
+ NULL, NULL, NULL,
+ &ftLastWrite );
+
+ if ( ! ret ) {
+ strcpy( temp_buff, key_name );
+ strcat( temp_buff, TEXT("\\") );
+ strcat( temp_buff, name );
+
+ DriveFound = TRUE ;
+ DriverLoaded = TRUE ;
+ HWC_AddFloppyTapeDrive( temp_buff );
+ }
+
+ key_index++ ;
+
+ } while ( ! ret );
+
+ RegCloseKey( hkResult );
+
+ return( SUCCESS );
+
+}
+
+
+INT HWC_AddFloppyTapeDrive( CHAR *key_name )
+{
+LONG ret;
+REGSAM samDesired;
+HKEY hkResult;
+ULONG key_index;
+CHAR data[ REGENUMKEYSIZE ] ;
+DWORD data_size ;
+CHAR value_id[ REGENUMKEYSIZE ] ;
+DWORD value_size ;
+DWORD device = 0 ;
+INT tape_drive = FALSE;
+INT driver_loaded = FALSE;
+CHAR identifier[ TEMPBUFFSIZE ] ;
+CHAR unique[ TEMPBUFFSIZE ] ;
+CHAR deviceName[ REGENUMKEYSIZE ] ;
+
+ samDesired = KEY_QUERY_VALUE;
+
+ ret = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+ key_name, 0UL, samDesired, &hkResult );
+
+ if ( ret ) {
+ return( FAILURE );
+ }
+
+ identifier[ 0 ] = unique[ 0 ] = TEXT( '\0' ) ;
+ key_index = 0UL ;
+
+ do {
+
+ value_size = REGENUMKEYSIZE ;
+ data_size = sizeof(data) ;
+
+ ret = RegEnumValue( hkResult, key_index, value_id, &value_size,
+ (LPDWORD)NULL, (LPDWORD)NULL, (LPBYTE)data, &data_size );
+
+ if ( ! ret ) {
+
+ // null terminate data string from RegEnumValue() call
+ data_size /= sizeof( CHAR ) ;
+ data[ data_size ] = TEXT('\0') ;
+
+ if ( ! stricmp( value_id, TEXT("DeviceName") ) ) {
+ CHAR *s ;
+
+ strcpy( deviceName, data ) ; // store the tape string
+ s = data ;
+ s += strlen( TEXT("Tape") ) ;
+ device = atoi( s );
+ driver_loaded = TRUE;
+ }
+
+ if ( ! stricmp( value_id, TEXT("UniqueId") ) ) {
+ strcpy( unique, data ) ;
+ }
+
+ if ( ! stricmp( value_id, TEXT("Identifier") ) ) {
+ strcpy( identifier, data ) ;
+ }
+
+ }
+
+ key_index++;
+
+ } while ( ! ret );
+
+ if ( driver_loaded ) {
+
+ if ( *unique == TEXT('\0') ) {
+ strcpy( unique, deviceName ) ;
+ }
+
+ strcat( unique, TEXT( " " ) );
+ strcat( unique, identifier );
+ HWC_AddToDriveList( -1, -1, -1, -1, device, unique );
+ }
+
+ RegCloseKey( hkResult );
+
+ return( SUCCESS );
+
+}
+
+
+
+INT HWC_FindScsiCards( CHAR *key_name )
+{
+LONG ret ;
+REGSAM samDesired ;
+HKEY hkResult ;
+ULONG key_index ;
+INT card ;
+FILETIME ftLastWrite ;
+CHAR name[ REGENUMKEYSIZE ] ;
+ULONG name_size ;
+CHAR temp_buff[ TEMPBUFFSIZE ] ;
+
+ samDesired = KEY_READ;
+
+ ret = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+ key_name, 0UL, samDesired, &hkResult );
+
+ if ( ret ) {
+ return( FAILURE );
+ }
+
+ key_index = 0UL ;
+
+ do {
+
+ name_size = REGENUMKEYSIZE ;
+
+ ret = RegEnumKeyEx( hkResult, key_index, name, &name_size,
+ NULL, NULL, NULL,
+ &ftLastWrite );
+
+ if ( ! ret ) {
+ CHAR_PTR s ;
+
+ strcpy( temp_buff, key_name );
+ strcat( temp_buff, TEXT("\\") );
+ strcat( temp_buff, name );
+
+ s = name ;
+
+ while ( *s && !_HWC_IsDigit( *s ) ) {
+ s++ ;
+ }
+
+ card = atoi( s );
+
+ HWC_FindBuses( card, temp_buff );
+ }
+
+ key_index++;
+
+ } while ( ! ret );
+
+ RegCloseKey( hkResult );
+
+ return( SUCCESS );
+}
+
+
+INT HWC_FindBuses( INT card, CHAR *key_name )
+{
+LONG ret;
+INT bus;
+REGSAM samDesired;
+HKEY hkResult;
+ULONG key_index;
+FILETIME ftLastWrite;
+CHAR name[ REGENUMKEYSIZE ] ;
+ULONG name_size ;
+CHAR temp_buff[ TEMPBUFFSIZE ] ;
+
+ samDesired = KEY_READ;
+
+ ret = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+ key_name, 0UL, samDesired, &hkResult );
+
+ if ( ret ) {
+ return( FAILURE );
+ }
+
+ key_index = 0UL ;
+
+ do {
+
+ name_size = REGENUMKEYSIZE ;
+
+ ret = RegEnumKeyEx( hkResult, key_index, name, &name_size,
+ NULL, NULL, NULL,
+ &ftLastWrite );
+
+ if ( ! ret ) {
+ CHAR_PTR s;
+
+ strcpy( temp_buff, key_name );
+ strcat( temp_buff, TEXT("\\") );
+ strcat( temp_buff, name );
+
+ s = name ;
+
+ while ( *s && !_HWC_IsDigit( *s ) ) {
+ s++ ;
+ }
+
+ bus = atoi( s );
+
+ HWC_FindTargets( card, bus, temp_buff );
+ }
+
+ key_index++;
+
+ } while ( ! ret );
+
+ RegCloseKey( hkResult );
+
+ return( SUCCESS );
+}
+
+
+INT HWC_FindTargets( INT card, INT bus, CHAR *key_name )
+{
+LONG ret;
+REGSAM samDesired;
+HKEY hkResult;
+ULONG key_index;
+FILETIME ftLastWrite;
+INT id = 0 ;
+CHAR name[ REGENUMKEYSIZE ] ;
+ULONG name_size ;
+CHAR temp_buff[ TEMPBUFFSIZE ];
+
+ samDesired = KEY_READ;
+
+ ret = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+ key_name, 0UL, samDesired, &hkResult );
+
+ if ( ret ) {
+ return( FAILURE );
+ }
+
+ key_index = 0UL ;
+
+ do {
+
+ name_size = REGENUMKEYSIZE ;
+
+ ret = RegEnumKeyEx( hkResult, key_index, name, &name_size,
+ NULL, NULL, NULL,
+ &ftLastWrite );
+
+ if ( ! ret ) {
+ CHAR_PTR s;
+
+ strcpy( temp_buff, key_name );
+ strcat( temp_buff, TEXT("\\") );
+ strcat( temp_buff, name );
+
+ s = name ;
+
+ while ( *s && !_HWC_IsDigit( *s ) ) {
+ s++ ;
+ }
+
+ id = atoi( s );
+
+ HWC_FindLuns( card, bus, id, temp_buff );
+ }
+
+ key_index++;
+
+ } while ( ! ret );
+
+ RegCloseKey( hkResult );
+
+ return( SUCCESS );
+}
+
+INT HWC_FindLuns( INT card, INT bus, INT id, CHAR *key_name )
+{
+LONG ret;
+INT lun;
+REGSAM samDesired;
+HKEY hkResult;
+ULONG key_index;
+FILETIME ftLastWrite;
+CHAR name[ REGENUMKEYSIZE ] ;
+ULONG name_size ;
+CHAR temp_buff[ TEMPBUFFSIZE ] ;
+
+
+ samDesired = KEY_READ;
+
+ ret = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+ key_name, 0UL, samDesired, &hkResult );
+
+ if ( ret ) {
+ return( FAILURE );
+ }
+
+ key_index = 0UL ;
+
+ do {
+
+ name_size = REGENUMKEYSIZE ;
+
+ ret = RegEnumKeyEx( hkResult, key_index, name, &name_size,
+ NULL, NULL, NULL,
+ &ftLastWrite );
+
+ if ( ! ret ) {
+ CHAR_PTR s;
+
+ strcpy( temp_buff, key_name );
+ strcat( temp_buff, TEXT("\\") );
+ strcat( temp_buff, name );
+
+ s = name ;
+
+ while ( *s && !_HWC_IsDigit( *s ) ) {
+ s++ ;
+ }
+
+ lun = atoi( s );
+
+ HWC_QueryValues( card, bus, id, lun, temp_buff );
+ }
+
+ key_index++;
+
+ } while ( ! ret );
+
+ RegCloseKey( hkResult );
+
+ return( SUCCESS );
+}
+
+
+INT HWC_QueryValues( INT card, INT bus, INT id, INT lun, CHAR *key_name )
+{
+LONG ret;
+REGSAM samDesired;
+HKEY hkResult;
+ULONG key_index;
+CHAR data[ REGENUMKEYSIZE ] ;
+DWORD data_size ;
+CHAR value_id[ REGENUMKEYSIZE ] ;
+DWORD value_size ;
+DWORD device = 0;
+INT tape_drive = FALSE;
+INT driver_loaded = FALSE;
+CHAR buffer[ TEMPBUFFSIZE ] ;
+
+ samDesired = KEY_QUERY_VALUE;
+
+ ret = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+ key_name, 0UL, samDesired, &hkResult );
+
+ if ( ret ) {
+ return( FAILURE );
+ }
+
+ key_index = 0UL ;
+
+ do {
+
+ value_size = REGENUMKEYSIZE ;
+ data_size = sizeof(data) ;
+
+ ret = RegEnumValue( hkResult, key_index, value_id, &value_size,
+ (LPDWORD)NULL, (LPDWORD)NULL, (LPBYTE)data, &data_size );
+
+ if ( ! ret ) {
+
+ if ( ! stricmp( value_id, TEXT("Type") ) ) {
+
+ if ( ! stricmp( data, TEXT("TapePeripheral") ) ) {
+ DriveFound = TRUE ;
+ tape_drive = TRUE;
+ }
+ }
+
+ if ( ! stricmp( value_id, TEXT("DeviceName") ) ) {
+ CHAR *s;
+
+ s = data;
+ s += strlen( TEXT("Tape") ) ;
+ device = atoi( s );
+ DriverLoaded = TRUE ;
+ driver_loaded = TRUE;
+ }
+
+
+ if ( ! stricmp( value_id, TEXT("Identifier") ) ) {
+ sprintf( buffer, TEXT("Scsi %d, Bus %d, Id %d, Lun %d %s"), card, bus, id, lun, data ) ;
+ }
+
+ }
+
+ key_index++;
+
+ } while ( ! ret );
+
+ if ( tape_drive && driver_loaded ) {
+ HWC_AddToDriveList( card, bus, id, lun, device, buffer );
+ }
+
+ RegCloseKey( hkResult );
+
+ return( SUCCESS );
+}
+
+BOOL HWC_AddToDriveList (
+INT card,
+INT bus,
+INT target_id,
+INT lun,
+INT device,
+CHAR_PTR drive_name ) // I - name of the device driver
+{
+ HWDRIVE_PTR new_drive;
+ static HWDRIVE_PTR last_drive;
+
+ // Allocate memory for the new card and stuff it.
+
+ new_drive = malloc( sizeof ( HWDRIVE ) +
+ ( ( strlen( drive_name ) + 1 ) * sizeof( CHAR )));
+
+ if ( new_drive == NULL ) {
+ return( FAILURE );
+ }
+
+ new_drive->drive_name = (CHAR_PTR)new_drive;
+ (INT8_PTR)(new_drive->drive_name) += sizeof( HWDRIVE );
+
+ // fill in drive name
+
+ strcpy ( new_drive->drive_name, drive_name );
+
+ // OK, fill out the rest of the card DS.
+
+ new_drive->q_elem.q_ptr = new_drive;
+ new_drive->card = card;
+ new_drive->bus = bus;
+ new_drive->target_id = target_id;
+ new_drive->lun = lun;
+ new_drive->device = device;
+ new_drive->floppy = FALSE;
+
+ if ( card == -1 && bus == -1 && target_id == -1 && lun == -1 ) {
+ new_drive->floppy = TRUE;
+ }
+
+
+ // Put the card on the end of the list.
+
+ if ( ! QueueCount( &DriveQueue ) ) {
+ EnQueueElem( &DriveQueue,
+ &(new_drive->q_elem), FALSE );
+ }
+ else {
+ InsertElem( &DriveQueue,
+ &(last_drive->q_elem),
+ &(new_drive->q_elem), AFTER );
+ }
+
+ last_drive = new_drive;
+
+ return SUCCESS;
+}
+
+
+HWDRIVE_PTR HWC_IsInDriveList (
+INT card,
+INT bus,
+INT id,
+INT lun,
+CHAR_PTR drive_name ) // I - name of the device driver
+{
+ HWDRIVE_PTR drive;
+
+
+ // CONFIGURATION WAS FOUND.
+ // Now, select the card in the list to be the card in the config.
+
+ drive = HWC_GetFirstDrive();
+
+ while ( drive ) {
+
+ if ( card == -1 || bus == -1 || id == -1 || lun == -1 ) {
+
+ // If we get any -1's and they have a floppy drive,
+ // default to it.
+
+ if ( drive->floppy ) {
+
+// return( drive ); // Card is valid, everything's OK.
+ }
+ }
+
+ if ( ( ( drive->card == card ) || ( card == -1 ) || drive->floppy ) &&
+ ( ( drive->bus == bus ) || ( bus == -1 ) || drive->floppy ) &&
+ ( ( drive->lun == lun ) || ( lun == -1 ) ) &&
+ ( ( drive->target_id == id ) || ( id == -1 ) ) ) {
+
+ if ( ! stricmp( drive->drive_name, drive_name ) ) {
+
+ return( drive ); // Card is valid, everything's OK.
+ }
+ }
+
+ drive = HWC_GetNextDrive( drive );
+ }
+
+ // CONFIGURATION WAS NOT FOUND OR WAS NOT VALID.
+
+ // return first drive, they probably only have one anyway.
+
+ drive = HWC_GetFirstDrive();
+
+ return ( drive );
+
+}
+
+
+BOOL HWC_BuildDriveComboBox (
+HWND hDlg ) // I - handle to the dialog
+{
+ HWDRIVE_PTR drive;
+
+ // Add all of the the controller cards to the list box.
+
+ drive = HWC_GetFirstDrive();
+
+ while ( drive ) {
+
+ SendDlgItemMessage ( (HWND) hDlg,
+ (INT) IDD_H_CONTROLLER,
+ (MSGID) CB_ADDSTRING,
+ (MPARAM1) 0,
+ (MPARAM2) drive->drive_name
+ );
+
+ drive = HWC_GetNextDrive( drive );
+ }
+
+ if ( mwSelectedDrive != NULL ) {
+
+ SendDlgItemMessage ( (HWND) hDlg,
+ (INT) IDD_H_CONTROLLER,
+ (MSGID) CB_SELECTSTRING,
+ (MPARAM1) -1,
+ (MPARAM2) mwSelectedDrive->drive_name
+ );
+ }
+ else {
+
+ // Indicate that there was no previously selected hardware config.
+
+ // If there is no controller card selected, setup the screen so
+ // that the user can make a selection based on cards that are
+ // supported by available device driver DLLs.
+
+ // Select the first card in the card list.
+
+
+
+ }
+
+ return FALSE;
+
+} /* end HWC_BuildDriveComboBox() */
+
+
+BOOL HWC_NewDriveSelected(
+HWND hDlg ) // I - handle to the dialog
+{
+ INT i;
+ INT nCard;
+ CHAR buffer[ 512 ];
+
+ // Get the index of the card in the list.
+
+ nCard = (INT)SendDlgItemMessage ( (HWND) hDlg,
+ (INT) IDD_H_CONTROLLER,
+ (MSGID) CB_GETCURSEL,
+ (MPARAM1) 0,
+ (MPARAM2) 0
+ );
+
+ if ( nCard == CB_ERR ) {
+ return FALSE;
+ }
+
+ nCard = (INT)SendDlgItemMessage ( (HWND) hDlg,
+ (INT) IDD_H_CONTROLLER,
+ (MSGID) CB_GETLBTEXT,
+ (MPARAM1) nCard,
+ (MPARAM2) buffer
+ );
+
+ if ( nCard == CB_ERR ) {
+ return FALSE;
+ }
+
+
+ // Now, get its associated card structure pointer.
+
+ mwSelectedDrive = HWC_GetFirstDrive();
+
+ while ( mwSelectedDrive ) {
+
+ if ( ! stricmp( mwSelectedDrive->drive_name, buffer ) ) {
+ break;
+ }
+ mwSelectedDrive = HWC_GetNextDrive( mwSelectedDrive );
+ }
+
+ return( TRUE );
+}
+
+
+
+VOID HWC_FreeDriveList ( VOID )
+{
+
+ mwSelectedDrive = (VOID_PTR)NULL;
+
+}
+
+
+
+
+HWDRIVE_PTR HWC_GetFirstDrive()
+{
+ Q_ELEM_PTR q_elem_ptr;
+
+ q_elem_ptr = QueueHead( &DriveQueue );
+
+ if ( q_elem_ptr != NULL ) {
+ return( (HWDRIVE_PTR)q_elem_ptr->q_ptr );
+ }
+
+ return( NULL );
+}
+
+
+HWDRIVE_PTR HWC_GetNextDrive( HWDRIVE_PTR drive )
+{
+ Q_ELEM_PTR q_elem_ptr;
+
+ if ( drive != NULL ) {
+
+ q_elem_ptr = QueueNext( &(drive->q_elem) );
+
+ if ( q_elem_ptr != NULL ) {
+ return( (HWDRIVE_PTR) q_elem_ptr->q_ptr );
+ }
+ }
+
+ return( NULL );
+}
+
+
+INT HWC_ProcessDILHWD( INT nProcFlag, DIL_HWD_PTR dil_ptr )
+{
+
+ if ( thw_list != NULL ) {
+
+ return( SUCCESS );
+ }
+ else {
+
+ HWC_ProcessError( (UINT16)nProcFlag,
+ (UINT16)0,
+ (UINT16)DRIVER_LOAD_FAILURE,
+ (UINT16)0,
+ CDS_GetPerm() );
+
+ return( HW_ERROR_DETECTED );
+ }
+}
+
+
+
+INT HWC_TestHardware( )
+{
+ gfHWInitialized = FALSE;
+ return( HWC_TapeHWProblem( bsd_list ) );
+}
+
+
+INT HWC_InitDILHWD( DIL_HWD_PTR *dil_ptr, INT *num_cards )
+{
+ return( SUCCESS );
+}
+
+
+INT HWC_ProcessError(
+UINT16 nProcFlag,
+UINT16 wStatus,
+UINT16 wError,
+UINT16 wCardNumber,
+CDS_PTR cds )
+{
+
+ if ( nProcFlag == HW_DISP_ERROR ) {
+
+ HWC_BuildDriveList();
+ HWC_FreeDriveList( );
+
+ if ( DriverLoaded ) {
+ WM_MsgBox ( ID(IDS_POLLDRIVE_MESSAGE),
+ ID(IDS_POLLDRIVE_SMALLPROBLEM),
+ WMMB_OK,
+ WMMB_ICONEXCLAMATION );
+
+ } else if ( DriveFound ) { /* driver not loaded */
+
+ WM_MsgBox ( ID(IDS_POLLDRIVE_MESSAGE),
+ ID(IDS_HWC_NO_DRIVE),
+ WMMB_OK,
+ WMMB_ICONEXCLAMATION );
+
+ } else { /* a drive did not exist */
+ WM_MsgBox ( ID(IDS_POLLDRIVE_MESSAGE),
+ ID(IDS_POLLDRIVE_BIGPROBLEM),
+ WMMB_OK,
+ WMMB_ICONEXCLAMATION );
+ }
+
+ }
+
+ return( SUCCESS );
+}
diff --git a/private/utils/ntbackup/src/hwctext.rc b/private/utils/ntbackup/src/hwctext.rc
new file mode 100644
index 000000000..7d5ae787b
--- /dev/null
+++ b/private/utils/ntbackup/src/hwctext.rc
@@ -0,0 +1,181 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: hwctext.rc
+
+ Description: This file contains the references to string resources for
+ the Windows GUI Project HARDWARE CONFIG Resource File.
+
+ $Log: G:/UI/LOGFILES/HWCTEXT.RCV $
+
+ Rev 1.11.1.3 11 Jun 1993 13:17:50 CHUCKB
+ Small grammar changes.
+
+ Rev 1.11.1.2 04 Jun 1993 19:44:10 STEVEN
+ fix typo
+
+ Rev 1.11.1.1 04 Jun 1993 18:55:24 STEVEN
+ added messages
+
+ Rev 1.11 12 Apr 1993 15:15:00 BARRY
+ Changed text of HWC_NO_DRIVE and IDS_POLLDRIVE_DRIVE_FAILURE per MSoft.
+
+ Rev 1.10 28 Jan 1993 15:57:48 GLENN
+ Changed Adaptec to ASPI.
+
+ Rev 1.9 27 Jan 1993 15:26:56 STEVEN
+ fix 'resart' to 'restart'
+
+ Rev 1.8 18 Jan 1993 14:50:50 GLENN
+ Changed 'shure' to 'sure' - DeVos Spelling.
+
+ Rev 1.7 30 Nov 1992 16:09:32 GLENN
+ Added IBM PS/2 SCSI hardware support.
+
+ Rev 1.6 02 Oct 1992 16:28:34 STEVEN
+ Added polldrive failure text.
+
+ Rev 1.5 04 May 1992 16:41:40 GLENN
+ Added PS/2 QIC and SCSI stuff.
+
+ Rev 1.4 19 Mar 1992 16:48:50 GLENN
+ Added enhanced status support.
+
+ Rev 1.3 17 Mar 1992 15:40:30 GLENN
+ Added POLLDRIVE messages.
+
+ Rev 1.2 10 Feb 1992 09:04:16 GLENN
+ Added warning text.
+
+ Rev 1.1 29 Jan 1992 17:52:04 GLENN
+ Added Testing hardware string.
+
+ Rev 1.0 24 Jan 1992 19:00:58 GLENN
+ Initial revision.
+
+******************************************************************************/
+
+
+// SEE ALSO STRINGS.H and PRODDEFS.H -- PRODDEFS.H MUST BE TRANSLATED!!!!!
+
+// hardware settings dialog control text
+
+
+IDS_HWC_DRIVER_MS_SCSI "MS_SCSI"
+IDS_HWC_CARD_0_MS_SCSI "Maynard PC 8-Bit SCSI Controller"
+IDS_HWC_CARD_1_MS_SCSI "Maynard PC 16-Bit SCSI Controller"
+IDS_HWC_CARD_2_MS_SCSI "Maynard PS/2 SCSI Controller"
+
+IDS_HWC_DRIVER_MS_QIC "MS_QIC"
+IDS_HWC_CARD_0_MS_QIC "Maynard PC QIC-02 Controller"
+IDS_HWC_CARD_1_MS_QIC "Maynard PS/2 QIC-02 Controller"
+
+IDS_HWC_DRIVER_AD_SCSI "AD_SCSI"
+IDS_HWC_CARD_0_AD_SCSI "ASPI PC SCSI Controller"
+IDS_HWC_CARD_1_AD_SCSI "ASPI PS/2 SCSI Controller"
+
+IDS_HWC_DRIVER_MS_DUMMY "MS_DUMMY"
+IDS_HWC_CARD_0_MS_DUMMY "Maynard Dummy Controller"
+
+IDS_HWC_DRIVER_IBM_SCSI "IBM_SCSI"
+IDS_HWC_CARD_0_IBM_SCSI "IBM PS/2 SCSI Controller"
+
+
+IDS_HWC_ATTACHED "&Attached drives"
+IDS_HWC_IOADDRESS "&I/O Address"
+IDS_HWC_IRQNUM "Interrupt &Number"
+IDS_HWC_DMACHANNEL "D&MA Channel"
+
+IDS_HWC_AUTO "Auto Determine"
+IDS_HWC_NONDMA "None (non-DMA)"
+
+IDS_HWC_IO_360 "360"
+IDS_HWC_IO_370 "370"
+IDS_HWC_IO_FF60 "FF60"
+IDS_HWC_IO_FF70 "FF70"
+
+IDS_HWC_0 "0"
+IDS_HWC_1 "1"
+IDS_HWC_2 "2"
+IDS_HWC_3 "3"
+IDS_HWC_4 "4"
+IDS_HWC_5 "5"
+IDS_HWC_6 "6"
+IDS_HWC_7 "7"
+IDS_HWC_8 "8"
+IDS_HWC_9 "9"
+IDS_HWC_10 "10"
+IDS_HWC_11 "11"
+IDS_HWC_12 "12"
+IDS_HWC_13 "13"
+IDS_HWC_14 "14"
+IDS_HWC_15 "15"
+
+
+
+IDS_HWC_TESTRESULTSTITLE "Tape Hardware Initialization Results"
+
+// LEAVE THE TRAILING BLANKS IN THE FOLLOWING STRINGS!
+
+IDS_HWC_TESTED_NOT "The hardware has not been initialized for this configuration. "
+IDS_HWC_TESTED_GOOD "The hardware is ACTIVE and initialized for this configuration. "
+IDS_HWC_TESTED_BAD "The hardware FAILED to initialize for this configuration. "
+IDS_HWC_TESTED_INIT "The hardware is initializing. "
+
+IDS_HWC_NOCONFIG "Select a controller card."
+
+IDS_HWC_INIT_SUCCESS "The hardware has been tested successfully."
+
+IDS_HWC_JUMPER_CHANGE "Warning: this change requires a jumper change to the controller card."
+
+#ifdef OS_WIN32
+IDS_POLLDRIVE_BIGPROBLEM "No tape drive detected. If a tape drive is attached, make sure that the cables are properly connected and that the power is on. Also make sure that the appropriate tape driver has been installed using the Tape Devices option in Control Panel."
+IDS_HWC_NO_DRIVE "A SCSI tape device has been detected, but the tape driver has either not been installed, or failed to start. Make sure that the appropriate driver has been installed using the Tape Devices option in Control Panel."
+IDS_POLLDRIVE_SMALLPROBLEM "A tape device has been detected, and the tape driver started. However, the tape device is not responding. Check that tape device power is on and cables are properly connected."
+#else
+IDS_HWC_NO_DRIVE "No tape drive has been detected. Make sure a tape drive is attached and power is on."
+IDS_POLLDRIVE_BIGPROBLEM "A hardware error has been detected. All attempts to correct this problem have failed. Please exit %s. It is not safe to continue."
+IDS_POLLDRIVE_SMALLPROBLEM "A hardware error has been detected. The hardware must be tested to help determine the problem."
+#endif
+
+IDS_HWC_INTERRUPT_CONFLICT "Interrupt conflict. Change the controller interrupt number."
+IDS_HWC_DMA_CONFLICT "DMA conflict. Change the controller card DMA setting."
+IDS_HWC_NO_CARD "No card has been detected. Install a card in the machine."
+IDS_HWC_INVALID_BASE_ADDR "Invalid Base Address. Select a different address."
+IDS_HWC_INVALID_INTERRUPT "Invalid Interrupt Number. Select a different number."
+IDS_HWC_INVALID_DMA "Invalid DMA Channel. Select a different channel."
+IDS_HWC_ATTACHED_DRIVES "The number of attached drives found (%u) does not match the configured value (%u)."
+IDS_HWC_NO_TARGET_ID "No Target ID has been selected. At least one Target ID must be selected."
+IDS_HWC_CARD_DISABLED "The Controller Card is Disabled. Enable it to perform the test."
+IDS_HWC_NO_DRIVE_LOADED "The device driver failed to load. This may be due to an incomplete installation. Reinstall or contact Technical Support."
+IDS_HWC_ERROR_NUMBER "HARDWARE ERROR: 0x%.4x. Contact Technical Support."
+
+IDS_HWC_WARNING_TITLE "Hardware Configuration Warning"
+IDS_HWC_NO_CONFIG "A controller card has not been selected. Do you wish to select one now?"
+
+#ifdef OEM_MSOFT
+IDS_POLLDRIVE_MESSAGE "Tape Drive Error Detected"
+#else
+IDS_POLLDRIVE_MESSAGE "Hardware Error Detected"
+#endif
+
+IDS_POLLDRIVE_DRIVE_FAILURE "The tape drive is not responding. Please check to make sure the tape drive is on, the cables are connected and the tape driver is installed. Then restart the %s program."
+IDS_POLLDRIVE_TAPE_EJECT "Tape Eject had a BIG PROBLEM: %d"
+
+
+
+
+// THE FOLLOWING DO NOT HAVE TO BE TRANSLATED!!!!!
+
+IDS_POLLDRIVE_INIT "Poll Drive Initialized"
+IDS_POLLDRIVE_INIT_FAILED "Poll Drive Initialization failed - FS_OpenFileSys()"
+IDS_POLLDRIVE_START "Poll Drive Start Message: %d"
+IDS_POLLDRIVE_POLL "Poll Drive Poll Message: %d"
+IDS_POLLDRIVE_STOP "Poll Drive Stop Message: %d"
+IDS_POLLDRIVE_START_REENT "Poll Drive RE_ENTERED: Start Message"
+IDS_POLLDRIVE_POLL_REENT "Poll Drive RE_ENTERED: Poll Message"
+IDS_POLLDRIVE_STOP_REENT "Poll Drive RE_ENTERED: Stop Message"
+IDS_POLLDRIVE_FAILED_MINOR "Poll Drive FAILED: MINOR ERROR -- Temporarily Ending Poll Drive"
+IDS_POLLDRIVE_FAILED_SEVERE "Poll Drive FAILED: SEVERE ERROR -- Shutting Off Poll Drive"
diff --git a/private/utils/ntbackup/src/icons.rc b/private/utils/ntbackup/src/icons.rc
new file mode 100644
index 000000000..36b6e2a6f
--- /dev/null
+++ b/private/utils/ntbackup/src/icons.rc
@@ -0,0 +1,85 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: wntrpark.rc
+
+ Description: This file contains the references to icon resources for
+ the Windows GUI Project Resource File.
+
+ $Log: G:/UI/LOGFILES/ICONS.RCV $
+
+ Rev 1.6 04 Jun 1992 17:21:10 DAVEV
+ OEM_MSOFT: only included icons which are required - no extras allowed
+
+ Rev 1.5 31 Mar 1992 14:07:56 DAVEV
+ OEM_MSOFT: alternate icons
+
+ Rev 1.4 04 Mar 1992 14:39:54 GLENN
+ Changed to old icons.
+
+ Rev 1.3 03 Mar 1992 18:02:50 GLENN
+ Updated animated icons.
+
+ Rev 1.2 26 Jan 1992 16:37:28 CHUCKB
+ Fixed some includes.
+
+ Rev 1.1 22 Jan 1992 12:27:50 GLENN
+ Added animated icons
+
+ Rev 1.0 20 Nov 1991 19:17:26 SYSTEM
+ Initial revision.
+
+******************************************************************************/
+
+// ICONS -- ID's are defined in the Resource Manager header file 'ss_rsm.h'
+#ifdef OEM_MSOFT //alternate icons
+
+ IDRI_WNTRPARK ICON ombackup.ico // Main icon.
+ //IDRI_BACKUP ICON ombacku2.ico // Backup icon.
+
+#else //ifdef OEM_MSOFT //alternate main icon
+
+ IDRI_WNTRPARK ICON wp6.ico // Main icon.
+
+#endif //OEM_MSOFT //alternate main icon
+
+IDRI_DISKS ICON disks.ico // Disks icon.
+IDRI_TAPES ICON tapes3.ico // Tapes icon.
+IDRI_TREE ICON tree.ico // Hierarchical tree list icon.
+IDRI_FILES ICON files.ico // Files list icon.
+IDRI_TREEFILE ICON treefile.ico // Tree and file list icon.
+IDRI_DEBUG ICON debug.ico // Debug window icon.
+IDRI_EXCHANGE ICON entrpris.ico // Enterprise icon.
+
+#ifndef OEM_MSOFT
+
+ IDRI_SETUP ICON setup.ico // Setup icon.
+ IDRI_JOBS ICON jobs.ico // Jobs icon.
+ IDRI_JOBS1 ICON jobs1.ico // Jobs 1 icon.
+ IDRI_JOBS2 ICON jobs2.ico // Jobs 2 icon.
+ IDRI_SERVERS ICON servers.ico // Servers icon.
+ IDRI_LOGFILES ICON logfiles.ico // Log files icon.
+ IDRI_SEARCH ICON search.ico // Search results icon.
+
+ IDRI_BACKUP ICON backup.ico // Backup icon.
+
+ IDRI_RESTORE ICON restore.ico // Restore icon.
+ IDRI_TRANSFER ICON transfer.ico // Transfer icon.
+ IDRI_DONE ICON done.ico // Operation Done icon.
+ IDRI_BKUP0 ICON bkup0.ico // Animated backup icon.
+ IDRI_BKUP1 ICON bkup1.ico // Animated backup icon.
+ IDRI_BKUP2 ICON bkup2.ico // Animated backup icon.
+ IDRI_BKUP3 ICON bkup3.ico // Animated backup icon.
+ IDRI_BKUP4 ICON bkup4.ico // Animated backup icon.
+ IDRI_BKUP5 ICON bkup5.ico // Animated backup icon.
+ IDRI_BKUP6 ICON bkup6.ico // Animated backup icon.
+ IDRI_BKUP7 ICON bkup7.ico // Animated backup icon.
+ IDRI_BKUP8 ICON bkup00.ico // Animated backup icon.
+ IDRI_SPIN0 ICON spin0.ico // Animated tape spin icon.
+ IDRI_SPIN1 ICON spin1.ico // Animated tape spin icon.
+ IDRI_SPIN2 ICON spin2.ico // Animated tape spin icon.
+ IDRI_SPIN3 ICON spin3.ico // Animated tape spin icon.
+
+#endif //OEM_MSOFT
diff --git a/private/utils/ntbackup/src/initfsys.c b/private/utils/ntbackup/src/initfsys.c
new file mode 100644
index 000000000..8a0aaddb5
--- /dev/null
+++ b/private/utils/ntbackup/src/initfsys.c
@@ -0,0 +1,456 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: initfsys.c
+
+ Description: This file contains code used to initialize the DLE
+ list. To do this all necessary resoruces are allocated.
+ Additionaly, this function contains the critical error function.
+
+
+ $Log: M:/LOGFILES/INITFSYS.C_V $
+
+ Rev 1.33 04 Jan 1994 14:30:08 BARRY
+Now call fs init entry points from FS_InitFileSys, not DLE_UpdateList
+
+ Rev 1.32 07 Sep 1993 14:54:50 MARINA
+(BARRY) Init MSNET function table
+
+ Rev 1.31 23 Jun 1993 10:45:26 DON
+Added back the change made in rev 1.29 which was lost when Mike P. Enabled C++ in rev 1.30
+
+ Rev 1.30 18 Jun 1993 10:04:50 MIKEP
+enable c++
+
+ Rev 1.28 19 May 1993 16:49:58 DON
+Only skip the DLE_UpdateList for OS_NLM. Causes problems the Client App can't deal with
+
+ Rev 1.27 19 May 1993 11:12:06 Stefan
+If compiling for the windows client, need to keep the DLE_Updatelist
+call in the initialization.
+
+ Rev 1.26 18 May 1993 20:05:18 DON
+Made the ifdef's a bit more readable!
+
+ Rev 1.25 18 May 1993 16:24:24 DON
+if OS_NLM or P_CLIENT then there's no need to call DLE_UpdateList until we
+actually need to use the dle_list.
+
+ Rev 1.24 19 Jan 1993 15:34:30 DOUG
+Changed dle_hand malloc() to calloc()
+
+ Rev 1.23 13 Jan 1993 15:04:38 DOUG
+Changed FS_RMFS to FS_GRFS
+
+ Rev 1.22 11 Nov 1992 22:26:52 GREGG
+Unicodeized literals.
+
+ Rev 1.21 18 Aug 1992 10:22:30 STEVEN
+fix warnings
+
+ Rev 1.20 05 Aug 1992 10:54:58 DON
+removed warning's
+
+ Rev 1.19 01 Mar 1992 12:34:42 DOUG
+Added support for RMFS.
+
+ Rev 1.18 13 Jan 1992 18:45:48 STEVEN
+changes for WIN32 compile
+
+ Rev 1.17 20 Dec 1991 10:41:46 STEVEN
+redesign function for common functions into tables
+
+ Rev 1.16 06 Dec 1991 11:31:36 BARRY
+Fixed default device problems
+
+ Rev 1.15 14 Nov 1991 10:07:46 BARRY
+Use new defines for initialization bits (to reflect the move from
+be_init.h to fsys_str.h).
+
+ Rev 1.14 13 Nov 1991 14:56:44 BARRY
+Misspelled some of the BE_FS macros.
+
+ Rev 1.13 31 Oct 1991 19:03:22 BARRY
+Forgot to include be_init.h.
+
+ Rev 1.12 24 Oct 1991 14:57:18 BARRY
+TRICYCLE: Added new bit-mask parameter to FS_InitFileSys() to select
+file systems at run-time.
+
+ Rev 1.11 01 Oct 1991 11:15:26 BARRY
+Include standard headers.
+
+ Rev 1.10 10 Sep 1991 17:32:24 STEVEN
+need to determine net before add servers
+
+ Rev 1.9 09 Sep 1991 10:17:06 BARRY
+Added support for SMS.
+
+ Rev 1.8 12 Aug 1991 15:47:00 BARRY
+BEC_DisplayNetwareServers( ) should not be referenced. We always add
+all kinds of Novell DLEs.
+
+ Rev 1.7 06 Aug 1991 18:31:34 DON
+added NLM File System support
+
+ Rev 1.6 25 Jul 1991 16:24:02 BARRY
+Config changes, fix up #ifdef code, NLM warning removal.
+
+ Rev 1.5 04 Jun 1991 18:46:46 BARRY
+Removed critical error code and now call InitCritErrorHandler() and
+DeInitCritErrorHandler() functions. (These reside in separate
+OS-specific modules.)
+
+ Rev 1.4 03 Jun 1991 13:26:40 BARRY
+Remove product defines from conditional compilation.
+
+ Rev 1.3 29 May 1991 11:07:44 STEVEN
+fix bugs in DLE insertsion sort
+
+ Rev 1.2 28 May 1991 12:05:26 STEVEN
+fix typo
+
+ Rev 1.1 23 May 1991 16:40:06 BARRY
+Changed FSYSs to be conditional on FS_XXX defines instead of product defines.
+
+ Rev 1.0 09 May 1991 13:35:40 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+
+#if defined( OS_OS2 )
+
+#define INCL_DOS
+#include <os2.h>
+
+#elif defined( OS_DOS )
+
+#include <dos.h>
+
+#endif /* OS-specific includes */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "fsys_err.h"
+#include "crit_err.h"
+#include "beconfig.h"
+#include "be_debug.h"
+
+/* $end$ include list */
+
+INT16 (*uw_crit_err)( CHAR_PTR, UINT16 ) = NULL ; /* user interface critical error handler */
+BOOLEAN uw_critical_error = FALSE ;
+
+/**/
+/**
+
+ Name: FS_InitFileSys()
+
+ Description: This function builds a list of all accessible drives
+ (DLEs). It also allocates resources needed to store and maintain this
+ list. It installs acritical error handler. The crit_err parameter
+ passed in points to a user interface function which prompts the user
+ to Abort, Retry, OR Ignore.
+
+
+ Modified: 7-12-89
+
+ Returns: The return value is an error code. They are:
+ OUT_OF_MEMORY
+ SUCCESS
+
+ Notes: This function is designed to only be called once.
+ The limitation is due to the critical error handler. There can
+ only be one handler, thus multiple installs must discard old
+ critical error handlers. If this does not cause a problem with
+ the application the multiple calls can be made.
+
+
+ See also: $/SEE( FS_OpenFileSys() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 FS_InitFileSys(
+DLE_HAND *hand, /* O - head of DLE list */
+BOOLEAN (*crit_err)( CHAR_PTR, UINT16 ), /* I - user interface critical error handler */
+BE_CFG_PTR cfg, /* I - config struct needed to create partition names */
+UINT16 remote_filter , /* I - bit_mask to specify visible remote resource types */
+UINT32 file_sys_mask ) /* I - bit_mask to specify file systems */
+{
+ BOOLEAN allocation_error = FALSE ;
+ INT16 ret_val = SUCCESS ;
+ INT16 i ;
+
+ /* Remote filter parameter not currently used */
+ (VOID) remote_filter ;
+
+ /* Initialize all entries to GENERIC for starters */
+
+ for ( i = 0; (i < MAX_DRV_TYPES); i++ ) {
+ func_tab[ i ] = GENFuncTab ;
+ }
+
+ /* Conditionally set all of the other entries to real FSs */
+
+#if defined( FS_DOS )
+ func_tab[ LOCAL_DOS_DRV ] = DOSFuncTab ;
+#endif
+
+#if defined( FS_OS2 )
+ func_tab[ LOCAL_OS2_DRV ] = OS2FuncTab ;
+#endif
+
+#if defined( FS_IMAGE )
+ func_tab[ LOCAL_IMAGE ] = ImageTab ;
+#endif
+
+#if defined( FS_REMOTE )
+ func_tab[ REMOTE_WORK_STAT ] = RemoteWSFuncTab ;
+ func_tab[ REMOTE_DOS_DRV ] = RemoteFuncTab ;
+#elif defined( FS_FAKEREM )
+ func_tab[ REMOTE_WORK_STAT ] = FakeRemoteWSFuncTab ;
+ func_tab[ REMOTE_DOS_DRV ] = FakeRemoteFuncTab ;
+#endif
+
+#if defined( FS_NOV_SERVER )
+ func_tab[ NOVELL_SERVER_ONLY ] = ServerVolFuncTab ;
+#endif
+
+#if defined( FS_AFP )
+ func_tab[ NOVELL_AFP_DRV ] = AFP_NovellFuncTab ;
+#endif
+
+#if defined( FS_NONAFP )
+ func_tab[ NOVELL_DRV ] = NovellFuncTab ;
+#endif
+
+#if defined( FS_NLMSERVER )
+ func_tab[ NLM_SERVER_ONLY ] = NLMServerVolFuncTab ;
+#endif
+
+#if defined( FS_NLMAFP )
+ func_tab[ NLM_AFP_VOLUME ] = NLMAFPNovellFuncTab ;
+#endif
+
+#if defined( FS_NLMNOV )
+ func_tab[ NLM_VOLUME ] = NLMNovellFuncTab ;
+#endif
+
+#if defined( FS_OS2 )
+ func_tab[ LOCAL_OS2_DRV ] = OS2FuncTab ;
+ if ( uw_os_version == 0 ) {
+ if ( DosGetVersion( &uw_os_version ) != SUCCESS ) {
+ uw_os_version = OS2_VER_1_1 ;
+ }
+ }
+#endif
+
+#if defined( FS_NTFS )
+ func_tab[ LOCAL_NTFS_DRV ] = NTFSFuncTab ;
+#endif
+
+
+#if defined( FS_SMS )
+ func_tab[ SMS_AGENT ] = TSAFuncTab ;
+ func_tab[ SMS_SERVICE ] = TSFuncTab ;
+ func_tab[ SMS_OBJECT ] = SMSFuncTab ;
+#endif
+
+#if defined( FS_GRFS )
+ func_tab[ GRFS_SERVER ] = GRFSFuncTab ;
+#endif
+
+#if defined( FS_MSNET )
+ func_tab[ MSNET ] = MSNetFuncTab ;
+#endif
+
+#if defined( FS_EMS )
+ func_tab[ FS_EMS_DRV ] = EMSFuncTab ;
+#endif
+
+/*
+ initialize the queue header
+*/
+
+ /** DJF: calloc() the dle_hand structure, so fs_initialize
+ field is reset **/
+
+ *hand = (struct HEAD_DLE *)calloc( 1, sizeof( struct HEAD_DLE ) ) ;
+ if ( *hand == NULL ) {
+ allocation_error = TRUE ;
+
+ } else {
+
+ (*hand)->default_drv = NULL ;
+ InitQueue( &((*hand)->q_hdr) ) ;
+ InitQueue( &((*hand)->fsh_queue) ) ;
+
+ InitCritErrorHandler( crit_err );
+ }
+
+ (*hand)->file_sys_mask = file_sys_mask ;
+
+
+/*
+ Pre -Initializes any special file systems
+*/
+
+ for ( i = 0; (i < MAX_DRV_TYPES) && (ret_val == SUCCESS); i++ ) {
+ if ( func_tab[i].InitFsys != NULL ) {
+ ret_val = func_tab[i].InitFsys( *hand, cfg, file_sys_mask ) ;
+ }
+ }
+
+ if ( ret_val == SUCCESS ) {
+ ret_val = DLE_UpdateList( *hand, cfg ) ;
+ }
+
+ if ( ret_val != SUCCESS ) {
+ FS_RemoveFileSys( *hand ) ;
+ }
+
+ return ret_val ;
+}
+
+/**/
+/**
+
+ Name: FS_RemoveFileSys()
+
+ Description: This function releases all resources allocated by the
+ FS_InitFileSys( ) call. It also releases the Critical Error Handler.
+
+
+ Modified: 7/12/1989
+
+ Returns: Error codes:
+ FS_NOT_INITIALIZED
+ SUCCESS
+
+ Notes:
+
+ See also: $/SEE( FS_InitFileSys() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID FS_RemoveFileSys(
+DLE_HAND hand ) /* I - drive list handle */
+{
+ GENERIC_DLE_PTR temp_dle ;
+ INT16 i ;
+
+ DLE_GetFirst( hand, &temp_dle ) ;
+
+ while ( temp_dle != NULL ) {
+ DLE_RemoveRecurse( temp_dle, TRUE ) ;
+ DLE_GetFirst( hand, &temp_dle ) ;
+ }
+
+ for( i = 0; i < MAX_DRV_TYPES; i++ ) {
+ if ( func_tab[i].DeInit != NULL ) {
+ func_tab[i].DeInit( hand ) ;
+ }
+ }
+
+ DeInitCritErrorHandler( ) ;
+
+ free( hand ) ;
+}
+
+
+
+/**/
+/**
+
+ Name: DLE_QueueInsert()
+
+ Description: This function inserts a dle into the DLE list
+
+ Modified: 9/26/1990
+
+ Returns: None
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID DLE_QueueInsert(
+DLE_HAND dle_hand, /* I - head of DLE list */
+GENERIC_DLE_PTR new_dle ) /* I - dle to insert into queue */
+{
+ GENERIC_DLE_PTR temp_dle ;
+ GENERIC_DLE_PTR last_dle = NULL ;
+ CHAR_PTR new_name ;
+ CHAR_PTR q_elem_name ;
+
+ new_name = DLE_GetDeviceName( new_dle ) ;
+
+ temp_dle = (GENERIC_DLE_PTR)QueueHead( &(dle_hand->q_hdr) ) ;
+
+ while( temp_dle != NULL ) {
+
+ q_elem_name = DLE_GetDeviceName( temp_dle ) ;
+
+ if ( ( new_name[1] == TEXT(':') ) && ( new_name[2] == TEXT('\0') ) &&
+ ( new_dle->type != LOCAL_IMAGE ) ) {
+
+ if ( ( q_elem_name[1] == TEXT(':') ) && ( q_elem_name[2] == TEXT('\0') ) ) {
+
+ if ( new_name[0] < q_elem_name[0] ) {
+ break ;
+ }
+
+ } else {
+
+ break ;
+ }
+ } else {
+
+ if ( new_dle->type < temp_dle->type ) {
+ break ;
+
+ } else if ( new_dle->type == temp_dle->type ) {
+
+ if ( stricmp( new_name, q_elem_name ) < 0 ) {
+ break ;
+ }
+ }
+ }
+
+ last_dle = temp_dle ;
+ temp_dle = (GENERIC_DLE_PTR)QueueNext( &(temp_dle->q) ) ;
+ }
+
+ if ( temp_dle == NULL ) {
+
+ EnQueueElem( &(dle_hand->q_hdr), &((new_dle)->q), FALSE ) ;
+
+ } else if ( last_dle == NULL ) {
+
+ InsertElem( &(dle_hand->q_hdr), &(temp_dle->q), &(new_dle->q), BEFORE ) ;
+
+ } else {
+
+ InsertElem( &(dle_hand->q_hdr), &(last_dle->q), &(new_dle->q), AFTER ) ;
+ }
+
+ return ;
+}
+
diff --git a/private/utils/ntbackup/src/log.c b/private/utils/ntbackup/src/log.c
new file mode 100644
index 000000000..1e3613929
--- /dev/null
+++ b/private/utils/ntbackup/src/log.c
@@ -0,0 +1,1864 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: log.c
+
+ Description: This file contains the functions for the GUI Log File
+ Manager (LOG). The functions handle reading, writing,
+ displaying, the log files. The Log File Manager uses the
+ Display List Manager to list and display the files.
+
+ $Log: G:/UI/LOGFILES/LOG.C_V $
+
+ Rev 1.50 22 Jul 1993 17:06:20 MARINA
+enable c++
+
+ Rev 1.49 24 Jun 1993 10:52:48 KEVINS
+Avoid potential hang by not checking return status when deleting log file.
+
+ Rev 1.48 21 Jun 1993 15:56:12 KEVINS
+Check return status of log file selected, just in case it's not there.
+
+ Rev 1.47 07 Jun 1993 08:18:26 MIKEP
+Fix warnings.
+
+ Rev 1.46 24 May 1993 15:21:44 BARRY
+Unicode fixes.
+
+ Rev 1.45 10 May 1993 17:14:36 KEVINS
+Allow user to specify log file base name.
+
+ Rev 1.44 02 May 1993 16:54:28 MIKEP
+Add call to support log files base name changing.
+
+ Rev 1.43 21 Apr 1993 10:31:50 DARRYLP
+Added the setting of the file name to the local variable to allow a viewed
+log file to be printed.
+
+ Rev 1.42 29 Mar 1993 11:05:14 TIMN
+Added f(x)s to get the catalog path or filename only
+
+ Rev 1.41 17 Mar 1993 18:12:58 DARRYLP
+Cleaned up display of file/date/time.
+
+ Rev 1.40 16 Mar 1993 12:38:54 CARLS
+LOG file changes
+
+ Rev 1.39 13 Mar 1993 20:13:12 MIKEP
+VLM_CloseWin will free the wininfo pointer
+
+
+******************************************************************************/
+
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+// PRIVATE FUNCTION PROTOTYPES
+
+BOOL LOG_InsertFiles ( Q_HEADER_PTR pLogQueue );
+BOOL LOG_KillLogFiles ( Q_HEADER_PTR pLogQueue, BOOL fRefresh );
+BOOL LOG_MakeNewFile ( LPSTR szFileName );
+VOID_PTR LOG_SetTag ( LOGITEM_PTR pLogItem, BYTE bTag );
+BYTE LOG_GetTag ( LOGITEM_PTR pLogItem );
+UINT LOG_GetItemCount ( Q_HEADER_PTR pLogQueue );
+VOID_PTR LOG_GetFirstItem ( Q_HEADER_PTR pLogQueue );
+VOID_PTR LOG_GetNextItem ( LOGITEM_PTR pLogItem );
+VOID_PTR LOG_GetPrevItem ( LOGITEM_PTR pLogItem );
+VOID_PTR LOG_GetObjects ( LOGITEM_PTR pLogItem );
+VOID_PTR LOG_SetObjects ( LOGITEM_PTR, WORD, BYTE );
+VOID LOG_SortLogFiles ( Q_HEADER_PTR pLogQueue );
+VOID LOG_ViewFile ( LOGITEM_PTR pLogItem );
+INT16 LOG_ItemCompare ( Q_ELEM_PTR pLogElem1, Q_ELEM_PTR pLogElem2 ) ;
+INT LOG_BuildLogViewList ( DLM_LOGITEM_PTR pDlm ) ;
+VOID LOG_BuildTitle ( LOGITEM_PTR pLogItem ) ;
+
+VOID_PTR LOG_SetViewTag ( LOGVIEWITEM_PTR pLogViewItem, BYTE bTag );
+BYTE LOG_GetViewTag ( LOGVIEWITEM_PTR pLogViewItem );
+VOID_PTR LOG_GetViewNextItem ( LOGVIEWITEM_PTR pLogViewItem );
+VOID_PTR LOG_GetViewPrevItem ( LOGVIEWITEM_PTR pLogViewItem );
+VOID_PTR LOG_GetViewObjects ( LOGVIEWITEM_PTR pLogViewItem );
+VOID_PTR LOG_SetViewObjects ( LOGVIEWITEM_PTR, WORD, BYTE );
+
+VOID LOG_ProcessViewList ( INT hFile, Q_HEADER_PTR pLogViewQueue, LPSTR szLogFile ) ;
+LPSTR LOG_GetLineFromFile ( INT hFile, LPWORD pwLength ) ;
+
+
+#define READBUFFERSIZE 4000
+#define MAXLINELENGTH 132
+
+static Q_HEADER_PTR mwpLogQueue;
+
+static UCHAR mwszCurrentLogFile [ MAX_UI_FULLPATH_SIZE ] = TEXT("\0");
+static UCHAR mwszCurrentViewLogFile [ MAX_UI_FULLPATH_SIZE ] = TEXT("\0");
+
+
+// FUNCTIONS
+
+
+/******************************************************************************
+
+ Name: LOG_BaseNameChanged()
+
+ Description: Refresh the window the base name displayed has changed.
+
+ Returns: SUCCESS if successful, otherwise FAILURE.
+
+******************************************************************************/
+
+VOID LOG_BaseNameChanged( VOID ) {
+
+ LOG_Refresh( );
+
+}
+
+/******************************************************************************
+
+ Name: LOG_Init()
+
+ Description: This function initializes and creates the log files window.
+
+ Returns: SUCCESS if successful, otherwise FAILURE.
+
+******************************************************************************/
+
+VOID LOG_Init ( VOID )
+
+{
+# if defined ( OEM_MSOFT ) // special feature
+ {
+# define OEMLOG_MAX_FILEPATH 512 //NTKLUG
+
+ CHAR szLogFilePath [ OEMLOG_MAX_FILEPATH ];
+ INT len;
+
+ if ( len = GetWindowsDirectory ( szLogFilePath,
+ OEMLOG_MAX_FILEPATH ) )
+ {
+ if ( szLogFilePath [ len-1 ] != TEXT('\\') //NTKLUG
+ && len < OEMLOG_MAX_FILEPATH )
+ {
+ strcat ( szLogFilePath, TEXT("\\") );
+ ++len;
+ }
+ if ( len < OEMLOG_MAX_FILEPATH
+ && RSM_StringCopy( IDS_OEMLOG_BACKUP_DEF_NAME,
+ szLogFilePath+len,
+ OEMLOG_MAX_FILEPATH - len ) > 0 )
+ {
+ LOG_SetCurrentLogName ( szLogFilePath );
+ }
+ }
+
+ }
+# endif //defined ( OEM_MSOFT ) // special feature
+# if !defined ( OEM_MSOFT ) // unsupported feature
+ {
+
+ PDS_WMINFO pdsWinInfo;
+ DLM_INIT dsDLM;
+ Q_HEADER_PTR pLogQueue;
+ UCHAR szName[ MAX_UI_RESOURCE_SIZE ] ;
+ CDS_PTR pCDS = CDS_GetPerm ();
+
+
+ ghWndLogFileView = 0;
+
+ pLogQueue = mwpLogQueue = (Q_HEADER_PTR)calloc( 1, sizeof(Q_HEADER) );
+
+ InitQueue ( pLogQueue );
+
+ // Check for any log files.
+
+ LOG_InsertFiles ( pLogQueue );
+
+ // Create the log window.
+
+ pdsWinInfo = (PDS_WMINFO)( calloc ( 1, sizeof ( DS_WMINFO ) ) );
+
+ WMDS_SetWinType ( pdsWinInfo, WMTYPE_LOGFILES );
+ WMDS_SetWinClosable ( pdsWinInfo, FALSE );
+ WMDS_SetCursor ( pdsWinInfo, RSM_CursorLoad ( ID(IDRC_ARROW) ) );
+ WMDS_SetIcon ( pdsWinInfo, RSM_IconLoad ( IDRI_LOGFILES ) );
+ WMDS_SetRibbon ( pdsWinInfo, ghRibbonMain );
+ WMDS_SetFlatList ( pdsWinInfo, pLogQueue );
+
+ DLM_ListBoxType ( &dsDLM, DLM_FLATLISTBOX );
+ DLM_Mode ( &dsDLM, DLM_SINGLECOLUMN ) ;
+ DLM_Display ( &dsDLM, DLM_SMALL_BITMAPS );
+ DLM_DispHdr ( &dsDLM, pLogQueue );
+ DLM_TextFont ( &dsDLM, DLM_SYSTEM_FONT );
+ DLM_GetItemCount ( &dsDLM, LOG_GetItemCount );
+ DLM_GetFirstItem ( &dsDLM, LOG_GetFirstItem );
+ DLM_GetNext ( &dsDLM, LOG_GetNextItem );
+ DLM_GetPrev ( &dsDLM, LOG_GetPrevItem );
+ DLM_GetObjects ( &dsDLM, LOG_GetObjects );
+ DLM_SetObjects ( &dsDLM, LOG_SetObjects );
+ DLM_GetTag ( &dsDLM, LOG_GetTag );
+ DLM_SetTag ( &dsDLM, LOG_SetTag );
+ DLM_GetSelect ( &dsDLM, NULL );
+ DLM_SetSelect ( &dsDLM, NULL );
+ DLM_SSetItemFocus ( &dsDLM, NULL ) ;
+ DLM_MaxNumObjects ( &dsDLM, 8 );
+
+ DLM_DispListInit ( pdsWinInfo, &dsDLM );
+
+ RSM_StringCopy( IDS_LOGFILESWINDOWNAME, (LPSTR)szName, MAX_UI_RESOURCE_LEN ) ;
+
+ ghWndLogFiles = WM_Create ( (WORD)(WM_MDIPRIMARY | WM_FLATLISTSC | CDS_GetLogInfo ( pCDS ).nSize),
+ (LPSTR) szName,
+ (LPSTR) NULL,
+ (INT)CDS_GetLogInfo ( pCDS ).x,
+ (INT)CDS_GetLogInfo ( pCDS ).y,
+ (INT)CDS_GetLogInfo ( pCDS ).cx,
+ (INT)CDS_GetLogInfo ( pCDS ).cy,
+ pdsWinInfo );
+
+ DLM_DispListProc ( WMDS_GetWinFlatList ( pdsWinInfo ), 0, NULL );
+
+ WM_Show ( ghWndLogFiles );
+ }
+# endif //!defined ( OEM_MSOFT ) // unsupported feature
+
+} /* end LOG_Init() */
+
+
+/******************************************************************************
+
+ Name: LOG_Deinit()
+
+ Description: This function deinitializes the log files window.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID LOG_Deinit ( VOID )
+
+{
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ CDS_PTR pCDS = CDS_GetPerm ();
+ PDS_WMINFO pdsWinInfo;
+
+
+ // See if the current session log file should be printed.
+ // Do not attempt to print if winback was called by the
+ // program manager or the launcher.
+
+ if ( CDS_GetYesFlag( pCDS ) != YESYES_FLAG ) {
+
+ PM_CheckSessionLogPrint() ;
+
+ }
+
+ // Destroy the log file view and log file windows.
+
+ if ( IsWindow( ghWndLogFileView) ) {
+
+ pdsWinInfo = WM_GetInfoPtr ( ghWndLogFileView );
+
+ WM_Destroy ( ghWndLogFileView );
+ }
+
+ if ( IsWindow( ghWndLogFiles) ) {
+
+ pdsWinInfo = WM_GetInfoPtr ( ghWndLogFiles );
+
+ CDS_WriteLogWinSize ( ghWndLogFiles );
+ WM_Destroy ( ghWndLogFiles );
+ }
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+} /* end LOG_Deinit() */
+
+
+/******************************************************************************
+
+ Name: LOG_GetLogFileName()
+
+ Description: This function gets a log file name from an item that has
+ been tagged. This name is used by the Print Manager to
+ print the log file.
+
+ Returns: A pointer to the next tagged log file item in the list.
+
+******************************************************************************/
+
+VOID_PTR LOG_GetLogFileName (
+
+VOID_PTR pLogItem, // I - pointer to NULL or a log item.
+LPSTR pString ) // O - pointer to log file name to be printed.
+
+{
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ PDS_WMINFO pdsWinInfo;
+ Q_HEADER_PTR pLogQueue;
+ CDS_PTR pCDS = CDS_GetPerm();
+
+ // If the log item pointer is 0, return the first item in the queue.
+ // Otherwise, get the next item in the queue.
+
+ if ( ! pLogItem ) {
+
+ pdsWinInfo = WM_GetInfoPtr ( ghWndLogFiles );
+
+ pLogQueue = pdsWinInfo->pFlatList;
+
+ DLM_UpdateTags ( ghWndLogFiles, DLM_FLATLISTBOX );
+
+ pLogItem = (VOID_PTR)LOG_GetFirstItem ( pLogQueue );
+ }
+ else {
+ pLogItem = (VOID_PTR)LOG_GetNextItem ( (LOGITEM_PTR) pLogItem );
+ }
+
+ // Look for the next item that is tagged.
+
+ do {
+ if ( pLogItem && ((LOGITEM_PTR)pLogItem)->bTag ) {
+
+ wsprintf ( pString, TEXT("%s%s"),
+ CDS_GetUserDataPath (),
+ (((LOGITEM_PTR)pLogItem)->szFileName ) );
+
+ break;
+ }
+ else if ( pLogItem ) {
+
+ pLogItem = (VOID_PTR)LOG_GetNextItem ( (LOGITEM_PTR) pLogItem );
+ }
+
+ } while ( pLogItem );
+
+
+ if ( ! pLogItem ) {
+
+ *pString = 0;
+ }
+
+ return pLogItem;
+ }
+# else //if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ return (VOID_PTR)( pLogItem = NULL );
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+} /* end LOG_GetLogFileName() */
+
+
+/******************************************************************************
+
+ Name: LOG_Refresh()
+
+ Description: This function refreshes the log files window by keeping
+ the most recent number of files that the user has
+ specified.
+
+ Notes: User will lose highlighted selections after this call.
+
+ Returns: none
+
+******************************************************************************/
+
+VOID LOG_Refresh ( VOID )
+
+{
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+
+ PDS_WMINFO pdsWinInfo ;
+ Q_HEADER_PTR pLogQueue ;
+ Q_ELEM_PTR pQElem ;
+ LOGITEM_PTR pLogItem ;
+
+ if ( ! IsWindow( ghWndLogFiles) ) {
+ return;
+ }
+
+ // Blow Away the List
+
+ pdsWinInfo = WM_GetInfoPtr( ghWndLogFiles ) ;
+ pLogQueue = pdsWinInfo->pFlatList;
+
+ // Release all the items in the queue
+
+ pQElem = DeQueueElem( pLogQueue );
+
+ while ( pQElem != NULL ) {
+
+ if ( pQElem->q_ptr ) {
+ free( pQElem->q_ptr );
+ }
+
+ pQElem = DeQueueElem( pLogQueue );
+ }
+
+ // Check for any log files.
+
+ InitQueue ( pLogQueue );
+
+ LOG_InsertFiles ( pLogQueue );
+
+ // Update the Display List Manager.
+
+ DLM_Update ( ghWndLogFiles, DLM_FLATLISTBOX, WM_DLMUPDATELIST, (LMHANDLE)NULL, 0 );
+
+ // IF the first log file on the queue is currently being viewed,
+ // THEN update the Log View File window to reflect possible changes.
+ // A current session log file must exist first.
+
+ if ( ( ghWndLogFileView ) && ( strlen ( LOG_GetCurrentLogName () ) ) ) {
+
+ if ( strcmpi ( LOG_GetCurrentLogName (), (LPSTR)mwszCurrentViewLogFile ) == 0 ) {
+
+ // The current log file will always be the first on the list.
+
+ pLogItem = (LOGITEM_PTR)LOG_GetFirstItem ( pLogQueue );
+
+ LOG_ViewFile( pLogItem ) ;
+ }
+ }
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+
+} /* end LOG_Refresh() */
+
+
+/******************************************************************************
+
+ Name: LOG_InsertFiles()
+
+ Description: This function inserts log file items into the log files
+ window list in sorted order. The display list manager
+ will use this list to display the information about
+ the log files.
+
+ Returns: SUCCESS if successful, otherwise FAILURE.
+
+******************************************************************************/
+
+BOOL LOG_InsertFiles (
+
+Q_HEADER_PTR pLogQueue ) // I - pointer to the header of the log item list.
+
+{
+ LOGITEM_PTR pLogItem;
+ UCHAR szPath[ VLM_MAXFNAME ];
+ UCHAR szFile[ VLM_MAXFNAME ];
+ CHAR_PTR pMaynPath;
+ VLM_FIND_PTR pVlmFind = NULL;
+ UINT unHour;
+ CHAR szPrefix [ MAX_UI_RESOURCE_SIZE ] ;
+ CHAR szExtension[ MAX_UI_RESOURCE_SIZE ] ;
+ CDS_PTR pCDS = CDS_GetPerm ();
+
+
+ if ( ! pLogQueue ) {
+ return FAILURE;
+ }
+
+ // Get the path and drive.
+
+ pMaynPath = CDS_GetUserDataPath ();
+
+ // Add the file specifier.
+
+ strcpy ( szPrefix , CDS_GetLogFileRoot ( pCDS ) );
+ RSM_StringCopy( IDS_LOGEXTENSION, szExtension, MAX_UI_RESOURCE_LEN ) ;
+
+ wsprintf ( (LPSTR)szPath, TEXT("%s%s%s%s"), pMaynPath, szPrefix, TEXT("??"), szExtension );
+
+ // Get all log file directory entries.
+
+ if ( !( pVlmFind = VLM_FindFirst ( (LPSTR)szPath, VLMFIND_NORMAL, (LPSTR)szFile ) ) )
+ {
+ return FAILURE;
+ }
+
+ // We have a log file.
+
+ do {
+ pLogItem = (LOGITEM_PTR) calloc ( 1, sizeof ( DS_LOGITEM ) );
+
+ // Quick exit if no memory.
+
+ if ( !pLogItem ) {
+ return ( FAILURE ) ;
+ }
+
+ pLogItem->pQElem.q_ptr = pLogItem;
+
+ strcpy ( (LPSTR)pLogItem->szFileName, (LPSTR)szFile );
+
+ // Insert log file into the log file queue.
+
+ unHour = VLM_FindWriteHour ( pVlmFind );
+
+ // Save Date and Time for quick sorting.
+
+ pLogItem->iDate = VLM_FindWriteDate ( pVlmFind );
+ pLogItem->iTime = VLM_FindWriteTime ( pVlmFind );
+ pLogItem->lSize = VLM_FindSize ( pVlmFind );
+
+ EnQueueElem ( pLogQueue, &pLogItem->pQElem, FALSE );
+
+
+ } while ( VLM_FindNext ( pVlmFind, (LPSTR)szFile ) );
+
+ VLM_FindClose( &pVlmFind );
+
+ // Sort them in the queue.
+
+ LOG_SortLogFiles ( pLogQueue ) ;
+
+ // Now kill off the oldest files over the maximum log files to keep.
+
+ LOG_KillLogFiles ( pLogQueue, FALSE );
+
+ return SUCCESS;
+
+} /* end LOG_InsertFiles() */
+
+
+/******************************************************************************
+
+ Name: LOG_KillLogFiles()
+
+ Description: This function deletes the oldest log files maintaining only
+ the most recent number of files that the user has
+ specified. It will refresh the log files window if
+ fRefresh is set to TRUE.
+
+ Returns: SUCCESS if successful, otherwise FAILURE.
+
+******************************************************************************/
+
+BOOL LOG_KillLogFiles (
+
+Q_HEADER_PTR pLogQueue, // I - the log queue
+BOOL fRefresh ) // I - specifies whether to refresh the log window
+
+{
+ UINT i;
+ UINT usCnt;
+ UINT usKeepCnt;
+ LOGITEM_PTR pLogItem;
+ LOGITEM_PTR pMaxLogItem;
+ CDS_PTR pCDS = CDS_GetPerm();
+
+ if ( ! pLogQueue ) {
+ return FAILURE;
+ }
+
+ // If the number of log sessions = 0, then don't do anything.
+
+ if ( CDS_GetNumLogSessions( pCDS ) == 0 ) {
+ return SUCCESS;
+ }
+
+ // Get the number of log files to keep.
+
+ usKeepCnt = CDS_GetNumLogSessions( pCDS);
+ usCnt = LOG_GetItemCount( pLogQueue );
+
+ // How many log files do we have? Remember the list is sorted by age
+ // in increasing order.
+
+ if ( usCnt && ( usCnt > usKeepCnt ) ) {
+
+ // Delete any extra log files starting with the oldest, etc...
+ // Go the Max number log session item and dequeue all items from
+ // here on.
+
+ pLogItem = (LOGITEM_PTR)LOG_GetFirstItem ( pLogQueue );
+
+ for ( i = 0; ( pLogItem && ( i < ( usKeepCnt - 1 ) ) ); i++ ) {
+ pLogItem = (LOGITEM_PTR)LOG_GetNextItem ( (LOGITEM_PTR) pLogItem );
+ }
+
+ // If list is found to be corrupt, then return FAILURE.
+
+ pMaxLogItem = pLogItem;
+
+ // Delete all elements on the list from here and delete
+ // the log files each element references.
+
+ pLogItem = (LOGITEM_PTR)LOG_GetNextItem ( (LOGITEM_PTR) pMaxLogItem );
+
+ while ( pLogItem ) {
+
+ UCHAR szPath[ MAX_UI_FULLPATH_SIZE ] ;
+
+ // Delete the file after building the full file path name.
+
+ wsprintf ( (LPSTR)szPath, TEXT("%s%s"), CDS_GetUserDataPath(),pLogItem->szFileName );
+
+ // delete the file
+
+ unlink( (LPSTR)szPath );
+
+ // Remove Item off the list.
+
+ RemoveQueueElem( pLogQueue, &pLogItem->pQElem ) ;
+ free( pLogItem ) ;
+
+ pLogItem = (LOGITEM_PTR)LOG_GetNextItem ( (LOGITEM_PTR) pMaxLogItem );
+ }
+
+ if ( fRefresh ) {
+ LOG_Refresh ();
+ }
+ }
+
+ return SUCCESS;
+
+} /* end LOG_KillLogFiles() */
+
+
+/******************************************************************************
+
+ Name: LOG_MakeNewFileName()
+
+ Description: This function makes the next available log file name.
+
+ Returns: SUCCESS if successful, otherwise FAILURE.
+
+******************************************************************************/
+
+BOOL LOG_MakeNewFileName (
+
+LPSTR pDest ) // I - destination string pointer
+
+{
+ UCHAR szPath[ MAX_UI_PATH_SIZE ] ;
+ CHAR_PTR pMaynPath;
+ UINT16 unNum;
+ CHAR szPrefix [ MAX_UI_SMALLRES_SIZE ] ;
+ CHAR szExtension[ MAX_UI_SMALLRES_SIZE ] ;
+
+ BOOL fFound = FALSE;
+ CDS_PTR pCDS = CDS_GetPerm ();
+
+ // Get the path and drive.
+
+ strcpy ( szPrefix , CDS_GetLogFileRoot ( pCDS ) );
+ RSM_StringCopy( IDS_LOGEXTENSION, szExtension, MAX_UI_SMALLRES_LEN ) ;
+
+ unNum = 0 ;
+
+ pMaynPath = CDS_GetUserDataPath ();
+
+ do {
+ // Add the file specifier, the number, and extension.
+
+ wsprintf ( (LPSTR)szPath, TEXT("%s%s%.2u%s"), pMaynPath, szPrefix, unNum, szExtension );
+
+ // See if the file exists.
+
+ if ( access ( (LPSTR)szPath, LOG_FILEEXISTS ) == -1 ) {
+ fFound = TRUE;
+ }
+ else {
+ unNum++;
+ }
+
+ } while ( ! fFound && unNum < (UINT16) CDS_GetNumLogSessions( pCDS ) );
+
+ wsprintf ( pDest, TEXT("%s%.2u%s"), szPrefix, unNum, szExtension );
+
+ return ! fFound;
+
+} /* end LOG_MakeNewFileName() */
+
+
+
+/******************************************************************************
+
+ Name: LOG_GenerateLogFileName()
+
+ Description: This function will generate a new file name.
+ If the user has reached the maximum limit of log files,
+ the oldest log files will be deleted for a new log file.
+
+ Returns: SUCCESS if successful, otherwise FAILURE.
+
+******************************************************************************/
+
+VOID LOG_GenerateLogFileName (
+
+LPSTR pDest ) // I - destination string pointer
+
+{
+ UCHAR szPath[ MAX_UI_PATH_SIZE ]; // File name plus extension. Extra bytes.
+
+ // Kill off log files if need be. Passing TRUE will refresh the log files
+ // window if any log files were killed.
+
+ LOG_KillLogFiles ( mwpLogQueue, TRUE );
+
+ // Get the path and drive.
+
+ strcpy( pDest, CDS_GetUserDataPath () ) ;
+
+ LOG_MakeNewFileName ( (LPSTR)szPath ) ;
+
+ strcat( pDest, (LPSTR)szPath ) ;
+
+ LOG_SetCurrentLogName ( pDest );
+
+}
+
+/**************************************************************************
+
+ Name: LOG_GetCurrentLogPathOnly
+
+ Description: This function will get the path of the current
+ log file path. If no log path is being used, then
+ an empty string is stored. The parameter 'path'
+ is used as the buffer to store the log path. The
+ path ends with a trailing backslash.
+ i.e., 'c:\nt\'
+
+ Modified: 03/23/1993
+
+ Returns: Nothing.
+
+ See also : LOG_GenerateLogFileName
+
+**************************************************************************/
+
+VOID LOG_GetCurrentLogPathOnly( CHAR_PTR path )
+
+{
+LPSTR pEndOfPath = strrchr( (LPSTR)mwszCurrentLogFile, '\\' ) ;
+INT nPathSize ;
+
+ if ( pEndOfPath != NULL ) {
+ nPathSize = (INT)((++pEndOfPath) - (LPSTR)mwszCurrentLogFile ) ;
+ strncpy( path, (LPSTR)mwszCurrentLogFile, nPathSize ) ;
+ path[ nPathSize ] = TEXT('\0') ;
+ }
+ else {
+ // no path supplied, will exclude every file with log name
+ strcpy( path, TEXT("") ) ;
+ }
+}
+
+/**************************************************************************
+
+ Name: LOG_GetCurrentLogNameOnly
+
+ Description: This function will return the name of the current
+ log file only. If a path is include in the log file,
+ it is parsed out. There is always at least a default
+ log path+file in the mwszCurrentLogFile data field
+
+ Modified: 03/23/1993
+
+ Returns: Pointer to a string.
+
+ See also : LOG_GenerateLogFileName
+
+**************************************************************************/
+
+LPSTR LOG_GetCurrentLogNameOnly( VOID )
+
+{
+LPSTR szTemp = strrchr( (LPSTR)mwszCurrentLogFile, '\\' ) ;
+
+ if ( szTemp != NULL ) {
+ return( szTemp + 1 ) ;
+ }
+ else {
+ return (LPSTR)mwszCurrentLogFile ;
+ }
+}
+
+/**************************************************************************
+
+ Name: LOG_GetCurrentLogName
+
+ Description: This function will return the name of the current
+ log file. If no log file is being used, then
+ then an empty string is returned.
+
+ Modified: 10/24/1991
+
+ Returns: Pointer to a string.
+
+ See also : LOG_GenerateLogFileName
+
+**************************************************************************/
+
+LPSTR LOG_GetCurrentLogName( void )
+
+{
+ return (LPSTR)mwszCurrentLogFile;
+}
+
+
+/**************************************************************************
+
+ Name: LOG_SetCurrentLogName
+
+ Description: This function will set the name of the current
+ log file.
+
+ Modified: 2/24/1991
+
+ Returns: Pointer to a string.
+
+ See also : LOG_SetCurrentLogName
+
+**************************************************************************/
+
+VOID LOG_SetCurrentLogName (
+
+LPSTR pszLogName )
+
+{
+ strcpy ( (LPSTR)mwszCurrentLogFile, pszLogName );
+}
+
+
+/**************************************************************************
+
+ Name: LOG_GetCurrentViewLogName
+
+ Description: This function will return the name of the current
+ log view file.
+
+ Modified: 10/24/1991
+
+ Returns: Pointer to a string.
+
+ Notes: Always check the handle ghWndLogFileView for being NULL
+ before assuming the validity of this field.
+
+**************************************************************************/
+
+LPSTR LOG_GetCurrentViewLogName( void )
+
+{
+ return (LPSTR)mwszCurrentViewLogFile ;
+}
+
+
+
+/******************************************************************************
+
+ Name: LOG_SortLogFiles()
+
+ Description: This function sorts the log files by date and time.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID LOG_SortLogFiles (
+
+Q_HEADER_PTR pLogQueue ) // I - pointer to a log item.
+
+{
+
+ SortQueue( pLogQueue, LOG_ItemCompare );
+
+} /* end LOG_SortLogFiles() */
+
+
+/******************************************************************************
+
+ Name: LOG_ItemCompare()
+
+ Description: This function will compare the dates of two log files.
+ Ordering is youngest to oldest.
+
+ Returns: 1 if date of log1 < log2.
+ 0 if dates equal.
+ -1 if date of log1 > log2.
+
+******************************************************************************/
+
+INT16 LOG_ItemCompare(
+
+Q_ELEM_PTR pLogElem1, // I - queue element 1
+Q_ELEM_PTR pLogElem2 ) // I - queue element 2
+
+{
+ INT nResult ;
+ LOGITEM_PTR pLogItem1, pLogItem2;
+
+ pLogItem1 = (LOGITEM_PTR) pLogElem1->q_ptr;
+ pLogItem2 = (LOGITEM_PTR) pLogElem2->q_ptr;
+
+ // First check the dates and then the time if need be.
+
+ // Set default value to 0 to designate the elements being equal.
+
+ nResult = 0 ;
+
+ if ( LOG_GetItemDate( pLogItem1 ) == LOG_GetItemDate( pLogItem2 ) ) {
+
+ nResult = ( ( pLogItem1->iTime < pLogItem2->iTime ) ? 1 : -1 ) ;
+
+ } else {
+
+ // Set return value appropiately.
+
+ nResult = ( ( LOG_GetItemDate( pLogItem1 ) < LOG_GetItemDate( pLogItem2 ) ) ? 1 : -1 ) ;
+ }
+
+ return( (INT16)nResult ) ;
+}
+
+
+// DISPLAY LIST MANAGER CALL BACK FUNCTIONS.
+
+
+/****************************************************************************
+
+ Name: LOG_SetTag()
+
+ Description: This function sets the tag status of an item structure.
+
+ Returns: Nothing.
+
+****************************************************************************/
+
+VOID_PTR LOG_SetTag (
+
+LOGITEM_PTR pLogItem, // I - pointer to a list item
+BYTE bState ) // I - state to set the item to
+
+{
+ pLogItem->bTag = bState;
+ return( NULL ) ; // Return value unused.
+}
+
+
+
+/******************************************************************************
+
+ Name: LOG_GetTag()
+
+ Description: This function gets the tag status for the
+ Display List Manager.
+
+ Returns: The tag status of the item.
+
+******************************************************************************/
+
+BYTE LOG_GetTag (
+
+LOGITEM_PTR pLogItem ) // I - pointer to a list item
+
+{
+ return pLogItem->bTag;
+}
+
+
+/******************************************************************************
+
+ Name: LOG_GetItemCount()
+
+ Description: This function gets the item count in our list for the
+ Display List Manager.
+
+ Returns: The number of items in the list.
+
+******************************************************************************/
+
+UINT LOG_GetItemCount (
+
+Q_HEADER_PTR pLogQueue ) // I - pointer to a Log queue.
+
+{
+ return QueueCount ( pLogQueue );
+}
+
+
+/******************************************************************************
+
+ Name: LOG_GetFirstItem()
+
+ Description: This function returns the first item for the
+ Display List Manager.
+
+ Returns: The first item in the list.
+
+******************************************************************************/
+
+VOID_PTR LOG_GetFirstItem (
+
+Q_HEADER_PTR pLogQueue ) // I - pointer to a Log queue.
+
+{
+ Q_ELEM_PTR q;
+
+ q = QueueHead ( pLogQueue );
+
+ return( (q) ? (VOID_PTR)QueuePtr(q) : (VOID_PTR)NULL );
+}
+
+
+/******************************************************************************
+
+ Name: LOG_GetPrevItem()
+
+ Description: This function returns the previous list item for the
+ Display List Manager.
+
+ Returns: The previous item in the list.
+
+******************************************************************************/
+
+VOID_PTR LOG_GetPrevItem (
+
+LOGITEM_PTR pLogItem ) // I - pointer to a list item
+
+{
+ Q_ELEM_PTR q;
+
+ q = QueuePrev( &(pLogItem->pQElem) );
+
+ return( (q) ? (VOID_PTR)QueuePtr(q) : (VOID_PTR)NULL );
+}
+
+
+/******************************************************************************
+
+ Name: LOG_GetNextItem()
+
+ Description: This function returns the next list item for the
+ Display List Manager.
+
+ Returns: The next item in the list.
+
+******************************************************************************/
+
+VOID_PTR LOG_GetNextItem (
+
+LOGITEM_PTR pLogItem ) // I - pointer to a list item
+
+{
+ Q_ELEM_PTR q;
+
+ q = QueueNext ( &(pLogItem->pQElem) );
+
+ return( (q) ? (VOID_PTR)QueuePtr(q) : (VOID_PTR)NULL );
+}
+
+
+/******************************************************************************
+
+ Name: LOG_GetObjects()
+
+ Description: This function returns a given object and gets the
+ information that needs to be displayed by Display List
+ Manager.
+
+ Returns: The list of objects to be displayed.
+
+ Notes: 8 objects described:
+
+ 1st - Bitmap
+ 2nd - "Logged On"
+ 3rd - Date
+ 4th - Time
+ 5th - " for [fn] "
+ 6th - length
+ 7th - "bytes"
+
+ Example Output String
+
+ Logged On 12/12/1987 at 3:24 a.m. for MAYN0001.LOG 3456 bytes.
+
+*****************************************************************************/
+
+VOID_PTR LOG_GetObjects (
+
+LOGITEM_PTR pLogItem ) // I - pointer to a list item
+
+{
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ CHAR_PTR memblk ;
+ DLM_ITEM_PTR item;
+ PDS_WMINFO pdsWinInfo;
+ LPSTR pszString ;
+ UCHAR szShortFileName [ MAX_UI_FILENAME_SIZE ] ;
+ UCHAR szFormat [ MAX_UI_RESOURCE_SIZE ] ;
+ UCHAR szResourceStr [ MAX_UI_RESOURCE_SIZE ] ;
+ CHAR szDate [ MAX_UI_TIME_SIZE ];
+ CHAR szTime [ MAX_UI_TIME_SIZE ] ;
+ CHAR szLoggedOn [ MAX_UI_SMALLRES_SIZE ] ;
+ CHAR szAt [ MAX_UI_SMALLRES_SIZE ] ;
+ CHAR szFor [ MAX_UI_SMALLRES_SIZE ] ;
+ CHAR szPrefix [ MAX_UI_SMALLRES_SIZE ] ;
+ CHAR szExtension [ MAX_UI_SMALLRES_SIZE ] ;
+ CHAR szAMString [ MAX_UI_SMALLRES_SIZE ] ;
+ CHAR szPMString [ MAX_UI_SMALLRES_SIZE ] ;
+
+ DLM_HEADER_PTR pdsHdr ;
+ INT nPixel ;
+ INT nPixelpm ;
+ BYTE bObjectCnt = 0 ;
+
+ // Read in resources.
+
+ RSM_StringCopy( IDS_LOGPREFIX, szPrefix, MAX_UI_SMALLRES_LEN ) ;
+ RSM_StringCopy( IDS_LOGEXTENSION, szExtension, MAX_UI_SMALLRES_LEN ) ;
+ RSM_StringCopy( IDS_LOGLOGGEDON, szLoggedOn, MAX_UI_SMALLRES_LEN ) ;
+ RSM_StringCopy( IDS_LOGSTRINGAT, szAt, MAX_UI_SMALLRES_LEN ) ;
+ RSM_StringCopy( IDS_LOGFILENAMEPREFIX, szFor, MAX_UI_SMALLRES_LEN ) ;
+ RSM_StringCopy( IDS_LOGLENGTHOFFILE, (LPSTR)szFormat, MAX_UI_RESOURCE_LEN ) ;
+
+
+ // Get International date and time.
+
+ UI_IntToDate( szDate, LOG_GetItemDate ( pLogItem ) ) ;
+ UI_IntToTime( szTime, LOG_GetItemTime ( pLogItem ) ) ;
+
+ pdsWinInfo = WM_GetInfoPtr( ghWndLogFiles );
+
+ pdsHdr = DLM_GetDispHdr ( pdsWinInfo->hWndFlatList ) ;
+
+ memblk = (CHAR_PTR)DLM_GetObjectsBuffer( pdsWinInfo->hWndFlatList );
+
+ // Exception Handling.
+
+ if ( !pdsWinInfo || !pdsHdr || !memblk ) {
+ return (NULL ) ;
+ }
+
+ // Store the number of items in the first two bytes.
+
+ *memblk = 6; // Set up when window was created.
+
+ // Set up the bitmap.
+
+ item = (DLM_ITEM_PTR)( memblk + 6 );
+
+ DLM_ItemcbNum( item ) = bObjectCnt++ ; // Object #1
+ DLM_ItembType( item ) = DLM_BITMAP;
+ DLM_ItemwId( item ) = IDRBM_LOGFILE;
+ DLM_ItembMaxTextLen( item ) = 0;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+
+ // Set up text "Logged on"
+
+ item++;
+ DLM_ItemcbNum( item ) = bObjectCnt++ ; // Object #2
+ DLM_ItembType( item ) = DLM_TEXT_ONLY ;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+
+ strcpy( (LPSTR)DLM_ItemqszString( item ), szLoggedOn );
+
+ nPixel = RSM_GetFontStringWidth( ghFontIconLabels,
+ szLoggedOn, strlen( szLoggedOn ) ) ;
+
+ DLM_ItembMaxTextLen( item ) = ( BYTE ) ( ( nPixel / (INT) (pdsHdr->cxTextWidth ) ) + 1 ) ;
+
+ // Set up date
+
+ item++;
+ DLM_ItemcbNum( item ) = bObjectCnt++ ; // Object #3
+ DLM_ItembType( item ) = DLM_TEXT_ONLY ;
+ DLM_ItembTextMode( item ) = DLM_RIGHT_JUSTIFY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0; // mm/dd/yyyy worse case
+ sprintf((CHAR_PTR)szResourceStr, TEXT("%8s"), (CHAR_PTR)szDate);
+ strcpy( (LPSTR)DLM_ItemqszString( item ), (CHAR_PTR)szResourceStr );
+
+ if ( UI_UseLeadCentury() ) {
+
+ nPixel = RSM_GetFontStringWidth( ghFontIconLabels,
+ TEXT("00/00/0000"), strlen( TEXT("00/00/0000") ) ) ;
+
+ } else {
+
+ nPixel = RSM_GetFontStringWidth( ghFontIconLabels,
+ TEXT("00/00/00"), strlen( TEXT("00/00/00") ) ) ;
+ }
+
+ DLM_ItembMaxTextLen( item ) = ( BYTE ) ( ( nPixel / (INT) (pdsHdr->cxTextWidth ) ) + 1 ) ;
+
+
+ // Set up time
+
+ UI_GetPMString ( szPMString ) ;
+ UI_GetAMString ( szAMString ) ;
+
+ item++;
+ DLM_ItemcbNum( item ) = bObjectCnt++ ; // Object #5
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItembTextMode( item ) = DLM_RIGHT_JUSTIFY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0; // hh/mm [stringxx]
+
+ sprintf((CHAR_PTR)szResourceStr, TEXT("%8s"), (CHAR_PTR)szTime);
+ strcpy( (LPSTR)DLM_ItemqszString( item ), (CHAR_PTR)szResourceStr );
+
+
+ nPixel = RSM_GetFontStringWidth( ghFontIconLabels,
+ TEXT("00:00:00 "), strlen( TEXT("00:00:00 ") ) ) ;
+
+ DLM_ItembMaxTextLen( item ) = ( BYTE ) ( ( nPixel / (INT) (pdsHdr->cxTextWidth ) ) + 1 ) ;
+
+ // If am or pm string defined, then pick maximum
+
+ if ( strlen( szAMString ) || strlen( szPMString ) ) {
+
+ nPixel = RSM_GetFontStringWidth( ghFontIconLabels,
+ szAMString, strlen( szAMString ) ) ;
+
+ nPixelpm = RSM_GetFontStringWidth( ghFontIconLabels,
+ szPMString, strlen( szPMString ) ) ;
+
+ if ( nPixelpm > nPixel ) {
+ nPixel = nPixelpm ;
+ }
+
+ DLM_ItembMaxTextLen( item ) += (BYTE) ( nPixel / (INT) (pdsHdr->cxTextWidth ) ) + 1 ;
+
+ }
+
+ // Set up " for [fn] "
+
+ item++;
+ DLM_ItemcbNum( item ) = bObjectCnt++ ; // Object #6
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = ( BYTE ) ( strlen( szFor ) ) ;
+ strcpy( (LPSTR)DLM_ItemqszString( item ), szFor );
+
+ // Concatenate file name.
+
+ if ( pszString = strrchr( (LPSTR)pLogItem->szFileName , TEXT('\\') ) ) {
+ strcpy( (LPSTR)szShortFileName, ++pszString ) ;
+ } else {
+ strcpy( (LPSTR)szShortFileName, (LPSTR)pLogItem->szFileName ) ;
+ }
+
+ strcat( (LPSTR)DLM_ItemqszString( item ), (LPSTR)szShortFileName ) ;
+
+ nPixel = RSM_GetFontStringWidth( ghFontIconLabels,
+ (LPSTR)DLM_ItemqszString( item ),
+ strlen( (LPSTR)DLM_ItemqszString( item ) ) ) ;
+
+
+ DLM_ItembMaxTextLen( item ) = ( BYTE ) ( ( nPixel / (INT) (pdsHdr->cxTextWidth ) ) + 1 ) ;
+
+ // Setup length of log file
+
+ item++;
+ DLM_ItemcbNum( item ) = bObjectCnt++; // Object #7
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItembTextMode( item ) = DLM_RIGHT_JUSTIFY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+
+ wsprintf( (LPSTR)szResourceStr, (LPSTR)szFormat, pLogItem->lSize ) ;
+ strcpy( (LPSTR)DLM_ItemqszString( item ), (LPSTR)szResourceStr ) ;
+
+ wsprintf( (LPSTR)szResourceStr, (LPSTR)szFormat, (long) 99999999L ) ;
+
+ nPixel = RSM_GetFontStringWidth( ghFontIconLabels,
+ (LPSTR)szResourceStr,
+ strlen( (LPSTR)szResourceStr ) ) ;
+
+ DLM_ItembMaxTextLen( item ) = ( BYTE ) ( ( nPixel / (INT) (pdsHdr->cxTextWidth ) ) + 1 ) ;
+
+
+ return ( memblk ) ;
+ }
+# else //if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ return NULL;
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+}
+
+
+/******************************************************************************
+
+ Name: LOG_SetObjects()
+
+ Description: This function performs an action based on a click or
+ double-click on an item that is in the list.
+
+ Returns: NULL.
+
+******************************************************************************/
+
+VOID_PTR LOG_SetObjects (
+
+LOGITEM_PTR pLogItem, // I - pointer to a list item
+WORD wEvent, // I - type of event
+BYTE bSubItem ) // I - sub item
+
+{
+ DBG_UNREFERENCED_PARAMETER ( bSubItem );
+
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ if ( wEvent == WM_DLMDBCLK ) {
+ WM_ShowWaitCursor( TRUE );
+ LOG_ViewFile( pLogItem );
+ WM_ShowWaitCursor( FALSE );
+ }
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ return( NULL ) ; // Return value unused.
+
+} /* end LOG_SetObjects() */
+
+
+/******************************************************************************
+
+ Name: LOG_GetCurrentTime()
+
+ Description: This function gets the current date and time in
+ a particular format to be used in the header of all
+ log files, viewed or just printed.
+
+ Returns: NULL.
+
+ Notes: Needs to be internationalized.
+
+******************************************************************************/
+
+VOID LOG_GetCurrentTime(
+
+LPSTR szDate, // I/O
+LPSTR szTime ) // I/O
+
+{
+ UI_CurrentDate( szDate ) ;
+ UI_CurrentTime( szTime ) ;
+
+}
+
+
+
+/******************************************************************************
+
+ Name: LOG_ViewFile()
+
+ Description: This function displays a log file in a window.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID LOG_ViewFile (
+
+LOGITEM_PTR pLogItem ) // I - pointer to a log item.
+
+{
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ PDS_WMINFO pdsWinInfo ;
+ UCHAR szMinimizedName[ MAX_UI_RESOURCE_SIZE ] ;
+ DLM_LOGITEM_PTR pDlm ;
+ INT32_PTR pArray ;
+
+
+ // See if there is a log file currently being displayed.
+
+ if ( ghWndLogFileView ) {
+
+ // Is it the same file that has just been requested to be viewed?
+
+ pdsWinInfo = WM_GetInfoPtr ( ghWndLogFileView );
+
+ if ( strcmp ( WMDS_GetWinTitle( pdsWinInfo ), (LPSTR)pLogItem->szDateTime ) == 0 ) {
+
+ // Just bring the log file view window to the foreground.
+
+ WM_DocActivate( ghWndLogFileView ) ;
+ return ;
+
+ } else {
+
+ // Blow Away the window.
+
+ WM_Destroy ( ghWndLogFileView );
+ }
+ }
+
+ pDlm = ( DLM_LOGITEM_PTR ) calloc( 1, sizeof( DLM_LOGITEM ) ) ;
+
+ if ( !pDlm ) {
+ return ;
+ }
+
+ L_SetMaxNumOfBlocks( pDlm, 200 ) ;
+ L_SetRecsPerBlock( pDlm, 1000 ) ;
+ L_SetRecsPerTrack( pDlm, 1 ) ;
+ L_SetMaxStringLen( pDlm, 133 ) ;
+ L_SetFont ( pDlm, ghFontLog ) ;
+
+ pArray = ( INT32_PTR) calloc( L_GetMaxNumOfBlocks( pDlm ), sizeof( INT32_PTR ) ) ;
+
+ if ( !pArray ) {
+ return ;
+ }
+
+ L_SetArrayPtr( pDlm, pArray ) ;
+
+ pArray = ( INT32_PTR) calloc( L_GetMaxStringLen( pDlm ), sizeof( CHAR ) ) ;
+
+ if ( !pArray ) {
+ return ;
+ }
+
+ L_GetBuffer( pDlm ) = (LPSTR) pArray ;
+
+ // Build the full path name for log file.
+
+ wsprintf ( L_GetFileName( pDlm ) , TEXT("%s%s"), CDS_GetUserDataPath (),
+ (((LOGITEM_PTR)pLogItem)->szFileName ) );
+
+ strcpy( (LPSTR)mwszCurrentViewLogFile, L_GetFileName( pDlm ) ) ;
+ // Create a log file view window.
+
+ // Read in the log file.
+
+ if ( ( LOG_BuildLogViewList ( pDlm ) ) != SUCCESS ) {
+ LOG_Refresh( );
+ return;
+ }
+
+ LOG_BuildTitle ( pLogItem ) ;
+
+ // Create the log view window.
+
+ pdsWinInfo = (PDS_WMINFO)( calloc ( 1, sizeof ( DS_WMINFO ) ) );
+
+ WMDS_SetWinType ( pdsWinInfo, WMTYPE_LOGVIEW );
+ WMDS_SetWinClosable ( pdsWinInfo, FALSE );
+ WMDS_SetCursor ( pdsWinInfo, RSM_CursorLoad ( ID(IDRC_ARROW) ) );
+ WMDS_SetIcon ( pdsWinInfo, RSM_IconLoad ( IDRI_LOGFILES ) );
+ WMDS_SetRibbon ( pdsWinInfo, ghRibbonMain );
+ WMDS_SetAppInfo ( pdsWinInfo, (Q_HEADER_PTR) pDlm );
+
+ RSM_StringCopy( IDS_LOGVIEWMINWINDOWNAME, (LPSTR)szMinimizedName, MAX_UI_RESOURCE_LEN ) ;
+
+ ghWndLogFileView = WM_Create ( WM_MDISECONDARY | WM_VIEWWIN ,
+ (LPSTR)pLogItem->szDateTime,
+ (LPSTR)szMinimizedName,
+ WM_DEFAULT,
+ WM_DEFAULT,
+ WM_DEFAULT,
+ WM_DEFAULT,
+ pdsWinInfo );
+
+ WM_SetTitle ( ghWndLogFileView, (LPSTR)pLogItem->szDateTime ) ;
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+} /* end LOG_ViewFile() */
+
+
+/******************************************************************************
+
+ Name: LOG_ClearBlocks
+
+ Description: This function will free the blocks allocated.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+
+VOID LOG_ClearBlocks(
+
+DLM_LOGITEM_PTR pDlm ) // I - Pointer to information
+
+{
+ int i ;
+
+ for(i=0; i<L_GetMaxNumOfBlocks( pDlm ); i++) {
+
+ if ( L_GetBlockPtr( pDlm, i ) ) {
+ free( (LPSTR) L_GetBlockPtr( pDlm, i ) ) ;
+ }
+
+ L_SetBlockPtr( pDlm, i, /*(INT32_PTR) NULL*/ 0 ) ;
+ }
+
+ L_SetNumOfUsedBlocks( pDlm, 0 ) ;
+ L_SetTotalLines( pDlm, 0 ) ;
+ L_SetVisibleTopLine( pDlm, 0 ) ;
+ L_SetTrackMax( pDlm, 0 ) ;
+ L_SetVscrollMax( pDlm, 0 ) ;
+ L_SetVscrollPos( pDlm, 0 ) ;
+ L_SetHscrollMax( pDlm, 0 ) ;
+ L_SetHscrollPos( pDlm, 0 ) ;
+}
+
+
+/******************************************************************************
+
+ Name: LOG_BuildTitle
+
+ Description: This function build title for window.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID LOG_BuildTitle (
+
+LOGITEM_PTR pLogItem ) // I - pointer to a log item.
+
+{
+
+ CHAR szDate [ MAX_UI_TIME_SIZE ];
+ CHAR szTime [ MAX_UI_TIME_SIZE ] ;
+ CHAR szLoggedOn [ MAX_UI_SMALLRES_SIZE ] ;
+ CHAR szAt [ MAX_UI_SMALLRES_SIZE ] ;
+ CHAR szFor [ MAX_UI_SMALLRES_SIZE ] ;
+
+ // Read in resources.
+
+ RSM_StringCopy( IDS_LOGLOGGEDON, szLoggedOn, MAX_UI_SMALLRES_LEN ) ;
+ RSM_StringCopy( IDS_LOGSTRINGAT, szAt, MAX_UI_SMALLRES_LEN ) ;
+ RSM_StringCopy( IDS_LOGFILENAMEPREFIX, szFor, MAX_UI_SMALLRES_LEN ) ;
+
+ // Get International date and time.
+
+ UI_IntToDate( szDate, LOG_GetItemDate ( pLogItem ) ) ;
+ UI_IntToTime( szTime, LOG_GetItemTime ( pLogItem ) ) ;
+
+ wsprintf( (LPSTR)pLogItem->szDateTime,
+ TEXT("%s%11s %s %-15s"),
+ szLoggedOn ,
+ szDate ,
+ szAt ,
+ szTime
+ ) ;
+
+}
+
+
+/******************************************************************************
+
+ Name: LOG_BuildLogViewList()
+
+ Description: This function builds a list of pointers to records
+ in a log file.
+
+ Returns: SUCCESS if Ok.
+ FAILURE if not Ok.
+
+******************************************************************************/
+
+INT LOG_BuildLogViewList (
+
+DLM_LOGITEM_PTR pDlm ) // I - Item in the list.
+
+{
+
+ FILE *fp ;
+ LPSTR pszLine ;
+ LONG lLastSeekPos ;
+ INT nStatus ;
+ INT index = 0 ;
+ INT nLen ;
+ INT32_PTR pCurBlock ;
+ CHAR szString[ MAX_UI_SMALLRES_SIZE ] ;
+
+
+ pszLine = L_GetBuffer( pDlm ) ;
+
+ nStatus = SUCCESS ;
+
+ // Turn the cursor to wait .
+ WM_ShowWaitCursor( TRUE ) ;
+
+ // Update status line.
+ RSM_StringCopy( IDS_LOGSCANNINGFILE, szString, MAX_UI_SMALLRES_LEN ) ;
+ STM_DrawText( szString ) ;
+
+ // Open a file.
+
+ L_SetFilePtr( pDlm, UNI_fopen ( L_GetFileName( pDlm ), _O_RDONLY ) ) ;
+
+ if ( L_GetFilePtr( pDlm ) ) {
+
+ fp = L_GetFilePtr( pDlm ) ;
+
+ // Record last relative position in file .
+
+ lLastSeekPos = ftell( fp ) ;
+
+ while ( TRUE ) {
+
+ if ( fgets( pszLine, (L_GetMaxStringLen( pDlm )-1), fp ) == NULL ) {
+ if ( feof( fp ) ) {
+ if ( ferror( fp ) ) {
+ nStatus = FAILURE ;
+ } else {
+ nStatus = SUCCESS ;
+ }
+
+ fclose( fp ) ;
+ L_SetFilePtr( pDlm, NULL ) ;
+ break ;
+ }
+ } else {
+
+
+ if ( L_NewBlock( pDlm ) ) {
+
+
+ WM_MultiTask() ;
+
+ // New Block needed
+
+ pCurBlock = ( INT32_PTR) calloc( L_GetRecsPerBlock( pDlm ), sizeof( LONG ) ) ;
+
+ if ( L_GetMaxNumOfBlocks ( pDlm ) == L_GetNumOfUsedBlocks( pDlm ) ) {
+
+ // Maximum number of blocks limit hit.
+
+ fclose( fp ) ;
+ L_SetFilePtr( pDlm, NULL ) ;
+ nStatus = FAILURE ;
+ break ;
+ }
+
+ // Leave room for header lines in array.
+
+ if ( lLastSeekPos == 0L ) {
+ index = LOG_NUMHEADERLINES ;
+ L_GetTotalLines( pDlm ) += LOG_NUMHEADERLINES ;
+ } else {
+ index = 0 ;
+ }
+
+ // pCurBlock is the address of new block .
+
+ L_SetBlockPtr( pDlm, L_GetNumOfUsedBlocks( pDlm ), ( (LONG) pCurBlock ) ) ;
+
+ L_GetNumOfUsedBlocks( pDlm )++ ;
+
+ }
+
+ // Set Maximum length if possible .
+
+ nLen = strlen( pszLine ) ;
+
+ if ( nLen > L_GetMaxWidth( pDlm ) ) {
+ L_GetMaxWidth( pDlm ) = nLen ;
+ }
+
+ // Save relative offset in block.
+
+ pCurBlock[ index++ ] = lLastSeekPos ;
+
+ // Increment line counter.
+
+ L_GetTotalLines( pDlm )++ ;
+
+ // LOG_MAXRECS is the current limit.
+
+ if ( L_GetTotalLines( pDlm ) == (LOG_MAXRECS+1+LOG_NUMHEADERLINES) ) {
+
+ CHAR szFormat[ MAX_UI_RESOURCE_SIZE ] ;
+ CHAR szString[ MAX_UI_RESOURCE_SIZE ] ;
+ CHAR szApp [ MAX_UI_RESOURCE_SIZE ] ;
+ LPSTR pString ;
+
+ // Restore the cursor.
+ WM_ShowWaitCursor( FALSE ) ;
+
+ // This log file contains more than %ld lines.
+
+ RSM_StringCopy( IDS_LOGMAXLINES, szFormat, MAX_UI_RESOURCE_LEN ) ;
+ wsprintf( szString, szFormat, (LONG) LOG_MAXRECS );
+
+ // Maynstream supports viewing the first %ld lines.
+
+ RSM_StringCopy( IDS_LOGMAXSUPPORT, szFormat, MAX_UI_RESOURCE_LEN ) ;
+ RSM_StringCopy( IDS_APPNAME, szApp, MAX_UI_RESOURCE_LEN ) ;
+ pString = szString + strlen( szString ) ;
+ strcat( pString, TEXT("\n") );
+ wsprintf( pString, szFormat, szApp, (LONG) LOG_MAXRECS ) ;
+
+ nStatus = WM_MsgBox( ID(IDS_LOGVIEWMINWINDOWNAME), szString,
+ (WORD)WMMB_OK, (WORD)WMMB_ICONINFORMATION ) ;
+
+ nStatus = FAILURE ;
+ fclose( fp ) ;
+ L_SetFilePtr( pDlm, NULL ) ;
+ nStatus = FAILURE ;
+ L_GetTotalLines( pDlm )-- ;
+
+ break ;
+ }
+
+
+ // Record last relative position in file .
+
+ lLastSeekPos = ftell( fp ) ;
+
+ }
+ }
+
+ // Set the number of tracks.
+
+ L_GetTrackMax( pDlm ) = ( INT ) (L_GetTotalLines( pDlm ) / L_GetRecsPerTrack( pDlm ) ) ;
+
+ if ( L_GetTrackMax( pDlm ) ) {
+
+ if ( L_GetTotalLines( pDlm ) % L_GetRecsPerTrack( pDlm ) ) {
+ L_GetTrackMax( pDlm ) -- ;
+ }
+ }
+
+ } else {
+
+ // Problem opening log file .
+
+
+ CHAR szFormat[ MAX_UI_RESOURCE_SIZE ] ;
+ CHAR szString[ MAX_UI_RESOURCE_SIZE ] ;
+
+ // Restore the cursor.
+ WM_ShowWaitCursor( FALSE ) ;
+
+ RSM_StringCopy( IDS_CANTOPEN, szFormat, MAX_UI_RESOURCE_LEN ) ;
+ wsprintf( szString, szFormat, L_GetFileName( pDlm ) );
+ nStatus = WM_MsgBox( ID(IDS_LOGVIEWMINWINDOWNAME), szString,
+ (WORD)WMMB_OK, (WORD)WMMB_ICONINFORMATION ) ;
+ nStatus = FAILURE ;
+ }
+
+
+ // Restore the cursor.
+
+ WM_ShowWaitCursor( FALSE ) ;
+
+ RSM_StringCopy( IDS_READY, szString, MAX_UI_SMALLRES_LEN ) ;
+ STM_DrawText( szString ) ;
+
+ return( nStatus ) ;
+
+}
+
+/******************************************************************************
+
+ Name: LOG_GetViewHdrLine()
+
+ Description: This function builds the string for view header lines.
+
+
+ Returns: pszResult - string.
+
+ Notes: Four lines are currently implemented.
+
+******************************************************************************/
+
+
+VOID LOG_GetViewHdrLine(
+
+DLM_LOGITEM_PTR pDlm , // I - pointer to app area
+INT i , // I - Index of header line
+LPSTR pszResult ) // I/O - Buffer
+
+{
+
+ /*****************************************************************
+ The lines are defined as follows:
+
+ File Name : MAYNxxxx.LOG line 0
+ Date: mm/dd/yy line 1
+ Time: hh:mm[a,p]m line 2
+ line 3
+ ******************************************************************/
+
+
+ CHAR szDate[ MAX_UI_DATE_SIZE ] ;
+ CHAR szTime[ MAX_UI_TIME_SIZE ] ;
+ CHAR szBuf [ MAX_UI_RESOURCE_SIZE ] ;
+ CHAR szBuf1[ MAX_UI_RESOURCE_SIZE ] ;
+ LPSTR pszString ;
+
+ switch ( i ) {
+
+ case 0:
+
+ // File Name : MAYNxxxx.LOG
+
+ RSM_StringCopy( IDS_LOGHEADERFILENAME,
+ szBuf, MAX_UI_RESOURCE_LEN ) ;
+
+ if ( pszString = strrchr( L_GetFileName( pDlm ) , TEXT('\\') ) ) {
+ strcpy( szBuf1, ++pszString ) ;
+ } else {
+ strcpy( szBuf1, L_GetFileName( pDlm ) ) ;
+ }
+
+ // Save the full path name for print manager.
+
+ strcpy( (LPSTR)mwszCurrentViewLogFile, L_GetFileName( pDlm ) ) ;
+ wsprintf( pszResult, szBuf, szBuf1 ) ;
+
+ break ;
+
+ case 1:
+
+ /* Date : mm/dd/yy */
+
+ LOG_GetCurrentTime ( szDate, szTime ) ;
+ RSM_StringCopy ( IDS_LOGHEADERDATE, szBuf, MAX_UI_RESOURCE_LEN ) ;
+ wsprintf( pszResult, szBuf, szDate ) ;
+
+ break ;
+
+
+ case 2:
+
+
+ /* Time : hh:mm */
+
+ LOG_GetCurrentTime ( szDate, szTime ) ;
+ RSM_StringCopy( IDS_LOGHEADERTIME, szBuf, MAX_UI_RESOURCE_LEN ) ;
+ wsprintf( pszResult, szBuf, szTime ) ;
+
+ break ;
+
+ case 3:
+ default :
+
+ /* blank line */
+
+ strcpy( pszResult,TEXT("") ) ;
+
+ }
+
+}
+
diff --git a/private/utils/ntbackup/src/logoproc.c b/private/utils/ntbackup/src/logoproc.c
new file mode 100644
index 000000000..e3cff4697
--- /dev/null
+++ b/private/utils/ntbackup/src/logoproc.c
@@ -0,0 +1,257 @@
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+RCG
+
+ Name: logoproc.c
+
+ Description: This file contains the functions for processing messages
+ sent by Windows to the LOGO window.
+
+
+ The following routines are in this module:
+
+ WM_LogoWndProc
+
+ $Log: G:\ui\logfiles\logoproc.c_v $
+
+ Rev 1.17 05 Aug 1993 17:31:06 GLENN
+Increased size of text display on logo window.
+
+ Rev 1.16 03 Aug 1993 19:46:32 MARINA
+updated param type cast
+
+ Rev 1.15 28 Jul 1993 17:27:16 MARINA
+enable c++
+
+ Rev 1.14 12 Apr 1993 10:16:38 CHUCKB
+Fixed adjustment coefficients placement of version text.
+
+ Rev 1.13 01 Nov 1992 16:01:24 DAVEV
+Unicode changes
+
+ Rev 1.12 07 Oct 1992 15:12:02 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.11 04 Oct 1992 19:38:38 DAVEV
+Unicode Awk pass
+
+ Rev 1.10 18 May 1992 09:00:48 MIKEP
+header
+
+ Rev 1.9 16 Apr 1992 11:44:18 JOHNWT
+removed beta/er info
+
+ Rev 1.8 15 Apr 1992 18:25:04 GLENN
+updated for new bmp
+
+ Rev 1.7 09 Apr 1992 11:33:48 GLENN
+Using exe version and eng release version stamps in display now.
+
+ Rev 1.6 30 Mar 1992 18:04:38 GLENN
+Added support for discarding logo bitmap when done.
+
+ Rev 1.5 23 Mar 1992 14:08:00 JOHNWT
+updated to new logo
+
+ Rev 1.4 19 Mar 1992 16:44:16 GLENN
+Updated.
+
+ Rev 1.3 18 Mar 1992 09:16:12 GLENN
+Updated width of text area.
+
+ Rev 1.2 17 Mar 1992 18:29:40 GLENN
+Pulling strings from resources.
+
+ Rev 1.1 10 Mar 1992 16:31:32 GLENN
+Still working on this one...
+
+ Rev 1.0 09 Mar 1992 09:00:58 GLENN
+Initial revision.
+
+
+
+******************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+#define ADJ_TOP 170
+#define ADJ_BOTTOM 10
+#define ADJ_LEFT 232
+#define ADJ_RIGHT 10
+
+static HWND mwhWndLogo = (HWND)0;
+static BOOL mwfRegistered = FALSE;
+
+
+/******************************************************************************
+
+ Name: WM_LogoWndProc()
+
+ Description: This function is called internally by Windows when events
+ occur relating to the LOGO window.
+
+ Returns: A WINRELULT
+
+******************************************************************************/
+
+WINRESULT APIENTRY WM_LogoWndProc (
+
+HWND hWnd, // I - window handle of the list box
+MSGID msg, // I - message
+MP1 mp1, // I - another message parameter
+MP2 mp2 ) // I - yet another message parameter
+
+
+{
+ switch (msg) {
+
+ case WM_CREATE:
+
+ DM_CenterDialog ( hWnd );
+ break;
+
+ case WM_PAINT: { /* Begin Block */
+
+ HDC hDC;
+ PAINTSTRUCT ps;
+
+ HANDLE hSaveObject;
+ RECT rcInfo;
+
+ CHAR szMessage[MAX_UI_RESOURCE_SIZE];
+
+ hDC = BeginPaint (hWnd, &ps);
+
+ RSM_Sprintf ( szMessage, ID(IDS_STARTUPTEXT), gszExeVer );
+
+ // Set Font.
+
+ hSaveObject = SelectObject ( hDC, ghFontStatus );
+
+ // Set backgrnd to transparent and text to black
+
+ SetBkMode ( hDC, TRANSPARENT );
+ SetTextColor ( hDC, RGB( 0, 0, 0 ) );
+
+ // get the rectangle and then adjust for the text portion
+
+ GetClientRect ( hWnd, &rcInfo );
+
+ rcInfo.top += ADJ_TOP;
+ rcInfo.bottom -= ADJ_BOTTOM;
+ rcInfo.left += ADJ_LEFT;
+ rcInfo.right -= ADJ_RIGHT;
+
+ // draw the bitmap and then the text on top
+
+ RSM_BitmapDraw ( IDRBM_LOGO, 0, 0, 0, 0, hDC );
+
+ DrawText ( hDC,
+ szMessage,
+ -1,
+ &rcInfo,
+ DT_RIGHT
+ );
+
+ SelectObject( hDC, hSaveObject );
+
+ EndPaint ( hWnd, &ps );
+
+ return FALSE;
+
+ } /* End Block */
+
+ case WM_DESTROY:
+
+ mwhWndLogo = (HWND)NULL;
+ break;
+
+ } /* end switch */
+
+ return DefWindowProc ( hWnd, msg, mp1, mp2 );
+
+} /* end WM_LogoWndProc() */
+
+
+VOID WM_LogoShow ( VOID )
+
+{
+
+ WNDCLASS wc;
+ INT nWidth;
+ INT nHeight;
+
+ // If the frame is not minimized and we have not already registered
+ // the class, do the logo thing.
+
+ if ( ! WM_IsMinimized ( ghWndFrame ) && ! mwfRegistered ) {
+
+ wc.style = 0;
+ wc.lpfnWndProc = WM_LogoWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = ghInst;
+ wc.hIcon = RSM_IconLoad ( IDRI_WNTRPARK );
+ wc.hCursor = RSM_CursorLoad ( ( LPSTR )IDC_ARROW );
+ wc.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE + 1);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = WMCLASS_LOGO;
+
+ if ( ! RegisterClass( &wc ) ) {
+ return;
+ }
+
+ mwfRegistered = TRUE;
+ }
+ else {
+ return;
+ }
+
+ // Load the logo bitmap and get it's size.
+
+ RSM_BitmapLoad ( IDRBM_LOGO, RSM_MAGICCOLOR );
+ RSM_GetBitmapSize ( IDRBM_LOGO, ( LPINT )&nWidth, ( LPINT )&nHeight );
+
+ nWidth += 2;
+ nHeight += 2;
+
+ // create the window
+
+ mwhWndLogo = CreateWindow ( WMCLASS_LOGO, // class name
+ TEXT("\0"), // window title
+ WMSTYLE_LOGO, // window style
+ 200, // starting x position
+ 100, // starting y position
+ nWidth, // window width
+ nHeight, // window height
+ ghWndFrame, // parent window handle
+ (HMENU)NULL,
+ ghInst, // instance (global)
+ (LPSTR)NULL // window creation parameter
+ );
+
+ WM_MultiTask ();
+
+} /* end WM_LogoShow() */
+
+
+VOID WM_LogoDestroy ( VOID )
+
+{
+ if ( mwhWndLogo ) {
+
+ DestroyWindow ( mwhWndLogo );
+ WM_MultiTask ();
+ UnregisterClass ( WMCLASS_LOGO, ghInst );
+ mwfRegistered = FALSE;
+ RSM_BitmapFree ( IDRBM_LOGO );
+ }
+
+
+} /* end WM_LogoDestroy() */
+
+
diff --git a/private/utils/ntbackup/src/lp_tdir.c b/private/utils/ntbackup/src/lp_tdir.c
new file mode 100644
index 000000000..aec676e4d
--- /dev/null
+++ b/private/utils/ntbackup/src/lp_tdir.c
@@ -0,0 +1,494 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: lp_tdir.c
+
+ Description: this file contains the entry points for the
+ tape directory routines.
+
+ $Log: N:/LOGFILES/LP_TDIR.C_V $
+
+ Rev 1.23 14 Jan 1993 13:33:16 STEVEN
+added stream_id to error message
+
+ Rev 1.22 23 Jul 1992 16:45:02 STEVEN
+fix warnings
+
+ Rev 1.21 23 Jul 1992 12:08:02 STEVEN
+fix warnings
+
+ Rev 1.20 21 May 1992 17:22:34 TIMN
+Added corrupt block filename length
+
+ Rev 1.19 14 May 1992 16:11:38 STEVEN
+corrupt -> corrupt_bit
+
+ Rev 1.18 13 May 1992 12:27:20 TIMN
+Removed used references to tapename and backup_set_name for TPOS structs.
+
+ Rev 1.17 13 May 1992 11:59:58 STEVEN
+40 format changes
+
+ Rev 1.16 24 Feb 1992 10:03:10 GREGG
+Call TF_OpenTape at beginning of loop, Open/Close Set in loop, CloseTape at end.
+
+ Rev 1.15 19 Feb 1992 16:01:28 GREGG
+Added vcb_only parameter to call to TF_OpenSet.
+
+ Rev 1.14 04 Feb 1992 21:42:02 GREGG
+Changed parameters in calls to TF_AllocateTapeBuffers and TF_FreeTapeBuffers.
+
+ Rev 1.13 22 Jan 1992 10:20:28 STEVEN
+fix warnings for WIN32
+
+ Rev 1.0 22 Jan 1992 10:17:40 STEVEN
+fix warnings for WIN32
+
+ Rev 1.12 13 Dec 1991 15:21:48 GREGG
+SKATEBOARD - Initial Integration.
+
+ Rev 1.11 06 Nov 1991 19:24:50 GREGG
+BIGWHEEL - 8200sx - Get cat_enabled from the BE config.
+
+ Rev 1.10 28 Oct 1991 13:07:16 GREGG
+BIGWHEEL - Re-switch after calls to ProcessEOM.
+
+ Rev 1.9 18 Oct 1991 16:25:12 STEVEN
+added parm for restore over exist prompt
+
+ Rev 1.8 17 Oct 1991 01:53:58 ED
+BIGWHEEL - 8200sx - Initial integration.
+
+ Rev 1.7 24 Jul 1991 17:42:30 STEVEN
+lp was not set up
+
+ Rev 1.6 22 Jul 1991 10:57:14 DAVIDH
+Corrected type mismatch warnings.
+
+ Rev 1.5 21 Jun 1991 09:33:12 STEVEN
+new config unit
+
+ Rev 1.4 30 May 1991 09:10:16 STEVEN
+bsdu_err.h no longer exists
+
+ Rev 1.3 28 May 1991 10:49:06 STEVEN
+use MAYN_MEM instead of MAYN_OS2
+
+ Rev 1.2 24 May 1991 13:15:18 STEVEN
+updates from BSDU redesign
+
+ Rev 1.1 15 May 1991 09:35:08 DAVIDH
+Cleared up Watcom compiler warnings for NLM.
+
+ Rev 1.0 09 May 1991 13:38:02 HUNTER
+Initial revision.
+
+**/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "std_err.h"
+#include "queues.h"
+#include "beconfig.h"
+#include "msassert.h"
+#include "tbe_defs.h"
+#include "tbe_err.h"
+#include "bsdu.h"
+#include "fsys.h"
+#include "tflproto.h"
+#include "tfldefs.h"
+#include "loops.h"
+#include "loop_prv.h"
+#include "lis.h"
+/**/
+/**
+
+ Name: LP_StartTapeDirectory()
+
+ Description: this routine starts a tape directory operation.
+
+ Modified: 5/24/1991 12:21:43
+
+ Returns: tape backup engine error.
+
+ Notes: none
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 LP_StartTapeDirectory(
+TAPE_DIR_PTR tape_dir_ptr, /* I - Tape directory interface structure */
+LIS_PTR lis_ptr, /* I - Loop interface structure */
+INT32 tid, /* I - tape Id */
+INT16 tno, /* I - tape number */
+INT16 bno, /* I - backup set number */
+THW_PTR tdrv_list ) /* I - Specifies the tape drive */
+{
+ BSD_PTR bsd_ptr ;
+ TFL_OPBLK pb ;
+ DBLK_PTR dblk_ptr ;
+ INT16 return_status = SUCCESS ;
+ UINT16 mem_save ;
+ UINT16 max_buffs ;
+ UINT16 buff_size ;
+ INT16 status ;
+ LP_ENV_PTR lp ;
+ BE_CFG_PTR cfg ;
+
+ bsd_ptr = BSD_GetFirst( lis_ptr->bsd_list ) ;
+ lis_ptr->curr_bsd_ptr = bsd_ptr ;
+
+ cfg = BSD_GetConfigData( bsd_ptr ) ;
+
+ /* Allocate the loop environment structure */
+ if( ( tape_dir_ptr->lp = ( LP_ENV_PTR )calloc( 1, sizeof( LP_ENV ) ) ) == NULL ) {
+
+ /* we cannot use macro because it relies on the lp structure */
+ lis_ptr->message_handler( MSG_TBE_ERROR, lis_ptr->pid, bsd_ptr, NULL, NULL, LP_OUT_OF_MEMORY_ERROR, NULL, NULL ) ;
+
+ return LP_OUT_OF_MEMORY_ERROR ;
+
+ }
+
+ lp = ( LP_ENV_PTR )tape_dir_ptr->lp ;
+
+ /* allocate DBLKs */
+ if( ( dblk_ptr = ( DBLK_PTR )calloc( 3, sizeof( DBLK ) ) ) == NULL ) {
+
+ /* Set this to NULL so we do not attempt to free it in LP_END... */
+ lp->rr.vcb_ptr = NULL ;
+
+ LP_MsgError( lis_ptr->pid, bsd_ptr, NULL, NULL, LP_OUT_OF_MEMORY_ERROR, NULL, NULL, 0L ) ;
+
+ /* Free local allocations */
+ free( tape_dir_ptr->lp ) ;
+
+ return LP_OUT_OF_MEMORY_ERROR ;
+
+ }
+ else {
+ /* Set up the loop environment structure */
+ /* set up the DBLK_PTRs in the Request/Reply structure */
+ lp->rr.vcb_ptr = dblk_ptr ;
+ lp->rr.ddb_ptr = dblk_ptr + 1 ;
+ lp->saved_ddb = dblk_ptr + 1 ;
+ lp->rr.fdb_ptr = dblk_ptr + 2 ; /* ASSUMPTION : */
+ lp->rr.idb_ptr = dblk_ptr + 2 ; /* no FS has both FDB & IDB */
+ lp->curr_ddb = &lp->dblk1 ;
+ lp->curr_blk = &lp->dblk2 ;
+ lp->empty_blk = &lp->dblk3 ;
+ lp->blk_is_empty = TRUE ;
+ lp->lis_ptr = lis_ptr ;
+ lp->tpos.reference = (UINT32)lis_ptr;
+ }
+
+ /* allocate buffers for operation */
+
+ mem_save = BEC_GetReserveMem( cfg ) ;
+ max_buffs = BEC_GetMaxTapeBuffers( cfg ) ;
+ buff_size = BEC_GetTFLBuffSize( cfg ) ;
+
+ return_status = TF_AllocateTapeBuffers( mem_save, max_buffs, buff_size ) ;
+
+ if( return_status != SUCCESS ) {
+
+ LP_MsgError( lp->lis_ptr->pid, bsd_ptr, NULL, &lp->tpos, LP_OUT_OF_MEMORY_ERROR, NULL, NULL, 0L ) ;
+
+ /* Free local allocations */
+ free( dblk_ptr ) ;
+ free( tape_dir_ptr->lp ) ;
+
+ return LP_OUT_OF_MEMORY_ERROR ;
+
+ }
+
+ if( ( return_status = FS_OpenFileSys( &lp->curr_fsys, GENERIC_DATA, cfg ) ) == OUT_OF_MEMORY ) {
+
+ LP_MsgError( lp->lis_ptr->pid, bsd_ptr, NULL, &lp->tpos, LP_OUT_OF_MEMORY_ERROR, NULL, NULL, 0L ) ;
+
+ /* Deinit operation buffers */
+ if( ( status = TF_FreeTapeBuffers( ) ) != SUCCESS ) {
+ LP_MsgError( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos, status, NULL, NULL, 0L ) ;
+ }
+
+ /* Free local allocations */
+ free( dblk_ptr ) ;
+ free( lp ) ;
+
+
+ return( return_status ) ;
+
+ }
+
+ tape_dir_ptr->curr_fsys = lp->curr_fsys ;
+ tape_dir_ptr->first_time = TRUE ;
+ tape_dir_ptr->last_time = FALSE ;
+ tape_dir_ptr->valid_save_block = FALSE ;
+ lp->rr.filter_to_use = TF_KEEP_ALL_DATA ; /* to permit keystroke processing */
+
+ /* set up for tape positioning */
+ pb.tape_position = &lp->tpos ;
+ pb.tape_position->tape_id = tid ;
+ pb.tape_position->tape_seq_num = tno ;
+ pb.tape_position->backup_set_num = bno ;
+ pb.tape_position->reference = ( UINT32 )NULL ;
+ pb.tape_position->UI_TapePosRoutine = lis_ptr->tape_pos_handler ;
+ pb.rewind_sdrv = FALSE ;
+ pb.sdrv = tdrv_list ;
+ pb.perm_filter = TF_KEEP_ALL_DATA ; /* to permit keystroke processing */
+ pb.attributes = 0L ;
+ pb.fsh = lp->curr_fsys ;
+ pb.mode = TF_READ_OPERATION ;
+ pb.ignore_clink = FALSE ;
+ pb.wrt_format = 0 ;
+ pb.idle_call = NULL ;
+ pb.cat_enabled = (BOOLEAN)(BEC_GetCatalogLevel( cfg ) != CATALOGS_NONE) ;
+
+ /* Now open the backup set */
+ lp->set_opened = FALSE ;
+ if( ( return_status = TF_OpenTape( &pb.channel, pb.sdrv, pb.tape_position ) ) == SUCCESS ) {
+ lp->set_opened = TRUE ;
+ return_status = TF_OpenSet( &pb, FALSE ) ;
+ }
+ lp->channel = pb.channel ;
+
+ /* Need to set up the tape directory pointer to point */
+ /* to the loop environment structure */
+
+ if( return_status == SUCCESS ) {
+
+ lp->rr.cur_dblk = dblk_ptr ;
+ return_status = LP_StartTPEDialogue( lp, FALSE ) ;
+
+ }
+
+ return( return_status ) ;
+}
+/**/
+/**
+
+ Name: LP_EndTapeDirectory()
+
+ Description: this routine ends a tape directory
+
+ Modified: 5/24/1991 12:37:1
+
+ Returns: tape backup engine error.
+
+ Notes: none
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+INT16 LP_EndTapeDirectory(
+TAPE_DIR_PTR tape_dir_ptr, /* I - Tape directory handle */
+BOOLEAN tf_finish_needed ) /* I - TRUE if abort contition */
+{
+ INT16 return_status = SUCCESS ;
+ INT16 status = SUCCESS ;
+ LP_ENV_PTR lp ;
+
+ /* Get loop environment structure */
+ lp = ( LP_ENV_PTR )tape_dir_ptr->lp ;
+
+ /* If we did not run out of memory */
+ if( lp ) {
+
+ if( tf_finish_needed ) {
+ LP_FinishedOper( lp ) ;
+ }
+
+ /* close off the tape format layer */
+ if( lp->set_opened ) {
+ TF_CloseSet( lp->channel, NULL ) ;
+ }
+ TF_CloseTape( lp->channel ) ;
+
+ /* Deinit operation buffers */
+ if( ( return_status = TF_FreeTapeBuffers( ) ) != SUCCESS ) {
+ LP_MsgError( lp->lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, NULL, &lp->tpos, return_status, NULL, NULL, 0L ) ;
+ }
+
+ if( ( status = FS_CloseFileSys( lp->curr_fsys ) ) != SUCCESS ) {
+ msassert( status == SUCCESS ) ;
+ }
+
+ /* Free local allocations */
+ if( lp->rr.vcb_ptr != NULL ) {
+ free( lp->rr.vcb_ptr ) ;
+ }
+ free( lp ) ;
+ }
+
+ return( return_status ) ;
+}
+/**/
+/**
+
+ Name: LP_ReadTape()
+
+ Description: this routine reads a block from the tape
+
+ Modified: 7/26/1989
+
+ Returns: tape backup engine error
+
+ Notes: none
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 LP_ReadTape(
+TAPE_DIR_PTR tape_dir_ptr, /* I - tape directory handle */
+BOOLEAN *valid_blk, /* O - TRUE if block returne is valid */
+DBLK_PTR dblk ) /* O - Where to copy the dblk */
+{
+ INT16 return_status = SUCCESS ;
+ CHAR crrpt_blk_fname[ 13 ] ;
+ INT16 crrpt_blk_fname_leng ; /* length of corrupt block filename */
+ GEN_FDB_DATA gfdb_data ;
+ LP_ENV_PTR lp ;
+ INT16 msg_err_stat ;
+ BOOLEAN done = FALSE ;
+
+ /* Get loop environment structure */
+ lp = ( LP_ENV_PTR )tape_dir_ptr->lp ;
+
+ if( LP_AbortFlagIsSet( lp->lis_ptr ) ) {
+
+ return TFLE_USER_ABORT ;
+ }
+
+ *valid_blk = FALSE ;
+
+ if( tape_dir_ptr->last_time ) {
+ /* Then we need to send the last block, if there is one */
+ if( tape_dir_ptr->valid_save_block ) {
+ tape_dir_ptr->valid_save_block = FALSE ;
+ *valid_blk = TRUE ;
+ *dblk = *lp->curr_ddb ;
+ }
+ return( return_status ) ;
+ }
+
+ lp->rr.lp_message = LRR_STUFF ;
+ lp->rr.cur_dblk = lp->curr_blk ;
+
+ if( ( return_status = TF_GetNextTapeRequest( &lp->rr ) ) == SUCCESS ) {
+
+ /* This loop is for the EOM case. We call ProcessEOM and it does
+ another GetNextTapeRequest so we need to re-switch on the new
+ tf_message.
+ */
+ while( !done && return_status == SUCCESS ) {
+
+ done = TRUE ;
+
+ switch( lp->rr.tf_message ) {
+
+ case TRR_DATA:
+ lp->rr.buff_used = lp->rr.buff_size ;
+ break ;
+
+ case TRR_DDB:
+ case TRR_IDB:
+
+ /* return saved block if any */
+ if( tape_dir_ptr->valid_save_block ) {
+ *dblk = *lp->curr_ddb ;
+ *valid_blk = TRUE ;
+ *lp->curr_ddb = *lp->curr_blk ;
+ } else {
+
+ /* if no saved block, then return this one */
+ *dblk = *lp->curr_blk ;
+ *valid_blk = TRUE ;
+ }
+ break ;
+
+ case TRR_FDB:
+
+ /* return saved block (if any) */
+ if( tape_dir_ptr->valid_save_block ) {
+ *dblk = *lp->curr_ddb ;
+ *valid_blk = TRUE ;
+ }
+
+ /* simply store the block */
+ tape_dir_ptr->valid_save_block = TRUE ;
+ *lp->curr_ddb = *lp->curr_blk ;
+ break ;
+
+ case TRR_CFDB:
+
+ /* Set the corrupt attribute of the saved block */
+ FS_SetAttribFromDBLK( lp->curr_fsys, lp->curr_ddb,
+ ( FS_GetAttribFromDBLK( lp->curr_fsys, lp->curr_ddb ) | OBJ_CORRUPT_BIT ) ) ;
+ /* and continue */
+ break ;
+
+ case TRR_END:
+ tape_dir_ptr->last_time = TRUE ;
+ /* Check if there is a saved block */
+ if( tape_dir_ptr->valid_save_block ) {
+ *dblk = *lp->curr_ddb ;
+ *valid_blk = TRUE ;
+ tape_dir_ptr->valid_save_block = FALSE ;
+ }
+ break ;
+
+ case TRR_EOM:
+ return_status = LP_ProcessEOM( lp, (UINT16)TRR_EOM ) ;
+ done = FALSE ; /* Switch Again! */
+ break ;
+
+ case TRR_RECV_ERR:
+ lp->rr.tf_message = TRR_FDB ;
+
+ FS_SetDefaultDBLK( lp->curr_fsys, FDB_ID, ( CREATE_DBLK_PTR ) &gfdb_data ) ;
+ gfdb_data.std_data.dblk = lp->rr.cur_dblk ;
+ gfdb_data.std_data.disp_size = U64_Init(0,0) ; /* $$$ literal */
+
+ /* call message handler to provide filename */
+ LP_MsgPrompt( lp->lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, lp->curr_fsys, &lp->tpos,
+ CORRUPT_BLOCK_PROMPT, crrpt_blk_fname, &crrpt_blk_fname_leng ) ;
+
+ gfdb_data.fname = crrpt_blk_fname ;
+ gfdb_data.fname_size = crrpt_blk_fname_leng ;
+ FS_CreateGenFDB( lp->curr_fsys, &gfdb_data ) ;
+ break ;
+
+ case TRR_DATA_END:
+ break ;
+
+ case TRR_FATAL_ERR:
+ msassert( FALSE ) ;
+ break ;
+
+ case TRR_VCB:
+ break ;
+
+ }
+ }
+ }
+ else {
+ if( ( msg_err_stat = LP_MsgError( lp->lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, lp->curr_fsys, &lp->tpos, return_status, NULL, NULL, 0L ) ) != MSG_ACK ) {
+ return( msg_err_stat ) ;
+ }
+ }
+
+ return( return_status ) ;
+
+}
diff --git a/private/utils/ntbackup/src/lp_tens.c b/private/utils/ntbackup/src/lp_tens.c
new file mode 100644
index 000000000..aea851516
--- /dev/null
+++ b/private/utils/ntbackup/src/lp_tens.c
@@ -0,0 +1,239 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: lp_tens.c
+
+ Description: Main loop for tension, erase and security erase
+
+ $Log: N:/LOGFILES/LP_TENS.C_V $
+
+ Rev 1.11 15 Mar 1993 13:50:16 CARLS
+removed START_BACKUP_SET message
+
+ Rev 1.10 12 Mar 1993 13:59:12 CARLS
+added MSG_START_BACKUP_SET message
+
+ Rev 1.9 18 Jan 1993 14:09:40 GREGG
+Changes to allow format command passed to driver through TpErase.
+
+ Rev 1.8 14 Jan 1993 13:33:20 STEVEN
+added stream_id to error message
+
+ Rev 1.7 13 May 1992 12:29:00 TIMN
+Removed used references to tapename and backup_set_name for TPOS structs.
+
+ Rev 1.6 18 Sep 1991 09:59:52 GREGG
+TF_RetensionChannel now called for reten and erase.
+
+ Rev 1.5 24 Jul 1991 15:53:42 DAVIDH
+Cleared up warnings for Watcom.
+
+ Rev 1.4 21 Jun 1991 09:42:32 STEVEN
+new config unit
+
+ Rev 1.3 30 May 1991 09:10:34 STEVEN
+bsdu_err.h no longer exists
+
+ Rev 1.2 24 May 1991 13:16:46 STEVEN
+updates from BSDU redesign
+
+ Rev 1.1 15 May 1991 09:50:10 DAVIDH
+Cleared up type mismatch warning found by Watcom compiler.
+
+
+ Rev 1.0 09 May 1991 13:38:06 HUNTER
+Initial revision.
+
+**/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "queues.h"
+#include "beconfig.h"
+#include "msassert.h"
+#include "tbe_defs.h"
+#include "tbe_err.h"
+#include "bsdu.h"
+#include "fsys.h"
+#include "tflproto.h"
+#include "tfldefs.h"
+#include "loops.h"
+#include "loop_prv.h"
+#include "lis.h"
+#include "get_next.h"
+
+/**/
+/**
+
+ Name: LP_Tension_Tape_Engine
+
+ Description: Performs the various tension / erase operations of a tape
+
+ Modified: 5/24/1991 12:6:6
+
+ Returns: NO_ERR or error code from Tape Format or Loop error code
+
+ Notes:
+
+ See also:
+
+ Declaration:
+
+**/
+INT16 LP_Tension_Tape_Engine(
+LIS_PTR lis_ptr ) /* I - Loop Interface Structure */
+{
+ BSD_PTR bsd_ptr ;
+ TFL_OPBLK pb ;
+ LP_ENV_PTR lp ;
+ INT16 return_status = SUCCESS ;
+ INT16 status ;
+ DBLK_PTR dblk_ptr ;
+ BE_CFG_PTR cfg ;
+
+ bsd_ptr = BSD_GetFirst( lis_ptr->bsd_list ) ;
+
+ cfg = BSD_GetConfigData( bsd_ptr ) ;
+
+ /* Allocate the loop environment structure */
+ if( ( lp = ( LP_ENV_PTR )calloc( 1, sizeof( LP_ENV ) ) ) == NULL ) {
+
+ /* we cannot use macro because it relies on the lp structure */
+ lis_ptr->message_handler( MSG_TBE_ERROR, lis_ptr->pid, bsd_ptr, NULL, NULL, LP_OUT_OF_MEMORY_ERROR, NULL, NULL ) ;
+
+ return LP_OUT_OF_MEMORY_ERROR ;
+
+ }
+
+ /* Set up the loop environment structure */
+ lp->lis_ptr = lis_ptr ;
+ lp->tpos.reference = ( UINT32 )lis_ptr ;
+
+ /* allocate DBLKs */
+ if( ( dblk_ptr = ( DBLK_PTR )calloc( 3, sizeof( DBLK ) ) ) == NULL ) {
+
+ LP_MsgError( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos, LP_OUT_OF_MEMORY_ERROR, NULL, NULL, 0L ) ;
+
+ /* Free local allocations */
+ free( lp ) ;
+
+ return LP_OUT_OF_MEMORY_ERROR ;
+
+ } else {
+ /* set up the DBLK_PTRs in the Request/Reply structure */
+ lp->rr.vcb_ptr = dblk_ptr ;
+ lp->rr.ddb_ptr = dblk_ptr + 1 ;
+ lp->rr.fdb_ptr = dblk_ptr + 2 ; /* ASSUMPTION : */
+ lp->rr.idb_ptr = dblk_ptr + 2 ; /* no FS has both FDB & IDB */
+ }
+
+ /* Set up the loop environment structure */
+
+ if( ( return_status = FS_OpenFileSys( &lp->curr_fsys, GENERIC_DATA, cfg ) ) == OUT_OF_MEMORY ) {
+
+ LP_MsgError( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos, LP_OUT_OF_MEMORY_ERROR, NULL, NULL, 0L ) ;
+
+ /* Free local allocations */
+ free( dblk_ptr ) ;
+ free( lp ) ;
+
+ return LP_OUT_OF_MEMORY_ERROR ;
+
+ }
+ else {
+
+ /* indicate the start of the operation */
+ LP_MsgStartOP( lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos ) ;
+
+ /* set up for tape positioning */
+ pb.tape_position = &lp->tpos ;
+ pb.rewind_sdrv = FALSE ;
+ pb.sdrv = LP_DetermineStartingTPDrv( lis_ptr->oper_type, bsd_ptr, &lp->tpos, lis_ptr->auto_det_sdrv ) ;
+ pb.perm_filter = TF_SKIP_ALL_DATA ;
+ pb.attributes = 0L ;
+ pb.fsh = lp->curr_fsys ;
+ pb.mode = 0 ; /* tape format fills this out */
+ pb.ignore_clink = FALSE ;
+ pb.wrt_format = 0 ;
+ pb.idle_call = NULL ;
+ lp->get_spcl = FALSE ;
+ lp->seq_num = 1 ;
+ lp->start_new_dir = FALSE ;
+ lp->get_first_file = FALSE ;
+ lp->get_next_first_time = FALSE ;
+ lp->curr_blk = &lp->dblk1 ;
+ lp->curr_ddb = &lp->dblk2 ;
+ lp->empty_blk = &lp->dblk3 ;
+ lp->blk_is_empty = FALSE ;
+ lp->send_saved_block = FALSE ;
+ lp->tpos.tape_id = -1 ;
+ lp->tpos.tape_seq_num = -1 ;
+ lp->tpos.backup_set_num = -1 ;
+ lp->tpos.UI_TapePosRoutine = lis_ptr->tape_pos_handler ;
+ lp->rr.filter_to_use = TF_SKIP_ALL_DATA ;
+ lp->channel = pb.channel ;
+
+ switch( lis_ptr->oper_type ) {
+
+ case TENSION_OPER:
+ return_status = TF_RetensionChannel( &pb, TF_RETENSION_READ ) ;
+ break ;
+
+ case TENSION_NO_READ_OPER:
+ return_status = TF_RetensionChannel( &pb, TF_RETENSION_NO_READ ) ;
+ break ;
+
+ case ERASE_OPER:
+ return_status = TF_RetensionChannel( &pb, TF_ERASE_READ ) ;
+ break ;
+
+ case ERASE_NO_READ_OPER:
+ return_status = TF_RetensionChannel( &pb, TF_ERASE_NO_READ ) ;
+ break ;
+
+ case SEC_ERASE_NO_READ_OPER:
+ return_status = TF_RetensionChannel( &pb, TF_ERASE_SEC_NO_READ ) ;
+ break ;
+
+ case SECURITY_ERASE_OPER:
+ return_status = TF_RetensionChannel( &pb, TF_ERASE_SECURITY ) ;
+ break ;
+
+ /* This case is used for Maynard production facility as is specified
+ via the /FM undocumented switch for tension */
+ case ERASE_FMARK_ONLY:
+ return_status = TF_RetensionChannel( &pb, TF_ERASE_FMARK ) ;
+ break ;
+
+ case FORMAT_OPER:
+ return_status = TF_RetensionChannel( &pb, TF_FORMAT_READ ) ;
+ break ;
+
+ }
+
+ if( return_status != SUCCESS ) {
+ /* report error condition */
+ LP_MsgError( lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, return_status, NULL, NULL, 0L ) ;
+ } else {
+ /* log the end of the operation */
+ LP_MsgEndTens( lis_ptr->oper_type ) ;
+ }
+
+ if( ( status = FS_CloseFileSys( lp->curr_fsys ) ) != SUCCESS ) {
+ msassert( status == SUCCESS ) ;
+ }
+ }
+
+ /* indicate the end of the operation */
+ LP_MsgEndOP( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos ) ;
+
+ /* Free local allocations */
+ free( dblk_ptr ) ;
+ free( lp ) ;
+
+ return( return_status ) ;
+
+}
diff --git a/private/utils/ntbackup/src/lpbackup.c b/private/utils/ntbackup/src/lpbackup.c
new file mode 100644
index 000000000..d4d9937c6
--- /dev/null
+++ b/private/utils/ntbackup/src/lpbackup.c
@@ -0,0 +1,301 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: lpbackup.c
+
+ Description: This module contains the entry point for the backup engine.
+
+ $Log: N:/LOGFILES/LPBACKUP.C_V $
+
+ Rev 1.12 14 Jan 1993 13:33:44 STEVEN
+added stream_id to error message
+
+ Rev 1.11 24 Feb 1992 09:54:30 GREGG
+Call TF_OpenTape at beginning of loop, Open/Close Set in loop, CloseTape at end.
+
+ Rev 1.10 04 Feb 1992 21:40:26 GREGG
+Changed parameters in calls to TF_AllocateTapeBuffers and TF_FreeTapeBuffers.
+
+ Rev 1.9 16 Jan 1992 15:45:28 STEVEN
+fix warnings for WIN32
+
+ Rev 1.8 13 Dec 1991 15:25:36 GREGG
+SKATEBOARD - Initial Integration.
+
+ Rev 1.7 06 Nov 1991 19:04:40 GREGG
+BIGWHEEL - 8200sx - Get cat_enabled from the BE config.
+
+ Rev 1.6 23 Aug 1991 17:00:34 STEVEN
+added support for NORMAL/COPY/DIFERENTIAL/INCREMENTAL
+
+ Rev 1.5 21 Jun 1991 09:28:46 STEVEN
+new config unit
+
+ Rev 1.4 30 May 1991 09:12:16 STEVEN
+bsdu_err.h no longer exists
+
+ Rev 1.3 28 May 1991 09:59:38 STEVEN
+use MAYN_MEM instead of MAYN_OS2
+
+ Rev 1.2 24 May 1991 14:42:34 STEVEN
+complete changes for new getnext
+
+ Rev 1.1 23 May 1991 16:19:26 STEVEN
+update for BSD redesign
+
+ Rev 1.0 09 May 1991 13:35:48 HUNTER
+Initial revision.
+
+**/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "queues.h"
+#include "beconfig.h"
+#include "msassert.h"
+#include "tbe_defs.h"
+#include "tbe_err.h"
+#include "bsdu.h"
+#include "fsys.h"
+#include "tflproto.h"
+#include "tfldefs.h"
+#include "loops.h"
+#include "loop_prv.h"
+#include "lis.h"
+#include "vm.h"
+#include "get_next.h"
+
+/**/
+/**
+
+ Name: LP_Backup_Engine()
+
+ Description: this routine orchestrates backups on a volume by volume basis. it is the entry
+ point into the tape backup engine for the backup operation.
+
+ Modified: 5/23/1991 13:9:10
+
+ Returns: SUCCESS or error code from Tape Format or Loop error code
+
+ Notes:
+
+ See also: $/SEE( LP_Restore_Engine(), LP_Verify_Engine() )$
+ $/SEE( LP_Delete_Engine() )$
+
+ Declaration:
+
+**/
+INT16 LP_Backup_Engine(
+LIS_PTR lis_ptr ) /* I - Loop Interface structure */
+{
+ BSD_PTR bsd_ptr ;
+ GENERIC_DLE_PTR dle_ptr ;
+ LP_ENV_PTR lp ;
+ INT16 return_status = SUCCESS ;
+ INT16 status ;
+ UINT16 mem_save ;
+ UINT16 max_buffs ;
+ UINT16 buff_size ;
+ DBLK_PTR dblk_ptr ;
+ UINT16 tfl_open_mode = TF_WRITE_OPERATION ;
+ BE_CFG_PTR cfg ;
+ BOOLEAN tape_opened = FALSE ;
+ INT16 channel_no ;
+ THW_PTR sdrv ;
+
+ bsd_ptr = BSD_GetFirst( lis_ptr->bsd_list ) ;
+
+ msassert( bsd_ptr != NULL ) ;
+
+ lis_ptr->curr_bsd_ptr = bsd_ptr ;
+
+ cfg = BSD_GetConfigData( bsd_ptr ) ;
+ if ( cfg == NULL ) {
+ return OUT_OF_MEMORY ;
+ }
+
+ /* Allocate the loop environment structure */
+ if( ( lp = ( LP_ENV_PTR )calloc( 1, sizeof( LP_ENV ) ) ) == NULL ) {
+
+ /* we cannot use macro because it relies on the lp structure */
+ lis_ptr->message_handler( MSG_TBE_ERROR, lis_ptr->pid, bsd_ptr, NULL, NULL, LP_OUT_OF_MEMORY_ERROR, NULL, NULL ) ;
+
+ return LP_OUT_OF_MEMORY_ERROR ;
+
+ }
+
+ /* Set up the loop environment structure */
+ lp->lis_ptr = lis_ptr ;
+ lp->tpos.reference = ( UINT32 )lis_ptr ;
+
+ /* allocate DBLKs */
+ if( ( dblk_ptr = ( DBLK_PTR )calloc( 4, sizeof( DBLK ) ) ) == NULL ) {
+
+ LP_MsgError( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos, LP_OUT_OF_MEMORY_ERROR, NULL, NULL, 0L ) ;
+
+ /* Free local allocations */
+ free( lp ) ;
+
+ return LP_OUT_OF_MEMORY_ERROR ;
+
+ }
+
+ /* set up the DBLK_PTRs in the Request/Reply structure */
+ lp->rr.vcb_ptr = dblk_ptr ;
+ lp->rr.ddb_ptr = dblk_ptr + 1 ;
+ lp->rr.fdb_ptr = dblk_ptr + 2 ; /* ASSUMPTION : */
+ lp->rr.idb_ptr = dblk_ptr + 2 ; /* no FS has both FDB & IDB */
+ lp->rr.cfdb_ptr = dblk_ptr + 3 ; /* CFDB needed during backup */
+
+ /* allocate CFDB data */
+ if( ( lp->rr.cfdb_data_ptr = ( GEN_CFDB_DATA_PTR )calloc( 1, sizeof( GEN_CFDB_DATA ) ) ) == NULL ) {
+
+ LP_MsgError( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos, LP_OUT_OF_MEMORY_ERROR, NULL, NULL, 0L ) ;
+
+ /* Free local allocations */
+ free( dblk_ptr ) ;
+ free( lp ) ;
+
+ return LP_OUT_OF_MEMORY_ERROR ;
+
+ }
+
+ /* allocate buffers for operation */
+
+ mem_save = BEC_GetReserveMem( cfg ) ;
+ max_buffs = BEC_GetMaxTapeBuffers( cfg ) ;
+ buff_size = BEC_GetTFLBuffSize( cfg ) ;
+
+ return_status = TF_AllocateTapeBuffers( mem_save, max_buffs, buff_size ) ;
+
+ if( ( return_status != SUCCESS ) ) {
+
+ LP_MsgError( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos, return_status, NULL, NULL, 0L ) ;
+
+ /* Free local allocations */
+ free( lp->rr.cfdb_data_ptr ) ;
+ free( dblk_ptr ) ;
+ free( lp ) ;
+
+ return( return_status ) ;
+
+ }
+
+ /* indicate the start of the operation */
+ LP_MsgStartOP( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos ) ;
+
+ /* loop for each bsd */
+ do {
+
+ if( BSD_GetMarkStatus( bsd_ptr ) == NONE_SELECTED ) {
+
+ bsd_ptr = BSD_GetNext( bsd_ptr ) ;
+ continue ;
+
+ }
+
+ /* First attach to the drive */
+ dle_ptr = BSD_GetDLE( bsd_ptr ) ;
+ lis_ptr->curr_bsd_ptr = bsd_ptr ;
+
+ cfg = BEC_CloneConfig( BSD_GetConfigData( bsd_ptr ) ) ;
+ if ( cfg == NULL ) {
+ return_status = OUT_OF_MEMORY ;
+ break ;
+ }
+
+ BEC_UseConfig( cfg ) ;
+ if ( !BSD_CompatibleBackup( bsd_ptr) ) {
+
+ if ( BSD_SetArchiveBackup( bsd_ptr ) ) {
+ BEC_SetSetArchiveFlag( cfg, (BOOLEAN)TRUE ) ;
+ } else {
+ BEC_SetSetArchiveFlag( cfg, (BOOLEAN)FALSE ) ;
+ }
+
+ if ( BSD_ModFilesOnly( bsd_ptr ) ) {
+ BEC_SetModifiedOnlyFlag( cfg, (BOOLEAN)TRUE ) ;
+ } else {
+ BEC_SetModifiedOnlyFlag( cfg, (BOOLEAN)FALSE ) ;
+ }
+ }
+
+ /* Now attach to the dle */
+ if( ( return_status = FS_AttachToDLE( &lp->curr_fsys, dle_ptr, cfg, NULL, NULL ) ) == SUCCESS ) {
+
+ /* Set up the loop environment structure */
+ lp->get_spcl = TRUE ;
+ lp->seq_num = 1 ;
+ lp->start_new_dir = TRUE ;
+ lp->get_first_file = TRUE ;
+ lp->get_next_first_time = TRUE ;
+ lp->after_bs = FALSE ;
+ lp->curr_blk = &lp->dblk1 ;
+ lp->curr_ddb = &lp->dblk2 ;
+ lp->empty_blk = &lp->dblk3 ;
+ lp->pdl_q = NULL ;
+ lp->cat_enabled = (BOOLEAN)(BEC_GetCatalogLevel( cfg ) != CATALOGS_NONE) ;
+ lp->tpos.tape_id = BSD_GetTapeID( bsd_ptr ) ;
+ lp->tpos.tape_seq_num = BSD_GetTapeNum( bsd_ptr ) ;
+ lp->tpos.backup_set_num = BSD_GetSetNum( bsd_ptr ) ;
+ lp->tpos.UI_TapePosRoutine = lis_ptr->tape_pos_handler ;
+ lp->curr_dle = dle_ptr ;
+
+ sdrv = LP_DetermineStartingTPDrv( lis_ptr->oper_type, bsd_ptr, &lp->tpos, lis_ptr->auto_det_sdrv ) ;
+
+ if( !tape_opened ) {
+ tape_opened = TRUE ;
+ /* open the tape for operation */
+ if( ( return_status = TF_OpenTape( &channel_no, sdrv, &lp->tpos ) ) != SUCCESS ) {
+ LP_MsgError( lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, return_status, NULL, NULL, 0L ) ;
+ }
+ }
+
+ if( return_status == SUCCESS ) {
+ /* Perform the operation */
+ return_status = LP_BackupDLE( bsd_ptr, lp, tfl_open_mode, channel_no, sdrv ) ;
+
+ LP_ClearPDL( lp ) ;
+
+ FS_DetachDLE( lp->curr_fsys ) ;
+ }
+ }
+ else if( return_status != USER_ABORT ) {
+
+ /* error attaching to the drive, just go on to next drive, if there is one */
+ LP_MsgError( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos, LP_DRIVE_ATTACH_ERROR, NULL, NULL, 0L ) ;
+
+ /* reset return_status, and try the next bsd */
+ return_status = SUCCESS ;
+ }
+
+ BEC_ReleaseConfig( cfg ) ;
+
+ tfl_open_mode = TF_WRITE_APPEND ;
+ bsd_ptr = BSD_GetNext( bsd_ptr ) ;
+
+ } while( !return_status && (bsd_ptr != NULL) ) ;
+
+ if( tape_opened ) {
+ TF_CloseTape( channel_no ) ;
+ }
+
+ if( ( status = TF_FreeTapeBuffers( ) ) != SUCCESS ) {
+ LP_MsgError( lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr,
+ NULL, &lp->tpos, status, NULL, NULL, 0L ) ;
+ }
+
+ /* indicate the end of the operation */
+ LP_MsgEndOP( lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, NULL, &lp->tpos ) ;
+
+ /* Free local allocations */
+ free( lp->rr.cfdb_data_ptr ) ;
+ free( dblk_ptr ) ;
+ free( lp ) ;
+
+ return( return_status ) ;
+
+}
diff --git a/private/utils/ntbackup/src/lpdelete.c b/private/utils/ntbackup/src/lpdelete.c
new file mode 100644
index 000000000..03236b53a
--- /dev/null
+++ b/private/utils/ntbackup/src/lpdelete.c
@@ -0,0 +1,414 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: lpdelete.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+
+ $Log: N:\logfiles\lpdelete.c_v $
+
+ Rev 1.15 12 Aug 1993 21:28:04 BARRY
+fix delete bug
+
+ Rev 1.14 26 Jul 1993 14:53:30 CARLS
+added code for delete failure
+
+ Rev 1.13 20 Jul 1993 15:31:50 BARRY
+Call FS_FindCloseObj
+
+ Rev 1.12 19 Jun 1993 10:14:28 DON
+If a release build, and msassert are gone
+don't attempt to use a NULL bsd_ptr
+
+ Rev 1.11 14 Jan 1993 13:33:30 STEVEN
+added stream_id to error message
+
+ Rev 1.10 13 May 1992 12:00:58 TIMN
+Added TEXT() macro to literals, but not msassert literals
+
+ Rev 1.9 26 Mar 1992 15:26:34 CARLS
+was deleting special files
+
+ Rev 1.8 22 Jan 1992 15:57:28 BARRY
+Now is aware of new return status codes from BSD_MatchObj().
+
+ Rev 1.7 23 Dec 1991 13:27:10 BARRY
+Wasn't deleting anything but the first DLE--Terri's fix.
+
+ Rev 1.6 24 Jun 1991 17:25:32 STEVEN
+remove date time from StartBS
+
+ Rev 1.5 21 Jun 1991 09:32:38 STEVEN
+new config unit
+
+ Rev 1.4 14 Jun 1991 11:05:42 BARRY
+Config ptr sent to FS_AttachToDLE() should come from BSD.
+
+ Rev 1.3 30 May 1991 09:13:06 STEVEN
+bsdu_err.h no longer exists
+
+ Rev 1.2 24 May 1991 13:18:16 STEVEN
+updates from BSDU redesign
+
+ Rev 1.1 23 May 1991 18:30:08 BARRY
+Made delete a little more tolerant about possible file system problems.
+
+ Rev 1.0 09 May 1991 13:37:52 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "stdtypes.h"
+#include "msassert.h"
+#include "beconfig.h"
+#include "tbe_err.h"
+#include "tbe_defs.h"
+#include "tflproto.h"
+#include "tfldefs.h"
+#include "bsdu.h"
+#include "fsys.h"
+#include "queues.h"
+#include "loops.h"
+#include "loop_prv.h"
+/* $end$ include list */
+
+/* static function declarations */
+static INT16 LP_DeleteDLE( LP_ENV_PTR lp ) ;
+
+#define EMPTY_DO_NOT_DEL 2
+#define DELETE_SUCCESS 0
+#define DELETE_FAILED 1
+
+/**/
+/**
+
+ Name: LP_Delete_Engine()
+
+ Description:
+
+ Modified: 6/22/1989
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 LP_Delete_Engine(
+LIS_PTR lis_ptr ) /* loop interface structure */
+{
+ BSD_PTR bsd_ptr ;
+ GENERIC_DLE_PTR dle_ptr ;
+ LP_ENV_PTR lp ;
+ INT16 error = SUCCESS ;
+
+ bsd_ptr = BSD_GetFirst( lis_ptr->bsd_list ) ;
+
+ if ( bsd_ptr == NULL ) {
+ msassert( FALSE );
+ /* if the UI managed to pass in a NULL bsd were done */
+ return SUCCESS ;
+ }
+
+ /* Allocate the loop environment structure */
+ if( ( lp = ( LP_ENV_PTR )calloc( 1, sizeof( LP_ENV ) ) ) == NULL ) {
+
+ /* we cannot use macro because it relies on the lp structure */
+ lis_ptr->message_handler( MSG_TBE_ERROR, lis_ptr->pid, bsd_ptr, NULL, NULL, LP_OUT_OF_MEMORY_ERROR, NULL, NULL ) ;
+
+ return LP_OUT_OF_MEMORY_ERROR ;
+
+ }
+
+ /* Set up the loop environment structure */
+ lp->lis_ptr = lis_ptr ;
+ lp->tpos.reference = ( UINT32 )lis_ptr ;
+
+ /* indicate the start of the operation */
+ LP_MsgStartOP( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos ) ;
+
+ /* loop for each bsd */
+ do {
+ /* First attach to the drive */
+ dle_ptr = BSD_GetDLE( bsd_ptr ) ;
+ lp->curr_blk = &lp->dblk1 ;
+ lp->curr_ddb = &lp->dblk2 ;
+ lp->empty_blk = &lp->dblk3 ;
+
+ /* Now attach to the dle */
+ error = FS_AttachToDLE( &lp->curr_fsys, dle_ptr, BSD_GetConfigData( bsd_ptr ), NULL, NULL ) ;
+
+ if( error == SUCCESS ) {
+ /* No problems getting ahold of the drive */
+
+ LP_MsgStartBS( lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, NULL ) ;
+
+ error = LP_DeleteDLE( lp ) ;
+ if ( ( error == DELETE_SUCCESS) || (error == EMPTY_DO_NOT_DEL) ) {
+ error = SUCCESS ;
+ }
+
+ LP_MsgEndBS( lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos ) ;
+
+ FS_DetachDLE( lp->curr_fsys ) ;
+
+ } else if( error != USER_ABORT ) {
+ /* error attaching to the drive, now we just want to */
+ /* go on with the next drive, if there is one */
+ LP_MsgError( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos, LP_DRIVE_ATTACH_ERROR, NULL, NULL, 0L ) ;
+
+ /* reset error, and continue on */
+ error = SUCCESS ;
+ }
+
+ /* Now we continue, as long as we did not have an error, and we can get a new bsd */
+ bsd_ptr = BSD_GetNext( bsd_ptr ) ;
+
+ /* assign the bsd ptr to the lis' curr bsd so that LP_DeleteDLE gets the next bsd */
+ lp->lis_ptr->curr_bsd_ptr = bsd_ptr ;
+
+ } while( !error && ( bsd_ptr != NULL ) ) ;
+
+ /* indicate the end of the operation */
+ LP_MsgEndOP( lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, NULL, &lp->tpos ) ;
+
+ /* Free local allocations */
+ free( lp ) ;
+
+ return error ;
+}
+/**/
+/**
+
+ Name: LP_DeleteDLE()
+
+ Description:
+
+ Modified: 6/22/1989
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 LP_DeleteDLE( lp )
+register LP_ENV_PTR lp ;
+{
+ INT16 result ;
+ BOOLEAN empty_flag = TRUE ;
+ INT16 finished = FALSE ;
+ INT16 first_time = TRUE ;
+ UINT8 scan_blk_type = FDB_ID;
+ BOOLEAN log_dir = FALSE ;
+ INT16 ret_val ;
+
+ static FSYS_HAND fsh ;
+ static BSD_PTR bsd_ptr ;
+ static UINT32 pid ;
+ static FSE_PTR fse_ptr ;
+
+ bsd_ptr = lp->lis_ptr->curr_bsd_ptr ;
+ fsh = lp->curr_fsys ;
+ pid = lp->lis_ptr->pid ;
+
+ FS_GetCurrentDDB( fsh, lp->curr_ddb ) ;
+
+ result = BSD_MatchObj( bsd_ptr, &fse_ptr, fsh, lp->curr_ddb, NULL, FALSE ) ;
+
+ if ( result != BSD_SKIP_OBJECT ) {
+ log_dir = TRUE ;
+ }
+
+ while( !finished ) {
+
+ /* check for abort conditions */
+ switch( LP_GetAbortFlag( lp->lis_ptr ) ) {
+ case CONTINUE_PROCESSING:
+ break ;
+
+ case ABORT_CTRL_BREAK:
+ LP_MsgError( pid, bsd_ptr, fsh, &lp->tpos, LP_USER_ABORT_ERROR, NULL, NULL, 0L ) ;
+ /* falling through (no break) */
+ case ABORT_PROCESSED:
+ return USER_ABORT ;
+
+
+ case ABORT_AT_EOM:
+
+ return USER_ABORT ;
+
+ }
+
+ do {
+ if( first_time ) {
+ result = FS_FindFirstObj( fsh, lp->curr_blk, ALL_FILES ) ;
+ if( result == SUCCESS ) {
+ empty_flag = FALSE ;
+ } else {
+ FS_FindObjClose( fsh, lp->curr_blk );
+ }
+
+ first_time = FALSE ;
+
+ } else {
+ FS_ReleaseDBLK( fsh, lp->curr_blk );
+ result = FS_FindNextObj( fsh, lp->curr_blk ) ;
+ if ( result != SUCCESS ) {
+ FS_FindObjClose( fsh, lp->curr_blk );
+ }
+ }
+ } while( ( result == SUCCESS ) && ( FS_GetBlockType( lp->curr_blk ) != scan_blk_type ) ) ;
+
+ if( ( result != SUCCESS) && ( scan_blk_type == FDB_ID ) ) {
+ scan_blk_type = DDB_ID ;
+ first_time = TRUE ;
+ continue ;
+ }
+
+ if( result != SUCCESS ) {
+ /* delete empty directories */
+
+ if ( empty_flag ) {
+ if ( BEC_GetProcEmptyFlag( BSD_GetConfigData( bsd_ptr ) ) ) {
+
+ result = BSD_MatchObj( bsd_ptr, &fse_ptr, fsh,
+ lp->curr_ddb, NULL, FALSE ) ;
+
+ if ( !(result == BSD_SKIP_OBJECT) && !(result == FSL_EMPTY) ) {
+
+ LP_MsgLogBlock( pid, bsd_ptr, fsh, &lp->tpos, lp->curr_ddb ) ;
+ LP_MsgBlockProcessed( pid, bsd_ptr, fsh, &lp->tpos, lp->curr_ddb ) ;
+
+ }
+
+ } else {
+ return EMPTY_DO_NOT_DEL ;
+ }
+
+ }
+
+ return DELETE_SUCCESS ;
+
+ } else {
+
+ /* Don't match on a possibly bogus DBLK */
+ if ( FS_GetObjInfo( fsh, lp->curr_blk ) != SUCCESS ) {
+ continue;
+ }
+
+ /* Now process item type */
+ switch( FS_GetBlockType( lp->curr_blk ) ) {
+ case FDB_ID:
+ result = BSD_MatchObj( bsd_ptr, &fse_ptr, fsh, lp->curr_ddb, lp->curr_blk, FALSE ) ;
+
+ if ( !(result == BSD_SKIP_OBJECT) && !(result == FSL_EMPTY) ) {
+ if ( ( result == BSD_SPECIAL_OBJECT ) && !BSD_GetProcSpecialFlg( bsd_ptr ) ) {
+ break;
+ }
+
+ if ( log_dir ) {
+ log_dir = FALSE ;
+ LP_MsgLogBlock( pid, bsd_ptr, fsh, &lp->tpos, lp->curr_ddb ) ;
+ LP_MsgBlockProcessed( pid, bsd_ptr, fsh, &lp->tpos, lp->curr_ddb ) ;
+ }
+
+#ifndef TDEMO
+ /* Make sure DBLK is completely filled out before asking FS to delete it */
+ if ( (ret_val = FS_GetObjInfo( fsh, lp->curr_blk )) == SUCCESS ) {
+ ret_val = FS_DeleteObj( fsh, lp->curr_blk ) ;
+ }
+
+ if ( ret_val != SUCCESS ) {
+ /* send message to UI we were unable to delete */
+ /* this object. */
+ LP_MsgNotDeleted( pid, bsd_ptr, fsh, &lp->tpos, lp->curr_blk ) ;
+ }
+#endif
+
+ if ( ret_val == SUCCESS ) {
+ LP_MsgLogBlock( pid, bsd_ptr, fsh, &lp->tpos, lp->curr_blk ) ;
+ LP_MsgBlockProcessed( pid, bsd_ptr, fsh, &lp->tpos, lp->curr_blk ) ;
+ }
+ }
+ break ;
+
+ case DDB_ID:
+ result = BSD_MatchObj( bsd_ptr, &fse_ptr, fsh, lp->curr_blk, NULL, TRUE ) ;
+
+ if ( !(result == BSD_SKIP_OBJECT) && !(result == FSL_EMPTY) ) {
+
+ ret_val = FS_PushMinDDB( fsh, lp->curr_blk ) ;
+
+ if( ret_val != SUCCESS ) {
+ LP_MsgError( pid, bsd_ptr, fsh, &lp->tpos, LP_OUT_OF_MEMORY_ERROR, NULL, NULL, 0L ) ;
+ ret_val = OUT_OF_MEMORY ;
+ finished = TRUE ;
+ break ;
+
+ }
+
+ FS_ChangeIntoDDB( fsh, lp->curr_blk ) ;
+
+ ret_val = LP_DeleteDLE( lp ) ;
+
+ FS_UpDir( fsh ) ;
+ FS_ReleaseDBLK( fsh, lp->curr_ddb );
+ FS_GetCurrentDDB( fsh, lp->curr_ddb ) ;
+
+ if( FS_PopMinDDB( fsh, lp->curr_blk ) ) {
+ LP_MsgError( pid, bsd_ptr, fsh, &lp->tpos, LP_OUT_OF_MEMORY_ERROR, NULL, NULL, 0L ) ;
+ ret_val = OUT_OF_MEMORY ;
+ finished = TRUE ;
+ break ;
+ }
+
+ if ( (ret_val != DELETE_SUCCESS) && (ret_val != EMPTY_DO_NOT_DEL) ) {
+ return( ret_val ) ;
+ }
+
+ if ( !(result == BSD_SKIP_OBJECT) && !(result == FSL_EMPTY) ) {
+ if ( ret_val != EMPTY_DO_NOT_DEL ) {
+#ifndef TDEMO
+ /* Make sure DBLK is completely filled out before asking FS to delete it */
+ ret_val = FS_GetObjInfo( fsh,
+ lp->curr_blk );
+
+ if ( ret_val == SUCCESS ) {
+ ret_val = FS_DeleteObj( fsh, lp->curr_blk ) ;
+ }
+
+ if ( ret_val != SUCCESS ) {
+ /* send message to UI we were unable to delete */
+ /* this object. */
+ log_dir = FALSE ;
+ LP_MsgNotDeleted( pid, bsd_ptr, fsh, &lp->tpos, lp->curr_blk ) ;
+ }
+ FS_ReleaseDBLK( fsh, lp->curr_blk );
+#endif
+ }
+ }
+ }
+ break ;
+ }
+ }
+ }
+ return DELETE_SUCCESS ;
+}
+
+
diff --git a/private/utils/ntbackup/src/lplist.c b/private/utils/ntbackup/src/lplist.c
new file mode 100644
index 000000000..a9ab053c4
--- /dev/null
+++ b/private/utils/ntbackup/src/lplist.c
@@ -0,0 +1,443 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: lplist.c
+
+ Description: This module contains the entry point for the list tape engine.
+
+ $Log: J:/LOGFILES/LPLIST.C_V $
+
+ Rev 1.23 05 Nov 1993 15:01:48 MARILYN
+EPR963: keeping track of which tape we are on so we know which one to expect
+
+ Rev 1.22 14 Jan 1993 13:33:34 STEVEN
+added stream_id to error message
+
+ Rev 1.21 30 May 1992 23:31:38 GREGG
+Turn off rewind_sdrv if we know the family id, sequence number and set number.
+
+ Rev 1.20 29 May 1992 10:22:50 STEVEN
+added support for not rewinding
+
+ Rev 1.19 13 May 1992 12:26:50 TIMN
+Removed used references to tapename and backup_set_name for TPOS structs.
+
+ Rev 1.18 20 Mar 1992 13:09:58 STEVEN
+do not call tape format if AUXIL_ERROR
+
+ Rev 1.17 24 Feb 1992 10:03:32 GREGG
+Call TF_OpenTape at beginning of loop, Open/Close Set in loop, CloseTape at end.
+
+ Rev 1.16 19 Feb 1992 16:01:48 GREGG
+Added vcb_only parameter to call to TF_OpenSet.
+
+ Rev 1.15 04 Feb 1992 21:41:42 GREGG
+Changed parameters in calls to TF_AllocateTapeBuffers and TF_FreeTapeBuffers.
+
+ Rev 1.14 22 Jan 1992 10:20:12 STEVEN
+fix warnings for WIN32
+
+ Rev 1.0 22 Jan 1992 10:17:54 STEVEN
+fix warnings for WIN32
+
+ Rev 1.13 13 Dec 1991 15:21:18 GREGG
+SKATEBOARD - Initial Integration.
+
+ Rev 1.12 13 Dec 1991 15:18:18 STEVEN
+bug in pba stuff
+
+ Rev 1.11 21 Nov 1991 14:29:42 STEVEN
+set pba in tpos structure
+
+ Rev 1.10 06 Nov 1991 19:25:18 GREGG
+BIGWHEEL - 8200sx - Get cat_enabled from the BE config.
+
+ Rev 1.9 28 Oct 1991 12:09:54 GREGG
+BIGWHEEL - Assert if TRR_EOM encountered (should be taken care of in GetNextTPE.
+
+ Rev 1.8 17 Oct 1991 01:53:26 ED
+BIGWHEEL - 8200sx - Initial integration.
+
+ Rev 1.7 22 Jul 1991 10:56:50 DAVIDH
+Corrected type mismatch warnings.
+
+ Rev 1.6 24 Jun 1991 17:24:14 STEVEN
+remove date time from StartBS
+
+ Rev 1.5 21 Jun 1991 09:33:34 STEVEN
+new config unit
+
+ Rev 1.4 30 May 1991 09:15:06 STEVEN
+bsdu_err.h no longer exists
+
+ Rev 1.3 28 May 1991 10:49:18 STEVEN
+use MAYN_MEM instead of MAYN_OS2
+
+ Rev 1.2 24 May 1991 13:15:30 STEVEN
+updates from BSDU redesign
+
+ Rev 1.1 15 May 1991 09:36:04 DAVIDH
+Cleared up Watcom compiler warnings for NLM.
+
+ Rev 1.0 09 May 1991 13:37:52 HUNTER
+Initial revision.
+
+**/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "queues.h"
+#include "beconfig.h"
+#include "msassert.h"
+#include "tbe_defs.h"
+#include "tbe_err.h"
+#include "bsdu.h"
+#include "fsys.h"
+#include "tflproto.h"
+#include "tfldefs.h"
+#include "loops.h"
+#include "loop_prv.h"
+#include "get_next.h"
+
+
+
+INT16 LP_List_Tape_Engine(
+LIS_PTR lis_ptr ) /* I - Loop interface structure */
+{
+ BSD_PTR bsd_ptr ;
+ TFL_OPBLK pb ;
+ LP_ENV_PTR lp ;
+ INT16 done = FALSE ;
+ INT16 return_status = SUCCESS ;
+ INT16 status ;
+ UINT16 mem_save ;
+ UINT16 max_buffs ;
+ UINT16 buff_size ;
+ DBLK_PTR dblk_ptr ;
+ DBLK_PTR curr_blk ;
+ BE_CFG_PTR cfg ;
+
+ bsd_ptr = BSD_GetFirst( lis_ptr->bsd_list ) ;
+
+ msassert( bsd_ptr != NULL ) ;
+
+ cfg = BSD_GetConfigData( bsd_ptr ) ;
+
+ /* Allocate the loop environment structure */
+ if( ( lp = ( LP_ENV_PTR )calloc( 1, sizeof( LP_ENV ) ) ) == NULL ) {
+
+ /* we cannot use macro because it relies on the lp structure */
+ lis_ptr->message_handler( MSG_TBE_ERROR, lis_ptr->pid, bsd_ptr, NULL, NULL, LP_OUT_OF_MEMORY_ERROR, NULL, NULL ) ;
+
+ return LP_OUT_OF_MEMORY_ERROR ;
+
+ }
+
+ /* Set up the loop environment structure */
+ lp->lis_ptr = lis_ptr ;
+ lp->tpos.reference = ( UINT32 )lis_ptr ;
+
+ /* allocate DBLKs */
+ if( ( dblk_ptr = ( DBLK_PTR )calloc( 3, sizeof( DBLK ) ) ) == NULL ) {
+
+ LP_MsgError( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos, LP_OUT_OF_MEMORY_ERROR, NULL, NULL, 0L ) ;
+
+ /* Free local allocations */
+ free( lp ) ;
+
+ return LP_OUT_OF_MEMORY_ERROR ;
+
+ } else {
+ /* set up the DBLK_PTRs in the Request/Reply structure */
+ lp->rr.vcb_ptr = dblk_ptr ;
+ lp->rr.ddb_ptr = dblk_ptr + 1 ;
+ lp->saved_ddb = dblk_ptr + 1 ;
+ lp->rr.fdb_ptr = dblk_ptr + 2 ; /* ASSUMPTION : */
+ lp->rr.idb_ptr = dblk_ptr + 2 ; /* no FS has both FDB & IDB */
+ }
+
+ /* Set up the loop environment structure */
+ lp->get_spcl = TRUE ;
+ lp->seq_num = 1 ;
+ lp->start_new_dir = TRUE ;
+ lp->get_first_file = TRUE ;
+ lp->get_next_first_time = TRUE ;
+ lp->curr_blk = &lp->dblk1 ;
+ lp->curr_ddb = &lp->dblk2 ;
+ lp->empty_blk = &lp->dblk3 ;
+ lp->blk_is_empty = TRUE ;
+ lp->send_saved_block = FALSE ;
+
+ /* allocate buffers for operation */
+
+ mem_save = BEC_GetReserveMem( cfg ) ;
+ max_buffs = BEC_GetMaxTapeBuffers( cfg ) ;
+ buff_size = BEC_GetTFLBuffSize( cfg ) ;
+
+ return_status = TF_AllocateTapeBuffers( mem_save, max_buffs, buff_size ) ;
+
+ if( return_status != SUCCESS ) {
+
+ LP_MsgError( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos, return_status, NULL, NULL, 0L ) ;
+
+ /* Free local allocations */
+ free( dblk_ptr ) ;
+ free( lp ) ;
+
+ return( return_status ) ;
+
+ }
+
+ /* Need to open file system */
+ if( ( return_status = FS_OpenFileSys( &lp->curr_fsys, GENERIC_DATA, cfg ) ) == OUT_OF_MEMORY ) {
+
+ LP_MsgError( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos, LP_OUT_OF_MEMORY_ERROR, NULL, NULL, 0L ) ;
+
+ /* Deinit operation buffers */
+ if( ( status = TF_FreeTapeBuffers( ) ) != SUCCESS ) {
+ LP_MsgError( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos, status, NULL, NULL, 0L ) ;
+ }
+
+ /* Free local allocations */
+ free( dblk_ptr ) ;
+ free( lp ) ;
+
+ return LP_OUT_OF_MEMORY_ERROR ;
+
+ } else {
+
+ /* indicate the start of the operation */
+ LP_MsgStartOP( lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos ) ;
+
+ msassert( return_status == SUCCESS ) ;
+
+ /* set up for tape positioning */
+ lp->tpos.tape_id = BSD_GetTapeID( bsd_ptr ) ;
+ lp->tpos.tape_seq_num = BSD_GetTapeNum( bsd_ptr ) ;
+ lp->tpos.backup_set_num = BSD_GetSetNum( bsd_ptr ) ;
+ lp->tpos.tape_loc.pba_vcb = BSD_GetPBA( bsd_ptr );
+ lp->tpos.UI_TapePosRoutine = lis_ptr->tape_pos_handler ;
+ pb.tape_position = &lp->tpos ;
+ pb.sdrv = LP_DetermineStartingTPDrv( lis_ptr->oper_type, bsd_ptr, &lp->tpos, lis_ptr->auto_det_sdrv ) ;
+ pb.perm_filter = TF_SKIP_ALL_DATA ;
+ pb.attributes = 0L ;
+ pb.fsh = lp->curr_fsys ;
+ pb.mode = TF_SCAN_OPERATION ;
+ pb.ignore_clink = FALSE ;
+ pb.wrt_format = 0 ;
+ pb.idle_call = NULL ;
+ pb.cat_enabled = (BOOLEAN)(BEC_GetCatalogLevel( cfg ) != CATALOGS_NONE) ;
+ lp->rr.filter_to_use = TF_SKIP_ALL_DATA ;
+ lp->rr.tape_loc.pba_vcb = BSD_GetPBA( bsd_ptr );
+
+ pb.rewind_sdrv = (BOOLEAN)(( lis_ptr->oper_type == CATALOG_TAPE_OPER ) ? TRUE : FALSE ) ;
+ if( lp->tpos.tape_id != -1 &&
+ lp->tpos.tape_seq_num != -1 &&
+ lp->tpos.backup_set_num != -1 ) {
+
+ pb.rewind_sdrv = FALSE ;
+ }
+
+ /* Don't really want negative backup set numbers */
+ if ( (lp->tpos.backup_set_num != -1) && (lp->tpos.backup_set_num < 0) ) {
+ lp->tpos.backup_set_num = -BSD_GetSetNum( bsd_ptr ) ;
+ }
+
+ /* Open the tape */
+ if( ( return_status = TF_OpenTape( &pb.channel, pb.sdrv, pb.tape_position ) ) != SUCCESS ) {
+ LP_MsgError( lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, return_status, NULL, NULL, 0L ) ;
+ } else {
+
+ /* Now open the backup set */
+ if( ( return_status = TF_OpenSet( &pb, FALSE ) ) != SUCCESS ) {
+ TF_CloseSet( lp->channel, NULL ) ;
+ LP_MsgError( lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, return_status, NULL, NULL, 0L ) ;
+ } else {
+
+ lp->channel = pb.channel ;
+
+ BEC_SetProcEmptyFlag( cfg, (BOOLEAN)TRUE ) ;
+ BEC_SetSpecialFlag( cfg, (BOOLEAN)TRUE ) ;
+ BEC_SetHiddenFlag( cfg, (BOOLEAN)TRUE ) ;
+
+
+ while( return_status == SUCCESS ) {
+
+ if( ( return_status = LP_StartTPEDialogue( lp, FALSE ) ) == SUCCESS ) {
+
+ do {
+ switch( lp->rr.tf_message ) {
+
+ case TRR_FDB:
+ case TRR_DDB:
+ case TRR_IDB:
+ case TRR_CFDB:
+ /* call message handler to process the directory listing */
+ return_status = LP_MsgLogBlock( lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, curr_blk ) ;
+ break ;
+
+ case TRR_VCB:
+ done = FALSE ;
+
+ /* call message handler to log the start of the operation */
+ switch( return_status = LP_MsgStartBS( lis_ptr->pid,
+ bsd_ptr,
+ lp->curr_fsys,
+ &lp->tpos,
+ lp->curr_blk ) ) {
+
+ case OPERATION_COMPLETE:
+ break ;
+
+ case SKIP_TO_NEXT_BSET:
+ pb.rewind_sdrv = FALSE ;
+ lp->tpos.backup_set_num++ ;
+ break ;
+
+ default:
+ break ;
+ }
+
+ break ;
+
+ case TRR_END:
+ done = TRUE ;
+ break ;
+
+ case TRR_EOM:
+ /* This shold be taken care of in LP_GetNextTPEBlock. */
+ msassert( FALSE ) ;
+ break ;
+
+ default:
+ break ;
+ }
+
+ /* check for abort conditions */
+ switch( LP_GetAbortFlag( lis_ptr ) ) {
+
+ case CONTINUE_PROCESSING:
+ break ;
+
+ case ABORT_CTRL_BREAK:
+ LP_MsgError( lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, LP_USER_ABORT_ERROR, NULL, NULL, 0L ) ;
+
+ /* falling through (no break) */
+
+ case ABORT_PROCESSED:
+ return_status = USER_ABORT ;
+ break ;
+
+ case ABORT_AT_EOM:
+ return_status = USER_ABORT ;
+ break ;
+ }
+
+ if( ( return_status != OPERATION_COMPLETE ) &&
+ ( return_status != USER_ABORT ) &&
+ ( return_status != TFLE_USER_ABORT ) &&
+ ( return_status != ABORT_OPERATION ) &&
+ ( return_status != AUXILARY_ERROR ) &&
+ ( return_status != SKIP_TO_NEXT_BSET ) ) {
+
+ if( !( return_status = LP_GetNextTPEBlock( lp, &curr_blk ) ) ) {
+ if ( curr_blk == NULL ) {
+ break ;
+ }
+ }
+ }
+
+ } while( !return_status && !done ) ;
+
+ /* call message handler to log the end of the operation */
+ LP_MsgEndBS( lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos ) ;
+ }
+
+ /* Process last tape format request as long as no fatal error occurred */
+ switch( return_status ) {
+
+ case SKIP_TO_NEXT_BSET:
+ case OPERATION_COMPLETE:
+ case AUXILARY_ERROR:
+ case TFLE_USER_ABORT:
+ case TFLE_UI_HAPPY_ABORT:
+ case USER_ABORT:
+ if( return_status == SKIP_TO_NEXT_BSET ) {
+ lp->rr.lp_message = LRR_FINISHED ;
+ } else {
+ lp->rr.lp_message = LRR_ABORT ;
+ }
+ if( ( return_status == SKIP_TO_NEXT_BSET ) ||
+ ( return_status == OPERATION_COMPLETE ) ||
+ ( return_status == TFLE_USER_ABORT ) ||
+ ( ( return_status == TFLE_UI_HAPPY_ABORT ) && ( LP_GetAbortFlag( lis_ptr ) != ABORT_AT_EOM ) ) ||
+ ( ( return_status == USER_ABORT ) && ( LP_GetAbortFlag( lis_ptr ) != ABORT_AT_EOM ) ) ) {
+
+ if( ( status = TF_GetNextTapeRequest( &lp->rr ) ) != SUCCESS ) {
+ LP_MsgError( lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, status, NULL, NULL, 0L ) ;
+ }
+ }
+ break ;
+
+ default:
+ /* don't care about these conditions */
+ break ;
+ }
+
+ /* Close set, save current tape device and post tape stats */
+ LP_CloseSet( pb.channel ) ;
+
+ if( ( return_status != OPERATION_COMPLETE ) &&
+ ( return_status != ABORT_OPERATION ) &&
+ ( return_status != AUXILARY_ERROR ) &&
+ ( return_status != TFLE_UI_HAPPY_ABORT ) &&
+ ( return_status != TFLE_USER_ABORT ) &&
+ ( return_status != USER_ABORT ) ) {
+
+ if( return_status != SKIP_TO_NEXT_BSET ) {
+ /* try to get the next bset */
+ lp->tpos.backup_set_num++ ;
+ pb.rewind_sdrv = FALSE ;
+ }
+
+ /* Update current tape device in TF pblock in case we crossed to a new drive */
+ pb.sdrv = lw_last_tpdrv ;
+
+ /* if specific set was specified then exit out of loop */
+ if ( BSD_GetPBA( bsd_ptr ) != 0 ) {
+ break ;
+ }
+
+ if( ( return_status = TF_OpenSet( &pb, FALSE ) ) != SUCCESS ) {
+ TF_CloseSet( lp->channel, NULL ) ;
+ LP_MsgError( lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, return_status, NULL, NULL, 0L ) ;
+ }
+ }
+ } /* END: while( return_status == SUCCESS ) */
+ }
+ }
+
+ if( ( status = FS_CloseFileSys( lp->curr_fsys ) ) != SUCCESS ) {
+ msassert( status == SUCCESS ) ;
+ }
+ }
+
+ TF_CloseTape( lp->channel ) ;
+
+ /* Deinit operation buffers */
+ if( ( status = TF_FreeTapeBuffers( ) ) != SUCCESS ) {
+ LP_MsgError( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos, status, NULL, NULL, 0L ) ;
+ }
+
+ /* indicate the end of the operation */
+ LP_MsgEndOP( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos ) ;
+
+ /* Free local allocations */
+ free( dblk_ptr ) ;
+ free( lp ) ;
+
+ return( return_status ) ;
+}
diff --git a/private/utils/ntbackup/src/lprestor.c b/private/utils/ntbackup/src/lprestor.c
new file mode 100644
index 000000000..2632c5801
--- /dev/null
+++ b/private/utils/ntbackup/src/lprestor.c
@@ -0,0 +1,341 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: lprestor.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This module contains the entry point for the restore engine.
+
+
+ $Log: T:\logfiles\lprestor.c_v $
+
+ Rev 1.11.1.0 07 Feb 1994 02:06:52 GREGG
+Fixed and expanded 'extended error reporting'.
+
+ Rev 1.11 29 Apr 1993 22:26:44 GREGG
+Transfer the Tape Catalog Version in the BSD to the tpos structure.
+
+ Rev 1.10 14 Jan 1993 13:33:38 STEVEN
+added stream_id to error message
+
+ Rev 1.9 24 Feb 1992 09:58:42 GREGG
+Call TF_OpenTape at beginning of loop, Open/Close Set in loop, CloseTape at end.
+
+ Rev 1.8 04 Feb 1992 21:40:50 GREGG
+Changed parameters in calls to TF_AllocateTapeBuffers and TF_FreeTapeBuffers.
+
+ Rev 1.7 16 Jan 1992 15:56:36 STEVEN
+fix warnings for WIN32
+
+ Rev 1.6 13 Dec 1991 15:25:06 GREGG
+SKATEBOARD - Initial Integration.
+
+ Rev 1.5 06 Nov 1991 19:07:38 GREGG
+BIGWHEEL - 8200sx - Get cat_enabled from the BE config.
+
+ Rev 1.4 21 Jun 1991 09:23:02 STEVEN
+new config unit
+
+ Rev 1.3 30 May 1991 09:14:26 STEVEN
+bsdu_err.h no longer exists
+
+ Rev 1.2 28 May 1991 10:12:22 STEVEN
+use MAYN_MEM instead of MAYN_OS2
+
+ Rev 1.1 24 May 1991 14:45:46 STEVEN
+complete changes for new getnext
+
+ Rev 1.0 09 May 1991 13:37:54 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "queues.h"
+#include "beconfig.h"
+#include "msassert.h"
+#include "tbe_defs.h"
+#include "tbe_err.h"
+#include "bsdu.h"
+#include "fsys.h"
+#include "tflproto.h"
+#include "loops.h"
+#include "loop_prv.h"
+#include "tfldefs.h"
+#include "lis.h"
+/* $end$ include list */
+
+/**/
+/**
+
+ Name: LP_Restore_Engine()
+
+ Description: this routine handles restoring multiple backup sets to multiple targets.
+
+ Modified: 02/02/1990
+
+ Returns: SUCCESS or error code from Tape Format or Loop error code
+
+ Notes: the loop interface structure must be entirely filled out.
+
+ See also: $/SEE( LP_Backup_Engine(), LP_Verify_Engine )$
+ $/SEE( LP_Delete_Engine() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 LP_Restore_Engine(
+LIS_PTR lis_ptr )
+{
+ BSD_PTR bsd_ptr ;
+ BSD_PTR temp_bsd_ptr;
+ GENERIC_DLE_PTR dle_ptr ;
+ register LP_ENV_PTR lp ;
+ INT16 return_status = SUCCESS ;
+ INT16 status ;
+ UINT16 mem_save ;
+ UINT16 max_buffs ;
+ UINT16 buff_size ;
+ DBLK_PTR dblk_ptr ;
+ BOOLEAN reuse_bsd = FALSE ;
+ BOOLEAN first_time = TRUE ;
+ BE_CFG_PTR cfg ;
+ BOOLEAN tape_opened = FALSE ;
+ INT16 channel_no ;
+ THW_PTR sdrv ;
+
+ bsd_ptr = BSD_GetFirst( lis_ptr->bsd_list ) ;
+
+ msassert( bsd_ptr != NULL ) ;
+
+ cfg = BSD_GetConfigData( bsd_ptr ) ;
+
+ /* Allocate the loop environment structure */
+ if( ( lp = ( LP_ENV_PTR )calloc( 1, sizeof( LP_ENV ) ) ) == NULL ) {
+
+ lis_ptr->message_handler( MSG_TBE_ERROR, lis_ptr->pid, bsd_ptr, NULL, NULL, LP_OUT_OF_MEMORY_ERROR, NULL, NULL ) ;
+
+ return LP_OUT_OF_MEMORY_ERROR ;
+
+ }
+
+ /* Set up the loop environment structure */
+ lp->lis_ptr = lis_ptr ;
+ lp->tpos.reference = ( UINT32 )lis_ptr ;
+
+ /* allocate DBLKs */
+ if( ( dblk_ptr = ( DBLK_PTR )calloc( 3, sizeof( DBLK ) ) ) == NULL ) {
+
+ LP_MsgError( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos, LP_OUT_OF_MEMORY_ERROR, NULL, NULL, 0L ) ;
+
+ /* Free local allocations */
+ free( lp ) ;
+
+ return LP_OUT_OF_MEMORY_ERROR ;
+
+ }
+ else {
+ /* set up the DBLK_PTRs in the Request/Reply structure */
+ lp->rr.vcb_ptr = dblk_ptr ;
+ lp->rr.ddb_ptr = dblk_ptr + 1 ;
+ lp->saved_ddb = dblk_ptr + 1 ;
+ lp->rr.fdb_ptr = dblk_ptr + 2 ; /* ASSUMPTION : */
+ lp->rr.idb_ptr = dblk_ptr + 2 ; /* no FS has both FDB & IDB */
+ }
+
+ /* Set up the loop environment structure */
+ lp->rr.filter_to_use = TF_KEEP_ALL_DATA ;
+ lp->seq_num = 1 ;
+ lp->tpos.tape_id = -1 ;
+ lp->tpos.tape_seq_num = -1 ;
+
+ /* allocate buffers for operation */
+
+ mem_save = BEC_GetReserveMem( cfg ) ;
+ max_buffs = BEC_GetMaxTapeBuffers( cfg ) ;
+ buff_size = BEC_GetTFLBuffSize( cfg ) ;
+
+ return_status = TF_AllocateTapeBuffers( mem_save, max_buffs, buff_size ) ;
+
+ if( return_status != SUCCESS ) {
+
+ LP_MsgError( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos, return_status, NULL, NULL, 0L ) ;
+
+ /* Free local allocations */
+ free( dblk_ptr ) ;
+ free( lp ) ;
+
+ return( return_status ) ;
+
+ }
+
+ /* indicate the start of the operation */
+ LP_MsgStartOP( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos ) ;
+
+ /* for each bsd */
+ do {
+
+ /* First attach to the drive */
+ dle_ptr = BSD_GetDLE( bsd_ptr ) ;
+ cfg = BSD_GetConfigData( bsd_ptr ) ;
+
+ lis_ptr->curr_bsd_ptr = bsd_ptr ;
+
+ /* Now attach to the dle */
+ if( ( return_status = FS_AttachToDLE( &lp->curr_fsys, dle_ptr, cfg, NULL, NULL ) ) == SUCCESS ) {
+
+ /* Set up the loop environment structure */
+ lp->get_spcl = TRUE ;
+ lp->seq_num = 1 ;
+ lp->start_new_dir = TRUE ;
+ lp->get_first_file = TRUE ;
+ lp->get_next_first_time = TRUE ;
+ lp->send_saved_block = FALSE ;
+ lp->curr_blk = &lp->dblk1 ;
+ lp->curr_ddb = &lp->dblk2 ;
+ lp->empty_blk = &lp->dblk3 ;
+ lp->blk_is_empty = TRUE ;
+ lp->ffr_inited = FALSE ;
+ lp->cat_enabled = (BOOLEAN)(BEC_GetCatalogLevel( cfg ) != CATALOGS_NONE) ;
+ /* Reset the PBA values in case one set is fully catalogged */
+ /* and another is not. */
+ lp->tpos.tape_loc.pba_vcb = 0 ;
+ lp->rr.tape_loc.pba_vcb = 0 ;
+ lp->tpos.tape_loc.lba = 0 ;
+ lp->rr.tape_loc.lba = 0 ;
+ lp->tpos.UI_TapePosRoutine = lis_ptr->tape_pos_handler ;
+ lp->curr_dle = dle_ptr ;
+ lp->tpos.tape_cat_ver = BSD_GetTapeCatVer( bsd_ptr ) ;
+
+ sdrv = LP_DetermineStartingTPDrv( lis_ptr->oper_type, bsd_ptr, &lp->tpos, lis_ptr->auto_det_sdrv ) ;
+
+ /* fill in the the set number before calling LP_RestoreDLE */
+
+ if ( reuse_bsd ) {
+ lp->tpos.backup_set_num ++ ;
+ /* In case any FSEs have been tagged as deleted by processing
+ the last set, make sure they are "real" now */
+ BSD_ClearDelete( bsd_ptr ) ;
+ }
+ else {
+
+ /* this is the first time we are looking at this BSD */
+
+ if ( BSD_GetSetNum( bsd_ptr ) < 0 ) {
+
+ /* Set reuse indicator based upon whether another
+ bsd is in the queue */
+
+ temp_bsd_ptr = BSD_GetNext( bsd_ptr );
+ if ( temp_bsd_ptr != NULL ) {
+ reuse_bsd = FALSE;
+ }
+ else {
+ reuse_bsd = TRUE;
+ }
+
+ if ( BSD_GetSetNum( bsd_ptr ) == -1 ) {
+ /* negative one means the current set and all following sets */
+ if( first_time ) {
+ lp->tpos.backup_set_num = -1;
+ } else {
+ lp->tpos.backup_set_num++ ;
+ }
+ }
+ else {
+
+ /* -2 means set 2 and all the following sets */
+ /* -3 " " 3 " " " " " */
+ /* and so on */
+
+ lp->tpos.backup_set_num = (-BSD_GetSetNum( bsd_ptr ) ) ;
+ }
+ }
+ else {
+ lp->tpos.backup_set_num = BSD_GetSetNum( bsd_ptr ) ;
+ }
+ }
+
+ if( !tape_opened ) {
+ /* open the tape for operation */
+ tape_opened = TRUE ;
+ if( ( return_status = TF_OpenTape( &channel_no, sdrv, &lp->tpos ) ) != SUCCESS ) {
+ LP_MsgError( lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, return_status, NULL, NULL, 0L ) ;
+ }
+ }
+
+ if( return_status == SUCCESS ) {
+
+ /* Perform the operation */
+ return_status = LP_RestoreDLE( bsd_ptr, lp, reuse_bsd, channel_no, sdrv ) ;
+
+ if ( reuse_bsd && ( ( return_status == TFLE_UI_HAPPY_ABORT ) || ( return_status == TFLE_USER_ABORT ) ) && !( first_time ) ) {
+
+ /* we've hit the end of a tape that we were restoring unknown sets from */
+
+ reuse_bsd = FALSE ;
+
+ /* filter out the error */
+ return_status = SUCCESS ;
+ }
+
+ /* The following condition is used to fix the prompt for
+ 2nd tape in a multiple tape restore/verify with
+ restore that tape 1 contains uncataloged backup sets
+ or with the possibility of containing uncataloged
+ backup sets */
+
+ if ( return_status == TFLE_UI_HAPPY_ABORT ) {
+ temp_bsd_ptr = BSD_GetNext( bsd_ptr ) ;
+ if ( temp_bsd_ptr != NULL ) {
+ return_status = SUCCESS ;
+ }
+ }
+
+ first_time = FALSE ;
+
+ FS_DetachDLE( lp->curr_fsys ) ; /* $$$ ??? checking return value */
+ }
+
+ } else if( return_status != USER_ABORT ) {
+
+ /* error attaching to the drive, just go on to next drive, if there is one */
+ LP_MsgError( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos, LP_DRIVE_ATTACH_ERROR, NULL, NULL, 0L ) ;
+
+ /* reset return_status, and try the next bsd */
+ return_status = SUCCESS ;
+ }
+
+ if ( ! reuse_bsd ) {
+ bsd_ptr = BSD_GetNext( bsd_ptr ) ;
+ }
+
+ /* Continue, as long as we did not have an error, and we can get a new bsd */
+ } while( !return_status && ( bsd_ptr != NULL ) ) ;
+
+ if( tape_opened ) {
+ TF_CloseTape( channel_no ) ;
+ }
+
+ /* Deinit operation buffers */
+ if( ( status = TF_FreeTapeBuffers( ) ) != SUCCESS ) {
+ LP_MsgError( lis_ptr->pid, lis_ptr->curr_bsd_ptr, NULL, &lp->tpos,
+ status, NULL, NULL, 0L ) ;
+ }
+
+ /* indicate the end of the operation */
+ LP_MsgEndOP( lis_ptr->pid, lis_ptr->curr_bsd_ptr, NULL, &lp->tpos ) ;
+
+ /* Free local allocations */
+ free( dblk_ptr ) ;
+ free( lp ) ;
+
+ return( return_status ) ;
+}
diff --git a/private/utils/ntbackup/src/lprintf.c b/private/utils/ntbackup/src/lprintf.c
new file mode 100644
index 000000000..37bca761d
--- /dev/null
+++ b/private/utils/ntbackup/src/lprintf.c
@@ -0,0 +1,610 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: lprintf.c
+
+ Description: Functions for log file support
+
+ $Log: G:\UI\LOGFILES\LPRINTF.C_V $
+
+ Rev 1.26 14 Dec 1993 09:14:40 MikeP
+fix msoft logfiles to always append
+
+ Rev 1.25 26 Jul 1993 17:51:50 MARINA
+enable c++
+
+ Rev 1.24 10 May 1993 09:20:24 chrish
+NOSTRADAMUS EPR 0401: Fixed the problem of the "backup.log" always being
+appended to. Fixed such that when a new session of the app is invoked it
+replaces the the log rather than append to it.
+
+ Rev 1.23 31 Mar 1993 17:56:12 TIMN
+Doesn't log to logfile with DONT LOG selected EPR(unknown)
+
+ Rev 1.22 08 Feb 1993 15:44:54 chrish
+Change in lresprintf routine to allow directory information on
+detail as well as summary logging selected.
+
+ Rev 1.21 05 Nov 1992 17:09:18 DAVEV
+fix ts
+
+ Rev 1.19 07 Oct 1992 14:50:38 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.18 04 Oct 1992 19:38:42 DAVEV
+Unicode Awk pass
+
+ Rev 1.17 28 Jul 1992 14:48:08 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.16 10 Jun 1992 12:40:54 JOHNWT
+bug out if verify/skipped for msoft
+
+ Rev 1.15 19 May 1992 13:01:20 MIKEP
+mips changes
+
+ Rev 1.14 14 May 1992 16:51:10 MIKEP
+nt pass 2
+
+ Rev 1.13 28 Apr 1992 08:32:58 ROBG
+Took tab out of the logging of multiple file names on a single line.
+
+ Rev 1.12 06 Apr 1992 13:28:26 GLENN
+Fixed new-line problem for all log files.
+
+ Rev 1.11 31 Mar 1992 11:32:34 DAVEV
+OEM_MSOFT:do not attempt to open log file if none specified
+
+ Rev 1.10 20 Mar 1992 12:38:42 DAVEV
+Changes for OEM_MSOFT product alternate functionality
+
+ Rev 1.9 18 Mar 1992 11:58:00 ROBG
+Fixed problem when more than one log file is opened and
+the names are misused.
+
+ Rev 1.8 18 Mar 1992 09:38:24 ROBG
+Modified the New Page after closing of a log file to New Line.
+
+ Rev 1.7 18 Mar 1992 09:33:18 DAVEV
+changes for OEM_MSOFT log files
+
+ Rev 1.6 25 Feb 1992 21:32:04 GLENN
+Changed log file name to be created only if not prev created.
+
+ Rev 1.5 18 Feb 1992 15:43:08 ROBG
+Modified UI_TruncateString call Not to set blanks to 0xFF.
+
+ Rev 1.4 03 Feb 1992 16:57:38 ROBG
+Added debug line when closing the log file.
+
+ Rev 1.3 20 Jan 1992 12:58:36 MIKEP
+disk full error
+
+ Rev 1.2 16 Jan 1992 11:23:48 DAVEV
+16/32 bit port-2nd pass
+
+ Rev 1.1 10 Jan 1992 16:24:54 CARLS
+removed strings
+
+ Rev 1.0 20 Nov 1991 19:30:02 SYSTEM
+Initial revision.
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+/* Defined logging output lookup table for various output files */
+
+LOG_DEST output_dest[ NUM_DEST_TYPES ] = {
+ { /* Log file */
+ NULL,
+ 0xff,
+ },
+ { /* corrupt file */
+ NULL,
+ LOG_APPEND,
+ },
+ { /* debug log file */
+ NULL,
+ LOG_APPEND,
+ },
+ { /* skipped file */
+ NULL,
+ LOG_APPEND,
+ },
+ { /* verify file */
+ NULL,
+ LOG_APPEND,
+ }
+};
+
+static CHAR_PTR GetResId( INT, INT );
+static VOID OpenLog( INT );
+static VOID DetermineLogFileName( CHAR_PTR, INT );
+static CHAR log_name[ MAX_UI_PATH_SIZE ];
+
+/*****************************************************************************
+
+ Name: OpenLog
+
+ Description: Init the logging capability, disk file or printer
+
+ Returns: (void)
+
+ Notes: Called indirectly from a call to lresprintf with the
+ "LOG_START" message. Log file is opened in append mode
+ always except upon the first entry if the permanent
+ configuration specified to overwrite the log.
+
+*****************************************************************************/
+static VOID OpenLog( INT index )
+{
+ CDS_PTR conf_ptr = CDS_GetCopy( );
+ BOOLEAN append = CDS_GetLogMode( conf_ptr );
+ CHAR open_mode[ 2 ];
+ INT open_mode_UNI ;
+
+ msassert( index < NUM_DEST_TYPES );
+
+ // Determine file name based on the type of log file.
+ // Determine the name if not the session log file.
+
+ if ( index ) {
+ DetermineLogFileName( log_name, index );
+ } else {
+
+ // For the process log file only, use the previous defined.
+
+ strcpy( log_name, LOG_GetCurrentLogName() ) ;
+ }
+
+ /* Determine file open mode */
+
+ if ( output_dest[index].mode == 0xff ) { // For log file only.
+
+ DetermineLogFileName( log_name, index );
+
+#ifdef OEM_MSOFT
+
+ // According to Steve, microsoft wants it to always append. mikep 12/12/93
+
+ strcpy( open_mode, TEXT("a") );
+ open_mode_UNI = _O_TEXT|_O_APPEND ;
+#else
+ strcpy( open_mode, ( append ? TEXT("a"):TEXT("w") ) );
+ if ( append ) {
+ open_mode_UNI = _O_TEXT|_O_APPEND ;
+ }
+#endif
+
+ CDS_SetLogMode( conf_ptr, 1 ); /* set runtime config to append mode */
+ output_dest[index].mode = LOG_APPEND;
+
+ }
+ else {
+
+ if ( output_dest[index].mode == LOG_APPEND ) {
+ strcpy( open_mode, TEXT("a") );
+ open_mode_UNI = _O_TEXT|_O_APPEND ;
+ }
+ else {
+ open_mode_UNI = _O_TEXT;
+ strcpy( open_mode, TEXT("w") );
+ }
+ }
+
+# if defined ( OEM_MSOFT ) // special feature
+ {
+ if ( !*log_name )
+ {
+ return; // no log file to open!
+ }
+ }
+# endif //defined ( OEM_MSOFT ) // special feature
+
+ zprintf( DEBUG_USER_INTERFACE, RES_OPENING_LOG_NAME, log_name, open_mode[0] );
+
+ if ( ( output_dest[index].fh = UNI_fopen( log_name, open_mode_UNI ) ) == NULL ) {
+ eresprintf( RES_OPEN_LOG_ERROR, log_name );
+ }
+
+ return;
+
+}
+/*****************************************************************************
+
+ Name: lresprintf
+
+ Description: Entry point for logging information to log file/printer
+
+ Returns: (void)
+
+*****************************************************************************/
+VOID lresprintf( INT index, INT message, ... )
+{
+ INT res_session; /* resource session for format */
+ INT res_id; /* variable argument resource id # */
+ CHAR buffer[ UI_MAX_DETAIL_LENGTH ]; /* temporary filename */
+ FSYS_HAND fsh; /* variable argument file system handle */
+ DBLK_PTR dblk_ptr; /* variable argument dblock pointer */
+ CHAR_PTR fmt; /* resource format string */
+ va_list arg_ptr; /* variable argument pointer */
+ CDS_PTR conf_ptr = CDS_GetCopy( ); /* working copy config */
+ static UINT16 num_files[ NUM_DEST_TYPES ]; /* counters for wide logging of files */
+ static BOOLEAN OS_flag = TRUE; /* indicate how to build file details */
+ CHAR text[ MAX_UI_RESOURCE_SIZE ];
+ CHAR title[ MAX_UI_RESOURCE_SIZE ];
+ CHAR_PTR stream_name ;
+
+ msassert( index < NUM_DEST_TYPES );
+
+ if ( ( index == LOGGING_FILE ) && ( CDS_GetOutputDest( conf_ptr ) == LOG_NOWHERE ) ||
+ ( index == LOGGING_FILE ) && ( CDS_GetLogLevel( conf_ptr ) == LOG_DISABLED ) ||
+ ( index == DEBUG_LOG_FILE ) ) {
+ return;
+ }
+
+#if defined ( OEM_MSOFT ) // not supported
+
+ if ( ( index == VERIFY_FILE ) || ( index == SKIPPED_FILE ) ) {
+ return;
+ }
+
+#endif //defined ( OEM_MSOFT )
+
+ va_start( arg_ptr, message );
+
+ switch( message ) {
+
+ case LOG_DIRECTORY:
+// chs:02-03-93 if( CDS_GetLogLevel( conf_ptr ) > LOG_ERRORS ) {
+
+ //
+ // Allow the directory information when detail or summary
+ // logging was selected by the user.
+ //
+
+ if( CDS_GetLogLevel( conf_ptr ) >= LOG_ERRORS ) { // chs: 02-03-93
+ res_session = va_arg( arg_ptr, INT );
+ res_id = va_arg( arg_ptr, INT );
+ fmt = GetResId ( res_session, res_id );
+
+ if( num_files[ index ] ) { /* force a blank line and reset counter */
+ lprintf ( index, TEXT("\n") );
+ num_files[ index ] = 0;
+ }
+ lvprintf( index, fmt, arg_ptr );
+ lprintf( index, TEXT("\n") );
+ }
+ break;
+
+ case LOG_FILE:
+ /* get additional arguments first */
+ fsh = va_arg( arg_ptr, FSYS_HAND );
+ dblk_ptr = va_arg( arg_ptr, DBLK_PTR );
+ if( CDS_GetLogLevel( conf_ptr ) == LOG_FILES ) {
+ /* log filenames only */
+ if ( OS_flag ) {
+ FS_GetOSFnameFromFDB( fsh, dblk_ptr, buffer );
+ } else {
+ FS_GetFnameFromFDB( fsh, dblk_ptr, buffer );
+ }
+ UI_TruncateString( buffer, (UINT16)UI_MAX_WIDE_FILE_DISPLAY, FALSE );
+ if( num_files[ index ] >= 5 ) { /* advance to next line */
+ lprintf( index, TEXT("\n") );
+ num_files[ index ] = 0;
+ }
+#ifndef UNICODE
+ lprintf( index, TEXT("%-15s"), buffer );
+#else //UNICODE
+ lprintf( index, TEXT("%-15ws"), buffer );
+#endif //UNICODE
+ num_files[ index ]++;
+ } else if ( CDS_GetLogLevel( conf_ptr ) == LOG_DETAIL ) {
+ /* log filenames and detail also */
+ UI_BuildFileDetail( buffer, fsh, dblk_ptr, OS_flag );
+ lprintf( index, TEXT("%s"), buffer );
+ }
+ break;
+
+ case LOG_STREAM:
+ fsh = va_arg( arg_ptr, FSYS_HAND );
+ stream_name = va_arg( arg_ptr, CHAR_PTR );
+ if( CDS_GetLogLevel( conf_ptr ) == LOG_DETAIL ) {
+
+ lprintf ( index, stream_name );
+ lprintf ( index, TEXT("\n") );
+ }
+
+ break;
+
+ case LOG_MSG:
+ case LOG_ERROR:
+ case LOG_WARNING:
+ res_session = va_arg( arg_ptr, INT );
+ res_id = va_arg( arg_ptr, INT );
+ fmt = GetResId ( res_session, res_id );
+
+ // Advance to next line.
+
+ if( num_files[ index ] ) { /* force a blank line and reset counter */
+ lprintf ( index, TEXT("\n") );
+ num_files[ index ] = 0;
+ }
+
+ lvprintf( index, fmt, arg_ptr );
+ lprintf ( index, TEXT("\n") );
+
+ break;
+
+ case LOG_START:
+ OS_flag = va_arg( arg_ptr, BOOLEAN );
+ OpenLog( index );
+ gb_logging_error = FALSE;
+
+ // Reset the number of files for this index.
+
+ num_files[ index ] = 0;
+
+ break;
+
+ case LOG_END:
+
+ if ( gb_logging_error ) {
+
+ // Tell user disk was full.
+
+ RSM_StringCopy ( IDS_VLMLOGERROR, title, MAX_UI_RESOURCE_LEN );
+ RSM_StringCopy ( IDS_VLMLOGFULLERROR, text, MAX_UI_RESOURCE_LEN );
+
+ WM_MsgBox( title,
+ text,
+ WMMB_OK, WMMB_ICONINFORMATION );
+ }
+
+ if ( output_dest[index].fh != NULL ) {
+ if ( index <= CORRUPT_FILE ) {
+ fprintf( output_dest[index].fh, TEXT("\n") ); /* send new line */
+ }
+
+ zprintf( DEBUG_USER_INTERFACE, RES_CLOSING_LOG_NAME, log_name );
+
+ fclose( output_dest[index].fh );
+
+ // Refresh the Log Files Window.
+
+ LOG_Refresh();
+
+ output_dest[index].fh = NULL;
+
+# if defined ( OEM_MSOFT ) //special feature
+ {
+ if ( index == 0 ) // if Log file
+ {
+ output_dest[index].mode = 0xff; //reset log file info
+ }
+ }
+# endif //defined ( OEM_MSOFT ) //special feature
+
+ }
+ break;
+
+ default:
+ eresprintf( RES_UNKNOWN_LOG_MSG, message );
+ break;
+ }
+
+ va_end( arg_ptr );
+ return;
+}
+
+/*****************************************************************************
+
+ Name: GetResId
+
+ Description: Performs calls to Resource Manager to load a specific
+ session and a specific resource
+
+ Returns: CHAR_PTR to requested resource, asserts if not found
+
+ Notes: Desired session should already be loaded, if resource is
+ not found, inconsistencies exist in resource file so
+ an assert is done.
+
+*****************************************************************************/
+CHAR_PTR GetResId( INT res_session, INT res_id )
+{
+ UINT16 num_resources;/* number of resource items */
+ UINT16 error; /* resource manager error */
+ CHAR_PTR fmt; /* resource format string read */
+
+ fmt = (LPSTR)RM_GetResource( rm, (UINT) res_session, (UINT) res_id, &num_resources, &error );
+ msassert( error == RM_NO_ERROR );
+
+ return( fmt );
+}
+/*****************************************************************************
+
+ Name: lprintf
+
+ Description: Log printf function that accepts a format string and a
+ variable list of arguments and calls lvprintf to perform
+ actual logging
+
+ Returns: (void)
+
+*****************************************************************************/
+VOID lprintf( INT index, CHAR_PTR fmt, ... )
+{
+ va_list arg_ptr;
+
+ msassert( index < NUM_DEST_TYPES );
+
+#if defined ( OEM_MSOFT ) // not supported
+
+ if ( ( index == VERIFY_FILE ) || ( index == SKIPPED_FILE ) ) {
+ return;
+ }
+
+#endif //defined ( OEM_MSOFT )
+
+ va_start( arg_ptr, fmt );
+
+ lvprintf( index, fmt, arg_ptr );
+
+ va_end( arg_ptr );
+
+ return;
+
+}
+/*****************************************************************************
+
+ Name: lvprintf
+
+ Description: Performs call to vfprintf with log file handle,
+ format string and list of variable arguments to be
+ written to the log file
+
+ Returns: (void)
+
+*****************************************************************************/
+VOID lvprintf(
+INT index,
+CHAR_PTR fmt,
+va_list arg_ptr )
+{
+ msassert( index < NUM_DEST_TYPES );
+
+ if ( output_dest[index].fh != NULL && gb_logging_error != TRUE ) {
+
+ gb_logging = NOW_LOGGING;
+ if (IS_JAPAN() ) {
+ CHAR wBuff[MAX_UI_RESOURCE_SIZE];
+ char aBuff[MAX_UI_RESOURCE_SIZE*2];
+ BOOL fDefCharUsed;
+ int iRet;
+
+ wvsprintf( wBuff, fmt, arg_ptr );
+ iRet = WideCharToMultiByte(CP_ACP, 0, (WCHAR *)wBuff, -1, aBuff,
+ MAX_UI_RESOURCE_SIZE*2, NULL, &fDefCharUsed );
+ if( !iRet ) {
+ gb_logging_error = TRUE;
+ } else{
+ fwrite(aBuff, 1, iRet, output_dest[index].fh);
+ }
+
+ } else {
+ vfprintf( output_dest[index].fh, fmt, arg_ptr );
+ }
+
+ if ( ferror( output_dest[index].fh ) ) {
+
+ gb_logging_error = TRUE;
+ }
+
+ if ( gb_logging == STOP_LOGGING ) {
+
+ fclose( output_dest[index].fh );
+
+ output_dest[index].fh = NULL;
+ }
+
+ clearerr( output_dest[index].fh );
+
+ gb_logging = NOT_LOGGING;
+ }
+
+ return;
+
+}
+/*****************************************************************************
+
+ Name: LogFileExists
+
+ Description: Determines if a log file exists or not
+
+ Returns: TRUE if the file was found on disk
+ FALSE if the file was not found
+
+*****************************************************************************/
+BOOLEAN LogFileExists( INT index )
+{
+ CHAR log_name[ UI_MAX_PATH_LENGTH + UI_MAX_FILENAME_LENGTH ];
+
+ msassert( index < NUM_DEST_TYPES );
+
+ DetermineLogFileName( log_name, index );
+
+ return (BOOLEAN)( ( access( log_name, 0 ) == 0 ) ? TRUE : FALSE );
+
+}
+/*****************************************************************************
+
+ Name: DetermineLogFileName
+
+ Description:
+
+ Returns: VOID
+
+ Notes: Call is responsible for memory associated with name string
+
+*****************************************************************************/
+static VOID DetermineLogFileName(
+CHAR_PTR pLogName,
+INT nIndex )
+{
+ CDS_PTR pCDS = CDS_GetCopy( );
+
+ msassert( nIndex < NUM_DEST_TYPES );
+
+ switch ( nIndex ) {
+
+ case LOGGING_FILE:
+
+ if ( CDS_GetOutputDest( pCDS ) == LOG_TO_FILE ) {
+
+ strcpy ( pLogName, LOG_GetCurrentLogName () );
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+ {
+ if ( ! strlen ( pLogName ) ) {
+ LOG_GenerateLogFileName ( pLogName );
+ }
+ }
+# endif //!defined ( OEM_MSOFT ) // unsupported feature
+ }
+
+ break;
+
+ case CORRUPT_FILE:
+ strcpy( pLogName, CDS_GetUserDataPath( ) );
+ strcat( pLogName, CORRUPT_LOG );
+ strcat( pLogName, LST_EXT );
+ break;
+
+ case DEBUG_LOG_FILE:
+ strcpy( pLogName, CDS_GetUserDataPath( ) );
+ strcat( pLogName, DEBUG_LOG );
+ strcat( pLogName, LOG_EXT );
+ break;
+
+ case SKIPPED_FILE:
+ strcpy( pLogName, CDS_GetUserDataPath( ) );
+ strcat( pLogName, SKIPPED_LOG );
+ strcat( pLogName, BKS_EXT );
+ break;
+
+ case VERIFY_FILE:
+ strcpy( pLogName, CDS_GetUserDataPath( ) );
+ strcat( pLogName, VERIFY_LOG );
+ strcat( pLogName, BKS_EXT );
+ break;
+ }
+
+ return;
+}
diff --git a/private/utils/ntbackup/src/lptools.c b/private/utils/ntbackup/src/lptools.c
new file mode 100644
index 000000000..4a5b0f3de
--- /dev/null
+++ b/private/utils/ntbackup/src/lptools.c
@@ -0,0 +1,837 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: lptools.c
+
+ Description: this module contains the loop tools used by the loops layer.
+
+ $Log: T:/LOGFILES/LPTOOLS.C_V $
+
+ Rev 1.32 13 Mar 1993 17:09:42 GREGG
+Changed LP_SendDataEnd back to the old method of always setting buff_used to 0.
+
+ Rev 1.31 11 Mar 1993 12:43:38 STEVEN
+fix bugs found by GREGG
+
+ Rev 1.30 14 Jan 1993 13:34:00 STEVEN
+added stream_id to error message
+
+ Rev 1.29 20 Nov 1992 12:57:00 STEVEN
+added support for skip stream filter
+
+ Rev 1.28 20 Nov 1992 10:38:24 STEVEN
+added suport for continue VCB message
+
+ Rev 1.27 04 Nov 1992 17:29:48 STEVEN
+fix typo
+
+ Rev 1.26 04 Nov 1992 13:23:54 STEVEN
+fix various bugs with read
+
+ Rev 1.25 27 Oct 1992 12:10:48 STEVEN
+if we send new stream then return
+
+ Rev 1.24 21 Oct 1992 16:23:02 STEVEN
+forgot the case statement
+
+ Rev 1.23 15 Oct 1992 10:01:46 STEVEN
+added new stream message
+
+ Rev 1.22 13 Oct 1992 17:26:22 STEVEN
+oops I forgot the TRR_END message
+
+ Rev 1.21 13 Oct 1992 17:20:24 STEVEN
+save old tf message
+
+ Rev 1.20 23 Jul 1992 16:44:48 STEVEN
+fix warnings
+
+ Rev 1.19 23 Jul 1992 12:10:12 STEVEN
+fix warnings
+
+ Rev 1.18 06 Jul 1992 09:39:10 STEVEN
+fix typo
+
+ Rev 1.17 21 May 1992 17:20:30 TIMN
+Converted CHARs to INT8
+
+ Rev 1.16 13 May 1992 12:35:36 TIMN
+Added TEXT() macro to literals, but not msassert literals
+
+ Rev 1.15 13 May 1992 12:00:34 STEVEN
+40 format changes
+
+ Rev 1.14 04 Feb 1992 22:22:00 GREGG
+Don't restart clock in ProcessEOM until after tape request returns.
+
+ Rev 1.13 25 Jan 1992 15:04:02 GREGG
+Removed loop around GetNxetTapeRequest in ProcessEOM so he only calls it
+once, and leaves it up to the caller to decide what to do with the response.
+
+ Rev 1.12 16 Jan 1992 15:11:00 STEVEN
+fix warnings for WIN32
+
+ Rev 1.11 19 Dec 1991 16:32:08 BARRY
+Clear buffer used when sending END_DATA message.
+
+ Rev 1.10 25 Oct 1991 15:58:06 GREGG
+TRICYCLE - Re-switch after calls to ProcessEOM.
+
+ Rev 1.9 18 Oct 1991 14:06:36 STEVEN
+TRICYCLE-added function for end of varible length file
+
+ Rev 1.8 18 Oct 1991 14:02:42 STEVEN
+BIGWHEEL-fixed bug where we asserted
+
+ Rev 1.7 18 Oct 1991 11:34:12 STEVEN
+BIGWHEEL-add parameter to message prompt
+
+ Rev 1.6 16 Aug 1991 17:11:26 STEVEN
+Could not Verify or Restore multiple sets
+
+ Rev 1.5 27 Jun 1991 13:06:20 STEVEN
+removed unused parm to ReceiveData
+
+ Rev 1.4 21 Jun 1991 08:45:40 STEVEN
+new config unit
+
+ Rev 1.3 17 Jun 1991 16:28:14 STEVEN
+LP_PadData is called from lptools.c so it was moved to there
+
+ Rev 1.2 30 May 1991 09:10:52 STEVEN
+bsdu_err.h no longer exists
+
+ Rev 1.1 24 May 1991 13:12:10 STEVEN
+changed to ANSI prototypes
+
+ Rev 1.0 09 May 1991 13:37:56 HUNTER
+Initial revision.
+
+**/
+#include <string.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "msassert.h"
+#include "tbe_err.h"
+#include "tbe_defs.h"
+#include "tflproto.h"
+#include "tfldefs.h"
+#include "bsdu.h"
+#include "fsys.h"
+#include "queues.h"
+#include "loops.h"
+#include "loop_prv.h"
+#include "get_next.h"
+#include "be_debug.h"
+
+/* internal function prototypes */
+INT16 LP_ProcessEOM( LP_ENV_PTR lp, UINT16 tf_message ) ;
+
+/* Static table of values for LP_Send( ) when sending DBLK, not data */
+static UINT16 loops_messages[] = {
+
+ 0,
+ LRW_VCB,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ LRW_DDB,
+ LRW_FDB,
+ LRW_IDB,
+ LRW_CFDB } ;
+
+/**/
+/**
+
+ Name: LP_StartTPEDialogue()
+
+ Description: this routine starts the dialogue with the tape format.
+
+ Modified: 5/24/1991 12:47:11
+
+ Returns: SUCCESS or the error returned by Tape Format
+
+ Notes: none
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+INT16 LP_StartTPEDialogue(
+register LP_ENV_PTR lp, /* I - loop environment pointer */
+BOOLEAN write ) /* I - TRUE if starting for write */
+{
+ INT16 return_status = SUCCESS ;
+ INT16 msg_err_stat ;
+
+ if( lp->lis_ptr != NULL ) {
+
+ if( LP_AbortFlagIsSet( lp->lis_ptr ) ) {
+
+ return TFLE_USER_ABORT ;
+
+ }
+ }
+
+ /* start dialogue with tape format */
+ lp->rr.lp_message = (INT16)(( write ) ? LRW_START : LRR_START) ;
+ lp->rr.cur_dblk = lp->curr_blk ;
+
+ if( ( return_status = TF_GetNextTapeRequest( &lp->rr ) ) == SUCCESS ) {
+
+ switch( lp->rr.tf_message ) {
+
+ default:
+ break ;
+
+ case TRR_FATAL_ERR:
+ case TRW_FATAL_ERR:
+ case TRR_DATA:
+ case TRW_DATA:
+ case TRR_EOM:
+ case TRW_EOM:
+ msassert( FALSE ) ;
+ break ;
+
+ }
+ }
+ else {
+ if( ( msg_err_stat = LP_MsgError( lp->lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, lp->curr_fsys, &lp->tpos, return_status, NULL, NULL, 0L ) ) != MSG_ACK ) {
+ return( msg_err_stat ) ;
+ }
+ }
+
+ return( return_status ) ;
+
+}
+
+/**/
+/**
+
+ Name: LP_Send()
+
+ Description: this routine sends a descriptor block or data to the tape format.
+
+ Modified: 5/24/1991 12:47:34
+
+ Returns: SUCCESS or the error returned by Tape Format
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+INT16 LP_Send(
+register LP_ENV_PTR lp, /* I - loop environment structure */
+BOOLEAN data_flag ) /* I - True if we are in data phase */
+{
+ INT16 return_status = SUCCESS ;
+ INT16 msg_err_stat ;
+ BOOLEAN request_made = FALSE ;
+
+ if( LP_AbortFlagIsSet( lp->lis_ptr ) ) {
+
+ return TFLE_USER_ABORT ;
+
+ }
+
+ if( ( msg_err_stat = LP_MsgIdle( lp->lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, lp->curr_fsys, &lp->tpos ) ) != MSG_ACK ) {
+ return( msg_err_stat ) ;
+ }
+
+ /* set loop message */
+ if ( data_flag ) {
+
+ if ( lp->rr.stream.id != STRM_INVALID ) {
+
+ lp->current_stream_size = lp->rr.stream.size ;
+ lp->current_stream_id = lp->rr.stream.id ;
+ lp->rr.lp_message = LRW_NEW_STREAM ;
+ return_status = TF_GetNextTapeRequest( &lp->rr ) ;
+ request_made = TRUE ;
+
+ } else {
+ lp->rr.lp_message = LRW_DATA ;
+ }
+
+ } else {
+ lp->rr.lp_message = loops_messages[ FS_GetBlockType( lp->rr.cur_dblk ) ] ;
+ }
+
+ lp->rr.requested_size = 0 ; /* only to be used during reads */
+
+ if ( !request_made ) {
+ return_status = TF_GetNextTapeRequest( &lp->rr ) ;
+ }
+
+ if ( return_status == SUCCESS ) {
+
+ switch( lp->rr.tf_message ) {
+
+ default:
+ break ;
+
+ case TRW_EOM:
+ return_status = LP_ProcessEOM( lp, TRW_EOM ) ;
+ break ;
+
+ case TRW_FATAL_ERR:
+ msassert( FALSE ) ;
+ break ;
+
+ }
+ }
+ else {
+ if( ( msg_err_stat = LP_MsgError( lp->lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, lp->curr_fsys, &lp->tpos, return_status, NULL, NULL, 0L ) ) != MSG_ACK ) {
+ return( msg_err_stat ) ;
+ }
+ }
+
+ return( return_status ) ;
+
+}
+/**/
+/**
+
+ Name: LP_SendDataEnd()
+
+ Description: this routine sends a end data message to tape format.
+
+ Modified: 5/24/1991 12:47:34
+
+ Returns: SUCCESS or the error returned by Tape Format
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+INT16 LP_SendDataEnd(
+register LP_ENV_PTR lp ) /* I - loop environment structure */
+{
+ INT16 return_status = SUCCESS ;
+ INT16 msg_err_stat ;
+
+ /* set loop message */
+ lp->rr.lp_message = LRW_DATA_END ;
+ lp->rr.buff_used = 0 ;
+ lp->rr.requested_size = 0 ; /* only to be used during reads */
+
+ if( ( return_status = TF_GetNextTapeRequest( &lp->rr ) ) == SUCCESS ) {
+
+ switch( lp->rr.tf_message ) {
+
+ default:
+ break ;
+
+ case TRW_EOM:
+ return_status = LP_ProcessEOM( lp, TRW_EOM ) ;
+ break ;
+
+ case TRW_FATAL_ERR:
+ msassert( FALSE ) ;
+ break ;
+
+ }
+ }
+ else {
+ if( ( msg_err_stat = LP_MsgError( lp->lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, lp->curr_fsys, &lp->tpos, return_status, NULL, NULL, 0L ) ) != MSG_ACK ) {
+ return( msg_err_stat ) ;
+ }
+ }
+
+ return( return_status ) ;
+}
+
+/**/
+/**
+
+ Name: LP_ReceiveDBLK()
+
+ Description:
+
+ Modified: 5/24/1991 12:48:54
+
+ Returns: SUCCESS or the error returned by Tape Format
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+INT16 LP_ReceiveDBLK(
+register LP_ENV_PTR lp ) /* I - Loop Environment structre */
+{
+ INT16 return_status = SUCCESS ;
+ INT16 msg_err_stat ;
+ DBLK_PTR temp_ptr ;
+ CHAR crrpt_blk_fname[ 13 ] ; /* $$$ literal ??? MAX_FNAME_LEN ??? */
+ INT16 crrpt_blk_fname_leng ;
+ GEN_FDB_DATA gfdb_data ;
+ BOOLEAN done = FALSE ;
+
+ if( LP_AbortFlagIsSet( lp->lis_ptr ) ) {
+
+ return TFLE_USER_ABORT ;
+
+ }
+
+ /* Let everyone know we are here */
+ if( ( msg_err_stat = LP_MsgIdle( lp->lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, lp->curr_fsys, &lp->tpos ) ) != MSG_ACK ) {
+ return( msg_err_stat ) ;
+ }
+
+ if ( lp->blk_is_empty ) {
+
+ lp->rr.cur_dblk = lp->empty_blk ;
+
+ if( ( return_status = TF_GetNextTapeRequest( &lp->rr ) ) == SUCCESS ) {
+
+ /* This loop is for the EOM case. We call ProcessEOM and it does
+ another GetNextTapeRequest so we need to re-switch on the new
+ tf_message.
+ */
+ while( !done && return_status == SUCCESS ) {
+
+ done = TRUE ;
+
+ switch( lp->rr.tf_message ) {
+
+ default:
+ break ;
+
+ case TRR_END:
+ /* end of set */
+ break ;
+
+ case TRR_DATA_END:
+ if( lp->rr.error_locus == TF_ERROR_BLK_WAS_FDB ) {
+ /* data dumped to disk was associated with a FDB */
+ LP_MsgRecFDB( lp->lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, lp->curr_fsys, &lp->tpos ) ;
+
+ } else if( lp->rr.error_locus == TF_ERROR_BLK_WAS_DDB ) {
+ /* data dumped to disk was associated with a DDB */
+ LP_MsgRecDDB( lp->lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, lp->curr_fsys, &lp->tpos ) ;
+ }
+ break ;
+
+ case TRR_RECV_ERR:
+ lp->rr.tf_message = TRR_FDB ;
+
+ FS_SetDefaultDBLK( lp->curr_fsys, FDB_ID, ( CREATE_DBLK_PTR ) &gfdb_data ) ;
+ gfdb_data.std_data.dblk = lp->rr.cur_dblk ;
+ gfdb_data.std_data.disp_size = U64_Init(0,0) ; /* $$$ literal */
+
+ /* call message handler to prompt user for filename */
+ LP_MsgPrompt( lp->lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, lp->curr_fsys, &lp->tpos,
+ CORRUPT_BLOCK_PROMPT, crrpt_blk_fname, &crrpt_blk_fname_leng ) ;
+
+ gfdb_data.fname = crrpt_blk_fname ;
+ gfdb_data.fname_size = crrpt_blk_fname_leng ;
+ FS_CreateGenFDB( lp->curr_fsys, &gfdb_data ) ;
+ break ;
+
+ case TRR_EOM:
+ return_status = LP_ProcessEOM( lp, (UINT16)TRR_EOM ) ;
+ done = FALSE ; /* Switch Again! */
+ break ;
+
+ case TRR_FATAL_ERR:
+ case TRR_DATA:
+ msassert( FALSE ) ;
+ break ;
+
+ }
+ }
+ }
+ else {
+ if( ( msg_err_stat = LP_MsgError( lp->lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, lp->curr_fsys, &lp->tpos, return_status, NULL, NULL, 0L ) ) != MSG_ACK ) {
+ return( msg_err_stat ) ;
+ }
+ }
+ } else {
+ lp->rr.tf_message = lp->last_tape_message ;
+ }
+
+
+ temp_ptr = lp->empty_blk ;
+ lp->empty_blk = lp->curr_blk ;
+ lp->curr_blk = temp_ptr ;
+ lp->blk_is_empty = TRUE ;
+ lp->rr.filter_to_use = TF_KEEP_ALL_DATA ;
+
+ return( return_status ) ;
+
+}
+
+
+/**/
+/**
+
+ Name: LP_FinishedOper()
+
+ Description: Sends a Finished message to Tape format
+
+ Modified: 5/24/1991 12:49:46
+
+ Returns: the error returned by Tape Format
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+INT16 LP_FinishedOper(
+register LP_ENV_PTR lp ) /* I - Loop Environment structure */
+{
+ INT16 return_status = SUCCESS ;
+
+ if( LP_AbortFlagIsSet( lp->lis_ptr ) ) {
+
+ return TFLE_USER_ABORT ;
+
+ }
+
+ lp->rr.lp_message = LRR_FINISHED ;
+
+ return_status = TF_GetNextTapeRequest( &lp->rr ) ;
+
+ return( return_status ) ;
+
+}
+
+
+/**/
+/**
+
+ Name: LP_ReceiveData()
+
+ Description:
+
+ Modified: 5/24/1991 12:50:10
+
+ Returns: SUCCESS or the error returned by Tape Format
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+INT16 LP_ReceiveData(
+register LP_ENV_PTR lp, /* I - Loop environment strucutre */
+UINT32 amount_used ) /* I - Amount of last buffer used */
+{
+ INT16 return_status = SUCCESS ;
+ INT16 msg_err_stat ;
+ CHAR crrpt_blk_fname[ 13 ] ; /* $$$ literal ??? MAX_FNAME_LEN ??? */
+ INT16 crrpt_blk_fname_leng ;
+ GEN_FDB_DATA gfdb_data ;
+ BOOLEAN done = FALSE ;
+
+ if( LP_AbortFlagIsSet( lp->lis_ptr ) ) {
+
+ return TFLE_USER_ABORT ;
+
+ }
+
+ /* Let everyone know we are here */
+ if( ( msg_err_stat = LP_MsgIdle( lp->lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, lp->curr_fsys, &lp->tpos ) ) != MSG_ACK ) {
+ return( msg_err_stat ) ;
+ }
+
+ lp->rr.lp_message = LRR_STUFF ;
+ lp->rr.buff_used = ( UINT16 )amount_used ;
+ lp->rr.cur_dblk = lp->empty_blk ;
+ lp->rr.requested_size = 0 ;
+
+
+ if( ( return_status = TF_GetNextTapeRequest( &lp->rr ) ) == SUCCESS ) {
+
+ /* This loop is for the EOM case. We call ProcessEOM and it does
+ another GetNextTapeRequest so we need to re-switch on the new
+ tf_message.
+ */
+ while( !done && return_status == SUCCESS ) {
+
+ done = TRUE ;
+
+ switch( lp->rr.tf_message ) {
+
+ case TRR_FDB:
+ case TRR_DDB:
+ case TRR_CFDB:
+ case TRR_VCB:
+ case TRR_IDB:
+ lp->blk_is_empty = FALSE ;
+ lp->last_tape_message = lp->rr.tf_message ;
+ lp->rr.tf_message = TRR_DATA_END ;
+ break ;
+
+ case TRR_END:
+ /* end of set */
+ lp->blk_is_empty = FALSE ;
+ lp->last_tape_message = lp->rr.tf_message ;
+ lp->rr.tf_message = TRR_DATA_END ;
+ break ;
+
+ case TRR_RECV_ERR:
+ lp->tape_rd_error = TRUE ;
+
+ if( lp->rr.error_locus == TF_ERROR_IN_DBLK ) {
+ lp->rr.tf_message = TRR_FDB ;
+
+ FS_SetDefaultDBLK( lp->curr_fsys, FDB_ID, ( CREATE_DBLK_PTR ) &gfdb_data ) ;
+ gfdb_data.std_data.dblk = lp->rr.cur_dblk ;
+ gfdb_data.std_data.disp_size = U64_Init(0,0) ; /* $$$ literal */
+
+ /* call message handler to prompt user for filename */
+ LP_MsgPrompt( lp->lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, lp->curr_fsys, &lp->tpos,
+ CORRUPT_BLOCK_PROMPT, crrpt_blk_fname, &crrpt_blk_fname_leng ) ;
+
+ gfdb_data.fname = crrpt_blk_fname ;
+ gfdb_data.fname_size = crrpt_blk_fname_leng ;
+ FS_CreateGenFDB( lp->curr_fsys, &gfdb_data ) ;
+ }
+ else {
+ /* message informing user of data read error at offset */
+ LP_MsgDataLost( lp->lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, lp->curr_fsys, &lp->tpos,
+ lp->rr.error_file_offset, lp->rr.error_data_loss ) ;
+
+ lp->rr.tf_message = TRR_DATA ;
+ lp->rr.buff_size = lp->rr.error_data_loss ;
+
+ LP_PadData( lp->rr.buff_ptr, ( UINT32 )lp->rr.buff_size ) ;
+ }
+ break ;
+
+ case TRR_EOM:
+ return_status = LP_ProcessEOM( lp, (UINT16)TRR_EOM ) ;
+ done = FALSE ; /* Switch Again! */
+ break ;
+
+ case TRR_NEW_STREAM :
+ lp->current_stream_size = lp->rr.stream.size ;
+ lp->current_stream_id = lp->rr.stream.id ;
+ lp->rr.tf_message = TRR_DATA ;
+ break ;
+
+ case TRR_DATA :
+ lp->rr.stream.id = STRM_INVALID ;
+ break ;
+
+ case TRR_DATA_END :
+ default:
+ break ;
+
+ case TRR_FATAL_ERR:
+ msassert( FALSE ) ;
+ break ;
+
+ }
+ }
+ }
+ else {
+ if( ( msg_err_stat = LP_MsgError( lp->lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, lp->curr_fsys, &lp->tpos, return_status, NULL, NULL, 0L ) ) != MSG_ACK ) {
+ return( msg_err_stat ) ;
+ }
+ }
+
+ lp->rr.filter_to_use = TF_KEEP_ALL_DATA ;
+
+ return( return_status ) ;
+
+}
+
+
+/**/
+/**
+
+ Name: LP_ProcessEOM()
+
+ Description: Processes end of media condition
+
+ Modified: 5/24/1991 12:54:59
+
+ Returns: SUCCESS or the error returned by Tape Format
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 LP_ProcessEOM(
+LP_ENV_PTR lp, /* I - Loope Environment struct */
+UINT16 tf_message ) /* I - Message returne from tape format */
+{
+ INT16 return_status = SUCCESS ;
+ INT16 msg_err_stat ;
+ UINT16 lp_message = (INT16)(( tf_message == TRW_EOM ) ? LRW_EOM_ACK : LRR_EOM_ACK ) ;
+
+ /* stop the clock during EOM processing */
+ LP_MsgStopClock( lp->lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, lp->curr_fsys, &lp->tpos ) ;
+
+ /* call message handler to prompt for next tape */
+ LP_MsgEOM( lp->lis_ptr->pid,
+ lp->lis_ptr->curr_bsd_ptr,
+ lp->curr_fsys,
+ &lp->tpos,
+ lp->rr.vcb_ptr,
+ lp->rr.ddb_ptr,
+ lp->rr.fdb_ptr,
+ lp->rr.idb_ptr ) ;
+
+ /* now acknowledge EOM to tape format and return control */
+ lp->rr.lp_message = lp_message ;
+
+ /* Let everyone know we are here */
+ if( ( msg_err_stat = LP_MsgIdle( lp->lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, lp->curr_fsys, &lp->tpos ) ) != MSG_ACK ) {
+ return( msg_err_stat ) ;
+ }
+
+ return_status = TF_GetNextTapeRequest( &lp->rr ) ;
+
+ /* restart the clock after EOM processing */
+ LP_MsgStartClock( lp->lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, lp->curr_fsys, &lp->tpos ) ;
+
+ /* check to see if the user wanted to continue processing */
+ if( return_status == TFLE_UI_HAPPY_ABORT ) {
+ LP_SetAbortFlag( lp->lis_ptr, ABORT_AT_EOM ) ;
+
+ } else if( return_status != SUCCESS ) {
+
+ if( ( msg_err_stat = LP_MsgError( lp->lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, lp->curr_fsys, &lp->tpos, return_status, NULL, NULL, 0L ) ) != MSG_ACK ) {
+ return( msg_err_stat ) ;
+ }
+
+ } else {
+ LP_MsgContinueVCB( lp->lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, lp->curr_fsys, &lp->tpos, lp->rr.vcb_ptr ) ;
+
+ }
+
+ return( return_status ) ;
+
+}
+
+/**/
+/**
+
+ Name: LP_PadData()
+
+ Description: This function fills a buffer of specified size with padded data.
+
+ Modified: 5/24/1991 13:3:0
+
+ Returns: none
+
+ Notes: the pad data is "This is padding !! \r\n"
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID LP_PadData(
+INT8_PTR buf, /* I - Buffer to place pad data into */
+UINT32 count ) /* I - Number of bytes of pad */
+{
+ UINT16 dest_pos ;
+ INT16 source_pos = 0 ;
+ INT8_PTR pad_string = "This is padding!! \r\n" ;
+
+
+ for( dest_pos = 0 ; dest_pos < (UINT16)count; dest_pos ++ ) {
+
+ if( pad_string[source_pos] == '\0' ) {
+ source_pos = 0 ;
+ }
+
+ buf[dest_pos] = pad_string[ source_pos ++ ] ;
+ }
+
+ return ;
+
+}
+/**/
+/**
+
+ Name: LP_CheckForOpen()
+
+ Description: This function trys to re open the file.
+
+ Modified: 11/16/1989
+
+ Returns: File system errors for open.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 LP_CheckForOpen( ref )
+UINT32 ref ;
+{
+ LP_ENV_PTR lp;
+
+ lp = ( LP_ENV_PTR )ref ;
+
+ return( FS_OpenObj( lp->curr_fsys, lp->f_hand, lp->curr_blk, FS_READ ) ) ;
+
+}
+
+
+/**/
+/**
+
+ Name: LP_CheckForReadLock()
+
+ Description: This function trys to re read the file inorder to
+ obtain a lock.
+
+ Modified: 11/16/1989
+
+ Returns: File system errors for Read.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 LP_CheckForReadLock( ref )
+UINT32 ref ;
+{
+ LP_ENV_PTR lp;
+
+ lp = ( LP_ENV_PTR )ref ;
+
+ return( FS_ReadObj( lp->file_hand, lp->buf_start, &lp->read_size, &lp->blk_size, &lp->rr.stream ) ) ;
+
+}
+
+
+
diff --git a/private/utils/ntbackup/src/lptpcat.c b/private/utils/ntbackup/src/lptpcat.c
new file mode 100644
index 000000000..7995cdebc
--- /dev/null
+++ b/private/utils/ntbackup/src/lptpcat.c
@@ -0,0 +1,180 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-92
+
+
+ Name: lptpcat.c
+
+ Description: Tape catalog read loop.
+
+ $Log: T:/LOGFILES/LPTPCAT.C_V $
+
+ Rev 1.4 10 Jun 1993 20:24:44 GREGG
+Initialize the channel number in the tpos structure.
+
+ Rev 1.3 16 Apr 1993 15:12:04 GREGG
+Steve's fix for abort handling.
+
+ Rev 1.2 21 Jan 1993 15:04:40 GREGG
+Added parameter to MsgError macro.
+
+ Rev 1.1 14 Jan 1993 13:33:12 STEVEN
+added stream_id to error message
+
+ Rev 1.0 09 Nov 1992 14:26:42 GREGG
+Initial revision.
+
+**/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "queues.h"
+#include "beconfig.h"
+#include "msassert.h"
+#include "tbe_defs.h"
+#include "tbe_err.h"
+#include "bsdu.h"
+#include "fsys.h"
+#include "tflproto.h"
+#include "tfldefs.h"
+#include "loops.h"
+#include "loop_prv.h"
+#include "get_next.h"
+
+
+/* the regular define for error messages, 'LP_MsgError', won't work because
+ we don't have a loop environment structure.
+*/
+#define MsgError( pid, bsd_ptr, fsys, tpos, error, ddb_dblk_ptr, dblk_ptr, strm_id ) \
+ ( lis_ptr->message_handler( MSG_TBE_ERROR, pid, bsd_ptr, fsys, tpos, error, ddb_dblk_ptr, dblk_ptr, strm_id ) )
+
+
+/**/
+/**
+
+ Unit: Loops
+
+ Name: LP_Tape_Cat_Engine
+
+ Description: This function simulates the behavior of
+ LP_List_Tape_Engine while calling the tape catalog API
+ to hide the fact that the DBLKs are being generated
+ from OTC as opposed to scanning the actual set.
+
+ Returns: Error code.
+
+ Notes: None.
+
+**/
+
+INT16 LP_Tape_Cat_Engine(
+ LIS_PTR lis_ptr ) /* I - Loop interface structure */
+{
+ BSD_PTR bsd_ptr ;
+ INT16 done = FALSE ;
+ INT16 return_status = SUCCESS ;
+ INT16 status ;
+ DBLK dblk ;
+ TPOS tpos ;
+ FSYS_HAND fsh ;
+
+ bsd_ptr = BSD_GetFirst( lis_ptr->bsd_list ) ;
+ msassert( bsd_ptr != NULL ) ;
+ tpos.reference = (UINT32)lis_ptr ;
+
+ /* open file system */
+ if( ( return_status = FS_OpenFileSys( &fsh, GENERIC_DATA,
+ BSD_GetConfigData( bsd_ptr ) ) )
+ == OUT_OF_MEMORY ) {
+
+ MsgError( lis_ptr->pid, bsd_ptr, NULL, &tpos,
+ LP_OUT_OF_MEMORY_ERROR, NULL, NULL, 0L ) ;
+
+ return( LP_OUT_OF_MEMORY_ERROR ) ;
+ }
+ msassert( return_status == SUCCESS ) ;
+
+ /* indicate the start of the operation */
+ lis_ptr->message_handler( MSG_START_OPERATION, lis_ptr->pid,
+ bsd_ptr, fsh, &tpos ) ;
+
+ /* set up for tape positioning */
+ tpos.tape_id = BSD_GetTapeID( bsd_ptr ) ;
+ tpos.tape_seq_num = BSD_GetTapeNum( bsd_ptr ) ;
+ tpos.backup_set_num = BSD_GetSetNum( bsd_ptr ) ;
+ tpos.tape_loc.pba_vcb = BSD_GetPBA( bsd_ptr );
+
+ /* This is a kludge! Currently, there is only one channel. */
+ tpos.channel = 0 ;
+
+ done = FALSE ;
+ return_status = lis_ptr->message_handler( MSG_START_BACKUP_SET,
+ lis_ptr->pid, bsd_ptr,
+ fsh, &tpos, NULL ) ;
+
+ while( return_status == SUCCESS && !done ) {
+
+ switch( return_status = TF_GetNextSCEntry( fsh, &dblk ) ) {
+
+ case TFLE_NO_ERR :
+ return_status = lis_ptr->message_handler( MSG_LOG_BLOCK,
+ lis_ptr->pid,
+ bsd_ptr, fsh,
+ &tpos, &dblk ) ;
+ break ;
+
+ case TF_NO_MORE_ENTRIES :
+ return_status = SUCCESS ;
+ done = TRUE ;
+ break ;
+
+ default :
+ if( ( return_status = MsgError( lis_ptr->pid, bsd_ptr, fsh,
+ &tpos, return_status, NULL,
+ NULL, 0L ) ) == MSG_ACK ) {
+
+ return_status = SUCCESS ;
+ }
+ }
+
+ if( !done ) {
+ /* check for abort conditions */
+ switch( LP_GetAbortFlag( lis_ptr ) ) {
+
+ case CONTINUE_PROCESSING:
+ break ;
+
+ case ABORT_CTRL_BREAK:
+ /* falling through (no break) */
+ case ABORT_PROCESSED:
+ MsgError( lis_ptr->pid, bsd_ptr, fsh, &tpos,
+ LP_USER_ABORT_ERROR, NULL, NULL, 0L ) ;
+
+
+ return_status = USER_ABORT ;
+ break ;
+
+ case ABORT_AT_EOM:
+ return_status = USER_ABORT ;
+ break ;
+ }
+ }
+ }
+
+ /* call message handler to log the end of the operation */
+ lis_ptr->message_handler( MSG_END_BACKUP_SET, lis_ptr->pid,
+ bsd_ptr, fsh, &tpos ) ;
+
+ if( ( status = FS_CloseFileSys( fsh ) ) != SUCCESS ) {
+ msassert( status == SUCCESS ) ;
+ }
+
+ /* indicate the end of the operation */
+ lis_ptr->message_handler( MSG_END_OPERATION, lis_ptr->pid,
+ bsd_ptr, NULL, &tpos ) ;
+
+ return( return_status ) ;
+}
+
diff --git a/private/utils/ntbackup/src/lpverify.c b/private/utils/ntbackup/src/lpverify.c
new file mode 100644
index 000000000..40175545d
--- /dev/null
+++ b/private/utils/ntbackup/src/lpverify.c
@@ -0,0 +1,353 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: lpverify.c
+
+ Description: This module contains the entry point for the verify engine.
+
+
+ $Log: T:\logfiles\lpverify.c_v $
+
+ Rev 1.13.1.0 07 Feb 1994 02:06:42 GREGG
+Fixed and expanded 'extended error reporting'.
+
+ Rev 1.13 29 Apr 1993 22:26:46 GREGG
+Transfer the Tape Catalog Version in the BSD to the tpos structure.
+
+ Rev 1.12 14 Jan 1993 13:33:10 STEVEN
+added stream_id to error message
+
+ Rev 1.11 10 Nov 1992 17:28:32 STEVEN
+verify buffer off by factor of 1K
+
+ Rev 1.10 28 Oct 1992 15:05:42 STEVEN
+very buffer is buffer size
+
+ Rev 1.9 24 Feb 1992 10:00:52 GREGG
+Call TF_OpenTape at beginning of loop, Open/Close Set in loop, CloseTape at end.
+
+ Rev 1.8 04 Feb 1992 21:41:14 GREGG
+Changed parameters in calls to TF_AllocateTapeBuffers and TF_FreeTapeBuffers.
+
+ Rev 1.7 16 Jan 1992 15:52:54 STEVEN
+fix warnings for WIN32
+
+ Rev 1.6 13 Dec 1991 15:26:06 GREGG
+SKATEBOARD - Initial Integration.
+
+ Rev 1.5 06 Nov 1991 19:14:00 GREGG
+BIGWHEEL - 8200sx - Get cat_enabled from the BE config.
+
+ Rev 1.4 21 Jun 1991 08:49:28 STEVEN
+new config unit
+
+ Rev 1.3 30 May 1991 09:11:24 STEVEN
+bsdu_err.h no longer exists
+
+ Rev 1.2 28 May 1991 10:13:48 STEVEN
+use MAYN_MEM instead of MAYN_OS2
+
+ Rev 1.1 24 May 1991 13:18:48 STEVEN
+updates from BSDU redesign
+
+ Rev 1.0 09 May 1991 13:38:00 HUNTER
+Initial revision.
+
+**/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "queues.h"
+#include "beconfig.h"
+#include "msassert.h"
+#include "tbe_defs.h"
+#include "tbe_err.h"
+#include "bsdu.h"
+#include "fsys.h"
+#include "tflproto.h"
+#include "tfldefs.h"
+#include "loops.h"
+#include "loop_prv.h"
+#include "lis.h"
+/**/
+/**
+
+ Name: LP_Verify_Engine()
+
+ Description: this routine processes a list of bsds for a verify operation.
+
+ Modified: 5/24/1991 10:33:31
+
+ Returns: SUCCESS or error code from Tape Format or Loop error code
+
+ Notes: na
+
+ See also: $/SEE( LP_Backup_Engine(), LP_Restore_Engine() )$
+ $/SEE( LP_Delete_Engine() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 LP_Verify_Engine(
+LIS_PTR lis_ptr ) /* I - Loop interface structure */
+{
+ BSD_PTR bsd_ptr ;
+ BSD_PTR temp_bsd_ptr;
+ GENERIC_DLE_PTR dle_ptr ;
+ register LP_ENV_PTR lp ;
+ INT16 return_status = SUCCESS ;
+ INT16 status ;
+ UINT16 mem_save ;
+ UINT16 max_buffs ;
+ UINT16 buff_size ;
+ DBLK_PTR dblk_ptr ;
+ BOOLEAN reuse_bsd = FALSE ;
+ BOOLEAN first_time = TRUE ;
+ BE_CFG_PTR cfg ;
+ BOOLEAN tape_opened = FALSE ;
+ INT16 channel_no ;
+ THW_PTR sdrv ;
+
+ bsd_ptr = BSD_GetFirst( lis_ptr->bsd_list ) ;
+
+ msassert( bsd_ptr != NULL ) ;
+
+ cfg = BSD_GetConfigData( bsd_ptr ) ;
+
+ /* Allocate the loop environment structure */
+ if( ( lp = ( LP_ENV_PTR )calloc( 1, sizeof( LP_ENV ) ) ) == NULL ) {
+
+ /* we cannot use macro because it relies on the lp structure */
+ lis_ptr->message_handler( MSG_TBE_ERROR, lis_ptr->pid, bsd_ptr, NULL, NULL, LP_OUT_OF_MEMORY_ERROR, NULL, NULL ) ;
+
+ return LP_OUT_OF_MEMORY_ERROR ;
+
+ }
+
+ /* Set up the loop environment structure */
+ lp->lis_ptr = lis_ptr ;
+ lp->tpos.reference = ( UINT32 )lis_ptr ;
+
+ /* allocate DBLKs */
+ if( ( dblk_ptr = ( DBLK_PTR )calloc( 3, sizeof( DBLK ) ) ) == NULL ) {
+
+ LP_MsgError( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos, LP_OUT_OF_MEMORY_ERROR, NULL, NULL, 0L ) ;
+
+ /* Free local allocations */
+ free( lp ) ;
+
+ return LP_OUT_OF_MEMORY_ERROR ;
+
+ }
+ else {
+ /* set up the DBLK_PTRs in the Request/Reply structure */
+ lp->rr.vcb_ptr = dblk_ptr ;
+ lp->rr.ddb_ptr = dblk_ptr + 1 ;
+ lp->saved_ddb = dblk_ptr + 1 ;
+ lp->rr.fdb_ptr = dblk_ptr + 2 ; /* ASSUMPTION : */
+ lp->rr.idb_ptr = dblk_ptr + 2 ; /* no FS has both FDB & IDB */
+ }
+
+ /* Set up the loop environment structure */
+ lp->rr.filter_to_use = TF_KEEP_ALL_DATA ;
+ lp->seq_num = 1 ;
+ lp->tpos.tape_id = -1 ;
+ lp->tpos.tape_seq_num = -1 ;
+
+ mem_save = BEC_GetReserveMem( cfg ) ;
+ max_buffs = BEC_GetMaxTapeBuffers( cfg ) ;
+ buff_size = BEC_GetTFLBuffSize( cfg ) ;
+
+ if( ( lp->very_buff = calloc( 1, buff_size * 1024 ) ) == NULL ) {
+
+ /* Free local allocations */
+ free( dblk_ptr ) ;
+ free( lp ) ;
+
+ LP_MsgError( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos, LP_OUT_OF_MEMORY_ERROR, NULL, NULL, 0L ) ;
+
+ return LP_OUT_OF_MEMORY_ERROR ;
+
+ }
+
+ /* allocate buffers for operation */
+
+ return_status = TF_AllocateTapeBuffers( mem_save, max_buffs, buff_size ) ;
+
+ if( return_status != SUCCESS ) {
+
+ LP_MsgError( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos, return_status, NULL, NULL, 0L ) ;
+
+ /* Free local allocations */
+ free( lp->very_buff ) ;
+ free( dblk_ptr ) ;
+ free( lp ) ;
+
+ return( return_status ) ;
+
+ }
+
+ /* indicate the start of the operation */
+ LP_MsgStartOP( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos ) ;
+
+ /* loop for each bsd */
+ do {
+
+ /* First attach to the drive */
+ dle_ptr = BSD_GetDLE( bsd_ptr ) ;
+ cfg = BSD_GetConfigData( bsd_ptr ) ;
+
+ /* Now attach to the dle */
+ if( ( return_status = FS_AttachToDLE( &lp->curr_fsys, dle_ptr, cfg, NULL, NULL ) ) == SUCCESS ) {
+
+ /* Set up the loop environment structure */
+ lp->get_spcl = TRUE ;
+ lp->start_new_dir = TRUE ;
+ lp->get_first_file = TRUE ;
+ lp->get_next_first_time = TRUE ;
+ lp->send_saved_block = FALSE ;
+ lp->curr_blk = &lp->dblk1 ;
+ lp->curr_ddb = &lp->dblk2 ;
+ lp->empty_blk = &lp->dblk3 ;
+ lp->blk_is_empty = TRUE ;
+ lp->ffr_inited = FALSE;
+ lp->cat_enabled = (BOOLEAN)(BEC_GetCatalogLevel( cfg ) != CATALOGS_NONE) ;
+ /* Reset the PBA values in case one set is fully catalogged */
+ /* and another is not. */
+ lp->tpos.tape_loc.pba_vcb = 0 ;
+ lp->rr.tape_loc.pba_vcb = 0 ;
+ lp->tpos.tape_loc.lba = 0 ;
+ lp->rr.tape_loc.lba = 0 ;
+
+ lp->tpos.UI_TapePosRoutine = lis_ptr->tape_pos_handler ;
+ lp->curr_dle = dle_ptr ;
+ lp->tpos.tape_cat_ver = BSD_GetTapeCatVer( bsd_ptr ) ;
+
+ sdrv = LP_DetermineStartingTPDrv( lis_ptr->oper_type, bsd_ptr, &lp->tpos, lis_ptr->auto_det_sdrv ) ;
+
+ /* fill in the the set number before calling LP_VerifyDLE */
+
+ if ( reuse_bsd ) {
+ lp->tpos.backup_set_num ++ ;
+ /* In case any FSEs have been tagged as deleted by processing
+ the last set, make sure they are "real" now */
+ BSD_ClearDelete( bsd_ptr ) ;
+ }
+ else {
+
+ /* this is the first time we are looking at this BSD */
+
+ if ( BSD_GetSetNum( bsd_ptr ) < 0 ) {
+
+ /* Set reuse indicator based upon whether another
+ bsd is in the queue */
+ temp_bsd_ptr = BSD_GetNext( bsd_ptr );
+ if ( temp_bsd_ptr != NULL ) {
+ reuse_bsd = FALSE;
+ }
+ else {
+ reuse_bsd = TRUE;
+ }
+
+ if ( BSD_GetSetNum( bsd_ptr ) == -1 ) {
+ /* negative one means the current set and all following sets */
+ if( first_time ) {
+ lp->tpos.backup_set_num = -1;
+ } else {
+ lp->tpos.backup_set_num++ ;
+ }
+ }
+ else {
+
+ /* -2 means set 2 and all the following sets */
+ /* -3 " " 3 " " " " " */
+ /* and so on */
+
+ lp->tpos.backup_set_num = (-BSD_GetSetNum( bsd_ptr ) ) ;
+ }
+ }
+ else {
+ lp->tpos.backup_set_num = BSD_GetSetNum( bsd_ptr ) ;
+ }
+ }
+
+ if( !tape_opened ) {
+ /* open the tape for operation */
+ tape_opened = TRUE ;
+ if( ( return_status = TF_OpenTape( &channel_no, sdrv, &lp->tpos ) ) != SUCCESS ) {
+ LP_MsgError( lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, return_status, NULL, NULL, 0L ) ;
+ }
+ }
+
+ if( return_status == SUCCESS ) {
+
+ /* Perform the operation */
+ return_status = LP_VerifyDLE( bsd_ptr, lp, reuse_bsd, channel_no, sdrv ) ;
+
+ first_time = FALSE ;
+
+ if ( reuse_bsd && ( return_status == TFLE_UI_HAPPY_ABORT ) ) {
+
+ /* we've hit the end of a tape that we were verifying unknown sets from */
+
+ reuse_bsd = FALSE ;
+
+ /* filter out the error */
+ return_status = SUCCESS ;
+ }
+
+ /* The following condition is used to fix the prompt for
+ 2nd tape in a multiple tape restore/verify with
+ restore that tape 1 contains uncataloged backup sets
+ or with the possibility of containing uncataloged
+ backup sets */
+
+ if ( return_status == TFLE_UI_HAPPY_ABORT ) {
+ temp_bsd_ptr = BSD_GetNext( bsd_ptr ) ;
+ if ( temp_bsd_ptr != NULL ) {
+ return_status = SUCCESS ;
+ }
+ }
+
+ FS_DetachDLE( lp->curr_fsys ) ;
+ }
+
+ } else if( return_status != USER_ABORT ) {
+
+ /* error attaching to the drive, print error and give up */
+ LP_MsgError( lis_ptr->pid, bsd_ptr, NULL, &lp->tpos, LP_DRIVE_ATTACH_ERROR, NULL, NULL, 0L ) ;
+
+ /* reset return_status, and try the next bsd */
+ return_status = SUCCESS ;
+ }
+
+ if ( ! reuse_bsd ) {
+ bsd_ptr = BSD_GetNext( bsd_ptr ) ;
+ }
+
+ /* Continue, as long as we did not have an error, and we can get a new bsd */
+ } while( !return_status && (bsd_ptr != NULL ) ) ;
+
+ if( tape_opened ) {
+ TF_CloseTape( channel_no ) ;
+ }
+
+ /* Deinit operation buffers */
+ if( ( status = TF_FreeTapeBuffers( ) ) != SUCCESS ) {
+ LP_MsgError( lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, NULL, &lp->tpos, status, NULL, NULL, 0L ) ;
+ }
+
+ /* indicate the end of the operation */
+ LP_MsgEndOP( lis_ptr->pid, lp->lis_ptr->curr_bsd_ptr, NULL, &lp->tpos ) ;
+
+ /* Free local allocations */
+ free( lp->very_buff ) ;
+ free( dblk_ptr ) ;
+ free( lp ) ;
+
+ return( return_status ) ;
+}
diff --git a/private/utils/ntbackup/src/ltape.bmp b/private/utils/ntbackup/src/ltape.bmp
new file mode 100644
index 000000000..6ce446768
--- /dev/null
+++ b/private/utils/ntbackup/src/ltape.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/lw_data.c b/private/utils/ntbackup/src/lw_data.c
new file mode 100644
index 000000000..bdd8678f2
--- /dev/null
+++ b/private/utils/ntbackup/src/lw_data.c
@@ -0,0 +1,122 @@
+/**/
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: lw_data.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains all the layer wide definitions.
+
+
+ $Log: T:\logfiles\lw_data.c_v $
+
+ Rev 1.12 30 Aug 1993 18:47:42 GREGG
+Modified the way we control hardware compression from software to work around
+a bug in Archive DAT DC firmware rev. 3.58 (we shipped a lot of them).
+Files Modified: lw_data.c, lw_data.h, tfstuff.c, mtf10wdb.c, mtf10wt.c and
+ drives.c
+
+ Rev 1.11 22 Jul 1993 12:13:26 ZEIR
+ad'd lw_software_name & _len
+
+ Rev 1.10 11 May 1993 21:55:34 GREGG
+Moved Sytos translator stuff from layer-wide area to translator.
+
+ Rev 1.9 10 May 1993 15:13:28 Terri_Lynn
+Added Steve's changes and My changes for EOM processing
+
+ Rev 1.8 17 Mar 1993 15:08:20 GREGG
+Added global array for Sytos Plus translator and tape drive block mode changes
+
+ Rev 1.7 24 Jul 1992 16:51:40 NED
+Incorporated Skateboard and BigWheel changed into Graceful Red code,
+including MTF4.0 translator support, adding 3.1 file-system structures
+support to the 3.1 translator, additions to GOS to support non-4.0 translators.
+Also did Unicode and 64-bit filesize changes.
+
+ Rev 1.6 05 Apr 1992 19:09:54 GREGG
+ROLLER BLADES - Changed lw_sx_file_path to lw_cat_file_path.
+
+ Rev 1.5 16 Jan 1992 18:40:28 NED
+Skateboard: buffer manager changes
+
+ Rev 1.4 02 Jan 1992 14:56:28 NED
+Buffer Manager/UTF translator integration.
+
+ Rev 1.3 05 Dec 1991 13:48:52 GREGG
+SKATEBOARD - New Buff Mgt - Initial Integration.
+
+ Rev 1.2 17 Oct 1991 01:21:26 GREGG
+BIGWHEEL - 8200sx - Added sx file path pointers.
+
+ Rev 1.1 10 May 1991 16:17:48 GREGG
+Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:12:06 GREGG
+Initial revision.
+
+**/
+
+#include "stdtypes.h"
+#include "queues.h"
+#include "stdmath.h"
+
+#include "tfldefs.h"
+#include "drive.h"
+#include "channel.h"
+#include "lw_cntl.h"
+#include "buffman.h"
+#include "dblkmap.h"
+
+
+/* The Channel Array */
+CHANNEL_PTR lw_channels = NULL ;
+
+/* The Drive List */
+DRIVE_PTR lw_drives = NULL ;
+
+/* The Drive linked list */
+Q_HEADER lw_drive_list = { NULL } ;
+
+/* The Main TFL control structure */
+LW_CNTL lw_tfl_control = {
+ FALSE, /* drives_active */
+ FALSE, /* driver_inited */
+ NULL, /* cntl_cards */
+ NULL, /* driver_addr */
+ 0, /* no_channels */
+ 0, /* no_chans_open */
+ 0 /* use_fast_file */
+ } ;
+
+
+/* The current byte format indicator */
+UINT16 lw_byte_fmt = INTEL ;
+
+/* The Buffer Requirements */
+BUF_REQ lw_default_vcb_requirements ; /* for initial reads */
+BUF_REQ lw_default_bm_requirements ; /* for regular reads */
+UINT16 lw_buff_size ; /* from config */
+
+/* The directory where catalog type files should be written */
+CHAR_PTR lw_cat_file_path = NULL ;
+CHAR_PTR lw_cat_file_path_end = NULL ;
+
+/* The name of this software - who's creating sets for MTF */
+CHAR_PTR lw_software_name = NULL ;
+UINT16 lw_software_name_len = 0 ;
+
+/* some global UINT64 constants for our use */
+const UINT64 lw_UINT64_ZERO = { 0, 0 };
+const UINT64 lw_UINT64_MAX = { 0xffffffffUL, 0xffffffffUL };
+
+/* List of valid tape drive physical block sizes. */
+UINT32 lw_blk_size_list[] = { 512UL, 1024UL, 2048UL, 4096UL,
+ 8192UL, 16384UL, 32768UL } ;
+INT lw_num_blk_sizes = sizeof( lw_blk_size_list ) / sizeof( UINT32 ) ;
+
+/* TRUE if we want the next set to be backed up with hardware compression */
+BOOLEAN lw_hw_comp = FALSE ;
+
diff --git a/private/utils/ntbackup/src/lwtfinf.c b/private/utils/ntbackup/src/lwtfinf.c
new file mode 100644
index 000000000..de2f136da
--- /dev/null
+++ b/private/utils/ntbackup/src/lwtfinf.c
@@ -0,0 +1,147 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: lwtfinf.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the layer tape of supported formats.
+
+
+ $Log: Q:/LOGFILES/LWTFINF.C_V $
+
+ Rev 1.16 21 Jul 1993 18:25:10 ZEIR
+Reintroduced (from Cougar/Skateboard) TAPES_FIRST_TO_LAST for relevant translators
+
+ Rev 1.15 05 Apr 1993 14:58:04 TERRI
+Added resource defintion for Sypl 10
+
+ Rev 1.14 17 Mar 1993 15:17:16 TERRI
+Added changes for the Sytos Plus translator
+
+ Rev 1.13 12 Mar 1993 17:34:38 GREGG
+Removed POS_INF_AVAIL attribute from 3.1 translator.
+
+ Rev 1.12 18 Feb 1993 00:13:54 GREGG
+Removed attribute bits which are no longer valid.
+
+ Rev 1.11 22 Jan 1993 13:51:48 unknown
+Removed the Tape Format name from the structure. Instead of embedding
+this info in the structure, the format_id field has become an index
+into a resource session. The UI gets the tape format name from the
+resources based on the format_id. Note that the format_id of the
+first tape format is required to be zero because the Backup engine
+always writes tape format zero.
+
+ Rev 1.10 11 Nov 1992 10:55:10 GREGG
+Unicodeized literals.
+
+ Rev 1.9 17 Aug 1992 08:33:52 GREGG
+Added min_size_for_dblk field.
+
+ Rev 1.8 29 May 1992 15:13:36 GREGG
+Added CAN_READ_FROM_VCB_BUFF attr bit to appropriate translators.
+
+ Rev 1.7 25 Mar 1992 19:00:50 GREGG
+ROLLER BLADES - Added 4.0 format.
+
+ Rev 1.6 07 Jan 1992 14:11:06 ZEIR
+Added UTF entry
+
+ Rev 1.5 05 Dec 1991 14:46:38 LORIB
+Changed format name from "SY-TOS Format 3.11" to "Non-Maynard Format".
+
+ Rev 1.4 22 Jul 1991 12:44:00 GREGG
+Set 3.1 format attribute bit to indicate we must write a continuation tape
+if EOS coincides with EOM.
+
+ Rev 1.3 06 Jun 1991 23:48:42 NED
+Added compiler directives to allow selective inclusion of translators.
+
+ Rev 1.2 21 May 1991 17:05:46 NED
+added max_password_size field.
+
+ Rev 1.1 10 May 1991 11:54:28 GREGG
+Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:18:22 GREGG
+Initial revision.
+
+**/
+/* Note that to change the list of supported formats, you must also
+ * edit the file "fmttab.c"
+ */
+/* begin include list */
+
+#include "stdtypes.h"
+#include "fmtinf.h"
+#include "eng_fmt.h"
+
+/* $end$ include list */
+
+
+TFINF lw_fmtdescr[] = {
+
+#ifdef MY40_TRANS
+ {
+ ( RD_FORMAT_BIT | WT_FORMAT_BIT | POS_INF_AVAIL |
+ APPEND_SUPPORTED | MUST_WRITE_CONT | CAN_READ_FROM_VCB_BUFF ),
+ 9, RES_MY40_TRANS, 1024
+ },
+#endif
+
+#ifdef MY31_TRANS
+ {
+ ( RD_FORMAT_BIT | CAN_READ_FROM_VCB_BUFF ),
+ 9, RES_MY31_TRANS, 512
+ },
+#endif
+
+#ifdef MY30_TRANS
+ {
+ ( RD_FORMAT_BIT | CAN_READ_FROM_VCB_BUFF ),
+ 9, RES_MY30_TRANS, 512
+ },
+#endif
+
+#ifdef MY25_TRANS
+ {
+ ( RD_FORMAT_BIT | CAN_READ_FROM_VCB_BUFF ),
+ 9, RES_MY25_TRANS, 512
+ },
+#endif
+
+#ifdef QS19_TRANS
+ {
+ ( RD_FORMAT_BIT | CAN_READ_FROM_VCB_BUFF | TAPES_FIRST_TO_LAST ),
+ 9, RES_QS19_TRANS, 512
+ },
+#endif
+
+#ifdef SY31_TRANS
+ {
+ ( RD_FORMAT_BIT | CAN_READ_FROM_VCB_BUFF | TAPES_FIRST_TO_LAST ),
+ 20, RES_SY31_TRANS, 512
+ },
+#endif
+
+#ifdef SYPL10_TRANS
+ {
+ ( RD_FORMAT_BIT | CAN_READ_FROM_VCB_BUFF | TAPES_FIRST_TO_LAST ),
+ 20, RES_SYPL10_TRANS, 1024
+ },
+#endif
+
+#ifdef UTF_TRANS
+ {
+ ( RD_FORMAT_BIT | TAPES_FIRST_TO_LAST ),
+ 11, RES_UTF_TRANS, 512
+ }
+#endif
+
+
+
+} ;
+
+UINT16 lw_num_supported_fmts = sizeof( lw_fmtdescr ) / sizeof( lw_fmtdescr[0] ) ;
diff --git a/private/utils/ntbackup/src/mach_nt.c b/private/utils/ntbackup/src/mach_nt.c
new file mode 100644
index 000000000..4924a2f25
--- /dev/null
+++ b/private/utils/ntbackup/src/mach_nt.c
@@ -0,0 +1,38 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: mach_nt.c
+
+ Description: Function to determine if machine type is PS/2
+ It now always returns UNKNOWN_MACHINE.
+
+
+ $Log: P:/LOGFILES/MACH_NT.C_V $
+
+ Rev 1.0 17 Jan 1992 17:25:30 STEVEN
+Initial revision.
+
+**/
+/* begin include list */
+#include "stdtypes.h"
+#include "machine.h"
+/* $end$ include list */
+
+/**/
+/**
+
+ Name: GetMachineType
+
+ Description: For NT this function always return UNKNOWN_MACHINE.
+
+ Modified: 1/17/1992 15:53:9
+
+ Returns: machine type
+
+**/
+INT16 GetMachineType( VOID )
+{
+ return UNKNOWN_MACHINE ;
+}
+
diff --git a/private/utils/ntbackup/src/makecfdb.c b/private/utils/ntbackup/src/makecfdb.c
new file mode 100644
index 000000000..83b196a65
--- /dev/null
+++ b/private/utils/ntbackup/src/makecfdb.c
@@ -0,0 +1,88 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: makecfdb.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains all code relevant to CFDBs
+
+
+ $Log: Q:/LOGFILES/MAKECFDB.C_V $
+
+ Rev 1.3 18 Jun 1993 10:09:48 MIKEP
+enable c++
+
+ Rev 1.2 25 Apr 1993 20:13:46 GREGG
+Fifth in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Store the corrupt stream number in the CFIL tape struct and the CFDB.
+
+Matches: MTF10WDB.C 1.9, FSYS.H 1.33, FSYS_STR.H 1.47, MAKECFDB.C 1.2,
+ BACK_OBJ.C 1.36, MAYN40RD.C 1.58
+
+ Rev 1.1 05 Aug 1992 10:55:06 DON
+removed warning's
+
+ Rev 1.0 09 May 1991 13:33:56 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include "stdtypes.h"
+
+#include "tfldefs.h"
+#include "fsys.h"
+/* $end$ include list */
+
+/**/
+/**
+
+ Name: FS_CreateGenCFDB()
+
+ Description: This functioncreates a CFDB
+
+ Modified: 9/12/1989
+
+ Returns: TF_SKIP_ALL_DATA ;
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 FS_CreateGenCFDB(
+FSYS_HAND fsh ,
+GEN_CFDB_DATA_PTR data )
+{
+ (void)fsh ;
+
+ data->std_data.dblk->blk_type = CFDB_ID ;
+ data->std_data.dblk->com.blkid = data->std_data.blkid;
+ data->std_data.dblk->com.f_d.did = data->std_data.did ;
+ data->std_data.dblk->com.ba.lba = data->std_data.lba ;
+ data->std_data.dblk->com.continue_obj = FALSE;
+ data->std_data.dblk->com.stream_ptr = NULL;
+ data->std_data.dblk->com.stream_offset = 0;
+ data->std_data.dblk->com.tape_seq_num = 0; // ???
+ data->std_data.dblk->com.string_type = 0; // ??
+ data->std_data.dblk->com.os_id = 0;
+ data->std_data.dblk->com.os_ver = 0;
+
+
+ ((CFDB_PTR)data->std_data.dblk)->corrupt_offset = data->corrupt_offset ;
+ ((CFDB_PTR)data->std_data.dblk)->stream_number = data->stream_number ;
+ ((CFDB_PTR)data->std_data.dblk)->attributes = data->std_data.attrib ;
+
+ return TF_SKIP_ALL_DATA;
+}
+
+
+
+
+
diff --git a/private/utils/ntbackup/src/makefile b/private/utils/ntbackup/src/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/ntbackup/src/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/ntbackup/src/makefile.inc b/private/utils/ntbackup/src/makefile.inc
new file mode 100644
index 000000000..effef6444
--- /dev/null
+++ b/private/utils/ntbackup/src/makefile.inc
@@ -0,0 +1,2 @@
+bkuevent.h bkuevent.rc msg00001.bin: bkuevent.mc
+ mc -v bkuevent.mc
diff --git a/private/utils/ntbackup/src/makeudb.c b/private/utils/ntbackup/src/makeudb.c
new file mode 100644
index 000000000..9c2c281da
--- /dev/null
+++ b/private/utils/ntbackup/src/makeudb.c
@@ -0,0 +1,66 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: makeudb.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains all the code to support a UDB
+
+
+ $Log: S:/LOGFILES/MAKEUDB.C_V $
+
+ Rev 1.1 24 Jul 1991 11:00:58 DAVIDH
+Corrected Watcom compiler warnings.
+
+ Rev 1.0 09 May 1991 13:33:48 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include "stdtypes.h"
+
+#include "tfldefs.h"
+#include "fsys.h"
+/* $end$ include list */
+
+
+/**/
+/**
+
+ Name: FS_CreateGenUDB()
+
+ Description: This function creates a UDB
+
+ Modified: 9/13/1989
+
+ Returns: TF_SKIP_ALL_DATA
+
+ Notes:
+
+ See also: $/SEE( FS_CreateGenVCB() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 FS_CreateGenUDB( fsh, data )
+FSYS_HAND fsh;
+GEN_UDB_DATA_PTR data ;
+{
+
+ (VOID) fsh ;
+
+ data->std_data.dblk->blk_type = UDB_ID ;
+ data->std_data.dblk->com.blkid = data->std_data.blkid;
+ data->std_data.dblk->com.f_d.did = data->std_data.did ;
+ data->std_data.dblk->com.ba.lba = data->std_data.lba ;
+
+
+ return TF_SKIP_ALL_DATA;
+}
+
+
+
+
diff --git a/private/utils/ntbackup/src/makevcb.c b/private/utils/ntbackup/src/makevcb.c
new file mode 100644
index 000000000..5e2111aed
--- /dev/null
+++ b/private/utils/ntbackup/src/makevcb.c
@@ -0,0 +1,428 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: makevcb.c
+
+ Description: This file contains all the code necessary to support the VCBs
+
+
+ $Log: N:/LOGFILES/MAKEVCB.C_V $
+
+ Rev 1.18.1.3 24 Mar 1994 21:58:48 STEVEN
+alignment fault if password was odd size
+
+ Rev 1.18.1.2 19 Jan 1994 12:52:30 BARRY
+Supress warnings
+
+ Rev 1.18.1.1 15 Oct 1993 10:35:30 GREGG
+Set string type in dblk and make sure dev_name_leng is 0 if not NLM.
+
+ Rev 1.18.1.0 21 Sep 1993 14:16:18 BARRY
+Unicode fixes
+
+ Rev 1.18 15 Jul 1993 19:23:32 GREGG
+Added setting compressed_obj and vendor_id; Removed setting compression_alg.
+
+ Rev 1.17 18 Jun 1993 10:13:14 MIKEP
+enable c++
+
+ Rev 1.16 03 Jun 1993 15:59:52 DON
+Changed the OTHER msassert( fsh->attached_dle != NULL ) to an if, since
+we may not have a volume name in create-vcb data and may not be attached
+to a DLE (retension tape, catalog tape, etc...).
+
+ Rev 1.15 19 Apr 1993 18:00:50 GREGG
+Second in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ Changes to write version 2 of OTC, and to read both versions.
+
+Matches: mayn40rd.c 1.55, otc40msc.c 1.19, otc40rd.c 1.23, otc40wt.c 1.23,
+ makevcb.c 1.15, fsys.h 1.32, fsys_str.h 1.46, tpos.h 1.16,
+ mayn40.h 1.32, mtf.h 1.3.
+
+NOTE: There are additional changes to the catalogs needed to save the OTC
+ version and put it in the tpos structure before loading the OTC
+ File/Directory Detail. These changes are NOT listed above!
+
+ Rev 1.14 24 Mar 1993 10:24:28 unknown
+ChuckS: Changed msassert( fsh->attached_dle != NULL ) to an if, since
+we may not have a device name in create-vcb data and may not be attached
+to a DLE (read tape, verify tape, etc).
+
+ Rev 1.13 18 Mar 1993 15:17:44 ChuckS
+OS_NLM (for now): Add code to put DeviceName into VCB
+
+ Rev 1.12 04 Feb 1993 14:55:36 TIMN
+Added Unicode header to resolve link errors
+
+ Rev 1.11 26 Oct 1992 18:10:06 STEVEN
+added continue bit
+
+ Rev 1.10 21 Oct 1992 10:39:46 GREGG
+Changed 'set_catalog_level' to 'on_tape_cat_level'.
+
+ Rev 1.9 20 Oct 1992 15:51:22 STEVEN
+added support for otc / catalog interface through DBLK
+
+ Rev 1.8 14 Oct 1992 14:20:42 STEVEN
+fix typos
+
+ Rev 1.7 14 Oct 1992 11:56:22 STEVEN
+add translations for unicode strings
+
+ Rev 1.6 05 Oct 1992 17:05:56 DAVEV
+Unicode strlen verification
+
+ Rev 1.5 18 Aug 1992 10:25:12 STEVEN
+fix warnings
+
+ Rev 1.4 13 Jan 1992 18:46:02 STEVEN
+changes for WIN32 compile
+
+ Rev 1.3 07 Jan 1992 11:59:32 STEVEN
+move common functions to tables
+
+ Rev 1.2 06 Aug 1991 18:29:48 DON
+added NLM File System support
+
+ Rev 1.1 03 Jun 1991 13:26:56 BARRY
+Remove product defines from conditional compilation.
+
+ Rev 1.0 09 May 1991 13:33:46 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include <stdio.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "stdwcs.h"
+
+#include "msassert.h"
+#include "fsys.h"
+#include "tfldefs.h"
+/* $end$ include list */
+
+static INT16 SetStringInVCB(
+ INT8_PTR target,
+ INT16_PTR target_length_ptr,
+ VOID_PTR source,
+ INT16 source_length,
+ BOOLEAN in_str_asci,
+ BOOLEAN out_str_asci ) ;
+
+/**/
+/**
+
+ Name: FS_CreateGenVCB( )
+
+ Description: This function creates a VCB given the data provided
+
+ Modified: 6/22/1990
+
+ Returns: TF_SKIP_ALL_DATA
+
+ Notes: If the volume name in the request structure is blank
+ then it is filled out.
+
+ The drive leter has been added to the volume name for
+ Novell network drives. This was done for MBS. If This
+ causes a problem contact the MBS group before you change
+ it back.
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 FS_CreateGenVCB(
+FSYS_HAND fsh ,
+GEN_VCB_DATA_PTR data )
+{
+ VCB_PTR vcb ;
+ INT8_PTR vcb_str ;
+ BOOLEAN in_str_asci ;
+ BOOLEAN out_str_asci ;
+
+ if ( data->std_data.string_type != FS_GetStringTypes( fsh ) ) {
+ if ( data->std_data.string_type == BEC_ANSI_STR ) {
+ in_str_asci = TRUE;
+ out_str_asci = FALSE;
+ } else {
+ in_str_asci = FALSE;
+ out_str_asci = TRUE;
+ }
+ } else {
+ if ( data->std_data.string_type == BEC_ANSI_STR ) {
+ in_str_asci = TRUE;
+ out_str_asci = TRUE;
+ } else {
+ in_str_asci = FALSE;
+ out_str_asci = FALSE;
+ }
+ }
+
+
+ data->std_data.dblk->blk_type = VCB_ID ;
+ data->std_data.dblk->com.blkid = data->std_data.blkid ;
+ data->std_data.dblk->com.f_d.f_mark = data->f_mark ;
+ data->std_data.dblk->com.ba.pba = data->pba ;
+ data->std_data.dblk->com.ba.lba = data->std_data.lba ;
+ data->std_data.dblk->com.os_id = data->std_data.os_id ;
+ data->std_data.dblk->com.continue_obj = data->std_data.continue_obj ;
+ data->std_data.dblk->com.os_ver = data->std_data.os_ver ;
+ data->std_data.dblk->com.tape_seq_num = data->std_data.tape_seq_num ;
+ data->std_data.dblk->com.compressed_obj = data->std_data.compressed_obj ;
+ data->std_data.dblk->com.string_type = data->std_data.string_type ;
+
+ vcb = ( VCB_PTR )data->std_data.dblk ;
+ vcb_str = ( BYTE_PTR )vcb ;
+
+
+ vcb->vcb_attributes = data->std_data.attrib ;
+ vcb->tape_id = data->tape_id ;
+ vcb->tape_seq_num = data->tape_seq_num ;
+ vcb->backup_set_num = data->bset_num ;
+ vcb->size = 0 ;
+ vcb->tf_major_ver = data->tf_major_ver ;
+ vcb->tf_minor_ver = data->tf_minor_ver ;
+ vcb->sw_major_ver = data->sw_major_ver ;
+ vcb->sw_minor_ver = data->sw_minor_ver ;
+ vcb->os_id = data->std_data.os_id ;
+ vcb->os_ver = data->std_data.os_ver ;
+ vcb->backup_date = *( data->date ) ;
+ vcb->password_encrypt_alg = data->password_encrypt_alg ;
+ vcb->data_encrypt_alg = data->data_encrypt_alg ;
+ vcb->set_cat_pba = data->set_cat_pba ;
+ vcb->set_cat_tape_seq_num = data->set_cat_tape_seq_num ;
+ vcb->on_tape_cat_level = data->on_tape_cat_level ;
+ vcb->set_cat_info_valid = data->set_cat_info_valid ;
+ vcb->on_tape_cat_ver = data->on_tape_cat_ver ;
+ vcb->vendor_id = data->vendor_id ;
+
+ if ( vcb->set_cat_info_valid ) {
+ vcb->set_cat_num_dirs = data->set_cat_num_dirs ;
+ vcb->set_cat_num_files = data->set_cat_num_files ;
+ vcb->set_cat_num_corrupt = data->set_cat_num_corrupt ;
+ }
+
+ /* tape name */
+ vcb->tape_name = sizeof( *vcb ) ;
+ SetStringInVCB( &vcb_str[ vcb->tape_name ],
+ &vcb->tape_name_leng,
+ data->tape_name,
+ data->tape_name_size,
+ in_str_asci,
+ out_str_asci ) ;
+
+ /* backup set name */
+ vcb->backup_set_name = (INT16)(vcb->tape_name + vcb->tape_name_leng ) ;
+ SetStringInVCB( &vcb_str[ vcb->backup_set_name ],
+ &vcb->backup_set_name_leng,
+ data->bset_name,
+ data->bset_name_size,
+ in_str_asci,
+ out_str_asci ) ;
+
+ /* backup set description */
+ vcb->backup_set_descript = (INT16)(vcb->backup_set_name + vcb->backup_set_name_leng ) ;
+ SetStringInVCB( &vcb_str[ vcb->backup_set_descript ],
+ &vcb->backup_set_descript_leng,
+ data->bset_descript,
+ data->bset_descript_size,
+ in_str_asci,
+ out_str_asci ) ;
+
+ /* user name */
+ vcb->user_name = (INT16)(vcb->backup_set_descript + vcb->backup_set_descript_leng ) ;
+ SetStringInVCB( &vcb_str[ vcb->user_name ],
+ &vcb->user_name_leng,
+ data->user_name,
+ data->user_name_size,
+ in_str_asci,
+ out_str_asci ) ;
+
+ /* tape password */
+ vcb->tape_password = (INT16)(vcb->user_name + vcb->user_name_leng ) ;
+ vcb->tape_password_leng = data->tape_password_size ;
+ memcpy( &vcb_str[ vcb->tape_password ],
+ data->tape_password,
+ data->tape_password_size ) ;
+
+ /* backup set password */
+ vcb->backup_set_password = (INT16)(vcb->tape_password + vcb->tape_password_leng ) ;
+ vcb->backup_set_password_leng = data->bset_password_size ;
+ memcpy( &vcb_str[ vcb->backup_set_password ], data->bset_password, data->bset_password_size ) ;
+
+ /* machine name */
+ vcb->machine_name = (INT16)(vcb->backup_set_password + vcb->backup_set_password_leng ) ;
+ vcb->machine_name += (vcb->machine_name & 1 ) ; // align the strings.
+ if( SetStringInVCB( &vcb_str[ vcb->machine_name ],
+ &vcb->machine_name_leng,
+ data->machine_name,
+ data->machine_name_size,
+ in_str_asci,
+ out_str_asci ) == 0 ) {
+
+
+ SetStringInVCB( &vcb_str[ vcb->machine_name ],
+ &vcb->machine_name_leng,
+ "IBM PC or compatible",
+ 21, // size in bytes of above string
+ TRUE,
+ out_str_asci ) ;
+
+ }
+
+ /* short machine name */
+ vcb->short_machine_name = (INT16)(vcb->machine_name + vcb->machine_name_leng ) ;
+ if( SetStringInVCB( &vcb_str[ vcb->short_machine_name ],
+ &vcb->short_machine_name_leng,
+ data->short_m_name,
+ data->short_m_name_size,
+ in_str_asci,
+ out_str_asci ) == 0 ) {
+
+
+ SetStringInVCB( &vcb_str[ vcb->short_machine_name ],
+ &vcb->short_machine_name_leng,
+ "IBM",
+ 4, // size in bytes of above string
+ TRUE,
+ out_str_asci ) ;
+ }
+
+ /* volume name */
+ vcb->vol_name = (INT16)(vcb->short_machine_name + vcb->short_machine_name_leng );
+ if( SetStringInVCB( &vcb_str[ vcb->vol_name ],
+ &vcb->vol_name_leng,
+ data->volume_name,
+ data->volume_name_size,
+ in_str_asci,
+ out_str_asci ) == 0 ) {
+
+ if ( fsh->attached_dle != NULL ) {
+ DLE_GetVolName( fsh->attached_dle, (CHAR_PTR)&vcb_str[ vcb->vol_name ] ) ;
+ vcb->vol_name_leng = DLE_SizeofVolName( fsh->attached_dle ) ;
+ }
+ }
+
+#if defined( OS_NLM )
+ /* device name */
+ vcb->dev_name = (INT16)( vcb->vol_name + vcb->vol_name_leng ) ;
+
+ if ( SetStringInVCB( &vcb_str[ vcb->dev_name ],
+ &vcb->dev_name_leng,
+ data->device_name,
+ data->dev_name_size,
+ in_str_asci,
+ out_str_asci ) == 0 ) {
+
+ if ( fsh->attached_dle != NULL ) {
+ DLE_DeviceName( fsh->attached_dle, &vcb_str[ vcb->dev_name ], DLE_SizeofDevName( fsh->attached_dle ) ) ;
+ vcb->dev_name_leng = DLE_SizeofDevName( fsh->attached_dle ) ;
+ }
+ }
+#else
+ vcb->dev_name = 0 ;
+ vcb->dev_name_leng = 0 ;
+#endif
+
+ return TF_SKIP_ALL_DATA ;
+}
+
+
+/**/
+/**
+
+ Name: SetStringInVCB
+
+ Description: Transfers string information from a source to a target ( in a VCB ).
+ If the target is not NUL terminated then the length ( in the VCB )
+ is incremented.
+
+ Modified: 4/23/1990
+
+ Returns: The actual length of the string as indicated in the VCB
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+static INT16 SetStringInVCB(
+INT8_PTR target,
+INT16_PTR target_length_ptr, // length in bytes incl NULL terminator
+VOID_PTR source,
+INT16 source_length, // length in bytes incl NULL terminator
+BOOLEAN in_str_asci,
+BOOLEAN out_str_asci )
+{
+ int target_size ;
+
+ target[ 0 ] = '\0' ;
+ target_size = *target_length_ptr = source_length ;
+
+ if( source_length == 0 ) { // simply return if nothing to do
+ return( 0 ) ;
+ }
+
+ if ( in_str_asci && !out_str_asci ) { // asci to unicode
+
+ WCHAR UNALIGNED * temp_ptr ;
+
+ target_size = *target_length_ptr = source_length * sizeof(WCHAR) ;
+
+ mapAnsiToUnic( (ACHAR_PTR)source, (WCHAR_PTR)target, &target_size ) ;
+
+ temp_ptr = (WCHAR UNALIGNED *)(&target[*target_length_ptr]) ;
+ if ( *(temp_ptr -1) != 0 ) {
+ *temp_ptr = 0 ;
+ ( *target_length_ptr ) +=sizeof(WCHAR) ;
+ }
+
+ } else if ( !in_str_asci && out_str_asci) { // unicode to ascii
+
+ target_size = *target_length_ptr = source_length / sizeof(WCHAR) ;
+
+ mapUnicToAnsi( (WCHAR_PTR)source, (ACHAR_PTR)target, (ACHAR)('_'), &target_size ) ;
+
+ if( target[ *target_length_ptr - 1 ] != 0 ) {
+ target[ *target_length_ptr ] = 0 ;
+ ( *target_length_ptr ) ++ ;
+ }
+
+
+ } else if ( !in_str_asci && !out_str_asci) { // unicode to unicode
+
+ WCHAR UNALIGNED *temp_ptr ;
+
+ memcpy( target, source, source_length ) ;
+
+ temp_ptr = (WCHAR UNALIGNED *)(&target[source_length]) ;
+ if ( *(temp_ptr -1) != 0 ) {
+ *temp_ptr = 0 ;
+ ( *target_length_ptr ) += sizeof(WCHAR) ;
+ }
+
+ } else { // ascii to asci
+
+ memcpy( target, source, source_length ) ;
+
+ if( target[ source_length - 1 ] != 0 ) {
+ target[ source_length ] = 0 ;
+ ( *target_length_ptr ) ++ ;
+ }
+ }
+
+ return( *target_length_ptr ) ;
+
+}
+
diff --git a/private/utils/ntbackup/src/mayn31rd.c b/private/utils/ntbackup/src/mayn31rd.c
new file mode 100644
index 000000000..1e868b246
--- /dev/null
+++ b/private/utils/ntbackup/src/mayn31rd.c
@@ -0,0 +1,1724 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: mayn31rd.c
+
+ Date Updated: $./FDT$ $./FTM$
+ 9/25/1989 15:9:9
+
+ Description: Contains the code for Maynard Format 3.1
+
+
+ $Log: T:/LOGFILES/MAYN31RD.C_V $
+
+ Rev 1.49.1.4 12 Jan 1995 16:47:44 GREGG
+Added code to deal with continuation bits wrongly set in DDBs.
+
+ Rev 1.49.1.3 05 Jan 1995 16:57:24 GREGG
+Several fixes to translation of OS info and generation of alt data streams.
+
+ Rev 1.49.1.2 11 Feb 1994 16:38:56 GREGG
+Clear the MOS bit in MoveToVCB. EPR 948-0244
+
+ Rev 1.49.1.1 24 Jan 1994 15:59:12 GREGG
+Fixed warnings.
+
+ Rev 1.49.1.0 17 Jan 1994 13:35:44 GREGG
+Unicode fixes.
+
+ Rev 1.49 29 Sep 1993 14:35:54 GREGG
+Fixed bug in generation of stream info in F40_RdFDB.
+
+ Rev 1.48 21 Aug 1993 03:56:10 GREGG
+Return TAPE_INCONSISTENCY instead of BAD_TAPE in F31_MoveToVCB if
+TF_NO_MORE_DATA is returned from MoveFileMarks.
+
+ Rev 1.47 15 Jul 1993 19:32:18 GREGG
+Set compressed_obj, vendor_id, and compressed, encrypted and future_rev
+bits in appropriate dblks.
+
+ Rev 1.46 30 Jun 1993 09:01:40 GREGG
+Fixed setting of continue_obj, and set cross_set and cross_lba in channel.
+
+ Rev 1.45 25 Jun 1993 20:45:34 GREGG
+We were screwing up the stream info reading the continuation VCB.
+
+ Rev 1.44 26 Apr 1993 02:43:46 GREGG
+Sixth in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Redefined attribute bits to match the spec.
+ - Eliminated unused/undocumented bits.
+ - Added code to translate bits on tapes that were written wrong.
+
+Matches MAYN40RD.C 1.59, DBLKS.H 1.15, MAYN40.H 1.34, OTC40RD.C 1.26,
+ SYPL10RD.C 1.8, BACK_VCB.C 1.17, MAYN31RD.C 1.44, SYPL10.H 1.2
+
+ Rev 1.43 30 Jan 1993 11:43:46 DON
+Removed compiler warnings
+
+ Rev 1.42 28 Jan 1993 12:28:50 GREGG
+Fixed warnings.
+
+ Rev 1.41 20 Jan 1993 14:50:12 BobR
+Added MOVE_ESA macro call(s)
+
+ Rev 1.40 20 Jan 1993 14:08:14 GREGG
+Fixed processing of continuation DBLKS (all remaining data labeled as pad stream).
+
+ Rev 1.39 13 Jan 1993 21:01:08 GREGG
+Fixed setting of pointer to OS info.
+
+ Rev 1.38 12 Jan 1993 11:10:58 GREGG
+Fixed problem with not recognizing we had repositioned and needed a new DBLK.
+
+ Rev 1.37 06 Jan 1993 17:20:22 GREGG
+Added pad stream to skip the pad data.
+
+ Rev 1.36 18 Dec 1992 08:46:16 HUNTER
+Fixes for "streamizing"
+
+ Rev 1.35 18 Nov 1992 10:41:14 HUNTER
+Bug fixes
+
+ Rev 1.34 11 Nov 1992 14:17:34 GREGG
+Moved F31_CalculatePad from Write.
+
+ Rev 1.33 11 Nov 1992 09:47:38 HUNTER
+Added support for the New Stream methods. Deleted both the VARIABLE block
+code, and SUPPORT FOR IMAGE DBs.
+
+ Rev 1.32 12 Aug 1992 13:04:56 BARRY
+Removed translation of Turtle tapes to GOS (old SMS).
+
+ Rev 1.31 24 Jul 1992 16:49:40 NED
+Incorporated Skateboard and BigWheel changed into Graceful Red code,
+including MTF4.0 translator support, adding 3.1 file-system structures
+support to the 3.1 translator, additions to GOS to support non-4.0 translators.
+Also did Unicode and 64-bit filesize changes.
+
+ Rev 1.30 20 May 1992 18:35:08 STEVEN
+Changes for 64 bit file system.
+
+ Rev 1.29 25 Mar 1992 20:11:54 GREGG
+ROLLER BLADES - 64 bit support.
+
+ Rev 1.28 20 Mar 1992 17:58:00 NED
+added exception updating after TpReceive calls
+
+ Rev 1.27 12 Mar 1992 17:05:26 NED
+Added changes for EOS at EOM bug not requesting second tape
+when cataloging.
+
+ Rev 1.26 19 Feb 1992 17:26:22 GREGG
+In exception handler, if we can't get a regular buffer, use the VCB buffer.
+
+ Rev 1.25 03 Feb 1992 11:35:10 NED
+re-enabled MakeIDB for non-DOS
+
+ Rev 1.24 23 Jan 1992 23:28:06 GREGG
+Kludge for Wangtech bug. (again???)
+
+ Rev 1.23 05 Dec 1991 14:02:58 GREGG
+SKATEBOARD - New Buff Mgt - Initial Integration.
+
+ Rev 1.22 13 Nov 1991 06:55:30 GREGG
+Changed assert calls to msassert.
+
+ Rev 1.21 07 Nov 1991 15:20:52 unknown
+VBLK - Added support for Maynard 3.1 Rd
+
+ Rev 1.20 29 Oct 1991 10:49:36 GREGG
+Set EOS position bit if EOS detected by exception handler call in move_to_vcb.
+
+ Rev 1.19 15 Oct 1991 07:42:56 GREGG
+Added ThreadSwitch call in empty TpReceive loops.
+
+ Rev 1.18 07 Oct 1991 22:27:52 GREGG
+Update lba stuff in continuation read.
+
+ Rev 1.17 16 Sep 1991 20:24:10 GREGG
+Changed Initializer to return a TFLE_xxx.
+
+ Rev 1.16 27 Aug 1991 14:39:50 GREGG
+Fixed bug in MoveToVCB (Move FMKS as else to rewind_first).
+
+ Rev 1.15 22 Aug 1991 16:28:58 NED
+Changed all references to internals of the buffer structure to macros.
+
+ Rev 1.14 16 Aug 1991 09:09:00 GREGG
+Added handling of BSDBs with associated data.
+
+ Rev 1.13 14 Aug 1991 12:07:48 GREGG
+Fixed bug in EOM handling in MoveToVCB.
+
+ Rev 1.12 30 Jul 1991 15:33:14 GREGG
+Included 'dddefs.h'.
+
+ Rev 1.11 22 Jul 1991 12:55:40 GREGG
+Modified the move to VCB routine to handle EOS encountered at EOM.
+
+ Rev 1.10 09 Jul 1991 15:56:50 NED
+Don't translate return from MoveFileMarks forward.
+
+ Rev 1.9 24 Jun 1991 19:41:36 NED
+If buffer has EOS or EOM exception, set filemark count one higher than listed
+in current DBLK (in SetStandFields). Added buffer parameter to SetStandFields
+to eliminate references to channel->cur_buff.
+
+ Rev 1.8 17 Jun 1991 18:12:00 GREGG
+Added logic to set the REW_CLOSE position bit only under specific conditions.
+
+ Rev 1.7 12 Jun 1991 15:35:46 GREGG
+Changes to positioning logic in MoveToVCB.
+
+ Rev 1.6 07 Jun 1991 01:24:16 GREGG
+Changed error check to msassert in MoveToVCB.
+
+ Rev 1.5 06 Jun 1991 23:24:02 GREGG
+New parameters for F31_DeInitialize. Set filemark pos from blocks when tape
+blocks at translation time. Check for EOM exception after read in
+F31_RdException. Changes to MoveToVCB due to Teac problems and appends to
+2.5 tapes. Removed product specific compiler directive.
+
+ Rev 1.4 23 May 1991 16:07:18 GREGG
+Handle EOM like FMK in exception handler.
+
+ Rev 1.3 20 May 1991 15:37:38 DAVIDH
+Cleared up Watcom warnings for "defined, but not referenced" parameters.
+
+ Rev 1.2 14 May 1991 11:22:54 GREGG
+Changed order of includes.
+
+ Rev 1.1 10 May 1991 11:56:02 GREGG
+Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:18:44 GREGG
+Initial revision.
+
+**/
+
+#include <string.h>
+#include <malloc.h>
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "stdmacro.h"
+#include "tbe_defs.h"
+#include "datetime.h"
+#include "drive.h"
+#include "channel.h"
+#include "fmteng.h"
+#include "mayn31.h"
+#include "f31proto.h"
+#include "transutl.h"
+#include "fsys.h"
+#include "tloc.h"
+#include "lw_data.h"
+#include "lwprotos.h"
+#include "tfldefs.h"
+#include "translat.h"
+#include "tfl_err.h"
+
+/* Device Driver Interface Headers */
+#include "retbuf.h"
+#include "special.h"
+#include "dilhwd.h"
+#include "drvinf.h"
+#include "generr.h"
+#include "genstat.h"
+#include "genfuncs.h"
+#include "dddefs.h"
+#include "dil.h"
+
+/* Internal Function Prototypes */
+
+static VOID _near SetStandFields( CHANNEL_PTR, STD_DBLK_DATA_PTR, DB_HDR_PTR, BUF_PTR ) ;
+
+/* Static data */
+
+static UINT16 blkhdr_layout[] = {
+ /* Conversion type Number of items to convert */
+ SIZE_WORD + 2,
+ SIZE_DWORD + 1,
+ SIZE_WORD + 4,
+ SIZE_DWORD + 4,
+ NO_MORE_CNV
+} ;
+
+static UINT16 vcb_layout[] = {
+ /* Conversion type Number of items to convert */
+ SIZE_DWORD + 1,
+ SIZE_DATE_TIME + 1,
+ SIZE_WORD + 4,
+ SIZE_DWORD + 1,
+ SIZE_WORD + 23,
+ NO_MORE_CNV
+} ;
+
+static UINT16 ddb_layout[] = {
+ /* Conversion type Number of items to convert */
+ SIZE_DWORD + 1,
+ SIZE_DATE_TIME + 3,
+ SIZE_DWORD + 1,
+ SIZE_WORD + 2,
+ NO_MORE_CNV
+} ;
+
+#ifdef SUPPORT_IMAGE
+static UINT16 idb_layout[] = {
+ /* Conversion type Number of items to convert */
+ SIZE_DWORD + 4,
+ SIZE_WORD + 1,
+ SIZE_DWORD + 2,
+ SIZE_WORD + 3,
+ NO_MORE_CNV
+} ;
+#endif
+
+static UINT16 cfdb_layout[] = {
+ /* Conversion type Number of items to convert */
+ SIZE_DWORD + 4,
+ NO_MORE_CNV
+} ;
+
+#ifdef OS_DOS
+#pragma alloc_text( MAYN31RD_1, F31_Initialize, F31_DeInitialize, F31_RdVCB )
+#pragma alloc_text( MAYN31RD_2, F31_DetBlkType, F31_RdDDB, F31_RdFDB )
+#pragma alloc_text( MAYN31RD_3, F31_RdIDB, F31_RdCFDB, F31_RdUDB )
+#pragma alloc_text( MAYN31RD_4, F31_RdContTape, F31_Recall )
+#pragma alloc_text( MAYN31RD_5, SetStandFields )
+#pragma alloc_text( MAYN31RD_6, F31_RdException )
+#pragma alloc_text( MAYN31RD_7, F31_MoveToVCB )
+#endif
+
+/**/
+/**
+
+ Format 3.1 Read Routines
+
+**/
+
+/**/
+/**
+
+ Name: F31_Initialize
+
+ Description: This routine is used to allocate and initialize
+ the format 3.1 environment structure.
+
+ Modified: Oct. 24, 1990 NK
+
+ Returns: TRUE if allocated & init'd OK
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+INT16 F31_Initialize(
+ CHANNEL_PTR channel )
+{
+ F31_ENV_PTR env_ptr = (F31_ENV_PTR)malloc( sizeof( F31_ENV ) ) ;
+
+ channel->fmt_env = env_ptr ;
+
+ if ( env_ptr == NULL ) {
+ return TFLE_NO_MEMORY ;
+ }
+
+ memset( env_ptr, 0, sizeof( F31_ENV ) ) ;
+
+ env_ptr->os_id = FS_PC_DOS ;
+ env_ptr->os_ver = FS_PC_DOS_VER ;
+ env_ptr->no_streams = 0 ;
+ env_ptr->stream_mode = FALSE ;
+ env_ptr->curr_lba = 0L ;
+ env_ptr->in_streams = FALSE ;
+
+ channel->lb_size = 512 ; /* Always the case! */
+
+ return TFLE_NO_ERR ;
+}
+
+/**/
+/**
+
+ Name: F31_DeInitialize
+
+ Description: Returns environment memory
+
+ Modified: 10/24/1990
+
+ Returns: Nothing.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+VOID F31_DeInitialize(
+ VOID_PTR *fmt_env )
+{
+ free( *fmt_env ) ;
+ *fmt_env = NULL ;
+}
+
+/**/
+/**
+
+ Name: F31_DetBlkType
+
+ Description: Determines the type of Descriptor Block for the given
+ buffer.
+
+ Modified: August 17, 1989 (3:00pm)
+
+ Returns: The Block type number.
+
+ Notes: This routine assumes the buffer is at least
+ min_siz_for_dblk bytes long.
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+INT16 F31_DetBlkType(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer, /* Transfer Parameter Block */
+ UINT16_PTR blk_type )
+{
+ DB_HDR_PTR cur_hdr = (DB_HDR_PTR)BM_NextBytePtr( buffer ) ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ F31_ENV_PTR currentEnv = ( F31_ENV_PTR ) channel->fmt_env ;
+
+ if( currentEnv->curr_lba != BM_BeginningLBA( buffer ) +
+ BM_NextByteOffset( buffer )
+ && ! currentEnv->in_streams ) {
+
+ currentEnv->stream_mode = FALSE ;
+ }
+
+ /* Are we in a stream mode */
+ if( currentEnv->stream_mode ) {
+ *blk_type = BT_STREAM ;
+ return( ret_val ) ;
+ }
+
+ *blk_type = cur_hdr->type ;
+
+ switch( *blk_type ) {
+ case F31_VCB_ID:
+ case F31_CVCB_ID:
+ case F31_DDB_ID:
+ case F31_FDB_ID:
+ case F31_CFDB_ID:
+ case F31_IDB_ID:
+ case F31_BSDB_ID:
+ break ;
+ default:
+ ret_val = BT_UDB ;
+ break ;
+ }
+
+ /* Make sure the block's checksums are valid */
+ if( CalcChecksum( (UINT16_PTR)(VOID_PTR)cur_hdr, F31_HDR_CHKSUM_LEN ) != cur_hdr->hdr_chksm ) {
+ *blk_type = BT_HOSED ;
+ ret_val = TFLE_TRANSLATION_FAILURE ;
+ }
+
+ if ( ret_val != BT_HOSED ) {
+ if( CalcChecksum( &cur_hdr->chksm_len, cur_hdr->chksm_len ) != cur_hdr->blk_chksm ) {
+ *blk_type = BT_HOSED ;
+ ret_val = TFLE_TRANSLATION_FAILURE ;
+ }
+ }
+
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Name: F31_SizeofTBLK
+
+ Description: returns the size of a tape block.
+
+ Modified: 10/5/1989 10:44:19
+
+ Returns: the size in bytes
+
+ Notes: IT IS ASSUMED THAT THE BUFFER PASSED TO THIS FUNCTION
+ CONTAINS A VALID FORMAT 3.1 TAPE BLOCK.
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+UINT16 F31_SizeofTBLK(
+ VOID_PTR buffer )
+{
+ return( ( (DB_HDR_PTR)buffer)->data_off ) ;
+}
+
+/**/
+/**
+ Name: F31_RdVCB
+
+ Description: Format 3.1 VCB translator.
+
+ Modified: 7/9/92 NK
+
+ Returns: True if successful, false if not
+
+ Notes:
+**/
+
+INT16 F31_RdVCB(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+ DBLK_PTR cur_dblk = channel->cur_dblk ;
+ F31_VCB_PTR cur_vcb = (F31_VCB_PTR)( BM_NextBytePtr( buffer ) ) ;
+ FSYS_HAND cur_fsys = channel->cur_fsys ;
+ GEN_VCB_DATA gvcb_data ;
+ UINT16 tmp_filter ;
+ ACHAR_PTR vstr_ptr = (ACHAR_PTR)( cur_vcb ) ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ F31_ENV_PTR cur_env = (F31_ENV_PTR)channel->fmt_env ;
+
+ /* If processor types don't match, swap bytes */
+ if( cur_vcb->hdr.format != CUR_PROCESSOR ) {
+ SwapBlock( blkhdr_layout, (UINT8_PTR)&cur_vcb->hdr.blk_chksm ) ;
+ SwapBlock( vcb_layout, (UINT8_PTR)( cur_vcb + sizeof( DB_HDR ) ) ) ;
+ }
+
+ /* Initialize the file systems interface structure */
+ FS_SetDefaultDBLK( cur_fsys, BT_VCB, (CREATE_DBLK_PTR)&gvcb_data ) ;
+ gvcb_data.std_data.dblk = cur_dblk ;
+
+ /* Set the non-defaulted standard fields for the FS */
+ SetStandFields( channel, &gvcb_data.std_data, &cur_vcb->hdr, buffer ) ;
+
+ gvcb_data.std_data.attrib =
+ ( ( ( cur_vcb->vcb_attribs & F31_VCB_ARCHIVE_BIT ) ? VCB_ARCHIVE_BIT : 0UL )
+ | ( ( cur_vcb->vcb_attribs & F31_VCB_COPY_SET ) ? VCB_COPY_SET : 0UL )
+ | ( ( cur_vcb->vcb_attribs & F31_VCB_NORMAL_SET ) ? VCB_NORMAL_SET : 0UL )
+ | ( ( cur_vcb->vcb_attribs & F31_VCB_DIFFERENTIAL_SET ) ? VCB_DIFFERENTIAL_SET : 0UL )
+ | ( ( cur_vcb->vcb_attribs & F31_VCB_INCREMENTAL_SET ) ? VCB_INCREMENTAL_SET : 0UL ) ) ;
+
+ if ( cur_vcb->hdr.blk_attribs & F31_DB_CONT_BIT ) {
+ gvcb_data.std_data.continue_obj = TRUE ;
+ cur_env->cont_vcb = TRUE ;
+ } else {
+ cur_env->cont_vcb = FALSE ;
+ }
+
+ /* The IDs for the tape */
+ gvcb_data.tape_id = (UINT32)cur_vcb->id ;
+ gvcb_data.tape_seq_num = (UINT16)cur_vcb->ts_num ;
+ gvcb_data.bset_num = (UINT16)cur_vcb->bs_num ;
+ gvcb_data.tf_major_ver = (CHAR)cur_vcb->tf_mjr_ver ;
+ gvcb_data.tf_minor_ver = (CHAR)cur_vcb->tf_mnr_ver ;
+ gvcb_data.sw_major_ver = (CHAR)cur_vcb->sw_mjr_ver ;
+ gvcb_data.sw_minor_ver = (CHAR)cur_vcb->sw_mnr_ver ;
+ gvcb_data.password_encrypt_alg = cur_vcb->pass_encrypt_algm ;
+ gvcb_data.data_encrypt_alg = cur_vcb->data_encrypt_algm ;
+ gvcb_data.vendor_id = 0 ;
+
+ /* The Variable Length Strings */
+ gvcb_data.tape_name = (CHAR_PTR)( vstr_ptr + cur_vcb->t_name_off ) ;
+ gvcb_data.tape_name_size = cur_vcb->t_name_len ;
+ gvcb_data.bset_name = (CHAR_PTR)( vstr_ptr + cur_vcb->bs_name_off ) ;
+ gvcb_data.bset_name_size = cur_vcb->bs_name_len ;
+ gvcb_data.bset_descript = (CHAR_PTR)( vstr_ptr + cur_vcb->bs_desc_off ) ;
+ gvcb_data.bset_descript_size = cur_vcb->bs_desc_len ;
+ gvcb_data.machine_name = (CHAR_PTR)( vstr_ptr + cur_vcb->mach_name_off ) ;
+ gvcb_data.machine_name_size = cur_vcb->mach_name_len ;
+ gvcb_data.short_m_name = (CHAR_PTR)( vstr_ptr + cur_vcb->shrt_mach_name_off ) ;
+ gvcb_data.short_m_name_size = cur_vcb->shrt_mach_name_len ;
+ gvcb_data.volume_name = (CHAR_PTR)( vstr_ptr + cur_vcb->vol_name_off ) ;
+ gvcb_data.volume_name_size = cur_vcb->vol_name_len ;
+ gvcb_data.user_name = (CHAR_PTR)( vstr_ptr + cur_vcb->username_off ) ;
+ gvcb_data.user_name_size = cur_vcb->username_len ;
+ gvcb_data.bset_password = (CHAR_PTR)( vstr_ptr + cur_vcb->bs_pass_off ) ;
+ gvcb_data.bset_password_size = cur_vcb->bs_pass_len ;
+ gvcb_data.tape_password = (CHAR_PTR)( vstr_ptr + cur_vcb->t_pass_off ) ;
+ gvcb_data.tape_password_size = cur_vcb->t_pass_len ;
+ gvcb_data.date = &cur_vcb->backup_date ;
+
+ /* Set up Position Info */
+ gvcb_data.pba = cur_vcb->hdr.pba_vcb ;
+
+ if( gvcb_data.std_data.continue_obj ) {
+ /* Fix for the app not knowing the LBA for a continuation VCB */
+ channel->cross_set = cur_vcb->bs_num ;
+ channel->cross_lba = cur_vcb->hdr.lba ;
+ }
+
+ /* Tell the file system to do its thing */
+ tmp_filter = (UINT16)FS_CreateGenVCB( cur_fsys, &gvcb_data ) ;
+
+ ProcessDataFilter( channel, tmp_filter ) ;
+
+ /* We are done with this much */
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Name: F31_RdDDB
+
+ Description:
+
+ Modified: 9/21/1989 11:12:3
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+INT16 F31_RdDDB(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+ DBLK_PTR cur_dblk = channel->cur_dblk ;
+ F31_DDB_PTR cur_ddb = (F31_DDB_PTR)( BM_NextBytePtr( buffer ) ) ;
+ FSYS_HAND cur_fsys = channel->cur_fsys ;
+ F31_ENV_PTR currentEnv = (F31_ENV_PTR)channel->fmt_env ;
+ GEN_DDB_DATA gddb_data ;
+ UINT16 tmp_filter ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ ACHAR_PTR vstr_ptr = (ACHAR_PTR)cur_ddb ;
+ VOID_PTR di_ptr ;
+ STREAM_INFO_PTR currentStream = &currentEnv->streams[0] ;
+ GOS gos ;
+ DATE_TIME fake_access_date ;
+
+ /* There was a bug in 3.1 write which caused the continuation bit to be
+ set in the first DDB of a set which was not a continuation set. It
+ is not clear how, why or how often this happened, but it was never
+ discovered because the read translator worked in such a way that it
+ was not apparent during read that anything was wrong. Now it messes
+ us up big time so we set a flag to tell if the VCB has the
+ continuation bit set, and clear the bit in the DDB if it wasn't set
+ in the VCB.
+ */
+ if( ( !currentEnv->cont_vcb ) &&
+ ( cur_ddb->hdr.blk_attribs & F31_DB_CONT_BIT ) ) {
+ cur_ddb->hdr.blk_attribs &= ~F31_DB_CONT_BIT ;
+ }
+
+ /* If the processor types don't match, swap bytes */
+ if( cur_ddb->hdr.format != CUR_PROCESSOR ) {
+ SwapBlock( blkhdr_layout, (UINT8_PTR)&cur_ddb->hdr.blk_chksm ) ;
+ SwapBlock( ddb_layout, (UINT8_PTR)( vstr_ptr + sizeof( DB_HDR ) ) ) ;
+ }
+
+ di_ptr = (VOID_PTR)( ( (INT8_PTR)cur_ddb ) + cur_ddb->hdr.non_gen_off ) ;
+
+ /* Initialize the file systems interface structure */
+ FS_SetDefaultDBLK( cur_fsys, BT_DDB, (CREATE_DBLK_PTR)&gddb_data ) ;
+ gddb_data.std_data.dblk = cur_dblk ;
+
+ (void)FS_InitializeGOS( channel->cur_fsys, &gos ) ;
+
+ /* Set the non-defaulted standard fields for the FS */
+ SetStandFields( channel, &gddb_data.std_data, &cur_ddb->hdr, buffer ) ;
+
+ /* now copy the OS-specific structure into the GOS if needed
+ * These things used to be done by the file system.
+ */
+ switch ( cur_ddb->hdr.os_id ) {
+
+ case FS_PC_OS2 :
+ {
+ F31_OS2_DIR_OS_INFO_PTR dip = di_ptr ;
+
+ gos.access_date = dip->access_date ;
+
+ gos.ea_fork_size = dip->ea_fork_size ;
+ gos.ea_fork_offset = dip->ea_fork_offset ;
+
+ if( dip->ea_fork_size ) {
+ currentStream->id = STRM_OS2_EA ;
+ currentStream->size = U64_Init( dip->ea_fork_size, 0L ) ;
+ currentStream++ ;
+ currentEnv->no_streams++ ;
+ }
+
+ gos.long_path_leng = dip->path_leng ;
+ gos.long_path = (ACHAR_PTR)(VOID_PTR)dip + dip->path ;
+
+ if( cur_ddb->hdr.os_ver == FS_PC_OS2_ACL_VER ) {
+ gos.acl_fork_size = dip->acl_fork_size ;
+ gos.acl_fork_offset = dip->acl_fork_offset ;
+
+ if( dip->acl_fork_size ) {
+ currentStream->id = STRM_OS2_ACL ;
+ currentStream->size = U64_Init( dip->acl_fork_size, 0L ) ;
+ currentStream++ ;
+ currentEnv->no_streams++ ;
+ }
+ } else {
+ gos.acl_fork_size = 0 ;
+ gos.acl_fork_offset = 0 ;
+ }
+
+ break ;
+ }
+
+ case FS_AFP_NOVELL :
+ {
+ F31_OLD_AFP_DIR_OS_INFO_PTR dip = di_ptr ;
+
+ memcpy( gos.finder, dip->finder, sizeof(gos.finder) );
+ gos.nov_owner_id = dip->owner_id ;
+
+ gos.trust_fork_size = dip->trust_fork_size ;
+ gos.trust_fork_offset = dip->trust_fork_offset ;
+
+ if( dip->trust_fork_size ) {
+ currentStream->id = STRM_NOV_TRUST_286 ;
+ currentStream->size = U64_Init( dip->trust_fork_size, 0L ) ;
+ currentStream++ ;
+ currentEnv->no_streams++ ;
+ }
+
+ gos.long_path_leng = dip->path_leng ;
+ gos.long_path = dip->long_path ;
+ break ;
+ }
+
+ case FS_AFP_NOVELL31 :
+ {
+ F31_AFP_DIR_OS_INFO_PTR dip = di_ptr ;
+
+ memcpy( gos.finder, dip->finder, sizeof(gos.finder) );
+ gos.nov_owner_id = dip->owner_id ;
+ gos.trust_fork_size = dip->trust_fork_size ;
+ gos.trust_fork_offset = dip->trust_fork_offset ;
+ gos.trust_fork_format = dip->trust_fork_format ;
+
+ if( dip->trust_fork_size ) {
+ currentStream->id = ( dip->trust_fork_format == TRUSTEE_FMT_286 )
+ ? STRM_NOV_TRUST_286 : STRM_NOV_TRUST_386 ;
+ currentStream->size = U64_Init( dip->trust_fork_size, 0L ) ;
+ currentStream++ ;
+ currentEnv->no_streams++ ;
+ }
+
+ gos.long_path_leng = dip->lpath_leng ;
+ gos.long_path = (ACHAR_PTR)( (UINT8_PTR)dip + dip->long_path ) ;
+
+ gos.dir_info_386.info_valid = dip->info_386.info_valid ;
+ gos.dir_info_386.maximum_space = dip->info_386.maximum_space ;
+ gos.dir_info_386.attributes_386 = dip->info_386.attributes_386 ;
+ gos.dir_info_386.extend_attr = dip->info_386.extend_attr ;
+ gos.dir_info_386.inherited_rights = dip->info_386.inherited_rights ;
+
+ memcpy( gos.proDosInfo, dip->proDosInfo, sizeof(gos.proDosInfo) );
+ break ;
+ }
+
+ case FS_NON_AFP_NOV :
+ case FS_NON_AFP_NOV31 :
+ {
+ F31_NOV_DIR_OS_INFO_PTR dip = di_ptr ;
+
+ gos.nov_owner_id = dip->owner_id;
+ gos.trust_fork_size = dip->trust_fork_size ;
+ gos.trust_fork_offset = dip->trust_fork_offset;
+ gos.trust_fork_format = dip->trust_fork_format ;
+
+ gos.dir_info_386.info_valid = dip->info_386.info_valid ;
+ gos.dir_info_386.maximum_space = dip->info_386.maximum_space ;
+ gos.dir_info_386.attributes_386 = dip->info_386.attributes_386 ;
+ gos.dir_info_386.extend_attr = dip->info_386.extend_attr ;
+ gos.dir_info_386.inherited_rights = dip->info_386.inherited_rights ;
+
+ if( dip->trust_fork_size ) {
+ currentStream->id = ( dip->trust_fork_format == TRUSTEE_FMT_286 )
+ ? STRM_NOV_TRUST_286 : STRM_NOV_TRUST_386 ;
+
+ currentStream->size = U64_Init( dip->trust_fork_size, 0L ) ;
+ currentStream++ ;
+ currentEnv->no_streams++ ;
+ }
+ break ;
+ }
+
+ /* case FS_NLM_AFP_NOVELL31: */
+ default:
+ break ;
+ }
+
+ /* If this is a continuation DDB, and we've called this function, we
+ DIDN'T see the first tape! We don't want to attemt to restore the
+ data anyway, so we're going to call all the data up to the next DBLK
+ pad instead of trying to figure out which stream we're in.
+ */
+ if ( cur_ddb->hdr.blk_attribs & F31_DB_CONT_BIT ) {
+ cur_dblk->com.continue_obj = TRUE ;
+ if( cur_ddb->hdr.rem_data_siz != 0L ) {
+ currentEnv->no_streams = 1 ;
+ currentEnv->streams[0].id = STRM_PAD ;
+ currentEnv->streams[0].size =
+ U64_Init( cur_ddb->hdr.rem_data_siz +
+ currentEnv->pad_size, 0L ) ;
+ }
+ } else {
+ if( currentEnv->pad_size ) {
+ currentEnv->no_streams++ ;
+ currentStream->id = STRM_PAD ;
+ currentStream->size = U64_Init( currentEnv->pad_size, 0L ) ;
+ currentStream++ ;
+ }
+ }
+
+ gos.novell_directory_max_rights = (UINT)
+ ( ( ( cur_ddb->dir_attribs & F31_DDB_READ_ACCESS_BIT ) ? NOVA_DIR_READ_RIGHTS : 0 )
+ | ( ( cur_ddb->dir_attribs & F31_DDB_WRITE_ACCESS_BIT ) ? NOVA_DIR_WRITE_RIGHTS : 0 )
+ | ( ( cur_ddb->dir_attribs & F31_DDB_OPEN_FILE_RIGHTS_BIT ) ? NOVA_DIR_OPEN_FILE_RIGHTS : 0 )
+ | ( ( cur_ddb->dir_attribs & F31_DDB_CREATE_FILE_RIGHTS_BIT ) ? NOVA_DIR_CREATE_FILE_RIGHTS : 0 )
+ | ( ( cur_ddb->dir_attribs & F31_DDB_DELETE_FILE_RIGHTS_BIT ) ? NOVA_DIR_DELETE_FILE_RIGHTS : 0 )
+ | ( ( cur_ddb->dir_attribs & F31_DDB_PARENTAL_RIGHTS_BIT ) ? NOVA_DIR_PARENTAL_RIGHTS : 0 )
+ | ( ( cur_ddb->dir_attribs & F31_DDB_SEARCH_RIGHTS_BIT ) ? NOVA_DIR_SEARCH_RIGHTS : 0 )
+ | ( ( cur_ddb->dir_attribs & F31_DDB_MOD_FILE_ATTRIBS_BIT ) ? NOVA_DIR_MOD_FILE_ATTRIBS : 0 ) ) ;
+
+ gddb_data.std_data.attrib =
+ ( ( cur_ddb->dir_attribs & F31_DDB_EMPTY_BIT ) ? DIR_EMPTY_BIT : 0 )
+ | ( ( cur_ddb->dir_attribs & F31_DDB_HIDDEN_BIT ) ? OBJ_HIDDEN_BIT : 0 )
+ | ( ( cur_ddb->dir_attribs & F31_DDB_SYSTEM_BIT ) ? OBJ_SYSTEM_BIT : 0 ) ;
+
+ /* Set the non-defaulted DDB specific fields */
+ gddb_data.path_name = (CHAR_PTR)( vstr_ptr + cur_ddb->dir_name_off ) ;
+ gddb_data.path_size = (INT16)cur_ddb->dir_name_len ;
+ gddb_data.creat_date = &cur_ddb->create_date ;
+ gddb_data.mod_date = &cur_ddb->mod_date ;
+ gddb_data.backup_date = &cur_ddb->backup_date ;
+
+ /* We don't have one of these, but they need a pointer to something! */
+ fake_access_date.date_valid = FALSE ;
+ gddb_data.access_date = &fake_access_date ;
+
+ gddb_data.std_data.os_info = (BYTE_PTR)&gos ;
+ gddb_data.std_data.os_info_size = sizeof(gos) ;
+ gddb_data.std_data.os_id = FS_GOS ;
+
+ /* Tell the file system to do its thing */
+ tmp_filter = (UINT16)FS_CreateGenDDB( cur_fsys, &gddb_data ) ;
+
+ ProcessDataFilter( channel, tmp_filter ) ;
+
+ channel->lst_did = cur_ddb->hdr.blk_id ;
+
+ currentEnv->curr_lba = BM_BeginningLBA( buffer ) +
+ BM_NextByteOffset( buffer ) ;
+ currentEnv->in_streams = FALSE ;
+
+ return ret_val ;
+}
+
+/**/
+/**
+
+ Name: F31_RdFDB
+
+ Description: Translates a tape format blk into a OS DBLK.
+
+ Modified: 9/21/1989 11:46:41
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+INT16 F31_RdFDB(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+ DBLK_PTR cur_dblk = channel->cur_dblk ;
+ F31_FDB_PTR cur_fdb = (F31_FDB_PTR)( BM_NextBytePtr( buffer ) ) ;
+ FSYS_HAND cur_fsys = channel->cur_fsys ;
+ GEN_FDB_DATA gfdb_data ;
+ UINT16 tmp_filter ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ ACHAR_PTR vstr_ptr = (ACHAR_PTR)cur_fdb ;
+ VOID_PTR di_ptr ;
+ GOS gos ;
+ F31_ENV_PTR currentEnv = (F31_ENV_PTR)channel->fmt_env ;
+ STREAM_INFO_PTR currentStream = &currentEnv->streams[0] ;
+ DATE_TIME fake_access_date ;
+
+ /* If the processor types don't match, swap bytes */
+ if( cur_fdb->hdr.format != CUR_PROCESSOR ) {
+ SwapBlock( blkhdr_layout, (UINT8_PTR)&cur_fdb->hdr.blk_chksm ) ;
+ SwapBlock( ddb_layout, (UINT8_PTR)( vstr_ptr + sizeof( DB_HDR ) ) ) ;
+ }
+
+ di_ptr = (VOID_PTR)( ( (INT8_PTR)cur_fdb ) + cur_fdb->hdr.non_gen_off ) ;
+
+ /* Initialize the file systems interface structure */
+ FS_SetDefaultDBLK( cur_fsys, BT_FDB, (CREATE_DBLK_PTR)&gfdb_data ) ;
+ gfdb_data.std_data.dblk = cur_dblk ;
+
+ (void)FS_InitializeGOS( channel->cur_fsys, &gos ) ;
+
+ /* Set the non-defaulted standard fields for the FS */
+ SetStandFields( channel, &gfdb_data.std_data, &cur_fdb->hdr, buffer ) ;
+
+ if( cur_fdb->hdr.gen_data_siz ) {
+ currentEnv->no_streams++ ;
+ currentStream->id = STRM_GENERIC_DATA ;
+ currentStream->size = U64_Init( cur_fdb->hdr.gen_data_siz, 0L ) ;
+ currentStream++ ;
+ }
+
+ /* now copy the OS-specific structure into the GOS if needed
+ * These things used to be done by the file system.
+ */
+ switch ( cur_fdb->hdr.os_id ) {
+
+ case FS_PC_OS2 :
+ {
+ F31_OS2_FILE_OS_INFO_PTR dip = di_ptr ;
+
+ gos.access_date = dip->access_date ;
+ gos.ea_fork_size = dip->ea_fork_size ;
+ gos.ea_fork_offset = dip->ea_fork_offset ;
+
+ if( dip->ea_fork_size ) {
+ currentStream->id = STRM_OS2_EA ;
+ currentStream->size = U64_Init( dip->ea_fork_size, 0L ) ;
+ currentStream++ ;
+ currentEnv->no_streams++ ;
+ }
+
+ if( cur_fdb->hdr.os_ver == FS_PC_OS2_ACL_VER ) {
+ gos.acl_fork_size = dip->acl_fork_size ;
+ gos.acl_fork_offset = dip->acl_fork_offset ;
+
+ if( dip->acl_fork_size ) {
+ currentStream->id = STRM_OS2_ACL ;
+ currentStream->size = U64_Init( dip->acl_fork_size, 0L ) ;
+ currentStream++ ;
+ currentEnv->no_streams++ ;
+ }
+ } else {
+ gos.acl_fork_size = 0 ;
+ gos.acl_fork_offset = 0 ;
+ }
+
+ gos.data_fork_size = dip->data_fork_size ;
+ gos.data_fork_offset = dip->data_fork_offset ;
+ gos.long_path_leng = dip->lname_leng ;
+ gos.long_path = (ACHAR_PTR)( (UINT8_PTR)dip + dip->long_name ) ;
+ gos.alloc_size = dip->alloc_size ;
+ break ;
+ }
+
+ case FS_AFP_NOVELL :
+ case FS_AFP_NOVELL31 :
+ {
+ F31_AFP_FILE_OS_INFO_PTR dip = di_ptr ;
+
+ memcpy( gos.finder, dip->finder, sizeof(gos.finder) );
+ memcpy( gos.long_name, dip->long_name, sizeof(gos.long_name) );
+
+ gos.data_fork_size = dip->data_fork_size ;
+ gos.data_fork_offset = dip->data_fork_offset ;
+
+ gos.res_fork_size = dip->res_fork_size ;
+ gos.res_fork_offset = dip->res_fork_offset ;
+
+ if( dip->res_fork_size ) {
+ dip->res_fork_size = BSwapLong( dip->res_fork_size ) ;
+ currentStream->id = STRM_MAC_RESOURCE ;
+ currentStream->size = U64_Init( dip->res_fork_size, 0L ) ;
+ currentStream++ ;
+ currentEnv->no_streams++ ;
+ }
+
+ gos.nov_owner_id = dip->owner_id ;
+ gos.access_date16 = dip->access_date ;
+
+ gos.file_info_386.info_valid = dip->info_386.info_valid ;
+ gos.file_info_386.creation_time = dip->info_386.creation_time ;
+ gos.file_info_386.archiver_id = dip->info_386.archiver_id ;
+ gos.file_info_386.attributes_386 = dip->info_386.attributes_386 ;
+ gos.file_info_386.last_modifier_id = dip->info_386.last_modifier_id ;
+ gos.file_info_386.trust_fork_size = dip->info_386.trust_fork_size ;
+ gos.file_info_386.trust_fork_offset = dip->info_386.trust_fork_offset ;
+ gos.file_info_386.trust_fork_format = dip->info_386.trust_fork_format ;
+ gos.file_info_386.inherited_rights = dip->info_386.inherited_rights ;
+
+ if( dip->info_386.trust_fork_size ) {
+ currentStream->id = ( dip->info_386.trust_fork_format == TRUSTEE_FMT_286 )
+ ? STRM_NOV_TRUST_286 : STRM_NOV_TRUST_386 ;
+
+ currentStream->size = U64_Init( dip->info_386.trust_fork_size, 0L ) ;
+ currentStream++ ;
+ currentEnv->no_streams++ ;
+ }
+
+ memcpy( gos.proDosInfo, dip->proDosInfo, sizeof(gos.proDosInfo) );
+ break ;
+ }
+
+ case FS_NON_AFP_NOV :
+ case FS_NON_AFP_NOV31 :
+ {
+ F31_NOV_FILE_OS_INFO_PTR dip = di_ptr ;
+
+ gos.nov_owner_id = dip->owner_id;
+ gos.access_date16 = dip->access_date ;
+
+ gos.file_info_386.info_valid = dip->info_386.info_valid ;
+ gos.file_info_386.creation_time = dip->info_386.creation_time ;
+ gos.file_info_386.archiver_id = dip->info_386.archiver_id ;
+ gos.file_info_386.attributes_386 = dip->info_386.attributes_386 ;
+ gos.file_info_386.last_modifier_id = dip->info_386.last_modifier_id ;
+ gos.file_info_386.trust_fork_size = dip->info_386.trust_fork_size ;
+ gos.file_info_386.trust_fork_offset = dip->info_386.trust_fork_offset ;
+ gos.file_info_386.trust_fork_format = dip->info_386.trust_fork_format ;
+ gos.file_info_386.inherited_rights = dip->info_386.inherited_rights ;
+
+ if( dip->info_386.trust_fork_size ) {
+ currentStream->id = ( dip->info_386.trust_fork_format == TRUSTEE_FMT_286 )
+ ? STRM_NOV_TRUST_286 : STRM_NOV_TRUST_386 ;
+
+ currentStream->size = U64_Init( dip->info_386.trust_fork_size, 0L ) ;
+ currentStream++ ;
+ currentEnv->no_streams++ ;
+ }
+
+ gos.data_fork_offset = dip->data_fork_offset ;
+ break ;
+ }
+
+ /* case FS_NLM_AFP_NOVELL31: */
+ default:
+ break ;
+ }
+
+ /* If this is a continuation FDB, and we've called this function, we
+ DIDN'T see the first tape! We don't want to attemt to restore the
+ data anyway, so we're going to call all the data up to the next DBLK
+ pad instead of trying to figure out which stream we're in.
+ */
+ if ( cur_fdb->hdr.blk_attribs & F31_DB_CONT_BIT ) {
+ cur_dblk->com.continue_obj = TRUE ;
+ if( cur_fdb->hdr.rem_data_siz != 0L ) {
+ currentEnv->no_streams = 1 ;
+ currentEnv->streams[0].id = STRM_PAD ;
+ currentEnv->streams[0].size =
+ U64_Init( cur_fdb->hdr.rem_data_siz +
+ currentEnv->pad_size, 0L ) ;
+ }
+ } else {
+ if( currentEnv->pad_size ) {
+ currentEnv->no_streams++ ;
+ currentStream->id = STRM_PAD ;
+ currentStream->size = U64_Init( currentEnv->pad_size, 0L ) ;
+ currentStream++ ;
+ }
+ }
+
+ gos.novell_file_attributes = (UINT)
+ ( ( ( cur_fdb->file_attribs & F31_FDB_READ_ONLY_BIT ) ? NOVA_FILE_READ_ONLY : 0 )
+ | ( ( cur_fdb->file_attribs & F31_FDB_HIDDEN_BIT ) ? NOVA_FILE_HIDDEN : 0 )
+ | ( ( cur_fdb->file_attribs & F31_FDB_SYSTEM_BIT ) ? NOVA_FILE_SYSTEM : 0 )
+ | ( ( cur_fdb->file_attribs & F31_FDB_EXECUTE_ONLY_BIT ) ? NOVA_FILE_EXECUTE_ONLY : 0 )
+ | ( ( cur_fdb->file_attribs & F31_FDB_MODIFIED_BIT ) ? NOVA_FILE_MODIFIED : 0 )
+ | ( ( cur_fdb->file_attribs & F31_FDB_SHAREABLE_BIT ) ? NOVA_FILE_SHAREABLE : 0 ) ) ;
+
+ gos.novell_extended_attributes = (UINT)
+ ( ( ( cur_fdb->file_attribs & F31_FDB_TRANSACTIONAL_BIT ) ? NOVA_FILE_TRANSACTIONAL : 0 )
+ | ( ( cur_fdb->file_attribs & F31_FDB_INDEXING_BIT ) ? NOVA_FILE_INDEXING : 0 ) ) ;
+
+ gfdb_data.std_data.attrib =
+ ( ( cur_fdb->file_attribs & F31_FDB_CORRUPT_FILE ) ? OBJ_CORRUPT_BIT : 0 )
+ | ( ( cur_fdb->file_attribs & F31_FDB_IN_USE_BIT ) ? FILE_IN_USE_BIT : 0 )
+ | ( ( cur_fdb->file_attribs & F31_FDB_READ_ONLY_BIT ) ? OBJ_READONLY_BIT : 0 )
+ | ( ( cur_fdb->file_attribs & F31_FDB_HIDDEN_BIT ) ? OBJ_HIDDEN_BIT : 0 )
+ | ( ( cur_fdb->file_attribs & F31_FDB_SYSTEM_BIT ) ? OBJ_SYSTEM_BIT : 0 )
+ | ( ( cur_fdb->file_attribs & F31_FDB_MODIFIED_BIT ) ? OBJ_MODIFIED_BIT : 0 ) ;
+
+ /* Set the non-defaulted FDB specific fields */
+ gfdb_data.fname = (CHAR_PTR)( vstr_ptr + cur_fdb->file_name_off ) ;
+ gfdb_data.fname_size = cur_fdb->file_name_len ;
+ gfdb_data.creat_date = &cur_fdb->create_date ;
+ gfdb_data.mod_date = &cur_fdb->mod_date ;
+ gfdb_data.backup_date = &cur_fdb->backup_date ;
+ gfdb_data.file_ver = cur_fdb->file_version ;
+
+ /* We don't have one of these, but they need a pointer to something! */
+ fake_access_date.date_valid = FALSE ;
+ gfdb_data.access_date = &fake_access_date ;
+
+ gfdb_data.std_data.os_info = (BYTE_PTR)&gos ;
+ gfdb_data.std_data.os_info_size = sizeof(gos) ;
+ gfdb_data.std_data.os_id = FS_GOS ;
+
+ /* Tell the file system to do its thing */
+ tmp_filter = (UINT16)FS_CreateGenFDB( cur_fsys, &gfdb_data ) ;
+
+ ProcessDataFilter( channel, tmp_filter ) ;
+
+ channel->lst_fid = cur_fdb->hdr.blk_id ;
+
+ currentEnv->curr_lba = BM_BeginningLBA( buffer ) +
+ BM_NextByteOffset( buffer ) ;
+ currentEnv->in_streams = FALSE ;
+
+ return( ret_val ) ;
+}
+
+INT16 F31_RdStream( CHANNEL_PTR Channel,
+ BUF_PTR Buffer )
+{
+ F31_ENV_PTR currentEnv = ( F31_ENV_PTR ) Channel->fmt_env ;
+
+ currentEnv->in_streams = TRUE ;
+
+ Channel->current_stream = currentEnv->streams[currentEnv->cur_stream++] ;
+
+ if( --currentEnv->no_streams == 0 ) {
+ currentEnv->stream_mode = FALSE ;
+ }
+
+ /* Reset Filter */
+ if( Channel->current_stream.id == STRM_PAD ) {
+ SetChannelStatus( Channel, CH_SKIP_CURRENT_STREAM ) ;
+ } else {
+ ClrChannelStatus( Channel, CH_SKIP_CURRENT_STREAM ) ;
+ }
+
+ return( TFLE_NO_ERR ) ;
+ (VOID)Buffer;
+}
+/**/
+/**
+
+ Name: F31_RdIDB
+
+ Description:
+
+ Modified: 9/21/1989 13:1:40
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+INT16 F31_RdIDB(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+#ifdef SUPPORT_IMAGE
+
+ BOOLEAN ret_val = TRUE ;
+ DBLK_PTR cur_dblk = channel->cur_dblk ;
+ F31_IDB_PTR cur_idb = (F31_IDB_PTR)( BM_NextBytePtr( buffer ) ) ;
+ FSYS_HAND cur_fsys = channel->cur_fsys ;
+ GEN_IDB_DATA gidb_data ;
+ UINT16 tmp_filter ;
+
+
+
+ /* If our processor types don't match swap bytes */
+ if( cur_idb->hdr.format != CUR_PROCESSOR ) {
+ SwapBlock( blkhdr_layout, (UINT8_PTR)&cur_idb->hdr.blk_chksm ) ;
+ SwapBlock( idb_layout, (UINT8_PTR)( (UINT8_PTR)cur_idb + sizeof( DB_HDR ) ) ) ;
+ }
+
+ /* Initialize the file systems interface structure */
+ FS_SetDefaultDBLK( cur_fsys, BT_IDB, (CREATE_DBLK_PTR)&gidb_data ) ;
+ gidb_data.std_data.dblk = cur_dblk ;
+
+ /* Set the non-defaulted standard fields for the FS */
+ SetStandFields( channel, &gidb_data.std_data, &cur_idb->hdr, buffer ) ;
+
+ gidb_data.std_data.attrib = cur_idb->image_attribs ;
+
+ /* Set the continuation bit, encryption and compression bits */
+ gidb_data.std_data.attrib |= cur_idb->hdr.blk_attribs ;
+
+ /* Set the non-defaulted IDB specific fields */
+ gidb_data.pname = (CHAR_PTR)( (ACHAR_PTR)cur_idb + cur_idb->partition_name_off ) ;
+ gidb_data.pname_size = cur_idb->partition_name_len ;
+
+ gidb_data.byte_per_sector = (UINT16)cur_idb->bytes_in_sector ;
+ gidb_data.num_sect = cur_idb->part_no_of_sector ;
+ gidb_data.sys_ind = cur_idb->part_sys_ind ;
+ gidb_data.hhead = cur_idb->no_of_heads ;
+ gidb_data.hsect = (UINT16)cur_idb->no_of_sectors ;
+ gidb_data.rsect = cur_idb->relative_sector ;
+
+ /* Setup Total Data Size */
+ channel->tdata_size = U32_To_U64( cur_idb->hdr.tot_data_siz ) ;
+
+ tmp_filter = (UINT16)FS_CreateGenIDB( cur_fsys, &gidb_data ) ;
+
+ ProcessDataFilter( channel, tmp_filter ) ;
+#else
+ (VOID)channel;(VOID)buffer;
+#endif
+
+ return( TFLE_NO_ERR ) ;
+}
+
+/**/
+/**
+
+ Name: F31_RdCFDB
+
+ Description:
+
+ Modified: 9/21/1989 12:2:27
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+INT16 F31_RdCFDB(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+ DBLK_PTR cur_dblk = channel->cur_dblk ;
+ F31_CFDB_PTR cur_cfdb = (F31_CFDB_PTR)( BM_NextBytePtr( buffer ) ) ;
+ FSYS_HAND cur_fsys = channel->cur_fsys ;
+ GEN_CFDB_DATA gcfdb_data ;
+ UINT16 tmp_filter ;
+ INT16 ret_val = TFLE_NO_ERR ;
+
+ /* If the processor types don't match, swap bytes */
+ if( cur_cfdb->hdr.format != CUR_PROCESSOR ) {
+ SwapBlock( blkhdr_layout, (UINT8_PTR)&cur_cfdb->hdr.blk_chksm ) ;
+ SwapBlock( cfdb_layout, (UINT8_PTR)( (UINT8_PTR)cur_cfdb + sizeof( DB_HDR ) ) ) ;
+ }
+
+ /* Initialize the file systems interface structure */
+ FS_SetDefaultDBLK( cur_fsys, BT_CFDB, (CREATE_DBLK_PTR)&gcfdb_data ) ;
+ gcfdb_data.std_data.dblk = cur_dblk ;
+
+ /* Set the non-defaulted standard fields for the FS */
+ SetStandFields( channel, &gcfdb_data.std_data, &cur_cfdb->hdr, buffer ) ;
+
+ gcfdb_data.std_data.attrib = cur_cfdb->crupt_file_attribs ;
+
+ /* Set the continuation bit, encryption and compression bits */
+ gcfdb_data.std_data.attrib |= cur_cfdb->hdr.blk_attribs ;
+
+ /* Set the non-defaulted standard fields for the FS */
+ gcfdb_data.corrupt_offset = cur_cfdb->file_offset ;
+
+ /* Tell the file system to do its thing */
+ tmp_filter = (UINT16)FS_CreateGenCFDB( cur_fsys, &gcfdb_data ) ;
+
+ ProcessDataFilter( channel, tmp_filter ) ;
+
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Name: F31_RdUDB
+
+ Description: Translates a Unknown Desciptor Block and throws away
+ the data.
+
+ Modified: 9/25/1989 14:50:13
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+INT16 F31_RdUDB(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+// F31_UDB_PTR cur_udb = (F31_UDB_PTR)( BM_NextBytePtr( buffer ) ) ;
+ GEN_UDB_DATA gudb_data ;
+ F31_ENV_PTR currentEnv = ( F31_ENV_PTR ) channel->fmt_env ;
+
+ /* Initialize the file systems interface structure */
+ FS_SetDefaultDBLK( channel->cur_fsys, BT_UDB, (CREATE_DBLK_PTR)&gudb_data ) ;
+ gudb_data.std_data.dblk = channel->cur_dblk ;
+
+ /* Create the entry less Ccfdb */
+ FS_CreateGenUDB( channel->cur_fsys, &gudb_data ) ;
+
+ currentEnv->pad_size = 0 ;
+
+/*
+ channel->data_size = lw_UINT64_ZERO ;
+ channel->tdata_size = U32_To_U64( cur_udb->hdr.length * 512L ) ;
+*/
+
+ return( TFLE_NO_ERR ) ;
+ (void)buffer;
+}
+
+/**/
+/**
+
+ Name: F31_RdContTape
+
+ Description: Sets up the continuation tape to pass over the updated
+ bs.
+
+ Modified: 9/29/1989 8:49:54
+
+ Returns:
+
+ Notes: THIS ASSUMES THAT THE BUFFER POINTER IS POINTING DIRECTLY
+ AFTER THE CONT. VCB. TO THE NEXT TBLK.
+
+ FURTHER, IT IS ASSUMED THE CURRENT BUFFER HAS BEEN READ
+ FROM THE NEXT TAPE IN THE TAPE SEQUENCE ( THIS SHOULD HAVE
+ BEEN DONE BY "Tape Positioning" .
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+BOOLEAN F31_RdContTape(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+ BOOLEAN ret_val = FALSE ;
+ DB_HDR_PTR cur_hdr = (DB_HDR_PTR)( BM_NextBytePtr( buffer ) ) ;
+ F31_ENV_PTR currentEnv = ( F31_ENV_PTR ) channel->fmt_env ;
+
+ if( IsChannelStatus( channel, CH_EOS_AT_EOM ) ) {
+ ClrChannelStatus( channel, CH_EOS_AT_EOM ) ;
+ return( TRUE ) ;
+ }
+
+ /* Set the lba of the beginning of the buffer and adjust the running lba */
+ BM_SetBeginningLBA( buffer, ( cur_hdr->lba - ( BM_NextByteOffset( buffer ) / 512L ) ) ) ;
+ channel->running_lba = cur_hdr->lba + ( BM_BytesFree( buffer ) / 512L ) ;
+
+ /* Find The last DBLK, we were operating on */
+ while( cur_hdr->blk_id != channel->eom_id ) {
+ BM_UpdCnts( buffer, (UINT16)( cur_hdr->length * 512 ) ) ;
+ cur_hdr = (DB_HDR_PTR)( BM_NextBytePtr( buffer ) ) ;
+ }
+
+ /* Okay we have a live one, let's update the counts */
+ if( cur_hdr->blk_id == channel->eom_id ) {
+ ret_val = TRUE ;
+ /* There is no data, so let's make set ourselves to the next block */
+ if( !cur_hdr->rem_data_siz ) {
+ BM_UpdCnts( buffer, (UINT16)( cur_hdr->length * 512 ) ) ;
+ } else {
+ if( currentEnv->no_streams != 0 ) {
+ currentEnv->stream_mode = TRUE ;
+ }
+ ProcessDataFilter( channel, channel->eom_filter ) ;
+ BM_UpdCnts( buffer, cur_hdr->data_off ) ;
+ }
+
+ }
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Name: SetStandFields
+
+ Description: Sets up the standard fields in translation to dblks.
+
+ Modified: 9/20/1989 14:8:27
+
+ Returns: Nothing.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+static VOID _near SetStandFields(
+ CHANNEL_PTR channel,
+ STD_DBLK_DATA_PTR std_data,
+ DB_HDR_PTR cur_hdr,
+ BUF_PTR buffer )
+{
+ UINT8_PTR os_info = (UINT8_PTR)cur_hdr ;
+ F31_ENV_PTR currentEnv = ( F31_ENV_PTR ) channel->fmt_env ;
+ UINT32 dataSize ;
+ BOOLEAN cont_mode ;
+
+ cont_mode = (BOOLEAN)( IsChannelStatus( channel, CH_CONTINUING ) ) ;
+
+ /* Reset the stream stuff */
+ if( !cont_mode ) {
+ currentEnv->no_streams = 0 ;
+ currentEnv->cur_stream = 0 ;
+
+ if( cur_hdr->tot_data_siz ) {
+ currentEnv->stream_mode = TRUE ;
+ }
+ }
+
+ std_data->tape_seq_num = channel->ts_num ;
+ std_data->os_id = ( UINT8 ) cur_hdr->os_id ;
+ std_data->os_ver = ( UINT8 ) cur_hdr->os_ver ;
+ std_data->disp_size = U32_To_U64( cur_hdr->gen_data_siz ) ;
+ std_data->blkid = cur_hdr->blk_id ;
+ std_data->lba = cur_hdr->lba ;
+ std_data->string_type = BEC_ANSI_STR ;
+ std_data->compressed_obj = FALSE ;
+
+
+ /* We don't have to retranslate */
+ channel->retranslate_size = lw_UINT64_MAX ;
+
+ /* Is This a continuation */
+ dataSize = ( ( cur_hdr->blk_attribs & F31_DB_CONT_BIT )
+ ? cur_hdr->rem_data_siz
+ : cur_hdr->tot_data_siz ) ;
+
+ if( !cont_mode ) {
+ currentEnv->pad_size = (UINT16)F31_CalculatePad( ChannelBlkSize( channel ), dataSize,
+ ( UINT16 ) ( ChannelBlkSize( channel ) - cur_hdr->data_off ) ) ;
+ }
+
+ if( dataSize != 0L ) {
+ BM_UpdCnts( buffer, cur_hdr->data_off ) ;
+ } else {
+ BM_UpdCnts( buffer, (UINT16)( cur_hdr->length * 512 ) ) ;
+ }
+
+ /* Get Generic info */
+ std_data->os_info = (BYTE_PTR)( os_info + cur_hdr->non_gen_off ) ;
+ std_data->os_info_size = cur_hdr->non_gen_siz ;
+
+ /* set filemark position from block (ugh!)
+ * as unpleasant as this may be, it is the only chance we have
+ * to keep up with the random tape motion caused by our Fast File
+ * strategy.
+ */
+ channel->cur_drv->cur_pos.fmks = cur_hdr->fmks ;
+
+ if ( BM_ReadError( buffer ) == GEN_ERR_ENDSET
+ || BM_ReadError( buffer ) == GEN_ERR_EOM ) {
+ channel->cur_drv->cur_pos.fmks++ ;
+ }
+}
+
+/**/
+/**
+
+ Name: F31_RdEndSet
+
+ Description: Does the Action at a filemark.
+
+ Modified: 12/27/1989 14:12:42
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+UINT16 F31_RdException(
+ CHANNEL_PTR channel, /* which channel */
+ INT16 exception ) /* which exception seen */
+{
+ BUF_PTR tmpBUF ;
+ INT16 drv_hdl = channel->cur_drv->drv_hdl ;
+ UINT16 ret_val = FMT_EXC_HOSED ;
+ DRIVE_PTR curDRV = channel->cur_drv ;
+ RET_BUF myret ;
+ UINT16 blk_type ;
+ F31_ENV_PTR currentEnv = ( F31_ENV_PTR ) channel->fmt_env ;
+
+ currentEnv->stream_mode = FALSE ;
+
+ if ( ( exception != GEN_ERR_ENDSET ) && ( exception != GEN_ERR_EOM ) ) {
+ return ret_val ;
+ }
+
+ /* re-use channel->cur_buff (don't need to BM_Put() it) */
+ if ( channel->cur_buff != NULL ) {
+ tmpBUF = channel->cur_buff ;
+ BM_InitBuf( tmpBUF ) ;
+ } else {
+ if( ( tmpBUF = BM_Get( &channel->buffer_list ) ) == NULL ) {
+ tmpBUF = BM_GetVCBBuff( &channel->buffer_list ) ;
+ }
+ }
+
+ if( tmpBUF == NULL ) {
+ /* !!! We need something better than this !!! */
+ return FMT_EXC_HOSED ;
+ }
+
+ TpRead( drv_hdl, BM_XferBase( tmpBUF ), (UINT32)BM_XferSize( tmpBUF ) ) ;
+ while( TpReceive( drv_hdl, &myret ) == FAILURE ) {
+ /* for non-preemptive operating systems: */
+ ThreadSwitch( ) ;
+ }
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( channel->cur_drv->thw_inf.the, myret.the ) ;
+
+ if ( myret.gen_error != GEN_NO_ERR ) {
+ curDRV->thw_inf.drv_status = myret.status ;
+ }
+
+/* NOTE: We used to check for proper gen_error codes below, as well as
+ sufficient len_got. However, due to an error in existing code
+ which causes Wangtech drives to mess up (like that's really hard)
+ and not write a second filemark, we now check only for 512 read,
+ and leave it up to the translators block determiner to determine
+ if something is amiss.
+*/
+ if ( myret.len_got < 512UL ) {
+ if ( channel->cur_buff == NULL ) {
+ BM_UseAll( tmpBUF ) ;
+ BM_Put( tmpBUF ) ;
+ }
+ return FMT_EXC_HOSED ;
+ }
+
+ F31_DetBlkType( channel, tmpBUF, &blk_type ) ;
+
+ switch( blk_type ) {
+ case BT_BSDB:
+ /* BSDB may have associated data. If it does, we eat it! */
+ if( myret.gen_error == GEN_NO_ERR ) {
+ TpReadEndSet( drv_hdl, 1, FORWARD ) ;
+ while( TpReceive( drv_hdl, &myret ) == FAILURE ) {
+ /* for non-preemptive operating systems: */
+ ThreadSwitch( ) ;
+ }
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( channel->cur_drv->thw_inf.the, myret.the ) ;
+
+ if( myret.gen_error != GEN_NO_ERR ) {
+ curDRV->thw_inf.drv_status = myret.status ;
+ ret_val = FMT_EXC_HOSED ;
+ break;
+ }
+ }
+ ret_val = FMT_EXC_EOS ;
+ break ;
+
+ case BT_CVCB:
+ if( myret.gen_error == GEN_NO_ERR ) {
+ ret_val = FMT_EXC_HOSED ;
+ } else {
+ ret_val = FMT_EXC_EOM ;
+ }
+ break ;
+ default:
+ ret_val = FMT_EXC_HOSED ;
+ break ;
+ }
+ curDRV->cur_pos.fmks ++ ;
+ BM_UseAll( tmpBUF ) ; /* so we have no bytes left */
+
+ /* channel->cur_buff will be Punted */
+ if ( channel->cur_buff == NULL ) {
+ BM_Put( tmpBUF ) ;
+ }
+
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Name: F31_MoveToVCB
+
+ Description:
+
+ Modified: 10/25/1990
+
+ Returns:
+
+ Notes:
+
+ Declaration:
+
+**/
+INT16 F31_MoveToVCB(
+ CHANNEL_PTR channel,
+ INT16 number,
+ BOOLEAN_PTR need_read,
+ BOOLEAN really_move )
+{
+ INT16 nmarks = 0 ; /* number of file marks to move */
+ INT16 ret_val = TFLE_NO_ERR ;
+ BOOLEAN at_mos = IsPosBitSet( channel->cur_drv, AT_MOS ) != 0UL ;
+ BOOLEAN at_eos = ( ! at_mos ) && IsPosBitSet( channel->cur_drv, AT_EOS ) ;
+
+ msassert( number <= 1 ) ;
+
+ if ( really_move ) { /* this is a no-op for us */
+ * need_read = FALSE ;
+ return( TFLE_NO_ERR ) ;
+ }
+
+ ClrPosBit( channel->cur_drv, AT_MOS ) ;
+
+ if ( number == 1 ) { /* move forward */
+ * need_read = TRUE ;
+ if( IsChannelStatus( channel, CH_AT_EOM ) ) {
+ ClrChannelStatus( channel, CH_AT_EOM ) ;
+ ret_val = TF_NEED_NEW_TAPE ;
+ } else if( at_eos ) {
+ ret_val = TFLE_NO_ERR ;
+ } else {
+ ret_val = MoveFileMarks( channel, 1, FORWARD ) ;
+ if( ret_val == TFLE_NO_ERR || ret_val == TFLE_UNEXPECTED_EOM ) {
+ ret_val = F31_RdException( channel, GEN_ERR_ENDSET ) ;
+ if( ret_val == FMT_EXC_HOSED ) {
+ SetPosBit( channel->cur_drv, REW_CLOSE ) ;
+ ret_val = TFLE_TAPE_INCONSISTENCY ;
+ } else if ( ret_val == FMT_EXC_EOM ) {
+ ret_val = TF_NEED_NEW_TAPE ;
+ } else {
+ SetPosBit( channel->cur_drv, AT_EOS ) ;
+ ret_val = TFLE_NO_ERR ;
+ }
+ } else if( ret_val == TF_NO_MORE_DATA ) {
+ SetPosBit( channel->cur_drv, REW_CLOSE ) ;
+ ret_val = TFLE_TAPE_INCONSISTENCY ;
+ }
+ }
+
+ } else {
+ /* If we're moving backward, AT_EOM is essentially the same as
+ AT_EOS (same number of filemarks to skip).
+ */
+ if( IsChannelStatus( channel, CH_AT_EOM ) ) {
+ ClrChannelStatus( channel, CH_AT_EOM ) ;
+ at_mos = FALSE ;
+ at_eos = TRUE ;
+ }
+ if ( number < 0 ) { /* move backward */
+ nmarks = ( number * -2 ) + 1 ;
+ if ( at_eos ) {
+ nmarks += 2 ;
+ }
+ } else { /* current */
+ if ( at_mos ) {
+ nmarks = 1 ;
+ } else if ( at_eos ) {
+ nmarks = 3 ;
+ } else { /* we're already there. */
+ * need_read = FALSE ;
+ ret_val = TFLE_NO_ERR ;
+ }
+ }
+ }
+
+ if( nmarks != 0 ) {
+ if ( channel->cur_drv->thw_inf.drv_info.drv_features & TDI_REV_FMK ) {
+ if( nmarks > (INT16) channel->cur_drv->cur_pos.fmks ) {
+ /*
+ We probably have one of two conditions:
+ 1. We are searching for the first set on tape.
+ 2. There is a mix of formats on the tape, so we
+ have to take it from the top.
+ */
+ ret_val = TF_NEED_REWIND_FIRST ;
+ } else {
+ * need_read = TRUE ;
+ ret_val = MoveFileMarks( channel, nmarks, BACKWARD ) ;
+ }
+ } else {
+ /* we can't go backwards without rewinding (ugh!) */
+ ret_val = TF_NEED_REWIND_FIRST ;
+ }
+ }
+
+ return ret_val ;
+}
+
+/**/
+/**
+
+ Name: F31_CalculatePad
+
+ Description: For the given amount of data calculates the appropriate
+ pad value.
+
+ Modified: 10/10/1989 15:5:3
+
+ Returns: The amount of data to use as a pad.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+UINT16 F31_CalculatePad(
+ UINT16 blk_size, /* The block size of a device */
+ UINT32 data_size, /* The total data size */
+ UINT16 bytes_to_next_blk ) /* The bytes to the next block */
+{
+ UINT16 pad ;
+
+ data_size -= bytes_to_next_blk ;
+ if( ( pad = (UINT16)( data_size % blk_size ) ) != 0 ) {
+ pad = blk_size - pad ;
+ }
+
+ return( pad ) ;
+
+}
diff --git a/private/utils/ntbackup/src/mayn40rd.c b/private/utils/ntbackup/src/mayn40rd.c
new file mode 100644
index 000000000..9e14bf324
--- /dev/null
+++ b/private/utils/ntbackup/src/mayn40rd.c
@@ -0,0 +1,2431 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-92
+
+
+ Name: mayn40rd.c
+
+ Description: Contains General and Read API's for Maynard's
+ 4.0 Format.
+
+ $Log: T:/LOGFILES/MAYN40RD.C_V $
+
+ Rev 1.74.1.12 27 Mar 1994 19:30:36 GREGG
+Don't map password strings to unicode no matter what.
+
+ Rev 1.74.1.11 16 Jan 1994 14:35:08 GREGG
+tape_password field in gvcb_data was being left uninitialized.
+
+ Rev 1.74.1.10 05 Jan 1994 10:56:18 BARRY
+Changed UINT16 parameters in Unicode mapping functions to INTs
+
+ Rev 1.74.1.9 22 Dec 1993 18:15:14 STEVEN
+don't cast INT16_PTR into an INT_PTR!!!
+
+ Rev 1.74.1.8 15 Dec 1993 18:15:24 GREGG
+Fixed warnings.
+
+ Rev 1.74.1.7 15 Dec 1993 17:22:36 GREGG
+Fixed method used to determine if we have the right tape in NewTape.
+
+ Rev 1.74.1.6 13 Dec 1993 19:25:52 GREGG
+Don't init 'make_streams_invisible' in StartRead if continuation.
+
+ Rev 1.74.1.5 24 Nov 1993 15:20:48 BARRY
+Clear up warnings for Unicode.
+
+ Rev 1.74.1.4 11 Nov 1993 15:42:26 GREGG
+Initialize the 'make_streams_invisible' environment flag in StartRead.
+
+ Rev 1.74.1.3 03 Nov 1993 11:45:20 GREGG
+Added string type conversion of tape name password if THDR type != SSET type.
+Translate file dblk attribs under DOS and OS2 to and from MTF.
+Modified F40_FindNextDBLK so all zeros won't pass as a valid DBLK, and
+changed call in F40_RdVOLB to look for any valid DBLK instead of only
+looking for a DIRB.
+
+ Rev 1.74.1.2 15 Sep 1993 14:15:10 GREGG
+Pass max of F40_LB_SIZE and sizeof DBLK to AllocChannelTmpBlks in case
+DBLK size is greater.
+
+ Rev 1.74.1.1 21 Aug 1993 03:37:54 GREGG
+Handle TF_NO_MORE_DATA return from MoveFileMarks in F40_MoveToVCB.
+
+ Rev 1.74.1.0 13 Aug 1993 00:13:32 GREGG
+Fixed free of same memory twice.
+
+ Rev 1.74 15 Jul 1993 19:31:08 GREGG
+Updated handling of ECC and future rev tapes, and set compressed_obj,
+vendor_id, and compressed, encrypted and future_rev bits in appropriate dblks.
+
+ Rev 1.73 04 Jul 1993 03:55:52 GREGG
+Added the function FindNextDBLK to get us past any streams or unknown DBLKs
+between the SSET and first VOLB, and between the first VOLB and the first
+DIRB. It is also used to skip between DBLKS in continuation tape processing.
+
+ Rev 1.72 25 Jun 1993 20:48:12 GREGG
+If EOS_AT_EOM in RdContTape, eat the SSET in the buffer.
+
+ Rev 1.71 21 Jun 1993 18:06:04 GREGG
+Ignore partial stream at EOM.
+
+ Rev 1.70 20 Jun 1993 16:16:38 GREGG
+Set compression algor in VCB to 0 since the field isn't in the SSET any more.
+
+ Rev 1.69 20 Jun 1993 16:08:32 GREGG
+Unicode fixes.
+
+ Rev 1.68 16 Jun 1993 19:57:58 GREGG
+Reset append flag in format environment whenever we get a new tape.
+
+ Rev 1.67 09 Jun 1993 04:27:46 GREGG
+Fixed handling of SSET only at BOT. Make partial VCB instead of ignoring it.
+
+ Rev 1.66 07 Jun 1993 23:58:36 GREGG
+Reset the buffer in RdContTape so we process ALL the continuation DBLKS.
+
+ Rev 1.65 04 Jun 1993 18:38:26 GREGG
+For OEM_MSOFT (ntbackup) - mark sets with encrypted or compressed data as
+image set so the UI wont try to restore the data. This is a kludge which
+will be fixed correctly when we have more time.
+
+ Rev 1.64 23 May 1993 19:15:52 GREGG
+Fix for EPR 294-0148 - Clear AT_MOS bit in MoveToVCB.
+
+ Rev 1.63 20 May 1993 08:53:36 GREGG
+Fix for EPR 357-0262 - Set the cur_drv pba_vcb in RdSSET.
+
+ Rev 1.62 17 May 1993 20:49:40 GREGG
+Added logic to deal with the fact that the app above tape format doesn't
+keep track of the lba of the vcb.
+
+ Rev 1.61 29 Apr 1993 22:26:50 GREGG
+Added StartRead to determine if we're about to read an 'old' set.
+
+ Rev 1.60 26 Apr 1993 11:45:40 GREGG
+Seventh in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Changed handling of EOM processing during non-OTC EOS processing.
+
+Matches CHANNEL.H 1.17, MAYN40RD.C 1.60, TFWRITE.C 1.63, MTF.H 1.5,
+ TFLUTILS.C 1.44, MTF10WDB.C 1.10, MTF10WT.C 1.9
+
+ Rev 1.59 26 Apr 1993 02:43:30 GREGG
+Sixth in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Redefined attribute bits to match the spec.
+ - Eliminated unused/undocumented bits.
+ - Added code to translate bits on tapes that were written wrong.
+
+Matches MAYN40RD.C 1.59, DBLKS.H 1.15, MAYN40.H 1.34, OTC40RD.C 1.26,
+ SYPL10RD.C 1.8, BACK_VCB.C 1.17, MAYN31RD.C 1.44, SYPL10.H 1.2
+
+ Rev 1.58 25 Apr 1993 20:12:32 GREGG
+Fifth in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Store the corrupt stream number in the CFIL tape struct and the CFDB.
+
+Matches: MTF10WDB.C 1.9, FSYS.H 1.33, FSYS_STR.H 1.47, MAKECFDB.C 1.2,
+ BACK_OBJ.C 1.36, MAYN40RD.C 1.58
+
+ Rev 1.57 25 Apr 1993 18:52:36 GREGG
+Fourth in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Parse the device name and volume name out of the FS supplied "volume
+ name", and write it to tape as separate fields.
+ - Generate the "volume name" the FS and UI expect out of the device
+ name and volume name on tape.
+ - Write all strings without NULL terminater, and translate them back
+ to NULL terminated strings on the read side.
+
+Matches: MTF10WDB.C 1.8, F40PROTO.H 1.26, OTC40WT.C 1.24, MAYN40.H 1.33,
+ MAYN40RD.C 1.57, OTC40RD.C 1.25
+
+ Rev 1.56 22 Apr 1993 03:31:28 GREGG
+Third in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Removed all references to the DBLK element 'string_storage_offset',
+ which no longer exists.
+ - Check for incompatable versions of the Tape Format and OTC and deals
+ with them the best it can, or reports tape as foreign if they're too
+ far out. Includes ignoring the OTC and not allowing append if the
+ OTC on tape is a future rev, different type, or on an alternate
+ partition.
+ - Updated OTC "location" attribute bits, and changed definition of
+ CFIL to store stream number instead of stream ID.
+
+Matches: TFL_ERR.H 1.9, MTF10WDB.C 1.7, TRANSLAT.C 1.39, FMTINF.H 1.11,
+ OTC40RD.C 1.24, MAYN40RD.C 1.56, MTF10WT.C 1.7, OTC40MSC.C 1.20
+ DETFMT.C 1.13, MTF.H 1.4
+
+ Rev 1.55 19 Apr 1993 17:59:34 GREGG
+Second in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ Changes to write version 2 of OTC, and to read both versions.
+
+Matches: mayn40rd.c 1.55, otc40msc.c 1.19, otc40rd.c 1.23, otc40wt.c 1.23,
+ makevcb.c 1.15, fsys.h 1.32, fsys_str.h 1.46, tpos.h 1.16,
+ mayn40.h 1.32, mtf.h 1.3.
+
+NOTE: There are additional changes to the catalogs needed to save the OTC
+ version and put it in the tpos structure before loading the OTC
+ File/Directory Detail. These changes are NOT listed above!
+
+ Rev 1.54 18 Apr 1993 17:21:12 GREGG
+Treat additional VOLBs in set as UDBs.
+
+ Rev 1.53 18 Apr 1993 00:41:06 GREGG
+First in a series of incremental changes to bring the translator in line
+with the MTF spec:
+ - Pass UINT8_PTR instead of CHAR_PTR to F40_SaveLclName.
+
+Matches: MTF10WDB.C 1.6, MTF10WT.C 1.6, MAYN40.H 1.31 and F40PROTO.H 1.25
+
+ Rev 1.52 14 Apr 1993 02:00:08 GREGG
+Fixes to deal with non-ffr tapes in ffr drives (i.e. EXB2200 in EXB5000).
+
+ Rev 1.51 08 Apr 1993 22:21:44 ZEIR
+Cleaned-up reverse file mark positioning for non-ffr drives (2200HS)
+
+ Rev 1.50 07 Apr 1993 16:18:18 GREGG
+Changed boolean in environment to one not used on write side (they collided).
+
+
+Rev 1.49 31 Mar 1993 17:37:24 GREGG
+Fix for continuation stream header not being 4 byte alligned.
+
+ Rev 1.48 24 Mar 1993 10:23:16 ChuckS
+Added code to handle device_name added to F40_ENV with 1.28+ of mayn40.h.
+
+ Rev 1.47 17 Mar 1993 14:47:46 GREGG
+This is Terri Lynn. Added Gregg's changes for switching a tape drive's
+block mode to match the block size of the current tape.
+
+
+ Rev 1.46 13 Mar 1993 17:39:40 GREGG
+Fixed F40_RdVarStream.
+
+ Rev 1.45 11 Mar 1993 17:28:42 GREGG
+Fixed RdMDB.
+
+ Rev 1.44 11 Mar 1993 08:17:24 STEVEN
+fix write protect detection
+
+ Rev 1.43 09 Mar 1993 18:15:12 GREGG
+Initial changes for new stream and EOM processing.
+
+ Rev 1.42 24 Feb 1993 18:06:06 GREGG
+Changed return on no_data read in NewTape from TFLE_UNKNOWN_FMT to TF_INVALID_VCB.
+
+ Rev 1.41 05 Feb 1993 12:51:36 GREGG
+Fixed incorrect parameter being sent to SaveLclName for the tape password.
+Removed tons of tabs!!!
+
+ Rev 1.40 01 Feb 1993 17:50:18 chrish
+Change in F40_NewTape routine to correct tape security password problem for NT.
+
+ Rev 1.39 30 Jan 1993 11:43:54 DON
+Removed compiler warnings
+
+ Rev 1.38 28 Jan 1993 11:37:08 GREGG
+Changed error returned when the tape header is the only thing on the tape.
+
+ Rev 1.37 18 Jan 1993 16:52:14 BobR
+Added MOVE_ESA macro calls
+
+ Rev 1.36 21 Dec 1992 12:24:50 DAVEV
+Enabled for Unicode - IT WORKS!!
+
+ Rev 1.35 18 Dec 1992 17:08:14 HUNTER
+Fixes for Variable streams.
+
+ Rev 1.34 14 Dec 1992 12:26:14 DAVEV
+Enabled for Unicode compile
+
+ Rev 1.33 11 Dec 1992 16:56:38 GREGG
+Fix to align stream headers on four byte boundaries.
+
+ Rev 1.32 07 Dec 1992 10:06:58 GREGG
+Changes for tf ver moved to SSET, otc ver added to SSET and links added to FDD.
+
+ Rev 1.31 02 Dec 1992 13:45:24 GREGG
+Unicode fixes - some CHAR_PTRs now UINT8_PTRs.
+
+ Rev 1.30 24 Nov 1992 18:15:56 GREGG
+Updates to match MTF document.
+
+ Rev 1.29 23 Nov 1992 10:03:40 GREGG
+Changes for path in stream.
+
+ Rev 1.28 18 Nov 1992 11:01:24 GREGG
+changed manner in which stream ID is referenced since it is now a UINT32.
+
+ Rev 1.27 12 Nov 1992 16:42:34 HUNTER
+Added code for frag stuff
+
+ Rev 1.26 09 Nov 1992 11:00:46 GREGG
+Merged in changes for new method of accessing OTC.
+
+ Rev 1.25 04 Nov 1992 13:05:20 HUNTER
+Fix for read.
+
+ Rev 1.24 03 Nov 1992 09:29:50 HUNTER
+various fixes for stream stuff
+
+ Rev 1.23 22 Oct 1992 10:40:34 HUNTER
+Major revision for New data Stream handling
+
+ Rev 1.22 25 Sep 1992 09:26:52 GREGG
+Added F40_RdEOSPadBlk.
+
+ Rev 1.21 22 Sep 1992 08:58:02 GREGG
+Initial changes to handle physical block sizes greater than 1K.
+
+ Rev 1.20 17 Aug 1992 08:37:54 GREGG
+Changes to deal with block sizeing scheme.
+
+ Rev 1.19 12 Aug 1992 18:29:38 GREGG
+Added logic to use OTC when scanning before calling MoveToVCB.
+
+ Rev 1.18 06 Aug 1992 12:07:54 BURT
+Changes to support VBLKs, specifically with 1K logical
+block size.
+
+
+ Rev 1.17 04 Aug 1992 16:23:16 GREGG
+Burt's fixes for variable length streams.
+
+ Rev 1.16 30 Jul 1992 13:24:06 GREGG
+Changes to StartRead for EOM handling.
+
+ Rev 1.15 27 Jul 1992 12:39:46 GREGG
+Fixed more warnings...
+
+ Rev 1.14 24 Jul 1992 16:20:30 GREGG
+Removed warnings.
+
+ Rev 1.13 15 Jul 1992 12:28:42 GREGG
+Don't kill OTC files when write oper calls read translator in EOM processing.
+
+ Rev 1.12 01 Jul 1992 19:31:44 GREGG
+Converted to new date/time structure for dates written to tape.
+
+ Rev 1.11 09 Jun 1992 16:00:38 GREGG
+Changes to use F40_CalcChecksum instead of CalcChecksum.
+Removed merging of attributes.
+Set a boolean for continuation blocks.
+Removed setting of filemark_count.
+
+ Rev 1.10 02 Jun 1992 21:42:44 GREGG
+Handle switching to and from OTC based on operation type.
+
+ Rev 1.9 01 Jun 1992 17:10:32 GREGG
+Set disp_size in gen_data structure.
+
+ Rev 1.8 29 May 1992 15:09:02 GREGG
+Added setting of last access date, and misc. bug fixes.
+
+ Rev 1.7 20 May 1992 19:27:38 GREGG
+Added Steve's changes for 64 bit file system to the tip.
+
+ Rev 1.6 20 May 1992 19:16:22 GREGG
+Changes to support OTC read.
+
+ Rev 1.5 05 May 1992 11:26:50 GREGG
+Folded 'local_tape' global into environment, and fixed bugs in EOM handling.
+
+ Rev 1.4 28 Apr 1992 16:13:22 GREGG
+ROLLER BLADES - Changes to conform to new 4.0 EOM handling specifications.
+
+ Rev 1.3 17 Apr 1992 15:59:50 BURT
+Translated error return from Call to RdVOLB to FALSE. This is what
+the upper levels expect. This will cause and error to be reported
+instead of a perpetual request for inserting tape 'n'.
+
+
+ Rev 1.2 16 Apr 1992 17:39:14 BURT
+Integrated my EOM processing changes with Gregg's OTC code.
+Changed structure of code to be closer to coding standards.
+
+
+ Rev 1.1 05 Apr 1992 17:18:26 GREGG
+ROLLER BLADES - Initial OTC integration.
+
+ Rev 1.0 25 Mar 1992 20:26:54 GREGG
+Initial revision.
+
+**/
+#include <string.h>
+#include <malloc.h>
+#include <stdio.h>
+
+#include "stdtypes.h"
+#include "tbe_defs.h"
+#include "datetime.h"
+#include "drive.h"
+#include "channel.h"
+#include "mayn40.h"
+#include "f40proto.h"
+#include "transutl.h"
+#include "fsys.h"
+#include "tloc.h"
+#include "lwprotos.h"
+#include "tfldefs.h"
+#include "translat.h"
+#include "tfl_err.h"
+#include "sx.h"
+#include "lw_data.h"
+#include "minmax.h"
+
+/* Device Driver InterFace Headers */
+#include "retbuf.h"
+#include "dilhwd.h"
+#include "drvinf.h"
+#include "generr.h"
+#include "genstat.h"
+#include "dddefs.h"
+#include "dil.h"
+
+
+/* Internal Function Prototypes */
+
+static VOID _near SetStandFields( CHANNEL_PTR, STD_DBLK_DATA_PTR,
+ MTF_DB_HDR_PTR, BUF_PTR ) ;
+
+static INT16 F40_RdEOSPadBlk( CHANNEL_PTR, BUF_PTR ) ;
+static INT16 F40_RdVarStream( CHANNEL_PTR, BUF_PTR ) ;
+static VOID F40_FindNextDBLK( BUF_PTR, UINT16, UINT8_PTR ) ;
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_CopyAndTerminate
+
+ Description: This function copys size bytes from src to dest, adds
+ a NULL terminator at the end, and sets the dest pointer
+ past the end of the terminated string.
+
+ Returns: New string size
+
+ Notes: This is a VERY specialized function for translating
+ strings on tape to strings the UI can understand.
+
+**/
+UINT16 F40_CopyAndTerminate(
+ UINT8_PTR *dest,
+ UINT8_PTR src,
+ UINT16 size,
+ UINT8 src_str_type,
+ UINT8 dest_str_type )
+{
+ INT new_size ;
+
+ if( src_str_type == dest_str_type ) {
+ memcpy( *dest, src, size ) ;
+ *dest += size ;
+ if( src_str_type == BEC_UNIC_STR ) {
+ *((WCHAR UNALIGNED *)(*dest)) = L'\0' ;
+ (*dest) += sizeof( WCHAR ) ;
+ new_size = size + sizeof( WCHAR ) ;
+ } else {
+ *((ACHAR_PTR)(*dest)) = '\0' ;
+ (*dest)++ ;
+ new_size = size + 1 ;
+ }
+ } else if( src_str_type == BEC_UNIC_STR ) {
+ new_size = size / sizeof( WCHAR ) ;
+ mapUnicToAnsiNoNull( (WCHAR_PTR)src, (ACHAR_PTR)(*dest), '_',
+ size, &new_size ) ;
+ *dest += new_size ;
+ *((ACHAR_PTR)(*dest)) = '\0' ;
+ (*dest)++ ;
+ new_size++ ;
+ } else {
+ new_size = size * sizeof( WCHAR ) ;
+ mapAnsiToUnicNoNull( (ACHAR_PTR)src, (WCHAR_PTR)(*dest),
+ size, &new_size ) ;
+ *dest += new_size ;
+ *((WCHAR UNALIGNED *)(*dest)) = L'\0' ;
+ (*dest) += sizeof( WCHAR ) ;
+ new_size += sizeof( WCHAR ) ;
+ }
+ return( new_size ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_StartRead
+
+ Description: This is our hook before a read operation starts.
+ At this point, all we need it for is to determine
+ what version of OTC we have, and set up an indicator
+ as to whether this is an "old" MTF tape.
+
+ Returns: TFLE_NO_ERR (we don't do a whole lot!)
+
+ Notes: If the OTC version number is 0, it means the VCB was
+ not cataloged at the start of the operation, so we also
+ set this in RdSSET and WtSSET. If this doesn't cover
+ all the bases, we're #@$%ed.
+
+**/
+INT16 F40_StartRead( CHANNEL_PTR channel )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+
+ if( !( IsChannelStatus( channel, CH_CONTINUING ) ) ) {
+ cur_env->make_streams_invisible = FALSE ;
+ }
+
+ if( channel->ui_tpos->tape_cat_ver != 0 ) {
+ if( channel->ui_tpos->tape_cat_ver == 1 ) {
+ cur_env->old_tape = TRUE ;
+ } else {
+ cur_env->old_tape = FALSE ;
+ }
+ }
+
+ return( TFLE_NO_ERR ) ;
+}
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_Initialize
+
+
+ Description: This routine is used to allocate and initialize
+ the format 4.0 environment structure.
+
+ Returns: TRUE if allocated & init'd OK
+
+ Notes:
+
+**/
+INT16 F40_Initialize(
+ CHANNEL_PTR channel )
+{
+ F40_ENV_PTR env_ptr ;
+ BUF_REQ new_reqs ;
+ BUF_REQ_PTR bufreq_ptr ;
+ INT16 ret_val = TFLE_NO_ERR ;
+
+ if( channel->fmt_env == NULL ) {
+
+ if( !IsChannelStatus( channel, CH_CONTINUING ) ) {
+ /* Allocate the temporary DBLK storage area in the channel */
+ if( ( ret_val = AllocChannelTmpBlks( channel, (UINT)( MAX( F40_LB_SIZE, sizeof( DBLK ) ) ) ) ) != TFLE_NO_ERR ) {
+ return( ret_val ) ;
+ }
+ }
+
+ if( ( env_ptr = calloc( 1, sizeof( F40_ENV ) ) ) == NULL ) {
+ return( TFLE_NO_MEMORY ) ;
+ }
+
+ memset( env_ptr, 0, sizeof( F40_ENV ) ) ;
+ if( ( env_ptr->util_buff = calloc( F40_INIT_UTIL_BUFF_SIZE, 1 ) ) == NULL ) {
+ free( env_ptr ) ;
+ return( TFLE_NO_MEMORY ) ;
+ }
+ env_ptr->util_buff_size = F40_INIT_UTIL_BUFF_SIZE ;
+
+ if( ( env_ptr->dir_links =
+ calloc( F40_INIT_DIR_LINKS_SIZE, sizeof( long ) ) ) == NULL ) {
+
+ free( env_ptr->util_buff ) ;
+ free( env_ptr ) ;
+ return( TFLE_NO_MEMORY ) ;
+ }
+ env_ptr->dir_links_size = F40_INIT_DIR_LINKS_SIZE ;
+
+ channel->fmt_env = env_ptr ;
+ channel->lb_size = F40_LB_SIZE ;
+
+ env_ptr->unaligned_stream = FALSE ;
+ }
+
+ /* if we're in write mode, we've got to add dblkmap storage */
+
+ if( channel->mode == TF_WRITE_CONTINUE &&
+ !IsChannelStatus( channel, CH_CONTINUING ) ) {
+
+ bufreq_ptr = BM_ListRequirements( &channel->buffer_list ) ;
+ BM_ClearRequirements( &new_reqs ) ;
+ new_reqs.b.min_size = F40_DEFAULT_AUX_BUFFER_SIZE ;
+ new_reqs.b.incr_size = F40_AUX_BUFFER_INCR_SIZE ;
+
+ if( BM_AddRequirements( bufreq_ptr, &new_reqs ) != BR_NO_ERR ) {
+ msassert( FALSE ) ;
+ return( TFLE_PROGRAMMER_ERROR1 ) ;
+ }
+
+ ret_val = BM_ReSizeList( &channel->buffer_list ) ;
+ }
+
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_DeInitialize
+
+ Description: Returns environment memory
+
+ Returns: Nothing.
+
+ Notes:
+
+**/
+VOID F40_DeInitialize(
+ VOID_PTR *fmt_env )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( *fmt_env ) ;
+
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ if( cur_env->tape_name != NULL ) {
+ free( cur_env->tape_name ) ;
+ }
+ if( cur_env->tape_password != NULL ) {
+ free( cur_env->tape_password ) ;
+ }
+ if( cur_env->vol_name != NULL ) {
+ free( cur_env->vol_name ) ;
+ }
+ if( cur_env->machine_name != NULL ) {
+ free( cur_env->machine_name ) ;
+ }
+ if ( cur_env->device_name != NULL ) {
+ free( cur_env->device_name ) ;
+ }
+ if( cur_env->util_buff != NULL ) {
+ free( cur_env->util_buff ) ;
+ }
+ if( cur_env->otc_buff != NULL ) {
+ free( cur_env->otc_buff ) ;
+ }
+ if( cur_env->dir_links != NULL ) {
+ free( cur_env->dir_links ) ;
+ }
+ free( *fmt_env ) ;
+ *fmt_env = NULL ;
+}
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_GetBlkType
+
+ Description: Returns a UINT16 value that represents the
+ 4 character block type in the passed dblk header.
+
+ Returns: The Block type number.
+
+ Notes: We don't expect to see a VOLB at this point, because we
+ only write one per set, and we handle it transparently.
+ So if we see one here someone else wrote this tape, and
+ we're just going to treat it as a UDB.
+
+**/
+UINT16 F40_GetBlkType( MTF_DB_HDR_PTR cur_hdr )
+{
+ INT i ;
+
+ static UINT8 *blk_type[] = { MTF_TAPE_N, MTF_SSET_N, MTF_DIRB_N,
+ MTF_FILE_N, MTF_ESET_N, MTF_EOTM_N,
+ F40_IMAG_N, MTF_CFIL_N, MTF_ESPB_N,
+ F40_DBDB_N, NULL } ;
+
+ static UINT16 blk_id[] = { F40_TAPE_IDI, F40_SSET_IDI, F40_DIRB_IDI,
+ F40_FILE_IDI, F40_ESET_IDI, F40_EOTM_IDI,
+ F40_IMAG_IDI, F40_CFIL_IDI, F40_ESPB_IDI,
+ F40_DBDB_IDI, 0 } ;
+
+ i = 0 ;
+ while( blk_type[i] != NULL ) {
+ if( memcmp( blk_type[i], cur_hdr->block_type, 4 ) == 0 ) {
+ return( blk_id[i] ) ;
+ }
+ ++i ;
+ }
+
+ /* F40_ types are equal to BT defines */
+ return( BT_UDB ) ;
+}
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_DetBlkType
+
+ Description: Determines the type of Descriptor Block for the given
+ buffer.
+
+ Returns: TFLE_xxx error code.
+
+ Notes: This routine assumes the buffer is at least
+ min_siz_for_dblk bytes long.
+**/
+INT16 F40_DetBlkType(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer,
+ UINT16_PTR blk_type )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ MTF_DB_HDR_PTR cur_hdr ;
+ MTF_DB_HDR temp ;
+ MTF_STREAM_PTR currentStream ;
+ INT16 ret_val = TFLE_NO_ERR ;
+
+ if( !cur_env->unaligned_stream ) {
+ BM_UpdCnts( buffer, (UINT16)PadToBoundary( BM_NextByteOffset( buffer ), 4 ) ) ;
+ cur_hdr = (MTF_DB_HDR_PTR)( BM_NextBytePtr( buffer ) ) ;
+ } else {
+ memcpy( (UINT8_PTR)&temp, (UINT8_PTR)BM_NextBytePtr( buffer ),
+ sizeof( MTF_DB_HDR ) ) ;
+ cur_hdr = &temp ;
+ cur_env->unaligned_stream = FALSE ;
+ }
+ currentStream = ( MTF_STREAM_PTR ) cur_hdr ;
+
+ if( BM_BytesFree( buffer ) < sizeof( MTF_STREAM ) ) {
+
+ cur_env->frag_cnt = BM_BytesFree( buffer ) ;
+ memcpy( &cur_env->frag[0], BM_NextBytePtr( buffer ), cur_env->frag_cnt ) ;
+ BM_UpdCnts( buffer, cur_env->frag_cnt ) ;
+ *blk_type = BT_MDB ;
+ return( TFLE_NO_ERR ) ;
+
+ } else if ( cur_env->frag_cnt ) {
+
+ memcpy( &cur_env->frag[cur_env->frag_cnt], BM_NextBytePtr( buffer ),
+ ( sizeof( MTF_STREAM ) - cur_env->frag_cnt ) ) ;
+ if( cur_env->make_streams_invisible ) {
+ *blk_type = BT_MDB ;
+ } else {
+ *blk_type = BT_STREAM ;
+ }
+ BM_UpdCnts( buffer, ( UINT16 ) ( sizeof( MTF_STREAM ) - cur_env->frag_cnt ) ) ;
+ return( TFLE_NO_ERR ) ;
+
+ } else if( ( *blk_type = F40_GetBlkType( cur_hdr ) ) == BT_VCB &&
+ !( cur_hdr->block_attribs & MTF_DB_CONT_BIT ) &&
+ BM_BytesFree( buffer ) == channel->lb_size ) {
+
+ /* This is the big lie! All we managed to fit on this tape was
+ the SSET, so were going to pretend it's not here (nobody said
+ software development was pretty!).
+ */
+ *blk_type = BT_CVCB ;
+ }
+
+
+ /* Verify checksums */
+ if( *blk_type == BT_UDB &&
+ ( F40_CalcChecksum( ( UINT16_PTR ) currentStream, F40_STREAM_CHKSUM_LEN ) == currentStream->chksum ) ) {
+
+ if( cur_env->make_streams_invisible ) {
+ *blk_type = BT_MDB ;
+ } else {
+ *blk_type = BT_STREAM ;
+ }
+
+ } else if( F40_CalcChecksum( (UINT16_PTR)cur_hdr, F40_HDR_CHKSUM_LEN ) != cur_hdr->hdr_chksm ) {
+ *blk_type = BT_HOSED ;
+ ret_val = TFLE_TRANSLATION_FAILURE ;
+ }
+
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_SizeofTBLK
+
+ Description: returns the size of a tape block.
+
+ Returns: the size in bytes
+
+ Notes: IT IS ASSUMED THAT THE BUFFER PASSED TO THIS FUNCTION
+ CONTAINS A VALID 4.0 FORMAT TAPE BLOCK.
+
+**/
+UINT16 F40_SizeofTBLK(
+ VOID_PTR buffer )
+{
+ (void)buffer ;
+ return( F40_LB_SIZE ) ;
+}
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_NewTape
+
+ Description: Get us past the tape header, extracting any necessary
+ information.
+
+ Returns: TFLE_xxx error code.
+
+ Notes:
+
+**/
+INT16 F40_NewTape(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer,
+ BOOLEAN_PTR need_read )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ MTF_TAPE_PTR cur_tape ;
+ UINT8_PTR vstr_ptr ;
+ BOOLEAN ret_val = TFLE_NO_ERR ;
+ BOOLEAN write_mode = FALSE ;
+ BOOLEAN resized_buff ;
+ RET_BUF myret ;
+
+ /* Always start with the assumption you can append to the tape */
+ lw_fmtdescr[channel->cur_fmt].attributes |= APPEND_SUPPORTED ;
+
+ if( ( ( channel->mode & ~0x8000 ) == TF_WRITE_OPERATION ) ||
+ ( ( channel->mode & ~0x8000 ) == TF_WRITE_APPEND ) ) {
+ write_mode = TRUE ;
+ }
+
+ /* Preserve the needed information from this tape header. */
+ cur_tape = (MTF_TAPE_PTR)( BM_NextBytePtr( buffer ) ) ;
+ vstr_ptr = (UINT8_PTR)( cur_tape ) ;
+
+ /* If this is a future rev tape, we don't want to try to process it! */
+ if( cur_tape->tf_major_ver != FORMAT_VER_MAJOR ) {
+ return( TF_FUTURE_REV_MTF ) ;
+ }
+
+ /* If tape has software ECC, we don't want to try to process it! */
+ if( cur_tape->ecc_algorithm != ECC_NONE ) {
+ return( TF_MTF_ECC_TAPE ) ;
+ }
+
+ /* If continuing, make sure this is the continuation tape */
+ if( !write_mode && IsChannelStatus( channel, CH_CONTINUING ) ) {
+ if( cur_tape->tape_id_number != (UINT32)channel->ui_tpos->tape_id ||
+ cur_tape->tape_seq_number != (UINT16)channel->ui_tpos->tape_seq_num ) {
+ return( TF_WRONG_TAPE ) ;
+ }
+ }
+
+ /* Set the logical block size in the channel */
+ channel->lb_size = cur_tape->logical_block_size ;
+
+ cur_env->tape_hdr = *cur_tape ;
+
+ if( cur_tape->block_header.block_attribs & MTF_DB_SM_EXISTS ) {
+ if( cur_tape->block_header.block_attribs & MTF_DB_FDD_ALLOWED ) {
+ cur_env->max_otc_level = TCL_FULL ;
+ } else {
+ cur_env->max_otc_level = TCL_PARTIAL ;
+ }
+ } else {
+ cur_env->max_otc_level = TCL_NONE ;
+ }
+
+ /* Don't allow append if the logical block size doesn't match what we
+ write.
+ */
+ if( channel->lb_size != F40_LB_SIZE ) {
+ lw_fmtdescr[channel->cur_fmt].attributes &= ~APPEND_SUPPORTED ;
+ }
+
+ /* Make sure we can use the catalogs */
+ if( cur_tape->block_header.block_attribs & MTF_DB_FDD_ALT_PART ) {
+ cur_env->max_otc_level = TCL_PARTIAL ;
+ }
+ if( ( cur_tape->block_header.block_attribs & MTF_DB_SM_ALT_OVERWRITE ) ||
+ ( cur_tape->block_header.block_attribs & MTF_DB_SM_ALT_APPEND ) ) {
+
+ lw_fmtdescr[channel->cur_fmt].attributes &= ~APPEND_SUPPORTED ;
+ cur_env->max_otc_level = TCL_NONE ;
+ }
+ if( cur_tape->tape_catalog_type != MTF10_OTC ) {
+ lw_fmtdescr[channel->cur_fmt].attributes &= ~APPEND_SUPPORTED ;
+ cur_env->max_otc_level = TCL_NONE ;
+ }
+ if( !SupportBlkPos( channel->cur_drv ) ||
+ !SupportFastEOD( channel->cur_drv ) ||
+ !SupportRevFmk( channel->cur_drv ) ) {
+
+ cur_env->max_otc_level = TCL_NONE ;
+ }
+
+ /* This sick little conditional checks to see if the tape name is NULL
+ terminated (which is only true on "old" tapes). If it's there, we
+ pretend it isn't. Note that there are no "old" UNICODE tapes.
+ */
+ if( cur_tape->block_header.string_type == BEC_ANSI_STR &&
+ cur_tape->tape_name.data_size != 0 &&
+ *( vstr_ptr + cur_tape->tape_name.data_offset +
+ cur_tape->tape_name.data_size - 1 ) == 0 ) {
+
+ cur_env->tape_hdr.tape_name.data_size-- ;
+ }
+
+ if( ( ret_val = F40_SaveLclName( &cur_env->tape_name,
+ (UINT8_PTR)( vstr_ptr + cur_tape->tape_name.data_offset ),
+ &cur_env->tape_name_size,
+ &cur_env->tape_name_alloc,
+ cur_env->tape_hdr.tape_name.data_size ) ) != TFLE_NO_ERR ) {
+
+ return( ret_val ) ;
+ }
+ if( ( ret_val = F40_SaveLclName( &cur_env->tape_password,
+ (UINT8_PTR)( vstr_ptr + cur_tape->tape_password.data_offset ),
+ &cur_env->tape_password_size,
+ &cur_env->tape_password_alloc,
+ cur_tape->tape_password.data_size ) ) != TFLE_NO_ERR ) {
+
+ return( ret_val ) ;
+ }
+
+ /* We need to make sure that we have eaten the File mark */
+
+ if( buffer->read_error != GEN_ERR_ENDSET ) {
+
+ DRIVER_CALL( channel->cur_drv->drv_hdl,
+ TpReadEndSet( channel->cur_drv->drv_hdl, (INT16)1, (INT16)FORWARD ),
+ myret, GEN_NO_ERR, GEN_NO_ERR, (VOID)0 )
+ }
+
+ channel->cur_drv->cur_pos.fmks = 1 ; /* always 1 ! */
+
+ /* NOTE:
+
+ The code below (in the "if 0") used to pretend that an SSET by
+ itself was not there. This turned out to be a bad idea since we
+ could overwrite the tape thinking it was blank! We still call
+ ReadABuff to catch the odd tape with a tape header only and report
+ is as foreign, but then we treat the lone SSET like any other short
+ set. F40_RdSSET will fake out that there is no Volume, Device or
+ Machine Name when generating the VCB, and thats all we care about
+ in the VOLB anyway.
+ */
+
+#if 0
+
+ /* Here we make the call to ReadABuff ourselves so we can catch some
+ edge conditions in EOM processing where all we write is an SSET
+ before the filemark on the continuation tape. If this is the case,
+ and we're not continuing, we're going to pretend this set isn't here
+ at all.
+ */
+ if( ( ret_val = ReadABuff( channel, FALSE, &resized_buff ) ) != TFLE_NO_ERR ) {
+ if( ret_val == TF_NO_MORE_DATA ) {
+ ret_val = TF_INVALID_VCB ;
+ }
+ return( ret_val ) ;
+ }
+ if( BM_BytesFree( buffer ) <= channel->lb_size &&
+ !IsChannelStatus( channel, CH_CONTINUING ) ) {
+
+ if( F40_RdException( channel, BM_ReadError( buffer ) ) != FMT_EXC_EOS ) {
+ return( TFLE_TAPE_INCONSISTENCY ) ;
+ }
+ *need_read = TRUE ;
+ } else {
+ *need_read = FALSE ;
+ }
+
+#endif
+
+ /* Here we make the call to ReadABuff ourselves so we can catch tapes
+ with only a tape header on them and report them as foreign.
+ */
+ if( ( ret_val = ReadABuff( channel, FALSE, &resized_buff ) ) != TFLE_NO_ERR ) {
+ if( ret_val == TF_NO_MORE_DATA ) {
+ ret_val = TF_INVALID_VCB ;
+ }
+ return( ret_val ) ;
+ }
+
+ *need_read = FALSE ;
+
+ return( TFLE_NO_ERR ) ;
+}
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_RdVOLB
+
+ Description: Format 4.0 VOLB translator.
+
+ Returns: TFLE_xxx error code.
+
+ Notes:
+
+**/
+INT16 F40_RdVOLB(
+ BUF_PTR buffer,
+ VOID_PTR env_ptr,
+ BOOLEAN_PTR cont_volb,
+ UINT8_PTR str_type )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)env_ptr ;
+ MTF_VOL_PTR cur_volb ;
+ UINT8_PTR vstr_ptr ;
+ INT16 ret_val ;
+
+ cur_volb = (MTF_VOL_PTR)( BM_NextBytePtr( buffer ) ) ;
+ vstr_ptr = (UINT8_PTR)( BM_NextBytePtr( buffer ) ) ;
+ *cont_volb = (BOOLEAN)( cur_volb->block_hdr.block_attribs & MTF_DB_CONT_BIT ) ;
+ *str_type = cur_volb->block_hdr.string_type ;
+
+ if( ( ret_val = F40_SaveLclName( &cur_env->vol_name,
+ (UINT8_PTR)( vstr_ptr +
+ cur_volb->volume_name.data_offset ),
+ &cur_env->vol_name_size,
+ &cur_env->vol_name_alloc,
+ cur_volb->volume_name.data_size ) )
+ == TFLE_NO_ERR ) {
+
+ if( ( ret_val = F40_SaveLclName( &cur_env->machine_name,
+ (UINT8_PTR)( vstr_ptr +
+ cur_volb->machine_name.data_offset ),
+ &cur_env->machine_name_size,
+ &cur_env->machine_name_alloc,
+ cur_volb->machine_name.data_size ) )
+ == TFLE_NO_ERR ) {
+
+ ret_val = F40_SaveLclName( &cur_env->device_name,
+ (UINT8_PTR)( vstr_ptr +
+ cur_volb->device_name.data_offset ),
+ &cur_env->device_name_size,
+ &cur_env->device_name_alloc,
+ cur_volb->device_name.data_size ) ;
+ }
+ }
+
+ if( ret_val == TFLE_NO_ERR ) {
+ F40_FindNextDBLK( buffer, cur_env->tape_hdr.logical_block_size, NULL ) ;
+ }
+
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_RdSSET
+
+ Description: Format 4.0 SSET translator.
+
+ Returns: TFLE_xxx error code
+
+ Notes:
+
+**/
+INT16 F40_RdSSET(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ DBLK_PTR cur_dblk = channel->cur_dblk ;
+ MTF_SSET_PTR cur_sset ;
+ FSYS_HAND cur_fsys = channel->cur_fsys ;
+ GEN_VCB_DATA gvcb_data ;
+ UINT16 tmp_filter ;
+ UINT8_PTR vstr_ptr ;
+ UINT8_PTR buff_ptr ;
+ UINT8 str_type ;
+ BOOLEAN cont_volb ;
+ INT16 ret_val ;
+ DATE_TIME backup_date ;
+
+ cur_sset = (MTF_SSET_PTR)( BM_NextBytePtr( buffer ) ) ;
+ vstr_ptr = (UINT8_PTR)( cur_sset ) ;
+
+ /* Figure out the OTC level for the set. If the catalog version is
+ greater than the one we write, we won't be able to read the FDD,
+ but we'll still be able to read the set map.
+ */
+ if( cur_env->max_otc_level == TCL_FULL ) {
+ if( ( cur_sset->block_hdr.block_attribs & MTF_DB_FDD_EXISTS ) &&
+ ( cur_sset->tape_cat_ver <= TAPE_CATALOG_VER ) ) {
+
+ cur_env->cur_otc_level = TCL_FULL ;
+ } else {
+ cur_env->cur_otc_level = TCL_PARTIAL ;
+ }
+ } else {
+ cur_env->cur_otc_level = cur_env->max_otc_level ;
+ }
+
+ if( cur_env->tape_hdr.tape_catalog_type == MTF10_OTC &&
+ cur_sset->tape_cat_ver == 1 ) {
+
+ cur_env->old_tape = TRUE ;
+ } else {
+ cur_env->old_tape = FALSE ;
+ }
+
+ /* Initialize the file systems interface structure */
+ FS_SetDefaultDBLK( cur_fsys, BT_VCB, (CREATE_DBLK_PTR)&gvcb_data ) ;
+ gvcb_data.std_data.dblk = cur_dblk ;
+
+ /* Set the non-defaulted standard fields for the FS */
+ SetStandFields( channel, &gvcb_data.std_data, &cur_sset->block_hdr, buffer ) ;
+
+ /* Tape catalog information. The Set Map entry is the only place
+ where the first two fields are valid.
+ */
+ gvcb_data.set_cat_pba = 0L ;
+ gvcb_data.set_cat_tape_seq_num = 0 ;
+ gvcb_data.set_cat_info_valid = FALSE ;
+ gvcb_data.on_tape_cat_level = cur_env->cur_otc_level ;
+ gvcb_data.on_tape_cat_ver = cur_sset->tape_cat_ver ;
+
+ /* General VCB info */
+
+ gvcb_data.tape_id = cur_env->tape_hdr.tape_id_number ;
+ gvcb_data.tape_seq_num = cur_env->tape_hdr.tape_seq_number ;
+ gvcb_data.tf_major_ver = (CHAR)cur_env->tape_hdr.tf_major_ver ;
+ gvcb_data.tf_minor_ver = (CHAR)cur_sset->tf_minor_ver ;
+ gvcb_data.bset_num = cur_sset->backup_set_number ;
+ gvcb_data.sw_major_ver = (CHAR)cur_sset->software_ver_mjr ;
+ gvcb_data.sw_minor_ver = (CHAR)cur_sset->software_ver_mnr ;
+ gvcb_data.password_encrypt_alg = cur_sset->password_encryption_algor ;
+ gvcb_data.data_encrypt_alg = cur_sset->data_encryption_algor ;
+ gvcb_data.vendor_id = cur_sset->software_vendor_id ;
+
+ /* Set the VCB attributes. Note that if this is an "old" tape,
+ the attibute bits were being set wrong, and need to be translated.
+ */
+ if( cur_env->old_tape ) {
+ gvcb_data.std_data.attrib = 0 ;
+ gvcb_data.std_data.attrib |= ( cur_sset->sset_attribs & OLD_VCB_COPY_SET )
+ ? VCB_COPY_SET : 0 ;
+ gvcb_data.std_data.attrib |= ( cur_sset->sset_attribs & OLD_VCB_NORMAL_SET )
+ ? VCB_NORMAL_SET : 0 ;
+ gvcb_data.std_data.attrib |= ( cur_sset->sset_attribs & OLD_VCB_DIFFERENTIAL_SET )
+ ? VCB_DIFFERENTIAL_SET : 0 ;
+ gvcb_data.std_data.attrib |= ( cur_sset->sset_attribs & OLD_VCB_INCREMENTAL_SET )
+ ? VCB_INCREMENTAL_SET : 0 ;
+ gvcb_data.std_data.attrib |= ( cur_sset->sset_attribs & OLD_VCB_DAILY_SET )
+ ? VCB_DAILY_SET : 0 ;
+ gvcb_data.std_data.attrib |= ( cur_sset->sset_attribs & OLD_VCB_ARCHIVE_BIT )
+ ? VCB_ARCHIVE_BIT : 0 ;
+ } else {
+ gvcb_data.std_data.attrib = cur_sset->sset_attribs ;
+ }
+
+ /* Clear other vendor's vendor specific bits */
+ gvcb_data.std_data.attrib &= 0x00FFFFFF ;
+
+ /* Set our own vendor specific bits */
+ gvcb_data.std_data.attrib |= ( cur_sset->tf_minor_ver != FORMAT_VER_MINOR )
+ ? VCB_FUTURE_VER_BIT : 0 ;
+ gvcb_data.std_data.attrib |= ( cur_sset->block_hdr.block_attribs & MTF_DB_COMPRESS_BIT )
+ ? VCB_COMPRESSED_BIT : 0 ;
+ gvcb_data.std_data.attrib |= ( cur_sset->block_hdr.block_attribs & MTF_DB_ENCRYPT_BIT )
+ ? VCB_ENCRYPTED_BIT : 0 ;
+
+ /* The Variable Length Strings */
+
+ if( cur_env->util_buff == NULL ) {
+ if( ( cur_env->util_buff = calloc( F40_INIT_UTIL_BUFF_SIZE, 1 ) ) == NULL ) {
+ return( TFLE_NO_MEMORY ) ;
+ }
+ cur_env->util_buff_size = F40_INIT_UTIL_BUFF_SIZE ;
+ }
+
+ buff_ptr = cur_env->util_buff ;
+
+ gvcb_data.tape_password = (CHAR_PTR)cur_env->tape_password ;
+ gvcb_data.tape_password_size = cur_env->tape_password_size ;
+
+ gvcb_data.bset_password =
+ (CHAR_PTR)( (INT8_PTR)vstr_ptr + cur_sset->backup_set_password.data_offset ) ;
+ gvcb_data.bset_password_size = cur_sset->backup_set_password.data_size ;
+
+ /* Tape Name */
+ gvcb_data.tape_name = (CHAR_PTR)buff_ptr ;
+ if( cur_env->tape_name_size != 0 ) {
+ gvcb_data.tape_name_size =
+ F40_CopyAndTerminate( &buff_ptr, cur_env->tape_name,
+ cur_env->tape_name_size,
+ cur_env->tape_hdr.block_header.string_type,
+ cur_sset->block_hdr.string_type ) ;
+ } else {
+ gvcb_data.tape_name_size = 0 ;
+ }
+
+ /* If this is an "old" tape the strings below are NULL terminated.
+ If it's a "new" tape, we have to copy the string to another data
+ area and NULL terminate them before passing them to the UI.
+ Note that the tape name is NEVER NULL terminated because we have to
+ strip it off before we store it to maintain consistancy.
+ */
+ if( cur_env->old_tape ) {
+ /* This is an old tape with NULL terminated strings. */
+
+ gvcb_data.bset_name = (CHAR_PTR)( vstr_ptr + cur_sset->backup_set_name.data_offset ) ;
+ gvcb_data.bset_name_size = cur_sset->backup_set_name.data_size ;
+ gvcb_data.bset_descript = (CHAR_PTR)( vstr_ptr + cur_sset->backup_set_description.data_offset ) ;
+ gvcb_data.bset_descript_size = cur_sset->backup_set_description.data_size ;
+ gvcb_data.user_name = (CHAR_PTR)( vstr_ptr + cur_sset->user_name.data_offset ) ;
+ gvcb_data.user_name_size = cur_sset->user_name.data_size ;
+
+ } else {
+ /* This is a new tape, copy the strings into a buffer and NULL
+ terminate them.
+ */
+
+ /* Backup Set Name */
+ gvcb_data.bset_name = (CHAR_PTR)buff_ptr ;
+ if( cur_sset->backup_set_name.data_size != 0 ) {
+ gvcb_data.bset_name_size =
+ F40_CopyAndTerminate( &buff_ptr, vstr_ptr +
+ cur_sset->backup_set_name.data_offset,
+ cur_sset->backup_set_name.data_size,
+ cur_sset->block_hdr.string_type,
+ cur_sset->block_hdr.string_type ) ;
+ } else {
+ gvcb_data.bset_name_size = 0 ;
+ }
+
+ /* Backup Set Description */
+ gvcb_data.bset_descript = (CHAR_PTR)buff_ptr ;
+ if( cur_sset->backup_set_description.data_size != 0 ) {
+ gvcb_data.bset_descript_size =
+ F40_CopyAndTerminate( &buff_ptr, vstr_ptr +
+ cur_sset->backup_set_description.data_offset,
+ cur_sset->backup_set_description.data_size,
+ cur_sset->block_hdr.string_type,
+ cur_sset->block_hdr.string_type ) ;
+ } else {
+ gvcb_data.bset_descript_size = 0 ;
+ }
+
+ /* User Name */
+ gvcb_data.user_name = (CHAR_PTR)buff_ptr ;
+ if( cur_sset->user_name.data_size != 0 ) {
+ gvcb_data.user_name_size =
+ F40_CopyAndTerminate( &buff_ptr, vstr_ptr +
+ cur_sset->user_name.data_offset,
+ cur_sset->user_name.data_size,
+ cur_sset->block_hdr.string_type,
+ cur_sset->block_hdr.string_type ) ;
+ } else {
+ gvcb_data.user_name_size = 0 ;
+ }
+ }
+
+ TapeDateToDate( &backup_date, &cur_sset->backup_date ) ;
+ gvcb_data.date = &backup_date ;
+
+ /* Set up Position Info */
+ gvcb_data.pba = U64_Lsw( cur_sset->physical_block_address ) ;
+ channel->cur_drv->cur_pos.pba_vcb = U64_Lsw( cur_sset->physical_block_address ) ;
+
+ /* This is saved so we know whether or not the tape has position
+ info stored on it in case they do an append.
+ */
+ cur_env->last_sset_pba = U64_Lsw( cur_sset->physical_block_address ) ;
+
+ gvcb_data.short_m_name = (CHAR_PTR)buff_ptr ;
+ gvcb_data.short_m_name_size = 0 ;
+
+ BM_SetBytesFree( buffer, BM_BytesFree( buffer ) +
+ BM_NextByteOffset( buffer ) ) ;
+ BM_SetNextByteOffset( buffer, 0 ) ;
+ F40_FindNextDBLK( buffer, channel->lb_size, MTF_VOLB_N ) ;
+
+ /* If we only have an SSET we either have an EOM at EOS continuation,
+ or a short set generated by another application (since we write an
+ SSET and VOLB at the very least). So we'll fake out the volume
+ info in a way which the UI can deal with.
+ */
+ if( BM_BytesFree( buffer ) != 0 ) {
+
+ if( ( ret_val = F40_RdVOLB( buffer, channel->fmt_env, &cont_volb,
+ &str_type ) ) != TFLE_NO_ERR ) {
+ return( ret_val ) ;
+ }
+
+ if( !cont_volb ) {
+
+ /* At this point we have a continuation SSET but not a
+ continuation VOLB, so we're going to pretend that this
+ is a brand new set.
+ */
+
+ gvcb_data.std_data.continue_obj = FALSE ;
+ }
+
+ /* If this is an "old" tape the strings below are NULL terminated.
+ If it's a "new" tape, we have to copy the strings to another
+ data area and NULL terminate them before passing them to the UI.
+ */
+ if( cur_env->old_tape ) {
+ /* This is an old tape with NULL terminated strings. */
+
+ gvcb_data.volume_name = (CHAR_PTR)cur_env->vol_name ;
+ gvcb_data.volume_name_size = cur_env->vol_name_size ;
+ gvcb_data.machine_name = (CHAR_PTR)cur_env->machine_name ;
+ gvcb_data.machine_name_size = cur_env->machine_name_size ;
+ gvcb_data.device_name = (CHAR_PTR)cur_env->device_name ;
+ gvcb_data.dev_name_size = cur_env->device_name_size ;
+
+ } else {
+ /* This is a new tape, copy the strings into a buffer and
+ NULL terminate them.
+ */
+
+ /* Device Name */
+ gvcb_data.device_name = (CHAR_PTR)buff_ptr ;
+ if( cur_env->device_name_size != 0 ) {
+ gvcb_data.dev_name_size =
+ F40_CopyAndTerminate( &buff_ptr,
+ cur_env->device_name,
+ cur_env->device_name_size,
+ str_type, str_type ) ;
+ } else {
+ gvcb_data.dev_name_size = 0 ;
+ }
+
+ /* Volume Name */
+ gvcb_data.volume_name = (CHAR_PTR)buff_ptr ;
+ if( cur_env->vol_name_size != 0 ) {
+ gvcb_data.volume_name_size =
+ F40_CopyAndTerminate( &buff_ptr,
+ cur_env->vol_name,
+ cur_env->vol_name_size,
+ str_type, str_type ) ;
+ } else {
+ gvcb_data.volume_name_size = 0 ;
+ }
+
+ /* Machine Name */
+ gvcb_data.machine_name = (CHAR_PTR)buff_ptr ;
+ if( cur_env->machine_name_size != 0 ) {
+ gvcb_data.machine_name_size =
+ F40_CopyAndTerminate( &buff_ptr,
+ cur_env->machine_name,
+ cur_env->machine_name_size,
+ str_type, str_type ) ;
+ } else {
+ gvcb_data.machine_name_size = 0 ;
+ }
+
+ /* Other than in the NLM where they already fixed this, the
+ UI expects to see a volume name of the form
+ "<device name><space><volume name>", and NO DEVICE NAME.
+ We do this by pointing the volume name at the device name,
+ and replacing the NULL terminator on the device name with
+ a space.
+ */
+
+#if !defined( OS_NLM )
+
+ if( gvcb_data.dev_name_size != 0 ) {
+ gvcb_data.volume_name = gvcb_data.device_name ;
+ gvcb_data.volume_name_size += gvcb_data.dev_name_size ;
+ if( gvcb_data.volume_name_size != gvcb_data.dev_name_size ) {
+ vstr_ptr = (UINT8_PTR)gvcb_data.volume_name ;
+ if( str_type == BEC_ANSI_STR ) {
+ vstr_ptr += gvcb_data.dev_name_size - 1 ;
+ *((ACHAR *)vstr_ptr) = (ACHAR)' ' ;
+ } else {
+ vstr_ptr += gvcb_data.dev_name_size - 2 ;
+ *((WCHAR *)vstr_ptr) = (WCHAR)' ' ;
+ }
+ }
+ gvcb_data.dev_name_size = 0 ;
+ }
+
+#endif
+
+ }
+
+ if( gvcb_data.std_data.continue_obj ) {
+ /* Fix for the app not knowing the LBA for a continuation VCB */
+ channel->cross_set = cur_sset->backup_set_number ;
+ channel->cross_lba = U64_Lsw( cur_sset->block_hdr.logical_block_address ) ;
+ }
+
+ } else {
+ gvcb_data.device_name = TEXT( "" ) ;
+ gvcb_data.dev_name_size = sizeof( CHAR ) ;
+ gvcb_data.volume_name = TEXT( "" ) ;
+ gvcb_data.volume_name_size = sizeof( CHAR ) ;
+ gvcb_data.machine_name = TEXT( "" ) ;
+ gvcb_data.machine_name_size = sizeof( CHAR ) ;
+ }
+
+ /* Tell the file system to do its thing */
+ tmp_filter = FS_CreateGenVCB( cur_fsys, &gvcb_data ) ;
+
+ ProcessDataFilter( channel, tmp_filter ) ;
+
+ return( TFLE_NO_ERR ) ;
+}
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_RdDIRB
+
+ Description: Translates a tape format DIRB blk into a OS DBLK.
+
+ Returns: TFLE_xxx error code
+
+ Notes:
+
+**/
+INT16 F40_RdDIRB(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ DBLK_PTR cur_dblk = channel->cur_dblk ;
+ MTF_DIR_PTR cur_dirb = (MTF_DIR_PTR)( BM_NextBytePtr( buffer ) ) ;
+ F40_DBDB_PTR cur_dbdb = (F40_DBDB_PTR)( BM_NextBytePtr( buffer ) ) ;
+ FSYS_HAND cur_fsys = channel->cur_fsys ;
+ GEN_DDB_DATA gddb_data ;
+ UINT16 tmp_filter ;
+ UINT8_PTR vstr_ptr = (UINT8_PTR)cur_dirb ;
+ DATE_TIME dummy_date ;
+ DATE_TIME create_date ;
+ DATE_TIME last_mod_date ;
+ DATE_TIME backup_date ;
+ DATE_TIME last_access_date ;
+
+ /* Initialize the file systems interface structure */
+ FS_SetDefaultDBLK( cur_fsys, BT_DDB, (CREATE_DBLK_PTR)&gddb_data ) ;
+ gddb_data.std_data.dblk = cur_dblk ;
+
+ if( memcmp( F40_DBDB_N, BM_NextBytePtr( buffer ), 4 ) == 0 ) {
+ /* This is a Database DBLK, but the boys upstairs don't want to
+ know about such silly things! So we lie and call it a DDB to
+ get it passed on to the File System. The File System can tell
+ what it really is too, and will deal with it appropriatly.
+ */
+ /* Set the non-defaulted standard fields for the FS */
+ SetStandFields( channel, &gddb_data.std_data, &cur_dirb->block_hdr, buffer ) ;
+
+ gddb_data.std_data.attrib = cur_dbdb->database_attribs ;
+
+ /* Clear all vendor specific bits */
+ gddb_data.std_data.attrib &= 0x00FFFFFF ;
+
+ /* Set our vendor specific bit that says this is a DBDB */
+ gddb_data.std_data.attrib |= DIR_IS_REALLY_DB ;
+
+ gddb_data.path_name =
+ (CHAR_PTR)( (INT8_PTR)vstr_ptr + cur_dbdb->database_name.data_offset ) ;
+ gddb_data.path_size = (INT16)cur_dbdb->database_name.data_size ;
+
+ TapeDateToDate( &backup_date, &cur_dbdb->backup_date ) ;
+ gddb_data.backup_date = &backup_date ;
+
+ /* DBDBs don't have the following date fields */
+ memset( &dummy_date, 0, sizeof( dummy_date ) ) ;
+ gddb_data.creat_date = &dummy_date ;
+ gddb_data.mod_date = &dummy_date ;
+ gddb_data.access_date = &dummy_date ;
+
+ } else {
+
+ /* Standard DDB structure stuffing */
+
+ /* Set the non-defaulted standard fields for the FS */
+ SetStandFields( channel, &gddb_data.std_data, &cur_dirb->block_hdr, buffer ) ;
+
+ /* Set the DIR attributes. Note that if this is an "old" tape,
+ the attibute bits were being set wrong, and need to be translated.
+ */
+ if( cur_env->old_tape ) {
+
+ gddb_data.std_data.attrib = cur_dirb->directory_attribs &
+ ~( OLD_DIR_EMPTY_BIT | OLD_DIR_PATH_IN_STREAM_BIT ) ;
+
+ gddb_data.std_data.attrib |= ( cur_dirb->directory_attribs & OLD_DIR_EMPTY_BIT )
+ ? DIR_EMPTY_BIT : 0 ;
+ gddb_data.std_data.attrib |= ( cur_dirb->directory_attribs & OLD_DIR_PATH_IN_STREAM_BIT )
+ ? DIR_PATH_IN_STREAM_BIT : 0 ;
+ } else {
+ gddb_data.std_data.attrib = cur_dirb->directory_attribs ;
+ }
+
+ /* Clear all vendor specific bits */
+ gddb_data.std_data.attrib &= 0x00FFFFFF ;
+
+ /* Set the non-defaulted DDB specific fields */
+ if( ! ( cur_dirb->directory_attribs & DIR_PATH_IN_STREAM_BIT ) ) {
+ gddb_data.path_name =
+ (CHAR_PTR)( (INT8_PTR)vstr_ptr + cur_dirb->directory_name.data_offset ) ;
+ gddb_data.path_size = (INT16)cur_dirb->directory_name.data_size ;
+ } else {
+ gddb_data.path_name = NULL ;
+ gddb_data.path_size = 0 ;
+ }
+
+ TapeDateToDate( &create_date, &cur_dirb->create_date ) ;
+ gddb_data.creat_date = &create_date ;
+ TapeDateToDate( &last_mod_date, &cur_dirb->last_mod_date ) ;
+ gddb_data.mod_date = &last_mod_date ;
+ TapeDateToDate( &backup_date, &cur_dirb->backup_date ) ;
+ gddb_data.backup_date = &backup_date ;
+ TapeDateToDate( &last_access_date, &cur_dirb->last_access_date ) ;
+ gddb_data.access_date = &last_access_date ;
+ }
+
+ /* Tell the file system to do its thing */
+ tmp_filter = FS_CreateGenDDB( cur_fsys, &gddb_data ) ;
+
+ ProcessDataFilter( channel, tmp_filter ) ;
+
+ channel->lst_did = cur_dirb->block_hdr.control_block_id ;
+
+ return( TFLE_NO_ERR ) ;
+}
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_RdFILE
+
+ Description: Translates a tape format FILE blk into a OS DBLK.
+
+ Returns: TFLE_xxx error code
+
+ Notes:
+
+**/
+INT16 F40_RdFILE(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ DBLK_PTR cur_dblk = channel->cur_dblk ;
+ MTF_FILE_PTR cur_file = (MTF_FILE_PTR)( BM_NextBytePtr( buffer ) ) ;
+ FSYS_HAND cur_fsys = channel->cur_fsys ;
+ GEN_FDB_DATA gfdb_data ;
+ UINT16 tmp_filter ;
+ UINT8_PTR vstr_ptr = (UINT8_PTR)cur_file ;
+ UINT8_PTR buff_ptr ;
+ DATE_TIME create_date ;
+ DATE_TIME last_mod_date ;
+ DATE_TIME backup_date ;
+ DATE_TIME last_access_date ;
+
+ /* Initialize the file systems interface structure */
+ FS_SetDefaultDBLK( cur_fsys, BT_FDB, (CREATE_DBLK_PTR)&gfdb_data ) ;
+ gfdb_data.std_data.dblk = cur_dblk ;
+
+ /* Set the non-defaulted standard fields for the FS */
+ SetStandFields( channel, &gfdb_data.std_data, &cur_file->block_hdr, buffer ) ;
+
+ /* Set the FILE attributes. Note that if this is an "old" tape,
+ the attibute bits were being set wrong, and need to be translated.
+ */
+ if( cur_env->old_tape ) {
+
+ gfdb_data.std_data.attrib = cur_file->file_attributes &
+ ~( OLD_FILE_IN_USE_BIT | OLD_FILE_NAME_IN_STREAM_BIT ) ;
+
+ gfdb_data.std_data.attrib |= ( cur_file->file_attributes & OLD_FILE_IN_USE_BIT )
+ ? FILE_IN_USE_BIT : 0 ;
+ gfdb_data.std_data.attrib |= ( cur_file->file_attributes & OLD_FILE_NAME_IN_STREAM_BIT )
+ ? FILE_NAME_IN_STREAM_BIT : 0 ;
+ } else {
+ gfdb_data.std_data.attrib = cur_file->file_attributes ;
+ if( cur_file->block_hdr.machine_os_id == FS_PC_DOS ||
+ cur_file->block_hdr.machine_os_id == FS_PC_OS2 ) {
+
+ gfdb_data.std_data.attrib &= 0xFFFF00FF ;
+ gfdb_data.std_data.attrib |=
+ ( cur_file->file_attributes & DOS_FILE_READONLY_BIT )
+ ? OBJ_READONLY_BIT : 0 ;
+ gfdb_data.std_data.attrib |=
+ ( cur_file->file_attributes & DOS_FILE_HIDDEN_BIT )
+ ? OBJ_HIDDEN_BIT : 0 ;
+ gfdb_data.std_data.attrib |=
+ ( cur_file->file_attributes & DOS_FILE_SYSTEM_BIT )
+ ? OBJ_SYSTEM_BIT : 0 ;
+ gfdb_data.std_data.attrib |=
+ ( cur_file->file_attributes & DOS_FILE_MODIFIED_BIT )
+ ? OBJ_MODIFIED_BIT : 0 ;
+ gfdb_data.std_data.attrib &= 0xFFFFFF00 ;
+ }
+ }
+
+ /* If this is an "old" tape the file name is NULL terminated. If it's
+ a "new" tape, we have to copy the string to another data area and
+ NULL terminate it before passing it to the UI.
+ */
+ if( cur_env->old_tape ) {
+ /* This is an old tape with NULL terminated strings. */
+
+ gfdb_data.fname = (CHAR_PTR)( vstr_ptr + cur_file->file_name.data_offset ) ;
+ gfdb_data.fname_size = cur_file->file_name.data_size ;
+
+ } else {
+ /* This is a new tape, copy the file name into a buffer and NULL
+ terminate it.
+ */
+
+ if( cur_env->util_buff == NULL ) {
+ if( ( cur_env->util_buff = calloc( F40_INIT_UTIL_BUFF_SIZE, 1 ) ) == NULL ) {
+ return( TFLE_NO_MEMORY ) ;
+ }
+ cur_env->util_buff_size = F40_INIT_UTIL_BUFF_SIZE ;
+ }
+
+ buff_ptr = cur_env->util_buff ;
+
+ gfdb_data.fname = (CHAR_PTR)buff_ptr ;
+ if( cur_file->file_name.data_size != 0 ) {
+ gfdb_data.fname_size =
+ F40_CopyAndTerminate( &buff_ptr, vstr_ptr +
+ cur_file->file_name.data_offset,
+ cur_file->file_name.data_size,
+ cur_file->block_hdr.string_type,
+ cur_file->block_hdr.string_type ) ;
+ } else {
+ gfdb_data.fname_size = 0 ;
+ }
+ }
+
+ TapeDateToDate( &create_date, &cur_file->create_date ) ;
+ gfdb_data.creat_date = &create_date ;
+ TapeDateToDate( &last_mod_date, &cur_file->last_mod_date ) ;
+ gfdb_data.mod_date = &last_mod_date ;
+ TapeDateToDate( &backup_date, &cur_file->backup_date ) ;
+ gfdb_data.backup_date = &backup_date ;
+ TapeDateToDate( &last_access_date, &cur_file->last_access_date ) ;
+ gfdb_data.access_date = &last_access_date ;
+
+ /* Tell the file system to do its thing */
+ tmp_filter = FS_CreateGenFDB( cur_fsys, &gfdb_data ) ;
+ ProcessDataFilter( channel, tmp_filter ) ;
+
+ channel->lst_fid = cur_file->block_hdr.control_block_id ;
+
+ return( TFLE_NO_ERR ) ;
+}
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_RdIMAG
+
+ Description: Translates a tape format IMAG blk into a OS DBLK.
+
+ Returns: TFLE_xxx error code
+
+ Notes:
+
+**/
+INT16 F40_RdIMAG(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+ DBLK_PTR cur_dblk = channel->cur_dblk ;
+ F40_IMAG_PTR cur_imag = (F40_IMAG_PTR)( BM_NextBytePtr( buffer ) ) ;
+ FSYS_HAND cur_fsys = channel->cur_fsys ;
+ GEN_IDB_DATA gidb_data ;
+ UINT16 tmp_filter ;
+
+ /* Initialize the file systems interface structure */
+ FS_SetDefaultDBLK( cur_fsys, BT_IDB, (CREATE_DBLK_PTR)&gidb_data ) ;
+ gidb_data.std_data.dblk = cur_dblk ;
+
+ /* Set the non-defaulted standard fields for the FS */
+ SetStandFields( channel, &gidb_data.std_data, &cur_imag->block_hdr,
+ buffer ) ;
+
+ gidb_data.std_data.attrib = cur_imag->image_attribs ;
+
+ /* Set the non-defaulted IDB specific fields */
+ gidb_data.pname =
+ (CHAR_PTR)( (UINT8_PTR)cur_imag + cur_imag->partition_name.data_offset ) ;
+ gidb_data.pname_size = cur_imag->partition_name.data_size ;
+
+ gidb_data.byte_per_sector = (UINT16)cur_imag->bytes_in_sector ;
+ gidb_data.num_sect = cur_imag->partition_no_of_sector ;
+ gidb_data.sys_ind = cur_imag->partition_sys_ind ;
+ gidb_data.hhead = cur_imag->no_of_heads ;
+ gidb_data.hsect = (UINT16)cur_imag->no_of_sectors ;
+ gidb_data.rsect = cur_imag->relative_sector_no ;
+
+ /* Setup Total Data Size */
+ /* ***** 64 BIT ****
+ channel->tdata_size = cur_imag->block_hdr.number_of_data_bytes ;
+ */
+
+ tmp_filter = FS_CreateGenIDB( cur_fsys, &gidb_data ) ;
+
+ ProcessDataFilter( channel, tmp_filter ) ;
+
+ return( TFLE_NO_ERR ) ;
+}
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_RdCFIL
+
+ Description: Translates a tape format CFIL blk into a OS DBLK.
+
+ Returns: TFLE_xxx error code
+
+ Notes:
+
+**/
+INT16 F40_RdCFIL(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ DBLK_PTR cur_dblk = channel->cur_dblk ;
+ MTF_CFIL_PTR cur_cfil = (MTF_CFIL_PTR)( BM_NextBytePtr( buffer ) ) ;
+ FSYS_HAND cur_fsys = channel->cur_fsys ;
+ GEN_CFDB_DATA gcfdb_data ;
+ INT16 tmp_filter ;
+
+ /* Initialize the file systems interface structure */
+ FS_SetDefaultDBLK( cur_fsys, BT_CFDB, (CREATE_DBLK_PTR)&gcfdb_data ) ;
+ gcfdb_data.std_data.dblk = cur_dblk ;
+
+ SetStandFields( channel, &gcfdb_data.std_data, &cur_cfil->block_hdr, buffer ) ;
+
+ /* Set the CFIL attributes. Note that if this is an "old" tape,
+ the attibute bits were being set wrong, and need to be translated.
+ */
+ if( cur_env->old_tape ) {
+ gcfdb_data.std_data.attrib = 0 ;
+ gcfdb_data.std_data.attrib |= ( cur_cfil->corrupt_file_attribs & OLD_CFDB_LENGTH_CHANGE_BIT )
+ ? CFDB_LENGTH_CHANGE_BIT : 0 ;
+ gcfdb_data.std_data.attrib |= ( cur_cfil->corrupt_file_attribs & OLD_CFDB_UNREADABLE_BLK_BIT )
+ ? CFDB_UNREADABLE_BLK_BIT : 0 ;
+ gcfdb_data.std_data.attrib |= ( cur_cfil->corrupt_file_attribs & OLD_CFDB_DEADLOCK_BIT )
+ ? CFDB_DEADLOCK_BIT : 0 ;
+
+ } else {
+ gcfdb_data.std_data.attrib = cur_cfil->corrupt_file_attribs ;
+ }
+
+ gcfdb_data.corrupt_offset = U64_Lsw( cur_cfil->stream_offset ) ;
+ gcfdb_data.stream_number = cur_cfil->corrupt_stream_number ;
+
+ /* Tell the file system to do its thing */
+ tmp_filter = FS_CreateGenCFDB( cur_fsys, &gcfdb_data ) ;
+
+ ProcessDataFilter( channel, tmp_filter ) ;
+
+ return( TFLE_NO_ERR ) ;
+}
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_RdEOSPadBlk
+
+ Description: We know if we see this DBLK type that there is no more
+ real data in the set, and that the data area this block
+ is intended to pad out is in this buffer (it is the left
+ over area of a physical block and the buffer size must
+ be an even multiple of the pbysical block size). So we
+ set all the data size stuff to 0, and set the buffer
+ offset to the end of data. the read loop will check for
+ another DBLK, and when it doesn't find one it will report
+ that we are at the end of set.
+
+ Returns: TFLE_xxx error code
+
+ Notes:
+
+**/
+static INT16 F40_RdEOSPadBlk(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+ channel->retranslate_size = CH_NO_RETRANSLATE_40 ;
+
+ /* We know that is the last DBLK in the buffer, and that the data area
+ it is padding out is the remainder of the data in this buffer.
+ */
+ BM_UpdCnts( channel->cur_buff, BM_BytesFree( channel->cur_buff ) ) ;
+ return( TFLE_NO_ERR ) ;
+ (VOID)buffer;
+}
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_RdVarStream
+
+ Description: This is actually used for Variable length streams
+
+ Returns: TFLE_xxx error code
+
+ Notes:
+
+**/
+
+INT16 F40_RdVarStream( CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+ F40_ENV_PTR currentEnv = (F40_ENV_PTR)( channel->fmt_env ) ;
+ MTF_STREAM_PTR currentStream = (MTF_STREAM_PTR)BM_NextBytePtr( buffer ) ;
+
+
+ channel->current_stream.size = currentStream->data_length ;
+ BM_UpdCnts( buffer, sizeof( MTF_STREAM ) ) ;
+ SetChannelStatus( channel, CH_DATA_PHASE ) ;
+
+ if( currentStream->tf_attribs & STREAM_VAR_END ) {
+ currentEnv->make_streams_invisible = FALSE ;
+ }
+
+ return( TFLE_NO_ERR ) ;
+}
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_RdVarStream
+
+ Description: This is actually used for Variable length streams
+
+ Returns: TFLE_xxx error code
+
+ Notes:
+
+**/
+INT16 F40_RdMDB( CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+ F40_ENV_PTR currentEnv = (F40_ENV_PTR)( channel->fmt_env ) ;
+
+
+ if( currentEnv->frag_cnt && BM_BytesFree( buffer ) == 0 ) {
+ return( TFLE_NO_ERR ) ;
+ }
+
+ if( currentEnv->make_streams_invisible ) {
+ return( F40_RdVarStream( channel, buffer ) ) ;
+ } else {
+ return( F40_RdEOSPadBlk( channel, buffer ) ) ;
+ }
+}
+
+
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_RdStream
+
+ Description: Reads a Stream Header
+
+ Returns: TFLE_xxx error code
+
+ Notes:
+
+**/
+
+INT16 F40_RdStream( CHANNEL_PTR Channel,
+ BUF_PTR Buffer )
+{
+ F40_ENV_PTR currentEnv = (F40_ENV_PTR)( Channel->fmt_env ) ;
+ MTF_STREAM_PTR currentStream = (MTF_STREAM_PTR)( BM_NextBytePtr( Buffer ) ) ;
+ STREAM_INFO_PTR channelStream = &Channel->current_stream ;
+
+
+
+ if( currentEnv->frag_cnt ) {
+ currentStream = ( MTF_STREAM_PTR ) &currentEnv->frag[0] ;
+ currentEnv->frag_cnt = 0 ;
+ } else {
+ BM_UpdCnts( Buffer, sizeof( MTF_STREAM ) ) ;
+ }
+
+
+ /* Reset Filter */
+ if( currentStream->id == STRM_PAD ) {
+ SetChannelStatus( Channel, CH_SKIP_CURRENT_STREAM ) ;
+ } else {
+ ClrChannelStatus( Channel, CH_SKIP_CURRENT_STREAM ) ;
+ }
+
+ channelStream->id = currentStream->id ;
+ channelStream->fs_attrib = currentStream->fs_attribs ;
+ channelStream->tf_attrib = currentStream->tf_attribs ;
+ channelStream->size = currentStream->data_length ;
+
+ if( currentStream->tf_attribs & STREAM_VARIABLE ) {
+ currentEnv->make_streams_invisible = TRUE ;
+ } else {
+ currentEnv->make_streams_invisible = FALSE ;
+ }
+
+ return( TFLE_NO_ERR ) ;
+
+}
+
+
+
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_RdUDB
+
+ Description: Translates a Unknown Desciptor Block and throws away
+ the data.
+
+ Returns: TFLE_xxx error code
+
+ Notes:
+
+**/
+INT16 F40_RdUDB(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+ F40_UDB_PTR cur_udb = (F40_UDB_PTR)( BM_NextBytePtr( buffer ) ) ;
+ GEN_UDB_DATA gudb_data ;
+ INT16 tmp_filter ;
+
+ /* Initialize the file systems interface structure */
+ FS_SetDefaultDBLK( channel->cur_fsys, BT_UDB, (CREATE_DBLK_PTR)&gudb_data ) ;
+ gudb_data.std_data.dblk = channel->cur_dblk ;
+
+ /* Set the non-defaulted standard fields for the FS */
+ SetStandFields( channel, &gudb_data.std_data, &cur_udb->block_hdr, buffer ) ;
+
+ tmp_filter = FS_CreateGenUDB( channel->cur_fsys, &gudb_data ) ;
+ ProcessDataFilter( channel, tmp_filter ) ;
+
+ return( TFLE_NO_ERR ) ;
+}
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_RdContTape
+
+ Description: Sets up the continuation tape to pass over the updated bs.
+
+ Returns: BOOLEAN indicating Success or Failure
+
+ Notes: THIS ASSUMES THAT THE BUFFER POINTER IS POINTING DIRECTLY
+ AFTER THE CONT. VCB. TO THE NEXT TBLK.
+
+ FURTHER, IT IS ASSUMED THE CURRENT BUFFER HAS BEEN READ
+ FROM THE NEXT TAPE IN THE TAPE SEQUENCE ( THIS SHOULD
+ HAVE BEEN DONE BY "Tape Positioning".
+
+**/
+BOOLEAN F40_RdContTape(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+ MTF_DB_HDR_PTR cur_hdr ;
+ MTF_STREAM_PTR cur_strm ;
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+
+ BM_SetBytesFree( buffer, BM_BytesFree( buffer ) +
+ BM_NextByteOffset( buffer ) ) ;
+ BM_SetNextByteOffset( buffer, 0 ) ;
+
+ if( cur_env->tape_hdr.block_header.block_attribs & MTF_DB_EOS_AT_EOM_BIT ) {
+ BM_SetNextByteOffset( buffer, BM_BytesFree( buffer ) ) ;
+ BM_SetBytesFree( buffer, 0 ) ;
+ return( TRUE ) ;
+ }
+
+ cur_hdr = (MTF_DB_HDR_PTR)( BM_NextBytePtr( buffer ) ) ;
+
+ /* Set the lba of the beginning of the buffer and adjust the running lba */
+ BM_SetBeginningLBA( buffer, ( U64_Lsw( cur_hdr->logical_block_address ) -
+ ( BM_NextByteOffset( buffer ) / channel->lb_size ) ) ) ;
+
+ channel->running_lba = U64_Lsw( cur_hdr->logical_block_address ) +
+ ( BM_BytesFree( buffer ) / channel->lb_size ) ;
+
+ /* Find The last DBLK, we were operating on */
+ while( cur_hdr->control_block_id != channel->eom_id ) {
+ F40_FindNextDBLK( buffer, channel->lb_size, NULL ) ;
+ cur_hdr = (MTF_DB_HDR_PTR)( BM_NextBytePtr( buffer ) ) ;
+ }
+
+ /* Okay we have a live one, let's update the counts */
+ if( cur_hdr->control_block_id == channel->eom_id ) {
+ BM_UpdCnts( buffer, cur_hdr->offset_to_data ) ;
+
+ /* If the next block is a stream header, and it's a continuation,
+ just skip it.
+ */
+ cur_strm = (MTF_STREAM_PTR)BM_NextBytePtr( buffer ) ;
+ if( F40_CalcChecksum( (UINT16_PTR)cur_strm, F40_STREAM_CHKSUM_LEN )
+ == cur_strm->chksum ) {
+ if( cur_strm->tf_attribs & STREAM_CONTINUE ) {
+ BM_UpdCnts( buffer, sizeof( MTF_STREAM ) ) ;
+ }
+ }
+ }
+ return( TRUE ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: SetStandFields
+
+ Description: Sets up the standard fields in translation to dblks.
+
+ Returns: Nothing.
+
+ Notes:
+
+**/
+static VOID _near SetStandFields(
+ CHANNEL_PTR channel,
+ STD_DBLK_DATA_PTR std_data,
+ MTF_DB_HDR_PTR cur_hdr,
+ BUF_PTR buffer )
+{
+ UINT8_PTR os_info = (UINT8_PTR)cur_hdr ;
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)channel->fmt_env ;
+
+ /* New Block, reset filter */
+ ClrChannelStatus( channel, CH_SKIP_ALL_STREAMS ) ;
+
+ std_data->tape_seq_num = cur_env->tape_hdr.tape_seq_number ;
+
+ std_data->os_id = ( UINT8 ) cur_hdr->machine_os_id ;
+ std_data->os_ver = ( UINT8 ) cur_hdr->machine_os_version ;
+
+ std_data->string_type = cur_hdr->string_type ;
+
+ std_data->blkid = cur_hdr->control_block_id ;
+ std_data->lba = U64_Lsw( cur_hdr->logical_block_address ) ;
+
+ std_data->continue_obj = (BOOLEAN)( cur_hdr->block_attribs & MTF_DB_CONT_BIT ) ;
+ std_data->compressed_obj = (BOOLEAN)( cur_hdr->block_attribs & MTF_DB_COMPRESS_BIT ) ;
+
+ /* Calculate Total Data & Pad Sizes */
+ std_data->disp_size = cur_hdr->displayable_size ;
+
+ channel->retranslate_size = CH_NO_RETRANSLATE_40 ;
+
+ BM_UpdCnts( buffer, cur_hdr->offset_to_data ) ;
+
+ /* There is only one case where the offset to data isn't on a 4 byte
+ boundary, and that's when we're pointing at a continuation stream
+ header. If this is the case, we set a flag so DetBlkType won't
+ try to line up on a boundary before looking for the header.
+ */
+ if( cur_hdr->offset_to_data % 4 != 0 ) {
+ msassert( std_data->continue_obj ) ;
+ cur_env->unaligned_stream = TRUE ;
+ }
+
+ /* Get OS Specific info */
+ std_data->os_info = (BYTE_PTR)( (INT8_PTR)os_info + cur_hdr->os_specific_data.data_offset ) ;
+ std_data->os_info_size = cur_hdr->os_specific_data.data_size ;
+
+ /* we're not ready for this yet! need to calc FMs from Bset# first
+ *
+ *
+ * if ( BM_ReadError( buffer ) == GEN_ERR_ENDSET ) {
+ * channel->cur_drv->cur_pos.fmks++ ;
+ * }
+ *
+ */
+}
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_RdException
+
+ Description: Determines the meaning of an exception passed to it.
+
+ Returns: UINT16 - FMT_EXC_xxx
+
+ Notes:
+
+**/
+UINT16 F40_RdException(
+ CHANNEL_PTR channel,
+ INT16 exception )
+{
+ BUF_PTR tmpBUF ;
+ INT16 drv_hdl = channel->cur_drv->drv_hdl ;
+ UINT16 ret_val = FMT_EXC_HOSED ;
+ DRIVE_PTR curDRV = channel->cur_drv ;
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)channel->fmt_env ;
+ RET_BUF myret ;
+ UINT16 blk_type ;
+
+ /* If we had a partial stream at EOM, ignore it. */
+ cur_env->frag_cnt = 0 ;
+
+ if( exception != GEN_ERR_ENDSET ) {
+ return( FMT_EXC_HOSED ) ;
+ }
+
+ if( ( tmpBUF = BM_Get( &channel->buffer_list ) ) == NULL ) {
+ if( ( tmpBUF = BM_GetVCBBuff( &channel->buffer_list ) ) == NULL ) {
+ msassert( FALSE ) ;
+ return( FMT_EXC_HOSED ) ;
+ }
+ }
+
+ if( TpRead( drv_hdl, BM_XferBase( tmpBUF ),
+ (UINT32)BM_XferSize( tmpBUF ) ) == FAILURE ) {
+ BM_Put( tmpBUF ) ;
+ return( FMT_EXC_HOSED ) ;
+ }
+ while( TpReceive( drv_hdl, &myret ) == FAILURE ) {
+ /* for non-preemptive operating systems: */
+ ThreadSwitch( ) ;
+ }
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( channel->cur_drv->thw_inf.the, myret.the ) ;
+
+ if ( myret.gen_error != GEN_NO_ERR ) {
+ curDRV->thw_inf.drv_status = myret.status ;
+ }
+
+ if ( myret.len_got < sizeof( MTF_DB_HDR ) ||
+ ( myret.gen_error != GEN_NO_ERR &&
+ myret.gen_error != GEN_ERR_ENDSET ) ) {
+
+ BM_Put( tmpBUF ) ;
+ return( FMT_EXC_HOSED ) ;
+ }
+
+ if( F40_DetBlkType( channel, tmpBUF, &blk_type ) != TFLE_NO_ERR ) {
+ BM_Put( tmpBUF ) ;
+ return( FMT_EXC_HOSED ) ;
+ }
+
+ switch( blk_type ) {
+
+ case F40_ESET_IDI:
+ /* ESET may have associated data. If it does, we eat it! */
+ if( myret.gen_error == GEN_NO_ERR ) {
+ if( TpReadEndSet( drv_hdl, (INT16)1, (INT16)FORWARD ) == FAILURE ) {
+ BM_Put( tmpBUF ) ;
+ return( FMT_EXC_HOSED ) ;
+ }
+ while( TpReceive( drv_hdl, &myret ) == FAILURE ) {
+ /* for non-preemptive operating systems: */
+ ThreadSwitch( ) ;
+ }
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( channel->cur_drv->thw_inf.the, myret.the ) ;
+
+ if( myret.gen_error != GEN_NO_ERR ) {
+ BM_Put( tmpBUF ) ;
+ return( FMT_EXC_HOSED ) ;
+ }
+ }
+ ret_val = FMT_EXC_EOS ;
+ break ;
+
+ case F40_EOTM_IDI:
+ ret_val = FMT_EXC_EOM ;
+ break ;
+
+ default:
+ ret_val = FMT_EXC_HOSED ;
+ break ;
+ }
+
+ curDRV->cur_pos.fmks++ ;
+ BM_Put( tmpBUF ) ;
+
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_MoveToVCB
+
+ Description: Positions the tape in front of the SSET for the set
+ a relative offset from the current set.
+
+ Returns: INT16 - TFLE_xxx
+
+ Notes:
+
+**/
+INT16 F40_MoveToVCB(
+ CHANNEL_PTR channel,
+ INT16 number,
+ BOOLEAN_PTR need_read,
+ BOOLEAN really_move )
+{
+ INT16 nmarks = 0 ; /* number of file marks to move */
+ INT16 ret_val = TFLE_NO_ERR ;
+ BOOLEAN at_mos = IsPosBitSet( channel->cur_drv, AT_MOS ) != 0UL ;
+ BOOLEAN at_eos = ( ! at_mos ) && IsPosBitSet( channel->cur_drv, AT_EOS ) ;
+
+ msassert( number <= 1 ) ;
+
+ if ( really_move ) { /* this is a no-op for us */
+ *need_read = FALSE ;
+ return( TFLE_NO_ERR ) ;
+ }
+
+ ClrPosBit( channel->cur_drv, AT_MOS ) ;
+
+ if ( number == 1 ) { /* move forward */
+ *need_read = TRUE ;
+ if( at_eos ) {
+ ret_val = TFLE_NO_ERR ;
+ } else {
+ ret_val = MoveFileMarks( channel, (INT16)1, (INT16)FORWARD ) ;
+ if( ret_val == TFLE_NO_ERR || ret_val == TFLE_UNEXPECTED_EOM ) {
+ ret_val = F40_RdException( channel, (INT16)GEN_ERR_ENDSET ) ;
+ if( ret_val == FMT_EXC_HOSED ) {
+ SetPosBit( channel->cur_drv, REW_CLOSE ) ;
+ ret_val = TFLE_TAPE_INCONSISTENCY ;
+ } else if( ret_val == FMT_EXC_EOM ) {
+ ret_val = TF_NEED_NEW_TAPE ;
+ } else {
+ SetPosBit( channel->cur_drv, AT_EOS ) ;
+ ret_val = TFLE_NO_ERR ;
+ }
+ } else if ( ret_val == TF_NO_MORE_DATA ) {
+ SetPosBit( channel->cur_drv, REW_CLOSE ) ;
+ ret_val = TFLE_TAPE_INCONSISTENCY ;
+ }
+ }
+
+ } else if ( number < 0 ) { /* move backward */
+ nmarks = ( number * (INT16)(-2) ) + (INT16)1 ;
+ if( at_eos ) {
+ nmarks += 2 ;
+ }
+ } else { /* current */
+ if( at_mos ) {
+ nmarks = 1 ;
+ } else if( at_eos ) {
+ nmarks = 3 ;
+ } else { /* we're already there. */
+ *need_read = FALSE ;
+ ret_val = TFLE_NO_ERR ;
+ }
+ }
+
+ if( nmarks != 0 ) {
+ if( channel->cur_drv->thw_inf.drv_info.drv_features & TDI_REV_FMK ) {
+ if( nmarks >= (INT16) channel->cur_drv->cur_pos.fmks ) {
+ /* We probably have one of two conditions:
+ 1. We are searching for the first set on tape.
+ 2. There is a mix of formats on the tape, so we
+ have to take it from the top.
+ */
+ ret_val = TF_NEED_REWIND_FIRST ;
+ } else {
+ *need_read = TRUE ;
+ ret_val = MoveFileMarks( channel, nmarks, (INT16)BACKWARD ) ;
+ /* MoveFileMarks is DERANGED - kludge filemark count */
+ /* 'cause we're not allowed to FIX MoveFileMarks properly! */
+ ++channel->cur_drv->cur_pos.fmks ;
+ }
+ } else {
+ /* we can't go backwards without rewinding (ugh!) */
+ ret_val = TF_NEED_REWIND_FIRST ;
+ }
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: DateToTapeDate
+
+ Description: Translates the Date/Time structure used by the upper
+ layers into a compressed format for writing to tape.
+
+ Returns: Nothing
+
+ Notes: Assumes integers stored in Intel format
+
+**/
+VOID DateToTapeDate(
+ MTF_DATE_TIME_PTR tape_date, /* O - Dest Tape Date/Time struct */
+ DATE_TIME_PTR date ) /* I - Source Date/Time struct */
+{
+ UINT16 temp ;
+
+ if( !date->date_valid ) {
+ tape_date->dt_field[2] = 0 ;
+ } else {
+ temp = date->year << 2 ;
+ tape_date->dt_field[0] = ((UINT8_PTR)&temp)[1] ;
+ tape_date->dt_field[1] = ((UINT8_PTR)&temp)[0] ;
+ temp = date->month << 6 ;
+ tape_date->dt_field[1] |= ((UINT8_PTR)&temp)[1] ;
+ tape_date->dt_field[2] = ((UINT8_PTR)&temp)[0] ;
+ temp = date->day << 1 ;
+ tape_date->dt_field[2] |= ((UINT8_PTR)&temp)[0] ;
+ temp = date->hour << 4 ;
+ tape_date->dt_field[2] |= ((UINT8_PTR)&temp)[1] ;
+ tape_date->dt_field[3] = ((UINT8_PTR)&temp)[0] ;
+ temp = date->minute << 6 ;
+ tape_date->dt_field[3] |= ((UINT8_PTR)&temp)[1] ;
+ tape_date->dt_field[4] = ((UINT8_PTR)&temp)[0] ;
+ temp = date->second ;
+ tape_date->dt_field[4] |= ((UINT8_PTR)&temp)[0] ;
+ }
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: TapeDateToDate
+
+ Description: Translates the compressed Tape Date/Time structure
+ stored on tape to the Date/Time structure used by the
+ upper layers.
+
+ Returns: Nothing
+
+ Notes:
+
+**/
+VOID TapeDateToDate(
+ DATE_TIME_PTR date, /* O - Dest Date/Time struct */
+ MTF_DATE_TIME_PTR tape_date ) /* I - Source Tape Date/Time struct */
+{
+ UINT8 temp[2] ;
+
+ if( tape_date->dt_field[2] == 0 ) {
+ date->date_valid = 0 ;
+ } else {
+ date->date_valid = 1 ;
+ temp[0] = tape_date->dt_field[1] ;
+ temp[1] = tape_date->dt_field[0] ;
+ date->year = *((UINT16_PTR)temp) >> 2 ;
+ temp[0] = tape_date->dt_field[2] ;
+ temp[1] = tape_date->dt_field[1] ;
+ date->month = (*((UINT16_PTR)temp) >> 6) & 0x000F ;
+ date->day = (*((UINT16_PTR)temp) >> 1) & 0x001F ;
+ temp[0] = tape_date->dt_field[3] ;
+ temp[1] = tape_date->dt_field[2] ;
+ date->hour = (*((UINT16_PTR)temp) >> 4) & 0x001F ;
+ temp[0] = tape_date->dt_field[4] ;
+ temp[1] = tape_date->dt_field[3] ;
+ date->minute = (*((UINT16_PTR)temp) >> 6) & 0x003F ;
+ date->second = *((UINT16_PTR)temp) & 0x003F ;
+ }
+}
+
+
+static VOID F40_FindNextDBLK(
+ BUF_PTR buffer,
+ UINT16 lb_size,
+ UINT8_PTR blk_type )
+{
+ MTF_DB_HDR_PTR cur_hdr ;
+ UINT8 temp[4] ;
+
+ if( blk_type == NULL ) {
+ temp[0] = temp[1] = temp[2] = temp[3] = 0 ;
+ }
+
+ BM_UpdCnts( buffer, lb_size ) ;
+ cur_hdr = (MTF_DB_HDR_PTR)BM_NextBytePtr( buffer ) ;
+ while( BM_BytesFree( buffer ) >= lb_size ) {
+ if( F40_CalcChecksum( (UINT16_PTR)cur_hdr, F40_HDR_CHKSUM_LEN )
+ == cur_hdr->hdr_chksm ) {
+ if( ( blk_type == NULL &&
+ memcmp( temp, cur_hdr->block_type, 4 ) != 0 )) {
+ return ;
+ }
+ if ( ( blk_type == NULL) ||
+ memcmp( blk_type, cur_hdr->block_type, 4 ) == 0 ) {
+
+ return ;
+ }
+ }
+ BM_UpdCnts( buffer, lb_size ) ;
+ cur_hdr = (MTF_DB_HDR_PTR)BM_NextBytePtr( buffer ) ;
+ }
+}
+
diff --git a/private/utils/ntbackup/src/memang32.c b/private/utils/ntbackup/src/memang32.c
new file mode 100644
index 000000000..094792c23
--- /dev/null
+++ b/private/utils/ntbackup/src/memang32.c
@@ -0,0 +1,801 @@
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: memang32.c
+
+ Description: This file contains the functions for the 32 bit GUI Memory
+ Manager (MEM).
+
+ $Log: T:/LOGFILES/MEMANG32.C_V $
+
+ Rev 1.11.1.1 11 Feb 1994 16:38:52 GREGG
+Report more details when size mismatch detected.
+
+ Rev 1.11.1.0 24 Jan 1994 15:59:26 GREGG
+A variety of improvements to the debug side.
+
+ Rev 1.11 29 Oct 1993 16:17:58 BARRY
+ Almost a total rewrite. Changed the block-copied nature of
+malloc, calloc, and realloc. Gregg fixed ANSI violations in behavior
+of realloc.
+ The debug code has been completely rewritten to start a
+thread that does nothing but continually check the validity of
+allocated memory. [This is turned on by defining MEM_DEBUG.] Any
+inconsistency found will result in a mscassert [critical assert]
+being raised.
+
+
+ Rev 1.10 12 Aug 1993 16:39:32 BARRY
+In debug code, count bytes used properly.
+
+ Rev 1.9 12 Aug 1993 12:50:14 BARRY
+Added some debug code (enabled by definition of MEM_DEBUG) to help
+diagnose common memory corruption problems.
+
+ Rev 1.8 14 May 1993 15:24:56 BARRY
+Fixed warning.
+
+ Rev 1.7 16 Mar 1993 15:41:08 STEVEN
+fix free of failed realloc
+
+ Rev 1.6 16 Mar 1993 13:46:18 STEVEN
+realloc sucked
+
+ Rev 1.5 07 Mar 1993 10:38:48 MIKEP
+fix wwarnings for no return values
+
+ Rev 1.4 11 Feb 1993 12:12:16 STEVEN
+stuf from mike
+
+ Rev 1.3 04 Sep 1992 15:19:54 STEVEN
+realloc must be moveable
+
+ Rev 1.2 18 Aug 1992 10:02:52 BURT
+fix warnings
+
+ Rev 1.1 25 Jun 1992 11:16:44 STEVEN
+do not zeroinit a realloc and specify fixed
+
+ Rev 1.0 09 Jun 1992 17:14:56 STEVEN
+Initial revision.
+
+
+******************************************************************************/
+
+#include "all.h"
+
+// GLOBAL VARIABLES
+
+UINT gunSegCount = 0;
+ULONG gulMemAvail = 0;
+ULONG gulMemUsed = 0;
+BOOL gfShowMemory = FALSE;
+
+
+static HTIMER TimerHandle;
+
+INT MEM_StartShowMemory( )
+{
+ TimerHandle = WM_HookTimer( STM_DrawMemory, 5 );
+ return( 0 );
+}
+
+
+INT MEM_StopShowMemory( )
+{
+ WM_UnhookTimer( TimerHandle );
+ return( 0 );
+}
+
+
+#if !defined( MEM_DEBUG )
+
+/**/
+/**
+
+ Name: MEM_Malloc
+
+ Description: Calls LocalAlloc to allocate memory.
+
+ Modified: 18-Aug-93
+
+ Returns: NULL if no memory available, Pointer to block otherwise.
+ Note: This uses LocalAlloc( with fixed block ) to
+ perform the alloc.
+
+ Notes: Zeros memory (and MEM_Calloc relies on this).
+**/
+VOID_PTR MEM_Malloc( UINT size )
+{
+ VOID_PTR mem;
+
+ mem = (VOID_PTR)LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT, size );
+
+ if ( mem != NULL )
+ {
+ gulMemUsed += LocalSize( (HLOCAL)mem );
+ }
+
+ return mem;
+}
+
+/**/
+/**
+
+ Name: MEM_Calloc
+
+ Description: This routine allocates storage space for an array of
+ n elements, each of length size bytes. Each element
+ is initialized to zero.
+
+ Modified: 18-Aug-93
+
+ Returns: NULL if unsuccessful, otherwise returns pointer to
+ allocated block.
+
+ Notes: Relies on MEM_Malloc clearing allocated memory.
+
+**/
+VOID_PTR MEM_Calloc( UINT n, UINT size )
+{
+ return MEM_Malloc( n * size );
+}
+
+/**/
+/**
+
+ Name: MEM_ReAlloc
+
+ Description: This function changes the size of a previously allocated
+ memory block.
+
+ If "buf" is NULL, a new buffer is "malloc"-ed.
+
+ If "new_size" is 0, then the block, if it was allocated
+ is now freed (and we return NULL).
+
+ Note: This routine DOES NOT SUPPORT realloc-ing a buffer
+ previously freed. This uses LocalReAlloc()
+ to do the work.
+
+ Modified: 18-Aug-93
+
+ Returns: NULL if unsuccessful, pointer otherwise.
+
+ Notes:
+
+**/
+VOID_PTR MEM_ReAlloc( VOID_PTR oldMem, UINT newSize )
+{
+ VOID_PTR newMem = NULL;
+
+ if ( oldMem == NULL )
+ {
+ newMem = MEM_Malloc( newSize );
+ }
+ else if ( newSize == 0UL )
+ {
+ MEM_Free( oldMem );
+ }
+ else
+ {
+ UINT oldSize = LocalSize( oldMem );
+
+ if ( oldSize >= newSize )
+ {
+ newMem = oldMem;
+ }
+ else
+ {
+ newMem = MEM_Malloc( newSize ) ;
+ if ( newMem != NULL )
+ {
+ memcpy( newMem, oldMem, oldSize ) ;
+ MEM_Free( oldMem );
+ }
+ }
+ }
+ return newMem;
+}
+
+/**/
+/**
+
+ Name: MEM_Free
+
+ Description: This routine frees the memory allocated by a previous
+ call to MEM_Malloc.
+
+ Modified: 18-Aug-93
+
+ Returns: Nothing
+
+**/
+VOID MEM_Free( VOID_PTR mem )
+{
+ if ( mem != NULL )
+ {
+ gulMemUsed -= LocalSize( (HLOCAL)mem );
+ LocalFree( (HLOCAL)mem );
+ }
+}
+
+#else /* MEM_DEBUG */
+
+/**/
+/**************************************************************************
+
+ Debug code to help find memory hits. For each requested memory
+ allocation, addition memory is allocated to hold a debug "header"
+ and a linked list of this memory is maintained. Upon the first
+ allocation, a thread is started that continually scans this list
+ looking for errors (memory overruns, free of invalid pointer, or
+ a free of the same pointer more than once). Upon any error, a
+ critical assert is raised.
+
+
+ gMemList -------> +-------------+
+ | block size | Checked for agreement w/ OS
+ +-------------+
+ | user's size |
+ +-------------+
+ | next block |---> next block
+ +-------------+
+ previous blk <----| prev block |
+ +-------------+
+ | a55aa55a | Checked for "underrun"
+ +-------------+
+ | | Pointer to this area returned
+ | user memory | to caller of malloc, calloc,
+ | | or realloc.
+ +-------------+
+ | a55aa55a | Checked for "overrun"
+ +-------------+
+
+ This list is protected by Enter/LeaveCriticalSection whenever
+ it is manipulated.
+
+ Important: This block is defined to be a multiple of 16 bytes,
+ and must stay that way for MIPS compatibility. This could be
+ conditionally compiled based on the target platform.
+
+
+**************************************************************************/
+
+
+/* Data to put outside allocated memory to detect mem getting trodden on */
+#define NOISE_WORD 0xa55aa55a
+
+/* Structure must be multiple of 16 bytes for MIPS compatibility */
+typedef struct MEM_HEADER {
+ UINT32 size; // Size allocated (>= size requested)
+ UINT32 userSize; // Size requested
+ struct MEM_HEADER *next;
+ struct MEM_HEADER *prev;
+ UINT16 bad; // See MEMERR defines below
+ UINT16 allocLine; // Source line where mem was allocated
+ CHAR allocFile[16]; // Source file where mem was allocated
+ UINT32 reserved[2]; // Pad, adjust if structure changes
+ UINT32 noise; // Leave last
+} MEM_HEADER;
+
+static MEM_HEADER *gMemList = NULL; // Linked list of mem blocks
+static BOOLEAN gMemInited = FALSE; // Is sniffer thread started?
+static UINT32 gMemBlocks = 0; // Count of mem blocks
+static UINT32 gBadBlocks = 0; // Count of bad mem blocks
+static CRITICAL_SECTION gMemListCriticalSection; // Protects list of blocks
+
+typedef struct MEMERR_REC {
+ UINT16 bad;
+ UINT16 allocLine;
+ CHAR allocFile[16];
+ UINT32 gle_code;
+ UINT32 lcl_size;
+ UINT32 save_size;
+} MEMERR_REC;
+
+static MEMERR_REC memErrList[20];
+
+/* Amount of extra memory needed for debug info on each allocation. */
+#define OVERHEAD_SIZE (sizeof(MEM_HEADER) + sizeof(UINT32))
+
+#define MEMERR_NOT_BAD 0
+#define MEMERR_BAD_SIZE 1
+#define MEMERR_BAD_FRONT 2
+#define MEMERR_BAD_BACK 3
+
+
+/**/
+/**
+
+ Name: MEM_ConsistencyCheck()
+
+ Description:
+
+ Modified: 22-Sep-93
+
+ Returns:
+
+ Notes:
+
+**/
+static VOID MEM_ConsistencyCheck( VOID )
+{
+ MEM_HEADER *memList;
+ UINT32 noise = NOISE_WORD;
+ UINT16 count = 0;
+ DWORD gle_code = NO_ERROR ;
+ UINT lcl_size ;
+
+ EnterCriticalSection( &gMemListCriticalSection );
+
+ memList = gMemList;
+
+ for ( ; memList != NULL; memList = memList->next )
+ {
+ if ( memList->bad == MEMERR_NOT_BAD )
+ {
+ UINT16 bad = MEMERR_NOT_BAD;
+
+ SetLastError( NO_ERROR ) ;
+ lcl_size = LocalSize( (HLOCAL)memList );
+ if ( memList->size != lcl_size )
+ {
+ gle_code = GetLastError( ) ;
+ bad = MEMERR_BAD_SIZE;
+ }
+ else if ( memList->noise != NOISE_WORD )
+ {
+ bad = MEMERR_BAD_FRONT;
+ }
+ else
+ {
+ BYTE *p = (BYTE *)(memList + 1) + memList->userSize;
+
+ if ( memcmp( p, &noise, sizeof( noise ) ) != 0 )
+ {
+ bad = MEMERR_BAD_BACK;
+ }
+ }
+
+ if ( bad )
+ {
+ if ( !gb_no_abort_on_mem_check )
+ {
+ RaiseException( EXCEPTION_BREAKPOINT,
+ 0,
+ 0,
+ NULL );
+
+ // Because the debugger doesn't like to stop ...
+
+ RaiseException( EXCEPTION_BREAKPOINT,
+ 0,
+ 0,
+ NULL );
+ }
+ memList->bad = bad;
+ memErrList[count].bad = bad;
+ memErrList[count].lcl_size = lcl_size;
+ memErrList[count].save_size = memList->size;
+ memErrList[count].gle_code = gle_code;
+ memErrList[count].allocLine = memList->allocLine;
+ memcpy( memErrList[count].allocFile,
+ memList->allocFile, 16 * sizeof( CHAR ) );
+ count++;
+ gBadBlocks++;
+ }
+ }
+ }
+ LeaveCriticalSection( &gMemListCriticalSection );
+
+ while ( count-- )
+ {
+ switch ( memErrList[count].bad )
+ {
+ case MEMERR_BAD_SIZE :
+ zprintf( 0, TEXT("Memory consistency checker reported bad size\n") );
+ break;
+
+ case MEMERR_BAD_FRONT :
+ zprintf( 0, TEXT("Memory consistency checker reported buffer underflow\n") );
+ break;
+
+ case MEMERR_BAD_BACK :
+ zprintf( 0, TEXT("Memory consistency checker reported buffer overflow\n") );
+ break;
+ }
+
+ zprintf( 0, "on memory allocated in %s at line %d.\n",
+ memErrList[count].allocFile, memErrList[count].allocLine );
+
+ if ( memErrList[count].bad == MEMERR_BAD_SIZE ) {
+ zprintf( 0, TEXT("Expected size = %lu, Local size = %lu, GetLastError returned: %08lX.\n"),
+ memErrList[count].save_size,
+ memErrList[count].lcl_size,
+ memErrList[count].gle_code );
+ }
+ }
+}
+
+/**/
+/**
+
+ Name: MEM_SnifferThread()
+
+ Description:
+
+ Modified: 22-Sep-93
+
+ Returns:
+
+ Notes:
+
+**/
+static VOID MEM_SnifferThread( )
+{
+ for ( ;; )
+ {
+ MEM_ConsistencyCheck( );
+ _sleep( 1 ) ;
+ }
+}
+
+/**/
+/**
+
+ Name: MEM_InitDebugStuff()
+
+ Description:
+
+ Modified: 22-Sep-93
+
+ Returns:
+
+ Notes:
+
+**/
+static BOOL MEM_InitDebugStuff( VOID )
+{
+ DWORD threadID;
+ BOOL ret_val = FALSE;
+
+ mscassert( !gMemInited );
+
+ if ( !gMemInited )
+ {
+ InitializeCriticalSection( &gMemListCriticalSection );
+
+ if ( CreateThread( NULL, // lpsa,
+ (DWORD)0, // cbStack,
+ (LPVOID)MEM_SnifferThread, // lpStartAddr,
+ NULL, // lpvThreadParm,
+ 0, // fdwCreate,
+ &threadID ) != NULL )
+ {
+ gMemInited = TRUE;
+ ret_val = TRUE;
+ }
+ }
+ else
+ {
+ ret_val = TRUE;
+ }
+ return ret_val;
+}
+
+
+/**/
+/**
+
+ Name: MEM_PrepareMemBlock()
+
+ Description:
+
+ Modified: 22-Sep-93
+
+ Returns:
+
+ Notes:
+
+**/
+static VOID MEM_PrepareMemBlock( VOID *mem, UINT userSize, ACHAR_PTR allocFile, INT allocLine )
+{
+ MEM_HEADER *header = (MEM_HEADER *)mem;
+ BYTE *p;
+ UINT32 noise = NOISE_WORD;
+ ACHAR_PTR q;
+ INT size = 32;
+
+ header->size = LocalSize( (HLOCAL)mem );
+ header->userSize = userSize;
+ header->next = NULL;
+ header->prev = NULL;
+ header->bad = MEMERR_NOT_BAD;
+ header->allocLine = (UINT16)allocLine;
+ header->noise = noise;
+
+ if ( allocFile != NULL )
+ {
+ q = allocFile + strlenA( allocFile );
+ while( q > allocFile && *(q-1) != '\\' )
+ {
+ q--;
+ }
+ q[15] = TEXT('\0');
+
+#ifdef UNICODE
+ mapAnsiToUnic( q, header->allocFile, &size );
+#else
+ strcpy( header->allocFile, q );
+#endif
+ }
+ else
+ {
+ header->allocFile[0] = TEXT('\0');
+ }
+
+ p = (BYTE *)(header + 1) + userSize;
+ memcpy( p, &noise, sizeof( noise ) );
+}
+
+
+/**/
+/**
+
+ Name: MEM_InsertMemBlock()
+
+ Description:
+
+ Modified: 22-Sep-93
+
+ Returns:
+
+ Notes:
+
+**/
+static VOID MEM_InsertMemBlock( VOID *mem )
+{
+ MEM_HEADER *p = (MEM_HEADER *)mem;
+
+ if ( mem != NULL )
+ {
+ EnterCriticalSection( &gMemListCriticalSection );
+
+ // Insert this memory in the list;
+ if ( gMemList == NULL )
+ {
+ p->next = NULL;
+ }
+ else
+ {
+ p->next = gMemList;
+ gMemList->prev = p;
+ }
+ p->prev = NULL;
+ gMemList = p;
+
+ LeaveCriticalSection( &gMemListCriticalSection );
+ }
+}
+
+
+/**/
+/**
+
+ Name: MEM_RemoveMemBlock()
+
+ Description:
+
+ Modified: 22-Sep-93
+
+ Returns:
+
+ Notes:
+
+**/
+static VOID MEM_RemoveMemBlock( VOID *mem )
+{
+ if ( mem != NULL )
+ {
+ BOOLEAN found;
+ MEM_HEADER *cur;
+
+ /*
+ * Let's scan the list and be sure the memory really is in it
+ * before we dequeue it.
+ */
+
+ EnterCriticalSection( &gMemListCriticalSection );
+
+ for ( found = FALSE, cur = gMemList; (cur != NULL); cur = cur->next )
+ {
+ if ( cur == mem )
+ {
+ found = TRUE;
+ break;
+ }
+ }
+
+ if ( found )
+ {
+ MEM_HEADER *p = (MEM_HEADER *)mem;
+
+ /* Adjust pointers to remove elem from list */
+ if ( p->next != NULL )
+ {
+ p->next->prev = p->prev;
+ }
+
+ if ( p->prev != NULL )
+ {
+ p->prev->next = p->next;
+ }
+
+ /* Special case for removing item at head of list */
+ if ( p == gMemList )
+ {
+ gMemList = p->next;
+ }
+ }
+ LeaveCriticalSection( &gMemListCriticalSection );
+
+ /* If this elem wasn't found in list, somebody freed it twice. */
+ mscassert( found == TRUE );
+ }
+}
+
+
+/**/
+/**
+
+ Name: MEM_Malloc()
+
+ Description:
+
+ Modified: 22-Sep-93
+
+ Returns:
+
+ Notes:
+
+**/
+VOID_PTR MEM_Malloc( UINT size, ACHAR_PTR allocFile, INT allocLine )
+{
+ VOID_PTR mem;
+
+ if ( gMemInited == FALSE )
+ {
+ if ( !MEM_InitDebugStuff( ) )
+ {
+ return NULL;
+ }
+ }
+
+ mem = (VOID_PTR)LocalAlloc( LMEM_FIXED | LMEM_ZEROINIT,
+ size + OVERHEAD_SIZE );
+
+ if ( mem != NULL )
+ {
+ gMemBlocks++;
+ MEM_PrepareMemBlock( mem, size, allocFile, allocLine );
+ MEM_InsertMemBlock( mem );
+
+ gulMemUsed += LocalSize( (HLOCAL)mem );
+ return (VOID_PTR)((MEM_HEADER *)mem + 1);
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+/**/
+/**
+
+ Name: MEM_Calloc()
+
+ Description:
+
+ Modified: 22-Sep-93
+
+ Returns:
+
+ Notes:
+
+**/
+VOID_PTR MEM_Calloc( UINT n, UINT size, ACHAR_PTR allocFile, INT allocLine )
+{
+ return MEM_Malloc( n * size, allocFile, allocLine );
+}
+
+/**/
+/**
+
+ Name: MEM_ReAlloc()
+
+ Description:
+
+ Modified: 22-Sep-93
+
+ Returns:
+
+ Notes:
+
+**/
+VOID_PTR MEM_ReAlloc( VOID_PTR oldMem, UINT newSize, ACHAR_PTR allocFile, INT allocLine )
+{
+ VOID_PTR newMem = NULL;
+
+ if ( oldMem == NULL )
+ {
+ newMem = MEM_Malloc( newSize, allocFile, allocLine );
+ }
+ else if ( newSize == 0UL )
+ {
+ MEM_Free( oldMem, allocFile, allocLine );
+ }
+ else
+ {
+ VOID_PTR oldRealPtr;
+ UINT oldSize;
+
+ oldRealPtr = (VOID_PTR)((MEM_HEADER *)oldMem - 1);
+ oldSize = LocalSize( oldRealPtr );
+ mscassert( oldSize > 0 );
+ oldSize -= OVERHEAD_SIZE;
+
+ if ( oldSize >= newSize )
+ {
+ newMem = oldMem;
+ }
+ else
+ {
+ newMem = MEM_Malloc( newSize, allocFile, allocLine ) ;
+ if ( newMem != NULL )
+ {
+ memcpy( newMem, oldMem, oldSize ) ;
+ MEM_Free( oldMem, allocFile, allocLine );
+ }
+ }
+ }
+ return newMem;
+}
+
+/**/
+/**
+
+ Name: MEM_Free()
+
+ Description:
+
+ Modified: 22-Sep-93
+
+ Returns:
+
+ Notes:
+
+**/
+VOID MEM_Free( VOID_PTR mem, ACHAR_PTR allocFile, INT allocLine )
+{
+ if ( mem != NULL )
+ {
+ /*
+ * User is passing us their pointer -- back up over the
+ * header to get our "real" pointer.
+ */
+
+ gMemBlocks--;
+ mem = (VOID_PTR)((MEM_HEADER *)mem - 1);
+
+ MEM_RemoveMemBlock( mem );
+
+ gulMemUsed -= LocalSize( (HLOCAL)mem );
+ LocalFree( (HLOCAL)mem );
+ }
+}
+
+
+#endif /* MEM_DEBUG */
+
diff --git a/private/utils/ntbackup/src/memver.c b/private/utils/ntbackup/src/memver.c
new file mode 100644
index 000000000..6aa873974
--- /dev/null
+++ b/private/utils/ntbackup/src/memver.c
@@ -0,0 +1,79 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: memver.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+
+ $Log: N:/LOGFILES/MEMVER.C_V $
+
+ Rev 1.3 14 Oct 1993 17:49:46 STEVEN
+fix unicode bugs
+
+ Rev 1.2 18 Jun 1993 10:15:26 MIKEP
+enable c++
+
+ Rev 1.1 01 Oct 1991 11:15:38 BARRY
+Include standard headers.
+
+ Rev 1.0 09 May 1991 13:35:54 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include <string.h>
+
+#include "stdtypes.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+/* $end$ include list */
+
+/**/
+/**
+
+ Name: memver()
+
+ Description: Simple memory compairson routine which specifies
+ the position of the difference ;
+
+ Modified: 8/1/1989
+
+ Returns: SUCCESS if same
+ FAILURE if different.
+
+ Notes: Should be converted to assembly.
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 memver(
+BYTE_PTR buf1 ,
+BYTE_PTR buf2 ,
+UINT16 *size )
+{
+ UINT16 i ;
+ INT16 ret_val = SUCCESS ;
+
+ if ( memcmp( buf1, buf2, *size ) ) {
+
+ for ( i = 0; i < *size; i++ ) {
+
+ if (buf1[i] != buf2[i] ) {
+ ret_val = FAILURE ;
+ *size = i ;
+ break ;
+ }
+ }
+ }
+
+ return ret_val ;
+}
+
+
diff --git a/private/utils/ntbackup/src/menumang.c b/private/utils/ntbackup/src/menumang.c
new file mode 100644
index 000000000..bb50d01fe
--- /dev/null
+++ b/private/utils/ntbackup/src/menumang.c
@@ -0,0 +1,1546 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: menumang.c
+
+ Description: This file contains the functions for the GUI Menu
+ Manager (MM).
+
+ $Log: G:\ui\logfiles\menumang.c_v $
+
+ Rev 1.53 19 Jul 1993 11:11:58 GLENN
+Added sticky file sort and file details support.
+
+ Rev 1.52 25 May 1993 14:02:12 GLENN
+Removed commented sprintf - someone at Microsoft complained.
+
+ Rev 1.51 24 May 1993 15:21:54 BARRY
+Unicode fixes.
+
+ Rev 1.50 18 May 1993 14:49:04 GLENN
+Synchronized tool bar with menu. Fixed show menu status help macro which fixed need for Ready.
+
+ Rev 1.49 06 May 1993 16:04:00 DARRYLP
+Tied Backup/Transfer and Restore/Verify.
+
+ Rev 1.48 27 Apr 1993 19:01:44 GLENN
+Move the VLM change font to the font.c file.
+
+ Rev 1.47 26 Apr 1993 08:45:08 MIKEP
+Add support for telling the vlm that the user may have changed font
+case display for FAT, HPFS, etc.
+
+ Rev 1.46 22 Apr 1993 15:58:48 GLENN
+Added file SORT option support.
+
+ Rev 1.45 21 Apr 1993 16:05:08 GLENN
+Fixed Nostradamus and Cayman menu enabling problems.
+
+ Rev 1.44 09 Apr 1993 15:20:34 GLENN
+Enabling INFO menu item based on ribbon state.
+
+ Rev 1.43 09 Apr 1993 15:03:00 GLENN
+Graying out Net connect, disconnect, font.
+
+ Rev 1.42 08 Apr 1993 11:02:12 DARRYLP
+Removed Print menu graying to allow new functionality to work.
+
+ Rev 1.41 02 Apr 1993 14:12:16 GLENN
+Added display info. Changed to NT help menu style and IDs.
+
+ Rev 1.40 26 Mar 1993 10:39:24 DARRYLP
+The print options are now firmly grayed for the beta.
+
+ Rev 1.39 16 Mar 1993 15:38:38 CARLS
+put back the changes for format tape that were removed by accident
+
+ Rev 1.38 12 Mar 1993 13:53:52 ROBG
+Changed to "Ready" from "" in status bar when nothing is to be done.
+
+ Rev 1.36 03 Mar 1993 16:44:58 ROBG
+Added support to set operation menu selections to ribbon statuses
+for MSOFT_UI.
+
+ Rev 1.35 02 Mar 1993 09:34:36 ROBG
+Placed a "Ready" in status line after showing/hiding a toolbar,
+window refresh on a drive, and showing/hiding the status bar.
+
+ Rev 1.34 22 Feb 1993 13:51:20 ROBG
+Disabled the VIEW split selection if active doc is minimized.
+
+ Rev 1.33 11 Dec 1992 18:22:36 GLENN
+Now handling state of hardware option under NT.
+
+ Rev 1.32 18 Nov 1992 11:38:42 GLENN
+Removed warnings.
+
+ Rev 1.31 01 Nov 1992 16:02:14 DAVEV
+Unicode changes
+
+ Rev 1.30 07 Oct 1992 15:11:18 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.29 04 Oct 1992 19:38:50 DAVEV
+Unicode Awk pass
+
+ Rev 1.28 22 Sep 1992 10:23:28 GLENN
+Removed the WNet calls and headers. They are now in the VLM_UTIL.C file.
+
+ Rev 1.27 10 Sep 1992 17:18:58 GLENN
+Resolved outstanding state issues for toolbar and menubar.
+
+ Rev 1.26 09 Sep 1992 14:39:12 DARRYLP
+Added WFW net functionality - net connect and disconnect.
+
+ Rev 1.25 08 Sep 1992 16:43:00 DARRYLP
+
+ Rev 1.24 20 Aug 1992 09:32:46 GLENN
+Added catalog operation support for NT.
+
+ Rev 1.23 10 Jul 1992 10:27:30 GLENN
+Enabled font selection support NT.
+
+ Rev 1.22 23 Jun 1992 17:59:50 DAVEV
+correctly fixed IDM_VIEWMENU problem this time!
+
+ Rev 1.21 23 Jun 1992 17:34:56 DAVEV
+IDM_VIEWFONT only for OEM_MSOFT
+
+ Rev 1.20 10 Jun 1992 16:15:14 GLENN
+Updated according to NT SPEC.
+
+ Rev 1.19 15 May 1992 13:32:16 MIKEP
+nt pass 2
+
+ Rev 1.18 20 Apr 1992 14:03:46 GLENN
+Changed send to post message when requested to close the app.
+
+ Rev 1.17 15 Apr 1992 16:44:54 GLENN
+Added MM_ShowMenuStatusHelp() call to show status help only for valid menu IDs.
+
+ Rev 1.16 17 Mar 1992 18:26:46 GLENN
+Allowing spaces at the begining of a job name in quick pick.
+
+ Rev 1.15 03 Mar 1992 19:01:02 GLENN
+Added && double ampersand support to quick pick.
+
+ Rev 1.14 25 Feb 1992 21:33:22 GLENN
+Changed close all call.
+
+ Rev 1.13 23 Feb 1992 13:42:50 GLENN
+Fixed exit case.
+
+ Rev 1.12 11 Feb 1992 17:19:08 GLENN
+Enabling view-split for tapes and servers.
+
+ Rev 1.11 10 Feb 1992 09:14:10 GLENN
+Changed Settings - Options to Settings - General.
+
+ Rev 1.10 29 Jan 1992 18:04:32 GLENN
+Grayed out delete sel when no selections exist.
+
+ Rev 1.9 27 Jan 1992 12:45:58 GLENN
+Changed dialog support calls.
+
+ Rev 1.8 22 Jan 1992 12:31:42 GLENN
+Clean-up.
+
+ Rev 1.7 13 Jan 1992 16:50:42 CHUCKB
+Fixed string variables that hold job names.
+
+ Rev 1.6 07 Jan 1992 17:25:26 GLENN
+Added MDI split/slider support
+
+ Rev 1.5 26 Dec 1991 13:46:10 GLENN
+Changed show flags to use CDS calls
+
+ Rev 1.4 12 Dec 1991 17:06:42 DAVEV
+16/32 bit port -2nd pass
+
+ Rev 1.3 10 Dec 1991 13:47:54 GLENN
+Replaced ghWndActiveDoc with WM_GetActiveDoc().
+
+ Rev 1.2 04 Dec 1991 15:21:12 DAVEV
+Modifications for 16/32-bit Windows port - 1st pass.
+
+
+ Rev 1.1 03 Dec 1991 16:24:34 GLENN
+Added code to set limit on jobs in menu to 9. Added VLM_Refresh call.
+
+ Rev 1.0 20 Nov 1991 19:30:40 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+// PRIVATE DEFINITIONS
+
+#define MAX_JOBS_IN_MENU 9
+
+// PRIVATE FUNCTION PROTOTYPES
+
+VOID MM_InitFileMenu ( HMENU, WORD );
+VOID MM_InitTreeMenu ( HMENU, WORD, DWORD );
+VOID MM_InitViewMenu ( HMENU, WORD, DWORD );
+VOID MM_InitOperationsMenu ( HMENU, WORD, WORD );
+VOID MM_InitSelectMenu ( HMENU, WORD, WORD );
+VOID MM_InitJobsMenu ( HMENU, WORD );
+VOID MM_InitSettingsMenu ( HMENU, WORD );
+VOID MM_InitWindowsMenu ( HMENU, WORD );
+
+// FUNCTIONS
+
+/******************************************************************************
+
+ Name: MM_Init()
+
+ Description: This function initializes the menus.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID MM_Init (
+
+HMENU hMenu ) // I - handle of the menu to be initialized
+
+{
+ WORD wStatus;
+ PDS_WMINFO pdsWinInfo;
+ DWORD dwMenuState = 0L;
+ WORD wWinType = 0;
+
+ // Set the status to Enabled if there is active child doc window to
+ // talk to and if there is not an operation going on.
+
+ if ( WM_GetActiveDoc () && ! gfOperation ) {
+
+ wStatus = MF_ENABLED;
+ pdsWinInfo = WM_GetInfoPtr ( WM_GetActiveDoc () );
+ dwMenuState = pdsWinInfo->dwMenuState;
+ if (pdsWinInfo ) {
+ wWinType = pdsWinInfo->wType;
+ if ( ( wWinType == WMTYPE_DISKTREE ) ||
+ ( wWinType == WMTYPE_TAPETREE ) ) {
+
+ dwMenuState = pdsWinInfo->dwMenuState ;
+ }
+ }
+
+ }
+ else {
+ wStatus = MF_GRAYED;
+ }
+
+ MM_InitFileMenu ( hMenu, wStatus );
+ MM_InitTreeMenu ( hMenu, wStatus, dwMenuState );
+ MM_InitViewMenu ( hMenu, wStatus, dwMenuState );
+ MM_InitOperationsMenu ( hMenu, wStatus, wWinType );
+ MM_InitSelectMenu ( hMenu, wStatus, wWinType );
+ MM_InitJobsMenu ( hMenu, wStatus );
+ MM_InitSettingsMenu ( hMenu, wStatus );
+ MM_InitWindowsMenu ( hMenu, wStatus );
+
+
+} /* end MM_Init() */
+
+
+/******************************************************************************
+
+ Name: MM_InitFileMenu()
+
+ Description: This function initializes the File Menu.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID MM_InitFileMenu (
+
+HMENU hMenu, // I - handle of the menu to be initialized
+WORD wStatus ) // I - enabled or disabled status
+
+{
+# if !defined ( OEM_MSOFT )
+ {
+ EnableMenuItem ( hMenu, IDM_FILEEXIT, wStatus );
+ EnableMenuItem ( hMenu, IDM_FILESETUP, wStatus );
+
+ if ( ( WM_GetActiveDoc () != ghWndLogFiles ) &&
+ ( WM_GetActiveDoc () != ghWndLogFileView ) ) {
+
+ wStatus = MF_GRAYED;
+ }
+
+ EnableMenuItem ( hMenu, IDM_FILEPRINT, wStatus );
+ }
+# endif
+
+} /* end MM_InitFileMenu() */
+
+
+/******************************************************************************
+
+ Name: MM_InitTreeMenu()
+
+ Description: This function initializes the Tree Menu.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID MM_InitTreeMenu (
+
+HMENU hMenu, // I - handle of the menu to be initialized
+WORD wStatus, // I - enabled or disabled status
+DWORD dwMenuState ) // I - MDI Document menu state bit mask
+
+{
+ // Gray out the entire menu if the active doc window does not support it
+ // or if the active doc is minimized.
+
+ if ( wStatus != MF_GRAYED &&
+ ( IsIconic ( WM_GetActiveDoc () ) || ! MM_HasTreeMenu ( dwMenuState ) ) ) {
+
+ wStatus = MF_GRAYED;
+ }
+
+ EnableMenuItem ( hMenu, IDM_TREEEXPANDONE, wStatus );
+ EnableMenuItem ( hMenu, IDM_TREEEXPANDBRANCH, wStatus );
+ EnableMenuItem ( hMenu, IDM_TREEEXPANDALL, wStatus );
+ EnableMenuItem ( hMenu, IDM_TREECOLLAPSEBRANCH, wStatus );
+
+
+} /* end MM_InitTreeMenu() */
+
+
+/******************************************************************************
+
+ Name: MM_InitViewMenu()
+
+ Description: This function initializes the View Menu.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID MM_InitViewMenu (
+
+HMENU hMenu, // I - handle of the menu to be initialized
+WORD wStatus, // I - enabled or disabled status
+DWORD dwMenuState ) // I - MDI Document menu state bit mask
+
+{
+ PDS_WMINFO info_ptr ;
+
+ WORD wPassedStatus = wStatus;
+ WORD wType ;
+
+ info_ptr = WM_GetInfoPtr ( WM_GetActiveDoc () ) ;
+
+ if (!info_ptr) return ;
+
+ wType = WMDS_GetWinType ( info_ptr ) ;
+
+ // Uncheck all the View Menu Items.
+
+ CheckMenuItem ( hMenu, IDM_VIEWTREEANDDIR, MF_UNCHECKED );
+ CheckMenuItem ( hMenu, IDM_VIEWTREEONLY, MF_UNCHECKED );
+ CheckMenuItem ( hMenu, IDM_VIEWDIRONLY, MF_UNCHECKED );
+ CheckMenuItem ( hMenu, IDM_VIEWALLFILEDETAILS, MF_UNCHECKED );
+
+# ifndef OEM_MSOFT
+ {
+ CheckMenuItem ( hMenu, IDM_VIEWSORTNAME, MF_UNCHECKED );
+ CheckMenuItem ( hMenu, IDM_VIEWSORTTYPE, MF_UNCHECKED );
+ CheckMenuItem ( hMenu, IDM_VIEWSORTSIZE, MF_UNCHECKED );
+ CheckMenuItem ( hMenu, IDM_VIEWSORTDATE, MF_UNCHECKED );
+ }
+# endif
+
+# if defined ( OEM_MSOFT ) // new function
+ {
+ CDS_PTR pPermCDS = CDS_GetPerm () ;
+ UINT fSet;
+
+ fSet = ( CDS_GetShowStatusLine( pPermCDS ) == CDS_ENABLE )
+ ? MF_CHECKED : MF_UNCHECKED ;
+ CheckMenuItem ( hMenu, IDM_VIEWSTATUS, fSet );
+
+ fSet = ( CDS_GetShowMainRibbon( pPermCDS ) == CDS_ENABLE )
+ ? MF_CHECKED : MF_UNCHECKED ;
+ CheckMenuItem ( hMenu, IDM_VIEWURIBBON, fSet );
+
+ }
+# endif // defined ( OEM_MSOFT ) // new function
+
+ EnableMenuItem ( hMenu, IDM_VIEWFONT, wStatus );
+
+ // Gray out the entire menu if the active window does not support it.
+
+ if ( ! MM_HasViewMenu ( dwMenuState ) ) {
+
+ wStatus = MF_GRAYED;
+ }
+ else {
+
+ // Check the only one per group, if the menu is enabled.
+
+ // Do the TREE group.
+
+ if ( dwMenuState & MMDOC_TREEANDDIR ) {
+
+ CheckMenuItem ( hMenu, IDM_VIEWTREEANDDIR, MF_CHECKED );
+ }
+ else if ( dwMenuState & MMDOC_TREEONLY ) {
+
+ CheckMenuItem ( hMenu, IDM_VIEWTREEONLY, MF_CHECKED );
+ }
+ else if ( dwMenuState & MMDOC_DIRONLY ) {
+
+ CheckMenuItem ( hMenu, IDM_VIEWDIRONLY, MF_CHECKED );
+ }
+
+ // Do the FILE group.
+
+ CheckMenuItem ( hMenu, IDM_VIEWALLFILEDETAILS,
+ ( dwMenuState & MMDOC_FILEDETAILS ) ? MF_CHECKED : MF_UNCHECKED );
+
+# ifndef OEM_MSOFT
+ {
+ // Ok, now the SORT group.
+
+ if ( dwMenuState & MMDOC_SORTNAME ) {
+
+ CheckMenuItem ( hMenu, IDM_VIEWSORTNAME, MF_CHECKED );
+ }
+ else if ( dwMenuState & MMDOC_SORTTYPE ) {
+
+ CheckMenuItem ( hMenu, IDM_VIEWSORTTYPE, MF_CHECKED );
+ }
+ else if ( dwMenuState & MMDOC_SORTSIZE ) {
+
+ CheckMenuItem ( hMenu, IDM_VIEWSORTSIZE, MF_CHECKED );
+ }
+ else if ( dwMenuState & MMDOC_SORTDATE ) {
+
+ CheckMenuItem ( hMenu, IDM_VIEWSORTDATE, MF_CHECKED );
+ }
+ }
+# endif
+
+ }
+
+ // If the doc is minimized, gray out the tree/dir stuff.
+
+ if ( wStatus != MF_GRAYED && IsIconic ( WM_GetActiveDoc () ) ) {
+ wStatus = MF_GRAYED;
+ }
+
+ EnableMenuItem ( hMenu, IDM_VIEWTREEANDDIR, wStatus );
+ EnableMenuItem ( hMenu, IDM_VIEWTREEONLY, wStatus );
+ EnableMenuItem ( hMenu, IDM_VIEWDIRONLY, wStatus );
+ EnableMenuItem ( hMenu, IDM_VIEWALLFILEDETAILS, wStatus );
+
+# ifndef OEM_MSOFT
+ {
+ EnableMenuItem ( hMenu, IDM_VIEWSORTNAME, wStatus );
+ EnableMenuItem ( hMenu, IDM_VIEWSORTTYPE, wStatus );
+ EnableMenuItem ( hMenu, IDM_VIEWSORTSIZE, wStatus );
+ EnableMenuItem ( hMenu, IDM_VIEWSORTDATE, wStatus );
+ }
+# endif
+
+ // Determine the way to display the split menu item.
+
+ if ( ( wPassedStatus == MF_ENABLED ) &&
+ ( !IsIconic ( WM_GetActiveDoc () ) ) &&
+ ( wType == WMTYPE_TAPES || wType == WMTYPE_DISKTREE ||
+ wType == WMTYPE_TAPETREE || wType == WMTYPE_SERVERS
+#ifdef OEM_EMS
+ || wType == WMTYPE_EXCHANGE
+#endif
+ ) ) {
+
+ wStatus = MF_ENABLED;
+ }
+ else {
+ wStatus = MF_GRAYED;
+ }
+
+ EnableMenuItem ( hMenu, IDM_VIEWSPLIT, wStatus );
+
+} /* end MM_InitViewMenu() */
+
+
+/******************************************************************************
+
+ Name: MM_InitOperationsMenu()
+
+ Description: This function initializes the Operations Menu.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+#ifdef FS_EMS
+extern HINSTANCE JetApi ;
+#endif
+
+VOID MM_InitOperationsMenu (
+
+HMENU hMenu, // I - handle of the menu to be initialized
+WORD wStatus, // I - enabled or disabled status
+WORD wType ) // I - window type
+
+
+{
+ WORD wTempStatus;
+ WORD wTapeStatus;
+ WORD wTapeFmtStatus;
+
+ // Set the temp status based on the currently active window.
+
+ if ( wType == WMTYPE_DISKS || wType == WMTYPE_DISKTREE || wType == WMTYPE_SERVERS ||
+ wType == WMTYPE_TAPES || wType == WMTYPE_TAPETREE || wType == WMTYPE_SEARCH
+#ifdef OEM_EMS
+ || wType == WMTYPE_EXCHANGE
+#endif
+ ) {
+
+ wTempStatus = wStatus;
+ }
+ else {
+ wTempStatus = MF_GRAYED;
+ }
+
+ wTapeStatus = ( MUI_IsTapeInDrive () ) ? wTempStatus : (WORD)MF_GRAYED;
+ wTapeFmtStatus = ( MUI_IsTapeInDrive () ) ? MF_ENABLED : (WORD)MF_GRAYED;
+
+ // OK, so maybe we could use the ribbon states. But,
+ // a better way is to use a state table - maybe we will do this
+ // when we use C++. Sure we will. The problem with doing it this
+ // way is, what happens when we yank something out of the ribbon?
+ // What do we do then?
+
+ EnableMenuItem ( hMenu,
+ IDM_OPERATIONSBACKUP,
+ ( ( RIB_IsItemEnabled ( ghRibbonMain, IDM_OPERATIONSBACKUP ) ) ? MF_ENABLED : MF_GRAYED )
+ );
+
+ EnableMenuItem ( hMenu,
+ IDM_OPERATIONSRESTORE,
+ ( ( RIB_IsItemEnabled ( ghRibbonMain, IDM_OPERATIONSRESTORE ) ) ? MF_ENABLED : MF_GRAYED )
+ );
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+ {
+ EnableMenuItem ( hMenu,
+ IDM_OPERATIONSTRANSFER,
+ ( ( RIB_IsItemEnabled ( ghRibbonMain, IDM_OPERATIONSBACKUP ) ) ? MF_ENABLED : MF_GRAYED )
+ );
+
+ EnableMenuItem ( hMenu,
+ IDM_OPERATIONSINFO,
+ ( ( RIB_IsItemEnabled ( ghRibbonMain, IDM_OPERATIONSINFO ) ) ? MF_ENABLED : MF_GRAYED )
+ );
+
+ EnableMenuItem ( hMenu,
+ IDM_OPERATIONSVERIFY,
+ ( ( RIB_IsItemEnabled ( ghRibbonMain, IDM_OPERATIONSRESTORE ) ) ? MF_ENABLED : MF_GRAYED )
+ );
+
+ EnableMenuItem ( hMenu,
+ IDM_OPERATIONSCATALOG,
+ ( ( RIB_IsItemEnabled ( ghRibbonMain, IDM_OPERATIONSCATALOG ) ) ? MF_ENABLED : MF_GRAYED )
+ );
+
+ // Catalog file dependent menu items.
+
+ EnableMenuItem ( hMenu,
+ IDM_OPERATIONSSEARCH,
+ ( ( RIB_IsItemEnabled ( ghRibbonMain, IDM_OPERATIONSSEARCH ) ) ? MF_ENABLED : MF_GRAYED )
+ );
+
+ EnableMenuItem ( hMenu, IDM_OPERATIONSCATMAINT, ( QTC_AnyCatalogFiles () ) ? wTempStatus : MF_GRAYED );
+
+ // Special tape-in-drive dependent menu items.
+
+ EnableMenuItem ( hMenu,
+ IDM_OPERATIONSEJECT,
+ ( ( RIB_IsItemEnabled ( ghRibbonMain, IDM_OPERATIONSEJECT ) ) ? MF_ENABLED : MF_GRAYED )
+ );
+
+ EnableMenuItem ( hMenu,
+ IDM_OPERATIONSERASE,
+ ( ( RIB_IsItemEnabled ( ghRibbonMain, IDM_OPERATIONSERASE ) ) ? MF_ENABLED : MF_GRAYED )
+ );
+
+ EnableMenuItem ( hMenu,
+ IDM_OPERATIONSRETENSION,
+ ( ( RIB_IsItemEnabled ( ghRibbonMain, IDM_OPERATIONSRETENSION ) ) ? MF_ENABLED : MF_GRAYED )
+ );
+
+ EnableMenuItem ( hMenu,
+ IDM_OPERATIONSCONNECT,
+ ( ( RIB_IsItemEnabled ( ghRibbonMain, IDM_OPERATIONSCONNECT ) ) ? MF_ENABLED : MF_GRAYED )
+ );
+
+ EnableMenuItem ( hMenu,
+ IDM_OPERATIONSDISCON,
+ ( ( RIB_IsItemEnabled ( ghRibbonMain, IDM_OPERATIONSDISCON ) ) ? MF_ENABLED : MF_GRAYED )
+ );
+ }
+# endif // !defined ( OEM_MSOFT ) // unsupported feature
+
+# if defined ( OS_WIN32 )
+ {
+ if ( thw_list && gfHWInitialized && ( thw_list->drv_info.drv_features & TDI_FORMAT ) ) {
+ EnableMenuItem ( hMenu, IDM_OPERATIONSFORMAT, wTapeFmtStatus );
+ }
+ else {
+ EnableMenuItem ( hMenu, IDM_OPERATIONSFORMAT, (WORD)MF_GRAYED );
+ }
+ }
+# endif // defined ( OS_WIN32 )
+
+# if defined ( OEM_MSOFT ) // Use the ribbon states.
+ {
+ EnableMenuItem ( hMenu, IDM_OPERATIONSHARDWARE, wStatus );
+
+ /******************************************************************
+
+ For Microsoft's product, the menu is set to the status of the
+ ribbon buttons.
+
+ The menu selections are made to reflect the ribbon button statuses
+
+ IDM_OPERATIONSCATALOG Catalog button
+ IDM_OPERATIONSRETENSION Retension button
+ IDM_OPERATIONSEJECT Eject button
+ IDM_OPERATIONSERASE Erase button
+
+ ******************************************************************/
+
+ EnableMenuItem ( hMenu,
+ IDM_OPERATIONSCATALOG,
+ ( ( RIB_IsItemEnabled ( ghRibbonMain, IDM_OPERATIONSCATALOG ) ) ? MF_ENABLED : MF_GRAYED )
+ );
+
+ EnableMenuItem ( hMenu,
+ IDM_OPERATIONSRETENSION,
+ ( ( RIB_IsItemEnabled ( ghRibbonMain, IDM_OPERATIONSRETENSION ) ) ? MF_ENABLED : MF_GRAYED )
+ );
+
+ EnableMenuItem ( hMenu,
+ IDM_OPERATIONSEJECT,
+ ( ( RIB_IsItemEnabled ( ghRibbonMain, IDM_OPERATIONSEJECT ) ) ? MF_ENABLED : MF_GRAYED )
+ );
+
+ EnableMenuItem ( hMenu,
+ IDM_OPERATIONSERASE,
+ ( ( RIB_IsItemEnabled ( ghRibbonMain, IDM_OPERATIONSERASE ) ) ? MF_ENABLED : MF_GRAYED )
+ );
+
+ EnableMenuItem ( hMenu, IDM_OPERATIONSEXIT, wStatus );
+
+# ifdef FS_EMS
+ if ( !JetApi ) {
+ JetApi = LoadLibrary( TEXT("edbbcli.dll")) ;
+ }
+
+ EnableMenuItem ( hMenu, IDM_OPERATIONSEXCHANGE, (WORD)MF_GRAYED );
+
+ if ( JetApi ) {
+ static first_time = TRUE ;
+ if (first_time ) {
+ InsertMenu ( hMenu,
+ IDM_OPERATIONSEXCHANGE,
+ MF_BYCOMMAND | MF_SEPARATOR | wStatus,
+ 0,
+ (LPSTR)NULL
+ );
+ first_time = FALSE ;
+ }
+
+ EnableMenuItem ( hMenu, IDM_OPERATIONSEXCHANGE, wStatus );
+ } else {
+ static first_time = TRUE ;
+ if (first_time ) {
+ RemoveMenu( hMenu, IDM_OPERATIONSEXCHANGE, MF_BYCOMMAND) ;
+ first_time = FALSE ;
+ }
+ }
+
+# endif
+ }
+
+# endif
+
+} /* end MM_InitOperationsMenu() */
+
+
+/******************************************************************************
+
+ Name: MM_InitSelectMenu()
+
+ Description: This function initializes the Select Menu.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID MM_InitSelectMenu (
+
+HMENU hMenu, // I - handle of the menu to be initialized
+WORD wStatus, // I - enabled or disabled status
+WORD wType ) // I - window type
+
+{
+ WORD wTempStatus = wStatus;
+
+# if !defined ( OEM_MSOFT )
+ {
+ // Check or Uncheck the STATUS LINE, MAIN RIBBON, etc... menu items.
+
+ CheckMenuItem ( hMenu, IDM_SELECTSUBDIRS,
+ ( CDS_GetIncludeSubdirs ( CDS_GetPerm () ) ) ? MF_CHECKED : MF_UNCHECKED );
+ }
+# endif // !defined ( OEM_MSOFT )
+
+ if ( ! ( wType == WMTYPE_DISKS || wType == WMTYPE_DISKTREE || wType == WMTYPE_SERVERS ||
+ wType == WMTYPE_TAPES || wType == WMTYPE_TAPETREE || wType == WMTYPE_SEARCH
+#ifdef OEM_EMS
+ || wType == WMTYPE_EXCHANGE
+#endif
+ ) ) {
+
+ wTempStatus = MF_GRAYED;
+ }
+
+ EnableMenuItem ( hMenu, IDM_SELECTCHECK, wTempStatus );
+ EnableMenuItem ( hMenu, IDM_SELECTUNCHECK, wTempStatus );
+
+# if !defined ( OEM_MSOFT )
+ {
+ EnableMenuItem ( hMenu, IDM_SELECTADVANCED, ( wType != WMTYPE_SEARCH ) ? wTempStatus : MF_GRAYED );
+ EnableMenuItem ( hMenu, IDM_SELECTSUBDIRS, ( wType != WMTYPE_SEARCH ) ? wTempStatus : MF_GRAYED );
+ EnableMenuItem ( hMenu, IDM_SELECTCLEAR, wTempStatus );
+
+ EnableMenuItem ( hMenu, IDM_SELECTSAVE, ( VLM_AnyDiskSelections () ) ? wStatus : MF_GRAYED );
+ EnableMenuItem ( hMenu, IDM_SELECTUSE, ( VLM_AnySelFiles () ) ? wStatus : MF_GRAYED );
+ EnableMenuItem ( hMenu, IDM_SELECTDELETE, ( VLM_AnySelFiles () ) ? wStatus : MF_GRAYED );
+
+ }
+# endif // !defined ( OEM_MSOFT )
+
+} /* end MM_InitSelectMenu() */
+
+
+/******************************************************************************
+
+ Name: MM_InitJobsMenu()
+
+ Description: This function initializes the Job Menu.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID MM_InitJobsMenu (
+
+HMENU hMenu, // I - handle of the menu to be initialized
+WORD wStatus ) // I - enabled or disabled status
+
+{
+# if !defined ( OEM_MSOFT ) // unsupported feature
+ {
+ BOOL fJobFiles = ( JOB_GetNextJob ( (JOBREC_PTR)NULL ) ) ? TRUE : FALSE;
+ BOOL fDone = FALSE;
+
+ EnableMenuItem ( hMenu, IDM_JOBMAINTENANCE, wStatus );
+
+ // Use the Jobs Menu GLOBAL handle for deleting and appending
+ // from/to this menu. First, delete any old job entries in the menu
+ // regardless of whether or not any jobs exist at this time.
+
+ // Delete the old job list, since it could have changed.
+
+ do {
+ fDone = ! DeleteMenu ( ghMenuJobs, JOBSMENUSEPARATORPOS, MF_BYPOSITION );
+
+ } while ( ! fDone );
+
+ // If there are any job files, append them to the menu as menu items.
+
+ if ( fJobFiles ) {
+
+ JOBREC_PTR pJobItem = (JOBREC_PTR)NULL;
+ CHAR szJobName[MAX_JOBNAME_LEN * 2];
+ WORD wIndex = 0;
+ LPSTR pSrc;
+ LPSTR pDest;
+
+ // Insert the separator.
+
+ InsertMenu ( ghMenuJobs,
+ (UINT)-1,
+ MF_BYPOSITION | MF_SEPARATOR | wStatus,
+ 0,
+ (LPSTR)NULL
+ );
+
+ // Loop for appending job names to the Jobs menu.
+
+ while ( pJobItem = JOB_GetNextJob ( pJobItem ) ) {
+
+ wIndex++;
+
+ if ( wIndex > MAX_JOBS_IN_MENU ) {
+
+ RSM_StringCopy ( IDS_JOBMOREJOBS, szJobName, MAX_JOBNAME_LEN );
+
+ szJobName[MAX_JOBNAME_LEN] = TEXT('\0');
+
+ InsertMenu ( ghMenuJobs,
+ (UINT)-1,
+ MF_BYPOSITION | MF_STRING | wStatus,
+ IDM_JOBSFIRSTJOB + wIndex,
+ szJobName
+ );
+
+ break;
+ }
+
+ // Prefix the job name with a job reference number by
+ // copying the index into the begining of the menu item
+ // string. Then, get the next job name and append it
+ // to the menu item string.
+
+ wsprintf ( szJobName, TEXT("&%u "), wIndex );
+
+ pDest = szJobName + strlen ( szJobName );
+
+ pSrc = JOB_GetJobName ( pJobItem );
+
+ while ( *pSrc != TEXT('\0') ) {
+
+ // Replace & with && to prevent problem with underscores
+ // being in the job name.
+
+ if ( *pSrc == TEXT('&') ) {
+ *pDest++ = TEXT('&');
+ }
+
+ *pDest++ = *pSrc++;
+ }
+
+ *pDest++ = *pSrc++;
+
+ // Insert the menu item at the end of the menu by position
+ // as a string with the status that is passed to this
+ // function, if there is a valid job.
+
+ InsertMenu ( ghMenuJobs,
+ (UINT)-1,
+ MF_BYPOSITION | MF_STRING | wStatus,
+ IDM_JOBSFIRSTJOB + wIndex,
+ szJobName
+ );
+
+ }
+ }
+
+ }
+# endif // !defined ( OEM_MSOFT ) // unsupported feature
+
+} /* end MM_InitJobsMenu() */
+
+
+/******************************************************************************
+
+ Name: MM_InitSettingsMenu()
+
+ Description: This function initializes the Settings Menu.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID MM_InitSettingsMenu (
+
+HMENU hMenu, // I - handle of the menu to be initialized
+WORD wStatus ) // I - enabled or disabled status
+
+{
+# if !defined ( OEM_MSOFT ) // unsupported feature
+ {
+ EnableMenuItem ( hMenu, IDM_SETTINGSGENERAL, wStatus );
+ EnableMenuItem ( hMenu, IDM_SETTINGSBACKUP, wStatus );
+ EnableMenuItem ( hMenu, IDM_SETTINGSRESTORE, wStatus );
+ EnableMenuItem ( hMenu, IDM_SETTINGSLOGGING, wStatus );
+ EnableMenuItem ( hMenu, IDM_SETTINGSNETWORK, wStatus );
+ EnableMenuItem ( hMenu, IDM_SETTINGSCATALOG, wStatus );
+ EnableMenuItem ( hMenu, IDM_SETTINGSHARDWARE, wStatus );
+ EnableMenuItem ( hMenu, IDM_SETTINGSDEBUGWINDOW, wStatus );
+
+ }
+# endif // !defined ( OEM_MSOFT ) // unsupported feature
+
+} /* end MM_InitSettingsMenu() */
+
+
+/******************************************************************************
+
+ Name: MM_InitWindowsMenu()
+
+ Description: This function initializes the Window Menu.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID MM_InitWindowsMenu (
+
+HMENU hMenu, // I - handle of the menu to be initialized
+WORD wStatus ) // I - enabled or disabled status
+
+{
+ // The following menu items are enabled if there is an active window.
+
+ EnableMenuItem ( hMenu, IDM_WINDOWSTILE, wStatus );
+ EnableMenuItem ( hMenu, IDM_WINDOWSCASCADE, wStatus );
+ EnableMenuItem ( hMenu, IDM_WINDOWSREFRESH, wStatus );
+ EnableMenuItem ( hMenu, IDM_WINDOWSCLOSEALL, wStatus );
+ EnableMenuItem ( hMenu, IDM_WINDOWSARRANGEICONS, wStatus );
+
+} /* end MM_InitWindowsMenu() */
+
+
+/******************************************************************************
+
+ Name: MM_GetJobNameFromMenu()
+
+ Description: This function extracts a filename from a menu item's text.
+
+ Returns: A pointer to the filename string.
+
+******************************************************************************/
+
+LPSTR MM_GetJobNameFromMenu (
+
+WORD wJobMenuID, // I - menu ID of the job name
+LPSTR pszJobName ) // I - pointer to the job name string
+
+{
+ CHAR szTemp[MAX_JOBNAME_LEN * 2];
+ CHAR_PTR pSrc = szTemp;
+ LPSTR pDest = pszJobName;
+
+ // Determine the job name.
+
+ GetMenuString ( GetMenu ( ghWndFrame ),
+ wJobMenuID,
+ szTemp,
+ sizeof ( szTemp ),
+ MF_BYCOMMAND
+ );
+
+ // Bump the pointer past the prefix number and the space(s).
+
+ for ( ; *pSrc != TEXT(' '); pSrc ++ ); // point past number
+
+ pSrc++; // point past the space.
+
+// for ( ; *pSrc == ' '; pSrc ++ ); // point past space(s)
+
+ // Now, remove any double && that we put in (underscore char).
+
+ while ( *pSrc != TEXT('\0') ) {
+
+ if ( *pSrc == TEXT('&') ) {
+
+ pSrc++;
+ }
+
+ *pDest++ = *pSrc++;
+ }
+
+ *pDest = *pSrc;
+
+ return pszJobName;
+
+} /* end MM_GetJobNameFromMenu() */
+
+
+/******************************************************************************
+
+ Name: MM_MenuCmdHandler()
+
+ Description: This handles menu commands.
+
+ Returns: TRUE, if it was a menu command, otherwise FALSE.
+
+******************************************************************************/
+
+BOOL MM_MenuCmdHandler (
+
+HWND hWnd,
+WORD wID ) // ID of control which generated the WM_COMMAND
+
+{
+ BOOL fCmdProcessed = TRUE;
+ WORD wDialogID = 0xFFFF;
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+ {
+
+ // JOB MENU SELECTIONS:
+
+ if ( ( wID >= IDM_JOBSFIRSTJOB ) && ( wID <= IDM_JOBSLASTJOB ) ) {
+
+ CHAR szJobName[MAX_JOBNAME_LEN + 5];
+
+ MM_GetJobNameFromMenu ( wID, szJobName );
+
+ if ( wID <= ( IDM_JOBSFIRSTJOB + MAX_JOBS_IN_MENU ) ) {
+
+ JOB_StartJob ( szJobName, JOB_NOTSCHEDULED );
+ }
+ else {
+
+ DM_ShowDialog ( ghWndFrame, IDD_JOBMAINTENANCE, (PVOID)0 );
+ }
+
+ return fCmdProcessed;
+ }
+
+ }
+# endif // !defined ( OEM_MSOFT ) // unsupported feature
+
+ switch ( wID ) {
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+
+ // FILE MENU COMMANDS
+
+ case IDM_FILEPRINT:
+
+ PM_FilePrint ();
+ break;
+
+ case IDM_FILESETUP:
+
+ PM_FileSetup ();
+ break;
+
+# endif // !defined ( OEM_MSOFT ) // unsupported feature
+
+
+# if defined ( OEM_MSOFT ) // alternate feature
+
+ case IDM_OPERATIONSEXIT:
+
+# else // !defined ( OEM_MSOFT ) // standard feature
+
+ case IDM_FILEEXIT:
+
+# endif // else !defined ( OEM_MSOFT ) // alternate/standard feature
+
+
+ if ( ! gfOperation ) {
+ PostMessage ( ghWndFrame, WM_CLOSE, (MP1)NULL, (MP2)NULL );
+ }
+
+ break;
+
+
+ // TREE MENU COMMANDS
+
+ case IDM_TREEEXPANDONE:
+ case IDM_TREEEXPANDBRANCH:
+ case IDM_TREEEXPANDALL:
+ case IDM_TREECOLLAPSEBRANCH:
+
+ VLM_ChangeSettings ( wID, 0L );
+ break;
+
+ // VIEW MENU COMMANDS
+
+ case IDM_VIEWTREEANDDIR:
+ case IDM_VIEWTREEONLY:
+ case IDM_VIEWDIRONLY:
+ case IDM_VIEWALLFILEDETAILS: {
+
+ WORD wChangeMsg = WM_DocIsMenuChange ( WM_GetActiveDoc (), wID );
+
+ if ( wChangeMsg ) {
+
+ if ( wID == IDM_VIEWALLFILEDETAILS ) {
+
+ BOOL fFileDetails = ( wChangeMsg == ID_FILEDETAILS ) ? TRUE : FALSE;
+
+ CDS_SetFileDetails ( CDS_GetPerm (), fFileDetails );
+ CDS_WriteFileDetails ( CDS_GetPerm () );
+ }
+
+ VLM_ChangeSettings ( wChangeMsg, 0L );
+ }
+
+ break;
+ }
+
+# ifndef OEM_MSOFT
+ {
+ // VIEW MENU SORT COMMANDS
+
+ case IDM_VIEWSORTNAME:
+ case IDM_VIEWSORTTYPE:
+ case IDM_VIEWSORTSIZE:
+ case IDM_VIEWSORTDATE: {
+
+ WORD wChangeMsg = WM_DocIsMenuChange ( WM_GetActiveDoc (), wID );
+
+ if ( wChangeMsg ) {
+
+ CDS_SetSortOptions ( CDS_GetPerm (), wChangeMsg );
+ CDS_WriteSortOptions ( CDS_GetPerm () );
+ VLM_ChangeSettings ( wChangeMsg, 0L );
+ }
+
+ break;
+ }
+ }
+# endif
+
+ case IDM_VIEWSPLIT:
+
+ WM_DocSetSliderMode ( WM_GetActiveDoc (), WMDOC_SLIDERON );
+ break;
+
+# if defined ( OEM_MSOFT ) // new feature
+
+ case IDM_VIEWSTATUS: // Toggle the view/hide status bar state
+ {
+ CDS_PTR pPermCDS = CDS_GetPerm () ;
+ UINT uSet = ( CDS_GetShowStatusLine( pPermCDS ) == CDS_ENABLE )
+ ? CDS_DISABLE : CDS_ENABLE ;
+
+ CDS_SetShowStatusLine( pPermCDS, uSet ) ;
+ CDS_WriteShowStatusLine( pPermCDS ) ;
+ WM_FrameUpdate ();
+ }
+
+ STM_SetIdleText( IDS_READY ) ; //**ROB
+ break;
+
+
+ case IDM_VIEWURIBBON: // Toggle the view/hide ribbon state
+ {
+ CDS_PTR pPermCDS = CDS_GetPerm () ;
+ UINT uSet = ( CDS_GetShowMainRibbon( pPermCDS ) == CDS_ENABLE )
+ ? CDS_DISABLE : CDS_ENABLE ;
+
+ CDS_SetShowMainRibbon( pPermCDS, uSet );
+ CDS_WriteShowMainRibbon( pPermCDS ) ;
+ WM_FrameUpdate ();
+ }
+
+ STM_SetIdleText( IDS_READY ) ; //**ROB
+ break;
+
+# endif //defined ( OEM_MSOFT ) // new feature
+
+ case IDM_VIEWFONT: // Put up the common Font Dialog.
+
+ WM_ChangeFont ();
+
+ break;
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+
+ // SELECT MENU COMMANDS
+
+ case IDM_SELECTSUBDIRS:
+
+ CDS_SetIncludeSubdirs ( CDS_GetPerm(), ! CDS_GetIncludeSubdirs ( CDS_GetPerm () ) );
+ break;
+
+ case IDM_SELECTCLEAR:
+
+ VLM_ClearAllSelections ();
+ break;
+
+# endif // !defined ( OEM_MSOFT ) // unsupported feature
+
+ case IDM_SELECTCHECK:
+ case IDM_SELECTUNCHECK:
+
+ VLM_ChangeSettings ( wID, 0L );
+ break;
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+
+ case IDM_SELECTADVANCED:
+
+ MUI_AdvancedSelections ();
+ break;
+
+# endif // !defined ( OEM_MSOFT ) // unsupported feature
+
+ // WINDOW MENU COMMANDS
+
+ case IDM_WINDOWSTILE:
+
+ // Tile MDI windows.
+ SendMessage ( ghWndMDIClient, WM_MDITILE, 0, 0L );
+ break;
+
+ case IDM_WINDOWSCASCADE:
+
+ // Cascade MDI windows.
+ SendMessage ( ghWndMDIClient, WM_MDICASCADE, 0, 0L );
+ break;
+
+ case IDM_WINDOWSREFRESH:
+
+ VLM_Refresh ( );
+ STM_SetIdleText( IDS_READY ) ; //**ROB
+ break;
+
+ case IDM_WINDOWSCLOSEALL:
+
+ WM_SetDocSizes ();
+ WM_MinimizeDocs ();
+ break;
+
+ case IDM_WINDOWSARRANGEICONS:
+
+ // Arrange all ICONS in the window.
+ SendMessage( ghWndMDIClient, WM_MDIICONARRANGE, 0, 0L);
+ break;
+
+
+ // OPERATIONS MENU SELECTIONS
+
+ case IDM_OPERATIONSBACKUP:
+ case IDM_OPERATIONSRESTORE:
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+
+ case IDM_OPERATIONSTRANSFER:
+ case IDM_OPERATIONSVERIFY:
+
+# endif // !defined ( OEM_MSOFT ) // unsupported feature
+
+ case IDM_OPERATIONSCATALOG:
+
+ MUI_StartOperation ( wID, TRUE );
+
+ break;
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+
+ case IDM_OPERATIONSINFO:
+ case IDM_OPERATIONSDISCON:
+ case IDM_OPERATIONSCONNECT:
+ case IDM_OPERATIONSCATMAINT:
+ case IDM_OPERATIONSSEARCH:
+
+# endif // !defined ( OEM_MSOFT ) // unsupported feature
+
+ case IDM_OPERATIONSEJECT:
+ case IDM_OPERATIONSERASE:
+ case IDM_OPERATIONSRETENSION:
+
+#ifdef OS_WIN32
+ case IDM_OPERATIONSFORMAT:
+#endif // OS_WIN32
+
+#ifdef OEM_EMS
+ case IDM_OPERATIONSEXCHANGE:
+#endif // OEM_EMS
+
+ MUI_StartOperation ( wID, TRUE );
+
+ break;
+
+ // HELP MENU SELECTIONS
+
+ case IDM_HELPINDEX:
+ case IDM_HELPSEARCH:
+ case IDM_HELPUSINGHELP:
+
+ HM_MenuCommands ( hWnd, wID );
+ break;
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+
+ // MENU ITEMS THAT CALL DIALOGS.
+
+ case IDM_SELECTSAVE:
+ wDialogID = IDD_SELECTSAVE;
+ break;
+
+ case IDM_SELECTUSE:
+ wDialogID = IDD_SELECTUSE;
+ break;
+
+ case IDM_SELECTDELETE:
+ wDialogID = IDD_SELECTDELETE;
+ break;
+
+ case IDM_JOBMAINTENANCE:
+ wDialogID = IDD_JOBMAINTENANCE;
+ break;
+
+ case IDM_SETTINGSGENERAL:
+ wDialogID = IDD_SETTINGSOPTIONS;
+ break;
+
+ case IDM_SETTINGSBACKUP:
+ wDialogID = IDD_SETTINGSBACKUP;
+ break;
+
+ case IDM_SETTINGSRESTORE:
+ wDialogID = IDD_SETTINGSRESTORE;
+ break;
+
+ case IDM_SETTINGSLOGGING:
+ wDialogID = IDD_SETTINGSLOGGING;
+ break;
+
+ case IDM_SETTINGSNETWORK:
+ wDialogID = IDD_SETTINGSNETWORK;
+ break;
+
+ case IDM_SETTINGSCATALOG:
+ wDialogID = IDD_SETTINGSCATALOG;
+ break;
+
+ case IDM_SETTINGSHARDWARE:
+ wDialogID = IDD_SETTINGSHARDWARE;
+ break;
+
+ case IDM_SETTINGSDEBUGWINDOW:
+ wDialogID = IDD_SETTINGSDEBUGWINDOW;
+ break;
+
+# else // defined ( OEM_MSOFT ) // alternate feature
+
+ case IDM_OPERATIONSHARDWARE:
+ wDialogID = IDD_SETTINGSHARDWARE;
+ break;
+
+# endif // else defined ( OEM_MSOFT ) // unsupported/alternate feature
+
+
+
+# if !defined ( OEM_MSOFT ) // Standard Maynstream product feature
+
+ case IDM_HELPABOUTWINTERPARK:
+ wDialogID = IDD_HELPABOUTWINTERPARK;
+ break;
+
+
+# else // OEM_MSOFT - alternate feature
+
+ case IDM_HELPABOUTNOSTRADOMUS:
+ wDialogID = IDD_HELPABOUTWINTERPARK; // NEED TO CHANGE THIS!!
+ break;
+
+# endif // !defined ( OEM_MSOFT ) - standard/alternate feature
+
+
+ default:
+
+ fCmdProcessed = FALSE;
+
+ } /* end switch() */
+
+
+ // Check to see if a dialog ID was found. If so, show it.
+
+ if ( fCmdProcessed && wDialogID != 0xFFFF ) {
+
+ if ( DM_ShowDialog ( hWnd, wDialogID, (PVOID)0 ) == DM_SHOWNOTFOUND ) {
+ fCmdProcessed = FALSE;
+ }
+ }
+
+ return fCmdProcessed;
+
+} /* end MM_MenuCmdHandler() */
+
+
+/******************************************************************************
+
+ Name: MM_ShowMenuStatusHelp()
+
+ Description: This handles showing menu help one-liners on the status
+ line.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID MM_ShowMenuStatusHelp (
+
+WORD wID ) // ID of the menu item for displaying status help
+
+{
+ // You may be able to get away with just a range, but this
+ // way, you are guaranteed that no erroneous messages will be
+ // displayed.
+
+# if !defined ( OEM_MSOFT ) //alternate functionality
+ {
+
+ switch ( wID ) { //Menus for standard Maynstream product...
+
+ case IDM_FILEPRINT:
+ case IDM_FILESETUP:
+ case IDM_FILEEXIT:
+
+ case IDM_JOBMAINTENANCE:
+
+ case IDM_TREEEXPANDONE:
+ case IDM_TREEEXPANDBRANCH:
+ case IDM_TREEEXPANDALL:
+ case IDM_TREECOLLAPSEBRANCH:
+
+ case IDM_VIEWTREEANDDIR:
+ case IDM_VIEWTREEONLY:
+ case IDM_VIEWDIRONLY:
+ case IDM_VIEWSPLIT:
+ case IDM_VIEWALLFILEDETAILS:
+ case IDM_VIEWSORTNAME:
+ case IDM_VIEWSORTTYPE:
+ case IDM_VIEWSORTSIZE:
+ case IDM_VIEWSORTDATE:
+ case IDM_VIEWFONT:
+
+ case IDM_OPERATIONSBACKUP:
+ case IDM_OPERATIONSRESTORE:
+ case IDM_OPERATIONSTRANSFER:
+ case IDM_OPERATIONSVERIFY:
+ case IDM_OPERATIONSINFO:
+ case IDM_OPERATIONSCATALOG:
+ case IDM_OPERATIONSCATMAINT:
+ case IDM_OPERATIONSSEARCH:
+ case IDM_OPERATIONSEJECT:
+ case IDM_OPERATIONSERASE:
+ case IDM_OPERATIONSRETENSION:
+ case IDM_OPERATIONSCONNECT:
+ case IDM_OPERATIONSDISCON:
+#ifdef OS_WIN32
+ case IDM_OPERATIONSFORMAT:
+#endif // OS_WIN32
+
+ case IDM_SELECTCHECK:
+ case IDM_SELECTUNCHECK:
+ case IDM_SELECTADVANCED:
+ case IDM_SELECTSUBDIRS:
+ case IDM_SELECTSAVE:
+ case IDM_SELECTUSE:
+ case IDM_SELECTDELETE:
+ case IDM_SELECTCLEAR:
+
+ case IDM_SETTINGSBACKUP:
+ case IDM_SETTINGSRESTORE:
+ case IDM_SETTINGSLOGGING:
+ case IDM_SETTINGSNETWORK:
+ case IDM_SETTINGSCATALOG:
+ case IDM_SETTINGSHARDWARE:
+ case IDM_SETTINGSDEBUGWINDOW:
+ case IDM_SETTINGSGENERAL:
+
+ case IDM_WINDOWSCASCADE:
+ case IDM_WINDOWSTILE:
+ case IDM_WINDOWSREFRESH:
+ case IDM_WINDOWSCLOSEALL:
+ case IDM_WINDOWSARRANGEICONS:
+
+ case IDM_HELPINDEX:
+ case IDM_HELPSEARCH:
+ case IDM_HELPUSINGHELP:
+ case IDM_HELPABOUTWINTERPARK:
+
+ STM_DrawText ( ID(wID) );
+ return;
+
+ default:
+
+ STM_DrawText ( TEXT("") );
+ return;
+
+ }
+ }
+# else //if defined ( OEM_MSOFT ) //alternate functionality
+ {
+ switch ( wID ) { // Menus for OEM_MSOFT product...
+
+ case IDM_OPERATIONSBACKUP:
+ case IDM_OPERATIONSRESTORE:
+ case IDM_OPERATIONSCATALOG:
+ case IDM_OPERATIONSERASE:
+ case IDM_OPERATIONSRETENSION:
+ case IDM_OPERATIONSEJECT:
+ case IDM_OPERATIONSHARDWARE:
+ case IDM_OPERATIONSEXIT:
+ case IDM_OPERATIONSFORMAT:
+#ifdef OEM_EMS
+ case IDM_OPERATIONSEXCHANGE:
+#endif
+
+ case IDM_TREEEXPANDONE:
+ case IDM_TREEEXPANDBRANCH:
+ case IDM_TREEEXPANDALL:
+ case IDM_TREECOLLAPSEBRANCH:
+
+ case IDM_VIEWTREEANDDIR:
+ case IDM_VIEWTREEONLY:
+ case IDM_VIEWDIRONLY:
+ case IDM_VIEWSPLIT:
+ case IDM_VIEWALLFILEDETAILS:
+ case IDM_VIEWSTATUS:
+ case IDM_VIEWURIBBON:
+ case IDM_VIEWFONT:
+
+ case IDM_SELECTCHECK:
+ case IDM_SELECTUNCHECK:
+
+ case IDM_WINDOWSCASCADE:
+ case IDM_WINDOWSTILE:
+ case IDM_WINDOWSARRANGEICONS:
+ case IDM_WINDOWSREFRESH:
+ case IDM_WINDOWSCLOSEALL:
+
+ case IDM_HELPINDEX:
+ case IDM_HELPSEARCH:
+ case IDM_HELPUSINGHELP:
+ case IDM_HELPABOUTNOSTRADOMUS:
+
+ STM_DrawText ( ID(wID) );
+ return;
+
+ default:
+
+ STM_DrawText ( TEXT("") );
+ return;
+
+ }
+ }
+# endif //!defined ( OEM_MSOFT ) //alternate functionality
+
+
+} /* end MM_ShowMenuStatusHelp() */
diff --git a/private/utils/ntbackup/src/msgbox.c b/private/utils/ntbackup/src/msgbox.c
new file mode 100644
index 000000000..c508cfe30
--- /dev/null
+++ b/private/utils/ntbackup/src/msgbox.c
@@ -0,0 +1,1304 @@
+
+/******************************************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+JPW
+
+ Name: msgbox.c
+
+ Description: This module contains the message box functions. The
+ original WM_MsgBox call has been stubbed to call the
+ new WM_MessageBox. See the header of WM_MessageBox
+ for a complete description of the new features.
+
+ Functions in this module:
+
+ WM_MsgBox - old call to display message box
+ WM_MessageBox - new call to display message box
+ WM_MessageDlg - dialog procedure for message box
+
+
+ $Log: G:\ui\logfiles\msgbox.c_v $
+
+ Rev 1.49.1.2 04 Mar 1994 16:57:24 STEVEN
+prompt if disk is full
+
+ Rev 1.49.1.1 28 Jan 1994 17:22:30 Glenn
+Simplified and fixed Icon support.
+
+ Rev 1.49.1.0 04 Nov 1993 15:22:20 STEVEN
+fixes from Wa
+
+ Rev 1.49 10 Aug 1993 14:29:58 GLENN
+Now showing help only if the help ID is not NULL.
+
+ Rev 1.48 28 Jul 1993 17:52:18 MARINA
+enable c++
+
+ Rev 1.47 30 Jun 1993 14:46:04 STEVEN
+update lagest message to 400
+
+ Rev 1.46 15 Jun 1993 11:19:10 GLENN
+Fixed box to load button text strings only when needed.
+
+ Rev 1.45 08 Jun 1993 15:27:46 BARRY
+Get rid of DT_TABSTOP in call to DrawText -- was hosing '&' in dialogs.
+
+ Rev 1.44 24 May 1993 14:48:04 GLENN
+Added Dynamic Button Sizing based on the length of button string and Font Type.
+
+ Rev 1.43 03 May 1993 11:48:02 CHUCKB
+Change default tab stops in message box.
+
+ Rev 1.42 01 Nov 1992 16:02:38 DAVEV
+Unicode changes
+
+ Rev 1.41 16 Oct 1992 15:55:24 GLENN
+Got rid of a ton of compiler warnings for windows.
+
+ Rev 1.40 14 Oct 1992 15:58:26 GLENN
+Added code to pause and resume the wait cursor during a message box.
+
+ Rev 1.39 04 Oct 1992 19:38:56 DAVEV
+Unicode Awk pass
+
+ Rev 1.38 17 Aug 1992 13:20:44 DAVEV
+MikeP's changes at Microsoft
+
+ Rev 1.37 10 Jun 1992 14:30:06 JOHNWT
+changed font to ghFontMsgBox
+
+ Rev 1.36 29 May 1992 15:59:42 JOHNWT
+PCH updates
+
+ Rev 1.35 30 Mar 1992 18:02:44 GLENN
+Added support for pulling resources from .DLL
+
+ Rev 1.34 23 Mar 1992 16:10:48 JOHNWT
+added WMMB_BUT2DEFAULT functionality
+
+ Rev 1.33 22 Mar 1992 12:53:06 JOHNWT
+added WMMB_OKDISABLE
+
+ Rev 1.32 19 Mar 1992 11:45:50 JOHNWT
+moved WM_MakeAppActive to winmang.c
+
+ Rev 1.31 17 Mar 1992 08:05:02 ROBG
+added IDHELP
+
+ Rev 1.30 28 Feb 1992 16:32:22 JOHNWT
+tried more things
+
+ Rev 1.29 25 Feb 1992 21:25:08 GLENN
+Removed system modal specific calls.
+
+ Rev 1.28 23 Feb 1992 13:55:56 GLENN
+Trying new things...
+
+ Rev 1.27 18 Feb 1992 18:33:46 GLENN
+Placed strategically located WM_MultiTask() statements.
+
+ Rev 1.26 11 Feb 1992 17:24:16 GLENN
+Moved multitask to destroy case.
+
+ Rev 1.25 06 Feb 1992 16:11:00 DAVEV
+NT ONLY: Kludged weird bug where GetClientRect on a push button seems to return dialog units in Re
+ct.bottom?!?
+
+ Rev 1.24 31 Jan 1992 14:37:24 JOHNWT
+if iconic use IDS_APPNAME as msg title
+
+ Rev 1.23 31 Jan 1992 13:44:06 JOHNWT
+moved center operation to DM_CenterDialog
+
+ Rev 1.22 30 Jan 1992 11:41:04 JOHNWT
+moved WMMB_SYSMODAL to msgbox.h
+
+ Rev 1.21 29 Jan 1992 13:14:18 CARLS
+No change
+
+ Rev 1.20 27 Jan 1992 00:29:46 CHUCKB
+Updated dialog id's.
+
+ Rev 1.19 21 Jan 1992 16:53:52 JOHNWT
+changed checkyy to noyycheck flag
+
+ Rev 1.18 14 Jan 1992 17:25:00 JOHNWT
+more sysmodal changes
+
+ Rev 1.17 14 Jan 1992 16:36:16 JOHNWT
+reset ghModelessDialog to sysmodal
+
+ Rev 1.16 13 Jan 1992 10:22:18 JOHNWT
+added help
+
+ Rev 1.15 20 Dec 1991 16:58:36 JOHNWT
+return ghModelessDialog
+
+ Rev 1.14 19 Dec 1991 15:24:38 GLENN
+Added windows.h
+
+ Rev 1.13 18 Dec 1991 11:21:30 JOHNWT
+changed modeless to runtime
+
+ Rev 1.12 16 Dec 1991 17:18:18 JOHNWT
+made parent the active window
+
+ Rev 1.11 16 Dec 1991 10:07:20 JOHNWT
+removed get/set focus call!
+
+ Rev 1.10 13 Dec 1991 16:40:42 JOHNWT
+fixed last fix
+
+ Rev 1.9 13 Dec 1991 15:45:06 JOHNWT
+added get/setfocus
+
+ Rev 1.8 12 Dec 1991 17:07:12 DAVEV
+16/32 bit port -2nd pass
+
+ Rev 1.7 09 Dec 1991 11:43:58 JOHNWT
+fixed bogus ReleaseDC
+
+ Rev 1.6 04 Dec 1991 15:19:40 DAVEV
+Modifications for 16/32-bit Windows port - 1st pass.
+
+
+ Rev 1.5 02 Dec 1991 12:53:54 JOHNWT
+check malloc/callocs
+
+ Rev 1.4 25 Nov 1991 15:25:14 JOHNWT
+adjusted size of msgbox
+
+ Rev 1.3 24 Nov 1991 13:03:52 JOHNWT
+removed large font on inst line
+
+ Rev 1.2 21 Nov 1991 18:11:26 JOHNWT
+added yy flag check
+
+ Rev 1.1 21 Nov 1991 13:33:48 JOHNWT
+do not force large font
+
+ Rev 1.0 20 Nov 1991 19:34:00 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+#include "all.h"
+#include "ctl3d.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+/* module wide defines */
+
+#define WMMB_MAX_TITLE 100 /* maximum size of title */
+#define WMMB_MAX_MESSAGE 400 /* maximum size of message */
+#define WMMB_MAX_INSTRUCTION 60 /* maximum size of instruction */
+
+#define WMMB_MAX_BUTTON 40 /* maximum size of button text */
+#define WMMB_MAX_MSG_LINE (IS_JAPAN()?60:40) /* max line length (dlg base units) */
+#define WMMB_MID_MSG_LINE (IS_JAPAN()?40:30) /* mid line length (dlg base units) */
+#define WMMB_MIN_MSG_LINE 20 /* min line length (dlg base units) */
+
+#define BUTTON_BORDERWIDTH 3
+
+/* structure passed to WM_MessageDlg */
+
+typedef struct DS_MESSAGE {
+
+ WORD wIcon; /* message box icon to use */
+ WORD wType; /* buttons to use, etc */
+ CHAR_PTR pTitle; /* ptr to title (caption) */
+ CHAR_PTR pMessage; /* ptr to message text */
+ CHAR_PTR pInstruction; /* optional instruction line */
+ WORD wInstBitMap; /* optional bitmap to precede inst line */
+ WORD wHelpID; /* optional help id for message */
+
+} DS_MESSAGE, far *DS_MESSAGE_PTR;
+
+// MODULE-WIDE VARIABLES
+
+static WORD mwwHelpButID, /* help button id */
+ mwwHelpID; /* help id */
+
+/* Dialog procedure prototype */
+
+DLGRESULT APIENTRY WM_MessageDlg( HWND, MSGID, MP1, MP2 );
+
+static INT MB_SetButtons ( HWND, WORD, INT *, DS_MESSAGE_PTR );
+static INT MB_GetMaxButtonExtent ( HDC, LPSTR, INT );
+
+
+
+/******************************************************************************
+
+ Name: WM_MsgBox()
+
+ Description: This function displays a message box. The message box can
+ contain a title, message, various buttons, and one out
+ of various icons.
+
+ Modified: 11/14/91
+
+ Returns: Various message IDs depending on the input parameters and
+ the button selected.
+
+ WMMB_IDOK
+ WMMB_IDRETRY
+ WMMB_IDIGNOR
+ WMMB_IDYES
+ WMMB_IDCONTINUE
+ WMMB_IDCANCEL
+ WMMB_IDNO
+ WMMB_IDABORT
+ WMMB_IDDISABLE
+
+
+ Notes: This function is now a stub which calls WM_MessageBox.
+
+******************************************************************************/
+
+INT WM_MsgBox (
+
+LPSTR lpszTitle, /* I - title of the message box */
+LPSTR lpszMessage, /* I - message of the message box */
+WORD wType, /* I - type IDs of buttons OR'd together */
+WORD wIcon ) /* I - icon ID to be displayed */
+
+{
+
+ return WM_MessageBox( lpszTitle, lpszMessage, wType, wIcon, (CHAR_PTR)NULL, 0, 0 );
+
+} /* end WM_MsgBox() */
+
+
+/******************************************************************************
+
+ Name: WM_MessageBox()
+
+ Description: This function displays a message box. The message box can
+ contain a title, icon, message, instruction line, a
+ bitmap which precedes the instruction line, and various
+ buttons. If WMMB_NOYYCHECK is set, it will not check the YY
+ flag, otherwise it will return yes if it is set.
+
+ Modified: 11/14/91
+
+ Input: Text input can be in the form of pointers or resids.
+ The message can contain line-breaks (\012) and tabs (\011).
+
+ pTitle - msgbox title, if NULL, "Message" is title
+ pMessage - message text ( max 400 chars if resid )
+
+ wType - one of the following:
+
+ WMMB_OK - OK button only
+ WMMB_RETRYCANCEL - Retry/Cancel buttons
+ WMMB_YESNO - Yes/No buttons
+ WMMB_OKCANCEL - OK/Cancel buttons
+ WMMB_CONTABORT - Continue/Abort buttons
+ WMMB_CONTCANCEL - Continue/Cancel buttons
+ WMMB_OKDISABLE - OK/Disable buttons
+ WMMB_ABORTRETRYIGNOR - Abort/Retry/Ignore buttons
+
+ maybe OR'ed with:
+
+ WMMB_BUT2DEFAULT - make but 2 default
+ WMMB_NOYYCHECK - Ignore the YY flag
+ WMMB_INSTBIG - Big font for inst
+ WMMB_MSGBIG - Big font for msg
+ WMMB_MSGBIGBOLD - Big-bold font for msg
+
+ wIcon - one of the following (0 for none)
+
+ WMMB_ICONQUESTION - question mark
+ WMMB_ICONSTOP - stop sign
+ WMMB_ICONINFORMATION - circled i
+ WMMB_ICONEXCLAMATION - circled !
+
+ pInstruction - inst text (one line only, NULL for none)
+ wInstBitMap - inst bitmap to precede inst (0 for none)
+ wHelpID - help id for message (0 for none)
+
+ Return: Various message IDs depending on the input parameters and
+ the button selected.
+
+ Affirmative responses: Negative responses:
+
+ WMMB_IDOK WMMB_IDCANCEL
+ WMMB_IDRETRY WMMB_IDNO
+ WMMB_IDYES WMMB_IDABORT
+ WMMB_IDCONTINUE WMMB_IDDISABLE
+
+ Notes:
+
+******************************************************************************/
+
+INT WM_MessageBox (
+
+ CHAR_PTR pTitle, /* I - title, if NULL - TEXT("Message") is title */
+ CHAR_PTR pMessage, /* I - ptr to message or resid */
+ WORD wType, /* I - type of buttons, font size */
+ WORD wIcon, /* I - icon to display, if 0 none is displayed */
+ CHAR_PTR pInstruction, /* I - ptr to message of resid */
+ WORD wInstBitMap, /* I - bitmap or 0 for none */
+ WORD wHelpID ) /* I - help id for message */
+
+{
+ INT rc;
+ DS_MESSAGE Message;
+ WNDPROC lpProc ;
+ HWND hWnd;
+ CHAR_PTR pResTitle = (CHAR_PTR)NULL;
+ CHAR_PTR pResMessage = (CHAR_PTR)NULL;
+ CHAR_PTR pResInstruction = (CHAR_PTR)NULL;
+ /* If the ignore option is not set, check the YY flag to see if we
+ should just return. */
+
+ WM_ShowWaitCursor( FALSE ) ;
+
+ if ( !( wType & WMMB_NOYYCHECK ) &&
+ ( CDS_GetYesFlag ( CDS_GetCopy() ) == YESYES_FLAG ) ) {
+
+ return WMMB_IDYES;
+ }
+
+ /* If a RESOURCE ID was passed, copy the string from the resource. */
+
+ if ( pTitle && ! HIWORD(pTitle) ) {
+
+ pResTitle = ( CHAR_PTR )calloc( WMMB_MAX_TITLE, sizeof ( CHAR ) );
+
+ if ( pResTitle == (CHAR_PTR)NULL ) {
+ return WMMB_IDNO;
+ }
+
+ RSM_StringCopy ( LOWORD((DWORD)pTitle), pResTitle, WMMB_MAX_TITLE - 1 );
+ pTitle = pResTitle;
+ }
+
+ if ( pMessage && ! HIWORD(pMessage) ) {
+
+ pResMessage = ( CHAR_PTR )calloc( WMMB_MAX_MESSAGE, sizeof ( CHAR ) );
+
+ if ( pResMessage == (CHAR_PTR)NULL ) {
+ if ( pResTitle ) {
+ free( pResTitle );
+ }
+ return WMMB_IDNO;
+ }
+
+ RSM_StringCopy ( LOWORD((DWORD)pMessage), pResMessage, WMMB_MAX_MESSAGE - 1 );
+ pMessage = pResMessage;
+ }
+
+ if ( pInstruction && ! HIWORD(pInstruction) ) {
+
+ pResInstruction = ( CHAR_PTR )calloc( WMMB_MAX_INSTRUCTION, sizeof ( CHAR ) );
+
+ if ( pResInstruction == (CHAR_PTR)NULL ) {
+
+ if ( pResTitle ) {
+ free( pResTitle );
+ }
+
+ if ( pResMessage ) {
+ free( pResMessage );
+ }
+
+ return WMMB_IDNO;
+ }
+
+ RSM_StringCopy ( LOWORD((DWORD)pInstruction), pResInstruction, WMMB_MAX_INSTRUCTION - 1 );
+ pInstruction = pResInstruction;
+ }
+
+ /* Set up message structure to pass for the init dialog processing */
+
+ Message.wIcon = wIcon;
+ Message.wType = wType;
+ Message.pTitle = pTitle;
+ Message.pMessage = pMessage;
+ Message.pInstruction = pInstruction;
+ Message.wInstBitMap = wInstBitMap;
+ Message.wHelpID = wHelpID;
+
+ WM_MultiTask ();
+
+ WM_MakeAppActive();
+
+ WM_MultiTask ();
+
+ /* Get the top window of our app */
+
+ if ( ghModelessDialog ) {
+ hWnd = GetLastActivePopup( ghModelessDialog );
+ }
+ else {
+ hWnd = GetLastActivePopup( ghWndFrame );
+ }
+
+ // Check to see if the wait cursor is being shown. If so, pause it,
+ // then resume it later.
+
+ WM_ShowWaitCursor ( SWC_PAUSE );
+
+ WM_MultiTask ();
+
+ /* make our proc instance and display the dialog */
+
+ lpProc = (WNDPROC)MakeProcInstance( ( FARPROC )WM_MessageDlg, ghInst ) ;
+
+ rc = DialogBoxParam( ghResInst,
+ MAKEINTRESOURCE( IDD_MESSAGE_BOX ),
+ hWnd,
+ (DLGPROC)lpProc,
+ (LONG) (DS_MESSAGE_PTR)&Message );
+
+ FreeProcInstance( lpProc );
+
+ // Resume the wait cursor. (only if it was truly paused)
+
+ WM_ShowWaitCursor ( SWC_RESUME );
+
+ /* free any allocated memory due to resids */
+
+ if ( pResTitle ) {
+ free( pResTitle );
+ }
+
+ if ( pResMessage ) {
+ free( pResMessage );
+ }
+
+ if ( pResInstruction ) {
+ free( pResInstruction );
+ }
+
+ return rc;
+
+} /* end WM_MessageBox() */
+
+
+/******************************************************************************
+
+ Name: WM_MessageDlg ()
+
+ Description: Dialog procedure for the message box.
+
+ Modified: 11/14/91
+
+ Returns: TRUE if message was processed
+
+ Notes: The size and placement of all controls is calculated
+ during the INIT_DIALOG processing. Required info is
+ placed in static variables for use during the PAINT
+ message.
+
+******************************************************************************/
+
+DLGRESULT APIENTRY WM_MessageDlg (
+
+ HWND hDlg, /* I - from Windows */
+ MSGID msg, /* I - from Windows */
+ MP1 mp1, /* I - from Windows */
+ MP2 mp2 ) /* I - from Windows, contains ptr to DS_MESSAGE struc */
+
+{
+ static WORD wIcon, /* icon to be displayed in upper left */
+ wType, /* holds type of buttons, font */
+ wInstBitMap; /* bitmap for instruction line */
+ static HWND hWndIcon, /* handle of window for icon drawing */
+ hWndMsg, /* handle of window for message text */
+ hWndInst; /* handle of window for inst bitmap/text */
+ static CHAR_PTR pMsgText, /* message text */
+ pInstText; /* instruction text */
+ static RECT MsgRect, /* rectangle in which to display message */
+ InstRect; /* rectangle in which to displa inst */
+ static INT nInstIconX; /* X coordinate of instruction bitmap */
+ static LOGFONT logfont; /* logical font */
+ static LONG lDlgBaseUnits; /* base units for dialog boxes */
+ static INT nButtonWidth; /* width of the buttons */
+
+ HWND hWndBut; /* button window */
+ RECT DlgRect, /* calculated size of dialog */
+ Rect; /* used for get calls */
+ HDC hDC; /* device context */
+ INT nTextBot, /* height of all texts + margins */
+ nButsBot = 2, /* number of buttons (def to 2) */
+ nButX, /* X coordinate of buttons */
+ nTextWidth; /* longest width of text */
+ SIZE sizeRect; /* length/width of line in current hDC*/
+ HFONT hFont; /* holds old font */
+
+
+ /* switch based on message passed by Windows */
+
+ switch ( msg ) {
+
+/***************************************************************************
+ * Initialize the dialog
+ ***************************************************************************/
+
+ case WM_INITDIALOG :
+ {
+ DS_MESSAGE_PTR pMessage;
+ HICON hIcon;
+ BYTE csfont ;
+ if (IS_JAPAN() ) {
+ CHARSETINFO csi;
+ DWORD dw = GetACP();
+
+ if (!TranslateCharsetInfo((DWORD*)dw, &csi, TCI_SRCCODEPAGE))
+ csi.ciCharset = ANSI_CHARSET;
+ csfont = csi.ciCharset;
+ } else {
+ csfont = ANSI_CHARSET ;
+ }
+
+ WM_MultiTask ();
+
+ /* Let's go 3-D! */
+ Ctl3dSubclassDlgEx( hDlg, CTL3D_ALL );
+
+ pMessage = (DS_MESSAGE_PTR) mp2;
+
+ /* save info in static variables */
+
+ pMsgText = pMessage->pMessage;
+ pInstText = pMessage->pInstruction;
+ wIcon = pMessage->wIcon;
+ wType = pMessage->wType;
+ wInstBitMap = pMessage->wInstBitMap;
+
+ /* if the message is small, force it into the big font */
+
+ // if ( ( strlen( pMsgText ) < ( 3 * WMMB_MAX_MSG_LINE ) ) &&
+ // !( wType & ( WMMB_MSGBIG | WMMB_MSGBIGBOLD ) ) ) {
+ // wType |= WMMB_MSGBIG;
+ // }
+
+
+ // Set the icon.
+
+ switch ( wIcon ) {
+
+ case WMMB_ICONQUESTION:
+ hIcon = LoadIcon( (HINSTANCE)NULL, IDI_QUESTION );
+ break;
+
+ case WMMB_ICONSTOP:
+ hIcon = LoadIcon( (HINSTANCE)NULL, IDI_HAND );
+ break;
+
+ case WMMB_ICONEXCLAMATION:
+ hIcon = LoadIcon( (HINSTANCE)NULL, IDI_EXCLAMATION );
+ break;
+
+ default:
+ hIcon = LoadIcon( (HINSTANCE)NULL, IDI_ASTERISK );
+ break;
+ }
+
+ SendDlgItemMessage ( hDlg, IDD_MSG_ICON, STM_SETICON, (MP1)hIcon, 0L );
+
+
+ /* Get the base units for dialogs which will determine where */
+ /* everything resides. */
+
+ lDlgBaseUnits = GetDialogBaseUnits();
+
+ /* Create our logical font */
+
+ if (IS_JAPAN() ) {
+ logfont.lfWeight = FW_NORMAL;
+ logfont.lfCharSet = csfont;
+ logfont.lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS;
+ strcpy( logfont.lfFaceName, TEXT("MS Shell Dlg") );
+ } else {
+ logfont.lfWeight = FW_BOLD;
+ logfont.lfCharSet = ANSI_CHARSET;
+ logfont.lfPitchAndFamily = VARIABLE_PITCH | FF_SWISS;
+ strcpy( logfont.lfFaceName, TEXT("Swiss") );
+ }
+
+ if( pMessage->pTitle ) {
+ SetWindowText ( hDlg, pMessage->pTitle );
+ }
+
+ /* set up rectangle for call to DrawText which will */
+ /* modify the right and bottom to make the text fit. */
+ /* We start with just one line of max chars. */
+
+ MsgRect.left = 0;
+ MsgRect.top = 0;
+ MsgRect.right = WMMB_MAX_MSG_LINE * LOWORD(lDlgBaseUnits);
+ MsgRect.bottom = HIWORD(lDlgBaseUnits);
+
+ hWndMsg = GetDlgItem( hDlg, IDD_MSG_TEXT );
+ hDC = GetDC( hWndMsg );
+
+ if ( wType & ( WMMB_MSGBIG | WMMB_MSGBIGBOLD ) ) {
+ logfont.lfHeight = ( wType & WMMB_MSGBIG ) ?
+ HIWORD(lDlgBaseUnits) + (HIWORD(lDlgBaseUnits) / 4) :
+ HIWORD(lDlgBaseUnits) + (HIWORD(lDlgBaseUnits) / 2);
+ hFont = SelectObject( hDC, CreateFontIndirect( &logfont ) );
+ } else {
+ SelectObject ( hDC, ghFontMsgBox );
+ }
+
+ nButtonWidth = MB_SetButtons ( hDlg, wType, &nButsBot, pMessage );
+
+ /* Make sure we don't have a long skinny message box */
+
+ GetTextExtentPoint( hDC, pMsgText, strlen( pMsgText ), &sizeRect );
+
+ if ( sizeRect.cx < (INT) MsgRect.right ) {
+ MsgRect.right = WMMB_MIN_MSG_LINE * LOWORD(lDlgBaseUnits);
+ } else if ( pInstText == (CHAR_PTR)NULL ) {
+ if ( sizeRect.cx < (INT) (2 * MsgRect.right) ) {
+ MsgRect.right = WMMB_MIN_MSG_LINE * LOWORD(lDlgBaseUnits);
+ } else if ( sizeRect.cx < (INT) (3 * MsgRect.right) ) {
+ MsgRect.right = WMMB_MID_MSG_LINE * LOWORD(lDlgBaseUnits);
+ }
+ } else {
+ if ( sizeRect.cx < (INT) (2 * MsgRect.right) ) {
+ MsgRect.right = WMMB_MID_MSG_LINE * LOWORD(lDlgBaseUnits);
+ }
+ }
+
+ DrawText( hDC, pMsgText, -1, &MsgRect,
+ DT_CALCRECT | DT_EXPANDTABS | DT_LEFT |
+ DT_NOPREFIX | DT_WORDBREAK );
+
+ if ( wType & ( WMMB_MSGBIG | WMMB_MSGBIGBOLD ) ) {
+ DeleteObject( SelectObject( hDC, hFont ) );
+ }
+
+ ReleaseDC( hWndMsg, hDC );
+
+ /* if text is less than the minimum, set length to minimum */
+
+ nTextWidth = MsgRect.right;
+ if ( nTextWidth < (INT)( WMMB_MIN_MSG_LINE * LOWORD(lDlgBaseUnits) ) ) {
+ nTextWidth = WMMB_MIN_MSG_LINE * LOWORD(lDlgBaseUnits);
+ MsgRect.right = nTextWidth;
+ }
+
+ /* calculate the width of the instruction line */
+
+ if ( pInstText != (CHAR_PTR)NULL ) {
+
+ hWndInst = GetDlgItem( hDlg, IDD_MSG_INST );
+ hDC = GetDC( hWndInst );
+
+ if ( wType & WMMB_INSTBIG ) {
+ logfont.lfHeight = HIWORD(lDlgBaseUnits) + ( HIWORD(lDlgBaseUnits) / 4 );
+ hFont = SelectObject( hDC, CreateFontIndirect( &logfont ) );
+ } else {
+ SelectObject ( hDC, ghFontMsgBox );
+ }
+
+ GetTextExtentPoint( hDC, pInstText, strlen( pInstText ),
+ &sizeRect );
+
+ if ( wType & WMMB_INSTBIG ) {
+ DeleteObject( SelectObject( hDC, hFont ) );
+ }
+
+ ReleaseDC( hWndInst, hDC );
+
+ nTextWidth = sizeRect.cx;
+
+ /* if bitmap defined, use icon size to calculate size */
+
+ if ( wInstBitMap != 0 ) {
+ nTextWidth += LOWORD(lDlgBaseUnits) +
+ GetSystemMetrics( SM_CXICON );
+ }
+
+ /* if the line is longer than the max, set it back */
+
+ if ( nTextWidth > (INT)( WMMB_MAX_MSG_LINE * LOWORD(lDlgBaseUnits) ) ) {
+ nTextWidth = WMMB_MAX_MSG_LINE * LOWORD(lDlgBaseUnits) ;
+ }
+
+ /* if the instruction text is less than the message, set it to */
+ /* the same and then set up the instruction rectangle size. */
+
+ if ( nTextWidth < MsgRect.right ) {
+ nTextWidth = MsgRect.right;
+ }
+
+ InstRect.top = 0;
+ InstRect.left = 0;
+ InstRect.right = nTextWidth;
+ InstRect.bottom = GetSystemMetrics( SM_CYICON );
+
+ /* if no bitmap and inst is less than max, center it */
+
+ if ( wInstBitMap == 0 ) {
+
+ if ( sizeRect.cx < (INT) nTextWidth ) {
+ InstRect.left = ( nTextWidth - sizeRect.cx ) / 2;
+ }
+
+ } else {
+
+ /* calculate the X position of the bitmap */
+
+ nInstIconX = LOWORD(lDlgBaseUnits) +
+ GetSystemMetrics( SM_CXICON ) + sizeRect.cx;
+ if ( nInstIconX < nTextWidth ) {
+ nInstIconX = ( nTextWidth - nInstIconX ) / 2;
+ } else {
+ nInstIconX = 0;
+ }
+
+ InstRect.left = nInstIconX + LOWORD(lDlgBaseUnits) +
+ GetSystemMetrics( SM_CXICON );
+ }
+
+ /* if the inst stuff is longer than the message, reset the msg */
+
+ if ( nTextWidth > MsgRect.right) {
+ MsgRect.right = nTextWidth;
+ }
+
+ }
+
+
+ /* get the current dialog rectangle and subtract off the size */
+ /* of the client area which will leave us the size of the */
+ /* borders, title, etc. */
+
+ GetWindowRect( hDlg, &DlgRect );
+ GetClientRect( hDlg, &Rect );
+
+ DlgRect.right -= Rect.right;
+ DlgRect.bottom -= Rect.bottom;
+
+ /* Now we calculate the width and height of the dialog. */
+ /* We add 8 base-unit-widths for margins, the width of */
+ /* the icon, the width of the message text, and the */
+ /* width of a button. */
+
+ hWndBut = GetDlgItem( hDlg, IDD_MSG_BUT1 );
+
+
+# if defined ( NTKLUG )
+ {
+
+ // Note: this is a definite kludge for NT!!
+ // the height seems to be getting returned in
+ // dialog units??!! (which happen to be 14).
+ // The temporary fix is to convert these units to pixels.
+
+ GetClientRect( hWndBut, &Rect );
+
+ if (Rect.bottom == 14)
+ Rect.bottom = (Rect.bottom * LOWORD (lDlgBaseUnits)) /4;
+ }
+# else
+ {
+ GetClientRect( hWndBut, &Rect );
+ }
+# endif
+
+ DlgRect.right += (8 * LOWORD(lDlgBaseUnits) ) +
+ GetSystemMetrics( SM_CXICON ) +
+ MsgRect.right +
+ nButtonWidth;
+// Rect.right;
+
+ /* The height is room for margins plus the height of the */
+ /* message text. If an instruction line is defined, add */
+ /* the height of the line which is defined by the icon */
+ /* height. */
+
+ nTextBot = (2 * HIWORD(lDlgBaseUnits) ) + MsgRect.bottom;
+
+ if ( pMessage->pInstruction != (CHAR_PTR)NULL ) {
+ nTextBot += HIWORD(lDlgBaseUnits) + GetSystemMetrics( SM_CYICON );
+ }
+
+ /* We must also calculate the height of the buttons since */
+ /* they may exceed the height of the text. If so, the */
+ /* height of the dialog is set to the button heights. */
+
+ nButsBot *= (HIWORD(lDlgBaseUnits) / 2) + Rect.bottom;
+ nButsBot += (HIWORD(lDlgBaseUnits) / 2) + HIWORD(lDlgBaseUnits);
+
+ DlgRect.bottom += (nTextBot > nButsBot) ? nTextBot : nButsBot;
+
+ /* Now put everything in its place. We start with the dialog */
+ /* itself. We set its size and then call the center function. */
+
+ SetWindowPos( hDlg, (HWND)NULL, 0, 0,
+ (DlgRect.right - DlgRect.left + 1 ),
+ (DlgRect.bottom - DlgRect.top + 1 ),
+ SWP_NOACTIVATE );
+
+ DM_CenterDialog( hDlg );
+
+ /* place the icon in its place */
+
+ hWndIcon = GetDlgItem( hDlg, IDD_MSG_ICON );
+
+ SetWindowPos( hWndIcon, (HWND)NULL,
+ 2 * LOWORD(lDlgBaseUnits),
+ HIWORD(lDlgBaseUnits),
+ GetSystemMetrics( SM_CXICON ),
+ GetSystemMetrics( SM_CYICON ),
+ SWP_NOACTIVATE );
+
+ /* place the message text in its place */
+
+ SetWindowPos( hWndMsg, (HWND)NULL,
+ (4 * LOWORD(lDlgBaseUnits) ) + GetSystemMetrics( SM_CXICON ),
+ HIWORD(lDlgBaseUnits),
+ MsgRect.right,
+ MsgRect.bottom,
+ SWP_NOACTIVATE );
+
+ /* place the instruction text in its place and set visible */
+
+ if ( pInstText != (CHAR_PTR)NULL ) {
+
+ SetWindowPos( hWndInst, (HWND)NULL,
+ (4 * LOWORD(lDlgBaseUnits) ) + GetSystemMetrics( SM_CXICON ),
+ (2* HIWORD(lDlgBaseUnits) ) + MsgRect.bottom,
+ nTextWidth,
+ GetSystemMetrics( SM_CYICON ),
+ SWP_NOACTIVATE );
+
+ ShowWindow( hWndInst, SW_SHOWNOACTIVATE );
+
+ }
+
+ /* Now line up the buttons. We first calculate the X position */
+ /* since it is the same for all the buttons. The top and bottom */
+ /* margins on the button stack are one base-unit-height. Between */
+ /* the buttons is 1/2 a base-unit-height. */
+
+ nButX = (6 * LOWORD(lDlgBaseUnits) ) + GetSystemMetrics( SM_CXICON ) +
+ MsgRect.right;
+
+ /* set the button positions */
+
+ hWndBut = GetDlgItem( hDlg, IDD_MSG_BUT2 );
+
+# if defined ( NTKLUG )
+ {
+ // Note: this is a definite kludge for NT!!
+ // the height seems to be getting returned in
+ // dialog units??!! (which happen to be 14).
+ // The temporary fix is to convert these units to pixels.
+
+ GetClientRect( hWndBut, &Rect );
+
+ if (Rect.bottom == 14)
+ Rect.bottom = (Rect.bottom * LOWORD (lDlgBaseUnits)) /4;
+ }
+# else
+ {
+ GetClientRect( hWndBut, &Rect );
+ }
+# endif
+
+ Rect.right = nButtonWidth;
+
+ SetWindowPos( hWndBut, (HWND)NULL,
+ nButX,
+ (HIWORD(lDlgBaseUnits) / 2) + HIWORD(lDlgBaseUnits) + Rect.bottom,
+ Rect.right,
+ Rect.bottom,
+ SWP_NOACTIVATE );
+
+ hWndBut = GetDlgItem( hDlg, IDD_MSG_BUT3 );
+ SetWindowPos( hWndBut, (HWND)NULL,
+ nButX,
+ (2 * HIWORD(lDlgBaseUnits)) + (2 * Rect.bottom),
+ Rect.right,
+ Rect.bottom,
+ SWP_NOACTIVATE );
+
+ hWndBut = GetDlgItem( hDlg, IDD_MSG_BUT1 );
+ SetWindowPos( hWndBut, (HWND)NULL,
+ nButX,
+ HIWORD(lDlgBaseUnits),
+ Rect.right,
+ Rect.bottom,
+ SWP_NOACTIVATE );
+
+ /* if flag set, set button 2 as default */
+
+ if ( wType & WMMB_BUT2DEFAULT ) {
+ SendDlgItemMessage( hDlg, IDD_MSG_BUT1, BM_SETSTYLE, (WORD) BS_PUSHBUTTON, 0L );
+ SendDlgItemMessage( hDlg, IDD_MSG_BUT2, BM_SETSTYLE, (WORD) BS_DEFPUSHBUTTON, 0L );
+ SetFocus( GetDlgItem( hDlg, IDD_MSG_BUT2 ) ) ;
+ } else {
+ SetFocus( GetDlgItem( hDlg, IDD_MSG_BUT1 ) ) ;
+ }
+
+ /* if flag set, set the dialog to system modal */
+
+ if ( wType & WMMB_SYSMODAL ) {
+ SetSysModalWindow( hDlg ) ;
+ }
+
+ WM_MultiTask ();
+
+ return FALSE; /* since we have already set the focus */
+ }
+
+
+/***************************************************************************
+ * Respond to button selections
+ ***************************************************************************/
+
+ case WM_COMMAND:
+ {
+ switch ( GET_WM_COMMAND_ID ( mp1, mp2 ) ) {
+
+ case IDD_MSG_BUT1: /* button 1, ret affirmative */
+ {
+
+ if ( wType & WMMB_ABORTRETRYIGNOR ) {
+
+ EndDialog ( hDlg, FALSE );
+
+ } else {
+
+ EndDialog ( hDlg, TRUE );
+ }
+ return TRUE;
+ }
+
+ case IDD_MSG_BUT2: /* button 2, ret negative */
+ {
+ if ( mwwHelpButID == GET_WM_COMMAND_ID( mp1, mp2 ) ) {
+ HM_DialogHelp( mwwHelpID ) ;
+ } else {
+
+ if ( wType & WMMB_ABORTRETRYIGNOR ) {
+ EndDialog ( hDlg, TRUE );
+ } else {
+ EndDialog ( hDlg, FALSE );
+ }
+ }
+ return TRUE;
+ }
+
+ case IDCANCEL: /* sent because of ESC button */
+ {
+
+ if ( wType & WMMB_OK ) {
+ EndDialog ( hDlg, TRUE ); /* if just the OK, ret affirm */
+ } else {
+ EndDialog ( hDlg, FALSE ); /* if two buttons, ret neg */
+ }
+ return TRUE;
+ }
+
+ case IDD_MSG_BUT3:
+ if ( wType & WMMB_ABORTRETRYIGNOR ) {
+ EndDialog ( hDlg, WMMB_IDIGNOR );
+ }
+ case IDHELP :
+ {
+
+ if ( mwwHelpID ) {
+ HM_DialogHelp( mwwHelpID ) ;
+ }
+ return TRUE;
+ }
+ }
+ break;
+ }
+
+/***************************************************************************
+ * Respond to the close selection from the system menu
+ ***************************************************************************/
+
+ case WM_CLOSE:
+ {
+ EndDialog ( hDlg, FALSE ); /* return false in this case */
+ return TRUE;
+ }
+
+/***************************************************************************
+ * Respond to the destroy message
+ ***************************************************************************/
+
+ case WM_DESTROY:
+
+ WM_MultiTask ();
+ break;
+
+/***************************************************************************
+ * Paint the dialog
+ ***************************************************************************/
+
+ case WM_PAINT:
+
+ PostMessage( hDlg, WM_MSGBOXDRAWTXT, mp1, mp2 );
+ break;
+
+ case WM_MSGBOXDRAWTXT:
+ {
+
+ /* draw the message text */
+
+ InvalidateRect( hWndMsg, (LPRECT)NULL, TRUE );
+ UpdateWindow( hWndMsg );
+ hDC = GetDC( hWndMsg );
+
+ if ( wType & ( WMMB_MSGBIG | WMMB_MSGBIGBOLD ) ) {
+ logfont.lfHeight = ( wType & WMMB_MSGBIG ) ?
+ HIWORD(lDlgBaseUnits) + (HIWORD(lDlgBaseUnits) / 4) :
+ HIWORD(lDlgBaseUnits) + (HIWORD(lDlgBaseUnits) / 2);
+ hFont = SelectObject( hDC, CreateFontIndirect( &logfont ) );
+ } else {
+ SelectObject ( hDC, ghFontMsgBox );
+ }
+
+ /* set the background and text colors and then draw the text */
+
+ SetBkColor( hDC, GetSysColor( COLOR_BTNFACE) );
+ SetTextColor( hDC, GetSysColor( COLOR_BTNTEXT ) ) ;
+
+ if (IS_JAPAN()) {
+ DrawText( hDC, pMsgText, -1, &MsgRect,
+ DT_EXPANDTABS | DT_LEFT | DT_NOPREFIX | DT_WORDBREAK);
+ } else {
+ DrawText( hDC, pMsgText, -1, &MsgRect,
+ DT_EXPANDTABS | DT_LEFT | DT_NOPREFIX | DT_WORDBREAK | 0x0A00 );
+ }
+
+ if ( wType & ( WMMB_MSGBIG | WMMB_MSGBIGBOLD ) ) {
+ DeleteObject( SelectObject( hDC, hFont ) );
+ }
+
+ ReleaseDC( hWndMsg, hDC );
+
+
+ /* draw the instruction text */
+
+ if ( pInstText != (CHAR_PTR)NULL ) {
+
+ InvalidateRect( hWndInst, (LPRECT)NULL, TRUE );
+ UpdateWindow( hWndInst );
+ hDC = GetDC( hWndInst );
+
+ if ( wType & WMMB_INSTBIG ) {
+ logfont.lfHeight = HIWORD(lDlgBaseUnits) + ( HIWORD(lDlgBaseUnits) / 4 );
+ hFont = SelectObject( hDC, CreateFontIndirect( &logfont ) );
+ } else {
+ SelectObject ( hDC, ghFontMsgBox );
+ }
+
+ /* set the background and text colors and then draw the text */
+
+ SetBkColor( hDC, GetSysColor( COLOR_BTNFACE) );
+ SetTextColor( hDC, GetSysColor( COLOR_BTNTEXT ) ) ;
+
+ DrawText( hDC, pInstText, -1, &InstRect,
+ DT_LEFT | DT_NOPREFIX | DT_SINGLELINE | DT_VCENTER );
+
+ /* if a bitmap was defined, draw the bitmap centered */
+
+ if ( wInstBitMap != 0 ) {
+ RSM_BitmapDrawCentered ( (WORD)(wInstBitMap + BTNFACE_BACKGND),
+ nInstIconX,
+ 0,
+ GetSystemMetrics( SM_CXICON ),
+ GetSystemMetrics( SM_CYICON ),
+ hDC );
+ }
+
+ if ( wType & WMMB_INSTBIG ) {
+ DeleteObject( SelectObject( hDC, hFont ) );
+ }
+ ReleaseDC( hWndInst, hDC );
+ }
+ break; /* pass the message along */
+ }
+ }
+ return FALSE; /* message not processed (or more required) */
+}
+
+
+static INT MB_SetButtons (
+
+HWND hDlg,
+WORD wType,
+INT *nButsBot,
+DS_MESSAGE_PTR pMessage )
+
+{
+ INT nTemp;
+ INT nDefaultWidth;
+ CHAR szButton1[WMMB_MAX_BUTTON]; /* used for loading resources */
+ CHAR szButton2[WMMB_MAX_BUTTON]; /* used for loading resources */
+ CHAR szHelpButton[WMMB_MAX_BUTTON]; /* used for loading resources */
+ HDC hDC;
+ RECT rc;
+
+ // Clear out the button text strings.
+
+ szButton1[0] = 0;
+ szButton2[0] = 0;
+ szHelpButton[0] = 0;
+
+ // Set the button text based on the wType.
+
+ // The YES NO button group.
+
+ if ( wType & WMMB_YESNO ) {
+ RSM_StringCopy( IDS_BUT_YES, szButton1, sizeof ( szButton1 ) );
+ RSM_StringCopy( IDS_BUT_NO, szButton2, sizeof ( szButton2 ) );
+ }
+
+
+ // The ABORT first button group.
+
+ if ( wType & WMMB_ABORTRETRYIGNOR ) {
+ RSM_StringCopy( IDS_BUT_ABORT, szButton1, sizeof ( szButton1 ) );
+ }
+
+ // The OK first button group.
+
+ if ( wType & ( WMMB_OK | WMMB_OKCANCEL | WMMB_OKDISABLE ) ) {
+ RSM_StringCopy( IDS_BUT_OK, szButton1, sizeof ( szButton1 ) );
+ }
+
+ // The RETRY first button group.
+
+ if ( wType & WMMB_RETRYCANCEL ) {
+ RSM_StringCopy( IDS_BUT_RETRY, szButton1, sizeof ( szButton1 ) );
+ }
+
+ // The CONTINUE first button group.
+
+ if ( wType & ( WMMB_CONTABORT | WMMB_CONTCANCEL ) ) {
+ RSM_StringCopy( IDS_BUT_CONTINUE, szButton1, sizeof ( szButton1 ) );
+ }
+
+ // The RETRY second button group.
+
+ if ( wType & WMMB_ABORTRETRYIGNOR ) {
+ RSM_StringCopy( IDS_BUT_RETRY, szButton2, sizeof ( szButton2 ) );
+ }
+
+ // The CANCEL second button group.
+
+ if ( wType & ( WMMB_OKCANCEL | WMMB_RETRYCANCEL | WMMB_CONTCANCEL ) ) {
+ RSM_StringCopy( IDS_BUT_CANCEL, szButton2, sizeof ( szButton2 ) );
+ }
+
+ // The ABORT second button group.
+
+ if ( wType & WMMB_CONTABORT ) {
+ RSM_StringCopy( IDS_BUT_ABORT, szButton2, sizeof ( szButton2 ) );
+ }
+
+ // The DISABLE second button group.
+
+ if ( wType & WMMB_OKDISABLE ) {
+ RSM_StringCopy( IDS_BUT_DISABLE, szButton2, sizeof ( szButton2 ) );
+ }
+
+ SetDlgItemText ( hDlg, IDD_MSG_BUT1, szButton1 );
+
+ if ( !(wType & WMMB_OK) ) {
+ SetDlgItemText ( hDlg, IDD_MSG_BUT2, szButton2 );
+ ShowWindow( GetDlgItem( hDlg, IDD_MSG_BUT2 ), SW_SHOWNOACTIVATE );
+ }
+
+ // The IGNORE Third button group.
+
+ if ( wType & WMMB_ABORTRETRYIGNOR ) {
+ RSM_StringCopy( IDS_BUT_IGNORE, szHelpButton, sizeof ( szHelpButton ) );
+ SetDlgItemText ( hDlg, IDD_MSG_BUT3, szHelpButton );
+ ShowWindow ( GetDlgItem( hDlg, IDD_MSG_BUT3 ), SW_SHOWNOACTIVATE );
+ *nButsBot = *nButsBot + 1;
+
+ }
+
+ if ( pMessage->wHelpID ) {
+
+ RSM_StringCopy ( IDS_BUT_HELP, szHelpButton, sizeof ( szHelpButton ) );
+
+ if ( wType & WMMB_OK ) {
+ mwwHelpButID = IDD_MSG_BUT2;
+ }
+ else {
+ mwwHelpButID = IDD_MSG_BUT3;
+ *nButsBot = *nButsBot + 1;
+ }
+
+ mwwHelpID = pMessage->wHelpID;
+
+ SetDlgItemText ( hDlg, mwwHelpButID, szHelpButton );
+ ShowWindow ( GetDlgItem( hDlg, mwwHelpButID ), SW_SHOWNOACTIVATE );
+
+ }
+ else {
+
+ mwwHelpButID = 0;
+ mwwHelpID = 0;
+
+ }
+
+ // Get the default width of the buttons.
+
+ GetClientRect ( GetDlgItem ( hDlg, IDD_MSG_BUT1 ), &rc );
+
+ nDefaultWidth = rc.right - rc.left;
+
+ hDC = GetDC ( GetDlgItem ( hDlg, IDD_MSG_BUT1 ) );
+
+ // Get the button text widths.
+
+ nTemp = MB_GetMaxButtonExtent ( hDC, szButton1, nDefaultWidth );
+ nTemp = MB_GetMaxButtonExtent ( hDC, szButton2, nTemp );
+ nTemp = MB_GetMaxButtonExtent ( hDC, szHelpButton, nTemp );
+
+ ReleaseDC ( hDlg, hDC );
+
+ return nTemp;
+}
+
+
+
+static INT MB_GetMaxButtonExtent (
+
+HDC hDC,
+LPSTR lpString,
+INT nOldWidth )
+
+{
+ INT nTemp;
+ SIZE sizeRect; // Return from GetTextExtentPoint
+
+// HFONT hFont = (HFONT) GetStockObject ( SYSTEM_FONT );
+// nTemp = RSM_GetFontStringWidth ( hFont, lpString, strlen ( lpString ) );
+
+ // Get the text extent width and height.
+
+ GetTextExtentPoint ( hDC, lpString, strlen ( lpString ), &sizeRect );
+
+ nTemp = sizeRect.cx;
+
+ // Now add in the 3D borders.
+
+ nTemp += ( 2 * ( BUTTON_BORDERWIDTH + 2 ) );
+
+ if ( nTemp < nOldWidth ) {
+
+ nTemp = nOldWidth;
+ }
+
+ return nTemp;
+}
diff --git a/private/utils/ntbackup/src/msgbox.dlg b/private/utils/ntbackup/src/msgbox.dlg
new file mode 100644
index 000000000..0494d54d9
--- /dev/null
+++ b/private/utils/ntbackup/src/msgbox.dlg
@@ -0,0 +1,52 @@
+
+/**************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+JPW
+
+ Name: msgbox.dlg
+
+ Description: This file contains the dialog template for the
+ generic message box.
+
+ $Log: G:\UI\LOGFILES\MSGBOX.DLV $
+
+ Rev 1.7 28 Jan 1994 17:23:36 Glenn
+ Simplified and fixed Icon support.
+
+ Rev 1.6 10 May 1993 13:24:28 CHUCKB
+ Don't process & for every control.
+
+ Rev 1.5 18 Dec 1992 11:16:42 chrish
+ Moved #include to dialogs.rc
+
+ Rev 1.4 10 Jun 1992 14:30:30 JOHNWT
+ changed font
+
+ Rev 1.3 27 Apr 1992 18:51:40 STEVEN
+ NTKLUG for font type
+
+ Rev 1.2 06 Apr 1992 10:08:46 CHUCKB
+ Fixed include list.
+
+ Rev 1.1 27 Jan 1992 00:46:40 CHUCKB
+ Updated dialog id's.
+
+ Rev 1.0 20 Nov 1991 19:18:22 SYSTEM
+ Initial revision.
+
+**************************************************************************/
+
+IDD_MESSAGE_BOX DIALOG 38, 64, 241, 62
+STYLE DS_ABSALIGN | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION |
+ WS_SYSMENU
+CAPTION "Message"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ ICON 0, IDD_MSG_ICON, 8, 8, 20, 20
+ LTEXT "", IDD_MSG_TEXT, 30, 8, 164, 26, SS_NOPREFIX
+ LTEXT "", IDD_MSG_INST, 30, 44, 164, 10, NOT WS_VISIBLE | SS_NOPREFIX
+ DEFPUSHBUTTON "", IDD_MSG_BUT1, 200, 6, 35, 14
+ PUSHBUTTON "", IDD_MSG_BUT2, 200, 24, 35, 14, NOT WS_VISIBLE
+ PUSHBUTTON "", IDD_MSG_BUT3, 200, 42, 35, 14, NOT WS_VISIBLE
+END
+
diff --git a/private/utils/ntbackup/src/msmktemp.c b/private/utils/ntbackup/src/msmktemp.c
new file mode 100644
index 000000000..9f5ee3139
--- /dev/null
+++ b/private/utils/ntbackup/src/msmktemp.c
@@ -0,0 +1,72 @@
+/*
+
+ $Log: T:/LOGFILES/MSMKTEMP.C_V $
+
+ Rev 1.1 26 Oct 1993 23:37:16 GREGG
+Mod the process id with 0xFFFF just in case it's larger.
+
+ Rev 1.0 14 Oct 1993 18:20:16 GREGG
+Initial revision.
+
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <process.h>
+#include <io.h>
+#include <errno.h>
+
+#include "stdtypes.h"
+#include "msmktemp.h"
+
+CHAR_PTR msmktemp( CHAR_PTR template )
+{
+ CHAR_PTR ptr ;
+ int i ;
+ int ret ;
+ int len ;
+ BOOLEAN success = FALSE ;
+ CHAR rep_str[41] ;
+
+ strcpy( rep_str, TEXT("0123456789abcdefghijklmnopqrstuvwxyz$_!-") ) ;
+
+ if( template == NULL || strlen( template ) < 8 ) {
+ return( NULL ) ;
+ }
+
+ ptr = template + strlen( template ) - 1 ;
+ for( i = 0; i < 5; i++, ptr-- ) {
+ if( *ptr != TEXT('X') ) {
+ return( NULL ) ;
+ }
+ }
+ if( *ptr != TEXT('X') ) {
+ return( NULL ) ;
+ }
+
+#if defined( OS_WIN32 )
+
+ sprintf( ptr, TEXT(" %05d"), _getpid( ) % 0xFFFF ) ;
+
+#elif defined( OS_NLM )
+
+ sprintf( ptr, TEXT(" %05d"), GetNLMHandle( ) % 0xFFFF ) ;
+
+#endif
+
+ len = strlen( rep_str ) ;
+ for( i = 0; !success && i < len; i++ ) {
+ *ptr = rep_str[i] ;
+ if( access( template, 0 ) == -1 && errno == ENOENT ) {
+ success = TRUE ;
+ }
+ }
+
+ if( success ) {
+ return( template ) ;
+ }else {
+ return( NULL ) ;
+ }
+}
+
diff --git a/private/utils/ntbackup/src/mtf10wdb.c b/private/utils/ntbackup/src/mtf10wdb.c
new file mode 100644
index 000000000..5f8a7bf20
--- /dev/null
+++ b/private/utils/ntbackup/src/mtf10wdb.c
@@ -0,0 +1,1639 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: mtf40wdb.c
+
+ Description: Contains the Code for writing Maynard 4.0 Format.
+
+
+ $Log: T:\logfiles\mtf10wdb.c_v $
+
+ Rev 1.24.1.3 11 Jan 1994 13:35:54 GREGG
+Changed asserts to mscasserts.
+
+ Rev 1.24.1.2 16 Nov 1993 22:23:50 GREGG
+Modified the way we control hardware compression from software to work around
+a bug in Archive DAT DC firmware rev. 3.58 (we shipped a lot of them).
+Files Modified: lw_data.c, lw_data.h, tfstuff.c, mtf10wdb.c, mtf10wt.c and
+ drives.c
+
+ Rev 1.24.1.1 02 Nov 1993 12:34:58 GREGG
+Translate file dblk attribs under DOS and OS2 to and from MTF.
+
+ Rev 1.24.1.0 09 Sep 1993 17:51:44 GREGG
+Call WriteInit before InitTape so if we get an early OTC failure we don't
+leave a tape with just a tape header on it.
+
+ Rev 1.24 22 Jul 1993 12:14:44 ZEIR
+ad'd lw_software_name logic
+
+ Rev 1.23 17 Jul 1993 17:57:00 GREGG
+Changed write translator functions to return INT16 TFLE_xxx errors instead
+of BOOLEAN TRUE/FALSE. Files changed:
+ MTF10WDB.C 1.23, TRANSLAT.H 1.22, F40PROTO.H 1.30, FMTENG.H 1.23,
+ TRANSLAT.C 1.43, TFWRITE.C 1.68, MTF10WT.C 1.18
+
+ Rev 1.22 04 Jul 1993 03:48:34 GREGG
+Fixed setting of file_id and directory_id in DIRB, FILE and CFIL structs.
+
+ Rev 1.21 04 Jul 1993 03:35:40 GREGG
+Reset lb_size in channel and EOS_AT_EOM bits when writing cont tape header.
+
+ Rev 1.20 20 Jun 1993 16:15:22 GREGG
+Added setting of vendor id in SSET, and removed setting of compression algor.
+
+ Rev 1.19 20 Jun 1993 16:08:12 GREGG
+Unicode fixes.
+
+ Rev 1.18 18 Jun 1993 17:14:48 GREGG
+Reset append attrib when overwriting tape.
+
+ Rev 1.17 28 May 1993 18:06:18 ZEIR
+Made software_package changes UNICODE compliant
+
+ Rev 1.16 24 May 1993 13:25:50 GREGG
+In InitTape we were resetting max_otc_level on continuation tapes.
+
+ Rev 1.15 19 May 1993 14:20:10 ZEIR
+cx'd vendor_id to conner_software_vendor_id
+
+ Rev 1.14 18 May 1993 15:52:24 ZEIR
+More MTF clean-up...
+ a) F40_InitTape now inits software_package for Nostradamus only (currently)
+ b) SetupDBHeader ensures os_spec_data_offset is 0 if there's no data
+ c) F40_WtSSet had a few non-sensical channel assignments removed
+ d) usage of local macro LongAlignOffset improved throughout compiland
+
+ Rev 1.13 12 May 1993 12:14:06 GREGG
+Set 'last_sset_pba' in WtSSET to fix faulty determination of incompatible
+drive during fast append.
+
+ Rev 1.12 29 Apr 1993 22:26:58 GREGG
+Set the Tape Catalog Version in the VCB.
+
+ Rev 1.11 27 Apr 1993 02:17:14 GREGG
+Don't put SSET attribs in VOLB.
+
+ Rev 1.10 26 Apr 1993 11:45:52 GREGG
+Seventh in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Changed handling of EOM processing during non-OTC EOS processing.
+
+Matches CHANNEL.H 1.17, MAYN40RD.C 1.60, TFWRITE.C 1.63, MTF.H 1.5,
+ TFLUTILS.C 1.44, MTF10WDB.C 1.10, MTF10WT.C 1.9
+
+ Rev 1.9 25 Apr 1993 20:12:26 GREGG
+Fifth in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Store the corrupt stream number in the CFIL tape struct and the CFDB.
+
+Matches: MTF10WDB.C 1.9, FSYS.H 1.33, FSYS_STR.H 1.47, MAKECFDB.C 1.2,
+ BACK_OBJ.C 1.36, MAYN40RD.C 1.58
+
+ Rev 1.8 25 Apr 1993 17:36:02 GREGG
+Fourth in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Parse the device name and volume name out of the FS supplied "volume
+ name", and write it to tape as separate fields.
+ - Generate the "volume name" the FS and UI expect out of the device
+ name and volume name on tape.
+ - Write all strings without NULL terminater, and translate them back
+ to NULL terminated strings on the read side.
+
+Matches: MTF10WDB.C 1.8, F40PROTO.H 1.26, OTC40WT.C 1.24, MAYN40.H 1.33,
+ MAYN40RD.C 1.57, OTC40RD.C 1.25
+
+ Rev 1.7 22 Apr 1993 03:31:20 GREGG
+Third in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Removed all references to the DBLK element 'string_storage_offset',
+ which no longer exists.
+ - Check for incompatable versions of the Tape Format and OTC and deals
+ with them the best it can, or reports tape as foreign if they're too
+ far out. Includes ignoring the OTC and not allowing append if the
+ OTC on tape is a future rev, different type, or on an alternate
+ partition.
+ - Updated OTC "location" attribute bits, and changed definition of
+ CFIL to store stream number instead of stream ID.
+
+Matches: TFL_ERR.H 1.9, MTF10WDB.C 1.7, TRANSLAT.C 1.39, FMTINF.H 1.11,
+ OTC40RD.C 1.24, MAYN40RD.C 1.56, MTF10WT.C 1.7, OTC40MSC.C 1.20
+ DETFMT.C 1.13, MTF.H 1.4
+
+ Rev 1.6 18 Apr 1993 00:38:58 GREGG
+First in a series of incremental changes to bring the translator in line
+with the MTF spec:
+ - Rewrote F40_InitTape:
+ - Stop using SetupDBHeader to set up the Tape Header (needs
+ special setup specific to that DBLK).
+ - Cleaned up logic.
+ - Set string_storage_offset properly in all DBLKs.
+ - Pass UINT8_PTR instead of CHAR_PTR to F40_SaveLclName.
+
+Matches: MTF10WT.C 1.6, MAYN40RD.C 1.53, MAYN40.H 1.31 and F40PROTO.H 1.25
+
+ Rev 1.5 17 Apr 1993 19:41:34 GREGG
+In F40_WtCFIL tell SetupDBHeader that there will never be associated data.
+
+ Rev 1.4 14 Apr 1993 02:00:04 GREGG
+Fixes to deal with non-ffr tapes in ffr drives (i.e. EXB2200 in EXB5000).
+
+ Rev 1.3 18 Mar 1993 15:17:50 ChuckS
+OS_NLM (for now): Added code to get dev name out of VCB
+
+ Rev 1.2 09 Mar 1993 18:36:18 GREGG
+Was calling FS_ViewDataEncrypt to get password encryption algorithm.
+
+ Rev 1.1 28 Jan 1993 11:39:40 GREGG
+Set the Tape Cat Level and Set Cat Valid fields while writing the SSET.
+
+ Rev 1.0 27 Jan 1993 14:37:42 GREGG
+Half of mayn40wt.c.
+
+
+**/
+/* begin include list */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "stdtypes.h"
+#include "stdmacro.h"
+#include "fsys.h"
+#include "tbe_defs.h"
+#include "datetime.h"
+
+#include "drive.h"
+#include "channel.h"
+#include "fmteng.h"
+#include "mayn40.h"
+#include "f40proto.h"
+#include "transutl.h"
+#include "tloc.h"
+#include "lw_data.h"
+#include "tfldefs.h"
+#include "lwprotos.h"
+#include "sx.h"
+#include "tfl_err.h"
+
+/* Device Driver InterFace Headers */
+#include "retbuf.h"
+#include "special.h"
+#include "dilhwd.h"
+#include "drvinf.h"
+#include "generr.h"
+#include "genfuncs.h"
+#include "dil.h"
+#include "tdemo.h"
+#include "dddefs.h"
+/* $end$ include list */
+
+/*
+ * Define the test OTC level here 0 == none, 1 == partial, 2 == full
+*/
+#define TEST_OTC_LEVEL 2
+
+/* Size required to pad to next logical block */
+#define PadToLBBoundary( x ) PadToBoundary( (x), F40_LB_SIZE )
+
+/* Adjusts offset to next 4 byte boundary */
+#define LongAlignOffset( x ) ( (x) += PadToBoundary( (x), 4 ) )
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: SetupDBHeader
+
+ Description: This does all the setup necessary for the standard block
+ header. It also updates the used count in the buffer
+ pointer.
+
+ Returns: The amount of space the header used in the buffer.
+
+ Notes: THIS FUNCTION MUST BE CALLED AFTER ALL OTHER FIELDS ARE
+ FILLED OUT IN THE HEADER
+
+**/
+
+UINT16 SetupDBHeader(
+ UINT8_PTR block_type, /* four byte array */
+ CHANNEL_PTR channel, /* current Channel Structure */
+ DBLK_PTR cur_dblk, /* current DBLK */
+ MTF_DB_HDR_PTR cur_hdr, /* current tape block header structure */
+ UINT16 offset, /* space used by var string portion */
+ BOOLEAN data_to_follow, /* Is data to follow */
+ BOOLEAN continuation ) /* Continuation flag */
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ FSYS_HAND cur_fsys = channel->cur_fsys ;
+ UINT16 temp_os_id ;
+ UINT16 temp_os_ver ;
+
+
+ /* Setup the block type */
+ F40_SetBlkType( cur_hdr, block_type ) ;
+
+ cur_hdr->logical_block_address = U64_Init( channel->running_lba, 0L ) ;
+ FS_SetLBAinDBLK( cur_dblk, channel->running_lba ) ;
+
+ /* Let's get the OS specific info loaded in */
+ LongAlignOffset( offset ) ;
+
+ if( ( cur_hdr->os_specific_data.data_size =
+ (UINT16)FS_SizeofOS_InfoInDBLK( cur_fsys, cur_dblk ) ) != 0 ){
+
+ cur_hdr->os_specific_data.data_offset = offset ;
+ (VOID)FS_GetOS_InfoFromDBLK( cur_fsys, cur_dblk,
+ (UINT8_PTR)cur_hdr + offset ) ;
+ offset += cur_hdr->os_specific_data.data_size ;
+ LongAlignOffset( offset ) ;
+ }
+
+ (VOID)FS_GetOSid_verFromDBLK( cur_fsys, cur_dblk, &temp_os_id, &temp_os_ver ) ;
+ cur_hdr->machine_os_id = (UINT8)temp_os_id;
+ cur_hdr->machine_os_version = (UINT8)temp_os_ver ;
+
+ cur_hdr->session_id = U64_Init( 0L, 0L ) ;
+
+ cur_hdr->displayable_size = FS_GetDisplaySizeFromDBLK( cur_fsys, cur_dblk ) ;
+
+ cur_hdr->string_type = (UINT8)FS_GetStringTypes( cur_fsys ) ;
+
+ cur_hdr->block_attribs = 0L ;
+
+ if( continuation ) {
+ cur_hdr->block_attribs |= MTF_DB_CONT_BIT ;
+ if( IsChannelStatus( channel, CH_EOS_AT_EOM ) ) {
+ cur_hdr->block_attribs |= MTF_DB_EOS_AT_EOM_BIT ;
+ }
+ /* Setup Block ID, if its a continuation, don't increment it */
+ cur_hdr->control_block_id = channel->eom_id ;
+ data_to_follow = FALSE ;
+ } else {
+ cur_hdr->control_block_id = channel->eom_id++ ;
+ }
+
+ if( !data_to_follow ) {
+ offset += (UINT16)PadToLBBoundary( offset ) ;
+ } else {
+ cur_env->pad_size = (UINT16)PadToLBBoundary( offset ) ;
+ }
+
+
+ cur_hdr->offset_to_data = offset ;
+
+ /* Calculate the Header Check Sum */
+ cur_hdr->hdr_chksm = F40_CalcChecksum( (UINT16_PTR)cur_hdr, F40_HDR_CHKSUM_LEN ) ;
+
+ return( offset ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_InitTape
+
+ Description: Writes the TAPE tape header block to tape. Checks to
+ see if this is a continuation and if so doesn't generate
+ new information and sets the continuation attribute bit
+ in the block header. Copies the tape header information
+ to the global storage for things like tape name etc.
+
+ Notes:
+
+ Returns: INT16 - TFLE_xxx error code.
+
+**/
+INT16 F40_InitTape(
+ CHANNEL_PTR channel, /* Current active channel */
+ BOOLEAN continuation, /* I think we need the ability to flag cont*/
+ BUF_PTR tmpBUF )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ INT16 drv_hdl = channel->cur_drv->drv_hdl ;
+ RET_BUF myret ;
+ DRIVE_PTR curDRV = channel->cur_drv ;
+ DBLK_PTR cur_dblk = channel->cur_dblk ; /* Pointer to cur DBLK */
+ MTF_TAPE_PTR cur_tape ; /* Current tape header structure storage */
+ MTF_DB_HDR_PTR cur_hdr ;
+ UINT8_PTR vstr_ptr ;
+ UINT16 offset, date, time ;
+ INT16 lcl_ret_val ;
+ DATE_TIME temp_date ;
+ UINT16 temp_os_id ;
+ UINT16 temp_os_ver ;
+
+ /* If the drive supports hardware compression we need to keep it in
+ uncompressed mode unless we're actually writing a compressed set.
+ This is a work-around for a firmware bug in early Archive DAT DC
+ drives. If we are going to write a compressed set, we set it here.
+ */
+ if( lw_hw_comp && ( curDRV->thw_inf.drv_info.drv_features & TDI_DRV_COMPRESSION ) ) {
+ if( TpSpecial( drv_hdl, SS_SET_DRV_COMPRESSION,
+ ENABLE_DRV_COMPRESSION ) != SUCCESS ) {
+ return( TFLE_DRIVE_FAILURE ) ;
+ }
+ }
+
+ if( channel->tape_id != 0L && !continuation ) {
+ /* Get the PBA before writing the SSET. Note that in this case
+ we are appending, and if we didn't put position info in ANY
+ of the prior sets on tape, we're not going to put any in this
+ one either. We don't dare try because there are drives which
+ change their mind about whether or not TpGetPosition is a
+ valid command depending on the tape in the drive. So if the
+ prior sets don't have a PBA for the SSET, we assume it's
+ because that info isn't available. In order to write position
+ info when overwriting, the drive has to indicate it has the
+ Get and Seek Position features, even when it doesn't. So we
+ use this alternative method to tell. IDDI-NSMDI-YCPA
+ */
+ if( SupportBlkPos( curDRV ) &&
+ cur_env->last_sset_pba != 0UL ) {
+
+ ret_val = GetCurrentPosition( curDRV ) ;
+ } else {
+ curDRV->cur_pos.pba_vcb = 0 ;
+ }
+ return( ret_val ) ;
+ }
+
+ /* reinit the buffer */
+ BM_SetNextByteOffset( tmpBUF, 0 ) ;
+ memset( BM_XferBase( tmpBUF ), 0, BM_XferSize( tmpBUF ) ) ;
+
+ cur_tape = (MTF_TAPE_PTR)( BM_XferBase( tmpBUF ) ) ;
+ cur_hdr = (MTF_DB_HDR_PTR)cur_tape ;
+ vstr_ptr = ( BM_XferBase( tmpBUF ) ) ;
+ offset = sizeof( MTF_TAPE ) ;
+
+ channel->lb_size = F40_LB_SIZE ;
+ cur_env->eset_pba = 0L ;
+
+ /* Set up the TAPE BLOCK */
+ if( channel->tape_id == 0L ) {
+
+ msassert( !continuation ) ;
+
+ /* Here we do our own version of SetupDBHeader that does only what
+ we need, and not all the extranious stuff.
+ */
+ F40_SetBlkType( cur_hdr, MTF_TAPE_N ) ;
+
+ (VOID)FS_GetOSid_verFromDBLK( channel->cur_fsys, channel->cur_dblk, &temp_os_id, &temp_os_ver ) ;
+
+ cur_hdr->machine_os_id = (UINT8)temp_os_id;
+ cur_hdr->machine_os_version = (UINT8)temp_os_ver ;
+ cur_hdr->logical_block_address = U64_Init( 0L, 0L ) ;
+ cur_hdr->os_specific_data.data_offset = 0 ;
+ cur_hdr->os_specific_data.data_size = 0 ;
+ cur_hdr->session_id = U64_Init( 0L, 0L ) ;
+ cur_hdr->displayable_size = U64_Init( 0L, 0L ) ;
+ cur_hdr->string_type = (UINT8)FS_GetStringTypes( channel->cur_fsys ) ;
+ cur_hdr->block_attribs = 0L ;
+
+ /* Fill out general info */
+ cur_tape->software_vendor_id = CONNER_SOFTWARE_VENDOR_ID ;
+ cur_tape->tape_seq_number = 1 ;
+ cur_tape->logical_block_size = F40_LB_SIZE ;
+ cur_tape->tf_major_ver = FORMAT_VER_MAJOR ;
+ cur_tape->ecc_algorithm = ECC_NONE ;
+ cur_tape->tape_catalog_type = MTF10_OTC ;
+ cur_tape->tape_attributes = 0L ;
+ cur_tape->password_encryption_algor =
+ FS_ViewPswdEncryptInVCB( (VCB_PTR)cur_dblk ) ;
+
+ /* Get backup date */
+ GetCurrentDate( &temp_date ) ;
+ DateToTapeDate( &cur_tape->tape_date, &temp_date ) ;
+
+ /* Generate tape ID */
+ DOSDateTime( &temp_date, &date, &time ) ;
+#ifdef TDEMO
+ cur_tape->tape_id_number = ( (UINT32)date << 16 ) |
+ ( (UINT32)time & 0xFFFC ) |
+ TdemoGeneratedTapeId( ) ;
+#else
+ cur_tape->tape_id_number = ( ( (UINT32)date << 16 ) |
+ ( (UINT32)time ) ) ;
+#endif
+
+ /* Setup string data. NOTE: On strings other than the password we
+ decrement the size to leave off the '\0'.
+ */
+ cur_tape->tape_name.data_size = FS_SizeofTapeNameInVCB( (VCB_PTR)cur_dblk ) ;
+ if( cur_tape->tape_name.data_size != 0 ) {
+ cur_tape->tape_name.data_size -= sizeof( CHAR ) ;
+ cur_tape->tape_name.data_offset = offset ;
+ FS_GetTapeNameInVCB( cur_dblk, (CHAR_PTR)( (INT8_PTR)vstr_ptr + offset ) ) ;
+ offset += cur_tape->tape_name.data_size ;
+ if( ( lcl_ret_val =
+ F40_SaveLclName( &cur_env->tape_name,
+ (UINT8_PTR)( vstr_ptr +
+ cur_tape->tape_name.data_offset ),
+ &cur_env->tape_name_size,
+ &cur_env->tape_name_alloc,
+ cur_tape->tape_name.data_size ) )
+ != TFLE_NO_ERR ) {
+
+ return lcl_ret_val ;
+ }
+ } else {
+ cur_env->tape_name_size = 0 ;
+ cur_tape->tape_name.data_offset = 0 ;
+ }
+
+ /* For now we have no tape description */
+ cur_tape->tape_description.data_offset = 0 ;
+ cur_tape->tape_description.data_size = 0 ;
+
+ cur_tape->tape_password.data_size = FS_SizeofTapePswdInVCB( (VCB_PTR)cur_dblk ) ;
+ if( cur_tape->tape_password.data_size != 0 ) {
+ cur_tape->tape_password.data_offset = offset ;
+ FS_GetTapePswdInVCB( cur_dblk, (CHAR_PTR)( (INT8_PTR)vstr_ptr + offset ) ) ;
+ offset += cur_tape->tape_password.data_size ;
+ if( ( lcl_ret_val =
+ F40_SaveLclName( &cur_env->tape_password,
+ (UINT8_PTR)( vstr_ptr +
+ cur_tape->tape_password.data_offset ),
+ &cur_env->tape_password_size,
+ &cur_env->tape_password_alloc,
+ cur_tape->tape_password.data_size ) )
+ != TFLE_NO_ERR ) {
+
+ return lcl_ret_val ;
+ }
+ } else {
+ cur_env->tape_password_size = 0 ;
+ cur_tape->tape_password.data_offset = 0 ;
+ }
+
+ cur_tape->software_name.data_size = lw_software_name_len * sizeof(CHAR) ;
+ if( lw_software_name != NULL ){
+ cur_tape->software_name.data_offset = offset ;
+ memcpy( (UINT8_PTR)( vstr_ptr + offset ), lw_software_name,
+ cur_tape->software_name.data_size ) ;
+ offset += cur_tape->software_name.data_size ;
+ }else{
+ cur_tape->software_name.data_offset = 0 ;
+ }
+
+ /* Set block specific attribs to indicate OTC level allowed */
+ if( cur_env->max_otc_level != TCL_NONE ) {
+ cur_tape->block_header.block_attribs |= MTF_DB_SM_EXISTS ;
+ if( cur_env->max_otc_level == TCL_FULL ) {
+ cur_tape->block_header.block_attribs |= MTF_DB_FDD_ALLOWED ;
+ }
+ }
+
+ /* Copy current tape header to environment */
+ cur_env->tape_hdr = *cur_tape ;
+
+ /* Set the channel stuff */
+ channel->bs_num = channel->ts_num = 1 ;
+ channel->tape_id = (INT32)cur_tape->tape_id_number ;
+
+ } else {
+ /* We need to get the last TAPE HEADER info and update the
+ appropriate fields.
+ */
+ *cur_tape = cur_env->tape_hdr ;
+ cur_env->tape_hdr.tape_seq_number = (UINT16)channel->ts_num ;
+ cur_tape->tape_seq_number = (UINT16)channel->ts_num ;
+ if( cur_env->tape_name_size != 0 ) {
+ memcpy( (UINT8_PTR)( vstr_ptr + offset ), cur_env->tape_name,
+ cur_env->tape_name_size ) ;
+ offset += cur_env->tape_name_size ;
+ }
+ if( cur_env->tape_password_size != 0 ) {
+ memcpy( (UINT8_PTR)( vstr_ptr + offset ), cur_env->tape_password,
+ cur_env->tape_password_size ) ;
+ offset += cur_env->tape_password_size ;
+ }
+
+ cur_tape->software_name.data_size = lw_software_name_len * sizeof(CHAR) ;
+ if( lw_software_name != NULL ){
+ cur_tape->software_name.data_offset = offset ;
+ memcpy( (UINT8_PTR)( vstr_ptr + offset ), lw_software_name,
+ cur_tape->software_name.data_size ) ;
+ offset += cur_tape->software_name.data_size ;
+ }else{
+ cur_tape->software_name.data_offset = 0 ;
+ }
+
+ cur_hdr->block_attribs |= MTF_DB_CONT_BIT ;
+ if( IsChannelStatus( channel, CH_EOS_AT_EOM ) ) {
+ cur_hdr->block_attribs |= MTF_DB_EOS_AT_EOM_BIT ;
+ } else {
+ cur_hdr->block_attribs &= ~MTF_DB_EOS_AT_EOM_BIT ;
+ }
+ }
+
+ FS_SetTSNumInVCB( (DBLK_PTR)channel->lst_osvcb, channel->ts_num ) ;
+
+ /* Here we need to adjust the offset_to_data field to insure we write
+ a full physical block.
+ */
+ offset += (UINT16)PadToLBBoundary( offset ) ;
+ cur_hdr->offset_to_data = offset +
+ PadToBoundary( offset, ChannelBlkSize( channel ) ) ;
+
+ /* Recalculate the Header Check Sum */
+ cur_hdr->hdr_chksm = F40_CalcChecksum( (UINT16_PTR)cur_tape, F40_HDR_CHKSUM_LEN ) ;
+
+ BM_UpdCnts( tmpBUF, cur_tape->block_header.offset_to_data ) ;
+
+ DRIVER_CALL( drv_hdl, TpWrite( drv_hdl, BM_XferBase( tmpBUF ), BM_NextByteOffset( tmpBUF ) ),
+ myret, GEN_NO_ERR, GEN_NO_ERR, (void)0 )
+
+ /* Once we've successfully written the header, it is one of our tapes.
+ It may have been a tape we didn't allow append to before, so we need
+ to reset the bit that says we can.
+ */
+ lw_fmtdescr[channel->cur_fmt].attributes |= APPEND_SUPPORTED ;
+
+ if( ( ret_val = WriteEndSet( curDRV ) ) == TFLE_NO_ERR ) {
+
+ /* Get the PBA before writing the SSET. */
+ if( SupportBlkPos( channel->cur_drv ) ) {
+ ret_val = GetCurrentPosition( curDRV ) ;
+ } else {
+ channel->cur_drv->cur_pos.pba_vcb = 0 ;
+ }
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_WtVOLB
+
+ Description: Translates a DBLK in a format 4.0 VOLB.
+
+ Returns: INT16 TFLE_xxx error code.
+
+ Notes: None.
+
+**/
+INT16 F40_WtVOLB(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer,
+ BOOLEAN continuation,
+ UINT16_PTR offset ) /* Pointer to offset passed in */
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ DBLK_PTR cur_dblk = channel->cur_dblk ; /* Pointer to cur DBLK */
+ FSYS_HAND cur_fsys = channel->cur_fsys ;
+ MTF_DB_HDR_PTR cur_hdr ;
+ MTF_VOL_PTR cur_volb ;
+ UINT8_PTR vstr_ptr ;
+ UINT16 v_offset ;
+ DATE_TIME temp_date ;
+ UINT16 temp_os_id ;
+ UINT16 temp_os_ver ;
+
+ cur_volb = (MTF_VOL_PTR)( BM_NextBytePtr( buffer ) ) ;
+ cur_hdr = (MTF_DB_HDR_PTR)cur_volb ;
+ vstr_ptr = (UINT8_PTR)cur_volb ;
+ v_offset = sizeof( MTF_VOL ) ;
+
+ if( !continuation ) {
+ channel->running_lba += F40_CalcRunningLBA( cur_env ) ;
+ }
+
+ /* Get Backup Date */
+ GetCurrentDate( &temp_date ) ;
+ DateToTapeDate( &cur_volb->backup_date, &temp_date ) ;
+
+
+ /* Setup string data. NOTE: On strings other than the password we
+ decrement the size to leave off the '\0'.
+ */
+
+#if defined( OS_NLM )
+
+ /* Device Name */
+ cur_volb->device_name.data_size = FS_SizeofDevNameInVCB( (VCB_PTR) cur_dblk ) ;
+ if( cur_volb->device_name.data_size != 0 ) {
+ cur_volb->device_name.data_size -= sizeof( CHAR ) ;
+ cur_volb->device_name.data_offset = v_offset ;
+ FS_GetDevNameInVCB( cur_dblk, (CHAR_PTR)( (INT8_PTR) vstr_ptr + v_offset ) ) ;
+ if( ( ret_val = F40_SaveLclName( &cur_env->device_name,
+ (UINT8_PTR)( vstr_ptr + v_offset ),
+ &cur_env->device_name_size,
+ &cur_env->device_name_alloc,
+ cur_volb->device_name.data_size ) ) != TFLE_NO_ERR ) {
+
+ return( ret_val ) ;
+ }
+ v_offset += cur_volb->device_name.data_size ;
+ } else {
+ cur_env->device_name_size = 0 ;
+ cur_volb->device_name.data_offset = 0 ;
+ }
+
+ /* Volume Name */
+ cur_volb->volume_name.data_size = FS_SizeofVolNameInVCB( (VCB_PTR)cur_dblk ) ;
+ if( cur_volb->volume_name.data_size != 0 ) {
+ cur_volb->volume_name.data_size -= sizeof( CHAR ) ;
+ cur_volb->volume_name.data_offset = v_offset ;
+ FS_GetVolNameInVCB( cur_dblk, (CHAR_PTR)( (INT8_PTR)vstr_ptr + v_offset ) ) ;
+ if( ( ret_val = F40_SaveLclName( &cur_env->vol_name,
+ (UINT8_PTR)( vstr_ptr + v_offset ),
+ &cur_env->vol_name_size,
+ &cur_env->vol_name_alloc,
+ cur_volb->volume_name.data_size ) ) != TFLE_NO_ERR ) {
+
+ return( ret_val ) ;
+ }
+ v_offset += cur_volb->volume_name.data_size ;
+ } else {
+ cur_env->vol_name_size = 0 ;
+ cur_volb->volume_name.data_offset = 0 ;
+ }
+
+#else
+
+ /* If we have a volume name, it is actually of the form
+ "<device name><space><volume name>". We have to do some fiddling
+ here to put it on tape as a device name and volume name.
+
+ !!!!NOTE : We "know the device name is "<drive letter>:" for CAYMAN
+ and NOSTRADAMUS ONLY!!! All other products using this
+ BE will have to provide us with the device name and
+ volume name separately (as the NLM does above).
+ */
+ cur_volb->volume_name.data_size = FS_SizeofVolNameInVCB( (VCB_PTR)cur_dblk ) ;
+ if( cur_volb->volume_name.data_size != 0 ) {
+ CHAR UNALIGNED *temp_vol_name;
+
+ /* Device Name */
+ temp_vol_name = (CHAR_PTR)( (INT8_PTR)vstr_ptr + v_offset ) ;
+ FS_GetVolNameInVCB( cur_dblk, temp_vol_name ) ;
+ cur_volb->device_name.data_offset = v_offset ;
+
+ if ( temp_vol_name[1] == TEXT(':') ) {
+ cur_volb->device_name.data_size = 2 * sizeof( CHAR ) ;
+ } else {
+ cur_volb->device_name.data_size = cur_volb->volume_name.data_size ;
+ }
+
+ if( ( ret_val = F40_SaveLclName( &cur_env->device_name,
+ (UINT8_PTR)( vstr_ptr + v_offset ),
+ &cur_env->device_name_size,
+ &cur_env->device_name_alloc,
+ cur_volb->device_name.data_size ) ) != TFLE_NO_ERR ) {
+
+ return( ret_val ) ;
+ }
+ v_offset += cur_volb->device_name.data_size ;
+
+ cur_volb->volume_name.data_size -= cur_volb->device_name.data_size
+ + sizeof( CHAR ) ;
+
+ if( ( temp_vol_name[1] == TEXT(':') ) &&
+ (cur_volb->volume_name.data_size > sizeof( CHAR ) ) ) {
+
+ /* Shift Volume Name back over the space character */
+ cur_volb->volume_name.data_size -= sizeof( CHAR ) ;
+ memmove( vstr_ptr + v_offset, vstr_ptr + v_offset + sizeof( CHAR ),
+ cur_volb->volume_name.data_size ) ;
+
+ cur_volb->volume_name.data_offset = v_offset ;
+ if( ( ret_val = F40_SaveLclName( &cur_env->vol_name,
+ (UINT8_PTR)( vstr_ptr + v_offset ),
+ &cur_env->vol_name_size,
+ &cur_env->vol_name_alloc,
+ cur_volb->volume_name.data_size ) ) != TFLE_NO_ERR ) {
+
+ return( ret_val ) ;
+ }
+ v_offset += cur_volb->volume_name.data_size ;
+
+ } else {
+ cur_env->vol_name_size = 0 ;
+ cur_volb->volume_name.data_size = 0 ;
+ cur_volb->volume_name.data_offset = 0 ;
+ }
+ } else {
+ cur_env->device_name_size = 0 ;
+ cur_volb->device_name.data_size = 0 ;
+ cur_volb->device_name.data_offset = 0 ;
+ cur_env->vol_name_size = 0 ;
+ cur_volb->volume_name.data_offset = 0 ;
+ }
+
+#endif
+
+ cur_volb->machine_name.data_size = FS_SizeofMachNameInVCB( (VCB_PTR)cur_dblk ) ;
+ if( cur_volb->machine_name.data_size != 0 ) {
+ cur_volb->machine_name.data_size -= sizeof( CHAR ) ;
+ cur_volb->machine_name.data_offset = v_offset ;
+ FS_GetMachNameInVCB( cur_dblk, (CHAR_PTR)( (INT8_PTR)vstr_ptr + v_offset ) ) ;
+
+ if( ( ret_val = F40_SaveLclName( &cur_env->machine_name,
+ (UINT8_PTR)( vstr_ptr + v_offset ),
+ &cur_env->machine_name_size,
+ &cur_env->machine_name_alloc,
+ cur_volb->machine_name.data_size ) ) != TFLE_NO_ERR ) {
+
+ return( ret_val ) ;
+ }
+ v_offset += cur_volb->machine_name.data_size ;
+ } else {
+ cur_env->machine_name_size = 0 ;
+ cur_volb->machine_name.data_offset = 0 ;
+ }
+
+
+ cur_volb->volume_attribs = 0 ;
+
+ /* Here we do our own version of SetupDBHeader that does only what
+ we need, and not all the extranious stuff.
+ */
+
+ F40_SetBlkType( cur_hdr, MTF_VOLB_N ) ;
+
+ (VOID)FS_GetOSid_verFromDBLK( cur_fsys, cur_dblk, &temp_os_id, &temp_os_ver ) ;
+
+ cur_hdr->machine_os_id = (UINT8)temp_os_id;
+ cur_hdr->machine_os_version = (UINT8)temp_os_ver ;
+ cur_hdr->logical_block_address = U64_Init( channel->running_lba, 0L ) ;
+ cur_hdr->os_specific_data.data_offset = 0 ;
+ cur_hdr->os_specific_data.data_size = 0 ;
+ cur_hdr->session_id = U64_Init( 0L, 0L ) ;
+ cur_hdr->displayable_size = U64_Init( 0L, 0L ) ;
+ cur_hdr->string_type = (UINT8)FS_GetStringTypes( cur_fsys ) ;
+ cur_hdr->block_attribs = 0L ;
+
+ if( continuation ) {
+ cur_hdr->block_attribs |= MTF_DB_CONT_BIT ;
+ /* Setup Block ID, if its a continuation, don't increment it */
+ cur_hdr->control_block_id = channel->eom_id ;
+ } else {
+ cur_hdr->control_block_id = channel->eom_id++ ;
+ }
+
+ v_offset += (UINT16)PadToLBBoundary( v_offset ) ;
+ cur_hdr->offset_to_data = v_offset ;
+
+ /* Calculate the Header Check Sum */
+ cur_hdr->hdr_chksm = F40_CalcChecksum( (UINT16_PTR)cur_hdr, F40_HDR_CHKSUM_LEN ) ;
+
+ *offset = v_offset ;
+
+ /* For later pad calculations */
+ if( !continuation ) {
+ cur_env->used_so_far = U64_Init( v_offset, 0L ) ;
+ }
+
+ /* Write OTC SM and FDD entry */
+ if( ret_val == TFLE_NO_ERR && cur_env->cur_otc_level != TCL_NONE
+ && !cur_env->sm_aborted ) {
+ ret_val = OTC_GenVolEntry( cur_env, cur_volb, channel->ts_num ) ;
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_WtSSET
+
+ Description: Translates a DBLK in a format 4.0 SSET.
+
+ Returns: INT16 TFLE_xxx error code.
+
+ Notes: I have two concerns about this function:
+
+ 1) I don't know if the translators should be
+ setting up the Tape ID, Tape Sequence, and
+ Backup Set NUmber. This seems to be a unit
+ violation, and also requires a writer of
+ of translator to know he must update the fields
+ in the channel, and in the "current dblk".
+
+ 2) I forgot what the second concern was. This really
+ concerns me.
+
+ If the field "channel->tape_id" is zero, this function
+ manufactures a tape_id, a backup set number, and tape
+ sequence number and sets the appropriate fields in
+ the channel structure. Note: It also needs to create
+ a TAPE HEADER DBLK and save the appropriate information
+ in an Enviornment that is never destroyed.
+
+ The TAPE HEADER must be written first, followed by
+ the SSET block. Then a VOLB block must be written
+ with the volume information.
+
+**/
+
+INT16 F40_WtSSET(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer,
+ BOOLEAN continuation )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ DBLK_PTR cur_dblk = channel->cur_dblk ; /* Pointer to cur DBLK */
+ DRIVE_PTR curDRV = channel->cur_drv ;
+ MTF_SSET_PTR cur_sset ;
+ FSYS_HAND cur_fsys = channel->cur_fsys ;
+ UINT8_PTR vstr_ptr ;
+ UINT16 offset ;
+ DATE_TIME temp_date ;
+ INT16 ret_val ;
+
+ if( channel->tape_id == 0L && !continuation ) {
+ cur_env->max_otc_level = TEST_OTC_LEVEL ;
+ }
+
+ /* Temporary way to stop OTC on drives that don't have seek capability */
+ if( !SupportBlkPos( curDRV ) ||
+ !SupportFastEOD( curDRV ) ||
+ !SupportRevFmk( curDRV ) ) {
+
+ if( cur_env->max_otc_level != TCL_NONE && continuation ) {
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ cur_env->max_otc_level = TCL_NONE ;
+ }
+
+ if( !continuation ) {
+ if( ( ret_val = F40_WriteInit( channel, TEST_OTC_LEVEL, buffer ) ) != TFLE_NO_ERR ) {
+ return( ret_val ) ;
+ }
+ }
+
+ if( ( ret_val = F40_InitTape( channel, continuation, buffer ) ) != TFLE_NO_ERR ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ return( ret_val ) ;
+ }
+
+ /* Now we need to get a pointer to the SSET in the buffer */
+ /* Here we are going to 'rewind' the pointer back to the start
+ of the buffer. We don't want the tape header to be rememebered.
+ */
+ BM_SetNextByteOffset( buffer, 0 ) ;
+ BM_SetBytesFree( buffer, BM_TFSize( buffer ) ) ;
+ memset( BM_XferBase( buffer ), 0, BM_XferSize( buffer ) ) ;
+ cur_sset = (MTF_SSET_PTR)( BM_XferBase( buffer ) ) ;
+ vstr_ptr = BM_XferBase( buffer ) ;
+ offset = sizeof( MTF_SSET ) ;
+
+ if( !continuation ) {
+ cur_env->used_so_far = U64_Init( 0L, 0L ) ;
+ }
+
+ if( !continuation ) {
+ channel->running_lba += F40_CalcRunningLBA( cur_env ) ;
+ }
+
+ /* Set based on information in the channel. The channel information
+ will have been properly setup by the call to F40_InitTape()
+ */
+
+ cur_sset->backup_set_number = (UINT16)channel->bs_num ;
+ cur_sset->time_zone = LOCAL_TZ ;
+
+ /* NOTE: On strings other than the password we decrement the size to
+ leave off the '\0'.
+ */
+
+ /* Backup Set Name */
+ if( ( cur_sset->backup_set_name.data_size =
+ FS_SizeofBackupSetNameInVCB( (VCB_PTR)cur_dblk ) ) != 0 ) {
+
+ cur_sset->backup_set_name.data_offset = offset ;
+ FS_GetSetNameInVCB( cur_dblk, (CHAR_PTR)( (INT8_PTR)vstr_ptr + offset ) ) ;
+ cur_sset->backup_set_name.data_size -= sizeof( CHAR ) ;
+ offset += cur_sset->backup_set_name.data_size ;
+ } else {
+ cur_sset->backup_set_name.data_offset = 0 ;
+ }
+
+ /* Backup Description */
+ if( ( cur_sset->backup_set_description.data_size =
+ FS_SizeofSetDescriptInVCB( (VCB_PTR)cur_dblk ) ) != 0 ) {
+ cur_sset->backup_set_description.data_offset = offset ;
+ FS_GetSetDescrInVCB( cur_dblk, (CHAR_PTR)( (INT8_PTR)vstr_ptr + offset ) ) ;
+ cur_sset->backup_set_description.data_size -= sizeof( CHAR ) ;
+ offset += cur_sset->backup_set_description.data_size ;
+ } else {
+ cur_sset->backup_set_description.data_offset = 0 ;
+ }
+
+ /* Backup Set Password */
+ if( ( cur_sset->backup_set_password.data_size =
+ FS_SizeofSetPswdInVCB( (VCB_PTR)cur_dblk ) ) != 0 ) {
+ cur_sset->backup_set_password.data_offset = offset ;
+ FS_GetSetPswdInVCB( cur_dblk, (CHAR_PTR)( (INT8_PTR)vstr_ptr + offset ) ) ;
+ offset += cur_sset->backup_set_password.data_size ;
+ } else {
+ cur_sset->backup_set_password.data_offset = 0 ;
+ }
+
+ cur_sset->software_vendor_id = CONNER_SOFTWARE_VENDOR_ID ;
+ cur_sset->password_encryption_algor =
+ FS_ViewPswdEncryptInVCB( (VCB_PTR)cur_dblk ) ;
+
+ /* User Name */
+ if( ( cur_sset->user_name.data_size =
+ FS_SizeofUserNameInVCB( (VCB_PTR)cur_dblk ) ) != 0 ) {
+ cur_sset->user_name.data_offset = offset ;
+ FS_GetUserNameInVCB( cur_dblk, (CHAR_PTR)( (INT8_PTR)vstr_ptr + offset ) ) ;
+ cur_sset->user_name.data_size -= sizeof( CHAR ) ;
+ offset += cur_sset->user_name.data_size ;
+ } else {
+ cur_sset->user_name.data_offset = 0 ;
+ }
+
+ cur_sset->software_ver_mjr = BE_MAJ_VERSION ;
+
+ cur_sset->software_ver_mnr = BE_MIN_VERSION ;
+
+ cur_sset->tf_minor_ver = FORMAT_VER_MINOR ;
+ cur_sset->tape_cat_ver = TAPE_CATALOG_VER ;
+
+ /* Get Backup Date */
+ GetCurrentDate( &temp_date ) ;
+ DateToTapeDate( &cur_sset->backup_date, &temp_date ) ;
+
+ /* Okay Set Them in The saved DBLK in the Channel list and in the curDBLK */
+ FS_SetBSNumInVCB( (DBLK_PTR)channel->lst_osvcb,
+ cur_sset->backup_set_number ) ;
+ FS_SetBSNumInVCB( cur_dblk, cur_sset->backup_set_number ) ;
+
+ FS_SetTSNumInVCB( (DBLK_PTR)channel->lst_osvcb,
+ cur_env->tape_hdr.tape_seq_number ) ;
+ FS_SetTSNumInVCB( cur_dblk, cur_env->tape_hdr.tape_seq_number ) ;
+
+ FS_SetTapeIDInVCB( (DBLK_PTR)channel->lst_osvcb,
+ cur_env->tape_hdr.tape_id_number ) ;
+ FS_SetTapeIDInVCB( cur_dblk, cur_env->tape_hdr.tape_id_number ) ;
+
+ FS_SetTFMajorVerInVCB( (DBLK_PTR)channel->lst_osvcb, FORMAT_VER_MAJOR ) ;
+ FS_SetTFMajorVerInVCB( cur_dblk, FORMAT_VER_MAJOR ) ;
+ FS_SetTFMinorVerInVCB( (DBLK_PTR)channel->lst_osvcb, FORMAT_VER_MINOR ) ;
+ FS_SetTFMinorVerInVCB( cur_dblk, FORMAT_VER_MINOR ) ;
+ FS_SetSWMajorVerInVCB( (DBLK_PTR)channel->lst_osvcb,
+ cur_sset->software_ver_mjr ) ;
+ FS_SetSWMajorVerInVCB( cur_dblk, cur_sset->software_ver_mjr ) ;
+ FS_SetSWMinorVerInVCB( (DBLK_PTR)channel->lst_osvcb,
+ cur_sset->software_ver_mnr ) ;
+ FS_SetSWMinorVerInVCB( cur_dblk, cur_sset->software_ver_mnr ) ;
+
+ /* Set the Time for the loops */
+ FS_SetBackupDateInVCB( cur_dblk, &temp_date ) ;
+
+ FS_SetOnTapeCatLevel( cur_dblk, cur_env->cur_otc_level ) ;
+ FS_SetSetCatInfoValid( cur_dblk, FALSE ) ;
+ FS_SetOnTapeCatVer( cur_dblk, TAPE_CATALOG_VER ) ;
+
+ cur_sset->data_encryption_algor = FS_ViewDataEncryptInVCB( (VCB_PTR)cur_dblk ) ;
+
+ cur_sset->sset_attribs = FS_GetAttribFromDBLK( cur_fsys, cur_dblk ) ;
+
+ cur_sset->physical_block_address = U64_Init( PbaOfVCB( channel ), 0L ) ;
+ offset = SetupDBHeader( MTF_SSET_N, channel, cur_dblk,
+ (MTF_DB_HDR_PTR)cur_sset, offset, FALSE, continuation ) ;
+
+ FS_SetLBAinDBLK( (DBLK_PTR)channel->lst_osvcb, channel->running_lba ) ;
+
+ if( cur_env->cur_otc_level == TCL_FULL ) {
+ cur_sset->block_hdr.block_attribs |= MTF_DB_FDD_EXISTS ;
+ /* Recalculate the Header Check Sum */
+ cur_sset->block_hdr.hdr_chksm =
+ F40_CalcChecksum( (UINT16_PTR)cur_sset, F40_HDR_CHKSUM_LEN ) ;
+ }
+
+ FS_SetPBAinVCB( cur_dblk, U64_Lsw( cur_sset->physical_block_address ) ) ;
+ FS_SetPBAinVCB( (DBLK_PTR)channel->lst_osvcb,
+ U64_Lsw( cur_sset->physical_block_address ) ) ;
+ cur_env->last_sset_pba = U64_Lsw( cur_sset->physical_block_address ) ;
+ LongAlignOffset( offset ) ;
+
+ BM_UpdCnts( buffer, offset ) ;
+
+ /* For later pad calculations */
+ if( !continuation ) {
+ cur_env->used_so_far = U64_Init( offset, 0L ) ;
+ }
+
+ /* This grotesque little conditional checks to see if we wrote the SSET
+ on the last tape but fell short of writing the VOLB, or if we are
+ crossing tape during CloseSet processing. In either case, we don't
+ want to write a continuation VOLB, or an OTC SM Entry.
+ */
+ if( continuation &&
+ ( ( channel->lst_tblk == BT_VCB && channel->eom_buff != NULL &&
+ BM_NextByteOffset( channel->eom_buff ) == F40_LB_SIZE ) ||
+ IsChannelStatus( channel, CH_EOS_AT_EOM ) ) ) {
+
+ /* We're all done. */
+ return( TFLE_NO_ERR ) ;
+ }
+
+ /* Write OTC SM entry */
+ if( cur_env->cur_otc_level != TCL_NONE && !cur_env->sm_aborted ) {
+ if( ( ret_val = OTC_GenSMEntry( cur_sset, channel, continuation ) ) != TFLE_NO_ERR ) {
+ return( ret_val ) ;
+ }
+ }
+
+ /* Now we need to do the VOLB block. This will involve saving
+ the current VOLB information in the enviornment and testing
+ to see if anything changed. If there has been a change then we
+ must write a new VOLB. Of course if this is the start of a
+ new set we need a new VOLB.
+ */
+ if( ( ret_val = F40_WtVOLB( channel, buffer, continuation, &offset ) ) != TFLE_NO_ERR ) {
+ return( ret_val ) ;
+ }
+
+ BM_UpdCnts( buffer, offset ) ;
+
+
+ return( TFLE_NO_ERR ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_WtDIRB
+
+ Description: Translates an OSDBLK DDB into a format 4.0 DIRB
+
+ Returns: INT16 TFLE_xxx error code.
+
+ Notes:
+
+**/
+INT16 F40_WtDIRB(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer,
+ BOOLEAN continuation )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ DBLK_PTR cur_dblk = channel->cur_dblk ; /* Pointer to cur DBLK */
+ FSYS_HAND cur_fsys = channel->cur_fsys ; /* Pointer to cur FilSys */
+ MTF_DIR_PTR cur_dir = (MTF_DIR_PTR)( BM_NextBytePtr( buffer ) ) ;
+ UINT16 offset = sizeof( MTF_DIR ) ;
+ UINT8_PTR vstr_ptr = ( BM_NextBytePtr( buffer ) ) ;
+ DATE_TIME temp_date ;
+
+ cur_dir->directory_attribs = FS_GetAttribFromDBLK( cur_fsys, cur_dblk ) ;
+
+ if( cur_dir->directory_attribs & DIR_IS_REALLY_DB ) {
+ /* This is a Database DBLK, but the boys upstairs don't want to
+ know about such silly things! So the File System lies and
+ calls it a DDB to get it passed on to us. Now we're going
+ to call the appropriate function to write a Database DBLK
+ (DBDB) to tape.
+ */
+ return( F40_WtDBDB( channel, buffer, continuation ) ) ;
+ }
+
+ if( !continuation ) {
+ channel->running_lba += F40_CalcRunningLBA( cur_env ) ;
+ }
+
+ /* UpDate Dates */
+ FS_GetMDateFromDBLK( cur_fsys, cur_dblk, &temp_date ) ;
+ DateToTapeDate( &cur_dir->last_mod_date, &temp_date ) ;
+ FS_GetCDateFromDBLK( cur_fsys, cur_dblk, &temp_date ) ;
+ DateToTapeDate( &cur_dir->create_date, &temp_date ) ;
+ FS_GetBDateFromDBLK( cur_fsys, cur_dblk, &temp_date ) ;
+ DateToTapeDate( &cur_dir->backup_date, &temp_date ) ;
+ FS_GetADateFromDBLK( cur_fsys, cur_dblk, &temp_date ) ;
+ DateToTapeDate( &cur_dir->last_access_date, &temp_date ) ;
+
+ /* dir_name */
+ if( ! ( cur_dir->directory_attribs & DIR_PATH_IN_STREAM_BIT ) ) {
+ vstr_ptr += cur_dir->directory_name.data_offset = offset ;
+ FS_GetOSPathFromDDB( cur_fsys, cur_dblk, (CHAR_PTR)( vstr_ptr ) ) ;
+ offset += cur_dir->directory_name.data_size =
+ FS_SizeofOSPathInDDB( cur_fsys, cur_dblk ) ;
+ } else {
+ cur_dir->directory_name.data_size = 0 ;
+ cur_dir->directory_name.data_offset = 0 ;
+ }
+
+ if( !continuation ) {
+ cur_dir->directory_id = ++cur_env->dir_count ;
+ } else {
+ cur_dir->directory_id = cur_env->eom_dir_id ;
+ }
+
+ /* Setup DB header */
+ offset = SetupDBHeader( MTF_DIRB_N, channel, cur_dblk,
+ (MTF_DB_HDR_PTR)cur_dir, offset, TRUE, continuation ) ;
+
+ BM_UpdCnts( buffer, offset ) ;
+
+ /* For later pad calculations */
+ if( !continuation ) {
+ cur_env->used_so_far = U64_Init( offset, 0L ) ;
+ }
+
+ /* For later file stuff */
+ channel->lst_did = cur_dir->block_hdr.control_block_id ;
+
+ /* Write OTC FDD entry */
+ if( ret_val == TFLE_NO_ERR && cur_env->cur_otc_level == TCL_FULL
+ && !cur_env->fdd_aborted ) {
+ ret_val = OTC_GenDirEntry( channel, cur_dir, channel->ts_num ) ;
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_WtDBDB
+
+ Description: Translates an OSDBLK DDB into an MTF DBDB.
+
+ Returns: INT16 TFLE_xxx error code.
+
+ Notes:
+
+**/
+INT16 F40_WtDBDB(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer,
+ BOOLEAN continuation )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ DBLK_PTR cur_dblk = channel->cur_dblk ;
+ FSYS_HAND cur_fsys = channel->cur_fsys ;
+ F40_DBDB_PTR cur_dbdb = (F40_DBDB_PTR)( BM_NextBytePtr( buffer ) ) ;
+ UINT16 offset = sizeof( F40_DBDB ) ;
+ UINT8_PTR vstr_ptr = ( BM_NextBytePtr( buffer ) ) ;
+ DATE_TIME temp_date ;
+
+ if( !continuation ) {
+ channel->running_lba += F40_CalcRunningLBA( cur_env ) ;
+ }
+
+ FS_GetBDateFromDBLK( cur_fsys, cur_dblk, &temp_date ) ;
+ DateToTapeDate( &cur_dbdb->backup_date, &temp_date ) ;
+
+ cur_dbdb->database_attribs = FS_GetAttribFromDBLK( cur_fsys, cur_dblk ) ;
+
+ vstr_ptr += cur_dbdb->database_name.data_offset = offset ;
+ FS_GetOSPathFromDDB( cur_fsys, cur_dblk, (CHAR_PTR)( vstr_ptr ) ) ;
+ offset += cur_dbdb->database_name.data_size =
+ FS_SizeofOSPathInDDB( cur_fsys, cur_dblk ) ;
+
+ /* Setup DB header */
+ offset = SetupDBHeader( F40_DBDB_N, channel, cur_dblk,
+ (MTF_DB_HDR_PTR)cur_dbdb, offset, TRUE, continuation ) ;
+
+ BM_UpdCnts( buffer, offset ) ;
+
+ /* For later pad calculations */
+ if( !continuation ) {
+ cur_env->used_so_far = U64_Init( offset, 0L ) ;
+ }
+
+ /* Write OTC FDD entry */
+ if( ret_val == TFLE_NO_ERR && cur_env->cur_otc_level == TCL_FULL
+ && !cur_env->fdd_aborted ) {
+ ret_val = OTC_GenDBDBEntry( channel, cur_dbdb, channel->ts_num ) ;
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_WtFILE
+
+ Description: Translates an OSDBLK FDB into a format 4.0 FILE
+
+ Returns: INT16 TFLE_xxx error code.
+
+ Notes:
+
+**/
+INT16 F40_WtFILE(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer,
+ BOOLEAN continuation )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ DBLK_PTR cur_dblk = channel->cur_dblk ;
+ FSYS_HAND cur_fsys = channel->cur_fsys ;
+ MTF_FILE_PTR cur_file = (MTF_FILE_PTR)( BM_NextBytePtr( buffer ) ) ;
+ UINT16 offset = sizeof( MTF_FILE ) ;
+ UINT8_PTR vstr_ptr = ( BM_NextBytePtr( buffer ) ) ;
+ DATE_TIME temp_date ;
+
+ if( !continuation ) {
+ channel->running_lba += F40_CalcRunningLBA( cur_env ) ;
+ }
+
+ /* Get generic fields from file system */
+ FS_GetMDateFromDBLK( cur_fsys, cur_dblk, &temp_date ) ;
+ DateToTapeDate( &cur_file->last_mod_date, &temp_date ) ;
+ FS_GetCDateFromDBLK( cur_fsys, cur_dblk, &temp_date ) ;
+ DateToTapeDate( &cur_file->create_date, &temp_date ) ;
+ FS_GetBDateFromDBLK( cur_fsys, cur_dblk, &temp_date ) ;
+ DateToTapeDate( &cur_file->backup_date, &temp_date ) ;
+ FS_GetADateFromDBLK( cur_fsys, cur_dblk, &temp_date ) ;
+ DateToTapeDate( &cur_file->last_access_date, &temp_date ) ;
+
+ /* For error recovery */
+ if( !continuation ) {
+ cur_file->directory_id = cur_env->dir_count ;
+ cur_file->file_id = ++cur_env->file_count ;
+ } else {
+ cur_file->directory_id = cur_env->eom_dir_id ;
+ cur_file->file_id = cur_env->eom_file_id ;
+ }
+
+ /* file name */
+ vstr_ptr += cur_file->file_name.data_offset = offset ;
+ FS_GetOSFnameFromFDB( cur_fsys, cur_dblk, (CHAR_PTR)( vstr_ptr ) ) ;
+ cur_file->file_name.data_size = FS_SizeofOSFnameInFDB( cur_fsys, cur_dblk ) ;
+
+ /* Decrement the size to leave off the '\0'. */
+ cur_file->file_name.data_size -= sizeof( CHAR ) ;
+
+ offset += cur_file->file_name.data_size ;
+
+ cur_file->file_attributes = FS_GetAttribFromDBLK( cur_fsys, cur_dblk ) ;
+
+ /* Setup DB header */
+ offset = SetupDBHeader( MTF_FILE_N, channel, cur_dblk,
+ (MTF_DB_HDR_PTR)cur_file, offset, TRUE, continuation ) ;
+
+ if( cur_file->block_hdr.machine_os_id == FS_PC_DOS ||
+ cur_file->block_hdr.machine_os_id == FS_PC_OS2 ) {
+
+ cur_file->file_attributes |=
+ ( cur_file->file_attributes & OBJ_READONLY_BIT )
+ ? DOS_FILE_READONLY_BIT : 0 ;
+ cur_file->file_attributes |=
+ ( cur_file->file_attributes & OBJ_HIDDEN_BIT )
+ ? DOS_FILE_HIDDEN_BIT : 0 ;
+ cur_file->file_attributes |=
+ ( cur_file->file_attributes & OBJ_SYSTEM_BIT )
+ ? DOS_FILE_SYSTEM_BIT : 0 ;
+ cur_file->file_attributes |=
+ ( cur_file->file_attributes & OBJ_MODIFIED_BIT )
+ ? DOS_FILE_MODIFIED_BIT : 0 ;
+ cur_file->file_attributes &= 0xFFFF00FF ;
+ }
+
+ BM_UpdCnts( buffer, offset ) ;
+
+ if( !continuation ) {
+ cur_env->used_so_far = U64_Init( offset, 0L ) ;
+ }
+
+ /* For later file stuff */
+ channel->lst_fid = cur_file->block_hdr.control_block_id ;
+
+ /* Write OTC FDD entry */
+ if( ret_val == TFLE_NO_ERR && cur_env->cur_otc_level == TCL_FULL
+ && !cur_env->fdd_aborted ) {
+ ret_val = OTC_GenFileEntry( cur_env, cur_file, channel->ts_num ) ;
+ }
+
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_WtIMAG
+
+ Description: This writes an image descriptor block to the buffer.
+
+ Returns: INT16 TFLE_xxx error code.
+
+ Notes:
+
+**/
+INT16 F40_WtIMAG(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer,
+ BOOLEAN continuation )
+{
+ INT16 ret_val = TFLE_NO_ERR ;
+
+#if defined( FS_IMAGE )
+ DBLK_PTR cur_dblk = channel->cur_dblk ;
+ FSYS_HAND cur_fsys = channel->cur_fsys ;
+ F40_IMAG_PTR cur_imag = (F40_IMAG_PTR)( BM_NextBytePtr( buffer ) ) ;
+ UINT16 offset = sizeof( F40_IMAG ) ;
+ UINT8_PTR vstr_ptr = ( BM_NextBytePtr( buffer ) ) ;
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+
+
+ if( !continuation ) {
+ channel->running_lba += F40_CalcRunningLBA( cur_env ) ;
+ }
+
+ cur_imag->block_hdr.block_attribs = 0 ;
+
+ cur_imag->bytes_in_sector = FS_ViewDriveSecSizeIDB( cur_fsys, cur_dblk ) ;
+ cur_imag->no_of_sectors = FS_ViewDriveNumSecIDB( cur_fsys, cur_dblk ) ;
+ cur_imag->no_of_heads = FS_ViewDriveNumHeadsIDB( cur_fsys, cur_dblk ) ;
+
+
+ cur_imag->relative_sector_no = FS_ViewPartRelSecIDB( cur_fsys, cur_dblk) ;
+ cur_imag->partition_no_of_sector =
+ FS_ViewPartNumSecIDB( cur_fsys, cur_dblk ) ;
+ cur_imag->partition_sys_ind = FS_ViewPartSysIndIDB( cur_fsys, cur_dblk ) ;
+
+ vstr_ptr += cur_imag->partition_name.string_offset = offset ;
+ FS_GetPnameIDB( cur_fsys, cur_dblk, (CHAR_PTR)( vstr_ptr ) ) ;
+ offset += cur_imag->partition_name.data_size =
+ FS_SizeofPnameInIDB( cur_fsys, cur_dblk ) ;
+ offset = SetupDBHeader( F40_IMAG_N, channel, cur_dblk,
+ (MTF_DB_HDR_PTR)cur_imag, offset, TRUE, continuation ) ;
+ BM_UpdCnts( buffer, offset ) ;
+
+ /* For later pad calculations */
+ if( !continuation ) {
+ cur_env->used_so_far = U64_Init( offset, 0L ) ;
+ }
+
+#else
+ (VOID) channel ;
+ (VOID) buffer ;
+ (VOID) continuation ;
+ mscassert( FALSE ) ;
+ ret_val = TFLE_TRANSLATION_FAILURE ;
+#endif
+
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_WtCFDB
+
+ Description: Writes a corrupt file descriptor block.
+
+ Returns: INT16 TFLE_xxx error code.
+
+ Notes:
+
+**/
+
+INT16 F40_WtCFIL(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer,
+ BOOLEAN continuation )
+{
+
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ DBLK_PTR cur_dblk = channel->cur_dblk ;
+ FSYS_HAND cur_fsys = channel->cur_fsys ;
+ MTF_CFIL_PTR cur_cfil = (MTF_CFIL_PTR)( BM_NextBytePtr( buffer ) ) ;
+ UINT16 offset = sizeof( MTF_CFIL ) ;
+
+ if( !continuation ) {
+ cur_env->corrupt_obj_count++ ;
+ channel->running_lba += F40_CalcRunningLBA( cur_env ) ;
+ }
+
+ LongAlignOffset( offset ) ;
+ /* Clear Attributes */
+ cur_cfil->block_hdr.block_attribs = 0 ;
+
+ cur_cfil->corrupt_file_attribs = FS_GetAttribFromDBLK( cur_fsys, cur_dblk ) ;
+ if( !continuation ) {
+ cur_cfil->directory_id = cur_env->dir_count ;
+ cur_cfil->file_id = cur_env->file_count ;
+ } else {
+ cur_cfil->directory_id = cur_env->eom_dir_id ;
+ cur_cfil->file_id = cur_env->eom_file_id ;
+ }
+
+ cur_cfil->stream_offset =
+ U32_To_U64( FS_GetCorruptOffsetInCFDB( (CFDB_PTR)cur_dblk ) ) ;
+ cur_cfil->corrupt_stream_number =
+ FS_GetCorruptStrmNumInCFDB( (CFDB_PTR)cur_dblk ) ;
+
+ /* Setup DB header */
+ offset = SetupDBHeader( MTF_CFIL_N, channel, cur_dblk,
+ (MTF_DB_HDR_PTR)cur_cfil, offset, FALSE, continuation ) ;
+
+ BM_UpdCnts( buffer, offset ) ;
+
+ /* For later pad calculations */
+ if( !continuation ) {
+ cur_env->used_so_far = U64_Init( offset, 0L ) ;
+ }
+
+ /* Adjust OTC FDD entry */
+ if( ret_val == TFLE_NO_ERR && cur_env->cur_otc_level == TCL_FULL
+ && !cur_env->fdd_aborted ) {
+ ret_val = OTC_MarkLastEntryCorrupt( cur_env ) ;
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_WtESET
+
+ Description: Translates a DBLK in a format 4.0 ESET.
+ End of Set.
+
+ Returns: INT16 TFLE_xxx error code.
+
+ Notes: None
+
+**/
+INT16 F40_WtESET(
+ CHANNEL_PTR channel, /* Pointer to current channel */
+ BUF_PTR buffer, /* Pointer to buffer */
+ BOOLEAN continuation, /* TRUE if continuation VCB */
+ BOOLEAN abort ) /* TRUE if aborted operation */
+{
+ INT16 ret_val = TFLE_NO_ERR ;
+ DBLK_PTR cur_dblk = channel->cur_dblk ; /* Pointer to cur DBLK */
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ MTF_ESET_PTR cur_eset ;
+ MTF_DB_HDR_PTR cur_hdr ;
+ FSYS_HAND cur_fsys = channel->cur_fsys ;
+ UINT16 offset ;
+ DATE_TIME temp_date ;
+ UINT16 temp_os_id ;
+ UINT16 temp_os_ver ;
+
+ /* get a pointer to the ESET in the buffer */
+ cur_eset = (MTF_ESET_PTR)( BM_NextBytePtr( buffer ) ) ;
+ cur_hdr = &cur_eset->block_hdr ;
+ offset = sizeof( MTF_ESET ) ;
+ LongAlignOffset( offset ) ;
+
+ cur_eset->corrupt_file_count = cur_env->corrupt_obj_count ;
+ cur_eset->set_map_phys_blk_adr = U64_Init( 0L, 0L ) ;
+ cur_eset->fdd_phys_blk_adr = U64_Init( 0L, 0L ) ;
+
+ cur_hdr->control_block_id = (UINT32)channel->tape_id ;
+ cur_eset->backup_set_number = (UINT16)channel->bs_num ;
+
+ /* Get Backup Date */
+ GetCurrentDate( &temp_date ) ;
+ DateToTapeDate( &cur_eset->backup_date, &temp_date ) ;
+
+ cur_hdr->control_block_id = (UINT32)channel->tape_id ;
+ cur_eset->backup_set_number = (UINT16)channel->bs_num ;
+
+ cur_eset->eset_attribs = 0L ;
+
+ /* Here we do our own version of SetupDBHeader because we're setting
+ up our own data streams (OTC)
+ */
+
+ /* Setup the block type */
+ F40_SetBlkType( cur_hdr, MTF_ESET_N ) ;
+
+ cur_hdr->logical_block_address = U64_Init( 0L, 0L ) ;
+ cur_hdr->os_specific_data.data_offset = 0 ;
+ cur_hdr->os_specific_data.data_size = 0 ;
+ (VOID)FS_GetOSid_verFromDBLK( cur_fsys, cur_dblk, &temp_os_id, &temp_os_ver ) ;
+ cur_hdr->machine_os_id = (UINT8)temp_os_id;
+ cur_hdr->machine_os_version = (UINT8)temp_os_ver ;
+
+ cur_hdr->session_id = U64_Init( 0L, 0L ) ;
+
+ /* Setup Block ID, if its a continuation, don't increment it */
+ if( continuation ) {
+ cur_hdr->control_block_id = channel->eom_id ;
+ } else {
+ cur_hdr->control_block_id = channel->eom_id++ ;
+ }
+
+ /* set up the attributes */
+ cur_hdr->block_attribs = 0L ;
+ if( abort ) {
+ cur_hdr->block_attribs |= MTF_DB_ABORTED_SET_BIT ;
+ }
+ if( continuation ) {
+ cur_hdr->block_attribs |= MTF_DB_CONT_BIT ;
+ }
+ if( cur_env->fdd_aborted ) {
+ cur_hdr->block_attribs |= MTF_DB_FDD_ABORTED_BIT ;
+ }
+ if( cur_env->sm_aborted ) {
+ cur_hdr->block_attribs |= MTF_DB_END_OF_FAMILY_BIT ;
+ }
+
+ /* Set data size fields */
+ cur_hdr->displayable_size = U64_Init( 0L, 0L ) ;
+
+ offset += PadToBoundary( offset, ChannelBlkSize( channel ) ) ;
+ cur_hdr->offset_to_data = offset ;
+
+ /* Calculate the Header Check Sum */
+ cur_hdr->hdr_chksm = F40_CalcChecksum( (UINT16_PTR)cur_eset, F40_HDR_CHKSUM_LEN ) ;
+
+ BM_UpdCnts( buffer, offset ) ;
+ return( ret_val ) ;
+
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_WtEOSPadBlk
+
+ Description: Writes an ESPB descriptor block to pad buffer out to a
+ physical block boundary.
+
+ Returns: Nothing
+
+ Notes:
+
+**/
+
+VOID F40_WtEOSPadBlk(
+ CHANNEL_PTR channel )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ MTF_DB_HDR_PTR cur_hdr = (MTF_DB_HDR_PTR)( BM_NextBytePtr( channel->cur_buff ) ) ;
+ UINT16 size ;
+ UINT16 temp_os_id ;
+ UINT16 temp_os_ver ;
+
+ size = BM_BytesFree( channel->cur_buff ) % ChannelBlkSize( channel ) ;
+ memset( cur_hdr, 0, size ) ;
+
+ channel->running_lba += F40_CalcRunningLBA( cur_env ) ;
+ cur_env->used_so_far = U64_Init( size, 0L ) ;
+
+ F40_SetBlkType( cur_hdr, MTF_ESPB_N ) ;
+
+ (VOID)FS_GetOSid_verFromDBLK( channel->cur_fsys, channel->cur_dblk, &temp_os_id, &temp_os_ver ) ;
+ cur_hdr->machine_os_id = (UINT8)temp_os_id ;
+ cur_hdr->machine_os_version = (UINT8)temp_os_ver ;
+ cur_hdr->session_id = U64_Init( 0L, 0L ) ;
+ cur_hdr->offset_to_data = size ;
+ cur_hdr->control_block_id = channel->eom_id++ ;
+ cur_hdr->logical_block_address = U64_Init( channel->running_lba, 0L ) ;
+ cur_hdr->hdr_chksm = F40_CalcChecksum( (UINT16_PTR)cur_hdr, F40_HDR_CHKSUM_LEN ) ;
+
+ cur_env->pad_size = 0 ;
+
+ BM_UpdCnts( channel->cur_buff, size ) ;
+}
+
diff --git a/private/utils/ntbackup/src/mtf10wt.c b/private/utils/ntbackup/src/mtf10wt.c
new file mode 100644
index 000000000..b7a39e9ba
--- /dev/null
+++ b/private/utils/ntbackup/src/mtf10wt.c
@@ -0,0 +1,1678 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: mtf40wt.c
+
+ Description: Contains the Code for writing Maynard 4.0 Format.
+
+ $Log: T:/LOGFILES/MTF10WT.C_V $
+
+ Rev 1.20.1.2 11 Jan 1995 21:05:08 GREGG
+Calculate OTC addrs from fmk instead of always asking (fixes Wangtek bug).
+
+ Rev 1.20.1.1 08 Jan 1995 21:51:06 GREGG
+Added database DBLK.
+
+ Rev 1.20.1.0 13 Jan 1994 17:20:44 GREGG
+If backup was aborted, mark last file entry in OTC as corrupt.
+
+ Rev 1.20 08 Sep 1993 13:28:36 GREGG
+Fixed method WriteInit uses to determine if we are appending.
+
+ Rev 1.19 31 Aug 1993 16:54:54 GREGG
+Modified the way we control hardware compression from software to work around
+a bug in Archive DAT DC firmware rev. 3.58 (we shipped a lot of them).
+Files Modified: lw_data.c, lw_data.h, tfstuff.c, mtf10wdb.c, mtf10wt.c and
+ drives.c
+
+ Rev 1.18 17 Jul 1993 17:57:22 GREGG
+Changed write translator functions to return INT16 TFLE_xxx errors instead
+of BOOLEAN TRUE/FALSE. Files changed:
+ MTF10WDB.C 1.23, TRANSLAT.H 1.22, F40PROTO.H 1.30, FMTENG.H 1.23,
+ TRANSLAT.C 1.43, TFWRITE.C 1.68, MTF10WT.C 1.18
+
+ Rev 1.17 04 Jul 1993 03:38:52 GREGG
+Set eom_file_id and eom_dir_id in ParseWrittenBuffer.
+
+ Rev 1.16 15 Jun 1993 18:48:46 GREGG
+Fixed EPR #294-0443 - Continue flag not set if EOM hit writing 1st fmk.
+
+ Rev 1.15 09 Jun 1993 19:53:04 GREGG
+Fix for EPR #0525 - Accept GEN_ERR_EOM return on space to EOD for Wangtek bug.
+
+ Rev 1.14 09 Jun 1993 03:51:14 GREGG
+In EOS at EOM case, don't call OTC_PreprocessEOM.
+
+ Rev 1.13 08 Jun 1993 00:09:56 GREGG
+Fix for bug in the way we were handling EOM and continuation OTC entries.
+Files modified for fix: mtf10wt.c, otc40wt.c, otc40msc.c f40proto.h mayn40.h
+
+ Rev 1.12 24 May 1993 13:23:22 GREGG
+Put back the VCB buffer before returning error in WtContTape.
+
+ Rev 1.11 17 May 1993 20:11:56 GREGG
+Added logic to deal with the fact that the app above tape format doesn't
+keep track of the lba of the vcb.
+
+ Rev 1.10 29 Apr 1993 23:37:14 GREGG
+Fixed assert caused by GetBlkType calling a VOLB a UDB.
+
+ Rev 1.9 26 Apr 1993 11:45:56 GREGG
+Seventh in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Changed handling of EOM processing during non-OTC EOS processing.
+
+Matches CHANNEL.H 1.17, MAYN40RD.C 1.60, TFWRITE.C 1.63, MTF.H 1.5,
+ TFLUTILS.C 1.44, MTF10WDB.C 1.10, MTF10WT.C 1.9
+
+ Rev 1.8 25 Apr 1993 17:12:48 GREGG
+Fixed cast (CHAR_PTR to UINT8_PTR) in F40_SaveLclName.
+
+ Rev 1.7 22 Apr 1993 03:31:32 GREGG
+Third in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Removed all references to the DBLK element 'string_storage_offset',
+ which no longer exists.
+ - Check for incompatable versions of the Tape Format and OTC and deals
+ with them the best it can, or reports tape as foreign if they're too
+ far out. Includes ignoring the OTC and not allowing append if the
+ OTC on tape is a future rev, different type, or on an alternate
+ partition.
+ - Updated OTC "location" attribute bits, and changed definition of
+ CFIL to store stream number instead of stream ID.
+
+Matches: TFL_ERR.H 1.9, MTF10WDB.C 1.7, TRANSLAT.C 1.39, FMTINF.H 1.11,
+ OTC40RD.C 1.24, MAYN40RD.C 1.56, MTF10WT.C 1.7, OTC40MSC.C 1.20
+ DETFMT.C 1.13, MTF.H 1.4
+
+ Rev 1.6 18 Apr 1993 00:34:36 GREGG
+First in a series of incremental changes to bring the translator in line
+with the MTF spec:
+ - Rewrote F40_WtCloseTape:
+ - Stop using SetupDBHeader to set up the Tape Header (needs
+ special setup specific to that DBLK).
+ - Set string_storage_offset properly.
+ - Changed CHAR_PTRs to UINT8_PTRs in F40_SaveLclName.
+
+Matches: MTF10WDB.C 1.6, MAYN40RD.C 1.53, MAYN40.H 1.31 and F40PROTO.H 1.25
+
+ Rev 1.5 14 Apr 1993 02:00:00 GREGG
+Fixes to deal with non-ffr tapes in ffr drives (i.e. EXB2200 in EXB5000).
+
+ Rev 1.4 12 Mar 1993 14:13:50 DON
+Changed F40_SeekEOD so it will call the ui with new message TF_FAST_SEEK_EOD
+
+ Rev 1.3 10 Mar 1993 16:03:52 DON
+EndVStream copying to hold buffer instead of buffer
+
+ Rev 1.2 09 Mar 1993 18:16:30 GREGG
+Initial changes for new stream and EOM processing.
+
+ Rev 1.1 30 Jan 1993 11:44:00 DON
+Removed compiler warnings
+
+ Rev 1.0 27 Jan 1993 14:37:38 GREGG
+Half of mayn40wt.c.
+
+**/
+/* begin include list */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "stdtypes.h"
+#include "stdmacro.h"
+#include "fsys.h"
+#include "tbe_defs.h"
+#include "datetime.h"
+
+#include "drive.h"
+#include "channel.h"
+#include "fmteng.h"
+#include "mayn40.h"
+#include "f40proto.h"
+#include "transutl.h"
+#include "tloc.h"
+#include "lw_data.h"
+#include "tfldefs.h"
+#include "lwprotos.h"
+#include "sx.h"
+#include "tfl_err.h"
+#include "minmax.h"
+
+/* Device Driver InterFace Headers */
+#include "retbuf.h"
+#include "special.h"
+#include "dilhwd.h"
+#include "drvinf.h"
+#include "generr.h"
+#include "genfuncs.h"
+#include "dil.h"
+#include "tdemo.h"
+#include "dddefs.h"
+/* $end$ include list */
+
+/*
+ * Define the test OTC level here 0 == none, 1 == partial, 2 == full
+*/
+#define TEST_OTC_LEVEL 2
+
+/* Size required to pad to next logical block */
+#define PadToLBBoundary( x ) PadToBoundary( (x), F40_LB_SIZE )
+
+/* Adjusts offset to next 4 byte boundary */
+#define LongAlignOffset( x ) ( (x) += PadToBoundary( (x), 4 ) )
+
+
+/**/
+/**
+
+ Name: F40_SeekEOD
+
+ Description: Seeks to EOD and sets up to start an append operation
+ (load Set Map if there is one, and get last set number).
+
+ Returns: TFLE_xxx error or TF_NEED_NEW_TAPE
+
+ Notes:
+
+ Declaration:
+
+**/
+
+INT16 F40_SeekEOD( CHANNEL_PTR channel )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)(channel->fmt_env) ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ DRIVE_PTR curDRV = channel->cur_drv ;
+ INT16 drv_hdl = channel->cur_drv->drv_hdl ;
+ RET_BUF myret ;
+ BOOLEAN expect_sm ;
+ BOOLEAN sm_exists ;
+ TPOS_PTR ui_tpos = channel->ui_tpos ;
+
+ /* First we need to make sure the drive has all the features required
+ to do a fast append. Note that in some cases the driver supports
+ block positioning, but not for the tape currently in the drive
+ (backward compatability mode). We can't tell this for sure, so we
+ have to make an assumtion that if there isn't a PBA in the SSET of
+ the first set, position info must not be available.
+ */
+ if( !SupportBlkPos( curDRV ) ||
+ !SupportFastEOD( curDRV ) ||
+ !SupportRevFmk( curDRV ) ||
+ cur_env->last_sset_pba == 0UL ) {
+
+ return( TFLE_INCOMPATIBLE_DRIVE ) ;
+ }
+
+ if( cur_env->cur_otc_level == TCL_NONE ) {
+ expect_sm = FALSE ;
+ } else {
+ expect_sm = TRUE ;
+ ret_val = OTC_OpenSM( cur_env, FALSE, &sm_exists ) ;
+ }
+
+ if( ret_val == TFLE_NO_ERR ) {
+ (*ui_tpos->UI_TapePosRoutine)( TF_FAST_SEEK_EOD, ui_tpos,
+ curDRV->vcb_valid, &curDRV->cur_vcb,
+ channel->mode ) ;
+
+ if( TpReadEndSet( drv_hdl, (INT16)0, (INT16)TO_EOD ) != SUCCESS ) {
+ ret_val = TFLE_DRIVER_FAILURE ;
+ } else {
+
+ while( TpReceive( drv_hdl, &myret ) == FAILURE ) {
+ MOVE_ESA( ui_tpos->the, myret.the ) ;
+ (*ui_tpos->UI_TapePosRoutine)( TF_IDLE_NOBREAK,
+ ui_tpos,
+ curDRV->vcb_valid,
+ &curDRV->cur_vcb,
+ channel->mode ) ;
+ }
+
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( curDRV->thw_inf.the, myret.the ) ;
+
+ if ( myret.gen_error != GEN_NO_ERR ) {
+ curDRV->thw_inf.drv_status = myret.status ;
+ if ( myret.gen_error != GEN_NO_ERR ) {
+ ret_val = TFLE_DRIVE_FAILURE ;
+ }
+ }
+
+ if( ret_val == TFLE_NO_ERR ) {
+ ret_val = OTC_GetPrevSM( channel, channel->cur_buff,
+ TRUE, expect_sm ) ;
+ }
+ }
+ }
+
+ if( expect_sm ) {
+ if( ret_val == TFLE_NO_ERR ) {
+ ClrPosBit( curDRV, AT_BOT ) ;
+ SetPosBit( curDRV, AT_EOD ) ;
+ OTC_Close( cur_env, OTC_CLOSE_SM, FALSE ) ;
+ } else {
+ OTC_Close( cur_env, OTC_CLOSE_SM, TRUE ) ;
+ }
+ }
+
+ /* This is a really stupid little kludge, but in the case where we
+ are at EOD because we did a read or OTC operation then WriteInit
+ will call GetPrevSM and it will be expected to bump the bs_num,
+ so GetPrevSM sets bs_num to one greater than the last set. However,
+ in this case, we are being called by PositionAtSet (no, we're not
+ supposed to know that ... so what's your point?!?) and PositionAtSet,
+ in it's constant attempt to do everything for everyone, is going to
+ bump the bs_num itself. So, here we decrement bs_num to couteract
+ PositionAtSet's increment. (I don't want to hear it!!!)
+ */
+ if( ret_val == TFLE_NO_ERR ) {
+ channel->bs_num-- ;
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Name: F40_ParseWrittenBufer
+
+ Description: Parses the return buffer from the driver to keep track
+ of the last DDB, FDB and Stream which successfully made
+ it to tape. This information is used during EOM
+ processing.
+
+ Returns: Nothing
+
+ Notes: It is possible for a stream header to be only partially
+ written to tape for one of two reasons:
+
+ 1. It crosses buffer boundaries
+ 2. It crosses tape boundaries
+
+ In both cases the portion of the stream that made it to
+ tape is written into 'eom_stream', and 'pstream_crosses'
+ is set to TRUE to indicate this. If the first case is
+ true, the next buffer we see will have the remainder of
+ the header at the front. We complete the 'eom_stream',
+ and clear the flag. In the second case, F40_WtContTape
+ will handle "rebuilding" the crossing stream on the
+ continuation tape, but leave the flag set as the next
+ buffer we will see will start at the point where we left
+ off with this one (i.e. the first thing in it will be
+ the rest of the stream header) and we will handle it in
+ the same manner as the first case, just in case this
+ same stream crosses the next EOM (never say never).
+
+**/
+VOID F40_ParseWrittenBuffer(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer,
+ UINT16 written )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)channel->fmt_env ;
+ INT num = (INT)BM_NoDblks( buffer ) ;
+ DBLKMAP_PTR dmap = (DBLKMAP_PTR)BM_AuxBase( buffer ) ;
+ BOOLEAN got_ddb = FALSE ;
+ BOOLEAN got_fdb = FALSE ;
+ BOOLEAN got_strm = FALSE ;
+ BOOLEAN blk_proc = FALSE ;
+ UINT16 rem_strm = 0 ;
+ INT i ;
+ UINT64 data ;
+ BOOLEAN stat ;
+
+ if( written == 0 ) { /* This little bugger case just doesn't fit in! */
+ return ;
+ }
+
+ if( cur_env->pstream_crosses ) {
+ rem_strm = sizeof( MTF_STREAM ) - cur_env->pstream_offset ;
+ memcpy( (UINT8_PTR)( &cur_env->eom_stream ) +
+ cur_env->pstream_offset,
+ BM_XferBase( buffer ), rem_strm ) ;
+ cur_env->pstream_offset = 0 ;
+ cur_env->pstream_crosses = FALSE ;
+ }
+
+ for( i = num - 1; i >= 0 && !got_ddb; i-- ) {
+
+ if( dmap[i].blk_offset >= written ) {
+ continue ;
+ }
+
+ switch( dmap[i].blk_type ) {
+
+ case BT_FDB:
+ if( !got_fdb ) {
+ got_fdb = TRUE ;
+ memcpy( channel->lst_osfdb,
+ (UINT8_PTR)BM_XferBase( buffer ) +
+ dmap[i].blk_offset, (int)F40_LB_SIZE ) ;
+ cur_env->eom_file_id =
+ ((MTF_FILE_PTR)channel->lst_osfdb)->file_id ;
+ ClrChannelStatus( channel, CH_FDB_DBLK ) ;
+ channel->lst_tblk = dmap[i].blk_type ;
+ }
+ break ;
+
+ case BT_DDB:
+ got_ddb = TRUE ;
+ memcpy( channel->lst_osddb, (UINT8_PTR)BM_XferBase( buffer ) +
+ dmap[i].blk_offset, (int)F40_LB_SIZE ) ;
+ cur_env->eom_dir_id =
+ ((MTF_DIR_PTR)channel->lst_osddb)->directory_id ;
+ ClrChannelStatus( channel, CH_DDB_DBLK ) ;
+ if( !got_fdb ) {
+ channel->lst_tblk = dmap[i].blk_type ;
+ }
+ break ;
+
+ case BT_STREAM:
+ if( !got_strm && !got_fdb ) {
+ got_strm = TRUE ;
+ if( written - dmap[i].blk_offset < sizeof( MTF_STREAM ) ) {
+ cur_env->pstream_offset = written - dmap[i].blk_offset ;
+ memcpy( &cur_env->eom_stream,
+ (UINT8_PTR)BM_XferBase( buffer ) +
+ dmap[i].blk_offset, cur_env->pstream_offset ) ;
+ cur_env->pstream_crosses = TRUE ;
+ } else {
+ memcpy( &cur_env->eom_stream,
+ (UINT8_PTR)BM_XferBase( buffer ) +
+ dmap[i].blk_offset, sizeof( MTF_STREAM ) ) ;
+ data = U32_To_U64( (UINT32)( written -
+ ( dmap[i].blk_offset +
+ sizeof( MTF_STREAM ) ) ) ) ;
+ cur_env->eom_stream.data_length =
+ U64_Sub( cur_env->eom_stream.data_length,
+ data, &stat ) ;
+ }
+ }
+ break ;
+
+ case BT_VCB:
+ /* There is only one of these, and we have already copied it
+ to lst_osvcb.
+ */
+ channel->lst_tblk = dmap[i].blk_type ;
+ break ;
+
+ default:
+ /* I guess we'll just let this slide once the msassert goes
+ away (release code). It should NEVER, EVER, EVER HAPPEN!!!
+ */
+ msassert( FALSE ) ;
+ continue ;
+ }
+
+ if( !blk_proc ) {
+ blk_proc = TRUE ;
+ }
+ }
+
+ if( !blk_proc ) {
+ cur_env->eom_stream.data_length =
+ U64_Sub( cur_env->eom_stream.data_length,
+ U32_To_U64( (UINT32)( written - rem_strm ) ),
+ &stat ) ;
+ } else {
+ cur_env->stream_at_eom = got_strm ;
+ }
+}
+
+
+/**/
+/**
+
+ Name: F40_CalcChecksum
+
+ Description: This routine will calculate the checksum for
+ 'Length' words starting at location pointed
+ to by "StartPtr". This routine supports both INTEL
+ and MOTOROLA byte ordering as byte order is unimportant.
+
+ Returns: result of checksum
+
+ Notes:
+
+ Declaration:
+
+**/
+UINT16 F40_CalcChecksum(
+ UINT16_PTR StartPtr,
+ UINT16 Length )
+{
+ UINT16 resultSoFar = INTERIM_CHECKSUM_BASE ;
+
+ while( Length-- ) {
+ resultSoFar ^= *StartPtr++ ;
+ }
+
+ return( resultSoFar ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_WtCloseSet
+
+ Description: This writes an ESET for the given backup set. The
+ cur_drv pointer in the channel must be valid. Also,
+ the "lst_osvcb" field in the channel must contain a
+ valid SSET DBLK.
+
+ In the presence of OTC it will write a FILE MARK, ESET,
+ { { F/DD } SM ESET } FILE MARK. If EOM is encountered
+ during this process it is handled internally.
+
+ There is an assumption that if we return with the EOM
+ Pos Bit set we will get called back once a continuation
+ tape has been inserted.
+
+ We use the VCB buffer here to insure that OTC will have
+ a buffer to use.
+
+ Returns: INT16 - TFLE_xxx
+
+ Notes:
+
+**/
+INT16 F40_WtCloseSet(
+ CHANNEL_PTR channel,
+ BOOLEAN abort )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ INT16 drv_hdl = channel->cur_drv->drv_hdl ;
+ DRIVE_PTR curDRV = channel->cur_drv ;
+ RET_BUF myret ;
+ MTF_ESET_PTR cur_eset ;
+ BUF_PTR tmpBUF ;
+ INT16 ret_val ;
+
+ /* Write Ending OTC FDD entry */
+ if( cur_env->cur_otc_level == TCL_FULL &&
+ !cur_env->end_set_continuing &&
+ !cur_env->fdd_aborted ) {
+
+ if( abort ) {
+ if( ( ret_val = OTC_MarkLastEntryCorrupt( cur_env ) ) != TFLE_NO_ERR ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ return( ret_val ) ;
+ }
+ }
+ if( !cur_env->fdd_aborted ) {
+ if( ( ret_val = OTC_GenEndEntry( channel ) ) != TFLE_NO_ERR ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ return( ret_val ) ;
+ }
+ }
+ }
+
+ /* drop a filemark */
+ if( ( ret_val = WriteEndSet( curDRV ) ) != TFLE_NO_ERR ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ return( ret_val ) ;
+ }
+
+ /* if we hit EOM writing the filemark, we don't even start end set
+ processing. We just write the EOTM, and make this look like the
+ case where EOM is encountered at the end of the set data.
+ */
+ if( IsPosBitSet( curDRV, ( AT_EOM ) ) ) {
+
+ SetChannelStatus( channel, CH_EOS_AT_EOM ) ;
+ cur_env->end_set_continuing = TRUE ;
+
+ /* set the flag to tell CloseTape not to write the first filemark */
+ cur_env->eotm_no_first_fmk = TRUE ;
+
+ if( ( ret_val = F40_WtCloseTape( channel ) ) != TFLE_NO_ERR ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ }
+ cur_env->eotm_no_first_fmk = FALSE ;
+ return( ret_val ) ;
+ }
+
+ /* Get base address for calculating OTC and ESET addresses. */
+ if( SupportBlkPos( curDRV ) ) {
+
+ DRIVER_CALL( drv_hdl, TpGetPosition( drv_hdl, FALSE ), myret,
+ GEN_NO_ERR, GEN_NO_ERR,
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) )
+ } else {
+ curDRV->cur_pos.pba_vcb = 0 ;
+ }
+ cur_env->eset_base_addr = myret.misc ;
+
+
+ /* Get a buffer */
+ tmpBUF = BM_GetVCBBuff( &channel->buffer_list ) ;
+
+ /* Generate the ESET */
+ cur_eset = (MTF_ESET_PTR)( BM_NextBytePtr( tmpBUF ) ) ;
+ channel->cur_dblk = (DBLK_PTR)channel->lst_osvcb ;
+ F40_WtESET( channel, tmpBUF, cur_env->end_set_continuing, abort ) ;
+ DRIVER_CALL( drv_hdl, TpWrite( drv_hdl, BM_XferBase( tmpBUF ), BM_NextByteOffset( tmpBUF ) ),
+ myret, GEN_NO_ERR, GEN_ERR_EOM,
+ { BM_Put( tmpBUF ) ; OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ; } )
+
+ cur_env->eset_base_addr += BM_NextByteOffset( tmpBUF ) / ChannelBlkSize( channel ) ;
+
+ if( myret.gen_error == GEN_ERR_EOM ) {
+
+ SetChannelStatus( channel, CH_EOS_AT_EOM ) ;
+ cur_env->end_set_continuing = TRUE ;
+
+ SetPosBit( curDRV, ( AT_EOM | TAPE_FULL ) ) ;
+ if( myret.len_req != myret.len_got ) {
+ BM_SetNextByteOffset( tmpBUF, (UINT16)myret.len_got ) ;
+ DRIVER_CALL( drv_hdl, TpWrite( drv_hdl, BM_NextBytePtr( tmpBUF ), myret.len_req - myret.len_got ),
+ myret, GEN_NO_ERR, GEN_ERR_EOM,
+ { BM_Put( tmpBUF ) ; OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ; } )
+ }
+ BM_Put( tmpBUF ) ;
+ if( ( ret_val = F40_WtCloseTape( channel ) ) != TFLE_NO_ERR ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ }
+ return( ret_val ) ;
+ }
+
+ if( cur_env->cur_otc_level != TCL_NONE ) {
+
+ /* Write the catalog info to tape. Note that the physical
+ block addresses and tape sequence numbers of the start of
+ the SM and FDD will be filled in by this function.
+ */
+ if( ( ret_val = OTC_WriteCat( channel, cur_eset ) ) != TFLE_NO_ERR ) {
+ BM_Put( tmpBUF ) ;
+ return( ret_val ) ;
+ }
+
+ if( IsPosBitSet( curDRV, AT_EOM ) ) {
+ BM_Put( tmpBUF ) ;
+ SetChannelStatus( channel, CH_EOS_AT_EOM ) ;
+ cur_env->end_set_continuing = TRUE ;
+ if( ( ret_val = F40_WtCloseTape( channel ) ) != TFLE_NO_ERR ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ }
+ return( ret_val ) ;
+ }
+
+ /* Save the PBA in the environment (for EOM processing) */
+ cur_env->eset_pba = cur_env->eset_base_addr ;
+
+ /* Write the second ESET */
+ /*
+ NOTE: tmpBUF still holds the first ESET, and the PBA of the
+ FDD and SM are now filled in. Here we check to see
+ if the FDD or SM aborted bits need to be set. We also
+ need to check the offset_to_data. The first ESETs
+ offset is the physical block size of the device. The
+ second ESET offset must be at least Logical Block
+ Size. So the first one could be 512, and we need to
+ adjust this for the second.
+ */
+ if( cur_env->fdd_aborted ) {
+ cur_eset->block_hdr.block_attribs |= MTF_DB_FDD_ABORTED_BIT ;
+ }
+ if( cur_env->sm_aborted ) {
+ cur_eset->block_hdr.block_attribs |= MTF_DB_END_OF_FAMILY_BIT ;
+ }
+ if( BM_NextByteOffset( tmpBUF ) < F40_LB_SIZE ) {
+ BM_SetNextByteOffset( tmpBUF, F40_LB_SIZE ) ;
+ cur_eset->block_hdr.offset_to_data = BM_NextByteOffset( tmpBUF ) ;
+ }
+ /* Calculate the Header Check Sum */
+ cur_eset->block_hdr.hdr_chksm =
+ F40_CalcChecksum( (UINT16_PTR)cur_eset, F40_HDR_CHKSUM_LEN ) ;
+
+ DRIVER_CALL( drv_hdl, TpWrite( drv_hdl, BM_XferBase( tmpBUF ), BM_NextByteOffset( tmpBUF ) ),
+ myret, GEN_NO_ERR, GEN_ERR_EOM,
+ { BM_Put( tmpBUF ) ;
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ; } )
+
+ if( myret.gen_error == GEN_ERR_EOM ) {
+ cur_env->sm_continuing = TRUE ;
+ SetChannelStatus( channel, CH_EOS_AT_EOM ) ;
+ cur_env->end_set_continuing = TRUE ;
+ SetPosBit( curDRV, ( AT_EOM | TAPE_FULL ) ) ;
+ if( myret.len_req != myret.len_got ) {
+ BM_SetNextByteOffset( tmpBUF, (UINT16)myret.len_got ) ;
+ DRIVER_CALL( drv_hdl, TpWrite( drv_hdl, BM_NextBytePtr( tmpBUF ), myret.len_req - myret.len_got ),
+ myret, GEN_NO_ERR, GEN_ERR_EOM,
+ { BM_Put( tmpBUF ) ;
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ; } )
+ }
+ BM_Put( tmpBUF ) ;
+ if( ( ret_val = F40_WtCloseTape( channel ) ) != TFLE_NO_ERR ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ }
+ return( ret_val ) ;
+ }
+ }
+
+ /* drop a filemark */
+ if( ( ret_val = WriteEndSet( curDRV ) ) != TFLE_NO_ERR ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ BM_Put( tmpBUF ) ;
+ return( ret_val ) ;
+ }
+
+ BM_Put( tmpBUF ) ;
+ if( IsPosBitSet( curDRV, ( AT_EOM ) ) ) {
+
+ SetChannelStatus( channel, CH_EOS_AT_EOM ) ;
+ cur_env->end_set_continuing = TRUE ;
+ if( cur_env->cur_otc_level != TCL_NONE ) {
+ cur_env->sm_continuing = TRUE ;
+ }
+
+ /* set the flag to tell CloseTape not to write the first filemark */
+ cur_env->eotm_no_first_fmk = TRUE ;
+ if( ( ret_val = F40_WtCloseTape( channel ) ) != TFLE_NO_ERR ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ }
+ cur_env->eotm_no_first_fmk = FALSE ;
+ return( ret_val ) ;
+ }
+
+ OTC_Close( cur_env, OTC_CLOSE_SM, FALSE ) ;
+
+ /* If the drive supports hardware compression we need to keep it in
+ uncompressed mode unless we're actually writing a compressed set.
+ This is a work-around for a firmware bug in early Archive DAT DC
+ drives.
+ */
+ if( curDRV->thw_inf.drv_info.drv_features & TDI_DRV_COMPRESSION ) {
+ if( TpSpecial( drv_hdl, SS_SET_DRV_COMPRESSION,
+ DISABLE_DRV_COMPRESSION ) != SUCCESS ) {
+
+ return( TFLE_DRIVE_FAILURE ) ;
+ }
+ }
+
+ return( TFLE_NO_ERR ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_WtCloseTape
+
+ Description: Writes an EOTM on the tape.
+
+ Returns: An error code if an error occurred.
+
+ Notes: THE DRIVE MUST BE IN SINGLE STEP MODE BEFORE CALLING
+ THIS FUNCTION.
+
+**/
+INT16 F40_WtCloseTape(
+ CHANNEL_PTR channel )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ INT16 drv_hdl = channel->cur_drv->drv_hdl ;
+ DRIVE_PTR curDRV = channel->cur_drv ;
+ RET_BUF myret ;
+ MTF_EOTM_PTR cur_eotm ;
+ MTF_DB_HDR_PTR cur_hdr ;
+ BUF_PTR tmpBUF ;
+ UINT16 offset ;
+ INT16 ret_val ;
+ UINT16 temp_os_id ;
+ UINT16 temp_os_ver ;
+
+ if( ! cur_env->eotm_no_first_fmk ) {
+ /* drop a filemark */
+ if( ( ret_val = WriteEndSet( curDRV ) ) != TFLE_NO_ERR ) {
+ return( ret_val ) ;
+ }
+ }
+
+ /* Get a buffer */
+ tmpBUF = BM_GetVCBBuff( &channel->buffer_list ) ;
+
+ cur_eotm = (MTF_EOTM_PTR)( BM_XferBase( tmpBUF ) ) ;
+ cur_hdr = (MTF_DB_HDR_PTR)cur_eotm ;
+
+ channel->cur_dblk = (DBLK_PTR)channel->lst_osvcb ; /* GRH - Why is this here!?! Just for call to SetupDBHeader??? See if it can go away!!! */
+ offset = sizeof( MTF_EOTM ) ;
+
+ /* Here we do our own version of SetupDBHeader that does only what
+ we need, and not all the extranious stuff.
+ */
+
+ F40_SetBlkType( cur_hdr, MTF_EOTM_N ) ;
+
+ (VOID)FS_GetOSid_verFromDBLK( channel->cur_fsys, channel->cur_dblk, &temp_os_id, &temp_os_ver ) ;
+
+ cur_hdr->machine_os_id = (UINT8)temp_os_id;
+ cur_hdr->machine_os_version = (UINT8)temp_os_ver ;
+ cur_hdr->logical_block_address = U64_Init( 0L, 0L ) ;
+ cur_hdr->os_specific_data.data_offset = 0 ;
+ cur_hdr->os_specific_data.data_size = 0 ;
+ cur_hdr->session_id = U64_Init( 0L, 0L ) ;
+ cur_hdr->displayable_size = U64_Init( 0L, 0L ) ;
+ cur_hdr->string_type = (UINT8)FS_GetStringTypes( channel->cur_fsys ) ;
+ cur_hdr->block_attribs = 0L ;
+
+ offset += (UINT16)PadToLBBoundary( offset ) ;
+ offset += PadToBoundary( offset, ChannelBlkSize( channel ) ) ;
+
+ /* If we're doing OTC, set PBA of the second ESET of the last set
+ completed on this tape. If not doing OTC or no set was completed
+ on this tape, set block attributes to indicate this.
+ */
+ cur_eotm->eset_phys_blk_adr = U64_Init( cur_env->eset_pba, 0L ) ;
+ if( cur_env->cur_otc_level != TCL_NONE ) {
+ if( cur_env->eset_pba == 0L ) {
+ cur_eotm->block_hdr.block_attribs |= MTF_DB_NO_ESET_PBA ;
+ }
+ } else {
+ cur_eotm->block_hdr.block_attribs |= MTF_DB_INVALID_ESET_PBA ;
+ }
+
+ cur_eotm->block_hdr.hdr_chksm = F40_CalcChecksum( (UINT16_PTR)cur_eotm, F40_HDR_CHKSUM_LEN ) ;
+ DRIVER_CALL( drv_hdl, TpWrite( drv_hdl, BM_XferBase( tmpBUF ), (UINT32)offset ),
+ myret, GEN_NO_ERR, GEN_ERR_EOM, BM_Put( tmpBUF ) )
+
+ BM_Put( tmpBUF ) ;
+
+ /* drop a filemark */
+ ret_val = WriteEndSet( curDRV ) ;
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_WtContTape
+
+ Description: Writes the continuation info for a given tape.
+
+ Returns: INT16 - TFLE_xxx
+
+ Notes:
+
+**/
+INT16 F40_WtContTape(
+ CHANNEL_PTR channel )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ INT16 drv_hdl = channel->cur_drv->drv_hdl ;
+ RET_BUF myret ;
+ BUF_PTR tmpBUF ;
+ UINT32 eom_id ;
+ MTF_DB_HDR_PTR cur_hdr ;
+ UINT16 num_lbs ;
+ UINT16 offset ;
+ UINT16 end_db_offset ;
+ UINT16 strm_hdr_size ;
+ UINT16 blk_size = MAX( (UINT16)F40_LB_SIZE, ChannelBlkSize( channel ) ) ;
+ INT16 ret_val ;
+
+ if( cur_env->cur_otc_level == TCL_FULL && !cur_env->fdd_aborted &&
+ !IsChannelStatus( channel, CH_EOS_AT_EOM ) ) {
+
+ if( ( ret_val = OTC_PreprocessEOM( cur_env, channel->eom_lba ) ) != TFLE_NO_ERR ) {
+ return( ret_val ) ;
+ }
+ }
+
+ if( !cur_env->end_set_continuing ) {
+ cur_env->sm_count++ ;
+ }
+
+ /* Get a buffer */
+ tmpBUF = BM_GetVCBBuff( &channel->buffer_list ) ;
+
+ channel->cur_dblk = (DBLK_PTR)channel->lst_osvcb ;
+
+ /* In this first pass, we will write all the continuation DBLKs
+ to the buffer, then we will make a second pass adjusting their
+ LBAs.
+ */
+
+ eom_id = channel->eom_id ;
+ channel->eom_id = FS_ViewBLKIDinDBLK( channel->cur_dblk ) ;
+
+ /* This will write the tape header and put the SSET and VOLB blocks
+ in the buffer.
+ */
+ if( ( ret_val = F40_WtSSET( channel, tmpBUF, TRUE ) ) != TFLE_NO_ERR ) {
+ BM_Put( tmpBUF ) ;
+ return( ret_val ) ;
+ }
+
+ if( channel->lst_tblk != BT_VCB &&
+ !IsChannelStatus( channel, CH_EOS_AT_EOM ) ) {
+
+ if( channel->lst_tblk == BT_IDB ) {
+ channel->cur_dblk = (DBLK_PTR)channel->lst_osfdb ;
+ channel->eom_id = FS_ViewBLKIDinDBLK( channel->cur_dblk ) ;
+ if( ( ret_val = F40_WtIMAG( channel, tmpBUF, TRUE ) ) != TFLE_NO_ERR ) {
+ BM_Put( tmpBUF ) ;
+ return( ret_val ) ;
+ }
+ } else {
+ channel->cur_dblk = (DBLK_PTR)channel->lst_osddb ;
+ channel->eom_id = FS_ViewBLKIDinDBLK( channel->cur_dblk ) ;
+ if( ( ret_val = F40_WtDIRB( channel, tmpBUF, TRUE ) ) != TFLE_NO_ERR ) {
+ BM_Put( tmpBUF ) ;
+ return( ret_val ) ;
+ }
+ if( channel->lst_tblk == BT_FDB ) {
+
+ channel->cur_dblk = (DBLK_PTR)channel->lst_osfdb ;
+ channel->eom_id = FS_ViewBLKIDinDBLK( channel->cur_dblk ) ;
+ if( ( ret_val = F40_WtFILE( channel, tmpBUF, TRUE ) ) != TFLE_NO_ERR ) {
+ BM_Put( tmpBUF ) ;
+ return( ret_val ) ;
+ }
+ }
+ }
+ }
+
+ /* This is pass 2, adjusting the LBAs */
+ offset = BM_NextByteOffset( tmpBUF ) ;
+ offset += PadToBoundary( offset, blk_size ) ;
+ num_lbs = (UINT16)( offset / F40_LB_SIZE ) ;
+ offset = BM_NextByteOffset( tmpBUF ) ;
+ BM_SetNextByteOffset( tmpBUF, (UINT16)0 ) ;
+ do {
+ cur_hdr = (MTF_DB_HDR_PTR)BM_NextBytePtr( tmpBUF ) ;
+ cur_hdr->logical_block_address = U64_Init( ( channel->eom_lba - num_lbs ), 0L ) ;
+ cur_hdr->hdr_chksm = F40_CalcChecksum( (UINT16_PTR)cur_hdr, F40_HDR_CHKSUM_LEN ) ;
+ num_lbs -= ( UINT16 ) cur_hdr->offset_to_data / ( UINT16 ) F40_LB_SIZE ;
+ BM_UpdCnts( tmpBUF, cur_hdr->offset_to_data ) ;
+
+ /* Set the LBA in the DBLK */
+ switch( F40_GetBlkType( cur_hdr ) ) {
+
+ case F40_SSET_IDI :
+ FS_SetLBAinDBLK( (DBLK_PTR)channel->lst_osvcb,
+ U64_Lsw( cur_hdr->logical_block_address ) ) ;
+
+ /* Fix for the app not knowing the LBA for a continuation VCB */
+ channel->cross_set = FS_ViewBSNumInVCB( channel->lst_osvcb ) ;
+ channel->cross_lba = U64_Lsw( cur_hdr->logical_block_address ) ;
+
+ break ;
+
+ case F40_VOLB_IDI :
+ break ;
+
+ case F40_DIRB_IDI :
+ FS_SetLBAinDBLK( (DBLK_PTR)channel->lst_osddb,
+ U64_Lsw( cur_hdr->logical_block_address ) ) ;
+ break ;
+
+ case F40_FILE_IDI :
+ case F40_IMAG_IDI :
+ FS_SetLBAinDBLK( (DBLK_PTR)channel->lst_osfdb,
+ U64_Lsw( cur_hdr->logical_block_address ) ) ;
+ break ;
+
+ default :
+ /* This is a yucky little fix for the fact that GetBlkType
+ now returns UDB for the VOLB block because we need to
+ skip VOLBs if there are multiple ones in a single set.
+ */
+
+ /* DO NOT UNICODEIZE THE FOLLOWING CONSTANT!!! */
+ if( memcmp( cur_hdr->block_type, "VOLB", 4 ) != 0 ) {
+ msassert( FALSE ) ;
+ BM_Put( tmpBUF ) ;
+ return( TFLE_TRANSLATION_FAILURE ) ;
+ }
+ }
+
+ } while( BM_NextByteOffset( tmpBUF ) != offset ) ;
+
+ cur_hdr->offset_to_data += PadToBoundary( offset, blk_size ) ;
+ offset += PadToBoundary( offset, blk_size ) ;
+
+ if( cur_env->stream_at_eom &&
+ U64_NE( cur_env->eom_stream.data_length, lw_UINT64_ZERO ) ) {
+
+ if( cur_env->pstream_crosses ) {
+ strm_hdr_size = cur_env->pstream_offset ;
+ } else {
+ strm_hdr_size = sizeof( MTF_STREAM ) ;
+ cur_env->eom_stream.tf_attribs |= STREAM_CONTINUE ;
+ cur_env->eom_stream.chksum =
+ F40_CalcChecksum( (UINT16_PTR)&cur_env->eom_stream,
+ F40_STREAM_CHKSUM_LEN ) ;
+ }
+
+ end_db_offset = cur_hdr->os_specific_data.data_offset +
+ cur_hdr->os_specific_data.data_size ;
+ LongAlignOffset( end_db_offset ) ;
+ if( cur_hdr->offset_to_data - end_db_offset < strm_hdr_size ) {
+ cur_hdr->offset_to_data += blk_size ;
+ offset += blk_size ;
+ }
+ cur_hdr->offset_to_data -= strm_hdr_size ;
+ memcpy( (UINT8_PTR)cur_hdr + cur_hdr->offset_to_data,
+ &cur_env->eom_stream, strm_hdr_size ) ;
+ }
+
+ cur_hdr->hdr_chksm = F40_CalcChecksum( (UINT16_PTR)cur_hdr, F40_HDR_CHKSUM_LEN ) ;
+
+ DRIVER_CALL( drv_hdl, TpWrite( drv_hdl, (UINT8_PTR)BM_XferBase( tmpBUF ), (UINT32)offset ),
+ myret, GEN_NO_ERR, GEN_NO_ERR, BM_Put( tmpBUF ) )
+
+ /* Back to normal */
+ channel->eom_id = eom_id ;
+ BM_Put( tmpBUF ) ;
+
+ if( cur_env->cur_otc_level != TCL_NONE && !cur_env->sm_aborted ) {
+ if( ( ret_val = OTC_PostprocessEOM( channel, channel->cross_lba ) ) != TFLE_NO_ERR ) {
+ return( ret_val ) ;
+ }
+ }
+
+ return( TFLE_NO_ERR ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_WtContVStream
+
+ Description: Writes a copy of the current variable length stream
+ header to the buffer.
+
+ Returns: TFLE_xxx error code.
+
+ Notes: If the stream is variable, we write it in chunks, with
+ stream headers in front of each chunk. The first
+ chunk is written by F40_WtStream, then subsequent
+ chunks are written by this function. The size provided
+ in the stream info is zero for variable length streams,
+ but the actual stream header must contain the size of
+ the chunk. Therefore, the data_length field is set to
+ the number of bytes remaining in the buffer. See
+ F40_WtEndVStream for details on how the data_length
+ field is adjusted when we reach the end of the data
+ stream.
+
+ There is an assumption made in this function that we
+ have the full buffer to play with, since chunk sizes
+ are always based on the total remaining space in the
+ current buffer, only the first header written by
+ F40_WtStream would ever be written at points other than
+ the front of the buffer.
+
+**/
+INT16 F40_WtContVStream(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)channel->fmt_env ;
+ BOOLEAN status ;
+ INT16 ret_val = TFLE_NO_ERR ;
+
+ /* This may have been set by WtStream to indicate to EndVStream that
+ the stream header crossed a tape boundary. This header obviously
+ doesn't cross buffers, so we clear the flag.
+ */
+ cur_env->stream_crosses = FALSE ;
+
+ cur_env->cur_stream.data_length =
+ U64_Init( BM_XferSize( buffer ) - sizeof( MTF_STREAM ), 0L ) ;
+ cur_env->cur_stream.chksum =
+ F40_CalcChecksum( (UINT16_PTR)&cur_env->cur_stream,
+ F40_STREAM_CHKSUM_LEN ) ;
+ memcpy( BM_XferBase( buffer ), &cur_env->cur_stream, sizeof( MTF_STREAM ) ) ;
+ BM_UpdCnts( buffer, sizeof( MTF_STREAM ) ) ;
+
+ channel->current_stream.size = cur_env->cur_stream.data_length ;
+ cur_env->var_stream_offset = 0L ;
+ cur_env->used_so_far = U64_Add( cur_env->used_so_far,
+ U64_Init( sizeof( MTF_STREAM ), 0L ), &status ) ;
+ cur_env->used_so_far = U64_Add( cur_env->used_so_far,
+ cur_env->cur_stream.data_length, &status ) ;
+
+ /* Setup DBLK map */
+ if( ( ret_val = GetDBLKMapStorage( channel, buffer ) ) == TFLE_NO_ERR ) {
+ BM_IncNoDblks( buffer ) ;
+ channel->map_entry->blk_offset = 0 ;
+ channel->map_entry->blk_type = BT_STREAM ;
+ channel->map_entry->blk_data = cur_env->cur_stream.data_length ;
+ }
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_WtEndVStream
+
+ Description: Rewrites the last variable stream header as a variable
+ stream ending header.
+
+ Returns: Nothing
+
+ Notes: If the stream is variable, we write it in chunks, with
+ stream headers in front of each chunk. When each
+ header is written, the data_length field is set to the
+ number of bytes remaining in the buffer. When the end
+ of the stream is reached, this function is called with
+ 'used' set to the portion of the last chunk which was
+ actually filled with data. This function backs up to
+ the last stream header written to the buffer (located
+ with 'var_stream_offset'), and changes the attributes
+ to indicate this is the last chunk for this stream.
+
+ If the flag 'stream_crosses' in the environment is TRUE,
+ then the stream header spans from the end of the buffer
+ pointed to by 'channel->hold_buff' to the front of the
+ buffer passed in, and this must be dealt with in
+ rewriting the stream header.
+
+**/
+VOID F40_WtEndVStream(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer,
+ UINT16 used )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)channel->fmt_env ;
+ UINT64 used_64 = U64_Init( (UINT32)used, 0L ) ;
+ UINT64 diff ;
+ BOOLEAN status ;
+
+ cur_env->cur_stream.tf_attribs |= STREAM_VAR_END ;
+ cur_env->cur_stream.tf_attribs &= ~STREAM_VARIABLE ;
+ channel->current_stream.tf_attrib &= ~STREAM_VARIABLE ;
+
+ diff = U64_Sub( cur_env->cur_stream.data_length, used_64, &status ) ;
+ cur_env->used_so_far = U64_Sub( cur_env->used_so_far, diff, &status ) ;
+
+ channel->map_entry->blk_data = cur_env->cur_stream.data_length = used_64 ;
+ cur_env->cur_stream.chksum =
+ F40_CalcChecksum( (UINT16_PTR)&cur_env->cur_stream,
+ F40_STREAM_CHKSUM_LEN ) ;
+ if( cur_env->stream_crosses ) {
+ cur_env->stream_crosses = FALSE ;
+ memcpy( (UINT8_PTR)BM_XferBase( channel->hold_buff ) +
+ cur_env->var_stream_offset, &cur_env->cur_stream,
+ cur_env->stream_offset ) ;
+ memcpy( BM_XferBase( buffer ),
+ (UINT8_PTR)&cur_env->cur_stream + cur_env->stream_offset,
+ sizeof( MTF_STREAM ) - cur_env->stream_offset ) ;
+
+ } else {
+ memcpy( (UINT8_PTR)BM_XferBase( buffer ) +
+ cur_env->var_stream_offset, &cur_env->cur_stream,
+ sizeof( MTF_STREAM ) ) ;
+ }
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_WtStream
+
+ Description: Writes a stream header into the buffer.
+
+ Returns: TFLE_xxx error code or NEED_NEW_BUFFER if there isn't
+ room to complete the stream header in the current buffer.
+
+ Notes: If the stream is variable, we write it in chunks, with
+ stream headers in front of each chunk. This function
+ writes the first chunk, then subsequent chunks are
+ written by F40_WtContVStream. The size provided in the
+ stream info is zero for variable length streams, but
+ the actual stream header must contain the size of the
+ chunk. Therefore, the data_length field is set to the
+ number of bytes remaining in the buffer. See
+ F40_WtEndVStream for details on how the data_length
+ field is adjusted when we reach the end of the data
+ stream.
+
+**/
+
+INT16 F40_WtStream(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer,
+ STREAM_INFO_PTR new_stream )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)channel->fmt_env ;
+ BOOLEAN status ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ UINT16 pad ;
+ UINT16 rem_strm ;
+
+ /* If stream_crosses is TRUE, we are being called back to fill out the
+ rest of a stream we started in the last buffer. Otherwise we need
+ to initialize the basic fields for the stream header.
+ */
+ if( !cur_env->stream_crosses ) {
+ /* Pad to align stream on four byte boundary (format spec). */
+ pad = PadToBoundary( BM_NextByteOffset( buffer ), 4 ) ;
+ cur_env->used_so_far = U64_Add( U64_Init( (UINT32)pad, 0L ),
+ cur_env->used_so_far, &status ) ;
+ BM_UpdCnts( buffer, pad ) ;
+
+ /* If we don't even have room to start a new stream header, there
+ isn't any point in setting anything up. So we return failure
+ now to force a call-back as if we'd never been called at all.
+ */
+ if( BM_BytesFree( buffer ) == 0 ) {
+ return( NEED_NEW_BUFFER ) ;
+ }
+
+ cur_env->cur_stream.id = new_stream->id ;
+ cur_env->cur_stream.fs_attribs = new_stream->fs_attrib ;
+ cur_env->cur_stream.tf_attribs = new_stream->tf_attrib ;
+ cur_env->cur_stream.data_length = new_stream->size ;
+ cur_env->cur_stream.encr_algor = 0 ;
+ cur_env->cur_stream.comp_algor = 0 ;
+
+ /* Setup DBLK map */
+ if( ( ret_val = GetDBLKMapStorage( channel, buffer ) ) != TFLE_NO_ERR ) {
+ return( ret_val ) ;
+ }
+ BM_IncNoDblks( buffer ) ;
+ channel->map_entry->blk_offset = BM_NextByteOffset( buffer ) ;
+ channel->map_entry->blk_type = BT_STREAM ;
+ channel->map_entry->blk_data = new_stream->size ;
+ }
+
+ /* One of three thing is true at this point:
+
+ 1. We're being called back to finish a stream header we started in
+ the last buffer.
+ 2. This is the first time called for this stream header, but we
+ don't have room to write it and will have to be called back.
+ 3. This is the first time called, and we have room (general case).
+ */
+ if( cur_env->stream_crosses ) {
+
+ /* Case 1:
+
+ We need to write the remainder of the stream at the front of
+ the new buffer. If this is a variable length stream, we need
+ to fill in the data_length field, because it could not be
+ determined until we got the new buffer (see note in header for
+ explanation). This means we also have to calculate the
+ checksum, and write the first half of the stream header
+ to the end of the previous buffer which is being held in
+ channel->hold_buff. Note that if the stream isn't variable
+ we clear the stream_crosses flag immediatly, otherwise we leave
+ it set in case have to rewrite the stream header as an "end
+ variable stream" (see the function F40_EndVBLK for further
+ details).
+ */
+ rem_strm = sizeof( MTF_STREAM ) - cur_env->stream_offset ;
+
+ if( cur_env->cur_stream.tf_attribs & STREAM_VARIABLE ) {
+ cur_env->cur_stream.data_length =
+ U64_Init( BM_BytesFree( buffer ) -
+ rem_strm, 0L ) ;
+ channel->map_entry->blk_data = new_stream->size =
+ cur_env->cur_stream.data_length ;
+ cur_env->cur_stream.chksum =
+ F40_CalcChecksum( (UINT16_PTR)&cur_env->cur_stream,
+ F40_STREAM_CHKSUM_LEN ) ;
+ memcpy( BM_NextBytePtr( channel->hold_buff ),
+ &cur_env->cur_stream, cur_env->stream_offset ) ;
+ BM_UpdCnts( channel->hold_buff, cur_env->stream_offset ) ;
+
+ } else {
+ cur_env->stream_crosses = FALSE ;
+ }
+
+ memcpy( BM_XferBase( buffer ), (UINT8_PTR)&cur_env->cur_stream +
+ cur_env->stream_offset, rem_strm ) ;
+ BM_UpdCnts( buffer, rem_strm ) ;
+
+ cur_env->used_so_far = U64_Add( U64_Init( sizeof( MTF_STREAM ), 0L ),
+ cur_env->used_so_far, &status ) ;
+ cur_env->used_so_far = U64_Add( cur_env->used_so_far,
+ cur_env->cur_stream.data_length,
+ &status ) ;
+
+ } else if( BM_BytesFree( buffer ) < sizeof( MTF_STREAM ) ) {
+
+ /* Case 2:
+
+ If the stream is variable, we don't know what value goes in
+ the data_length (see note in header for explanation), so there's
+ no point in writing anything. We point channel->hold_buff at
+ the buffer so the caller won't send it off to tape. This way
+ we can fill it in when we are called back. This buffer is then
+ held on to until we are certain that we don't have to rewrite
+ the stream header as an "end variable stream" (see the function
+ F40_EndVBLK for further details).
+ If the stream isn't variable, we fill it out in full, and
+ write as much as we can fit at the end of the buffer. The
+ caller is free to send this buffer off to tape immediatly.
+ In both cases, we set the stream_crosses flag to remember
+ we're being called back, and return FAILURE so the caller will
+ call us back with a fresh buffer.
+ */
+ ret_val = NEED_NEW_BUFFER ;
+ cur_env->stream_offset = BM_BytesFree( buffer ) ;
+ cur_env->stream_crosses = TRUE ;
+
+ if( cur_env->cur_stream.tf_attribs & STREAM_VARIABLE ) {
+ channel->hold_buff = buffer ;
+ cur_env->var_stream_offset = BM_NextByteOffset( buffer ) ;
+
+ } else {
+ cur_env->cur_stream.chksum =
+ F40_CalcChecksum( (UINT16_PTR)&cur_env->cur_stream,
+ F40_STREAM_CHKSUM_LEN ) ;
+ memcpy( BM_NextBytePtr( buffer ), &cur_env->cur_stream,
+ cur_env->stream_offset ) ;
+ BM_UpdCnts( buffer, cur_env->stream_offset ) ;
+ }
+
+ } else {
+
+ /* Case 3:
+
+ This is the most common of the three cases. If the stream is
+ variable, we calculate the data_length (see note in header for
+ explanation), then we calculate the checksum, and copy the
+ header into the buffer.
+ */
+ if( cur_env->cur_stream.tf_attribs & STREAM_VARIABLE ) {
+ cur_env->cur_stream.data_length =
+ U64_Init( BM_BytesFree( buffer ) -
+ sizeof( MTF_STREAM ), 0L ) ;
+ channel->map_entry->blk_data = new_stream->size =
+ cur_env->cur_stream.data_length ;
+ cur_env->var_stream_offset = (UINT32)BM_NextByteOffset( buffer ) ;
+ }
+
+ cur_env->cur_stream.chksum =
+ F40_CalcChecksum( (UINT16_PTR)&cur_env->cur_stream,
+ F40_STREAM_CHKSUM_LEN ) ;
+ memcpy( BM_NextBytePtr( buffer ), &cur_env->cur_stream,
+ sizeof( MTF_STREAM ) ) ;
+ BM_UpdCnts( buffer, sizeof( MTF_STREAM ) ) ;
+
+ cur_env->used_so_far = U64_Add( U64_Init( sizeof( MTF_STREAM ), 0L ),
+ cur_env->used_so_far, &status ) ;
+ cur_env->used_so_far = U64_Add( cur_env->used_so_far,
+ cur_env->cur_stream.data_length,
+ &status ) ;
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_EndData
+
+ Description: Writes a pad stream header to the buffer and updates
+ the byte counts in the buffer to pad out to a logical
+ block boundary in preparation for writing the next DBLK.
+
+ Returns: TFLE_xxx error code or NEED_NEW_BUFFER if there isn't
+ room to complete the stream header in the current buffer.
+
+ Notes: It is possible that the amount of pad that is needed is
+ smaller than a stream header. In this case we add one
+ logical block size to the size of the pad. Since
+ buffer sizes are evenly divisable by the logical block
+ size, a pad stream will normally fit in the current
+ buffer, but in this special case, it is possible that
+ the pad stream header will cross buffer boundaries.
+ So we call F40_WtStream to write the pad stream, as it
+ is set up to deal with this whole mess.
+
+**/
+INT16 F40_EndData(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)channel->fmt_env ;
+ STREAM_INFO info ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ UINT16 offset ;
+
+ if( !cur_env->stream_crosses ) {
+ /* Pad to align stream on four byte boundary (format spec).
+ Note: F40_WtStream does this, but we do it first because if the
+ alignment puts us on a logical block boundary, we don't
+ need a pad stream.
+ */
+ offset = PadToBoundary( BM_NextByteOffset( buffer ), 4 ) ;
+ BM_UpdCnts( buffer, offset ) ;
+ cur_env->pad_size =
+ (UINT16)PadToLBBoundary( BM_NextByteOffset( buffer ) ) ;
+
+ /* Bump pad size if smaller than stream header. */
+ if( cur_env->pad_size != 0 && cur_env->pad_size < sizeof( MTF_STREAM ) ) {
+ cur_env->pad_size += F40_LB_SIZE ;
+ }
+ }
+
+ if( cur_env->pad_size != 0 ) {
+ info.id = STRM_PAD ;
+ info.fs_attrib = 0 ;
+ info.tf_attrib = 0 ;
+ info.size = U32_To_U64( (UINT32)( cur_env->pad_size -
+ sizeof( MTF_STREAM ) ) ) ;
+
+ /* Note that this will fail once at most, and when it succeeds
+ we are gaurenteed, by virtue of the fact that the buffer sizes
+ are evenly divisible by the logical block size, that the
+ actual "pad data" will all fit in this buffer.
+ */
+ if( ( ret_val = F40_WtStream( channel, buffer, &info ) ) == TFLE_NO_ERR ) {
+ BM_UpdCnts( buffer, (UINT16)( U64_Lsw( info.size ) ) ) ;
+ }
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+ Unit: Translators
+
+ Name: F40_SaveLclName
+
+ Description: Saves the passed string and length in the destination
+ passed as a pointer. Assumes that the initial
+ destination pointer and last_alloc_size are set to zero,
+ as they are with a global variable. This will allocate
+ a chunk of memory to hold the name and if needed later
+ will release this memory and allocate a bigger chunk for
+ larger strings.
+
+ Returns: INT16 - TFLE_xxx error for no memory or no error code.
+
+**/
+/*
+ The following define is used to specify the minimum memory to be allocated
+ for path and machine names etc.
+*/
+#define F40_MIN_ALLOC 1024
+#define F40_CHUNK 64
+
+INT16 F40_SaveLclName(
+ UINT8_PTR *dest_string,
+ UINT8_PTR source_string,
+ UINT16_PTR dest_length,
+ UINT16_PTR last_alloc_size,
+ UINT16 source_length )
+{
+ UINT16 alloc_size ;
+
+ /* If there is not string space allocated or the desired length is
+ greater than the currently allocated length then we need to insure
+ that we have enough space for the current data.
+ */
+ if( *dest_string == NULL || source_length > *last_alloc_size ) {
+ if( *dest_string != NULL ) {
+ /* Release the existing memory since we need to allocate more */
+ free( *dest_string ) ;
+ *dest_string = NULL ; /* Mark as not allocated */
+ } else {
+ *last_alloc_size = 0 ;
+ }
+
+ if( source_length > (UINT16)0 ) {
+ /* There is something to copy so we need to get the storage.
+ This probably needs to have some smarts added to it to
+ keep a small static size that can be used for strings
+ that are shorter than some threshold. This will prevent
+ the malloc'ing of single bytes which can happen with the
+ 4.0 tape format.
+
+ We need to malloc the greater of minimum alloc size or
+ source_length, whichever is larger. This will avoid
+ successive mallocs of single bytes etc.
+ */
+ alloc_size = source_length ;
+ if( alloc_size % F40_CHUNK != 0 ) {
+ alloc_size += F40_CHUNK ; /* Add the chunk size */
+ }
+ alloc_size = max( (UINT16)alloc_size, F40_MIN_ALLOC ) ;
+ *dest_string = (UINT8_PTR)malloc( alloc_size ) ;
+ if( *dest_string == NULL ) {
+ return TFLE_NO_MEMORY ;
+ }
+
+ /* Update the static var last_size so we can use it to
+ determine if we need to release the current memory and
+ allocate more.
+ */
+ *last_alloc_size = alloc_size ;
+ *dest_length = source_length ;
+ memmove( *dest_string, source_string, (size_t)source_length ) ;
+
+ } else {
+
+ /* Nothing to copy so just set the length to 0 */
+ *dest_length = 0 ;
+ }
+
+ } else { /* End of env tape name needs malloc */
+
+ *dest_length = source_length ;
+ memmove( *dest_string, source_string, (size_t)source_length ) ;
+ }
+
+ return TFLE_NO_ERR ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_SetBlkType
+
+ Description: This function sets the passed block type in the
+ passed in block header.
+
+ Returns: Nothing
+
+ Notes: None
+
+**/
+VOID F40_SetBlkType(
+ MTF_DB_HDR_PTR cur_hdr, /* The current tape block header structure*/
+ UINT8_PTR block_id )
+{
+ INT i ;
+
+ for ( i = 0 ; i < 4 ; i++ ) {
+ cur_hdr->block_type[i] = block_id[i] ;
+ }
+}
+
+/**/
+/**
+
+ Name: F40_CalcRunningLBA
+
+ Description: This calculates the number of Logical block the last
+ Format 4.0 block occupied.
+
+ Returns: Number of Logical Blocks the last DBLK occupied
+
+ Notes:
+
+ Declaration:
+
+**/
+UINT32 F40_CalcRunningLBA( F40_ENV_PTR CurrentEnv )
+{
+ UINT64 remaining ;
+ BOOLEAN status ;
+ UINT32 noLBAs ;
+
+ noLBAs = U64_Lsw( U64_Div( CurrentEnv->used_so_far,
+ U64_Init( F40_LB_SIZE, 0L ),
+ &remaining, &status ) ) ;
+
+ noLBAs += remaining.lsw ? 1L : 0L ;
+
+ return( noLBAs ) ;
+
+}
+
+
+/**/
+/**
+ Unit: Translators
+
+ Name: F40_WriteInit
+
+ Modified:
+
+ Description: Initializes the OTC temporary files.
+
+ Notes: The otc_level is for the current set, but it must be
+ compatible with the max_otc_level for the tape as follows:
+
+ MAX ALLOWED
+ --- -------
+ NONE NONE
+ PARTIAL PARTIAL
+ FULL PARTIAL or FULL
+
+ Returns: INT16 - TFLE_xxx error code.
+
+**/
+INT16 F40_WriteInit(
+ CHANNEL_PTR channel, /* Current active channel */
+ UINT16 otc_level, /* Attributes for OTC */
+ BUF_PTR buffer ) /* For GetPrevSM */
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ BOOLEAN sm_exists ;
+ BOOLEAN appending = ( channel->tape_id != 0L ) ;
+ UINT16 ret_val ;
+
+ if( appending && !( lw_fmtdescr[channel->cur_fmt].attributes & APPEND_SUPPORTED ) ) {
+ return( TFLE_APPEND_NOT_ALLOWED ) ;
+ }
+
+ cur_env->sm_count = 1 ;
+ cur_env->dir_count = 0 ;
+ cur_env->file_count = 0 ;
+ cur_env->fdd_seq_num = 0 ;
+ cur_env->fdd_pba = 0L ;
+ cur_env->fdd_aborted = FALSE ;
+ cur_env->sm_aborted = FALSE ;
+ cur_env->fdd_completed = FALSE ;
+ cur_env->sm_adjusted = FALSE ;
+ cur_env->fdd_continuing = FALSE ;
+ cur_env->sm_continuing = FALSE ;
+ cur_env->end_set_continuing = FALSE ;
+ cur_env->eotm_no_first_fmk = FALSE ;
+ cur_env->corrupt_obj_count = 0 ;
+ cur_env->dir_links[0] = 0L ;
+ cur_env->dir_level = 0 ;
+ cur_env->max_dir_level = 0 ;
+ cur_env->last_volb = -1L ;
+ cur_env->stream_crosses = FALSE ;
+ cur_env->stream_offset = 0 ;
+ cur_env->stream_at_eom = FALSE ;
+ cur_env->pstream_crosses = FALSE ;
+ cur_env->pstream_offset = 0 ;
+
+ cur_env->cur_otc_level = otc_level ;
+
+ /* Temporary way to stop OTC on drives that don't have seek capability */
+ if( !SupportBlkPos( channel->cur_drv ) ||
+ !SupportFastEOD( channel->cur_drv ) ||
+ !SupportRevFmk( channel->cur_drv ) ||
+ ( cur_env->max_otc_level == TCL_NONE && appending ) ) {
+
+ cur_env->cur_otc_level = TCL_NONE ;
+ }
+
+ if( cur_env->cur_otc_level == TCL_NONE ) {
+ msassert( cur_env->max_otc_level == TCL_NONE ) ;
+ if( cur_env->max_otc_level != TCL_NONE ) {
+ return( TFLE_OTC_FAILURE ) ;
+ } else {
+ return( TFLE_NO_ERR ) ;
+ }
+ }
+
+ if( ( ret_val = OTC_OpenSM( cur_env, appending, &sm_exists ) ) != TFLE_NO_ERR ) {
+ cur_env->sm_aborted = TRUE ;
+ cur_env->fdd_aborted = TRUE ;
+ return( ret_val ) ;
+ }
+
+ if( appending ) {
+ if( !sm_exists ) {
+ if( ( ret_val = OTC_GetPrevSM( channel, buffer, FALSE, TRUE ) ) != TFLE_NO_ERR ) {
+ cur_env->sm_aborted = TRUE ;
+ cur_env->fdd_aborted = TRUE ;
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ return( ret_val ) ;
+ }
+ }
+ } else {
+ if( ( ret_val = OTC_GenSMHeader( channel ) ) != TFLE_NO_ERR ) {
+ cur_env->sm_aborted = TRUE ;
+ cur_env->fdd_aborted = TRUE ;
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ return( ret_val ) ;
+ }
+ }
+
+ if( cur_env->cur_otc_level == TCL_FULL ) {
+ msassert( cur_env->max_otc_level == TCL_FULL ) ;
+ if( cur_env->max_otc_level != TCL_FULL ) {
+ cur_env->cur_otc_level = TCL_PARTIAL ;
+ return( TFLE_NO_ERR ) ;
+ }
+ if( ( ret_val = OTC_OpenFDD( cur_env ) ) != TFLE_NO_ERR ) {
+ cur_env->sm_aborted = TRUE ;
+ cur_env->fdd_aborted = TRUE ;
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ return( ret_val ) ;
+ }
+ }
+
+ return( TFLE_NO_ERR ) ;
+}
+
diff --git a/private/utils/ntbackup/src/mui.c b/private/utils/ntbackup/src/mui.c
new file mode 100644
index 000000000..94ac39f25
--- /dev/null
+++ b/private/utils/ntbackup/src/mui.c
@@ -0,0 +1,1904 @@
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: mui.c
+
+ Description: This file contains the functions for the Maynard User
+ Interface (MUI) to the Graphical User Interface and the
+ Backup Engine.
+
+ $Log: G:\ui\logfiles\mui.c_v $
+
+ Rev 1.83.2.0 25 Jan 1994 15:49:38 chrish
+Added fix for ORCAS EPR 0054. Problem with using a space as a valid
+character in the log file name or directory name.
+
+ Rev 1.83 16 Aug 1993 14:55:38 BARRY
+Got rid of unresolved externals for NTBACKUP.
+
+ Rev 1.82 05 Aug 1993 17:43:48 GLENN
+Checking for a valid job name pointer now.
+
+ Rev 1.81 05 Aug 1993 17:32:02 GLENN
+Not initializing tape device or hardware if this is a command line job. Job Start will.
+
+ Rev 1.80 05 Aug 1993 13:23:30 GLENN
+Added support to allow mui to completely init if we were told to terminate the app - (allows proper deinit).
+
+ Rev 1.79 03 Aug 1993 20:59:38 CHUCKB
+Make job name string global and changed its name accordingly.
+
+ Rev 1.78 21 Jul 1993 18:02:02 MARINA
+enable c++
+
+ Rev 1.77 21 Jul 1993 16:55:16 GLENN
+Added operation queing support.
+
+ Rev 1.76 16 Jul 1993 13:38:24 chrish
+CAYMAN EPR 0564: Added code to open and close log file for writing information
+about invalid directories passed on the command line.
+
+ Rev 1.75 02 Jun 1993 13:21:30 DARRYLP
+Fixed the slight problem in which the iconified application does not
+permit keyboard switching when the backup is finished.
+
+ Rev 1.74 25 May 1993 15:44:44 GLENN
+Moved the mui deinit flag to top of MUI_Deinit().
+
+ Rev 1.73 25 May 1993 09:42:04 GLENN
+Fixed hardware init logic.
+
+ Rev 1.72 20 May 1993 13:36:54 DARRYLP
+Kill WinHelp if we called it and it is up during our termination.
+
+ Rev 1.71 18 May 1993 20:21:50 GLENN
+Added enable state for advanced button if it is not a search window.
+
+ Rev 1.70 18 May 1993 15:01:52 GLENN
+Changed tool bar settings based on window type.
+
+ Rev 1.69 14 May 1993 14:14:46 TIMN
+Added f(x) call to physically claim a specified tape device. No impact to
+NOST. Cayman needs hwconfnt.c dil_nt.c be_dinit.c global.c global.h hwconf.h
+
+
+ Rev 1.68 04 May 1993 12:59:28 BARRY
+Fixed MIPS compile error.
+
+ Rev 1.67 03 May 1993 11:40:52 TIMN
+Updated invalid device value which was changed in global.c
+
+ Rev 1.66 29 Apr 1993 16:14:34 DARRYLP
+Eject Tape now makes you wait for it to complete before allowing the user
+to attempt anything else.
+
+ Rev 1.65 22 Apr 1993 15:55:54 GLENN
+Cleanup.
+
+ Rev 1.64 19 Apr 1993 15:22:58 GLENN
+Added global return code setting at end of operation.
+
+ Rev 1.63 09 Apr 1993 14:02:06 GLENN
+Improved logic in MUI_ActivateDocument().
+
+ Rev 1.62 02 Apr 1993 14:09:00 GLENN
+Added display info support.
+
+ Rev 1.61 25 Mar 1993 15:49:24 CARLS
+changes in TapeInDrive for update to retension button
+
+ Rev 1.60 24 Mar 1993 11:23:38 chrish
+Added code to MUI_EnableOperation to fix aborting in the middle of a
+backup.
+
+ Rev 1.59 22 Mar 1993 13:44:16 chrish
+Added gbCurrentOperation = OPERATION_CATALOG to MUI_StartOperation routine.
+
+ Rev 1.58 17 Mar 1993 17:50:36 CHUCKB
+Fixed cayman's handling of jobs.
+
+ Rev 1.57 11 Mar 1993 13:27:56 STEVEN
+add batch
+
+ Rev 1.56 10 Mar 1993 12:47:52 CARLS
+Changes to move Format tape to the Operations menu
+
+ Rev 1.55 20 Jan 1993 20:26:12 MIKEP
+add mem display to NT
+
+ Rev 1.54 23 Nov 1992 14:28:56 MIKEP
+add vm ptr to qtc_init call
+
+ Rev 1.53 18 Nov 1992 13:04:04 GLENN
+Fixed button states based on the poll drive state.
+
+ Rev 1.52 01 Nov 1992 16:02:58 DAVEV
+Unicode changes
+
+ Rev 1.51 30 Oct 1992 15:44:02 GLENN
+Moved the configuration deinit after the units deinit.
+
+ Rev 1.50 07 Oct 1992 14:10:50 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.49 04 Oct 1992 19:39:04 DAVEV
+Unicode Awk pass
+
+ Rev 1.48 02 Oct 1992 16:47:50 GLENN
+Fixed wait cursor - set cursor stuff.
+
+ Rev 1.47 28 Sep 1992 17:01:28 GLENN
+MikeP changes (DriveType).
+
+ Rev 1.46 22 Sep 1992 10:24:48 GLENN
+Added the net connect and disconnect stuff.
+
+ Rev 1.45 10 Sep 1992 17:19:14 GLENN
+Resolved outstanding state issues for toolbar and menubar.
+
+ Rev 1.44 09 Sep 1992 16:59:00 GLENN
+Updated toolbar stuff for BIMINI and NT.
+
+ Rev 1.43 08 Sep 1992 15:40:30 GLENN
+Resolved modeless dialog while loop.
+
+ Rev 1.42 02 Sep 1992 16:42:22 GLENN
+Added support for toolbar button states based on current window. MikeP added catalog enable stuff
+.
+
+ Rev 1.41 06 Aug 1992 13:17:30 CHUCKB
+Changes for NT.
+
+ Rev 1.40 27 Jun 1992 18:31:46 MIKEP
+another qtc change to init
+
+ Rev 1.39 27 Jun 1992 17:58:38 MIKEP
+changes for qtc
+
+ Rev 1.38 20 May 1992 18:07:42 GLENN
+Fixed added checking to strtok - command line stuff. Put in changes for 1.32.1.1 branch.
+
+ Rev 1.37 19 May 1992 09:26:16 MIKEP
+mo changes
+
+ Rev 1.36 15 May 1992 16:48:14 MIKEP
+incl_cds removal
+
+ Rev 1.35 14 May 1992 18:00:26 MIKEP
+nt pass 2
+
+ Rev 1.34 11 May 1992 15:47:58 GLENN
+Made sure RTD had focus when MUI_EnableOperations() was called, iff the RTD existed.
+
+ Rev 1.33 11 May 1992 14:20:36 DAVEV
+OEM_MSOFT: modifications for batch command line support
+
+ Rev 1.32 27 Apr 1992 16:19:50 JOHNWT
+get pw for pwdb before startup.bks
+
+ Rev 1.31 23 Apr 1992 15:57:40 JOHNWT
+added pwdb check to jobs
+
+ Rev 1.30 20 Apr 1992 13:54:42 GLENN
+Removed multitask from MUI_EnableOperations() - caused exit problems.
+
+ Rev 1.29 09 Apr 1992 11:32:18 GLENN
+Added catalog initializing and UI initializing status line calls.
+
+ Rev 1.28 07 Apr 1992 10:25:30 GLENN
+Added a call back when there is a system change. (future)
+
+ Rev 1.27 02 Apr 1992 15:39:56 GLENN
+Added NT support for tape-in-drive dependent selection bar buttons.
+
+ Rev 1.26 26 Mar 1992 17:05:32 STEVEN
+remove hwconfig
+
+ Rev 1.25 23 Mar 1992 11:53:28 GLENN
+Added bad data and catalog path warning support.
+
+ Rev 1.24 22 Mar 1992 12:55:52 JOHNWT
+finished stdmodewarn disable
+
+ Rev 1.23 20 Mar 1992 17:23:50 GLENN
+Added std mode warning config option.
+
+ Rev 1.22 20 Mar 1992 12:40:08 DAVEV
+Changes for OEM_MSOFT product alternate functionality
+
+ Rev 1.21 19 Mar 1992 09:30:16 MIKEP
+debug deinit
+
+ Rev 1.20 17 Mar 1992 17:13:54 GLENN
+Added standard mode warning message box.
+
+ Rev 1.19 10 Mar 1992 15:50:46 DAVEV
+fix for OEM_MSOFT changes
+
+ Rev 1.18 09 Mar 1992 09:23:10 GLENN
+GLENN - Added logo bitmap support. DAVEV - Added NT ifdef options
+
+ Rev 1.17 27 Feb 1992 13:53:02 GLENN
+Enabled poll drive for command line jobs and scheduled jobs.
+
+ Rev 1.16 18 Feb 1992 16:36:40 CHUCKB
+Added code to make auto job for verify.
+
+ Rev 1.15 11 Feb 1992 17:23:26 GLENN
+Fixed ribbon enabling for search window.
+
+ Rev 1.14 08 Feb 1992 16:50:38 MIKEP
+refresh all selections
+
+ Rev 1.13 05 Feb 1992 20:50:16 MIKEP
+pass config to qtc init
+
+ Rev 1.12 05 Feb 1992 17:39:46 GLENN
+Added MUI_Deinit() call when forcefully terminating app.
+
+ Rev 1.11 30 Jan 1992 12:36:02 GLENN
+Changed UI_TapeHWProblem to HWC_TapeHWProblem for modularity.
+
+ Rev 1.10 28 Jan 1992 08:27:28 JOHNWT
+fixed my fix
+
+ Rev 1.9 28 Jan 1992 08:24:40 JOHNWT
+fixed pwdb flag setting
+
+ Rev 1.8 27 Jan 1992 00:32:10 CHUCKB
+Updated dialog id's.
+
+ Rev 1.7 22 Jan 1992 12:32:48 GLENN
+Added animate icon support.
+
+ Rev 1.6 10 Jan 1992 15:47:40 CARLS
+removed strings
+
+ Rev 1.5 10 Jan 1992 11:18:12 DAVEV
+16/32 bit port-2nd pass
+
+ Rev 1.4 07 Jan 1992 17:29:42 GLENN
+Added catalog data path support
+
+ Rev 1.3 10 Dec 1991 14:30:22 GLENN
+Bunches of changes by everyone
+
+ Rev 1.2 04 Dec 1991 18:36:40 GLENN
+Updated for ALT-F4 termination
+
+ Rev 1.1 03 Dec 1991 16:19:10 GLENN
+Added advanced restore, catalog maint operation to list.
+
+ Rev 1.0 20 Nov 1991 19:16:42 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+#define MUI_NO_STARTUP_JOBS 0xFFFF
+#define MAX_QUEUED_OPERATIONS 1
+
+// PRIVATE MODULE-WIDE VARIABLES
+
+static WORD mwwLastDocType = ID_NOTDEFINED;
+static BOOL mwfInitialized = FALSE;
+static BOOL mwfTapeInDrive = FALSE;
+
+static BOOL mwfTapeValid = FALSE;
+
+static BOOL mwfInfoAvailable = FALSE;
+
+static INT nJobIndex = MUI_NO_STARTUP_JOBS;
+static LONG lSchedKey = 0L ;
+
+static UINT mwnQueuedOperationMsg = 0;
+static INT mwnNumOperationsInQueue = 0;
+
+// PRIVATE FUNCTION PROTOTYPES
+
+static VOID MUI_CheckPWDB ( CDS_PTR );
+
+static VOID MUI_ProcessQuotedString ( LPSTR,
+ LPSTR,
+ BOOLEAN * );
+
+
+
+/******************************************************************************
+
+ Name: MUI_Init()
+
+ Description: This function initializes the Maynard User Interface (MUI)
+ by creating the tool bar and initializing the Volume List
+ Manager (VLM), which in turn creates the primary
+ documents.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+BOOL MUI_Init ( VOID )
+
+{
+ BE_INIT_STR pBE;
+ INT16 nErrorBE;
+ INT16 nResult = SUCCESS;
+ CDS_PTR pCDS = CDS_GetPerm();
+ BOOL fReadStartup;
+ BOOL fDelayTermination = FALSE;
+
+
+ WM_ShowWaitCursor ( TRUE );
+
+ // Make and Activate the Main tool bar window.
+
+ ghRibbonMain = MUI_MakeMainRibbon ();
+ RIB_Activate ( ghRibbonMain );
+ RIB_Draw ( ghRibbonMain );
+
+ // Now disable the operations, (and setup the UI accordingly).
+ MUI_DisableOperations ( (WORD)NULL );
+
+ WM_FrameUpdate ();
+
+ // Show the LOGO window.
+# if !defined ( OEM_MSOFT )
+ {
+ WM_LogoShow ();
+ }
+# endif //!defined ( OEM_MSOFT )
+
+ // If the debug flag is set, turn the debug window on.
+
+ if ( gfDebug ) {
+ DBM_Init ();
+ }
+
+ zprintf ( DEBUG_USER_INTERFACE, RES_INIT_APPLICATION );
+
+ // Allow the GUI to fully initialize by multitasking for a moment.
+
+ WM_MultiTask ();
+
+ // Setup the common module-wide resources.
+
+ UI_SetResources( );
+
+ // Initialize only the FILE SYSTEM and BSDU.
+
+ nErrorBE = UI_UnitsInit( &pBE, INIT_FSYS_BSDU );
+
+#ifdef OS_WIN32
+
+ // Display memory usage
+
+ if ( gfShowMemory ) {
+ MEM_StartShowMemory();
+ }
+
+
+# ifdef OEM_MSOFT
+ // Determine the starting drive to use if we didn't set it on
+ // the command line already.
+
+ if ( TapeDevice == (INT)INVALID_HANDLE_VALUE ) {
+ TapeDevice = HWC_GetTapeDevice ();
+ }
+# endif
+
+
+#endif // OS_WIN32
+
+
+ // Report any initialization errors.
+
+ WM_ShowWaitCursor ( FALSE );
+ HWC_ReportDiagError( &pBE, nErrorBE, &nResult );
+ WM_ShowWaitCursor ( TRUE );
+
+ // Now, check for advance to hardware config before going further.
+ // If advance to config is set, the hardware configuration dialog
+ // will be called. If the hardware is then initialized, the global
+ // hardware initialized flag will be set.
+
+# if !defined ( OS_WIN32 ) //NTKLUG?: done by Steve for NT only
+ {
+ WM_ShowWaitCursor ( FALSE );
+
+ if ( CDS_GetAdvToConfig ( pCDS ) ) {
+
+ // Destroy the LOGO window.
+
+ WM_LogoDestroy ();
+
+ nResult = (INT16)DM_ShowDialog ( ghWndFrame, IDD_SETTINGSHARDWARE, (PVOID)0 );
+
+
+ // Clear the advance to hardware config flag.
+
+ CDS_SetAdvToConfig ( pCDS, FALSE );
+ }
+
+ // If the hardware is not initialized, initialize it by calling the
+ // hardware problem handler.
+
+ if ( ! gfHWInitialized ) {
+
+ HWC_TapeHWProblem ( bsd_list );
+ }
+
+ WM_ShowWaitCursor ( TRUE );
+
+ }
+# else
+ {
+ WM_ShowWaitCursor ( FALSE );
+
+# ifndef OEM_MSOFT
+
+ // If this is a command line job - the job will init the
+ // tape device.
+
+ if ( ! gpszJobName ) {
+ HWC_InitTapeDevice() ; // claims the tape device
+ }
+# endif
+
+ // If this is a command line job - the job will init the hardware.
+
+#if defined( OEM_MSOFT )
+ if ( ! gpszJobName && ! gfHWInitialized ) {
+#else
+ if ( ! gpszJobName && ! gfHWInitialized && ! HWC_IsDeviceNoDevice () ) {
+#endif
+
+ HWC_TapeHWProblem ( bsd_list );
+ }
+
+ CDS_SetAdvToConfig( CDS_GetPerm(), FALSE );
+
+ WM_ShowWaitCursor ( TRUE );
+ }
+# endif // OS_WIN32 - NTKLUG?
+
+ // If we were told to terminate the app during hardware init,
+ // temporarily delay that order so that the app can finish initializing
+ // and log any job errors or other types of errors.
+
+ if ( gfTerminateApp ) {
+ fDelayTermination = TRUE;
+ gfTerminateApp = FALSE;
+ }
+
+ // Destroy the LOGO window.
+
+# if !defined ( OEM_MSOFT )
+ {
+ WM_LogoDestroy ();
+ }
+# endif //!defined ( OEM_MSOFT )
+
+ // Allow the GUI to be repainted.
+
+ WM_MultiTask ();
+
+# if !defined ( OEM_MSOFT )
+
+ // Enter the PWDB password if necessary
+
+ if ( ( gpszJobName ) ||
+ ( nJobIndex == MUI_NO_STARTUP_JOBS ) ) {
+
+ STM_SetIdleText ( IDS_INITUI );
+ MUI_CheckPWDB( pCDS );
+
+ }
+# endif //!defined ( OEM_MSOFT )
+
+ // Initialize the catalogs.
+
+ STM_SetIdleText ( IDS_INITCATALOGS );
+
+ // True is that we wish to read unicode cats
+
+ QTC_Init ( CDS_GetCatDataPath(), NULL );
+
+ // Initialize the BACKUP ENGINE and the PRIMARY DOCUMENT windows.
+
+ STM_SetIdleText ( IDS_INITUI );
+ fReadStartup = ( ( gpszJobName == NULL ) &&
+ ( nJobIndex == MUI_NO_STARTUP_JOBS ) );
+
+ VLM_Init ( fReadStartup );
+ WM_MultiTask ();
+
+ // Create the LOG FILES window.
+
+ LOG_Init ();
+ WM_MultiTask ();
+
+ // Display the standard mode warning if we are in standard mode.
+
+ if ( ! gfEnhanced && CDS_GetStdModeWarning ( pCDS ) ) {
+
+ CHAR szMessage[MAX_UI_RESOURCE_SIZE];
+ CHAR szTemp[MAX_UI_SMALLRES_SIZE];
+
+ RSM_StringCopy ( IDS_APPNAME, szTemp, sizeof ( szTemp ) );
+ RSM_Sprintf ( szMessage, ID(IDS_STDMODEWARNING), szTemp );
+
+ WM_ShowWaitCursor ( FALSE );
+
+ nResult = WM_MsgBox ( ID(IDS_APPNAME),
+ szMessage,
+ WMMB_OKDISABLE,
+ WMMB_ICONEXCLAMATION );
+
+ if ( nResult == WMMB_IDDISABLE ) {
+
+ CDS_SetStdModeWarning ( pCDS, FALSE );
+ CDS_WriteStdModeWarning ( pCDS );
+ }
+
+
+ WM_ShowWaitCursor ( TRUE );
+
+ }
+
+ // Initialize the application timer.
+
+ WM_InitTimer ();
+
+# if !defined ( OEM_MSOFT )
+
+ // Initialize the Jobs Queue and Create any non-existant permanent jobs.
+
+ JOB_Refresh ();
+ UI_MakeAutoJobs ( (INT)NULL );
+
+# endif //!defined ( OEM_MSOFT )
+
+
+ // Initialize Poll Drive and Start Polling the Drive.
+
+ PD_Init ();
+ PD_StartPolling ();
+ PD_SetFrequency ( CDS_GetPollFrequency ( pCDS ) );
+
+ mwfInitialized = TRUE;
+
+ zprintf ( DEBUG_USER_INTERFACE, RES_APPLICATION_INIT );
+
+ // Guarantee the tool bar, doc, and the rest of the screen is correct.
+
+// MUI_EnableOperations ( (WORD)NULL );
+
+ // WM_ShowWaitCursor ( FALSE );
+
+# if defined ( OS_WIN32 ) //alternate feature - cmd line batch job
+ {
+ // we must process the command line now (as opposed to during
+ // MUI_ProcessCommandLine) because dle_list and bsd_list
+ // must be initialized.
+
+ if ( glpCmdLine ) //global command line pointer
+ {
+ LPSTR pszNext = NULL; // Next command line item pointer
+ LPSTR pszCmdLine;
+ CHAR szBackup[ IDS_OEM_MAX_LEN ];
+ CHAR szEject[ IDS_OEM_MAX_LEN ];
+ CHAR szTokens[ IDS_OEM_MAX_LEN ];
+ CHAR szDSA[ IDS_OEM_MAX_LEN ];
+ CHAR szMonolithic[ IDS_OEM_MAX_LEN ];
+ OEMOPTS_PTR pOemOpts = NULL;
+ BSD_PTR bsd ;
+ LPSTR pszQuotedString;
+ BOOLEAN QuoteState = FALSE;
+ UINT8 uEmsFSType = (UINT8)FS_UNKNOWN_OS;
+ BOOLEAN oem_batch_eject_mode = FALSE ;
+
+ pszCmdLine = malloc( ( strlen( glpCmdLine ) + 1 ) * sizeof(CHAR) );
+
+ if ( pszCmdLine == NULL ) { //uh-oh - memory allocation problem!!
+
+ return FAILURE;
+ }
+
+ pszQuotedString = malloc( ( strlen( glpCmdLine ) + 1 ) * sizeof(CHAR) );
+
+ if ( pszQuotedString == NULL ) { //uh-oh - memory allocation problem!!
+
+ free( pszCmdLine );
+ return FAILURE;
+ }
+
+ strcpy( pszCmdLine, glpCmdLine );
+
+ RSM_StringCopy ( IDS_OEMBATCH_BACKUP,
+ szBackup, sizeof ( szBackup ) );
+
+ RSM_StringCopy ( IDS_OEMBATCH_EJECT,
+ szEject, sizeof ( szEject ) );
+
+ RSM_StringCopy ( IDS_OEMOPT_TOKENSEPS,
+ szTokens, sizeof ( szTokens ) );
+
+ pszNext = strtok ( pszCmdLine, szTokens ); //skip leading spaces
+
+ if ( pszNext &&
+ ( pOemOpts = OEM_DefaultBatchOptions () ) &&
+ ( (strnicmp ( pszNext, szBackup, strlen( pszNext ) ) == 0 ) ||
+ ( strnicmp ( pszNext, szEject, strlen( pszNext ) ) == 0 ) ) )
+ {
+ oem_batch_eject_mode = FALSE ;
+
+ if ( strnicmp ( pszNext, szEject, strlen( pszNext ) ) == 0 ) {
+ oem_batch_eject_mode = TRUE ;
+ }
+
+ // Make sure we're starting with a clear BSD list
+
+ bsd = BSD_GetFirst( bsd_list );
+
+ while ( bsd != NULL ) {
+ BSD_Remove( bsd );
+ bsd = BSD_GetFirst( bsd_list );
+ }
+
+ // Process the command line: all following items in the command
+ // line must be one or more path specifiers with optional batch
+ // options mixed in.
+
+
+ if ( strlen( LOG_GetCurrentLogName( ) ) > 0 ) { // chs:07-16-93
+ lresprintf( LOGGING_FILE, LOG_START, FALSE ); // chs:07-16-93
+ } // chs:07-16-93
+
+ RSM_StringCopy ( IDS_OEMOPT_DSA,
+ szDSA, sizeof ( szDSA ) );
+ RSM_StringCopy ( IDS_OEMOPT_MONOLITHIC,
+ szMonolithic, sizeof ( szMonolithic ) );
+
+ while ( pszNext = strtok ( NULL, szTokens ) ) {
+
+ if ( OEM_ProcessBatchCmdOption (
+ pOemOpts,
+ pszNext,
+ szTokens,
+ pszCmdLine ) == IDS_OEMOPT_NOTANOPTION )
+ {
+
+ //
+ // Previous logic did not account for a directory name haveing spaces
+ // example ... "G:\SUB DIR WITH SPACE". This was the easiest way
+ // to fix this problem without changing the central logic of
+ // the codes.
+ //
+
+ if ( *pszNext == TEXT( '"' ) || QuoteState ) {
+
+ if ( !QuoteState ) strcpy( pszQuotedString, TEXT( "" ) );
+ QuoteState = TRUE;
+ if ( *pszNext == TEXT( '"' ) ) {
+ MUI_ProcessQuotedString ( pszQuotedString, ( pszNext + 1 ), &QuoteState );
+ } else {
+ MUI_ProcessQuotedString ( pszQuotedString, pszNext, &QuoteState );
+ }
+ if ( !QuoteState ) {
+
+ //It's either a path or Exchange server name, based on the
+ //setting of uEmsFSType.
+ if ( ((UINT8)FS_UNKNOWN_OS) == uEmsFSType ) {
+ OEM_AddPathToBackupSets ( bsd_list, dle_list, pszNext );
+
+ } else {
+ // Add EMS Server path to Backup sets and reset EMS flag.
+#ifdef OEM_EMS
+ OEM_AddEMSServerToBackupSets ( bsd_list, dle_list,
+ pszNext, uEmsFSType );
+ uEmsFSType = (UINT8)FS_UNKNOWN_OS;
+#endif
+ }
+ } else {
+
+ strcat( pszQuotedString, TEXT( " " ) );
+ }
+ } else {
+
+ //It's not an option, so it must be a path specifier, an
+ //Exchange backup specifier, or an Exchange server specifier.
+
+ //Check first for Exchange DSA backup
+ if ( strnicmp ( pszNext, szDSA, strlen( pszNext ) ) == 0 ) {
+ uEmsFSType = FS_EMS_DSA_ID;
+
+ //Check next for Exchange Monolithic backup
+ } else if ( strnicmp ( pszNext, szMonolithic, strlen( pszNext ) ) == 0 ) {
+ uEmsFSType = FS_EMS_MDB_ID;
+
+ } else {
+
+ //It's either a path or Exchange server name, based on the
+ //setting of uEmsFSType.
+
+ if ( ((UINT8)FS_UNKNOWN_OS) == uEmsFSType ) {
+ OEM_AddPathToBackupSets ( bsd_list, dle_list, pszNext );
+
+ } else {
+#ifdef OEM_EMS
+ // Add EMS Server path to Backup sets and reset EMS flag
+ OEM_AddEMSServerToBackupSets ( bsd_list, dle_list,
+ pszNext, uEmsFSType );
+ uEmsFSType = (UINT8)FS_UNKNOWN_OS;
+#endif
+ }
+ }
+ }
+
+ }
+ }
+
+ if ( strlen( LOG_GetCurrentLogName( ) ) > 0 ) { // chs:07-16-93
+ lresprintf( LOGGING_FILE, LOG_END, FALSE ); // chs:07-16-93
+ }
+
+ //Update the BSD(s) with the batch option selections...
+
+ OEM_UpdateBatchBSDOptions ( bsd_list, pOemOpts );
+ OEM_DeleteBatchOptions ( &pOemOpts ); //don't need it anymore
+
+ // Now, go do the batch backup operation...
+ CDS_SetYesFlag ( CDS_GetPerm (), YESYES_FLAG );
+
+ MUI_EnableOperations ( (WORD)NULL );
+
+ WM_ShowWaitCursor ( FALSE );
+
+ if ( oem_batch_eject_mode ) {
+ MUI_StartOperation ( IDM_OPERATIONSEJECT, TRUE );
+ } else {
+ MUI_StartOperation ( IDM_OPERATIONSBACKUP, TRUE );
+ }
+
+ free ( pszCmdLine ); //don't need this anymore
+
+ return FAILURE; // we are done! exit the app.
+ }
+ else
+ {
+ free ( pszCmdLine ); //don't need this anymore
+ }
+ }
+ }
+#endif //if defined ( OS_WIN32 ) for command line batch jobs
+ MUI_EnableOperations ( (WORD)NULL );
+ WM_ShowWaitCursor ( FALSE );
+
+#if !defined ( OEM_MSOFT ) //OEM_MSOFT can't do jobs or schedules
+ {
+
+ // Kick off a job if one was found to be on the command line.
+ // If the job was on the command line, we exit the app when
+ // the job is done.
+
+ if ( gpszJobName ) {
+
+ JOB_StartJob ( gpszJobName, JOB_NOTSCHEDULED );
+ return FAILURE;
+
+ }
+ else if ( nJobIndex != MUI_NO_STARTUP_JOBS ) {
+
+ // If the password database is configured for use, set the db
+ // state flag to VERIFIED so that unattended jobs can run without
+ // a pw for the pwdb being entered.
+
+ if ( CDS_GetEnablePasswordDbase( pCDS ) ) {
+ gfPWForPWDBState = DBPW_VERIFIED;
+ }
+
+ SCH_StartJob ( (INT16)nJobIndex, (LONG) lSchedKey );
+ return FAILURE;
+ }
+
+ }
+# endif //defined ( OEM_MSOFT ) //alternate/Standard features
+
+ if ( fDelayTermination ) {
+ return FAILURE;
+ }
+
+ // Check for bad data paths and display warning(s) if found.
+
+ CDS_CheckForBadPaths ();
+
+ return SUCCESS;
+
+} /* end MUI_Init() */
+
+
+/******************************************************************************
+
+ Name: MUI_Deinit()
+
+ Description: This function deinitializes the Maynard User Interface (MUI).
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID MUI_Deinit ( VOID )
+
+{
+ // This may be called twice, so check to see if it has already been
+ // deinitialized. Once, by a normal close, another, by a TASK killer.
+ // We have to check for both. The reason it is done this way is so
+ // that we keep showing our application until the app is completely
+ // deinitialized. This is a courtesy to our users.
+
+ if ( mwfInitialized ) {
+
+ mwfInitialized = FALSE;
+
+ WM_ShowWaitCursor ( TRUE );
+
+ // Deinitialize the application timer.
+
+ WM_DeinitTimer ();
+
+ // Turn off and deinitialize the tape drive polling.
+
+ PD_StopPolling ();
+ PD_Deinit ();
+
+ if ( CDS_GetEjectTapeFlag ( CDS_GetPerm () ) ) {
+ PD_EjectTape ();
+ }
+
+ // Deinitialize the Log stuff.
+
+ LOG_Deinit ();
+
+ // Deinitialize the Jobs Queue.
+# if !defined ( OEM_MSOFT )
+
+ JOB_DeInitQueue ();
+
+# endif //!defined ( OEM_MSOFT )
+ // Deinitialize the VLM.
+
+ VLM_Deinit ();
+
+ // Clean up the catalogs.
+
+ QTC_Deinit ( (INT) gfDeleteCatalogs );
+
+ // Deinitialize the backup engine and hardware.
+
+ UI_UnitsDeInit ();
+
+ // Deinitialize the debug stuff.
+
+ DBM_Deinit( );
+
+ // Deinitialize and Save the CDS.
+
+ CDS_SaveDisplayConfig ();
+ CDS_Deinit ();
+
+ // Kill WinHelp if we brought it up and it is still around
+
+ WinHelp( ghWndFrame,
+ NULL,
+ HELP_QUIT,
+ 0L );
+
+ // Turn of the show memory flag.
+
+#ifdef OS_WIN32
+
+ if ( gfShowMemory ) {
+ MEM_StopShowMemory();
+ }
+#endif
+
+ gfShowMemory = FALSE;
+
+ WM_ShowWaitCursor ( FALSE );
+ }
+
+} /* end MUI_Deinit() */
+
+
+/******************************************************************************
+
+ Name: MUI_StartOperation()
+
+ Description: This function prepares the GUI for an operation, then
+ kicks off the operation.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+BOOL MUI_StartOperation (
+
+WORD wType, // I - type of operation to start
+BOOL fUpdateTempCDS ) // I - flag to update the temp CDS (copy of CDS)
+
+{
+ BOOL fError = SUCCESS;
+
+
+ // Bug out, if we cannot disable other operations. This will only occur
+ // if there is an operation currently being done.
+
+ if ( MUI_DisableOperations ( wType ) ) {
+ return FAILURE;
+ }
+
+ // SINCE THIS IS A RECURSIVE ROUTINE
+ // Check to see if an operation is currently in progress.
+ // If so, bug out. Otherwise, switch to the appropriate operation.
+
+ if ( fUpdateTempCDS ) {
+
+ // Refresh the temp or copy of the CDS with the perm CDS before the
+ // operation. The copy can be modified, but the modifications will
+ // not be reflected in the permanent CDS.
+
+ CDS_UpdateCopy ();
+ }
+
+ switch ( wType ) {
+
+ case IDM_OPERATIONSBACKUP:
+
+ STM_SetIdleText ( IDS_BACKINGUP );
+ WM_AnimateAppIcon ( wType, TRUE );
+
+ if ( ! VLM_StartBackup () ) {
+ VLM_ClearAllSelections ();
+
+# if !defined ( OEM_MSOFT )
+ UI_MakeAutoJobs ( JOBBACKUP );
+# endif //!defined ( OEM_MSOFT )
+ }
+
+ else {
+ VLM_RematchAllLists( );
+ fError = FAILURE;
+ }
+ break;
+
+# ifdef OEM_EMS
+ case IDM_OPERATIONSEXCHANGE:
+
+ DM_ShowDialog ( ghWndFrame, IDD_CONNECT_XCHNG, (PVOID) NULL );
+
+ break;
+# endif
+
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+
+ case IDM_OPERATIONSTRANSFER:
+
+ STM_SetIdleText ( IDS_TRANSFERRING );
+ WM_AnimateAppIcon ( wType, TRUE );
+
+ if ( ! VLM_StartTransfer () ) {
+ UI_MakeAutoJobs ( JOBTRANSFER );
+ VLM_ClearAllSelections ();
+ }
+ else {
+ VLM_RematchAllLists( );
+ fError = FAILURE;
+ }
+
+ break;
+
+# endif // !defined ( OEM_MSOFT ) // unsupported feature
+
+ case IDM_OPERATIONSRESTORE:
+
+ STM_SetIdleText ( IDS_RESTORING );
+ WM_AnimateAppIcon ( wType, TRUE );
+
+ if ( ! VLM_StartRestore () ) {
+ VLM_ClearAllSelections ();
+# if !defined ( OEM_MSOFT )
+ UI_MakeAutoJobs ( JOBRESTORE );
+# endif //!defined ( OEM_MSOFT )
+ }
+ else {
+ VLM_RematchAllLists( );
+ fError = FAILURE;
+ }
+
+ break;
+
+ case IDM_OPERATIONSCATALOG:
+
+ gbCurrentOperation = OPERATION_CATALOG; // chs:03-21-93
+ STM_SetIdleText ( IDS_CATALOGING );
+ WM_AnimateAppIcon ( wType, TRUE );
+ VLM_StartCatalog ();
+
+ break;
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+
+ case IDM_OPERATIONSVERIFY:
+
+ STM_SetIdleText ( IDS_VERIFYING );
+ WM_AnimateAppIcon ( wType, TRUE );
+
+ if ( ! VLM_StartVerify () ) {
+ UI_MakeAutoJobs ( JOBBACKUP );
+ VLM_ClearAllSelections ();
+ }
+ else {
+ VLM_RematchAllLists( );
+ fError = FAILURE;
+ }
+
+ break;
+
+ case IDM_OPERATIONSINFO:
+
+ STM_SetIdleText ( IDS_INFOING );
+ VLM_DisplayInfo ();
+
+ break;
+
+ case IDM_OPERATIONSCATMAINT:
+
+ STM_SetIdleText ( IDS_CATMAINT );
+ DM_ShowDialog ( ghWndFrame, IDD_OPERATIONSCATMAINT, (PVOID) NULL );
+
+ break;
+
+ case IDM_OPERATIONSSEARCH:
+
+ VLM_StartSearch ( NULL );
+
+ break;
+
+ case IDM_OPERATIONSCONNECT:
+
+ VLM_NetConnect ( );
+
+ break;
+
+ case IDM_OPERATIONSDISCON:
+
+ VLM_NetDisconnect ( );
+
+ break;
+
+# endif // !defined ( OEM_MSOFT ) // unsupported feature
+
+ case IDM_OPERATIONSEJECT:
+
+ WM_ShowWaitCursor(TRUE);
+ STM_SetIdleText ( IDS_EJECTING );
+ PD_EjectTape ();
+ WM_ShowWaitCursor(FALSE);
+
+ break;
+
+ case IDM_OPERATIONSERASE:
+
+ STM_SetIdleText ( IDS_ERASING );
+ VLM_StartErase ();
+
+ break;
+
+ case IDM_OPERATIONSRETENSION:
+
+ STM_SetIdleText ( IDS_RETENSIONING );
+ VLM_StartTension ();
+
+ break;
+
+
+#ifdef OS_WIN32
+ case IDM_OPERATIONSFORMAT:
+
+ STM_SetIdleText ( IDS_FORMATING );
+ VLM_StartFormat ();
+
+ break;
+#endif
+
+ } /* end switch */
+
+ MUI_EnableOperations ( wType );
+
+ gnReturnCode = (INT)fError;
+
+ return fError;
+
+} /* end MUI_StartOperation() */
+
+
+BOOL MUI_DisableOperations (
+
+WORD wType ) // type of operation that is disabling the display
+
+{
+ // If there is a currently active operation, don't let another occur.
+
+ if ( gfOperation ) {
+ return FAILURE;
+ }
+
+ gfOperation = TRUE;
+
+ // Disable all operation buttons, but the operation that is to occur.
+ // Push any tool bar item button down to reflect the operation.
+
+ MUI_SetOperationButtons ( RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL );
+ MUI_SetActionButtons ( RIB_ITEM_UP | RIB_ITEM_DISABLED );
+ MUI_SetButtonState ( wType, RIB_ITEM_DOWN | RIB_ITEM_ENABLED | RIB_ITEM_POSITIONAL );
+ WM_SetDocSizes ();
+ WM_MultiTask ();
+
+ return SUCCESS;
+
+} /* end MUI_DisableOperations() */
+
+
+BOOL MUI_EnableOperations (
+
+WORD wType ) // type of operation that is enabling the display
+
+{
+ HWND hWndFocus = GetFocus( );
+
+ DBG_UNREFERENCED_PARAMETER ( wType );
+
+ // Set the focus to the Runtime Status dialog if it is not already
+ // set to it. Then, bug out, because the dialog will call us when
+ // the user finishes the dialog.
+
+ if ( ghModelessDialog ) {
+
+ if (( ! hWndFocus || IsChild ( ghWndFrame, hWndFocus ) ) &&
+ !IsIconic(ghWndFrame))
+ {
+ SetFocus ( ghModelessDialog );
+ }
+
+ return FAILURE;
+ }
+
+ // Release any tool bar item button up that was down.
+
+ MUI_SetOperationButtons ( RIB_ITEM_UP | RIB_ITEM_ENABLED | RIB_ITEM_POSITIONAL );
+ MUI_SetActionButtons ( RIB_ITEM_UP | RIB_ITEM_ENABLED );
+
+ gfOperation = FALSE;
+
+ // Now, force a screen update based on the last active doc type.
+
+ mwwLastDocType = ID_NOTDEFINED;
+
+ //
+ // This maybe a Kludge but it appears to work. When you double click on the
+ // system menu to close the app. in the middle of a backup it comes through
+ // this routine twice. The second time WM_GetInfoPtr ( WM_GetActiveDoc () )
+ // is NULL. Thus we place a check here. I placed the PostQuitMessage here
+ // because without it the app does not terminate properly and seem to be
+ // hung in the WinMain ... while ( GetMessage ... waiting for a message
+ // which it never gets, thus the app. hangs.
+ //
+
+ if ( !WM_GetInfoPtr ( WM_GetActiveDoc () ) ) { // chs:03-23-93
+ PostQuitMessage( 0 ); // chs:03-23-93
+ } else { // chs:03-23-93
+ MUI_ActivateDocument ( WMDS_GetWinType ( WM_GetInfoPtr ( WM_GetActiveDoc () ) ) ); // chs:03-23-93
+ } // chs:03-23-93
+
+ WM_SetAppIcon ( RSM_IconLoad ( IDRI_WNTRPARK ) );
+ WM_RestoreDocs ();
+
+ STM_SetIdleText ( IDS_READY );
+
+ // Check to see if we are to terminate the application. This will happen
+ // if a user or task killer told our app to terminate during an operation.
+
+ if ( gfTerminateApp && ! MUI_AnyQueuedOperations () ) {
+
+ MUI_Deinit ();
+ WM_TerminateApp ();
+ }
+ else {
+
+ // Check to see if any operations were queued up since the
+ // last operation.
+
+ if ( MUI_AnyQueuedOperations () ) {
+ MUI_ReleaseQueuedOperation ();
+ }
+ }
+
+ return SUCCESS;
+
+} /* end MUI_EnableOperations() */
+
+
+/******************************************************************************
+
+ Name: MUI_QueueOperation ()
+
+ Description:
+
+ Returns: TRUE, if successful. Otherwise, FALSE.
+
+******************************************************************************/
+
+BOOL MUI_QueueOperation (
+
+UINT nType ) // I - type of window being activated
+
+{
+ if ( mwnNumOperationsInQueue >= MAX_QUEUED_OPERATIONS ) {
+ return FALSE;
+ }
+
+ mwnQueuedOperationMsg = nType;
+ mwnNumOperationsInQueue++;
+
+ return TRUE;
+
+} /* MUI_QueueOperation () */
+
+
+/******************************************************************************
+
+ Name: MUI_ReleaseQueuedOperation ()
+
+ Description:
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID MUI_ReleaseQueuedOperation ( VOID )
+
+{
+ if ( mwnNumOperationsInQueue > 0 && mwnQueuedOperationMsg > 0 ) {
+
+ POST_WM_COMMAND_MSG ( ghWndFrame, (MSGID)mwnQueuedOperationMsg, 0, 0 );
+
+ mwnQueuedOperationMsg = 0;
+ mwnNumOperationsInQueue--;
+ }
+
+
+} /* MUI_ReleaseQueuedOperation () */
+
+
+/******************************************************************************
+
+ Name: MUI_AnyQueuedOperations ()
+
+ Description:
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+BOOL MUI_AnyQueuedOperations ( VOID )
+
+{
+ return (BOOL)mwnNumOperationsInQueue;
+
+} /* MUI_AnyQueuedOperations () */
+
+
+/******************************************************************************
+
+ Name: MUI_ActivateDocument ()
+
+ Description: This function prepares the tool bar, menu and whatever else
+ needs preparation when a new document window becomes active.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID MUI_ActivateDocument (
+
+WORD wType ) // I - type of window being activated
+
+{
+ WORD wTempType = wType;
+
+ if ( gfOperation ) {
+ return;
+ }
+
+ if ( wType == WMTYPE_DISKTREE || wType == WMTYPE_TAPETREE ) {
+ MUI_SetInfoAvailable ( TRUE );
+ }
+ else {
+ MUI_SetInfoAvailable ( FALSE );
+ }
+
+ // Break out the types later, if needed.
+
+ switch ( wType ) {
+
+ case WMTYPE_DISKS:
+ case WMTYPE_DISKTREE:
+ case WMTYPE_SERVERS:
+#ifdef OEM_EMS
+ case WMTYPE_EXCHANGE :
+#endif
+
+ wType = WMTYPE_DISKS;
+
+ // If this is the same type of window, bug out.
+
+ if ( mwwLastDocType == wType ) {
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+ {
+ // Enable/disable the information button.
+
+ if ( MUI_IsInfoAvailable () ) {
+ MUI_SetButtonState ( IDM_OPERATIONSINFO, RIB_ITEM_UP | RIB_ITEM_ENABLED | RIB_ITEM_POSITIONAL );
+ }
+ else {
+ MUI_SetButtonState ( IDM_OPERATIONSINFO, RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL );
+ }
+
+ }
+# endif // !defined ( OEM_MSOFT ) //unsupported feature
+
+ break;
+ }
+
+ // Enable all operation and action tool bar items.
+
+ MUI_SetOperationButtons ( RIB_ITEM_UP | RIB_ITEM_ENABLED | RIB_ITEM_POSITIONAL );
+ MUI_SetActionButtons ( RIB_ITEM_UP | RIB_ITEM_ENABLED );
+
+ // Enable/Disable appropriate tool bar items.
+
+ MUI_SetButtonState ( IDM_OPERATIONSBACKUP, RIB_ITEM_UP | RIB_ITEM_ENABLED | RIB_ITEM_POSITIONAL );
+ MUI_SetButtonState ( IDM_OPERATIONSRESTORE, RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL );
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+ {
+ MUI_SetButtonState ( IDM_OPERATIONSTRANSFER, RIB_ITEM_UP | RIB_ITEM_ENABLED | RIB_ITEM_POSITIONAL );
+ }
+# endif // !defined ( OEM_MSOFT ) //unsupported feature
+
+ break;
+
+ case WMTYPE_TAPES:
+ case WMTYPE_TAPETREE:
+ case WMTYPE_SEARCH:
+
+ wType = WMTYPE_TAPES;
+
+ // If this is the same type of window, bug out.
+
+ if ( mwwLastDocType == wType ) {
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+ {
+ // Enable/disable the information button.
+
+ if ( MUI_IsInfoAvailable () ) {
+ MUI_SetButtonState ( IDM_OPERATIONSINFO, RIB_ITEM_UP | RIB_ITEM_ENABLED | RIB_ITEM_POSITIONAL );
+ }
+ else {
+ MUI_SetButtonState ( IDM_OPERATIONSINFO, RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL );
+ }
+
+ // Disable the Advanced button if this is a search window.
+
+ if ( wTempType == WMTYPE_SEARCH ) {
+ MUI_SetButtonState ( IDM_SELECTADVANCED, RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL );
+ }
+ else {
+ MUI_SetButtonState ( IDM_SELECTADVANCED, RIB_ITEM_UP | RIB_ITEM_ENABLED | RIB_ITEM_POSITIONAL );
+ }
+ }
+# endif // !defined ( OEM_MSOFT ) //unsupported feature
+
+ break;
+ }
+
+ // Enable all operation and action tool bar items.
+
+ MUI_SetOperationButtons ( RIB_ITEM_UP | RIB_ITEM_ENABLED | RIB_ITEM_POSITIONAL );
+ MUI_SetActionButtons ( RIB_ITEM_UP | RIB_ITEM_ENABLED );
+
+ // Enable/Disable appropriate tool bar items.
+
+ MUI_SetButtonState ( IDM_OPERATIONSBACKUP, RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL );
+ MUI_SetButtonState ( IDM_OPERATIONSRESTORE, RIB_ITEM_UP | RIB_ITEM_ENABLED | RIB_ITEM_POSITIONAL );
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+ {
+ MUI_SetButtonState ( IDM_OPERATIONSTRANSFER, RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL );
+
+ // Disable the Advanced button if this is a search window.
+
+ if ( wTempType == WMTYPE_SEARCH ) {
+ MUI_SetButtonState ( IDM_SELECTADVANCED, RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL );
+ }
+ }
+# endif // !defined ( OEM_MSOFT ) //unsupported feature
+
+ break;
+
+ case WMTYPE_DEBUG:
+ case WMTYPE_LOGFILES:
+ default:
+
+ wType = WMTYPE_DEBUG;
+
+ // If this is the same type of window, bug out.
+
+ if ( mwwLastDocType == wType ) {
+ break;
+ }
+
+ // Disable all action tool bar items.
+
+ MUI_SetOperationButtons ( RIB_ITEM_UP | RIB_ITEM_ENABLED | RIB_ITEM_POSITIONAL );
+ MUI_SetActionButtons ( RIB_ITEM_UP | RIB_ITEM_DISABLED );
+
+ // Enable/Disable appropriate tool bar items.
+
+ MUI_SetButtonState ( IDM_OPERATIONSBACKUP, RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL );
+ MUI_SetButtonState ( IDM_OPERATIONSRESTORE, RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL );
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+ {
+ // Enable/disable the information button.
+
+ if ( MUI_IsInfoAvailable () ) {
+ MUI_SetButtonState ( IDM_OPERATIONSINFO, RIB_ITEM_UP | RIB_ITEM_ENABLED | RIB_ITEM_POSITIONAL );
+ }
+ else {
+ MUI_SetButtonState ( IDM_OPERATIONSINFO, RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL );
+ }
+
+ MUI_SetButtonState ( IDM_SELECTADVANCED, RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL );
+
+ }
+# endif // !defined ( OEM_MSOFT ) //unsupported feature
+
+ break;
+
+ } /* end switch */
+
+ mwwLastDocType = wType;
+
+ STM_SetIdleText ( IDS_READY );
+
+} /* end MUI_ActivateDocument() */
+
+
+VOID MUI_TapeInDrive (
+
+BOOL fInDrive ) // I - flag indicating whether a tape is in the drive
+
+{
+ BOOL fTapeCurrentlyValid;
+ WORD wState;
+
+ // See if the tape in the drive is valid.
+
+ if ( VLM_GetDriveStatus ( NULL ) == VLM_VALID_TAPE ) {
+ fTapeCurrentlyValid = TRUE;
+ }
+ else {
+ fTapeCurrentlyValid = FALSE;
+ }
+
+ if ( ! gfOperation ) {
+
+ // Set all of the ribbon item states that are dependent upon a tape
+ // being in the drive, if the operation flag is not set.
+
+ if ( fInDrive != mwfTapeInDrive ) {
+
+ WORD wTempState;
+
+ if ( fInDrive ) {
+ wState = RIB_ITEM_UP | RIB_ITEM_ENABLED | RIB_ITEM_POSITIONAL;
+ }
+ else {
+ wState = RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL;
+ }
+
+ MUI_SetButtonState ( IDM_OPERATIONSEJECT, wState );
+ MUI_SetButtonState ( IDM_OPERATIONSERASE, wState );
+
+ // Set catalog a tape button status
+
+ wTempState = (WORD)(( fTapeCurrentlyValid ) ? wState : RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL);
+ MUI_SetButtonState ( IDM_OPERATIONSCATALOG, wTempState );
+
+ wTempState = (WORD)(( thw_list ) ? (BOOL)( thw_list->drv_info.drv_features & TDI_RETENSION ) : FALSE );
+ wTempState = (WORD)(( wTempState ) ? wState : RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL);
+ MUI_SetButtonState ( IDM_OPERATIONSRETENSION, wTempState );
+
+ }
+ else if ( mwfTapeValid != fTapeCurrentlyValid ) {
+
+ // WHY DO WE HAVE TO DO THIS, MIKEP?
+
+ if ( fTapeCurrentlyValid ) {
+ wState = RIB_ITEM_UP | RIB_ITEM_ENABLED | RIB_ITEM_POSITIONAL;
+ }
+ else {
+ wState = RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL;
+ }
+
+ MUI_SetButtonState ( IDM_OPERATIONSCATALOG, wState );
+ }
+
+ }
+
+ mwfTapeInDrive = fInDrive;
+ mwfTapeValid = fTapeCurrentlyValid;
+
+} /* end MUI_TapeInDrive() */
+
+
+BOOL MUI_IsTapeInDrive ( VOID )
+
+{
+ return ( ( gfPollDrive ) ? mwfTapeInDrive : gfHWInitialized );
+
+} /* end MUI_IsTapeInDrive() */
+
+
+BOOL MUI_IsEjectSupported ( VOID )
+
+{
+ return ( (thw_list && gfHWInitialized) ? (BOOL)( thw_list->drv_info.drv_features & TDI_UNLOAD ) : FALSE );
+
+} /* end MUI_IsEjectSupported() */
+
+
+VOID MUI_SetInfoAvailable (
+
+BOOL fAvailable )
+
+{
+
+ if ( fAvailable && QTC_AnySearchableBsets () ) {
+// if ( fAvailable && QTC_AnySearchableBsets () && VLM_IsInfoAvailable () ) {
+ mwfInfoAvailable = TRUE;
+ }
+ else {
+ mwfInfoAvailable = FALSE;
+ }
+
+} /* end MUI_SetInfoAvailable() */
+
+
+BOOL MUI_IsInfoAvailable ( VOID )
+
+{
+ return mwfInfoAvailable;
+
+} /* end MUI_IsInfoAvailable() */
+
+
+BOOL MUI_IsRetensionSupported ( VOID )
+
+{
+ return ( ( MUI_IsTapeInDrive () && thw_list ) ? (BOOL)( thw_list->drv_info.drv_features & TDI_RETENSION ) : FALSE );
+
+} /* end MUI_IsRetensionSupported() */
+
+
+BOOL MUI_IsTapeValid ( VOID )
+
+{
+ return (BOOL)( MUI_IsTapeInDrive () && mwfTapeValid );
+
+} /* end MUI_IsTapeValid() */
+
+
+/*****************************************************************************
+
+ Name: MUI_ProcessCommandLine ()
+
+ Description: This function processes the MUI part of the command line.
+
+ Returns: SUCCESS, if successful. Otherwise FAILURE, if there was
+ a problem.
+
+*****************************************************************************/
+
+BOOL MUI_ProcessCommandLine (
+
+LPSTR lpszCmdLine, // I - pointer to the command line string
+INT *pnCmdShow ) // I - pointer to the command show style integer
+
+{
+# if !defined ( OEM_MSOFT ) // unsupported feature
+ {
+
+ LPSTR pSubString;
+ LPSTR pIndex;
+ CHAR szTemp[10];
+
+ // Look for Jobs or Launched Jobs Now, but not both.
+
+ RSM_StringCopy ( IDS_JOBCOMMANDLINE, szTemp, sizeof ( szTemp ) );
+
+ pSubString = strstr ( lpszCmdLine, szTemp );
+
+ if ( pSubString ) {
+
+ CHAR chTerminator;
+
+ // Don't even allow poll drive to start.
+
+ // gfPollDrive = FALSE;
+
+ // Set the YYFLAG since this was started from the command line.
+
+ CDS_SetYesFlag ( CDS_GetPerm (), YESYES_FLAG );
+
+ pSubString += strlen ( szTemp );
+ pIndex = gpszJobName = (CHAR_PTR)calloc ( MAX_JOBNAME_LEN, sizeof ( CHAR ) );
+
+ // Extract the job name from the command line. Search for the
+ // job name terminator or the end of the command line string '\0'.
+ // The terminator is the same as the last character in the
+ // temporary string. In English it is the double-quote (").
+
+ chTerminator = *(pSubString - 1);
+
+ while ( ( *pSubString != chTerminator ) && ( *pSubString != TEXT('\0') ) ) {
+
+ *pIndex++ = *pSubString++;
+ }
+
+ pIndex = TEXT('\0');
+
+ // Get the show status of the job.
+
+ if ( JOB_IsIconic ( gpszJobName ) ) {
+ *pnCmdShow = SW_SHOWMINIMIZED;
+ }
+
+ }
+ else {
+
+ RSM_StringCopy ( IDS_SCHCOMMANDLINE, szTemp, sizeof ( szTemp ) );
+
+ pSubString = strstr ( lpszCmdLine, szTemp );
+
+ if ( pSubString ) {
+
+ // Don't even allow poll drive to start.
+
+ // gfPollDrive = FALSE;
+
+ // Set the YYFLAG since this was started from the command line.
+
+ CDS_SetYesFlag ( CDS_GetPerm (), YESYES_FLAG );
+
+ pSubString += strlen ( szTemp );
+
+ // Extract the job name index from the command line.
+
+ sscanf ( pSubString, TEXT("%d"), &nJobIndex );
+
+ // Get the show status of the job.
+
+ if ( SCH_IsJobIconic ( nJobIndex ) ) {
+ *pnCmdShow = SW_SHOWMINIMIZED;
+ }
+ }
+
+ // Pick up the unique key if specified. Only the launcher
+ // creates this entry.
+
+ RSM_StringCopy ( IDS_SCHUNIQUEKEY, szTemp, sizeof ( szTemp ) );
+
+ pSubString = strstr ( lpszCmdLine, szTemp );
+
+ if ( pSubString ) {
+
+ pSubString += strlen ( szTemp );
+
+ // Extract the unique key from the command line.
+
+ sscanf ( pSubString, TEXT("%ld"), &lSchedKey );
+
+
+ // THIS MAY NOT BE COMPLETE ?????
+ }
+ }
+
+ // Update the configuration copy now.
+
+ CDS_UpdateCopy ();
+
+ }
+# endif //!defined ( OEM_MSOFT ) // unsupported feature
+
+ return SUCCESS;
+
+} /* end MUI_ProcessCommandLine() */
+
+
+VOID MUI_AdvancedSelections ( VOID )
+
+{
+# if !defined ( OEM_MSOFT )
+ INT rc = DM_SHOWCANCEL;
+ PDS_WMINFO pdsWinInfo;
+ DS_ADVANCED_PTR pdsAdvanced;
+
+ pdsAdvanced = ( DS_ADVANCED_PTR ) calloc ( 1, sizeof ( DS_ADVANCED ) ) ;
+
+ // First, find out which dialog to show: tape or disk
+
+ pdsWinInfo = WM_GetInfoPtr( WM_GetActiveDoc () );
+
+ if ( ( pdsWinInfo->wType == WMTYPE_DISKTREE ) ||
+ ( pdsWinInfo->wType == WMTYPE_DISKS ) ||
+ ( pdsWinInfo->wType == WMTYPE_SERVERS ) ) {
+
+ rc = DM_ShowDialog ( ghWndFrame, IDD_SELECTADVANCED, (PVOID) pdsAdvanced ) ;
+
+ } else if ( ( pdsWinInfo->wType == WMTYPE_TAPETREE ) ||
+ ( pdsWinInfo->wType == WMTYPE_TAPES ) ) {
+
+ rc = DM_ShowDialog ( ghWndFrame, IDD_ADVRESTORE, (PVOID) pdsAdvanced ) ;
+ }
+
+ if ( rc == DM_SHOWOK ) {
+
+ // Call the VLM with the advanced selections structure, because
+ // the user made an advanced selection.
+
+ WM_ShowWaitCursor ( TRUE );
+ VLM_AddAdvancedSelection ( WM_GetActiveDoc (), pdsAdvanced );
+ WM_ShowWaitCursor ( FALSE );
+ }
+
+ free ( pdsAdvanced );
+
+ {
+ MUI_SetButtonState ( IDM_SELECTADVANCED, RIB_ITEM_UP | RIB_ITEM_ENABLED | RIB_ITEM_POSITIONAL );
+ }
+# endif // !defined ( OEM_MSOFT ) // unsupported feature
+
+ STM_SetIdleText ( IDS_READY );
+
+} /* end MUI_AdvancedSelections() */
+
+
+/*****************************************************************************
+
+ Name: MUI_UISystemChange ()
+
+ Description: This function is called when there is a low level UI system
+ change.
+
+ Returns: Nothing.
+
+*****************************************************************************/
+
+VOID MUI_UISystemChange ( VOID )
+
+{
+ // Nothing is done at this time.
+
+} /* end MUI_UISystemChange() */
+
+
+/*****************************************************************************
+
+ Name: MUI_CheckPWDB ()
+
+ Description: This function is called to check for a pw on the pwdb.
+
+ Returns: gfPWForPWDBState
+
+*****************************************************************************/
+
+VOID MUI_CheckPWDB (
+
+CDS_PTR pCDS )
+
+{
+
+ // If the password database is enabled and a password for the
+ // database exists, prompt the user to enter the PW.
+
+ if ( CDS_GetEnablePasswordDbase( pCDS ) ) {
+
+ if ( IsThereADBPassword() ) {
+
+ CDS_SetYesFlag ( CDS_GetCopy (), NO_FLAG );
+ WM_ShowWaitCursor ( FALSE );
+
+ EnterDBPassword( pCDS, ghWndFrame, DBPW_ALLOW_NEW );
+
+ if ( gpszJobName ) {
+ CDS_SetYesFlag ( CDS_GetCopy (), YESYES_FLAG );
+ }
+ WM_ShowWaitCursor ( TRUE );
+
+ } else {
+
+ gfPWForPWDBState = DBPW_VERIFIED;
+
+ }
+
+ }
+
+} /* end MUI_CheckPWDB() */
+
+
+/*****************************************************************************
+
+ Name: MUI_ProcessQuotedString
+
+ Description: Accepts beginning of a string in quotes. It starts and will build
+ a string when it encounters the first quote and continues until it
+ hits another quote. Example: 1. "this
+ 2. is
+ 3. a
+ 4. test" = this is a test
+ (without the quotes)
+ In the above this routine is called FOUR time to build that string
+
+ Parameters: OutPutString - Built string from InPutString. Must be initially
+ empty.
+ InPutString - OutPutString is built from this
+ QuoteState - The very first time this routine is called
+ the lag must be FALSE.
+
+*****************************************************************************/
+
+VOID MUI_ProcessQuotedString ( LPSTR OutPutString,
+ LPSTR InPutString,
+ BOOLEAN *QuoteState )
+{
+ UINT16 lngth;
+
+ lngth = strlen( InPutString );
+ if ( lngth < 1 ) {
+ return;
+ }
+
+ if ( *( InPutString + lngth - 1 ) == TEXT( '"' ) ) {
+ if ( *QuoteState ) {
+ *( InPutString + lngth - 1 ) = TEXT( '\0' );
+ strcat( OutPutString, InPutString );
+ *QuoteState = *QuoteState ? FALSE : TRUE;
+ }
+ }
+
+ if ( *QuoteState ) {
+ strcat( OutPutString, InPutString );
+ }
+}
+
diff --git a/private/utils/ntbackup/src/muiconf.c b/private/utils/ntbackup/src/muiconf.c
new file mode 100644
index 000000000..37d2a6eaa
--- /dev/null
+++ b/private/utils/ntbackup/src/muiconf.c
@@ -0,0 +1,1483 @@
+
+/******************************************************************************
+
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: muiconf.c
+
+ Description: This file contains the functions for the GUI Configuration
+ Manager (CM).
+
+ $Log: G:\ui\logfiles\muiconf.c_v $
+
+ Rev 1.50.1.3 16 Jun 1994 15:26:14 STEVEN
+do not save cfg on exit
+
+ Rev 1.50.1.2 28 Jan 1994 11:16:52 GREGG
+More warning fixes.
+
+ Rev 1.50.1.1 24 Nov 1993 19:11:48 GREGG
+Added hardware compression option to backup dialog and config.
+
+ Rev 1.50.1.0 16 Nov 1993 15:39:08 BARRY
+Put TEXT aroung hard-coded strings
+
+ Rev 1.50 16 Aug 1993 14:43:38 GLENN
+Now setting the gfIgnoreOTC flag based on the opposite of UseTapeCatalogs INI value.
+
+ Rev 1.49 23 Jul 1993 12:20:26 GLENN
+Added Sytron ECC and Drive Settling Time support.
+
+ Rev 1.48 22 Jul 1993 19:11:36 MARINA
+enable c++
+
+ Rev 1.47 16 Jul 1993 10:40:44 GLENN
+Added UseTapeCatalog and SortOptions support.
+
+ Rev 1.46 23 May 1993 19:57:58 BARRY
+Unicode changes.
+
+ Rev 1.45 18 May 1993 14:51:34 GLENN
+Added tape settling time to hardware data struct init.
+
+ Rev 1.44 10 May 1993 13:59:38 MIKEP
+remove calls to openuserprofilemapping.
+
+ Rev 1.43 06 May 1993 17:16:32 chrish
+Added CAYMAN stuff will not affect Nostradamus. To do HW/SW compression
+stuff.
+
+ Rev 1.42 02 May 1993 15:30:12 MIKEP
+Add code to place the event message information into the registry at startup
+if it is not already there. Steve is fixing this in nostradamus at msoft
+by having the entries placed in the distributed registries. But cayman must
+add it's own.
+
+ Rev 1.41 30 Apr 1993 15:54:30 GLENN
+Added INI command line support.
+
+ Rev 1.40 27 Apr 1993 11:24:24 GLENN
+Added Search tapes with password, Search subdirs, log file prefix.
+
+ Rev 1.39 23 Apr 1993 08:52:12 MIKEP
+Change the ini path to be \software\conner for cayman instead
+of \software\microsoft.
+
+ Rev 1.38 19 Apr 1993 15:08:52 GLENN
+Fixed registry string logic.
+
+ Rev 1.37 17 Apr 1993 17:20:58 MIKEP
+add ini to registry
+
+ Rev 1.36 05 Apr 1993 13:33:52 GLENN
+Starting debug window in normal position.
+
+ Rev 1.35 06 Jan 1993 10:17:16 GLENN
+Miscellaneous window validations.
+
+ Rev 1.34 04 Jan 1993 14:38:06 GLENN
+Added File Details and Search Limit items.
+
+ Rev 1.33 23 Dec 1992 15:41:58 GLENN
+Added all file details, runtime dlg pos saving, search limit, FAT drive lower case display.
+
+ Rev 1.32 18 Nov 1992 13:05:38 GLENN
+Added initialization states for frame and disk windows.
+
+ Rev 1.31 11 Nov 1992 16:33:28 DAVEV
+UNICODE: remove compile warnings
+
+ Rev 1.30 05 Nov 1992 17:09:42 DAVEV
+fix ts
+
+ Rev 1.28 30 Oct 1992 15:47:12 GLENN
+Added Frame and MDI Doc window size and position saving and restoring.
+
+ Rev 1.27 14 Oct 1992 15:53:36 GLENN
+Added Font selection to Config and INI.
+
+ Rev 1.26 07 Oct 1992 14:11:52 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.25 04 Oct 1992 19:39:14 DAVEV
+Unicode Awk pass
+
+ Rev 1.24 17 Sep 1992 17:40:36 DAVEV
+minor fix (strsiz->strsize)
+
+ Rev 1.23 17 Sep 1992 15:51:10 DAVEV
+UNICODE modifications: strlen usage check
+
+ Rev 1.22 08 Sep 1992 14:06:10 STEVEN
+fix warnings for NT
+
+ Rev 1.21 19 Aug 1992 14:31:42 CHUCKB
+Changed for NT.
+
+ Rev 1.20 06 Aug 1992 22:01:00 MIKEP
+add support for tape drive name for nt
+
+ Rev 1.19 29 Jul 1992 14:14:26 GLENN
+ChuckB checked in after NT fixes.
+
+ Rev 1.18 30 Jun 1992 13:16:12 JOHNWT
+added enable stats flag
+
+ Rev 1.17 10 Jun 1992 16:53:32 DAVEV
+OEM_MSOFT: force Prompt before overwite existing files
+
+ Rev 1.16 10 Jun 1992 10:43:48 STEVEN
+change NULL to 0
+
+ Rev 1.15 15 May 1992 16:48:12 MIKEP
+incl_cds removal
+
+ Rev 1.14 14 May 1992 18:00:36 MIKEP
+nt pass 2
+
+ Rev 1.13 01 Apr 1992 09:47:34 JOHNWT
+key creation of config on existence of debug info
+
+ Rev 1.12 20 Mar 1992 17:23:16 GLENN
+Added std mode warning config option.
+
+ Rev 1.11 18 Mar 1992 14:13:54 JOHNWT
+commented out write of PWD entries
+
+ Rev 1.10 27 Feb 1992 11:15:42 JOHNWT
+wait/skip files change
+
+ Rev 1.9 27 Feb 1992 08:37:50 GLENN
+Added SetupExePath and ChangeToExeDir.
+
+ Rev 1.8 23 Feb 1992 13:46:06 GLENN
+Moved INI util functions to confmisc.c
+
+ Rev 1.7 27 Jan 1992 12:51:16 GLENN
+Changed hardware config init status.
+
+ Rev 1.6 24 Jan 1992 14:50:48 GLENN
+Updated the get hardware config function.
+
+ Rev 1.5 20 Jan 1992 09:42:10 GLENN
+Moved data path verification to verify functions.
+
+ Rev 1.4 14 Jan 1992 08:16:44 GLENN
+Added Sort BSD support.
+
+ Rev 1.3 10 Jan 1992 11:18:42 DAVEV
+16/32 bit port-2nd pass
+
+ Rev 1.2 07 Jan 1992 17:29:00 GLENN
+Added catalog data path support
+
+ Rev 1.1 04 Dec 1991 18:43:10 GLENN
+Added machine type references.
+
+ Rev 1.0 20 Nov 1991 19:30:56 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+#ifdef TDEMO
+#define CMI_ARCBIT 0
+#define CMI_REMOTE 1
+#else
+#define CMI_ARCBIT 1
+#define CMI_REMOTE 0
+#endif
+
+#define CDS_TOKENS TEXT(", ")
+
+#define TOKEN_WINSIZE 1
+#define TOKEN_WINSHOW 2
+#define TOKEN_WINSLIDER 3
+
+// VARIABLE DECLARATIONS
+
+CDS PermCDS;
+CDS TempCDS;
+BE_CFG_PTR pPermBEC;
+
+
+// PRIVATE FUNCTION PROTOTYPES
+
+VOID CDS_GetUIConfig ( VOID );
+VOID CDS_GetDisplayConfig ( VOID );
+VOID CDS_GetLoggingConfig ( VOID );
+VOID CDS_GetDebugConfig ( VOID );
+VOID CDS_GetBEConfig ( VOID );
+INT CDS_GetToken ( WORD, LPSTR );
+
+VOID CDS_CreateConfigFile ( VOID );
+VOID CDS_SaveCDS ( VOID );
+VOID CDS_SaveUIConfig ( VOID );
+VOID CDS_SaveBEConfig ( VOID );
+
+#ifdef OS_WIN32
+
+INT CDS_CheckRegistryForIniMappings( VOID );
+INT CDS_CheckRegistryForEventMappings( VOID );
+
+/**************************************************************************
+
+ Name: CDS_CheckRegistryForEventMappings ()
+
+ Description: Check the registry to see if it knows about us already.
+
+ Returns: Nothing.
+
+**************************************************************************/
+
+INT CDS_CheckRegistryForEventMappings( )
+{
+ HKEY Key;
+ LONG Status;
+ DWORD Disposition;
+ DWORD Types = (DWORD)0x07;
+ INT KeyFound = FALSE;
+ CHAR path[ 256 ];
+
+ Status = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
+#ifdef OEM_MSOFT
+ TEXT("System\\CurrentControlSet\\Services\\EventLog\\Application\\Ntbackup.ini"),
+#else
+ TEXT("System\\CurrentControlSet\\Services\\EventLog\\Application\\Bewinnt"),
+#endif
+ (DWORD)0,
+ (LPTSTR)TEXT(""),
+ REG_OPTION_NON_VOLATILE,
+ MAXIMUM_ALLOWED,
+ (LPSECURITY_ATTRIBUTES)NULL,
+ &Key,
+ &Disposition );
+
+
+
+ if ( Status != ERROR_SUCCESS ) {
+
+ return( FAILURE );
+ }
+
+
+ strcpy( path, CDS_GetExePath() );
+ strcat( path, gb_exe_fname );
+
+ // Add our string to it.
+
+ Status = RegSetValueEx( Key,
+ TEXT("EventMessageFile"),
+ (DWORD)0,
+ REG_SZ,
+ (LPBYTE)path,
+ (DWORD)(strsize(path) * sizeof(CHAR) ) );
+
+ if ( Status != ERROR_SUCCESS ) {
+ RegCloseKey( Key );
+ return( FAILURE );
+ }
+
+ // Add our string to it.
+
+ Status = RegSetValueEx( Key,
+ TEXT("TypesSupported"),
+ (DWORD)0,
+ REG_DWORD,
+ (LPBYTE)&Types,
+ (DWORD)sizeof( DWORD ) );
+
+ if ( Status != ERROR_SUCCESS ) {
+ RegCloseKey( Key );
+ return( FAILURE );
+ }
+
+
+ RegCloseKey( Key );
+
+ return( SUCCESS );
+}
+
+/**************************************************************************
+
+ Name: CDS_CheckRegistryForIniMappings ()
+
+ Description: Check the registry to see if it knows about us already.
+
+ Returns: Nothing.
+
+**************************************************************************/
+
+INT CDS_CheckRegistryForIniMappings( )
+{
+ HKEY Key;
+ LONG Status;
+ DWORD Disposition;
+ INT KeyFound = FALSE;
+
+#ifdef OEM_MSOFT
+ CHAR String[] = TEXT("#USR:Software\\Microsoft\\Ntbackup");
+#else
+ CHAR String[] = TEXT("#USR:Software\\Conner\\Bewinnt");
+#endif
+
+ // ********************************************************
+ //
+ // First Do Machine Specific Part
+ //
+ // ********************************************************
+
+ Status = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
+#ifdef OEM_MSOFT
+ TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\IniFileMapping\\Ntbackup.ini"),
+#else
+ TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\IniFileMapping\\Bewinnt.ini"),
+#endif
+ (DWORD)0,
+ (LPTSTR)TEXT(""),
+ REG_OPTION_NON_VOLATILE,
+ MAXIMUM_ALLOWED,
+ (LPSECURITY_ATTRIBUTES)NULL,
+ &Key,
+ &Disposition );
+
+
+
+ if ( Status != ERROR_SUCCESS ) {
+
+ return( FAILURE );
+ }
+
+
+ if ( Disposition == REG_CREATED_NEW_KEY ) {
+
+
+ // Add our string to it.
+
+ Status = RegSetValueEx( Key,
+ TEXT(""),
+ (DWORD)0,
+ REG_SZ,
+ (LPBYTE)String,
+ (DWORD)(strsize(String) * sizeof(CHAR) ) );
+
+ if ( Status != ERROR_SUCCESS ) {
+ RegCloseKey( Key );
+ return( FAILURE );
+ }
+
+ }
+
+ RegCloseKey( Key );
+
+ // ********************************************************
+ //
+ // Then Do User Specific Part
+ //
+ // ********************************************************
+
+ Status = RegCreateKeyEx( HKEY_CURRENT_USER,
+#ifdef OEM_MSOFT
+ TEXT("Software\\Microsoft\\Ntbackup"),
+#else
+ TEXT("Software\\Conner\\Bewinnt"),
+#endif
+ (DWORD)0,
+ (LPTSTR)TEXT(""),
+ REG_OPTION_NON_VOLATILE,
+ MAXIMUM_ALLOWED,
+ (LPSECURITY_ATTRIBUTES)NULL,
+ &Key,
+ &Disposition );
+
+ if ( Status != ERROR_SUCCESS ) {
+
+ return( FAILURE );
+ }
+
+ RegCloseKey( Key );
+
+
+ return( SUCCESS );
+}
+
+#endif
+
+
+/******************************************************************************
+
+ Name: CDS_Init ()
+
+ Description: Initializes the perm CDS from the private profile file.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID CDS_Init ( VOID )
+
+{
+ INT nNumControllers;
+
+
+#ifdef OS_WIN32
+
+ if ( ! CDS_UsingCmdLineINI () ) {
+
+ CDS_CheckRegistryForIniMappings();
+ }
+
+#endif
+
+ // Set up the exe path and file name.
+
+ CDS_SetupExePath ();
+
+#ifdef OS_WIN32
+ CDS_CheckRegistryForEventMappings();
+#endif
+
+ // The loading of the INI name is NOW DONE IN GUI.C for
+ // multiple INI file support.
+
+ // Set the known defaults.
+
+ CDS_SetChangedConfig ( &PermCDS, FALSE );
+ CDS_SetDefaultDriveList ( &PermCDS, NULL );
+ CDS_SetYesFlag ( &PermCDS, NO_FLAG );
+ CDS_SetEraseFlag ( &PermCDS, ERASE_OFF );
+ CDS_SetTransferFlag ( &PermCDS, FALSE );
+ CDS_SetAdvToConfig ( &PermCDS, FALSE );
+
+ // Get and validate the Maynard data path. Do this by first stuffing
+ // the path read from the .INI file into the Temporary CDS, then making
+ // sure that a '\' is appended to the end of the path. This is
+ // accomplished by calling CDS_SetUserDataPath().
+
+ CDS_ReadUserDataPath ( &PermCDS );
+ CDS_ValidateUserDataPath ( CDS_GetUserDataPath () );
+ CDS_SetMaynFolder ( CDS_GetUserDataPath () );
+
+ // Validate the catalog data path.
+
+ CDS_ReadCatDataPath ( &PermCDS );
+ CDS_ValidateCatDataPath ( CDS_GetCatDataPath () );
+
+ // Set the Update password database filename.
+
+ RSM_StringCopy ( IDS_PWDFILENAME,
+ CDS_GetPwDbaseFname ( &PermCDS ),
+ MAX_UI_FILENAME_SIZE );
+
+ // Initialize the backup engine configuration unit.
+
+ BEC_Init ();
+
+ // Create the global permanent backup engine configuration structure.
+ // Lock the BEC to make sure that it does not get destroyed.
+
+ pPermBEC = PermCDS.pPermBEC = BEC_CloneConfig ( NULL );
+
+ BEC_LockConfig ( pPermBEC );
+
+ // Get the different config stuff
+
+ CDS_GetUIConfig ();
+ CDS_GetDisplayConfig ();
+ CDS_GetLoggingConfig ();
+
+ // If there are no configured controllers for this driver or the driver
+ // is invalid based on initializing the DIL HWD, then we want to advance
+ // to the hardware settings dialog by setting the flag.
+
+ PermCDS.pHWParms = (HWPARMS_PTR)calloc ( 1, sizeof ( HWPARMS ) );
+
+ nNumControllers = CDS_GetHardwareConfig ( CDS_GetActiveDriver ( &PermCDS ), PermCDS.pHWParms );
+
+ if ( ! nNumControllers || HWC_InitDILHWD ( &gb_dhw_ptr, &nNumControllers ) ) {
+
+ CDS_SetAdvToConfig ( &PermCDS, 1 );
+ }
+
+ // Reset the global DIL HWD pointer.
+
+ gb_dhw_ptr = (DIL_HWD_PTR)NULL;
+
+ CDS_GetDebugConfig ();
+ CDS_GetBEConfig ();
+
+ gfIgnoreOTC = ! CDS_GetUseTapeCatalogs ( &PermCDS );
+
+ // Update the temporary config from permanent.
+
+ CDS_UpdateCopy( ) ;
+
+ // if no debug info is in the config, we assume this is an incomplete
+ // config and write out the complete file
+
+ if ( CDS_GetInt ( CMS_DEBUG, CMS_DEBUGFLAG, 0xFFFF ) == 0xFFFF ) {
+
+ CDS_CreateConfigFile ();
+ }
+
+ CDS_ChangeToExeDir ();
+
+ return ;
+
+} /* end CDS_Init() */
+
+
+/******************************************************************************
+
+ Name: CDS_Deinit ()
+
+ Description: Deinitializes and saves the CDS and BEC.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID CDS_Deinit ( VOID )
+
+{
+ // Save the CDS and BEC configurations.
+
+#ifndef OEM_MSOFT
+ CDS_SaveCDS ();
+#endif
+ // Release the permanent BEC memory and close the BEC.
+
+ BEC_UnLockConfig ( pPermBEC );
+ BEC_ReleaseConfig ( pPermBEC );
+ BEC_Close ();
+
+} /* end CDS_Deinit() */
+
+
+/******************************************************************************
+
+ Name: CDS_GetUIConfig ()
+
+ Description: Gets the UI config from the private profile file.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID CDS_GetUIConfig ( VOID )
+
+{
+ CHAR szDefDrivesLine[CDS_STRLEN];
+ CHAR szDriveName[CDS_STRLEN];
+ CHAR_PTR p;
+ CHAR_PTR pLine;
+ DEF_DRIVE_ENTRY *pNewDriveEntry ;
+ DEF_DRIVE_ENTRY *pNextDriveEntry ;
+
+ // Read the UI config from the INI file.
+
+ CDS_ReadOutputDest ( &PermCDS );
+ CDS_ReadFilesFlag ( &PermCDS );
+ CDS_ReadPasswordFlag ( &PermCDS );
+ CDS_ReadCreateSkipped ( &PermCDS );
+ CDS_ReadDisplayNetwareServers ( &PermCDS );
+ CDS_ReadAutoVerifyBackup ( &PermCDS );
+ CDS_ReadAutoVerifyRestore ( &PermCDS );
+ CDS_ReadEnablePasswordDbase ( &PermCDS );
+ CDS_ReadMaxPwDbaseSize ( &PermCDS );
+ CDS_ReadAppendFlag ( &PermCDS );
+ CDS_ReadCatalogLevel ( &PermCDS );
+
+# if defined ( OEM_MSOFT ) // no user selection for restore over existing
+ {
+ CDS_SetDisplayNetwareServers ( &PermCDS, CDS_DISABLE );
+ CDS_SetRestoreExistingFiles ( &PermCDS, PROMPT_RESTORE_OVER_EXISTING );
+ }
+# else //if defined ( OEM_MSOFT ) // no user selection for restore over existing
+ {
+ CDS_ReadDisplayNetwareServers ( &PermCDS );
+ CDS_ReadRestoreExistingFiles ( &PermCDS );
+ }
+# endif //defined ( OEM_MSOFT ) // no user selection for restore over existing
+
+ CDS_ReadBackupCatalogs ( &PermCDS );
+ CDS_ReadLauncherFlag ( &PermCDS );
+ CDS_ReadIncludeSubdirs ( &PermCDS );
+ CDS_ReadDefaultBackupType ( &PermCDS );
+ CDS_ReadEjectTapeFlag ( &PermCDS );
+
+# if defined ( OEM_MSOFT ) // no stats
+ {
+ CDS_SetEnableStatsFlag ( &PermCDS, CDS_DISABLE );
+ }
+# else
+ {
+ CDS_ReadEnableStatsFlag ( &PermCDS );
+ }
+# endif //defined ( OEM_MSOFT )
+
+ CDS_ReadSearchLimit ( &PermCDS );
+ CDS_ReadSearchPwdTapes ( &PermCDS );
+ CDS_ReadSearchSubdirs ( &PermCDS );
+ CDS_ReadUseTapeCatalogs ( &PermCDS );
+
+ CDS_ReadWaitTime ( &PermCDS );
+ CDS_ReadStdModeWarning ( &PermCDS );
+
+ // If no groupname was found in the config file, get the default group
+ // name from the resources.
+
+ if ( ! CDS_ReadGroupName ( &PermCDS ) ) {
+ RSM_StringCopy ( IDS_APPNAME, CDS_GetGroupName (&PermCDS), MAX_GROUPNAME_SIZE );
+ }
+
+
+ // Create the default drives list.
+
+ CDS_GetString ( CMS_UI, CMS_DEFDRIVES, TEXT("C"), szDefDrivesLine, CDS_STRLEN );
+
+ pLine = szDefDrivesLine;
+
+ while ( *pLine != TEXT('\0') ) {
+
+ CDS_SkipBlanks ( pLine );
+
+ if ( *pLine != TEXT('\0') ) {
+
+ pNewDriveEntry = (DEF_DRIVE_ENTRY_PTR)malloc( sizeof( DEF_DRIVE_ENTRY ) );
+ pNewDriveEntry->next = NULL ;
+
+ // Get drive name.
+
+ p = szDriveName ;
+
+ // Copy the drive name into the szDriveName buffer.
+
+ while ( ( *pLine != TEXT(' ') ) && ( *pLine != TEXT('\0') ) ) {
+ *p = *pLine;
+ p++;
+ pLine++;
+ }
+
+ *p = TEXT('\0') ;
+
+ pNewDriveEntry->drive_name = (CHAR_PTR)malloc( strsize( szDriveName ) );
+ strcpy( pNewDriveEntry->drive_name, szDriveName ) ;
+
+ // Add to default drive list.
+
+ if ( CDS_GetDefaultDriveList ( &PermCDS ) == NULL ) {
+ CDS_SetDefaultDriveList ( &PermCDS, pNewDriveEntry );
+ }
+ else {
+
+ // Put the new entry at the end of the list.
+
+ pNextDriveEntry = CDS_GetDefaultDriveList ( &PermCDS );
+
+ while ( pNextDriveEntry->next != NULL ) {
+ pNextDriveEntry = pNextDriveEntry->next;
+ }
+
+ pNextDriveEntry->next = pNewDriveEntry;
+ }
+ }
+ }
+
+} /* end CDS_GetUIConfig() */
+
+
+/******************************************************************************
+
+ Name: CDS_GetDisplayConfig ()
+
+ Description: Gets the display config from the private profile file.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID CDS_GetDisplayConfig ( VOID )
+
+{
+ CDS_ReadShowMainRibbon ( &PermCDS );
+ CDS_ReadShowStatusLine ( &PermCDS );
+
+ CDS_ReadFontFace ( &PermCDS );
+ CDS_ReadFontSize ( &PermCDS );
+ CDS_ReadFontWeight ( &PermCDS );
+ CDS_ReadFontCase ( &PermCDS );
+ CDS_ReadFontCaseFAT ( &PermCDS );
+ CDS_ReadFontItalics ( &PermCDS );
+ CDS_ReadFileDetails ( &PermCDS );
+ CDS_ReadSortOptions ( &PermCDS );
+
+ // Add the MDI Doc Window coordinates to this list in the NEXT release.
+ // This time has arrived. Take a look.
+
+ if ( ! CDS_GetWinSize ( CMS_FRAMEWINDOW, &(PermCDS.frame_info) ) ) {
+ PermCDS.frame_info.x = 0;
+ PermCDS.frame_info.y = 0;
+ PermCDS.frame_info.nSize = 0;
+ }
+
+ if ( ! CDS_GetWinSize ( CMS_DISKWINDOW, &(PermCDS.disk_info) ) ) {
+ PermCDS.disk_info.x = 0;
+ PermCDS.disk_info.y = 0;
+ PermCDS.disk_info.nSize = 0;
+ }
+
+ CDS_GetWinSize ( CMS_SERVERWINDOW, &(PermCDS.server_info) );
+ CDS_GetWinSize ( CMS_TAPEWINDOW, &(PermCDS.tape_info) );
+ CDS_GetWinSize ( CMS_LOGWINDOW, &(PermCDS.log_info) );
+
+ if ( ! CDS_GetWinSize ( CMS_DEBUGWINDOW, &(PermCDS.debug_info) ) ) {
+ PermCDS.debug_info.nSize = 0;
+ }
+
+ if ( ! CDS_GetWinSize ( CMS_RUNTIMEDLG, &(PermCDS.runtime_info) ) ) {
+ PermCDS.runtime_info.nSize = WM_DEFAULT;
+ }
+
+
+} /* end CDS_GetDisplayConfig() */
+
+
+/******************************************************************************
+
+ Name: CDS_GetWinSize ()
+
+ Description: Gets the size of the window.
+
+ Returns: TRUE, if the config line was found, otherwise, FALSE.
+
+******************************************************************************/
+
+BOOL CDS_GetWinSize (
+
+LPSTR szType,
+PWINSIZE pWinSize )
+
+{
+ CHAR szTokens[MAX_UI_RESOURCE_SIZE];
+ BOOL fFound;
+
+ fFound = (BOOL)CDS_ReadWindowSize ( szType, szTokens );
+
+ pWinSize->x = CDS_GetToken ( TOKEN_WINSIZE, (LPSTR)szTokens );
+ pWinSize->y = CDS_GetToken ( TOKEN_WINSIZE, (LPSTR)NULL );
+ pWinSize->cx = CDS_GetToken ( TOKEN_WINSIZE, (LPSTR)NULL );
+ pWinSize->cy = CDS_GetToken ( TOKEN_WINSIZE, (LPSTR)NULL );
+ pWinSize->nSize = CDS_GetToken ( TOKEN_WINSHOW, (LPSTR)NULL );
+ pWinSize->nSliderPos = CDS_GetToken ( TOKEN_WINSLIDER, (LPSTR)NULL );
+
+ return fFound;
+
+} /* end CDS_GetWinSize() */
+
+
+/******************************************************************************
+
+ Name: CDS_GetLoggingConfig ()
+
+ Description: Gets the logging config from the private profile file.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID CDS_GetLoggingConfig ( VOID )
+
+{
+ CDS_ReadLogFileRoot ( &PermCDS );
+ CDS_ReadNumLogSessions ( &PermCDS );
+ CDS_ReadLogLevel ( &PermCDS );
+ CDS_ReadLogMode ( &PermCDS );
+ CDS_ReadPrintLogSession ( &PermCDS );
+
+} /* end CDS_GetLoggingConfig() */
+
+
+/******************************************************************************
+
+ Name: CDS_GetHardwareConfig ()
+
+ Description: Gets the hardware config from the private profile file.
+
+ Returns: The number of cards configured for this driver.
+
+******************************************************************************/
+
+INT CDS_GetHardwareConfig (
+
+LPSTR lpDriverName, // I - device driver name of controller configuration
+HWPARMS_PTR pCallerHW ) // I - pointer to the callers HW Parms
+
+{
+ CHAR szDriverConfig[40];
+ INT nNumControllers = 0; // number of controllers
+ BOOL fDone=FALSE;
+ WORD wStatus;
+ HWPARMS_PTR pHW;
+ HWPARMS_PTR pTempHW;
+
+ // Get the device driver name.
+
+#ifdef OS_WIN32
+ CDS_ReadTapeDriveName ( &PermCDS );
+#endif
+
+ CDS_ReadActiveDriver ( &PermCDS );
+
+ CDS_ReadHWCompMode ( &PermCDS ); // chs:05-06-93
+#ifndef OEM_MSOFT // chs:05-06-93
+ CDS_ReadSWCompMode ( &PermCDS ); // chs:05-06-93
+#endif // chs:05-06-93
+
+ CDS_ReadTapeDriveSettlingTime ( &PermCDS );
+
+ // TEMP STUFF
+
+ // Now, grab all of the controller lines in the configuration file.
+
+ while ( ! fDone ) {
+
+ sprintf ( szDriverConfig, TEXT("%s %s %d"), lpDriverName, CMS_CONTROLLER, nNumControllers );
+
+ wStatus = CDS_GetInt ( szDriverConfig, CMS_STATUS, 0xFFFF );
+
+ // If we have at least one controller and the status is invalid,
+ // we are done.
+
+ if ( nNumControllers && wStatus > 2 ) {
+
+ fDone = TRUE;
+ }
+ else {
+
+ // If there was a previous hardware parms structure, set the next
+ // pointer to the newly malloc'd structure.
+ // Otherwise, set the Hardware parms Config Pointer to point
+ // to the newly allocated structure.
+
+ if ( nNumControllers ) {
+ pHW->pNext = pTempHW = (HWPARMS_PTR)malloc ( sizeof ( HWPARMS ) );
+ }
+ else {
+ pTempHW = pCallerHW;
+ }
+
+ pHW = pTempHW;
+
+ pHW->wStatus = IDS_HWC_TESTED_NOT;
+ pHW->wCardID = CDS_GetInt ( szDriverConfig, CMS_CARDID, 0xFFFF );
+ pHW->wDrives = CDS_GetInt ( szDriverConfig, CMS_DRIVES, 0 );
+ pHW->wSlot = CDS_GetInt ( szDriverConfig, CMS_SLOT, 0 );
+ pHW->wTargets = CDS_GetInt ( szDriverConfig, CMS_TARGETS, 0xFFFF );
+
+ // Now get the device dependent parameters.
+
+ // ????? Temp hardcoded addr, irq, dma.
+
+ pHW->nNumParms = 3;
+
+ pHW->ulAddr = CDS_GetLongInt ( szDriverConfig, CMS_ADDR, 0xFFFFFFFF );
+ pHW->ulIRQ = CDS_GetLongInt ( szDriverConfig, CMS_IRQ, 0xFFFFFFFF );
+ pHW->ulDMA = CDS_GetLongInt ( szDriverConfig, CMS_DMA, 0xFFFFFFFF );
+
+ pHW->pNext = (HWPARMS_PTR)NULL;
+
+ // If this is the first controller and we have an invalid
+ // status, we have now set-up an autodetermine scenario.
+
+ if ( ! nNumControllers && wStatus == 0xFFFF ) {
+ return nNumControllers;
+ }
+
+ // Increment the controller count.
+
+ nNumControllers++;
+ }
+
+ } /* end while() */
+
+ return nNumControllers;
+
+} /* end CDS_GetHardwareConfig() */
+
+
+/******************************************************************************
+
+ Name: CDS_GetDebugConfig ()
+
+ Description: Gets the Debugging config from the private profile file.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID CDS_GetDebugConfig ( VOID )
+
+{
+ CDS_ReadDebugFlag ( &PermCDS );
+ CDS_ReadDebugToFile ( &PermCDS );
+ CDS_ReadDebugToWindow ( &PermCDS );
+ CDS_ReadDebugWindowShowAll ( &PermCDS );
+ CDS_ReadDebugWindowNumLines ( &PermCDS );
+ CDS_ReadDebugFileName ( &PermCDS );
+ CDS_ReadPollFrequency ( &PermCDS );
+
+
+} /* end CDS_GetDebugConfig() */
+
+
+/******************************************************************************
+
+ Name: CDS_GetBEConfig ()
+
+ Description: Gets the BEC config from the private profile file.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID CDS_GetBEConfig ( VOID )
+
+{
+ CDS_PTR pCDS = CDS_GetPerm ();
+
+ // The following two are not used by our app.
+
+ CDS_SetReserveMem ( pCDS, 0 );
+ //CDS_SetPartList ( pCDS, 0L );
+
+ // Default the restore security off.
+
+ CDS_SetRestoreSecurity ( pCDS, FALSE );
+
+ // Read the following BENGINE stuff from the INI file.
+
+ CDS_ReadSpecialWord ( pCDS );
+ CDS_ReadMaxTapeBuffers ( pCDS );
+ CDS_ReadTFLBuffSize ( pCDS );
+ CDS_ReadMaxBufferSize ( pCDS );
+ CDS_ReadSkipOpenFiles ( pCDS );
+ CDS_ReadBackupFilesInUse ( pCDS );
+ CDS_ReadAFPSupport ( pCDS );
+ CDS_ReadExtendedDateSupport ( pCDS );
+
+ CDS_ReadHiddenFlag ( pCDS );
+ CDS_ReadSpecialFlag ( pCDS );
+ CDS_ReadSetArchiveFlag ( pCDS );
+ CDS_ReadProcEmptyFlag ( pCDS );
+ CDS_ReadExistFlag ( pCDS );
+ CDS_ReadPromptFlag ( pCDS );
+ CDS_ReadNetNum ( pCDS );
+ CDS_ReadSortBSD ( pCDS );
+
+ CDS_ReadRemoteDriveBackup ( pCDS );
+ CDS_ReadFastFileRestore ( pCDS );
+
+#if !defined( OEM_MSOFT )
+ CDS_ReadWriteFormat ( pCDS );
+ CDS_ReadNRLDosVector ( pCDS );
+#endif
+
+ CDS_ReadConfiguredMachineType ( pCDS );
+ CDS_ReadProcessSytronECCFlag ( pCDS );
+
+ // Make sure we do not have a bogus machine type.
+
+ switch ( CDS_GetConfiguredMachineType ( pCDS ) ) {
+
+ case UNKNOWN_MACHINE:
+ case IBM_PS2:
+ case IBM_PC:
+ case IBM_XT_OR_PC_PORTABLE:
+ case IBM_PC_JR:
+ case IBM_AT:
+ break;
+
+ default:
+ CDS_SetConfiguredMachineType ( pCDS, UNKNOWN_MACHINE );
+ break;
+ }
+
+ CDS_ReadOTCLevel ( pCDS );
+
+
+} /* end CDS_GetBEConfig() */
+
+
+/******************************************************************************
+
+ Name: CDS_CreateConfigFile ()
+
+ Description: Saves GUI config data structure and BENGINE config data
+ structure to private a profile file.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID CDS_CreateConfigFile ( VOID )
+
+{
+ CDS_SaveUIConfig ();
+ CDS_SaveDisplayConfig ();
+ CDS_SaveLoggingConfig ();
+ CDS_SaveDebugConfig ();
+ CDS_SaveBEConfig ();
+
+ CDS_WriteHWCompMode ( &PermCDS ); // chs:05-06-93
+#ifndef OEM_MSOFT // chs:05-06-93
+ CDS_WriteSWCompMode ( &PermCDS ); // chs:05-06-93
+#endif // chs:05-06-93
+
+ CDS_WriteTapeDriveSettlingTime ( &PermCDS );
+
+} /* end CDS_CreateConfigFile() */
+
+
+/******************************************************************************
+
+ Name: CDS_SaveCDS ()
+
+ Description: Saves GUI config data structure to private profile file
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID CDS_SaveCDS ( VOID )
+
+{
+ if ( CDS_GetChangedConfig ( &PermCDS ) ) {
+
+ CDS_SaveUIConfig ();
+ CDS_SaveBEConfig ();
+ }
+
+ CDS_SaveDisplayConfig ();
+
+ return ;
+
+} /* end CDS_SaveCDS() */
+
+
+/******************************************************************************
+
+ Name: CDS_SaveUIConfig ()
+
+ Description: Saves UI config data structure to private profile file.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID CDS_SaveUIConfig ()
+
+{
+ // Write the UI config
+
+#ifdef OS_WIN32
+ CDS_WriteTapeDriveName ( &PermCDS );
+#endif
+ CDS_WriteOutputDest ( &PermCDS );
+ CDS_WriteFilesFlag ( &PermCDS );
+ CDS_WritePasswordFlag ( &PermCDS );
+ CDS_WriteCreateSkipped ( &PermCDS );
+ CDS_WriteDisplayNetwareServers ( &PermCDS );
+ CDS_WriteAutoVerifyBackup ( &PermCDS );
+ CDS_WriteAutoVerifyRestore ( &PermCDS );
+ CDS_WriteEnablePasswordDbase ( &PermCDS );
+// CDS_WriteMaxPwDbaseSize ( &PermCDS );
+ CDS_WriteAppendFlag ( &PermCDS );
+ CDS_WriteCatalogLevel ( &PermCDS );
+ CDS_WriteRestoreExistingFiles ( &PermCDS );
+ CDS_WriteBackupCatalogs ( &PermCDS );
+ CDS_WriteLauncherFlag ( &PermCDS );
+ CDS_WriteIncludeSubdirs ( &PermCDS );
+ CDS_WriteDefaultBackupType ( &PermCDS );
+ CDS_WriteEjectTapeFlag ( &PermCDS );
+ CDS_WriteEnableStatsFlag ( &PermCDS );
+ CDS_WriteSearchLimit ( &PermCDS );
+ CDS_WriteSearchPwdTapes ( &PermCDS );
+ CDS_WriteSearchSubdirs ( &PermCDS );
+ CDS_WriteUseTapeCatalogs ( &PermCDS );
+ CDS_WriteWaitTime ( &PermCDS );
+ CDS_WriteStdModeWarning ( &PermCDS );
+
+
+
+ // DEFAULT DRIVES ?????
+ // PASSWORD ?????
+
+} /* end CDS_SaveUIConfig() */
+
+
+/******************************************************************************
+
+ Name: CDS_SaveDisplayConfig ()
+
+ Description: Saves config data structure to private profile file.
+
+ Returns:
+
+******************************************************************************/
+
+VOID CDS_SaveDisplayConfig ()
+
+{
+ CDS_WriteShowMainRibbon ( &PermCDS );
+ CDS_WriteShowStatusLine ( &PermCDS );
+
+ CDS_WriteFontFace ( &PermCDS );
+ CDS_WriteFontSize ( &PermCDS );
+ CDS_WriteFontWeight ( &PermCDS );
+ CDS_WriteFontCase ( &PermCDS );
+ CDS_WriteFontCaseFAT ( &PermCDS );
+ CDS_WriteFontItalics ( &PermCDS );
+ CDS_WriteFileDetails ( &PermCDS );
+ CDS_WriteSortOptions ( &PermCDS );
+
+ CDS_WriteFrameWinSize ( ghWndFrame );
+
+} /* end CDS_SaveDisplayConfig() */
+
+
+/******************************************************************************
+
+ Name: CDS_SaveLoggingConfig ()
+
+ Description: Saves config data structure to private profile file.
+
+ Returns:
+
+******************************************************************************/
+
+VOID CDS_SaveLoggingConfig ()
+
+{
+ CDS_WriteLogFileRoot ( &PermCDS );
+ CDS_WriteNumLogSessions ( &PermCDS );
+ CDS_WriteLogLevel ( &PermCDS );
+ CDS_WriteLogMode ( &PermCDS );
+ CDS_WritePrintLogSession ( &PermCDS );
+
+} /* end CDS_SaveLoggingConfig() */
+
+
+/******************************************************************************
+
+ Name: CDS_SaveHardwareConfig ()
+
+ Description: Saves config data structure to private profile file.
+
+ Returns: FALSE, if no changes were detected. Otherwise, TRUE.
+
+******************************************************************************/
+
+VOID CDS_SaveHardwareConfig (
+
+LPSTR lpszDriver, // I - pointer to the driver name
+HWPARMS_PTR pHW, // I - pointer to the hardware parms to save
+LPSTR lpszCardName ) // I - string containing the card name
+
+{
+ CHAR szAppName[80];
+ CHAR szString[80];
+ INT nController = 0;
+ CDS_PTR pCDS = CDS_GetPerm ();
+
+
+
+
+ // If this is the autodetermine driver, don't save it.
+
+ if ( ! stricmp ( lpszDriver, CMS_AUTO ) ) {
+ return;
+ }
+
+ CDS_SetActiveDriver ( pCDS, lpszDriver );
+ CDS_SaveString ( CMS_HARDWARE, CMS_DRIVER, lpszDriver );
+
+ sprintf ( szAppName, TEXT("%s %s %u"), lpszDriver, CMS_CONTROLLER, nController );
+ sprintf ( szString, TEXT("%u (%s)"), pHW->wCardID, lpszCardName );
+ CDS_SaveString ( szAppName, CMS_CARDID, szString );
+
+ sprintf ( szString, TEXT("%u (%s)"), 1, TEXT("status mark") );
+ CDS_SaveString ( szAppName, CMS_STATUS, szString );
+
+ CDS_SaveInt ( szAppName, CMS_DRIVES, pHW->wDrives );
+ CDS_SaveInt ( szAppName, CMS_SLOT, pHW->wSlot );
+
+ CDS_SaveHexInt ( szAppName, CMS_TARGETS, (DWORD)pHW->wTargets );
+ CDS_SaveHexInt ( szAppName, CMS_ADDR, pHW->ulAddr );
+ CDS_SaveHexInt ( szAppName, CMS_IRQ, pHW->ulIRQ );
+ CDS_SaveHexInt ( szAppName, CMS_DMA, pHW->ulDMA );
+
+} /* end CDS_SaveHardwareConfig() */
+
+
+/******************************************************************************
+
+ Name: CDS_SaveDebugConfig ()
+
+ Description: Saves config data structure to private profile file.
+
+ Returns:
+
+******************************************************************************/
+
+VOID CDS_SaveDebugConfig ()
+
+{
+ CDS_WriteDebugFlag ( &PermCDS );
+ CDS_WriteDebugToFile ( &PermCDS );
+ CDS_WriteDebugToWindow ( &PermCDS );
+ CDS_WriteDebugWindowShowAll ( &PermCDS );
+ CDS_WriteDebugWindowNumLines ( &PermCDS );
+ CDS_WriteDebugFileName ( &PermCDS );
+ CDS_WritePollFrequency ( &PermCDS );
+
+} /* end CDS_SaveDebugConfig() */
+
+
+/******************************************************************************
+
+ Name: CDS_SaveBEConfig ()
+
+ Description: Saves config data structure to private profile file.
+
+ Returns:
+
+******************************************************************************/
+
+VOID CDS_SaveBEConfig ()
+
+{
+ CDS_PTR pCDS = CDS_GetPerm ();
+
+// CDS_WriteSpecialWord ( pCDS );
+ CDS_WriteMaxTapeBuffers ( pCDS );
+ CDS_WriteTFLBuffSize ( pCDS );
+ CDS_WriteMaxBufferSize ( pCDS );
+ CDS_WriteSkipOpenFiles ( pCDS );
+ CDS_WriteBackupFilesInUse ( pCDS );
+ CDS_WriteAFPSupport ( pCDS );
+ CDS_WriteExtendedDateSupport ( pCDS );
+
+ CDS_WriteHiddenFlag ( pCDS );
+ CDS_WriteSpecialFlag ( pCDS );
+ CDS_WriteSetArchiveFlag ( pCDS );
+ CDS_WriteProcEmptyFlag ( pCDS );
+ CDS_WriteExistFlag ( pCDS );
+ CDS_WritePromptFlag ( pCDS );
+ CDS_WriteNetNum ( pCDS );
+ CDS_WriteSortBSD ( pCDS );
+
+ CDS_WriteRemoteDriveBackup ( pCDS );
+ CDS_WriteFastFileRestore ( pCDS );
+ CDS_WriteWriteFormat ( pCDS );
+ CDS_WriteNRLDosVector ( pCDS );
+
+ CDS_WriteConfiguredMachineType ( pCDS );
+ CDS_WriteProcessSytronECCFlag ( pCDS );
+
+ CDS_WriteOTCLevel ( pCDS );
+
+} /* end CDS_SaveBEConfig() */
+
+
+//note: this function MUST return int since CW_USEDEFAULT is defined in NT
+// as 0x80000000!!!
+
+INT CDS_GetToken (
+
+WORD wType,
+LPSTR szValue )
+
+{
+ LPSTR lpHold;
+
+ lpHold = (LPSTR) strtok ( (LPSTR)szValue, (LPSTR)CDS_TOKENS);
+
+ switch ( wType ) {
+
+ case TOKEN_WINSIZE:
+
+ if (lpHold != NULL) {
+ return atoi(lpHold);
+ }
+ else {
+ return CW_USEDEFAULT;
+ }
+
+ break;
+
+ case TOKEN_WINSHOW:
+
+ if (lpHold != NULL) {
+ return atoi(lpHold);
+ }
+ else {
+ return WM_MIN;
+ }
+
+ break;
+
+ case TOKEN_WINSLIDER:
+
+ if (lpHold != NULL) {
+ return atoi(lpHold);
+ }
+ else {
+ return WM_SLIDERUNKNOWN;
+ }
+
+ break;
+
+ default:
+
+ return 0;
+ break;
+ }
+
+
+} /* end CDS_GetToken() */
+
+
+VOID CDS_SaveWinSize (
+
+LPSTR szName,
+HWND hWnd )
+
+{
+ CHAR szTokens[MAX_UI_RESOURCE_SIZE];
+ INT nSize;
+ WINDOWPLACEMENT dsWPDoc;
+
+ dsWPDoc.length = sizeof ( dsWPDoc );
+
+ if ( ! GetWindowPlacement ( hWnd, &dsWPDoc ) ) {
+ return;
+ }
+
+ if ( WM_IsMaximized ( hWnd ) ) {
+ nSize = WM_MAX;
+ }
+ else {
+ nSize = 0;
+ }
+
+ sprintf ( szTokens,
+ TEXT("%d, %d, %d, %d, %d, %d"),
+ dsWPDoc.rcNormalPosition.left,
+ dsWPDoc.rcNormalPosition.top,
+ dsWPDoc.rcNormalPosition.right - dsWPDoc.rcNormalPosition.left,
+ dsWPDoc.rcNormalPosition.bottom - dsWPDoc.rcNormalPosition.top,
+ nSize,
+ 0
+ );
+
+ CDS_WriteWindowSize ( szName, szTokens );
+
+} /* end CDS_SaveWinSize() */
+
+
+VOID CDS_SaveDlgWinSize (
+
+LPSTR szName,
+HWND hWnd )
+
+{
+ CHAR szTokens[MAX_UI_RESOURCE_SIZE];
+ INT nSize;
+ WINDOWPLACEMENT dsWPDoc;
+ RECT rcFrame;
+ INT x;
+ INT y;
+
+
+ dsWPDoc.length = sizeof ( dsWPDoc );
+
+ if ( ! GetWindowPlacement ( hWnd, &dsWPDoc ) ) {
+ return;
+ }
+
+ GetWindowRect ( ghWndFrame, &rcFrame );
+
+ x = dsWPDoc.rcNormalPosition.left - rcFrame.left;
+ y = dsWPDoc.rcNormalPosition.top - rcFrame.top;
+
+ nSize = 0;
+
+ sprintf ( szTokens,
+ TEXT("%d, %d, %d, %d, %d, %d"),
+ x,
+ y,
+ dsWPDoc.rcNormalPosition.right - dsWPDoc.rcNormalPosition.left,
+ dsWPDoc.rcNormalPosition.bottom - dsWPDoc.rcNormalPosition.top,
+ nSize,
+ 0
+ );
+
+ CDS_WriteWindowSize ( szName, szTokens );
+
+} /* end CDS_SaveDlgWinSize() */
+
+
+VOID CDS_SaveMDIWinSize (
+
+LPSTR szName,
+HWND hWnd )
+
+{
+ CHAR szTokens[MAX_UI_RESOURCE_SIZE];
+ INT nSize;
+ PDS_WMINFO pWinInfo;
+ WINDOWPLACEMENT dsWPDoc;
+
+ if ( ! IsWindow ( hWnd ) ) {
+ return;
+ }
+
+ pWinInfo = WM_GetInfoPtr ( hWnd );
+
+ dsWPDoc.length = sizeof ( dsWPDoc );
+
+ if ( ! GetWindowPlacement ( hWnd, &dsWPDoc ) ) {
+ return;
+ }
+
+ if ( WM_IsMinimized ( hWnd ) ) {
+ nSize = WM_MIN;
+ }
+ else if ( WM_IsMaximized ( hWnd ) ) {
+ nSize = WM_MAX;
+ }
+ else {
+ nSize = 0;
+ }
+
+ sprintf ( szTokens,
+ TEXT("%d, %d, %d, %d, %d, %d"),
+ dsWPDoc.rcNormalPosition.left,
+ dsWPDoc.rcNormalPosition.top,
+ dsWPDoc.rcNormalPosition.right - dsWPDoc.rcNormalPosition.left,
+ dsWPDoc.rcNormalPosition.bottom - dsWPDoc.rcNormalPosition.top,
+ nSize,
+ WMDS_GetSliderPos ( pWinInfo )
+ );
+
+ CDS_WriteWindowSize ( szName, szTokens );
+
+} /* end CDS_SaveMDIWinSize() */
+
diff --git a/private/utils/ntbackup/src/muiutil.c b/private/utils/ntbackup/src/muiutil.c
new file mode 100644
index 000000000..06768ef17
--- /dev/null
+++ b/private/utils/ntbackup/src/muiutil.c
@@ -0,0 +1,1560 @@
+
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: muiutil.c
+
+ Description: This module contains miscellaneous functions within the
+ MAYNARD USER INTERFACE (MUI) for displaying information.
+
+ This file contains the following functions:
+
+ UI_AnsiLowerChar()
+ UI_AnsiLowerString()
+ UI_AnsiUpperChar()
+ UI_AnsiUpperString()
+ UI_CountLetters()
+ UI_CurrentDate()
+ UI_CurrentDateLeadingZero()
+ UI_CurrentTime()
+ UI_CurrentTimeLeadingZero()
+ UI_GetDateFormat()
+ UI_GetDateSeparator()
+ UI_GetTimeSeparator()
+ UI_InitDate()
+ UI_InitIntl()
+ UI_InitThousandsChar()
+ UI_InitTime()
+ UI_IntToDate()
+ UI_IntToTime()
+ UI_LongToDate()
+ UI_LongToTime()
+ UI_MakeDateString()
+ UI_MakeTimeString()
+ UI_MakeShortTimeString()
+ UI_UseLeadCentury()
+ UI_UseLeadDays()
+ UI_UseLeadHours()
+ UI_UseLeadMonth()
+ UI_Use24Hour()
+
+ WM_MultiTask()
+
+ $Log: G:\UI\LOGFILES\MUIUTIL.C_V $
+
+ Rev 1.25.1.3 18 Jan 1994 14:39:06 MIKEP
+fix buffers that were too small for mark
+
+ Rev 1.25.1.2 10 Jan 1994 13:08:06 MikeP
+fix leading zero on dates > 2000
+
+ Rev 1.25.1.1 10 Jan 1994 11:52:58 MikeP
+fix epr 168 about dates greater than 1999
+
+ Rev 1.25.1.0 04 Nov 1993 15:22:56 STEVEN
+fixes from Wa
+
+ Rev 1.25 24 Jun 1993 17:07:10 CARLS
+added UI_CurrentDateLeadingZero and UI_CurrentTimeLeadingZero routines
+
+ Rev 1.24 23 Jun 1993 09:20:04 GLENN
+Added code to break when WM_COMMAND messages are found - to prevent reentrancy problems.
+
+ Rev 1.23 27 Apr 1993 19:10:32 GLENN
+Removed dead code from the multitask -- just for fun.
+
+ Rev 1.22 29 Dec 1992 13:33:28 DAVEV
+unicode fixes (3)
+
+ Rev 1.21 05 Nov 1992 17:10:06 DAVEV
+fix ts
+
+ Rev 1.19 07 Oct 1992 14:13:26 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.18 04 Oct 1992 19:39:18 DAVEV
+Unicode Awk pass
+
+ Rev 1.17 22 Sep 1992 10:33:32 GLENN
+Added FULL BACKUP, INCREMENTAL BACKUP, DIFFERENTIAL BACKUP, FM REPLACE, FM APPEND
+
+ Rev 1.16 10 Jun 1992 12:46:00 JOHNWT
+removed autojob creation for msoft
+
+ Rev 1.15 14 May 1992 18:00:22 MIKEP
+nt pass 2
+
+ Rev 1.14 09 Mar 1992 16:58:58 CHUCKB
+Fixed InitDate().
+
+ Rev 1.13 13 Feb 1992 13:35:56 CHUCKB
+Fixed am string length constants.
+
+ Rev 1.12 12 Feb 1992 18:03:56 CHUCKB
+Got ValidatePath working, then removed it.
+
+ Rev 1.11 10 Feb 1992 10:36:04 CHUCKB
+Added InitIntl and moved BuildNumeralWithCommas.
+
+ Rev 1.10 22 Jan 1992 10:26:00 CHUCKB
+Fixed make time string functions for 12:00 a.m.
+
+ Rev 1.9 10 Jan 1992 11:20:06 DAVEV
+16/32 bit port-2nd pass
+
+ Rev 1.8 03 Jan 1992 17:47:10 CHUCKB
+Added UI_MakeShortDateString.
+
+ Rev 1.7 13 Dec 1991 09:44:50 ROBG
+Corrected #define LAUNCHER logic in WM_MultiTask.
+
+ Rev 1.6 13 Dec 1991 09:24:42 ROBG
+Made multitask to support the launcher as well.
+
+ Rev 1.5 10 Dec 1991 10:05:20 CHUCKB
+Put in makeautojobs function.
+
+ Rev 1.4 05 Dec 1991 10:44:12 CHUCKB
+Put in LongToDate/Time.
+
+ Rev 1.3 04 Dec 1991 18:41:52 GLENN
+Converted parse routines to init routines which are called at init time and
+WIN.INI change time. Removed calls to the old parse routines, unnecessary
+due to init routines.
+
+ Rev 1.2 03 Dec 1991 14:52:10 CHUCKB
+Fixed IntToDate and IntToTime.
+
+ Rev 1.1 27 Nov 1991 11:15:14 CHUCKB
+Put in default international values
+
+ Rev 1.0 20 Nov 1991 19:30:48 SYSTEM
+Initial revision.
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+// PRIVATE DEFINITIONS
+
+#define TEMP_STR_SIZE 100
+
+// module-wide flags and other variables for international date/time functions
+
+static CHAR mwcDateSeparator;
+static INT mwnOrder;
+static BOOL mwfLeadMonth;
+static BOOL mwfLeadDay;
+static BOOL mwfLeadYear;
+static BOOL mwfLeadTime;
+static CHAR mwcTimeSeparator;
+static BOOL mwfIs24Hour;
+static BOOL mwfIsTimePrefix;
+static CHAR mwszAMString[TEMP_STR_SIZE];
+static CHAR mwszPMString[TEMP_STR_SIZE];
+static CHAR mwThousandBuffer[TEMP_STR_SIZE]; // these two are used to find the character
+static CHAR mwDefThousandBuffer[TEMP_STR_SIZE]; // that separates thousands numerals
+static BOOL mwfMultitasking;
+
+// FUNCTIONS
+
+/******************************************************************************
+
+ Name: UI_AnsiLowerChar()
+
+ Description: This function changes a character to lower case.
+
+ Returns: The converted character.
+
+******************************************************************************/
+
+INT16 UI_AnsiLowerChar (
+
+INT16 nChar ) // I - character to be converted
+
+{
+ return (INT16)(DWORD) AnsiLower( (LPSTR)(LONG)(UCHAR)(nChar) );
+
+} /* end UI_AnsiLowerChar() */
+
+/******************************************************************************
+
+ Name: UI_AnsiLowerString()
+
+ Description: This function changes a null terminated string to lower
+ case.
+
+ Returns: The converted string.
+
+******************************************************************************/
+
+CHAR_PTR UI_AnsiLowerString (
+
+CHAR_PTR pString ) // I - character to be converted
+
+{
+ return AnsiLower ( (LPSTR)pString );
+
+} /* end UI_AnsiLowerChar() */
+
+
+/******************************************************************************
+
+ Name: UI_AnsiUpperChar()
+
+ Description: This function changes a character to upper case.
+
+ Returns: The converted character.
+
+******************************************************************************/
+
+INT16 UI_AnsiUpperChar (
+
+INT16 nChar ) // I - character to be converted
+
+{
+ return (INT16)(DWORD) AnsiUpper( (LPSTR)(LONG)(UCHAR)(nChar) );
+
+} /* end UI_AnsiUpperChar() */
+
+/******************************************************************************
+
+ Name: UI_AnsiUpperString()
+
+ Description: This function changes a null terminated string to upper
+ case.
+
+ Returns: The converted string.
+
+******************************************************************************/
+
+CHAR_PTR UI_AnsiUpperString (
+
+CHAR_PTR pString ) // I - character to be converted
+
+{
+ return AnsiUpper ( (LPSTR)pString );
+
+} /* end UI_AnsiUpperChar() */
+
+/*****************************************************************************
+
+ Name: UI_BuildNumeralWithCommas
+
+ Description: Builds a numeral with commas
+
+ Returns: VOID
+
+*****************************************************************************/
+
+VOID UI_BuildNumeralWithCommas(
+
+CHAR_PTR numeral ) // I/O - buffer in which to build the numeral
+
+{
+ CHAR_PTR n;
+ CHAR_PTR w;
+ INT comma_index;
+ CHAR work_area[ UI_MAX_NUMERAL_LENGTH ];
+
+ n = numeral;
+ w = work_area;
+
+ /* make sure comma_index is not negative */
+ if( ( comma_index = ( strlen( numeral ) % UI_COMMA_SPACING ) - 1 ) < 0 ) {
+ comma_index += UI_COMMA_SPACING;
+ }
+
+ /* first char must not be comma */
+ *w++ = *n++;
+
+ while( *n ) {
+ if( comma_index-- ) {
+ *w++ = *n++;
+ }
+ else {
+ if ( mwThousandBuffer[0] ) {
+ *w++ = mwThousandBuffer[0];
+ }
+ comma_index = UI_COMMA_SPACING;
+ }
+ }
+
+ *w = TEXT('\0');
+
+ strcpy( numeral, work_area );
+
+ return;
+}
+
+/***************************************************
+
+ Name: UI_CountLetters
+
+ Description: counts the number of consecutive occurences
+ of a given letter in a given string;
+ the letter is specified by its index in the string
+
+ Modified: 11-13-91
+
+ Returns: INT the number of consecutive occurrences of the letter
+ at the given position of the given string starting
+ at the given position
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+INT UI_CountLetters ( CHAR string[], INT index )
+
+{
+ INT nCount = 1; // the character at least matches itself
+
+ while ( string[index] == string[index+1] ) {
+
+ index++;
+ nCount++;
+ }
+
+ return ( nCount );
+}
+
+/***************************************************
+
+ Name: UI_CurrentDate
+
+ Description: Generates a string with the current date in
+ the current international format.
+
+ Modified: 11-11-91
+
+ Returns: void
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+VOID UI_CurrentDate ( LPSTR szDateBuffer )
+
+{
+ SYSTEMTIME loc_time ;
+
+ GetLocalTime( &loc_time ) ;
+
+ UI_MakeDateString ( szDateBuffer, loc_time.wMonth,
+ loc_time.wDay, loc_time.wYear -1900 );
+
+ return;
+
+}
+/***************************************************
+
+ Name: UI_CurrentDateLeadingZero
+
+ Description: Generates a string with the current date in
+ the current international format, forcing
+ leading zeros.
+
+ Modified: 6-24-93
+
+ Returns: void
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+VOID UI_CurrentDateLeadingZero ( LPSTR szDateBuffer )
+
+{
+ BOOL fLeadMonthSave;
+ BOOL fLeadDaySave;
+ LONG lCurTime;
+
+ // get the current date, and send that to UI_LongToDate
+
+ //save the global flags
+ fLeadMonthSave = mwfLeadMonth ;
+ fLeadDaySave = mwfLeadDay ;
+
+ mwfLeadMonth = TRUE ;
+ mwfLeadDay = TRUE ;
+
+ time ( &lCurTime );
+
+ UI_LongToDate( szDateBuffer, lCurTime );
+
+ //restore the global flags
+ mwfLeadMonth = fLeadMonthSave ;
+ mwfLeadDay = fLeadDaySave ;
+
+ return;
+}
+
+/***************************************************
+
+ Name: UI_CurrentTime
+
+ Description: Puts the current time in the input string in int'l format
+
+ Modified: 11-11-91
+
+ Returns: void; returns value through input argument
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+VOID UI_CurrentTime ( LPSTR szTimeBuffer )
+
+{
+ LONG lCurTime;
+
+ // get the current time, and send that to UI_LongToTime
+
+ time ( &lCurTime );
+
+ UI_LongToTime( szTimeBuffer, lCurTime );
+ return;
+}
+
+/***************************************************
+
+ Name: UI_CurrentTimeLeadingZero
+
+ Description: Puts the current time in the input string in int'l format
+
+ Modified: 11-11-91
+
+ Returns: void; returns value through input argument
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+VOID UI_CurrentTimeLeadingZero ( LPSTR szTimeBuffer )
+
+{
+ BOOL fLeadTimeSave;
+ LONG lCurTime;
+
+ // get the current time, and send that to UI_LongToTime
+
+ //save the global flags
+ fLeadTimeSave = mwfLeadTime ;
+
+ mwfLeadTime = TRUE ;
+
+ time ( &lCurTime );
+
+ UI_LongToTime( szTimeBuffer, lCurTime );
+
+ //restore the global flags
+ mwfLeadTime = fLeadTimeSave ;
+
+ return;
+}
+
+/***************************************************
+
+ Name: UI_GetAMString
+
+ Description: Returns the string that goes after am times
+
+ Modified: 11-18-91
+
+ Returns: void
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+VOID UI_GetAMString ( LPSTR lpszBuffer )
+
+{
+ lstrcpy ( lpszBuffer, mwszAMString );
+}
+
+/***************************************************
+
+ Name: UI_GetDateFormat
+
+ Description: Tells what the format for dates is
+
+ Modified: 11-11-91
+
+ Returns: INT YMD, MDY, or DMY
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+INT UI_GetDateFormat ( )
+
+{
+ return mwnOrder;
+}
+
+/***************************************************
+
+ Name: UI_GetDateSeparator
+
+ Description: Tells what the date field separator character is
+
+ Modified: 11-11-91
+
+ Returns: CHAR the character that separates the fields of dates
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+CHAR UI_GetDateSeparator ( )
+
+{
+ return mwcDateSeparator;
+}
+
+/***************************************************
+
+ Name: UI_GetPMString
+
+ Description: Returns the string that goes after pm times
+
+ Modified: 11-18-91
+
+ Returns: void
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+VOID UI_GetPMString ( LPSTR lpszBuffer )
+
+{
+ lstrcpy ( lpszBuffer, mwszPMString );
+}
+
+/***************************************************
+
+ Name: UI_GetTimeSeparator
+
+ Description: Tells what the time field separator character is
+
+ Modified: 11-11-91
+
+ Returns: CHAR the character that separates the fields of times
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+CHAR UI_GetTimeSeparator ( )
+
+{
+ return mwcTimeSeparator;
+}
+
+/***************************************************
+
+ Name: UI_InitDate
+
+ Description: Parses the short date key field in win.ini
+ determines the date format, separator character,
+ whether or not the month and day have leading 0's,
+ and whether or not the year has a leading century
+
+ Modified:
+
+ Returns: void
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+VOID UI_InitDate ( )
+
+{
+ CHAR szDateBuffer[TEMP_STR_SIZE];
+ CHAR szDefaultBuffer[TEMP_STR_SIZE];
+ INT nTemp, nTemp2;
+
+ mwnOrder = -1;
+
+ RSM_StringCopy( IDS_DEFAULT_SHORTDATE, szDefaultBuffer, TEMP_STR_SIZE );
+
+ GetProfileString ( TEXT("intl"), TEXT("sShortDate"), szDefaultBuffer, szDateBuffer, TEMP_STR_SIZE );
+
+ // the year field will tell us the separator,
+ // because it must have either 2 or 4 y's;
+ // there cannot be 3 or 5 y's in a valid year
+ // the year is either the first or last field in the string
+
+ if ( szDateBuffer[0] == TEXT('y') ) {
+
+ // this is ymd format, so the y's are first, followed by the separator
+
+ mwnOrder = YMD;
+ mwfLeadYear = FALSE;
+ nTemp = 1;
+
+ while ( szDateBuffer[nTemp] == TEXT('y') ) {
+
+ nTemp++;
+ }
+
+ mwcDateSeparator = szDateBuffer[nTemp];
+
+ } else {
+
+ // the year is not the first field, so it is the last field
+ // count backward from the end to find the separator
+
+ nTemp = lstrlen ( szDateBuffer ) - 1;
+ nTemp2 = 0;
+ while ( szDateBuffer[nTemp] == TEXT('y') ) {
+
+ nTemp--;
+ nTemp2++;
+ }
+
+ mwcDateSeparator = szDateBuffer[nTemp];
+ }
+
+ mwfLeadYear = ( nTemp > 2 ); // nTemp has the number of y's
+
+ //
+ // after the separator has been identified, parse the d's and M's
+ //
+
+ if ( szDateBuffer[0] == TEXT('d') ) { // the order is DMY
+
+ mwnOrder = DMY;
+
+ // days are followed by months, so count d's first
+
+ nTemp = UI_CountLetters ( szDateBuffer, 0 );
+ mwfLeadDay = ( ( nTemp == 3 ) ||
+ ( ( mwcDateSeparator != TEXT('d') ) &&
+ ( nTemp > 1 ) ) );
+
+ // followed by either 1 or 2 M's, followed by one separator,
+ // if the separator is not a 'd', skip the separator
+
+ if ( mwcDateSeparator != TEXT('d') ) {
+
+ nTemp++;
+ }
+
+ mwfLeadMonth = ( UI_CountLetters ( szDateBuffer, nTemp ) > 1 );
+
+ // skip the M and the separator; if there is an extra M, skip it too
+
+ nTemp +=2;
+ if ( mwfLeadMonth ) {
+
+ nTemp++;
+ }
+
+ // followed by either 2 or 4 y's
+
+ mwfLeadYear = ( UI_CountLetters ( szDateBuffer, nTemp ) > 2 );
+
+ } else {
+
+ // see what the order is: if it isn't YMD it is MDY
+
+ if ( mwnOrder != YMD ) {
+
+ mwnOrder = MDY;
+
+ nTemp = UI_CountLetters ( szDateBuffer, 0 );
+ mwfLeadMonth = ( ( nTemp == 3 ) ||
+ ( ( mwcDateSeparator != TEXT('M') ) &&
+ ( nTemp > 1 ) ) );
+
+ // followed by either 1 or 2 d's, followed by one separator
+
+ if ( mwcDateSeparator != TEXT('d') ) {
+
+ nTemp++;
+ }
+
+ mwfLeadDay = ( UI_CountLetters ( szDateBuffer, nTemp ) > 1 );
+
+ // now find the y's
+
+ while ( ( szDateBuffer[nTemp] != TEXT('y') ) &&
+ ( nTemp < lstrlen ( szDateBuffer ) ) ) {
+
+ nTemp++;
+ }
+
+ // followed by either 2 or 4 y's
+
+ mwfLeadYear = ( UI_CountLetters ( szDateBuffer, nTemp ) > 2 );
+
+ } else { // the order is YMD
+
+ // find the first M
+
+ nTemp = 3;
+ if ( mwfLeadYear ) {
+
+ nTemp += 2;
+ }
+
+ nTemp2 = UI_CountLetters ( szDateBuffer, nTemp );
+ mwfLeadMonth = ( ( nTemp2 == 3 ) ||
+ ( ( mwcDateSeparator != TEXT('M') ) &&
+ ( nTemp2 > 1 ) ) );
+
+ nTemp += nTemp2;
+
+ // followed by a separator and either 1 or 2 d's
+
+ if ( mwcDateSeparator != TEXT('M') ) {
+
+ nTemp++;
+ }
+
+ mwfLeadDay = ( UI_CountLetters ( szDateBuffer, nTemp ) > 1 );
+ }
+ }
+ return;
+}
+
+/*****************************************************************************
+
+ Name: UI_InitThousandsChar
+
+ Description: Gets the character that separates every three digits in
+ numbers with more than three digits. In the U.S., this
+ character is a comma; in other countries, it may vary.
+
+ Returns: VOID
+
+*****************************************************************************/
+
+VOID UI_InitThousandsChar( )
+
+{
+ RSM_StringCopy( IDS_DEFAULT_THOUSAND, mwDefThousandBuffer, TEMP_STR_SIZE );
+ GetProfileString( TEXT("intl"), TEXT("sThousand"), mwDefThousandBuffer, mwThousandBuffer, TEMP_STR_SIZE );
+}
+
+/***************************************************
+
+ Name: UI_InitTime
+
+ Description: Determines important international things about the
+ Windows time settings.
+
+ Modified:
+
+ Returns:
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+VOID UI_InitTime ( )
+
+{
+ // This guy is much easier to parse than the bloody date
+
+ CHAR szBuffer[TEMP_STR_SIZE];
+ CHAR szDefaultBuffer[TEMP_STR_SIZE];
+
+ // Should we display using 24 hour (military) time.
+
+ mwfIs24Hour = (BOOL) GetProfileInt( TEXT("intl"), TEXT("iTime"), 0 );
+
+ if ( GetLocaleInfo( LOCALE_USER_DEFAULT, LOCALE_STIMEFORMAT, szBuffer, TEMP_STR_SIZE*sizeof(CHAR) ) ) {
+ if ( *szBuffer == 'H') {
+ mwfIs24Hour = (BOOL)TRUE ;
+ }
+ }
+
+ if ( IS_JAPAN() ) {
+ /* v-hirot July.12.1993 for New Prefix */
+ mwfIsTimePrefix = (BOOL) GetProfileInt( TEXT("intl"), TEXT("iTimePrefix"), 0 );
+ }
+
+ // Get the AM string.
+
+ RSM_StringCopy( IDS_DEFAULT_1159, szDefaultBuffer, TEMP_STR_SIZE );
+ GetProfileString( TEXT("intl"), TEXT("s1159"), szDefaultBuffer, mwszAMString, TEMP_STR_SIZE );
+
+ // Get the PM string.
+
+ RSM_StringCopy( IDS_DEFAULT_2359, szDefaultBuffer, TEMP_STR_SIZE );
+ GetProfileString( TEXT("intl"), TEXT("s2359"), szDefaultBuffer, mwszPMString, TEMP_STR_SIZE );
+
+ // Should we use leading zeros for hours.
+
+ mwfLeadTime = (BOOL) GetProfileInt( TEXT("intl"), TEXT("iTLZero"), 0 );
+
+ // Get the separator. Really, it's only 1 character, but we'll make the
+ // buffer bigger anyway.
+
+ RSM_StringCopy( IDS_DEFAULT_TIME, szDefaultBuffer, TEMP_STR_SIZE );
+ GetProfileString( TEXT("intl"), TEXT("sTime"), szDefaultBuffer, szBuffer, TEMP_STR_SIZE );
+ mwcTimeSeparator = szBuffer[0];
+
+ return;
+}
+
+/***************************************************
+
+ Name: UI_InitIntl
+
+ Description: Calls InitDate, InitTime, and InitThousandsChar to make
+ life easier for frmproc.c when WIN.INI gets changed
+
+ Modified: 2-7-92
+
+ Returns: void
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+VOID UI_InitIntl( )
+{
+ UI_InitDate( );
+ UI_InitTime( );
+ UI_InitThousandsChar( );
+
+ return;
+}
+
+/***************************************************
+
+ Name: UI_IntToDate
+
+ Description: converts an integer to a date string
+
+ Modified: 11-19-91
+
+ Returns: void
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+VOID UI_IntToDate ( LPSTR lpszDateBuffer,
+ UINT16 uInValue )
+
+{
+ // from Duncan's DOS book
+ // 00h-04h day of month 1-31
+ // 05h-08h month 1-12
+ // 09h-0fh year from 1980
+
+ INT nMonth;
+ INT nDay;
+ INT nYear;
+
+ nDay = (INT)(uInValue & 0x001f);
+ uInValue >>= 5;
+ nMonth =(INT)(uInValue & 0x000f);
+ uInValue >>= 4;
+ nYear = (INT)(( uInValue & 0x007f ) + 80);
+
+ UI_MakeDateString( lpszDateBuffer, nMonth, nDay, nYear );
+
+ return;
+}
+
+/***************************************************
+
+ Name: UI_IntToTime
+
+ Description: converts an integer to a time string
+
+ Modified: 11-19-91
+
+ Returns: void
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+VOID UI_IntToTime ( LPSTR lpszTimeBuffer,
+ UINT16 uInValue )
+
+{
+ // from Duncan's DOS book
+ // 00h-04h binary number of 2-second increments 0-29
+ // 05h-0ah binary number of minutes
+ // 0bh-0fh binary number of hours
+
+ INT nHour;
+ INT nMinute;
+ INT nSecond;
+
+ nSecond = (INT)(uInValue & 0x001f);
+ uInValue >>= 5;
+ nMinute = (INT)(uInValue & 0x003f);
+ uInValue >>= 6;
+ nHour = (INT)(uInValue & 0x001f);
+
+ UI_MakeTimeString( lpszTimeBuffer, nHour, nMinute, nSecond );
+
+ return;
+}
+
+/***************************************************
+
+ Name: UI_LongToDate
+
+ Description: converts a long to a string with the date in it
+
+ Modified: 11-19-91
+
+ Returns: void
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+VOID UI_LongToDate ( LPSTR lpszDateBuffer,
+ LONG lInValue )
+
+{
+ struct tm *dsDate;
+
+ dsDate = localtime ( &lInValue );
+
+ UI_MakeDateString ( lpszDateBuffer, (dsDate->tm_mon) + 1,
+ dsDate->tm_mday, dsDate->tm_year );
+ return;
+}
+
+/***************************************************
+
+ Name: UI_LongToTime
+
+ Description: converts a long to a string with the time in it
+
+ Modified: 11-19-91
+
+ Returns: void
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+VOID UI_LongToTime ( LPSTR lpszTimeBuffer,
+ LONG lInValue )
+
+{
+ struct tm *dsTime;
+
+ dsTime = localtime ( &lInValue );
+
+ UI_MakeTimeString ( lpszTimeBuffer, dsTime->tm_hour,
+ dsTime->tm_min, dsTime->tm_sec );
+ return;
+}
+
+/***************************************************
+
+ Name: UI_MakeAutoJobs
+
+ Description: If the skipped/verify scripts exist and their jobs don't,
+ this function causes those jobs to be created.
+
+ Modified: 12-9-91
+
+ Returns: void
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+VOID UI_MakeAutoJobs ( INT nOperType )
+
+{
+#if !defined ( OEM_MSOFT ) //unsupported feature
+
+ JOB_MakeAutoJob ( IDS_SKIPPED_JOBNAME, IDS_SKIPPED_JOBNAME, JOBBACKUP, BSD_BACKUP_NORMAL, TRUE, TRUE );
+ JOB_MakeAutoJob ( IDS_VERIFY_JOBNAME, IDS_VERIFY_JOBNAME, JOBBACKUP, BSD_BACKUP_NORMAL, TRUE, TRUE );
+
+ JOB_MakeAutoJob ( IDS_FULLBACKUP_JOBNAME, IDS_VLMSTARTUPBKS, JOBBACKUP, BSD_BACKUP_NORMAL, FALSE, TRUE );
+ JOB_MakeAutoJob ( IDS_INCBACKUP_JOBNAME, IDS_VLMSTARTUPBKS, JOBBACKUP, BSD_BACKUP_INCREMENTAL, FALSE, TRUE );
+ JOB_MakeAutoJob ( IDS_DIFFBACKUP_JOBNAME, IDS_VLMSTARTUPBKS, JOBBACKUP, BSD_BACKUP_DIFFERENTIAL, FALSE, TRUE );
+
+ JOB_MakeAutoJob ( IDS_FM_APPEND_JOBNAME, IDS_FM_SCRIPTNAME, JOBBACKUP, BSD_BACKUP_NORMAL, TRUE, TRUE );
+ JOB_MakeAutoJob ( IDS_FM_REPLACE_JOBNAME, IDS_FM_SCRIPTNAME, JOBBACKUP, BSD_BACKUP_NORMAL, FALSE, TRUE );
+
+#endif //!defined ( OEM_MSOFT ) //unsupported feature
+}
+
+/***************************************************
+
+ Name: UI_MakeDateString
+
+ Description: Makes a string by putting the input date into
+ the current international format
+
+ Modified: 11-11-91
+
+ Returns: void
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+VOID UI_MakeDateString ( LPSTR lpszDateBuffer,// O - string with date in int'l form
+ INT nMonth, // I - month being passed in
+ INT nDay, // I - day/date being passed in
+ INT nYear ) // I - year being passed in
+
+{
+ CHAR szProfile[100]; // profile string for wsprintf statements
+
+ // now put the correct values in the return string
+ // first, set up the profile string for the wsprintf;
+ // then just put the values in
+
+ if ( mwfLeadYear ) {
+ nYear += 1900;
+ }
+ else {
+ nYear %= 100;
+ }
+
+
+
+ switch ( mwnOrder ) {
+
+ case YMD : // print the year, then month, then date
+
+ wsprintf ( szProfile, TEXT("%s%c%s%c%s"),
+ TEXT("%02d"), mwcDateSeparator,
+ ( mwfLeadMonth ? TEXT("%02d") : TEXT("%d") ), mwcDateSeparator,
+ ( mwfLeadDay ? TEXT("%02d") : TEXT("%d") ) );
+
+ wsprintf ( lpszDateBuffer, szProfile,
+ nYear, nMonth, nDay );
+
+ break;
+
+ case MDY : // print the month, then day, then year
+
+ wsprintf ( szProfile, TEXT("%s%c%s%c%s"),
+ ( mwfLeadMonth ? TEXT("%02d") : TEXT("%d") ), mwcDateSeparator,
+ ( mwfLeadDay ? TEXT("%02d") : TEXT("%d") ), mwcDateSeparator,
+ TEXT("%02d") );
+
+ wsprintf ( lpszDateBuffer, szProfile, nMonth, nDay, nYear );
+
+ break;
+
+ case DMY : // print the day, then month, then year
+
+ wsprintf ( szProfile, TEXT("%s%c%s%c%s"),
+ ( mwfLeadDay ? TEXT("%02d") : TEXT("%d") ), mwcDateSeparator,
+ ( mwfLeadMonth ? TEXT("%02d") : TEXT("%d") ), mwcDateSeparator,
+ TEXT("%02d") );
+
+ wsprintf ( lpszDateBuffer, szProfile, nDay, nMonth, nYear );
+
+ break;
+
+ default :
+
+ break;
+ }
+ return;
+}
+
+/***************************************************
+
+ Name: UI_MakeTimeString
+
+ Description: Makes a string by putting the input time into
+ the current international format
+
+ Modified: 11-11-91
+
+ Returns: void
+
+ Notes:
+
+ See also: UI_MakeDateString [in this file]
+
+*****************************************************/
+
+VOID UI_MakeTimeString (
+
+LPSTR lpszTimeBuffer, // O - pointer to user's time buffer
+INT nHours, // I - number of hours
+INT nMinutes, // I - number of minutes
+INT nSeconds ) // I - number of seconds
+
+{
+ CHAR szProfile[100];
+ INT nTempHours;
+
+ nTempHours = nHours;
+
+ if ( !mwfIs24Hour ) {
+
+ if ( nHours == 0 ) {
+
+ nTempHours = 12;
+
+ } else if ( nHours > 12 ) {
+
+ nTempHours -= 12;
+ }
+ }
+
+ // minutes and seconds always have leading 0's; hours might not
+
+ if ( IS_JAPAN() ) {
+ /* v-hirot July.12.1993 for New Prefix */
+ if( mwfIsTimePrefix ){
+ if ( mwfIs24Hour ) {
+ wsprintf ( szProfile,
+ TEXT("%s%c%%02d%c%%02d"),
+ ( mwfLeadTime ? TEXT("%02d") : TEXT("%d") ),
+ mwcTimeSeparator,
+ mwcTimeSeparator );
+
+ wsprintf ( lpszTimeBuffer,
+ szProfile,
+ nTempHours,
+ nMinutes,
+ nSeconds );
+ } else {
+ wsprintf ( szProfile,
+ TEXT("%%s %s%c%%02d%c%%02d"),
+ ( mwfLeadTime ? TEXT("%02d") : TEXT("%d") ),
+ mwcTimeSeparator,
+ mwcTimeSeparator );
+
+ wsprintf ( lpszTimeBuffer,
+ szProfile,
+ ( (nHours < 12 ) ? mwszAMString : mwszPMString ),
+ nTempHours,
+ nMinutes,
+ nSeconds );
+ }
+ }
+ else{
+
+ if ( mwfIs24Hour ) {
+ wsprintf ( szProfile,
+ TEXT("%s%c%%02d%c%%02d"),
+ ( mwfLeadTime ? TEXT("%02d") : TEXT("%d") ),
+ mwcTimeSeparator,
+ mwcTimeSeparator );
+
+ wsprintf ( lpszTimeBuffer,
+ szProfile,
+ nTempHours,
+ nMinutes,
+ nSeconds ) ;
+ } else {
+ wsprintf ( szProfile,
+ TEXT("%s%c%%02d%c%%02d %%s"),
+ ( mwfLeadTime ? TEXT("%02d") : TEXT("%d") ),
+ mwcTimeSeparator,
+ mwcTimeSeparator );
+
+ wsprintf ( lpszTimeBuffer,
+ szProfile,
+ nTempHours,
+ nMinutes,
+ nSeconds,
+ ( (nHours < 12 ) ? mwszAMString : mwszPMString ) );
+ }
+ }
+ } else {
+ if ( !mwfIs24Hour ) {
+ wsprintf ( szProfile,
+ TEXT("%s%c%%02d%c%%02d %%s"),
+ ( mwfLeadTime ? TEXT("%02d") : TEXT("%d") ),
+ mwcTimeSeparator,
+ mwcTimeSeparator );
+
+ wsprintf ( lpszTimeBuffer,
+ szProfile,
+ nTempHours,
+ nMinutes,
+ nSeconds,
+ ( (nHours < 12 ) ? mwszAMString : mwszPMString ) );
+ } else {
+ wsprintf ( szProfile,
+ TEXT("%s%c%%02d%c%%02d"),
+ ( mwfLeadTime ? TEXT("%02d") : TEXT("%d") ),
+ mwcTimeSeparator,
+ mwcTimeSeparator );
+
+ wsprintf ( lpszTimeBuffer,
+ szProfile,
+ nTempHours,
+ nMinutes,
+ nSeconds,
+ TEXT("") );
+ }
+ }
+
+}
+
+/***************************************************
+
+ Name: UI_MakeShortTimeString
+
+ Description: Makes a string by putting the input time into
+ the current international format
+
+ Modified: 11-11-91
+
+ Returns: void
+
+ Notes:
+
+ See also: UI_MakeDateString [in this file]
+
+*****************************************************/
+
+VOID UI_MakeShortTimeString (
+
+LPSTR lpszTimeBuffer, // O - pointer to user's time buffer
+INT nHours, // I - number of hours
+INT nMinutes ) // I - number of minutes
+
+{
+ CHAR szProfile[100];
+ INT nTempHours;
+
+ nTempHours = nHours;
+
+ if ( !mwfIs24Hour ) {
+
+ if ( nHours == 0 ) {
+
+ nTempHours = 12;
+
+ } else if ( nHours > 12 ) {
+
+ nTempHours -= 12;
+ }
+ }
+
+ // minutes and seconds always have leading 0's; hours might not
+
+ if ( IS_JAPAN() ) {
+ /* v-hirot July.12.1993 for New Prefix */
+ if( mwfIsTimePrefix ){
+ if ( mwfIs24Hour ) {
+ wsprintf ( szProfile,
+ TEXT("%s%c%%02d"),
+ ( mwfLeadTime ? TEXT("%02d") : TEXT("%d") ),
+ mwcTimeSeparator );
+
+ wsprintf ( lpszTimeBuffer,
+ szProfile,
+ nTempHours,
+ nMinutes );
+ } else {
+ wsprintf ( szProfile,
+ TEXT("%%s %s%c%%02d"),
+ ( mwfLeadTime ? TEXT("%02d") : TEXT("%d") ),
+ mwcTimeSeparator );
+
+ wsprintf ( lpszTimeBuffer,
+ szProfile,
+ ( ( nHours < 12 ) ? mwszAMString : mwszPMString ),
+ nTempHours,
+ nMinutes );
+ }
+ }
+ else{
+ if ( mwfIs24Hour ) {
+ wsprintf ( szProfile,
+ TEXT("%s%c%%02d"),
+ ( mwfLeadTime ? TEXT("%02d") : TEXT("%d") ),
+ mwcTimeSeparator );
+
+ wsprintf ( lpszTimeBuffer,
+ szProfile,
+ nTempHours,
+ nMinutes ) ;
+ } else {
+
+ wsprintf ( szProfile,
+ TEXT("%s%c%%02d %%s"),
+ ( mwfLeadTime ? TEXT("%02d") : TEXT("%d") ),
+ mwcTimeSeparator );
+
+ wsprintf ( lpszTimeBuffer,
+ szProfile,
+ nTempHours,
+ nMinutes,
+ ( ( nHours < 12 ) ? mwszAMString : mwszPMString ) );
+ }
+ }
+ } else {
+ if ( mwfIs24Hour ) {
+ wsprintf ( szProfile,
+ TEXT("%s%c%%02d"),
+ ( mwfLeadTime ? TEXT("%02d") : TEXT("%d") ),
+ mwcTimeSeparator );
+
+ wsprintf ( lpszTimeBuffer,
+ szProfile,
+ nTempHours,
+ nMinutes ) ;
+ } else {
+ wsprintf ( szProfile,
+ TEXT("%s%c%%02d %%s"),
+ ( mwfLeadTime ? TEXT("%02d") : TEXT("%d") ),
+ mwcTimeSeparator );
+
+ wsprintf ( lpszTimeBuffer,
+ szProfile,
+ nTempHours,
+ nMinutes,
+ ( ( nHours < 12 ) ? mwszAMString : mwszPMString ) );
+ }
+ }
+
+
+}
+
+/***************************************************
+
+ Name: UI_UseLeadCentury()
+
+ Description: Tells caller if leading century is used on year field
+
+ Modified: 11-11-91
+
+ Returns: BOOL TRUE if leading century is used
+ FALSE otherwise
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+BOOL UI_UseLeadCentury ( )
+{
+ return ( mwfLeadYear );
+}
+
+/***************************************************
+
+ Name: UI_UseLeadDays()
+
+ Description:
+
+ Modified: 11-11-91
+
+ Returns: BOOL TRUE if leading zero is used on day fields
+ FALSE otherwise
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+BOOL UI_UseLeadDays ( )
+{
+ return ( mwfLeadDay );
+}
+
+/***************************************************
+
+ Name: UI_UseLeadMonth()
+
+ Description:
+
+ Modified: 11-11-91
+
+ Returns: BOOL TRUE if leading zero is used on month fields
+ FALSE otherwise
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+BOOL UI_UseLeadMonth ( )
+{
+ return ( mwfLeadMonth );
+}
+
+/***************************************************
+
+ Name: UI_UseLeadTime ()
+
+ Description:
+
+ Modified: 11-11-91
+
+ Returns: BOOL TRUE if leading zeroes are used on time fields
+ FALSE otherwise
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+BOOL UI_UseLeadTime ( )
+{
+ return ( mwfLeadTime );
+}
+
+/***************************************************
+
+ Name: UI_Use24Hour()
+
+ Description:
+
+ Modified: 11-11-91
+
+ Returns: BOOL TRUE if 24-hour time is used
+ FALSE otherwise
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+BOOL UI_Use24Hour ( )
+{
+ return ( mwfIs24Hour );
+}
+
+/******************************************************************************
+
+ Name: WM_MultiTask()
+
+ Description: This function basically gives up the CPU until there are
+ no more messages to be processed by other applications.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID WM_MultiTask ( VOID )
+
+{
+ MSG msg;
+ BOOL fContinue = TRUE;
+
+ mwfMultitasking = FALSE;
+
+ // Make sure that we don't allow recursion to this routine.
+
+ if ( mwfMultitasking ) {
+ return;
+ }
+
+ mwfMultitasking = TRUE;
+
+ while ( fContinue && PeekMessage ( &msg, (HWND)NULL, 0, 0, PM_REMOVE ) ) {
+
+ if ( msg.message == WM_COMMAND ) {
+ fContinue = FALSE;
+ }
+
+ // DIALOG MESSAGE STUFF WILL GO HERE IF NEEDED.
+
+ if ( ( ! ghWndMDIClient || ! TranslateMDISysAccel ( ghWndMDIClient, &msg ) ) &&
+ ( ! ghAccel || ! TranslateAccelerator ( ghWndFrame, ghAccel, &msg ) ) &&
+ ( ! ghModelessDialog || ! IsDialogMessage ( ghModelessDialog, &msg ) ) ) {
+
+ TranslateMessage ( &msg );
+ DispatchMessage ( &msg );
+ }
+ }
+
+ mwfMultitasking = FALSE;
+
+} /* end WM_MultiTask() */
+
+
+BOOL WM_IsMultiTaskBusy ( VOID )
+
+{
+ return mwfMultitasking;
+
+} /* end WM_IsMultiTaskBusy() */
+
+BOOLEAN IS_JAPAN( void )
+{
+ static INT lastAnswer = -1 ;
+ CHAR szMachNLCode[4];
+
+ if ( lastAnswer == -1 ) {
+ // Get this machines NL code.
+
+ GetProfileString ( TEXT("intl"), TEXT("sLanguage"), TEXT("ENU"), szMachNLCode, sizeof( szMachNLCode ) );
+
+ // The third character is unimportant to us, just the first two.
+
+ szMachNLCode[2] = 0;
+
+ CharUpper ( szMachNLCode );
+
+ // Scan for the matching NL code(s).
+
+ if ( !memcmp( TEXT("JP"), szMachNLCode, 2*sizeof(CHAR) ) ) {
+ lastAnswer = 1 ;
+ return TRUE ;
+ }
+ lastAnswer = 0 ;
+ return FALSE ;
+ }
+ return (BOOLEAN)lastAnswer ;
+}
diff --git a/private/utils/ntbackup/src/myn40otc.c b/private/utils/ntbackup/src/myn40otc.c
new file mode 100644
index 000000000..db7559c93
--- /dev/null
+++ b/private/utils/ntbackup/src/myn40otc.c
@@ -0,0 +1,315 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-92
+
+
+ Name: myn40otc.c
+
+ Description: This module contains the Maynard 4.0 translator entry
+ points for accessing On Tape Catalogs.
+
+ $Log: T:/LOGFILES/MYN40OTC.C_V $
+
+ Rev 1.7 22 Jun 1993 10:53:08 GREGG
+Added API to change the catalog directory path.
+
+ Rev 1.6 10 Jun 1993 20:22:54 GREGG
+Set Fatal status in channel on TFLE return from GetNext routines.
+
+ Rev 1.5 09 Jun 1993 19:53:06 GREGG
+Fix for EPR #0525 - Accept GEN_ERR_EOM return on space to EOD for Wangtek bug.
+
+ Rev 1.4 30 Jan 1993 11:44:04 DON
+Removed compiler warnings
+
+ Rev 1.3 26 Jan 1993 01:30:30 GREGG
+Added Fast Append functionality.
+
+ Rev 1.2 24 Nov 1992 18:16:20 GREGG
+Updates to match MTF document.
+
+ Rev 1.1 23 Nov 1992 10:04:32 GREGG
+Changes for path in stream.
+
+ Rev 1.0 09 Nov 1992 14:28:14 GREGG
+Initial revision.
+
+**/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "stdtypes.h"
+#include "lwprotos.h"
+#include "mayn40.h"
+#include "f40proto.h"
+#include "lw_data.h"
+#include "tfl_err.h"
+
+/* Device Driver InterFace Headers */
+#include "drvinf.h"
+#include "generr.h"
+#include "genfuncs.h"
+#include "dil.h"
+#include "dddefs.h"
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_LoadSM
+
+ Description: This function loads the last (and best) Set Map of the
+ current tape into a temporary file on disk and sets it
+ up for F40_GetNextSMEntry.
+
+ Returns: INT - TFLE_xxx or TF_xxx as appropriate. Also,
+ 'complete' is set to TRUE if this is the last Set Map
+ in the family.
+
+ Notes: If 'get_best' is TRUE, TF_NEED_NEW_TAPE is returned if
+ this is not the last tape in the family.
+
+**/
+
+INT F40_LoadSM(
+ CHANNEL_PTR channel,
+ BOOLEAN_PTR complete,
+ BOOLEAN get_best )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)(channel->fmt_env) ;
+ INT ret_val = TFLE_NO_ERR ;
+ INT16 drv_hdl = channel->cur_drv->drv_hdl ;
+ RET_BUF myret ;
+ BOOLEAN sm_exists ;
+
+ msassert( cur_env->otc_sm_fptr == NULL ) ;
+
+ if( cur_env->otc_buff == NULL ) {
+ /* This can only happen if a realloc call in OTC_GenDirEntry
+ failed during a previous backup.
+ */
+ if( ( cur_env->otc_buff = calloc( F40_INIT_OTC_BUFF_SIZE, 1 ) ) == NULL ) {
+ return( TFLE_NO_MEMORY ) ;
+ }
+ cur_env->otc_buff_size = F40_INIT_OTC_BUFF_SIZE ;
+ }
+
+ if( cur_env->cur_otc_level == TCL_NONE ) {
+ ret_val = TF_NO_SM_FOR_FAMILY ;
+
+ } else if( ( ret_val = OTC_OpenSM( cur_env, FALSE, &sm_exists ) ) == TFLE_NO_ERR ) {
+ DRIVER_CALL( drv_hdl, TpReadEndSet( drv_hdl, (INT16)0, (INT16)TO_EOD ),
+ myret, GEN_NO_ERR, GEN_ERR_EOM, (VOID)0 )
+ if( ( ret_val = OTC_GetPrevSM( channel, channel->cur_buff, get_best, TRUE ) ) != TFLE_NO_ERR ) {
+ OTC_Close( cur_env, OTC_CLOSE_SM, TRUE ) ;
+ } else {
+ /* we need to skip the SM header */
+ if( fseek( cur_env->otc_sm_fptr, (long)sizeof( MTF_SM_HDR ),
+ SEEK_SET ) != 0 ) {
+ ret_val = TFLE_OTC_FAILURE ;
+ }
+ }
+ *complete = !( cur_env->sm_at_eom ) ;
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_LoadFDD
+
+ Description: This function loads the File/Directory Detail at the PBA
+ specified in channel->ui_tpos into a temporary file on
+ disk and sets it up for F40_GetNextFDDEntry.
+
+ Returns: INT - TFLE_xxx or TF_xxx as appropriate.
+
+ Notes: None.
+
+**/
+
+INT F40_LoadFDD(
+ CHANNEL_PTR channel )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ INT ret_val = TFLE_NO_ERR ;
+
+ if( cur_env->otc_buff == NULL ) {
+ /* This can only happen if a realloc call in OTC_GenDirEntry
+ failed during a previous backup.
+ */
+ if( ( cur_env->otc_buff = calloc( F40_INIT_OTC_BUFF_SIZE, 1 ) ) == NULL ) {
+ return( TFLE_NO_MEMORY ) ;
+ }
+ cur_env->otc_buff_size = F40_INIT_OTC_BUFF_SIZE ;
+ }
+
+ if( !cur_env->fdd_continuing ) {
+ ret_val = OTC_OpenFDD( cur_env ) ;
+ }
+
+ if( ret_val == TFLE_NO_ERR ) {
+ if( ( ret_val = OTC_FDDtoFile( channel ) ) != TFLE_NO_ERR ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ }
+ }
+
+ /* We may have hit EOM reading the FDD */
+ if( IsPosBitSet( channel->cur_drv, AT_EOM ) ) {
+ ret_val = TF_NEED_NEW_TAPE ;
+ }
+
+ if( ret_val == TFLE_NO_ERR ) {
+
+ /* Initialize the OTC buffer. Setting remaining to 0 will force
+ OTC_GetFDDType to read in the first buffer full of FDD data
+ the first time he is called.
+ */
+ cur_env->otc_buff_ptr = cur_env->otc_buff ;
+ cur_env->otc_buff_remaining = 0 ;
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_GetNextSMEntry
+
+ Description: This function gets an entry from the Set Map currently
+ loaded on disk and translates it into a DBLK stored in
+ the channel cur_dblk.
+
+ Returns: INT - TFLE_xxx or TF_xxx as appropriate.
+
+ Notes: None.
+
+**/
+
+INT F40_GetNextSMEntry(
+ CHANNEL_PTR channel )
+{
+ INT ret_val = TFLE_NO_ERR ;
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+
+ msassert( cur_env->otc_sm_fptr != NULL ) ;
+ if( ( ret_val = OTC_RdSSET( channel ) ) == TF_NO_MORE_ENTRIES ) {
+ OTC_Close( cur_env, OTC_CLOSE_SM, TRUE ) ;
+ }
+
+ if( IsTFLE( ret_val ) ) {
+ SetChannelStatus( channel, CH_FATAL_ERR ) ;
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_GetNextFDDEntry
+
+ Description: This function gets an entry from the File/Directory
+ Detail currently loaded on disk and translates it into
+ a DBLK stored in the channel cur_dblk.
+
+ Returns: INT - TFLE_xxx or TF_xxx as appropriate.
+
+ Notes: Continuation entries and Volume entries are skipped
+ because the upper layers don't currently want to see
+ them.
+
+ When the end entry is encountered, the message
+ TF_NO_MORE_ENTRIES is returned.
+
+**/
+
+INT F40_GetNextFDDEntry(
+ CHANNEL_PTR channel )
+{
+ UINT16 blk_type = FDD_UNKNOWN_BLK ;
+ INT ret_val = TFLE_NO_ERR ;
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+
+ msassert( cur_env->otc_fdd_fptr != NULL ) ;
+ while( ret_val == TFLE_NO_ERR && blk_type == FDD_UNKNOWN_BLK ) {
+ if( ( ret_val = OTC_GetFDDType( channel, &blk_type ) ) == TFLE_NO_ERR ) {
+ if( blk_type == FDD_VOL_BLK ) {
+ if( ( ret_val = OTC_SkipFDDEntry( channel ) ) == TFLE_NO_ERR ) {
+ if( ( ret_val = OTC_SkipFDDContEntries( channel ) ) == TFLE_NO_ERR ) {
+ ret_val = OTC_GetFDDType( channel, &blk_type ) ;
+ }
+ }
+ }
+ if( ret_val == TFLE_NO_ERR ) {
+
+ switch( blk_type ) {
+
+ case FDD_DIR_BLK :
+ ret_val = OTC_RdDIR( channel ) ;
+ break ;
+
+ case FDD_FILE_BLK :
+ ret_val = OTC_RdFILE( channel ) ;
+ break ;
+
+ case FDD_END_BLK :
+ ret_val = TF_NO_MORE_ENTRIES ;
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ break ;
+
+ case FDD_UNKNOWN_BLK :
+ ret_val = OTC_SkipFDDEntry( channel ) ;
+ break ;
+
+ default :
+ msassert( FALSE ) ;
+ ret_val = TFLE_TAPE_INCONSISTENCY ;
+ break ;
+ }
+ }
+ }
+ }
+
+ if( IsTFLE( ret_val ) ) {
+ SetChannelStatus( channel, CH_FATAL_ERR ) ;
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: F40_CloseCatalogs
+
+ Description: This function is just an API shell for deleteing the
+ temporary OTC files.
+
+ Returns: Nothing
+
+ Notes:
+
+**/
+
+VOID F40_CloseCatalogs( VOID_PTR env_ptr )
+{
+ OTC_Close( (F40_ENV_PTR)env_ptr, OTC_CLOSE_ALL, TRUE ) ;
+}
+
diff --git a/private/utils/ntbackup/src/nostrad.rc b/private/utils/ntbackup/src/nostrad.rc
new file mode 100644
index 000000000..43ecf39bc
--- /dev/null
+++ b/private/utils/ntbackup/src/nostrad.rc
@@ -0,0 +1,89 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+DAVEV
+
+ Name: nostrad.rc
+
+ Description: This file contains the headers and resource files to build
+ the 32-bit Windows/NT GUI Project Resource File created
+ under OEM contract for Microsoft Corporation.
+
+ This file was initially created by copying and modifying
+ WntrPark.Rc which is used for the standard Windows
+ Maynstream product.
+
+ File Names: All files included by this this file are named
+ using the following conventions:
+
+ - If the file was previously created for use with
+ the standard Windows Maynstream product, the
+ original file name not changed.
+
+ - If the file was created by copying and modifying
+ a file previously created for the Windows
+ Maynstream product, the file name is appended
+ with 'OM' and the remaining portion of the
+ file name is truncated if necessary. OM stands
+ for OEM Microsoft. Example:
+ ACCKEYS.H becomes OMACCKEY.H
+
+ - All new files created specifically for this project
+ are given a name starting with 'OM'.
+ Eg.: OMNEW.RC or OM_NEW.RC, etc.
+
+ $Log: G:/UI/LOGFILES/NOSTRAD.RCV $
+
+ Rev 1.4 16 Nov 1993 19:34:28 STEVEN
+ add support for filever
+
+ Rev 1.3 18 Dec 1992 11:25:20 chrish
+ Consolidated dialogs, now using one common file to hold
+ all the dialogs ... "dialogs.rc"
+
+ Rev 1.2 24 Aug 1992 15:21:16 DAVEV
+ include bkuevent.rc for NT Event Logging
+
+ Rev 1.1 18 Mar 1992 14:47:00 DAVEV
+
+
+ Rev 1.0 03 Mar 1992 12:23:00 DAVEV
+ Initial revision.
+
+
+******************************************************************************/
+
+#define OEM_MSOFT 1
+
+#include <windows.h>
+
+#include "ss_gui.h"
+#include "cursors.h"
+#include "icons.h"
+#include "bitmaps.h"
+#include "ommenus.h" // modified from menus.h
+#include "keys.h"
+#include "omstring.h" // modified from strings.h
+#include "dialogs.h"
+#include "eng_msg.h"
+#include "eng_err.h"
+#include "eng_dbug.h"
+
+#include "proddefs.h" // THIS FILE MUST BE TRANSLATED!!!!!
+
+#ifdef OEM_EMS
+#include "ctl3d.h"
+#endif
+
+#include "cursors.rc"
+#include "icons.rc"
+#include "bitmaps.rc"
+#include "ommenus.rc" // modified from menus.rc
+#include "omacckey.rc" // modified from acckeys.rc
+#include "omstring.rc" // modified from strings.rc
+#include "dialogs.rc"
+#include "version.rc" // Conner keeps deleting this.
+
+#ifdef OS_WIN32
+# include "bkuevent.rc" // include messages for NT Event Logging
+#endif
diff --git a/private/utils/ntbackup/src/nothing.c b/private/utils/ntbackup/src/nothing.c
new file mode 100644
index 000000000..ba64be408
--- /dev/null
+++ b/private/utils/ntbackup/src/nothing.c
@@ -0,0 +1,34 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: nothing.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+
+ $Log: L:/LOGFILES/NOTHING.C_V $
+
+ Rev 1.1 18 Aug 1992 10:05:34 BURT
+fix warnings
+
+ Rev 1.0 09 May 1991 13:34:34 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+
+/* $end$ include list */
+
+#include "stdtypes.h"
+
+
+UINT16 nothing( VOID )
+{
+
+ return SUCCESS ;
+
+}
+
diff --git a/private/utils/ntbackup/src/ntbackup.c b/private/utils/ntbackup/src/ntbackup.c
new file mode 100644
index 000000000..45f5bbf62
--- /dev/null
+++ b/private/utils/ntbackup/src/ntbackup.c
@@ -0,0 +1,309 @@
+
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: backup.c
+
+ Description: This file contains the WinMain() for the GUI Windows
+ Application. This is the 'C' main() for Windows.
+
+ $Log: J:/UI/LOGFILES/BACKUP.C_V $
+
+ Rev 1.22.1.12 11 Feb 1994 16:38:36 GREGG
+Removed old command line preprocessor since we call new one in gui.c.
+
+ Rev 1.22.1.11 13 Jan 1994 18:20:20 GREGG
+Mike P's fix so Orcas could use tip of globals.c and globals.h.
+
+ Rev 1.22.1.10 20 Dec 1993 15:13:40 GLENN
+Fixed multiple instance 20 second delay for OEM_MSOFT.
+
+ Rev 1.22.1.9 16 Dec 1993 13:19:02 BARRY
+Placed TEXT around string literal
+
+ Rev 1.22.1.8 03 Dec 1993 13:33:00 GREGG
+Removed TEXT macro from around string defines which already have TEXT macro.
+
+ Rev 1.22.1.7 18 Oct 1993 18:47:54 STEVEN
+fixed unicode bo-bo
+
+ Rev 1.22.1.6 26 May 1993 17:49:32 CHUCKB
+Changed sleep to Sleep to get rid of a warning.
+
+ Rev 1.22.1.5 26 May 1993 15:29:54 STEVEN
+fix another text()
+
+ Rev 1.22.1.4 26 May 1993 14:41:20 STEVEN
+fix typo
+
+ Rev 1.22.1.3 26 May 1993 12:05:24 STEVEN
+added text macro for version constants
+
+ Rev 1.22.1.2 14 May 1993 16:02:48 GLENN
+Returning msg.wParam for return code.
+
+ Rev 1.22.1.1 10 May 1993 09:11:46 CHUCKB
+Adjusted sleep time in checking for previous instance.
+
+ Rev 1.22.1.0 07 May 1993 16:43:12 CHUCKB
+Put in sleep and check for frame window to make sure we can come back up
+after an abend.
+
+ Rev 1.22 19 Apr 1993 15:26:12 GLENN
+Changed return code back to 0. Return code is passed in quit message.
+
+ Rev 1.21 09 Apr 1993 14:05:30 GLENN
+Added global return code. Beautified code.
+
+ Rev 1.20 23 Mar 1993 13:11:18 DARRYLP
+Once again... Missed a few changes.
+
+ Rev 1.18 22 Mar 1993 14:49:20 DARRYLP
+Altered the way we check for previous instances to make it "Cleaner".
+This should fix EPR#22 for Cayman.
+
+ Rev 1.17 22 Mar 1993 13:38:06 DARRYLP
+Altered startup code to check not only for a file mapping, but to check
+and see if our Frame window is already up.
+
+ Rev 1.16 15 Mar 1993 16:57:12 DARRYLP
+Removed unwanted string functions from my last fix.
+
+ Rev 1.15 15 Mar 1993 15:58:54 DARRYLP
+Brought inactive window to foreground when re-started.
+
+ Rev 1.13 15 Mar 1993 14:53:54 DARRYLP
+Only Restore for EPR31 if Iconic.
+
+ Rev 1.12 15 Mar 1993 14:44:28 chrish
+Fix for command line, oops on /z command.
+
+ Rev 1.11 15 Mar 1993 14:43:04 DARRYLP
+Restore minimized application when an attempt to execute a
+subsequent instance occurs. Fix for EPR #31.
+
+ Rev 1.10 10 Mar 1993 14:15:58 chrish
+Made a change for CAYMAN NT in the AlterTheCmdLineParam routine.
+
+ Rev 1.9 09 Mar 1993 14:27:02 chrish
+Added fix for command line argument passed.
+
+ Rev 1.8 25 Feb 1993 12:16:36 CHUCKB
+Fixed check for duplicate instances.
+
+ Rev 1.7 07 Dec 1992 15:06:38 STEVEN
+updates from msoft
+
+ Rev 1.6 20 Nov 1992 14:54:50 DAVEV
+fix cmd line processing for NT
+
+ Rev 1.5 18 Nov 1992 15:47:30 MIKEP
+fix malloc changes
+
+ Rev 1.4 17 Nov 1992 21:24:30 DAVEV
+unicode fixes
+
+ Rev 1.3 04 Oct 1992 19:32:22 DAVEV
+Unicode Awk pass
+
+ Rev 1.2 18 Aug 1992 17:49:42 DAVEV
+Chgs for switch to prev inst as per Microsoft
+
+ Rev 1.1 30 Jul 1992 10:04:12 davev
+Chgs for switching to prev app on 2nd instance
+
+ Rev 1.0 21 May 1992 15:09:02 MIKEP
+Initial revision.
+
+
+******************************************************************************/
+
+#include "all.h"
+
+// GLOBALS - APPLICATION SPECIFIC
+
+CHAR * gszAppName = APPLICATIONNAME;
+CHAR * gszExeVer = APP_EXEVER;
+CHAR * gszResVer = APP_RESVER;
+CHAR * gszEngRel = APP_ENGREL;
+
+static HANDLE mhMap;
+
+// FUNCTIONS
+
+#if defined ( OS_WIN32 ) // special feature
+
+static BOOL IsAlreadyRunning( void ) ;
+
+#endif //defined ( OS_WIN32 ) // special feature
+
+
+/******************************************************************************
+
+ Name: WinMain()
+
+ Description: This function is the WinMain() for the GUI Windows
+ Application. IT IS CALLED DIRECTLY BY WINDOWS ONLY.
+ This is the equivalent of a 'C' main() for Windows.
+
+ Returns: NULL or 0 if successful, otherwise ! NULL.
+
+******************************************************************************/
+
+int WINAPI WinMain(
+
+HINSTANCE hInstance, // I - handle of application instance
+HINSTANCE hPrevInstance, // I - handle of any previous instance
+char * lpCmdLine, // I - long pointer to the command line
+int nCmdShow ) // I - how to show the window
+
+{
+ MSG msg;
+ LPSTR pszCmdLine = NULL;
+
+ ghInst = hInstance; // set the global instance handle for the app.
+
+ // Allow only one instance of the application. If this is compiled
+ // under the large memory model, there can only be one instance.
+ // If this is the only instance of the application, initialize.
+
+ // OS_WIN32: Since hPrevInstance is always NULL in NT, it isn't
+ // very informative. IsAlreadyRunning uses shared memory
+ // to check for other instances.
+
+# if defined ( OS_WIN32 ) // special feature
+ {
+
+ pszCmdLine = GetCommandLine (); // chs:03-05-93
+
+ // cycle past the executable name to the first parameter if
+ // there is one...
+
+ while ( *pszCmdLine && isspace ( *pszCmdLine ) ) ++pszCmdLine; // chs:03-05-93
+ while ( *pszCmdLine && !isspace ( *pszCmdLine ) ) ++pszCmdLine; // chs:03-05-93
+ while ( *pszCmdLine && isspace ( *pszCmdLine ) ) ++pszCmdLine; // chs:03-05-93
+
+ // New routine - If IsAlreadyRunning() returns back that we have a prior
+ // instance, we double check to verify before handling the situation.
+
+ if ( IsAlreadyRunning () ) {
+
+ // Get the window handle and Show it restored.
+
+ HWND hWndMain;
+
+ hWndMain = FindWindow ( WMCLASS_FRAME, NULL );
+
+ if ( IsWindow ( hWndMain ) ) {
+
+ if ( IsIconic ( hWndMain ) != FALSE ) {
+ ShowWindow ( hWndMain, SW_RESTORE );
+ }
+
+ SetForegroundWindow ( hWndMain );
+ }
+
+ return 0;
+ }
+ }
+# else
+ {
+ pszCmdLine = lpCmdLine; // chs:03-05-93
+ }
+# endif //defined ( OS_WIN32 ) // special feature
+
+ if ( hPrevInstance || GUI_Init ( pszCmdLine, nCmdShow ) ) {
+
+ return 0;
+ }
+
+ // MAIN MESSAGE LOOP
+ // -----------------
+ //
+ // KEYBOARD: If a keyboard message is for the MDI, let the MDI client
+ // take care of it. Otherwise, check to see if it's a normal
+ // accelerator key (like F3 = find next).
+ //
+ // MODELESS DIALOG:
+ //
+ // OTHERS: Just handle the message as usual.
+ //
+
+
+ // Initialize the application.
+
+ PostMessage ( ghWndFrame, WM_INITAPPLICATION, 0, 0L );
+
+
+ while ( GetMessage ( &msg, NULL, 0, 0 ) ) {
+
+ if ( ! TranslateMDISysAccel ( ghWndMDIClient, &msg ) &&
+ ! TranslateAccelerator ( ghWndFrame, ghAccel, &msg ) &&
+ ( ! ghModelessDialog || ! IsDialogMessage ( ghModelessDialog, &msg ) ) ) {
+
+ TranslateMessage ( &msg );
+ DispatchMessage ( &msg );
+ }
+ }
+
+ GUI_Deinit ();
+
+ CloseHandle ( mhMap );
+
+ return msg.wParam;
+
+} /* end WinMain() */
+
+
+#ifdef OS_WIN32 //special feature
+
+// This function uses shared memory to indicate that it is running.
+// If the call fails, that means that an instance of this app. is already
+// running, and this instance should discontinue itself.
+// Return TRUE if another instance already exists; FALSE otherwise.
+
+static BOOL IsAlreadyRunning ( void )
+{
+ INT nLastErr;
+
+ mhMap = CreateFileMapping ( (HANDLE) -1,
+ NULL,
+ PAGE_READONLY,
+ 0,
+ 1,
+ APPLICATIONNAME
+ );
+
+ nLastErr = GetLastError ();
+
+ if ( mhMap && nLastErr == ERROR_ALREADY_EXISTS ) {
+
+ INT nTimer = 30;
+ BOOL fFound = FALSE;
+
+ // Hunt for the existing application frame window for about
+ // 30 seconds max.
+
+ while ( ! fFound && nTimer > 0 ) {
+
+ if ( FindWindow ( WMCLASS_FRAME, NULL ) ) {
+
+ CloseHandle ( mhMap );
+ mhMap = NULL;
+ fFound = TRUE;
+ }
+ else {
+
+ Sleep ( 1000 );
+ nTimer--;
+ }
+ }
+ }
+
+ return ! mhMap;
+}
+
+#endif //OS_WIN32 //special feature
+
diff --git a/private/utils/ntbackup/src/ntfs_tab.c b/private/utils/ntbackup/src/ntfs_tab.c
new file mode 100644
index 000000000..591c16721
--- /dev/null
+++ b/private/utils/ntbackup/src/ntfs_tab.c
@@ -0,0 +1,184 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: ntfs_tab.c
+
+ Description: This file contains the DOS functon table.
+
+
+ $Log: M:/LOGFILES/NTFS_TAB.C_V $
+
+ Rev 1.13 16 Nov 1993 18:13:24 BARRY
+Added init/deinit entry points to set up our static stuff.
+
+ Rev 1.12 29 Sep 1993 20:28:40 GREGG
+Removed the dummy function from the table since it was only there to shut
+the compiler up. The compiler was complaining because the last initializer
+was followed by a comma, so I also removed the last comma, and in some
+cases, added NULLs for new functions which had been added to the bottom of
+the table since the last update.
+Files Modified: GEN_TAB.C, GR_TAB.C, TSA_TAB.C, TS_TAB.C, MNET_TAB.C,
+ SMS_TAB.C, NTFS_TAB.C and FSYS_STR.H
+
+ Rev 1.11 30 Jul 1993 13:18:16 STEVEN
+if dir too deep make new one
+
+ Rev 1.10 29 Jun 1993 16:22:12 BARRY
+Don't GetSpecialDBLKs for Cayman.
+
+ Rev 1.9 27 Jun 1993 14:36:56 MIKEP
+Don't generate special files for cayman.
+
+ Rev 1.8 13 May 1993 21:24:10 BARRY
+For NTBACKUP use real EnumSpecial files; for others, don't enum reg files.
+
+ Rev 1.7 21 Oct 1992 11:53:04 STEVEN
+added SpecialExclude
+
+ Rev 1.6 14 Oct 1992 16:33:22 STEVEN
+fix typos
+
+ Rev 1.5 22 Sep 1992 15:36:20 BARRY
+Got rid of GetTotalSizeDBLK.
+
+ Rev 1.4 03 Sep 1992 17:06:32 STEVEN
+add support for volume name
+
+ Rev 1.3 22 May 1992 16:05:16 STEVEN
+
+
+ Rev 1.2 12 Mar 1992 15:50:08 STEVEN
+64 bit changes
+
+ Rev 1.1 13 Feb 1992 10:44:34 STEVEN
+fix stuff
+
+ Rev 1.0 20 Jan 1992 14:48:20 STEVEN
+Initial revision.
+**/
+/* begin include list */
+#include <windows.h>
+#include "stdtypes.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "ntfs_fs.h"
+#include "gen_fs.h"
+/* $end$ include list */
+
+FUNC_LIST NTFSFuncTab = {
+
+ NTFS_InitFileSys,
+ NTFS_FindDrives,
+ GEN_RemoveDLE,
+ NTFS_DeInitFileSys,
+
+ NTFS_DeviceDispName,
+ NTFS_GetVolName,
+ NTFS_SizeofVolName,
+ GEN_MakePath,
+ NTFS_InitMakeData,
+
+ NTFS_IsBlkComplete,
+ NTFS_CompleteBlk,
+ NTFS_DupBlk,
+ NTFS_ReleaseBlk,
+
+ NTFS_AttachToDLE,
+ NTFS_DetachDLE,
+ NTFS_EndOperationOnDLE,
+
+ NTFS_ProcessDDB,
+ NTFS_GetCurrentDDB,
+ NTFS_GetCurrentPath,
+ NULL,
+ NULL,
+ NULL,
+ NTFS_ChangeDir,
+ NTFS_UpDir,
+
+#ifdef TDEMO
+ NULL,
+ NTFS_OpenObj,
+ NTFS_SeekObj,
+ NTFS_ReadObj,
+ NULL,
+ NULL,
+ NTFS_CloseObj,
+ NULL,
+ NTFS_GetObjInfo,
+ NULL,
+ NTFS_VerObjInfo,
+#else
+ NTFS_CreateObj,
+ NTFS_OpenObj,
+ NTFS_SeekObj,
+ NTFS_ReadObj,
+ NTFS_WriteObj,
+ NTFS_VerObj,
+ NTFS_CloseObj,
+ NTFS_DeleteObj,
+ NTFS_GetObjInfo,
+ NTFS_SetObjInfo,
+ NTFS_VerObjInfo,
+#endif
+
+ NTFS_FindFirst,
+ NTFS_FindNext,
+ NTFS_PushMinDDB,
+ NTFS_PopMinDDB,
+
+#if defined ( OEM_MSOFT )
+ NTFS_GetSpecDBLKS,
+ NTFS_EnumSpecFiles,
+#else
+ DUMMY_GetSpecDBLKS,
+ DUMMY_EnumSpecFiles,
+#endif
+
+ NTFS_ModFnameFDB,
+ NTFS_ModPathDDB,
+ NTFS_GetOSFnameFDB,
+ GEN_GetPartName,
+ NTFS_GetOSPathDDB,
+ NTFS_GetCdateDBLK,
+ NTFS_GetMdateDBLK,
+ NTFS_ModBdateDBLK,
+ NTFS_ModAdateDBLK,
+ NTFS_GetDisplaySizeDBLK,
+ NTFS_ModAttribDBLK,
+ NTFS_GetFileVerFDB,
+ NTFS_SetOwnerId,
+
+ NTFS_GetObjTypeDBLK,
+
+ NTFS_SizeofFname,
+ NTFS_SizeofPath,
+ NTFS_SizeofOSFname,
+ GEN_SizeofPartName, /* IMAGE size of part name */
+ NTFS_SizeofOSPath,
+
+ NTFS_SizeofOSInfo,
+
+ NTFS_GetOS_InfoDBLK,
+ NTFS_GetActualSizeDBLK,
+
+ DUMMY_InitGOS,
+
+ NTFS_CreateFDB,
+ GEN_CreateIDB,
+ NTFS_CreateDDB,
+ NTFS_ChangeIntoDDB,
+
+#if defined ( OEM_MSOFT )
+ NTFS_SpecExcludeObj,
+#else
+ GEN_SpecExcludeObj,
+#endif
+ GEN_SetDataSize,
+ NULL, /* SetObjTypeDBLK, */
+ DUMMY_LogoutDevice,
+ NTFS_FindClose,
+ NULL, /* SizeofDevName */
+ NULL /* GeneratedErrorLog */
+} ;
diff --git a/private/utils/ntbackup/src/ntfslink.c b/private/utils/ntbackup/src/ntfslink.c
new file mode 100644
index 000000000..454b07a7b
--- /dev/null
+++ b/private/utils/ntbackup/src/ntfslink.c
@@ -0,0 +1,476 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: ntfslink.c
+
+ Date Updated: 20-Oct-92
+
+ Description: Miscellaneous convenience functions for support
+ of linked-files in the NT file system.
+
+ $Log: M:/LOGFILES/NTFSLINK.C_V $
+
+ Rev 1.13 24 Nov 1993 14:35:22 BARRY
+Unicode fixes
+
+ Rev 1.12 30 Jul 1993 13:19:36 STEVEN
+if dir too deep make new one
+
+ Rev 1.11 21 Jul 1993 16:09:38 BARRY
+Add case for FS_NOT_FOUND in error routine.
+
+ Rev 1.10 16 Jul 1993 11:59:50 BARRY
+Add FS_NO_MORE to error translation routine.
+
+ Rev 1.9 02 Jun 1993 14:35:22 BARRY
+Was closing wrong handle in NTFS_LinkFileToFDB
+
+ Rev 1.8 12 Mar 1993 13:13:24 STEVEN
+fix warnings
+
+ Rev 1.7 27 Jan 1993 13:50:46 STEVEN
+updates from msoft
+
+ Rev 1.6 15 Jan 1993 13:19:04 BARRY
+added support for new error messages and backup priviladge
+
+ Rev 1.5 24 Nov 1992 11:01:48 BARRY
+Changes to make LINK streams null-impregnated.
+
+ Rev 1.4 17 Nov 1992 22:19:06 DAVEV
+unicode fixes
+
+ Rev 1.3 17 Nov 1992 15:22:58 BARRY
+Updates after testing with Backup APIs.
+
+ Rev 1.2 10 Nov 1992 08:33:14 STEVEN
+fix path name to full_name_ptr
+
+ Rev 1.1 29 Oct 1992 16:49:02 BARRY
+Restore links coded (need Unicode support, though.
+
+ Rev 1.0 21 Oct 1992 19:57:22 BARRY
+Initial revision.
+
+**/
+
+
+#include <windows.h>
+#include <string.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "std_err.h"
+#include "queues.h"
+
+#include "beconfig.h"
+#include "msassert.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "fsys_err.h"
+#include "ntfsdblk.h"
+#include "ntfs_fs.h"
+
+
+static BOOLEAN SearchFunc( INT8_PTR elem, INT8_PTR parm );
+
+typedef struct {
+ DWORD lo;
+ DWORD hi;
+} LINK_ID;
+
+/**/
+/**
+
+ Name: NTFS_SearchLinkQueue()
+
+ Description: Search the linkq for the file specified by its
+ unique id.
+
+ Modified: 20-Oct-92
+
+ Returns: A pointer to the linkq element if found,
+ NULL if not found.
+
+**/
+NTFS_LINK_Q_ELEM_PTR NTFS_SearchLinkQueue( FSYS_HAND fsh,
+ DWORD idHi,
+ DWORD idLo )
+{
+ NTFS_FSYS_RESERVED_PTR res = fsh->reserved.ptr;
+ LINK_ID id;
+
+ id.lo = idLo;
+ id.hi = idHi;
+
+ return (NTFS_LINK_Q_ELEM_PTR)SearchQueue( &res->linkq,
+ SearchFunc,
+ (INT8_PTR)&id,
+ FALSE );
+}
+static BOOLEAN SearchFunc( INT8_PTR elem, INT8_PTR parm )
+{
+ NTFS_LINK_Q_ELEM_PTR linkElem = (NTFS_LINK_Q_ELEM_PTR)elem;
+ LINK_ID *id = (LINK_ID *)parm;
+
+ return id->lo == linkElem->idLo && id->hi == linkElem->idHi;
+}
+
+
+/**/
+/**
+
+ Name: NTFS_EnqueueLinkInfo(()
+
+ Description: Adds a file to the link queue. (Presumably because
+ the file has links and we just backed it up.)
+
+ Modified: 20-Oct-92
+
+ Returns: SUCCESS
+ FAILURE
+
+ Notes:
+
+**/
+INT16 NTFS_EnqueueLinkInfo( FSYS_HAND fsh,
+ DWORD idHi,
+ DWORD idLo,
+ CHAR_PTR path,
+ CHAR_PTR name )
+{
+ NTFS_LINK_Q_ELEM_PTR elem;
+ NTFS_FSYS_RESERVED_PTR res = fsh->reserved.ptr;
+ size_t sizeNeeded;
+ INT16 ret = FAILURE;
+
+ sizeNeeded = sizeof( NTFS_LINK_Q_ELEM );
+
+ /* Need room for path, name, and maybe a separator */
+ sizeNeeded += strsize( path ) + strsize( name ) + sizeof( CHAR );
+
+ if ( (elem = malloc( sizeNeeded )) != NULL )
+ {
+ CHAR_PTR p;
+
+ InitQElem( &elem->q );
+
+ elem->idHi = idHi;
+ elem->idLo = idLo;
+ elem->linkName = (CHAR_PTR)(elem + 1);
+
+ strcpy( elem->linkName, path + 1 );
+ if ( (strlen(elem->linkName) > 0) &&
+ (*(path + strlen( path ) - 1) != TEXT('\\')) )
+ {
+ strcat( elem->linkName, TEXT("\\") );
+ }
+ strcat( elem->linkName, name );
+ elem->linkNameLen = strsize( elem->linkName ) ;
+
+ for ( p = elem->linkName; ( *p ); p++ )
+ {
+ if ( *p == TEXT('\\') )
+ {
+ *p = TEXT('\0');
+ }
+ }
+ EnQueueElem( &res->linkq, &elem->q, FALSE );
+ }
+ return ret;
+}
+
+
+/**/
+/**
+
+ Name: NTFS_LinkFileToFDB()
+
+ Description: Links the FDB in the hand with the original file
+ whose full path was received in WriteObj.
+
+ Modified: 13-Nov-92
+
+ Returns: SUCCESS
+ OUT_OF_MEMORY
+ FS_ACCESS_DENIED if link could not be performed
+
+**/
+INT16 NTFS_LinkFileToFDB( FILE_HAND hand )
+{
+ NTFS_OBJ_HAND_PTR nt_hand = hand->obj_hand.ptr;
+ INT16 ret = FS_ACCESS_DENIED;
+ HANDLE fhand;
+ INT temp_size;
+
+ /* Open the original file.... */
+
+#if defined( UNICODE )
+ if ( hand->dblk->com.string_type == BEC_ANSI_STR )
+ {
+ ACHAR *p = (ACHAR *)nt_hand->linkBuffer;
+ UINT16 i;
+
+ for ( i = 0; (i < (nt_hand->linkNameLen - 1)); i++, p++ )
+ {
+ if ( *p == (ACHAR)'\0' )
+ {
+ *p = (ACHAR)'\\';
+ }
+ }
+ temp_size = nt_hand->linkBufferSize ;
+
+ mapAnsiToUnic( (ACHAR_PTR)nt_hand->linkBuffer,
+ (WCHAR_PTR)nt_hand->linkBuffer,
+ &temp_size );
+
+ nt_hand->linkBufferSize = temp_size ;
+ }
+#else
+ if ( hand->dblk->com.string_type == BEC_UNIC_STR )
+ {
+ WCHAR *p = (WCHAR *)nt_hand->linkBuffer;
+ UINT16 i;
+
+ for ( i = 0; (i < (nt_hand->linkNameLen - 1)); i++, p++ )
+ {
+ if ( *p == (WCHAR)'\0' )
+ {
+ *p = (WCHAR)'\\';
+ }
+ }
+
+ temp_size = nt_hand->linkBufferSize ;
+
+ mapUnicToAnsi( (WCHAR_PTR)nt_hand->linkBuffer,
+ (ACHAR_PTR)nt_hand->linkBuffer,
+ (const ACHAR)'_',
+ &temp_size );
+
+ nt_hand->linkBufferSize = temp_size ;
+ }
+#endif
+ else
+ {
+ CHAR *p = nt_hand->linkBuffer;
+ UINT16 i;
+
+ for ( i = 0; (i < (nt_hand->linkNameLen - 1)/sizeof(CHAR)); i++, p++ )
+ {
+ if ( (*p == TEXT('\0')) && (*(p+1) == TEXT('\0')) ) {
+ break ;
+ }
+
+ if ( *p == TEXT('\0') )
+ {
+ *p = TEXT('\\');
+ }
+ }
+ }
+
+ fhand = CreateFile( nt_hand->linkBuffer,
+ GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS,
+ NULL ) ;
+
+ if ( fhand == INVALID_HANDLE_VALUE ) {
+ return FS_ACCESS_DENIED ;
+
+ } else {
+// if ( fhand != INVALID_HANDLE_VALUE )
+// {
+ NTFS_DBLK_PTR fdb = (NTFS_DBLK_PTR)hand->dblk;
+ BOOLEAN stat;
+ WCHAR_PTR uniPath;
+ size_t pathCharCount;
+ INT uniBufferSize;
+
+ /* Stuff the current path and name as link data to the original. */
+
+ pathCharCount = strsize( DLE_GetDeviceName( hand->fsh->attached_dle ) );
+ pathCharCount += sizeof( CHAR ) ;
+ pathCharCount += strsize( hand->fsh->cur_dir ) ;
+ if ( *(hand->fsh->cur_dir + strlen( hand->fsh->cur_dir) - 1) != TEXT('\\') )
+ {
+ pathCharCount += sizeof( CHAR );
+ }
+ pathCharCount += strsize( fdb->full_name_ptr->name );
+ pathCharCount+= sizeof(CHAR); // Account for NULL
+
+ uniBufferSize = pathCharCount * sizeof(WCHAR) ;
+
+ uniPath = (WCHAR_PTR)malloc( uniBufferSize );
+
+ if ( uniPath == NULL )
+ {
+ ret = OUT_OF_MEMORY;
+ }
+ else
+ {
+ VOID_PTR context = NULL;
+ DWORD sizeout;
+
+ strcpy( (CHAR_PTR)uniPath, DLE_GetDeviceName( hand->fsh->attached_dle ) );
+ strcat( (CHAR_PTR)uniPath, hand->fsh->cur_dir );
+ if ( *(hand->fsh->cur_dir + strlen( hand->fsh->cur_dir) - 1) != TEXT('\\') )
+ {
+ strcat( (CHAR_PTR)uniPath, TEXT("\\") );
+ }
+ strcat( (CHAR_PTR)uniPath, fdb->full_name_ptr->name );
+
+#if !defined( UNICODE )
+ mapAnsiToUnic( (ACHAR_PTR)uniPath, uniPath, &uniBufferSize );
+#endif
+
+ nt_hand->streamHeader.id = BACKUP_LINK;
+ nt_hand->streamHeader.attrib = 0;
+ nt_hand->streamHeader.size_hi = 0;
+ nt_hand->streamHeader.size_lo = uniBufferSize;
+ nt_hand->streamHeader.name_leng = 0;
+
+ stat = BackupWrite( fhand,
+ (LPBYTE)&nt_hand->streamHeader,
+ NT_SIZEOF_NAMELESS_STREAM_HEAD,
+ &sizeout,
+ FALSE,
+ TRUE,
+ &context );
+ if ( stat )
+ {
+ stat = BackupWrite( fhand,
+ (LPBYTE)uniPath,
+ nt_hand->streamHeader.size_lo,
+ &sizeout,
+ FALSE,
+ TRUE,
+ &context );
+ }
+
+ if ( stat )
+ {
+ ret = SUCCESS;
+ }
+
+ /* Need to let Backup API clean up context? */
+
+ if ( context != NULL )
+ {
+ BackupRead( fhand, NULL, 0, NULL, TRUE, FALSE, &context );
+ }
+ free( uniPath );
+ }
+ CloseHandle( fhand );
+ }
+ return ret;
+}
+
+/**/
+/**
+
+ Name: NTFS_TranslateBackupError()
+
+ Description: Translates Win32 errors received from BackupRead
+ or BackupWrite to an FS_XXX error code.
+
+ Modified: 13-Jan-93
+
+ Returns: FS error code mapped from Win32 error.
+
+ Notes: Not intended to map all errors, but primarily those
+ encountered when using BackupRead & BackupWrite.
+
+**/
+INT16 NTFS_TranslateBackupError( DWORD backupError )
+{
+ INT16 ret;
+
+ switch ( backupError )
+ {
+ case ERROR_FILENAME_EXCED_RANGE:
+ ret = FS_PATH_TOO_LONG ;
+ break;
+
+ case ERROR_FILE_NOT_FOUND:
+ ret = FS_NOT_FOUND;
+ break;
+
+ case ERROR_NO_MORE_FILES:
+ case ERROR_NO_MORE_ITEMS:
+ ret = FS_NO_MORE;
+ break;
+
+ case ERROR_ALREADY_EXISTS:
+ case ERROR_DRIVE_LOCKED:
+ case ERROR_WRITE_PROTECT:
+ case ERROR_INVALID_OWNER:
+ ret = FS_ACCESS_DENIED;
+ break;
+
+ case ERROR_DEV_NOT_EXIST:
+ case ERROR_NOT_DOS_DISK:
+ case ERROR_READ_FAULT:
+ case ERROR_WRITE_FAULT:
+ ret = FS_DEVICE_ERROR;
+ break;
+
+ case ERROR_DISK_FULL:
+ case ERROR_HANDLE_DISK_FULL:
+ ret = FS_OUT_OF_SPACE;
+ break;
+
+ case ERROR_DISK_CORRUPT:
+ case ERROR_FILE_CORRUPT:
+ case ERROR_FILE_INVALID:
+ case ERROR_SEEK:
+ ret = FS_OBJECT_CORRUPT;
+ break;
+
+ case ERROR_HANDLE_EOF:
+ ret = FS_EOF_REACHED;
+ break;
+
+ case ERROR_EA_ACCESS_DENIED:
+ case ERROR_EA_FILE_CORRUPT:
+ case ERROR_EA_LIST_INCONSISTENT:
+ case ERROR_EA_TABLE_FULL:
+ case ERROR_INVALID_ACL:
+ case ERROR_EAS_NOT_SUPPORTED:
+ ret = FS_STREAM_CORRUPT;
+ break;
+
+ case ERROR_INVALID_HANDLE:
+ ret = FS_OBJECT_NOT_OPENED;
+ break;
+
+ case ERROR_LOCK_FAILED:
+ case ERROR_LOCK_VIOLATION:
+ ret = FS_UNABLE_TO_LOCK;
+ break;
+
+ case ERROR_NETWORK_BUSY:
+ case ERROR_PATH_BUSY:
+ ret = FS_BUSY;
+ break;
+
+ case ERROR_SHARING_VIOLATION:
+ ret = FS_IN_USE_ERROR;
+ break;
+
+ case NO_ERROR:
+ ret = SUCCESS;
+ break;
+
+ default:
+ ret = FS_ACCESS_DENIED; // CBN -- Need better default
+ break;
+ }
+ return ret;
+}
+
diff --git a/private/utils/ntbackup/src/ntfsregy.c b/private/utils/ntbackup/src/ntfsregy.c
new file mode 100644
index 000000000..fc042ef8f
--- /dev/null
+++ b/private/utils/ntbackup/src/ntfsregy.c
@@ -0,0 +1,1330 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: ntfsregy.c
+
+ Description: This file contains code to work with registry's on
+ NT machines.
+
+ $Log: N:/LOGFILES/NTFSREGY.C_V $
+
+ Rev 1.13.1.11 31 Jan 1994 20:37:26 STEVEN
+remove mac syntax from Reg calls
+
+ Rev 1.13.1.10 07 Jan 1994 19:04:50 STEVEN
+event file check must skip mac stuff
+
+ Rev 1.13.1.9 04 Jan 1994 11:08:14 BARRY
+Fixed lots of Unicode problems
+
+ Rev 1.13.1.8 21 Oct 1993 15:17:44 BARRY
+Now pass device name instead of drive letter to REG_GetRegistryPath
+
+ Rev 1.13.1.7 17 Aug 1993 20:02:22 STEVEN
+fix unicode bug
+
+ Rev 1.13.1.6 16 Aug 1993 18:14:40 BARRY
+Fix warning
+
+ Rev 1.13.1.5 26 Jul 1993 17:03:26 STEVEN
+fixe restore active file with registry
+
+ Rev 1.13.1.4 26 Jul 1993 16:48:14 STEVEN
+fix restore over active files
+
+ Rev 1.13.1.3 17 Jun 1993 12:35:50 STEVEN
+changed OpenRegistry calls to CreateRegistry calls
+
+ Rev 1.13.1.2 03 May 1993 20:42:14 BARRY
+Hacked out the remote registry stuff that doesn't belong.
+
+ Rev 1.13.1.1 02 May 1993 19:49:40 BARRY
+Comparing registry paths with case-sensitive compare can't be done
+any longer since the UI is lowercasing paths before they're sent down.
+
+ Rev 1.13.1.0 19 Apr 1993 11:16:34 BARRY
+Steve's registry fixes from Microsoft.
+
+ Rev 1.13 08 Feb 1993 07:55:08 STEVEN
+fix unable to restore registry problem.
+
+ Rev 1.12 07 Dec 1992 14:16:54 STEVEN
+updates from msoft
+
+ Rev 1.11 23 Nov 1992 09:32:16 STEVEN
+fix support for event log
+
+ Rev 1.10 03 Nov 1992 15:32:52 MIKEP
+call GetLastError to see if privileges ok
+
+ Rev 1.9 28 Oct 1992 12:18:18 STEVEN
+event stuff not needed
+
+ Rev 1.8 26 Oct 1992 10:57:34 MIKEP
+event file stuff
+
+ Rev 1.7 21 Oct 1992 19:40:32 BARRY
+Fixed warning.
+
+ Rev 1.6 20 Oct 1992 17:35:02 STEVEN
+started support for Event files
+
+ Rev 1.5 20 Oct 1992 13:13:40 STEVEN
+made it compile
+
+ Rev 1.4 19 Oct 1992 15:13:02 unknown
+fix REG_Restore
+
+ Rev 1.3 16 Oct 1992 14:59:02 STEVEN
+added support for backing up registry
+
+ Rev 1.2 07 Oct 1992 15:55:20 MIKEP
+fix tabs
+
+ Rev 1.1 07 Oct 1992 15:33:24 STEVEN
+registry.h does not exist
+
+ Rev 1.0 05 Oct 1992 13:34:54 STEVEN
+Initial revision.
+
+**/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <memory.h>
+#include <windows.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "stdwcs.h"
+
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "ntfs_fs.h"
+
+
+// Local Defines
+
+#ifndef IN
+#define IN
+#endif
+
+#ifndef OUT
+#define OUT
+#endif
+
+
+// This should be plenty big for the things it is used for here.
+
+#define REG_BUFF_SIZE 256
+
+// Local function prototypes
+
+INT REG_ChopOffDirectory( CHAR * );
+INT REG_CheckEventListForFile( HKEY, CHAR_PTR, CHAR_PTR );
+INT REG_CheckHiveListForFile( HKEY, CHAR_PTR, CHAR_PTR, INT );
+INT REG_CheckSingleEventForFile( HKEY, CHAR *, CHAR * );
+INT REG_GetPathFromHiveEntry( CHAR *, CHAR *, INT * );
+INT REG_GetRegistryPathFromHiveList( HKEY, CHAR *, INT * );
+INT REG_LocalIsRegistryFile( GENERIC_DLE_PTR, CHAR_PTR, CHAR_PTR, INT );
+INT REG_LocalIsEventFile( GENERIC_DLE_PTR, CHAR_PTR, CHAR_PTR );
+INT REG_RestoreActiveRegistryFile( CHAR *, CHAR *, CHAR * );
+INT REG_SaveActiveRegistryFile( CHAR *, CHAR * );
+
+/**/
+/**
+
+ Name: REG_AssertBackupPrivilege
+
+ Description: Tell the OS that we will be doing backups.
+
+ Modified:
+
+ Returns: SUCCESS/FAILURE
+
+ Declaration:
+**/
+
+INT REG_AssertBackupPrivilege()
+{
+ INT ret_val = SUCCESS;
+ HANDLE ProcessHandle;
+ DWORD DesiredAccess;
+ HANDLE TokenHandle;
+ LUID BackupValue;
+ TOKEN_PRIVILEGES NewState;
+
+
+ // get process handle
+
+ ProcessHandle = GetCurrentProcess();
+
+ // open process token
+
+ DesiredAccess = MAXIMUM_ALLOWED;
+
+ if ( ! OpenProcessToken( ProcessHandle, DesiredAccess, &TokenHandle ) ) {
+ return( FAILURE );
+ }
+
+ // adjust backup token privileges
+
+ if ( ! LookupPrivilegeValue( NULL, TEXT("SeBackupPrivilege"), &BackupValue ) ) {
+ ret_val = FAILURE;
+ }
+
+ // Enable backup privilege for this process
+
+ NewState.PrivilegeCount = 1;
+ NewState.Privileges[0].Luid = BackupValue;
+ NewState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+ if ( ! AdjustTokenPrivileges( TokenHandle, FALSE, &NewState, (DWORD)0, NULL, NULL ) ) {
+ ret_val = FAILURE;
+ }
+
+ // AdjustTokenPriv always returns SUCCESS, call GetLast to see if it worked.
+
+ if ( GetLastError() != ERROR_SUCCESS ) {
+ ret_val = FAILURE;
+ }
+
+ // close process token
+
+ CloseHandle( TokenHandle );
+ return( ret_val );
+}
+
+/**/
+/**
+
+ Name: REG_AssertRestorePrivilege
+
+ Description: Tell the OS that we are going to be doing restores.
+
+ Modified:
+
+ Returns: SUCCESS/FAILURE
+
+ Declaration:
+**/
+
+INT REG_AssertRestorePrivilege( )
+{
+ INT ret_val = SUCCESS;
+ HANDLE ProcessHandle;
+ DWORD DesiredAccess;
+ HANDLE TokenHandle;
+ LUID RestoreValue;
+ TOKEN_PRIVILEGES NewState;
+
+ // get process handle
+
+ ProcessHandle = GetCurrentProcess();
+
+ // open process token
+
+ DesiredAccess = MAXIMUM_ALLOWED;
+
+ if ( ! OpenProcessToken( ProcessHandle, DesiredAccess, &TokenHandle ) ) {
+ return( FAILURE );
+ }
+
+ // adjust restore token privileges
+
+ if ( ! LookupPrivilegeValue( NULL, TEXT("SeRestorePrivilege"), &RestoreValue ) ) {
+ ret_val = FAILURE;
+ }
+
+ // Enable backup privilege for this process
+
+ NewState.PrivilegeCount = 1;
+ NewState.Privileges[0].Luid = RestoreValue;
+ NewState.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+ if ( ! AdjustTokenPrivileges( TokenHandle, FALSE, &NewState, (DWORD)0, NULL, NULL ) ) {
+ ret_val = FAILURE;
+ }
+
+ if ( GetLastError() != ERROR_SUCCESS ) {
+ ret_val = FAILURE;
+ }
+
+ CloseHandle( TokenHandle );
+ return( ret_val );
+}
+
+/**/
+/**
+
+ Name: REG_IsRegistryFile
+
+ Description: Determine if a file is a registry file. This function
+ is for public use.
+
+ Modified:
+
+ Returns: SUCCESS/FAILURE
+
+ Declaration:
+**/
+
+INT REG_IsRegistryFile(
+IN GENERIC_DLE_PTR dle,
+IN CHAR_PTR FileSpec )
+{
+ CHAR ValueKey[ REG_BUFF_SIZE ];
+
+
+ return( REG_LocalIsRegistryFile( dle,
+ FileSpec,
+ ValueKey, REG_BUFF_SIZE ) == SUCCESS );
+}
+
+INT REG_IsEventFile(
+ GENERIC_DLE_PTR dle,
+ CHAR_PTR FileSpec,
+ CHAR_PTR buffer )
+{
+ if ( NTFS_GetRegistryPathSize(dle) != 0 ) {
+
+ return( REG_LocalIsEventFile( dle,
+ FileSpec,
+ buffer ) == SUCCESS );
+ } else {
+ return FALSE ;
+ }
+}
+
+INT REG_IsCurDirRegistryPath(
+IN FSYS_HAND fsh )
+{
+ CHAR_PTR p ;
+
+ if ( NTFS_GetRegistryPathSize(fsh->attached_dle) != 0 ) {
+
+ p = strchr( NTFS_GetRegistryPath( fsh->attached_dle ), TEXT( '\\' ) ) ;
+
+ if ( (p != NULL ) && !stricmp( p, fsh->cur_dir ) ) {
+ return TRUE ;
+ }
+ }
+
+ return FALSE ;
+}
+
+/**/
+/**
+
+ Name: REG_LocalIsEventFile
+
+ Description: Determine if a file is an event file.
+
+ Modified:
+
+ Returns: SUCCESS/FAILURE
+
+ Declaration:
+**/
+
+INT REG_LocalIsEventFile(
+IN GENERIC_DLE_PTR dle,
+IN CHAR_PTR FileSpec,
+OUT CHAR_PTR buffer )
+{
+ HKEY Key;
+ INT RegPathSize;
+ CHAR_PTR p ;
+ INT ret_val = FAILURE;
+ LONG ret;
+ CHAR *FileName;
+ CHAR Machine[ REG_BUFF_SIZE ];
+ CHAR RegPath[ REG_BUFF_SIZE ];
+
+ RegPathSize = NTFS_GetRegistryPathSize(dle) ;
+
+
+ memcpy( RegPath,
+ NTFS_GetRegistryPath(dle),
+ NTFS_GetRegistryPathSize(dle) ) ;
+
+ // Separate the path from the file name.
+
+ p = strrchr( FileSpec, TEXT( '\\' ) ) ;
+
+ if ( p != NULL ) {
+ *p = TEXT( '\0' );
+ FileName = p + 1 ;
+ } else {
+ return( ret_val ) ;
+ }
+
+ // Is this file in the correct path ?
+
+ if ( dle->info.ntfs->mac_name_syntax ) {
+ FileSpec += 4; // this takes care of \\?\ syntax
+ }
+
+ if ( memicmp( RegPath, FileSpec, RegPathSize ) ) {
+ *p = TEXT( '\\' );
+ return( ret_val );
+ }
+
+ *p = TEXT( '\\' );
+
+ // Now we have to go through the damned registry to see if it's in it.
+
+ if ( ! DLE_HasFeatures( dle, DLE_FEAT_REMOTE_DRIVE ) ) {
+ ret_val = REG_CheckEventListForFile( HKEY_LOCAL_MACHINE, FileSpec, buffer );
+ }
+ else {
+
+ ret_val = FAILURE;
+ }
+
+ return( ret_val );
+}
+
+/**/
+/**
+
+ Name: REG_LocalIsRegistryFile
+
+ Description: Determine if a file is a registry file.
+
+ Modified:
+
+ Returns: SUCCESS/FAILURE
+
+ Declaration:
+**/
+
+INT REG_LocalIsRegistryFile(
+IN GENERIC_DLE_PTR dle,
+IN CHAR_PTR FileSpec,
+OUT CHAR_PTR ValueKey,
+IN INT ValueKeySize )
+{
+ HKEY Key;
+ INT RegPathSize;
+ CHAR_PTR p ;
+ INT ret_val = FAILURE;
+ LONG ret;
+ CHAR *FileName;
+ CHAR Machine[ REG_BUFF_SIZE ];
+ CHAR RegPath[ REG_BUFF_SIZE ];
+
+ RegPathSize = NTFS_GetRegistryPathSize(dle) ;
+
+
+ memcpy( RegPath,
+ NTFS_GetRegistryPath(dle),
+ NTFS_GetRegistryPathSize(dle) ) ;
+
+ // Separate the path from the file name.
+
+ p = strrchr( FileSpec, TEXT( '\\' ) ) ;
+
+ if ( p != NULL ) {
+ *p = TEXT( '\0' );
+ FileName = p + 1 ;
+ } else {
+ return( ret_val ) ;
+ }
+
+ // Is this file in the correct path ?
+
+// if ( memicmp( RegPath, FileSpec, RegPathSize ) ) {
+// *p = TEXT( '\\' );
+// return( ret_val );
+// }
+
+ *p = TEXT( '\\' );
+
+ // Now we have to go through the damned hivelist to see if it's in it.
+
+ if ( ! DLE_HasFeatures( dle, DLE_FEAT_REMOTE_DRIVE ) ) {
+ ret_val = REG_CheckHiveListForFile( HKEY_LOCAL_MACHINE, FileName, ValueKey, ValueKeySize );
+ }
+ else {
+
+ ret_val = FAILURE;
+ }
+
+ return( ret_val );
+}
+
+
+/**/
+/**
+
+ Name: REG_CheckEventListForFile
+
+ Description: See if a file is in the registry event list.
+
+ Modified:
+
+ Returns: SUCCESS/FAILURE
+
+ Declaration:
+**/
+
+INT REG_CheckEventListForFile(
+IN HKEY Key,
+IN CHAR_PTR FileName,
+OUT CHAR_PTR buffer )
+{
+ INT index = 0;
+ INT ret_val = FAILURE;
+ LONG ret;
+ ULONG ulOptions = 0L;
+ HKEY key2;
+ REGSAM samDesired = KEY_READ;
+ FILETIME ftLastWrite;
+ CHAR data[ REG_BUFF_SIZE ];
+ INT data_size;
+
+
+ // Now let's see what event log directories the registry has in it.
+
+ ret = RegOpenKeyEx( Key,
+ TEXT("system\\currentcontrolset\\services\\eventlog"),
+ ulOptions, samDesired, &key2 ) ;
+
+ if ( ret ) {
+ return( FAILURE );
+ }
+
+ do {
+
+ data_size = REG_BUFF_SIZE;
+
+ ret = RegEnumKeyEx( key2,
+ index,
+ data, (LPDWORD)&data_size,
+ NULL, NULL, NULL,
+ &ftLastWrite );
+
+ if ( ! ret ) {
+
+ // Now let's see what the event file in this directory is named.
+
+ ret_val = REG_CheckSingleEventForFile( key2, data, FileName );
+
+ if ( ret_val == SUCCESS )
+ {
+ data[ data_size ] = TEXT( '\0' );
+ strcpy( buffer, data ) ;
+ ret = -1;
+ }
+ }
+
+ index++;
+
+ } while ( ! ret );
+
+ RegCloseKey( key2 );
+
+ return( ret_val );
+}
+
+/**/
+/**
+
+ Name: REG_CheckHiveListForFile
+
+ Description: See if a file is in the hivelist.
+
+ Modified:
+
+ Returns: SUCCESS/FAILURE
+
+ Declaration:
+**/
+
+INT REG_CheckHiveListForFile(
+IN HKEY Key,
+IN CHAR_PTR FileName,
+OUT CHAR_PTR ValueKey,
+IN INT ValueKeySize )
+{
+ INT index = 0;
+ INT ret_val = FAILURE;
+ CHAR *name;
+ LONG ret;
+ ULONG ulOptions = 0L ;
+ HKEY key2;
+ REGSAM samDesired = KEY_QUERY_VALUE;
+ CHAR data[ REG_BUFF_SIZE ];
+ INT value_size;
+ INT data_size;
+
+
+ ret = RegOpenKeyEx( Key,
+ TEXT("system\\currentcontrolset\\control\\hivelist"),
+ ulOptions, samDesired, &key2 ) ;
+
+ if ( ret ) {
+ return( FAILURE );
+ }
+
+ do {
+
+ value_size = ValueKeySize;
+ data_size = REG_BUFF_SIZE;
+
+ ret = RegEnumValue( key2,
+ index,
+ ValueKey,
+ (LPDWORD)&value_size,
+ NULL,
+ NULL,
+ (LPBYTE)
+ data,
+ (LPDWORD)&data_size );
+
+ if ( ! ret ) {
+
+ // separate file name from end of data.
+
+ data_size /= sizeof(CHAR);
+
+ data[ data_size ] = 0;
+
+ while ( ( data[ data_size ] != TEXT( '\\' ) ) && data_size )
+ {
+ data_size--;
+ }
+
+ if ( data_size )
+ {
+ name = &data[ data_size + 1 ];
+ }
+ else
+ {
+ name = data;
+ }
+
+ if ( ! stricmp( name, FileName ) )
+ {
+ ret_val = SUCCESS; // success !
+ }
+ }
+
+ index++;
+
+ } while ( ( ! ret ) && ( ret_val == FAILURE ) );
+
+ RegCloseKey( key2 );
+
+ return( ret_val );
+}
+/**/
+/**
+
+ Name: REG_CheckHiveListForFile
+
+ Description: See if a file is in the hivelist.
+
+ Modified:
+
+ Returns: SUCCESS/FAILURE
+
+ Declaration:
+**/
+
+INT REG_CheckSingleEventForFile(
+IN HKEY Key,
+IN CHAR_PTR Directory,
+IN CHAR_PTR FileName )
+{
+ INT index = 0;
+ INT ret_val = FAILURE;
+ CHAR *name;
+ LONG ret;
+ ULONG ulOptions = 0L ;
+ HKEY key2;
+ REGSAM samDesired = KEY_QUERY_VALUE;
+ CHAR value[ REG_BUFF_SIZE ];
+ CHAR data[ REG_BUFF_SIZE ];
+ INT value_size;
+ INT data_size;
+ INT name_length;
+ INT file_length;
+
+ ret = RegOpenKeyEx( Key,
+ Directory,
+ ulOptions, samDesired, &key2 ) ;
+
+ if ( ret ) {
+ return( FAILURE );
+ }
+
+ do {
+
+ value_size = REG_BUFF_SIZE;
+ data_size = REG_BUFF_SIZE;
+
+ ret = RegEnumValue( key2,
+ index,
+ value,
+ (LPDWORD)&value_size,
+ NULL,
+ NULL,
+ (LPBYTE)data,
+ (LPDWORD)&data_size );
+
+ if ( ! ret ) {
+
+ if ( ! strncmp( value, TEXT( "File" ), 4 ) ) {
+
+ // separate file name from end of data.
+
+ data_size /= sizeof( CHAR );
+
+ data[ data_size ] = TEXT( '\0' );
+
+ while ( ( data[ data_size ] != TEXT( '%' ) ) && data_size )
+ {
+ data_size--;
+ }
+
+ if ( data_size )
+ {
+ name = &data[ data_size + 1 ];
+ }
+ else
+ {
+ name = data;
+ }
+
+ name_length = strlen( name );
+ file_length = strlen( FileName );
+ if ( file_length >= name_length )
+ {
+ FileName += ( file_length - name_length );
+ if ( ! stricmp( name, FileName ) )
+ {
+ ret_val = SUCCESS; // success !
+ ret = -1;
+ }
+ }
+ }
+ }
+
+ index++;
+
+ } while ( ! ret );
+
+ RegCloseKey( key2 );
+
+ return( ret_val );
+}
+
+
+/**/
+/**
+
+ Name: REG_GetRegistryPath
+
+ Description: Determine if/where the registry is for a drive.
+
+ Modified:
+
+ Returns: SUCCESS/FAILURE
+
+ Declaration:
+**/
+
+INT REG_GetRegistryPath(
+IN CHAR *Machine,
+IN CHAR Drive,
+OUT CHAR_PTR Path,
+IN INT *PathSize )
+{
+ CHAR system[ REG_BUFF_SIZE ];
+ CHAR drive[] = TEXT("X:\\");
+ DWORD DriveType;
+ OFSTRUCT openbuff;
+ INT i;
+ INT ret;
+ INT ret_val = FAILURE;
+ INT RegFound;
+ INT fh;
+ HKEY Key;
+
+
+ drive[ 0 ] = Drive;
+
+ DriveType = GetDriveType( drive );
+
+ if ( DriveType == DRIVE_FIXED )
+ {
+ GetSystemDirectory( system, (DWORD)255 );
+
+ if ( ! strnicmp( system, drive, 2 ) )
+ {
+ // There is a registry on this drive, lets find it.
+
+ ret_val = REG_GetRegistryPathFromHiveList( HKEY_LOCAL_MACHINE,
+ Path,
+ PathSize );
+ }
+ }
+
+ if ( ret_val != SUCCESS )
+ {
+ *PathSize = 0;
+ }
+
+ return ret_val;
+}
+
+/**/
+/**
+
+ Name: REG_ChopOffDirectory
+
+ Description: Remove the top level directory from the path.
+
+ Modified:
+
+ Returns: SUCCESS/FAILURE
+
+ Declaration:
+**/
+
+INT REG_ChopOffDirectory(
+CHAR *Path )
+{
+ CHAR *s;
+ CHAR *t;
+
+ if ( strlen( Path ) < 4 ) {
+ return( FAILURE );
+ }
+
+ // We are going to drop something.
+
+ s = Path;
+ while ( *s && *s != TEXT( '\\' ) ) s++;
+ s++;
+
+ t = s;
+ while ( *t && *t != TEXT( '\\' ) ) t++;
+
+ if ( *t == TEXT( '\\' ) ) {
+ t++;
+ strcpy( s, t );
+ }
+ else {
+ *s = TEXT( '\0' );
+ }
+
+ return( SUCCESS );
+}
+
+/**/
+/**
+
+ Name: REG_GetRegistryPathFromHiveList
+
+ Description: Get the registry's path from the hivelist.
+
+ Modified:
+
+ Returns: SUCCESS/FAILURE
+
+ Declaration:
+**/
+
+INT REG_GetRegistryPathFromHiveList(
+IN HKEY key,
+OUT CHAR *Path,
+IN INT *PathSize )
+{
+ CHAR Data[ REG_BUFF_SIZE ];
+ CHAR Value[ REG_BUFF_SIZE ];
+ REGSAM samDesired = KEY_QUERY_VALUE;
+ ULONG ulOptions = 0L ;
+ DWORD ValueSize;
+ DWORD DataSize;
+ INT Index = 0;
+ INT ret;
+
+ ret = RegOpenKeyEx( key,
+ TEXT("SYSTEM\\CURRENTCONTROLSET\\CONTROL\\HIVELIST"),
+ ulOptions, samDesired, &key );
+
+ if ( ! ret )
+ {
+ do
+ {
+ ValueSize = REG_BUFF_SIZE;
+ DataSize = REG_BUFF_SIZE;
+
+ ret = RegEnumValue( key,
+ Index,
+ Value,
+ (LPDWORD)&ValueSize,
+ NULL,
+ NULL,
+ (LPBYTE)Data,
+ (LPDWORD)&DataSize );
+
+ if ( ! ret )
+ {
+ DataSize /= sizeof( CHAR );
+ Data[ DataSize ] = TEXT( '\0' );
+
+ if ( DataSize > 1 )
+ {
+ ret = REG_GetPathFromHiveEntry( Data, Path, PathSize );
+ break;
+ }
+ }
+
+ Index++;
+
+ } while( ! ret );
+
+ RegCloseKey( key );
+ }
+
+ return( ret );
+}
+
+/**/
+/**
+
+ Name: REG_GetPathFromHiveEntry
+
+ Description: Get the registry's path from a hive entry.
+
+ Modified:
+
+ Returns: SUCCESS/FAILURE
+
+ Declaration:
+**/
+
+INT REG_GetPathFromHiveEntry(
+IN CHAR *Data,
+OUT CHAR *Path,
+IN INT *PathSize )
+{
+ INT Length;
+ INT Index;
+ INT i;
+
+
+ Path[ 0 ] = TEXT( '\0' );
+
+ // BEFORE
+ // Data = TEXT("\device\harddisk0\partition1\NT\SYSTEM\CONFIG\SOFTWARE")
+ // *PathSize = sizeof( Path )
+
+
+ // AFTER
+ // Path = TEXT("\NT\SYSTEM\CONFIG")
+ // *PathSize = 17
+
+
+ Length = strlen( Data );
+
+ // Chop off file name.
+
+ Index = Length;
+ while ( Index && Data[ Index ] != TEXT( '\\' ) ) Index--;
+ Data[ Index ] = TEXT( '\0' );
+
+ // Find start of path.
+
+ Index = 0;
+ for ( i = 0; i < 4; i ++ ) {
+ while ( Index < Length && Data[ Index ] != TEXT( '\\' ) ) Index++;
+ Index++;
+ }
+
+ // Quick sanity check
+
+ if ( Index >= Length ) {
+ *PathSize = 0;
+ return( FAILURE );
+ }
+
+ if ( (INT)strsize( &Data[ Index ] ) >= *PathSize ) {
+ *PathSize = strsize( &Data[ Index ] ) + sizeof(CHAR);
+ return( FAILURE );
+ }
+ else {
+ *PathSize = strsize( &Data[ Index-1 ] ) + sizeof(CHAR);
+ strcpy( Path, &Data[ Index-1 ] );
+ }
+
+
+ return( SUCCESS );
+}
+
+/**/
+/**
+
+ Name: REG_BackupRegistryFile
+
+ Description: Code to back up an active registry hive.
+
+ Modified:
+
+ Returns: SUCCESS/FAILURE
+
+ Declaration:
+**/
+
+INT REG_BackupRegistryFile(
+IN GENERIC_DLE_PTR dle,
+IN CHAR_PTR RegFileSpec,
+IN CHAR_PTR TempFileSpec )
+{
+ CHAR ValueKey[ REG_BUFF_SIZE ];
+
+ if ( DLE_HasFeatures( dle, DLE_FEAT_REMOTE_DRIVE ) )
+ {
+ // We don't do remote ones yet.
+
+ return( FAILURE );
+ }
+
+ if ( ! REG_LocalIsRegistryFile( dle, RegFileSpec, ValueKey, REG_BUFF_SIZE ) )
+ {
+ return( REG_SaveActiveRegistryFile( ValueKey, TempFileSpec ) );
+ }
+
+ return( FAILURE );
+}
+
+
+/**/
+/**
+
+ Name: REG_SaveActiveRegistryFile
+
+ Description: Save an active hive to a temp file.
+
+ Modified:
+
+ Returns: SUCCESS/FAILURE
+
+ Declaration:
+**/
+
+INT REG_SaveActiveRegistryFile(
+IN CHAR *ValueKey,
+IN CHAR *NewFile )
+{
+ HKEY hkey;
+ LONG status;
+ CHAR *keyname;
+ CHAR *machine = TEXT("\\REGISTRY\\MACHINE");
+ DWORD disposition ;
+ REGSAM samDesired = MAXIMUM_ALLOWED;
+
+
+ keyname = ValueKey;
+ keyname += strlen( ValueKey );
+ while ( *keyname != TEXT( '\\' ) ) keyname--;
+ keyname++;
+
+ if ( ! strnicmp( machine, ValueKey, strlen( machine ) ) ) {
+
+ status = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
+ keyname,
+ 0,
+ NULL,
+ REG_OPTION_BACKUP_RESTORE,
+ samDesired,
+ NULL,
+ &hkey,
+ &disposition );
+
+ }
+ else {
+
+ status = RegCreateKeyEx( HKEY_USERS,
+ keyname,
+ 0,
+ NULL,
+ REG_OPTION_BACKUP_RESTORE,
+ samDesired,
+ NULL,
+ &hkey,
+ &disposition );
+ }
+
+ if ( status ) {
+ return( FAILURE );
+ }
+
+ status = RegSaveKey( (HKEY)hkey, NewFile, (LPSECURITY_ATTRIBUTES)NULL );
+
+ if ( status != ERROR_SUCCESS ) {
+ status = FAILURE;
+ }
+ else {
+ status = SUCCESS;
+ }
+
+ RegCloseKey( hkey );
+
+ return( status );
+}
+
+/**/
+/**
+
+ Name: REG_RestoreRegistryFile
+
+ Description: Code to restore an active registry file.
+
+ Modified:
+
+ Returns: SUCCESS/FAILURE
+
+ Declaration:
+**/
+
+INT REG_RestoreRegistryFile(
+IN GENERIC_DLE_PTR dle,
+IN CHAR_PTR RegFileSpec, // current active registry file
+IN CHAR_PTR NewFileSpec, // file to become new registry on reboot
+IN CHAR_PTR OldFileSpec ) // file to place old registry into.
+{
+ CHAR ValueKey[ REG_BUFF_SIZE ] ;
+
+ if ( DLE_HasFeatures( dle, DLE_FEAT_REMOTE_DRIVE ) ) {
+
+ // We don't do remote ones yet.
+
+ return( FAILURE );
+ }
+
+ if ( ! REG_LocalIsRegistryFile( dle, RegFileSpec, ValueKey, REG_BUFF_SIZE ) ) {
+
+ return( REG_RestoreActiveRegistryFile( ValueKey, NewFileSpec, OldFileSpec ) );
+ }
+
+ return( FAILURE );
+}
+
+
+INT REG_RestoreActiveRegistryFile(
+CHAR *ValueKey,
+CHAR *NewFileSpec,
+CHAR *OldFileSpec )
+{
+ HKEY LocalKey;
+ HKEY BigKey;
+ INT Status;
+ DWORD disposition ;
+ REGSAM samDesired = MAXIMUM_ALLOWED;
+ CHAR Machine[] = TEXT( "\\REGISTRY\\MACHINE" );
+ CHAR *keyname;
+
+ keyname = ValueKey;
+ keyname += strlen( ValueKey );
+ while ( *keyname != TEXT( '\\' ) ) keyname--;
+ keyname++;
+
+ // Set BigKey
+
+ if ( ! strnicmp( Machine, ValueKey, strlen( Machine ) ) ) {
+ BigKey = HKEY_LOCAL_MACHINE;
+ }
+ else {
+ BigKey = HKEY_USERS;
+ }
+
+
+
+
+ Status = RegCreateKeyEx( BigKey,
+ keyname,
+ 0,
+ NULL,
+ REG_OPTION_BACKUP_RESTORE,
+ samDesired,
+ NULL,
+ &LocalKey,
+ &disposition );
+
+ if ( Status ) {
+ return( FAILURE );
+ }
+
+ if ( !strncmp( NewFileSpec, TEXT("\\\\?\\"),4 ) ) {
+ NewFileSpec +=4 ;
+ }
+ if ( !strncmp( OldFileSpec, TEXT("\\\\?\\"),4 ) ) {
+ OldFileSpec +=4 ;
+ }
+
+ Status = RegReplaceKey( LocalKey, NULL, NewFileSpec, OldFileSpec );
+
+ if ( Status != ERROR_SUCCESS ) {
+ Status = FAILURE;
+ }
+ else {
+ Status = SUCCESS;
+ }
+
+ RegCloseKey( LocalKey );
+
+ return( Status );
+}
+
+VOID REG_MoveActiveRenameKey(
+GENERIC_DLE_PTR dle,
+CHAR_PTR reg_file )
+{
+ CHAR Data[ REG_BUFF_SIZE ];
+ CHAR Value[ REG_BUFF_SIZE ];
+ CHAR DestKeyName[ REG_BUFF_SIZE ];
+ DWORD ValueSize;
+ DWORD DataSize;
+ INT ret ;
+ HKEY key_in ;
+ HKEY key_out ;
+ HKEY key_temp ;
+ HKEY key ;
+ INT Index = 0;
+ DWORD val_type ;
+ CHAR_PTR temp_name ;
+ DWORD disposition ;
+ REGSAM samDesired = MAXIMUM_ALLOWED;
+
+ /* load in the temporary Key */
+ ret = RegLoadKey( HKEY_LOCAL_MACHINE, TEXT("NT_BACKUP_REG"), reg_file ) ;
+
+ if ( ret == ERROR_SUCCESS ) {
+
+ /* Open Select to determine Default */
+
+ ret = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
+ TEXT("NT_BACKUP_REG\\Select"),
+ 0,
+ NULL,
+ REG_OPTION_BACKUP_RESTORE,
+ samDesired,
+ NULL,
+ &key,
+ &disposition );
+
+// ret = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+// TEXT("NT_BACKUP_REG\\Select"),
+// 0L, KEY_QUERY_VALUE, &key );
+
+
+ if ( ret == ERROR_SUCCESS ) {
+
+ DataSize = REG_BUFF_SIZE;
+
+ ret = RegQueryValueEx( key,
+ TEXT("Default"),
+ NULL,
+ NULL,
+ (LPBYTE)Data,
+ (LPDWORD)&DataSize );
+
+ if ( ! ret )
+ {
+ DataSize /= sizeof(CHAR);
+ Data[ DataSize ] = TEXT('\0');
+ sprintf( DestKeyName, TEXT("NT_BACKUP_REG\\ControlSet%03d\\Control\\Session Manager\\FileRenameOperations"), *((LPDWORD)Data) ) ;
+ }
+
+
+ RegCloseKey( key ) ;
+
+ if ( !ret ) {
+
+ /* Open the control for the new registry file */
+ ret = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
+ DestKeyName,
+ 0,
+ NULL,
+ REG_OPTION_BACKUP_RESTORE,
+ samDesired,
+ NULL,
+ &key_out,
+ &disposition );
+
+// ret = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+// DestKeyName,
+// 0L, KEY_SET_VALUE, &key_out );
+
+ if ( !ret ) {
+
+
+ /* Open the control for the Current file */
+
+ ret = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
+ TEXT("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\FileRenameOperations"),
+ 0,
+ NULL,
+ REG_OPTION_BACKUP_RESTORE,
+ samDesired,
+ NULL,
+ &key_in,
+ &disposition );
+
+// ret = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+// TEXT("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\FileRenameOperations"),
+// 0L, KEY_QUERY_VALUE, &key_in );
+
+ if ( !ret ) {
+
+
+ temp_name = NTFS_MakeTempName( reg_file, TEXT("REG") ) ;
+
+ if ( temp_name != NULL ) {
+
+ ret = RegSaveKey( key_in, temp_name, NULL ) ;
+ if ( ret ) {
+ CHAR *p ;
+
+ DeleteFile( temp_name ) ;
+ free( temp_name ) ;
+ p = strrchr( reg_file, TEXT('\\') ) ;
+ if ( p ) {
+ *p = TEXT('\0') ;
+ temp_name = NTFS_MakeTempName( reg_file, TEXT("REG") ) ;
+ *p = TEXT('\\') ;
+ ret = RegSaveKey( key_in, temp_name, NULL ) ;
+ }
+ }
+
+ if ( !ret ) {
+
+ ret = RegRestoreKey( key_out, temp_name, 0 );
+
+ }
+ DeleteFile( temp_name ) ;
+
+ free( temp_name ) ;
+ }
+
+ RegCloseKey( key_in ) ;
+ }
+ RegCloseKey( key_out ) ;
+ }
+ }
+ }
+
+ RegFlushKey( HKEY_LOCAL_MACHINE ) ;
+
+ ret = RegUnLoadKey( HKEY_LOCAL_MACHINE, TEXT("NT_BACKUP_REG") ) ;
+
+ }
+}
diff --git a/private/utils/ntbackup/src/ntfstemp.c b/private/utils/ntbackup/src/ntfstemp.c
new file mode 100644
index 000000000..34c3dc29b
--- /dev/null
+++ b/private/utils/ntbackup/src/ntfstemp.c
@@ -0,0 +1,449 @@
+/**
+Copyright(c) Conner Peripherals, Inc. 1993
+
+
+ Name: ntfstemp.c
+
+ Date Updated: 29-Nov-93
+
+ Description: Manages temporary file names for actively restored
+ files.
+
+ $Log: M:/LOGFILES/NTFSTEMP.C_V $
+
+ Rev 1.1 17 Feb 1994 17:40:12 BARRY
+Removed debug printfs
+
+ Rev 1.0 29 Nov 1993 18:43:34 BARRY
+Initial revision.
+
+**/
+
+#include <windows.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "ntfs_fs.h"
+#include "msassert.h"
+#include "be_debug.h"
+
+
+/*
+ * The following are for maintaining statistics about the performance
+ * of this module. They should be removed once this is debugged and
+ * working....
+ */
+UINT32 numQueries; /* Number of times GetTempName is called */
+UINT32 numProbes; /* Number of times GetTempName has to hunt */
+
+
+/*
+ * Entry for each item in the hash table. A vector of pointers to
+ * this type of structure is maintained.
+ */
+typedef struct HASH_ENTRY
+{
+ struct HASH_ENTRY *next; /* next item for collision resolution */
+ CHAR_PTR tapeName; /* name of item as on tape */
+ CHAR_PTR diskName; /* name of item on disk -- temp name */
+} HASH_ENTRY;
+
+HASH_ENTRY **hashTable; /* Pointer to vector of entries */
+UINT16 hashTableSize;
+UINT16 hashTableEntries;
+
+/*
+ * Vector of prime numbers for sizes to make table. If the table gets
+ * over half-way filled, the next higher table size will be used.
+ * (This probably will not happen under most circumstances.) If the
+ * table needs to get larger than the largest size here, the table
+ * will be increased to (2 * currentTableSize + 1). (The numbers chosen
+ * here are rather arbitrary.)
+ */
+UINT16 tableSizes[] = { 1223, 2377, 3571, 0 };
+
+/*
+ * Number of bits to rotate hash code for each character in key.
+ */
+#define HASH_ROTATE_BITS 3
+
+
+/**/
+/**
+
+ Name: NTFS_InitTemp()
+
+ Description: Performs initializations needed in this module.
+
+ Modified: 29-Nov-93
+
+ Returns: Nothing
+
+ Notes: Only called once, at program start.
+
+**/
+VOID NTFS_InitTemp( VOID )
+{
+ hashTable = NULL;
+ hashTableSize = 0;
+ hashTableEntries = 0;
+
+ /* Debug stuff */
+ numProbes = 0;
+ numQueries = 0;
+}
+
+
+/**/
+/**
+
+ Name: NTFS_DeinitTemp()
+
+ Description: Frees any memory used by the hash table.
+
+ Modified: 29-Nov-93
+
+ Returns: Nothing
+
+ Notes: Only called once, at program end.
+
+**/
+VOID NTFS_DeinitTemp( VOID )
+{
+ UINT32 i;
+ HASH_ENTRY *nxt;
+ HASH_ENTRY *cur;
+
+ if ( hashTable != NULL )
+ {
+ for ( i = 0; (i < hashTableSize); i++ )
+ {
+ cur = *(hashTable + i);
+
+ while ( cur != NULL )
+ {
+ nxt = cur->next;
+
+ free( cur->diskName );
+ free( cur->tapeName );
+ free( cur );
+
+ cur = nxt;
+ }
+ }
+ free( hashTable );
+ hashTable = NULL;
+ }
+ hashTableSize = 0;
+ hashTableEntries = 0;
+}
+
+
+/**/
+/**
+
+ Name: Hash()
+
+ Description: Computes a hash code from a key (fully-qualified
+ path)
+
+ Modified: 29-Nov-93
+
+ Returns: 16-bit hash code
+
+ Notes: Rotates the code a little for each character in
+ the key (in hopes to better scatter the codes).
+ The macro HASH_ROTATE_BITS allows this value to
+ be changed for experimentation.
+
+**/
+static UINT16 Hash( CHAR_PTR s )
+{
+ UINT16 code = 0;
+ UINT16 temp;
+
+ while ( *s )
+ {
+ /*
+ * XOR the character into the hash code.
+ */
+ code ^= (unsigned)*s++;
+
+ /*
+ * Rotate the hash code by number of bits specified.
+ */
+ temp = code >> (sizeof(code) * 8 - HASH_ROTATE_BITS);
+ code <<= HASH_ROTATE_BITS;
+ code |= temp;
+ }
+ return code;
+}
+
+/**/
+/**
+
+ Name: GrowHashTable()
+
+ Description: Expands the hash table
+
+ Modified: 29-Nov-93
+
+ Returns: TRUE if either:
+ a) the table could be expanded
+ b) the table could not be expanded but
+ existed in the first place
+
+ FALSE if the hash table did not exist and
+ could not be allocated
+
+ Notes: Uses global vector of suggested table sizes
+
+**/
+static BOOLEAN GrowHashTable( VOID )
+{
+ BOOLEAN ret = TRUE;
+ UINT32 i;
+ UINT16 newTableSize = 0;
+ HASH_ENTRY **newTable;
+
+ for ( i = 0; (tableSizes[i] != 0); i++ )
+ {
+ if ( tableSizes[i] > hashTableSize )
+ {
+ newTableSize = tableSizes[i];
+ break;
+ }
+ }
+
+ if ( newTableSize == 0 )
+ {
+ newTableSize = hashTableSize * 2 + 1;
+ }
+
+ newTable = realloc( hashTable, newTableSize * sizeof( hashTable ) );
+
+ if ( newTable != NULL )
+ {
+ hashTable = newTable;
+ hashTableSize = newTableSize;
+ }
+ else if ( hashTable == NULL )
+ {
+ ret = FALSE;
+ }
+ return ret;
+}
+
+
+/**/
+/**
+
+ Name: NTFS_SaveTempName()
+
+ Description: Saves the real name (ie, tape name) and the
+ name on disk (the temp name) for an actively-
+ restored file.
+
+ Modified: 29-Nov-93
+
+ Returns: TRUE if name was successfully saved,
+ FALSE otherwise
+
+**/
+BOOLEAN NTFS_SaveTempName( CHAR_PTR tapeName, CHAR_PTR diskName )
+{
+ BOOLEAN ret = TRUE;
+
+ /*
+ * If table is half full, expand it. We want lookups
+ * to be very, very fast....
+ */
+
+ if ( hashTableEntries >= (hashTableSize / 2) )
+ {
+ ret = GrowHashTable();
+ }
+
+ if ( ret )
+ {
+ HASH_ENTRY *dest;
+ HASH_ENTRY *prev = NULL;
+ INT compVal = 0;
+ UINT16 tableIndex;
+
+ /*
+ * Hash the name and get an index into hash table
+ */
+ tableIndex = Hash( tapeName ) % hashTableSize;
+
+ /*
+ * Go into the hash table and find a place for the
+ * new entry, chaining if necessary.
+ */
+ dest = *(hashTable + tableIndex);
+
+ while ( dest != NULL )
+ {
+ compVal = strcmp( dest->tapeName, tapeName );
+
+ if ( compVal >= 0 )
+ {
+ break;
+ }
+ prev = dest;
+ dest = dest->next;
+ }
+
+ /*
+ * We've found the right spot for the name. Let's store it.
+ */
+ if ( dest != NULL && compVal == 0 )
+ {
+ CHAR_PTR newName;
+
+ /*
+ * This is a special case of replacement of a disk name.
+ * (Somebody's restored the same active file twice.)
+ */
+
+ newName = realloc( dest->diskName, strsize( diskName ) );
+ if ( newName == NULL )
+ {
+ free( dest->diskName );
+ dest->diskName = NULL;
+ ret = FALSE;
+ }
+ else
+ {
+ dest->diskName = newName;
+ strcpy( dest->diskName, diskName );
+ }
+ }
+ else
+ {
+ HASH_ENTRY *newEntry;
+ CHAR_PTR tapeNameMem;
+ CHAR_PTR diskNameMem;
+
+ /*
+ * Allocate memory for the table entry and strings.
+ */
+ newEntry = malloc( sizeof( HASH_ENTRY ) );
+ tapeNameMem = malloc( strsize( tapeName ) );
+ diskNameMem = malloc( strsize( diskName ) );
+
+ if ( newEntry == NULL || tapeNameMem == NULL || diskNameMem == NULL )
+ {
+ free( newEntry );
+ free( tapeNameMem );
+ free( diskNameMem );
+
+ ret = FALSE;
+ }
+ else
+ {
+ /*
+ * Stick the entry in the table (or chain)
+ */
+
+ newEntry->next = NULL;
+ newEntry->diskName = diskNameMem;
+ newEntry->tapeName = tapeNameMem;
+
+ strcpy( newEntry->tapeName, tapeName );
+ strcpy( newEntry->diskName, diskName );
+
+ if ( prev != NULL )
+ {
+ newEntry->next = prev->next;
+ prev->next = newEntry;
+ }
+ else
+ {
+ newEntry->next = dest;
+ *(hashTable + tableIndex) = newEntry;
+ }
+ hashTableEntries++;
+ }
+ }
+ }
+ return ret;
+}
+
+
+/**/
+/**
+
+ Name: NTFS_GetTempName()
+
+ Description: Retrieves the disk name (temp name) of a file,
+ given the file's tape name.
+
+ Modified: 29-Nov-93
+
+ Returns: Pointer to name.
+
+ Notes: If the file name does not exist in the hash table,
+ a pointer to the tape name is returned.
+
+**/
+CHAR_PTR NTFS_GetTempName( CHAR_PTR tapeName )
+{
+ CHAR_PTR diskName = tapeName;
+
+ numQueries++;
+
+ /*
+ * Unless someone's restored at least one active file, the
+ * hash table will have never been allocated. Simply returning
+ * the pointer passed will be the bulk of this function's use.
+ */
+
+ if ( hashTable != NULL )
+ {
+ HASH_ENTRY *entry;
+ INT comp;
+
+ /*
+ * Get the hash table entry where the name should be.
+ */
+
+ entry = hashTable[ Hash( tapeName ) % hashTableSize ];
+
+ while ( entry != NULL )
+ {
+ comp = strcmp( tapeName, entry->tapeName );
+
+ /*
+ * Since the entries for each bucket are maintained in
+ * sorted order, we can stop if the name matches or is
+ * greater than the name we're looking for.
+ */
+
+ if ( comp >= 0 )
+ {
+ /* If we have a match, return the temp name */
+ if ( comp == 0 )
+ {
+ /*
+ * Make sure that we have a name (a failed realloc
+ * could result in a NULL name).
+ */
+
+ if ( entry->diskName != NULL )
+ {
+ diskName = entry->diskName;
+ }
+ }
+ break;
+ }
+ numProbes++;
+ entry = entry->next;
+ }
+ }
+ return diskName;
+}
+
+
+
diff --git a/private/utils/ntbackup/src/ntfsutil.c b/private/utils/ntbackup/src/ntfsutil.c
new file mode 100644
index 000000000..66725ee63
--- /dev/null
+++ b/private/utils/ntbackup/src/ntfsutil.c
@@ -0,0 +1,158 @@
+/**
+Copyright(c) Arcada Software, Inc. 1994
+
+
+ Name: ntfsutil.c
+
+ Date Updated: 18-Jan-94
+
+ Description: Utility functions for the NTFS and MSNet file systems.
+
+ $Log: M:/LOGFILES/NTFSUTIL.C_V $
+
+ Rev 1.1 23 Jan 1994 14:00:34 BARRY
+Changed types for ANSI/Unicode compiles
+
+ Rev 1.0 23 Jan 1994 12:49:04 BARRY
+Initial revision.
+
+**/
+
+#include <windows.h>
+#include <stdio.h> /* for printf functions */
+#include <stdarg.h> /* for var arg functions */
+#include <wchar.h> /* for wprintf functions */
+#include "stdtypes.h"
+#include "std_err.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "ntfs_fs.h"
+
+#if defined( FS_MSNET )
+#include "mnet.h"
+#endif
+
+#include "be_debug.h"
+#include "msassert.h"
+
+
+
+/*
+ * Definitions for debug print code
+ */
+
+#define NTFS_DEBUG_WIDTH 78
+
+#if defined( UNICODE )
+#define vsnprintf _vsnwprintf
+#else
+#define vsnprintf _vsnprintf
+#endif
+
+
+
+/**/
+/**
+
+ Name: NTFS_DebugPrintFunction()
+
+ Description: Prints to a string buffer and calls BE_Zprintf
+ with the result. Written as special function to
+ take potentially huge strings (like when a deep
+ path is printed) and split them up into smaller
+ lines.
+
+ Modified: 18-Jan-94
+
+ Returns: Nothing
+
+
+ Notes: Use the NTFS_DebugPrint macro to call this function
+
+**/
+VOID NTFS_DebugPrintFunction( CHAR *fmt, ... )
+{
+ static CHAR_PTR buff = NULL;
+ static size_t buffSize = 0;
+ va_list args;
+
+ va_start( args, fmt );
+
+ while ( vsnprintf( buff, buffSize, fmt, args ) == -1 )
+ {
+ CHAR_PTR newBuff;
+
+ /* Buffer wasn't big enough. Realloc and try again. */
+ buffSize += 256;
+ newBuff = realloc( buff, buffSize * sizeof(CHAR) );
+
+ if ( newBuff != NULL )
+ {
+ buff = newBuff;
+ }
+ else
+ {
+ free( buff );
+ buff = NULL;
+ buffSize = 0;
+ break;
+ }
+ }
+
+ if ( buff == NULL )
+ {
+ BE_Zprintf( DEBUG_TEMPORARY, TEXT("NTFS_DebugPrint: out of memory") );
+ }
+ else
+ {
+ CHAR_PTR src = buff;
+ CHAR_PTR end;
+ CHAR c;
+ int len = (int)strlen( buff );
+
+ do {
+ end = src + min( len, NTFS_DEBUG_WIDTH );
+ len -= end - src;
+ c = *end;
+ *end = TEXT('\0');
+ BE_Zprintf( DEBUG_TEMPORARY, TEXT("%s"), src );
+ *end = c;
+ src = end;
+ } while ( *src );
+ }
+}
+
+/**/
+/**
+
+ Name: NTFS_DuplicateString()
+
+ Description: Convenience function to duplicate strings.
+ May be called with NULL string pointer.
+
+ Modified: 18-Jan-94
+
+ Returns: Pointer to duplicate string; NULL if source string
+ is NULL or if memory allocation fails.
+
+
+ Notes: Use free() to discard the string.
+
+
+**/
+CHAR_PTR NTFS_DuplicateString( CHAR_PTR src )
+{
+ CHAR_PTR result = NULL;
+
+ if ( src != NULL )
+ {
+ if ( (result = malloc(strsize(src))) != NULL )
+ {
+ strcpy( result, src );
+ }
+ }
+ return result;
+}
+
+
+
diff --git a/private/utils/ntbackup/src/om_blank.bmp b/private/utils/ntbackup/src/om_blank.bmp
new file mode 100644
index 000000000..17110911a
--- /dev/null
+++ b/private/utils/ntbackup/src/om_blank.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/om_dsap.bmp b/private/utils/ntbackup/src/om_dsap.bmp
new file mode 100644
index 000000000..2812d9d25
--- /dev/null
+++ b/private/utils/ntbackup/src/om_dsap.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/om_dsas.bmp b/private/utils/ntbackup/src/om_dsas.bmp
new file mode 100644
index 000000000..e2e972d1e
--- /dev/null
+++ b/private/utils/ntbackup/src/om_dsas.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/om_dsax.bmp b/private/utils/ntbackup/src/om_dsax.bmp
new file mode 100644
index 000000000..4567c4c16
--- /dev/null
+++ b/private/utils/ntbackup/src/om_dsax.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/om_entrs.bmp b/private/utils/ntbackup/src/om_entrs.bmp
new file mode 100644
index 000000000..fde3eb60d
--- /dev/null
+++ b/private/utils/ntbackup/src/om_entrs.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/om_mdbp.bmp b/private/utils/ntbackup/src/om_mdbp.bmp
new file mode 100644
index 000000000..741de7923
--- /dev/null
+++ b/private/utils/ntbackup/src/om_mdbp.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/om_mdbs.bmp b/private/utils/ntbackup/src/om_mdbs.bmp
new file mode 100644
index 000000000..07342ab59
--- /dev/null
+++ b/private/utils/ntbackup/src/om_mdbs.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/om_mdbx.bmp b/private/utils/ntbackup/src/om_mdbx.bmp
new file mode 100644
index 000000000..f293d3dd8
--- /dev/null
+++ b/private/utils/ntbackup/src/om_mdbx.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/om_servs.bmp b/private/utils/ntbackup/src/om_servs.bmp
new file mode 100644
index 000000000..435df3fa1
--- /dev/null
+++ b/private/utils/ntbackup/src/om_servs.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/om_sites.bmp b/private/utils/ntbackup/src/om_sites.bmp
new file mode 100644
index 000000000..4fb902941
--- /dev/null
+++ b/private/utils/ntbackup/src/om_sites.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/om_stats.bmp b/private/utils/ntbackup/src/om_stats.bmp
new file mode 100644
index 000000000..d41f8d34f
--- /dev/null
+++ b/private/utils/ntbackup/src/om_stats.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/omabout.dlg b/private/utils/ntbackup/src/omabout.dlg
new file mode 100644
index 000000000..b56bc4267
--- /dev/null
+++ b/private/utils/ntbackup/src/omabout.dlg
@@ -0,0 +1,49 @@
+// NT style about box.
+// Apparently \n is now supported in the TEXT controls now.
+//
+
+
+IDD_HELPABOUTWINTERPARK DIALOG DISCARDABLE 20, 20, 229, 190
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION ABOUTAPPLICATIONNAME
+FONT 8, "MS Shell Dlg"
+BEGIN
+ ICON 0,IDD_ABOUTICON,10,5,18,20
+ LTEXT "<app text string>",IDD_ABOUTAPPNAME,45,5,181,8,
+ SS_NOPREFIX | NOT WS_GROUP
+ LTEXT "<version number goes here>",IDD_ABOUTVERSION,45,15,180,10,
+ SS_NOPREFIX | NOT WS_GROUP
+
+#ifdef CONNER
+ LTEXT "Copyright \251 1993-1996 Seagate Software, Inc.\n\nCall Conner's 1-800 number for additional information on software products.",
+#else
+ LTEXT "Copyright \251 1993-1996 Seagate Software, Inc.\n\nCall Seagate Software's 1-800 number for additional information on software products.",
+#endif
+ -1,45,25,180,35,SS_NOPREFIX | NOT WS_GROUP
+
+ LTEXT "This product is licensed to:",-1,45,67,180,10,
+ SS_NOPREFIX | NOT WS_GROUP
+ LTEXT "<user name goes here>",IDD_ABOUTUSERNAME,45,77,180,10,
+ SS_NOPREFIX | NOT WS_GROUP
+ LTEXT "<organization name goes here>",IDD_ABOUTCOMPANYNAME,45,87,
+ 180,10,SS_NOPREFIX | NOT WS_GROUP
+ CONTROL "",9998,"Static",SS_BLACKRECT,45,100,180,1
+ LTEXT "Product ID:",
+ IDD_ABOUTSERIALNUM,45,108,178,18,SS_NOPREFIX | NOT WS_GROUP
+ LTEXT "<product ID here>",IDD_ABOUTPRODID,95,108,180,10,
+ CONTROL "",9999,"Static",SS_BLACKRECT,45,128,180,1
+ LTEXT "Total Physical Memory:",IDD_ABOUTMEMTITLE,45,135,90,10,
+ SS_NOPREFIX | NOT WS_GROUP
+ LTEXT "%s KB",IDD_ABOUTMEMORY,140,135,74,10,SS_NOPREFIX | NOT
+ WS_GROUP
+ LTEXT "Processor:",IDD_ABOUTPROCESSORTITLE,45,144,90,10,SS_NOPREFIX |
+ NOT WS_GROUP
+ LTEXT "<processor name>",IDD_ABOUTPROCESSOR,88,144,114,10,
+ SS_NOPREFIX | NOT WS_GROUP | SS_LEFTNOWORDWRAP
+ LTEXT "Identifier:",IDD_ABOUTIDENTTITLE,45,153,90,10,SS_NOPREFIX |
+ NOT WS_GROUP
+ LTEXT "<identifier name>",IDD_ABOUTIDENT,88,153,114,10,
+ SS_NOPREFIX | NOT WS_GROUP | SS_LEFTNOWORDWRAP
+ DEFPUSHBUTTON "OK",IDOK,94,170,40,14
+END
+
diff --git a/private/utils/ntbackup/src/omacckey.rc b/private/utils/ntbackup/src/omacckey.rc
new file mode 100644
index 000000000..abd7a876e
--- /dev/null
+++ b/private/utils/ntbackup/src/omacckey.rc
@@ -0,0 +1,34 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+DAVEV
+
+ Name: wntrpark.rc
+
+ Description: This file contains the references to accelerator resources
+ for the Microsoft OEM GUI Project for NT Resource File.
+
+ This file was created by copying and modifying the
+ Standard Maynard GUI Project file: ACCKEYS.RC
+
+ $Log: G:/UI/LOGFILES/OMACCKEY.RCV $
+
+ Rev 1.0 03 Mar 1992 12:23:02 DAVEV
+ Initial revision.
+
+******************************************************************************/
+
+// ACCELERATOR KEYS -- ID's are defined in the Menu Manager header file 'ss_mm.h'
+
+// Frame Menu Accelerators
+
+IDRA_ACCKEYS ACCELERATORS
+BEGIN
+ VK_F2, IDM_HELPABOUTNOSTRADOMUS, VIRTKEY, SHIFT
+// VK_INSERT, IDM_EDITCOPY, VIRTKEY, CONTROL
+// VK_INSERT, IDM_EDITPASTE, VIRTKEY, SHIFT
+// VK_DELETE, IDM_EDITCUT, VIRTKEY, SHIFT
+// VK_BACK, IDM_EDITUNDO, VIRTKEY, ALT
+END
+
+
diff --git a/private/utils/ntbackup/src/ombackup.bmp b/private/utils/ntbackup/src/ombackup.bmp
new file mode 100644
index 000000000..218f2872b
--- /dev/null
+++ b/private/utils/ntbackup/src/ombackup.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/ombackup.ico b/private/utils/ntbackup/src/ombackup.ico
new file mode 100644
index 000000000..17f772be3
--- /dev/null
+++ b/private/utils/ntbackup/src/ombackup.ico
Binary files differ
diff --git a/private/utils/ntbackup/src/ombatch.c b/private/utils/ntbackup/src/ombatch.c
new file mode 100644
index 000000000..f863e656d
--- /dev/null
+++ b/private/utils/ntbackup/src/ombatch.c
@@ -0,0 +1,1205 @@
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+DAVEV
+
+ Name: ombatch.c
+
+ Description: This file contains the functions for the Microsoft
+ OEM version of Maynstream for Windows & Win32/NT to
+ support Command Line batch processing.
+
+ The following support is implemented for batch mode
+ processing (see the NT Backup/Restore Utility
+ Specification for more information.)
+
+ The batch command has the following parameters:
+
+ APPNAME [OPERATION PATHNAMES [OPTIONS]]
+
+ where:
+
+ OPERATION = "Backup"
+
+ PATHNAMES = [[drive:][path]filespec] ...
+
+ OPTIONS = {Mode, Verify, RestrictAccess,
+ Description, BackupType, Logfile,
+ Logmode }...
+
+ Mode = /A[ppend]
+ Verify = /V[erify]
+ Access = /R[estrict]
+ Description = /D[escription] "text"
+ BackupType = /T[ype] {Normal, Incremental,
+ Differential, Copy,
+ Incremental_Copy}
+ Logfile = /L[ogfile] "filename"
+ Logmode = /E[xceptions]
+
+ Note: In this implementation, options may appear
+ anywhere in the command line following the
+ 'Backup' operation key word - they are not
+ restricted to just following the list of
+ path names.
+
+ $Log: G:/UI/LOGFILES/OMBATCH.C_V $
+
+ Rev 1.22.1.3 24 Feb 1994 16:13:52 STEVEN
+DO NOT prompt for skip open files
+
+ Rev 1.22.1.2 24 Feb 1994 16:06:06 STEVEN
+log switch functionality was broken
+
+ Rev 1.22.1.1 25 Jan 1994 15:48:12 chrish
+Added fix for ORCAS EPR 0054. Problem with using a space as a valid
+character in the log file name or directory name.
+
+ Rev 1.22.1.0 26 Oct 1993 18:10:34 BARRY
+Added backupRegistry option
+
+ Rev 1.22 04 Jun 1993 17:14:32 chrish
+Nostradamus EPR 0490 - Added source to fix command line /r switch. Fix
+to set the command line restrict access flag.
+
+Added in the OEM_UpdateBatchBSDOptions routine the line ...
+CDS_SetCmdLineRestrictAccess ( pcds, (pOpts->eAccess == OEM_ACCESS_RESTRICTED ) );
+to set the "cmd_line_restrict_access" flag in the CDS structure.
+
+ Rev 1.21 18 May 1993 13:48:32 chrish
+NOSTRADAMUS and CAYMAN - Commented out portion of code that gave a default
+description when one was not supplied. Did this to make the display more
+consistent. If user does not supply a description, he does not get one.
+
+ Rev 1.20 14 May 1993 18:02:56 chrish
+NOSTRADAMUS EPR 0478: Fix for command line description from 32 to 50
+characters. Another fix for the fix at Rev 1.19.
+
+ Rev 1.19 11 May 1993 17:05:48 chrish
+NOSTRADAMUS EPR 0478: Fix for command line description from 32 to 50
+characters.
+
+ Rev 1.18 07 Apr 1993 15:34:02 MIKEP
+fix called in by steve
+
+ Rev 1.17 11 Mar 1993 15:27:34 STEVEN
+
+
+ Rev 1.16 26 Feb 1993 17:13:50 STEVEN
+fix typo
+
+ Rev 1.15 25 Feb 1993 13:37:50 STEVEN
+trunk set label at 32 characters
+
+ Rev 1.14 11 Feb 1993 12:02:42 STEVEN
+fix batch logfile and path
+
+ Rev 1.13 30 Nov 1992 15:41:16 DAVEV
+Changed /D to backup set description and use default tape label text
+
+ Rev 1.12 01 Nov 1992 16:03:56 DAVEV
+Unicode changes
+
+ Rev 1.11 15 Oct 1992 13:02:32 DAVEV
+fix problem with batch mode /T option
+
+ Rev 1.10 07 Oct 1992 14:13:46 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.9 04 Oct 1992 19:39:28 DAVEV
+Unicode Awk pass
+
+ Rev 1.8 30 Sep 1992 10:41:44 DAVEV
+Unicode strlen verification, MikeP's chgs from MS
+
+ Rev 1.7 17 Sep 1992 17:39:46 DAVEV
+minor fix (strsiz->strsize)
+
+ Rev 1.6 17 Sep 1992 15:51:30 DAVEV
+UNICODE modifications: strlen usage check
+
+ Rev 1.5 24 Jul 1992 13:31:34 davev
+Removed warnings when building for NT
+
+ Rev 1.4 08 Jul 1992 15:32:42 STEVEN
+Unicode BE changes
+
+ Rev 1.3 29 May 1992 16:00:58 JOHNWT
+PCH updates
+
+ Rev 1.2 18 May 1992 15:28:08 DAVEV
+Created OEM_StrDup and replaced all calls to strdup() wiht it
+
+ Rev 1.1 18 May 1992 13:47:58 MIKEP
+i don't know
+
+ Rev 1.0 11 May 1992 14:28:42 DAVEV
+Initial revision.
+
+******************************************************************************/
+
+
+//#define INCL_CDS_READWRITE_MACROS
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+extern WORD RT_max_BSD_index; //Why isn't this in a header file????
+
+static LPSTR OEM_StrDup ( LPSTR pszSrc );
+static void OEM_FixPathCase( LPSTR pszPath ) ;
+
+#if defined ( OEM_EMS )
+static VOID EMS_RecurseSearchDLE (
+ GENERIC_DLE_PTR dle_tree, // I - DLE subtree root to search
+ GENERIC_DLE_PTR *dle, // O - pointer to matched DLE
+ LPSTR pszName, // I - name of server
+ UINT8 uType ); // I - type of dle to search for
+
+static VOID EMS_GetDleByEmsType(
+ GENERIC_DLE_PTR dle_tree, // I - Matching EMS server dle
+ GENERIC_DLE_PTR *dle, // O - pointer to matched dle
+ UINT8 uType ); // I - type of dle to search for
+#endif
+
+OEMOPTS_PTR OEM_DefaultBatchOptions ( VOID )
+{
+ OEMOPTS_PTR pOpts = calloc ( 1, sizeof ( OEMOPTS ) );
+
+ if ( pOpts )
+ {
+ // Set options to default values..
+
+ pOpts->eMode = OEM_MODE_OVERWRITE;
+ pOpts->eVerify = OEM_VERIFY_OFF;
+ pOpts->eAccess = OEM_ACCESS_NO_RESTRICT;
+ pOpts->eType = OEM_TYPE_NORMAL;
+ pOpts->eLogOpt = OEM_LOG_FULLDETAIL; //ignored if no logname given
+
+ pOpts->pszLogName = NULL;
+ pOpts->pszDescription = NULL;
+ pOpts->backupRegistry = FALSE;
+ }
+ return pOpts;
+}
+
+VOID OEM_UpdateBatchBSDOptions ( BSD_HAND hbsdList, OEMOPTS_PTR pOpts )
+{
+ CDS_PTR pcds = CDS_GetPerm ();
+ BE_CFG_PTR pbe_cfg;
+ BSD_PTR pbsd;
+ INT cBsds = 0; //count of BSD's
+ INT16 desc_str_size; // chs:05-14-93
+ LPSTR pszTmp;
+ CHAR szLabel [MAX_UI_RESOURCE_SIZE];
+ CHAR szLabel1 [MAX_UI_RESOURCE_SIZE];
+ CHAR szLabel2 [MAX_UI_RESOURCE_SIZE];
+
+ //Set the global backup configuration options...
+ if ( pOpts->pszLogName )
+ {
+ CDS_SetLogLevel ( pcds, (pOpts->eLogOpt == OEM_LOG_SUMMARY_ONLY)
+ ? LOG_ERRORS : LOG_DETAIL );
+ LOG_SetCurrentLogName ( pOpts->pszLogName );
+ }
+ else
+ {
+ CDS_SetLogLevel ( pcds, LOG_DISABLED );
+ }
+ CDS_SetAppendFlag ( pcds, (pOpts->eMode == OEM_MODE_APPEND) ) ;
+ CDS_SetAutoVerifyBackup ( pcds, (pOpts->eVerify == OEM_VERIFY_ON) ) ;
+ CDS_SetCmdLineRestrictAccess ( pcds, (pOpts->eAccess == OEM_ACCESS_RESTRICTED ) ); // chs:06-04-93
+
+//
+// Comment out setting a default description string
+//
+// chs:05-18-93 if ( pOpts->eMode == OEM_MODE_OVERWRITE
+// chs:05-18-93 && !pOpts->pszDescription )
+// chs:05-18-93 {
+// chs:05-18-93 // create a default tape description...
+// chs:05-18-93
+// chs:05-18-93 CHAR szBuf[ MAX_TAPE_NAME_SIZE ] ;
+// chs:05-18-93 LPSTR psz;
+// chs:05-18-93
+// chs:05-18-93 RSM_StringCopy( IDS_DEFAULT_TAPE_NAME, szBuf, MAX_TAPE_NAME_LEN ) ;
+// chs:05-18-93 psz = szBuf ;
+// chs:05-18-93 while ( *psz ) ++psz;
+// chs:05-18-93 UI_CurrentDate( psz ) ;
+// chs:05-18-93 pOpts->pszDescription = OEM_StrDup ( szBuf );
+// chs:05-18-93 }
+// chs:05-18-93 /* set default tape name */
+// chs:05-18-93
+
+ RSM_StringCopy( IDS_DEFAULT_TAPE_NAME, szLabel1, MAX_TAPE_NAME_LEN );
+ UI_CurrentDate( szLabel2 );
+ wsprintf( szLabel, szLabel1, szLabel2 ) ;
+
+ //Insert the options into each of the bsd's in the bsd list.
+ // keeping a count of the number of BSD's
+ for ( pbsd = BSD_GetFirst( hbsdList ), cBsds = 0;
+ pbsd != NULL;
+ pbsd = BSD_GetNext( pbsd ), ++cBsds )
+ {
+ if (pOpts->pszDescription)
+ {
+ desc_str_size = (INT16)strsize( pOpts->pszDescription); // chs:05-14-93
+ BSD_SetBackupDescript( pbsd, (INT8_PTR)pOpts->pszDescription,
+ desc_str_size ); // chs:05-14-93
+
+ if ( strlen(pOpts->pszDescription) > MAX_BSET_DESC_LEN ) {
+ pOpts->pszDescription[ MAX_BSET_DESC_LEN ] = TEXT('\0') ; // chs:05-14-93
+ }
+
+ BSD_SetBackupLabel( pbsd, (INT8_PTR)pOpts->pszDescription,
+ (INT16)strsize( pOpts->pszDescription) );
+ }
+
+ BSD_SetTapeLabel( pbsd, (INT8_PTR)szLabel,
+ (INT16) strsize( szLabel ) );
+ BSD_SetBackupType ( pbsd, (INT16)pOpts->eType );
+ BSD_SetFullyCataloged( pbsd, TRUE ); /* always do full cataloging */
+
+ pbe_cfg = BSD_GetConfigData( pbsd );
+// BEC_SetSkipOpenFiles ( pbe_cfg, (INT16)SKIP_NO );
+ BEC_SetRestoreSecurity ( pbe_cfg,
+ (pOpts->eAccess == OEM_ACCESS_RESTRICTED) );
+
+ if ( pOpts->backupRegistry &&
+ DLE_HasFeatures( BSD_GetDLE( pbsd ),
+ DLE_FEAT_BKUP_SPECIAL_FILES ) )
+ {
+ BSD_SetProcSpecialFlg( pbsd, TRUE );
+ }
+
+ }
+ RT_max_BSD_index = (WORD) ( cBsds );
+}
+
+VOID OEM_DeleteBatchOptions ( OEMOPTS_PTR * pOpts )
+{
+ if ( pOpts && *pOpts )
+ {
+ if ( (*pOpts)->pszLogName )
+ free ( (*pOpts)->pszLogName );
+ if ( (*pOpts)->pszDescription )
+ free ( (*pOpts)->pszDescription );
+ free ( * pOpts );
+
+ *pOpts = NULL;
+ }
+}
+
+
+/*****************************************************************************
+
+ Name: OEM_LookupBatchType
+
+ Description: If the target string contains a valid type specifier
+ for the type option, look it up in the type table and
+ return the associated resource string identifier.
+
+ Returns(INT): IDS_OEMTYPE_UNKNOWN - This is not a recognized type
+ specifier.
+
+ other - One of the IDS_OEMTYPE_* resource string ids
+ defined in OMSTRING.H.
+
+ INT OEM_LookupBatchType (
+ LPSTR pszType ) I - Targe type string to look for
+
+
+*****************************************************************************/
+LPSTR apszTypeTable [ IDS_OEMTYPE_COUNT ];
+
+static BOOL OEM_InitTypeTable ( VOID )
+{
+ CHAR szType [ IDS_OEM_MAX_LEN ]; //Temporary string buffer
+ INT count; //loop counter
+
+ memset ( apszTypeTable, 0, sizeof ( apszTypeTable ) );
+ for ( count = 0; count < IDS_OEMTYPE_COUNT; ++count )
+ {
+ // Read in the option string and add it to the table
+
+ RSM_StringCopy ( IDS_OEMTYPE_FIRST + count, szType, sizeof ( szType ) );
+ apszTypeTable[ count ] = OEM_StrDup ( szType );
+ }
+ return TRUE;
+}
+/*----------------------------------------------------------------------*/
+
+OEMTYPE OEM_LookupTypeOption ( LPSTR pszType )
+{
+ INT idx = 0; //Start with first option
+ INT found_idx = 0; //Start with first option
+ BOOL wasFound = FALSE; //Did we find the option?
+ INT nTypeLen; //Length of target option string
+ OEMTYPE oemType = OEM_TYPE_UNKNOWN;
+ BOOL idx_valid = FALSE ;
+
+ if( pszType
+ && ( nTypeLen = strlen ( pszType ) ) //must have a length!
+ && ( *apszTypeTable || OEM_InitTypeTable () )) //init table if needed
+ {
+ // cycle through the option table comparing each entry with the
+ // target option. Note that only as much of the option as the user
+ // has entered needs to be matched, since anything past the first
+ // character is optional.
+
+ do {
+ while ( idx < IDS_OEMTYPE_COUNT ) {
+
+ wasFound = (strnicmp ( pszType,
+ apszTypeTable[ idx ],
+ nTypeLen ) == 0) ;
+
+ if ( wasFound && (found_idx != 0) ) { /*not significant enough */
+ found_idx = idx = 0;
+ nTypeLen ++ ;
+ wasFound = 0 ;
+ idx_valid = FALSE ;
+ break ;
+
+ } else if ( wasFound ) {
+ found_idx = idx ;
+ idx_valid = TRUE ;
+ }
+
+ idx ++ ;
+ }
+
+ } while( (idx < IDS_OEMTYPE_COUNT) ) ;
+
+ idx = found_idx ;
+
+ }
+ if ( idx_valid )
+ {
+ // map the array index into a backup type
+
+ switch ( idx + IDS_OEMTYPE_FIRST )
+ {
+ case IDS_OEMTYPE_NORMAL:
+ oemType = OEM_TYPE_NORMAL; break;
+
+ case IDS_OEMTYPE_COPY:
+ oemType = OEM_TYPE_COPY; break;
+
+ case IDS_OEMTYPE_DIFFERENTIAL:
+ oemType = OEM_TYPE_DIFFERENTIAL; break;
+
+ case IDS_OEMTYPE_INCREMENTAL:
+ oemType = OEM_TYPE_INCREMENTAL; break;
+
+ case IDS_OEMTYPE_DAILY:
+ oemType = OEM_TYPE_DAILY; break;
+
+ case IDS_OEMTYPE_COMPATIBLE:
+ oemType = OEM_TYPE_COMPATIBLE; break;
+
+ default:
+ oemType = OEM_TYPE_UNKNOWN; break;
+ }
+ }
+ return oemType;
+}
+
+/*****************************************************************************
+
+ Name: OEM_ProcessCmdOption
+
+ Description: This function processes an option on the Backup batch
+ mode command line. The command line is expected to
+ be partially tokenized (via strtok) so that strtok may
+ be called with NULL as the second parameter
+ will continue tokenization using the original token
+ seperators. This is a requirement - NOT an option.
+
+ The contents of the option buffer are verified to
+ determine if it contains a backup option. If so,
+ the option is processed and the contents of the
+ OEM Option buffer is updated to contain the appropriate
+ information. The command line may be futher tokenized
+ before this function returns if required by processed
+ option.
+
+
+ Returns(INT): IDS_OEMOPT_NOANOPTION - The target string is not an
+ option string.
+ IDS_OEMOPT_UNKNOWN - This is not a recognized batch
+ option - it may be an error
+ or a general application option.
+
+ other - One of the IDS_OEMOPT_* resource string ids
+ defined in OMSTRING.H.
+
+*****************************************************************************/
+
+INT OEM_ProcessBatchCmdOption (
+ OEMOPTS_PTR pOpts, //IO - Pointer to the options buffer to update
+ LPSTR pszOption, //I - Pointer to option string
+ LPSTR pszTokens, //I - Token seperators between cmd line options
+ LPSTR pszCmdLine) //IO - Pointer to partially tokenized command line
+ // ( not really needed, but may be modified
+ // as a side effect of strtok () )
+{
+ INT nOptId = IDS_OEMOPT_UNKNOWN; //default to unrecognized option
+
+ UNREFERENCED_PARAMETER ( pszCmdLine );
+
+ if ( pOpts && pszOption ) // Must have these to do anything!
+ {
+ switch ( ( nOptId = OEM_LookupBatchOption ( pszOption ) ) )
+ {
+ case IDS_OEMOPT_VALIDGUIOPTION:
+ break ;
+
+ case IDS_OEMOPT_APPEND:
+ pOpts->eMode = OEM_MODE_APPEND;
+ break;
+
+ case IDS_OEMOPT_VERIFY:
+ pOpts->eVerify = OEM_VERIFY_ON;
+ break;
+
+ case IDS_OEMOPT_RESTRICT:
+ pOpts->eAccess = OEM_ACCESS_RESTRICTED;
+ break;
+
+ case IDS_OEMOPT_DESCRIPTION:
+ {
+ // this is a little more complext than the others, since
+ // the description following the IDS_OEMOPT_DESCRIPTION token
+ // may be deliminated by quotes. So, we look ahead in the
+ // partially tokenized command line string to determine what
+ // the first non-token seperator character is, and, if it is
+ // a quote or double quote, use that in the call to strtok...
+
+ LPSTR pszTemp = & pszOption [ strlen ( pszOption ) + 1 ];
+ CHAR szDelim [2] = TEXT("\0");
+ INT cSeps = 0; //number of extra token seperators betw
+ //the option and the descripton strings
+ // ('extra' meaning 'more than one'
+
+ while ( *pszTemp && OEM_CharInSet ( *pszTemp, pszTokens ) )
+ {
+ ++pszTemp;
+ ++cSeps;
+ }
+ if ( *pszTemp )
+ {
+ if ( *pszTemp == TEXT('\'') )
+ {
+ szDelim [0] = TEXT('\'');
+ }
+ else
+ if ( *pszTemp == TEXT('"') )
+ {
+ szDelim [0] = TEXT('"');
+ }
+ if ( szDelim [0] ) //is it quote deliminated?
+ {
+ // bump up to the starting deliminator
+ // if there was more than one token seperator
+ // between the option and the first deliminator
+
+ if ( cSeps )
+ pszOption = strtok ( NULL, szDelim );
+
+ // and get the string up to the closing deliminator
+ pszOption = strtok ( NULL, szDelim );
+ }
+ else // option is not deliminated by quotes
+ {
+ pszOption = strtok ( NULL, pszTokens );
+ }
+ if ( pOpts->pszDescription )
+ free ( pOpts->pszDescription );
+ pOpts->pszDescription = NULL ;
+
+ if ( pszOption )
+ pOpts->pszDescription = OEM_StrDup ( pszOption );
+ }
+ }
+ break;
+
+ case IDS_OEMOPT_TYPE:
+ if ( pszOption = strtok ( NULL, pszTokens ) )
+ {
+ if ((pOpts->eType = OEM_LookupTypeOption ( pszOption ))
+ == OEM_TYPE_UNKNOWN)
+ {
+ nOptId = IDS_OEMOPT_UNKNOWN; //default to unrecognized option
+
+ //NTKLUG: error! unknown backup type specified. use normal
+ pOpts->eType = OEM_TYPE_NORMAL;
+ }
+ }
+ break;
+
+ case IDS_OEMOPT_LOGFILENAME:
+ //
+ // The previous logic did not account for logfile names with spaces. Example
+ // ... /L "LOG FILE". So this fix is to allow spaces in log file names. Kind
+ // of kludgie but implemented without changing much of the central logic for the
+ // whole string passed on the command line.
+ //
+
+ if ( pszOption = strtok ( NULL, pszTokens ) )
+ {
+ if ( pOpts->pszLogName )
+ free ( pOpts->pszLogName );
+
+ if ( *pszOption == TEXT( '\"' ) ) {
+ *pszCmdLine = TEXT( '\0' );
+ strcpy( pszCmdLine, ( pszOption + 1 ) );
+
+ // We don't want to call strtok if we see the next qoute
+
+ while ( !strchr( pszCmdLine, TEXT('\"') ) &&
+ (pszOption = strtok ( NULL, pszTokens ) ) ) {
+
+ strcat( pszCmdLine, TEXT( " " ) );
+ strcat( pszCmdLine, pszOption );
+ }
+
+ if ( strlen( pszCmdLine ) > 1 ) {
+ // Ignore closing quote character, string will always have ending
+ // quotes if it has a beginning quote. This is forced in some previous
+ // string routine.
+ *( pszCmdLine + strlen( pszCmdLine ) - 1 ) = TEXT( '\0' );
+ }
+ pOpts->pszLogName = OEM_StrDup ( pszCmdLine );
+
+ } else {
+
+ pOpts->pszLogName = OEM_StrDup ( pszOption );
+ }
+
+ }
+ break;
+
+ case IDS_OEMOPT_LOGEXCEPTIONS: //this is ignored if no logname given
+ pOpts->eLogOpt = OEM_LOG_SUMMARY_ONLY;
+ break;
+
+ case IDS_OEMOPT_BACKUP_REGISTRY:
+ pOpts->backupRegistry = TRUE;
+ break;
+
+ //default:
+ // either this is not an option, or it is an
+ // unrecognized option - must be an application option (not
+ // specific to batch mode backup) so just ignore it.
+ // No errors can be reported without more extensive processing.
+ }
+ }
+ return nOptId;
+}
+
+
+/*****************************************************************************
+
+ Name: OEM_LookupBatchOption
+
+ Description: If the target string contains a valid batch command
+ line option, look it up in the option table and
+ return the associated resource string identifier.
+
+ Returns(INT): IDS_OEMOPT_NOANOPTION - The target string is not an
+ option string.
+ IDS_OEMOPT_UNKNOWN - This is not a recognized batch
+ option - it may be an error
+ or a general application option.
+
+ other - One of the IDS_OEMOPT_* resource string ids
+ defined in OMSTRING.H.
+
+ INT OEM_LookupBatchOption (
+ LPSTR pszOption ) I - Targe option string to look for
+
+
+*****************************************************************************/
+
+// The option table is an array containing all of the batch options
+// in NULL-terminated strings.
+
+static LPSTR apszOptionsTable [ IDS_OEMOPT_COUNT ] = {NULL};
+
+// Initialize the option table by reading all the IDS_OEMOPT_* strings
+// This is only done the first time OEM_LookupBatchOption is called
+
+static BOOL OEM_InitOptTable ( VOID )
+{
+ CHAR szOpt [ IDS_OEM_MAX_LEN ]; //Temporary string buffer
+ INT count; //loop counter
+
+ memset ( apszOptionsTable, 0, sizeof ( apszOptionsTable ) );
+
+ for ( count = 0; count < IDS_OEMOPT_COUNT; ++count )
+ {
+ // Read in the option string and add it to the table
+
+ RSM_StringCopy ( IDS_OEMOPT_FIRST + count, szOpt, sizeof ( szOpt ) );
+ apszOptionsTable[ count ] = OEM_StrDup ( szOpt );
+ }
+ return TRUE;
+}
+/*----------------------------------------------------------------------*/
+
+INT OEM_LookupBatchOption (
+ LPSTR pszOption ) //I - Targe option string to look for
+{
+ INT idx = 0; //Start with first option
+ BOOL wasFound = FALSE; //Did we find the option?
+ INT nOptLen; //Length of target option string
+static CHAR szPrefix [ IDS_OEM_MAX_LEN ]; //option prefixes string buffer
+
+ if (!*szPrefix) // load the option prefixes string if first time
+ {
+ RSM_StringCopy ( IDS_OEMOPT_PREFIXES, szPrefix, sizeof ( szPrefix ) );
+ }
+ if( !pszOption //make sure we have a
+ || !OEM_CharInSet( *pszOption, szPrefix ) ) // valid option string
+ {
+ return IDS_OEMOPT_NOTANOPTION; // it's not an option!
+ }
+ else
+ if( ( nOptLen = strlen ( ++pszOption ) ) //must have a length!
+ && ( *apszOptionsTable || OEM_InitOptTable () )) //init table if needed
+ {
+ // cycle through the option table comparing each entry with the
+ // target option. Note that only as much of the option as the user
+ // has entered needs to be matched, since anything past the first
+ // character is optional.
+
+ while ( !(wasFound = (strnicmp ( pszOption,
+ apszOptionsTable[ idx ],
+ nOptLen ) == 0) )
+ && ++idx < IDS_OEMOPT_COUNT );
+ }
+ if ( !wasFound ) {
+ if ( !stricmp( pszOption, TEXT("MISSINGTAPE") ) ||
+ !stricmp( pszOption, TEXT("ZL") ) ||
+ !stricmp( pszOption, TEXT("Z") ) ||
+ !stricmp( pszOption, TEXT("CONTONMEMERR") ) ||
+ !stricmp( pszOption, TEXT("KEEPCATS") ) ||
+ !stricmp( pszOption, TEXT("CONFIG") ) ||
+ !stricmp( pszOption, TEXT("HC:ON") ) ||
+ !stricmp( pszOption, TEXT("HC:OFF") ) ) {
+ return IDS_OEMOPT_VALIDGUIOPTION ;
+ }
+
+
+ if ( !strnicmp( pszOption, TEXT("TAPE:"),5 ) &&
+ (pszOption[5] >= TEXT('0')) &&
+ (pszOption[5] <= TEXT('9')) ) {
+
+ return IDS_OEMOPT_VALIDGUIOPTION ;
+ }
+
+ if (!stricmp( pszOption, TEXT("NOPOLL") ) ) {
+ return IDS_OEMOPT_NOPOLLOPTION ;
+ }
+
+ if ( !strcmp( pszOption, TEXT("?") ) ) {
+ return IDS_OEMOPT_USAGE ;
+ }
+
+ }
+ return ( wasFound ) ? (idx + IDS_OEMOPT_FIRST) : IDS_OEMOPT_UNKNOWN;
+}
+
+
+/*****************************************************************************
+
+ Name: OEM_AddPathToBackupSet
+
+ Description: Given a path to a file, optionally containing wild cards
+ and/or a drive descriptor, insert it into the proper
+ backup set in the list of backup sets for the proper
+ drive. If no appropriate backup set exists, one will
+ be created and added to the backup set list.
+
+ The path must be of the form allowed for the target
+ system and may include whatever wildcards are allowed
+ by the file system.
+
+ If no drive is specified, the current drive will be used.
+ If no path is specified, the current path will be used.
+
+ Return(BOOL): TRUE if the path was added succesfully,
+ FALSE otherwise.
+
+*****************************************************************************/
+
+BOOL OEM_AddPathToBackupSets (
+ BSD_HAND hbsd, //IO - list of backup sets to update
+ DLE_HAND hdle, //I - list of drives
+ LPSTR pszPath ) //I - Path to insert into backup set
+{
+ GENERIC_DLE_PTR pdle = NULL;
+ BSET_OBJECT_PTR pbset = NULL;
+ BSD_PTR pbsd = NULL;
+ FSE_PTR pfse = NULL;
+ BE_CFG_PTR pbeConfig = NULL;
+ BOOLEAN star_star;
+ CHAR_PTR pchFile;
+ CHAR szDir [ MAX_UI_PATH_LEN + MAX_UI_FILENAME_LEN + 1 ] ;
+ INT16 nBufLen = (INT16)( MAX_UI_PATH_LEN + MAX_UI_FILENAME_LEN );
+ CHAR_PTR pszTemp;
+
+ OEM_FixPathCase( pszPath ) ;
+
+ pszTemp = calloc( strsize( pszPath ) + strsize( TEXT("\\*.* ") ), 1 ) ;
+
+ if ( pszTemp == NULL ) {
+
+ return FALSE ;
+ }
+ strcpy( pszTemp, pszPath ) ;
+ if ( pszTemp[ strlen(pszTemp) - 1 ] != TEXT( '\\' ) ) {
+ strcat( pszTemp, TEXT( "\\*.*") ) ;
+ }
+ else {
+ strcat( pszTemp, TEXT( "*.*") ) ;
+ }
+ pszPath = pszTemp;
+
+ if ( FS_ParsePath( hdle, (CHAR_PTR)pszPath,
+ &pdle, (CHAR_PTR)szDir,
+ &nBufLen, &pchFile, &star_star ) != SUCCESS )
+ {
+ return FALSE; // NTKLUG: need error handling here!
+ }
+ if ( pszTemp )
+ {
+ free ( pszTemp );
+ pszTemp = NULL;
+ }
+ pszPath = NULL; //can't use this anymore
+
+ if ( BSD_CreatFSE( &pfse, (INT16)INCLUDE,
+ (INT8_PTR) szDir,
+ (INT16) nBufLen,
+ (INT8_PTR) pchFile,
+ (INT16) strsize( pchFile ),
+ (BOOLEAN) USE_WILD_CARD,
+ (BOOLEAN) TRUE ) != SUCCESS )
+ {
+ return FALSE; // NTKLUG: need error handling here!
+ }
+ else
+ {
+ pbsd = BSD_FindByDLE ( hbsd, pdle ); //look for the right BSD
+ }
+ if ( pbsd == NULL )
+ {
+ pbeConfig = BEC_CloneConfig( CDS_GetPermBEC() );
+ BEC_UnLockConfig( pbeConfig );
+
+ BSD_Add( hbsd, &pbsd, pbeConfig, NULL,
+ pdle, (UINT32)-1L, (UINT16)-1, (INT16)-1, NULL, NULL );
+ }
+ if ( pbsd != NULL )
+ {
+ BSD_AddFSE( pbsd, pfse );
+
+ return TRUE; //SUCCESS
+ }
+ return FALSE; //FAILED!
+}
+
+#ifdef OEM_EMS
+/*****************************************************************************
+
+ Name: OEM_AddEMSServerToBackupSet
+
+ Description: Given a name of an Exchange server, insert it into the proper
+ backup set in the list of backup sets for the proper
+ drive. If no appropriate backup set exists, one will
+ be created and added to the backup set list.
+
+ The path must be of the form allowed for the target
+ system and may include whatever wildcards are allowed
+ by the file system.
+
+ Return(BOOL): TRUE if the server was added succesfully,
+ FALSE otherwise.
+
+*****************************************************************************/
+
+BOOL OEM_AddEMSServerToBackupSets (
+ BSD_HAND hbsd, //IO - list of backup sets to update
+ DLE_HAND hdle, //I - list of drives
+ LPSTR pszServer, //I - Server name to insert into backup set
+ UINT8 uType ) //I - FS_EMS_MDB_ID (Monolithic) or
+ // FS_EMS_DSA_ID (DSA)
+{
+ GENERIC_DLE_PTR pdle = NULL;
+ BSET_OBJECT_PTR pbset = NULL;
+ BSD_PTR pbsd = NULL;
+ FSE_PTR pfse = NULL;
+ BE_CFG_PTR pbeConfig = NULL;
+ CHAR_PTR pszTemp;
+
+ pszTemp = pszServer;
+
+ // Extract off the leading '\'s from the server name.
+ while ( TEXT ('\\') == *pszTemp ) pszTemp++;
+
+ if ( ( !pszTemp ) || ( TEXT ( '\0' ) == *pszTemp ) )
+ return FALSE;
+
+ // Things that have to happen in order. First, add name to EMS server list.
+ if ( SUCCESS == EMS_AddToServerList ( hdle, pszTemp ) ) {
+ if ( SUCCESS != FS_FindDrives( FS_EMS_DRV, hdle, pbeConfig = CDS_GetPermBEC(), 0 ) ) {
+ return FALSE;
+ }
+ }
+
+ // Next, find the DLE for the server name and type.
+ if ( SUCCESS != DLE_FindByEMSServerName( hdle, pszTemp, uType, &pdle ) ) {
+ return FALSE;
+ }
+
+ if ( BSD_CreatFSE( &pfse, (INT16)INCLUDE,
+ (CHAR_PTR) TEXT( "" ),
+ (INT16) sizeof( CHAR ),
+ (CHAR_PTR) ALL_FILES,
+ (INT16) ALL_FILES_LENG,
+ (BOOLEAN) USE_WILD_CARD,
+ (BOOLEAN) TRUE ) != SUCCESS ) {
+
+ return FALSE; // NTKLUG: need error handling here!
+
+ } else {
+
+ pbsd = BSD_FindByDLE ( hbsd, pdle ); //look for the right BSD
+ }
+ if ( pbsd == NULL )
+ {
+ pbeConfig = BEC_CloneConfig( CDS_GetPermBEC() );
+ BEC_UnLockConfig( pbeConfig );
+
+ BSD_Add( hbsd, &pbsd, pbeConfig, NULL,
+ pdle, (UINT32)-1L, (UINT16)-1, (INT16)-1, NULL, NULL );
+ }
+ if ( pbsd != NULL )
+ {
+ BSD_AddFSE( pbsd, pfse );
+
+ return TRUE; //SUCCESS
+ }
+ return FALSE; //FAILED!
+}
+#endif OEM_EMS
+
+/***************************************************************************
+
+ Name: CharInSet
+
+ Description: Search the set of characters contained in a set for
+ one that matches the target character.
+
+ Parameters: CHAR chTarg : I - The target character to search for.
+ LPSTR pszSet: I - A NULL-terminated string containing
+ the set of charaters to search.
+
+ Returns: BOOL : TRUE if a matching character was found in the set,
+ FALSE otherwise.
+
+****************************************************************************/
+
+INT OEM_CharInSet ( CHAR chTarg, LPSTR pszSet )
+{
+ if ( !pszSet )
+ return FALSE;
+
+ while ( *pszSet && chTarg != *pszSet ) ++pszSet;
+
+ return ( *pszSet != 0 );
+}
+
+/***************************************************************************
+
+ Name: OEM_StrDup
+
+ Description: Replacement for the strdup() function. strdup() may
+ not be called because malloc, calloc, etc. may be
+ mapped to alternate functions.
+
+ Parameters: LPSTR pszSrc: I - Source string to duplicate
+
+ Returns: LPSTR: pointer to allocated string copy.
+
+****************************************************************************/
+
+static LPSTR OEM_StrDup ( LPSTR pszSrc )
+{
+ LPSTR pszResult = NULL;
+
+ if ( pszSrc )
+ {
+ pszResult = malloc ( strsize ( pszSrc ) );
+
+ if ( pszResult )
+ {
+ strcpy ( pszResult, pszSrc );
+ }
+ }
+ return pszResult;
+}
+
+
+#ifdef OEM_EMS
+
+/*************************************************************************/
+/**
+
+ Name: DLE_FindByEMSServerName()
+
+ Description: This function scans through the DLE tree looking for the
+ DLE with the EMS server name and specified type.
+
+ Modified: 9/15/1994
+
+ Returns: NOT_FOUND
+ SUCCESS
+
+ Notes: If no dle can be found then NULL is returned as the
+ DLE pointer.
+
+ See also: $/SEE( )$
+
+ Declaration: Ombatch.h
+/**/
+/* begin declaration */
+
+INT16 DLE_FindByEMSServerName (
+ DLE_HAND hand, /* I - DLE list handle */
+ LPSTR name, /* I - name to search for */
+ UINT8 uType, /* I - type of dle to search for */
+ GENERIC_DLE_PTR *dle ) /* O - pointer to matched DLE */
+
+{
+ GENERIC_DLE_PTR temp_dle ;
+ GENERIC_DLE_PTR found_dle ;
+ UINT8 uCurType;
+
+ *dle = NULL ;
+
+ if ( (name == NULL) || (hand == NULL) ) {
+ return FS_NOT_FOUND ;
+
+ } else {
+
+ if ( NULL == (temp_dle = (GENERIC_DLE_PTR)QueueHead( &(hand->q_hdr) )) )
+ return FS_NOT_FOUND;
+
+ found_dle = NULL ;
+
+ // Recurse on each of the EMS device with the server name that we're looking for.
+ do {
+
+ uCurType = DLE_GetDeviceType( temp_dle );
+ if( FS_EMS_DRV == uCurType ) {
+
+ EMS_RecurseSearchDLE ( temp_dle, &found_dle, name, uType ) ;
+
+ }
+
+ } while ( (NULL == found_dle) && (SUCCESS == DLE_GetNext( &temp_dle )) ) ;
+
+ if ( found_dle != NULL ) {
+
+ *dle = found_dle ;
+
+ } else {
+
+ return FS_NOT_FOUND ;
+ }
+ }
+ return SUCCESS ;
+}
+
+/*************************************************************************/
+/**
+
+ Name: EMS_RecurseSearchDLE()
+
+ Description: Does a recursive scan on an EMS drive for the server matching the
+ the description and calls EMS_GetDleByEmsType to find the child DLE
+ corresponding to the type..
+
+ Modified: 9/15/1994
+
+ Returns: Nothing.
+
+ Notes: If no dle can be found then NULL is returned as the
+ DLE pointer.
+
+ See also: $/SEE( )$
+
+ Declaration: Private
+
+**/
+/* begin declaration */
+static VOID EMS_RecurseSearchDLE (
+ GENERIC_DLE_PTR dle_tree, // I - DLE subtree root to search
+ GENERIC_DLE_PTR *dle, // O - pointer to matched DLE
+ LPSTR pszName, // I - name of server
+ UINT8 uType ) // I - type of dle to search for
+{
+ GENERIC_DLE_PTR dle_child;
+
+ while ( (dle_tree != NULL) && (*dle == NULL) ) {
+
+ if ( EMS_SERVER == DLE_GetDeviceSubType( dle_tree ) ) {
+
+ if ( 0 == strnicmp( pszName, DLE_GetDeviceName( dle_tree ), strsize( pszName ) ) ) {
+
+ // Get the specified DSA or MDB DLE for the server.
+ EMS_GetDleByEmsType( dle_tree, dle, uType );
+ }
+ } else {
+
+ // Not at server level - recurse through the children looking for the server name.
+ if ( (QueueCount( &(dle_tree->child_q) ) != 0) &&
+ (SUCCESS == DLE_GetFirstChild( dle_tree, &dle_child )) ) {
+
+ EMS_RecurseSearchDLE( dle_child, dle, pszName, uType );
+ }
+ }
+ if( SUCCESS != DLE_GetNext( &dle_tree ) )
+ return ;
+ }
+}
+
+
+/*************************************************************************/
+/**
+
+ Name: EMS_GetDleByEmsType()
+
+ Description: Iterates through child DLEs of an EMS server looking for
+ the DLE of the specified type.
+
+ Modified: 9/15/1994
+
+ Returns: Nothing.
+
+ Notes: If no dle can be found then NULL is returned as the
+ DLE pointer.
+
+ See also: $/SEE( )$
+
+ Declaration: Private
+
+**/
+/* begin declaration */
+
+static VOID EMS_GetDleByEmsType(
+ GENERIC_DLE_PTR dle_tree, // I - Matching EMS server dle
+ GENERIC_DLE_PTR *dle, // O - pointer to matched dle
+ UINT8 uType ) // I - type of dle to search for
+{
+ GENERIC_DLE_PTR dle_child;
+
+ *dle = NULL;
+
+ if ( SUCCESS == DLE_GetFirstChild( dle_tree, &dle_child ) )
+ {
+
+ /* Now that we've found the first child, let's try them all until
+ we find the one with the correct type. */
+ do {
+
+ if ( DLE_GetOsId( dle_child ) == uType ) {
+
+ *dle = dle_child ;
+ }
+
+ } while ( (NULL == *dle) &&
+ (SUCCESS == DLE_GetNext( &dle_child )) ) ;
+
+ }
+}
+
+#endif //OEM_EMS
+
+void OEM_FixPathCase( LPSTR pszPath )
+{
+CHAR CurDir[512] ;
+WIN32_FIND_DATA find_data;
+HANDLE find_hand;
+CHAR_PTR new_path_start ;
+CHAR_PTR old_str ;
+CHAR_PTR temp_str ;
+CHAR_PTR temp_str_start ;
+INT sub_dir_name_size ;
+
+ if (pszPath[1] != TEXT(':') ) {
+ return ;
+ }
+ CurDir[0] = pszPath[0] ;
+ CurDir[1] = TEXT(':') ;
+ CurDir[2] = TEXT('\\') ;
+ CurDir[3] = TEXT('\0') ;
+ temp_str = &(CurDir[3]) ;
+
+// new_path_start must point to first char of path name
+ if ( pszPath[2] == TEXT('\\') ) {
+ old_str = &pszPath[3] ;
+ } else {
+ old_str = &pszPath[2] ;
+ }
+
+ while ( *old_str != TEXT('\0')) {
+
+ temp_str_start = temp_str ;
+ new_path_start = old_str ;
+ sub_dir_name_size = 0 ;
+
+ while ( (*old_str != TEXT('\0')) && (*old_str != TEXT('\\')) ) {
+ *temp_str = *old_str ;
+ temp_str ++ ; old_str++ ;
+ sub_dir_name_size++ ;
+ }
+
+ *temp_str = TEXT('*') ;
+ *(temp_str+1) = TEXT('\0') ;
+
+ find_hand = FindFirstFile( CurDir, &find_data ) ;
+
+ if (find_hand == INVALID_HANDLE_VALUE ) {
+ return ;
+ }
+ while( ( strlen(find_data.cFileName) != (unsigned short)sub_dir_name_size ) ||
+ memicmp( find_data.cFileName, temp_str_start, sub_dir_name_size*sizeof(CHAR) ) ) {
+
+ if ( !FindNextFile( find_hand, &find_data ) ) {
+ FindClose( find_hand ) ;
+ return ;
+ }
+ }
+
+ FindClose( find_hand ) ;
+
+ memcpy( new_path_start, find_data.cFileName, sub_dir_name_size * sizeof(CHAR) ) ;
+
+ *temp_str = *old_str ;
+
+ if ( *old_str == TEXT('\0')) {
+ break ;
+ }
+
+ temp_str ++ ; old_str++ ;
+
+ }
+
+}
+
diff --git a/private/utils/ntbackup/src/ombkup.dlg b/private/utils/ntbackup/src/ombkup.dlg
new file mode 100644
index 000000000..772407757
--- /dev/null
+++ b/private/utils/ntbackup/src/ombkup.dlg
@@ -0,0 +1,67 @@
+
+IDD_BACKUPSET DIALOG 5, 15, 268, 236
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Backup Information"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Current Tape:",-1,6,6,59,10
+ CONTROL "",IDD_BKUP_CURRENT_TAPE_NAME,"Static",SS_LEFTNOWORDWRAP |
+ SS_NOPREFIX | WS_GROUP,62,6,200,12
+ LTEXT "Creation Date:",-1,6,21,59,10
+ LTEXT "",IDD_BKUP_CREATION_DATE,62,21,200,10,SS_NOPREFIX
+ LTEXT "Owner:",-1,6,36,59,10
+ LTEXT "",IDD_BKUP_OWNER,62,36,200,10,SS_NOPREFIX
+ LTEXT "&Tape Name:",IDD_BKUP_TAPE_NAME_TEXT,6,51,52,12
+ EDITTEXT IDD_BKUP_TAPE_NAME,62,49,140,12,ES_AUTOHSCROLL |
+ WS_GROUP
+ CONTROL "&Verify After Backup",IDD_BKUP_AUTO_VERIFY,"Button",
+ BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,6,66,89,10
+ CONTROL "Backup Local Re&gistry",IDD_BKUP_REGISTRY,"Button",
+ BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,110,66,89,10
+ CONTROL "R&estrict Access to Owner or Administrator",
+ IDD_BKUP_RESTRICT_ACCESS,"Button",BS_AUTOCHECKBOX |
+ WS_GROUP | WS_TABSTOP,6,78,194,10
+ CONTROL "Hardware &Compression",IDD_BKUP_HARDCOMP,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,6,90,194,10
+ GROUPBOX "Operation",105,210,45,52,44,WS_GROUP
+ CONTROL "&Append ",IDD_BKUP_APPEND,"Button",BS_AUTORADIOBUTTON |
+ WS_GROUP | WS_TABSTOP,214,61,46,11
+ CONTROL "&Replace ",IDD_BKUP_REPLACE,"Button",BS_AUTORADIOBUTTON,
+ 214,75,46,11
+ SCROLLBAR IDD_BKUP_SCROLLBAR,249,106,11,54,SBS_VERT | WS_TABSTOP
+ GROUPBOX "Backup Set Information ",IDD_BKUP_INFO_TITLE,6,102,256,
+ 58
+ LTEXT "Drive Name:",IDD_BKUP_DRIVE_NAME_TEXT,12,116,48,10,NOT
+ WS_GROUP
+ LTEXT "",IDD_BKUP_DRIVE_NAME,62,116,186,10,SS_NOPREFIX | NOT
+ WS_GROUP
+ LTEXT "&Description:",IDD_BKUP_DESC_TEXT,12,130,48,10,
+ NOT WS_GROUP
+ EDITTEXT IDD_BKUP_DESCRIPTION,62,128,183,12,ES_AUTOHSCROLL |
+ WS_GROUP
+ LTEXT "&Backup Type:",IDD_BKUP_TYPE_TEXT,12,146,48,10,
+ NOT WS_GROUP
+ COMBOBOX IDD_BKUP_METHOD,62,144,84,58,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ COMBOBOX IDD_XCHG_BKUP_METHOD,62,144,84,58,CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ LTEXT "Microsoft Exchange:",IDD_BKUP_XCHG_NAME_TEXT,
+ 12,116,80,10,NOT WS_VISIBLE | NOT WS_GROUP
+ LTEXT "",IDD_BKUP_XCHG_NAME,90,116,155,10,NOT WS_VISIBLE |
+ SS_NOPREFIX | NOT WS_GROUP | SS_LEFTNOWORDWRAP
+ GROUPBOX "Log Information",-1,6,164,256,46
+ LTEXT "&Log File:",-1,12,180,48,10
+ EDITTEXT IDD_BKUP_LOG_FILENAME,62,178,163,12,ES_AUTOHSCROLL |
+ WS_GROUP
+ PUSHBUTTON "...",IDD_BKUP_LOG_BROWSE,224,178,15,12,WS_GROUP
+ CONTROL "&Full Detail",IDD_BKUP_LOG_FULL,"Button",
+ BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,62,196,65,10
+ CONTROL "&Summary Only",IDD_BKUP_LOG_SUMMARY,"Button",
+ BS_AUTORADIOBUTTON,129,196,65,10
+ CONTROL "D&on't Log",IDD_BKUP_LOG_NONE,"Button",
+ BS_AUTORADIOBUTTON,196,196,45,10
+ DEFPUSHBUTTON "OK",IDD_BKUP_OK_BUTTON,48,216,40,14,WS_GROUP
+ PUSHBUTTON "Cancel",IDD_BKUP_CANCEL_BUTTON,112,216,40,14
+ PUSHBUTTON "&Help",IDD_BKUP_HELP_BUTTON,180,216,40,14
+END
+
diff --git a/private/utils/ntbackup/src/ombrowse.dlg b/private/utils/ntbackup/src/ombrowse.dlg
new file mode 100644
index 000000000..3dfac9496
--- /dev/null
+++ b/private/utils/ntbackup/src/ombrowse.dlg
@@ -0,0 +1,105 @@
+/******************************************************************************
+Copyright (c) Arcada Software, Inc. 1994
+GSH
+
+ Name: ombrowse.dlg
+
+ Description:
+
+ $Log: G:\UI\LOGFILES\OMBROWSE.DLV $
+
+ Rev 1.2 02 Feb 1994 11:29:54 Glenn
+ Added log file browse template.
+
+******************************************************************************/
+
+IDD_BROWSE DIALOG 139, 24, 220, 134
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Browse Path"
+FONT 8, "MS Shell Dlg"
+BEGIN
+
+ LTEXT "&Directories:", -1, 7, 6, 140, 9
+ LTEXT "", stc1, 7, 18, 140, 9, SS_NOPREFIX
+ LISTBOX lst2, 7, 32, 140, 68, LBS_SORT | LBS_OWNERDRAWFIXED |
+ LBS_HASSTRINGS | LBS_DISABLENOSCROLL | WS_VSCROLL | WS_HSCROLL |
+ WS_TABSTOP
+
+ LTEXT "Dri&ves:", stc4, 7, 104, 140, 9
+ COMBOBOX cmb2, 7, 114, 140, 68, CBS_DROPDOWNLIST |
+ CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | CBS_SORT |
+ CBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_TABSTOP
+
+ DEFPUSHBUTTON "OK", IDOK, 160, 6, 50, 14, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, 160, 24, 50, 14, WS_GROUP
+ PUSHBUTTON "&Help", psh15, 160, 46, 50, 14, WS_GROUP
+
+ // CONTROLS NOT USED - but needed for template.
+
+ LTEXT "File &Name:", stc3, 137, 115, 1, 1, NOT WS_VISIBLE |
+ WS_GROUP
+ EDITTEXT edt1, 112, 90, 1, 1, ES_AUTOHSCROLL |
+ NOT WS_VISIBLE | NOT WS_TABSTOP
+ LISTBOX lst1, 129, 92, 1, 1, LBS_SORT | LBS_OWNERDRAWFIXED |
+ LBS_HASSTRINGS | LBS_DISABLENOSCROLL | WS_VSCROLL |
+ NOT WS_VISIBLE
+
+ LTEXT "List Files of &Type:", stc2, 141, 94, 1, 1,
+ NOT WS_VISIBLE | NOT WS_GROUP
+ COMBOBOX cmb1, 143, 105, 1, 1, CBS_DROPDOWNLIST | CBS_AUTOHSCROLL |
+ WS_BORDER | WS_VSCROLL | NOT WS_VISIBLE
+
+ CONTROL "&Read Only", chx1, "Button", BS_AUTOCHECKBOX |
+ WS_VISIBLE, 160, 68, 1, 1
+
+END
+
+
+IDD_LOGFILEBROWSE DIALOG LOADONCALL MOVEABLE DISCARDABLE
+36, 24, 264, 134
+CAPTION "Log File Browse"
+STYLE WS_CAPTION | WS_SYSMENU | WS_POPUP | DS_MODALFRAME
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "File &Name:", stc3, 6, 6, 76, 9
+ CONTROL "", edt1, "edit", ES_LEFT | ES_AUTOHSCROLL | WS_BORDER |
+ WS_TABSTOP | WS_CHILD,
+ 6, 16, 90, 12
+ CONTROL "", lst1, "listbox",
+ LBS_SORT | LBS_HASSTRINGS | LBS_NOTIFY | LBS_DISABLENOSCROLL
+ | WS_VSCROLL | WS_CHILD | WS_BORDER | WS_TABSTOP
+ | LBS_OWNERDRAWFIXED,
+ 6, 32, 90, 68
+
+ LTEXT "&Directories:", -1, 110, 6, 92, 9
+ LTEXT "", stc1, 110, 18, 92, 9, SS_NOPREFIX
+ CONTROL "", lst2, "listbox",
+ LBS_SORT | LBS_HASSTRINGS | LBS_NOTIFY | LBS_DISABLENOSCROLL
+ | WS_VSCROLL | WS_HSCROLL | WS_CHILD | WS_BORDER | WS_TABSTOP
+ | LBS_OWNERDRAWFIXED,
+ 110, 32, 92, 68
+
+ LTEXT "List Files of &Type:", stc2, 6, 104, 90, 9
+ CONTROL "", cmb1, "combobox", CBS_DROPDOWNLIST | CBS_AUTOHSCROLL |
+ WS_BORDER | WS_VSCROLL | WS_TABSTOP | WS_CHILD,
+ 6, 114, 90, 36
+
+ LTEXT "Dri&ves:", stc4, 110, 104, 92, 9
+ CONTROL "", cmb2, "combobox",
+ CBS_SORT | CBS_HASSTRINGS | CBS_OWNERDRAWFIXED | CBS_DROPDOWNLIST
+ | WS_CHILD | CBS_AUTOHSCROLL | WS_BORDER | WS_VSCROLL
+ | WS_TABSTOP,
+ 110, 114, 92, 68
+
+ DEFPUSHBUTTON "OK", IDOK, 208, 6, 50, 14, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, 208, 24, 50, 14, WS_GROUP
+
+ PUSHBUTTON "&Help", pshHelp, 208, 46, 50, 14, WS_GROUP
+// AUTOCHECKBOX "&Read Only", chx1, 208, 68, 50, 12,
+// WS_TABSTOP | WS_GROUP
+
+// PUSHBUTTON "Net&work...", psh14, 208, 114, 50, 14, WS_GROUP
+
+
+END
+
diff --git a/private/utils/ntbackup/src/omcat.bmp b/private/utils/ntbackup/src/omcat.bmp
new file mode 100644
index 000000000..850fb081e
--- /dev/null
+++ b/private/utils/ntbackup/src/omcat.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/omcatlog.dlg b/private/utils/ntbackup/src/omcatlog.dlg
new file mode 100644
index 000000000..5ca32c34f
--- /dev/null
+++ b/private/utils/ntbackup/src/omcatlog.dlg
@@ -0,0 +1,15 @@
+
+IDD_CATALOG DIALOG 27, 32, 270, 94
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Job Status - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+
+ CONTROL "OK", IDD_JS_OK, "BUTTON", BS_PUSHBUTTON | WS_GROUP | WS_TABSTOP, 66, 77, 40, 12
+ CONTROL "&Abort", IDD_JS_ABORT, "BUTTON", BS_PUSHBUTTON | WS_GROUP | WS_TABSTOP, 116, 77, 40, 12
+ CONTROL "&Help", IDD_JS_HELP, "BUTTON", BS_PUSHBUTTON | WS_TABSTOP, 167, 77, 40, 12
+
+ LTEXT "Summary", 0x0069, 3, 4, 39, 8
+ LISTBOX IDD_JS_LISTBOX, 4, 15, 261, 61, WS_VSCROLL | WS_HSCROLL |
+ WS_TABSTOP
+END
diff --git a/private/utils/ntbackup/src/omcdisk.bmp b/private/utils/ntbackup/src/omcdisk.bmp
new file mode 100644
index 000000000..8b78cb20a
--- /dev/null
+++ b/private/utils/ntbackup/src/omcdisk.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/omcheck.bmp b/private/utils/ntbackup/src/omcheck.bmp
new file mode 100644
index 000000000..cf4d199b6
--- /dev/null
+++ b/private/utils/ntbackup/src/omcheck.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/omeject.bmp b/private/utils/ntbackup/src/omeject.bmp
new file mode 100644
index 000000000..341d5d762
--- /dev/null
+++ b/private/utils/ntbackup/src/omeject.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/omerase.bmp b/private/utils/ntbackup/src/omerase.bmp
new file mode 100644
index 000000000..141701586
--- /dev/null
+++ b/private/utils/ntbackup/src/omerase.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/omerase.dlg b/private/utils/ntbackup/src/omerase.dlg
new file mode 100644
index 000000000..14fdc77e4
--- /dev/null
+++ b/private/utils/ntbackup/src/omerase.dlg
@@ -0,0 +1,23 @@
+
+IDD_ERASE DIALOG 32, 47, 288, 100
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Erase Tape"
+FONT 8, "MS Shell Dlg"
+BEGIN
+
+ ICON 0, IDD_ERASE_EXCLAMATION_BITMAP, 8, 6, 20, 20
+ LTEXT "WARNING: You have chosen to erase the contents of this tape. All of the information on the tape will be destroyed!",
+ IDD_ERASE_LINE2, 33, 6, 204, 46, SS_NOPREFIX
+
+ LTEXT "", IDD_ERASE_LINE1, 33, 32, 204, 46, SS_NOPREFIX
+
+ DEFPUSHBUTTON "Cancel", IDD_ERASE_CANCEL_BUTTON, 245, 27, 40, 14
+ PUSHBUTTON "&Continue", IDD_ERASE_CONTINUE_BUTTON, 245, 8, 40, 14
+ PUSHBUTTON "&Help", IDD_ERASE_HELP_BUTTON, 245, 46, 40, 14
+
+ CONTROL "&Quick Erase", IDD_ERASE_QUICK_BUTTON, "Button",
+ BS_AUTORADIOBUTTON, 97, 80, 55, 10
+ CONTROL "&Secure Erase", IDD_ERASE_SECURE_BUTTON, "Button",
+ BS_AUTORADIOBUTTON, 160, 80, 64, 10
+END
+
diff --git a/private/utils/ntbackup/src/omevent.c b/private/utils/ntbackup/src/omevent.c
new file mode 100644
index 000000000..a9bcdd75e
--- /dev/null
+++ b/private/utils/ntbackup/src/omevent.c
@@ -0,0 +1,329 @@
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+DAVEV
+
+ Name: omevent.c
+
+ Description: This file contains the functions for the Microsoft
+ OEM version of Maynstream for Windows & Win32/NT to
+ support Event Logging.
+
+ Events must be logged at the start and end of the
+ following backup application operations:
+
+ Backup, Restore, Retension and Erase
+
+ For Backup and Restore opperations, the state of
+ the verify flag must be recorded.
+
+ For Backup operations the following information must
+ be supplied:
+
+ - Append or Replace,
+ - Type: Incremental, Differential, Daily,
+ Normal or Copy
+ $Log: G:/UI/LOGFILES/OMEVENT.C_V $
+
+ Rev 1.9 14 May 1993 14:40:54 DARRYLP
+Modified event logging text
+
+ Rev 1.8 10 May 1993 13:01:18 DARRYLP
+Changed the style of display to eliminate cryptic app logs.
+
+ Rev 1.7 11 Nov 1992 16:33:40 DAVEV
+UNICODE: remove compile warnings
+
+ Rev 1.6 01 Nov 1992 16:04:10 DAVEV
+Unicode changes
+
+ Rev 1.5 04 Oct 1992 19:39:32 DAVEV
+Unicode Awk pass
+
+ Rev 1.4 30 Sep 1992 10:46:06 DAVEV
+Unicode strlen verification, MikeP's chgs from MS
+
+ Rev 1.3 01 Sep 1992 13:04:00 STEVEN
+id name has changed
+
+ Rev 1.2 31 Aug 1992 09:56:30 DAVEV
+
+ Rev 1.1 31 Aug 1992 09:48:34 DAVEV
+Added Verify Events
+
+******************************************************************************/
+
+//#ifdef OEM_MSOFT // module compiled ONLY for Microsoft OEM version
+
+#include "all.h"
+
+#include <winnetwk.h>
+#include "bkuevent.h"
+
+void OMEVENT_LogEvent ( DWORD dwEventId, //id of event message
+ WORD wEventType, //type of event
+ INT cStrings, //number of replacement strings
+ ... ) //replacement strings
+{
+#if defined ( OS_WIN32 )
+
+ static HANDLE hEvent = NULL;
+ static CHAR szSource [ IDS_OEMEVENT_MAX_SOURCE_LEN ] = TEXT("");
+
+#define MAX_USERNAME_LENGTH 200 //NTKLUG: Remove when Win32 has a define for this!!
+ static CHAR szUserName [ MAX_USERNAME_LENGTH ] = TEXT("");
+ static DWORD dwUserLen = MAX_USERNAME_LENGTH;
+
+ if ( hEvent == NULL )
+ {
+ RSM_StringCopy ( IDS_OEMEVENT_SOURCE_NAME,
+ szSource, sizeof ( szSource ) );
+
+ GetUserName ( szUserName, &dwUserLen );
+ hEvent = RegisterEventSource ( NULL, szSource );
+ }
+ if ( hEvent != NULL )
+ {
+ LPSTR apszStrings [ 10 ];
+ INT i;
+ va_list ap;
+
+ va_start ( ap, cStrings );
+
+ memset ( apszStrings, 0, sizeof (apszStrings) );
+ for ( i = 0; i < cStrings; ++i )
+ {
+ apszStrings [ i ] = va_arg ( ap, LPSTR );
+ if ( apszStrings [i] && !strlen (apszStrings [i]) )
+ {
+ // note: ReportEvent will fail if a zero-length replacement
+ // string is passed. I have reported this as an NT bug.
+ strcpy ( apszStrings [i], TEXT(" ") );
+ }
+ }
+ va_end ( ap );
+
+ if ( !ReportEvent ( hEvent,
+ wEventType, //type of event
+ (WORD)0, //category
+ dwEventId, //id of message
+ NULL,//szUserName, //Current User Name
+ (WORD)cStrings, //# of strings
+ (DWORD)0, //# bytes of data
+ apszStrings, //msg replacement strings
+ NULL ) ) //binary data
+ {
+ DWORD dwLastError = GetLastError ();
+ zprintf ( DEBUG_USER_INTERFACE, IDS_OEMLOG_ERROR_REPORTEVENT,
+ dwLastError, dwEventId, wEventType, cStrings );
+ for ( i = 0; i < cStrings; ++i )
+ {
+ zprintf ( DEBUG_USER_INTERFACE, IDS_OEMLOG_ERROR_EVENTSTRING,
+ i, apszStrings [ i ] );
+ }
+ }
+ }
+#endif
+}
+
+
+// Save the backup set info recieved on a LogBegin for Backup or Restore for
+// use in the associated LogEnd call
+
+#define OMEVT_MAX_DRIVE 512
+
+static struct _OMEVT_BACKUPSETINFO {
+
+ CHAR szDrive [ OMEVT_MAX_DRIVE ];
+ CHAR szVerify [ 8 ];
+ CHAR szMode [ 8 ];
+ CHAR szType [ 8 ];
+
+ } mwBkpSet;
+
+void OMEVENT_LogBeginBackup (
+ CHAR_PTR pszDrive, //Drive name
+ INT16 verify, //VERIFY ON or OFF
+ INT16 mode, //APPEND or REPLACE
+ INT16 type ) //NORMAL, COPY, etc.
+{
+ memset ( &mwBkpSet, 0, sizeof ( mwBkpSet ) );
+ strncpy ( mwBkpSet.szDrive, pszDrive, OMEVT_MAX_DRIVE-1 );
+ if (verify == 0)
+ {
+ strcpy(mwBkpSet.szVerify, TEXT("Off"));
+ } else
+ {
+ strcpy(mwBkpSet.szVerify, TEXT("On"));
+ }
+ if (mode == 0)
+ {
+ strcpy(mwBkpSet.szMode, TEXT("Replace"));
+ } else
+ {
+ strcpy(mwBkpSet.szMode, TEXT("Append"));
+ }
+ switch(type)
+ {
+ case 1:
+ strcpy(mwBkpSet.szType, TEXT("Normal"));
+ break;
+
+ case 2:
+ strcpy(mwBkpSet.szType, TEXT("Copy"));
+ break;
+
+ case 3:
+ strcpy(mwBkpSet.szType, TEXT("Dif"));
+ break;
+
+ case 4:
+ strcpy(mwBkpSet.szType, TEXT("Inc"));
+ break;
+ }
+
+ OMEVENT_LogEvent((DWORD)EVENT_BKUP_BEGINBACKUP,
+ (WORD)EVENTLOG_INFORMATION_TYPE,
+ 4, mwBkpSet.szDrive, mwBkpSet.szVerify,
+ mwBkpSet.szMode, mwBkpSet.szType );
+}
+
+
+void OMEVENT_LogEndBackup(BOOL bError ) //Did an error occur?
+{
+ OMEVENT_LogEvent ( (DWORD)EVENT_BKUP_ENDBACKUP,
+ (WORD) ((bError) ? EVENTLOG_ERROR_TYPE
+ : EVENTLOG_INFORMATION_TYPE),
+ 4, mwBkpSet.szDrive, mwBkpSet.szVerify,
+ mwBkpSet.szMode, mwBkpSet.szType );
+}
+
+
+void OMEVENT_LogBeginRestore (
+ CHAR_PTR pszDrive, //Drive name
+ INT16 verify ) //VERIFY ON or OFF
+{
+ memset ( &mwBkpSet, 0, sizeof ( mwBkpSet ) );
+ strncpy ( mwBkpSet.szDrive, pszDrive, OMEVT_MAX_DRIVE-1 );
+ if (verify == 0)
+ {
+ strcpy(mwBkpSet.szVerify, TEXT("Off"));
+ } else
+ {
+ strcpy(mwBkpSet.szVerify, TEXT("On"));
+ }
+
+ OMEVENT_LogEvent ( (DWORD)EVENT_BKUP_BEGINRESTORE,
+ (WORD) EVENTLOG_INFORMATION_TYPE,
+ 2, mwBkpSet.szDrive, mwBkpSet.szVerify );
+}
+
+
+void OMEVENT_LogEndRestore (
+ BOOL bError ) //Did an error occur?
+{
+ OMEVENT_LogEvent ( (DWORD)EVENT_BKUP_ENDRESTORE,
+ (WORD)((bError) ? EVENTLOG_ERROR_TYPE
+ : EVENTLOG_INFORMATION_TYPE),
+ 2, mwBkpSet.szDrive, mwBkpSet.szVerify );
+}
+
+void OMEVENT_LogBeginErase ( VOID )
+{
+ OMEVENT_LogEvent ( (DWORD)EVENT_BKUP_BEGINERASE,
+ (WORD) EVENTLOG_INFORMATION_TYPE,
+ 0 );
+}
+
+
+void OMEVENT_LogEndErase (
+ BOOL bError ) //Did an error occur?
+{
+ OMEVENT_LogEvent ( (DWORD)EVENT_BKUP_ENDERASE,
+ (WORD) ((bError) ? EVENTLOG_ERROR_TYPE
+ : EVENTLOG_INFORMATION_TYPE),
+ 0 );
+}
+
+void OMEVENT_LogBeginRetension ( VOID )
+{
+ OMEVENT_LogEvent ( (DWORD)EVENT_BKUP_BEGINRETENSION,
+ (WORD) EVENTLOG_INFORMATION_TYPE,
+ 0 );
+}
+
+
+void OMEVENT_LogEndRetension (
+ BOOL bError ) //Did an error occur?
+{
+ OMEVENT_LogEvent ( (DWORD)EVENT_BKUP_ENDRETENSION,
+ (WORD) ((bError) ? EVENTLOG_ERROR_TYPE
+ : EVENTLOG_INFORMATION_TYPE),
+ 0 );
+}
+
+void OMEVENT_LogBeginVerify ( CHAR_PTR pszDrive )
+{
+ memset ( &mwBkpSet, 0, sizeof ( mwBkpSet ) );
+ strncpy ( mwBkpSet.szDrive, pszDrive, OMEVT_MAX_DRIVE-1 );
+
+ OMEVENT_LogEvent ( (DWORD)EVENT_BKUP_BEGINVERIFY,
+ (WORD) EVENTLOG_INFORMATION_TYPE,
+ 1, mwBkpSet.szDrive );
+}
+
+
+void OMEVENT_LogEndVerify ( CHAR_PTR pszDrive,
+ BOOL bError ) //Did an error occur?
+{
+ memset ( &mwBkpSet, 0, sizeof ( mwBkpSet ) );
+ strncpy ( mwBkpSet.szDrive, pszDrive, OMEVT_MAX_DRIVE-1 );
+
+ OMEVENT_LogEvent ( (DWORD)EVENT_BKUP_ENDVERIFY,
+ (WORD) ((bError) ? EVENTLOG_ERROR_TYPE
+ : EVENTLOG_INFORMATION_TYPE),
+ 1, mwBkpSet.szDrive );
+}
+void OMEVENT_LogEMSError (
+ CHAR_PTR function_name,
+ INT status,
+ CHAR_PTR additional_info ) //Did an error occur?
+{
+CHAR stat_str [30] ;
+
+ sprintf( stat_str, TEXT("%x"), status ) ;
+ OMEVENT_LogEvent ( (DWORD)EVENT_BKUP_EMS_ERROR,
+ (WORD) EVENTLOG_ERROR_TYPE,
+ 3,
+ stat_str,
+ function_name,
+ additional_info );
+}
+void OMEVENT_LogEMSErrorText (
+ CHAR_PTR function_name,
+ CHAR_PTR status,
+ CHAR_PTR additional_info ) //Did an error occur?
+{
+ OMEVENT_LogEvent ( (DWORD)EVENT_BKUP_EMS_ERROR,
+ (WORD) EVENTLOG_ERROR_TYPE,
+ 3,
+ status,
+ function_name,
+ additional_info );
+}
+
+void OMEVENT_LogEMSToFewDbError (
+ INT num_found,
+ INT num_needed )
+{
+CHAR found_str [30] ;
+CHAR needed_str [30] ;
+
+ sprintf( found_str, TEXT("%x"), num_found ) ;
+ sprintf( needed_str, TEXT("%x"), num_needed ) ;
+
+ OMEVENT_LogEvent ( (DWORD)EVENT_BKUP_EMS_DB_ERROR,
+ (WORD) EVENTLOG_ERROR_TYPE,
+ 2,
+ found_str,
+ needed_str ) ;
+}
diff --git a/private/utils/ntbackup/src/omfdisk.bmp b/private/utils/ntbackup/src/omfdisk.bmp
new file mode 100644
index 000000000..b1e85498d
--- /dev/null
+++ b/private/utils/ntbackup/src/omfdisk.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/omfiler.dlg b/private/utils/ntbackup/src/omfiler.dlg
new file mode 100644
index 000000000..9e605348d
--- /dev/null
+++ b/private/utils/ntbackup/src/omfiler.dlg
@@ -0,0 +1,19 @@
+
+IDD_FILEREPLACE DIALOG 30, 82, 299, 70
+CAPTION "Confirm File Replace"
+FONT 8, "MS Shell Dlg"
+STYLE DS_ABSALIGN | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+BEGIN
+ ICON 0, IDD_FILE_REPLACE_BITMAP, 8, 6, 20, 20
+ CONTROL "Replace File:", -1, "STATIC", SS_LEFT | WS_GROUP, 26, 6, 46, 8
+ CONTROL "With File:", -1, "STATIC", SS_LEFT | WS_GROUP, 26, 27, 46, 8
+ CONTROL "", IDD_FILE_REPLACE_LINE1, "STATIC", SS_LEFT | WS_GROUP, 72, 6, 219, 8
+ CONTROL "", IDD_FILE_REPLACE_LINE2, "STATIC", SS_LEFT | WS_GROUP, 72, 16, 219, 8
+ CONTROL "", IDD_FILE_REPLACE_LINE3, "STATIC", SS_LEFT | WS_GROUP, 72, 27, 219, 8
+ CONTROL "", IDD_FILE_REPLACE_LINE4, "STATIC", SS_LEFT | WS_GROUP, 72, 37, 219, 8
+ CONTROL "&Yes", IDD_FILE_REPLACE_YES, "BUTTON", BS_DEFPUSHBUTTON | WS_TABSTOP, 40, 54, 40, 13
+ CONTROL "Yes to &All", IDD_FILE_REPLACE_ALL, "BUTTON", BS_PUSHBUTTON | WS_TABSTOP, 100, 54, 40, 13
+ CONTROL "&No", IDD_FILE_REPLACE_NO, "BUTTON", BS_PUSHBUTTON | WS_TABSTOP, 160, 54, 40, 13
+ CONTROL "Cancel", IDD_FILE_REPLACE_CANCEL, "BUTTON", BS_PUSHBUTTON | WS_TABSTOP, 220, 54, 40, 13
+// CONTROL "&Help", IDD_FILE_REPLACE_HELP, "BUTTON", BS_PUSHBUTTON | WS_TABSTOP, 228, 54, 40, 13
+END
diff --git a/private/utils/ntbackup/src/omgbacku.bmp b/private/utils/ntbackup/src/omgbacku.bmp
new file mode 100644
index 000000000..78ad2fcb2
--- /dev/null
+++ b/private/utils/ntbackup/src/omgbacku.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/omgcat.bmp b/private/utils/ntbackup/src/omgcat.bmp
new file mode 100644
index 000000000..b47089921
--- /dev/null
+++ b/private/utils/ntbackup/src/omgcat.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/omgcheck.bmp b/private/utils/ntbackup/src/omgcheck.bmp
new file mode 100644
index 000000000..65443dd4f
--- /dev/null
+++ b/private/utils/ntbackup/src/omgcheck.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/omgeject.bmp b/private/utils/ntbackup/src/omgeject.bmp
new file mode 100644
index 000000000..0744d6249
--- /dev/null
+++ b/private/utils/ntbackup/src/omgeject.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/omgerase.bmp b/private/utils/ntbackup/src/omgerase.bmp
new file mode 100644
index 000000000..97e14bd9f
--- /dev/null
+++ b/private/utils/ntbackup/src/omgerase.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/omgresto.bmp b/private/utils/ntbackup/src/omgresto.bmp
new file mode 100644
index 000000000..ee63dd963
--- /dev/null
+++ b/private/utils/ntbackup/src/omgresto.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/omgtensi.bmp b/private/utils/ntbackup/src/omgtensi.bmp
new file mode 100644
index 000000000..9a172a600
--- /dev/null
+++ b/private/utils/ntbackup/src/omgtensi.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/omgunche.bmp b/private/utils/ntbackup/src/omgunche.bmp
new file mode 100644
index 000000000..44bff6168
--- /dev/null
+++ b/private/utils/ntbackup/src/omgunche.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/omhdisk.bmp b/private/utils/ntbackup/src/omhdisk.bmp
new file mode 100644
index 000000000..9a6a6f7da
--- /dev/null
+++ b/private/utils/ntbackup/src/omhdisk.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/omhwconf.dlg b/private/utils/ntbackup/src/omhwconf.dlg
new file mode 100644
index 000000000..1ff78ffc0
--- /dev/null
+++ b/private/utils/ntbackup/src/omhwconf.dlg
@@ -0,0 +1,13 @@
+
+IDD_SETTINGSHARDWARE DIALOG 68, 30, 241, 73
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Hardware Setup"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Tape Drive", -1, 10, 8, 149, 8
+ COMBOBOX IDD_H_CONTROLLER, 11, 20, 221, 50, CBS_DROPDOWNLIST |
+ CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ DEFPUSHBUTTON "OK", HWC_SECONDLISTBOX, 44, 50, 35, 14, WS_GROUP
+ PUSHBUTTON "Cancel", HWC_THIRDLISTBOX, 103, 50, 35, 14
+ PUSHBUTTON "&Help", IDHELP, 160, 50, 35, 14
+END
diff --git a/private/utils/ntbackup/src/ommenus.rc b/private/utils/ntbackup/src/ommenus.rc
new file mode 100644
index 000000000..587d110e0
--- /dev/null
+++ b/private/utils/ntbackup/src/ommenus.rc
@@ -0,0 +1,131 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+DAVEV
+
+ Name: wntrpark.rc
+
+ Description: This file contains the references to menu resources for
+ the 32-bit Windows/NT GUI Project Resource File.
+
+ This file was created by copying and modifying
+ MENUS.RC from the standard Windows GUI project.
+
+ $Log: G:\UI\LOGFILES\OMMENUS.RCV $
+
+ Rev 1.12 27 Jan 1994 13:36:44 Glenn
+ Added F5 Refresh support.
+
+ Rev 1.11 21 Apr 1993 15:25:14 GLENN
+ Changed all file details hot key from F to A.
+
+ Rev 1.10 12 Mar 1993 16:47:02 CARLS
+ added ... to format tape
+
+ Rev 1.9 10 Mar 1993 12:55:56 CARLS
+ Changes to move Format tape to the Operations menu
+
+ Rev 1.8 27 Jan 1993 14:23:56 STEVEN
+ updates from msoft
+
+ Rev 1.7 11 Dec 1992 17:33:40 GLENN
+ Changed a help menu item hot-key.
+
+ Rev 1.6 28 Sep 1992 16:27:14 GLENN
+ Added the split to the view menu.
+
+ Rev 1.5 20 Aug 1992 08:46:32 GLENN
+ Added catalog menu support.
+
+ Rev 1.4 07 Jul 1992 16:03:02 GLENN
+ Enabled the view/font item - was commented out for beta.
+
+ Rev 1.3 10 Jun 1992 16:09:06 GLENN
+ Updated according to NT SPEC.
+
+ Rev 1.2 06 May 1992 11:19:54 GLENN
+ Changed hot key for select menu and status bar.
+
+ Rev 1.1 25 Mar 1992 17:45:34 DAVEV
+ OEM_MSOFT: changes to meet spec.
+
+ Rev 1.0 03 Mar 1992 12:23:04 DAVEV
+ Initial revision.
+
+******************************************************************************/
+
+// MENUS -- ID's are defined in the Menu Manager header file 'ntmenus.h'
+
+// Frame window menu.
+
+IDRM_MAINMENU MENU PRELOAD
+BEGIN
+
+ POPUP "&Operations"
+ BEGIN
+ MENUITEM "&Backup...", IDM_OPERATIONSBACKUP
+ MENUITEM "&Restore...", IDM_OPERATIONSRESTORE
+ MENUITEM "&Catalog", IDM_OPERATIONSCATALOG
+ MENUITEM "&Erase Tape...", IDM_OPERATIONSERASE
+ MENUITEM "Re&tension Tape...", IDM_OPERATIONSRETENSION
+ MENUITEM "E&ject Tape", IDM_OPERATIONSEJECT
+ MENUITEM "&Format Tape...", IDM_OPERATIONSFORMAT
+#ifdef FS_EMS
+ MENUITEM "&Microsoft Exchange..." IDM_OPERATIONSEXCHANGE
+#endif
+ MENUITEM SEPARATOR
+ MENUITEM "&Hardware Setup...", IDM_OPERATIONSHARDWARE
+ MENUITEM SEPARATOR
+ MENUITEM "E&xit", IDM_OPERATIONSEXIT
+ END
+
+ POPUP "&Tree"
+ BEGIN
+ MENUITEM "E&xpand One Level", IDM_TREEEXPANDONE
+ MENUITEM "Expand &Branch", IDM_TREEEXPANDBRANCH
+ MENUITEM "Expand &All", IDM_TREEEXPANDALL
+ MENUITEM "&Collapse Branch", IDM_TREECOLLAPSEBRANCH
+ END
+
+ POPUP "&View"
+ BEGIN
+ MENUITEM "Tr&ee and Directory",IDM_VIEWTREEANDDIR
+ MENUITEM "&Tree Only", IDM_VIEWTREEONLY
+ MENUITEM "&Directory Only", IDM_VIEWDIRONLY
+ MENUITEM SEPARATOR
+ MENUITEM "Sp&lit", IDM_VIEWSPLIT
+ MENUITEM SEPARATOR
+ MENUITEM "&All File Details", IDM_VIEWALLFILEDETAILS
+ MENUITEM SEPARATOR
+ MENUITEM "&Status Bar", IDM_VIEWSTATUS
+ MENUITEM "Tool&bar", IDM_VIEWURIBBON
+ MENUITEM SEPARATOR
+ MENUITEM "&Font...", IDM_VIEWFONT
+
+ END
+
+ POPUP "&Select"
+ BEGIN
+ MENUITEM "&Check", IDM_SELECTCHECK
+ MENUITEM "&Uncheck", IDM_SELECTUNCHECK
+ END
+
+ POPUP "&Window"
+ BEGIN
+ MENUITEM "&Cascade", IDM_WINDOWSCASCADE
+ MENUITEM "&Tile", IDM_WINDOWSTILE
+ MENUITEM "&Arrange Icons", IDM_WINDOWSARRANGEICONS
+ MENUITEM "&Refresh\tF5", IDM_WINDOWSREFRESH
+ MENUITEM "C&lose All", IDM_WINDOWSCLOSEALL
+ END
+
+ POPUP "&Help"
+ BEGIN
+ MENUITEM "&Contents", IDM_HELPINDEX
+ MENUITEM "&Search for Help on...", IDM_HELPSEARCH
+ MENUITEM "&How to Use Help", IDM_HELPUSINGHELP
+ MENUITEM SEPARATOR
+ MENUITEM AABOUTAPPLICATIONNAME, IDM_HELPABOUTNOSTRADOMUS
+ END
+
+END
diff --git a/private/utils/ntbackup/src/ommuibar.c b/private/utils/ntbackup/src/ommuibar.c
new file mode 100644
index 000000000..cded2f89b
--- /dev/null
+++ b/private/utils/ntbackup/src/ommuibar.c
@@ -0,0 +1,458 @@
+
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1992
+GSH
+
+ Name: ommuibar.c
+
+ Description: This file contains the functions for the NT Maynard User
+ Interface (MUI) Selection Bar / Ribbon Bar.
+
+ $Log: J:\ui\logfiles\ommuibar.c_v $
+
+ Rev 1.12 07 Feb 1994 01:46:02 GREGG
+Don't allow backup or restore if we're running with the 'NOPOLL' option.
+
+ Rev 1.11 11 Dec 1992 18:21:32 GLENN
+Added dynamic text region sizing based on the length of a text string in a button.
+
+ Rev 1.10 18 Nov 1992 13:01:36 GLENN
+Added microsoft 3D button enhancement.
+
+ Rev 1.9 07 Oct 1992 14:11:30 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.8 04 Oct 1992 19:39:34 DAVEV
+Unicode Awk pass
+
+ Rev 1.7 10 Sep 1992 17:19:04 GLENN
+Resolved outstanding state issues for toolbar and menubar.
+
+ Rev 1.6 20 Aug 1992 09:07:54 GLENN
+Added catalog button support.
+
+ Rev 1.5 10 Jun 1992 16:14:30 GLENN
+Updated according to NT SPEC.
+
+ Rev 1.4 29 May 1992 16:01:18 JOHNWT
+PCH updates
+
+ Rev 1.3 15 May 1992 14:55:30 MIKEP
+changes
+
+ Rev 1.2 21 Apr 1992 16:53:06 chrish
+NT stuff
+
+ Rev 1.1 21 Apr 1992 16:19:46 DAVEV
+Added conditionals to include/exclude all code based on definition of OEM_MSOFT
+
+ Rev 1.0 02 Apr 1992 16:22:52 GLENN
+Initial revision.
+
+******************************************************************************/
+
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+#ifdef OEM_MSOFT //This file is only compiled for OEM_MSOFT
+
+
+// MODULE WIDE DEFINITIONS
+#define OEM_BUTTONBAR_HEIGHT (IS_JAPAN()?33:26)
+#define OEM_BUTTON_WIDTH 23
+#define OEM_BUTTON_HEIGHT (IS_JAPAN()?28:21)
+#define OEM_BUTTONWITHTEXT_WIDTH 86
+#define OEM_BORDER_WIDTH ( RIB_ITEM_BORDER_WIDTH - 1 )
+#define OEM_BETWEEN_BUTTON_SPACE 7
+#define OEM_BEGIN_BUTTON_LEFT 9
+#define OEM_BEGIN_BUTTON_TOP 2
+#define OEM_BITMAP_TEXT_SPACE 3
+
+// PRIVATE FUNCTIONS
+
+INT MUI_GetMaxTextWidth ( WORD, INT );
+
+
+/******************************************************************************
+
+ Name: MUI_MakeMainRibbon()
+
+ Description: This function creates and stuffs the applications main
+ ribbon.
+
+ Returns: A handle to the main ribbon.
+
+******************************************************************************/
+
+HRIBBON MUI_MakeMainRibbon ( VOID )
+
+{
+ HRIBBON hRibbon;
+ DS_RIBITEMINFO dsItem;
+ UINT i = 0;
+ INT nFontMaxWidth = 0;
+ INT nFontMaxHeight = 0;
+ INT nTextWidth;
+ INT nButtonWithTextWidth;
+
+ // Create the Ribbon.
+
+ hRibbon = RIB_Create ( ghWndMainRibbon,
+ (WORD) 0,
+ MAIN_RIBBON_ITEMWIDTH,
+ MAIN_RIBBON_HEIGHT,
+ MAIN_RIBBON_MAXITEMS
+ );
+
+ // Add the item information. Note: the accelerator key is derived from
+ // the string.
+
+ dsItem.wAccelKey = ID_NOTDEFINED;
+
+ // Use the system font.
+
+ dsItem.hFont = ghFontRibbon;
+
+ // Draw the text left justified and vertically centered.
+
+ dsItem.wTextStyle = RIB_TEXT_HLEFT | RIB_TEXT_VCENTER;
+
+ //
+ // Stuff the COMMON parts of the buttons.
+ //
+ // the TOP, BOTTOM, BITMAP WIDTH, etc.
+ //
+
+ dsItem.Rect.top = OEM_BEGIN_BUTTON_TOP;;
+ dsItem.Rect.bottom = dsItem.Rect.top + OEM_BUTTON_HEIGHT;
+
+ dsItem.rcBM = dsItem.rcText = dsItem.Rect;
+
+ dsItem.rcBM.top += OEM_BORDER_WIDTH;
+ dsItem.rcBM.bottom -= OEM_BORDER_WIDTH;
+
+// dsItem.rcText.top += 2;
+
+ dsItem.rcText.top += OEM_BORDER_WIDTH + 1;
+ dsItem.rcText.bottom -= OEM_BORDER_WIDTH - 1;
+
+ dsItem.wStyle = RIB_ITEM_STYLECHICKLET;
+
+ // Determine the size of the buttons with text in them.
+ // The size will be based on the largest text size.
+
+ nButtonWithTextWidth = OEM_BUTTONWITHTEXT_WIDTH;
+
+ nTextWidth = OEM_BUTTONWITHTEXT_WIDTH - ( ( 2 * OEM_BORDER_WIDTH ) +
+ OEM_BUTTON_WIDTH +
+ OEM_BITMAP_TEXT_SPACE + 4
+ );
+
+
+ nTextWidth = MUI_GetMaxTextWidth ( IDS_RIB_BACKUP, nTextWidth );
+ nTextWidth = MUI_GetMaxTextWidth ( IDS_RIB_RESTORE, nTextWidth );
+
+
+ nButtonWithTextWidth = ( 2 * OEM_BORDER_WIDTH ) + OEM_BUTTON_WIDTH +
+ OEM_BITMAP_TEXT_SPACE + nTextWidth + (IS_JAPAN()?6:4) ;
+
+ // Now, stuff each item.
+
+
+ // BACKUP
+
+ dsItem.wEnabledID = IDRBM_BACKUP;
+ dsItem.wDisabledID = IDRBM_BACKUP_GRAY;
+ dsItem.wState = RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL;
+ dsItem.wMessage = IDM_OPERATIONSBACKUP;
+ dsItem.wStringID = IDS_RIB_BACKUP;
+
+ dsItem.Rect.left = OEM_BEGIN_BUTTON_LEFT;;
+ dsItem.Rect.right = dsItem.Rect.left + nButtonWithTextWidth;
+
+ dsItem.rcBM.left = dsItem.Rect.left + OEM_BORDER_WIDTH;
+ dsItem.rcBM.right = dsItem.rcBM.left + OEM_BUTTON_WIDTH + 2;
+
+ dsItem.rcText.left = dsItem.rcBM.right + ( OEM_BITMAP_TEXT_SPACE + 2 );
+ dsItem.rcText.right = dsItem.Rect.right - ( OEM_BORDER_WIDTH + 2 );
+
+ RIB_ItemAppend ( hRibbon, &dsItem );
+
+
+ // RESTORE
+
+ dsItem.wEnabledID = IDRBM_RESTORE;
+ dsItem.wDisabledID = IDRBM_RESTORE_GRAY;
+ dsItem.wState = RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL;
+ dsItem.wMessage = IDM_OPERATIONSRESTORE;
+ dsItem.wStringID = IDS_RIB_RESTORE;
+
+ dsItem.Rect.left = dsItem.Rect.left + nButtonWithTextWidth + OEM_BETWEEN_BUTTON_SPACE;
+ dsItem.Rect.right = dsItem.Rect.left + nButtonWithTextWidth;
+
+ dsItem.rcBM.left = dsItem.Rect.left + OEM_BORDER_WIDTH;
+ dsItem.rcBM.right = dsItem.rcBM.left + OEM_BUTTON_WIDTH + 2;
+
+ dsItem.rcText.left = dsItem.rcBM.right + ( OEM_BITMAP_TEXT_SPACE + 2 );
+ dsItem.rcText.right = dsItem.Rect.right - ( OEM_BORDER_WIDTH + 2 );
+
+ RIB_ItemAppend ( hRibbon, &dsItem );
+
+
+ // CATALOG
+
+ dsItem.wEnabledID = IDRBM_CATALOG;
+ dsItem.wDisabledID = IDRBM_CATALOG_GRAY;
+ dsItem.wState = RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL;
+ dsItem.wMessage = IDM_OPERATIONSCATALOG;
+ dsItem.wStringID = ID_NOTDEFINED;
+
+ dsItem.Rect.left = dsItem.Rect.left + nButtonWithTextWidth + OEM_BETWEEN_BUTTON_SPACE;
+ dsItem.Rect.right = dsItem.Rect.left + OEM_BUTTON_WIDTH;
+
+ dsItem.rcBM.left = dsItem.Rect.left + OEM_BORDER_WIDTH;
+ dsItem.rcBM.right = dsItem.Rect.right - OEM_BORDER_WIDTH + 1;
+
+ RIB_ItemAppend ( hRibbon, &dsItem );
+
+
+ // RETENSION
+
+ dsItem.wEnabledID = IDRBM_RETENSION;
+ dsItem.wDisabledID = IDRBM_RETENSION_GRAY;
+ dsItem.wState = RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL;
+ dsItem.wMessage = IDM_OPERATIONSRETENSION;
+ dsItem.wStringID = ID_NOTDEFINED;
+
+ dsItem.Rect.left = dsItem.Rect.left + OEM_BUTTON_WIDTH;
+ dsItem.Rect.right = dsItem.Rect.left + OEM_BUTTON_WIDTH;
+
+ dsItem.rcBM.left = dsItem.Rect.left + OEM_BORDER_WIDTH - 1;
+ dsItem.rcBM.right = dsItem.Rect.right - OEM_BORDER_WIDTH;
+
+ RIB_ItemAppend ( hRibbon, &dsItem );
+
+
+ // EJECT
+
+ dsItem.wEnabledID = IDRBM_EJECT;
+ dsItem.wDisabledID = IDRBM_EJECT_GRAY;
+ dsItem.wState = RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL;
+ dsItem.wMessage = IDM_OPERATIONSEJECT;
+ dsItem.wStringID = ID_NOTDEFINED;
+
+ dsItem.Rect.left = dsItem.Rect.left + OEM_BUTTON_WIDTH;
+ dsItem.Rect.right = dsItem.Rect.left + OEM_BUTTON_WIDTH;
+
+ dsItem.rcBM.left = dsItem.Rect.left + OEM_BORDER_WIDTH;
+ dsItem.rcBM.right = dsItem.Rect.right - OEM_BORDER_WIDTH + 1;
+
+ RIB_ItemAppend ( hRibbon, &dsItem );
+
+
+ // ERASE
+
+ dsItem.wEnabledID = IDRBM_ERASE;
+ dsItem.wDisabledID = IDRBM_ERASE_GRAY;
+ dsItem.wState = RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL;
+ dsItem.wMessage = IDM_OPERATIONSERASE;
+ dsItem.wStringID = ID_NOTDEFINED;
+
+ dsItem.Rect.left = dsItem.Rect.left + OEM_BUTTON_WIDTH;
+ dsItem.Rect.right = dsItem.Rect.left + OEM_BUTTON_WIDTH;
+
+ dsItem.rcBM.left = dsItem.Rect.left + OEM_BORDER_WIDTH;
+ dsItem.rcBM.right = dsItem.Rect.right - OEM_BORDER_WIDTH + 1;
+
+ RIB_ItemAppend ( hRibbon, &dsItem );
+
+
+ // CHECK
+
+ dsItem.wEnabledID = IDRBM_CHECK;
+ dsItem.wDisabledID = IDRBM_CHECK_GRAY;
+ dsItem.wState = RIB_ITEM_UP | RIB_ITEM_DISABLED;
+ dsItem.wMessage = IDM_SELECTCHECK;
+ dsItem.wStringID = ID_NOTDEFINED;
+
+ dsItem.Rect.left = dsItem.Rect.left + OEM_BUTTON_WIDTH + OEM_BETWEEN_BUTTON_SPACE;
+ dsItem.Rect.right = dsItem.Rect.left + OEM_BUTTON_WIDTH;
+
+ dsItem.rcBM.left = dsItem.Rect.left + OEM_BORDER_WIDTH;
+ dsItem.rcBM.right = dsItem.Rect.right - OEM_BORDER_WIDTH + 1;
+
+ RIB_ItemAppend ( hRibbon, &dsItem );
+
+
+ // UNCHECK
+
+ dsItem.wEnabledID = IDRBM_UNCHECK;
+ dsItem.wDisabledID = IDRBM_UNCHECK_GRAY;
+ dsItem.wState = RIB_ITEM_UP | RIB_ITEM_DISABLED;
+ dsItem.wMessage = IDM_SELECTUNCHECK;
+ dsItem.wStringID = ID_NOTDEFINED;
+
+ dsItem.Rect.left = dsItem.Rect.left + OEM_BUTTON_WIDTH;
+ dsItem.Rect.right = dsItem.Rect.left + OEM_BUTTON_WIDTH;
+
+ dsItem.rcBM.left = dsItem.Rect.left + OEM_BORDER_WIDTH;
+ dsItem.rcBM.right = dsItem.Rect.right - OEM_BORDER_WIDTH + 1;
+
+ RIB_ItemAppend ( hRibbon, &dsItem );
+
+
+ gnMainRibbonHeight = OEM_BUTTONBAR_HEIGHT + 1;
+
+ RIB_SetOwner ( hRibbon, ghWndFrame );
+
+ return hRibbon;
+
+} /* end MUI_MakeMainRibbon() */
+
+
+/******************************************************************************
+
+ Name: MUI_SetOperationButtons ()
+
+ Description: This function sets the state of all operation buttons.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID MUI_SetOperationButtons (
+
+WORD wState ) // I - state of the buttons
+
+{
+ WORD wNewState = wState;
+
+ wNewState = (WORD)(( gfPollDrive ) ? wState : RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL);
+
+ RIB_ItemSetState ( ghRibbonMain, IDM_OPERATIONSBACKUP, wNewState );
+ RIB_ItemSetState ( ghRibbonMain, IDM_OPERATIONSRESTORE, wNewState );
+
+ // Special tape-in-drive dependent buttons.
+
+ wNewState = (WORD)(( MUI_IsTapeInDrive () ) ? wState : RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL);
+
+ RIB_ItemSetState ( ghRibbonMain, IDM_OPERATIONSERASE, wNewState );
+ RIB_ItemSetState ( ghRibbonMain, IDM_OPERATIONSEJECT, wNewState );
+
+ wNewState = (WORD)(( MUI_IsTapeValid () ) ? wState : RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL);
+
+ RIB_ItemSetState ( ghRibbonMain, IDM_OPERATIONSCATALOG, wNewState );
+
+ wNewState = (WORD)(( MUI_IsRetensionSupported () ) ? wState : RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL);
+
+ RIB_ItemSetState ( ghRibbonMain, IDM_OPERATIONSRETENSION, wNewState );
+
+} /* end MUI_SetOperationButtons() */
+
+
+/******************************************************************************
+
+ Name: MUI_SetActionButtons()
+
+ Description: This function sets the state of all action buttons.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID MUI_SetActionButtons (
+
+WORD wState ) // I - state of the buttons
+
+{
+ RIB_ItemSetState ( ghRibbonMain, IDM_SELECTCHECK, wState );
+ RIB_ItemSetState ( ghRibbonMain, IDM_SELECTUNCHECK, wState );
+
+} /* end MUI_SetActionButtons() */
+
+
+/******************************************************************************
+
+ Name: MUI_SetButtonState()
+
+ Description: This function sets the state of a single button.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID MUI_SetButtonState (
+
+WORD wType, // I - button ID
+WORD wState ) // I - state of the button
+
+{
+ WORD wNewState = wState ;
+
+ if( !gfPollDrive &&
+ ( wType == IDM_OPERATIONSBACKUP ||
+ wType == IDM_OPERATIONSRESTORE ||
+ wType == IDM_OPERATIONSCATALOG ) ) {
+
+ wNewState = (WORD)( RIB_ITEM_UP | RIB_ITEM_DISABLED | RIB_ITEM_POSITIONAL ) ;
+ }
+
+ RIB_ItemSetState ( ghRibbonMain, wType, wNewState );
+
+} /* end MUI_SetButtonState() */
+
+
+
+INT MUI_GetMaxTextWidth (
+
+WORD wStringID,
+INT nOldStringWidth )
+
+{
+// INT nMaxFontWidth = 0;
+// INT nAvgFontWidth = 0;
+// INT nFontHeight = 0;
+ INT nStringLen = 0;
+ INT nMaxStringWidth = 0;
+ CHAR szString[RIB_ITEM_TEXT_SIZE];
+
+ INT nTemp = 0;
+ UINT j;
+
+ nStringLen = RSM_StringCopy ( wStringID, szString, RIB_ITEM_TEXT_SIZE );
+
+// RSM_GetFontSize ( ghFontRibbon, &nMaxFontWidth, &nAvgFontWidth, &nFontHeight );
+// nMaxStringWidth = nStringLen * nAvgFontWidth;
+// nMaxStringWidth = ( nOldStringWidth > nMaxStringWidth ) ? nOldStringWidth : nMaxStringWidth;
+
+ // Remove the underscore character ('&') from the string if any.
+
+ for ( j = 0; j < strlen ( szString ); j++ ) {
+
+ if ( szString[j] == TEXT('&') ) {
+
+ do {
+ szString[j] = szString[j+1];
+ } while ( szString[++j] != TEXT('\0') );
+
+ break;
+ }
+ }
+
+ nMaxStringWidth = RSM_GetFontStringWidth ( ghFontRibbon, szString, nStringLen ) +(IS_JAPAN()?OEM_BITMAP_TEXT_SPACE:0);
+ nMaxStringWidth = ( nOldStringWidth > nMaxStringWidth ) ? nOldStringWidth : nMaxStringWidth;
+
+ return nMaxStringWidth;
+
+} /* end MUI_GetMaxTextWidth() */
+
+
+#endif //OEM_MSOFT //This file is only compiled for OEM_MSOFT
+
+
+
diff --git a/private/utils/ntbackup/src/omndisk.bmp b/private/utils/ntbackup/src/omndisk.bmp
new file mode 100644
index 000000000..f93edd0d7
--- /dev/null
+++ b/private/utils/ntbackup/src/omndisk.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/omrdisk.bmp b/private/utils/ntbackup/src/omrdisk.bmp
new file mode 100644
index 000000000..df925d42b
--- /dev/null
+++ b/private/utils/ntbackup/src/omrdisk.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/omrestor.bmp b/private/utils/ntbackup/src/omrestor.bmp
new file mode 100644
index 000000000..7a5cc595c
--- /dev/null
+++ b/private/utils/ntbackup/src/omrestor.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/omrset.dlg b/private/utils/ntbackup/src/omrset.dlg
new file mode 100644
index 000000000..5f08c6df2
--- /dev/null
+++ b/private/utils/ntbackup/src/omrset.dlg
@@ -0,0 +1,71 @@
+
+IDD_RESTORESET DIALOG DISCARDABLE 5, 15, 270, 208
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Restore Information"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "Restore Set Information ",IDD_RSET_INFO_TITLE,5,3,260,
+ 136
+ LTEXT "Tape Name:",IDD_RSET_TAPE_NAME_TEXT,10,17,59,10,NOT
+ WS_GROUP
+ CONTROL "",IDD_RSET_TAPE_NAME,"Static",SS_LEFTNOWORDWRAP |
+ SS_NOPREFIX,70,17,184,10
+ LTEXT "Backup Set:",IDD_RSET_SET_TEXT,10,29,59,10,NOT WS_GROUP
+ CONTROL "",IDD_RSET_SET_LINE_1,"Static",SS_LEFTNOWORDWRAP |
+ SS_NOPREFIX,70,29,184,10
+ LTEXT "Creation Date:",-1,10,41,60,10,NOT WS_GROUP
+ LTEXT "",IDD_RSET_CREATION_DATE,70,41,184,10,SS_NOPREFIX | NOT
+ WS_GROUP
+ LTEXT "Owner:",-1,10,53,60,10,NOT WS_GROUP
+ LTEXT "",IDD_RSET_OWNERS_NAME,70,53,184,10,SS_NOPREFIX | NOT
+ WS_GROUP
+ LTEXT "Original Server:",IDD_RSET_ORG_TEXT,16,75,63,8
+ LTEXT "",IDD_RSET_ORG_NAME,82,75,147,12,SS_NOPREFIX | NOT
+ WS_GROUP
+ LTEXT "Dest&ination Server:",IDD_RSET_DEST_TEXT,16,90,63,8
+ LTEXT "Destination Server:",IDD_RSET_DS_DEST_TEXT,16,90,63,8
+ LTEXT "",IDD_RSET_DSA_DEST_NAME,82,90,147,12,SS_NOPREFIX | NOT
+ WS_GROUP
+ EDITTEXT IDD_RSET_DEST_NAME,82,88,147,12,ES_AUTOHSCROLL
+ CONTROL "&Erase all existing data",IDD_RSET_WIPE_DATA,"Button",
+ BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,16,103,100,9
+ CONTROL "&Private",IDD_RSET_PRIV_IS,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,120,103,43,9
+ CONTROL "P&ublic",IDD_RSET_PUB_IS,"Button",BS_AUTOCHECKBOX |
+ WS_GROUP | WS_TABSTOP,192,103,43,9
+ CONTROL "&Verify After Restore",IDD_RSET_VERIFY_AFTER,"Button",
+ BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,11,121,77,12
+ CONTROL "S&tart Service After Restore ",IDD_RSET_START_EMS,"Button",
+ BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,150,121,100,12
+ GROUPBOX "Restore",-1,10,62,238,56
+ LTEXT "Restore to &Drive:",IDD_RSET_DRIVE_TEXT,16,74,60,9,NOT
+ WS_GROUP
+ COMBOBOX IDD_RSET_DRIVE_BOX,76,72,163,60,CBS_DROPDOWNLIST |
+ CBS_SORT | WS_VSCROLL | WS_GROUP | WS_TABSTOP
+ LTEXT "&Alternate Path:",IDD_RSET_PATH_TEXT,16,90,54,9,NOT
+ WS_GROUP
+ EDITTEXT IDD_RSET_RESTORE_PATH,76,88,148,12,ES_AUTOHSCROLL |
+ WS_GROUP
+ PUSHBUTTON "...",IDD_RSET_BROWSE_BUTTON,224,88,15,12,WS_GROUP
+ CONTROL "Restore Local Re&gistry",IDD_RSET_REGISTRY,"Button",
+ BS_AUTOCHECKBOX | WS_GROUP | WS_TABSTOP,16,103,104,12
+ CONTROL "&Restore File Permissions",IDD_RSET_SECURITY_INFO,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,126,103,96,12
+ SCROLLBAR IDD_RSET_SCROLLBAR,254,7,11,132,SBS_VERT | WS_GROUP |
+ WS_TABSTOP
+ GROUPBOX "Log Information",-1,5,142,260,44
+ LTEXT "&Log File:",-1,10,156,60,9
+ EDITTEXT IDD_RSET_LOG_FILENAME,70,155,148,12,ES_AUTOHSCROLL |
+ WS_GROUP
+ PUSHBUTTON "...",IDD_RSET_LOG_BROWSE,218,155,15,12,WS_GROUP
+ CONTROL "&Full Detail",IDD_RSET_LOG_FULL,"Button",
+ BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,70,172,47,10
+ CONTROL "&Summary Only",IDD_RSET_LOG_SUMMARY,"Button",
+ BS_AUTORADIOBUTTON,121,172,58,10
+ CONTROL "D&on't Log",IDD_RSET_LOG_NONE,"Button",
+ BS_AUTORADIOBUTTON,185,172,46,10
+ DEFPUSHBUTTON "OK",IDD_RSET_OK_BUTTON,50,191,40,14,WS_GROUP
+ PUSHBUTTON "Cancel",IDD_RSET_CANCEL_BUTTON,115,191,40,14
+ PUSHBUTTON "&Help",IDD_RSET_HELP_BUTTON,180,191,40,14
+END
+
diff --git a/private/utils/ntbackup/src/omruntim.dlg b/private/utils/ntbackup/src/omruntim.dlg
new file mode 100644
index 000000000..fdea4dce3
--- /dev/null
+++ b/private/utils/ntbackup/src/omruntim.dlg
@@ -0,0 +1,82 @@
+/**************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: omruntim.dlg
+
+ Description: This file contains a dialog template.
+
+ $Log: G:\UI\LOGFILES\OMRUNTIM.DLV $
+
+ Rev 1.6 31 Jan 1994 13:49:00 Glenn
+ Cleared out the width and height of dummy bitmap controls - NT processes dialogs differently now.
+
+ Rev 1.5 13 Mar 1993 18:41:36 MIKEP
+ fix byte count display
+
+ Rev 1.4 22 Feb 1993 17:34:52 ROBG
+ Made height of IDD_JS_FILE 9 instead of 8.
+ Bitmaps written are 16 pixels tall. 1/8*9 will yield 16 pixels.
+
+ Rev 1.3 18 Dec 1992 11:19:02 chrish
+ Moved from omdialog.rc
+
+ Rev 1.2 19 Aug 1992 14:23:18 CHUCKB
+ Moved things around for NT.
+
+ Rev 1.1 10 Jun 1992 16:11:08 GLENN
+ Updated according to NT SPEC.
+
+ Rev 1.0 11 May 1992 16:54:50 GLENN
+ Initial revision.
+
+**************************************************************************/
+
+IDD_RUNTIME DIALOG 40, 20, 246, 174
+FONT 8, "MS Shell Dlg"
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+BEGIN
+ CONTROL "Text", 304, "STATIC", SS_BLACKFRAME, 4, 4, 238, 34
+ CONTROL "Text", 132, "STATIC", SS_BLACKFRAME, 122, 4, 120, 34
+
+ CONTROL "Directories:", IDD_JS_DP_LABEL, "STATIC", SS_LEFT | WS_GROUP, 6, 6, 80, 10
+ CONTROL "0", IDD_JS_DP, "STATIC", SS_RIGHT | WS_GROUP, 60, 6, 60, 8
+
+ CONTROL "Files:", IDD_JS_FP_LABEL, "STATIC", SS_NOPREFIX | SS_LEFT, 6, 16, 64, 10
+ CONTROL "0", IDD_JS_FP, "STATIC", SS_RIGHT, 60, 16, 60, 8
+
+ CONTROL "Bytes:", IDD_JS_BP_LABEL, "STATIC", SS_NOPREFIX | SS_LEFT, 6, 26, 64, 10
+ CONTROL "0", IDD_JS_BP, "STATIC", SS_RIGHT, 60, 26, 60, 8
+
+ CONTROL "Elapsed time:", IDD_JS_ET_LABEL, "STATIC", SS_NOPREFIX | SS_LEFT, 126, 6, 60, 10
+ CONTROL "00:00", IDD_JS_ET, "STATIC", SS_RIGHT, 190, 6, 50, 8
+
+ CONTROL "Corrupt files:", IDD_JS_CF_LABEL, "STATIC", SS_NOPREFIX | SS_LEFT, 126, 16, 60, 10
+ CONTROL "0", IDD_JS_CF, "STATIC", SS_RIGHT, 190, 16, 50, 8
+
+ CONTROL "Skipped files:", IDD_JS_SF_LABEL, "STATIC", SS_NOPREFIX | SS_LEFT, 126, 26, 60, 10
+ CONTROL "0", IDD_JS_SF, "STATIC", SS_RIGHT, 190, 26, 50, 8
+
+
+ CONTROL "", IDD_JS_SOURCE_DRIVE, "STATIC", SS_LEFT, 4, 42, 0, 0
+ CONTROL "", IDD_JS_SOURCE_NAME, "STATIC", SS_LEFT | SS_NOPREFIX, 22, 42, 186, 8
+
+ CONTROL "Text", 124, "STATIC", SS_BLACKFRAME, 4, 53, 238, 24
+ CONTROL "", IDD_JS_FOLDER, "STATIC", SS_LEFT, 10, 56, 10, 8
+ CONTROL "", IDD_JS_FILE, "STATIC", SS_LEFT, 14, 66, 10, 8
+ CONTROL "", IDD_JS_LINE1, "STATIC", SS_LEFT | SS_NOPREFIX, 23, 56, 198, 8
+ CONTROL "", IDD_JS_LINE2, "STATIC", SS_LEFT | SS_NOPREFIX, 27, 66, 194, 8
+
+
+ CONTROL "Summary", 305, "STATIC", SS_NOPREFIX | SS_LEFT, 4, 80, 238, 56
+ CONTROL "", IDD_JS_LISTBOX, "LISTBOX", LBS_HASSTRINGS | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP | SS_NOPREFIX, 4, 90, 238, 68
+
+
+ CONTROL "OK", IDD_JS_OK, "BUTTON", BS_PUSHBUTTON | WS_GROUP | WS_TABSTOP, 52, 159, 40, 12
+ CONTROL "&Abort", IDD_JS_ABORT, "BUTTON", BS_PUSHBUTTON | WS_GROUP | WS_TABSTOP, 102, 159, 40, 12
+ CONTROL "&Help", IDD_JS_HELP, "BUTTON", BS_PUSHBUTTON | WS_TABSTOP, 153, 159, 40, 12
+
+
+
+END
+
diff --git a/private/utils/ntbackup/src/omselall.bmp b/private/utils/ntbackup/src/omselall.bmp
new file mode 100644
index 000000000..a6408bb48
--- /dev/null
+++ b/private/utils/ntbackup/src/omselall.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/omselnon.bmp b/private/utils/ntbackup/src/omselnon.bmp
new file mode 100644
index 000000000..74029a058
--- /dev/null
+++ b/private/utils/ntbackup/src/omselnon.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/omselpar.bmp b/private/utils/ntbackup/src/omselpar.bmp
new file mode 100644
index 000000000..7c6a4f267
--- /dev/null
+++ b/private/utils/ntbackup/src/omselpar.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/omstring.rc b/private/utils/ntbackup/src/omstring.rc
new file mode 100644
index 000000000..c47d7312f
--- /dev/null
+++ b/private/utils/ntbackup/src/omstring.rc
@@ -0,0 +1,1515 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+
+ Name: strings.rc
+
+ Description: This file contains the references to string resources for
+ the 32-bit Windows/NT GUI Project Resource File developed
+ under contract to Microsoft Corp.
+
+ This file was created by copying and modifying
+ the WinterPark file: STRING.RC.
+
+ $Log: J:/UI/LOGFILES/OMSTRING.RCV $
+
+ Rev 1.80 24 May 1994 20:11:12 GREGG
+ Improved handling of ECC, SQL, FUTURE_VER and OUT_OF_SEQUENCE tapes.
+
+ Rev 1.79 26 Apr 1994 18:55:22 STEVEN
+ fix disconnect bug
+
+ Rev 1.78 04 Mar 1994 16:58:42 STEVEN
+ prompt if disk is full
+
+ Rev 1.77 11 Feb 1994 16:38:22 GREGG
+ Changed prompt for user to eject tape. EPR 948-0153
+
+ Rev 1.76 07 Feb 1994 02:06:12 GREGG
+ Fixed and expanded 'extended error reporting'.
+
+ Rev 1.75 27 Jan 1994 15:48:28 GREGG
+ Always ask to abort at EOF and don't display bytes remaining.
+
+ Rev 1.74 17 Jan 1994 13:32:18 GREGG
+ Changed translation error strings and ran spell checker on it (1 error found).
+
+ Rev 1.73 10 Jan 1994 21:02:02 STEVEN
+ fix minor grammer stuff
+
+ Rev 1.72 08 Jan 1994 14:58:48 MikeP
+ fix string internationalization characteristics
+
+ Rev 1.71 06 Jan 1994 14:10:40 GREGG
+ Fixed phrasing in SQL tape string.
+
+ Rev 1.70 05 Jan 1994 20:20:00 GREGG
+ Changed string defines for extended error reporting.
+
+ Rev 1.69 01 Dec 1993 14:19:10 mikep
+ add SQL recognition support to poll drive
+
+ Rev 1.68 16 Nov 1993 19:00:14 MARINA
+ fix hard coded text - NEED d_o_bkup.c
+
+ Rev 1.67 04 Nov 1993 16:28:20 STEVEN
+ fixes from WA
+
+ Rev 1.66 26 Oct 1993 18:10:24 BARRY
+ Added backupRegistry option
+
+ Rev 1.65 16 Aug 1993 15:07:24 BARRY
+ Added new strings to bring Nostradamus to UI tips.
+
+ Rev 1.64 29 Jun 1993 17:33:50 GLENN
+ Added new style about box support.
+
+ Rev 1.63 25 May 1993 14:57:36 GLENN
+ Added IDS_VLMDRIVESMSG.
+
+ Rev 1.62 23 May 1993 13:41:46 MIKEP
+ fix epr 294-489, adjust foreign tape as continuation tape msg.
+
+ Rev 1.61 21 May 1993 18:13:24 KEVINS
+ Added browse strings.
+
+
+ Rev 1.60 21 May 1993 10:25:48 chrish
+ This change is for both CAYMAN and NOSTRADAMUS.
+ NOSTRADAMUS EPR 0407: Added new string resource ... RES_SAME_TAPE_FAMILY.
+ The string is used when backing up across two tapes, to warn the user
+ when he has placed a second tape in the drive to be backed up that it
+ is of the same tape family.
+
+ Rev 1.59 21 May 1993 10:05:12 chrish
+ Minor clean-up, changed some mispelled words.
+
+ Rev 1.58 14 May 1993 14:12:20 CHUCKB
+ Added string for active files restored.
+
+ Rev 1.57 10 May 1993 16:16:02 chrish
+ NOSTRADAMUS EPR 0400 and 0172: Did not catch the fix in the veryfy and restore
+ processes of the backup app. Both EPR are the same ... message the tape is
+ rewinding when it already was rewound. Made correction to display proper
+ message.
+
+
+ Rev 1.56 07 May 1993 17:46:00 MIKEP
+ elaborate error msg to user
+
+ Rev 1.55 05 May 1993 10:46:20 MIKEP
+ add message to handle cataloging with full hard drive.
+
+ Rev 1.54 03 May 1993 15:02:04 chrish
+ Nostradamus EPR 0376: log file problem, no quotes around tape name.
+
+ Rev 1.53 03 May 1993 11:29:00 chrish
+ Nostradamous EPR 0172 and 0400: Added RES_TAPE_FULL_REWOUND resource string
+ to display a different message when spanning tape. Current message indication
+ that tape is rewinding when in effect by the time it display this message
+ the tape has been rewound.
+
+ Rev 1.52 02 May 1993 20:01:38 BARRY
+ Changed tense in "...differences was found" to "...differences were found"
+
+
+
+ Rev 1.51 30 Apr 1993 15:46:26 chrish
+ NOSTRADAMOUS EPR 0391: When user aborts operation instead of saying "...
+ operation completed successfully" now says "Operation completed". Will
+ get slightly different message when completed or aborted.
+
+
+ Rev 1.50 29 Apr 1993 17:33:58 DARRYLP
+ Changed DAily to Daily.
+
+ Rev 1.49 28 Apr 1993 16:30:54 CARLS
+ added RES_DRIVE_ERROR_DETECTED
+
+ Rev 1.48 22 Apr 1993 16:04:50 GLENN
+ Fixed event string to say NTBackup.
+
+ Rev 1.47 16 Apr 1993 14:34:32 MIKEP
+ add tape drive name
+
+ Rev 1.46 16 Apr 1993 09:49:30 MIKEP
+ add stings for cataloging
+
+ Rev 1.45 07 Apr 1993 17:56:02 CARLS
+ Changes for seek to end of data
+
+ Rev 1.44 07 Apr 1993 11:15:22 CHUCKB
+ Had a problem with chkout that caused me to lose the changes made for revisions
+ 1.34 through 1.40. This change was to put those changes back in.
+
+ Rev 1.43 02 Apr 1993 15:45:54 CARLS
+ changes for DC2000 unformatted tape
+
+ Rev 1.42 31 Mar 1993 10:42:48 MIKEP
+ add catalog message
+
+ Rev 1.41 25 Mar 1993 17:41:20 CHUCKB
+ Added string for aborting an operation (it isn't just for backups any more).
+
+ Rev 1.34 03 Mar 1993 14:17:06 DARRYLP
+ New read only drive strings
+
+ Rev 1.33 10 Feb 1993 13:13:32 ROBG
+ Renamed title of Tension dialog to ReTension.
+
+ Rev 1.32 10 Feb 1993 12:15:22 chrish
+ Added string resources dor description of backup/restore process info.
+
+ Rev 1.31 09 Feb 1993 10:04:16 CARLS
+ changed VERIFY_INFO from set label to description
+
+ Rev 1.30 09 Feb 1993 09:29:38 chrish
+ Added strings for backup/restore abort ....
+
+ Rev 1.29 27 Jan 1993 14:24:06 STEVEN
+ updates from msoft
+
+ Rev 1.28 18 Jan 1993 14:47:22 GLENN
+ Added Stream Error Reporting Strings and IDs.
+
+ Rev 1.27 06 Jan 1993 15:05:36 chrish
+ Added some more messages for tape security.
+
+ Rev 1.26 23 Dec 1992 13:28:32 MIKEP
+ fix name
+
+ Rev 1.25 23 Dec 1992 10:59:52 chrish
+ Minor string changes
+
+ Rev 1.24 22 Dec 1992 14:48:08 MIKEP
+ fix bytes processed messages
+
+ Rev 1.23 18 Nov 1992 17:13:06 MIKEP
+ on tapes resource
+
+ Rev 1.22 17 Nov 1992 20:09:02 MIKEP
+ unformated message
+
+ Rev 1.21 13 Nov 1992 17:27:12 chrish
+ Added stuff for Tape Security for NT
+
+ Rev 1.20 28 Oct 1992 16:45:58 chrish
+ Added string for Control Break Handling
+
+ Rev 1.19 19 Oct 1992 14:47:26 STEVEN
+ no more remaining size
+
+ Rev 1.18 15 Oct 1992 13:03:10 DAVEV
+ fix problem with batch mode /T option
+
+ Rev 1.17 09 Oct 1992 13:24:06 MIKEP
+ add daily backup type
+
+ Rev 1.16 02 Oct 1992 16:57:52 GLENN
+ Changed backup set name to backup description.
+
+ Rev 1.15 17 Sep 1992 16:54:08 STEVEN
+ added support for daily backup
+
+ Rev 1.14 04 Sep 1992 18:11:18 CHUCKB
+ Added string for sales pitch.
+
+ Rev 1.13 04 Sep 1992 14:32:04 STEVEN
+ file detail byte size is string
+
+ Rev 1.12 04 Sep 1992 10:09:32 GLENN
+ Changed underscore on continue button text.
+
+ Rev 1.11 02 Sep 1992 14:58:44 GLENN
+ Added catalog and davev added event logging stuff and
+ chuckb added about box stuff.
+
+ Rev 1.10 23 Jun 1992 17:37:10 DAVEV
+ added ids from strings.rc, modified RES_FOREIGN_TAPE_MSG
+
+ Rev 1.9 10 Jun 1992 16:11:22 GLENN
+ Updated according to NT SPEC.
+
+ Rev 1.8 05 Jun 1992 12:49:50 DAVEV
+ Added default log file name strings
+
+ Rev 1.7 01 Jun 1992 15:32:42 GLENN
+ Removed excess baggage from RES_DISPLAY_TAPE.
+
+ Rev 1.6 11 May 1992 14:28:16 DAVEV
+ Batch command line option strings added
+
+ Rev 1.5 23 Apr 1992 10:05:50 DAVEV
+ Added new strings from strings.h
+
+
+
+ Rev 1.4 27 Mar 1992 11:56:56 DAVEV
+ Added new ids from WinterPark. Added user name to tape description strings
+
+ Rev 1.3 25 Mar 1992 17:45:04 DAVEV
+ OEM_MSOFT: changes to meet spec.
+
+ Rev 1.2 18 Mar 1992 14:47:10 DAVEV
+
+
+ Rev 1.1 11 Mar 1992 17:03:38 DAVEV
+ integrated winterpark strings.h changes
+
+ Rev 1.0 03 Mar 1992 12:23:04 DAVEV
+ Initial revision.
+
+******************************************************************************/
+
+
+// SEE ALSO PRODDEFS.H -- PRODDEFS.H MUST BE TRANSLATED!!!!!
+
+
+// STRINGS -- ID's are defined in the Resource Manager Header File 'resmang.h'
+
+
+STRINGTABLE
+BEGIN
+
+IDS_APPNAME APPLICATIONNAME
+IDS_EXEFILENAME EXEFILENAME
+IDS_INIFILENAME INIFILENAME
+//IDS_PWDFILENAME PWDFILENAME
+
+IDS_CANTOPEN "Cannot open the file \042%s\042."
+IDS_CANTREAD "Cannot read the file \042%s\042."
+IDS_CANTCREATE "Cannot create the file \042%s\042."
+IDS_CANTWRITE "Cannot write the file \042%s\042."
+IDS_CANTCLOSE "Cannot close the file \042%s\042."
+IDS_ADDEXT ".TXT"
+IDS_ILLFNM "Invalid filename: %s"
+IDS_CLOSESAVE "%s has been changed. Save this file before closing?"
+IDS_CANTFIND "Cannot find %s."
+IDS_HELPNOTAVAIL "Cannot load Windows Help application."
+IDS_CLIENTTITLE "MaynStream"
+IDS_UNTITLED "Untitled"
+IDS_STDMODEWARNING "CAUTION! You are running Windows in Standard mode. Do not enter a DOS box while %s is running.\012\012\012To disable this message, choose Disable."
+IDS_APPVERSION ABOUTVERSION
+IDS_STARTUPTEXT "%s\012\012%s\012%s\012\012The finest backup software\012in the industry."
+IDS_COPYRIGHT COPYRIGHT
+IDS_COMPANY COMPANY
+IDS_APPMSGNAME APPMSGNAME
+IDS_APPEXEVER APP_EXEVER
+IDS_APPRESVER APP_RESVER
+IDS_APPENGREL APP_ENGREL
+IDS_CONGLOMERATE CONGLOMERATE
+IDS_LONGAPPNAME LONGAPPNAME
+IDS_SALESPITCH SALESPITCH
+
+IDS_BADUSERDATAPATH "WARNING! The Data Path specified, \042%s\042, is invalid.\012\012Defaulting to \042%s\042."
+IDS_BADCATDATAPATH "WARNING! The Catalog Path specified, \042%s\042, is invalid.\012\012Defaulting to \042%s\042."
+
+IDS_UNDERSCOREMARKER "&"
+IDS_FONTHELV "MS Shell Dlg"
+IDS_FONTSYSTEM "system"
+IDS_FONTCOURIER "courier"
+
+IDS_BADRESVER "Inconsistent resource files were found. Please reinstall %s."
+IDS_NORESFILE "The %s resource files were not found. Please reinstall %s."
+
+// OPERATION ACTIONS
+
+IDS_READY "Ready"
+IDS_INITIALIZING "Initializing..."
+IDS_BACKINGUP "Backing up files from disk to tape..."
+IDS_TRANSFERRING "Transferring files from disk to tape..."
+IDS_RESTORING "Restoring files from tape to disk..."
+IDS_VERIFYING "Verifying files..."
+IDS_RETENSIONING "Retensioning the tape..."
+IDS_ERASING "Erasing the tape..."
+IDS_CATALOGING "Cataloging the tape..."
+IDS_REWINDING "Rewinding the tape..."
+IDS_EJECTING "Ejecting the tape..."
+IDS_INITFILESYS "Initializing the file system..."
+IDS_INITHARDWARE "Initializing the hardware..."
+IDS_DIRSCANNED "Directories scanned: %d"
+IDS_CATMAINT "Partially catalog the tape or remove it from the catalog."
+IDS_NEXTSETTING "Searching for unknown backup sets..."
+IDS_INITCATALOGS "Initializing the catalogs..."
+IDS_INITUI "Initializing the user interface..."
+IDS_FORMATING "Formatting the tape..."
+
+
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+//
+// DO NOT EVER CHANGE THE ID NUMBERING BELOW 100.
+// BELOW 100 CONTAINS STRINGS THAT WILL NEVER CHANGE FROM VERSION
+// TO VERSION, THIS IS WHERE ALL VERSION STAMPS ARE KEPT FOR ALL
+// FUTURE RELEASES.
+//
+// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+
+// Ribbon Manager Item/Button Strings //CHANGE
+
+IDS_RIB_BACKUP "&Backup"
+IDS_RIB_RESTORE "&Restore"
+IDS_RIB_TRANSFER "&Transfer"
+IDS_RIB_ERASE "&Erase"
+IDS_RIB_RETENSION "Rete&nsion"
+IDS_RIB_JOBSTATUS "&Job Status"
+IDS_RIB_CHECK "&Check"
+IDS_RIB_UNCHECK "&Uncheck"
+IDS_RIB_MODIFIED "&Modified"
+IDS_RIB_ADVANCED "&Advanced"
+IDS_RIB_UNDO "&Undo"
+IDS_RIB_INCLUDE "&Include"
+IDS_RIB_EXCLUDE "E&xclude"
+IDS_RIB_VERIFY "&Verify"
+IDS_RIB_CATALOG "Cata&log"
+IDS_RIB_SEARCH "&Search"
+IDS_RIB_NEXTSET "&Next Set"
+IDS_RIB_EJECT "&Eject"
+IDS_RIB_REWIND "Re&wind"
+IDS_RIB_EXIT "E&xit"
+
+IDS_RIB_MEMDEBUG "Memory Trace ON/OFF"
+IDS_RIB_STATLINE "Status Line"
+
+/* button strings used in msgbox.c */
+
+IDS_BUT_OK "OK"
+IDS_BUT_CANCEL "Cancel"
+IDS_BUT_RETRY "&Retry"
+IDS_BUT_YES "&Yes"
+IDS_BUT_NO "&No"
+IDS_BUT_CONTINUE "&Continue"
+IDS_BUT_ABORT "&Abort"
+IDS_BUT_HELP "&Help"
+IDS_BUT_DISABLE "&Disable"
+IDS_BUT_IGNORE "&Ignore"
+
+// Menu Item Status Line Help Strings
+
+IDS_OPERATIONSBACKUP "Back up data from disk to tape."
+IDS_OPERATIONSRESTORE "Restore data from tape to disk."
+IDS_OPERATIONSCATALOG "Catalog and search tape for backup sets."
+IDS_OPERATIONSERASE "Erase a Tape"
+IDS_OPERATIONSRETENSION "Retension a Tape"
+IDS_OPERATIONSEJECT "Rewind and Eject the Tape"
+IDS_OPERATIONSHARDWARE "Change Hardware specific settings"
+IDS_OPERATIONSEXIT "Exit this application; close it down"
+IDS_OPERATIONSFORMAT "Format a tape"
+#ifdef OEM_EMS
+IDS_OPERATIONSEXCHANGE "Connect to a Microsoft Exchange server."
+#endif
+
+IDS_TREEEXPANDONE "Expand the Tree One Level down"
+IDS_TREEEXPANDBRANCH "Expand the current branch"
+IDS_TREEEXPANDALL "Expand All branches"
+IDS_TREECOLLAPSEBRANCH "Collapse the current branch"
+
+IDS_VIEWTREEANDDIR "Show the tree list and the directory list."
+IDS_VIEWTREEONLY "Show only the tree list."
+IDS_VIEWDIRONLY "Show only the directory list."
+IDS_VIEWALLFILEDETAILS "Show all of the file details."
+IDS_VIEWSTATUS "Show/Hide the Status Bar."
+IDS_VIEWURIBBON "Show/Hide the Tool Bar."
+IDS_VIEWFONT "Select a new font."
+IDS_VIEWSPLIT "Create a split bar to resize tree and directory windows."
+
+IDS_SELECTCHECK "Check the highlighted item(s)"
+IDS_SELECTUNCHECK "Uncheck the highlighted item(s)"
+
+IDS_WINDOWSCASCADE "Overlap active windows."
+IDS_WINDOWSTILE "Place active windows adjacent to one another."
+IDS_WINDOWSARRANGEICONS "Arrange all icons."
+IDS_WINDOWSREFRESH "Update the contents of the active window."
+IDS_WINDOWSCLOSEALL "Close all user created windows."
+
+IDS_HELPINDEX "Display the Help Index window."
+IDS_HELPSEARCH "Search for information on a specific subject"
+IDS_HELPKEYBOARD "Display help on the available keystroke commands."
+IDS_HELPCOMMANDS "Display help on the available commands."
+IDS_HELPPROCEDURES "Display help on MaynStream procedures."
+IDS_HELPUSINGHELP "Display help on using the Help system."
+IDS_HELPABOUTNOSTRADOMUS ABOUTAPPLICATIONNAME
+
+
+// DEFINES for the RUNTIME DIALOGS
+
+IDS_DLGTITLEJOBSTATBACKUP "Backup Status"
+IDS_DLGTITLEJOBSTATRESTORE "Restore Status"
+IDS_DLGTITLEJOBSTATTRANSFER "Transfer Status" //DEL
+IDS_DLGTITLEJOBSTATVERIFY "Verify Status"
+IDS_DLGTITLEJOBSTATCATALOG "Catalog Status" //DEL?
+IDS_DLGTITLEJOBSTATTENSION "Retension Status"
+IDS_DLGTITLEJOBSTATERASE "Erase Status"
+IDS_DLGTITLEJOBSTATDELETE "Delete Status"
+IDS_DLGTITLEJOBSTATFORMAT "Format Status"
+
+// STRINGS for the HELP MANAGER
+
+IDS_HMHELPFILENAME HLPFILENAME
+IDS_HMKEYWORDKEYS "keys"
+IDS_HMKEYWORDCOMMANDS "commands"
+IDS_HMKEYWORDPROCS "procedures"
+IDS_HMUSINGHELPFILENAME "winhelp.hlp"
+IDS_HMNOHELPFILE "Help file \042%s\042 was not found."
+
+
+// defines for launcher
+
+//IDS_LCHAPPNAME LCHAPPLICATIONNAME
+//IDS_LCHEXITAPP "To run a scheduled job, please exit "
+//IDS_LCHDELAYTITLE LCHDELAYTITLE
+//IDS_LCHWNTRPARKEXE "winback.exe"
+//IDS_LCHEXECUTIONERROR "Launcher was unable to execute WINBACK.EXE."
+//IDS_LCHONHOLD "Hold"
+//IDS_LCHACTIVE "Ready"
+//IDS_LCHRUNNING "Running"
+//IDS_LCHTOOMANYCLOCKS "Too many clocks or timers in system."
+//IDS_LCHABORTED "Aborted"
+//IDS_LCHDELAYED "Delayed"
+//IDS_LCHMISSED "Missed"
+//IDS_LCHSKIPMSG "Skipping this job will remove it from the schedule list. Do you wish to continue?"
+
+
+IDS_RESTOREPATHINVALID "Specified path is not valid."
+IDS_RESTOREEMSSERVERINVALID "Connection could not be made to the Microsoft Exchange services on the specified server."
+IDS_RESTOREEMSWARNING "You are about to restore Microsoft Exchange components. The Microsoft Exchange services on the destination server will be stopped."
+IDS_RESTOREEMSNOWIPE "You cannot delete the existing data if you don't restore both the public and private stores."
+IDS_DONT_SPECIFY_DRIVE "Path cannot contain a drive designator."
+IDS_DONT_SPECIFY_FNAME "Path cannot contain a file name."
+IDS_RESTORESTOPEXCHANGE "Shutting down Microsoft Exchange services before restoring."
+IDS_RESTORESTARTEXCHANGE "Starting Microsoft Exchange services on \\\\%s.\n Be sure to verify that this service has started successfully."
+IDS_STARTEXCHANGE "Microsoft Exchange service is starting. Be sure to verify that it has started successfully."
+IDS_RESTOREBEGINEXCHANGE "Copying Microsoft Exchange database files."
+RES_RESTOREWRITEERROR "Unable to restore data to %s,\ncheck the application event log for more information."
+IDS_EMS_NO_INC_DS_BACKUP "\\\\%s Directory\nA Normal or Copy type backup must be performed on this Microsoft Exchange component before a Differential or Incremental type backup can be performed on it."
+IDS_EMS_NO_INC_IS_BACKUP "\\\\%s Information Store\nA Normal or Copy type backup must be performed on this Microsoft Exchange component before a Differential or Incremental type backup can be performed on it."
+IDS_EMS_CIRC_LOGS_DS "\\\\%s Directory\nCircular Logging is turned on for this Microsoft Exchange component. Only Normal or Copy type backups can be performed while Circular Logging is turned on."
+IDS_EMS_CIRC_LOGS_IS "\\\\%s Information Store\nCircular Logging is turned on for this Microsoft Exchange component. Only Normal or Copy type backups can be performed while Circular Logging is turned on."
+IDS_EMS_NO_DEST_DRIVE "You must enter a Destination Server."
+IDS_EMS_MUST_PUB_OR_PRI "You must choose to restore the Private or Public or both Information Stores."
+IDS_EMS_NOT_RESPONDING_DS "Directory service on \\\\%s is not responding."
+IDS_EMS_NOT_RESPONDING_IS "Information Store service on \\\\%s is not responding."
+IDS_RESTOREEMSMUSTWIPE "You must select 'Erase all existing data' if the Destination Server is not the same as the Original Server."
+IDS_EMS_NO_PUBLIC_SERVICE "You have selected to restore the Public database to a Private only server.\n"
+IDS_EMS_NO_PRIVATE_SERVICE "You have selected to restore the Private database to a Public only server.\n"
+
+IDS_BACKUP_TYPE "Backup Method: %s\n"
+IDS_WIPE_SPECIFIED "Deleting existing log files."
+
+// defines for Job processing //DEL?
+
+IDS_JOBPROGMAN "PROGMAN"
+IDS_JOBPMGROUP "PMGROUP"
+IDS_JOBDEFAULTGROUP APPGROUP
+IDS_JOBNOPROGMAN "Insertion failed. Program Manager must be running."
+IDS_JOBPROGMANTITLE "Job Icon for Program Manager"
+IDS_JOBPROGMANCONFIRM "Inserting Job \042%s\042 into Group \042%s\042. Do you want to continue?"
+IDS_JOBPROGMANCREATEGROUP "[CreateGroup(%s)]"
+IDS_JOBPROGMANFORMATLINE "[CreateGroup(%s)][ShowGroup(%s,5)][AddItem(%s%s /J:\042%s\042,%s,%s%s,%s )]"
+IDS_JOBFILENAME JOBFILENAME
+IDS_JOBBACKUPICONVALUE "14"
+IDS_JOBTRANSFERICONVALUE "16"
+IDS_JOBRESTOREICONVALUE "15"
+IDS_JOBCOMMANDLINE "/J:\042"
+IDS_JOBSTARTEDLOGMSG "Job \042%s\042 began execution on %s at %s."
+IDS_JOBFINISHEDLOGMSG "Job \042%s\042 ended execution on %s at %s."
+IDS_JOBNOTFOUNDLOGMSG "Job \042%s\042 was not found on %s at %s.\n"
+IDS_JOBMOREJOBS "&More Jobs..."
+IDS_JOBSCHEDULEDJOB "** Scheduled **"
+IDS_JOBEXECERROR "Job Execution Error."
+IDS_JOBWRONGMETHOD "Method has been changed to copy."
+
+// names for automatic jobs (to go with verify.bks and skipped.bks) //DEL?
+
+IDS_VERIFY_JOBNAME "VERIFY"
+IDS_SKIPPED_JOBNAME "SKIPPED"
+
+// error message for when a job can't find its selection file
+
+IDS_JOB_SELNOTFOUNDLOGMSG "Selection File \042%s\042 was not found on %s at %s.\n"
+IDS_JOB_SELNOTVALIDLOGMSG "\nSelection File \042%s\042 was found on %s at %s, but contained\nno valid selections for the settings at that time.\n"
+
+// defines for Schedule processing //DEL?
+
+IDS_SCHEXTENSION "*.SEL"
+IDS_SCHFILENAME SCHFILENAME
+IDS_SCHCOMMANDLINE "/S:"
+IDS_SCHUNIQUEKEY "/K:"
+
+// Job/Schedule error message strings //DEL?
+
+IDS_JOBIOERR "Job File Error"
+IDS_SCHEDULEIOERR "Schedule File Error"
+IDS_JOBISSCHEDULED "This job has been scheduled."
+
+// The days of the week
+
+IDS_DAYOFTHEWEEK "Day of the Week"
+
+IDS_MONDAY "Monday"
+IDS_TUESDAY "Tuesday"
+IDS_WEDNESDAY "Wednesday"
+IDS_THURSDAY "Thursday"
+IDS_FRIDAY "Friday"
+IDS_SATURDAY "Saturday"
+IDS_SUNDAY "Sunday"
+
+// days of the week hot keys
+
+IDS_MONDAYKEY "&Monday"
+IDS_TUESDAYKEY "&Tuesday"
+IDS_WEDNESDAYKEY "&Wednesday"
+IDS_THURSDAYKEY "T&hursday"
+IDS_FRIDAYKEY "&Friday"
+IDS_SATURDAYKEY "&Saturday"
+IDS_SUNDAYKEY "S&unday"
+
+// Weeks of the month
+
+IDS_WEEKOFTHEMONTH "Week of the Month"
+
+IDS_FIRSTWEEK "&First"
+IDS_SECONDWEEK "&Second"
+IDS_THIRDWEEK "&Third"
+IDS_FOURTHWEEK "Fo&urth"
+IDS_LASTWEEK "&Last"
+
+// Backup set description dialog method text
+
+IDS_METHOD_NORMAL "Normal"
+IDS_METHOD_COPY "Copy"
+IDS_METHOD_INCREMENTAL "Incremental"
+IDS_METHOD_DIFFERENTIAL "Differential"
+IDS_METHOD_DAILY "Daily"
+
+IDS_DEFAULT_TAPE_NAME "Tape created on %s"
+IDS_BKUP_PASSWORD_ERROR "Passwords do not match. Would you like to try again?"
+IDS_BKUP_SHORT_PASSWORD_ERROR "Passwords do not match."
+IDS_BKUP_PASSWORD_ERROR_TITLE "Password Error"
+IDS_SET_INFORMATION " Backup Set Information (%d of %d sets) "
+IDS_NO_BSET_NAME "< Not Named >"
+IDS_TAPE_PASSWORD_PROTECTED "Tape is password protected."
+IDS_XCHG_BKUP_NAME "%s \\\\%s"
+
+
+//
+// Tape Security for NT
+//
+
+IDS_BKUP_TAPE_SECURITY "This tape has been secured. You do not have the proper backup privileges."
+IDS_TAPE_SECURITY_TITLE "Tape Security Violation"
+IDS_REST_TAPE_SECURITY "This tape has been secured. You do not have the proper restore privileges."
+IDS_ERASE_TAPE_SECURITY "This tape has been secured. You do not have the proper erase privileges."
+IDS_GENERAL_TAPE_SECURITY "This tape has been secured. You do not have the proper privileges."
+
+// Catalog defines
+
+IDS_TAPEOUTOFSEQUENCE "Warning: This tape is out of sequence."
+IDS_ALLTAPES "All Tapes"
+IDS_ALLFILES "*.*"
+IDS_CATALOGSETNAME "Catalogs Backup" //DEL OR CHANGE?
+IDS_CANTDELTAPEINDRIVECAPTION "Catalog Maintenance Error" //DEL OR CHANGE?
+IDS_CANTDELTAPEINDRIVE "The tape in the drive cannot be removed from the catalog." //CHANGE?
+
+IDS_CATINFOTITLE "Catalog Information"
+IDS_NOSETSADDED "No uncataloged sets were found on the tape."
+
+IDS_CHANGETOPARTIAL "Change to Partially Cataloged"
+
+IDS_REALLYCHANGETOPARTIAL "Do you really want to change %s to partially cataloged?"
+IDS_DELETEFROMCATALOG "Remove backup set from catalog"
+IDS_REALLYDELETEFROMCATALOG "Do you really want to remove tape %s from the catalog?"
+
+// Attach-to-server defines
+
+IDS_LOGINTOSERVERCAPTION "Login to: " //DEL
+
+// Selection and Job Setup defines
+
+IDS_ALLSELECTIONFILES "*.BKS"
+IDS_SELECTIONEXTENSION ".BKS"
+
+IDS_NETWORKERRORCAPTION "Selections invalid for current network setting." //DEL all network stuff
+IDS_MAPPEDFOUND "Network setting is currently Server/Volumes, but mapped drives were found. Do you wish to continue?"
+IDS_SERVERSFOUND "Network setting is currently Mapped Drives, but server/volumes were found. Do you wish to continue?"
+IDS_SERVOLUMES "Server/Volumes"
+IDS_MAPPEDDRIVES "Mapped Drives"
+
+IDS_SELECTCAPTION "Advanced File Selection" //DEL
+IDS_NOSERVERSFOUND "No servers are currently attached." //DEL
+
+IDS_ADVANCEDDATESCAPTION "Please check the dates again." //DEL
+IDS_ADVANCEDDATESMESSAGE "The 'To' date must be later than the 'From' date." //DEL
+IDS_NOFILESSELECTED "No Files Selected."
+
+IDS_SELECTWARNING "Confirm Deletion of Selection File"
+IDS_SELECTAREYOUSURE "Are you sure you want to delete the file \042%s\042?"
+IDS_SELECTUSEDBYJOB "Selection file \042%s\042 is being used by job \042%s\042. "
+
+IDS_SELECTNAMEINUSE "%s Already Exists."
+IDS_SELECTREPLACE "Do you want to replace \042%s\042?"
+IDS_SELECTNAMENOTVALID "Invalid File Name"
+IDS_SELECTENTERVALID "Please enter a valid file name."
+
+IDS_ADVNOTAPESCATALOGED "A tape must be cataloged before making advanced selections."
+IDS_ADVNOTAPESCATALOGEDCAPTION "No tapes are cataloged."
+
+IDS_SELECTNOTFOUND "Selection file \042%s\042 could not be found."
+IDS_NONETWORKFOUND "This selection file contains selections from a network drive that could not be found."
+
+IDS_SELECT_WRITE_ERROR "Unable to open selection file."
+
+// jobs //DEL all jobs stuff
+
+IDS_JOBWARNING "Delete a Job"
+IDS_SCHWARNING "Removing a Scheduled Job"
+IDS_JOBAREYOUSURE "Are you sure you want to delete job \042%s\042?"
+IDS_SCHAREYOUSURE "Are you sure you want to remove job \042%s\042?"
+
+IDS_NOJOBSELECTED "No Job Selected"
+IDS_PLSSELECTJOBRUN "Please select a job to run."
+IDS_PLSSELECTJOBEDIT "Please select a job to edit."
+IDS_NEWJOBCAPTION "Create a New Job"
+IDS_JOBNAMEINUSE "Job \042%s\042 already exists."
+IDS_NOMORESPACE "No more job space available."
+IDS_JOBNOTINLIST "Job is not in the Job List."
+IDS_JOBNAMENOTVALID "Invalid Job Name"
+IDS_PLSSELECTVALIDJOB "Please select a valid job name."
+IDS_PLSENTERVALIDJOB "Please enter a valid job name."
+IDS_EDITJOB "Edit a Job"
+
+// job operations
+
+IDS_OPERATIONBACKUP "BACKUP"
+IDS_OPERATIONTRANSFER "TRANSFER"
+
+// Errors with days/times/time intervals //DEL?
+
+IDS_NODAYCHECKED "No day of the week specified."
+IDS_PLSSELECTDAY "Please check at least one day of the week."
+IDS_NOWEEKCHECKED "No week of the month specified."
+IDS_PLSSELECTWEEK "Please check at least one week of the month."
+IDS_FILENAMENOTVALID "Invalid File Name"
+IDS_INTERVALNOTVALID "Invalid Interval"
+
+IDS_NEXTTIMEINVALID "Invalid Next Time"
+IDS_CHECKMINUTES "Check the minutes and try again."
+IDS_CHECKHOURS "Check the hours and try again."
+IDS_CHECKAMPM "Check the am or pm and try again."
+IDS_CHECKDAY "Check the day and try again."
+IDS_CHECKMONTH "Check the month and try again."
+IDS_CHECKYEAR "Check the year and try again."
+
+IDS_ALLBSETS "All backup sets"
+
+// Default International strings
+
+IDS_DEFAULT_SHORTDATE "MM/dd/yyyy"
+IDS_DEFAULT_TIME ":"
+IDS_DEFAULT_1159 "am"
+IDS_DEFAULT_2359 "pm"
+IDS_DEFAULT_THOUSAND ","
+
+// DEBUG MANAGER STRINGS
+
+IDS_DEBUGWARNING "Debug Settings Warning"
+IDS_DEBUGMESSAGESTOOLOW "The number of debug messages to keep must be at least 10."
+IDS_DEBUGMESSAGESTOOHIGH "The number of debug messages to keep may not be greater than 250."
+IDS_DEBUGBADFILENAME "The file name may not contain blanks."
+
+// LOG FILE MANAGER STRINGS
+
+IDS_LOGFILESWINDOWNAME "Log Files"
+IDS_LOGVIEWMINWINDOWNAME "View Log File"
+IDS_LOGHEADERFILENAME "Log File Name: %s"
+IDS_LOGHEADERDATE "Current Date: %s"
+IDS_LOGHEADERTIME "Current Time: %s"
+IDS_LOGLOGGEDON "Logged on"
+IDS_LOGSTRINGAT "at"
+IDS_LOGLENGTHOFFILE "%8ld bytes"
+IDS_LOGFILENAMEPREFIX " for "
+IDS_LOGPREFIX SHORTAPPNAME
+IDS_LOGEXTENSION ".LOG"
+IDS_LOG_BKS ".BKS"
+IDS_LOG_TKS ".TKS"
+IDS_LOG_RSS ".RSS"
+IDS_LOG_LST ".LST"
+IDS_LOGMAXLINES "Log file contains more than %ld lines."
+IDS_LOGMAXSUPPORT "%s supports viewing only the first %ld lines."
+IDS_LOGSCANNINGFILE "Scanning log file..."
+
+// PRINT MANAGER STRINGS //DEL all print manager stuff
+
+IDS_PRTHEADERFORMAT " Page %4d Date: %s Time: %s Log File Name: %s"
+IDS_PRTSESSIONLOGQUESTION "Do you want to print the log file?"
+IDS_PRTSETUPALREADYOPEN "A Printer Setup dialog box is already open.\012 Close it and try again."
+IDS_PRTPMTITLE "Print Manager"
+IDS_PRTDEFAULT "A default printer must be specified."
+IDS_PRTNOLOGSSELECTED "There are no log files selected to be printed."
+IDS_PRTPRINTINGABORTED "Printing of log files canceled."
+IDS_PRTPRINTINGCOMPLETE "Printing of log files complete."
+IDS_PRTNUMOFLOGFILES "%d log files"
+IDS_PRTONELOGFILE "%d log file"
+IDS_PRTSTARTERROR "Unable to start the print operation."
+IDS_PRTDRIVERNOTFOUND "Printer driver not found."
+IDS_PRTCANNOTACCESSDRIVER "Cannot access the specified printer driver."
+IDS_PRTPRINTSTATUS "Printing \042%s\042 Page %4d. Choose <Esc> to cancel."
+IDS_PRTPRINTCOMPLETE "Printing \042%s\042 complete."
+IDS_PRTPRINTERDRIVERERROR "Printer driver error. Setup failed."
+IDS_PRTNOPRINTERSAVAILABLE "There are no printers available."
+IDS_PRTONSTRING " on "
+IDS_PRTUNACCESSABLE "Printer is currently unavailable."
+
+// EJECT STRINGS
+
+IDS_EJECTTAPEMESSAGE "Eject Tape"
+IDS_EJECTTAPEMANUALEJECT "The tape has been rewound.\012Please remove the tape and choose OK to continue."
+IDS_EJECTTAPENOTAPE "There is no tape in the drive."
+IDS_EJECTTAPEBIGPROBLEM "Tape Eject Failed.\012 Not possible to eject tape now."
+
+// EJECT STRINGS
+
+
+
+// MEMORY MANAGER STRINGS
+
+IDS_MEMNORUNAPP "Insufficient memory available. Close other applications before starting this application again."
+IDS_MEMRETRY "Insufficient memory available. To continue, close another application and choose Retry or choose Cancel to quit."
+IDS_MEMFAILED "Insufficient memory available."
+
+// Read Only drive support...
+
+IDS_RDONLY_DRV_ENCOUNTER "Read Only Drive Encountered!"
+IDS_RDONLY_COPY "Drive %s will not have the attribute bits reset during backup."
+
+// Browse strings
+
+IDS_BROWSETITLE "Browse"
+IDS_BROWSELOGFILES "Log Files(*.LOG)"
+IDS_BROWSELOGFILESEXT "*.log"
+IDS_BROWSEALLFILES "All Files(*.*)"
+IDS_BROWSEALLFILESEXT "*.*"
+
+
+// Extended error reporting stuff
+
+IDS_GENERR_TITLE "Tape Drive Error"
+IDS_GENERR_DRIVER_FAIL1 "Tape device driver failed on a request to %s."
+IDS_GENERR_DRIVER_FAIL2 "Tape device failed on a request to %s."
+IDS_GENERR_DRIVE_FAILED "Tape device reported an error on a request to %s.\n\nError reported:\n%s."
+
+IDS_GENERR_TIMEOUT "Timeout before function completed"
+IDS_GENERR_EOM "End of media early warning"
+IDS_GENERR_BAD_DATA "Unrecognizable data"
+IDS_GENERR_NO_MEDIA "No tape is in drive"
+IDS_GENERR_ENDSET "File mark encountered"
+IDS_GENERR_NO_DATA "No data exists"
+IDS_GENERR_INVALID_CMD "Command is not valid"
+IDS_GENERR_RESET "Bus reset"
+IDS_GENERR_WRT_PROTECT "Write protected tape"
+IDS_GENERR_HARDWARE "Hardware failure"
+IDS_GENERR_UNDETERMINED "Unknown error"
+IDS_GENERR_EOM_OVERFLOW "Attempt to move past end of tape"
+IDS_GENERR_WRONG_BLOCK_SIZE "Device block size differs from size with which tape was written"
+IDS_GENERR_UNRECOGNIZED_MEDIA "Tape is not formatted"
+IDS_GENFUNC_INIT "initialize"
+IDS_GENFUNC_OPEN "claim device"
+IDS_GENFUNC_NRCLOSE "close device"
+IDS_GENFUNC_RCLOSE "deinitialize"
+IDS_GENFUNC_READ "read data from tape"
+IDS_GENFUNC_WRITE "write data to tape"
+IDS_GENFUNC_WRITE_ENDSET "write a file mark to tape"
+IDS_GENFUNC_SPACE_FWD_FMK "space forward by file marks"
+IDS_GENFUNC_SPACE_BKWD_FMK "space backward by file marks"
+IDS_GENFUNC_SPACE_EOD "space to end of data"
+IDS_GENFUNC_SPACE_FWD_BLK "space forward by blocks"
+IDS_GENFUNC_SPACE_BKWD_BLK "space backward by blocks"
+IDS_GENFUNC_ERASE "erase the tape"
+IDS_GENFUNC_REWIND "rewind the tape"
+IDS_GENFUNC_REWINDI "rewind the tape"
+IDS_GENFUNC_RETEN "retension the tape"
+IDS_GENFUNC_STATUS "get device status"
+IDS_GENFUNC_RELEASE "release device"
+IDS_GENFUNC_SEEK "seek to a logical tape address"
+IDS_GENFUNC_GETPOS "report current logical tape address"
+IDS_GENFUNC_MOUNT "mount the tape"
+IDS_GENFUNC_DISMOUNT "dismount the tape"
+IDS_GENFUNC_SPECIAL_GET_INFO "get device information"
+IDS_GENFUNC_SPECIAL_CHNG_BLK_SIZE "change physical block size"
+IDS_GENFUNC_SPECIAL_SET_COMPRESS "enable/disable hardware compression"
+IDS_GENFUNC_EJECT "eject the tape"
+
+
+// VLM
+
+IDS_VLMDISKTITLE "Drives"
+IDS_VLMSERVERTITLE "Servers"
+IDS_VLMSEARCHTITLE "Search Results"
+IDS_VLMTAPETITLE "Tapes"
+IDS_VLMSRCHOOPS "Error"
+IDS_VLMSRCHNOFILESFOUND "No matching files were found."
+IDS_VLMSRCHNOMATCHINGSETS "None of the backup sets matched the requested volume."
+IDS_VLMSRCHTOOMANY "Too many files matched the selection criteria. More files were found than will be displayed."
+IDS_VLMSRCHNOCATALOGS "There are no cataloged tapes to search."
+IDS_VLMSRCHBADFILENAME "Invalid file name."
+IDS_VLMSRCHINGWHAT "Searching tape \042%s\042, set %d"
+IDS_VLMFILESSCANNED "Files scanned: %d"
+IDS_VLMCATWARNING "Catalog Warning"
+IDS_VLMSETINCOMPLETE "This set is not completely cataloged."
+IDS_VLMSETPARTIAL "This set must be cataloged before it can be viewed."
+IDS_VLMSETIMAGE "Image backups cannot be viewed or restored."
+IDS_VLMCATERROR "Catalog Error"
+IDS_VLMCATREADERROR "Error reading a catalog file, the file may be corrupted."
+IDS_VLMCATWRITEERROR "Error writing a catalog file, check available disk space."
+IDS_VLMCATOPENERROR "Error opening a catalog file, check available disk space, and Verify that you have full access to the Working Directory."
+IDS_VLMCATHANDLEERROR "Not enough available file handles."
+IDS_VLMCATSEEKERROR "Error positioning in a catalog file. The file may be corrupted."
+IDS_VLMCATMEMERROR "Insufficient memory available."
+IDS_VLMCATFULLERROR "Insufficient disk space. Verify that you have full access to the Working Directory and there is disk space available."
+IDS_VLMCATUNKNOWNERROR "Unknown error."
+IDS_VLMLOGERROR "Logging error"
+IDS_VLMLOGFULLERROR "Insufficient disk space. Verify that you have full access to the Working Directory and there is disk space available."
+IDS_VLMDEVICEERRORTITLE "Device Error."
+IDS_VLMDEVICEERRORMSG "Drive not responding."
+IDS_VLMSETNUMBER "Set %d"
+IDS_VLMNORM "norm"
+IDS_VLMIMAGE "image"
+IDS_VLMDIFF "diff"
+IDS_VLMCOPY "copy"
+IDS_VLMINCR "incr"
+IDS_VLMDAILY "daily"
+IDS_VLMSERVERNOTLOGGEDIN "You are not logged on to the server."
+IDS_VLMSTARTUPBKS "STARTUP.BKS"
+IDS_VLMTAPENAME "Untitled Tape"
+IDS_VLMAFPTITLE "Warning"
+IDS_VLMAFPTEXT "All open volumes for this server must be closed."
+IDS_TITLEERASEWARNING "Erase Warning"
+IDS_TEXTERASEWARNING "Are you sure you want to erase the tape in the drive ?"
+IDS_VLMONTAPES "Tapes %d/%d"
+IDS_VLMONTAPE "Tape %d"
+IDS_VLMFOREIGNTITLE "Foreign Tape"
+IDS_VLMFOREIGNTEXT "The tape in the drive must be erased before it can be used."
+IDS_VLMUNFORMATEDTITLE "Unrecognizable Tape"
+IDS_VLMUNFORMATEDTEXT "The tape in the drive has an unrecognizable format or is not formatted."
+IDS_VLMDRIVEMSG "Drive %s %s"
+IDS_VLMGOOFYTITLE "Out of Sequence Error"
+IDS_VLMGOOFYTEXT "Tapes in this family require sequential access. Only tape one of the family can be independently identified."
+
+IDS_VLMSETCOMPRESSED "This set is compressed and cannot be viewed or restored."
+IDS_VLMSETENCRYPT "This set is encrypted and cannot be viewed or restored."
+IDS_VLMSETFUTURE "This set was written with a newer version of software and cannot be viewed or restored."
+IDS_VLMSETSMS "This set contains an SMS data stream and cannot be viewed or restored."
+IDS_VLMSQLTEXT "This tape was created with Microsoft(R) SQL Server(c). The data cannot be translated by this application."
+
+IDS_VLMEMSTITLE "Microsoft Exchange - %s"
+
+IDS_VLMECCTEXT "This tape was written with software ECC and cannot be read by this application."
+IDS_VLMFUTURETEXT "This tape was made with a newer version of software and cannot be read by this application."
+IDS_VLMACCESSDENIEDMSG "Access Denied."
+
+IDS_DISKFULL_TITLE "Error Restoring File"
+IDS_DISKFULL "Backup cannot restore %s: There is not enough space on the disk.\n\nDelete one or more files to increase disk space, and then try again."
+
+IDS_XCHNG_NO_SERVER "Specified computer cannot be found."
+IDS_XCHNG_NO_CONNECT "Specified computer is not a Microsoft Exchange server or its Microsoft Exchange services are not started."
+IDS_XCHNG_STOP_RECOVER "The connection to the server being restored will be terminated and no further progress indication will be available. The recovery procedure will continue on the server and cannot be interrupted."
+IDS_XCHNG_RECOVER_TITLE "Microsoft Exchange"
+IDS_XCHNG_SERVICE_NO_START "Microsoft Exchange service failed to start."
+IDS_XCHNG_SERVICE_RUNNING "Microsoft Exchange service is already running on the specified computer."
+IDS_XCHNG_NO_SERVICE "Specified computer is not a Microsoft Exchange server."
+IDS_XCHNG_NO_SERVICE_ACCESS "Your account does not have access to start the Microsoft Exchange services on the specified computer."
+IDS_XCHNG_DIR "Directory"
+IDS_XCHNG_INFO_STORE "Information Store"
+IDS_XCHNG_NO_SERVICE_RUNNING "The Microsoft Exchange %s service is not \nstarted on the selected computer."
+IDS_XCHNG_BKUP_IN_PROG "The selected Microsoft Exchange service is currently \nbeing backed up by another process."
+
+// Loops
+
+IDS_LOOPSOUTOFSEQUENCE "This tape is out of sequence."
+IDS_CAT_LOADING_SM "Loading set list from tape."
+IDS_CAT_LOADING_FDD "Loading set directory from tape."
+IDS_CAT_TAPENAME "The tape"
+IDS_TAPEDRIVENAME "the tape drive"
+IDS_CATLOADERROR "Unable to load catalog data from the tape."
+IDS_BACKUPERRORTITLE "Backup Error"
+IDS_BACKUPWRONGFAMILY "Current tape is from a different tape family."
+
+
+
+// MAYNARD MSII.RES STRINGS
+
+RES_ABORT_KEY "A"
+RES_ABORT_RETRY_FAIL "Abort, Retry, Fail? "
+RES_ABORT_STRING APPABORT
+RES_ABORT_QUESTION "Do you want to end this operation? "
+RES_AFTER_NOON "p"
+RES_ALREADY_CATALOGED_SET "Backup set #%d: %s\nPreviously cataloged"
+RES_APPEND_QUEST "Do you want to append data to this tape? "
+RES_ARCHIVE_NO_SELECTIONS "Nothing selected for Transfer."
+RES_ARCHIVE_REPLACE_WARNING "WARNING: This tape was created with the Transfer option. The data on this tape may have been permanently erased from your disk."
+RES_BACKED_UP_CORRUPT "One corrupted file was backed up."
+RES_BACKED_UP_CORRUPTS "%ld corrupted files were backed up."
+RES_BACKED_UP_CORRUPT_WARNING "File %s is corrupted.\nThis file cannot be verified."
+RES_BACKED_UP_DIRS_FILES "Backed up %ld files in %ld directories."
+RES_BACKED_UP_DIRS_FILE "Backed up %ld file in %ld directories."
+RES_BACKED_UP_DIR_FILE "Backed up %ld file in %ld directory."
+RES_BACKED_UP_DIR_FILES "Backed up %ld files in %ld directory."
+RES_BACKED_UP_IN_USE "%ld file was in use."
+RES_BACKED_UP_IN_USES "%ld files were in use."
+RES_BACKED_UP_IN_USE_WARNING "File %s is in use but is being backed up anyway."
+RES_BACKED_UP_MAC "%ld Macintosh file was backed up."
+RES_BACKED_UP_MACS "%ld Macintosh files were backed up."
+RES_BACKUP_COMPLETED "Backup completed on %s at %s."
+RES_BACKUP_NO_SELECTIONS "No files were selected for Backup."
+RES_BACKUP_STARTED "Backup started on %s at %s."
+RES_BAD_ATTACH_TO_SERVER "Unable to attach to server %s."
+RES_BAD_ATTR_READ "WARNING: Unable to read extended file information for file \042%s\042."
+RES_BAD_SERVER_LOGIN "Unable to login to server %s. Enter another user name and password."
+RES_BENGINE_IN_USE "The MaynStream software is already in use on this system. Concurrent use of MaynStream is not supported."
+RES_BLANK_TAPE "The tape in %s cannot be read."
+RES_CATALOGING_ITEMS "Cataloging file detail information. Please wait..."
+RES_CATALOG_COMPLETED "Cataloging completed on %s at %s."
+RES_CATALOG_STARTED "Cataloging started on %s at %s."
+RES_COMMAND_SYNTAX_ERROR "Syntax error in command line."
+RES_CONFIRM_TAPE_PASSWORD "Reenter the password to confirm that it is correct: "
+RES_CONTINUE "Press any key to continue..."
+RES_CONTINUE_BACKUP_ABORT "Aborting ... Completing backup of file. "
+RES_CONTINUE_RESTORE_ABORT "Aborting ... Completing restore of file. "
+RES_CONTINUE_QUEST "Do you want to continue? "
+RES_CONTINU_FILE_PROMPT "Do you want to restore this file? "
+RES_CONTINU_FILE_WARNING "File %s will be smaller if it is restored."
+RES_CONVERT_MAC_BSET "WARNING: This backup set contains Macintosh folders and files. To restore this information, filenames and directory names may need to be abbreviated from their original Macintosh format."
+RES_CORRUPT_HEADER "List of corrupted files during Backup of %s, device %s at %s, %s."
+RES_CORRUPT_RESTORE_WARNING "WARNING: The CORRUPT.LST file was found. This file indicates that corrupted file(s) have been backed up."
+RES_DATA_LOST "The tape data starting at offset %d, size %d was unreadable. The file has been padded."
+RES_DELETE_COMPLETED "Transfer deletion completed on %s at %s."
+RES_DELETE_DIRS_FILES "Deleted %ld files in %ld directories."
+RES_DELETE_DIR_FILE "Deleted %ld file in %ld directory."
+RES_DELETE_DIR_FILES "Deleted %ld files in %ld directory."
+RES_DELETE_MAC "%ld Macintosh file was deleted."
+RES_DELETE_MACS "%ld Macintosh files were deleted."
+RES_DELETE_QUEST "Do you want to delete all data from your disk? "
+RES_DELETE_STARTED "Transfer deletion started on %s at %s."
+RES_DEVICE_DEAD "Connection to device %s has been lost."
+RES_DIRECTORY "Directory %s"
+RES_DIRECTORYS_NOT_FOUND "%ld directories were not found."
+RES_DIRECTORY_DIFFERENT "Security information for the %s directory is different."
+RES_DIRECTORY_NOT_FOUND "%ld directory was not found."
+RES_DIRECTORY_NOT_FOUND_ON_DISK "Directory %s not found on the disk."
+RES_DISPLAY_BSD_VCB "\nTape #%d: \042%s\042\nBackup performed on %s at %s\nBackup set #%d: \042%s\042"
+RES_DISPLAY_TAPE "\nTape Name: \042%s\042"
+RES_DISPLAY_VCB "Backup of %s on %s at %s\nBackup set #%d on tape #%d\nBackup description: \042%s\042"
+RES_DISPLAY_VOLUME "\nBackup of \042%s\042\nBackup set #%d on tape #%d\nBackup description: \042%s\042"
+RES_DISPLAY_VOLUME_1 "Backup of \042%s\042\nBackup set #%d on tape #%d\nBackup description: \042%s\042"
+RES_DRIVE_MATCH_ERROR "Target drive must match the source drive. Source: %s, target: %s."
+RES_DRIVE_NOT_READY " "
+RES_EMBEDDED_PW_MISMATCH "The password does not match."
+RES_EMPTY_DRIVE_ERROR "%s does not contain a tape."
+RES_EMPTY_TREE_WARNING "Security information will be restored for all selected directories, even if no files are restored to these directories."
+RES_END_CHANNEL "Improperly linked tape drive channel."
+RES_ENTER_TAPE_PASSWORD "Enter a new password or press <Enter> to skip the password: "
+RES_EOM_TAPE_ABORT "The tape operation was terminated."
+RES_ERASE_CAT_WARNING "The tape was not read before it was erased. You must manually delete this tape from the catalog."
+RES_ERASE_COMPLETED "Tape Erase completed on %s at %s."
+RES_ERASE_QUEST "Do you want to erase the data on this tape? "
+RES_ERASE_STARTED "Tape Erase started on %s at %s.\nErasing. "
+RES_ERROR_CREATING_DIR "Unable to create the directory %s."
+RES_ERROR_CREATING_FILE "Unable to create the file %s."
+RES_ERROR_DURING_ATTACH "Error 0x%x during attachment to device %s."
+RES_ERROR_DURING_OPERATION "Error(s) were found during the operation."
+RES_ERROR_FILE_TO_EXAMINE "Examine %s for more detailed error information."
+RES_ERROR_OPENING_PWDBASE "Error accessing the password database."
+RES_ERROR_POSITIONING_TAPE "Tape positioning error on %s."
+RES_ERROR_READING_PDBASE "Error reading the password database."
+RES_ERROR_RESTORING_AFP_FILE "Error restoring AFP resource data for the file %s."
+RES_ERROR_RESTORING_DIR "Unable to restore the directory %s."
+RES_ERROR_RESTORING_FILE "Error restoring the file %s."
+RES_ERROR_RESTORING_FILE_SEC "Unable to restore \042File Attributes Security\042 for file %s."
+RES_ERROR_RESTORING_TRUSTEE_SEC "Unable to restore \042Extended Attribute\042 information for directory %s."
+RES_ERROR_UPDATING_PDBASE "Error writing to the password database."
+RES_ERROR_EMS_RESTART "Unable to bring the Microsoft Exchange service \'%s\' back on line. Check the event log for more details."
+RES_ERROR_WRITING_SCRIPT "Error writing the script file %s."
+RES_ERROR_COMPRESS_FILE_FAIL "Unable to set the NT compression state for %s."
+RES_EU_ERROR "Encryption Unit error: 0x%x."
+RES_FAIL_KEY "F"
+RES_FAIL_STRING "Fail"
+RES_FATAL_TAPE_DRIVE_ERR "Error on %s."
+RES_FATAL_TAPE_ERR "Error on the tape in %s."
+RES_FATAL_TAPE_FMT_ERR "An inconsistency was encountered on the tape in %s."
+RES_FATAL_TAPE_READ_ERR "Unable to read the tape in %s."
+RES_FATAL_TAPE_TRANS_ERR "An error occurred during translation of data to or from the tape in %s."
+RES_FATAL_TAPE_WRITE_ERR "Unable to write to the tape in %s."
+RES_FILES_DIFFERENT "%ld files were different."
+RES_FILES_NOT_FOUND "%ld files were not found."
+RES_FILE_DIFFERENT "%ld file was different."
+RES_FILE_EA_DIFF "Extended Attribute information for the file %s is different."
+RES_FILE_IS_DIFFERENT "File %s is different."
+RES_FILE_NOT_FOUND "One file was not found on the target disk."
+RES_FILE_NOT_FOUND_ON_DISK "File %s was not found on disk."
+RES_FILE_OPEN_ERROR "Unable to open the file %s - skipped."
+RES_FILE_RENAME_ERROR "File may not be renamed. Source: %s Target: %s."
+RES_FILE_RES_DIFF "Resource fork data for the file %s is different."
+RES_FILE_SECURITY_DIFF "Security information for the file %s is different."
+RES_FILE_SKIPPED "File %s is in use. It has been skipped."
+RES_FILE_SKIPPEDS_STAT "%ld files were skipped."
+RES_FILE_SKIPPED_STAT "%ld file was skipped."
+RES_FOREIGN_TAPE_ERROR "Tape in %s is unrecognizable and cannot be read."
+RES_FOREIGN_TAPE_MSG "The tape in %s is not blank. It was created by another application. Do you wish to continue?"
+RES_FOREIGN_TAPE_MSG2 "Tape in drive %s is not blank. It was created by another application. Do you want to replace the data on this tape?"
+RES_GENERAL_FAILURE "General failure."
+RES_INCONSISTENT_HW_PARMS "Inconsistent tape hardware parameters were defined."
+RES_INSERT_MULTI_TAPES "Insert tapes %d-%d in drives %d-%d."
+RES_INSERT_NEW_TAPE "Insert a tape in %s."
+RES_INSERT_NEXT_TAPE "Insert tape number %d in drive %s."
+RES_INSERT_NEXT_TAPE_REWOUND "Tape has been rewound. Insert tape number %d in drive %s."
+RES_ACTIVE_FILES_RESTORED "Active files that were restored will not become usable until the computer is restarted."
+RES_INSUFFICIENT_DISK_SPACE "Insufficient disk space. Verify that you have full access to the Working Directory and there is disk space available."
+RES_INSUFFICIENT_PRIVILEGE "Insufficient privilege for the file %s - skipped."
+RES_INVALID_PARAMETER "Command line %s contains an invalid parameter."
+RES_INVALID_SOURCE "Invalid source path or file name specified in %s."
+RES_INVALID_TARGET "Invalid target path or file name specified in %s."
+RES_MAKE_ANOTHER_COPY "Do you want to make another copy? "
+RES_MENU_CONTINUE "Press any key to return to the menu."
+RES_MISMATCHED_PASSWORD "The supplied password does not match. Please try again."
+RES_MISSING_HW_RESOURCE "Error opening resource file: %s%s."
+RES_MISSING_NKS "Exclude script NOVELL.NKS was not found."
+RES_MISSING_RSS "Exclude script EXCLUDE.RSS was not found."
+RES_NEWLY_CATALOGED_SET "Backup set #%d: %s was added to the catalog."
+RES_NOERROR_DURING_OPERATION "\nThe operation was successfully completed."
+RES_NO_MORE_CONNECTIONS "There are no more connections available for this device."
+RES_NO_MORE_TAPE_INFO "There is no more data on this tape."
+RES_NO_TAPE_PASSWORD "This tape is not password protected."
+RES_NO_TRANSFER_APPEND "You cannot append a transfer set to a tape containing data that was created using the Backup operation."
+RES_OPERATION_COMPLETED "\nOperation Completed."
+RES_ON_DISK "File information found on disk:"
+RES_ON_TAPE "File information found on tape:"
+RES_OPEN_LOG_ERROR "Error opening the log file %s. "
+RES_OS_FILE_INFO_DIFFERENT "Extended file information for %s is different."
+RES_OUT_OF_MEMORY "Insufficient memory available."
+RES_OUT_OF_SEQUENCE_WARNING "Tape number %d is out of sequence."
+RES_PDBASE_FULL "The password database is full. Increase the value of \042Max_PDBase_Entries\042 in the MAYNARD.INI file."
+RES_PRE_NOON "a"
+RES_PRINTER_ERROR " "
+RES_PROCESS_ABORTED "Process Aborted "
+RES_PROCESSED_BYTES "Processed %s bytes in %d minute(s) and %d second(s)."
+RES_PROCESSED_BYTES_MIN "Processed %s bytes in %d minute(s)."
+RES_PROCESSED_BYTES_SEC "Processed %s bytes in %d second(s)."
+RES_PROCESS_RATE "Rate: %ld bytes/second."
+RES_PROMPT_VERIFY_BACKUP "Do you want to verify the Backup operation? "
+RES_PROMPT_VERIFY_RESTORE "Do you want to verify the Restore operation? "
+RES_READ_ERROR " "
+RES_RECOVERED_DIR "The recovered data was associated with a directory."
+RES_RECOVERED_FILE "The recovered data was associated with a file."
+RES_REMOTE_DENIED_READ "You do not have privileges to restore to the volume %s."
+RES_REPLACE_OLD_TAPE "Replace the tape in %s."
+RES_REPLACE_TAPE "Do you want to replace the data on this tape?"
+RES_REPLACE_WARNING "All of the data on the tape in drive %s will be replaced.\012\012Tape:\011%s\012\011Tape number %d\012Set number %d:\011%s\012\012Do you want to replace this information?"
+RES_RESTORED_CORRUPT "One corrupted file was restored. This file was corrupted before it was backed up."
+RES_RESTORED_CORRUPTS "%ld corrupted files were restored. These files were corrupted before they were backed up."
+RES_RESTORED_CORRUPT_WARNING "Corrupted file %s was restored."
+RES_RESTORED_DIRS_FILES "Restored %ld files in %ld directories."
+RES_RESTORED_DIR_FILE "Restored %ld file in %ld directory."
+RES_RESTORED_DIR_FILES "Restored %ld files in %ld directory."
+RES_RESTORED_DIRS_FILE "Restored %ld file in %ld directories."
+RES_RESTORED_IN_USE "%ld in-use file was restored."
+RES_RESTORED_IN_USES "%ld in-use files were restored."
+RES_RESTORED_IN_USE_WARNING "In-use file %s was restored."
+RES_RESTORED_MAC "%ld Macintosh file was restored."
+RES_RESTORED_MACS "%ld Macintosh files were restored."
+RES_RESTORE_BINDERY "Do you want to restore the bindery files if they are present in this backup set? "
+RES_RESTORE_COMPLETED "Restore completed on %s at %s."
+RES_RESTORE_FILE_PROMPT "The file \042%s\042 on disk is more recent than the version on tape."
+RES_RESTORE_NO_SELECTIONS "No files were selected for Restore."
+RES_RESTORE_QUEST "WARNING: You are about to restore data to %s."
+RES_RESTORE_RECOVER "A tape read error occurred. Writing recovered data to %s."
+RES_RESTORE_SECURITY "Do you want to restore directory security information for each directory? "
+RES_RESTORE_STARTED "Restore started on %s at %s."
+RES_RETRY_KEY "R"
+RES_RETRY_STRING "Retry"
+RES_REWINDING "Rewinding the tape. Please wait... "
+RES_SCRIPT_NESTING_ERROR "Too many nested script files."
+RES_SCRIPT_OPEN_ERROR "Cannot open the script file %s."
+RES_SCRIPT_SYNTAX_ERROR "Syntax error on line %d of the script %s."
+RES_SEARCHING "Searching for the backup set. Please wait... "
+RES_SEARCHING_NEXT_FILE "\rSearching for the next file. Please wait... "
+RES_SEARCH_QUEST "Do you want to search for another backup set on this tape? "
+RES_SECTOR_NOT_FOUND "Sector not found."
+RES_SECURITY_DIFFERENCE "%ld security difference was found."
+RES_SECURITY_DIFFERENCES "%ld security differences were found."
+RES_SEC_ERASE_COMPLETED "Tape security erase completed on %s at %s."
+RES_SEC_ERASE_STARTED "Tape security erase started on %s at %s.\nErasing..."
+RES_SEEK_ERROR "Seek error"
+RES_SERVER_ADDR_NOT_FOUND "Unable to obtain the address of the server %s on the network."
+RES_SKIPPED_DEVICE "{Attachment to the device failed during backup of %s, device %s at %s, %s.}"
+RES_SKIPPED_SCRIPT_HEADER "{List of skipped files during backup of %s, device %s at %s, %s.}"
+RES_SKIPPING_REMOTE "The selections for %s will be omitted from the operation."
+RES_SKIP_CONTINUE "Skip this file?"
+RES_TAPE_CREATED "Tape created on "
+RES_TAPE_DRIVE_NAME "Drive %d"
+RES_TAPE_NOT_INSERTED "Tape in drive %s is not properly inserted."
+RES_TAPE_PASSWORD_MATCH "The password is confirmed."
+RES_TAPE_PASSWORD_MISMATCH "The password does not match. Please try again."
+RES_TAPE_REQUEST "Insert the following tape in %s:\012\012%s\012Tape #%d."
+RES_TENSION_COMPLETED "Tape retension completed on %s at %s."
+RES_TENSION_STARTED "Tape retension started on %s at %s.\nRetensioning... "
+RES_UNEXPECTED_EOS "Unexpected end of backup set encountered on %s."
+RES_UNKNOWN_DEVICE "Unknown Device"
+RES_UNKNOWN_HW_ERR "Unknown device driver initialization error."
+RES_UNKNOWN_LOG_MSG "Unknown log message: 0x%x."
+RES_UNKNOWN_LOOPS_ERR "Unknown loops error: %d."
+RES_UNKNOWN_LOOPS_PROMPT "Unknown loops prompt type: 0x%x."
+RES_UNKNOWN_MSG_HNDLR_MSG "Unknown MSG handler message: %d."
+RES_UNKNOWN_PDBASE_ERROR "Unknown password database error: 0x%x."
+RES_UNKNOWN_TF_MSG "Unknown tape format message: %d."
+RES_UNRECOVERABLE_DISK_ERROR "Unrecoverable Disk Error"
+RES_USER_TAPE_ABORT "The tape operation was terminated by the user."
+RES_VERIFIED_DIRS_FILES "Verified %ld files in %ld directories."
+RES_VERIFIED_DIR_FILE "Verified %ld file in %ld directory."
+RES_VERIFIED_DIR_FILES "Verified %ld files in %ld directory."
+RES_VERIFIED_MAC "%ld Macintosh file was processed."
+RES_VERIFIED_MACS "%ld Macintosh files were processed."
+RES_VERIFY_COMPLETED "Verify completed on %s at %s."
+RES_VERIFY_DATA_DIFFERENCE "Verify failed at offset %ld."
+RES_VERIFY_DATA_VERIFIED "Contents verified."
+RES_VERIFY_NO_SELECTIONS "No files were selected for Verify."
+RES_VERIFY_OPEN_ERROR "Disk file was not found or was not accessible."
+RES_VERIFY_PASSWORD_MISMATCH "The password does not match. Please try again. "
+RES_VERIFY_QUEST "Do you want to verify this data with the data on drive %s? "
+RES_VERIFY_SCRIPT_HEADER "{List of files not verified from %s, device %s on %s at %s.}"
+RES_VERIFY_STARTED "Verify started on %s at %s."
+RES_VERIFY_TAPE_PASSWORD "Enter the old password: "
+RES_WAITING "Waiting for the tape drive. Please wait... "
+RES_WAITING_FOR_OPEN "File %s is in use and is waiting."
+RES_WAIT_AND_REPLACE_TAPE "To make an additional copy, wait for the tape to finish rewinding and insert another tape."
+RES_WRITE_ERROR "Write prot "
+RES_WRITE_PROT "Tape in drive %s is write-protected."
+RES_WRITE_PROTECTED "Write Protected "
+RES_TARGET_TRANSFER_TITLE "Transfer"
+RES_ERASE_FOREIGN_TAPE "The tape in the drive is unrecognizable."
+RES_ERASE_BLANK_TAPE "The tape in the drive is blank."
+RES_ERASE_NO_TAPE "There is no tape in the drive."
+RES_ERASE_TAPE_INFO1 "The tape in the drive is \042%s\042 and was created by %s on %s at %s."
+RES_ERASE_DRIVE_BUSY "The tape drive is busy. Please wait..."
+RES_NEED_NEXT_TAPE "The end of the tape was reached. When the tape finishes rewinding, insert the next tape for this backup."
+RES_NEED_NEXT_TAPE_REWOUND "The end of the tape was reached and the tape has been rewound. Insert the next tape for this backup."
+RES_TAPE_FULL "The tape is full. When the tape finishes rewinding, insert the next tape for this backup."
+RES_TAPE_FULL_REWOUND "The tape is full. The tape has been rewound. Insert the next tape for this backup."
+RES_RESTORE_DESC_1 "%s backup of \042%s\042 performed %s at %s by %s."
+RES_TITLE_NEW_LINE "\n"
+RES_NEXT_SET "Search for the next backup set on tape: \042%s\042?"
+RES_NO_NEXT_SET "Invalid tape for the Next Set on Tape operation."
+RES_FOUND_BSET "A backup set was found and has been added to the catalog. Do you want to continue searching?"
+RES_ERASE_POLL_DRIVE_DISABLED "Poll drive is disabled."
+RES_POLL_DRIVE_BAD_TAPE "This tape cannot be cataloged."
+RES_POLL_DRIVE_GOOFY_TAPE "Tapes in this family require sequential access. Please insert the first tape in this family."
+RES_RETENSION_MESSAGE "Retensioning the tape may take several minutes."
+RES_KEEP_CURRENT_SETTINGS "Do you want to keep the current settings for this operation?"
+RES_ERASE_PWDB "Do you want to erase the password database?"
+RES_PWDB_DISABLED "You have entered three invalid passwords. The password database has been disabled."
+RES_PWDB_BAD_CONFIRM "The password failed to confirm. Please try again."
+RES_INIT_FILE_SYSTEM "Initializing the file system."
+RES_INIT_HARDWARE "Initializing the hardware."
+RES_INIT_APPLICATION "Initializing the application."
+RES_APPLICATION_INIT "Application initialized."
+RES_INIT_VLM "Initializing the VLM."
+RES_OPENING_LOG_NAME "\n Opening log: %s, mode: %c\n"
+RES_ERROR_ATTACHING "Unable to attach to %s."
+RES_FILE_DETAIL "%s bytes %s %s\n"
+RES_CLOSING_LOG_NAME "\n Closing log: %s \n"
+RES_ALREADY_FULLY_CATALOGED "Backup set #%d: %s\nPreviously cataloged with file detail information."
+RES_IMAGE_BACKUP "Backup set #%d: %s\nImage Backup."
+RES_ERASE_BAD_TAPE "The tape in the drive is unrecognizable. Use another tape."
+RES_DISPLAY_VERIFY_INFO "\nVerify of \042%s\042\nBackup set #%d on tape #%d\nBackup description: \042%s\042"
+RES_VERIFIED_DIRS_FILE "Verified %ld file in %ld directories."
+RES_FATAL_TAPE_FMT_NO_APPEND "An inconsistency was encountered on the tape in %s. Do not append to this tape."
+RES_COMM_FAILURE "Network disk drive has stopped responding. Backup set aborted."
+RES_EMS_COMM_FAILURE "The Microsoft Exchange service on \\\\%s has\nreported an error. Check the event log for more information."
+RES_EMS_BKU_ACCESS_FAILURE "Your account is not a member of the Backup Operators group\non either this system or \\\\%s. \nYou cannot back up this Microsoft Exchange server."
+RES_EMS_RST_ACCESS_FAILURE "The Microsoft Exchange services could not be stopped. Your account must be\na member of the Administrators group on this system and \non\\\\%s.You cannot restore to this Microsoft Exchange server."
+
+RES_SAME_TAPE_FAMILY "This tape is of the same tape family. Insert a different tape in the drive."
+
+#ifdef OS_WIN32
+RES_FORMAT_TAPE_WARNING "You have chosen to format this tape. All of the information on the tape will be destroyed."
+RES_FORMAT_DIALOG_TITLE "Format Tape"
+RES_FORMAT_COMPLETED "Format completed on %s at %s."
+RES_FORMAT_STARTED "Format started on %s at %s.\nFormatting..."
+#endif
+
+RES_USESYPLFLAG "Sytos ECC translation error. Please check the manual for possible solutions."
+
+//
+// ABORT ERROR STRING
+//
+
+RES_CURRENT_FILE "Current File:"
+RES_BACKUP_ABORT_EOF "Current file: %s\012\012Click Continue to finish writing this file to tape, or click Abort to stop the backup without finishing the current file."
+RES_RESTORE_ABORT_EOF "Current File: %s\012\012Choose Continue to finish writing this file to disk, or click Abort to stop restoring without finishing the current file."
+
+
+// DEBUG ERROR STRINGS
+
+RES_CONFIG_REMOTE "CDS_GetRemoteDriveBackup %d"
+RES_CONFIG_NRL_DOS_VECTOR "CDS_GetNRLDosVector returned %02X."
+RES_SMB_INITIALIZE "SMB_Initialize returned %d (%04X)"
+RES_REMOTE_BUFFERS " InitializeRemote : Buffs %d Unused %d"
+RES_NO_NRL_FUNCTION_TABLE "rinitfs: Could not locate NRL function table."
+RES_REWIND_DRIVE_HDL "RewindDrive( ): hdl = %d "
+RES_DRV_RET " Drv Error = %d"
+RES_RET_VAL_EQUALS " ret_val = %d"
+RES_ERASE_EXABYTE_SECURITY "EraseDrive -- Exabyte: %d Security: %d"
+RES_CALLING_ERASE "Calling TpErase() ..."
+RES_CALLING_WRITE_END_SET "Calling TpWriteEndSet() ..."
+RES_READ_NEXT_SET "ReadNextSet( ):"
+RES_READ_END_SET " TpReadEndSet( ): "
+RES_END_OF_SET " EOS Detected"
+RES_END_OF_MEDIA " EOM Detected"
+RES_TP_READ " TpRead( ): "
+RES_DRV_ERROR_BYTES_RCVD "Error = %d Req = %ld Got = %ld"
+RES_READ_NEXT_SET_RETVAL "ReadNextSet( ): ret_val = %d"
+RES_GOTO_BCKUP_SET "GotoBckUpSet( )"
+RES_OPEN_DRIVE_CARD_NO "OpenDrive( ): Card = %d No = %d"
+RES_CLOSE_DRIVE "CloseDrive( ):"
+RES_REWIND " -- Rewind"
+RES_NO_REWIND " -- No Rewind"
+RES_BADDR_IRQ_DMA_NO_DRIVES "Baddr: %x Irq: %d Dma: %d No Drives: %d"
+RES_UPDATE_DRIVE_STATUS "UpdateDriveStatus( ): "
+RES_VAL_CHANGED " Val = %lx Changed"
+RES_VAL_UNCHANGED " Val = %lx Unchanged"
+RES_CATALOG_TIME "Cataloging Elapsed Time : %d minute(s) and %d second(s)"
+RES_UI_TPOS_TAPE_SET "UI_TPOS: %s, tape #%d, set #%d"
+RES_IMAGE_DIFFERENCE "Difference at head %u cyl %u sector %u\nTape Contents: "
+RES_HEX_BYTE "%02X"
+RES_DISK_CONTENTS "Disk Contents: "
+RES_NEW_LINE ""
+RES_TAPE_PARTITION_SPECS "Tape: bytes/sec %u sec/track %u rsect %lu num sect %lu sys_ind %u"
+RES_DISK_PARTITION_SPECS "Disk: bytes/sec %u sec/track %u rsect %lu num sect %lu sys_ind %u"
+RES_REM_ATTACH_TO_DLE "REM_AttachToDLE"
+RES_SMB_CONNECT_APPLICATION "REM_AttachToDLE: SMB_ConnectApplication returned %p"
+RES_FOUND_REMOTE_DEVICE "REM_AttachToDLE: Found device %s"
+RES_REMOTE_BINDING "REM_AttachToDLE: Binding... "
+RES_FAILED "failed! %04X"
+RES_OKAY "OK!"
+RES_SMB_RELEASE "REM_DetachDLE: SMB_ReleaseDevice "
+RES_REM_SMB_DISCONNECT "REM_DetachDLE: SMB_DisconnectApplication "
+RES_HEX_INT "%04X."
+RES_RWS_ATTACH_TO_DLE "RWS_AttachToDLE"
+RES_DLE_GET_CHILD "DLE_GetChild..."
+RES_RWS_SMB_DISCONNECT "RWS_DetachDLE: SMB_DisconnectApplication "
+RES_SOFT_ERRORS_UNDERRUNS "%d soft error(s) encountered, %d underrun(s)"
+RES_REQUESTED_SET "Requested Set: ID = %lx Seq = %d Set = %d"
+RES_RESIDUAL_READ_BUFFER "Residual Read Buffer"
+RES_ATTEMPTING_TO_VCB "Attempting to VCB tape"
+RES_CURRENT_VCB "Current VCB: ID = %lx Seq = %d Set = %d"
+RES_POSITION_AT_SET "PositionAtSet( ): TF Msg = %x"
+RES_UI_MSG " UI Msg = %x"
+RES_TF_CLOSE_SET "TF_CloseSet "
+RES_FATAL_ERROR_DETECTED "Error detected"
+RES_READ_BUFFER_LEFT_OVER " - Read Buffer Left Over"
+RES_TF_OPEN_SET "TF_OpenSet( )"
+RES_HOLD_BUFFER "Hold Buffer from last Close"
+RES_DESTROY_HOLD_BUFFER "Destroying Hold buffer"
+RES_OPEN_REQUESTED_REWIND "Rewind Requested from Open"
+RES_END_OF_TFOPEN_SET "End of TF_OpenSet: Ret_val = %d Buffs = %d HiWater = %d"
+RES_TF_ALLOCATE_BUFFERS "TF_AllocateTapeBuffers( ): SysMem = %ld Reserved = %ld"
+RES_END_ALLOCATE "End Allocate: No = %d Sz = %ld"
+RES_TF_FREE_BUFFERS "TF_FreeTapeBuffers( ): Start = %d "
+RES_END_EQUALS "End = %d"
+RES_TF_GETNEXT_TAPE_REQUEST "TF_GetNextTapeRequest( ): Recalled in Error State"
+RES_TF_GETNEXT_ERROR "TF_GetNextTapeRequest( ) Error = %d "
+RES_ABORT_READ "AbortRead( )"
+RES_INITIATE_WATCH "TF_InitiateWatch( )"
+RES_WATCH_REWIND "Watch Rewind"
+RES_DEVICE_ERROR "Device Error = %d"
+RES_GOTO_LBA "GotoBlock( ): vPBA = %lx vLBA = %lx rLBA = %lx rBLK = %lx"
+RES_DRIVER_TO_LOAD "Determined driver: %s"
+RES_LOADING_DRIVER "Using driver: %s"
+RES_TPINIT_FAILURE "TpInit() returned - %x"
+RES_WATCH_DRIVE_CALLED "TF_WatchDrive( )"
+RES_WATCH_DRIVE_STATUS "Drv_ret Action = %d Error = %d Len Got = %d"
+RES_WATCH_DRIVE_EXIT " Watch Return = %d"
+RES_WATCH_DRIVE_END "TF_EndWatch( )"
+RES_GET_CURRENT_POS_STAT "Current Block is = %x"
+RES_UI_PURGE_CATALOG "UI_PurgeCatalog( ) = 0x%x"
+RES_UNFORMATED_STRING "%s"
+RES_IMAGE_BAD_VERIFY "No longer able to read disk at head %u cylinder %u sector %u."
+RES_IMAGE_BAD_BLOCK "Not verifying bad sector at head %u cyl %u sector %u."
+RES_IMAGE_BAD_READ "Unable to read disk at head %u cyl %u sector %u."
+RES_IMAGE_BAD_WRITE "Unable to write to disk at head %u cyl %u sector %u."
+RES_CLOSE_BINDERY "Closing Bindery"
+RES_AL_RESULT " AL = %x"
+RES_OPEN_BINDERY "Opening Bindery"
+RES_PARM_BLK_DESCR "Card %d Parameter Block:"
+RES_PARM_BLK "%8lx %8lx %8lx %8lx %8lx"
+RES_CRIT_ADDRS "DriverAddr = %lx lw_channels = %lx"
+RES_ATTACH_TO_DLE "Attach to %s"
+RES_DETACH_FROM_DLE "Detach from %s"
+RES_NOVELL_SERVER_INFO "NOVELL(%d) server %s, volume %s, supp = 0x%02x"
+RES_DLE_BASE_PATH "Base = \042%s\042"
+RES_NO_ATTACHED_DRIVES "Card %x number of attached drives %x"
+RES_INIT_ERROR "Card %x init error status = %x"
+
+RES_VLM_ECC_TAPE "Software ECC Tape"
+RES_VLM_FUTURE_TAPE "Newer Version Tape"
+RES_VLM_BLANK_TAPE "Blank Tape"
+RES_VLM_FOREIGN_TAPE "Foreign Tape"
+RES_VLM_BAD_TAPE "Bad Tape"
+RES_VLM_SQL_TAPE "SQL Tape"
+RES_VLM_GOOFY_TAPE "Out of Sequence Tape"
+RES_VLM_NO_TAPE "No tape in the drive."
+RES_VLM_BUSY_DRIVE "The tape drive is busy."
+RES_VLM_UNFORMATED_TAPE "Unrecognizable Tape"
+RES_FILE_WAS_SKIPPED "File %s was skipped."
+RES_FILE_WAS_SKIPPED_USER "File %s was skipped by the user."
+
+RES_NEW_PROCESSED_BYTES "%s"
+RES_BYTES_PROCESSED "Processed %s bytes in "
+RES_BYTES_PROCESSED_HOUR " %d hour, "
+RES_BYTES_PROCESSED_HOURS " %d hours, "
+RES_BYTES_PROCESSED_MINUTE1 " %d minute, and "
+RES_BYTES_PROCESSED_MINUTES1 " %d minutes, and "
+RES_BYTES_PROCESSED_MINUTE2 " %d minute and "
+RES_BYTES_PROCESSED_MINUTES2 " %d minutes and "
+RES_BYTES_PROCESSED_SECOND " %d second."
+RES_BYTES_PROCESSED_SECONDS " %d seconds."
+
+RES_ABORT_OPERATION "Abort Operation"
+RES_DRIVE_ERROR_DETECTED "Tape drive error was detected."
+
+/* MessageBox titles */
+
+IDS_MSGTITLE_VERIFY "Verify"
+IDS_MSGTITLE_INSERT "Insert Tape"
+IDS_MSGTITLE_REPLACE "Replace Information"
+IDS_MSGTITLE_APPEND "Append Information"
+IDS_MSGTITLE_INUSE "File In-Use"
+IDS_MSGTITLE_CONTINUE "Continue"
+IDS_MSGTITLE_COPY "Copy Tape"
+IDS_MSGTITLE_ERASE "Erase"
+IDS_MSGTITLE_CORRUPT "Corrupted File"
+IDS_MSGTITLE_RESTORE "Restore"
+IDS_MSGTITLE_MACNAMES "Macintosh Names"
+IDS_MSGTITLE_BINDFILES "Bindery Files"
+IDS_MSGTITLE_SECURITY "Security Information"
+IDS_MSGTITLE_ERROR APPERROR
+IDS_MSGTITLE_NEXT "Next Set on Tape"
+IDS_MSGTITLE_RETENSION "Retension"
+IDS_MSGTITLE_KEEP_SETTINGS "Keep Current Settings"
+IDS_MSGTITLE_WARNING "Warning"
+IDS_MSGTITLE_TAPEPSWD "Tape Password"
+IDS_MSGTITLE_XFERMETHOD "Method Is Invalid"
+IDS_MSGTITLE_ABORT "Abort"
+IDS_MSGTITLE_BADEXCHNG "Backup"
+
+
+#include "hwctext.rc"
+
+// Microsoft OEM version command line batch processing strings.
+// ------------------------------------------------------------------
+// The backup string must be the first item on the command line and
+// must match exactly (case insensitive).
+// Each of these IDS_OEM* strings may be no longer than
+// IDS_OEM_MAX_LEN - 1 (eg. 31) characters in length (defined in OMSTRING.H)
+// See OMBATCH.C and MUI_ProcessCommandLine in MUI.C for more information.
+
+IDS_OEMBATCH_BACKUP "Backup"
+IDS_OEMBATCH_EJECT "Eject"
+
+ // Can use DSA or Monolithic backup of Microsoft Mail Exchange servers.
+
+IDS_OEMOPT_DSA "DS"
+IDS_OEMOPT_MONOLITHIC "IS"
+
+ // Each option on the command line must be prefixed by one of the chars
+ // specified in the prefixes string.
+
+IDS_OEMOPT_PREFIXES "/-"
+
+ // This string holds the list of tokens (characters) which seperate
+ // one command line item from another - eg. spaces, tabs, commas, etc.
+
+IDS_OEMOPT_TOKENSEPS " \t,"
+
+ // The first letter of each of the following option MUST BE UNIQUE!!
+
+IDS_OEMOPT_APPEND "Append"
+IDS_OEMOPT_VERIFY "Verify"
+IDS_OEMOPT_RESTRICT "Restrict"
+IDS_OEMOPT_DESCRIPTION "Description"
+IDS_OEMOPT_TYPE "Type"
+IDS_OEMOPT_LOGFILENAME "Logfile"
+IDS_OEMOPT_LOGEXCEPTIONS "Exceptions"
+IDS_OEMOPT_BACKUP_REGISTRY "B" // Need text for this?
+
+ // The first letter of each of the following types MUST BE UNIQUE!!
+IDS_OEMTYPE_NORMAL "Normal"
+IDS_OEMTYPE_COPY "Copy"
+IDS_OEMTYPE_INCREMENTAL "Incremental"
+IDS_OEMTYPE_DIFFERENTIAL "Differential"
+IDS_OEMTYPE_DAILY "Daily"
+IDS_OEMTYPE_COMPATIBLE "#Compatible" //special undocumented feature!
+
+#ifdef OS_WIN32
+ //Microsoft OEM Event Logging 'Source' Name - eg. the name which identifies
+ // a message logged to the event logger as having come from us.
+ IDS_OEMEVENT_SOURCE_NAME "NTBackup"
+#endif
+
+//Backup and Restore Log file default names
+IDS_OEMLOG_BACKUP_DEF_NAME "BACKUP.LOG"
+IDS_OEMLOG_RESTORE_DEF_NAME "RESTORE.LOG"
+IDS_OEMLOG_ERROR_REPORTEVENT "Error %ld Logging EventId=%ld Type=%d nStrings=%d"
+IDS_OEMLOG_ERROR_EVENTSTRING "-- Event String %d: '%s'"
+
+// Extra stuff for the About box
+
+IDS_ABOUT_ENHANCED_MODE "386 Enhanced Mode"
+IDS_ABOUT_STANDARD_MODE "Standard Mode"
+IDS_ABOUT_MEMORY "Memory:"
+IDS_ABOUT_MEM_FORMAT "%d,%03d KB Free"
+IDS_ABOUT_RESOURCES "System Resources:"
+IDS_ABOUT_RES_FORMAT "%d%% Free"
+IDS_APPTEXTSTRING "Microsoft Windows NT %s"
+IDS_LICENSEINFOKEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
+IDS_CURRENTVERSION "CurrentVersion"
+IDS_REGUSER "RegisteredOwner"
+IDS_REGORGANIZATION "RegisteredOrganization"
+IDS_VERSIONMSG "Version %s %s"
+IDS_DEBUG "Debug"
+IDS_PROCESSORINFOKEY "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"
+IDS_PROCESSORIDENTIFIER "Identifier"
+IDS_IDENTIFIERIDENTIFIER "HARDWARE\\DESCRIPTION\\System"
+IDS_PRODUCTIDINFOKEY "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
+IDS_PRODUCTIDENTIFIER "ProductId"
+
+
+// Runtime JOB Status Events
+
+
+IDS_RTD_ACCESSDENIED_FILE "You do not have permission to access portions of\n %s.\nPlease see the owner or administrator to get permission."
+IDS_RTD_ACCESSDENIED_DIR "You do not have permission to access portions of\n %s.\nPlease see the owner or administrator to get permission."
+
+IDS_RTD_WRITEERROR_FILE "You do not have permission to access portions of\n %s.\nPlease see the owner or administrator to get permission."
+IDS_RTD_WRITEERROR_DIR "You do not have permission to access portions of\n %s.\nPlease see the owner or administrator to get permission."
+
+IDS_RTD_READERROR_STREAM "Error reading file data."
+IDS_RTD_WRITEERROR_STREAM "Error writing file data."
+IDS_RTD_VERIFYERROR_DATA "Difference encountered in file data."
+
+IDS_RTD_READERROR_SECURITYSTREAM "Unable to read security information."
+IDS_RTD_WRITEERROR_SECURITYSTREAM "Unable to write security information."
+IDS_RTD_VERIFYERROR_SECURITYSTREAM "Difference encountered in security information."
+
+IDS_RTD_READERROR_EA "Error reading Extended Attribute information."
+IDS_RTD_WRITEERROR_EA "Error writing Extended Attribute information."
+IDS_RTD_VERIFYERROR_EA "Difference encountered in Extended Attribute information."
+
+IDS_RTD_READERROR_ALTSTREAM "Error reading alternate file data."
+IDS_RTD_WRITEERROR_ALTSTREAM "Error writing alternate file data."
+IDS_RTD_VERIFYERROR_ALTSTREAM "Difference encountered in alternate file data."
+
+IDS_RTD_READERROR_LINK "Error reading file link information."
+IDS_RTD_CREATEERROR_LINK "Unable to create file link."
+
+END
+
diff --git a/private/utils/ntbackup/src/omtensio.bmp b/private/utils/ntbackup/src/omtensio.bmp
new file mode 100644
index 000000000..85fdc1fd2
--- /dev/null
+++ b/private/utils/ntbackup/src/omtensio.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/omunchec.bmp b/private/utils/ntbackup/src/omunchec.bmp
new file mode 100644
index 000000000..b6dc56e2b
--- /dev/null
+++ b/private/utils/ntbackup/src/omunchec.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/omxchng.dlg b/private/utils/ntbackup/src/omxchng.dlg
new file mode 100644
index 000000000..252c0b9d9
--- /dev/null
+++ b/private/utils/ntbackup/src/omxchng.dlg
@@ -0,0 +1,52 @@
+
+IDD_CONNECT_XCHNG DIALOG DISCARDABLE 0, 0, 217, 93
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Microsoft Exchange"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ ICON IDRI_EXCHANGE,-1,6,6,18,20
+ LTEXT "Type the name of any online Microsoft Exchange server in the organization.",
+ -1,30,7,125,16
+ LTEXT "&Server:",-1,6,32,23,8
+ EDITTEXT IDD_XCNCT_SVR_NAME,6,43,135,12,ES_AUTOHSCROLL
+ PUSHBUTTON "...",IDD_XCNCT_PICKER,141,43,12,12
+ CONTROL "&Connect to Organization",IDD_XCNCT_CONNECT,"Button",
+ BS_AUTORADIOBUTTON,6,63,92,10
+ CONTROL "S&tart Service:",IDD_XCNCT_ONLINE,"Button",
+ BS_AUTORADIOBUTTON,6,76,78,10
+ COMBOBOX IDD_XCNCT_SERVICE,88,75,73,30, CBS_DROPDOWNLIST |
+ CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ DEFPUSHBUTTON "OK",IDD_XCNCT_OK,161,6,50,14
+ PUSHBUTTON "&Help",IDD_XCNCT_HELP,161,40,50,14
+ PUSHBUTTON "Cancel",IDD_XCNCT_CANCEL,161,23,50,14
+END
+
+IDD_XCHG_RECOVER DIALOG DISCARDABLE 38, 64, 241, 59
+STYLE DS_ABSALIGN | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION |
+ WS_SYSMENU
+CAPTION "Recovering..."
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Recovering %s Service",IDD_XCHG_RCVR_TEXT,6,6,164,11,
+ SS_NOPREFIX
+ CONTROL "%d%% Complete",IDD_XCHG_RCVR_PCT,"Static",
+ SS_LEFTNOWORDWRAP | SS_NOPREFIX | WS_GROUP,6,48,115,8
+ DEFPUSHBUTTON "Close",IDD_XCHG_RCVR_CANCEL,185,34,50,14
+ ICON IDRI_EXCHANGE,-1,211,6,18,20
+ CONTROL "",IDD_XCHG_RCVR_STATUS,"Button",BS_OWNERDRAW,91,18,117,
+ 11
+ CONTROL "Phase %d of %d",IDD_XCHG_RCVR_PHASE,"Static",
+ SS_LEFTNOWORDWRAP | SS_NOPREFIX | WS_GROUP,6,20,115,8
+ CONTROL "",IDD_XCHG_RCVR_STATUS_BORDER,"Static",SS_BLACKFRAME,6,
+ 34,169,11
+END
+
+IDR_XCHG_RCVR_IS_PHASE RCDATA
+BEGIN
+ 4
+END
+
+IDR_XCHG_RCVR_DS_PHASE RCDATA
+BEGIN
+ 2
+END
diff --git a/private/utils/ntbackup/src/openbsdu.c b/private/utils/ntbackup/src/openbsdu.c
new file mode 100644
index 000000000..24027157b
--- /dev/null
+++ b/private/utils/ntbackup/src/openbsdu.c
@@ -0,0 +1,109 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: openbsdu.c
+
+ Description: This file contains code to initialize the BSDU and code
+ to close and remove an initialized BSD list.
+
+ $Log: N:/LOGFILES/OPENBSDU.C_V $
+
+ Rev 1.2 12 Jun 1991 16:05:16 STEVEN
+added virtual memory for LBAs
+
+ Rev 1.1 29 May 1991 17:21:08 STEVEN
+Re-Design of BSDU for New Fast File Restore
+
+ Rev 1.0 09 May 1991 13:38:24 HUNTER
+Initial revision.
+
+**/
+#include <stdlib.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "queues.h"
+#include "vm.h"
+
+#include "bsdu.h"
+#include "msassert.h"
+/**/
+/**
+
+ Name: BSD_OpenList()
+
+ Description: This function allocates memory for a BSD handle and
+ modifies the pointer provided to point to this handle. It
+ also initializes The list which will be pointed to by the new
+ handle.
+
+ Modified: 5/17/1991 13:21:29
+
+ Returns: Error codes:
+ OUT_OF_MEMORY
+ SUCCESS
+
+ Notes: The handle returned must be passed to all subsequent
+ BSDU list operation functions calls.
+
+ See also: $/SEE( BSDU_CloseList() )$
+
+ Declaration:
+
+**/
+INT16 BSD_OpenList(
+BSD_HAND *bsdh, /* O - The BSD handle */
+VM_HDL vm_hand ) /* I - virtual memory handle */
+{
+ INT16 ret_val ;
+
+ msassert( bsdh != NULL );
+
+ *bsdh = (BSD_HAND)calloc( 1, sizeof( BSD_LIST ) );
+
+ if( *bsdh != NULL ) {
+
+ (*bsdh)->vm_hand = vm_hand ;
+ ret_val = SUCCESS;
+
+ } else {
+ ret_val = OUT_OF_MEMORY ;
+ }
+
+ return( ret_val ) ;
+}
+/**/
+/**
+
+ Name: BSDU_CloseList()
+
+ Description: This function goes through both the Last Oper list and
+ the current list and removes all BSD elements. It then releases
+ the BSD handle itself.
+
+
+ Modified: 8/7/1989
+
+ Returns: None.
+
+ Notes: All pointers previously returned by the BSDU for this
+ handle will now point to free memory.
+
+
+ See also: $/SEE( BSDU_OpenList() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID BSD_CloseList(
+BSD_HAND bsdh ) /* I - BSD List to close */
+{
+ BSD_ClearCurrOper( bsdh ) ;
+ BSD_ClearLastOper( bsdh ) ;
+
+ free( bsdh ) ;
+
+}
+
diff --git a/private/utils/ntbackup/src/opensys.c b/private/utils/ntbackup/src/opensys.c
new file mode 100644
index 000000000..c0c1bdc32
--- /dev/null
+++ b/private/utils/ntbackup/src/opensys.c
@@ -0,0 +1,273 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: opensys.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains the code to open and close a specified
+ file system. A file system must be opened prior to access.
+
+
+ $Log: J:/LOGFILES/OPENSYS.C_V $
+
+ Rev 1.15 26 Jul 1993 19:22:54 DON
+When we close down the file system, added a call to free the os path or name queue!
+
+ Rev 1.14 11 Nov 1992 09:52:34 GREGG
+Unicodeized literals.
+
+ Rev 1.13 10 Nov 1992 08:17:46 STEVEN
+move os path and os name into common part of dblk
+
+ Rev 1.12 25 Sep 1992 16:22:22 CARLS
+Fixed error in last edit. [Barry]
+
+ Rev 1.11 25 Sep 1992 13:18:26 BARRY
+Removed references to FS_SIZEOF_NAMELESS_STREAM_HEAD.
+
+ Rev 1.10 01 Sep 1992 11:44:20 TIMN
+Fixed typo for BINT16
+
+ Rev 1.9 18 Aug 1992 10:26:48 STEVEN
+fix warnings
+
+ Rev 1.8 23 Jul 1992 12:41:06 STEVEN
+fix warning
+
+ Rev 1.7 09 Jul 1992 13:58:30 STEVEN
+BE_Unicode updates
+
+ Rev 1.6 21 May 1992 13:58:10 STEVEN
+added more long path stuff
+
+ Rev 1.5 16 Mar 1992 10:06:56 LORIB
+Added InitQueue() for path_q.
+
+ Rev 1.4 01 Oct 1991 11:15:48 BARRY
+Include standard headers.
+
+ Rev 1.3 06 Aug 1991 18:30:24 DON
+added NLM File System support
+
+ Rev 1.2 25 Jun 1991 09:34:54 BARRY
+Changes for new config.
+
+ Rev 1.1 03 Jun 1991 13:27:04 BARRY
+Remove product defines from conditional compilation.
+
+ Rev 1.0 09 May 1991 13:38:26 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include <stdlib.h>
+#include <std_err.h>
+
+#include "stdtypes.h"
+#include "msassert.h"
+
+#include "beconfig.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+/* $end$ include list */
+
+/**/
+/**
+
+ Name: FS_OpenFileSys()
+
+ Description: This function is called to get a file system handle.
+ The handle is required for all subsequent calls to the file system.
+ This routine allocates all resources necessary to support the
+ particular file system. The valid file system types are:
+ LOCAL_IMAGE
+ LOCAL_DOS_DRV
+ REMOTE_DOS_DRV
+ NOVELL_DRV
+ NOVELL_AFP_DRV
+ IBM_PC_LAN_DRV
+
+ Modified: 7/14/1989
+
+ Returns: Error codes:
+ UNDEFINED_TYPE
+ OUT_OF_MEMORY
+ SUCCESS
+
+
+ Notes:
+
+ See also: $/SEE( FS_AttachDLE(), FS_CloseFileSys() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 FS_OpenFileSys(
+FSYS_HAND *fsh, /* O - Created file system handle */
+INT16 type, /* I - File system type */
+BE_CFG_PTR cfg ) /* I - configuration structure */
+{
+ if ( type >= MAX_DRV_TYPES ) {
+ return ( FS_UNDEFINED_TYPE ) ;
+ }
+
+ *fsh = (FSYS_HAND)calloc( 1, sizeof( struct FSYS_HAND_STRUCT ) ) ;
+
+ if( *fsh != NULL ) {
+
+ (*fsh)->stream_ptr = NULL;
+ (*fsh)->stream_buf_size = 0;
+
+ (*fsh)->cur_dir = calloc( 1, CUR_DIR_CHUNK ) ;
+
+ if ( (*fsh)->cur_dir == NULL ) {
+ free( (*fsh)->stream_ptr ) ;
+ free( *fsh ) ;
+ } else {
+
+ #if ( defined(FS_AFP) && defined(FS_NONAFP) )
+ if ( ( type == NOVELL_AFP_DRV ) && !BEC_GetAFPSupport( cfg ) ) {
+ type = NOVELL_DRV ;
+ }
+ #endif
+
+ #if ( defined(FS_NLMAFP) && defined(FS_NLMNOV) )
+ if ( ( type == NLM_AFP_VOLUME ) && !BEC_GetAFPSupport( cfg ) ) {
+ type = NLM_VOLUME ;
+ }
+ #endif
+
+ (*fsh)->f_type = type ;
+ (*fsh)->tab_ptr = &(func_tab[type]) ;
+ (*fsh)->leng_dir = CUR_DIR_CHUNK ;
+ (*fsh)->cfg = cfg;
+
+ InitQueue( &((*fsh)->min_ddb_stk) ) ;
+
+ InitQueue( &((*fsh)->in_use_name_q) ) ;
+
+ InitQueue( &((*fsh)->avail_name_q) ) ;
+
+ return ( SUCCESS ) ;
+ }
+ }
+ return ( OUT_OF_MEMORY ) ;
+}
+
+/**/
+/**
+
+ Name: FS_ReOpenFileSys()
+
+ Description: This function is called to modify a file system handle.
+ The previously opened file system is closed and the memory for the old
+ handle is reused for the new file system. This routine allocates all
+ resources necessary to support the particular file system. The valid
+ file system types are:
+ LOCAL_IMAGE
+ LOCAL_DOS_DRV
+ REMOTE_DOS_DRV
+ NOVELL_DRV
+ NOVELL_AFP_DRV
+ IBM_PC_LAN_DRV
+
+ Modified: 7/14/1989
+
+ Returns: Error codes:
+ UNDEFINED_TYPE
+ OUT_OF_MEMORY
+ SUCCESS
+
+
+ Notes:
+
+ See also: $/SEE( FS_AttachDLE(), FS_CloseFileSys() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 FS_ReOpenFileSys(
+FSYS_HAND fsh, /* O - Modified file system handle */
+INT16 type, /* I - File system type */
+BE_CFG_PTR cfg ) /* I - configuration structure */
+{
+ if ( type < MAX_DRV_TYPES ) {
+ return ( FS_UNDEFINED_TYPE ) ;
+ }
+
+ msassert( fsh != NULL ) ;
+
+ if ( fsh->attached_dle != NULL ) {
+ FS_DetachDLE( fsh ) ;
+ }
+
+ fsh->f_type = type ;
+ fsh->tab_ptr = &(func_tab[type]) ;
+ fsh->cur_dir[0] = TEXT('\0') ;
+ fsh->cfg = cfg;
+
+ InitQueue( &(fsh->min_ddb_stk) ) ;
+
+ InitQueue( &(fsh->in_use_name_q) ) ;
+
+ InitQueue( &(fsh->avail_name_q) ) ;
+
+ return ( SUCCESS ) ;
+}
+
+
+/**/
+/**
+
+ Name: FS_CloseFileSys()
+
+ Description: This releases any memory allocated by the FS_OpenFileSys()
+ function. It will also release any memory leftover from FS_PushDir()
+
+
+ Modified: 7/14/1989
+
+ Returns: Error codes:
+ FS_NOT_OPEN
+ SUCCESS
+
+ Notes:
+
+ See also: $/SEE( FS_OpenFileSys( ), FS_PushDir( ) )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 FS_CloseFileSys( fsh )
+FSYS_HAND fsh ;
+{
+ if ( fsh != NULL ) {
+
+ /* Release any unreleased resources in the name queue */
+ FS_FreeOSPathOrNameQueueInHand( fsh );
+
+ if ( fsh->attached_dle != NULL ) {
+ FS_DetachDLE( fsh ) ;
+ }
+
+ free( fsh->cur_dir ) ;
+ free( fsh->stream_ptr ) ;
+ free( fsh ) ;
+
+ return ( SUCCESS ) ;
+ } else {
+
+ return ( FS_NOT_OPEN );
+
+ }
+}
+
+UINT16 FS_GetStringTypes( FSYS_HAND fsh )
+{
+ return BEC_GetStringTypes( fsh->cfg ) ;
+}
diff --git a/private/utils/ntbackup/src/otc40msc.c b/private/utils/ntbackup/src/otc40msc.c
new file mode 100644
index 000000000..ae0afe1d6
--- /dev/null
+++ b/private/utils/ntbackup/src/otc40msc.c
@@ -0,0 +1,1192 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-92
+
+
+ Name: otc40msc.c
+
+ Description: Contains misc code for processing On Tape Catalogs.
+
+
+ $Log: T:/LOGFILES/OTC40MSC.C_V $
+
+ Rev 1.28.2.0 11 Jan 1995 21:04:54 GREGG
+Calculate OTC addrs from fmk instead of always asking (fixes Wangtek bug).
+
+ Rev 1.28 17 Dec 1993 16:40:18 GREGG
+Extended error reporting.
+
+ Rev 1.27 15 Oct 1993 18:12:04 GREGG
+Call GetPosition to get addr of the 2nd ESET in case we need it for an EOTM.
+
+ Rev 1.26 14 Oct 1993 18:17:16 GREGG
+Call home grown mktemp.
+
+ Rev 1.25 15 Sep 1993 21:37:28 GREGG
+Use mktemp to generate the temp OTC file names to gaurentee unique names.
+
+ Rev 1.24 09 Jun 1993 03:48:46 GREGG
+Consider pad in calculating how far to back up in FDD if EOM encountered.
+
+ Rev 1.23 07 Jun 1993 23:59:58 GREGG
+Fix for bug in the way we were handling EOM and continuation OTC entries.
+Files modified for fix: mtf10wt.c, otc40wt.c, otc40msc.c f40proto.h mayn40.h
+
+ Rev 1.22 17 May 1993 19:30:34 GREGG
+In GetPrevSM, we now do a TpSpace to get to the ESET or EOTM instead of
+calculating an address and doing a seek. (safer and faster)
+
+ Rev 1.21 27 Apr 1993 03:09:40 GREGG
+Allign pad stream after Set Map on 4 byte boundary, and pad to max of
+logical or physical block boundary.
+
+ Rev 1.20 22 Apr 1993 03:31:34 GREGG
+Third in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Removed all references to the DBLK element 'string_storage_offset',
+ which no longer exists.
+ - Check for incompatable versions of the Tape Format and OTC and deals
+ with them the best it can, or reports tape as foreign if they're too
+ far out. Includes ignoring the OTC and not allowing append if the
+ OTC on tape is a future rev, different type, or on an alternate
+ partition.
+ - Updated OTC "location" attribute bits, and changed definition of
+ CFIL to store stream number instead of stream ID.
+
+Matches: TFL_ERR.H 1.9, MTF10WDB.C 1.7, TRANSLAT.C 1.39, FMTINF.H 1.11,
+ OTC40RD.C 1.24, MAYN40RD.C 1.56, MTF10WT.C 1.7, OTC40MSC.C 1.20
+ DETFMT.C 1.13, MTF.H 1.4
+
+ Rev 1.19 19 Apr 1993 18:00:28 GREGG
+Second in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ Changes to write version 2 of OTC, and to read both versions.
+
+Matches: mayn40rd.c 1.55, otc40msc.c 1.19, otc40rd.c 1.23, otc40wt.c 1.23,
+ makevcb.c 1.15, fsys.h 1.32, fsys_str.h 1.46, tpos.h 1.16,
+ mayn40.h 1.32, mtf.h 1.3.
+
+NOTE: There are additional changes to the catalogs needed to save the OTC
+ version and put it in the tpos structure before loading the OTC
+ File/Directory Detail. These changes are NOT listed above!
+
+ Rev 1.18 17 Mar 1993 16:20:30 GREGG
+Changed GetPrevSM to report BAD_SET_MAP if data detected past last filemark.
+
+ Rev 1.17 18 Feb 1993 09:02:16 DON
+Cleaned up compiler warnings
+
+ Rev 1.16 05 Feb 1993 12:26:22 GREGG
+Make sure we get a GEN_ERR_NO_DATA read at EOD or some drivers won't write.
+
+ Rev 1.15 30 Jan 1993 11:44:06 DON
+Removed compiler warnings
+
+ Rev 1.14 26 Jan 1993 01:30:26 GREGG
+Added Fast Append functionality.
+
+ Rev 1.13 21 Jan 1993 15:46:26 GREGG
+Added parameter to calls to TpSeek and TpGetPosition.
+
+ Rev 1.12 14 Dec 1992 12:28:24 DAVEV
+Enabled for Unicode compile
+
+ Rev 1.11 24 Nov 1992 18:16:04 GREGG
+Updates to match MTF document.
+
+ Rev 1.10 17 Nov 1992 14:14:32 GREGG
+Fixed catalog write code to deal with new stream stuff.
+
+ Rev 1.9 11 Nov 1992 22:33:34 GREGG
+Unicodeized literals.
+
+ Rev 1.8 09 Nov 1992 11:00:40 GREGG
+Merged in changes for new method of accessing OTC.
+
+ Rev 1.7 22 Oct 1992 10:43:20 HUNTER
+Changes for Stream Headers
+
+ Rev 1.6 28 Sep 1992 11:02:42 GREGG
+Set using_sm and have_sm to false when reporting TF_NEED_NEW_TAPE.
+
+ Rev 1.5 22 Sep 1992 18:46:02 GREGG
+Removed asserts on error from unlink (error returned if file doesn't exist).
+
+ Rev 1.4 22 Sep 1992 08:57:12 GREGG
+Initial changes to handle physical block sizes greater than 1K.
+
+ Rev 1.3 31 Aug 1992 19:10:28 GREGG
+Added fflush calls to insure all data gets to disk and fclose doesn't fail.
+
+ Rev 1.2 17 Aug 1992 08:40:10 GREGG
+Changes to deal with block sizeing scheme.
+
+ Rev 1.1 12 Aug 1992 14:55:00 GREGG
+Fixed bugs in OTC_WriteStream and OTC_MoveToVCB.
+
+ Rev 1.0 30 Jul 1992 16:24:38 GREGG
+Initial revision.
+
+**/
+
+#include <stdio.h>
+#include <io.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <fcntl.h>
+
+#include "stdtypes.h"
+#include "channel.h"
+#include "mayn40.h"
+#include "f40proto.h"
+#include "lw_data.h"
+#include "tfl_err.h"
+#include "lwprotos.h"
+#include "minmax.h"
+#include "transutl.h"
+#include "fsstream.h"
+#include "msmktemp.h"
+
+/* Device Driver InterFace Headers */
+#include "retbuf.h"
+#include "drvinf.h"
+#include "generr.h"
+#include "genfuncs.h"
+#include "dil.h"
+#include "dddefs.h"
+
+/* Local Function Prototypes */
+static INT16 _near OTC_SMtoFile( CHANNEL_PTR channel, BUF_PTR tmpBUF ) ;
+static INT16 _near OTC_ReadStream( CHANNEL_PTR channel, BUF_PTR tmpBUF,
+ FILE * fptr ) ;
+static INT16 _near OTC_WriteFDD( CHANNEL_PTR channel, BUF_PTR tmpBUF,
+ unsigned int rdwr_size ) ;
+static INT16 _near OTC_WriteSM( CHANNEL_PTR channel, BUF_PTR tmpBUF,
+ unsigned int rdwr_size ) ;
+static INT16 _near OTC_WriteStream( CHANNEL_PTR channel, BUF_PTR tmpBUF,
+ unsigned int rdwr_size, FILE * fptr,
+ UINT32 type, UINT32 length,
+ BOOLEAN pad_to_boundary,
+ BOOLEAN_PTR completed,
+ BOOLEAN continuation ) ;
+static INT16 _near OTC_WriteSMPadStream( CHANNEL_PTR channel,
+ BUF_PTR tmpBUF ) ;
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_OpenSM
+
+ Description: Opens the temporary SM header file.
+
+ Returns: INT16 - TFLE_xxx
+
+ Notes:
+
+**/
+INT16 OTC_OpenSM(
+ F40_ENV_PTR cur_env,
+ BOOLEAN appending,
+ BOOLEAN_PTR sm_exists )
+{
+ INT16 ret_val = TFLE_NO_ERR ;
+
+ /* Gen file name */
+ if( cur_env->sm_fname[0] == TEXT('\0') ) {
+ strcpy( lw_cat_file_path_end, TEXT("SMXXXXXX") ) ;
+ if( msmktemp( lw_cat_file_path ) == NULL ) {
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ strcat( lw_cat_file_path, TEXT(".SM") ) ;
+ strcpy( cur_env->sm_fname, lw_cat_file_path_end ) ;
+ } else {
+ strcpy( lw_cat_file_path_end, cur_env->sm_fname ) ;
+ }
+
+ if( !appending ) {
+ if( ( cur_env->otc_sm_fptr = UNI_fopen( lw_cat_file_path, 0 ) ) == NULL ) {
+ ret_val = TFLE_OTC_FAILURE ;
+ }
+
+ } else {
+ if( access( lw_cat_file_path, 0 ) == -1 ) {
+ if( ( cur_env->otc_sm_fptr = UNI_fopen( lw_cat_file_path, 0 ) ) == NULL ) {
+ ret_val = TFLE_OTC_FAILURE ;
+ }
+ *sm_exists = FALSE ;
+ } else {
+ if( ( cur_env->otc_sm_fptr = UNI_fopen( lw_cat_file_path, _O_APPEND ) ) == NULL ) {
+ ret_val = TFLE_OTC_FAILURE ;
+ }
+
+// fseek( cur_env->otc_sm_fptr, 0L, SEEK_SET ) ;
+ *sm_exists = TRUE ;
+ }
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_OpenFDD
+
+ Description: Opens the temporary FDD file.
+
+ Returns: INT16 - TFLE_xxx
+
+ Notes:
+
+**/
+INT16 OTC_OpenFDD(
+ F40_ENV_PTR cur_env )
+{
+ INT16 ret_val = TFLE_NO_ERR ;
+
+ /* Gen file name */
+ if( cur_env->fdd_fname[0] == TEXT('\0') ) {
+ strcpy( lw_cat_file_path_end, TEXT("FDXXXXXX") ) ;
+ if( msmktemp( lw_cat_file_path ) == NULL ) {
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ strcat( lw_cat_file_path, TEXT(".FDD") ) ;
+ strcpy( cur_env->fdd_fname, lw_cat_file_path_end ) ;
+ } else {
+ strcpy( lw_cat_file_path_end, cur_env->fdd_fname ) ;
+ }
+
+ if( ( cur_env->otc_fdd_fptr = UNI_fopen( lw_cat_file_path, 0 ) ) == NULL ) {
+ ret_val = TFLE_OTC_FAILURE ;
+ }
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_Close
+
+ Description: Closes the OTC temporary files indicated, and deletes
+ them if indicated.
+
+ Returns: Nothing
+
+ Notes: Defined values for the first parameter are:
+
+ OTC_CLOSE_SM
+ OTC_CLOSE_FDD
+ OTC_CLOSE_ALL
+
+**/
+VOID OTC_Close(
+ F40_ENV_PTR cur_env,
+ UINT16 otc_files,
+ BOOLEAN delete_after )
+{
+ int ret ;
+
+ if( otc_files != OTC_CLOSE_FDD ) {
+ /* close the SM file if open and delete it if indicated */
+ if( cur_env->otc_sm_fptr != NULL ) {
+ fflush( cur_env->otc_sm_fptr ) ;
+ ret = fclose( cur_env->otc_sm_fptr ) ;
+ msassert( ret == 0 ) ;
+ cur_env->otc_sm_fptr = NULL ;
+ }
+ if( delete_after ) {
+ if( cur_env->sm_fname[0] != TEXT('\0') ) {
+ strcpy( lw_cat_file_path_end, cur_env->sm_fname ) ;
+ remove( lw_cat_file_path ) ;
+ cur_env->sm_fname[0] = TEXT('\0') ;
+ }
+ }
+ }
+
+ if( otc_files != OTC_CLOSE_SM ) {
+ /* close the FDD file if open and delete it if indicated */
+ if( cur_env->otc_fdd_fptr != NULL ) {
+ fflush( cur_env->otc_fdd_fptr ) ;
+ ret = fclose( cur_env->otc_fdd_fptr ) ;
+ msassert( ret == 0 ) ;
+ cur_env->otc_fdd_fptr = NULL ;
+ }
+ if( delete_after ) {
+ if( cur_env->fdd_fname[0] != TEXT('\0') ) {
+ strcpy( lw_cat_file_path_end, cur_env->fdd_fname ) ;
+ remove( lw_cat_file_path ) ;
+ cur_env->fdd_fname[0] = TEXT('\0') ;
+ }
+ }
+
+ /* If the EOM FDD processing file is around, close and delete it */
+ if( cur_env->otc_eom_fptr != NULL ) {
+ fflush( cur_env->otc_eom_fptr ) ;
+ ret = fclose( cur_env->otc_eom_fptr ) ;
+ msassert( ret == 0 ) ;
+ cur_env->otc_eom_fptr = NULL ;
+ strcpy( lw_cat_file_path_end, cur_env->eom_fname ) ;
+ remove( lw_cat_file_path ) ;
+ }
+ }
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_GetPrevSM
+
+ Description: This function retrieves the Set Map from the last set
+ fully written to the current tape. It is called before
+ an append operation so that the Set Map may be updated
+ and written after the appended set. It is also called
+ by F40_LoadSM to set the Set Map up for subsequent calls
+ to F40_GetNextSMEntry. It also gets the last set number
+ from the ESET. We need this if we are going to do an
+ append operation.
+
+ If the boolean 'expect_sm' is FALSE, it is assumed that
+ there is no Set Map and all we do is get the previous
+ set number.
+
+ If the boolean 'get_best' is TRUE, it means we are
+ looking for the end of the tape FAMILY (to get the best
+ Set Map possible or to start an append operation), so
+ if we see an EOTM we return TF_NEED_NEW_TAPE indicating
+ the family continues onto another tape.
+
+ Returns: INT16 - TFLE_xxx, TF_NO_SM_ON_TAPE or TF_NEED_NEW_TAPE
+
+ Notes: It is assumed that we are at EOD when this function is
+ called.
+
+ If 'get_best' is FALSE and there is no set which ends on
+ the current tape then there is obviously no Set Map on
+ the tape and we return TF_NO_SM_ON_TAPE. This is not an
+ error, only an indication that since we can't get the
+ next tape in the family we cannot provide ANY set map
+ information for the tape family.
+
+**/
+INT16 OTC_GetPrevSM(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer,
+ BOOLEAN get_best,
+ BOOLEAN expect_sm )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)(channel->fmt_env) ;
+ MTF_ESET_PTR cur_eset = (MTF_ESET_PTR)BM_XferBase( buffer ) ;
+ MTF_DB_HDR_PTR cur_hdr = (MTF_DB_HDR_PTR)BM_XferBase( buffer ) ;
+ MTF_EOTM_PTR cur_eotm = (MTF_EOTM_PTR)BM_XferBase( buffer ) ;
+ INT16 drv_hdl = channel->cur_drv->drv_hdl ;
+ INT16 ret_val ;
+ RET_BUF myret ;
+ UINT32 addr ;
+ INT16 num_blks ;
+
+ msassert( buffer != NULL ) ;
+
+ /* Move to previous ESET */
+
+ DRIVER_CALL( drv_hdl, TpReadEndSet( drv_hdl, (INT16)1, (INT16)BACKWARD ), myret,
+ GEN_NO_ERR, GEN_NO_ERR, (VOID)0 )
+ if( ChannelBlkSize( channel ) < channel->lb_size ) {
+ num_blks = channel->lb_size / ChannelBlkSize( channel ) ;
+ } else {
+ num_blks = 1 ;
+ }
+
+ DRIVER_CALL( drv_hdl, TpSpace( drv_hdl, num_blks, SPACE_BKWD_BLK ),
+ myret, GEN_NO_ERR, GEN_NO_ERR, (VOID)0 )
+
+ DRIVER_CALL( drv_hdl, TpGetPosition( drv_hdl, FALSE ), myret,
+ GEN_NO_ERR, GEN_NO_ERR, (VOID)0 )
+ addr = myret.misc ;
+
+ DRIVER_CALL( drv_hdl, TpRead( drv_hdl, BM_XferBase( buffer ), (UINT32)BM_XferSize( buffer ) ),
+ myret, GEN_NO_ERR, GEN_ERR_ENDSET, (VOID)0 )
+
+ BM_SetBytesFree( buffer, (UINT16)myret.len_got ) ;
+ BM_SetReadError( buffer, myret.gen_error ) ;
+
+ /* If we read an EOTM, and get_best is TRUE, or expect_sm is FALSE,
+ tell them we need the next tape, otherwise we use the EOTM to get
+ to the last ESET on tape.
+ */
+ if( F40_GetBlkType( cur_hdr ) == BT_CVCB ) {
+ cur_env->sm_at_eom = TRUE ;
+ if( get_best || !expect_sm ) {
+ return( TF_NEED_NEW_TAPE ) ;
+ }
+ if( cur_hdr->block_attribs & MTF_DB_NO_ESET_PBA ) {
+ return( TF_NO_SM_ON_TAPE ) ;
+ }
+ addr = U64_Lsw( cur_eotm->eset_phys_blk_adr ) ;
+ DRIVER_CALL( drv_hdl, TpSeek( drv_hdl, addr, FALSE ),
+ myret, GEN_NO_ERR, GEN_NO_ERR, (VOID)0 )
+
+ BM_SetNextByteOffset( buffer, 0 ) ;
+ DRIVER_CALL( drv_hdl, TpRead( drv_hdl, BM_XferBase( buffer ), (UINT32)BM_XferSize( buffer ) ),
+ myret, GEN_NO_ERR, GEN_ERR_ENDSET, (VOID)0 )
+
+ BM_SetBytesFree( buffer, (UINT16)myret.len_got ) ;
+ BM_SetReadError( buffer, myret.gen_error ) ;
+ } else {
+ cur_env->sm_at_eom = FALSE ;
+
+ /* Save the PBA in the environment (for EOM processing) */
+ cur_env->eset_pba = addr ;
+ }
+
+ if( F40_GetBlkType( cur_hdr ) != BT_BSDB ) {
+ return( TFLE_TAPE_INCONSISTENCY ) ;
+ }
+
+ /* So we put the correct set number on tape. */
+ if( ( ( channel->mode & ~0x8000 ) == TF_WRITE_OPERATION ) ||
+ ( ( channel->mode & ~0x8000 ) == TF_WRITE_APPEND ) ) {
+
+ channel->bs_num = cur_eset->backup_set_number + 1 ;
+ }
+
+ if( !expect_sm ) {
+ return( TFLE_NO_ERR ) ;
+ }
+
+ /* Get SM starting address from ESET */
+ if( cur_hdr->block_attribs & MTF_DB_END_OF_FAMILY_BIT ) {
+ return( TFLE_BAD_SET_MAP ) ;
+ } else {
+ addr = U64_Lsw( cur_eset->set_map_phys_blk_adr ) ;
+ }
+
+ /* Position to start of SM */
+ DRIVER_CALL( drv_hdl, TpSeek( drv_hdl, addr, FALSE ), myret, GEN_NO_ERR,
+ GEN_NO_ERR, (VOID)0 )
+
+ /* Write SM to file */
+ ret_val = OTC_SMtoFile( channel, buffer ) ;
+
+ if( ret_val == TFLE_NO_ERR && !cur_env->sm_at_eom ) {
+ /* We need to do a "no data" read for the drives sake!!! */
+ myret.gen_error = GEN_NO_ERR ;
+ while( ret_val == TFLE_NO_ERR && myret.gen_error != GEN_ERR_NO_DATA ) {
+ if( TpRead( drv_hdl, BM_XferBase( buffer ),
+ (UINT32)BM_XferSize( buffer ) ) != SUCCESS ) {
+
+ ret_val = TFLE_DRIVER_FAILURE ;
+ } else {
+ while( TpReceive( drv_hdl, &myret ) == FAILURE ) {
+ ThreadSwitch( ) ;
+ }
+ if( myret.gen_error == GEN_NO_ERR ||
+ ( myret.gen_error == GEN_ERR_NO_DATA &&
+ myret.len_got != 0 ) ) {
+
+ ret_val = TFLE_BAD_SET_MAP ;
+ } else if( myret.gen_error == GEN_ERR_NO_MEDIA ) {
+ ret_val = TFLE_NO_TAPE ;
+ } else if( myret.gen_error != GEN_ERR_ENDSET &&
+ myret.gen_error != GEN_ERR_NO_DATA ) {
+ ret_val = TFLE_DRIVE_FAILURE ;
+ }
+ }
+ }
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_SMtoFile
+
+ Description: Called by OTC_GetPrevSM to transfer the Set Map on tape
+ to the temporary SM file.
+
+ Returns: INT16 - TFLE_xxx
+
+ Notes: Assumes tape is positioned at start of SM.
+
+**/
+static INT16 _near OTC_SMtoFile(
+ CHANNEL_PTR channel,
+ BUF_PTR tmpBUF )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)(channel->fmt_env) ;
+ INT16 ret_val ;
+
+ if( ( ret_val = OTC_ReadStream( channel, tmpBUF, cur_env->otc_sm_fptr ) ) != TFLE_NO_ERR ) {
+ return( ret_val ) ;
+ }
+ if( IsPosBitSet( channel->cur_drv, AT_EOM ) ) {
+ /* We should never be reading a set map which did not finish
+ before hitting EOM.
+ */
+ msassert( FALSE ) ;
+ return( TFLE_TAPE_INCONSISTENCY ) ;
+ }
+
+ return( TFLE_NO_ERR ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_FDDtoFile
+
+ Description: This function seeks to the fdd_pba as set in the
+ environment, reads in the FDD, and writes it to the
+ FDD temporary file.
+
+ Returns: INT16 - TFLE_xxx
+
+ Notes:
+
+**/
+INT16 OTC_FDDtoFile(
+ CHANNEL_PTR channel )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ FILE * fptr = cur_env->otc_fdd_fptr ;
+ INT16 drv_hdl = channel->cur_drv->drv_hdl ;
+ RET_BUF myret ;
+ INT16 ret_val ;
+ UINT32 skip ;
+ long cur_pos ;
+ long new_pos ;
+ MTF_FDD_HDR fdd_hdr ;
+
+ /* Position to start of FDD */
+ if( cur_env->fdd_continuing ) {
+ cur_env->fdd_continuing = FALSE ;
+ skip = (UINT32)( sizeof( MTF_ESET ) +
+ PadToBoundary( sizeof( MTF_ESET ),
+ ChannelBlkSize( channel ) ) ) ;
+ DRIVER_CALL( drv_hdl, TpRead( drv_hdl, BM_XferBase( channel->cur_buff ), skip ),
+ myret, GEN_NO_ERR, GEN_NO_ERR, (VOID)0 )
+ } else {
+ cur_env->otc_ver = channel->ui_tpos->tape_cat_ver ;
+
+ DRIVER_CALL( drv_hdl, TpSeek( drv_hdl, channel->ui_tpos->set_cat_pba, FALSE ),
+ myret, GEN_NO_ERR, GEN_NO_ERR, (VOID)0 )
+ }
+
+ if( ( ret_val = OTC_ReadStream( channel, channel->cur_buff, fptr ) ) != TFLE_NO_ERR ) {
+ return( ret_val ) ;
+ }
+
+ if( IsPosBitSet( channel->cur_drv, AT_EOM ) ) {
+
+ /* If this is rev 1 of otc, the continuation of the FDD stream
+ starts after the last entry which was fully written to this
+ tape, so we need to adjust the file pointer to point to this
+ position before we write the portion of the FDD on the
+ continuation tape.
+
+ If this is rev 2, the FDD stream will pick up where it left off.
+ */
+ if( cur_env->otc_ver == 1 ) {
+ cur_pos = ftell( fptr ) ;
+ new_pos = 0L ;
+ fdd_hdr.length = 0L ;
+ while( new_pos + fdd_hdr.length <= cur_pos ) {
+ new_pos += fdd_hdr.length ;
+ if( fseek( fptr, new_pos, SEEK_SET ) != 0 ) {
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ if( cur_pos - new_pos >= sizeof( MTF_FDD_HDR ) ) {
+ if( fread( (void *)&fdd_hdr, sizeof( MTF_FDD_HDR ), 1, fptr ) != 1 ) {
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ } else {
+ break ;
+ }
+ }
+ fseek( fptr, new_pos, SEEK_SET ) ;
+ }
+ cur_env->fdd_continuing = TRUE ;
+ } else {
+ fseek( fptr, 0L, SEEK_SET ) ;
+ }
+
+ return( TFLE_NO_ERR ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_ReadStream
+
+ Description:
+
+ Returns: INT16 - TFLE_xxx
+
+ Notes:
+
+**/
+static INT16 _near OTC_ReadStream(
+ CHANNEL_PTR channel,
+ BUF_PTR tmpBUF,
+ FILE * fptr )
+{
+ unsigned int rdwr_size ;
+ UINT32 size ;
+ INT16 drv_hdl = channel->cur_drv->drv_hdl ;
+ RET_BUF myret ;
+
+ if( ( rdwr_size = UINT_MAX - UINT_MAX % ChannelBlkSize( channel ) ) == UINT_MAX ) {
+ rdwr_size -= ChannelBlkSize( channel ) ;
+ }
+ rdwr_size = MIN( rdwr_size, BM_XferSize( tmpBUF ) ) ;
+
+ /* Read in the first buffer which contains the stream header */
+ BM_SetNextByteOffset( tmpBUF, 0 ) ;
+ DRIVER_CALL( drv_hdl, TpRead( drv_hdl, BM_XferBase( tmpBUF ), (UINT32)rdwr_size ),
+ myret, GEN_NO_ERR, GEN_ERR_ENDSET, (VOID)0 )
+ BM_SetBytesFree( tmpBUF, (UINT16)myret.len_got ) ;
+ BM_SetReadError( tmpBUF, myret.gen_error ) ;
+
+ /* get the size of the stream */
+ size = U64_Lsw( ((MTF_STREAM_PTR)BM_XferBase( tmpBUF ))->data_length ) ;
+ BM_UpdCnts( tmpBUF, sizeof( MTF_STREAM ) ) ;
+
+ while( size > BM_BytesFree( tmpBUF ) ) {
+ size -= BM_BytesFree( tmpBUF ) ;
+ if( fwrite( BM_NextBytePtr( tmpBUF ), 1, (size_t)BM_BytesFree( tmpBUF ), fptr )
+ != (size_t)BM_BytesFree( tmpBUF ) ) {
+ return( TFLE_OTC_FAILURE ) ;
+ }
+
+ if( BM_ReadError( tmpBUF ) == GEN_ERR_ENDSET ) {
+ SetPosBit( channel->cur_drv, ( AT_EOM | TAPE_FULL ) ) ;
+ return( TFLE_NO_ERR ) ;
+ }
+ BM_SetNextByteOffset( tmpBUF, 0 ) ;
+ DRIVER_CALL( drv_hdl, TpRead( drv_hdl, BM_XferBase( tmpBUF ), (UINT32)rdwr_size ),
+ myret, GEN_NO_ERR, GEN_ERR_ENDSET, (VOID)0 )
+ BM_SetBytesFree( tmpBUF, (UINT16)myret.len_got ) ;
+ BM_SetReadError( tmpBUF, myret.gen_error ) ;
+ }
+ if( fwrite( BM_NextBytePtr( tmpBUF ), 1, (size_t)size, fptr )
+ != (size_t)size ) {
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ if( fflush( fptr ) != 0 ) {
+ return( TFLE_OTC_FAILURE ) ;
+ }
+
+ /* if we haven't crossed over the ending file mark, do so now, and set
+ the drive position accordingly.
+ */
+ if( BM_ReadError( tmpBUF ) != GEN_ERR_ENDSET ) {
+ DRIVER_CALL( drv_hdl, TpReadEndSet( drv_hdl, (INT16)1, (INT16)FORWARD ),
+ myret, GEN_NO_ERR, GEN_NO_ERR, (VOID)0 )
+ }
+ ClrPosBit( channel->cur_drv, ( AT_EOD | AT_EOM | AT_MOS ) ) ;
+ SetPosBit( channel->cur_drv, AT_EOS ) ;
+ return( TFLE_NO_ERR ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_WriteCat
+
+ Description: This function transfers the OTC temporary files to tape.
+
+ Returns: INT16 - TFLE_xxx
+
+ Notes:
+
+**/
+INT16 OTC_WriteCat(
+ CHANNEL_PTR channel,
+ MTF_ESET_PTR cur_eset )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)(channel->fmt_env) ;
+ BUF_PTR tmpBUF ;
+ INT16 ret_val ;
+ INT16 drv_hdl = channel->cur_drv->drv_hdl ;
+ RET_BUF myret ;
+ unsigned int rdwr_size ;
+
+ /* get buffer and calc transfer size to work on file read as
+ well as tape write.
+ */
+ tmpBUF = BM_Get( &channel->buffer_list ) ;
+ if( ( rdwr_size = UINT_MAX - UINT_MAX % ChannelBlkSize( channel ) ) == UINT_MAX ) {
+ rdwr_size -= ChannelBlkSize( channel ) ;
+ }
+ rdwr_size = MIN( rdwr_size, BM_XferSize( tmpBUF ) ) ;
+
+ /* if we're writing FDD ... */
+ if( cur_env->cur_otc_level == TCL_FULL && !cur_env->fdd_aborted &&
+ !cur_env->fdd_completed ) {
+
+ /* Set the PBA and sequence number of the FDD in the ESET */
+ if( !cur_env->fdd_continuing ) {
+ cur_env->fdd_pba = cur_env->eset_base_addr ;
+ cur_eset->fdd_phys_blk_adr = U64_Init( cur_env->eset_base_addr, 0L ) ;
+ cur_env->fdd_seq_num = channel->ts_num ;
+ cur_eset->fdd_tape_seq_number = channel->ts_num ;
+ } else {
+ cur_eset->fdd_phys_blk_adr = U64_Init( cur_env->fdd_pba, 0L ) ;
+ cur_eset->fdd_tape_seq_number = cur_env->fdd_seq_num ;
+ }
+
+ /* Write FDD to tape */
+ if( ( ret_val = OTC_WriteFDD( channel, tmpBUF, rdwr_size ) ) != TFLE_NO_ERR ) {
+ BM_Put( tmpBUF ) ;
+ return( ret_val ) ;
+ }
+
+ if( IsPosBitSet( channel->cur_drv, ( AT_EOM ) ) ) {
+ BM_Put( tmpBUF ) ;
+ return( ret_val ) ;
+ }
+ }
+
+ /* Update OTC SM entry */
+ if( !cur_env->sm_aborted && !cur_env->sm_continuing ) {
+ if( ( ret_val = OTC_UpdateSMEntry( (F40_ENV_PTR)channel->fmt_env ) )
+ != TFLE_NO_ERR ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ BM_Put( tmpBUF ) ;
+ return( ret_val ) ;
+ }
+ }
+
+ if( !cur_env->sm_aborted ) {
+ /* Set the PBA of the SM in the ESET. Note that if we hit EOM we
+ won't write the ESET and we will rewrite the whole SM on the
+ continuation tape, so we do this no matter what.
+ */
+ cur_eset->set_map_phys_blk_adr = U64_Init( cur_env->eset_base_addr, 0L ) ;
+
+ BM_SetNextByteOffset( tmpBUF, 0U ) ;
+ ret_val = OTC_WriteSM( channel, tmpBUF, rdwr_size ) ;
+ }
+
+ BM_Put( tmpBUF ) ;
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_WriteFDD
+
+ Description: This function is called by OTC_WriteCat to transfer the
+ FDD data to tape.
+
+ Returns: INT16 - TFLE_xxx
+
+ Notes:
+
+**/
+static INT16 _near OTC_WriteFDD(
+ CHANNEL_PTR channel,
+ BUF_PTR tmpBUF,
+ unsigned int rdwr_size )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)(channel->fmt_env) ;
+ FILE * fptr = cur_env->otc_fdd_fptr ;
+ BOOLEAN completed ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ UINT32 len ;
+ long hdr_size = sizeof( MTF_FDD_HDR ) ;
+ UINT32 bsize = ChannelBlkSize( channel ) ;
+
+ len = filelength( _fileno( fptr ) ) + sizeof( MTF_STREAM ) ;
+
+ /* rewind the file */
+ if( !cur_env->fdd_continuing ) {
+ if( fseek( fptr, 0L, SEEK_SET ) != 0 ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ } else {
+ len -= ftell( fptr ) ;
+ }
+
+ len = ( ( len + bsize - 1L ) / bsize ) * bsize ;
+ cur_env->eset_base_addr += len / bsize ;
+ len -= sizeof( MTF_STREAM ) ;
+
+ ret_val = OTC_WriteStream( channel, tmpBUF, rdwr_size, fptr,
+ STRM_OTC_FDD, len, TRUE, &completed,
+ cur_env->fdd_continuing ) ;
+
+ cur_env->fdd_continuing = FALSE ;
+
+ if( ret_val != TFLE_NO_ERR ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ if( ret_val == TFLE_OTC_FAILURE ) {
+ ret_val = TFLE_NO_ERR ;
+ }
+
+ } else if( IsPosBitSet( channel->cur_drv, AT_EOM ) && !completed ) {
+ cur_env->fdd_continuing = TRUE ;
+
+ } else {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_completed = TRUE ;
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_WriteSM
+
+ Description: This function is called by OTC_WriteCat to transfer the
+ SM data to tape.
+
+ Returns: INT16 - TFLE_xxx
+
+ Notes: We don't close the SM file here because we may still
+ hit EOM and have to rewrite the SM on the next tape.
+
+**/
+static INT16 _near OTC_WriteSM(
+ CHANNEL_PTR channel,
+ BUF_PTR tmpBUF,
+ unsigned int rdwr_size )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)(channel->fmt_env) ;
+ MTF_SM_HDR sm_hdr ;
+ FILE * fptr = cur_env->otc_sm_fptr ;
+ INT16 ret_val ;
+ BOOLEAN completed ;
+ UINT32 len ;
+
+ if( !cur_env->sm_adjusted ) {
+ /* read SM header, update it and write it back out */
+ fseek( fptr, 0L, SEEK_SET ) ;
+ if( fread( &sm_hdr, sizeof( MTF_SM_HDR ), 1, fptr ) != 1 ) {
+ /* Abort Set Map */
+ OTC_Close( cur_env, OTC_CLOSE_SM, TRUE ) ;
+ cur_env->sm_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ sm_hdr.num_set_recs += cur_env->sm_count ;
+ fseek( fptr, 0L, SEEK_SET ) ;
+ if( fwrite( &sm_hdr, sizeof( MTF_SM_HDR ), 1, fptr ) != 1 ) {
+ /* Abort Set Map */
+ OTC_Close( cur_env, OTC_CLOSE_SM, TRUE ) ;
+ cur_env->sm_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ cur_env->sm_adjusted = TRUE ;
+ }
+
+ /* rewind the file */
+ if( fseek( fptr, 0L, SEEK_SET ) != 0 ) {
+ OTC_Close( cur_env, OTC_CLOSE_SM, TRUE ) ;
+ cur_env->sm_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+
+ len = filelength( _fileno( fptr ) ) ;
+ cur_env->eset_base_addr += ( len + sizeof( MTF_STREAM ) ) /
+ ChannelBlkSize( channel ) ;
+ ret_val = OTC_WriteStream( channel, tmpBUF, rdwr_size, fptr,
+ STRM_OTC_SM, len, FALSE, &completed, FALSE ) ;
+
+ if( ret_val != TFLE_NO_ERR ) {
+ OTC_Close( cur_env, OTC_CLOSE_SM, TRUE ) ;
+ cur_env->sm_aborted = TRUE ;
+ if( ret_val == TFLE_OTC_FAILURE ) {
+ ret_val = TFLE_NO_ERR ;
+ }
+ } else if( IsPosBitSet( channel->cur_drv, AT_EOM ) ) {
+ cur_env->sm_continuing = TRUE ;
+ } else {
+ if( ( ret_val = OTC_WriteSMPadStream( channel, tmpBUF ) ) != TFLE_NO_ERR ) {
+ OTC_Close( cur_env, OTC_CLOSE_SM, TRUE ) ;
+ cur_env->sm_aborted = TRUE ;
+ if( ret_val == TFLE_OTC_FAILURE ) {
+ ret_val = TFLE_NO_ERR ;
+ }
+ } else if( IsPosBitSet( channel->cur_drv, AT_EOM ) ) {
+ cur_env->sm_continuing = TRUE ;
+ }
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_WriteStream
+
+ Description: This function is called by OTC_WriteFDD and OTC_WriteSM
+ to write the stream header and data to tape.
+
+ Returns: INT16 - TFLE_xxx
+
+ Notes:
+
+**/
+static INT16 _near OTC_WriteStream(
+ CHANNEL_PTR channel,
+ BUF_PTR tmpBUF,
+ unsigned int rdwr_size,
+ FILE * fptr,
+ UINT32 type,
+ UINT32 length,
+ BOOLEAN pad_to_boundary,
+ BOOLEAN_PTR completed,
+ BOOLEAN continuation )
+{
+ RET_BUF myret ;
+ unsigned int size ;
+ MTF_STREAM_PTR str_hdr ;
+ BOOLEAN first_time = TRUE ;
+ INT16 drv_hdl = channel->cur_drv->drv_hdl ;
+ BOOLEAN file_error = FALSE ;
+ UINT32 pad ;
+ long offset ;
+
+ memset( (void *)BM_XferBase( tmpBUF ), 0, (size_t)BM_XferSize( tmpBUF ) ) ;
+ *completed = TRUE ;
+
+ /* Write the stream header */
+ str_hdr = ( MTF_STREAM_PTR ) BM_XferBase( tmpBUF ) ;
+
+ str_hdr->id = type ;
+ str_hdr->fs_attribs = 0L ;
+ str_hdr->tf_attribs = 0L ;
+ str_hdr->encr_algor = 0 ;
+ str_hdr->comp_algor = 0 ;
+ str_hdr->data_length = U64_Init( length, 0L ) ;
+
+ if( continuation ) {
+ str_hdr->tf_attribs |= STREAM_CONTINUE ;
+ }
+
+ str_hdr->chksum = CalcChecksum( (UINT16_PTR)str_hdr, F40_STREAM_CHKSUM_LEN ) ;
+
+ BM_SetNextByteOffset( tmpBUF, sizeof( MTF_STREAM ) ) ;
+
+ /* loop writing file to tape until done, error or EOM */
+ do {
+ /* On the first pass, the stream header is already in the buffer. */
+ if( first_time ) {
+ first_time = FALSE ;
+ size = rdwr_size - sizeof( MTF_STREAM ) ;
+ size = fread( (void *)BM_NextBytePtr( tmpBUF ), 1, size, fptr ) ;
+ if( ferror( fptr ) != 0 ) {
+ file_error = TRUE ;
+ size = (unsigned int)( MIN( length, ( rdwr_size - sizeof( MTF_STREAM ) ) ) ) ;
+ }
+ length -= size ;
+ size += sizeof( MTF_STREAM ) ;
+ } else {
+ if( !file_error ) {
+ size = fread( (void *)BM_XferBase( tmpBUF ), 1, rdwr_size, fptr ) ;
+ if( ferror( fptr ) != 0 ) {
+ file_error = TRUE ;
+ size = (unsigned int)( MIN( length, rdwr_size ) ) ;
+ }
+ } else {
+ size = (unsigned int)( MIN( length, rdwr_size ) ) ;
+ }
+ length -= size ;
+ }
+
+ /* if we are done, set size to include pad out to block boundry. */
+ if( !file_error && feof( fptr ) ) {
+ if( pad_to_boundary ) {
+ msassert( length == ( rdwr_size - size ) % ChannelBlkSize( channel ) ) ;
+ pad = length ;
+ size += length ;
+ length = 0 ;
+
+ } else {
+ msassert( length == 0 ) ;
+ BM_SetNextByteOffset( tmpBUF, size ) ;
+ BM_SetBytesFree( tmpBUF, rdwr_size - size ) ;
+ return( TFLE_NO_ERR ) ;
+ }
+ }
+
+ DRIVER_CALL( drv_hdl, TpWrite( drv_hdl, BM_XferBase( tmpBUF ), size ),
+ myret, GEN_NO_ERR, GEN_ERR_EOM, (VOID)0 )
+
+ memset( (void *)BM_XferBase( tmpBUF ), 0, size ) ;
+
+ if( myret.gen_error == GEN_ERR_EOM ) {
+ SetPosBit( channel->cur_drv, ( AT_EOM | TAPE_FULL ) ) ;
+ if( myret.len_got != myret.len_req || !feof( fptr ) ) {
+ *completed = FALSE ;
+ }
+ if( type == STRM_OTC_FDD && myret.len_got != myret.len_req ) {
+
+ /* seek back in file the amount not written */
+ offset = (long)( myret.len_req - myret.len_got ) ;
+ offset -= pad ;
+ if( fseek( fptr, - offset, SEEK_CUR ) != 0 ) {
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ }
+ return( TFLE_NO_ERR ) ;
+ }
+ } while( length != 0 ) ;
+
+ return( file_error ? TFLE_OTC_FAILURE : TFLE_NO_ERR ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name:
+
+ Description:
+
+ Returns:
+
+ Notes: We need to make sure we are on a 1024 boundary to avoid
+ a bug with the Wangtek 525 drives reporting the PBA
+ wrong when in 512 mode.
+
+**/
+static INT16 _near OTC_WriteSMPadStream(
+ CHANNEL_PTR channel,
+ BUF_PTR tmpBUF )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)(channel->fmt_env) ;
+ INT16 drv_hdl = channel->cur_drv->drv_hdl ;
+ UINT32 bsize = ChannelBlkSize( channel ) ;
+ RET_BUF myret ;
+ unsigned int size = 0 ;
+ unsigned int part ;
+ MTF_STREAM str_hdr ;
+ UINT8_PTR p ;
+
+ /* Pad to align stream on four byte boundary (format spec). */
+ BM_UpdCnts( tmpBUF, (UINT16)PadToBoundary( BM_NextByteOffset( tmpBUF ), 4 ) ) ;
+
+ if( BM_BytesFree( tmpBUF ) % bsize != 0 ) {
+
+ cur_env->eset_base_addr++ ;
+ size = (unsigned int)( BM_BytesFree( tmpBUF ) % bsize ) ;
+ /* If we're not on a 1024, get there. */
+ if( bsize == 512 && cur_env->eset_base_addr % 2 != 0 ) {
+ size += 512 ;
+ cur_env->eset_base_addr++ ;
+ }
+ /* If the pad is smaller than the header, pad anoth chunk. */
+ if( size < sizeof( MTF_STREAM ) ) {
+ size += MAX( bsize, 1024 ) ;
+ cur_env->eset_base_addr += size / bsize ;
+ }
+ size -= sizeof( MTF_STREAM ) ;
+ } else {
+ /* If we're not on a 1024, get there. */
+ if( bsize == 512 && cur_env->eset_base_addr % 2 != 0 ) {
+ size = 512 - sizeof( MTF_STREAM ) ;
+ cur_env->eset_base_addr++ ;
+ }
+ }
+
+ if( size != 0 ) {
+ str_hdr.id = STRM_PAD ;
+ str_hdr.fs_attribs = 0L ;
+ str_hdr.tf_attribs = 0L ;
+ str_hdr.encr_algor = 0 ;
+ str_hdr.comp_algor = 0 ;
+ str_hdr.data_length = U64_Init( size, 0L ) ;
+ str_hdr.chksum = CalcChecksum( (UINT16_PTR)&str_hdr, F40_STREAM_CHKSUM_LEN ) ;
+ size += sizeof( MTF_STREAM ) ;
+
+ if( ( part = BM_BytesFree( tmpBUF ) ) < sizeof( MTF_STREAM ) ) {
+ if( part != 0 ) {
+ memcpy( BM_NextBytePtr( tmpBUF ), &str_hdr, part ) ;
+ BM_UpdCnts( tmpBUF, (UINT16)part ) ;
+ }
+ DRIVER_CALL( drv_hdl, TpWrite( drv_hdl, BM_XferBase( tmpBUF ), BM_NextByteOffset( tmpBUF ) ),
+ myret, GEN_NO_ERR, GEN_ERR_EOM, (VOID)0 )
+
+ if( myret.gen_error == GEN_ERR_EOM ) {
+ SetPosBit( channel->cur_drv, ( AT_EOM | TAPE_FULL ) ) ;
+ return( TFLE_NO_ERR ) ;
+ }
+ p = (UINT8_PTR)(void *)( &str_hdr ) ;
+ p += part ;
+ size -= part ;
+ memset( BM_XferBase( tmpBUF ), 0, (size_t)BM_XferSize( tmpBUF ) ) ;
+ memcpy( BM_XferBase( tmpBUF ), p, sizeof( MTF_STREAM ) - part ) ;
+ } else {
+ memset( BM_NextBytePtr( tmpBUF ), 0, (size_t)BM_BytesFree( tmpBUF ) ) ;
+ memcpy( BM_NextBytePtr( tmpBUF ), &str_hdr, sizeof( MTF_STREAM ) ) ;
+ if( size > BM_BytesFree( tmpBUF ) ) {
+ size -= BM_BytesFree( tmpBUF ) ;
+ BM_UpdCnts( tmpBUF, BM_BytesFree( tmpBUF ) ) ;
+ DRIVER_CALL( drv_hdl, TpWrite( drv_hdl, BM_XferBase( tmpBUF ), BM_NextByteOffset( tmpBUF ) ),
+ myret, GEN_NO_ERR, GEN_ERR_EOM, (VOID)0 )
+ memset( BM_XferBase( tmpBUF ), 0, (size_t)size ) ;
+ } else {
+ size += BM_NextByteOffset( tmpBUF ) ;
+ }
+ }
+ } else {
+ size = BM_NextByteOffset( tmpBUF ) ;
+ }
+
+ if( size != 0 ) {
+ DRIVER_CALL( drv_hdl, TpWrite( drv_hdl, BM_XferBase( tmpBUF ), size ),
+ myret, GEN_NO_ERR, GEN_ERR_EOM, (VOID)0 )
+
+ if( myret.gen_error == GEN_ERR_EOM ) {
+ SetPosBit( channel->cur_drv, ( AT_EOM | TAPE_FULL ) ) ;
+ }
+ }
+
+ return( TFLE_NO_ERR ) ;
+}
diff --git a/private/utils/ntbackup/src/otc40rd.c b/private/utils/ntbackup/src/otc40rd.c
new file mode 100644
index 000000000..4a7af701c
--- /dev/null
+++ b/private/utils/ntbackup/src/otc40rd.c
@@ -0,0 +1,1058 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-92
+
+
+ Name: otc40rd.c
+
+ Description: Contains the Code for reading On Tape Catalogs.
+
+
+ $Log: T:/LOGFILES/OTC40RD.C_V $
+
+ Rev 1.32.1.2 27 Mar 1994 19:30:22 GREGG
+Don't map password strings to unicode no matter what.
+
+ Rev 1.32.1.1 05 Jan 1994 10:51:52 BARRY
+Changed UINT16 parameters in Unicode mapping functions to INTs
+
+ Rev 1.32.1.0 02 Nov 1993 12:43:02 GREGG
+Added string type conversion of tape name password if THDR type != SSET type.
+
+ Rev 1.32 15 Jul 1993 19:32:04 GREGG
+Set compressed_obj, vendor_id, and compressed, encrypted and future_rev
+bits in appropriate dblks.
+
+ Rev 1.32 13 Jul 1993 19:28:04 GREGG
+Set compressed_set, compressed_obj, encrypted_set, future_rev and vendor_id
+in appropriate dblks.
+
+ Rev 1.31 04 Jun 1993 18:50:42 GREGG
+Fixed bug where we were skipping past the "FEND" entry thinking it was a
+continuation entry (garbage data in the attrib field which is not defined
+for a "FEND" entry).
+
+ Rev 1.30 04 Jun 1993 18:35:50 GREGG
+For OEM_MSOFT (ntbackup) - mark sets with encrypted or compressed data as
+image set so the UI wont try to restore the data. This is a kludge which
+will be fixed correctly when we have more time.
+
+ Rev 1.29 02 Jun 1993 16:59:26 GREGG
+Fixed bug in determining if the OTC is version 1 or 2 in OTC_RdDIR.
+
+ Rev 1.28 20 May 1993 17:33:04 BARRY
+Declare a problematic variable volatile to get around an MSoft NT compiler bug.
+
+ Rev 1.27 26 Apr 1993 11:32:44 GREGG
+Old tape read fix: Was getting OTC ver number from wrong place.
+
+ Rev 1.26 26 Apr 1993 02:43:40 GREGG
+Sixth in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Redefined attribute bits to match the spec.
+ - Eliminated unused/undocumented bits.
+ - Added code to translate bits on tapes that were written wrong.
+
+Matches MAYN40RD.C 1.59, DBLKS.H 1.15, MAYN40.H 1.34, OTC40RD.C 1.26,
+ SYPL10RD.C 1.8, BACK_VCB.C 1.17, MAYN31RD.C 1.44, SYPL10.H 1.2
+
+ Rev 1.25 25 Apr 1993 18:52:40 GREGG
+Fourth in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Parse the device name and volume name out of the FS supplied "volume
+ name", and write it to tape as separate fields.
+ - Generate the "volume name" the FS and UI expect out of the device
+ name and volume name on tape.
+ - Write all strings without NULL terminater, and translate them back
+ to NULL terminated strings on the read side.
+
+Matches: MTF10WDB.C 1.8, F40PROTO.H 1.26, OTC40WT.C 1.24, MAYN40.H 1.33,
+ MAYN40RD.C 1.57, OTC40RD.C 1.25
+
+ Rev 1.24 22 Apr 1993 03:31:26 GREGG
+Third in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Removed all references to the DBLK element 'string_storage_offset',
+ which no longer exists.
+ - Check for incompatable versions of the Tape Format and OTC and deals
+ with them the best it can, or reports tape as foreign if they're too
+ far out. Includes ignoring the OTC and not allowing append if the
+ OTC on tape is a future rev, different type, or on an alternate
+ partition.
+ - Updated OTC "location" attribute bits, and changed definition of
+ CFIL to store stream number instead of stream ID.
+
+Matches: TFL_ERR.H 1.9, MTF10WDB.C 1.7, TRANSLAT.C 1.39, FMTINF.H 1.11,
+ OTC40RD.C 1.24, MAYN40RD.C 1.56, MTF10WT.C 1.7, OTC40MSC.C 1.20
+ DETFMT.C 1.13, MTF.H 1.4
+
+ Rev 1.23 19 Apr 1993 18:00:26 GREGG
+Second in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ Changes to write version 2 of OTC, and to read both versions.
+
+Matches: mayn40rd.c 1.55, otc40msc.c 1.19, otc40rd.c 1.23, otc40wt.c 1.23,
+ makevcb.c 1.15, fsys.h 1.32, fsys_str.h 1.46, tpos.h 1.16,
+ mayn40.h 1.32, mtf.h 1.3.
+
+NOTE: There are additional changes to the catalogs needed to save the OTC
+ version and put it in the tpos structure before loading the OTC
+ File/Directory Detail. These changes are NOT listed above!
+
+ Rev 1.22 12 Feb 1993 02:26:48 GREGG
+Fixes to deal with the MIPS machine's dislike for unaligned pointers.
+
+ Rev 1.21 07 Dec 1992 10:06:52 GREGG
+Changes for tf ver moved to SSET, otc ver added to SSET and links added to FDD.
+
+ Rev 1.20 24 Nov 1992 18:16:10 GREGG
+Updates to match MTF document.
+
+ Rev 1.19 23 Nov 1992 10:03:52 GREGG
+Changes for path in stream.
+
+ Rev 1.18 17 Nov 1992 14:12:42 GREGG
+Added string_type.
+
+ Rev 1.17 09 Nov 1992 11:00:34 GREGG
+Merged in changes for new method of accessing OTC.
+
+ Rev 1.16 22 Oct 1992 10:43:02 HUNTER
+Changes for Stream Headers
+
+
+ Rev 1.15 22 Sep 1992 08:58:18 GREGG
+Initial changes to handle physical block sizes greater than 1K.
+
+ Rev 1.14 30 Jul 1992 16:14:22 GREGG
+Moved OTC_MoveToVCB and OTC_GetFDDtoFile to otc40msc.c.
+
+ Rev 1.13 27 Jul 1992 12:48:56 GREGG
+Fixed more warnings...
+
+ Rev 1.12 01 Jul 1992 19:30:54 GREGG
+Converted to new date/time structure for dates written to tape.
+
+ Rev 1.11 18 Jun 1992 16:29:26 GREGG
+Handled request to move to the current set in OTC_MoveToVCB.
+
+ Rev 1.10 17 Jun 1992 15:56:06 GREGG
+Fixed loop transfering OTC from tape to disk.
+
+ Rev 1.9 12 Jun 1992 10:38:28 GREGG
+Fixed bug with single set sm_entry not being copied to the environment.
+
+ Rev 1.8 09 Jun 1992 16:01:24 GREGG
+Changes to use F40_CalcChecksum instead of CalcChecksum.
+Removed merging of attributes.
+Set a boolean for continuation blocks.
+Removed setting of filemark_count.
+
+ Rev 1.7 08 Jun 1992 16:57:32 GREGG
+Changed msassert in OTC_MoveToVCB.
+
+ Rev 1.6 04 Jun 1992 16:20:24 GREGG
+Fixed buffer handling in OTC_RdSSET.
+
+ Rev 1.5 01 Jun 1992 17:10:18 GREGG
+Set disp_size in gen_data structure.
+
+ Rev 1.4 29 May 1992 15:03:54 GREGG
+Added setting of last access date.
+
+ Rev 1.3 25 May 1992 18:26:50 GREGG
+Expect call to OTC_MoveToVCB more than once at EOD.
+
+ Rev 1.2 22 May 1992 15:25:30 GREGG
+Changed dots to pointers.
+
+ Rev 1.1 21 May 1992 12:22:08 GREGG
+Changes for 64 bit file system.
+
+ Rev 1.0 21 May 1992 12:07:02 GREGG
+Initial revision.
+
+
+**/
+
+#include <stdio.h>
+#include <io.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "stdtypes.h"
+#include "channel.h"
+#include "mayn40.h"
+#include "f40proto.h"
+#include "lw_data.h"
+#include "tfl_err.h"
+#include "lwprotos.h"
+#include "minmax.h"
+#include "transutl.h"
+
+/* Device Driver InterFace Headers */
+#include "retbuf.h"
+#include "drvinf.h"
+#include "generr.h"
+#include "genfuncs.h"
+#include "dil.h"
+#include "dddefs.h"
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_RdSSET
+
+ Description: Reads in an SM entry and it's associated volume entry
+ from the SM file, and translates it to a VCB.
+
+ Returns: INT16 - TFLE_xxx error code
+
+ Notes:
+
+**/
+INT16 OTC_RdSSET(
+ CHANNEL_PTR channel )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ GEN_VCB_DATA gvcb_data ;
+ STD_DBLK_DATA_PTR std_data = &gvcb_data.std_data ;
+ UNALIGNED MTF_SM_ENTRY_PTR sm_entry = (UNALIGNED MTF_SM_ENTRY_PTR)cur_env->otc_buff ;
+ UINT8_PTR buff_ptr = cur_env->otc_buff ;
+ UINT8_PTR dest_ptr ;
+ UINT8_PTR src_ptr ;
+ UNALIGNED MTF_FDD_HDR_PTR fdd_hdr ;
+ UNALIGNED MTF_FDD_VOL_V1_PTR fdd_vol_v1 ;
+ UNALIGNED MTF_FDD_VOL_V2_PTR fdd_vol_v2 ;
+ FILE * fptr = cur_env->otc_sm_fptr ;
+ volatile size_t size ;
+ DATE_TIME backup_date ;
+ MTF_DATE_TIME temp_date ;
+
+ /* read the Set Map Entry */
+ if( fread( sm_entry, sizeof( MTF_SM_ENTRY ), 1, fptr ) != 1 ) {
+ if( !ferror( fptr ) && feof( fptr ) ) {
+ return( TF_NO_MORE_ENTRIES ) ;
+ } else {
+ OTC_Close( cur_env, OTC_CLOSE_SM, TRUE ) ;
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ }
+
+ /* Figure out the OTC level for the set. If the catalog version is
+ greater than the one we write, we won't be able to read the FDD,
+ but we'll still be able to read the set map.
+ */
+ if( U64_Lsw( sm_entry->fdd_pba ) != 0L &&
+ sm_entry->tape_cat_ver <= TAPE_CATALOG_VER ) {
+
+ cur_env->cur_otc_level = TCL_FULL ;
+ } else {
+ cur_env->cur_otc_level = TCL_PARTIAL ;
+ }
+
+ /* read the Set Map Entry's strings */
+ buff_ptr += sizeof( MTF_SM_ENTRY ) ;
+ size = (size_t)sm_entry->length - sizeof( MTF_SM_ENTRY ) ;
+ if( fread( buff_ptr, 1, size, fptr ) != size ) {
+ OTC_Close( cur_env, OTC_CLOSE_SM, TRUE ) ;
+ return( TFLE_OTC_FAILURE ) ;
+ }
+
+ /* read the Set Map Volume Entry */
+ buff_ptr += size ;
+ fdd_hdr = (UNALIGNED MTF_FDD_HDR_PTR)buff_ptr ;
+ if( sm_entry->tape_cat_ver == 1 ) {
+ fdd_vol_v1 = (UNALIGNED MTF_FDD_VOL_V1_PTR)(void *)( fdd_hdr + 1 ) ;
+ size = sizeof( MTF_FDD_HDR ) + sizeof( MTF_FDD_VOL_V1 ) ;
+ } else {
+ fdd_vol_v2 = (UNALIGNED MTF_FDD_VOL_V2_PTR)(void *)( fdd_hdr + 1 ) ;
+ size = sizeof( MTF_FDD_HDR ) + sizeof( MTF_FDD_VOL_V2 ) ;
+ }
+ if( fread( fdd_hdr, 1, size, fptr ) != size ) {
+ OTC_Close( cur_env, OTC_CLOSE_SM, TRUE ) ;
+ return( TFLE_OTC_FAILURE ) ;
+ }
+
+ /* read the Set Map Volume Entry's strings */
+ buff_ptr += size ;
+ size = (size_t)fdd_hdr->length - size ;
+ if( fread( buff_ptr, 1, size, fptr ) != size ) {
+ OTC_Close( cur_env, OTC_CLOSE_SM, TRUE ) ;
+ return( TFLE_OTC_FAILURE ) ;
+ }
+
+ /* Initialize the file systems interface structure */
+ FS_SetDefaultDBLK( channel->cur_fsys, BT_VCB, (CREATE_DBLK_PTR)&gvcb_data ) ;
+ std_data->dblk = channel->cur_dblk ;
+
+ std_data->tape_seq_num = sm_entry->seq_num ;
+
+ /* Set the VCB attributes. Note that if this is an "old" tape,
+ the attibute bits were being set wrong, and need to be translated.
+ */
+ if( sm_entry->tape_cat_ver == 1 ) { // if old tape
+
+ std_data->attrib = 0 ;
+ std_data->attrib |= ( sm_entry->set_attribs & OLD_VCB_COPY_SET )
+ ? VCB_COPY_SET : 0 ;
+ std_data->attrib |= ( sm_entry->set_attribs & OLD_VCB_NORMAL_SET )
+ ? VCB_NORMAL_SET : 0 ;
+ std_data->attrib |= ( sm_entry->set_attribs & OLD_VCB_DIFFERENTIAL_SET )
+ ? VCB_DIFFERENTIAL_SET : 0 ;
+ std_data->attrib |= ( sm_entry->set_attribs & OLD_VCB_INCREMENTAL_SET )
+ ? VCB_INCREMENTAL_SET : 0 ;
+ std_data->attrib |= ( sm_entry->set_attribs & OLD_VCB_DAILY_SET )
+ ? VCB_DAILY_SET : 0 ;
+ std_data->attrib |= ( sm_entry->set_attribs & OLD_VCB_ARCHIVE_BIT )
+ ? VCB_ARCHIVE_BIT : 0 ;
+ } else {
+ std_data->attrib = sm_entry->set_attribs ;
+ }
+
+ /* Clear other vendor's vendor specific bits */
+ std_data->attrib &= 0x00FFFFFF ;
+
+ /* Set our own vendor specific bits */
+ std_data->attrib |= ( sm_entry->tf_minor_ver != FORMAT_VER_MINOR )
+ ? VCB_FUTURE_VER_BIT : 0 ;
+ std_data->attrib |= ( sm_entry->blk_attribs & MTF_DB_COMPRESS_BIT )
+ ? VCB_COMPRESSED_BIT : 0 ;
+ std_data->attrib |= ( sm_entry->blk_attribs & MTF_DB_ENCRYPT_BIT )
+ ? VCB_ENCRYPTED_BIT : 0 ;
+
+ std_data->continue_obj = (BOOLEAN)( sm_entry->blk_attribs & MTF_DB_CONT_BIT ) ;
+ std_data->compressed_obj = (BOOLEAN)( sm_entry->blk_attribs & MTF_DB_COMPRESS_BIT ) ;
+
+ std_data->os_id = (UINT8)sm_entry->os_id ;
+ std_data->os_ver = (UINT8)sm_entry->os_ver ;
+
+ std_data->os_info = NULL ;
+ std_data->os_info_size = 0 ;
+
+ std_data->lba = U64_Lsw( sm_entry->lba ) ;
+ std_data->disp_size = sm_entry->disp_size ;
+
+ std_data->string_type = sm_entry->string_type ;
+
+ gvcb_data.vendor_id = 0 ;
+
+ gvcb_data.set_cat_tape_seq_num = sm_entry->fdd_seq_num ;
+ if( ( gvcb_data.set_cat_pba = U64_Lsw( sm_entry->fdd_pba ) ) == 0L ||
+ sm_entry->tape_cat_ver > TAPE_CATALOG_VER ||
+ cur_env->max_otc_level != TCL_FULL ) {
+
+ gvcb_data.set_cat_info_valid = FALSE ;
+ gvcb_data.on_tape_cat_level = TCL_PARTIAL ;
+ } else {
+ gvcb_data.set_cat_info_valid = TRUE ;
+ gvcb_data.on_tape_cat_level = TCL_FULL ;
+ }
+ gvcb_data.on_tape_cat_ver = sm_entry->tape_cat_ver ;
+
+ gvcb_data.tf_major_ver = (CHAR)cur_env->tape_hdr.tf_major_ver ;
+ gvcb_data.tf_minor_ver = (CHAR)sm_entry->tf_minor_ver ;
+ gvcb_data.tape_id = cur_env->tape_hdr.tape_id_number ;
+ gvcb_data.tape_seq_num = sm_entry->seq_num ;
+ gvcb_data.bset_num = sm_entry->set_num ;
+
+ gvcb_data.password_encrypt_alg = sm_entry->pswd_encr_algor ;
+
+ if( cur_env->util_buff == NULL ) {
+ if( ( cur_env->util_buff = calloc( F40_INIT_UTIL_BUFF_SIZE, 1 ) ) == NULL ) {
+ OTC_Close( cur_env, OTC_CLOSE_SM, TRUE ) ;
+ return( TFLE_NO_MEMORY ) ;
+ }
+ cur_env->util_buff_size = F40_INIT_UTIL_BUFF_SIZE ;
+ }
+
+ dest_ptr = cur_env->util_buff ;
+
+ gvcb_data.tape_password = (CHAR_PTR)cur_env->tape_password ;
+ gvcb_data.tape_password_size = cur_env->tape_password_size ;
+
+ gvcb_data.bset_password = (CHAR_PTR)( (INT8_PTR)sm_entry + sm_entry->password.data_offset ) ;
+ gvcb_data.bset_password_size = sm_entry->password.data_size ;
+
+ gvcb_data.short_m_name = NULL ;
+ gvcb_data.short_m_name_size = 0 ;
+
+ gvcb_data.set_cat_num_dirs = (UINT16)sm_entry->num_dirs ;
+ gvcb_data.set_cat_num_files = (UINT16)sm_entry->num_files ;
+ gvcb_data.set_cat_num_corrupt = (UINT16)sm_entry->num_corrupt_files ;
+
+
+ /* Tape Name */
+ gvcb_data.tape_name = (CHAR_PTR)dest_ptr ;
+ if( cur_env->tape_name_size != 0 ) {
+ gvcb_data.tape_name_size =
+ F40_CopyAndTerminate( &dest_ptr, cur_env->tape_name,
+ cur_env->tape_name_size,
+ cur_env->tape_hdr.block_header.string_type,
+ sm_entry->string_type ) ;
+ } else {
+ gvcb_data.tape_name_size = 0 ;
+ }
+
+ /* If this is an "old" tape the strings below are NULL terminated.
+ If it's a "new" tape, we have to copy the string to another data
+ area and NULL terminate them before passing them to the UI.
+ Note that the tape name is NEVER NULL terminated because we have to
+ strip it off before we store it to maintain consistancy.
+ */
+ if( sm_entry->tape_cat_ver == 1 ) {
+ /* This is an old tape with NULL terminated strings. */
+
+ gvcb_data.bset_name = (CHAR_PTR)( (INT8_PTR)sm_entry + sm_entry->set_name.data_offset ) ;
+ gvcb_data.bset_name_size = sm_entry->set_name.data_size ;
+ gvcb_data.bset_descript = (CHAR_PTR)( (INT8_PTR)sm_entry + sm_entry->set_descr.data_offset ) ;
+ gvcb_data.bset_descript_size = sm_entry->set_descr.data_size ;
+ gvcb_data.user_name = (CHAR_PTR)( (INT8_PTR)sm_entry + sm_entry->user_name.data_offset ) ;
+ gvcb_data.user_name_size = sm_entry->user_name.data_size ;
+ gvcb_data.device_name = NULL ;
+ gvcb_data.dev_name_size = 0 ;
+ gvcb_data.volume_name = (CHAR_PTR)( (INT8_PTR)fdd_hdr + fdd_vol_v1->vol_name.data_offset ) ;
+ gvcb_data.volume_name_size = fdd_vol_v1->vol_name.data_size ;
+ gvcb_data.machine_name = (CHAR_PTR)( (INT8_PTR)fdd_hdr + fdd_vol_v1->machine_name.data_offset ) ;
+ gvcb_data.machine_name_size = fdd_vol_v1->machine_name.data_size ;
+
+ } else {
+ /* This is a new tape, copy the strings into a buffer and NULL
+ terminate them.
+ */
+
+ src_ptr = (UINT8_PTR)sm_entry ;
+
+ /* Backup Set Name */
+ gvcb_data.bset_name = (CHAR_PTR)dest_ptr ;
+ if( sm_entry->set_name.data_size != 0 ) {
+ gvcb_data.bset_name_size =
+ F40_CopyAndTerminate( &dest_ptr, src_ptr +
+ sm_entry->set_name.data_offset,
+ sm_entry->set_name.data_size,
+ sm_entry->string_type,
+ sm_entry->string_type ) ;
+ } else {
+ gvcb_data.bset_name_size = 0 ;
+ }
+
+ /* Backup Set Description */
+ gvcb_data.bset_descript = (CHAR_PTR)dest_ptr ;
+ if( sm_entry->set_descr.data_size != 0 ) {
+ gvcb_data.bset_descript_size =
+ F40_CopyAndTerminate( &dest_ptr, src_ptr +
+ sm_entry->set_descr.data_offset,
+ sm_entry->set_descr.data_size,
+ sm_entry->string_type,
+ sm_entry->string_type ) ;
+ } else {
+ gvcb_data.bset_descript_size = 0 ;
+ }
+
+ /* User Name */
+ gvcb_data.user_name = (CHAR_PTR)dest_ptr ;
+ if( sm_entry->user_name.data_size != 0 ) {
+ gvcb_data.user_name_size =
+ F40_CopyAndTerminate( &dest_ptr, src_ptr +
+ sm_entry->user_name.data_offset,
+ sm_entry->user_name.data_size,
+ sm_entry->string_type,
+ sm_entry->string_type ) ;
+ } else {
+ gvcb_data.user_name_size = 0 ;
+ }
+
+ src_ptr = (UINT8_PTR)fdd_hdr ;
+
+ /* Device Name */
+ gvcb_data.device_name = (CHAR_PTR)dest_ptr ;
+ if( fdd_vol_v2->device_name.data_size != 0 ) {
+ gvcb_data.dev_name_size =
+ F40_CopyAndTerminate( &dest_ptr, src_ptr +
+ fdd_vol_v2->device_name.data_offset,
+ fdd_vol_v2->device_name.data_size,
+ fdd_hdr->string_type,
+ fdd_hdr->string_type ) ;
+ } else {
+ gvcb_data.dev_name_size = 0 ;
+ }
+
+ /* Volume Name */
+ gvcb_data.volume_name = (CHAR_PTR)dest_ptr ;
+ if( fdd_vol_v2->vol_name.data_size != 0 ) {
+ gvcb_data.volume_name_size =
+ F40_CopyAndTerminate( &dest_ptr, src_ptr +
+ fdd_vol_v2->vol_name.data_offset,
+ fdd_vol_v2->vol_name.data_size,
+ fdd_hdr->string_type,
+ fdd_hdr->string_type ) ;
+ } else {
+ gvcb_data.volume_name_size = 0 ;
+ }
+
+ /* Machine Name */
+ gvcb_data.machine_name = (CHAR_PTR)dest_ptr ;
+ if( fdd_vol_v2->machine_name.data_size != 0 ) {
+ gvcb_data.machine_name_size =
+ F40_CopyAndTerminate( &dest_ptr, src_ptr +
+ fdd_vol_v2->machine_name.data_offset,
+ fdd_vol_v2->machine_name.data_size,
+ fdd_hdr->string_type,
+ fdd_hdr->string_type ) ;
+ } else {
+ gvcb_data.machine_name_size = 0 ;
+ }
+
+ /* Other than in the NLM where they already fixed this, the
+ UI expects to see a volume name of the form
+ "<device name><space><volume name>", and NO DEVICE NAME.
+ We do this by pointing the volume name at the device name,
+ and replacing the NULL terminator on the device name with
+ a space.
+ */
+
+#if !defined( OS_NLM )
+
+ if( gvcb_data.dev_name_size != 0 ) {
+ gvcb_data.volume_name = gvcb_data.device_name ;
+ gvcb_data.volume_name_size += gvcb_data.dev_name_size ;
+ if( gvcb_data.volume_name_size != gvcb_data.dev_name_size ) {
+ dest_ptr = (UINT8_PTR)gvcb_data.volume_name ;
+ if( fdd_hdr->string_type == BEC_ANSI_STR ) {
+ dest_ptr += gvcb_data.dev_name_size - 1 ;
+ *((ACHAR *)dest_ptr) = (ACHAR)' ' ;
+ } else {
+ dest_ptr += gvcb_data.dev_name_size - 2 ;
+ *((WCHAR *)dest_ptr) = (WCHAR)' ' ;
+ }
+ }
+ gvcb_data.dev_name_size = 0 ;
+ }
+
+#endif
+
+ } // end of else these are new tapes
+
+ temp_date = sm_entry->backup_date ;
+ TapeDateToDate( &backup_date, &temp_date ) ;
+ gvcb_data.date = &backup_date ;
+
+ gvcb_data.pba = U64_Lsw( sm_entry->sset_pba ) ;
+
+ /* Tell the file system to do its thing. It returns a data filter
+ which we have no use for.
+ */
+ (void) FS_CreateGenVCB( channel->cur_fsys, &gvcb_data ) ;
+
+ return( TFLE_NO_ERR ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_RdDIR
+
+ Description:
+
+ Returns: INT16 - TFLE_xxx error code
+
+ Notes:
+
+**/
+INT16 OTC_RdDIR(
+ CHANNEL_PTR channel )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ GEN_DDB_DATA gddb_data ;
+ STD_DBLK_DATA_PTR std_data = &gddb_data.std_data ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ UNALIGNED MTF_FDD_HDR_PTR fdd_hdr ;
+ UNALIGNED MTF_FDD_DIR_V1_PTR fdd_dir_v1 ;
+ UNALIGNED MTF_FDD_DIR_V2_PTR fdd_dir_v2 ;
+ UNALIGNED F40_FDD_DBDB_PTR fdd_dbdb ;
+ DATE_TIME create_date ;
+ DATE_TIME last_mod_date ;
+ DATE_TIME backup_date ;
+ DATE_TIME last_access_date ;
+ DATE_TIME dummy_date ;
+ MTF_DATE_TIME temp_date ;
+
+ /* Note: We know we have at least the FDD header, or the block type
+ determiner would have gotten us a new buffer.
+ */
+ fdd_hdr = (UNALIGNED MTF_FDD_HDR_PTR)cur_env->otc_buff_ptr ;
+ if( cur_env->otc_buff_remaining < fdd_hdr->length ) {
+ if( ( ret_val = OTC_ReadABuff( cur_env, fdd_hdr->length ) ) != TFLE_NO_ERR ) {
+ return( ret_val ) ;
+ }
+ fdd_hdr = (UNALIGNED MTF_FDD_HDR_PTR)cur_env->otc_buff_ptr ;
+ }
+
+ cur_env->otc_buff_ptr += fdd_hdr->length ;
+ cur_env->otc_buff_remaining -= fdd_hdr->length ;
+
+ /* Initialize the file systems interface structure */
+ FS_SetDefaultDBLK( channel->cur_fsys, BT_DDB, (CREATE_DBLK_PTR)&gddb_data ) ;
+
+ std_data->dblk = channel->cur_dblk ;
+ std_data->tape_seq_num = fdd_hdr->seq_num ;
+ std_data->continue_obj = (BOOLEAN)( fdd_hdr->blk_attribs & MTF_DB_CONT_BIT ) ;
+ std_data->compressed_obj = (BOOLEAN)( fdd_hdr->blk_attribs & MTF_DB_COMPRESS_BIT ) ;
+ std_data->os_id = (UINT8)fdd_hdr->os_id ;
+ std_data->os_ver = (UINT8)fdd_hdr->os_ver ;
+ std_data->os_info = NULL ;
+ std_data->os_info_size = 0 ;
+ std_data->lba = U64_Lsw( fdd_hdr->lba ) ;
+ std_data->disp_size = fdd_hdr->disp_size ;
+ std_data->string_type = fdd_hdr->string_type ;
+
+ if( memcmp( fdd_hdr->type, "DBDB", 4 ) == 0 ) {
+ /* This is a Database DBLK, but the boys upstairs don't want to
+ know about such silly things! So we lie and call it a DDB to
+ get it passed on to the File System. The File System can tell
+ what it really is too, and will deal with it appropriatly.
+ */
+ fdd_dbdb = (UNALIGNED F40_FDD_DBDB_PTR)(void *)( fdd_hdr + 1 ) ;
+
+ std_data->attrib = fdd_dbdb->database_attribs ;
+
+ /* Clear all vendor specific bits */
+ std_data->attrib &= 0x00FFFFFF ;
+
+ /* Set our vendor specific bit that says this is a DBDB */
+ std_data->attrib |= DIR_IS_REALLY_DB ;
+
+ gddb_data.path_name = (CHAR_PTR)( (INT8_PTR)fdd_hdr + fdd_dbdb->database_name.data_offset ) ;
+ gddb_data.path_size = fdd_dbdb->database_name.data_size ;
+
+ TapeDateToDate( &backup_date, &fdd_dbdb->backup_date ) ;
+ gddb_data.backup_date = &backup_date ;
+
+ /* DBDBs don't have the following date fields */
+ memset( &dummy_date, 0, sizeof( dummy_date ) ) ;
+ gddb_data.creat_date = &dummy_date ;
+ gddb_data.mod_date = &dummy_date ;
+ gddb_data.access_date = &dummy_date ;
+
+ } else {
+
+ /* Standard DDB structure stuffing */
+
+ if( cur_env->otc_ver == 1 ) {
+ fdd_dir_v1 = (UNALIGNED MTF_FDD_DIR_V1_PTR)(void *)( fdd_hdr + 1 ) ;
+ } else {
+ fdd_dir_v2 = (UNALIGNED MTF_FDD_DIR_V2_PTR)(void *)( fdd_hdr + 1 ) ;
+ }
+
+ /* Set the DIR attributes. Note that if this is an "old" tape,
+ the attibute bits were being set wrong, and need to be translated.
+ */
+ if( cur_env->otc_ver == 1 ) {
+
+ std_data->attrib = fdd_dir_v1->dir_attribs &
+ ~( OLD_DIR_EMPTY_BIT | OLD_DIR_PATH_IN_STREAM_BIT ) ;
+
+ std_data->attrib |= ( fdd_dir_v1->dir_attribs & OLD_DIR_EMPTY_BIT )
+ ? DIR_EMPTY_BIT : 0 ;
+ std_data->attrib |= ( fdd_dir_v1->dir_attribs & OLD_DIR_PATH_IN_STREAM_BIT )
+ ? DIR_PATH_IN_STREAM_BIT : 0 ;
+ } else {
+ std_data->attrib = fdd_dir_v2->dir_attribs ;
+ }
+
+ if( cur_env->otc_ver == 1 ) {
+ gddb_data.path_name = (CHAR_PTR)( (INT8_PTR)fdd_hdr + fdd_dir_v1->dir_name.data_offset ) ;
+ gddb_data.path_size = fdd_dir_v1->dir_name.data_size ;
+
+ temp_date = fdd_dir_v1->create_date ;
+ TapeDateToDate( &create_date, &temp_date ) ;
+ temp_date = fdd_dir_v1->last_mod_date ;
+ TapeDateToDate( &last_mod_date, &temp_date ) ;
+ temp_date = fdd_dir_v1->backup_date ;
+ TapeDateToDate( &backup_date, &temp_date ) ;
+ temp_date = fdd_dir_v1->last_access_date ;
+ TapeDateToDate( &last_access_date, &temp_date ) ;
+ } else {
+ gddb_data.path_name = (CHAR_PTR)( (INT8_PTR)fdd_hdr + fdd_dir_v2->dir_name.data_offset ) ;
+ gddb_data.path_size = fdd_dir_v2->dir_name.data_size ;
+
+ temp_date = fdd_dir_v2->create_date ;
+ TapeDateToDate( &create_date, &temp_date ) ;
+ temp_date = fdd_dir_v2->last_mod_date ;
+ TapeDateToDate( &last_mod_date, &temp_date ) ;
+ temp_date = fdd_dir_v2->backup_date ;
+ TapeDateToDate( &backup_date, &temp_date ) ;
+ temp_date = fdd_dir_v2->last_access_date ;
+ TapeDateToDate( &last_access_date, &temp_date ) ;
+ }
+ gddb_data.creat_date = &create_date ;
+ gddb_data.mod_date = &last_mod_date ;
+ gddb_data.backup_date = &backup_date ;
+ gddb_data.access_date = &last_access_date ;
+ }
+
+ /* Tell the file system to do its thing. It returns a data filter
+ which we have no use for.
+ */
+ (void) FS_CreateGenDDB( channel->cur_fsys, &gddb_data ) ;
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_RdFILE
+
+ Description:
+
+ Returns: INT16 - TFLE_xxx error code
+
+ Notes:
+
+**/
+INT16 OTC_RdFILE(
+ CHANNEL_PTR channel )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ GEN_FDB_DATA gfdb_data ; /* FDB create structure */
+ STD_DBLK_DATA_PTR std_data = &gfdb_data.std_data ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ UNALIGNED MTF_FDD_HDR_PTR fdd_hdr ;
+ UNALIGNED MTF_FDD_FILE_V1_PTR fdd_file_v1 ;
+ UNALIGNED MTF_FDD_FILE_V2_PTR fdd_file_v2 ;
+ DATE_TIME create_date ;
+ DATE_TIME last_mod_date ;
+ DATE_TIME backup_date ;
+ DATE_TIME last_access_date ;
+ MTF_DATE_TIME temp_date ;
+ UINT8_PTR buff_ptr ;
+
+ /* Note: We know we have at least the FDD header, or the block type
+ determiner would have gotten us a new buffer.
+ */
+ fdd_hdr = (UNALIGNED MTF_FDD_HDR_PTR)cur_env->otc_buff_ptr ;
+ if( cur_env->otc_buff_remaining < fdd_hdr->length ) {
+ if( ( ret_val = OTC_ReadABuff( cur_env, fdd_hdr->length ) ) != TFLE_NO_ERR ) {
+ return( ret_val ) ;
+ }
+ fdd_hdr = (UNALIGNED MTF_FDD_HDR_PTR)cur_env->otc_buff_ptr ;
+ }
+ if( cur_env->otc_ver == 1 ) {
+ fdd_file_v1 = (UNALIGNED MTF_FDD_FILE_V1_PTR)(void *)( fdd_hdr + 1 ) ;
+ } else {
+ fdd_file_v2 = (UNALIGNED MTF_FDD_FILE_V2_PTR)(void *)( fdd_hdr + 1 ) ;
+ }
+ cur_env->otc_buff_ptr += fdd_hdr->length ;
+ cur_env->otc_buff_remaining -= fdd_hdr->length ;
+
+ /* Initialize the file systems interface structure */
+ FS_SetDefaultDBLK( channel->cur_fsys, BT_DDB, (CREATE_DBLK_PTR)&gfdb_data ) ;
+
+ std_data->dblk = channel->cur_dblk ;
+ std_data->tape_seq_num = fdd_hdr->seq_num ;
+ std_data->continue_obj = (BOOLEAN)( fdd_hdr->blk_attribs & MTF_DB_CONT_BIT ) ;
+ std_data->compressed_obj = (BOOLEAN)( fdd_hdr->blk_attribs & MTF_DB_COMPRESS_BIT ) ;
+ std_data->os_id = (UINT8)fdd_hdr->os_id ;
+ std_data->os_ver = (UINT8)fdd_hdr->os_ver ;
+ std_data->os_info = NULL ;
+ std_data->os_info_size = 0 ;
+ std_data->lba = U64_Lsw( fdd_hdr->lba ) ;
+ std_data->disp_size = fdd_hdr->disp_size ;
+ std_data->string_type = fdd_hdr->string_type ;
+
+ /* Set the FILE attributes. Note that if this is an "old" tape,
+ the attibute bits were being set wrong, and need to be translated.
+ */
+ if( cur_env->otc_ver == 1 ) { // if old tape
+
+ std_data->attrib = fdd_file_v1->file_attribs &
+ ~( OLD_FILE_IN_USE_BIT | OLD_FILE_NAME_IN_STREAM_BIT |
+ OLD_OBJ_CORRUPT_BIT ) ;
+
+ std_data->attrib |= ( fdd_file_v1->file_attribs & OLD_FILE_IN_USE_BIT )
+ ? FILE_IN_USE_BIT : 0 ;
+ std_data->attrib |= ( fdd_file_v1->file_attribs & OLD_FILE_NAME_IN_STREAM_BIT )
+ ? FILE_NAME_IN_STREAM_BIT : 0 ;
+ std_data->attrib |= ( fdd_file_v1->file_attribs & OLD_OBJ_CORRUPT_BIT )
+ ? OBJ_CORRUPT_BIT : 0 ;
+ } else {
+ std_data->attrib = fdd_file_v2->file_attribs ;
+ }
+
+ if( cur_env->otc_ver == 1 ) {
+ temp_date = fdd_file_v1->create_date ;
+ TapeDateToDate( &create_date, &temp_date ) ;
+ temp_date = fdd_file_v1->last_mod_date ;
+ TapeDateToDate( &last_mod_date, &temp_date ) ;
+ temp_date = fdd_file_v1->backup_date ;
+ TapeDateToDate( &backup_date, &temp_date ) ;
+ temp_date = fdd_file_v1->last_access_date ;
+ TapeDateToDate( &last_access_date, &temp_date ) ;
+ } else {
+ temp_date = fdd_file_v2->create_date ;
+ TapeDateToDate( &create_date, &temp_date ) ;
+ temp_date = fdd_file_v2->last_mod_date ;
+ TapeDateToDate( &last_mod_date, &temp_date ) ;
+ temp_date = fdd_file_v2->backup_date ;
+ TapeDateToDate( &backup_date, &temp_date ) ;
+ temp_date = fdd_file_v2->last_access_date ;
+ TapeDateToDate( &last_access_date, &temp_date ) ;
+ }
+
+ /* If this is an "old" tape the file name is NULL terminated. If it's
+ a "new" tape, we have to copy the string to another data area and
+ NULL terminate it before passing it to the UI.
+ */
+ if( cur_env->otc_ver == 1 ) {
+ /* This is an old tape with NULL terminated strings. */
+
+ gfdb_data.fname = (CHAR_PTR)( (INT8_PTR)fdd_hdr + fdd_file_v1->file_name.data_offset ) ;
+ gfdb_data.fname_size = fdd_file_v1->file_name.data_size ;
+
+ } else {
+ /* This is a new tape, copy the file name into a buffer and NULL
+ terminate it.
+ */
+
+ if( cur_env->util_buff == NULL ) {
+ if( ( cur_env->util_buff = calloc( F40_INIT_UTIL_BUFF_SIZE, 1 ) ) == NULL ) {
+ return( TFLE_NO_MEMORY ) ;
+ }
+ cur_env->util_buff_size = F40_INIT_UTIL_BUFF_SIZE ;
+ }
+
+ buff_ptr = cur_env->util_buff ;
+
+ gfdb_data.fname = (CHAR_PTR)buff_ptr ;
+ if( fdd_file_v2->file_name.data_size != 0 ) {
+ gfdb_data.fname_size =
+ F40_CopyAndTerminate( &buff_ptr, (UINT8_PTR)fdd_hdr +
+ fdd_file_v2->file_name.data_offset,
+ fdd_file_v2->file_name.data_size,
+ fdd_hdr->string_type,
+ fdd_hdr->string_type ) ;
+ } else {
+ gfdb_data.fname_size = 0 ;
+ }
+ }
+
+ gfdb_data.creat_date = &create_date ;
+ gfdb_data.mod_date = &last_mod_date ;
+ gfdb_data.backup_date = &backup_date ;
+ gfdb_data.access_date = &last_access_date ;
+
+ /* Tell the file system to do its thing. It returns a data filter
+ which we have no use for.
+ */
+ (void) FS_CreateGenFDB( channel->cur_fsys, &gfdb_data ) ;
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_ReadABuff
+
+ Description:
+
+ Returns: INT16 - TFLE_xxx error code
+
+ Notes:
+
+**/
+INT16 OTC_ReadABuff(
+ F40_ENV_PTR cur_env,
+ UINT16 length )
+{
+ UINT8_PTR tmp_buff ;
+ FILE * fptr = cur_env->otc_fdd_fptr ;
+ size_t size ;
+ size_t size_got ;
+
+ if( cur_env->otc_buff_size < length ) {
+ while( cur_env->otc_buff_size < length ) {
+ cur_env->otc_buff_size += F40_OTC_BUFF_INC ;
+ }
+ if( ( tmp_buff = calloc( cur_env->otc_buff_size, 1 ) ) == NULL ) {
+ return( TFLE_NO_MEMORY ) ;
+ }
+ if( cur_env->otc_buff_remaining != 0 ) {
+ memmove( tmp_buff, cur_env->otc_buff_ptr, cur_env->otc_buff_remaining ) ;
+ }
+ free( cur_env->otc_buff ) ;
+ cur_env->otc_buff = tmp_buff ;
+ } else {
+ if( cur_env->otc_buff_remaining != 0 ) {
+ memmove( cur_env->otc_buff, cur_env->otc_buff_ptr, cur_env->otc_buff_remaining ) ;
+ }
+ }
+
+ cur_env->otc_buff_ptr = cur_env->otc_buff + cur_env->otc_buff_remaining ;
+ size = cur_env->otc_buff_size - cur_env->otc_buff_remaining ;
+
+ if( ( size_got = fread( cur_env->otc_buff_ptr, 1, size, fptr ) ) != size ) {
+ if( ferror( fptr ) || !feof( fptr ) ) {
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ }
+
+ cur_env->otc_buff_ptr = cur_env->otc_buff ;
+ cur_env->otc_buff_remaining += (UINT16)size_got ;
+ return( TFLE_NO_ERR ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_GetFDDType
+
+ Description: This function determines the type of the next FDD entry
+ in the buffer.
+
+ Returns: INT16 - TFLE_xxx
+
+ Notes:
+
+**/
+INT16 OTC_GetFDDType(
+ CHANNEL_PTR channel,
+ UINT16_PTR blk_type )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ UNALIGNED MTF_FDD_HDR_PTR fdd_hdr ;
+
+ if( cur_env->otc_buff_remaining < sizeof( MTF_FDD_HDR ) ) {
+ if( ( ret_val = OTC_ReadABuff( cur_env, sizeof( MTF_FDD_HDR ) ) ) != TFLE_NO_ERR ) {
+ return( ret_val ) ;
+ }
+ }
+ fdd_hdr = (UNALIGNED MTF_FDD_HDR_PTR)cur_env->otc_buff_ptr ;
+
+ /* DO NOT UNICODEIZE THE FOLLOWING CONSTANTS!!! */
+
+ if( memcmp( fdd_hdr->type, "VOLB", 4 ) == 0 ) {
+ *blk_type = FDD_VOL_BLK ;
+
+ } else if( memcmp( fdd_hdr->type, "DIRB", 4 ) == 0 ||
+ memcmp( fdd_hdr->type, "DBDB", 4 ) == 0 ) {
+ *blk_type = FDD_DIR_BLK ;
+
+ } else if( memcmp( fdd_hdr->type, "FILE", 4 ) == 0 ) {
+ *blk_type = FDD_FILE_BLK ;
+
+ } else if( memcmp( fdd_hdr->type, "FEND", 4 ) == 0 ) {
+ *blk_type = FDD_END_BLK ;
+ } else {
+ *blk_type = FDD_UNKNOWN_BLK ;
+ msassert( FALSE ) ;
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_SkipFDDEntry
+
+ Description:
+
+ Returns: INT16 - TFLE_xxx error code
+
+ Notes:
+
+**/
+INT16 OTC_SkipFDDEntry(
+ CHANNEL_PTR channel )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ UNALIGNED MTF_FDD_HDR_PTR fdd_hdr ;
+ INT16 ret_val = TFLE_NO_ERR ;
+
+ /* Note: We know we have at least the FDD header, or the block type
+ determiner would have gotten us a new buffer.
+ */
+ fdd_hdr = (UNALIGNED MTF_FDD_HDR_PTR)cur_env->otc_buff_ptr ;
+ if( cur_env->otc_buff_remaining < fdd_hdr->length ) {
+ if( ( ret_val = OTC_ReadABuff( cur_env, fdd_hdr->length ) ) != TFLE_NO_ERR ) {
+ return( ret_val ) ;
+ }
+ fdd_hdr = (UNALIGNED MTF_FDD_HDR_PTR)cur_env->otc_buff_ptr ;
+ }
+ cur_env->otc_buff_ptr += fdd_hdr->length ;
+ cur_env->otc_buff_remaining -= fdd_hdr->length ;
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_SkipFDDContEntries
+
+ Description: Skip past any FDD entries which have the continuation
+ bit set, unit you encounter one that doesn't.
+
+ Returns: INT16 - TFLE_xxx error code
+
+ Notes: Since the attrib field in the FEND entry is undefined,
+ it may have garbage in it! We do a special check to
+ make sure we don't accidently skip past it.
+
+**/
+INT16 OTC_SkipFDDContEntries(
+ CHANNEL_PTR channel )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)( channel->fmt_env ) ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ UNALIGNED MTF_FDD_HDR_PTR fdd_hdr ;
+
+ while( 1 ) {
+ if( cur_env->otc_buff_remaining < sizeof( MTF_FDD_HDR ) ) {
+ if( ( ret_val = OTC_ReadABuff( cur_env, sizeof( MTF_FDD_HDR ) ) ) != TFLE_NO_ERR ) {
+ return( ret_val ) ;
+ }
+ }
+ fdd_hdr = (UNALIGNED MTF_FDD_HDR_PTR)cur_env->otc_buff_ptr ;
+
+ /* DO NOT UNICODEIZE THE FOLLOWING CONSTANT!!! */
+
+ if( ( fdd_hdr->blk_attribs & MTF_DB_CONT_BIT ) &&
+ memcmp( fdd_hdr->type, "FEND", 4 ) != 0 ) {
+
+ if( ( ret_val = OTC_SkipFDDEntry( channel ) ) != TFLE_NO_ERR ) {
+ return( ret_val ) ;
+ }
+ } else {
+ return( TFLE_NO_ERR ) ;
+ }
+ }
+}
+
diff --git a/private/utils/ntbackup/src/otc40wt.c b/private/utils/ntbackup/src/otc40wt.c
new file mode 100644
index 000000000..ec7c623ba
--- /dev/null
+++ b/private/utils/ntbackup/src/otc40wt.c
@@ -0,0 +1,1793 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-92
+
+
+ Name: otc40wt.c
+
+ Description: Contains the Code for writing On Tape Catalogs.
+
+
+ $Log: T:/LOGFILES/OTC40WT.C_V $
+
+ Rev 1.30.2.1 11 Jan 1995 21:01:18 GREGG
+Added size of FDD header to calculation of FDD end entry size.
+
+ Rev 1.30.2.0 08 Jan 1995 21:49:00 GREGG
+Added database DBLK.
+
+ Rev 1.30 01 Dec 1993 15:51:40 GREGG
+Fixed unicode bug in OTC_SetDirLinks.
+
+ Rev 1.29 14 Oct 1993 18:17:04 GREGG
+Call home grown mktemp.
+
+ Rev 1.28 15 Sep 1993 21:37:40 GREGG
+Use mktemp to generate the temp OTC file names to gaurentee unique names.
+
+ Rev 1.27 09 Jun 1993 03:55:08 GREGG
+In EOS at EOM case in OTC_PostprocessEOM, don't process FDD.
+
+ Rev 1.26 08 Jun 1993 00:02:36 GREGG
+Fix for bug in the way we were handling EOM and continuation OTC entries.
+Files modified for fix: mtf10wt.c, otc40wt.c, otc40msc.c f40proto.h mayn40.h
+
+ Rev 1.25 17 May 1993 21:13:36 ZEIR
+GenSMHeader pad bytes are now clean 0's
+
+ Rev 1.24 25 Apr 1993 17:36:06 GREGG
+Fourth in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Parse the device name and volume name out of the FS supplied "volume
+ name", and write it to tape as separate fields.
+ - Generate the "volume name" the FS and UI expect out of the device
+ name and volume name on tape.
+ - Write all strings without NULL terminater, and translate them back
+ to NULL terminated strings on the read side.
+
+Matches: MTF10WDB.C 1.8, F40PROTO.H 1.26, OTC40WT.C 1.24, MAYN40.H 1.33,
+ MAYN40RD.C 1.57, OTC40RD.C 1.25
+
+ Rev 1.23 19 Apr 1993 18:00:32 GREGG
+Second in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ Changes to write version 2 of OTC, and to read both versions.
+
+Matches: mayn40rd.c 1.55, otc40msc.c 1.19, otc40rd.c 1.23, otc40wt.c 1.23,
+ makevcb.c 1.15, fsys.h 1.32, fsys_str.h 1.46, tpos.h 1.16,
+ mayn40.h 1.32, mtf.h 1.3.
+
+NOTE: There are additional changes to the catalogs needed to save the OTC
+ version and put it in the tpos structure before loading the OTC
+ File/Directory Detail. These changes are NOT listed above!
+
+ Rev 1.22 19 Mar 1993 17:14:36 GREGG
+Bobo head (that's me) was reallocing less than was initially alloced!!!
+
+ Rev 1.21 03 Mar 1993 17:26:54 GREGG
+Fixed realloc calls to eliminate possible memory loss.
+
+ Rev 1.20 28 Jan 1993 12:28:56 GREGG
+Fixed warnings.
+
+ Rev 1.19 05 Jan 1993 17:21:48 GREGG
+Fix for initial DIRB not being root.
+
+ Rev 1.18 07 Dec 1992 10:06:46 GREGG
+Changes for tf ver moved to SSET, otc ver added to SSET and links added to FDD.
+
+ Rev 1.17 24 Nov 1992 18:16:16 GREGG
+Updates to match MTF document.
+
+ Rev 1.16 23 Nov 1992 10:03:48 GREGG
+Changes for path in stream.
+
+ Rev 1.15 17 Nov 1992 14:12:36 GREGG
+Added string_type.
+
+ Rev 1.14 09 Nov 1992 11:01:06 GREGG
+Changed references to tape catalog levels for new defines.
+
+ Rev 1.13 22 Oct 1992 10:42:48 HUNTER
+Changes for Stream Headers
+
+ Rev 1.12 31 Aug 1992 19:10:16 GREGG
+Added fflush calls to insure all data gets to disk and fclose doesn't fail.
+
+ Rev 1.11 30 Jul 1992 16:23:26 GREGG
+A lot of the functions previosly in this module were moved to otc40msc.c.
+Some changes were made to the functions which remained to deal with the
+addition of Stream Headers and to fix some EOM bugs.
+
+ Rev 1.10 27 Jul 1992 12:48:34 GREGG
+Fixed more warnings...
+
+ Rev 1.9 17 Jun 1992 15:55:50 GREGG
+Fixed loop transfering OTC from tape to disk.
+
+ Rev 1.8 12 Jun 1992 14:15:04 GREGG
+Call GetBlkType instead of DetBlkType in OTC_GetPrevSM.
+
+ Rev 1.7 09 Jun 1992 15:50:54 GREGG
+Removed setting of filemark_count.
+
+ Rev 1.6 29 May 1992 15:05:48 GREGG
+Added setting of last access date.
+
+ Rev 1.5 20 May 1992 20:21:46 GREGG
+Replaced reference of FILE_CORRUPT_BIT with OBJ_CORRUPT_BIT.
+
+ Rev 1.4 20 May 1992 20:04:28 GREGG
+Bug fixes and code review changes.
+
+ Rev 1.3 11 May 1992 13:35:40 GREGG
+More changes for EOM handling. NOTE: THIS IS NOT A STABLE REVISION!!!
+
+ Rev 1.2 05 May 1992 11:25:50 GREGG
+Folded 'local_tape' global into environment.
+
+ Rev 1.1 29 Apr 1992 12:57:28 GREGG
+ A variety of changes for a variety of reasons (still early in development).
+
+ Rev 1.0 09 Apr 1992 11:14:56 GREGG
+Initial revision.
+
+**/
+
+#include <stdio.h>
+#include <io.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+
+#include "stdtypes.h"
+#include "channel.h"
+#include "mayn40.h"
+#include "f40proto.h"
+#include "lw_data.h"
+#include "tfl_err.h"
+#include "lwprotos.h"
+#include "minmax.h"
+#include "msmktemp.h"
+
+/* Device Driver InterFace Headers */
+#include "retbuf.h"
+#include "drvinf.h"
+#include "generr.h"
+#include "genfuncs.h"
+#include "dil.h"
+#include "dddefs.h"
+
+/* Local Function Prototypes */
+static VOID _near OTC_SetFDDHeaderFields( MTF_FDD_HDR_PTR fdd_hdr,
+ MTF_DB_HDR_PTR db_hdr, INT16 seq_num ) ;
+static INT _near OTC_ReverseLinks( F40_ENV_PTR cur_env ) ;
+static INT _near OTC_SetLink( FILE * fptr, long curr_link, long next_link,
+ long * prev_link ) ;
+static INT16 _near OTC_SetDirLink( F40_ENV_PTR cur_env,
+ MTF_FDD_HDR_PTR fdd_hdr,
+ UINT8_PTR str_ptr, UINT16 size ) ;
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_GenSMHeader
+
+ Description: Called when starting a new tape family, this function
+ writes a new Set Map header to the temporary SM file.
+
+ Returns: INT16 - TFLE_xxx
+
+ Notes:
+
+**/
+INT16 OTC_GenSMHeader(
+ CHANNEL_PTR channel )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)(channel->fmt_env) ;
+ MTF_SM_HDR sm_hdr ;
+
+ sm_hdr.num_set_recs = 0 ;
+ sm_hdr.family_id = channel->tape_id ;
+ sm_hdr.pad[0] = sm_hdr.pad[1] = 0 ; /* kill random tape litter */
+ if( fwrite( &sm_hdr, sizeof( MTF_SM_HDR ), 1, cur_env->otc_sm_fptr ) != 1 ) {
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ return( TFLE_NO_ERR ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_SetFDDHeaderFields
+
+ Description: Generates an OTC volume entry and writes it to the SM
+ and FDD temporary files.
+
+ Returns: Nothing
+
+ Notes:
+
+**/
+static VOID _near OTC_SetFDDHeaderFields(
+ MTF_FDD_HDR_PTR fdd_hdr,
+ MTF_DB_HDR_PTR db_hdr,
+ INT16 seq_num )
+{
+ fdd_hdr->seq_num = seq_num ;
+ fdd_hdr->blk_attribs = db_hdr->block_attribs ;
+ fdd_hdr->lba = db_hdr->logical_block_address ;
+ fdd_hdr->disp_size = db_hdr->displayable_size ;
+ fdd_hdr->os_id = db_hdr->machine_os_id ;
+ fdd_hdr->os_ver = db_hdr->machine_os_version ;
+ fdd_hdr->string_type = db_hdr->string_type ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_GenVolEntry
+
+ Description: Generates an OTC volume entry and writes it to the SM
+ and FDD temporary files.
+
+ Returns: INT16 - TFLE_xxx
+
+ Notes:
+
+**/
+INT16 OTC_GenVolEntry(
+ F40_ENV_PTR cur_env,
+ MTF_VOL_PTR cur_volb,
+ INT16 seq_num )
+{
+ MTF_FDD_HDR fdd_hdr ;
+ MTF_FDD_VOL_V2 fdd_vol ;
+ UINT8_PTR str_ptr ;
+ UINT16 offset = sizeof( MTF_FDD_HDR ) + sizeof( MTF_FDD_VOL_V2 ) ;
+ FILE * fptr = cur_env->otc_sm_fptr ;
+
+ /* DO NOT UNICODEIZE THIS CONSTANT!!! */
+ memcpy( fdd_hdr.type, "VOLB", 4 ) ;
+ OTC_SetFDDHeaderFields( &fdd_hdr, &cur_volb->block_hdr, seq_num ) ;
+
+ fdd_vol.backup_date = cur_volb->backup_date ;
+ fdd_vol.vol_attribs = cur_volb->volume_attribs ;
+ fdd_vol.os_info.data_size = 0 ;
+ fdd_vol.os_info.data_offset = 0 ;
+
+ if( ( fdd_vol.device_name.data_size = cur_volb->device_name.data_size ) != 0 ) {
+ fdd_vol.device_name.data_offset = offset ;
+ offset += fdd_vol.device_name.data_size ;
+ } else {
+ fdd_vol.device_name.data_offset = 0 ;
+ }
+
+ if( ( fdd_vol.vol_name.data_size = cur_volb->volume_name.data_size ) != 0 ) {
+ fdd_vol.vol_name.data_offset = offset ;
+ offset += fdd_vol.vol_name.data_size ;
+ } else {
+ fdd_vol.vol_name.data_offset = 0 ;
+ }
+
+ if( ( fdd_vol.machine_name.data_size = cur_volb->machine_name.data_size ) != 0 ) {
+ fdd_vol.machine_name.data_offset = offset ;
+ } else {
+ fdd_vol.machine_name.data_offset = 0 ;
+ }
+
+ /* The link field is always zero in the Set Map. If we are writing FDD
+ too, the link field will be set just before we write the entry in
+ the FDD temp file.
+ */
+ fdd_hdr.link = 0L ;
+
+ fdd_hdr.length = sizeof( MTF_FDD_HDR ) + sizeof( MTF_FDD_VOL_V2 )
+ + fdd_vol.device_name.data_size
+ + fdd_vol.vol_name.data_size
+ + fdd_vol.machine_name.data_size ;
+
+ if( fwrite( &fdd_hdr, sizeof( MTF_FDD_HDR ), 1, fptr ) != 1 ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = TRUE ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ if( fwrite( &fdd_vol, sizeof( MTF_FDD_VOL_V2 ), 1, fptr ) != 1 ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = TRUE ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ if( fdd_vol.device_name.data_size != 0 ) {
+ str_ptr = (UINT8_PTR)cur_volb + cur_volb->device_name.data_offset ;
+ if( fwrite( str_ptr, 1, fdd_vol.device_name.data_size, fptr )
+ != fdd_vol.device_name.data_size ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = TRUE ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ }
+ if( fdd_vol.vol_name.data_size != 0 ) {
+ str_ptr = (UINT8_PTR)cur_volb + cur_volb->volume_name.data_offset ;
+ if( fwrite( str_ptr, 1, fdd_vol.vol_name.data_size, fptr )
+ != fdd_vol.vol_name.data_size ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = TRUE ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ }
+ if( fdd_vol.machine_name.data_size != 0 ) {
+ str_ptr = (UINT8_PTR)cur_volb + cur_volb->machine_name.data_offset ;
+ if( fwrite( str_ptr, 1, fdd_vol.machine_name.data_size, fptr )
+ != fdd_vol.machine_name.data_size ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = TRUE ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ }
+ if( fflush( fptr ) != 0 ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = TRUE ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_OTC_FAILURE ) ;
+ }
+
+ if( cur_env->cur_otc_level == TCL_FULL && !cur_env->fdd_aborted ) {
+
+ fptr = cur_env->otc_fdd_fptr ;
+
+ /* Here we set the link field to the previous volume entry. This
+ is done so that at the end of the backup we can traverse back
+ through the volume entries setting foreward links from each
+ one to its next sibling.
+ */
+ fdd_hdr.link = cur_env->last_volb ;
+ cur_env->last_volb = ftell( fptr ) ;
+
+ if( fwrite( &fdd_hdr, sizeof( MTF_FDD_HDR ), 1, fptr ) != 1 ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ if( fwrite( &fdd_vol, sizeof( MTF_FDD_VOL_V2 ), 1, fptr ) != 1 ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ if( fdd_vol.device_name.data_size != 0 ) {
+ str_ptr = (UINT8_PTR)cur_volb + cur_volb->device_name.data_offset ;
+ if( fwrite( str_ptr, 1, fdd_vol.device_name.data_size, fptr )
+ != fdd_vol.device_name.data_size ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = TRUE ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ }
+ if( fdd_vol.vol_name.data_size != 0 ) {
+ str_ptr = (UINT8_PTR)cur_volb + cur_volb->volume_name.data_offset ;
+ if( fwrite( str_ptr, 1, fdd_vol.vol_name.data_size, fptr )
+ != fdd_vol.vol_name.data_size ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ }
+ if( fdd_vol.machine_name.data_size != 0 ) {
+ str_ptr = (UINT8_PTR)cur_volb + cur_volb->machine_name.data_offset ;
+ if( fwrite( str_ptr, 1, fdd_vol.machine_name.data_size, fptr )
+ != fdd_vol.machine_name.data_size ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ }
+ }
+
+ return( TFLE_NO_ERR ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_GenDirEntry
+
+ Description: Generates an OTC directory entry and writes it to the
+ FDD temporary file.
+
+ Returns: INT16 - TFLE_xxx
+
+ Notes: Currently always returns TFLE_NO_ERR since failed writes
+ to disk are handled internally and shouldn't cause a
+ backup to be aborted.
+
+**/
+INT16 OTC_GenDirEntry(
+ CHANNEL_PTR channel,
+ MTF_DIR_PTR cur_dir,
+ INT16 seq_num )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)(channel->fmt_env) ;
+ MTF_FDD_HDR fdd_hdr ;
+ MTF_FDD_DIR_V2 fdd_dir ;
+ UINT8_PTR str_ptr ;
+ FILE * fptr = cur_env->otc_fdd_fptr ;
+ void * temp ;
+ UINT16 new_size ;
+
+ /* DO NOT UNICODEIZE THIS CONSTANT!!! */
+ memcpy( fdd_hdr.type, "DIRB", 4 ) ;
+ OTC_SetFDDHeaderFields( &fdd_hdr, &cur_dir->block_hdr, seq_num ) ;
+
+ fdd_dir.last_mod_date = cur_dir->last_mod_date ;
+ fdd_dir.create_date = cur_dir->create_date ;
+ fdd_dir.backup_date = cur_dir->backup_date ;
+ fdd_dir.last_access_date = cur_dir->last_access_date ;
+ fdd_dir.dir_attribs = cur_dir->directory_attribs ;
+ fdd_dir.os_info.data_size = 0 ;
+ fdd_dir.os_info.data_offset = 0 ;
+
+ /* Here we need to get a path which may not be in the buffer with the
+ DBLK (path in stream). We have a special buffer for this in the
+ environment, which we pass to the file system to fill out. If the
+ size currently allocated to this buffer isn't big enough, we need
+ to reallocate.
+ */
+ if( fdd_dir.dir_attribs & DIR_PATH_IN_STREAM_BIT ) {
+ fdd_dir.dir_attribs &= ~DIR_PATH_IN_STREAM_BIT ;
+ fdd_dir.dir_name.data_size = FS_SizeofOSPathInDDB( channel->cur_fsys, channel->cur_dblk ) ;
+ if( cur_env->util_buff_size < fdd_dir.dir_name.data_size ) {
+ new_size = cur_env->util_buff_size ;
+ while( new_size < fdd_dir.dir_name.data_size ) {
+ new_size += F40_UTIL_BUFF_INC ;
+ }
+ if( ( temp = realloc( cur_env->util_buff, new_size ) ) == NULL ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ } else {
+ cur_env->util_buff = temp ;
+ cur_env->util_buff_size = new_size ;
+ }
+ }
+ str_ptr = cur_env->util_buff ;
+ FS_GetOSPathFromDDB( channel->cur_fsys, channel->cur_dblk, (CHAR_PTR)( str_ptr ) ) ;
+ } else {
+ str_ptr = (UINT8_PTR)cur_dir + cur_dir->directory_name.data_offset ;
+ fdd_dir.dir_name.data_size = cur_dir->directory_name.data_size ;
+ }
+
+ fdd_dir.dir_name.data_offset = sizeof( MTF_FDD_HDR )
+ + sizeof( MTF_FDD_DIR_V2 ) ;
+
+ fdd_hdr.length = sizeof( MTF_FDD_HDR ) + sizeof( MTF_FDD_DIR_V2 )
+ + fdd_dir.dir_name.data_size ;
+
+ if( OTC_SetDirLink( cur_env, &fdd_hdr, str_ptr,
+ fdd_dir.dir_name.data_size ) != TFLE_NO_ERR ) {
+
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+
+ if( fwrite( &fdd_hdr, sizeof( MTF_FDD_HDR ), 1, fptr ) != 1 ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+
+ /* for setting the corrupt file bit later (if necessary) */
+ if( !( fdd_hdr.blk_attribs & MTF_DB_CONT_BIT ) ) {
+ cur_env->last_fdd_offset = ftell( fptr ) ;
+ cur_env->last_fdd_type = FDD_DIR_BLK ;
+ }
+
+ if( fwrite( &fdd_dir, sizeof( MTF_FDD_DIR_V2 ), 1, fptr ) != 1 ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ if( fdd_dir.dir_name.data_size != 0 ) {
+ if( fwrite( str_ptr, 1, fdd_dir.dir_name.data_size, fptr )
+ != fdd_dir.dir_name.data_size ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ }
+
+ return( TFLE_NO_ERR ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_GenDBDBEntry
+
+ Description: Generates an OTC database entry and writes it to the
+ FDD temporary file.
+
+ Returns: INT16 - TFLE_xxx
+
+ Notes: Currently always returns TFLE_NO_ERR since failed writes
+ to disk are handled internally and shouldn't cause a
+ backup to be aborted.
+
+**/
+INT16 OTC_GenDBDBEntry(
+ CHANNEL_PTR channel,
+ F40_DBDB_PTR cur_dbdb,
+ INT16 seq_num )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)(channel->fmt_env) ;
+ MTF_FDD_HDR fdd_hdr ;
+ F40_FDD_DBDB fdd_dbdb ;
+ UINT8_PTR str_ptr ;
+ FILE * fptr = cur_env->otc_fdd_fptr ;
+ void * temp ;
+ UINT16 new_size ;
+
+ /* DO NOT UNICODEIZE THIS CONSTANT!!! */
+ memcpy( fdd_hdr.type, "DBDB", 4 ) ;
+ OTC_SetFDDHeaderFields( &fdd_hdr, &cur_dbdb->block_hdr, seq_num ) ;
+
+ fdd_dbdb.backup_date = cur_dbdb->backup_date ;
+ fdd_dbdb.database_attribs = cur_dbdb->database_attribs ;
+ fdd_dbdb.os_info.data_size = 0 ;
+ fdd_dbdb.os_info.data_offset = 0 ;
+
+ str_ptr = (UINT8_PTR)cur_dbdb + cur_dbdb->database_name.data_offset ;
+ fdd_dbdb.database_name.data_size = cur_dbdb->database_name.data_size ;
+
+ fdd_dbdb.database_name.data_offset = sizeof( MTF_FDD_HDR )
+ + sizeof( F40_FDD_DBDB ) ;
+
+ fdd_hdr.length = sizeof( MTF_FDD_HDR ) + sizeof( F40_FDD_DBDB )
+ + fdd_dbdb.database_name.data_size ;
+
+ fdd_hdr.link = 0 ;
+
+ if( fwrite( &fdd_hdr, sizeof( MTF_FDD_HDR ), 1, fptr ) != 1 ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+
+ /* for setting the corrupt file bit later (if necessary) */
+ if( !( fdd_hdr.blk_attribs & MTF_DB_CONT_BIT ) ) {
+ cur_env->last_fdd_offset = ftell( fptr ) ;
+ cur_env->last_fdd_type = FDD_DBDB_BLK ;
+ }
+
+ if( fwrite( &fdd_dbdb, sizeof( F40_FDD_DBDB ), 1, fptr ) != 1 ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ if( fdd_dbdb.database_name.data_size != 0 ) {
+ if( fwrite( str_ptr, 1, fdd_dbdb.database_name.data_size, fptr )
+ != fdd_dbdb.database_name.data_size ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ }
+
+ return( TFLE_NO_ERR ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_GenFileEntry
+
+ Description: Generates an OTC file entry and writes it to the FDD
+ temporary file.
+
+ Returns: INT16 - TFLE_xxx
+
+ Notes: Currently always returns TFLE_NO_ERR since failed writes
+ to disk are handled internally and shouldn't cause a
+ backup to be aborted.
+
+**/
+INT16 OTC_GenFileEntry(
+ F40_ENV_PTR cur_env,
+ MTF_FILE_PTR cur_file,
+ INT16 seq_num )
+{
+ MTF_FDD_HDR fdd_hdr ;
+ MTF_FDD_FILE_V2 fdd_file ;
+ UINT8_PTR str_ptr = (UINT8_PTR)cur_file ;
+ FILE * fptr = cur_env->otc_fdd_fptr ;
+
+ /* DO NOT UNICODEIZE THIS CONSTANT!!! */
+ memcpy( fdd_hdr.type, "FILE", 4 ) ;
+ OTC_SetFDDHeaderFields( &fdd_hdr, &cur_file->block_hdr, seq_num ) ;
+
+ fdd_file.last_mod_date = cur_file->last_mod_date ;
+ fdd_file.last_access_date = cur_file->last_access_date ;
+ fdd_file.create_date = cur_file->create_date ;
+ fdd_file.backup_date = cur_file->backup_date ;
+ fdd_file.file_attribs = cur_file->file_attributes ;
+ fdd_file.os_info.data_size = 0 ;
+ fdd_file.os_info.data_offset = 0 ;
+ fdd_file.file_name.data_size = cur_file->file_name.data_size ;
+ fdd_file.file_name.data_offset = sizeof( MTF_FDD_HDR )
+ + sizeof( MTF_FDD_FILE_V2 ) ;
+
+ fdd_hdr.length = sizeof( MTF_FDD_HDR ) + sizeof( MTF_FDD_FILE_V2 )
+ + fdd_file.file_name.data_size ;
+
+ /* Set link to parent directory */
+ fdd_hdr.link = cur_env->dir_links[cur_env->dir_level] ;
+
+ str_ptr += cur_file->file_name.data_offset ;
+
+ if( fwrite( &fdd_hdr, sizeof( MTF_FDD_HDR ), 1, fptr ) != 1 ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+
+ /* for setting the corrupt file bit later (if necessary) */
+ if( !( fdd_hdr.blk_attribs & MTF_DB_CONT_BIT ) ) {
+ cur_env->last_fdd_offset = ftell( fptr ) ;
+ cur_env->last_fdd_type = FDD_FILE_BLK ;
+ }
+
+ if( fwrite( &fdd_file, sizeof( MTF_FDD_FILE_V2 ), 1, fptr ) != 1 ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ if( fdd_file.file_name.data_size != 0 ) {
+ if( fwrite( str_ptr, 1, fdd_file.file_name.data_size, fptr )
+ != fdd_file.file_name.data_size ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ }
+
+ return( TFLE_NO_ERR ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_GenEndEntry
+
+ Description: Generates an OTC End-of-FDD entry and writes it to the
+ FDD temporary file.
+
+ Returns: INT16 - TFLE_xxx
+
+ Notes: Currently always returns TFLE_NO_ERR since failed writes
+ to disk are handled internally and shouldn't cause a
+ backup to be aborted.
+
+**/
+INT16 OTC_GenEndEntry(
+ CHANNEL_PTR channel )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)(channel->fmt_env) ;
+ MTF_FDD_HDR fdd_hdr ;
+ FILE * fptr = cur_env->otc_fdd_fptr ;
+ UINT16 len ;
+
+ memset( &fdd_hdr, 0, sizeof( MTF_FDD_HDR ) ) ;
+
+ /* DO NOT UNICODEIZE THIS CONSTANT!!! */
+ memcpy( fdd_hdr.type, "FEND", 4 ) ;
+
+ /* Set length to include pad out to physical block boundary */
+ len = (UINT16)( ( ftell( fptr ) +
+ sizeof( MTF_STREAM ) +
+ sizeof( MTF_FDD_HDR ) ) % ChannelBlkSize( channel ) ) ;
+ fdd_hdr.length = ChannelBlkSize( channel ) - len ;
+
+ if( fwrite( &fdd_hdr, sizeof( MTF_FDD_HDR ), 1, fptr ) != 1 ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ if( fflush( fptr ) != 0 ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+
+ /* Set up the link fields */
+ if( OTC_ReverseLinks( cur_env ) != TFLE_NO_ERR ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+
+ return( TFLE_NO_ERR ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_GenSMEntry
+
+ Description: Generates an OTC Set Map entry and writes it to the SM
+ temporary file.
+
+ Returns: INT16 - TFLE_xxx
+
+ Notes:
+
+**/
+INT16 OTC_GenSMEntry(
+ MTF_SSET_PTR cur_sset,
+ CHANNEL_PTR channel,
+ BOOLEAN continuation )
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)(channel->fmt_env) ;
+ MTF_SM_ENTRY sm_entry ;
+ UINT8_PTR str_ptr ;
+ UINT16 offset = sizeof( MTF_SM_ENTRY ) ;
+ FILE * fptr = cur_env->otc_sm_fptr ;
+
+ sm_entry.seq_num = channel->ts_num ;
+ sm_entry.set_num = cur_sset->backup_set_number ;
+ sm_entry.blk_attribs = cur_sset->block_hdr.block_attribs ;
+ sm_entry.set_attribs = cur_sset->sset_attribs ;
+ sm_entry.sset_pba = cur_sset->physical_block_address ;
+ sm_entry.lba = cur_sset->block_hdr.logical_block_address ;
+ sm_entry.backup_date = cur_sset->backup_date ;
+ sm_entry.os_id = cur_sset->block_hdr.machine_os_id ;
+ sm_entry.os_ver = cur_sset->block_hdr.machine_os_version ;
+ sm_entry.disp_size = cur_sset->block_hdr.displayable_size ;
+ sm_entry.num_volumes = 1 ;
+ sm_entry.time_zone = cur_sset->time_zone ;
+ sm_entry.pswd_encr_algor = cur_sset->password_encryption_algor ;
+ sm_entry.string_type = cur_sset->block_hdr.string_type ;
+ sm_entry.tf_minor_ver = cur_sset->tf_minor_ver ;
+ sm_entry.tape_cat_ver = cur_sset->tape_cat_ver ;
+
+ if( ( sm_entry.set_name.data_size =
+ cur_sset->backup_set_name.data_size ) != 0 ) {
+ sm_entry.set_name.data_offset = offset ;
+ offset += sm_entry.set_name.data_size ;
+ } else {
+ sm_entry.set_name.data_offset = 0 ;
+ }
+
+ if( ( sm_entry.password.data_size =
+ cur_sset->backup_set_password.data_size ) != 0 ) {
+ sm_entry.password.data_offset = offset ;
+ offset += sm_entry.password.data_size ;
+ } else {
+ sm_entry.password.data_offset = 0 ;
+ }
+
+ if( ( sm_entry.set_descr.data_size =
+ cur_sset->backup_set_description.data_size ) != 0 ) {
+ sm_entry.set_descr.data_offset = offset ;
+ offset += sm_entry.set_descr.data_size ;
+ } else {
+ sm_entry.set_descr.data_offset = 0 ;
+ }
+
+ if( ( sm_entry.user_name.data_size =
+ cur_sset->user_name.data_size ) != 0 ) {
+ sm_entry.user_name.data_offset = offset ;
+ } else {
+ sm_entry.user_name.data_offset = 0 ;
+ }
+
+ sm_entry.length = sizeof( MTF_SM_ENTRY ) + sm_entry.set_name.data_size
+ + sm_entry.password.data_size
+ + sm_entry.set_descr.data_size
+ + sm_entry.user_name.data_size ;
+
+ if( fseek( fptr, 0L, SEEK_END ) != 0 ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = TRUE ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_OTC_FAILURE ) ;
+ }
+
+ /* for setting the remainder of the SM fields */
+ if( !continuation ) {
+ cur_env->last_sm_offset = ftell( fptr ) ;
+ } else {
+ cur_env->cont_sm_offset = ftell( fptr ) ;
+ }
+
+ if( fwrite( &sm_entry, sizeof( MTF_SM_ENTRY ), 1, fptr ) != 1 ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = TRUE ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ if( sm_entry.set_name.data_size != 0 ) {
+ str_ptr = (UINT8_PTR)cur_sset + cur_sset->backup_set_name.data_offset ;
+ if( fwrite( str_ptr, 1, sm_entry.set_name.data_size, fptr )
+ != sm_entry.set_name.data_size ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = TRUE ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ }
+ if( sm_entry.password.data_size != 0 ) {
+ str_ptr = (UINT8_PTR)cur_sset + cur_sset->backup_set_password.data_offset ;
+ if( fwrite( str_ptr, 1, sm_entry.password.data_size, fptr )
+ != sm_entry.password.data_size ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = TRUE ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ }
+ if( sm_entry.set_descr.data_size != 0 ) {
+ str_ptr = (UINT8_PTR)cur_sset + cur_sset->backup_set_description.data_offset ;
+ if( fwrite( str_ptr, 1, sm_entry.set_descr.data_size, fptr )
+ != sm_entry.set_descr.data_size ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = TRUE ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ }
+ if( sm_entry.user_name.data_size != 0 ) {
+ str_ptr = (UINT8_PTR)cur_sset + cur_sset->user_name.data_offset ;
+ if( fwrite( str_ptr, 1, sm_entry.user_name.data_size, fptr )
+ != sm_entry.user_name.data_size ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = TRUE ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ }
+
+ return( TFLE_NO_ERR ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_UpdateSMEntry
+
+ Description: Updates all Set Map entries for the current backup with
+ information which is not available until the backup has
+ completed, and writes the updated entries to the SM
+ temporary file.
+
+ Returns: INT16 - TFLE_xxx
+
+ Notes: Currently always returns TFLE_NO_ERR since failed writes
+ to disk are handled internally and shouldn't cause a
+ backup to be aborted.
+
+**/
+INT16 OTC_UpdateSMEntry(
+ F40_ENV_PTR cur_env )
+{
+ MTF_SM_ENTRY sm_entry ;
+ MTF_FDD_HDR fdd_hdr ;
+ FILE * fptr = cur_env->otc_sm_fptr ;
+ long pos = cur_env->last_sm_offset ;
+ UINT16 count = cur_env->sm_count ;
+
+ while( count != 0 ) {
+ if( fseek( fptr, pos, SEEK_SET ) != 0 ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = TRUE ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ if( fread( &sm_entry, sizeof( MTF_SM_ENTRY ), 1, fptr ) != 1 ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = TRUE ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+
+ if( cur_env->cur_otc_level == TCL_FULL && !cur_env->fdd_aborted ) {
+ sm_entry.fdd_pba = U64_Init( cur_env->fdd_pba, 0L ) ;
+ sm_entry.fdd_seq_num = cur_env->fdd_seq_num ;
+ } else {
+ sm_entry.fdd_pba = U64_Init( 0L, 0L ) ;
+ sm_entry.fdd_seq_num = 0 ;
+ }
+
+ sm_entry.num_dirs = cur_env->dir_count ;
+ sm_entry.num_files = cur_env->file_count ;
+ sm_entry.num_corrupt_files = cur_env->corrupt_obj_count ;
+
+ if( fseek( fptr, pos, SEEK_SET ) != 0 ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = TRUE ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ if( fwrite( &sm_entry, sizeof( MTF_SM_ENTRY ), 1, fptr ) != 1 ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = TRUE ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+
+ if( --count != 0 ) {
+ pos += sm_entry.length ;
+ if( fseek( fptr, pos, SEEK_SET ) != 0 ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = TRUE ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ if( fread( &fdd_hdr, sizeof( MTF_FDD_HDR ), 1, fptr ) != 1 ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = TRUE ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ pos += fdd_hdr.length ;
+ }
+ }
+
+ return( TFLE_NO_ERR ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_MarkLastEntryCorrupt
+
+ Description: Called when the last object backed up is found to be
+ corrupt, this function reads the last FDD entry from
+ the temporary file, sets the corrupt bit in the
+ attribute field, and writes it back out.
+
+ Returns: INT16 - TFLE_xxx
+
+ Notes: Currently always returns TFLE_NO_ERR since failed writes
+ to disk are handled internally and shouldn't cause a
+ backup to be aborted.
+
+**/
+INT16 OTC_MarkLastEntryCorrupt(
+ F40_ENV_PTR cur_env )
+{
+ union {
+ MTF_FDD_DIR_V2 d ;
+ MTF_FDD_FILE_V2 f ;
+ F40_FDD_DBDB db ;
+ } fdd_entry ;
+
+// FDD_ENTRY fdd_entry ;
+
+ FILE * fptr = cur_env->otc_fdd_fptr ;
+ size_t size ;
+
+ switch( cur_env->last_fdd_type ) {
+
+ case FDD_DIR_BLK:
+ size = sizeof( MTF_FDD_DIR_V2 ) ;
+ break ;
+
+ case FDD_FILE_BLK:
+ size = sizeof( MTF_FDD_FILE_V2 ) ;
+ break ;
+
+ case FDD_DBDB_BLK:
+ size = sizeof( F40_FDD_DBDB ) ;
+ break ;
+
+ default:
+ msassert( FALSE ) ;
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+
+ if( fseek( fptr, cur_env->last_fdd_offset, SEEK_SET ) != 0 ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ if( fread( &fdd_entry, 1, size, fptr ) != size ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+
+ switch( cur_env->last_fdd_type ) {
+
+ case FDD_DIR_BLK:
+ fdd_entry.d.dir_attribs |= OBJ_CORRUPT_BIT ;
+ break ;
+
+ case FDD_FILE_BLK:
+ fdd_entry.f.file_attribs |= OBJ_CORRUPT_BIT ;
+ break ;
+
+ case FDD_DBDB_BLK:
+ fdd_entry.db.database_attribs |= OBJ_CORRUPT_BIT ;
+ break ;
+ }
+
+ if( fseek( fptr, cur_env->last_fdd_offset, SEEK_SET ) != 0 ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ if( fwrite( &fdd_entry, 1, size, fptr ) != size ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ if( fseek( fptr, 0, SEEK_END ) != 0 ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+
+ return( TFLE_NO_ERR ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_ReverseLinks
+
+ Description: When this function is called, the link fields in the
+ directory and volume entries contain the file offset of
+ the entry who's link field SHOULD point at them. This
+ function traverses back through these "backward" links
+ and makes them foreward links.
+
+ Returns: TFLE_xxx error code
+
+ Notes: In the case of directory links, if the back link is
+ negative it indicates that the previous directory at
+ that tree level does not have the same parent. In this
+ case we use the link field to get to the previous entry,
+ but we don't put in a foreward link.
+
+**/
+static INT _near OTC_ReverseLinks(
+ F40_ENV_PTR cur_env )
+{
+ UINT16 level ;
+ FILE * fptr = cur_env->otc_fdd_fptr ;
+ long prev_link ;
+ long curr_link ;
+ long next_link ;
+
+ curr_link = cur_env->last_volb ;
+ next_link = 0L ;
+ while( curr_link != -1L ) {
+ if( OTC_SetLink( fptr, curr_link, next_link, &prev_link ) != TFLE_NO_ERR ) {
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ next_link = curr_link ;
+ curr_link = prev_link ;
+ }
+
+ for( level = 0; level <= cur_env->max_dir_level; level++ ) {
+ curr_link = cur_env->dir_links[level] ;
+ next_link = 0L ;
+ while( curr_link != 0L ) {
+ if( OTC_SetLink( fptr, curr_link, next_link, &prev_link ) != TFLE_NO_ERR ) {
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ if( prev_link < 0L ) {
+ next_link = 0L ;
+ curr_link = - prev_link ;
+ } else {
+ next_link = curr_link ;
+ curr_link = prev_link ;
+ }
+ }
+ }
+
+ /* Set the file pointer back to the end */
+ if( fseek( fptr, 0L, SEEK_END ) != 0 ) {
+ return( TFLE_OTC_FAILURE ) ;
+ }
+
+ return( TFLE_NO_ERR ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_SetLink
+
+ Description: This function seeks to the given file position,
+ reads in the FDD_HDR at that location, sets the
+ 'prev_link' parameter to the contents of the link
+ field in the header, sets the link field to the given
+ 'next_link' value and rewrites the header.
+
+ Returns: TFLE_xxx error code
+
+ Notes:
+
+**/
+static INT _near OTC_SetLink(
+ FILE * fptr,
+ long curr_link,
+ long next_link,
+ long * prev_link )
+{
+ MTF_FDD_HDR fdd_hdr ;
+
+ if( fseek( fptr, curr_link, SEEK_SET ) != 0 ) {
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ if( fread( &fdd_hdr, sizeof( MTF_FDD_HDR ), 1, fptr ) != 1 ) {
+ return( TFLE_OTC_FAILURE ) ;
+ }
+
+ *prev_link = fdd_hdr.link ;
+ fdd_hdr.link = next_link ;
+
+ if( fseek( fptr, curr_link, SEEK_SET ) != 0 ) {
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ if( fwrite( &fdd_hdr, sizeof( MTF_FDD_HDR ), 1, fptr ) != 1 ) {
+ return( TFLE_OTC_FAILURE ) ;
+ }
+ return( TFLE_NO_ERR ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_PreprocessEOM
+
+ Description: This function copies the FDD data into a temporary file,
+ rewinds the FDD file, and writes the entries which
+ actually made it on to the first tape to the FDD file.
+ This is done in preparation for writing the continuation
+ entries.
+
+ Returns: TFLE_xxx error code
+
+ Notes: After the continuation entries are written, the function
+ OTC_PostprocessEOM will be called to write the remaining
+ entries in the temporary file back to the FDD file, and
+ delete the temporary file.
+
+ OTC_Close will also close and delete the EOM temporary
+ file since this isn't the only function using it, so we
+ open it here, but we don't explicitly close it if there
+ is an error.
+
+ Currently always returns TFLE_NO_ERR since failed writes
+ to disk are handled internally and shouldn't cause a
+ backup to be aborted.
+
+**/
+
+INT16 OTC_PreprocessEOM(
+ F40_ENV_PTR cur_env, /* The format environment */
+ UINT32 cross_lba ) /* The LBA of the crossing entry */
+{
+ FILE * fdd_fptr = cur_env->otc_fdd_fptr ;
+ FILE * tmp_fptr ;
+ UINT8_PTR buff_ptr ;
+ UINT8_PTR str_ptr ;
+ size_t size ;
+ UINT16 len ;
+ MTF_FDD_HDR fdd_hdr ;
+ BOOLEAN first = TRUE ;
+ long hdr_size = (long)sizeof( MTF_FDD_HDR ) ;
+ UNALIGNED MTF_FDD_DIR_V2 * fdd_dir ;
+ INT32 save_link ;
+ void * temp ;
+ UINT16 new_size ;
+
+ msassert( cur_env->otc_fdd_fptr != NULL ) ;
+ msassert( cur_env->otc_eom_fptr == NULL ) ;
+
+ /* Make sure we have utility buffer space allocated */
+ if( cur_env->util_buff == NULL ) {
+ if( ( cur_env->util_buff = calloc( F40_INIT_UTIL_BUFF_SIZE, 1 ) ) == NULL ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ cur_env->util_buff_size = F40_INIT_UTIL_BUFF_SIZE ;
+ }
+ buff_ptr = cur_env->util_buff ;
+
+ /* Open the temp file */
+ strcpy( lw_cat_file_path_end, TEXT("EMXXXXXX") ) ;
+ if( msmktemp( lw_cat_file_path ) == NULL ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ strcat( lw_cat_file_path, TEXT(".FDD") ) ;
+ strcpy( cur_env->eom_fname, lw_cat_file_path_end ) ;
+ if( ( cur_env->otc_eom_fptr = UNI_fopen( lw_cat_file_path, 0 ) ) == NULL ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ tmp_fptr = cur_env->otc_eom_fptr ;
+
+ /* Rewind the FDD file, and copy it to the temp file */
+ if( fseek( fdd_fptr, 0L, SEEK_SET ) != 0 ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ while( !feof( fdd_fptr ) ) {
+ size = fread( buff_ptr, 1, cur_env->util_buff_size, fdd_fptr ) ;
+ if( ferror( fdd_fptr ) ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ if( size != 0 ) {
+ if( fwrite( buff_ptr, 1, size, tmp_fptr ) != size ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ first = FALSE ;
+ } else {
+ if( first ) { // Nothing to transfer
+ return( TFLE_NO_ERR ) ;
+ }
+ }
+ }
+
+ /* Rewind the temp file, clear the FDD file, and copy all entries
+ with LBAs less than the crossing LBA.
+ */
+ if( fseek( tmp_fptr, 0L, SEEK_SET ) != 0 ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ fclose( cur_env->otc_fdd_fptr ) ;
+ cur_env->otc_fdd_fptr = NULL ;
+ if( OTC_OpenFDD( cur_env ) != TFLE_NO_ERR ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ fdd_fptr = cur_env->otc_fdd_fptr ;
+
+ if( fread( &fdd_hdr, sizeof( MTF_FDD_HDR ), 1, tmp_fptr ) != 1 ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+
+ /* We're going to reset all the dir links */
+ cur_env->dir_links[0] = 0L ;
+ cur_env->dir_level = 0 ;
+ cur_env->max_dir_level = 0 ;
+
+ while( !feof( tmp_fptr ) && U64_Lsw( fdd_hdr.lba ) < cross_lba ) {
+ len = fdd_hdr.length - sizeof( MTF_FDD_HDR ) ;
+
+ if( cur_env->util_buff_size < len ) {
+ new_size = cur_env->util_buff_size + F40_UTIL_BUFF_INC ;
+ if( ( temp = realloc( cur_env->util_buff, new_size ) ) == NULL ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ } else {
+ cur_env->util_buff = temp ;
+ cur_env->util_buff_size = new_size ;
+ buff_ptr = cur_env->util_buff ;
+ }
+ }
+
+ if( fread( buff_ptr, 1, len, tmp_fptr ) != len ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+
+ /* DO NOT UNICODEIZE THE FOLLOWING CONSTANT!!! */
+ if( memcmp( fdd_hdr.type, "DIRB", 4 ) == 0 ) {
+
+ fdd_dir = (UNALIGNED MTF_FDD_DIR_V2 *)(void *)( buff_ptr ) ;
+ str_ptr = buff_ptr + ( fdd_dir->dir_name.data_offset -
+ sizeof( MTF_FDD_HDR ) ) ;
+ save_link = fdd_hdr.link ;
+
+ if( OTC_SetDirLink( cur_env, &fdd_hdr, str_ptr,
+ fdd_dir->dir_name.data_size ) != TFLE_NO_ERR ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ msassert( save_link == fdd_hdr.link ) ;
+ }
+
+ if( fwrite( &fdd_hdr, sizeof( MTF_FDD_HDR ), 1, fdd_fptr ) != 1 ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ if( fwrite( buff_ptr, 1, len, fdd_fptr ) != len ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+
+ if( fread( &fdd_hdr, sizeof( MTF_FDD_HDR ), 1, tmp_fptr ) != 1 ) {
+ if( !feof( tmp_fptr ) ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ }
+ }
+
+ if( !feof( tmp_fptr ) ) {
+ if( fseek( tmp_fptr, -hdr_size, SEEK_CUR ) != 0 ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ }
+
+ return( TFLE_NO_ERR ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_PostProcessEOM
+
+ Description: This function adjusts the LBAs in the continuation
+ entries in the Set Map and FDD since we don't know
+ what they really are until after they're written.
+ If FDD is being written, it then copies the remainder
+ of the EOM temporary FDD file to the actual FDD file.
+
+ Returns: TFLE_xxx error code
+
+ Notes: It is assumed the prior to calling this function,
+ OTC_PreprocessEOM has been called, and the continuation
+ FDD entries have been appended to the FDD file.
+
+ OTC_Close will also close and delete the EOM temporary
+ file since this isn't the only function using it, so we
+ open it here, but we don't explicitly close it if there
+ is an error. If the operation completes successfully,
+ the we explicitly close and delete it since we don't
+ want it sitting around until OTC close in called.
+
+ Currently always returns TFLE_NO_ERR since failed writes
+ to disk are handled internally and shouldn't cause a
+ backup to be aborted.
+
+**/
+
+INT16 OTC_PostprocessEOM(
+ CHANNEL_PTR channel,
+ UINT32 sset_lba ) /* LBA of the continuation SSET */
+{
+ F40_ENV_PTR cur_env = (F40_ENV_PTR)(channel->fmt_env) ;
+ FILE * fdd_fptr = cur_env->otc_fdd_fptr ;
+ FILE * tmp_fptr = cur_env->otc_eom_fptr ;
+ FILE * sm_fptr = cur_env->otc_sm_fptr ;
+ UINT8_PTR buff_ptr ;
+ size_t size ;
+ UINT16 len ;
+ MTF_FDD_HDR fdd_hdr ;
+ MTF_SM_ENTRY sm_entry ;
+ long pos = cur_env->cont_sm_offset ;
+ long count ;
+ BOOLEAN done ;
+ UNALIGNED MTF_FDD_DIR_V2 * fdd_dir ;
+ void * temp ;
+ UINT16 new_size ;
+ UINT8_PTR str_ptr ;
+ int ret ;
+
+ msassert( cur_env->otc_sm_fptr != NULL ) ;
+
+ /* This grotesque little conditional checks to see if we wrote the SSET
+ on the last tape but fell short of writing the VOLB, or if we are
+ crossing tape during CloseSet processing. In either case, there
+ aren't any continuation entries to adjust the LBAs in.
+ */
+ if( ( channel->lst_tblk != BT_VCB || channel->eom_buff == NULL ||
+ BM_NextByteOffset( channel->eom_buff ) != F40_LB_SIZE ) &&
+ !IsChannelStatus( channel, CH_EOS_AT_EOM ) ) {
+
+ /* Adjust the SSET LBA */
+ if( fseek( sm_fptr, pos, SEEK_SET ) != 0 ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ if( fread( &sm_entry, sizeof( MTF_SM_ENTRY ), 1, sm_fptr ) != 1 ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = TRUE ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+
+ sm_entry.lba = U64_Init( sset_lba, 0L ) ;
+
+ if( fseek( sm_fptr, pos, SEEK_SET ) != 0 ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ if( fwrite( &sm_entry, sizeof( MTF_SM_ENTRY ), 1, sm_fptr ) != 1 ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+
+ /* Adjust the LBA of the VOLB in the Set Map */
+ pos += sm_entry.length ;
+ if( fseek( sm_fptr, pos, SEEK_SET ) != 0 ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ if( fread( &fdd_hdr, sizeof( MTF_FDD_HDR ), 1, sm_fptr ) != 1 ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+
+ fdd_hdr.lba = U64_Init( sset_lba + 1L, 0L ) ;
+
+ if( fseek( sm_fptr, pos, SEEK_SET ) != 0 ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ if( fwrite( &fdd_hdr, sizeof( MTF_FDD_HDR ), 1, sm_fptr ) != 1 ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+
+ /* Set file pointer to end */
+ if( fseek( sm_fptr, 0L, SEEK_END ) != 0 ) {
+ OTC_Close( cur_env, OTC_CLOSE_ALL, TRUE ) ;
+ cur_env->sm_aborted = cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+
+ /* Adjust the LBAs of the continuation FDD entries */
+ if( cur_env->cur_otc_level == TCL_FULL && !cur_env->fdd_aborted ) {
+ pos = cur_env->last_volb ;
+ count = 1L ;
+ done = FALSE ;
+ while( !done ) {
+ if( fseek( fdd_fptr, pos, SEEK_SET ) != 0 ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ if( fread( &fdd_hdr, sizeof( MTF_FDD_HDR ), 1, fdd_fptr ) != 1 ) {
+ if( feof( fdd_fptr ) ) {
+ done = TRUE ;
+ } else {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ }
+ if( !done ) {
+ fdd_hdr.lba = U64_Init( sset_lba + count, 0L ) ;
+ count++ ;
+ if( fseek( fdd_fptr, pos, SEEK_SET ) != 0 ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ if( fwrite( &fdd_hdr, sizeof( MTF_FDD_HDR ), 1, fdd_fptr ) != 1 ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ pos += fdd_hdr.length ;
+ }
+ }
+ }
+ }
+
+ if( cur_env->cur_otc_level != TCL_FULL || cur_env->fdd_aborted ||
+ IsChannelStatus( channel, CH_EOS_AT_EOM ) ) {
+
+ /* Not doing FDD, or done with it, so skip the next part */
+ return( TFLE_NO_ERR ) ;
+ }
+
+ msassert( cur_env->otc_fdd_fptr != NULL ) ;
+ msassert( cur_env->otc_eom_fptr != NULL ) ;
+
+ /* Make sure we have utility buffer space allocated */
+ if( cur_env->util_buff == NULL ) {
+ if( ( cur_env->util_buff = calloc( F40_INIT_UTIL_BUFF_SIZE, 1 ) ) == NULL ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ cur_env->util_buff_size = F40_INIT_UTIL_BUFF_SIZE ;
+ }
+ buff_ptr = cur_env->util_buff ;
+
+ /* Copy the remainder of the temp file to the FDD file */
+ if( fread( &fdd_hdr, sizeof( MTF_FDD_HDR ), 1, tmp_fptr ) != 1 ) {
+ if( !feof( tmp_fptr ) ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ }
+
+ while( !feof( tmp_fptr ) ) {
+
+ len = fdd_hdr.length - sizeof( MTF_FDD_HDR ) ;
+
+ if( cur_env->util_buff_size < len ) {
+ new_size = cur_env->util_buff_size + F40_UTIL_BUFF_INC ;
+ if( ( temp = realloc( cur_env->util_buff, new_size ) ) == NULL ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ } else {
+ cur_env->util_buff = temp ;
+ cur_env->util_buff_size = new_size ;
+ buff_ptr = cur_env->util_buff ;
+ }
+ }
+
+ if( fread( buff_ptr, 1, len, tmp_fptr ) != len ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+
+ fdd_hdr.seq_num++ ;
+
+ /* DO NOT UNICODEIZE THE FOLLOWING CONSTANT!!! */
+ if( memcmp( fdd_hdr.type, "DIRB", 4 ) == 0 ) {
+
+ fdd_dir = (UNALIGNED MTF_FDD_DIR_V2 *)(void *)( buff_ptr ) ;
+ str_ptr = (UINT8_PTR)( buff_ptr +
+ ( fdd_dir->dir_name.data_offset -
+ sizeof( MTF_FDD_HDR ) ) ) ;
+
+ if( OTC_SetDirLink( cur_env, &fdd_hdr, str_ptr,
+ fdd_dir->dir_name.data_size ) != TFLE_NO_ERR ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ }
+
+ /* DO NOT UNICODEIZE THE FOLLOWING CONSTANT!!! */
+ if( memcmp( fdd_hdr.type, "FILE", 4 ) == 0 ) {
+ fdd_hdr.link = cur_env->dir_links[cur_env->dir_level] ;
+ }
+
+ if( fwrite( &fdd_hdr, sizeof( MTF_FDD_HDR ), 1, fdd_fptr ) != 1 ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+
+ /* DO NOT UNICODEIZE THE FOLLOWING CONSTANTS!!! */
+ if( memcmp( fdd_hdr.type, "DIRB", 4 ) == 0 ) {
+ cur_env->last_fdd_type = FDD_DIR_BLK ;
+ cur_env->last_fdd_offset = ftell( fdd_fptr ) ;
+ } else if( memcmp( fdd_hdr.type, "DBDB", 4 ) == 0 ) {
+ cur_env->last_fdd_type = FDD_DBDB_BLK ;
+ cur_env->last_fdd_offset = ftell( fdd_fptr ) ;
+ } else if( memcmp( fdd_hdr.type, "FILE", 4 ) == 0 ) {
+ cur_env->last_fdd_type = FDD_FILE_BLK ;
+ cur_env->last_fdd_offset = ftell( fdd_fptr ) ;
+ }
+
+ if( fwrite( buff_ptr, 1, len, fdd_fptr ) != len ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+
+ if( fread( &fdd_hdr, sizeof( MTF_FDD_HDR ), 1, tmp_fptr ) != 1 ) {
+ if( !feof( tmp_fptr ) ) {
+ OTC_Close( cur_env, OTC_CLOSE_FDD, TRUE ) ;
+ cur_env->fdd_aborted = TRUE ;
+ return( TFLE_NO_ERR ) ;
+ }
+ }
+ }
+
+ /* Close and delete the temp file */
+ fflush( cur_env->otc_eom_fptr ) ;
+ ret = fclose( cur_env->otc_eom_fptr ) ;
+ msassert( ret == 0 ) ;
+ cur_env->otc_eom_fptr = NULL ;
+ strcpy( lw_cat_file_path_end, cur_env->eom_fname ) ;
+ remove( lw_cat_file_path ) ;
+
+ return( TFLE_NO_ERR ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Translators
+
+ Name: OTC_SetDirLink
+
+ Description: This function sets the link field to the previous
+ directory at the same level, if the previous directory
+ is from a new different tree, we make the link value
+ negative to indicate this. This is all done so that at
+ the end of the backup we can traverse back through the
+ directories setting foreward links from each directory
+ to its next sibling.
+
+ Returns: INT16 - TFLE_xxx
+
+ Notes: This function relies on the str_ptr being on a two byte
+ boundary if the path is a Unicode string, and we are
+ running on a machine which requires even byte alignment
+ for 2 byte characters (such as the MIPS). We don't
+ want to use an unaligned pointer as this would slow
+ us down too much.
+
+**/
+static INT16 _near OTC_SetDirLink(
+ F40_ENV_PTR cur_env,
+ MTF_FDD_HDR_PTR fdd_hdr,
+ UINT8_PTR str_ptr,
+ UINT16 size )
+{
+ FILE * fptr = cur_env->otc_fdd_fptr ;
+ UINT16 level ;
+ void * temp ;
+ UINT16 new_size ;
+ WCHAR_PTR wp ;
+ UNALIGNED WCHAR_PTR uwp ;
+ ACHAR_PTR ap ;
+ int i ;
+
+ if( fdd_hdr->string_type == BEC_ANSI_STR ) { // Path is an ASCII string.
+
+ if( size == 1 ) {
+ level = 0 ;
+ } else {
+ level = 1 ;
+ size-- ;
+ for( i = 0, ap = (ACHAR_PTR)str_ptr; i < size; i++, ap++ ) {
+ if( *ap == (ACHAR)('\0') ) {
+ level++ ;
+ }
+ }
+ }
+ } else { // Path is a Unicode string.
+
+ if( (UINT32)str_ptr & 1 ) {
+ if( size == 2 ) {
+ level = 0 ;
+ } else {
+ level = 1 ;
+ size -= 2 ;
+ for( i = 0, uwp = (UNALIGNED WCHAR_PTR)str_ptr; i < size; i += 2, uwp++ ) {
+ if( *uwp == (WCHAR)('\0') ) {
+ level++ ;
+ }
+ }
+ }
+ } else {
+ if( size == 2 ) {
+ level = 0 ;
+ } else {
+ level = 1 ;
+ size -= 2 ;
+ for( i = 0, wp = (WCHAR_PTR)str_ptr; i < size; i += 2, wp++ ) {
+ if( *wp == (WCHAR)('\0') ) {
+ level++ ;
+ }
+ }
+ }
+ }
+ }
+
+ if( level > cur_env->dir_level ) {
+ if( level > cur_env->max_dir_level ) {
+
+ if( level == cur_env->dir_links_size ) {
+ new_size = cur_env->dir_links_size + F40_DIR_LINKS_INC ;
+ if( ( temp = realloc( cur_env->dir_links,
+ new_size * sizeof( long ) ) ) == NULL ) {
+
+ return( TFLE_NO_MEMORY ) ;
+ } else {
+ cur_env->dir_links_size = new_size ;
+ cur_env->dir_links = temp ;
+ }
+ }
+
+ for( i = cur_env->max_dir_level + 1; i < level; i++ ) {
+ cur_env->dir_links[i] = 0L ;
+ }
+
+ fdd_hdr->link = 0L ;
+ cur_env->max_dir_level = level ;
+ } else {
+ if( cur_env->dir_links[level] == 0L ) {
+ fdd_hdr->link = 0L ;
+ } else {
+ fdd_hdr->link = - cur_env->dir_links[level] ;
+ }
+ }
+ } else {
+ fdd_hdr->link = cur_env->dir_links[level] ;
+ }
+
+ cur_env->dir_level = level ;
+ cur_env->dir_links[level] = ftell( fptr ) ;
+
+ return( TFLE_NO_ERR ) ;
+}
+
diff --git a/private/utils/ntbackup/src/parspath.c b/private/utils/ntbackup/src/parspath.c
new file mode 100644
index 000000000..6b42c3a68
--- /dev/null
+++ b/private/utils/ntbackup/src/parspath.c
@@ -0,0 +1,1104 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: parspath.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file is responsible for seperating the drive,
+ path name, and file name, from a text string.
+
+
+ $Log: M:/LOGFILES/PARSPATH.C_V $
+
+ Rev 1.19.1.2 19 Nov 1993 12:46:26 BARRY
+Unicode fix: improper path sizes were being returned.
+
+ Rev 1.19.1.1 18 Aug 1993 18:20:18 BARRY
+Removed temp Unicode fix and call strcspn since it is in stdwcs.c now
+
+ Rev 1.19.1.0 13 Aug 1993 15:44:44 TIMN
+Changed ALPHA define to ALTTER due to DECs ALPHA machine conflicts
+
+ Rev 1.19 19 Feb 1993 09:31:56 STEVEN
+fix steve's forgoen NULL
+
+ Rev 1.18 12 Feb 1993 09:01:02 STEVEN
+fix typo
+
+ Rev 1.17 11 Feb 1993 15:25:30 STEVEN
+fixe defined from define
+
+ Rev 1.16 11 Feb 1993 11:53:50 STEVEN
+win32 does large paths
+
+ Rev 1.13 04 Jan 1993 09:40:22 MIKEP
+temporary unicode fix
+
+ Rev 1.12 02 Dec 1992 17:00:16 CHUCKB
+Casted to remove a warning. You might say the warning was cast out...
+
+ Rev 1.11 11 Nov 1992 09:53:50 GREGG
+Unicodeized literals.
+
+ Rev 1.10 06 Oct 1992 09:23:14 ChuckS
+Got by mistake, but fixed typo anyway
+
+ Rev 1.9 05 Oct 1992 17:05:58 DAVEV
+Unicode strlen verification
+
+ Rev 1.8 18 Aug 1992 10:28:38 STEVEN
+fix warnings
+
+ Rev 1.7 28 Jul 1992 15:38:14 STEVEN
+fix warnings
+
+ Rev 1.6 24 Mar 1992 10:10:58 DON
+if *path is '\0' and psize is 0 then psize is 1
+
+ Rev 1.5 13 Jan 1992 18:46:38 STEVEN
+changes for WIN32 compile
+
+ Rev 1.4 06 Aug 1991 18:32:20 DON
+added NLM File System support
+
+ Rev 1.3 25 Jul 1991 16:32:26 BARRY
+Finish #ifdef changes, remove warnings.
+
+ Rev 1.2 04 Jun 1991 11:28:46 BARRY
+Starting to make #defines not product specific--more to come.
+
+ Rev 1.1 29 May 1991 13:51:08 CARLS
+added valid sregs pointers for intdosx calls for windows
+
+ Rev 1.0 09 May 1991 13:38:46 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#if defined( OS_OS2 )
+#define INCL_DOS
+#include <os2.h>
+#else
+#include <dos.h>
+#endif
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "stdmacro.h"
+
+#include "fsys.h"
+#include "fsys_err.h"
+#include "novcom.h"
+#include "parstab.h" /* must be last include in list */
+#include "msassert.h"
+/* $end$ include list */
+
+
+#define DOS8_3 1
+#define NOV_14 2
+#define OS2_HPFS 3
+#define MAC_SPEC 4
+
+#define BACK_ZERO_DIR 1
+#define BACK_ONE_DIR 2
+
+#define FNAME_ELEM 0
+#define DIR_ELEM_MID 1
+#define DIR_ELEM_TRAIL 2
+
+static CHAR parse_table[6][11] = {
+#if defined ( OS_OS2 ) || defined( OS_WIN32 )
+/* COLON PERIOD BK_SLASH END_OS ALETTER NUMERIC SPECIAL GRAPHIC ANY REMOT_CHAR IMAGE_START */
+/*INITIAL*/ MAC_SPC, DRVDONE, DRVDONE, ERROR, DRV_REL, DRV_REL, DRV_REL, DRV_REL, ERROR, REM_DRV, DRV_REL,
+/*DRV_REL*/ DRVDONE, DRV_REL, DRVDONE, FILEDON, DRV_REL, DRV_REL, DRV_REL, DRV_REL, DRV_REL, ERROR, ERROR,
+/*MAC_SPC*/ MAC_SPC, MAC_SPC, MAC_SPC, ALLDON, MAC_SPC, MAC_SPC, MAC_SPC, MAC_SPC, MAC_SPC, MAC_SPC, MAC_SPC,
+/*DOS*/ ERROR, DOS, DOS, ALLDON, DOS, DOS, DOS, DOS, ERROR, ERROR, ERROR,
+/*IM_NAME*/ IM_NAME, IM_NAME, IM_NAME, IM_DONE, IM_NAME, IM_NAME, IM_NAME, IM_NAME, IM_NAME, IM_NAME, IM_NAME,
+/*OS2*/ ERROR, OS2, OS2, ALLDON, OS2, OS2, OS2, OS2, OS2, OS2, ERROR
+};
+#else
+/* COLON PERIOD BK_SLASH END_OS ALETTER NUMERIC SPECIAL GRAPHIC ANY REMOT_CHAR IMAGE_START */
+/*INITIAL*/ MAC_SPC, DRVDONE, DRVDONE, ERROR, DRV_REL, DRV_REL, DRV_REL, DRV_REL, ERROR, REM_DRV, IM_NAME,
+/*DRV_REL*/ DRVDONE, DRV_REL, DRVDONE, FILEDON, DRV_REL, DRV_REL, DRV_REL, DRV_REL, DRV_REL, REM_DRV, ERROR,
+/*MAC_SPC*/ MAC_SPC, MAC_SPC, MAC_SPC, ALLDON, MAC_SPC, MAC_SPC, MAC_SPC, MAC_SPC, MAC_SPC, MAC_SPC, MAC_SPC,
+/*DOS*/ ERROR, DOS, DOS, ALLDON, DOS, DOS, DOS, DOS, ERROR, ERROR, ERROR,
+/*IM_NAME*/ IM_NAME, IM_NAME, IM_NAME, IM_DONE, IM_NAME, IM_NAME, IM_NAME, IM_NAME, IM_NAME, IM_NAME, IM_NAME
+};
+#endif
+
+#if defined( FS_IMAGE )
+static INT16 FindImageDLE ( DLE_HAND, CHAR_PTR, GENERIC_DLE_PTR * ) ;
+#endif
+
+static INT16 FindDLE ( DLE_HAND, CHAR_PTR, GENERIC_DLE_PTR * ) ;
+static INT16 InitPathRoot( GENERIC_DLE_PTR dle,
+ CHAR_PTR path,
+ INT16 *pcb_psize,
+ INT16 cb_original_size ) ;
+
+static INT16 ValidateDirElem( CHAR_PTR str, INT16 fmt, INT name_is_dir ) ;
+
+/**/
+/**
+
+ Name: FS_ParsePath()
+
+ Description: The input_text is parsed and the remain parameter are
+ modified to reflect the contents of the input_text. The dle is
+ modified to point to the DLE which represents the drive specified
+ by the input_text. The path name in the input_text is copied in to
+ the memory pointed to by the path parameter. Likewise the file
+ name in the input_text is coppied in to the memory pointed to by
+ the file parameter. If the input_text specifies all the files in
+ a directory then the star_star parameter is set to TRUE otherwise
+ it is set to FALSE.
+
+ Note that if the input_text does not specify a drive then the
+ dle is set to the default DLE. If the input_test does specify
+ a drive but the drive cannot be found then an error is returned.
+
+
+ Modified: 7/20/1989
+
+ Returns: The return value is an error code. They are:
+ DRIVE_NOT_FOUND
+ ATTACH_TO_PARRENT
+ INVALID_PATH_DESCRIPTOR
+ INVALID_FILE_DESCRIPTOR
+ SUCCESS
+
+
+ Notes: If you pass NULL for DLE_HAND then this routine will
+ ignore any drive specification data.
+ If you pass NULL for the file name pointer then this
+ Routine assumes the path does not contain a file name.
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 FS_ParsePath( dle_hand, input_text, dle, path, psize, file, star_star )
+DLE_HAND dle_hand;
+CHAR_PTR input_text;
+GENERIC_DLE_PTR *dle ;
+CHAR_PTR path;
+INT16 *psize ;
+CHAR_PTR *file;
+BOOLEAN *star_star;
+{
+ INT16 state = INITIAL ;
+ INT16 cch_input_pos = 0 ; // char count offset into string
+ INT16 cch_buf_pos = 0 ; // char count offset into string
+ INT16 path_type = UNKNOWN ;
+ INT16 ret_val ;
+ INT16 ret_save = 0 ;
+ INT16 cb_original_size ; // byte length of string incl NULL term
+ CHAR character ;
+ int i;
+#if defined( OS_OS2 ) || defined( OS_WIN32 )
+ INT16 path_format = OS2_HPFS ;
+#else
+ INT16 path_format = DOS8_3 ;
+#endif
+
+ msassert( psize != NULL );
+ msassert( path != NULL );
+ msassert( ( dle_hand == NULL ) || ( dle != NULL ) ) ;
+
+ /* first skip over any initial './' */
+ while( (input_text[cch_input_pos] == TEXT ('.')) && ( input_text[cch_input_pos + 1] == TEXT ('\\') ) ) {
+ cch_input_pos +=2 ;
+ }
+
+ cb_original_size = *psize ;
+ if ( cb_original_size > 0 ) {
+ *path = TEXT ('\0') ;
+ }
+
+ *psize = 0 ;
+
+ while( (state != ERROR) && (state != ALLDON) && ( state != IM_DONE ) ) {
+
+ ret_val = INVALID_PATH_DESCRIPTOR ;
+
+ switch ( state ) {
+
+ case INITIAL:
+ case DRV_REL:
+
+ character = input_text[ cch_input_pos++ ] ;
+ path[ cch_buf_pos++ ] = character ;
+ if ( (UINT)character < 256 )
+ state = parse_table[ state] [ ascii[(UINT8)character] ];
+ else
+ state = parse_table[ state] [ ALETTER ];
+
+ if ( state == REM_DRV ) {
+
+ if ( cch_buf_pos == 1 ) {
+ path_type = REM_DRV ;
+ cch_buf_pos = 0 ;
+ state = DRV_REL ;
+ } else {
+ state = ERROR ;
+ }
+
+ } else if( state == MAC_SPC) {
+
+ path_format = MAC_SPEC ;
+ cch_buf_pos = 0 ;
+
+ } else if( ( state == DRVDONE ) && ( cch_buf_pos ==2 ) &&
+ isdigit( input_text[0] ) ) {
+
+ state = IM_NAME ;
+ }
+
+ break ;
+
+ case IM_NAME:
+ path_type = IM_NAME ;
+ character = input_text[ cch_input_pos++ ] ;
+ path[ cch_buf_pos++ ] = character ;
+ if ( (UINT)character < 256 )
+ state = parse_table[ state ][ ascii[(UINT8)character] ];
+ else
+ state = parse_table[ state ][ ALETTER ];
+
+ break ;
+
+
+
+ case FILEDON:
+ case DRVDONE:
+
+ ret_val = SUCCESS ;
+
+ if ( character == TEXT (':') ){
+
+ path[ cch_buf_pos ] = TEXT ('\0') ;
+ cch_buf_pos = 0;
+
+ #if defined( OS_OS2 ) || defined ( OS_WIN32 )
+ state = OS2 ;
+ path_format = OS2_HPFS ;
+ #endif
+
+ if ( dle_hand != NULL ) {
+ ret_val = FindDLE( dle_hand, path, dle ) ;
+ } else {
+ ret_val = DRIVE_DESCRIPTOR_ERROR ;
+ }
+
+ if( ret_val == FS_DEFAULT_SPECIFIED ) {
+ ret_save = ret_val ;
+ ret_val = SUCCESS ;
+ state = DOS ;
+
+ } else if ( ret_val != SUCCESS ) {
+ state = ERROR ;
+ break;
+
+ } else {
+ path_format = DOS8_3 ;
+ state = DOS ;
+
+ switch ( DLE_GetDeviceType( *dle ) ) {
+
+ case LOCAL_OS2_DRV :
+ case LOCAL_NTFS_DRV :
+
+#if defined( OS_OS2 ) || defined( OS_WIN32 )
+ path_format = OS2_HPFS ;
+ state = OS2 ;
+
+ if ( (*dle)->info.os2->fname_fmt == FAT_FNAME ) {
+ state = DOS ;
+ path_format = DOS8_3 ;
+ }
+#endif
+
+ break ;
+
+ case NOVELL_DRV :
+ case NOVELL_AFP_DRV :
+ if ( !((*dle)->info.nov->server_support & SUPPORT_386 ) ) {
+ state = DOS ;
+ path_format = NOV_14 ;
+ }
+ break ;
+
+ case NLM_VOLUME :
+ case NLM_AFP_VOLUME :
+ if ( !((*dle)->info.nlm->server_support & SUPPORT_386 ) ) {
+ state = DOS ;
+ path_format = NOV_14 ;
+ }
+ break ;
+
+ }
+
+ }
+
+ #if !defined( OS_OS2 ) && !defined ( OS_WIN32 )
+ state = DOS ;
+ #endif
+
+ } else { /* relative path with no drive specified */
+
+ #if defined( OS_OS2 ) || defined( OS_WIN32 )
+ path_type = OS2 ;
+ path_format = OS2_HPFS ;
+ #else
+ path_type = DOS ;
+ #endif
+
+ if ( dle_hand != NULL ) {
+
+ ret_val = FindDLE( dle_hand, NULL, dle ) ;
+
+ if ( ret_val != SUCCESS ) {
+ state = ERROR ;
+ break;
+#if defined( OS_OS2 ) || defined( OS_WIN32 )
+ } else {
+ if ( ( (*dle)->type != LOCAL_OS2_DRV ) || ( (*dle)->info.os2->fname_fmt == FAT_FNAME ) ) {
+ path_type = DOS ;
+ }
+#endif
+ }
+ }
+
+ if ( path[ cch_buf_pos-1 ] == TEXT ('.') ) {
+ path[ cch_buf_pos ] = TEXT ('\0') ;
+
+ } else {
+ path[ cch_buf_pos -1 ] = TEXT ('\0') ;
+ }
+
+ if (state != FILEDON ){
+ state = path_type ;
+ } else {
+ state = ALLDON ;
+ }
+ }
+
+ if ( dle_hand != NULL ) {
+
+ if ( input_text[cch_input_pos] != TEXT ('\\') ) {
+ if ( (cch_buf_pos != 1) || (path[0] == TEXT ('.') ) ) {
+ *psize = cch_buf_pos * sizeof (CHAR) ;
+ ret_val = InitPathRoot( *dle, path, psize, cb_original_size ) ;
+ cch_buf_pos = *psize / sizeof (CHAR);
+ }
+ }
+ }
+
+ if ( cch_buf_pos == 1 ) { /* will hapen if path start with '\' */
+ cch_buf_pos = 0 ;
+ }
+
+ if ( ret_val != SUCCESS ) {
+ state = ERROR ;
+ }
+
+ break ;
+
+ case DOS:
+ path_type = DOS ;
+
+ character = input_text[ cch_input_pos++ ] ;
+ if ( (UINT)character < 256 )
+ state = parse_table[ state ][ ascii[(UINT8)character] ];
+ else
+ state = parse_table[ state ][ ALETTER ];
+
+ if ( character != TEXT ('\\') ) {
+ path[ cch_buf_pos++ ] = character ;
+
+ } else if ( cch_buf_pos != 0 ) {
+
+ if ( path[ cch_buf_pos-1 ] != TEXT ('\0') ) {
+ path[ cch_buf_pos++ ] = TEXT ('\0');
+
+ } else {
+ state = ERROR ;
+ ret_val = INVALID_PATH_DESCRIPTOR ;
+ }
+
+ if( cch_buf_pos > 1 ) {
+
+ /* find start of this sub dir */
+ for ( i = cch_buf_pos - 2;
+ ((i!=0) && (path[i-1] != TEXT ('\0'))) ; i -- ) {
+ }
+
+ ret_val = ValidateDirElem( &path[i], path_format, DIR_ELEM_MID ) ;
+
+ if ( ret_val == BACK_ZERO_DIR ) {
+ cch_buf_pos -= 2 ;
+
+ } else if ( ret_val == BACK_ONE_DIR ) {
+
+ if ( i == 0 ) {
+ ret_val = INVALID_PATH_DESCRIPTOR ;
+ } else {
+ for ( i = (i-1) ; ((i!=0) && (path[i-1] != TEXT ('\0'))) ; i -- ) {
+ }
+ cch_buf_pos = (INT16)i ;
+ }
+ }
+
+ if ( ret_val != SUCCESS ) {
+ state = ERROR ;
+ }
+
+ }
+
+ }
+
+ break ;
+
+#if defined( OS_OS2 ) || defined(OS_WIN32)
+ case OS2:
+ path_type = OS2 ;
+
+ character = input_text[ cch_input_pos++ ] ;
+ if ( (UINT)character < 256 )
+ state = parse_table[ state ][ ascii[(UINT8)character] ];
+ else
+ state = parse_table[ state ][ ALETTER ];
+
+
+ if ( character != TEXT ('\\') ) {
+ path[ cch_buf_pos++ ] = character ;
+
+ } else if ( cch_buf_pos != 0 ) {
+
+ if ( path[ cch_buf_pos-1 ] != TEXT ('\0') ) {
+ path[ cch_buf_pos++ ] = TEXT ('\0');
+
+ } else {
+ state = ERROR ;
+ ret_val = INVALID_PATH_DESCRIPTOR ;
+ }
+
+ if( cch_buf_pos > 1 ) {
+
+ /* find start of this sub dir */
+ for (i = cch_buf_pos - 2; ((i!=0) && (path[i-1] != TEXT ('\0'))) ; i -- ) {
+ }
+
+ ret_val = ValidateDirElem( &path[i], path_format, DIR_ELEM_MID ) ;
+
+ if ( ret_val == BACK_ZERO_DIR ) {
+ cch_buf_pos -= 2 ;
+
+ } else if ( ret_val == BACK_ONE_DIR ) {
+
+ if ( i == 0 ) {
+ ret_val = INVALID_PATH_DESCRIPTOR ;
+ } else {
+ for ( i = i-1 ; ((i!=0) && (path[i-1] != TEXT ('\0'))) ; i -- ) {
+ }
+ cch_buf_pos = i ;
+ }
+ }
+
+ if ( ret_val != SUCCESS ) {
+ state = ERROR ;
+ }
+
+ }
+
+ }
+
+ break ;
+
+#endif
+ case MAC_SPC:
+ path_type = MAC_SPC ;
+
+ character = input_text[ cch_input_pos++ ] ;
+
+ if ( (UINT)character < 256 )
+ state = parse_table[ state ][ ascii[(UINT8)character] ];
+ else
+ state = parse_table[ state ][ ALETTER ];
+
+ if ( character != TEXT (':') ) {
+ path[ cch_buf_pos++ ] = character ;
+ } else {
+ path[ cch_buf_pos++ ] = TEXT ('\0');
+
+ /* check if valid directory name */
+ for (i = cch_buf_pos - 2; (i != 0 ) && (path[i-1] != TEXT ('\0')) ; i -- ) {
+ }
+
+ ret_val = ValidateDirElem( &path[i], path_format, DIR_ELEM_MID ) ;
+
+ if ( ( ret_val == BACK_ZERO_DIR ) ||
+ ( ret_val == BACK_ONE_DIR ) ) {
+
+ ret_val = INVALID_PATH_DESCRIPTOR ;
+
+ }
+
+ if ( ret_val != SUCCESS ) {
+ state = ERROR ;
+ }
+
+ }
+
+ break ;
+
+ } /* end switch */
+
+ if ( cch_buf_pos+1 > cb_original_size / (INT16) sizeof (CHAR) ) {
+ ret_val = FS_BUFFER_TO_SMALL ;
+ state = ERROR;
+ }
+
+ }
+
+
+ if ( state == ALLDON ) {
+
+ ret_val = SUCCESS ;
+
+ if ( ( path[0] == TEXT ('+') ) && ( path_format != MAC_SPEC ) && ( path_format != OS2_HPFS ) ) {
+
+ ret_val = INVALID_PATH_DESCRIPTOR ;
+
+ } else if ( file != NULL ) {
+
+ if ( cch_buf_pos <= 1 ) {
+ path[0] = TEXT ('\0') ;
+ strcpy( &path[1], TEXT("*.*") ) ;
+ cch_buf_pos = 3 ;
+
+ } else if ( path[ cch_buf_pos -2 ] == TEXT ('\0') ) {
+ strcpy( &path[ cch_buf_pos -1 ], TEXT("*.*") ) ;
+ cch_buf_pos += 2 ;
+ }
+
+ for (i = cch_buf_pos - 2;(i!=0) && (path[i-1] != TEXT ('\0')) ; i -- ) {
+ }
+
+ if ( i == 0 ) {
+ memmove( &path[1], path, cch_buf_pos++ * sizeof (CHAR) ) ;
+ path[0] = TEXT ('\0');
+ i = 1 ;
+ }
+
+ *psize = (INT16)i * sizeof( CHAR );
+
+
+ ret_val = ValidateDirElem( &path[i], path_format, FNAME_ELEM ) ;
+
+ if ( ret_val != SUCCESS ) {
+
+ ret_val = INVALID_FILE_DESCRIPTOR ;
+
+ }
+
+ *star_star = FALSE ;
+
+ if ( ret_val == SUCCESS ) {
+
+ *file = &path[ i ] ;
+
+ if ( !strncmp (*file, TEXT("*.*"),3 ) ) {
+ *star_star = TRUE ;
+ }
+
+ }
+ } else {
+
+ if ( cch_buf_pos <=1 ) {
+ cch_buf_pos = 2 ;
+ path[0] = TEXT ('\0') ;
+ path[1] = TEXT ('\0') ;
+ *psize = sizeof( CHAR );
+
+ } else if ( path[ cch_buf_pos - 2 ] == TEXT ('\0') ) {
+ cch_buf_pos -- ;
+ *psize = cch_buf_pos * sizeof (CHAR) ;
+ }
+
+ for (i = cch_buf_pos - 2; (i > 0 ) && (path[i-1] != TEXT ('\0')) ; i -- ) {
+ }
+
+ if ( i < 1 ) {
+
+ ret_val = ValidateDirElem( &path[i], path_format, DIR_ELEM_TRAIL ) ;
+
+ if ( ret_val != SUCCESS ) {
+ ret_val = INVALID_PATH_DESCRIPTOR ;
+ } else if ( *psize == 0 ) {
+ *psize = cch_buf_pos * sizeof (CHAR) ;
+ }
+ } else {
+
+ *psize = cch_buf_pos * sizeof (CHAR) ;
+ }
+
+ }
+
+ } else if ( state == IM_DONE ) {
+ *star_star = FALSE ;
+
+#if defined( FS_IMAGE )
+ ret_val = FindImageDLE ( dle_hand, path, dle ) ;
+
+ path[0] = TEXT ('\0') ;
+ path[1] = TEXT ('\0') ;
+
+ if ( file != NULL ) {
+ *file = path+1 ;
+ }
+ *psize = sizeof( CHAR );
+#else
+ ret_val = INVALID_PATH_DESCRIPTOR ;
+#endif
+ }
+
+
+ if( ( ret_val == SUCCESS ) && ( ret_save != 0 ) ) {
+ ret_val = ret_save ;
+ }
+
+ /*
+ if *path is TEXT ('\0') and psize is 0 then psize is 1
+ */
+ if ( ( *psize == 0 ) && ( *path == TEXT ('\0') ) ) {
+ *psize = sizeof( CHAR );
+ }
+
+ return( ret_val ) ;
+
+}
+/**/
+/**
+
+ Name: FindDLE()
+
+ Description: This function scans through the DLE list looking
+ for a DLE which has the name specified in the path.
+
+ Modified: 7/20/1989
+
+ Returns: Error codes
+ ATTACH_TO_PARENT
+ NO_DLE_FOUND
+ SUCCESS
+
+ Notes:
+
+ See also: $/SEE( FS_ParsePath() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+static INT16 FindDLE( dle_hand, path, dle )
+DLE_HAND dle_hand;
+CHAR_PTR path ;
+GENERIC_DLE_PTR *dle ;
+{
+ INT16 ret_val ;
+ CHAR_PTR pch;
+ CHAR_PTR pch2 = NULL ;
+
+ if ( ( path == NULL ) || ( *path == TEXT ('\0') ) ) {
+
+ *dle = dle_hand->default_drv ;
+ ret_val = SUCCESS ;
+
+ } else if ( !stricmp( path, TEXT("DEFAULT:") ) ) {
+ *dle = NULL ;
+ ret_val = FS_DEFAULT_SPECIFIED ;
+
+ } else {
+
+ ret_val = DLE_FindByName( dle_hand, path, ANY_DRIVE_TYPE, dle ) ;
+
+ if ( ret_val != SUCCESS ) {
+ pch = strchr( path, TEXT ('/') ) ;
+
+ /* search backwards up the dle names until we find a match */
+ do {
+
+ if ( pch2 != NULL ) {
+ *pch2 = TEXT( '\0' ) ;
+ }
+
+ pch = strrchr( path, TEXT ('/') ) ;
+
+ ret_val = DLE_FindByName( dle_hand, path, ANY_DRIVE_TYPE, dle ) ;
+
+ if ( ret_val == SUCCESS ) {
+ ret_val = FS_ATTACH_TO_PARENT ;
+ break ;
+ } else {
+ ret_val = FS_DEVICE_NOT_FOUND ;
+ }
+
+ if ( pch2 != NULL ) {
+ *pch2 = TEXT( '/' ) ;
+ }
+
+ pch2 = pch ;
+
+
+ } while ( pch != NULL ) ;
+
+ }
+ }
+ return ret_val ;
+}
+/**/
+/**
+
+ Name: InitPathRoot()
+
+ Description: This function gets the current directory for the
+ specified drive. For DOS drives this is the active directory
+ at MaynStream initialization time. For all other drives this
+ will be simply the root.
+
+ It is possible that our support of IBM PC NET will follow the
+ DOS functionality.
+
+ Modified: 8/14/1989
+
+ Returns: Error Codes
+ FS_BUFFER_TO_SMALL
+ SUCCESS
+
+ Notes: This function is only called from FS_ParsePath()
+
+ Possible input paths are in DOS relative path format.
+ for example: PROJ\MSII\TEST
+ The input path will never start with a '\'.
+
+ See also: $/SEE( FindDLE(), FS_ParsePath() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+static INT16 InitPathRoot(
+GENERIC_DLE_PTR dle, /* I - drive to get current dir for */
+CHAR_PTR path, /*I/O- Entry: path so far, Exit:new path */
+INT16 *pcb_psize, /*I/O- byte size of path on entry and exit*/
+INT16 original_size ) /* I - byte size of buffer for path string*/
+{
+ CHAR_PTR dos_path = NULL ;
+ CHAR dos_wk_space[260] ;
+ CHAR_PTR temp ;
+ INT16 cb_cur_path_leng ; //path buffer length in bytes w/ NULL term
+ INT16 ret_val = SUCCESS ;
+
+
+ if ( dle == NULL ) {
+ dos_path = dos_wk_space ;
+ dos_wk_space[0] = TEXT ('\0') ;
+
+ } else {
+
+ #if defined( OS_OS2 )
+ if( dle->type == LOCAL_OS2_DRV ) {
+
+ cb_cur_path_leng = 260 ;
+
+ if ( DosQCurDir( *(dle->device_name) - 0x40, dos_wk_space,
+ &cb_cur_path_leng ) == SUCCESS ) {
+
+ dos_path = dos_wk_space ;
+ }
+ }
+
+ #elif defined( OS_DOS )
+
+ if( dle->type == LOCAL_DOS_DRV ) {
+
+ union REGS inregs, outregs ;
+ struct SREGS sregs ;
+
+ inregs.x.ax = 0x4700 ;
+ temp = dos_wk_space ;
+ inregs.x.si = FP_OFF( temp ) ;
+ sregs.ds = FP_SEG( temp ) ;
+
+ /* need valid sregs pointers for windows */
+ sregs.es = FP_SEG( temp ) ;
+
+ inregs.h.dl = *(dle->device_name) - (UINT8)0x40 ;
+
+ intdosx( &inregs, &outregs, &sregs) ;
+
+ if( !outregs.x.cflag ) {
+ dos_path = temp ;
+ }
+ }
+ #elif defined( OS_WIN32 )
+ cb_cur_path_leng = 260 ;
+ dos_path = dos_wk_space ;
+ dos_wk_space[0] = TEXT ('\0') ;
+ #else
+
+ dos_path = dos_wk_space ;
+ dos_wk_space[0] = TEXT ('\0') ;
+
+ #endif
+ }
+
+ if ( dos_path != NULL ) {
+
+ cb_cur_path_leng = (INT16)(strsize ( dos_path ) ) ;
+
+ if ( cb_cur_path_leng + *pcb_psize > original_size ) {
+ ret_val = FS_BUFFER_TO_SMALL ;
+
+ } else {
+ memmove( &path[ cb_cur_path_leng ], path, *pcb_psize ) ;
+ memcpy( path, dos_path, cb_cur_path_leng ) ;
+ *pcb_psize += cb_cur_path_leng ;
+
+ temp = strchr(path, TEXT ('\\') ) ;
+ while ( temp != NULL ) {
+ *temp = TEXT ('\0') ;
+ temp = strchr( temp+1, TEXT ('\\') ) ;
+ }
+ }
+ }
+
+ return ret_val ;
+}
+
+#if defined( FS_IMAGE )
+/**/
+/**
+
+ Name: FindImageDLE()
+
+ Description: This function looks for a image partition using a stirng
+ of the following format :
+ n:[name].Px where n is the drive number;
+ x is the partition number and
+ name is the partition name.
+
+ if the name may be omitted. If the brackets [] are omitted
+ then the period must also be omitted.
+ the other leagal permutations are :
+
+ [].Px or n:Px or [name] or [name].Px
+ or n:[name]
+
+
+ Modified: 9/22/1989
+
+ Returns: Error Codes
+ NO_DLE_FOUND
+ SUCCESS
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+static INT16 FindImageDLE ( dle_hand, name, dle )
+DLE_HAND dle_hand ;
+CHAR_PTR name;
+GENERIC_DLE_PTR *dle ;
+{
+ INT16 drive_num = -1 ;
+ INT16 part_num = -1 ;
+ CHAR_PTR p ;
+ INT16 ret_val = SUCCESS ;
+
+ if ( isdigit( name[0] ) && ( name[1] == TEXT (':')) ) {
+
+ drive_num = name[0] - TEXT ('0') ;
+ }
+
+ p = strchr( name, TEXT ('[') ) ;
+
+ if ( p != NULL ) {
+ name = p + 1 ;
+ p = strchr( name, TEXT (']') ) ;
+
+ if (p != NULL ) {
+ *p = TEXT ('\0') ;
+
+ if ( p[1] == TEXT ('.') ) {
+ p = p+2;
+ }
+
+ } else {
+ ret_val = FAILURE ;
+ }
+ } else {
+ p = name ;
+ }
+ if ( ( p[0] ==TEXT ('P') ) && ( isdigit( p[1] ) ) ) {
+ part_num = p[1] - TEXT ('0') ;
+ }
+
+ if ( ret_val == SUCCESS ) {
+
+ if ( ( drive_num != -1 ) && ( part_num != -1 ) ) {
+
+ ret_val = DLE_GetFirst( dle_hand, dle ) ;
+
+ while ( ret_val == SUCCESS ) {
+
+ if ( (*dle)->type == LOCAL_IMAGE ) {
+
+ if ( ( ((*dle)->info.image->drive_num & 0x7f) == (INT8)drive_num ) &&
+ ( (*dle)->info.image->partition == (INT8)part_num ) ) {
+ break ;
+ }
+ }
+ ret_val = DLE_GetNext( dle ) ;
+ }
+
+ } else {
+
+ ret_val = DLE_FindByName( dle_hand, name, LOCAL_IMAGE, dle ) ;
+
+ }
+
+ }
+
+ if ( ret_val != SUCCESS ) {
+ ret_val = FS_DEVICE_NOT_FOUND;
+ }
+
+ return ret_val ;
+}
+
+#endif /* FS_IMAGE */
+
+static INT16 ValidateDirElem(
+CHAR_PTR str,
+INT16 fmt,
+INT name_is_dir )
+{
+ CHAR_PTR p ;
+ CHAR_PTR s ;
+ INT16 cch_dir_leng ; //number of chars in str (strlen)
+ INT16 ret_val = SUCCESS ;
+
+ cch_dir_leng = (INT16)strlen( str ) ;
+
+ if ( ( name_is_dir == DIR_ELEM_MID ) && ( cch_dir_leng == 0 ) ) {
+
+ ret_val = INVALID_PATH_DESCRIPTOR ;
+
+ } else {
+
+ switch ( fmt ) {
+
+ case NOV_14:
+ case DOS8_3:
+
+ if ( cch_dir_leng > 14 ) {
+ ret_val = INVALID_PATH_DESCRIPTOR ;
+ }
+
+ p = strchr( str, TEXT ('.') ) ;
+
+ if ( p != NULL ) {
+
+ if ( ( fmt == DOS8_3 ) || !name_is_dir ) {
+
+ if( ( p - ( str ) > 8 ) ||
+ ( strlen( p ) > 4 ) ||
+ ( cch_dir_leng > 12 ) ) {
+
+ ret_val = INVALID_PATH_DESCRIPTOR ;
+ }
+ }
+
+ } else {
+ if ( ( fmt == DOS8_3 ) || !name_is_dir ) {
+ if ( strlen( str ) > 8 ) {
+ ret_val = INVALID_PATH_DESCRIPTOR ;
+ }
+ }
+ }
+
+ if ( strcspn( str, TEXT("<>\"\\/:;,=+|[]") ) != (size_t)cch_dir_leng ) {
+
+ ret_val = INVALID_PATH_DESCRIPTOR ;
+ }
+
+
+ if ( name_is_dir ) {
+ if ( strchr( str, TEXT ('*') ) || strchr( str, TEXT ('?') ) ) {
+
+ ret_val = INVALID_PATH_DESCRIPTOR ;
+ }
+
+ if ( ( ret_val == SUCCESS ) && !strcmp( str, TEXT(".") ) ) {
+ ret_val = BACK_ZERO_DIR ;
+ }
+
+ if ( ( ret_val == SUCCESS ) && !strcmp( str, TEXT("..") ) ) {
+ ret_val = BACK_ONE_DIR ;
+
+ }
+ }
+
+ break ;
+
+ case OS2_HPFS:
+
+ if ( cch_dir_leng > 256 ) {
+ ret_val = INVALID_PATH_DESCRIPTOR ;
+ }
+
+ if ( strcspn( str, TEXT("<>\"\\/") ) != strlen( str ) ) {
+ ret_val = INVALID_PATH_DESCRIPTOR ;
+ }
+
+ if ( name_is_dir ) {
+
+ if ( strchr( str, TEXT ('*') ) || strchr( str, TEXT ('?') ) ) {
+ ret_val = INVALID_PATH_DESCRIPTOR ;
+ }
+
+ if ( ( ret_val == SUCCESS ) && !strcmp( str, TEXT(".") ) ) {
+ ret_val = BACK_ZERO_DIR ;
+ }
+
+ if ( ( ret_val == SUCCESS ) && !strcmp( str, TEXT("..") ) ) {
+ ret_val = BACK_ONE_DIR ;
+ }
+ }
+ break ;
+
+ case MAC_SPEC:
+ if ( cch_dir_leng > 32 ) {
+ ret_val = INVALID_PATH_DESCRIPTOR ;
+ }
+ break ;
+ }
+
+ }
+
+ return ret_val ;
+
+}
+
diff --git a/private/utils/ntbackup/src/passdb.c b/private/utils/ntbackup/src/passdb.c
new file mode 100644
index 000000000..a1e3443b3
--- /dev/null
+++ b/private/utils/ntbackup/src/passdb.c
@@ -0,0 +1,383 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: passdb.c
+
+ Description: The Password Database Interface offers the following
+ functionality: PD_Open, PD_Close,
+ PD_Read, and PD_Write.
+
+ $Log: G:/UI/LOGFILES/PASSDB.C_V $
+
+ Rev 1.13 28 Jul 1993 14:41:04 DARRYLP
+
+ Rev 1.12 26 Jul 1993 18:25:30 MARINA
+enable c++
+
+ Rev 1.11 01 Nov 1992 16:04:24 DAVEV
+Unicode changes
+
+ Rev 1.10 07 Oct 1992 14:54:20 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.9 04 Oct 1992 19:39:38 DAVEV
+Unicode Awk pass
+
+ Rev 1.8 30 Sep 1992 10:45:48 DAVEV
+Unicode strlen verification, MikeP's chgs from MS
+
+ Rev 1.7 28 Jul 1992 14:43:16 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.6 27 Jul 1992 11:10:30 JOHNWT
+ChuckB checked in for John Wright, who is no longer with us.
+
+ Rev 1.5 14 May 1992 17:24:10 MIKEP
+nt pass 2
+
+ Rev 1.4 18 Mar 1992 16:57:36 JOHNWT
+*** TOTALLY NEW CODE ***
+
+ Rev 1.3 21 Jan 1992 13:50:48 JOHNWT
+remove partially created/init file
+
+ Rev 1.2 20 Dec 1991 09:33:34 DAVEV
+16/32 bit port - 2nd pass
+
+ Rev 1.1 04 Dec 1991 15:21:14 MIKEP
+remoce pwxface.h
+
+ Rev 1.0 20 Nov 1991 19:20:14 SYSTEM
+Initial revision.
+
+*****************************************************************************/
+
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+static UINT16 PD_WriteThePassword( DB_HAND_PTR pd_hnd, CHAR_PTR key, CHAR_PTR pswd ) ;
+static UINT16 PD_GetTheRecordNumber( DB_HAND_PTR pd_hnd, CHAR_PTR key ) ;
+
+/*****************************************************************************
+
+ Name: PD_Open
+
+ Description: PD_Open provides the caller with a database file_ptr for the
+ given file. If the file does not exist, it will be created.
+
+ Modified: 9/18/1989 3/12/1992
+
+ Returns: The database file_ptr is NULL if an error occurs opening the file.
+ The following errors are returned:
+ PD_RECORD_LENGTH_INVALID, PD_MEMORY_ERROR, PD_FILE_FAILED_INIT, PD_READ_ERROR,
+ PD_REBUILD_ERROR, and PD_NO_ERROR.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+*****************************************************************************/
+
+UINT16 PD_Open(
+ DB_HAND_PTR pd_hnd , /* O - file pointer to the PWDatabase */
+ CHAR_PTR pwd_name ) /* I - Name of PWDatabase file to open */
+{
+
+ /* clear the file pointer */
+ pd_hnd->fhand = NULL ;
+
+ /* open the specified "existing" database file */
+ if( ( pd_hnd->fhand = UNI_fopen( pwd_name, 0) ) == NULL ) {
+
+ return (UINT16) PD_FILE_OPEN_ERROR ;
+ }
+
+ return PD_NO_ERROR ;
+}
+
+/*****************************************************************************
+
+ Name: PD_Close
+
+ Description: PD_Close attempts to close the file and free the memory associated with
+ the handle.
+
+ Modified: 9/18/1989
+
+ Returns: The following error values are returned PD_NULL_HANDLE, PD_NO_ERROR, and
+ PD_CLOSE_ERROR.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+*****************************************************************************/
+
+UINT16 PD_Close(
+ DB_HAND_PTR pd_hnd ) /* I - Close and free memory */
+{
+
+ /* validate pwd file pointer */
+ if( pd_hnd->fhand == NULL ) {
+ return (UINT16) PD_NULL_HANDLE ;
+ }
+
+ /* close the password database file */
+ if( !fclose( pd_hnd->fhand ) ) {
+
+ pd_hnd->fhand = NULL ;
+ return PD_NO_ERROR ;
+
+ } else {
+ return (UINT16) PD_CLOSE_ERROR ;
+ }
+}
+
+/*****************************************************************************
+
+ Name: PD_Write
+
+ Description: PD_Write places the given key and password into the password
+ database. If the password already exist, it is over written.
+
+ Modified: 9/18/1989
+
+ Returns: The following error values are returned: PD_NO_ERROR, PD_WRITE_ERROR,
+ PD_READ_ERROR, PD_FULL.
+
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+*****************************************************************************/
+
+UINT16 PD_Write(
+ DB_HAND_PTR pd_hnd , /* I - PWDatabase file pointer */
+ CHAR_PTR key , /* I - Key -- Server/User/Alias name */
+ CHAR_PTR pswd ) /* I - Password */
+{
+ UINT16 error ;
+
+ /* validate pwd file pointer */
+ if( pd_hnd->fhand == NULL ) {
+ return (UINT16) PD_NULL_HANDLE ;
+ }
+
+ PD_GetTheRecordNumber( pd_hnd, key ) ;
+
+ /* add a new record */
+ error = PD_WriteThePassword( pd_hnd, key, pswd ) ;
+
+ return error ;
+}
+
+/*****************************************************************************
+
+ Name: WritePasswordFile
+
+ Description: Checks the length of the key and password before writing it to the Password
+ Database.
+
+ Modified: 9/18/1989
+
+ Returns: PD_NO_ERROR and PD_EXCEEDED_RECORD_LENGTH
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+*****************************************************************************/
+
+static UINT16 PD_WriteThePassword(
+ DB_HAND_PTR pd_hnd , /* I - Required DB handle */
+ CHAR_PTR key , /* I - Server/User name */
+ CHAR_PTR pswd ) /* I - Password */
+{
+
+ UINT8 password_size ; /* size of password */
+
+
+ /* Seek to record number */
+
+ fseek( pd_hnd->fhand,
+ ((INT32)(MAX_PSWD_RECORD_SIZE * sizeof (CHAR))) * pd_hnd->record_number,
+ SEEK_SET ) ;
+
+
+ /* Initialize the pad amount */
+ memset( pd_hnd->buffer, TEXT('Û'), MAX_PSWD_RECORD_SIZE * sizeof (CHAR) ) ;
+
+ /* get the password size */
+ password_size = (UINT8)( strsize( pswd ) - sizeof (CHAR) ) ;
+
+
+ /* 1 the byte for storing the password size */
+
+ if( (INT16)( strsize( key ) + password_size + 1 ) <= MAX_PSWD_RECORD_SIZE ) {
+
+ /* fill the buffer */
+ memcpy( pd_hnd->buffer, key, strsize ( key ) ) ;
+
+ pd_hnd->buffer[strlen( key )] = TEXT('\0') ;
+
+ /* encrypt the password */
+ CryptPassword( (INT16) ENCRYPT, ENC_ALGOR_3, (INT8_PTR)pswd, (INT16) password_size ) ;
+
+ memcpy( &(pd_hnd->buffer)[ ( strlen( key ) + 1 ) ],
+ &password_size, 1 ) ;
+
+ memcpy( &(pd_hnd->buffer)[ ( strlen( pd_hnd->buffer ) + 2 ) ],
+ pswd, password_size ) ;
+
+
+ /* write the buffer to file */
+ fwrite( pd_hnd->buffer, MAX_PSWD_RECORD_SIZE*sizeof(CHAR), 1, pd_hnd->fhand ) ;
+ if( ferror( pd_hnd->fhand ) ) {
+ return (UINT16) PD_WRITE_ERROR ;
+ }
+
+ return PD_NO_ERROR ;
+
+ }
+
+ return (UINT16) PD_EXCEEDED_RECORD_LENGTH ;
+
+}
+
+/*****************************************************************************
+
+ Name: PD_Read
+
+ Description: PD_Read matches the given key to the key and password in
+ the database. The password is copied to the pswd parameter.
+
+
+ Modified: 9/18/1989
+
+ Returns: The following error values : PD_NULL_HANDLE, PD_MEMORY_ERROR,
+ PD_READ_ERROR, PD_NOT_FOUND, and PD_NO_ERROR.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+*****************************************************************************/
+
+INT16 PD_Read(
+ DB_HAND_PTR pd_hnd , /* I - PWDatabase file pointer */
+ CHAR_PTR key , /* I - key -- Server/User/Alias name */
+ CHAR_PTR pswd ) /* O - password */
+{
+
+ CHAR tmp_pwd[MAX_PSWD_SIZE] ; /* current password */
+ UINT16 error ; /* return value */
+ UINT8 pswd_size ; /* size of the password */
+
+ /* validate file pointer */
+ if( pd_hnd->fhand == NULL ) {
+ return PD_NULL_HANDLE ;
+ }
+
+ error = PD_GetTheRecordNumber( pd_hnd, key ) ;
+
+ if( error == PD_NO_ERROR ) {
+
+ /* Retrieve the password */
+ memcpy( &pswd_size, &(pd_hnd->buffer)[ ( strlen( pd_hnd->buffer ) + 1 ) ], 1 ) ;
+
+ memcpy( tmp_pwd, &(pd_hnd->buffer)[ ( strlen( pd_hnd->buffer ) + 2 ) ], pswd_size ) ;
+
+ CryptPassword( (INT16) DECRYPT, ENC_ALGOR_3, (INT8_PTR)tmp_pwd, (INT16) pswd_size ) ;
+
+ memcpy( pswd, tmp_pwd, pswd_size ) ;
+
+ pswd[ pswd_size/sizeof(CHAR) ] = TEXT('\0') ;
+
+ }
+ return error ;
+}
+
+/*****************************************************************************
+
+ Name: PD_GetTheRecordNumber
+
+ Description: Performs a linear search of the password database file and
+ attempts to match the key.
+
+
+ Modified: 3/11/1992
+
+ Returns: The following error values :
+ PD_NOT_FOUND, and PD_NO_ERROR.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+*****************************************************************************/
+
+UINT16 PD_GetTheRecordNumber(
+ DB_HAND_PTR pd_hnd, /* I - PWDatabase file pointer */
+ CHAR_PTR key ) /* I - key -- Server/User/Alias name */
+{
+
+ UINT16 cmp_error ; /* compare error variable */
+
+
+ /* ensure that the ptr is at the beginning of file */
+ fseek( pd_hnd->fhand , 0L, SEEK_SET ) ;
+
+ /* Set the record number */
+ pd_hnd->record_number = 0 ;
+
+ /* match key name */
+ while( !feof( pd_hnd->fhand ) ) {
+
+ /* fill buffer */
+ fread( pd_hnd->buffer, MAX_PSWD_RECORD_SIZE*sizeof(CHAR), 1, pd_hnd->fhand ) ;
+ if( ferror( pd_hnd->fhand ) ){
+
+ clearerr( pd_hnd->fhand ) ;
+ return (UINT16) PD_READ_ERROR ;
+ }
+
+ /* match the key name */
+ cmp_error = strcmpi( pd_hnd->buffer, key ) ;
+ if( ( cmp_error == 0 ) ) {
+
+ return PD_NO_ERROR ;
+ }
+
+ /* if eof, return */
+ if ( feof( pd_hnd->fhand ) ) {
+
+ return (UINT16) PD_NOT_FOUND;
+
+ }
+
+ /* Increment the record number */
+ pd_hnd->record_number++ ;
+
+ }
+
+ return (UINT16) PD_NOT_FOUND ;
+
+}
diff --git a/private/utils/ntbackup/src/password.c b/private/utils/ntbackup/src/password.c
new file mode 100644
index 000000000..3e6281682
--- /dev/null
+++ b/private/utils/ntbackup/src/password.c
@@ -0,0 +1,813 @@
+
+
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: password.c
+
+ Description:
+
+ Code to handle tape/bset passwords.
+
+ $Log: J:/UI/LOGFILES/PASSWORD.C_V $
+
+ Rev 1.35 24 Mar 1994 15:29:30 GREGG
+Initialize temp size parameter passed into MapAnsiToUnicNoNull.
+
+ Rev 1.34 21 Mar 1994 12:39:58 STEVEN
+fix mapuin bugs
+
+ Rev 1.33 18 Mar 1994 14:33:38 chrish
+Added change to allow unicode ORCAS to read ANSI ORCAS tapes that
+were backed up with restrict accessed to owner.
+
+ Rev 1.32 02 Feb 1994 17:28:18 chrish
+Added changes for the UNICODE version of the app to handle ANSI
+secured tapes.
+
+ Rev 1.31 17 Jan 1994 15:05:46 MIKEP
+fix more unicode warnings
+
+ Rev 1.30 24 Nov 1993 15:28:52 BARRY
+Fix Unicode warnings
+
+ Rev 1.29 26 Jul 1993 18:35:48 MARINA
+enable c++
+
+ Rev 1.28 08 Apr 1993 17:20:10 chrish
+Made change to check for tape passworded by Cayman.
+
+
+ Rev 1.27 22 Mar 1993 13:47:08 chrish
+Made changes to VerifyTapePassword routine for CAYMAN.
+
+ Rev 1.26 17 Mar 1993 16:31:02 chrish
+Made change to VerifyTapePassword routine, since we change the security
+privilege checking.
+
+ Rev 1.25 10 Mar 1993 17:19:54 chrish
+Added another paramater passed to DM_GetTapePswd.
+
+ Rev 1.24 22 Feb 1993 11:12:08 chrish
+Added changes received from MikeP.
+Check to see if the user is an administrator when checking to see if
+password matches. This allows administrator to access any tape. Now
+that I think about it, this wil need changing for Cayman, so admin's
+can't access one of our real tape password.
+
+ Rev 1.23 07 Jan 1993 13:25:00 chrish
+Added tape security for full catalog.
+
+ Rev 1.22 13 Nov 1992 17:10:24 chrish
+Minor change for Tape Security stuff inside VerifyTapePassword routine
+
+ Rev 1.21 01 Nov 1992 16:04:40 DAVEV
+Unicode changes
+
+ Rev 1.20 07 Oct 1992 14:54:34 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.19 05 Oct 1992 14:22:10 DAVEV
+cbPasswordSize
+
+ Rev 1.18 05 Oct 1992 14:02:12 DAVEV
+fix password struct names
+
+ Rev 1.17 04 Oct 1992 19:39:40 DAVEV
+Unicode Awk pass
+
+ Rev 1.16 30 Sep 1992 10:45:14 DAVEV
+Unicode strlen verification, MikeP's chgs from MS
+
+ Rev 1.15 10 Sep 1992 17:45:32 DAVEV
+Integrate MikeP's changes from Microsoft
+
+ Rev 1.14 06 Aug 1992 13:17:18 CHUCKB
+Changes for NT.
+
+ Rev 1.13 28 Jul 1992 15:05:18 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.12 07 Jul 1992 15:50:38 MIKEP
+unicode changes
+
+ Rev 1.11 14 May 1992 17:23:54 MIKEP
+nt pass 2
+
+ Rev 1.10 02 Mar 1992 16:26:22 CHUCKB
+Fixed length of password in CollectTapePassword.
+
+ Rev 1.9 08 Feb 1992 16:48:14 MIKEP
+fix mac passwords
+
+ Rev 1.8 03 Feb 1992 16:52:46 CHUCKB
+In function VerifyTapePassword, changed size of array password to MAX_..._SIZE instead of ..._LEN.
+
+ Rev 1.7 23 Jan 1992 13:10:34 CARLS
+fixed password problems
+
+ Rev 1.6 13 Jan 1992 17:22:16 CARLS
+added call to JobStatusBackupRestore for Tape
+password cancel
+
+ Rev 1.5 20 Dec 1991 09:34:12 DAVEV
+16/32 bit port - 2nd pass
+
+ Rev 1.4 06 Dec 1991 15:38:38 CHUCKB
+No change.
+
+ Rev 1.3 04 Dec 1991 14:54:08 CARLS
+changed return value from TRUE to FALSE if prompting id disabled
+
+ Rev 1.2 03 Dec 1991 20:49:04 MIKEP
+macros & headers
+
+ Rev 1.1 22 Nov 1991 08:47:00 MIKEP
+structure changes in tape_object
+
+ Rev 1.0 20 Nov 1991 19:34:08 SYSTEM
+Initial revision.
+
+****************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+LOCALVAR Q_HEADER tape_pswd_list;
+
+/* prototypes for internal functions */
+
+LOCALFN BOOLEAN MatchOldPassword( INT8_PTR, INT16 );
+
+#ifdef OEM_MSOFT
+ LOCALFN BOOLEAN CompareTapePswdToCurrentPaswd(
+ INT8_PTR tape_password, /* tape password in NULL terminated string*/
+ INT16 tape_password_size ); /* length of tape_password in BYTES */
+#endif
+
+
+/**********************
+
+ NAME : PSWD_CheckForPassword
+
+ DESCRIPTION :
+
+ Checks the given tape/bset combination for read permission. Returns
+ success if no password is present, the password has already been
+ entered or the user entered the correct password after he was prompted.
+
+ RETURNS : SUCCESS or FAILURE
+
+**********************/
+
+INT16 PSWD_CheckForPassword( UINT32 tape_fid, INT16 bset_num )
+{
+ TAPE_OBJECT_PTR tape;
+ BSET_OBJECT_PTR bset;
+ INT16 status;
+
+ // See if this tape has a password
+
+ tape = VLM_GetFirstTAPE( );
+
+ while ( tape ) {
+
+ if ( TAPE_GetFID( tape ) == tape_fid ) {
+ break;
+ }
+ tape = VLM_GetNextTAPE( tape );
+ }
+
+ if ( tape == NULL ) {
+ return( FAILURE );
+ }
+
+ bset = VLM_GetFirstBSET( &TAPE_GetBsetQueue( tape ) );
+
+ while ( bset != NULL ) {
+
+ if ( BSET_GetBsetNum( bset ) == bset_num ) {
+ break;
+ }
+ bset = VLM_GetNextBSET( bset );
+ }
+
+ if ( bset == NULL ) {
+ return( FAILURE );
+ }
+
+ if ( BSET_GetPswdSize( bset ) == 0 ) {
+ return( SUCCESS );
+ }
+
+ if ( BSET_GetBsetPswd( bset ) ) {
+
+ status = VerifyTapePassword( TAPE_GetName( tape ),
+ BSET_GetName( bset ),
+ BSET_GetUserName( bset ),
+ (UINT16) BSET_GetEncryptAlgor( bset ),
+ NULL,
+ (INT16) 0,
+ (INT8_PTR)BSET_GetPassword( bset ),
+ (INT16) BSET_GetPswdSize( bset ),
+ tape_fid );
+ }
+ else {
+
+ status = VerifyTapePassword( TAPE_GetName( tape ),
+ BSET_GetName( bset ),
+ BSET_GetUserName( bset ),
+ (UINT16) BSET_GetEncryptAlgor( bset ),
+ (INT8_PTR)BSET_GetPassword( bset ),
+ (INT16) BSET_GetPswdSize( bset ),
+ NULL,
+ (INT16) 0,
+ tape_fid );
+ }
+
+ if ( status == TRUE ) { /* if passwords matched - set return code to SUCCESS */
+ status = SUCCESS;
+ }
+ else {
+ status = FAILURE;
+ }
+
+ return( status );
+}
+
+/**********************
+
+ NAME : PSWD_GetFirstPSWD
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+PSWD_OBJECT_PTR PSWD_GetFirstPSWD( )
+{
+ Q_ELEM_PTR q_elem_ptr;
+
+ q_elem_ptr = QueueHead( &tape_pswd_list );
+
+ if ( q_elem_ptr != NULL ) {
+ return (PSWD_OBJECT_PTR)( q_elem_ptr->q_ptr ) ;
+ }
+
+ return( NULL );
+}
+
+/**********************
+
+ NAME : PSWD_GetNextPSWD
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+PSWD_OBJECT_PTR PSWD_GetNextPSWD( PSWD_OBJECT_PTR pswd )
+{
+ Q_ELEM_PTR q_elem_ptr;
+
+ q_elem_ptr = QueueNext( &(pswd->q_elem) );
+
+ if ( q_elem_ptr != NULL ) {
+ return (PSWD_OBJECT_PTR)( q_elem_ptr->q_ptr ) ;
+ }
+
+ return( NULL );
+}
+
+/**********************
+
+ NAME : PSWD_AddPassword
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT16 PSWD_AddPassword(
+INT8_PTR pszPassword,
+INT16 cbPasswordLen,
+UINT16 algor,
+UINT32 tape_fid )
+{
+ PSWD_OBJECT_PTR pswd;
+
+ pswd = (PSWD_OBJECT_PTR)malloc( sizeof( PSWD_OBJECT ) );
+
+ if ( pswd != NULL ) {
+ pswd->q_elem.q_ptr = pswd;
+ memcpy( pswd->achPassword, pszPassword, cbPasswordLen );
+ pswd->cbPasswordSize = cbPasswordLen;
+ pswd->encrypt_algor = algor;
+ pswd->tape_fid = tape_fid;
+ EnQueueElem( &tape_pswd_list, &(pswd->q_elem), FALSE );
+ return( SUCCESS );
+ }
+
+ return( FAILURE );
+}
+
+/**********************
+
+ NAME : PSWD_InitPSWDList
+
+ DESCRIPTION :
+
+ RETURNS : nothing.
+
+**********************/
+
+INT16 PSWD_InitPSWDList( )
+{
+
+ InitQueue( &tape_pswd_list );
+ return( SUCCESS );
+}
+
+/**********************
+
+ NAME : PSWD_FreePSWDList
+
+ DESCRIPTION :
+
+ A function that hasn't been done yet.
+
+ RETURNS : nothing.
+
+**********************/
+
+INT16 PSWD_FreePSWDList( )
+{
+
+ return( SUCCESS );
+}
+
+
+/**********************
+
+ NAME : VerifyTapePassword
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+BOOLEAN VerifyTapePassword(
+CHAR_PTR tape_name,
+CHAR_PTR bset_name,
+CHAR_PTR user_name,
+UINT16 encrypt_algor,
+INT8_PTR tape_password, /* tape password in NULL terminated string*/
+INT16 tape_password_size, /* length of tape_password in BYTES */
+INT8_PTR bset_password, /* BSET password in NULL terminated string*/
+INT16 bset_password_size, /* length of bset_password in BYTES */
+UINT32 tape_fid )
+{
+ PSWD_OBJECT_PTR pswd;
+ CHAR password[ MAX_TAPE_PASSWORD_SIZE ];
+ BOOLEAN status = FALSE;
+ CHAR buffer[ MAX_UI_RESOURCE_SIZE ]; // chs:04-08-93
+ CHAR buffer2[ MAX_UI_RESOURCE_SIZE ]; // chs:04-08-93
+
+
+#ifdef OEM_MSOFT
+
+ if ( ( WhoPasswordedTape( tape_password, tape_password_size ) == OTHER_APP ) || // chs:04-08-93
+ ( WhoPasswordedTape( bset_password, bset_password_size ) == OTHER_APP ) ) { // chs:04-08-93
+ // chs:04-08-93
+ // // chs:04-08-93
+ // Popup dialog box message if // chs:04-08-93
+ // not a valid user // chs:04-08-93
+ // // chs:04-08-93
+ // chs:04-08-93
+ RSM_StringCopy( IDS_GENERAL_TAPE_SECURITY, buffer, sizeof(buffer) ); // chs:04-08-93
+ RSM_StringCopy( IDS_TAPE_SECURITY_TITLE, buffer2, sizeof(buffer2) ); // chs:04-08-93
+ WM_MsgBox( buffer2, buffer, WMMB_OK | WMMB_NOYYCHECK, WMMB_ICONEXCLAMATION ); // chs:04-08-93
+ return ( FALSE ); // chs:04-08-93
+ } // chs:04-08-93
+
+ switch ( gbCurrentOperation ) { // chs:03-15-93
+ // chs:03-15-93
+ case OPERATION_BACKUP: // chs:03-15-93
+ // chs:03-15-93
+ if ( DoesUserHaveThisPrivilege( TEXT( "SeBackupPrivilege" ) ) ) { // chs:03-15-93
+ return( TRUE ); // chs:03-15-93
+ } // chs:03-15-93
+ break; // chs:03-15-93
+ // chs:03-15-93
+ case OPERATION_RESTORE: // chs:03-15-93
+ case OPERATION_CATALOG: // chs:03-15-93
+ if ( DoesUserHaveThisPrivilege( TEXT( "SeRestorePrivilege" ) ) ) { // chs:03-15-93
+ return( TRUE ); // chs:03-15-93
+ } // chs:03-15-93
+ break; // chs:03-15-93
+ // chs:03-15-93
+ default: // chs:03-15-93
+ return( TRUE ); // chs:03-15-93
+ break; // chs:03-15-93
+ // chs:03-15-93
+ } // chs:03-15-93
+
+#endif
+
+ if ( tape_password_size != 0 ) {
+
+ // See if it's in our list already
+
+ pswd = PSWD_GetFirstPSWD();
+
+ while ( pswd != NULL ) {
+
+ if ( ( encrypt_algor == pswd->encrypt_algor ) &&
+ ( tape_fid == pswd->tape_fid ) &&
+ ( (UINT16)tape_password_size == pswd->cbPasswordSize ) ) {
+
+ if ( ! memcmp( pswd->achPassword, tape_password, tape_password_size ) ) {
+ return( TRUE );
+ }
+ }
+
+ pswd = PSWD_GetNextPSWD( pswd );
+ }
+
+ // Ask user for it
+
+ memcpy( password, tape_password, tape_password_size );
+
+ CryptPassword( (INT16) DECRYPT, encrypt_algor, (INT8_PTR)password, tape_password_size );
+
+ password[ tape_password_size / sizeof (CHAR) ] = TEXT( '\0' );
+
+ if ( strlen( password ) == 0 ) {
+
+ // I have a maxstream tape that says the password is 8 characters
+ // long but it is all zero's.
+
+ return( TRUE );
+ }
+
+#ifndef OEM_MSOFT
+ status = DM_GetTapePswd( tape_name, NULL, NULL, password, tape_password_size ); // chs:03-10-93
+#else
+ status = FALSE;
+#endif /* OEM_MSOFT */
+
+ // If it was good enter it into our list
+
+ if ( status == TRUE && password[0] != NTPASSWORDPREFIX ) { // chs:04-08-93
+ // clear right answer out of memory // chs:03-22-93
+ // chs:03-22-93
+ memset( password, 0, sizeof (password) ); // chs:03-22-93
+ // chs:03-22-93
+ PSWD_AddPassword( tape_password, tape_password_size, encrypt_algor, tape_fid ); // chs:03-22-93
+ } // chs:03-22-93
+
+ }
+
+ if ( bset_password_size != 0 ) {
+
+ // See if it's in our list already
+
+ pswd = PSWD_GetFirstPSWD();
+
+ while ( pswd != NULL ) {
+
+ if ( ( encrypt_algor == pswd->encrypt_algor ) &&
+ ( tape_fid == pswd->tape_fid ) &&
+ ( (UINT16)bset_password_size == pswd->cbPasswordSize ) ) {
+
+ if ( ! memcmp( pswd->achPassword, bset_password, bset_password_size ) ) {
+ return( TRUE );
+ }
+ }
+
+ pswd = PSWD_GetNextPSWD( pswd );
+ }
+
+ // Ask user for it
+
+ memcpy( password, bset_password, bset_password_size );
+
+ CryptPassword( (INT16) DECRYPT, encrypt_algor, (INT8_PTR)password, bset_password_size );
+
+ password[ bset_password_size / sizeof (CHAR) ] = 0;
+
+#ifndef OEM_MSOFT
+ status = DM_GetTapePswd( tape_name, bset_name, user_name, password, bset_password_size ); // chs:03-10-93
+#else
+ status = FALSE;
+#endif /* OEM_MSOFT */
+
+
+ // If it was good enter it into our list
+
+ if ( status == TRUE && password[0] != NTPASSWORDPREFIX ) { // chs:04-08-93
+ // clear right answer out of memory // chs:03-22-93
+ // chs:03-22-93
+ memset( password, 0, sizeof (password) ); // chs:03-22-93
+ // chs:03-22-93
+ PSWD_AddPassword( bset_password, bset_password_size, encrypt_algor, tape_fid ); // chs:03-22-93
+ } // chs:03-22-93
+
+
+
+ }
+
+
+#ifdef OEM_MSOFT
+{
+
+ // Microsoft only supports tape passwords.
+
+ if ( status == FALSE ) {
+
+ INT8_PTR temp_password = ( INT8_PTR )calloc( 1, tape_password_size + ( 2 * sizeof( CHAR ) ) );
+
+ if ( !temp_password ) { return( FALSE ); }
+
+ memcpy( temp_password, tape_password, tape_password_size );
+
+ CryptPassword( (INT16)DECRYPT, (UINT16)encrypt_algor, temp_password, (INT16)tape_password_size );
+
+ status = CompareTapePswdToCurrentPaswd(
+ temp_password,
+ (INT16)tape_password_size );
+
+ if ( status != TRUE ) {
+
+ //
+ // Popup dialog box message if
+ // not a valid user
+ //
+
+ RSM_StringCopy( IDS_GENERAL_TAPE_SECURITY, buffer, sizeof(buffer) );
+ RSM_StringCopy( IDS_TAPE_SECURITY_TITLE, buffer2, sizeof(buffer2) );
+ WM_MsgBox( buffer2, buffer, WMMB_OK | WMMB_NOYYCHECK, WMMB_ICONEXCLAMATION ); // chs:03-17-93
+ }
+
+ free( temp_password );
+ }
+
+}
+#endif
+
+ return( status );
+
+}
+
+
+/***********
+
+ Name: CryptPassword
+
+ Description: Interfaces with Encryption Unit to encrypt of decrypt
+ the supplied password buffer
+
+ Returns: n/a
+
+ Notes: The Encryption Unit is opened with the supplied mode:
+ ENCRYPT or DECRYPT and the specified algorithm
+
+**********/
+VOID CryptPassword(
+INT16 mode, /* encrypt or decrypt mode */
+UINT16 encrypt_algor, /* encryption algorithm used on tape */
+INT8_PTR password, /* buffer to manipulate */
+INT16 password_size ) /* size of tape password */
+{
+ EU_HAND_PTR enchand; /* encrypt unit handle */
+ INT16 blck, error, ret_code; /* variables for EU */
+
+ /* open encryption unit */
+
+ enchand = EU_Open( encrypt_algor,
+ mode,
+ (INT8_PTR)gb_encryption_key,
+ (INT16)(strlenA( gb_encryption_key ) ),
+ &blck, &error );
+
+ if ( enchand == NULL ) {
+ eresprintf( (INT16) RES_EU_ERROR, error );
+ return;
+ }
+
+ /* perform requested function */
+
+ ret_code = EU_Encrypt( enchand, (INT8_PTR)password, password_size );
+
+ if ( ret_code != EU_NO_ERROR ) {
+ eresprintf( (INT16) RES_EU_ERROR, ret_code );
+ }
+
+ EU_Close( enchand );
+
+ return;
+}
+
+
+/************
+
+ Name: CollectTapePassword
+
+ Description: Function to validate current tape password and collect
+ new tape password as appropriate
+
+ Returns: TRUE or FALSE if existing password is verified
+ TRUE = password matched
+ FALSE = password did not match, or user wants to cancel
+
+ Notes: Called for backup only
+
+**************/
+
+BOOLEAN CollectTapePassword( INT8_PTR new_password,
+ INT16_PTR new_password_size,
+ UINT16 encrypt_algor,
+ INT8_PTR old_password,
+ INT16 old_password_size )
+{
+ CHAR confirm[ MAX_TAPE_PASSWORD_SIZE ]; /* confirmation buffer */
+ BOOLEAN confirmed = FALSE; /* continue condition */
+ DBLK_PTR vcb_ptr;
+ WORD status;
+ UINT32 current_tape_id;
+
+ status = VLM_GetDriveStatus( &vcb_ptr );
+
+ if( status == VLM_VALID_TAPE ) {
+
+ /* get tape ID */
+ current_tape_id = FS_ViewTapeIDInVCB( vcb_ptr );
+ }
+
+ /* used for initial comparisons */
+ memset( confirm, TEXT('\0'), sizeof (confirm) );
+
+ /* Check for .EXE embedded password supplied */
+ if ( memcmp( confirm, gb_auto_password.string, MAX_TAPE_PASSWORD_LEN * sizeof (CHAR) ) ) {
+
+ if ( old_password_size > 0 ) {
+
+ if ( memcmp( old_password, gb_auto_password.string, MAX_TAPE_PASSWORD_LEN * sizeof (CHAR) ) ) {
+
+ memcpy( confirm, old_password, min( old_password_size, MAX_TAPE_PASSWORD_LEN * sizeof (CHAR) ) );
+
+ /* Make adjustments for 2.0 Encryption algorithm */
+ if( encrypt_algor == ENC_ALGOR_1 ) {
+ old_password_size = (INT16) min( (UINT16)( strlen( confirm ) * sizeof (CHAR) ), (UINT16)old_password_size );
+ confirm[ old_password_size/sizeof (CHAR) ] = TEXT('\0');
+ }
+
+ CryptPassword( (INT16) DECRYPT, encrypt_algor, (INT8_PTR)confirm, old_password_size );
+ CryptPassword( (INT16) ENCRYPT, ENC_ALGOR_3, (INT8_PTR)confirm, old_password_size );
+
+ if ( memcmp( confirm, gb_auto_password.string, old_password_size ) ) {
+ eresprintf( (INT16) RES_EMBEDDED_PW_MISMATCH );
+
+ return FALSE;
+
+ }
+ }
+ }
+
+ memcpy( new_password, gb_auto_password.string, MAX_TAPE_PASSWORD_LEN * sizeof (CHAR) );
+ *new_password_size = strlen( (CHAR_PTR)new_password ) * sizeof (CHAR) ;
+
+ return TRUE;
+
+ }
+
+ /* verify existing tape password if necessary, return if mismatch */
+
+ if ( ( old_password_size != 0 ) &&
+ ( memcmp( confirm, old_password, old_password_size ) ) ) {
+
+ if ( ! VerifyTapePassword( (CHAR_PTR)FS_ViewTapeNameInVCB( vcb_ptr ),
+ (CHAR_PTR)FS_ViewSetNameInVCB( vcb_ptr ),
+ (CHAR_PTR)FS_ViewUserNameInVCB( vcb_ptr ),
+ encrypt_algor,
+ old_password,
+ old_password_size,
+ (INT8_PTR)TEXT("setpassword"),
+ (INT16) 0,
+ current_tape_id ) ) {
+
+ return FALSE; /* password mismatch */
+ }
+ return TRUE; /* password matched */
+ }
+
+ /* return a null password if prompting is disabled or "yes" flag set */
+
+ if ( ( ! CDS_GetPasswordFlag( CDS_GetCopy() ) ) ||
+ ( CDS_GetYesFlag( CDS_GetCopy() ) != NO_FLAG ) ) {
+
+ memset( new_password, TEXT('\0'), MAX_TAPE_PASSWORD_LEN * sizeof (CHAR) );
+ *new_password_size = 0;
+ return TRUE;
+ }
+ return TRUE;
+}
+
+
+/************
+
+ Name: CompareTapePswdToCurrentPaswd
+
+ Description: This routine will compare the password on the
+ selected tape against the current logged on user
+ password (Machine/Username). This routine is
+ specific to NT. In the NT app only the only password
+ that is allowed is the tape password NOT the backup
+ set password.
+
+
+ Returns: TRUE = password matched or no password checking needed
+ FALSE = password did not match, or user wants to cancel
+
+
+ Notes: The tape_password parameter passed in is not encrypted.
+
+**************/
+
+#ifdef OEM_MSOFT
+
+BOOLEAN CompareTapePswdToCurrentPaswd(
+ INT8_PTR tape_password, /* tape password in NULL terminated string*/
+ INT16 tape_password_size ) /* length of tape_password in BYTES */
+{
+ CHAR_PTR generic_str_ptr;
+ CHAR_PTR alteredtemppassword = NULL;
+ CHAR_PTR buffer = NULL;
+ BOOLEAN retcode = FALSE;
+ INT dummy_size ;
+
+ if ( tape_password_size == 0 ) return( TRUE ); // No password detected
+
+ generic_str_ptr = GetCurrentMachineNameUserName( ); // Get current logged on user password
+ if ( !generic_str_ptr ) return( TRUE );
+
+ alteredtemppassword = ( CHAR_PTR )calloc( 1, ( 3 + strlen( generic_str_ptr ) ) * sizeof( CHAR ) );
+ if ( !alteredtemppassword ) return( FALSE );
+ *alteredtemppassword = NTPASSWORDPREFIX;
+ strcat( alteredtemppassword, generic_str_ptr );
+
+#ifdef UNICODE
+ buffer = ( CHAR_PTR )calloc( 1, tape_password_size * sizeof( CHAR ) );
+ if ( !buffer ) {
+ free( alteredtemppassword );
+ return( FALSE );
+ }
+
+ if ( ( ( tape_password[0] & 0xff ) == NTPASSWORDPREFIX ) &&
+ ( ( tape_password[1] & 0xff ) != 0) ) { // this is an ANSI tape.....
+
+ tape_password_size *= sizeof( CHAR );
+ dummy_size = (INT)tape_password_size ;
+ mapAnsiToUnicNoNull( ( ACHAR_PTR )tape_password, ( WCHAR_PTR )buffer, ( INT )(tape_password_size / sizeof( CHAR ) ), &dummy_size ) ;
+ tape_password_size = (INT16)dummy_size ;
+ if ( ( *tape_password & 0xff ) == NTPASSWORDPREFIX ) {
+ *buffer = NTPASSWORDPREFIX;
+ }
+ } else {
+ memcpy( buffer, tape_password, tape_password_size );
+ }
+#else
+ buffer = tape_password;
+#endif
+
+ if ( tape_password_size == ( INT16 )( strlen( alteredtemppassword ) * sizeof( CHAR ) ) ) {
+
+ if ( !memcmp( buffer, alteredtemppassword, tape_password_size ) ) {
+ retcode = TRUE;
+
+ } else {
+ retcode = FALSE;
+ }
+
+ } else {
+ retcode = FALSE;
+ }
+
+ if ( alteredtemppassword ) free( alteredtemppassword );
+
+#ifdef UNICODE
+ if ( buffer ) free( buffer );
+#endif
+
+ return( retcode );
+
+}
+
+#endif
diff --git a/private/utils/ntbackup/src/pdir2.bmp b/private/utils/ntbackup/src/pdir2.bmp
new file mode 100644
index 000000000..b9bc64c2b
--- /dev/null
+++ b/private/utils/ntbackup/src/pdir2.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/polldrv.c b/private/utils/ntbackup/src/polldrv.c
new file mode 100644
index 000000000..5e1b981f3
--- /dev/null
+++ b/private/utils/ntbackup/src/polldrv.c
@@ -0,0 +1,1124 @@
+
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: polldrv.c
+
+ Description: This file contains the functions for UI poll drive.
+
+ Code Reviews: 11-21-91
+
+ $Log: J:/UI/LOGFILES/POLLDRV.C_V $
+
+ Rev 1.43.1.2 11 Feb 1994 16:38:30 GREGG
+Changed prompt for user to eject tape. EPR 948-0153
+
+ Rev 1.43.1.1 07 Feb 1994 02:06:02 GREGG
+Fixed and expanded 'extended error reporting'.
+
+ Rev 1.43.1.0 01 Feb 1994 15:12:54 GREGG
+Put TEXT macros debug print format strings.
+
+ Rev 1.43 01 Dec 1993 14:27:10 mikep
+add SQL recognition support to poll drive
+
+ Rev 1.42 23 Sep 1993 15:48:20 GLENN
+Added signalling to Frame window when out of poll drive, if it was previously busy.
+
+ Rev 1.41 21 Jul 1993 17:02:58 GLENN
+Added PD_WaitUntilSettled () function to wait until poll drive is in a settled state.
+
+ Rev 1.40 13 Jul 1993 17:57:18 MARINA
+enable c++
+
+ Rev 1.39 01 Jul 1993 18:00:34 GLENN
+Removed bogus thw_list NULL check - it should not be in here, it causes problems when resetting flags.
+
+ Rev 1.38 16 Jun 1993 16:38:10 GLENN
+Added PD_IsPollDriveBusy().
+
+ Rev 1.37 04 Jun 1993 18:46:34 STEVEN
+added messages for tape failures
+
+ Rev 1.36 25 May 1993 15:03:48 GLENN
+Checking init flag in deinit. Moved static vars around. Ifdef'd no device code for Nost.
+
+ Rev 1.35 25 May 1993 09:39:34 GLENN
+Moved inappropriate message box at begining of Start function.
+
+ Rev 1.34 28 Apr 1993 16:35:02 CARLS
+add code for drive failure in GetDriveStatus call
+
+ Rev 1.33 08 Apr 1993 14:29:06 DARRYLP
+Replaced references to undefined IDS_POLLDRIVE_DRIVE_FAILURE with
+IDS_POLLDRIVE_SMALLPROBLEM.
+
+ Rev 1.32 30 Mar 1993 16:21:50 GREGG
+Changed PD_UNFORMATTED_TAPE to PD_UNRECOGNIZED_MEDIA.
+
+ Rev 1.31 12 Mar 1993 15:17:42 MIKEP
+add unformated tape support
+
+ Rev 1.30 12 Mar 1993 14:46:54 MIKEP
+add auto format call
+
+ Rev 1.29 12 Mar 1993 14:35:58 MIKEP
+auto call erase if foreign tape
+
+ Rev 1.28 18 Nov 1992 13:24:32 GLENN
+Improved speed by increasing polling during dynamic/unstable states.
+
+ Rev 1.27 01 Nov 1992 16:04:56 DAVEV
+Unicode changes
+
+ Rev 1.26 07 Oct 1992 14:09:18 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.25 04 Oct 1992 19:39:44 DAVEV
+Unicode Awk pass
+
+ Rev 1.24 02 Oct 1992 16:33:26 STEVEN
+Changed to report drive failure for NT only.
+
+ Rev 1.22 02 Sep 1992 16:32:24 GLENN
+MikeP changes for NT.
+
+ Rev 1.21 28 Jul 1992 14:41:58 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.20 24 Jul 1992 10:37:00 STEVEN
+do not start polldrive if no drive exists
+
+ Rev 1.19 31 May 1992 11:13:20 MIKEP
+auto catalog changes
+
+ Rev 1.18 14 May 1992 18:00:10 MIKEP
+nt pass 2
+
+ Rev 1.17 23 Mar 1992 15:53:08 GLENN
+Added success message box when hardware retests successful.
+
+ Rev 1.16 19 Mar 1992 15:58:02 GLENN
+Fixed eject bug.
+
+ Rev 1.15 17 Mar 1992 15:39:26 GLENN
+Changed major and minor hardware error processing.
+
+ Rev 1.14 31 Jan 1992 15:02:10 GLENN
+Added restart logic messaging and major error messaging.
+
+ Rev 1.13 21 Jan 1992 16:57:04 JOHNWT
+removed checkyy flag
+
+ Rev 1.12 14 Jan 1992 08:17:08 GLENN
+Updated error processor.
+
+ Rev 1.11 11 Jan 1992 09:22:02 CARLS
+remove strings
+
+ Rev 1.10 07 Jan 1992 17:31:42 GLENN
+Added support for polldrive retry after hwinit failure
+
+ Rev 1.9 26 Dec 1991 13:37:00 GLENN
+Added yy flag check to message boxes
+
+ Rev 1.8 20 Dec 1991 09:34:48 DAVEV
+16/32 bit port - 2nd pass
+
+ Rev 1.7 18 Dec 1991 14:06:42 GLENN
+Added windows.h
+
+ Rev 1.6 18 Dec 1991 13:13:12 GLENN
+Put backin poll drive init check in the start function
+
+ Rev 1.5 11 Dec 1991 13:05:10 JOHNWT
+changed assert in StopPolling to return
+
+ Rev 1.4 04 Dec 1991 18:19:22 GLENN
+Added TF_NO_TAPE_PRESENT to eject error processing.
+
+ Rev 1.3 04 Dec 1991 12:55:24 DAVEV
+Modifications for 16/32-bit Windows port - 1st pass.
+
+
+ Rev 1.2 27 Nov 1991 12:12:52 GLENN
+Clean-up.
+
+ Rev 1.1 21 Nov 1991 10:42:18 GLENN
+Added headers and eject/polldrive re-entrancy protection.
+
+ Rev 1.0 20 Nov 1991 19:19:54 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+// POLL DRIVE DATA STRUCTURES
+
+typedef struct DS_SETTLE far *DS_SETTLE_PTR;
+typedef struct DS_SETTLE far *PDS_SETTLE;
+typedef struct DS_SETTLE {
+
+ BOOL fWaiting;
+ INT nCurrentState;
+ INT nTimeout;
+ INT nOldFrequency;
+ HTIMER hTimerID;
+ PF_VOID fnUserCallBack;
+
+} DS_SETTLE;
+
+static DS_SETTLE mwdsSettle;
+
+// PRIVATE MODULE WIDE VARIABLES
+
+static FSYS_HAND mwhFileSys = (FSYS_HAND)NULL;
+static BOOL mwfPDInitialized = FALSE;
+static BOOL mwfPollDriveInUse = FALSE;
+static BOOL mwfSignalWhenAvailable = FALSE;
+static BOOL mwfStarted = FALSE;
+static HTIMER mwhTimer = INVALID_TIMER_HANDLE;
+static INT mwnFrequency = 0;
+static INT mwnEjectAttempts = 0;
+static BOOL mwfEjectInProgess = FALSE;
+static BOOL mwfFastPolling = FALSE;
+static INT mwnOldFrequency = 0;
+static DBLK mwVCB;
+static INT16 mwnLastMsg;
+static BOOL mwfInVLMTapeChanged = FALSE;
+
+
+// PRIVATE FUNCTION PROTOTYPES
+
+static UINT16 PD_TapePosCallBack ( WORD wMsg, TPOS_PTR pTpos, BOOL fCurrValidVCB, DBLK_PTR pCurVCB, WORD wMode ) ;
+static VOID PD_DisplayMajorError ( WORD res_id, INT16 pd_error );
+static INT PD_GetLastMessage ( VOID );
+static VOID PD_SettleCallBack ( VOID );
+
+// FUNCTIONS
+
+/******************************************************************************
+
+ Name: PD_Init()
+
+ Description: Initializes the UI portion of poll drive.
+
+ Returns: SUCCESS, if successful, otherwise, FAILURE.
+
+******************************************************************************/
+
+BOOL PD_Init ( VOID )
+
+{
+ // Get a generic file system handle.
+
+ if ( FS_OpenFileSys ( &mwhFileSys, GENERIC_DATA, CDS_GetPermBEC () ) ) {
+
+ mwhFileSys = (FSYS_HAND)NULL;
+ zprintf ( DEBUG_USER_INTERFACE, IDS_POLLDRIVE_INIT_FAILED );
+ return FAILURE;
+ }
+
+ mwfPDInitialized = TRUE;
+
+ // Show the init message in the debug window.
+
+ zprintf ( DEBUG_USER_INTERFACE, IDS_POLLDRIVE_INIT );
+
+ return SUCCESS;
+
+} /* end PD_Init() */
+
+
+/******************************************************************************
+
+ Name: PD_Deinit()
+
+ Description: Deinitializes the UI portion of poll drive.
+
+ Returns: SUCCESS, if successful, otherwise, FAILURE.
+
+******************************************************************************/
+
+BOOL PD_Deinit ( VOID )
+
+{
+ // Close the generic file system using the stored file system handle.
+
+ if ( mwfPDInitialized && mwhFileSys ) {
+ FS_CloseFileSys( mwhFileSys );
+ }
+
+ mwfPDInitialized = FALSE;
+
+ return SUCCESS;
+
+} /* end PD_Deinit() */
+
+
+/******************************************************************************
+
+ Name: PD_StartPolling()
+
+ Description: Determines if the TF poll drive can be called. If it can,
+ it will start it with a timer callback to PD_PollDrive().
+
+ Returns: SUCCESS, if successful, otherwise, FAILURE.
+
+******************************************************************************/
+
+BOOL PD_StartPolling ( VOID )
+
+{
+ INT16 nMsg;
+
+ // If poll drive was never or is no longer initialized, or was previously
+ // started, or poll drive is not enabled, or we do not have a generic
+ // file system handle, or the hardware was not initialized, BUG OUT.
+
+ if ( ! mwfPDInitialized || mwfStarted || ! gfPollDrive || ! mwhFileSys || ! gfHWInitialized ) {
+ zprintf ( 0, TEXT("Poll Drive Start IGNORED - already started or HW not initialized") );
+ return FAILURE;
+ }
+
+ if ( mwfPollDriveInUse ) {
+
+ zprintf ( DEBUG_USER_INTERFACE, IDS_POLLDRIVE_START_REENT );
+ return FAILURE;
+ }
+
+ mwfPollDriveInUse = TRUE;
+
+ nMsg = TF_PollDrive( thw_list, (DBLK_PTR)&mwVCB, mwhFileSys,
+ (TPOS_HANDLER) PD_TapePosCallBack, (INT16) PDMSG_START );
+
+ if ( nMsg != PD_NO_CHANGE ) {
+ mwnLastMsg = nMsg;
+ }
+
+ // Show the message in the debug window.
+
+ zprintf ( DEBUG_USER_INTERFACE, IDS_POLLDRIVE_START, nMsg );
+
+ switch ( nMsg ) {
+
+ case PD_DRIVE_FAILURE:
+ case PD_DRIVER_FAILURE:
+
+ // End the poll drive and fall through to the break.
+
+ TF_PollDrive ( thw_list, (DBLK_PTR)&mwVCB, mwhFileSys,
+ (TPOS_HANDLER)PD_TapePosCallBack, (INT16) PDMSG_END );
+
+ // Start failed.
+
+ zprintf ( DEBUG_USER_INTERFACE, IDS_POLLDRIVE_FAILED_MINOR );
+
+ gfHWInitialized = FALSE;
+
+ PD_AttemptRestart ();
+
+ break;
+
+ case PD_OUT_OF_MEMORY:
+ case PD_NO_FREE_CHANNELS:
+ case PD_FUBAR:
+
+ // Start failed.
+
+ // ????? THE APPLICATION SHOULD BE SHUT DOWN AT THIS POINT.
+
+ zprintf ( DEBUG_USER_INTERFACE, IDS_POLLDRIVE_FAILED_SEVERE );
+
+ gfPollDrive = FALSE;
+
+ break;
+
+
+ default:
+
+ mwfStarted = TRUE;
+
+ // Kick off the timer.
+
+ mwhTimer = WM_HookTimer ( (PF_VOID)PD_PollDrive, (WORD)PD_TIMERDELAY );
+
+ // Signal the VLM that the tape has changed.
+
+ mwfInVLMTapeChanged = TRUE;
+ VLM_TapeChanged ( nMsg, &mwVCB, mwhFileSys );
+ mwfInVLMTapeChanged = FALSE;
+
+ break;
+ }
+
+ mwfPollDriveInUse = FALSE;
+
+ return ( mwfStarted ) ? SUCCESS : FAILURE ;
+
+} /* end PD_StartPolling () */
+
+
+/******************************************************************************
+
+ Name: PD_StopPolling()
+
+ Description: Stops TF poll drive only if poll drive was previously
+ started. It also removes the timer for the PD_PollDrive()
+ call back.
+
+ Returns: SUCCESS, if successful, otherwise, FAILURE.
+
+******************************************************************************/
+
+BOOL PD_StopPolling ( VOID )
+
+{
+ INT16 nMsg;
+
+ // If the polling was not started, simply return.
+
+ if ( ! mwfPDInitialized || ! mwfStarted ) {
+ zprintf ( 0, TEXT("Poll Drive Stop IGNORED - not started") );
+ return FAILURE;
+ }
+
+ if ( mwfPollDriveInUse ) {
+
+ zprintf ( DEBUG_USER_INTERFACE, IDS_POLLDRIVE_STOP_REENT );
+ return FAILURE;
+ }
+
+ mwfPollDriveInUse = TRUE;
+
+ // Turn the started flag off so that no continue messages are sent to the
+ // TF_PollDrive() function by the timer function.
+
+ mwfStarted = FALSE;
+
+ // Unhook the timer -- this is done before a tape operation.
+
+ WM_UnhookTimer ( mwhTimer );
+
+ // Call the TF to stop the polling.
+
+ nMsg = TF_PollDrive( thw_list, (DBLK_PTR)&mwVCB, mwhFileSys,
+ (TPOS_HANDLER)PD_TapePosCallBack, (INT16) PDMSG_END );
+
+ if ( nMsg != PD_NO_CHANGE ) {
+ mwnLastMsg = nMsg;
+ }
+
+ // Show the message in the debug window.
+
+ zprintf ( DEBUG_USER_INTERFACE, IDS_POLLDRIVE_STOP, nMsg );
+
+ switch ( nMsg ) {
+
+ case PD_BUSY:
+
+ break;
+
+ case PD_SQL_TAPE:
+ case PD_NO_TAPE:
+ case PD_NEW_TAPE:
+ case PD_VALID_VCB:
+ case PD_BLANK_TAPE:
+ case PD_FOREIGN_TAPE:
+ case PD_MTF_ECC_TAPE:
+ case PD_FUTURE_REV_MTF:
+ case PD_UNRECOGNIZED_MEDIA:
+
+ // Signal the VLM that the tape has changed.
+
+ mwfInVLMTapeChanged = TRUE;
+ VLM_TapeChanged ( nMsg, &mwVCB, mwhFileSys );
+ mwfInVLMTapeChanged = FALSE;
+ break;
+
+ default:
+
+ break;
+ }
+
+ mwfPollDriveInUse = FALSE;
+
+ return SUCCESS;
+
+} /* end PD_StopPolling() */
+
+
+/******************************************************************************
+
+ Name: PD_SetFrequency()
+
+ Description: Sets the frequency of poll drive (in seconds).
+
+ Returns: The old poll drive frequency.
+
+******************************************************************************/
+
+INT PD_SetFrequency (
+
+INT nFrequency ) // I - frequency to call poll drive
+
+{
+ // If the frequency is not specified, set it to the poll drive default.
+ // Otherwise, change the module wide default frequency.
+
+ if ( ! nFrequency ) {
+ nFrequency = mwnFrequency;
+ }
+ else {
+ mwnFrequency = nFrequency;
+ }
+
+ // If we are in the middle of a fast poll, set the old frequency to
+ // the new frequency that was past, and return the old frequency, but
+ // dont actually reset the timer frequency right now, because it will
+ // be set to the new frequency when the fast polling stops. OK?
+
+ if ( mwfFastPolling ) {
+
+ nFrequency = mwnOldFrequency;
+ mwnOldFrequency = mwnFrequency;
+ }
+ else {
+
+ nFrequency = WM_SetTimerFrequency ( mwhTimer, nFrequency );
+ }
+
+ // Get/Set the old poll drive frequency from the timer module.
+
+ return nFrequency;
+
+} /* end PD_SetFrequency() */
+
+
+/******************************************************************************
+
+ Name: PD_PollDrive()
+
+ Description: CALLED BY HOOKING THE WM_HookTimer() to call TF poll drive
+ only if poll drive was started and poll drive is not
+ currently in progress (re-entered).
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID PD_PollDrive ( VOID )
+
+{
+ INT16 nMsg;
+
+ // If the polling was not started, somebody is calling it directly.
+ // THIS IS NOT ALLOWED, so ASSERT.
+
+ msassert ( mwfStarted );
+
+ if ( mwfPollDriveInUse ) {
+
+ mwfSignalWhenAvailable = TRUE;
+ if( !mwfInVLMTapeChanged ) {
+ zprintf ( DEBUG_USER_INTERFACE, IDS_POLLDRIVE_POLL_REENT );
+ }
+ return;
+ }
+
+ mwfPollDriveInUse = TRUE;
+
+ nMsg = TF_PollDrive( thw_list, (DBLK_PTR)&mwVCB, mwhFileSys,
+ (TPOS_HANDLER)PD_TapePosCallBack, (INT16) PDMSG_CONTINUE );
+
+ if ( nMsg != PD_NO_CHANGE ) {
+ mwnLastMsg = nMsg;
+ }
+
+ switch ( nMsg ) {
+
+ case PD_DRIVE_FAILURE:
+ case PD_DRIVER_FAILURE:
+
+ zprintf ( DEBUG_USER_INTERFACE, IDS_POLLDRIVE_FAILED_MINOR );
+
+ gfHWInitialized = FALSE;
+ mwfPollDriveInUse = FALSE;
+
+ PD_StopPolling ();
+
+ VLM_TapeChanged ( nMsg, &mwVCB, mwhFileSys );
+
+ // The following may need to be done with some sort of a PostMessage,
+ // if it fails to work properly. Maybe, maybe not. I guess we'll
+ // find out sooner or later.
+
+#ifdef OS_WIN32
+
+ // OK, there is a small problem. Let's tell the user.
+
+ PD_DisplayMajorError ( IDS_POLLDRIVE_SMALLPROBLEM, nMsg );
+
+#else
+ PD_AttemptRestart ();
+
+#endif
+ break;
+
+ case PD_FUBAR:
+ case PD_OUT_OF_MEMORY:
+
+ // Stop the polling and clear the hardware initialized flag so that
+ // the next time the user goes to perform an operation, he/she
+ // will get notified of the error. At this time, TF_PollDrive()
+ // does not do any error processing with the UI.
+
+ // ????? THE APPLICATION SHOULD BE SHUT DOWN AT THIS POINT.
+
+ zprintf ( DEBUG_USER_INTERFACE, IDS_POLLDRIVE_FAILED_SEVERE );
+
+ gfPollDrive = FALSE;
+ gfHWInitialized = FALSE;
+ mwfPollDriveInUse = FALSE;
+
+ PD_DisplayMajorError ( IDS_POLLDRIVE_FAILED_SEVERE, 0 );
+ PD_StopPolling ();
+
+ break;
+
+ case PD_BUSY:
+ break;
+
+ case PD_NEW_TAPE:
+
+ // Make sure that fast polling is turned on.
+
+ if ( ! mwfFastPolling ) {
+
+ mwnOldFrequency = WM_SetTimerFrequency ( mwhTimer, -1 );
+ mwfFastPolling = TRUE;
+ }
+
+ // Signal the VLM that the tape has changed.
+
+ mwfInVLMTapeChanged = TRUE;
+ VLM_TapeChanged ( nMsg, &mwVCB, mwhFileSys );
+ mwfInVLMTapeChanged = FALSE;
+ break;
+
+ case PD_NO_TAPE:
+ case PD_SQL_TAPE:
+ case PD_BAD_TAPE:
+ case PD_VALID_VCB:
+ case PD_BLANK_TAPE:
+ case PD_FOREIGN_TAPE:
+ case PD_MTF_ECC_TAPE:
+ case PD_FUTURE_REV_MTF:
+ case PD_UNRECOGNIZED_MEDIA:
+ case PD_OUT_OF_SEQUENCE:
+
+ // OK, if fast polling is on, you can turn it off now.
+
+ if ( mwfFastPolling ) {
+
+ WM_SetTimerFrequency ( mwhTimer, mwnOldFrequency );
+ mwfFastPolling = FALSE;
+ }
+
+ // Signal the VLM that the tape has changed.
+
+ mwfInVLMTapeChanged = TRUE;
+ VLM_TapeChanged ( nMsg, &mwVCB, mwhFileSys );
+ mwfInVLMTapeChanged = FALSE;
+ break;
+
+ case PD_NO_CHANGE:
+
+ break;
+
+ default:
+
+ // THE APP WILL BE COMPLETELY HOSED.
+
+ msassert ( FALSE );
+
+ break;
+ }
+
+ mwfPollDriveInUse = FALSE;
+
+ if ( mwfSignalWhenAvailable ) {
+ PostMessage ( ghWndFrame, WM_POLLDRIVEMSG, (MP1)0, (MP2)0 );
+ mwfSignalWhenAvailable = FALSE;
+ }
+
+} /* end PD_PollDrive() */
+
+
+/*****************************************************************************
+
+ Name: PD_GetLastMessage
+
+ Description: Poll drive last message status routine.
+
+ Returns: Poll drive last message status.
+
+*****************************************************************************/
+
+INT PD_GetLastMessage ( VOID )
+
+{
+ return (INT)mwnLastMsg;
+
+} /* end PD_GetLastMessage () */
+
+
+/******************************************************************************
+
+ Name: PD_IsPollDriveBusy()
+
+ Description: Called to determine if Poll Drive is busy in the process
+ of executing.
+
+ Returns: TRUE, if busy. Otherwise, FALSE.
+
+******************************************************************************/
+
+BOOL PD_IsPollDriveBusy ( VOID )
+
+{
+ if ( mwfPollDriveInUse ) {
+ mwfSignalWhenAvailable = TRUE;
+ }
+
+ return mwfPollDriveInUse;
+
+} /* end PD_IsPollDriveBusy () */
+
+
+
+/******************************************************************************
+
+ Name: PD_AttemptRestart()
+
+ Description: Attempts to restart poll drive when a minor error occurs.
+ This should be called only when a minor error has occured.
+
+ Returns: SUCCESS, if successful, otherwise, FAILURE.
+
+******************************************************************************/
+
+BOOL PD_AttemptRestart ( VOID )
+
+{
+ BOOL fResult;
+ INT nAnswer;
+
+ zprintf ( DEBUG_USER_INTERFACE, IDS_POLLDRIVE_SMALLPROBLEM );
+
+ // OK, there is a small problem. Let's tell the user.
+
+ nAnswer = WM_MsgBox ( ID(IDS_POLLDRIVE_MESSAGE),
+ ID(IDS_POLLDRIVE_SMALLPROBLEM),
+ WMMB_OK,
+ WMMB_ICONEXCLAMATION
+ );
+
+ // Attempt to reinitialize the hardware.
+ // If successful, reset the "restart attempts" counter.
+ // If unsuccessful, put the user into the hardware configuration
+ // dialog.
+
+ if ( ! HWC_TapeHWProblem ( bsd_list ) ) {
+
+ WM_MsgBox ( ID(IDS_HWC_TESTRESULTSTITLE),
+ ID(IDS_HWC_INIT_SUCCESS),
+ WMMB_OK,
+ WMMB_ICONINFORMATION
+ );
+
+ fResult = SUCCESS;
+ }
+ else {
+
+ DM_ShowDialog ( ghWndFrame, IDD_SETTINGSHARDWARE, (PVOID)0 );
+
+ if ( gfHWInitialized ) {
+
+ // It be fixed now.
+
+ fResult = SUCCESS;
+ }
+ else {
+
+ // We're HOSED!!!!!
+
+ PD_DisplayMajorError ( IDS_POLLDRIVE_BIGPROBLEM, 0 );
+ fResult = FAILURE;
+ }
+ }
+
+ // Turn Polling back on if everything is OK.
+
+ if ( fResult == SUCCESS ) {
+
+ PD_StartPolling ();
+ }
+
+ STM_SetIdleText ( IDS_READY );
+
+ return fResult;
+
+} /* end PD_AttemptRestart() */
+
+
+/******************************************************************************
+
+ Name: PD_TapePosCallBack()
+
+ Description: This is called by the TF layer during a lengthy operation.
+
+ Returns: UI_ACKNOWLEDGED.
+
+******************************************************************************/
+
+static UINT16 PD_TapePosCallBack (
+
+WORD wMsg,
+TPOS_PTR pTpos,
+BOOL fCurrValidVCB,
+DBLK_PTR pVCB,
+WORD wMode )
+
+{
+ DBG_UNREFERENCED_PARAMETER ( wMsg );
+ DBG_UNREFERENCED_PARAMETER ( pTpos );
+ DBG_UNREFERENCED_PARAMETER ( fCurrValidVCB );
+ DBG_UNREFERENCED_PARAMETER ( pVCB );
+ DBG_UNREFERENCED_PARAMETER ( wMode );
+
+ // Allow the GUI to update any display changes.
+
+ WM_MultiTask ();
+
+ return UI_ACKNOWLEDGED;
+
+} /* end PD_TapePosCallBack() */
+
+
+/******************************************************************************
+
+ Name: PD_DisplayMajorError()
+
+ Description: This is called by the TF layer during a lengthy operation.
+
+ Returns: UI_ACKNOWLEDGED.
+
+******************************************************************************/
+
+static VOID PD_DisplayMajorError ( WORD res_id, INT16 pd_error )
+
+{
+ CHAR szString[MAX_UI_RESOURCE_SIZE];
+ CHAR szMessage[MAX_UI_RESOURCE_SIZE];
+ CHAR szAppName[MAX_UI_RESOURCE_SIZE];
+ BOOLEAN have_msg = FALSE;
+
+ if ( res_id == IDS_POLLDRIVE_SMALLPROBLEM ) {
+ have_msg = UI_GetExtendedErrorString( pd_error, szMessage );
+ }
+
+ if ( !have_msg ) {
+ RSM_StringCopy ( res_id, szString, sizeof ( szString ) );
+ RSM_StringCopy ( IDS_APPNAME, szAppName, sizeof ( szAppName ) );
+ sprintf ( szMessage, szString, szAppName );
+ }
+
+ WM_MsgBox ( ID(IDS_POLLDRIVE_MESSAGE),
+ szMessage,
+ WMMB_OK,
+ WMMB_ICONSTOP
+ );
+
+} /* end PD_DisplayMajorError() */
+
+
+/******************************************************************************
+
+ Name: PD_EjectTape()
+
+ Description: Rewinds and Ejects a tape only if poll drive is not in use
+ (by some strange re-entry occurance). TF poll drive must
+ be ended prior to calling TF eject tape, otherwise
+ unpredictable results will occur. (we make sure it is ended)
+ If we detect poll drive in use, we post a message to eject
+ the tape at a later time.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID PD_EjectTape ( VOID )
+
+{
+ INT rc;
+ INT16 tf_rc;
+ CHAR szMessage[MAX_UI_RESOURCE_SIZE];
+
+ // Wait until poll drive is settled into a known state before attempting
+ // to eject the tape.
+
+ rc = PD_WaitUntilSettled ( PD_SETTLE_NOCALLBACK, 30 );
+
+ if ( rc == PD_SETTLE_TIMEOUT ) {
+
+ zprintf ( DEBUG_USER_INTERFACE, IDS_EJECTTAPEBIGPROBLEM );
+
+ WM_MsgBox ( ID(IDS_EJECTTAPEMESSAGE),
+ ID(IDS_EJECTTAPEBIGPROBLEM),
+ WMMB_OK,
+ WMMB_ICONINFORMATION
+ );
+ }
+
+ // Reset the eject attempts.
+
+ mwnEjectAttempts = 0;
+
+ // Call the Tape Format Eject API if there is no hardware problem
+ // and we are busy fast polling or the tape is known to be in the drive.
+ // If we are fast polling, the tape is still in the drive even if the
+ // tape in drive status indicates otherwise by the VLM.
+
+ if ( MUI_IsTapeInDrive () && ! HWC_TapeHWProblem ( bsd_list ) ) {
+
+ // Turn off Polling.
+
+ PD_StopPolling ();
+
+ tf_rc = (INT)TF_EjectTape ( thw_list, (TPOS_HANDLER)PD_TapePosCallBack );
+
+ switch ( tf_rc ) {
+
+ case TFLE_NO_ERR:
+
+ // Put up a manual eject message box if electronic eject is not
+ // supported.
+
+ if ( ! MUI_IsEjectSupported () ) {
+
+ WM_MsgBox ( ID(IDS_EJECTTAPEMESSAGE),
+ ID(IDS_EJECTTAPEMANUALEJECT),
+ WMMB_OKCANCEL,
+ WMMB_ICONINFORMATION
+ );
+ }
+
+ break;
+
+ case TFLE_NO_TAPE:
+ case TF_NO_TAPE_PRESENT:
+
+ WM_MsgBox ( ID(IDS_EJECTTAPEMESSAGE),
+ ID(IDS_EJECTTAPENOTAPE),
+ WMMB_OK,
+ WMMB_ICONINFORMATION
+ );
+ break;
+
+ case TFLE_DRIVE_FAILURE:
+ case TFLE_DRIVER_FAILURE:
+
+ if ( ! UI_GetExtendedErrorString( tf_rc, szMessage ) ) {
+ RSM_StringCopy ( IDS_EJECTTAPEBIGPROBLEM, szMessage, MAX_UI_RESOURCE_LEN );
+ }
+ WM_MsgBox ( ID(IDS_EJECTTAPEMESSAGE),
+ szMessage,
+ WMMB_OK,
+ WMMB_ICONINFORMATION
+ );
+ break;
+
+ default:
+
+ zprintf ( DEBUG_USER_INTERFACE, IDS_POLLDRIVE_TAPE_EJECT, tf_rc );
+
+ WM_MsgBox ( ID(IDS_EJECTTAPEMESSAGE),
+ ID(IDS_EJECTTAPEBIGPROBLEM),
+ WMMB_OK,
+ WMMB_ICONINFORMATION
+ );
+ break;
+ }
+
+ MUI_TapeInDrive ( FALSE );
+
+ // Turn Polling back on.
+
+ PD_StartPolling ();
+ }
+ else {
+
+ // TEMPORARY
+
+ MessageBeep ( MB_ICONEXCLAMATION );
+ }
+
+
+} /* end PD_EjectTape() */
+
+
+/*****************************************************************************
+
+ Name: PD_WaitUntilSettled ()
+
+ Description: Waits untile poll drive has settled to a known state.
+
+ Returns:
+
+*****************************************************************************/
+
+INT PD_WaitUntilSettled (
+
+PF_VOID fnCallBack,
+INT nTimeout )
+
+{
+
+ // If the polling was not started, simply return not started.
+
+ if ( ! mwfPDInitialized || ! mwfStarted ) {
+ zprintf ( 0, TEXT("Poll Drive Wait Until Settled IGNORED - poll drive was not started") );
+ return PD_SETTLE_NOTINITIALIZED;
+ }
+
+ // Bug out if already waiting.
+
+ if ( mwdsSettle.fWaiting ) {
+
+ return PD_SETTLE_ALREADYWAITING;
+ }
+
+ mwdsSettle.fWaiting = TRUE;
+ mwdsSettle.nCurrentState = PD_SETTLE_UNKNOWN;
+ mwdsSettle.nTimeout = nTimeout;
+ mwdsSettle.fnUserCallBack = fnCallBack;
+
+ // Set up the callback.
+
+ if ( nTimeout ) {
+
+ PD_SettleCallBack ( );
+
+ if ( mwdsSettle.nCurrentState == PD_SETTLE_UNKNOWN ) {
+
+ // Set up the timer and set the PD frequency to one second.
+
+// mwdsSettle.nOldFrequency = PD_SetFrequency ( 1 );
+ mwdsSettle.hTimerID = WM_HookTimer ( PD_SettleCallBack, 1 );
+
+ while ( mwdsSettle.nCurrentState == PD_SETTLE_UNKNOWN ) {
+
+ WaitMessage ();
+ WM_MultiTask ();
+ }
+
+ }
+ }
+ else {
+
+ // Set up the timer and set the PD frequency to one second.
+ // The settle call back routine will unhook the timer and reset
+ // the frequency when a stable state occurs.
+
+// mwdsSettle.nOldFrequency = PD_SetFrequency ( 1 );
+ mwdsSettle.hTimerID = WM_HookTimer ( PD_SettleCallBack, 1 );
+ }
+
+ mwdsSettle.fWaiting = FALSE;
+
+ return mwdsSettle.nCurrentState;
+
+} /* end PD_WaitUntilSettled */
+
+
+/*****************************************************************************
+
+ Name: PD_SettleCallBack ()
+
+ Description: Poll drive status routine
+
+ Returns: VOID
+
+*****************************************************************************/
+
+static VOID PD_SettleCallBack ( VOID )
+
+{
+ static INT nCallCount = 0;
+
+ INT nLastMsg = PD_GetLastMessage ();
+
+
+ switch ( nLastMsg ) {
+
+ case PD_NO_TAPE:
+ case PD_SQL_TAPE:
+ case PD_BAD_TAPE:
+ case PD_VALID_VCB:
+ case PD_BLANK_TAPE:
+ case PD_FOREIGN_TAPE:
+ case PD_MTF_ECC_TAPE:
+ case PD_FUTURE_REV_MTF:
+ case PD_UNRECOGNIZED_MEDIA:
+ case PD_OUT_OF_SEQUENCE:
+
+ mwdsSettle.nCurrentState = PD_SETTLE_OK;
+ nCallCount = 0;
+ break;
+
+ case PD_BUSY:
+ case PD_NEW_TAPE:
+
+ nCallCount++;
+ break;
+
+ default: // Some severe problem occurred - let's signal a break out.
+
+ mwdsSettle.nCurrentState = PD_SETTLE_ERROR;
+ nCallCount = 0;
+ }
+
+ // Check for a timeout.
+
+ if ( mwdsSettle.nTimeout != PD_SETTLE_NOWAIT && nCallCount > mwdsSettle.nTimeout ) {
+ mwdsSettle.nCurrentState = PD_SETTLE_TIMEOUT;
+ }
+
+ // If the state is now known, free up the timer.
+
+ if ( mwdsSettle.nCurrentState != PD_SETTLE_UNKNOWN ) {
+
+ // Free up the timer and reset the PD frequency back to
+ // the old one.
+
+ WM_UnhookTimer ( mwdsSettle.hTimerID );
+// PD_SetFrequency ( mwdsSettle.nOldFrequency );
+ }
+
+ // Call back the users function.
+
+ if ( mwdsSettle.fnUserCallBack ) {
+
+ mwdsSettle.fnUserCallBack ();
+ }
+
+} /* end PD_SettleCallBack () */
+
diff --git a/private/utils/ntbackup/src/posatset.c b/private/utils/ntbackup/src/posatset.c
new file mode 100644
index 000000000..745bd0f26
--- /dev/null
+++ b/private/utils/ntbackup/src/posatset.c
@@ -0,0 +1,1185 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: posatset.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the code for PositionAtSet().
+
+
+ $Log: T:/LOGFILES/POSATSET.C_V $
+
+ Rev 1.42.1.6 24 May 1994 20:16:22 GREGG
+Never eject foreign tapes in write mode.
+
+ Rev 1.42.1.5 24 May 1994 15:55:50 GREGG
+Report wierd tapes (SQL, Sytos continuation, etc.) as WRONG_TAPE when
+searching for EOD to append.
+
+ Rev 1.42.1.4 11 May 1994 14:36:58 GREGG
+Don't eject foreign tapes in write-continue mode.
+
+ Rev 1.42.1.3 01 Feb 1994 15:12:28 GREGG
+Put TEXT macros debug print format strings.
+
+ Rev 1.42.1.2 21 Nov 1993 23:34:22 GREGG
+Added eject on conditions where we know we need a different tape.
+
+ Rev 1.42.1.1 17 Nov 1993 00:56:48 GREGG
+1. Handle no tape and new tape conditions returned from Mount after UI
+ callback.
+2. Report an error if the UI tells us to append and the format on the
+ current tape doesn't allow append operations.
+
+ Rev 1.42.1.0 27 Sep 1993 14:16:28 GREGG
+Reset pos info so we don't look for a particular tape during EOM continuation.
+
+ Rev 1.42 03 Aug 1993 21:23:50 ZEIR
+fixes/cleanups for UI_FAST_APPEND & UI_EOD
+
+ Rev 1.41 21 Jul 1993 19:13:40 ZEIR
+Reintroduced TAPES_FIRST_TO_LAST logic from Cougar/Skateboard.
+
+ Rev 1.40 15 Jul 1993 11:51:44 GREGG
+Don't free the fmt env on TF_EMPTY_TAPE msg when in cont mode.
+
+ Rev 1.39 26 Jun 1993 02:03:02 GREGG
+Fixed a bug for a VERY specific case: The UI wants to partially catalogging
+a tape, so they keep starting read operations requesting -1, -1, -1, and
+then aborting them once DoRead gives them the VCB. If DoRead reads to EOM
+before getting aborted, then we are sitting at EOM and at MOS when the next
+request comes in for -1, -1, -1. In this unique case, we clear the channel
+EOM bit, and set the tf_msg to TF_NEED_NEW_TAPE before we even enter the
+positioning loop the first time, because this case is too confusing for the
+rest of the positioning logic.
+
+ Rev 1.38 18 Jun 1993 17:12:48 GREGG
+Fixed EPR 294-0560 - Now reports wrong tape instead of empty or invalid tape.
+
+ Rev 1.37 13 Jun 1993 21:57:28 GREGG
+Fix for EPR #294-0544 -- Continuation on EOD search was being allowed to
+tapes not in the same family. This fix require a change to the backup tpos
+routine to expect TF_WRONG_TAPE, and to use the sequence number in the
+position info structure to prompt for the tape on WRONG_TAPE and NEED_NEW.
+
+ Rev 1.36 22 May 1993 22:20:04 GREGG
+Fix for EPR 357-0250 - won't append if drive can't do fast append.
+
+ Rev 1.35 19 May 1993 15:57:00 GREGG
+Added logic to prevent using tape with same family id to continue a backup.
+
+ Rev 1.34 17 May 1993 20:12:06 GREGG
+Added logic to deal with the fact that the app above tape format doesn't
+keep track of the lba of the vcb.
+
+ Rev 1.33 29 Apr 1993 22:26:56 GREGG
+Need to call StartRead even if we're going to do FFR.
+
+ Rev 1.32 14 Apr 1993 01:59:58 GREGG
+Fixes to deal with non-ffr tapes in ffr drives (i.e. EXB2200 in EXB5000).
+
+ Rev 1.31 12 Apr 1993 22:35:18 GREGG
+Don't do Fast Append if the drive doesn't have the features to support it.
+
+ Rev 1.30 01 Apr 1993 13:50:22 GREGG
+Fixed a STUPID logic error in changes made for last rev.
+
+ Rev 1.29 31 Mar 1993 18:24:12 GREGG
+Always dismount before calling the UI.
+
+ Rev 1.28 30 Mar 1993 16:15:46 GREGG
+Handle Unrecognized Media error (unformatted DC2000).
+
+ Rev 1.27 10 Mar 1993 11:01:52 GREGG
+Dismount tape if write protected and in write mode anticipating tape change.
+
+ Rev 1.26 26 Jan 1993 18:22:48 GREGG
+Added Fast Append functionality.
+
+ Rev 1.25 04 Aug 1992 17:17:12 GREGG
+Added case for UI_NON_OTC_SCAN.
+
+ Rev 1.24 23 Jul 1992 10:33:04 GREGG
+Fixed warnings.
+
+ Rev 1.23 15 Jul 1992 12:23:12 GREGG
+Don't punt the buffer at the end if the mode is TF_SCAN_CONTINUE.
+
+ Rev 1.22 05 Apr 1992 19:13:48 GREGG
+ROLLER BLADES - Removed call to InitTape, and don't call StartRead in write mode!
+
+ Rev 1.21 28 Mar 1992 18:23:00 GREGG
+ROLLER BLADES - OTC - Initial integration.
+
+ Rev 1.20 20 Feb 1992 18:15:20 NED
+ensured proper rewind upon finding a foreign tape.
+
+ Rev 1.19 12 Feb 1992 19:16:42 GREGG
+Bug fixes.
+
+ Rev 1.18 08 Feb 1992 14:29:10 GREGG
+Removed references to lst_oper in drive stucture (it no longer exits).
+
+ Rev 1.17 15 Jan 1992 01:47:54 GREGG
+Added a boolean parameter indicating if all they want is a VCB off the tape,
+and code to call the special GetVCBBuff if that is the case.
+
+ Rev 1.16 13 Jan 1992 13:45:22 GREGG
+Skateboard - Bug fixes.
+
+ Rev 1.15 02 Jan 1992 14:56:52 NED
+Buffer Manager/UTF translator integration.
+
+ Rev 1.14 05 Dec 1991 13:51:22 GREGG
+SKATEBOARD - New Buff Mgt - Initial Integration.
+
+ Rev 1.13 29 Oct 1991 10:42:10 GREGG
+BIGWHEEL - EPR #13 - Don't increment tape_seq_num for next_tape if dont_care.
+
+ Rev 1.12 23 Oct 1991 10:07:44 GREGG
+EPR #7 - Replaced rewindDrive with ResetDrivePosition when aborting from NEED_NEW_TAPE.
+
+ Rev 1.11 17 Oct 1991 01:25:46 GREGG
+BIGWHEEL - 8200sx - Initial integration.
+
+ Rev 1.10 17 Sep 1991 12:06:20 GREGG
+Changed continuation logic to save format in channel, and only during write.
+
+ Rev 1.9 22 Aug 1991 16:40:06 NED
+Changed all references to internals of the buffer structure to macros.
+
+ Rev 1.8 16 Aug 1991 09:30:06 GREGG
+Added saving of current format at continuation time.
+
+ Rev 1.7 14 Aug 1991 12:17:26 GREGG
+Indicate drive sholud be rewound on calls to ResetChannelList so that the
+current tape is rewound before the user is prompted for a new one.
+Eliminated stuff to throw away the current buffer on user and happy abort.
+
+ Rev 1.6 22 Jul 1991 13:01:24 GREGG
+Removed macro calls to set unreferenced channel status bits.
+Added handling for two new channel status bits: CH_CONTINUING and CH_EOS_AT_EOM.
+
+ Rev 1.5 10 Jul 1991 11:12:22 GREGG
+Free format environment in case of an aborted continuation.
+
+ Rev 1.4 09 Jul 1991 16:06:14 NED
+Free format env if tape in drive is found to be empty.
+Pass address of the position structure's backup set number to GotoBckUpSet.
+Handle exception in current buffer (if any) at Happy Abort time.
+
+ Rev 1.3 26 Jun 1991 16:23:08 NED
+added exception handling prior to PuntBuffer after UI_HAPPY_ABORT
+zeroed bytes_free after SnagBuffer at top of positioning loop for F25_MoveToVCB()
+
+ Rev 1.2 20 Jun 1991 14:30:46 GREGG
+Removed forced rewind on abort.
+
+ Rev 1.1 10 May 1991 16:18:04 GREGG
+Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:12:16 GREGG
+Initial revision.
+
+**/
+/* begin include list */
+#include <stdtypes.h>
+#include <queues.h>
+
+#include "channel.h"
+#include "drive.h"
+#include "tpos.h"
+#include "lwprotos.h"
+#include "tfl_err.h"
+#include "tfldefs.h"
+#include "translat.h"
+#include "sx.h"
+#include "lw_data.h"
+
+/* Device driver header source */
+#include "retbuf.h"
+#include "dilhwd.h"
+#include "drvinf.h"
+#include "generr.h"
+#include "genstat.h"
+#include "dil.h"
+#include "tdemo.h"
+
+/* The file system files */
+#include "fsys.h"
+
+/* For Debug */
+#include "be_debug.h"
+
+
+/* $end$ include list */
+
+
+/* Some Useful Defines */
+
+#define NO_MATCH 0
+#define MATCH 1
+#define DONT_CARE 2
+
+/* Static Prototypes */
+static INT16 _near MatchTapeId( DBLK_PTR, INT32 ) ;
+static INT16 _near MatchTapeSeq( DBLK_PTR, INT16 ) ;
+static INT16 _near MatchBckSet( DBLK_PTR, INT16 ) ;
+
+
+
+/**/
+/**
+
+ Name: PositionAtSet
+
+ Description: This is the main tape positioning routine for the system.
+ This does the initial position on TF_OpenSet().
+
+ Modified: 3/1/1990 10:43:17
+
+ Returns: 0 if positioned OK, or an Error Code
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+INT16 PositionAtSet(
+ CHANNEL_PTR channel, /* Channel we are dealing with */
+ TPOS_PTR position, /* Tape Position desired */
+ BOOLEAN vcb_only ) /* TRUE: We're only going to VCB the tape */
+{
+ INT16 tmp ;
+ DRIVE_PTR curDRV = channel->cur_drv ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ INT16 tf_msg = 0 ;
+ INT16 prev_tf_msg = 0 ;
+ UINT16 ui_msg = 0 ;
+ INT16 matched_id, matched_seq, matched_set ;
+ UINT16 mode ;
+ RET_BUF myret ;
+ BOOLEAN is_tape_present,
+ done = FALSE,
+ space = FALSE,
+ search_eod = FALSE,
+ need_new_vcb = FALSE,
+ write_mode = FALSE,
+ read_mode = FALSE,
+ cont_mode = FALSE,
+ abs_pos = FALSE,
+ pop_it = FALSE,
+ rewind_it = FALSE,
+ fast_file = FALSE ;
+
+ /* Set up some Booleans */
+ if( ( ( channel->mode & ~0x8000 ) == TF_WRITE_OPERATION ) ||
+ ( ( channel->mode & ~0x8000 ) == TF_WRITE_APPEND ) ) {
+ write_mode = TRUE ;
+ }
+
+ if( ( ( channel->mode & ~0x8000 ) == TF_READ_OPERATION ) ||
+ ( ( channel->mode & ~0x8000 ) == TF_READ_OPERATION ) ) {
+ read_mode = TRUE ;
+ }
+
+ if( channel->mode & 0x8000 ) {
+ cont_mode = TRUE ;
+ }
+
+ BE_Zprintf( DEBUG_TAPE_FORMAT, RES_REQUESTED_SET,
+ position->tape_id, position->tape_seq_num, position->backup_set_num ) ;
+
+ /* The haven't specified a position, special READ processing */
+ if( !write_mode ) {
+
+ /* Are they requesting a fast position ( via ordinary SEEK ) ? */
+ fast_file = ( position->tape_loc.pba_vcb &&
+ ( DriveAttributes( channel->cur_drv ) & TDI_FAST_NBLK ) )
+ ? TRUE : FALSE ;
+
+ /* Are they requesting a fast position ( on an EXABYTE 8200SX - MaynStream 2200+ ) ? */
+ if( !fast_file && position->tape_loc.pba_vcb && SX_IsOK( channel ) ) {
+
+ /* if SX file exists for this physical tape THEN ... */
+ if( SX_OpenFile( channel,
+ position->tape_id,
+ position->tape_seq_num ) ) {
+
+ /* some record of the set exists in the SX file THEN ... */
+ if( SX_SeekSetInFile( channel,
+ position->backup_set_num,
+ (INT16)SX_FINDING_SET ) ) {
+
+ /* OK to fast file on the EXABYTE 8200SX - MaynStream 2200+ */
+ fast_file = TRUE ;
+ } else {
+ /* what's the point of keeping the file open */
+ SX_CloseFile( channel ) ;
+ }
+ }
+ }
+
+ /* If there are available bytes in the is buffer, and nothing has been
+ used from it, and we are at end of set ... then this must have been read
+ at the end of set on the last operation, so we don't need to read tape
+ */
+ if( ( channel->cur_buff != NULL ) &&
+ ( BM_BytesFree( channel->cur_buff ) && BM_NextByteOffset( channel->cur_buff ) == 0 ) &&
+ IsPosBitSet( channel->cur_drv, AT_EOS ) ) {
+ BE_Zprintf( DEBUG_TAPE_FORMAT, RES_RESIDUAL_READ_BUFFER ) ;
+ need_new_vcb = TRUE ;
+ } else if( position->tape_id == -1L && position->tape_seq_num == -1 && position->backup_set_num == -1 ) {
+ /* We are at the end of set, so lets get the next VCB */
+ if( IsPosBitSet( channel->cur_drv, AT_EOS ) ) {
+ need_new_vcb = TRUE ;
+ } else if( IsPosBitSet( channel->cur_drv, AT_MOS ) ) {
+ BE_Zprintf( 0, TEXT("Posatset: 'don't care' request at MOS \n") ) ;
+ need_new_vcb = TRUE ;
+ if( !AtEOM( channel ) ) {
+ BE_Zprintf( 0, TEXT(" Not at EOM, setting space = TRUE \n") ) ;
+ space = TRUE ;
+ } else {
+ BE_Zprintf( 0, TEXT(" At EOM, leaving space = FALSE \n") ) ;
+ if( cont_mode ) {
+ BE_Zprintf( 0, TEXT(" In cont mode, leaving EOM status \n") ) ;
+ } else {
+ BE_Zprintf( 0, TEXT(" Not in cont mode, clearing EOM status \n") ) ;
+ ClrChannelStatus( channel, CH_AT_EOM ) ;
+ tf_msg = TF_NEED_NEW_TAPE ;
+ }
+ }
+ }
+ }
+ }
+
+ /* If we don't have a buffer, then get one */
+
+ if( channel->cur_buff == NULL ) {
+ channel->cur_buff = ( vcb_only || write_mode ) ?
+ BM_GetVCBBuff( &channel->buffer_list ) :
+ BM_Get( &channel->buffer_list ) ;
+ if ( channel->cur_buff == NULL ) {
+ ret_val = TFLE_NO_MEMORY ;
+ } else {
+ BM_SetBytesFree( channel->cur_buff, 0 ) ;
+ }
+ }
+
+ if( cont_mode ) {
+ SetChannelStatus( channel, CH_CONTINUING ) ;
+ if( write_mode ) {
+ /* Save the write format */
+ channel->save_fmt = channel->cur_fmt ;
+ channel->cur_fmt = UNKNOWN_FORMAT ;
+ channel->save_env = channel->fmt_env ;
+ channel->fmt_env = NULL ;
+ }
+ }
+
+ /* At this point, if everything is ok, we should have a buffer.
+ Let's start positioning. */
+ while( !done && !ret_val ) {
+
+ /* The drive could have changed so reset it */
+ curDRV = channel->cur_drv ;
+
+ /* This code should only execute on a multi-drive channel */
+ if( curDRV->hold_buff != NULL ) {
+ PuntBuffer( channel ) ;
+ channel->cur_buff = curDRV->hold_buff ;
+ curDRV->hold_buff = NULL ;
+ BM_UnReserve( channel->cur_buff );
+ }
+
+ /* Has some position been specified */
+ if( position->tape_id != -1 || position->tape_seq_num != -1 || position->backup_set_num != -1 ) {
+ abs_pos = TRUE ;
+ }
+
+ if( !tf_msg ) {
+
+ /* Tell the UI we need a new tape if :
+ 1) There is no previous drive in the channel.
+ 2) We are at EOM.
+ 3) There is no previous ui_msg ( indicating this is the first pass ).
+ */
+ if( curDRV->thw_inf.channel_link.q_prev == NULL && AtEOM( channel ) && !ui_msg ) {
+
+ tf_msg = TF_NEED_NEW_TAPE ;
+
+ /* If a tape is not mounted, then there is not tape */
+ } else if( !IsTapeMounted( channel ) ) {
+
+ tf_msg = TF_NO_TAPE_PRESENT ;
+
+ /* We Need to read a new VCB if:
+ 1) The current drive's VCB is not valid, or
+ 2) The positioner is explicitly requesting a VCB, and
+ 3) We know we are not at the end of data
+ */
+ } else if( ( !curDRV->vcb_valid || need_new_vcb ) && !( IsPosBitSet( curDRV, AT_EOD ) ) ) {
+ BE_Zprintf( DEBUG_TAPE_FORMAT, RES_ATTEMPTING_TO_VCB ) ;
+ if ( ( IsPosBitSet( curDRV, AT_BOT ) && IsPosBitSet( curDRV, AT_EOS ) ) || space ) {
+ ClrPosBit( curDRV, AT_BOT ) ;
+ }
+ if ( IsPosBitSet( curDRV, AT_BOT ) ) {
+ tmp = ReadNewTape( channel, position, TRUE ) ;
+ } else {
+ tmp = MoveNextSet( channel, position ) ;
+ }
+ if ( tmp == TFLE_NO_ERR ) {
+ tmp = ReadThisSet( channel ) ;
+ }
+ space = FALSE ;
+ /* If there is an Error, Who do I address it to ? */
+ IsTFLE( tmp ) ? ( ret_val = tmp ) : ( tf_msg = tmp ) ;
+ if( ret_val ) {
+ break ;
+ }
+ /* This assumes that he will have rejected the current VCB
+ and we will need a new one on the next pass
+ */
+ need_new_vcb = TRUE ;
+
+ /* This logic moves us down a multi-drive channel */
+ if( ( !write_mode || search_eod ) && tf_msg == TF_NEED_NEW_TAPE ) {
+ /* do a preliminary match for later test */
+ matched_id = MatchTapeId( &curDRV->cur_vcb, position->tape_id ) ;
+ if( NextDriveInChannel( channel, FALSE ) != TF_END_CHANNEL ) {
+ curDRV = channel->cur_drv ;
+ tf_msg = 0 ;
+ /* On a dual drive system, the UI has no idea that EOM has occurred, hence
+ we must increment the sequence number to prevent the wrong tape
+ message */
+ if( ( matched_id == MATCH ) && ( position->tape_seq_num != -1 ) ) {
+ position->tape_seq_num++ ;
+ }
+ continue ;
+ } else {
+ ResetChannelList( channel, TRUE ) ;
+ }
+ }
+ }
+
+ /* If the VCB is valid, then attempt to match it against the
+ criteria passed in the TPOS structure from the loops */
+ if( curDRV->vcb_valid ) {
+
+ BE_Zprintf( DEBUG_TAPE_FORMAT, RES_CURRENT_VCB,
+ FS_ViewTapeIDInVCB( &curDRV->cur_vcb ),
+ FS_ViewTSNumInVCB( &curDRV->cur_vcb ),
+ FS_ViewBSNumInVCB( &curDRV->cur_vcb ) ) ;
+
+ /* If We are search for a place to write, update the current
+ position in the channel structure */
+
+ if( write_mode && !cont_mode ) {
+ /*lint -e713 */
+ channel->tape_id = FS_ViewTapeIDInVCB( &curDRV->cur_vcb ) ;
+ channel->ts_num = FS_ViewTSNumInVCB( &curDRV->cur_vcb ) ;
+ channel->bs_num = FS_ViewBSNumInVCB( &curDRV->cur_vcb ) ;
+ /*lint +e713 */
+ }
+
+ /* If this is a read, and we are at end of data, say VCB_EOD */
+ if( ( !write_mode && ( tf_msg == TF_NO_MORE_DATA || IsPosBitSet( channel->cur_drv, AT_EOD ) ) ) && !abs_pos ) {
+ tf_msg = TF_VCB_EOD ;
+ }
+
+ if( !tf_msg ) {
+
+ /* Ok, what is what */
+ matched_id = MatchTapeId( &curDRV->cur_vcb, position->tape_id ) ;
+ if( matched_id == MATCH ){
+ if( lw_fmtdescr[channel->cur_fmt].attributes & TAPES_FIRST_TO_LAST ){
+ position->tape_seq_num = FS_ViewTSNumInVCB( &curDRV->cur_vcb ) ;
+ }
+ if( !(lw_fmtdescr[channel->cur_fmt].attributes & POS_INF_AVAIL) ){
+ fast_file = FALSE ;
+ position->tape_loc.pba_vcb = 0 ;
+ }
+ }
+ matched_seq = MatchTapeSeq( &curDRV->cur_vcb, position->tape_seq_num ) ;
+ matched_set = MatchBckSet( &curDRV->cur_vcb, position->backup_set_num ) ;
+
+ /* Has the idiot specified an actual tape position or are we
+ winging it ? */
+ if( matched_id == MATCH || matched_id == DONT_CARE ) {
+ if( matched_seq == MATCH || matched_seq == DONT_CARE ) {
+ if( matched_set == MATCH ) {
+ /* If the match conditions succeed and the following conditions fail:
+ 1) We are at End of Set and we don't need a new VCB ( this suggests
+ that we had a VCB prior to entering this function, hence we are
+ no really sitting at the beginning ot this set.
+ 2) We are at End of Data, hence we are not really sitting at
+ the VCB we are.
+ 3) We are sitting somewhere in the middle of the Set.
+ Tell the user we found his VCB
+ */
+ if( ( IsPosBitSet( curDRV, AT_EOS ) && !need_new_vcb )
+ || IsPosBitSet( curDRV, AT_EOD )
+ || IsPosBitSet( curDRV, AT_MOS ) ) {
+ matched_set = NO_MATCH ;
+ } else {
+ tf_msg = TF_REQUESTED_VCB_FOUND ;
+ }
+ }
+ }
+ }
+
+ /* No complete match yet, so let's either do some positioning or talk
+ to the UI */
+
+ /* We need a new tape if:
+ 1) The tape id didn't match, or
+ 2) The Tape sequence didn't match, or
+ 3) we are at BOT, and
+ 4) current VCBs Backup Set number is greater then
+ the requested Backup set number.
+ */
+ if( matched_id == NO_MATCH || matched_seq == NO_MATCH ) {
+ /* Is this a more then one drive system ? */
+ if( curDRV->thw_inf.channel_link.q_next != NULL || curDRV->thw_inf.channel_link.q_prev ) {
+ if( NextDriveInChannel( channel, TRUE ) != TF_END_CHANNEL ) {
+ curDRV = channel->cur_drv ;
+ if( curDRV->vcb_valid ) {
+ need_new_vcb = FALSE ;
+ }
+ /* No Message this pass */
+ tf_msg = 0 ;
+ /* If the drive is in the middle of set, rewind before proceeding */
+ if( IsPosBitSet( curDRV, AT_MOS ) ) {
+ RewindDrive( channel->cur_drv, position, TRUE, TRUE, channel->mode ) ;
+ }
+ /* Ugly jump to top of loop */
+ continue ;
+ } else {
+ ResetChannelList( channel, FALSE ) ;
+ tf_msg = TF_WRONG_TAPE ;
+ }
+ } else {
+ tf_msg = TF_WRONG_TAPE ;
+ }
+ } else if( ( IsPosBitSet( curDRV, AT_BOT ) &&
+ ( (UINT16)FS_ViewBSNumInVCB( &curDRV->cur_vcb ) > (UINT16)position->backup_set_num ) ) ) {
+ tf_msg = TF_WRONG_TAPE ;
+ if( lw_fmtdescr[channel->cur_fmt].attributes & TAPES_FIRST_TO_LAST ){
+ position->tape_seq_num = 1 ;
+ }
+ }
+
+ /* We currently have the right tape in the drive, */
+ /* now let's attempt to position to correct set. */
+ if( !tf_msg && ( matched_id == MATCH || matched_id == DONT_CARE )
+ && ( matched_seq == MATCH || matched_seq == DONT_CARE )
+ && ( matched_set == NO_MATCH ) ) {
+ if( !fast_file ) {
+ tmp = GotoBckUpSet( channel, &position->backup_set_num, position ) ;
+ IsTFLE( tmp ) ? ( ret_val = tmp ) : ( tf_msg = tmp ) ;
+ /* This logic moves us down a multi-drive channel */
+ if( tf_msg == TF_NEED_NEW_TAPE ) {
+ /* Do a preliminary match for later test */
+ matched_id = MatchTapeId( &curDRV->cur_vcb, position->tape_id ) ;
+ if( NextDriveInChannel( channel, FALSE ) != TF_END_CHANNEL ) {
+ curDRV = channel->cur_drv ;
+ /* No Message this pass */
+ tf_msg = 0 ;
+ /* On a dual drive system, the UI has no idea that EOM has occurred, hence
+ we must increment the sequence number to prevent the wrong tape
+ message */
+ if( ( matched_id == MATCH ) && ( position->tape_seq_num != -1 ) ) {
+ position->tape_seq_num++ ;
+ }
+ /* Ugly jump to top of loop */
+ continue ;
+ } else {
+ ResetChannelList( channel, TRUE ) ;
+ }
+ }
+ /* Is This now the correct Set ? */
+ if ( (lw_fmtdescr[channel->cur_fmt].attributes & TAPES_FIRST_TO_LAST) && tf_msg ) {
+ /* make sure we skip the next assignment! */
+ } else if ( MatchBckSet( &curDRV->cur_vcb, position->backup_set_num ) == MATCH ) {
+ tf_msg = TF_REQUESTED_VCB_FOUND ;
+ }
+ } else { /* using fast file */
+ channel->tape_id = position->tape_id ;
+ channel->ts_num = position->tape_seq_num ;
+ channel->bs_num = position->backup_set_num ;
+ if( ( tmp = StartRead( channel ) ) != TFLE_NO_ERR ) {
+ IsTFLE( tmp ) ? ( ret_val = tmp ) : ( tf_msg = tmp ) ;
+ } else {
+ done = TRUE ;
+ }
+ }
+ }
+ }
+ }
+ }
+ /* We are not done yet */
+ if( !done && !ret_val ) {
+
+ /* If we don't have a message for the UI interface yet, use
+ one of these ( this will occur when no absolute position
+ has been requested */
+ if( !tf_msg ) {
+ if( IsPosBitSet( curDRV, AT_EOD ) ) {
+ tf_msg = TF_VCB_EOD ;
+ } else if( IsPosBitSet( curDRV, AT_BOT ) && !search_eod ) {
+
+ /* If the ID for this tape and the last tape match,
+ the stupid user has requested to overwrite one
+ of the tapes in the family they're trying to
+ continue.
+ */
+ if( write_mode && cont_mode &&
+ FS_ViewTapeIDInVCB( &curDRV->cur_vcb ) == FS_ViewTapeIDInVCB( channel->lst_osvcb ) ) {
+
+ tf_msg = TF_CONT_TAPE_IN_FAMILY ;
+ } else {
+ tf_msg = TF_VCB_BOT ;
+ }
+ } else if( search_eod ) {
+ tf_msg = TF_ACCIDENTAL_VCB ;
+ } else {
+ tf_msg = TF_POSITIONED_AT_A_VCB ;
+ }
+ }
+
+ /* If we have a no more data message from ReadNextSet(), and we
+ are at BOT, the tape is empty
+ */
+ if( tf_msg == TF_NO_MORE_DATA && IsPosBitSet( curDRV, AT_BOT ) ) {
+ tf_msg = TF_EMPTY_TAPE ;
+ if( !cont_mode ) {
+ FreeFormatEnv( &channel->cur_fmt, &channel->fmt_env ) ;
+ }
+ }
+
+ if( tf_msg == TF_EMPTY_TAPE ||
+ tf_msg == TF_FUTURE_REV_MTF ||
+ tf_msg == TF_MTF_ECC_TAPE ||
+ tf_msg == TF_SQL_TAPE ||
+ tf_msg == TF_TAPE_OUT_OF_ORDER ||
+ tf_msg == TF_INVALID_VCB ) {
+ if( write_mode && !cont_mode && position->tape_id != -1 ) {
+ tf_msg = TF_WRONG_TAPE ;
+ } else {
+ if( ( ret_val = RewindDrive( channel->cur_drv, position, FALSE, TRUE, channel->mode ) ) != TFLE_NO_ERR ) {
+ break ;
+ }
+ }
+ }
+
+ /* Reset the tape id overwriting */
+ if( tf_msg == TF_EMPTY_TAPE && write_mode && !cont_mode ) {
+ channel->tape_id = 0L ;
+ }
+
+ mode = channel->mode ;
+
+ /* This is a TOTAL KLUDGE, implemented only because THE UI
+ has know idea what it did, is currently doing, or is going to do in
+ the future ... */
+ if( !write_mode && !cont_mode && tf_msg == TF_NEED_NEW_TAPE ) {
+ /* mode |= 0x8000 ; *//* Heaven only knows if or when we'll need this again! */
+ if( position->tape_seq_num != -1 ) {
+ position->tape_seq_num++ ;
+ }
+ }
+
+ if( write_mode && !cont_mode && tf_msg == TF_NEED_NEW_TAPE ){
+
+ if( position->tape_id == -1 ){
+ position->tape_id = FS_ViewTapeIDInVCB( &curDRV->cur_vcb ) ;
+ position->tape_seq_num = FS_ViewTSNumInVCB( &curDRV->cur_vcb ) ;
+ }
+ ++position->tape_seq_num ;
+ }
+
+ BE_Zprintf( DEBUG_TAPE_FORMAT, RES_POSITION_AT_SET, tf_msg ) ;
+
+ /* We now dismount (and possibly eject) the tape in all cases,
+ just in case the UI decides to allow the user to change
+ tapes. Note that we dismount without rewinding or ejecting
+ except in cases where we expect the user to change tapes.
+ */
+ pop_it = FALSE ;
+ rewind_it = FALSE ;
+ switch( tf_msg ) {
+
+ case TF_NEED_NEW_TAPE :
+ case TF_WRONG_TAPE :
+ case TF_CONT_TAPE_IN_FAMILY :
+ rewind_it = pop_it = TRUE ;
+ break ;
+
+ case TF_INVALID_VCB :
+ rewind_it = TRUE ;
+ if( read_mode ) {
+ pop_it = TRUE ;
+ }
+ break ;
+
+ case TF_EMPTY_TAPE :
+ rewind_it = TRUE ;
+ if( read_mode && position->tape_id != -1 ) {
+ pop_it = TRUE ;
+ }
+ break ;
+
+ case TF_UNRECOGNIZED_MEDIA :
+ break ;
+
+ default:
+ if( write_mode &&
+ ( channel->cur_drv->thw_inf.drv_status & TPS_WRITE_PROTECT ) ) {
+ rewind_it = pop_it = TRUE ;
+ }
+ break ;
+ }
+
+ if( rewind_it ) {
+ ret_val = RewindDrive( curDRV, position, TRUE, TRUE, 0 ) ;
+ }
+
+ if( ret_val == TFLE_NO_ERR && pop_it &&
+ ( curDRV->thw_inf.drv_info.drv_features & TDI_UNLOAD ) ) {
+
+ if( TpEject( curDRV->drv_hdl ) == FAILURE ) {
+ ret_val = TFLE_DRIVER_FAILURE ;
+ } else {
+ while( TpReceive( curDRV->drv_hdl, &myret ) == FAILURE ) {
+ (*position->UI_TapePosRoutine)( TF_IDLE_NOBREAK, position, curDRV->vcb_valid, &curDRV->cur_vcb, 0 ) ;
+ }
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( thw->the, myret.the ) ;
+
+ if( myret.gen_error != GEN_NO_ERR ) {
+ curDRV->thw_inf.drv_status = myret.status ;
+ ret_val = TFLE_DRIVE_FAILURE ;
+ }
+ }
+ }
+
+ if( ret_val == TFLE_NO_ERR ) {
+ ret_val = DisMountTape( curDRV, NULL, FALSE ) ;
+ }
+
+ if( IsTFLE( ret_val ) ) {
+ break ;
+ }
+
+ /* Tell 'em the deal */
+ ui_msg = (*position->UI_TapePosRoutine)( tf_msg, position, curDRV->vcb_valid, &curDRV->cur_vcb, mode ) ;
+
+ BE_Zprintf( DEBUG_TAPE_FORMAT, RES_UI_MSG, ui_msg ) ;
+
+ if( ( ret_val = MountTape( channel->cur_drv, position, &is_tape_present ) ) != TFLE_NO_ERR ) {
+ if( IsTFLE( ret_val ) ) {
+ break ;
+ }
+ ResetDrivePosition( channel->cur_drv ) ;
+
+ if( ui_msg != UI_ABORT_POSITIONING &&
+ ui_msg != UI_HAPPY_ABORT ) {
+
+ tf_msg = ret_val ;
+ ret_val = TFLE_NO_ERR ;
+ continue ;
+ }
+ ret_val = TFLE_NO_ERR ;
+ }
+
+ if( !is_tape_present ) {
+ if( ui_msg != UI_ABORT_POSITIONING &&
+ ui_msg != UI_HAPPY_ABORT ) {
+
+ tf_msg = TF_NO_TAPE_PRESENT ;
+ continue ;
+ }
+
+ } else if( channel->cur_drv->thw_inf.drv_status &
+ ( TPS_NEW_TAPE|TPS_RESET ) ) {
+ switch( ui_msg ) {
+ case UI_ACKNOWLEDGED:
+ case UI_END_POSITIONING:
+ case UI_OVERWRITE:
+ case UI_BOT:
+ case UI_EOD:
+ case UI_CONTINUE_POSITIONING:
+ case UI_NEW_POSITION_REQUESTED:
+ case UI_SEARCH_CHANNEL:
+ case UI_FAST_APPEND:
+ ui_msg = UI_NEW_TAPE_INSERTED ;
+ break ;
+
+ default:
+ break ;
+ }
+ }
+
+ /* Clear Our message for the next loop around */
+ prev_tf_msg = tf_msg ;
+ tf_msg = 0 ;
+
+ /* Process what he Told us */
+ switch( ui_msg ) {
+
+ case UI_END_POSITIONING:
+ if( !write_mode ) {
+ if( ( tmp = StartRead( channel ) ) != TFLE_NO_ERR ) {
+ IsTFLE( tmp ) ? ( ret_val = tmp ) : ( tf_msg = tmp ) ;
+ if( ret_val != TFLE_NO_ERR ) {
+ done = TRUE ;
+ } else {
+ channel->mode |= 0x8000 ;
+ cont_mode = TRUE ;
+ }
+
+ } else {
+ done = TRUE ;
+ }
+ } else {
+ if( IsPosBitSet( curDRV, AT_EOD ) ) {
+ if( channel->cur_fmt == UNKNOWN_FORMAT ||
+ !( lw_fmtdescr[channel->cur_fmt].attributes & APPEND_SUPPORTED ) ) {
+ ret_val = TFLE_APPEND_NOT_ALLOWED ;
+ }
+ }
+ done = TRUE ;
+ }
+ break ;
+
+ case UI_NEW_TAPE_INSERTED:
+ TdemoNewTape( position->tape_id ) ;
+ channel->cur_drv->vcb_valid = FALSE ;
+ if( is_tape_present ) {
+ ClrPosBit( channel->cur_drv, TAPE_FULL ) ;
+ RewindDrive( channel->cur_drv, position, TRUE, TRUE, channel->mode ) ;
+ /* Re-status the drive */
+ UpdateDriveStatus( channel->cur_drv ) ;
+ }
+ break ;
+
+ case UI_BOT:
+ /* Although Update Drive Status should do this if necessary,
+ the ARCHIVE DRIVES have a problem with exceptions */
+ ClrPosBit( channel->cur_drv, TAPE_FULL ) ;
+ channel->cur_drv->vcb_valid = FALSE ;
+ RewindDrive( channel->cur_drv, position, TRUE, TRUE, channel->mode ) ;
+ /* Re-status the drive */
+ UpdateDriveStatus( channel->cur_drv ) ;
+ break ;
+
+ case UI_OVERWRITE:
+ RewindDrive( channel->cur_drv, position, TRUE, TRUE, channel->mode ) ;
+ /* BLATZ - add the code for TF_POSITIONED_FOR_WRITE */
+
+ /* if we're writing */
+ if( write_mode ) {
+
+ /* In case there was EXABYTE SX - 2200+ positioning info in an SX file
+ then delete the SX file corresponding to the physical tape in the drive
+ which is about to be overwritten */
+ SX_DeleteFile( FS_ViewTapeIDInVCB( &curDRV->cur_vcb ),
+ FS_ViewTSNumInVCB( &curDRV->cur_vcb ) ) ;
+
+ /* if this is not continuation positioning */
+ if( !cont_mode ) {
+
+ /* Start a New Tape Family */
+ channel->tape_id = 0L ;
+
+ /* Fix for the app not knowing the LBA for a
+ continuation VCB
+ */
+ channel->cross_set = 0 ;
+ channel->cross_lba = 0UL ;
+ }
+ }
+ done = TRUE ;
+ break ;
+
+
+ case UI_ABORT_POSITIONING:
+ ret_val = TFLE_USER_ABORT ;
+ /* fall through */
+
+ case UI_HAPPY_ABORT:
+ if( prev_tf_msg == TF_NEED_NEW_TAPE ) {
+ ClrChannelStatus( channel, CH_EOS_AT_EOM ) ;
+ FreeFormatEnv( &channel->cur_fmt, &channel->fmt_env ) ;
+ ResetDrivePosition( channel->cur_drv ) ;
+ }
+
+ if( !ret_val ) {
+ ret_val = TFLE_UI_HAPPY_ABORT ;
+ }
+ break ;
+
+ case UI_ACKNOWLEDGED:
+ case UI_CONTINUE_POSITIONING:
+ need_new_vcb = TRUE ;
+ /* BLATZ -- I believe this line should be changed to
+ space = IsPosBitSet( curDRV, AT_EOS ) ? FALSE : TRUE ;
+ This would fix the problem of skipping a set if we
+ are Positioned at the beginning of a set and we return
+ the last read VCB. I am not fixing it right now, as it
+ might break the UI. */
+ space = TRUE ;
+ break ;
+
+ case UI_SEARCH_CHANNEL:
+ case UI_NEW_POSITION_REQUESTED:
+ need_new_vcb = FALSE ;
+ break ;
+
+ case UI_BEGINNING_OF_CHANNEL:
+ ResetChannelList( channel, TRUE ) ;
+ break ;
+
+ case UI_NEXT_DRIVE:
+ tmp = NextDriveInChannel( channel, FALSE ) ;
+ IsTFLE( tmp ) ? ( ret_val = tmp ) : ( tf_msg = tmp ) ;
+ break ;
+
+ case UI_PREVIOUS_DRIVE:
+ tmp = PrevDriveInChannel( channel, FALSE ) ;
+ IsTFLE( tmp ) ? ( ret_val = tmp ) : ( tf_msg = tmp ) ;
+ break ;
+
+ case UI_FAST_APPEND:
+ if( channel->cur_fmt == UNKNOWN_FORMAT ||
+ !( lw_fmtdescr[channel->cur_fmt].attributes & APPEND_SUPPORTED ) ) {
+ ret_val = TFLE_APPEND_NOT_ALLOWED ;
+ done = TRUE ;
+ } else {
+ if( IsPosBitSet( channel->cur_drv, TAPE_FULL ) ) {
+ /* See if there is another drive in the channel */
+ if( NextDriveInChannel( channel, TRUE ) == TF_END_CHANNEL ) {
+ /* If not, start at the beginning and ask for new tape */
+ ResetChannelList( channel, FALSE ) ;
+ tf_msg = TF_NEED_NEW_TAPE ;
+ }
+ } else if( IsPosBitSet( channel->cur_drv, AT_EOD ) ) {
+ /* If we're already at EOD, the old way is faster */
+ need_new_vcb = TRUE ;
+ space = ( !IsPosBitSet( channel->cur_drv, AT_EOS )
+ ? TRUE : FALSE ) ;
+ search_eod = TRUE ;
+ } else {
+ ret_val = SeekEOD( channel ) ;
+ if( ret_val == TF_NEED_NEW_TAPE ) {
+ ret_val = TFLE_NO_ERR ;
+ /* See if there is another drive in the channel */
+ if( NextDriveInChannel( channel, TRUE ) == TF_END_CHANNEL ) {
+ /* If not, start at the beginning and ask for new tape */
+ ResetChannelList( channel, FALSE ) ;
+ tf_msg = TF_NEED_NEW_TAPE ;
+ }
+ } else if( ret_val == TFLE_INCOMPATIBLE_DRIVE ) {
+
+ ret_val = TFLE_NO_ERR ;
+ need_new_vcb = TRUE ;
+ space = ( !IsPosBitSet( channel->cur_drv, AT_EOS )
+ ? TRUE : FALSE ) ;
+ search_eod = TRUE ;
+ } else {
+ done = TRUE ;
+ }
+ }
+ }
+ break ;
+
+ case UI_EOD:
+ if( channel->cur_fmt == UNKNOWN_FORMAT ||
+ !( lw_fmtdescr[channel->cur_fmt].attributes & APPEND_SUPPORTED ) ) {
+ ret_val = TFLE_APPEND_NOT_ALLOWED ;
+ done = TRUE ;
+ } else {
+ /* They are asking to append, and this tape is full */
+ if( IsPosBitSet( channel->cur_drv, TAPE_FULL ) ) {
+ /* See if there is another drive in the channel */
+ if( NextDriveInChannel( channel, TRUE ) == TF_END_CHANNEL ) {
+ /* If not, start at the beginning and ask for new tape */
+ ResetChannelList( channel, FALSE ) ;
+ tf_msg = TF_NEED_NEW_TAPE ;
+ }
+ } else {
+ need_new_vcb = TRUE ;
+ space = ( !IsPosBitSet( channel->cur_drv, AT_EOS )
+ ? TRUE : FALSE ) ;
+ }
+ search_eod = TRUE ;
+ }
+ break ;
+
+
+ default:
+ msassert( FALSE ) ;
+ break ;
+ }
+ }
+ }
+
+ /* If we're in write mode, we may have messed with the position info
+ while seeking to end of data, so we reset it to "don't care" here
+ in case we come back to posatset to get a continuation tape.
+ */
+ if( write_mode ) {
+ position->tape_id = -1 ;
+ position->tape_seq_num = -1 ;
+ }
+
+ if( IsChannelStatus( channel, CH_CONTINUING ) ) {
+ ClrChannelStatus( channel, CH_CONTINUING ) ;
+ if( write_mode ) {
+ /* Restore the write format */
+ FreeFormatEnv( &( channel->cur_fmt ), &( channel->fmt_env ) ) ;
+ channel->cur_fmt = channel->save_fmt ;
+ channel->fmt_env = channel->save_env ;
+ }
+ }
+
+ /* Translate the append operation to the WRITE Operation */
+ channel->mode = ( ( channel->mode == TF_WRITE_APPEND ) ? TF_WRITE_OPERATION : channel->mode ) ;
+
+ /* Update Mode for later */
+ if( !ret_val ) {
+ channel->mode |= 0x8000 ;
+ }
+
+ /* If we are writing, check if the tape is write protected */
+ if( !ret_val && write_mode ) {
+ if( curDRV->thw_inf.drv_status & TPS_WRITE_PROTECT ) {
+ ret_val = TFLE_WRITE_PROTECT ;
+ }
+ }
+
+ /* We Need the current buffer for end of volume processing */
+ if ( write_mode || ( channel->mode != TF_READ_CONTINUE &&
+ channel->mode != TF_SCAN_CONTINUE &&
+ AtEOM( channel ) ) ) {
+ PuntBuffer( channel ) ;
+ }
+
+ return ret_val;
+}
+
+/**/
+/**
+
+ Name: MatchTapeId
+
+ Description: Tests to see if the current tape id matches the desired
+ tape id.
+
+ Modified: 8/10/1989 15:28:19
+
+ Returns: MATCH if it matchs, DONT_CARE if we don't care, and
+ NO_MATCH if we don't match.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+static INT16 _near MatchTapeId(
+ DBLK_PTR dblk,
+ INT32 tape_id )
+{
+ INT16 ret_val = DONT_CARE ;
+
+
+ if( tape_id != -1 ) {
+ ret_val = ( FS_ViewTapeIDInVCB( dblk ) == (UINT32)tape_id ) ? MATCH : NO_MATCH ;
+ }
+
+ return( ret_val ) ;
+
+}
+
+/**/
+/**
+
+ Name: MatchTapeSeq
+
+ Description: Matchs the current DBLKs Tape Sequence number against
+ the specified sequeunce.
+
+ Modified: 8/10/1989 15:30:1
+
+ Returns: MATCH if it matchs, DONT_CARE if we don't care, and
+ NO_MATCH if we don't match.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+static INT16 _near MatchTapeSeq(
+ DBLK_PTR dblk,
+ INT16 seq_num )
+{
+ INT16 ret_val = DONT_CARE ;
+
+
+ if( seq_num != -1 ) {
+ ret_val = ( FS_ViewTSNumInVCB( dblk ) == (UINT16)seq_num ) ? MATCH : NO_MATCH ;
+ }
+
+ return( ret_val ) ;
+
+
+}
+
+/**/
+/**
+
+ Name: MatchBckSet
+
+ Description: Matches the current DBLKs backup set number against the
+ specified number.
+
+ Modified: 8/10/1989 15:31:52
+
+ Returns: MATCH if it matchs, DONT_CARE if we don't care, and
+ NO_MATCH if we don't match.
+
+
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+static INT16 _near MatchBckSet(
+ DBLK_PTR dblk,
+ INT16 bck_set )
+{
+ INT16 ret_val = DONT_CARE ;
+
+
+ if( bck_set != -1 ) {
+ ret_val = ( FS_ViewBSNumInVCB( dblk ) == ( INT16 ) bck_set ) ? MATCH : NO_MATCH ;
+ }
+
+ return( ret_val ) ;
+
+}
diff --git a/private/utils/ntbackup/src/pwxface.c b/private/utils/ntbackup/src/pwxface.c
new file mode 100644
index 000000000..0d9a100d9
--- /dev/null
+++ b/private/utils/ntbackup/src/pwxface.c
@@ -0,0 +1,720 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: pwxface.c
+
+ Description: Password database interface routines used during
+ drive selection and backup, restore, verify operations
+
+ $Log: G:/UI/LOGFILES/PWXFACE.C_V $
+
+ Rev 1.20 26 Jul 1993 19:25:48 MARINA
+enable c++
+
+ Rev 1.19 01 Nov 1992 16:05:58 DAVEV
+Unicode changes
+
+ Rev 1.18 07 Oct 1992 14:54:48 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.17 04 Oct 1992 19:40:08 DAVEV
+Unicode Awk pass
+
+ Rev 1.16 14 May 1992 17:24:06 MIKEP
+nt pass 2
+
+ Rev 1.15 18 Mar 1992 16:58:22 JOHNWT
+updated to work with new passdb.c
+
+ Rev 1.14 06 Feb 1992 17:42:36 JOHNWT
+made pwdb compat with 3.1
+
+ Rev 1.13 27 Jan 1992 12:47:54 GLENN
+Changed dialog support calls.
+
+ Rev 1.12 21 Jan 1992 13:51:40 JOHNWT
+correct error processing
+
+ Rev 1.11 21 Jan 1992 11:28:44 JOHNWT
+fixed UAE on full disk
+
+ Rev 1.10 20 Jan 1992 10:24:28 CARLS
+added a call to DM_CenterDialog
+
+ Rev 1.9 13 Jan 1992 10:27:22 JOHNWT
+added help
+
+ Rev 1.8 09 Jan 1992 14:49:24 JOHNWT
+added confirm new pw
+
+ Rev 1.7 06 Jan 1992 13:46:36 JOHNWT
+added remove pw protection
+
+ Rev 1.6 23 Dec 1991 15:47:20 JOHNWT
+PW for PWDB II
+
+ Rev 1.5 20 Dec 1991 09:35:26 DAVEV
+16/32 bit port - 2nd pass
+
+ Rev 1.4 16 Dec 1991 15:52:46 JOHNWT
+added parent window to EnterDBPassword
+
+ Rev 1.3 16 Dec 1991 15:28:40 JOHNWT
+added YY countdown timer
+
+ Rev 1.2 14 Dec 1991 13:44:08 JOHNWT
+changes for pw to enable db
+
+ Rev 1.1 04 Dec 1991 15:21:48 MIKEP
+remoce pwxface.h
+
+ Rev 1.0 20 Nov 1991 19:18:36 SYSTEM
+Initial revision.
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+/* module defines */
+
+#define PW_READ_ERR 0 /* error in read attempt */
+#define PW_NOT_FOUND 1 /* no pw for key found */
+#define PW_FOUND 2 /* pw for the key found */
+
+/* struct for data used by dialog procedure to get PWDB lock pw */
+
+typedef struct PWDB_DATA {
+
+ CHAR password[MAX_LOCKPW_SIZE]; /* pw to match (passed to dlg) */
+ CHAR new_password[MAX_LOCKPW_SIZE]; /* new password passed back */
+ INT allow_new; /* enable new passwd field */
+
+} PWDB_DATA, *PWDB_DATA_PTR;
+
+/* module functions */
+
+static DB_HAND_PTR OpenPwdbase ( CDS_PTR );
+static VOID ClosePwdbase ( DB_HAND_PTR );
+static INT16 GetDLEPassword ( CDS_PTR, GENERIC_DLE_PTR, CHAR_PTR );
+static INT16 GetPassword ( CDS_PTR, CHAR_PTR, CHAR_PTR );
+static VOID clock_routine ( VOID );
+
+/* module-wide variables */
+
+PWDB_DATA_PTR mw_verify_pw_ptr; /* pointer used by dialog proc */
+DB_HAND mw_pw_hand;
+
+
+/*****************************************************************************
+
+ Name: CheckThePWDBase
+
+ Description: Checks to see if the pwdb is enabled, if so, it checks
+ to see if the pwdb password has been entered. If not,
+ it prompts for the pwdb password. If all is ok, it opens
+ the pwdb and attempts to read the info for the DLE.
+
+ Returns: SUCCESS - pw info successfully read from pwdb
+ FAILURE - must prompt user for pw
+
+ Notes:
+
+*****************************************************************************/
+
+INT16 CheckThePWDBase(
+CDS_PTR conf_ptr, /* I - config pointer */
+GENERIC_DLE_PTR dle_ptr ) /* I - DLE for match */
+{
+ INT16 result = FAILURE;
+ CHAR pw_buffer[ MAX_PWDBASE_REC_SIZE + 1 ];
+
+ /* if the db password was verified, look for the DLE info */
+
+ if ( gfPWForPWDBState == DBPW_VERIFIED ) {
+ result = GetDLEPassword( conf_ptr, dle_ptr, pw_buffer );
+ }
+
+ return( result );
+}
+
+
+/*****************************************************************************
+
+ Name: IsThereADBPassword
+
+ Description: Checks to see if a password exists for the DB.
+
+ Modified: 12/23/91
+
+ Returns: TRUE
+ FALSE
+
+*****************************************************************************/
+
+BOOLEAN IsThereADBPassword( VOID )
+{
+ CHAR pw_buffer[ MAX_PWDBASE_REC_SIZE + 1 ];
+
+ /* look for the db password in the db */
+
+ if ( GetPassword( CDS_GetPerm(), DBPW_KEY, pw_buffer ) == PW_FOUND ) {
+
+ if ( strnicmp( DBPW_NODBPW, pw_buffer, MAX_LOCKPW_SIZE ) != 0 ) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+/*****************************************************************************
+
+ Name: EnterDBPassword
+
+ Description: Retrieves the password for the DB from the DB using the
+ unique key. If found it initializes the data buffer.
+ The password dialog is then displayed. If OK is returned,
+ a successful pw was entered. If a new one was specified,
+ it is saved in the DB.
+
+ Modified: 12/23/91
+
+ Returns: SUCCESS - pw successfully entered
+ FAILURE - pw not entered or incorrect
+
+*****************************************************************************/
+
+INT16 EnterDBPassword(
+CDS_PTR conf_ptr, /* I - config pointer */
+HWND hWnd, /* parent window */
+INT allow_new ) /* I - allow new pw to be entered */
+{
+ INT16 pw_result = PW_FOUND;
+ CHAR pw_buffer[ MAX_PWDBASE_REC_SIZE + 1 ];
+ PWDB_DATA verify_pw;
+
+ /* look for the db password in the db */
+
+ pw_result = GetPassword( conf_ptr, DBPW_KEY, pw_buffer );
+
+ if ( pw_result != PW_READ_ERR ) {
+
+ verify_pw.password[0] = 0;
+ verify_pw.new_password[0] = 0;
+ verify_pw.allow_new = allow_new;
+
+ /* if the pw for the db was found, and it is not the dummy pw, copy
+ to buffer for use in compare in dialog procedure */
+
+ if ( ( pw_result == PW_FOUND ) &&
+ ( strnicmp( DBPW_NODBPW, pw_buffer, MAX_LOCKPW_SIZE ) != 0 ) ) {
+ strcpy( verify_pw.password, pw_buffer );
+ }
+
+ /* set the module-wide ptr and call the dialog */
+
+ mw_verify_pw_ptr = &verify_pw;
+
+ if ( DM_ShowDialog( hWnd, IDD_PWDB_PASSWORD, NULL ) ==
+ DM_SHOWOK ) {
+
+ if ( gfPWForPWDBState == DBPW_VERIFIED ) {
+
+ /* if a new password was specified, save it in the db */
+
+ if ( verify_pw.new_password[0] != 0 ) {
+ SavePassword( conf_ptr, DBPW_KEY, verify_pw.new_password );
+ }
+
+ return SUCCESS;
+
+ }
+ }
+ }
+
+ return FAILURE;
+}
+
+
+/*****************************************************************************
+
+ Name: DM_PWDBPassword
+
+ Description: Dialog procedure for the DB password. If a password is
+ already in the buffer, we init the dialog normally.
+ Otherwise we assume it is the first time and only enable
+ the new password field. The password is verified and
+ the global verified flag set after OK is pressed.
+
+ Modified: 12/14/91
+
+ Returns: TRUE - message processed
+ FALSE - message ignored
+
+*****************************************************************************/
+
+DLGRESULT APIENTRY DM_PWDBPassword (
+
+ HWND hDlg,
+ MSGID msg,
+ MPARAM1 mp1,
+ MPARAM2 mp2 )
+
+{
+ CHAR pw_input[ MAX_LOCKPW_SIZE ]; /* temp buffer for user input */
+ static INT attempts;
+
+ UNREFERENCED_PARAMETER ( mp2 );
+
+ switch ( msg ) {
+
+ case WM_INITDIALOG :
+
+ DM_CenterDialog( hDlg ) ;
+
+ /* set the text limits on the password fields */
+
+ SendDlgItemMessage( hDlg, IDD_PWDB_PW, EM_LIMITTEXT,
+ (MPARAM1) MAX_LOCKPW_LEN, (MPARAM2) NULL );
+ SendDlgItemMessage( hDlg, IDD_PWDB_NEWPW, EM_LIMITTEXT,
+ (MPARAM1) MAX_LOCKPW_LEN, (MPARAM2) NULL );
+ SendDlgItemMessage( hDlg, IDD_PWDB_CONFIRM, EM_LIMITTEXT,
+ (MPARAM1) MAX_LOCKPW_LEN, (MPARAM2) NULL );
+
+ /* if no password was passed in, disable the password window */
+
+ if ( mw_verify_pw_ptr->password[0] == 0 ) {
+
+ EnableWindow( GetDlgItem( hDlg, IDD_PWDB_PW ), FALSE );
+ EnableWindow( GetDlgItem( hDlg, IDD_PWDB_PWTEXT ), FALSE );
+
+ }
+
+ /* if the new option is disabled, disable the new password window */
+
+ if ( mw_verify_pw_ptr->allow_new == DBPW_NO_NEW ) {
+
+ EnableWindow( GetDlgItem( hDlg, IDD_PWDB_NEWPW ), FALSE );
+ EnableWindow( GetDlgItem( hDlg, IDD_PWDB_NEWPWTEXT ), FALSE );
+ EnableWindow( GetDlgItem( hDlg, IDD_PWDB_CONFIRM ), FALSE );
+ EnableWindow( GetDlgItem( hDlg, IDD_PWDB_CONFTEXT ), FALSE );
+
+ }
+
+ attempts = 0; /* user gets 3 attempts */
+
+ return TRUE ;
+
+ case WM_COMMAND :
+
+ switch ( GET_WM_COMMAND_ID ( mp1, mp2 ) ) {
+
+ case IDOK:
+
+ /* first get the text in the new password field */
+
+ GetDlgItemText( hDlg, IDD_PWDB_NEWPW,
+ mw_verify_pw_ptr->new_password,
+ MAX_LOCKPW_SIZE );
+
+ /* if the user entered a new password, make sure it matches
+ the confirm field */
+
+ if ( mw_verify_pw_ptr->new_password[0] != 0 ) {
+
+ GetDlgItemText( hDlg, IDD_PWDB_CONFIRM, pw_input, MAX_LOCKPW_SIZE );
+ if ( strnicmp( mw_verify_pw_ptr->new_password, pw_input,
+ MAX_LOCKPW_SIZE ) != 0 ) {
+ WM_MessageBox( ID( IDS_BKUP_PASSWORD_ERROR_TITLE ),
+ ID( RES_PWDB_BAD_CONFIRM ),
+ WMMB_OK, WMMB_ICONEXCLAMATION, NULL, 0, 0 );
+ SetFocus( GetDlgItem ( hDlg, IDD_PWDB_CONFIRM ) );
+ return TRUE;
+ }
+
+ }
+
+ /* if no password was required (first time), simply
+ check for the new password, don't exit without it */
+
+ if ( mw_verify_pw_ptr->password[0] == 0 ) {
+
+ if ( mw_verify_pw_ptr->new_password[0] == 0 ) {
+ SetFocus( GetDlgItem ( hDlg, IDD_PWDB_NEWPW ) );
+ return TRUE;
+ } else {
+ gfPWForPWDBState = DBPW_VERIFIED;
+ }
+
+ } else {
+
+ /* get the pw the user entered and compare it to the
+ one in the buffer */
+
+ attempts++;
+ GetDlgItemText( hDlg, IDD_PWDB_PW, pw_input, MAX_LOCKPW_SIZE );
+
+ if ( strnicmp( mw_verify_pw_ptr->password, pw_input,
+ MAX_LOCKPW_SIZE ) != 0 ) {
+
+ /* WRONG! If we have 3 invalids, lock them out. Else,
+ inform the user then erase the input fields,
+ reset the focus and set the global flag to false. */
+
+ if ( attempts == MAX_ATTEMPTS ) {
+
+ gfPWForPWDBState = DBPW_LOCKOUT;
+
+ WM_MessageBox( ID( IDS_BKUP_PASSWORD_ERROR_TITLE ),
+ ID( RES_PWDB_DISABLED ),
+ WMMB_OK, WMMB_ICONEXCLAMATION, NULL, 0, 0 );
+
+ } else {
+
+ WM_MessageBox( ID( IDS_BKUP_PASSWORD_ERROR_TITLE ),
+ ID( RES_MISMATCHED_PASSWORD ),
+ WMMB_OK, WMMB_ICONEXCLAMATION, NULL, 0, 0 );
+
+ SetDlgItemText( hDlg, IDD_PWDB_PW, TEXT("") );
+ SetDlgItemText( hDlg, IDD_PWDB_NEWPW, TEXT("") );
+ SetDlgItemText( hDlg, IDD_PWDB_CONFIRM, TEXT("") );
+ SetFocus( GetDlgItem ( hDlg, IDD_PWDB_PW ) );
+ gfPWForPWDBState = DBPW_NOT_VERIFIED;
+
+ return TRUE;
+
+ }
+
+ } else {
+
+ /* everything was peachy */
+
+ gfPWForPWDBState = DBPW_VERIFIED;
+ }
+
+ }
+
+ EndDialog ( hDlg, DM_SHOWOK ) ;
+ return TRUE ;
+
+ case IDCANCEL:
+
+ EndDialog ( hDlg, DM_SHOWCANCEL ) ;
+ return TRUE ;
+
+ case IDHELP:
+
+ HM_DialogHelp( HELPID_DIALOGPWDBPASSWORD ) ;
+
+ return TRUE;
+ }
+
+ break ;
+
+ }
+ return FALSE ;
+}
+
+
+/*****************************************************************************
+
+ Name: SaveDLEPassword
+
+ Description: This function is used to add a new entry to the password
+ database. Both the username and the password are passed
+ into this module.
+
+ Returns: (void)
+
+ Notes: If any errors occurred during the database update operation,
+ they are reported here via eresprintf and processing should
+ continue normally
+
+*****************************************************************************/
+
+VOID SaveDLEPassword(
+CDS_PTR conf_ptr,
+GENERIC_DLE_PTR dle_ptr,
+CHAR_PTR pw_buffer,
+CHAR_PTR user_name )
+{
+
+ CHAR password[ MAX_PWDBASE_REC_SIZE + 1 ];
+
+ /* if a password is required for this DLE save it in the password database */
+
+ if( DLE_PswdRequired( dle_ptr ) && CDS_GetEnablePasswordDbase( conf_ptr ) ) {
+
+ strcpy( password, TEXT("") ) ;
+
+ switch ( DLE_GetDeviceType( dle_ptr ) ) {
+
+ case NOVELL_SERVER_ONLY:
+ strcpy( password, user_name ) ;
+ strcat( password, TEXT("/") ) ;
+ break ;
+
+ default:
+ break ;
+ }
+
+ strcat( password, pw_buffer );
+
+ if ( SavePassword( conf_ptr, DLE_GetDeviceName( dle_ptr ), password )
+ == SUCCESS ) {
+
+ switch ( DLE_GetDeviceType( dle_ptr ) ) {
+
+ case NOVELL_SERVER_ONLY:
+ DLE_UserSaved( dle_ptr ) = TRUE;
+ DLE_PswdSaved( dle_ptr ) = TRUE;
+ break ;
+
+ default:
+ break ;
+ }
+ }
+ }
+
+ return ;
+}
+
+
+/*****************************************************************************
+
+ Name: SavePassword
+
+ Description: This function is used to add a new entry to the password
+ database.
+
+ Returns: SUCCESS/FAILURE
+
+ Notes: If any errors occurred during the database update operation,
+ they are reported here via eresprintf and processing should
+ continue normally
+
+*****************************************************************************/
+
+INT16 SavePassword(
+CDS_PTR conf_ptr,
+CHAR_PTR key_ptr,
+CHAR_PTR password )
+{
+ INT16 pw_error;
+ INT16 result = FAILURE;
+ DB_HAND_PTR pw_hand;
+
+ pw_hand = OpenPwdbase( conf_ptr );
+
+ if ( pw_hand != NULL ) {
+
+ pw_error = (INT16)PD_Write( pw_hand, key_ptr, password );
+
+ switch( pw_error ) {
+
+ case PD_NO_ERROR :
+ result = SUCCESS;
+ break;
+
+ case PD_WRITE_ERROR :
+ CDS_SetEnablePasswordDbase( conf_ptr, FALSE ) ;
+ eresprintf( RES_ERROR_UPDATING_PDBASE );
+ break;
+
+ case PD_READ_ERROR :
+ CDS_SetEnablePasswordDbase( conf_ptr, FALSE ) ;
+ eresprintf( RES_ERROR_READING_PDBASE );
+ break;
+
+ case PD_FULL :
+ eresprintf( RES_PDBASE_FULL );
+ break;
+
+ default :
+ CDS_SetEnablePasswordDbase( conf_ptr, FALSE ) ;
+ eresprintf( RES_UNKNOWN_PDBASE_ERROR, pw_error );
+ break ;
+ }
+
+ ClosePwdbase( pw_hand );
+ }
+
+ return result;
+}
+
+
+/*****************************************************************************
+
+ Name: GetDLEPassword
+
+ Description: Interfaces to password database to read a password for
+ a specified device.
+
+ Returns: FAILURE meaning that a user password prompt is required
+ SUCCESS in reading a password, meaning that the user is not
+ required to be prompted
+
+*****************************************************************************/
+
+INT16 GetDLEPassword(
+CDS_PTR conf_ptr,
+GENERIC_DLE_PTR dle_ptr,
+CHAR_PTR pw_buffer )
+{
+ INT16 result = FAILURE;
+ CHAR_PTR p;
+
+ /* check for saved password */
+
+ if ( GetPassword( conf_ptr, DLE_GetDeviceName( dle_ptr ), pw_buffer ) ==
+ PW_FOUND ) {
+
+ result = SUCCESS;
+
+ switch ( DLE_GetDeviceType( dle_ptr ) ) {
+
+ case NOVELL_SERVER_ONLY:
+
+ p = strchr( pw_buffer, TEXT('/') ) ;
+ msassert ( p != NULL ) ;
+ *(p++) = TEXT('\0') ;
+ strcpy( DLE_GetServerUserName ( dle_ptr ), pw_buffer ) ;
+ strcpy( DLE_GetServerPswd ( dle_ptr ), p ) ;
+ DLE_UserSaved ( dle_ptr ) = TRUE ;
+ DLE_PswdSaved ( dle_ptr ) = TRUE ;
+
+ break ;
+
+ default:
+ break ;
+ }
+ }
+
+ return result;
+}
+
+
+/*****************************************************************************
+
+ Name: GetPassword
+
+ Description: Interfaces to password database to read a password for
+ a specified key.
+
+ Returns: PW_READ_ERR - could not read the db
+ PW_NOT_FOUND - key not found in db
+ PW_FOUND - found it
+
+*****************************************************************************/
+
+INT16 GetPassword(
+CDS_PTR conf_ptr,
+CHAR_PTR key_ptr,
+CHAR_PTR pw_buffer )
+{
+ INT16 pw_error;
+ INT16 result = PW_READ_ERR;
+ DB_HAND_PTR pw_hand;
+
+ pw_hand = OpenPwdbase( conf_ptr );
+
+ if ( pw_hand != NULL ) {
+
+ pw_error = (INT16)PD_Read( pw_hand, key_ptr, pw_buffer );
+
+ switch( pw_error ) {
+
+ case PD_NO_ERROR :
+ result = PW_FOUND;
+ break ;
+
+ case PD_MEMORY_ERROR :
+ CDS_SetEnablePasswordDbase( conf_ptr, FALSE ) ;
+ eresprintf( RES_OUT_OF_MEMORY ) ;
+ break ;
+
+ case PD_NOT_FOUND :
+ /* requested database key not found, return with indication
+ that user must be prompted for password */
+ result = PW_NOT_FOUND;
+ break ;
+
+ default :
+ CDS_SetEnablePasswordDbase( conf_ptr, FALSE ) ;
+ eresprintf( RES_ERROR_READING_PDBASE ) ;
+ break ;
+ }
+
+ ClosePwdbase( pw_hand );
+ }
+
+ return result;
+}
+
+
+/*****************************************************************************
+
+ Name: OpenPwdbase
+
+ Description: Opens the password database through a call to PD_Open
+
+ Returns: Handle of db or NULL for failure
+
+ Notes: Will set the module wide password database handle so that
+ subsequent database calls should be performed
+
+*****************************************************************************/
+
+DB_HAND_PTR OpenPwdbase(
+
+CDS_PTR conf_ptr )
+{
+ UINT16 pw_error ; /* password database error */
+ CHAR pwd_file[MAX_UI_PATH_SIZE] ;
+
+ /* concatenate the path and password file name. */
+
+ strcpy ( pwd_file, CDS_GetUserDataPath () );
+ strcat ( pwd_file, CDS_GetPwDbaseFname ( conf_ptr ) );
+
+ /* open password database */
+
+ pw_error = PD_Open( &mw_pw_hand, pwd_file ) ;
+
+ if( pw_error != PD_NO_ERROR ) {
+ eresprintf( RES_ERROR_OPENING_PWDBASE ) ;
+ CDS_SetEnablePasswordDbase( conf_ptr, FALSE ) ;
+ return (DB_HAND_PTR) NULL;
+ }
+
+ return &mw_pw_hand;
+}
+
+
+/*****************************************************************************
+
+ Name: ClosePwdbase
+
+ Description: Interfaces with the password database to close the file
+
+ Returns: (void)
+
+ Notes: Does not attempt the operation if the current pw_handle is NULL
+
+*****************************************************************************/
+
+VOID ClosePwdbase(
+
+DB_HAND_PTR pw_hand )
+{
+ if( pw_hand ) {
+ PD_Close( pw_hand ) ;
+ }
+
+ return ;
+}
diff --git a/private/utils/ntbackup/src/qtc_add.c b/private/utils/ntbackup/src/qtc_add.c
new file mode 100644
index 000000000..e883daf10
--- /dev/null
+++ b/private/utils/ntbackup/src/qtc_add.c
@@ -0,0 +1,1028 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: QTC_ADD.C
+
+ Description:
+
+ The functions used when constructing catalog information about
+ a new bset being backed up or a tape being cataloged.
+
+ $Log: N:\LOGFILES\QTC_ADD.C_V $
+
+ Rev 1.15 10 Mar 1994 22:09:56 MIKEP
+fix memory leak
+
+ Rev 1.14 11 Dec 1993 11:48:22 MikeP
+fix bug overwriting byte that wasn't mine
+
+ Rev 1.13 06 Dec 1993 09:46:16 mikep
+Very deep path support & unicode fixes
+
+ Rev 1.12 05 Nov 1993 08:45:04 MIKEP
+fix error msg reporting
+
+ Rev 1.11 03 Nov 1993 09:06:58 MIKEP
+warning fixes
+
+ Rev 1.10 28 Oct 1993 14:50:20 MIKEP
+dll changes
+
+ Rev 1.9 29 Jul 1993 14:42:34 MIKEP
+fix support for >32bit set sizes
+
+ Rev 1.8 21 Apr 1993 17:23:58 TERRI
+Placed a NULL after path in QTC_AddDir.
+
+ Rev 1.7 14 Apr 1993 13:05:38 Stefan
+Fixed really minor warning (there was an newline within a single line comment)
+
+ Rev 1.6 25 Feb 1993 13:05:54 STEVEN
+changes from MIKEP @Msoft
+
+ Rev 1.5 30 Jan 1993 12:06:24 DON
+Removed compiler warnings
+
+ Rev 1.4 14 Dec 1992 12:28:42 DAVEV
+Enabled for Unicode compile
+
+ Rev 1.3 20 Nov 1992 13:37:06 CHARLIE
+JAGUAR: Move to SRM based QTC code
+
+ENDEAVOR: Replaced rroduct conditionals with NOT_MTF4_0. Such conditions
+are no longer determined on a product basis.
+
+ Rev 1.2 06 Nov 1992 15:30:14 DON
+Change debug.h to be_debug.h and zprintf to BE_Zprintf
+
+ Rev 1.1 09 Oct 1992 11:53:46 MIKEP
+unicode pass
+
+ Rev 1.0 03 Sep 1992 16:56:10 STEVEN
+Initial revision.
+
+ Rev 1.17 12 Aug 1992 18:21:04 STEVEN
+alignment problems
+
+ Rev 1.16 09 Jul 1992 10:30:40 MIKEP
+chnages
+
+
+****************************************************/
+
+#include <dos.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <io.h>
+#include <string.h>
+#include <time.h>
+#include <share.h>
+#include <malloc.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "stdwcs.h"
+#include "qtc.h"
+
+// unicode text macro
+#ifndef UNALIGNED
+#define UNALIGNED
+#endif
+
+#ifndef TEXT
+#define TEXT( x ) x
+#endif
+
+
+/********
+
+ We were doing a backup or catalog operation. When we hit a directory entry we
+ go back and record the number of files and bytes in the previous directory.
+ But this time we hit two directories in a row, so mark the last one empty.
+
+********/
+
+INT QTC_MarkLastDirEmpty( QTC_BUILD_PTR build )
+{
+ QTC_RECORD_PTR record_ptr;
+ UINT32 record_num;
+ INT size;
+ INT Error;
+
+
+
+ // Why don't we default every entry to empty. So this function is not needed at all ?
+
+
+
+ // If this dir is empty then no files have been added since we added
+ // it, so it was the last record added.
+
+ // See if record is still in buffer, 90% success rate.
+
+
+ // If offset is not 0, then the last entry is in the buffer.
+
+ if ( build->rec_offset ) {
+
+ record_ptr = (QTC_RECORD_PTR)(build->rec_buffer + build->rec_offset);
+ record_ptr--;
+
+ record_ptr->status |= QTC_EMPTY;
+
+ return( SUCCESS );
+ }
+
+ // Back up one record and turn the empty bit on.
+
+ record_num = build->record_cnt - 1;
+
+ QTC_SeekFile( build->fh_rec, record_num * sizeof(QTC_RECORD) );
+
+ size = QTC_ReadFile( build->fh_rec, (BYTE_PTR)&(build->record), sizeof(QTC_RECORD), &Error );
+
+ if ( size == sizeof(QTC_RECORD ) ) {
+
+ build->record.status |= QTC_EMPTY;
+
+ QTC_SeekFile( build->fh_rec, record_num * sizeof(QTC_RECORD) );
+
+ size = QTC_WriteFile( build->fh_rec, (BYTE_PTR)&(build->record), sizeof(QTC_RECORD), &Error );
+
+ if ( size != sizeof( QTC_RECORD ) ) {
+ build->error = Error;
+ build->state = QTC_ERROR_STATE;
+ QTC_ErrorCleanup( build );
+ return( FAILURE );
+ }
+ }
+ else {
+
+ build->error = QTC_READ_FAILED;
+ build->state = QTC_ERROR_STATE;
+ QTC_ErrorCleanup( build );
+ return( FAILURE );
+ }
+
+ return( SUCCESS );
+
+}
+
+INT QTC_SetCountsForLastDir( QTC_BUILD_PTR build )
+{
+ QTC_NAME UNALIGNED *name; // Fix for MIPS portability.
+ INT bytes_to_add;
+ INT bytes;
+ INT Error;
+ UINT32 temp32;
+ UINT32 UNALIGNED *i32;
+ BYTE buffer[ QTC_BUF_SIZE ];
+ BYTE data[ 15 ];
+
+
+ if ( build == NULL ) {
+ return( FAILURE );
+ }
+
+ if ( build->error ) {
+ return( FAILURE );
+ }
+
+ if ( ! build->do_full_cataloging ) {
+ return( SUCCESS );
+ }
+
+ if ( build->state != QTC_ACTIVE_STATE ) {
+ return( SUCCESS );
+ }
+
+ if ( build->record_cnt == 0 ) {
+ return( SUCCESS );
+ }
+
+ if ( build->files_in_dir == 0 ) {
+
+ QTC_MarkLastDirEmpty( build );
+ return( SUCCESS );
+ }
+
+ // We need to add the bytes and files info to the xtra bytes
+ // for the last dir entry.
+
+ if ( U64_Msw( build->bytes_in_dir ) ) {
+
+ // Use QTC_BYTE_COUNT_MSW, QTC_FILE_COUNT && QTC_BYTE_COUNT_LSW
+
+ bytes_to_add = 15;
+
+ data[ 0 ] = QTC_FILE_COUNT;
+ i32 = (UINT32 *)&data[ 1 ];
+ *i32 = build->files_in_dir;
+
+ data[ 5 ] = QTC_BYTE_COUNT_LSW;
+
+ i32 = (UINT32 *)&data[ 6 ];
+ *i32 = U64_Lsw( build->bytes_in_dir );
+
+ data[ 10 ] = QTC_BYTE_COUNT_MSW;
+
+ i32 = (UINT32 *)&data[ 11 ];
+ *i32 = U64_Msw( build->bytes_in_dir );
+ }
+ else {
+
+ if ( ( build->files_in_dir < 256 ) &&
+ ! ( U64_Lsw( build->bytes_in_dir ) & 0xFF000000L ) ) {
+
+ temp32 = U64_Lsw( build->bytes_in_dir );
+ temp32 += (UINT32)build->files_in_dir << 24;
+
+ // Use QTC_COMBO_COUNT
+ bytes_to_add = 5;
+
+ data[ 0 ] = QTC_COMBO_COUNT;
+ i32 = (UINT32 *)&data[ 1 ];
+ *i32 = temp32;
+
+ }
+ else {
+ // Use QTC_FILE_COUNT && QTC_BYTE_COUNT_LSW
+
+ bytes_to_add = 10;
+
+ data[ 0 ] = QTC_FILE_COUNT;
+ i32 = (UINT32 *)&data[ 1 ];
+ *i32 = build->files_in_dir;
+
+ data[ 5 ] = QTC_BYTE_COUNT_LSW;
+
+ i32 = (UINT32 *)&data[ 6 ];
+ *i32 = U64_Lsw( build->bytes_in_dir );
+ }
+ }
+
+ // We now know what to add, find the correct place to add it.
+ // If we are lucky, and we are very lucky, it will still be
+ // in the buffer, not on disk.
+
+ if ( build->curr_dir_off < build->last_mom_offset ) {
+
+ // starts in buffer
+
+ if ( bytes_to_add + build->dir_offset <= QTC_BUF_SIZE ) {
+
+ // finishes in buffer also
+
+ memcpy( &build->dir_buffer[ build->dir_offset ], &data, bytes_to_add );
+ build->dir_offset += bytes_to_add;
+
+ name = (QTC_NAME_PTR)&build->dir_buffer[ build->last_mom_offset - build->curr_dir_off ];
+
+ name->size += bytes_to_add;
+ name->xtra_size += bytes_to_add;
+
+ // We be done !
+
+ return( SUCCESS );
+ }
+ }
+
+
+ // Write out buffer and work on file.
+
+ bytes = QTC_WriteFile( build->fh_dir, build->dir_buffer, build->dir_offset, &Error );
+
+ if ( bytes != build->dir_offset ) {
+ build->error = Error;
+ build->state = QTC_ERROR_STATE;
+ QTC_ErrorCleanup( build );
+ return( FAILURE );
+ }
+
+ build->curr_dir_off += bytes; // increment file size
+ build->dir_offset = 0; // reset buff pointer to empty
+
+ // get data from file
+
+ QTC_SeekFile( build->fh_dir, build->last_mom_offset );
+
+ bytes = QTC_ReadFile( build->fh_dir, buffer, (INT)(build->curr_dir_off - build->last_mom_offset), &Error );
+
+ // work on it
+
+ name = (QTC_NAME_PTR)buffer;
+
+ name->size += bytes_to_add;
+ name->xtra_size += bytes_to_add;
+
+ memcpy( &buffer[ bytes ], data, bytes_to_add );
+
+ // write it back
+
+ QTC_SeekFile( build->fh_dir, build->last_mom_offset );
+
+ QTC_WriteFile( build->fh_dir, buffer, bytes + bytes_to_add, &Error );
+
+ // notice file pointer is left at end of file !
+
+ // update file size
+
+ build->curr_dir_off += bytes_to_add; // increment file size
+
+ return( SUCCESS );
+}
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+VOID QTC_AddDirectoryToCatalog(
+QTC_BUILD_PTR build,
+UINT64 DisplaySize,
+CHAR_PTR szPath,
+INT nPathLength,
+UINT16 Date,
+UINT16 Time,
+UINT32 Attribute,
+UINT32 LBA,
+BYTE_PTR xtra_bytes,
+UINT xtra_size )
+{
+ BYTE temp_xtra_bytes[ QTC_MAX_XTRA_BYTES ];
+ INT temp_xtra_size;
+ CHAR *buffer;
+ INT path_len; // path length in characters
+ UINT32 size_msw;
+
+ // Make sure we don't UAE in my code.
+
+ if ( build == NULL ) {
+ return;
+ }
+
+ if ( ! build->do_full_cataloging ||
+ build->error ||
+ ( build->header == NULL ) ) {
+ return;
+ }
+
+ // Copy the xtra bytes to a larger buffer, in case we have to add
+ // to them with a 64 bit file size.
+
+ if ( xtra_size ) {
+ memcpy( temp_xtra_bytes, xtra_bytes, xtra_size );
+ }
+ temp_xtra_size = xtra_size;
+
+ QTC_SetCountsForLastDir( build );
+
+ // Clear out counts
+
+ build->files_in_dir = 0;
+ build->bytes_in_dir = U64_Init( 0L, 0L );
+
+ build->header->num_bytes += U64_Lsw( DisplaySize );
+ size_msw = U64_Msw( DisplaySize );
+
+ if ( size_msw ) {
+
+ // add high part to xtrabytes
+
+ temp_xtra_bytes[ temp_xtra_size++ ] = QTC_XTRA_64BIT_SIZE;
+ memcpy( &temp_xtra_bytes[ temp_xtra_size ], &size_msw, 4 );
+ temp_xtra_size += 4;
+ }
+
+ buffer = malloc( nPathLength );
+ if ( buffer == NULL ) {
+ return;
+ }
+
+ memcpy( buffer, szPath, nPathLength );
+ path_len = nPathLength / sizeof(CHAR);
+
+ build->record.status = QTC_DIRECTORY;
+
+ build->record.date = Date;
+ build->record.time = Time;
+
+ build->record.attribute = Attribute;
+ build->record.lba = LBA;
+
+ // Fake a root if needed.
+
+ if ( ( path_len != 1 ) && ( build->record_cnt == 0 ) ) {
+ QTC_AddDir( build, TEXT(""), 1,
+ temp_xtra_bytes, temp_xtra_size );
+ }
+
+ QTC_AddDir( build, buffer, path_len,
+ temp_xtra_bytes, temp_xtra_size );
+
+ free( buffer );
+}
+
+
+
+VOID QTC_AddFileToCatalog(
+QTC_BUILD_PTR build,
+UINT64 DisplaySize,
+CHAR_PTR szFile,
+UINT16 Date,
+UINT16 Time,
+UINT32 Attribute,
+UINT32 LBA,
+UINT32 AFPObject,
+BYTE_PTR xtra_bytes,
+UINT xtra_size )
+{
+ BYTE temp_xtra_bytes[ QTC_MAX_XTRA_BYTES ];
+ INT temp_xtra_size;
+ UINT32 size_msw;
+ BOOLEAN u64_stat;
+ UINT64 temp64;
+
+ if ( build == NULL ) {
+ return;
+ }
+
+ if ( ! build->do_full_cataloging ||
+ build->error ||
+ ( build->header == NULL ) ) {
+ return;
+ }
+
+ // Copy the xtra bytes to a larger buffer, in case we have to add
+ // to them with a 64 bit file size.
+
+ if ( xtra_size ) {
+ memcpy( temp_xtra_bytes, xtra_bytes, xtra_size );
+ }
+ temp_xtra_size = xtra_size;
+
+ // switch based on what type dblk they passed us.
+
+ build->header->num_files++;
+
+ // Add file size to size of set.
+
+ temp64 = U64_Init( build->header->num_bytes, build->header->num_bytes_msw );
+ temp64 = U64_Add( temp64, DisplaySize, &u64_stat );
+
+ build->header->num_bytes = U64_Lsw( temp64 );
+ build->header->num_bytes_msw = U64_Msw( temp64 );
+
+ // Get high 32 bits of file size.
+
+ size_msw = U64_Msw( DisplaySize );
+
+ if ( size_msw ) {
+
+ // put high part of file size into xtrabytes
+
+ temp_xtra_bytes[ temp_xtra_size++ ] = QTC_XTRA_64BIT_SIZE;
+ memcpy( &temp_xtra_bytes[ temp_xtra_size ], &size_msw, 4 );
+ temp_xtra_size += 4;
+ }
+
+ // We keep file and byte counts on a per dir basis
+
+ build->files_in_dir++;
+
+ build->bytes_in_dir = U64_Add( build->bytes_in_dir, DisplaySize, &u64_stat );
+
+ build->record.status = QTC_FILE;
+
+ if ( AFPObject ) {
+ build->record.status |= QTC_AFP;
+ }
+ build->record.date = Date;
+ build->record.time = Time;
+
+ build->record.common.size = U64_Lsw( DisplaySize );
+
+ build->record.attribute = Attribute;
+ build->record.lba = LBA;
+
+ QTC_AddFile( build, szFile, temp_xtra_bytes, temp_xtra_size );
+}
+
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+VOID QTC_AddRecord( QTC_BUILD_PTR build )
+{
+ BYTE_PTR s;
+ INT bytes;
+ INT Error;
+
+ if ( build->rec_offset + sizeof(QTC_RECORD) <= QTC_BUF_SIZE ) {
+ memcpy( &build->rec_buffer[ build->rec_offset ],
+ &build->record,
+ sizeof(QTC_RECORD) );
+ build->rec_offset += sizeof(QTC_RECORD);
+ }
+ else {
+ s = (BYTE_PTR)&build->record;
+
+ memcpy( &build->rec_buffer[ build->rec_offset ],
+ s,
+ QTC_BUF_SIZE - build->rec_offset );
+
+ QTC_SeekFile( build->fh_rec, build->curr_rec_off );
+
+ bytes = QTC_WriteFile( build->fh_rec, build->rec_buffer, QTC_BUF_SIZE, &Error );
+
+ if ( bytes != QTC_BUF_SIZE ) {
+ build->error = Error;
+ build->state = QTC_ERROR_STATE;
+ QTC_ErrorCleanup( build );
+ return;
+ }
+
+ s += (QTC_BUF_SIZE - build->rec_offset);
+
+ memcpy( &build->rec_buffer[ 0 ],
+ s,
+ sizeof(QTC_RECORD) - (QTC_BUF_SIZE - build->rec_offset) );
+
+ build->curr_rec_off += QTC_BUF_SIZE;
+ build->rec_offset = sizeof(QTC_RECORD) -
+ (QTC_BUF_SIZE - build->rec_offset);
+ }
+
+}
+
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+VOID QTC_AddFile(
+QTC_BUILD_PTR build,
+CHAR_PTR filename,
+BYTE_PTR xtra_bytes,
+INT xtra_size )
+{
+ QTC_NAME temp;
+ BYTE_PTR s;
+ INT bytes;
+ INT level;
+ INT name_length;
+ INT Error;
+
+ level = build->current_level + 1;
+
+ name_length = strlen( filename ) * sizeof( CHAR );
+
+ temp.size = (INT16)(sizeof( QTC_NAME ) + name_length + xtra_size);
+ temp.record = build->record_cnt;
+ temp.mom_offset = build->mom_offset[ level - 1 ];
+ temp.xtra_size = xtra_size;
+
+ build->record_cnt++;
+ build->record.name_offset = build->curr_fil_off + build->fil_offset;
+
+ // RECORD
+
+ QTC_AddRecord( build );
+
+ // FIXED PART
+
+ if ( sizeof(QTC_NAME) + build->fil_offset <= QTC_BUF_SIZE ) {
+
+ memcpy( &build->fil_buffer[ build->fil_offset ],
+ &temp, sizeof(QTC_NAME) );
+ build->fil_offset += sizeof(QTC_NAME);
+ }
+ else {
+
+ s = (BYTE_PTR)&temp;
+
+ memcpy( &build->fil_buffer[ build->fil_offset ],
+ s,
+ QTC_BUF_SIZE - build->fil_offset );
+
+ bytes = QTC_WriteFile( build->fh_fil, build->fil_buffer, QTC_BUF_SIZE, &Error );
+
+ if ( bytes != QTC_BUF_SIZE ) {
+ build->error = Error;
+ build->state = QTC_ERROR_STATE;
+ QTC_ErrorCleanup( build );
+ return;
+ }
+
+ s += (QTC_BUF_SIZE - build->fil_offset);
+
+ memcpy( &build->fil_buffer[ 0 ],
+ s,
+ sizeof(QTC_NAME) - (QTC_BUF_SIZE - build->fil_offset) );
+
+ build->curr_fil_off += QTC_BUF_SIZE;
+ build->fil_offset = sizeof(QTC_NAME) - (QTC_BUF_SIZE - build->fil_offset);
+ }
+
+ // NAME PART
+
+ if ( name_length + build->fil_offset <= QTC_BUF_SIZE ) {
+
+ memcpy( &build->fil_buffer[ build->fil_offset ], filename, name_length );
+ build->fil_offset += name_length;
+ }
+ else {
+
+ s = (BYTE_PTR)filename;
+
+ memcpy( &build->fil_buffer[ build->fil_offset ],
+ s,
+ QTC_BUF_SIZE - build->fil_offset );
+
+ bytes = QTC_WriteFile( build->fh_fil, build->fil_buffer, QTC_BUF_SIZE, &Error );
+
+ if ( bytes != QTC_BUF_SIZE ) {
+ build->error = Error;
+ build->state = QTC_ERROR_STATE;
+ QTC_ErrorCleanup( build );
+ return;
+ }
+
+ s += (QTC_BUF_SIZE - build->fil_offset);
+ memcpy( &build->fil_buffer[ 0 ],
+ s,
+ name_length - (QTC_BUF_SIZE - build->fil_offset) );
+
+ build->curr_fil_off += QTC_BUF_SIZE;
+ build->fil_offset = name_length - (QTC_BUF_SIZE - build->fil_offset);
+ }
+
+ // XTRA BYTE PART
+
+ if ( xtra_size + build->fil_offset <= QTC_BUF_SIZE ) {
+
+ memcpy( &build->fil_buffer[ build->fil_offset ],
+ xtra_bytes, xtra_size );
+ build->fil_offset += xtra_size;
+ }
+ else {
+
+ memcpy( &build->fil_buffer[ build->fil_offset ],
+ xtra_bytes,
+ QTC_BUF_SIZE - build->fil_offset );
+
+ bytes = QTC_WriteFile( build->fh_fil, build->fil_buffer, QTC_BUF_SIZE, &Error );
+
+ if ( bytes != QTC_BUF_SIZE ) {
+ build->error = Error;
+ build->state = QTC_ERROR_STATE;
+ QTC_ErrorCleanup( build );
+ return;
+ }
+
+ xtra_bytes += (QTC_BUF_SIZE - build->fil_offset);
+ memcpy( &build->fil_buffer[ 0 ],
+ xtra_bytes,
+ xtra_size - (QTC_BUF_SIZE - build->fil_offset) );
+
+ build->curr_fil_off += QTC_BUF_SIZE;
+ build->fil_offset = xtra_size - (QTC_BUF_SIZE - build->fil_offset);
+ }
+
+ return;
+}
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+VOID QTC_AddDir(
+QTC_BUILD_PTR build,
+CHAR_PTR path,
+INT path_len, // In characters
+BYTE_PTR xtra_bytes,
+INT xtra_size )
+{
+ CHAR *buffer;
+ CHAR *last_path;
+ CHAR *name;
+ CHAR *temp;
+ INT i;
+ INT level;
+ INT process_level;
+
+
+ last_path = malloc( build->build_path_len * sizeof(CHAR) );
+ buffer = malloc( path_len * sizeof(CHAR) );
+
+ if ( last_path == NULL || buffer == NULL ) {
+ free( last_path );
+ free( buffer );
+ return;
+ }
+
+ memcpy( last_path, build->curr_build_path, build->build_path_len * sizeof(CHAR) );
+ memcpy( buffer, path, path_len * sizeof(CHAR));
+
+ if ( (INT)(path_len * sizeof(CHAR)) > build->curr_build_path_size ) {
+
+ // make our path buffer bigger.
+
+ temp = malloc( ( path_len + 256 ) * sizeof(CHAR) );
+
+ if ( temp == NULL ) {
+ free( last_path );
+ free( buffer );
+ return;
+ }
+
+ build->curr_build_path_size = (path_len + 256) * sizeof(CHAR);
+
+ free( build->curr_build_path );
+ build->curr_build_path = temp;
+ }
+
+ memcpy( build->curr_build_path, buffer, path_len * sizeof(CHAR) );
+
+ build->build_path_len = path_len;
+
+ // See what the deepest level of this new guy is.
+
+ level = 0;
+ process_level = 0;
+
+ if ( buffer[0] ) {
+
+ for ( i = 0; i < path_len; i++ ) {
+ if ( buffer[i] == TEXT( '\0' ) ) level++;
+ }
+
+ //
+ // Be careful here not to completely skip a directory because it was
+ // the same as the last directory. The deepest directory should be
+ // processed as a duplicate directory. But do determine where the
+ // new path starts differing from the last one.
+ //
+ // Example 1:
+ // LAST: \DOS\BIN\JUNK
+ // NEW: \DOS\GAMES
+ // Set process_level to 2 and start working with "GAMES", because
+ // the "DOS" part of the path has already been done.
+ //
+ // Example 2:
+ // LAST: \MIKE\JUNK
+ // NEW: \MIKE\JUNK
+ // Set process_level to 2 and start with "JUNK" because it is a
+ // duplicate directory that needs to be processed.
+ //
+ // Example 3:
+ // LAST: \MIKE\JUNK
+ // NEW: \
+ // Set process_level to 0, and add another root to the catalogs.
+ // Note this case is automaticly handled for you.
+
+ process_level = 1;
+ i = 0;
+
+ while ( ( i < path_len ) && ( process_level < level ) ) {
+
+ if ( stricmp( &buffer[i], &last_path[i] ) ) {
+ break;
+ }
+ process_level++;
+ while ( buffer[i] ) i++;
+ i++;
+ }
+ }
+
+ build->current_level = level;
+
+ // do this stuff for all the directories that are different
+ // from the last dblk.
+
+
+
+
+ while ( process_level <= level ) {
+
+ name = buffer;
+
+ for ( i = 1; i < process_level; i++ ) {
+ while ( *name++ ) ;
+ }
+
+ if ( process_level < level ) {
+ build->record.status |= QTC_MANUFACTURED;
+ }
+
+ build->record.name_offset = build->curr_dir_off + build->dir_offset;
+ build->record.common.common.file_start = build->curr_fil_off + build->fil_offset;
+ build->record.common.common.height = process_level;
+
+ QTC_SaveDirRecord( build, name, process_level++,
+ build->record_cnt++, xtra_bytes, xtra_size );
+
+ build->header->num_dirs++;
+ }
+
+ free( last_path );
+ free( buffer );
+
+ return;
+}
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+VOID QTC_SaveDirRecord(
+QTC_BUILD_PTR build,
+CHAR_PTR name,
+INT level,
+UINT32 record,
+BYTE_PTR xtra_bytes,
+INT xtra_size )
+{
+ UINT32 *temp_mom_offset;
+ QTC_NAME temp;
+ BYTE_PTR s;
+ INT bytes;
+ INT name_size;
+ INT Error;
+
+ name_size = strlen( name ) * sizeof( CHAR );
+
+ temp.size = (INT16)(sizeof( QTC_NAME ) + name_size + xtra_size);
+ temp.xtra_size = xtra_size;
+ temp.record = record;
+
+ if ( level ) {
+ temp.mom_offset = build->mom_offset[ level - 1 ];
+ }
+ else {
+ temp.mom_offset = 0;
+ }
+
+ // RECORD
+
+ QTC_AddRecord( build );
+
+ // FIXED PART
+
+ if ( level >= build->mom_depth ) {
+
+ // increase path depth support another 10 levels
+
+ temp_mom_offset = malloc( ( level + 10 ) * sizeof( UINT32 ) );
+ if ( temp_mom_offset == NULL ) {
+ build->error = QTC_NO_MEMORY;
+ build->state = QTC_ERROR_STATE;
+ QTC_ErrorCleanup( build );
+ return;
+ }
+
+ memcpy( temp_mom_offset, build->mom_offset, level * sizeof( UINT32 ) );
+ free( build->mom_offset );
+ build->mom_offset = temp_mom_offset;
+ build->mom_depth = level + 10;
+ }
+
+ build->mom_offset[ level ] = build->curr_dir_off + build->dir_offset;
+
+ // We use this to update counts, after it is added.
+
+ build->last_mom_offset = build->mom_offset[ level ];
+
+ if ( sizeof(QTC_NAME) + build->dir_offset <= QTC_BUF_SIZE ) {
+
+ memcpy( &build->dir_buffer[ build->dir_offset ], &temp, sizeof(QTC_NAME) );
+ build->dir_offset += sizeof(QTC_NAME);
+ }
+ else {
+
+ s = (BYTE_PTR)&temp;
+
+ memcpy( &build->dir_buffer[ build->dir_offset ],
+ s,
+ QTC_BUF_SIZE - build->dir_offset );
+
+ bytes = QTC_WriteFile( build->fh_dir, build->dir_buffer, QTC_BUF_SIZE, &Error );
+
+ if ( bytes != QTC_BUF_SIZE ) {
+ build->error = Error;
+ build->state = QTC_ERROR_STATE;
+ QTC_ErrorCleanup( build );
+ return;
+ }
+
+ s += (QTC_BUF_SIZE - build->dir_offset);
+ memcpy( &build->dir_buffer[ 0 ],
+ s,
+ sizeof(QTC_NAME) - (QTC_BUF_SIZE - build->dir_offset) );
+
+ build->curr_dir_off += QTC_BUF_SIZE;
+ build->dir_offset = sizeof(QTC_NAME) - (QTC_BUF_SIZE - build->dir_offset);
+ }
+
+
+ // NAME PART
+
+ if ( name_size + build->dir_offset <= QTC_BUF_SIZE ) {
+
+ memcpy( &build->dir_buffer[ build->dir_offset ], name, name_size );
+ build->dir_offset += name_size;
+ }
+ else {
+
+ s = (BYTE_PTR)name;
+ memcpy( &build->dir_buffer[ build->dir_offset ],
+ s,
+ QTC_BUF_SIZE - build->dir_offset );
+
+ bytes = QTC_WriteFile( build->fh_dir, build->dir_buffer, QTC_BUF_SIZE, &Error );
+
+ if ( bytes != QTC_BUF_SIZE ) {
+ build->error = Error;
+ build->state = QTC_ERROR_STATE;
+ QTC_ErrorCleanup( build );
+ return;
+ }
+
+ s += (QTC_BUF_SIZE - build->dir_offset);
+ memcpy( &build->dir_buffer[ 0 ],
+ s,
+ name_size - (QTC_BUF_SIZE - build->dir_offset) );
+
+ build->curr_dir_off += QTC_BUF_SIZE;
+ build->dir_offset = name_size - (QTC_BUF_SIZE - build->dir_offset);
+ }
+
+ // XTRA BYTES PART
+
+ if ( xtra_size + build->dir_offset <= QTC_BUF_SIZE ) {
+
+ memcpy( &build->dir_buffer[ build->dir_offset ],
+ xtra_bytes,
+ xtra_size );
+ build->dir_offset += xtra_size;
+ }
+ else {
+
+ memcpy( &build->dir_buffer[ build->dir_offset ],
+ xtra_bytes,
+ QTC_BUF_SIZE - build->dir_offset );
+
+ bytes = QTC_WriteFile( build->fh_dir, build->dir_buffer, QTC_BUF_SIZE, &Error );
+
+ if ( bytes != QTC_BUF_SIZE ) {
+ build->error = Error;
+ build->state = QTC_ERROR_STATE;
+ QTC_ErrorCleanup( build );
+ return;
+ }
+
+ xtra_bytes += (QTC_BUF_SIZE - build->dir_offset);
+ memcpy( &build->dir_buffer[ 0 ],
+ xtra_bytes,
+ xtra_size - (QTC_BUF_SIZE - build->dir_offset) );
+
+ build->curr_dir_off += QTC_BUF_SIZE;
+ build->dir_offset = xtra_size - (QTC_BUF_SIZE - build->dir_offset);
+ }
+
+ return;
+}
diff --git a/private/utils/ntbackup/src/qtc_back.c b/private/utils/ntbackup/src/qtc_back.c
new file mode 100644
index 000000000..3df503855
--- /dev/null
+++ b/private/utils/ntbackup/src/qtc_back.c
@@ -0,0 +1,1884 @@
+
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: QTC_Back.C
+
+ Description:
+
+ The functions used when constructing catalog information about
+ a new bset being backed up or a tape being cataloged.
+
+ $Log: N:\LOGFILES\QTC_BACK.C_V $
+
+ Rev 1.36 07 Jan 1994 14:23:28 mikep
+fixes for unicode
+
+ Rev 1.35 11 Dec 1993 11:49:16 MikeP
+fix warnings from unicode compile
+
+ Rev 1.34 06 Dec 1993 09:46:34 mikep
+Very deep path support & unicode fixes
+
+ Rev 1.33 05 Nov 1993 08:47:16 MIKEP
+fix error msg reporting
+
+ Rev 1.32 03 Nov 1993 09:08:54 MIKEP
+warning fixes
+
+ Rev 1.31 02 Nov 1993 17:55:30 MIKEP
+remove unused parameter
+
+ Rev 1.30 28 Oct 1993 14:47:32 MIKEP
+dll changes
+
+ Rev 1.11 28 Oct 1993 14:47:04 MIKEP
+dll changes
+
+ Rev 1.29 27 Sep 1993 13:08:26 MIKEP
+set ecc flags
+
+ Rev 1.28 12 Aug 1993 18:21:56 DON
+If were out of disk space say so, not just open failure
+
+ Rev 1.27 06 Aug 1993 16:52:22 DON
+Set NO_REDIRECT and/or NON_VOLUME if File System says we should
+
+ Rev 1.26 20 Jun 1993 17:36:28 GREGG
+Removed include of mtf.h.
+
+ Rev 1.25 07 Jun 1993 17:02:48 CARLS
+add code to save the SSET attributes in the catalogs
+
+ Rev 1.24 19 May 1993 16:18:44 ChuckS
+OS_NLM: Get user name for catalog record from gb_QTC.cat_user, not the
+VCB.
+
+ Rev 1.23 13 May 1993 13:24:30 ChuckS
+Changes for revamped QTC usage of virtual memory. Removed (Q_ELEM *) cast
+of v_bset_item when assigned to q_elem.q_ptr -- it's now a VQ_HDL; changed
+argument to QTC_NewBset to vm handle for bset.
+
+ Rev 1.22 10 May 1993 08:28:08 MIKEP
+Add support for DAILY backup type. Fix qtc_abortcataloging to not blow
+up if called in idle state. Nostradamus needs this change.
+
+ Rev 1.21 23 Apr 1993 10:33:40 MIKEP
+Add support for gregg's new on tape catalog version info.
+
+ Rev 1.20 14 Apr 1993 13:01:08 Stefan
+Changed if !defined( P_CLIENT ) by adding "|| defined(OS_WIN) because
+the windows client needs this code.
+
+ Rev 1.19 23 Mar 1993 18:00:26 ChuckS
+Added arg to QTC_OpenFile indicating if need to open for writes
+
+ Rev 1.18 18 Mar 1993 15:17:52 ChuckS
+OS_NLM: Use device name in preference to volume name
+
+ Rev 1.17 27 Jan 1993 11:15:04 CHARLIE
+Use NO_MTF40 as criteria to include tfldefs.h or mtf.h
+
+ Rev 1.16 26 Jan 1993 17:10:44 MIKEP
+vcb changes
+
+ Rev 1.15 04 Jan 1993 16:13:54 DON
+changed if OS_??? to NO_MTF40
+
+ Rev 1.14 01 Jan 1993 15:19:20 MIKEP
+fix crossing tape bug
+
+ Rev 1.13 14 Dec 1992 12:28:52 DAVEV
+Enabled for Unicode compile
+
+ Rev 1.12 08 Dec 1992 09:40:54 DON
+Graceful Red: changed VCB_CONT_BIT to MTF_DB_CONT_BIT
+
+ Rev 1.11 01 Dec 1992 13:24:22 MIKEP
+otc fix for setting status bits
+
+ Rev 1.10 23 Nov 1992 14:20:40 MIKEP
+fix continuation vcb for MTF only
+
+ Rev 1.9 20 Nov 1992 13:28:44 CHARLIE
+JAGUAR: Move to SRM based QTC code
+
+ENDEAVOR: Ifdef'd out all code in the module. Only reason we're linking it
+in is to get the global QTC structure. And this module brings in qtc_add.
+
+ENDEAVOR: Modified QTC_AbortCataloging to pass BOOLEAN keep_items
+
+ENDEAVOR: Keep TAPE, BSET info at Virtual Memory
+
+ENDEAVOR: We needed to clean up the QTC_TEMP files after an abort
+
+ Rev 1.8 15 Nov 1992 16:05:36 MIKEP
+fix warnings
+
+ Rev 1.7 06 Nov 1992 15:30:06 DON
+Change debug.h to be_debug.h and zprintf to BE_Zprintf
+
+ Rev 1.6 28 Oct 1992 11:32:30 MIKEP
+fix PBA of FDD stuff
+
+ Rev 1.5 23 Oct 1992 13:26:20 MIKEP
+change otc call
+
+ Rev 1.4 22 Oct 1992 16:51:42 MIKEP
+otc fixes
+
+ Rev 1.3 22 Oct 1992 09:27:34 MIKEP
+second pass otc changes
+
+ Rev 1.2 15 Oct 1992 10:31:38 MIKEP
+add fdd fields
+
+ Rev 1.1 09 Oct 1992 11:53:40 MIKEP
+unicode pass
+
+ Rev 1.0 03 Sep 1992 16:56:14 STEVEN
+Initial revision.
+
+****************************************************/
+
+#include <dos.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <io.h>
+#include <string.h>
+#include <time.h>
+#include <share.h>
+#include <malloc.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "stdwcs.h"
+#include "qtc.h"
+
+// unicode text macro
+
+#ifndef TEXT
+#define TEXT( x ) x
+#endif
+
+
+/*
+ This is THE global catalog.
+*/
+
+QTC_CATALOG gb_QTC;
+
+
+#if !defined( P_CLIENT ) || defined( OS_WIN )
+
+static INT QTC_AssembleError( QTC_BUILD_PTR, INT );
+static INT QTC_AssembleFiles( QTC_BUILD_PTR );
+
+
+INT QTC_ErrorCleanup( QTC_BUILD_PTR build )
+{
+
+ if ( build ) {
+ if ( build->files_open ) {
+ QTC_CloseFile( build->fh_rec );
+ build->fh_rec = -1 ;
+ QTC_CloseFile( build->fh_dir );
+ build->fh_dir = -1 ;
+ QTC_CloseFile( build->fh_fil );
+ build->fh_fil = -1 ;
+ build->files_open = FALSE;
+ }
+ }
+
+ return( SUCCESS );
+}
+
+
+
+QTC_BUILD_PTR QTC_GetBuildHandle( )
+{
+ QTC_BUILD_PTR build;
+ INT i;
+
+ build = calloc( sizeof( QTC_BUILD ), 1 );
+
+ if ( build != NULL ) {
+
+ build->files_open = FALSE;
+
+ build->rec_file = malloc( (strlen( gb_QTC.data_path ) + 30) * sizeof(CHAR) );
+ build->dir_file = malloc( (strlen( gb_QTC.data_path ) + 30) * sizeof(CHAR) );
+ build->fil_file = malloc( (strlen( gb_QTC.data_path ) + 30) * sizeof(CHAR) );
+
+ build->mom_offset = malloc( QTC_START_DEPTH * sizeof( UINT32 ) );
+
+ build->last_mom_offset = 0L;
+
+ build->curr_build_path = malloc( 256 );
+ build->curr_build_path_size = 256;
+
+ if ( ( build->rec_file != NULL ) &&
+ ( build->dir_file != NULL ) &&
+ ( build->fil_file != NULL ) &&
+ ( build->curr_build_path != NULL ) &&
+ ( build->mom_offset != NULL ) ) {
+
+ build->continuation_tape = FALSE;
+ build->mom_depth = QTC_START_DEPTH;
+
+ for ( i = 0; i < QTC_START_DEPTH; i++ ) {
+ build->mom_offset[ i ] = 0L;
+ }
+ }
+ else {
+
+ free( build->curr_build_path );
+ free( build->rec_file );
+ free( build->dir_file );
+ free( build->fil_file );
+ free( build->mom_offset );
+ free( build );
+ build = NULL;
+ }
+ }
+
+ return( build );
+}
+
+
+INT QTC_FreeBuildHandle( QTC_BUILD_PTR build )
+{
+ if ( build != NULL ) {
+ if ( build->files_open ) {
+ QTC_CloseFile( build->fh_rec );
+ build->fh_rec = -1 ;
+ QTC_CloseFile( build->fh_dir );
+ build->fh_dir = -1 ;
+ QTC_CloseFile( build->fh_fil );
+ build->fh_fil = -1 ;
+ }
+ free( build->curr_build_path );
+ free( build->old_header );
+ free( build->header );
+ free( build->rec_file );
+ free( build->dir_file );
+ free( build->fil_file );
+ free( build->mom_offset );
+ free( build );
+ }
+
+ return( SUCCESS );
+}
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ There are 3.1 tapes with image sets as the first set on tape that do not
+ identify themselves as image sets. This routine corrects the attributes
+ if we hit one of these.
+
+ RETURNS :
+
+**********************/
+
+INT QTC_ImageScrewUp( QTC_BUILD_PTR build )
+{
+ if ( build != NULL ) {
+
+ if ( build->header != NULL ) {
+ build->header->status |= QTC_IMAGE;
+ build->header->status |= QTC_PARTIAL;
+ }
+ }
+
+ return( 0 );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ The 4.0 tape format (MTF) does NOT put the continuation vcb at PBA 0,
+ LBA 0, like all the others do. So it has to be corrected after the VCB
+ has been written to tape. This call will correct the current one being
+ built.
+
+ RETURNS :
+
+**********************/
+
+VOID QTC_PatchVCB( QTC_BUILD_PTR build, UINT32 LBA, UINT32 PBA )
+{
+ if ( build != NULL ) {
+
+ if ( build->header != NULL ) {
+
+ build->header->LBA = LBA;
+ build->header->PBA_VCB = PBA;
+
+ }
+ }
+
+ return;
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+VOID QTC_AbortBackup( QTC_BUILD_PTR build )
+{
+
+ if ( build == NULL ) {
+ return;
+ }
+
+ switch ( build->state ) {
+
+ case QTC_WAITING_STATE:
+ case QTC_ERROR_STATE:
+
+ /*
+ Reset everything important
+ */
+
+ if( build->rec_file != NULL ) {
+ QTC_CloseFile( build->fh_rec ) ;
+ build->fh_rec = -1 ;
+ unlink( build->rec_file ) ;
+ free( build->rec_file ) ;
+ build->rec_file = NULL ;
+ }
+ if( build->dir_file != NULL ) {
+ QTC_CloseFile( build->fh_dir ) ;
+ build->fh_dir = -1 ;
+ unlink( build->dir_file ) ;
+ free( build->dir_file ) ;
+ build->dir_file = NULL ;
+ }
+ if( build->fil_file != NULL ) {
+ QTC_CloseFile( build->fh_fil );
+ build->fh_fil = -1 ;
+ unlink( build->fil_file ) ;
+ free( build->fil_file ) ;
+ build->fil_file = NULL ;
+ }
+
+ free( build->header );
+ build->header = NULL;
+ break;
+
+ case QTC_ACTIVE_STATE:
+
+
+#ifndef OS_WIN32
+
+ /*
+ Reset this bset to partial, because we can't tell what
+ really went to tape and what didn't. MTF 4.0 does put all
+ the files to tape, so there is no reason to convert set to
+ partial cataloging.
+ */
+
+ build->header->status |= QTC_PARTIAL;
+ build->do_full_cataloging = FALSE;
+
+ build->record_cnt = 0;
+ build->dir_offset = 0;
+ build->curr_dir_off = 0;
+ build->fil_offset = 0;
+ build->curr_fil_off = 0;
+ build->rec_offset = 0;
+ build->curr_rec_off = 0;
+#endif
+ QTC_FinishBackup( build );
+ break;
+
+ case QTC_IDLE_STATE:
+ default:
+ break;
+ }
+
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+VOID QTC_AbortCataloging( QTC_BUILD_PTR build, BOOLEAN keep_items )
+{
+ if ( build == NULL ) {
+ return;
+ }
+
+ switch ( build->state ) {
+
+ case QTC_ACTIVE_STATE:
+
+ if ( keep_items ) {
+
+ build->header->status |= QTC_INCOMPLETE;
+
+ } else {
+
+ build->header->status |= QTC_PARTIAL;
+ build->do_full_cataloging = FALSE;
+
+ build->record_cnt = 0;
+ build->dir_offset = 0;
+ build->curr_dir_off = 0;
+ build->fil_offset = 0;
+ build->curr_fil_off = 0;
+ build->rec_offset = 0;
+ build->curr_rec_off = 0;
+ }
+
+ QTC_FinishBackup( build );
+
+ break;
+
+
+ case QTC_WAITING_STATE:
+ case QTC_ERROR_STATE:
+ /*
+ Reset everything important
+ */
+
+ if( build->rec_file != NULL ) {
+ QTC_CloseFile( build->fh_rec );
+ build->fh_rec = -1 ;
+ unlink( build->rec_file ) ;
+ free( build->rec_file ) ;
+ build->rec_file = NULL ;
+ }
+ if( build->dir_file != NULL ) {
+ QTC_CloseFile( build->fh_dir );
+ build->fh_dir = -1 ;
+ unlink( build->dir_file ) ;
+ free( build->dir_file ) ;
+ build->dir_file = NULL ;
+ }
+ if( build->fil_file != NULL ) {
+ QTC_CloseFile( build->fh_fil );
+ build->fh_fil = -1 ;
+ unlink( build->fil_file ) ;
+ free( build->fil_file ) ;
+ build->fil_file = NULL ;
+ }
+
+ build->header = NULL;
+ build->state = QTC_IDLE_STATE;
+ break;
+
+ case QTC_IDLE_STATE:
+ default:
+ break;
+ }
+}
+
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ We buffer all data going to disk. In case we need to work on the data
+ being actively written or we have completed recieving data, then this
+ function will flush the buffer contents to disk.
+
+ RETURNS :
+
+**********************/
+INT QTC_FlushInternalBuffers( QTC_BUILD_PTR build )
+{
+ INT ret;
+ INT Error;
+
+ // Flush directory names buffer
+
+ if ( build == NULL ) {
+ return( FAILURE );
+ }
+
+ QTC_SeekFile( build->fh_dir, build->curr_dir_off );
+
+ ret = QTC_WriteFile( build->fh_dir, build->dir_buffer, build->dir_offset, &Error );
+
+ if ( ret == build->dir_offset ) {
+ build->curr_dir_off += ret;
+ }
+ else {
+ build->error = Error;
+ build->state = QTC_ERROR_STATE;
+ QTC_ErrorCleanup( build );
+ return(FAILURE);
+ }
+
+ // Flush file names buffer
+
+ QTC_SeekFile( build->fh_fil, build->curr_fil_off );
+
+ ret = QTC_WriteFile( build->fh_fil, build->fil_buffer, build->fil_offset, &Error );
+
+ if ( ret == build->fil_offset ) {
+ build->curr_fil_off += ret;
+ }
+ else {
+ build->error = Error;
+ build->state = QTC_ERROR_STATE;
+ QTC_ErrorCleanup( build );
+ return(FAILURE);
+ }
+
+ // Flush records buffer
+
+ QTC_SeekFile( build->fh_rec, build->curr_rec_off );
+
+ ret = QTC_WriteFile( build->fh_rec, build->rec_buffer, build->rec_offset, &Error );
+
+ if ( ret == build->rec_offset ) {
+ build->curr_rec_off += ret;
+ }
+ else {
+ build->error = Error;
+ build->state = QTC_ERROR_STATE;
+ QTC_ErrorCleanup( build );
+ return(FAILURE);
+ }
+
+ // Reset the internal buffer pointers for the next Bset
+
+ build->dir_offset = 0;
+ build->fil_offset = 0;
+ build->rec_offset = 0;
+
+ return( SUCCESS );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT QTC_ChangeBsetFlags( QTC_HEADER_PTR header, INT flags )
+{
+ QTC_HEADER disk_header;
+ INT fd;
+ INT Error;
+
+ header->status |= flags;
+
+ fd = QTC_OpenFile( header->tape_fid, (INT16)header->tape_seq_num, TRUE, FALSE );
+
+ if ( fd < 0 ) {
+ return( FAILURE );
+ }
+
+ QTC_SeekFile( fd, header->offset );
+
+ if ( QTC_ReadFile( fd, (BYTE_PTR)&disk_header, sizeof( QTC_HEADER ), &Error ) != sizeof( QTC_HEADER ) ) {
+ QTC_CloseFile( fd );
+ return( FAILURE );
+ }
+
+ disk_header.status |= flags;
+
+ QTC_SeekFile( fd, header->offset );
+
+ if ( QTC_WriteFile( fd, (BYTE_PTR)&disk_header, sizeof( QTC_HEADER ), &Error ) != sizeof( QTC_HEADER ) ) {
+ QTC_CloseFile( fd );
+ return( FAILURE );
+ }
+
+ QTC_CloseFile( fd );
+ return( SUCCESS );
+}
+
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+INT QTC_BuildNewPath( QTC_BUILD_PTR build, UINT32 mom_offset )
+{
+ INT i;
+ INT result;
+ INT Error;
+ INT BytesNeeded;
+ QTC_NAME_PTR name;
+ CHAR_PTR dirname;
+ CHAR_PTR temp;
+ BYTE_PTR buff1;
+ BYTE_PTR buff2;
+ CHAR_PTR terminator ;
+
+
+ buff1 = calloc( QTC_BUF_SIZE, 1 );
+ buff2 = calloc( QTC_BUF_SIZE, 1 );
+
+ name = (QTC_NAME_PTR)buff2;
+
+ dirname = (CHAR_PTR)( buff2 + sizeof(QTC_NAME) );
+
+ if ( mom_offset == 0 ) {
+ build->curr_build_path[ 0 ] = TEXT( '\0' );
+ build->build_path_len = 1; // in characters, not bytes
+ }
+ else {
+
+ build->build_path_len = 0;
+
+ while ( mom_offset ) {
+
+ QTC_SeekFile( build->fh_dir, mom_offset );
+
+ result = QTC_ReadFile( build->fh_dir, buff1, QTC_BUF_SIZE, &Error );
+
+ if ( QTC_GetNameFromBuff( buff1, name, result ) ) {
+
+ build->error = QTC_READ_FAILED;
+ build->state = QTC_ERROR_STATE;
+ QTC_ErrorCleanup( build );
+ free( buff1 );
+ free( buff2 );
+ return( FAILURE );
+ }
+
+ // terminate dir_name string in buffer with a zero
+
+ terminator = (CHAR_PTR)(&buff2[ name->size - (INT)name->xtra_size ] );
+ *terminator = TEXT( '\0' );
+
+ mom_offset = name->mom_offset;
+
+ // BEFORE
+ // path[] dirname[]
+ // 01234567890 0123456789
+ // xx0xxx0 yyy0
+ //
+ // AFTER
+ // path[]
+ // yyy0xx0xxx0
+
+
+ if ( (INT)((build->build_path_len + strlen( dirname ) + 1 ) * sizeof(CHAR)) >= build->curr_build_path_size ) {
+
+ // We need to enlarge the curr_build_path buffer
+
+ BytesNeeded = build->build_path_len + strlen( dirname );
+ BytesNeeded += 256; // room to grow.
+ BytesNeeded *= sizeof(CHAR);
+
+ temp = malloc( BytesNeeded );
+
+ if ( temp == NULL ) {
+
+ build->error = QTC_READ_FAILED;
+ build->state = QTC_ERROR_STATE;
+ QTC_ErrorCleanup( build );
+ free( buff1 );
+ free( buff2 );
+ return( FAILURE );
+ }
+
+ memcpy( temp, build->curr_build_path, build->build_path_len * sizeof(CHAR) );
+ free( build->curr_build_path );
+ build->curr_build_path = temp;
+
+ build->curr_build_path_size = BytesNeeded;
+ }
+
+ // shift everything to the right, far enough to insert new directory name.
+
+ for ( i = build->build_path_len; i > 0; i-- ) {
+ build->curr_build_path[ i + strlen( dirname ) ] = build->curr_build_path[ i - 1 ];
+ }
+
+ strcpy( build->curr_build_path, dirname );
+ build->build_path_len += strlen( dirname ) + 1;
+ }
+ }
+
+ free( buff1 );
+ free( buff2 );
+ return( SUCCESS );
+}
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+ The last file or directory saved to tape failed its verification test
+ So mark it as corrupt
+
+ RETURNS :
+
+**********************/
+
+INT QTC_BlockBad( QTC_BUILD_PTR build )
+{
+ UINT32 record_num;
+ INT size;
+ INT Error;
+
+ if ( build == NULL ) {
+ return( FAILURE );
+ }
+
+ if ( build->error ) {
+ return( FAILURE );
+ }
+
+ if ( ! build->do_full_cataloging ) {
+ return( SUCCESS );
+ }
+
+ if ( build->state != QTC_ACTIVE_STATE ) {
+ return( SUCCESS );
+ }
+
+ QTC_FlushInternalBuffers( build );
+
+ build->header->num_corrupt_files++;
+
+ // Back up one record and turn the corrupt bit on.
+
+ record_num = build->record_cnt - 1;
+
+ QTC_SeekFile( build->fh_rec, record_num * sizeof(QTC_RECORD) );
+
+ size = QTC_ReadFile( build->fh_rec, (BYTE_PTR)&(build->record), sizeof(QTC_RECORD), &Error );
+
+ if ( size == sizeof(QTC_RECORD ) ) {
+
+ build->record.status |= QTC_CORRUPT;
+
+ QTC_SeekFile( build->fh_rec, record_num * sizeof(QTC_RECORD) );
+
+ size = QTC_WriteFile( build->fh_rec, (BYTE_PTR)&(build->record), sizeof(QTC_RECORD), &Error );
+
+ if ( size != sizeof( QTC_RECORD ) ) {
+ build->error = Error;
+ build->state = QTC_ERROR_STATE;
+ QTC_ErrorCleanup( build );
+ return( FAILURE );
+ }
+ }
+ else {
+ build->error = QTC_READ_FAILED;
+ build->state = QTC_ERROR_STATE;
+ QTC_ErrorCleanup( build );
+ return( FAILURE );
+ }
+
+ // Now mark this guys parent as corrupt so that we can tell in the
+ // tree if there's a file in this directory that is corrupt.
+
+ while ( record_num != 0 ) {
+
+ // Look for a directory record
+
+ record_num--;
+
+ QTC_SeekFile( build->fh_rec, record_num * sizeof(QTC_RECORD) );
+
+ size = QTC_ReadFile( build->fh_rec, (BYTE_PTR)&(build->record), sizeof(QTC_RECORD), &Error );
+
+ if ( size == sizeof(QTC_RECORD ) ) {
+
+ if ( build->record.status & QTC_DIRECTORY ) {
+
+ build->record.status |= QTC_CORRUPT;
+
+ QTC_SeekFile( build->fh_rec, record_num * sizeof(QTC_RECORD) );
+
+ size = QTC_WriteFile( build->fh_rec, (BYTE_PTR)&(build->record), sizeof(QTC_RECORD), &Error );
+
+ if ( size != sizeof( QTC_RECORD ) ) {
+ build->error = Error;
+ build->state = QTC_ERROR_STATE;
+ QTC_ErrorCleanup( build );
+ return( FAILURE );
+ }
+
+ return( SUCCESS );
+ }
+ }
+ else {
+ build->error = QTC_READ_FAILED;
+ build->state = QTC_ERROR_STATE;
+ QTC_ErrorCleanup( build );
+ return( FAILURE );
+ }
+ }
+
+ return( SUCCESS );
+}
+
+
+INT QTC_UpdateOTCInfo( QTC_HEADER_PTR header )
+{
+ QTC_BSET_PTR bset;
+ UINT32 FDD_SeqNum;
+ UINT32 FDD_PBA;
+ UINT32 FDD_Version;
+ INT fd;
+ INT ret;
+ INT Error;
+ INT num_files;
+ INT num_dirs ;
+ INT num_corrupt_files;
+
+ if ( ! ( header->status & QTC_OTCVALID ) ) {
+ return( SUCCESS );
+ }
+
+ bset = QTC_FindBset( header->tape_fid, (INT16)header->tape_seq_num, (INT16)header->bset_num );
+
+ // Copy all the headers into it.
+
+ if ( bset != NULL ) {
+
+ if ( (bset->status & ( QTC_SMEXISTS | QTC_FDDEXISTS | QTC_OTCVALID )) ==
+ (header->status & ( QTC_SMEXISTS | QTC_FDDEXISTS | QTC_OTCVALID )) ) {
+
+ // They are the same.
+
+ return( SUCCESS );
+ }
+
+ // Adjust the one in memory.
+
+ bset->status &= ~( QTC_SMEXISTS | QTC_FDDEXISTS | QTC_OTCVALID );
+ bset->status |= header->status & ( QTC_SMEXISTS | QTC_FDDEXISTS | QTC_OTCVALID );
+
+ FDD_PBA = header->FDD_PBA;
+ FDD_SeqNum = header->FDD_SeqNum;
+ FDD_Version = header->FDD_Version;
+ num_files = header->num_files ;
+ num_dirs = header->num_dirs;
+ num_corrupt_files = header->num_corrupt_files;
+
+ // Load the header for the one bset that is changing.
+
+ header = QTC_LoadHeader( bset );
+
+ if ( header == NULL ) {
+ return( FAILURE );
+ }
+
+ header->status &= ~( QTC_SMEXISTS | QTC_FDDEXISTS | QTC_OTCVALID );
+ header->status |= bset->status & ( QTC_SMEXISTS | QTC_FDDEXISTS | QTC_OTCVALID );
+
+ header->FDD_PBA = FDD_PBA;
+ header->FDD_SeqNum = FDD_SeqNum;
+ header->FDD_Version = FDD_Version;
+
+ header->num_files =num_files ;
+ header->num_dirs=num_dirs ;
+ header->num_corrupt_files=num_corrupt_files ;
+
+ fd = QTC_OpenFile( bset->tape_fid, (INT16)bset->tape_seq_num, TRUE, FALSE );
+
+ if ( fd < 0 ) {
+ return( FAILURE );
+ }
+
+ QTC_SeekFile( fd, bset->offset );
+
+ ret = QTC_WriteFile( fd, (BYTE_PTR)header, sizeof( QTC_HEADER ), &Error );
+
+ QTC_CloseFile( fd );
+
+ free( header );
+
+ if ( ret != sizeof( QTC_HEADER ) ) {
+ return( FAILURE );
+ }
+ }
+
+ return( SUCCESS );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+ Start the catalog off building data for a new Bset
+
+ RETURNS :
+
+**********************/
+
+INT QTC_StartNewBackup(
+QTC_BUILD_PTR build,
+CHAR_PTR szTapeName,
+CHAR_PTR szSetName,
+CHAR_PTR szUserName,
+CHAR_PTR szSetDescription,
+CHAR_PTR szDeviceName,
+CHAR_PTR szVolumeName,
+CHAR_PTR szTapePassword,
+CHAR_PTR szSetPassword,
+INT nTapePasswordLength,
+INT nSetPasswordLength,
+UINT32 TapeID,
+UINT16 TapeNum,
+UINT16 SetNum,
+UINT32 LBA,
+UINT32 PBA,
+UINT32 Attribute,
+INT FDDVersion,
+INT fFDDExists,
+INT fSMExists,
+UINT32 SetCatPBA,
+UINT32 SetCatSeqNumber,
+INT fSetCatInfoValid,
+INT fBlockContinued,
+INT nBackupType,
+INT OS_id,
+INT OS_ver,
+INT fImage,
+INT fNonVolume,
+INT fNoRedirect,
+INT fFutureVersion,
+INT fCompressed,
+INT fEncrypted,
+UINT16 Date,
+UINT16 Time,
+INT EncryptionAlgorithm )
+{
+ QTC_HEADER_PTR header;
+ INT string_size;
+ INT alloc_size;
+ BYTE_PTR byte_ptr;
+
+
+ (void)szUserName;
+
+ // Clear errors and reset states.
+
+ if ( build == NULL ) {
+ return( FAILURE );
+ }
+
+ build->error = 0;
+ build->state = QTC_IDLE_STATE;
+
+ free( build->header ); // free header from last time
+ free( build->old_header );
+
+ build->header = NULL;
+ build->old_header = NULL;
+
+ // Get tape data from vcb, sizes are bytes.
+
+ string_size = 0;
+
+#ifdef OS_NLM
+ if ( szDeviceName ) {
+ string_size += strsize( szDeviceName ) * sizeof( CHAR ) ;
+ } else {
+ string_size += strsize( szVolumeName ) * sizeof( CHAR ) ;
+ }
+#else
+ string_size += strsize( szVolumeName ) * sizeof (CHAR);
+#endif
+ string_size += strsize( szTapeName ) * sizeof (CHAR);
+ string_size += strsize( szSetName ) * sizeof (CHAR);
+ string_size += strsize( szSetDescription ) * sizeof (CHAR);
+
+#ifdef OS_NLM
+ if ( gb_QTC.cat_user ) {
+ string_size += strsize( gb_QTC.cat_user ) * sizeof(CHAR);
+ } else {
+ string_size += sizeof( CHAR ) ;
+ }
+#else
+ string_size += strsize( szUserName ) * sizeof (CHAR);
+#endif
+
+ string_size += nTapePasswordLength + sizeof (CHAR);
+ string_size += nSetPasswordLength + sizeof (CHAR);
+
+
+ alloc_size = sizeof( QTC_HEADER ) + string_size;
+ if ( alloc_size < 512 ) alloc_size = 512;
+
+ header = calloc( alloc_size, 1 );
+
+ if ( header == NULL ) {
+ build->error = QTC_NO_MEMORY;
+ return( QTC_OPERATION_COMPLETE );
+ }
+
+ header->header_size = alloc_size;
+ header->string_offset = sizeof( QTC_HEADER );
+
+ build->end_of_media = FALSE;
+ build->fake_root_added = FALSE;
+
+ build->last_record = 0;
+
+ build->header = header; // for building purposes
+
+ // Set string pointers
+#ifdef OS_NLM
+ if ( szDeviceName ) {
+ header->volume_name_size = (UINT16)( strsize( szDeviceName ) * sizeof (CHAR));
+ } else {
+ header->volume_name_size = (UINT16)( strsize( szVolumeName ) * sizeof (CHAR));
+ }
+#else
+ header->volume_name_size = (UINT16)( strsize( szVolumeName ) * sizeof (CHAR));
+#endif
+
+ header->tape_name_size = (UINT16)( strsize( szTapeName ) * sizeof (CHAR));
+ header->bset_name_size = (UINT16)( strsize( szSetName ) * sizeof (CHAR));
+ header->bset_description_size = (UINT16)( strsize( szSetDescription ) * sizeof (CHAR));
+
+#ifdef OS_NLM
+ if ( gb_QTC.cat_user ) {
+ header->user_name_size = strsize( gb_QTC.cat_user ) * sizeof(CHAR);
+ } else {
+ header->user_name_size = sizeof( CHAR ) ;
+ }
+#else
+ header->user_name_size = (UINT16)( strsize( szUserName ) * sizeof(CHAR));
+#endif
+
+ header->bset_password_size = nSetPasswordLength;
+ header->tape_password_size = nTapePasswordLength;
+
+ byte_ptr = (BYTE_PTR)header;
+ byte_ptr += header->string_offset;
+
+ header->tape_name = (CHAR_PTR)byte_ptr;
+ byte_ptr += header->tape_name_size;
+ header->bset_name = (CHAR_PTR)byte_ptr;
+ byte_ptr += header->bset_name_size;
+ header->volume_name = (CHAR_PTR)byte_ptr;
+ byte_ptr += header->volume_name_size;
+ header->user_name = (CHAR_PTR)byte_ptr;
+ byte_ptr += header->user_name_size;
+ header->bset_description = (CHAR_PTR)byte_ptr;
+ byte_ptr += header->bset_description_size;
+ header->tape_password = (CHAR_PTR)byte_ptr;
+ byte_ptr += header->tape_password_size;
+ header->bset_password = (CHAR_PTR)byte_ptr;
+
+ header->tape_fid = TapeID;
+ header->tape_seq_num = TapeNum;
+ header->bset_num = SetNum;
+
+ header->FDD_SeqNum = 0;
+ header->FDD_PBA = 0;
+
+ header->VCB_attributes = Attribute;
+
+ header->FDD_Version = FDDVersion;
+
+ if ( fSetCatInfoValid ) {
+
+ header->FDD_SeqNum = SetCatSeqNumber;
+ header->FDD_PBA = SetCatPBA;
+ header->status |= QTC_OTCVALID;
+ }
+
+ if ( fFutureVersion ) {
+ header->status |= QTC_FUTURE_VER;
+ }
+ if ( fEncrypted ) {
+ header->status |= QTC_ENCRYPTED;
+ }
+ if ( fCompressed ) {
+ header->status |= QTC_COMPRESSED;
+ }
+
+ if ( fFDDExists ) {
+ header->status |= QTC_FDDEXISTS;
+ }
+
+ if ( fSMExists ) {
+ header->status |= QTC_SMEXISTS;
+ }
+
+ if ( fBlockContinued ) {
+ header->status |= QTC_CONTINUATION;
+ }
+
+ if ( QTC_GetLowerTapeBset( header->tape_fid,
+ (INT16)header->tape_seq_num,
+ (INT16)header->bset_num ) ) {
+
+ header->status |= QTC_CONTINUATION;
+ }
+
+ if ( QTC_GetHigherTapeBset( header->tape_fid,
+ (INT16)header->tape_seq_num,
+ (INT16)header->bset_num ) ) {
+
+ header->status |= QTC_SPLIT;
+ }
+
+ if ( header->status & ( QTC_SPLIT | QTC_CONTINUATION ) ) {
+
+ // Try updating flags on other pieces of this bset.
+
+ QTC_AdjustFlagsOnOtherPieces( header->tape_fid,
+ (INT16)header->tape_seq_num,
+ (INT16)header->bset_num );
+
+ }
+
+ if ( gb_QTC.unicode ) {
+ header->status |= QTC_UNICODE;
+ }
+
+ header->num_dirs = build->num_dirs;
+ header->num_files = build->num_files ;
+ header->num_bytes = 0;
+ header->num_bytes_msw = 0;
+ header->num_corrupt_files = build->num_corrupt_files;
+ header->num_files_in_use = 0;
+
+ if ( QTC_IsThisBsetKnown( build, header ) ) {
+ QTC_UpdateOTCInfo( header );
+ free( header );
+ build->header = NULL;
+ return( QTC_SKIP_TO_NEXT_BSET );
+ }
+
+ if ( header->tape_name_size ) {
+ memcpy( header->tape_name,
+ szTapeName, (INT)header->tape_name_size );
+ header->tape_name[ (header->tape_name_size - 1) / sizeof(CHAR) ] = TEXT( '\0' );
+ }
+ else {
+
+ header->tape_name_size = sizeof( CHAR );
+ header->tape_name[ 0 ] = TEXT( '\0' );
+ }
+
+ if ( header->bset_name_size ) {
+ strncpy( header->bset_name,
+ szSetName, (INT)header->bset_name_size / sizeof (CHAR) );
+ header->bset_name[ (header->bset_name_size - 1) / sizeof(CHAR) ] = TEXT( '\0' );
+ }
+ else {
+ header->bset_name_size = sizeof( CHAR );
+ header->bset_name[ 0 ] = TEXT( '\0' );
+ }
+
+ if ( header->bset_description_size ) {
+ strncpy( header->bset_description,
+ szSetDescription, (INT)header->bset_description_size / sizeof (CHAR) );
+ header->bset_description[ (header->bset_description_size - 1) / sizeof(CHAR) ] = TEXT( '\0' );
+ }
+ else {
+ header->bset_description_size = sizeof( CHAR );
+ header->bset_description[ 0 ] = TEXT( '\0' );
+ }
+
+ if ( header->user_name_size ) {
+#ifdef OS_NLM
+
+ if ( gb_QTC.cat_user ) {
+ strncpy( header->user_name, gb_QTC.cat_user, header->user_name_size ) ;
+ } else {
+ msassert( header->user_name_size == sizeof( CHAR ) ) ;
+ }
+#else
+ strncpy( header->user_name,
+ szUserName, (INT)header->user_name_size / sizeof (CHAR) );
+#endif
+ header->user_name[ (header->user_name_size - 1) / sizeof(CHAR) ] = TEXT( '\0' );
+ }
+ else {
+ header->user_name_size = sizeof( CHAR );
+ header->user_name[ 0 ] = 0;
+ }
+
+ if ( header->volume_name_size ) {
+#ifdef OS_NLM
+ if ( szDeviceName ) {
+ memcpy( header->volume_name,
+ szDeviceName, (INT)header->volume_name_size ) ;
+ } else {
+ strncpy( header->volume_name,
+ szVolumeName, (INT) header->volume_name_size / sizeof( CHAR ) ) ;
+ }
+#else
+ strncpy( header->volume_name,
+ szVolumeName, (INT) header->volume_name_size / sizeof( CHAR ) ) ;
+#endif
+ header->volume_name[ (header->volume_name_size - 1) / sizeof(CHAR) ] = TEXT( '\0' );
+ }
+ else {
+ header->volume_name_size = sizeof( CHAR );
+ header->volume_name[ 0 ] = TEXT( '\0' );
+ }
+
+ if ( header->tape_password_size ) {
+ memcpy( header->tape_password,
+ szTapePassword,
+ (INT)header->tape_password_size );
+ }
+
+ if ( header->bset_password_size ) {
+ memcpy( header->bset_password,
+ szSetPassword,
+ (INT)header->bset_password_size );
+ }
+
+ header->encrypt_algor = EncryptionAlgorithm;
+
+ // set backup set type
+
+ header->backup_type = nBackupType;
+
+ // init other stuff for this bset
+
+ header->LBA = LBA;
+ header->PBA_VCB = PBA;
+
+
+ header->backup_date = Date;
+ header->backup_time = Time;
+
+ header->OS_id = OS_id;
+ header->OS_ver = OS_ver;
+
+ if ( fNoRedirect ) {
+ header->status |= QTC_NO_REDIRECT;
+ }
+
+ if ( fNonVolume ) {
+ header->status |= QTC_NON_VOLUME;
+ }
+
+ header->dir_start = 0;
+ header->fil_start = 0;
+ header->rec_start = 0;
+
+ header->dir_size = 0;
+ header->fil_size = 0;
+ header->rec_size = 0;
+
+ if ( fImage ) {
+ header->status |= QTC_IMAGE;
+ header->status |= QTC_PARTIAL;
+ build->do_full_cataloging = FALSE;
+ }
+
+ if ( build->continuation_tape ) {
+ header->status |= QTC_CONTINUATION;
+ }
+
+ if ( ! build->do_full_cataloging ) {
+ header->status |= QTC_PARTIAL;
+ }
+
+ header->num_dirs = build->num_dirs;
+ header->num_files = build->num_files ;
+ header->num_bytes = 0;
+ header->num_bytes_msw = 0;
+ header->num_corrupt_files = build->num_corrupt_files;
+ header->num_files_in_use = 0;
+
+ if ( QTC_OpenTempFiles( build ) != SUCCESS ) {
+
+ free( header );
+ header = NULL;
+ build->header = NULL;
+
+ return( QTC_OPERATION_COMPLETE );
+ }
+
+ build->build_path_len = 0;
+ build->curr_fil_off = 0;
+ build->curr_dir_off = 0;
+ build->curr_rec_off = 0;
+ build->record_cnt = 0;
+
+ build->state = QTC_ACTIVE_STATE;
+
+ build->current_level = 0;
+
+ if ( ( build->do_full_cataloging == FALSE ) ||
+ ( header->status & QTC_IMAGE ) ) {
+
+ // Save a pointer to this backup set in case we cross tape.
+
+ build->old_header = malloc( (INT)build->header->header_size );
+ memcpy( build->old_header, build->header, (INT)build->header->header_size );
+ QTC_FinishBackup( build );
+
+ return( QTC_SKIP_TO_NEXT_BSET );
+ }
+
+ return( QTC_SKIP_TO_NEXT_ITEM );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT QTC_AdjustFlagsOnOtherPieces(
+UINT32 tape_fid,
+INT16 tape_seq_num,
+INT16 bset_num )
+{
+ QTC_BSET_PTR bset;
+ QTC_HEADER_PTR header;
+
+ bset = QTC_GetHigherTapeBset( tape_fid, tape_seq_num, bset_num );
+
+ while ( bset != NULL ) {
+
+ if ( ! bset->status & QTC_CONTINUATION ) {
+ header = QTC_LoadHeader( bset );
+ if ( header ) {
+ QTC_ChangeBsetFlags( header, QTC_CONTINUATION );
+ free( header );
+ }
+ }
+
+ bset = QTC_GetHigherTapeBset( bset->tape_fid,
+ (INT16)bset->tape_seq_num,
+ (INT16)bset->bset_num );
+ }
+
+
+ bset = QTC_GetLowerTapeBset( tape_fid, tape_seq_num, bset_num );
+
+ while ( bset != NULL ) {
+
+ if ( ! bset->status & QTC_SPLIT ) {
+ header = QTC_LoadHeader( bset );
+ if ( header ) {
+ QTC_ChangeBsetFlags( header, QTC_SPLIT );
+ free( header );
+ }
+ }
+
+ bset = QTC_GetLowerTapeBset( bset->tape_fid,
+ (INT16)bset->tape_seq_num,
+ (INT16)bset->bset_num );
+ }
+
+
+ return( SUCCESS );
+}
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT QTC_IsThisBsetKnown( QTC_BUILD_PTR build, QTC_HEADER_PTR header )
+{
+ QTC_BSET_PTR bset;
+
+ bset = QTC_FindBset( header->tape_fid,
+ (INT16)header->tape_seq_num,
+ (INT16)header->bset_num );
+
+ if ( bset != NULL ) {
+
+ if ( ( bset->status & (QTC_PARTIAL|QTC_INCOMPLETE) ) &&
+ build->do_full_cataloging ) {
+
+ // this space intentionally left blank
+
+ }
+ else {
+
+ return( TRUE );
+ }
+ }
+
+ return( FALSE );
+}
+
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ Called when we reached the end of data for a Bset.
+
+ RETURNS :
+
+**********************/
+
+INT QTC_FinishBackup( QTC_BUILD_PTR build )
+{
+ QTC_BSET_PTR bset;
+
+ if ( build == NULL ) {
+ return( FAILURE );
+ }
+
+ if ( build->error ) {
+ return( FAILURE );
+ }
+
+ // If this was set then we are done with it and it should be reset,
+ // otherwise all sets on tape N are labeled as contiuation sets.
+
+ build->continuation_tape = FALSE;
+
+ // We were doing a partial catalog a tape and not a backup
+ // and this operation has already been done.
+
+ if ( build->header == NULL ) {
+
+ return( SUCCESS );
+ }
+
+ if ( (build->record_cnt == 0) && build->do_full_cataloging ) {
+
+ // Fake the root
+
+ build->record.status = QTC_DIRECTORY;
+ build->record.attribute = 0;
+ build->record.date = 0;
+ build->record.time = 0;
+ build->record.lba = 1;
+ build->record.name_offset = 0;
+ build->record.common.common.file_start = 0;
+ build->record.common.common.height = 0;
+
+ QTC_SaveDirRecord( build, TEXT(""), 0, build->record_cnt++, NULL, 0 );
+ }
+
+ // Update data for last dir processed
+
+ QTC_SetCountsForLastDir( build );
+
+ // Flush the internal data buffers
+
+ QTC_FlushInternalBuffers( build );
+
+ // Save the size in bytes of catalog data stored for this Bset
+
+ build->header->rec_size = build->curr_rec_off;
+ build->header->fil_size = build->curr_fil_off;
+ build->header->dir_size = build->curr_dir_off;
+
+ if ( QTC_AssembleFiles( build ) == SUCCESS ) {
+
+ VM_MemUnLock( qtc_vmem_hand, v_bset_item );
+ v_bset_item = VM_Alloc( qtc_vmem_hand, sizeof( QTC_BSET ) );
+ bset = VM_MemLock( qtc_vmem_hand, v_bset_item, VM_READ_WRITE );
+
+ if ( bset != NULL ) {
+
+ // fill in bset
+ bset->q_elem.q_ptr = v_bset_item;
+ bset->tape_fid = build->header->tape_fid;
+ bset->tape_seq_num = build->header->tape_seq_num;
+ bset->bset_num = build->header->bset_num;
+ bset->offset = build->header->offset;
+ bset->status = build->header->status;
+
+ QTC_NewBset( v_bset_item ) ;
+ free( build->header );
+ build->header = NULL;
+ }
+ else {
+ build->error = QTC_NO_MEMORY;
+ }
+ }
+
+ build->state = QTC_IDLE_STATE;
+ build->end_of_media = FALSE;
+
+ if ( build->error ) {
+ return( FAILURE );
+ }
+
+ return( SUCCESS );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+static INT QTC_AssembleFiles( QTC_BUILD_PTR build )
+{
+ INT fd = -1;
+ INT ret;
+ INT Error;
+ UINT32 offset;
+ UINT32 last_header_offset = 0;
+ BYTE_PTR buffer = NULL;
+ QTC_TAPE_HEADER tape_header;
+ QTC_TAPE_PTR tape;
+ QTC_BSET_PTR bset;
+ QTC_HEADER temp_header;
+
+
+ if ( build->error ) {
+ return( QTC_AssembleError( build, fd ) );
+ }
+
+ buffer = malloc( QTC_BUF_SIZE ); // borrow a buffer
+
+ if ( buffer == NULL ) {
+ return( QTC_AssembleError( build, fd ) );
+ }
+
+ // find previous last bset header
+
+ last_header_offset = 0L;
+
+ tape = QTC_GetFirstTape();
+
+ while ( tape != NULL ) {
+
+ if ( ( tape->tape_fid == build->header->tape_fid ) &&
+ ( tape->tape_seq_num == (INT16)build->header->tape_seq_num ) ) {
+
+ bset = QTC_GetFirstBset( tape );
+
+ while ( bset != NULL ) {
+ if ( bset->offset > last_header_offset ) {
+ last_header_offset = bset->offset;
+ }
+ bset = QTC_GetNextBset( bset );
+ }
+ break;
+ }
+ tape = QTC_GetNextTape( tape );
+ }
+
+ fd = QTC_OpenFile( build->header->tape_fid,
+ (INT16)build->header->tape_seq_num, TRUE, TRUE );
+
+ if ( fd < 0 ) {
+
+ free( buffer );
+ if ( errno == ENOSPC ) {
+ build->error = QTC_DISK_FULL;
+ }
+ else if ( errno == EMFILE ) {
+ build->error = QTC_NO_FILE_HANDLES;
+ }
+ else {
+ build->error = QTC_OPEN_FAILED;
+ }
+
+ build->state = QTC_ERROR_STATE;
+ return( QTC_AssembleError( build, fd ) );
+ }
+
+ if ( last_header_offset != 0 ) {
+
+ QTC_SeekFile( fd, last_header_offset );
+
+ ret = QTC_ReadFile( fd, (BYTE_PTR)&temp_header, sizeof( QTC_HEADER ), &Error );
+
+ if ( ret != sizeof( QTC_HEADER ) ) {
+ free( buffer );
+ build->error = QTC_READ_FAILED;
+ build->state = QTC_ERROR_STATE;
+ return( QTC_AssembleError( build, fd ) );
+ }
+
+ // make it point to end of good data, which may not be EOF
+
+ offset = last_header_offset + temp_header.header_size;
+ offset += temp_header.rec_size;
+ offset += temp_header.fil_size;
+ offset += temp_header.dir_size;
+
+ // point to new last bset offset
+
+ temp_header.next_bset = offset;
+
+ QTC_SeekFile( fd, offset );
+ }
+ else {
+
+ QTC_SeekFile( fd, 0L );
+
+ memcpy( tape_header.signature, QTC_SIGNATURE, sizeof( QTC_SIGNATURE ) );
+
+ tape_header.major_version = QTC_MAJOR_VERSION;
+ tape_header.minor_version = QTC_MINOR_VERSION;
+
+ ret = QTC_WriteFile( fd, (BYTE_PTR)&tape_header, sizeof(QTC_TAPE_HEADER), &Error );
+
+ if ( ret != sizeof( QTC_TAPE_HEADER ) ) {
+
+ free( buffer );
+
+ build->error = Error;
+ build->state = QTC_ERROR_STATE;
+
+ return( QTC_AssembleError( build, fd ) );
+ }
+
+ offset = sizeof( QTC_TAPE_HEADER );
+ }
+
+ build->header->offset = offset;
+
+ build->header->rec_start = build->header->offset + build->header->header_size;
+ build->header->dir_start = build->header->rec_start + build->header->rec_size;
+ build->header->fil_start = build->header->dir_start + build->header->dir_size;
+
+ build->header->next_bset = 0L;
+
+ // write out bset header
+
+ ret = QTC_WriteFile( fd, (BYTE_PTR)build->header, (INT)build->header->header_size, &Error );
+
+ if ( ret != (INT)build->header->header_size ) {
+
+ free( buffer );
+
+ build->error = Error;
+ build->state = QTC_ERROR_STATE;
+
+ return( QTC_AssembleError( build, fd ) );
+ }
+
+ // transfer records file
+
+ ret = QTC_CopyFile( build->fh_rec, fd, build->header->rec_size, buffer );
+
+ if ( ret != SUCCESS ) {
+
+ if ( errno == ENOSPC ) {
+ build->error = QTC_DISK_FULL;
+ }
+ else {
+ build->error = QTC_WRITE_FAILED;
+ }
+ build->state = QTC_ERROR_STATE;
+ free( buffer );
+
+ return( QTC_AssembleError( build, fd ) );
+ }
+ else {
+ QTC_CloseFile( build->fh_rec );
+ build->fh_rec = -1;
+ unlink( build->rec_file );
+ }
+
+ // transfer directories file
+
+ ret = QTC_CopyFile( build->fh_dir, fd, build->header->dir_size, buffer );
+
+ if ( ret != SUCCESS ) {
+ if ( errno == ENOSPC ) {
+ build->error = QTC_DISK_FULL;
+ }
+ else {
+ build->error = QTC_WRITE_FAILED;
+ }
+ build->state = QTC_ERROR_STATE;
+ free( buffer );
+ return( QTC_AssembleError( build, fd ) );
+ }
+ else {
+ QTC_CloseFile( build->fh_dir );
+ build->fh_dir = -1;
+ unlink( build->dir_file );
+ }
+
+ // transfer files file
+
+ ret = QTC_CopyFile( build->fh_fil, fd, build->header->fil_size, buffer );
+
+ if ( ret != SUCCESS ) {
+ if ( errno == ENOSPC ) {
+ build->error = QTC_DISK_FULL;
+ }
+ else {
+ build->error = QTC_WRITE_FAILED;
+ }
+ build->state = QTC_ERROR_STATE;
+ free( buffer );
+ return( QTC_AssembleError( build, fd ) );
+ }
+ else {
+ QTC_CloseFile( build->fh_fil );
+ build->fh_fil = -1;
+ unlink( build->fil_file );
+ }
+
+ if ( last_header_offset ) {
+
+ // set the last bset to point to this one now that all the data
+ // was correctly written to file.
+
+ QTC_SeekFile( fd, last_header_offset );
+ QTC_WriteFile( fd, (BYTE_PTR)&temp_header, sizeof( QTC_HEADER ), &Error );
+ }
+
+ // close the new longer data file
+
+ QTC_CloseFile( fd );
+
+ free( buffer );
+
+ // return that everything is A-OK
+
+ return( SUCCESS );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT QTC_CopyFile(
+INT from,
+INT to,
+UINT32 count,
+BYTE_PTR buffer )
+{
+ INT size;
+ INT Error;
+
+ // Reposition to beginning of temp data file
+
+ QTC_SeekFile( from, 0L );
+
+ do {
+
+ if ( count > (UINT32)QTC_BUF_SIZE ) {
+ size = QTC_BUF_SIZE;
+ }
+ else {
+ size = (INT)count;
+ }
+
+ size = QTC_ReadFile( from, buffer, size, &Error );
+ if ( size == -1 ) {
+ return( FAILURE );
+ }
+
+ size = QTC_WriteFile( to, buffer, size, &Error );
+ if ( size == -1 ) {
+ return( FAILURE );
+ }
+
+ count -= size;
+
+ } while ( size != 0 && count != 0 );
+
+ if ( count ) {
+ return( FAILURE );
+ }
+
+ return( SUCCESS );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static INT QTC_AssembleError( QTC_BUILD_PTR build, INT fd )
+{
+
+ if ( fd >= 0 ) {
+ QTC_CloseFile( fd );
+ }
+
+ if ( build->fh_rec >= 0 ) {
+ QTC_CloseFile( build->fh_rec );
+ unlink( build->rec_file );
+ }
+
+ if ( build->fh_dir >= 0 ) {
+ QTC_CloseFile( build->fh_dir );
+ unlink( build->dir_file );
+ }
+
+ if ( build->fh_fil >= 0 ) {
+ QTC_CloseFile( build->fh_fil );
+ unlink( build->fil_file );
+ }
+
+ build->files_open = FALSE;
+
+ // check to see if this was a new file and if so delete it.
+
+ return( FAILURE );
+}
+
+
+#endif // #if !defined( P_CLIENT )
diff --git a/private/utils/ntbackup/src/qtc_bset.c b/private/utils/ntbackup/src/qtc_bset.c
new file mode 100644
index 000000000..91c3d22fe
--- /dev/null
+++ b/private/utils/ntbackup/src/qtc_bset.c
@@ -0,0 +1,685 @@
+
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: QTC_BSET.C
+
+ Description:
+
+ The functions used when constructing catalog information about
+ a new bset being backed up or a tape being cataloged.
+
+ $Log: N:\LOGFILES\QTC_BSET.C_V $
+
+ Rev 1.9 06 Dec 1993 09:46:10 mikep
+Very deep path support & unicode fixes
+
+ Rev 1.8 28 Oct 1993 14:50:12 MIKEP
+dll changes
+
+ Rev 1.7 16 Sep 1993 15:19:20 JOHNES
+803EPR0879 - When adding a new tape to gb_QTC.tape_list, started inserting
+it in the right place with respect to the other tapes in a family
+(i.e. seq #'s 1, 2, 3 ... );
+
+ Rev 1.6 13 May 1993 13:18:44 ChuckS
+Revamped QTC usage of virtual memory. Changed bset arguments of QTC_RemoveBset
+and QTC_NewBset to VM handles (VQ_HDL's); changed queue function calls to
+corresponding vm- queue calls. Removed logic in QTC_NewBset which was
+deciding whether to InsertElem AFTER the last element of the queue, or
+to EnQueue the elem (there's no difference).
+
+ Rev 1.5 23 Mar 1993 18:00:32 ChuckS
+Added arg to QTC_OpenFile indicating if need to open for writes
+
+ Rev 1.4 04 Dec 1992 17:37:42 ChuckS
+Deleted line that was smashing the v_tape_item VM_HDL we were saving in
+the q_ptr of the QUEUE_ELEM. This was causing VM_SEEK_ERROR's when QTC was
+asking the VM unit to load bogus virtual memory pages.
+
+ Rev 1.3 20 Nov 1992 13:49:54 CHARLIE
+JAGUAR: Move to SRM based QTC code
+
+ENDEAVOR: Integrated virtual memory usage in anticipation of DOS. These
+changes should be transparent to non DOS products.
+
+ Rev 1.2 06 Nov 1992 15:29:56 DON
+Change debug.h to be_debug.h and zprintf to BE_Zprintf
+
+ Rev 1.1 09 Oct 1992 11:53:48 MIKEP
+unicode pass
+
+ Rev 1.0 03 Sep 1992 16:56:16 STEVEN
+Initial revision.
+
+****************************************************/
+
+
+#include <dos.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <io.h>
+#include <string.h>
+#include <time.h>
+#include <share.h>
+#include <malloc.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "msassert.h"
+#include "qtc.h"
+
+// unicode text macro
+
+#ifndef TEXT
+#define TEXT( x ) x
+#endif
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+QTC_BSET_PTR QTC_GetLowerTapeBset(
+UINT32 tape_fid,
+INT16 tape_seq_num,
+INT16 bset_num )
+{
+ QTC_TAPE_PTR tape;
+ QTC_BSET_PTR bset;
+ QTC_BSET_PTR bset_found = NULL;
+
+ tape = QTC_GetFirstTape();
+
+ while ( tape != NULL ) {
+
+ if ( ( tape->tape_fid == tape_fid ) &&
+ ( tape->tape_seq_num < tape_seq_num ) ) {
+
+ bset = QTC_GetFirstBset( tape );
+
+ while ( bset != NULL ) {
+
+ if ( bset->bset_num == bset_num ) {
+
+ if ( ( bset_found == NULL ) ||
+ ( bset_found->tape_seq_num < bset->tape_seq_num ) ) {
+
+ bset_found = bset;
+ }
+ }
+
+ bset = QTC_GetNextBset( bset );
+ }
+ }
+ tape = QTC_GetNextTape( tape );
+ }
+
+ return( bset_found );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+QTC_BSET_PTR QTC_GetHigherTapeBset(
+UINT32 tape_fid,
+INT16 tape_seq_num,
+INT16 bset_num )
+{
+ QTC_TAPE_PTR tape;
+ QTC_BSET_PTR bset;
+ QTC_BSET_PTR bset_found = NULL;
+
+ tape = QTC_GetFirstTape();
+
+ while ( tape != NULL ) {
+
+ if ( ( tape->tape_fid == tape_fid ) &&
+ ( tape->tape_seq_num > tape_seq_num ) ) {
+
+ bset = QTC_GetFirstBset( tape );
+
+ while ( bset != NULL ) {
+
+ if ( bset->bset_num == bset_num ) {
+
+ if ( ( bset_found == NULL ) ||
+ ( bset_found->tape_seq_num > bset->tape_seq_num ) ) {
+
+ bset_found = bset;
+ }
+ }
+
+ bset = QTC_GetNextBset( bset );
+ }
+ }
+ tape = QTC_GetNextTape( tape );
+ }
+
+ return( bset_found );
+}
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+ This option is used when a bset is going to be recataloged. So we remove
+ the old bset header for it by marking it erased.
+
+ RETURNS :
+
+**********************/
+
+VOID QTC_RemoveBset( QTC_TAPE_PTR tape, VQ_HDL hBset )
+{
+ INT fd;
+ INT ret;
+ INT Error;
+ QTC_HEADER temp_header;
+ QTC_BSET_PTR bset ;
+
+ // Need to open file and mark this bset as QTC_ERASED
+ // then close the file.
+
+ vmRemoveQueueElem( &(tape->bset_list), hBset ) ;
+
+ bset = VM_MemLock( qtc_vmem_hand, hBset, VM_READ_WRITE ) ;
+
+ // Rewrite bset header in data file to indicate
+ // it's gone.
+
+ fd = QTC_OpenFile( bset->tape_fid, (INT16)bset->tape_seq_num, TRUE, FALSE );
+
+ if ( fd >= 0 ) {
+
+ QTC_SeekFile( fd, bset->offset );
+
+ ret = QTC_ReadFile( fd, (BYTE_PTR)&temp_header, sizeof( QTC_HEADER ), &Error );
+
+ if ( ret == sizeof( QTC_HEADER ) ) {
+ temp_header.status |= QTC_ERASED;
+ QTC_SeekFile( fd, bset->offset );
+ QTC_WriteFile( fd, (BYTE_PTR)&temp_header, sizeof( QTC_HEADER ), &Error );
+ }
+ QTC_CloseFile( fd );
+ }
+
+ /* free( bset ); VM_stuff */
+ VM_MemUnLock( qtc_vmem_hand, hBset ) ;
+
+}
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+ Add a new tape/bset to our list of known bsets
+
+ RETURNS :
+
+**********************/
+
+INT QTC_NewBset( VQ_HDL hBset )
+{
+ QTC_TAPE_PTR tape;
+ QTC_BSET_PTR temp_bset;
+ QTC_BSET_PTR bset ;
+ VQ_HDL v_bset_old_item ;
+ VQ_HDL hRelatedTape ; /* pointer to a related tape, if any. */
+ INT16 RelatedTapeSeqNo ; /* the sequence number of the related tape */
+
+ if ( !( bset = VM_MemLock( qtc_vmem_hand, hBset, VM_READ_WRITE ) ) ) {
+ return QTC_NO_MEMORY ;
+ }
+
+ // Look through list to see if tapes already here before adding it
+ //
+ // The new tape must be sorted into the queue so while we're looking,
+ // keep track of the nearest related tape already in the list (preferably
+ // the one just before it).
+
+ tape = QTC_GetFirstTape( );
+
+ hRelatedTape = 0 ;
+ RelatedTapeSeqNo = 0 ; /* sequence numbers start at 1 */
+
+ while ( tape != NULL ) {
+
+ msassert( tape->tape_seq_num != 0 ) ;
+
+ if ( tape->tape_fid == bset->tape_fid ) {
+
+ if ( tape->tape_seq_num == (INT16)bset->tape_seq_num ) {
+
+ hRelatedTape = 0 ;
+ RelatedTapeSeqNo = 0 ; /* sequence numbers start at 1 */
+
+ break;
+
+ } else {
+
+ if ( tape->tape_seq_num > (INT16)bset->tape_seq_num ) {
+
+ // this 'tape' comes after the new bset tape
+ // since the list is in sorted order, there
+ // is no need to search any farther.
+
+ hRelatedTape = tape->q_elem.q_ptr ;
+ RelatedTapeSeqNo = tape->tape_seq_num ;
+
+ // leave the lock of the 'tape' virtual memory
+ // hanging since that's what QTC_GetNextTape
+ // would do if it were at the end of the list
+ tape = NULL ;
+
+ break ;
+
+ } else {
+
+ // the new bset tape must come after this 'tape' so
+ // save this VM pointer and seq_no in-case it's
+ // the last one in the list.
+
+ hRelatedTape = tape->q_elem.q_ptr ;
+ RelatedTapeSeqNo = tape->tape_seq_num ;
+
+ }
+
+ }
+
+ } else {
+
+ // if we've found a related tape and the next tape
+ // has a different FID, there's no need to keep searching
+ // since all the tapes with the same FID are together in
+ // the list.
+
+ if ( hRelatedTape != 0 ) {
+
+ // leave the lock of the 'tape' virtual memory
+ // hanging since that's what QTC_GetNextTape
+ // would do if it were at the end of the list
+ tape = NULL ;
+ break;
+
+ }
+
+ }
+
+ tape = QTC_GetNextTape( tape );
+ }
+
+ if ( tape == NULL ) {
+
+ VM_MemUnLock( qtc_vmem_hand, v_tape_item ) ;
+ v_tape_item = VM_Alloc( qtc_vmem_hand, sizeof(QTC_TAPE) ) ;
+ tape = VM_MemLock( qtc_vmem_hand, v_tape_item, VM_READ_WRITE ) ;
+
+ if ( tape == NULL ) {
+ return( QTC_NO_MEMORY ) ;
+ }
+ vmInitQElem( &( tape->q_elem ) ) ;
+ tape->status = 0;
+ tape->tape_fid = bset->tape_fid;
+ tape->tape_seq_num = (INT16)bset->tape_seq_num;
+
+ tape->q_elem.q_ptr = v_tape_item ;
+
+ vmInitQueue( &(tape->bset_list) ) ;
+
+
+ // insert the tape into the queue.
+
+
+ // if we found a related tape out there, use it as an
+ // anchor point else just insert at the end
+ if ( hRelatedTape != (VQ_HDL)NULL ) {
+
+ if ( tape->tape_seq_num < RelatedTapeSeqNo ) {
+
+ // the new element must come before this one
+ vmInsertElem( &(gb_QTC.tape_list),
+ hRelatedTape,
+ v_tape_item, BEFORE );
+
+ } else {
+
+ // the new element must come after this one
+ vmInsertElem( &(gb_QTC.tape_list),
+ hRelatedTape,
+ v_tape_item, AFTER );
+
+ }
+ }
+ else {
+ // Insert at the end. There's no difference between
+ // inserting an element AFTER the last element and enqueueing...
+ vmEnQueueElem( &(gb_QTC.tape_list), v_tape_item, FALSE ) ;
+ }
+
+ } /* endif !tape */
+
+ /*
+ Search to see if another bset matches this one, they may have
+ fully cataloged an existing partial set.
+ */
+
+ if ( vmQueueCount( &(tape->bset_list ) ) ) {
+
+ // Try to start searching at the end, saves time.
+
+ temp_bset = QTC_GetLastBset( tape ) ;
+
+ if ( temp_bset->bset_num > bset->bset_num ) {
+
+ temp_bset = QTC_GetFirstBset( tape ) ;
+ }
+
+ while ( temp_bset != NULL ) {
+
+ if ( temp_bset->bset_num == bset->bset_num ) {
+
+ v_bset_old_item = v_bset_item ;
+ temp_bset = QTC_GetNextBset( temp_bset ) ;
+
+ QTC_RemoveBset( tape, v_bset_old_item ) ;
+ VM_Free( qtc_vmem_hand, v_bset_old_item ) ;
+
+ break;
+ }
+
+ // There's no guarantee temp_bset is still non-NULL, because of
+ // temp_bset = QTC_GetNextBset( temp_bset ) above. So check it...
+
+ if ( temp_bset ) {
+ if ( temp_bset->bset_num > bset->bset_num ) {
+ break;
+ }
+
+ temp_bset = QTC_GetNextBset( temp_bset );
+ }
+ }
+
+ if ( temp_bset != NULL ) {
+
+ // Insert before this one.
+
+ vmInsertElem( &(tape->bset_list),
+ v_bset_item,
+ hBset, BEFORE );
+ }
+ else {
+ // Insert at the end. There's no difference between
+ // inserting an element AFTER the last element and enqueueing...
+ vmEnQueueElem( &(tape->bset_list), hBset, FALSE ) ;
+ }
+ }
+ else {
+
+ // First item added.
+ vmEnQueueElem( &(tape->bset_list), hBset, FALSE ) ;
+ }
+
+
+ // leave a the lock on v_tape_item hanging
+ // the next call to QTC_GetxxxxTape will clear it.
+
+ VM_MemUnLock( qtc_vmem_hand, hBset ) ;
+
+ return( SUCCESS ) ;
+}
+
+/**********************
+
+ NAME : QTC_FindBset
+
+ DESCRIPTION :
+
+ Returns a pointer to the backup set if it exists in the catalog.
+
+ RETURNS :
+
+**********************/
+
+QTC_BSET_PTR QTC_FindBset( UINT32 tape_fid, INT16 tape_num, INT16 bset_num )
+{
+ QTC_TAPE_PTR tape;
+ QTC_BSET_PTR bset;
+
+ tape = QTC_GetFirstTape( ) ;
+
+ while ( tape != NULL ) {
+
+ if ( tape->tape_fid == tape_fid ) {
+
+ if ( ( tape->tape_seq_num == tape_num ) ||
+ ( tape_num == -1 ) ) {
+
+ bset = QTC_GetFirstBset( tape );
+
+ while ( bset != NULL ) {
+
+ if ( ( bset->bset_num == bset_num ) ||
+ ( bset_num == -1 ) ) {
+ return( bset );
+ }
+
+ bset = QTC_GetNextBset( bset );
+ }
+ }
+ }
+ tape = QTC_GetNextTape( tape );
+ }
+
+ return( NULL );
+}
+
+
+/**********************
+
+ NAME : QTC_AnySearchableBsets
+
+ DESCRIPTION :
+
+ A function to tell the menu manager if the search catalogs option is
+ possible. It checks to see if there is at least one known fully
+ cataloged bset.
+
+ RETURNS :
+
+**********************/
+
+INT QTC_AnySearchableBsets( )
+{
+ QTC_TAPE_PTR tape;
+ QTC_BSET_PTR bset;
+
+ tape = QTC_GetFirstTape( );
+
+ while ( tape != NULL ) {
+
+ bset = QTC_GetFirstBset( tape );
+
+ while ( bset != NULL ) {
+
+ if ( bset->status & QTC_PARTIAL ) {
+ bset = QTC_GetNextBset( bset );
+ }
+ else {
+ return( TRUE );
+ }
+ }
+
+ tape = QTC_GetNextTape( tape );
+ }
+
+ return( FALSE );
+}
+
+
+/**********************
+
+ NAME : QTC_IsThereAnotherBset
+
+ DESCRIPTION :
+
+ Determine if there is another bset on this tape that we know about.
+
+ RETURNS :
+
+**********************/
+
+INT QTC_IsThereAnotherBset( QTC_BSET_PTR bset )
+{
+ INT16 seq_num;
+
+ seq_num = (INT16)bset->tape_seq_num;
+
+ bset = QTC_GetNextBset( bset );
+
+ if ( bset == NULL ) {
+ return( FALSE );
+ }
+
+ if ( bset->tape_seq_num != seq_num ) {
+ return( FALSE );
+ }
+
+ return( TRUE );
+}
+
+
+/**********************
+
+ NAME : QTC_GetFirstBset
+
+ DESCRIPTION :
+
+ Get a pointer to the first bset on this tape.
+
+ RETURNS :
+
+**********************/
+
+QTC_BSET_PTR QTC_GetFirstBset(
+QTC_TAPE_PTR tape ) // I - tape to get bsets from
+{
+ VQ_HDL hBset ;
+
+ if ( tape == NULL ) {
+ return( (QTC_BSET_PTR)NULL );
+ }
+
+ hBset = vmQueueHead( &(tape->bset_list) ) ;
+
+ if ( hBset != (VQ_HDL) NULL ) {
+ VM_MemUnLock( qtc_vmem_hand, v_bset_item ) ;
+ return( (QTC_BSET_PTR)VM_MemLock( qtc_vmem_hand, v_bset_item = hBset, VM_READ_WRITE ) ) ;
+ }
+
+ return( NULL ) ;
+}
+
+/**********************
+
+ NAME : QTC_GetLastBset
+
+ DESCRIPTION :
+
+ Get a pointer to the last bset on this tape.
+
+ RETURNS :
+
+**********************/
+
+QTC_BSET_PTR QTC_GetLastBset(
+QTC_TAPE_PTR tape ) // I - tape to get bsets from
+{
+ VQ_HDL hBset ;
+
+ if ( tape == NULL ) {
+ return( (QTC_BSET_PTR)NULL );
+ }
+
+ hBset = vmQueueTail( &(tape->bset_list) );
+
+ if ( hBset != (VQ_HDL) NULL ) {
+ VM_MemUnLock( qtc_vmem_hand, v_bset_item ) ;
+ return( (QTC_BSET_PTR)VM_MemLock( qtc_vmem_hand, v_bset_item = hBset, VM_READ_WRITE ) ) ;
+ }
+
+ return( NULL );
+}
+
+/**********************
+
+ NAME : QTC_GetNextBset
+
+ DESCRIPTION :
+
+ Get a pointer to the next bset on this tape.
+
+ RETURNS :
+
+**********************/
+
+QTC_BSET_PTR QTC_GetNextBset(
+QTC_BSET_PTR bset ) // I - current bset
+{
+ VQ_HDL hBset ;
+
+ hBset = vmQueueNext( &( bset->q_elem ) ) ;
+
+ if ( hBset != (VQ_HDL) NULL ) {
+ VM_MemUnLock( qtc_vmem_hand, v_bset_item );
+ return( (QTC_BSET_PTR)VM_MemLock( qtc_vmem_hand, v_bset_item = hBset, VM_READ_WRITE ) ) ;
+ }
+
+ return( NULL );
+}
+
+/**********************
+
+ NAME : QTC_GetPrevBset
+
+ DESCRIPTION :
+
+ Get a pointer to the previous bset on this tape.
+
+ RETURNS :
+
+**********************/
+
+QTC_BSET_PTR QTC_GetPrevBset(
+QTC_BSET_PTR bset ) // I - current bset
+{
+ VQ_HDL hBset ;
+
+ hBset = vmQueuePrev( &( bset->q_elem ) ) ;
+
+ if ( hBset != (VQ_HDL) NULL ) {
+ VM_MemUnLock( qtc_vmem_hand, v_bset_item );
+ return( (QTC_BSET_PTR)VM_MemLock( qtc_vmem_hand, v_bset_item = hBset, VM_READ_WRITE ) ) ;
+ }
+
+ return( NULL );
+}
diff --git a/private/utils/ntbackup/src/qtc_eom.c b/private/utils/ntbackup/src/qtc_eom.c
new file mode 100644
index 000000000..0f8dfef14
--- /dev/null
+++ b/private/utils/ntbackup/src/qtc_eom.c
@@ -0,0 +1,894 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: QTC_EOM.C
+
+ Description:
+
+ The functions used when constructing catalog information about
+ a new bset being backed up or a tape being cataloged, and you
+ hit EOM.
+
+ $Log: N:/LOGFILES/QTC_EOM.C_V $
+
+ Rev 1.19.1.0 20 Jul 1994 19:35:12 STEVEN
+fix unicode status flag
+
+ Rev 1.19 23 Mar 1994 10:27:30 MIKEP
+fix trap if eom reached after abort called
+
+ Rev 1.18 15 Feb 1994 14:05:24 MIKEP
+fix cataloging crossing set bug
+
+ Rev 1.17 11 Dec 1993 11:49:18 MikeP
+fix warnings from unicode compile
+
+ Rev 1.16 06 Dec 1993 09:46:48 mikep
+Very deep path support & unicode fixes
+
+ Rev 1.15 28 Oct 1993 14:47:36 MIKEP
+dll changes
+
+ Rev 1.14 16 Jun 1993 21:29:22 GLENN
+fix crossing set restores for eom with mtf.
+
+ Rev 1.13 18 Feb 1993 09:02:08 DON
+Cleaned up compiler warnings
+
+ Rev 1.12 09 Feb 1993 17:22:44 STEVEN
+checkin for mikep
+
+ Rev 1.11 30 Jan 1993 12:06:26 DON
+Removed compiler warnings
+
+ Rev 1.10 26 Jan 1993 17:11:00 MIKEP
+vcb changes
+
+ Rev 1.9 25 Jan 1993 09:10:00 MIKEP
+add stdwcs because it seems to need it now
+
+ Rev 1.8 01 Jan 1993 15:19:58 MIKEP
+fix unicode bug
+
+ Rev 1.7 14 Dec 1992 12:29:00 DAVEV
+Enabled for Unicode compile
+
+ Rev 1.6 07 Dec 1992 13:47:06 CHARLIE
+Fixed warning
+
+ Rev 1.5 02 Dec 1992 10:14:14 MIKEP
+fix warnings
+
+ Rev 1.4 20 Nov 1992 13:53:46 CHARLIE
+JAGUAR: Move to SRM based QTC code - no changes from previous version
+
+ Rev 1.3 06 Nov 1992 15:30:12 DON
+Change debug.h to be_debug.h and zprintf to BE_Zprintf
+
+ Rev 1.2 15 Oct 1992 10:27:26 MIKEP
+add fdd fields
+
+ Rev 1.1 09 Oct 1992 11:53:50 MIKEP
+unicode pass
+
+ Rev 1.0 03 Sep 1992 16:56:04 STEVEN
+Initial revision.
+
+****************************************************/
+
+#include <dos.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <io.h>
+#include <string.h>
+#include <time.h>
+#include <share.h>
+#include <malloc.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "stdwcs.h"
+#include "msassert.h"
+#include "qtc.h"
+
+// unicode text macro
+
+#ifndef TEXT
+#define TEXT( x ) x
+#endif
+
+
+/*
+ Structure used for end of media processing during backups.
+*/
+
+typedef struct QTC_ZOMBIE *QTC_ZOMBIE_PTR;
+typedef struct QTC_ZOMBIE {
+
+ Q_ELEM q_elem;
+ CHAR_PTR name;
+ INT name_size; // size of name in BYTES incl NULL terminator
+ BYTE_PTR xtra_bytes;
+ INT xtra_byte_size;
+ UINT32 status; // file or directory
+ UINT32 attribute; // maynard FS_ attribute
+ UINT16 date; // dos date & time
+ UINT16 time;
+ union {
+ UINT32 size; // file size
+ struct {
+ UINT32 file_start:24; // start offset of file names for this dir
+ UINT32 height:8; // hieght in tree of directory
+ } common;
+ } common;
+ UINT32 lba; // logical block address on tape
+
+} QTC_ZOMBIE;
+
+
+
+
+static INT QTC_AdjustForZombies( QTC_BUILD_PTR, CHAR_PTR, CHAR_PTR, INT, Q_HEADER_PTR );
+static INT QTC_ZombieMatch( QTC_BUILD_PTR, QTC_RECORD_PTR, QTC_NAME_PTR, CHAR_PTR, CHAR_PTR, INT );
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+/****************************
+
+ Gather round and listen to my story,
+
+ During a backup operation we have hit the end of tape. Several files that
+ we have already entered into the catalogs were not actually put on this
+ tape. What happens is that we are told about the files when they are
+ placed in buffers and sent to the device driver. So when tape runs out,
+ there are files (zombies) in the buffers that will end up on the next tape,
+ not this one. The file that crosses tape is in the DDB/FDB
+ passed into this routine. We must look backwards through our catalogs to
+ find that file. The item should be marked as a split
+ item on this tape and not put on the next tape. All the
+ later items are to be placed on the next tape as normal entries. We will
+ go ahead and start the bset for the next tape and force these entries into
+ into it. However if the user aborts and doesn't supply a continuation
+ tape, then this new bset will have to be deleted.
+
+*****************************/
+
+VOID QTC_EndOfTapeReached(
+QTC_BUILD_PTR build,
+CHAR_PTR szFile,
+CHAR_PTR szPath,
+INT nPathLength )
+{
+ QTC_HEADER_PTR old_header;
+ Q_HEADER zombie_list;
+ Q_ELEM_PTR q_elem;
+
+ if ( build == NULL ) {
+ return;
+ }
+
+ if ( build->error ) {
+ return;
+ }
+
+ if ( build->header == NULL ) {
+ return;
+ }
+
+ InitQueue( &zombie_list );
+
+ if ( build->do_full_cataloging ) {
+
+ // Flush the internal data buffers
+
+ if ( QTC_FlushInternalBuffers( build ) != SUCCESS ) {
+ return;
+ }
+
+ // Save the size in bytes of catalog data stored for this Bset
+
+ build->header->rec_size = build->curr_rec_off;
+ build->header->fil_size = build->curr_fil_off;
+ build->header->dir_size = build->curr_dir_off;
+
+ // Now mark the last successful file/directory and build a queue
+ // of all the items to be sent to the next tape; and adjust our
+ // catalog size pointers for this bset, subtracting off any files
+ // sent to the next tape.
+
+ QTC_AdjustForZombies( build, szFile, szPath, nPathLength, &zombie_list );
+
+ // Just in case no files were on this tape reset that it's not a
+ // continuation tape;
+
+ build->continuation_tape = FALSE;
+
+ build->fake_root_added = FALSE;
+
+ // Mark this bset as incomplete on this tape
+
+ build->header->status |= QTC_SPLIT;
+
+ // save pointer to old bset
+
+ old_header = malloc( (INT)build->header->header_size );
+ if ( old_header == NULL ) {
+ build->error = QTC_NO_MEMORY;
+ return;
+ }
+
+ memcpy( old_header, build->header, (INT)build->header->header_size );
+
+ // close down current catalogs
+
+ if ( ! build->error ) {
+
+ build->end_of_media = TRUE; // save structures
+
+ QTC_FinishBackup( build );
+
+ // Restart cataloging for next tape
+
+ if ( ! QTC_RestartBackup( build, old_header, &zombie_list ) ) {
+
+ build->state = QTC_WAITING_STATE;
+ }
+ }
+
+ free( old_header );
+
+ // Free our zombie queue.
+
+ q_elem = DeQueueElem( &zombie_list );
+
+ while ( q_elem != NULL ) {
+ free( q_elem->q_ptr );
+ q_elem = DeQueueElem( &zombie_list );
+ }
+ }
+ else {
+
+ // Holy Tangled Tape Batman, we were doing partial cataloging/backup
+ // and we crossed the end of media. This program is about to blow its
+ // grits all over the user's lap.
+
+ // Change the flags on the active and disk copy of the bset.
+
+ QTC_ChangeBsetFlags( build->old_header, QTC_SPLIT );
+
+ // Restart cataloging for next tape
+
+ if ( ! QTC_RestartBackup( build, build->old_header, &zombie_list ) ) {
+
+ build->state = QTC_WAITING_STATE;
+
+ // This new one for use next time.
+
+ memcpy( build->old_header, build->header, (INT)build->header->header_size );
+
+ QTC_FinishBackup( build );
+ }
+
+ }
+
+}
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static INT QTC_AdjustForZombies(
+QTC_BUILD_PTR build,
+CHAR_PTR szFile,
+CHAR_PTR szPath,
+INT nPathLength,
+Q_HEADER_PTR zombie_list )
+{
+ QTC_ZOMBIE_PTR zombie;
+ Q_ELEM_PTR curr_elem = NULL;
+ BYTE_PTR byte_ptr;
+ BYTE_PTR buffer;
+ BYTE_PTR xtra_bytes;
+ CHAR_PTR item_path;
+ CHAR_PTR item_buffer;
+ CHAR_PTR item;
+ INT item_size = 0;
+ INT xtra_byte_size = 0;
+ INT ret;
+ INT Error;
+ QTC_NAME_PTR name_ptr;
+ CHAR_PTR filename;
+ QTC_RECORD record;
+ QTC_RECORD temp_record;
+ UINT32 temp_record_num;
+ BOOLEAN done;
+ INT nSize;
+
+
+ if ( szFile == NULL && szPath == NULL ) {
+ return( SUCCESS );
+ }
+
+ buffer = (BYTE_PTR)calloc( QTC_BUF_SIZE, 1 );
+
+ if ( szFile && ((INT)strsize( szFile ) > nPathLength) ) {
+ nSize = strsize( szFile );
+ }
+ else {
+ nSize = nPathLength;
+ }
+
+ nSize *= 2; // << safety feature, i'm insecure about my math abilities
+
+ item_path = (CHAR_PTR)calloc( nSize, 1 );
+ item_buffer = (CHAR_PTR)calloc( nSize, 1 );
+
+ xtra_bytes = (BYTE_PTR)calloc( QTC_MAX_XTRA_BYTES, 1 );
+
+ name_ptr = (QTC_NAME_PTR)buffer;
+ filename = (CHAR_PTR)&buffer[ sizeof( QTC_NAME ) ];
+
+ // See what we are looking for dir or file and get name
+
+ if ( szFile != NULL ) {
+ strcpy( (CHAR_PTR)buffer, szFile );
+ strcpy( item_buffer, (CHAR_PTR)szFile );
+ item = item_buffer;
+ }
+ else {
+ item = NULL;
+ }
+
+ memcpy( buffer, szPath, nPathLength );
+ memcpy( item_path, szPath, nPathLength );
+ item_size = nPathLength;
+
+ done = FALSE;
+
+ while ( ! done ) {
+
+ if ( QTC_GetLastRecordEntered( build, &record,
+ buffer,
+ xtra_bytes, &xtra_byte_size ) != SUCCESS ) {
+ break;
+ }
+
+ if ( QTC_ZombieMatch( build, &record, name_ptr, item,
+ item_path, item_size ) == SUCCESS ) {
+
+ // Don't remove the crossing entry from the catalogs for
+ // tape 1 and don't add it to the zombie list for tape 2.
+
+ done = TRUE;
+
+ }
+ else {
+
+ if ( record.status & QTC_DIRECTORY ) {
+
+ /*******
+ Build a new current build path
+
+ Look through records for last directory and then pass
+ its name_offset as the last dir in the new path.
+ *******/
+
+ temp_record_num = build->record_cnt - 2;
+
+ while ( temp_record_num > 0 ) {
+
+ QTC_SeekFile( build->fh_rec, temp_record_num * sizeof( QTC_RECORD ) );
+
+ ret = QTC_ReadFile( build->fh_rec, (BYTE_PTR)&temp_record, sizeof( QTC_RECORD ), &Error );
+
+ if ( ret != sizeof( QTC_RECORD ) ) {
+ build->error = QTC_READ_FAILED;
+ build->state = QTC_ERROR_STATE;
+ free( buffer );
+ free( item_path );
+ free( item_buffer );
+ free( xtra_bytes );
+ return( FAILURE );
+ }
+
+ if ( temp_record.status & QTC_DIRECTORY ) {
+ break;
+ }
+
+ temp_record_num--;
+ }
+
+ // Turn the current build path into a zombie.
+
+ zombie = calloc( sizeof( QTC_ZOMBIE ) + ( build->build_path_len * sizeof(CHAR) ), 1 );
+
+ if ( zombie == NULL ) {
+ build->state = QTC_ERROR_STATE;
+ build->error = QTC_NO_MEMORY;
+ free( buffer );
+ free( item_path );
+ free( item_buffer );
+ free( xtra_bytes );
+ return( FAILURE );
+ }
+
+ byte_ptr = (BYTE_PTR)zombie;
+ byte_ptr += sizeof( QTC_ZOMBIE );
+ zombie->name = (CHAR_PTR)byte_ptr;
+ zombie->name_size = build->build_path_len * sizeof (CHAR);
+ memcpy( zombie->name,
+ build->curr_build_path,
+ build->build_path_len * sizeof (CHAR) );
+
+
+ // Now change the current build path to remove the last directory.
+
+ if ( temp_record_num ) {
+
+ if ( QTC_BuildNewPath( build, temp_record.name_offset ) ) {
+ free( buffer );
+ free( item_path );
+ free( item_buffer );
+ free( xtra_bytes );
+ return( FAILURE );
+ }
+ }
+ else {
+ build->curr_build_path[ 0 ] = TEXT( '\0' );
+ build->build_path_len = 1; // character count, not byte count
+ }
+ }
+ else {
+
+ zombie = calloc( sizeof( QTC_ZOMBIE ) + ( strsize( filename ) * sizeof(CHAR) ) + xtra_byte_size, 1 );
+
+ if ( zombie == NULL ) {
+ build->state = QTC_ERROR_STATE;
+ build->error = QTC_NO_MEMORY;
+ free( buffer );
+ free( item_path );
+ free( item_buffer );
+ free( xtra_bytes );
+ return( FAILURE );
+ }
+
+ byte_ptr = (BYTE_PTR)zombie;
+ byte_ptr += sizeof( QTC_ZOMBIE );
+ zombie->name = (CHAR_PTR)byte_ptr;
+ zombie->name_size = strsize ( filename );
+ strcpy( zombie->name, filename );
+ zombie->xtra_bytes = (INT8_PTR)zombie->name + zombie->name_size;
+ zombie->xtra_byte_size = xtra_byte_size;
+ if ( zombie->xtra_byte_size ) {
+ memcpy( zombie->xtra_bytes, xtra_bytes, xtra_byte_size );
+ }
+ }
+
+ zombie->q_elem.q_ptr = zombie;
+ zombie->status = record.status;
+ zombie->attribute = record.attribute;
+ zombie->date = (INT16)record.date;
+ zombie->time = (INT16)record.time;
+ zombie->lba = record.lba;
+ zombie->common.size = record.common.size;
+
+ if ( QueueCount( zombie_list ) ) {
+ InsertElem( zombie_list, curr_elem, &(zombie->q_elem), BEFORE );
+ }
+ else {
+ EnQueueElem( zombie_list, &(zombie->q_elem), FALSE );
+ }
+
+ curr_elem = &(zombie->q_elem);
+
+ // and shorten offsets and sizes
+
+ if ( record.status & QTC_FILE ) {
+ build->curr_fil_off -= name_ptr->size;
+ }
+ else {
+ build->curr_dir_off -= name_ptr->size;
+ }
+
+ build->curr_rec_off -= sizeof( QTC_RECORD );
+ build->record_cnt--;
+
+ }
+ }
+
+ free( buffer );
+ free( item_path );
+ free( item_buffer );
+ free( xtra_bytes );
+ return( SUCCESS );
+}
+
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static INT QTC_ZombieMatch(
+QTC_BUILD_PTR build,
+QTC_RECORD_PTR record,
+QTC_NAME_PTR name,
+CHAR_PTR item,
+CHAR_PTR item_path,
+INT item_size )
+{
+ BYTE_PTR byte_ptr;
+ CHAR_PTR filename;
+
+ byte_ptr = (BYTE_PTR)name;
+ byte_ptr += sizeof( QTC_NAME );
+ filename = (CHAR_PTR)byte_ptr;
+
+ // Is the path the right one ?
+
+ if ( ( (UINT)item_size == (UINT)( build->build_path_len * sizeof(CHAR) ) &&
+ ( ! memicmp( build->curr_build_path, item_path, item_size ) ) ) ) {
+
+ // Was there a file, and is this it ?
+
+ if ( ( record->status & QTC_FILE ) &&
+ ( item != NULL ) ) {
+
+ if ( ! stricmp( filename, item ) ) {
+ return( SUCCESS );
+ }
+ }
+
+ // Was it a directory that crossed and is this it ?
+
+ if ( ( record->status & QTC_DIRECTORY ) &&
+ ( item == NULL ) ) {
+
+ return( SUCCESS );
+ }
+ }
+
+ return( FAILURE );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT QTC_GetLastRecordEntered(
+QTC_BUILD_PTR build,
+QTC_RECORD_PTR record,
+BYTE_PTR buffer,
+BYTE_PTR xtra_bytes,
+INT * xtra_byte_size )
+{
+ QTC_NAME_PTR name;
+ CHAR_PTR char_ptr;
+ INT ret;
+ INT Error;
+
+ name = (QTC_NAME_PTR)buffer;
+
+ // Always leave the root, record #1 present
+
+ if ( build->record_cnt < 2 ) {
+ return( FAILURE );
+ }
+
+ QTC_SeekFile( build->fh_rec, (build->record_cnt - 1) * sizeof( QTC_RECORD ) );
+
+ ret = QTC_ReadFile( build->fh_rec, (BYTE_PTR)record, sizeof( QTC_RECORD ), &Error );
+
+ if ( ret != sizeof( QTC_RECORD ) ) {
+ build->error = QTC_READ_FAILED;
+ build->state = QTC_ERROR_STATE;
+ return( FAILURE );
+ }
+
+ if ( record->status & QTC_FILE ) {
+ QTC_SeekFile( build->fh_fil, record->name_offset );
+ ret = QTC_ReadFile( build->fh_fil, buffer, QTC_BUF_SIZE, &Error );
+ }
+ else {
+ QTC_SeekFile( build->fh_dir, record->name_offset );
+ ret = QTC_ReadFile( build->fh_dir, buffer, QTC_BUF_SIZE, &Error );
+ }
+
+ if ( ret < sizeof( QTC_NAME ) ) {
+ build->error = QTC_READ_FAILED;
+ build->state = QTC_ERROR_STATE;
+ return( FAILURE );
+ }
+
+ if ( ret < (INT)name->size ) {
+ build->error = QTC_READ_FAILED;
+ build->state = QTC_ERROR_STATE;
+ return( FAILURE );
+ }
+
+ *xtra_byte_size = (INT)name->xtra_size;
+
+ if ( name->xtra_size ) {
+
+ memcpy( xtra_bytes,
+ &buffer[ name->size - (INT)name->xtra_size ],
+ (INT)name->xtra_size );
+ }
+
+ // null terminate string
+ char_ptr = (CHAR_PTR)&buffer[ name->size - name->xtra_size ];
+ *char_ptr = TEXT( '\0' );
+
+ return( SUCCESS );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT QTC_RestartBackup(
+QTC_BUILD_PTR build,
+QTC_HEADER_PTR old_header,
+Q_HEADER_PTR zombie_list )
+{
+ QTC_ZOMBIE_PTR zombie;
+ QTC_HEADER_PTR header;
+ QTC_HEADER_PTR temp_header;
+ QTC_BSET_PTR bset;
+ Q_ELEM_PTR q_elem;
+ INT i;
+
+ // Get tape data from vcb
+
+ header = calloc( (INT)old_header->header_size, 1 );
+
+ if ( header == NULL ) {
+ build->state = QTC_ERROR_STATE;
+ build->error = QTC_NO_MEMORY;
+ return( FAILURE );
+ }
+
+ memcpy( header, old_header, (INT)old_header->header_size );
+
+ // Adjust all the string pointers to point to this
+ // headers strings, rather than the old_headers memory
+ // locations.
+
+ QTC_SetUpStrings( header );
+
+ header->tape_seq_num = (UINT16)(old_header->tape_seq_num + 1);
+
+ msassert( header->tape_seq_num != 0 );
+
+ // init other stuff for this header
+
+ header->LBA = 0; //
+ header->PBA_VCB = 1; //
+
+ header->FDD_SeqNum = 0; // Tape FDD starts on
+ header->FDD_PBA = 0; // PBA of FDD info for set
+
+
+ // With maynstream 3.1 formats when we crossed EOM we faked the
+ // crossing VCB because we knew the numbers for it. We don't know
+ // them with MTF 1.0
+
+ // With MTF 1.0, a problem has developed here. The cont vcb is loaded
+ // correctly from the set list. It has the correct PBA for the VCB,
+ // usually a number greater than or equal to 4. But almost never 1.
+
+ // When we fully catalog the crossing set we generate an End-of-media
+ // call the attempts to duplicate the vcb from tape 1. By doing this
+ // we lose the good numbers we had from the set list catalog. This
+ // attempts to preserve any good numbers we already had. mikep
+
+ bset = QTC_FindBset( header->tape_fid,
+ (INT16)header->tape_seq_num,
+ (INT16)header->bset_num );
+
+
+ if ( bset != NULL ) {
+
+
+ temp_header = QTC_LoadHeader( bset ) ;
+
+
+ if ( temp_header != NULL ) {
+
+ header->LBA = temp_header->LBA;
+ header->PBA_VCB = temp_header->PBA_VCB;
+
+ header->FDD_SeqNum = temp_header->FDD_SeqNum;
+ header->FDD_PBA = temp_header->FDD_PBA;
+
+ free( temp_header );
+ }
+
+ }
+
+
+ // clear data offsets and sizes
+
+ header->dir_start = 0;
+ header->fil_start = 0;
+ header->rec_start = 0;
+
+ header->dir_size = 0;
+ header->fil_size = 0;
+ header->rec_size = 0;
+
+ // Clear all other status bits
+
+ header->status = QTC_CONTINUATION;
+
+ if ( gb_QTC.unicode ) {
+ header->status |= QTC_UNICODE;
+ }
+
+ // stats
+
+ header->num_dirs = 0;
+ header->num_files = 0;
+ header->num_bytes = 0;
+ header->num_bytes_msw = 0;
+ header->num_corrupt_files = 0;
+ header->num_files_in_use = 0;
+
+ if ( QTC_OpenTempFiles( build ) != SUCCESS ) {
+
+ free( header );
+ return( FAILURE );
+ }
+
+ build->header = header;
+
+ build->curr_fil_off = 0;
+ build->curr_dir_off = 0;
+ build->curr_rec_off = 0;
+
+ build->record_cnt = 0;
+
+ // Add old build path to catalog here
+
+ build->current_level = 0;
+
+ if ( build->do_full_cataloging ) {
+
+ // Send out root directory
+
+ build->record.status = QTC_DIRECTORY | QTC_CONTINUATION;
+ build->record.attribute = 0;
+ build->record.date = 0;
+ build->record.time = 0;
+ build->record.lba = 1;
+ build->record.name_offset = build->curr_dir_off +
+ build->dir_offset;
+
+ build->record.common.common.file_start = 0;
+ build->record.common.common.height = 0;
+
+ QTC_SaveDirRecord( build, TEXT(""),
+ 0,
+ build->record_cnt++, NULL, 0 );
+
+ i = 0;
+
+ while ( ( i < build->build_path_len ) &&
+ ( build->build_path_len != 1 ) ) {
+
+ build->record.status = QTC_DIRECTORY | QTC_CONTINUATION;
+ build->record.attribute = 0;
+ build->record.date = 0;
+ build->record.time = 0;
+ build->record.lba = 0;
+ build->record.name_offset = build->curr_dir_off +
+ build->dir_offset;
+
+ build->record.common.common.file_start = 0;
+ build->record.common.common.height = build->current_level + 1;
+
+ QTC_SaveDirRecord( build,
+ &build->curr_build_path[ i ],
+ ++build->current_level,
+ build->record_cnt++,
+ NULL, 0 );
+
+ while ( build->curr_build_path[i] ) i++;
+ i++;
+ }
+
+ /*************************************
+
+ Send out zombie list here.
+
+ ***********************************/
+
+ i = 0;
+
+ q_elem = QueueHead( zombie_list );
+
+ while ( q_elem != NULL ) {
+
+ RemoveQueueElem( zombie_list, q_elem );
+
+ zombie = (QTC_ZOMBIE_PTR)q_elem->q_ptr;
+
+ if ( ! i++ ) {
+ zombie->status |= QTC_CONTINUATION;
+ }
+
+ if ( zombie->status & QTC_FILE ) {
+ build->record.status = zombie->status;
+ build->record.date = zombie->date;
+ build->record.time = zombie->time;
+ build->record.common.size = zombie->common.size;
+ build->record.attribute = zombie->attribute;
+ build->record.lba = zombie->lba;
+ QTC_AddFile( build, zombie->name,
+ zombie->xtra_bytes, zombie->xtra_byte_size );
+ }
+ else {
+ build->record.status = zombie->status;
+ build->record.date = zombie->date;
+ build->record.time = zombie->time;
+ build->record.attribute = zombie->attribute;
+ build->record.lba = zombie->lba;
+ build->record.common.common.file_start = zombie->common.common.file_start;
+ build->record.common.common.height = zombie->common.common.height;
+ QTC_AddDir( build,
+ zombie->name, zombie->name_size / sizeof(CHAR),
+ zombie->xtra_bytes, zombie->xtra_byte_size );
+ }
+
+ free( zombie );
+ q_elem = QueueHead( zombie_list );
+ }
+ }
+ else {
+
+ // We are partially cataoging.
+
+ build->header->status |= QTC_PARTIAL;
+ }
+
+ if ( ! build->error ) {
+ build->state = QTC_ACTIVE_STATE;
+ }
+
+ return( SUCCESS );
+}
diff --git a/private/utils/ntbackup/src/qtc_init.c b/private/utils/ntbackup/src/qtc_init.c
new file mode 100644
index 000000000..f6ba5d536
--- /dev/null
+++ b/private/utils/ntbackup/src/qtc_init.c
@@ -0,0 +1,660 @@
+
+
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: QTC_INIT.C
+
+ Description:
+
+ A lot of utility functions for the catalogs.
+
+ $Log: N:\LOGFILES\QTC_INIT.C_V $
+
+ Rev 1.23 07 Dec 1993 16:35:54 MikeP
+Remove redundant call to free
+
+ Rev 1.22 06 Dec 1993 09:46:42 mikep
+Very deep path support & unicode fixes
+
+ Rev 1.21 03 Nov 1993 09:11:06 MIKEP
+warning fixes
+
+ Rev 1.20 28 Oct 1993 14:50:18 MIKEP
+dll changes
+
+ Rev 1.19 20 Sep 1993 10:27:04 unknown
+Started saving (and then using a virtual pointer to our temp_bset instead
+of allocating additional memory for it.
+
+ Rev 1.18 16 Sep 1993 17:48:38 Stefan
+Free temp_bset after we're done with it
+
+ Rev 1.17 14 Sep 1993 09:48:28 Stefan
+Added a temporary bset variable in QTC_LoadBsetInfo to keep some P_CLIENT
+code from using an uninitialized variable (and potentially freed variable)
+if there were no valid backup sets in a tape catalog.
+
+ Rev 1.16 26 Jun 1993 15:14:22 ChuckS
+803EPR0307 Got rid of stupid msassert in QTC_Init. We're checking for NULL
+ data_path on next line and returning an error anyway, so why bother
+ asserting? Also changed error to QTC_OPEN_FAILED.
+
+ Rev 1.15 15 Jun 1993 11:21:50 ChuckS
+P_CLIENT || OS_NLM only: Added test of QTC_TAPE_DELETED bit of status
+for first set of tape. If set, tape is not loaded.
+
+P_CLIENT: added test for !error before going on with file stat. If
+error is QTC_TAPE_TAGGED_DELETED, we don't care what filedate the file
+has. We don't have a QTC_TAPE pointer to store the stat info in anyway.
+
+
+ Rev 1.14 19 May 1993 16:18:22 ChuckS
+If P_CLIENT or OS_NLM, free gb_QTC.cat_user in QTC_Deinit, if allocated.
+If P_CLIENT, need to load bset strings during QTC_LoadBsetInfo. If not
+supervisor and cat_user is set, need the user_name to restrict the view
+of the catalogs.
+
+ Rev 1.13 13 May 1993 13:18:02 ChuckS
+Changes for revamped QTC usage of virtual memory. Changed queue calls to
+corresponding vm- queue calls.
+
+ Rev 1.12 12 Apr 1993 13:17:02 DON
+Don't allow a NULL data path
+
+ Rev 1.11 05 Apr 1993 18:22:44 DON
+Needed to free the data path allocated at init
+
+ Rev 1.10 30 Jan 1993 12:06:28 DON
+Removed compiler warnings
+
+ Rev 1.9 25 Jan 1993 09:10:04 MIKEP
+add stdwcs because it seems to need it now
+
+ Rev 1.8 04 Jan 1993 09:36:22 MIKEP
+unicode changes
+
+ Rev 1.7 14 Dec 1992 12:29:06 DAVEV
+Enabled for Unicode compile
+
+ Rev 1.6 11 Dec 1992 16:44:06 CHARLIE
+Removed literal string
+
+ Rev 1.5 25 Nov 1992 16:14:20 ChuckS
+P_CLIENT only: Code to init new v_olume and wr_time fields
+
+ Rev 1.4 20 Nov 1992 13:27:54 CHARLIE
+JAGUAR: Move to SRM based QTC code
+
+ENDEAVOR: Modified QTC_Init prototype to require VM_HDL vm_hdl passed by the
+front end calling routine. Passing NULL indicates virtual memory will not
+be used (by design or consequence)
+
+ENDEAVOR: Integrated virtual memory usage in anticipation of DOS. These
+changes should be transparent to non DOS products.
+
+ Rev 1.3 06 Nov 1992 15:30:10 DON
+Change debug.h to be_debug.h and zprintf to BE_Zprintf
+
+ Rev 1.2 15 Oct 1992 10:21:42 MIKEP
+fix delete catalogs option
+
+ Rev 1.1 09 Oct 1992 11:53:54 MIKEP
+unicode pass
+
+ Rev 1.0 03 Sep 1992 16:56:04 STEVEN
+Initial revision.
+
+****************************************************/
+
+#include <dos.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <io.h>
+#include <string.h>
+#include <time.h>
+#include <share.h>
+#include <malloc.h>
+#include <sys\types.h>
+#include <sys\stat.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "stdwcs.h"
+#include "msassert.h"
+#include "qtc.h"
+
+// global data
+
+VM_HDL qtc_vmem_hand;
+VM_PTR v_bset_item;
+VM_PTR v_tape_item;
+
+// unicode text macro
+
+#ifndef TEXT
+#define TEXT( x ) x
+#endif
+
+
+/**********************
+
+ NAME : QTC_Deinit
+
+ DESCRIPTION :
+
+ The application is terminating, so free everything.
+
+ RETURNS :
+
+**********************/
+
+VOID QTC_Deinit( INT delete_catalogs )
+{
+ QTC_TAPE_PTR tape;
+ QTC_BSET_PTR bset;
+
+
+ // Yank the temporary disk scan file, if it exists
+
+ QTC_RemoveTape( 0L, (INT16) 1 ) ;
+
+ // Yank all known files for microsoft
+ if ( delete_catalogs ) {
+ QTC_PurgeAllFiles();
+ }
+
+ // Free all our queues
+
+ tape = QTC_GetFirstTape( );
+
+ while ( tape != NULL ) {
+
+ bset = QTC_GetFirstBset( tape ) ;
+
+ while ( bset != NULL ) {
+ msassert( bset->q_elem.q_ptr == v_bset_item ) ;
+
+ vmRemoveQueueElem( &( tape->bset_list ), v_bset_item ) ;
+ VM_MemUnLock( qtc_vmem_hand, v_bset_item ) ;
+ VM_Free( qtc_vmem_hand, v_bset_item ) ;
+ v_bset_item = (VM_PTR) NULL ;
+
+ bset = QTC_GetFirstBset( tape ) ;
+ }
+
+ msassert( tape->q_elem.q_ptr == v_tape_item ) ;
+
+ vmRemoveQueueElem( &(gb_QTC.tape_list), v_tape_item ) ;
+ VM_MemUnLock( qtc_vmem_hand, v_tape_item ) ;
+ VM_Free( qtc_vmem_hand, v_tape_item ) ;
+ v_tape_item = (VM_PTR) NULL ;
+
+ tape = QTC_GetFirstTape( ) ;
+ }
+
+ // Free the data path allocated at init
+
+ if ( gb_QTC.data_path != NULL ) {
+ free( gb_QTC.data_path );
+ }
+
+#if defined( P_CLIENT ) || defined( OS_NLM )
+
+ if ( gb_QTC.cat_user ) {
+ free( gb_QTC.cat_user ) ;
+ gb_QTC.cat_user = NULL ;
+ }
+
+#endif
+}
+
+
+
+/**********************
+
+ NAME : QTC_PurgeAllFiles
+
+ DESCRIPTION :
+
+ Used by the microsoft version of NT to delete all catalog files when
+ the user exits.
+
+ RETURNS :
+
+**********************/
+
+INT QTC_PurgeAllFiles( )
+{
+ QTC_TAPE_PTR tape;
+
+ tape = QTC_GetFirstTape( );
+
+ while ( tape ) {
+ QTC_RemoveTape( tape->tape_fid, tape->tape_seq_num ) ;
+ tape = QTC_GetFirstTape( );
+ }
+
+ return( 0 );
+}
+
+
+
+/**********************
+
+ NAME : QTC_Init
+
+ DESCRIPTION :
+
+ Init the catalogs, called ONCE at start up time.
+ Tries to read existing catalogs, if it fails it creates new ones.
+
+ RETURNS :
+
+**********************/
+
+INT QTC_Init(
+CHAR_PTR data_path,
+VM_HDL vm_hdl )
+{
+
+ // Are we returning ASCII or UNICODE results.
+
+#ifdef UNICODE
+ gb_QTC.unicode = TRUE;
+#else
+ gb_QTC.unicode = FALSE;
+#endif
+
+ // Set virtual memory handle as passed from the UI
+
+ qtc_vmem_hand = vm_hdl ;
+
+ vmSetVMHandle( vm_hdl ) ;
+
+ // Don't allow passing of a NULL data path
+ if ( data_path == NULL ) {
+ return( QTC_OPEN_FAILED ) ;
+ }
+
+ gb_QTC.data_path = malloc( strsize ( data_path ) );
+
+ if ( gb_QTC.data_path == NULL ) {
+
+ return( QTC_NO_MEMORY );
+ }
+
+ strcpy( gb_QTC.data_path, data_path );
+
+ // Delete the disk scan temporary file if present
+
+ QTC_UnlinkFile( 0L, (INT16) 1 );
+
+ vmInitQueue( &(gb_QTC.tape_list) ) ;
+
+ // Mark that we were successfully inited.
+
+ gb_QTC.inited = QTC_MAGIC_NUMBER;
+
+ return( SUCCESS );
+}
+
+
+/**********************
+
+ NAME : QTC_GetFIDFromName
+
+ DESCRIPTION :
+
+ We need to make sure the stupid user did not rename the catalog file.
+ So we check to make sure the tape fid of the sets match the file name.
+ This function works because we are garanteed that the name is
+ "xxxxxxxx.yyy"
+
+ RETURNS :
+
+**********************/
+
+INT QTC_GetDataFromName( CHAR_PTR name, UINT32_PTR fid, UINT16_PTR seq )
+{
+ CHAR_PTR s;
+ INT i;
+ INT16 value;
+
+ *fid = 0;
+ *seq = 0;
+
+ i = strlen( name );
+ i -= 12;
+
+ s = &name[ i ];
+
+ for ( i = 0; i < 8; i++ ) {
+
+ if ( *s >= TEXT('0') && *s <= TEXT('9') ) {
+ value = ( *s - TEXT('0') );
+ }
+ else {
+ value = 10 + ( toupper( *s ) - TEXT('A') );
+ }
+
+ s++;
+
+ *fid *= 16;
+ *fid += value;
+ }
+
+ i = strlen( name );
+ i -= 2;
+
+ s = &name[ i ];
+
+ for ( i = 0; i < 2; i++ ) {
+
+ if ( *s >= TEXT('0') && *s <= TEXT('9') ) {
+ value = ( *s - TEXT('0') );
+ }
+
+ s++;
+
+ *seq *= 10;
+ *seq += value;
+ }
+
+ return( SUCCESS );
+}
+
+/**********************
+
+ NAME : QTC_LoadBsetInfo
+
+ DESCRIPTION :
+
+ Reads in all the bset headers from a catalog file and builds a queue.
+
+ Uses either the file name passed in or the tape, set the other to NULL.
+
+ RETURNS :
+
+**********************/
+
+INT QTC_LoadBsetInfo( CHAR_PTR name, QTC_TAPE_PTR tape )
+{
+ INT fd;
+ LONG ret;
+ UINT32 next_header = sizeof( QTC_TAPE_HEADER );
+ QTC_TAPE_HEADER tape_header;
+ QTC_HEADER header;
+ QTC_BSET_PTR bset;
+ UINT32 fid;
+ UINT16 seq;
+ INT error = SUCCESS;
+ INT Error;
+ CHAR *name_buffer;
+
+#if defined( P_CLIENT )
+ VQ_HDL v_temp_bset = (VQ_HDL)NULL ;
+#endif
+
+ if ( gb_QTC.inited != QTC_MAGIC_NUMBER ) {
+ return( QTC_NO_INIT );
+ }
+
+ // open file, share it with everyone
+
+ if ( name != NULL ) {
+ name_buffer = (CHAR *)malloc( ( strsize( gb_QTC.data_path ) + strsize( name ) ) * sizeof(CHAR ) );
+ if ( name_buffer == NULL ) {
+ return( QTC_NO_INIT );
+ }
+ strcpy( name_buffer, gb_QTC.data_path );
+ strcat( name_buffer, name );
+ }
+
+ if ( ( tape != NULL ) && ( name == NULL ) ) {
+ QTC_GetFileName( tape->tape_fid, tape->tape_seq_num, name_buffer );
+ }
+ else {
+ //first lets make sure this is a valid name
+ if ( (strlen( name ) != 12) ||
+ (name[10] < '0') ||
+ ((name[10] > '9' ) && (name[10] < 'A') ) ||
+ ((name[10] > 'F' ) && (name[10] < 'a') ) ||
+ (name[10] > 'f' ) ||
+ (name[11] < '0') ||
+ ((name[11] > '9' ) && (name[11] < 'A') ) ||
+ ((name[11] > 'F' ) && (name[11] < 'a') ) ||
+ (name[11] > 'f' ) ) {
+
+ return( QTC_OPEN_FAILED );
+ }
+
+ QTC_GetDataFromName( name, &fid, &seq );
+ }
+
+ fd = QTC_OpenFile( fid, seq, FALSE, FALSE );
+
+ if ( fd < 0 ) {
+ return( QTC_OPEN_FAILED );
+ }
+
+ // read header
+
+ ret = QTC_ReadFile( fd, (BYTE_PTR)&tape_header, sizeof( QTC_TAPE_HEADER ), &Error );
+
+ if ( ret != sizeof( QTC_TAPE_HEADER ) ) {
+ QTC_CloseFile( fd );
+ return( QTC_INVALID_FILE );
+ }
+
+ if ( memcmp( tape_header.signature, QTC_SIGNATURE, sizeof( QTC_SIGNATURE ) ) ||
+ ( tape_header.major_version != QTC_MAJOR_VERSION ) ) {
+
+ QTC_CloseFile( fd );
+ return( QTC_INVALID_FILE );
+ }
+
+ QTC_GetDataFromName( name_buffer, &fid, &seq );
+
+ free( name_buffer );
+
+ while ( ( next_header != 0L ) && ( error == SUCCESS ) ) {
+
+ // skip to first bset
+
+ ret = QTC_SeekFile( fd, next_header );
+
+ // read temp bset info to get size
+
+ ret = QTC_ReadFile( fd, (BYTE_PTR)&header, sizeof( QTC_HEADER ), &Error );
+
+ if ( ret != sizeof( QTC_HEADER ) ) {
+ QTC_CloseFile( fd );
+ return( QTC_READ_FAILED );
+ }
+
+ if ( ( header.tape_fid != fid ) ||
+ ( header.tape_seq_num != (INT32)seq ) ) {
+
+ // User renamed file or it is corrupt.
+ QTC_CloseFile( fd );
+ return( QTC_INVALID_FILE );
+ }
+
+
+#if defined( P_CLIENT ) || defined( OS_NLM )
+
+ if ( header.status & QTC_TAPE_DELETED ) {
+ error = QTC_TAPE_TAGGED_DELETED ;
+ break ;
+ }
+
+#endif
+
+ if ( ! ( header.status & QTC_ERASED ) ) {
+
+#if defined( P_CLIENT )
+ QTC_HEADER_PTR vlen_header ;
+ INT rbytes ;
+
+ // P_CLIENT needs to filter user view of catalogs based on who
+ // the user is.
+ //
+ if ( !( vlen_header = malloc( (size_t) header.header_size ) ) ) {
+ QTC_CloseFile( fd ) ;
+ return ( QTC_NO_MEMORY ) ;
+ }
+
+ QTC_SeekFile( fd, next_header ) ;
+ rbytes = QTC_ReadFile( fd, vlen_header, (size_t) header.header_size, &Error ) ;
+
+ if ( rbytes != (INT) header.header_size ) {
+ free( vlen_header );
+ QTC_CloseFile( fd ) ;
+ return( QTC_INVALID_FILE ) ;
+ }
+
+ QTC_SetUpStrings( vlen_header ) ;
+
+ if ( gb_QTC.cat_user == NULL || !strcmpi( gb_QTC.cat_user, vlen_header->user_name ) ) {
+
+#endif
+ VM_MemUnLock( qtc_vmem_hand, v_bset_item ) ;
+ v_bset_item = VM_Alloc( qtc_vmem_hand, sizeof( QTC_BSET ) ) ;
+ bset = VM_MemLock( qtc_vmem_hand, v_bset_item, VM_READ_WRITE ) ;
+
+ if ( bset == NULL ) {
+
+#if defined( P_CLIENT )
+ free( vlen_header );
+#endif
+
+ QTC_CloseFile( fd );
+ return( QTC_NO_MEMORY ) ;
+ }
+ vmInitQElem( &( bset->q_elem ) ) ;
+
+ QTC_SeekFile( fd, next_header );
+
+ bset->q_elem.q_ptr = v_bset_item ;
+ bset->bset_num = header.bset_num ;
+ bset->tape_seq_num = header.tape_seq_num ;
+ bset->tape_fid = header.tape_fid ;
+ bset->status = header.status ;
+
+ bset->offset = next_header ; // set where this guy actually started in file
+
+#if defined( P_CLIENT )
+ bset->v_volume = NULL ;
+ // save a virtual pointer to the backup set
+ // for later use.
+ v_temp_bset = v_bset_item ;
+#endif
+
+ error = QTC_NewBset( v_bset_item ) ;
+
+ // We are NOT entitled to use the bset pointer after QTC_NewBset
+ // returns!! Problem is, it was locked as v_bset_item above.
+ // Meanwhile, QTC_NewBset may have called QTC_GetFirstBset, etc.
+ // which unlocked v_bset_item...
+
+#if defined( P_CLIENT )
+ }
+ free( vlen_header ) ;
+#endif
+ }
+
+ // get address of next bset
+
+ next_header = header.next_bset ;
+ }
+
+
+#if defined( P_CLIENT )
+ if ( !error ) {
+ struct stat tmp_stat ;
+
+ // if 'tape' argument was NULL, find tape in the in-memory queue
+ // also check that there actually WAS a bset to compare against.
+ if ( (tape == NULL) && (v_temp_bset != (VQ_HDL)NULL) ) {
+
+
+ // lock the last temp_bset we saved.
+ bset = VM_MemLock( qtc_vmem_hand, v_temp_bset, VM_READ_WRITE ) ;
+
+ if ( bset == NULL ) {
+ QTC_CloseFile( fd );
+ return( QTC_NO_MEMORY ) ;
+ }
+
+ tape = QTC_GetFirstTape( );
+
+ while ( tape != NULL ) {
+ if ( ( tape->tape_fid == bset->tape_fid ) &&
+ ( tape->tape_seq_num == (INT16)bset->tape_seq_num ) ) {
+ break;
+ }
+ tape = QTC_GetNextTape( tape );
+ }
+
+ VM_MemUnLock( qtc_vmem_hand, v_temp_bset ) ;
+
+ }
+
+
+ // There's a possibility that tape _is_ NULL, if this user didn't
+ // have any backups on this tape
+ if ( tape != NULL ) {
+
+ // save the file's modified date/time in the structure
+ if ( !fstat( fd, &tmp_stat ) ) {
+
+ msassert( sizeof( time_t ) == sizeof( UINT32 ) ) ;
+ tape->wr_time = (UINT32) tmp_stat.st_mtime ;
+ }
+ }
+ }
+#endif
+
+
+ QTC_CloseFile( fd );
+ return( error );
+}
+
+/**********************
+
+ NAME : QTC_DumpBsetInfo
+
+ DESCRIPTION :
+
+ Frees the bset queue for this tape from memory.
+
+ RETURNS :
+
+**********************/
+
+INT QTC_DumpBsetInfo( QTC_TAPE_PTR tape )
+{
+ QTC_BSET_PTR bset;
+
+ if ( tape != NULL ) {
+
+ bset = QTC_GetFirstBset( tape );
+
+ while ( bset != NULL ) {
+ msassert( v_bset_item == bset->q_elem.q_ptr ) ;
+
+ vmRemoveQueueElem( &(tape->bset_list), v_bset_item ) ;
+ VM_MemUnLock( qtc_vmem_hand, v_bset_item ) ;
+ VM_Free( qtc_vmem_hand, v_bset_item ) ;
+ v_bset_item = (VM_PTR) NULL ;
+
+ bset = QTC_GetFirstBset( tape ) ;
+ }
+ }
+
+ return( SUCCESS );
+}
diff --git a/private/utils/ntbackup/src/qtc_srch.c b/private/utils/ntbackup/src/qtc_srch.c
new file mode 100644
index 000000000..6accc9945
--- /dev/null
+++ b/private/utils/ntbackup/src/qtc_srch.c
@@ -0,0 +1,3034 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: QTC_SRCH.C
+
+ Description:
+
+ A lot of searching functions for the catalogs.
+
+ $Log: N:\logfiles\qtc_srch.c_v $
+
+ Rev 1.31.1.0 20 Jul 1994 19:36:38 STEVEN
+now search next tape as well
+
+ Rev 1.31 18 Feb 1994 17:01:52 MIKEP
+one more unicode typo
+
+ Rev 1.30 15 Feb 1994 11:15:24 MIKEP
+fix unicode catalog search stuff
+
+ Rev 1.29 24 Jan 1994 09:36:04 MIKEP
+fix yet another unicode bug
+
+ Rev 1.28 07 Jan 1994 14:23:22 mikep
+fixes for unicode
+
+ Rev 1.27 11 Dec 1993 11:49:12 MikeP
+fix warnings from unicode compile
+
+ Rev 1.26 06 Dec 1993 09:46:26 mikep
+Very deep path support & unicode fixes
+
+ Rev 1.25 28 Oct 1993 14:47:40 MIKEP
+dll changes
+
+ Rev 1.24 20 Jul 1993 20:18:06 MIKEP
+fix unicode bug for steve.
+
+ Rev 1.23 16 Jul 1993 11:45:46 MIKEP
+Fix bug if searching for files & not searching subdirectories &
+crossing tapes all at the same time. It would return files that
+were in child subdirectories, when it shouldn't.
+
+ Rev 1.22 22 Jun 1993 14:35:12 DON
+Needed to check if there was an error before checking for QTC_NO_MORE in SearchFirstItem
+
+ Rev 1.21 08 Jun 1993 19:05:32 DON
+If we are calling QTC_SearchFirstItem and then searching for more matches
+withing the same BSD, as is the case when restoring multiple Single
+File Selections, ERROR will be set to QTC_NO_MORE and when we call
+QTC_SearchFirstItem again to find the next file, ERROR has not be cleared!
+So...If ERROR is QTC_NO_MORE just reset error and continue else FAILURE.
+
+ Rev 1.20 11 May 1993 08:55:24 MIKEP
+Enable unicode to compile.
+
+ Rev 1.19 30 Apr 1993 08:36:24 MIKEP
+Fix search if the user is searching the root and does not wish
+to search subdirectories. It was broken and would search
+everything in the set if the path was the root.
+
+ Rev 1.18 23 Mar 1993 18:00:34 ChuckS
+Added arg to QTC_OpenFile indicating if need to open for writes
+
+ Rev 1.17 04 Mar 1993 17:28:54 ANDY
+Added bug-fix for MIKEP
+
+ Rev 1.16 18 Feb 1993 09:02:10 DON
+Cleaned up compiler warnings
+
+ Rev 1.15 09 Feb 1993 17:26:46 STEVEN
+checkin for mikep
+
+ Rev 1.14 26 Jan 1993 12:28:04 ANDY
+if OS_NLM, don't want alloc_text pragma's either!
+
+ Rev 1.13 25 Jan 1993 09:09:00 MIKEP
+fix duplicate \system directory bug
+
+ Rev 1.12 21 Jan 1993 16:20:58 MIKEP
+fix undisplayed directories with duplicate parents
+
+ Rev 1.11 20 Jan 1993 19:47:16 MIKEP
+fix nt warnings
+
+ Rev 1.10 04 Jan 1993 09:34:36 MIKEP
+unicode changes
+
+ Rev 1.8 22 Dec 1992 12:02:12 DAVEV
+fix for loop problem indexing past end of unicode string
+
+ Rev 1.7 14 Dec 1992 12:29:24 DAVEV
+Enabled for Unicode compile
+
+ Rev 1.6 20 Nov 1992 13:50:38 CHARLIE
+JAGUAR: Move to SRM based QTC code
+
+ENDEAVOR: Virtualized QTC_SRCH into multiple sections in anticipation of DOS.
+
+ Rev 1.5 15 Nov 1992 16:05:18 MIKEP
+fix warnings and change wcs.h to stdwcs.h
+
+ Rev 1.4 06 Nov 1992 15:29:58 DON
+Change debug.h to be_debug.h and zprintf to BE_Zprintf
+
+ Rev 1.3 05 Nov 1992 08:55:20 STEVEN
+fix typo
+
+ Rev 1.2 29 Oct 1992 14:41:28 MIKEP
+fix duplicate directory detection
+
+ Rev 1.1 09 Oct 1992 11:53:56 MIKEP
+unicode pass
+
+ Rev 1.0 03 Sep 1992 16:56:06 STEVEN
+Initial revision.
+
+
+****************************************************/
+
+//
+// A query structure may be used for 1 set of GetFirst/GetNext commands
+// at a time. You may not use the same query structure to go through
+// the directory tree and get all the files in those directories.
+// But you can use as many different query structures as you wish,
+// at the same time, intermingling the calls. You may reuse a query
+// structure.
+//
+
+#include <dos.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <io.h>
+#include <string.h>
+#include <time.h>
+#include <share.h>
+#include <malloc.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "stdwcs.h"
+#include "qtc.h"
+
+#if !defined( OS_WIN32 ) && !defined( OS_NLM )
+#pragma alloc_text( QTC_SRCH_SEG1, QTC_SearchFirstItem )
+#pragma alloc_text( QTC_SRCH_SEG2, QTC_SearchNextItem )
+#pragma alloc_text( QTC_SRCH_SEG3, QTC_FastSearchForFile )
+#pragma alloc_text( QTC_SRCH_SEG4, QTC_FastSearchForDir )
+#pragma alloc_text( QTC_SRCH_SEG5, QTC_GetNextItem )
+#pragma alloc_text( QTC_SRCH_SEG6, QTC_FindStoppingOffset )
+#endif
+
+// unicode text macro
+#ifndef UNALIGNED
+#define UNALIGNED
+#endif
+
+#ifndef TEXT
+#define TEXT( x ) x
+#endif
+
+// defines for data buffering scheme
+
+#define BUFF_DIR 0
+#define BUFF_FILE 1
+#define BUFF_CHILD_DIR 2
+
+
+static INT QTC_FindDirectoryPath( QTC_QUERY_PTR, QTC_RECORD_PTR, UINT32, INT );
+
+
+QTC_BSET_PTR QTC_GetBsetForSrch( QTC_QUERY_PTR qtc )
+{
+ QTC_TAPE_PTR tape;
+ QTC_BSET_PTR bset;
+ QTC_BSET_PTR temp_bset;
+
+ // Now find a bset that matches it
+
+ tape = QTC_GetFirstTape( );
+
+ temp_bset = NULL;
+ bset = NULL;
+
+ while ( tape != NULL ) {
+
+ if ( ( tape->tape_fid == qtc->tape_fid ) &&
+ ( tape->tape_seq_num == qtc->tape_seq_num ) ) {
+
+ bset = QTC_GetFirstBset( tape );
+
+ while ( bset != NULL ) {
+
+ if ( bset->bset_num == qtc->bset_num ) {
+
+ if ( ! ( bset->status & ( QTC_PARTIAL | QTC_IMAGE ) ) ) {
+ break;
+ }
+ }
+ bset = QTC_GetNextBset( bset );
+ }
+ break;
+ }
+ else {
+
+ if ( ( tape->tape_fid == qtc->tape_fid ) &&
+ ( qtc->tape_seq_num == -1 ) ) {
+
+ temp_bset = QTC_GetFirstBset( tape );
+
+ while ( temp_bset != NULL ) {
+
+ if ( temp_bset->bset_num == qtc->bset_num ) {
+
+ if ( ! ( temp_bset->status & ( QTC_PARTIAL | QTC_IMAGE ) ) ) {
+
+ if ( bset == NULL ) {
+ bset = temp_bset;
+ }
+
+ if ( bset->tape_seq_num > temp_bset->tape_seq_num ) {
+
+ bset = temp_bset;
+ }
+ }
+ }
+ temp_bset = QTC_GetNextBset( temp_bset );
+ }
+ }
+ }
+
+ tape = QTC_GetNextTape( tape );
+ }
+
+ return( bset );
+}
+
+
+
+INT QTC_SetFileCounts( QTC_QUERY_PTR qtc )
+{
+ INT index;
+ UINT32 files = 0;
+ UINT32 bytes_msw = 0;
+ UINT32 bytes_lsw = 0;
+ UINT32 UNALIGNED *i32;
+
+ index = 0;
+
+ while ( index < qtc->xtra_size ) {
+
+ if ( qtc->xtra_bytes[ index ] == QTC_COMBO_COUNT ) {
+
+ i32 = (UINT32 *)&qtc->xtra_bytes[ index + 1 ];
+ files = *i32 >> 24;
+ bytes_lsw = *i32 & 0x00FFFFFFL;
+
+ }
+ if ( qtc->xtra_bytes[ index ] == QTC_FILE_COUNT ) {
+
+ i32 = (UINT32 *)&qtc->xtra_bytes[ index + 1 ];
+ files = *i32;
+ }
+ if ( qtc->xtra_bytes[ index ] == QTC_BYTE_COUNT_LSW ) {
+
+ i32 = (UINT32 *)&qtc->xtra_bytes[ index + 1 ];
+ bytes_lsw = *i32;
+ }
+ if ( qtc->xtra_bytes[ index ] == QTC_BYTE_COUNT_MSW ) {
+
+ i32 = (UINT32 *)&qtc->xtra_bytes[ index + 1 ];
+ bytes_msw = *i32;
+ }
+ index += 5;
+ }
+
+ qtc->file_count = (INT)files;
+ qtc->byte_count = U64_Init( bytes_lsw, bytes_msw );
+
+ return( SUCCESS );
+}
+
+INT QTC_TestItemSize( QTC_QUERY_PTR qtc, INT bytes )
+{
+ CHAR_PTR item;
+
+ bytes += 4; // in case they ask for 0
+
+ if ( qtc->size_of_item < bytes ) {
+ item = malloc( bytes );
+ memcpy( item, qtc->item, qtc->size_of_item );
+ free( qtc->item );
+ qtc->item = item;
+ qtc->size_of_item = bytes;
+ }
+
+ return( SUCCESS );
+}
+
+INT QTC_TestPathSize( QTC_QUERY_PTR qtc, INT bytes )
+{
+ CHAR_PTR path;
+
+ bytes += 4;
+
+ if ( qtc->size_of_path < bytes ) {
+ path = malloc( bytes );
+ memcpy( path, qtc->path, qtc->size_of_path );
+ free( qtc->path );
+ qtc->path = path;
+ qtc->size_of_path = bytes;
+ }
+
+ return( SUCCESS );
+}
+
+INT QTC_TestLastPathSize( QTC_QUERY_PTR qtc, INT bytes )
+{
+ CHAR_PTR path;
+
+ bytes += 4;
+
+ if ( qtc->size_of_last_path < bytes ) {
+ path = malloc( bytes );
+ memcpy( path, qtc->last_path, qtc->size_of_last_path );
+ free( qtc->last_path );
+ qtc->last_path = path;
+ qtc->size_of_last_path = bytes;
+ }
+
+ return( SUCCESS );
+}
+
+/***************
+ Get the path to search for in the query structure provided.
+****************/
+
+INT QTC_GetSearchPath( QTC_QUERY_PTR qtc, CHAR_PTR path )
+{
+ if ( qtc == NULL ) {
+ return( QTC_FAILURE );
+ }
+
+ memcpy( path, qtc->search_path, qtc->search_path_size );
+
+ return( QTC_SUCCESS );
+}
+
+/***************
+ Get the path to search for in the query structure provided.
+****************/
+
+INT QTC_GetSearchPathLength( QTC_QUERY_PTR qtc )
+{
+ if ( qtc == NULL ) {
+ return( 0 );
+ }
+
+ return( qtc->search_path_size );
+}
+
+
+/***************
+ Set the path to search for in the query structure provided.
+****************/
+
+INT QTC_SetSearchPath( QTC_QUERY_PTR qtc, CHAR_PTR path, INT size )
+{
+ free( qtc->search_path );
+
+ qtc->search_path = malloc( size );
+ qtc->search_path_size = size;
+
+ if ( qtc->search_path == NULL ) {
+ qtc->error = TRUE;
+ return( FAILURE );
+ }
+
+ memcpy( qtc->search_path, path, size );
+
+ return( QTC_SUCCESS );
+}
+
+
+/***************
+ Set the name to search for in the query structure provided.
+
+ Fills in the unicode and ascii versions for use later if needed.
+
+****************/
+
+INT QTC_SetSearchName( QTC_QUERY_PTR qtc, CHAR_PTR name )
+{
+ int length;
+
+ free( qtc->search_name );
+
+ length = strlen( name ) + 1;
+
+ qtc->search_name = malloc( length * sizeof (CHAR) );
+
+ if ( qtc->search_name == NULL ) {
+ qtc->error = TRUE;
+ return( FAILURE );
+ }
+
+ memcpy( qtc->search_name, name, length * sizeof (CHAR) );
+
+ return( SUCCESS );
+}
+
+
+/*******************
+
+ The user would like to query the catalogs and he has asked us to init
+ a query structure for him. So do it.
+
+********************/
+
+QTC_QUERY_PTR QTC_InitQuery( )
+{
+ QTC_QUERY_PTR qtc;
+
+ qtc = calloc( sizeof(QTC_QUERY), 1 );
+
+ if ( qtc != NULL ) {
+
+ qtc->search_path = NULL;
+
+ qtc->path = NULL;
+ qtc->item = NULL;
+ qtc->last_path = NULL;
+
+ qtc->size_of_path = 0;
+ qtc->size_of_item = 0;
+ qtc->size_of_last_path = 0;
+
+ qtc->header = NULL;
+ qtc->error = FALSE; // no error yet
+ qtc->file_open = FALSE; // no data file open either
+
+ QTC_TestItemSize( qtc, sizeof( CHAR ) );
+ strcpy( qtc->item, TEXT( "" ) );
+
+ QTC_SetSubdirs( qtc, TRUE );
+ QTC_SetPreDate( qtc, 0 );
+ QTC_SetPostDate( qtc, 0 );
+
+ QTC_SetSearchName( qtc, TEXT("*.*") );
+ QTC_SetSearchPath( qtc, TEXT(""), sizeof(CHAR) );
+ }
+
+
+ return( qtc );
+}
+
+/**************
+ The user is done with this query structure.
+ Terminate It.
+**************/
+
+INT QTC_CloseQuery(
+QTC_QUERY_PTR qtc ) // I - query structure to dump
+{
+
+ if ( qtc->file_open ) {
+ QTC_CloseFile( qtc->fh );
+ }
+
+ free( qtc->path );
+ free( qtc->last_path );
+ free( qtc->item );
+ free( qtc->header );
+ free( qtc->search_path );
+ free( qtc->search_name );
+ free( qtc );
+
+ return( SUCCESS );
+}
+
+
+/********************
+
+ The user has requested a search of the catalogs. The search criteria are
+ in the qtc structure. Set up our own stuff for the search and then call
+ QTC_GetNextSearchItem(), to find the first item.
+
+*********************/
+
+INT QTC_SearchFirstItem(
+QTC_QUERY_PTR qtc )
+{
+ BOOLEAN found;
+ QTC_RECORD record;
+
+ if ( gb_QTC.inited != QTC_MAGIC_NUMBER ) {
+ return( QTC_NO_INIT );
+ }
+
+ free( qtc->header );
+ qtc->header = NULL;
+
+ /*
+ If we are calling this function and then searching for more matches
+ withing the same BSD, as is the case when restoring multiple Single
+ File Selections, error will be set to QTC_NO_MORE and when we call
+ this function again to find the next file, error will not be cleared!
+
+ So, if the error is QTC_NO_MORE we will just reset error and continue
+ else FAILURE.
+ */
+
+ if ( qtc->error )
+ {
+ if ( qtc->error == QTC_NO_MORE )
+ {
+ qtc->error = FALSE;
+ }
+ else
+ {
+ return( QTC_FAILURE );
+ }
+ }
+
+ if ( qtc->file_open ) {
+ QTC_CloseFile( qtc->fh );
+ qtc->file_open = FALSE;
+ }
+
+ qtc->bset = QTC_GetBsetForSrch( qtc );
+
+ if ( qtc->bset == NULL ) {
+ return( QTC_BSET_NOT_FOUND );
+ }
+
+ qtc->header = QTC_LoadHeader( qtc->bset );
+ if ( qtc->header == NULL ) {
+ return( QTC_NO_HEADER );
+ }
+
+ qtc->fh = QTC_OpenFile( qtc->bset->tape_fid,
+ (INT16)qtc->bset->tape_seq_num, FALSE, FALSE );
+
+ if ( qtc->fh < 0 ) {
+ return( QTC_OPEN_FAILED );
+ }
+
+ qtc->file_open = TRUE;
+
+ qtc->fil_dir_offset = 0;
+
+ // Here we need to find the starting and ending offsets to search.
+ // For the root default to entire bset.
+
+ if ( ! strlen( qtc->search_name ) ) {
+
+ // they only wanted a directory
+
+ found = FALSE;
+
+ do {
+
+ if ( QTC_FindDirRec( qtc, &record ) == SUCCESS ) {
+
+ qtc->curr_mom_offset = qtc->header->dir_start + record.name_offset;
+ found = TRUE;
+ break;
+ }
+
+ } while ( QTC_MoveToNextTapeInFamily( qtc ) == SUCCESS );
+
+ if ( ! found ) {
+ return( QTC_NO_MORE );
+ }
+
+ QTC_TestPathSize( qtc, qtc->search_path_size );
+ memcpy( qtc->path, qtc->search_path, qtc->search_path_size );
+ qtc->path_size = qtc->search_path_size;
+
+ QTC_TestItemSize( qtc, ( strlen( TEXT("") ) + 1 ) * sizeof(CHAR) );
+ strcpy( qtc->item, TEXT("") );
+
+ qtc->status = (UINT8)record.status;
+ qtc->date = (INT16)record.date;
+ qtc->time = (INT16)record.time;
+ qtc->attrib = record.attribute;
+ qtc->size = U64_Init( record.common.common.height, 0L );
+ qtc->lba = record.lba;
+
+ QTC_SetFileCounts( qtc );
+ return( QTC_SUCCESS );
+ }
+
+
+ // Decide where to start and stop searching in this set. We can just
+ // search the entire set if the path is the root and we can search
+ // subdirectories.
+
+
+ if ( ( qtc->search_path_size == sizeof(CHAR) ) && ( qtc->subdirs ) ) {
+
+ qtc->search_start = qtc->header->fil_start;
+ qtc->curr_mom_offset = qtc->header->dir_start;
+ qtc->search_stop = qtc->header->fil_start + qtc->header->fil_size;
+ }
+ else {
+
+ found = FALSE;
+
+ do {
+
+ if ( QTC_FindDirRec( qtc, &record ) == SUCCESS ) {
+
+ qtc->curr_mom_offset = qtc->header->dir_start + record.name_offset;
+ found = TRUE;
+ break;
+ }
+
+ } while ( QTC_MoveToNextTapeInFamily( qtc ) == SUCCESS );
+
+ if ( ! found ) {
+ return( QTC_NO_MORE );
+ }
+
+ qtc->search_start = qtc->header->fil_start + record.common.common.file_start;
+
+ // Find the first directory at a higher level than this one and
+ // that's where to stop.
+
+ if ( QTC_FindStoppingOffset( qtc, &record ) ) {
+ return( QTC_READ_FAILED );
+ }
+
+ }
+
+ // Initialize buffers as empty
+
+ qtc->search_max = 0;
+ qtc->search_index = 0;
+ qtc->search_base = qtc->search_start;
+
+ // If no '*' characters in search name then set requested search length
+
+ if ( strchr( qtc->search_name, TEXT('*') ) ) {
+ qtc->search_size = 0;
+ }
+ else {
+
+ qtc->search_size = (UINT16)( sizeof( QTC_NAME ) +
+ (strlen( qtc->search_name ) * sizeof(CHAR) ) );
+ }
+
+ return( QTC_SearchNextItem( qtc ) );
+}
+
+/************************
+
+ Find the next matching item to the search request set up in the qtc.
+
+*************************/
+
+INT QTC_SearchNextItem( QTC_QUERY_PTR qtc )
+{
+ QTC_NAME UNALIGNED * name;
+ QTC_RECORD record;
+ UINT32 offset;
+ UINT32 msw_size = 0L;
+ BYTE_PTR s;
+ BOOLEAN found;
+ INT result;
+ INT size;
+ INT i;
+ INT Error;
+
+
+ if ( qtc->error ) {
+ return( QTC_FAILURE );
+ }
+
+ if ( ! strlen( qtc->search_name ) ) {
+
+ // They only wanted a directory, so look for a duplicate.
+
+ if ( QTC_FindNextDirRec( qtc, &record ) != SUCCESS ) {
+
+ found = FALSE;
+
+ while ( QTC_MoveToNextTapeInFamily( qtc ) == SUCCESS ) {
+
+ if ( QTC_FindDirRec( qtc, &record ) == SUCCESS ) {
+
+ qtc->curr_mom_offset = qtc->header->dir_start + record.name_offset;
+ found = TRUE;
+ break;
+ }
+
+ }
+
+ if ( ! found ) {
+ return( QTC_NO_MORE );
+ }
+ }
+
+ qtc->curr_mom_offset = qtc->header->dir_start + record.name_offset;
+
+ QTC_TestPathSize( qtc, qtc->search_path_size );
+ memcpy( qtc->path, qtc->search_path, qtc->search_path_size );
+ qtc->path_size = qtc->search_path_size;
+
+ QTC_TestItemSize( qtc, ( strlen( TEXT("") ) + 1 ) * sizeof(CHAR) );
+ strcpy( qtc->item, TEXT("") );
+
+ qtc->status = (UINT8)record.status;
+ qtc->date = (INT16)record.date;
+ qtc->time = (INT16)record.time;
+ qtc->attrib = record.attribute;
+ qtc->size = U64_Init( record.common.common.height, 0L );
+ qtc->lba = record.lba;
+
+ QTC_SetFileCounts( qtc );
+ return( QTC_SUCCESS );
+ }
+
+ // If duplicates exist in the directory, than we need to check for the
+ // possible existence of another valid search area.
+
+ if ( QTC_FastSearchForFile( qtc ) != SUCCESS ) {
+
+ found = FALSE;
+
+ // Loop over all the directories in all the tapes.
+
+ while ( ! found ) {
+
+ // Look at all duplicate directories first.
+
+ while ( QTC_FindNextDirRec( qtc, &record ) == SUCCESS ) {
+
+ qtc->curr_mom_offset = qtc->header->dir_start + record.name_offset;
+
+ qtc->search_start = qtc->header->fil_start + record.common.common.file_start;
+
+ // Find the first directory at a higher level than this one and
+ // that's where to stop.
+
+ if ( QTC_FindStoppingOffset( qtc, &record ) ) {
+ return( QTC_READ_FAILED );
+ }
+
+ // Initialize buffers as empty
+
+ qtc->search_max = 0;
+ qtc->search_index = 0;
+ qtc->search_base = qtc->search_start;
+
+ // Now look for the file in our new duplicate directory.
+
+ if ( QTC_FastSearchForFile( qtc ) == SUCCESS ) {
+ found = TRUE;
+ break;
+ }
+
+ }
+
+ if ( ! found ) {
+
+ // Try another tape, same bset number.
+
+ if ( QTC_MoveToNextTapeInFamily( qtc ) == SUCCESS ) {
+
+ // Find the directory.
+
+ if ( QTC_FindDirRec( qtc, &record ) == SUCCESS ) {
+
+ qtc->curr_mom_offset = qtc->header->dir_start + record.name_offset;
+
+ if ( ( qtc->search_path_size == sizeof(CHAR) ) && ( qtc->subdirs ) ) {
+
+ qtc->search_start = qtc->header->fil_start;
+ qtc->search_stop = qtc->header->fil_start + qtc->header->fil_size;
+ }
+ else {
+
+ qtc->search_start = qtc->header->fil_start + record.common.common.file_start;
+
+ // Find the first directory at a higher level than this one and
+ // that's where to stop.
+
+ if ( QTC_FindStoppingOffset( qtc, &record ) ) {
+ return( QTC_READ_FAILED );
+ }
+ }
+
+ // Initialize buffers as empty
+
+ qtc->search_max = 0;
+ qtc->search_index = 0;
+ qtc->search_base = qtc->search_start;
+
+ // Look for the file.
+
+ if ( QTC_FastSearchForFile( qtc ) == SUCCESS ) {
+ found = TRUE;
+ }
+
+ // Go back up to the top and look for a duplicate directory.
+ }
+ }
+ else {
+
+ // Every damn thing we've tried has failed.
+
+ return( FAILURE );
+ }
+ }
+ }
+ }
+
+ name = (QTC_NAME UNALIGNED *)qtc->buff1;
+
+ offset = qtc->header->rec_start;
+ offset += name->record * sizeof( QTC_RECORD );
+
+ QTC_SeekFile( qtc->fh, offset );
+
+ result = QTC_ReadFile( qtc->fh, (BYTE_PTR)&record, sizeof( QTC_RECORD ), &Error );
+
+ if ( result != sizeof( QTC_RECORD ) ) {
+ return( QTC_READ_FAILED );
+ }
+
+ QTC_TestPathSize( qtc, sizeof(CHAR) );
+ qtc->path[ 0 ] = TEXT( '\0' );
+ qtc->path_size = sizeof(CHAR);
+
+ // Copy name
+
+ s = qtc->buff1 + sizeof( QTC_NAME );
+
+ size = (INT)name->size - (INT)name->xtra_size - sizeof( QTC_NAME );
+
+ QTC_TestItemSize( qtc, size );
+ memcpy( qtc->item, s, size );
+ qtc->item[ size / sizeof(CHAR) ] = TEXT( '\0' );
+
+ // Item xtra bytes
+
+ s += name->size - (INT)name->xtra_size - sizeof( QTC_NAME );
+ memcpy( qtc->xtra_bytes, s, (INT)name->xtra_size );
+ qtc->xtra_size = (INT8)name->xtra_size;
+
+ for ( i = 0; i < qtc->xtra_size; i += 5 ) {
+ if ( qtc->xtra_bytes[ i ] == QTC_XTRA_64BIT_SIZE ) {
+ memcpy( &msw_size, &qtc->xtra_bytes[ i + 1 ] , 4 );
+ }
+ }
+
+ // record data
+
+ qtc->status = (UINT8)record.status;
+ qtc->date = (INT16)record.date;
+ qtc->time = (INT16)record.time;
+ qtc->attrib = record.attribute;
+ qtc->size = U64_Init( record.common.size, msw_size );
+ qtc->lba = record.lba;
+
+ // build path up
+
+ if ( QTC_BuildWholePath( qtc, name->mom_offset ) ) {
+ return( QTC_READ_FAILED );
+ }
+
+ QTC_SetFileCounts( qtc );
+
+ return( QTC_SUCCESS );
+}
+
+/**********************
+
+ The goal here is to fill in the qtc->search_stop field.
+
+ The user has asked for a search and specified a path. We have already
+ found the location in the catalogs where the path "\DOS\GAMES\JF"
+ starts and now we want to know where it stops. By finding the end
+ of this directory we can abort out of our search as soon as the valid
+ area has been searched. The QTC_NAME structure for the \JF entry is
+ in qtc->buff1 and the record for \JF is in the record field. Both of
+ these are no longer needed so they can be trashed by this routine.
+
+ If the user has requested we not search subdirectories then stop at
+ the first directory we find.
+
+ If we hit the end of the backup set before we reach the end of the
+ \JF directory than the end of the bset is where we stop searching.
+
+***********************/
+
+INT QTC_FindStoppingOffset( QTC_QUERY_PTR qtc, QTC_RECORD_PTR record )
+{
+ UINT32 curr_try_offset;
+ UINT32 dir_max;
+ UINT32 offset;
+ INT init = TRUE;
+ INT result;
+ INT Error;
+ QTC_NAME UNALIGNED * name;
+
+
+ // where is the end of valid data ?
+
+ dir_max = qtc->header->dir_start + qtc->header->dir_size;
+
+ // use buff1 to store the temp results in
+
+ name = ( QTC_NAME *)qtc->buff1;
+
+ // start looking immediately after the entry for starting at
+
+ curr_try_offset = qtc->header->dir_start;
+ curr_try_offset += record->name_offset + name->size;
+
+ // Look for name with mom_offset < last_offset
+ // This guy will fill in the name structure for us
+
+ while ( ! QTC_FastSearchForDir( qtc,
+ &curr_try_offset,
+ dir_max,
+ 0,
+ init ) ) {
+
+ // Only init once
+
+ if ( init ) {
+ init = FALSE;
+ }
+
+ // See if we found a brother or higher relative to the
+ // directory we started with. If we do then we are done.
+
+ if ( ( name->mom_offset < record->name_offset ) ||
+ ( ! qtc->subdirs ) ) {
+
+ // Yo dude, success !
+
+ offset = qtc->header->rec_start;
+ offset += ( name->record * sizeof( QTC_RECORD ) );
+
+ QTC_SeekFile( qtc->fh, offset );
+
+ result = QTC_ReadFile( qtc->fh, (BYTE_PTR)record, sizeof( QTC_RECORD ), &Error );
+
+ if ( result != sizeof(QTC_RECORD ) ) {
+ return( QTC_READ_FAILED );
+ }
+
+ qtc->search_stop = qtc->header->fil_start + record->common.common.file_start;
+
+ return( QTC_SUCCESS );
+ }
+ }
+
+ // We hit the end of the bset, use it for the stopping location
+
+ qtc->search_stop = qtc->header->fil_start + qtc->header->fil_size;
+
+ return( QTC_SUCCESS );
+}
+
+
+/**********************
+
+ Build the entire path starting with the offset passed in. We have
+ found a file during a search whose parent directory ends with the
+ directory entry at 'offset'. Fill in the qtc->path field with the
+ complete path for this file by working backwards up the name table.
+ Where each entry has the offset of its parent. When the parent
+ offset is zero, you can stop, you are at the root.
+
+***********************/
+
+INT QTC_BuildWholePath( QTC_QUERY_PTR qtc, UINT32 offset )
+{
+ INT i;
+ INT result;
+ INT bytes;
+ INT Error;
+ QTC_NAME UNALIGNED * name;
+ CHAR_PTR dirname;
+ BYTE buff1[ QTC_BUF_SIZE ];
+ BYTE_PTR byte_ptr;
+
+ name = (QTC_NAME UNALIGNED *)buff1;
+
+ byte_ptr = (BYTE_PTR)name;
+ byte_ptr += sizeof( QTC_NAME );
+
+ dirname = (CHAR_PTR)byte_ptr;
+
+ if ( offset == 0 ) {
+ QTC_TestPathSize( qtc, sizeof( CHAR ) );
+ qtc->path[ 0 ] = TEXT( '\0' );
+ qtc->path_size = sizeof( CHAR );
+ }
+ else {
+
+ qtc->path_size = 0;
+
+ while ( offset ) {
+
+ QTC_SeekFile( qtc->fh, qtc->header->dir_start + offset );
+
+ result = QTC_ReadFile( qtc->fh, buff1, QTC_BUF_SIZE, &Error );
+
+ if ( result < sizeof( QTC_NAME ) || result < (INT)name->size ) {
+ return( QTC_READ_FAILED );
+ }
+
+ // Zero terminate name
+
+ dirname[ (name->size - name->xtra_size - sizeof( QTC_NAME )) / sizeof(CHAR) ] = 0;
+
+ offset = name->mom_offset;
+
+ // BEFORE
+ // qtc->path[] dirname[]
+ // 01234567890 0123456789
+ // xx0xxx0 yyy0
+ //
+ // AFTER
+ // qtc->path[]
+ // yyy0xx0xxx0
+
+ bytes = qtc->path_size + strsize( dirname );
+
+ QTC_TestPathSize( qtc, bytes );
+ for ( i = qtc->path_size/sizeof(CHAR); i > 0; i-- ) {
+ qtc->path[ i + strlen( dirname ) ] = qtc->path[ i - 1 ];
+ }
+
+ strcpy( qtc->path, dirname );
+ qtc->path_size += strsize( dirname );
+ }
+ }
+
+
+ return( SUCCESS );
+}
+
+
+/*******************
+
+ The user is performing a catalog search call. The search parameters are
+ all set up and the only thing for us to do now is skim through the
+ filenames looking for one that is a match.
+
+********************/
+
+INT QTC_FastSearchForFile( QTC_QUERY_PTR qtc )
+{
+ UINT bytes_left;
+ INT index;
+ QTC_NAME UNALIGNED *name;
+ BYTE buff[ QTC_BUF_SIZE ];
+ BYTE_PTR s;
+ INT Error;
+
+
+ name = ( QTC_NAME *)qtc->buff1;
+
+ while ( TRUE ) {
+
+ s = (BYTE_PTR)name;
+
+ // copy the fixed size part of the structure
+
+ if ( qtc->search_index + sizeof( QTC_NAME ) <= qtc->search_max ) {
+
+ // fast copy, no buffer break
+
+ memcpy( s, &(qtc->buff2[ qtc->search_index ]), sizeof( QTC_NAME ) );
+
+ qtc->search_index += sizeof( QTC_NAME );
+ }
+ else {
+
+ // Slow copy to handle buffer break
+
+ memcpy( s,
+ &(qtc->buff2[ qtc->search_index ]),
+ qtc->search_max - qtc->search_index );
+
+
+ s += qtc->search_max - qtc->search_index;
+
+ bytes_left = sizeof(QTC_NAME) -
+ ( qtc->search_max - qtc->search_index );
+
+ qtc->search_base += qtc->search_max;
+
+ if ( qtc->search_base >= qtc->search_stop ) {
+ return( QTC_NO_MORE );
+ }
+
+ qtc->search_max = (UINT16)min( (INT32)QTC_BUF_SIZE,
+ qtc->search_stop - qtc->search_base );
+
+ QTC_SeekFile( qtc->fh, qtc->search_base );
+
+ qtc->search_max = (UINT16)QTC_ReadFile( qtc->fh, qtc->buff2, (INT)qtc->search_max, &Error );
+
+ if ( qtc->search_max < (UINT16)bytes_left ) {
+ return( QTC_NO_MORE );
+ }
+
+ memcpy( s,
+ &(qtc->buff2[ 0 ]),
+ bytes_left );
+
+ qtc->search_index = (UINT16)bytes_left;
+
+ }
+
+ // See if this file is a match
+
+ s = (BYTE_PTR)name;
+
+ if ( ( qtc->search_size == 0 ) ||
+ ( qtc->search_size == (UINT16)(name->size - name->xtra_size ) ) ) {
+
+ // copy variable sized part of structure, the name which we learned
+ // how long it was from the fixed part we just read in.
+
+ s += sizeof( QTC_NAME );
+
+ if ( (UINT16)( qtc->search_index +
+ (INT)name->size - sizeof(QTC_NAME) ) <= qtc->search_max ) {
+
+ // fast copy name
+
+ memcpy( s,
+ &(qtc->buff2[ qtc->search_index ]),
+ (INT)name->size - sizeof( QTC_NAME ) );
+
+ qtc->search_index += (UINT16)(name->size - sizeof( QTC_NAME ));
+ }
+ else {
+
+ // Slow copy to handle buffer break
+
+ memcpy( s,
+ &(qtc->buff2[ qtc->search_index ]),
+ qtc->search_max - qtc->search_index );
+
+ s += qtc->search_max - qtc->search_index;
+
+ bytes_left = (INT)name->size - sizeof(QTC_NAME) -
+ ( qtc->search_max - qtc->search_index );
+
+ qtc->search_base += qtc->search_max;
+
+ if ( qtc->search_base >= qtc->search_stop ) {
+ return( QTC_NO_MORE );
+ }
+
+ qtc->search_max = (UINT16)min( (INT32)QTC_BUF_SIZE,
+ qtc->search_stop - qtc->search_base );
+
+ QTC_SeekFile( qtc->fh, qtc->search_base );
+
+ qtc->search_max = (UINT16)QTC_ReadFile( qtc->fh, qtc->buff2, (INT)qtc->search_max, &Error );
+
+ if ( qtc->search_max < (UINT16)bytes_left ) {
+ return( QTC_NO_MORE );
+ }
+
+ memcpy( s,
+ &(qtc->buff2[ 0 ]),
+ bytes_left );
+
+ qtc->search_index = (UINT16)bytes_left;
+
+ }
+
+ s = (BYTE_PTR)name;
+ s += sizeof(QTC_NAME); // point to file name again
+
+ memcpy( buff, s, (INT)name->size - (INT)name->xtra_size - sizeof(QTC_NAME) );
+
+ index = (INT)name->size - (INT)name->xtra_size - sizeof(QTC_NAME);
+ buff[ index ] = 0;
+
+ if ( sizeof(CHAR) != 1 ) {
+ buff[ ++index ] = 0;
+ }
+
+ if ( ! QTC_TryToMatchFile( qtc, buff ) ) {
+ return( QTC_SUCCESS );
+ }
+ }
+ else {
+
+ // skip over worthless data
+
+ if ( (UINT16)( qtc->search_index +
+ (INT)name->size - sizeof(QTC_NAME) ) <= qtc->search_max ) {
+
+ qtc->search_index += (UINT16)(name->size - sizeof( QTC_NAME ));
+ }
+ else {
+
+ bytes_left = (INT)name->size - sizeof(QTC_NAME) -
+ ( qtc->search_max - qtc->search_index );
+
+ if ( (qtc->search_base + qtc->search_max) >= qtc->search_stop ) {
+ return( QTC_NO_MORE );
+ }
+
+ qtc->search_base += qtc->search_max;
+
+ qtc->search_max = (UINT16)min( (INT32)QTC_BUF_SIZE,
+ qtc->search_stop - qtc->search_base );
+
+ QTC_SeekFile( qtc->fh, qtc->search_base );
+
+ qtc->search_max = (UINT16)QTC_ReadFile( qtc->fh, qtc->buff2, (INT)qtc->search_max, &Error );
+
+ if ( qtc->search_max < (UINT16)bytes_left ) {
+ return( QTC_NO_MORE );
+ }
+
+ qtc->search_index = (UINT16)bytes_left;
+ }
+ }
+ }
+
+ return( QTC_FAILURE );
+}
+
+
+/**********************
+
+ While doing a getfirst/getnext command we ran into the end of media and
+ we want to attempt to move on to the next tape and continue with the
+ same bset.
+
+***********************/
+
+INT QTC_MoveToNextTapeInFamily( QTC_QUERY_PTR qtc )
+{
+ QTC_TAPE_PTR tape;
+ QTC_BSET_PTR bset;
+ QTC_TAPE_PTR best_tape = NULL;
+ INT tape_seq_num = 0;
+
+ // was user picky about sequence number ?
+
+ if ( qtc->tape_seq_num != -1 ) {
+ return( FAILURE );
+ }
+
+ free( qtc->header );
+ qtc->header = NULL;
+
+ // close the old file if it's open
+
+ if ( qtc->file_open ) {
+ QTC_CloseFile( qtc->fh );
+ qtc->file_open = FALSE;
+ }
+
+ // Now find a bset that matches it
+
+ tape = QTC_GetFirstTape( );
+
+ while ( tape != NULL ) {
+
+ if ( ( tape->tape_fid == qtc->tape_fid ) &&
+ ( tape->tape_seq_num > (INT16)qtc->bset->tape_seq_num ) ) {
+
+ // Find the lowest numbered tape in this family that's higher
+ // number than the current tape we are using.
+
+ if ( ( best_tape == NULL ) ||
+ ( tape_seq_num > tape->tape_seq_num ) ) {
+
+ tape_seq_num = tape->tape_seq_num;
+ best_tape = tape;
+ }
+ }
+ tape = QTC_GetNextTape( tape );
+ }
+
+ // We have found another member of the same tape family
+
+ if ( best_tape == NULL ) {
+ return( FAILURE );
+ }
+
+ // Now see if the desired set continues on to this tape.
+
+ bset = QTC_GetFirstBset( best_tape );
+
+ while ( bset != NULL ) {
+
+ if ( qtc->bset->bset_num == bset->bset_num ) {
+ break;
+ }
+
+ bset = QTC_GetNextBset( bset );
+ }
+
+ // No known continuation bset
+
+ if ( bset == NULL ) {
+ return( FAILURE );
+ }
+
+ qtc->header = QTC_LoadHeader( bset );
+
+ if ( qtc->header == NULL ) {
+ return( QTC_NO_HEADER );
+ }
+
+ // Open the file
+
+ qtc->fh = QTC_OpenFile( bset->tape_fid, (INT16)bset->tape_seq_num, FALSE, FALSE );
+
+ if ( qtc->fh < 0 ) {
+ return( FAILURE );
+ }
+
+ qtc->bset = bset;
+
+ qtc->file_open = TRUE;
+
+ return( SUCCESS );
+}
+
+/**********************
+
+ Get us all the entries for a bset
+
+***********************/
+
+INT QTC_GetFirstItem(
+QTC_QUERY_PTR qtc ) // I - query structure to use
+{
+
+ if ( gb_QTC.inited != QTC_MAGIC_NUMBER ) {
+ return( QTC_NO_INIT );
+ }
+
+ if ( qtc->file_open ) {
+ QTC_CloseFile( qtc->fh );
+ qtc->file_open = FALSE;
+ }
+
+ free( qtc->header );
+ qtc->header = NULL;
+
+ qtc->last_path_size = 0;
+
+ // Now find a bset that matches it
+
+ qtc->bset = QTC_GetBsetForSrch( qtc );
+
+ if ( qtc->bset == NULL ) {
+ // So sorry, never heard of that bset
+ return( QTC_BSET_NOT_FOUND );
+ }
+
+ qtc->header = QTC_LoadHeader( qtc->bset );
+
+ if ( qtc->header == NULL ) {
+ return( QTC_NO_HEADER );
+ }
+
+ // Open data file for bset
+
+ qtc->fh = QTC_OpenFile( qtc->bset->tape_fid, (INT16)qtc->bset->tape_seq_num, FALSE, FALSE );
+
+ if ( qtc->fh < 0 ) {
+ return( QTC_OPEN_FAILED );
+ }
+
+ qtc->file_open = TRUE;
+
+ // Set up the record number to return next
+
+ qtc->record_number = 0L;
+
+ return( QTC_GetNextItem( qtc ) );
+
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT QTC_GetNextItem(
+QTC_QUERY_PTR qtc ) // I - query structure to use
+{
+ BYTE_PTR s;
+ QTC_NAME UNALIGNED * name;
+ QTC_RECORD record;
+ INT limit;
+ INT i, j;
+ INT size;
+ INT Error;
+ INT BytesNeeded;
+ UINT32 msw_size = 0L;
+
+ name = (QTC_NAME UNALIGNED *)qtc->buff1;
+
+ if ( ! qtc->file_open ) {
+ return( QTC_NO_MORE );
+ }
+
+ do {
+
+ if ( qtc->record_number * sizeof( QTC_RECORD ) < qtc->header->rec_size ) {
+
+ QTC_SeekFile( qtc->fh, qtc->header->rec_start + ( qtc->record_number * sizeof( QTC_RECORD ) ) );
+
+ if ( QTC_ReadFile( qtc->fh, (BYTE_PTR)&record, sizeof( QTC_RECORD ), &Error ) == sizeof( QTC_RECORD ) ) {
+
+ if ( record.status & QTC_DIRECTORY ) {
+
+ // read in a directory name item
+
+ QTC_SeekFile( qtc->fh, qtc->header->dir_start + record.name_offset );
+
+ limit = QTC_ReadFile( qtc->fh, qtc->buff2, QTC_BUF_SIZE, &Error );
+ limit = (INT)min( (LONG)limit, (LONG)(qtc->header->dir_size - record.name_offset) );
+ if ( ! QTC_GetNameFromBuff( qtc->buff2, name, limit ) ) {
+ break;
+ }
+ }
+ else {
+
+ // read in a file name item
+
+ QTC_SeekFile( qtc->fh, qtc->header->fil_start + record.name_offset );
+
+ limit = QTC_ReadFile( qtc->fh, qtc->buff2, QTC_BUF_SIZE, &Error );
+ limit = (INT)min( (LONG)limit, (LONG)(qtc->header->fil_size - record.name_offset) );
+ if ( ! QTC_GetNameFromBuff( qtc->buff2, name, limit ) ) {
+ break;
+ }
+ }
+ }
+ }
+
+ if ( QTC_MoveToNextTapeInFamily( qtc ) != SUCCESS ) {
+ return( QTC_NO_MORE );
+ }
+
+ // We've changed backup sets, so reset buffer.
+
+ qtc->data_index = 0;
+ qtc->data_max = 0;
+
+ } while ( TRUE );
+
+ // next time get the next record
+
+ qtc->record_number++;
+
+ // Fill in results for application layer
+
+ // Item name
+
+ s = (BYTE_PTR)name;
+ s += sizeof( QTC_NAME );
+
+ size = (INT)name->size - (INT)name->xtra_size - sizeof( QTC_NAME );
+
+ QTC_TestItemSize( qtc, size + sizeof(CHAR) );
+ memcpy( qtc->item, s, size );
+ qtc->item[ size / sizeof(CHAR) ] = TEXT( '\0' );
+
+ // Item xtra bytes
+
+ s += name->size - (INT)name->xtra_size - sizeof( QTC_NAME );
+ memcpy( qtc->xtra_bytes, s, (INT)name->xtra_size );
+ qtc->xtra_size = (INT8)name->xtra_size;
+
+ for ( i = 0; i < qtc->xtra_size; i += 5 ) {
+ if ( qtc->xtra_bytes[ i ] == QTC_XTRA_64BIT_SIZE ) {
+ memcpy( &msw_size, &qtc->xtra_bytes[ i + 1 ] , 4 );
+ }
+ }
+
+ // Record data
+
+ qtc->status = (UINT8)record.status;
+ qtc->date = (INT16)record.date;
+ qtc->time = (INT16)record.time;
+ qtc->attrib = record.attribute;
+ qtc->lba = record.lba;
+
+ if ( qtc->status & QTC_FILE ) {
+ qtc->size = U64_Init( record.common.size, msw_size );
+ }
+ else {
+
+ qtc->size = U64_Init( record.common.common.height, 0L );
+
+ QTC_TestPathSize( qtc, qtc->last_path_size );
+ memcpy( qtc->path, qtc->last_path, qtc->last_path_size );
+
+ i = 1;
+ j = 0;
+
+ while ( i < (INT)U64_Lsw( qtc->size ) ) {
+
+ while ( qtc->path[ j++ ] );
+ i++;
+ }
+
+ qtc->path_size = j * sizeof (CHAR);
+
+ if ( U64_Lsw( qtc->size ) < 2 ) {
+ QTC_TestPathSize( qtc, sizeof(CHAR) );
+ qtc->path[ 0 ] = TEXT( '\0' );
+ qtc->path_size = sizeof(CHAR);
+ }
+
+ QTC_TestLastPathSize( qtc, qtc->path_size );
+ memcpy( qtc->last_path, qtc->path, qtc->path_size );
+
+ BytesNeeded = strsize( qtc->item ) + (j * sizeof(CHAR));
+ QTC_TestLastPathSize( qtc, BytesNeeded );
+ strcpy( &qtc->last_path[ j ], qtc->item );
+
+ qtc->last_path_size = BytesNeeded;
+
+ QTC_SetFileCounts( qtc );
+ }
+
+ return( QTC_SUCCESS );
+}
+
+/**********************
+
+ Get us all the directory entries for a bset
+
+***********************/
+
+INT QTC_GetFirstDir(
+QTC_QUERY_PTR qtc ) // I - query structure to use
+{
+
+ if ( gb_QTC.inited != QTC_MAGIC_NUMBER ) {
+ return( QTC_NO_INIT );
+ }
+
+ if ( qtc->file_open ) {
+ QTC_CloseFile( qtc->fh );
+ qtc->file_open = FALSE;
+ }
+
+ free( qtc->header );
+ qtc->header = NULL;
+
+ qtc->last_path_size = 0;
+
+ // Now find a bset that matches it
+
+ qtc->bset = QTC_GetBsetForSrch( qtc );
+
+ if ( qtc->bset == NULL ) {
+ // So sorry, never heard of that bset
+ return( QTC_BSET_NOT_FOUND );
+ }
+
+ qtc->header = QTC_LoadHeader( qtc->bset );
+
+ if ( qtc->header == NULL ) {
+ return( QTC_NO_HEADER );
+ }
+
+ // Open data file for bset
+
+ qtc->fh = QTC_OpenFile( qtc->bset->tape_fid, (INT16)qtc->bset->tape_seq_num, FALSE, FALSE );
+
+ if ( qtc->fh < 0 ) {
+ return( QTC_OPEN_FAILED );
+ }
+
+ qtc->file_open = TRUE;
+
+ // Set up our buffer stuff
+
+ qtc->dir_offset = qtc->header->dir_start;
+
+ qtc->data_index = 0;
+ qtc->data_max = 0;
+
+ return( QTC_GetNextDir( qtc ) );
+
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT QTC_GetNextDir(
+QTC_QUERY_PTR qtc ) // I - query structure to use
+{
+ BYTE_PTR s;
+ QTC_NAME UNALIGNED * name;
+ QTC_RECORD record;
+ INT i, j;
+ INT size;
+ INT BytesNeeded;
+ UINT32 msw_size = 0L;
+
+
+ if ( ! qtc->file_open ) {
+ return( QTC_NO_MORE );
+ }
+
+ do {
+
+ name = QTC_GetNextItemFromBuffer( qtc, &record, BUFF_DIR );
+
+ if ( name ) {
+ break;
+ }
+
+ if ( QTC_MoveToNextTapeInFamily( qtc ) != SUCCESS ) {
+ return( QTC_NO_MORE );
+ }
+
+ // We've changed backup sets, so reset buffer.
+
+ qtc->dir_offset = qtc->header->dir_start;
+ qtc->data_index = 0;
+ qtc->data_max = 0;
+
+ } while ( TRUE );
+
+ // Fill in results for application layer
+
+ // Item name
+
+ s = (BYTE_PTR)name;
+ s += sizeof( QTC_NAME );
+
+ size = (INT)name->size - (INT)name->xtra_size - sizeof( QTC_NAME );
+
+ QTC_TestItemSize( qtc, size + sizeof(CHAR) );
+ memcpy( qtc->item, s, size );
+ qtc->item[ size / sizeof(CHAR) ] = TEXT( '\0' );
+
+ // Item xtra bytes
+
+ s += name->size - (INT)name->xtra_size - sizeof( QTC_NAME );
+ memcpy( qtc->xtra_bytes, s, (INT)name->xtra_size );
+ qtc->xtra_size = (INT8)name->xtra_size;
+
+ for ( i = 0; i < qtc->xtra_size; i += 5 ) {
+ if ( qtc->xtra_bytes[ i ] == QTC_XTRA_64BIT_SIZE ) {
+ memcpy( &msw_size, &qtc->xtra_bytes[ i + 1 ] , 4 );
+ }
+ }
+
+ // Record data
+
+ qtc->status = (UINT8)record.status;
+ qtc->date = (INT16)record.date;
+ qtc->time = (INT16)record.time;
+ qtc->attrib = record.attribute;
+ qtc->size = U64_Init( record.common.common.height, msw_size );
+ qtc->lba = record.lba;
+
+ QTC_TestPathSize( qtc, qtc->last_path_size );
+ memcpy( qtc->path, qtc->last_path, qtc->last_path_size );
+
+ i = 1;
+ j = 0;
+
+ while ( i < (INT)U64_Lsw( qtc->size ) ) {
+
+ while ( qtc->path[ j++ ] );
+ i++;
+ }
+
+ qtc->path_size = j * sizeof (CHAR);
+
+ if ( U64_Lsw( qtc->size ) < 2 ) {
+ QTC_TestPathSize( qtc, sizeof(CHAR) );
+ qtc->path[ 0 ] = TEXT( '\0' );
+ qtc->path_size = sizeof(CHAR);
+ }
+
+
+ BytesNeeded = strsize( qtc->item ) + ( j * sizeof(CHAR) );
+ QTC_TestLastPathSize( qtc, BytesNeeded );
+ memcpy( qtc->last_path, qtc->path, qtc->path_size );
+ strcpy( &qtc->last_path[ j ], qtc->item );
+
+ qtc->last_path_size = BytesNeeded;
+
+ QTC_SetFileCounts( qtc );
+ return( QTC_SUCCESS );
+}
+
+/*************
+
+ The data[] buffer contains info from a name file, with a name record
+ starting at byte 0. Limit is the size of good data in the buffer.
+ name points to not only a name structure, but also has space for the
+ name to be placed in memory after it. This routine will fill in the
+ name structure for you.
+
+***************/
+
+
+INT QTC_GetNameFromBuff(
+BYTE_PTR data, // I - source of data
+QTC_NAME UNALIGNED *name, // O - name structure to fill in
+INT limit ) // I - how much data is available
+{
+ if ( limit < sizeof( QTC_NAME ) ) {
+ return( QTC_NO_MORE );
+ }
+
+ // Copy fixed size of structure
+
+ memcpy( (BYTE *)name, data, sizeof( QTC_NAME ) );
+
+ // Now get variable size of structure from fixed part
+
+ if ( name->size > (INT16)limit ) {
+ return( QTC_NO_MORE );
+ }
+
+ memcpy( (BYTE *)name, data, (INT)name->size );
+
+ return( QTC_SUCCESS );
+}
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+QTC_NAME UNALIGNED * QTC_GetNextItemFromBuffer(
+QTC_QUERY_PTR qtc,
+QTC_RECORD_PTR record,
+INT buff_type )
+{
+ BOOLEAN buffer_needs_refilling;
+ QTC_NAME UNALIGNED *name;
+ INT limit;
+ INT32 data_left;
+ INT Error;
+
+ if ( qtc->data_max >= (INT)sizeof( QTC_NAME ) + qtc->data_index ) {
+
+ name = (QTC_NAME UNALIGNED *)&qtc->buff2[ qtc->data_index ];
+
+ if ( qtc->data_max - qtc->data_index < (INT)name->size ) {
+
+ buffer_needs_refilling = TRUE;
+ }
+
+ }
+ else {
+
+ buffer_needs_refilling = TRUE;
+ }
+
+ if ( buffer_needs_refilling ) {
+
+ buffer_needs_refilling = FALSE;
+
+ name = (QTC_NAME UNALIGNED *)qtc->buff2;
+
+ switch ( buff_type ) {
+
+ case BUFF_DIR:
+
+ qtc->dir_offset += qtc->data_index;
+
+ QTC_SeekFile( qtc->fh, qtc->dir_offset );
+
+ data_left = qtc->header->dir_start + qtc->header->dir_size;
+ data_left -= qtc->dir_offset;
+ break;
+
+ case BUFF_FILE:
+ qtc->fil_offset += qtc->data_index;
+
+ QTC_SeekFile( qtc->fh, qtc->fil_offset );
+
+ data_left = qtc->header->fil_start + qtc->header->fil_size;
+ data_left -= qtc->fil_offset;
+ break;
+
+ case BUFF_CHILD_DIR:
+
+ qtc->fil_dir_offset += qtc->data_index;
+
+ QTC_SeekFile( qtc->fh, qtc->fil_dir_offset );
+
+ data_left = qtc->header->dir_start + qtc->header->dir_size;
+ data_left -= qtc->fil_dir_offset;
+ break;
+
+ default:
+ return( NULL );
+
+ }
+
+ limit = (INT)min( (INT32)QTC_BUF_SIZE, data_left );
+
+ qtc->data_max = QTC_ReadFile( qtc->fh, qtc->buff2, limit, &Error );
+
+ if ( qtc->data_max == -1 ) {
+
+ // Read error
+ return( NULL );
+ }
+
+ qtc->data_index = 0;
+
+ if ( qtc->data_max < sizeof( QTC_NAME ) ) {
+ buffer_needs_refilling = TRUE;
+ }
+ else {
+
+ if ( qtc->data_max - qtc->data_index < (INT)name->size ) {
+
+ buffer_needs_refilling = TRUE;
+ }
+ }
+ }
+
+ if ( ! buffer_needs_refilling ) {
+
+ // We have enough good data to return a solution.
+
+ QTC_SeekFile( qtc->fh, qtc->header->rec_start + (name->record * sizeof( QTC_RECORD)) );
+
+ if ( QTC_ReadFile( qtc->fh, (BYTE_PTR)record, sizeof( QTC_RECORD ), &Error ) != sizeof( QTC_RECORD ) ) {
+
+ return( NULL );
+ }
+
+ qtc->data_index += (INT)name->size; // bump our buffer index
+
+ }
+ else {
+ return( NULL );
+ }
+
+ return( (QTC_NAME UNALIGNED *)name );
+}
+
+// if we do find a duplicate directory path after all the files in the
+// current directory are returned, then we set everything up for the
+// next call and return QTC_TRY_AGAIN.
+
+INT QTC_GetFirstObj(
+QTC_QUERY_PTR qtc ) // I - query structure to use
+{
+ QTC_RECORD record;
+ QTC_TAPE_PTR tape;
+ QTC_BSET_PTR temp_bset;
+
+ if ( gb_QTC.inited != QTC_MAGIC_NUMBER ) {
+ return( QTC_NO_INIT );
+ }
+
+ if ( qtc->file_open ) {
+ QTC_CloseFile( qtc->fh );
+ qtc->file_open = FALSE;
+ }
+ // Now find a bset that matches it
+
+ tape = QTC_GetFirstTape( );
+
+ temp_bset = NULL;
+ qtc->bset = NULL;
+
+ while ( tape != NULL ) {
+
+ if ( ( tape->tape_fid == qtc->tape_fid ) &&
+ ( tape->tape_seq_num == qtc->tape_seq_num ) ) {
+
+ qtc->bset = QTC_GetFirstBset( tape );
+
+ while ( qtc->bset != NULL ) {
+
+ if ( qtc->bset->bset_num == qtc->bset_num ) {
+ if ( ! ( qtc->bset->status & ( QTC_PARTIAL | QTC_IMAGE ) ) ) {
+ break;
+ }
+ }
+ qtc->bset = QTC_GetNextBset( qtc->bset );
+ }
+ break;
+ }
+ else {
+
+ if ( ( tape->tape_fid == qtc->tape_fid ) &&
+ ( qtc->tape_seq_num == -1 ) ) {
+
+ temp_bset = QTC_GetFirstBset( tape );
+
+ while ( temp_bset != NULL ) {
+
+ if ( temp_bset->bset_num == qtc->bset_num ) {
+
+ if ( ! ( temp_bset->status & ( QTC_PARTIAL | QTC_IMAGE ) ) ) {
+ if ( qtc->bset == NULL ) {
+ qtc->bset = temp_bset;
+ }
+
+ if ( qtc->bset->tape_seq_num > temp_bset->tape_seq_num ) {
+
+ qtc->bset = temp_bset;
+ }
+ }
+ }
+ temp_bset = QTC_GetNextBset( temp_bset );
+ }
+ }
+ }
+
+ tape = QTC_GetNextTape( tape );
+ }
+
+ if ( qtc->bset == NULL ) {
+ return( QTC_BSET_NOT_FOUND );
+ }
+
+ qtc->header = QTC_LoadHeader( qtc->bset );
+ if ( qtc->header == NULL ) {
+ return( QTC_NO_HEADER );
+ }
+
+ qtc->fh = QTC_OpenFile( qtc->bset->tape_fid, (INT16)qtc->bset->tape_seq_num, FALSE, FALSE );
+
+ if ( qtc->fh < 0 ) {
+ return( QTC_OPEN_FAILED );
+ }
+
+ // Copy search path to reply path, it won't change
+
+ QTC_TestPathSize( qtc, qtc->search_path_size );
+ memcpy( qtc->path, qtc->search_path, qtc->search_path_size );
+ qtc->path_size = qtc->search_path_size;
+
+ qtc->file_open = TRUE;
+
+ // Attempt to find the requested path on all the tapes this
+ // bset is on.
+
+ do {
+
+ qtc->fil_dir_offset = 0;
+
+ if ( QTC_FindDirRec( qtc, &record ) == SUCCESS ) {
+
+ // We found the path, set up for FindNextObj.
+
+ qtc->fil_offset = record.common.common.file_start + qtc->header->fil_start;
+ qtc->curr_mom_offset = qtc->header->dir_start + record.name_offset;
+
+ qtc->data_index = 0;
+ qtc->data_max = 0;
+
+ return( QTC_GetNextObj( qtc ) );
+ }
+
+ } while ( QTC_MoveToNextTapeInFamily( qtc ) == SUCCESS );
+
+ // Requested path doesn't exist in catalogs.
+
+
+ return( QTC_NO_MORE );
+}
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT QTC_GetNextObj(
+QTC_QUERY_PTR qtc ) // I - query structure to use
+{
+ BOOLEAN done = FALSE;
+ QTC_RECORD record;
+
+
+ if ( ! qtc->file_open ) {
+ return( QTC_NO_MORE );
+ }
+
+ while ( ! done ) {
+
+ if ( QTC_TryToLocateFile( qtc ) == SUCCESS ) {
+ QTC_SetFileCounts( qtc );
+ return( SUCCESS );
+ }
+
+ if ( QTC_LookForChildDirs( qtc ) == SUCCESS ) {
+ QTC_SetFileCounts( qtc );
+ return( SUCCESS );
+ }
+
+ // Try for a duplicate directory.
+
+ qtc->fil_dir_offset = 0;
+
+ if ( QTC_FindNextDirRec( qtc, &record ) == SUCCESS ) {
+
+ // We found a new duplicate path, go to top loop again.
+
+ // Set up for FindNextObj.
+
+ qtc->fil_offset = record.common.common.file_start + qtc->header->fil_start;
+ qtc->curr_mom_offset = qtc->header->dir_start + record.name_offset;
+
+ qtc->data_index = 0;
+ qtc->data_max = 0;
+
+ continue;
+ }
+
+ // Everything has failed on this tape, try for a new one.
+
+ done = TRUE;
+
+ while ( QTC_MoveToNextTapeInFamily( qtc ) == SUCCESS ) {
+
+ qtc->fil_dir_offset = 0;
+
+ if ( QTC_FindDirRec( qtc, &record ) == SUCCESS ) {
+
+ // We found a new duplicate path, go to top loop again.
+
+ // Set up for FindNextObj.
+
+ qtc->fil_offset = record.common.common.file_start + qtc->header->fil_start;
+ qtc->curr_mom_offset = qtc->header->dir_start + record.name_offset;
+
+ qtc->data_index = 0;
+ qtc->data_max = 0;
+
+ done = FALSE;
+ break;
+ }
+ }
+
+ }
+
+
+ return( QTC_NO_MORE );
+}
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT QTC_TryToLocateFile(
+QTC_QUERY_PTR qtc )
+{
+ INT bytes;
+ INT i;
+ UINT32 msw_size = 0L;
+ BYTE_PTR s;
+ QTC_NAME UNALIGNED * name;
+ QTC_RECORD record;
+
+
+ do {
+
+ if ( qtc->fil_dir_offset ) {
+ return( FAILURE );
+ }
+
+ name = QTC_GetNextItemFromBuffer( qtc, &record, BUFF_FILE );
+
+ // No more files
+
+ if ( name == NULL ) {
+ return( FAILURE );
+ }
+
+ // No more files in this directory
+
+ if ( (qtc->header->dir_start + name->mom_offset) != qtc->curr_mom_offset ) {
+ return( FAILURE );
+ }
+
+ s = (BYTE_PTR)name;
+ s += sizeof( QTC_NAME );
+
+ // Item name
+
+ bytes = (INT)name->size - (INT)name->xtra_size - sizeof( QTC_NAME );
+
+ QTC_TestItemSize( qtc, bytes + 1 );
+ memcpy( qtc->item, s, bytes );
+ qtc->item[ bytes/sizeof (CHAR) ] = TEXT( '\0' );
+
+ } while ( QTC_TryToMatchFile( qtc, (BYTE_PTR)qtc->item ) );
+
+ // Item xtra bytes
+
+ s += name->size - (INT)name->xtra_size - sizeof( QTC_NAME );
+ memcpy( qtc->xtra_bytes, s, (INT)name->xtra_size );
+ qtc->xtra_size = (UINT8)name->xtra_size;
+
+ for ( i = 0; i < qtc->xtra_size; i += 5 ) {
+ if ( qtc->xtra_bytes[ i ] == QTC_XTRA_64BIT_SIZE ) {
+ memcpy( &msw_size, &qtc->xtra_bytes[ i + 1 ] , 4 );
+ }
+ }
+
+ // Record data
+
+ qtc->status = (UINT8)record.status;
+ qtc->date = (INT16)record.date;
+ qtc->time = (INT16)record.time;
+ qtc->attrib = record.attribute;
+ qtc->size = U64_Init( record.common.size, msw_size );
+ qtc->lba = record.lba;
+
+ QTC_SetFileCounts( qtc );
+
+ return( SUCCESS );
+}
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ Given the qtc->curr_mom_offset, look for any children directories, using
+ qtc->fil_dir_offset as a base and stop at bset->dir_start + bset->dir_size;
+
+********************/
+
+INT QTC_LookForChildDirs(
+QTC_QUERY_PTR qtc )
+{
+ QTC_RECORD record;
+ QTC_NAME UNALIGNED *name;
+ BYTE_PTR s;
+ UINT32 msw_size = 0L;
+ INT ret;
+ INT i;
+ INT bytes;
+ INT Error;
+
+
+ name = ( QTC_NAME UNALIGNED *)qtc->buff1;
+
+ if ( qtc->fil_dir_offset == 0 ) {
+
+ qtc->fil_dir_offset = qtc->curr_mom_offset;
+ qtc->data_index = 0;
+ qtc->data_max = 0;
+
+ /** skip over parent **/
+
+ QTC_SeekFile( qtc->fh, qtc->fil_dir_offset );
+
+ ret = QTC_ReadFile( qtc->fh, (BYTE_PTR)name, sizeof( QTC_NAME), &Error );
+
+ if ( ret != sizeof( QTC_NAME ) ) {
+ return( FAILURE );
+ }
+
+ qtc->fil_dir_offset += name->size;
+ }
+
+ do {
+
+ name = QTC_GetNextItemFromBuffer( qtc, &record, BUFF_CHILD_DIR );
+
+ if ( name == NULL ) {
+ return( FAILURE );
+ }
+
+ // Once we find an older parent's kids,
+ // we will never hit any more of this guys.
+
+ if ( qtc->header->dir_start + name->mom_offset < qtc->curr_mom_offset ) {
+ return( FAILURE );
+ }
+
+ // Keep skipping over younger children.
+
+ } while ( qtc->header->dir_start + name->mom_offset != qtc->curr_mom_offset );
+
+ // Item name
+
+ s = (BYTE_PTR)name;
+ s += sizeof( QTC_NAME );
+ bytes = (INT)name->size - (INT)name->xtra_size - sizeof( QTC_NAME );
+ QTC_TestItemSize( qtc, bytes + 1 );
+ memcpy( qtc->item, s, bytes );
+ qtc->item[ bytes / sizeof (CHAR) ] = TEXT( '\0' );
+
+ // Item xtra bytes
+
+ s += name->size - (INT)name->xtra_size - sizeof( QTC_NAME );
+ memcpy( qtc->xtra_bytes, s, (INT)name->xtra_size );
+ qtc->xtra_size = (INT8)name->xtra_size;
+
+ for ( i = 0; i < qtc->xtra_size; i += 5 ) {
+ if ( qtc->xtra_bytes[ i ] == QTC_XTRA_64BIT_SIZE ) {
+ memcpy( &msw_size, &qtc->xtra_bytes[ i + 1 ] , 4 );
+ }
+ }
+
+ // Record data
+
+ qtc->status = (UINT8)record.status;
+ qtc->date = (INT16)record.date;
+ qtc->time = (INT16)record.time;
+ qtc->attrib = record.attribute;
+ qtc->size = U64_Init( record.common.common.height, msw_size );
+ qtc->lba = record.lba;
+ QTC_SetFileCounts( qtc );
+
+ return( SUCCESS );
+
+}
+
+
+
+
+/**************
+
+ Given the path in qtc fill in the record structure for the last
+ subdirectory in the path.
+ Also fill in the dir_rec_offsets[] array;
+
+ ex. \DOS\GAMES\TETRIS
+
+ fills in the record structure for TETRIS.
+
+****************/
+
+INT QTC_FindDirRec(
+QTC_QUERY_PTR qtc, // I - use the path in this structure
+QTC_RECORD_PTR record ) // O - the record for the deepest dir in path
+{
+ // start looking at the start of the directory data
+
+ return( QTC_FindDirectoryPath( qtc, record, qtc->header->dir_start, TRUE ) );
+}
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ We have been asked to find yet another matching path. The success of
+ this function call is dependent on there being duplicate directories
+ in the catalog. This DOES happen with the \SYSTEM directory on
+ NOVELL servers if security stuff is backed up.
+
+ qtc->curr_mom_offset is the current directory tail.
+
+ RETURNS :
+
+**********************/
+
+INT QTC_FindNextDirRec(
+QTC_QUERY_PTR qtc, // I - use the path in this structure
+QTC_RECORD_PTR record ) // O - the record for the deepest dir in path
+{
+ UINT32 curr_try_offset; // current offset in the directory names
+ QTC_NAME UNALIGNED * name;
+ INT Error;
+
+ name = (QTC_NAME UNALIGNED *)qtc->buff1;
+
+ // Determine the offset we wish to find a child from. Use the mom
+ // offset of the current directory at qtc->curr_mom_offset.
+
+ QTC_SeekFile( qtc->fh, qtc->curr_mom_offset );
+
+ if ( QTC_ReadFile( qtc->fh, (BYTE_PTR)name, sizeof( QTC_NAME ), &Error ) != sizeof( QTC_NAME ) ) {
+ return( FAILURE );
+ }
+
+ // Determine the offset in the directory data to start looking at.
+ // It should be the entry immediately after qtc->curr_mom_offset.
+
+ curr_try_offset = qtc->curr_mom_offset + name->size;
+
+ return( QTC_FindDirectoryPath( qtc, record, curr_try_offset, FALSE ) );
+}
+
+
+
+/**********************
+
+ NAME :
+
+ QTC_FindDirectoryPath
+
+ DESCRIPTION :
+
+ Called by QTC_FindDirRec() and QTC_FindNextDirRec() to find out if
+ a path exists in the current backup set. It returns the record for
+ the last directory entry in the path, if successful.
+
+ RETURNS :
+
+ SUCCESS/FAILURE
+
+**********************/
+
+static INT QTC_FindDirectoryPath(
+QTC_QUERY_PTR qtc, // I - use the path in this structure
+QTC_RECORD_PTR record, // O - the record for the deepest dir in path
+UINT32 curr_try_offset,
+INT start_at_root )
+{
+ QTC_NAME UNALIGNED *name;
+ INT current_level;
+ INT final_level;
+ INT new_level;
+ INT i;
+ INT Error;
+ INT init = TRUE;
+ CHAR *dir_name;
+ BYTE *s;
+ UINT32 dir_max;
+ UINT32 offset;
+
+ name = (QTC_NAME UNALIGNED *)qtc->buff1;
+
+ // Stop looking at the end of the directory data
+
+ dir_max = qtc->header->dir_start + qtc->header->dir_size;
+
+ // Uuse buff1 to store the temp results in
+
+ name = ( QTC_NAME *)qtc->buff1;
+
+ s = (BYTE_PTR)name;
+ s += sizeof( QTC_NAME );
+
+ // Determine depth of this path
+
+ final_level = 1;
+
+ if ( qtc->search_path_size > sizeof(CHAR) ) {
+ for ( i = 0; i < (INT)( qtc->search_path_size / sizeof(CHAR) ); i++ ) {
+ if ( qtc->search_path[i] == TEXT('\0') ) {
+ final_level++;
+ }
+ }
+ }
+
+ // example:
+ // for \, final_level = 1
+ // for \dos\games\tetris, final_level = 4
+
+
+ // current_level is the maximum level for which a solution directory
+ // is valid, we may come across a directory at level 6, that
+ // is an exact match for the level 6 name we are looking for,
+ // but if we are currently only working at level 2, then this
+ // new entry has the wrong parent for us to use it.
+
+ if ( start_at_root ) {
+ current_level = 0;
+ }
+ else {
+ current_level = final_level - 1;
+ }
+
+ do {
+
+ // Look for name with mom_offset == last_offset
+
+ if ( QTC_FastSearchForDir( qtc, &curr_try_offset,
+ dir_max, 0, init ) ) {
+
+ // A normal return, we ran out of namespace.
+ return( FAILURE );
+ }
+
+ // Only init once
+
+ if ( init ) {
+ init = FALSE;
+ }
+
+ // See if the directory found matches the name and
+ // height we are looking for.
+
+ // Load the record for this directory. Notice that if this is the
+ // solution directory, than we have loaded it here to return it.
+
+ offset = qtc->header->rec_start;
+ offset += ( name->record * sizeof( QTC_RECORD ) );
+ QTC_SeekFile( qtc->fh, offset );
+
+ if ( QTC_ReadFile( qtc->fh, (BYTE_PTR)record, sizeof( QTC_RECORD ), &Error ) != sizeof( QTC_RECORD ) ) {
+ return( FAILURE );
+ }
+
+ new_level = (INT)record->common.common.height;
+
+ if ( new_level <= current_level ) {
+
+ // Get the name we are looking for at this level.
+
+ dir_name = TEXT(""); // find the root first
+ if ( new_level != 0 ) {
+ dir_name = qtc->search_path;
+ for ( i = 1; i < new_level; i++ ) {
+ while ( *dir_name++ );
+ }
+ }
+
+ // Initialize a pointer to this new entry's name.
+
+ ((CHAR_PTR)s)[ ((INT)name->size - (INT)name->xtra_size - sizeof( QTC_NAME ))/ sizeof (CHAR) ] = TEXT ('\0');
+
+ if ( ! stricmp( (CHAR_PTR)s, dir_name ) ) {
+
+ // We matched at this level, move down one deeper.
+
+ current_level = new_level + 1;
+ }
+ else {
+ current_level = new_level;
+ }
+
+ }
+
+ // We are done as soon as this we need to look one deeper than
+ // what our goal was.
+
+ } while ( current_level < final_level );
+
+ return( SUCCESS );
+
+}
+
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ Starting at offset in the directory name file, this routine will look
+ for an entry with size == requested_size. Max is the ending offset
+ for data to be searched, usually the end of this BSET. Init is TRUE
+ if this is the first call. The name structure will
+ be filled in with the answer for you. If requested_size == 0, it
+ returns the first one found.
+
+******************/
+
+INT QTC_FastSearchForDir(
+QTC_QUERY_PTR qtc, // I - query structure to use
+UINT32_PTR offset, // I/O - file offset to start/finished at
+UINT32 max, // I - how far from offset can we look
+INT requested_size, // I - size of requested name
+INT init ) // I - is this the first call
+{
+ UINT bytes_left;
+ INT Error;
+ QTC_NAME UNALIGNED * name;
+ BYTE_PTR s;
+
+
+ name = (QTC_NAME UNALIGNED *)qtc->buff1;
+
+ if ( init ) {
+ qtc->search_index = 0;
+ qtc->search_max = 0;
+ qtc->search_base = *offset;
+ QTC_SeekFile( qtc->fh, *offset );
+ }
+
+ /** find dir name in dir names **/
+
+ while ( TRUE ) {
+
+ *offset = qtc->search_base + (UINT32)qtc->search_index;
+
+ s = (BYTE_PTR)name;
+
+ // copy structure
+
+ if ( qtc->search_index + sizeof( QTC_NAME ) <= qtc->search_max ) {
+
+ memcpy( s, &(qtc->buff2[ qtc->search_index ]), sizeof( QTC_NAME ) );
+ qtc->search_index += sizeof( QTC_NAME );
+ }
+ else {
+
+ // Slow copy to handle buffer break
+
+ memcpy( s,
+ &(qtc->buff2[ qtc->search_index ]),
+ qtc->search_max - qtc->search_index );
+
+
+ s += qtc->search_max - qtc->search_index;
+
+ bytes_left = sizeof(QTC_NAME) - ( qtc->search_max - qtc->search_index );
+
+ if ( (qtc->search_base + qtc->search_max) >= max ) {
+ return( QTC_NO_MORE );
+ }
+
+ qtc->search_base += qtc->search_max;
+
+ qtc->search_max = (UINT16)min( (INT32)QTC_BUF_SIZE, max - qtc->search_base );
+
+ QTC_SeekFile( qtc->fh, qtc->search_base );
+
+ qtc->search_max = (UINT16)QTC_ReadFile( qtc->fh, qtc->buff2, (INT)qtc->search_max, &Error );
+
+ if ( qtc->search_max < (UINT16)bytes_left ) {
+ return( QTC_NO_MORE );
+ }
+
+ memcpy( s, &(qtc->buff2[ 0 ]), bytes_left );
+
+ qtc->search_index = (UINT16)bytes_left;
+
+ s = (BYTE_PTR)name;
+ }
+
+ if ( ( requested_size == (INT)name->size - (INT)name->xtra_size ) ||
+ ( requested_size == 0 ) ) {
+
+ // Copy variable sized name part,
+ // we are going to return this entry.
+
+ s += sizeof( QTC_NAME );
+
+ if ( ( qtc->search_index +
+ (INT16)name->size - sizeof(QTC_NAME) ) <= qtc->search_max ) {
+
+ memcpy( s,
+ &(qtc->buff2[ qtc->search_index ]),
+ (INT)name->size - sizeof( QTC_NAME ) );
+
+ qtc->search_index += (UINT16)(name->size - sizeof( QTC_NAME ));
+ }
+ else {
+
+ // Slow copy to handle buffer break
+
+ memcpy( s,
+ &(qtc->buff2[ qtc->search_index ]),
+ (INT)name->size - sizeof(QTC_NAME) );
+
+ s += qtc->search_max - qtc->search_index;
+
+ bytes_left = (INT)name->size - sizeof(QTC_NAME) - ( qtc->search_max - qtc->search_index );
+
+ qtc->search_base += qtc->search_max;
+
+ if ( qtc->search_base >= max ) {
+ return( QTC_NO_MORE );
+ }
+
+ qtc->search_max = (UINT16)min( (INT32)QTC_BUF_SIZE, max - qtc->search_base );
+
+ QTC_SeekFile( qtc->fh, qtc->search_base );
+
+ qtc->search_max = (UINT16)QTC_ReadFile( qtc->fh, qtc->buff2, (INT)qtc->search_max, &Error );
+
+ if ( qtc->search_max < (UINT16)bytes_left ) {
+ return( QTC_NO_MORE );
+ }
+
+ memcpy( s,
+ &(qtc->buff2[ 0 ]),
+ bytes_left );
+
+ qtc->search_index = (UINT16)bytes_left;
+
+ }
+
+ return( QTC_SUCCESS );
+ }
+ else {
+
+ // skip worthless data
+
+ if ( (UINT16)( qtc->search_index + (INT)name->size - sizeof(QTC_NAME) ) <= qtc->search_max ) {
+
+ qtc->search_index += (UINT16)(name->size - sizeof( QTC_NAME ));
+ }
+ else {
+
+ bytes_left = (INT)name->size - sizeof(QTC_NAME) - ( qtc->search_max - qtc->search_index );
+
+ qtc->search_base += qtc->search_max;
+
+ if ( qtc->search_base >= max ) {
+ return( QTC_NO_MORE );
+ }
+
+ qtc->search_max = (UINT16)min( (INT32)QTC_BUF_SIZE, max - qtc->search_base );
+
+ QTC_SeekFile( qtc->fh, qtc->search_base );
+
+ qtc->search_max = (UINT16)QTC_ReadFile( qtc->fh, qtc->buff2, (INT)qtc->search_max, &Error );
+
+ if ( qtc->search_max < (UINT16)bytes_left ) {
+ return( QTC_NO_MORE );
+ }
+
+ qtc->search_index = (UINT16)bytes_left;
+ }
+
+ }
+
+ }
+
+ return( QTC_FAILURE );
+}
+
+
+/*
+ Here's how this works, to keep up the speed of searches, we created
+ two copies of the name comparison code. One if the bset is ascii,
+ and the other if the bset is unicode. We have two search name fields
+ already filled in. A one time conversion, to last the entire search.
+*/
+
+INT QTC_TryToMatchFile(
+QTC_QUERY_PTR qtc,
+BYTE_PTR file_name )
+{
+ INT ret = -1;
+
+#ifdef NO_UNICODE
+
+ // The UI has no desire to support anything having to do with unicode.
+
+ if ( ! ( qtc->bset->status & QTC_UNICODE ) ) {
+ ret = QTC_CompNormalNames( (CHAR_PTR)qtc->search_name,
+ (CHAR_PTR)file_name );
+ }
+
+#else
+
+ if ( gb_QTC.unicode ) {
+ ret = QTC_CompUnicodeNames( (WCHAR_PTR)qtc->search_name,
+ (WCHAR_PTR)file_name );
+ }
+ else {
+ ret = QTC_CompAsciiNames( (ACHAR_PTR)qtc->search_name,
+ (ACHAR_PTR)file_name );
+ }
+#endif
+
+ return( ret );
+}
+
+#if defined(NO_UNICODE)
+
+INT QTC_CompNormalNames( CHAR_PTR srch_name, CHAR_PTR file_name )
+{
+ INT pos = 0; /* index for file_name */
+ INT i; /* index for wild_name */
+ INT ret_val = 0;
+ CHAR_PTR p;
+ CHAR save_char;
+ INT ptrn_len;
+
+ pos = 0;
+
+ if ( strcmp( srch_name, "*.*" ) ) {
+
+ for ( i = 0; (srch_name[i] != 0) && (ret_val == 0); i++ ) {
+
+ switch( srch_name[i] ) {
+
+ case '*':
+
+ while ( srch_name[i+1] != 0 ) {
+
+ if ( srch_name[i+1] == '?' ) {
+ if ( file_name[ ++pos ] == 0 ) {
+ break;
+ }
+
+ }
+ else {
+ if ( srch_name[i+1] != '*' ) {
+ break;
+ }
+ }
+ i++;
+ }
+
+ p = strpbrk( &srch_name[i+1], TEXT ("*?") );
+
+ if ( p != NULL ) {
+ save_char = *p;
+ *p = 0;
+
+ ptrn_len = strlen( &srch_name[i+1] );
+
+ while ( file_name[pos] &&
+ strnicmp( &file_name[pos], &srch_name[i+1], ptrn_len ) ) {
+ pos++;
+ }
+
+ i += ptrn_len;
+
+ *p = save_char;
+
+ if ( file_name[pos] == 0 ) {
+ ret_val = -1;
+ } else {
+ pos++;
+ }
+ }
+ else {
+ if ( srch_name[i+1] == 0 ) {
+ pos = strlen( file_name );
+ break;
+ }
+ else {
+
+ p = strchr( &file_name[pos], srch_name[i+1] );
+ if ( p != NULL ) {
+ pos += p - &file_name[pos];
+ }
+ else {
+ ret_val = -1;
+ }
+ }
+ }
+ break;
+
+ case '?' :
+ if ( file_name[pos] != 0 ) {
+ pos++;
+ }
+ break;
+
+ default:
+ if ( ( file_name[pos] == 0 ) ||
+ ( toupper(file_name[pos]) != toupper(srch_name[i]) ) ){
+ ret_val = -1;
+ }
+ else {
+ pos++;
+ }
+ }
+ }
+
+ if ( file_name[pos] != 0 ) {
+ ret_val = -1;
+ }
+ }
+
+ return( ret_val );
+}
+
+#else
+
+INT QTC_CompAsciiNames( ACHAR_PTR srch_name, ACHAR_PTR file_name )
+{
+ INT pos = 0; /* index for file_name */
+ INT i; /* index for wild_name */
+ INT ret_val = 0;
+ ACHAR_PTR p;
+ ACHAR save_char;
+ INT ptrn_len;
+
+ pos = 0;
+
+ if ( strcmpA( srch_name, "*.*" ) ) {
+
+ for ( i = 0; (srch_name[i] != 0) && (ret_val == 0); i++ ) {
+
+ switch( srch_name[i] ) {
+
+ case '*':
+
+ while ( srch_name[i+1] != 0 ) {
+
+ if ( srch_name[i+1] == '?' ) {
+ if ( file_name[ ++pos ] == 0 ) {
+ break;
+ }
+
+ }
+ else {
+ if ( srch_name[i+1] != '*' ) {
+ break;
+ }
+ }
+ i++;
+ }
+
+ p = strpbrkA( &srch_name[i+1], "*?" );
+
+ if ( p != NULL ) {
+ save_char = *p;
+ *p = 0;
+
+ ptrn_len = strlenA( &srch_name[i+1] );
+
+ while ( file_name[pos] &&
+ strnicmpA( &file_name[pos], &srch_name[i+1], ptrn_len ) ) {
+ pos++;
+ }
+
+ i += ptrn_len;
+
+ *p = save_char;
+
+ if ( file_name[pos] == 0 ) {
+ ret_val = -1;
+ } else {
+ pos++;
+ }
+ }
+ else {
+ if ( srch_name[i+1] == 0 ) {
+ pos = strlenA( file_name );
+ break;
+ }
+ else {
+
+ p = strchrA( &file_name[pos], srch_name[i+1] );
+ if ( p != NULL ) {
+ pos += p - &file_name[pos];
+ }
+ else {
+ ret_val = -1;
+ }
+ }
+ }
+ break;
+
+ case '?' :
+ if ( file_name[pos] != 0 ) {
+ pos++;
+ }
+ break;
+
+ default:
+ if ( ( file_name[pos] == 0 ) ||
+ ( toupper(file_name[pos]) != toupper(srch_name[i]) ) ){
+ ret_val = -1;
+ }
+ else {
+ pos++;
+ }
+ }
+ }
+
+ if ( file_name[pos] != 0 ) {
+ ret_val = -1;
+ }
+ }
+
+ return( ret_val );
+}
+
+
+
+INT QTC_CompUnicodeNames( WCHAR_PTR srch_name, WCHAR_PTR file_name )
+{
+#ifdef UNICODE
+
+ INT pos = 0; /* index for file_name */
+ INT i; /* index for wild_name */
+ INT ret_val = 0;
+ WCHAR_PTR p;
+ WCHAR save_char;
+ WCHAR stardotstar[ 4 ];
+ WCHAR starquestion[ 4 ];
+ INT ptrn_len;
+
+ strcpy( stardotstar, TEXT( "*.*" ) );
+
+ strcpy( starquestion, TEXT( "*?" ) );
+
+ pos = 0;
+
+ if ( wcscmp( srch_name, stardotstar ) ) {
+
+ for ( i = 0; (srch_name[i] != TEXT('\0')) && (ret_val == 0); i++ ) {
+
+ switch ( srch_name[i] ) {
+
+ case TEXT('*'):
+
+ while ( srch_name[i+1] != TEXT('\0') ) {
+
+ if ( srch_name[i+1] == TEXT('?') ) {
+ if ( file_name[ ++pos ] == TEXT('\0') ) {
+ break;
+ }
+
+ }
+ else {
+ if ( srch_name[i+1] != TEXT('*') ) {
+ break;
+ }
+ }
+ i++;
+ }
+
+ p = wcspbrk( &srch_name[i+1], starquestion );
+
+ if ( p != NULL ) {
+ save_char = *p;
+ *p = TEXT('0');
+
+ ptrn_len = wcslen( &srch_name[i+1] );
+
+ while ( file_name[pos] &&
+ wcsnicmp( &file_name[pos], &srch_name[i+1], ptrn_len ) ) {
+ pos++;
+ }
+
+ i += ptrn_len;
+
+ *p = save_char;
+
+ if ( file_name[pos] == TEXT('\0') ) {
+ ret_val = -1;
+ } else {
+ pos++;
+ }
+ }
+ else {
+ if ( srch_name[i+1] == TEXT('\0') ) {
+ pos = wcslen( file_name );
+ break;
+ }
+ else {
+
+ p = wcschr( &file_name[pos], srch_name[i+1] );
+ if ( p != NULL ) {
+ pos += p - &file_name[pos];
+ }
+ else {
+ ret_val = -1;
+ }
+ }
+ }
+ break;
+
+ case TEXT('?') :
+ if ( file_name[pos] != TEXT('\0') ) {
+ pos++;
+ }
+ break;
+
+ default:
+ if ( ( file_name[pos] == TEXT('\0') ) ||
+ ( toupper(file_name[pos]) != toupper(srch_name[i]) ) ){
+ ret_val = -1;
+ }
+ else {
+ pos++;
+ }
+ }
+ }
+
+ if ( file_name[pos] != TEXT( '\0' ) ) {
+ ret_val = -1;
+ }
+ }
+ return( ret_val );
+
+#endif
+ return( 0 );
+}
+
+#endif
diff --git a/private/utils/ntbackup/src/qtc_util.c b/private/utils/ntbackup/src/qtc_util.c
new file mode 100644
index 000000000..03588d107
--- /dev/null
+++ b/private/utils/ntbackup/src/qtc_util.c
@@ -0,0 +1,1555 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: QTC_UTIL.C
+
+ Description:
+
+ A lot of utility functions for the catalogs.
+
+ $Log: N:\LOGFILES\QTC_UTIL.C_V $
+
+ Rev 1.32 07 Jan 1994 14:23:18 mikep
+fixes for unicode
+
+ Rev 1.31 11 Dec 1993 11:49:20 MikeP
+fix warnings from unicode compile
+
+ Rev 1.30 06 Dec 1993 09:46:54 mikep
+Very deep path support & unicode fixes
+
+ Rev 1.29 05 Nov 1993 08:46:16 MIKEP
+fix error msg reporting
+
+ Rev 1.28 02 Nov 1993 17:49:14 MIKEP
+fix non-dll build
+
+ Rev 1.27 28 Oct 1993 14:50:14 MIKEP
+dll changes
+
+ Rev 1.26 21 Sep 1993 11:03:26 JOHNES
+Started mallocing long character strings so we would be sure not to
+overflow them. Added some msasserts to make sure this really doesn't happen.
+
+ Rev 1.25 12 Aug 1993 18:22:00 DON
+If were out of disk space say so, not just open failure
+
+ Rev 1.24 24 May 1993 16:56:58 MIKEP
+Fix getting the pba of the vcb so that it always gets the pba
+of the set from the lowest numbered tape available.
+
+ Rev 1.23 19 May 1993 16:18:32 ChuckS
+P_CLIENT || OS_NLM: Added QTC_SetCatUserName function.
+
+ Rev 1.22 13 May 1993 13:18:22 ChuckS
+Revamped QTC usage of virtual memory. Changed queue calls to corresponding
+vm- queue calls; added msassert's to check integrity of vm queue objects
+(q_ptr always points to the object, providing a means of getting the handle,
+if you only have a pointer).
+
+ Rev 1.21 30 Apr 1993 10:12:36 BRYAN
+(fixed compiler warning)
+
+ Rev 1.20 29 Apr 1993 22:26:42 GREGG
+If there is no TapeCatVer stored in the catalog, set it to one.
+
+ Rev 1.19 29 Apr 1993 11:36:38 MIKEP
+add on tape catalog version call
+
+ Rev 1.18 27 Apr 1993 16:14:54 ChuckS
+Broke QTC_RemoveTape into two functions. Calling QTC_RemoveTape should have
+exactly the same effect as before, but clients can now call QTC_ForgetTape,
+which merely discards the memory allocations associated with the tape,
+without attempting to unlink the file.
+
+ Rev 1.17 26 Apr 1993 08:54:18 MIKEP
+Fix qtc_accessfiles call that I didn't quite get right last time.
+
+ Rev 1.15 15 Apr 1993 10:00:30 Stefan
+Changed if !defined(P_CLIENT) to add || defined(OS_WIN) because the windows
+client needs this code.
+
+ Rev 1.14 24 Mar 1993 11:11:22 ChuckS
+Enclosed QTC_OpenTempFiles with #if !defined( P_CLIENT ) ... #endif.
+
+ Rev 1.13 23 Mar 1993 18:00:30 ChuckS
+Added arg to QTC_OpenFile indicating if need to open for writes
+
+ Rev 1.12 23 Mar 1993 10:32:02 BRYAN
+Fixed compiler warnings.
+
+ Rev 1.11 18 Mar 1993 11:35:20 TIMN
+Added two f(x)s to get catalog info: get data path and get filename only
+
+ Rev 1.10 30 Jan 1993 12:06:28 DON
+Removed compiler warnings
+
+ Rev 1.9 27 Jan 1993 11:25:40 CHARLIE
+Eliminated compiler warnings
+
+ Rev 1.8 26 Jan 1993 17:11:04 MIKEP
+vcb changes
+
+ Rev 1.7 25 Jan 1993 09:10:02 MIKEP
+add stdwcs because it seems to need it now
+
+ Rev 1.6 04 Jan 1993 09:35:18 MIKEP
+unicode changes
+
+ Rev 1.4 14 Dec 1992 12:29:36 DAVEV
+Enabled for Unicode compile
+
+ Rev 1.3 20 Nov 1992 13:51:40 CHARLIE
+JAGUAR: Move to SRM based QTC code
+
+ENDEAVOR: Integrated virtual memory usage in anticipation of DOS. These
+changes should be transparent to non DOS products.
+
+ENDEAVOR: chmod sets S_IREAD along with S_IWRITE to fix a novell clib bug
+that made the file hidden for the NLM in QTC_UnlinkFile.
+
+ Rev 1.2 06 Nov 1992 15:30:04 DON
+Change debug.h to be_debug.h and zprintf to BE_Zprintf
+
+ Rev 1.1 09 Oct 1992 11:54:04 MIKEP
+unicode pass
+
+ Rev 1.0 03 Sep 1992 16:56:16 STEVEN
+Initial revision.
+
+****************************************************/
+
+#include <dos.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <io.h>
+#include <string.h>
+#include <time.h>
+#include <share.h>
+#include <malloc.h>
+#include <sys\types.h>
+#include <sys\stat.h>
+
+#ifdef WIN32 // Needed for file i/o prototypes.
+#include <windows.h>
+#endif
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "stdwcs.h"
+#include "msassert.h"
+#include "qtc.h"
+
+
+// unicode text macro
+
+#ifndef TEXT
+#define TEXT( x ) x
+#endif
+
+INT QTC_OpenUniqueTempFile( CHAR_PTR );
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT QTC_CouldThisSetCrossTapes(
+UINT32 tape_fid,
+INT16 tape_seq_num,
+INT16 bset_num )
+{
+ QTC_BSET_PTR bset;
+
+ bset = QTC_FindBset( tape_fid, tape_seq_num, bset_num );
+
+ // We don't even have it so who knows.
+
+ if ( bset == NULL ) {
+ return( TRUE );
+ }
+
+ // If it is split, then we know it crosses.
+
+ if ( bset->status & QTC_SPLIT ) {
+ return( TRUE );
+ }
+
+ // If he has a later brother on this tape he doesn't cross.
+
+ bset = QTC_GetNextBset( bset );
+
+ if ( bset != NULL ) {
+ return( FALSE );
+ }
+
+ // No known "Next set", he may cross.
+
+ return( TRUE );
+}
+
+
+
+
+/**********************
+
+ NAME : QTC_AnyCatalogFiles
+
+ DESCRIPTION :
+
+ A quick call for the menu to know if there are any catalog files.
+
+ RETURNS :
+
+**********************/
+
+BOOLEAN QTC_AnyCatalogFiles( VOID )
+{
+ return( (BOOLEAN) vmQueueCount( &gb_QTC.tape_list ) ) ;
+}
+
+
+INT QTC_PartializeTape( UINT32 tape_fid, INT16 tape_seq_num, INT16 bset_num )
+{
+ QTC_TAPE_HEADER tape_header;
+ QTC_HEADER_PTR header;
+ QTC_TAPE_PTR tape;
+ QTC_BSET_PTR bset;
+ INT fd;
+ INT ret;
+ INT Error;
+ INT16 temp_tape_seq_num;
+ INT BytesNeeded;
+ UINT32 temp_tape_fid;
+ UINT32 offset;
+ CHAR_PTR temp_file_name ;
+ CHAR_PTR real_file_name ;
+
+
+ BytesNeeded = strlen( gb_QTC.data_path ) + 13;
+ BytesNeeded *= sizeof( CHAR );
+
+ if ( ( temp_file_name = (CHAR_PTR)malloc( BytesNeeded )) == NULL ) {
+ return ( FAILURE ) ;
+ }
+
+ if ( ( real_file_name = (CHAR_PTR)malloc( BytesNeeded )) == NULL ) {
+ free( temp_file_name ) ;
+ return ( FAILURE ) ;
+ }
+
+ // Look for the right tape.
+
+ tape = QTC_GetFirstTape( );
+
+ while ( tape != NULL ) {
+
+ if ( ( ( tape->tape_fid == tape_fid ) ||
+ ( (INT32)tape_fid == -1L ) ) &&
+ ( ( tape->tape_seq_num == tape_seq_num ) ||
+ ( tape_seq_num == -1 ) ) ) {
+
+ temp_tape_fid = tape->tape_fid;
+
+ if ( bset_num == -1 ) {
+
+ // Create a temp file
+
+ fd = QTC_OpenUniqueTempFile( temp_file_name );
+
+ msassert( strlen( temp_file_name ) < (strlen( gb_QTC.data_path ) + 13) ) ;
+
+ if ( fd < 0 ) {
+ free( temp_file_name ) ;
+ free( real_file_name ) ;
+ return( FAILURE );
+ }
+
+ // Write out the QTC header.
+
+ memcpy( tape_header.signature, QTC_SIGNATURE, sizeof(QTC_SIGNATURE) );
+
+ tape_header.major_version = QTC_MAJOR_VERSION;
+ tape_header.minor_version = QTC_MINOR_VERSION;
+
+ ret = QTC_WriteFile( fd, (BYTE_PTR)&tape_header, sizeof( QTC_TAPE_HEADER ), &Error );
+
+ if ( ret != sizeof( QTC_TAPE_HEADER ) ) {
+
+ // tell user he's hosed
+
+ QTC_CloseFile( fd );
+
+ unlink( temp_file_name );
+
+ free( temp_file_name ) ;
+ free( real_file_name ) ;
+
+ return( FAILURE );
+ }
+
+ offset = sizeof( QTC_TAPE_HEADER );
+
+ // Now look for bsets.
+
+ bset = QTC_GetFirstBset( tape );
+
+ // Copy all the headers into it.
+
+ while ( bset != NULL ) {
+
+ temp_tape_seq_num = (INT16)bset->tape_seq_num;
+
+ // Write out all the bsets for this tape.
+
+ while ( bset->tape_seq_num == temp_tape_seq_num ) {
+
+ header = QTC_LoadHeader( bset );
+
+ if ( header == NULL ) {
+ QTC_CloseFile( fd );
+ unlink( temp_file_name );
+
+ free( temp_file_name ) ;
+ free( real_file_name ) ;
+
+ return( FAILURE );
+ }
+
+ bset->status |= QTC_PARTIAL;
+ header->status |= QTC_PARTIAL;
+
+ header->dir_size = 0;
+ header->fil_size = 0;
+ header->rec_size = 0;
+
+ header->offset = offset;
+ bset->offset = offset;
+
+ offset += header->header_size;
+
+ if ( QTC_IsThereAnotherBset( bset ) ) {
+ header->next_bset = offset;
+ }
+ else {
+ header->next_bset = 0L;
+ }
+
+ // write out bset
+
+ ret = QTC_WriteFile( fd, (BYTE_PTR)header, (INT)header->header_size, &Error );
+
+ if ( ret != (INT)header->header_size ) {
+
+ free( header );
+ QTC_CloseFile( fd );
+ unlink( temp_file_name );
+ free( temp_file_name ) ;
+ free( real_file_name ) ;
+
+ return( FAILURE );
+ }
+
+ free( header );
+
+ bset = QTC_GetNextBset( bset );
+
+ if ( bset == NULL ) {
+ break;
+ }
+ }
+
+ QTC_CloseFile( fd );
+
+ // Delete the original.
+
+ QTC_UnlinkFile( temp_tape_fid, temp_tape_seq_num );
+
+ // Rename the temp file.
+
+ QTC_GetFileName( temp_tape_fid, temp_tape_seq_num, real_file_name );
+
+ msassert( strlen( real_file_name ) < (strlen( gb_QTC.data_path ) + 13) ) ;
+
+ rename( temp_file_name, real_file_name );
+ }
+ }
+ }
+
+ tape = QTC_GetNextTape( tape );
+ }
+
+ free( temp_file_name ) ;
+ free( real_file_name ) ;
+
+ return( SUCCESS );
+}
+
+/*
+ A single bset is being converted to partial. Just change its status
+ bits and leave all the data there.
+*/
+
+INT QTC_PartializeBset(
+UINT32 tape_fid,
+INT16 tape_seq_num,
+INT16 bset_num )
+{
+ QTC_HEADER_PTR header;
+ QTC_TAPE_PTR tape;
+ QTC_BSET_PTR bset;
+ INT Error;
+ INT fd;
+ INT ret;
+
+ // Look for the right tape.
+
+ tape = QTC_GetFirstTape( );
+
+ while ( tape != NULL ) {
+
+ if ( ( ( tape->tape_fid == tape_fid ) ||
+ ( (INT32)tape_fid == -1L ) ) &&
+ ( ( tape->tape_seq_num == tape_seq_num ) ||
+ ( tape_seq_num == -1 ) ) ) {
+
+ // mark the set as partial in memory and on disk.
+
+ // Now look for bsets.
+
+ bset = QTC_GetFirstBset( tape );
+
+ // Copy all the headers into it.
+
+ while ( bset != NULL ) {
+
+ // Find the one bset that is changing.
+
+ if ( bset->bset_num == bset_num ) {
+
+ header = QTC_LoadHeader( bset );
+
+ if ( header == NULL ) {
+ return( FAILURE );
+ }
+
+ bset->status |= QTC_PARTIAL; // in memory queue
+
+ header->status |= QTC_PARTIAL; // structure going out to disk
+ header->dir_size = 0;
+ header->fil_size = 0;
+ header->rec_size = 0;
+
+ fd = QTC_OpenFile( bset->tape_fid, (INT16)bset->tape_seq_num, TRUE, FALSE );
+
+ if ( fd < 0 ) {
+ return( FAILURE );
+ }
+
+ QTC_SeekFile( fd, bset->offset );
+
+ ret = QTC_WriteFile( fd, (BYTE_PTR)header, (INT)header->header_size, &Error );
+
+ QTC_CloseFile( fd );
+
+ if ( ret != (INT)header->header_size ) {
+
+ free( header );
+ return( FAILURE );
+ }
+
+ free( header );
+ }
+
+ bset = QTC_GetNextBset( bset );
+ }
+ }
+
+ tape = QTC_GetNextTape( tape );
+ }
+
+ return( SUCCESS );
+}
+
+
+/**********************
+
+ NAME : QTC_Partialize
+
+ DESCRIPTION :
+
+ The user has requested by way of catalog maintenance, that this tape be
+ converted to partially cataloged to save disk space. Rewrite the file
+ onto disk leaving out all data sets.
+
+ RETURNS :
+
+**********************/
+
+INT QTC_Partialize(
+UINT32 tape_fid,
+INT16 tape_seq_num,
+INT16 bset_num )
+{
+ INT error;
+
+ if ( bset_num == -1 ) {
+ error = QTC_PartializeTape( tape_fid, tape_seq_num, bset_num );
+ }
+ else {
+ error = QTC_PartializeBset( tape_fid, tape_seq_num, bset_num );
+ }
+
+ return( error );
+}
+
+/**********************
+
+ NAME : QTC_GetMeTheVCBPBA
+
+ DESCRIPTION :
+
+ Another of those FFR support routines. Returns the PBA of the VCB for
+ this BSET on this FID.
+
+ RETURNS :
+
+**********************/
+
+INT32 QTC_GetMeTheVCBPBA(
+UINT32 tape_fid,
+INT16 tape_num,
+INT16 bset_num )
+{
+ QTC_BSET_PTR best_bset = NULL;
+ QTC_HEADER_PTR header;
+ UINT32 PBA_VCB = 0L;
+ BOOLEAN done = FALSE;
+ QTC_TAPE_PTR tape;
+ QTC_BSET_PTR bset;
+
+
+ tape = QTC_GetFirstTape( );
+
+ while ( tape != NULL && ! done ) {
+
+ if ( ( tape->tape_fid == tape_fid ) &&
+ ( ( tape->tape_seq_num == tape_num ) ||
+ ( tape_num == -1 ) ) ) {
+
+ bset = QTC_GetFirstBset( tape );
+
+ while ( bset != NULL && ! done ) {
+
+ if ( bset->bset_num == bset_num ) {
+
+ if ( best_bset == NULL ) {
+
+ best_bset = bset;
+
+ // if its all on one tape we are done.
+
+ if ( ! (best_bset->status & (QTC_SPLIT | QTC_CONTINUATION) ) ) {
+ done = TRUE;
+ }
+ }
+ else {
+ if ( best_bset->tape_seq_num > bset->tape_seq_num ) {
+ best_bset = bset;
+ }
+ }
+ if ( best_bset->tape_seq_num == 1 ) {
+ done = TRUE;
+ }
+ }
+
+ bset = QTC_GetNextBset( bset );
+ }
+ }
+
+ tape = QTC_GetNextTape( tape );
+ }
+
+ if ( best_bset != NULL ) {
+
+ header = QTC_LoadHeader( best_bset );
+
+ if ( header ) {
+ PBA_VCB = header->PBA_VCB;
+ free( header );
+ }
+ }
+
+ return( PBA_VCB );
+
+}
+
+
+
+/**********************
+
+ NAME : QTC_GetMeTheTapeCatVer
+
+ DESCRIPTION :
+
+ Another of those FFR support routines.
+ Returns the on tape catalog version.
+
+ RETURNS :
+
+**********************/
+
+UINT8 QTC_GetMeTheTapeCatVer(
+UINT32 tape_fid,
+INT16 tape_num,
+INT16 bset_num )
+{
+ QTC_BSET_PTR bset;
+ QTC_HEADER_PTR header;
+ UINT8 TapeCatVer = (UINT8)0;
+
+ bset = QTC_FindBset( tape_fid, tape_num, bset_num );
+
+ if ( bset != NULL ) {
+ header = QTC_LoadHeader( bset );
+
+ if ( header ) {
+ if( ( TapeCatVer = (UINT8) header->FDD_Version ) == 0 ) {
+ TapeCatVer = 1 ;
+ }
+ free( header );
+ }
+ }
+
+ return( TapeCatVer );
+}
+
+
+
+/**********************
+
+ NAME : QTC_RemoveTape
+
+ DESCRIPTION :
+
+ This tape is going to be written over, so remove all information from the
+ catalogs for it. Or the user has requested we delete this tape from the
+ catalogs in the maintenance option.
+
+ RETURNS :
+
+**********************/
+
+VOID QTC_RemoveTape(
+UINT32 tape_fid, // I - the family ID
+INT16 tape_seq_num ) // I - the sequence number
+{
+ QTC_TAPE_PTR tape;
+
+ tape = QTC_GetFirstTape();
+
+ while ( tape != NULL ) {
+
+ if ( ( tape->tape_fid == tape_fid ) &&
+ ( ( tape->tape_seq_num == tape_seq_num ) ||
+ ( tape_seq_num == -1 ) ) ) {
+
+ // Delete file from disk
+ QTC_UnlinkFile( tape->tape_fid, tape->tape_seq_num );
+
+ // remove it from our list
+ QTC_ForgetTape( tape ) ;
+ tape = NULL;
+ }
+
+ if ( tape == NULL ) {
+ tape = QTC_GetFirstTape();
+ }
+ else {
+ tape = QTC_GetNextTape( tape );
+ }
+ }
+}
+
+
+
+
+/**********************
+
+ NAME : QTC_ForgetTape
+
+ DESCRIPTION :
+
+ This is code broken out of the bottom of QTC_RemoveTape. It takes care
+ of freeing the queue of QTC_BSET's associated with the tape, and the
+ QTC_TAPE record itself.
+
+ This function was created because the client may want to remove all
+ record of a tape, without necessarily erasing the tape file.
+
+
+* IMPORTANT NOTE *
+
+ It is IMPERATIVE that the caller NOT USE the QTC_TAPE_PTR he passed in,
+ after this function returns. i,e, safe usage is:
+
+ QTC_ForgetTape( tape ) ;
+ tape = NULL ;
+
+ RETURNS :
+
+**********************/
+VOID QTC_ForgetTape(
+ QTC_TAPE_PTR tape
+)
+{
+ VQ_HDL hBset ;
+ VQ_HDL hTape ;
+
+ hBset = vmDeQueueElem( &( tape->bset_list ) ) ;
+
+ while ( hBset != (VQ_HDL) NULL ) {
+ if ( hBset == v_bset_item ) {
+ VM_MemUnLock( qtc_vmem_hand, hBset ) ;
+ v_bset_item = (VM_PTR) NULL ;
+ }
+
+ VM_Free( qtc_vmem_hand, hBset ) ;
+ hBset = vmDeQueueElem( &(tape->bset_list) ) ;
+ }
+
+ // Now remove that tape from the tapes list
+ vmRemoveQueueElem( &(gb_QTC.tape_list), ( hTape = tape->q_elem.q_ptr ) ) ;
+
+ if ( hTape == v_tape_item ) {
+ // if it happens to be the current tape item, unlock it and NULL v_tape_item
+ VM_MemUnLock( qtc_vmem_hand, hTape ) ;
+ v_tape_item = (VQ_HDL) NULL ;
+ }
+
+ VM_Free( qtc_vmem_hand, hTape ) ;
+}
+
+
+/**********************
+
+ NAME : QTC_CheckFilesAccess
+
+ DESCRIPTION :
+
+ Check to see if any files are gone from the disk and delete them
+ if they are.
+
+ RETURNS :
+
+**********************/
+
+INT QTC_CheckFilesAccess( )
+{
+ QTC_TAPE_PTR tape;
+ VQ_HDL hBset ;
+ CHAR_PTR path ;
+ INT BytesNeeded;
+
+ BytesNeeded = strsize( gb_QTC.data_path ) + 13;
+ BytesNeeded *= sizeof(CHAR );
+
+ if ( ( path = (CHAR_PTR)malloc( BytesNeeded ) ) == NULL ) {
+ return ( FAILURE ) ;
+ }
+
+ tape = QTC_GetFirstTape( ) ;
+
+ while ( tape != NULL ) {
+
+ QTC_GetFileName( tape->tape_fid, tape->tape_seq_num, path ) ;
+
+ msassert( strlen( path ) < (strlen( gb_QTC.data_path ) + 13) ) ;
+
+ if ( access( path, 0 ) ) {
+
+ // Remove it from our list
+
+ hBset = vmDeQueueElem( &(tape->bset_list) ) ;
+
+ while ( hBset != (VQ_HDL) NULL ) {
+ if ( hBset == v_bset_item ) {
+ VM_MemUnLock( qtc_vmem_hand, v_bset_item ) ;
+ v_bset_item = (VM_PTR) NULL ;
+ }
+ VM_Free( qtc_vmem_hand, hBset ) ;
+ hBset = vmDeQueueElem( &(tape->bset_list) ) ;
+ }
+
+ // Now remove that tape from the tapes list
+
+ msassert( v_tape_item == tape->q_elem.q_ptr ) ;
+
+ vmRemoveQueueElem( &(gb_QTC.tape_list), v_tape_item ) ;
+ VM_MemUnLock( qtc_vmem_hand, v_tape_item );
+ VM_Free( qtc_vmem_hand, v_tape_item ) ;
+ tape = NULL ;
+ }
+
+ if ( tape != NULL ) {
+ tape = QTC_GetNextTape( tape ) ;
+ } else {
+ tape = QTC_GetFirstTape() ;
+ }
+ }
+
+ free( path ) ;
+
+ return( SUCCESS );
+}
+
+/**********************
+
+ NAME : QTC_GetFirstTape
+
+ DESCRIPTION :
+
+ Get a pointer to the first tape in the catalogs
+
+ RETURNS :
+
+**********************/
+
+QTC_TAPE_PTR QTC_GetFirstTape( )
+{
+ VQ_HDL hTape ;
+
+ hTape = vmQueueHead( &(gb_QTC.tape_list) ) ;
+
+ if ( hTape != (VQ_HDL) NULL ) {
+ VM_MemUnLock( qtc_vmem_hand, v_tape_item ) ;
+ return( (QTC_TAPE_PTR)VM_MemLock( qtc_vmem_hand, v_tape_item = hTape, VM_READ_WRITE ) ) ;
+ }
+
+ return( NULL ) ;
+}
+
+
+/**********************
+
+ NAME : QTC_GetNextTape
+
+ DESCRIPTION :
+
+ Get a pointer to the next tape in the catalogs
+
+ RETURNS :
+
+**********************/
+
+QTC_TAPE_PTR QTC_GetNextTape(
+QTC_TAPE_PTR tape ) // I - current tape
+{
+ VQ_HDL hTape ;
+
+ hTape = vmQueueNext( &tape->q_elem ) ;
+
+ if ( hTape != (VQ_HDL) NULL ) {
+ VM_MemUnLock( qtc_vmem_hand, v_tape_item ) ;
+ return( (QTC_TAPE_PTR)VM_MemLock( qtc_vmem_hand, v_tape_item = hTape, VM_READ_WRITE ) ) ;
+ }
+
+ return( NULL );
+}
+
+
+/**********************
+
+ NAME : QTC_GetPrevTape
+
+ DESCRIPTION :
+
+ Get a pointer to the previous tape in the catalog
+
+ RETURNS :
+
+**********************/
+
+QTC_TAPE_PTR QTC_GetPrevTape(
+QTC_TAPE_PTR tape ) // I - current tape
+{
+ VQ_HDL hTape ;
+
+ hTape = vmQueuePrev( &( tape->q_elem ) ) ;
+
+ if ( hTape != (VQ_HDL) NULL ) {
+ VM_MemUnLock( qtc_vmem_hand, v_tape_item ) ;
+ return( (QTC_TAPE_PTR)VM_MemLock( qtc_vmem_hand, hTape, VM_READ_WRITE ) ) ;
+ }
+
+ return( NULL ) ;
+}
+
+
+
+
+/**********************
+
+ NAME : QTC_GetDataPath
+
+ DESCRIPTION :
+
+ Returns global path where catalog files reside.
+
+ RETURNS : TRUE if successful, FALSE if not enough space to copy path
+
+**********************/
+
+BOOLEAN QTC_GetDataPath( CHAR_PTR path, INT16 pathSize )
+{
+ BOOLEAN retValu = TRUE;
+
+ if ( pathSize > (INT16)strsize( gb_QTC.data_path ) ) {
+ strcpy( path, gb_QTC.data_path );
+ }
+ else {
+ *path = TEXT( '\0' );
+ retValu = FALSE;
+ }
+
+ return( retValu );
+}
+
+
+/**********************
+
+ NAME : QTC_GetFileName
+
+ DESCRIPTION :
+
+ Builds the complete path and file name for a catalog file.
+
+ RETURNS :
+
+**********************/
+
+VOID QTC_GetFileName(
+UINT32 tape_fid,
+INT16 tape_seq,
+CHAR_PTR name )
+{
+ CHAR temp[13];
+
+ strcpy( name, gb_QTC.data_path );
+ QTC_GetFileNameOnly( tape_fid, tape_seq, temp ) ;
+ strcat( name, temp );
+}
+
+
+/**********************
+
+ NAME : QTC_GetFileNameOnly
+
+ DESCRIPTION :
+
+ Builds only the file name for a catalog file.
+
+ RETURNS :
+
+**********************/
+
+CHAR_PTR QTC_GetFileNameOnly(
+UINT32 tape_fid,
+INT16 tape_seq,
+CHAR_PTR name )
+{
+ INT i;
+ static CHAR hex[16] = { TEXT('0'), TEXT('1'), TEXT('2'), TEXT('3'),
+ TEXT('4'), TEXT('5'), TEXT('6'), TEXT('7'),
+ TEXT('8'), TEXT('9'), TEXT('A'), TEXT('B'),
+ TEXT('C'), TEXT('D'), TEXT('E'), TEXT('F') };
+
+ if ( gb_QTC.unicode ) {
+ sprintf( name, TEXT("00000000.U%02d"), tape_seq );
+ }
+ else {
+ sprintf( name, TEXT("00000000.D%02d"), tape_seq );
+ }
+
+ for ( i = 7; i >= 0; i-- ) {
+ name[ i ] = hex[ tape_fid & 0x0f ];
+ tape_fid >>= 4;
+ }
+
+ return( name ) ;
+}
+
+
+/**********************
+
+ NAME : QTC_UnlinkFile
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT QTC_UnlinkFile( UINT32 tape_fid, INT16 tape_seq_num )
+{
+ CHAR_PTR name;
+ INT BytesNeeded;
+
+ BytesNeeded = strsize( gb_QTC.data_path ) + 13;
+ BytesNeeded *= sizeof(CHAR);
+
+ if ( ( name = (CHAR_PTR)malloc( BytesNeeded ) ) == NULL ) {
+ return ( FAILURE ) ;
+ }
+
+ QTC_GetFileName( tape_fid, tape_seq_num, name );
+
+ msassert( strlen( name ) < strlen( gb_QTC.data_path ) + 13 ) ;
+
+ // Make sure they haven't set it to read only.
+
+ chmod( name, S_IREAD | S_IWRITE );
+
+ if ( unlink( name ) ) {
+ free ( name );
+ return( FAILURE );
+ }
+
+ free ( name );
+
+ return( SUCCESS );
+}
+
+
+// Squeeze it.
+
+INT QTC_CompressFile( UINT32 tape_fid, INT16 tape_seq_num )
+{
+ (VOID)tape_fid;(VOID)tape_seq_num;
+
+ // rename it
+
+ // open new file, and start copying blocks
+
+ // delete old renamed one
+
+
+ return( SUCCESS );
+}
+
+UINT32 QTC_GetKiloBytesWasted( UINT32 tape_fid, UINT16 tape_seq_num )
+{
+ (VOID)tape_fid;
+ (VOID)tape_seq_num;
+
+ return( 0L );
+}
+
+
+
+INT QTC_Open( CHAR_PTR szFile, INT fCreate, INT fWrite, INT *Error )
+{
+ INT fd = -1;
+ INT nError;
+
+ *Error = 0;
+ (void)nError;
+
+ #ifdef WIN32
+
+ if ( fCreate ) {
+ fd = (INT)CreateFile( szFile,
+ (DWORD)(GENERIC_READ|GENERIC_WRITE),
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ (LPSECURITY_ATTRIBUTES)NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ (HANDLE)NULL );
+ }
+ else {
+ fd = (INT)CreateFile( szFile,
+ (DWORD)( fWrite ? GENERIC_READ|GENERIC_WRITE : GENERIC_READ ),
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ (LPSECURITY_ATTRIBUTES)NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ (HANDLE)NULL );
+ }
+
+ if ( fd < 0 ) {
+
+ nError = GetLastError();
+
+ switch ( nError ) {
+
+ case ERROR_HANDLE_DISK_FULL:
+ *Error = QTC_DISK_FULL;
+ break;
+
+ case ERROR_TOO_MANY_OPEN_FILES:
+ *Error = QTC_NO_FILE_HANDLES;
+ break;
+
+ default:
+ *Error = QTC_OPEN_FAILED; // Start with generic case.
+ break;
+ }
+
+ }
+
+ #else
+
+ if ( fCreate ) {
+ fd = sopen( szFile, O_CREAT|O_RDWR|O_BINARY, SH_DENYNO, S_IWRITE|S_IREAD );
+ }
+ else {
+ fd = sopen( szFile, ( fWrite ? O_RDWR:O_RDONLY ) | O_BINARY, SH_DENYNO, S_IWRITE|S_IREAD ) ;
+ }
+
+ if ( fd < 0 ) {
+
+ *Error = QTC_OPEN_FAILED; // Start with generic case.
+
+ if ( errno == ENOSPC ) { // Try fr specific things
+ *Error = QTC_DISK_FULL;
+ }
+ if ( errno == EMFILE ) {
+ *Error = QTC_NO_FILE_HANDLES;
+ }
+ }
+
+ #endif
+
+
+ return( fd );
+}
+
+INT QTC_CloseFile( INT FileHandle )
+{
+ INT ret_val;
+
+ #ifdef WIN32
+ ret_val = (INT)CloseHandle( (HANDLE)FileHandle );
+ #else
+ ret_val = close( FileHandle );
+ #endif
+
+ return( ret_val );
+}
+
+INT QTC_SeekFile( INT FileHandle, INT Offset )
+{
+ INT ret_val;
+
+ #ifdef WIN32
+ ret_val = SetFilePointer( (HANDLE)FileHandle, (LONG)Offset, (PLONG)NULL, FILE_BEGIN );
+ #else
+ ret_val = lseek( FileHandle, Offset, SEEK_SET );
+ #endif
+
+ return( ret_val );
+}
+
+INT QTC_ReadFile( INT FileHandle, BYTE_PTR Buffer, INT Size, INT *Error )
+{
+ INT ret_val;
+
+ #ifdef WIN32
+
+ DWORD BytesRead;
+
+ *Error = 0;
+
+ ret_val = (INT)ReadFile( (HANDLE)FileHandle, Buffer, (DWORD)Size, (LPDWORD)&BytesRead, (LPOVERLAPPED)NULL );
+
+ ret_val = BytesRead;
+
+ if ( (DWORD)Size != BytesRead ) {
+ *Error = QTC_READ_FAILED;
+ }
+
+ #else
+
+ *Error = 0;
+
+ ret_val = read( FileHandle, Buffer, Size );
+
+ if ( ret_val < 0 ) {
+ *Error = QTC_READ_FAILED;
+ }
+
+ #endif
+
+ return( ret_val );
+}
+
+INT QTC_WriteFile( INT FileHandle, BYTE_PTR Buffer, INT Size, INT *Error )
+{
+ INT ret_val;
+
+ #ifdef WIN32
+ DWORD BytesWritten;
+
+ *Error = 0;
+
+ ret_val = (INT)WriteFile( (HANDLE)FileHandle, Buffer, (DWORD)Size, (LPDWORD)&BytesWritten, (LPOVERLAPPED)NULL );
+
+ if ( (DWORD)Size == BytesWritten ) {
+ ret_val = BytesWritten;
+ }
+ else {
+
+ *Error = QTC_WRITE_FAILED;
+
+ if ( GetLastError() == ERROR_HANDLE_DISK_FULL ) {
+ *Error = QTC_DISK_FULL;
+ }
+
+ }
+
+ #else
+
+ *Error = 0;
+
+ ret_val = write( FileHandle, Buffer, Size );
+
+ if ( ret_val != Size ) {
+
+ *Error = QTC_WRITE_FAILED;
+
+ if ( errno == ENOSPC ) {
+ *Error = QTC_DISK_FULL;
+ }
+ }
+
+ #endif
+
+ return( ret_val );
+}
+
+
+
+
+/**********************
+
+ NAME : QTC_OpenFile
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT QTC_OpenFile( UINT32 tape_fid, INT16 tape_seq_num, INT write_mode, INT create )
+{
+ INT fd = -1;
+ INT Error;
+ INT BytesNeeded;
+ CHAR_PTR name;
+
+ BytesNeeded = strsize( gb_QTC.data_path ) + 13;
+ BytesNeeded *= sizeof(CHAR);
+
+ if ( ( name = (CHAR_PTR)malloc( BytesNeeded ) ) == NULL ) {
+ return ( fd ) ;
+ }
+
+ QTC_GetFileName( tape_fid, tape_seq_num, name );
+
+ // open files and share them with every one
+
+ if ( access( name, 0 ) ) {
+
+ if ( create ) {
+
+ msassert( write_mode != FALSE ) ;
+
+ fd = QTC_Open( name, TRUE, TRUE, &Error );
+ }
+ }
+ else {
+ fd = QTC_Open( name, FALSE, write_mode, &Error ) ;
+ }
+
+ free ( name ) ;
+
+ return( fd );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT QTC_OpenUniqueTempFile( CHAR_PTR file )
+{
+ INT file_number = 0;
+ INT Error;
+
+ do {
+
+ if ( file_number == 1000 ) {
+ return( FAILURE );
+ }
+
+ sprintf( file, TEXT("%sQTC_TEMP.%03d"), gb_QTC.data_path, file_number++ );
+
+ } while ( ! access( file, 0 ) );
+
+ // Now we have a unique file name, try to open it.
+
+ return( QTC_Open( file, TRUE, TRUE, &Error ) );
+
+}
+
+
+
+#if !defined( P_CLIENT ) || defined( OS_WIN )
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT QTC_OpenTempFiles(
+QTC_BUILD_PTR build )
+{
+
+ build->fh_rec = -1;
+ build->fh_dir = -1;
+ build->fh_fil = -1;
+
+ build->fh_fil = QTC_OpenUniqueTempFile( build->fil_file );
+
+ if ( build->fh_fil < 0 ) {
+
+ if ( errno == ENOSPC ) {
+ build->error = QTC_DISK_FULL;
+ }
+ else if ( errno == EMFILE ) {
+ build->error = QTC_NO_FILE_HANDLES;
+ }
+ else {
+ build->error = QTC_OPEN_FAILED;
+ }
+ build->state = QTC_ERROR_STATE;
+ QTC_CloseFile( build->fh_rec );
+ build->fh_rec = INVALID_HANDLE_VALUE ;
+ return( FAILURE );
+ }
+
+ build->fh_rec = QTC_OpenUniqueTempFile( build->rec_file );
+
+ if ( build->fh_rec < 0 ) {
+
+ if ( errno == ENOSPC ) {
+ build->error = QTC_DISK_FULL;
+ }
+ else if ( errno == EMFILE ) {
+ build->error = QTC_NO_FILE_HANDLES;
+ }
+ else {
+ build->error = QTC_OPEN_FAILED;
+ }
+ build->state = QTC_ERROR_STATE;
+ return( FAILURE );
+ }
+
+
+ build->fh_dir = QTC_OpenUniqueTempFile( build->dir_file );
+
+ if ( build->fh_dir < 0 ) {
+
+ if ( errno == ENOSPC ) {
+ build->error = QTC_DISK_FULL;
+ }
+ else if ( errno == EMFILE ) {
+ build->error = QTC_NO_FILE_HANDLES;
+ }
+ else {
+ build->error = QTC_OPEN_FAILED;
+ }
+ build->state = QTC_ERROR_STATE;
+ QTC_CloseFile( build->fh_rec );
+ build->fh_rec = INVALID_HANDLE_VALUE ;
+ QTC_CloseFile( build->fh_fil );
+ build->fh_fil = INVALID_HANDLE_VALUE ;
+ return( FAILURE );
+ }
+
+ build->files_open = TRUE;
+
+ return( SUCCESS );
+}
+#endif
+
+
+QTC_HEADER_PTR QTC_LoadHeader( QTC_BSET_PTR bset )
+{
+ QTC_HEADER_PTR header = NULL;
+ QTC_HEADER temp_header;
+ INT Error;
+ INT fh;
+ INT ret;
+
+ // load it from file.
+
+ // open file
+
+ fh = QTC_OpenFile( bset->tape_fid, (UINT16)bset->tape_seq_num, FALSE, FALSE );
+
+ if ( fh < 0 ) {
+ return( NULL );
+ }
+
+ // seek file
+
+ QTC_SeekFile( fh, bset->offset );
+
+ // read file
+
+ ret = QTC_ReadFile( fh, (BYTE_PTR)&temp_header, sizeof( QTC_HEADER ), &Error );
+
+ if ( ret != sizeof( QTC_HEADER ) ) {
+ return( NULL );
+ }
+
+ header = (QTC_HEADER_PTR)malloc( (INT)temp_header.header_size );
+
+ if ( header == NULL ) {
+ return( NULL );
+ }
+
+ QTC_SeekFile( fh, bset->offset );
+
+ ret = QTC_ReadFile( fh, (BYTE_PTR)header, (INT)temp_header.header_size, &Error );
+
+ if ( ret != (INT)temp_header.header_size ) {
+ free( header );
+ return( NULL );
+ }
+
+ // close file
+
+ QTC_CloseFile( fh );
+
+ header->offset = bset->offset;
+
+ // Quick sanity check
+
+ if ( ( bset->tape_fid != header->tape_fid ) ||
+ ( bset->tape_seq_num != header->tape_seq_num ) ||
+ ( bset->bset_num != header->bset_num ) ) {
+
+ msassert( FALSE );
+ free( header );
+ return( NULL );
+ }
+
+ // Fun test for safety.
+
+ if ( header->status & ( QTC_IMAGE | QTC_PARTIAL ) ) {
+
+ header->dir_size = 0;
+ header->rec_size = 0;
+ header->fil_size = 0;
+ }
+
+ // Update bset pointers
+
+ header->rec_start = header->offset + header->header_size;
+ header->dir_start = header->rec_start + header->rec_size;
+ header->fil_start = header->dir_start + header->dir_size;
+
+ // set up string pointers
+
+ header = QTC_SetUpStrings( header );
+
+ return( header );
+}
+
+
+
+// The string pointers in the header data structure need to be pointed to
+// the correct memory locations in the extra memory located immediately
+// after the header. These strings may very well also need to be converted.
+
+QTC_HEADER_PTR QTC_SetUpStrings( QTC_HEADER_PTR header )
+{
+ BYTE_PTR b; // byte always
+
+ b = (BYTE_PTR)header;
+ b += header->string_offset;
+
+ header->tape_name = (CHAR_PTR)b;
+ b += header->tape_name_size;
+ header->bset_name = (CHAR_PTR)b;
+ b += header->bset_name_size;
+ header->volume_name = (CHAR_PTR)b;
+ b += header->volume_name_size;
+ header->user_name = (CHAR_PTR)b;
+ b += header->user_name_size;
+ header->bset_description = (CHAR_PTR)b;
+ b += header->bset_description_size;
+ header->tape_password = (CHAR_PTR)b;
+ b += header->tape_password_size;
+ header->bset_password = (CHAR_PTR)b;
+
+ return( header );
+}
+
+
+#if defined( P_CLIENT ) || defined( OS_NLM )
+
+/**********************
+
+ NAME : QTC_SetCatUser
+
+ DESCRIPTION : Sets the user name to use when scanning the catalog
+ files and building the in-memory queue of tapes and
+ sets.
+
+ If user_name == NULL, all sets will be returned. If
+ user_name != NULL, only those sets belonging to the
+ same user_name, or sets having no user-name, will
+ be visible.
+
+ RETURNS :
+
+**********************/
+
+VOID QTC_SetCatUserName( CHAR_PTR user_name )
+{
+ if ( gb_QTC.cat_user ) {
+ free( gb_QTC.cat_user ) ;
+ }
+
+ if ( user_name ) {
+ // MSC strdup and our DOS substitution strdup don't handle NULL
+ // arg very well, so assume other compiler libraries may not
+ // handle it.
+ gb_QTC.cat_user = strdup( user_name ) ;
+ } else {
+ gb_QTC.cat_user = NULL ;
+ }
+}
+#endif
diff --git a/private/utils/ntbackup/src/qtcxface.c b/private/utils/ntbackup/src/qtcxface.c
new file mode 100644
index 000000000..15301efaf
--- /dev/null
+++ b/private/utils/ntbackup/src/qtcxface.c
@@ -0,0 +1,1173 @@
+/***************************************************
+Copyright (C) Conner Software 1994
+
+ Name: QTCxface.C
+
+ Description:
+
+ This file contains all of the interface functions to the catalog unit. It prevents the
+ catalog unit froming having to understand tape format, file systems, or loops. It also
+ contains the function interfaces to the catalog dll.
+
+ $Log: N:\LOGFILES\QTCXFACE.C_V $
+
+ Rev 1.6 12 Jan 1994 09:34:26 MikeP
+mark files as corrupt if they have corrupt bit set
+
+ Rev 1.5 07 Jan 1994 14:42:22 mikep
+change ifdef
+
+ Rev 1.4 06 Dec 1993 18:27:30 mikep
+deep pathes and unicode fixes
+
+ Rev 1.3 03 Nov 1993 09:02:54 MIKEP
+warning fixes
+
+ Rev 1.2 02 Nov 1993 18:02:06 MIKEP
+fix dll build
+
+ Rev 1.1 02 Nov 1993 17:49:16 MIKEP
+fix non-dll build
+
+ Rev 1.0 28 Oct 1993 14:49:32 MIKEP
+Initial revision.
+
+ Rev 1.0 28 Oct 1993 14:45:54 MIKEP
+Initial revision.
+
+****************************************************/
+
+#include <dos.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <io.h>
+#include <string.h>
+#include <time.h>
+#include <share.h>
+#include <malloc.h>
+
+#ifdef QTCDLL
+#include <windows.h>
+#endif
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "lp_msg.h"
+#include "fsys.h"
+#include "tfldefs.h"
+#include "qtc.h"
+#include "qtcxface.h"
+#include "dle.h"
+
+// unicode text macro
+
+#ifndef TEXT
+#define TEXT( x ) x
+#endif
+
+
+#ifdef QTCDLL
+
+typedef INT (APIENTRY *PFNQTC_BLOCKBAD)( QTC_BUILD_PTR );
+PFNQTC_BLOCKBAD pfnQTC_BlockBad;
+
+typedef INT (APIENTRY *PFNQTC_INIT)( CHAR_PTR, VM_HDL );
+PFNQTC_INIT pfnQTC_Init;
+
+typedef INT (APIENTRY *PFNQTC_FINISHBACKUP)( QTC_BUILD_PTR );
+PFNQTC_FINISHBACKUP pfnQTC_FinishBackup;
+
+typedef QTC_TAPE_PTR (APIENTRY *PFNQTC_GETFIRSTTAPE)( VOID );
+PFNQTC_GETFIRSTTAPE pfnQTC_GetFirstTape;
+
+typedef QTC_TAPE_PTR (APIENTRY *PFNQTC_GETNEXTTAPE)( QTC_TAPE_PTR );
+PFNQTC_GETNEXTTAPE pfnQTC_GetNextTape;
+
+typedef QTC_BSET_PTR (APIENTRY *PFNQTC_GETFIRSTBSET)( QTC_TAPE_PTR );
+PFNQTC_GETFIRSTBSET pfnQTC_GetFirstBset;
+
+typedef QTC_BSET_PTR (APIENTRY *PFNQTC_GETNEXTBSET)( QTC_BSET_PTR );
+PFNQTC_GETNEXTBSET pfnQTC_GetNextBset;
+
+typedef QTC_BSET_PTR (APIENTRY *PFNQTC_GETPREVBSET)( QTC_BSET_PTR );
+PFNQTC_GETPREVBSET pfnQTC_GetPrevBset;
+
+typedef VOID (APIENTRY *PFNQTC_ABORTBACKUP)( QTC_BUILD_PTR );
+PFNQTC_ABORTBACKUP pfnQTC_AbortBackup;
+
+typedef VOID (APIENTRY *PFNQTC_ABORTCATALOGING)( QTC_BUILD_PTR, BOOLEAN );
+PFNQTC_ABORTCATALOGING pfnQTC_AbortCataloging;
+
+typedef VOID (APIENTRY *PFNQTC_ADDDIRECTORYTOCATALOG)( QTC_BUILD_PTR, UINT64, CHAR_PTR, INT, UINT16, UINT16, UINT32, UINT32, BYTE_PTR, UINT );
+PFNQTC_ADDDIRECTORYTOCATALOG pfnQTC_AddDirectoryToCatalog;
+
+typedef VOID (APIENTRY *PFNQTC_ADDFILETOCATALOG)( QTC_BUILD_PTR, UINT64, CHAR_PTR, UINT16, UINT16, UINT32, UINT32, UINT32, BYTE_PTR, UINT );
+PFNQTC_ADDFILETOCATALOG pfnQTC_AddFileToCatalog;
+
+typedef BOOLEAN (APIENTRY *PFNQTC_ANYCATALOGFILES)( VOID );
+PFNQTC_ANYCATALOGFILES pfnQTC_AnyCatalogFiles;
+
+typedef INT (APIENTRY *PFNQTC_ANYSEARCHABLEBSETS)( VOID );
+PFNQTC_ANYSEARCHABLEBSETS pfnQTC_AnySearchableBsets;
+
+typedef INT (APIENTRY *PFNQTC_CLOSEQUERY)( QTC_QUERY_PTR );
+PFNQTC_CLOSEQUERY pfnQTC_CloseQuery;
+
+typedef VOID (APIENTRY *PFNQTC_DEINIT)( INT );
+PFNQTC_DEINIT pfnQTC_Deinit;
+
+typedef VOID (APIENTRY *PFNQTC_ENDOFTAPEREACHED)( QTC_BUILD_PTR, CHAR_PTR, CHAR_PTR, INT );
+PFNQTC_ENDOFTAPEREACHED pfnQTC_EndOfTapeReached;
+
+typedef QTC_BSET_PTR (APIENTRY *PFNQTC_FINDBSET)( UINT32, INT16, INT16 );
+PFNQTC_FINDBSET pfnQTC_FindBset;
+
+typedef INT (APIENTRY *PFNQTC_FREEBUILDHANDLE)( QTC_BUILD_PTR );
+PFNQTC_FREEBUILDHANDLE pfnQTC_FreeBuildHandle;
+
+typedef QTC_BUILD_PTR (APIENTRY *PFNQTC_GETBUILDHANDLE)( VOID );
+PFNQTC_GETBUILDHANDLE pfnQTC_GetBuildHandle;
+
+typedef VOID (APIENTRY *PFNQTC_GETFILENAME)( UINT32, INT16, CHAR_PTR );
+PFNQTC_GETFILENAME pfnQTC_GetFileName;
+
+typedef CHAR_PTR (APIENTRY *PFNQTC_GETFILENAMEONLY)( UINT32, INT16, CHAR_PTR );
+PFNQTC_GETFILENAMEONLY pfnQTC_GetFileNameOnly;
+
+typedef INT (APIENTRY *PFNQTC_GETFIRSTDIR)( QTC_QUERY_PTR );
+PFNQTC_GETFIRSTDIR pfnQTC_GetFirstDir;
+
+typedef INT (APIENTRY *PFNQTC_GETFIRSTITEM)( QTC_QUERY_PTR );
+PFNQTC_GETFIRSTITEM pfnQTC_GetFirstItem;
+
+typedef INT (APIENTRY *PFNQTC_GETFIRSTOBJ)( QTC_QUERY_PTR );
+PFNQTC_GETFIRSTOBJ pfnQTC_GetFirstObj;
+
+typedef UINT8 (APIENTRY *PFNQTC_GETMETHETAPECATVER)( UINT32, INT16, INT16 );
+PFNQTC_GETMETHETAPECATVER pfnQTC_GetMeTheTapeCatVer;
+
+typedef INT32 (APIENTRY *PFNQTC_GETMETHEVCBPBA)( UINT32, INT16, INT16 );
+PFNQTC_GETMETHEVCBPBA pfnQTC_GetMeTheVCBPBA;
+
+typedef INT (APIENTRY *PFNQTC_GETNEXTDIR)( QTC_QUERY_PTR );
+PFNQTC_GETNEXTDIR pfnQTC_GetNextDir;
+
+typedef INT (APIENTRY *PFNQTC_GETNEXTITEM)( QTC_QUERY_PTR );
+PFNQTC_GETNEXTITEM pfnQTC_GetNextItem;
+
+typedef INT (APIENTRY *PFNQTC_GETNEXTOBJ)( QTC_QUERY_PTR );
+PFNQTC_GETNEXTOBJ pfnQTC_GetNextObj;
+
+typedef INT (APIENTRY *PFNQTC_IMAGESCREWUP)( QTC_BUILD_PTR );
+PFNQTC_IMAGESCREWUP pfnQTC_ImageScrewUp;
+
+typedef QTC_QUERY_PTR (APIENTRY *PFNQTC_INITQUERY)( VOID );
+PFNQTC_INITQUERY pfnQTC_InitQuery;
+
+typedef INT (APIENTRY *PFNQTC_LOADBSETINFO)( CHAR_PTR, QTC_TAPE_PTR );
+PFNQTC_LOADBSETINFO pfnQTC_LoadBsetInfo;
+
+typedef QTC_HEADER_PTR (APIENTRY *PFNQTC_LOADHEADER)( QTC_BSET_PTR );
+PFNQTC_LOADHEADER pfnQTC_LoadHeader;
+
+typedef INT (APIENTRY *PFNQTC_PARTIALIZE)( UINT32, INT16, INT16 );
+PFNQTC_PARTIALIZE pfnQTC_Partialize;
+
+typedef VOID (APIENTRY *PFNQTC_PATCHVCB)( QTC_BUILD_PTR, UINT32, UINT32 );
+PFNQTC_PATCHVCB pfnQTC_PatchVCB;
+
+typedef VOID (APIENTRY *PFNQTC_REMOVETAPE)( UINT32, INT16 );
+PFNQTC_REMOVETAPE pfnQTC_RemoveTape;
+
+typedef INT (APIENTRY *PFNQTC_SEARCHFIRSTITEM)( QTC_QUERY_PTR );
+PFNQTC_SEARCHFIRSTITEM pfnQTC_SearchFirstItem;
+
+typedef INT (APIENTRY *PFNQTC_SEARCHNEXTITEM)( QTC_QUERY_PTR );
+PFNQTC_SEARCHNEXTITEM pfnQTC_SearchNextItem;
+
+typedef INT (APIENTRY *PFNQTC_SETSEARCHNAME)( QTC_QUERY_PTR, CHAR_PTR );
+PFNQTC_SETSEARCHNAME pfnQTC_SetSearchName;
+
+typedef INT (APIENTRY *PFNQTC_SETSEARCHPATH)( QTC_QUERY_PTR, CHAR_PTR, INT );
+PFNQTC_SETSEARCHPATH pfnQTC_SetSearchPath;
+
+typedef INT (APIENTRY *PFNQTC_STARTNEWBACKUP)( QTC_BUILD_PTR, CHAR_PTR, CHAR_PTR, CHAR_PTR, CHAR_PTR, CHAR_PTR, CHAR_PTR, CHAR_PTR, CHAR_PTR,
+ INT, INT, UINT32, UINT16, UINT16, UINT32, UINT32, UINT32, INT, INT, INT,
+ UINT32, UINT32, INT, INT, INT,
+ INT, INT, INT, INT, INT, INT, INT, INT, UINT16, UINT16, INT );
+
+PFNQTC_STARTNEWBACKUP pfnQTC_StartNewBackup;
+
+static HINSTANCE mwhLibQTC;
+
+
+VOID QTC_AbortBackup( QTC_BUILD_PTR pB )
+{
+ if ( pfnQTC_AbortBackup ) {
+ (*pfnQTC_AbortBackup)( pB );
+ }
+}
+
+VOID QTC_AbortCataloging( QTC_BUILD_PTR pB, BOOLEAN b )
+{
+ if ( pfnQTC_AbortCataloging ) {
+ (*pfnQTC_AbortCataloging)( pB, b );
+ }
+}
+
+VOID QTC_AddDirectoryToCatalog(
+QTC_BUILD_PTR build,
+UINT64 DisplaySize,
+CHAR_PTR szPath,
+INT nPathLength,
+UINT16 Date,
+UINT16 Time,
+UINT32 Attribute,
+UINT32 LBA,
+BYTE_PTR xtra_bytes,
+UINT xtra_size )
+{
+
+ if ( pfnQTC_AddDirectoryToCatalog ) {
+ (*pfnQTC_AddDirectoryToCatalog)( build,
+ DisplaySize,
+ szPath,
+ nPathLength,
+ Date,
+ Time,
+ Attribute,
+ LBA,
+ xtra_bytes,
+ xtra_size );
+ }
+
+}
+
+VOID QTC_AddFileToCatalog(
+QTC_BUILD_PTR build,
+UINT64 DisplaySize,
+CHAR_PTR szFile,
+UINT16 Date,
+UINT16 Time,
+UINT32 Attribute,
+UINT32 LBA,
+UINT32 AFPObject,
+BYTE_PTR xtra_bytes,
+UINT xtra_size )
+{
+ if ( pfnQTC_AddFileToCatalog ) {
+ (*pfnQTC_AddFileToCatalog)( build,
+ DisplaySize,
+ szFile,
+ Date,
+ Time,
+ Attribute,
+ LBA,
+ AFPObject,
+ xtra_bytes,
+ xtra_size );
+ }
+}
+
+BOOLEAN QTC_AnyCatalogFiles( VOID )
+{
+ if ( pfnQTC_AnyCatalogFiles ) {
+ return( (*pfnQTC_AnyCatalogFiles)() );
+ }
+ else {
+ return( FALSE );
+ }
+}
+
+INT QTC_AnySearchableBsets( VOID )
+{
+ if ( pfnQTC_AnySearchableBsets ) {
+ return( (*pfnQTC_AnySearchableBsets)() );
+ }
+ else {
+ return( FALSE );
+ }
+}
+
+INT QTC_CloseQuery( QTC_QUERY_PTR pQ )
+{
+ if ( pfnQTC_CloseQuery ) {
+ return( (*pfnQTC_CloseQuery)( pQ ) );
+ }
+}
+
+VOID QTC_Deinit( INT n )
+{
+
+ if ( pfnQTC_Deinit ) {
+ (*pfnQTC_Deinit)( n );
+ }
+}
+
+VOID QTC_EndOfTapeReached( QTC_BUILD_PTR pB, CHAR_PTR path, CHAR_PTR file, INT size )
+{
+ if ( pfnQTC_EndOfTapeReached ) {
+ (*pfnQTC_EndOfTapeReached)( pB, path, file, size );
+ }
+}
+
+QTC_BSET_PTR QTC_FindBset( UINT32 fid, INT16 tape, INT16 set )
+{
+ if ( pfnQTC_FindBset ) {
+ return( (*pfnQTC_FindBset)( fid, tape, set ) );
+ }
+ else {
+ return( (QTC_BSET_PTR)NULL );
+ }
+}
+
+INT QTC_FreeBuildHandle( QTC_BUILD_PTR pB )
+{
+ if ( pfnQTC_FreeBuildHandle ) {
+ return( (*pfnQTC_FreeBuildHandle)( pB ) );
+ }
+}
+
+QTC_BUILD_PTR QTC_GetBuildHandle( VOID )
+{
+ if ( pfnQTC_GetBuildHandle ) {
+ return( (*pfnQTC_GetBuildHandle)() );
+ }
+ else {
+ return( (QTC_BUILD_PTR)NULL );
+ }
+}
+
+VOID QTC_GetFileName( UINT32 fid, INT16 tape, CHAR_PTR name )
+{
+ if ( pfnQTC_GetFileName ) {
+ (*pfnQTC_GetFileName)( fid, tape, name );
+ }
+}
+
+CHAR_PTR QTC_GetFileNameOnly( UINT32 fid, INT16 tape, CHAR_PTR name )
+{
+ if ( pfnQTC_GetFileNameOnly ) {
+ return( (*pfnQTC_GetFileNameOnly)( fid, tape, name ) );
+ }
+ else {
+ return( (CHAR_PTR)NULL );
+ }
+}
+
+INT QTC_GetFirstDir( QTC_QUERY_PTR pQ )
+{
+ if ( pfnQTC_GetFirstDir ) {
+ return( (*pfnQTC_GetFirstDir)( pQ ) );
+ }
+ else {
+ return( QTC_FAILURE );
+ }
+}
+
+INT QTC_GetFirstItem( QTC_QUERY_PTR pQ )
+{
+ if ( pfnQTC_GetFirstItem ) {
+ return( (*pfnQTC_GetFirstItem)( pQ ) );
+ }
+ else {
+ return( QTC_FAILURE );
+ }
+}
+
+INT QTC_GetFirstObj( QTC_QUERY_PTR pQ )
+{
+ if ( pfnQTC_GetFirstObj ) {
+ return( (*pfnQTC_GetFirstObj)( pQ ) );
+ }
+ else {
+ return( QTC_FAILURE );
+ }
+}
+
+UINT8 QTC_GetMeTheTapeCatVer( UINT32 fid, INT16 tape, INT16 set )
+{
+ if ( pfnQTC_GetMeTheTapeCatVer ) {
+ return( (*pfnQTC_GetMeTheTapeCatVer)( fid, tape, set ) );
+ }
+ else {
+ return( (UINT8)0 );
+ }
+}
+
+INT32 QTC_GetMeTheVCBPBA( UINT32 fid, INT16 tape, INT16 set )
+{
+ if ( pfnQTC_GetMeTheVCBPBA ) {
+ return( (*pfnQTC_GetMeTheVCBPBA)( fid, tape, set ) );
+ }
+ else {
+ return( (INT32)0 );
+ }
+}
+
+INT QTC_GetNextDir( QTC_QUERY_PTR pQ )
+{
+ if ( pfnQTC_GetNextDir ) {
+ return( (*pfnQTC_GetNextDir)( pQ ) );
+ }
+ else {
+ return( QTC_FAILURE );
+ }
+}
+
+INT QTC_GetNextItem( QTC_QUERY_PTR pQ )
+{
+ if ( pfnQTC_GetNextItem ) {
+ return( (*pfnQTC_GetNextItem)( pQ ) );
+ }
+ else {
+ return( QTC_FAILURE );
+ }
+}
+
+INT QTC_GetNextObj( QTC_QUERY_PTR pQ )
+{
+ if ( pfnQTC_GetNextObj ) {
+ return( (*pfnQTC_GetNextObj)( pQ ) );
+ }
+ else {
+ return( QTC_FAILURE );
+ }
+}
+
+INT QTC_ImageScrewUp( QTC_BUILD_PTR pB )
+{
+ if ( pfnQTC_ImageScrewUp ) {
+ return( (*pfnQTC_ImageScrewUp)( pB ) );
+ }
+}
+
+QTC_QUERY_PTR QTC_InitQuery( VOID )
+{
+ if ( pfnQTC_InitQuery ) {
+ return( (*pfnQTC_InitQuery)() );
+ }
+ else {
+ return( (QTC_QUERY_PTR)NULL );
+ }
+}
+
+INT QTC_LoadBsetInfo( CHAR_PTR psz, QTC_TAPE_PTR pT )
+{
+ if ( pfnQTC_LoadBsetInfo ) {
+ return( (*pfnQTC_LoadBsetInfo)( psz, pT ) );
+ }
+ else {
+ return( QTC_FAILURE );
+ }
+}
+
+QTC_HEADER_PTR QTC_LoadHeader( QTC_BSET_PTR bset )
+{
+ if ( pfnQTC_LoadHeader ) {
+ return( (*pfnQTC_LoadHeader)( bset ) );
+ }
+ else {
+ return( (QTC_HEADER_PTR)NULL );
+ }
+}
+
+INT QTC_Partialize( UINT32 fid, INT16 tape, INT16 set )
+{
+ if ( pfnQTC_Partialize ) {
+ return( (*pfnQTC_Partialize)( fid, tape, set ) );
+ }
+}
+
+VOID QTC_PatchVCB( QTC_BUILD_PTR pB, UINT32 lba, UINT32 pba )
+{
+ if ( pfnQTC_PatchVCB ) {
+ (*pfnQTC_PatchVCB)( pB, lba, pba );
+ }
+}
+
+VOID QTC_RemoveTape( UINT32 fid, INT16 tape )
+{
+ if ( pfnQTC_RemoveTape ) {
+ (*pfnQTC_RemoveTape)( fid, tape );
+ }
+}
+
+INT QTC_SearchFirstItem( QTC_QUERY_PTR pQ )
+{
+ if ( pfnQTC_SearchFirstItem ) {
+ return( (*pfnQTC_SearchFirstItem)( pQ ) );
+ }
+}
+
+INT QTC_SearchNextItem( QTC_QUERY_PTR pQ)
+{
+ if ( pfnQTC_SearchNextItem ) {
+ return( (*pfnQTC_SearchNextItem)( pQ ) );
+ }
+}
+
+INT QTC_SetSearchName( QTC_QUERY_PTR pQ, CHAR_PTR file )
+{
+ if ( pfnQTC_SetSearchName ) {
+ return( (*pfnQTC_SetSearchName)( pQ, file ) );
+ }
+}
+
+INT QTC_SetSearchPath( QTC_QUERY_PTR pQ, CHAR_PTR path, INT len )
+{
+ if ( pfnQTC_SetSearchPath ) {
+ return( (*pfnQTC_SetSearchPath)( pQ, path, len ) );
+ }
+}
+
+INT QTC_StartNewBackup(
+QTC_BUILD_PTR build,
+CHAR_PTR szTapeName,
+CHAR_PTR szSetName,
+CHAR_PTR szUserName,
+CHAR_PTR szSetDescription,
+CHAR_PTR szDeviceName,
+CHAR_PTR szVolumeName,
+CHAR_PTR szTapePassword,
+CHAR_PTR szSetPassword,
+INT nTapePasswordLength,
+INT nSetPasswordLength,
+UINT32 TapeID,
+UINT16 TapeNum,
+UINT16 SetNum,
+UINT32 LBA,
+UINT32 PBA,
+UINT32 Attribute,
+INT FDDVersion,
+INT fFDDExists,
+INT fSMExists,
+UINT32 SetCatPBA,
+UINT32 SetCatSeqNumber,
+INT fSetCatInfoValid,
+INT fBlockContinued,
+INT nBackupType,
+INT OS_id,
+INT OS_ver,
+INT fImage,
+INT fNonVolume,
+INT fNoRedirect,
+INT fFutureVersion,
+INT fCompressed,
+INT fEncrypted,
+UINT16 Date,
+UINT16 Time,
+INT EncryptionAlgorithm )
+{
+ if ( pfnQTC_StartNewBackup ) {
+ return( (*pfnQTC_StartNewBackup)( build,
+ szTapeName,
+ szSetName,
+ szUserName,
+ szSetDescription,
+ szDeviceName,
+ szVolumeName,
+ szTapePassword,
+ szSetPassword,
+ nTapePasswordLength,
+ nSetPasswordLength,
+ TapeID,
+ TapeNum,
+ SetNum,
+ LBA,
+ PBA,
+ Attribute,
+ FDDVersion,
+ fFDDExists,
+ fSMExists,
+ SetCatPBA,
+ SetCatSeqNumber,
+ fSetCatInfoValid,
+ fBlockContinued,
+ nBackupType,
+ OS_id,
+ OS_ver,
+ fImage,
+ fNonVolume,
+ fNoRedirect,
+ fFutureVersion,
+ fCompressed,
+ fEncrypted,
+ Date,
+ Time,
+ EncryptionAlgorithm ) );
+ }
+ else {
+ return( QTC_FAILURE );
+ }
+}
+
+INT QTC_Init( CHAR_PTR psz, VM_HDL vmh )
+{
+
+ if ( pfnQTC_Init ) {
+ return( (*pfnQTC_Init)( psz, vmh ) );
+ }
+}
+
+INT QTC_BlockBad( QTC_BUILD_PTR pB )
+{
+ if ( pfnQTC_BlockBad ) {
+ return( (*pfnQTC_BlockBad)( pB ) );
+ }
+}
+
+
+INT QTC_FinishBackup( QTC_BUILD_PTR pB )
+{
+ if ( pfnQTC_FinishBackup ) {
+ return( (*pfnQTC_FinishBackup)( pB ) );
+ }
+ else {
+ return( QTC_FAILURE );
+ }
+}
+
+
+QTC_TAPE_PTR QTC_GetFirstTape( )
+{
+ if ( pfnQTC_GetFirstTape ) {
+ return( (*pfnQTC_GetFirstTape)() );
+ }
+ else {
+ return( (QTC_TAPE_PTR)NULL );
+ }
+}
+
+
+QTC_TAPE_PTR QTC_GetNextTape( QTC_TAPE_PTR pT )
+{
+ if ( pfnQTC_GetNextTape ) {
+ return( (*pfnQTC_GetNextTape)( pT ) );
+ }
+ else {
+ return( (QTC_TAPE_PTR)NULL );
+ }
+}
+
+QTC_BSET_PTR QTC_GetFirstBset( QTC_TAPE_PTR pT )
+{
+ if ( pfnQTC_GetFirstBset ) {
+ return( (*pfnQTC_GetFirstBset)( pT ) );
+ }
+ else {
+ return( (QTC_BSET_PTR)NULL );
+ }
+}
+
+QTC_BSET_PTR QTC_GetNextBset( QTC_BSET_PTR pBset )
+{
+ if ( pfnQTC_GetNextBset ) {
+ return( (*pfnQTC_GetNextBset)( pBset ) );
+ }
+ else {
+ return( (QTC_BSET_PTR)NULL );
+ }
+}
+
+QTC_BSET_PTR QTC_GetPrevBset( QTC_BSET_PTR pBset )
+{
+ if ( pfnQTC_GetPrevBset ) {
+ return( (*pfnQTC_GetPrevBset)( pBset ) );
+ }
+ else {
+ return( (QTC_BSET_PTR)NULL );
+ }
+}
+
+#endif
+
+// ------------------------------------------------------
+//
+// Code for both the DLL version and the regular version.
+//
+// ------------------------------------------------------
+
+INT QTC_LoadDLL( CHAR_PTR library_name )
+{
+
+#ifdef QTCDLL
+ if ( strlen ( library_name ) ) {
+
+ mwhLibQTC = LoadLibrary ( library_name );
+
+ if ( ! mwhLibQTC ) {
+ return (INT)0;
+ }
+ }
+
+ pfnQTC_AbortBackup = (PFNQTC_ABORTBACKUP) GetProcAddress( mwhLibQTC, "QTC_AbortBackup");
+ pfnQTC_AbortCataloging = (PFNQTC_ABORTCATALOGING) GetProcAddress( mwhLibQTC, "QTC_AbortCataloging");
+ pfnQTC_AddDirectoryToCatalog = (PFNQTC_ADDDIRECTORYTOCATALOG)GetProcAddress( mwhLibQTC, "QTC_AddDirectoryToCatalog");
+ pfnQTC_AddFileToCatalog = (PFNQTC_ADDFILETOCATALOG) GetProcAddress( mwhLibQTC, "QTC_AddFileToCatalog");
+ pfnQTC_AnyCatalogFiles = (PFNQTC_ANYCATALOGFILES) GetProcAddress( mwhLibQTC, "QTC_AnyCatalogFiles");
+ pfnQTC_AnySearchableBsets = (PFNQTC_ANYSEARCHABLEBSETS) GetProcAddress( mwhLibQTC, "QTC_AnySearchableBsets");
+ pfnQTC_CloseQuery = (PFNQTC_CLOSEQUERY) GetProcAddress( mwhLibQTC, "QTC_CloseQuery");
+ pfnQTC_Deinit = (PFNQTC_DEINIT) GetProcAddress( mwhLibQTC, "QTC_Deinit");
+ pfnQTC_EndOfTapeReached = (PFNQTC_ENDOFTAPEREACHED) GetProcAddress( mwhLibQTC, "QTC_EndOfTapeReached");
+ pfnQTC_FindBset = (PFNQTC_FINDBSET) GetProcAddress( mwhLibQTC, "QTC_FindBset");
+ pfnQTC_FreeBuildHandle = (PFNQTC_FREEBUILDHANDLE) GetProcAddress( mwhLibQTC, "QTC_FreeBuildHandle");
+ pfnQTC_GetBuildHandle = (PFNQTC_GETBUILDHANDLE) GetProcAddress( mwhLibQTC, "QTC_GetBuildHandle");
+ pfnQTC_GetFileName = (PFNQTC_GETFILENAME) GetProcAddress( mwhLibQTC, "QTC_GetFileName");
+ pfnQTC_GetFileNameOnly = (PFNQTC_GETFILENAMEONLY) GetProcAddress( mwhLibQTC, "QTC_GetFileNameOnly");
+ pfnQTC_GetFirstDir = (PFNQTC_GETFIRSTDIR) GetProcAddress( mwhLibQTC, "QTC_GetFirstDir");
+ pfnQTC_GetFirstItem = (PFNQTC_GETFIRSTITEM) GetProcAddress( mwhLibQTC, "QTC_GetFirstItem");
+ pfnQTC_GetFirstObj = (PFNQTC_GETFIRSTOBJ) GetProcAddress( mwhLibQTC, "QTC_GetFirstObj");
+ pfnQTC_GetMeTheTapeCatVer = (PFNQTC_GETMETHETAPECATVER) GetProcAddress( mwhLibQTC, "QTC_GetMeTheTapeCatVer");
+ pfnQTC_GetMeTheVCBPBA = (PFNQTC_GETMETHEVCBPBA) GetProcAddress( mwhLibQTC, "QTC_GetMeTheVCBPBA");
+ pfnQTC_GetNextDir = (PFNQTC_GETNEXTDIR) GetProcAddress( mwhLibQTC, "QTC_GetNextDir");
+ pfnQTC_GetNextItem = (PFNQTC_GETNEXTITEM) GetProcAddress( mwhLibQTC, "QTC_GetNextItem");
+ pfnQTC_GetNextObj = (PFNQTC_GETNEXTOBJ) GetProcAddress( mwhLibQTC, "QTC_GetNextObj");
+ pfnQTC_ImageScrewUp = (PFNQTC_IMAGESCREWUP) GetProcAddress( mwhLibQTC, "QTC_ImageScrewUp");
+ pfnQTC_InitQuery = (PFNQTC_INITQUERY) GetProcAddress( mwhLibQTC, "QTC_InitQuery");
+ pfnQTC_LoadBsetInfo = (PFNQTC_LOADBSETINFO) GetProcAddress( mwhLibQTC, "QTC_LoadBsetInfo");
+ pfnQTC_LoadHeader = (PFNQTC_LOADHEADER) GetProcAddress( mwhLibQTC, "QTC_LoadHeader");
+ pfnQTC_Partialize = (PFNQTC_PARTIALIZE) GetProcAddress( mwhLibQTC, "QTC_Partialize");
+ pfnQTC_PatchVCB = (PFNQTC_PATCHVCB) GetProcAddress( mwhLibQTC, "QTC_PatchVCB");
+ pfnQTC_RemoveTape = (PFNQTC_REMOVETAPE) GetProcAddress( mwhLibQTC, "QTC_RemoveTape");
+ pfnQTC_SearchFirstItem = (PFNQTC_SEARCHFIRSTITEM) GetProcAddress( mwhLibQTC, "QTC_SearchFirstItem");
+ pfnQTC_SearchNextItem = (PFNQTC_SEARCHNEXTITEM) GetProcAddress( mwhLibQTC, "QTC_SearchNextItem");
+ pfnQTC_SetSearchName = (PFNQTC_SETSEARCHNAME) GetProcAddress( mwhLibQTC, "QTC_SetSearchName");
+ pfnQTC_SetSearchPath = (PFNQTC_SETSEARCHPATH) GetProcAddress( mwhLibQTC, "QTC_SetSearchPath");
+ pfnQTC_StartNewBackup = (PFNQTC_STARTNEWBACKUP) GetProcAddress( mwhLibQTC, "QTC_StartNewBackup");
+ pfnQTC_BlockBad = (PFNQTC_BLOCKBAD) GetProcAddress( mwhLibQTC, "QTC_BlockBad");
+ pfnQTC_Init = (PFNQTC_INIT) GetProcAddress( mwhLibQTC, "QTC_Init");
+ pfnQTC_FinishBackup = (PFNQTC_FINISHBACKUP) GetProcAddress( mwhLibQTC, "QTC_FinishBackup");
+ pfnQTC_GetFirstTape = (PFNQTC_GETFIRSTTAPE) GetProcAddress( mwhLibQTC, "QTC_GetFirstTape");
+ pfnQTC_GetNextTape = (PFNQTC_GETNEXTTAPE) GetProcAddress( mwhLibQTC, "QTC_GetNextTape");
+ pfnQTC_GetFirstBset = (PFNQTC_GETFIRSTBSET) GetProcAddress( mwhLibQTC, "QTC_GetFirstBset");
+ pfnQTC_GetNextBset = (PFNQTC_GETNEXTBSET) GetProcAddress( mwhLibQTC, "QTC_GetNextBset");
+ pfnQTC_GetPrevBset = (PFNQTC_GETPREVBSET) GetProcAddress( mwhLibQTC, "QTC_GetPrevBset");
+#else
+ (void)library_name;
+
+#endif
+
+ return (INT)1;
+
+}
+
+INT QTC_UnLoadDLL( )
+{
+#ifdef QTCDLL
+ if ( mwhLibQTC ) {
+ FreeLibrary ( mwhLibQTC );
+ mwhLibQTC = 0;
+ }
+
+#endif
+ return SUCCESS;
+}
+
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+ Start the catalog off building data for a new Bset
+
+ RETURNS :
+
+**********************/
+
+INT QTC_StartBackup( QTC_BUILD_PTR build, DBLK_PTR dblk )
+{
+ CHAR_PTR szTapeName;
+ CHAR_PTR szSetName;
+ CHAR_PTR szUserName;
+ CHAR_PTR szSetDescription;
+ CHAR_PTR szDeviceName = NULL;
+ CHAR_PTR szVolumeName;
+ CHAR_PTR szTapePassword;
+ CHAR_PTR szSetPassword;
+ INT nTapePasswordLength;
+ INT nSetPasswordLength;
+ UINT32 TapeID;
+ UINT16 TapeNum;
+ UINT16 SetNum;
+ UINT32 LBA;
+ UINT32 PBA;
+ UINT32 Attribute;
+ INT FDDVersion;
+ INT fFDDExists = FALSE;
+ INT fSMExists = FALSE;
+ UINT32 SetCatPBA;
+ UINT32 SetCatSeqNumber;
+ INT fSetCatInfoValid = FALSE;
+ INT fBlockContinued = FALSE;
+ INT nBackupType;
+ INT OS_id;
+ INT OS_ver;
+ INT fImage = FALSE;
+ INT fNonVolume = FALSE;
+ INT fNoRedirect = FALSE;
+ INT fFutureVersion = FALSE;
+ INT fCompressed = FALSE;
+ INT fEncrypted = FALSE;
+ UINT16 Date;
+ UINT16 Time;
+ INT EncryptionAlgorithm;
+ INT ret_val ;
+
+ nTapePasswordLength = FS_SizeofTapePswdInVCB( dblk );
+ nSetPasswordLength = FS_SizeofSetPswdInVCB( dblk );
+
+ szTapeName = (CHAR *)FS_ViewTapeNameInVCB( dblk );
+ szSetName = (CHAR *)FS_ViewSetNameInVCB( dblk );
+ szSetDescription = (CHAR *)FS_ViewSetDescriptInVCB( dblk );
+
+ TapeID = FS_ViewTapeIDInVCB( dblk );
+ TapeNum = FS_ViewTSNumInVCB( dblk );
+ SetNum = FS_ViewBSNumInVCB( dblk );
+
+ Attribute = FS_GetAttribFromVCB( dblk ) ;
+
+ FDDVersion = FS_GetOnTapeCatVer( dblk );
+
+ if ( FS_IsSetCatInfoValid( dblk ) ) {
+
+ fSetCatInfoValid = TRUE;
+ SetCatSeqNumber = FS_GetSetCatSeqNumberInVCB( dblk );
+ SetCatPBA = FS_GetSetCatPbaInVCB( dblk );
+ }
+
+ if ( Attribute & VCB_FUTURE_VER_BIT ) {
+ fFutureVersion = TRUE;
+ }
+ if ( Attribute & VCB_ENCRYPTED_BIT ) {
+ fEncrypted = TRUE;
+ }
+ if ( Attribute & VCB_COMPRESSED_BIT ) {
+ fCompressed = TRUE;
+ }
+
+ if ( FS_GetOnTapeCatLevel( dblk ) == TCL_FULL ) {
+ fFDDExists = TRUE;
+ fSMExists = TRUE;
+ }
+
+ if ( FS_GetOnTapeCatLevel( dblk ) == TCL_PARTIAL ) {
+ fSMExists = TRUE;
+ }
+
+ if ( FS_IsBlockContinued( dblk ) ) {
+ fBlockContinued = TRUE;
+ }
+
+#ifdef OS_NLM
+ if ( gb_QTC.cat_user ) {
+ szUserName = gb_QTC.cat_user;
+ } else {
+ szUserName = TEXT( "" );
+ }
+#else
+ szUserName = (CHAR_PTR)FS_ViewUserNameInVCB( dblk );
+#endif
+
+#ifdef OS_NLM
+ if ( FS_SizeofDevNameInVCB( dblk ) ) {
+ szVolumeName = FS_ViewDevNameInVCB( dblk );
+ } else {
+ szVolumeName = FS_ViewVolNameInVCB( dblk );
+ }
+#else
+ szVolumeName = (CHAR_PTR)FS_ViewVolNameInVCB( dblk );
+#endif
+
+ szTapePassword = (CHAR *)FS_ViewTapePasswordInVCB( dblk );
+ szSetPassword = (CHAR *)FS_ViewSetPswdInVCB( dblk );
+
+ EncryptionAlgorithm = FS_ViewPswdEncryptInVCB( dblk );
+
+ nBackupType = QTC_NORM_BACKUP;
+
+ if ( FS_GetAttribFromVCB( dblk ) & VCB_COPY_SET ) {
+ nBackupType = QTC_COPY_BACKUP;
+ }
+ if ( FS_GetAttribFromVCB( dblk ) & VCB_DIFFERENTIAL_SET ) {
+ nBackupType = QTC_DIFF_BACKUP;
+ }
+ if ( FS_GetAttribFromVCB( dblk ) & VCB_INCREMENTAL_SET ) {
+ nBackupType = QTC_INCR_BACKUP;
+ }
+ if ( FS_GetAttribFromVCB( dblk ) & VCB_DAILY_SET ) {
+ nBackupType = QTC_DAIL_BACKUP;
+ }
+
+ // init other stuff for this bset
+
+ LBA = FS_ViewLBAinDBLK( dblk );
+ PBA = FS_ViewPBAinVCB( dblk );
+
+ Date = ConvertDateDOS( FS_ViewBackupDateInVCB( dblk ) );
+ Time = ConvertTimeDOS( FS_ViewBackupDateInVCB( dblk ) );
+
+ FS_GetOSid_verFromVCB( dblk, (UINT16_PTR)&OS_id, (UINT16_PTR)&OS_ver );
+
+#ifndef OS_WIN32
+#ifndef OEM_MSOFT
+ if ( FS_IsNoRedirectRestore( dblk ) ) {
+ fNoRedirect = TRUE;
+ }
+
+ if ( FS_IsNonVolume( dblk ) ) {
+ fNonVolume = TRUE;
+ }
+#endif
+#endif
+
+ if ( OS_id == FS_PC_IMAGE ) {
+ fImage = TRUE;
+ }
+
+ build->num_files = FS_ViewNumFiles( dblk ) ;
+ build->num_dirs = FS_ViewNumDirs( dblk ) ;
+ build->num_corrupt_files = FS_ViewNumCorrupt( dblk ) ;
+
+
+ switch ( QTC_StartNewBackup( build,
+ szTapeName,
+ szSetName,
+ szUserName,
+ szSetDescription,
+ szDeviceName,
+ szVolumeName,
+ szTapePassword,
+ szSetPassword,
+ nTapePasswordLength,
+ nSetPasswordLength,
+ TapeID,
+ TapeNum,
+ SetNum,
+ LBA,
+ PBA,
+ Attribute,
+ FDDVersion,
+ fFDDExists,
+ fSMExists,
+ SetCatPBA,
+ SetCatSeqNumber,
+ fSetCatInfoValid,
+ fBlockContinued,
+ nBackupType,
+ OS_id,
+ OS_ver,
+ fImage,
+ fNonVolume,
+ fNoRedirect,
+ fFutureVersion,
+ fCompressed,
+ fEncrypted,
+ Date,
+ Time,
+ EncryptionAlgorithm ) ) {
+
+ case QTC_OPERATION_COMPLETE:
+ ret_val = OPERATION_COMPLETE;
+ break;
+
+ case QTC_SKIP_TO_NEXT_BSET:
+ ret_val = SKIP_TO_NEXT_BSET;
+ break;
+
+ case QTC_SKIP_TO_NEXT_ITEM:
+ ret_val = SKIP_TO_NEXT_ITEM;
+ break;
+
+ }
+
+ return( ret_val );
+
+}
+
+
+VOID QTC_PatchContinuationVCB( QTC_BUILD_PTR build, DBLK_PTR vcb )
+{
+ if ( build != NULL ) {
+
+ if ( build->header != NULL ) {
+
+ QTC_PatchVCB( build, FS_ViewLBAinDBLK( vcb ), FS_ViewPBAinVCB( vcb ) );
+
+ }
+ }
+}
+
+
+VOID QTC_EndOfTape(
+QTC_BUILD_PTR build,
+DBLK_PTR vcb,
+DBLK_PTR ddb,
+DBLK_PTR fdb,
+FSYS_HAND fsh )
+{
+ CHAR_PTR szFile = NULL;
+ CHAR_PTR szPath = NULL;
+ INT nPathLength = 0;
+
+
+ CHAR buffer[ 2048 ];
+
+ (void)vcb;
+
+ // Every now and then we get empty ones, that aren't null.
+
+ if ( fdb ) {
+ if ( FS_GetBlockType( fdb ) != BT_FDB ) {
+ fdb = NULL;
+ }
+ else {
+ FS_GetOSFnameFromFDB( fsh, fdb, buffer );
+ szFile = (CHAR_PTR)malloc( strsize( buffer ) * sizeof(CHAR) );
+ if ( szFile ) {
+ strcpy( szFile, buffer );
+ }
+ }
+ }
+
+ if ( ddb ) {
+ if ( FS_GetBlockType( ddb ) != BT_DDB ) {
+ ddb = NULL;
+ }
+ else {
+ nPathLength = FS_SizeofOSPathInDDB( fsh, ddb );
+ szPath = (CHAR_PTR)malloc( nPathLength );
+ if ( szPath ) {
+ FS_GetOSPathFromDDB( fsh, ddb, szPath );
+ }
+ }
+ }
+
+ QTC_EndOfTapeReached( build, szFile, szPath, nPathLength );
+
+ if ( szFile ) {
+ free( szFile );
+ }
+ if ( szPath ) {
+ free( szPath );
+ }
+}
+
+VOID FillFakeInfo( QTC_BUILD_PTR build, CHAR *buff, INT nPathLength, UINT64 DisplaySize, UINT16 Date, UINT16 Time, UINT32 Attribute, UINT32 LBA, BYTE *xtra_bytes, UINT xtra_size );
+
+VOID QTC_AddToCatalog(
+QTC_BUILD_PTR build,
+DBLK_PTR dblk,
+FSYS_HAND fsh,
+BOOLEAN split,
+BYTE_PTR xtra_bytes,
+UINT xtra_size )
+{
+ UINT32 Attribute;
+ UINT32 LBA;
+ UINT16 Date;
+ UINT16 Time;
+ INT nPathLength; // path length in characters
+ UINT64 DisplaySize;
+ CHAR *buffer;
+ OBJECT_TYPE ObjectType;
+ DATE_TIME datetime;
+
+ (void)split;
+
+ switch ( FS_GetBlockType( dblk ) ) {
+
+ case BT_FDB:
+
+ DisplaySize = FS_GetDisplaySizeFromDBLK( fsh, dblk );
+
+ buffer = malloc( 1024 );
+
+ if ( buffer ) {
+
+ FS_GetOSFnameFromFDB( fsh, dblk, buffer );
+ FS_GetMDateFromDBLK( fsh, dblk, &datetime );
+ FS_GetObjTypeDBLK( fsh, dblk, &ObjectType );
+
+ Date = ConvertDateDOS( &datetime );
+ Time = ConvertTimeDOS( &datetime );
+
+ Attribute = FS_GetAttribFromDBLK( fsh, dblk );
+ LBA = FS_ViewLBAinDBLK( dblk );
+
+ if ( ObjectType == AFP_OBJECT ) {
+ ObjectType = TRUE;
+ }
+ else {
+ ObjectType = FALSE;
+ }
+
+ QTC_AddFileToCatalog( build, DisplaySize, buffer, Date, Time, Attribute, LBA, ObjectType, xtra_bytes, xtra_size );
+
+ if ( Attribute & OBJ_CORRUPT_BIT ) {
+ QTC_BlockBad( build );
+ }
+
+ free( buffer );
+ }
+ break;
+
+ case BT_DDB:
+
+ DisplaySize = FS_GetDisplaySizeFromDBLK( fsh, dblk );
+
+ nPathLength = FS_SizeofOSPathInDDB( fsh, dblk );
+
+ buffer = malloc( nPathLength * sizeof(CHAR) );
+
+ if ( buffer ) {
+
+ FS_GetOSPathFromDDB( fsh, dblk, buffer );
+ FS_GetMDateFromDBLK( fsh, dblk, &datetime );
+
+ Date = ConvertDateDOS( &datetime );
+ Time = ConvertTimeDOS( &datetime );
+
+ Attribute = FS_GetAttribFromDBLK( fsh, dblk );
+ LBA = FS_ViewLBAinDBLK( dblk );
+
+ QTC_AddDirectoryToCatalog( build, DisplaySize, buffer, nPathLength, Date, Time, Attribute, LBA, xtra_bytes, xtra_size );
+
+ // FillFakeInfo( build, buffer, nPathLength, DisplaySize, Date, Time, Attribute, LBA, xtra_bytes, xtra_size );
+
+ if ( Attribute & OBJ_CORRUPT_BIT ) {
+ QTC_BlockBad( build );
+ }
+
+ free( buffer );
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+VOID FillFakeInfo( QTC_BUILD_PTR build, CHAR *buff, INT nPathLength, UINT64 DisplaySize, UINT16 Date, UINT16 Time, UINT32 Attribute, UINT32 LBA, BYTE *xtra_bytes, UINT xtra_size )
+{
+ CHAR buffer[ 8192 ];
+
+ if ( nPathLength > 2 ) {
+
+ memcpy( buffer, buff, nPathLength * sizeof(CHAR) );
+
+ while ( nPathLength < 4096 ) {
+
+ strcpy( &buffer[ nPathLength / sizeof(CHAR) ], TEXT("bark like a dog") );
+ nPathLength += 32;
+ }
+
+ QTC_AddDirectoryToCatalog( build, DisplaySize, buffer, nPathLength, Date, Time, Attribute, LBA, xtra_bytes, xtra_size );
+ }
+
+}
+
diff --git a/private/utils/ntbackup/src/queues.c b/private/utils/ntbackup/src/queues.c
new file mode 100644
index 000000000..c2199bb78
--- /dev/null
+++ b/private/utils/ntbackup/src/queues.c
@@ -0,0 +1,914 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: queues.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: ALL of the code that deals with queues in one simple
+ easy to deal with place.
+
+
+ $Log: M:/LOGFILES/QUEUES.C_V $
+
+ Rev 1.3 24 Nov 1993 14:51:36 BARRY
+Unicode fixes
+
+ Rev 1.2 08 Sep 1993 12:37:22 JOHNES
+Added TopOfStack_with_0_values for those cases where you want to know if the
+stack is empty or the next value is just 0.
+
+
+ Rev 1.1 17 Nov 1992 22:18:32 DAVEV
+unicode fixes
+
+ Rev 1.0 30 Oct 1992 12:47:26 STEVEN
+Initial revision.
+
+
+**/
+/* begin include list */
+
+/* $end$ include list */
+#include <stdlib.h>
+
+#include "stdtypes.h"
+#include "queues.h"
+#include "cli.h"
+
+static INT16 ElementCount( Q_HEADER_PTR q_hdr, Q_ELEM_PTR q_el ) ;
+
+/**/
+/**
+
+ Name: DeQueueElem
+
+ Description: Dequeue an element for the specified queue.
+
+ Modified: 8/9/1989 13:42:20
+
+ Returns: A pointer to the element that was dequeue'd or a null
+ if the queue was empty.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+Q_ELEM_PTR DeQueueElem(
+Q_HEADER_PTR queue ) /* The queue */
+{
+ Q_ELEM_PTR element = NULL ;
+ BOOLEAN prev_state;
+
+ prev_state = DisableInterrupts() ;
+
+
+ if( ( element = queue->q_head ) != NULL ) {
+ queue->q_count-- ;
+ if( queue->q_tail == element ) {
+ queue->q_tail = NULL ;
+ }
+ queue->q_head = element->q_next ;
+ if( element->q_next != NULL ) {
+ element->q_next->q_prev = NULL ;
+ element->q_next = NULL ;
+ }
+ element->q_next = NULL; /* let's practice safe coding */
+ element->q_prev = NULL;
+ }
+
+ RestoreInterruptState( prev_state );
+ return( element ) ;
+
+}
+
+
+/**/
+/**
+
+ Name: EnQueueElem
+
+ Description: Enqueues an element on the specified queue. If the priority
+ field is TRUE, this function will enqueue the element in sorted
+ order based on the "q_priority" field in the element structure.
+
+ Modified: 8/9/1989 13:38:31
+
+ Returns: A pointer to that element.
+
+ Notes:
+
+ See also: $/SEE( DeQeueuElem )$
+
+ Declaration:
+
+**/
+
+Q_ELEM_PTR EnQueueElem(
+Q_HEADER_PTR queue, /* The destination queue */
+Q_ELEM_PTR element, /* The element */
+BOOLEAN w_priority ) /* Enqueue w/ priority */
+{
+ Q_ELEM_PTR telem ;
+ BOOLEAN prev_state;
+
+ prev_state = DisableInterrupts() ;
+
+
+ /* If priority insertion is not set or there are no elements on
+ the stack. */
+ if( !w_priority || !queue->q_count ) {
+ element->q_next = NULL ; /* end of queue */
+ element->q_prev = queue->q_tail ; /* previous = queue's old tail */
+ if( !QueueCount( queue ) ) {
+ queue->q_head = element ; /* 0 elems .. element is head */
+ } else {
+ queue->q_tail->q_next = element ; /* old tail's next is elem */
+ }
+ queue->q_tail = element ; /* tail is always element */
+ } else {
+ telem = QueueHead( queue ) ; /* set temp to head */
+ while ( telem ) {
+ if( element->q_priority <= telem->q_priority ) {
+ element->q_next = telem ;
+ element->q_prev = telem->q_prev ;
+ if( !telem->q_prev ) {
+ queue->q_head = element ;
+ } else {
+ telem->q_prev->q_next = element ;
+ }
+ telem->q_prev = element ;
+ /* takes care of if element is being inserted
+ at head */
+ break ;
+ }
+ telem = QueueNext( telem ) ;
+ }
+ /* insert at tail */
+ if( !telem ) {
+ element->q_next = NULL ;
+ element->q_prev = queue->q_tail ;
+ queue->q_tail->q_next = element ;
+ queue->q_tail = element ;
+ }
+ }
+ queue->q_count++ ;
+ element->q_element = queue->q_magic++ ;
+
+ RestoreInterruptState( prev_state );
+ return( element ) ;
+
+}
+
+
+/**/
+/**
+
+ Name: FindQueueElem
+
+ Description: Finds the specified queue element in a queue.
+
+ Modified: 8/9/1989 13:50:33
+
+ Returns: A NULL if it was not found, and a pointer to the element
+ if it was.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+Q_ELEM_PTR FindQueueElem(
+Q_HEADER_PTR queue ,
+Q_ELEM_PTR element )
+{
+ INT16 i ;
+ Q_ELEM_PTR next_elem ;
+
+ next_elem = QueueHead( queue ) ;
+
+ for( i = 0 ; i < QueueCount( queue ) ; i++ ) {
+ if( next_elem == element ) {
+ return( next_elem ) ;
+ }
+ next_elem = QueueNext( next_elem ) ;
+ }
+
+ return( NULL ) ;
+
+}
+
+
+/**/
+/**
+
+ Name: InitQueue
+
+ Description: Initializes a queue header
+
+ Modified: 7/12/1989
+
+ Returns: It's a VOID dummy
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+VOID InitQueue(
+Q_HEADER_PTR queue )
+{
+ queue->q_head = queue->q_tail = NULL ;
+ queue->q_count = 0 ;
+ queue->q_active = TRUE ;
+ queue->q_magic = 1 ;
+
+ return ;
+}
+
+
+/**/
+/**
+
+ Name: InitQelem
+
+ Description: Initialises a queue element.
+
+ Modified: 8/9/1989 13:37:8
+
+ Returns: Nothing
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+VOID InitQElem(
+Q_ELEM_PTR element )
+{
+ element->q_prev = element->q_next = NULL ;
+ element->q_element = 0 ;
+ element->q_priority = 0L ;
+
+ return ;
+}
+
+
+/**/
+/**
+
+ Name: InsertElem
+
+ Description: Inserts an element into a queue. If the "boa" field is set
+ to 0 ( defined as BEFORE in queues.h ), this will insert the
+ element before the anchor element. If it is set to 1 ( defined
+ as AFTER in queues.h ), it will insert it after.
+
+ Modified: 8/9/1989 13:44:55
+
+ Returns: A pointer to the inserted element.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+Q_ELEM_PTR InsertElem(
+Q_HEADER_PTR q ,
+Q_ELEM_PTR anchor ,
+Q_ELEM_PTR elem ,
+UINT16 boa )
+{
+
+ if( boa == BEFORE ) {
+ if( anchor->q_prev != NULL ) {
+ elem->q_prev = anchor->q_prev ;
+ anchor->q_prev->q_next = elem ;
+ }
+ else {
+ elem->q_prev = NULL;
+ q->q_head = elem;
+ }
+ elem->q_next = anchor ;
+ anchor->q_prev = elem ;
+ }
+ else /* boa == AFTER */ {
+
+ if( anchor->q_next != NULL ) {
+ elem->q_next = anchor->q_next ;
+ anchor->q_next->q_prev = elem ;
+ }
+ else {
+ elem->q_next = NULL ;
+ q->q_tail = elem;
+ }
+ elem->q_prev = anchor ;
+ anchor->q_next = elem ;
+ }
+ elem->q_element = q->q_magic++;
+ q->q_count++ ;
+
+ return elem ;
+
+}
+
+
+/**/
+/**
+
+ Name: MoveQueue
+
+ Description: Moves the elements of the "from_queue" to "to_queue".
+
+ Modified: 10/16/1989 10:52:28
+
+ Returns: Nothing.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+VOID MoveQueue(
+Q_HEADER_PTR from_queue,
+Q_HEADER_PTR to_queue )
+{
+ while( from_queue->q_count ) {
+ EnQueueElem( to_queue, DeQueueElem( from_queue ), FALSE ) ;
+ }
+ return ;
+}
+
+
+/**/
+/**
+
+ Name: PopElem
+
+ Description: Functions exactly like DeQueueElem, returns a pointer to the
+ head of the queue, and deletes the head from off the queue.
+
+ Modified: 8/9/1989 13:54:34
+
+ Returns: A pointer to the element that was popped, or NULL if the
+ list is empty.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+Q_ELEM_PTR PopElem(
+Q_HEADER_PTR queue )
+{
+ return( DeQueueElem( queue ) ) ;
+}
+
+/**/
+/**
+
+ Name: PushElem
+
+ Description: This makes a queue function like a stack. Unlike EnQueueElem()
+ which puts the element at the tail of the specified queue,
+ PushElem() puts the element on the head of the queue.
+
+ Modified: 8/9/1989 13:52:59
+
+ Returns: Nothing
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+VOID PushElem(
+Q_HEADER_PTR queue,
+Q_ELEM_PTR element )
+{
+ BOOLEAN prev_state;
+
+ prev_state = DisableInterrupts() ;
+
+ element->q_prev = NULL ;
+ element->q_next = QueueHead( queue ) ;
+ element->q_element = queue->q_magic++ ;
+ if( !QueueCount( queue ) ) {
+ queue->q_tail = element ;
+ } else {
+ queue->q_head->q_prev = element ;
+ }
+ queue->q_head = element ;
+ queue->q_count++ ;
+
+ RestoreInterruptState( prev_state );
+ return ;
+}
+
+/**/
+/**
+
+ Name: RemoveElem
+
+ Description: Routine for removing an element from a queue.
+ No error checking is performed and the element is assumed
+ to be a valid one. Currently this routine is used by
+ RemoveQueueElem() and SearchQueue().
+
+
+ Modified: 10/16/1989 10:49:46
+
+ Returns: Nothing.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+VOID RemoveElem(
+Q_HEADER_PTR queue,
+Q_ELEM_PTR element )
+{
+ queue->q_count-- ;
+
+ if( queue->q_head == element ) {
+ queue->q_head = QueueNext( element ) ;
+ }
+ if( queue->q_tail == element ) {
+ queue->q_tail = QueuePrev( element ) ;
+ }
+ if( element->q_prev != NULL ) {
+ element->q_prev->q_next = QueueNext( element ) ;
+ }
+ if( element->q_next != NULL ) {
+ element->q_next->q_prev = QueuePrev( element ) ;
+ }
+ element->q_prev = element->q_next = NULL ;
+
+ return ;
+}
+
+
+/**/
+/**
+
+ Name: RemoveQueueElem
+
+ Description: Removes a queue element from a queue.
+
+ Modified: 8/9/1989 13:48:48
+
+ Returns: Returns SUCCESS if the element was not removed, and FAILURE
+ if it was not.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+BOOLEAN RemoveQueueElem(
+Q_HEADER_PTR queue,
+Q_ELEM_PTR element )
+{
+ Q_ELEM_PTR temp ;
+ BOOLEAN ret = FAILURE ;
+ BOOLEAN prev_state;
+
+ prev_state = DisableInterrupts() ;
+
+ for( temp = QueueHead( queue ) ;
+ ( ( temp != NULL ) && ( element != temp ) ) ;
+ temp = QueueNext( temp ) ) ;
+ if( temp != NULL ) {
+ RemoveElem( queue, element ) ;
+ ret = SUCCESS ;
+ }
+
+ RestoreInterruptState( prev_state );
+ return ret ;
+}
+
+
+/**/
+/**
+
+ Name: SortQueue
+
+ Description: This function sorts the specified queue into order. A pointer
+ to the compare rountine is passed to the function. This compare
+ routine must follow the following conventions:
+
+ 1) It takes two Q_ELEM pointers ( Q_ELEM_PTR ) as its
+ arguements.
+
+ 2) It returns a <0 for parm1 < parm2, 0 for parm1 == parm2,
+ and >0 for parm1 > parm2.
+
+ 3) This function is slower than molasses on the north pole.
+ You should build/maintain your queue in order so that you
+ never have to sort it.
+
+ Modified: 10/16/1989 10:38:47
+
+ Returns: Nothing
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+VOID SortQueue(
+Q_HEADER_PTR queue,
+INT16 ( *cmp )( Q_ELEM_PTR, Q_ELEM_PTR ) )
+{
+ INT16 i ;
+ INT16 end ;
+ BOOLEAN any_swaps ;
+ Q_ELEM_PTR cur_el, temp ;
+
+ end = QueueCount( queue );
+ if( end > 1 ) {
+ do {
+ cur_el = QueueHead( queue ) ;
+ any_swaps = FALSE ;
+ for( i = 1 ; i < end; i++ ) {
+ if( (*cmp)( cur_el, QueueNext(cur_el)) > 0) {
+ temp = QueueNext( cur_el );
+
+ if ( QueueHead( queue ) == cur_el ) {
+ queue->q_head = temp;
+ }
+ else {
+ QueuePrev( cur_el )->q_next = temp ;
+ }
+ temp->q_prev = QueuePrev( cur_el );
+
+ if ( QueueTail( queue ) == temp ) {
+ queue->q_tail = cur_el;
+ }
+ else {
+ QueueNext( temp )->q_prev = cur_el ;
+ }
+ cur_el->q_next = QueueNext( temp );
+
+ temp->q_next = cur_el;
+ cur_el->q_prev = temp;
+
+
+ any_swaps = TRUE ;
+ }
+ else {
+ cur_el = QueueNext( cur_el );
+ }
+ }
+ end -- ;
+ } while( any_swaps ) ;
+ }
+ return ;
+}
+
+/**/
+/**
+
+ Name: SplitQueue( )
+
+ Description: Splits a queue into two queues at a specified element.
+
+ Modified: 2/21/1990
+
+ Returns: Pointer to the new_Q
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+
+Q_HEADER_PTR SplitQueue(
+Q_HEADER_PTR old_Q, /* I/O - the original queue */
+Q_ELEM_PTR split, /* I - the element to split at */
+Q_HEADER_PTR new_Q ) /* O - a queue header for the new queue */
+
+{
+ BOOLEAN prev_state ; /* saves interrupt enable state */
+ INT16 q_ct ; /* saves current count in queue */
+
+ InitQueue( new_Q ) ;
+
+ if ( split ) {
+ prev_state = DisableInterrupts( ) ;
+
+ if ( old_Q->q_head != split ) {
+ q_ct = QueueCount( old_Q ) ;
+ old_Q->q_count = ElementCount( old_Q, split ) ;
+
+ new_Q->q_tail = old_Q->q_tail ;
+
+ if ( old_Q->q_tail = split->q_prev ) {
+ old_Q->q_tail->q_next = NULL ;
+ }
+ split->q_prev = NULL ;
+
+ new_Q->q_head = split ;
+ new_Q->q_count = q_ct - old_Q->q_count ;
+ new_Q->q_magic = old_Q->q_magic ;
+
+ } else {
+ *new_Q = *old_Q ;
+ InitQueue( old_Q ) ;
+ }
+
+ RestoreInterruptState( prev_state ) ;
+ }
+
+ return new_Q ;
+}
+
+/**/
+/**
+
+ Name: ElementCount
+
+ Description: Finds the number of elements in the queue PRECEDING a
+ specific queue element.
+
+ Modified: 2/21/1990
+
+ Returns: The number of elements found preceding the element.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+
+static INT16 ElementCount(
+Q_HEADER_PTR q_hdr,
+Q_ELEM_PTR q_el )
+{
+ Q_ELEM_PTR tmp ;
+ INT16 ct = 0 ;
+
+ for ( tmp = q_hdr->q_head ; tmp != NULL && tmp != q_el ; tmp = tmp->q_next ) {
+ ct++ ;
+ }
+
+ return ct ;
+}
+
+
+/**/
+/**
+
+ Name: SearchQueue
+
+ Description: This function searches the specifed queue for the first
+ occurrence of a member which satisfies the compare routine.
+ The compare routine must follow these guidelines.
+
+ 1) It takes two character pointers: the first is to be a
+ cast of the element and the second is the 'parm'.
+
+ 2) It returns TRUE when the cmp function is satisfied
+ with the element.
+
+ The boolean 'remove' flag is used to indicate whether of not
+ the caller wishes the found element to be removed from the
+ queue.
+
+ Modified: 10/16/1989 10:42:43
+
+ Returns: An element pointer to the found element or NULL if not
+ found.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+Q_ELEM_PTR SearchQueue(
+Q_HEADER_PTR queue ,
+BOOLEAN ( *cmp )( VOID_PTR, VOID_PTR ) ,
+VOID_PTR parm ,
+BOOLEAN remove )
+{
+ Q_ELEM_PTR element ;
+ BOOLEAN prev_state;
+
+ prev_state = DisableInterrupts() ;
+
+
+ for( element = QueueHead( queue ) ;
+ ( ( element != NULL ) && !( (*cmp)( element, parm ) ) ) ;
+ element = QueueNext( element ) ) ;
+ if( remove && ( element != NULL ) ) {
+ RemoveElem( queue, element ) ;
+ }
+
+ RestoreInterruptState( prev_state );
+ return( element ) ;
+}
+
+
+//
+// Stacks Code Below Here
+//
+
+/**/
+/** :FH1: Copyright (C) Maynard Electronics, Inc. 1988
+
+ :Name: InitStack() - Initialize a Stack
+
+ :Declaration: VOID InitStack( STACK_HDR_PTR stack )
+
+ :Description: This routine will initialize a "STACK_HDR". The
+ stack header is actually a "QUEUE_HDR".
+
+ :See Also: InitQueue()
+
+ :Notes:
+
+ :Design:
+
+**/
+VOID InitStack(
+STACK_HDR_PTR stack )
+{
+ InitQueue( ( Q_HEADER_PTR ) stack ) ;
+ return ;
+}
+
+/**/
+/** :FH1: Copyright (C) Maynard Electronics, Inc. 1988
+
+ :Name: Push() - Push an item on the Stack
+
+ :Declaration: UINT16 Push( STACK_HDR_PTR stack, UINT32 item )
+
+ :Description: This routine will "push" an item on the stack. A
+ Queue element is allocated for the item, the item
+ is stored in the Queue element and "pushed" onto
+ the stack.
+
+ If we are unable to allocate a "Queue" Element then
+ this routine will fail to "push" the element, and return
+ a non zero value.
+
+ :See Also: PushElem()
+
+ :Notes:
+
+ :Design:
+
+**/
+UINT16 Push(
+STACK_HDR_PTR stack,
+UINT32 item )
+{
+ STACK_ELEM_PTR qptr ;
+
+ /* Allocate the memory and enqueue the item */
+ if( ( qptr = ( STACK_ELEM_PTR ) malloc( sizeof( STACK_ELEM ) ) ) != NULL ) {
+ InitQElem( ( Q_ELEM_PTR ) qptr ) ;
+ qptr->item = item ;
+ PushElem( ( Q_HEADER_PTR ) stack, ( Q_ELEM_PTR ) qptr ) ;
+ return SUCCESS ;
+ }
+ return FAILURE ;
+}
+
+/**/
+/** :FH1: Copyright (C) Maynard Electronics, Inc. 1988
+
+ :Name: Pop() - Pop an item from the Stack
+
+ :Declaration: UINT32 Pop( STACK_HDR_PTR stack )
+
+ :Description: This routine will "pop" an item on the stack. This
+ routine will return NULL if there are no more items
+ on the stack.
+
+ :See Also: PushElem()
+
+ :Notes:
+
+ :Design:
+
+**/
+UINT32 Pop(
+STACK_HDR_PTR stack )
+{
+ STACK_ELEM_PTR qptr ;
+ UINT32 item ;
+
+ if( ( qptr = ( STACK_ELEM_PTR ) PopElem( ( Q_HEADER_PTR ) stack ) ) != NULL ) {
+ item = qptr->item ;
+ free( qptr ) ;
+ return item ;
+ }
+ return (UINT32)0;
+}
+
+/**/
+/** :FH1: Copyright (C) Maynard Electronics, Inc. 1988
+
+ :Name: TopOfStack() - Get Top of Stack
+
+ :Declaration: UINT32 TopOfStack( STACK_HDR_PTR stack )
+
+ :Description: This routine will return the top of the stack. This
+ routine will return NULL if there are no more items
+ on the stack.
+
+ :See Also:
+
+ :Notes:
+
+ :Design:
+
+**/
+UINT32 TopOfStack(
+STACK_HDR_PTR stk_ptr )
+{
+ if( stk_ptr->q_head != NULL ) {
+ return( ( ( STACK_ELEM_PTR ) stk_ptr->q_head )->item ) ;
+ }
+ return (UINT32)0 ;
+}
+
+
+
+/**/
+/** :FH1: Copyright (C) Maynard Electronics, Inc. 1988 - 1993
+
+ :Name: TopOfStack_with_0_values() - Get Top of Stack
+
+ :Declaration: UINT32 TopOfStack( STACK_HDR_PTR stack )
+
+ :Description: This routine will return the top value of a stack which
+ may contain the value 0. If there are no more values
+ on the stack, it will return FAILURE.
+
+ :See Also:
+
+ :Notes:
+
+ :Design:
+
+**/
+UINT16 TopOfStack_with_0_values( stk_ptr, stk_elem )
+STACK_HDR_PTR stk_ptr ;
+UINT32_PTR stk_elem ;
+{
+ if( stk_ptr->q_head != NULL ) {
+
+ *stk_elem = (UINT32)( ( STACK_ELEM_PTR ) stk_ptr->q_head )->item ;
+
+ return SUCCESS ;
+ }
+ return FAILURE ;
+}
diff --git a/private/utils/ntbackup/src/resmang.c b/private/utils/ntbackup/src/resmang.c
new file mode 100644
index 000000000..10699bd1a
--- /dev/null
+++ b/private/utils/ntbackup/src/resmang.c
@@ -0,0 +1,1381 @@
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: resmang.c
+
+ Description: This file contains the functions for windows resource calls.
+ It processes requests for loading, drawing, sizing,
+ background color replacing, and freeing of bitmaps.
+
+
+ $Log: G:/UI/LOGFILES/RESMANG.C_V $
+
+ Rev 1.34 03 Aug 1993 19:44:08 MARINA
+RSM_GetBitmapSize(), RSM_GetFontSize(): changed params to LPINT
+
+ Rev 1.33 28 Jul 1993 18:19:52 MARINA
+enable c++
+
+ Rev 1.32 09 Jun 1993 16:39:22 GLENN
+Adjusted max font width for fixed fonts due to integer division truncating.
+
+ Rev 1.31 07 Jun 1993 14:03:06 GLENN
+Fixed the true type font display problem by kludging the max char width.
+
+ Rev 1.30 04 Jun 1993 14:50:14 TerriLynn
+
+I added the #define OS_WIN32 to the Global Alloc code. Bimini's startup
+bitmap does not paint correctly with this NT specific code."
+
+
+
+ Rev 1.29 14 Apr 1993 16:00:36 GLENN
+Added GlobalAlloc()/GlobalFree() to be able to create bitmaps greater than 64K.
+
+ Rev 1.28 14 Apr 1993 10:54:10 GLENN
+Now copying the bitmap resouce to our memory before modifying the color table. (STEVED)
+
+ Rev 1.27 02 Apr 1993 14:10:22 GLENN
+Added display info support. Fixed background color problem.
+
+ Rev 1.26 10 Mar 1993 11:18:48 ROBG
+Fixed extra comma problem found by the Mike Meister.
+
+ Rev 1.25 02 Mar 1993 15:00:02 ROBG
+Added logic to keep the value of a loaded bitmap equal to the
+original value in the executable. The color table, once used
+to create a memory-based bitmap, is restored to its original state.
+NT requires this.
+
+ Rev 1.24 14 Dec 1992 12:23:54 DAVEV
+Enabled for Unicode compile
+
+ Rev 1.23 18 Nov 1992 11:39:16 GLENN
+Removed warnings.
+
+ Rev 1.22 11 Nov 1992 16:34:30 DAVEV
+UNICODE: remove compile warnings
+
+ Rev 1.21 01 Nov 1992 16:06:16 DAVEV
+Unicode changes
+
+ Rev 1.20 07 Oct 1992 15:10:58 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.19 04 Oct 1992 19:40:12 DAVEV
+Unicode Awk pass
+
+ Rev 1.18 09 Sep 1992 17:00:12 GLENN
+Updated NEW LOOK toolbar bitmap stuff for BIMINI.
+
+ Rev 1.17 08 Sep 1992 15:41:22 GLENN
+Added more room for new bitmaps.
+
+ Rev 1.16 20 Aug 1992 09:05:32 GLENN
+ifdef'd NT bitmaps just a little bit further.
+
+ Rev 1.15 03 Jun 1992 13:31:42 JOHNWT
+added empty dir bitmaps
+
+ Rev 1.14 18 May 1992 09:00:52 MIKEP
+header
+
+ Rev 1.13 14 May 1992 18:36:16 STEVEN
+40Format changes
+
+ Rev 1.12 22 Apr 1992 17:34:12 GLENN
+Added shark and diver bitmap stuff.
+
+ Rev 1.11 21 Apr 1992 16:48:06 chrish
+NT changes
+
+ Rev 1.10 30 Mar 1992 18:01:42 GLENN
+Added support for pulling resources from .DLL
+
+ Rev 1.9 27 Mar 1992 17:34:08 GLENN
+Changed cursor and icon load macros to functions.
+
+ Rev 1.8 09 Mar 1992 09:18:20 GLENN
+Added logo bitmap support.
+
+ Rev 1.7 25 Feb 1992 21:34:24 GLENN
+Created RSM_Sprintf().
+
+ Rev 1.6 05 Feb 1992 17:53:12 GLENN
+In Process - adding logic to calc bitmap string width.
+
+ Rev 1.5 24 Jan 1992 14:48:34 GLENN
+Removed the msassert calls, should not kill the app.
+
+ Rev 1.4 07 Jan 1992 17:41:58 GLENN
+Preloading some more bitmaps.
+
+ Rev 1.3 15 Dec 1991 10:28:20 MIKEP
+hidden files
+
+ Rev 1.2 12 Dec 1991 17:09:06 DAVEV
+16/32 bit port -2nd pass
+
+ Rev 1.1 10 Dec 1991 13:54:16 GLENN
+Added functions for get bitmap, font, font string sizes
+
+ Rev 1.0 20 Nov 1991 19:31:16 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+static HBITMAP BMTable[] = {
+
+ 0, // 0 IDRBM_FLOPPYDRIVE
+ 0, // 1 IDRBM_HARDDRIVE
+ 0, // 2 IDRBM_RAMDRIVE
+ 0, // 3 IDRBM_NETDRIVE
+ 0, // 4 IDRBM_TAPEDRIVE01
+ 0, // 5 IDRBM_TAPEDRIVE02
+ 0, // 6 IDRBM_TAPEDRIVE03
+ 0, // 7 IDRBM_MACRO
+ 0, // 8 IDRBM_SEL_NONE
+ 0, // 9 IDRBM_SEL_PART
+ 0, // 10 IDRBM_SEL_ALL
+ 0, // 11 IDRBM_FOLDER
+ 0, // 12 IDRBM_FOLDERPLUS
+ 0, // 13 IDRBM_FOLDERMINUS
+ 0, // 14 IDRBM_EXE
+ 0, // 15 IDRBM_FILE
+ 0, // 16 IDRBM_DOC
+ 0, // 17 IDRBM_FOLDEROPEN
+ 0, // 18 IDRBM_FOLDERPLUSOPEN
+ 0, // 19 IDRBM_FOLDERMINUSOPEN
+ 0, // 20 IDRBM_BACKUP
+ 0, // 21 IDRBM_RESTORE
+ 0, // 22 IDRBM_ERASE
+ 0, // 23 IDRBM_RETENSION
+ 0, // 24 IDRBM_JOBSTATUS
+ 0, // 25 IDRBM_SELECT
+ 0, // 26 IDRBM_SELECTALL
+ 0, // 27 IDRBM_DESELECT
+ 0, // 28 IDRBM_CHECK
+ 0, // 29 IDRBM_UNCHECK
+ 0, // 30 IDRBM_MODIFIED
+ 0, // 31 IDRBM_ADVANCED
+ 0, // 32 IDRBM_UNDO
+ 0, // 33 IDRBM_RUN
+ 0, // 34 IDRBM_SCHEDULE
+ 0, // 35 IDRBM_RECORD
+ 0, // 36 IDRBM_EDIT
+ 0, // 37 IDRBM_SAVE
+ 0, // 38 IDRBM_TEST
+ 0, // 39 IDRBM_INSERT
+ 0, // 40 IDRBM_DELETE
+ 0, // 41 IDRBM_SAVEAS
+ 0, // 42 IDRBM_CANCEL
+ 0, // 43 IDRBM_BACKUP_GRAY
+ 0, // 44 IDRBM_RESTORE_GRAY
+ 0, // 45 IDRBM_ERASE_GRAY
+ 0, // 46 IDRBM_TRANSFER
+ 0, // 47 IDRBM_TRANSFER_GRAY
+ 0, // 48 IDRBM_RETENSION_GRAY
+ 0, // 49 IDRBM_PARENTDIR
+ 0, // 50 IDRBM_MEMORY
+ 0, // 51 IDRBM_SEARCH
+ 0, // 52 IDRBM_TAPE
+ 0, // 53 IDRBM_SERVER
+ 0, // 54 IDRBM_SDISK
+ 0, // 55 IDRBM_BSET
+ 0, // 56 IDRBM_LOGFILE
+ 0, // 57 IDRBM_UPARROW
+ 0, // 58 IDRBM_DNARROW
+ 0, // 59 IDRBM_CATALOG
+ 0, // 60 IDRBM_VERIFY
+ 0, // 61 IDRBM_BSETPART
+ 0, // 62 IDRBM_SERVERDETACHED
+ 0, // 63 IDRBM_CHECK_GRAY
+ 0, // 64 IDRBM_UNCHECK_GRAY
+ 0, // 65 IDRBM_MODIFIED_GRAY
+ 0, // 66 IDRBM_ADVANCED_GRAY
+ 0, // 67 IDRBM_CATALOG_GRAY
+ 0, // 68 IDRBM_VERIFY_GRAY
+ 0, // 69 IDRBM_SEARCH_GRAY
+ 0, // 70 IDRBM_NEXTSET
+ 0, // 71 IDRBM_NEXTSET_GRAY
+ 0, // 72 IDRBM_EJECT
+ 0, // 73 IDRBM_EJECT_GRAY
+ 0, // 74 IDRBM_TAPEINDRIVE
+ 0, // 75 IDRBM_REWIND
+ 0, // 76 IDRBM_REWIND_GRAY
+ 0, // 77 IDRBM_LTAPE
+ 0, // 78 IDRBM_UPARROW_GRAY
+ 0, // 79 IDRBM_DOWNARROW_GRAY
+ 0, // 80 IDRBM_RT_ARROW_GRAY
+ 0, // 81 IDRBM_CORRUPTFILE
+ 0, // 82 IDRBM_FOLDERC
+ 0, // 83 IDRBM_FOLDERPLUSC
+ 0, // 84 IDRBM_FOLDERMINUSC
+ 0, // 85 IDRBM_FOLDEROPENC
+ 0, // 86 IDRBM_FOLDERPLUSOPENC
+ 0, // 87 IDRBM_FOLDERMINUSOPENC
+ 0, // 88 IDRBM_HFILE
+ 0, // 89 IDRBM_HEXE
+ 0, // 90 IDRBM_HCRPTFILE
+ 0, // 91 IDRBM_EXIT
+ 0, // 92 IDRBM_EXIT_GRAY
+ 0, // 93 IDRBM_LOGO
+ 0, // 94 IDRBM_SEL_ALL_RED
+ 0, // 95 IDRBM_CHECK_RED
+ 0, // 96 IDRBM_UNCHECK_RED
+ 0, // 97 IDRBM_ADVANCED_RED
+ 0, // 98 IDRBM_SHARK1
+ 0, // 99 IDRBM_SHARK2
+ 0, //100 IDRBM_SHARK3
+ 0, //101 IDRBM_DIVER1
+ 0, //102 IDRBM_DIVER2
+ 0, //103 IDRBM_DIVER3
+ 0, //104 IDRBM_FOLDER_EN
+ 0, //105 IDRBM_FOLDER_EM
+ 0, //106 IDRBM_FOLDER_EP
+ 0, //107 IDRBM_FOLDER_EON
+ 0, //108 IDRBM_FOLDER_EOM
+ 0, //109 IDRBM_FOLDER_EOP
+ 0, //110 IDRBM_FOLDER_ECN
+ 0, //111 IDRBM_FOLDER_ECM
+ 0, //112 IDRBM_FOLDER_ECP
+ 0, //113 IDRBM_FOLDER_EOCN
+ 0, //114 IDRBM_FOLDER_EOCM
+ 0, //115 IDRBM_FOLDER_EOCP
+ 0, //116 IDRBM_CDROM
+ 0, //117 IDRBM_TAPES
+ 0, //118 IDRBM_TAPESINDRIVE
+ 0, //119 IDRBM_NETCONNECT
+ 0, //120 IDRBM_NETCONNECT_GRAY
+ 0, //121 IDRBM_NETDISCON
+ 0, //122 IDRBM_NETDISCON_GRAY
+ 0, //123 IDRBM_FLOPPYSINDRIVE
+ 0, //124 IDRBM_FLOPPYINDRIVE
+ 0, //125 IDRBM_FLOPPYS
+ 0, //126 IDRBM_FLOPPY
+ 0, //127 IDRBM_INFO
+ 0, //128 IDRBM_INFO_GRAY
+ 0, //129 IDRBM_COLINDICATOR
+ 0, //130 IDRBM_EMS_ENTERPRISE
+ 0, //131 IDRBM_EMS_SITE
+ 0, //132 IDRBM_EMS_SERVER
+ 0, //133 IDRBM_EMS_MDB
+ 0, //134 IDRBM_EMS_DSA
+ 0, //135 IDRBM_RCVR_STATUS
+ 0, //136 IDRBM_EMS_MDBX
+ 0, //137 IDRBM_EMS_DSAX
+ 0, //138 IDRBM_EMS_MDBP
+ 0, //139 IDRBM_EMS_DSAP
+ 0, //140 IDRBM_BLANK16x16
+};
+
+
+static HBITMAP BMTableButton[] = {
+
+ 0, // 0 IDRBM_FLOPPYDRIVE
+ 0, // 1 IDRBM_HARDDRIVE
+ 0, // 2 IDRBM_RAMDRIVE
+ 0, // 3 IDRBM_NETDRIVE
+ 0, // 4 IDRBM_TAPEDRIVE01
+ 0, // 5 IDRBM_TAPEDRIVE02
+ 0, // 6 IDRBM_TAPEDRIVE03
+ 0, // 7 IDRBM_MACRO
+ 0, // 8 IDRBM_SEL_NONE
+ 0, // 9 IDRBM_SEL_PART
+ 0, // 10 IDRBM_SEL_ALL
+ 0, // 11 IDRBM_FOLDER
+ 0, // 12 IDRBM_FOLDERPLUS
+ 0, // 13 IDRBM_FOLDERMINUS
+ 0, // 14 IDRBM_EXE
+ 0, // 15 IDRBM_FILE
+ 0, // 16 IDRBM_DOC
+ 0, // 17 IDRBM_FOLDEROPEN
+ 0, // 18 IDRBM_FOLDERPLUSOPEN
+ 0, // 19 IDRBM_FOLDERMINUSOPEN
+ 0, // 20 IDRBM_BACKUP
+ 0, // 21 IDRBM_RESTORE
+ 0, // 22 IDRBM_ERASE
+ 0, // 23 IDRBM_RETENSION
+ 0, // 24 IDRBM_JOBSTATUS
+ 0, // 25 IDRBM_SELECT
+ 0, // 26 IDRBM_SELECTALL
+ 0, // 27 IDRBM_DESELECT
+ 0, // 28 IDRBM_CHECK
+ 0, // 29 IDRBM_UNCHECK
+ 0, // 30 IDRBM_MODIFIED
+ 0, // 31 IDRBM_ADVANCED
+ 0, // 32 IDRBM_UNDO
+ 0, // 33 IDRBM_RUN
+ 0, // 34 IDRBM_SCHEDULE
+ 0, // 35 IDRBM_RECORD
+ 0, // 36 IDRBM_EDIT
+ 0, // 37 IDRBM_SAVE
+ 0, // 38 IDRBM_TEST
+ 0, // 39 IDRBM_INSERT
+ 0, // 40 IDRBM_DELETE
+ 0, // 41 IDRBM_SAVEAS
+ 0, // 42 IDRBM_CANCEL
+ 0, // 43 IDRBM_BACKUP_GRAY
+ 0, // 44 IDRBM_RESTORE_GRAY
+ 0, // 45 IDRBM_ERASE_GRAY
+ 0, // 46 IDRBM_TRANSFER
+ 0, // 47 IDRBM_TRANSFER_GRAY
+ 0, // 48 IDRBM_RETENSION_GRAY
+ 0, // 49 IDRBM_PARENTDIR
+ 0, // 50 IDRBM_MEMORY
+ 0, // 51 IDRBM_SEARCH
+ 0, // 52 IDRBM_TAPE
+ 0, // 53 IDRBM_SERVER
+ 0, // 54 IDRBM_SDISK
+ 0, // 55 IDRBM_BSET
+ 0, // 56 IDRBM_LOGFILE
+ 0, // 57 IDRBM_UPARROW
+ 0, // 58 IDRBM_DNARROW
+ 0, // 59 IDRBM_CATALOG
+ 0, // 60 IDRBM_VERIFY
+ 0, // 61 IDRBM_BSETPART
+ 0, // 62 IDRBM_SERVERDETACHED
+ 0, // 63 IDRBM_CHECK_GRAY
+ 0, // 64 IDRBM_UNCHECK_GRAY
+ 0, // 65 IDRBM_MODIFIED_GRAY
+ 0, // 66 IDRBM_ADVANCED_GRAY
+ 0, // 67 IDRBM_CATALOG_GRAY
+ 0, // 68 IDRBM_VERIFY_GRAY
+ 0, // 69 IDRBM_SEARCH_GRAY
+ 0, // 70 IDRBM_NEXTSET
+ 0, // 71 IDRBM_NEXTSET_GRAY
+ 0, // 72 IDRBM_EJECT
+ 0, // 73 IDRBM_EJECT_GRAY
+ 0, // 74 IDRBM_TAPEINDRIVE
+ 0, // 75 IDRBM_REWIND
+ 0, // 76 IDRBM_REWIND_GRAY
+ 0, // 77 IDRBM_LTAPE
+ 0, // 78 IDRBM_UPARROW_GRAY
+ 0, // 79 IDRBM_DOWNARROW_GRAY
+ 0, // 80 IDRBM_RT_ARROW_GRAY
+ 0, // 81 IDRBM_CORRUPTFILE
+ 0, // 82 IDRBM_FOLDERC
+ 0, // 83 IDRBM_FOLDERPLUSC
+ 0, // 84 IDRBM_FOLDERMINUSC
+ 0, // 85 IDRBM_FOLDEROPENC
+ 0, // 86 IDRBM_FOLDERPLUSOPENC
+ 0, // 87 IDRBM_FOLDERMINUSOPENC
+ 0, // 88 IDRBM_HFILE
+ 0, // 89 IDRBM_HEXE
+ 0, // 90 IDRBM_HCRPTFILE
+ 0, // 91 IDRBM_EXIT
+ 0, // 92 IDRBM_EXIT_GRAY
+ 0, // 93 IDRBM_LOGO
+ 0, // 94 IDRBM_SEL_ALL_RED
+ 0, // 95 IDRBM_CHECK_RED
+ 0, // 96 IDRBM_UNCHECK_RED
+ 0, // 97 IDRBM_ADVANCED_RED
+ 0, // 98 IDRBM_SHARK1
+ 0, // 99 IDRBM_SHARK2
+ 0, //100 IDRBM_SHARK3
+ 0, //101 IDRBM_DIVER1
+ 0, //102 IDRBM_DIVER2
+ 0, //103 IDRBM_DIVER3
+ 0, //104 IDRBM_FOLDER_EN
+ 0, //105 IDRBM_FOLDER_EM
+ 0, //106 IDRBM_FOLDER_EP
+ 0, //107 IDRBM_FOLDER_EON
+ 0, //108 IDRBM_FOLDER_EOM
+ 0, //109 IDRBM_FOLDER_EOP
+ 0, //110 IDRBM_FOLDER_ECN
+ 0, //111 IDRBM_FOLDER_ECM
+ 0, //112 IDRBM_FOLDER_ECP
+ 0, //113 IDRBM_FOLDER_EOCN
+ 0, //114 IDRBM_FOLDER_EOCM
+ 0, //115 IDRBM_FOLDER_EOCP
+ 0, //116 IDRBM_CDROM
+ 0, //117 IDRBM_TAPES
+ 0, //118 IDRBM_TAPESINDRIVE
+ 0, //119 IDRBM_NETCONNECT
+ 0, //120 IDRBM_NETCONNECT_GRAY
+ 0, //121 IDRBM_NETDISCON
+ 0, //122 IDRBM_NETDISCON_GRAY
+ 0, //123 IDRBM_FLOPPYSINDRIVE
+ 0, //124 IDRBM_FLOPPYINDRIVE
+ 0, //125 IDRBM_FLOPPYS
+ 0, //126 IDRBM_FLOPPY
+ 0, //127 IDRBM_INFO
+ 0, //128 IDRBM_INFO_GRAY
+ 0, //129 IDRBM_COLINDICATOR
+ 0, //130 IDRBM_EMS_ENTERPRISE
+ 0, //131 IDRBM_EMS_SITE
+ 0, //132 IDRBM_EMS_SERVER
+ 0, //133 IDRBM_EMS_MDB
+ 0, //134 IDRBM_EMS_DSA
+ 0, //135 IDRBM_RCVR_STATUS
+ 0, //136 IDRBM_EMS_MDBX
+ 0, //137 IDRBM_EMS_DSAX
+ 0, //138 IDRBM_EMS_MDBP
+ 0, //139 IDRBM_EMS_DSAP
+ 0, //140 IDRBM_BLANK16x16
+};
+
+#define NUMBITMAPS (sizeof (BMTable) / sizeof (BMTable[0]) )
+
+
+// MODULE WIDE VARIABLES - PRIVATE
+
+static COLORREF mwBitmapBackGnd;
+
+extern BOOL gfRedChecks;
+
+// PRIVATE FUNCTION PROTOTYPES
+
+
+
+// FUNCTIONS
+
+/******************************************************************************
+
+ Name: RSM_BitmapDraw()
+
+ Description: This function draws a bitmap at the specified
+ upper-left location using the specified dimensions.
+ If the bitmap handle was not previously loaded into
+ the bitmap table, the function loads it using the
+ the specified bitmap ID. If no width or height are
+ specified, the bitmap's width and height are used.
+
+ Returns: FALSE, if successful. Otherwise, TRUE.
+
+******************************************************************************/
+
+BOOL RSM_BitmapDraw (
+
+WORD wBitmapID, // I - ID of the bitmap to be drawn
+INT X, // I - starting X location
+INT Y, // I - starting Y location
+INT nWidth, // I - bitmap width
+INT nHeight, // I - bitmap height
+HDC hDC ) // I - handle to a device context
+
+{
+ BOOL fRC; // return code
+ HDC hDCMem1; // memory DC
+ HBITMAP hBM; // handle to the bitmap
+
+ // Get a handle to the bitmap and put it into a memory DC.
+ // Almost all of the time, the bitmap will already be loaded. This
+ // code is optimized (I hope) for this scenario.
+
+ if ( wBitmapID < BTNFACE_BACKGND + BM_OFFSET ) {
+ hBM = BMTable[ wBitmapID - BM_OFFSET ];
+
+ } else {
+
+ hBM = BMTableButton[ wBitmapID - BM_OFFSET - BTNFACE_BACKGND ];
+ }
+
+ if ( ! hBM ) {
+
+ hBM = RSM_BitmapLoad ( wBitmapID, mwBitmapBackGnd );
+
+ if ( ! hBM ) {
+ return TRUE;
+ }
+ }
+
+ hDCMem1 = CreateCompatibleDC ( hDC );
+ fRC = ! SelectObject ( hDCMem1, hBM );
+
+ if ( ! fRC ) {
+
+ SetMapMode ( hDCMem1, GetMapMode ( hDC ) );
+
+ // If the caller specified NULL for the WIDTH or HEIGHT, use the
+ // bitmaps WIDTH and HEIGHT for drawing.
+
+ if ( ! nWidth || ! nHeight ) {
+
+ BITMAP dsBM ;
+
+ GetObject ( hBM, sizeof (BITMAP), (LPSTR)&dsBM ) ;
+
+ nWidth = dsBM.bmWidth;
+ nHeight = dsBM.bmHeight;
+ }
+
+ fRC = BitBlt( hDC, // Destination device context.
+ X, // Destination X location.
+ Y, // Destination Y location.
+ nWidth, // Destination bitmap width.
+ nHeight, // Destination bitmap height.
+ hDCMem1, // Source device context.
+ 0, // Source X origin.
+ 0, // Source Y origin.
+ SRCCOPY // Copy the source to the destination.
+ );
+ }
+
+ DeleteDC ( hDCMem1 );
+
+ return fRC;
+
+} /* end RSM_BitmapDraw() */
+
+
+/******************************************************************************
+
+ Name: RSM_BitmapDrawCentered()
+
+ Description: This function draws a bitmap at the specified
+ upper-left location using the specified dimensions.
+ If the bitmap handle was not previously loaded into
+ the bitmap table, the function loads it using the
+ the specified bitmap ID. If no width or height are
+ specified, the bitmap's width and height are used.
+
+ Returns: FALSE, if successful. Otherwise, TRUE.
+
+******************************************************************************/
+
+BOOL RSM_BitmapDrawCentered (
+
+WORD wBitmapID, // I - ID of the bitmap to be drawn
+INT X, // I - starting X location
+INT Y, // I - starting Y location
+INT nWidth, // I - bitmap width
+INT nHeight, // I - bitmap height
+HDC hDC ) // I - handle to a device context
+
+{
+ BOOL fRC; // return code
+ HBITMAP hBM; // handle to the bitmap
+ BITMAP dsBM; // bitmap data structure
+ INT i; // temp integer
+
+ // Get a handle to the bitmap and put it into a memory DC.
+ // Almost all of the time, the bitmap will already be loaded. This
+ // code is optimized (I hope) for this scenario.
+
+ hBM = BMTable[ wBitmapID - BM_OFFSET ];
+
+ if ( ! hBM ) {
+
+ hBM = RSM_BitmapLoad ( wBitmapID, mwBitmapBackGnd );
+
+ if ( ! hBM ) {
+ return TRUE;
+ }
+ }
+
+ // Calculate the rectangular area dimensions to CENTER the BITMAP.
+
+ GetObject ( hBM, sizeof ( BITMAP ), (LPSTR)&dsBM );
+
+ i = nWidth - dsBM.bmWidth;
+
+ if ( i > 1 ) {
+
+ i = i / 2;
+
+ X += i;
+ nWidth -= i;
+ }
+
+ i = nHeight - dsBM.bmHeight;
+
+ if ( i > 1 ) {
+
+ i = i / 2;
+
+ Y += i;
+ nHeight -= i;
+ }
+
+// fRC = RSM_BitmapDraw ( wBitmapID, X, Y, nWidth, nHeight, hDC );
+
+ fRC = RSM_BitmapDraw ( wBitmapID, X, Y, dsBM.bmWidth, dsBM.bmHeight, hDC );
+
+ return fRC;
+
+} /* end RSM_BitmapDrawCentered() */
+
+
+/******************************************************************************
+
+ Name: RSM_BitmapFree()
+
+ Description: This function frees the memory associated with a bitmap,
+ then clears the handle out of the bitmap table.
+
+ Returns: FALSE, if successful. Otherwise, TRUE.
+
+******************************************************************************/
+
+BOOL RSM_BitmapFree (
+
+WORD wBitmapID ) // I - bitmap ID to be freed
+
+{
+ BOOL wStatus;
+
+ wStatus = DeleteObject ( BMTable[ wBitmapID - BM_OFFSET ] ) ;
+
+ BMTable[ wBitmapID - BM_OFFSET ] = 0;
+
+ return wStatus;
+
+} /* end RSM_BitmapFree() */
+
+
+/******************************************************************************
+
+ Name: RSM_BitmapFreeAll()
+
+ Description: This function frees all memory associated with all bitmaps.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID RSM_BitmapFreeAll ( VOID )
+
+{
+ int i;
+
+ for ( i = 0; i < NUMBITMAPS; i++ ) {
+
+ if ( BMTable[i] ) {
+ DeleteObject ( BMTable[i] ) ;
+ BMTable[i] = 0;
+ }
+ }
+
+} /* end RSM_BitmapFreeAll() */
+
+
+/******************************************************************************
+
+ Name: RSM_BitmapInit()
+
+ Description: This function initializes the bitmap background color.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID RSM_BitmapInit ( VOID )
+
+{
+ COLORREF ColorGray = GetSysColor ( COLOR_BTNFACE );
+ COLORREF ColorBackGnd = GetSysColor ( COLOR_WINDOW );
+ COLORREF BackGround;
+
+ // Load the bitmaps that do not require background color changes.
+
+
+ // Setup the color to use when replacing background color bits in bitmaps.
+ // Do this by CONVERTING the RGB to BGR, since DIB format uses BGRs --
+ // Who knows why?
+
+ // MAYBE pre-load some bitmaps that will be used immediately.
+
+ // OK, let's load the Selection Bar bitmaps with a gray (button face)
+ // background.
+
+ BackGround = RGB (
+ (BYTE)( HIWORD(ColorGray) ),
+ (BYTE)( (WORD)ColorGray >> 8 ),
+ (BYTE)ColorGray
+ );
+
+ RSM_BitmapLoad ( IDRBM_BACKUP, BackGround );
+ RSM_BitmapLoad ( IDRBM_BACKUP_GRAY, BackGround );
+ RSM_BitmapLoad ( IDRBM_RESTORE, BackGround );
+ RSM_BitmapLoad ( IDRBM_RESTORE_GRAY, BackGround );
+ RSM_BitmapLoad ( IDRBM_EJECT, BackGround );
+ RSM_BitmapLoad ( IDRBM_EJECT_GRAY, BackGround );
+ RSM_BitmapLoad ( IDRBM_CHECK, BackGround );
+ RSM_BitmapLoad ( IDRBM_CHECK_GRAY, BackGround );
+ RSM_BitmapLoad ( IDRBM_UNCHECK, BackGround );
+ RSM_BitmapLoad ( IDRBM_UNCHECK_GRAY, BackGround );
+ RSM_BitmapLoad ( IDRBM_CATALOG, BackGround );
+ RSM_BitmapLoad ( IDRBM_CATALOG_GRAY, BackGround );
+ RSM_BitmapLoad ( IDRBM_ERASE, BackGround );
+ RSM_BitmapLoad ( IDRBM_ERASE_GRAY, BackGround );
+ RSM_BitmapLoad ( IDRBM_RETENSION, BackGround );
+ RSM_BitmapLoad ( IDRBM_RETENSION_GRAY, BackGround );
+
+
+ RSM_BitmapLoad ( BTNFACE_BACKGND + IDRBM_HARDDRIVE, BackGround );
+ RSM_BitmapLoad ( BTNFACE_BACKGND + IDRBM_NETDRIVE, BackGround );
+ RSM_BitmapLoad ( BTNFACE_BACKGND + IDRBM_SEL_NONE, BackGround );
+ RSM_BitmapLoad ( BTNFACE_BACKGND + IDRBM_SEL_PART, BackGround );
+ RSM_BitmapLoad ( BTNFACE_BACKGND + IDRBM_SEL_ALL, BackGround );
+ RSM_BitmapLoad ( BTNFACE_BACKGND + IDRBM_FOLDER, BackGround );
+ RSM_BitmapLoad ( BTNFACE_BACKGND + IDRBM_FOLDERPLUS, BackGround );
+ RSM_BitmapLoad ( BTNFACE_BACKGND + IDRBM_FOLDERMINUS, BackGround );
+ RSM_BitmapLoad ( BTNFACE_BACKGND + IDRBM_EXE, BackGround );
+ RSM_BitmapLoad ( BTNFACE_BACKGND + IDRBM_FILE, BackGround );
+ RSM_BitmapLoad ( BTNFACE_BACKGND + IDRBM_FOLDEROPEN, BackGround );
+ RSM_BitmapLoad ( BTNFACE_BACKGND + IDRBM_FOLDERPLUSOPEN, BackGround );
+ RSM_BitmapLoad ( BTNFACE_BACKGND + IDRBM_FOLDERMINUSOPEN, BackGround );
+
+#ifdef OEM_EMS
+ RSM_BitmapLoad ( BTNFACE_BACKGND + IDRBM_EMS_ENTERPRISE, BackGround );
+ RSM_BitmapLoad ( BTNFACE_BACKGND + IDRBM_EMS_SITE, BackGround );
+ RSM_BitmapLoad ( BTNFACE_BACKGND + IDRBM_EMS_SERVER, BackGround );
+ RSM_BitmapLoad ( BTNFACE_BACKGND + IDRBM_EMS_MDB, BackGround );
+ RSM_BitmapLoad ( BTNFACE_BACKGND + IDRBM_EMS_DSA, BackGround );
+ RSM_BitmapLoad ( BTNFACE_BACKGND + IDRBM_BLANK16x16, BackGround );
+#endif // OEM_EMS
+
+
+
+# if defined ( OEM_MSOFT )
+ {
+ }
+# else
+ {
+ RSM_BitmapLoad ( IDRBM_TRANSFER, BackGround );
+ RSM_BitmapLoad ( IDRBM_TRANSFER_GRAY, BackGround );
+ RSM_BitmapLoad ( IDRBM_SEARCH, BackGround );
+ RSM_BitmapLoad ( IDRBM_SEARCH_GRAY, BackGround );
+ RSM_BitmapLoad ( IDRBM_ADVANCED, BackGround );
+ RSM_BitmapLoad ( IDRBM_ADVANCED_GRAY, BackGround );
+ RSM_BitmapLoad ( IDRBM_INFO, BackGround );
+ RSM_BitmapLoad ( IDRBM_INFO_GRAY, BackGround );
+ RSM_BitmapLoad ( IDRBM_EXIT, BackGround );
+ RSM_BitmapLoad ( IDRBM_EXIT_GRAY, BackGround );
+ RSM_BitmapLoad ( IDRBM_UPARROW, BackGround );
+ RSM_BitmapLoad ( IDRBM_UPARROW_GRAY, BackGround );
+ RSM_BitmapLoad ( IDRBM_DNARROW, BackGround );
+ RSM_BitmapLoad ( IDRBM_DOWNARROW_GRAY, BackGround );
+ RSM_BitmapLoad ( IDRBM_NETCONNECT, BackGround );
+ RSM_BitmapLoad ( IDRBM_NETCONNECT_GRAY,BackGround );
+ RSM_BitmapLoad ( IDRBM_NETDISCON, BackGround );
+ RSM_BitmapLoad ( IDRBM_NETDISCON_GRAY, BackGround );
+ }
+# endif // defined ( OEM_MSOFT )
+
+
+ // Now, let's load the rest of the most commonly used bitmaps with the
+ // windows (user selected) background color.
+
+ BackGround = RGB (
+ (BYTE)( HIWORD(ColorBackGnd) ),
+ (BYTE)( (WORD)ColorBackGnd >> 8 ),
+ (BYTE)ColorBackGnd,
+ );
+
+ RSM_BitmapLoad ( IDRBM_HARDDRIVE, BackGround );
+ RSM_BitmapLoad ( IDRBM_NETDRIVE, BackGround );
+ RSM_BitmapLoad ( IDRBM_SEL_NONE, BackGround );
+ RSM_BitmapLoad ( IDRBM_SEL_PART, BackGround );
+ RSM_BitmapLoad ( IDRBM_SEL_ALL, BackGround );
+ RSM_BitmapLoad ( IDRBM_FOLDER, BackGround );
+ RSM_BitmapLoad ( IDRBM_FOLDERPLUS, BackGround );
+ RSM_BitmapLoad ( IDRBM_FOLDERMINUS, BackGround );
+ RSM_BitmapLoad ( IDRBM_EXE, BackGround );
+ RSM_BitmapLoad ( IDRBM_FILE, BackGround );
+ RSM_BitmapLoad ( IDRBM_FOLDEROPEN, BackGround );
+ RSM_BitmapLoad ( IDRBM_FOLDERPLUSOPEN, BackGround );
+ RSM_BitmapLoad ( IDRBM_FOLDERMINUSOPEN, BackGround );
+
+#ifdef OEM_EMS
+ RSM_BitmapLoad ( IDRBM_EMS_ENTERPRISE, BackGround );
+ RSM_BitmapLoad ( IDRBM_EMS_SITE, BackGround );
+ RSM_BitmapLoad ( IDRBM_EMS_SERVER, BackGround );
+ RSM_BitmapLoad ( IDRBM_EMS_MDB, BackGround );
+ RSM_BitmapLoad ( IDRBM_EMS_DSA, BackGround );
+#endif // OEM_EMS
+
+
+ mwBitmapBackGnd = BackGround;
+
+} /* end RSM_BitmapInit() */
+
+
+COLORREF RSM_BitmapGetBackgroundColor ( VOID )
+{
+ return mwBitmapBackGnd ;
+}
+
+VOID RSM_BitmapSetBackgroundColor ( COLORREF new_color )
+{
+
+ mwBitmapBackGnd = new_color ;
+}
+
+/******************************************************************************
+
+
+ Name: RSM_BitmapLoad()
+
+ Description: This function load a bitmaps and sets the bitmap backgound
+ color to the background color specified. This function
+ checks to see if the bitmap was previously loaded. If so,
+ it simply returns the handle to that bitmap.
+
+ Returns: A handle to a bitmap if successful. Otherwise, NULL.
+
+******************************************************************************/
+
+
+HBITMAP RSM_BitmapLoad (
+
+WORD wBitmapID, // I - bitmap ID
+COLORREF cBackGround ) // I - background replacement color
+
+{
+ HDC hDC;
+ INT nIndex;
+ DWORD FAR *lpColorTable;
+ DWORD FAR *lpColorTableEnd;
+ HBITMAP hBM;
+ HANDLE hRes;
+ LPBITMAPINFOHEADER lpBMIH;
+#if defined ( OS_WIN32 )
+ UINT32 unResSize;
+ VOID_PTR pTemp;
+ HANDLE hMem;
+#endif
+
+ // Determine whether to display RED or BLACK checkmarks.
+
+ if ( gfRedChecks && FALSE ) {
+
+ switch ( wBitmapID ) {
+
+ case IDRBM_SEL_ALL:
+ wBitmapID = IDRBM_SEL_ALL_RED;
+
+ break;
+
+ case IDRBM_CHECK:
+ wBitmapID = IDRBM_CHECK_RED;
+
+ break;
+
+ case IDRBM_UNCHECK:
+ wBitmapID = IDRBM_UNCHECK_RED;
+
+ break;
+
+ case IDRBM_ADVANCED:
+ wBitmapID = IDRBM_ADVANCED_RED;
+
+ break;
+ }
+ }
+
+ // Determine the bitmap ID index into the Bitmap Table.
+
+ nIndex = wBitmapID - BM_OFFSET;
+
+ // Check to see if the bitmap has already been loaded. If so, then
+ // return the handle from the table.
+
+ if ( nIndex < BTNFACE_BACKGND ) {
+ if ( BMTable[ nIndex ] ) {
+ return BMTable[ nIndex ];
+ }
+ } else {
+
+ COLORREF ColorGray = GetSysColor ( COLOR_BTNFACE );
+
+ if ( BMTableButton[ nIndex - BTNFACE_BACKGND ] ) {
+ return BMTableButton[ nIndex - BTNFACE_BACKGND ];
+ }
+ wBitmapID -= BTNFACE_BACKGND ;
+
+ cBackGround = RGB (
+ (BYTE)( HIWORD(ColorGray) ),
+ (BYTE)( (WORD)ColorGray >> 8 ),
+ (BYTE)ColorGray
+ );
+ }
+
+ // THE NO-BACKGROUND-COLOR VERSION.
+ //
+ // Load the bitmap.
+ // hBM = LoadBitmap ( ghResInst, ID(wBitmapID) );
+ // BMTable[nIndex] = hBM; // REMOVE THIS LINE IF DIBs ARE SUPPORTED
+ // return hBM;
+
+ // THE BACKGROUND-COLOR VERSION.
+ //
+ // Load the bitmap as a resource.
+
+ hRes = LoadResource ( ghResInst, FindResource ( ghResInst, ID(wBitmapID), RT_BITMAP ) );
+
+ if ( ! hRes ) {
+ return (HBITMAP)NULL;
+ }
+
+ // Lock it down and get a Long Pointer to the BitMap Information Header.
+
+ lpBMIH = (LPBITMAPINFOHEADER)LockResource ( hRes );
+
+#if defined( OS_WIN32 )
+ // Determine the size of the bitmap header including the size of
+ // the color table. This will be used to determine the size of the
+ // entire bitmap for copying it to our memory.
+
+ lpColorTable = (DWORD FAR *)( (INT8_PTR)(lpBMIH) + (WORD)(lpBMIH->biSize) );
+
+ // Determine the ending point of the color table search.
+
+ lpColorTableEnd = (DWORD FAR *)( (INT8_PTR)(lpColorTable) +
+ (WORD)( ( 1 << lpBMIH->biBitCount ) *
+ sizeof ( RGBQUAD ) ) );
+ // Now, copy the bitmap resource to our own memory since we can
+ // no longer modify it directly in NT. We might as well do it
+ // for all OS's since it can't hurt.
+
+ unResSize = (INT8_PTR)lpColorTableEnd - (INT8_PTR)lpBMIH ;
+
+ if ( lpBMIH->biSizeImage ) {
+
+ // Add the compressed size found in biSizeImage.
+
+ unResSize += lpBMIH->biSizeImage ;
+ }
+ else {
+
+ // The bitmap is not compressed, multiply the width x height.
+
+ unResSize += ( lpBMIH->biWidth * lpBMIH->biHeight );
+ }
+
+ hMem = GlobalAlloc ( GHND, unResSize );
+
+ if ( ! hMem ) {
+ return (HBITMAP)NULL;
+ }
+
+ pTemp = GlobalLock ( hMem );
+
+ if ( ! pTemp ) {
+ return (HBITMAP)NULL;
+ }
+
+ memcpy( pTemp, lpBMIH, unResSize ) ;
+ lpBMIH=(LPBITMAPINFOHEADER)pTemp ;
+
+#endif
+
+ // Now get a pointer to the color table of the bitmap. This will be the
+ // starting point of the search for the color table entry which will be
+ // replaced by the background color.
+
+ lpColorTable = (DWORD FAR *)( (INT8_PTR)(lpBMIH) + (WORD)(lpBMIH->biSize) );
+
+ // Determine the ending point of the color table search.
+
+ lpColorTableEnd = (DWORD FAR *)( (INT8_PTR)(lpColorTable) +
+ (WORD)( ( 1 << lpBMIH->biBitCount ) *
+ sizeof ( RGBQUAD ) ) );
+
+ // Search for the PURE BLUE (RSM_MAGICCOLOR) entry and replace it with
+ // the current background RGB.
+
+ for ( ; lpColorTable < lpColorTableEnd; lpColorTable++ ) {
+
+// if ( *lpColorTable == RSM_MAGICCOLOR ) { // PURE BLUE
+ if ( *lpColorTable == 0x00ff00FF ) { // PURE BLUE
+
+ *lpColorTable = cBackGround;
+ break;
+ }
+ }
+
+ // Create a color DIB compatible with the display device.
+
+ hDC = GetDC ( (HWND)NULL );
+
+ hBM = CreateDIBitmap ( hDC,
+ lpBMIH,
+ (DWORD)CBM_INIT,
+ (BYTE_PTR)lpColorTableEnd,
+ (LPBITMAPINFO)lpBMIH,
+ DIB_RGB_COLORS
+ );
+
+ ReleaseDC ( (HWND)NULL, hDC );
+
+ // Now UNLOCK and FREE the resource and the copy of the bitmap.
+
+ GlobalUnlock ( hRes );
+ FreeResource ( hRes );
+
+#if defined( OS_WIN32 )
+ GlobalUnlock ( hMem );
+ GlobalFree ( hMem ) ;
+#endif
+
+ if ( nIndex < BTNFACE_BACKGND ) {
+ BMTable[nIndex] = hBM;
+ } else {
+ BMTableButton[nIndex - BTNFACE_BACKGND] = hBM;
+ }
+
+ return hBM;
+
+} /* end RSM_BitmapLoad() */
+
+
+/******************************************************************************
+
+ Name: RSM_BitmapStretch()
+
+ Description: This function stretches or shrinks a bitmap to the
+ specified width.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID RSM_BitmapStretch (
+
+HDC hDC, // I - handle to a device context
+WORD wBitmapID, // I - ID of the bitmap to stretch
+INT nWidth, // I - bitmap width
+INT nHeight ) // I - bitmap height
+
+{
+ DBG_UNREFERENCED_PARAMETER ( hDC );
+ DBG_UNREFERENCED_PARAMETER ( wBitmapID );
+ DBG_UNREFERENCED_PARAMETER ( nWidth );
+ DBG_UNREFERENCED_PARAMETER ( nHeight );
+/*
+ INT nIndex; // index into the bitmap table
+ HBITMAP hBM1; // bitmap handle
+ HBITMAP hBM2; // bitmap handle
+ BITMAP bm1; // temporary bitmap
+ BITMAP bm2; // temporary bitmap
+
+
+ nIndex = wBitmapID - BM_OFFSET;
+
+ hBM1 = BMTable[ nIndex ];
+
+ GetObject ( hBM1, sizeof(BITMAP), (LPSTR) &bm1 );
+ hDCMem1 = CreateCompatibleDC ( hDC );
+ hDCMem2 = CreateCompatibleDC ( hDC );
+
+ bm2 = bm1;
+ bm2.bmWidth = nWidth;
+ bm2.bmHeight = nHeight;
+ bm2.bmWidthBytes = ( ( bm2.bmWidth + 15 ) / 16 ) * 2; // Why? Because!
+
+ hBM2 = CreateBitmapIndirect( &bm2 );
+
+ SelectObject ( hDCMem1, hBM1 );
+ SelectObject ( hDCMem2, hBM2 );
+
+ StretchBlt ( hDCMem2, 0, 0, bm2.bmWidth, bm2.bmHeight,
+ hDCMem1, 0, 0, bm1.bmWidth, bm1.bmHeight, SRCCOPY );
+
+ DeleteDC ( hDCMem1);
+ DeleteDC ( hDCMem2);
+
+ DeleteObject ( hBM1 );
+
+ BMTable[ nIndex ] = hBM2;
+*/
+
+} /* end RSM_BitmapStretch() */
+
+
+/******************************************************************************
+
+ Name: RSM_GetBitmapSize()
+
+ Description: This function gets the width and height of the bitmap.
+
+ Returns: SUCCESS if successful, otherwise, FAILURE.
+
+******************************************************************************/
+
+BOOL RSM_GetBitmapSize (
+
+WORD wBitmapID, // I - ID of the bitmap to stretch
+LPINT pnWidth, // O - pointer to storage of bitmap width
+LPINT pnHeight ) // O - pointer to storage of bitmap height
+
+{
+ HBITMAP hBM; // handle to the bitmap
+ BITMAP dsBM; // bitmap data structure
+
+ // Get a handle to the bitmap and put it into a memory DC.
+ // Almost all of the time, the bitmap will already be loaded. This
+ // code is optimized (I hope) for this scenario.
+
+ hBM = BMTable[ wBitmapID - BM_OFFSET ];
+
+ if ( ! hBM ) {
+
+ hBM = RSM_BitmapLoad ( wBitmapID, mwBitmapBackGnd );
+
+ if ( ! hBM ) {
+ return FAILURE;
+ }
+ }
+
+ GetObject ( hBM, sizeof (BITMAP), (LPSTR)&dsBM );
+
+ *pnWidth = dsBM.bmWidth;
+ *pnHeight = dsBM.bmHeight;
+
+ return SUCCESS;
+
+} /* end RSM_GetBitmapSize() */
+
+
+/******************************************************************************
+
+ Name: RSM_GetFontMaxSize()
+
+ Description: This function gets the maximum width, average width,
+ and height of a font.
+
+ Returns: SUCCESS if successful, otherwise, FAILURE.
+
+******************************************************************************/
+
+BOOL RSM_GetFontSize (
+
+HFONT hFont, // I - handle to a font
+LPINT pnMaxWidth, // O - pointer to storage of max font width
+LPINT pnAvgWidth, // O - pointer to storage of average font width
+LPINT pnHeight ) // O - pointer to storage of font height
+
+{
+ BOOL fRC; // return code
+ HDC hDC;
+ HFONT hOldFont;
+ TEXTMETRIC dsMetrics;
+
+ hDC = GetDC ( ghWndFrame );
+
+ // Select the new font and save the old font to put it back.
+
+ hOldFont = SelectObject ( hDC, hFont );
+
+ // Get the text metrics data structure.
+
+ fRC = GetTextMetrics ( hDC, &dsMetrics );
+
+ if ( fRC ) {
+ *pnMaxWidth = dsMetrics.tmMaxCharWidth;
+ *pnAvgWidth = dsMetrics.tmAveCharWidth;
+ *pnHeight = dsMetrics.tmHeight;
+ }
+
+ // Kludge the max width for the DLM - FIX THE DLM LATER.
+
+ if ( *pnMaxWidth < ( *pnAvgWidth + ( *pnAvgWidth / 2 ) ) ) {
+
+ *pnMaxWidth += ( ( *pnAvgWidth + 1 ) / 2 );
+ }
+
+ // Put back the old font.
+
+ SelectObject ( hDC, hOldFont );
+
+ ReleaseDC ( ghWndFrame, hDC );
+
+ return ! fRC;
+
+} /* end RSM_GetFontMaxSize() */
+
+
+/******************************************************************************
+
+ Name: RSM_GetFontStringWidth()
+
+ Description: This function gets the display width of a string based on
+ the font passed.
+
+ Returns: The width of the string.
+
+******************************************************************************/
+
+INT RSM_GetFontStringWidth (
+
+HFONT hFont, // I - handle to a font
+LPSTR lpString, // I - string ID or a pointer to the string
+INT nStringLen ) // I - string length
+
+{
+ HDC hDC;
+ HDC hDCMem;
+ HFONT hOldFont;
+ LPSTR lpResString = (LPSTR)NULL;
+ SIZE sizeRect; //Return from GetTextExtentPoint
+
+ // If the pointer contains a resource ID, get the string from the
+ // resources.
+
+ if ( lpString && ! HIWORD(lpString) ) {
+
+ lpResString = ( LPSTR )calloc( nStringLen + 1, sizeof ( CHAR ) );
+
+ if ( ! lpResString ) {
+ return 0;
+ }
+
+ RSM_StringCopy ( LOWORD((DWORD)lpString), lpResString, nStringLen + 1 );
+ lpString = lpResString;
+ }
+
+ hDC = CreateIC ( TEXT("DISPLAY"), NULL, NULL, NULL );
+ hDCMem = CreateCompatibleDC ( hDC );
+
+ // Select the new font and save the old font to put it back.
+
+ hOldFont = SelectObject ( hDCMem, hFont );
+
+ // Get the text extent width and height.
+
+ GetTextExtentPoint ( hDCMem, lpString, nStringLen, &sizeRect );
+
+ // Put back the old font. Just for fun.
+
+ SelectObject ( hDC, hOldFont );
+
+ DeleteDC ( hDCMem );
+ DeleteDC ( hDC );
+
+ // Free up any memory allocated.
+
+ if ( lpResString ) {
+ free ( lpResString );
+ }
+
+ return sizeRect.cx;
+
+} /* end RSM_GetFontStringWidth() */
+
+
+/******************************************************************************
+
+ Name: RSM_StringLoad()
+
+ Description: This function loads a string from the resources.
+
+ Returns: The number of characters copied into the buffer. It is
+ 0 if unsuccessful.
+
+ Note: String Resources are pulled from the DLL.
+
+******************************************************************************/
+
+INT RSM_StringLoad (
+
+VOID_PTR pID, // I - ID of the string to load
+LPSTR lpBuffer, // O - pointer to destination buffer area
+INT nBufferMax ) // I - max number of characters to copy
+
+{
+ return LoadString ( ghResInst, (WORD)(DWORD)pID, lpBuffer, nBufferMax );
+
+} /* end RSM_StringLoad() */
+
+
+/******************************************************************************
+
+ Name: RSM_Sprintf()
+
+ Description: This function loads a string from the resources.
+
+ Returns: The number of characters copied into the buffer. It is
+ 0 if unsuccessful.
+
+******************************************************************************/
+
+INT RSM_Sprintf (
+
+LPSTR lpDestBuffer, // O - pointer to destination buffer area
+LPSTR lpFormatBuffer, // I - pointer to format string area
+... ) // I - argument list
+
+{
+ va_list lpArgList ;
+ CHAR szTemp[MAX_UI_RESOURCE_SIZE];
+ INT nCount;
+
+ // If the pointer contains a resource ID, get the string from the
+ // resources.
+
+ if ( lpFormatBuffer && ! HIWORD(lpFormatBuffer) ) {
+
+ RSM_StringCopy ( LOWORD((DWORD)lpFormatBuffer), szTemp, sizeof ( szTemp ) );
+ lpFormatBuffer = szTemp;
+ }
+
+ va_start( lpArgList, lpFormatBuffer ) ;
+
+ nCount = wvsprintf ( lpDestBuffer, lpFormatBuffer, lpArgList );
+
+ va_end( lpArgList ) ;
+
+ return nCount;
+
+} /* end RSM_Sprintf() */
+
+
+/******************************************************************************
+
+ Name: RSM_CursorLoad()
+
+ Description: This function loads an icon from the resources.
+
+ Returns: The handle to the icon if successful. It is
+ 0 if unsuccessful.
+
+ Note: Icon Resources are pulled from the DLL.
+
+******************************************************************************/
+
+HCURSOR RSM_CursorLoad (
+
+LPSTR pID ) // I - ID of the icon to load
+
+{
+ HANDLE hInst = ( ( pID < WIN_RES_MIN ) ? ghResInst : 0 );
+
+ return LoadCursor ( hInst, pID );
+
+} /* end RSM_CursorLoad() */
+
+
+/******************************************************************************
+
+ Name: RSM_IconLoad()
+
+ Description: This function loads an icon from the resources.
+
+ Returns: The handle to the icon if successful. It is
+ 0 if unsuccessful.
+
+ Note: Icon Resources are pulled from the EXE.
+
+******************************************************************************/
+
+HICON RSM_IconLoad (
+
+LPSTR pID ) // I - ID of the icon to load
+
+{
+ HANDLE hInst = ( ( pID < WIN_RES_MIN ) ? ghInst : 0 );
+
+ return LoadIcon ( hInst, pID );
+
+} /* end RSM_IconLoad() */
+
+
diff --git a/private/utils/ntbackup/src/rest_dle.c b/private/utils/ntbackup/src/rest_dle.c
new file mode 100644
index 000000000..3426e970e
--- /dev/null
+++ b/private/utils/ntbackup/src/rest_dle.c
@@ -0,0 +1,259 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: rest_dle.c
+
+ Description: this file contains the routines to process a dle for restore
+
+ $Log: T:\logfiles\rest_dle.c_v $
+
+ Rev 1.16.1.0 07 Feb 1994 02:06:50 GREGG
+Fixed and expanded 'extended error reporting'.
+
+ Rev 1.16 11 Oct 1993 18:32:56 DON
+If ABORT_OPERATION still need to get the next tape request with ABORT
+
+ Rev 1.15 14 Jan 1993 13:33:24 STEVEN
+added stream_id to error message
+
+ Rev 1.14 08 Apr 1992 17:40:22 NED
+added handling of TFLE_USER_ABORT
+from LP_StartTPEDialog().
+Marilyn made me do it!
+
+ Rev 1.13 16 Mar 1992 16:23:16 STEVEN
+initialize the DBLKS
+
+ Rev 1.12 24 Feb 1992 09:58:24 GREGG
+Call TF_OpenTape at beginning of loop, Open/Close Set in loop, CloseTape at end.
+
+ Rev 1.11 19 Feb 1992 16:00:16 GREGG
+Added vcb_only parameter to call to TF_OpenSet.
+
+ Rev 1.10 06 Nov 1991 18:22:34 GREGG
+BIGWHEEL - 8200sx - Get cat_enabled from lp instead of lis.
+
+ Rev 1.9 17 Oct 1991 01:51:30 ED
+BIGWHEEL - 8200sx - Initial integration.
+
+ Rev 1.8 27 Aug 1991 13:35:30 STEVEN
+would stop after one DDB
+
+ Rev 1.7 16 Aug 1991 17:11:40 STEVEN
+Could not Verify or Restore multiple sets
+
+ Rev 1.6 22 Jul 1991 10:56:26 DAVIDH
+Corrected type mismatch warnings.
+
+ Rev 1.5 24 Jun 1991 17:21:56 STEVEN
+remove date time from StartBS
+
+ Rev 1.4 21 Jun 1991 09:22:22 STEVEN
+new config unit
+
+ Rev 1.3 30 May 1991 09:14:46 STEVEN
+bsdu_err.h no longer exists
+
+ Rev 1.2 24 May 1991 14:45:32 STEVEN
+complete changes for new getnext
+
+ Rev 1.1 14 May 1991 14:51:06 DAVIDH
+Resolved pointer type mismatch warning under Watcom compiler
+
+
+ Rev 1.0 09 May 1991 13:34:26 HUNTER
+Initial revision.
+
+**/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "queues.h"
+#include "msassert.h"
+#include "tbe_defs.h"
+#include "tbe_err.h"
+#include "bsdu.h"
+#include "fsys.h"
+#include "tflproto.h"
+#include "tfldefs.h"
+#include "loops.h"
+#include "loop_prv.h"
+#include "lis.h"
+#include "get_next.h"
+
+/**/
+/**
+
+ Name: LP_RestoreDLE()
+
+ Description: This function restores all the objects for a specirfied
+ Backup Set.
+
+ Modified: 5/23/1991 16:49:25
+
+ Returns: Any lower layer error enountered.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 LP_RestoreDLE(
+BSD_PTR bsd_ptr, /* I - The verify selections */
+register LP_ENV_PTR lp, /* I - The Loop Environment struct */
+BOOLEAN reuse_bsd, /* I - TRUE if this is the same BSD */
+INT16 channel_no, /* I - The channel number */
+THW_PTR sdrv ) /* I - The starting drive */
+{
+ INT16 return_status ;
+ DBLK_PTR curr_blk ;
+ TFL_OPBLK pb ;
+ DATA_FRAGMENT data_frag ;
+ LBA_ELEM lba_elem ;
+ BOOLEAN lba_empty ;
+
+ /* setup requested tape id and tape seq number */
+ if( ( ( BSD_GetTapeID( bsd_ptr ) != -1 ) ||
+ ( BSD_GetTapeNum( bsd_ptr ) != -1 ) ) &&
+ ( !reuse_bsd ) ) {
+ lp->tpos.tape_id = BSD_GetTapeID( bsd_ptr ) ;
+ lp->tpos.tape_seq_num = BSD_GetTapeNum( bsd_ptr ) ;
+ }
+
+ memset( lp->curr_ddb, 0, sizeof(DBLK) ) ;
+ memset( lp->curr_blk, 0, sizeof(DBLK) ) ;
+
+ pb.tape_position = &lp->tpos ;
+ pb.sdrv = sdrv ;
+ pb.channel = channel_no ;
+ pb.rewind_sdrv = FALSE ;
+ pb.perm_filter = TF_KEEP_ALL_DATA ;
+ pb.attributes = 0L ;
+ pb.fsh = lp->curr_fsys ;
+ pb.mode = TF_READ_OPERATION ;
+ pb.ignore_clink = FALSE ;
+ pb.wrt_format = 0 ;
+ pb.idle_call = NULL ;
+ pb.cat_enabled = lp->cat_enabled ;
+ data_frag.buffer_used = 0 ;
+ data_frag.buffer_size = 0 ;
+ data_frag.memory_allocated = 0 ;
+ data_frag.buffer = NULL ;
+
+ if( !reuse_bsd ) {
+ /* Setup for FFR based operation... */
+ lp->tpos.tape_loc.pba_vcb = BSD_GetPBA( bsd_ptr );
+ lp->rr.tape_loc.pba_vcb = BSD_GetPBA( bsd_ptr );
+ }
+
+ lba_empty = BSD_GetFirstLBA( bsd_ptr, &lba_elem ) ;
+
+ if ( !reuse_bsd && !lba_empty ) {
+
+ lp->tpos.tape_loc.tape_seq = LBA_GetTapeNum( &lba_elem );
+ lp->tpos.tape_loc.lba = LBA_GetLBA( &lba_elem );
+ lp->rr.tape_loc.tape_seq = LBA_GetTapeNum( &lba_elem );
+ lp->rr.tape_loc.lba = LBA_GetLBA( &lba_elem );
+ pb.tape_position->tape_seq_num = LBA_GetTapeNum( &lba_elem );
+ pb.tape_position->tape_id = BSD_GetTapeID( bsd_ptr );
+
+ } else {
+
+ /* If not a FFR drive, nor a drive which can be mode switched to FFR, nor an SX drive then
+ make sure that PBA of the VCB has been cleared */
+ if( !( BSD_HardwareSupportsFeature( bsd_ptr, TDI_FAST_NBLK ) ||
+ BSD_HardwareSupportsFeature( bsd_ptr, TDI_MODE_CHANGE ) ||
+ BSD_HardwareSupportsFeature( bsd_ptr, TDI_FIND_BLK ) ) ) {
+ lp->tpos.tape_loc.pba_vcb = 0 ;
+ lp->rr.tape_loc.pba_vcb = 0 ;
+ }
+
+ }
+
+
+ /* Now open the backup set */
+ if( ( return_status = TF_OpenSet( &pb, FALSE ) ) == SUCCESS ) {
+
+ /* store the channel */
+ lp->channel = pb.channel ;
+
+ if( ( return_status = LP_StartTPEDialogue( lp, FALSE ) ) == SUCCESS ) {
+
+ /* log start of backup set */
+ LP_MsgStartBS( lp->lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, lp->curr_blk ) ;
+
+ /* Now we have the GetNextItemLoop */
+ while( return_status == SUCCESS ) {
+
+ if( ( return_status = LP_GetNextTPEBlock( lp, &curr_blk ) ) == SUCCESS ) {
+
+ if ( curr_blk != NULL ) {
+ return_status = LP_RestoreOBJ( lp, curr_blk, &data_frag ) ;
+ } else {
+ break ;
+ }
+
+ }
+
+ /* check for abort conditions */
+ switch( LP_GetAbortFlag( lp->lis_ptr ) ) {
+
+ case CONTINUE_PROCESSING:
+ break ;
+
+ case ABORT_CTRL_BREAK:
+ LP_MsgError( lp->lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, LP_USER_ABORT_ERROR, NULL, NULL, 0L ) ;
+
+ /* falling through (no break) */
+
+ case ABORT_PROCESSED:
+ return_status = USER_ABORT ;
+ break ;
+
+ case ABORT_AT_EOM:
+ return_status = USER_ABORT ;
+ break ;
+ }
+ }
+
+ /* Log end of backup set */
+ LP_MsgEndBS( lp->lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos ) ;
+
+ } else if ( return_status == TFLE_USER_ABORT ) {
+ LP_MsgError( lp->lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, LP_USER_ABORT_ERROR, NULL, NULL, 0L ) ;
+ }
+
+ /* Process last tape format request as long as no fatal error occurred */
+ // NOTE: COMM_FAILUREs will return ABORT_OPERATION
+ if( ( return_status == ABORT_OPERATION ) || ( return_status == USER_ABORT ) && ( LP_GetAbortFlag( lp->lis_ptr ) != ABORT_AT_EOM ) ) {
+ lp->rr.lp_message = LRR_ABORT ;
+ if( ( TF_GetNextTapeRequest( &lp->rr ) ) != SUCCESS ) {
+ LP_MsgError( lp->lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, return_status, NULL, NULL, 0L ) ;
+ }
+ }
+
+ /* Close set, save current tape device and post tape stats */
+ LP_CloseSet( pb.channel ) ;
+
+ }
+ else {
+ TF_CloseSet( lp->channel, NULL ) ;
+ if( return_status == TFLE_USER_ABORT ) {
+ LP_MsgError( lp->lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, LP_USER_ABORT_ERROR, NULL, NULL, 0L ) ;
+
+ } else if( return_status != TFLE_UI_HAPPY_ABORT ) {
+ LP_MsgError( lp->lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, return_status, NULL, NULL, 0L ) ;
+ }
+ }
+
+ free( data_frag.buffer ) ;
+
+ return( return_status ) ;
+
+}
diff --git a/private/utils/ntbackup/src/rest_obj.c b/private/utils/ntbackup/src/rest_obj.c
new file mode 100644
index 000000000..a411fd3f2
--- /dev/null
+++ b/private/utils/ntbackup/src/rest_obj.c
@@ -0,0 +1,983 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: rest_obj.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+
+ $Log: N:\logfiles\rest_obj.c_v $
+
+ Rev 1.49.1.1 04 Mar 1994 16:52:14 STEVEN
+prompt if disk is full
+
+ Rev 1.49.1.0 01 Dec 1993 14:07:40 STEVEN
+fix problem with re-reading path stream
+
+ Rev 1.49 24 Aug 1993 19:47:56 STEVEN
+fix too_long bugs
+
+ Rev 1.48 19 Aug 1993 16:32:24 STEVEN
+fix unicode bugs
+
+ Rev 1.47 30 Jul 1993 13:17:50 STEVEN
+if dir too deep make new one
+
+ Rev 1.46 19 Jul 1993 14:25:08 BARRY
+Added code to skip files when told to do so by FS_CreateObj or FS_OpenObj.
+
+ Rev 1.45 13 Jul 1993 11:59:46 DON
+Added case for FS_IN_USE_ERROR on WriteObj call. This is the only time we know this in SMS
+
+ Rev 1.44 28 Jun 1993 15:23:22 DEBBIE
+803EPR0311 - Because the code for the FS_ACCESS_DENIED error returned from
+ FS_WriteObj would set error to SUCCESS, the bytes and file were
+ not getting added to the skipped stats. I added the calls to
+ LP_MsgBlockSkipped and LP_MsgBytesSkipped there.
+
+ Rev 1.43 01 Jun 1993 15:19:58 CARLS
+code was sending LP_MsgBlockSkipped twice
+
+ Rev 1.42 25 May 1993 17:18:36 DON
+If we LP_SkipStream then don't attempt to CheckSum!
+
+ Rev 1.41 20 May 1993 20:22:46 DON
+If we have a COMM Failure then we need to abort the restore
+
+ Rev 1.40 13 May 1993 13:47:54 BARRY
+Send msg to UI when the FS restores over an active file.
+
+ Rev 1.39 11 May 1993 13:08:06 DON
+Need to check for COMM_FAILURE during read/write operations. May lose attachment!
+
+ Rev 1.38 31 Mar 1993 08:51:54 MARILYN
+changed over to use MTF checksums, display message when a data stream
+does not have a checksum when we are supposed to be processing them
+
+ Rev 1.37 09 Mar 1993 12:27:36 STEVEN
+if we have an access violation writing a stream then skip to next stream
+
+ Rev 1.36 04 Mar 1993 15:36:22 MARILYN
+Now sending back LP_LOG_DIFFERENCE when the checksum verification fails.
+
+ Rev 1.35 01 Mar 1993 17:36:16 MARILYN
+If BEC_GetProcChecksumStrms is set, a checksum will be computed for
+each object restored and verified against the checksum stream on
+tape (if it exists).
+
+ Rev 1.34 19 Feb 1993 09:21:36 STEVEN
+fix some bugs
+
+ Rev 1.33 04 Feb 1993 18:05:00 STEVEN
+fix problem with calling back tpfmt if error ocured
+
+ Rev 1.32 01 Feb 1993 19:46:30 STEVEN
+bug fixes
+
+ Rev 1.31 27 Jan 1993 13:50:52 STEVEN
+updates from msoft
+
+ Rev 1.30 14 Jan 1993 16:40:12 STEVEN
+fix bugs in last checkin
+
+ Rev 1.29 14 Jan 1993 13:33:56 STEVEN
+added stream_id to error message
+
+ Rev 1.28 04 Nov 1992 13:23:34 STEVEN
+fix various bugs with read
+
+ Rev 1.27 04 Nov 1992 09:29:18 STEVEN
+fix initial receive
+
+ Rev 1.26 03 Nov 1992 10:09:30 STEVEN
+change the way we skip data
+
+ Rev 1.25 19 Oct 1992 15:55:36 STEVEN
+remaining size is gone
+
+ Rev 1.24 05 Oct 1992 10:29:54 STEVEN
+remove TotalSize
+
+ Rev 1.23 16 Sep 1992 16:55:18 STEVEN
+added support for stream info struct for Tpfmt
+
+ Rev 1.22 01 Sep 1992 16:12:10 STEVEN
+added stream headers to fsys API
+
+ Rev 1.21 23 Jul 1992 16:45:50 STEVEN
+fix warnings
+
+ Rev 1.19 23 Jul 1992 12:13:46 STEVEN
+fix warnings
+
+ Rev 1.18 27 May 1992 17:39:24 TIMN
+Changed CHARs to INT8s
+
+ Rev 1.17 05 May 1992 17:19:24 STEVEN
+fixed typos and misc bugs
+
+ Rev 1.16 27 Apr 1992 16:41:54 STEVEN
+fix typo in include
+
+ Rev 1.15 20 Mar 1992 13:43:32 STEVEN
+do not prompt for special files
+
+ Rev 1.14 16 Mar 1992 16:40:34 STEVEN
+more 64 bit support for format 40
+
+ Rev 1.13 13 Mar 1992 09:23:28 STEVEN
+4.0 tape format 64 bit
+
+ Rev 1.12 04 Feb 1992 10:35:56 DON
+if NOT defined FS_IMAGE then Images should be ignored
+
+ Rev 1.11 11 Dec 1991 14:09:34 STEVEN
+read converted to FS_READ
+
+ Rev 1.10 18 Oct 1991 14:11:28 STEVEN
+BIGWHEEL-add support for prompt before restore over exist
+
+ Rev 1.9 02 Oct 1991 15:34:58 STEVEN
+BIGWEEL - Added support for Prompt before restore over existing
+
+ Rev 1.8 19 Sep 1991 17:00:22 STEVEN
+fix warning for UNSIGNED SIGNED mismatch
+
+ Rev 1.7 10 Sep 1991 18:19:40 DON
+got rid of pointer type mismatches
+
+ Rev 1.6 25 Jul 1991 10:39:14 STEVEN
+remove 0 length files if disk is full
+
+ Rev 1.5 27 Jun 1991 13:05:46 STEVEN
+removed unused parm to ReceiveData
+
+ Rev 1.4 21 Jun 1991 09:22:42 STEVEN
+new config unit
+
+ Rev 1.3 30 May 1991 09:14:06 STEVEN
+bsdu_err.h no longer exists
+
+ Rev 1.2 24 May 1991 14:45:18 STEVEN
+complete changes for new getnext
+
+ Rev 1.1 14 May 1991 14:52:08 DAVIDH
+Initialized blk_size to 0 -- resolved Watcom compiler warning
+
+
+ Rev 1.0 09 May 1991 13:34:28 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "queues.h"
+#include "beconfig.h"
+#include "msassert.h"
+#include "tbe_defs.h"
+#include "tbe_err.h"
+#include "bsdu.h"
+#include "fsys.h"
+#include "tflproto.h"
+#include "tfldefs.h"
+#include "loops.h"
+#include "loop_prv.h"
+#include "lis.h"
+#include "sleep.h"
+#include "checksum.h"
+/* $end$ include list */
+
+#define TOO_DEEP_DIR TEXT("TOO_LONG.BKP")
+
+/* static variables */
+static DBLK disk_dblk ;
+
+static INT16 LP_ShortenDDB( LP_ENV_PTR lp, DBLK_PTR tape_dblk_ptr ) ;
+
+/**/
+/**
+
+ Name: LP_RestoreOBJ()
+
+ Description:
+
+ Modified: 7/20/1989
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 LP_RestoreOBJ(
+register LP_ENV_PTR lp, /* I - Loop environment structure */
+DBLK_PTR tape_dblk_ptr, /* I - Object to be restored. */
+DATA_FRAGMENT_PTR frag_ptr ) /* I - Buffer to use for fragments */
+{
+ INT16 res_id ;
+ UINT16 write_size ;
+ UINT16 atempt_size ;
+ UINT16 blk_size = 0 ;
+ UINT32 attr ;
+ BOOLEAN do_it, skippedStream ;
+ UINT64 amount_restored ;
+ INT16 error = SUCCESS ;
+ INT16 buffer_used_size ;
+ INT8_PTR tape_data_buf ;
+ INT16 return_status = SUCCESS ;
+ BOOLEAN math_status ;
+ UINT32 checksum ;
+ STREAM_INFO savedStrmHeader ;
+ BOOLEAN block_skipped_flag = TRUE ;
+ BOOLEAN temp_renamed_dir = FALSE ;
+ DBLK temp_new_dir ;
+ UINT32 last_stream_id = STRM_INVALID ;
+
+
+
+ BSD_PTR bsd_ptr ;
+ FSYS_HAND fsh ;
+ UINT32 pid ;
+ BE_CFG_PTR cfg ;
+ FILE_HAND hdl = NULL ;
+
+ fsh = lp->curr_fsys ;
+ bsd_ptr = lp->lis_ptr->curr_bsd_ptr ;
+ pid = lp->lis_ptr->pid ;
+ cfg = BSD_GetConfigData( bsd_ptr ) ;
+
+ amount_restored = U64_Init(0,0) ;
+
+ /* if it is a CFDB ... */
+ if( FS_GetBlockType( tape_dblk_ptr ) == BT_CFDB ) {
+
+ return_status = LP_MsgLogBlock( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr ) ;
+
+ return return_status ;
+
+ }
+
+#ifndef FS_IMAGE
+
+ if( FS_GetBlockType( tape_dblk_ptr ) == BT_IDB ) {
+ LP_MsgBlockSkipped( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, lp->curr_ddb ) ;
+ LP_MsgBytesSkipped( pid, bsd_ptr, fsh, &lp->tpos, FS_GetDisplaySizeFromDBLK( fsh, tape_dblk_ptr ) ) ;
+ LP_SkipData( lp ) ;
+ return SUCCESS ;
+ }
+
+#endif
+
+ /* if the current directory is invalid AND it is a file ... */
+ if( lp->ddb_create_error && FS_GetBlockType( tape_dblk_ptr ) == BT_FDB) {
+
+ switch( lp->ddb_create_error ) {
+ case FS_OUT_OF_SPACE:
+ res_id = LP_OUT_OF_SPACE_ERROR ;
+ break ;
+
+ case FS_ACCESS_DENIED:
+ res_id = LP_ACCESS_DENIED_ERROR ;
+ break ;
+
+ case FS_COMM_FAILURE:
+ res_id = FS_COMM_FAILURE;
+ break;
+
+ case FS_DEVICE_ERROR:
+ default:
+ res_id = LP_FILE_CREATION_ERROR ;
+ break ;
+ }
+
+ LP_MsgError( pid, bsd_ptr, fsh, &lp->tpos, res_id, lp->curr_ddb, tape_dblk_ptr, 0L ) ;
+ LP_MsgBlockSkipped( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, lp->curr_ddb ) ;
+ LP_MsgBytesSkipped( pid, bsd_ptr, fsh, &lp->tpos, FS_GetDisplaySizeFromDBLK( fsh, tape_dblk_ptr ) ) ;
+ LP_SkipData( lp ) ;
+
+ if ( lp->ddb_create_error == FS_COMM_FAILURE ) {
+ return FAILURE;
+ } else {
+ return SUCCESS ;
+ }
+ }
+
+ disk_dblk = *tape_dblk_ptr ;
+
+ /* determine if continuation file */
+ do_it = TRUE ;
+ if ( FS_IsBlockContinued( tape_dblk_ptr ) ) {
+ do_it = LP_MsgPrompt( pid, bsd_ptr, fsh, &lp->tpos,
+ ASK_TO_RESTORE_CONTINUE, tape_dblk_ptr, NULL ) ;
+ }
+
+ if( do_it ) {
+ /* determine whether block exists or not on disk */
+ switch( FS_GetObjInfo( fsh, &disk_dblk ) ) {
+ case FS_ACCESS_DENIED:
+
+ LP_MsgError( pid, bsd_ptr, fsh, &lp->tpos, LP_ACCESS_DENIED_ERROR, lp->curr_ddb, &disk_dblk, 0L ) ;
+ LP_MsgBlockSkipped( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, lp->curr_ddb ) ;
+ LP_MsgBytesSkipped( pid, bsd_ptr, fsh, &lp->tpos, FS_GetDisplaySizeFromDBLK( fsh, tape_dblk_ptr ) ) ;
+
+ if( FS_GetBlockType( tape_dblk_ptr ) == BT_DDB ) {
+ lp->ddb_create_error = FS_ACCESS_DENIED ;
+ }
+
+ LP_SkipData( lp ) ;
+
+ return SUCCESS ;
+
+ case FS_COMM_FAILURE:
+
+ LP_MsgError( pid, bsd_ptr, fsh, &lp->tpos, FS_COMM_FAILURE, lp->curr_ddb, &disk_dblk, 0L ) ;
+ LP_MsgBlockSkipped( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, lp->curr_ddb ) ;
+ LP_MsgBytesSkipped( pid, bsd_ptr, fsh, &lp->tpos, FS_GetDisplaySizeFromDBLK( fsh, tape_dblk_ptr ) ) ;
+ if( FS_GetBlockType( tape_dblk_ptr ) == BT_DDB ) {
+ lp->ddb_create_error = FS_COMM_FAILURE;
+ }
+ LP_SkipData( lp ) ;
+
+ return SUCCESS;
+
+ case FS_NOT_FOUND:
+ case FS_NO_MORE:
+ break ;
+
+ case SUCCESS:
+ if( (FS_GetBlockType( tape_dblk_ptr ) == BT_FDB) &&
+ !FS_SpecExcludeObj( fsh, lp->curr_ddb, tape_dblk_ptr ) ) {
+
+ /* handle condition to restore existing files */
+ if( BEC_GetExistFlag( cfg ) == BEC_NO_REST_OVER_EXIST ) {
+ do_it = FALSE ;
+
+ } else if( BEC_GetExistFlag( cfg ) == BEC_PROMPT_REST_OVER_EXIST ) {
+ do_it = LP_MsgPrompt( pid, bsd_ptr, fsh, &lp->tpos,
+ ASK_TO_REPLACE_EXISTING, tape_dblk_ptr, &disk_dblk ) ;
+
+ } else {
+
+ attr = FS_GetAttribFromDBLK( fsh, &disk_dblk ) ;
+
+ /* handle condition to restore the file if it was modified or read only ... */
+ if( ( ( attr & OBJ_MODIFIED_BIT ) || ( attr & OBJ_READONLY_BIT ) ) ) {
+ /* ... and if the user should be prompted ... */
+ if( BEC_GetPromptFlag( cfg ) ) {
+ do_it = LP_MsgPrompt( pid, bsd_ptr, fsh, &lp->tpos,
+ ASK_TO_REPLACE_MODIFIED, tape_dblk_ptr, NULL ) ;
+ }
+ }
+ }
+ }
+
+ break ;
+ default:
+ msassert( FALSE ) ; /* this should never happen */
+ break ;
+ }
+ }
+
+ if( !do_it ) {
+ /* never mind ... */
+ LP_SkipData( lp ) ;
+
+ return SUCCESS ;
+
+ }
+
+#ifdef TDEMO
+ error = SUCCESS ;
+#else
+ error = FS_CreateObj( fsh, tape_dblk_ptr ) ;
+
+ if ( error == FS_PATH_TOO_LONG ) {
+
+ if( FS_GetBlockType( tape_dblk_ptr ) == BT_DDB ) {
+ LP_ShortenDDB( lp, tape_dblk_ptr ) ;
+ error = FS_CreateObj( fsh, tape_dblk_ptr ) ;
+
+ } else if( FS_GetBlockType( tape_dblk_ptr ) == BT_FDB ) {
+
+ BOOLEAN save_ignore_data_flag = lp->ignore_data_for_ddb ;
+
+ lp->ignore_data_for_ddb = TRUE ;
+ FS_DuplicateDBLK( fsh, lp->curr_ddb, &temp_new_dir ) ;
+ LP_ShortenDDB( lp, lp->curr_ddb ) ;
+
+ error = LP_RestoreOBJ( lp, lp->curr_ddb, frag_ptr ) ;
+
+ lp->ignore_data_for_ddb = save_ignore_data_flag ;
+
+ if ( error != SUCCESS ) {
+ return( error ) ;
+ } else {
+
+ temp_renamed_dir = TRUE ;
+ error = FS_CreateObj( fsh, tape_dblk_ptr ) ;
+ if ( error != SUCCESS ) {
+ LP_ShortenDDB( lp, lp->curr_ddb ) ;
+ error = LP_RestoreOBJ( lp, lp->curr_ddb, frag_ptr ) ;
+ if ( error != SUCCESS ) {
+ return( error ) ;
+ }
+ error = FS_CreateObj( fsh, tape_dblk_ptr ) ;
+
+ if ( error != SUCCESS ) {
+
+ FS_ReleaseDBLK( fsh, lp->curr_ddb ) ;
+ FS_DuplicateDBLK( fsh, &temp_new_dir, lp->curr_ddb );
+ temp_renamed_dir = FALSE ;
+ }
+ }
+ }
+
+ }
+ }
+
+#endif
+
+ while ( error == FS_OUT_OF_SPACE ) {
+
+ /* I am assuming that an out of PathTooLong error would be */
+ /* returned instead of OUT_OF_SPACE if the path was to long */
+
+ if ( LP_MsgPrompt( pid, bsd_ptr, fsh, &lp->tpos,
+ ASK_DISK_FULL, tape_dblk_ptr, NULL ) ) {
+
+ error = FS_CreateObj( fsh, tape_dblk_ptr ) ;
+
+ } else {
+ LP_MsgError( pid, bsd_ptr, fsh, &lp->tpos, LP_OUT_OF_SPACE_ERROR, lp->curr_ddb, tape_dblk_ptr, 0L ) ;
+ break ;
+ }
+ }
+
+
+ if( FS_GetBlockType( tape_dblk_ptr ) == BT_DDB ) {
+ lp->ddb_create_error = error ;
+ }
+
+ if( error != SUCCESS ) {
+
+ switch( error ) {
+
+ case FS_SKIP_OBJECT: /* Do nothing for skip request. */
+ break;
+
+ case FS_OUT_OF_SPACE:
+ res_id = LP_OUT_OF_SPACE_ERROR ;
+ break ;
+
+ case FS_ACCESS_DENIED:
+ res_id = LP_ACCESS_DENIED_ERROR ;
+ break ;
+
+ case FS_INCOMPATIBLE_OBJECT :
+ res_id = LP_FILE_OPEN_ERROR ;
+ break ;
+
+ case FS_COMM_FAILURE:
+ res_id = FS_COMM_FAILURE;
+ break;
+
+ case FS_DEVICE_ERROR:
+ default:
+ res_id = LP_FILE_CREATION_ERROR ;
+ break ;
+ }
+
+ if ( error != FS_SKIP_OBJECT ) {
+ LP_MsgError( pid, bsd_ptr, fsh, &lp->tpos, res_id, lp->curr_ddb, tape_dblk_ptr, -1L ) ;
+ }
+
+ if ( DLE_GetDeviceType(BSD_GetDLE(bsd_ptr)) == FS_EMS_DRV ) {
+ return (error ) ;
+
+ } else if( FS_GetBlockType( tape_dblk_ptr ) == BT_IDB ) {
+ LP_FinishedOper( lp ) ;
+
+ return( error ) ;
+
+ } else {
+
+ /* quietly skip the object */
+ if ( error != FS_SKIP_OBJECT ) {
+ LP_MsgBlockSkipped( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, lp->curr_ddb ) ;
+ LP_MsgBytesSkipped( pid, bsd_ptr, fsh, &lp->tpos, FS_GetDisplaySizeFromDBLK( fsh, tape_dblk_ptr ) ) ;
+ }
+
+ LP_SkipData( lp ) ;
+
+ if ( error == FS_COMM_FAILURE ) {
+ return FAILURE;
+ } else {
+ return SUCCESS ;
+ }
+ }
+ }
+
+ LP_MsgLogBlock( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr ) ; /* create may change block */
+
+#ifdef TDEMO
+ error = SUCCESS ;
+#else
+ error = FS_OpenObj( fsh, &hdl, tape_dblk_ptr, FS_WRITE ) ;
+#endif
+
+ if(( error == FS_COMPRES_RESET_FAIL )||
+ ( error == FS_EMS_NO_PUBLIC ) ||
+ ( error == FS_EMS_NO_PRIVATE ) ) {
+ LP_MsgError( pid,
+ bsd_ptr,
+ fsh,
+ &lp->tpos,
+ error,
+ lp->curr_ddb,
+ tape_dblk_ptr,
+ 0L ) ;
+
+ }
+
+ if( error == FS_COMPRES_RESET_FAIL ) {
+ error = SUCCESS ;
+ }
+
+ if( error == SUCCESS ) {
+
+ Checksum_Init( &checksum ) ;
+ skippedStream = FALSE;
+
+ /* restore the object here */
+ if ( !lp->ignore_data_for_ddb ) {
+ buffer_used_size = lp->initial_tape_buf_used ;
+
+ /* get initial data */
+ if( ( error = LP_ReceiveData( lp, buffer_used_size ) ) != ABORT_OPERATION ) {
+ tape_data_buf = lp->rr.buff_ptr ;
+ write_size = lp->rr.buff_size ;
+ }
+ }
+
+ /* If the current data stream is not checksumed, tell em */
+ if ( BEC_GetProcChecksumStrm( cfg ) &&
+ ( lp->rr.stream.id != STRM_INVALID ) &&
+ ( lp->rr.stream.id != STRM_PAD ) &&
+ !FS_IsStreamChecksumed( &lp->rr.stream ) ) {
+
+ LP_MsgNoChecksum( pid,
+ bsd_ptr,
+ fsh,
+ &lp->tpos,
+ tape_dblk_ptr,
+ lp->curr_ddb,
+ 0L ) ;
+
+ }
+
+ while( !lp->ignore_data_for_ddb && !error && lp->rr.tf_message == TRR_DATA )
+ {
+ /* if checksum processing enabled, calculate */
+ /* the checksum for the object */
+ if ( FS_IsStreamChecksumed( &lp->rr.stream ) ) {
+
+ Checksum_Block( &checksum, lp->rr.buff_ptr, lp->rr.buff_size ) ;
+
+ /* we need to know the type of stream being processed */
+ /* so that our data corrupt message will be able to */
+ /* inform the user what type of data was corrupt */
+ if ( lp->rr.stream.id != STRM_INVALID ) {
+ savedStrmHeader = lp->rr.stream ;
+ }
+ }
+
+ if (lp->rr.stream.id != STRM_INVALID ) {
+ if ( (last_stream_id == STRM_EMS_MONO_DB) ||
+ (last_stream_id == STRM_EMS_MONO_LOG) ) {
+
+ CHAR strm_name[256] ;
+ INT16 size = sizeof(strm_name) ;
+
+ EMS_GetStreamName( hdl, (BYTE_PTR)strm_name, &size ) ;
+ LP_MsgLogStream( pid, bsd_ptr, fsh, &lp->tpos, strm_name ) ;
+
+ }
+
+ last_stream_id = lp->rr.stream.id ;
+ }
+
+ atempt_size = write_size ;
+
+#ifdef TDEMO
+ if ( (FAST_TDEMO & BEC_GetSpecialWord( cfg )) == 0 ) {
+ sleep( (UINT32) (write_size / 130) );
+ }
+ error = SUCCESS ;
+#else
+ error = FS_WriteObj( hdl, tape_data_buf, &write_size, &blk_size, &lp->rr.stream ) ;
+#endif
+ switch( error ) {
+
+ case FS_DONT_WANT_STREAM:
+ LP_SkipStream( lp ) ;
+ last_stream_id = STRM_INVALID ;
+ skippedStream = TRUE;
+ error = SUCCESS ;
+ break ;
+
+ case FS_OUT_OF_SPACE:
+
+ if ( !LP_MsgPrompt( pid, bsd_ptr, fsh, &lp->tpos,
+ ASK_DISK_FULL, tape_dblk_ptr, NULL ) ) {
+
+ LP_MsgError( pid, bsd_ptr, fsh, &lp->tpos, LP_OUT_OF_SPACE_ERROR, lp->curr_ddb, tape_dblk_ptr, 0L ) ;
+ break ;
+ } else {
+ error = SUCCESS ;
+ /* fall through */
+ }
+
+ case SUCCESS:
+
+ amount_restored = U64_Add(amount_restored, U64_Init(write_size, 0), &math_status ) ;
+
+ if( FS_GetBlockType( tape_dblk_ptr ) == BT_IDB ) {
+ /* let's lie about the number of bytes processed ( so that we can handle 2.5 images ) */
+ /* the msg handlers must know that we are lying */
+#ifdef TDEMO
+ /* amount_restored is probably equal to the ObjPos durring TMENU */
+ LP_MsgBytesProcessed( pid, bsd_ptr, fsh, &lp->tpos, amount_restored ) ;
+#else
+ LP_MsgBytesProcessed( pid, bsd_ptr, fsh, &lp->tpos, U64_Init(FS_GetObjPosition( hdl ), 0) ) ;
+#endif
+ } else {
+ LP_MsgBytesProcessed( pid, bsd_ptr, fsh, &lp->tpos, U64_Init(write_size, 0) ) ;
+ }
+
+ if( tape_data_buf == lp->rr.buff_ptr ) {
+ buffer_used_size = write_size ;
+ }
+
+ if( ( atempt_size != write_size ) &&
+ ( (UINT16)(atempt_size - write_size) < blk_size ) ) {
+
+ if( frag_ptr->memory_allocated < (UINT16)blk_size ) {
+ free( frag_ptr->buffer ) ;
+
+ frag_ptr->buffer = calloc( 1, blk_size ) ;
+ if( frag_ptr->buffer == NULL ) {
+ error = OUT_OF_MEMORY ;
+#ifndef TDEMO
+ FS_CloseObj( hdl ) ;
+#endif
+ LP_FinishedOper( lp ) ;
+ return OUT_OF_MEMORY ;
+ }
+
+ frag_ptr->memory_allocated = blk_size ;
+ }
+
+ frag_ptr->buffer_used = atempt_size - write_size ;
+ memcpy( frag_ptr->buffer,
+ tape_data_buf + write_size,
+ frag_ptr->buffer_used ) ;
+ buffer_used_size = atempt_size ;
+ }
+
+ break ;
+
+ case FS_ACCESS_DENIED :
+ LP_MsgError( pid, bsd_ptr, fsh, &lp->tpos, LP_ACCESS_DENIED_ERROR, lp->curr_ddb, tape_dblk_ptr, lp->current_stream_id ) ;
+ LP_MsgBlockSkipped( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, lp->curr_ddb ) ;
+ LP_MsgBytesSkipped( pid, bsd_ptr, fsh, &lp->tpos, FS_GetDisplaySizeFromDBLK( fsh, tape_dblk_ptr ) ) ;
+ LP_SkipStream( lp ) ;
+ skippedStream = TRUE;
+ error = SUCCESS ;
+ break ;
+
+ case FS_IN_USE_ERROR:
+ LP_MsgError( pid, bsd_ptr, fsh, &lp->tpos, LP_FILE_IN_USE_ERROR, lp->curr_ddb, tape_dblk_ptr, lp->current_stream_id ) ;
+ LP_MsgBlockSkipped( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, lp->curr_ddb ) ;
+ LP_MsgBytesSkipped( pid, bsd_ptr, fsh, &lp->tpos, FS_GetDisplaySizeFromDBLK( fsh, tape_dblk_ptr ) ) ;
+ LP_SkipStream( lp ) ;
+ skippedStream = TRUE;
+ error = SUCCESS ;
+ break ;
+
+ case FS_DEVICE_ERROR:
+ case FS_COMM_FAILURE:
+ LP_MsgError( pid, bsd_ptr, fsh, &lp->tpos, error, lp->curr_ddb, tape_dblk_ptr, lp->current_stream_id ) ;
+ break;
+
+ default:
+ LP_MsgError( pid, bsd_ptr, fsh, &lp->tpos, LP_FILE_WRITE_ERROR, lp->curr_ddb, tape_dblk_ptr, lp->current_stream_id ) ;
+ break ;
+ }
+
+ /* check for abort conditions */
+ switch( LP_GetAbortFlag( lp->lis_ptr ) ) {
+
+ case CONTINUE_PROCESSING:
+ break ;
+
+ case ABORT_CTRL_BREAK:
+ LP_MsgError( pid, bsd_ptr, fsh, &lp->tpos, LP_USER_ABORT_ERROR, NULL, NULL, 0L ) ;
+
+ /* falling through (no break) */
+
+ case ABORT_PROCESSED:
+ error = USER_ABORT ;
+ break ;
+
+ case ABORT_AT_EOM:
+ error = USER_ABORT ;
+ break ;
+ }
+
+ if( error == SUCCESS ) {
+ /* get more data */
+ if( ( error = LP_ReceiveData( lp, (INT32)buffer_used_size ) ) != ABORT_OPERATION ) {
+
+ if( frag_ptr->buffer_used != 0 ) {
+
+ if( lp->rr.buff_size < (UINT16)(blk_size - frag_ptr->buffer_used) ) {
+ memcpy( frag_ptr->buffer + frag_ptr->buffer_used,
+ lp->rr.buff_ptr,
+ lp->rr.buff_size ) ;
+
+ frag_ptr->buffer_used += lp->rr.buff_size ;
+ buffer_used_size = lp->rr.buff_size ;
+ write_size = 0 ;
+ } else {
+
+ memcpy( frag_ptr->buffer + frag_ptr->buffer_used,
+ lp->rr.buff_ptr,
+ blk_size - frag_ptr->buffer_used ) ;
+
+ tape_data_buf = frag_ptr->buffer ;
+ write_size = blk_size ;
+ buffer_used_size = blk_size - frag_ptr->buffer_used ;
+ frag_ptr->buffer_used = 0 ;
+ }
+
+ } else {
+ write_size = lp->rr.buff_size ;
+ tape_data_buf = lp->rr.buff_ptr ;
+ }
+ }
+
+ } else if( error != USER_ABORT ) {
+
+ block_skipped_flag = FALSE ;
+ LP_MsgBlockSkipped( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, lp->curr_ddb ) ;
+ LP_MsgBytesSkipped( pid, bsd_ptr, fsh, &lp->tpos, FS_GetDisplaySizeFromDBLK( fsh, tape_dblk_ptr ) ) ;
+
+ LP_SkipData( lp ) ;
+ }
+
+ /* if checksum processing if enabled and a checksum stream is encountered, */
+ /* verify that the checksum computed as the object was restored matches */
+ /* the checksum that was stored on tape for the object */
+ if ( !skippedStream && !error &&
+ ( lp->rr.stream.id == STRM_CHECKSUM_DATA ) &&
+ BEC_GetProcChecksumStrm( cfg ) ) {
+
+ error = LP_VerifyChecksumStream( checksum, lp ) ;
+
+ /* Bad news. The checksum data did not match. */
+ /* The data on the tape is corrupt. */
+ if ( error == FS_CRC_FAILURE ) {
+
+ error = LP_MsgLogDifference( pid,
+ bsd_ptr,
+ fsh,
+ &lp->tpos,
+ tape_dblk_ptr,
+ lp->curr_ddb,
+ savedStrmHeader,
+ 0L ) ;
+ }
+
+ /* We know that we just processed an entire stream. Now */
+ /* we need to get the next stream header and set things */
+ /* up to process it. Note: we don't need to frag */
+ /* because no data will be sent back with the header. */
+ if ( lp->rr.tf_message != TRR_FATAL_ERR && !error ) {
+
+ Checksum_Init( &checksum ) ;
+ skippedStream = FALSE;
+ error = LP_ReceiveData( lp, (INT32)lp->rr.buff_size ) ;
+ }
+ }
+ }
+
+ return_status = error ;
+
+
+ if ( (last_stream_id == STRM_EMS_MONO_DB) ||
+ (last_stream_id == STRM_EMS_MONO_LOG) ) {
+
+ CHAR strm_name[256] ;
+ INT16 size = sizeof(strm_name) ;
+
+ EMS_GetStreamName( hdl, (BYTE_PTR)strm_name, &size ) ;
+ LP_MsgLogStream( pid, bsd_ptr, fsh, &lp->tpos, strm_name ) ;
+
+ }
+
+#ifdef TDEMO
+ error = SUCCESS ;
+#else
+ error = FS_CloseObj( hdl );
+#endif
+
+ /*
+ * On NT, if a file was active (open) there is a way to restore
+ * it anyway. But the user needs to know that this happened so
+ * they can reboot to get the files back. Send a message to the
+ * UI so it can be nice.
+ */
+ if ( error == FS_RESTORED_ACTIVE ) {
+ error = SUCCESS;
+ LP_MsgRestoredActive( pid,
+ bsd_ptr,
+ fsh,
+ &lp->tpos,
+ lp->curr_ddb,
+ tape_dblk_ptr );
+ }
+
+ if ( return_status == SUCCESS ) {
+ return_status = error ;
+ }
+
+ if ( ( return_status == FS_OUT_OF_SPACE ) &&
+ ( FS_GetBlockType( tape_dblk_ptr ) == BT_FDB ) ) {
+
+#ifndef TDEMO
+ FS_DeleteObj( fsh, tape_dblk_ptr ) ;
+#endif
+ }
+
+ if ( error == FS_ACCESS_DENIED ) {
+ LP_MsgError( pid, bsd_ptr, fsh, &lp->tpos, LP_PRIVILEGE_ERROR, lp->curr_ddb, tape_dblk_ptr, lp->current_stream_id ) ;
+ } else if ( ( error == FS_COMM_FAILURE ) &&
+ ( DLE_GetDeviceType(BSD_GetDLE(bsd_ptr)) == FS_EMS_DRV ) ) {
+ LP_MsgError( pid, bsd_ptr, fsh, &lp->tpos, error, lp->curr_ddb, tape_dblk_ptr, 0L ) ;
+ return_status = SUCCESS ;
+
+ } else if ( return_status == error ) {
+ return_status = SUCCESS ;
+ }
+
+ if( ( FS_GetBlockType( tape_dblk_ptr ) == BT_FDB ) &&
+ ( FS_GetAttribFromDBLK( fsh, tape_dblk_ptr ) & FILE_IN_USE_BIT ) ) {
+ LP_MsgOpenedInUse( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr ) ;
+ }
+ } else {
+
+ LP_MsgError( pid, bsd_ptr, fsh, &lp->tpos, LP_FILE_OPEN_ERROR, lp->curr_ddb, tape_dblk_ptr, 0L ) ;
+ LP_MsgBlockSkipped( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, lp->curr_ddb ) ;
+ LP_MsgBytesSkipped( pid, bsd_ptr, fsh, &lp->tpos, FS_GetDisplaySizeFromDBLK( fsh, tape_dblk_ptr ) ) ;
+
+ /* skip the data and log it ... */
+ LP_SkipData( lp ) ;
+
+ return SUCCESS ;
+
+ }
+
+ if( return_status == SUCCESS) {
+ if ( FS_GetBlockType( tape_dblk_ptr ) != BT_IDB ) {
+
+ LP_MsgBlockProcessed( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr ) ;
+ }
+
+ } else if( ( return_status != USER_ABORT ) ) {
+
+ /* if FALSE then we already logged error somewhere above */
+ if( block_skipped_flag ) {
+
+ LP_MsgBlockSkipped( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, lp->curr_ddb ) ;
+ LP_MsgBytesSkipped( pid, bsd_ptr, fsh, &lp->tpos, FS_GetDisplaySizeFromDBLK( fsh, tape_dblk_ptr ) ) ;
+
+ /* skip the data and log it ... */
+ LP_SkipData( lp ) ;
+
+ }
+
+ if ( return_status != ABORT_OPERATION ) {
+ return_status = SUCCESS ;
+ }
+
+ }
+
+ if ( temp_renamed_dir ) {
+
+ FS_ReleaseDBLK( fsh, lp->curr_ddb ) ;
+ FS_DuplicateDBLK( fsh, &temp_new_dir, lp->curr_ddb );
+ FS_ChangeIntoDDB( fsh, lp->curr_ddb ) ;
+ temp_renamed_dir = FALSE ;
+ }
+
+ return( return_status ) ;
+
+}
+
+static INT16 LP_ShortenDDB( LP_ENV_PTR lp, DBLK_PTR ddb )
+{
+ CHAR_PTR path ;
+ INT16 psize ;
+ CHAR_PTR p ;
+ CHAR_PTR from ;
+ CHAR_PTR to ;
+ INT16 ret_val ;
+
+ psize = FS_SizeofPathInDDB( lp->curr_fsys, ddb ) ;
+
+ path = calloc( 1, psize ) ;
+
+ if ( path == NULL ) {
+ return OUT_OF_MEMORY;
+ }
+
+ FS_GetPathFromDDB( lp->curr_fsys, ddb, path ) ;
+
+ p = path + psize/sizeof(CHAR) -2 ;
+
+ strcpy( path, TOO_DEEP_DIR ) ;
+
+ for ( ;*p != TEXT('\0'); p-- ) ;
+
+ from = p + 1 ;
+ to = path + strlen( TOO_DEEP_DIR ) + 1 ;
+
+ if ( from == to ) {
+ psize = strsize( TOO_DEEP_DIR ) ;
+ } else {
+ memmove( to, from, psize + ((BYTE_PTR)path - (BYTE_PTR)from) ) ;
+ psize -= ((BYTE_PTR)from - (BYTE_PTR)to) ;
+ }
+
+ ret_val = FS_SetPathInDDB( lp->curr_fsys, ddb, path, &psize ) ;
+
+ free( path ) ;
+
+ return ret_val ;
+}
+
+
+
+
+
diff --git a/private/utils/ntbackup/src/ribproc.c b/private/utils/ntbackup/src/ribproc.c
new file mode 100644
index 000000000..d798e5a04
--- /dev/null
+++ b/private/utils/ntbackup/src/ribproc.c
@@ -0,0 +1,1968 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: ribproc.c
+
+ Description: This file contains the functions for processing messages
+ sent by Windows to ribbon windows. It also contains the
+ supporting functions called the Ribbon Manager (RIB).
+ The functions handle selecting, drawing button items using
+ text and bitmaps ( in up and down positions with enabled and
+ disabled status ), and message sending and posting.
+
+
+ $Log: G:\ui\logfiles\ribproc.c_v $
+
+ Rev 1.29 11 Aug 1993 11:19:44 GLENN
+Replaced the sleep call with a maintained delay variable.
+
+ Rev 1.28 05 Aug 1993 16:45:16 MARINA
+enable c++
+
+ Rev 1.27 15 Jul 1993 15:05:30 KEVINS
+Sleep a little bit before spinning really takes off.
+
+ Rev 1.26 18 May 1993 15:07:12 GLENN
+Removed bogus stuff from ribbon disable to eliminate warning.
+
+ Rev 1.25 09 Apr 1993 14:07:36 GLENN
+Added RIB_ItemEnable, RIB_Init, RIB_Deinit, RIB_IsItemEnabled routines.
+
+ Rev 1.24 03 Mar 1993 16:50:06 ROBG
+Added function RIB_ItemGetState so MSOFT_UI can set the some
+menu statuses to particular ribbon statuses.
+
+ Rev 1.23 02 Mar 1993 15:25:14 ROBG
+Added RIB_UpPosition to support WIN32 applications.
+
+ Rev 1.22 18 Nov 1992 11:42:02 GLENN
+Added new feature to emulate Microsoft's 3D highlighting.
+
+ Rev 1.21 10 Nov 1992 07:50:36 GLENN
+Now clearing the current item in the right place. (found under NT)
+
+ Rev 1.20 01 Nov 1992 16:06:38 DAVEV
+Unicode changes
+
+ Rev 1.19 07 Oct 1992 15:10:10 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.18 04 Oct 1992 19:40:18 DAVEV
+Unicode Awk pass
+
+ Rev 1.17 10 Jun 1992 16:21:08 GLENN
+Took out the extra line at the top of the ribbon.
+
+ Rev 1.16 29 May 1992 16:00:32 JOHNWT
+PCH updates
+
+ Rev 1.15 20 Apr 1992 14:00:04 GLENN
+Fixed status line help problem. Renamed global variables to module wides.
+
+ Rev 1.14 07 Apr 1992 10:39:38 GLENN
+Using global ribbon font instead of font passed in rib item structure due to sys change problems.
+
+ Rev 1.13 02 Apr 1992 16:18:54 GLENN
+Put the new changes into the spinner.
+
+ Rev 1.12 02 Apr 1992 15:29:02 GLENN
+Added bitmap and text rectangles for buttons - drawing is faster. Supports NT better now.
+
+ Rev 1.11 23 Feb 1992 13:49:32 GLENN
+Added IsWindow calls to keyboard functions.
+
+ Rev 1.10 11 Feb 1992 17:27:46 GLENN
+Fixed point stuff.
+
+ Rev 1.9 04 Feb 1992 16:37:36 STEVEN
+now use macro to convert MP2 to POINT
+
+ Rev 1.8 04 Feb 1992 16:21:20 GLENN
+Working on auto calc size for ribbon.
+
+ Rev 1.7 29 Jan 1992 18:05:06 DAVEV
+
+
+ * No changes
+
+ Rev 1.6 19 Dec 1991 15:25:34 GLENN
+Added windows.h
+
+ Rev 1.5 12 Dec 1991 17:10:30 DAVEV
+16/32 bit port -2nd pass
+
+ Rev 1.4 10 Dec 1991 14:37:44 GLENN
+Added RIB_AutoCalcSize() stuff
+
+ Rev 1.3 05 Dec 1991 17:51:46 GLENN
+Changed active window handle to macro
+
+ Rev 1.2 02 Dec 1991 17:50:44 DAVEV
+16/32 bit Windows port changes
+
+ Rev 1.1 27 Nov 1991 12:07:52 GLENN
+Added code to prevent messages if the button is already down and it is
+a positional button.
+
+ Rev 1.0 20 Nov 1991 19:28:36 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+// PRIVATE DEFINITIONS
+
+#define WINCLASS_RIBBON TEXT("GSH_Ribbon") // Class name for the ribbon windows.
+
+// POSSIBLY HAVE THE ABILITY TO ENABLE AND DISABLE RIBBON ITEMS BASED ON
+// AN ITEM ID AS WELL AS AN ITEM INDEX INTO THE RIBBON ITEM LIST.
+
+static BOOL mwfButtonDown = FALSE;
+static WORD mwwButtonType = 0;
+static BOOL mwfWasInRect = FALSE;
+static CHAR mwszRibbonText[RIB_ITEM_TEXT_SIZE];
+
+static HBRUSH mwhColorFace;
+static HPEN mwhColorBorder;
+static HPEN mwhColorHilite;
+static HPEN mwhColorShadow;
+
+static HANDLE mwhAppInst = 0;
+static HANDLE mwhResInst = 0;
+static BOOL mwfInitialized = FALSE;
+static INT mwnCurrentDelay = 0;
+static INT mwnRepeatDelay = 400;
+
+// PRIVATE MACROS
+
+#define RIB_GetInfoPtr( x ) (HRIBBON)GetWindowLong( x, 0 )
+#define RIB_SetInfoPtr( x, y ) SetWindowLong( x, 0, (DWORD)y )
+
+// PRIVATE FUNCTION PROTOTYPES
+
+VOID RIB_MouseMove ( HWND, MP2 );
+VOID RIB_Paint ( HWND );
+VOID RIB_Timer ( HWND );
+VOID RIB_Up3D( HDC, LPRECT, BOOL );
+VOID RIB_Down3D( HDC, LPRECT, BOOL );
+
+// FUNCTIONS NOT YET IMPLEMENTED
+
+BOOL RIB_GetInfo ( HRIBBON, PDS_RIBINFO );
+HWND RIB_GetOwner ( HRIBBON );
+HRIBBON RIB_Load ( WORD );
+BOOL RIB_SetState ( HRIBBON, LPSTR );
+BOOL RIB_ItemDelete ( HRIBBON, UINT );
+BOOL RIB_ItemGetState ( HRIBBON, UINT, PDS_RIBITEMINFO );
+
+
+// FUNCTIONS
+
+/******************************************************************************
+
+ Name: WM_RibbonWndProc()
+
+ Description: This function is called internally by Windows.
+ Windows calls this function when messages related to
+ Ribbon windows must be processed.
+
+ Returns: NULL or a default message handler's return code.
+
+******************************************************************************/
+
+WINRESULT APIENTRY WM_RibbonWndProc (
+
+ register HWND hWnd, // I - window handle of the list box
+ MSGID msg, // I - message
+ MP1 mp1, // I - another message parameter
+ MP2 mp2 ) // I - yet another message parameter
+
+{
+ switch ( msg ) {
+
+ case WM_CREATE: // Do some creation initialization stuff.
+
+ RIB_SetInfoPtr ( hWnd, NULL );
+ break;
+
+ case WM_SETCURSOR: // Set the right cursor for this window position.
+
+ break;
+
+ case WM_LBUTTONDOWN:
+
+ // If we have a help context mode handler callback,
+ // do the callback. I will add this later.
+
+//# ifdef MAYN_WIN
+ {
+ if ( HM_ContextLbuttonDown( hWnd, mp1, mp2 ) == TRUE ) {
+ return 0;
+ }
+ }
+//# endif
+
+ // Fall through if Help is not called
+
+ case WM_LBUTTONDBLCLK:
+
+ RIB_KeyDown ( hWnd, RIB_MOUSE, mp1, mp2 );
+ return 0;
+
+
+ case WM_LBUTTONUP:
+
+ RIB_KeyUp ( hWnd, RIB_MOUSE, mp1, mp2 );
+ return 0;
+
+ case WM_MOUSEMOVE:
+
+ RIB_MouseMove ( hWnd, mp2 );
+ return 0;
+
+ case WM_PAINT: // Paint the ribbon or ribbon item.
+
+ RIB_Paint( hWnd );
+ return 0;
+
+ case WM_TIMER:
+
+ RIB_Timer ( hWnd );
+ return 0;
+
+ default:
+ break;
+ }
+
+ return DefWindowProc ( hWnd, msg, mp1, mp2 );
+
+
+} /* end WM_RibbonWndProc() */
+
+
+/******************************************************************************
+
+ Name: RIB_Init ()
+
+ Description: This function initializes the ribbon/toolbar manager.
+
+ Returns: SUCCESS, if successful. Otherwise, FAILURE.
+
+******************************************************************************/
+
+BOOL RIB_Init (
+
+HANDLE hAppInst,
+HANDLE hResInst )
+
+{
+ if ( ! mwfInitialized ) {
+
+ WNDCLASS wc;
+
+ mwhAppInst = hAppInst;
+ mwhResInst = hResInst;
+
+ wc.style = 0;
+ wc.lpfnWndProc = WM_RibbonWndProc;
+ wc.hInstance = mwhAppInst;
+ wc.hIcon = (HICON)NULL;
+ wc.hCursor = LoadCursor ( (HANDLE)NULL, IDC_ARROW );
+ wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
+ wc.lpszMenuName = NULL;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = sizeof(PDS_RIBINFO) + sizeof(WORD);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = WINCLASS_RIBBON;
+
+ if ( ! RegisterClass( &wc ) ) {
+ return FAILURE;
+ }
+
+ // Create any needed brushes and pens.
+
+ mwhColorFace = CreateSolidBrush ( GetSysColor ( COLOR_BTNFACE ) );
+ mwhColorBorder = GetStockObject ( BLACK_PEN );
+ mwhColorHilite = GetStockObject ( WHITE_PEN );
+ mwhColorShadow = CreatePen ( PS_SOLID, 1, GetSysColor ( COLOR_BTNSHADOW ) );
+
+ mwfInitialized = TRUE;
+ }
+
+ return SUCCESS;
+
+} /* end RIB_Init() */
+
+
+/******************************************************************************
+
+ Name: RIB_Deinit ()
+
+ Description: This function initializes the ribbon/toolbar manager.
+
+ Returns: FALSE, if successful. Otherwise, TRUE.
+
+******************************************************************************/
+
+VOID RIB_Deinit ( VOID )
+
+{
+ if ( mwfInitialized ) {
+
+ // Destroy objects - pens, brushes.
+
+ if ( mwhColorFace ) DeleteObject ( mwhColorFace );
+ if ( mwhColorShadow ) DeleteObject ( mwhColorShadow );
+
+ UnregisterClass ( WINCLASS_RIBBON, mwhAppInst );
+
+ mwfInitialized = FALSE;
+ }
+
+} /* end RIB_Deinit() */
+
+
+/******************************************************************************
+
+ Name: RIB_SystemChange ()
+
+ Description: This function initializes ribbon/toolbar colors.
+
+ Returns: FALSE, if successful. Otherwise, TRUE.
+
+******************************************************************************/
+
+VOID RIB_SystemChange ( VOID )
+
+{
+ if ( mwfInitialized ) {
+
+ // Destroy objects - pens, brushes.
+
+ if ( mwhColorFace ) DeleteObject ( mwhColorFace );
+ if ( mwhColorShadow ) DeleteObject ( mwhColorShadow );
+
+ // Create any needed brushes and pens.
+
+ mwhColorFace = CreateSolidBrush ( GetSysColor ( COLOR_BTNFACE ) );
+ mwhColorBorder = GetStockObject ( BLACK_PEN );
+ mwhColorHilite = GetStockObject ( WHITE_PEN );
+ mwhColorShadow = CreatePen ( PS_SOLID, 1, GetSysColor ( COLOR_BTNSHADOW ) );
+ }
+
+} /* end RIB_SystemChange() */
+
+
+/******************************************************************************
+
+ Name: RIB_IsItemEnabled ()
+
+ Description: This function gets the state of a button by using an
+ item id.
+
+ Returns: TRUE, if the item is enable. Otherwise FALSE.
+
+
+*****************************************************************************/
+
+BOOL RIB_IsItemEnabled (
+
+HRIBBON hRibbon, // I - ribbon handle
+WORD wItemID ) // I - item ID
+
+{
+ PDS_RIBITEMINFO pdsItem;
+ INT i;
+ BOOL fEnabled = FALSE;
+
+ // Ribbon must exist.
+
+ if ( ! hRibbon ) {
+ return fEnabled;
+ }
+
+ // Find the Menu Id in the list of buttons.
+
+ pdsItem = hRibbon->pdsItemList;
+
+ for ( i = 0; i < hRibbon->nNumItems; i++ ) {
+
+ if ( pdsItem[i].wMessage == wItemID ) {
+ fEnabled = (pdsItem[i].wState & RIB_ITEM_ENABLED) ? TRUE : FALSE;
+ break;
+ }
+ }
+
+ return fEnabled;
+
+}
+
+
+/******************************************************************************
+
+ Name: RIB_UpPosition()
+
+ Description: This function resets a depressed button to the up position
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID RIB_UpPosition (
+
+HRIBBON hRibbon )
+
+{
+ PDS_RIBITEMINFO pdsItems;
+
+ if ( ! hRibbon ) {
+ return;
+ }
+
+ pdsItems = hRibbon->pdsItemList;
+
+ if ( ! pdsItems ) {
+ return;
+ }
+
+ // Change the item to the "up" state if depressed by a mouse.
+
+ if ( ( hRibbon->nCurItem != RIB_ITEMUNKNOWN ) && ( mwfButtonDown == TRUE ) ) {
+
+ pdsItems[hRibbon->nCurItem].wState |= RIB_ITEM_UP;
+
+ hRibbon->nCurItem = RIB_ITEMUNKNOWN;
+
+ mwfWasInRect = FALSE;
+ mwfButtonDown = FALSE;
+ mwwButtonType = 0;
+
+ ReleaseCapture ();
+
+ RIB_Draw( hRibbon );
+
+ UpdateWindow( hRibbon->hWnd );
+
+ }
+
+} /* end RIB_UpPosition */
+
+
+/******************************************************************************
+
+ Name: RIB_Activate()
+
+ Description: This function sets the active ribbon for a ribbon window.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+BOOL RIB_Activate (
+
+HRIBBON hRibbon ) // I - handle of the ribbon to activate
+
+{
+ if ( hRibbon ) {
+
+ WM_SetInfoPtr ( hRibbon->hWnd, hRibbon );
+
+ // Restore the ribbon state for this window.
+
+ // WM_SetState ( );
+
+ // Draw the ribbon.
+
+ }
+
+ return FALSE;
+
+} /* end RIB_Activate() */
+
+
+/******************************************************************************
+
+ Name: RIB_AutoCalcSize()
+
+ Description: This function automatically calculates the size of each
+ button in a ribbon. The buttons will automatically be
+ set next to each other and the size will be determined
+ based on the character font size, the bitmap size, and
+ the button border width.
+
+ Returns: The height of the ribbon.
+
+******************************************************************************/
+
+BOOL RIB_AutoCalcSize (
+
+HRIBBON hRibbon ) // I - handle of the ribbon to calculate the size for
+
+{
+ INT i;
+ INT nItemWidth = 0;
+ INT nItemHeight = 0;
+ INT nTempWidth = 0;
+ INT nTempHeight = 0;
+ INT nMaxFontWidth = 0;
+ INT nAvgFontWidth = 0;
+ INT nFontHeight = 0;
+ INT nBitmapWidth = 0;
+ INT nBitmapHeight = 0;
+ INT nStringLen = 0;
+ INT nTempStringWidth = 0;
+ INT nMaxStringWidth = 0;
+ CHAR szString[RIB_ITEM_TEXT_SIZE];
+
+ INT nTemp = 0;
+ UINT j;
+
+ PDS_RIBITEMINFO pdsItems;
+
+ msassert ( hRibbon != (HRIBBON)NULL );
+
+ pdsItems = hRibbon->pdsItemList =
+ (PDS_RIBITEMINFO)( (BYTE FAR *)hRibbon + sizeof (DS_RIBINFO) );
+
+ // Calculate the max bitmap width and height of all buttons in the ribbon.
+
+ for ( i = 0; i < hRibbon->nNumItems; i++ ) {
+
+ if ( ! RSM_GetBitmapSize ( pdsItems[i].wEnabledID, &nTempWidth, &nTempHeight ) ) {
+
+ nBitmapWidth = ( nTempWidth > nBitmapWidth ) ? nTempWidth : nBitmapWidth;
+ nBitmapHeight = ( nTempHeight > nBitmapHeight ) ? nTempHeight : nBitmapHeight;
+ }
+ }
+
+ // Calculate the max string width and height of all buttons in the ribbon.
+
+ RSM_GetFontSize ( ghFontRibbon, &nMaxFontWidth, &nAvgFontWidth, &nFontHeight );
+
+ for ( i = 0; i < hRibbon->nNumItems; i++ ) {
+
+ nStringLen = RSM_StringCopy ( pdsItems[i].wStringID, szString, RIB_ITEM_TEXT_SIZE );
+ nTempStringWidth = nStringLen * nAvgFontWidth;
+ nMaxStringWidth = ( nTempStringWidth > nMaxStringWidth ) ? nTempStringWidth : nMaxStringWidth;
+
+ // Remove the underscore character ('&') from the string if any.
+
+ for ( j = 0; j < strlen ( szString ); j++ ) {
+
+ if ( szString[j] == TEXT('&') ) {
+
+ do {
+ szString[j] = szString[j+1];
+ } while ( szString[++j] != TEXT('\0') );
+
+ break;
+ }
+ }
+
+ nTemp = RSM_GetFontStringWidth ( ghFontRibbon, szString, nStringLen );
+ }
+
+ // Calculate button width.
+
+ nItemWidth = ( 2 * RIB_ITEM_BORDER_WIDTH ) + ( ( nBitmapWidth > nMaxStringWidth ) ? nBitmapWidth : nMaxStringWidth );
+
+ // Calculate button height.
+
+ nItemHeight = ( 2 * RIB_ITEM_BORDER_WIDTH ) + nBitmapHeight + nFontHeight;
+
+ // Now set up the width and height of each button item.
+
+ for ( i = 0; i < hRibbon->nNumItems; i++ ) {
+
+ // Stuff the font in the item.
+
+ pdsItems[i].hFont = ghFontRibbon;
+
+ // Calculate the Button rectangle.
+
+ pdsItems[i].Rect.left = ( i * nItemWidth );
+ pdsItems[i].Rect.right = ( i * nItemWidth ) + ( nItemWidth );
+ pdsItems[i].Rect.top = 0;
+ pdsItems[i].Rect.bottom = nItemHeight - 1;
+
+ pdsItems[i].rcBM = pdsItems[i].rcText = pdsItems[i].Rect;
+
+ // Calculate the Bitmap rectangle.
+
+ pdsItems[i].rcBM.left += RIB_ITEM_BORDER_WIDTH;
+ pdsItems[i].rcBM.right -= RIB_ITEM_BORDER_WIDTH;
+
+ // Calculate the Text rectangle.
+
+ pdsItems[i].rcText.left += RIB_ITEM_BORDER_WIDTH;
+ pdsItems[i].rcText.right -= RIB_ITEM_BORDER_WIDTH;
+
+ // Don't give any room to things that aren't displayed.
+
+ if ( pdsItems[i].wEnabledID == ID_NOTDEFINED ) {
+
+ pdsItems[i].rcText.top += RIB_ITEM_BORDER_WIDTH;
+ pdsItems[i].rcText.bottom -= RIB_ITEM_BORDER_WIDTH;
+ }
+ else if ( pdsItems[i].wStringID == ID_NOTDEFINED ) {
+
+ pdsItems[i].rcBM.top += RIB_ITEM_BORDER_WIDTH;
+ pdsItems[i].rcBM.bottom -= RIB_ITEM_BORDER_WIDTH;
+ }
+ else {
+
+ pdsItems[i].rcBM.top += RIB_ITEM_BORDER_WIDTH;
+ pdsItems[i].rcBM.bottom -= 14;
+ pdsItems[i].rcText.top = pdsItems[i].rcBM.bottom - 2;
+ pdsItems[i].rcText.bottom -= 2;
+ }
+ }
+
+ return nItemHeight;
+
+} /* end RIB_AutoCalcSize() */
+
+
+/******************************************************************************
+
+ Name: RIB_Create()
+
+ Description: This function creates a ribbon for the specified ribbon
+ window.
+
+ Returns: A handle to the newly created ribbon.
+
+ Note: There can be multiple ribbons per ribbon window, but only
+ one active ribbon at a time. The width and height of the
+ ribbon items is used as the default if they are not
+ specified on an item by item basis.
+
+******************************************************************************/
+
+HRIBBON RIB_Create (
+
+HWND hWnd, // I - handle of a ribbon window
+WORD wType, // I - the type of ribbon to create
+INT nItemWidth, // I - the default width of each item
+INT nItemHeight, // I - the default height of each item
+INT nMaxItems ) // I - the maximum number of items in this ribbon
+
+{
+ INT i;
+ HRIBBON hRibbon;
+ PDS_RIBITEMINFO pdsItems;
+
+ // Allocate the memory for the creation of a new ribbon.
+
+ i = sizeof ( DS_RIBINFO ) + ( nMaxItems * sizeof ( DS_RIBITEMINFO ) );
+
+ hRibbon = (HRIBBON)calloc ( 1, i );
+
+ // Stuff the ribbon structure.
+
+ hRibbon->hWnd = hWnd;
+ hRibbon->wType = wType;
+ hRibbon->nItemWidth = nItemWidth;
+ hRibbon->nItemHeight = nItemHeight;
+ hRibbon->nMaxItems = nMaxItems;
+ hRibbon->nNumItems = 0;
+ hRibbon->nCurItem = RIB_ITEMUNKNOWN;
+
+ pdsItems = hRibbon->pdsItemList =
+ (PDS_RIBITEMINFO)( (BYTE FAR *)hRibbon + sizeof (DS_RIBINFO) );
+
+ // Initialize each of the item rectangles.
+
+ for ( i = 0; i < nMaxItems; i++ ) {
+
+ pdsItems[i].Rect.left = ( i * nItemWidth );
+ pdsItems[i].Rect.right = ( i * nItemWidth ) + ( nItemWidth );
+ pdsItems[i].Rect.top = 0;
+ pdsItems[i].Rect.bottom = nItemHeight - 1;
+ }
+
+ return hRibbon;
+
+} /* end RIB_Create() */
+
+
+/******************************************************************************
+
+ Name: RIB_Deactivate()
+
+ Description: This function deactivates the current ribbon in this
+ window.
+
+ Returns: FALSE, if successful. Otherwise, TRUE.
+
+******************************************************************************/
+
+BOOL RIB_Deactivate (
+
+HRIBBON hRibbon ) // I - the handle of the ribbon to be deactivated
+
+{
+ PDS_WMINFO pdsWinInfo;
+
+ // Save the current ribbon item status settings into ribbon's current
+ // owner ribbon status area. HUH? Just do it!
+
+ if ( hRibbon && WM_GetActiveDoc () ) {
+
+ pdsWinInfo = (PDS_WMINFO)NULL;
+ }
+
+ return FALSE;
+
+} /* end RIB_Deactivate() */
+
+
+/******************************************************************************
+
+ Name: RIB_Destroy()
+
+ Description: This function destroys a ribbon and frees all of it's
+ associated memory.
+
+ Returns: FALSE, if successful. Otherwise, TRUE.
+
+******************************************************************************/
+
+BOOL RIB_Destroy (
+
+HRIBBON hRibbon ) // I - the handle of the ribbon to be destroyed
+
+{
+ // Free the memory associated with the ribbon.
+
+ if ( hRibbon ) {
+ free( hRibbon );
+ return FALSE;
+ }
+
+ return TRUE;
+
+} /* end RIB_Destroy */
+
+
+/******************************************************************************
+
+ Name: RIB_Disable()
+
+ Description: This function disables each item in a ribbon and saves the
+ current state in the area specified by the caller.
+
+ Returns: FALSE, if successful. Otherwise, TRUE.
+
+******************************************************************************/
+
+BOOL RIB_Disable (
+
+HRIBBON hRibbon, // I - the handle of the ribbon to be disabled
+LPSTR lpCurState ) // I - the pointer to the callers area where the
+ // current state will be stored
+
+{
+ INT i;
+
+ DBG_UNREFERENCED_PARAMETER ( lpCurState );
+
+ if ( ! hRibbon ) {
+
+ return TRUE;
+ }
+
+ // Save the current state of each item in the callers area.
+
+ for ( i = 0; i < hRibbon->nNumItems; i++ ) {
+
+ }
+
+ // Disable all items in the ribbon.
+
+ for ( i = 0; i < hRibbon->nNumItems; i++ ) {
+
+ }
+
+ // Draw the disabled ribbon.
+
+ RIB_Draw ( hRibbon );
+
+ return FALSE;
+
+} /* end RIB_Disable() */
+
+
+/******************************************************************************
+
+ Name: RIB_Enable()
+
+ Description: This function enables each item in a ribbon to the state
+ that is specified in the callers area.
+
+ Returns: FALSE, if successful. Otherwise, TRUE.
+
+******************************************************************************/
+
+BOOL RIB_Enable (
+
+HRIBBON hRibbon, // I - the handle of the ribbon to be enabled
+LPSTR lpOldState ) // I - the pointer to the callers area where the
+ // old state will be restored from
+
+{
+ INT i;
+ DBG_UNREFERENCED_PARAMETER ( lpOldState );
+
+ if ( ! hRibbon ) {
+
+ return TRUE;
+ }
+
+ // Set the current state of each item to that in the callers area.
+
+ for ( i = 0; i < hRibbon->nNumItems; i++ ) {
+
+ }
+
+ // Draw the enabled ribbon.
+
+ RIB_Draw ( hRibbon );
+
+ return FALSE;
+
+} /* end RIB_Enable() */
+
+
+/******************************************************************************
+
+ Name: RIB_GetState()
+
+ Description: This function gets the current state of each item in a
+ ribbon and stores it in the location specified by the
+ caller.
+
+ Returns: FALSE, if successful. Otherwise, TRUE.
+
+******************************************************************************/
+
+BOOL RIB_GetState (
+
+HRIBBON hRibbon, // I - the handle of the ribbon to be disabled
+LPSTR lpCurState ) // I - the pointer to the callers area where the
+ // current state will be stored
+
+{
+ DBG_UNREFERENCED_PARAMETER ( lpCurState );
+
+ if ( ! hRibbon ) {
+
+ return TRUE;
+ }
+
+/////////////////////////////////////////////////////////////////////
+ return FALSE;
+
+} /* end RIB_GetState() */
+
+
+/******************************************************************************
+
+ Name: RIB_KeyDown()
+
+ Description: This function processes a key down message if a mouse
+ key was pressed or a keyboard key was pressed.
+
+ Returns: FALSE, if the key was used. Otherwise, TRUE.
+
+******************************************************************************/
+
+BOOL RIB_KeyDown (
+
+HWND hWnd, // I - handle of the ribbon window
+WORD wType, // I - type of key down - MOUSE or KEYBOARD
+MP1 mp1, // I - key information parameter
+MP2 mp2 ) // I - mouse information parameter
+
+{
+ HRIBBON hRibbon;
+ INT i;
+ PDS_RIBITEMINFO pdsItems;
+ BOOL fRepeat = FALSE;
+ BOOL fControlDown;
+ POINT CurPoint ;
+
+ if ( IsWindow ( hWnd ) && ! mwfButtonDown ) {
+
+ hRibbon = (HRIBBON)RIB_GetInfoPtr ( hWnd );
+
+ if ( ! hRibbon ) {
+
+ return ! RIB_KEYUSED;
+ }
+
+ // The control key must be down before we allow any key board
+ // messages to be passed on through.
+
+ fControlDown = ( GetKeyState ( VK_CONTROL ) < 0 ) ? TRUE : FALSE;
+
+ mwwButtonType = wType;
+
+ pdsItems = hRibbon->pdsItemList;
+
+ for ( i = 0; i < hRibbon->nNumItems; i++ ) {
+
+ // If the button down was a MOUSE type and it was in this button,
+ // OR, the button down was a CTRL accelerator key,
+ // AND, the button item was ENABLED,
+ // AND, the button was not POSITIONAL and already down, WHEW...
+ // Then, let's change the button state and see if we should send
+ // a message.
+
+ WM_FromMP2toPOINT( CurPoint, mp2 ) ;
+
+ if ( ( ( wType == RIB_MOUSE && PtInRect ( &pdsItems[i].Rect, CurPoint ) ) ||
+ ( wType == RIB_KEYBOARD && fControlDown && pdsItems[i].wAccelKey == (WORD)mp1 ) ) &&
+ ( pdsItems[i].wState & RIB_ITEM_ENABLED ) &&
+ ! ( ( pdsItems[i].wState & RIB_ITEM_POSITIONAL ) &&
+ ! ( pdsItems[i].wState & RIB_ITEM_UP ) ) ) {
+
+ // Indicate that the button is down, capture the mouse,
+ // etc...
+
+ mwfButtonDown = TRUE;
+ mwfWasInRect = TRUE;
+ SetCapture ( hWnd );
+
+ // Get the current state of the item and change it.
+
+ if ( pdsItems[i].wState & RIB_ITEM_UP ) {
+ pdsItems[i].wState &= ~RIB_ITEM_UP;
+ }
+ else {
+ pdsItems[i].wState |= RIB_ITEM_UP;
+ }
+
+ hRibbon->nCurItem = i;
+
+ InvalidateRect ( hWnd, &pdsItems[i].Rect, FALSE );
+ UpdateWindow ( hWnd );
+
+ // If the creator of the ribbon has requested the DOWN
+ // message be sent, post the message that tells the owner
+ // that the item is down.
+
+ if ( ( hRibbon->wType & RIB_DOWNMESSAGE ) &&
+ ( pdsItems[i].wMessage != ID_NOTDEFINED ) ) {
+
+ POST_WM_COMMAND_MSG (hRibbon->hWndCurOwner,
+ pdsItems[i].wMessage,
+ hRibbon->hWnd, RIB_ITEM_DOWN );
+
+ fRepeat = ( hRibbon->wType & RIB_DOWNREPEAT ) ? TRUE : FALSE;
+ mwnCurrentDelay = 0;
+ }
+
+ // If the down message should be repeated while the item
+ // is down, set a timer to do so.
+
+ if ( fRepeat ) {
+
+ WM_MultiTask ();
+
+ SetTimer ( hRibbon->hWnd, RIB_TIMERID, RIB_TIMERDELAY, NULL );
+ }
+
+ return RIB_KEYUSED;
+ }
+ }
+ }
+
+ return ! RIB_KEYUSED;
+
+} /* end RIB_KeyDown() */
+
+
+/******************************************************************************
+
+ Name: RIB_KeyUp()
+
+ Description: This function processes a key up message if a mouse
+ key was released or a keyboard key was released.
+
+ Returns: FALSE, if the key was used. Otherwise, TRUE.
+
+******************************************************************************/
+
+BOOL RIB_KeyUp (
+
+HWND hWnd, // I - handle of the ribbon window
+WORD wType, // I - type of key down - MOUSE or KEYBOARD
+MP1 mp1, // I - key information parameter
+MP2 mp2 ) // I - mouse information parameter
+
+{
+ HRIBBON hRibbon;
+ PDS_RIBITEMINFO pdsItems;
+ POINT CurPoint ;
+
+ if ( IsWindow ( hWnd ) && mwfButtonDown && ( wType == mwwButtonType ) ) {
+
+ hRibbon = (HRIBBON)RIB_GetInfoPtr ( hWnd );
+
+ if ( ! hRibbon ) {
+
+ return ! RIB_KEYUSED;
+ }
+
+ pdsItems = hRibbon->pdsItemList;
+
+ if ( ( mwwButtonType == RIB_MOUSE ) ||
+ ( mwwButtonType == RIB_KEYBOARD && pdsItems[hRibbon->nCurItem].wAccelKey == (WORD)mp1 ) ) {
+
+ WM_FromMP2toPOINT( CurPoint, mp2 ) ;
+
+ if ( ! ( mwwButtonType == RIB_MOUSE && ! PtInRect ( &pdsItems[hRibbon->nCurItem].Rect, CurPoint ) ) ) {
+
+ // TRICKY BUSINESS, if the button is positional, don't
+ // change its state. If it is momentary, change its state.
+
+ if ( ! ( pdsItems[hRibbon->nCurItem].wState & RIB_ITEM_POSITIONAL ) ) {
+
+ // Get the current state of the item and change it.
+
+ if ( pdsItems[hRibbon->nCurItem].wState & RIB_ITEM_UP ) {
+ pdsItems[hRibbon->nCurItem].wState &= ~RIB_ITEM_UP;
+ }
+ else {
+ pdsItems[hRibbon->nCurItem].wState |= RIB_ITEM_UP;
+ }
+
+ InvalidateRect ( hWnd, &pdsItems[hRibbon->nCurItem].Rect, FALSE );
+ UpdateWindow ( hWnd );
+ }
+
+ // Post the message associated with the item.
+
+ if ( pdsItems[hRibbon->nCurItem].wMessage != ID_NOTDEFINED ) {
+
+ POST_WM_COMMAND_MSG ( hRibbon->hWndCurOwner,
+ pdsItems[hRibbon->nCurItem].wMessage,
+ hRibbon->hWnd, RIB_ITEM_UP );
+ }
+
+ // STM_SetIdleText ( IDS_READY );
+ }
+
+ // If the creator of the ribbon had requested REPEATED DOWN
+ // messages be sent, kill the timer associated with it.
+
+ if ( ( hRibbon->wType & ( RIB_DOWNMESSAGE | RIB_DOWNREPEAT ) ) &&
+ pdsItems[hRibbon->nCurItem].wMessage != ID_NOTDEFINED ) {
+
+ KillTimer ( hRibbon->hWnd, RIB_TIMERID );
+ }
+
+ hRibbon->nCurItem = RIB_ITEMUNKNOWN;
+
+ // Indicate the button is released and release the captured mouse.
+
+ mwfButtonDown = FALSE;
+ ReleaseCapture ();
+
+ return RIB_KEYUSED;
+ }
+
+ mwfWasInRect = FALSE;
+ }
+
+ return ! RIB_KEYUSED;
+
+} /* end RIB_KeyUp() */
+
+
+/******************************************************************************
+
+ Name: RIB_MouseMove()
+
+ Description: This function processes a mouse move message if a mouse
+ was moved in a ribbon window. If a ribbon item or button
+ was pressed and the mouse moves outside of the item's
+ region, the item changes to it's opposite position.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID RIB_MouseMove (
+
+HWND hWnd, // I - the handle to a ribbon window
+MP2 mp2 ) // I - mouse information parameter
+
+{
+ BOOL fIsInRect;
+ HRIBBON hRibbon;
+ PDS_RIBITEMINFO pdsItems;
+ POINT CurPoint ;
+
+ // If the mouse cursor is in the selected item, the item remains the
+ // same. Otherwise change the state from UP to DOWN or DOWN to UP.
+
+ if ( mwfButtonDown && ( mwwButtonType == RIB_MOUSE ) ) {
+
+ // Get the information associated with the ribbon.
+
+ hRibbon = (PDS_RIBINFO)RIB_GetInfoPtr ( hWnd );
+ pdsItems = hRibbon->pdsItemList;
+
+ // Change the item state only when the cursor transitions in
+ // or out of the item.
+
+ WM_FromMP2toPOINT( CurPoint, mp2 ) ;
+ fIsInRect = PtInRect ( &pdsItems[hRibbon->nCurItem].Rect, CurPoint );
+
+ if ( ( fIsInRect || mwfWasInRect ) && ! ( fIsInRect && mwfWasInRect ) ) {
+
+ // Get the current state of the item and change it.
+
+ if ( pdsItems[hRibbon->nCurItem].wState & RIB_ITEM_UP ) {
+ pdsItems[hRibbon->nCurItem].wState &= ~RIB_ITEM_UP;
+ }
+ else {
+ pdsItems[hRibbon->nCurItem].wState |= RIB_ITEM_UP;
+ }
+
+ InvalidateRect ( hWnd, &pdsItems[hRibbon->nCurItem].Rect, FALSE );
+ }
+
+ mwfWasInRect = fIsInRect;
+ }
+
+} /* end RIB_MouseMove() */
+
+
+/******************************************************************************
+
+ Name: RIB_Paint()
+
+ Description: This function processes a paint message if a ribbon item
+ or items need repainting.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID RIB_Paint (
+
+HWND hWnd ) // I - handle to a ribbon window
+
+{
+ HDC hDC;
+ PAINTSTRUCT ps;
+ RECT Rect;
+ PDS_RIBITEMINFO pdsItem;
+ INT i;
+ PDS_RIBINFO hRibbon;
+
+ hDC = BeginPaint ( hWnd, &ps );
+
+ // Get the information associated with the ribbon.
+
+ hRibbon = (PDS_RIBINFO)RIB_GetInfoPtr ( hWnd );
+
+ if ( hRibbon ) {
+
+ if ( hRibbon->nCurItem == RIB_ITEMUNKNOWN ) {
+
+ GetClientRect ( hWnd, &Rect );
+
+ if ( Rect.right && Rect.bottom ) {
+
+ // Draw the top border.
+
+ SelectObject ( hDC, ghPenBlack );
+
+ // MoveToEx ( hDC, Rect.left, Rect.top, NULL );
+ // LineTo ( hDC, Rect.right, Rect.top );
+
+ // Draw the bottom border.
+
+ MoveToEx ( hDC, Rect.right, Rect.bottom - 1, NULL );
+ LineTo ( hDC, Rect.left - 1, Rect.bottom - 1 );
+
+ // Paint each button item.
+
+ for ( i = 0; i < hRibbon->nNumItems; i++ ) {
+
+ pdsItem = &hRibbon->pdsItemList[i];
+
+ RIB_ItemDraw ( hRibbon, hDC, pdsItem );
+ }
+ }
+ }
+ else {
+
+ RIB_ItemDraw ( hRibbon, hDC, &hRibbon->pdsItemList[hRibbon->nCurItem] );
+
+ if ( ! mwfButtonDown) {
+ hRibbon->nCurItem = RIB_ITEMUNKNOWN;
+ }
+ }
+ }
+
+ EndPaint ( hWnd, &ps );
+
+} /* end RIB_Paint() */
+
+
+/******************************************************************************
+
+ Name: RIB_Timer()
+
+ Description: This function processes a timer message if a ribbon item
+ is down and the repeat option has been specified.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID RIB_Timer (
+
+HWND hWnd ) // I - handle to a ribbon window
+
+{
+ HRIBBON hRibbon;
+
+ if ( mwfButtonDown && mwfWasInRect ) {
+
+ if ( mwnCurrentDelay < mwnRepeatDelay ) {
+ mwnCurrentDelay += RIB_TIMERDELAY;
+ }
+ else {
+ hRibbon = (HRIBBON)RIB_GetInfoPtr ( hWnd );
+
+ POST_WM_COMMAND_MSG ( hRibbon->hWndCurOwner,
+ hRibbon->pdsItemList[hRibbon->nCurItem].wMessage,
+ hRibbon->hWnd, RIB_ITEM_DOWN );
+ }
+ }
+
+} /* end RIB_Timer() */
+
+
+/******************************************************************************
+
+ Name: RIB_ItemDraw()
+
+ Description: This function draws a ribbon item in the up or down
+ position depending on which has been specified.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID RIB_ItemDraw (
+
+HRIBBON hRibbon, // I - handle to the ribbon
+HDC hDC, // I - handle to a display device context
+PDS_RIBITEMINFO pdsItem ) // I - pointer to a ribbon item
+
+{
+ RECT rcButton = pdsItem->Rect;
+ RECT rcText = pdsItem->rcText;
+ RECT rcBM = pdsItem->rcBM;
+ WORD wBitmapID;
+ INT nOldBkMode;
+ BOOL fChicklet = (BOOL)( pdsItem->wStyle | RIB_ITEM_STYLECHICKLET );
+
+
+ // Set up the FONT, PAINT BRUSH, and BACKGROUND COLOR.
+
+// if ( pdsItem->hFont ) {
+// SelectObject ( hDC, pdsItem->hFont );
+// }
+
+ if ( ghFontRibbon ) {
+ SelectObject ( hDC, ghFontRibbon );
+ }
+
+ SelectObject ( hDC, ghBrushLtGray );
+ SetBkColor ( hDC, GetSysColor ( COLOR_BTNFACE ) );
+
+ // Determine ENABLED or DISABLED bitmap ID and TEXT color.
+
+ if( pdsItem->wState & RIB_ITEM_ENABLED ) {
+
+ wBitmapID = pdsItem->wEnabledID;
+ SetTextColor ( hDC, GetSysColor ( COLOR_BTNTEXT ) );
+ }
+ else {
+ wBitmapID = pdsItem->wDisabledID;
+ SetTextColor ( hDC, GetSysColor ( COLOR_BTNSHADOW ) );
+ }
+
+ if ( pdsItem->wState & RIB_ITEM_UP ) {
+
+ // Draw the button in the up position.
+
+ RIB_Up3D( hDC, &rcButton, fChicklet );
+ }
+ else {
+
+ // Draw the button in the down position.
+
+ RIB_Down3D( hDC, &rcButton, fChicklet );
+
+ if ( fChicklet ) {
+
+ rcBM.left += 1;
+ rcBM.right += 1;
+ rcBM.top += 1;
+ rcBM.bottom += 1;
+
+ rcText.left += 1;
+ rcText.right += 1;
+ rcText.top += 1;
+ rcText.bottom += 1;
+ }
+ else {
+
+ rcBM.left += 2;
+ rcBM.right += 2;
+ rcBM.top += 2;
+ rcBM.bottom += 2;
+
+ rcText.left += 2;
+ rcText.right += 2;
+ rcText.top += 2;
+ rcText.bottom += 2;
+ }
+ }
+
+ // Draw the bitmap CENTERED in the rectangle.
+
+ if ( wBitmapID != ID_NOTDEFINED ) {
+
+ RSM_BitmapDrawCentered ( wBitmapID,
+ rcBM.left,
+ rcBM.top,
+ rcBM.right - rcBM.left,
+ rcBM.bottom - rcBM.top,
+ hDC
+ );
+ }
+
+ // Get the string and draw it CENTERED with a TRANSPARENT BACKGROUND.
+
+ nOldBkMode = SetBkMode( hDC, TRANSPARENT );
+
+ if ( pdsItem->wStringID != ID_NOTDEFINED ) {
+
+ WORD wFormat = 0;
+
+ RSM_StringCopy ( pdsItem->wStringID, mwszRibbonText, RIB_ITEM_TEXT_SIZE );
+
+ // Do the horizontal allignment stuff.
+
+ if ( pdsItem->wTextStyle & RIB_TEXT_HCENTER ) {
+ wFormat |= DT_CENTER;
+ }
+ else if ( pdsItem->wTextStyle & RIB_TEXT_HLEFT ) {
+ wFormat |= DT_LEFT;
+ }
+ else if ( pdsItem->wTextStyle & RIB_TEXT_HRIGHT ) {
+ wFormat |= DT_RIGHT;
+ }
+ else {
+ wFormat |= DT_CENTER;
+ }
+
+ // Do the vertical allignment stuff.
+
+ if ( pdsItem->wTextStyle & RIB_TEXT_VCENTER ) {
+ wFormat |= DT_VCENTER;
+ }
+ else if ( pdsItem->wTextStyle & RIB_TEXT_VTOP ) {
+ wFormat |= DT_TOP;
+ }
+ else if ( pdsItem->wTextStyle & RIB_TEXT_VBOTTOM ) {
+ wFormat |= DT_BOTTOM;
+ }
+ else {
+ wFormat |= DT_VCENTER;
+ }
+
+ DrawText ( hDC, mwszRibbonText, -1, &rcText, wFormat );
+ }
+
+ // Show any status line text (based on a menu item).
+
+ if ( mwfButtonDown && ! ( pdsItem->wState & RIB_ITEM_NOMENUITEM ) ) {
+
+ if ( ! ( pdsItem->wState & RIB_ITEM_UP ) ) {
+
+ // The mouse button is down and so is the ribbon item.
+ // So, show any status line help (this is directly related to the menus).
+
+ SEND_WM_MENUSELECT_MSG ( hRibbon->hWndCurOwner, pdsItem->wMessage, 0, 0 );
+
+ }
+ else if ( mwfButtonDown ) {
+
+ // The mouse button is down, but the ribbon item isn't.
+ // So, send a message to clear out the menu select.
+
+ SEND_WM_MENUSELECT_MSG ( hRibbon->hWndCurOwner, 0, LOWORD(MM_MENUCLOSED), 0 );
+ }
+ }
+
+ SetBkMode( hDC, nOldBkMode );
+
+} /* end RIB_ItemDraw() */
+
+
+/******************************************************************************
+
+ Name: RIB_ItemInsert()
+
+ Description: This function inserts an item into a ribbon at the position
+ specified.
+
+ Returns: FALSE, if the item was inserted. Otherwise, TRUE.
+
+******************************************************************************/
+
+BOOL RIB_ItemInsert (
+
+HRIBBON hRibbon, // I - handle to a ribbon
+UINT unPosition, // I - position to insert after
+PDS_RIBITEMINFO pdsItem ) // I - pointer to a ribbon item
+
+{
+ UINT i;
+
+ // See if the ribbon is full.
+
+ if ( ! hRibbon || hRibbon->nNumItems == hRibbon->nMaxItems ) {
+ return TRUE;
+ }
+
+ // Extract the accelerator key from the item string and insert it into the
+ // accelerator key item.
+
+ if ( pdsItem->wStringID != ID_NOTDEFINED ) {
+
+ LPSTR pHotKey;
+ CHAR szMarker[3];
+
+ RSM_StringCopy ( pdsItem->wStringID, mwszRibbonText, RIB_ITEM_TEXT_SIZE );
+ RSM_StringCopy ( IDS_UNDERSCOREMARKER, szMarker, 3 );
+
+ // Search for the accelerator key MARKER in the string. If one is not
+ // found, use the first character in the string. Otherwise, use the
+ // character following the accelerator key MARKER.
+
+ pHotKey = strstr ( mwszRibbonText, szMarker );
+
+ if ( ! pHotKey || ! *(pHotKey+1) ) {
+ pHotKey = mwszRibbonText;
+ }
+ else {
+ pHotKey++;
+ }
+
+ // Get the key scan code and strip out the shift state for
+ // the character.
+
+ pdsItem->wAccelKey = (WORD)( LOBYTE ( VkKeyScan ( *pHotKey ) ) );
+ }
+
+
+ hRibbon->nNumItems ++;
+
+ // Determine the item number to insert.
+
+ if ( ( unPosition == RIB_APPEND ) || ( unPosition >= (UINT)hRibbon->nNumItems ) ) {
+
+ unPosition = hRibbon->nNumItems;
+ }
+ else {
+
+ // Move the existing items down one.
+
+ for ( i = hRibbon->nNumItems - 1; i > unPosition; i-- ) {
+ memcpy ( &hRibbon->pdsItemList[i], &hRibbon->pdsItemList[i-1], sizeof ( DS_RIBITEMINFO ) );
+ }
+ }
+
+ memcpy ( &hRibbon->pdsItemList[--unPosition], pdsItem, sizeof ( DS_RIBITEMINFO ) );
+
+ return FALSE;
+
+} /* end RIB_ItemInsert() */
+
+
+/******************************************************************************
+
+ Name: RIB_Up3D()
+
+ Description: This function draws a raised 3-D border of a ribbon
+ item/button to using the specified rectangle. Simulates
+ a button in the up position.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID RIB_Up3D (
+
+HDC hDC, // I - handle to a display device context
+LPRECT pRect, // I - pointer to a rectangle structure
+BOOL fChicklet ) // I - Chicklet type highlighting
+
+{
+ RECT rcTemp = *pRect;
+
+ rcTemp.top = pRect->top + 1;
+ rcTemp.bottom = pRect->bottom - 1;
+ rcTemp.left = pRect->left + 1;
+ rcTemp.right = pRect->right - 1;
+
+ FillRect ( hDC, &rcTemp, ghBrushLtGray );
+
+ // Draw the border.
+
+ SelectObject ( hDC, ghPenBlack );
+
+ MoveToEx ( hDC, pRect->left + 1, pRect->top, NULL );
+ LineTo ( hDC, pRect->right, pRect->top );
+
+ MoveToEx ( hDC, pRect->right, pRect->top + 1, NULL );
+ LineTo ( hDC, pRect->right, pRect->bottom );
+
+ MoveToEx ( hDC, pRect->right - 1, pRect->bottom, NULL );
+ LineTo ( hDC, pRect->left, pRect->bottom );
+
+ MoveToEx ( hDC, pRect->left, pRect->bottom - 1, NULL );
+ LineTo ( hDC, pRect->left, pRect->top );
+
+ // Draw the highlight.
+
+ SelectObject ( hDC, ghPenWhite );
+
+ MoveToEx ( hDC, pRect->left + 1, pRect->bottom - 2, NULL );
+ LineTo ( hDC, pRect->left + 1, pRect->top + 1 );
+ LineTo ( hDC, pRect->right - 1, pRect->top + 1 );
+
+ if ( ! fChicklet ) {
+
+ MoveToEx ( hDC, pRect->left + 2, pRect->bottom - 3, NULL );
+ LineTo ( hDC, pRect->left + 2, pRect->top + 2 );
+ LineTo ( hDC, pRect->right - 2, pRect->top + 2 );
+ }
+
+ // Draw the shadow.
+
+ SelectObject ( hDC, ghPenDkGray );
+
+ MoveToEx ( hDC, pRect->left + 1, pRect->bottom - 1, NULL );
+ LineTo ( hDC, pRect->right - 1, pRect->bottom - 1 );
+ LineTo ( hDC, pRect->right - 1, pRect->top + 0 );
+ MoveToEx ( hDC, pRect->left + 2, pRect->bottom - 2, NULL );
+ LineTo ( hDC, pRect->right - 2, pRect->bottom - 2 );
+ LineTo ( hDC, pRect->right - 2, pRect->top + 1 );
+
+} /* end RIB_Up3D() */
+
+
+/******************************************************************************
+
+ Name: RIB_Down3D()
+
+ Description: This function draws a depressed 3-D border of a ribbon
+ item/button to using the specified rectangle. Simulates
+ a button in the down position.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID RIB_Down3D (
+
+HDC hDC, // I - handle to a display device context
+LPRECT pRect, // I - pointer to a rectangle structure
+BOOL fChicklet ) // I - Chicklet type highlighting
+
+{
+ RECT rcTemp = *pRect;
+
+ rcTemp.top = pRect->top + 1;
+ rcTemp.bottom = pRect->bottom;
+ rcTemp.left = pRect->left + 1;
+ rcTemp.right = pRect->right;
+
+ FillRect ( hDC, &rcTemp, ghBrushLtGray );
+
+ // Draw the border.
+
+ SelectObject ( hDC, ghPenBlack );
+
+ MoveToEx ( hDC, pRect->left + 1, pRect->top, NULL );
+ LineTo ( hDC, pRect->right, pRect->top );
+
+ MoveToEx ( hDC, pRect->right, pRect->top + 1, NULL );
+ LineTo ( hDC, pRect->right, pRect->bottom );
+
+ MoveToEx ( hDC, pRect->right - 1, pRect->bottom, NULL );
+ LineTo ( hDC, pRect->left, pRect->bottom );
+
+ MoveToEx ( hDC, pRect->left, pRect->bottom - 1, NULL );
+ LineTo ( hDC, pRect->left, pRect->top );
+
+// MoveToEx ( hDC, pRect->left, pRect->top, NULL );
+// LineTo ( hDC, pRect->right, pRect->top );
+// LineTo ( hDC, pRect->right, pRect->bottom );
+// LineTo ( hDC, pRect->left, pRect->bottom );
+// LineTo ( hDC, pRect->left, pRect->top );
+
+ // Draw the shadow.
+
+ SelectObject ( hDC, ghPenDkGray );
+
+ MoveToEx ( hDC, pRect->left + 1, pRect->bottom, NULL );
+ LineTo ( hDC, pRect->left + 1, pRect->top + 1 );
+ LineTo ( hDC, pRect->right , pRect->top + 1 );
+
+
+ if ( ! fChicklet ) {
+
+ MoveToEx ( hDC, pRect->left + 2, pRect->bottom, NULL );
+ LineTo ( hDC, pRect->left + 2, pRect->top + 2 );
+ LineTo ( hDC, pRect->right , pRect->top + 2 );
+ }
+
+} /* end RIB_Down3D() */
+
+
+/******************************************************************************
+
+ Name: RIB_ItemReplace()
+
+ Description: This function replaces the contents of a ribbon item
+ structure.
+
+ Returns: FALSE, if successful. Otherwise, TRUE.
+
+******************************************************************************/
+
+BOOL RIB_ItemReplace (
+
+HRIBBON hRibbon, // I - handle to a ribbon
+WORD wMessageID, // I - the ribbon item message ID
+PDS_RIBITEMINFO pdsRibItem ) // I - the pointer to the ribbon item data structure
+
+{
+ PDS_RIBITEMINFO pdsItems;
+ INT i;
+
+ if ( ! hRibbon ) {
+ return TRUE;
+ }
+
+ pdsItems = hRibbon->pdsItemList;
+
+ // Loop through the items until we find the matching one.
+
+ for ( i = 0; i < hRibbon->nNumItems; i++ ) {
+
+ if ( pdsItems[i].wMessage == wMessageID ) {
+
+ memcpy ( &pdsItems[i], &pdsRibItem, sizeof ( DS_RIBITEMINFO ) );
+ InvalidateRect ( hRibbon->hWnd, &pdsItems[i].Rect, FALSE );
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+
+} /* end RIB_ItemReplace() */
+
+
+/******************************************************************************
+
+ Name: RIB_ItemSetState()
+
+ Description: This function sets the state of a ribbon item.
+
+ Returns: FALSE, if successful. Otherwise, TRUE.
+
+******************************************************************************/
+
+BOOL RIB_ItemSetState (
+
+HRIBBON hRibbon, // I - handle to a ribbon
+WORD wMessageID, // I - the ribbon item message ID
+WORD wState ) // I - the new ribbon item state.
+
+{
+ PDS_RIBITEMINFO pdsItems;
+ INT i;
+
+ if ( ! hRibbon ) {
+ return TRUE;
+ }
+
+ pdsItems = hRibbon->pdsItemList;
+
+ // Loop through the items until we find the matching one.
+
+ for ( i = 0; i < hRibbon->nNumItems; i++ ) {
+
+ if ( pdsItems[i].wMessage == wMessageID ) {
+
+ // Set the state and redraw only if it is different.
+
+ if ( pdsItems[i].wState != wState ) {
+
+ // If the item was DOWN and now it is UP,
+ // clear any menu select message.
+
+ if ( ! ( pdsItems[i].wState & RIB_ITEM_UP ) ) {
+ SEND_WM_MENUSELECT_MSG ( hRibbon->hWndCurOwner, 0, LOWORD(MM_MENUCLOSED), 0 );
+ }
+
+ pdsItems[i].wState = wState;
+ InvalidateRect ( hRibbon->hWnd, &pdsItems[i].Rect, FALSE );
+ }
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+
+} /* end RIB_ItemSetState() */
+
+
+/******************************************************************************
+
+ Name: RIB_ItemEnable()
+
+ Description: This function enables a ribbon item.
+
+ Returns: FALSE, if successful. Otherwise, TRUE.
+
+******************************************************************************/
+
+BOOL RIB_ItemEnable (
+
+HRIBBON hRibbon, // I - handle to a ribbon
+WORD wMessageID, // I - the ribbon item message ID
+BOOL fEnable ) // I - enable/disable flag.
+
+{
+ PDS_RIBITEMINFO pdsItems;
+ INT i;
+ WORD wState;
+
+ if ( ! hRibbon ) {
+ return TRUE;
+ }
+
+ pdsItems = hRibbon->pdsItemList;
+
+ // Loop through the items until we find the matching one.
+
+ for ( i = 0; i < hRibbon->nNumItems; i++ ) {
+
+ if ( pdsItems[i].wMessage == wMessageID ) {
+
+ // Always force UP when the item is enabled or disabled.
+
+ wState = pdsItems[i].wState;
+
+ wState |= RIB_ITEM_UP;
+
+ if ( fEnable ) {
+ wState |= RIB_ITEM_ENABLED;
+ }
+ else {
+ wState &= ~RIB_ITEM_ENABLED;
+ }
+
+ // Set the state and redraw only if it is different.
+
+ if ( pdsItems[i].wState != wState ) {
+
+ // If the item was DOWN and now it is UP,
+ // clear any menu select message.
+
+ if ( ! ( pdsItems[i].wState & RIB_ITEM_UP ) ) {
+ SEND_WM_MENUSELECT_MSG ( hRibbon->hWndCurOwner, 0, LOWORD(MM_MENUCLOSED), 0 );
+ }
+
+ pdsItems[i].wState = wState;
+ InvalidateRect ( hRibbon->hWnd, &pdsItems[i].Rect, FALSE );
+
+ }
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+
+} /* end RIB_ItemEnable() */
+
+
+
+HSPINNER RIB_CreateSpinner (
+
+HWND hWnd,
+WORD wItemID,
+INT x,
+INT y,
+WORD wIncrementMsg,
+WORD wDecrementMsg )
+
+{
+ HSPINNER hSpinner;
+ HWND hWndSpinnerRib;
+ DS_RIBITEMINFO dsRibItem;
+
+ DBG_UNREFERENCED_PARAMETER ( x );
+ DBG_UNREFERENCED_PARAMETER ( y );
+
+ if ( ! hWnd ) {
+ return (HSPINNER)0;
+ }
+
+ hSpinner = (HSPINNER)malloc ( sizeof ( DS_SPINNER ) );
+
+ if ( ! hSpinner ) {
+ return (HSPINNER)0;
+ }
+
+ // create the ribbon window here
+
+ hWndSpinnerRib = WM_Create ( WM_RIBBON,
+ TEXT("Spinner Ribbon"),
+ NULL,
+ 0,
+ 0,
+ 15,
+ 27,
+ (PDS_WMINFO) (DWORD) GetDlgItem ( hWnd, wItemID )
+ );
+
+ // Create/initialize the ribbon itself inside the ribbon window.
+
+ hSpinner->hRib = RIB_Create ( hWndSpinnerRib, RIB_DOWNMESSAGE | RIB_DOWNREPEAT, 8, 16, 2 ) ;
+ hSpinner->wIncrementMsg = wIncrementMsg;
+ hSpinner->wDecrementMsg = wDecrementMsg;
+
+ // Set up the font.
+
+ dsRibItem.hFont = ghFontRibbon;
+
+ // UP ARROW
+
+ dsRibItem.Rect.left = 0;
+ dsRibItem.Rect.top = 0;
+ dsRibItem.Rect.right = 15;
+ dsRibItem.Rect.bottom = 13;
+
+ dsRibItem.rcBM = dsRibItem.Rect;
+
+ dsRibItem.rcBM.left += RIB_ITEM_BORDER_WIDTH;
+ dsRibItem.rcBM.top += RIB_ITEM_BORDER_WIDTH;
+ dsRibItem.rcBM.right -= RIB_ITEM_BORDER_WIDTH;
+ dsRibItem.rcBM.bottom -= RIB_ITEM_BORDER_WIDTH;
+
+ dsRibItem.wEnabledID = IDRBM_UPARROW ;
+ dsRibItem.wDisabledID = IDRBM_UPARROW_GRAY ;
+ dsRibItem.wStringID = ID_NOTDEFINED ;
+ dsRibItem.wAccelKey = ID_NOTDEFINED ;
+ dsRibItem.wState = RIB_ITEM_ENABLED | RIB_ITEM_UP | RIB_ITEM_NOMENUITEM;
+ dsRibItem.wMessage = wIncrementMsg ;
+
+ RIB_ItemAppend ( hSpinner->hRib, &dsRibItem ) ;
+
+
+ // DOWN ARROW
+
+ dsRibItem.Rect.top = 13;
+ dsRibItem.Rect.bottom = 26;
+
+ dsRibItem.rcBM = dsRibItem.Rect;
+
+ dsRibItem.rcBM.left += RIB_ITEM_BORDER_WIDTH;
+ dsRibItem.rcBM.top += RIB_ITEM_BORDER_WIDTH;
+ dsRibItem.rcBM.right -= RIB_ITEM_BORDER_WIDTH;
+ dsRibItem.rcBM.bottom -= RIB_ITEM_BORDER_WIDTH;
+
+ dsRibItem.wEnabledID = IDRBM_DNARROW ;
+ dsRibItem.wDisabledID = IDRBM_DOWNARROW_GRAY ;
+ dsRibItem.wMessage = wDecrementMsg ;
+
+ RIB_ItemAppend ( hSpinner->hRib, &dsRibItem ) ;
+
+ // Set up the spinner owner, the activate, show, and draw the spinner.
+
+ RIB_SetOwner ( hSpinner->hRib, hWnd ) ;
+ RIB_Activate ( hSpinner->hRib );
+ WM_Show ( hSpinner->hRib->hWnd );
+ RIB_Draw ( hSpinner->hRib ) ;
+
+ return hSpinner;
+
+} /* end RIB_CreateSpinner() */
+
+
+VOID RIB_DestroySpinner (
+
+HSPINNER hSpinner )
+
+{
+ if ( ! hSpinner ) {
+ return;
+ }
+
+ // Destroy the spinner ribbon window, then the ribbon.
+
+ DestroyWindow ( hSpinner->hRib->hWnd );
+ RIB_Destroy ( hSpinner->hRib ) ;
+ free ( hSpinner );
+
+} /* end RIB_DestroySpinner() */
+
+
+BOOL RIB_EnableSpinner (
+
+HSPINNER hSpinner,
+BOOL fEnable )
+
+{
+ WORD wState = (WORD) (RIB_ITEM_UP
+ | RIB_ITEM_NOMENUITEM
+ | ( ( fEnable ) ? RIB_ITEM_ENABLED
+ : RIB_ITEM_DISABLED ));
+
+ if ( ! hSpinner ) {
+ return TRUE;
+ }
+
+ RIB_ItemSetState ( hSpinner->hRib, hSpinner->wIncrementMsg, wState );
+ RIB_ItemSetState ( hSpinner->hRib, hSpinner->wDecrementMsg, wState );
+ return FALSE ;
+
+} /* end RIB_EnableSpinner() */
+
diff --git a/private/utils/ntbackup/src/runtime.c b/private/utils/ntbackup/src/runtime.c
new file mode 100644
index 000000000..214738c77
--- /dev/null
+++ b/private/utils/ntbackup/src/runtime.c
@@ -0,0 +1,2481 @@
+
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: RUNTIME.C
+
+ Description: Displays the runtime status for backup, restore
+ verify, delete, erase, and tension.
+
+ $Log: G:\UI\LOGFILES\RUNTIME.C_V $
+
+ Rev 1.98.1.4 27 Jan 1994 16:50:10 Glenn
+Pushing and popping the status line for hw init.
+
+ Rev 1.98.1.3 27 Jan 1994 15:48:52 GREGG
+Always ask to abort at EOF and don't display bytes remaining.
+
+ Rev 1.98.1.2 18 Jan 1994 18:11:28 chrish
+Added fix for EPR 0169. Added fix to handle aborting incremental backup.
+
+ Rev 1.98.1.1 12 Jan 1994 10:24:50 MikeP
+add handling for abort in middle of file
+
+ Rev 1.98.1.0 08 Dec 1993 11:32:44 MikeP
+very deep pathes and unicode
+
+ Rev 1.98 23 Aug 1993 18:33:54 BARRY
+Under OS_WIN32, allow a really large number of lines in the rutime listbox.
+
+ Rev 1.97 20 Aug 1993 09:57:18 GLENN
+Fixed problem with horizontal scroll bar extent - it is now based on the text string extent.
+
+ Rev 1.96 04 Aug 1993 10:17:32 GLENN
+Added support for moving runtime dialog into viewing area if it is moved completely off of the screen.
+
+ Rev 1.95 30 Jul 1993 15:57:12 chrish
+Fixed bug for Nostradamus, when backing up using the command line, aborting
+a large file would wait for complete backup of that file before aborting.
+
+ Rev 1.94 26 Jul 1993 08:53:22 chrish
+CAYMAN EPR 0578: Cleaned up abort messages to display and log file
+
+ Rev 1.93 13 Jul 1993 16:10:14 chrish
+CAYMAN EPR 0578: Added logic to handle aborting a backup or restore. The
+small abort box will only be displayed if there does not exist a file to
+display. Otherwise if aborted in the middle of a file one will get the
+large abort box.
+
+ Rev 1.92 09 Jul 1993 16:47:56 TIMN
+Added Abort dialog help. Need helpids.h also. Fixes EPR(357-0419)
+
+ Rev 1.91 03 Jun 1993 13:16:30 chrish
+CAYMAN fix for canceling of a restore to continue processing.
+
+ Rev 1.90 25 May 1993 14:18:46 chrish
+For CAYMAN - Added new backup/restore abort dialog box.
+
+ Rev 1.89 24 May 1993 15:28:12 CARLS
+
+ Rev 1.88 24 May 1993 12:34:10 chrish
+For Nostradamus and Cayman:
+Cleaned up some logic for JOB_STATUS_ABORT_CHECK switch condition. Also
+modified LargeFileAbort to check to see if operation came from an
+OPERATION_BACKUP or OPERATION_RESTORE operation.
+
+ Rev 1.87 22 May 1993 14:23:58 MIKEP
+fix cataloging abort bug. nostradamus should get this.
+
+ Rev 1.86 18 May 1993 20:04:40 GLENN
+Added INI file name root to the Runtime TITLE bar.
+
+ Rev 1.85 11 May 1993 13:22:30 GLENN
+Added JS_OkToClose() to indicate that the RTD can be closed (operation completed) Removed SC_CLOSE stuff.
+
+ Rev 1.84 29 Apr 1993 11:08:32 CARLS
+fixed runtime status display - screen saver problem
+
+ Rev 1.83 27 Apr 1993 19:30:10 GLENN
+Fixed the tension dialog from calling MultiTask after the DestroyWindow-this fixed EPR that hung the app.
+
+ Rev 1.82 24 Apr 1993 14:51:04 DARRYLP
+Added trap for Alt-F4, allowing us to abort a runtime operation by simulating
+an abort.
+
+ Rev 1.81 22 Apr 1993 13:36:36 chrish
+Nostradamous fix: EPR 0116 - Fixes a problem when the user presses the abort
+button during a backup. The elapse time continue will noe suspend while
+waiting for the user to continue or abort.
+
+ Rev 1.80 21 Apr 1993 17:20:42 GLENN
+Displaying Ready on the status line when the OK button is enabled.
+
+ Rev 1.79 19 Apr 1993 13:36:00 CARLS
+removed warnings
+
+ Rev 1.78 19 Apr 1993 10:26:40 CARLS
+added new line to lprintf's in JS_ReportStreamError routine
+
+ Rev 1.77 13 Apr 1993 16:36:46 GLENN
+Fixed ALT-F4 problem during ERASE. Fixed problem with tape name not displayed.
+
+ Rev 1.76 18 Mar 1993 11:13:22 chrish
+Changed MAX_DISPLAY_PATH_LENGTH to 30
+
+ Rev 1.75 17 Mar 1993 14:31:34 DARRYLP
+Properly fixed the previous bitmap problem - This time I covered the
+correct bitmap.
+
+ Rev 1.74 15 Mar 1993 16:36:04 DARRYLP
+Commented out source bitmap "stuff" for MikeP
+
+ Rev 1.73 12 Mar 1993 09:41:24 MIKEP
+fix bitmap being displayed
+
+ Rev 1.72 11 Mar 1993 15:57:16 chrish
+Addeded code to routine NormalFileAbort such during an abort of a backup or a
+restore when there a multiple set, does not go through all the sets before
+aborting.
+
+ Rev 1.71 09 Mar 1993 11:53:52 STEVEN
+fix bug where we except if no rights to set ACL for DIR
+
+ Rev 1.70 04 Mar 1993 11:10:54 CHUCKB
+When a button gets enabled, make it a default button.
+
+ Rev 1.69 02 Mar 1993 16:45:02 ROBG
+Added *.CMD files to be displayed as executables for WIN32 apps.
+
+ Rev 1.68 18 Feb 1993 11:55:34 BURT
+Changes for Cayman (WIN32)
+
+
+ Rev 1.67 09 Feb 1993 09:33:36 chrish
+1. Moved backup/restore strings to resource strings.
+2. Added stuff for restore abort.
+3. Added back stuff for backup abort ... this was previously put in but don't
+ know if someone forgot to merge back in.
+
+ Rev 1.66 01 Feb 1993 19:55:26 STEVEN
+bug fixes
+
+ Rev 1.65 27 Jan 1993 14:23:10 STEVEN
+updates from msoft
+
+ Rev 1.64 18 Jan 1993 14:32:34 GLENN
+Initialized pointers in the Stream Error reporter.
+
+ Rev 1.63 18 Jan 1993 14:25:38 GLENN
+Added Stream Error Reporting stuff.
+
+ Rev 1.62 08 Jan 1993 14:32:24 chrish
+Kludged the SetModelessFocus routine, the IsChild API does not appear to
+be working properly under NT (Bld-349).
+
+ Rev 1.61 06 Jan 1993 10:18:46 GLENN
+Miscellaneous window validations.
+
+ Rev 1.60 04 Jan 1993 13:37:34 GLENN
+Try something new with horiz ext.
+
+ Rev 1.59 23 Dec 1992 15:37:56 GLENN
+Worked on horizontal SB - now using DlgUnits. Added ability to save RTD location.
+
+ Rev 1.58 17 Nov 1992 08:45:18 chrish
+Minor change to aborting a backup on a large file. Size done maybe greater
+than the file size.
+
+ Rev 1.57 11 Nov 1992 16:34:50 DAVEV
+UNICODE: remove compile warnings
+
+ Rev 1.56 05 Nov 1992 17:20:56 DAVEV
+fix ts
+
+ Rev 1.55 03 Nov 1992 08:27:48 MIKEP
+save otc changes
+
+ Rev 1.54 01 Nov 1992 16:07:02 DAVEV
+Unicode changes
+
+ Rev 1.53 31 Oct 1992 14:56:06 MIKEP
+continue adding small catalog dialog
+
+ Rev 1.52 30 Oct 1992 17:55:56 MIKEP
+started small catalog window
+
+ Rev 1.51 28 Oct 1992 16:44:26 chrish
+Control Break Handling For Backup
+
+ Rev 1.50 07 Oct 1992 13:44:48 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.49 04 Oct 1992 19:40:28 DAVEV
+Unicode Awk pass
+
+ Rev 1.48 02 Oct 1992 16:49:06 GLENN
+Fixed focus change stuff on verify when app is not active.
+
+ Rev 1.47 10 Sep 1992 17:17:44 GLENN
+Fixed bitmap display for BIMINI.
+
+ Rev 1.46 08 Sep 1992 17:29:44 GLENN
+Same as last but added to DM_Tension.
+
+ Rev 1.45 08 Sep 1992 15:42:16 GLENN
+Added MUI_EnableOperations() call in DESTROY message.
+
+ Rev 1.44 19 Aug 1992 14:29:38 CHUCKB
+Added new stuff for NT.
+
+ Rev 1.43 20 Jul 1992 09:59:46 JOHNWT
+gas gauge display work
+
+ Rev 1.42 07 Jul 1992 15:42:06 MIKEP
+unicode changes
+
+ Rev 1.41 19 May 1992 11:58:56 MIKEP
+mips changes
+
+ Rev 1.40 14 May 1992 18:10:18 MIKEP
+nt pass 2
+
+ Rev 1.39 11 May 1992 16:14:40 GLENN
+Added NT changes and a focus fix.
+
+
+*****************************************************/
+
+#include "all.h"
+#include "ctl3d.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+#define ONEMEG (UINT32) 1048576
+#define LISTBOX_BUFFER_LEN 256
+#define LISTBOX_BUFFER_SIZE ( LISTBOX_BUFFER_LEN + 1 )
+#define LISTBOX_LINE_SIZE 256
+#if defined( OS_WIN32 )
+#define MAX_LISTBOX_INDEX 3000 /* max # of items in Runtime listbox */
+#else
+#define MAX_LISTBOX_INDEX 250 /* max # of items in Runtime listbox */
+#endif
+#define GENERAL_NO_ANSWER -999
+#define TEXT_BOX_BUFSIZE 500
+#define FILE_PATH_BUFSIZE 500
+#define NUMERIC_ASCII_BUFSIZE 64
+#define MAX_DISPLAY_PATH_LENGTH 30
+
+extern WORD RT_BSD_index ;
+extern WORD RT_max_BSD_index ;
+#ifdef OEM_EMS
+extern INT32 RT_BSD_OsId ;
+#endif
+
+/* PRIVATE FUNCTION PROTOTYPES */
+
+static INT NormalFileAbort( VOID );
+#ifdef OEM_MSOFT
+ static VOID LargeFileAbort( VOID );
+#else
+ static INT AlternateLargeFileAbort( VOID );
+#endif
+static VOID ListBoxText( LPSTR ) ;
+static VOID SetModelessFocus( WORD );
+static VOID SetTotalBytes( VOID );
+
+/* PRIVATE VARIABLES */
+
+static BOOL mwfSavePos;
+static BOOL mwfOkToClose = FALSE;
+static WORD wIdFile ;
+static WORD wIdFileSave ;
+static WORD wIdDestination ;
+static WORD wIdSource ;
+static WORD wIdBitmapReverseFlag ;
+static HMENU hMenu ;
+static CHAR_PTR abort_flag_ptr ;
+static WORD dialog_status ;
+static WORD wMaxLength ;
+static LONG listbox_index = 4 ;
+static WORD mwActiveListBoxID ;
+static CHAR mwRuntimeAbortFlag ;
+static CHAR mwRuntimeCloseFlag ;
+static UINT64 mwTotalBytes;
+static HWND mwhWndStatus;
+static UINT64 mwLastByteCnt;
+static STATS_PTR op_stats;
+
+#ifdef OEM_EMS
+static DLG_CTRL_ENTRY DefaultCtrlTable[] = {
+ { IDD_JS_DP, 0, CM_ENABLE },
+ { IDD_JS_DP_LABEL, 0, CM_ENABLE },
+ { IDD_JS_FP, 0, CM_ENABLE },
+ { IDD_JS_FP_LABEL, 0, CM_ENABLE },
+ { IDD_JS_BP, 0, CM_ENABLE },
+ { IDD_JS_BP_LABEL, 0, CM_ENABLE },
+ { IDD_JS_ET, 0, CM_ENABLE },
+ { IDD_JS_ET_LABEL, 0, CM_ENABLE },
+ { IDD_JS_CF, 0, CM_ENABLE },
+ { IDD_JS_CF_LABEL, 0, CM_ENABLE },
+ { IDD_JS_SF, 0, CM_ENABLE },
+ { IDD_JS_SF_LABEL, 0, CM_ENABLE }
+};
+
+static DLG_CTRL_ENTRY EMSCtrlTable[] = {
+ { IDD_JS_DP, 0, CM_HIDE },
+ { IDD_JS_DP_LABEL, 0, CM_DISABLE },
+ { IDD_JS_FP, 0, CM_HIDE },
+ { IDD_JS_FP_LABEL, 0, CM_DISABLE },
+ { IDD_JS_BP, 0, CM_ENABLE },
+ { IDD_JS_BP_LABEL, 0, CM_ENABLE },
+ { IDD_JS_ET, 0, CM_ENABLE },
+ { IDD_JS_ET_LABEL, 0, CM_ENABLE },
+ { IDD_JS_CF, 0, CM_HIDE },
+ { IDD_JS_CF_LABEL, 0, CM_DISABLE },
+ { IDD_JS_SF, 0, CM_HIDE },
+ { IDD_JS_SF_LABEL, 0, CM_DISABLE }
+};
+
+// FS_UNKNOWN_OS must be last w/ no other iDispType == FS_UNKNOWN_OS (or its value).
+static DLG_DISPLAY_ENTRY RuntimeDispTable[] = {
+ { FS_EMS_MDB_ID, EMSCtrlTable,
+ sizeof(EMSCtrlTable)/sizeof(EMSCtrlTable[0]), HELPID_DIALOGRUNTIME },
+ { FS_EMS_DSA_ID, EMSCtrlTable,
+ sizeof(EMSCtrlTable)/sizeof(EMSCtrlTable[0]), HELPID_DIALOGRUNTIME },
+ { FS_UNKNOWN_OS, DefaultCtrlTable,
+ sizeof(DefaultCtrlTable)/sizeof(DefaultCtrlTable[0]), HELPID_DIALOGRUNTIME }
+};
+
+static DLG_MODE ModeTable[] = {
+ { 0, RuntimeDispTable,
+ sizeof(RuntimeDispTable)/sizeof(RuntimeDispTable[0]), &(RuntimeDispTable[2]) },
+};
+
+static UINT16 cModeTblSize = sizeof( ModeTable ) / sizeof( ModeTable[0] );
+static DLG_MODE *pCurMode = ModeTable;
+
+#endif
+
+STATS_PTR UI_GetBackupPtrToStatsStructure( );
+
+// Keep track of what's displayed.
+
+#define RUNTIME_NONE 0
+#define RUNTIME_SMALL 1
+#define RUNTIME_LARGE 2
+
+static INT mwRuntimeDisplayed = RUNTIME_NONE;
+
+/***************************************************
+
+ Name: DM_Runtime()
+
+ Description:
+
+ Modified:
+
+ Returns:
+
+*****************************************************/
+DLGRESULT APIENTRY DM_Runtime (
+
+HWND hDlg, /* window handle of the dialog box */
+MSGID msg, /* type of message */
+MP1 mp1, /* message-specific information */
+MP2 mp2 )
+
+{
+ PAINTSTRUCT ps;
+ HDC hDC;
+ HDC hDCBitmap;
+ HWND hWnd;
+
+ UNREFERENCED_PARAMETER ( mp2 );
+
+ switch ( msg ) {
+
+ case WM_INITDIALOG: /* message: initialize dialog box */
+ {
+ CDS_PTR pCDS = CDS_GetPerm ();
+
+ // Let's go 3-D!!
+ Ctl3dSubclassDlgEx( hDlg, CTL3D_ALL );
+
+#ifdef OEM_EMS
+ pCurMode = DM_InitCtrlTables( hDlg, ModeTable, cModeTblSize, 0 );
+ DM_DispShowControls( hDlg, pCurMode, FS_UNKNOWN_OS );
+#endif
+ // Place the dialog in the place saved relative to the
+ // frame window.
+
+ if ( ( ! IsIconic ( ghWndFrame ) ) && CDS_GetRuntimeSize ( pCDS ) != WM_DEFAULT ) {
+
+ RECT rcOldFrame;
+ INT x;
+ INT y;
+
+ GetWindowRect ( ghWndFrame, &rcOldFrame );
+
+ // Move the runtime window to the last position that it was
+ // relative to the frame window.
+
+ x = rcOldFrame.left + CDS_GetRuntimeInfo ( pCDS ).x;
+ y = rcOldFrame.top + CDS_GetRuntimeInfo ( pCDS ).y;
+
+ SetWindowPos ( hDlg,
+ (HWND)NULL,
+ x,
+ y,
+ 0,
+ 0,
+ ( SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE )
+ );
+
+ }
+ else {
+
+ DM_CenterDialog( hDlg );
+ }
+
+ EnableWindow ( GetDlgItem ( hDlg, IDD_JS_OK ), FALSE ) ;
+ EnableWindow ( GetDlgItem ( hDlg, IDD_JS_ABORT ), FALSE ) ;
+
+ // mwhWndStatus = GetDlgItem( hDlg, IDD_STATUS_BAR );
+
+ mwLastByteCnt = U64_Init( 0L, 0L );
+ mwTotalBytes = U64_Init( 0L, 0L );
+
+ mwfSavePos = FALSE;
+ mwfOkToClose = FALSE;
+
+ return FALSE;
+ }
+
+ case WM_MOVE:
+
+ if ( ! IsIconic ( ghWndFrame ) ) {
+
+ RECT rcIntersect;
+ RECT rcDesktop;
+ RECT rcRuntime;
+
+ GetWindowRect ( GetDesktopWindow(), &rcDesktop );
+ GetWindowRect ( hDlg, &rcRuntime );
+
+ if ( ! IntersectRect ( &rcIntersect, &rcDesktop, &rcRuntime ) ) {
+ DM_CenterDialog( hDlg );
+ }
+
+ mwfSavePos = TRUE;
+ }
+
+ break;
+
+ case WM_PAINT:
+
+ /* After removing the screen saver, parts of the runtime display
+ were not refreshed. This call invalidates the window and
+ causes the window to be repainted */
+ InvalidateRect( hDlg, NULL, FALSE ) ;
+
+ hDC = BeginPaint( hDlg, &ps );
+ EndPaint( hDlg, &ps );
+ UpdateWindow( hDlg );
+
+ /* source bitmap */
+
+ if ( wIdSource ) {
+ if ( mwRuntimeDisplayed == RUNTIME_LARGE ) {
+ hWnd = GetDlgItem( hDlg, IDD_JS_SOURCE_DRIVE );
+ hDCBitmap = GetDC( hWnd );
+ RSM_BitmapDraw( (WORD)(wIdSource + BTNFACE_BACKGND), 0, 0, 0, 0, hDCBitmap );
+ ReleaseDC( hWnd, hDCBitmap );
+ }
+ }
+
+ if ( mwRuntimeDisplayed == RUNTIME_LARGE ) {
+ /* destination bitmap */
+
+#ifndef OEM_MSOFT
+ if ( wIdDestination ) {
+ hWnd = GetDlgItem( hDlg, IDD_JS_DEST_DRIVE );
+ hDCBitmap = GetDC( hWnd );
+ RSM_BitmapDraw( wIdDestination, 0, 0, 0, 0, hDCBitmap );
+ ReleaseDC( hWnd, hDCBitmap );
+ }
+#endif
+ /* arrow bitmap */
+ // hWnd = GetDlgItem( hDlg, IDD_JS_ARROW );
+ // hDCBitmap = GetDC( hWnd );
+ // RSM_BitmapDraw( IDRBM_RT_ARROW + BTNFACE_BACKGND, 0, 0, 0, 0, hDCBitmap );
+ // ReleaseDC( hWnd, hDCBitmap );
+
+ hWnd = GetDlgItem( hDlg, IDD_JS_FOLDER );
+ hDCBitmap = GetDC( hWnd );
+ RSM_BitmapDraw( IDRBM_BLANK16x16 + BTNFACE_BACKGND, 0, 0, 0, 0, hDCBitmap );
+#ifdef OEM_EMS
+ switch ( RT_BSD_OsId ) {
+
+ case FS_EMS_MDB_ID:
+ RSM_BitmapDraw( IDRBM_EMS_MDB + BTNFACE_BACKGND, 0, 0, 0, 0, hDCBitmap );
+ wIdFile= 0 ;
+ break;
+ case FS_EMS_DSA_ID:
+ RSM_BitmapDraw( IDRBM_EMS_DSA + BTNFACE_BACKGND, 0, 0, 0, 0, hDCBitmap );
+ wIdFile= 0 ;
+ break;
+ default:
+ RSM_BitmapDraw( IDRBM_FOLDER + BTNFACE_BACKGND, 0, 0, 0, 0, hDCBitmap );
+ break;
+ }
+#else
+ RSM_BitmapDraw( IDRBM_FOLDER + BTNFACE_BACKGND, 0, 0, 0, 0, hDCBitmap );
+#endif
+ ReleaseDC( hWnd, hDCBitmap );
+
+ if ( wIdFile ) {
+
+ hWnd = GetDlgItem( hDlg, IDD_JS_FILE );
+ hDCBitmap = GetDC( hWnd );
+ RSM_BitmapDraw( IDRBM_BLANK16x16 + BTNFACE_BACKGND, 0, 0, 0, 0, hDCBitmap );
+ RSM_BitmapDraw( (WORD)(wIdFile + BTNFACE_BACKGND), 0, 0, 0, 0, hDCBitmap );
+ ReleaseDC( hWnd, hDCBitmap );
+ }
+
+ JobStatusStats( mwLastByteCnt );
+ }
+
+ return TRUE;
+
+ case WM_COMMAND:
+
+ switch ( GET_WM_COMMAND_ID ( mp1, mp2 ) ) {
+
+ case IDOK:
+ case IDD_JS_OK:
+
+ // If the OK button is enabled, kill off the dialog.
+
+ if ( IsWindowEnabled ( GetDlgItem ( hDlg, IDD_JS_OK ) ) ) {
+ DestroyWindow ( hDlg );
+ mwRuntimeDisplayed = RUNTIME_NONE;
+ }
+
+ return TRUE;
+
+ case IDCANCEL:
+ case IDD_JS_ABORT:
+
+ // Only allow an ABORT when the ABORT button is enable
+ // or the OK button is enabled
+ // If the ABORT button is enabled, then pop up the message
+ // box.
+
+ if ( IsWindowEnabled ( GetDlgItem( hDlg, IDD_JS_ABORT ) ) ) {
+ mwRuntimeAbortFlag = TRUE ;
+ EnableWindow( GetDlgItem( hDlg, IDD_JS_ABORT ), FALSE );
+ }
+ else if ( IsWindowEnabled ( GetDlgItem( hDlg, IDD_JS_OK ) ) ) {
+ DestroyWindow( hDlg ) ;
+ mwRuntimeDisplayed = RUNTIME_NONE;
+ }
+
+ return TRUE;
+
+ case IDHELP:
+ case IDD_JS_HELP:
+
+ HM_DialogHelp( HELPID_DIALOGRUNTIME );
+ return TRUE;
+
+ } /* end switch() */
+
+ break;
+
+ case WM_CLOSE:
+
+ if ( IsWindowEnabled ( GetDlgItem ( hDlg, IDD_JS_OK ) ) ) {
+ DestroyWindow ( hDlg );
+ mwRuntimeDisplayed = RUNTIME_NONE;
+ }
+ else {
+ mwRuntimeAbortFlag = TRUE ;
+ mwRuntimeCloseFlag = TRUE;
+ SendMessage ( hDlg, (MSGID)WM_COMMAND, (MPARAM1)IDCANCEL, (MPARAM2)NULL );
+ }
+
+ return TRUE;
+
+ case WM_DESTROY:
+
+ if ( ghModelessDialog ) {
+
+ if ( mwfSavePos ) {
+
+ CDS_PTR pCDS = CDS_GetPerm ();
+
+ CDS_WriteRuntimeWinSize ( ghModelessDialog );
+ CDS_ReadRuntimeWinSize ( pCDS );
+ mwfSavePos = FALSE;
+ }
+
+ mwRuntimeDisplayed = RUNTIME_NONE;
+ ghModelessDialog = (HWND)NULL ;
+
+ MUI_EnableOperations ( (WORD)NULL );
+
+ return FALSE;
+ }
+ else {
+ return TRUE;
+ }
+
+ } /* end switch() */
+
+ return FALSE;
+}
+
+
+/***************************************************
+
+ Name: JobStatusStats()
+
+ Description:
+
+ Returns:
+
+*****************************************************/
+VOID JobStatusStats (
+
+UINT64 NumBytes )
+
+{
+#ifndef OEM_MSOFT
+
+ HDC hDC;
+ HBRUSH hBrush;
+ RECT rect;
+ UINT32 divisor;
+ INT width;
+ CHAR szPercent[5];
+ INT BkModeOld;
+ INT x,y;
+ INT AmtDone;
+#if !defined( WIN32 )
+ DWORD dwExtent;
+#endif
+#if defined ( WIN32 )
+ SIZE tSize ;
+#endif
+
+ mwLastByteCnt = NumBytes;
+
+ if ( ( !U64_EQ(mwTotalBytes, U64_Init( 0L, 0L )) ) &&
+ ( !U64_EQ(NumBytes, U64_Init( 0L, 0L )) ) ) {
+
+ GetClientRect( mwhWndStatus, &rect );
+ divisor = mwTotalBytes.lsw / ((UINT32) rect.right);
+ width = rect.right;
+ rect.right = (INT) ( NumBytes.lsw / divisor );
+
+ hDC = GetDC( mwhWndStatus );
+
+ divisor = mwTotalBytes.lsw / ((UINT32) 100);
+ AmtDone = (INT) ( NumBytes.lsw / divisor );
+ sprintf (szPercent, TEXT("%d%%"), AmtDone);
+#if !defined( WIN32 )
+ dwExtent = GetTextExtent (hDC, szPercent, strlen(szPercent));
+ x = ( width - LOWORD(dwExtent) ) / 2;
+ y = ( rect.bottom - HIWORD(dwExtent) ) / 2;
+#else
+ GetTextExtentPoint ( hDC, szPercent, strlen(szPercent), &tSize );
+ x = ( width - tSize.cx ) / 2;
+ y = ( rect.bottom - tSize.cy ) / 2;
+
+#endif
+
+ // kludge to erase the background
+ if ( rect.right < x+25 ) {
+ TextOut (hDC, x, y, TEXT(" "), 6);
+ }
+
+ BkModeOld = SetBkMode (hDC, TRANSPARENT);
+
+ hBrush = SelectObject( hDC, ghBrushGray );
+
+ Rectangle( hDC, rect.left,
+ rect.top,
+ rect.right,
+ rect.bottom );
+
+ TextOut (hDC, x, y, szPercent, strlen(szPercent));
+
+ SetBkMode (hDC, BkModeOld);
+ SelectObject( hDC, hBrush );
+ ReleaseDC( mwhWndStatus, hDC );
+
+ }
+
+#endif
+
+ return;
+}
+
+
+
+/***************************************************
+
+ Name: JobStatusBackupRestore()
+
+ Description:
+
+ Modified:
+
+ Returns:
+
+*****************************************************/
+
+VOID JobStatusBackupRestore (
+
+WORD control_function ) /* I - control function number */
+
+{
+ HWND hWnd ;
+ HDC hDCBitmap ;
+
+ switch( control_function ) {
+
+ case JOB_STATUS_N_OF_N:
+
+ if ( mwRuntimeDisplayed != RUNTIME_LARGE ) break;
+
+ /* catalog a tape will not know the max number of backup sets on */
+ /* the tape, so don't display "N of N" */
+
+ /* for each new backup set clear the runtime display status fields */
+ if ( RT_max_BSD_index ) {
+
+ #ifndef OEM_MSOFT
+ {
+ CHAR buffer1[ LISTBOX_BUFFER_SIZE ] ;
+ CHAR buffer2[ LISTBOX_BUFFER_SIZE ] ;
+
+ /* display the N of N count */
+ RSM_StringCopy( IDS_SET_INFORMATION, buffer1, 80) ;
+ wsprintf( buffer2, buffer1, RT_BSD_index, RT_max_BSD_index ) ;
+ SetDlgItemText( ghModelessDialog, IDD_JS_N_OF_N, buffer2 ) ;
+ }
+ #endif
+
+ /* clear the all the counter fields between sets */
+ yprintf( TEXT("0\r") ) ;
+ SetDlgItemText( ghModelessDialog, IDD_JS_FP, gszTprintfBuffer ) ;
+ SetDlgItemText( ghModelessDialog, IDD_JS_BP, gszTprintfBuffer ) ;
+ SetDlgItemText( ghModelessDialog, IDD_JS_DP, gszTprintfBuffer ) ;
+ SetDlgItemText( ghModelessDialog, IDD_JS_SF, gszTprintfBuffer ) ;
+ SetDlgItemText( ghModelessDialog, IDD_JS_CF, gszTprintfBuffer ) ;
+
+ /* clear the elapsed time field */
+ yprintf( TEXT("00%c00\r"), UI_GetTimeSeparator() ) ;
+ SetDlgItemText( ghModelessDialog, IDD_JS_ET, gszTprintfBuffer ) ;
+
+ /* clear the directory & file name fields */
+ yprintf( TEXT(" \r") ) ;
+// SetDlgItemText( ghModelessDialog, IDD_JS_FILE, gszTprintfBuffer ) ;
+// SetDlgItemText( ghModelessDialog, IDD_JS_FOLDER, gszTprintfBuffer ) ;
+ SetDlgItemText( ghModelessDialog, IDD_JS_LINE1, gszTprintfBuffer ) ;
+ SetDlgItemText( ghModelessDialog, IDD_JS_LINE2, gszTprintfBuffer ) ;
+
+ hWnd = GetDlgItem( ghModelessDialog, IDD_JS_FOLDER ) ;
+ hDCBitmap = GetDC( hWnd );
+ RSM_BitmapDraw( IDRBM_BLANK16x16 + BTNFACE_BACKGND, 0, 0, 0, 0, hDCBitmap );
+
+ ReleaseDC( hWnd, hDCBitmap );
+
+ hWnd = GetDlgItem( ghModelessDialog, IDD_JS_FILE ) ;
+
+ hDCBitmap = GetDC( hWnd ) ;
+ RSM_BitmapDraw( IDRBM_BLANK16x16 + BTNFACE_BACKGND, 0, 0, 0, 0, hDCBitmap );
+
+ ReleaseDC ( hWnd, hDCBitmap ) ;
+
+ }
+ break ;
+
+ case JOB_STATUS_DIRECTORY_NAMES:
+
+ if ( mwRuntimeDisplayed != RUNTIME_LARGE ) break;
+ DisplayDirectory( ghModelessDialog, gszTprintfBuffer, IDD_JS_LINE1 ) ;
+ wIdFileSave = FALSE ;
+
+// SetDlgItemText ( ghModelessDialog, IDD_JS_FILE, TEXT(" \r") ) ;
+ SetDlgItemText ( ghModelessDialog, IDD_JS_LINE2, TEXT(" \r") ) ;
+
+ hWnd = GetDlgItem( ghModelessDialog, IDD_JS_FOLDER ) ;
+ hDCBitmap = GetDC( hWnd );
+ RSM_BitmapDraw( IDRBM_BLANK16x16 + BTNFACE_BACKGND, 0, 0, 0, 0, hDCBitmap );
+
+ switch ( RT_BSD_OsId ) {
+
+ case FS_EMS_MDB_ID:
+ RSM_BitmapDraw( IDRBM_EMS_MDB + BTNFACE_BACKGND, 0, 0, 0, 0, hDCBitmap );
+ break;
+ case FS_EMS_DSA_ID:
+ RSM_BitmapDraw( IDRBM_EMS_DSA + BTNFACE_BACKGND, 0, 0, 0, 0, hDCBitmap );
+ break;
+ default:
+ RSM_BitmapDraw( IDRBM_FOLDER + BTNFACE_BACKGND, 0, 0, 0, 0, hDCBitmap );
+ break;
+ }
+ ReleaseDC( hWnd, hDCBitmap );
+
+ hWnd = GetDlgItem( ghModelessDialog, IDD_JS_FILE ) ;
+
+ hDCBitmap = GetDC( hWnd ) ;
+ RSM_BitmapDraw( IDRBM_BLANK16x16 + BTNFACE_BACKGND, 0, 0, 0, 0, hDCBitmap );
+
+ ReleaseDC ( hWnd, hDCBitmap ) ;
+
+ break ;
+
+ case JOB_STATUS_ELAPSED_TIME:
+
+ if ( mwRuntimeDisplayed != RUNTIME_LARGE ) break;
+ SetDlgItemText( ghModelessDialog, IDD_JS_ET, gszTprintfBuffer ) ;
+ break ;
+
+ case JOB_STATUS_FILES_PROCESSED:
+
+ if ( mwRuntimeDisplayed != RUNTIME_LARGE ) break;
+ SetDlgItemText( ghModelessDialog, IDD_JS_FP, gszTprintfBuffer ) ;
+ break ;
+
+ case JOB_STATUS_BYTES_PROCESSED:
+
+ if ( mwRuntimeDisplayed != RUNTIME_LARGE ) break;
+ SetDlgItemText( ghModelessDialog, IDD_JS_BP, gszTprintfBuffer ) ;
+ break ;
+
+ case JOB_STATUS_SOURCE_NAME:
+
+ if ( mwRuntimeDisplayed != RUNTIME_LARGE ) break;
+
+ /* display the source name */
+ SetDlgItemText( ghModelessDialog, IDD_JS_SOURCE_NAME, gszTprintfBuffer ) ;
+
+ /* for each new backup set clear the runtime display status fields */
+ JobStatusBackupRestore( JOB_STATUS_N_OF_N ) ;
+
+ /* increment the N of N counter */
+ RT_BSD_index++ ;
+
+ break ;
+
+ case JOB_STATUS_DEST_NAME:
+
+ if ( mwRuntimeDisplayed != RUNTIME_LARGE ) break;
+
+ /* display the destination name */
+ SetDlgItemText( ghModelessDialog, IDD_JS_DEST_NAME, gszTprintfBuffer ) ;
+
+ break ;
+#ifdef OEM_EMS
+ case JOB_STATUS_FS_TYPE:
+
+ DM_DispShowControls( ghModelessDialog, pCurMode, RT_BSD_OsId );
+
+ break;
+#endif
+ case JOB_STATUS_VOLUME_HARDDRIVE:
+
+ if ( mwRuntimeDisplayed != RUNTIME_LARGE ) break;
+
+ if ( wIdBitmapReverseFlag ) {
+ wIdSource = IDRBM_LTAPE;
+ }
+ else {
+ wIdSource = IDRBM_HARDDRIVE;
+ }
+
+ hWnd = GetDlgItem( ghModelessDialog, IDD_JS_SOURCE_DRIVE ) ;
+ hDCBitmap = GetDC( hWnd ) ;
+ RSM_BitmapDraw( (WORD)(wIdSource + BTNFACE_BACKGND), 0, 0, 0, 0, hDCBitmap ) ;
+ ReleaseDC( hWnd, hDCBitmap ) ;
+
+ if ( wIdBitmapReverseFlag ) {
+ wIdDestination = IDRBM_HARDDRIVE ;
+ }
+ else {
+ wIdDestination = IDRBM_LTAPE ;
+ }
+
+ #ifndef OEM_MSOFT
+ {
+ hWnd = GetDlgItem( ghModelessDialog, IDD_JS_DEST_DRIVE ) ;
+ hDCBitmap = GetDC( hWnd ) ;
+ RSM_BitmapDraw( wIdDestination + BTNFACE_BACKGND, 0, 0, 0, 0, hDCBitmap ) ;
+ ReleaseDC( hWnd, hDCBitmap ) ;
+
+ // hWnd = GetDlgItem( ghModelessDialog, IDD_JS_ARROW ) ;
+ // hDCBitmap = GetDC( hWnd ) ;
+ // RSM_BitmapDraw( IDRBM_RT_ARROW, 0, 0, 0, 0, hDCBitmap ) ;
+ // ReleaseDC( hWnd, hDCBitmap ) ;
+ }
+ #endif
+
+ break ;
+
+ case JOB_STATUS_VOLUME_NETDRIVE:
+
+ if ( mwRuntimeDisplayed != RUNTIME_LARGE ) break;
+
+ if ( wIdBitmapReverseFlag ) {
+ wIdSource = IDRBM_LTAPE;
+ }
+ else {
+ wIdSource = IDRBM_NETDRIVE;
+ }
+
+ hWnd = GetDlgItem( ghModelessDialog, IDD_JS_SOURCE_DRIVE ) ;
+ hDCBitmap = GetDC( hWnd ) ;
+
+ RSM_BitmapDraw( (WORD)(wIdSource + BTNFACE_BACKGND), 0, 0, 0, 0, hDCBitmap ) ;
+ ReleaseDC( hWnd, hDCBitmap ) ;
+
+ if ( wIdBitmapReverseFlag ) {
+ wIdDestination = IDRBM_NETDRIVE ;
+ }
+ else {
+ wIdDestination = IDRBM_LTAPE ;
+ }
+
+ #ifndef OEM_MSOFT
+ {
+ hWnd = GetDlgItem( ghModelessDialog, IDD_JS_DEST_DRIVE ) ;
+ hDCBitmap = GetDC( hWnd ) ;
+ RSM_BitmapDraw( wIdDestination + BTNFACE_BACKGND, 0, 0, 0, 0, hDCBitmap ) ;
+ ReleaseDC( hWnd, hDCBitmap ) ;
+
+ // hWnd = GetDlgItem( ghModelessDialog, IDD_JS_ARROW ) ;
+ // hDCBitmap = GetDC( hWnd ) ;
+ // RSM_BitmapDraw( IDRBM_RT_ARROW, 0, 0, 0, 0, hDCBitmap ) ;
+ // ReleaseDC( hWnd, hDCBitmap ) ;
+ }
+ #endif
+
+
+ break ;
+
+ case JOB_STATUS_VOLUME_TAPE:
+
+ if ( mwRuntimeDisplayed != RUNTIME_LARGE ) break;
+
+ wIdSource = IDRBM_LTAPE;
+
+ hWnd = GetDlgItem( ghModelessDialog, IDD_JS_SOURCE_DRIVE ) ;
+ hDCBitmap = GetDC( hWnd ) ;
+
+ RSM_BitmapDraw( (WORD)(wIdSource + BTNFACE_BACKGND), 0, 0, 0, 0, hDCBitmap ) ;
+ ReleaseDC( hWnd, hDCBitmap ) ;
+
+ #ifndef OEM_MSOFT
+ {
+ wIdDestination = IDRBM_HARDDRIVE ;
+ hWnd = GetDlgItem( ghModelessDialog, IDD_JS_DEST_DRIVE ) ;
+ hDCBitmap = GetDC( hWnd ) ;
+ RSM_BitmapDraw( wIdDestination + BTNFACE_BACKGND, 0, 0, 0, 0, hDCBitmap ) ;
+ ReleaseDC( hWnd, hDCBitmap ) ;
+
+ // hWnd = GetDlgItem( ghModelessDialog, IDD_JS_ARROW ) ;
+ // hDCBitmap = GetDC( hWnd ) ;
+ // RSM_BitmapDraw( IDRBM_RT_ARROW, 0, 0, 0, 0, hDCBitmap ) ;
+ // ReleaseDC( hWnd, hDCBitmap ) ;
+ }
+ #endif
+
+ break ;
+
+ case JOB_STATUS_EXCEPTION_WINDOW:
+
+ if ( mwRuntimeDisplayed != RUNTIME_NONE ) break;
+ SetDlgItemText( ghModelessDialog, IDD_JS_LISTBOX, gszTprintfBuffer ) ;
+ break ;
+
+ case JOB_STATUS_DIRECTORIES_PROCESS:
+
+ if ( mwRuntimeDisplayed != RUNTIME_LARGE ) break;
+ SetDlgItemText( ghModelessDialog, IDD_JS_DP, gszTprintfBuffer ) ;
+ break ;
+
+ case JOB_STATUS_SKIPPED_FILES:
+
+ if ( mwRuntimeDisplayed != RUNTIME_LARGE ) break;
+ SetDlgItemText( ghModelessDialog, IDD_JS_SF, gszTprintfBuffer ) ;
+ break ;
+
+ case JOB_STATUS_CORRUPT_FILES:
+
+ if ( mwRuntimeDisplayed != RUNTIME_LARGE ) break;
+ SetDlgItemText( ghModelessDialog, IDD_JS_CF, gszTprintfBuffer ) ;
+ break ;
+
+ case JOB_STATUS_FILE_NAMES:
+
+ if ( mwRuntimeDisplayed != RUNTIME_LARGE ) break;
+
+ if ( strstr ( gszTprintfBuffer, TEXT(".COM") ) ) {
+ wIdFile = IDRBM_EXE ;
+ }
+ else if ( strstr ( gszTprintfBuffer, TEXT(".EXE") ) ) {
+ wIdFile = IDRBM_EXE ;
+ }
+
+#if defined ( WIN32 )
+
+ else if ( strstr ( gszTprintfBuffer, TEXT(".CMD") ) ) {
+ wIdFile = IDRBM_EXE ;
+ }
+#endif
+
+ else {
+ wIdFile = IDRBM_FILE ;
+ }
+
+ /* only draw the bitmap if it has changed */
+ if( wIdFile != wIdFileSave ) {
+
+ hWnd = GetDlgItem( ghModelessDialog, IDD_JS_FILE ) ;
+
+ hDCBitmap = GetDC( hWnd ) ;
+
+ RSM_BitmapDraw ( (WORD)(wIdFile + BTNFACE_BACKGND), 0, 0, 0, 0, hDCBitmap ) ;
+
+ ReleaseDC ( hWnd, hDCBitmap ) ;
+ }
+
+ wIdFileSave = wIdFile ;
+
+ strlwr ( gszTprintfBuffer ) ;
+ SetDlgItemText ( ghModelessDialog, IDD_JS_LINE2, gszTprintfBuffer ) ;
+ break ;
+
+ case JOB_STATUS_LISTBOX:
+
+ if ( mwRuntimeDisplayed == RUNTIME_NONE ) break;
+ ListBoxText( gszTprintfBuffer ) ;
+ break ;
+
+ case JOB_STATUS_ABORT:
+
+ if ( mwRuntimeDisplayed == RUNTIME_NONE ) break;
+ *abort_flag_ptr = (CHAR)ABORT_PROCESSED ;
+ break ;
+
+ case JOB_STATUS_ABORT_OFF:
+
+ if ( mwRuntimeDisplayed == RUNTIME_NONE ) break;
+ WM_SetAppIcon ( RSM_IconLoad ( IDRI_DONE ) );
+
+ EnableWindow ( GetDlgItem ( ghModelessDialog, IDD_JS_OK ), TRUE );
+ SetModelessFocus ( IDD_JS_OK );
+ EnableMenuItem ( hMenu, SC_CLOSE, MF_ENABLED );
+
+ EnableWindow ( GetDlgItem ( ghModelessDialog, IDD_JS_ABORT ), FALSE );
+
+ STM_SetIdleText ( IDS_READY );
+ mwfOkToClose = TRUE;
+
+ // If the Yes Flag is set, don't wait for the OK, kill off the
+ // window. Also if this was a WM_CLOSE, kill the window.
+
+ if ( ( CDS_GetYesFlag ( CDS_GetCopy () ) == YESYES_FLAG ) || mwRuntimeCloseFlag ) {
+
+ JobStatusBackupRestore( JOB_STATUS_DESTROY_DIALOG );
+ }
+
+ break ;
+
+ case JOB_STATUS_ABORT_ON:
+ case JOB_STATUS_ABORT_ENABLE:
+
+ if ( mwRuntimeDisplayed == RUNTIME_NONE ) break;
+ EnableWindow ( GetDlgItem ( ghModelessDialog, IDD_JS_ABORT ), TRUE ) ;
+ SetModelessFocus( IDD_JS_ABORT ) ;
+ EnableMenuItem( hMenu, SC_CLOSE, MF_ENABLED ) ;
+ break ;
+
+ case JOB_STATUS_ABORT_DISABLE:
+
+ /* if abort button enabled - disable it */
+
+ if ( mwRuntimeDisplayed == RUNTIME_NONE ) break;
+
+ if ( IsWindowEnabled ( GetDlgItem ( ghModelessDialog, IDD_JS_ABORT ) ) ) {
+ SetModelessFocus ( IDD_JS_HELP );
+ EnableWindow ( GetDlgItem ( ghModelessDialog, IDD_JS_ABORT ), FALSE ) ;
+ EnableMenuItem( hMenu, SC_CLOSE, MF_GRAYED ) ;
+ }
+
+ break ;
+
+ case JOB_STATUS_ABORT_CHECK:
+
+ if ( mwRuntimeAbortFlag ) {
+
+ if ( gbCurrentOperation == OPERATION_BACKUP ) {
+ op_stats = UI_GetBackupPtrToStatsStructure( );
+ ST_StartBackupSetIdle( op_stats );
+ }
+
+#ifdef OEM_MSOFT
+ if ( NormalFileAbort() == WMMB_IDYES ) {
+ LargeFileAbort();
+ }
+#else
+ if ( !AlternateLargeFileAbort() ) {
+ NormalFileAbort();
+ }
+#endif
+
+ if ( gbCurrentOperation == OPERATION_BACKUP ) {
+ ST_EndBackupSetIdle( op_stats );
+ }
+ }
+
+ break;
+
+ case JOB_STATUS_CREATE_DIALOG:
+
+ // if ( mwRuntimeDisplayed != RUNTIME_NONE ) break;
+
+ /* if the runtime dialog is displayed already, don't try to create it */
+ if ( ! ghModelessDialog ) {
+
+ mwRuntimeDisplayed = RUNTIME_LARGE;
+
+ DM_ShowDialog ( ghWndFrame, IDD_RUNTIME, NULL ) ;
+
+ SetWindowText( ghModelessDialog, TEXT(" ") ) ;
+
+ /* Show the dialog window like the frame window is shown. */
+
+ if ( IsIconic ( ghWndFrame ) ) {
+ ShowWindow ( ghModelessDialog, SW_HIDE ) ;
+ }
+ else {
+ ShowWindow ( ghModelessDialog, SW_SHOWNORMAL ) ;
+ }
+
+ hMenu = GetSystemMenu( ghModelessDialog, FALSE ) ;
+ EnableMenuItem( hMenu, SC_CLOSE, MF_GRAYED ) ;
+
+ wIdFile = 0 ;
+
+ /* reset the HARD DRIVE as the default bitmap */
+
+ wIdSource = 0 ;
+ wIdDestination = 0 ;
+
+ // wIdSource = IDRBM_HARDDRIVE ;
+ // wIdDestination = IDRBM_LTAPE ;
+
+ UpdateWindow( ghModelessDialog ) ;
+
+ hMenu = GetSystemMenu( ghModelessDialog, FALSE ) ;
+ EnableMenuItem( hMenu, SC_CLOSE, MF_GRAYED ) ;
+
+ /* clear the elapsed time field */
+ yprintf( TEXT("00%c00\r"), UI_GetTimeSeparator() ) ;
+ SetDlgItemText( ghModelessDialog, IDD_JS_ET, gszTprintfBuffer ) ;
+
+ wMaxLength = 1 ;
+ listbox_index = 4 ;
+
+ /* set the ID for the Runtime status listbox */
+ mwActiveListBoxID = IDD_JS_LISTBOX ;
+ }
+
+ // set the statistics totals
+ mwLastByteCnt = U64_Init( 0L, 0L );
+ mwTotalBytes = U64_Init( 0L, 0L );
+ if ( CDS_GetEnableStatsFlag ( CDS_GetPerm () ) ) {
+ SetTotalBytes();
+ }
+
+ /* disable the ABORT button until the abort flag pointer has been set */
+ EnableWindow ( GetDlgItem ( ghModelessDialog, IDD_JS_ABORT ), FALSE ) ;
+
+ /* disable the OK button */
+ EnableWindow ( GetDlgItem ( ghModelessDialog, IDD_JS_OK ), FALSE ) ;
+
+ /* disable the system menu close */
+ EnableMenuItem ( hMenu, SC_CLOSE, MF_GRAYED );
+
+ /* give the listbox the focus */
+ SetModelessFocus ( IDD_JS_LISTBOX );
+
+ mwRuntimeAbortFlag = FALSE ;
+ mwRuntimeCloseFlag = FALSE ;
+ wIdFileSave = FALSE ;
+
+ break ;
+
+
+ case JOB_STATUS_CREATE_SMALL_DIALOG:
+
+ /* if the runtime dialog is displayed already, don't try to create it */
+
+ if ( mwRuntimeDisplayed != RUNTIME_NONE ) break;
+
+ if ( ! ghModelessDialog ) {
+
+ mwRuntimeDisplayed = RUNTIME_SMALL;
+
+ DM_ShowDialog ( ghWndFrame, IDD_CATALOG, NULL ) ;
+
+ SetWindowText( ghModelessDialog, TEXT(" ") ) ;
+
+ /* Show the dialog window like the frame window is shown. */
+
+ if ( IsIconic ( ghWndFrame ) ) {
+ ShowWindow ( ghModelessDialog, SW_HIDE ) ;
+ }
+ else {
+ ShowWindow ( ghModelessDialog, SW_SHOWNORMAL ) ;
+ }
+
+ hMenu = GetSystemMenu( ghModelessDialog, FALSE ) ;
+ EnableMenuItem( hMenu, SC_CLOSE, MF_GRAYED ) ;
+
+ UpdateWindow( ghModelessDialog ) ;
+
+ hMenu = GetSystemMenu( ghModelessDialog, FALSE ) ;
+ EnableMenuItem( hMenu, SC_CLOSE, MF_GRAYED ) ;
+
+ wMaxLength = 1 ;
+ listbox_index = 4 ;
+
+ /* set the ID for the Runtime status listbox */
+ mwActiveListBoxID = IDD_JS_LISTBOX ;
+ }
+
+ /* disable the ABORT button until the abort flag pointer has been set */
+ EnableWindow ( GetDlgItem ( ghModelessDialog, IDD_JS_ABORT ), FALSE ) ;
+
+ /* disable the OK button */
+ EnableWindow ( GetDlgItem ( ghModelessDialog, IDD_JS_OK ), FALSE ) ;
+
+ /* disable the system menu close */
+ EnableMenuItem ( hMenu, SC_CLOSE, MF_GRAYED );
+
+ /* give the listbox the focus */
+ SetModelessFocus ( IDD_JS_LISTBOX );
+
+ mwRuntimeAbortFlag = FALSE ;
+ mwRuntimeCloseFlag = FALSE ;
+ break ;
+
+
+ case JOB_STATUS_DESTROY_DIALOG:
+
+ if ( mwRuntimeDisplayed != RUNTIME_NONE ) {
+ DestroyWindow ( ghModelessDialog ) ;
+ mwRuntimeDisplayed = RUNTIME_NONE;
+ }
+
+ return;
+
+ case JOB_STATUS_BACKUP_TITLE:
+
+ if ( mwRuntimeDisplayed != RUNTIME_LARGE ) break;
+
+ if ( CDS_UsingCmdLineINI () ) {
+
+ CHAR szTemp[MAX_UI_RESOURCE_SIZE];
+ LPSTR p;
+
+ CDS_GetIniFileName ( szTemp, sizeof ( szTemp ) );
+
+ p = strstr ( szTemp, TEXT(".INI") );
+
+ *p = (CHAR)NULL;
+
+ strcat ( gszTprintfBuffer, TEXT(" - ") );
+ strcat ( gszTprintfBuffer, szTemp );
+ }
+
+ SetWindowText( ghModelessDialog, gszTprintfBuffer ) ;
+
+ RT_BSD_index = 1 ; /* start with set number 1 */
+
+ /* clear the source/destination name fields */
+ yprintf( TEXT(" \r") ) ;
+ SetDlgItemText( ghModelessDialog, IDD_JS_SOURCE_NAME, gszTprintfBuffer ) ;
+
+ #ifndef OEM_MSOFT
+ {
+ SetDlgItemText( ghModelessDialog, IDD_JS_DEST_NAME, gszTprintfBuffer ) ;
+ }
+ #endif
+
+ wIdBitmapReverseFlag = FALSE ;
+ break ;
+
+ case JOB_STATUS_RESTORE_TITLE:
+
+ if ( mwRuntimeDisplayed != RUNTIME_LARGE ) break;
+ SetWindowText( ghModelessDialog, gszTprintfBuffer ) ;
+ RT_BSD_index = 1 ; /* start with set number 1 */
+ wIdBitmapReverseFlag = TRUE ;
+ break ;
+
+ case JOB_STATUS_CATALOG_TITLE:
+
+ if ( mwRuntimeDisplayed == RUNTIME_NONE ) break;
+ SetWindowText( ghModelessDialog, gszTprintfBuffer ) ;
+ RT_BSD_index = 1 ; /* start with set number 1 */
+ RT_max_BSD_index = 0 ; /* will not know the max BSDs when cataloging */
+ wIdBitmapReverseFlag = TRUE ;
+ break ;
+
+ case JOB_STATUS_VERIFY_TITLE:
+
+ if ( mwRuntimeDisplayed != RUNTIME_LARGE ) break;
+ SetWindowText( ghModelessDialog, gszTprintfBuffer ) ;
+
+ /* clear the source/destination name fields */
+ yprintf( TEXT(" \r") ) ;
+ SetDlgItemText( ghModelessDialog, IDD_JS_SOURCE_NAME, gszTprintfBuffer ) ;
+
+ #ifndef OEM_MSOFT
+ {
+ SetDlgItemText( ghModelessDialog, IDD_JS_DEST_NAME, gszTprintfBuffer ) ;
+ }
+ #endif
+
+ /* clear the directory & file name fields */
+ SetDlgItemText( ghModelessDialog, IDD_JS_LINE1, gszTprintfBuffer ) ;
+ SetDlgItemText( ghModelessDialog, IDD_JS_LINE2, gszTprintfBuffer ) ;
+
+ /* clear the all the counter fields */
+ yprintf( TEXT("0\r") ) ;
+ SetDlgItemText( ghModelessDialog, IDD_JS_FP, gszTprintfBuffer ) ;
+ SetDlgItemText( ghModelessDialog, IDD_JS_BP, gszTprintfBuffer ) ;
+ SetDlgItemText( ghModelessDialog, IDD_JS_DP, gszTprintfBuffer ) ;
+ SetDlgItemText( ghModelessDialog, IDD_JS_SF, gszTprintfBuffer ) ;
+ SetDlgItemText( ghModelessDialog, IDD_JS_CF, gszTprintfBuffer ) ;
+
+ /* clear the elapsed time field */
+ yprintf( TEXT("00%c00\r"), UI_GetTimeSeparator() ) ;
+ SetDlgItemText( ghModelessDialog, IDD_JS_ET, gszTprintfBuffer ) ;
+
+ RT_BSD_index = 1 ; /* start with set number 1 */
+
+ wIdBitmapReverseFlag = TRUE ;
+ break ;
+
+ }
+
+ if ( ghModelessDialog ) {
+ UpdateWindow( ghModelessDialog ) ;
+ }
+
+ WM_MultiTask ( ) ;
+}
+
+
+/***************************************************
+
+ Name: LargeFileAbort ()
+
+ Description: Performs the abort process
+ during backup for a file that
+ has > 1MEG bytes left to process
+
+ Modified:
+
+ Returns:
+
+*****************************************************/
+static VOID LargeFileAbort ( VOID )
+{
+
+ INT nAnswer;
+ CHAR fpath[FILE_PATH_BUFSIZE];
+ CHAR buffer1[LISTBOX_BUFFER_SIZE ] ;
+ CHAR AbortText[TEXT_BOX_BUFSIZE];
+ INT largeAbort = 1;
+ INT operation;
+ CHAR AbortFmtStr[MAX_UI_RESOURCE_SIZE];
+ CHAR AbortTitle[81];
+ STATS stats;
+
+ UI_GetCurrentStatus( &operation, &stats, fpath, sizeof( fpath ) - 1 );
+
+ if ( operation == OPERATION_BACKUP || operation == OPERATION_RESTORE ) {
+ // do nothing
+ } else {
+ /* We answered YES to normal abort, so change the abort pointer */
+ /* back to ABORT_PROCESSED - This is for operations catalog, delete, verify */
+ *abort_flag_ptr = (CHAR)ABORT_PROCESSED;
+ return;
+ }
+
+ UI_FixPath( fpath, MAX_DISPLAY_PATH_LENGTH, TEXT('\\') );
+
+ /* reset the abort flag */
+ mwRuntimeAbortFlag = FALSE ;
+
+ // Ask the user if an abort is really what they want.
+
+ if ( operation == OPERATION_BACKUP ) {
+ RSM_StringCopy( RES_BACKUP_ABORT_EOF, AbortFmtStr, MAX_UI_RESOURCE_SIZE );
+ } else {
+ RSM_StringCopy( RES_RESTORE_ABORT_EOF, AbortFmtStr, MAX_UI_RESOURCE_SIZE );
+ }
+
+ RSM_StringCopy( IDS_MSGTITLE_ABORT, AbortTitle, 80 );
+
+ sprintf( AbortText, AbortFmtStr, fpath ) ;
+
+ nAnswer = WM_MessageBox ( AbortTitle,
+ AbortText,
+ WMMB_CONTABORT | WMMB_NOYYCHECK,
+ WMMB_ICONEXCLAMATION,
+ NULL,
+ 0,
+ HELPID_OPERATIONSBACKUP ) ;
+
+ if ( nAnswer == WMMB_IDABORT ) {
+
+ gfAbortInMiddleOfFile = TRUE;
+
+ *abort_flag_ptr = (CHAR)ABORT_PROCESSED;
+
+ // if we are terminating the app, set the YY flag so
+ // we exit out without prompts
+
+ if ( gfTerminateApp ) {
+
+ CDS_SetYesFlag ( CDS_GetCopy (), YESYES_FLAG );
+
+ }
+
+ }
+ else {
+ /* display the abort message in the listbox */
+
+ if ( operation == OPERATION_BACKUP ) {
+ RSM_StringCopy( RES_CONTINUE_BACKUP_ABORT, buffer1, LISTBOX_BUFFER_LEN ) ;
+ lresprintf( LOGGING_FILE ,
+ LOG_MSG ,
+ SES_ENG_MSG ,
+ RES_CONTINUE_BACKUP_ABORT );
+ } else {
+ RSM_StringCopy( RES_CONTINUE_RESTORE_ABORT, buffer1, LISTBOX_BUFFER_LEN ) ;
+ lresprintf( LOGGING_FILE ,
+ LOG_MSG ,
+ SES_ENG_MSG ,
+ RES_CONTINUE_RESTORE_ABORT );
+ }
+
+ ListBoxText( buffer1 ) ;
+
+
+ //
+ // These two lines below tell the backup app. not to chop
+ // off the file when the user aborts the backup or restore
+ // process. Compliments of MikeP.
+ //
+
+ *abort_flag_ptr = CONTINUE_PROCESSING ; // chs
+ UI_AbortAtEndOfFile(); // chs
+
+ //
+ //
+ //
+
+ EnableWindow( GetDlgItem( ghModelessDialog, IDD_JS_ABORT ), FALSE );
+
+ }
+
+}
+
+
+/***************************************************
+
+ Name: NormalAbortFile ()
+
+ Description: Performs the abort process
+ during backup.
+
+ Modified:
+
+ Returns: WMMB_? value
+
+*****************************************************/
+static INT NormalFileAbort ( VOID )
+{
+ CHAR buffer1[ LISTBOX_BUFFER_SIZE ] ;
+ INT nAnswer;
+ STATS stats;
+ CHAR fpath[FILE_PATH_BUFSIZE];
+ // and file name
+
+
+ /* reset the abort flag */
+ mwRuntimeAbortFlag = FALSE ;
+
+ // Ask the user if an abort is really what they want.
+
+ nAnswer = WM_MsgBox ( ID( RES_ABORT_STRING ),
+ ID( RES_ABORT_QUESTION ),
+ WMMB_YESNO | WMMB_NOYYCHECK,
+ WMMB_ICONQUESTION );
+
+ if ( nAnswer == WMMB_IDYES ) {
+
+ *abort_flag_ptr = (CHAR)ABORT_PROCESSED;
+
+ /* display the abort message in the listbox */
+
+ RSM_StringCopy( RES_PROCESS_ABORTED, buffer1, LISTBOX_BUFFER_LEN ) ;
+
+ ListBoxText( buffer1 ) ;
+
+ lresprintf( LOGGING_FILE ,
+ LOG_MSG ,
+ SES_ENG_MSG ,
+ RES_PROCESS_ABORTED );
+
+ *abort_flag_ptr = CONTINUE_PROCESSING ;
+
+ if ( UI_GetBackupCurrentStatus( &stats, fpath, sizeof( fpath ) - 1 ) == SUCCESS ) {
+ // chs:03-11-93
+ //
+ // If current file size is zero then we do not have a file.
+ //
+
+ if ( U64_EQ( ST_GetCFSize( &stats ), U32_To_U64( 0L ) ) ) {
+
+ *abort_flag_ptr = (CHAR)ABORT_PROCESSED;
+ } else {
+
+ UI_AbortAtEndOfFile();
+ }
+
+ } else {
+ *abort_flag_ptr = (CHAR)ABORT_PROCESSED;
+ }
+
+ // if we are terminating the app, set the YY flag so
+ // we exit out without prompts
+
+ if ( gfTerminateApp ) {
+
+ CDS_SetYesFlag ( CDS_GetCopy (), YESYES_FLAG );
+
+ }
+
+ }
+ else { /* don't abort */
+
+ gfTerminateApp = FALSE;
+ EnableWindow( GetDlgItem( ghModelessDialog, IDD_JS_ABORT ), TRUE );
+ SetModelessFocus ( IDD_JS_ABORT );
+ mwRuntimeCloseFlag = FALSE ;
+
+ }
+
+ return( nAnswer );
+}
+
+/***************************************************
+
+ Name: JobStatusAbort( )
+
+ Description:
+
+ Modified:
+
+ Returns: Void
+
+*****************************************************/
+
+VOID JobStatusAbort( VOID *p )
+{
+ abort_flag_ptr = (CHAR *)p ;
+}
+
+
+/***************************************************
+
+ Name: JS_OkToClose ( )
+
+ Description:
+
+ Modified:
+
+ Returns: TRUE, if OK to close, otherwise FALSE.
+
+*****************************************************/
+
+BOOL JS_OkToClose ( VOID )
+{
+ return mwfOkToClose;
+}
+
+
+/***************************************************
+
+ Name: ListBoxText( )
+
+ Description: This routine processes strings for the runtime and
+ tension/erase listbox.
+
+ Modified:
+
+ Returns: Void
+
+*****************************************************/
+static VOID ListBoxText(
+LPSTR input_buffer_ptr ) /* i - pointer to string */
+{
+ CHAR buff[ LISTBOX_BUFFER_SIZE ] ;
+ LPSTR p ;
+ CHAR *temp_buffer_ptr, ch ;
+ WORD char_counter ;
+ LONG index ;
+ HDC hDC ;
+ WORD wLength ;
+
+ char_counter = 0 ;
+ temp_buffer_ptr = buff ;
+
+ do
+ {
+ ch = *temp_buffer_ptr = *input_buffer_ptr ;
+ char_counter++ ;
+
+ if ( char_counter == LISTBOX_LINE_SIZE ) {
+
+ if ( *input_buffer_ptr != TEXT(' ') ) {
+
+ /* try to find a word break to split the line */
+ while ( *input_buffer_ptr != TEXT(' ') )
+ {
+ *input_buffer_ptr-- ;
+ *temp_buffer_ptr-- ;
+ }
+
+ *input_buffer_ptr-- ;
+ ch = 0 ;
+ }
+ }
+
+ if ( ch == 0x0a || ch == 0x0d || ch == 0 ) {
+
+ if ( ch == 0x0a ) {
+ *temp_buffer_ptr++ = TEXT(' ') ; /* replace the LF control CHAR with a space */
+ }
+ *temp_buffer_ptr = 0 ;
+
+ /* if any data in the buffer, print it */
+ if ( strlen ( buff ) ) {
+
+ SIZE dsSize;
+
+ hDC = GetDC( GetDlgItem( ghModelessDialog, mwActiveListBoxID) ) ;
+
+ /* get the length of the string in logical units */
+
+ GetTextExtentPoint ( hDC, buff, strlen ( buff ), &dsSize );
+
+ // Add in about 5% for dialog list box approximation error.
+
+ wLength = ( (WORD)dsSize.cx * 105 ) / 100;
+
+ if ( wLength > wMaxLength ) {
+
+ SendMessage( GetDlgItem( ghModelessDialog, mwActiveListBoxID),
+ LB_SETHORIZONTALEXTENT, wLength, 0L ) ;
+
+ wMaxLength = wLength ;
+
+ /* if horizontal scroll bars are displayed - */
+ /* then only allow 4 entries in the list box */
+
+ listbox_index = 3 ;
+ }
+
+ ReleaseDC( GetDlgItem( ghModelessDialog, mwActiveListBoxID), hDC ) ;
+
+ p = buff ;
+
+ /* add the new string to the list box */
+
+ index = SendDlgItemMessage ( ghModelessDialog,
+ mwActiveListBoxID,
+ LB_ADDSTRING,
+ ( WORD )NULL,
+ ( DWORD )p ) ;
+
+ // Needed for single lines broken up into multiple lines?
+
+ UpdateWindow ( ghModelessDialog );
+
+ /* only allow MAX_LISTBOX_INDEX entries in the list box */
+
+ if( index > MAX_LISTBOX_INDEX ) {
+
+ SendDlgItemMessage ( ghModelessDialog,
+ mwActiveListBoxID,
+ LB_DELETESTRING,
+ ( WORD )0,
+ ( DWORD )NULL ) ;
+ }
+
+ /* there can be 4 or 5 lines in the listbox */
+ /* if printing to the last line, cause the listbox */
+ /* to scroll */
+
+ if ( index > listbox_index ) {
+
+ HWND hWnd = GetDlgItem ( ghModelessDialog, mwActiveListBoxID );
+
+ SEND_WM_VSCROLL_MSG ( hWnd, SB_BOTTOM, 0, NULL );
+ SEND_WM_VSCROLL_MSG ( hWnd, SB_ENDSCROLL, 1, NULL );
+
+// SendDlgItemMessage ( ghModelessDialog,
+// mwActiveListBoxID,
+// LB_SETTOPINDEX,
+// ( WORD )( index - listbox_index ),
+// (MP2) NULL ) ;
+ }
+ }
+
+ temp_buffer_ptr = buff ;
+ char_counter = 0 ;
+ }
+ else {
+ *temp_buffer_ptr++ ;
+ }
+
+ } while( *input_buffer_ptr++ ) ;
+}
+
+
+/***************************************************
+
+ Name: DM_Tension( )
+
+ Description:
+
+ Modified:
+
+ Returns:
+
+*****************************************************/
+
+BOOL FAR PASCAL DM_Tension (
+
+HWND hDlg, /* window handle of the dialog box */
+MSGID message, /* type of message */
+MP1 mp1, /* message-specific information */
+MP2 mp2 )
+
+{
+ PAINTSTRUCT ps;
+ HDC hDC;
+
+ UNREFERENCED_PARAMETER ( mp2 );
+
+ switch ( message ) {
+
+ case WM_INITDIALOG: /* message: initialize dialog box */
+
+ DM_CenterDialog( hDlg );
+ mwfOkToClose = FALSE;
+ return TRUE;
+
+ case WM_PAINT:
+
+ hDC = BeginPaint( hDlg, &ps );
+ EndPaint( hDlg, &ps );
+ UpdateWindow( hDlg );
+ return TRUE;
+
+ case WM_COMMAND: /* message: received a command */
+ {
+ WORD wId = GET_WM_COMMAND_ID ( mp1, mp2 );
+
+ if ( wId == IDOK || wId == IDD_JST_OK ) { /* TEXT("OK") box selected? */
+
+ // if the OK button is enabled, destroy the dialog
+
+ if ( IsWindowEnabled ( GetDlgItem ( hDlg, IDD_JST_OK ) ) ) {
+ DestroyWindow ( hDlg );
+ mwRuntimeDisplayed = RUNTIME_NONE;
+ }
+
+ return TRUE; // RETURN
+ }
+
+ break;
+ }
+
+ case WM_CLOSE:
+
+ if ( ghModelessDialog && IsWindowEnabled ( GetDlgItem ( hDlg, IDD_JST_OK ) ) ) {
+ DestroyWindow ( hDlg );
+ mwRuntimeDisplayed = RUNTIME_NONE;
+ }
+
+ break;
+
+ case WM_DESTROY:
+
+ if ( ghModelessDialog ) {
+ ghModelessDialog = (HWND)NULL;
+ MUI_EnableOperations ( (WORD)NULL );
+ break;
+ }
+ else {
+ return TRUE;
+ }
+
+ } /* end switch */
+
+ return FALSE; /* Didn't process a message */
+}
+
+
+/***************************************************
+
+ Name: JobStatusTension( )
+
+ Description:
+
+ Modified:
+
+ Returns: Void
+
+*****************************************************/
+
+VOID JobStatusTension (
+
+WORD control_function ) /* I - control function number */
+
+{
+
+ switch ( control_function ) {
+
+ case JOB_TENSION_LISTBOX:
+
+ ListBoxText( gszTprintfBuffer );
+ break;
+
+ case JOB_TENSION_ABORT_OFF:
+
+ EnableMenuItem( hMenu, SC_CLOSE, MF_ENABLED );
+ EnableWindow( GetDlgItem( ghModelessDialog, IDD_JST_OK ), 1 );
+ SetModelessFocus( IDD_JST_OK );
+ STM_SetIdleText ( IDS_READY );
+ mwfOkToClose = TRUE;
+ break;
+
+ case JOB_TENSION_ABORT_ON:
+ break;
+
+ case JOB_TENSION_DRAW_BITMAP:
+ break;
+
+ case JOB_TENSION_CREATE_DIALOG:
+
+ DM_ShowDialog ( ghWndFrame, IDD_TENSION, NULL );
+
+ SetWindowText( ghModelessDialog, TEXT(" ") );
+
+ hMenu = GetSystemMenu( ghModelessDialog, FALSE );
+ EnableMenuItem( hMenu, SC_CLOSE, MF_GRAYED );
+ EnableWindow( GetDlgItem( ghModelessDialog, IDD_JST_OK ), 0 );
+ wMaxLength = 1;
+ listbox_index = 4;
+
+ /* set the ID for the Tension/Erase listbox */
+ mwActiveListBoxID = IDD_JST_LISTBOX;
+
+ break;
+
+ case JOB_TENSION_DESTROY_DIALOG:
+
+ if ( mwRuntimeDisplayed != RUNTIME_NONE ) {
+ DestroyWindow ( ghModelessDialog );
+ mwRuntimeDisplayed = RUNTIME_NONE;
+ }
+
+ return;
+
+ case JOB_TENSION_ERASE_TITLE:
+
+ SetWindowText( ghModelessDialog, gszTprintfBuffer );
+ break;
+
+ case JOB_TENSION_TENSION_TITLE:
+
+ SetWindowText( ghModelessDialog, gszTprintfBuffer );
+ break;
+ }
+
+ if ( ghModelessDialog ) {
+ UpdateWindow ( ghModelessDialog );
+ }
+
+ WM_MultiTask ( );
+}
+
+/***************************************************
+
+ Name: SetModelessFocus( )
+
+ Description: Set the focus to a dialog control if our
+ app is active.
+
+ Returns: Void
+
+*****************************************************/
+
+static VOID SetModelessFocus ( WORD wControl )
+{
+ HWND hWndActive = GetActiveWindow( );
+ HWND ParentWindow;
+
+ if ( !hWndActive ) {
+ return;
+ }
+
+ ParentWindow = GetParent( hWndActive );
+
+ if ( ( GetParent ( hWndActive ) == ghModelessDialog ) ||
+ ( IsChild ( ghWndFrame, hWndActive ) == TRUE ) ||
+ ( ParentWindow == ghWndFrame ) ) {
+
+ SetFocus ( GetDlgItem ( ghModelessDialog, wControl ) );
+ SendDlgItemMessage( ghModelessDialog, wControl, BM_SETSTYLE,
+ (WPARAM) LOWORD(BS_DEFPUSHBUTTON), MAKELPARAM(TRUE, 0) );
+ }
+}
+
+/***************************************************
+
+ Name: SetTotalBytes( )
+
+ Description:
+
+
+ Returns: Void
+
+*****************************************************/
+
+static VOID SetTotalBytes( VOID )
+{
+
+ return;
+
+}
+
+
+/******************************************************************************
+
+ Name: JS_ReportStreamError ()
+
+ Description:
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID JS_ReportStreamError (
+
+FSYS_HAND hFsys,
+GENERIC_DLE_PTR dle,
+UINT32 unStreamID,
+WORD wOperationType,
+INT16 nLoopError,
+DBLK_PTR pDirDBLK,
+DBLK_PTR pFileDBLK )
+
+{
+ CHAR szBuffer[MAX_UI_RESOURCE_SIZE];
+ UINT unStringID;
+ BOOL fDirOnly = TRUE;
+ UINT16 alloc_size ;
+
+ if ( pFileDBLK && FS_GetBlockType( pFileDBLK ) == DDB_ID ) {
+ pDirDBLK = pFileDBLK ;
+ pFileDBLK = NULL ;
+ }
+
+ // Verify difference in data, security, alt-data, extended attr.
+
+ switch ( nLoopError ) {
+
+ case LP_ACCESS_DENIED_ERROR:
+ case LP_PRIVILEGE_ERROR:
+
+ if ( DLE_GetDeviceType( dle ) == FS_EMS_DRV ) {
+ if (wOperationType == OPERATION_BACKUP ) {
+ unStringID = RES_EMS_BKU_ACCESS_FAILURE ;
+ } else {
+ unStringID = RES_EMS_RST_ACCESS_FAILURE ;
+ }
+
+ if ( DLE_GetParent( dle ) ) {
+
+ dle = DLE_GetParent(dle) ;
+ }
+
+
+ unStreamID = STRM_INVALID ;
+
+ } else if ( pFileDBLK != NULL ) {
+ unStringID = IDS_RTD_ACCESSDENIED_FILE;
+ fDirOnly = FALSE;
+ }
+ else {
+ unStringID = IDS_RTD_ACCESSDENIED_DIR;
+ }
+
+ break;
+
+ case FS_BAD_ATTACH_TO_SERVER:
+
+ unStringID = IDS_XCHNG_NO_SERVICE_RUNNING ;
+ unStreamID = STRM_INVALID ;
+
+ break;
+ case LP_FILE_WRITE_ERROR:
+
+ if ( pFileDBLK != NULL ) {
+ unStringID = IDS_RTD_WRITEERROR_FILE;
+ fDirOnly = FALSE;
+ }
+ else {
+ unStringID = IDS_RTD_WRITEERROR_DIR;
+ }
+
+ break;
+
+ default:
+
+ unStringID = 0;
+ break;
+
+ }
+
+ // If there is a valid string ID, print out the message to the
+ // list box, log file, and debug window.
+
+ if ( unStringID ) {
+
+ LPSTR pszDirFile = NULL;
+ alloc_size = FS_SizeofPathInDDB( hFsys, pDirDBLK ) + 5 ;
+
+ if ( pFileDBLK ) {
+ alloc_size += FS_SizeofFnameInFDB( hFsys, pFileDBLK ) ;
+ }
+
+ UI_AllocPathBuffer( &pszDirFile,
+ alloc_size ) ;
+
+ if ( pszDirFile ) {
+
+ CHAR chDelimiter = (CHAR)DLE_GetPathDelim ( dle );
+
+ UI_BuildDelimitedPathFromDDB ( &pszDirFile, hFsys, pDirDBLK, chDelimiter, FALSE );
+
+ if ( ! fDirOnly ) {
+
+ LPSTR pszFile = NULL;
+
+ UI_AllocPathBuffer ( &pszFile, FS_SizeofFnameInFDB ( hFsys, pFileDBLK ) ) ;
+
+ if ( pszFile ) {
+
+ FS_GetFnameFromFDB( hFsys, pFileDBLK, pszFile );
+ UI_AppendDelimiter( pszDirFile, chDelimiter );
+ strcat( pszDirFile, pszFile );
+ UI_FreePathBuffer( &pszFile );
+ }
+ }
+ }
+
+ RSM_Sprintf ( szBuffer, (LPSTR)(DWORD)unStringID, pszDirFile+1 );
+
+ UI_FreePathBuffer ( &pszDirFile ) ;
+
+ zprintf ( 0, szBuffer );
+ ListBoxText ( szBuffer );
+ lprintf( (INT16) LOGGING_FILE, TEXT("%s\n"), szBuffer );
+
+ }
+
+ unStringID = 0 ;
+ switch ( unStreamID ) {
+
+ case -1:
+ case 0 :
+ break ;
+
+ case STRM_GENERIC_DATA: /* 'STAN' */
+
+ switch ( wOperationType ) {
+
+ case OPERATION_BACKUP:
+ unStringID = IDS_RTD_READERROR_STREAM;
+ break;
+
+ case OPERATION_RESTORE:
+ unStringID = IDS_RTD_WRITEERROR_STREAM;
+ break;
+ }
+
+ break;
+
+ case STRM_NT_ACL: /* 'NACL' */
+ case STRM_NOV_TRUST_286: /* 'N286' */
+ case STRM_NOV_TRUST_386: /* 'N386' */
+
+ switch( wOperationType ) {
+
+ case OPERATION_BACKUP:
+ unStringID = IDS_RTD_READERROR_SECURITYSTREAM;
+ break;
+
+ case OPERATION_RESTORE:
+ unStringID = IDS_RTD_WRITEERROR_SECURITYSTREAM;
+ break;
+ }
+
+ break;
+
+ case STRM_NT_EA: /* 'NTEA' */
+
+ switch( wOperationType ) {
+
+ case OPERATION_BACKUP:
+ unStringID = IDS_RTD_READERROR_EA;
+ break;
+
+ case OPERATION_RESTORE:
+ unStringID = IDS_RTD_WRITEERROR_EA;
+ break;
+
+ case OPERATION_VERIFY:
+ unStringID = IDS_RTD_VERIFYERROR_EA;
+ break;
+ }
+
+ break;
+
+ case STRM_NTFS_LINK: /* 'LINK' */
+
+ switch( wOperationType ) {
+
+ case OPERATION_BACKUP:
+ unStringID = IDS_RTD_READERROR_LINK;
+ break;
+
+ case OPERATION_RESTORE:
+ unStringID = IDS_RTD_CREATEERROR_LINK;
+ break;
+ }
+
+ break;
+
+ case STRM_MAC_RESOURCE: /* 'MRSC' */
+ case STRM_NTFS_ALT_DATA: /* 'ADAT' */
+
+ default:
+
+ switch( wOperationType ) {
+
+ case OPERATION_BACKUP:
+ unStringID = IDS_RTD_READERROR_ALTSTREAM;
+ break;
+
+ case OPERATION_RESTORE:
+ unStringID = IDS_RTD_WRITEERROR_ALTSTREAM;
+ break;
+ }
+
+ break;
+
+ } /* end switch() */
+
+
+ // Print out the message to the list box, log file, and debug window.
+ if ( unStringID != 0 ) {
+
+ RSM_StringCopy ( unStringID, szBuffer, sizeof ( szBuffer ) );
+
+ zprintf ( 0, szBuffer );
+ ListBoxText ( szBuffer );
+ lprintf( (INT16) LOGGING_FILE, TEXT("%s\n"), szBuffer );
+ }
+
+ return;
+
+} /* end JS_ReportStreamError() */
+
+
+#ifndef OEM_MSOFT
+
+/***************************************************
+
+ Name: AlternateLargeFileAbort ()
+
+ Description: Performs the abort process
+ during backup for a file
+
+ Modified:
+
+ Returns:
+
+*****************************************************/
+static INT AlternateLargeFileAbort ( VOID )
+{
+
+ INT nAnswer;
+ STATS stats;
+ CHAR fpath[FILE_PATH_BUFSIZE];
+ CHAR buffer1[ LISTBOX_BUFFER_SIZE ] ;
+ CHAR AbortText[TEXT_BOX_BUFSIZE];
+ INT operation;
+ BOOLEAN retval;
+ CHAR AbortMsg[2][TEXT_BOX_BUFSIZE / 2];
+ WNDPROC lpProc ;
+ HWND hWnd;
+ INT16 FileFound = 0;
+
+
+ UI_GetCurrentStatus( &operation, &stats, fpath, sizeof( fpath ) - 1 );
+
+ if ( operation == OPERATION_BACKUP || operation == OPERATION_RESTORE ) {
+ // do nothing
+ } else {
+ /* We answered YES to normal abort, so change the abort pointer */
+ /* back to ABORT_PROCESSED - This is for operations catalog, delete, verify */
+
+ return( 0 );
+ }
+
+ if ( strlen( fpath ) > 1 ) {
+ if ( stricmp( &fpath[ strlen( fpath ) - 1 ], TEXT( "\\" ) ) )
+ FileFound = 1;
+ }
+
+ if ( !FileFound ) {
+
+
+ // if we are terminating the app, set the YY flag so
+ // we exit out without prompts
+
+ if ( gfTerminateApp ) {
+ CDS_SetYesFlag ( CDS_GetCopy (), YESYES_FLAG );
+ }
+ return( 0 );
+ }
+
+
+ UI_FixPath( fpath, MAX_DISPLAY_PATH_LENGTH, TEXT('\\') );
+
+ /* reset the abort flag */
+ mwRuntimeAbortFlag = FALSE ;
+
+ // Ask the user if an abort is really what they want.
+
+ RSM_StringCopy( RES_CURRENT_FILE, AbortMsg[0], TEXT_BOX_BUFSIZE / 2 );
+
+ if ( operation == OPERATION_BACKUP ) {
+ RSM_StringCopy( RES_BACKUP_ABORT_PART2, AbortMsg[1], TEXT_BOX_BUFSIZE / 2 );
+ } else {
+ RSM_StringCopy( RES_RESTORE_ABORT_PART2, AbortMsg[1], TEXT_BOX_BUFSIZE / 2 );
+ }
+
+ sprintf(AbortText, TEXT("%s %s\012\012%s"), AbortMsg[0], fpath, AbortMsg[1]);
+
+
+ hWnd = GetLastActivePopup( ghWndFrame );
+
+ nAnswer = DM_ShowDialog( hWnd, IDD_ABORT_BOX, AbortText );
+
+ switch (nAnswer ) {
+
+ case IDD_ABORT_YES:
+
+ /* display the abort message in the listbox */
+
+ RSM_StringCopy( RES_PROCESS_ABORTED, buffer1, LISTBOX_BUFFER_LEN ) ;
+
+ ListBoxText( buffer1 ) ;
+
+ lresprintf( LOGGING_FILE ,
+ LOG_MSG ,
+ SES_ENG_MSG ,
+ RES_PROCESS_ABORTED );
+
+ *abort_flag_ptr = (CHAR)ABORT_PROCESSED;
+
+ // if we are terminating the app, set the YY flag so
+ // we exit out without prompts
+
+ if ( gfTerminateApp ) {
+ CDS_SetYesFlag ( CDS_GetCopy (), YESYES_FLAG );
+ }
+
+ break;
+
+ case IDD_ABORT_EOF:
+
+
+ /* display the abort message in the listbox */
+
+ RSM_StringCopy( RES_PROCESS_ABORTED, buffer1, LISTBOX_BUFFER_LEN ) ;
+
+ ListBoxText( buffer1 ) ;
+
+ lresprintf( LOGGING_FILE ,
+ LOG_MSG ,
+ SES_ENG_MSG ,
+ RES_PROCESS_ABORTED );
+
+ //
+ // These two lines below tell the backup app. not to chop
+ // off the file when the user aborts the backup or restore
+ // process. Compliments of MikeP.
+ //
+
+ *abort_flag_ptr = CONTINUE_PROCESSING ;
+ UI_AbortAtEndOfFile();
+
+ //
+ //
+ //
+
+ EnableWindow( GetDlgItem( ghModelessDialog, IDD_JS_ABORT ), TRUE );
+
+ break;
+
+ case IDD_ABORT_CANCEL:
+
+
+// chs:07-24-93 ListBoxText( buffer1 ) ;
+// chs:07-24-93
+// chs:07-24-93 lresprintf( LOGGING_FILE ,
+// chs:07-24-93 LOG_MSG ,
+// chs:07-24-93 SES_ENG_MSG ,
+// chs:07-24-93 RES_RESUME_PROCESS );
+
+ mwRuntimeAbortFlag = FALSE ;
+ gfTerminateApp = FALSE;
+ mwRuntimeCloseFlag = FALSE ;
+ gb_abort_flag = *abort_flag_ptr = CONTINUE_PROCESSING ;
+ gbAbortAtEOF = FALSE;
+ EnableWindow( GetDlgItem( ghModelessDialog, IDD_JS_ABORT ), TRUE );
+
+ break;
+ }
+
+ return( 1 );
+
+}
+
+/***************************************************
+
+ Name: DM_Abort()
+
+ Description:
+
+ Returns:
+
+*****************************************************/
+DLGRESULT APIENTRY DM_Abort(
+ HWND hDlg , /* window handle of the dialog box */
+ MSGID message , /* type of message */
+ MP1 mp1 , /* message-specific information */
+ MP2 mp2
+)
+{
+ static HWND hWndMsg;
+ HDC hDC; /* device context */
+ RECT rect;
+ CHAR_PTR MsgPtr;
+ HICON hIcon;
+ HWND hWndIcon; /* handle of window for icon drawing */
+ PAINTSTRUCT ps ;
+
+
+ switch ( message )
+ {
+ case WM_INITDIALOG: /* message: initialize dialog box */
+
+ DM_CenterDialog( hDlg );
+ MsgPtr = ( CHAR_PTR )mp2;
+ SetDlgItemText( hDlg, IDD_ABORT_MESSAGE_TEXT, MsgPtr );
+
+ return (TRUE);
+
+ break;
+
+ case WM_PAINT:
+
+ hDC = BeginPaint( hDlg, &ps ) ;
+ EndPaint( hDlg, &ps ) ;
+ UpdateWindow( hDlg ) ; /* force the dialog to be displayed now */
+
+ hWndIcon = GetDlgItem( hDlg, IDD_MSG_ICON );
+ hIcon = LoadIcon( (HINSTANCE)NULL, IDI_EXCLAMATION );
+ hDC = GetDC( hWndIcon );
+ DrawIcon( hDC, 0, 0, hIcon );
+ ReleaseDC( hWndIcon, hDC );
+
+ return ( TRUE ) ;
+
+ break;
+
+ case WM_COMMAND: /* message: received a command */
+ switch( GET_WM_COMMAND_ID ( mp1, mp2 ) )
+ {
+
+ case IDD_ABORT_YES:
+ case IDD_ABORT_EOF:
+ case IDD_ABORT_CANCEL:
+ EndDialog( hDlg, GET_WM_COMMAND_ID ( mp1, mp2 ) );
+ return( TRUE );
+ break;
+
+ case IDHELP:
+ HM_DialogHelp( HELPID_DIALOGABORT ) ;
+ return( TRUE );
+ break;
+
+ default:
+ return( FALSE );
+ break;
+
+ }
+ break;
+
+
+/***************************************************************************
+ * Respond to the close selection from the system menu
+ ***************************************************************************/
+
+ case WM_CLOSE:
+ {
+ EndDialog ( hDlg, FALSE ); /* return false in this case */
+ return TRUE;
+ }
+
+/***************************************************************************
+ * Respond to the destroy message
+ ***************************************************************************/
+
+ case WM_DESTROY:
+
+ WM_MultiTask ();
+ break;
+
+ }
+
+
+ return ( FALSE ); /* Didn't process a message */
+}
+
+#endif
+
+
+
diff --git a/private/utils/ntbackup/src/savepath.c b/private/utils/ntbackup/src/savepath.c
new file mode 100644
index 000000000..44b7c88fe
--- /dev/null
+++ b/private/utils/ntbackup/src/savepath.c
@@ -0,0 +1,164 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: savepath.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains code to attach a "current directory" string
+ on to the file system handle
+
+
+ $Log: M:/LOGFILES/SAVEPATH.C_V $
+
+ Rev 1.8 24 Nov 1993 14:47:16 BARRY
+Unicode fixes
+
+ Rev 1.7 10 Nov 1993 13:09:22 STEVEN
+fixed memory corruption with unicode
+
+ Rev 1.6 04 Feb 1993 14:56:18 TIMN
+Added Unicode header to resolve link errors
+
+ Rev 1.5 11 Nov 1992 22:26:56 GREGG
+Unicodeized literals.
+
+ Rev 1.4 06 Oct 1992 13:24:20 DAVEV
+Unicode strlen verification
+
+ Rev 1.3 18 Aug 1992 10:29:52 STEVEN
+fix warnings
+
+ Rev 1.2 13 Jan 1992 18:46:14 STEVEN
+changes for WIN32 compile
+
+ Rev 1.1 01 Oct 1991 11:16:20 BARRY
+Include standard headers.
+
+ Rev 1.0 09 May 1991 13:37:10 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "stdwcs.h"
+
+#include "fsys.h"
+#include "fsys_prv.h"
+/* $end$ include list */
+
+/**/
+/**
+
+ Name: FS_SavePath()
+
+ Description: This function attaches a copy of the passed path to the
+ file system handle.
+
+ Modified: 8/10/1989
+
+ Returns: SUCCESS or OUT_OF_MEMORY
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 FS_SavePath(
+FSYS_HAND fsh,
+UINT8_PTR path,
+UINT16 path_len ) // size of path buffer in bytes incl NULL term
+{
+ UINT16 cb_psize; // string buffer size in bytes incl NULL term
+ CHAR_PTR temp;
+ INT16 ret_val = SUCCESS ;
+
+ if ( path_len > (UINT16)fsh->leng_dir ) {
+
+ /* previous buffer was too small. so lets allocate a */
+ /* bigger one and throw the old one away. */
+
+ cb_psize = (INT16)(((path_len + 2 * sizeof (CHAR) ) / CUR_DIR_CHUNK + 1 ) * CUR_DIR_CHUNK );
+ temp = fsh->cur_dir;
+ fsh->cur_dir = (CHAR_PTR) malloc( cb_psize ) ;
+
+ if ( fsh->cur_dir == NULL ) {
+ fsh->cur_dir = temp ;
+ ret_val = OUT_OF_MEMORY ;
+ } else {
+ free( temp ) ;
+ fsh->leng_dir = cb_psize ;
+ memcpy( fsh->cur_dir, path, path_len );
+ fsh->cur_dir[path_len/sizeof(CHAR)] = TEXT('\0') ;
+ }
+ } else {
+ memcpy( fsh->cur_dir, path, path_len );
+ }
+
+ return ret_val ;
+}
+
+/**/
+/**
+
+ Name: FS_AppendPath()
+
+ Description: This function appends a copy of the passed path to the
+ path in file system handle.
+
+ Modified: 8/10/1989
+
+ Returns: SUCCESS or OUT_OF_MEMORY
+
+ Notes: This function requires that the saved path and the
+ provided path are ASCIIZ strings.
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 FS_AppendPath(
+FSYS_HAND fsh,
+UINT8_PTR path,
+UINT16 path_len ) //size of path buffer in bytes incl NULL term
+{
+ INT16 cb_psize; //string buffer length in bytes incl NULL term
+ CHAR_PTR temp;
+ INT16 ret_val = SUCCESS ;
+
+ cb_psize = (INT16)(strsize(fsh->cur_dir) + path_len + sizeof (CHAR)) ;
+ if ( cb_psize > fsh->leng_dir ) {
+
+ /* previous buffer was too small. so lets allocate a */
+ /* bigger one and throw the old one away. */
+
+ cb_psize = (INT16)((cb_psize / CUR_DIR_CHUNK + sizeof (CHAR) ) * CUR_DIR_CHUNK) ;
+ temp = fsh->cur_dir;
+ fsh->cur_dir = (CHAR_PTR) calloc( 1, cb_psize ) ;
+
+ if ( fsh->cur_dir == NULL ) {
+ fsh->cur_dir = temp ;
+ ret_val = OUT_OF_MEMORY ;
+ } else {
+ strcpy( fsh->cur_dir, temp ) ;
+ strncat( fsh->cur_dir, (CHAR_PTR)path, path_len / sizeof (CHAR) ) ;
+ fsh->leng_dir = cb_psize ;
+ free( temp ) ;
+ }
+ } else {
+ strncat( fsh->cur_dir, (CHAR_PTR)path, path_len / sizeof (CHAR) ) ;
+ }
+
+ return ret_val ;
+}
+
diff --git a/private/utils/ntbackup/src/scanbsd.c b/private/utils/ntbackup/src/scanbsd.c
new file mode 100644
index 000000000..39a47339e
--- /dev/null
+++ b/private/utils/ntbackup/src/scanbsd.c
@@ -0,0 +1,283 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: scanbsd.c
+
+ Description: This file contains code to scan the list of BSDs and
+ read the data associated with them
+
+
+ $Log: M:/LOGFILES/SCANBSD.C_V $
+
+ Rev 1.9.1.0 24 Nov 1993 15:11:46 BARRY
+Unicode fixes
+
+ Rev 1.9 29 Jul 1993 13:27:54 TIMN
+Added a required header
+
+ Rev 1.8 21 Jul 1993 08:56:30 DON
+bsd_matchname function incorrectly defined
+
+ Rev 1.7 20 Jul 1993 11:08:30 MIKEP
+add bsd_findbyname call
+
+ Rev 1.6 19 Jul 1993 10:06:08 BARRY
+Fixes for disappearing DLEs.
+
+ Rev 1.5 22 May 1992 13:35:20 TIMN
+Changed CHAR to INT8
+
+ Rev 1.4 14 Jan 1992 10:24:20 STEVEN
+fix warnings for WIN32
+
+ Rev 1.3 23 Jul 1991 16:19:48 STEVEN
+added BSD_RefreshConfig( )
+
+ Rev 1.2 03 Jul 1991 15:25:50 BRYAN
+Fixed typo in msassert.
+
+ Rev 1.1 29 May 1991 17:21:12 STEVEN
+Re-Design of BSDU for New Fast File Restore
+
+ Rev 1.0 09 May 1991 13:37:12 HUNTER
+Initial revision.
+
+**/
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "queues.h"
+#include "msassert.h"
+
+#include "dle_str.h"
+#include "beconfig.h"
+#include "bsdu.h"
+
+
+typedef struct {
+ UINT32 tape_id ;
+ UINT16 set_num ;
+} TAPE_MATCH_STRUCT, *TAPE_MATCH_STRUCT_PTR ;
+
+static BOOLEAN BSD_MatchDLE( VOID_PTR bsd, VOID_PTR dle ) ;
+static BOOLEAN BSD_MatchName( VOID_PTR bsd, VOID_PTR name ) ;
+static BOOLEAN BSD_MatchTapeID( VOID_PTR bsd, VOID_PTR tap_match ) ;
+static BOOLEAN BSD_MatchSourceDev( VOID_PTR bsd, VOID_PTR src_dev ) ;
+/**/
+/**
+
+ Name: BSD_FindByDLE()
+
+ Description: This function scans through the BSD list looking for
+ the first BSD which points to the specified dle.
+
+ Modified: 8/8/1989
+
+ Returns: The bsd found
+ NULL if BSD not found
+
+ Notes:
+
+ Declaration:
+
+**/
+/* begin declaration */
+BSD_PTR BSD_FindByDLE(
+BSD_HAND bsdh, /* I - BSD list to look through */
+struct GENERIC_DLE *dle ) /* I - DLE to search for */
+{
+ BSD_PTR bsd ;
+
+ bsd = (BSD_PTR)SearchQueue( &(bsdh->current_q_hdr),
+ BSD_MatchDLE,
+ dle,
+ FALSE ) ;
+
+ return( bsd ) ;
+}
+
+/**/
+/**
+
+ Name: BSD_FindByName()
+
+ Description: This function scans through the BSD list looking for
+ the first BSD which points to the specified dle name.
+
+ Modified: 7/20/1993
+
+ Returns: The bsd found
+ NULL if BSD not found
+
+ Notes:
+
+ Declaration:
+
+**/
+/* begin declaration */
+BSD_PTR BSD_FindByName(
+BSD_HAND bsdh, /* I - BSD list to look through */
+CHAR_PTR name ) /* I - name to search for */
+{
+ BSD_PTR bsd ;
+
+ bsd = (BSD_PTR)SearchQueue( &(bsdh->current_q_hdr),
+ BSD_MatchName,
+ name,
+ FALSE ) ;
+
+ return( bsd ) ;
+}
+
+
+
+static BOOLEAN BSD_MatchName(
+VOID_PTR bsd,
+VOID_PTR name )
+{
+ return( !stricmp( name , BSD_GetName( (BSD_PTR)bsd ) ) );
+}
+
+static BOOLEAN BSD_MatchDLE(
+VOID_PTR bsd,
+VOID_PTR dle )
+{
+ return (dle == BSD_GetDLE( (BSD_PTR)bsd ));
+}
+
+/**/
+/**
+
+ Name: BSD_FindByTapeID()
+
+ Description: This function scans through the BSD list looking for
+ the first BSD for the specified tape ID and set number.
+
+ Modified: 8/8/1989
+
+ Returns: The bsd found
+ NULL if BSD not found
+
+ Notes:
+
+ Declaration:
+
+**/
+/* begin declaration */
+BSD_PTR BSD_FindByTapeID(
+BSD_HAND bsdh, /* I - BSD list to look through */
+UINT32 tape_id, /* I - Tape ID to look for */
+UINT16 set_num ) /* I - Set number to look for */
+{
+ TAPE_MATCH_STRUCT tap_match ;
+ BSD_PTR bsd ;
+
+ msassert( bsdh != NULL );
+
+ tap_match.tape_id = tape_id ;
+ tap_match.set_num = set_num ;
+
+ bsd = (BSD_PTR)SearchQueue( &(bsdh->current_q_hdr),
+ BSD_MatchTapeID,
+ &tap_match,
+ FALSE ) ;
+
+ return( bsd ) ;
+}
+
+static BOOLEAN BSD_MatchTapeID(
+VOID_PTR bsd,
+VOID_PTR tap_match )
+{
+ TAPE_MATCH_STRUCT_PTR t_m ;
+ BSD_PTR bsd_ptr ;
+
+ msassert( bsd != NULL );
+ msassert( tap_match != NULL );
+
+ bsd_ptr = (BSD_PTR) bsd ;
+ t_m = (TAPE_MATCH_STRUCT_PTR)tap_match ;
+
+ if ( ( t_m->tape_id == bsd_ptr->tape_id ) &&
+ ( t_m->set_num == (UINT16)bsd_ptr->set_num ) ) {
+
+ return ( TRUE ) ;
+ } else {
+ return( FALSE ) ;
+ }
+}
+
+
+/**/
+/**
+
+ Name: BSD_FindBySourceDevice()
+
+ Description: This function scans through the BSD list looking for
+ the first BSD for the specified SourceDevice.
+
+ Modified: 8/8/1989
+
+ Returns: The bsd found
+ NULL if BSD not found
+
+ Notes:
+
+ Declaration:
+**/
+BSD_PTR BSD_FindBySourceDevice(
+BSD_HAND bsdh, /* I - BSD list to look through */
+VOID_PTR source_dev ) /* I - Soruce Device to look for */
+{
+ BSD_PTR bsd ;
+
+ bsd = (BSD_PTR)SearchQueue( &(bsdh->current_q_hdr),
+ BSD_MatchSourceDev,
+ source_dev,
+ FALSE ) ;
+
+ return( bsd ) ;
+}
+static BOOLEAN BSD_MatchSourceDev(
+VOID_PTR bsd,
+VOID_PTR source_dev )
+{
+ return (INT16)( source_dev == ((BSD_PTR)bsd)->source_dev ) ;
+}
+
+/**/
+/**
+
+ Name: BSD_RefreshConfig()
+
+ Description: This funciton refreshes the config data in all BSDs for
+ the specified BSD handle.
+
+ Modified: 7/23/1991 16:12:3
+
+ Returns:
+
+ Notes:
+
+ Declaration:
+**/
+VOID BSD_RefreshConfig(
+BSD_HAND bsdh,
+struct BE_CFG *conf )
+{
+ BSD_PTR bsd ;
+
+ bsd = BSD_GetFirst( bsdh ) ;
+
+ while ( bsd != NULL ) {
+
+ BEC_UpdateConfig( BSD_GetConfigData( bsd ), conf ) ;
+ bsd = BSD_GetNext( bsd ) ;
+ }
+}
+
+
+
diff --git a/private/utils/ntbackup/src/scomplex.c b/private/utils/ntbackup/src/scomplex.c
new file mode 100644
index 000000000..58b253b24
--- /dev/null
+++ b/private/utils/ntbackup/src/scomplex.c
@@ -0,0 +1,618 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: scomplex.c
+
+ Description: This file contains code to initialize the complex info
+ for an FSE. The complex info includes target path and
+ file names, date selections, and attribute selectios.
+
+
+ $Log: M:/LOGFILES/SCOMPLEX.C_V $
+
+ Rev 1.11 16 Dec 1993 10:20:18 BARRY
+Change INT8_PTRs to VOID_PTRs
+
+ Rev 1.10 18 Jun 1993 09:03:46 MIKEP
+C++ enable
+
+ Rev 1.9 26 May 1992 13:41:50 TIMN
+Added target filename size
+
+ Rev 1.8 19 May 1992 12:57:36 TIMN
+Removed strlen call
+
+ Rev 1.7 14 May 1992 11:56:04 TIMN
+Changed CHARs to INT8
+Changed strcpy to memcpy
+Added file name size to formal parameter lists
+
+ Rev 1.6 14 Jan 1992 10:24:34 STEVEN
+fix warnings for WIN32
+
+ Rev 1.5 18 Dec 1991 11:50:00 DON
+changed mallocs to callocs to avoid using invalid memory...
+
+ Rev 1.4 19 Sep 1991 17:02:28 STEVEN
+fix warning for alloc_size unused
+
+ Rev 1.3 27 Aug 1991 17:30:10 STEVEN
+added BSD target dir support
+
+ Rev 1.2 08 Jul 1991 08:37:16 STEVEN
+did not initialize return value
+
+ Rev 1.1 29 May 1991 17:21:16 STEVEN
+Re-Design of BSDU for New Fast File Restore
+
+ Rev 1.0 09 May 1991 13:36:16 HUNTER
+Initial revision.
+
+**/
+#include <stdlib.h>
+#include <malloc.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "msassert.h"
+#include "std_err.h"
+
+#include "bsdu.h"
+#include "be_debug.h"
+
+static INT16 FSE_SetDate( DATE_TIME_PTR *dptr, DATE_TIME_PTR date ) ;
+static INT16 FSE_AllocCplxInfo( FSE_PTR fse ) ;
+
+/**/
+/**
+
+ Name: FSE_SetTargetInfo()
+
+ Description: This function allocated a target info structure if
+ necessary; then sets the specified attribute information.
+
+ Modified: 5/17/1991 11:24:8
+
+ Returns: SUCCESS or OUT_OF_MEMORY
+
+ Notes:
+
+ See also: $/SEE( BSD_AddFSE( ) )$
+
+ Declaration:
+
+**/
+INT16 FSE_SetTargetInfo(
+FSE_PTR fse, /* I - FSE to set target info for */
+VOID_PTR path, /* I - target path name (NULL Impregnated */
+INT16 psize, /* I - size of target path */
+VOID_PTR fname, /* I - ASCIZ string for target file name */
+INT16 fnsize ) /* I - size of target file name */
+{
+ INT16 alloc_size ;
+ INT16 ret_val = SUCCESS ;
+ FSE_TGT_INFO_PTR tgt ;
+
+ free( fse->tgt ) ;
+
+ alloc_size = (INT16)(sizeof( FSE_TGT_INFO ) + psize) ;
+ if ( fname != NULL ) {
+ alloc_size += fnsize + 1 ;
+ }
+
+ tgt = (FSE_TGT_INFO_PTR)calloc( 1, alloc_size ) ;
+
+ fse->tgt = tgt ;
+
+ if ( tgt != NULL ) {
+ tgt->psize = psize ;
+ tgt->path = tgt + 1;
+ memcpy( tgt->path, path, psize ) ;
+ if ( fname != NULL ) {
+ tgt->fname = (INT8_PTR)tgt->path + psize ;
+ tgt->fnsize = fnsize ;
+ memcpy( tgt->fname, fname, fnsize ) ;
+ }
+ else {
+ tgt->fname = NULL ;
+ tgt->fnsize = 0 ;
+ }
+ } else {
+ ret_val = OUT_OF_MEMORY ;
+ }
+
+ return ret_val ;
+
+}
+/**/
+/**
+
+ Name: FSE_GetTargetInfo()
+
+ Description: returns any target information for the FSE.
+ If no target info exists, then all returns are NULL .
+
+ Modified: 5/17/1991 11:23:58
+
+ Returns: None
+
+ Notes:
+
+ See also: $/SEE( BSD_AddFSE( ) )$
+
+ Declaration:
+
+**/
+VOID FSE_GetTargetInfo(
+FSE_PTR fse, /* I - FSE to set target info for */
+VOID_PTR *path, /* O - target path name (NULL Impregnated */
+INT16 *psize, /* O - size of target path */
+VOID_PTR *fname, /* O - ASCIZ string for target file name */
+INT16 *fnsize ) /* O - size of target file name */
+{
+ FSE_TGT_INFO_PTR tgt = fse->tgt ;
+
+ if ( tgt != NULL ) {
+ *path = tgt->path ;
+ *psize = tgt->psize ;
+ *fname = tgt->fname ;
+ *fnsize = tgt->fnsize ;
+ } else {
+ *path = NULL ;
+ *psize = 0 ;
+ *fname = NULL ;
+ *fnsize = 0 ;
+ }
+}
+/**/
+/**
+
+ Name: BSD_SetTargetInfo()
+
+ Description: This function allocated a target info structure if
+ necessary; then sets the specified attribute information.
+
+ Modified: 5/17/1991 11:24:8
+
+ Returns: SUCCESS or OUT_OF_MEMORY
+
+ Notes:
+
+ See also: $/SEE( BSD_AddFSE( ) )$
+
+ Declaration:
+
+**/
+INT16 BSD_SetTargetInfo(
+BSD_PTR bsd, /* I - BSD to set target info for */
+VOID_PTR path, /* I - target path name (NULL Impregnated */
+INT16 psize ) /* I - size of target path */
+{
+ INT16 ret_val = SUCCESS ;
+ VOID_PTR tgt ;
+
+ free( bsd->target_path ) ;
+ bsd->target_path = NULL ;
+ bsd->tgt_psize = 0 ;
+
+ if ( psize > 1 ) {
+
+ tgt = calloc( 1, psize ) ;
+
+ bsd->target_path = tgt ;
+
+ if ( tgt == NULL ) {
+ psize = 0 ;
+ ret_val = OUT_OF_MEMORY ;
+ } else {
+ memcpy( tgt, path, psize ) ;
+ }
+
+ bsd->tgt_psize = psize ;
+ }
+
+ return ret_val ;
+}
+/**/
+/**
+
+ Name: BSD_GetTargetInfo()
+
+ Description: returns any target information for the BSD.
+ If no target info exists, then all returns are NULL .
+
+ Modified: 5/17/1991 11:23:58
+
+ Returns: None
+
+ Notes:
+
+ See also: $/SEE( BSD_AddFSE( ) )$
+
+ Declaration:
+
+**/
+VOID BSD_GetTargetInfo(
+BSD_PTR bsd, /* I - BSD to set target info for */
+VOID_PTR *path, /* O - target path name (NULL Impregnated */
+INT16 *psize ) /* O - size of target path */
+{
+
+ *path = bsd->target_path ;
+ *psize = bsd->tgt_psize ;
+
+}
+/**/
+/**
+
+ Name: FSE_SetAttribInfo()
+
+ Description: This function allocated a complex info structure if
+ necessary; then sets the specified attribute information.
+
+ Modified: 5/17/1991 11:25:36
+
+ Returns: SUCCESS or OUT_OF_MEMORY
+
+ Notes:
+
+ See also: $/SEE( BSD_AddFSE( ) )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 FSE_SetAttribInfo(
+FSE_PTR fse, /* I - FSE to set attribute info in */
+UINT32 a_on_mask, /* I - bits which must Be set to match */
+UINT32 a_off_mask ) /* I - bits which must be cleared to match */
+{
+ INT16 ret_val ;
+
+ ret_val = FSE_AllocCplxInfo( fse );
+
+ if ( ret_val == SUCCESS ) {
+ fse->cplx->attr_on_mask = a_on_mask ;
+ fse->cplx->attr_off_mask = a_off_mask ;
+ }
+
+ return ret_val ;
+}
+
+/**/
+/**
+
+ Name: FSE_GetAttribInfo()
+
+ Description: returns any attribute information for the FSE.
+ If no complex info exists, then all returns are 0 .
+
+ Modified: 5/17/1991 11:23:58
+
+ Returns: None
+
+ Notes:
+
+ See also: $/SEE( BSD_AddFSE( ) )$
+
+ Declaration:
+
+**/
+VOID FSE_GetAttribInfo(
+FSE_PTR fse, /* I - FSE to set attribute info in */
+UINT32_PTR a_on_mask, /* O - bits which must Be set to match */
+UINT32_PTR a_off_mask ) /* O - bits which must be cleared to match */
+{
+ FSE_COMPLEX_PTR cplx = fse->cplx ;
+
+ if ( cplx != NULL ) {
+ *a_on_mask = cplx->attr_on_mask ;
+ *a_off_mask = cplx->attr_off_mask ;
+ } else {
+ *a_on_mask = 0 ;
+ *a_off_mask = 0 ;
+ }
+}
+
+/**/
+/**
+
+ Name: FSE_SetModDate()
+
+ Description: This function allocated a complex info structure if
+ necessary; then allocates a date time structure if necessary;
+ then sets the date time fields approprately ;
+
+ Modified: 5/17/1991 12:12:32
+
+ Returns: SUCCESS or OUT_OF_MEMORY
+
+ Notes: if you wish to not specify one of the dates,
+ simply pass NULL, You may also pass an invalid date.
+
+ See also: $/SEE( BSD_AddFSE( ) )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 FSE_SetModDate(
+FSE_PTR fse, /* I - FSE to set the Modification dates in */
+DATE_TIME_PTR pre, /* I - The Before modification date */
+DATE_TIME_PTR post ) /* I - The After modification date */
+{
+ INT16 ret_val ;
+ FSE_COMPLEX_PTR cplx ;
+
+ ret_val = FSE_AllocCplxInfo( fse );
+
+ cplx = fse->cplx ;
+
+ if ( ret_val == SUCCESS ) {
+ ret_val = FSE_SetDate( &cplx->pre_m_date, pre ) ;
+
+ if ( ret_val == SUCCESS ) {
+ ret_val = FSE_SetDate( &cplx->post_m_date, post ) ;
+ if ( ret_val != SUCCESS ) {
+ free( &cplx->pre_m_date ) ;
+ }
+ }
+ }
+
+ return ret_val ;
+}
+
+/**/
+/**
+
+ Name: FSE_GetModDate()
+
+ Description: This function returns any modification date information
+ for the specified FSE. If no Complex information exists,
+ then both return date are NULL .
+
+ Modified: 5/17/1991 12:12:32
+
+ Returns: None
+
+ Notes:
+
+ See also: $/SEE( BSD_AddFSE( ) )$
+
+ Declaration:
+
+**/
+VOID FSE_GetModDate(
+FSE_PTR fse, /* I - The FSE to get the date from */
+DATE_TIME_PTR *pre, /* O - The before date */
+DATE_TIME_PTR *post ) /* O - The after date */
+{
+ FSE_COMPLEX_PTR cplx = fse->cplx ;
+
+ if ( cplx != NULL ) {
+ *pre = cplx->pre_m_date ;
+ *post = cplx->post_m_date ;
+ } else {
+ *pre = NULL ;
+ *post = NULL ;
+ }
+}
+
+/**/
+/**
+
+ Name: FSE_SetAccDate()
+
+ Description: This function allocated a complex info structure if
+ necessary; then allocates a date time structure if necessary;
+ then sets the date time fields approprately ;
+
+ Modified: 5/17/1991 12:17:10
+
+ Returns: SUCCESS or OUT_OF_MEMORY
+
+ Notes:
+
+ See also: $/SEE( BSD_AddFSE( ) )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 FSE_SetAccDate(
+FSE_PTR fse, /* I - The FSE to set the access date in */
+DATE_TIME_PTR pre ) /* I - The new access date */
+{
+ INT16 ret_val ;
+
+ ret_val = FSE_AllocCplxInfo( fse );
+
+ if ( ret_val == SUCCESS ) {
+ ret_val = FSE_SetDate( &fse->cplx->access_date, pre ) ;
+ }
+
+ return ret_val ;
+}
+
+/**/
+/**
+
+ Name: FSE_GetAccDate()
+
+ Description: This function gets the access date information from the
+ specified FSE. If no complex info exist for the FSE then
+ a NULL date is returned.
+
+ Modified: 5/17/1991 12:17:10
+
+ Returns: None
+
+ Notes:
+
+ See also: $/SEE( BSD_AddFSE( ) )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+
+VOID FSE_GetAccDate(
+FSE_PTR fse, /* I - The FSE to get the date from */
+DATE_TIME_PTR *pre ) /* O - The access date */
+{
+ if ( fse->cplx != NULL ) {
+ *pre = fse->cplx->access_date ;
+ } else {
+ *pre = NULL ;
+ }
+}
+
+/**/
+/**
+
+ Name: FSE_SetBakDate()
+
+ Description: This function allocated a complex info structure if
+ necessary; then allocates a date time structure if necessary;
+ then sets the date time fields approprately ;
+
+ Modified: 5/17/1991 12:19:41
+
+ Returns: SUCCESS or OUT_OF_MEMORY
+
+ Notes:
+
+ See also: $/SEE( BSD_AddFSE( ) )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 FSE_SetBakDate(
+FSE_PTR fse, /* I - The FSE to set the backup date in */
+DATE_TIME_PTR pre ) /* I - The backup date */
+{
+ INT16 ret_val ;
+
+ ret_val = FSE_AllocCplxInfo( fse );
+
+ if ( ret_val == SUCCESS ) {
+ ret_val = FSE_SetDate( &fse->cplx->backup_date, pre ) ;
+ }
+
+ return ret_val ;
+}
+/**/
+/**
+
+ Name: FSE_GetBakDate()
+
+ Description: This function returns the Backup date stored in the FSE.
+ If there is no complex info for the FSE the backup date
+ returned is NULL.
+
+ Modified: 5/17/1991 12:17:10
+
+ Returns: None
+
+ Notes:
+
+ See also: $/SEE( BSD_AddFSE( ) )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID FSE_GetBakDate(
+FSE_PTR fse, /* I - The FSE to get the date from */
+DATE_TIME_PTR *pre ) /* O - The backup date */
+{
+ if ( fse->cplx != NULL ) {
+ *pre = fse->cplx->backup_date ;
+ } else {
+ *pre = NULL ;
+ }
+}
+
+/**/
+/**
+
+ Name: FSE_AllocCplxInfo()
+
+ Description: This is a private function which will allocate a
+ Complex Info structure if necessary.
+
+ Modified: 5/17/1991 12:23:35
+
+ Returns: SUCCESS or OUT_OF_MEMORY
+
+ Notes:
+
+ See also: $/SEE( BSD_AddFSE( ) )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+static INT16 FSE_AllocCplxInfo(
+FSE_PTR fse )
+{
+ if ( fse->cplx == NULL ) {
+ fse->cplx = (FSE_COMPLEX_PTR)calloc( 1, sizeof ( FSE_COMPLEX ) ) ;
+ }
+
+ if ( fse->cplx == NULL ) {
+ return OUT_OF_MEMORY ;
+ }
+
+ return SUCCESS ;
+}
+
+/**/
+/**
+
+ Name: FSE_SetDate()
+
+ Description: This is a private function which will allocate a
+ date_time structure and set the date.
+
+ Modified: 5/17/1991 12:23:35
+
+ Returns: SUCCESS or OUT_OF_MEMORY
+
+ Notes:
+
+ See also: $/SEE( BSD_AddFSE( ) )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+static INT16 FSE_SetDate(
+DATE_TIME_PTR *d_ptr,
+DATE_TIME_PTR date )
+{
+ INT16 ret_val = SUCCESS ;
+
+ if ( ( date == NULL ) || !date->date_valid ) {
+ free (*d_ptr ) ;
+ *d_ptr = NULL ;
+
+ } else if ( *d_ptr == NULL ) {
+ *d_ptr = (DATE_TIME_PTR)calloc( 1, sizeof( DATE_TIME ) ) ;
+
+ } else {
+ ret_val = OUT_OF_MEMORY ;
+ }
+
+ if ( *d_ptr != NULL ) {
+ **d_ptr = *date ;
+ }
+
+ return ret_val ;
+}
+
+
+
+
diff --git a/private/utils/ntbackup/src/sdisk.bmp b/private/utils/ntbackup/src/sdisk.bmp
new file mode 100644
index 000000000..a5d35a043
--- /dev/null
+++ b/private/utils/ntbackup/src/sdisk.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/set_dbug.dlg b/private/utils/ntbackup/src/set_dbug.dlg
new file mode 100644
index 000000000..864645eff
--- /dev/null
+++ b/private/utils/ntbackup/src/set_dbug.dlg
@@ -0,0 +1,43 @@
+
+IDD_SETTINGSDEBUGWINDOW DIALOG 27, 28, 255, 133
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Debug Window Settings"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "Window", 0xFFFF, 2, 2, 85, 124
+ CONTROL "Record to &window", IDD_DB_TOWIN, "Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP, 7, 16, 75, 10
+ RADIOBUTTON "Record &last", IDD_DB_RLAST, 7, 34, 57, 10
+ EDITTEXT IDD_DB_RNUM, 64, 34, 19, 12, ES_AUTOHSCROLL
+ LTEXT "messages", IDD_DB_M, 17, 48, 41, 8
+ RADIOBUTTON "Record &all messages", IDD_DB_RALL, 6, 64, 78, 10
+ LTEXT "Messages:", 0x006B, 5, 84, 42, 8
+ LTEXT "", IDD_DB_WMSGS, 50, 84, 20, 8, SS_NOPREFIX
+ PUSHBUTTON "&Reset Window", IDD_DB_RMEM, 11, 101, 64, 14
+ GROUPBOX "File", 0xFFFF, 96, 2, 108, 77
+ CONTROL "Record to &file", IDD_DB_TOFILE, "Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP, 102, 15, 70, 10
+ LTEXT "File &name:", IDD_DB_FNAMELABEL, 102, 31, 35, 8
+ EDITTEXT IDD_DB_FNAME, 138, 29, 59, 12, ES_AUTOHSCROLL
+ LTEXT "Messages:", 0x006C, 102, 47, 42, 8
+ LTEXT "", IDD_DB_FMSGS, 146, 47, 18, 8, SS_NOPREFIX
+ PUSHBUTTON "R&eset File", IDD_DB_RFILE, 114, 61, 70, 14
+ GROUPBOX "Options", 0xFFFF, 96, 86, 108, 40
+ CONTROL "Display &memory trace", IDD_DB_MEMTRACE, "Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP, 103, 99, 98, 10
+ CONTROL "Enable &poll drive", IDD_DB_POLLDRIVEON, "Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP, 103, 111, 95, 10
+ DEFPUSHBUTTON "OK", IDOK, 213, 6, 40, 14
+ PUSHBUTTON "Cancel", IDCANCEL, 213, 26, 40, 14
+ DEFPUSHBUTTON "&Help", IDHELP, 213, 46, 40, 14
+
+# ifndef OEM_MSOFT //no shadows allowed in OEM version
+ CONTROL "", 0xFFFF, "Static", SS_BLACKRECT, 87, 10, 3, 119
+ CONTROL "", 0xFFFF, "Static", SS_BLACKRECT, 204, 10, 3, 72
+ CONTROL "", 0xFFFF, "Static", SS_BLACKRECT, 99, 79, 106, 3
+ CONTROL "", 0xFFFF, "Static", SS_BLACKRECT, 204, 94, 2, 35
+ CONTROL "", 0xFFFF, "Static", SS_BLACKRECT, 5, 126, 84, 3
+ CONTROL "", 0xFFFF, "Static", SS_BLACKRECT, 99, 126, 107, 3
+# endif //OEM_MSOFT //no shadows allowed in OEM version
+
+END
diff --git a/private/utils/ntbackup/src/skipno.c b/private/utils/ntbackup/src/skipno.c
new file mode 100644
index 000000000..c20349128
--- /dev/null
+++ b/private/utils/ntbackup/src/skipno.c
@@ -0,0 +1,133 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: SKIPNO.C
+
+ Description:
+
+ $Log: G:\UI\LOGFILES\SKIPNO.C_V $
+
+ Rev 1.1 28 Jan 1994 17:22:36 Glenn
+Simplified and fixed Icon support.
+
+ Rev 1.0 13 Jul 1993 17:04:28 CARLS
+Initial revision
+
+*****************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+/***************************************************
+
+ Name: DM_StartSkipNo
+
+ Description:
+
+ Returns: Returns the status from the dialog.
+
+*****************************************************/
+INT DM_StartSkipNo( )
+{
+ INT16 status ;
+
+ status = DM_ShowDialog( ghModelessDialog, IDD_SKIPNO, NULL ) ;
+
+ return( status ) ;
+}
+/***************************************************
+
+ Name: DM_SkipNo
+
+ Description:
+
+ Returns:
+
+*****************************************************/
+DLGRESULT APIENTRY DM_SkipNo(
+HWND hDlg , /* window handle of the dialog box */
+MSGID message , /* type of message */
+MP1 mp1 , /* message-specific information */
+MP2 mp2
+)
+{
+ PAINTSTRUCT ps;
+ HDC hDC;
+ HDC hDCBitmap;
+ HWND hWnd;
+ HICON hIcon;
+ WORD answer ;
+
+ UNREFERENCED_PARAMETER ( mp2 );
+
+ switch ( message )
+ {
+ case WM_INITDIALOG: /* message: initialize dialog box */
+
+ DM_CenterDialog( hDlg );
+
+ hIcon = LoadIcon( 0, IDI_EXCLAMATION );
+ SendDlgItemMessage ( hDlg, IDD_SKIPNO_BITMAP, STM_SETICON, (MP1)hIcon, 0L );
+
+ SetDlgItemText( hDlg, IDD_SKIPNO_TEXT, gszTprintfBuffer );
+
+ return ( TRUE );
+
+ case WM_COMMAND: /* message: received a command */
+ switch( GET_WM_COMMAND_ID ( mp1, mp2 ) )
+ {
+/****************************************************************************
+ Yes button
+/***************************************************************************/
+ case IDD_SKIPNO_YES:
+ EndDialog( hDlg, SKIPNO_YES_BUTTON ); /* Exits the dialog box */
+ break;
+/****************************************************************************
+ Yes to all button
+/***************************************************************************/
+ case IDD_SKIPNO_ALL:
+ EndDialog( hDlg, SKIPNO_YES_TO_ALL_BUTTON ); /* Exits the dialog box */
+ break;
+/****************************************************************************
+ No button
+/***************************************************************************/
+ case IDD_SKIPNO_NO:
+ EndDialog( hDlg, SKIPNO_NO_BUTTON ); /* Exits the dialog box */
+ break;
+/****************************************************************************
+ Cancel button
+/***************************************************************************/
+ case IDD_SKIPNO_CANCEL:
+ case IDCANCEL:
+
+ /* Ask the user if an abort is really what they want? */
+
+ answer = (WORD)WM_MsgBox( ID( RES_ABORT_STRING ),
+ ID( RES_ABORT_QUESTION ),
+ (WORD)WMMB_YESNO, (WORD)WMMB_ICONQUESTION );
+ if( answer == WMMB_IDYES) {
+
+ yresprintf( (INT16) RES_PROCESS_ABORTED );
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ lresprintf( (INT16) LOGGING_FILE ,
+ (INT16) LOG_MSG ,
+ SES_ENG_MSG ,
+ RES_PROCESS_ABORTED );
+
+ EndDialog( hDlg, SKIPNO_CANCEL_BUTTON ); /* Exits the dialog box */
+
+ }
+ return ( TRUE );
+ break;
+
+ }
+ break;
+ }
+ return ( FALSE ); /* Didn't process a message */
+}
+
diff --git a/private/utils/ntbackup/src/skipno.dlg b/private/utils/ntbackup/src/skipno.dlg
new file mode 100644
index 000000000..19c5bd9b3
--- /dev/null
+++ b/private/utils/ntbackup/src/skipno.dlg
@@ -0,0 +1,12 @@
+IDD_SKIPNO DIALOG 12, 43, 254, 61
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Skip Open File"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ ICON 0, IDD_SKIPNO_BITMAP, 8, 6, 20, 20
+ LTEXT "", IDD_SKIPNO_TEXT, 33, 6, 220, 33, SS_NOPREFIX
+ DEFPUSHBUTTON "&Yes", IDD_SKIPNO_YES, 15, 44, 44, 14
+ PUSHBUTTON "&No", IDD_SKIPNO_NO, 135, 44, 44, 14
+ PUSHBUTTON "Yes to &ALL", IDD_SKIPNO_ALL, 75, 44, 44, 14
+ PUSHBUTTON "&Cancel", IDD_SKIPNO_CANCEL, 194, 44, 44, 14
+END
diff --git a/private/utils/ntbackup/src/skipopen.c b/private/utils/ntbackup/src/skipopen.c
new file mode 100644
index 000000000..ccbb0bafa
--- /dev/null
+++ b/private/utils/ntbackup/src/skipopen.c
@@ -0,0 +1,235 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: SKIPOPEN.C
+
+ Description: Skip open files dialog.
+
+ $Log: G:\UI\LOGFILES\SKIPOPEN.C_V $
+
+ Rev 1.15 28 Jan 1994 14:50:40 MIKEP
+fix if file goes away while we're waiting
+
+ Rev 1.14 27 Jul 1993 14:35:02 CARLS
+changed timer routine to use elapsed time
+
+ Rev 1.13 14 May 1993 15:24:30 CARLS
+check for open file in the timer function
+
+ Rev 1.12 01 Nov 1992 16:07:56 DAVEV
+Unicode changes
+
+ Rev 1.11 07 Oct 1992 13:44:18 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.10 04 Oct 1992 19:40:44 DAVEV
+Unicode Awk pass
+
+ Rev 1.9 28 Jul 1992 14:49:30 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.8 14 May 1992 16:40:16 MIKEP
+Nt pass 2
+
+ Rev 1.7 27 Jan 1992 12:50:10 GLENN
+Changed dialog support calls.
+
+ Rev 1.6 22 Jan 1992 14:53:02 JOHNWT
+fixed last fix
+
+ Rev 1.5 20 Jan 1992 09:35:12 CARLS
+added a call to DM_CenterDialog
+
+ Rev 1.4 09 Jan 1992 18:25:26 DAVEV
+16/32 bit port 2nd pass
+
+ Rev 1.3 20 Dec 1991 16:55:00 JOHNWT
+return ghModelessDialog
+
+ Rev 1.2 18 Dec 1991 11:33:46 JOHNWT
+changed ghModelessDialog to ghRuntimeDialog
+
+ Rev 1.1 26 Nov 1991 17:27:06 DAVEV
+16/32 bit Windows port changes
+
+ Rev 1.0 20 Nov 1991 19:34:26 SYSTEM
+Initial revision.
+
+*****************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+static VOID clock_routine( VOID );
+
+struct skipopen_temp {
+ WORD dialog_return_status;
+ WORD wait_time;
+ HTIMER timer_handle;
+ HWND ghDlg; /* global window handle of the dialog box */
+ CHK_OPEN TryOpen;
+ UINT32 parm;
+ INT status;
+ time_t stop_time ;
+};
+
+static struct skipopen_temp *skip_temp_ptr;
+
+/***************************************************
+
+ Name: DM_StartSkipOpen()
+
+ Description: Starts the Skip Open files dialog
+
+ Returns: Returns the status from the dialog.
+
+*****************************************************/
+INT DM_StartSkipOpen( CHK_OPEN TryOpen, UINT32 parm )
+{
+INT status;
+struct skipopen_temp temp_data;
+
+ skip_temp_ptr = &temp_data;
+ skip_temp_ptr->TryOpen = TryOpen ;
+ skip_temp_ptr->parm = parm ;
+ skip_temp_ptr->status = ~SUCCESS ;
+ time( &skip_temp_ptr->stop_time ) ;
+
+ status = (INT16)DM_ShowDialog( ghModelessDialog, IDD_SKIPOPEN, NULL );
+
+ return( skip_temp_ptr->status );
+}
+/***************************************************
+
+ Name: DM_SkipOpen()
+
+ Description: Skip open files dialog procedure
+
+ Returns:
+
+*****************************************************/
+DLGRESULT APIENTRY DM_SkipOpen(
+ HWND hDlg , /* window handle of the dialog box */
+ MSGID message , /* type of message */
+ MP1 mp1 , /* message-specific information */
+ MP2 mp2
+)
+{
+ CDS_PTR cds_ptr;
+
+ CHAR buffer[20] ;
+ INT16 error ;
+ time_t current_time ;
+ time_t elapsed_time ;
+
+ UNREFERENCED_PARAMETER ( mp2 );
+ switch ( message )
+ {
+ case WM_INITDIALOG: /* message: initialize dialog box */
+
+ DM_CenterDialog( hDlg );
+
+ SetDlgItemText( hDlg, IDD_SKIP_FILE_NAME, gszTprintfBuffer );
+
+ /* save the handle to this window */
+ skip_temp_ptr->ghDlg = hDlg;
+
+ cds_ptr = CDS_GetCopy();
+
+ /* get the skip wait time */
+ skip_temp_ptr->wait_time = CDS_GetWaitTime( cds_ptr );
+ skip_temp_ptr->stop_time += skip_temp_ptr->wait_time ;
+
+ time( &current_time ) ;
+ elapsed_time = skip_temp_ptr->stop_time - current_time ;
+ if( elapsed_time >= 1 ) {
+ wsprintf( buffer, TEXT("%d"), elapsed_time ) ;
+
+ /* display the remaining time until we skip this file */
+ SetDlgItemText( skip_temp_ptr->ghDlg, IDD_SKIP_OPEN_WAIT_TIME, buffer ) ;
+ }
+
+ /* save the handle to the timer */
+ skip_temp_ptr->timer_handle = WM_HookTimer( clock_routine, 1 );
+
+ return (TRUE);
+
+ case WM_COMMAND: /* message: received a command */
+ switch( GET_WM_COMMAND_ID ( mp1, mp2 ) )
+ {
+/****************************************************************************
+ Cancel button
+/***************************************************************************/
+ case IDD_SKIP_CANCEL_BUTTON:
+ case IDCANCEL:
+
+ skip_temp_ptr->dialog_return_status = TRUE;
+
+ /* release the timer */
+ WM_UnhookTimer( skip_temp_ptr->timer_handle );
+
+ EndDialog(hDlg, FALSE); /* Exits the dialog box */
+
+ return (TRUE);
+ break;
+
+ }
+ break;
+ }
+ return (FALSE); /* Didn't process a message */
+}
+
+/***************************************************
+
+ Name: clock_routine()
+
+ Description: Skip Open files timer
+
+ Returns: void
+
+*****************************************************/
+static VOID clock_routine( VOID )
+{
+ CHAR buffer[20] ;
+ INT16 error ;
+ time_t current_time ;
+ time_t elapsed_time ;
+
+ time( &current_time ) ;
+ elapsed_time = skip_temp_ptr->stop_time - current_time ;
+ if( elapsed_time >= 1 ) {
+ wsprintf( buffer, TEXT("%d"), elapsed_time ) ;
+
+ /* display the remaining time until we skip this file */
+ SetDlgItemText( skip_temp_ptr->ghDlg, IDD_SKIP_OPEN_WAIT_TIME, buffer ) ;
+ }
+
+ if( current_time >= skip_temp_ptr->stop_time ) {
+
+ skip_temp_ptr->dialog_return_status = TRUE ;
+
+ /* release the timer */
+ WM_UnhookTimer( skip_temp_ptr->timer_handle ) ;
+
+ EndDialog(skip_temp_ptr->ghDlg, FALSE) ; /* close the dialog box */
+ }
+
+ /* try to open the file */
+ error = skip_temp_ptr->TryOpen( skip_temp_ptr->parm ) ;
+
+ if ( error == SUCCESS || error == FS_NOT_FOUND || error == FS_OPENED_INUSE ) {
+
+ /* the file was opened, set the return status */
+ skip_temp_ptr->status = error;
+
+ /* release the timer */
+ WM_UnhookTimer( skip_temp_ptr->timer_handle ) ;
+
+ EndDialog(skip_temp_ptr->ghDlg, FALSE) ; /* close the dialog box */
+ }
+
+}
diff --git a/private/utils/ntbackup/src/skipopen.dlg b/private/utils/ntbackup/src/skipopen.dlg
new file mode 100644
index 000000000..a9119e208
--- /dev/null
+++ b/private/utils/ntbackup/src/skipopen.dlg
@@ -0,0 +1,33 @@
+/**************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+
+ Name: skipopen.dlg
+
+ Description: This file contains a dialog template.
+
+ $Log: G:/UI/LOGFILES/SKIPOPEN.DLV $
+
+ Rev 1.3 18 Dec 1992 11:22:56 chrish
+ Moved #include to dialogs.rc
+
+ Rev 1.2 06 Apr 1992 07:36:56 CARLS
+ added DLGINCLUDE
+
+ Rev 1.1 27 Jan 1992 00:43:08 CHUCKB
+ Updated dialog id's.
+
+ Rev 1.0 20 Nov 1991 19:19:06 SYSTEM
+ Initial revision.
+
+**************************************************************************/
+
+IDD_SKIPOPEN DIALOG 53, 67, 186, 50
+CAPTION "Skip Open Files Wait Time"
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+BEGIN
+ CONTROL "", IDD_SKIP_OPEN_WAIT_TIME, "STATIC", SS_RIGHT | WS_GROUP, 39, 19, 26, 8
+ CONTROL "seconds remaining", -1, "STATIC", SS_LEFT | WS_GROUP, 71, 19, 80, 8
+ CONTROL "Cancel", IDD_SKIP_CANCEL_BUTTON, "BUTTON", BS_DEFPUSHBUTTON | WS_TABSTOP, 71, 33, 39, 14
+ CONTROL "", IDD_SKIP_FILE_NAME, "STATIC", SS_CENTER | WS_GROUP, 7, 5, 173, 8
+END
+ \ No newline at end of file
diff --git a/private/utils/ntbackup/src/sleepwin.c b/private/utils/ntbackup/src/sleepwin.c
new file mode 100644
index 000000000..c1f61edaa
--- /dev/null
+++ b/private/utils/ntbackup/src/sleepwin.c
@@ -0,0 +1,85 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-91
+
+
+ Name: sleepwin.c
+
+ Description: This function loops until the specified
+ number of thousandths of a second have
+ elapsed.
+
+ Note: Thousandths of seconds are used instead
+ of timer ticks so that this function
+ could be ported easily to other machines
+ or operating systems.
+
+
+ $Log: L:/LOGFILES/SLEEPWIN.C_V $
+
+ Rev 1.4 18 Aug 1992 10:06:36 BURT
+fix warnings
+
+ Rev 1.3 23 Jul 1992 12:15:20 STEVEN
+fix warnings
+
+ Rev 1.2 28 Oct 1991 13:53:18 STEVEN
+remove WM_MultiTask() prototype
+
+ Rev 1.1 18 Sep 1991 10:28:58 GREGG
+Added 'killtimer' function.
+
+ Rev 1.0 21 Jun 1991 13:12:52 STEVEN
+Initial revision.
+
+**/
+/* begin include list */
+
+#include <windows.h>
+
+#include "stdtypes.h"
+#include "sleep.h"
+/* $end$ include list */
+
+extern HANDLE ghInst ;
+
+WORD FAR PASCAL TimerFunc( HWND hwind, WORD msg, INT16 event, DWORD time ) ;
+
+static BOOLEAN mw_time_up ;
+
+VOID sleep( UINT32 thousandths )
+{
+ UINT16 loop_cnt ;
+ WORD hTimerInst;
+ static FARPROC pfTimerFunc = (FARPROC)0 ;
+
+ if ( ! pfTimerFunc ) {
+ pfTimerFunc = (FARPROC)MakeProcInstance( TimerFunc, ghInst ) ;
+ }
+
+ loop_cnt = (UINT16)(thousandths >> 16);
+
+ hTimerInst = SetTimer ( (HWND)NULL, 0, (UINT16)thousandths, (TIMERPROC)pfTimerFunc );
+
+ do {
+ mw_time_up = FALSE ;
+
+ if ( hTimerInst ) {
+ while( ! mw_time_up ) {
+ WM_MultiTask ();
+ }
+ }
+
+ } while( loop_cnt-- != 0 );
+
+ KillTimer ( (HWND)NULL, hTimerInst );
+}
+
+WORD FAR PASCAL TimerFunc(
+HWND hwind,
+WORD msg,
+INT16 event,
+DWORD time )
+{
+ mw_time_up = TRUE ;
+ return 0 ;
+}
diff --git a/private/utils/ntbackup/src/sources b/private/utils/ntbackup/src/sources
new file mode 100644
index 000000000..466bad038
--- /dev/null
+++ b/private/utils/ntbackup/src/sources
@@ -0,0 +1,392 @@
+#
+# Build SOURCES file for Nostradamus -- Microsoft's NTBACKUP application.
+#
+
+MAJORCOMP=utils
+MINORCOMP=ntbackup
+
+TARGETNAME=ntbackup
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+USE_CRTDLL=1
+#
+# If MSUNICODE is defined, a Unicode application will be built; otherwise
+# an ASCII version will be built.
+#
+# If MSDEBUG is not defined, we will build an application without msasserts.
+# If MSDEBUG is defined, we will build with memory manager debug code
+# and msasserts (with strings).
+# (For now, memory debug code is enabled only on x86 machines -- it
+# doesn't seem to work on MIPS/Alpha.)
+#
+# IMPORTANT!:
+# This SOURCES file also defines CONNER_SOFTWARE_BUILD. This places our
+# own E.R. and other info in the about box. This must not be checked in
+# literally at Microsoft.
+#
+
+PRODUCT_OPTIONS=-DOEM_EMS -DOEM_MSOFT -DMY40_TRANS -DMY31_TRANS -DSYPL10_TRANS -DNTKLUG
+
+OS_OPTIONS=-D_WIN32_ -DWIN32 -DOS_WIN32
+
+DEBUG_OPTIONS=-DMS_RELEASE
+
+UNICODE_OPTION=-DUNICODE
+
+FSYS=-DFS_NTFS -DFS_EMS
+
+#############################################################################
+
+!IF ("$(TDCOMMON)"=="")||("$(MBUDEV)"=="")
+INCLUDES=..\inc;..\exchange\inc;..\..\..\inc
+!ELSE
+INCLUDES=..\inc;..\exchange\build\inc;$(TDCOMMON)\inc;$(MBUDEV)\inc32;$(MBUDEV)\inc32\sys
+!ENDIF
+
+SOURCES= \
+ addbsd.c \
+ addfse.c \
+ addlba.c \
+ atachdle.c \
+ att_drv.c \
+ back_dle.c \
+ back_obj.c \
+ back_vcb.c \
+ be_debug.c \
+ be_dinit.c \
+ be_init.c \
+ be_tfutl.c \
+ bec_init.c \
+ bec_mem.c \
+ bec_misc.c \
+ bsdlasto.c \
+ bsdmatch.c \
+ bsdsinfo.c \
+ bsdthw.c \
+ buffman.c \
+ buffnt.c \
+ checksum.c \
+ clearfsl.c \
+ cli_stub.c \
+ confmisc.c \
+ critstub.c \
+ ctbrkstb.c \
+ d_about.c \
+ d_adv_us.c \
+ d_attach.c \
+ d_browse.c \
+ d_ctape.c \
+ d_date.c \
+ d_dbug.c \
+ d_erase.c \
+ d_o_bkup.c \
+ d_o_rset.c \
+ d_r_path.c \
+ d_t_pswd.c \
+ d_v_path.c \
+ datetime.c \
+ dateutil.c \
+ dblksize.c \
+ ddeproc.c \
+ debug.c \
+ defchan.c \
+ defltblk.c \
+ details.c \
+ detfmt.c \
+ dettpdrv.c \
+ dialmang.c \
+ dilnttp.c \
+ dilntmsc.c \
+ dledelet.c \
+ dleget.c \
+ dlereset.c \
+ dleupdat.c \
+ dlg_util.c \
+ dlm_draw.c \
+ dlm_init.c \
+ dlm_lbn.c \
+ dlm_proc.c \
+ dlm_scrn.c \
+ dlm_updt.c \
+ do_back.c \
+ do_cat.c \
+ do_del.c \
+ do_excl.c \
+ do_ffr.c \
+ do_misc.c \
+ do_next.c \
+ do_rest.c \
+ do_tens.c \
+ do_very.c \
+ docproc.c \
+ drives.c \
+ enc_tab.c \
+ encrypt.c \
+ eprintf.c \
+ erase.c \
+ filgetc.c \
+ fmttab.c \
+ font.c \
+ freplace.c \
+ frmproc.c \
+ fsecopy.c \
+ func_tab.c \
+ gen_tab.c \
+ gendblk.c \
+ get_vcb.c \
+ getres.c \
+ getstrm.c \
+ ginitfs.c \
+ global.c \
+ gmkdblk.c \
+ gmoddblk.c \
+ gname.c \
+ gsize.c \
+ gtnxtdle.c \
+ gtnxttpe.c \
+ gui.c \
+ helpmang.c \
+ hwcheck.c \
+ hwconfnt.c \
+ initfsys.c \
+ log.c \
+ logoproc.c \
+ lp_tdir.c \
+ lp_tens.c \
+ lpbackup.c \
+ lpdelete.c \
+ lplist.c \
+ lprestor.c \
+ lprintf.c \
+ lptools.c \
+ lptpcat.c \
+ lpverify.c \
+ lw_data.c \
+ lwtfinf.c \
+ mach_nt.c \
+ makecfdb.c \
+ makeudb.c \
+ makevcb.c \
+ mayn31rd.c \
+ mayn40rd.c \
+ mtf10wt.c \
+ mtf10wdb.c \
+ memang32.c \
+ memver.c \
+ menumang.c \
+ winassrt.c \
+ msgbox.c \
+ msmktemp.c \
+ mui.c \
+ muiconf.c \
+ muiutil.c \
+ myn40otc.c \
+ nothing.c \
+ ntfs_tab.c \
+ ntfslink.c \
+ ntfsregy.c \
+ ntfstemp.c \
+ ntfsutil.c \
+ ombatch.c \
+ omevent.c \
+ ommuibar.c \
+ openbsdu.c \
+ opensys.c \
+ otc40rd.c \
+ otc40wt.c \
+ otc40msc.c \
+ parspath.c \
+ passdb.c \
+ password.c \
+ polldrv.c \
+ posatset.c \
+ pwxface.c \
+ qtc_add.c \
+ qtc_back.c \
+ qtc_bset.c \
+ qtc_eom.c \
+ qtc_init.c \
+ qtc_srch.c \
+ qtc_util.c \
+ qtcxface.c \
+ queues.c \
+ tfread.c \
+ resmang.c \
+ rest_dle.c \
+ rest_obj.c \
+ ribproc.c \
+ runtime.c \
+ savepath.c \
+ scanbsd.c \
+ scomplex.c \
+ skipno.c \
+ skipopen.c \
+ sleepwin.c \
+ statline.c \
+ stats.c \
+ stdmath.c \
+ stdwcs.c \
+ stubfunc.c \
+ sx.c \
+ sypl10rd.c \
+ tattach.c \
+ tbdpars.c \
+ tbgetc.c \
+ tbnextok.c \
+ tbpdat.c \
+ tbprocsw.c \
+ tbrparse.c \
+ tchgdir.c \
+ tclose.c \
+ tcomplet.c \
+ tcreate.c \
+ tdelete.c \
+ tfbuffs.c \
+ tfclose.c \
+ tfeject.c \
+ tfinit.c \
+ tflutils.c \
+ tfopen.c \
+ tfpoll.c \
+ tfreten.c \
+ tfrewind.c \
+ tfstuff.c \
+ tftpcat.c \
+ tgetinfo.c \
+ tgetnext.c \
+ tgetpath.c \
+ tgetspec.c \
+ timers.c \
+ tinitfs.c \
+ tminddb.c \
+ tmkdblk.c \
+ tmoddblk.c \
+ tname.c \
+ topen.c \
+ tposmisc.c \
+ tprintf.c \
+ translat.c \
+ transutl.c \
+ treadobj.c \
+ tseekobj.c \
+ tsetinfo.c \
+ tsize.c \
+ tverinfo.c \
+ tverobj.c \
+ twritobj.c \
+ uadd_dle.c \
+ unicode.c \
+ unitinit.c \
+ very_dle.c \
+ very_obj.c \
+ viewproc.c \
+ vlm_bset.c \
+ vlm_cat.c \
+ vlm_disk.c \
+ vlm_file.c \
+ vlm_find.c \
+ vlm_init.c \
+ vlm_menu.c \
+ vlm_poll.c \
+ vlm_refr.c \
+ vlm_srch.c \
+ vlm_srv.c \
+ vlm_strt.c \
+ vlm_tape.c \
+ vlm_tree.c \
+ vlm_util.c \
+ vmstubs.c \
+ winmang.c \
+ tfwrite.c \
+ writescr.c \
+ yprintf.c \
+ zprintf.c \
+ xinitfs.c \
+ ems_tab.c \
+ d_o_xchg.c \
+ xattach.c \
+ xmoddblk.c \
+ xgetnext.c \
+ xgetpath.c \
+ xname.c \
+ xsize.c \
+ xchgdir.c \
+ xopen.c \
+ xcreate.c \
+ xreadobj.c \
+ xgetinfo.c \
+ xverinfo.c \
+ xsetinfo.c \
+ xclose.c \
+ xverobj.c \
+ xseekobj.c \
+ xwritobj.c \
+ xmkdblk.c \
+ vlm_xchg.c \
+ nostrad.rc
+#
+# NOTE: The following C_DEFINES definition determines whether the app is
+# compiled for ASCII/ANSI or Unicode. Use only one of these...
+#
+# Compile app for Unicode support...
+#
+#C_DEFINES= -DUNICODE -DUNIKLUG -D_WIN32_ -DWIN32 -DMS_RELEASE -DOS_WIN32 -DFS_NTFS -DMY40_TRANS -DMY31_TRANS -DNTKLUG -DOEM_MSOFT -DSTRICT
+#
+# Compile app for ASCII/ANSI support...
+#
+C_DEFINES= $(DEBUG_OPTIONS) $(UNICODE_OPTION) $(FSYS) $(PRODUCT_OPTIONS) $(OS_OPTIONS)
+
+UMTYPE=windows
+UMENTRY=winmain
+UMAPPL=ntbackup
+
+!IF ("$(TDCOMMON)"=="")||("$(MBUDEV)"=="")
+UMLIBS=obj\*\ntbackup.lib \
+$(BASEDIR)\public\sdk\lib\*\mpr.lib \
+$(BASEDIR)\public\sdk\lib\*\comdlg32.lib \
+$(BASEDIR)\public\sdk\lib\*\netapi32.lib \
+$(BASEDIR)\public\sdk\lib\*\ntlanman.lib \
+$(BASEDIR)\public\sdk\lib\*\rpcrt4.lib \
+$(BASEDIR)\public\sdk\lib\*\wsock32.lib \
+$(BASEDIR)\public\sdk\lib\*\ntctl3d.lib \
+$(BASEDIR)\public\sdk\lib\*\oldnames.lib \
+..\exchange\lib\*\sadapi.lib
+!ELSE
+!IF !$(386)
+UMLIBS=obj\*\ntbackup.lib \
+$(MBUDEV)\lib32\mpr.lib \
+$(MBUDEV)\lib32\comdlg32.lib \
+$(MBUDEV)\lib32\netapi32.lib \
+$(MBUDEV)\lib32\rpcrt4.lib \
+$(MBUDEV)\lib32\wsock32.lib \
+$(MBUDEV)\lib32\msvcrtd.lib \
+$(MBUDEV)\lib32\user32.lib \
+$(MBUDEV)\lib32\kernel32.lib \
+$(MBUDEV)\lib32\gdi32.lib \
+$(MBUDEV)\lib32\advapi32.lib \
+..\exchange\build\lib\*\ntlanman.lib \
+..\exchange\build\lib\*\ntctl3d.lib \
+$(TDCOMMON)\lib\win32\sadapi.lib
+!ELSE
+UMLIBS=obj\*\ntbackup.lib \
+$(MBUDEV)\lib32\mpr.lib \
+$(MBUDEV)\lib32\comdlg32.lib \
+$(MBUDEV)\lib32\netapi32.lib \
+$(MBUDEV)\lib32\rpcrt4.lib \
+$(MBUDEV)\lib32\wsock32.lib \
+$(MBUDEV)\lib32\crtdll.lib \
+$(MBUDEV)\lib32\user32.lib \
+$(MBUDEV)\lib32\kernel32.lib \
+$(MBUDEV)\lib32\gdi32.lib \
+$(MBUDEV)\lib32\int64.lib \
+$(MBUDEV)\lib32\advapi32.lib \
+..\exchange\build\lib\*\ntlanman.lib \
+..\exchange\build\lib\*\ntctl3d.lib \
+$(TDCOMMON)\lib\win32\sadapi.lib
+!ENDIF
+!ENDIF
+
+UMRES=obj\*\nostrad.res
+
+NTTARGETFILE0=bkuevent.h bkuevent.rc
diff --git a/private/utils/ntbackup/src/statline.c b/private/utils/ntbackup/src/statline.c
new file mode 100644
index 000000000..2d9f5bee4
--- /dev/null
+++ b/private/utils/ntbackup/src/statline.c
@@ -0,0 +1,396 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: statline.c
+
+ Description: This file contains the functions for the GUI Status Line
+ Manager (STM). The Status Line Manager displays information
+ on the status line. What else?
+
+ $Log: G:/UI/LOGFILES/STATLINE.C_V $
+
+ Rev 1.17 04 Aug 1993 18:44:14 MARINA
+enable c++
+
+ Rev 1.16 20 Jan 1993 19:54:56 MIKEP
+add nt memory display
+
+ Rev 1.15 01 Nov 1992 16:08:10 DAVEV
+Unicode changes
+
+ Rev 1.14 07 Oct 1992 15:10:38 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.13 04 Oct 1992 19:40:46 DAVEV
+Unicode Awk pass
+
+ Rev 1.12 10 Jul 1992 10:29:10 GLENN
+Changed the status line to be identical to the new file manager.
+
+ Rev 1.11 10 Jun 1992 16:14:38 GLENN
+Updated according to NT SPEC.
+
+ Rev 1.10 29 May 1992 16:00:42 JOHNWT
+PCH updates
+
+ Rev 1.9 22 Apr 1992 17:53:32 GLENN
+Using MAX_STATUS_LINE_LEN for status line text length.
+
+ Rev 1.8 20 Apr 1992 13:48:38 GLENN
+Added status line get/set capability.
+
+ Rev 1.7 26 Mar 1992 08:44:48 JOHNWT
+don't display mem line unless app is up
+
+ Rev 1.6 03 Mar 1992 18:18:38 GLENN
+Updated draw text call.
+
+ Rev 1.5 23 Feb 1992 13:56:54 GLENN
+Removed right status box - not used at this time.
+
+ Rev 1.4 20 Jan 1992 13:09:56 MIKEP
+changes
+
+ Rev 1.3 26 Dec 1991 13:41:12 GLENN
+Changed show flags to use CDS calls
+
+ Rev 1.2 19 Dec 1991 15:25:14 GLENN
+Added windows.h
+
+ Rev 1.1 02 Dec 1991 17:51:36 DAVEV
+16/32 bit Windows port changes
+
+ Rev 1.0 20 Nov 1991 19:32:46 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+// MODULE-WIDE VARIABLES
+
+static BOOL mwfMemoryText = FALSE;
+
+// PRIVATE FUNCTION PROTOTYPES
+
+VOID STM_Raised3D ( HDC, LPRECT );
+VOID STM_Recessed3D ( HDC, LPRECT );
+
+// FUNCTIONS
+
+
+/******************************************************************************
+
+ Name: STM_DrawBorder()
+
+ Description: This function draws a cool looking 3-D border with a
+ recessed area to frame the status line text.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID STM_DrawBorder ( VOID )
+
+{
+ HDC hDC;
+ RECT Rect;
+
+ if ( CDS_GetShowStatusLine ( CDS_GetPerm () ) ) {
+
+ hDC = GetDC ( ghWndFrame );
+
+ // Make the Status Line rectangle.
+
+ gpStatusRect = gRectFrameClient;
+
+ gpStatusRect.top = gRectFrameClient.bottom - STATUS_LINE_HEIGHT;
+ gpStatusRect.right = max ( gRectFrameClient.right, STATUS_TEXT );
+
+ Rect = gpStatusRect;
+
+ Rect.top += STATUS_BORDER + STATUS_HIGHLIGHT_WIDTH;
+ Rect.bottom -= STATUS_BORDER + STATUS_HIGHLIGHT_WIDTH;
+
+ // Give a raised 3-D look to the status line.
+
+ STM_Raised3D ( hDC, &gpStatusRect );
+
+ // Now make the text areas recessed.
+
+ Rect.left += STATUS_BORDER + STATUS_INDENT;
+ Rect.right = Rect.left + STATUS_TEXT;
+
+ STM_Recessed3D ( hDC, &Rect );
+
+ // The other Status Area is unused at this time.
+
+ // Rect.left += Rect.right + STATUS_BORDER;
+ // Rect.right = gRectFrameClient.right - STATUS_BORDER;
+
+ // STM_Recessed3D ( hDC, &Rect );
+
+ ReleaseDC ( ghWndFrame, hDC );
+
+ // Resize the status rectangle for drawing text inside the border.
+
+ gpStatusRect.top += ( STATUS_BORDER + STATUS_HIGHLIGHT_WIDTH + 1 );
+ gpStatusRect.bottom -= ( STATUS_BORDER + STATUS_HIGHLIGHT_WIDTH );
+ gpStatusRect.left += ( STATUS_INDENT + STATUS_BORDER + STATUS_TEXT_MARGIN );
+ gpStatusRect.right = ( STATUS_INDENT + STATUS_BORDER + STATUS_TEXT - STATUS_TEXT_MARGIN );
+ }
+
+} /* end STM_DrawBorder() */
+
+
+/******************************************************************************
+
+ Name: STM_DrawMemory()
+
+ Description: This function draws the current memory status on the status
+ line.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID STM_DrawMemory( VOID )
+{
+ // if the app has been displayed, show the memory usage
+
+ if ( ghWndFrame ) {
+
+#ifdef OS_WIN32
+ sprintf ( gszStatusLine,
+ TEXT( "Bytes: %10lu" ), gulMemUsed );
+#else
+ wsprintf ( gszStatusLine,
+ TEXT("Memory bytes: %lu in use; %lu allocated; %u segment(s)"),
+ gulMemUsed, gulMemAvail, gunSegCount );
+#endif
+
+ mwfMemoryText = TRUE;
+ STM_DrawText ( gszStatusLine );
+ mwfMemoryText = FALSE;
+
+ }
+
+} /* end STM_DrawMemory() */
+
+
+/******************************************************************************
+
+ Name: STM_DrawText()
+
+ Description: This function draws the specified text string on the status
+ line.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID STM_DrawText (
+
+LPSTR lpszText ) // I - pointer to a text string
+
+{
+ HDC hDC;
+
+ // If we are monitoring memory than don't display other messages.
+
+ if ( CDS_GetShowStatusLine ( CDS_GetPerm () ) && ( ! gfShowMemory || ( gfShowMemory && mwfMemoryText ) ) ) {
+
+ hDC = GetDC ( ghWndFrame );
+
+ FillRect ( hDC, &gpStatusRect, ghBrushLtGray );
+
+ // Default text color is black.
+
+ SelectObject ( hDC, ghFontStatus );
+ SelectObject ( hDC, ghBrushLtGray );
+
+ SetBkColor( hDC, GetSysColor ( COLOR_BTNFACE ) );
+
+ // If a RESOURCE ID was passed, copy the string from the resource.
+
+ if ( ! HIWORD(lpszText) ) {
+
+ RSM_StringCopy ( LOWORD((DWORD)lpszText),
+ gszStatusLine,
+ MAX_STATUS_LINE_LEN );
+
+ lpszText = gszStatusLine;
+ }
+
+ DrawText ( hDC, lpszText, -1, &gpStatusRect, DT_LEFT | DT_VCENTER | DT_SINGLELINE );
+
+ ReleaseDC( ghWndFrame, hDC );
+ }
+
+} /* end STM_DrawText() */
+
+
+/******************************************************************************
+
+ Name: STM_SetIdleText()
+
+ Description: This function extracts a text string from the resource file
+ based on the passed ID. It then displays this text
+ whenever the application is idle.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID STM_SetIdleText (
+
+WORD wTextID ) // I - resource text string ID.
+
+{
+ RSM_StringCopy ( wTextID, gszStatusLine, MAX_STATUS_LINE_LEN );
+ STM_DrawText ( gszStatusLine );
+
+} /* end STM_SetIdleText() */
+
+
+/******************************************************************************
+
+ Name: STM_Raised3D()
+
+ Description: This function draws a 3-D raised looking rectangle on
+ the status line.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID STM_Raised3D(
+
+HDC hDC,
+LPRECT pRect )
+
+{
+ FillRect ( hDC, pRect, ghBrushLtGray );
+
+ // Draw a black frame.
+
+ SelectObject ( hDC, ghPenBlack );
+
+ MoveToEx ( hDC, pRect->left, pRect->top, NULL );
+ LineTo ( hDC, pRect->right + 1, pRect->top );
+
+ // LineTo ( hDC, pRect->right, pRect->bottom );
+ // LineTo ( hDC, pRect->left, pRect->bottom );
+ // LineTo ( hDC, pRect->left, pRect->top );
+
+ // Draw the white highlights.
+
+ SelectObject ( hDC, ghPenWhite );
+
+ MoveToEx ( hDC, pRect->left, pRect->top + 1, NULL );
+ LineTo ( hDC, pRect->right, pRect->top + 1 );
+
+ // MoveToEx ( hDC, pRect->left + 2, pRect->bottom - 2, NULL );
+ // LineTo ( hDC, pRect->left + 2, pRect->top + 2 );
+ // LineTo ( hDC, pRect->right - 2, pRect->top + 2 );
+
+ // Draw the gray shadows.
+
+ // SelectObject ( hDC, ghPenDkGray );
+
+ // MoveToEx ( hDC, pRect->left + 2, pRect->bottom - 1, NULL );
+ // LineTo ( hDC, pRect->right - 1, pRect->bottom - 1 );
+ // LineTo ( hDC, pRect->right - 1, pRect->top + 1 );
+ // MoveToEx ( hDC, pRect->left + 3, pRect->bottom - 2, NULL );
+ // LineTo ( hDC, pRect->right - 2, pRect->bottom - 2 );
+ // LineTo ( hDC, pRect->right - 2, pRect->top + 2 );
+
+} /* end STM_Raised3D() */
+
+
+/******************************************************************************
+
+ Name: STM_Recessed3D()
+
+ Description: This function draws a 3-D recessed looking rectangle on
+ the status line.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID STM_Recessed3D (
+
+HDC hDC, // I - handle to a display device context
+LPRECT pRect ) // I - the rectangle to draw the 3-D recess in
+
+{
+ SelectObject ( hDC, ghPenDkGray );
+
+ MoveToEx ( hDC, pRect->left, pRect->bottom, NULL );
+ LineTo ( hDC, pRect->left, pRect->top );
+ LineTo ( hDC, pRect->right, pRect->top );
+
+ // MoveToEx ( hDC, pRect->left + 1, pRect->bottom - 1, NULL );
+ // LineTo ( hDC, pRect->left + 1, pRect->top + 1 );
+ // LineTo ( hDC, pRect->right - 1, pRect->top + 1 );
+
+ SelectObject ( hDC, ghPenWhite );
+
+ MoveToEx ( hDC, pRect->left + 1, pRect->bottom, NULL );
+ LineTo ( hDC, pRect->right, pRect->bottom );
+ LineTo ( hDC, pRect->right, pRect->top + 1 );
+
+ // MoveToEx ( hDC, pRect->left + 2, pRect->bottom - 1, NULL );
+ // LineTo ( hDC, pRect->right - 1, pRect->bottom - 1 );
+ // LineTo ( hDC, pRect->right - 1, pRect->top + 1 );
+
+} /* end STM_Recessed3D() */
+
+
+/******************************************************************************
+
+ Name: STM_GetStatusLineText()
+
+ Description: This function returns a pointer to the current status line
+ text string.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+LPSTR STM_GetStatusLineText ( VOID )
+
+{
+ return gszStatusLine;
+
+} /* end STM_GetStatusLineText() */
+
+
+/******************************************************************************
+
+ Name: STM_SetStatusLineText()
+
+ Description: This function returns a pointer to the current status line
+ text string.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID STM_SetStatusLineText (
+
+LPSTR pString )
+
+{
+ strncpy ( gszStatusLine, pString, MAX_STATUS_LINE_LEN );
+
+} /* end STM_SetStatusLineText() */
+
diff --git a/private/utils/ntbackup/src/stats.c b/private/utils/ntbackup/src/stats.c
new file mode 100644
index 000000000..537733d3b
--- /dev/null
+++ b/private/utils/ntbackup/src/stats.c
@@ -0,0 +1,360 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: stats.c
+
+ Description:
+
+ $Log: G:/UI/LOGFILES/STATS.C_V $
+
+ Rev 1.5 26 Jul 1993 19:32:06 MARINA
+enable c++
+
+ Rev 1.4 07 Oct 1992 15:01:56 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.3 04 Oct 1992 19:40:50 DAVEV
+Unicode Awk pass
+
+ Rev 1.2 29 May 1992 16:03:44 JOHNWT
+PCH updates
+
+ Rev 1.1 29 Dec 1991 11:35:50 MIKEP
+remove msassert we were hitting
+
+ Rev 1.0 20 Nov 1991 19:34:34 SYSTEM
+Initial revision.
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+/*****************************************************************************
+
+ Name: ST_StartOperation()
+
+ Description:
+
+ Returns:
+
+*****************************************************************************/
+VOID ST_StartOperation(
+
+STATS_PTR stats_ptr )
+{
+ SYSTEMTIME loc_time ;
+ struct tm dos_time ;
+ time_t t_time ;
+
+ GetLocalTime( &loc_time ) ;
+
+ dos_time.tm_sec = loc_time.wSecond;
+ dos_time.tm_min = loc_time.wMinute ;
+ dos_time.tm_hour = loc_time.wHour ;
+ dos_time.tm_mday = loc_time.wDay ;
+ dos_time.tm_mon = loc_time.wMonth -1;
+ dos_time.tm_year = loc_time.wYear -1900 ;
+ dos_time.tm_isdst= -1 ;
+
+ t_time = mktime( &dos_time ) ;
+ if ( t_time == -1 ) {
+ t_time = 0 ;
+ }
+
+ memset( stats_ptr, 0, sizeof( STATS ) ) ;
+ ST_SetOPStartTime( stats_ptr, t_time ) ;
+
+ return ;
+
+}
+/*****************************************************************************
+
+ Name: ST_EndOperation()
+
+ Description:
+
+ Returns:
+
+*****************************************************************************/
+VOID ST_EndOperation(
+
+STATS_PTR stats_ptr )
+{
+ SYSTEMTIME loc_time ;
+ struct tm dos_time ;
+ time_t t_time ;
+
+ GetLocalTime( &loc_time ) ;
+
+ dos_time.tm_sec = loc_time.wSecond;
+ dos_time.tm_min = loc_time.wMinute ;
+ dos_time.tm_hour = loc_time.wHour ;
+ dos_time.tm_mday = loc_time.wDay ;
+ dos_time.tm_mon = loc_time.wMonth -1;
+ dos_time.tm_year = loc_time.wYear -1900;
+ dos_time.tm_isdst= -1 ;
+
+ t_time = mktime( &dos_time ) ;
+ if ( t_time == -1 ) {
+ t_time = 0 ;
+ }
+
+ ST_SetOPEndTime( stats_ptr, t_time ) ;
+
+ return ;
+
+}
+/*****************************************************************************
+
+ Name: ST_StartOperationIdle()
+
+ Description:
+
+ Returns:
+
+*****************************************************************************/
+VOID ST_StartOperationIdle(
+
+STATS_PTR stats_ptr )
+{
+ SYSTEMTIME loc_time ;
+ struct tm dos_time ;
+ time_t t_time ;
+
+ GetLocalTime( &loc_time ) ;
+
+ dos_time.tm_sec = loc_time.wSecond;
+ dos_time.tm_min = loc_time.wMinute ;
+ dos_time.tm_hour = loc_time.wHour ;
+ dos_time.tm_mday = loc_time.wDay ;
+ dos_time.tm_mon = loc_time.wMonth -1;
+ dos_time.tm_year = loc_time.wYear -1900;
+ dos_time.tm_isdst= -1 ;
+
+ t_time = mktime( &dos_time ) ;
+ if ( t_time == -1 ) {
+ t_time = 0 ;
+ }
+
+
+ if( ST_OPIdleLevel( stats_ptr ) == 0 ) {
+ ST_SetOPStartIdle( stats_ptr, t_time ) ;
+ }
+ else {
+ msassert( ST_GetOPStartIdle( stats_ptr ) != 0L ) ;
+ }
+
+ ST_PushOPIdleLevel( stats_ptr ) ;
+
+ return ;
+
+}
+/*****************************************************************************
+
+ Name: ST_EndOperationIdle()
+
+ Description:
+
+*****************************************************************************/
+VOID ST_EndOperationIdle(
+
+STATS_PTR stats_ptr )
+{
+ SYSTEMTIME loc_time ;
+ struct tm dos_time ;
+ time_t t_time ;
+
+ GetLocalTime( &loc_time ) ;
+
+ dos_time.tm_sec = loc_time.wSecond;
+ dos_time.tm_min = loc_time.wMinute ;
+ dos_time.tm_hour = loc_time.wHour ;
+ dos_time.tm_mday = loc_time.wDay ;
+ dos_time.tm_mon = loc_time.wMonth -1;
+ dos_time.tm_year = loc_time.wYear -1900;
+ dos_time.tm_isdst= -1 ;
+
+ t_time = mktime( &dos_time ) ;
+ if ( t_time == -1 ) {
+ t_time = 0 ;
+ }
+
+ if( ST_OPIdleLevel( stats_ptr ) == 1 ) {
+ ST_AddOPIdle( stats_ptr, ( UINT32 )( t_time - ST_GetOPStartIdle( stats_ptr ) ) ) ;
+ ST_SetOPStartIdle( stats_ptr, 0L ) ;
+ }
+
+ ST_PopOPIdleLevel( stats_ptr ) ;
+
+ return ;
+
+}
+/*****************************************************************************
+
+ Name: ST_StartBackupSet()
+
+ Description:
+
+ Returns:
+
+*****************************************************************************/
+VOID ST_StartBackupSet(
+
+STATS_PTR stats_ptr )
+{
+ SYSTEMTIME loc_time ;
+ struct tm dos_time ;
+ time_t t_time ;
+
+ GetLocalTime( &loc_time ) ;
+
+ dos_time.tm_sec = loc_time.wSecond;
+ dos_time.tm_min = loc_time.wMinute ;
+ dos_time.tm_hour = loc_time.wHour ;
+ dos_time.tm_mday = loc_time.wDay ;
+ dos_time.tm_mon = loc_time.wMonth -1;
+ dos_time.tm_year = loc_time.wYear -1900;
+ dos_time.tm_isdst= -1 ;
+
+ t_time = mktime( &dos_time ) ;
+ if ( t_time == -1 ) {
+ t_time = 0 ;
+ }
+
+
+ memset( stats_ptr, 0, sizeof( STATS ) ) ;
+ ST_SetBSStartTime( stats_ptr, t_time ) ;
+
+ return ;
+
+}
+/*****************************************************************************
+
+ Name: ST_EndBackupSet()
+
+ Description:
+
+ Returns:
+
+*****************************************************************************/
+VOID ST_EndBackupSet(
+
+STATS_PTR stats_ptr )
+{
+ SYSTEMTIME loc_time ;
+ struct tm dos_time ;
+ time_t t_time ;
+
+ GetLocalTime( &loc_time ) ;
+
+ dos_time.tm_sec = loc_time.wSecond;
+ dos_time.tm_min = loc_time.wMinute ;
+ dos_time.tm_hour = loc_time.wHour ;
+ dos_time.tm_mday = loc_time.wDay ;
+ dos_time.tm_mon = loc_time.wMonth -1;
+ dos_time.tm_year = loc_time.wYear -1900;
+ dos_time.tm_isdst= -1 ;
+
+ t_time = mktime( &dos_time ) ;
+ if ( t_time == -1 ) {
+ t_time = 0 ;
+ }
+
+
+ ST_SetBSEndTime( stats_ptr, t_time ) ;
+
+ return ;
+
+}
+/*****************************************************************************
+
+ Name: ST_StartBackupSetIdle()
+
+ Description:
+
+ Returns:
+*****************************************************************************/
+VOID ST_StartBackupSetIdle(
+
+STATS_PTR stats_ptr )
+{
+ SYSTEMTIME loc_time ;
+ struct tm dos_time ;
+ time_t t_time ;
+
+ GetLocalTime( &loc_time ) ;
+
+ dos_time.tm_sec = loc_time.wSecond;
+ dos_time.tm_min = loc_time.wMinute ;
+ dos_time.tm_hour = loc_time.wHour ;
+ dos_time.tm_mday = loc_time.wDay ;
+ dos_time.tm_mon = loc_time.wMonth -1;
+ dos_time.tm_year = loc_time.wYear -1900;
+ dos_time.tm_isdst= -1 ;
+
+ t_time = mktime( &dos_time ) ;
+ if ( t_time == -1 ) {
+ t_time = 0 ;
+ }
+
+
+ if( ST_BSIdleLevel( stats_ptr ) == 0 ) {
+ ST_SetBSStartIdle( stats_ptr, t_time ) ;
+ }
+ else {
+ msassert( ST_GetBSStartIdle( stats_ptr ) != 0L ) ;
+ }
+
+ ST_PushBSIdleLevel( stats_ptr ) ;
+
+ return ;
+
+}
+/*****************************************************************************
+
+ Name: ST_EndBackupSetIdle()
+
+ Description:
+
+ Returns:
+
+*****************************************************************************/
+VOID ST_EndBackupSetIdle(
+
+STATS_PTR stats_ptr )
+{
+ SYSTEMTIME loc_time ;
+ struct tm dos_time ;
+ time_t t_time ;
+
+ GetLocalTime( &loc_time ) ;
+
+ dos_time.tm_sec = loc_time.wSecond;
+ dos_time.tm_min = loc_time.wMinute ;
+ dos_time.tm_hour = loc_time.wHour ;
+ dos_time.tm_mday = loc_time.wDay ;
+ dos_time.tm_mon = loc_time.wMonth -1;
+ dos_time.tm_year = loc_time.wYear -1900;
+ dos_time.tm_isdst= -1 ;
+
+ t_time = mktime( &dos_time ) ;
+ if ( t_time == -1 ) {
+ t_time = 0 ;
+ }
+
+
+ if( ST_BSIdleLevel( stats_ptr ) == 1 ) {
+ ST_AddBSIdle( stats_ptr, ( UINT32 )( t_time - ST_GetBSStartIdle( stats_ptr ) ) ) ;
+ ST_SetBSStartIdle( stats_ptr, 0L ) ;
+ }
+
+ ST_PopBSIdleLevel( stats_ptr ) ;
+
+ return ;
+
+}
+
diff --git a/private/utils/ntbackup/src/stdmath.c b/private/utils/ntbackup/src/stdmath.c
new file mode 100644
index 000000000..95ecd11bf
--- /dev/null
+++ b/private/utils/ntbackup/src/stdmath.c
@@ -0,0 +1,1976 @@
+/**
+ $Header: T:/LOGFILES/STDMATH.C_V 1.19 21 Jul 1993 17:10:16 GREGG $
+ Name: stdmath.c
+
+ Description: To provide support functions for 64 bit unsigned manipulations.
+
+ $Log: T:/LOGFILES/STDMATH.C_V $
+
+ Rev 1.19 21 Jul 1993 17:10:16 GREGG
+Fixed and optimized U64_LitoA.
+
+ Rev 1.18 03 Mar 1993 14:15:26 DON
+Commented out local variable t_str to agree with commented out use of such variable
+
+ Rev 1.17 01 Mar 1993 16:37:02 TIMN
+Added header to resolve wide char function linking errors
+
+ Rev 1.16 17 Nov 1992 22:19:38 DAVEV
+unicode fixes
+
+ Rev 1.15 27 Oct 1992 21:09:20 GREGG
+Replaced mallocs of small chunks used for temporary storage in binary_divide
+with static arrays.
+Removed functions which are now implemented as macros in stdmath.h.
+Cleaned up and indented code.
+
+ Rev 1.14 08 Oct 1992 14:21:20 DAVEV
+Unicode strlen verfication
+
+ Rev 1.13 14 Aug 1992 09:56:16 BARRY
+Fixed warnings.
+
+ Rev 1.12 12 Aug 1992 17:55:52 BARRY
+Added max and min functions.
+
+ Rev 1.11 28 Jul 1992 15:39:16 STEVEN
+fix warnings
+
+ Rev 1.10 23 Jul 1992 16:44:32 STEVEN
+fix warnings
+
+ Rev 1.9 29 May 1992 13:05:20 BURT
+Fixed octal conversions for numbers > 32 bits. Added a function, and related
+logic, called U64_Commas() to specify the addition of commas to the resulting
+string for decimal conversions from UINT64 to ASCII string.
+
+
+ Rev 1.6 26 May 1992 10:13:10 MIKEP
+fixes to last change
+
+ Rev 1.5 26 May 1992 10:11:48 MIKEP
+fixes to last change
+
+ Rev 1.4 26 May 1992 09:30:54 BURT
+Added logic to U64_Div to perform 32 bit division in the event that
+the msws of arg1 and arg2 are both 0.
+
+Removed leading 0 from U64_Litoa decimal conversions, cut and paste
+strikes again.
+
+
+ Rev 1.3 17 Apr 1992 14:57:32 BURT
+Standardified the source code.
+
+
+ Rev 1.2 18 Mar 1992 16:09:26 BURT
+Cleaned up braces for if's and added type casts to constants
+again to ease port to NT.
+
+
+ Rev 1.1 18 Mar 1992 10:26:26 BURT
+Changed INT and INT_PTR to INT16 and INT16_PTR to make it easier
+to port to NT
+
+ Rev 1.0 7 Feb 1992 16:19:00 BURT
+ Initial revision.
+
+**/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#ifdef STAND_ALONE
+#define NO_STD_HOOKS
+#endif
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "stdwcs.h"
+
+#include "msassert.h"
+
+/* TRUE if we want commas in the string (decimal only) */
+static BOOLEAN commas = FALSE ;
+
+static UINT64 mw_powers[] = {
+ { 0x89E80000L, 0x8AC72304L },
+ { 0xA7640000L, 0xDE0B6B3L },
+ { 0x5D8A0000L, 0x1634578L },
+ { 0x6FC10000L, 0x2386F2L },
+ { 0xA4C68000L, 0x38D7EL },
+ { 0x107A4000L, 0x5AF3L },
+ { 0x4E72A000L, 0x918L },
+ { 0xD4A51000L, 0xE8L },
+ { 0x4876E800L, 0x17L },
+ { 0x540BE400L, 0x2L },
+ { 0x3B9ACA00L, 0x0L },
+ { 0x5F5E100L, 0x0L },
+ { 0x989680L, 0x0L },
+ { 0xF4240L, 0x0L },
+ { 0x186A0L, 0x0L },
+ { 0x2710L, 0x0L },
+ { 0x3E8L, 0x0L },
+ { 0x64L, 0x0L },
+ { 0xAL, 0x0L } } ;
+
+
+/**/
+/**
+
+ Name: U64_Add()
+
+ Description: Adds 64 bit values arg1 and arg2. Returns result in
+ *result and returns TRUE if no overflow. Otherwise
+ returns FALSE and the value in *result reflects the
+ result of the overflow.
+
+ Entry: UINT64 arg1
+
+ UINT64 arg2
+
+ BOOLEAN_PTR status
+
+ Returns: UINT64 sum of arg1+arg2, Sets *status to TRUE if there
+ is no overflow, FALSE otherwise.
+
+**/
+
+UINT64 U64_Add(
+ UINT64 arg1, /* First 64 bit argument to add */
+ UINT64 arg2, /* Second 64 bit argument to add */
+ BOOLEAN_PTR status ) /* Error status */
+{
+ UINT32 temp1 ;
+ UINT64 result ;
+
+ /* Take sum of lsw. If it overflows we should be able to test for it
+ by comparing with each of the operands. If the sum is less than
+ either of the operands then we have overflow. In this case we will
+ add 1 to the msw.
+ */
+ temp1 = arg1.lsw + arg2.lsw ;
+ if( temp1 < arg1.lsw || temp1 < arg2.lsw ) { /* Handle case of carry */
+ result.lsw = arg1.lsw + arg2.lsw ;
+ result.msw = arg1.msw + arg2.msw + 1L ; /* Add in carry */
+
+ if( arg1.msw + 1L > arg1.msw ) {
+ /* Add here so we can test for possible overflow later */
+ arg1.msw += 1L ;
+ } else if( arg2.msw + 1L > arg2.msw ) {
+ /* else we don't need to add since we will overflow anyway. */
+ arg2.msw += 1L ;
+ }
+ } else {
+ /* Case of no carry on lsw */
+ result.lsw = arg1.lsw + arg2.lsw ;
+ result.msw = arg1.msw + arg2.msw ;
+ }
+
+ /* Take sum of msw. If it overflows we can test by comparing with each
+ of the operands. If the sum is less than either of the operands then
+ we have overflow. If we see overflow we will return FALSE in *status
+ to indicate that the value returned is an overflowed value.
+ */
+ temp1 = arg1.msw + arg2.msw ;
+ *status = TRUE ;
+ if( ( temp1 < arg1.msw ) || ( temp1 < arg2.msw ) ) {
+ *status = FALSE ;
+ }
+
+ return( result ) ;
+}
+
+
+/**/
+/**
+
+ Name: U64_Sub()
+
+ Description: Subtract arg2 from arg1 (arg1 - arg2) retunr the UINT64
+ result. Set *status TRUE if there was no underflow.
+ Otherwise set *status FALSE and the UINT64 value returned
+ reflects the underflow condition.
+
+ Entry: UINT64 arg1
+
+ UINT64 arg2
+
+ BOOLEAN_PTR status
+
+ Returns: UINT64 value which is arg1 - arg2, and sets *status to
+ TRUE if there was no underflow, else sets *status to
+ FALSE and the returned value reflects the underflow.
+
+**/
+
+UINT64 U64_Sub(
+ UINT64 arg1, /* 64 bit argument */
+ UINT64 arg2, /* 64 bit argument */
+ BOOLEAN_PTR status ) /* Error status */
+{
+ UINT64 result ;
+
+ result.msw = result.lsw = 0L ;
+
+ /* see if we will have underflow */
+ if( arg1.msw < arg2.msw ) {
+ *status = FALSE ;
+ return( result ) ;
+ }
+
+ /* Subtract the msw portions. */
+ result.msw = arg1.msw - arg2.msw ;
+
+ /* Do lsw subtraction and let it uflow */
+ result.lsw = arg1.lsw - arg2.lsw ;
+
+ if( arg1.lsw < arg2.lsw ) {
+ /* Need to borrow from .msw, the .lsw has done an implied borrow
+ from the 'bit bank' already so we just need to fix .msw
+ */
+ if( result.msw == 0L ) {
+ *status = FALSE ;
+ return( result ) ;
+ } else {
+ result.msw-- ;
+ }
+ }
+ *status = TRUE ;
+ return( result ) ;
+}
+
+
+/**/
+/**
+
+ Name: U64_To_32Bit()
+
+ Description: Converts a 64 bit entity to 2 UINT32s. The 64 Bit value
+ is passed in arg1 and the lsw and msw are returned in
+ *lsw and *msw respectively.
+
+ Entry: UINT64 arg1 64 bit argument
+
+ UINT32_PTR lsw Pointer to 32 bit least significant
+ portion.
+
+ UINT32_PTR msw Pointer to 32 bit most significant
+ portion.
+
+ Returns: TRUE and sets *lsw and *msw accordingly.
+
+**/
+
+BOOLEAN U64_To_32Bit(
+ UINT64 arg1, /* 64 bit argument */
+ UINT32_PTR lsw, /* Pointer to least significant 32 bits */
+ UINT32_PTR msw ) /* Pointer to most significant 32 bits */
+{
+ *lsw = arg1.lsw ;
+ *msw = arg1.msw ;
+ return( TRUE ) ;
+}
+
+
+/**/
+/**
+
+ Name: U32_To_U64()
+
+ Description: Enters with a 32 bit value in arg. Returns a 64 Bit
+ result that consists of the msw set to 0L and the lsw
+ set to the 32 bit argument.
+
+ Entry: UINT32 arg
+
+ Returns: UINT64 value with msw set to 0L and lsw set to arg.
+
+**/
+
+UINT64 U32_To_U64(
+ UINT32 arg ) /* 32 bit argument */
+{
+ UINT64 result ;
+
+ result.lsw = arg ;
+ result.msw = 0L ;
+ return( result ) ;
+}
+
+
+/**/
+/**
+
+ Name: U64_Test()
+
+ Description: Returns non-zero if any of the specified bits are set.
+
+ Entry: UINT64 arg
+
+ UINT32 lsw_mask Least significant 32 bits to test.
+
+ UINT32 msw_mask Most significant 32 bits to test.
+
+ Returns: UINT32 0 if none of the specified bits are set.
+ Otherwise returns a non-zero value.
+
+**/
+
+UINT32 U64_Test(
+ UINT64 arg, /* 64 bit argument */
+ UINT32 lsw_mask, /* Least significant 32 bits of mask */
+ UINT32 msw_mask ) /* Most significant 32 bits of mask */
+{
+ return( (arg.lsw & lsw_mask) | (arg.msw & msw_mask) ) ;
+}
+
+
+/**/
+/**
+
+ Name: U64_Stest()
+
+ Description: Returns non-zero if any of the specified bits are set.
+
+ Entry: UINT64 arg
+
+ CHAR_PTR mask 'C' string representation of 64 bit mask.
+ May be Hex, Octal (and eventually) Decimal.
+
+ Returns: UINT32 0 if none of the specified bits are set.
+ Otherwise returns a non-zero value.
+
+**/
+
+UINT32 U64_Stest(
+ UINT64 arg, /* 64 bit argument */
+ CHAR_PTR mask ) /* Pointer to TEXT('C') string representation of mask */
+{
+ BOOLEAN status ;
+ UINT64 tui64 ;
+
+ /* First we need to convert the value in mask to a UINT64 and then
+ we can test the arg with it.
+ */
+ tui64 = U64_Atoli( mask, &status ) ;
+
+ return( ( arg.lsw & tui64.lsw ) | ( arg.msw & tui64.msw ) ) ;
+}
+
+
+/**/
+
+/* Defines used by U64_Btop() and related Macros */
+
+#define CLR_64BIT 0
+#define SET_64BIT 1
+#define XOR_64BIT 2
+#define OR_64BIT 3
+#define AND_64BIT 4
+#define NOT_64BIT 5
+/* Shift operations */
+#define SHL_64BIT 6
+#define SHR_64BIT 7
+
+/**
+
+ Name: U64_Btop()
+
+ Description: Does 64 Bit manipulations. Clear, Set, Xor, Or, And,
+ Shift Left and Shift Right. NOTE: These are all
+ unsigned operations. So pay attention if you attempt
+ to use this with signed 64 Bit entities. Sets or clears
+ bits in the UINT64 arg based on the value passed in lws
+ and msw_mask and operation. If operation == CLR_64BIT
+ then the specified bits will be cleared. If
+ operation == SET_64BIT then the bits will be set. If
+ operation == XOR_64BIT then the bits will be exclusive
+ OR'd. Likewise for OR_64BIT and AND_64BIT.
+
+ Entry: UINT64 arg 64 Bit argument to be operated on.
+
+ UINT32 lsw_mask Least significant 32 bits to operate
+ on.
+
+ UINT32 msw_mask Most significant 32 bits to operate
+ on. NOTE: lsw_mask and msw_mask have
+ no meaning to shift left or right.
+
+ INT16 operation Requested operation.
+
+ INT16 shift_count Number of bits to shift by. Values
+ outside of the range of 1 - 63 are
+ ignored. shift_count has no meaning
+ for operations other than shift left
+ and right.
+
+ Returns: UINT64 value that is the result of applying the requested
+ operation to arg.
+
+**/
+
+UINT64 U64_Btop(
+ UINT64 arg, /* 64 bit argument */
+ UINT32 lsw_mask, /* 32 bit least significant 32 bits of mask */
+ UINT32 msw_mask, /* 32 bit most significant 32 bits of mask */
+ INT operation, /* Operation to be performed */
+ INT shift_count ) /* Number of bits for shift operations */
+{
+ switch( operation ) {
+
+ case CLR_64BIT: /* Clears the bits specified in the masks */
+ arg.lsw &= ~lsw_mask ;
+ arg.msw &= ~msw_mask ;
+ break ;
+
+ case NOT_64BIT: /* Bitwise NOT operation */
+ arg.lsw = ~arg.lsw ;
+ arg.msw = ~arg.msw ;
+ break ;
+
+ case XOR_64BIT: /* Exclusive OR the bits specified in the masks */
+ arg.lsw ^= lsw_mask ;
+ arg.msw ^= msw_mask ;
+ break ;
+
+ case SET_64BIT: /* Sets the bits specified in the masks */
+ case OR_64BIT : /* OR is the same as setting the bits */
+ arg.lsw |= lsw_mask ;
+ arg.msw |= msw_mask ;
+ break ;
+
+ case AND_64BIT: /* Ands the bits specified in the masks */
+ arg.lsw &= lsw_mask ;
+ arg.msw &= msw_mask ;
+ break ;
+
+ case SHR_64BIT: /* Shifts the bits right by shift count number */
+ if( shift_count > 0 && shift_count < (INT16)64 ) {
+ if( shift_count == (INT16)32 ) {
+ arg.lsw = arg.msw ;
+ arg.msw = 0L ;
+
+ } else if( shift_count > (INT16)32 ) {
+ arg.lsw = arg.msw ;
+ arg.lsw >>= ( shift_count - (INT16)32 ) ;
+ arg.msw = 0L ;
+
+ } else {
+ UINT32 t = 0x80000000L ;
+ INT16 i ;
+
+ arg.lsw >>= shift_count ;
+ t = ( t >> ( shift_count - (INT16)1 ) ) ;
+ for( i = 0; i < shift_count; i++ ) {
+ if( arg.msw & 0x01 ) {
+ /* We need to place this bit in the appropriate
+ position in the lsw.
+ */
+ arg.lsw |= t ;
+ }
+ t <<= 1;
+ arg.msw >>= (INT16)1 ;
+ }
+ }
+ }
+ break ;
+
+ case SHL_64BIT: /* Shifts the bits left by shift_count number */
+ if( shift_count > 0 && shift_count < (INT16)64 ) {
+ if( shift_count == (INT16)32 ) {
+ arg.msw = arg.lsw ;
+ arg.lsw = 0L ;
+
+ } else if( shift_count > (INT16)32 ) {
+ arg.msw = arg.lsw ;
+ arg.msw <<= ( shift_count - (INT16)32 ) ;
+ arg.lsw = 0L ;
+
+ } else {
+ UINT32 t = ( 1L << ( shift_count - (INT16)1 ) ) ;
+ INT16 i ;
+
+ arg.msw <<= shift_count ;
+ for( i = 0; i < shift_count; i++ ) {
+ if( arg.lsw & 0x80000000L ) {
+ /* We need to place this bit in the appropriate
+ position in the msw.
+ */
+ arg.msw |= t ;
+ }
+ t >>= (INT16)1 ;
+ arg.lsw <<= (INT16)1 ;
+ }
+ }
+ }
+ break ;
+
+ default:
+ break ;
+
+ } /* End of switch */
+
+ return( arg ) ;
+}
+
+
+/**/
+
+/* Some macros to make life easier for the different bit wise functions */
+
+#define U64_CLR( arg, mask ) \
+ U64_Btop( (arg), ( U64_Lsw( mask ) ), ( U64_Msw( mask ) ), CLR_64BIT, 0 )
+
+#define U64_SET( arg, mask ) \
+ U64_Btop( (arg), ( U64_Lsw( mask ) ), ( U64_Msw( mask ) ), SET_64BIT, 0 )
+
+#define U64_XOR( arg, mask ) \
+ U64_Btop( (arg), ( U64_Lsw( mask ) ), ( U64_Msw( mask ) ), XOR_64BIT, 0 )
+
+#define U64_OR( arg, mask ) \
+ U64_Btop( (arg), ( U64_Lsw( mask ) ), ( U64_Msw( mask ) ), OR_64BIT, 0 )
+
+#define U64_AND( arg, mask ) \
+ U64_Btop( (arg), ( U64_Lsw( mask ) ), ( U64_Msw( mask ) ), AND_64BIT, 0 )
+
+#define U64_NOT( arg, mask ) \
+ U64_Btop( (arg), ( U64_Lsw( mask ) ), ( U64_Msw( mask ) ), NOT_64BIT, 0 )
+
+/* Shift operations */
+#define U64_SHL( arg, shift_count ) \
+ U64_Btop( (arg), 0L, 0L, SHL_64BIT, (shift_count) )
+
+#define U64_SHR( arg, shift_count ) \
+ U64_Btop( (arg), 0L, 0L, SHR_64BIT, (shift_count) )
+
+
+/**/
+
+/**
+
+ Name: U64_Init()
+
+ Description: A fast 'constructor' for a UINT64. Takes two UINT32 args
+ and initializes a temporary UINT64. Returns a UINT64.
+
+ Entry: UINT32 lsw
+
+ UINT32 msw
+
+ Returns: UINT64 value that consists of msw and lsw.
+
+**/
+
+UINT64 U64_Init(
+ UINT32 lsw, /* Least significant 32 bits */
+ UINT32 msw ) /* Most significnat 32 bits */
+{
+ UINT64 result ;
+
+ result.lsw = lsw ;
+ result.msw = msw ;
+ return( result ) ;
+}
+
+
+/**/
+/**
+
+ Name: U64_Atoli()
+
+ Description: A slower, but more flexible, 'constructor' for a UINT64.
+ Takes a 'C' string that may be a Decimal, Hex or Octal
+ number and converts it to a UINT64.
+
+ Entry: CHAR_PTR arg
+
+ BOOLEAN_PTR status
+
+ Returns: UINT64 value that is the 64 bit value represented by the
+ 'C' string. Sets *status to TRUE if there was no error
+ during the conversion. Uses standard C conversion
+ functions to do the work where possible.
+
+ NOTE: If the number of Hex digits is > 16 it is an error.
+ If the number of Dec digits is > 20 it is an error.
+ If the number of Oct digits is > 22 it is an error.
+
+**/
+
+UINT64 U64_Atoli(
+ CHAR_PTR arg, /* Pointer to TEXT('C') string that is the Decimal,
+ Hex or Octal representation of the desired
+ 64 bit number.
+ */
+ BOOLEAN_PTR status ) /* Pointer to completion status */
+{
+ UINT64 result ;
+ CHAR buffer[32] ; /* Biggest number of digits */
+
+ *status = TRUE ;
+ *buffer = TEXT('\0') ;
+ result.lsw = 0L ;
+ result.msw = 0L ;
+
+ if( *arg == TEXT('0') && toupper(*(arg+1)) == TEXT('X') ) {
+ if( strlen( arg + 2 ) > 16 ) { /* If we are too many digits croak */
+ *status = FALSE ;
+ return( result ) ;
+ }
+
+ /* Assume that it is hex for now */
+ if( strlen( arg + 2 ) < 9 ) {
+ result.msw = 0L ;
+ sscanf( arg, TEXT("%lX"), &result.lsw ) ;
+
+ } else {
+ /* We have to do 64 bit conversion. The lower 8 bytes go
+ into lsw and the upper n - 8 bytes go into msw.
+ */
+
+ INT tlen = strlen( arg + 2 ) ; /* Get number of digits */
+
+ strcpy( buffer, TEXT("0x") ) ;
+ strcat( buffer, arg + 2 + (tlen - 8) ) ;
+
+ sscanf( buffer, TEXT("%lX"), &result.lsw ) ;
+ strcpy( buffer, arg ) ;
+ *( buffer + 2 + ( tlen - 8 ) ) = TEXT('\0') ;
+ sscanf( buffer, TEXT("%lX"), &result.msw ) ;
+ }
+
+ } else if( *arg == TEXT('0') ) {
+ /* Assume Octal */
+ if( strlen( arg + 1 ) > 22 ) { /* If we are too many digits croak */
+ *status = FALSE ;
+ return( result ) ;
+ }
+ if( strlen( arg + 1 ) < 11 ||
+ ( strlen( arg + 1 ) == 11 && *( arg + 1 ) < TEXT('4') ) ) {
+
+ /* Only 32 bit so it is easy */
+ result.msw = 0L ;
+ sscanf( arg, TEXT("%lO"), &result.lsw ) ;
+
+ } else {
+ /* We have to do 64 bit conversion. */
+ INT tlen ;
+ CHAR temp[2] ;
+ CHAR temp1[2] ;
+
+ temp[0] = 0 ;
+ temp[1] = 0 ;
+ temp1[0] = 0 ;
+ temp1[1] = 0 ;
+ tlen = strlen( arg + 1 ) ; /* Get number of digits */
+ strcpy( buffer, TEXT("0") ) ;
+
+ /* Get the high order octal digit */
+ *temp = arg[ 1 + (tlen - 11)] ;
+
+ /* If this is more than 2 bits we need to keep the low order
+ 2 bits for the lsw and save the high order bit to be added
+ to the bottom of the msw.
+ */
+ if( *temp > TEXT('3') ) {
+ *temp1 = *temp & (CHAR)0x03;
+ *temp1 = *temp1 + (CHAR)TEXT('0') ;
+ strcat( buffer, temp1 ) ;
+
+ if( ( *temp & 0x04 ) == 0x04 ) {
+ *temp = TEXT('1') ;
+ }
+
+ } else {
+ *temp = TEXT('\0') ;
+ }
+
+ strcat( buffer, arg + 1 + ( tlen - 11 ) ) ;
+ sscanf( buffer, TEXT("%lO"), &result.lsw ) ;
+ strcpy( buffer, arg ) ;
+ buffer[ 1 + ( tlen - 11 ) ] = TEXT('\0') ;
+ sscanf( buffer, TEXT("%lO"), &result.msw ) ;
+
+ if( *temp != TEXT('\0') ) {
+ result.msw <<= 1 ; /* Shift left by 1 */
+ result.msw |= 1L ; /* Add in LSBit from lsw MSBit */
+
+ } else {
+ result.msw <<= 1 ;
+ result.msw &= ~0x00000001L ; /* Kill the low order bit */
+ }
+ }
+
+ } else { /* Must be 64 bit decimal conversion */
+
+ /* Here we must do real work since we don't have as easy a way to
+ scale and convert decimal numbers.
+ */
+
+ UINT64 factor ;
+ UINT64 temp ;
+ UINT64 ten ;
+ BOOLEAN stat ;
+ INT16 arg_index = strlen( arg ) ;
+
+ result.lsw = 0 ;
+ result.msw = 0 ;
+ factor.lsw = 10L ;
+ factor.msw = 0 ;
+ ten.lsw = 10L ;
+ ten.msw = 0 ;
+
+ if( arg_index > 20 ) {
+ *status = FALSE ;
+ return( result ) ;
+ }
+
+ if( arg_index <= 0 ) {
+ *status = TRUE ;
+ return( result ) ;
+ }
+
+ arg_index-- ; /* Index to the last byte in the string LSB */
+
+ if( isdigit( arg[arg_index] ) ) {
+ result.lsw = arg[arg_index] - TEXT('0') ;
+
+ } else {
+ *status = FALSE ;
+ return( result ) ;
+ }
+
+ --arg_index ;
+ while( arg_index >= 0 ) {
+ if( isdigit( arg[arg_index] ) ) {
+ temp.lsw = arg[arg_index] - TEXT('0') ;
+ } else {
+ *status = FALSE ;
+ return( result ) ;
+ }
+ temp.msw = 0 ;
+ result = U64_Add( result, U64_Mult( temp, factor ), &stat ) ;
+ factor = U64_Mult( factor, ten ) ;
+ --arg_index ;
+ }
+ /* When we get here we should have the conversion in result */
+ *status = TRUE ; /* Should be fine now */
+
+ }
+
+ return( result ) ;
+}
+
+
+/**/
+
+CHAR_PTR mstrncat( CHAR_PTR target, CHAR_PTR source, INT num )
+{
+ INT16 i ;
+
+ i = strlen( target ) ;
+
+ while( num ) {
+ target[i] = *source ;
+ ++i;
+ ++source ;
+ --num ;
+ }
+ target[i] = TEXT('\0') ;
+ return( target ) ;
+}
+
+
+/**/
+/**
+
+ Name: U64_Litoa()
+
+ Description: Convert a UINT64 argument to a 'C' ASCII string.
+
+ Entry: UINT64 arg 64 bit value to be converted.
+
+ CHAR_PTR string Pointer to char array to hold result.
+
+ INT16 base Number base to convert to. 8 - Octal,
+ 10 - decimal, 16 - Hex.
+
+ BOOLEAN_PTR status Holds status of conversion operation.
+
+ Returns: CHAR_PTR to string. The string will have the ASCII
+ representation of arg and *status will be set to TRUE
+ unless there is an error. If there is an error *string
+ will be set to '\0' and *status will be set to FALSE.
+
+ NOTE: Currently up to 64 bit values may be handled in Octal
+ and Hex and up to 32 bit values in decimal. *status
+ will be set FALSE if a decimal value greater than 32
+ bits would result from the conversion.
+
+**/
+
+CHAR_PTR U64_Litoa(
+ UINT64 arg, /* 64 bit argument to be converted. */
+ CHAR_PTR string, /* Pointer to character array to hold result */
+ INT16 base, /* Base to convert to. Dec, Hex, Oct. */
+ BOOLEAN_PTR status ) /* Pointer to completion status */
+{
+ CHAR work_str[32] ; /* Holds comma'fied string */
+ INT16 index ;
+ BOOLEAN did_decimal = FALSE ;
+
+ *status = TRUE ;
+
+ if( string != NULL ) {
+ *string = TEXT('\0') ;
+ } else {
+ *status = FALSE ;
+ return( NULL ) ;
+ }
+
+
+ if( arg.msw != 0L ) {
+ if( base == 16 ) {
+ sprintf( string, TEXT("0x%lx%08.8lx"), arg.msw, arg.lsw ) ;
+
+ } else if( base == 8 ) {
+ INT temp;
+
+ temp = (INT16)arg.msw & 0x1 ;
+ temp <<= 2 ;
+ temp |= (INT16)((arg.lsw & 0xC0000000L) >> 30) ;
+
+ arg = U64_CLR( arg, U64_Init( 0xC0000000, 0 ) ) ;
+ arg.msw >>= 1 ; /* Shift off low order bit */
+
+ sprintf( string, TEXT("0%lo%d%lo"), arg.msw, temp, arg.lsw ) ;
+
+ } else {
+
+ UINT64 temp ;
+ UINT64 remainder ;
+ BOOLEAN stat ;
+ INT16 i ;
+
+ /* Find the first power of ten which is smaller than arg. */
+ for( i = 0; i < 19; i++ ) {
+ if( U64_LT( mw_powers[i], arg ) ) {
+ break ;
+ }
+ }
+
+ /* Start dividing by powers of ten, placing the result in
+ the string.
+ */
+ for( ; i < 19; i++ ) {
+ temp = U64_Div( arg, mw_powers[i], &remainder, &stat ) ;
+ sprintf ( &string[strlen(string)], TEXT("%ld"), temp.lsw ) ;
+ arg = remainder ; /* Use the remainder */
+ }
+
+ /* Must add the remainder in, this is the Least
+ significant digit.
+ */
+ sprintf ( &string[strlen(string)], TEXT("%ld"), arg.lsw ) ;
+ did_decimal = TRUE ;
+ *status = TRUE ;
+ }
+
+ } else { /* Process 16 and 32 bit flavors (lsw only) */
+ if( base == 16 ) {
+ sprintf( string, TEXT("0x%lx"), arg.lsw ) ;
+ } else if ( base == 10 ) {
+ did_decimal = TRUE ;
+ sprintf( string, TEXT("%lu"), arg.lsw ) ;
+ } else {
+ sprintf( string, TEXT("0%lo"), arg.lsw ) ;
+ }
+ }
+
+ /* If we wanted commas and we did decimal numbers */
+ if( commas && did_decimal ) {
+ INT16 t ;
+
+ if( strlen( string ) > 3 ) {
+
+ /* Need a copy of the string to work with */
+ strcpy( work_str, string ) ;
+ memset( string, 0, strsize( work_str ) ) ;
+
+ /* Now start with the LSB and work backwards, every 3rd
+ char insert a ','.
+ */
+ index = 0 ;
+ t = strlen( work_str ) % 3 ;
+ if( t == 0 ) {
+
+ /* Need to copy 3 bytes, add ',' and repeat until done */
+ strncpy( string, work_str, 3 ) ;
+ strcat( string, TEXT(",") ) ;
+ index += 3 ;
+
+ } else if( t == 2 ) {
+ strncpy( string, work_str, 2 ) ;
+ strcat( string, TEXT(",") ) ;
+ index += 2 ;
+
+ } else if( t == 1 ) {
+ strncpy( string, work_str, 1 ) ;
+ strcat( string, TEXT(",") ) ;
+ index++ ;
+ }
+
+ while( index <= (INT16)( strlen( work_str ) - 3 ) ) {
+
+ mstrncat( string, &work_str[index], 3 ) ;
+
+ if( index != (INT16)( strlen( work_str ) - 3 ) ) {
+ strcat( string, TEXT(",") ) ;
+ }
+
+ index += 3 ;
+ }
+ }
+ }
+
+ return( string ) ;
+}
+
+
+/**/
+/**
+
+ Name: bshift()
+
+ Description: Binary shift for 64 Bit numbers.
+
+ Entry: UINT16_PTR src Pointer to the bytes to be shifted.
+
+ INT16 num Number of bits to be shifted.
+
+ UINT16_PTR dest Pointer to the location to hold the
+ result of the shift operation.
+
+ INT16 carry Initial Carry to be factored into the
+ shift operation.
+
+ INT16 size Number of bytes in source and dest.
+
+ Returns: INT16 Carry out from shift. The result of the shift is
+ placed at the location pointed to by dest.
+
+**/
+
+static INT16 bshift(
+ UINT16_PTR src, /* Source bytes to be shifted */
+ INT num, /* Number of bits to shift */
+ UINT16_PTR dest, /* Destination storage */
+ UINT carry, /* Initial carry to be shifted in */
+ INT size ) /* Number of bytes in src and dest */
+{
+ unsigned long accumulator ;
+ INT16 i ;
+
+ if( num == 0 ) {
+ memmove( dest, src, size * sizeof( *src ) ) ;
+ return( 0 ) ;
+ }
+
+ accumulator = carry ;
+ for( i = little_end(size) ; not_msd( i, size ) ; i = next_msd( i ) ) {
+ accumulator |= (unsigned long) src[i] << num ;
+ dest[i] = (UINT16)(accumulator & mask_low16) ;
+ accumulator = accumulator >> 16 ;
+ }
+ return( (UINT16)accumulator ) ;
+}
+
+
+/**/
+/**
+
+ Name: binary_divide()
+
+ Description: Low level binary division for 2 64 Bit numbers.
+
+ Entry: UINT16_PTR arg1 Pointer to the 64 bit (quad
+ word) dividend. Treated as an
+ array of 16 bit entities to
+ ease the manipulations.
+
+ UINT16_PTR arg2 Pointer to the 64 bit (quad
+ word) divisor. Handled as an
+ array of 16 bit entities to
+ ease the manipulations.
+
+ UINT16_PTR quotient Pointer to the 64 bit quotient
+ (result) of the division. Also
+ handled as an array of 16 bit
+ entities.
+
+ UINT16_PTR remainder Pointer to the 64 bit remainder
+ of the division. You guessed
+ it, handled as an array of 16
+ bit entities.
+
+ INT16 arg1_size Size of arg1 in bytes.
+
+ INT16 arg2_size Size of arg2 in bytes.
+
+ Returns: UINT16 status of operation. The result of the division
+ is placed at the location pointed to by quotient and
+ remainder.
+
+**/
+
+INT16 binary_divide(
+ UINT16_PTR arg1,
+ UINT16_PTR arg2,
+ UINT16_PTR quotient,
+ UINT16_PTR remainder,
+ INT arg1_size,
+ INT arg2_size )
+{
+ UINT32 qhat ;
+ UINT32 rhat ;
+ UINT32 accumulator ;
+ UINT16 buff1[16] ; /* holds arg1_size BYTES (currently max 32) */
+ UINT16 buff2[8] ; /* holds arg2_size BYTES (currently max 16) */
+ UINT16_PTR temp1 = buff1 ;
+ UINT16_PTR temp2 = buff2 ;
+ UINT16_PTR u0 ;
+ UINT16_PTR u1 ;
+ UINT16_PTR u2 ;
+ UINT16_PTR v0 ;
+ INT16 d ;
+ INT16 qn ;
+ INT16 i ;
+ INT16 j ;
+
+ /* If this assert fails, you need to increase the size of the buff
+ arrays
+ */
+ msassert( arg1_size <= 32 && arg2_size <= 16 ) ;
+
+ arg1_size /= sizeof( *arg1 ) ;
+ arg2_size /= sizeof( *arg2 ) ;
+ qn = arg1_size - arg2_size ;
+
+ /* Remove leading zero digits from divisor, and the same number of
+ digits (which must be zero) from dividend.
+ */
+
+ while( arg2[big_end(arg2_size)] == 0 ) {
+ remainder[big_end( arg2_size )] = 0 ;
+
+ arg1 += little_end( 2 ) ;
+ arg2 += little_end( 2 ) ;
+ remainder += little_end( 2 ) ;
+ arg1_size-- ;
+ arg2_size-- ;
+
+ /* Check for zero divisor. */
+ if( arg2_size == 0 ) {
+ return( U64_DIVZ ) ;
+ }
+ }
+
+ /* If divisor is a single digit, do short division. */
+
+ if( arg2_size == 1 ) {
+ accumulator = arg1[big_end( arg1_size )] ;
+ arg1 += little_end( 2 ) ;
+ for( j = big_end( qn ) ; not_lsd( j, qn ) ; j = next_lsd( j ) ) {
+ accumulator = (accumulator << 16) | arg1[j] ;
+ quotient[j] = (UINT16)(accumulator / *arg2) ;
+ accumulator = accumulator % *arg2 ;
+ }
+ *remainder = (UINT16)(accumulator) ;
+ return( U64_OK ) ;
+ }
+
+ /* Gotta do long division. Shift divisor and dividend left until the
+ high bit of the divisor becomes 1.
+ */
+
+ for( d = 0 ; d < 16 ; d++ ) {
+ if( arg2[big_end( arg2_size )] & ( 1 << ( 16 - 1 - d ) ) ) {
+ break ;
+ }
+ }
+
+ bshift ( arg1, d, temp1, 0, arg1_size ) ;
+ bshift ( arg2, d, temp2, 0, arg2_size ) ;
+
+ /* Get pointers to the high dividend and divisor digits. */
+
+ u0 = temp1 + big_end( arg1_size ) - big_end( qn ) ;
+ u1 = next_lsd( u0 ) ;
+ u2 = next_lsd( u1 ) ;
+ temp1 += little_end( 2 ) ;
+
+ v0 = temp2 + big_end( arg2_size ) ;
+
+ /* Main loop: find a quotient digit, multiply it by the divisor, and
+ subtract that from the dividend, shifted over the right amount.
+ */
+
+ for( j = big_end( qn ) ; not_lsd( j, qn ) ; j = next_lsd( j ) ) {
+
+ /* Quotient digit initial guess: high 2 dividend digits over high
+ divisor digit.
+ */
+ if( u0[j] == *v0 ) {
+ qhat = B - 1 ;
+ rhat = (UINT32) *v0 + u1[j] ;
+
+ } else {
+ UINT32 numerator = ((UINT32)u0[j] << 16) | u1[j] ;
+
+ qhat = numerator / *v0 ;
+ rhat = numerator % *v0 ;
+ }
+
+ /* Now get the quotient right for high 3 dividend digits over high
+ 2 divisor digits.
+ */
+
+ while( rhat < B &&
+ qhat * *next_lsd (v0) > ( ( rhat << 16 ) | u2[j] ) ) {
+
+ qhat -= 1 ;
+ rhat += *v0 ;
+ }
+
+ /* Multiply quotient by divisor, subtract from dividend. */
+
+ accumulator = 0 ;
+ for( i = little_end( arg2_size ) ; not_msd( i, arg2_size ) ;
+ i = next_msd( i ) ) {
+
+ accumulator += (UINT32)(temp1 + j)[i] - temp2[i] * qhat ;
+ (temp1 + j)[i] = (UINT16)(accumulator & mask_low16) ;
+ if(accumulator < B) {
+ accumulator = 0 ;
+ } else {
+ accumulator = (accumulator >> 16) | -B ;
+ }
+ }
+
+ quotient[j] = (UINT16)(qhat) ;
+
+ /* Quotient may have been too high by 1. If dividend went
+ negative, decrement the quotient by 1 and add the divisor back.
+ */
+
+ if( (INT32)(accumulator + u0[j]) < 0 ) {
+ quotient[j] -= 1 ;
+ accumulator = 0 ;
+ for( i = little_end( arg2_size ) ; not_msd( i, arg2_size ) ;
+ i = next_msd( i ) ) {
+
+ accumulator += (UINT32)(temp1 + j)[i] + temp2[i] ;
+ (temp1 + j)[i] = (UINT16)(accumulator & mask_low16) ;
+ accumulator = accumulator >> 16 ;
+ }
+ }
+ }
+
+ /* Now the remainder is what's left of the dividend, shifted right by
+ by the amount of the normalizing left shift at the top.
+ */
+
+ remainder[big_end( arg2_size )] =
+ bshift( temp1 + 1 + little_end( j - 1 ), 16 - d,
+ remainder + little_end( 2 ),
+ temp1[little_end( arg1_size - 1 )] >> d,
+ arg2_size - 1 ) ;
+
+ return( U64_OK ) ;
+}
+
+
+/**/
+
+/* Some defines for status returns from the Division and Mod operations */
+
+#define U64_OK 0
+#define U64_BAD_DIV 1
+#define U64_OVRFL 2
+#define U64_UNDFL 3
+#define U64_DIVZ 4
+
+/**
+
+ Name: U64_Div()
+
+ Description: Divide 2 64 Bit numbers and return result, remainder and
+ status of operation.
+
+ Entry: UINT64 arg1 The 64 bit (quad word) dividend.
+
+ UINT64 arg2 The 64 bit (quad word) divisor.
+
+ UINT64_PTR remainder The 64 bit remainder of the
+ division.
+
+ INT_PTR status One of the defined values
+ reporting the status of the
+ division.
+
+ Returns: UINT64 value that is the result of the division.
+ (arg1 / arg2), sets *remainder to the UINT64 value of
+ the remainder of the division operation and sets *status
+ to U64_OK if no error otherwise sets *status to one of
+ the defined error values.
+
+**/
+
+UINT64 U64_Div(
+ UINT64 arg1, /* 64 bit dividend */
+ UINT64 arg2, /* 64 bit divisor */
+ UINT64_PTR remainder, /* Pointer to 64 bit remainder */
+ INT16_PTR status ) /* Pointer to completion status */
+{
+ UINT32 accumulator[2][2] ; /* Allow for a 128 bit accumulator */
+ UINT32 bwork[2] ;
+ UINT32 quotient[2] ;
+ UINT32 rwork[2] ;
+ long_64 work ;
+ long_64 temp1 ;
+ long_64 temp2 ;
+
+ temp1.big_long = arg1 ;
+ temp2.big_long = arg2 ;
+
+ accumulator[HIGH][HIGH] = 0 ;
+ accumulator[HIGH][LOW] = 0 ;
+ accumulator[LOW][HIGH] = temp1.s.high ;
+ accumulator[LOW][LOW] = temp1.s.low ;
+ bwork[HIGH] = temp2.s.high ;
+ bwork[LOW] = temp2.s.low ;
+
+ *status = binary_divide( (UINT16_PTR)&accumulator[0][0],
+ (UINT16_PTR)bwork, (UINT16_PTR)quotient,
+ (UINT16_PTR)rwork, sizeof( accumulator ),
+ sizeof( bwork ) ) ;
+
+ remainder->lsw = rwork[LOW] ; /* Update the remainder */
+ remainder->msw = rwork[HIGH] ;
+
+ work.s.high = quotient[HIGH] ;
+ work.s.low = quotient[LOW] ;
+
+ return( work.big_long ) ;
+}
+
+
+/**/
+/**
+
+ Name: U64_Mod()
+
+ Description: Mod function. arg1 % arg2. Returns UINT64 result that
+ is the remainder of the division.
+
+ Entry: UINT64 arg1
+
+ UINT64 arg2
+
+ INT16_PTR status
+
+ Returns: UINT64 value that is the remainder of arg1 / arg2. Sets
+ *status to U64_OK if no error else sets *status to a
+ defined error value.
+
+**/
+
+UINT64 U64_Mod(
+ UINT64 arg1, /* 64 bit dividend argument */
+ UINT64 arg2, /* 64 bit divisor argument */
+ INT16_PTR status ) /* Pointer to completion status */
+{
+ UINT32 accumulator[2][2] ; /* Allow for a 128 bit accumulator */
+ UINT32 bwork[2] ;
+ UINT32 quotient[2] ;
+ UINT32 remainder[2] ;
+ long_64 work ;
+ long_64 temp1 ;
+ long_64 temp2 ;
+
+ temp1.big_long = arg1 ;
+ temp2.big_long = arg2 ;
+
+ accumulator[HIGH][HIGH] = 0 ;
+ accumulator[HIGH][LOW] = 0 ;
+ accumulator[LOW][HIGH] = temp1.s.high ;
+ accumulator[LOW][LOW] = temp1.s.low ;
+ bwork[HIGH] = temp2.s.high ;
+ bwork[LOW] = temp2.s.low ;
+
+ /* Do the division */
+ *status = binary_divide( (UINT16_PTR)accumulator, (UINT16_PTR)bwork,
+ (UINT16_PTR)quotient, (UINT16_PTR)remainder,
+ sizeof( accumulator ), sizeof( bwork ) ) ;
+
+ work.s.high = remainder[HIGH] ;
+ work.s.low = remainder[LOW] ;
+
+ return( work.big_long ) ;
+}
+
+
+/**/
+/**
+
+ Name: binary_mult()
+
+ Description: Binary 64 bit multiplication. Places the result of the
+ multiplication of arg1 * arg2 in result.
+
+ Entry: UINT64 arg1 Treated as an array of 16 bit
+ entities to ease manipulation.
+
+ UINT64 arg2 Treated as an array of 16 bit
+ entities to ease manipulation.
+
+ Returns: Nothing. The result of the multiplication is placed in
+ memory pointed to by result.
+
+**/
+
+static VOID binary_mult(
+ UINT16_PTR arg1,
+ UINT16_PTR arg2,
+ UINT16_PTR result,
+ INT m,
+ INT n )
+{
+ INT16 i ;
+ INT16 j ;
+ UINT32 accumulator ;
+
+ memset( result, 0, ( m + n ) ) ; /* Zero the bytes */
+
+ m /= sizeof( *arg1 ) ;
+ n /= sizeof( *arg2 ) ;
+
+ for( j = little_end( n ) ; not_msd( j, n ) ; j = next_msd( j ) ) {
+
+ UINT16_PTR c1 = result + j + little_end( 2 ) ;
+
+ accumulator = 0 ;
+ for( i = little_end( m ) ; not_msd( i, m ) ; i = next_msd( i ) ) {
+
+ /* Widen before arithmetic to avoid loss of high bits. */
+ accumulator += (UINT32)arg1[i] * arg2[j] + c1[i] ;
+ c1[i] = (UINT16)(accumulator & mask_low16) ;
+ accumulator = accumulator >> 16 ;
+ }
+ c1[i] = (UINT16)(accumulator) ;
+ }
+}
+
+
+/**/
+/**
+
+ Name: U64_Mult()
+
+ Description: 64 bit multiply function. arg1 * arg2.
+
+ Entry: UINT64 arg1
+
+ UINT64 arg2
+
+ Returns: UINT64 value that is the result of arg1 * arg2.
+
+**/
+
+UINT64 U64_Mult(
+ UINT64 arg1,
+ UINT64 arg2 )
+{
+ INT32 accumulator[2] ;
+ INT32 bwork[2] ;
+ INT32 c[2][2] ;
+ long_64 work ;
+ long_64 temp1 ;
+ long_64 temp2 ;
+
+ temp1.big_long = arg1 ;
+ temp2.big_long = arg2 ;
+
+ accumulator[HIGH] = temp1.s.high ;
+ accumulator[LOW] = temp1.s.low ;
+ bwork[HIGH] = temp2.s.high ;
+ bwork[LOW] = temp2.s.low ;
+
+ /* Do the multiply */
+ binary_mult( (UINT16_PTR)accumulator, (UINT16_PTR)bwork,
+ (UINT16_PTR)c, sizeof( accumulator ), sizeof( bwork ) ) ;
+
+ work.s.high = c[LOW][HIGH] ;
+ work.s.low = c[LOW][LOW] ;
+
+ return( work.big_long ) ;
+}
+
+
+/**
+
+ Name: U64_Commas()
+
+ Description: Specifies if the string returned by Litoa() for decimal
+ conversions has commas (',') in it. If action is set to
+ TRUE then the resulting decimal string will be of the
+ form 'nnn,nnn,nnn' If action is set to FALSE then the
+ resulting decimal string will be of the form
+ 'nnnnnnnnn'. Octal and Hex conversions are not affected.
+ The default is FALSE (no commas in the string).
+
+ Entry: BOOLEAN action
+
+
+ Returns: Nothing. Sets and internal flag that tells Litoa() to
+ include or omit commas from the converted decimal string.
+
+**/
+
+VOID U64_Commas(
+ BOOLEAN action )
+{
+ commas = action ;
+}
+
+
+/**/
+
+#ifdef STAND_ALONE
+
+/**
+
+ Name: main()
+
+ Description: Used to test this module in a stand alone mode. I.e.
+ without needing to link with another application.
+
+ Entry: None.
+
+ Returns: Nothing. Prints results to stdin.
+
+**/
+
+VOID main()
+{
+ UINT64 t1, t2, t3, t4, save_t1, save_t2 ;
+ INT16 RetVal ;
+ BOOLEAN bRetVal ;
+ CHAR buffer[64], buffer2[64] ;
+ UINT64 arg1, arg2, result, remainder ;
+ INT16 status ;
+
+#ifdef INTER_ACT
+
+ CHAR value[128] ;
+
+ U64_Commas( TRUE ) ; /* Want commas in dec out strings */
+ while( 1 ) {
+ printf( TEXT("Enter the number to be converted (Enter alone to exit) >") ) ;
+
+ gets( value ) ;
+ if( *value == TEXT('\0') ) {
+ exit(1) ;
+ }
+ printf( TEXT("Converting %s to UINT64\n"), value ) ;
+ t1 = U64_Atoli( value, &bRetVal ) ;
+
+ printf( TEXT("Raw t1 = %08lX:%08lX\n"), t1.msw, t1.lsw ) ;
+ if( bRetVal == FALSE ) {
+ printf( TEXT("Error returned from Atoli()\n") ) ;
+ }
+
+ printf( TEXT("t1 = %s Decimal\n"), U64_Litoa( t1, buffer2, 10, &bRetVal ) ) ;
+ if( bRetVal == FALSE ) {
+ printf( TEXT("Error returned from Litoa()\n") ) ;
+ }
+ printf( TEXT("t1 = %s Octal\n"), U64_Litoa( t1, buffer2, 8, &bRetVal ) ) ;
+ if( bRetVal == FALSE ) {
+ printf( TEXT("Error returned from Litoa()\n") ) ;
+ }
+ printf( TEXT("t1 = %s Hex\n"), U64_Litoa( t1, buffer2, 16, &bRetVal ) ) ;
+ if( bRetVal == FALSE ) {
+ printf( TEXT("Error returned from Litoa()\n") ) ;
+ }
+ printf( TEXT("\n") ) ;
+ }
+
+#else /* INTER_ACT not defined */
+
+ t1 = U64_Atoli( TEXT("1000000000"), &bRetVal ) ;
+ printf( TEXT("t1 = %08lX:%08lX\n"), t1.msw, t1.lsw ) ;
+ if( bRetVal == FALSE ) {
+ printf( TEXT("Error returned from Atoli()\n") ) ;
+ }
+
+ printf( TEXT("Converting 1000000000003 to UINT64\n") ) ;
+ t1 = U64_Atoli( TEXT("1000000000003"), &bRetVal ) ;
+ printf( TEXT("t1 = %08lX:%08lX\n"), t1.msw, t1.lsw ) ;
+ if( bRetVal == FALSE ) {
+ printf( TEXT("Error returned from Atoli()\n") ) ;
+ }
+
+ printf( TEXT("t1 = %s\n"), U64_Litoa( t1, buffer2, 10, &bRetVal ) ) ;
+ if( bRetVal == FALSE ) {
+ printf( TEXT("Error returned from Litoa()\n") ) ;
+ }
+
+
+
+ arg1.msw = 0x02 ;
+ arg1.lsw = 0x04 ;
+
+ arg2.msw = 0x01 ;
+ arg2.lsw = 0x00 ;
+
+ printf( TEXT("Dividing %08lX:%08lXh by %08lX:%08lX\n"),
+ arg1.msw, arg1.lsw, arg2.msw, arg2.lsw ) ;
+
+ result = U64_Div( arg1, arg2, &remainder, &status ) ;
+
+ printf( TEXT("Result is %08lX:%08lXh\n"), result.msw, result.lsw ) ;
+
+
+ arg1.msw = 0x01 ;
+ arg1.lsw = 0x0000 ;
+
+ arg2.msw = 0x00 ;
+ arg2.lsw = 0x002 ;
+
+ printf( TEXT("Dividing %08lX:%08lXh by %08lX:%08lX\n"),
+ arg1.msw, arg1.lsw, arg2.msw, arg2.lsw ) ;
+
+ result = U64_Div( arg1, arg2, &remainder, &status ) ;
+
+ printf( TEXT("Result is %08lX:%08lXh\n"), result.msw, result.lsw ) ;
+
+ printf( TEXT("Mod of %08lX:%08lXh by %08lX:%08lX\n"),
+ arg1.msw, arg1.lsw, arg2.msw, arg2.lsw ) ;
+
+ result = U64_Mod( arg1, arg2, &status ) ;
+
+ printf( TEXT("Result is %08lX:%08lXh\n"), result.msw, result.lsw ) ;
+
+ arg1.msw = 0x01 ;
+ arg1.lsw = 0x0000 ;
+
+ arg2.msw = 0x00 ;
+ arg2.lsw = 0x003 ;
+
+ printf( TEXT("Dividing %08lX:%08lXh by %08lX:%08lX\n"),
+ arg1.msw, arg1.lsw, arg2.msw, arg2.lsw ) ;
+
+ result = U64_Div( arg1, arg2, &remainder, &status ) ;
+
+ printf( TEXT("Result is %08lX:%08lXh\n"), result.msw, result.lsw ) ;
+
+ printf( TEXT("Mod of %08lX:%08lXh by %08lX:%08lX\n"),
+ arg1.msw, arg1.lsw, arg2.msw, arg2.lsw ) ;
+
+ result = U64_Mod( arg1, arg2, &status ) ;
+
+ printf( TEXT("Result is %08lX:%08lXh\n\n"), result.msw, result.lsw ) ;
+
+
+ arg1.msw = 0x01 ;
+ arg1.lsw = 0x0000 ;
+
+ arg2.msw = 0x00 ;
+ arg2.lsw = 0x003 ;
+
+ printf( TEXT("Mult of %08lX:%08lXh by %08lX:%08lX\n"),
+ arg1.msw, arg1.lsw, arg2.msw, arg2.lsw ) ;
+ printf( TEXT("%s dec * %s dec\n"), U64_Litoa( arg1, buffer2, 10, &bRetVal ),
+ U64_Litoa( arg2, buffer2, 10, &bRetVal ) ) ;
+
+ result = U64_Mult( arg1, arg2 ) ;
+
+
+ printf( TEXT("Result is %08lX:%08lXh\n"), result.msw, result.lsw ) ;
+
+
+ t1 = U64_Atoli( TEXT("0x0000000F80000001"), &bRetVal ) ;
+ if( U64_Stest( t1, TEXT("0x0000000000000000") ) != 0L ) {
+ printf( TEXT("Bits are set\n") ) ;
+ } else {
+ printf( TEXT("Bits are not set\n") ) ;
+ }
+
+ t1 = U64_Atoli( TEXT("0x0000000F80000001"), &bRetVal ) ;
+ printf( TEXT("t1 = %sH\n"), U64_Litoa( t1, buffer2, 16, &bRetVal ) ) ;
+ if( bRetVal == FALSE ) {
+ printf( TEXT("Error returned from Litoa()\n") ) ;
+ }
+
+ printf( TEXT("t1 = %sD\n"), U64_Litoa( t1, buffer2, 10, &bRetVal ) ) ;
+ if( bRetVal == FALSE ) {
+ printf( TEXT("Error returned from Litoa()\n") ) ;
+ }
+ printf( TEXT("t1 = %sO\n"), U64_Litoa( t1, buffer2, 8, &bRetVal ) ) ;
+ if( bRetVal == FALSE ) {
+ printf( TEXT("Error returned from Litoa()\n") ) ;
+ }
+
+ t1 = U64_Atoli( TEXT("0x0000000000000001"), &bRetVal ) ;
+ printf( TEXT("t1 = %sH\n"), U64_Litoa( t1, buffer2, 16, &bRetVal ) ) ;
+ if( bRetVal == FALSE ) {
+ printf( TEXT("Error returned from Litoa()\n") ) ;
+ }
+
+ t1 = U64_Atoli( TEXT("0x000000FFF0000000001"), &bRetVal ) ;
+ if( bRetVal == FALSE ) {
+ printf( TEXT("Error returned from Atoli()\n") ) ;
+ }
+ printf( TEXT("t1 = %sH\n"), U64_Litoa( t1, buffer2, 16, &bRetVal ) ) ;
+ if( bRetVal == FALSE ) {
+ printf( TEXT("Error returned from Litoa()\n") ) ;
+ }
+ printf( TEXT("t1 = %sD\n"), U64_Litoa( t1, buffer2, 10, &bRetVal ) ) ;
+ if( bRetVal == FALSE ) {
+ printf( TEXT("Error returned from Litoa()\n") ) ;
+ }
+ printf( TEXT("t1 = %sO\n"), U64_Litoa( t1, buffer2, 8, &bRetVal ) ) ;
+ if( bRetVal == FALSE ) {
+ printf( TEXT("Error returned from Litoa()\n") ) ;
+ }
+
+ t1 = U64_Atoli( TEXT("0x00000000F0000001"), &bRetVal ) ;
+ printf( TEXT("t1 = %sH\n"), U64_Litoa( t1, buffer2, 16, &bRetVal ) ) ;
+ if( bRetVal == FALSE ) {
+ printf( TEXT("Error returned from Litoa()\n") ) ;
+ }
+
+ printf( TEXT("t1 = %sD\n"), U64_Litoa( t1, buffer2, 10, &bRetVal ) ) ;
+ if( bRetVal == FALSE ) {
+ printf( TEXT("Error returned from Litoa()\n") ) ;
+ }
+ printf( TEXT("t1 = %sO\n"), U64_Litoa( t1, buffer2, 8, &bRetVal ) ) ;
+ if( bRetVal == FALSE ) {
+ printf( TEXT("Error returned from Litoa()\n") ) ;
+ }
+
+ t1 = U64_Init( 0x00000043L, 0x00000001L ) ;
+ /* 3 % 4 */
+ printf( TEXT("67 Mod 4 = %04X\n"), 67 % 4 ) ;
+ t2 = U64_Init( 0x00000004L, 0x00000000L ) ;
+ save_t1 = t1 ;
+ save_t2 = t2 ;
+ printf( TEXT("(%sH / %sH) = "), U64_Litoa( t1, buffer, 16, &bRetVal ),
+ U64_Litoa( t2, buffer2, 16, &bRetVal ) ) ;
+
+ t4 = U64_Div( t1, t2, &t3, &RetVal ) ;
+ printf( TEXT("%sH\n"), U64_Litoa( t4, buffer, 16, &bRetVal ) ) ;
+ printf( TEXT("Remainder = %sH and status = %d\n"),
+ U64_Litoa( t3, buffer, 16, &bRetVal ), RetVal ) ;
+
+ t1 = U64_Init( 0x00000000L, 0x00000001L ) ;
+ t1 = U64_Init( 0x00000043L, 0x00000001L ) ;
+ /* 3 % 4 */
+ printf( TEXT("67 Mod 2 = %04X\n"), 67 % 2 ) ;
+ t2 = U64_Init( 0x00000002L, 0x00000000L ) ;
+ save_t1 = t1 ;
+ save_t2 = t2 ;
+ printf( TEXT("(%sH / %sH) = "), U64_Litoa( t1, buffer, 16, &bRetVal ),
+ U64_Litoa( t2, buffer2, 16, &bRetVal ) ) ;
+
+ t4 = U64_Div( t1, t2, &t3, &RetVal ) ;
+ printf( TEXT("%sH\n"), U64_Litoa( t4, buffer, 16, &bRetVal ) ) ;
+ printf( TEXT("Remainder = %sH and status = %d\n"),
+ U64_Litoa( t3, buffer, 16, &bRetVal ), RetVal ) ;
+
+ t1 = U64_Atoli( TEXT("0x0000000100000043"), &bRetVal ) ;
+ /* 3 % 4 */
+ printf( TEXT("Divide by 0\n") ) ;
+ t2 = U64_Atoli( TEXT("0x0000000000000000"), &bRetVal ) ;
+ printf( TEXT("(%sH / %sH) = "), U64_Litoa( t1, buffer, 16, &bRetVal ),
+ U64_Litoa( t2, buffer2, 16, &bRetVal ) ) ;
+
+ t4 = U64_Div( t1, t2, &t3, &RetVal ) ;
+ printf( TEXT("%sH\n"), U64_Litoa( t4, buffer, 16, &bRetVal ) ) ;
+ printf( TEXT("Remainder = %sH and status = %d\n"),
+ U64_Litoa( t3, buffer, 16, &bRetVal ), RetVal ) ;
+
+ t1 = U64_Atoli( TEXT("0x0000000100000043"), &bRetVal ) ;
+ printf( TEXT("Divide by 1\n") ) ;
+ t2 = U64_Atoli( TEXT("0x0000000000000001"), &bRetVal ) ;
+ printf( TEXT("(%sH / %sH) = "), U64_Litoa( t1, buffer, 16, &bRetVal ),
+ U64_Litoa( t2, buffer2, 16, &bRetVal ) ) ;
+
+ t4 = U64_Div( t1, t2, &t3, &RetVal ) ;
+ printf( TEXT("%sH\n"), U64_Litoa( t4, buffer, 16, &bRetVal ) ) ;
+ printf( TEXT("Remainder = %sH and status = %d\n"),
+ U64_Litoa( t3, buffer, 8, &bRetVal ), RetVal ) ;
+
+ t1 = U64_Atoli( TEXT("0x0000000100000043"), &bRetVal ) ;
+ printf( TEXT("t1 == t2\n") ) ;
+ t2 = U64_Atoli( TEXT("0x0000000100000043"), &bRetVal ) ;
+ printf( TEXT("(%sH / %sH) = "), U64_Litoa( t1, buffer, 16, &bRetVal ),
+ U64_Litoa( t2, buffer2, 16, &bRetVal ) ) ;
+
+ t4 = U64_Div( t1, t2, &t3, &RetVal ) ;
+ printf( TEXT("%sH\n"), U64_Litoa( t4, buffer, 16, &bRetVal ) ) ;
+ printf( TEXT("Remainder = %sH and status = %d\n"),
+ U64_Litoa( t3, buffer, 16, &bRetVal ), RetVal ) ;
+
+ t1 = U64_Atoli( TEXT("0x0000000000000008"), &bRetVal ) ;
+ t2 = U64_Atoli(TEXT("0x0000000000000002"), &bRetVal ) ;
+ t1 = save_t1 ;
+ t2 = save_t2 ;
+ printf( TEXT("(%sH %c %sH) = "), U64_Litoa( t1, buffer, 16, &bRetVal ), TEXT('%'),
+ U64_Litoa( t2, buffer2, 16, &bRetVal ) ) ;
+
+ t4 = U64_Mod( t1, t2, &RetVal ) ;
+ printf( TEXT("%sH and status = %d\n"), U64_Litoa( t4, buffer, 16, &bRetVal ),
+ RetVal ) ;
+
+
+ t1 = U64_Atoli(TEXT("0x0001000110001000"), &bRetVal ) ;
+
+ printf( TEXT("UINT64 t1 = %sH before setting bits 62 and 2\n"),
+ U64_Litoa( t1, buffer, 16, &bRetVal ) ) ;
+
+ t1 = U64_SET( t1, U64_Init( 0x00000002L, 0x40000000L ) ) ;
+ printf( TEXT("UINT64 t1 = %sH after set bits 62 and 2\n\n"),
+ U64_Litoa( t1, buffer, 16, &bRetVal ) ) ;
+
+ t1 = U64_Atoli(TEXT("0x4000002001010002"), &bRetVal ) ;
+ printf( TEXT("UINT64 t1 = %sH before clear bits 62 and 2\n"),
+ U64_Litoa( t1, buffer, 16, &bRetVal ) ) ;
+ t1 = U64_CLR( t1, U64_Init( 0x00000002L, 0x40000000L ) ) ;
+ printf( TEXT("UINT64 t1 = %sH after clear bits 62 and 2\n\n"),
+ U64_Litoa( t1, buffer, 16, &bRetVal ) ) ;
+
+ // Now check out the bit test
+ if( U64_Test( t1, 0x00000002L, 0x40000000L ) != 0L ) {
+ printf( TEXT("The bits are set\n") ) ;
+ } else {
+ printf( TEXT("The bits are not set\n") ) ;
+ }
+
+ t1 = U64_SET( t1, U64_Init( 0x00000002L, 0x40000000L ) ) ;
+ printf( TEXT("UINT64 t1 = %sH after set bits 62 and 2\n\n"),
+ U64_Litoa( t1, buffer, 16, &bRetVal ) ) ;
+
+ // Now check out the bit test
+ if( U64_Test( t1, 0x00000002L, 0x40000000L ) != 0L ) {
+ printf( TEXT("The bits are set\n") ) ;
+ } else {
+ printf( TEXT("The bits are not set\n") ) ;
+ }
+
+ t1 = U64_XOR( t1, U64_Init( 0x00000002L, 0x00000000L ) ) ;
+ printf( TEXT("UINT64 t1 = %sH after XOR bit 2\n\n"),
+ U64_Litoa( t1, buffer, 16, &bRetVal ) ) ;
+
+ t1 = U64_XOR( t1, U64_Init( 0x00000002L, 0x00000000L ) ) ;
+ printf( TEXT("UINT64 t1 = %sH after XOR bit 2 again\n\n"),
+ U64_Litoa( t1, buffer, 16, &bRetVal ) ) ;
+
+ t1 = U64_Atoli(TEXT("0x0000000100000002"), &bRetVal ) ;
+ t2 = U64_Atoli( TEXT("0x0000000000000000"), &bRetVal ) ;
+
+ printf( TEXT("Testing Subtraction\n") ) ;
+
+ {
+ INT16 i ;
+ BOOLEAN bRetVal1 ;
+
+ for( i = 0; i < 64; i++ ) {
+ printf( TEXT("(%2d) (%08lX%08lX - "), i, t1.msw, t1.lsw ) ;
+ printf( TEXT("%08lX%08lX) = "), t2.msw,t2.lsw ) ;
+ t3 = U64_Sub( t1, t2, &bRetVal ) ;
+ printf( TEXT("%sH %s\n"), U64_Litoa( t3, buffer, 16, &bRetVal1 ),
+ bRetVal == TRUE ? TEXT("") : TEXT("Uflw") ) ;
+ t2 = U64_SHL( t2, 1 ) ;
+ if( i == 0 ) {
+ t2 = U64_SET( t2, U64_Init( 0x01L, 0x0L ) ) ;
+ }
+ }
+ printf( TEXT("\n") ) ;
+
+ t1 = U64_Atoli( TEXT("0x0000000100000002"), &bRetVal ) ;
+ t2 = U64_Atoli( TEXT("0x0000000000000000"), &bRetVal ) ;
+
+ printf( TEXT("Testing Addition\n") ) ;
+
+ for( i = 0; i < 64; i++ ) {
+ printf( TEXT("(%2d) (%08lX%08lX + "), i, t1.msw, t1.lsw ) ;
+ printf( TEXT("%08lX%08lX) = "), t2.msw,t2.lsw ) ;
+ t3 = U64_Add( t1, t2, &bRetVal ) ;
+ printf( TEXT("%sH %s\n"), U64_Litoa( t3, buffer, 16, &bRetVal1 ),
+ bRetVal == TRUE ? TEXT("") : TEXT("Ovfl")) ;
+ t2 = U64_SHL( t2, 1 ) ;
+ if( i == 0 ) {
+ t2 = U64_SET( t2, U64_Init( 0x01L, 0x0L ) ) ;
+ }
+ }
+
+ printf( TEXT("\nTesting Left Shift\n") ) ;
+
+ for ( i = 0; i <= 64; i++ ) {
+ t1 = U64_Atoli( TEXT("0x0000000000000001"), &bRetVal ) ;
+ printf( TEXT("%sH is "), U64_Litoa( t1, buffer, 16, &bRetVal ) ) ;
+ t1 = U64_SHL( t1, i ) ;
+ printf( TEXT("%sH after SHL by %2d\n"),
+ U64_Litoa( t1, buffer, 16, &bRetVal1 ),i ) ;
+ }
+
+ printf( TEXT("Testing Right Shift\n") ) ;
+ for ( i = 0; i <= 64; i++ ) {
+ t1 = U64_Atoli( TEXT("0x8000000000000000"), &bRetVal ) ;
+ printf( TEXT("%sH is "), U64_Litoa( t1, buffer, 16, &bRetVal ) ) ;
+ t1 = U64_SHR( t1, i ) ;
+ printf( TEXT("%sH after SHR by %2d\n"),
+ U64_Litoa( t1, buffer, 16, &bRetVal1 ), i ) ;
+ }
+ } /* End of local block */
+
+#endif /* INTER_ACT */
+
+
+ printf( TEXT("Testing Comparisons\n") ) ;
+
+ arg1.msw = 0L ;
+ arg1.lsw = 0L ;
+ arg2.msw = 0L ;
+ arg2.lsw = 0L ;
+ printf( TEXT("arg1: %08lX : %08lX arg2: %08lX : %08lX\n"), arg1.msw, arg1.lsw, arg2.msw, arg2.lsw ) ;
+ printf( TEXT(" U64_EQ returned: %d\n"), U64_EQ( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_NE returned: %d\n"), U64_NE( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_LT returned: %d\n"), U64_LT( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_GT returned: %d\n"), U64_GT( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_LE returned: %d\n"), U64_LE( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_GE returned: %d\n"), U64_GE( arg1, arg2 ) ) ;
+ t1 = U64_Min( arg1, arg2 ) ;
+ printf( TEXT(" U64_Min returned: %08lX : %08lX\n"), t1.msw, t1.lsw ) ;
+ t1 = U64_Max( arg1, arg2 ) ;
+ printf( TEXT(" U64_Max returned: %08lX : %08lX\n"), t1.msw, t1.lsw ) ;
+
+ arg1.msw = 5L ;
+ arg1.lsw = 0L ;
+ arg2.msw = 0L ;
+ arg2.lsw = 0L ;
+ printf( TEXT("arg1: %08lX : %08lX arg2: %08lX : %08lX\n"), arg1.msw, arg1.lsw, arg2.msw, arg2.lsw ) ;
+ printf( TEXT(" U64_EQ returned: %d\n"), U64_EQ( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_NE returned: %d\n"), U64_NE( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_LT returned: %d\n"), U64_LT( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_GT returned: %d\n"), U64_GT( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_LE returned: %d\n"), U64_LE( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_GE returned: %d\n"), U64_GE( arg1, arg2 ) ) ;
+ t1 = U64_Min( arg1, arg2 ) ;
+ printf( TEXT(" U64_Min returned: %08lX : %08lX\n"), t1.msw, t1.lsw ) ;
+ t1 = U64_Max( arg1, arg2 ) ;
+ printf( TEXT(" U64_Max returned: %08lX : %08lX\n"), t1.msw, t1.lsw ) ;
+
+ arg1.msw = 0L ;
+ arg1.lsw = 5L ;
+ arg2.msw = 0L ;
+ arg2.lsw = 0L ;
+ printf( TEXT("arg1: %08lX : %08lX arg2: %08lX : %08lX\n"), arg1.msw, arg1.lsw, arg2.msw, arg2.lsw ) ;
+ printf( TEXT(" U64_EQ returned: %d\n"), U64_EQ( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_NE returned: %d\n"), U64_NE( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_LT returned: %d\n"), U64_LT( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_GT returned: %d\n"), U64_GT( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_LE returned: %d\n"), U64_LE( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_GE returned: %d\n"), U64_GE( arg1, arg2 ) ) ;
+ t1 = U64_Min( arg1, arg2 ) ;
+ printf( TEXT(" U64_Min returned: %08lX : %08lX\n"), t1.msw, t1.lsw ) ;
+ t1 = U64_Max( arg1, arg2 ) ;
+ printf( TEXT(" U64_Max returned: %08lX : %08lX\n"), t1.msw, t1.lsw ) ;
+
+ arg1.msw = 0L ;
+ arg1.lsw = 0L ;
+ arg2.msw = 5L ;
+ arg2.lsw = 0L ;
+ printf( TEXT("arg1: %08lX : %08lX arg2: %08lX : %08lX\n"), arg1.msw, arg1.lsw, arg2.msw, arg2.lsw ) ;
+ printf( TEXT(" U64_EQ returned: %d\n"), U64_EQ( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_NE returned: %d\n"), U64_NE( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_LT returned: %d\n"), U64_LT( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_GT returned: %d\n"), U64_GT( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_LE returned: %d\n"), U64_LE( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_GE returned: %d\n"), U64_GE( arg1, arg2 ) ) ;
+ t1 = U64_Min( arg1, arg2 ) ;
+ printf( TEXT(" U64_Min returned: %08lX : %08lX\n"), t1.msw, t1.lsw ) ;
+ t1 = U64_Max( arg1, arg2 ) ;
+ printf( TEXT(" U64_Max returned: %08lX : %08lX\n"), t1.msw, t1.lsw ) ;
+
+ arg1.msw = 0L ;
+ arg1.lsw = 0L ;
+ arg2.msw = 0L ;
+ arg2.lsw = 5L ;
+ printf( TEXT("arg1: %08lX : %08lX arg2: %08lX : %08lX\n"), arg1.msw, arg1.lsw, arg2.msw, arg2.lsw ) ;
+ printf( TEXT(" U64_EQ returned: %d\n"), U64_EQ( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_NE returned: %d\n"), U64_NE( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_LT returned: %d\n"), U64_LT( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_GT returned: %d\n"), U64_GT( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_LE returned: %d\n"), U64_LE( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_GE returned: %d\n"), U64_GE( arg1, arg2 ) ) ;
+ t1 = U64_Min( arg1, arg2 ) ;
+ printf( TEXT(" U64_Min returned: %08lX : %08lX\n"), t1.msw, t1.lsw ) ;
+ t1 = U64_Max( arg1, arg2 ) ;
+ printf( TEXT(" U64_Max returned: %08lX : %08lX\n"), t1.msw, t1.lsw ) ;
+
+ arg1.msw = 1L ;
+ arg1.lsw = 5L ;
+ arg2.msw = 1L ;
+ arg2.lsw = 5L ;
+ printf( TEXT("arg1: %08lX : %08lX arg2: %08lX : %08lX\n"), arg1.msw, arg1.lsw, arg2.msw, arg2.lsw ) ;
+ printf( TEXT(" U64_EQ returned: %d\n"), U64_EQ( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_NE returned: %d\n"), U64_NE( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_LT returned: %d\n"), U64_LT( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_GT returned: %d\n"), U64_GT( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_LE returned: %d\n"), U64_LE( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_GE returned: %d\n"), U64_GE( arg1, arg2 ) ) ;
+ t1 = U64_Min( arg1, arg2 ) ;
+ printf( TEXT(" U64_Min returned: %08lX : %08lX\n"), t1.msw, t1.lsw ) ;
+ t1 = U64_Max( arg1, arg2 ) ;
+ printf( TEXT(" U64_Max returned: %08lX : %08lX\n"), t1.msw, t1.lsw ) ;
+
+ arg1.msw = 2L ;
+ arg1.lsw = 5L ;
+ arg2.msw = 1L ;
+ arg2.lsw = 5L ;
+ printf( TEXT("arg1: %08lX : %08lX arg2: %08lX : %08lX\n"), arg1.msw, arg1.lsw, arg2.msw, arg2.lsw ) ;
+ printf( TEXT(" U64_EQ returned: %d\n"), U64_EQ( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_NE returned: %d\n"), U64_NE( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_LT returned: %d\n"), U64_LT( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_GT returned: %d\n"), U64_GT( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_LE returned: %d\n"), U64_LE( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_GE returned: %d\n"), U64_GE( arg1, arg2 ) ) ;
+ t1 = U64_Min( arg1, arg2 ) ;
+ printf( TEXT(" U64_Min returned: %08lX : %08lX\n"), t1.msw, t1.lsw ) ;
+ t1 = U64_Max( arg1, arg2 ) ;
+ printf( TEXT(" U64_Max returned: %08lX : %08lX\n"), t1.msw, t1.lsw ) ;
+
+ arg1.msw = 1L ;
+ arg1.lsw = 5L ;
+ arg2.msw = 2L ;
+ arg2.lsw = 5L ;
+ printf( TEXT("arg1: %08lX : %08lX arg2: %08lX : %08lX\n"), arg1.msw, arg1.lsw, arg2.msw, arg2.lsw ) ;
+ printf( TEXT(" U64_EQ returned: %d\n"), U64_EQ( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_NE returned: %d\n"), U64_NE( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_LT returned: %d\n"), U64_LT( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_GT returned: %d\n"), U64_GT( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_LE returned: %d\n"), U64_LE( arg1, arg2 ) ) ;
+ printf( TEXT(" U64_GE returned: %d\n"), U64_GE( arg1, arg2 ) ) ;
+ t1 = U64_Min( arg1, arg2 ) ;
+ printf( TEXT(" U64_Min returned: %08lX : %08lX\n"), t1.msw, t1.lsw ) ;
+ t1 = U64_Max( arg1, arg2 ) ;
+ printf( TEXT(" U64_Max returned: %08lX : %08lX\n"), t1.msw, t1.lsw ) ;
+
+}
+
+#endif
diff --git a/private/utils/ntbackup/src/stdwcs.c b/private/utils/ntbackup/src/stdwcs.c
new file mode 100644
index 000000000..ee3af8836
--- /dev/null
+++ b/private/utils/ntbackup/src/stdwcs.c
@@ -0,0 +1,902 @@
+/** Copyright (C) Maynard Electronics, An Archive Company. 1992
+
+ Name: STDWCS.C
+
+ Description:
+
+ Contains wide string functions, unicode mapping functions,
+ unicode comparison functions and memory functions. The file
+ is divided into the sections as outline here.
+
+ MIKEP-note,
+ Wide string functions for using unicode strings under MSC 6.0
+ and not having a library to use. If you add a function, add
+ it here, to STDWCS.H, and to MAPPINGS.H
+
+
+ $Log: M:/LOGFILES/STDWCS.C_V $
+
+ Rev 1.11 17 Jan 1994 15:06:46 BARRY
+Changed memorycmp functions to take VOID_PTR args
+
+ Rev 1.10 16 Nov 1993 13:25:28 GREGG
+Replaced 'L' modifier with cast.
+
+ Rev 1.9 20 Oct 1993 19:29:10 GREGG
+Fixed conversion routines and removed tabs.
+
+ Rev 1.8 18 Aug 1993 18:19:22 BARRY
+Added strcspn/wcscspn
+
+ Rev 1.7 12 Aug 1993 16:43:26 DON
+Fixed cleanup code for map_dst_overflow
+
+ Rev 1.6 11 Aug 1993 18:01:10 STEVEN
+fix read of unicode tape with ansi app
+
+ Rev 1.5 12 Nov 1992 11:00:34 DAVEV
+transparent unicode support fixes, comment out strlwr, strupr
+
+ Rev 1.4 12 Nov 1992 10:44:54 BARRY
+Change mapAnsiToUnic to work on strings in place.
+
+ Rev 1.3 23 Jul 1992 08:32:44 STEVEN
+fix warnings
+
+ Rev 1.2 17 Jul 1992 14:58:56 STEVEN
+fix NT bugs
+
+ Rev 1.0 10 Jun 1992 16:11:10 TIMN
+Initial Revision (UNICODE)
+
+
+
+**/
+
+
+/* include files go here */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#define NO_STRING_REMAPPING 1 /* bypasses wide str function remapping */
+
+#include "stdtypes.h"
+#include "msassert.h"
+#include "stdwcs.h"
+
+
+
+/**
+ begin private wide string stuff *****
+**/
+
+
+
+
+/**
+ begin private unicode mapping stuff *****
+**/
+
+/* begin defines */
+
+#define MAP_MAX_ANSI_CH 0x00FF /* max. ansi to unic mappable code point */
+
+#define MAP_CTRLCH_TBL_SIZ 32 /* num of ansi ctrl chars, 00h-1Fh */
+#define MAP_MAX_CTRL_CH 0x1F /* max. ctrl char code point */
+
+#define MAP_EXTCH_TBL_SIZ 128 /* num of ansi mappable chars, 80h-FFh */
+#define MAP_BASE_CH 0x80 /* first ansi mappable code point */
+
+#define MAP_COMPATCH_TBL_SIZ 37 /* num of ansi mappable compatability zone chars */
+#define MAP_BEGIN_CMPTZONE 0xFE33 /* begin mappable compatability zone */
+#define MAP_END_CMPTZONE 0xFFE5 /* end mappable compatability zone */
+
+
+
+/* begin data structures */
+
+static WCHAR ansiToUnicExtChTbl[ MAP_EXTCH_TBL_SIZ ] = {
+/* map cp437 chars to Unicode 1250 */
+
+ /* 80 */ (WCHAR)0x00C7, (WCHAR)0x00FC, (WCHAR)0x00E9, (WCHAR)0x00E2,
+ (WCHAR)0x00E4, (WCHAR)0x00E0, (WCHAR)0x00E5, (WCHAR)0x00E7,
+ (WCHAR)0x00EA, (WCHAR)0x00EB, (WCHAR)0x00E8, (WCHAR)0x00EF,
+ (WCHAR)0x00EE, (WCHAR)0x00EC, (WCHAR)0x00C4, (WCHAR)0x00C5,
+ /* 90 */ (WCHAR)0x00C9, (WCHAR)0x00E6, (WCHAR)0x00C6, (WCHAR)0x00F4,
+ (WCHAR)0x00F6, (WCHAR)0x00F2, (WCHAR)0x00FB, (WCHAR)0x00F9,
+ (WCHAR)0x00FF, (WCHAR)0x00D6, (WCHAR)0x00DC, (WCHAR)0x00A2,
+ (WCHAR)0x00A3, (WCHAR)0x00A5, (WCHAR)0x20A7, (WCHAR)0x0192,
+ /* A0 */ (WCHAR)0x00E1, (WCHAR)0x00ED, (WCHAR)0x00F3, (WCHAR)0x00FA,
+ (WCHAR)0x00F1, (WCHAR)0x00D1, (WCHAR)0x00AA, (WCHAR)0x00BA,
+ (WCHAR)0x00BF, (WCHAR)0x2310, (WCHAR)0x00AC, (WCHAR)0x00BD,
+ (WCHAR)0x00BC, (WCHAR)0x00A1, (WCHAR)0x00AB, (WCHAR)0x00BB,
+ /* B0 */ (WCHAR)0x2591, (WCHAR)0x2592, (WCHAR)0x2593, (WCHAR)0x2502,
+ (WCHAR)0x2524, (WCHAR)0x2561, (WCHAR)0x2562, (WCHAR)0x2556,
+ (WCHAR)0x2555, (WCHAR)0x2563, (WCHAR)0x2551, (WCHAR)0x2557,
+ (WCHAR)0x255D, (WCHAR)0x255C, (WCHAR)0x255B, (WCHAR)0x2510,
+ /* C0 */ (WCHAR)0x2514, (WCHAR)0x2534, (WCHAR)0x252C, (WCHAR)0x251C,
+ (WCHAR)0x2500, (WCHAR)0x253C, (WCHAR)0x255E, (WCHAR)0x255F,
+ (WCHAR)0x255A, (WCHAR)0x2554, (WCHAR)0x2569, (WCHAR)0x2566,
+ (WCHAR)0x2560, (WCHAR)0x2550, (WCHAR)0x256C, (WCHAR)0x2567,
+ /* D0 */ (WCHAR)0x2568, (WCHAR)0x2564, (WCHAR)0x2565, (WCHAR)0x2559,
+ (WCHAR)0x2558, (WCHAR)0x2552, (WCHAR)0x2553, (WCHAR)0x256B,
+ (WCHAR)0x256A, (WCHAR)0x2518, (WCHAR)0x250C, (WCHAR)0x2588,
+ (WCHAR)0x2584, (WCHAR)0x258C, (WCHAR)0x2590, (WCHAR)0x2580,
+ /* E0 */ (WCHAR)0x03B1, (WCHAR)0x00DF, (WCHAR)0x0393, (WCHAR)0x03C0,
+ (WCHAR)0x03A3, (WCHAR)0x03C3, (WCHAR)0x00B5, (WCHAR)0x03C4,
+ (WCHAR)0x03A6, (WCHAR)0x0398, (WCHAR)0x03A9, (WCHAR)0x03B4,
+ (WCHAR)0x221E, (WCHAR)0x03C6, (WCHAR)0x03B5, (WCHAR)0x2229,
+ /* F0 */ (WCHAR)0x2261, (WCHAR)0x00B1, (WCHAR)0x2265, (WCHAR)0x2264,
+ (WCHAR)0x2320, (WCHAR)0x2321, (WCHAR)0x00F7, (WCHAR)0x2248,
+ (WCHAR)0x00B0, (WCHAR)0x2219, (WCHAR)0x00B7, (WCHAR)0x221A,
+ (WCHAR)0x207F, (WCHAR)0x00B2, (WCHAR)0x25A0, (WCHAR)0x00A0
+} ;
+
+
+/* parallel arrays of UNIC/ANSI mappable chars for extended chars Unic1250 to cp437 */
+
+static WCHAR unicExtChTbl[ MAP_EXTCH_TBL_SIZ ] = {
+/* ascending order Unic 1250 extended chars. Maps Unic to cp437 */
+
+ /* 80 */ (WCHAR)0x00A0, (WCHAR)0x00A1, (WCHAR)0x00A2, (WCHAR)0x00A3,
+ (WCHAR)0x00A5, (WCHAR)0x00AA, (WCHAR)0x00AB, (WCHAR)0x00AC,
+ (WCHAR)0x00B0, (WCHAR)0x00B1, (WCHAR)0x00B2, (WCHAR)0x00B5,
+ (WCHAR)0x00B7, (WCHAR)0x00BA, (WCHAR)0x00BB, (WCHAR)0x00BC,
+ /* 90 */ (WCHAR)0x00BD, (WCHAR)0x00BF, (WCHAR)0x00C4, (WCHAR)0x00C5,
+ (WCHAR)0x00C6, (WCHAR)0x00C7, (WCHAR)0x00C9, (WCHAR)0x00D1,
+ (WCHAR)0x00D6, (WCHAR)0x00DC, (WCHAR)0x00DF, (WCHAR)0x00E0,
+ (WCHAR)0x00E1, (WCHAR)0x00E2, (WCHAR)0x00E4, (WCHAR)0x00E5,
+ /* A0 */ (WCHAR)0x00E6, (WCHAR)0x00E7, (WCHAR)0x00E8, (WCHAR)0x00E9,
+ (WCHAR)0x00EA, (WCHAR)0x00EB, (WCHAR)0x00EC, (WCHAR)0x00ED,
+ (WCHAR)0x00EE, (WCHAR)0x00EF, (WCHAR)0x00F1, (WCHAR)0x00F2,
+ (WCHAR)0x00F3, (WCHAR)0x00F4, (WCHAR)0x00F6, (WCHAR)0x00F7,
+ /* B0 */ (WCHAR)0x00F9, (WCHAR)0x00FA, (WCHAR)0x00FB, (WCHAR)0x00FC,
+ (WCHAR)0x00FF, (WCHAR)0x0192, (WCHAR)0x0393, (WCHAR)0x0398,
+ (WCHAR)0x03A3, (WCHAR)0x03A6, (WCHAR)0x03A9, (WCHAR)0x03B1,
+ (WCHAR)0x03B4, (WCHAR)0x03B5, (WCHAR)0x03C0, (WCHAR)0x03C3,
+ /* C0 */ (WCHAR)0x03C4, (WCHAR)0x03C6, (WCHAR)0x207F, (WCHAR)0x20A7,
+ (WCHAR)0x2219, (WCHAR)0x221A, (WCHAR)0x221E, (WCHAR)0x2229,
+ (WCHAR)0x2248, (WCHAR)0x2261, (WCHAR)0x2264, (WCHAR)0x2265,
+ (WCHAR)0x2310, (WCHAR)0x2320, (WCHAR)0x2321, (WCHAR)0x2500,
+ /* D0 */ (WCHAR)0x2502, (WCHAR)0x250C, (WCHAR)0x2510, (WCHAR)0x2514,
+ (WCHAR)0x2518, (WCHAR)0x251C, (WCHAR)0x2524, (WCHAR)0x252C,
+ (WCHAR)0x2534, (WCHAR)0x253C, (WCHAR)0x2550, (WCHAR)0x2551,
+ (WCHAR)0x2552, (WCHAR)0x2553, (WCHAR)0x2554, (WCHAR)0x2555,
+ /* E0 */ (WCHAR)0x2556, (WCHAR)0x2557, (WCHAR)0x2558, (WCHAR)0x2559,
+ (WCHAR)0x255A, (WCHAR)0x255B, (WCHAR)0x255C, (WCHAR)0x255D,
+ (WCHAR)0x255E, (WCHAR)0x255F, (WCHAR)0x2560, (WCHAR)0x2561,
+ (WCHAR)0x2562, (WCHAR)0x2563, (WCHAR)0x2564, (WCHAR)0x2565,
+ /* F0 */ (WCHAR)0x2566, (WCHAR)0x2567, (WCHAR)0x2568, (WCHAR)0x2569,
+ (WCHAR)0x256A, (WCHAR)0x256B, (WCHAR)0x256C, (WCHAR)0x2580,
+ (WCHAR)0x2584, (WCHAR)0x2588, (WCHAR)0x258C, (WCHAR)0x2590,
+ (WCHAR)0x2591, (WCHAR)0x2592, (WCHAR)0x2593, (WCHAR)0x25A0
+} ;
+
+static ACHAR ansiExtCh[ MAP_EXTCH_TBL_SIZ ] = {
+/* ANSI mappable chars that correlate to unicExtChTbl */
+
+ /* 80 */ (ACHAR)0xFF, (ACHAR)0xAD, (ACHAR)0x9B, (ACHAR)0x9C,
+ (ACHAR)0x9D, (ACHAR)0xA6, (ACHAR)0xAE, (ACHAR)0xAA,
+ (ACHAR)0xF8, (ACHAR)0xF1, (ACHAR)0xFD, (ACHAR)0xE6,
+ (ACHAR)0xFA, (ACHAR)0xA7, (ACHAR)0xAF, (ACHAR)0xAC,
+ /* 90 */ (ACHAR)0xAB, (ACHAR)0xA8, (ACHAR)0x8E, (ACHAR)0x8F,
+ (ACHAR)0x92, (ACHAR)0x80, (ACHAR)0x90, (ACHAR)0xA5,
+ (ACHAR)0x99, (ACHAR)0x9A, (ACHAR)0xE1, (ACHAR)0x85,
+ (ACHAR)0xA0, (ACHAR)0x83, (ACHAR)0x84, (ACHAR)0x86,
+ /* A0 */ (ACHAR)0x91, (ACHAR)0x87, (ACHAR)0x8A, (ACHAR)0x82,
+ (ACHAR)0x88, (ACHAR)0x89, (ACHAR)0x8D, (ACHAR)0xA1,
+ (ACHAR)0x8C, (ACHAR)0x8B, (ACHAR)0xA4, (ACHAR)0x95,
+ (ACHAR)0xA2, (ACHAR)0x93, (ACHAR)0x94, (ACHAR)0xF6,
+ /* B0 */ (ACHAR)0x97, (ACHAR)0xA3, (ACHAR)0x96, (ACHAR)0x81,
+ (ACHAR)0x98, (ACHAR)0x9F, (ACHAR)0xE2, (ACHAR)0xE9,
+ (ACHAR)0xE4, (ACHAR)0xE8, (ACHAR)0xEA, (ACHAR)0xE0,
+ (ACHAR)0xEB, (ACHAR)0xEE, (ACHAR)0xE3, (ACHAR)0xE5,
+ /* C0 */ (ACHAR)0xE7, (ACHAR)0xED, (ACHAR)0xFC, (ACHAR)0x9E,
+ (ACHAR)0xF9, (ACHAR)0xFB, (ACHAR)0xEC, (ACHAR)0xEF,
+ (ACHAR)0xF7, (ACHAR)0xF0, (ACHAR)0xF3, (ACHAR)0xF2,
+ (ACHAR)0xA9, (ACHAR)0xF4, (ACHAR)0xF5, (ACHAR)0xC4,
+ /* D0 */ (ACHAR)0xB3, (ACHAR)0xDA, (ACHAR)0xBF, (ACHAR)0xC0,
+ (ACHAR)0xD9, (ACHAR)0xC3, (ACHAR)0xB4, (ACHAR)0xC2,
+ (ACHAR)0xC1, (ACHAR)0xC5, (ACHAR)0xCD, (ACHAR)0xBA,
+ (ACHAR)0xD5, (ACHAR)0xD6, (ACHAR)0xC9, (ACHAR)0xB8,
+ /* E0 */ (ACHAR)0xB7, (ACHAR)0xBB, (ACHAR)0xD4, (ACHAR)0xD3,
+ (ACHAR)0xC8, (ACHAR)0xBE, (ACHAR)0xBD, (ACHAR)0xBC,
+ (ACHAR)0xC6, (ACHAR)0xC7, (ACHAR)0xCC, (ACHAR)0xB5,
+ (ACHAR)0xB6, (ACHAR)0xB9, (ACHAR)0xD1, (ACHAR)0xD2,
+ /* F0 */ (ACHAR)0xCB, (ACHAR)0xCF, (ACHAR)0xD0, (ACHAR)0xCA,
+ (ACHAR)0xD8, (ACHAR)0xD7, (ACHAR)0xCE, (ACHAR)0xDF,
+ (ACHAR)0xDC, (ACHAR)0xDB, (ACHAR)0xDD, (ACHAR)0xDE,
+ (ACHAR)0xB0, (ACHAR)0xB1, (ACHAR)0xB2, (ACHAR)0xFE
+} ;
+
+
+
+/* parallel arrays of UNIC/ANSI mappable chars for control chars Unic1250 to cp437 */
+
+static WCHAR unicCtrlChTbl[ MAP_CTRLCH_TBL_SIZ ] = {
+/* ascending order Unic 1250 control chars. Maps Unic to cp437 */
+
+ /* 00 */ (WCHAR)0x0000, (WCHAR)0x00A7, (WCHAR)0x00B6, (WCHAR)0x2022,
+ (WCHAR)0x203C, (WCHAR)0x2190, (WCHAR)0x2191, (WCHAR)0x2192,
+ (WCHAR)0x2193, (WCHAR)0x2194, (WCHAR)0x2195, (WCHAR)0x21A8,
+ (WCHAR)0x221F, (WCHAR)0x22D9, (WCHAR)0x25AC, (WCHAR)0x25B2,
+ /* 10 */ (WCHAR)0x25BA, (WCHAR)0x25BC, (WCHAR)0x25C4, (WCHAR)0x25CB,
+ (WCHAR)0x25D8, (WCHAR)0x263A, (WCHAR)0x263B, (WCHAR)0x263C,
+ (WCHAR)0x2640, (WCHAR)0x2642, (WCHAR)0x2660, (WCHAR)0x2663,
+ (WCHAR)0x2665, (WCHAR)0x2666, (WCHAR)0x266A, (WCHAR)0x266B
+} ;
+
+static ACHAR ansiCtrlCh[ MAP_CTRLCH_TBL_SIZ ] = {
+/* ANSI mappable chars that correlate to unicCtrlChTbl */
+
+ /* 00 */ (ACHAR)0x00, (ACHAR)0x15, (ACHAR)0x16, (ACHAR)0x1C,
+ (ACHAR)0x1D, (ACHAR)0x1B, (ACHAR)0x1A, (ACHAR)0x03,
+ (ACHAR)0x14, (ACHAR)0x13, (ACHAR)0x0D, (ACHAR)0x19,
+ (ACHAR)0x18, (ACHAR)0x1E, (ACHAR)0x1F, (ACHAR)0x17,
+ /* 10 */ (ACHAR)0x10, (ACHAR)0x12, (ACHAR)0x0A, (ACHAR)0x04,
+ (ACHAR)0x02, (ACHAR)0x01, (ACHAR)0x0E, (ACHAR)0x0B,
+ (ACHAR)0x06, (ACHAR)0x08, (ACHAR)0x07, (ACHAR)0x05,
+ (ACHAR)0x0C, (ACHAR)0x09, (ACHAR)0x0F, (ACHAR)0x11
+} ;
+
+
+
+/* parallel arrays of UNIC/ANSI mappable chars for compatability zone chars Unic1250 to cp437 */
+
+static WCHAR unicCmptZoneChTbl[ MAP_COMPATCH_TBL_SIZ ] = {
+/* ascending order Unic 1250 compatability zone chars. Maps Unic to cp437 */
+
+ (WCHAR)0xFE33, (WCHAR)0xFE34, (WCHAR)0xFE35, (WCHAR)0xFE36,
+ (WCHAR)0xFE37, (WCHAR)0xFE38, (WCHAR)0xFE4D, (WCHAR)0xFE4E,
+ (WCHAR)0xFE4F, (WCHAR)0xFE50, (WCHAR)0xFE52, (WCHAR)0xFE54,
+ (WCHAR)0xFE55, (WCHAR)0xFE56, (WCHAR)0xFE57, (WCHAR)0xFE59,
+ (WCHAR)0xFE5A, (WCHAR)0xFE5B, (WCHAR)0xFE5C, (WCHAR)0xFE5F,
+ (WCHAR)0xFE60, (WCHAR)0xFE61, (WCHAR)0xFE62, (WCHAR)0xFE63,
+ (WCHAR)0xFE64, (WCHAR)0xFE65, (WCHAR)0xFE66, (WCHAR)0xFE68,
+ (WCHAR)0xFE69, (WCHAR)0xFE6A, (WCHAR)0xFE6B, (WCHAR)0xFFE0,
+ (WCHAR)0xFFE1, (WCHAR)0xFFE2, (WCHAR)0xFFE3, (WCHAR)0xFFE4,
+ (WCHAR)0xFFE5
+} ;
+
+static ACHAR ansiCmptZoneCh[ MAP_COMPATCH_TBL_SIZ ] = {
+/* ANSI mappable chars that correlate to unicCmptZoneChTbl */
+
+ (ACHAR)0x5F, (ACHAR)0x5F, (ACHAR)0x28, (ACHAR)0x29,
+ (ACHAR)0x7B, (ACHAR)0x7D, (ACHAR)0x5F, (ACHAR)0x5F,
+ (ACHAR)0x5F, (ACHAR)0x2C, (ACHAR)0x2E, (ACHAR)0x3B,
+ (ACHAR)0x3A, (ACHAR)0x3F, (ACHAR)0x21, (ACHAR)0x28,
+ (ACHAR)0x29, (ACHAR)0x7B, (ACHAR)0x7D, (ACHAR)0x23,
+ (ACHAR)0x26, (ACHAR)0x2A, (ACHAR)0x2B, (ACHAR)0x2D,
+ (ACHAR)0x3C, (ACHAR)0x3E, (ACHAR)0x3D, (ACHAR)0x5C,
+ (ACHAR)0x24, (ACHAR)0x25, (ACHAR)0x40, (ACHAR)0xA2,
+ (ACHAR)0xA3, (ACHAR)0xAC, (ACHAR)0xAF, (ACHAR)0xA6,
+ (ACHAR)0xA5
+} ;
+
+
+
+/* begin macros */
+
+#define _cvtExtChToTblIndx(c) ( (unsigned char)(c) - MAP_BASE_CH )
+
+
+/* macros to access parallel arrays for UNIC to ANSI mappings */
+
+#define _getAnsiExtCh( x ) ( ansiExtCh[ x ] )
+#define _getAnsiCtrlCh( x ) ( ansiCtrlCh[ x ] )
+#define _getAnsiCmptZoneCh( x ) ( ansiCmptZoneCh[ x ] )
+
+
+
+/* begin private unicode utility stuff */
+
+static BOOLEAN bSrchUnicChTbl( WCHAR wch, WCHAR_PTR unicTblArry, INT max, INT *indx ) ;
+
+
+
+/**
+ begin wide string functions *****
+**/
+
+#if !defined( OS_WIN32 )
+
+INT wcslen( WCHAR_PTR s )
+{
+ INT i = 0;
+ while ( *s++ ) i++;
+ return( i );
+}
+
+WCHAR_PTR wcscpy
+( WCHAR_PTR s, WCHAR_PTR t )
+{
+ WCHAR_PTR tmp;
+ tmp = s;
+ while ( *s++ = *t++ );
+ return( tmp );
+}
+
+WCHAR_PTR wcsncpy( WCHAR_PTR s, WCHAR_PTR t, INT i )
+{
+ WCHAR_PTR tmp;
+ tmp = s;
+ while ( i-- && (*s++ = *t++) );
+ return( tmp );
+
+}
+
+WCHAR_PTR wcscat( WCHAR_PTR s, WCHAR_PTR t )
+{
+ WCHAR_PTR tmp;
+ tmp = s;
+ while ( *s++ );
+ while ( *s++ = *t++ );
+ return( tmp );
+}
+
+WCHAR_PTR wcsncat( WCHAR_PTR s, WCHAR_PTR t, INT i )
+{
+ WCHAR_PTR tmp;
+ tmp = s;
+ while ( *s++ );
+ while ( i-- && (*s++ = *t++) );
+
+ if ( !i ) {
+ *s = (WCHAR)NULL ;
+ }
+ return( tmp );
+}
+
+INT wcscmp( WCHAR_PTR s, WCHAR_PTR t )
+{
+ while ( *s && ( *s++ == *t++ ) );
+ if ( *s > *t ) return( 1 );
+ if ( *s < *t ) return( -1 );
+ return( 0 );
+}
+
+INT wcsncmp( WCHAR_PTR s, WCHAR_PTR t, INT i )
+{
+ while ( *s && i-- && ( *s++ == *t++ ) );
+ if ( *s > *t && i ) return( 1 );
+ if ( *s < *t && i ) return( -1 );
+ return( 0 );
+}
+
+INT wcsicmp( WCHAR_PTR s, WCHAR_PTR t )
+{
+ INT n = _toLowerW( *s ) - _toLowerW( *t ) ;
+
+ while ( !n && *s++ && *t++ ) {
+ n = _toLowerW( *s ) - _toLowerW( *t ) ;
+ }
+
+ return( n ) ;
+}
+
+INT wcsnicmp( WCHAR_PTR s, WCHAR_PTR t, INT i )
+{
+ INT n = 0 ;
+
+ msassert( i >= 0 ) ;
+
+ if ( i ) {
+ n = _toLowerW( *s ) - _toLowerW( *t ) ;
+
+ while ( --i && !n && *s++ && *t++ ) {
+ n = _toLowerW( *s ) - _toLowerW( *t ) ;
+ }
+ }
+
+ return( n ) ;
+}
+
+WCHAR_PTR wcsrchr( WCHAR_PTR s, INT c )
+{
+ INT i;
+
+ i = wcslen( s ) + 1;
+ s += i;
+
+ for ( ; i >= 0; i-- ) {
+ if ( *s == (WCHAR)c ) {
+ return( s );
+ }
+ s--;
+ }
+
+ return( NULL );
+}
+
+WCHAR_PTR wcschr( WCHAR_PTR s, INT c )
+{
+ INT i;
+
+ i = wcslen( s );
+
+ for ( ; i >= 0; i-- ) {
+ if ( *s == (WCHAR)c ) {
+ return( s );
+ }
+ s++;
+ }
+
+ return( NULL );
+}
+
+WCHAR_PTR wcspbrk( WCHAR_PTR s, WCHAR_PTR t )
+{
+ INT i;
+
+ while ( *s ) {
+ for ( i = 0; t[i]; i++ ) {
+ if ( *s == t[i] ) {
+ return( s );
+ }
+ }
+ s++;
+ }
+
+ return( NULL );
+}
+
+WCHAR_PTR wcslwr( WCHAR_PTR s )
+{
+ WCHAR_PTR tmp = s ;
+
+ for ( ; *s; s++) {
+ *s = _toLowerW( *s ) ;
+ }
+
+ return( tmp ) ;
+}
+
+WCHAR_PTR wcsupr( WCHAR_PTR s )
+{
+ WCHAR_PTR tmp = s ;
+
+ for ( ; *s; s++) {
+ *s = _toUpperW( *s ) ;
+ }
+
+ return( tmp ) ;
+}
+
+WCHAR_PTR wcsstr( WCHAR_PTR s, WCHAR_PTR t )
+{
+ INT i;
+ i = wcslen( t );
+
+ while ( *s ) {
+ if ( ! wcsncmp( s, t, i ) ) {
+ return( s );
+ }
+ s++;
+ }
+
+ return( NULL );
+}
+
+size_t wcscspn( WCHAR_PTR s, WCHAR_PTR t )
+{
+ size_t index;
+ WCHAR_PTR p;
+
+ for ( index = 0; ( *s ); index++, s++ )
+ {
+ for ( p = t; ( *p ); p++ )
+ {
+ if ( *s == *p )
+ {
+ return index;
+ }
+ }
+ }
+ return index;
+}
+
+#endif //!OS_WIN32
+
+
+/**
+ ANSI strings for use when UNICODE is defined
+**/
+#ifdef UNICODE
+INT strlenA( ACHAR_PTR s )
+{
+ return( strlen( s ) );
+}
+
+ACHAR_PTR strcpyA( ACHAR_PTR s, ACHAR_PTR t )
+{
+ return( strcpy( s, t ) );
+}
+
+ACHAR_PTR strncpyA( ACHAR_PTR s, ACHAR_PTR t, INT i )
+{
+ return( strncpy( s, t, i ) );
+}
+
+ACHAR_PTR strcatA( ACHAR_PTR s, ACHAR_PTR t )
+{
+ return( strcat( s, t ) );
+}
+
+ACHAR_PTR strncatA( ACHAR_PTR s, ACHAR_PTR t, INT i )
+{
+ return( strncat( s, t, i ) );
+}
+
+INT strcmpA( ACHAR_PTR s, ACHAR_PTR t )
+{
+ return( strcmp( s, t ) );
+}
+
+INT strncmpA( ACHAR_PTR s, ACHAR_PTR t, INT i )
+{
+ return( strncmp( s, t, i ) );
+}
+
+INT stricmpA( ACHAR_PTR s, ACHAR_PTR t )
+{
+ return( stricmp( s, t ) );
+}
+
+INT strnicmpA( ACHAR_PTR s, ACHAR_PTR t, INT i )
+{
+ return( strnicmp( s, t, i ) );
+}
+
+ACHAR_PTR strrchrA( ACHAR_PTR s, INT c )
+{
+ return( strrchr( s, c ) );
+}
+
+ACHAR_PTR strchrA( ACHAR_PTR s, INT c )
+{
+ return( strchr( s, c ) );
+}
+
+ACHAR_PTR strpbrkA( ACHAR_PTR s, ACHAR_PTR t )
+{
+ return( strpbrkA( s, t ) );
+}
+
+//ACHAR_PTR strlwrA( ACHAR_PTR s )
+//{
+// return( strlwr( s ) );
+//}
+
+//ACHAR_PTR struprA( ACHAR_PTR s )
+//{
+// return( strupr( s ) );
+//}
+
+ACHAR_PTR strstrA( ACHAR_PTR s, ACHAR_PTR t )
+{
+ return( strstr( s, t ) );
+}
+
+#endif //UNICODE
+
+
+/**
+ begin unicode mapping functions *****
+**/
+
+/**/
+/**
+
+ Name: mapAnsiToUnic()
+
+ Description: Converts ASCII string to UNICODE.
+
+ Modified: 11-Nov-92
+
+ Returns: MAP_DST_OVERFLOW if buffer is too small
+ SUCCESS otherwise.
+
+ Notes: If buffer is too small, *dstStrSize will give the
+ number of additional bytes required.
+ Will work on a string in-place (ie, src==dst).
+
+**/
+INT mapAnsiToUnic( ACHAR_PTR src, WCHAR_PTR dst, INT *dstStrSize )
+{
+ INT result;
+ INT asciiSize = strlenA( src ) + 1;
+
+ if ( (asciiSize * 2) > *dstStrSize )
+ {
+ msassert( (asciiSize * 2) <= *dstStrSize ) ;
+ result = MAP_DST_OVERFLOW ;
+ *dstStrSize = (asciiSize * 2) - *dstStrSize;
+ }
+ else
+ {
+ result = SUCCESS;
+
+ dst += asciiSize - 1;
+ src += asciiSize - 1;
+
+ while ( asciiSize-- > 0 )
+ {
+ *dst = ((unsigned char)*src < MAP_BASE_CH) ?
+ (WCHAR)*src :
+ ansiToUnicExtChTbl[ _cvtExtChToTblIndx( *src ) ];
+
+ dst--, src--;
+ }
+ }
+ return result;
+}
+
+
+INT mapUnicToAnsi( WCHAR_PTR src, ACHAR_PTR dst, const ACHAR rplCh, INT *dstStrSize )
+{
+ WCHAR UNALIGNED *ua_src = (WCHAR UNALIGNED *)src ;
+ INT result = SUCCESS ;
+ INT indx ;
+ ACHAR_PTR pDst = dst ;
+ INT unicSize = sizeof( WCHAR ) ;
+
+ while( *ua_src ) {
+ unicSize += sizeof(WCHAR) ;
+ ua_src++ ;
+ }
+
+ ua_src = (WCHAR UNALIGNED *)src ;
+
+ if ( (unicSize / 2) > *dstStrSize ) {
+ msassert( (unicSize / 2) <= *dstStrSize ) ;
+ result = MAP_DST_OVERFLOW ;
+ *dstStrSize = (unicSize / 2) - *dstStrSize ;
+ }
+ else {
+ /* source string is a NULL terminated string */
+ for ( ; *ua_src != (WCHAR)'\0'; ua_src++ ) {
+ /* assign UNICODE character to destination */
+ if ( *ua_src < MAP_BASE_CH ) {
+ /* direct mapping from UNICODE to ANSI */
+ *pDst = (ACHAR) *ua_src ;
+ }
+ else {
+ /* is char a mappable ANSI extended char */
+ if ( bSrchUnicChTbl( *ua_src, unicExtChTbl, MAP_EXTCH_TBL_SIZ, &indx ) ) {
+ indx = _getAnsiExtCh( indx ) ;
+ }
+ /* okay, it wasn't. How about a mappable ANSI control char */
+ else if ( bSrchUnicChTbl( *ua_src, unicCtrlChTbl, MAP_CTRLCH_TBL_SIZ, &indx ) ) {
+ indx = _getAnsiCtrlCh( indx ) ;
+ }
+ else {
+ indx = 0 ; /* default to not found */
+
+ /* okay, it wasn't. How about a mappable ANSI char from the compatablity zone */
+ if ( ( *ua_src >= MAP_BEGIN_CMPTZONE ) && ( *ua_src <= MAP_END_CMPTZONE ) ) {
+
+ /* ANSI Latin1 mappable chars using offset */
+ if ( ( *ua_src >= 0xFF01 ) && ( *ua_src <= 0xFF5E ) ) {
+ indx = (ACHAR) (( *ua_src & 0x00FF ) + 0x0020 ) ;
+ }
+ /* search compatability zone table for char */
+ else if ( bSrchUnicChTbl( *ua_src, unicCmptZoneChTbl, MAP_COMPATCH_TBL_SIZ, &indx ) ) {
+ indx = _getAnsiCmptZoneCh( indx ) ;
+ }
+ }
+ }
+
+ *pDst = ( indx ) ? (ACHAR) indx : rplCh ;
+ }
+
+ pDst++ ;
+ }
+
+ /* NULL terminate destination */
+ *pDst = '\0' ;
+ }
+
+ return( result ) ;
+}
+
+
+/**/
+/**
+
+ Name: mapAnsiToUnicNoNull()
+
+ Description: Converts ASCII string with possible embedded nulls
+ to UNICODE.
+
+ Modified: 11-Nov-92
+
+ Returns: MAP_DST_OVERFLOW if buffer is too small
+ SUCCESS otherwise.
+
+ Notes: If buffer is too small, *dstStrSize will give the
+ number of additional bytes required.
+ Will work on a string in-place (ie, src==dst).
+
+**/
+INT mapAnsiToUnicNoNull( ACHAR_PTR src, WCHAR_PTR dst, INT srcStrSize, INT *dstStrSize )
+{
+ INT result;
+ INT asciiSize = srcStrSize;
+ WCHAR UNALIGNED *ua_dst = (WCHAR UNALIGNED *)dst ;
+
+ if ( (asciiSize * 2) > *dstStrSize )
+ {
+ result = MAP_DST_OVERFLOW ;
+ *dstStrSize = (asciiSize * 2) - *dstStrSize;
+ }
+ else
+ {
+ result = SUCCESS;
+
+ ua_dst += asciiSize - 1;
+ src += asciiSize - 1;
+
+ while ( asciiSize-- > 0 )
+ {
+ *ua_dst = ((unsigned char)*src < MAP_BASE_CH) ?
+ (WCHAR)*src :
+ ansiToUnicExtChTbl[ _cvtExtChToTblIndx( *src ) ];
+
+ ua_dst--, src--;
+ }
+ }
+ return result;
+}
+
+
+INT mapUnicToAnsiNoNull(
+ WCHAR_PTR src,
+ ACHAR_PTR dst,
+ const ACHAR rplCh,
+ INT srcStrSize,
+ INT *dstStrSize )
+{
+ INT result = SUCCESS ;
+ INT indx ;
+ ACHAR_PTR pDst = dst ;
+ WCHAR UNALIGNED *ua_src = (WCHAR UNALIGNED *)src ;
+
+ if ( (srcStrSize / 2) > *dstStrSize ) {
+ msassert( (srcStrSize / 2) <= *dstStrSize ) ;
+ result = MAP_DST_OVERFLOW ;
+ *dstStrSize = (srcStrSize / 2) - *dstStrSize ;
+ }
+ else {
+ for ( ; srcStrSize > 0; srcStrSize -= sizeof(WCHAR), ua_src++ ) {
+ /* assign UNICODE character to destination */
+ if ( *ua_src < MAP_BASE_CH ) {
+ /* direct mapping from UNICODE to ANSI */
+ *pDst = (ACHAR) *ua_src ;
+ }
+ else {
+ /* is char a mappable ANSI extended char */
+ if ( bSrchUnicChTbl( *ua_src, unicExtChTbl, MAP_EXTCH_TBL_SIZ, &indx ) ) {
+ indx = _getAnsiExtCh( indx ) ;
+ }
+ /* okay, it wasn't. How about a mappable ANSI control char */
+ else if ( bSrchUnicChTbl( *ua_src, unicCtrlChTbl, MAP_CTRLCH_TBL_SIZ, &indx ) ) {
+ indx = _getAnsiCtrlCh( indx ) ;
+ }
+ else {
+ indx = 0 ; /* default to not found */
+
+ /* okay, it wasn't. How about a mappable ANSI char from the compatablity zone */
+ if ( ( *ua_src >= MAP_BEGIN_CMPTZONE ) && ( *ua_src <= MAP_END_CMPTZONE ) ) {
+
+ /* ANSI Latin1 mappable chars using offset */
+ if ( ( *ua_src >= 0xFF01 ) && ( *ua_src <= 0xFF5E ) ) {
+ indx = (ACHAR) (( *ua_src & 0x00FF ) + 0x0020 ) ;
+ }
+ /* search compatability zone table for char */
+ else if ( bSrchUnicChTbl( *ua_src, unicCmptZoneChTbl, MAP_COMPATCH_TBL_SIZ, &indx ) ) {
+ indx = _getAnsiCmptZoneCh( indx ) ;
+ }
+ }
+ }
+
+ *pDst = ( indx ) ? (ACHAR) indx : rplCh ;
+ }
+
+ pDst++ ;
+ }
+ }
+
+ return( result ) ;
+}
+
+
+
+/**
+ begin unicode comparison functions *****
+**/
+
+
+INT cmpiUnicToUnic( WCHAR_PTR ws1, WCHAR_PTR ws2 )
+{
+ INT cmpValu = SUCCESS ;
+
+ /* compare strings, i.e., lowercase */
+ for ( ; !cmpValu && ( *ws1 && *ws2 ); ws1++, ws2++ ) {
+ cmpValu = _toLowerW( *ws1 ) - _toLowerW( *ws2 ) ;
+ }
+
+ /* was one string shorter than the other */
+ if ( !( *ws1 && *ws2 ) ) {
+ cmpValu = *ws1 - *ws2 ;
+ }
+
+ return( cmpValu ) ;
+}
+
+
+
+/**
+ begin memory functions *****
+**/
+
+
+INT memorycmp( const VOID_PTR s1, const INT s1len, const VOID_PTR s2, const INT s2len )
+{
+ INT cmpValu = memcmp( s1, s2, (( s1len < s2len ) ? s1len : s2len ) ) ;
+
+ if ( !cmpValu ) {
+ cmpValu = s2len - s1len ;
+ }
+
+ return( cmpValu ) ;
+}
+
+INT memoryicmp( const VOID_PTR s1, const INT s1len, const VOID_PTR s2, const INT s2len )
+{
+ INT cmpValu = memicmp( s1, s2, (( s1len < s2len ) ? s1len : s2len ) ) ;
+
+ if ( !cmpValu ) {
+ cmpValu = s2len - s1len ;
+ }
+
+ return( cmpValu ) ;
+}
+
+
+
+
+/**
+ begin unicode utility functions *****
+**/
+
+static BOOLEAN bSrchUnicChTbl( WCHAR wch, WCHAR_PTR unicTblArry, INT max, INT *indx )
+{
+ INT min, mid ;
+
+ msassert( unicTblArry != NULL ) ;
+ msassert( max ) ;
+
+ *indx = min = 0 ;
+ max-- ;
+
+ while ( min <= max ) {
+ mid = ( min + max ) / 2 ;
+
+ if ( wch < unicTblArry[ mid ] ) {
+ max = mid - 1 ;
+ }
+ else if ( wch > unicTblArry[ mid ] ) {
+ min = mid + 1;
+ }
+ else {
+ *indx = mid ;
+ return( TRUE ) ;
+ }
+ }
+
+ return( FALSE ) ;
+}
diff --git a/private/utils/ntbackup/src/stubfunc.c b/private/utils/ntbackup/src/stubfunc.c
new file mode 100644
index 000000000..61b1c11ac
--- /dev/null
+++ b/private/utils/ntbackup/src/stubfunc.c
@@ -0,0 +1,206 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: stubfunc.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains a set of stub function. These
+ functions are "DUMMY" functions for the file system tables.
+
+
+ $Log: M:/LOGFILES/STUBFUNC.C_V $
+
+ Rev 1.3 28 Aug 1992 16:31:40 BARRY
+Changed InitGOS to default Novell items differently.
+
+ Rev 1.2 01 Oct 1991 11:16:30 BARRY
+Include standard headers.
+
+ Rev 1.1 24 Jul 1991 11:08:42 DAVIDH
+Corrected Watcom compiler warnings.
+
+ Rev 1.0 09 May 1991 13:40:40 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include <string.h>
+
+#include "stdtypes.h"
+
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "tfldefs.h"
+/* $end$ include list */
+
+/**/
+/**
+
+ Name: DUMMY_CreateIDB()
+
+ Description: For file systems which do not support Images this is
+ the function to use for CreateGenIDB()
+
+ Modified: 9/13/1989
+
+ Returns: TF_SKIP_ALL_DATA
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 DUMMY_CreateIDB( fsh, data )
+FSYS_HAND fsh; /* I - file system handle */
+GEN_IDB_DATA_PTR data ; /* I - retquest structure */
+{
+ (VOID) fsh ;
+
+ data->std_data.dblk->blk_type = IDB_ID ;
+ data->std_data.dblk->com.blkid = data->std_data.blkid;
+ data->std_data.dblk->com.f_d.did = data->std_data.did ;
+ data->std_data.dblk->com.ba.lba = data->std_data.lba ;
+
+ return TF_SKIP_ALL_DATA ;
+}
+
+/**/
+/**
+
+ Name: DUMMY_InitGOS()
+
+ Description: Simpel return of success for GOS
+ initialization.
+
+ Modified: 9/21/1989
+
+ Returns: SUCCESS
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 DUMMY_InitGOS( fsh, gos )
+FSYS_HAND fsh ;
+GOS_PTR gos ;
+{
+ (VOID)fsh;
+
+ memset( gos, 0, sizeof( *gos ) );
+
+ /* Initiailize things that shouldn't default to zero */
+
+ gos->max_rights = 0xff;
+ gos->novell_directory_max_rights = 0xffff;
+
+ return SUCCESS;
+}
+
+/**/
+/**
+
+ Name: DUMMY_EnumSpecFiles()
+
+ Description: This function allways returns NO_MORE
+
+ Modified: 9/4/1990
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 DUMMY_EnumSpecFiles( dle, index, path, psize, fname )
+GENERIC_DLE_PTR dle ;
+UINT16 *index ;
+CHAR_PTR *path ;
+INT16 *psize ;
+CHAR_PTR *fname ;
+{
+ (VOID) dle ; /* Prevent compiler warnings. */
+ (VOID) index ;
+ (VOID) path ;
+ (VOID) psize ;
+ (VOID) fname ;
+
+ return FS_NO_MORE ;
+}
+
+/**/
+/**
+
+ Name: DUMMY_GetSpecDBLKS()
+
+ Description: This function is called to return DBLKS for files or
+ directories which should be backed up first (index = 1) or
+ last (index = -1). For DOS there are no special dblks.
+
+ Modified: 8-21-89
+
+ Returns: Error codes:
+ FS_NO_MORE
+
+ See also: $/SEE( DOS_FindFirst(), DOS_FindNext() )$
+
+ Notes: Should consider if \IO.SYS should be a special dblk.
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 DUMMY_GetSpecDBLKS( fsh, dblk, index )
+FSYS_HAND fsh;
+DBLK_PTR dblk;
+INT32 *index;
+{
+
+ (VOID) dblk ;
+ (VOID) index ;
+ (VOID) fsh ;
+
+ msassert( fsh->attached_dle != NULL ) ;
+
+ return FS_NO_MORE ;
+}
+
+
+
+/**/
+/**
+
+ Name: DUMMY_LogoutDevice()
+
+ Description: Logout of a server.
+
+ Modified: 10-17-90
+
+ Returns: None
+
+ Notes: Only valid when dle is NOVELL_SERVER_ONLY.
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 DUMMY_LogoutDevice( dle )
+GENERIC_DLE_PTR dle ;
+{
+
+ (VOID) dle ;
+
+ return SUCCESS ;
+}
diff --git a/private/utils/ntbackup/src/sx.c b/private/utils/ntbackup/src/sx.c
new file mode 100644
index 000000000..0b1cc41d6
--- /dev/null
+++ b/private/utils/ntbackup/src/sx.c
@@ -0,0 +1,1239 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: sx.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the Support functions for the SX drive
+
+
+ $Log: T:/LOGFILES/SX.C_V $
+
+ Rev 1.14 18 Jan 1993 14:42:40 BobR
+Added MOVE_ESA macro call(s)
+
+ Rev 1.13 29 Dec 1992 13:32:48 DAVEV
+unicode fixes (3)
+
+ Rev 1.12 11 Nov 1992 10:53:58 GREGG
+Unicodeized literals.
+
+ Rev 1.11 22 Sep 1992 11:32:50 GREGG
+Fixed last fixes.
+
+ Rev 1.10 18 Aug 1992 10:35:16 BURT
+fix warnings
+
+ Rev 1.9 17 Aug 1992 09:01:38 GREGG
+Changes to deal with block sizeing scheme.
+
+ Rev 1.8 22 Jul 1992 14:35:38 GREGG
+Fixed warnings.
+
+ Rev 1.7 09 Jun 1992 15:35:16 GREGG
+Changed call to check for continuation block.
+
+ Rev 1.6 21 May 1992 16:22:34 GREGG
+Changed reference to VCB_CONT_BIT to DB_CONT_BIT.
+
+ Rev 1.5 05 Apr 1992 19:09:34 GREGG
+ROLLER BLADES - Changed lw_sx_file_path to lw_cat_file_path.
+
+ Rev 1.4 20 Mar 1992 18:02:36 NED
+added exception updating after TpReceive calls
+
+ Rev 1.3 02 Mar 1992 14:53:26 DON
+added ThreadSwitch's before low level I/O calls
+
+ Rev 1.2 06 Feb 1992 17:34:38 DON
+Added ThreadSwitch call in empty TpReceive call and if no call to ui
+
+ Rev 1.1 17 Oct 1991 01:23:20 GREGG
+Now uses lw_sx_file_path in place of CDS_GetMaynFolder.
+
+ Rev 1.0 30 Sep 1991 11:02:10 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+
+#include <stdio.h>
+#include <conio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys\types.h>
+#include <sys\stat.h>
+#include <io.h>
+#include <memory.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "fsys.h"
+#include "lw_data.h"
+#include "tfl_err.h"
+#include "tfldefs.h"
+#include "sx.h"
+
+/* Device Driver Interface Files */
+#include "retbuf.h"
+#include "special.h"
+#include "dilhwd.h"
+#include "drvinf.h"
+#include "generr.h"
+#include "genfuncs.h"
+#include "dil.h"
+
+#include "be_debug.h"
+
+/*
+ * LOCAL FUNCTION PROTOTYPES
+ */
+
+static BOOLEAN SX_OpenTmpFile( /* called by: SX_StartSampling() */
+ CHANNEL_PTR channel
+) ;
+
+static BOOLEAN SX_SeekFile( /* called by: SX_OpenFile() */
+ CHANNEL_PTR channel, /* SX_SeekSetInFile() */
+ INT32 offset, /* SX_FindBlock() */
+ INT origin, /* SX_StartSampling() */
+ INT file_type
+) ;
+
+static BOOLEAN SX_ReadFile( /* called by: SX_OpenFile() */
+ CHANNEL_PTR channel /* SX_SeekSetInFile() */
+) ;
+
+/**/
+/**
+
+ Name: SX_Begin
+
+ Description: Contains the code to initialize the SX INFO.
+
+ Modified: 5/2/91
+
+ Returns: nothing
+
+ Notes: memory is TpLocked for OS/2 device driver reference
+
+ called by: TFOPEN TF_OpenSet()
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+VOID SX_Begin(
+ CHANNEL_PTR channel,
+ UINT16 tf_mode )
+{
+ /* Initialize SX info */
+ memset( ( VOID_PTR )&channel->sx_info, SX_INITIALIZER, sizeof( SX_INFO ) ) ;
+
+ /* Initialize the SX status */
+ SX_ClearStatus( channel, SX_STATUS ) ;
+
+ /* check to see if we would like to scan tape for positioning information */
+ if( tf_mode & TF_LIST_TAPE_OPERATION ) {
+ SX_SetStatus( channel, SX_LIST_TAPE_IN_PROGRESS ) ;
+ }
+
+#if defined( MAYN_OS2 )
+ /* ( for OS/2 ) lock memory to be used by device driver */
+ TpLock( ( INT8_PTR )&( SX_GetRecord( channel ) ), &( SX_GetLock( channel ) ) ) ;
+#endif
+
+ return ;
+
+}
+
+
+/**/
+/**
+
+ Name: SX_End
+
+ Description: Contains the code to ensure any opened SX file is closed and
+ the SX tmp file is deleted
+
+ Modified: 5/2/91
+
+ Returns: nothing
+
+ Notes: memory is TpLocked for OS/2 device driver reference
+
+ called by: TFCLOSE TF_CloseSet()
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+VOID SX_End( CHANNEL_PTR channel )
+{
+ /* in case positioning was attempted using an SX file for an EXABYTE 8200SX - MaynStream 2200+ ... */
+ if( SX_FileIsOpen( channel ) || SX_TmpFileIsOpen( channel ) ) {
+ SX_CloseFile( channel ) ;
+ }
+
+ /* build the tmp file name */
+ strcpy( lw_cat_file_path_end, SX_TMP_FILE_NAME ) ;
+
+ /* delete the file tmp file */
+ unlink( lw_cat_file_path ) ;
+
+ /* reset the SX status */
+ SX_ClearStatus( channel, SX_STATUS ) ;
+
+#if defined( MAYN_OS2 )
+ /* unlock memory */
+ TpUnlock( &( SX_GetLock( channel ) ) ) ;
+#endif
+
+ return ;
+
+}
+
+
+/**/
+/**
+
+ Name: SX_OpenFile
+
+ Description: Contains the code to open the SX file in READ mode for a physical tape.
+
+ Modified: 4/12/91
+
+ Returns: TRUE - successful
+ FALSE - unsuccessful
+
+ Notes: called by: POSATSET PositionAtSet()
+ READ StartRead()
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+BOOLEAN SX_OpenFile(
+ CHANNEL_PTR channel,
+ UINT32 tape_id,
+ UINT16 ts_num )
+{
+ BOOLEAN result = TRUE ;
+ CHAR sx_file_name[ SX_FILE_NAME_LENGTH ] ;
+
+ /* close any SX files which may be open */
+ result = SX_CloseFile( channel ) ;
+
+ if( result ) {
+
+ /* generate the name in the form "TAPE ID"."TS_NUM" */
+ sprintf( sx_file_name, SX_FILE_FORMAT, tape_id, ts_num ) ;
+
+ /* form the full path name */
+ strcpy( lw_cat_file_path_end, sx_file_name ) ;
+
+ /* relinquish control */
+ ThreadSwitch( ) ;
+
+ /* open the file */
+
+// if( ( SX_FileHandle( channel ) = UNI_fopen( lw_cat_file_path, SX_READ_FLAG ) ) == -1 ) {
+// result = FALSE ;
+// } else {
+// /* indicate the file is opened for READ */
+// SX_SetStatus( channel, SX_OPEN_FOR_READ ) ;
+//
+// /* be sure we are at the beginning */
+// result = SX_SeekFile( channel, 0L, SEEK_SET, SX_FILE ) ;
+//
+// /* indicate where we are at */
+// if( result ) {
+// SX_SetAt( channel, SX_AT_BOF ) ;
+// } else {
+// SX_ClearAt( channel ) ;
+// }
+// }
+ }
+
+ return( result ) ;
+
+}
+
+
+
+
+/**/
+/**
+
+ Name: SX_CloseFile
+
+ Description: Contains the code to close the SX file for a physical tape and the SX tmp file
+ if either or both were open.
+
+ Modified: 5/8/91
+
+ Returns: TRUE - successful
+ FALSE - unsuccessful
+
+ Notes: called by: POSATSET PositionAtSet()
+ READ StartRead()
+ SX SX_OpenFile()
+ SX SX_End()
+ SX SX_EndSampling()
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+BOOLEAN SX_CloseFile( CHANNEL_PTR channel )
+{
+ BOOLEAN result_sx = TRUE ;
+ BOOLEAN result_tmp = TRUE ;
+
+ /* if the SX file is open ... */
+ if( SX_FileIsOpen( channel ) ) {
+
+ /* relinquish control */
+ ThreadSwitch( ) ;
+
+ /* close the SX file */
+ if( close( SX_FileHandle( channel ) ) != 0 ) {
+ result_sx = FALSE ;
+ SX_SetStatus( channel, SX_ERROR ) ;
+ }
+ /* clear the handle */
+ SX_FileHandle( channel ) = -1L ;
+ }
+
+ /* if the SX tmp file is open ... */
+ if( SX_TmpFileIsOpen( channel ) ) {
+
+ /* relinquish control */
+ ThreadSwitch( ) ;
+
+ /* close the SX tmp file */
+ if( close( SX_TmpFileHandle( channel ) ) != 0 ) {
+ result_tmp = FALSE ;
+ SX_SetStatus( channel, SX_ERROR ) ;
+ }
+ /* clear the handle */
+ SX_TmpFileHandle( channel ) = -1L ;
+ }
+
+ /* clear the status of any refernece to files being opened */
+ SX_ClearStatus( channel, SX_OPEN ) ;
+
+ return( result_sx && result_tmp ) ;
+
+}
+
+
+
+
+/**/
+/**
+
+ Name: SX_DeleteFile
+
+ Description: Contains the code to delete the SX file for the specified physical tape.
+
+ Modified: 4/4/91
+
+ Returns: 0 - successful
+ -1 - error ( check errno )
+
+ Notes: called by: POSATSET PositionAtSet()
+ TFERASE TF_EraseChannel()
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+INT16 SX_DeleteFile(
+ UINT32 tape_id,
+ UINT16 ts_num )
+{
+ CHAR sx_file_name[ SX_FILE_NAME_LENGTH ] ;
+
+ /* generate the name in the form "TAPE ID"."TS_NUM" */
+ sprintf( sx_file_name, SX_FILE_FORMAT, tape_id, ts_num ) ;
+
+ /* form the full path name */
+ strcpy( lw_cat_file_path_end, sx_file_name ) ;
+
+ /* delete the file */
+
+ return( unlink( lw_cat_file_path ) ) ;
+
+}
+
+
+
+
+/**/
+/**
+
+ Name: SX_WriteTmpFile
+
+ Description: Contains the code to write a record to the SX tmp file.
+
+ Modified: 4/12/91
+
+ Returns: TRUE - successful
+ FALSE - unsuccessful
+
+ Notes: called by: READ AcquireReadBuffer()
+ READ CleanUpDriverQ()
+ WRITE AcquireWriteBuffer()
+ WRITE FinishWrite()
+ SX SX_ShowBlock()
+ SX SX_StartSampling()
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+BOOLEAN SX_WriteTmpFile( CHANNEL_PTR channel )
+{
+ BOOLEAN result = FALSE ;
+
+ /* the tmp file has to be open ... */
+ if( SX_TmpFileIsOK( channel ) ) {
+
+ /* relinquish control */
+ ThreadSwitch( ) ;
+
+ /* write the record in the tmp file */
+ if( write( SX_TmpFileHandle( channel ),
+ ( CHAR_PTR )&( SX_GetRecord( channel ) ),
+ sizeof( SX_RECORD ) )
+ == sizeof( SX_RECORD ) ) {
+ result = TRUE ;
+#ifdef SX_DEBUG
+ SX_InfoDump( channel, TEXT("SX_WriteTmpFile( )") ) ;
+#endif
+ } else {
+ SX_SetStatus( channel, SX_ERROR ) ;
+ }
+ } else {
+ SX_SetStatus( channel, SX_ERROR ) ;
+ }
+
+ return( result ) ;
+
+}
+
+
+
+
+/**/
+/**
+
+ Name: SX_SeekSetInFile
+
+ Description: Contains the code to lseek to the first record of a set in the SX file.
+
+ Modified: 4/12/91
+
+ Returns: TRUE - successful
+ FALSE - unsuccessful
+
+ Notes: called by: POSATSET PositionAtSet()
+ READ StartRead()
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+BOOLEAN SX_SeekSetInFile(
+ CHANNEL_PTR channel,
+ INT16 set,
+ INT16 mode )
+{
+ BOOLEAN found = FALSE ;
+ BOOLEAN done = FALSE ;
+ SX_RECORD record_hold ;
+
+ /* we are looking into a new set so ... */
+ SX_ClearStatus( channel, SX_FOUND_BLOCK ) ;
+
+ /* the SX file must be open ... */
+ if( SX_FileIsOK( channel ) ) {
+
+ /* if we are just checking to see if this set is here */
+ if( mode == SX_CHECKING_FOR_SET ) {
+
+ /* in case we've got something importaant like a would be VCB */
+ record_hold = SX_GetRecord( channel ) ;
+ }
+
+ /* make sure we're at the beginning */
+ if( !SX_IsStatusSet( channel, SX_AT_BOF ) ) {
+ SX_SeekFile( channel, 0L, SEEK_SET, SX_FILE ) ;
+ }
+
+ do {
+ /* make sure we remember where we were */
+ if( SX_SeekFile( channel, 0L, SEEK_CUR, SX_FILE ) ) {
+
+ /* read the record from the SX file */
+ if( SX_ReadFile( channel ) ) {
+
+ /* determine the set from the record and see it it matches */
+ if( set == SX_GetBackupSetNumber( channel ) ) {
+ found = TRUE ;
+ done = TRUE ;
+ }
+ } else {
+ done = TRUE ;
+ }
+ } else {
+ done = TRUE ;
+ }
+
+ } while( !done ) ;
+
+ /* if we are just checking to see if this set is here */
+ if( mode == SX_CHECKING_FOR_SET ) {
+
+ /* reset the record */
+ SX_SetRecord( channel, record_hold ) ;
+
+ } else if( found ) {
+
+ /* make sure we are at where we were */
+ SX_OffsetFile( channel ) ;
+ SX_SetAt( channel, SX_AT_SET ) ;
+ }
+ }
+
+ return( found ) ;
+
+}
+
+
+
+
+/**/
+/**
+
+ Name: SX_FindBlock
+
+ Description: Contains the code to fast seek to a lba using the SX file.
+
+ Modified: 4/15/91
+
+ Returns: A TFL error code
+
+ Notes: called by: READ StartRead()
+ READ DoRead()
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+INT16 SX_FindBlock(
+ CHANNEL_PTR channel,
+ UINT32 lba,
+ TPOS_PTR ui_tpos,
+ INT16 tf_message )
+{
+ INT16 ret_val = TFLE_DRIVE_FAILURE ;
+ DRIVE_PTR curDRV = channel->cur_drv ;
+ BOOLEAN done = FALSE ;
+ BOOLEAN ready = FALSE ;
+ SX_RECORD record_hold ;
+ UINT32 at_set_hold ;
+ RET_BUF myret ;
+
+ /* we should never be doing this unless we are ready ... */
+ if( SX_IsOK( channel ) &&
+ SX_IsStatusSet( channel, SX_AT_SET ) ) {
+
+ ret_val = TFLE_NO_ERR ;
+ at_set_hold = SX_GetMisc( channel ) ;
+
+ /* let everyone know what we are doing */
+ BE_Zprintf( DEBUG_TAPE_FORMAT,
+ RES_GOTO_LBA,
+ curDRV->cur_pos.pba_vcb,
+ curDRV->cur_pos.lba_vcb,
+ lba,
+ lba ) ;
+
+ if( ui_tpos != NULL ) {
+ ( *ui_tpos->UI_TapePosRoutine )( tf_message,
+ ui_tpos,
+ curDRV->vcb_valid,
+ &curDRV->cur_vcb,
+ 0 ) ;
+ } else {
+ /* relinquish control */
+ ThreadSwitch( ) ;
+ }
+
+ /* since we will overwrite the SX_RECORD */
+ SX_ClearAt( channel ) ;
+
+ /* if we already close by ... */
+ if( SX_IsNearbyLBA( channel, lba ) ) {
+
+ /* but we are not actually already there ... */
+ if( SX_IsNotAlreadyAtLBA( channel, lba ) ) {
+
+ /* VOID out the SX_POSITION information */
+ memset( ( VOID_PTR )&( SX_GetPosition( channel ) ), SX_DO_NOT_MOVE, sizeof( SX_POSITION ) ) ;
+
+ /* indicate where we currently are */
+ SX_SetLBA( channel ) ;
+
+ /* everything is set to issue a TpSpecial call which will only SPACE from where we are */
+ ready = TRUE ;
+ }
+ } else {
+
+ /* find the closest previously sampled position */
+ do {
+ /* hold on to the wanna be */
+ record_hold = SX_GetRecord( channel ) ;
+
+ /* read the next record */
+ if( SX_ReadFile( channel ) ) {
+
+ /* determine if this lba goes too far */
+ if( SX_GetLBA( channel ) > lba ) {
+
+ /* the wanna be is a */
+ SX_SetRecord( channel, record_hold ) ;
+
+ ready = TRUE ;
+ done = TRUE ;
+ }
+ } else {
+ done = TRUE ;
+ }
+
+ } while( !done ) ;
+ }
+
+ if( ready ) {
+
+ /* determine how many blocks to SPACE after the position is reached */
+ if( ChannelBlkSize( channel ) > channel->lb_size ) {
+ channel->sx_info.sx_record.lba =
+ ( lba - SX_GetLBA( channel ) ) /
+ ( ChannelBlkSize( channel ) / channel->lb_size ) ;
+ } else {
+ channel->sx_info.sx_record.lba =
+ ( lba - SX_GetLBA( channel ) ) *
+ ( channel->lb_size / ChannelBlkSize( channel ) ) ;
+ }
+#ifdef SX_DEBUG
+ SX_InfoDump( channel, TEXT("SX_FindBlock( )") ) ;
+#endif
+ /* really go there */
+ TpSpecial( curDRV->drv_hdl, (INT16)SS_FIND_BLOCK, ( UINT32 )&( SX_GetRecord( channel ) ) ) ;
+
+ while( TpReceive( curDRV->drv_hdl, &myret ) == FAILURE ) {
+ if( ui_tpos != NULL ) {
+
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( channel->cur_drv->thw_inf.the, myret.the ) ;
+
+ if( ( *ui_tpos->UI_TapePosRoutine )( TF_IDLE_NOBREAK,
+ ui_tpos,
+ curDRV->vcb_valid,
+ &curDRV->cur_vcb, 0 ) == UI_ABORT_POSITIONING ) {
+ ret_val = TFLE_USER_ABORT ;
+ }
+ } else {
+ /* for non-preemptive operating systems: */
+ ThreadSwitch( ) ;
+ }
+ }
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( channel->cur_drv->thw_inf.the, myret.the ) ;
+
+ if ( myret.gen_error != GEN_NO_ERR ) {
+ curDRV->thw_inf.drv_status = myret.status ;
+ }
+ }
+
+ /* reset the SX file to be positioned at the set for the next search */
+ if( SX_SeekFile( channel, at_set_hold, SEEK_SET, SX_FILE ) ) {
+
+ /* restore the record in the SX info */
+ if( SX_ReadFile( channel ) ) {
+
+ /* reset the SX file to be positioned at the set for the next search */
+ if ( SX_SeekFile( channel, at_set_hold, SEEK_SET, SX_FILE ) ) {
+
+ SX_SetAt( channel, SX_AT_SET ) ;
+ } else {
+ SX_SetStatus( channel, SX_ERROR ) ;
+ }
+ } else {
+ SX_SetStatus( channel, SX_ERROR ) ;
+ }
+ } else {
+ SX_SetStatus( channel, SX_ERROR ) ;
+ }
+ }
+
+ if( !ret_val ) {
+
+ /* we fould what we were looking for */
+ SX_SetLBANow( channel, lba ) ;
+ SX_SetStatus( channel, SX_FOUND_BLOCK ) ;
+ }
+
+ return( ret_val ) ;
+
+}
+
+
+/**/
+/**
+
+ Name: SX_ShowBlock
+
+ Description: Contains the code to determine the position of the drive on an SX drive.
+
+ Modified: 5/2/91
+
+ Returns: A TFL error code
+
+ Notes: called by: DRIVES ReadNextSet()
+ SX SX_SamplingProcessing()
+ SX SX_EndSampling()
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+INT16 SX_ShowBlock(
+ CHANNEL_PTR channel,
+ UINT16 mode )
+{
+ RET_BUF myret ;
+ INT16 ret_val = TFLE_NO_ERR ;
+
+#ifdef SX_DEBUG
+ BE_Zprintf( 0, TEXT("\nSX_ShowBlock()\n") ) ;
+#endif
+
+ if( SX_IsOK( channel ) ) {
+
+ /* reset the memory */
+ memset( ( VOID_PTR )&( SX_GetPosition( channel ) ), SX_INITIALIZER, sizeof( SX_POSITION ) ) ;
+
+ /* do it */
+ TpSpecial( channel->cur_drv->drv_hdl, (INT16)SS_SHOW_BLOCK, ( UINT32 )&( SX_GetPosition( channel ) ) ) ;
+
+ /* if this is not to be queued ... */
+ if( mode & SX_SHOW_IMMEDIATE ) {
+
+ while( TpReceive( channel->cur_drv->drv_hdl, &myret ) == FAILURE ) {
+ /* for non-preemptive operating systems: */
+ ThreadSwitch( ) ;
+ }
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( channel->cur_drv->thw_inf.the, myret.the ) ;
+
+ if( myret.gen_error ) {
+ channel->cur_drv->thw_inf.drv_status = myret.status ;
+ ret_val = TFLE_DRIVE_FAILURE ;
+ } else if( mode & SX_SHOW_WRITE ) {
+ /* write the positioning information sample to the SX file */
+ SX_WriteTmpFile( channel ) ;
+ }
+ }
+
+ if( !ret_val ) {
+ /* if we think this might turn out to be a VCB ... */
+ if( mode & SX_SHOW_VCB_PENDING ) {
+ SX_SetType( channel, SX_VCB_PENDING ) ;
+ } else {
+ SX_ClearType( channel ) ;
+ }
+ }
+ } else {
+ ret_val = TFLE_DRIVE_FAILURE ;
+ }
+
+ return( ret_val ) ;
+
+}
+
+
+/**/
+/**
+
+ Name: SX_SamplingProcessing
+
+ Description: Contains the code to sample the tape position for the SX.
+
+ Modified: 4/11/91
+
+ Returns: Nothing
+
+ Notes: called by: READ ReadRequest()
+ WRITE WriteRequest()
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+VOID SX_SamplingProcessing(
+ CHANNEL_PTR channel,
+ UINT32 bytes )
+{
+ /* is it soup yet ??? */
+ if( SX_SampleNeeded( channel ) ) {
+
+ /* set the lba which will be associated with the position */
+ SX_SetLBA( channel ) ;
+
+ /* determine when the next sample needs to be taken */
+ SX_NextSample( channel ) ;
+
+ SX_ShowBlock( channel, SX_SHOW_QUEUED ) ;
+ }
+
+ /* adjust the LBA for next call to SX_SamplingProcessing */
+ SX_AdjustLBANow( channel, bytes ) ;
+
+ return ;
+
+}
+
+
+
+
+/**/
+/**
+
+ Name: SX_StartSampling
+
+ Description: Contains the code to begin processing records into an SX file
+
+ Modified: 4/11/1991
+
+ Returns: Nothing
+
+ Notes: called by: READ StartRead()
+ WRITE WriteDBLK()
+ WRITE EOM_Write()
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+VOID SX_StartSampling( CHANNEL_PTR channel )
+{
+ /* open tmp file */
+ SX_OpenTmpFile( channel ) ;
+
+ if( SX_TmpFileIsOK( channel ) ) {
+
+ /* set the backup set number which will be associated with the position */
+ SX_SetBackupSetNumber( channel ) ;
+
+
+ /* FIRST figure out where we are ... */
+
+ /* we do things differently for continuation backup sets when scanning a tape ... */
+ if( SX_IsStatusSet( channel, SX_SCAN_ACTIVE ) &&
+ ( FS_IsBlockContinued( ( &channel->cur_drv->cur_vcb ) ) ) ) {
+
+ /* initialize the LBA for the first call to SX_SamplingProcessing */
+ SX_SetLBANow( channel, channel->cur_drv->cur_pos.lba_vcb ) ;
+
+ /* vs. continuation backup sets during WRITE ... */
+ } else if( AtEOM( channel ) ) {
+
+ /* initialize the LBA for the first call to SX_SamplingProcessing */
+ SX_SetLBANow( channel, channel->eom_lba ) ;
+
+ /* vs. anything else */
+ } else {
+
+ /* initialize the LBA for the first call to SX_SamplingProcessing */
+ SX_SetLBANow( channel, SX_FIRST_LBA ) ;
+ }
+
+
+ /* THEN figure out how to go about recording it ... */
+
+ /* we do things differently when scanning a tape ... */
+ if( SX_IsStatusSet( channel, SX_SCAN_ACTIVE ) ) {
+
+ /* set the lba which will be associated with the position */
+ SX_SetLBA( channel ) ;
+
+ /* setup for next call to SX_SamplingProcessing */
+ SX_SetMisc( channel, SX_GetLBANow( channel ) + SX_SAMPLE_RATE ) ;
+
+ /* record the previous SHOW for the VCB now or it might be too late */
+ SX_WriteTmpFile( channel ) ;
+
+ /* vs. anything else */
+ } else {
+
+ /* force a SHOW on next call to SX_SamplingProcessing */
+ SX_SetMisc( channel, SX_GetLBANow( channel ) ) ;
+ }
+ }
+
+ return ;
+
+}
+
+
+
+/**/
+/**
+
+ Name: SX_EndSampling
+
+ Description: Contains the code to get the last sample of the tape position for the SX.
+
+ Modified: 4/11/91
+
+ Returns: Nothing
+
+ Notes: called by: READ AcquireReadBuffer()
+ WRITE FinishWrite()
+ WRITE EOMWrite()
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+VOID SX_EndSampling( CHANNEL_PTR channel )
+{
+ INT32 tmp_file_length ;
+ CHAR sx_file_name[ SX_FILE_NAME_LENGTH ] ;
+
+ if( SX_TmpFileIsOK( channel ) ) {
+
+ /* set the LBA which will be associated with the "last" position */
+ SX_SetLBANow( channel, SX_LAST_LBA ) ;
+
+ /* set the PBA which will be associated with the "last" position */
+ SX_SetLBA( channel ) ;
+
+ /* process the "last" position */
+ SX_ShowBlock( channel, SX_SHOW_IMMEDIATE | SX_SHOW_WRITE ) ;
+
+ if( SX_TmpFileIsOK( channel ) ) {
+
+ /* generate the name in the form "TAPE ID"."TS_NUM" */
+ sprintf( sx_file_name, SX_FILE_FORMAT, channel->tape_id, channel->ts_num ) ;
+
+ /* form the full path name */
+ strcpy( lw_cat_file_path_end, sx_file_name ) ;
+
+ /* open the SX file */
+// if( ( SX_FileHandle( channel ) = UNI_fopen( lw_cat_file_path, SX_WRITE_FLAG ) ) != -1 ) {
+ if ( 0 ) {
+
+ /* indicate the SX file is open */
+ SX_SetStatus( channel, SX_OPEN_FOR_WRITE ) ;
+
+ /* save the length of the SX file */
+ SX_SetMisc( channel, filelength( SX_FileHandle( channel ) ) ) ;
+
+ /* save the length of the temp file */
+ tmp_file_length = filelength( SX_TmpFileHandle( channel ) ) ;
+
+ /* if the lengths of the files are OK ... */
+ if( ( SX_GetMisc( channel ) != -1L ) && ( tmp_file_length != -1L ) ) {
+
+ /* seek to the beginning of the TMP file */
+ SX_SeekFile( channel, 0L, SEEK_SET, SX_TMP_FILE ) ;
+
+ /* seek to the end of the SX file */
+ SX_SeekFile( channel, 0L, SEEK_END, SX_FILE ) ;
+
+ /* if the length of the SX file can be properly extended to include all of the tmp file ... */
+ if( SX_IsOK( channel ) && ( chsize( SX_FileHandle( channel ), SX_GetMisc( channel ) + tmp_file_length ) != -1L ) ) {
+
+ /* reseek to the end of the SX file */
+ SX_OffsetFile( channel ) ;
+
+ /* relinquish control */
+ ThreadSwitch( ) ;
+
+ while( read( SX_TmpFileHandle( channel ),
+ ( CHAR_PTR )&( SX_GetRecord( channel ) ),
+ sizeof( SX_RECORD ) )
+ == sizeof( SX_RECORD ) ) {
+
+ /* relinquish control */
+ ThreadSwitch( ) ;
+
+ write( SX_FileHandle( channel ),
+ ( CHAR_PTR )&( SX_GetRecord( channel ) ),
+ sizeof( SX_RECORD ) ) ;
+ }
+ } else {
+ /* out of disk space */
+ SX_SetStatus( channel, SX_ERROR ) ;
+ }
+ } else {
+ /* ??? */
+ SX_SetStatus( channel, SX_ERROR ) ;
+ }
+ } else {
+ /* out of disk space or ??? */
+ SX_SetStatus( channel, SX_ERROR ) ;
+ }
+ }
+ }
+
+ /* all the positioning info has been gathered for this set so close the SX file */
+ SX_CloseFile( channel ) ;
+
+
+ return ;
+
+}
+
+
+
+
+/**/
+/**
+
+ Name: SX_OpenTmpFile
+
+ Description: Contains the code to open the SX tmp file
+
+ Modified: 4/12/91
+
+ Returns: TRUE - successful
+ FALSE - unsuccessful
+
+ Notes: called by: SX_StartSampling()
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+static BOOLEAN SX_OpenTmpFile( CHANNEL_PTR channel )
+{
+ BOOLEAN result = TRUE ;
+
+ /* form the full path name */
+ strcpy( lw_cat_file_path_end, SX_TMP_FILE_NAME ) ;
+
+ /* relinquish control */
+ ThreadSwitch( ) ;
+
+ /* open the file */
+// if( ( SX_TmpFileHandle( channel ) = UNI_fopen( lw_cat_file_path, SX_TMP_FLAG ) ) == -1 ) {
+//
+ SX_SetStatus( channel, SX_ERROR ) ;
+ result = FALSE ;
+
+// } else {
+//
+// SX_SetStatus( channel, SX_TMP_OPEN_FOR_WRITE ) ;
+// }
+
+ return( result ) ;
+
+}
+
+
+
+/**/
+/**
+
+ Name: SX_SeekFile
+
+ Description: Contains the code to lseek in the SX file.
+
+ Modified: 5/5/91
+
+ Returns: TRUE - successful
+ FALSE - unsuccessful
+
+ Notes: called by: SX_OpenFile()
+ SX_FindBlock()
+ SX_SeekSetInFile()
+ SX_StartSampling()
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+static BOOLEAN SX_SeekFile(
+ CHANNEL_PTR channel,
+ INT32 offset,
+ INT origin,
+ INT file_type )
+{
+ BOOLEAN result = FALSE ;
+ INT32 position = -1L ;
+
+ /* do it for either the SX file or the SX tmp file according to file_type */
+ if( ( file_type == SX_FILE ) ? SX_FileIsOK( channel ) : SX_TmpFileIsOK( channel ) ) {
+
+ if( ( position = lseek( ( file_type == SX_FILE ) ? SX_FileHandle( channel )
+ : SX_TmpFileHandle( channel ),
+ offset,
+ origin ) ) != -1L ) {
+ result = TRUE ;
+ }
+ }
+
+ /* if you can't get there from here ... */
+ if( position == -1L ) {
+ SX_SetStatus( channel, SX_ERROR ) ;
+ }
+
+ if( SX_IsStatusSet( channel, SX_OPEN_FOR_READ ) ) {
+ /* this is how we know where we are at */
+ SX_SetMisc( channel, position ) ;
+ }
+
+ if( file_type == SX_FILE ) {
+ /* we are no longer where we were */
+ SX_ClearAt( channel ) ;
+ }
+
+ return( result ) ;
+
+}
+
+
+
+
+/**/
+/**
+
+ Name: SX_ReadFile
+
+ Description: Contains the code to read a record from the SX file.
+
+ Modified: 4/12/91
+
+ Returns: TRUE - successful
+ FALSE - unsuccessful
+
+ Notes: called by: SX_OpenFile()
+ SX_SeekSetInFile()
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+static BOOLEAN SX_ReadFile( CHANNEL_PTR channel )
+{
+ BOOLEAN result = FALSE ;
+
+ /* the SX file needs to be open ... */
+ if( SX_FileIsOK( channel ) ) {
+
+ /* relinquish control */
+ ThreadSwitch( ) ;
+
+ /* read a record */
+ if( read( SX_FileHandle( channel ),
+ ( CHAR_PTR )&( SX_GetRecord( channel ) ),
+ sizeof( SX_RECORD ) )
+ == sizeof( SX_RECORD ) ) {
+ result = TRUE ;
+ }
+ } else {
+ SX_SetStatus( channel, SX_ERROR ) ;
+ }
+
+ /* we are no longer where we were */
+ SX_ClearAt( channel ) ;
+
+ return( result ) ;
+
+}
+
+
+
+#ifdef SX_DEBUG
+
+/**/
+/**
+
+ Name: SX_InfoDump
+
+ Description: Contains the code to debug the current sx_info
+
+ Modified: 4/23/91
+
+ Returns: Nothing
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+VOID SX_InfoDump(
+ CHANNEL_PTR channel,
+ CHAR_PTR message )
+{
+ INT16 index ;
+
+ BE_Zprintf( 0, TEXT("\n\nposition") ) ;
+
+ for( index = 0 ; index < sizeof( SX_POSITION ) ; index++ ) {
+ BE_Zprintf( 0, TEXT(" %02X"), channel->sx_info.sx_record.sx_position.data[ index ] ) ;
+ }
+
+ BE_Zprintf( 0, TEXT("\nset 0x%04x"), channel->sx_info.sx_record.set ) ;
+ BE_Zprintf( 0, TEXT("\nlba 0x%08lx"), channel->sx_info.sx_record.lba ) ;
+ BE_Zprintf( 0, TEXT("\nlba_now 0x%08lx"), channel->sx_info.lba_now ) ;
+ BE_Zprintf( 0, TEXT("\nmisc 0x%08lx"), channel->sx_info.misc ) ;
+ BE_Zprintf( 0, TEXT("\nhdl 0x%04x"), channel->sx_info.sx_hdl ) ;
+ BE_Zprintf( 0, TEXT("\ntmp 0x%04x"), channel->sx_info.sx_tmp ) ;
+ BE_Zprintf( 0, TEXT("\nstatus 0x%04x"), channel->sx_info.status ) ;
+
+ BE_Zprintf( 0, TEXT("\n\n%s\n\n"), message ) ;
+
+ return ;
+
+}
+
+#endif
+
+
diff --git a/private/utils/ntbackup/src/sypl10rd.c b/private/utils/ntbackup/src/sypl10rd.c
new file mode 100644
index 000000000..4652b440a
--- /dev/null
+++ b/private/utils/ntbackup/src/sypl10rd.c
@@ -0,0 +1,1365 @@
+/**
+Copyright(c) Archive Software Division 1984-89
+
+
+ Name: sypl10rd.c
+
+ Description: Translator for Sytos Plus V. 1.0
+
+ $Log: T:/LOGFILES/SYPL10RD.C_V $
+
+ Rev 1.38.1.2 01 Jun 1994 14:08:00 GREGG
+Process the ACL data stream BEFORE the EA data stream.
+
+ Rev 1.38.1.1 24 May 1994 14:56:32 GREGG
+Clear channel skip_stream bit in ReadMakeStreams.
+
+ Rev 1.38.1.0 02 Mar 1994 18:28:34 GREGG
+Don't screw with the channel's stream info in init!!!
+
+ Rev 1.38 22 Feb 1994 18:03:36 GREGG
+Reset the 'streamMode' flag at the start of all read operations (EPR 91).
+
+ Rev 1.37 16 Feb 1994 19:17:00 GREGG
+More fixes to ConvertName, and changed return types to match func tab.
+
+ Rev 1.36 14 Feb 1994 17:06:32 GREGG
+Fixed reading of UNC path names. Cleaned up ConvertName function and
+added error handling to loop reading past the first filemark in the
+NewTape routine.
+
+ Rev 1.35 24 Jan 1994 15:59:34 GREGG
+Fixed warnings.
+
+ Rev 1.34 16 Jan 1994 14:31:56 GREGG
+Unicode bug fixes.
+
+ Rev 1.33 14 Jan 1994 15:25:36 BARRY
+Adjust string counts and terminate strings after strncpy calls
+
+ Rev 1.32 15 Dec 1993 19:48:24 GREGG
+Added support for UNC path specification.
+
+ Rev 1.31 22 Nov 1993 18:07:08 BARRY
+Unicode fixes. Used ANSI versions of string functions. Made about
+a million unnecessary casts to CHAR_PTR because the FSYS headers
+aren't correct. These should probably be cleaned up at a later time.
+
+
+ Rev 1.30 21 Oct 1993 15:57:36 BARRY
+Fixed warning
+
+ Rev 1.29 16 Aug 1993 22:43:08 BARRY
+Fix warning.
+
+ Rev 1.28 09 Aug 1993 16:41:36 TerriLynn
+Fix for EPR#357-698
+
+ Rev 1.27 02 Aug 1993 17:04:02 TerriLynn
+Added TFLE for Use SYPL ECC Flag
+
+ Rev 1.26 26 Jul 1993 14:35:18 TerriLynn
+The Enterprise team must be able to
+see this global or they don't compile.
+
+ Rev 1.25 21 Jul 1993 18:25:14 TerriLynn
+Set the VCB's tape seq num with the one from tape.
+In New Tape, check for user requested processing
+of Sytron's ECC.
+
+ Rev 1.24 16 Jul 1993 12:13:52 STEVEN
+fix alignment problem on mips
+
+ Rev 1.23 15 Jul 1993 14:21:48 STEVEN
+fix volume header
+
+ Rev 1.22 23 Jun 1993 16:25:38 STEVEN
+fix retrans bug with ECC
+
+ Rev 1.21 17 May 1993 09:30:28 TerriLynn
+fixed compiler warning from ReTranslate
+
+ Rev 1.19 13 May 1993 17:51:34 Terri_Lynn
+If EOM need to set continue obj true
+
+ Rev 1.18 13 May 1993 16:11:50 Terri_Lynn
+Changed Stream order for EAs ACLs and Data
+
+ Rev 1.17 11 May 1993 21:55:32 GREGG
+Moved Sytos translator stuff from layer-wide area to translator.
+
+ Rev 1.16 11 May 1993 08:50:40 Terri__Lynn
+Initialize pad_size in FDB and DDB
+
+ Rev 1.15 10 May 1993 17:03:00 Terri_Lynn
+ added Steve's change to make it a super streamer
+
+ Rev 1.14 10 May 1993 15:12:20 Terri_Lynn
+Added Steve's changes and My changes for EOM processing
+
+ Rev 1.13 05 May 1993 13:53:08 terri
+1) Applied stream processing to MakeDDB for ACLs and EAs via the Mountain Man
+2) Added Steve's fix to consistently set stream processing to FALSE
+
+
+ Rev 1.12 03 May 1993 16:23:16 TERRI
+
+1) Made NULL correction in ConvertName instead of MakeDDB.
+2) Re-Initialize stream stuff on the second pass.
+3) In debug code, dump the complete header and EA block.
+4) Deleted reread stuff when the common header is not found. Instead
+ continue to process as a BT_STREAM. This has the same effect.
+
+ Rev 1.11 02 May 1993 20:17:52 BARRY
+Got rid of ternary that MIPS refused to compile.
+
+ Rev 1.10 28 Apr 1993 17:58:36 TERRI
+
+Surrounded the temporary code with if
+defined SYPL10_TRANS_DEBUG
+
+ Rev 1.9 28 Apr 1993 17:34:00 TERRI
+
+Updated file name and path name with ending
+NULLS and incremented the length of each. In other
+words, "STRING" len is 6 now is "STRING0" len is 7.
+
+Also there is temporay code in this version. The code
+creates an output file, syplea.dat with EA data info.
+The format is FilenameBeginofEAData. For the Mountain Man.
+
+ Rev 1.8 26 Apr 1993 02:43:42 GREGG
+Sixth in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Redefined attribute bits to match the spec.
+ - Eliminated unused/undocumented bits.
+ - Added code to translate bits on tapes that were written wrong.
+
+Matches MAYN40RD.C 1.59, DBLKS.H 1.15, MAYN40.H 1.34, OTC40RD.C 1.26,
+ SYPL10RD.C 1.8, BACK_VCB.C 1.17, MAYN31RD.C 1.44, SYPL10.H 1.2
+
+ Rev 1.7 21 Apr 1993 17:02:52 TERRI
+Fixed count for number of tapes.
+Fixed display size for a backup set.
+Changed reaction when a file header can't
+be found for the second time.
+
+ Rev 1.5 08 Apr 1993 12:10:16 TERRI
+Removed references to long names EA and ACL.
+Fixed inability to create sub dirs - don't eat the sub dir header
+
+
+
+ Rev 1.4 02 Apr 1993 12:52:32 TERRI
+Took out code path for setting long names when GENing an FDB or DDB
+**
+*/
+#include <malloc.h>
+#include <string.h>
+#include <ctype.h>
+#include <memory.h>
+#include <time.h>
+#include <stdio.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "datetime.h"
+#include "msassert.h"
+#include "channel.h"
+#include "drive.h"
+#include "drvinf.h"
+#include "dilhwd.h"
+#include "retbuf.h"
+#include "dddefs.h"
+#include "dil.h"
+#include "buffman.h"
+#include "tfl_err.h"
+#include "tfldefs.h"
+#include "translat.h"
+#include "lwprotos.h"
+#include "lw_data.h"
+#include "fmteng.h"
+#include "generr.h"
+#include "genstat.h"
+#include "transutl.h"
+#include "osinfo.h"
+
+/* local includes */
+#include "syplpto.h" /* sytos plus prototypes */
+#include "sypl10.h" /* sytos plus structures and defines */
+
+static VOID _near SYPLSetStandFields( CHANNEL_PTR, STD_DBLK_DATA_PTR ) ;
+
+#ifdef OS_DOS
+#pragma alloc_text( SYPL10RD_1, SYPL_Initialize, SYPL_DeInitialize, SYPL_GetCurrentVCB )
+#pragma alloc_text( SYPL10RD_2, SYPL_Parse, SYPL_ReadMakeDDB, SYPL_ReadMakeFDB )
+#pragma alloc_text( SYPL10RD_3, SYPL_NewTape, SYPL_ReTranslate )
+#pragma alloc_text( SYPL10RD_4, SYPLDateToDateTime, ConvertName )
+#pragma alloc_text( SYPL10RD_5, DecryptTapePassword, NextECC )
+#pragma alloc_text( SYPL10RD_6, SYPL_ReadMakeStreams SYPL_RdException )
+#pragma alloc_text( SYPL10RD_7, SYPL_MoveToVCB )
+#endif
+
+/* define iff viper tdh is fixed to propegate EOM status */
+#define TRUST_VIPER_EOM 0
+
+/**/
+/**
+
+ Name: SYPLDatetoDateTime
+
+ Description: Converts Sytos Plus' modified date format to
+ a date time pointer.
+
+**/
+static VOID NEAR SYPLDateToDateTime(
+ UINT32_PTR date, /* I pointer to Sytos Plus Date */
+ DATE_TIME_PTR datetime /* O pointer to a datetime struct */
+ )
+{
+ S10_DATE_FIELD_PTR df ;
+ S10_TIME_FIELD_PTR tf ;
+ UINT16 low ;
+ UINT16 high ;
+ UINT32 UNALIGNED *udate = (UINT32 UNALIGNED *)date ;
+ DATE_TIME UNALIGNED *udatetime = (DATE_TIME UNALIGNED *)datetime ;
+
+ udatetime->date_valid = FALSE ;
+
+ high = (UINT16)( *udate ) ; /* This is high to Sytos i.e. Motorola */
+ low = (UINT16)( *udate >> 16 ) ; /* This is low to Sytos i.e. Motorola */
+
+ df = (S10_DATE_FIELD_PTR ) &high ;
+ tf = (S10_TIME_FIELD_PTR ) &low ;
+
+ if( *udate != FAT_FILE_SYSTEM ) {
+ udatetime->second = (UINT16)tf->second ;
+ udatetime->minute = (UINT16)tf->minute ;
+ udatetime->hour = (UINT16)tf->hour ;
+ udatetime->day = (UINT16)df->day ;
+ udatetime->month = (UINT16)df->month ;
+ udatetime->year = (UINT16)df->year + 1900 ;
+ udatetime->date_valid = TRUE ;
+ udatetime->day_of_week = 0 ;
+ }
+
+}
+/**/
+/**
+
+ Name: DeterminePadSize
+
+ Description: Determines the pad size when given the length of data
+ and the current block size.
+**/
+
+static UINT16 NEAR DeterminePadSize(
+ UINT32 data_len, /* I length of data */
+ UINT16 block_size /* I current block size */
+ )
+{
+ UINT16 nbb = 0 ; /* next block boundary */
+ UINT16 blks = 0 ; /* number of blocks */
+ UINT16 pad_size = 0 ; /* pad size */
+
+ if( data_len > 0 ) {
+ /* calculate next block boundary */
+ if( data_len > block_size ) {
+ /* Calculate the next block boundary */
+ blks = (UINT16)data_len / block_size ;
+ if( data_len % block_size ) {
+ blks++ ;
+ }
+ nbb = blks * block_size ;
+ /* calculate pad size */
+ pad_size = (UINT16)(nbb - data_len) ;
+ } else {
+ if( data_len == block_size ) {
+ pad_size = 0 ;
+ } else {
+ pad_size = block_size - (UINT16)data_len ;
+ }
+ }
+ }
+ return pad_size ;
+}
+/**/
+/**
+
+ Name: DecryptTapePassword
+
+ Description: Decrypts the tapes password located in the
+ tape header.
+
+**/
+static VOID NEAR DecryptTapePassword(
+ VOID_PTR buffer /* I buffer containing the tape header */
+ )
+{
+ S10_COMMON_HEADER_PTR common_hdr_ptr = (S10_COMMON_HEADER_PTR)buffer ;
+ UINT8_PTR p = buffer ;
+ size_t size = 0 ;
+
+ switch ( common_hdr_ptr->type ) {
+
+ case tape_header_type :
+ {
+ S10_TAPE_HEADER_PTR th = (S10_TAPE_HEADER_PTR)buffer ;
+ /* decrypt the password */
+ for ( size = SHORT_NAME_LEN, p = th->password; size > 0 && *p != '\0'; p++, size-- ) {
+ *p ^= PWD_CRYPT_CHAR ;
+ }
+ }
+ break ;
+
+ default : /* garbage data */
+ msassert( FALSE ) ;
+ break ;
+ }
+}
+/**/
+/**
+
+ Name: NextECC
+
+ Description: Calculates the distance in bytes to the next
+ ECC ( -1K..15K). Uses CHANNEL::blocks_used
+ and S10_ENV::prior_blocks_used
+
+**/
+
+static INT16 NEAR NextECC( CHANNEL_PTR channel, BUF_PTR buffer )
+{
+ S10_ENV_PTR env = channel->fmt_env ;
+ UINT32 here ; /* byte offset within set */
+
+ msassert( env->using_ecc ) ;
+
+ here = ( ( env->prior_blocks_used + channel->blocks_used ) << 9 ) + BM_NextByteOffset( buffer ) ;
+ return ( 16384 - 1024 ) - (INT16)( here & 16383UL ) ;
+}
+
+/**/
+/**
+
+ Name: ConvertName
+
+ Description: Parses out file and path. Changes backslashes to nulls.
+
+ Assigns new path or file len to size.
+
+**/
+static void NEAR ConvertName( VOID_PTR header )
+{
+ S10_DIRECTORY_HEADER_PTR dh = (S10_DIRECTORY_HEADER_PTR)header ;
+ S10_FILE_HEADER_PTR fh = (S10_FILE_HEADER_PTR)header ;
+ BYTE_PTR p ;
+ UINT16 pos, len ;
+
+ switch ( dh->common.type ) {
+
+ case directory_header_type :
+ if ( ( dh->path_name[0] == '\\' ) && (dh->path_name[1] == '\\') ) {
+ /* get rid of UNC name */
+ pos = 2 ;
+ while( pos < dh->path_len &&
+ dh->path_name[pos] != '\\' &&
+ dh->path_name[pos] != '\0' ) {
+ pos++ ;
+ }
+ if( pos == dh->path_len || dh->path_name[pos] == '\0' ) {
+ /* This shouldn't happen!!! We need an error!!! */
+ msassert( FALSE ) ;
+ dh->path_name[0] = '\0' ;
+ dh->path_len = 1 ;
+ break ; // END OF CASE
+ }
+ pos++ ;
+ while( pos < dh->path_len &&
+ dh->path_name[pos] != '\\' &&
+ dh->path_name[pos] != '\0' ) {
+ pos++ ;
+ }
+ if( pos == dh->path_len || dh->path_name[pos] == '\0' ) {
+ /* This is a root */
+ dh->path_name[0] = '\0' ;
+ dh->path_len = 1 ;
+ break ; // END OF CASE
+ }
+ pos++ ;
+ dh->path_len -= pos ;
+ memmove( dh->path_name, &dh->path_name[pos], (size_t)dh->path_len );
+
+ /* Change NULLs to SLASHES in the path */
+ for( p = dh->path_name, len = 0; len < dh->path_len; p++, len++ ) {
+ if( *p == '\\' ) {
+ *p = '\0' ;
+ }
+ }
+ dh->path_name[dh->path_len++] = '\0' ;
+
+ /* get rid of the drive letter */
+ } else if( dh->path_name[1] == ':' && dh->path_len > 2 ) {
+
+ /* for the path */
+ dh->path_len -= 3 ;
+ memmove( dh->path_name, &dh->path_name[3], (size_t)dh->path_len );
+
+ /* Change NULLs to SLASHES in the path */
+ for( p = dh->path_name, len = 0; len < dh->path_len; p++, len++ ) {
+ if ( *p == '\\' ) {
+ *p = '\0' ;
+ }
+ }
+ dh->path_name[dh->path_len++] = '\0' ;
+
+ } else {
+ /* for the root */
+ dh->path_name[0] = '\0' ;
+ dh->path_len = 1 ;
+
+ }
+ break ;
+
+ case file_header_type :
+ p = fh->filename + strlenA( fh->filename ) ;
+ while( p > fh->filename && *p != '\\' ) {
+ p-- ;
+ }
+ if( *p == '\\' ) {
+ p++ ;
+ }
+ fh->filename_len = strlenA( p ) + 1 ;
+ if( p != fh->filename ) {
+ memmove( fh->filename, p, (size_t)fh->filename_len ) ;
+ }
+ break ;
+ }
+}
+
+/**/
+/**
+
+ Name: SYPL_Initialize
+
+ Description: Allocates environment memory for translator
+
+**/
+INT16 SYPL_Initialize(
+ CHANNEL_PTR channel ) /* I channel pointer */
+{
+ S10_ENV_PTR env ;
+
+ /* allocate environment memory */
+ channel->fmt_env = env = calloc( 1, sizeof( S10_ENV ) ) ;
+ if ( env == NULL ) {
+ return TFLE_NO_MEMORY ;
+ }
+ env->bytes_left = TRUE ;
+
+ /* Reset stream stuff */
+ env->no_streams = 0 ;
+ env->streamMode = FALSE ;
+ env->currentStream = 0 ;
+
+ return TFLE_NO_ERR ;
+}
+
+/**/
+/**
+
+ Name: SYPL_NewTape
+
+ Description: Called upon first examining a new tape. This may
+ do special per-tape things for the translator.
+ When this is called, we are sitting in the right
+ place: just after the first filemark. We use all
+ the data in the buffer. Returns TFLE_xxxx codes.
+**/
+INT16 SYPL_NewTape(
+ CHANNEL_PTR channel, /* I current channel */
+ BUF_PTR buffer, /* I buffer with bytes from beginning of tape */
+ BOOLEAN_PTR need_read ) /* O TRUE if we need to re-read tape */
+{
+ S10_ENV_PTR env = channel->fmt_env ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ TPOS_PTR tpos_ptr = channel->ui_tpos;
+
+ /* from tape just read: */
+ S10_TAPE_HEADER tape_hdr ; /* from this tape */
+ S10_TAPE_HEADER_PTR header = (VOID_PTR)(BM_NextBytePtr( buffer ));
+
+ tape_hdr = *header; /* copy our header */
+ header = &tape_hdr; /* cause we're going to kill the buffer */
+
+ env->block_size = ChannelBlkSize( channel ) ;
+
+ /* The next assignment is not good because the
+ block size of the drive is not necessarily
+ the tape's logical block size but it is needed
+ to avoid a divide by zero in read.c at Start
+ Read Operation. The size can be 512 or 1024K.
+ */
+ channel->lb_size = ChannelBlkSize( channel ) ;
+
+ DecryptTapePassword( header ) ;
+
+ if ( env->continuing ) {
+ if ( header->tape_date != env->family_id || header->tape_seq_num != env->destination_tape_seq_num ) {
+ ret_val = TF_WRONG_TAPE ;
+ tpos_ptr->tape_seq_num = env->destination_tape_seq_num ;
+ }
+ } else {
+ if ( tpos_ptr == NULL || tpos_ptr->tape_id == -1 ) { /* they don't care which family */
+ if ( header->tape_seq_num != 1 ) { /* can't read this way */
+ ret_val = TF_TAPE_OUT_OF_ORDER ;
+ }
+ } else if ( tpos_ptr->tape_id != (INT32)header->tape_date ) { /* they've specified a family */
+ ret_val = TF_WRONG_TAPE ; /* and this isn't it! */
+ } else if ( header->tape_seq_num != 1 ) { /* right family... */
+ ret_val = TF_WRONG_TAPE ; /* ...wrong starting tape */
+ tpos_ptr->tape_seq_num = 1 ; /* ensure we request it! */
+ }
+ }
+
+ if ( ret_val != TFLE_NO_ERR ) {
+ return ret_val ;
+ }
+
+ /* Get the Tape Header Information */
+
+ strncpyA( env->volname, header->tape_name, SHORT_NAME_LEN );
+ env->volname[SHORT_NAME_LEN] = '\0';
+
+ strncpyA( env->password, header->password, SHORT_NAME_LEN );
+ env->password[SHORT_NAME_LEN] = '\0';
+
+ strncpyA( env->tape_descrpt, header->tape_descrpt, DESCRPT_LEN );
+ env->tape_descrpt[DESCRPT_LEN] = '\0';
+
+ SYPLDateToDateTime( &header->tape_date, &env->tape_date ) ;
+ env->family_id = header->tape_date ;
+ env->tape_seq_num = header->tape_seq_num ;
+
+ if ( ( env->tape_seq_num = header->tape_seq_num ) == 1 ) {
+ /* Initialize Backup Set Number */
+ env->current_vcb.bset_num = 1 ;
+
+ switch( gnProcessSytronECC ) {
+ case SYPL_ECC_ON:
+ header->ecc_flag = SYPL_ECC_ON ;
+ break ;
+ case SYPL_ECC_OFF:
+ header->ecc_flag = SYPL_ECC_OFF ;
+ break ;
+ default:
+ /* leaves ecc flag as is */
+ break ;
+ }
+
+ if( header->ecc_flag ) {
+ /* Check for ECC Data */
+ /* assumes that buffers are greater than 512 bytes in length. */
+ env->using_ecc = ( BM_BytesFree( buffer ) > env->block_size ) ;
+ }
+ }
+
+ /* Did we not eat the filemark? We can fix that... */
+ while ( BM_ReadError( buffer ) == GEN_NO_ERR ) {
+ INT16 drv_hdl = channel->cur_drv->drv_hdl ;
+ RET_BUF myret ;
+
+ if( TpRead( drv_hdl, BM_XferBase( buffer ), (UINT32)BM_XferSize( buffer ) ) != SUCCESS ) {
+ return( TFLE_DRIVER_FAILURE ) ;
+ }
+ while( TpReceive( drv_hdl, &myret ) == FAILURE ) {
+ ThreadSwitch() ;
+ }
+ BM_SetReadError( buffer, myret.gen_error );
+ }
+
+ switch( BM_ReadError( buffer ) ) {
+ case GEN_ERR_ENDSET : // This is the one we want!
+ break ;
+
+ case GEN_ERR_EOM :
+ case GEN_ERR_NO_DATA :
+ ret_val = TF_INVALID_VCB ;
+ break ;
+
+ case GEN_ERR_BAD_DATA :
+ case GEN_ERR_UNRECOGNIZED_MEDIA :
+ case GEN_ERR_WRONG_BLOCK_SIZE :
+ ret_val = TF_READ_ERROR ;
+ break ;
+
+ case GEN_ERR_NO_MEDIA :
+ ret_val = TF_NO_TAPE_PRESENT ;
+ break ;
+
+ default :
+ ret_val = TFLE_DRIVE_FAILURE ;
+ break ;
+ }
+
+ BM_UseAll( buffer ) ; /* consume all the buffer */
+ *need_read = TRUE ; /* we need to re-read the tape */
+ channel->cur_drv->cur_pos.fmks = 1 ;
+
+ return ret_val ;
+}
+
+/**/
+/**
+
+ Name: SYPL_MoveToVCB
+
+ Description: Move to next/prior/current VCB position
+
+
+**/
+INT16 SYPL_MoveToVCB(
+ CHANNEL_PTR channel, /* I channel pointer */
+ INT16 number, /* I number of file marks to move */
+ BOOLEAN_PTR need_read, /* I true if need to read tape */
+ BOOLEAN really_move ) /* I true if we are really moving tape */
+{
+ INT16 nmarks ; /* number of file marks to move */
+ BOOLEAN at_mos = IsPosBitSet( channel->cur_drv, AT_MOS ) != 0UL ;
+ BOOLEAN at_eos = ( ! at_mos ) && IsPosBitSet( channel->cur_drv, AT_EOS ) ;
+ BOOLEAN at_eod = IsPosBitSet( channel->cur_drv, AT_EOD ) != 0UL ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ INT16 direction ;
+ S10_ENV_PTR env = channel->fmt_env ;
+ TPOS_PTR tpos_ptr = channel->ui_tpos;
+
+ msassert( number <= 1 ) ;
+
+ if ( really_move ) {
+ *need_read = FALSE ;
+ env->prior_blocks_used = 0 ;
+ channel->blocks_used = 0 ;
+
+ if ( env->using_ecc ) {
+ channel->retranslate_size = U32_To_U64( (UINT32)NextECC( channel, channel->cur_buff ) );
+ } else {
+ channel->retranslate_size = lw_UINT64_MAX ;
+ }
+ env->in_ecc = FALSE ;
+ env->streamMode = FALSE ;
+ return TFLE_NO_ERR ;
+ }
+
+ ClrPosBit( channel->cur_drv, AT_MOS ) ;
+
+ /* compute the number of filemarks we have to move. */
+
+ if ( number == 1 ) { /* move forward */
+ *need_read = TRUE ;
+ if ( at_eod ) { /* they'll find out soon enough when they read */
+ return TFLE_NO_ERR ;
+ }
+ if ( at_eos ) {
+ env->current_vcb.bset_num++;
+ return TFLE_NO_ERR ;
+ }
+ ret_val = MoveFileMarks( channel, (INT16)1, (INT16)FORWARD ) ; /* no data? */
+ if ( ret_val == TFLE_NO_ERR ) {
+ env->current_vcb.bset_num++;
+ } else if ( ret_val == TFLE_UNEXPECTED_EOM || ret_val == TF_NO_MORE_DATA ) {
+ env->continuing = TRUE;
+ env->destination_tape_seq_num = env->tape_seq_num + 1;
+ ret_val = TF_NEED_NEW_TAPE;
+ }
+ return ret_val;
+ } else if ( number < 0 ) { /* move backward */
+ direction = BACKWARD ;
+ nmarks = -number + ( at_eos || at_eod ) ;
+ } else { /* current */
+ direction = BACKWARD ;
+ env->prior_blocks_used = 0UL ;
+ if ( at_mos ) {
+ nmarks = 0 ; /* have to go back just after immediately prior */
+ } else if ( at_eos || at_eod ) {
+ nmarks = 1 ; /* have to go back to beginning of last set */
+ } else {
+ *need_read = FALSE ;
+ return TFLE_NO_ERR ;
+ }
+ }
+
+ /* here, we have to move backwards */
+
+ /* if we have to go back to another tape
+ * or back to the start of a continued set, then start at tape 1
+ */
+ if ( nmarks > (INT16)channel->cur_drv->cur_pos.fmks - 1
+ || ( (INT16)channel->cur_drv->cur_pos.fmks - nmarks == 1
+ && env->tape_seq_num != 1 ) ) {
+ tpos_ptr->tape_seq_num = env->destination_tape_seq_num = 1;
+ ret_val = TF_WRONG_TAPE ;
+ } else {
+ * need_read = TRUE ;
+ /* !!! This code compensates for the inconsistencies of reverse
+ * motion in MoveFileMarks().
+ */
+ if ( channel->cur_drv->thw_inf.drv_info.drv_features & TDI_REV_FMK ) {
+ /* this will move nmarks+1 backward, 1 forward */
+ ret_val = MoveFileMarks( channel, (INT16)(nmarks+1), (INT16)BACKWARD ) ;
+ /* skip the header if we have to */
+ if ( ret_val == TFLE_NO_ERR && channel->cur_drv->cur_pos.fmks == 0 ) {
+ ret_val = MoveFileMarks( channel, (INT16)1, (INT16)FORWARD ) ;
+ }
+ } else {
+ if ( nmarks == 0 ) {
+ ret_val = MoveFileMarks( channel, (INT16)1, (INT16)BACKWARD );
+ if ( ret_val == TFLE_NO_ERR ) {
+ ret_val = MoveFileMarks( channel, (INT16)1, (INT16)FORWARD ) ;
+ }
+ } else {
+ ret_val = MoveFileMarks( channel, (INT16)nmarks, (INT16)BACKWARD );
+ }
+ }
+
+ if ( ret_val == TFLE_NO_ERR ) {
+ env->current_vcb.bset_num += number - at_eod;
+ }
+ }
+
+ return ret_val;
+}
+
+
+/**/
+/**
+
+ Name: SYPL_GetCurrent VCB
+
+ Description: Get the current VCB given the first chunk of a set.
+ Uses, but does not consume, data from tape.
+
+**/
+INT16 SYPL_GetCurrentVCB(
+ CHANNEL_PTR channel, /* I channel pointer */
+ BUF_PTR buffer ) /* I buffer */
+{
+ S10_DIRECTORY_HEADER_PTR dir_hdr ;
+ S10_BACKUP_SET_HEADER_PTR header = (VOID_PTR)( BM_NextBytePtr( buffer ) ) ;
+ S10_ENV_PTR env = channel->fmt_env ;
+ GEN_VCB_DATA gvcb_data ;
+ SYPL_VCB_PTR cur_vcb = &env->current_vcb ;
+ static UINT8 uniq_id[] = S10_UNIQ_ID ;
+
+ msassert( cur_vcb != NULL ) ;
+
+ FS_SetDefaultDBLK( channel->cur_fsys, BT_VCB, (CREATE_DBLK_PTR)&gvcb_data ) ;
+ gvcb_data.std_data.dblk = channel->cur_dblk ;
+
+ if ( !env->continuing ) {
+
+ /* Initialize the vcb variables */
+ cur_vcb->attrib = 0;
+ cur_vcb->drive[1] = ':';
+ cur_vcb->drive[2] = 0;
+
+ /* Insure that this block is the backup set header */
+ if( ( !header->compression ) && (header->common.type == backup_set_header_type) &&
+ ( !memicmp( header->common.uniq_tape_id, uniq_id, UNQ_HDR_ID_LEN) ) ) {
+
+ strncpyA( env->bset_name, header->bset_name, SHORT_NAME_LEN ) ;
+ env->bset_name[SHORT_NAME_LEN] = '\0';
+
+ strncpyA( env->bset_descrpt, header->bset_descrpt, DESCRPT_LEN ) ;
+ env->bset_descrpt[DESCRPT_LEN] = '\0';
+
+ SYPLDateToDateTime( &header->bset_date, &cur_vcb->backup_date_time ) ;
+
+ } else {
+ /* Unique id does not compare with expected format for Sytos Plus
+ or Cannot process tape; the data is compressed.
+ */
+ return TFLE_TAPE_INCONSISTENCY ;
+ }
+ /* Insure that the next block is the directory header */
+ BM_UpdCnts( buffer, env->block_size ) ;
+ dir_hdr = (S10_DIRECTORY_HEADER_PTR)( BM_NextBytePtr( buffer ) ) ;
+ if( (dir_hdr->common.type == directory_header_type) &&
+ ( !memicmp( dir_hdr->common.uniq_tape_id, uniq_id, UNQ_HDR_ID_LEN) ) ) {
+ if (dir_hdr->common.drive_indicator == DRIVEROOT_TYPE ) {
+ /* assign the drive */
+ cur_vcb->drive[0] = dir_hdr->path_name[0] ;
+ }
+ } else {
+ if( BM_ReadError( buffer ) == GEN_ERR_ENDSET ) {
+ /* This is an empty set */
+ BM_UseAll( buffer ) ;
+ cur_vcb->drive[0] = 'C' ; // Fake it.
+ } else {
+ /* Unexpected format for Sytos Plus */
+ return TFLE_TAPE_INCONSISTENCY ;
+ }
+ }
+
+ } else {
+ channel->cur_dblk->com.continue_obj = TRUE ;
+ }
+
+ *gvcb_data.date = cur_vcb->backup_date_time;
+
+ /* The cur vcb attribs do not exist for a tape header. */
+ /* They could be somewhere in the unknown 197 bytes of the tape's */
+ /* header, but until this is known, no attributes will be set */
+ gvcb_data.std_data.attrib = cur_vcb->attrib ;
+
+ /* Fix for Cougar EPR# 1720 */
+ if( env->password[0] != '\0' &&
+ (channel->ui_tpos == NULL ||
+ channel->ui_tpos->backup_set_num == -1 ||
+ (channel->ui_tpos->backup_set_num == (INT16)cur_vcb->bset_num &&
+ !env->continuing) ) ){
+
+ gvcb_data.tape_password = (CHAR_PTR)env->password ; /* backup set password */
+ gvcb_data.tape_password_size = strlenA( env->password ) + 1; /* size of the above password */
+ gvcb_data.password_encrypt_alg = 0 ; /* plaintext password */
+ }
+
+ gvcb_data.std_data.blkid = (UINT32)(-1L) ;
+ gvcb_data.std_data.did = (UINT32)(-1L) ;
+ gvcb_data.std_data.string_type = BEC_ANSI_STR ;
+ gvcb_data.std_data.tape_seq_num = env->tape_seq_num ;
+ channel->cur_dblk->com.tape_seq_num = env->tape_seq_num ;
+
+ gvcb_data.f_mark = channel->cur_drv->cur_pos.fmks ; /* tape format - number of file marks */
+ gvcb_data.tape_id = env->family_id ; /* tape format - unique tape ID */
+ gvcb_data.tape_seq_num = env->tape_seq_num ; /* which tape in a tape family */
+
+ gvcb_data.tape_name = (CHAR_PTR)env->volname ;
+ gvcb_data.tape_name_size = strlenA( env->volname ) + 1;
+
+ gvcb_data.bset_name = (CHAR_PTR)env->bset_name ;
+ gvcb_data.bset_name_size = strlenA( env->bset_name ) + 1;
+ gvcb_data.bset_descript = (CHAR_PTR)env->bset_descrpt ;
+ gvcb_data.bset_descript_size = strlenA( env->bset_descrpt ) + 1;
+ gvcb_data.bset_num = cur_vcb->bset_num ; /* backup set number in tape family */
+
+ gvcb_data.tf_major_ver = 1 ; /* tape format version - major */
+ gvcb_data.tf_minor_ver = 0 ; /* tape format version - minor */
+
+ gvcb_data.user_name = (CHAR_PTR)"";
+ gvcb_data.user_name_size = 0 ;
+
+ gvcb_data.volume_name = (CHAR_PTR)cur_vcb->drive ;
+ gvcb_data.volume_name_size = 3;
+
+ /* Tell the file system to do its thing */
+ FS_CreateGenVCB( channel->cur_fsys, &gvcb_data ) ;
+
+ /* reset the flag here, knowing it will be set by RdException
+ * or MoveToVCB logic later if necessary.
+ */
+ env->continuing = FALSE;
+
+ return TFLE_NO_ERR ;
+}
+
+/**/
+/**
+
+ Name: SYPL_Parse
+
+ Description: Given a buffer, return block type BT_xxx
+
+
+**/
+INT16 SYPL_Parse(
+ CHANNEL_PTR channel, /* I channel pointer */
+ BUF_PTR buffer, /* I buffer pointer */
+ UINT16_PTR blk_type ) /* O new block type */
+{
+ S10_DIRECTORY_HEADER_PTR header = BM_NextBytePtr( buffer ) ;
+ S10_ENV_PTR env = channel->fmt_env ;
+ INT16 ret_val = TFLE_NO_ERR ;
+
+ /* Initialize block type */
+ *blk_type = BT_HOSED ;
+
+ /* Eat all pads */
+ BM_UpdCnts( buffer, (UINT16)env->pad_size ) ;
+ env->pad_size = 0 ;
+
+ if ( env->using_ecc ) {
+ channel->retranslate_size = U32_To_U64( (UINT32)NextECC( channel, buffer ) );
+ }
+
+ if( BM_BytesFree( buffer ) == 0 ) {
+ env->bytes_left = FALSE ;
+ *blk_type = BT_MDB ;
+ return ret_val ;
+ }
+
+ /* Are we in a stream mode */
+ if( env->streamMode ) {
+ *blk_type = BT_STREAM ;
+ return ret_val ;
+ }
+
+ header = BM_NextBytePtr( buffer ) ;
+
+ /* see if we're in ECC; consume it if needed. */
+ if ( env->in_ecc || ( env->using_ecc && NextECC( channel, buffer ) <= 0 ) ) {
+ *blk_type = BT_MDB ;
+ return ret_val ;
+ }
+ if ( header->common.type == ecc_header_type ) {
+ env->in_ecc = TRUE ;
+ *blk_type = BT_MDB ;
+ return ret_val ;
+ }
+ if ( header->common.type == file_header_type ) {
+ *blk_type = BT_FDB ;
+ return ret_val ;
+
+ } else if ( header->common.type == directory_header_type ) {
+ *blk_type = BT_DDB ;
+ return ret_val ;
+
+ } else if ( header->common.type == backup_set_header_type ) {
+ S10_BACKUP_SET_HEADER_PTR bsh = (S10_BACKUP_SET_HEADER_PTR)header ;
+ if( bsh->end_of_backup ) {
+ if( !memicmp( bsh->eom_identifier, "SYTOS PLUS (EOM)", 16 ) ) {
+ channel->cur_dblk->com.continue_obj = TRUE ;
+ SetChannelStatus( channel, CH_AT_EOM ) ;
+ env->continuing = TRUE ;
+ env->destination_tape_seq_num = env->tape_seq_num + 1 ;
+ }
+ }
+ *blk_type = BT_MDB ;
+ return ret_val ;
+ }
+
+ if( env->tape_seq_num > 1 ) {
+ /* Forces the tape to be */
+ /* VCBed. Fixes EPR #357-698 */
+ *blk_type = BT_MDB ;
+ return ret_val ;
+ } else {
+ /* I believe that other conditions will */
+ /* preclude me from always returning this */
+ /* error. Currently, I do not know what */
+ /* those conditions are. tls */
+ return TFLE_USE_SYPL_ECC_FLAG ;
+
+ }
+}
+
+/**/
+/**
+
+ Name: SYPL_RdException
+
+ Description: Called when read returns a filemark indication
+
+**/
+UINT16 SYPL_RdException(
+ CHANNEL_PTR channel, /* I channel pointer */
+ INT16 exception ) /* I exception to operate on */
+{
+ S10_ENV_PTR env = channel->fmt_env ;
+
+ switch ( exception ) {
+ case GEN_ERR_ENDSET :
+ return FMT_EXC_EOS ;
+
+ case GEN_ERR_NO_DATA :
+#if TRUST_VIPER_EOM
+ /* this will probably only work on the Viper Drives */
+ if ( channel->cur_drv->thw_inf.drv_status & TPS_EOM ) {
+#endif /* TRUST_VIPER_EOM */
+ channel->cur_dblk->com.continue_obj = TRUE ;
+ SetChannelStatus( channel, CH_AT_EOM ) ;
+ env->prior_blocks_used += channel->blocks_used ;
+ env->continuing = TRUE;
+ env->destination_tape_seq_num = env->tape_seq_num + 1;
+ return FMT_EXC_EOM ;
+#if TRUST_VIPER_EOM
+ } else {
+ return FMT_EXC_HOSED ;
+ }
+#endif /* TRUST_VIPER_EOM */
+
+ default :
+ return FMT_EXC_HOSED ;
+ }
+}
+
+/**/
+/**
+
+ Name: SYPL_ReTranslate
+
+ Description: If called again devour ECC blocks
+
+**/
+BOOLEAN SYPL_ReTranslate(
+ CHANNEL_PTR channel, /* I channel pointer */
+ BUF_PTR buffer ) /* I buffer pointer */
+{
+ S10_ENV_PTR env = channel->fmt_env ;
+ UINT16 block_size = env->block_size ;
+
+ if ( env->next_retrans_size ) {
+ BM_UpdCnts( buffer, (UINT16)env->next_retrans_size ) ;
+ env->next_retrans_size = 0 ;
+ channel->retranslate_size = U32_To_U64( (UINT32)NextECC( channel, buffer ) );
+
+ } else if ( BM_BytesFree( buffer ) < 1024 ) {
+ env->next_retrans_size = 1024 - BM_BytesFree( buffer ) ;
+ channel->retranslate_size = U32_To_U64( 0 ) ;
+ BM_UpdCnts( buffer, BM_BytesFree( buffer ) ) ;
+ } else {
+ env->next_retrans_size = 0 ;
+ BM_UpdCnts( buffer, 1024 ) ;
+ channel->retranslate_size = U32_To_U64( (UINT32)NextECC( channel, buffer ) );
+ }
+
+
+ return SUCCESS ;
+
+}
+/**/
+/**
+
+ Name: SYPL_ReadMakeDDB
+ Description: Translates a DDB from data in the buffer.
+**/
+INT16 SYPL_ReadMakeDDB(
+ CHANNEL_PTR channel, /* I channel */
+ BUF_PTR buffer ) /* I buffer */
+{
+ S10_DIRECTORY_HEADER_PTR header = (VOID_PTR)( BM_NextBytePtr( buffer ) ) ;
+ S10_ENV_PTR env = (S10_ENV_PTR)channel->fmt_env ;
+ DBLK_PTR cur_dblk = channel->cur_dblk ;
+ STREAM_INFO_PTR currentStream ;
+ GEN_DDB_DATA gddb_data ;
+ UINT8 tmp_buf[256] ;
+ INT16 tmp_filter ;
+ DATE_TIME create_date ;
+ DATE_TIME backup_date ;
+
+ /* Initialize the file system's interface structure */
+ FS_SetDefaultDBLK( channel->cur_fsys, BT_DDB, (CREATE_DBLK_PTR)&gddb_data ) ;
+
+ SYPLSetStandFields( channel, &gddb_data.std_data ) ;
+
+ env->in_ecc = FALSE ;
+
+ gddb_data.std_data.os_id = FS_PC_DOS ;
+
+ ConvertName( (VOID_PTR)header ) ;
+ memcpy( tmp_buf, header->path_name, header->path_len ) ;
+ gddb_data.path_name = (CHAR_PTR)tmp_buf ;
+ gddb_data.path_size = header->path_len ;
+
+ if (header->common.drive_indicator == DRIVEROOT_TYPE ) {
+ SYPLDateToDateTime( &header->dir_date, &backup_date ) ;
+ gddb_data.backup_date = &backup_date ;
+
+ /* Sytos Plus does not provide the access date (or we can't */
+ /* determine the access date) for the root directory and */
+ /* GEN_MkDDB requires an access date; therefore the backup */
+ /* date will be assigned and then invalidated. */
+ gddb_data.access_date = &backup_date ;
+ gddb_data.access_date->date_valid = 0 ;
+ env->dir_date = backup_date ;
+
+ } else {
+ SYPLDateToDateTime( &header->dir_date, &create_date ) ;
+ gddb_data.access_date = &create_date ;
+ gddb_data.creat_date = &create_date ;
+ gddb_data.mod_date = &create_date ;
+ gddb_data.backup_date = &backup_date ;
+ }
+
+ env->processed_ddb = TRUE ;
+
+ /* Sytos Plus attrib appears to be shifted left by one bit */
+ gddb_data.std_data.attrib |= ( header->dir_attribs & 0X01 ) ? OBJ_READONLY_BIT : 0 ;
+ gddb_data.std_data.attrib |= ( header->dir_attribs & 0X02 ) ? OBJ_HIDDEN_BIT : 0 ;
+ gddb_data.std_data.attrib |= ( header->dir_attribs & 0X04 ) ? OBJ_SYSTEM_BIT : 0 ;
+ gddb_data.std_data.attrib |= ( header->dir_attribs & 0X20 ) ? OBJ_MODIFIED_BIT : 0 ;
+
+ gddb_data.std_data.tape_seq_num = env->tape_seq_num ;
+ cur_dblk->com.string_type = BEC_ANSI_STR ;
+ cur_dblk->com.tape_seq_num = env->tape_seq_num ;
+ gddb_data.std_data.dblk = cur_dblk ;
+
+ gddb_data.std_data.blkid = (UINT32)(-1) ;
+ gddb_data.std_data.did = (UINT32)(-1) ;
+
+ /* Assign memory */
+ currentStream = &env->streams[env->no_streams] ;
+
+ if( header->acl_info_len ) {
+ currentStream->id = STRM_OS2_ACL ;
+ currentStream->size = U64_Init( (header->acl_info_len), 0L ) ;
+ currentStream++ ;
+ env->no_streams++ ;
+ currentStream->id = 0 ;
+ currentStream->size = U64_Init( 0L, 0L ) ;
+ }
+
+ if( header->ea_data_len ) {
+ currentStream->id = STRM_OS2_EA ;
+ currentStream->size = U64_Init( (header->ea_data_len), 0L ) ;
+ currentStream++ ;
+ env->no_streams++ ;
+ currentStream->id = 0 ;
+ currentStream->size = U64_Init( 0L, 0L ) ;
+ }
+
+ if( env->no_streams ) {
+ env->streamMode = TRUE ;
+ }
+
+ env->pad_size = 0 ;
+ tmp_filter = FS_CreateGenDDB( channel->cur_fsys, &gddb_data ) ;
+ ProcessDataFilter( channel, tmp_filter ) ;
+
+ BM_UpdCnts( buffer, env->block_size ) ;
+
+ if ( env->using_ecc ) {
+ INT16 next_ecc ;
+ next_ecc = NextECC( channel, buffer ) ;
+ channel->retranslate_size = U32_To_U64( (UINT32)next_ecc );
+ } else {
+ channel->retranslate_size = lw_UINT64_MAX ;
+ }
+
+ return TFLE_NO_ERR ;
+}
+/**/
+/**
+
+ Name: SYPL_ReadMakeFDB
+
+ Description: Translates an FDB
+
+**/
+INT16 SYPL_ReadMakeFDB( CHANNEL_PTR channel, BUF_PTR buffer )
+{
+ S10_FILE_HEADER_PTR header = (VOID_PTR)( BM_NextBytePtr( buffer ) ) ;
+ S10_ENV_PTR env = (S10_ENV_PTR)channel->fmt_env ;
+ STREAM_INFO_PTR currentStream ;
+ GEN_FDB_DATA gfdb_data ;
+ UINT8 tmp_buf[256] ;
+ INT16 tmp_filter ;
+ DATE_TIME create_date ;
+ DATE_TIME mod_date ;
+ DATE_TIME access_date ;
+ INT16 next_ecc ;
+ UINT16 pad_size = 0 ;
+
+
+ /* Initialize the file systems interface structure */
+ FS_SetDefaultDBLK( channel->cur_fsys, BT_FDB, (CREATE_DBLK_PTR)&gfdb_data ) ;
+
+ SYPLSetStandFields( channel, &gfdb_data.std_data ) ;
+
+ channel->cur_dblk->com.tape_seq_num = env->tape_seq_num ;
+ gfdb_data.std_data.tape_seq_num = env->tape_seq_num ;
+ gfdb_data.std_data.dblk = channel->cur_dblk ;
+ gfdb_data.std_data.os_id = FS_PC_DOS ;
+
+ /* obtain information for the file system create */
+ gfdb_data.std_data.os_info = NULL ;
+
+ gfdb_data.std_data.attrib |= ( header->file_attribs & 0X01 ) ? OBJ_READONLY_BIT : 0 ;
+ gfdb_data.std_data.attrib |= ( header->file_attribs & 0X02 ) ? OBJ_HIDDEN_BIT : 0 ;
+ gfdb_data.std_data.attrib |= ( header->file_attribs & 0X04 ) ? OBJ_SYSTEM_BIT : 0 ;
+ gfdb_data.std_data.attrib |= ( header->file_attribs & 0X20 ) ? OBJ_MODIFIED_BIT : 0 ;
+
+ ConvertName( (VOID_PTR)header ) ;
+ memcpy( tmp_buf, header->filename, header->filename_len ) ;
+ *( tmp_buf + header->filename_len ) = '\0';
+ gfdb_data.fname = (CHAR_PTR)tmp_buf ;
+ gfdb_data.fname_size = header->filename_len + 1;
+
+ SYPLDateToDateTime( &header->last_access_date, &access_date ) ;
+ gfdb_data.backup_date = &access_date ;
+ gfdb_data.access_date = &access_date ;
+ SYPLDateToDateTime( &header->file_create_date, &create_date ) ;
+ gfdb_data.creat_date = &create_date ;
+ SYPLDateToDateTime( &header->last_modified_date, &mod_date ) ;
+ gfdb_data.mod_date = &mod_date ;
+
+ /* Assign memory */
+ currentStream = &env->streams[env->no_streams] ;
+ currentStream->id = 0 ;
+ currentStream->size = U64_Init( 0L, 0L ) ;
+
+ if( header->acl_info_len ) {
+ currentStream->id = STRM_OS2_ACL ;
+ currentStream->size = U64_Init( (header->acl_info_len), 0L ) ;
+ currentStream++ ;
+ env->no_streams++ ;
+ currentStream->id = 0 ;
+ currentStream->size = U64_Init( 0L, 0L ) ;
+ }
+
+ if( header->ea_data_len ) {
+ currentStream->id = STRM_OS2_EA ;
+ currentStream->size = U64_Init( (header->ea_data_len), 0L ) ;
+ currentStream++ ;
+ env->no_streams++ ;
+ currentStream->id = 0 ;
+ currentStream->size = U64_Init( 0L, 0L ) ;
+
+ }
+
+ if( header->file_size ) {
+ currentStream->id = STRM_GENERIC_DATA ;
+ currentStream->size = U64_Init( (header->file_size), 0L ) ;
+ env->file_size = header->file_size ;
+ currentStream++ ;
+ env->no_streams++ ;
+ currentStream->id = 0 ;
+ currentStream->size = U64_Init( 0L, 0L ) ;
+ gfdb_data.std_data.disp_size = U64_Init( (header->file_size), 0L ) ;
+ }
+
+ /* Tell the file system to do its thing */
+ tmp_filter = FS_CreateGenFDB( channel->cur_fsys, &gfdb_data ) ;
+
+ if( env->no_streams ) {
+ env->streamMode = TRUE ;
+ }
+
+ env->pad_size = 0 ;
+ ProcessDataFilter( channel, tmp_filter ) ;
+ BM_UpdCnts( buffer, env->block_size ) ;
+
+ if ( env->using_ecc ) {
+ next_ecc = NextECC( channel, buffer ) ;
+ channel->retranslate_size = U32_To_U64( (UINT32)next_ecc );
+ } else {
+ channel->retranslate_size = lw_UINT64_MAX ;
+ }
+
+ return TFLE_NO_ERR ;
+}
+
+/**/
+/**
+
+ Name: SYPL_ReadMakeMDB
+
+ Description: Helps in devouring unneeded blocks
+**/
+INT16 SYPL_ReadMakeMDB(
+ CHANNEL_PTR channel, /* I channel pointer */
+ BUF_PTR buffer ) /* I buffer pointer */
+{
+ S10_COMMON_HEADER_PTR header = (VOID_PTR)( BM_NextBytePtr( buffer ) ) ;
+ S10_ENV_PTR env = channel->fmt_env ;
+
+ if( env->bytes_left ) {
+ BM_UpdCnts( buffer, env->block_size ) ; /* use the current block */
+
+ if ( env->using_ecc ) {
+ INT16 next_ecc ;
+ next_ecc = NextECC( channel, buffer ) ;
+ channel->retranslate_size = U32_To_U64( (UINT32)next_ecc );
+ } else {
+ channel->retranslate_size = lw_UINT64_MAX ;
+ }
+
+ } else {
+ env->bytes_left = TRUE ;
+ }
+ return TFLE_NO_ERR ;
+}
+/**/
+/**
+
+ Name: SYPL_ReadMakeStreams
+
+ Description: Creates Stream Headers for stream processing
+**/
+INT16 SYPL_ReadMakeStreams(
+ CHANNEL_PTR Channel, /* I channel pointer */
+ BUF_PTR Buffer ) /* I buffer pointer */
+{
+ S10_ENV_PTR currentEnv = ( S10_ENV_PTR ) Channel->fmt_env ;
+
+ /* get next stream */
+ Channel->current_stream = currentEnv->streams[currentEnv->currentStream++] ;
+
+ /* Set the stream's pad Size */
+ currentEnv->pad_size = DeterminePadSize( U64_Lsw(Channel->current_stream.size), currentEnv->block_size ) ;
+
+ if( --currentEnv->no_streams == 0 ) {
+ /* completed stream processing */
+ currentEnv->streamMode = FALSE ;
+
+ }
+
+ ClrChannelStatus( Channel, CH_SKIP_CURRENT_STREAM ) ;
+
+ return TFLE_NO_ERR ;
+}
+
+/**/
+/**
+
+ Name: SYPL_DeInitialize
+
+ Description: Frees memory allocated by Initialize
+**/
+VOID SYPL_DeInitialize( VOID_PTR *fmt_env )
+{
+ S10_ENV_PTR env = *fmt_env ;
+
+ free( env ) ;
+ *fmt_env = NULL ;
+}
+
+
+/**/
+/**
+
+ Name: SetStandFields
+
+ Description: Sets up the standard fields in translation to dblks.
+
+ Modified: 9/20/1989 14:8:27
+
+ Returns: Nothing.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+static VOID _near SYPLSetStandFields(
+ CHANNEL_PTR channel,
+ STD_DBLK_DATA_PTR std_data )
+{
+ S10_ENV_PTR currentEnv = ( S10_ENV_PTR ) channel->fmt_env ;
+
+ /* Reset the stream stuff */
+ currentEnv->no_streams = 0 ;
+ currentEnv->currentStream = 0 ;
+ currentEnv->file_size = 0 ;
+
+ /* Set ASCII code in string type */
+ std_data->string_type = BEC_ANSI_STR ;
+
+ /* We don't have to retranslate */
+ channel->retranslate_size = lw_UINT64_MAX ;
+
+}
+
diff --git a/private/utils/ntbackup/src/tape2.bmp b/private/utils/ntbackup/src/tape2.bmp
new file mode 100644
index 000000000..1e422c6f1
--- /dev/null
+++ b/private/utils/ntbackup/src/tape2.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/tapein2.bmp b/private/utils/ntbackup/src/tapein2.bmp
new file mode 100644
index 000000000..0803f5175
--- /dev/null
+++ b/private/utils/ntbackup/src/tapein2.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/tapes2.bmp b/private/utils/ntbackup/src/tapes2.bmp
new file mode 100644
index 000000000..28e6259aa
--- /dev/null
+++ b/private/utils/ntbackup/src/tapes2.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/tapes3.ico b/private/utils/ntbackup/src/tapes3.ico
new file mode 100644
index 000000000..963db1da7
--- /dev/null
+++ b/private/utils/ntbackup/src/tapes3.ico
Binary files differ
diff --git a/private/utils/ntbackup/src/tapesin2.bmp b/private/utils/ntbackup/src/tapesin2.bmp
new file mode 100644
index 000000000..24484439c
--- /dev/null
+++ b/private/utils/ntbackup/src/tapesin2.bmp
Binary files differ
diff --git a/private/utils/ntbackup/src/tattach.c b/private/utils/ntbackup/src/tattach.c
new file mode 100644
index 000000000..383277606
--- /dev/null
+++ b/private/utils/ntbackup/src/tattach.c
@@ -0,0 +1,419 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tattach.c
+
+ Description: This file contains code to attach and detattach to
+ a given NTFS disk device.
+
+
+ $Log: N:\logfiles\tattach.c_v $
+
+ Rev 1.13.1.3 15 Mar 1994 22:48:38 STEVEN
+fix registry bugs
+
+ Rev 1.13.1.2 11 Mar 1994 15:12:00 BARRY
+On detatch, free the cur_dir work buff in reserved area
+
+ Rev 1.13.1.1 28 Jan 1994 21:01:24 STEVEN
+MoveFileEx() doe snot support mac_sytax
+
+ Rev 1.13.1.0 19 Jan 1994 12:48:02 BARRY
+Clear warning
+
+ Rev 1.13 26 Jul 1993 17:04:00 STEVEN
+fixe restore active file with registry
+
+ Rev 1.12 09 Jun 1993 10:30:50 BARRY
+Allocate a default security descriptor that will be used in CreateObj.
+
+ Rev 1.11 17 Nov 1992 22:18:22 DAVEV
+unicode fixes
+
+ Rev 1.10 11 Nov 1992 09:52:38 GREGG
+Unicodeized literals.
+
+ Rev 1.9 10 Nov 1992 08:19:56 STEVEN
+removed path and name from dblk now use full_name_ptr
+
+ Rev 1.8 21 Oct 1992 19:41:14 BARRY
+Added create/destroy of linked-file queue.
+
+ Rev 1.7 06 Oct 1992 13:25:14 DAVEV
+Unicode strlen verification
+
+ Rev 1.6 24 Sep 1992 13:42:00 BARRY
+Changes for huge file name support.
+
+ Rev 1.5 12 Aug 1992 17:47:36 STEVEN
+fixed bugs at microsoft
+
+ Rev 1.4 25 Jun 1992 11:25:56 STEVEN
+assert is backwards
+
+ Rev 1.3 21 May 1992 13:49:20 STEVEN
+more long path support
+
+ Rev 1.2 04 May 1992 09:31:26 LORIB
+Changes for variable length paths.
+
+ Rev 1.1 05 Feb 1992 15:47:38 STEVEN
+added support for FindHandle Queue
+
+ Rev 1.0 17 Jan 1992 17:50:06 STEVEN
+Initial revision.
+
+**/
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "ntfsdblk.h"
+#include "ntfs_fs.h"
+#include "msassert.h"
+
+static VOID InitDefaultSecurityDescriptor( BE_CFG_PTR cfg, GENERIC_DLE_PTR dle );
+static VOID FreeDefaultSecurityDescriptor( GENERIC_DLE_PTR dle );
+static VOID NTFS_FixUpSysReg( FSYS_HAND fsh ) ;
+
+
+/**/
+/**
+
+ Name: NTFS_AttachToDLE()
+
+ Description: This function simply expands the OS specific
+ information in the DLE.
+
+
+ Modified: 1/10/1992 10:45:57
+
+ Returns: Error Codes:
+ INSUFFICIENT_MEMORY
+ SUCCESS
+
+ Notes:
+
+ Declaration:
+
+**/
+INT16 NTFS_AttachToDLE( fsh, dle, u_name, pswd )
+FSYS_HAND fsh ; /* I - File system handle */
+GENERIC_DLE_PTR dle; /*I/O- drive to attach to. list element expanded */
+CHAR_PTR u_name; /* I - user name NOT USED */
+CHAR_PTR pswd ; /* I - passowrd NOT USED */
+{
+ CHAR vol_name[100] = {TEXT('\0')} ;
+ CHAR fs_name[64] = {TEXT('\0')} ;
+ CHAR dev_name[4] ;
+ UINT32 fsize ;
+ UINT32 sflags ;
+
+ u_name ;
+ pswd ;
+ dle ;
+
+ msassert( dle != NULL );
+
+ InitDefaultSecurityDescriptor( fsh->cfg, dle );
+
+ /* get the volume name */
+ if ( dle->info.ntfs->volume_label == NULL ) {
+ dev_name[0] = dle->device_name[0] ;
+ dev_name[1] = TEXT(':') ;
+ dev_name[2] = TEXT('\\') ;
+ dev_name[3] = TEXT('\0') ;
+
+ GetVolumeInformation( dev_name, vol_name, 100, NULL,
+ &fsize, &sflags, fs_name, 64 ) ;
+
+ if ( *vol_name != TEXT('\0') ) {
+ dle->info.ntfs->volume_label = calloc( 1, strsize(vol_name) ) ;
+ }
+
+ if ( dle->info.ntfs->volume_label != NULL ) {
+ strcpy (dle->info.ntfs->volume_label, vol_name ) ;
+ }
+ }
+
+ /* Reserved field used for GetNext mode flag */
+ fsh->reserved.ptr = calloc( 1, sizeof( NTFS_FSYS_RESERVED ) ) ;
+
+ if ( fsh->reserved.ptr != NULL ) {
+
+ NTFS_FSYS_RESERVED_PTR resPtr = fsh->reserved.ptr;
+
+ InitQueue( &resPtr->scan_q );
+ InitQueue( &resPtr->linkq );
+
+ if ( FS_SavePath( fsh, (BYTE_PTR)TEXT("\\"), 2 * sizeof( CHAR ) ) == SUCCESS ) {
+
+ fsh->file_hand = calloc( 1, sizeof( FILE_HAND_STRUCT ) + sizeof( NTFS_OBJ_HAND ) ) ;
+ if ( fsh->file_hand != NULL ) {
+ fsh->file_hand->obj_hand.ptr = (VOID_PTR)(fsh->file_hand + 1) ;
+
+ return SUCCESS ;
+ }
+ }
+ }
+
+ return OUT_OF_MEMORY ;
+
+}
+
+/**/
+/**
+
+ Name: NTFS_DetachDLE()
+
+ Description: This function detaches form the specified DLE.
+ Part of the detachment is to release any PUSHED
+ DDBs. Also we need to free any allocated path
+ buffers and open file scans.
+
+ Modified: 1/10/1992 11:16:11
+
+ Returns: SUCCESS
+
+**/
+INT16 NTFS_DetachDLE( fsh )
+FSYS_HAND fsh ;
+{
+ DBLK_PTR dummy_dblk ;
+
+ /* Free the security info we use on file creates. */
+ FreeDefaultSecurityDescriptor( fsh->attached_dle );
+
+ /* Release any pushed min DDBs */
+
+ dummy_dblk = (DBLK_PTR)calloc( 1, sizeof(DBLK) ) ;
+
+ if ( dummy_dblk != NULL ) {
+
+ while( NTFS_PopMinDDB( fsh, dummy_dblk ) == SUCCESS )
+ ;
+
+ free( dummy_dblk ) ;
+ }
+
+ /* deal with active files and the SYSTEM registry file */
+ if ( fsh->attached_dle->info.ntfs->LastSysRegPath ) {
+ NTFS_FixUpSysReg( fsh ) ;
+ }
+
+ /* Release any allocated path buffers */
+
+ FS_FreeOSPathOrNameQueueInHand( fsh ) ;
+
+ /* Release any allocated link buffers */
+
+ if ( fsh->reserved.ptr != NULL ) {
+
+ NTFS_FSYS_RESERVED_PTR resPtr = fsh->reserved.ptr;
+ NTFS_LINK_Q_ELEM_PTR link_q_elem ;
+
+ while ( (link_q_elem = (NTFS_LINK_Q_ELEM_PTR)DeQueueElem( &resPtr->linkq )) != NULL )
+ {
+ free( link_q_elem ) ;
+ }
+ free( resPtr->work_buf );
+ }
+
+
+ /* Release any saved file scan handles */
+ NTFS_EmptyFindHandQ( fsh ) ;
+
+ /* free the allocated file handle */
+ free( fsh->file_hand );
+
+ free( fsh->reserved.ptr );
+
+ return SUCCESS ;
+}
+
+INT32 NTFS_EndOperationOnDLE( FSYS_HAND fsh )
+{
+ return SUCCESS ;
+}
+
+/**/
+/**
+
+ Name: InitDefaultSecurityDescriptor()
+
+ Description: Allocates and initializes the default security
+ descriptor used at file create.
+
+ Modified: 09-Jun-93
+
+ Returns: Nothing
+
+ Notes:
+
+**/
+static VOID InitDefaultSecurityDescriptor( BE_CFG_PTR cfg,
+ GENERIC_DLE_PTR dle )
+{
+ LOCAL_NTFS_DRV_DLE_INFO_PTR ntdle;
+ BOOLEAN status = FALSE;
+
+ msassert( dle != NULL );
+ msassert( cfg != NULL );
+
+ ntdle = dle->info.ntfs;
+
+ /* Make sure any existing Security stuff gets freed. */
+ FreeDefaultSecurityDescriptor( dle );
+
+ /*
+ * If we're going to be restoring information to an NTFS drive,
+ * set up default security in the DLE so it may be used by
+ * the create calls.
+ */
+
+ if ( (BEC_GetRestoreSecurity( cfg ) == TRUE) &&
+ (strcmp( ntdle->fs_name, TEXT("NTFS"))) == 0)
+ {
+ ntdle->sd = malloc( sizeof( SECURITY_DESCRIPTOR ) );
+ ntdle->sdacl = malloc( sizeof ( ACL ) );
+
+ if ( (ntdle->sd != NULL) && (ntdle->sdacl != NULL) )
+ {
+ status = InitializeSecurityDescriptor( ntdle->sd,
+ SECURITY_DESCRIPTOR_REVISION );
+ if ( status )
+ {
+ status = InitializeAcl( ntdle->sdacl,
+ sizeof( ACL ),
+ ACL_REVISION );
+ }
+
+ if ( status )
+ {
+ status = SetSecurityDescriptorDacl( ntdle->sd,
+ TRUE,
+ ntdle->sdacl,
+ FALSE );
+ }
+ }
+
+ if ( status == FALSE )
+ {
+ FreeDefaultSecurityDescriptor( dle );
+ }
+ }
+}
+
+
+/**/
+/**
+
+ Name: FreeDefaultSecurityDescriptor()
+
+ Description: Frees all the stuff that was allocated at attach time
+ for the default security descriptor.
+
+ Modified: 09-Jun-93
+
+ Returns: Nothing
+
+ Notes:
+
+**/
+static VOID FreeDefaultSecurityDescriptor( GENERIC_DLE_PTR dle )
+{
+ if ( dle != NULL )
+ {
+ if ( dle->info.ntfs->sd != NULL )
+ {
+ free( dle->info.ntfs->sd );
+ dle->info.ntfs->sd = NULL;
+ }
+
+ if ( dle->info.ntfs->sdacl != NULL )
+ {
+ free( dle->info.ntfs->sd );
+ dle->info.ntfs->sd = NULL;
+ }
+ }
+}
+
+static VOID NTFS_FixUpSysReg( FSYS_HAND fsh )
+{
+ CHAR_PTR old_reg_name ;
+ LOCAL_NTFS_DRV_DLE_INFO_PTR ntfs_inf = fsh->attached_dle->info.ntfs ;
+ CHAR_PTR logname ;
+
+ old_reg_name = NTFS_MakeTempName( ntfs_inf->LastSysRegPath, TEXT("REG") ) ;
+
+ if ( old_reg_name != NULL ) {
+
+ if ( fsh->attached_dle->info.ntfs->mac_name_syntax ) {
+
+ MoveFileEx( old_reg_name+4, /* Existing file */
+ NULL, /* New (original) */
+ MOVEFILE_REPLACE_EXISTING |
+ MOVEFILE_DELAY_UNTIL_REBOOT );
+ } else {
+ MoveFileEx( old_reg_name, /* Existing file */
+ NULL, /* New (original) */
+ MOVEFILE_REPLACE_EXISTING |
+ MOVEFILE_DELAY_UNTIL_REBOOT );
+ }
+
+ logname = malloc( strsize(ntfs_inf->LastSysRegPathNew) + strsize(TEXT(".LOG"))) ;
+
+ if ( logname != NULL ) {
+
+ strcpy( logname, ntfs_inf->LastSysRegPathNew ) ;
+
+ if ( fsh->attached_dle->info.ntfs->mac_name_syntax ) {
+ MoveFileEx( logname+4,
+ NULL, /* New (original) */
+ MOVEFILE_REPLACE_EXISTING |
+ MOVEFILE_DELAY_UNTIL_REBOOT );
+ } else {
+ MoveFileEx( logname,
+ NULL, /* New (original) */
+ MOVEFILE_REPLACE_EXISTING |
+ MOVEFILE_DELAY_UNTIL_REBOOT );
+ }
+
+ strcat( logname, TEXT(".LOG") ) ;
+
+ if ( fsh->attached_dle->info.ntfs->mac_name_syntax ) {
+ MoveFileEx( logname+4,
+ NULL, /* New (original) */
+ MOVEFILE_REPLACE_EXISTING |
+ MOVEFILE_DELAY_UNTIL_REBOOT );
+ } else {
+ MoveFileEx( logname,
+ NULL, /* New (original) */
+ MOVEFILE_REPLACE_EXISTING |
+ MOVEFILE_DELAY_UNTIL_REBOOT );
+ }
+
+ free( logname ) ;
+ }
+ }
+
+ REG_MoveActiveRenameKey( fsh->attached_dle, ntfs_inf->LastSysRegPathNew ) ;
+
+ if ( old_reg_name != NULL ) {
+
+ REG_RestoreRegistryFile( fsh->attached_dle,
+ ntfs_inf->LastSysRegPath,
+ ntfs_inf->LastSysRegPathNew,
+ old_reg_name ) ;
+
+ free( old_reg_name ) ;
+ }
+}
+
+
diff --git a/private/utils/ntbackup/src/tbdpars.c b/private/utils/ntbackup/src/tbdpars.c
new file mode 100644
index 000000000..2b0cca270
--- /dev/null
+++ b/private/utils/ntbackup/src/tbdpars.c
@@ -0,0 +1,673 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: tbdpars.c
+
+ Description: This file contains code to parse a date string.
+ If time strings are to be added, then they must be added
+ here.
+
+ $Log: G:/UI/LOGFILES/TBDPARS.C_V $
+
+ Rev 1.8 13 Aug 1993 15:00:48 TIMN
+Changed ALPHA define to ALETTER due to DECs ALPHA machine conflicts
+
+ Rev 1.7 23 Jul 1993 15:35:40 MARINA
+enable c++
+
+ Rev 1.6 01 Nov 1992 16:08:26 DAVEV
+Unicode changes
+
+ Rev 1.5 07 Oct 1992 14:15:58 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.4 04 Oct 1992 19:40:52 DAVEV
+Unicode Awk pass
+
+ Rev 1.3 28 Jul 1992 14:41:38 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.2 18 May 1992 09:06:38 MIKEP
+header
+
+ Rev 1.1 10 Jan 1992 16:45:12 DAVEV
+16/32 bit port-2nd pass
+
+ Rev 1.0 20 Nov 1991 19:33:52 SYSTEM
+Initial revision.
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+static struct SW_TAB_TYPE montab[] =
+{
+ /* $$$ needs to be resources ??? */
+ { TEXT("APRIL"), 4 },
+ { TEXT("AUGUST"), 8 },
+ { TEXT("DECEMBER"), 12 },
+ { TEXT("FEBRUARY"), 2 },
+ { TEXT("JANUARY"), 1 },
+ { TEXT("JULY"), 7 },
+ { TEXT("JUNE"), 6 },
+ { TEXT("MARCH"), 3 },
+ { TEXT("MAY"), 5 },
+ { TEXT("NOVEMBER"), 11 },
+ { TEXT("OCTOBER"), 10 },
+ { TEXT("SEPTEMBER"), 9 }
+};
+
+static INT daymon[] =
+{
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+/**
+ Inputs for tbdttab FSM
+**/
+
+#define D_DASH 0
+#define D_DIGIT 1
+#define D_EOS 2
+#define D_LETTER 3
+#define D_SLASH 4
+
+#ifdef MBS
+#define D_UNDERSCORE 5
+#endif
+
+/**/
+/**
+ Actions for tbdttab FSM
+**/
+
+#define D_BAD_FORM 0
+#define D_DEF_DY1 1
+#define D_DONE_ALPHA_MON 2 // ALPHA has been changed to ALETTER
+#define D_DONE_DY1 3
+#define D_DONE_DY2 4
+#define D_DONE_DY3 5
+#define D_DONE_MO1 6
+#define D_DONE_MO2 7
+#define D_DONE_MO3 8
+#define D_DONE_NO_DAY 9
+#define D_DONE_YEAR1 10
+#define D_DONE_YEAR2 11
+#define D_RETURN_OK 12
+#define D_STORE_ALPHA 13 // ALPHA has been changed to ALETTER
+#define D_STORE_T1 14
+#define D_STORE_T2 15
+#define D_STORE_T3 16
+
+#ifdef MBS
+#define D_STORE_HR 17
+#define D_STORE_MIN 18
+#define D_STORE_SEC 19
+#define D_DONE_HR 20
+#define D_DONE_MIN 21
+#define D_DONE_SEC 22
+#endif
+
+/**
+ States for tbdttab FSM
+**/
+
+#define D_DONE 0
+#define D_INIT 1
+#define D_MON_OR_DY 2
+#define D_MON_OR_YR1 3
+#define D_MON_OR_YR2 4
+#define D_MONTH 5
+#define D_YEAR1 6
+#define D_YEAR2 7
+
+#ifdef MBS
+#define D_HR 8
+#define D_MIN 9
+#define D_SEC 10
+#endif
+
+#ifdef MBS
+#define TBDTTAB_N_INPUTS 6
+#define TBDTTAB_N_STATES 11
+#else
+#define TBDTTAB_N_INPUTS 5
+#define TBDTTAB_N_STATES 8
+#endif
+
+struct STATE_TAB_TYPE tbdttab_state_table[ TBDTTAB_N_INPUTS ] [ TBDTTAB_N_STATES ] = {
+ {
+ { D_BAD_FORM, D_DONE /* Input: d_dash, State: d_done */ },
+ { D_BAD_FORM, D_INIT /* Input: d_dash, State: d_init */ },
+ { D_DONE_DY2, D_MON_OR_YR2 /* Input: d_dash, State: d_mon_or_dy */ },
+ { D_DONE_MO3, D_YEAR1 /* Input: d_dash, State: d_mon_or_yr1 */ },
+ { D_BAD_FORM, D_MON_OR_YR2 /* Input: d_dash, State: d_mon_or_yr2 */ },
+ { D_DONE_MO2, D_YEAR2 /* Input: d_dash, State: d_month */ },
+ { D_BAD_FORM, D_YEAR1 /* Input: d_dash, State: d_year1 */ },
+ { D_BAD_FORM, D_YEAR2 /* Input: d_dash, State: d_year2 */ },
+#ifdef MBS
+ { D_BAD_FORM, D_HR /* INPUT: D_DASH, STATE: D_HR */ },
+ { D_BAD_FORM, D_MIN /* INPUT: D_DASH, STATE: D_MIN */ },
+ { D_BAD_FORM, D_SEC /* INPUT: D_DASH, STATE: D_SEC */ }
+#endif
+ },
+ {
+ { D_BAD_FORM, D_DONE /* Input: d_digit, State: d_done */ },
+ { D_STORE_T1, D_MON_OR_DY /* Input: d_digit, State: d_init */ },
+ { D_STORE_T1, D_MON_OR_DY /* Input: d_digit, State: d_mon_or_dy */ },
+ { D_STORE_T2, D_MON_OR_YR1 /* Input: d_digit, State: d_mon_or_yr1 */ },
+ { D_DONE_DY3, D_MON_OR_YR1 /* Input: d_digit, State: d_mon_or_yr2 */ },
+ { D_DONE_MO1, D_YEAR2 /* Input: d_digit, State: d_month */ },
+ { D_STORE_T3, D_YEAR1 /* Input: d_digit, State: d_year1 */ },
+ { D_STORE_T3, D_YEAR2 /* Input: d_digit, State: d_year2 */ },
+#ifdef MBS
+ { D_STORE_HR, D_HR /* INPUT: D_DIGIT, STATE: D_HR */ },
+ { D_STORE_MIN, D_MIN /* INPUT: D_DIGIT, STATE: D_MIN */ },
+ { D_STORE_SEC, D_SEC /* INPUT: D_DIGIT, STATE: D_SEC */ },
+#endif
+ },
+ {
+ { D_RETURN_OK, D_DONE /* Input: d_eos, State: d_done */ },
+ { D_BAD_FORM, D_INIT /* Input: d_eos, State: d_init */ },
+ { D_BAD_FORM, D_MON_OR_DY /* Input: d_eos, State: d_mon_or_dy */ },
+ { D_DONE_NO_DAY, D_DONE /* Input: d_eos, State: d_mon_or_yr1 */ },
+ { D_BAD_FORM, D_MON_OR_YR2 /* Input: d_eos, State: d_mon_or_yr2 */ },
+ { D_BAD_FORM, D_MONTH /* Input: d_eos, State: d_month */ },
+ { D_DONE_YEAR1, D_DONE /* Input: d_eos, State: d_year1 */ },
+ { D_DONE_YEAR2, D_DONE /* Input: d_eos, State: d_year2 */ },
+#ifdef MBS
+ { D_BAD_FORM, D_HR /* INPUT: D_EOS, STATE: D_HR */ },
+ { D_BAD_FORM, D_MIN /* INPUT: D_EOS, STATE: D_MIN */ },
+ { D_DONE_SEC, D_DONE /* INPUT: D_EOS, STATE: D_SEC */ },
+#endif
+ },
+ {
+ { D_BAD_FORM, D_DONE /* Input: d_letter, State: d_done */ },
+ { D_DEF_DY1, D_MONTH /* Input: d_letter, State: d_init */ },
+ { D_DONE_DY1, D_MONTH /* Input: d_letter, State: d_mon_or_dy */ },
+ { D_BAD_FORM, D_MON_OR_YR1 /* Input: d_letter, State: d_mon_or_yr1 */ },
+ { D_DONE_DY1, D_MONTH /* Input: d_letter, State: d_mon_or_yr2 */ },
+ { D_STORE_T2, D_MONTH /* Input: d_letter, State: d_month */ },
+ { D_BAD_FORM, D_YEAR1 /* Input: d_letter, State: d_year1 */ },
+ { D_BAD_FORM, D_YEAR2 /* Input: d_letter, State: d_year2 */ },
+#ifdef MBS
+ { D_BAD_FORM, D_HR /* INPUT: D_LETTER, STATE: D_HR */ },
+ { D_BAD_FORM, D_MIN /* INPUT: D_LETTER, STATE: D_MIN */ },
+ { D_BAD_FORM, D_SEC /* INPUT: D_LETTER, STATE: D_SEC */ },
+#endif
+ },
+ {
+ { D_BAD_FORM, D_DONE /* Input: d_slash, State: d_done */ },
+ { D_BAD_FORM, D_INIT /* Input: d_slash, State: d_init */ },
+ { D_DONE_DY2, D_MON_OR_YR1 /* Input: d_slash, State: d_mon_or_dy */ },
+ { D_DONE_MO3, D_YEAR1 /* Input: d_slash, State: d_mon_or_yr1 */ },
+ { D_BAD_FORM, D_MON_OR_YR2 /* Input: d_slash, State: d_mon_or_yr2 */ },
+ { D_DONE_MO2, D_YEAR2 /* Input: d_slash, State: d_month */ },
+ { D_BAD_FORM, D_YEAR1 /* Input: d_slash, State: d_year1 */ },
+ { D_BAD_FORM, D_YEAR2 /* Input: d_slash, State: d_year2 */ },
+#ifdef MBS
+ { D_BAD_FORM, D_HR /* INPUT: D_SLASH, STATE: D_HR */ },
+ { D_BAD_FORM, D_MIN /* INPUT: D_SLASH, STATE: D_MIN */ },
+ { D_BAD_FORM, D_SEC /* INPUT: D_SLASH, STATE: D_SEC */ },
+#endif
+ },
+#ifdef MBS
+ {
+ { D_BAD_FORM, D_DONE /* Input: D_UNDERSCORE, State: d_done */ },
+ { D_BAD_FORM, D_INIT /* Input: D_UNDERSCORE, State: d_init */ },
+ { D_BAD_FORM, D_MON_OR_DY /* Input: D_UNDERSCORE, State: d_mon_or_dy */ },
+ { D_BAD_FORM, D_MON_OR_YR1 /* Input: D_UNDERSCORE, State: d_mon_or_yr1 */ },
+ { D_BAD_FORM, D_MON_OR_YR2 /* Input: D_UNDERSCORE, State: d_mon_or_yr2 */ },
+ { D_BAD_FORM, D_MONTH /* Input: D_UNDERSCORE, State: d_month */ },
+ { D_DONE_YEAR1, D_HR /* Input: D_UNDERSCORE, State: d_year1 */ },
+ { D_DONE_YEAR2, D_HR /* Input: D_UNDERSCORE, State: d_year2 */ },
+ { D_DONE_HR, D_MIN /* INPUT: D_UNDERSCORE, STATE: D_HR */ },
+ { D_DONE_MIN, D_SEC /* INPUT: D_UNDERSCORE, STATE: D_MIN */ },
+ { D_BAD_FORM, D_SEC /* INPUT: D_UNDERSCORE, STATE: D_SEC */ },
+ },
+#endif
+};
+
+static int comp_month( VOID_PTR, VOID_PTR ) ;
+static INT16 valid_day( INT16, INT16, CHAR_PTR, INT16 * ) ;
+static INT16 valid_month( CHAR_PTR, INT16 * ) ;
+static INT16 valid_year( CHAR_PTR, INT16 * ) ;
+static INT16 lookup_month( CHAR_PTR, INT16 * ) ;
+static INT16 dnextch( CHAR_PTR , INT16_PTR , CHAR_PTR ) ;
+
+/*****************************************************************************
+
+ Name: tbdpars()
+
+ Description: This function parses a date string to produce a
+ generic time and date structure.
+
+ Returns: SUCCESS if successful or
+ !SUCCESS if failed.
+
+*****************************************************************************/
+INT16 tbdpars(
+CHAR *candidate, /* I - String to parse */
+DATE_TIME *out_date, /* O - date returned */
+DATE_DEFAULT date_default ) /* I - How should we default the un-specified fields */
+{
+ INT16 dpars_state ; /* current state of parser fsm */
+ INT16 dpars_old_state ; /* old state of parser fsm */
+ register INT16 dpars_input; /* conditioned input for syntax fsm */
+ register INT16 dpars_action; /* action to take */
+ CHAR c ; /* latest CHAR from candidate */
+ INT16 i = 0 ;
+
+ INT16 ret_val = SUCCESS;
+
+ CHAR t1[20];
+ CHAR t2[20];
+ CHAR t3[20];
+
+ INT16 i1 = 0 ;
+ INT16 i2 = 0 ;
+ INT16 i3 = 0 ;
+
+ INT16 year = 0 ;
+ INT16 month = 0 ;
+ INT16 day = 0 ;
+
+#ifdef MBS
+ CHAR hr[ 3 ] ;
+ CHAR min[ 3 ] ;
+ CHAR sec[ 3 ] ;
+
+ INT16 hr_index = 0 ;
+ INT16 min_index = 0 ;
+ INT16 sec_index = 0 ;
+
+ *hr = *min = *sec = TEXT('\0') ;
+#endif
+
+ *t1 = *t2 = *t3 = TEXT('\0') ;
+
+ out_date->date_valid = FALSE ;
+
+ dpars_state = D_INIT ;
+ dpars_old_state = D_INIT ;
+ dpars_input = 0 ;
+
+ while( ret_val == SUCCESS ) {
+ dpars_input = dnextch( candidate, &i, &c ) ;
+
+ msassert( dpars_input >= 0 && dpars_input < TBDTTAB_N_INPUTS ) ;
+
+ dpars_old_state = dpars_state ;
+ dpars_action = tbdttab_state_table[dpars_input][dpars_old_state].action ;
+ dpars_state = tbdttab_state_table[dpars_input][dpars_old_state].next_state ;
+
+ msassert( dpars_state >= 0 && dpars_state < TBDTTAB_N_STATES ) ;
+ switch( dpars_action ) {
+ case D_BAD_FORM :
+ ret_val = 1 ; /* quit with error */
+ break ;
+
+ case D_STORE_T1 :
+ t1[i1] = (CHAR)toupper( c ) ;
+ i1++ ;
+ break ;
+
+ case D_STORE_T2 :
+ t2[i2] = (CHAR)toupper( c ) ;
+ i2++ ;
+ break ;
+
+ case D_STORE_T3 :
+ t3[i3] = (CHAR)toupper( c ) ;
+ i3++ ;
+ break ;
+
+ case D_DEF_DY1 :
+ day = 1 ;
+ ( VOID ) strcpy( t1, TEXT("1") ) ;
+ t2[i2] = (CHAR)toupper( c ) ;
+ i2++ ;
+ break ;
+
+ case D_DONE_DY1 :
+ t1[i1] = TEXT('\0') ;
+ t2[i2] = (CHAR)toupper( c ) ;
+ i2 ++ ;
+ break ;
+
+ case D_DONE_DY2 :
+ t1[i1] = TEXT('\0') ;
+ break ;
+
+ case D_DONE_DY3 :
+ t1[i1] = TEXT('\0') ;
+ t2[i2] = c ;
+ i2 ++ ;
+ break ;
+
+ case D_DONE_MO1 :
+ t2[i2] = TEXT('\0') ;
+ year = 1980;
+
+ if( lookup_month( t2, &month ) != 0 ) {
+ ret_val = 2 ;
+ }
+ if( valid_day( year, month, t1, &day ) != 0 ) {
+ ret_val = 3 ;
+ }
+ t3[i3] = c ;
+ i3 ++ ;
+ break ;
+
+ case D_DONE_MO2 :
+ t2[i2] = TEXT('\0') ;
+ year = 1980;
+ if( lookup_month( t2, &month ) != 0 ) {
+ ret_val = 4 ;
+ }
+ if( valid_day( year, month, t1, &day ) != 0 ) {
+ ret_val = 5 ;
+ }
+ break ;
+
+ case D_DONE_MO3 :
+ t2[i2] = TEXT('\0') ;
+ year = 1980;
+ if( valid_month( t1, &month ) != 0 ) {
+ ret_val = 6 ;
+ }
+ if( valid_day( year, month, t2, &day ) != 0 ) {
+ ret_val = 7;
+ }
+ break ;
+
+ case D_DONE_NO_DAY:
+ day = 1 ;
+ t2[i2] = TEXT('\0') ;
+ if( valid_year( t2, &year ) != 0 ) {
+ ret_val = 8;
+ }
+ if( valid_month( t1, &month ) != 0 ) {
+ ret_val = 9 ;
+ }
+ ret_val = -1;
+ break ;
+
+ case D_DONE_YEAR1 :
+ t3[i3] = TEXT('\0') ;
+ if( valid_year( t3, &year ) != 0 ) {
+ ret_val = 10 ;
+ }
+ if( valid_month( t1, &month ) != 0 ) {
+ ret_val = 11 ;
+ }
+ if( valid_day( year, month, t2, &day ) != 0 ) {
+ ret_val = 12 ;
+ }
+ out_date->date_valid = TRUE ;
+#ifndef MBS
+ ret_val = -1;
+#endif
+ break ;
+
+ case D_DONE_YEAR2 :
+ t3[i3] = TEXT('\0') ;
+ if( valid_year( t3, &year ) != 0 ) {
+ ret_val = 13 ;
+ }
+ if( lookup_month( t2, &month ) != 0 ) {
+ ret_val = 14 ;
+ }
+ if( valid_day( year, month, t1, &day ) != 0 ) {
+ ret_val = 15 ;
+ }
+#ifndef MBS
+ ret_val = -1;
+#endif
+ break ;
+
+#ifdef MBS
+ case D_STORE_HR :
+ hr[ hr_index ] = (CHAR)toupper( c ) ;
+ hr_index++ ;
+ break ;
+
+ case D_STORE_MIN :
+ min[ min_index ] = (CHAR)toupper( c ) ;
+ min_index++ ;
+ break ;
+
+ case D_STORE_SEC :
+ sec[ sec_index ] = (CHAR)toupper( c ) ;
+ sec_index++ ;
+ break ;
+
+ case D_DONE_HR :
+ hr[ hr_index ] = TEXT('\0') ;
+ break ;
+
+ case D_DONE_MIN :
+ min[ min_index ] = TEXT('\0') ;
+ break ;
+
+ case D_DONE_SEC :
+ sec[ sec_index ] = TEXT('\0') ;
+ ret_val = - 1;
+ break ;
+#endif
+
+ case D_RETURN_OK:
+ ret_val = -1;
+ break ;
+
+ default :
+ ret_val = 1 ; /* quit with error */
+ msassert( /* dpars: bad action */ FALSE ) ;
+ break ;
+ } /* end switch */
+ } /* end while */
+ if( ret_val == -1 ) {
+ out_date->year = year ;
+ out_date->month = month ;
+ out_date->day = day ;
+#ifdef MBS
+ out_date->hour = atoi( hr ) ;
+ out_date->minute = atoi( min ) ;
+ out_date->second = atoi( sec ) ;
+ if ( (*hr == TEXT('\0')) && (*min == TEXT('\0')) && (*sec == TEXT('\0')) &&
+ (date_default == DEFAULT_LATE_NIGHT) ) {
+ out_date->hour = 25 ;
+ out_date->minute = 61 ;
+ out_date->second = 61 ;
+ }
+#else
+ if ( date_default == DEFAULT_EARLY_MORNING ) {
+ out_date->hour = 0 ;
+ out_date->minute = 0 ;
+ out_date->second = 0 ;
+ } else {
+ out_date->hour = 25 ;
+ out_date->minute = 61 ;
+ out_date->second = 61 ;
+ }
+#endif
+ out_date->day_of_week = 0 ;
+ out_date->date_valid = TRUE ;
+ ret_val = SUCCESS ;
+ }
+
+ return( ret_val ) ;
+
+} /* end tbparse */
+/*****************************************************************************
+
+ Name: valid_date()
+
+ Description: This function returns SUCCESS if the day in the
+ day_string is valid for the month in the tdate structure.
+ It modifies "day" to equal the day indecated by the day_string.
+
+ Returns: SUCCESS if valid
+
+ Notes: Does not support leap year.
+
+ See also: $/SEE( valid_month(), valid_year() )$
+
+*****************************************************************************/
+static INT16 valid_day(
+ INT16 year , /* I - check for this year */
+ INT16 month , /* I - and this month */
+ CHAR_PTR day_string , /* I - string to parse day from */
+ INT16 *day ) /* O - day found if valid */
+{
+
+ *day = (INT16)atoi( day_string ) ;
+ daymon[1] = ( year % 4 == 0 && year % 100 != 0 || year % 400 == 0 ) ? 29 : 28;
+
+ if ( (INT)*day < 1 || (INT)*day > daymon[month - 1] ) {
+ return( FAILURE ) ;
+ }
+ return( SUCCESS ) ;
+} /* end valid day */
+/*****************************************************************************
+
+ Name: valid_month()
+
+ Description: This function checks to see if the specified month
+ is valid.
+
+ Returns: SUCCESS if valid
+
+ Notes: simply checks to see if month is between 1 and 12
+ and converts it from string to INT.
+
+ See also: $/SEE( valid_day(), valid_year() )$
+
+*****************************************************************************/
+static INT16 valid_month (
+ CHAR_PTR month_string , /* I - month to parse TEXT("1") - TEXT("12") */
+ INT16 *month ) /* O - month if valid */
+{
+ *month = (INT16)atoi( month_string ) ;
+ if( *month < 1 || *month > 12 ) {
+ return( FAILURE ) ;
+ }
+ return( SUCCESS ) ;
+} /* end valid day */
+
+/*****************************************************************************
+
+ Name: lookup_month()
+
+ Description: Converts a string like "JAN" or "January" to a
+ string lik "1"
+
+ Returns: SUCCESS if valid
+
+ Notes: Needs the comp_month() function to pass to
+ bserach()
+
+ See also: $/SEE( valid_month() )$
+
+*****************************************************************************/
+static INT16 lookup_month(
+CHAR_PTR month_string, /* I - ascii string to parse */
+INT16 *month ) /* O - numeric string found */
+{
+ SW_TAB_PTR sp ;
+
+ *month = 0 ;
+
+ sp = (SW_TAB_PTR)bsearch( (VOID *)month_string, (VOID *)montab, 12,
+ sizeof( struct SW_TAB_TYPE ),
+ (int (__cdecl *)(const void *, const void *))comp_month ) ;
+
+ if( sp == NULL ) {
+ return( 1 ) ;
+ }
+ *month = sp->sw_action ;
+ return( 0 ) ;
+
+} /* end lookup_month */
+
+static int comp_month(
+VOID_PTR s1,
+VOID_PTR s2 )
+{
+ return( strncmp( (CHAR_PTR)s1, ((SW_TAB_PTR)s2)->sw_label, strlen( (CHAR_PTR)s1 ) ) ) ;
+}
+/*****************************************************************************
+
+ Name: valid_year()
+
+ Description: This function checks to make sure the year string
+ provided is valid. If valid it converts it to an interger.
+
+ Returns: SUCCESS if valid
+
+ Notes: This routine adds 1900 if the year is < 100.
+
+ See also: $/SEE( valid_day(), valid_month() )$
+
+*****************************************************************************/
+static INT16 valid_year(
+ CHAR_PTR year_string , /* I - string to parse */
+ INT16 *year ) /* O - year in an INT */
+{
+ *year = (INT16)atoi( year_string ) ;
+ if( *year < 100 ) {
+ *year += 1900 ;
+ }
+ if( *year > 1999 ) {
+ return( 1 ) ;
+ }
+ return( 0 ) ;
+} /* end valid_year */
+/*****************************************************************************
+
+ Name: dnextch()
+
+ Description: This function gets the next character from the
+ input stream. It returns the type of character read.
+
+ Returns: type of character :
+ D_LETTER
+ D_DIGET
+ D_DASH
+ D_SLASH
+ D_EOS
+
+ See also: $/SEE( tbdpars() )$
+
+*****************************************************************************/
+static INT16 dnextch(
+CHAR *source, /* I - data stream */
+INT16_PTR pos, /*I/O- current position */
+CHAR_PTR c ) /* O - next character found */
+{
+ *c = source[*pos] ;
+
+ ( *pos ) ++ ;
+ if( isdigit( *c ) ) {
+ return( D_DIGIT ) ;
+ }
+ if( isupper( *c ) || islower( *c ) ) {
+ return( D_LETTER ) ;
+ }
+ if( *c == TEXT('/') ) {
+ return( D_SLASH ) ;
+ }
+ if( *c == TEXT('-') ) {
+ return( D_DASH ) ;
+ }
+#ifdef MBS
+ if ( *c == TEXT('_') ) {
+ return( D_UNDERSCORE ) ;
+ }
+#endif
+ return( D_EOS ) ;
+}
diff --git a/private/utils/ntbackup/src/tbgetc.c b/private/utils/ntbackup/src/tbgetc.c
new file mode 100644
index 000000000..92fcb79da
--- /dev/null
+++ b/private/utils/ntbackup/src/tbgetc.c
@@ -0,0 +1,88 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: tbgetc.c
+
+ Description: This file contains code to get & unget a character from
+ a string.
+
+ $Log: G:/UI/LOGFILES/TBGETC.C_V $
+
+ Rev 1.6 23 Jul 1993 19:11:34 MARINA
+enable c++
+
+ Rev 1.5 01 Nov 1992 16:08:38 DAVEV
+Unicode changes
+
+ Rev 1.4 07 Oct 1992 14:16:10 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.3 04 Oct 1992 19:40:56 DAVEV
+Unicode Awk pass
+
+ Rev 1.2 17 Aug 1992 13:23:22 DAVEV
+MikeP's changes at Microsoft
+
+ Rev 1.1 18 May 1992 09:06:38 MIKEP
+header
+
+ Rev 1.0 20 Nov 1991 19:34:50 SYSTEM
+Initial revision.
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+/*****************************************************************************
+
+ Name: strgetc()
+
+ Description: This function gets the character at the specified
+ position in the specified string.
+
+ Returns: Character found or ^Z if end of file
+
+ See also: $/SEE( filgetc() )$
+
+*****************************************************************************/
+CHAR strgetc(
+CHAR_PTR s, /* I - string to get character from */
+INT16_PTR i ) /*I/O- current character poisition */
+{
+ CHAR next ;
+
+ next = s[*i] ;
+ if( next == TEXT('\0') )
+ {
+ next = ( CHAR ) 0x1a ; /* Control-Z, EOF */
+ }
+ ( *i ) ++ ;
+ return( next ) ;
+}
+/*****************************************************************************
+
+ Name: strpushc()
+
+ Description: This function "un-gets" the character in a string.
+
+ Returns: none
+
+ Notes: This function realy only decroments the string
+ possition.
+
+*****************************************************************************/
+VOID strpushc(
+CHAR c , /* U - not used, arround for consistancy */
+CHAR_PTR src_ptr , /* U - not used, arround for consistancy */
+INT16_PTR i ) /*I/O- string position */
+{
+ c; /* These two lines are to remove compiler warnings */
+ src_ptr ; /* */
+
+ ( *i ) -- ;
+ return ;
+}
diff --git a/private/utils/ntbackup/src/tbnextok.c b/private/utils/ntbackup/src/tbnextok.c
new file mode 100644
index 000000000..769c86303
--- /dev/null
+++ b/private/utils/ntbackup/src/tbnextok.c
@@ -0,0 +1,943 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: tbnextok.c
+
+ Description: This file contains code to get next token from the
+ specified input streem.
+
+ $Log: G:/UI/LOGFILES/TBNEXTOK.C_V $
+
+ Rev 1.5 26 Jul 1993 11:56:30 MARINA
+enable c++
+
+ Rev 1.4 01 Nov 1992 16:08:58 DAVEV
+Unicode changes
+
+ Rev 1.3 07 Oct 1992 14:16:40 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.2 04 Oct 1992 19:40:58 DAVEV
+Unicode Awk pass
+
+ Rev 1.1 18 May 1992 09:06:40 MIKEP
+header
+
+ Rev 1.0 20 Nov 1991 19:35:00 SYSTEM
+Initial revision.
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+/**
+ Inputs for tblextab FSM
+**/
+
+#define AT_SIGN 0
+#define BACK_SLASH 1
+#define CLOSE_COMMENT 2
+#define COLON 3
+#define D_QUOTE 4
+#define DIGIT 5
+#define EOI 6
+#define EQUALS_SIGN 7
+#define FORWARD_SLASH 8
+#define L_BRACKET 9
+#define LETTER 10
+#define MINUS_SIGN 11
+#define OTHER_CHAR 12
+#define PERIOD 13
+#define Q_MARK 14
+#define R_BRACKET 15
+#define STAR 16
+#define START_COMMENT 17
+#define WHITE_SPACE 18
+
+/**/
+/**
+ Actions for tblextab FSM
+**/
+
+#define BAD_TOKEN 0
+#define DO_NOTHING 1
+#define HANGING_COMMENT 2
+#define HANGING_QUOTE 3
+#define POP_STATE 4
+#define PUSH_STATE 5
+#define RETURN_AT_SIGN 6
+#define RETURN_EOI 7
+#define RETURN_EQUALS 8
+#define RETURN_NONDOS 9
+#define RETURN_NONDOS_PUSH 10
+#define RETURN_PATH 11
+#define RETURN_PATH_PUSH 12
+#define RETURN_SWITCH 13
+#define RETURN_SWITCH_PUSH 14
+#define STORE_CHAR 15
+#define STORE_OP1 16
+#define STORE_OP2 17
+#define STORE_SLASH_OP1 18
+#define STORE_SLASH_OP2 19
+#define POSSIBLE_RET_PATH 20
+/**/
+/**
+ States for tblextab FSM
+**/
+
+#define EMBEDDED_SLASH1 0
+#define EMBEDDED_SLASH2 1
+#define IN_COMMENT 2
+#define IN_LITERAL1 3
+#define IN_LITERAL2 4
+#define IN_NONDOS 5
+#define IN_NONDOS2 6
+#define IN_OP1 7
+#define IN_OP2 8
+#define IN_SWITCH 9
+#define IN_WHITESPACE 10
+#define PATH_NAME 11
+#define PATH_OR_NDOS 12
+#define QUOTED_PATH_LIT 13
+
+
+#define TBLEXTAB_N_INPUTS 19
+#define TBLEXTAB_N_STATES 14
+
+static struct STATE_TAB_TYPE tblextab_state_table[TBLEXTAB_N_INPUTS] [TBLEXTAB_N_STATES] =
+{
+ {
+ { BAD_TOKEN, EMBEDDED_SLASH1 /* Input: at_sign, State: embedded_slash1 */ },
+ { BAD_TOKEN, EMBEDDED_SLASH2 /* Input: at_sign, State: embedded_slash2 */ },
+ { DO_NOTHING, IN_COMMENT /* Input: at_sign, State: in_comment */ },
+ { STORE_OP1, IN_LITERAL1 /* Input: at_sign, State: in_literal1 */ },
+ { STORE_OP2, IN_LITERAL2 /* Input: at_sign, State: in_literal2 */ },
+ { STORE_CHAR, PATH_NAME /* Input: at_sign, State: in_nondos */ },
+ { STORE_CHAR, IN_NONDOS2 /* Input: at_sign, State: in_nondos2 */ },
+ { RETURN_SWITCH_PUSH, IN_WHITESPACE /* Input: at_sign, State: in_op1 */ },
+ { RETURN_SWITCH_PUSH, IN_WHITESPACE /* Input: at_sign, State: in_op2 */ },
+ { RETURN_SWITCH_PUSH, IN_WHITESPACE /* Input: at_sign, State: in_switch */ },
+ { RETURN_AT_SIGN, PATH_NAME /* Input: at_sign, State: in_whitespace */ },
+ { STORE_CHAR, PATH_NAME /* Input: at_sign, State: path_name */ },
+ { STORE_CHAR, PATH_NAME /* Input: at_sign, State: path_or_ndos */ },
+ { STORE_CHAR, QUOTED_PATH_LIT /* Input: at_sign, State: quoted_path_lit */ }
+ },
+ {
+ { BAD_TOKEN, EMBEDDED_SLASH1 /* Input: back_slash, State: embedded_slash1 */ },
+ { BAD_TOKEN, EMBEDDED_SLASH2 /* Input: back_slash, State: embedded_slash2 */ },
+ { DO_NOTHING, IN_COMMENT /* Input: back_slash, State: in_comment */ },
+ { STORE_OP1, IN_LITERAL1 /* Input: back_slash, State: in_literal1 */ },
+ { STORE_OP2, IN_LITERAL2 /* Input: back_slash, State: in_literal2 */ },
+ { BAD_TOKEN, IN_NONDOS /* Input: back_slash, State: in_nondos */ },
+ { STORE_CHAR, IN_NONDOS2 /* Input: back_slash, State: in_nondos2 */ },
+ { RETURN_SWITCH, PATH_NAME /* Input: back_slash, State: in_op1 */ },
+ { RETURN_SWITCH, PATH_NAME /* Input: back_slash, State: in_op2 */ },
+ { RETURN_SWITCH_PUSH, IN_WHITESPACE /* Input: back_slash, State: in_switch */ },
+ { STORE_CHAR, PATH_NAME /* Input: back_slash, State: in_whitespace */ },
+ { STORE_CHAR, PATH_NAME /* Input: back_slash, State: path_name */ },
+ { STORE_CHAR, PATH_NAME /* Input: back_slash, State: path_or_ndos */ },
+ { STORE_CHAR, QUOTED_PATH_LIT /* Input: back_slash, State: quoted_path_lit */ }
+ },
+ {
+ { BAD_TOKEN, EMBEDDED_SLASH1 /* Input: close_comment, State: embedded_slash1 */ },
+ { BAD_TOKEN, EMBEDDED_SLASH2 /* Input: close_comment, State: embedded_slash2 */ },
+ { POP_STATE, IN_COMMENT /* Input: close_comment, State: in_comment */ },
+ { STORE_OP1, IN_LITERAL1 /* Input: close_comment, State: in_literal1 */ },
+ { STORE_OP2, IN_LITERAL2 /* Input: close_comment, State: in_literal2 */ },
+ { BAD_TOKEN, IN_NONDOS /* Input: close_comment, State: in_nondos */ },
+ { BAD_TOKEN, IN_NONDOS2 /* Input: close_comment, State: in_nondos2 */ },
+ { BAD_TOKEN, IN_OP1 /* Input: close_comment, State: in_op1 */ },
+ { BAD_TOKEN, IN_OP2 /* Input: close_comment, State: in_op2 */ },
+ { BAD_TOKEN, IN_SWITCH /* Input: close_comment, State: in_switch */ },
+ { BAD_TOKEN, IN_WHITESPACE /* Input: close_comment, State: in_whitespace */ },
+ { STORE_CHAR, PATH_NAME /* Input: close_comment, State: path_name */ },
+ { STORE_CHAR, PATH_OR_NDOS /* Input: close_comment, State: path_or_ndos */ },
+ { STORE_CHAR, QUOTED_PATH_LIT /* Input: close_comment, State: quoted_path_lit */ }
+ },
+ {
+ { BAD_TOKEN, EMBEDDED_SLASH1 /* Input: colon, State: embedded_slash1 */ },
+ { BAD_TOKEN, EMBEDDED_SLASH2 /* Input: colon, State: embedded_slash2 */ },
+ { DO_NOTHING, IN_COMMENT /* Input: colon, State: in_comment */ },
+ { STORE_OP1, IN_LITERAL1 /* Input: colon, State: in_literal1 */ },
+ { STORE_OP2, IN_LITERAL2 /* Input: colon, State: in_literal2 */ },
+ { BAD_TOKEN, IN_NONDOS /* Input: colon, State: in_nondos */ },
+ { STORE_CHAR, IN_NONDOS2 /* Input: colon, State: in_nondos2 */ },
+ { DO_NOTHING, IN_OP2 /* Input: colon, State: in_op1 */ },
+ { BAD_TOKEN, IN_OP2 /* Input: colon, State: in_op2 */ },
+ { DO_NOTHING, IN_OP1 /* Input: colon, State: in_switch */ },
+ { BAD_TOKEN, IN_WHITESPACE /* Input: colon, State: in_whitespace */ },
+ { STORE_CHAR, PATH_NAME /* Input: colon, State: path_name */ },
+ { STORE_CHAR, IN_NONDOS /* Input: colon, State: path_or_ndos */ },
+ { STORE_CHAR, QUOTED_PATH_LIT /* Input: colon, State: quoted_path_lit */ }
+ },
+ {
+ { BAD_TOKEN, EMBEDDED_SLASH1 /* Input: d_quote, State: embedded_slash1 */ },
+ { BAD_TOKEN, EMBEDDED_SLASH2 /* Input: d_quote, State: embedded_slash2 */ },
+ { DO_NOTHING, IN_COMMENT /* Input: d_quote, State: in_comment */ },
+ { DO_NOTHING, IN_OP1 /* Input: d_quote, State: in_literal1 */ },
+ { DO_NOTHING, IN_OP2 /* Input: d_quote, State: in_literal2 */ },
+ { BAD_TOKEN, IN_NONDOS /* Input: d_quote, State: in_nondos */ },
+ { STORE_CHAR, IN_NONDOS2 /* Input: d_quote, State: in_nondos2 */ },
+ { DO_NOTHING, IN_LITERAL1 /* Input: d_quote, State: in_op1 */ },
+ { DO_NOTHING, IN_LITERAL2 /* Input: d_quote, State: in_op2 */ },
+ { BAD_TOKEN, IN_SWITCH /* Input: d_quote, State: in_switch */ },
+ { DO_NOTHING, QUOTED_PATH_LIT /* Input: d_quote, State: in_whitespace */ },
+ { DO_NOTHING, QUOTED_PATH_LIT /* Input: d_quote, State: path_name */ },
+ { BAD_TOKEN, PATH_OR_NDOS /* Input: d_quote, State: path_or_ndos */ },
+ { DO_NOTHING, PATH_NAME /* Input: d_quote, State: quoted_path_lit */ }
+ },
+ {
+ { STORE_SLASH_OP1, IN_OP1 /* Input: digit, State: embedded_slash1 */ },
+ { STORE_SLASH_OP2, IN_OP2 /* Input: digit, State: embedded_slash2 */ },
+ { DO_NOTHING, IN_COMMENT /* Input: digit, State: in_comment */ },
+ { STORE_OP1, IN_LITERAL1 /* Input: digit, State: in_literal1 */ },
+ { STORE_OP2, IN_LITERAL2 /* Input: digit, State: in_literal2 */ },
+ { STORE_CHAR, IN_NONDOS /* Input: digit, State: in_nondos */ },
+ { STORE_CHAR, IN_NONDOS2 /* Input: digit, State: in_nondos2 */ },
+ { STORE_OP1, IN_OP1 /* Input: digit, State: in_op1 */ },
+ { STORE_OP2, IN_OP2 /* Input: digit, State: in_op2 */ },
+ { STORE_CHAR, IN_SWITCH /* Input: digit, State: in_switch */ },
+ { STORE_CHAR, PATH_OR_NDOS /* Input: digit, State: in_whitespace */ },
+ { STORE_CHAR, PATH_NAME /* Input: digit, State: path_name */ },
+ { STORE_CHAR, PATH_NAME /* Input: digit, State: path_or_ndos */ },
+ { STORE_CHAR, QUOTED_PATH_LIT /* Input: digit, State: quoted_path_lit */ }
+ },
+ {
+ { BAD_TOKEN, EMBEDDED_SLASH1 /* Input: eoi, State: embedded_slash1 */ },
+ { BAD_TOKEN, EMBEDDED_SLASH2 /* Input: eoi, State: embedded_slash2 */ },
+ { HANGING_COMMENT, IN_WHITESPACE /* Input: eoi, State: in_comment */ },
+ { HANGING_QUOTE, IN_WHITESPACE /* Input: eoi, State: in_literal1 */ },
+ { HANGING_QUOTE, IN_WHITESPACE /* Input: eoi, State: in_literal2 */ },
+ { RETURN_NONDOS_PUSH, IN_WHITESPACE /* Input: eoi, State: in_nondos */ },
+ { BAD_TOKEN, IN_NONDOS2 /* Input: eoi, State: in_nondos2 */ },
+ { RETURN_SWITCH_PUSH, IN_WHITESPACE /* Input: eoi, State: in_op1 */ },
+ { RETURN_SWITCH_PUSH, IN_WHITESPACE /* Input: eoi, State: in_op2 */ },
+ { RETURN_SWITCH_PUSH, IN_WHITESPACE /* Input: eoi, State: in_switch */ },
+ { RETURN_EOI, IN_WHITESPACE /* Input: eoi, State: in_whitespace */ },
+ { RETURN_PATH_PUSH, IN_WHITESPACE /* Input: eoi, State: path_name */ },
+ { RETURN_PATH_PUSH, IN_WHITESPACE /* Input: eoi, State: path_or_ndos */ },
+ { HANGING_QUOTE, IN_WHITESPACE /* Input: eoi, State: quoted_path_lit */ }
+ },
+ {
+ { BAD_TOKEN, EMBEDDED_SLASH1 /* Input: equals_sign, State: embedded_slash1 */ },
+ { BAD_TOKEN, EMBEDDED_SLASH2 /* Input: equals_sign, State: embedded_slash2 */ },
+ { DO_NOTHING, IN_COMMENT /* Input: equals_sign, State: in_comment */ },
+ { STORE_OP1, IN_LITERAL1 /* Input: equals_sign, State: in_literal1 */ },
+ { STORE_OP2, IN_LITERAL2 /* Input: equals_sign, State: in_literal2 */ },
+ { RETURN_NONDOS_PUSH, IN_WHITESPACE /* Input: equals_sign, State: in_nondos */ },
+ { BAD_TOKEN, IN_NONDOS2 /* Input: equals_sign, State: in_nondos2 */ },
+ { RETURN_SWITCH_PUSH, IN_WHITESPACE /* Input: equals_sign, State: in_op1 */ },
+ { RETURN_SWITCH_PUSH, IN_WHITESPACE /* Input: equals_sign, State: in_op2 */ },
+ { RETURN_SWITCH_PUSH, IN_WHITESPACE /* Input: equals_sign, State: in_switch */ },
+ { RETURN_EQUALS, IN_WHITESPACE /* Input: equals_sign, State: in_whitespace */ },
+ { RETURN_PATH_PUSH, IN_WHITESPACE /* Input: equals_sign, State: path_name */ },
+ { RETURN_PATH_PUSH, IN_WHITESPACE /* Input: equals_sign, State: path_or_ndos */ },
+ { STORE_CHAR, QUOTED_PATH_LIT /* Input: equal_sign, State: quoted_path_lit */ }
+ },
+ {
+ { BAD_TOKEN, EMBEDDED_SLASH1 /* Input: forward_slash, State: embedded_slash1 */ },
+ { BAD_TOKEN, EMBEDDED_SLASH2 /* Input: forward_slash, State: embedded_slash2 */ },
+ { DO_NOTHING, IN_COMMENT /* Input: forward_slash, State: in_comment */ },
+ { STORE_OP1, IN_LITERAL1 /* Input: forward_slash, State: in_literal1 */ },
+ { STORE_OP2, IN_LITERAL2 /* Input: forward_slash, State: in_literal2 */ },
+ { RETURN_NONDOS, IN_SWITCH /* Input: forward_slash, State: in_nondos */ },
+ { STORE_CHAR, IN_NONDOS2 /* Input: forward_slash, State: in_nondos2 */ },
+ { DO_NOTHING, EMBEDDED_SLASH1 /* Input: forward_slash, State: in_op1 */ },
+ { DO_NOTHING, EMBEDDED_SLASH2 /* Input: forward_slash, State: in_op2 */ },
+ { RETURN_SWITCH_PUSH, IN_WHITESPACE /* Input: forward_slash, State: in_switch */ },
+ { DO_NOTHING, IN_SWITCH /* Input: forward_slash, State: in_whitespace */ },
+ { POSSIBLE_RET_PATH, PATH_NAME /* Input: forward_slash, State: path_name */ },
+ { RETURN_PATH, IN_SWITCH /* Input: forward_slash, State: path_or_ndos */ },
+ { STORE_CHAR, QUOTED_PATH_LIT /* Input: forward_slash, State: quoted_path_lit */ }
+ },
+ {
+ { BAD_TOKEN, EMBEDDED_SLASH1 /* Input: l_bracket, State: embedded_slash1 */ },
+ { BAD_TOKEN, EMBEDDED_SLASH2 /* Input: l_bracket, State: embedded_slash2 */ },
+ { DO_NOTHING, IN_COMMENT /* Input: l_bracket, State: in_comment */ },
+ { STORE_OP1, IN_LITERAL1 /* Input: l_bracket, State: in_literal1 */ },
+ { STORE_OP2, IN_LITERAL2 /* Input: l_bracket, State: in_literal2 */ },
+ { STORE_CHAR, IN_NONDOS2 /* Input: l_bracket, State: in_nondos */ },
+ { BAD_TOKEN, IN_NONDOS2 /* Input: l_bracket, State: in_nondos2 */ },
+ { BAD_TOKEN, IN_OP1 /* Input: l_bracket, State: in_op1 */ },
+ { BAD_TOKEN, IN_OP2 /* Input: l_bracket, State: in_op2 */ },
+ { BAD_TOKEN, IN_SWITCH /* Input: l_bracket, State: in_switch */ },
+ { STORE_CHAR, IN_NONDOS2 /* Input: l_bracket, State: in_whitespace */ },
+ { BAD_TOKEN, PATH_NAME /* Input: l_bracket, State: path_name */ },
+ { BAD_TOKEN, PATH_OR_NDOS /* Input: l_bracket, State: path_or_ndos */ },
+ { STORE_CHAR, QUOTED_PATH_LIT /* Input: l_bracket, State: quoted_path_lit */ }
+ },
+ {
+ { RETURN_SWITCH_PUSH, IN_SWITCH /* Input: letter, State: embedded_slash1 */ },
+ { RETURN_SWITCH_PUSH, IN_SWITCH /* Input: letter, State: embedded_slash2 */ },
+ { DO_NOTHING, IN_COMMENT /* Input: letter, State: in_comment */ },
+ { STORE_OP1, IN_LITERAL1 /* Input: letter, State: in_literal1 */ },
+ { STORE_OP2, IN_LITERAL2 /* Input: letter, State: in_literal2 */ },
+ { STORE_CHAR, IN_NONDOS /* Input: letter, State: in_nondos */ },
+ { STORE_CHAR, IN_NONDOS2 /* Input: letter, State: in_nondos2 */ },
+ { STORE_OP1, IN_OP1 /* Input: letter, State: in_op1 */ },
+ { STORE_OP2, IN_OP2 /* Input: letter, State: in_op2 */ },
+ { STORE_CHAR, IN_SWITCH /* Input: letter, State: in_switch */ },
+ { STORE_CHAR, PATH_NAME /* Input: letter, State: in_whitespace */ },
+ { STORE_CHAR, PATH_NAME /* Input: letter, State: path_name */ },
+ { STORE_CHAR, PATH_NAME /* Input: letter, State: path_or_ndos */ },
+ { STORE_CHAR, QUOTED_PATH_LIT /* Input: letter, State: quoted_path_lit */ }
+ },
+ {
+ { RETURN_SWITCH_PUSH, IN_SWITCH /* Input: minus_sign, State: embedded_slash1 */ },
+ { RETURN_SWITCH_PUSH, IN_SWITCH /* Input: minus_sign, State: embedded_slash2 */ },
+ { DO_NOTHING, IN_COMMENT /* Input: minus_sign, State: in_comment */ },
+ { STORE_OP1, IN_LITERAL1 /* Input: minus_sign, State: in_literal1 */ },
+ { STORE_OP2, IN_LITERAL2 /* Input: minus_sign, State: in_literal2 */ },
+ { BAD_TOKEN, IN_NONDOS /* Input: minus_sign, State: in_nondos */ },
+ { STORE_CHAR, IN_NONDOS2 /* Input: minus_sign, State: in_nondos2 */ },
+ { STORE_OP1, IN_OP1 /* Input: minus_sign, State: in_op1 */ },
+ { STORE_OP2, IN_OP2 /* Input: minus_sign, State: in_op2 */ },
+ { STORE_CHAR, IN_SWITCH /* Input: minus_sign, State: in_switch */ },
+ { STORE_CHAR, PATH_NAME /* Input: minus_sign, State: in_whitespace */ },
+ { STORE_CHAR, PATH_NAME /* Input: minus_sign, State: path_name */ },
+ { STORE_CHAR, PATH_NAME /* Input: minus_sign, State: path_or_ndos */ },
+ { STORE_CHAR, QUOTED_PATH_LIT /* Input: minus_sigh, State: quoted_path_lit */ }
+ },
+ {
+ { BAD_TOKEN, EMBEDDED_SLASH1 /* Input: other_char, State: embedded_slash1 */ },
+ { BAD_TOKEN, EMBEDDED_SLASH2 /* Input: other_char, State: embedded_slash2 */ },
+ { DO_NOTHING, IN_COMMENT /* Input: other_char, State: in_comment */ },
+ { STORE_OP1, IN_LITERAL1 /* Input: other_char, State: in_literal1 */ },
+ { STORE_OP2, IN_LITERAL2 /* Input: other_char, State: in_literal2 */ },
+ { BAD_TOKEN, IN_NONDOS /* Input: other_char, State: in_nondos */ },
+ { BAD_TOKEN, IN_NONDOS2 /* Input: other_char, State: in_nondos2 */ },
+ { BAD_TOKEN, IN_OP1 /* Input: other_char, State: in_op1 */ },
+ { BAD_TOKEN, IN_OP2 /* Input: other_char, State: in_op2 */ },
+ { BAD_TOKEN, IN_SWITCH /* Input: other_char, State: in_switch */ },
+ { BAD_TOKEN, IN_WHITESPACE /* Input: other_char, State: in_whitespace */ },
+ { BAD_TOKEN, PATH_NAME /* Input: other_char, State: path_name */ },
+ { BAD_TOKEN, PATH_OR_NDOS /* Input: other_char, State: path_or_ndos */ },
+ { STORE_CHAR, QUOTED_PATH_LIT /* Input: other_char, State: quoted_path_lit */ }
+ },
+ {
+ { BAD_TOKEN, EMBEDDED_SLASH1 /* Input: period, State: embedded_slash1 */ },
+ { BAD_TOKEN, EMBEDDED_SLASH2 /* Input: period, State: embedded_slash2 */ },
+ { DO_NOTHING, IN_COMMENT /* Input: period, State: in_comment */ },
+ { STORE_OP1, IN_LITERAL1 /* Input: period, State: in_literal1 */ },
+ { STORE_OP2, IN_LITERAL2 /* Input: period, State: in_literal2 */ },
+ { STORE_CHAR, IN_NONDOS /* Input: period, State: in_nondos */ },
+ { STORE_CHAR, IN_NONDOS2 /* Input: period, State: in_nondos2 */ },
+ { BAD_TOKEN, IN_OP1 /* Input: period, State: in_op1 */ },
+ { BAD_TOKEN, IN_OP2 /* Input: period, State: in_op2 */ },
+ { BAD_TOKEN, IN_SWITCH /* Input: period, State: in_switch */ },
+ { STORE_CHAR, PATH_NAME /* Input: period, State: in_whitespace */ },
+ { STORE_CHAR, PATH_NAME /* Input: period, State: path_name */ },
+ { STORE_CHAR, PATH_NAME /* Input: period, State: path_or_ndos */ },
+ { STORE_CHAR, QUOTED_PATH_LIT /* Input: period, State: quoted_path_lit */ }
+ },
+ {
+ { BAD_TOKEN, EMBEDDED_SLASH1 /* Input: q_mark, State: embedded_slash1 */ },
+ { BAD_TOKEN, EMBEDDED_SLASH2 /* Input: q_mark, State: embedded_slash2 */ },
+ { DO_NOTHING, IN_COMMENT /* Input: q_mark, State: in_comment */ },
+ { STORE_OP1, IN_LITERAL1 /* Input: q_mark, State: in_literal1 */ },
+ { STORE_OP2, IN_LITERAL2 /* Input: q_mark, State: in_literal2 */ },
+ { BAD_TOKEN, IN_NONDOS /* Input: q_mark, State: in_nondos */ },
+ { STORE_CHAR, IN_NONDOS2 /* Input: q_mark, State: in_nondos2 */ },
+ { STORE_OP1, IN_OP1 /* Input: q_mark, State: in_op1 */ },
+ { STORE_OP2, IN_OP2 /* Input: q_mark, State: in_op2 */ },
+ { STORE_OP1, IN_WHITESPACE /* Input: q_mark, State: in_switch */ },
+ { STORE_CHAR, PATH_NAME /* Input: q_mark, State: in_whitespace */ },
+ { STORE_CHAR, PATH_NAME /* Input: q_mark, State: path_name */ },
+ { STORE_CHAR, PATH_NAME /* Input: q_mark, State: path_or_ndos */ },
+ { STORE_CHAR, QUOTED_PATH_LIT /* Input: q_mark, State: quoted_path_lit */ }
+ },
+ {
+ { BAD_TOKEN, EMBEDDED_SLASH1 /* Input: r_bracket, State: embedded_slash1 */ },
+ { BAD_TOKEN, EMBEDDED_SLASH2 /* Input: r_bracket, State: embedded_slash2 */ },
+ { DO_NOTHING, IN_COMMENT /* Input: r_bracket, State: in_comment */ },
+ { STORE_OP1, IN_LITERAL1 /* Input: r_bracket, State: in_literal1 */ },
+ { STORE_OP2, IN_LITERAL2 /* Input: r_bracket, State: in_literal2 */ },
+ { BAD_TOKEN, IN_NONDOS /* Input: r_bracket, State: in_nondos */ },
+ { STORE_CHAR, IN_NONDOS /* Input: r_bracket, State: in_nondos2 */ },
+ { BAD_TOKEN, IN_OP1 /* Input: r_bracket, State: in_op1 */ },
+ { BAD_TOKEN, IN_OP2 /* Input: r_bracket, State: in_op2 */ },
+ { BAD_TOKEN, IN_SWITCH /* Input: r_bracket, State: in_switch */ },
+ { BAD_TOKEN, IN_WHITESPACE /* Input: r_bracket, State: in_whitespace */ },
+ { BAD_TOKEN, PATH_NAME /* Input: r_bracket, State: path_name */ },
+ { BAD_TOKEN, PATH_OR_NDOS /* Input: r_bracket, State: path_or_ndos */ },
+ { STORE_CHAR, QUOTED_PATH_LIT /* Input: r_bracket, State: quoted_path_lit */ }
+ },
+ {
+ { BAD_TOKEN, EMBEDDED_SLASH1 /* Input: star, State: embedded_slash1 */ },
+ { BAD_TOKEN, EMBEDDED_SLASH2 /* Input: star, State: embedded_slash2 */ },
+ { DO_NOTHING, IN_COMMENT /* Input: star, State: in_comment */ },
+ { STORE_OP1, IN_LITERAL1 /* Input: star, State: in_literal1 */ },
+ { STORE_OP2, IN_LITERAL2 /* Input: star, State: in_literal2 */ },
+ { BAD_TOKEN, IN_NONDOS /* Input: star, State: in_nondos */ },
+ { STORE_CHAR, IN_NONDOS2 /* Input: star, State: in_nondos2 */ },
+ { BAD_TOKEN, IN_OP1 /* Input: star, State: in_op1 */ },
+ { BAD_TOKEN, IN_OP2 /* Input: star, State: in_op2 */ },
+ { BAD_TOKEN, IN_SWITCH /* Input: star, State: in_switch */ },
+ { STORE_CHAR, PATH_NAME /* Input: star, State: in_whitespace */ },
+ { STORE_CHAR, PATH_NAME /* Input: star, State: path_name */ },
+ { STORE_CHAR, PATH_NAME /* Input: star, State: path_or_ndos */ },
+ { STORE_CHAR, QUOTED_PATH_LIT /* Input: star, State: quoted_path_lit */ }
+ },
+ {
+ { RETURN_SWITCH_PUSH, IN_WHITESPACE /* Input: start_comment, State: embedded_slash1 */ },
+ { RETURN_SWITCH_PUSH, IN_WHITESPACE /* Input: start_comment, State: embedded_slash2 */ },
+ { PUSH_STATE, IN_COMMENT /* Input: start_comment, State: in_comment */ },
+ { STORE_OP1, IN_LITERAL1 /* Input: start_comment, State: in_literal1 */ },
+ { STORE_OP2, IN_LITERAL2 /* Input: start_comment, State: in_literal2 */ },
+ { RETURN_NONDOS_PUSH, IN_WHITESPACE /* Input: start_comment, State: in_nondos */ },
+ { BAD_TOKEN, IN_NONDOS2 /* Input: start_comment, State: in_nondos2 */ },
+ { RETURN_SWITCH_PUSH, IN_WHITESPACE /* Input: start_comment, State: in_op1 */ },
+ { RETURN_SWITCH_PUSH, IN_WHITESPACE /* Input: start_comment, State: in_op2 */ },
+ { RETURN_SWITCH_PUSH, IN_WHITESPACE /* Input: start_comment, State: in_switch */ },
+ { PUSH_STATE, IN_COMMENT /* Input: start_comment, State: in_whitespace */ },
+ { STORE_CHAR, PATH_NAME /* Input: start_comment, State: path_name */ },
+ { STORE_CHAR, PATH_NAME /* Input: start_comment, State: path_or_ndos */ },
+ { STORE_CHAR, QUOTED_PATH_LIT /* Input: start_comment, State: quoted_path_lit */ }
+ },
+ {
+ { BAD_TOKEN, EMBEDDED_SLASH1 /* Input: white_space, State: embedded_slash1 */ },
+ { BAD_TOKEN, EMBEDDED_SLASH2 /* Input: white_space, State: embedded_slash2 */ },
+ { DO_NOTHING, IN_COMMENT /* Input: white_space, State: in_comment */ },
+ { STORE_OP1, IN_LITERAL1 /* Input: white_space, State: in_literal1 */ },
+ { STORE_OP2, IN_LITERAL2 /* Input: white_space, State: in_literal2 */ },
+ { RETURN_NONDOS, IN_WHITESPACE /* Input: white_space, State: in_nondos */ },
+ { STORE_CHAR, IN_NONDOS2 /* Input: white_space, State: in_nondos2 */ },
+ { RETURN_SWITCH, IN_WHITESPACE /* Input: white_space, State: in_op1 */ },
+ { RETURN_SWITCH, IN_WHITESPACE /* Input: white_space, State: in_op2 */ },
+ { RETURN_SWITCH, IN_WHITESPACE /* Input: white_space, State: in_switch */ },
+ { DO_NOTHING, IN_WHITESPACE /* Input: white_space, State: in_whitespace */ },
+ { RETURN_PATH, IN_WHITESPACE /* Input: white_space, State: path_name */ },
+ { RETURN_PATH, IN_WHITESPACE /* Input: white_space, State: path_or_ndos */ },
+ { STORE_CHAR, QUOTED_PATH_LIT /* Input: white_space, State: quoted_path_lit */ }
+ }
+};
+
+
+static UCHAR lex_input_conditioner[256] =
+{
+ OTHER_CHAR, /* 0 */
+ OTHER_CHAR, /* 1 */
+ OTHER_CHAR, /* 2 */
+ OTHER_CHAR, /* 3 */
+ OTHER_CHAR, /* 4 */
+ OTHER_CHAR, /* 5 */
+ OTHER_CHAR, /* 6 */
+ OTHER_CHAR, /* 7 */
+ OTHER_CHAR, /* 8 */
+ WHITE_SPACE, /* 9 */
+ WHITE_SPACE, /* 10 */
+ OTHER_CHAR, /* 11 */
+ OTHER_CHAR, /* 12 */
+ OTHER_CHAR, /* 13 */
+ OTHER_CHAR, /* 14 */
+ OTHER_CHAR, /* 15 */
+ OTHER_CHAR, /* 16 */
+ OTHER_CHAR, /* 17 */
+ OTHER_CHAR, /* 18 */
+ OTHER_CHAR, /* 19 */
+ OTHER_CHAR, /* 20 */
+ OTHER_CHAR, /* 21 */
+ OTHER_CHAR, /* 22 */
+ OTHER_CHAR, /* 23 */
+ OTHER_CHAR, /* 24 */
+ OTHER_CHAR, /* 25 */
+ EOI, /* 26 */
+ OTHER_CHAR, /* 27 */
+ OTHER_CHAR, /* 28 */
+ OTHER_CHAR, /* 29 */
+ OTHER_CHAR, /* 30 */
+ OTHER_CHAR, /* 31 */
+ WHITE_SPACE, /* 32 */
+ LETTER, /* 33 */
+ D_QUOTE, /* 34 */
+ LETTER, /* 35 */
+ LETTER, /* 36 */
+ LETTER, /* 37 */
+ LETTER, /* 38 */
+ LETTER, /* 39 */
+ LETTER, /* 40 */
+ LETTER, /* 41 */
+ STAR, /* 42 */
+ LETTER, /* 43 */
+ WHITE_SPACE, /* 44 */
+ MINUS_SIGN, /* 45 */
+ PERIOD, /* 46 */
+ FORWARD_SLASH, /* 47 */
+ DIGIT, /* 48 */
+ DIGIT, /* 49 */
+ DIGIT, /* 50 */
+ DIGIT, /* 51 */
+ DIGIT, /* 52 */
+ DIGIT, /* 53 */
+ DIGIT, /* 54 */
+ DIGIT, /* 55 */
+ DIGIT, /* 56 */
+ DIGIT, /* 57 */
+ COLON, /* 58 */
+ OTHER_CHAR, /* 59 */
+ OTHER_CHAR, /* 60 */
+ EQUALS_SIGN, /* 61 */
+ OTHER_CHAR, /* 62 */
+ Q_MARK, /* 63 */
+ AT_SIGN, /* 64 */
+ LETTER, /* 65 */
+ LETTER, /* 66 */
+ LETTER, /* 67 */
+ LETTER, /* 68 */
+ LETTER, /* 69 */
+ LETTER, /* 70 */
+ LETTER, /* 71 */
+ LETTER, /* 72 */
+ LETTER, /* 73 */
+ LETTER, /* 74 */
+ LETTER, /* 75 */
+ LETTER, /* 76 */
+ LETTER, /* 77 */
+ LETTER, /* 78 */
+ LETTER, /* 79 */
+ LETTER, /* 80 */
+ LETTER, /* 81 */
+ LETTER, /* 82 */
+ LETTER, /* 83 */
+ LETTER, /* 84 */
+ LETTER, /* 85 */
+ LETTER, /* 86 */
+ LETTER, /* 87 */
+ LETTER, /* 88 */
+ LETTER, /* 89 */
+ LETTER, /* 90 */
+ LETTER, /* 91 */
+ BACK_SLASH, /* 92 */
+ LETTER, /* 93 */
+ LETTER, /* 94 */
+ LETTER, /* 95 */
+ LETTER, /* 96 */
+ LETTER, /* 97 */
+ LETTER, /* 98 */
+ LETTER, /* 99 */
+ LETTER, /* 100 */
+ LETTER, /* 101 */
+ LETTER, /* 102 */
+ LETTER, /* 103 */
+ LETTER, /* 104 */
+ LETTER, /* 105 */
+ LETTER, /* 106 */
+ LETTER, /* 107 */
+ LETTER, /* 108 */
+ LETTER, /* 109 */
+ LETTER, /* 110 */
+ LETTER, /* 111 */
+ LETTER, /* 112 */
+ LETTER, /* 113 */
+ LETTER, /* 114 */
+ LETTER, /* 115 */
+ LETTER, /* 116 */
+ LETTER, /* 117 */
+ LETTER, /* 118 */
+ LETTER, /* 119 */
+ LETTER, /* 120 */
+ LETTER, /* 121 */
+ LETTER, /* 122 */
+ START_COMMENT, /* 123 */
+ OTHER_CHAR, /* 124 */
+ CLOSE_COMMENT, /* 125 */
+ LETTER, /* 126 */
+ OTHER_CHAR, /* 127 */
+ LETTER, /* 128 */
+ LETTER, /* 129 */
+ LETTER, /* 130 */
+ LETTER, /* 131 */
+ LETTER, /* 132 */
+ LETTER, /* 133 */
+ LETTER, /* 134 */
+ LETTER, /* 135 */
+ LETTER, /* 136 */
+ LETTER, /* 137 */
+ LETTER, /* 138 */
+ LETTER, /* 139 */
+ LETTER, /* 140 */
+ LETTER, /* 141 */
+ LETTER, /* 142 */
+ LETTER, /* 143 */
+ LETTER, /* 144 */
+ LETTER, /* 145 */
+ LETTER, /* 146 */
+ LETTER, /* 147 */
+ LETTER, /* 148 */
+ LETTER, /* 149 */
+ LETTER, /* 150 */
+ LETTER, /* 151 */
+ LETTER, /* 152 */
+ LETTER, /* 153 */
+ LETTER, /* 154 */
+ LETTER, /* 155 */
+ LETTER, /* 156 */
+ LETTER, /* 157 */
+ LETTER, /* 158 */
+ LETTER, /* 159 */
+ LETTER, /* 160 */
+ LETTER, /* 161 */
+ LETTER, /* 162 */
+ LETTER, /* 163 */
+ LETTER, /* 164 */
+ LETTER, /* 165 */
+ LETTER, /* 166 */
+ LETTER, /* 167 */
+ LETTER, /* 168 */
+ LETTER, /* 169 */
+ LETTER, /* 170 */
+ LETTER, /* 171 */
+ LETTER, /* 172 */
+ LETTER, /* 173 */
+ LETTER, /* 174 */
+ LETTER, /* 175 */
+ LETTER, /* 176 */
+ LETTER, /* 177 */
+ LETTER, /* 178 */
+ LETTER, /* 179 */
+ LETTER, /* 180 */
+ LETTER, /* 181 */
+ LETTER, /* 182 */
+ LETTER, /* 183 */
+ LETTER, /* 184 */
+ LETTER, /* 185 */
+ LETTER, /* 186 */
+ LETTER, /* 187 */
+ LETTER, /* 188 */
+ LETTER, /* 189 */
+ LETTER, /* 190 */
+ LETTER, /* 191 */
+ LETTER, /* 192 */
+ LETTER, /* 193 */
+ LETTER, /* 194 */
+ LETTER, /* 195 */
+ LETTER, /* 196 */
+ LETTER, /* 197 */
+ LETTER, /* 198 */
+ LETTER, /* 199 */
+ LETTER, /* 200 */
+ LETTER, /* 201 */
+ LETTER, /* 202 */
+ LETTER, /* 203 */
+ LETTER, /* 204 */
+ LETTER, /* 205 */
+ LETTER, /* 206 */
+ LETTER, /* 207 */
+ LETTER, /* 208 */
+ LETTER, /* 209 */
+ LETTER, /* 210 */
+ LETTER, /* 211 */
+ LETTER, /* 212 */
+ LETTER, /* 213 */
+ LETTER, /* 214 */
+ LETTER, /* 215 */
+ LETTER, /* 216 */
+ LETTER, /* 217 */
+ LETTER, /* 218 */
+ LETTER, /* 219 */
+ LETTER, /* 220 */
+ LETTER, /* 221 */
+ LETTER, /* 222 */
+ LETTER, /* 223 */
+ LETTER, /* 224 */
+ LETTER, /* 225 */
+ LETTER, /* 226 */
+ LETTER, /* 227 */
+ LETTER, /* 228 */
+ LETTER, /* 229 */
+ LETTER, /* 230 */
+ LETTER, /* 231 */
+ LETTER, /* 232 */
+ LETTER, /* 233 */
+ LETTER, /* 234 */
+ LETTER, /* 235 */
+ LETTER, /* 236 */
+ LETTER, /* 237 */
+ LETTER, /* 238 */
+ LETTER, /* 239 */
+ LETTER, /* 240 */
+ LETTER, /* 241 */
+ LETTER, /* 242 */
+ LETTER, /* 243 */
+ LETTER, /* 244 */
+ LETTER, /* 245 */
+ LETTER, /* 246 */
+ LETTER, /* 247 */
+ LETTER, /* 248 */
+ LETTER, /* 249 */
+ LETTER, /* 250 */
+ LETTER, /* 251 */
+ LETTER, /* 252 */
+ LETTER, /* 253 */
+ LETTER, /* 254 */
+ LETTER /* 255 */
+};
+
+/*****************************************************************************
+
+ Name: nexttok()
+
+ Description: This function returns a pointer to a structure
+ containing information about the next token in the input
+ stream. The returned structure has the token itself, plus
+ information as to its type and location in the input source.
+
+ Returns: Pointer to a TOKEN structure
+
+*****************************************************************************/
+TOKEN_PTR nexttok(
+CHAR ( * nextc ) ( CHAR_PTR , INT16_PTR ), /* used to get next CHAR from file or string */
+VOID ( * prevc ) ( CHAR, CHAR_PTR , INT16_PTR ), /* used to push back CHAR to file or string */
+INT16_PTR curr_state, /* used to remember state from previous invocation */
+INT16_PTR curr_line, /* line in source */
+INT16_PTR curr_col, /* col in source */
+CHAR_PTR src_ptr, /* pointer to file or string input source */
+INT16_PTR cmd_i ) /* index into source string */
+{
+ CHAR c ; /* latest CHAR from source */
+ INT16 curr_input ; /* latest conditioned input */
+ register INT16 i ; /* index into curr_token */
+ INT16 k ; /* indexes correct operand */
+ INT16 is[2] ; /* index into op strings */
+ INT16 c_nesting ; /* level of comment nesting */
+ INT16 old_state ; /* previous state */
+ register INT16 curr_action ; /* index into action jump table */
+ CHAR saved_c[10] ; /* holds raw input CHAR as string */
+ TOKEN_PTR this_token ; /* points to current token structure */
+
+ /* now malloc a structure to hold this token */
+ this_token = alltok( ) ;
+ if( this_token == NULL ) {
+ return( NULL ) ;
+ }
+
+ /* initialize everything in sight */
+ i = 0 ;
+ k = 0 ;
+ is[0] = 0 ;
+ is[1] = 0 ;
+ c_nesting = 0 ;
+ saved_c[0] = TEXT('\0') ;
+ this_token->tok_spelling[0] = TEXT('\0');
+ this_token->op_ptrs[0] = NULL ;
+ this_token->op_ptrs[1] = NULL ;
+
+ /* sanity checks */
+ msassert( nextc != NULL ) ;
+ msassert( prevc != NULL ) ;
+ msassert( src_ptr != NULL ) ;
+ msassert( *curr_state >= 0 && *curr_state < TBLEXTAB_N_STATES ) ;
+
+ while( TRUE )
+ {
+ /* get next input CHAR from the appropriate source (string or file) */
+ c = ( * nextc ) ( src_ptr, cmd_i ) ;
+ ( *curr_col ) ++ ;
+ if( c == TEXT('\n') ) {
+ ( *curr_line ) ++ ;
+ *curr_col = 1 ;
+ }
+ /* "condition" raw input to get fsm input */
+ curr_input = ( INT16 ) lex_input_conditioner[( ( UCHAR ) c )] ;
+
+ /* look into fsm table, see what to do and next state */
+ msassert( curr_input >= 0 && curr_input < TBLEXTAB_N_INPUTS ) ;
+
+ old_state = *curr_state ;
+ *curr_state = ( INT16 ) tblextab_state_table[curr_input][*curr_state].next_state ;
+
+ msassert( *curr_state >= 0 && *curr_state <= TBLEXTAB_N_STATES ) ;
+
+ curr_action = ( INT16 ) tblextab_state_table[curr_input][old_state].action ;
+
+ /* action routines */
+ switch ( curr_action ) {
+ case DO_NOTHING : /* no action, state change only */
+ continue ;
+
+ case BAD_TOKEN : /* ill-formed token */
+ this_token->tok_typ = T_BAD_TOKEN ;
+ break ;
+
+ case HANGING_COMMENT : /* comment open at eoi */
+ this_token->tok_typ = T_EARLY_EOF1 ;
+ break ;
+
+ case HANGING_QUOTE : /* quote open at eoi */
+ this_token->tok_typ = T_EARLY_EOF2 ;
+ break ;
+
+ case POP_STATE : /* TEXT("pop up") one level in comment nesting */
+ c_nesting -- ;
+ if( c_nesting == 0 ) {
+ *curr_state = IN_WHITESPACE ;
+ } else {
+ *curr_state = IN_COMMENT ;
+ }
+ continue ;
+
+ case PUSH_STATE : /* TEXT("push down") one level of comment nesting */
+ c_nesting ++ ;
+ continue ;
+
+ case RETURN_AT_SIGN : /* found include file switch TEXT("@") */
+ this_token->tok_typ = T_AT_SIGN ;
+ break ;
+
+ case RETURN_EOI : /* end of string or end of file */
+ this_token->tok_typ = T_EOF ;
+ break ;
+
+ case RETURN_EQUALS : /* found TEXT("=") seperateing target and source */
+ this_token->tok_typ = T_EQUALS ;
+ break ;
+
+ case RETURN_PATH_PUSH : /* set up to re-read last CHAR */
+ ( * prevc ) ( c , src_ptr, cmd_i ) ;
+
+ case RETURN_PATH : /* completed building a pathspec */
+ this_token->tok_typ = T_FILESPEC ;
+ break ;
+
+ case POSSIBLE_RET_PATH : /* completed building a pathspec */
+
+ {
+ CHAR_PTR p ;
+ CHAR_PTR old_p ;
+ BOOLEAN in_brack = FALSE ;
+
+ p = this_token->tok_spelling ;
+
+ if (*p == TEXT('+') || *p == TEXT('[')) {
+
+ this_token->tok_spelling[i] = TEXT('\0') ;
+
+ /* ignore all /'s in []'s */
+ do {
+ old_p = p ;
+ p = strchr( p, TEXT('[') ) ;
+
+ if ( p == NULL ) {
+ break ;
+ } else {
+ in_brack = TRUE ;
+ }
+
+ p = strchr( p, TEXT(']') ) ;
+
+ if ( p == NULL ) {
+ break ;
+ } else {
+ in_brack = FALSE ;
+ }
+ } while ( p != NULL ) ;
+
+
+ p = strchr( old_p, TEXT('/')) ;
+
+ if ( p == NULL || in_brack ) {
+
+ if( i > MAX_TOKEN_LEN ) {
+ this_token->tok_typ = T_TOKEN_TOO_LONG ;
+ i = MAX_TOKEN_LEN ;
+ *curr_state = IN_WHITESPACE ;
+ break ;
+ }
+ this_token->tok_spelling[i++] = c ;
+ continue;
+
+ }
+
+
+ }
+ *curr_state = IN_SWITCH ;
+ this_token->tok_typ = T_FILESPEC ;
+ }
+
+ break ;
+
+ case RETURN_NONDOS_PUSH : /* set up to re-read last CHAR */
+ ( * prevc ) ( c , src_ptr, cmd_i ) ;
+
+ case RETURN_NONDOS : /* completed a non-DOS path spec */
+ this_token->tok_typ = T_NONDOS ;
+ break ;
+
+ case RETURN_SWITCH_PUSH : /* set up to re-read last CHAR */
+ ( * prevc ) ( c , src_ptr, cmd_i ) ;
+
+ case RETURN_SWITCH : /* completed a switch */
+ this_token->tok_typ = T_SWITCH ;
+ /* Null terminate the operand strings, if present */
+ if( this_token->op_ptrs[0] != NULL ) {
+ this_token->op_ptrs[0][is[0]] = TEXT('\0') ;
+ }
+ if( this_token->op_ptrs[1] != NULL ) {
+ this_token->op_ptrs[1][is[1]] = TEXT('\0') ;
+ }
+ break ;
+
+ case STORE_CHAR : /* add current CHAR to token string */
+ if( i > MAX_TOKEN_LEN ) {
+ this_token->tok_typ = T_TOKEN_TOO_LONG ;
+ i = MAX_TOKEN_LEN ;
+ *curr_state = IN_WHITESPACE ;
+ break ;
+ }
+ if( (c > TEXT('`')) && (c < TEXT('{')) ) {
+ this_token->tok_spelling[i] = (CHAR)toupper( c ) ;
+ }
+ else {
+ this_token->tok_spelling[i] = c ;
+ }
+ i ++ ;
+ continue ;
+
+ case STORE_SLASH_OP1: /* deal with embedded slash in date switch */
+ case STORE_SLASH_OP2: /* deal with embedded slash in date switch */
+ case STORE_OP1 : /* store a character into 1st operand string */
+ case STORE_OP2 : /* store a character into 2nd operand string */
+ /* point to correct operand */
+ if( ( curr_action == STORE_SLASH_OP1 ) || ( curr_action == STORE_OP1 ) ) {
+ k = 0 ;
+ } else {
+ k = 1 ;
+ }
+ /* allocate storage for operand if necessary */
+ if( this_token->op_ptrs[k] == NULL ) {
+ this_token->op_ptrs[k] = (LPSTR)allop( MAX_TOKEN_LEN + 1) ;
+ if( this_token->op_ptrs[k] == NULL ) {
+ rlstok( &this_token ) ;
+ return( NULL ) ;
+ }
+ }
+ /* insert a slash if necessary */
+ if( ( curr_action == STORE_SLASH_OP1 ) || ( curr_action == STORE_SLASH_OP2 ) ) {
+ this_token->op_ptrs[k][is[k]] = TEXT('/') ;
+ is[k]++ ;
+ }
+ /* check that length is within bounds */
+ if( is[k] > MAX_TOKEN_LEN ) {
+ this_token->tok_typ = T_TOKEN_TOO_LONG ;
+ this_token->op_ptrs[k][MAX_TOKEN_LEN] = TEXT('\0') ;
+ *curr_state = IN_WHITESPACE ;
+ break ;
+ }
+ this_token->op_ptrs[k][is[k]] = c ;
+ is[k]++ ;
+ continue ;
+
+ default :
+ msassert( /* lex: invalid action */ FALSE ) ;
+ break ;
+ } /* end switch */
+ this_token->tok_spelling[i] = TEXT('\0') ;
+ this_token->src_line_no = *curr_line ;
+ this_token->src_col_no = *curr_col ;
+ return( this_token ) ;
+ } /* end while */
+} /* end nexttok */
diff --git a/private/utils/ntbackup/src/tbpdat.c b/private/utils/ntbackup/src/tbpdat.c
new file mode 100644
index 000000000..99c7a3213
--- /dev/null
+++ b/private/utils/ntbackup/src/tbpdat.c
@@ -0,0 +1,270 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: tbpdat.c
+
+ Description: This funciton contains the switches used by the
+ script parser.
+
+ PLEASE NOTE: the entries in the tables must remain
+ alphabetized.
+
+
+ $Log: G:/UI/LOGFILES/TBPDAT.C_V $
+
+ Rev 1.4 01 Nov 1992 16:09:14 DAVEV
+Unicode changes
+
+ Rev 1.3 07 Oct 1992 14:17:12 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.2 04 Oct 1992 19:41:04 DAVEV
+Unicode Awk pass
+
+ Rev 1.1 15 May 1992 13:35:32 MIKEP
+nt pass 2
+
+ Rev 1.0 20 Nov 1991 19:35:14 SYSTEM
+Initial revision.
+
+*****************************************************************************/
+
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+/* =>=>=>=>=> NOTE the flags MUST be in alphabetical order */
+
+struct SW_TAB_TYPE tbackup_switches[] =
+{
+ { TEXT("-ARCHIVE"), SW_MINUS_A, 2, 0 },
+ { TEXT("-FILES"), SW_FILES, 2, 0 },
+ { TEXT("-HIDDEN"), SW_MINUS_H, 2, 0 },
+ { TEXT("-SPECIAL"), SW_MINUS_S, 2, 0 },
+ { TEXT("3270"), SW_3270, 1, 0 },
+ { TEXT("ADATE"), SW_ACCESS_DATE, 2, 1 },
+
+ { TEXT("APPEND"), SW_APPEND, 1, 0 },
+ { TEXT("AUTOVERIFY"), SW_AUTO_VER, 2, 1 },
+ { TEXT("BACKUPNAME"), SW_BACK_NAME, 1, 1 },
+ { TEXT("CSR"), SW_CSR, 1, 2 },
+ { TEXT("DATE"), SW_DATE, 1, 2 },
+#if defined( MAYN_OS2 )
+ { TEXT("EDATE"), SW_NDATE, 2, 1 },
+#endif
+ { TEXT("EMPTY"), SW_EMPTY, 2, 0 },
+ { TEXT("ENTIRE"), SW_ENTIRE, 2, 0 },
+ { TEXT("FILES"), SW_FILES, 1, 0 },
+
+#if !defined( MAYN_OS2 )
+ { TEXT("IMAGE"), SW_DOS_IMAGE, 2, 0 },
+#endif
+
+ { TEXT("INUSE"), SW_B_INUSE, 2, 0 },
+ { TEXT("IOCHAN"), SW_IOCHAN, 2, 2 },
+ { TEXT("IRQ"), SW_IRQ, 2, 2 },
+ { TEXT("LABEL"), SW_LABEL, 2, 1 },
+ { TEXT("LEVEL"), SW_LOG_LEVEL, 2, 1 },
+ { TEXT("LISTING"), SW_LIST, 2, 2 },
+ { TEXT("MODIFIED"), SW_MODIFIED, 1, 0 },
+#if !defined( MAYN_OS2 )
+ { TEXT("NAFP"), SW_AFP, 2, 1},
+ { TEXT("NDATES"), SW_NDATE, 2, 1},
+ { TEXT("NONDOS"), SW_NONDOS, 2, 0 },
+#endif
+ { TEXT("NUMTAPE"), SW_NTAPE, 2, 1 },
+ { TEXT("PASSWORD"), SW_PASSWORD, 1, 0 },
+ { TEXT("REDIRECT"), SW_STDIN, 3, 0 },
+ { TEXT("REVISION"), SW_REV, 3, 0 },
+ { TEXT("SUBDIRECTORIES"),SW_SUBDIR, 1, 0 },
+ { TEXT("TAPENAME"), SW_TAPE_NAME, 1, 1 },
+ { TEXT("TRANSFER"), SW_TRANSFER, 2, 0 },
+ { TEXT("XCLUDE"), SW_EXCLUDE, 1, 0 },
+ { TEXT("YES"), SW_YES, 1, 0 }, /* ambiguous, resolve in */
+ { TEXT("YY"), SW_YES, 1, 0 }, /* tbprocsw based on input string */
+ { TEXT("Z"), SW_DEBUG, 1, 1 }
+};
+
+struct SW_TAB_TYPE trestore_switches[] =
+{
+ { TEXT("-FILES"), SW_FILES, 2, 0 },
+ { TEXT("3270"), SW_3270, 1, 0 },
+
+#ifdef MBS
+ { TEXT("ALL"), SW_ALL_VERSIONS, 2, 0 },
+#endif
+
+ { TEXT("AUTOVERIFY"), SW_AUTO_VER, 2, 1 },
+
+#ifdef MBS
+ { TEXT("BDATE"), SW_BKUP_DATE, 1, 2 },
+#endif
+
+ { TEXT("CSR"), SW_CSR, 1, 2 },
+ { TEXT("DATE"), SW_DATE, 1, 2 },
+
+#ifdef MBS
+ { TEXT("DELETED"), SW_DELETED_ONLY, 2, 0 },
+#endif
+
+#if defined( MAYN_OS2 )
+ { TEXT("EDATE"), SW_NDATE, 2, 1 },
+#endif
+ { TEXT("EMPTY"), SW_EMPTY, 2, 0 },
+ { TEXT("FILES"), SW_FILES, 1, 0 },
+ { TEXT("IOCHAN"), SW_IOCHAN, 2, 2 },
+ { TEXT("IRQ"), SW_IRQ, 2, 2 },
+ { TEXT("LEVEL"), SW_LOG_LEVEL, 2, 1 },
+ { TEXT("LISTING"), SW_LIST, 2, 2 },
+
+#if !defined( MAYN_OS2 )
+ { TEXT("NAFP"), SW_AFP, 2, 1},
+#endif
+
+
+#ifdef MBS
+ { TEXT("NDELETED"), SW_NON_DELETED_ONLY, 2, 0 },
+#endif
+
+
+#if !defined( MAYN_OS2 )
+ { TEXT("NONDOS"), SW_NONDOS, 2, 0 },
+#endif
+
+
+ { TEXT("NUMTAPE"), SW_NTAPE, 2, 1 },
+ { TEXT("PROMPT"), SW_P, 1, 0 },
+ { TEXT("Q"), SW_Q, 1, 0 },
+ { TEXT("REDIRECT"), SW_STDIN, 3, 0 },
+ { TEXT("REVISION"), SW_REV, 3, 0 },
+ { TEXT("SUBDIRECTORIES"),SW_SUBDIR, 1, 0 },
+ { TEXT("VOLUME"), SW_SETNO, 1, 1 },
+ { TEXT("XCLUDE"), SW_EXCLUDE, 1, 0 },
+ { TEXT("YES"), SW_YES, 1, 0 },
+ { TEXT("YY"), SW_YES, 1, 0 },
+ { TEXT("Z"), SW_DEBUG, 1, 1 },
+ { TEXT("__BSNUM"), SW_BSNUM, 5, 1 },
+ { TEXT("__TPNUM"), SW_TPNUM, 5, 1 },
+ { TEXT("__TPSEQ"), SW_BSNUM, 5, 1 }
+};
+
+struct SW_TAB_TYPE tdir_switches[] =
+{
+ { TEXT("-FILES"), SW_FILES, 2, 0 },
+ { TEXT("3270"), SW_3270, 1, 0 },
+ { TEXT("CSR"), SW_CSR, 1, 2 },
+ { TEXT("DATE"), SW_DATE, 1, 2 },
+ { TEXT("FILES"), SW_FILES, 1, 0 },
+ { TEXT("IOCHAN"), SW_IOCHAN, 2, 2 },
+ { TEXT("IRQ"), SW_IRQ, 2, 2 },
+ { TEXT("LEVEL"), SW_LOG_LEVEL, 2, 1 },
+ { TEXT("LISTING"), SW_LIST, 2, 2 },
+ { TEXT("NUMTAPE"), SW_NTAPE, 2, 1 },
+ { TEXT("PAGE"), SW_PAUSE, 1, 0 },
+ { TEXT("REDIRECT"), SW_STDIN, 3, 0 },
+ { TEXT("REVISION"), SW_REV, 3, 0 },
+ { TEXT("SUBDIRECTORIES"),SW_SUBDIR, 1, 0 },
+ { TEXT("VOLUME"), SW_SETNO, 1, 1 },
+ { TEXT("WIDE"), SW_WIDE, 1, 0 },
+ { TEXT("XCLUDE"), SW_EXCLUDE, 1, 0 },
+ { TEXT("YES"), SW_YES, 1, 0 },
+ { TEXT("YY"), SW_YES, 1, 0 },
+ { TEXT("Z"), SW_DEBUG, 1, 1 },
+ { TEXT("__BSNUM"), SW_BSNUM, 5, 1 },
+ { TEXT("__TPNUM"), SW_TPNUM, 5, 1 },
+ { TEXT("__TPSEQ"), SW_BSNUM, 5, 1 }
+};
+
+struct SW_TAB_TYPE tverify_switches[] =
+{
+ { TEXT("-FILES"), SW_FILES, 2, 0 },
+ { TEXT("3270"), SW_3270, 1, 0 },
+
+#ifdef MBS
+ { TEXT("ALL"), SW_ALL_VERSIONS, 1, 0 },
+ { TEXT("BDATE"), SW_BKUP_DATE, 1, 2 },
+#endif
+
+ { TEXT("CSR"), SW_CSR, 1, 2 },
+ { TEXT("DATE"), SW_DATE, 1, 2 },
+
+#ifdef MBS
+ { TEXT("DELETED"), SW_DELETED_ONLY, 2, 0 },
+#endif
+
+#if defined( MAYN_OS2 )
+ { TEXT("EDATE"), SW_NDATE, 2, 1 },
+#endif
+ { TEXT("EMPTY"), SW_EMPTY, 2, 0 },
+ { TEXT("FILES"), SW_FILES, 1, 0 },
+ { TEXT("IOCHAN"), SW_IOCHAN, 2, 2 },
+ { TEXT("IRQ"), SW_IRQ, 2, 2 },
+ { TEXT("LEVEL"), SW_LOG_LEVEL, 2, 1 },
+ { TEXT("LISTING"), SW_LIST, 2, 2 },
+
+#if !defined( MAYN_OS2 )
+ { TEXT("NAFP"), SW_AFP, 2, 1},
+#endif
+
+#ifdef MBS
+ { TEXT("NDELETED"), SW_NON_DELETED_ONLY, 2, 0 },
+#endif
+
+ { TEXT("NUMTAPE"), SW_NTAPE, 2, 1 },
+ { TEXT("REDIRECT"), SW_STDIN, 3, 0 },
+ { TEXT("REVISION"), SW_REV, 3, 0 },
+ { TEXT("SUBDIRECTORIES"),SW_SUBDIR, 1, 0 },
+ { TEXT("VOLUME"), SW_SETNO, 1, 1 },
+ { TEXT("XCLUDE"), SW_EXCLUDE, 1, 0 },
+ { TEXT("YES"), SW_YES, 1, 0 },
+ { TEXT("YY"), SW_YES, 1, 0 },
+ { TEXT("Z"), SW_DEBUG, 1, 1 },
+ { TEXT("__BSNUM"), SW_BSNUM, 5, 1 },
+ { TEXT("__TPNUM"), SW_TPNUM, 5, 1 },
+ { TEXT("__TPSEQ"), SW_BSNUM, 5, 1 }
+};
+
+struct SW_TAB_TYPE tension_switches[] =
+{
+ { TEXT("3270"), SW_3270, 1, 0 },
+ { TEXT("CSR"), SW_CSR, 1, 2 },
+ { TEXT("ERASE"), SW_ERASE_TAPE, 1, 0 },
+ { TEXT("FMARK"), SW_FMARK, 2, 0 },
+ { TEXT("IOCHAN"), SW_IOCHAN, 2, 2 },
+ { TEXT("IRQ"), SW_IRQ, 2, 2 },
+ { TEXT("LONG"), SW_LONG, 1, 0 },
+ { TEXT("NUMTAPE"), SW_NTAPE, 2, 1 },
+ { TEXT("REVISION"), SW_REV, 1, 0 },
+ { TEXT("YY"), SW_YES, 1, 0 },
+ { TEXT("Z"), SW_DEBUG, 1, 1 }
+};
+
+
+INT16 GetNumBkuSwitches( )
+{
+ return( sizeof( tbackup_switches ) / sizeof( struct SW_TAB_TYPE ) ) ;
+}
+
+INT16 GetNumRestSwitches( )
+{
+ return( sizeof( trestore_switches ) / sizeof( struct SW_TAB_TYPE ) ) ;
+}
+
+INT16 GetNumVerSwitches( )
+{
+ return( sizeof( tverify_switches ) / sizeof( struct SW_TAB_TYPE ) ) ;
+}
+
+INT16 GetNumDirSwitches( )
+{
+ return( sizeof( tdir_switches ) / sizeof( struct SW_TAB_TYPE ) ) ;
+}
+
+INT16 GetNumTenSwitches( )
+{
+ return( sizeof( tension_switches ) / sizeof( struct SW_TAB_TYPE ) ) ;
+}
+
diff --git a/private/utils/ntbackup/src/tbprocsw.c b/private/utils/ntbackup/src/tbprocsw.c
new file mode 100644
index 000000000..bfae7b31d
--- /dev/null
+++ b/private/utils/ntbackup/src/tbprocsw.c
@@ -0,0 +1,857 @@
+
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: tbprocsw.c
+
+ Description: This file contains code to process the switches
+ in the input stream
+
+
+ $Log: G:\UI\LOGFILES\TBPROCSW.C_V $
+
+ Rev 1.13 17 Jan 1994 16:22:14 MIKEP
+fix unicode warnings
+
+ Rev 1.12 26 Jul 1993 12:25:16 MARINA
+enable c++
+
+ Rev 1.11 01 Nov 1992 16:09:30 DAVEV
+Unicode changes
+
+ Rev 1.10 07 Oct 1992 14:19:06 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.9 07 Oct 1992 14:04:46 DAVEV
+various unicode chgs
+
+ Rev 1.8 04 Oct 1992 19:41:08 DAVEV
+Unicode Awk pass
+
+ Rev 1.7 28 Jul 1992 14:52:40 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.6 08 Jul 1992 15:35:24 STEVEN
+Unicode BE changes
+
+ Rev 1.5 15 May 1992 13:35:44 MIKEP
+nt pass 2
+
+ Rev 1.4 14 May 1992 18:36:38 STEVEN
+40Format changes
+
+ Rev 1.3 31 Mar 1992 11:53:50 CHUCKB
+Don't use /append switch in selection scripts.
+
+ Rev 1.2 20 Mar 1992 12:58:04 CHUCKB
+Fixed processing for all modified, modified dates, and LAD switches.
+
+ Rev 1.1 10 Jan 1992 16:47:06 DAVEV
+16/32 bit port-2nd pass
+
+ Rev 1.0 20 Nov 1991 19:35:44 SYSTEM
+Initial revision.
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+/*
+ Local functions
+*/
+
+static INT16 one_op( CHAR_PTR );
+static INT16 no_ops( CHAR_PTR , CHAR_PTR );
+static INT16 create_target_dir( CHAR_PTR );
+static int comp( VOID_PTR, VOID_PTR );
+
+static INT16 GetBeforeAfterDates( CHAR_PTR sw_op1_ptr,
+ CHAR_PTR sw_op2_ptr,
+ DATE_TIME_PTR after_date_ptr,
+ DATE_TIME_PTR before_date_ptr );
+
+/*
+ Local data
+*/
+
+INT16 debug_error_no;
+
+/**/
+INT16 process_switch(
+
+ CDS_PTR *cfg , /* configuration stucture */
+ DLE_HAND dle_hand , /* Drive list handle */
+ BSD_HAND bsd_hand , /* BSD list */
+ CUR_DEF *cur_def ,
+ SW_TAB_PTR sw_tab , /* switch table */
+ INT16 n_switches , /* number of elements in sw_tab */
+ CHAR_PTR sw_name , /* switch label */
+ CHAR_PTR sw_op1 , /* 1st operand or NULL */
+ CHAR_PTR sw_op2 ) /* 2nd operand or NULL */
+{
+ SW_TAB_PTR sp;
+ DATE_TIME before_date;
+ DATE_TIME after_date;
+ INT16 status = SUCCESS;
+ INT16 itmp;
+ INT16 indx;
+// FILE *fp;
+ CUR_DEF_PTR temp_def;
+ BOOLEAN matched;
+ CHAR path_buf[ 80 ];
+ CHAR path_buf2[ 80 ];
+ INT16 psize;
+ CHAR_PTR fname;
+ BSD_PTR bsd;
+ GENERIC_DLE_PTR dle;
+ static UINT32 tpnum;
+ static UINT16 bsnum;
+ static UINT16 tpseq;
+
+ msassert( sw_tab != NULL );
+ msassert( sw_name != NULL );
+ msassert( cfg != NULL );
+
+ sp = sw_tab;
+
+ for ( itmp = 0; itmp < n_switches; itmp++ ) {
+
+ if ( !strncmp( sw_name, sp[itmp].sw_label, strlen( sw_name ) ) ) {
+
+ if( (INT16)strlen( sw_name ) >= sp[itmp].sw_min_len ) {
+
+ matched = TRUE;
+ break;
+ }
+ }
+ }
+
+ sp = (SW_TAB_PTR)(&sp[itmp]);
+
+ if ( matched != TRUE ) {
+
+ debug_error_no = 1;
+ return( SCR_INVALID_SWITCH );
+ }
+
+ if( sp->sw_num_ops == 0 ) {
+ if( !no_ops( sw_op1, sw_op2 ) ) {
+
+ debug_error_no = 3;
+ return( SCR_TOO_MANY_PARMS );
+
+ }
+ } else if( sp->sw_num_ops == 1 ) {
+ if( !one_op( sw_op2 ) ) {
+ debug_error_no = 4;
+ return( SCR_TOO_MANY_PARMS );
+ }
+ }
+
+ switch( sp->sw_action ) {
+
+ case SW_ERASE_TAPE:
+ CDS_SetEraseFlag( *cfg, ERASE_ON );
+
+ break;
+
+ case SW_FMARK:
+ CDS_SetEraseFlag( *cfg, ERASE_FMARK );
+
+ break;
+
+ case SW_LONG:
+ CDS_SetEraseFlag( *cfg, ERASE_LONG );
+ break;
+
+ case SW_3270:
+ /* Not needed in 3.0 per Dave Krinker */
+ break;
+
+ case SW_MINUS_A :
+ CDS_SetSetArchiveFlag( *cfg, (INT16)FALSE );
+ break;
+
+ case SW_TRANSFER :
+ CDS_SetTransferFlag( *cfg, TRUE );
+ break;
+
+ case SW_AUTO_VER :
+
+ if ( sw_op1 == NULL ) {
+ itmp = 1;
+ } else {
+ if ( !isdigit( sw_op1[0] ) ) {
+ debug_error_no = 30;
+ return( SCR_BAD_SWITCH_FLAG );
+ } else {
+ itmp = (INT16)atoi( sw_op1 );
+ }
+ }
+ CDS_SetAutoVerifyBackup( *cfg, itmp );
+ CDS_SetAutoVerifyRestore( *cfg, itmp );
+
+ break;
+
+ case SW_LIST :
+ if( sw_op1 != NULL ) {
+
+ psize = sizeof (path_buf);
+
+ status = FS_ParsePath( dle_hand, sw_op1, &dle, path_buf, &psize, &fname, &itmp );
+
+ if ( status == SUCCESS ) {
+
+ if ( ( psize == 1 ) && ( strchr( sw_op1, TEXT('\\') ) == NULL ) ) {
+ strcpy( path_buf2, fname );
+ } else {
+ status = FS_MakePath( path_buf2, (INT16)sizeof (path_buf2), dle, path_buf, psize, fname );
+ }
+ }
+
+
+ /**** Commented Out. Unused ****
+
+ if ( status == SUCCESS ) {
+
+ create_target_dir( path_buf2 );
+
+ CDS_SetLogFilePath( *cfg, path_buf2 );
+
+ } else {
+
+ debug_error_no = 6;
+ return( SCR_BAD_LIST_DIR );
+ }
+
+
+ if( (fp=UNI_fopen( CDS_GetLogFilePath( *cfg ), _O_TEXT|_O_APPEND )) == NULL ) {
+ debug_error_no = 6;
+ return( SCR_BAD_LIST_DIR );
+ } else {
+ fclose( fp );
+ }
+
+ ****/
+
+ }
+
+ CDS_SetOutputDest( *cfg, LOG_TO_FILE );
+ CDS_SetLogMode( *cfg, LOG_OVERWRITE );
+
+ if( ( sw_op2 != NULL ) && !strcmpi( sw_op2 , TEXT("a") ) ) { /* user gave append mode */
+ CDS_SetLogMode( *cfg, LOG_APPEND );
+
+ }
+
+ break;
+
+ case SW_LOG_LEVEL :
+ if( sw_op1 == NULL ) {
+
+ debug_error_no = 7;
+ return( SCR_BAD_LOG_LEVEL );
+
+ } else { /* get output level */
+
+ itmp = (INT16)atoi( sw_op1 );
+
+ if ( ( itmp > 0 ) && ( itmp <= 4 ) ) {
+ CDS_SetLogLevel( *cfg, itmp );
+ } else {
+ debug_error_no = 31;
+ return( SCR_BAD_SWITCH_FLAG );
+ }
+
+ }
+ break;
+
+ case SW_AFP :
+ if( sw_op1 == NULL ) {
+ debug_error_no = 9;
+ return( SCR_BAD_SWITCH_FLAG );
+ } else { /* get output level */
+
+ itmp = (INT16)atoi( sw_op1 );
+
+ if ( ( itmp >= 0 ) && ( itmp <= 2 ) ) {
+ CDS_SetAFPSupport( *cfg, itmp );
+ } else {
+ debug_error_no = 10;
+ return( SCR_BAD_SWITCH_FLAG );
+ }
+ }
+
+ case SW_NDATE:
+ if ( sw_op1 == NULL ) {
+ CDS_SetExtendedDateSupport( *cfg, (INT16)TRUE );
+ } else {
+
+ if ( isdigit( sw_op1[0] ) ) {
+ if ( atoi( sw_op1 ) ) {
+ CDS_SetExtendedDateSupport( *cfg, (INT16)TRUE );
+ } else {
+ CDS_SetExtendedDateSupport( *cfg, (INT16)FALSE );
+ }
+ } else {
+ debug_error_no = 32;
+ return( SCR_BAD_SWITCH_FLAG );
+ }
+ }
+
+ break;
+
+ case SW_MINUS_H :
+
+ CDS_SetHiddenFlag( *cfg, (INT16)FALSE );
+
+ break;
+
+ case SW_MINUS_S :
+
+ CDS_SetSpecialFlag( *cfg, (INT16)FALSE );
+
+ break;
+
+ case SW_APPEND :
+
+ // This case should be interpreted by the Windows product for tmenu
+ // compatibility; however, since jobs work differently, this switch
+ // should not be used.
+
+ // CDS_SetAppendFlag( *cfg, TRUE );
+
+ break;
+
+ case SW_ENTIRE :
+ CDS_SetYesFlag( *cfg, YES_FLAG );
+
+ status = tbbuild_def_drives( dle_hand, bsd_hand, TEXT("\0"), (INT16)1, TEXT("*.*"), *cfg, &cur_def );
+ if ( status != SUCCESS ) {
+ return( status );
+ }
+ break;
+
+ case SW_DATE :
+
+ if( ( status = GetBeforeAfterDates( sw_op1, sw_op2, &after_date,
+ &before_date ) ) != SUCCESS ) {
+ return( status );
+ }
+
+ for( temp_def = cur_def; (temp_def != NULL) && (status == SUCCESS);
+ temp_def = temp_def->next_def ) {
+
+ if ( temp_def->cur_fse != NULL ) {
+
+ temp_def->unused = FALSE;
+ status = FSE_SetModDate( temp_def->cur_fse, &after_date, &before_date );
+ }
+
+ }
+ break;
+
+ case SW_ACCESS_DATE:
+
+ if( sw_op1 != NULL ) {
+ /* default date to today */
+ GetCurrentDate( &before_date );
+
+ before_date.year -= 1900;
+
+ if( DU_CalcTargetDateBackwd( &before_date, (INT16)atoi( sw_op1 ) ) ) {
+
+ return SCR_INVALID_SWITCH;
+
+ }
+
+ before_date.year += 1900;
+ before_date.hour = 0;
+ before_date.minute = 0;
+ before_date.second = 0;
+
+ } else {
+
+ return SCR_INVALID_SWITCH;
+
+ }
+
+ for( temp_def = cur_def;
+ (temp_def != NULL) && (status == SUCCESS);
+ temp_def = temp_def->next_def ) {
+
+ if ( temp_def->cur_fse != NULL ) {
+ temp_def->unused = FALSE;
+ status = FSE_SetAccDate( temp_def->cur_fse, &before_date );
+ }
+ }
+
+ if( status != SUCCESS ) {
+ debug_error_no = 13;
+ return( SCR_CANNOT_CREATE_FSE );
+ }
+ break;
+
+ case SW_EMPTY :
+ CDS_SetProcEmptyFlag( *cfg, (INT16)TRUE );
+ break;
+
+ case SW_FILES :
+ itmp = (INT16)( sw_name[0] != TEXT('-') );
+
+ CDS_SetFilesFlag( *cfg, itmp );
+
+ break;
+
+ case SW_DOS_IMAGE:
+ for( temp_def = cur_def; temp_def != NULL;
+ temp_def = temp_def->next_def ) {
+
+ if ( temp_def->cur_fse != NULL ) {
+
+ dle = BSD_GetDLE( temp_def->cur_bsd );
+
+ if( ( DLE_GetDeviceType( dle ) != LOCAL_DOS_DRV ) &&
+ ( DLE_GetDeviceType( dle ) != LOCAL_IMAGE ) ) {
+ debug_error_no = 14;
+ return( SCR_NO_IMAGE_FOR_DRIVE );
+
+ } else {
+
+ DLE_FindByName( dle_hand, DLE_GetDeviceName( dle ), LOCAL_IMAGE, &dle );
+ }
+
+ if ( dle == NULL ) {
+ debug_error_no = 15;
+ return( SCR_NO_IMAGE_FOR_DRIVE );
+
+ } else {
+ BSD_SetDLE( temp_def->cur_bsd, dle );
+ temp_def->unused = FALSE;
+
+ }
+ }
+ }
+ break;
+
+ case SW_B_INUSE :
+ CDS_SetBackupFilesInUse( *cfg, (INT16)TRUE );
+ break;
+
+ case SW_IOCHAN :
+ case SW_CSR :
+ case SW_IRQ:
+ /* do nothing */
+ break;
+
+ case SW_LABEL:
+ if( sw_op1 == NULL ) {
+ debug_error_no = 23;
+ return( SCR_BAD_SET_LABEL );
+ }
+
+ if ( sw_op1[0] == TEXT('?') ) {
+ // CDS_SetBackupSetDescriptor( *cfg, TRUE );
+
+ } else {
+
+ for( temp_def = cur_def; temp_def != NULL;
+ temp_def = temp_def->next_def ) {
+
+ if ( temp_def->cur_fse != NULL ) {
+
+ BSD_SetBackupDescript( temp_def->cur_bsd, (BYTE *)sw_op1,
+ (INT16) strsize( sw_op1 ) );
+ BSD_MarkBsetDescrNotChangable( temp_def->cur_bsd );
+ temp_def->unused = FALSE;
+ }
+ }
+ }
+
+
+ break;
+
+ case SW_TAPE_NAME:
+ if( sw_op1 == NULL ) {
+ debug_error_no = 23;
+ return( SCR_BAD_SET_LABEL );
+ }
+
+ if ( sw_op1[0] == TEXT('?') ) {
+ // CDS_SetPromptTapeName( *cfg, TRUE );
+
+ } else {
+
+ for( temp_def = cur_def; temp_def != NULL;
+ temp_def = temp_def->next_def ) {
+
+ if ( temp_def->cur_fse != NULL ) {
+
+ BSD_SetTapeLabel( temp_def->cur_bsd, (BYTE *)sw_op1,
+ (INT16)strsize( sw_op1 ) );
+ BSD_MarkTapeNameNotChangable( temp_def->cur_bsd );
+ }
+ }
+
+ bsd = BSD_GetFirst( bsd_hand );
+ while( bsd != NULL ) {
+ BSD_SetTapeLabel( bsd, (BYTE *)sw_op1,
+ (INT16)strsize( sw_op1 ) );
+ BSD_MarkTapeNameNotChangable( bsd );
+
+ bsd = BSD_GetNext( bsd );
+ }
+
+ }
+
+ break;
+
+ case SW_BACK_NAME:
+ if( sw_op1 == NULL ) {
+ debug_error_no = 23;
+ return( SCR_BAD_SET_LABEL );
+ }
+
+ if ( sw_op1[0] == TEXT('?') ) {
+ // CDS_SetPromptBackupSetName( *cfg, TRUE );
+
+ } else {
+
+ for( temp_def = cur_def; temp_def != NULL;
+ temp_def = temp_def->next_def ) {
+
+ if ( temp_def->cur_fse != NULL ) {
+
+ BSD_SetBackupLabel( temp_def->cur_bsd, (BYTE *)sw_op1,
+ (INT16)strsize( sw_op1 ) );
+ BSD_MarkBsetNameNotChangable( temp_def->cur_bsd );
+ temp_def->unused = FALSE;
+ }
+ }
+ }
+
+ break;
+
+ case SW_MODIFIED:
+
+ for( temp_def = cur_def; (temp_def != NULL) && (status == SUCCESS);
+ temp_def = temp_def->next_def ) {
+
+ if ( temp_def->cur_fse != NULL ) {
+
+ status = FSE_SetAttribInfo( temp_def->cur_fse, OBJ_MODIFIED_BIT, 0L );
+ temp_def->unused = FALSE;
+ }
+ }
+
+ if( status != SUCCESS ) {
+ debug_error_no = 25;
+ return( SCR_CANNOT_CREATE_FSE );
+ }
+
+ break;
+
+
+ case SW_TPNUM :
+
+ sscanf( sw_op1, TEXT("%lx"), &tpnum );
+
+ for( temp_def = cur_def; temp_def != NULL;
+ temp_def = temp_def->next_def ) {
+
+ if ( temp_def->cur_fse != NULL ) {
+
+ BSD_SetTapePos( temp_def->cur_bsd, tpnum, tpseq, bsnum );
+ BSD_SetFullyCataloged( temp_def->cur_bsd, TRUE );
+ }
+ }
+
+ break;
+ case SW_BSNUM :
+
+ sscanf( sw_op1, TEXT("%x"), &bsnum );
+
+ for( temp_def = cur_def; temp_def != NULL;
+ temp_def = temp_def->next_def ) {
+
+ if ( temp_def->cur_fse != NULL ) {
+
+ BSD_SetTapePos( temp_def->cur_bsd, tpnum, tpseq, bsnum );
+ BSD_SetFullyCataloged( temp_def->cur_bsd, TRUE );
+
+ }
+ }
+ break;
+
+ case SW_TPSEQ :
+
+ sscanf( sw_op1, TEXT("%x"), &tpseq );
+
+ for( temp_def = cur_def; temp_def != NULL;
+ temp_def = temp_def->next_def ) {
+
+ if ( temp_def->cur_fse != NULL ) {
+
+ BSD_SetTapePos( temp_def->cur_bsd, tpnum, tpseq, bsnum );
+ BSD_SetFullyCataloged( temp_def->cur_bsd, TRUE );
+ }
+ }
+
+ break;
+
+ case SW_SETNO:
+
+ for( temp_def = cur_def; temp_def != NULL;
+ temp_def = temp_def->next_def ) {
+
+ if ( temp_def->cur_fse != NULL ) {
+
+ BSD_SetTapePos( temp_def->cur_bsd, (UINT32)-1L, (UINT16)-1, (UINT16)( -atoi( sw_op1 ) ) );
+ }
+ }
+
+ break;
+
+ case SW_NONDOS:
+ /* does nothing */
+ break;
+
+ case SW_PASSWORD :
+ CDS_SetPasswordFlag( *cfg, TRUE );
+
+ break;
+
+ case SW_STDIN : /* read input from stdin, implies yes flag */
+
+ return( SCR_INVALID_SWITCH );
+ break;
+
+ case SW_SUBDIR:
+
+ for( temp_def = cur_def; temp_def != NULL;
+ temp_def = temp_def->next_def ) {
+
+ if ( temp_def->cur_fse != NULL ) {
+
+ FSE_SetIncSubFlag( temp_def->cur_fse, TRUE );
+ temp_def->unused = FALSE;
+ }
+ }
+
+ break;
+
+ case SW_EXCLUDE:
+
+ for( temp_def = cur_def; temp_def != NULL;
+ temp_def = temp_def->next_def ) {
+
+ if ( temp_def->cur_fse != NULL ) {
+
+ FSE_SetOperType( temp_def->cur_fse, EXCLUDE );
+ temp_def->unused = FALSE;
+ }
+ }
+
+ break;
+
+ case SW_YES:
+ if( !strcmp( sw_name, TEXT("YY") ) ) {
+ itmp = YESYES_FLAG;
+ } else {
+ itmp = YES_FLAG;
+ }
+
+ CDS_SetYesFlag( *cfg, itmp );
+
+ break;
+
+ case SW_P :
+ CDS_SetPromptFlag( *cfg, (INT16)TRUE );
+ break;
+
+ case SW_Q :
+ CDS_SetExistFlag( *cfg, (INT16)FALSE );
+ break;
+
+ case SW_WIDE :
+ // CDS_SetDirDisplayFlag( *cfg, CDS_GetDirDisplayFlag( *cfg ) | DIR_WIDE );
+ break;
+
+ case SW_PAUSE :
+ // CDS_SetDirDisplayFlag( *cfg, CDS_GetDirDisplayFlag( *cfg ) | DIR_PAGE );
+ break;
+
+ case SW_DEBUG:
+ if( sw_op1 == NULL ) {
+ itmp = (INT16)0xffff;
+ } else {
+ ( VOID ) sscanf( sw_op1, TEXT("%x"), &itmp );
+ }
+
+ CDS_SetDebugFlag( *cfg, itmp );
+
+ break;
+
+ case SW_NTAPE:
+ /* do nothing */
+/* if( sw_op1 == NULL ) { */
+/* debug_error_no = 28; */
+/* return( SCR_BAD_NUM_TAPE ); */
+/* } */
+/* */
+/* itmp = atoi( sw_op1 ); */
+/* */
+/* if( ( itmp >= 0 ) && ( itmp <= 2 ) ) { */
+/* CDS_SetNumTapeDrives( CDS_GetPerm(), itmp ); */
+/* CDS_SetNumTapeDrives( *cfg, itmp ); */
+/* } else { */
+/* debug_error_no = 29; */
+/* return( SCR_BAD_NUM_TAPE ); */
+/* } */
+ break;
+
+
+ default :
+ msassert( /* proc_sw: bad action */ FALSE );
+ break;
+ } /* end switch */
+ return( SUCCESS );
+
+ indx;
+
+} /* end process_switch */
+
+/**/
+static int comp(
+VOID_PTR s1,
+VOID_PTR s2 )
+{
+ return( strncmp( (LPSTR)s1, ((SW_TAB_PTR)s2)->sw_label, strlen( (LPSTR)s1 ) ) );
+}
+/**/
+/*
+ Check that a switch has no operands specified
+*/
+static INT16 no_ops(
+CHAR_PTR sw_op1,
+CHAR_PTR sw_op2 )
+{
+ if( ( sw_op1 != NULL ) || ( sw_op2 != NULL ) ) {
+ return( FALSE );
+ }
+ return( TRUE );
+}
+/**/
+/*
+ Check that a switch has only one operand specified
+*/
+static INT16 one_op(
+CHAR_PTR sw_op2 )
+{
+ if( sw_op2 != NULL ) {
+ return( FALSE );
+ }
+ return( TRUE );
+}
+/*****************************************************************************
+
+ Name: create_target_dir()
+
+ Description: This function creates a directory path on a DOS drive.
+ If the path is invalid then this function will create the valid
+ portion of the path and return an error.
+
+ Returns: SUCCESS if successful.
+
+*****************************************************************************/
+static INT16 create_target_dir(
+CHAR_PTR path )
+{
+ CHAR_PTR temp_ptr;
+ INT16 ret_val;
+
+ temp_ptr = strchr( path, TEXT('\\') );
+ while ( temp_ptr != NULL ) {
+
+ *temp_ptr = TEXT('\0');
+ ret_val = (INT16)mkdir( path );
+ *temp_ptr = TEXT('\\');
+
+ temp_ptr = strchr( temp_ptr + 1, TEXT('\\') );
+ }
+
+ return( ret_val );
+
+} /* end create_target_dir */
+
+/**/
+static INT16 GetBeforeAfterDates(
+ CHAR_PTR sw_op1_ptr,
+ CHAR_PTR sw_op2_ptr,
+ DATE_TIME_PTR after_date_ptr,
+ DATE_TIME_PTR before_date_ptr )
+{
+ UINT16 status;
+
+ if( ( sw_op1_ptr == NULL ) && ( sw_op2_ptr == NULL ) ) {
+ /* default before and after dates to today */
+ GetCurrentDate( before_date_ptr );
+ *after_date_ptr = *before_date_ptr;
+ } else { /* default after and before as in FSL */
+ after_date_ptr->date_valid = FALSE;
+ before_date_ptr->date_valid = FALSE;
+ }
+
+ /* try to convert what user gave, if anything */
+ if( sw_op1_ptr != NULL ) { /* after date value given */
+ status = tbdpars( sw_op1_ptr, after_date_ptr, DEFAULT_EARLY_MORNING );
+ if( status != 0 ) {
+ after_date_ptr->date_valid = FALSE;
+ debug_error_no = 11;
+ return( SCR_BAD_DATE );
+ }
+ }
+ if( sw_op2_ptr != NULL ) { /* before date value given */
+ status = tbdpars( sw_op2_ptr, before_date_ptr, DEFAULT_LATE_NIGHT );
+ if( status != 0 ) {
+ before_date_ptr->date_valid = FALSE;
+ debug_error_no = 12;
+ return( SCR_BAD_DATE );
+ }
+ }
+ return SUCCESS;
+}
+
+#ifdef MBS
+
+/**/
+static INT16 GetAccessDate(
+ CHAR_PTR sw_op1_ptr,
+ DATE_TIME_PTR access_date_ptr )
+{
+ UINT16 status;
+
+ if( sw_op1_ptr == NULL ) {
+ /* default access date to today */
+ GetCurrentDate( access_date_ptr );
+ } else { /* default access as in FSL */
+ access_date_ptr->date_valid = FALSE;
+ }
+
+ /* try to convert what user gave, if anything */
+ if( sw_op1_ptr != NULL ) { /* after date value given */
+ status = tbdpars( sw_op1_ptr, access_date_ptr );
+ if( status != 0 ) {
+ access_date_ptr->date_valid = FALSE;
+ debug_error_no = 11;
+ return( (INT16) SCR_BAD_DATE );
+ }
+ }
+ return SUCCESS;
+}
+
+#endif
diff --git a/private/utils/ntbackup/src/tbrparse.c b/private/utils/ntbackup/src/tbrparse.c
new file mode 100644
index 000000000..7db1b0f45
--- /dev/null
+++ b/private/utils/ntbackup/src/tbrparse.c
@@ -0,0 +1,882 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: tbrparse.c
+
+ Description: This file contains code to parse a script file for
+ backup, restore, verify, or directory.
+
+ $Log: G:\UI\LOGFILES\TBRPARSE.C_V $
+
+ Rev 1.22 17 Jan 1994 16:18:20 MIKEP
+fix unicode warnings
+
+ Rev 1.21 26 Jul 1993 12:53:02 MARINA
+enable c++
+
+ Rev 1.20 21 Jul 1993 17:12:24 CARLS
+added bsd_ptr parameter to tbrparse function
+
+ Rev 1.19 01 Nov 1992 16:09:48 DAVEV
+Unicode changes
+
+ Rev 1.18 20 Oct 1992 10:13:50 GLENN
+Removed hardcoded APPLICATIONNAME from message boxes.
+
+ Rev 1.17 07 Oct 1992 14:17:32 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.16 04 Oct 1992 19:41:14 DAVEV
+Unicode Awk pass
+
+ Rev 1.15 17 Aug 1992 13:23:52 DAVEV
+MikeP's changes at Microsoft
+
+ Rev 1.14 28 Jul 1992 15:05:04 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.13 08 Jul 1992 15:34:42 STEVEN
+Unicode BE changes
+
+ Rev 1.12 15 May 1992 13:32:04 MIKEP
+nt pass 2
+
+ Rev 1.11 23 Apr 1992 16:25:56 CHUCKB
+Cleaned up unused variables.
+
+ Rev 1.10 23 Apr 1992 16:22:04 CHUCKB
+Parser no longer removes unused BSD's.
+
+ Rev 1.9 14 Apr 1992 11:34:44 CHUCKB
+Fixed selection logging messages.
+
+ Rev 1.8 09 Apr 1992 14:51:16 CHUCKB
+Don't quit if a server is down.
+
+ Rev 1.7 23 Mar 1992 15:42:24 CHUCKB
+Fixed servers found warning.
+
+ Rev 1.6 16 Mar 1992 10:00:16 CHUCKB
+Fixed UAE if sel. file has net drives, but net shell not loaded.
+
+ Rev 1.5 25 Feb 1992 11:34:38 JOHNWT
+handle attach error and serv/map mode
+
+ Rev 1.4 13 Jan 1992 09:30:02 JOHNWT
+fixed includes
+
+ Rev 1.3 10 Jan 1992 16:47:36 DAVEV
+16/32 bit port-2nd pass
+
+ Rev 1.2 12 Dec 1991 11:04:36 JOHNWT
+removed unneeded pwdb calls
+
+ Rev 1.1 04 Dec 1991 15:22:24 MIKEP
+remoce pwxface.h
+
+ Rev 1.0 20 Nov 1991 19:24:30 SYSTEM
+Initial revision.
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+INT16 gb_mode;
+
+extern struct SW_TAB_TYPE tbackup_switches[ ];
+extern struct SW_TAB_TYPE trestore_switches[ ];
+extern struct SW_TAB_TYPE tdir_switches[ ];
+extern struct SW_TAB_TYPE tverify_switches[ ];
+extern struct SW_TAB_TYPE tension_switches[ ];
+
+struct STATE_TAB_TYPE tbsyntab_state_table[ 10 ][ 5 ] = {
+ {
+ { TB_ERROR_EXIT, TB_EXPECT_INC1 /* Input: t_at_sign, State: tb_expect_inc1 */ },
+ { TB_ERROR_EXIT, TB_EXPECT_INC2 /* Input: t_at_sign, State: tb_expect_inc2 */ },
+ { TB_ERROR_EXIT, TB_READY2 /* Input: t_at_sign, State: tb_expect_source */ },
+ { TB_DO_NOTHING, TB_EXPECT_INC1 /* Input: t_at_sign, State: tb_ready1 */ },
+ { TB_DO_NOTHING, TB_EXPECT_INC2 /* Input: t_at_sign, State: tb_ready2 */ }
+ },
+ {
+ { TB_ERROR_EXIT, TB_EXPECT_INC1 /* Input: t_bad_token, State: tb_expect_inc1 */ },
+ { TB_ERROR_EXIT, TB_EXPECT_INC2 /* Input: t_bad_token, State: tb_expect_inc2 */ },
+ { TB_ERROR_EXIT, TB_READY2 /* Input: t_bad_token, State: tb_expect_source */ },
+ { TB_ERROR_EXIT, TB_READY1 /* Input: t_bad_token, State: tb_ready1 */ },
+ { TB_ERROR_EXIT, TB_READY2 /* Input: t_bad_token, State: tb_ready2 */ }
+ },
+ {
+ { TB_ERROR_EXIT, TB_EXPECT_INC1 /* Input: t_early_eof1, State: tb_expect_inc1 */ },
+ { TB_ERROR_EXIT, TB_EXPECT_INC2 /* Input: t_early_eof1, State: tb_expect_inc2 */ },
+ { TB_ERROR_EXIT, TB_READY2 /* Input: t_early_eof1, State: tb_expect_source */ },
+ { TB_ERROR_EXIT, TB_READY1 /* Input: t_early_eof1, State: tb_ready1 */ },
+ { TB_ERROR_EXIT, TB_READY2 /* Input: t_early_eof1, State: tb_ready2 */ }
+ },
+ {
+ { TB_ERROR_EXIT, TB_EXPECT_INC1 /* Input: t_early_eof2, State: tb_expect_inc1 */ },
+ { TB_ERROR_EXIT, TB_EXPECT_INC2 /* Input: t_early_eof2, State: tb_expect_inc2 */ },
+ { TB_ERROR_EXIT, TB_READY2 /* Input: t_early_eof2, State: tb_expect_source */ },
+ { TB_ERROR_EXIT, TB_READY1 /* Input: t_early_eof2, State: tb_ready1 */ },
+ { TB_ERROR_EXIT, TB_READY2 /* Input: t_early_eof2, State: tb_ready2 */ }
+ },
+ {
+ { TB_ERROR_EXIT, TB_EXPECT_INC1 /* Input: t_eof, State: tb_expect_inc1 */ },
+ { TB_ERROR_EXIT, TB_EXPECT_INC2 /* Input: t_eof, State: tb_expect_inc2 */ },
+ { TB_ERROR_EXIT, TB_READY2 /* Input: t_eof, State: tb_expect_source */ },
+ { TB_NORMAL_RETURN, TB_READY1 /* Input: t_eof, State: tb_ready1 */ },
+ { TB_NORMAL_RETURN, TB_READY2 /* Input: t_eof, State: tb_ready2 */ }
+ },
+ {
+ { TB_ERROR_EXIT, TB_EXPECT_INC1 /* Input: t_equals, State: tb_expect_inc1 */ },
+ { TB_ERROR_EXIT, TB_EXPECT_INC2 /* Input: t_equals, State: tb_expect_inc2 */ },
+ { TB_ERROR_EXIT, TB_READY2 /* Input: t_equals, State: tb_expect_source */ },
+ { TB_ERROR_EXIT, TB_READY1 /* Input: t_equals, State: tb_ready1 */ },
+ { TB_DO_NOTHING, TB_EXPECT_SOURCE /* Input: t_equals, State: tb_ready2 */ }
+ },
+ {
+ { TB_PROCESS_INCLUDE, TB_READY1 /* Input: t_filespec, State: tb_expect_inc1 */ },
+ { TB_PROCESS_INCLUDE, TB_READY2 /* Input: t_filespec, State: tb_expect_inc2 */ },
+ { TB_PROCESS_TARGET, TB_READY2 /* Input: t_filespec, State: tb_expect_source */ },
+ { TB_PROCESS_SOURCE, TB_READY1 /* Input: t_filespec, State: tb_ready1 */ },
+ { TB_PROCESS_SOURCE, TB_READY2 /* Input: t_filespec, State: tb_ready2 */ }
+ },
+ {
+ { TB_ERROR_EXIT, TB_READY1 /* Input: t_nondos, State: tb_expect_inc1 */ },
+ { TB_ERROR_EXIT, TB_READY2 /* Input: t_nondos, State: tb_expect_inc2 */ },
+ { TB_ERROR_EXIT, TB_READY2 /* Input: t_nondos, State: tb_expect_source */ },
+ { TB_PROCESS_NONDOS, TB_READY1 /* Input: t_nondos, State: tb_ready1 */ },
+ { TB_PROCESS_NONDOS, TB_READY2 /* Input: t_nondos, State: tb_ready2 */ }
+ },
+ {
+ { TB_PROCESS_SWITCH, TB_EXPECT_INC1 /* Input: t_switch, State: tb_expect_inc1 */ },
+ { TB_PROCESS_SWITCH, TB_EXPECT_INC2 /* Input: t_switch, State: tb_expect_inc2 */ },
+ { TB_PROCESS_SWITCH, TB_READY2 /* Input: t_switch, State: tb_expect_source */ },
+ { TB_PROCESS_SWITCH, TB_READY1 /* Input: t_switch, State: tb_ready1 */ },
+ { TB_PROCESS_SWITCH, TB_READY2 /* Input: t_switch, State: tb_ready2 */ }
+ },
+ {
+ { TB_ERROR_EXIT, TB_READY1 /* Input: t_token_too_long, State: tb_expect_inc1 */ },
+ { TB_ERROR_EXIT, TB_READY2 /* Input: t_token_too_long, State: tb_expect_inc2 */ },
+ { TB_ERROR_EXIT, TB_READY2 /* Input: t_token_too_long, State: tb_expect_source */ },
+ { TB_ERROR_EXIT, TB_READY1 /* Input: t_token_too_long, State: tb_ready1 */ },
+ { TB_ERROR_EXIT, TB_READY2 /* Input: t_token_too_long, State: tb_ready2 */ }
+ }
+};
+
+/*****************************************************************************
+
+ Name: tbrparse()
+
+ Description: This function sets up the parameters for a call to
+ tbparse()
+
+ Returns: error codes
+ listed in scriperr.h
+
+*****************************************************************************/
+INT tbrparse(
+CDS_PTR *cfg,
+DLE_HAND dle_hand,
+BSD_HAND bsd_hand,
+CHAR_PTR src_string,
+INT mode,
+BSD_PTR bsd_ptr )
+{
+ INT16 cmd_indx;
+ INT n_switches;
+ INT init_state;
+ INT err_code;
+ CDS_PTR copy_cfg;
+ SW_TAB_PTR sw_tab;
+
+ copy_cfg = *cfg;
+
+ gb_mode = mode;
+
+ DLE_UpdateList( dle_list, CDS_GetPermBEC() );
+
+ msassert( src_string != NULL );
+
+ /* reset globals and statics for each run */
+
+ cmd_indx = 0;
+
+ switch( mode ) {
+
+ case TARCHIVE :
+ case TBACKUP :
+ sw_tab = &( tbackup_switches[0] );
+ n_switches = GetNumBkuSwitches();
+ init_state = TB_READY1;
+ break;
+
+ case TENSION :
+ sw_tab = &( tension_switches[0] );
+ n_switches = GetNumTenSwitches();
+ init_state = TB_READY1;
+ break;
+
+ case TDIR :
+ sw_tab = &( tdir_switches[0] );
+ n_switches = GetNumDirSwitches();
+ init_state = TB_READY1;
+ break;
+
+ case TRESTORE :
+ sw_tab = &( trestore_switches[0] );
+ n_switches = GetNumRestSwitches();
+ init_state = TB_READY2;
+ break;
+
+ case TVERIFY :
+ sw_tab = &( tverify_switches[0] );
+ n_switches = GetNumVerSwitches();
+ init_state = TB_READY2;
+ break;
+
+ default :
+ msassert( /* tbrparse: bad mode */ FALSE );
+ break;
+ }
+ err_code = tbparse( &copy_cfg, dle_hand, bsd_hand, strgetc, strpushc, src_string, &cmd_indx,
+ sw_tab, n_switches, init_state, bsd_ptr );
+
+ if( err_code != 0 ) {
+ fcloseall( );
+
+ return( err_code );
+ }
+
+ return( 0 );
+
+} /* end tbrparse
+
+/*****************************************************************************
+
+ Name: tbparse()
+
+ Description: This function gets tokesns from the specified input
+ streem and calls other lower level parsers to process Switches
+ and Path names.
+
+ Returns: Error codes: see SCRIPERR.H
+
+ Notes: This function adds to the BSD list.
+
+*****************************************************************************/
+INT tbparse(
+CDS_PTR *cfg,
+DLE_HAND dle_hand, /* I - Head of DLE list needed to access drives */
+BSD_HAND bsd_hand, /* I - Head of BSD list needed to add BSDs */
+/* I - the following are functions used to read from the input streem */
+CHAR ( *inchar )( CHAR_PTR , INT16_PTR ),
+VOID ( *pushchar )( CHAR, CHAR_PTR , INT16_PTR ),
+CHAR_PTR src_ptr, /* I - pointer to input stream */
+INT16_PTR cmd_i, /* I - positon in input stream */
+SW_TAB_PTR sw_tab, /* I - table to use when parsing switches */
+INT n_switches, /* I - number of switches in above table */
+INT init_state, /* I - initial state for parsing */
+BSD_PTR bsd_ptr )
+{
+ INT16 err_code; /* error value to returned */
+ INT16 curr_line; /* line in this source file */
+ INT16 curr_col; /* column in this source file */
+ INT16 lex_state; /* old state of lexical fsm */
+ INT16 syn_old_state; /* old state of syntax fsm */
+ INT16 syn_state; /* new state for syntax fsm */
+ register INT16 syn_input; /* conditioned input for syntax fsm */
+ register INT16 syn_action; /* action to take */
+ INT16 status; /* TRUE if filename valid by tbppars */
+ FILE *fin; /* our input file */
+ INT16 dummy = 0; /* dummy string index for recursive calls */
+ TOKEN_PTR this_token = NULL; /* token built by lexical level */
+ BOOLEAN done = FALSE;
+ INT16 ret_val = SUCCESS;
+ FSYS_HAND fsh = NULL;
+ static CHAR tape_name[ 80 ] = { TEXT('\0') };
+ static CUR_DEF_PTR cur_def = NULL;
+ CUR_DEF_PTR temp_def;
+ CHAR curr_filename[ 13 ];
+ static CHAR_PTR last_fname_ptr = NULL;
+ CHAR_PTR temp_ptr;
+ GENERIC_DLE_PTR dle;
+ static CHAR path[ MAX_TOKEN_LEN ];
+ CHAR_PTR fname;
+ INT16 path_size;
+ BOOLEAN invalid_spec;
+ static INT16 nesting = 0;
+
+ curr_line = 1;
+ curr_col = 1;
+
+ lex_state = IN_WHITESPACE;
+
+ if( init_state != -1 ) {
+ syn_state = init_state;
+ }
+ syn_old_state = syn_state;
+ syn_input = 0;
+
+ msassert( syn_state >= 0 && syn_state <= TBSYNTAB_N_STATES );
+ msassert( inchar != NULL );
+ msassert( pushchar != NULL );
+
+ while( !done ) {
+
+ rlstok( &this_token );
+
+ this_token = nexttok( inchar, pushchar, &lex_state, &curr_line, &curr_col, src_ptr, cmd_i );
+
+ if( this_token == NULL ) {
+ eresprintf( (INT16) RES_OUT_OF_MEMORY );
+ ret_val = SCR_ERROR_PRINTED;
+ break;
+ }
+
+ syn_old_state = syn_state;
+ syn_input = this_token->tok_typ;
+
+ msassert( syn_input >= 0 && syn_input <= TBSYNTAB_N_INPUTS );
+ msassert( syn_old_state >= 0 && syn_old_state <= TBSYNTAB_N_STATES );
+
+ syn_action = tbsyntab_state_table[syn_input][syn_old_state].action;
+ syn_state = tbsyntab_state_table[syn_input][syn_old_state].next_state;
+
+ msassert( syn_state >= 0 && syn_state <= TBSYNTAB_N_STATES );
+
+ switch( syn_action ) {
+
+ case TB_DO_NOTHING :
+ break;
+
+ case TB_ERROR_EXIT :
+ if( nesting > 0 ) {
+ eresprintf( (INT16) RES_SCRIPT_SYNTAX_ERROR, this_token->src_line_no, last_fname_ptr );
+ ret_val = SCR_ERROR_PRINTED;
+ rlstok( &this_token );
+ done = TRUE;
+ } else {
+
+ eresprintf( (INT16) RES_COMMAND_SYNTAX_ERROR );
+ ret_val = SCR_ERROR_PRINTED;
+
+ rlstok( &this_token );
+ done = TRUE;
+ }
+ break;
+
+ case TB_NORMAL_RETURN :
+ rlstok( &this_token );
+ done = TRUE;
+ break;
+
+ case TB_PROCESS_INCLUDE :
+
+ // We're parsing a file; open it and get tokens out.
+
+ fin = UNI_fopen( this_token->tok_spelling, _O_TEXT|_O_RDONLY );
+ if( fin == NULL ) {
+
+ eresprintf( (INT16) RES_SCRIPT_OPEN_ERROR, this_token->tok_spelling );
+ ret_val = SCR_ERROR_PRINTED;
+ rlstok( &this_token );
+ done = TRUE;
+ } else {
+ nesting ++;
+ if( nesting > MAX_NESTING ) {
+ eresprintf( (INT16) RES_SCRIPT_NESTING_ERROR );
+ ret_val = SCR_ERROR_PRINTED;
+ rlstok( &this_token );
+ done = TRUE;
+ break;
+ }
+
+ temp_ptr = strrchr( this_token->tok_spelling, TEXT('\\') );
+ if( temp_ptr == NULL ) {
+ temp_ptr = strrchr( this_token->tok_spelling, TEXT(':') );
+ if( temp_ptr == NULL ) {
+ temp_ptr = this_token->tok_spelling;
+ }
+ else {
+ temp_ptr++;
+ }
+ }
+ else {
+ temp_ptr++;
+ }
+
+ curr_filename[ 0 ] = TEXT('\0');
+ strncpy( curr_filename, temp_ptr, 12 );
+ curr_filename[ 12 ] = TEXT('\0');
+
+ temp_ptr = last_fname_ptr;
+ last_fname_ptr = curr_filename;
+
+ err_code = tbparse( cfg, dle_hand, bsd_hand, filgetc, filpushc, ( CHAR_PTR )fin,
+ &dummy, sw_tab, n_switches, init_state, bsd_ptr );
+ if( err_code ) {
+ ret_val = err_code;
+ done = TRUE;
+ } else {
+ last_fname_ptr = temp_ptr;
+ }
+
+ fclose( fin );
+ nesting --;
+ }
+ break;
+
+ case TB_PROCESS_NONDOS : // work on a line or part of a line
+ case TB_PROCESS_SOURCE : // of a script file
+
+ for ( temp_def = cur_def; temp_def != NULL; ) {
+
+ if( temp_def->cur_fse != NULL ) {
+ if( temp_def->unused ) {
+ BSD_AddFSE( temp_def->cur_bsd, temp_def->cur_fse );
+ BSD_RemoveFSE( temp_def->cur_fse );
+ } else {
+ BSD_AddFSE( temp_def->cur_bsd, temp_def->cur_fse );
+ }
+
+ if( tape_name[0] != TEXT('\0') ) {
+ BSD_SetTapeLabel( temp_def->cur_bsd, (BYTE_PTR)tape_name,
+ (INT16) strsize( tape_name ) );
+ BSD_MarkTapeNameNotChangable( temp_def->cur_bsd );
+ }
+ }
+ cur_def = temp_def;
+ temp_def = temp_def->next_def;
+ free( cur_def );
+ }
+ cur_def = NULL;
+
+ invalid_spec = FALSE;
+
+ path_size = MAX_TOKEN_LEN;
+
+ status = FS_ParsePath( dle_hand, this_token->tok_spelling, &dle,
+ path, &path_size, &fname, &dummy );
+
+ // if we are about to attach/use a server and we are not in
+ // server/volume mode, skip it
+
+ if ( dle && ( ( status == FS_ATTACH_TO_PARENT ) ||
+ ( ( ( DLE_GetDeviceType ( dle ) == NOVELL_DRV ) ||
+ ( DLE_GetDeviceType ( dle ) == NOVELL_AFP_DRV ) ) &&
+ ( DLE_GetParent ( dle ) != NULL ) ) ) &&
+ ( !gfServers ) ) {
+
+ CHAR szAppName[50] ;
+ CHAR szError[255];
+
+ // If the user is watching, tell him what's going on
+
+ RSM_StringCopy( IDS_APPNAME, szAppName, sizeof ( szAppName ) ) ;
+ RSM_Sprintf( szError, ID(IDS_SERVERSFOUND), szAppName ) ;
+
+ WM_MsgBox ( ID( IDS_NETWORKERRORCAPTION ),
+ szError,
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+
+ // Log the error
+
+ lresprintf( (INT16) LOGGING_FILE, (INT16) LOG_START, FALSE );
+ lprintf( (INT16) LOGGING_FILE, szError );
+ lresprintf( (INT16) LOGGING_FILE, (INT16) LOG_END );
+
+ break;
+ }
+
+ if( status == FS_ATTACH_TO_PARENT ) {
+
+ err_code = UI_AttachDrive( &fsh, dle, FALSE );
+
+ if( err_code ) {
+ ret_val = err_code;
+ done = TRUE;
+ break;
+ }
+
+ path_size = MAX_TOKEN_LEN;
+ status = FS_ParsePath( dle_hand, this_token->tok_spelling, &dle,
+ path, &path_size, &fname, &dummy );
+ }
+
+ if( status == FS_DEFAULT_SPECIFIED ) {
+
+ status = tbbuild_def_drives( dle_hand, bsd_hand, path, path_size,
+ fname, *cfg, &cur_def );
+
+ if( status != SUCCESS ) {
+ ret_val = OUT_OF_MEMORY;
+ done = TRUE;
+ }
+ break;
+
+ } else if( status != SUCCESS ) {
+
+ CHAR szFormat [ MAX_UI_RESOURCE_SIZE ];
+ CHAR szErrMsg [ MAX_UI_RESOURCE_SIZE ];
+
+ // log the error;
+ // put a message on the screen IFF a user is there
+
+ RSM_StringCopy( RES_INVALID_SOURCE, szFormat, MAX_UI_RESOURCE_SIZE );
+ lresprintf( (INT16) LOGGING_FILE, (INT16) LOG_START, FALSE );
+ lprintf( (INT16) LOGGING_FILE, szFormat, this_token->tok_spelling );
+ lresprintf( (INT16) LOGGING_FILE, (INT16) LOG_END );
+
+ sprintf( szErrMsg, szFormat, this_token->tok_spelling );
+
+ WM_MsgBox( ID( IDS_MSGTITLE_ERROR ), szErrMsg,
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+
+ rlstok( &this_token );
+ invalid_spec = TRUE;
+
+ } else if( !DLE_DriveWriteable( dle ) && ( gb_mode == TARCHIVE ) ) {
+
+ eresprintf( (INT16) RES_REMOTE_DENIED_READ, DLE_GetDeviceName( dle ) );
+ ret_val = FAILURE;
+ rlstok( &this_token );
+ done = TRUE;
+
+ }
+
+ if( !done ) {
+
+ cur_def = (CUR_DEF_PTR)calloc( 1, sizeof( CUR_DEF ) );
+ if( cur_def == NULL ) {
+
+ ret_val = OUT_OF_MEMORY;
+ done = TRUE;
+
+ } else {
+
+ cur_def->unused = TRUE;
+
+ if( !invalid_spec ) {
+
+ /* if a bsd_ptr was passed in, use it */
+ if( bsd_ptr ) {
+ cur_def->cur_bsd = bsd_ptr ;
+ } else {
+ cur_def->cur_bsd = BSD_FindByDLE( bsd_hand, dle );
+ }
+
+ if( cur_def->cur_bsd == NULL ) {
+
+ status = BSD_Add( bsd_hand, &(cur_def->cur_bsd), BEC_CloneConfig( CDS_GetPermBEC()),
+ NULL, dle, (UINT32) -1L, (UINT16) -1, (INT16) -1, thw_list, NULL );
+ }
+
+ cur_def->unused = FALSE;
+
+ if( status == SUCCESS ) {
+ status = BSD_CreatFSE( &(cur_def->cur_fse), (INT16) INCLUDE, (BYTE_PTR)path, path_size,
+ (BYTE_PTR)fname, (INT16) strsize( fname ),
+ (BOOLEAN) USE_WILD_CARD, (BOOLEAN) FALSE );
+ }
+
+ if( status != SUCCESS ) {
+ eresprintf( (INT16) RES_OUT_OF_MEMORY );
+ ret_val = SCR_ERROR_PRINTED;
+ rlstok( &this_token );
+
+ done = TRUE;
+ }
+ }
+ }
+ } /* endif parsed OK */
+
+ break;
+
+ case TB_PROCESS_TARGET :
+
+ msassert( cur_def != NULL );
+
+ if( cur_def->cur_fse != NULL ) {
+
+ path_size = MAX_TOKEN_LEN;
+ status = FS_ParsePath( dle_hand, this_token->tok_spelling, &dle,
+ path, &path_size, &fname, &dummy );
+
+ if( status == FS_ATTACH_TO_PARENT ) {
+
+ err_code = UI_AttachDrive( &fsh, dle, FALSE );
+
+ if( err_code ) {
+ ret_val = err_code;
+ done = TRUE;
+ break;
+ }
+
+ path_size = MAX_TOKEN_LEN;
+ status = FS_ParsePath( dle_hand, this_token->tok_spelling, &dle,
+ path, &path_size, &fname, &dummy );
+ }
+
+ if( status == FS_DEFAULT_SPECIFIED ) {
+ status = tbbuild_def_drives( dle_hand, bsd_hand, path, path_size,
+ fname, *cfg, &cur_def );
+
+ if( status != SUCCESS ) {
+ ret_val = OUT_OF_MEMORY;
+ done = TRUE;
+ }
+ break;
+
+ } else if( status != SUCCESS ) {
+ eresprintf( (INT16) RES_INVALID_TARGET, this_token->tok_spelling );
+ ret_val = SCR_ERROR_PRINTED;
+ rlstok( &this_token );
+ invalid_spec = TRUE;
+ done = TRUE;
+
+ } else if( !DLE_DriveWriteable( dle ) && ( gb_mode == TRESTORE ) ) {
+
+ eresprintf( (INT16) RES_REMOTE_DENIED_READ, DLE_GetDeviceName( dle ) );
+ rlstok( &this_token );
+ done = TRUE;
+ invalid_spec = TRUE;
+ }
+
+ if( (status == SUCCESS) && !done ) {
+ if( strcmp( fname, (CHAR_PTR)FSE_GetFname( cur_def->cur_fse ) ) ) { /* fname mismatch */
+ if( fname[0] != TEXT('\0') ) { /* because user gave filename */
+
+ eresprintf( (INT16) RES_FILE_RENAME_ERROR, FSE_GetFname( cur_def->cur_fse ), fname );
+ ret_val = SCR_ERROR_PRINTED;
+ rlstok( &this_token );
+ done = TRUE;
+ break;
+ }
+ }
+
+ msassert( cur_def != NULL );
+
+ if( status != SUCCESS ) {
+
+ eresprintf( (INT16) RES_OUT_OF_MEMORY );
+ ret_val = SCR_ERROR_PRINTED;
+ done = TRUE;
+ break;
+ }
+ }
+ }
+ break;
+
+ case TB_PROCESS_SWITCH :
+
+ status = SUCCESS;
+
+ if( ( cur_def != NULL ) &&
+ ( !cur_def->unused ) ) {
+
+ status = process_switch( cfg, dle_hand, bsd_hand, cur_def, sw_tab, (INT16) n_switches,
+ this_token->tok_spelling, this_token->op_ptrs[0], this_token->op_ptrs[1] );
+ if( status != 0 ) {
+
+ eresprintf( (INT16) RES_INVALID_PARAMETER,this_token->tok_spelling );
+ ret_val = SCR_ERROR_PRINTED;
+ rlstok( &this_token );
+ done = TRUE;
+
+ } else {
+ if( BSD_IsTapeNameChangable( cur_def->cur_bsd ) == FALSE ) {
+ strncpy( tape_name, (CHAR_PTR)BSD_GetTapeLabel( cur_def->cur_bsd ), 79 );
+ tape_name[ 79 ] = TEXT('\0');
+ }
+ }
+ }
+ break;
+
+ default :
+ msassert( /* parse: invalid action */ FALSE );
+ break;
+ } /* end switch */
+
+ if( fsh != NULL ) {
+ FS_DetachDLE( fsh );
+ fsh = NULL;
+
+ /* Add code to logout of Dynamically Logged-in Servers */
+
+ if ( DLE_GetDeviceType( dle ) == NOVELL_SERVER_ONLY ) {
+ if ( DLE_ServerLoggedIn( dle ) == DYNAMIC_LOGIN ) {
+ DLE_LogoutDevice( dle );
+ }
+ }
+ }
+
+
+ } /* end while */
+
+ /* flush all switch BSDs */
+
+ if( nesting == 0 ) {
+ for( temp_def = cur_def; temp_def != NULL; ) {
+
+ if( temp_def->cur_fse != NULL ) {
+ BSD_AddFSE( temp_def->cur_bsd, temp_def->cur_fse );
+
+ if( tape_name[0] != TEXT('\0') ) {
+ BSD_SetTapeLabel( temp_def->cur_bsd, (BYTE *)tape_name,
+ (INT16) strsize( tape_name ) );
+ BSD_MarkTapeNameNotChangable( temp_def->cur_bsd );
+ }
+ }
+
+ cur_def = temp_def;
+ temp_def = temp_def->next_def;
+ free( cur_def );
+ }
+ cur_def = NULL;
+ tape_name[ 0 ] = TEXT('\0');
+ }
+
+ return( ret_val );
+
+} /* end tbparse */
+
+/**/
+/*
+ Carefully dispose of a token and its operands
+*/
+VOID rlstok(
+TOKEN_PTR *tok_ptr )
+{
+ if( *tok_ptr != NULL )
+ {
+ rlsmem( &( ( *tok_ptr )->op_ptrs[ 0 ] ) );
+ rlsmem( &( ( *tok_ptr )->op_ptrs[ 1 ] ) );
+ rlsmem( ( CHAR_PTR * ) tok_ptr );
+ }
+ return;
+
+} /* end rlstok */
+
+/*
+ Carefully free memory
+*/
+VOID rlsmem(
+CHAR_PTR *mem_ptr )
+{
+ if( *mem_ptr != NULL )
+ {
+ free( *mem_ptr );
+ *mem_ptr = NULL;
+ }
+ return;
+
+} /* end rlsmem */
+
+/*****************************************************************************
+
+ Name: tbbuild_def_drives()
+
+ Description: This routine checks to see which drives are marked as
+ default drives for backing up. For those drives we then create
+ the "*.*" /s FSL to the drive element.
+
+ Returns: error codes or SUCCESS
+
+*****************************************************************************/
+/* begin declaration */
+INT16 tbbuild_def_drives(
+DLE_HAND dle_hand,
+BSD_HAND bsd_hand,
+CHAR_PTR path,
+INT16 path_size,
+CHAR_PTR fspec,
+CDS_PTR cfg,
+CUR_DEF_PTR *cur_def )
+/* $end$ declaration */
+{
+ GENERIC_DLE_PTR dle = NULL;
+ CHAR device_name[ 20 ];
+ INT16 dev_number = 0;
+ CUR_DEF_PTR temp_def = NULL;
+ CUR_DEF_PTR prev_def = NULL;
+ INT16 status;
+ BOOLEAN done = FALSE;
+ CHAR_PTR cds_dev_name;
+ BOOLEAN bsd_created = FALSE;
+
+ if( *cur_def != NULL ) {
+ prev_def = *cur_def;
+ while( prev_def->next_def != NULL ) {
+ prev_def = prev_def->next_def;
+ }
+ }
+
+ while( !done ) {
+
+ cds_dev_name = CDS_GetDefaultDrive( cfg, dev_number++ );
+
+ if( cds_dev_name != NULL ) {
+
+ strcpy( device_name, cds_dev_name );
+ strcat( device_name, TEXT(":") );
+ if( !strcmp( device_name, TEXT(":") ) ) {
+ done = TRUE;
+ break;
+ }
+ DLE_FindByName( dle_hand, device_name, (INT16) -1, &dle );
+
+ } else {
+ if( !bsd_created ) {
+ dle = DLE_GetDefaultDrive( dle_hand );
+ } else {
+ break;
+ }
+ }
+
+ if( dle != NULL ) {
+
+ bsd_created = TRUE;
+
+ temp_def = ( CUR_DEF_PTR )calloc( 1, sizeof( CUR_DEF ) );
+ if( temp_def == NULL ) {
+ return( OUT_OF_MEMORY );
+ }
+
+ temp_def->unused = FALSE;
+
+ temp_def->cur_bsd = BSD_FindByDLE( bsd_hand, dle );
+
+ if( temp_def->cur_bsd == NULL ) {
+
+ if( cfg == NULL ) {
+
+ return( OUT_OF_MEMORY );
+
+ }
+
+ status = BSD_Add( bsd_hand, &(temp_def->cur_bsd), BEC_CloneConfig( CDS_GetPermBEC()),
+ NULL, dle, (UINT32) -1L, (UINT16) -1, (INT16) -1, thw_list, NULL );
+ }
+
+ if( status == SUCCESS ) {
+ status = BSD_CreatFSE( &( temp_def->cur_fse ), (INT16) INCLUDE, (BYTE_PTR)path,
+ path_size, (BYTE_PTR)fspec, (UINT16)strsize(fspec),
+ (BOOLEAN) USE_WILD_CARD, (BOOLEAN) TRUE );
+ }
+
+ if( *cur_def == NULL ) {
+ *cur_def = temp_def;
+ prev_def = temp_def;
+ } else {
+ prev_def->next_def = temp_def;
+ prev_def = temp_def;
+ }
+ }
+ }
+
+ return SUCCESS;
+
+}
diff --git a/private/utils/ntbackup/src/tchgdir.c b/private/utils/ntbackup/src/tchgdir.c
new file mode 100644
index 000000000..ef7bf0b99
--- /dev/null
+++ b/private/utils/ntbackup/src/tchgdir.c
@@ -0,0 +1,213 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tchgdir.c
+
+ Description: This file contains code to Change the current directory.
+
+ $Log: M:/LOGFILES/TCHGDIR.C_V $
+
+ Rev 1.13 24 Nov 1993 14:46:40 BARRY
+Unicode fixes
+
+ Rev 1.12 19 Feb 1993 09:21:42 STEVEN
+fix some bugs
+
+ Rev 1.11 11 Nov 1992 10:10:50 GREGG
+Unicodeized literals.
+
+ Rev 1.10 10 Nov 1992 08:19:44 STEVEN
+removed path and name from dblk now use full_name_ptr
+
+ Rev 1.9 06 Oct 1992 13:25:24 DAVEV
+Unicode strlen verification
+
+ Rev 1.8 24 Sep 1992 13:42:16 BARRY
+Changes for huge file name support.
+
+ Rev 1.7 17 Aug 1992 15:39:24 STEVEN
+fix warnings
+
+ Rev 1.6 09 Jun 1992 15:05:14 BURT
+Sync up with NT stuff
+
+ Rev 1.4 21 May 1992 13:50:52 STEVEN
+more long path stuff
+
+ Rev 1.3 04 May 1992 09:32:58 LORIB
+Changes for variable length paths.
+
+ Rev 1.2 28 Feb 1992 13:03:30 STEVEN
+step one for varible length paths
+
+ Rev 1.1 13 Feb 1992 11:29:14 STEVEN
+fix DOS-> NTFS
+
+ Rev 1.0 17 Jan 1992 17:50:04 STEVEN
+Initial revision.
+
+**/
+/* begin include list */
+#include <windows.h>
+#include <malloc.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "ntfsdblk.h"
+#include "ntfs_fs.h"
+#include "msassert.h"
+/* $end$ include list */
+/**/
+/**
+
+ Name: NTFS_ChangeDir()
+
+ Description: This function changes directories into the directory
+ pointed to by path.
+
+ Modified: 1/10/1992 12:45:35
+
+ Returns: Error codes:
+ SUCCESS
+ OUT_OF_MEMORY
+
+ Notes:
+
+**/
+INT16 NTFS_ChangeDir(
+FSYS_HAND fsh, /* I - file system to changing directories on */
+CHAR_PTR path, /* I - describes the path of the new directory */
+INT16 psize ) /* I - specifies the length of the path */
+{
+ INT16 ret_val = SUCCESS;
+ CHAR_PTR new_path ;
+ NTFS_FSYS_RESERVED_PTR nt_fsh ;
+ int i, cch ;
+
+ msassert( fsh->attached_dle !=NULL ) ;
+
+ nt_fsh = (NTFS_FSYS_RESERVED_PTR)( fsh->reserved.ptr ) ;
+ while( nt_fsh->work_buf_in_use )
+ ; /* wait on semaphore */
+
+ nt_fsh->work_buf_in_use = sizeof (CHAR) ;
+
+ if ( nt_fsh->work_buf_size < (UINT16)psize + 10 ) {
+
+ //??UNICODE?? should the following be psize + 100*sizeof (CHAR)??
+
+ nt_fsh->work_buf_size = (UINT16)(psize + 100) ;
+ nt_fsh->work_buf = realloc( nt_fsh->work_buf, nt_fsh->work_buf_size ) ;
+ }
+
+ if ( nt_fsh->work_buf != NULL ) {
+ new_path = nt_fsh->work_buf ;
+ } else {
+ // Probably want to release the semaphore.
+ nt_fsh->work_buf_in_use = 0 ;
+ return OUT_OF_MEMORY ;
+ }
+ /* copy path replacing '\0' with '\\' (don't put backslash at end) */
+
+ new_path[0] = TEXT('\\');
+ for ( i = 0, cch = psize / sizeof (CHAR) - 1; i< cch; i++ ) {
+
+ if ( path[i] == TEXT('\0') ) {
+ new_path[i+1] = TEXT('\\') ;
+ } else {
+ new_path[i+1] = path[i] ;
+ }
+ }
+
+ new_path[i+1] = TEXT('\0');
+ ret_val = FS_SavePath( fsh, (UINT8_PTR)new_path, (INT16)(psize + sizeof( CHAR ) ) );
+ nt_fsh->work_buf_in_use = 0 ;
+ return( ret_val ) ;
+}
+/**/
+/**
+
+ Name: NTFS_UpDir()
+
+ Description: This function removes the last directory name from the
+ current directory path field of the "fsh"
+
+
+ Modified: 1/10/1992 12:47:23
+
+ Returns: Error codes:
+ FS_AT_ROOT
+ SUCCESS
+
+ Notes:
+
+**/
+INT16 NTFS_UpDir( fsh )
+FSYS_HAND fsh ; /* I - file system to change directories in */
+{
+ GENERIC_DLE_PTR dle ;
+ INT16 ret_val=SUCCESS;
+ CHAR_PTR p ;
+
+ msassert( fsh != NULL );
+ msassert( fsh->cur_dir != NULL );
+
+ dle = fsh->attached_dle ;
+ msassert( dle != NULL ) ;
+
+ p = strrchr( fsh->cur_dir, TEXT('\\') ) ;
+
+ if ( fsh->cur_dir[1] == TEXT('\0') ) {
+ ret_val = FS_AT_ROOT ; /* example \ */
+
+ } else if ( p == fsh->cur_dir ) {
+ *(p+1) = TEXT('\0') ; /* example \FRED */
+ } else {
+ *p = TEXT('\0') ; /* example \FRED\SUE */
+ }
+
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Name: NTFS_ChangeIntoDDB()
+
+ Description: This function changes into the directory specified in the
+ DBLK
+
+ Modified: 1/10/1992 12:48:54
+
+ Returns: OUT_OF_MEMORY
+ SUCCESS
+
+ Notes:
+
+**/
+INT16 NTFS_ChangeIntoDDB( fsh, dblk )
+FSYS_HAND fsh ; /* I - File system handle */
+DBLK_PTR dblk ; /* I - contains directory path to change into */
+{
+ NTFS_DBLK_PTR ddblk;
+ INT16 ret_val ;
+
+ msassert( fsh->attached_dle != NULL );
+ msassert( dblk->blk_type == DDB_ID ) ;
+
+ ddblk = (NTFS_DBLK_PTR)dblk ;
+
+ ret_val = FS_SavePath( fsh, (UINT8_PTR)TEXT("\\"), 2*sizeof (CHAR) );
+
+ if ( ret_val == SUCCESS ) {
+ ret_val = FS_AppendPath( fsh,
+ (UINT8_PTR)ddblk->full_name_ptr->name,
+ (INT16)(strsize( ddblk->full_name_ptr->name ) ) ) ;
+ }
+
+ return ret_val ;
+}
diff --git a/private/utils/ntbackup/src/tclose.c b/private/utils/ntbackup/src/tclose.c
new file mode 100644
index 000000000..b289922c4
--- /dev/null
+++ b/private/utils/ntbackup/src/tclose.c
@@ -0,0 +1,569 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tclose.c
+
+ Description: This file closes an opened object.
+
+
+ $Log: N:/LOGFILES/TCLOSE.C_V $
+
+ Rev 1.29.1.1 01 Jul 1994 17:40:02 STEVEN
+dont set modify tiem on verify
+
+ Rev 1.29.1.0 15 Mar 1994 22:48:40 STEVEN
+fix registry bugs
+
+ Rev 1.29 28 Jan 1994 20:58:00 BARRY
+fix MoveFileEx() does not support mac syntax
+
+ Rev 1.28 03 Jan 1994 18:44:28 BARRY
+Reset dates/times on all operations, not just restore
+
+ Rev 1.27 26 Jul 1993 17:04:34 STEVEN
+fixe restore active file with registry
+
+ Rev 1.26 29 Jun 1993 20:17:14 BARRY
+Upon registry restore, return FS_RESTORED_ACTIVE
+
+ Rev 1.25 29 Jun 1993 20:15:28 BARRY
+Don't destroy ret_val with FS_RESTORED_ACTIVE
+
+ Rev 1.24 02 Jun 1993 14:41:56 BARRY
+Link fixes
+
+ Rev 1.23 13 May 1993 13:32:42 BARRY
+Return FS_RESTORED_ACTIVE when we overwrite an active file.
+
+ Rev 1.22 24 Feb 1993 15:37:06 BARRY
+Fixed restore of active files when write errors occur.
+
+ Rev 1.21 19 Feb 1993 13:36:30 BARRY
+Fixed restoration of attributes and clear of modified bit for dirs.
+
+ Rev 1.20 15 Jan 1993 13:18:42 BARRY
+added support for new error messages and backup priviladge
+
+ Rev 1.19 25 Nov 1992 16:42:20 BARRY
+Fix MakeTempFile and restore over active files.
+
+ Rev 1.18 17 Nov 1992 22:17:32 DAVEV
+unicode fixes
+
+ Rev 1.17 17 Nov 1992 16:13:10 BARRY
+Fixes for linked files.
+
+ Rev 1.16 11 Nov 1992 09:54:16 GREGG
+Unicodeized literals.
+
+ Rev 1.15 10 Nov 1992 08:19:50 STEVEN
+removed path and name from dblk now use full_name_ptr
+
+ Rev 1.14 21 Oct 1992 19:42:00 BARRY
+Upon close, we enqueue information about linked files.
+
+ Rev 1.13 20 Oct 1992 14:22:30 STEVEN
+temp names should not have .TMP extension
+
+ Rev 1.11 07 Oct 1992 14:23:14 STEVEN
+added CloseDir function
+
+ Rev 1.10 21 Sep 1992 13:50:40 BARRY
+Turn off archive bit when backing up directories.
+
+ Rev 1.9 12 Aug 1992 17:48:08 STEVEN
+fixed bugs at microsoft
+
+ Rev 1.8 25 Jun 1992 11:27:14 STEVEN
+logical instead of bitwize NOT for clearing attribute
+
+ Rev 1.7 09 Jun 1992 15:35:32 BURT
+Sync with NT stuff
+
+ Rev 1.6 27 May 1992 18:50:28 STEVEN
+registry api is not implemented
+
+ Rev 1.5 22 May 1992 16:05:54 STEVEN
+
+
+ Rev 1.4 21 May 1992 13:51:04 STEVEN
+more long path stuff
+
+ Rev 1.3 04 May 1992 09:26:52 LORIB
+Fixes for structure member names.
+
+ Rev 1.2 28 Feb 1992 13:03:38 STEVEN
+step one for varible length paths
+
+ Rev 1.1 12 Feb 1992 10:44:38 STEVEN
+remove warning
+
+ Rev 1.0 07 Feb 1992 16:41:14 STEVEN
+Initial revision.
+
+**/
+#include <stdio.h>
+#include <windows.h>
+#include <string.h>
+#include <malloc.h>
+
+#include "stdtypes.h"
+#include "stdio.h"
+#include "std_err.h"
+#include "beconfig.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "fsys_err.h"
+#include "ntfsdblk.h"
+#include "ntfs_fs.h"
+
+static INT16 NTFS_CloseFile( FILE_HAND hand ) ;
+static INT16 NTFS_CloseDir( FILE_HAND hand ) ;
+
+/**/
+
+/**
+
+ Name: NTFS_CloseObj()
+
+ Description: This funciton closes an object.
+
+ Modified: 2/7/1992 10:55:12
+
+ Returns: Error Codes:
+ FS_OBJECT_NOT_OPENED
+ SUCCESS
+
+ Notes:
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 NTFS_CloseObj( hand )
+FILE_HAND hand ; /* I - handle of object to close */
+{
+ INT16 ret_val = SUCCESS;
+ NTFS_DBLK_PTR ddblk ;
+ FSYS_HAND fsh ;
+ NTFS_OBJ_HAND_PTR nt_hand = hand->obj_hand.ptr;
+
+ fsh = hand->fsh ;
+
+ ddblk = (NTFS_DBLK_PTR)(hand->dblk) ;
+
+ switch (hand->dblk->blk_type) {
+
+ case FDB_ID:
+
+ ret_val = NTFS_CloseFile( hand ) ;
+
+ break ;
+
+ case DDB_ID:
+ ret_val = NTFS_CloseDir( hand ) ;
+
+ break ;
+
+ case VCB_ID :
+ break ;
+
+ default:
+ ret_val = FS_OBJECT_NOT_OPENED;
+ }
+
+ /*
+ * Here we want to be sure that if we should have seen an ACL for
+ * this object, we report an error if there was no security present.
+ */
+ if ( (hand->dblk->blk_type == FDB_ID) || (hand->dblk->blk_type == DDB_ID) )
+ {
+ if ( (ret_val == SUCCESS) &&
+ (nt_hand->sawSecurity == FALSE) &&
+ (strcmp( hand->fsh->attached_dle->info.ntfs->fs_name,
+ TEXT("NTFS")) == 0) ) {
+
+ ret_val = FS_NO_SECURITY;
+ }
+ }
+
+ if( hand->fsh->file_hand == hand ) {
+ hand->fsh->hand_in_use = FALSE ;
+ memset( hand, 0, sizeof( FILE_HAND_STRUCT ) ) ;
+ } else {
+ free( hand ) ;
+ }
+
+ return ret_val ;
+}
+
+/**/
+/**
+
+ Name: NTFS_CloseFile()
+
+ Description: This function closes an opened file.
+
+ Modified: 2/7/1992 10:55:48
+
+ Returns: Error codes
+ FS_OBJECT_NOT_OPENED
+ SUCCESS
+
+**/
+static INT16 NTFS_CloseFile( hand )
+FILE_HAND hand ; /* I - handle to be closed */
+{
+ NTFS_OBJ_HAND_PTR nt_hand ;
+ CHAR_PTR path;
+ CHAR_PTR old_reg_name ;
+ NTFS_DBLK_PTR ddblk ;
+ INT16 ret_val = SUCCESS ;
+ FSYS_HAND fsh ;
+ DWORD attrib ;
+ LOCAL_NTFS_DRV_DLE_INFO_PTR ntfs_inf = hand->fsh->attached_dle->info.ntfs ;
+ CHAR_PTR logfile ;
+
+ fsh = hand->fsh ;
+
+ ddblk = (NTFS_DBLK_PTR)(hand->dblk) ;
+
+ nt_hand = (NTFS_OBJ_HAND_PTR)( hand->obj_hand.ptr ) ;
+
+ if ( ddblk->b.f.linkOnly )
+ {
+ if ( hand->mode == FS_WRITE )
+ {
+ ret_val = NTFS_LinkFileToFDB( hand );
+ }
+ else
+ {
+ CloseHandle( nt_hand->fhand );
+ ret_val = SUCCESS;
+ }
+ free( nt_hand->linkBuffer );
+ nt_hand->linkBuffer = NULL;
+ nt_hand->linkBufferSize = 0;
+ nt_hand->linkNameLen = 0;
+
+ return ret_val;
+ }
+
+ if ( nt_hand->context != NULL ) {
+ BackupRead( nt_hand->fhand,
+ NULL,
+ 0,
+ NULL,
+ TRUE,
+ FALSE,
+ &nt_hand->context ) ;
+ }
+
+ if ( hand->mode == FS_WRITE ) {
+ SetFileTime( nt_hand->fhand,
+ &(ddblk->dta.create_time),
+ &(ddblk->dta.access_time),
+ &(ddblk->dta.modify_time) ) ;
+
+ } else {
+ if ( fsh->attached_dle->feature_bits & DLE_FEAT_ACCESS_DATE ) {
+
+ SetFileTime( nt_hand->fhand,
+ NULL,
+ &(ddblk->dta.access_time),
+ NULL ) ;
+ }
+ }
+ if( !CloseHandle( nt_hand->fhand ) ) {
+ ret_val = FS_OBJECT_NOT_OPENED ;
+ }
+
+ if ( nt_hand->temp_file != NULL ) {
+
+ if ( hand->mode != FS_WRITE ) {
+
+ DeleteFile( nt_hand->temp_file ) ;
+
+ } else {
+
+ if ( NTFS_SetupWorkPath( fsh,
+ fsh->cur_dir,
+ ddblk->full_name_ptr->name,
+ &path ) == SUCCESS) {
+
+ /* if its the SYSTEM file save path for later processing */
+
+ if ( nt_hand->registry_file &&
+ !stricmp( ddblk->full_name_ptr->name, TEXT("SYSTEM") ) ) {
+
+ if ( ntfs_inf->LastSysRegPath != NULL ) {
+ free( ntfs_inf->LastSysRegPath ) ;
+ free( ntfs_inf->LastSysRegPathNew ) ;
+
+ }
+
+ ntfs_inf->LastSysRegPath =
+ malloc( strsize( path ) ) ;
+
+ if ( ntfs_inf->LastSysRegPath ) {
+
+ strcpy( ntfs_inf->LastSysRegPath, path ) ;
+ } else {
+
+ return OUT_OF_MEMORY ;
+ }
+
+
+ ntfs_inf->LastSysRegPathNew =
+ malloc( strsize( nt_hand->temp_file ) ) ;
+
+ if ( ntfs_inf->LastSysRegPathNew ) {
+
+ strcpy( ntfs_inf->LastSysRegPathNew,
+ nt_hand->temp_file ) ;
+ } else {
+
+ free( ntfs_inf->LastSysRegPath ) ;
+ return OUT_OF_MEMORY ;
+ }
+
+
+ ret_val = FS_RESTORED_ACTIVE;
+
+ } else if ( nt_hand->registry_file ) {
+
+ old_reg_name = NTFS_MakeTempName( path, TEXT("REG") ) ;
+
+ if ( old_reg_name != NULL ) {
+
+ NTFS_SaveTempName( path, old_reg_name) ;
+
+ ret_val = REG_RestoreRegistryFile( hand->fsh->attached_dle,
+ path,
+ nt_hand->temp_file,
+ old_reg_name ) ;
+
+ if ( fsh->attached_dle->info.ntfs->mac_name_syntax ) {
+ MoveFileEx( old_reg_name+4, /* Existing file */
+ NULL, /* New (original) */
+ MOVEFILE_REPLACE_EXISTING |
+ MOVEFILE_DELAY_UNTIL_REBOOT );
+ } else {
+ MoveFileEx( old_reg_name, /* Existing file */
+ NULL, /* New (original) */
+ MOVEFILE_REPLACE_EXISTING |
+ MOVEFILE_DELAY_UNTIL_REBOOT );
+ }
+
+ free( old_reg_name ) ;
+
+ logfile = malloc( strsize( nt_hand->temp_file) + strsize( TEXT(".LOG" ) ) ) ;
+ if ( logfile != NULL ) {
+
+ strcpy( logfile, nt_hand->temp_file ) ;
+ strcat( logfile, TEXT(".LOG" ) ) ;
+
+ if ( fsh->attached_dle->info.ntfs->mac_name_syntax ) {
+ MoveFileEx( logfile+4,
+ NULL, /* New (original) */
+ MOVEFILE_REPLACE_EXISTING |
+ MOVEFILE_DELAY_UNTIL_REBOOT );
+ } else {
+ MoveFileEx( logfile,
+ NULL, /* New (original) */
+ MOVEFILE_REPLACE_EXISTING |
+ MOVEFILE_DELAY_UNTIL_REBOOT );
+ }
+
+ free( logfile ) ;
+ }
+
+
+ if ( ret_val == SUCCESS ) {
+ ret_val = FS_RESTORED_ACTIVE;
+ } else {
+ ret_val = FS_ACCESS_DENIED ;
+ }
+ } else {
+ ret_val = OUT_OF_MEMORY ;
+
+ }
+
+ } else {
+
+ if ( nt_hand->writeError == TRUE ) {
+
+ /*
+ * We had a problem writing to the temp file,
+ * so let's not replace the original with
+ * trash (or an empty file).
+ */
+ DeleteFile( nt_hand->temp_file ) ;
+ ret_val = FS_ACCESS_DENIED;
+
+ } else {
+
+ BOOLEAN stat;
+
+ if ( fsh->attached_dle->info.ntfs->mac_name_syntax ) {
+ stat = MoveFileEx( nt_hand->temp_file+4, /* Existing file */
+ path+4, /* New (original) */
+ MOVEFILE_REPLACE_EXISTING |
+ MOVEFILE_DELAY_UNTIL_REBOOT );
+ } else {
+ stat = MoveFileEx( nt_hand->temp_file, /* Existing file */
+ path, /* New (original) */
+ MOVEFILE_REPLACE_EXISTING |
+ MOVEFILE_DELAY_UNTIL_REBOOT );
+ }
+
+ if ( stat ) {
+ ret_val = FS_RESTORED_ACTIVE;
+ } else {
+ ret_val = FS_ACCESS_DENIED; /* Really best? */
+ }
+ }
+ }
+ NTFS_ReleaseWorkPath( fsh ) ;
+ }
+ }
+ free( nt_hand->temp_file ) ;
+ nt_hand->temp_file = NULL ;
+ }
+
+ if ( (ret_val == SUCCESS) || (ret_val == FS_RESTORED_ACTIVE) ) {
+
+ if ( (hand->mode == FS_WRITE) || ((hand->mode == FS_READ) && (ddblk->dta.os_attr & 0x20)) ) {
+
+ if ( (hand->mode == FS_WRITE) || BEC_GetSetArchiveFlag( fsh->cfg ) ) {
+
+ if ( NTFS_SetupWorkPath( fsh, fsh->cur_dir,
+ ddblk->full_name_ptr->name, &path ) != SUCCESS) {
+
+ return OUT_OF_MEMORY ;
+ }
+
+ attrib = ddblk->dta.os_attr ;
+ if ( hand->mode != FS_WRITE ) {
+ attrib = ddblk->dta.os_attr & (~FILE_ATTRIBUTE_ARCHIVE ) ;
+ }
+ if ( attrib == 0 ) {
+ SetFileAttributes( path, FILE_ATTRIBUTE_NORMAL );
+ } else {
+ SetFileAttributes( path, attrib );
+ }
+
+ NTFS_ReleaseWorkPath( fsh ) ;
+ }
+
+ }
+ }
+
+ if ( (hand->mode == FS_READ) && (ddblk->b.f.linkCount > 1) )
+ {
+ NTFS_LINK_Q_ELEM_PTR linkElem;
+
+ linkElem = NTFS_SearchLinkQueue( fsh,
+ ddblk->b.f.idHi,
+ ddblk->b.f.idLo );
+ if ( linkElem == NULL )
+ {
+ /* Add this object to the queue as the original. */
+
+ NTFS_EnqueueLinkInfo( fsh,
+ ddblk->b.f.idHi,
+ ddblk->b.f.idLo,
+ fsh->cur_dir,
+ ddblk->full_name_ptr->name );
+ }
+ else
+ {
+ /*
+ * If anyone was interested, here we could keep track
+ * of how many we links we have hit for this file.
+ */
+ }
+ }
+
+ return ret_val;
+}
+/**/
+/**
+
+ Name: NTFS_CloseDir()
+
+ Description: This function closes an opened directory.
+
+ Modified: 19-Feb-93
+
+ Returns: Error codes
+ FS_OBJECT_NOT_OPENED
+ SUCCESS
+
+**/
+static INT16 NTFS_CloseDir( hand )
+FILE_HAND hand ; /* I - handle to be closed */
+{
+ NTFS_OBJ_HAND_PTR nt_hand = hand->obj_hand.ptr;
+ NTFS_DBLK_PTR ddblk = (NTFS_DBLK_PTR)(hand->dblk);
+ INT16 ret_val = SUCCESS;
+ FSYS_HAND fsh = hand->fsh;
+
+ if ( nt_hand->context != NULL )
+ {
+ BackupRead( nt_hand->fhand,
+ NULL,
+ 0,
+ NULL,
+ TRUE,
+ FALSE,
+ &nt_hand->context ) ;
+ }
+
+ SetFileTime( nt_hand->fhand,
+ &(ddblk->dta.create_time),
+ &(ddblk->dta.access_time),
+ &(ddblk->dta.modify_time) ) ;
+
+ if ( !CloseHandle( nt_hand->fhand ) )
+ {
+ ret_val = FS_OBJECT_NOT_OPENED ;
+ }
+ else if ( (hand->mode == FS_WRITE) ||
+ ((hand->mode == FS_READ) &&
+ (ddblk->dta.os_attr & ~FILE_ATTRIBUTE_ARCHIVE ) &&
+ BEC_GetSetArchiveFlag( fsh->cfg )) )
+ {
+ CHAR_PTR path;
+
+ /*
+ * We will only get in here if we are restoring the dir OR
+ * we were backing it up, it had the modified bit set, and
+ * we're supposed to turn off the modified bit.
+ */
+
+ if ( NTFS_SetupWorkPath( fsh, fsh->cur_dir, NULL, &path ) != SUCCESS)
+ {
+ ret_val = OUT_OF_MEMORY;
+ }
+ else
+ {
+ DWORD attrib = ddblk->dta.os_attr;
+
+ if ( hand->mode != FS_WRITE )
+ {
+ attrib &= ~FILE_ATTRIBUTE_ARCHIVE;
+ }
+ if ( attrib == 0 ) {
+ SetFileAttributes( path, FILE_ATTRIBUTE_NORMAL );
+ } else {
+ SetFileAttributes( path, attrib );
+ }
+ NTFS_ReleaseWorkPath( fsh );
+ }
+ }
+ return ret_val;
+}
+
+
diff --git a/private/utils/ntbackup/src/tcomplet.c b/private/utils/ntbackup/src/tcomplet.c
new file mode 100644
index 000000000..480442658
--- /dev/null
+++ b/private/utils/ntbackup/src/tcomplet.c
@@ -0,0 +1,260 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tcomplet.c
+
+
+ Description: This file contains code to read the path and add it to
+ the DBLK.
+
+ $Log: M:/LOGFILES/TCOMPLET.C_V $
+
+ Rev 1.10 15 Jan 1994 19:23:24 BARRY
+Call SetupOSPathOrName with BYTE_PTRs instead of CHAR_PTRs
+
+ Rev 1.9 24 Nov 1993 14:46:40 BARRY
+Unicode fixes
+
+ Rev 1.8 11 Nov 1992 22:49:20 STEVEN
+This is Gregg checking files in for Steve. I don't know what he did!
+
+ Rev 1.7 10 Nov 1992 08:20:46 STEVEN
+removed path and name from dblk now use full_name_ptr
+
+ Rev 1.6 21 Oct 1992 19:42:24 BARRY
+Fixed warnings.
+
+ Rev 1.5 16 Oct 1992 16:51:10 STEVEN
+fix streams to UINT64
+
+ Rev 1.4 07 Oct 1992 18:02:26 BARRY
+Set lengths correctly when reading from streams.
+
+ Rev 1.3 24 Sep 1992 13:42:50 BARRY
+Changes for huge file name support.
+
+ Rev 1.2 04 Jun 1992 15:36:32 BURT
+
+ Rev 1.1 22 May 1992 16:05:34 STEVEN
+
+
+ Rev 1.0 21 May 1992 13:49:48 STEVEN
+Initial revision.
+
+**/
+#include <windows.h>
+#include <malloc.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "msassert.h"
+#include "fsys.h"
+#include "ntfsdblk.h"
+#include "ntfs_fs.h"
+#include "fsys_prv.h"
+
+
+static INT16 SetupDDB( FSYS_HAND fsh,
+ NTFS_DBLK_PTR ddblk ) ;
+
+static INT16 SetupFDB( FSYS_HAND fsh,
+ NTFS_DBLK_PTR ddblk ) ;
+
+/**/
+/**
+
+ Name: NTFS_IsBlkComplete( )
+
+ Description: This function returns TRUE if the path is complete
+ inside the DBLK.
+
+ Modified: 5/18/1992 10:27:34
+
+ Returns: TRUE if complete
+ FALSE if path is not complete in DBLK.
+
+**/
+BOOLEAN NTFS_IsBlkComplete( FSYS_HAND fsh, DBLK_PTR dblk )
+{
+ NTFS_DBLK_PTR ddblk = (NTFS_DBLK_PTR)dblk;
+ BOOLEAN ret;
+
+ (VOID)fsh ;
+
+ switch ( ddblk->blk_type )
+ {
+ case DDB_ID:
+ case FDB_ID:
+ ret = ddblk->name_complete;
+ break;
+
+ default:
+ ret = TRUE;
+ break;
+ }
+ return ret;
+}
+
+/**/
+/**
+
+ Name: NTFS_CompleteBlk()
+
+ Description: This function accepts data as a stream and sets up
+ the path inside the DBLK based off of this stream.
+
+ Modified: 17-Sep-92
+
+ Returns: SUCCESS
+ OUT_OF_MEMORY
+
+**/
+INT16 NTFS_CompleteBlk( FSYS_HAND fsh,
+ DBLK_PTR dblk,
+ BYTE_PTR buffer,
+ UINT16 *size,
+ STREAM_INFO *s_info )
+{
+ INT16 ret_val = SUCCESS;
+ NTFS_DBLK_PTR ddblk = (NTFS_DBLK_PTR)dblk;
+ BYTE_PTR stream_data;
+ STREAM_INFO_PTR stream_info;
+
+ msassert( ddblk->name_complete == FALSE );
+
+ ret_val = FS_FillBufferWithStream( fsh, dblk, buffer, size, s_info );
+
+ if ( ret_val == FS_STREAM_COMPLETE )
+ {
+ /* buffer has been filled */
+ /* lets set up the buffers */
+
+ FS_GetStreamInfo( fsh, dblk, &stream_info, &stream_data ) ;
+
+ if ( FS_GetStrmSizeHi( stream_info ) != 0 )
+ {
+ ret_val = OUT_OF_MEMORY;
+ }
+ else
+ {
+ ret_val = FS_SetupOSPathOrNameInDBLK( fsh,
+ dblk,
+ (BYTE_PTR)stream_data,
+ (INT16)FS_GetStrmSizeLo( stream_info ) ) ;
+
+ if ( ret_val != SUCCESS ) {
+ return ret_val ;
+ }
+
+ switch( dblk->blk_type )
+ {
+ case DDB_ID:
+ ret_val = SetupDDB( fsh, ddblk ) ;
+ break;
+
+ case FDB_ID:
+ ret_val = SetupFDB( fsh, ddblk ) ;
+ break;
+ }
+ }
+ }
+ return ret_val;
+}
+
+
+/**/
+/**
+
+ Name: SetupDDB()
+
+ Description: Once the stream has been completely read, this function
+ sets it up the path in the DBLK.
+
+ Modified: 23-Sep-92
+
+ Returns: SUCCESS
+ OUT_OF_MEMORY
+
+**/
+static INT16 SetupDDB( FSYS_HAND fsh,
+ NTFS_DBLK_PTR ddblk )
+{
+ FS_NAME_Q_ELEM_PTR path_q_elem ;
+ DBLK_PTR dblk ;
+ INT16 psize ;
+
+ dblk = (DBLK_PTR)ddblk ;
+
+ psize = dblk->com.os_name->name_size ;
+
+ path_q_elem = FS_AllocPathOrName( fsh, psize ) ;
+
+ if ( path_q_elem == NULL ) {
+ return OUT_OF_MEMORY ;
+
+ }
+
+
+ ddblk->full_name_ptr = path_q_elem ;
+ memcpy( ddblk->full_name_ptr->name,
+ dblk->com.os_name->name,
+ psize ) ;
+
+
+ NTFS_FixPath( ddblk->full_name_ptr->name,
+ &psize,
+ fsh->attached_dle->info.ntfs->fname_leng );
+
+ ddblk->full_name_ptr->name_size = strsize( ddblk->full_name_ptr->name );
+ ddblk->name_complete = TRUE ;
+
+ return SUCCESS ;
+}
+
+
+/**/
+/**
+
+ Name: SetupFDB()
+
+ Description: Once the stream has been completely read, this function
+ sets it up the file name in the DBLK.
+
+ Modified: 23-Sep-92
+
+ Returns: SUCCESS
+ OUT_OF_MEMORY
+
+**/
+static INT16 SetupFDB( FSYS_HAND fsh,
+ NTFS_DBLK_PTR ddblk )
+{
+ FS_NAME_Q_ELEM_PTR name_q_elem ;
+ DBLK_PTR dblk ;
+
+ dblk = (DBLK_PTR)ddblk ;
+
+ name_q_elem = FS_AllocPathOrName( fsh, dblk->com.os_name->name_size ) ;
+
+ if ( ( name_q_elem == NULL ) ) {
+ return OUT_OF_MEMORY ;
+
+ }
+
+ ddblk->full_name_ptr = name_q_elem ;
+ memcpy( ddblk->full_name_ptr->name,
+ dblk->com.os_name->name,
+ dblk->com.os_name->name_size ) ;
+
+// NTFS_FixFname( ddblk->full_name_ptr->name,
+// (UINT16)fsh->attached_dle->info.ntfs->fname_leng ) ;
+
+ ddblk->full_name_ptr->name_size = strsize( ddblk->full_name_ptr->name ) ;
+
+ ddblk->name_complete = TRUE ;
+
+ return SUCCESS;
+}
diff --git a/private/utils/ntbackup/src/tcreate.c b/private/utils/ntbackup/src/tcreate.c
new file mode 100644
index 000000000..12da86283
--- /dev/null
+++ b/private/utils/ntbackup/src/tcreate.c
@@ -0,0 +1,508 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tcreate.c
+
+ Description: This file contains code to create a file or directory
+ path.
+
+
+ $Log: N:/LOGFILES/TCREATE.C_V $
+
+ Rev 1.34.1.1 16 Jun 1994 15:37:04 STEVEN
+do not set attrib in craete doit in close
+
+ Rev 1.34.1.0 15 Mar 1994 22:48:44 STEVEN
+fix registry bugs
+
+ Rev 1.34 01 Feb 1994 15:22:12 BARRY
+fix default security
+
+ Rev 1.33 14 Jan 1994 15:35:50 STEVEN
+do not create with posix switch
+
+ Rev 1.32 30 Nov 1993 16:16:04 BARRY
+Added call NTFS_SaveTempName for actively-restored files
+
+ Rev 1.31 24 Nov 1993 14:46:38 BARRY
+Unicode fixes
+
+ Rev 1.30 24 Aug 1993 19:47:48 STEVEN
+fix too_long bugs
+
+ Rev 1.29 04 Aug 1993 18:56:54 BARRY
+Use access macro.
+
+ Rev 1.28 26 Jul 1993 17:06:40 STEVEN
+fixe restore active file with registry
+
+ Rev 1.27 29 Jun 1993 16:19:56 BARRY
+Skip registry file if config doesn't say to restore them.
+
+ Rev 1.26 23 Jun 1993 11:10:08 BARRY
+Don't assume NT will give us valid errors on CreateDirectory.
+
+ Rev 1.25 19 Jun 1993 15:54:02 STEVEN
+need to set the attribute when creating the file
+
+ Rev 1.24 12 Jun 1993 11:56:00 BARRY
+Check only for sharing violation before creating temp files.
+
+ Rev 1.23 09 Jun 1993 10:40:18 BARRY
+Forgot to assign default security to directories as well.
+
+ Rev 1.22 09 Jun 1993 10:31:38 BARRY
+Use the default security descriptor from the DLE (allocated and inited at
+attach time) to deny all access to a file. Any ACLs that come later will
+override this default. Prevents ACL restore errors from leaving previously
+secured items vulnerable.
+
+ Rev 1.21 01 Jun 1993 16:20:16 STEVEN
+fix posix bugs
+
+ Rev 1.20 15 Mar 1993 15:11:24 BARRY
+Return better error codes.
+
+ Rev 1.19 09 Feb 1993 17:52:02 BARRY
+Fixed restore over active files.
+
+ Rev 1.18 01 Feb 1993 19:46:24 STEVEN
+bug fixes
+
+ Rev 1.17 07 Dec 1992 14:16:28 STEVEN
+updates from msoft
+
+ Rev 1.16 25 Nov 1992 16:42:16 BARRY
+Fix MakeTempFile and restore over active files.
+
+ Rev 1.15 11 Nov 1992 09:54:08 GREGG
+Unicodeized literals.
+
+ Rev 1.14 10 Nov 1992 08:19:52 STEVEN
+removed path and name from dblk now use full_name_ptr
+
+ Rev 1.13 29 Oct 1992 16:51:08 BARRY
+Do nothing for linked files.
+
+ Rev 1.12 20 Oct 1992 14:22:34 STEVEN
+temp names should not have .TMP extension
+
+ Rev 1.10 07 Oct 1992 15:54:50 DAVEV
+unicode strlen verification
+
+ Rev 1.9 23 Sep 1992 15:06:06 BARRY
+Changes for huge file names.
+
+ Rev 1.8 18 Sep 1992 14:13:38 BARRY
+Added suport for restore over existing files.
+
+ Rev 1.7 16 Sep 1992 08:54:36 STEVEN
+fix restore to redirected dir
+
+ Rev 1.5 09 Jun 1992 15:37:16 BURT
+Sync with NT stuff fix Dir exist bug
+
+ Rev 1.4 22 May 1992 16:05:48 STEVEN
+
+
+ Rev 1.3 21 May 1992 13:49:20 STEVEN
+more long path support
+
+ Rev 1.2 04 May 1992 09:29:32 LORIB
+Changes for variable length paths.
+
+ Rev 1.1 28 Feb 1992 13:03:40 STEVEN
+step one for varible length paths
+
+ Rev 1.0 10 Feb 1992 16:27:08 STEVEN
+Initial revision.
+
+**/
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "fsys_err.h"
+#include "ntfsdblk.h"
+#include "ntfs_fs.h"
+#include "dle_str.h"
+#include "msassert.h"
+
+static INT16 NTFS_CreateFile( FSYS_HAND fsh, NTFS_DBLK_PTR ddblk ) ;
+static INT16 NTFS_CreateDir( FSYS_HAND fsh, NTFS_DBLK_PTR ddblk ) ;
+
+static BOOLEAN TempFileName( CHAR *template );
+#define TEMP_NAME_LEN 8
+#define TEMP_NAME_SIZE (TEMP_NAME_LEN + 2) /* BACKSLASH and terminator */
+#define MAX_ATTEMPTS 65535
+
+/**/
+/**
+
+ Name: NTFS_CreateObj()
+
+ Description: This funciton determines whether the object is a
+ file or directory. It then calls the approprate static routine
+ to create the object.
+
+ Modified: 2/10/1992 15:49:17
+
+ Returns: Error Codes:
+ OUT_OF_MEMORY
+ FS_DLE_NOT_ATTACHED
+ FS_ACCESS_DENIED
+ FS_OUT_OF_SPACE
+ FS_BAD_DBLK
+ SUCCESS
+
+ Notes: This function will return FS_BAD_DBLK if an IDB is
+ passed in as the object.
+
+**/
+INT16 NTFS_CreateObj( fsh, dblk )
+FSYS_HAND fsh ; /* I - File system to create object on */
+DBLK_PTR dblk ; /* I - Describes object to create */
+{
+ GENERIC_DLE_PTR dle ;
+ INT16 ret_val ;
+ NTFS_DBLK_PTR ddblk ;
+
+ ddblk = (NTFS_DBLK_PTR) dblk;
+
+ msassert( dblk != NULL );
+
+ dle = fsh->attached_dle ;
+
+ msassert( dle != NULL ) ;
+
+ switch( ddblk->blk_type ){
+
+ case DDB_ID :
+
+ ret_val = NTFS_CreateDir( fsh, ddblk ) ;
+ break ;
+
+ case FDB_ID :
+ if ( ddblk->b.f.linkOnly ) {
+ /* Do nothing for linked files -- all handled at close */
+ ret_val = SUCCESS;
+ } else {
+ ret_val = NTFS_CreateFile( fsh, ddblk ) ;
+ }
+ break ;
+
+ default :
+
+ ret_val = FS_INCOMPATIBLE_OBJECT ;
+ }
+
+ if( ret_val == FS_ACCESS_DENIED ) {
+ /* check for disk full */
+ }
+
+ return ret_val;
+}
+/**/
+/**
+
+ Name: NTFS_CreateFile()
+
+ Description: This function makes a NTFS call to create a file. If the
+ call fails, we try to remove all attributes for the specified file
+ and try to create again.
+
+
+ Modified: 2/10/1992 15:50:44
+
+ Returns: Error codes:
+ FS_ACCESS_DENIED
+
+ Notes:
+
+**/
+static INT16 NTFS_CreateFile( FSYS_HAND fsh,
+ NTFS_DBLK_PTR ddblk )
+{
+ CHAR_PTR path ;
+ INT16 ret_val ;
+ INT posix_flag = 0 ;
+ SECURITY_ATTRIBUTES satr ;
+ SECURITY_ATTRIBUTES *satr_ptr = NULL ;
+
+ if ( fsh->attached_dle->info.ntfs->sd ) {
+ satr.nLength = sizeof(SECURITY_ATTRIBUTES);
+ satr.lpSecurityDescriptor = fsh->attached_dle->info.ntfs->sd ;
+ satr.bInheritHandle = FALSE ;
+ satr_ptr = &satr ;
+ }
+
+
+ ddblk->b.f.hand_registry = FALSE ;
+ ddblk->b.f.hand_temp_name = NULL ;
+
+
+ if ( NTFS_SetupWorkPath( fsh, fsh->cur_dir, ddblk->full_name_ptr->name, &path ) != SUCCESS )
+ {
+ return OUT_OF_MEMORY ;
+ }
+
+ if ( ddblk->b.f.PosixFile ) {
+ posix_flag = FILE_FLAG_POSIX_SEMANTICS ;
+ }
+
+ posix_flag = FALSE ; // Because the posix/win32 solution is not complete.
+ // we will backup both files but will restore them
+ // as one file.
+ // If the user wants a specific file he can select
+ // by itself and restore it to a seperate path.
+
+ ddblk->b.f.handle = CreateFile( path,
+ GENERIC_WRITE | GENERIC_READ | ACCESS_SYSTEM_SECURITY | WRITE_DAC | WRITE_OWNER,
+ FILE_SHARE_WRITE | FILE_SHARE_READ,
+ satr_ptr,
+ CREATE_ALWAYS,
+ FILE_FLAG_BACKUP_SEMANTICS | posix_flag,
+ NULL ) ;
+
+ ret_val = NTFS_TranslateBackupError( GetLastError() );
+
+ if ( (ddblk->b.f.handle == INVALID_HANDLE_VALUE) &&
+ (ret_val == FS_ACCESS_DENIED) ) {
+
+ SetFileAttributes( path, FILE_ATTRIBUTE_NORMAL ) ;
+
+
+ ddblk->b.f.handle = CreateFile( path,
+ GENERIC_WRITE | GENERIC_READ | ACCESS_SYSTEM_SECURITY | WRITE_DAC | WRITE_OWNER,
+ FILE_SHARE_WRITE | FILE_SHARE_READ,
+ satr_ptr,
+ CREATE_ALWAYS,
+ FILE_FLAG_BACKUP_SEMANTICS | posix_flag,
+ NULL ) ;
+
+ ret_val = NTFS_TranslateBackupError( GetLastError() );
+
+ }
+
+ if ( (ddblk->b.f.handle == INVALID_HANDLE_VALUE) &&
+ (ret_val == FS_ACCESS_DENIED) ) {
+
+ ddblk->b.f.handle = CreateFile( path,
+ GENERIC_WRITE | GENERIC_READ | WRITE_DAC | WRITE_OWNER,
+ FILE_SHARE_WRITE | FILE_SHARE_READ,
+ satr_ptr,
+ CREATE_ALWAYS,
+ FILE_FLAG_BACKUP_SEMANTICS | posix_flag,
+ NULL ) ;
+
+ ret_val = NTFS_TranslateBackupError( GetLastError() );
+ }
+
+ if ( ddblk->b.f.handle != INVALID_HANDLE_VALUE ) {
+ ret_val = SUCCESS ;
+
+ } else {
+ DWORD error = GetLastError();
+
+ ret_val = NTFS_TranslateBackupError( error );
+
+ /* Check the error for active file */
+ if ( ( error == ERROR_SHARING_VIOLATION ) ||
+ ( error == ERROR_USER_MAPPED_FILE ) ){
+ CHAR *tempName = NULL;
+
+ if ( REG_IsRegistryFile( fsh->attached_dle, path ) ) {
+
+ if ( BEC_GetProcSpecialFiles( fsh->cfg ) )
+ {
+ ddblk->b.f.hand_registry = TRUE ;
+ tempName = NTFS_MakeTempName( path, TEXT("REG") ) ;
+ }
+ else
+ {
+ ret_val = FS_SKIP_OBJECT;
+ }
+
+ } else {
+
+ tempName = NTFS_MakeTempName( path, TEXT("USE") ) ;
+ }
+
+ if ( tempName != NULL ) {
+
+
+ ddblk->b.f.handle = CreateFile( tempName,
+ GENERIC_WRITE | GENERIC_READ | ACCESS_SYSTEM_SECURITY | WRITE_DAC | WRITE_OWNER,
+ 0,
+ satr_ptr,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL| FILE_FLAG_BACKUP_SEMANTICS,
+ NULL ) ;
+
+
+ if ( ddblk->b.f.handle == INVALID_HANDLE_VALUE ) {
+
+ ddblk->b.f.handle = CreateFile( path,
+ GENERIC_WRITE | GENERIC_READ | WRITE_DAC | WRITE_OWNER,
+ FILE_SHARE_WRITE | FILE_SHARE_READ,
+ satr_ptr,
+ OPEN_ALWAYS,
+ FILE_FLAG_BACKUP_SEMANTICS | posix_flag,
+ NULL ) ;
+
+ }
+
+
+ if ( ddblk->b.f.handle != INVALID_HANDLE_VALUE ) {
+
+ NTFS_SaveTempName( path, tempName );
+
+ ddblk->b.f.hand_temp_name = tempName ;
+ ret_val = SUCCESS;
+
+ } else {
+ free( tempName );
+ }
+ }
+ }
+ }
+
+ NTFS_ReleaseWorkPath( fsh ) ;
+
+ return ret_val;
+}
+/**/
+/**
+
+ Name: NTFS_CreateDir()
+
+ Description: This function creates a directory path.
+
+ Modified: 2/10/1992 15:54:56
+
+ Returns: Error Codes
+ FS_ACCESS_DENIED
+ OUT_OF_MEMORY
+ SUCCESS
+
+ Notes: Non recursive
+
+**/
+static INT16 NTFS_CreateDir( fsh, ddblk )
+FSYS_HAND fsh ; /* I - File system to create directory on */
+NTFS_DBLK_PTR ddblk ; /* I - Decription of directory to create */
+{
+ INT16 ret_val = SUCCESS ;
+ CHAR_PTR p ;
+ CHAR_PTR path ;
+ UINT16 cch_path_leng ; //count of chars in path w/o NULL term
+ BOOLEAN isNTFS;
+ INT16 dev_name_size ;
+ SECURITY_ATTRIBUTES satr ;
+ SECURITY_ATTRIBUTES *satr_ptr = NULL ;
+
+// if ( fsh->attached_dle->info.ntfs->sd ) {
+// satr.nLength = sizeof(SECURITY_ATTRIBUTES);
+// satr.lpSecurityDescriptor = fsh->attached_dle->info.ntfs->sd ;
+// satr.bInheritHandle = FALSE ;
+// satr_ptr = &satr ;
+// }
+
+
+ isNTFS = strcmp(fsh->attached_dle->info.ntfs->fs_name, TEXT("NTFS")) == 0;
+
+ path = ddblk->full_name_ptr->name ;
+
+ if ( strlen( path ) != 0 ) {
+
+ if ( NTFS_SetupWorkPath( fsh,
+ path,
+ NULL,
+ &path ) != SUCCESS) {
+
+ return OUT_OF_MEMORY ;
+ }
+
+ cch_path_leng = (INT16)strlen( path ) ;
+
+ dev_name_size = strlen(path) - strlen( ddblk->full_name_ptr->name) ;
+
+ /* backup path until first one succeeds */
+
+ p = path + strlen(path) ;
+
+ while ( ( p > path + dev_name_size ) &&
+ !CreateDirectory( path, satr_ptr ) ) {
+
+ DWORD error = GetLastError();
+
+ satr_ptr = NULL ;
+
+ if ( error == ERROR_ALREADY_EXISTS ) {
+ break ;
+ } else {
+ /*
+ * If this is not an NTFS drive, and we get access
+ * denied from CreateDir, it may mean the directory
+ * already exists. Yes, this is a kludge.
+ */
+ if ( (isNTFS == FALSE) && (error == ERROR_ACCESS_DENIED) ) {
+ if ( GetFileAttributes( path ) != 0xffffffff ) {
+ /*
+ * If we got the attributes, the directory
+ * must exist.
+ */
+ break;
+ }
+ }
+ }
+
+ p = strrchr( path, TEXT('\\') ) ;
+ if ( p == NULL ) {
+ p = path ;
+ }
+
+ *p = TEXT('\0') ;
+
+ }
+
+ p = path ;
+
+ while ( ( ret_val == SUCCESS ) && ( (UINT16)strlen( path ) < cch_path_leng ) ) {
+
+ p = path + strlen( path ) ;
+ *p = TEXT('\\') ;
+
+ if ( (UINT16)strlen( path ) == cch_path_leng ) {
+ if ( fsh->attached_dle->info.ntfs->sd ) {
+ satr_ptr = &satr ;
+ }
+ }
+
+ if ( !CreateDirectory( path, satr_ptr ) ) {
+
+ DWORD error = GetLastError();
+
+ if ( error != ERROR_ALREADY_EXISTS ) {
+ ret_val = NTFS_TranslateBackupError( error );
+ }
+ }
+ }
+
+ if ( ret_val == SUCCESS ) {
+
+ ret_val = FS_SavePath( fsh, (UINT8_PTR)(&path[2]), (INT16)strsize( path ) ) ;
+
+ }
+ }
+
+ NTFS_ReleaseWorkPath( fsh ) ;
+
+ return ( ret_val ) ;
+}
diff --git a/private/utils/ntbackup/src/tdelete.c b/private/utils/ntbackup/src/tdelete.c
new file mode 100644
index 000000000..1f8c6efa6
--- /dev/null
+++ b/private/utils/ntbackup/src/tdelete.c
@@ -0,0 +1,176 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tdelete.c
+
+ Description: This file contains code to delete file and directories
+ on a LOCAL NTFS drive.
+
+
+ $Log: N:/LOGFILES/TDELETE.C_V $
+
+ Rev 1.5 10 Nov 1992 08:19:06 STEVEN
+removed path and name from dblk now use full_name_ptr
+
+ Rev 1.4 24 Sep 1992 13:43:12 BARRY
+Changes for huge file name support.
+
+ Rev 1.3 21 May 1992 13:50:56 STEVEN
+more long path stuff
+
+ Rev 1.2 04 May 1992 09:26:02 LORIB
+Changes for variable length paths.
+
+ Rev 1.1 28 Feb 1992 13:03:44 STEVEN
+step one for varible length paths
+
+ Rev 1.0 12 Feb 1992 14:46:14 STEVEN
+Initial revision.
+
+**/
+#include <windows.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "fsys_err.h"
+#include "ntfsdblk.h"
+#include "ntfs_fs.h"
+
+static INT16 NTFS_DeleteDir( FSYS_HAND fsh, NTFS_DBLK_PTR ddblk) ;
+static INT16 NTFS_DeleteFile( FSYS_HAND fsh, NTFS_DBLK_PTR ddblk) ;
+
+/**/
+/**
+
+ Name: NTFS_DeleteObj()
+
+ Description: This function deletes a LOCAL NTFS object.
+
+ Modified: 2/12/1992 14:35:59
+
+ Returns: Error codes:
+ FS_NOT_FOUND
+ FS_BAD_DBLK
+ FS_ACCESS_DENIED
+
+**/
+INT16 NTFS_DeleteObj( fsh, dblk )
+FSYS_HAND fsh ;
+DBLK_PTR dblk ;
+{
+ NTFS_DBLK_PTR ddblk ;
+ INT16 ret_val ;
+
+ msassert( fsh->attached_dle != NULL ) ;
+ ddblk = (NTFS_DBLK_PTR) dblk ;
+
+
+ switch( dblk->blk_type ){
+
+ case DDB_ID :
+
+ ret_val = NTFS_DeleteDir( fsh, ddblk ) ;
+
+ break ;
+
+ case FDB_ID :
+
+ ret_val = NTFS_DeleteFile( fsh, ddblk ) ;
+
+ break ;
+
+ default :
+
+ ret_val = FS_BAD_DBLK ;
+ }
+
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Name: NTFS_DeleteFile()
+
+ Description: This function deletes the file in the current directoy.
+
+ Modified: 7/28/1989
+
+ Returns: Error Codes :
+ FS_NOT_FOUND
+ FS_ACCESS_DENIED
+
+**/
+static INT16 NTFS_DeleteFile( fsh, ddblk )
+FSYS_HAND fsh ; /* I - File system to delete file from */
+NTFS_DBLK_PTR ddblk ; /* I - Describes file to delete */
+{
+ CHAR_PTR path ;
+ INT16 ret_val = SUCCESS ;
+
+ if ( NTFS_SetupWorkPath( fsh, fsh->cur_dir, ddblk->full_name_ptr->name, &path ) != SUCCESS ) {
+ return OUT_OF_MEMORY ;
+ }
+
+ if ( !DeleteFile( path ) ) {
+
+ SetFileAttributes( path, 0 ) ;
+
+ if ( !DeleteFile( path ) ) {
+ ret_val = FS_ACCESS_DENIED ;
+ }
+ }
+
+ NTFS_ReleaseWorkPath( fsh ) ;
+
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Name: NTFS_DeleteDir()
+
+ Description: This function removes a directory under the current
+ directory.
+
+ Modified: 2/12/1992 14:39:21
+
+ Returns: Error code
+ FS_ACCESS_DENIED
+ FS_NOT_FOUND
+ SUCCESS
+
+**/
+/* begin declaration */
+static INT16 NTFS_DeleteDir( fsh, ddblk )
+FSYS_HAND fsh ;
+NTFS_DBLK_PTR ddblk ;
+{
+ CHAR_PTR path ;
+ INT16 ret_val = SUCCESS ;
+
+ path = ddblk->full_name_ptr->name ;
+
+ if ( NTFS_SetupWorkPath( fsh, path, NULL, &path ) != SUCCESS) {
+ return OUT_OF_MEMORY ;
+ }
+
+ if ( !RemoveDirectory( path ) ) {
+
+ SetFileAttributes( path, 0 ) ;
+
+ if ( !RemoveDirectory( path ) ) {
+ ret_val = FS_ACCESS_DENIED ;
+ }
+ }
+
+ NTFS_ReleaseWorkPath( fsh ) ;
+
+ return( ret_val ) ;
+
+}
diff --git a/private/utils/ntbackup/src/tension.dlg b/private/utils/ntbackup/src/tension.dlg
new file mode 100644
index 000000000..54190da9d
--- /dev/null
+++ b/private/utils/ntbackup/src/tension.dlg
@@ -0,0 +1,11 @@
+
+IDD_TENSION DIALOG 27, 32, 270, 90
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Job Status - "
+FONT 8, "MS Shell Dlg"
+BEGIN
+ PUSHBUTTON "OK", IDD_JST_OK, 120, 71, 34, 14
+ LTEXT "Summary", 0x0069, 3, 4, 39, 8
+ LISTBOX IDD_JST_LISTBOX, 4, 15, 261, 61, WS_VSCROLL | WS_HSCROLL |
+ WS_TABSTOP
+END
diff --git a/private/utils/ntbackup/src/tfbuffs.c b/private/utils/ntbackup/src/tfbuffs.c
new file mode 100644
index 000000000..7ec0a149d
--- /dev/null
+++ b/private/utils/ntbackup/src/tfbuffs.c
@@ -0,0 +1,292 @@
+/**
+
+ Name: tfbuffs.c
+
+ Description: TF_AllocateTapeBuffers()
+ TF_FreeTapeBuffers()
+
+ $Log: T:\logfiles\tfbuffs.c_v $
+
+ Rev 1.18 01 Feb 1994 15:12:20 GREGG
+Put TEXT macros debug print format strings.
+
+ Rev 1.17 23 Jul 1992 10:11:56 GREGG
+Fixed warnings.
+
+ Rev 1.16 26 Feb 1992 12:02:18 STEVEN
+added buffnt.h
+
+ Rev 1.15 11 Feb 1992 17:12:02 NED
+changed buffman/translator interface parameters
+
+ Rev 1.14 08 Feb 1992 14:40:46 GREGG
+Fixed stupid mistake!
+
+ Rev 1.13 05 Feb 1992 20:17:56 GREGG
+Fixed buffer size math.
+
+ Rev 1.12 04 Feb 1992 19:53:02 GREGG
+Changes for dealing with new config parameters.
+
+ Rev 1.11 22 Jan 1992 15:53:06 NED
+Fixed buffer allocation parameters
+
+ Rev 1.10 16 Jan 1992 18:43:14 NED
+Skateboard: buffer manager changes
+
+ Rev 1.9 15 Jan 1992 00:45:50 GREGG
+Kludged in config stuffuntil we can fix it right.
+
+ Rev 1.8 13 Jan 1992 19:41:18 NED
+Changed allocation of buffers
+
+ Rev 1.7 13 Jan 1992 13:49:56 GREGG
+Skateboard - Bug fixes.
+
+ Rev 1.6 09 Jan 1992 10:01:06 NED
+Made hardwired 100K buffer allocation OS/2 specific.
+Improved debug messages.
+
+ Rev 1.5 03 Jan 1992 13:27:06 GREGG
+New Buffer Manager integration
+
+ Rev 1.4 03 Dec 1991 11:49:54 GREGG
+SKATEBOARD - New Buff Mgr - Initial integration.
+
+ Rev 1.3 14 Aug 1991 14:45:14 DON
+needed OS_NLM to not reference gb_dos_pool
+
+ Rev 1.2 26 Jul 1991 11:08:54 GREGG
+Changed MAYN_OS2 to OS_OS2.
+
+ Rev 1.1 10 May 1991 16:07:16 GREGG
+Ned's new stuff
+
+ Rev 1.0 10 May 1991 10:11:56 GREGG
+Initial revision.
+
+**/
+
+#include <malloc.h>
+
+#include "stdtypes.h"
+#include "drive.h"
+#include "channel.h"
+#include "buffman.h"
+#include "tfl_err.h"
+#include "lw_data.h"
+#include "tflproto.h"
+#include "mem.h"
+#include "be_debug.h"
+#include "minmax.h"
+#include "lw_data.h"
+
+#if defined( OS_NLM )
+#include "buffnlm.h"
+#elif defined( OS_WIN )
+#include "buffwin.h"
+#elif defined( OS_DOS )
+#include "buffdos.h"
+#elif defined( OS_OS2 )
+#include "buffos2.h"
+#elif defined( OS_WIN32 )
+#include "buffnt.h"
+#endif
+
+/**/
+/**
+ * Unit: Tape Format
+ *
+ * Name: TF_AllocateTapeBuffers
+ *
+ * Modified: Tuesday, December 17, 1991
+ *
+ * Description: Allocates most of the Tape Format read/write buffers.
+ *
+ * Notes: Two buffers have already been allocated
+ * in TF_OpenTapeFormat().
+ *
+ * Returns: INT16, a TFLE_xxxx code
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ ** Ask the OS for avail_mem, and get his opinion on buffer size
+ **
+ ** Determine the amount of allowable memory
+ **
+ ** split available memory among channels
+ **
+ ** For each channel
+ **
+ ** if we are in write mode
+ **
+ ** mark our vcb buffer as a vcb buffer
+ **
+ ** free or resize our vcb buffer
+ **
+ ** while we haven't allocated enough memory yet
+ **
+ ** Allocate a buffer using list requirements
+ **
+ **/
+
+INT16 TF_AllocateTapeBuffers(
+ UINT16 mem_save, /* I - number of Kb we should leave free */
+ UINT16 max_buffs, /* I - number buffers maximum we should use */
+ UINT16 buff_size ) /* I - Kb buffer size (recommended) */
+{
+ UINT32 avail_mem;
+ UINT32 buffer_allowance;
+ UINT32 translator_preferred;
+ UINT32 mem_per_channel;
+ UINT16 total_buffers;
+ UINT16 index;
+ INT16 ret_val = TFLE_NO_ERR;
+
+/*
+** Ask the OS for avail_mem, and get his opinion on buffer size
+*/
+ BM_OS_BufferRequirements( &avail_mem, &buff_size );
+
+ if ( avail_mem <= mem_save ) {
+ return TFLE_NO_MEMORY;
+ }
+
+/*
+** Determine the amount of allowable memory
+*/
+ buffer_allowance = (UINT32)( (UINT32)max_buffs * (UINT32)buff_size * 1024UL + (UINT32)max_buffs * (UINT32)BM_BufferOverhead( ) );
+
+ /* Hard wired until the translator gets sane */
+ translator_preferred = 100UL * 1024UL ;
+/*
+ TF_GetPreferredBufferSpace( QueueHead( &lw_drive_list ),
+ max_buffs, (UINT32)buff_size, &translator_preferred ) ;
+*/
+ buffer_allowance = MAX( buffer_allowance, translator_preferred );
+ avail_mem = MIN( avail_mem - ( mem_save * 1024 ), buffer_allowance );
+
+/*
+** split available memory among channels
+*/
+ mem_per_channel = avail_mem / lw_tfl_control.no_channels;
+ total_buffers = 0;
+/*
+** If no default buffer requirements have been set yet
+*/
+ if ( lw_default_bm_requirements.a.min_size == BR_DONT_CARE ) {
+/*
+** try to set default buffer requirements from VCB requirements and config
+** (default to VCB requirements if incompatible)
+*/
+ lw_default_bm_requirements.a.min_size = buff_size * 1024 ;
+ if ( BM_AddRequirements( &lw_default_bm_requirements,
+ &lw_default_vcb_requirements ) != BR_NO_ERR ) {
+ lw_default_bm_requirements = lw_default_vcb_requirements ;
+ }
+ /* set reasonable sizes given allocation size */
+ lw_default_bm_requirements.tf_size
+ = lw_default_bm_requirements.rw_size
+ = lw_default_bm_requirements.a.min_size;
+ }
+/*
+** For each channel
+*/
+ for ( index = 0; index < lw_tfl_control.no_channels && ret_val == TFLE_NO_ERR; index++ ) {
+ BUF_LIST_PTR buf_list_ptr ;
+ UINT16 count ;
+ UINT16 limit ;
+
+ buf_list_ptr = &lw_channels[index].buffer_list;
+ buf_list_ptr->max_memory = mem_per_channel;
+/*
+** if list requirements haven't been set yet
+*/
+ if ( BM_ListRequirements( buf_list_ptr )->a.min_size == BR_DONT_CARE ) {
+/*
+** set the requirements to default read requirements
+*/
+ BM_SetListRequirements( buf_list_ptr, &lw_default_bm_requirements );
+ }
+/*
+** while we haven't allocated enough memory yet
+*/
+ limit = (UINT16)(mem_per_channel / BM_RequiredSize( BM_ListRequirements( buf_list_ptr ) ) );
+ if ( BM_ListRequirements( buf_list_ptr )->a.min_size == buff_size * 1024U ) {
+ limit = MIN( limit, max_buffs ) ;
+ }
+ for( count = 0; count < limit; count++ ) {
+/*
+** Allocate a buffer using list requirements
+*/
+ if ( BM_Alloc( buf_list_ptr ) == NULL ) {
+ break; /* didn't quite catch our limit! */
+ }
+ }
+
+ if( count == 0 ) {
+ ret_val = TFLE_NO_MEMORY ;
+ }
+ total_buffers += BM_ListCount( buf_list_ptr ) ;
+ BE_Zprintf( DEBUG_TEMPORARY,
+ TEXT("Allocated %u buffers, size %u bytes, total used: %lu\n"),
+ total_buffers, buf_list_ptr->requirements_context.a.min_size,
+ buf_list_ptr->memory_used );
+ }
+
+
+ return ret_val ;
+}
+
+/**/
+/**
+ * Unit: Tape Format
+ *
+ * Name: TF_FreeTapeBuffers
+ *
+ * Modified: Monday, October 21, 1991
+ *
+ * Description: Free the buffers allocated by TF_AllocateTapeBuffers()
+ *
+ * Notes: Leaves two buffers in each channel
+ *
+ * Returns: INT16, a TFLE_xxxx code
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ ** For each channel
+ **
+ ** Free all the non-reserved buffers
+ **
+ ** Ensure we have 2 buffers on the channel list
+ **
+ **/
+
+INT16 TF_FreeTapeBuffers( VOID )
+{
+ UINT16 i ;
+ INT16 orig_buffers = 0;
+ INT16 total_buffers = 0;
+/*
+** For each channel
+*/
+ for( i = 0 ; i < lw_tfl_control.no_channels ; i++ ) {
+ BUF_LIST_PTR buf_list_ptr = &lw_channels[i].buffer_list;
+ orig_buffers += BM_ListCount( buf_list_ptr );
+/*
+** Free all the non-reserved buffers
+*/
+ BM_FreeAll( buf_list_ptr );
+ total_buffers += BM_ListCount( buf_list_ptr );
+ }
+
+ BE_Zprintf( DEBUG_TEMPORARY, TEXT("TF_FreeTapeBuffers: from %d to %d buffers\n"),
+ orig_buffers, total_buffers );
+
+ return( TFLE_NO_ERR ) ;
+}
+
diff --git a/private/utils/ntbackup/src/tfclose.c b/private/utils/ntbackup/src/tfclose.c
new file mode 100644
index 000000000..d0a6b89d2
--- /dev/null
+++ b/private/utils/ntbackup/src/tfclose.c
@@ -0,0 +1,229 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tfclose.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the code for the TF close command.
+
+
+ $Log: J:/LOGFILES/TFCLOSE.C_V $
+
+ Rev 1.17 13 May 1992 13:28:34 CHARLIE
+Eliminated BE_Zprint call
+
+ Rev 1.16 13 May 1992 11:21:16 GREGG
+EPR #1295 - On fatal errors, free format env, and force rewind on next mount.
+
+ Rev 1.15 20 Mar 1992 18:00:48 NED
+added exception updating after TpReceive calls
+
+ Rev 1.14 24 Feb 1992 15:19:02 GREGG
+Split TF_CloseSet into TF_CloseTape and TF_CloseSet.
+
+ Rev 1.13 16 Jan 1992 18:42:24 NED
+Skateboard: buffer manager changes
+
+ Rev 1.12 16 Jan 1992 10:17:34 GREGG
+Skateboard - Bug fixes.
+
+ Rev 1.11 03 Dec 1991 11:43:54 GREGG
+SKATEBOARD - New Buff Mgr - Initial integration.
+
+ Rev 1.10 17 Oct 1991 01:30:18 GREGG
+BIGWHEEL - 8200sx - Initial integration.
+
+ Rev 1.9 07 Oct 1991 22:19:16 GREGG
+Make sure the fmt env pointers are maintained in only one place at any given time.
+
+ Rev 1.8 17 Sep 1991 11:46:14 GREGG
+Always dismount the tape if you have a drive handle.
+
+ Rev 1.7 11 Sep 1991 12:49:42 GREGG
+No need to check the operation type when determining whether to save the buffer.
+
+ Rev 1.6 22 Aug 1991 16:35:00 NED
+Changed all references to internals of the buffer structure to macros.
+
+ Rev 1.5 20 Aug 1991 13:44:04 GREGG
+Don't put the cur_buff into hold_buff if the exception is NO_DATA.
+
+ Rev 1.4 20 Jun 1991 14:36:42 GREGG
+Save the current buffer if it has an exception OR unprocessed bytes.
+
+ Rev 1.3 18 Jun 1991 12:17:22 GREGG
+Removed process queue cleanup and forced rewind from Fatal Error processing.
+
+ Rev 1.2 06 Jun 1991 19:12:10 GREGG
+Save format environment after all successful operations.
+
+ Rev 1.1 10 May 1991 16:09:24 GREGG
+Ned's new stuff
+
+ Rev 1.0 10 May 1991 10:11:58 GREGG
+Initial revision.
+
+**/
+/* begin include list */
+
+#include <stdtypes.h>
+#include <queues.h>
+
+#include "drive.h"
+#include "channel.h"
+#include "lw_data.h"
+#include "tflopen.h"
+#include "lwprotos.h"
+#include "tflproto.h"
+#include "tflstats.h"
+#include "translat.h"
+#include "sx.h"
+
+/* Device Driver Interface Files */
+#include "retbuf.h"
+#include "dilhwd.h"
+#include "drvinf.h"
+#include "generr.h"
+
+#include "be_debug.h"
+
+/* $end$ include list */
+
+
+/**/
+/**
+
+ Name: TF_CloseTape
+
+ Description: Closes out a Tape operation for a given channel.
+
+ Modified: 9/28/1989 10:5:37
+
+ Returns: Nothing
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+VOID TF_CloseTape( UINT16 channel_no )
+{
+ CHANNEL_PTR channel = &lw_channels[channel_no] ;
+ BOOLEAN rewind ;
+
+ /* Close the drive */
+ if( channel->cur_drv->drv_hdl ) {
+ /* Tell the drive to rewind if requested and there is a tape */
+ rewind = ( BOOLEAN ) IsPosBitSet( channel->cur_drv, REW_CLOSE ) ;
+ DisMountTape( channel->cur_drv, channel->ui_tpos, rewind ) ;
+ ClrPosBit( channel->cur_drv, REW_CLOSE ) ;
+ }
+
+ ClrChannelStatus( channel, CH_IN_USE ) ;
+
+ lw_tfl_control.no_chans_open-- ;
+}
+
+
+/**
+
+ Name: TF_CloseSet
+
+ Description: Closes out a Tape operation for a given channel.
+
+ Modified: 9/28/1989 10:5:37
+
+ Returns: Nothing
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+VOID TF_CloseSet(
+ UINT16 channel_no,
+ TF_STATS_PTR setstats )
+{
+ CHANNEL_PTR channel = &lw_channels[channel_no] ;
+ BUF_PTR tmpBUF ;
+ Q_ELEM_PTR qe_ptr ;
+
+ BE_Zprintf( DEBUG_TAPE_FORMAT, RES_TF_CLOSE_SET ) ;
+
+ /* No matter what do the SX stuff in case any drive in the channel was an SX */
+ SX_End( channel ) ;
+
+ /* A fatal error occured on this channel */
+ if( FatalError( channel ) ) {
+
+ BE_Zprintf( DEBUG_TAPE_FORMAT, RES_FATAL_ERROR_DETECTED ) ;
+
+ PuntBuffer( channel ) ;
+
+ if( channel->eom_buff != NULL ) {
+ channel->cur_buff = channel->eom_buff ;
+ channel->eom_buff = NULL ;
+ PuntBuffer( channel ) ;
+ }
+
+ /* If another operation is tried on drive, we want a clean start */
+ FreeFormatEnv( &channel->cur_fmt, &channel->fmt_env ) ;
+ channel->cur_drv->force_rewind = TRUE ;
+ }
+
+ /* If the translator is still alive, we need to keep some context info */
+ if ( channel->fmt_env != NULL ) {
+
+ /* If there is live data or an exception in the current buffer */
+ if( !IsSetDone( channel ) &&
+ channel->cur_buff != NULL &&
+ ( BM_BytesFree( channel->cur_buff ) != 0 ||
+ ( BM_ReadError( channel->cur_buff ) != GEN_NO_ERR &&
+ BM_ReadError( channel->cur_buff ) != GEN_ERR_NO_DATA ) ) ) {
+
+ /* hold on to the unprocessed buffer */
+ BE_Zprintf( DEBUG_TAPE_FORMAT, RES_READ_BUFFER_LEFT_OVER ) ;
+ BM_Reserve( channel->cur_buff ) ; /* mark as reserved */
+ channel->cur_drv->hold_buff = channel->cur_buff ;
+ channel->cur_buff = NULL ;
+ }
+
+ /* save the current format environment */
+ channel->cur_drv->last_cur_fmt = channel->cur_fmt ;
+ channel->cur_drv->last_fmt_env = channel->fmt_env ;
+ channel->cur_fmt = UNKNOWN_FORMAT ;
+ channel->fmt_env = NULL ;
+
+ } else {
+ /* The translator bit the big one! Reset the buffer requirements */
+ /* to default so we'll allocate the proper size the next time we */
+ /* call TF_AllocateTapeBuffers. */
+ BM_SetListRequirements( &channel->buffer_list, &lw_default_bm_requirements );
+ }
+
+ BE_Zprintf( DEBUG_TAPE_FORMAT, RES_NEW_LINE ) ;
+
+ PuntBuffer( channel ) ;
+
+ /* Clean up in process queue */
+ while( ( qe_ptr = DeQueueElem( &channel->cur_drv->inproc_q ) ) != NULL ) {
+ tmpBUF = QueuePtr( qe_ptr );
+ channel->cur_buff = tmpBUF ;
+ PuntBuffer( channel ) ;
+ }
+
+ /* Set up Statistics -- This is an example of a BWMPU */
+ if( setstats != NULL ) {
+ *setstats = channel->cur_drv->cur_stats ;
+ }
+
+ ClrChannelStatus( channel, CH_DONE ) ;
+}
diff --git a/private/utils/ntbackup/src/tfeject.c b/private/utils/ntbackup/src/tfeject.c
new file mode 100644
index 000000000..1348800e7
--- /dev/null
+++ b/private/utils/ntbackup/src/tfeject.c
@@ -0,0 +1,123 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-91
+
+
+ Name: tfeject.c
+
+ Description: Contains the function to eject the tape from the
+ specified drive.
+
+
+ $Log: T:/LOGFILES/TFEJECT.C_V $
+
+ Rev 1.5 30 Mar 1993 16:15:36 GREGG
+Handle Unrecognized Media error (unformatted DC2000).
+
+ Rev 1.4 18 Jan 1993 14:20:04 BobR
+Added MOVE_ESA macro calls(s)
+
+ Rev 1.3 20 Mar 1992 18:00:10 NED
+added exception updating after TpReceive calls
+
+ Rev 1.2 30 Oct 1991 11:29:16 GREGG
+BIGWHEEL - Changed TpSpecial call to TpEject/TpReceive and cleaned up some stuff.
+
+ Rev 1.1 23 Oct 1991 08:39:02 GREGG
+EPR #9 - Don't kill the hold_buff until after MountTape (we may still need it).
+
+ Rev 1.0 02 Oct 1991 14:07:24 GREGG
+Initial revision.
+
+**/
+/* begin include list */
+#include "stdtypes.h"
+
+#include "drive.h"
+#include "lw_data.h"
+#include "tfl_err.h"
+#include "lwprotos.h"
+#include "tflproto.h"
+#include "translat.h"
+#include "dil.h"
+#include "special.h"
+#include "generr.h"
+
+/* $end$ include list */
+
+
+/**/
+/**
+
+ Name: TF_EjectTape
+
+ Description: This function rewinds the tape, resets the drive position,
+ and ejects the tape if the drive has the capability to do
+ this from software.
+
+ Returns: A TFLE_xxx error code.
+
+ Notes: None.
+
+ Declaration:
+
+**/
+
+INT16 TF_EjectTape( THW_PTR thw, /* (I) The drive to be ejected */
+ TPOS_HANDLER ui_tpos ) /* (I) For callback during */
+ /* rewind. */
+{
+ DRIVE_PTR curDRV = (DRIVE_PTR) thw ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ BOOLEAN have_tape ;
+ RET_BUF myret ;
+
+ /* Note: These are used only for tpos handler! */
+ TPOS tpos_struct ;
+ TPOS_PTR tpos_ptr = NULL ;
+
+ msassert( curDRV != NULL ) ;
+
+ if( ui_tpos != NULL ) {
+ tpos_struct.UI_TapePosRoutine = ui_tpos ;
+ tpos_ptr = &tpos_struct ;
+ }
+ ret_val = MountTape( curDRV, tpos_ptr, &have_tape ) ;
+ if( ret_val == TFLE_NO_ERR || ret_val == TF_UNRECOGNIZED_MEDIA ) {
+ FreeFormatEnv( & curDRV->last_cur_fmt, & curDRV->last_fmt_env ) ;
+ if( curDRV->hold_buff != NULL ) {
+ BM_Put( curDRV->hold_buff ) ;
+ curDRV->hold_buff = NULL ;
+ }
+ if( have_tape ) {
+ if( ret_val != TF_UNRECOGNIZED_MEDIA ) {
+ ret_val = RewindDrive( curDRV, tpos_ptr, TRUE, TRUE, 0 ) ;
+ } else {
+ ret_val = TFLE_NO_ERR ;
+ }
+
+ if( ret_val == TFLE_NO_ERR &&
+ ( curDRV->thw_inf.drv_info.drv_features & TDI_UNLOAD ) ) {
+
+ if( TpEject( curDRV->drv_hdl ) == FAILURE ) {
+ ret_val = TFLE_DRIVER_FAILURE ;
+ } else {
+ while( TpReceive( curDRV->drv_hdl, &myret ) == FAILURE ) {
+ /* for non-preemptive operating systems: */
+ ThreadSwitch( ) ;
+ }
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( thw->the, myret.the ) ;
+
+ if( myret.gen_error != GEN_NO_ERR ) {
+ curDRV->thw_inf.drv_status = myret.status ;
+ ret_val = TFLE_DRIVE_FAILURE ;
+ }
+ }
+ }
+ DisMountTape( curDRV, NULL, FALSE ) ;
+ }
+ }
+
+ return( ret_val ) ;
+}
+
diff --git a/private/utils/ntbackup/src/tfinit.c b/private/utils/ntbackup/src/tfinit.c
new file mode 100644
index 000000000..c4c8cb005
--- /dev/null
+++ b/private/utils/ntbackup/src/tfinit.c
@@ -0,0 +1,501 @@
+/**/
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tfinit.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the High Level Tape Format Entry Points ( No I
+ Don't Know Why I'm Capitalizing ).
+
+
+ $Log: J:/LOGFILES/TFINIT.C_V $
+
+ Rev 1.33 23 Jul 1993 08:53:50 DON
+Needed to use 'calloc' instead of 'malloc' when allocating the software_name
+
+ Rev 1.32 22 Jul 1993 12:12:48 ZEIR
+ad'd software_name logic to OpenTapeFormat
+
+ Rev 1.31 18 Jan 1993 14:21:46 BobR
+Added MOVE_ESA macro call(s)
+
+ Rev 1.30 08 Oct 1992 15:20:16 GREGG
+Changed mallocs to callocs of n chars at sizeof( CHAR ) for Unicode support.
+
+ Rev 1.29 06 Oct 1992 13:23:40 DAVEV
+Unicode strlen verification
+
+ Rev 1.28 17 Aug 1992 08:42:26 GREGG
+Changes to deal with block sizeing scheme.
+
+ Rev 1.27 27 Jul 1992 14:04:52 GREGG
+Fixed more warnings...
+
+ Rev 1.26 27 Jul 1992 12:55:40 GREGG
+Fixed more warnings...
+
+ Rev 1.25 05 Apr 1992 18:25:40 GREGG
+ROLLER BLADES - Changed lw_sx_file_path to lw_cat_file_path.
+
+ Rev 1.24 11 Mar 1992 14:49:04 GREGG
+If TF_NO_MAY_ID is defined, always call TpSpecial SS_NO_MAY_ID.
+
+ Rev 1.23 12 Feb 1992 16:25:54 STEVEN
+fix errors for NT
+
+ Rev 1.22 11 Feb 1992 17:11:16 NED
+changed buffman/translator interface parameters
+
+ Rev 1.21 04 Feb 1992 19:52:42 GREGG
+Changes for dealing with new config parameters.
+
+ Rev 1.20 16 Jan 1992 18:42:00 NED
+Skateboard: buffer manager changes
+
+ Rev 1.19 15 Jan 1992 00:46:16 GREGG
+Kludged in config stuffuntil we can fix it right.
+
+ Rev 1.18 14 Jan 1992 01:59:48 GREGG
+Skateboard bug fixes.
+
+ Rev 1.17 13 Jan 1992 19:39:30 NED
+Removed declaration of BM_AllocVCB()
+
+ Rev 1.16 13 Jan 1992 13:50:56 GREGG
+Skateboard - Bug fixes.
+
+ Rev 1.15 02 Jan 1992 14:53:10 NED
+Buffer Manager/UTF translator integration.
+
+ Rev 1.14 03 Dec 1991 11:45:42 GREGG
+SKATEBOARD - New Buff Mgr - Initial integration.
+
+ Rev 1.13 17 Oct 1991 01:29:48 GREGG
+BIGWHEEL - 8200sx - Initial integration.
+
+ Rev 1.12 15 Oct 1991 07:49:50 GREGG
+Added ThreadSwitch call in empty TpReceive loops.
+
+ Rev 1.11 14 Oct 1991 11:08:58 GREGG
+Modified handling of busy poll state in CloseTapeFormat.
+
+ Rev 1.10 07 Oct 1991 16:03:50 GREGG
+Free lw_channel before setting it to NULL in Close. (might help eh?)
+
+ Rev 1.9 23 Sep 1991 15:41:22 GREGG
+8200SX - Added forced_machine_type parameter.
+
+ Rev 1.8 18 Sep 1991 11:58:18 GREGG
+Handle drive being polled as well as drive being watched at close time.
+Defined out allocation for DriverDirectoryName for NLM, and freed the
+allocated memory in DeInit for everyone else.
+
+ Rev 1.7 06 Aug 1991 13:22:32 DON
+ifdef'd calls DriverLoad & SetActiveMSL for OS_NLM
+
+ Rev 1.6 26 Jul 1991 16:05:20 GREGG
+Changed MAYN_ defs to OS_ defs.
+
+ Rev 1.5 18 Jul 1991 13:58:56 DAVIDH
+Ignore int86 calls for NLM
+
+ Rev 1.4 27 Jun 1991 15:47:46 NED
+Removed reference to "config.h" and CDS_GetMaynFolder(),
+added parameter to end of list.
+
+ Rev 1.3 06 Jun 1991 20:59:04 GREGG
+Added translator environment initialization to open, and a call to free any
+existing environments in close.
+
+ Rev 1.2 20 May 1991 10:30:48 DAVIDH
+Cleared up compiler warnings under Watcom for NLM.
+
+ Rev 1.1 10 May 1991 16:08:34 GREGG
+Ned's new stuff
+
+ Rev 1.0 10 May 1991 10:12:06 GREGG
+Initial revision.
+
+**/
+/* begin include list */
+
+#include <malloc.h>
+#include <string.h>
+#include <dos.h>
+#include <conio.h> /* Strange, but contains inp(), etc. */
+
+#include "stdtypes.h"
+#include "queues.h"
+#include "machine.h"
+
+#include "fsys.h"
+#include "be_debug.h"
+#include "tfldefs.h"
+#include "tflproto.h"
+#include "channel.h"
+#include "drive.h"
+#include "buffman.h"
+#include "lw_data.h"
+#include "tfl_err.h"
+#include "lwprotos.h"
+#include "translat.h"
+
+/* Device Driver InterFace Headers */
+#include "retbuf.h"
+#include "special.h"
+#include "dilhwd.h"
+#include "drvinf.h"
+#include "generr.h"
+#include "genfuncs.h"
+#include "genstat.h"
+#include "dil.h"
+#include "ld_dvr.h"
+#include "detdrive.h"
+#include "lstdres.h"
+#include "lwdefs.h"
+
+#if !defined( OS_NLM )
+
+static CHAR_PTR DriverDirectory( VOID ) ;
+static CHAR_PTR DriverDirectoryName = NULL ;
+
+#endif
+
+#if !defined( TDEMO ) && !defined( OS_NLM )
+
+static STD_RESOURCES_INIT stdres = {
+#if !defined( OS_OS2 ) && !defined( OS_WIN32 )
+ intdosx,
+ free,
+ memset,
+ inp,
+ inpw,
+ outp,
+ outpw,
+ calloc,
+ int86,
+ int86x,
+#endif
+ DriverLoad,
+ DriverDirectory /* our static function */
+} ;
+
+#endif /* TDEMO and OS_NLM */
+
+/**/
+/**
+ * Unit: Tape Format
+ *
+ * Name: TF_OpenTapeFormat
+ *
+ * Modified: Tuesday, December 17, 1991
+ *
+ * Description: This function initializes the Tape Format Layer and sets
+ * up all the interface structures. One buffer is allocated
+ * per channel for the purpose of reading new tapes from
+ * TF_PollDrive().
+ *
+ * Notes:
+ *
+ * Returns: INT16, a TFLE_xxx code
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ **/
+
+INT16 TF_OpenTapeFormat(
+ CHAR_PTR drv_file , /* The device driver file to load */
+ DIL_HWD_PTR cards , /* The array of cards */
+ UINT16 no_cards , /* The number of cards */
+ THW_PTR *thw_ptr , /* Where to build the THW list */
+ INT16 max_channels , /* The maximum number of channels */
+ BOOLEAN use_fast_file, /* FALSE if FF to be suppressed */
+ BOOLEAN ignore_id , /* Operate on non Maynard Drives */
+ CHAR_PTR directory_name, /* for TDH */
+ INT16 forced_machine_type, /* 8200SX stuff */
+ CHAR_PTR catalog_directory, /* for SX files */
+ UINT16 initial_buff_alloc, /* DOS memory allocated at init */
+ CHAR_PTR software_name ) /* Name of software we're running */
+{
+ INT16 ret_val = TFLE_NO_ERR ;
+ INT16 i ;
+#if !defined( TDEMO ) && !defined( OS_NLM )
+ DRIVERHANDLE msl ;
+#endif
+
+ if( catalog_directory != NULL ) {
+ lw_cat_file_path = calloc( strlen( catalog_directory ) + SX_FILE_NAME_LENGTH + 1, sizeof( CHAR ) ) ;
+ if ( lw_cat_file_path == NULL ) {
+ return TFLE_NO_MEMORY ;
+ }
+ strcpy( lw_cat_file_path, catalog_directory ) ;
+ lw_cat_file_path_end = lw_cat_file_path + strlen( lw_cat_file_path ) ;
+ }
+
+ if( software_name != NULL ){
+ lw_software_name_len = strlen( software_name ) ;
+ lw_software_name = calloc( lw_software_name_len + 1, sizeof( CHAR ) ) ;
+ if( lw_software_name == NULL ){
+ lw_software_name_len = 0 ;
+ return TFLE_NO_MEMORY ;
+ }
+ strcpy( lw_software_name, software_name ) ;
+ }
+
+#if !defined( OS_NLM )
+
+ /* save driver directory name in private memory */
+ if ( DriverDirectoryName != NULL ) {
+ free( DriverDirectoryName ) ;
+ }
+ DriverDirectoryName = calloc( strlen( directory_name ) + 1, sizeof( CHAR ) ) ;
+ if ( DriverDirectoryName == NULL ) {
+ return TFLE_NO_MEMORY ;
+ }
+ strcpy( DriverDirectoryName, directory_name ) ;
+
+#else
+
+ (VOID) directory_name ; /* Reference to avoid compiler warnings. */
+
+#endif
+
+#if !defined( TDEMO ) && !defined( OS_NLM )
+
+ /* load the device driver */
+ if( drv_file != NULL ) {
+ if( ( lw_tfl_control.driver_addr = ( VOID_PTR ) DriverLoad( drv_file,&msl,&stdres,sizeof( stdres ) ) ) == NULL ) {
+ return( TFLE_DRIVER_LOAD_FAILURE ) ;
+ }
+ SetActiveMSL( msl ) ;
+ }
+
+#else
+
+ (VOID) drv_file; /* Reference to avoid compiler warnings. */
+
+#endif
+
+ /* Set up the pointer to the controller cards */
+ lw_tfl_control.cntl_cards = cards ;
+
+#if defined( TF_NO_MAY_ID )
+ TpSpecial( 0, SS_NO_MAY_ID, 0L ) ;
+#else
+ if( ignore_id ) {
+ TpSpecial( (INT16)0, (INT16)SS_NO_MAY_ID, 0L ) ;
+ }
+#endif
+
+ if( forced_machine_type != UNKNOWN_MACHINE ) {
+ TpSpecial( (INT16)0, (INT16)SS_FORCE_MACHINE_TYPE, (UINT32)forced_machine_type ) ;
+ }
+
+ lw_tfl_control.use_fast_file = use_fast_file ;
+ if( ( ret_val = SetupDriveList( cards, (INT16)no_cards ) ) == TFLE_NO_ERR ) {
+ lw_tfl_control.drives_active = TRUE ;
+ }
+
+ BE_Zprintf( DEBUG_TAPE_FORMAT, RES_CRIT_ADDRS,
+ lw_tfl_control.driver_addr,
+ lw_channels ) ;
+
+ *thw_ptr = (THW_PTR)(VOID_PTR)QueueHead( &lw_drive_list ) ;
+
+ /* Initialize Buffer Manager */
+ BM_Init( ) ;
+
+ BM_ClearRequirements( &lw_default_bm_requirements );
+
+ /* Ask translators for their default VCB buffer requirements */
+ TF_GetVCBBufferRequirements( &lw_default_vcb_requirements,
+ QueueHead( &lw_drive_list ), TF_DEFAULT_VCB_SIZE ) ;
+ BM_SetVCBRequirements( &lw_default_vcb_requirements );
+
+ /* Allocate memory for channels */
+ if ( ( lw_channels = calloc( (size_t)max_channels, sizeof(CHANNEL) ) ) == NULL ) {
+ return TFLE_NO_MEMORY ;
+ }
+ lw_tfl_control.no_channels = (UINT16)max_channels ;
+
+ /* For each channel */
+ for ( i = 0 ; i < max_channels && ret_val == TFLE_NO_ERR ; i++ ) {
+ /* initialize the translator environment and index */
+ lw_channels[i].cur_fmt = UNKNOWN_FORMAT ;
+ lw_channels[i].fmt_env = NULL ;
+
+ /* initialize the temporary DBLK storage poiters */
+ lw_channels[i].lst_osvcb = NULL ;
+ lw_channels[i].lst_osddb = NULL ;
+ lw_channels[i].lst_osfdb = NULL ;
+
+ /* initialize channel's buffer list */
+ if( ( ret_val = BM_InitList( &lw_channels[i].buffer_list, initial_buff_alloc ) ) == TFLE_NO_ERR ) {
+ /* allocate one buffer for VCB reading */
+ if ( BM_AllocVCB( &lw_channels[i].buffer_list ) == NULL ) {
+ ret_val = TFLE_NO_MEMORY ;
+ }
+ }
+ }
+ return ret_val ;
+}
+
+
+/**/
+/**
+
+ Name: TF_CloseTapeFormat
+
+ Description: Close the tape format layer
+
+ Returns: Nothing.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+VOID TF_CloseTapeFormat( VOID )
+{
+ DRIVE_PTR curDRV = (DRIVE_PTR)(VOID_PTR)QueueHead( &lw_drive_list ) ;
+ RET_BUF myret ;
+ UINT i ;
+
+ /* Rewind All The Drives */
+ if( lw_tfl_control.drives_active ) {
+
+ while( curDRV != NULL ) {
+
+ /* Was this drive watched */
+ if( IsPosBitSet( curDRV, WATCHED ) ||
+ curDRV->poll_stuff.state != st_CLOSED ) {
+
+ while( TpReceive( curDRV->drv_hdl, &myret ) == FAILURE ) {
+ /* for non-preemptive operating systems: */
+ ThreadSwitch( ) ;
+ }
+
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( curDRV->thw_inf.the, myret.the ) ;
+
+ ClrPosBit( curDRV, WATCHED ) ;
+ }
+
+ if( curDRV->poll_stuff.state != st_BSTAT ) {
+ if( curDRV->poll_stuff.state != st_BMNT ||
+ myret.gen_error == GEN_NO_ERR ) {
+
+ if( curDRV->poll_stuff.state != st_CLOSED ) {
+ /* Remember we lied in PollDrive */
+ curDRV->tape_mounted = TRUE ;
+ }
+
+ DisMountTape( curDRV, NULL, FALSE ) ;
+ }
+ }
+
+ curDRV->poll_stuff.state = st_CLOSED ;
+
+ /* If there is a hold_buff, it will be handled in BM_DeInit */
+ curDRV->hold_buff = NULL ;
+
+ /* free the format environment if any */
+ if ( curDRV->last_fmt_env != NULL ) {
+ FreeFormatEnv( & curDRV->last_cur_fmt, & curDRV->last_fmt_env ) ;
+ }
+
+ lw_channels[0].cur_drv = curDRV ;
+
+ /* Close the Drive */
+ CloseDrive( curDRV, NULL, (UINT16)0, (BOOLEAN)(!( curDRV->thw_inf.drv_status & TPS_NO_TAPE ) ) ) ;
+
+ curDRV = (DRIVE_PTR)(VOID_PTR)QueueNext( &curDRV->thw_inf.link ) ;
+ }
+ lw_tfl_control.drives_active = FALSE ;
+ }
+
+ /* reset layer-wide requirements */
+ BM_ClearRequirements( &lw_default_bm_requirements );
+ BM_ClearRequirements( &lw_default_vcb_requirements );
+
+ /* free all the remaining buffers */
+ BM_DeInit( ) ;
+
+
+ /* Release the drivers */
+ if( lw_tfl_control.driver_inited ) {
+ TpRelease( ) ;
+ lw_tfl_control.driver_inited = FALSE ;
+ }
+
+ if( lw_tfl_control.driver_addr != NULL ) {
+
+#if !defined( OS_OS2 ) && !defined( TDEMO ) && !defined( OS_NLM )
+
+ DriverUnLoad( ( VOID_PTR ) lw_tfl_control.driver_addr ) ;
+
+#endif
+
+ lw_tfl_control.driver_addr = NULL ;
+ }
+
+ /* Free the stuff */
+ if( lw_channels ) {
+ for( i = 0; i < lw_tfl_control.no_channels; i++ ) {
+ if( lw_channels[i].lst_osvcb != NULL ) {
+ free( lw_channels[i].lst_osvcb ) ;
+ }
+ if( lw_channels[i].lst_osddb != NULL ) {
+ free( lw_channels[i].lst_osddb ) ;
+ }
+ if( lw_channels[i].lst_osfdb != NULL ) {
+ free( lw_channels[i].lst_osfdb ) ;
+ }
+ }
+
+ free( lw_channels ) ;
+ lw_channels = NULL ;
+ }
+ if( lw_drives ) {
+ free( lw_drives ) ;
+ lw_drives = NULL ;
+ }
+
+ if( lw_cat_file_path ) {
+ free( lw_cat_file_path ) ;
+ lw_cat_file_path = NULL ;
+ lw_cat_file_path_end = NULL ;
+ }
+
+ if( lw_software_name ){
+ free( lw_software_name ) ;
+ lw_software_name = NULL ;
+ lw_software_name_len = 0 ;
+ }
+
+#if !defined( OS_NLM )
+
+ if ( DriverDirectoryName != NULL ) {
+ free( DriverDirectoryName ) ;
+ DriverDirectoryName = NULL ;
+ }
+
+#endif
+
+}
+
+#if !defined( OS_NLM )
+
+static CHAR_PTR DriverDirectory( VOID )
+{
+ return DriverDirectoryName ;
+}
+
+#endif
+
diff --git a/private/utils/ntbackup/src/tflutils.c b/private/utils/ntbackup/src/tflutils.c
new file mode 100644
index 000000000..0237d796d
--- /dev/null
+++ b/private/utils/ntbackup/src/tflutils.c
@@ -0,0 +1,1384 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tflutils.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains various Tape Format Layers.
+
+
+ $Log: T:/LOGFILES/TFLUTILS.C_V $
+
+ Rev 1.56.1.0 02 Mar 1994 18:16:16 GREGG
+Fixed buffer resize logic.
+
+ Rev 1.56 16 Feb 1994 19:20:46 GREGG
+Fixed error in filemark count caculation when MoveFilemarks goes backward.
+
+ Rev 1.55 04 Feb 1994 12:26:12 GREGG
+Fixed bug in buff resize logic when attempting to determine the proper
+block size to read the tape.
+
+ Rev 1.54 28 Jan 1994 11:26:36 GREGG
+Handle GEN_ERR_UNRECOGNIZED_MEDIA returned on reads as well as mounts.
+
+ Rev 1.53 03 Dec 1993 01:04:18 GREGG
+Call memcmp instead of strncmp for Unicode compatability.
+
+ Rev 1.52 01 Dec 1993 18:40:54 ZEIR
+Ad'd MS SQL_Determiner logic
+
+ Rev 1.51 30 Nov 1993 20:44:14 GREGG
+Fixed some error reporting and the stepping on of a boolean.
+
+ Rev 1.50 10 Nov 1993 18:05:04 GREGG
+Check for error return from SetDrvBlkSize.
+
+ Rev 1.49 20 Oct 1993 18:36:42 GREGG
+Don't set channel fatal status in ReadABuff unless error is TFLE.
+
+ Rev 1.48 21 Aug 1993 03:50:02 GREGG
+Translate GEN_ERR_NO_DATA as TF_NO_MORE_DATA in MoveFileMarks, and let
+the translator determine if it's an error.
+
+ Rev 1.47 12 Jul 1993 17:22:10 GREGG
+Get drv_info again after 1st read to make sure we have the right block size.
+
+ Rev 1.46 30 Jun 1993 09:03:22 GREGG
+Don't skip the default size when scanning for the right block size.
+
+ Rev 1.45 19 May 1993 19:03:54 DON
+Don't continue to use cur_buff if it's NULL in ReadABuff
+
+ Rev 1.44 26 Apr 1993 11:45:50 GREGG
+Seventh in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Changed handling of EOM processing during non-OTC EOS processing.
+
+Matches CHANNEL.H 1.17, MAYN40RD.C 1.60, TFWRITE.C 1.63, MTF.H 1.5,
+ TFLUTILS.C 1.44, MTF10WDB.C 1.10, MTF10WT.C 1.9
+
+ Rev 1.43 15 Apr 1993 23:23:22 ZEIR
+357.0235 - Unitialized locals in ReadNewTape causing later problems w/ buffer
+allocation.
+
+ Rev 1.42 14 Apr 1993 01:59:54 GREGG
+Fixes to deal with non-ffr tapes in ffr drives (i.e. EXB2200 in EXB5000).
+
+ Rev 1.41 31 Mar 1993 16:03:28 GREGG
+Added GEN_ERR_UNRECONIZED_MEDIA to MapGenErr2UIMesg.
+
+ Rev 1.40 17 Mar 1993 14:50:56 GREGG
+This is Terri Lynn. Added Gregg's changes for switching a tape drive's
+block mode to match the block size of the current tape.
+
+ Rev 1.39 09 Mar 1993 18:15:22 GREGG
+Initial changes for new stream and EOM processing.
+
+ Rev 1.38 04 Feb 1993 18:48:48 DON
+Don't set the buffer size to stream size if variable length stream
+
+ Rev 1.37 30 Jan 1993 11:51:28 DON
+Removed compiler warnings
+
+ Rev 1.36 20 Jan 1993 17:33:48 BobR
+Changes to MOVE_ESA macro calls
+
+ Rev 1.35 18 Jan 1993 14:27:28 BobR
+Added MOVE_ESA macro calls
+
+ Rev 1.34 11 Nov 1992 22:27:14 GREGG
+Unicodeized literals.
+
+ Rev 1.33 22 Oct 1992 15:53:16 HUNTER
+New Stream Stuff
+
+ Rev 1.32 22 Sep 1992 09:14:14 GREGG
+Initial changes to handle physical block sizes greater than 1K.
+
+ Rev 1.31 17 Aug 1992 09:01:18 GREGG
+Changes to deal with block sizeing scheme.
+
+ Rev 1.30 06 Aug 1992 12:09:06 BURT
+Fixed GetData.. to force 1K logical blocks instead of 512 byte physical
+for allocations.
+
+
+ Rev 1.29 27 Jul 1992 13:01:08 GREGG
+Fixed more warnings...
+
+ Rev 1.28 31 May 1992 14:20:56 GREGG
+Sped up DumpDebug.
+
+ Rev 1.27 29 May 1992 15:19:50 GREGG
+Don't set PBA in VCB unless position info isn't available, then make sure its 0.
+
+ Rev 1.26 21 May 1992 16:17:40 GREGG
+Expect TFLE_xxx return values from DetBlockType and GetCurrentVCB.
+
+ Rev 1.25 29 Apr 1992 13:05:54 GREGG
+ROLLER BLADES - Changes for new EOM handling.
+
+ Rev 1.24 25 Mar 1992 17:45:54 GREGG
+ROLLER BLADES - Added 64 bit support.
+
+ Rev 1.23 20 Mar 1992 18:01:48 NED
+added exception updating after TpReceive calls
+
+ Rev 1.22 20 Mar 1992 14:29:46 NED
+added WRITE PROTECT handling to MapGenErr
+
+ Rev 1.21 19 Feb 1992 17:13:58 GREGG
+In ReadABuff, if we can't get a regular buffer, use the VCB buffer.
+
+ Rev 1.20 08 Feb 1992 14:28:48 GREGG
+Removed references to lst_oper in drive stucture (it no longer exits).
+
+ Rev 1.19 25 Jan 1992 15:22:18 GREGG
+Clear AT_EOD pos bit in MoveFileMarks if we are going backward.
+
+ Rev 1.18 03 Jan 1992 13:19:06 NED
+Added DumpDebug() call
+
+ Rev 1.17 02 Jan 1992 14:57:24 NED
+Buffer Manager/UTF translator integration.
+
+ Rev 1.16 05 Dec 1991 13:49:30 GREGG
+SKATEBOARD - New Buff Mgt - Initial Integration.
+
+ Rev 1.15 04 Nov 1991 18:54:06 GREGG
+Check return from Tp calls. Cleaned up error handling in MoveFileMarks.
+
+ Rev 1.14 17 Oct 1991 01:24:26 GREGG
+BIGWHEEL - 8200sx - Initial integration.
+
+ Rev 1.13 19 Sep 1991 13:26:42 GREGG
+Oops! Set the format to new before calling Setup in ReadNewTape.
+
+ Rev 1.12 17 Sep 1991 13:37:02 GREGG
+Fixed logic in ReadNewTape to properly handle continuations.
+
+ Rev 1.11 23 Aug 1991 16:59:38 GREGG
+fixed BM_ macro edit problem in PuntBuffer
+
+ Rev 1.10 22 Aug 1991 16:40:40 NED
+Changed all references to internals of the buffer structure to macros.
+
+ Rev 1.9 14 Aug 1991 13:40:16 GREGG
+Update fmk count even if an error is encountered in MoveFileMarks.
+
+ Rev 1.8 30 Jul 1991 15:36:52 GREGG
+Included 'dddefs.h'.
+
+ Rev 1.7 22 Jul 1991 13:09:16 GREGG
+Removed unneeded call to UI tape positioner and setting of REW_CLOSE bit on
+unexpected EOM from MoveFileMarks routine.
+
+ Rev 1.6 15 Jul 1991 15:18:04 NED
+In new tape processing, if we are looking for a continuation tape, and we get
+a tape with a different format, force a Wrong Tape error, and don't free the
+old format.
+
+ Rev 1.5 09 Jul 1991 16:13:18 NED
+Changed GotoBckUpSet to handle inconsistent set numbering across format changes.
+
+ Rev 1.4 26 Jun 1991 16:25:00 NED
+changed EOS/MOS handling in MoveToVCB
+fixed position update in MoveToVCB
+
+ Rev 1.3 17 Jun 1991 11:41:34 NED
+maintained EOS/MOS status in ReadABuff
+added REW_CLOSE logic to error handling
+added BE_Zprintf messages
+
+ Rev 1.2 06 Jun 1991 22:56:20 NED
+Inherited all the tape positioning routines from drives.c, and made major
+changes to them to deal, in a clean manner, with problems caused by Teac's
+refusal to move over multiple filemark without reads in between, and the
+wonderful concept of appending 3.1 sets to 2.5 tapes! Also added a function
+to map format ID's to their indicies in the table.
+
+ Rev 1.1 10 May 1991 16:17:20 GREGG
+Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:12:18 GREGG
+Initial revision.
+
+**/
+#include <string.h>
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "queues.h"
+#include "drive.h"
+#include "channel.h"
+#include "buffman.h"
+#include "fsys.h"
+#include "lwprotos.h"
+#include "tfl_err.h"
+#include "translat.h"
+#include "tfl_err.h"
+#include "lw_data.h"
+#include "sx.h"
+#include "minmax.h"
+
+#include "be_debug.h"
+
+/* Device Driver InterFace Headers */
+#include "retbuf.h"
+#include "dilhwd.h"
+#include "drvinf.h"
+#include "generr.h"
+#include "dddefs.h"
+#include "dil.h"
+#include "special.h"
+
+
+INT16 SQL_Determiner( CHANNEL_PTR channel ) ;
+
+
+/**/
+/**
+
+ Name: MapGenErr2UIMesg
+
+ Description: Maps a Generic error returned from the device driver into
+ a UI Message. If value is negative, then the error was fatal
+ and the returned value is a TFLE error.
+
+ Returns: A signed integer representing either a UI message or a
+ a fatal Tape Format Layer Error ( TFLE ).
+
+ Notes:
+
+ Declaration:
+
+**/
+
+INT16 MapGenErr2UIMesg(
+ INT16 gen_error ) /* The Generic error returned from the driver */
+{
+ INT16 ret_val = 0 ;
+
+ switch( gen_error ) {
+
+ case GEN_ERR_TIMEOUT:
+ case GEN_ERR_INVALID_CMD:
+ case GEN_ERR_HARDWARE:
+ case GEN_ERR_UNDETERMINED:
+ ret_val = TFLE_DRIVE_FAILURE ;
+ break ;
+
+ case GEN_ERR_NO_MEDIA:
+ ret_val = TF_NO_TAPE_PRESENT ;
+ break ;
+
+ case GEN_ERR_EOM:
+ ret_val = TF_NEED_NEW_TAPE ;
+ break ;
+
+ case GEN_ERR_BAD_DATA:
+ case GEN_ERR_WRONG_BLOCK_SIZE:
+ ret_val = TF_READ_ERROR ;
+ break ;
+
+ case GEN_ERR_ENDSET:
+ break ;
+
+ case GEN_ERR_NO_DATA:
+ ret_val = TF_NO_MORE_DATA ;
+ break ;
+
+ case GEN_ERR_RESET:
+ break ;
+
+ case GEN_ERR_WRT_PROTECT:
+ ret_val = TFLE_WRITE_PROTECT ;
+ break ;
+
+ case GEN_ERR_UNRECOGNIZED_MEDIA:
+ ret_val = TFLE_UNRECOGNIZED_MEDIA ;
+ break ;
+
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Name: GetDBLKMapStorage
+
+ Description: Points channel->map_entry to the next available space
+ in the DBLK map. If there isn't enough space to add
+ another entry, an attempt is made to realloc additional
+ space.
+
+ Returns: TFLE_xxx error code.
+
+ Notes: The initial allocation will almost always be ample, and
+ the reallocation request is small. So if your failing
+ on attempts in this function, chances are your problem
+ is something other than a simple low memory condition.
+
+**/
+
+INT16 GetDBLKMapStorage(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+ INT16 ret_val = TFLE_NO_ERR ;
+
+ /* check for enough remaining size for map entry */
+ if( ( BM_NoDblks( buffer ) + 1 ) * sizeof( DBLKMAP ) > BM_AuxSize( buffer ) ) {
+ ret_val = BM_ReallocAux( &channel->buffer_list, buffer ) ;
+ }
+
+ if( ret_val == TFLE_NO_ERR ) {
+ channel->map_entry = (DBLKMAP_PTR)BM_AuxBase( buffer ) +
+ BM_NoDblks( buffer ) ;
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Name: GetDATAStorage
+
+ Description: Allocates a chunk of a buffer for a data space.
+
+ Returns: A pointer to the space, or a NULL if no space is available.
+
+ Notes: THIS DOES NOT UPDATE THE COUNTS IN THE BUFFER, YOU MUST
+ CALL "BM_UpdCnts" to do that.
+
+ Declaration:
+
+**/
+
+UINT8_PTR GetDATAStorage(
+ CHANNEL_PTR channel, /* I - the current channel */
+ UINT16_PTR size_avail_ptr ) /* O - Where I store the buffer size */
+{
+ UINT8_PTR tmp_ptr = NULL ;
+
+ if ( BM_BytesFree( channel->cur_buff ) != 0 ) {
+ tmp_ptr = (UINT8_PTR)BM_NextBytePtr( channel->cur_buff ) ;
+
+ if( U64_LT( channel->current_stream.size,
+ U32_To_U64( (UINT32)BM_BytesFree( channel->cur_buff ) ) ) &&
+ ! ( channel->current_stream.tf_attrib & STREAM_VARIABLE ) ) {
+
+ *size_avail_ptr = (UINT16)U64_Lsw( channel->current_stream.size ) ;
+ } else {
+ *size_avail_ptr = BM_BytesFree( channel->cur_buff ) ;
+ }
+ } else {
+ *size_avail_ptr = 0 ;
+ }
+
+ return( tmp_ptr ) ;
+}
+
+
+/**/
+/**
+
+ Name: SnagBuffer
+
+ Description: This functions attempts for get a buffer from the pool
+ and, updates the channel counts.
+
+ Returns: A Pointer to the buffer, or NULL if one wasn't allocated.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+BUF_PTR SnagBuffer( CHANNEL_PTR channel ) /* I/O - channel pointer */
+{
+ if( channel->cur_buff == NULL ) {
+ channel->cur_buff = BM_Get( &channel->buffer_list ) ;
+ }
+ return( channel->cur_buff ) ;
+}
+
+/**/
+/**
+
+ Name: PuntBuffer
+
+ Description: Puts the current channels buffer back on the free queue.
+
+ Returns: Nothing.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+VOID PuntBuffer( CHANNEL_PTR channel ) /* I/O - channel pointer */
+{
+ if( channel->cur_buff != NULL ) {
+ if( channel->cur_fmt != UNKNOWN_FORMAT ) {
+ channel->blocks_used +=
+ ( BM_NextByteOffset( channel->cur_buff )
+ + BM_BytesFree( channel->cur_buff ) )
+ / channel->lb_size ;
+ }
+ BM_Put( channel->cur_buff ) ;
+ channel->cur_buff = NULL ;
+ }
+}
+
+
+/**/
+/**
+
+ Name: ReadABuff
+
+ Description: Read in a single buffer
+
+ Returns: TFLE_xxx codes
+
+ Notes: factored out of ReadNextSet code
+
+ Declaration:
+
+**/
+INT16 ReadABuff(
+ CHANNEL_PTR channel,
+ BOOLEAN try_resize,
+ BOOLEAN_PTR resized_buff )
+{
+ INT16 drv_hdl = channel->cur_drv->drv_hdl ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ INT size_index = 0 ;
+ DRIVE_PTR curDRV = channel->cur_drv ;
+ RET_BUF myret ;
+ UINT32 eos_mos_state = curDRV->pos_inf & ( AT_EOS | AT_MOS ) ;
+ BOOLEAN done = FALSE ;
+ UINT16 def_size = ChannelBlkSize( channel ) ;
+
+ *resized_buff = FALSE ;
+
+ if( SnagBuffer( channel ) == NULL ) {
+ channel->cur_buff = BM_GetVCBBuff( &channel->buffer_list ) ;
+ }
+
+ if ( channel->cur_buff == NULL ) {
+ msassert(FALSE);
+ return TFLE_NO_MEMORY;
+ }
+
+ BM_InitBuf( channel->cur_buff ) ;
+ ClrPosBit( curDRV, ( AT_EOS | AT_MOS ) ) ;
+ ClrChannelStatus( channel, CH_DONE ) ;
+ BE_Zprintf(DEBUG_TAPE_FORMAT, RES_TP_READ ) ;
+
+ while( !done ) {
+ done = TRUE ;
+ if( TpRead( drv_hdl, BM_XferBase( channel->cur_buff ), (UINT32)BM_XferSize( channel->cur_buff ) ) == FAILURE ) {
+ SetChannelStatus( channel, CH_FATAL_ERR ) ;
+ ret_val = TFLE_DRIVER_FAILURE ;
+ break ;
+ }
+ while( TpReceive( drv_hdl, &myret ) == FAILURE ) {
+ /* for non-preemptive operating systems: */
+ ThreadSwitch( ) ;
+ }
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( channel->cur_drv->thw_inf.the, myret.the ) ;
+
+ BE_Zprintf(DEBUG_TAPE_FORMAT, RES_DRV_ERROR_BYTES_RCVD, myret.gen_error, myret.len_req, myret.len_got ) ;
+ BM_SetBytesFree( channel->cur_buff, (UINT16)myret.len_got ) ;
+ BM_SetReadError( channel->cur_buff, myret.gen_error ) ;
+
+ if( myret.gen_error ) {
+ channel->cur_drv->thw_inf.drv_status = myret.status ;
+ DumpDebug( drv_hdl ) ;
+ ret_val = MapGenErr2UIMesg( myret.gen_error ) ;
+
+ /* This is to handle the erasure of tape by placing a
+ filemark at the head of them.
+ */
+ if( ( myret.len_got == 0L &&
+ myret.gen_error == GEN_ERR_ENDSET ) ||
+ myret.gen_error == GEN_ERR_NO_DATA ) {
+
+ /* If we got no data, we be where we was. */
+ SetPosBit( curDRV, eos_mos_state ) ;
+ ret_val = TF_NO_MORE_DATA ;
+
+ } else if( myret.gen_error == GEN_ERR_UNRECOGNIZED_MEDIA ) {
+ ret_val = TF_UNRECOGNIZED_MEDIA ;
+
+ } else if( IsTFLE( ret_val ) && ret_val != TFLE_UNRECOGNIZED_MEDIA ) {
+ SetChannelStatus( channel, CH_FATAL_ERR ) ;
+ }
+
+ if( myret.gen_error == GEN_ERR_ENDSET ||
+ myret.gen_error == GEN_ERR_EOM ) {
+
+ channel->cur_drv->cur_pos.fmks++ ;
+ }
+
+ /* This is to deal with drives which don't have any idea what
+ block size the tape was written with. It is only done on
+ the initial read. If the gen_error is WRONG_BLOCK_SIZE,
+ we go through a list of valid sizes in an attempt to find
+ the right size to read the tape. If we exhaust the list,
+ we report it as a FOREIGN tape.
+ */
+ if( myret.gen_error == GEN_ERR_WRONG_BLOCK_SIZE ) {
+
+ ClrChannelStatus( channel, CH_FATAL_ERR ) ;
+
+ if( !try_resize || size_index == lw_num_blk_sizes ) {
+ if( try_resize ) {
+ ret_val = SetDrvBlkSize( channel,
+ channel->cur_buff,
+ def_size,
+ resized_buff ) ;
+ }
+ if( ret_val == TFLE_NO_ERR ) {
+ ret_val = TF_INVALID_VCB ;
+ }
+ } else {
+ if( ( ret_val = RewindDrive( curDRV, NULL, FALSE, TRUE, 0 ) ) == TFLE_NO_ERR ) {
+ ret_val = SetDrvBlkSize( channel,
+ channel->cur_buff,
+ lw_blk_size_list[size_index],
+ resized_buff ) ;
+ size_index++ ;
+ done = FALSE ;
+ }
+ }
+ }
+ }
+ }
+
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Name: MoveNextSet
+
+ Description: Moves to the next set and reads a buffer.
+
+ Returns:
+
+ Notes:
+
+ Declaration:
+
+**/
+INT16 MoveNextSet(
+ CHANNEL_PTR channel,
+ TPOS_PTR ui_tpos )
+{
+ INT16 ret_val = TFLE_NO_ERR ;
+ DRIVE_PTR curDRV = channel->cur_drv ;
+ DBLK_PTR hld_dblk = NULL ;
+ BOOLEAN need_a_buff = FALSE ;
+ BOOLEAN dummy ;
+ BE_Zprintf(0, TEXT("MoveNextSet( cur_fmt=%d )\n"), channel->cur_fmt) ;
+
+ if ( channel->cur_fmt == UNKNOWN_FORMAT ) {
+ SetPosBit( channel->cur_drv, REW_CLOSE ) ;
+ ret_val = TFLE_TRANSLATION_FAILURE ;
+ goto error ;
+ }
+
+ ClrPosBit( curDRV, AT_EOD ) ;
+ hld_dblk = channel->cur_dblk ;
+
+ /* If both the Beginning of Tape and the End of Set bits are set, on
+ entrance to this function, We are no longer at BOT Set */
+ if( ( IsPosBitSet( curDRV, AT_BOT ) && IsPosBitSet( curDRV, AT_EOS ) ) ) {
+ ClrPosBit( curDRV, AT_BOT ) ;
+ }
+
+ if ( ( ret_val = MoveToVCB( channel, (INT16)1, & need_a_buff, FALSE ) ) != TFLE_NO_ERR ) {
+ goto error ;
+ }
+
+ if( need_a_buff ) {
+ if ( ( ret_val = ReadABuff( channel, FALSE, &dummy ) ) != TFLE_NO_ERR ) {
+ goto error ;
+ }
+ }
+
+ /* here for error processing */
+error :
+
+ if( ret_val == TF_NO_MORE_DATA ) {
+ SetPosBit( curDRV, AT_EOD ) ;
+ }
+
+ channel->cur_dblk = hld_dblk ;
+
+ BE_Zprintf(0, TEXT("MoveNextSet() return=%d\n"), ret_val) ;
+
+ return( ret_val ) ;
+ (VOID)ui_tpos;
+}
+/**/
+/**
+
+ Name: ReadThisSet
+
+ Description: Called with buffer in channel->cur_buff, reads current
+ VCB.
+
+ Returns: TFLE_xxxx code.
+
+ Notes:
+
+ Declaration:
+
+**/
+INT16 ReadThisSet( CHANNEL_PTR channel ) /* The current Channel */
+{
+ INT16 ret_val = TFLE_NO_ERR ;
+ DRIVE_PTR curDRV = channel->cur_drv ;
+ DBLK_PTR hld_dblk ;
+ UINT16 blk_type ;
+
+ BE_Zprintf( 0, TEXT("ReadThisSet( cur_fmt=%d )\n"), channel->cur_fmt ) ;
+
+ hld_dblk = channel->cur_dblk ;
+
+ msassert( channel->cur_fmt != UNKNOWN_FORMAT ) ;
+
+ if( ( ret_val = DetBlockType( channel, channel->cur_buff, &blk_type ) ) != TFLE_NO_ERR ) {
+ goto error ;
+ }
+ if( blk_type == BT_CVCB ) {
+ ret_val = TF_NEED_NEW_TAPE ;
+ goto error ;
+ }
+
+ /* handle appended dissimilar sets */
+
+ if ( VerifyVCB( channel, channel->cur_buff ) == FALSE ) {
+ FreeFormatEnv( &( channel->cur_fmt ), &( channel->fmt_env ) ) ;
+ if( ( channel->cur_fmt = DetermineFormat( BM_XferBase( channel->cur_buff ),
+ (UINT32)BM_BytesFree( channel->cur_buff ) ) ) == UNKNOWN_FORMAT ) {
+ curDRV->vcb_valid = FALSE ;
+ SetPosBit( channel->cur_drv, REW_CLOSE ) ;
+ ret_val = TFLE_UNKNOWN_FMT ;
+ goto error ;
+ }
+ if( ( ret_val = SetupFormatEnv( channel ) ) != TFLE_NO_ERR ) {
+ goto error ;
+ }
+ }
+
+ /* now get the VCB */
+ channel->cur_dblk = & curDRV->cur_vcb ;
+
+ if ( ( ret_val = GetCurrentVCB( channel, channel->cur_buff ) ) != TFLE_NO_ERR ) {
+ curDRV->vcb_valid = FALSE ;
+ goto error ;
+ }
+
+ /* We Know The block type & It's a VCB, so tell the drive */
+ curDRV->vcb_valid = TRUE ;
+ curDRV->cur_pos.lba_vcb = FS_ViewLBAinDBLK( channel->cur_dblk ) ;
+
+ /* We need to supply 0 for pba_vcb for those translators
+ * which don't support Fast File Restore.
+ */
+ if( !( lw_fmtdescr[channel->cur_fmt].attributes & POS_INF_AVAIL ) ) {
+ FS_SetPBAinVCB( channel->cur_dblk, 0 ) ;
+ }
+
+ /* if the SX was looking for a VCB during a tape scan now we know it found one */
+ if( SupportSXShowBlk( channel->cur_drv ) && SX_IsStatusSet( channel, SX_LIST_TAPE_IN_PROGRESS ) ) {
+
+ if( SX_IsStatusSet( channel, SX_VCB_PENDING ) ) {
+ SX_SetType( channel, SX_VCB_CONFIRMED ) ;
+ }
+ }
+
+ /* here for error processing */
+error :
+
+ channel->cur_dblk = hld_dblk ;
+
+ BE_Zprintf( 0, TEXT("ReadThisSet() return=%d\n"), ret_val ) ;
+
+ return( ret_val ) ;
+}
+/**/
+/**
+
+ Name: ReadNewTape
+
+ Description: Gets an initial buffer from a new tape, prior to
+ calling ReadThisSet().
+
+ Returns: TFLE_xxx code
+
+ Notes: The 'try_resize' flag sent to ReadABuff is to deal with
+ drives which don't have any idea what block size the
+ tape was written with. Here are the cases in which
+ ReadNewTape is called, and how we deal with each:
+
+ 1. Called by PollDrive - 'read_tape' will be FALSE,
+ and PollDrive will have taken care of adjusting the
+ block size.
+ 2. Called in read mode - Allow resize.
+ 3. Called in read-continue mode - If the block size
+ doesn't match, this can't be the right continuation
+ tape. Don't allow resize.
+ 4. Called in write mode - Allow resize. Note that
+ whether they overwrite or append, we're going to
+ stick with the block size the tape was originally
+ written with.
+ 5. Called in write-continue mode - Allow resize, but
+ after tape is read, change back to the original
+ size. Note that if they want to overwrite the tape
+ we must write the same block size as we did on the
+ previous tape, and if they don't want to overwrite
+ it there is no more need to read it.
+
+ Declaration:
+
+**/
+INT16 ReadNewTape(
+ CHANNEL_PTR channel, /* The current Channel */
+ TPOS_PTR ui_tpos, /* So I can tell him I'm doing something */
+ BOOLEAN read_tape )
+{
+ INT16 ret_val = TFLE_NO_ERR ;
+ DRIVE_PTR curDRV = channel->cur_drv ;
+ DBLK_PTR hld_dblk ;
+ BOOLEAN need_a_buff = FALSE ;
+ BOOLEAN try_resize = FALSE ;
+ BOOLEAN resized_buff = FALSE ;
+ UINT16 new_fmt = UNKNOWN_FORMAT ;
+ BOOLEAN write_mode = FALSE ;
+ BOOLEAN cont_mode = FALSE ;
+ UINT16 save_size = ChannelBlkSize( channel ) ;
+ BOOLEAN dummy ;
+
+ if( ( ( channel->mode & ~0x8000 ) == TF_WRITE_OPERATION ) ||
+ ( ( channel->mode & ~0x8000 ) == TF_WRITE_APPEND ) ) {
+ write_mode = TRUE ;
+ }
+ cont_mode = IsChannelStatus( channel, CH_CONTINUING ) ? TRUE : FALSE ;
+
+ ClrPosBit( curDRV, AT_EOD ) ;
+ hld_dblk = channel->cur_dblk ;
+
+ if ( read_tape ) {
+
+ try_resize = ( DriveAttributes( curDRV ) & TDI_CHNG_BLK_SIZE ) ? TRUE : FALSE ;
+
+ if ( ( ret_val = ReadABuff( channel, try_resize, &resized_buff ) ) != TFLE_NO_ERR ) {
+ goto error ;
+ }
+
+ if ( BM_BytesFree( channel->cur_buff ) == 0 ) {
+ ret_val = TF_EMPTY_TAPE ;
+ goto error ;
+ }
+ }
+
+ if( TpSpecial( curDRV->drv_hdl, (INT16)SS_GET_DRV_INF, ( UINT32 )&curDRV->thw_inf.drv_info ) == FAILURE ) {
+ ret_val = TFLE_DRIVE_FAILURE ;
+ goto error ;
+ }
+
+ /* see if format has changed */
+
+ new_fmt = DetermineFormat( BM_XferBase( channel->cur_buff ), (UINT32)BM_BytesFree( channel->cur_buff ) ) ;
+
+ if( new_fmt == UNKNOWN_FORMAT &&
+ (ret_val = SQL_Determiner( channel )) != TFLE_NO_ERR ){
+ goto error ;
+ }
+
+ /* Note: If we are continuing, but the cur_fmt is UNKNOWN then we are */
+ /* in write mode, and we treat this like a new tape with no */
+ /* prior context information known. */
+
+ if( IsChannelStatus( channel, CH_CONTINUING ) && channel->cur_fmt != UNKNOWN_FORMAT ) {
+ if( new_fmt != channel->cur_fmt ) {
+ ret_val = TF_WRONG_TAPE ; /* obviously wrong! */
+ goto error ;
+ }
+ } else {
+ if( new_fmt == UNKNOWN_FORMAT ) {
+ FreeFormatEnv( &( channel->cur_fmt ), &( channel->fmt_env ) ) ;
+ curDRV->vcb_valid = FALSE ;
+ ret_val = TF_INVALID_VCB ;
+ goto error ;
+ }
+ if( new_fmt != channel->cur_fmt ) {
+ FreeFormatEnv( &( channel->cur_fmt ), &( channel->fmt_env ) ) ;
+ channel->cur_fmt = new_fmt ;
+ if( ( ret_val = SetupFormatEnv( channel ) ) != TFLE_NO_ERR ) {
+ goto error ;
+ }
+ }
+ }
+
+ if ( ( ret_val = NewTape( channel, &need_a_buff ) ) != TFLE_NO_ERR ) {
+ goto error ;
+ }
+
+ if( need_a_buff ) {
+ if ( ( ret_val = ReadABuff( channel, FALSE, &dummy ) ) != TFLE_NO_ERR ) {
+ goto error ;
+ }
+ }
+ channel->blocks_used = 0 ;
+
+error :
+
+ if( ret_val != TFLE_NO_ERR ) {
+ if( try_resize ) {
+ SetDrvBlkSize( channel, channel->cur_buff,
+ save_size, &resized_buff ) ;
+ }
+ } else if( write_mode && cont_mode ) {
+ if( try_resize && ChannelBlkSize( channel ) != save_size ) {
+ ret_val = SetDrvBlkSize( channel, channel->cur_buff,
+ save_size, &resized_buff ) ;
+ }
+ } else {
+ if( resized_buff ) {
+ (BM_ListRequirements( &channel->buffer_list ))->a.min_size =
+ (UINT16)lw_blk_size_list[lw_num_blk_sizes-1] ;
+ ret_val = BM_ReSizeList( &channel->buffer_list ) ;
+ }
+ }
+
+ if( ret_val == TF_NO_MORE_DATA ) {
+ SetPosBit( curDRV, AT_EOD ) ;
+ }
+
+ channel->cur_dblk = hld_dblk ;
+
+ return( ret_val ) ;
+ (VOID)ui_tpos;
+}
+/**/
+/**
+
+ Name: GotoBckUpSet
+
+ Description: This function attempts to move smartly to a backup set. It
+ is assumed that the the tape id has been matched and the
+ tape sequence is also correct.
+
+ Called from PositionAtSet().
+
+ Returns: An Error Code.
+
+ Notes: THE "cur_vcb" IN THE DRIVE STRUCTURE MUST BE VALID BEFORE
+ CALLING THIS ROUTINE. THAT IS, IT MUST CONTAIN THE CURRENT
+ VCB. FURTHER, THERE MUST BE A VALID BUFFER STORE IN THE CHANNEL.
+**/
+
+INT16 GotoBckUpSet(
+ CHANNEL_PTR channel,
+ INT16_PTR desired_set_ptr,
+ TPOS_PTR ui_tpos )
+{
+ INT16 desired_set = *desired_set_ptr ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ DRIVE_PTR curDRV = channel->cur_drv ;
+ DBLK_PTR dblk = &curDRV->cur_vcb ;
+ BOOLEAN need_read = FALSE ;
+ INT16 sets_to_move ;
+ UINT16 original_format = channel->cur_fmt ;
+ BOOLEAN resized_buff ;
+ enum {
+ gbs_START = 0,
+ gbs_SEEKING_FORWARD,
+ gbs_MOVING_BACKWARD,
+ gbs_CHECKING_FIRST_SET,
+ gbs_READING_SET_DATA,
+ gbs_MAKING_VCB,
+ gbs_END
+ } state = gbs_START ;
+
+ sets_to_move = desired_set - FS_ViewBSNumInVCB( (VOID_PTR)dblk ) ;
+
+ BE_Zprintf( 0, TEXT("GotoBckUpSet( desired=%d, this=%d )\n"), desired_set, desired_set-sets_to_move ) ;
+
+ while ( state != gbs_END ) {
+
+ BE_Zprintf(0, TEXT(" state %d, %d sets to go\n"), (INT16)state, sets_to_move) ;
+
+ switch ( state ) {
+
+ case gbs_START:
+ if ( sets_to_move > 0 ) {
+ state = gbs_SEEKING_FORWARD ;
+ } else {
+ state = gbs_MOVING_BACKWARD ;
+ }
+ break ;
+
+ case gbs_SEEKING_FORWARD:
+ ret_val = MoveNextSet( channel, ui_tpos ) ;
+ if ( ret_val == TFLE_NO_ERR ) {
+ ret_val = ReadThisSet( channel ) ;
+ }
+ if ( ret_val == TFLE_NO_ERR ) {
+ /* check to see if we have a discrepancy. */
+ if ( --sets_to_move != desired_set - FS_ViewBSNumInVCB( (VOID_PTR)dblk ) ) {
+ if ( channel->cur_fmt != original_format ) { /* we changed translators */
+ *desired_set_ptr = desired_set = FS_ViewBSNumInVCB( (VOID_PTR)dblk ) ; /* this is the one! */
+ } else {
+ ret_val = TFLE_TAPE_INCONSISTENCY ;
+ }
+ state = gbs_END ;
+ }
+ }
+ if ( sets_to_move == 0 || ret_val != TFLE_NO_ERR ) {
+ state = gbs_END ;
+ } else {
+ if ( ui_tpos != NULL ) {
+ ui_tpos->UI_TapePosRoutine( TF_ACCIDENTAL_VCB, ui_tpos, curDRV->vcb_valid, &curDRV->cur_vcb, channel->mode ) ;
+ }
+ }
+ break ;
+
+ case gbs_MOVING_BACKWARD:
+ ret_val = MoveToVCB( channel, sets_to_move, &need_read, FALSE ) ;
+ if ( ret_val == TF_NEED_REWIND_FIRST ) {
+ state = gbs_CHECKING_FIRST_SET ;
+ } else if ( ret_val == TFLE_NO_ERR ) {
+ if ( need_read ) {
+ state = gbs_READING_SET_DATA ;
+ } else {
+ state = gbs_MAKING_VCB ;
+ }
+ } else { /* some error */
+ state = gbs_END ;
+ }
+ break ;
+
+ case gbs_CHECKING_FIRST_SET:
+ if ( ( ( ret_val = RewindDrive( channel->cur_drv, ui_tpos, TRUE, TRUE, channel->mode ) ) == TFLE_NO_ERR )
+ && ( ( ret_val = ReadNewTape( channel, ui_tpos, TRUE ) ) == TFLE_NO_ERR )
+ && ( ( ret_val = ReadThisSet( channel ) ) == TFLE_NO_ERR ) ) {
+ sets_to_move = desired_set - FS_ViewBSNumInVCB( (VOID_PTR)dblk ) ;
+ if ( sets_to_move == 0 ) {
+ state = gbs_END ;
+ } else if ( sets_to_move > 0 ) {
+ state = gbs_SEEKING_FORWARD ;
+ } else { /* wrong tape? bad tape? */
+ SetPosBit( channel->cur_drv, REW_CLOSE ) ;
+ ret_val = TFLE_TAPE_INCONSISTENCY ;
+ state = gbs_END ;
+ }
+ } else { /* some error */
+ state = gbs_END ;
+ }
+ break ;
+
+
+ case gbs_READING_SET_DATA:
+ if ( ( ret_val = ReadABuff( channel, FALSE, &resized_buff ) ) != TFLE_NO_ERR ) {
+ state = gbs_END ;
+ } else {
+ state = gbs_MAKING_VCB ;
+ }
+ break ;
+
+ case gbs_MAKING_VCB:
+ if ( ( ret_val = ReadThisSet( channel ) ) == TFLE_NO_ERR ) {
+ sets_to_move = desired_set - FS_ViewBSNumInVCB( (VOID_PTR)dblk ) ;
+ if ( sets_to_move == 0 ) {
+ state = gbs_END ;
+ } else if ( sets_to_move > 0 ) {
+ state = gbs_SEEKING_FORWARD ;
+ } else { /* need to move backwards? */
+ state = gbs_CHECKING_FIRST_SET ;
+ }
+ } else {
+ state = gbs_END ;
+ }
+ break ;
+
+ default:
+ msassert( FALSE ) ; /* can't happen */
+ break ;
+
+ }
+ }
+
+ if ( ret_val == TFLE_NO_ERR ) {
+ if ( desired_set != FS_ViewBSNumInVCB( (VOID_PTR)dblk ) ) {
+ SetPosBit( channel->cur_drv, REW_CLOSE ) ;
+ ret_val = TFLE_TAPE_INCONSISTENCY ;
+ }
+ }
+
+ BE_Zprintf( 0, TEXT("GotoBckUpSet( ) return=%d\n"), ret_val ) ;
+
+ return ret_val ;
+}
+
+
+/**/
+/**
+
+ Name: MoveFileMarks
+
+ Description: Used by translators' MoveToVCB routines to move
+ forward or backward by given number of filemarks.
+ Does not interpret filemarks.
+
+ Returns: TFLE_xxx code
+
+ Notes: Punts channel buffer. If trying to reverse skip on
+ a drive that doesn't support it, calls RewindDrive
+ and recurses with forward motion.
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 MoveFileMarks(
+ CHANNEL_PTR channel,
+ INT16 number, /* how many file marks */
+ INT16 direction ) /* BACKWARD or FORWARD */
+{
+ DRIVE_PTR curDRV = channel->cur_drv ;
+ TPOS_PTR ui_tpos = channel->ui_tpos ;
+ INT16 drv_hdl = curDRV->drv_hdl ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ RET_BUF myret ;
+ INT16 new_fmks ;
+
+ BE_Zprintf( 0, TEXT("MoveFileMarks( %d )\n"), number * (( direction==FORWARD ) ? 1 : -1 ) ) ;
+
+ PuntBuffer( channel ) ; /* Put the current buffer if any */
+
+ if ( number == 0 ) {
+ return ret_val ;
+ }
+ if( ui_tpos != NULL ) {
+ ui_tpos->UI_TapePosRoutine( TF_SEARCHING, ui_tpos, curDRV->vcb_valid, &curDRV->cur_vcb, channel->mode ) ;
+ }
+
+ if ( direction == BACKWARD ) {
+ ClrPosBit( curDRV, AT_EOD ) ;
+ new_fmks = (INT16)curDRV->cur_pos.fmks - number ;
+ if ( new_fmks < 0 ) {
+ return TFLE_UNEXPECTED_EOM ;
+ }
+ if ( ( new_fmks > 0 ) && ( curDRV->thw_inf.drv_info.drv_features & TDI_REV_FMK ) ) {
+ BE_Zprintf(DEBUG_TAPE_FORMAT, RES_READ_END_SET ) ;
+ if( TpReadEndSet( drv_hdl, number, direction ) == FAILURE) {
+ ret_val = TFLE_DRIVER_FAILURE ;
+ }
+
+ /* Now while away the hours */
+ while( ret_val == TFLE_NO_ERR && TpReceive( drv_hdl, &myret ) == FAILURE ) {
+ if( ui_tpos != NULL ) {
+ /* Move ESA info directly to TPOS instead of going through
+ THW for optimal speed */
+ MOVE_ESA( ui_tpos->the, myret.the ) ;
+
+ if( (*ui_tpos->UI_TapePosRoutine)( TF_IDLE_NOBREAK, ui_tpos, curDRV->vcb_valid, &curDRV->cur_vcb, channel->mode )
+ == UI_ABORT_POSITIONING ) {
+ ret_val = TFLE_USER_ABORT ;
+ }
+ }
+ }
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( channel->cur_drv->thw_inf.the, myret.the ) ;
+
+ if( ret_val == TFLE_NO_ERR && myret.gen_error ) {
+ curDRV->thw_inf.drv_status = myret.status ;
+ if( myret.gen_error == GEN_ERR_NO_DATA || myret.gen_error == GEN_ERR_BAD_DATA ) {
+ SetPosBit( channel->cur_drv, REW_CLOSE ) ;
+ ret_val = TFLE_BAD_TAPE ;
+ } else if ( myret.gen_error == GEN_ERR_EOM ) {
+ ret_val = TFLE_UNEXPECTED_EOM ;
+ } else {
+ ret_val = MapGenErr2UIMesg( myret.gen_error ) ;
+ }
+ /* Note: myret.misc holds the number of fmks NOT skipped. */
+ number -= (INT16)myret.misc ;
+ }
+
+ /* make sure we're on the EOM side of the filemark. */
+ if ( ret_val == TFLE_NO_ERR ) {
+ number-- ;
+ if( TpReadEndSet( drv_hdl, (INT16)1, (INT16)FORWARD ) == FAILURE ) {
+ ret_val = TFLE_DRIVER_FAILURE ;
+ }
+ }
+
+ } else { /* fake reverse motion */
+ if ( ( ret_val = RewindDrive( curDRV, ui_tpos, TRUE, TRUE, channel->mode ) ) == TFLE_NO_ERR ) {
+ if ( new_fmks > 0 ) {
+ ret_val = MoveFileMarks( channel, new_fmks, (INT16)FORWARD ) ;
+ }
+ }
+ return ret_val ;
+ }
+ } else {
+ BE_Zprintf(DEBUG_TAPE_FORMAT, RES_READ_END_SET ) ;
+ if( TpReadEndSet( drv_hdl, number, direction ) == FAILURE) {
+ ret_val = TFLE_DRIVER_FAILURE ;
+ }
+ }
+
+ /* Now while away the hours */
+ while( ret_val == TFLE_NO_ERR && TpReceive( drv_hdl, &myret ) == FAILURE ) {
+ if( ui_tpos != NULL ) {
+ /* Move ESA info directly to TPOS instead of going through
+ THW for optimal speed */
+ MOVE_ESA( ui_tpos->the, myret.the ) ;
+
+ if( (*ui_tpos->UI_TapePosRoutine)( TF_IDLE_NOBREAK, ui_tpos, curDRV->vcb_valid, &curDRV->cur_vcb, channel->mode )
+ == UI_ABORT_POSITIONING ) {
+ ret_val = TFLE_USER_ABORT ;
+ }
+ }
+ }
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( channel->cur_drv->thw_inf.the, myret.the ) ;
+
+ BE_Zprintf(DEBUG_TAPE_FORMAT, RES_DRV_RET, myret.gen_error ) ;
+ if( myret.gen_error ) {
+ curDRV->thw_inf.drv_status = myret.status ;
+ DumpDebug( drv_hdl ) ;
+ }
+
+ if( ret_val == TFLE_NO_ERR && myret.gen_error != GEN_NO_ERR ) {
+ if( myret.gen_error == GEN_ERR_BAD_DATA ) {
+ SetPosBit( channel->cur_drv, REW_CLOSE ) ;
+ ret_val = TFLE_BAD_TAPE ;
+ } else if ( myret.gen_error == GEN_ERR_EOM ) {
+ ret_val = TFLE_UNEXPECTED_EOM ;
+ } else {
+ ret_val = MapGenErr2UIMesg( myret.gen_error ) ;
+ }
+ /* Note: myret.misc holds the number of fmks NOT skipped. */
+ number -= (INT16)myret.misc ;
+ }
+
+ if ( direction == FORWARD ) {
+ curDRV->cur_pos.fmks += (UINT32)number ;
+ } else {
+ curDRV->cur_pos.fmks -= (UINT32)number ;
+ }
+
+ if ( ret_val == TFLE_NO_ERR ) {
+ curDRV->cur_pos.lba = 0 ;
+ }
+
+ BE_Zprintf( 0, TEXT("MoveFileMarks( ) return=%d\n"), ret_val ) ;
+
+ return ret_val ;
+}
+
+
+/**/
+/**
+
+ Name: FormatIndexFromID
+
+ Description: given format ID, returns format table index
+
+ Returns: format table index, or UNKNOWN_FORMAT
+
+ Notes:
+
+**/
+
+UINT16 FormatIndexFromID( UINT16 format_id )
+{
+ UINT16 i ;
+
+ for ( i = 0; i < lw_num_supported_fmts; i++ ) {
+ if ( lw_fmtdescr[i].format_id == format_id ) {
+ return i ;
+ }
+ }
+ return UNKNOWN_FORMAT ;
+}
+
+/**/
+/**
+ * Unit: Tape Format
+ *
+ * Name: DumpDebug
+ *
+ * Modified: Friday, January 3, 1992
+ *
+ * Description: Given the drive handle, prints first 32 bytes of the
+ * last sense data buffer in the debug window.
+ *
+ * Notes:
+ *
+ * Returns: VOID
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ **/
+
+VOID DumpDebug( INT16 drv_hdl )
+{
+ UINT8 sense_data[256] ; /* area to contain raw sense data */
+ UINT16 i ;
+
+ for ( i = 0; i < 32; i++ ) { /* clear first 32 bytes of buffer */
+ sense_data[i] = 0 ;
+ }
+
+ TpSpecial( drv_hdl, (INT16)SS_LAST_STATUS, ( UINT32 )&sense_data ) ;
+
+ BE_Zprintf( 0, TEXT("\nSense Data =\n")) ;
+ BE_Zprintf( 0, TEXT(" %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n"),
+ sense_data[0], sense_data[1], sense_data[2], sense_data[3],
+ sense_data[4], sense_data[5], sense_data[6], sense_data[7],
+ sense_data[8], sense_data[9], sense_data[10], sense_data[11],
+ sense_data[12], sense_data[13], sense_data[14], sense_data[15] ) ;
+ BE_Zprintf( 0, TEXT(" %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n"),
+ sense_data[16], sense_data[17], sense_data[18], sense_data[19],
+ sense_data[20], sense_data[21], sense_data[22], sense_data[23],
+ sense_data[24], sense_data[25], sense_data[26], sense_data[27],
+ sense_data[28], sense_data[29], sense_data[30], sense_data[31] ) ;
+}
+
+
+/**
+
+ Name: SetDrvBlkSize
+
+ Description:
+
+ Returns: TFLE_xxx code
+
+ Notes:
+
+ Declaration:
+
+**/
+
+INT16 SetDrvBlkSize(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer,
+ UINT32 size,
+ BOOLEAN_PTR resized_buff )
+{
+ INT16 ret_val = TFLE_NO_ERR ;
+ DRIVE_PTR curDRV = channel->cur_drv ;
+
+ *resized_buff = FALSE ;
+ if( TpSpecial( curDRV->drv_hdl, SS_CHANGE_BLOCK_SIZE, size ) != SUCCESS ) {
+ ret_val = TFLE_DRIVE_FAILURE ;
+ } else {
+ curDRV->thw_inf.drv_info.drv_bsize = (UINT16)size ;
+ if( BM_XferSize( buffer ) % size != 0 ) {
+ *resized_buff = TRUE ;
+ lw_default_vcb_requirements.a.min_size =
+ lw_default_vcb_requirements.tf_size =
+ lw_default_vcb_requirements.rw_size =
+ (UINT16)lw_blk_size_list[lw_num_blk_sizes-1] ;
+ BM_SetVCBRequirements( &lw_default_vcb_requirements ) ;
+
+ if( !BM_IsVCBBuff( buffer ) ) {
+ (BM_ListRequirements( &channel->buffer_list ))->a.min_size
+ = (UINT16)lw_blk_size_list[lw_num_blk_sizes-1] ;
+ }
+ ret_val = BM_ReSizeBuff( buffer, &channel->buffer_list ) ;
+ }
+ }
+ return( ret_val ) ;
+}
+
+
+/**
+ *
+ * Unit: Tape Format
+ *
+ * Name: SQL_Determiner
+ *
+ * Modified: 12/01/93
+ *
+ * Description: Determines whether we're dealing w/ an MS SQL tape
+ *
+ * Notes:
+ *
+ * Returns: TF_SQL_TAPE - if MS SQL tape
+ * TFLE_NO_ERR - otherwise, unless ReadABuff fails, in which
+ * case we return ReadABuff's excuse
+ *
+ * Global Data: None
+ *
+**/
+
+
+typedef struct {
+ UINT8 std_label[4],
+ volume_name[6],
+ access,
+ reserved[68],
+ ansi_version ;
+} SQL_VOL, *SQL_VOL_PTR ;
+
+typedef struct {
+ UINT8 hdr1_60[60],
+ syscode[8] ;
+} SQL_HDR1, *SQL_HDR1_PTR ;
+
+
+INT16 SQL_Determiner(
+
+ CHANNEL_PTR channel
+)
+{
+ SQL_VOL_PTR sql = (SQL_VOL *)BM_XferBase( channel->cur_buff ) ;
+ SQL_HDR1_PTR hdr ;
+ INT16 ret_val ;
+ BOOLEAN dummy ;
+
+
+ /* DO NOT UNICODIZE THE FOLLOWING CONSTANTS!!! */
+ if( memcmp( sql->std_label, "VOL1", 4 ) ||
+ memcmp( sql->volume_name, "SQ", 2 ) ){
+
+ return TFLE_NO_ERR ;
+ }
+
+ BM_UpdCnts( channel->cur_buff, channel->cur_drv->thw_inf.drv_info.drv_bsize ) ;
+
+ if( !BM_BytesFree( channel->cur_buff ) &&
+ ( ret_val = ReadABuff( channel, FALSE, &dummy ) ) != TFLE_NO_ERR ){
+
+ return ret_val ;
+ }
+
+ hdr = (SQL_HDR1 *)BM_NextBytePtr( channel->cur_buff ) ;
+
+ /* DO NOT UNICODIZE THE FOLLOWING CONSTANT!!! */
+ return memcmp( hdr->syscode, "MSSQL ", 8 ) ? TFLE_NO_ERR : TF_SQL_TAPE ;
+}
diff --git a/private/utils/ntbackup/src/tfopen.c b/private/utils/ntbackup/src/tfopen.c
new file mode 100644
index 000000000..5047c4bde
--- /dev/null
+++ b/private/utils/ntbackup/src/tfopen.c
@@ -0,0 +1,394 @@
+/**/
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tfopen.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the TF_OpenSet() call.
+
+
+ $Log: T:\logfiles\tfopen.c_v $
+
+ Rev 1.37 15 Dec 1993 18:32:56 GREGG
+Make sure channel->cur_buff is NULL when we start. This is a kludge fix
+for a bug found at Microsoft. We need to find out why we're coming into
+TF_OpenSet with a non-null cur_buff, becase this should never happen!
+
+ Rev 1.36 24 Sep 1993 19:31:10 GREGG
+Clear the current_stream structure in the channel before each new operation.
+
+ Rev 1.35 30 Mar 1993 16:15:20 GREGG
+Handle Unrecognized Media error (unformatted DC2000).
+
+ Rev 1.34 09 Mar 1993 18:14:22 GREGG
+Initial changes for new stream and EOM processing.
+
+ Rev 1.33 23 Feb 1993 20:08:10 DON
+Update to calculate hi-water after we've allocated the buffers
+
+ Rev 1.32 11 Nov 1992 10:53:44 GREGG
+Unicodeized literals.
+
+ Rev 1.31 20 Oct 1992 13:59:46 HUNTER
+Deleted references to data stuff in channel.
+
+ Rev 1.30 29 May 1992 15:16:38 GREGG
+Check for CAN_READ_FROM_VCB_BUFF to see if we need to rewind before positioning.
+
+ Rev 1.29 21 May 1992 13:18:50 GREGG
+Initialize new channel element.
+
+ Rev 1.28 05 Apr 1992 18:59:50 GREGG
+Free format env before calling setup as setup won't do it any more.
+
+ Rev 1.27 28 Mar 1992 18:36:42 GREGG
+ROLLER BLADES - OTC - Initial integration.
+
+ Rev 1.26 25 Mar 1992 15:44:32 GREGG
+ROLLER BLADES - Added 64 bit support.
+
+ Rev 1.25 24 Feb 1992 15:18:06 GREGG
+Split TF_OpenSet into TF_OpenTape and TF_OpenSet.
+
+ Rev 1.24 19 Feb 1992 17:08:34 GREGG
+Added vcb_only parameter, and passed it on to PositionAtSet.
+
+ Rev 1.23 08 Feb 1992 14:26:58 GREGG
+Changed check for lst_oper == -1 to check for boolean force_rewind, since
+this is what the lst_oper field in the drive structure had been reduced to.
+
+ Rev 1.22 04 Feb 1992 21:07:58 NED
+Fixed bug in High Water calculation.
+
+ Rev 1.21 16 Jan 1992 18:42:48 NED
+Skateboard: buffer manager changes
+
+ Rev 1.20 15 Jan 1992 01:40:14 GREGG
+Added param to posatset calls indicating if only a VCB of the tape is required.
+
+ Rev 1.19 13 Jan 1992 19:40:44 NED
+Added re-size of list to default requirements and
+conditional freeing of VCB buffer.
+
+ Rev 1.18 13 Jan 1992 16:15:42 NED
+corrected call to BM_IsVCBBuff()
+
+ Rev 1.17 13 Jan 1992 13:50:26 GREGG
+Skateboard - Bug fixes.
+
+ Rev 1.16 09 Jan 1992 15:06:36 ZEIR
+TF_OpenSet now initializes pad_size to 0 !
+
+ Rev 1.15 03 Dec 1991 18:55:40 GREGG
+Call PositionAtSet even if there isn't a tape in the drive (he handles it).
+
+ Rev 1.14 03 Dec 1991 11:44:32 GREGG
+SKATEBOARD - New Buff Mgr - Initial integration.
+
+ Rev 1.13 04 Nov 1991 17:16:08 GREGG
+Count the hold buffer among the buffs used.
+
+ Rev 1.12 23 Oct 1991 08:41:28 GREGG
+BIGWHEEL - EPR #8 - Uninitialized tpos ptr was being sent to RewindDrive.
+
+ Rev 1.11 17 Oct 1991 01:29:16 GREGG
+BIGWHEEL - 8200sx - Initial integration.
+
+ Rev 1.10 14 Oct 1991 11:01:06 GREGG
+Modifications to more properly deal with the mount process.
+
+ Rev 1.9 07 Oct 1991 22:18:44 GREGG
+Make sure the fmt env pointers are maintained in only one place at any given time.
+
+ Rev 1.8 17 Sep 1991 11:44:02 GREGG
+Expect TFLE_xxx return from SetupFormatEnv.
+Don't throw away Hold Buffer after write operation.
+Be smarter about tape mounting and status checking.
+
+ Rev 1.7 28 Aug 1991 09:49:36 GREGG
+Mark vcb as invalid on fatal error exit from TF_OpenSet.
+
+ Rev 1.6 15 Jul 1991 15:06:16 NED
+Removed reference to unused channel status bits; added clear of CH_CONTINUING.
+
+ Rev 1.5 10 Jul 1991 16:30:02 NED
+Properly freed environment, translator, etc. when tape changed
+or removed between TF_CloseSet() and TF_OpenSet(). Added code
+to take Archive QIC drives into account.
+
+ Rev 1.4 17 Jun 1991 11:44:02 NED
+deleted SHORT_SET logic
+caught failure of SetupFormatEnv() as NO_MEMORY error
+
+ Rev 1.3 10 Jun 1991 13:53:24 GREGG
+Don't free the format env. unless we have a fatal error on the channel.
+
+ Rev 1.2 06 Jun 1991 22:25:10 GREGG
+Various changes to handling of format environment.
+
+ Rev 1.1 10 May 1991 16:08:06 GREGG
+Ned's new stuff
+
+ Rev 1.0 10 May 1991 10:12:12 GREGG
+Initial revision.
+
+**/
+/* begin include list */
+#include <string.h>
+#include <stdtypes.h>
+#include <queues.h>
+#include "stdmath.h"
+
+#include "drive.h"
+#include "channel.h"
+#include "lw_data.h"
+#include "tfl_err.h"
+#include "lwdefs.h"
+#include "tflopen.h"
+#include "lwprotos.h"
+#include "tflproto.h"
+#include "translat.h"
+#include "sx.h"
+
+/* Device Driver Interface Files */
+#include "retbuf.h"
+#include "special.h"
+#include "dilhwd.h"
+#include "drvinf.h"
+#include "generr.h"
+#include "genfuncs.h"
+#include "genstat.h"
+#include "dil.h"
+
+#include "be_debug.h"
+
+/**/
+/**
+
+ Name: TF_OpenTape
+
+ Description: Opens a channel for an operation. This is the first call
+ that must be made before any subsequent operation can take
+ place.
+
+ Returns: INT16, a TFLE_xxx code.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+INT16 TF_OpenTape(
+ INT16_PTR channel_no, /* channel number */
+ THW_PTR sdrv, /* starting drive */
+ TPOS_PTR tape_position ) /* position info */
+{
+ UINT16 i ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ CHANNEL_PTR channel = NULL ;
+ BOOLEAN is_tape_present ;
+
+ BE_Zprintf( 0, TEXT("TF_OpenTape()\n") ) ;
+
+ for( i = 0 ; i < lw_tfl_control.no_channels ; i++ ) {
+ if( !InUse( &lw_channels[i] ) ) {
+ tape_position->channel = *channel_no = i ;
+ channel = &lw_channels[i] ;
+ break ;
+ } else {
+ ret_val = TFLE_NO_FREE_CHANNELS ;
+ }
+ }
+
+ if( ret_val == TFLE_NO_ERR ) {
+
+ /* No matter what this channel is open */
+ channel->status = CH_IN_USE ; /* clear all other channel status bits */
+ lw_tfl_control.no_chans_open++ ;
+ channel->cur_drv = (DRIVE_PTR)(VOID_PTR)sdrv ;
+
+ if( channel->cur_drv->tape_mounted ) {
+ msassert( FALSE ) ;
+ } else {
+ ret_val = MountTape( channel->cur_drv, tape_position, &is_tape_present ) ;
+ }
+ }
+
+ /* if there is an error */
+ if ( ret_val != TFLE_NO_ERR && channel != NULL ) {
+
+ if( ret_val == TF_UNRECOGNIZED_MEDIA ) {
+ ret_val = TFLE_UNRECOGNIZED_MEDIA ;
+ }
+
+ /* then handle as fatal error */
+ channel->cur_drv->vcb_valid = FALSE ;
+ SetChannelStatus( channel, CH_FATAL_ERR ) ;
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**
+
+ Name: TF_OpenSet
+
+ Description: Opens a channel for an operation. This is the first call
+ that must be made before any subsequent operation can take
+ place.
+
+ Returns: INT16, a TFLE_xxx code.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+INT16 TF_OpenSet(
+ TFL_OPBLK_PTR open_info, /* The opening Parameter Stuff */
+ BOOLEAN vcb_only ) /* Caller doesn't intend to go into read or write loop */
+{
+ UINT16 index ;
+ INT16 nbuffs ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ CHANNEL_PTR channel ;
+
+ BE_Zprintf( DEBUG_TAPE_FORMAT, RES_TF_OPEN_SET ) ;
+
+ channel = &lw_channels[open_info->channel] ;
+
+ /* Setup Starting drive for this channel before taking care of the SX stuff */
+ channel->cur_drv = (DRIVE_PTR)(VOID_PTR)open_info->sdrv ;
+
+ /* No matter what do the SX stuff in case any drive in the channel is an SX */
+ channel->sx_info.cat_enabled = open_info->cat_enabled ;
+ SX_Begin( channel, open_info->mode ) ;
+
+ /* Initialize important local channel variables */
+ channel->perm_filter = open_info->perm_filter ;
+ channel->cur_fsys = open_info->fsh ;
+ /* strip off the operation bits from the mode */
+ channel->mode = open_info->mode & ~TF_OPERATION_MASK ;
+ channel->eom_id = 0L ;
+ channel->hiwater = channel->buffs_enqd = 0 ;
+ channel->retranslate_size = CH_NO_RETRANSLATE_40 ;
+ channel->blocks_used = 0L ;
+ channel->read_from_tape = TRUE ;
+ channel->hold_buff = NULL ;
+ memset( &channel->current_stream, 0, sizeof( STREAM_INFO ) ) ;
+ if( channel->cur_buff != NULL ) {
+ BM_Put( channel->cur_buff ) ;
+ channel->cur_buff = NULL ;
+ }
+
+ if ( channel->cur_drv->last_fmt_env != NULL ) {
+ channel->cur_fmt = channel->cur_drv->last_cur_fmt ;
+ channel->fmt_env = channel->cur_drv->last_fmt_env ;
+ channel->cur_drv->last_cur_fmt = UNKNOWN_FORMAT ;
+ channel->cur_drv->last_fmt_env = NULL ;
+ }
+
+ if( channel->cur_drv->hold_buff != NULL ) {
+ BE_Zprintf( DEBUG_TAPE_FORMAT, RES_HOLD_BUFFER ) ;
+ channel->cur_buff = channel->cur_drv->hold_buff ;
+ BM_UnReserve( channel->cur_buff );
+ channel->cur_drv->hold_buff = NULL ;
+ }
+
+ /* The last set of conditions indicates we were using a vcb-only
+ buffer and have a format which can't start reading from it,
+ so we need to rewind and re-read.
+ */
+ if( ( channel->cur_drv->thw_inf.drv_status & ( TPS_NEW_TAPE | TPS_RESET | TPS_NO_TAPE ) )
+ || channel->cur_drv->force_rewind
+ || open_info->rewind_sdrv
+ || ( channel->cur_buff != NULL
+ && BM_IsVCBBuff( channel->cur_buff )
+ && !vcb_only
+ && !( lw_fmtdescr[ channel->cur_fmt ].attributes & CAN_READ_FROM_VCB_BUFF ) ) ) {
+
+ channel->cur_drv->force_rewind = FALSE ;
+ if( channel->cur_buff ) {
+ BM_Put( channel->cur_buff ) ;
+ channel->cur_buff = NULL ;
+ }
+
+ FreeFormatEnv( &channel->cur_fmt, &channel->fmt_env ) ;
+ if( !( channel->cur_drv->thw_inf.drv_status & ( TPS_NO_TAPE ) ) ) {
+ ret_val = RewindDrive( channel->cur_drv, open_info->tape_position, TRUE, TRUE, channel->mode ) ;
+ }
+ }
+
+ /* if we have no valid translator */
+ if ( channel->cur_fmt == UNKNOWN_FORMAT ) {
+ /* re-size the list to defaults */
+ BM_SetListRequirements( &channel->buffer_list, &lw_default_bm_requirements );
+ BM_ReSizeList( &channel->buffer_list );
+ }
+
+ if( ret_val == TFLE_NO_ERR ) {
+ /* Okie-Dokie ... find that backup set */
+ channel->ui_tpos = open_info->tape_position ;
+ ClrPosBit( channel->cur_drv, NO_STAT ) ;
+ ret_val = PositionAtSet( channel, open_info->tape_position, vcb_only ) ;
+ }
+
+ if ( ret_val == TFLE_NO_ERR ) {
+ /* if we're in a write mode */
+ if ( channel->mode == TF_WRITE_OPERATION ||
+ channel->mode == TF_WRITE_CONTINUE ||
+ channel->mode == TF_WRITE_APPEND ) {
+
+ /* then set the write format */
+ index = FormatIndexFromID( open_info->wrt_format ) ;
+ msassert( index != UNKNOWN_FORMAT ) ;
+ msassert( ( lw_fmtdescr[index].attributes&WT_FORMAT_BIT ) == WT_FORMAT_BIT ) ;
+ if ( ( channel->mode == TF_WRITE_APPEND ) &&
+ ( ! ( lw_fmtdescr[channel->cur_fmt].attributes&APPEND_SUPPORTED ) ) ) {
+ /* BAD IDEA !!! */
+ msassert( FALSE ) ;
+ return TFLE_PROGRAMMER_ERROR1 ;
+ }
+ if( channel->cur_fmt != index ) {
+ FreeFormatEnv( &channel->cur_fmt, &channel->fmt_env ) ;
+ channel->cur_fmt = index ;
+ }
+ ret_val = SetupFormatEnv( channel ) ;
+ }
+ }
+
+ /* if there is an error */
+ if ( ret_val != TFLE_NO_ERR ) {
+
+ /* if it's not a user condition (handled in positioner) */
+ if ( ret_val != TFLE_USER_ABORT && ret_val != TFLE_UI_HAPPY_ABORT ) {
+
+ /* then handle as fatal error */
+ FreeFormatEnv( &( channel->cur_fmt ), &( channel->fmt_env ) ) ;
+ channel->cur_drv->vcb_valid = FALSE ;
+ SetChannelStatus( channel, CH_FATAL_ERR ) ;
+ }
+ } else {
+ /* Set the channel hi-water mark */
+ /* are we in non-DMA mode? */
+ if ( lw_tfl_control.cntl_cards[ channel->cur_drv->thw_inf.card_no ].card_attribs & DD_CARD_NON_ASYNC ) {
+ channel->hiwater = 1;
+ } else {
+ /* DMA mode */
+ /* set channel hi-water mark to 3/4 * (number_of_buffers-1) */
+ nbuffs = BM_ListCount( &channel->buffer_list );
+ channel->hiwater = ( nbuffs >= 4 ) ? ( ( nbuffs - 1 ) * 3/4 ) : nbuffs ;
+ }
+ }
+
+ BE_Zprintf( DEBUG_TAPE_FORMAT, RES_END_OF_TFOPEN_SET, ret_val,
+ BM_ListCount( &channel->buffer_list ), channel->hiwater ) ;
+
+ return( ret_val ) ;
+}
diff --git a/private/utils/ntbackup/src/tfpoll.c b/private/utils/ntbackup/src/tfpoll.c
new file mode 100644
index 000000000..43063df7f
--- /dev/null
+++ b/private/utils/ntbackup/src/tfpoll.c
@@ -0,0 +1,1077 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-91
+
+
+ Name: tfpoll.c
+
+ Description: This module contains the API TF_PollDrive.
+
+ $Log: T:\logfiles\tfpoll.c_v $
+
+ Rev 1.31.1.6 14 Feb 1994 16:52:04 GREGG
+Handle TF_NO_MORE_DATA return from ReadNewTape or ReadThisSet as foreign tape.
+
+ Rev 1.31.1.5 04 Feb 1994 12:37:34 GREGG
+Fixed potential access of pd_channel when it's NULL.
+
+ Rev 1.31.1.4 28 Jan 1994 11:26:46 GREGG
+Handle GEN_ERR_UNRECOGNIZED_MEDIA returned on reads as well as mounts.
+
+ Rev 1.31.1.3 17 Dec 1993 16:39:58 GREGG
+Extended error reporting.
+
+ Rev 1.31.1.2 30 Nov 1993 18:26:08 GREGG
+Handle TF_SQL_TAPE response from ReadNewTape.
+
+ Rev 1.31.1.1 10 Nov 1993 18:05:06 GREGG
+Check for error return from SetDrvBlkSize.
+
+ Rev 1.31.1.0 28 Sep 1993 17:15:02 GREGG
+Setup tpos struct at startup and reference it through the channel.
+
+ Rev 1.31 20 Jul 1993 17:57:12 TIMN
+Added TEXT macro to strings
+
+ Rev 1.30 19 Jul 1993 20:15:18 GREGG
+Fixed bug in last rev.
+
+ Rev 1.29 13 Jul 1993 19:30:50 GREGG
+Added handling of TF_FUTURE_REV_MTF and TF_MTF_ECC_TAPE returns in read case.
+
+ Rev 1.28 01 Jul 1993 11:48:10 GREGG
+Reduced frequency of debug messages.
+
+ Rev 1.27 30 Jun 1993 09:16:04 GREGG
+Don't skip the default size when scanning for the right block size.
+
+ Rev 1.26 03 Jun 1993 14:47:50 STEVEN
+if FUBAR the pd_channel = NULL
+
+ Rev 1.25 11 Apr 1993 18:43:50 GREGG
+Reset no_tape_reported flag at PollDrive startup.
+
+ Rev 1.24 05 Apr 1993 15:01:40 TERRI
+Reset VCB Buff before calling TPRewind under GEN_WRONG_BLOCK_SIZE
+
+ Rev 1.23 30 Mar 1993 16:15:12 GREGG
+Handle Unrecognized Media error (unformatted DC2000).
+
+ Rev 1.22 17 Mar 1993 14:38:52 GREGG
+This is Terri Lynn - Added Gregg's changes for switching a tape drive to
+1k block mode if the tape( i.e. a Sytos Plus tape ) was written in 1k block size.
+
+ Rev 1.21 18 Jan 1993 14:23:06 BobR
+Added MOVE_ESA macro call(s)
+
+ Rev 1.20 20 Oct 1992 14:01:06 HUNTER
+Deleted references to data_size
+
+ Rev 1.19 24 Apr 1992 16:34:24 BURT
+Fixed bug with pd_state containing garbage and causing an exception
+when Zprintf'ing under Nostradamus. Caused by polldrive being called
+with no buffers available, i.e. no drive on or connected to computer.
+Discovered by Dave VanCamp. Fixed by init'ing pd_state to NULL.
+
+ Rev 1.18 25 Mar 1992 16:03:52 GREGG
+ROLLER BLADES - Added 64 bit support.
+
+ Rev 1.17 20 Mar 1992 18:00:30 NED
+added exception updating after TpReceive calls
+
+ Rev 1.16 23 Jan 1992 23:38:34 GREGG
+Forgot to dismount after no data read.
+
+ Rev 1.15 07 Jan 1992 17:57:16 GREGG
+Change state after BAD_DATA.
+
+ Rev 1.14 02 Jan 1992 14:53:40 NED
+Buffer Manager/UTF translator integration.
+
+ Rev 1.13 10 Dec 1991 17:11:14 GREGG
+If pd_state has not been initialized, DON'T ZPRINTF IT!
+
+ Rev 1.12 03 Dec 1991 11:45:06 GREGG
+SKATEBOARD - New Buff Mgr - Initial integration.
+
+ Rev 1.11 25 Nov 1991 14:40:56 GREGG
+Added handling of GEN_ERR_BAD_DATA on read, and return PD_BUSY on first status call.
+
+ Rev 1.10 08 Nov 1991 10:54:04 GREGG
+Added TF_INVALID_VCB case to switch after ReadNewTape/ReadThisSet calls.
+
+ Rev 1.9 29 Oct 1991 11:44:50 GREGG
+BIGWHEEL - Check for GEN_ERR_RESET return from Tp calls.
+
+ Rev 1.8 14 Oct 1991 11:13:06 GREGG
+Yet another big redesign: return immediate on TpStatus calls.
+
+ Rev 1.7 07 Oct 1991 22:16:58 GREGG
+Make sure the fmt env pointers are maintained in only one place at any given time.
+
+ Rev 1.6 03 Oct 1991 14:49:08 GREGG
+Dismount tape after no tape detected, but don't remount until status change.
+
+ Rev 1.5 02 Oct 1991 09:20:36 GREGG
+Revamped the new tape detection and handling logic.
+
+ Rev 1.4 29 Sep 1991 23:00:34 GREGG
+Commented the code, fixed bug where vcb wasn't getting thedata it needed,
+fixed handling when re-entering poll in busy state, and pulled common code
+into static function. (whew)
+
+ Rev 1.3 17 Sep 1991 11:36:08 GREGG
+Changed TPOS_PTR parameter to TPOS_HANDLER. Removed DisMount on no tape case.
+
+ Rev 1.2 12 Sep 1991 09:52:48 GREGG
+You have to get a buffer before you try to write to it!!!
+
+ Rev 1.1 10 Sep 1991 15:49:38 GREGG
+Added break after st_HOSED state end assert after st_CLOSED and default states.
+
+ Rev 1.0 09 Sep 1991 21:07:44 GREGG
+Initial revision.
+
+**/
+
+#include <stdtypes.h>
+#include <queues.h>
+#include <stdmath.h>
+
+#include "drive.h"
+#include "channel.h"
+#include "lw_data.h"
+#include "tfl_err.h"
+#include "lwprotos.h"
+#include "tfldefs.h"
+#include "translat.h"
+
+#include "be_debug.h"
+
+/* Device Driver Interface Files */
+#include "generr.h"
+#include "genstat.h"
+#include "dil.h"
+#include "special.h"
+
+#include "tfpoll.h"
+
+/* Prototypical Prototype - See function for details */
+static VOID _near PD_HandleStatus( DRIVE_PTR, INT16_PTR, INT16_PTR, CHANNEL_PTR ) ;
+
+/**
+
+ Name: TF_PollDrive
+
+ Description: This function keeps track of tape activity, and reports
+ changes to the caller. When a new tape is detected in
+ the drive, it VCB's the tape and supplies the caller
+ with the new VCB.
+
+ Returns: A 'PD_' message indicating the status.
+
+ Notes: This function is intended to return immediatly, and does
+ not wait for tape functions to complete. As a result, it
+ must initially be called with msg == PDMSG_START, and
+ then PDMSG_CONTINUE until the caller no longer wishes to
+ poll the drive. Then it must be called a final time with
+ PDMSG_END.
+
+ There is one exception to the immediate returns: The
+ QS1.9x and SYTOS translators require additional tape
+ operations to VCB the tape, and their new tape functions
+ are not set up for immediate return. For this reason,
+ the caller should provide a TPOS_HANDLER if they wish to
+ be called back during these tape operations.
+
+ There are two other cases where the function will wait on
+ a TpReceive from the driver:
+
+ 1) If we are closed and reopened in a busy state,we will
+ do a status call, and wait for a response from that call
+ before resuming operation. This is to determine if any
+ tape change has been performed while we were inactive.
+ If this is the case, we must start over, otherwise we can
+ continue from the state we were in when we were closed.
+
+ 2) DisMountTape is called rather than going into a busy
+ dismounting status. This was done to reduce the
+ complexity of the function, and is not expected to have a
+ large impact on the immediate return functionality as the
+ calls will be infrequent, and are quick to return. A
+ thread switch will be added to the receive loop for those
+ OS's which require such a beast.
+
+ Declaration:
+
+**/
+
+INT16 TF_PollDrive( THW_PTR thw, /* (I) The drive to be polled */
+ DBLK_PTR vcb, /* (O) The tapes VCB info */
+ FSYS_HAND fsh, /* (I) A file system handle */
+ TPOS_HANDLER ui_tpos, /* (I) For callback during new */
+ /* tape processing */
+ INT16 msg ) /* (I) START, CONTINUE or END */
+{
+ CHANNEL_PTR pd_channel = NULL ;
+ INT16_PTR pd_state = NULL ; /* Added init to fix bug, BBB */
+ DRIVE_PTR curDRV ;
+ INT16 ret_val = PD_NO_CHANGE ;
+ INT16 tmp_ret ;
+ UINT16 i ;
+ RET_BUF myret ;
+ INT16 stat ;
+ static TPOS tpos_struct ; /* Note: Used only for tpos handler! */
+ INT idx ;
+ BOOLEAN resized_buff ;
+ BOOLEAN state_changed = FALSE ;
+
+ /* Startup Stuff ... */
+ if( msg == PDMSG_START ) {
+
+ /* get a channel */
+ for( i = 0 ; i < lw_tfl_control.no_channels ; i++ ) {
+ if( !InUse( &lw_channels[i] ) ) {
+ pd_channel = &lw_channels[i] ;
+ SetChannelStatus( pd_channel, CH_IN_USE ) ;
+ lw_tfl_control.no_chans_open++ ;
+ break ;
+ }
+ }
+ if( pd_channel == NULL ) {
+ ret_val = PD_NO_FREE_CHANNELS ;
+ } else {
+
+ /* hook the drive into the channel */
+ if( ( pd_channel->cur_drv = (DRIVE_PTR) thw ) == NULL ) {
+ msassert( FALSE ) ;
+ ret_val = PD_FUBAR ; /* Specified drive does not exist!!! */
+ }
+ }
+
+ /* set up the channel stuff */
+ if( ret_val == PD_NO_CHANGE ) {
+ ClrChannelStatus( pd_channel, ( CH_FATAL_ERR | CH_DATA_PHASE ) ) ;
+ pd_channel->cur_dblk = vcb ;
+ pd_channel->cur_fsys = fsh ;
+ pd_channel->eom_id = 0L ;
+ pd_channel->hiwater = pd_channel->buffs_enqd = 0 ;
+ pd_channel->retranslate_size = U64_Init( 0xffffffffUL, 0xffffffffUL ) ;
+ pd_channel->blocks_used = 0L ;
+
+ /* We do this so the UI won't have to send us the whole struct
+ when all we need is the handler. It is only at our level
+ that a structure pointer is needed.
+ */
+ if( ui_tpos != NULL ) {
+ tpos_struct.tape_id = -1 ;
+ tpos_struct.tape_seq_num = -1 ;
+ tpos_struct.backup_set_num = -1 ;
+ tpos_struct.UI_TapePosRoutine = ui_tpos ;
+ pd_channel->ui_tpos = &tpos_struct ;
+ } else {
+ pd_channel->ui_tpos = NULL ;
+ }
+
+ if ( pd_channel->cur_drv->last_fmt_env != NULL ) {
+ pd_channel->cur_fmt = pd_channel->cur_drv->last_cur_fmt ;
+ pd_channel->fmt_env = pd_channel->cur_drv->last_fmt_env ;
+ pd_channel->cur_drv->last_cur_fmt = UNKNOWN_FORMAT ;
+ pd_channel->cur_drv->last_fmt_env = NULL ;
+ }
+ if( pd_channel->cur_drv->hold_buff != NULL ) {
+ pd_channel->cur_buff = pd_channel->cur_drv->hold_buff ;
+ pd_channel->cur_drv->hold_buff = NULL ;
+ BM_UnReserve( pd_channel->cur_buff ) ;
+ }
+ curDRV = pd_channel->cur_drv ;
+ curDRV->poll_stuff.channel = pd_channel ;
+
+ /* The drive may have been polled before end ended in a busy
+ state. If this is the case, we start up where we left off.
+ SEE HEADER NOTE!
+ */
+ pd_state = &(curDRV->poll_stuff.state) ;
+ if( *pd_state != st_CLOSED ) {
+ curDRV->poll_stuff.reentered = TRUE ;
+ } else {
+ curDRV->poll_stuff.reentered = FALSE ;
+ curDRV->poll_stuff.first_status = TRUE ;
+ curDRV->poll_stuff.no_tape_reported = FALSE ;
+ curDRV->poll_stuff.def_blk_size = ChannelBlkSize( pd_channel ) ;
+ *pd_state = st_SSDC ;
+ }
+ }
+
+ } else { /* PDMSG_CONTINUE or PDMSG_END */
+
+ /* hook the drive into the channel */
+ if( ( curDRV = (DRIVE_PTR) thw ) == NULL ) {
+ msassert( FALSE ) ;
+ ret_val = PD_FUBAR ; /* Specified drive does not exist!!! */
+ } else {
+
+ /* set state and channel to the ones saved in the drive struct */
+ pd_channel = curDRV->poll_stuff.channel ;
+ pd_state = &(curDRV->poll_stuff.state) ;
+ }
+ }
+
+ /* If no error so far ... */
+ if( ret_val == PD_NO_CHANGE ) {
+
+ /* The big switch! (after all, this is a state machine) */
+ switch( *pd_state ) {
+
+ case st_SSDC : /* Same Status, Different Call */
+
+ /* Status the tape */
+ if( TpStatus( curDRV->drv_hdl ) == FAILURE ) {
+ ret_val = PD_DRIVER_FAILURE ;
+ } else {
+ *pd_state = st_BSTAT ;
+ if( curDRV->poll_stuff.first_status ) {
+ ret_val = PD_BUSY ;
+ }
+ }
+ break ;
+
+ case st_BSTAT : /* Busy STATusing */
+
+ if( curDRV->poll_stuff.first_status ) {
+ ret_val = PD_BUSY ;
+ }
+ if( TpReceive( curDRV->drv_hdl, &myret ) != FAILURE ) {
+
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( thw->the, myret.the ) ;
+
+ /* We don't care about unrecognized media here, we will
+ catch it when we try a mount at the point the tape
+ is first put in the drive.
+ */
+
+ if( myret.gen_error != GEN_NO_ERR &&
+ myret.gen_error != GEN_ERR_NO_MEDIA &&
+ myret.gen_error != GEN_ERR_RESET &&
+ myret.gen_error != GEN_ERR_UNRECOGNIZED_MEDIA ) {
+
+ ret_val = PD_DRIVE_FAILURE ;
+ break ; /* END CASE */
+ }
+
+ /* SEE HEADER NOTE! */
+ /* Okay here's how it goes see. If the status
+ changed, we want to do the status stuff
+ immediatly, but if it didn't change and we're
+ being reentered (ouch) we want to do it again.
+ */
+ if( curDRV->poll_stuff.reentered ) {
+ curDRV->poll_stuff.reentered = FALSE ;
+ if( curDRV->thw_inf.drv_status == myret.status ) {
+ if( TpStatus( curDRV->drv_hdl ) == FAILURE ) {
+ ret_val = PD_DRIVER_FAILURE ;
+ }
+ break ; /* END CASE */
+ }
+ }
+
+ curDRV->thw_inf.drv_status = myret.status ;
+ PD_HandleStatus( curDRV, &ret_val, pd_state, pd_channel ) ;
+ }
+ break ;
+
+ case st_BMNT : /* Busy MouNTing */
+
+ ret_val = PD_BUSY ;
+ if( TpReceive( curDRV->drv_hdl, &myret ) != FAILURE ) {
+
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( thw->the, myret.the ) ;
+
+ /* If no error, check for status change */
+ if( myret.gen_error != GEN_NO_ERR &&
+ myret.gen_error != GEN_ERR_NO_MEDIA &&
+ myret.gen_error != GEN_ERR_RESET &&
+ myret.gen_error != GEN_ERR_UNRECOGNIZED_MEDIA ) {
+
+ curDRV->tape_mounted = FALSE ;
+ ret_val = PD_DRIVE_FAILURE ;
+ } else {
+
+ if( myret.gen_error == GEN_ERR_NO_MEDIA || ( myret.status & TPS_NO_TAPE ) ) {
+
+ curDRV->thw_inf.drv_status = myret.status ;
+
+ /* They popped the tape! */
+ curDRV->tape_mounted = FALSE ;
+ ret_val = PD_NO_TAPE ;
+ curDRV->poll_stuff.no_tape_reported = TRUE ;
+ *pd_state = st_SSDC ;
+
+ } else if ( myret.gen_error == GEN_ERR_UNRECOGNIZED_MEDIA ) {
+
+ /* We need not go any further with this tape */
+ if( ( tmp_ret = DisMountTape( curDRV, NULL, FALSE ) ) != TFLE_NO_ERR ) {
+ if( tmp_ret == TFLE_DRIVER_FAILURE ) {
+ ret_val = PD_DRIVER_FAILURE ;
+ } else {
+ ret_val = PD_DRIVE_FAILURE ;
+ }
+ } else {
+ ret_val = PD_UNRECOGNIZED_MEDIA ;
+ *pd_state = st_SSDC ;
+ }
+
+ } else if( myret.gen_error == GEN_ERR_RESET ) {
+
+ /* Let's try this again ... */
+ curDRV->tape_mounted = FALSE ;
+ if( TpMount( curDRV->drv_hdl ) == FAILURE ) {
+ ret_val = PD_DRIVER_FAILURE ;
+ }
+ } else {
+
+ /* The mount was successful! */
+ curDRV->tape_mounted = TRUE ;
+
+ /* SEE HEADER NOTE! */
+ if( curDRV->poll_stuff.reentered ) {
+ curDRV->poll_stuff.reentered = FALSE ;
+ if( ( tmp_ret = UpdateDriveStatus( curDRV ) ) != TFLE_NO_ERR ) {
+ if( tmp_ret == TFLE_DRIVER_FAILURE ) {
+ ret_val = PD_DRIVER_FAILURE ;
+ } else {
+ ret_val = PD_DRIVE_FAILURE ;
+ }
+ break ; /* END CASE */
+ }
+ if( curDRV->thw_inf.drv_status &
+ ( TPS_NO_TAPE | TPS_NEW_TAPE | TPS_RESET ) ) {
+ /* They did something behind our
+ backs, lets start over.
+ */
+ if( ( tmp_ret = DisMountTape( curDRV, NULL, FALSE ) ) != TFLE_NO_ERR ) {
+ if( tmp_ret == TFLE_DRIVER_FAILURE ) {
+ ret_val = PD_DRIVER_FAILURE ;
+ } else {
+ ret_val = PD_DRIVE_FAILURE ;
+ }
+ } else {
+ PD_HandleStatus( curDRV, &ret_val, pd_state, pd_channel ) ;
+ }
+ break ; /* END CASE */
+ }
+ }
+
+ /* Start the rewind! */
+ if( TpRewind( curDRV->drv_hdl, FALSE ) == FAILURE ) {
+ ret_val = PD_DRIVER_FAILURE ;
+ } else {
+ ResetDrivePosition( curDRV ) ;
+ SetPosBit( curDRV, AT_BOT ) ;
+ *pd_state = st_BREW ;
+ state_changed = TRUE ;
+ }
+ }
+ }
+ }
+ break ;
+
+ case st_BREW : /* Busy REWinding */
+
+ ret_val = PD_BUSY ;
+ if( TpReceive( curDRV->drv_hdl, &myret ) != FAILURE ) {
+
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( thw->the, myret.the ) ;
+
+ if ( myret.gen_error != GEN_NO_ERR ) {
+ curDRV->thw_inf.drv_status = myret.status ;
+ }
+
+ /* process return from TpRewind */
+ switch( myret.gen_error ) {
+
+ case GEN_ERR_NO_MEDIA :
+
+ /* They popped the tape!!! */
+ curDRV->tape_mounted = FALSE ;
+ ret_val = PD_NO_TAPE ;
+ curDRV->poll_stuff.no_tape_reported = TRUE ;
+ *pd_state = st_SSDC ;
+ break ;
+
+ case GEN_ERR_RESET :
+
+ /* Let's try this again ... */
+ curDRV->tape_mounted = FALSE ;
+ *pd_state = st_BMNT ;
+ state_changed = TRUE ;
+ ret_val = PD_BUSY ;
+ if( TpMount( curDRV->drv_hdl ) == FAILURE ) {
+ ret_val = PD_DRIVER_FAILURE ;
+ }
+ break ;
+
+ case GEN_NO_ERR :
+
+ /* SEE HEADER NOTE! */
+ if( curDRV->poll_stuff.reentered ) {
+ curDRV->poll_stuff.reentered = FALSE ;
+ if( ( tmp_ret = UpdateDriveStatus( curDRV ) ) != TFLE_NO_ERR ) {
+ if( tmp_ret == TFLE_DRIVER_FAILURE ) {
+ ret_val = PD_DRIVER_FAILURE ;
+ } else {
+ ret_val = PD_DRIVE_FAILURE ;
+ }
+ break ; /* END CASE */
+ }
+ if( curDRV->thw_inf.drv_status &
+ ( TPS_NO_TAPE | TPS_NEW_TAPE | TPS_RESET ) ) {
+ /* They did something behind our
+ backs, lets start over.
+ */
+ if( ( tmp_ret = DisMountTape( curDRV, NULL, FALSE ) ) != TFLE_NO_ERR ) {
+ if( tmp_ret == TFLE_DRIVER_FAILURE ) {
+ ret_val = PD_DRIVER_FAILURE ;
+ } else {
+ ret_val = PD_DRIVE_FAILURE ;
+ }
+ } else {
+ PD_HandleStatus( curDRV, &ret_val, pd_state, pd_channel ) ;
+ }
+ break ; /* END CASE */
+ }
+ }
+
+ /* kick off the VCB read */
+ if( ( pd_channel->cur_buff = BM_GetVCBBuff( &pd_channel->buffer_list ) ) == NULL ) {
+ ret_val = PD_OUT_OF_MEMORY ;
+ } else {
+ if( TpRead( curDRV->drv_hdl, BM_XferBase( pd_channel->cur_buff ), (UINT32)BM_XferSize( pd_channel->cur_buff ) ) == FAILURE ) {
+ ret_val = PD_DRIVER_FAILURE ;
+ }
+ *pd_state = st_BREAD ;
+ state_changed = TRUE ;
+ }
+ break ;
+
+ default:
+ ret_val = PD_DRIVE_FAILURE ;
+ break ;
+ }
+ }
+ break ;
+
+ case st_BREAD : /* Busy READing (Stick with me, this be a biggie) */
+
+ ret_val = PD_BUSY ;
+ if( TpReceive( curDRV->drv_hdl, &myret ) != FAILURE ) {
+
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( thw->the, myret.the ) ;
+
+ if ( myret.gen_error != GEN_NO_ERR ) {
+ curDRV->thw_inf.drv_status = myret.status ;
+ }
+
+ /* process return from TpRead */
+ switch( myret.gen_error ) {
+
+ case GEN_ERR_NO_MEDIA :
+
+ /* They popped the tape!!! */
+ curDRV->tape_mounted = FALSE ;
+ ret_val = PD_NO_TAPE ;
+ curDRV->poll_stuff.no_tape_reported = TRUE ;
+ *pd_state = st_SSDC ;
+ BM_Put( pd_channel->cur_buff ) ;
+ pd_channel->cur_buff = NULL ;
+ break ;
+
+ case GEN_ERR_RESET :
+
+ /* Let's try this again ... */
+ curDRV->tape_mounted = FALSE ;
+ *pd_state = st_BMNT ;
+ state_changed = TRUE ;
+ ret_val = PD_BUSY ;
+ BM_Put( pd_channel->cur_buff ) ;
+ pd_channel->cur_buff = NULL ;
+ if( TpMount( curDRV->drv_hdl ) == FAILURE ) {
+ ret_val = PD_DRIVER_FAILURE ;
+ }
+ break ;
+
+ case GEN_ERR_UNRECOGNIZED_MEDIA :
+
+ ret_val = PD_UNRECOGNIZED_MEDIA ;
+ *pd_state = st_SSDC ;
+ if( ( tmp_ret = DisMountTape( curDRV, NULL, FALSE ) ) != TFLE_NO_ERR ) {
+ if( tmp_ret == TFLE_DRIVER_FAILURE ) {
+ ret_val = PD_DRIVER_FAILURE ;
+ } else {
+ ret_val = PD_DRIVE_FAILURE ;
+ }
+ }
+ break ;
+
+ case GEN_ERR_BAD_DATA :
+
+ ret_val = PD_BAD_TAPE ;
+ *pd_state = st_SSDC ;
+ if( ( tmp_ret = DisMountTape( curDRV, NULL, FALSE ) ) != TFLE_NO_ERR ) {
+ if( tmp_ret == TFLE_DRIVER_FAILURE ) {
+ ret_val = PD_DRIVER_FAILURE ;
+ } else {
+ ret_val = PD_DRIVE_FAILURE ;
+ }
+ }
+ break ;
+
+ case GEN_ERR_WRONG_BLOCK_SIZE :
+ /* This is to deal with drives which don't have any
+ idea what block size the tape was written with.
+ We go through a list of valid sizes in an attempt
+ to find the right size to read the tape. Each
+ time we try a new size, we issue another rewind
+ and set the state back to st_BREW, keeping track
+ of which sizes we have tried. If we exhaust the
+ list, we report it as a FOREIGN tape.
+ */
+ idx = curDRV->poll_stuff.blk_size_idx ;
+ if( ! ( DriveAttributes( curDRV ) & TDI_CHNG_BLK_SIZE )
+ || idx == lw_num_blk_sizes ) {
+
+ *pd_state = st_SSDC ;
+ ret_val = PD_FOREIGN_TAPE ;
+ if( DriveAttributes( curDRV ) & TDI_CHNG_BLK_SIZE ) {
+ INT16 ret ;
+
+ ret = SetDrvBlkSize( pd_channel,
+ pd_channel->cur_buff,
+ curDRV->poll_stuff.def_blk_size,
+ &resized_buff ) ;
+
+ if( ret == TFLE_NO_MEMORY ) {
+ ret_val = PD_DRIVE_FAILURE ;
+ } else if( ret != TFLE_NO_ERR ) {
+ ret_val = PD_FOREIGN_TAPE ;
+ } else {
+ if( ( tmp_ret = DisMountTape( curDRV, NULL, FALSE ) ) != TFLE_NO_ERR ) {
+ if( tmp_ret == TFLE_DRIVER_FAILURE ) {
+ ret_val = PD_DRIVER_FAILURE ;
+ } else {
+ ret_val = PD_DRIVE_FAILURE ;
+ }
+ }
+ }
+ } else {
+ if( ( tmp_ret = DisMountTape( curDRV, NULL, FALSE ) ) != TFLE_NO_ERR ) {
+ if( tmp_ret == TFLE_DRIVER_FAILURE ) {
+ ret_val = PD_DRIVER_FAILURE ;
+ } else {
+ ret_val = PD_DRIVE_FAILURE ;
+ }
+ }
+ }
+ } else {
+ INT16 ret ;
+
+ ret = SetDrvBlkSize( pd_channel,
+ pd_channel->cur_buff,
+ lw_blk_size_list[idx],
+ &resized_buff ) ;
+
+ if( ret == TFLE_NO_MEMORY ) {
+ ret_val = PD_OUT_OF_MEMORY ;
+ } else {
+
+ ++curDRV->poll_stuff.blk_size_idx ;
+
+ BM_Put( pd_channel->buffer_list.vcb_buff ) ;
+ if( TpRewind( curDRV->drv_hdl, FALSE ) == FAILURE ) {
+ ret_val = PD_DRIVER_FAILURE ;
+ } else {
+ ResetDrivePosition( curDRV ) ;
+ SetPosBit( curDRV, AT_BOT ) ;
+ *pd_state = st_BREW ;
+ state_changed = TRUE ;
+ }
+ }
+ }
+ break ;
+
+ case GEN_ERR_NO_DATA :
+ case GEN_NO_ERR :
+ case GEN_ERR_ENDSET :
+
+ curDRV->poll_stuff.def_blk_size = ChannelBlkSize( pd_channel ) ;
+
+ /* SEE HEADER NOTE! */
+ if( curDRV->poll_stuff.reentered ) {
+ curDRV->poll_stuff.reentered = FALSE ;
+ if( ( tmp_ret = UpdateDriveStatus( curDRV ) ) != TFLE_NO_ERR ) {
+ if( tmp_ret == TFLE_DRIVER_FAILURE ) {
+ ret_val = PD_DRIVER_FAILURE ;
+ } else {
+ ret_val = PD_DRIVE_FAILURE ;
+ }
+ break ; /* END CASE */
+ }
+ if( curDRV->thw_inf.drv_status &
+ ( TPS_NO_TAPE | TPS_NEW_TAPE | TPS_RESET ) ) {
+ /* They did something behind our
+ backs, lets start over.
+ */
+ if( ( tmp_ret = DisMountTape( curDRV, NULL, FALSE ) ) != TFLE_NO_ERR ) {
+ if( tmp_ret == TFLE_DRIVER_FAILURE ) {
+ ret_val = PD_DRIVER_FAILURE ;
+ } else {
+ ret_val = PD_DRIVE_FAILURE ;
+ }
+ } else {
+ PD_HandleStatus( curDRV, &ret_val, pd_state, pd_channel ) ;
+ }
+ break ; /* END CASE */
+ }
+ }
+
+ /* Attempt to generate a VCB */
+ ret_val = PD_BLANK_TAPE ;
+ *pd_state = st_SSDC ;
+ BM_SetBytesFree( pd_channel->cur_buff, (UINT16)myret.len_got ) ;
+ BM_SetReadError( pd_channel->cur_buff, myret.gen_error ) ;
+ if( BM_BytesFree( pd_channel->cur_buff ) ) {
+ if ( ( stat = ReadNewTape( pd_channel, pd_channel->ui_tpos, FALSE ) ) == TFLE_NO_ERR ) {
+ stat = ReadThisSet( pd_channel ) ;
+ }
+
+ switch( stat ) {
+
+ case TFLE_NO_ERR :
+
+ /* We got one!!! */
+ *pd_channel->cur_dblk = curDRV->cur_vcb ;
+ ret_val = PD_VALID_VCB ;
+ if( ( tmp_ret = DisMountTape( curDRV, NULL, FALSE ) ) != TFLE_NO_ERR ) {
+ if( tmp_ret == TFLE_DRIVER_FAILURE ) {
+ ret_val = PD_DRIVER_FAILURE ;
+ } else {
+ ret_val = PD_DRIVE_FAILURE ;
+ }
+ } else {
+ curDRV->vcb_valid = TRUE ;
+ }
+ break ;
+
+
+ case TF_NO_MORE_DATA :
+ case TF_SQL_TAPE :
+ case TF_INVALID_VCB :
+ case TF_FUTURE_REV_MTF :
+ case TF_MTF_ECC_TAPE :
+ case TFLE_UNKNOWN_FMT :
+ case TFLE_BAD_TAPE :
+ case TFLE_TAPE_INCONSISTENCY :
+ case TFLE_TRANSLATION_FAILURE :
+
+ if( stat == TF_FUTURE_REV_MTF ) {
+ ret_val = PD_FUTURE_REV_MTF ;
+ } else if( stat == TF_MTF_ECC_TAPE ) {
+ ret_val = PD_MTF_ECC_TAPE ;
+ } else if( stat == TF_SQL_TAPE ) {
+ ret_val = PD_SQL_TAPE ;
+ } else {
+ ret_val = PD_FOREIGN_TAPE ;
+ }
+ if( ( tmp_ret = DisMountTape( curDRV, NULL, FALSE ) ) != TFLE_NO_ERR ) {
+ if( tmp_ret == TFLE_DRIVER_FAILURE ) {
+ ret_val = PD_DRIVER_FAILURE ;
+ } else {
+ ret_val = PD_DRIVE_FAILURE ;
+ }
+ }
+ break ;
+
+ case TFLE_DRIVE_FAILURE :
+
+ ret_val = PD_DRIVE_FAILURE ;
+ break ;
+
+ case TFLE_DRIVER_FAILURE :
+
+ ret_val = PD_DRIVER_FAILURE ;
+ break ;
+
+ case TFLE_NO_TAPE :
+
+ /* They popped the tape!!! */
+ curDRV->tape_mounted = FALSE ;
+ ret_val = PD_NO_TAPE ;
+ curDRV->poll_stuff.no_tape_reported = TRUE ;
+ *pd_state = st_SSDC ;
+ BM_Put( pd_channel->cur_buff ) ;
+ pd_channel->cur_buff = NULL ;
+ break ;
+
+ case TFLE_NO_MEMORY :
+
+ ret_val = PD_OUT_OF_MEMORY ;
+ DisMountTape( curDRV, NULL, FALSE ) ;
+ break ;
+
+ case TF_WRONG_TAPE :
+ case TF_TAPE_OUT_OF_ORDER :
+
+ ret_val = PD_OUT_OF_SEQUENCE ;
+ if( ( tmp_ret = DisMountTape( curDRV, NULL, FALSE ) ) != TFLE_NO_ERR ) {
+ if( tmp_ret == TFLE_DRIVER_FAILURE ) {
+ ret_val = PD_DRIVER_FAILURE ;
+ } else {
+ ret_val = PD_DRIVE_FAILURE ;
+ }
+ }
+ break ;
+
+ default:
+ ret_val = PD_FUBAR ; /* shouldn't happen */
+ }
+ } else { /* BM_BytesFree == 0 */
+ if( ( tmp_ret = DisMountTape( curDRV, NULL, FALSE ) ) != TFLE_NO_ERR ) {
+ if( tmp_ret == TFLE_DRIVER_FAILURE ) {
+ ret_val = PD_DRIVER_FAILURE ;
+ } else {
+ ret_val = PD_DRIVE_FAILURE ;
+ }
+ }
+ }
+ break ;
+
+ default:
+
+ ret_val = PD_DRIVE_FAILURE ;
+ break ;
+ }
+ }
+ break ;
+
+ case st_HOSED : /* We reported a critical error. They should be
+ calling us with END!!!
+ */
+
+ if( msg != PDMSG_END ) {
+ msassert( FALSE ) ;
+ ret_val = PD_FUBAR ;
+ }
+ break ;
+
+ case st_CLOSED : /* This is REALLY BAD!!! */
+ default :
+
+ msassert( FALSE ) ;
+ ret_val = PD_FUBAR ;
+ }
+ }
+
+ /* Certain returns indicate the FormatEnv and buffers are no longer
+ valid. If this is the case, we ditch them.
+ */
+ switch( ret_val ) {
+
+ case PD_NO_CHANGE :
+ case PD_BUSY :
+ case PD_VALID_VCB :
+ case PD_NO_FREE_CHANNELS :
+
+ break ;
+
+ case PD_FUBAR :
+ case PD_OUT_OF_MEMORY :
+ case PD_DRIVE_FAILURE :
+ case PD_DRIVER_FAILURE :
+
+ *pd_state = st_HOSED ;
+
+ /* Fall Through */
+
+ case PD_BLANK_TAPE :
+ case PD_NO_TAPE :
+ case PD_FOREIGN_TAPE :
+ case PD_FUTURE_REV_MTF :
+ case PD_SQL_TAPE :
+ case PD_MTF_ECC_TAPE :
+ case PD_OUT_OF_SEQUENCE :
+ case PD_NEW_TAPE :
+ case PD_BAD_TAPE :
+ case PD_UNRECOGNIZED_MEDIA :
+
+ if( (pd_channel != NULL) && (pd_channel->cur_drv != NULL) ) {
+ curDRV->vcb_valid = FALSE ;
+ if( pd_channel->fmt_env != NULL ) {
+ FreeFormatEnv( &pd_channel->cur_fmt, &pd_channel->fmt_env ) ;
+ }
+ if( curDRV->hold_buff != NULL ) {
+ BM_UnReserve( curDRV->hold_buff ) ;
+ BM_Put( curDRV->hold_buff ) ;
+ curDRV->hold_buff = NULL ;
+ }
+ if( pd_channel->cur_buff != NULL ) {
+ BM_Put( pd_channel->cur_buff ) ;
+ pd_channel->cur_buff = NULL ;
+ }
+ }
+ break ;
+
+ default :
+ msassert( FALSE ) ;
+ }
+
+ /* Should we wrap it up? */
+ if( msg == PDMSG_END ) {
+
+ /* If we are currently reading into cur_buff, or it has valid data,
+ save it in hold_buff.
+ */
+ if( *pd_state == st_BREAD ) {
+ curDRV->hold_buff = pd_channel->cur_buff ;
+ pd_channel->cur_buff = NULL ;
+ BM_Reserve( curDRV->hold_buff ) ;
+
+ }else if( pd_channel != NULL && pd_channel->cur_buff != NULL &&
+ ( BM_BytesFree( pd_channel->cur_buff ) != 0 ||
+ ( BM_ReadError( pd_channel->cur_buff ) != GEN_NO_ERR &&
+ BM_ReadError( pd_channel->cur_buff ) != GEN_ERR_NO_DATA ) ) ) {
+ curDRV->hold_buff = pd_channel->cur_buff ;
+ pd_channel->cur_buff = NULL ;
+ BM_Reserve( curDRV->hold_buff ) ;
+ }
+
+ /* If the VCB's valid, save the currnt FormatEnv */
+ if( pd_channel != NULL ) {
+ if( curDRV->vcb_valid ) {
+ curDRV->last_cur_fmt = pd_channel->cur_fmt ;
+ curDRV->last_fmt_env = pd_channel->fmt_env ;
+ pd_channel->cur_fmt = UNKNOWN_FORMAT ;
+ pd_channel->fmt_env = NULL ;
+ } else if( pd_channel->fmt_env != NULL ) {
+ FreeFormatEnv( &pd_channel->cur_fmt, &pd_channel->fmt_env ) ;
+ }
+ }
+
+ /* If we're busy ... */
+ if( *pd_state == st_BMNT || *pd_state == st_BSTAT ||
+ *pd_state == st_BREW || *pd_state == st_BREAD ) {
+
+ /* Force a call to mount as next action on this drive. */
+ curDRV->tape_mounted = FALSE ;
+
+ } else {
+
+ /* Close it up! */
+ *pd_state = st_CLOSED ;
+ ClrPosBit( curDRV, REW_CLOSE ) ;
+ }
+
+ /* free up the channel */
+ if( pd_channel != NULL ) {
+ ClrChannelStatus( pd_channel, CH_IN_USE ) ;
+ curDRV->poll_stuff.channel = NULL ;
+ lw_tfl_control.no_chans_open-- ;
+ }
+ }
+
+ if( ( ret_val != PD_NO_CHANGE && ret_val != PD_BUSY ) ||
+ msg != PDMSG_CONTINUE || state_changed ) {
+
+ if( pd_state == NULL ) {
+ BE_Zprintf( 0, TEXT("PollDrive: msg: %d, NO STATE INFO, return: %d\n"), msg, ret_val ) ;
+ } else {
+ BE_Zprintf( 0, TEXT("PollDrive: msg: %d, new state: %d, return: %d\n"), msg, *pd_state, ret_val ) ;
+ }
+ }
+ return( ret_val ) ;
+}
+
+
+/**
+
+ Name: PD_HandleStatus
+
+ Description: This function checks the status of the drive and responds
+ accordingly.
+
+ Returns: Nothing, nada, zilch, zippo, ... (get the picture?)
+
+ Notes: It is important to keep in mind that the programmer was
+ not in his right mind while making this note and anything
+ said here should be ignored completely.
+
+ Declaration:
+
+**/
+
+static VOID _near PD_HandleStatus(
+ DRIVE_PTR curDRV, /* (I) drive being polled */
+ INT16_PTR ret_val, /* (O) Poll's return value */
+ INT16_PTR pd_state, /* (O) Poll's state */
+ CHANNEL_PTR pd_channel ) /* (I) active channel */
+{
+ if( curDRV->thw_inf.drv_status & TPS_NO_TAPE ) {
+
+ /* No tape in drive! */
+ *pd_state = st_SSDC ;
+
+ /* Report no tape only when it is first detected */
+ if( !curDRV->poll_stuff.no_tape_reported ) {
+ ResetDrivePosition( curDRV ) ;
+ *ret_val = PD_NO_TAPE ;
+ curDRV->poll_stuff.no_tape_reported = TRUE ;
+ ClrPosBit( curDRV, TAPE_FULL ) ;
+ }
+
+ } else {
+
+ /* We have a tape. Is it New? */
+ if( ( curDRV->thw_inf.drv_status & ( TPS_NEW_TAPE | TPS_RESET ) )
+ || ( !curDRV->vcb_valid && curDRV->poll_stuff.first_status )
+ || ( curDRV->poll_stuff.no_tape_reported ) ) {
+
+ /* Note that the second condition keeps us from constantly
+ trying to re-VCB a blank or foreign tape, and the last
+ condition is needed because the SCSI drives don't always
+ report NEW_TAPE.
+ */
+
+ /* It is new! Let's kick off the VCB process. */
+ curDRV->poll_stuff.no_tape_reported = FALSE ;
+ *ret_val = PD_NEW_TAPE ;
+ ClrPosBit( curDRV, TAPE_FULL ) ;
+ if( TpMount( curDRV->drv_hdl ) == FAILURE ) {
+ *ret_val = PD_DRIVER_FAILURE ;
+ }
+ *pd_state = st_BMNT ;
+
+ /* See the comment at GEN_ERR_WRONG_BLOCK_SIZE return
+ from TpRead.
+ */
+ curDRV->poll_stuff.blk_size_idx = 0 ;
+
+ } else {
+
+ *pd_state = st_SSDC ;
+
+ /* On first status, if this is not a new tape and we have a
+ valid VCB already, we give them the old VCB and inform
+ them that it is valid.
+ */
+ if( curDRV->poll_stuff.first_status ) {
+ *pd_channel->cur_dblk = curDRV->cur_vcb ;
+ *ret_val = PD_VALID_VCB ;
+ }
+ }
+ }
+
+ curDRV->poll_stuff.first_status = FALSE ;
+}
+
diff --git a/private/utils/ntbackup/src/tfread.c b/private/utils/ntbackup/src/tfread.c
new file mode 100644
index 000000000..eedd528cf
--- /dev/null
+++ b/private/utils/ntbackup/src/tfread.c
@@ -0,0 +1,1656 @@
+
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: read.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the support code for reading tapes.
+
+
+ $Log: T:/LOGFILES/TFREAD.C_V $
+
+ Rev 1.62 19 Oct 1993 17:34:04 GREGG
+Consider lba_offset (from GotoBlock) in calculating beginning and running LBAs.
+
+ Rev 1.61 22 Jul 1993 12:46:10 GREGG
+Fixed calc of Beginning and Running LBA after posatset call in DoRead.
+
+ Rev 1.60 14 Jul 1993 20:55:10 GREGG
+Fixed bug if CalcReTransSize dealing with stream sizes greater than 4 Gig.
+
+ Rev 1.59 30 Jun 1993 09:22:00 GREGG
+Fixed GOTO_LBA logic, and setting of running and beginning LBAs on cont tape.
+
+ Rev 1.58 25 Jun 1993 20:50:28 GREGG
+In EOM_Read, don't call FlushReads if there's an exception in the cur_buff.
+
+ Rev 1.57 24 May 1993 21:14:10 GREGG
+Fixed conditional to see if we did a seek to VCB in StartRead.
+
+ Rev 1.56 17 May 1993 20:11:54 GREGG
+Added logic to deal with the fact that the app above tape format doesn't
+keep track of the lba of the vcb.
+
+ Rev 1.55 18 Apr 1993 17:26:42 GREGG
+Don't bother reporting UDBs to loops, just skip them.
+
+ Rev 1.54 12 Mar 1993 12:32:50 DON
+Replaced empty TpReceive loops with ThreadSwitch's
+
+ Rev 1.53 10 Mar 1993 16:11:12 GREGG
+Should have been updating bytes free as well as next byte offset with offset
+returned from GotoBlock.
+
+ Rev 1.53 22 Feb 1993 12:23:08 chrish
+Added change received from MikeP.
+Restoring a set that contained a true "unexpected end of set" it trapped in
+GetData because cur_buf was NULL.
+
+ Rev 1.52 30 Jan 1993 11:51:22 DON
+Removed compiler warnings
+
+ Rev 1.51 27 Jan 1993 14:30:14 GREGG
+Preserve stream processing channel status in EOM_Read.
+
+ Rev 1.50 25 Jan 1993 12:36:06 GREGG
+Fixed bug where 'eom_id' was being set erroniously.
+
+ Rev 1.49 18 Jan 1993 14:17:48 BobR
+Added MOVE_ESA macro(s)
+
+ Rev 1.48 08 Dec 1992 21:02:50 GREGG
+Clear CH_DATA_PHASE bit after skipping data in GetData.
+
+ Rev 1.47 20 Nov 1992 13:05:42 HUNTER
+Added handling for TF_SKIP_CURRENT_STREAM
+
+ Rev 1.46 11 Nov 1992 22:27:04 GREGG
+Unicodeized literals.
+
+ Rev 1.45 04 Nov 1992 09:12:52 HUNTER
+Moved the processing of the reqrep's "filter_to_use" field
+
+ Rev 1.43 22 Oct 1992 10:24:50 HUNTER
+New data stream handling
+
+ Rev 1.42 22 Sep 1992 09:03:20 GREGG
+Initial changes to handle physical block sizes greater than 1K.
+
+ Rev 1.41 17 Aug 1992 08:42:02 GREGG
+Changes to deal with block sizeing scheme.
+
+ Rev 1.40 23 Jul 1992 10:11:32 GREGG
+Fixed warnings.
+
+ Rev 1.39 09 Jun 1992 15:35:54 GREGG
+Changed call to check for continuation block.
+
+ Rev 1.38 21 May 1992 12:52:02 GREGG
+Changes for OTC read.
+
+ Rev 1.37 13 May 1992 12:00:16 STEVEN
+40 format changes
+
+ Rev 1.36 25 Mar 1992 17:56:08 GREGG
+ROLLER BLADES - Initial Integration. Includes support for 4.0 format, 64
+ bit file sizes and tape block sizes > the logical block size.
+
+ Rev 1.35 20 Mar 1992 18:01:10 NED
+added exception updating after TpReceive calls
+
+ Rev 1.34 03 Mar 1992 12:22:40 GREGG
+ Added TpSpecial SS_PHYS_BLOCK call after PositionAtSet call in DoRead.
+
+ Rev 1.33 28 Feb 1992 16:14:30 GREGG
+Added TpSpecial SS_PHYS_BLOCK call in EOM_Read.
+
+ Rev 1.32 27 Feb 1992 18:35:44 NED
+fixed update of channel->cur_drv->cur_pos from rr struct
+
+ Rev 1.31 25 Feb 1992 15:17:24 NED
+updated tape_seq_num in cur_drv to fix goto LBA problem
+
+ Rev 1.30 08 Feb 1992 14:22:40 GREGG
+Removed references to lst_oper in drive stucture (it no longer exits).
+
+ Rev 1.29 04 Feb 1992 21:06:20 NED
+Added code to deal with TpRead calls failing due to request queue overflow.
+
+ Rev 1.28 17 Jan 1992 08:27:04 GREGG
+Removed call to now nonexistant StartReadHook function.
+
+ Rev 1.27 15 Jan 1992 01:39:10 GREGG
+Added param to posatset calls indicating if only a VCB of the tape is required.
+
+ Rev 1.26 03 Jan 1992 13:25:52 NED
+Added DumpDebug() call
+
+ Rev 1.25 02 Jan 1992 14:52:16 NED
+Buffer Manager/UTF translator integration.
+
+ Rev 1.24 03 Dec 1991 11:50:36 GREGG
+SKATEBOARD - New Buff Mgr - Initial integration.
+
+ Rev 1.23 22 Nov 1991 15:18:24 GREGG
+Replaced TF_IDLE call with ThreadSwitch.
+
+ Rev 1.22 19 Nov 1991 09:35:32 GREGG
+CleanupDriverQ was TpReceiving if buffer had an exception and there was no fmt.
+
+ Rev 1.21 17 Oct 1991 01:27:54 GREGG
+BIGWHEEL - 8200sx - Initial integration.
+
+ Rev 1.20 07 Oct 1991 22:26:06 GREGG
+Update lba stuff after Fast File positioning across EOM.
+
+ Rev 1.19 25 Sep 1991 20:40:08 GREGG
+Update channel->cur_drv->cur_pos.tape_seq at EOM.
+Don't call translator when doing a CleanupDriverQ in an error state.
+
+ Rev 1.18 17 Sep 1991 13:33:24 GREGG
+Added TF_SKIPPING_DATA message.
+
+ Rev 1.17 22 Aug 1991 16:36:18 NED
+hanged all references to internals of the buffer structure to macros.
+
+ Rev 1.16 16 Aug 1991 09:12:52 GREGG
+Moved preservation of current format during continuation into PositionAtSet.
+
+ Rev 1.15 14 Aug 1991 11:22:28 GREGG
+Clean up the driver queue if error encountered during read
+
+ Rev 1.14 01 Aug 1991 15:01:12 GREGG
+Save the current format before calling PosAtSet to handle EOM tape changes.
+
+ Rev 1.13 24 Jul 1991 16:16:44 DAVIDH
+Cleared up warnings under Watcom.
+
+ Rev 1.12 22 Jul 1991 13:13:18 GREGG
+Removed handling of CH_CONTINUING status (now done in PositionAtSet).
+
+ Rev 1.11 15 Jul 1991 15:02:04 NED
+Added logic to set CH_CONTINUING channel status at apropriate times.
+
+ Rev 1.10 26 Jun 1991 16:15:46 NED
+added EOD handling after calls to RD_Exception(), having
+removed it from there.
+
+ Rev 1.9 25 Jun 1991 09:56:02 NED
+Don't call FlushReads from DoRead if there is an exception in the current
+buffer. Cleaned up logic in AcquireReadBuffer. Changed CleanupDriverQ to
+properly handle exceptions.
+
+ Rev 1.8 17 Jun 1991 12:00:08 GREGG
+Changed AbortRead to stop rewinding the drive and freeing the format environment.
+Added logic to set the REW_CLOSE position bit only under specific conditions.
+Free the format environment on exceptions which request REW_CLOSE.
+Handle translator communication when exception encountered during CleanupDriverQ.
+
+ Rev 1.7 07 Jun 1991 01:31:46 GREGG
+Removed call to FreeFormatEnv in AbortRead.
+
+ Rev 1.6 06 Jun 1991 21:07:14 GREGG
+Updated parameters in calls to FreeFormatEnv and MoveToVCB.
+
+ Rev 1.5 28 May 1991 14:52:10 NED
+applied changes made to old code ;
+fixed handling of exceptions when skipping in GetData.
+
+ Rev 1.4 23 May 1991 17:51:10 GREGG
+In case where next LBA is on next tape, set CH_AT_EOD before call to PosAtSet
+and reset it after, so posAtSet knows to ask for next tape, and check return
+from PosAtSet before continuing.
+
+ Rev 1.3 23 May 1991 16:23:52 NED
+Fixed handling of end-of-set when last read ended just prior
+to filemark at end.
+
+ Rev 1.2 14 May 1991 16:37:30 NED
+Added exception handling return codes from AcquireReadBuffer
+and associated code to interpret them: TFLE_xxxx for errors,
+TFLE_NO_ERR for OK (got data), and FMT_EXC_xxx for exceptions.
+
+ Rev 1.1 10 May 1991 16:07:36 GREGG
+Ned's new stuff
+
+ Rev 1.0 10 May 1991 10:12:20 GREGG
+Initial revision.
+
+**/
+/* begin include list */
+#include <memory.h>
+#include <stdio.h>
+
+#include "stdtypes.h"
+#include "queues.h"
+#include "stdmath.h"
+
+#include "drive.h"
+#include "channel.h"
+#include "lw_data.h"
+#include "tfl_err.h"
+#include "lwdefs.h"
+#include "tflopen.h"
+#include "lwprotos.h"
+#include "tflproto.h"
+#include "translat.h"
+#include "tfldefs.h"
+#include "sx.h"
+
+/* Device Driver Interface Files */
+#include "retbuf.h"
+#include "special.h"
+#include "dilhwd.h"
+#include "drvinf.h"
+#include "generr.h"
+#include "genfuncs.h"
+#include "dil.h"
+
+#include "be_debug.h"
+
+/* $end$ include list */
+
+
+/* Static Prototypes */
+static INT16 _near StartReadOperation( CHANNEL_PTR, RR_PTR ) ;
+static INT16 _near GetData( CHANNEL_PTR, RR_PTR ) ;
+static INT16 _near EOM_Read(CHANNEL_PTR);
+static INT16 _near AcquireReadBuffer( CHANNEL_PTR, BOOLEAN ) ;
+static BOOLEAN _near ReadRequest( CHANNEL_PTR, BUF_PTR ) ;
+static VOID _near FlushReads(CHANNEL_PTR);
+static VOID _near AbortRead( CHANNEL_PTR, INT16 ) ;
+static BOOLEAN _near IsLBAInTheBuffers( CHANNEL_PTR, UINT32, INT16_PTR ) ;
+static VOID _near CleanUpDriverQ(CHANNEL_PTR);
+static UINT16 _near CalcReTransSize( CHANNEL_PTR, UINT64 ) ;
+static VOID _near HandleSXStartScanTapeConcerns( CHANNEL_PTR ) ;
+
+/**/
+/**
+
+ Name: StartReadOperation
+
+ Description: Kicks off a reading session.
+
+ Modified: 9/7/1989 13:33:9
+
+ Returns: An error code if there is an error, and a zero if there
+ is not.
+
+ Notes: THERE SHOULD ALWAYS BE A VALID READ BUFFER IN THE
+ "channel->cur_buff" pointer. This function is called after
+ positioning is done.
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+static INT16 _near StartReadOperation(
+ CHANNEL_PTR channel,
+ RR_PTR req )
+{
+ INT16 ret_val = TFLE_NO_ERR ;
+ DRIVE_PTR curDRV = channel->cur_drv ;
+ BOOLEAN need_read = FALSE ;
+ UINT16 lba_offset = 0 ;
+
+ /* Initialize buffer pointers */
+ req->buff_size = req->buff_used = 0 ;
+
+ /* Move to current VCB */
+ channel->running_lba = 0L ;
+ ret_val = MoveToVCB( channel, (INT16)0, & need_read, TRUE ) ;
+ if ( ret_val != TFLE_NO_ERR ) {
+ return ret_val ;
+ }
+
+ if( curDRV->vcb_valid ) {
+ /* Set the stuff up for next tape */
+ channel->tape_id = FS_ViewTapeIDInVCB( (VOID_PTR)&curDRV->cur_vcb ) ;
+ channel->ts_num = FS_ViewTSNumInVCB( (VOID_PTR)&curDRV->cur_vcb ) ;
+ channel->bs_num = FS_ViewBSNumInVCB( (VOID_PTR)&curDRV->cur_vcb ) ;
+
+ channel->cur_drv->cur_pos.tape_seq = channel->ts_num ;
+
+ /* we may be scanning tape on an SX drive */
+ HandleSXStartScanTapeConcerns( channel ) ;
+
+ /* Copy it to their memory */
+ *req->vcb_ptr = curDRV->cur_vcb ;
+ }
+
+ /* Fix for the app not knowing the LBA for a continuation VCB */
+ if( channel->cross_set == channel->ui_tpos->backup_set_num ) {
+ req->tape_loc.lba_vcb = channel->cross_lba ;
+
+ /* If we're going for the VCB itself, we need to set the LBA
+ as well for the GotoBlock math to work.
+ */
+ if( req->tape_loc.lba == 0 ) {
+ req->tape_loc.lba = channel->cross_lba ;
+ }
+ }
+
+ channel->cur_drv->cur_pos.tape_seq = req->tape_loc.tape_seq ;
+ channel->cur_drv->cur_pos.pba_vcb = req->tape_loc.pba_vcb ;
+ channel->cur_drv->cur_pos.lba_vcb = req->tape_loc.lba_vcb ;
+ channel->cur_drv->cur_pos.lba = req->tape_loc.lba ;
+
+ /* If needed, tell the drive the base block position we are positioning
+ from */
+ if( DriveAttributes( curDRV ) & TDI_REAL_BLK_POS ) {
+ TpSpecial( curDRV->drv_hdl, (INT16)SS_PHYS_BLOCK, req->tape_loc.pba_vcb ) ;
+ }
+
+ /* This is a special case where the translator is doing all the work */
+ if( !channel->read_from_tape ) {
+
+ /* Set Up Block Pointers */
+ channel->cur_dblk = req->cur_dblk ;
+
+ if( req->cur_dblk != NULL ) {
+ *req->cur_dblk = curDRV->cur_vcb ;
+ }
+
+ req->tf_message = TRR_VCB ;
+
+ /* indicate we are not doing fast file positioning */
+ req->tape_loc.pba_vcb = 0L ;
+
+ /* If we are doing fast file positioning - even on the EXABYTE 8200SX */
+ } else if( ( req->tape_loc.pba_vcb &&
+ req->tape_loc.pba_vcb != MANUFACTURED_PBA &&
+ SupportBlkPos( curDRV ) ) || SX_AbleToFindBlock( channel ) ) {
+
+ /* We Are not at end of set */
+ ClrPosBit( channel->cur_drv, ( AT_EOS | AT_EOD | AT_BOT ) ) ;
+ ClrChannelStatus( channel, CH_DONE ) ;
+
+ /* Get rid of the current buffer */
+ PuntBuffer( channel ) ;
+
+ /* Were holding on to an old vcb, and seeking to a new set! */
+ /* So update the vcb's and channel's ideas of what the set */
+ /* number is (we may need it later...). */
+ FS_SetBSNumInVCB( (VOID_PTR)&curDRV->cur_vcb, channel->ui_tpos->backup_set_num ) ;
+ channel->bs_num = channel->ui_tpos->backup_set_num ;
+
+ if( SX_AbleToFindBlock( channel ) ) {
+ /* Find that Block on the EXABYTE 8200SX */
+ ret_val = SX_FindBlock( channel, req->tape_loc.lba, channel->ui_tpos, TF_SEARCHING ) ;
+ } else {
+ /* Go to that Block */
+ ret_val = GotoBlock( channel, req->tape_loc.lba,
+ channel->ui_tpos, &lba_offset ) ;
+ }
+
+ if( ret_val == TFLE_USER_ABORT ) {
+ SetPosBit( channel->cur_drv, REW_CLOSE ) ;
+ }
+
+ channel->running_lba = req->tape_loc.lba -
+ lba_offset / channel->lb_size ;
+
+ } else if( curDRV->vcb_valid ) {
+
+ /* Set Up Block Pointers */
+ channel->cur_dblk = req->cur_dblk ;
+
+ if( req->cur_dblk != NULL ) {
+ *req->cur_dblk = curDRV->cur_vcb ;
+ }
+
+ req->tf_message = TRR_VCB ;
+
+ /* indicate we are not doing fast file positioning */
+ req->tape_loc.pba_vcb = 0L ;
+
+ } else {
+ /* indicate we are not doing fast file positioning */
+ req->tape_loc.pba_vcb = 0L ;
+ }
+
+ /* If no error so far */
+ if( !ret_val && channel->read_from_tape ) {
+ /* If we already have a buffer, and we haven't accounted for it
+ do so now */
+ if( channel->cur_buff != NULL ) {
+
+ channel->running_lba = req->tape_loc.lba_vcb +
+ (UINT32)( BM_XferSize( channel->cur_buff ) /
+ channel->lb_size ) ;
+
+ if( SX_IsStatusSet( channel, SX_SCAN_ACTIVE ) &&
+ SX_IsOK( channel ) ) {
+ /* adjust the LBA for the first TpRead() call */
+ SX_AdjustLBANow( channel, BM_XferSize( channel->cur_buff ) ) ;
+ }
+ BM_SetBeginningLBA( channel->cur_buff, req->tape_loc.lba_vcb ) ;
+ }
+
+ if ( channel->cur_buff == NULL || BM_ReadError( channel->cur_buff ) == GEN_NO_ERR ) {
+ FlushReads( channel ) ;
+ }
+
+ /* If Fast File - even on the EXABYTE 8200SX wait for a buffer */
+ if( ( req->tape_loc.pba_vcb &&
+ req->tape_loc.pba_vcb != MANUFACTURED_PBA &&
+ SupportBlkPos( curDRV ) ) ||
+ SX_AbleToFindBlock( channel ) ) {
+
+ ret_val = AcquireReadBuffer( channel, FALSE ) ;
+ if ( ret_val != TFLE_NO_ERR && ! IsTFLE( ret_val ) ) {
+ /* somehow we got an exception already! */
+ msassert( FALSE ) ;
+ ret_val = TFLE_PROGRAMMER_ERROR1 ;
+ }
+ if( ret_val == TFLE_NO_ERR ) {
+ BM_UpdCnts( channel->cur_buff, lba_offset ) ;
+ }
+ }
+ }
+
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Name: DoRead
+
+ Description: Dispatches a read call.
+
+ Modified: 6/19/1990 9:54:37
+
+ Returns: An error code if not successful, and zero if it was.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+INT16 DoRead(
+ CHANNEL_PTR channel,
+ RR_PTR req )
+{
+ BOOLEAN done = FALSE ;
+ BOOLEAN switched_tapes = FALSE ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ BUF_PTR tmpBUF ;
+ UINT32 lba ;
+ Q_ELEM_PTR qe_ptr;
+ UINT16 blk_type ;
+
+ /* We use this as a flag for later */
+ req->tf_message = 0 ;
+
+ switch( req->lp_message ) {
+
+ case LRR_ABORT:
+ ret_val = TFLE_USER_ABORT ;
+ /* fall through */
+
+ case LRR_FINISHED:
+ AbortRead( channel, ret_val ) ;
+ break ;
+
+ /* Handle the End Of Volume Case */
+ case LRR_EOM_ACK:
+ if( ( ret_val = EOM_Read( channel ) ) != TFLE_NO_ERR ) {
+ done = TRUE ;
+ } else {
+ *req->vcb_ptr = channel->cur_drv->cur_vcb ;
+ }
+ /* fall through */
+
+ case LRR_GOTO_LBA:
+
+ /* To prevent fall thru of above case */
+ if( req->lp_message != LRR_EOM_ACK ) {
+
+ if( channel->cur_drv->cur_pos.tape_seq != req->tape_loc.tape_seq ) {
+ CleanUpDriverQ( channel ) ;
+
+ /* Ok, now lets switch to a new drive */
+ SetChannelStatus( channel, CH_AT_EOM ) ;
+ if( NextDriveInChannel( channel, TRUE ) == TF_END_CHANNEL ) {
+ ResetChannelList( channel, FALSE ) ;
+ }
+
+ channel->cur_drv->cur_pos.tape_seq = req->tape_loc.tape_seq ;
+ channel->cur_drv->cur_pos.pba_vcb = req->tape_loc.pba_vcb ;
+ channel->cur_drv->cur_pos.lba_vcb = req->tape_loc.lba_vcb ;
+ channel->cur_drv->cur_pos.lba = req->tape_loc.lba ;
+
+ channel->ui_tpos->tape_seq_num = req->tape_loc.tape_seq ;
+ channel->ts_num = req->tape_loc.tape_seq ;
+
+ if( ( ret_val = PositionAtSet( channel, channel->ui_tpos, FALSE ) ) == TFLE_NO_ERR ) {
+
+ /* Set the lba of the beginning of the buffer and
+ adjust the running lba
+ */
+ BM_SetBeginningLBA( channel->cur_buff, channel->cur_drv->cur_pos.lba_vcb ) ;
+ channel->running_lba =
+ channel->cur_drv->cur_pos.lba_vcb +
+ (UINT32)( BM_XferSize( channel->cur_buff ) /
+ channel->lb_size ) ;
+
+ /* If needed, tell the drive the base block position
+ we are positioning from.
+ */
+ if( DriveAttributes( ( channel->cur_drv ) ) & TDI_REAL_BLK_POS ) {
+ TpSpecial( channel->cur_drv->drv_hdl, (INT16)SS_PHYS_BLOCK, FS_ViewPBAinVCB( &channel->cur_drv->cur_vcb ) ) ;
+ }
+ }
+ ClrChannelStatus( channel, CH_AT_EOM ) ;
+
+ /* this is the case because we need a different tape */
+ switched_tapes = TRUE ;
+ }
+
+ if( ret_val == TFLE_NO_ERR ) {
+ /* Setup Local Variable */
+ lba = req->tape_loc.lba ;
+
+ /* We will not be in data phase ... hopefully */
+ ClrChannelStatus( channel, CH_DATA_PHASE ) ;
+
+ /* If the drive supports fast file positioning,
+ even on the EXABYTE 8200SX - MaynStream 2200+ - do it */
+ if( ( req->tape_loc.pba_vcb != MANUFACTURED_PBA &&
+ req->tape_loc.pba_vcb != 0 &&
+ SupportBlkPos( channel->cur_drv ) ) ||
+ SX_AbleToFindBlock( channel ) ) {
+
+ /* Do we already have the requested block */
+ if( !IsLBAInTheBuffers( channel, lba, &ret_val ) && ret_val == TFLE_NO_ERR ) {
+
+ UINT16 lba_offset = 0 ;
+
+ /* Clean Up any Pending driver requests */
+ CleanUpDriverQ( channel ) ;
+
+ /* Attempt to goto the correct block, if successful, re-queue all read
+ requests
+ */
+ if( SX_AbleToFindBlock( channel ) ) {
+ /* Find that Block on the EXABYTE 8200SX */
+ ret_val = SX_FindBlock( channel, req->tape_loc.lba, channel->ui_tpos, TF_SKIPPING_DATA ) ;
+ } else {
+ /* Go to that Block */
+ ret_val = GotoBlock( channel,
+ req->tape_loc.lba,
+ NULL, &lba_offset ) ;
+ }
+
+ if( ret_val == TFLE_NO_ERR ) {
+ /* Re-read all buffers */
+ channel->running_lba = lba -
+ lba_offset / channel->lb_size ;
+ FlushReads( channel ) ;
+ ret_val = AcquireReadBuffer( channel, TRUE ) ;
+ if ( ret_val != TFLE_NO_ERR && ! IsTFLE( ret_val ) ) {
+ /* somehow we got an exception already! */
+ msassert( FALSE ) ;
+ ret_val = TFLE_PROGRAMMER_ERROR1 ;
+ }
+ if( ret_val == TFLE_NO_ERR ) {
+ BM_UpdCnts( channel->cur_buff, lba_offset ) ;
+ }
+ } else if ( ret_val == TFLE_USER_ABORT ) {
+ SetPosBit( channel->cur_drv, REW_CLOSE ) ;
+ }
+ }
+
+ } else {
+
+ /* indicate we are not doing fast file positioning */
+ req->tape_loc.pba_vcb = 0L ;
+
+ tmpBUF = channel->cur_buff ;
+
+ /* if we switched over to another tape then ... */
+ if( switched_tapes ) {
+
+ /* let's make sure we are back in sync ... */
+ req->tape_loc.lba_vcb = channel->cur_drv->cur_pos.lba_vcb ;
+ BM_SetBeginningLBA( tmpBUF, channel->cur_drv->cur_pos.lba_vcb ) ;
+ channel->running_lba =
+ channel->cur_drv->cur_pos.lba_vcb +
+ (UINT32)( BM_XferSize( channel->cur_buff ) /
+ channel->lb_size ) ;
+
+ FlushReads( channel ) ;
+ }
+
+ /* Simulate Goto block by reading until we hit the
+ buffer that contains the requested LBA
+ */
+ while( ret_val == TFLE_NO_ERR &&
+ ( lba > ( BM_BeginningLBA( tmpBUF ) +
+ ( ( BM_BytesFree( tmpBUF ) +
+ BM_NextByteOffset( tmpBUF ) ) /
+ channel->lb_size ) ) ) ) {
+
+ if( ( ret_val =
+ AcquireReadBuffer( channel, TRUE ) ) ==
+ TFLE_NO_ERR ) {
+ tmpBUF = channel->cur_buff ;
+ } else {
+ if ( ! IsTFLE( ret_val ) ) {
+ /* somehow we got an exception already! */
+ msassert( FALSE ) ;
+ ret_val = TFLE_PROGRAMMER_ERROR1 ;
+ }
+ }
+ }
+
+ /* If no error, adjust the buffer to point to the
+ right place
+ */
+ if( ret_val == TFLE_NO_ERR ) {
+ BM_UpdCnts( tmpBUF,
+ (UINT16)( channel->lb_size -
+ ( BM_NextByteOffset( tmpBUF ) %
+ channel->lb_size ) ) ) ;
+
+ lba -= (UINT32)( BM_NextByteOffset( tmpBUF ) /
+ channel->lb_size ) ;
+ BM_UpdCnts( tmpBUF, (UINT16)( ( lba -
+ BM_BeginningLBA( tmpBUF ) ) *
+ channel->lb_size ) ) ;
+ }
+ }
+ }
+ }
+ /* fall through */
+
+ case LRR_START:
+ case LRR_STUFF:
+
+ /* If we are starting out, then do the start code */
+ if( req->lp_message == LRR_START ) {
+ ret_val = StartReadOperation( channel, req ) ;
+ /* Unless we did a seek to the start of the set, we're done.
+ otherwise we need to read in the VCB.
+ */
+ if( !req->tape_loc.pba_vcb ||
+ ( channel->cross_set == channel->bs_num &&
+ req->tape_loc.lba != channel->cross_lba ) ||
+ ( channel->cross_set != channel->bs_num &&
+ req->tape_loc.lba != 0 ) ) {
+
+ done = TRUE ;
+ }
+ }
+
+ if( req->filter_to_use == TF_SKIP_ALL_DATA || req->filter_to_use == TF_SKIP_DATA_STREAM ) {
+ if( req->filter_to_use == TF_SKIP_ALL_DATA ) {
+ SetChannelStatus( channel, CH_SKIP_ALL_STREAMS ) ;
+ } else {
+ SetChannelStatus( channel, CH_SKIP_CURRENT_STREAM ) ;
+ }
+ (*channel->ui_tpos->UI_TapePosRoutine)( TF_SKIPPING_DATA, channel->ui_tpos, FALSE, NULL, channel->mode ) ;
+ }
+
+ while( !done && ret_val == TFLE_NO_ERR ) {
+
+ /* Normal Case ... We only want one pass */
+ done = TRUE ;
+
+ /* Is there data associated with this TBLK */
+ if( DataPhase( channel ) ) {
+
+
+ ret_val = GetData( channel, req ) ;
+
+ if( req->buff_size && DataPhase( channel ) ) {
+ req->tf_message = TRR_DATA ;
+ }
+ }
+
+ if( ret_val == TFLE_NO_ERR &&
+ channel->read_from_tape &&
+ ( channel->cur_buff == NULL ||
+ BM_BytesFree( channel->cur_buff ) == 0 ) ) {
+ if ( ! AtEOM( channel ) && ! IsSetDone( channel ) ) {
+ if( ( ret_val = AcquireReadBuffer( channel, FALSE ) ) == TFLE_NO_ERR ) {
+ if( BM_BytesFree( channel->cur_buff ) == 0 ) {
+ done = FALSE ;
+ continue ; /* for another AcquireReadBuffer */
+ }
+ } else if ( ! IsTFLE( ret_val ) ) {
+ /* hitting an exception is handled later. */
+ ret_val = TFLE_NO_ERR ;
+ }
+ }
+ if( AtEOM( channel ) ) {
+ req->tf_message = TRR_EOM ;
+ req->buff_size = 0 ;
+ req->buff_used = 0 ;
+ } else if( IsSetDone( channel ) ) {
+ SetPosBit( channel->cur_drv, AT_EOS ) ;
+ req->tf_message = TRR_END ;
+ }
+ }
+
+ if( !ret_val && req->tf_message != TRR_END && req->tf_message != TRR_DATA && req->tf_message != TRR_EOM ) {
+
+ channel->cur_dblk = req->cur_dblk ;
+ channel->loop_filter = TF_KEEP_ALL_DATA ;
+ ClrChannelStatus( channel, CH_DATA_PHASE ) ;
+
+ /* Zero Out Buffer Stuff */
+ req->buff_size = req->buff_used = 0 ;
+
+ if( ( ret_val = RD_TranslateDBLK( channel, channel->cur_buff, &blk_type ) ) != TFLE_NO_ERR ) {
+ if( ret_val == TF_NO_MORE_DATA ) {
+ SetChannelStatus( channel, CH_DONE ) ;
+ SetPosBit( channel->cur_drv, AT_EOS ) ;
+ req->tf_message = TRR_END ;
+ ret_val = TFLE_NO_ERR ;
+ } else {
+ SetPosBit( channel->cur_drv, REW_CLOSE ) ;
+ req->tf_message = TRR_FATAL_ERR ;
+ }
+ } else {
+
+ switch( blk_type ) {
+
+ case BT_FDB:
+ *req->fdb_ptr = *req->cur_dblk ;
+ channel->lst_fid = FS_ViewBLKIDinDBLK( req->cur_dblk ) ;
+ req->tf_message = TRR_FDB ;
+ channel->eom_id = FS_ViewBLKIDinDBLK( req->cur_dblk ) ;
+ break ;
+
+ case BT_DDB:
+ *req->ddb_ptr = *req->cur_dblk ;
+ channel->lst_did = FS_ViewBLKIDinDBLK( req->cur_dblk ) ;
+ req->tf_message = TRR_DDB ;
+ channel->eom_id = FS_ViewBLKIDinDBLK( req->cur_dblk ) ;
+ break ;
+
+ case BT_VCB:
+ *req->vcb_ptr = *req->cur_dblk ;
+ req->tf_message = TRR_VCB ;
+ channel->eom_id = FS_ViewBLKIDinDBLK( req->cur_dblk ) ;
+ break ;
+
+ case BT_MDB:
+ done = FALSE ;
+ break ;
+
+ case BT_UDB:
+ done = FALSE ;
+ break ;
+
+ case BT_IDB:
+ *req->idb_ptr = *req->cur_dblk ;
+ req->tf_message = TRR_IDB ;
+ channel->eom_id = FS_ViewBLKIDinDBLK( req->cur_dblk ) ;
+ break ;
+
+ case BT_CFDB:
+ req->tf_message = TRR_CFDB ;
+ channel->eom_id = FS_ViewBLKIDinDBLK( req->cur_dblk ) ;
+ break ;
+
+ case BT_STREAM:
+ req->tf_message = TRR_NEW_STREAM ;
+ SetChannelStatus( channel, CH_DATA_PHASE ) ;
+ req->stream = channel->current_stream ;
+ if( IsChannelStatus( channel, ( CH_SKIP_ALL_STREAMS | CH_SKIP_CURRENT_STREAM ) ) ) {
+ done = FALSE ;
+ continue ;
+ }
+ break ;
+
+ case BT_HOSED:
+ default:
+ SetPosBit( channel->cur_drv, REW_CLOSE ) ;
+ req->tf_message = TRR_FATAL_ERR ;
+ ret_val = TFLE_TAPE_INCONSISTENCY ;
+ break ;
+
+ }
+ }
+
+ } else if( req->tf_message == TRR_END ) {
+ while ( ( qe_ptr = DeQueueElem( &channel->cur_drv->inproc_q ) ) != NULL ) {
+ tmpBUF = QueuePtr( qe_ptr );
+ BM_Put( tmpBUF ) ;
+ }
+ }
+ } /* while !done */
+
+ break ;
+
+ case LRR_SKIP_STREAM:
+
+ break ;
+
+
+ default:
+ msassert( FALSE );
+ break;
+ } /* end switch */
+
+ if( IsPosBitSet( channel->cur_drv, REW_CLOSE ) ) {
+ FreeFormatEnv( &( channel->cur_fmt ), &( channel->fmt_env ) ) ;
+ }
+ if( ret_val != TFLE_NO_ERR &&
+ ret_val != TFLE_USER_ABORT &&
+ ret_val != TFLE_UI_HAPPY_ABORT ) {
+
+ CleanUpDriverQ( channel ) ;
+ }
+
+ return( ret_val ) ;
+}
+
+
+
+
+/**/
+/**
+
+ Name: AcquireReadBuffer
+
+ Description: Gets a packet of data from the tape.
+
+ Modified: 9/7/1989 14:14:26
+
+ Returns: if error: TFLE_xxx codes
+ if non-ignored exception: FMT_EXC_xxx codes
+ if we got data: TFLE_NO_ERR
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+static INT16 _near AcquireReadBuffer(
+ CHANNEL_PTR channel,
+ BOOLEAN ignore_eos )
+{
+ INT16 drv_hdl = channel->cur_drv->drv_hdl ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ DRIVE_PTR curDRV = channel->cur_drv ;
+ BUF_PTR tmpBUF ;
+ RET_BUF myret ;
+ UINT16 exception_type ;
+ BOOLEAN done = FALSE ;
+
+ /* If this function is called, and we say we think we are done, then there
+ be a problem */
+ if( IsSetDone( channel ) && !ignore_eos ) {
+ return( TFLE_UNEXPECTED_EOS ) ;
+ }
+
+ if ( channel->cur_buff != NULL && BM_ReadError( channel->cur_buff ) != GEN_NO_ERR ) {
+
+ BM_UseAll( channel->cur_buff ) ;
+
+ /* ask the translator how to handle the exception */
+ ret_val = RD_Exception( channel, BM_ReadError( channel->cur_buff ), &exception_type ) ;
+ if ( exception_type == FMT_EXC_EOS ) {
+ SetChannelStatus( channel, CH_DONE ) ;
+ }
+
+ if ( ret_val != TFLE_NO_ERR || exception_type != FMT_EXC_IGNORE ) {
+ PuntBuffer( channel ) ;
+ if ( ret_val != TFLE_NO_ERR ) {
+ return ret_val ;
+ } else {
+ return (INT16)exception_type ;
+ }
+ }
+ }
+
+ /* Since we have called this function,
+ we must be done with the current buffer */
+
+ if ( channel->cur_buff != NULL ) {
+ PuntBuffer( channel ) ;
+
+ /* Decide if we are using DMA or PIO */
+ if( !( lw_tfl_control.cntl_cards[curDRV->thw_inf.card_no].card_attribs & DD_CARD_NON_ASYNC ) ) {
+ if( !TpSpecial( drv_hdl, (INT16)SS_IS_ERROR, 0L ) ) {
+ tmpBUF = BM_Get( &channel->buffer_list ) ;
+ if ( tmpBUF != NULL ) {
+ if ( !ReadRequest( channel, tmpBUF ) ) {
+ BM_Put( tmpBUF );
+ }
+ }
+ }
+ } else { /* PIO */
+ FlushReads( channel ) ;
+ }
+ }
+
+ while( !done ) {
+ while( TpReceive( drv_hdl, &myret ) == FAILURE )
+ ThreadSwitch() ; /* for non-preemptive operating systems */
+
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( channel->cur_drv->thw_inf.the, myret.the ) ;
+
+ if( myret.call_type == GEN_SPECIAL ) {
+ /* we got a position information sample */
+ if( myret.gen_error == GEN_NO_ERR ) {
+ /* write the sample to the SX file */
+ SX_WriteTmpFile( channel ) ;
+ }
+ } else {
+
+ tmpBUF = QueuePtr( DeQueueElem( &curDRV->inproc_q ) ) ;
+ BM_SetBytesFree( tmpBUF, (UINT16)myret.len_got ) ;
+ BM_SetReadError( tmpBUF, myret.gen_error ) ;
+ channel->cur_buff = tmpBUF ;
+ done = TRUE ;
+ TF_ReadBufferHook( channel, tmpBUF );
+
+ if( myret.gen_error != GEN_NO_ERR ) {
+ BE_Zprintf( DEBUG_TAPE_FORMAT, RES_DEVICE_ERROR, myret.gen_error ) ;
+ BE_Zprintf( 0, TEXT("Len Req = %ld Len Got = %ld\n"), myret.len_req, myret.len_got ) ;
+ DumpDebug( drv_hdl ) ;
+ curDRV->thw_inf.drv_status = myret.status ;
+ curDRV->cur_stats.underruns = myret.underruns ;
+ curDRV->cur_stats.dataerrs = myret.readerrs ;
+ /* maintain our filemark position */
+ if ( myret.gen_error == GEN_ERR_ENDSET || myret.gen_error == GEN_ERR_EOM ) {
+ curDRV->cur_pos.fmks++ ;
+
+ /* consider ending the gathering of positioning information for this set */
+ if( SX_IsStatusSet( channel, SX_SCAN_ACTIVE ) ) {
+ if( SX_TmpFileIsOK( channel ) ) {
+ SX_EndSampling( channel ) ;
+ }
+
+ /* we are not scanning tape any more */
+ SX_ClearStatus( channel, SX_SCAN ) ;
+ }
+ }
+ }
+ }
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Name: GetData
+
+ Description: During a data phase of tape reading, parcels out data.
+
+ Modified: 9/11/1989 9:9:3
+
+ Returns: An error code, or zero if successful.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+static INT16 _near GetData(
+ CHANNEL_PTR channel,
+ RR_PTR req )
+{
+
+ INT16 ret_val = TFLE_NO_ERR ;
+ BUF_PTR cur_buf = channel->cur_buff ;
+ UINT16 amount ;
+ BOOLEAN t_ret_val, status ;
+ STREAM_INFO_PTR currentStream = &channel->current_stream ;
+
+ /* To Handle aborted sets */
+ if( IsSetDone( channel ) ) {
+ if ( cur_buf == NULL ) { // chs:02-22-93 per MikeP
+ return( TFLE_TAPE_INCONSISTENCY ) ; // chs:02-22-93 per MikeP
+ } // chs:02-22-93 per MikeP
+ if( U64_GT( currentStream->size,
+ U64_Init( BM_BytesFree( cur_buf ), 0L ) ) ) {
+ return( TFLE_TAPE_INCONSISTENCY ) ;
+ }
+ }
+
+ if( IsChannelStatus( channel, ( CH_SKIP_ALL_STREAMS | CH_SKIP_CURRENT_STREAM ) ) ) {
+
+
+
+ /* Is there any data to skip */
+ while( ( U64_EQ( currentStream->size, U64_Init( 0L, 0L ) ) == FALSE ) &&
+ ret_val == TFLE_NO_ERR ) {
+ if( (*channel->ui_tpos->UI_TapePosRoutine)( TF_IDLE, channel->ui_tpos, FALSE, NULL, channel->mode ) == UI_ABORT_POSITIONING ) {
+ return( TFLE_USER_ABORT ) ;
+ }
+ if ( BM_BytesFree( cur_buf ) == 0 ) {
+ if( AtEOM( channel ) ) {
+ return( ret_val ) ;
+ } else {
+ if ( ( ret_val = AcquireReadBuffer( channel, FALSE ) ) == TFLE_NO_ERR ) {
+ cur_buf = channel->cur_buff ;
+ }
+ }
+ }
+
+ if ( ret_val == TFLE_NO_ERR ) {
+
+ amount = CalcReTransSize( channel, currentStream->size ) ;
+
+ BM_UpdCnts( cur_buf, amount ) ;
+
+ currentStream->size = U64_Sub( currentStream->size,
+ U64_Init( ( UINT32 ) amount, 0 ), &status ) ;
+
+
+ if ( U64_EQ( channel->retranslate_size, CH_NO_RETRANSLATE_40 ) == FALSE ) {
+ channel->retranslate_size =
+ U64_Sub( channel->retranslate_size,
+ U64_Init( amount, 0L ), &t_ret_val );
+ }
+ } else {
+// if ( ! IsTFLE( ret_val ) ) { /* is this FMT_EXC_xxx ? */
+// ret_val = TFLE_NO_ERR ;
+// }
+ }
+ }
+ if ( ret_val != FMT_EXC_EOM ) {
+ ClrChannelStatus( channel, CH_DATA_PHASE ) ;
+ }
+
+ } else {
+
+ /* We want the data to this stream */
+
+
+ /* Are we supposed to get any data */
+ if( ( U64_EQ( currentStream->size, U64_Init( 0L, 0L ) ) == FALSE ) &&
+ ret_val == TFLE_NO_ERR ) {
+ /* How Much did he use ? */
+ BM_UpdCnts( cur_buf, req->buff_used ) ;
+
+ currentStream->size = U64_Sub( channel->current_stream.size,
+ U64_Init( ( UINT32 ) req->buff_used, 0 ), &status ) ;
+
+ if ( U64_EQ( channel->retranslate_size,
+ CH_NO_RETRANSLATE_40 ) == FALSE ) {
+ channel->retranslate_size =
+ U64_Sub( channel->retranslate_size,
+ U64_Init( req->buff_used, 0L ), &t_ret_val ) ;
+ }
+
+ /* loop is because retranslate could eat last part of buffer */
+ do {
+ /* Is This buffer used up */
+ if( BM_BytesFree( cur_buf ) == 0 &&
+ ( U64_EQ( currentStream->size, U64_Init( 0L, 0L ) ) == FALSE ) ) {
+
+ if ( ( ret_val = AcquireReadBuffer( channel, FALSE ) ) == TFLE_NO_ERR ) {
+ cur_buf = channel->cur_buff ;
+ }
+ }
+
+ if ( ret_val == TFLE_NO_ERR ) {
+ req->buff_size = CalcReTransSize( channel,
+ currentStream->size ) ;
+ req->buff_ptr = BM_NextBytePtr( cur_buf ) ;
+ }
+
+ } while ( ret_val == TFLE_NO_ERR && req->buff_size == 0 &&
+ U64_EQ( currentStream->size, U64_Init( 0L, 0L ) ) == FALSE ) ;
+ }
+
+ }
+
+ if ( ret_val != TFLE_NO_ERR && !IsTFLE( ret_val ) ) {
+ return TFLE_NO_ERR ; /* on exceptions */
+ } else {
+ return ret_val ;
+ }
+}
+
+/**/
+/**
+
+ Name: CalcReTransSize
+
+ Description: Calculates the retranslate size based on the channel info
+
+ Modified: 4/12/1990 14:5:20
+
+ Returns: UINT16, the amount to use from this buffer
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+static UINT16 _near CalcReTransSize(
+ CHANNEL_PTR channel,
+ UINT64 amount )
+{
+ UINT16 to_use, usable ;
+
+ /* There is no retranslate */
+ if( U64_EQ( channel->retranslate_size, CH_NO_RETRANSLATE_40 ) ) {
+
+ to_use = (UINT16)( ( U64_Lsw( amount ) >
+ BM_BytesFree( channel->cur_buff ) ||
+ U64_Msw( amount ) != 0L )
+ ? BM_BytesFree( channel->cur_buff )
+ : U64_Lsw( amount ) ) ;
+
+ } else if( U64_EQ( channel->retranslate_size, CH_IMMEDIATE_RETRANSLATE_40 ) ) {
+
+ if ( RD_ReTranslateDBLK( channel, channel->cur_buff ) ) {
+
+ usable = (UINT16)( ( U64_Lsw( amount ) >
+ BM_BytesFree( channel->cur_buff ) ||
+ U64_Msw( amount ) != 0L )
+ ? BM_BytesFree( channel->cur_buff )
+ : U64_Lsw( amount ) ) ;
+
+ to_use = (UINT16)( ( U64_Lsw( channel->retranslate_size ) >
+ usable ||
+ U64_Msw( amount ) != 0L )
+ ? usable
+ : U64_Lsw( channel->retranslate_size ) ) ;
+
+ } else {
+ to_use = 0 ;
+ }
+ } else {
+ usable = (UINT16)( ( U64_Lsw( amount ) >
+ BM_BytesFree( channel->cur_buff ) ||
+ U64_Msw( amount ) != 0L )
+ ? BM_BytesFree( channel->cur_buff )
+ : U64_Lsw( amount ) ) ;
+
+ to_use = (UINT16)( ( U64_Lsw( channel->retranslate_size ) >
+ usable ||
+ U64_Msw( amount ) != 0L )
+ ? usable
+ : U64_Lsw( channel->retranslate_size ) ) ;
+ }
+
+ return( to_use ) ;
+}
+
+/**/
+/**
+
+ Name: ReadRequest
+
+ Description: EnQueues a Request for Read.
+
+ Modified: 6/19/1990 9:54:20
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+static BOOLEAN _near ReadRequest(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+ /* do we need to sample the position for an EXABYTE 8200SX - MaynStream 2200+ ? */
+ if( SX_IsStatusSet( channel, SX_SCAN_ACTIVE ) &&
+ SX_TmpFileIsOK( channel ) ) {
+
+ SX_SamplingProcessing( channel, ( UINT32 )BM_XferSize( buffer ) ) ;
+
+ /* do we need to keep track of where the EXABYTE 8200SX - MaynStream 2200+ is a fast file search ? */
+ } else if( SX_IsStatusSet( channel, SX_AT_SET ) &&
+ SX_FileIsOK( channel ) ) {
+
+ SX_AdjustLBANow( channel, BM_XferSize( buffer ) ) ;
+ }
+
+ /* Read */
+ if ( TpRead( channel->cur_drv->drv_hdl, BM_XferBase( buffer ),
+ (UINT32)BM_XferSize( buffer ) ) == SUCCESS ) {
+
+ /* Update the first LBA in this buffer */
+ BM_SetBeginningLBA( buffer, channel->running_lba ) ;
+
+ /* Update the running LBA count */
+ channel->running_lba += (UINT32)( BM_XferSize( buffer ) /
+ channel->lb_size ) ;
+
+ /* Put it on the in process queue */
+ EnQueueElem( &channel->cur_drv->inproc_q, &BM_QElem( buffer ), FALSE ) ;
+
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+
+/**/
+/**
+
+ Name: EOM_Read
+
+ Description: Handles the EOM processing during a read sequence.
+
+ Modified: 9/13/1989 11:13:1
+
+ Returns: An error code if there is an error, and 0 if there is
+ not.
+
+ Notes: IT IS ASSUMED THAT THE "cur_dblk" IN THE CURRENT CHANNEL
+ IS SET BEFORE THIS FUNCTION IS CALLED.
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+static INT16 _near EOM_Read(
+ CHANNEL_PTR channel )
+{
+ INT16 ret_val = TFLE_NO_ERR, tmp ;
+ DRIVE_PTR old_drv = channel->cur_drv ;
+ BUF_PTR tmp_buf ;
+ Q_ELEM_PTR qe_ptr;
+ UINT16 save_stats = channel->status & (CH_SKIP_ALL_STREAMS|CH_SKIP_CURRENT_STREAM) ;
+
+ PuntBuffer( channel ) ;
+
+ /* Now Get rid of all pending reads */
+ while ( ( qe_ptr = DeQueueElem( &old_drv->inproc_q ) ) != NULL ) {
+ tmp_buf = QueuePtr( qe_ptr );
+ channel->cur_buff = tmp_buf ;
+ PuntBuffer( channel ) ;
+ }
+
+ /* Ok, now lets switch to a new drive */
+ tmp = NextDriveInChannel( channel, TRUE ) ;
+
+ if( IsTFLE( tmp ) ) {
+ ret_val = tmp ;
+ } else {
+ if( tmp == TF_END_CHANNEL ) {
+ tmp = ResetChannelList( channel, FALSE ) ;
+ if( IsTFLE( tmp ) ) {
+ ret_val = tmp ;
+ }
+ }
+ }
+
+ if( !ret_val ) {
+ /* If we are actually sitting at end of data, rewind drive before
+ proceeding */
+ if( IsPosBitSet( channel->cur_drv, AT_EOD ) ) {
+ RewindDrive( channel->cur_drv, channel->ui_tpos, TRUE, TRUE, channel->mode ) ;
+ }
+ /* Let's do some more positioning */
+ channel->ui_tpos->tape_id = channel->tape_id ;
+ channel->ui_tpos->tape_seq_num = ++( channel->ts_num ) ;
+ channel->cur_drv->cur_pos.tape_seq = channel->ts_num ;
+ channel->ui_tpos->backup_set_num = channel->bs_num ;
+
+ if( ( ret_val = PositionAtSet( channel, channel->ui_tpos, FALSE ) ) == TFLE_NO_ERR ) {
+
+ /* we may be scanning tape on an SX drive */
+ HandleSXStartScanTapeConcerns( channel ) ;
+
+ /* Do the continuation read */
+ if( !RD_ContinuationTape( channel, channel->cur_buff ) ) {
+ SetPosBit( channel->cur_drv, REW_CLOSE ) ;
+ ret_val = TFLE_TAPE_INCONSISTENCY ;
+ } else {
+
+ /* If we already have a buffer, and we haven't accounted for it
+ do so now */
+ if( SX_IsStatusSet( channel, SX_SCAN_ACTIVE ) &&
+ SX_IsOK( channel ) ) {
+
+ /* adjust the LBA for the continuation TpRead() call */
+ SX_AdjustLBANow( channel, BM_XferSize( channel->cur_buff ) ) ;
+ }
+
+ /* If needed, tell the drive the base block position we
+ are positioning from.
+ */
+ if( DriveAttributes( ( channel->cur_drv ) ) & TDI_REAL_BLK_POS ) {
+ TpSpecial( channel->cur_drv->drv_hdl, (INT16)SS_PHYS_BLOCK, FS_ViewPBAinVCB( &channel->cur_drv->cur_vcb ) ) ;
+ }
+
+ if( BM_ReadError( channel->cur_buff ) == GEN_NO_ERR ) {
+ FlushReads( channel ) ;
+ }
+ }
+ }
+ }
+
+ /* set the flag to false */
+ ClrChannelStatus( channel, CH_AT_EOM ) ;
+
+ channel->status &= ~(CH_SKIP_ALL_STREAMS|CH_SKIP_CURRENT_STREAM) ;
+ channel->status |= save_stats ;
+
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Name: FlushReads
+
+ Description: Flushs the remaining allowed buffers to tape.
+
+ Modified: 2/2/1990 16:54:33
+
+ Returns: Nada
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+static VOID _near FlushReads(
+ CHANNEL_PTR channel )
+{
+ BUF_PTR tmpBUF ;
+
+ /* Okie-dokie, let's fill in some of dem der buffers */
+ while ( !IsSetDone( channel ) ) {
+ if ( ( tmpBUF = BM_Get( &channel->buffer_list ) ) != NULL ) {
+ if ( !ReadRequest( channel, tmpBUF ) ) {
+ BM_Put( tmpBUF );
+ break;
+ }
+ } else {
+ break ;
+ }
+ }
+}
+
+
+/**/
+/**
+
+ Name: AbortRead
+
+ Description: Cleans up an early read termination.
+
+ Modified: 2/12/1990 17:0:8
+
+ Returns: Nothing.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+static VOID _near AbortRead(
+ CHANNEL_PTR channel,
+ INT16 ret_val )
+{
+ (VOID) ret_val ;
+
+ BE_Zprintf( DEBUG_TAPE_FORMAT, RES_ABORT_READ ) ;
+ CleanUpDriverQ( channel ) ;
+ if( ! ( IsPosBitSet( channel->cur_drv, AT_EOS ) ) ) {
+ SetPosBit( channel->cur_drv, AT_MOS ) ;
+ }
+}
+
+/**/
+/**
+
+ Name: IsLBAInTheBuffers
+
+ Description: Determines whether or not the requested LBA is already in the
+ buffers that we have.
+
+ Modified: 6/13/1990 9:45:30
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+static BOOLEAN _near IsLBAInTheBuffers(
+ CHANNEL_PTR channel,
+ UINT32 lba,
+ INT16_PTR err_code )
+{
+ BOOLEAN ret_val = FALSE ;
+ BUF_PTR tmpBUF = channel->cur_buff ;
+
+ /* Is the requested block within the already enq'd read buffers ? */
+ if( lba < channel->running_lba ) {
+
+ /* While away the until we find the right buffer */
+ while( lba > ( BM_BeginningLBA( tmpBUF ) +
+ ( ( BM_BytesFree( tmpBUF ) +
+ BM_NextByteOffset( tmpBUF ) ) /
+ channel->lb_size ) ) ) {
+
+ if( ( *err_code = AcquireReadBuffer( channel, TRUE ) ) != TFLE_NO_ERR ) {
+ if ( !IsTFLE( *err_code ) ) {
+ *err_code = TFLE_NO_ERR ;
+ }
+ return( ret_val ) ; /* this includes EXCeptions. */
+ }
+ tmpBUF = channel->cur_buff ;
+ }
+
+ /* Now adjust the pointer to point to the requested LBA */
+ BM_UpdCnts( tmpBUF, (UINT16)( channel->lb_size -
+ ( BM_NextByteOffset( tmpBUF ) %
+ channel->lb_size ) ) ) ;
+ lba -= (UINT32)( BM_NextByteOffset( tmpBUF ) / channel->lb_size ) ;
+ BM_UpdCnts( tmpBUF, (UINT16)( ( lba - BM_BeginningLBA( tmpBUF ) ) *
+ channel->lb_size ) ) ;
+ ret_val = TRUE ;
+ }
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Name: CleanUpDriverQ
+
+ Description: Cleans Up any pending requests on the driver queue.
+
+ Modified: 6/14/1990 12:5:13
+
+ Returns:
+
+ Notes: Punts current buffer, also.
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+static VOID _near CleanUpDriverQ( CHANNEL_PTR channel )
+{
+ BUF_PTR tmpBUF ;
+ RET_BUF myret ;
+ BOOLEAN done = FALSE ;
+ DRIVE_PTR curDRV = channel->cur_drv ;
+ UINT16 exception_type ; /* translator's exception_typeretation of exception (ignored) */
+ Q_ELEM_PTR qe_ptr ;
+
+ if ( channel->cur_buff != NULL ) {
+ if ( BM_ReadError( channel->cur_buff ) != GEN_NO_ERR ) {
+ done = TRUE ;
+ if( channel->cur_fmt != UNKNOWN_FORMAT ) {
+ RD_Exception( channel, BM_ReadError( channel->cur_buff ), &exception_type ) ;
+ if ( exception_type == FMT_EXC_EOS ) {
+ SetChannelStatus( channel, CH_DONE ) ;
+ }
+ } else {
+ PuntBuffer( channel ) ;
+ }
+ } else {
+ PuntBuffer( channel ) ;
+ }
+ }
+
+ while ( !done && curDRV->inproc_q.q_count > 0 ) {
+ while( TpReceive( curDRV->drv_hdl, &myret ) == FAILURE )
+ ThreadSwitch() ; /* for non-preemptive operating systems */
+
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( channel->cur_drv->thw_inf.the, myret.the ) ;
+
+ if( myret.call_type == GEN_SPECIAL ) {
+ if( !myret.gen_error ) {
+ /* write the positioning information sample to the SX file */
+ SX_WriteTmpFile( channel ) ;
+ }
+ } else {
+ tmpBUF = QueuePtr( DeQueueElem( &curDRV->inproc_q ) ) ;
+ msassert( tmpBUF != NULL ) ;
+ BM_SetBytesFree( tmpBUF, (UINT16)myret.len_got ) ;
+ BM_SetReadError( tmpBUF, myret.gen_error ) ;
+ channel->cur_buff = tmpBUF ;
+
+ if( myret.gen_error ) {
+ done = TRUE ;
+ curDRV->thw_inf.drv_status = myret.status ;
+ if( channel->cur_fmt != UNKNOWN_FORMAT ) {
+ RD_Exception( channel, myret.gen_error, &exception_type ) ;
+ if ( exception_type == FMT_EXC_EOS ) {
+ SetChannelStatus( channel, CH_DONE ) ;
+ }
+ } else {
+ PuntBuffer( channel ) ;
+ }
+ } else {
+ PuntBuffer( channel ) ;
+ }
+ }
+ }
+
+ msassert( channel->cur_buff == NULL ) ; /* we must not have ignored the exception. */
+
+ /* Clean up the channel in-process queue */
+ while ( ( qe_ptr = DeQueueElem( &channel->cur_drv->inproc_q ) ) != NULL ) {
+ tmpBUF = QueuePtr( qe_ptr );
+ channel->cur_buff = tmpBUF ;
+ PuntBuffer( channel ) ;
+ }
+}
+
+
+/**/
+/**
+$name$
+HandleSXStartScanTapeConcerns
+
+$paths$
+functions\all
+module\read.c
+subsystem\TAPE FORMAT\read.c
+$0$
+
+ Name: HandleSXStartScanTapeConcerns
+
+ Description: Considers whether the SX positioning information should be gathered for this tape
+
+ Modified: 5/11/1991
+
+ Returns: VOID
+
+ Notes:
+
+ Declaration:
+
+$-2$
+**/
+
+static VOID _near HandleSXStartScanTapeConcerns( CHANNEL_PTR channel )
+{
+// DRIVE_PTR curDRV = channel->cur_drv ;
+
+ /* positioning information may need to be gathered if this is an EXABYTE 8200sx - MaynStream 2200+ drive */
+ if( SX_IsStatusSet( channel, SX_LIST_TAPE_IN_PROGRESS ) ) {
+
+ if( SX_IsStatusSet( channel, SX_VCB_CONFIRMED ) &&
+ SX_IsOK( channel ) ) {
+
+ /* open SX file for this physical tape */
+ if( SX_OpenFile( channel,
+ channel->tape_id,
+ channel->ts_num ) ) {
+
+ /* if some record of the set exists in the SX file THEN ... */
+ if( SX_SeekSetInFile( channel,
+ channel->bs_num,
+ (INT16)SX_CHECKING_FOR_SET ) ) {
+
+ /* indicate the operation is not necessary */
+ SX_SetStatus( channel, SX_SCAN_INOPERATIVE ) ;
+ }
+
+ /* just close the file */
+ SX_CloseFile( channel ) ;
+ }
+
+ /* if we are able and still willing to get positioning information ... */
+ if( ( !( SX_IsStatusSet( channel, SX_SCAN_INOPERATIVE ) ) ) &&
+ ( SX_IsOK( channel ) ) ) {
+
+ /* indicate the operation is needed */
+ SX_SetStatus( channel, SX_SCAN_ACTIVE ) ;
+
+ /* get the operation going */
+ SX_StartSampling( channel ) ;
+ }
+ } else {
+
+ /* indicate the operation is not able to happen */
+ SX_SetStatus( channel, SX_SCAN_INOPERATIVE ) ;
+ }
+ }
+}
+
diff --git a/private/utils/ntbackup/src/tfreten.c b/private/utils/ntbackup/src/tfreten.c
new file mode 100644
index 000000000..ec8662c42
--- /dev/null
+++ b/private/utils/ntbackup/src/tfreten.c
@@ -0,0 +1,299 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tfreten.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the function to retension the drives.
+
+
+ $Log: T:/LOGFILES/TFRETEN.C_V $
+
+ Rev 1.22 30 Mar 1993 16:15:32 GREGG
+Handle Unrecognized Media error (unformatted DC2000).
+
+ Rev 1.21 30 Jan 1993 11:51:30 DON
+Removed compiler warnings
+
+ Rev 1.20 21 Jan 1993 14:23:38 GREGG
+Changed '*' to '&' in bitwise compare (details, details).
+
+ Rev 1.19 19 Jan 1993 15:41:48 GREGG
+Fixed setting of channel status bits.
+
+ Rev 1.18 18 Jan 1993 14:09:44 GREGG
+Changes to allow format command passed to driver through TpErase.
+
+ Rev 1.17 11 Nov 1992 22:16:56 GREGG
+Changed call to EraseDrive (only security boolean needed).
+
+ Rev 1.16 19 Feb 1992 17:00:12 GREGG
+Put the buffer back after user abort.
+
+ Rev 1.15 08 Feb 1992 14:27:24 GREGG
+Changed check for lst_oper == -1 to check for boolean force_rewind, since
+this is what the lst_oper field in the drive structure had been reduced to.
+
+ Rev 1.14 04 Feb 1992 21:11:16 GREGG
+If no tape is in the drive, don't rewind, but still call posatset.
+
+ Rev 1.13 22 Jan 1992 15:19:12 GREGG
+Do our own drive list traversal beacuse NextDriveInChannel does too much.
+
+ Rev 1.12 15 Jan 1992 01:40:38 GREGG
+Added param to posatset calls indicating if only a VCB of the tape is required.
+
+ Rev 1.11 02 Jan 1992 14:54:04 NED
+Buffer Manager/UTF translator integration.
+
+ Rev 1.10 10 Dec 1991 17:15:32 GREGG
+Removed memset of channel structure to 0.
+
+ Rev 1.9 03 Dec 1991 11:51:14 GREGG
+SKATEBOARD - New Buff Mgr - Initial integration.
+
+ Rev 1.8 21 Nov 1991 17:50:38 GREGG
+Check flag indicating a need to rewind before calling PositionAtSet.
+
+ Rev 1.7 17 Oct 1991 01:30:48 GREGG
+BIGWHEEL - 8200sx - Initial integration.
+
+ Rev 1.6 14 Oct 1991 11:03:08 GREGG
+Assert if we are called with the tape already mounted.
+
+ Rev 1.5 07 Oct 1991 22:18:10 GREGG
+Make sure the fmt env pointers are maintained in only one place at any given time.
+
+ Rev 1.4 25 Sep 1991 20:41:14 GREGG
+Set channel->cur_buff to NULL after BM_Put.
+
+ Rev 1.3 23 Sep 1991 12:20:16 GREGG
+Changed do-while condition to !=.
+
+ Rev 1.2 17 Sep 1991 11:33:28 GREGG
+Re-wrote TF_RetensionChannel to fix several bugs, merge in TF_EraseChannel,
+and add ability to Tension tape without pre-read.
+
+ Rev 1.1 10 May 1991 16:08:18 GREGG
+Ned's new stuff
+
+ Rev 1.0 10 May 1991 10:12:00 GREGG
+Initial revision.
+
+**/
+/* begin include list */
+#include <memory.h>
+
+#include "stdtypes.h"
+#include "queues.h"
+
+#include "drive.h"
+#include "channel.h"
+#include "lw_data.h"
+#include "tfl_err.h"
+#include "lwdefs.h"
+#include "tflopen.h"
+#include "lwprotos.h"
+#include "tflproto.h"
+#include "tfldefs.h"
+#include "translat.h"
+#include "sx.h"
+#include "fsys.h"
+
+#include "be_debug.h"
+
+/* Device Driver Interface Files */
+#include "generr.h"
+#include "genstat.h"
+#include "dil.h"
+
+/* $end$ include list */
+
+
+/**/
+/**
+
+ Name: TF_RetensionChannel
+
+ Description: Retensions or Erases all devices in the current channel,
+ based on the mode sent to it.
+
+ Modified: 9/27/1989 13:18:28
+
+ Returns: An error code.
+
+ Notes: The mode is actually a bit field which tells if the oper
+ is retension or which type of erase, and also indicates
+ whether or not we should call PositionAtSet first to read
+ the tape, and confirm the operation.
+
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+INT16 TF_RetensionChannel(
+ TFL_OPBLK_PTR open_blk,
+ UINT16 mode )
+{
+
+ CHANNEL_PTR channel ;
+ UINT16 i, j ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ Q_ELEM_PTR nxt_elem ;
+ BOOLEAN is_tape_present, security ;
+
+ /* Find a free Channel Entry */
+ for( i = 0 ; i < lw_tfl_control.no_channels ; i++ ) {
+ if( !InUse( &lw_channels[i] ) ) {
+ open_blk->channel = i ;
+ channel = &lw_channels[i] ;
+ /* Find the Starting drive for this channel */
+ for( j = 0 ; j < (UINT16)lw_drive_list.q_count ; j++ ) {
+ if( lw_drives[j].thw_inf.link.q_element == open_blk->sdrv->link.q_element ) {
+ channel->cur_drv = &lw_drives[j] ;
+ }
+ }
+ break ;
+ } else {
+ ret_val = TFLE_NO_FREE_CHANNELS ;
+ }
+ }
+
+ if( !ret_val ) {
+ /* Set up channel stuff */
+ channel->ui_tpos = open_blk->tape_position ;
+ channel->cur_fsys = open_blk->fsh ;
+ channel->mode = TF_DESTROY_OPERATION ;
+ channel->status = CH_IN_USE ; /* clear all other channel status bits */
+
+ /* Loop through all the drives in the list */
+ do {
+ if( channel->cur_drv->tape_mounted ) {
+ msassert( FALSE ) ;
+ ret_val = TFLE_PROGRAMMER_ERROR1 ;
+ } else {
+ ret_val = MountTape( channel->cur_drv, open_blk->tape_position, &is_tape_present ) ;
+ }
+ if( ret_val == TF_UNRECOGNIZED_MEDIA ) {
+ if( mode & TF_FMT ) {
+ mode |= TF_NO_RD ;
+ ret_val = TFLE_NO_ERR ;
+ } else {
+ ret_val = TFLE_UNRECOGNIZED_MEDIA ;
+ }
+ }
+ if( ret_val == TFLE_NO_ERR ) {
+ if( !( mode & TF_NO_RD ) ) {
+ if ( channel->cur_drv->last_fmt_env != NULL ) {
+ channel->cur_fmt = channel->cur_drv->last_cur_fmt ;
+ channel->fmt_env = channel->cur_drv->last_fmt_env ;
+ channel->cur_drv->last_cur_fmt = UNKNOWN_FORMAT ;
+ channel->cur_drv->last_fmt_env = NULL ;
+ }
+ if( channel->cur_drv->hold_buff != NULL ) {
+ BE_Zprintf( DEBUG_TAPE_FORMAT, RES_HOLD_BUFFER ) ;
+ channel->cur_buff = channel->cur_drv->hold_buff ;
+ channel->cur_drv->hold_buff = NULL ;
+ BM_UnReserve( channel->cur_buff ) ;
+ }
+ if( ( channel->cur_drv->thw_inf.drv_status & ( TPS_NEW_TAPE | TPS_RESET ) )
+ || ( channel->cur_drv->force_rewind )
+ || ( open_blk->rewind_sdrv ) ) {
+
+ channel->cur_drv->force_rewind = FALSE ;
+ if( channel->cur_buff ) {
+ BM_Put( channel->cur_buff ) ;
+ channel->cur_buff = NULL ;
+ }
+ channel->cur_drv->vcb_valid = FALSE ;
+ FreeFormatEnv( &channel->cur_fmt, &channel->fmt_env ) ;
+ if( is_tape_present ) {
+ ret_val = RewindDrive( channel->cur_drv, channel->ui_tpos, TRUE, TRUE, channel->mode ) ;
+ }
+ SetPosBit( channel->cur_drv, AT_BOT ) ;
+ }
+ if( ret_val == TFLE_NO_ERR ) {
+ ret_val = PositionAtSet( channel, open_blk->tape_position, TRUE ) ;
+ }
+ }
+
+ if( ret_val == TFLE_NO_ERR ) {
+ if( channel->cur_buff ) {
+ BM_Put( channel->cur_buff ) ;
+ channel->cur_buff = NULL ;
+ }
+ channel->cur_drv->vcb_valid = FALSE ;
+ FreeFormatEnv( &channel->cur_fmt, &channel->fmt_env ) ;
+ if( mode & TF_FMT ) {
+ ret_val = EraseDrive( channel, TRUE, TRUE ) ;
+ } else if( mode & TF_RET ) {
+ ret_val = RetensionDrive( channel ) ;
+ } else {
+ security = (BOOLEAN)( ( mode & TF_S_ER ) &&
+ ( !( mode & TF_F_ER ) ) ) ;
+ ret_val = EraseDrive( channel, security, FALSE ) ;
+ if( ret_val == TFLE_NO_ERR ) {
+ /* In case there was EXABYTE SX - 2200+
+ positioning info in an SX file then
+ delete the SX file corresponding to the
+ physical tape in the drive which was
+ erased.
+ */
+ SX_DeleteFile( FS_ViewTapeIDInVCB( &channel->cur_drv->cur_vcb ),
+ FS_ViewTSNumInVCB( &channel->cur_drv->cur_vcb ) ) ;
+ }
+ }
+ } else if( ret_val == TFLE_USER_ABORT ) {
+
+ /* If the cur_buff has valid data, save it in hold_buff. */
+ if( channel->cur_buff != NULL &&
+ ( BM_BytesFree( channel->cur_buff ) != 0 ||
+ ( BM_ReadError( channel->cur_buff ) != GEN_NO_ERR &&
+ BM_ReadError( channel->cur_buff ) != GEN_ERR_NO_DATA ) ) ) {
+
+ BM_Reserve( channel->cur_buff ) ; /* mark as reserved */
+ channel->cur_drv->hold_buff = channel->cur_buff ;
+ channel->cur_buff = NULL ;
+ } else if( channel->cur_buff != NULL ) {
+ BM_Put( channel->cur_buff ) ;
+ channel->cur_buff = NULL ;
+ }
+
+ /* If the VCB's valid, save the currnt FormatEnv */
+ if( channel->cur_drv->vcb_valid ) {
+ channel->cur_drv->last_cur_fmt = channel->cur_fmt ;
+ channel->cur_drv->last_fmt_env = channel->fmt_env ;
+ channel->cur_fmt = UNKNOWN_FORMAT ;
+ channel->fmt_env = NULL ;
+ } else if( channel->fmt_env != NULL ) {
+ FreeFormatEnv( &channel->cur_fmt, &channel->fmt_env ) ;
+ }
+ }
+ }
+ if( ret_val == TFLE_NO_ERR ) {
+ ret_val = DisMountTape( channel->cur_drv, NULL, FALSE ) ;
+ } else {
+ DisMountTape( channel->cur_drv, NULL, FALSE ) ;
+ }
+
+ /* NOTE: we don't call NextDriveInChannel here because it */
+ /* does more than we want (Mount, DisMount, Rewind, etc.) */
+ if( ret_val == TFLE_NO_ERR ) {
+ if( ( nxt_elem = QueueNext( ( Q_ELEM_PTR ) &channel->cur_drv->thw_inf.channel_link ) ) != NULL ) {
+ channel->cur_drv = ( DRIVE_PTR ) GetQueueElemPtr( nxt_elem ) ;
+ }
+ }
+
+ } while( ret_val == TFLE_NO_ERR && nxt_elem != NULL ) ;
+
+ ClrChannelStatus( channel, CH_IN_USE ) ;
+ }
+
+ return( ret_val ) ;
+}
+
diff --git a/private/utils/ntbackup/src/tfrewind.c b/private/utils/ntbackup/src/tfrewind.c
new file mode 100644
index 000000000..a97721f4f
--- /dev/null
+++ b/private/utils/ntbackup/src/tfrewind.c
@@ -0,0 +1,116 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-91
+
+
+ Name: tfrwind.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: Contains the function to rewind all the drives.
+
+
+ $Log: T:/LOGFILES/TFREWIND.C_V $
+
+ Rev 1.5 30 Mar 1993 16:15:40 GREGG
+Handle Unrecognized Media error (unformatted DC2000).
+
+ Rev 1.4 28 Feb 1992 15:42:50 NED
+added cast to shut compiler up
+
+ Rev 1.3 02 Jan 1992 14:54:24 NED
+Buffer Manager/UTF translator integration.
+
+ Rev 1.2 17 Sep 1991 10:28:34 GREGG
+Removed unneeded includes.
+
+ Rev 1.1 21 Aug 1991 14:51:24 GREGG
+Changed to immediate return from rewind.
+
+ Rev 1.0 05 Aug 1991 12:12:36 GREGG
+Initial revision.
+
+**/
+/* begin include list */
+#include "stdtypes.h"
+#include "queues.h"
+
+#include "drive.h"
+#include "channel.h"
+#include "lw_data.h"
+#include "tfl_err.h"
+#include "lwprotos.h"
+
+/* $end$ include list */
+
+
+/**/
+/**
+
+ Name: TF_RewindAllDrives
+
+ Description: Sets all drives with tape to rewinding, and returns.
+
+ Modified: 9/27/1989 13:18:28
+
+ Returns: A TFLE_xxx error code.
+
+ Notes: Will not rewind ANY drives if ANY of the channels are
+ currently in use.
+
+ Declaration:
+
+**/
+
+INT16 TF_RewindAllDrives( VOID )
+{
+
+ UINT16 i, j ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ BOOLEAN is_tape_present ;
+
+ if( ! lw_tfl_control.drives_active ) {
+ ret_val = TFLE_NO_DRIVES ;
+ }
+
+ if( ret_val == TFLE_NO_ERR ) {
+
+ /* Check for channels in use and report error if any are found. */
+ /* Otherwise mark them in use to avoid interruption. */
+ for( i = 0 ; i < lw_tfl_control.no_channels ; i++ ) {
+ if( InUse( &lw_channels[i] ) ) {
+ ret_val = TFLE_CHANNEL_IN_USE ;
+ for( j = 0 ; j < i ; j++ ) {
+ ClrChannelStatus( &lw_channels[j], CH_IN_USE ) ;
+ }
+ break ;
+ } else {
+ SetChannelStatus( &lw_channels[i], CH_IN_USE ) ;
+ }
+ }
+ }
+
+ if( ret_val == TFLE_NO_ERR ) {
+ /* Let's rewind them all */
+ for( i = 0 ; i < (UINT16)lw_drive_list.q_count && ret_val == TFLE_NO_ERR; i++ ) {
+
+ if( ( ret_val = MountTape( &lw_drives[i], NULL, &is_tape_present ) ) == TFLE_NO_ERR ) {
+ if( is_tape_present ) {
+ RewindDriveImmediate( &lw_drives[i] ) ;
+ }
+ ret_val = DisMountTape( &lw_drives[i], NULL, FALSE ) ;
+
+ } else if( ret_val == TF_UNRECOGNIZED_MEDIA ) {
+ /* Skip these, but don't bail out of the loop. */
+ ret_val = DisMountTape( &lw_drives[i], NULL, FALSE ) ;
+ }
+ }
+
+ /* Give them back their channels. */
+ for( i = 0 ; i < lw_tfl_control.no_channels ; i++ ) {
+ ClrChannelStatus( &lw_channels[i], CH_IN_USE ) ;
+ }
+ }
+
+ return( ret_val ) ;
+}
+
diff --git a/private/utils/ntbackup/src/tfstuff.c b/private/utils/ntbackup/src/tfstuff.c
new file mode 100644
index 000000000..a3ca63ec6
--- /dev/null
+++ b/private/utils/ntbackup/src/tfstuff.c
@@ -0,0 +1,290 @@
+/**
+Copyright(c) Conner Peripherals, Inc. 1993
+
+
+ Name: tfstuff.c
+
+ Description: This file contains functions formerly in tfgetnxt.c,
+ tfgtcfmt.c and tfgtcdev.c.
+
+ $Log: T:\logfiles\tfstuff.c_v $
+
+ Rev 1.3 17 Dec 1993 16:40:08 GREGG
+Extended error reporting.
+
+ Rev 1.2 30 Aug 1993 18:47:42 GREGG
+Modified the way we control hardware compression from software to work around
+a bug in Archive DAT DC firmware rev. 3.58 (we shipped a lot of them).
+Files Modified: lw_data.c, lw_data.h, tfstuff.c, mtf10wdb.c, mtf10wt.c and
+ drives.c
+
+ Rev 1.1 23 Jun 1993 11:11:32 GREGG
+Added cases I removed thinking they weren't needed in TF_GetNextTapeRequest.
+
+ Rev 1.0 22 Jun 1993 18:26:18 GREGG
+Combined tfgtcdev.c, tfgtcfmt.c and tfgetnxt.c, and added
+TF_SetHWCompression.
+
+**/
+
+#include <memory.h>
+#include "stdtypes.h"
+#include "queues.h"
+#include "drive.h"
+#include "channel.h"
+#include "lw_data.h"
+#include "tfl_err.h"
+#include "lwdefs.h"
+#include "tflopen.h"
+#include "lwprotos.h"
+#include "tflproto.h"
+#include "translat.h"
+#include "retbuf.h"
+#include "special.h"
+#include "dilhwd.h"
+#include "drvinf.h"
+#include "generr.h"
+#include "genfuncs.h"
+#include "dil.h"
+#include "be_debug.h"
+#include "dddefs.h"
+
+
+/**/
+/**
+
+ Name: TF_GetCurrentDevice
+
+ Description: Gets the current device for the specified channel.
+
+ Returns: A THW ptr to the current hardware device.
+
+ Notes:
+
+**/
+
+THW_PTR TF_GetCurrentDevice( UINT16 channel_no )
+{
+ CHANNEL_PTR channel = &lw_channels[channel_no] ;
+
+ return( &channel->cur_drv->thw_inf ) ;
+}
+
+
+/**/
+/**
+
+ Name: TF_GetTapeFormat
+
+ Description: Gets the current tape format desciptor for the specified.
+
+ Returns: An TFINF_PTR for the current format.
+
+ Notes:
+
+**/
+
+TFINF_PTR TF_GetTapeFormat( UINT16 channel_no )
+{
+ CHANNEL_PTR channel = &lw_channels[channel_no] ;
+
+ return (channel->cur_fmt != UNKNOWN_FORMAT) ? ( &lw_fmtdescr[channel->cur_fmt] ) : NULL ;
+}
+
+
+/**/
+/**
+
+ Name: TF_TapeFormatInfo
+
+ Description: Returns a pointer to the array of format descriptions.
+
+ Returns: A pointer to the first element, and the number of formats.
+
+ Notes:
+
+**/
+
+TFINF_PTR TF_GetTapeFormatInfo( UINT16_PTR num_formats )
+{
+ if ( num_formats != NULL ) {
+ *num_formats = lw_num_supported_fmts ;
+ }
+
+ return( &lw_fmtdescr[0] ) ;
+}
+
+
+/**/
+/**
+ Name: TF_GetTapeFormatID
+
+ Description: Gets the current tape format ID for the specified channel.
+
+ Returns: TFGT_UNKNOWN_FORMAT if we don't know, else an ID.
+
+ Notes:
+
+**/
+
+UINT16 TF_GetTapeFormatID( UINT16 channel_no )
+{
+ CHANNEL_PTR channel = &lw_channels[channel_no] ;
+
+ return (channel->cur_fmt != UNKNOWN_FORMAT)
+ ? ( lw_fmtdescr[channel->cur_fmt].format_id )
+ : TFGT_UNKNOWN_FORMAT ;
+}
+
+
+/**/
+/**
+ Name: TF_GetTapeFormatFromID
+
+ Description: Gets the current tape format desciptor for the specified.
+
+ Returns: A TFINF_PTR for the specified format, or NULL.
+
+ Notes:
+
+**/
+
+TFINF_PTR TF_GetTapeFormatFromID( UINT16 format_id )
+{
+ UINT16 format_index = FormatIndexFromID( format_id ) ;
+
+ return ( format_index == UNKNOWN_FORMAT ) ? NULL : lw_fmtdescr + format_index ;
+}
+
+
+/**/
+/**
+
+ Name: TF_GetNextTapeRequest
+
+ Description: Dispatches the loops IO request to the appropriate
+ handler.
+
+ Returns: A TFLE_xxx error code
+
+ Notes:
+
+**/
+
+INT16 TF_GetNextTapeRequest( RR_PTR req )
+{
+
+ INT16 ret_val = TFLE_NO_ERR ;
+ CHANNEL_PTR channel = &lw_channels[req->channel] ;
+
+ if( FatalError( channel ) ) {
+ /* A fatal error has occurred. If they are calling us with any
+ message other than an ABORT, fail the call. */
+ if( req->lp_message != LRR_ABORT || req->lp_message != LRW_ABORT ) {
+ BE_Zprintf( DEBUG_TAPE_FORMAT, RES_TF_GETNEXT_TAPE_REQUEST ) ;
+ return( TFLE_NO_ERR ) ; /* can't happen... */
+ } else {
+ return( TFLE_NO_ERR ) ;
+ }
+ }
+
+ switch( channel->mode ) {
+
+ case TF_WRITE_CONTINUE:
+ case TF_WRITE_OPERATION:
+ ret_val = DoWrite( channel, req ) ;
+ break ;
+
+ case TF_READ_CONTINUE:
+ case TF_READ_OPERATION:
+ case TF_SCAN_CONTINUE:
+ case TF_SCAN_OPERATION:
+ /* Set up the correct filter */
+ channel->loop_filter = req->filter_to_use ;
+ ret_val = DoRead( channel, req ) ;
+ break ;
+
+ default:
+ msassert( FALSE ) ;
+ break ;
+ }
+
+ if( ret_val ) {
+ BE_Zprintf( DEBUG_TAPE_FORMAT, RES_TF_GETNEXT_ERROR, ret_val ) ;
+ if ( ret_val != TFLE_USER_ABORT && ret_val != TFLE_UNEXPECTED_EOS ) {
+ SetChannelStatus( channel, CH_FATAL_ERR ) ;
+ }
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Name: TF_SetHWCompression
+
+ Description: This function used to make a TpSpecial Call to enable/
+ disable hardware compression. Due to a firmware bug in
+ early Archive DAT DC drives, we have to keep the drive
+ in uncompressed mode until we actually start a compressed
+ backup, and set it back to uncompressed mode as soon as
+ we're done. So we just set a tape format layer wide
+ global to indicate if the set is to be compressed. This
+ is yet another violation of the multiple channel concept,
+ and will have to be addressed in a different manner if
+ we ever decide to allow multiple channels.
+
+ Returns: A TFLE_xxx error code
+
+ Notes:
+
+**/
+
+INT16 TF_SetHWCompression( THW_PTR thw, BOOLEAN enable )
+{
+ (void)thw ;
+
+ lw_hw_comp = enable ;
+ return( TFLE_NO_ERR ) ;
+}
+
+
+/**/
+/**
+
+ Name: TF_GetLastDriveError
+
+ Description: This function calls the dil layer to get the function
+ id, gen_error and contents of the misc field of the
+ last function to report an error.
+
+ Returns: FALSE if there hasn't been an error since the last
+ time the function was called, or from the app start.
+ TRUE otherwise.
+
+ Notes:
+
+**/
+
+BOOLEAN TF_GetLastDriveError(
+ THW_PTR thw,
+ INT16_PTR gen_func,
+ INT16_PTR gen_err,
+ INT32_PTR gen_misc )
+{
+ RET_BUF myret ;
+
+ if( TpSpecial( ((DRIVE_PTR)thw)->drv_hdl, SS_GET_LAST_ERROR,
+ (UINT32)&myret ) == SUCCESS ) {
+
+ *gen_func = myret.call_type ;
+ *gen_err = myret.gen_error ;
+ *gen_misc = myret.misc ;
+ return( TRUE ) ;
+ }
+
+ return( FALSE ) ;
+}
+
diff --git a/private/utils/ntbackup/src/tftpcat.c b/private/utils/ntbackup/src/tftpcat.c
new file mode 100644
index 000000000..b62ab8172
--- /dev/null
+++ b/private/utils/ntbackup/src/tftpcat.c
@@ -0,0 +1,737 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-92
+
+
+ Name: tftpcat.c
+
+ Description: Tape format API's for accessing Tape Catalogs.
+
+ $Log: T:\logfiles\tftpcat.c_v $
+
+ Rev 1.10.1.1 28 Jan 1994 11:29:42 GREGG
+Don't tell dismount to rewind if we just ejected the tape (duh)!
+
+ Rev 1.10.1.0 21 Nov 1993 23:35:10 GREGG
+Added eject on conditions where we know we need a different tape.
+
+ Rev 1.10 15 Jul 1993 11:54:08 GREGG
+Convert TF_NO_MORE_DATA to TF_EMPTY_TAPE in GetTape.
+
+ Rev 1.9 23 Jun 1993 09:03:44 DON
+Added include of 'malloc.h' to get prototypes for calloc and free.
+Also, changed use of '<>' around our internal headers. These should only
+be used for 3rd party headers.
+
+ Rev 1.8 22 Jun 1993 10:53:10 GREGG
+Added API to change the catalog directory path.
+
+ Rev 1.7 10 Jun 1993 20:24:26 GREGG
+Initialize the channel number in the tpos structure in OpenChannel.
+
+ Rev 1.6 06 Jun 1993 21:07:22 GREGG
+Added abort flag parameter to TF_CloseSetMap and TF_CloseSetCat which they
+pass to CloseChannel. We're really lost if they abort a catalog operation,
+so we need to throw away the format environment, and force a
+reinitialization of the tape.
+
+ Rev 1.5 27 May 1993 12:01:06 GREGG
+Fix for EPR 294-0299 - Buffer was being transfered from drive hold to
+channel before calling MountTape. MountTape tries to access hold buffer
+when cleaning up after PollDrive.
+
+ Rev 1.4 06 Apr 1993 14:06:32 GREGG
+Return TFLE_UI_HAPPY_ABORT if user won't give us the tape we need.
+
+ Rev 1.3 01 Apr 1993 22:47:42 GREGG
+Handle Unrecognized Media error (unformatted DC2000).
+
+ Rev 1.2 26 Mar 1993 09:37:18 GREGG
+If OTC retrieval fails, set a flag to force a rewind before the next operation.
+
+ Rev 1.1 23 Nov 1992 09:57:54 GREGG
+Fixed GetTape handling of UI_END_POSITIONING.
+
+ Rev 1.0 09 Nov 1992 14:27:26 GREGG
+Initial revision.
+
+**/
+#include <string.h>
+#include <malloc.h>
+
+#include "stdtypes.h"
+#include "queues.h"
+#include "stdmath.h"
+
+#include "drive.h"
+#include "channel.h"
+#include "lw_data.h"
+#include "tfl_err.h"
+#include "lwprotos.h"
+#include "tfldefs.h"
+#include "translat.h"
+#include "tpos.h"
+#include "genstat.h"
+
+/* Device driver header source */
+#include "retbuf.h"
+#include "dilhwd.h"
+#include "drvinf.h"
+#include "generr.h"
+#include "genstat.h"
+#include "dil.h"
+#include "tdemo.h"
+
+static INT OpenChannel( THW_PTR thw, FSYS_HAND fsh, TPOS_PTR tpos ) ;
+static INT GetTape( CHANNEL_PTR channel, BOOLEAN get_best, INT msg_in ) ;
+static VOID CloseChannel( BOOLEAN abort ) ;
+
+/**/
+/**
+
+ Unit: Tape Format API's
+
+ Name: TF_OpenSetMap
+
+ Description: This function grabs the channel, insures that the
+ requested tape is in the drive, and calls the translator
+ to load the best Set Map from the tape. If 'get_best'
+ is set to TRUE, an attempt is made to get the last tape
+ in the given family, but if it can at least get the
+ originally requested tape, it will load a Set Map and
+ report success.
+
+ Returns: INT - TFLE_xxx error code. Also, 'complete' is set to
+ TRUE if this is the last Set Map in the family.
+
+ Notes: None.
+
+**/
+
+INT TF_OpenSetMap(
+ THW_PTR thw,
+ FSYS_HAND fsh,
+ TPOS_PTR tpos,
+ BOOLEAN_PTR complete,
+ BOOLEAN get_best )
+{
+ CHANNEL_PTR channel = &lw_channels[0] ;
+ BOOLEAN done = FALSE ;
+ INT ret_val = TFLE_NO_ERR ;
+ INT dm_ret = TFLE_NO_ERR ;
+
+ ret_val = OpenChannel( thw, fsh, tpos ) ;
+ if( ret_val == TFLE_NO_ERR || !IsTFLE( ret_val ) ) {
+ if( ( ret_val = GetTape( channel, get_best, ret_val ) ) == TF_END_POSITIONING ) {
+ ret_val = TFLE_UI_HAPPY_ABORT ;
+ }
+ }
+ if( ret_val == TFLE_NO_ERR ) {
+ while( !done ) {
+ ret_val = LoadSetMap( channel, complete, get_best ) ;
+ if( ret_val == TF_NEED_NEW_TAPE ) {
+ tpos->tape_seq_num++ ;
+ ret_val = GetTape( channel, get_best, TF_NEED_NEW_TAPE ) ;
+ if( ret_val == TF_END_POSITIONING ) {
+ ret_val = LoadSetMap( channel, complete, FALSE ) ;
+ done = TRUE ;
+ } else if( ret_val != TFLE_NO_ERR ) {
+ done = TRUE ;
+ }
+ } else {
+ done = TRUE ;
+ }
+ }
+ }
+ dm_ret = DisMountTape( channel->cur_drv, NULL, FALSE ) ;
+ if( ret_val == TFLE_NO_ERR ) {
+ ret_val = dm_ret ;
+ }
+ if( IsTFLE( ret_val ) ) {
+ SetChannelStatus( channel, CH_FATAL_ERR ) ;
+ }
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Tape Format API's
+
+ Name: TF_OpenSetCat
+
+ Description: This function grabs the channel, insures that the
+ requested tape is in the drive, and calls the translator
+ to load the requested Set Catalog from the tape.
+
+ Returns: INT - TFLE_xxx error code.
+
+ Notes: None.
+
+**/
+
+INT TF_OpenSetCat(
+ THW_PTR thw,
+ FSYS_HAND fsh,
+ TPOS_PTR tpos )
+{
+ CHANNEL_PTR channel = &lw_channels[0] ;
+ INT ret_val = TFLE_NO_ERR ;
+ INT dm_ret = TFLE_NO_ERR ;
+
+ ret_val = OpenChannel( thw, fsh, tpos ) ;
+ if( ret_val == TFLE_NO_ERR || !IsTFLE( ret_val ) ) {
+ ret_val = GetTape( channel, FALSE, ret_val ) ;
+ }
+ if( ret_val == TFLE_NO_ERR ) {
+ while( ( ret_val = LoadSetCat( channel ) ) == TF_NEED_NEW_TAPE ) {
+ tpos->tape_seq_num++ ;
+ if( ( ret_val = GetTape( channel, FALSE, TF_NEED_NEW_TAPE ) ) != TFLE_NO_ERR ) {
+ break ;
+ }
+ }
+ }
+ dm_ret = DisMountTape( channel->cur_drv, NULL, FALSE ) ;
+ if( !IsTFLE( ret_val ) && dm_ret != TFLE_NO_ERR ) {
+ ret_val = dm_ret ;
+ }
+ if( IsTFLE( ret_val ) ) {
+ SetChannelStatus( channel, CH_FATAL_ERR ) ;
+ }
+ if( ret_val == TF_END_POSITIONING ) {
+ ret_val = TFLE_UI_HAPPY_ABORT ;
+ }
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Tape Format API's
+
+ Name: TF_CloseSetMap
+
+ Description: This function calls CloseChannel to wrap things up after
+ TF_OpenSetMap has been called and all necessary calls to
+ TF_GetNextSMEntry have been made.
+
+ Returns: Nothing.
+
+ Notes: None.
+
+**/
+
+VOID TF_CloseSetMap( BOOLEAN abort )
+{
+ CloseChannel( abort ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Tape Format API's
+
+ Name: TF_CloseSetCat
+
+ Description: This function calls CloseChannel to wrap things up after
+ TF_OpenSetCat has been called and all necessary calls to
+ TF_GetNextSCEntry have been made.
+
+ Returns: Nothing.
+
+ Notes: None.
+
+**/
+
+VOID TF_CloseSetCat( BOOLEAN abort )
+{
+ CloseChannel( abort ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Tape Format API's
+
+ Name: TF_GetNextSMEntry
+
+ Description: This function calls the translator to translate the next
+ entry in the active Set Map into a VCB.
+
+ Returns: TFLE_xxx error code, TFLE_NO_ERR or TF_NO_MORE_ENTRIES.
+
+ Notes: None.
+
+**/
+
+INT TF_GetNextSMEntry(
+ FSYS_HAND fsh,
+ DBLK_PTR vcb )
+{
+ CHANNEL_PTR channel = &lw_channels[0] ;
+
+ if( !InUse( channel ) || channel->cur_buff == NULL ) {
+ msassert( FALSE ) ;
+ return( TFLE_PROGRAMMER_ERROR1 ) ;
+ }
+
+ channel->cur_fsys = fsh ;
+ channel->cur_dblk = vcb ;
+ return( GetNextSMEntry( channel ) ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Tape Format API's
+
+ Name: TF_GetNextSCEntry
+
+ Description: This function calls the translator to translate the next
+ entry in the active Set Catalog into a DBLK.
+
+ Returns: TFLE_xxx error code, TFLE_NO_ERR or TF_NO_MORE_ENTRIES.
+
+ Notes: None.
+
+**/
+
+INT TF_GetNextSCEntry(
+ FSYS_HAND fsh,
+ DBLK_PTR dblk )
+{
+ CHANNEL_PTR channel = &lw_channels[0] ;
+
+ if( !InUse( channel ) || channel->cur_buff == NULL ) {
+ msassert( FALSE ) ;
+ return( TFLE_PROGRAMMER_ERROR1 ) ;
+ }
+
+ channel->cur_fsys = fsh ;
+ channel->cur_dblk = dblk ;
+ return( GetNextSCEntry( channel ) ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Tape Format API's
+
+ Name: TF_ChangeCatPath
+
+ Description: This function calls the translator to delete any
+ existing temporary tape catalog files, and then changes
+ the layer wide catalog path string.
+
+ Returns: TFLE_xxx error code
+
+ Notes: It is not valid to call this function when we are in the
+ middle of an operation. This is checked by making sure
+ that if the channel is in use, the PollDrive state is
+ not closed.
+
+**/
+
+INT TF_ChangeCatPath( CHAR_PTR new_path )
+{
+ Q_ELEM_PTR qe_ptr ;
+ DRIVE_PTR cur_drv ;
+
+ if( ( InUse( &lw_channels[0] ) &&
+ lw_channels[0].cur_drv->poll_stuff.state == st_CLOSED ) ||
+ new_path == NULL ) {
+
+ msassert( FALSE ) ;
+ return( TFLE_PROGRAMMER_ERROR1 ) ;
+ }
+
+ for ( qe_ptr = QueueHead( &lw_drive_list ); qe_ptr != NULL; qe_ptr = QueueNext( qe_ptr ) ) {
+ cur_drv = (DRIVE_PTR)(VOID_PTR)qe_ptr ;
+ if ( cur_drv->last_fmt_env != NULL ) {
+ CloseTapeCatalogs( cur_drv->last_cur_fmt, cur_drv->last_fmt_env ) ;
+ }
+ }
+
+ if( lw_cat_file_path != NULL ) {
+ free( lw_cat_file_path ) ;
+ lw_cat_file_path = NULL ;
+ lw_cat_file_path_end = NULL ;
+ }
+
+ lw_cat_file_path = calloc( strlen( new_path ) + SX_FILE_NAME_LENGTH + 1, sizeof( CHAR ) ) ;
+ if ( lw_cat_file_path == NULL ) {
+ return TFLE_NO_MEMORY ;
+ }
+ strcpy( lw_cat_file_path, new_path ) ;
+ lw_cat_file_path_end = lw_cat_file_path + strlen( lw_cat_file_path ) ;
+
+ return( TFLE_NO_ERR ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Tape Format API's
+
+ Name: OpenChannel
+
+ Description: This function marks the channel in use, initializes the
+ channel fields, and mounts the tape in the given drive.
+
+ Returns: TFLE_xxx error code.
+
+ Notes: None.
+
+**/
+
+static INT OpenChannel(
+ THW_PTR thw,
+ FSYS_HAND fsh,
+ TPOS_PTR tpos )
+{
+ CHANNEL_PTR channel = &lw_channels[0] ;
+ INT ret_val = TFLE_NO_ERR ;
+ BOOLEAN is_tape_present ;
+ DRIVE_PTR curDRV ;
+
+ if( !InUse( channel ) ) {
+ SetChannelStatus( channel, CH_IN_USE ) ;
+ tpos->channel = 0 ;
+
+ /* hook the drive into the channel */
+ if( ( channel->cur_drv = (DRIVE_PTR)thw ) == NULL ) {
+ msassert( FALSE ) ;
+ ret_val = TFLE_NO_DRIVES ; /* Specified drive does not exist!!! */
+ } else {
+ curDRV = channel->cur_drv ;
+ }
+ } else {
+ msassert( FALSE ) ;
+ ret_val = TFLE_NO_FREE_CHANNELS ;
+ }
+
+ /* Mount that tape! */
+ if( ret_val == TFLE_NO_ERR ) {
+ if( curDRV->tape_mounted ) {
+ msassert( FALSE ) ;
+ ret_val = TFLE_PROGRAMMER_ERROR1 ;
+ } else {
+ ret_val = MountTape( curDRV, tpos, &is_tape_present ) ;
+ }
+ }
+
+ /* set up the channel stuff */
+ if( ret_val == TFLE_NO_ERR ) {
+ channel->ui_tpos = tpos ;
+ channel->cur_dblk = NULL ;
+ channel->cur_fsys = fsh ;
+ channel->eom_id = 0L ;
+ channel->hiwater = channel->buffs_enqd = 0 ;
+ channel->retranslate_size = U64_Init( 0xffffffffUL, 0xffffffffUL ) ;
+ channel->blocks_used = 0L ;
+ if ( curDRV->last_fmt_env != NULL ) {
+ channel->cur_fmt = curDRV->last_cur_fmt ;
+ channel->fmt_env = curDRV->last_fmt_env ;
+ curDRV->last_cur_fmt = UNKNOWN_FORMAT ;
+ curDRV->last_fmt_env = NULL ;
+ }
+ if( curDRV->hold_buff != NULL ) {
+ channel->cur_buff = curDRV->hold_buff ;
+ curDRV->hold_buff = NULL ;
+ BM_UnReserve( channel->cur_buff ) ;
+ } else {
+ if( ( channel->cur_buff =
+ BM_GetVCBBuff( &channel->buffer_list ) ) == NULL ) {
+
+ msassert( FALSE ) ;
+ ret_val = TFLE_PROGRAMMER_ERROR1 ;
+ }
+ }
+ }
+
+ if( ret_val == TFLE_NO_ERR ) {
+ if( ( curDRV->thw_inf.drv_status &
+ ( TPS_NEW_TAPE | TPS_RESET | TPS_NO_TAPE ) )
+ || curDRV->force_rewind ) {
+
+ curDRV->force_rewind = FALSE ;
+ FreeFormatEnv( &channel->cur_fmt, &channel->fmt_env ) ;
+ if( is_tape_present ) {
+ ret_val = RewindDrive( curDRV, tpos, TRUE, TRUE, 0 ) ;
+ }
+ }
+ }
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Tape Format API's
+
+ Name: GetTape
+
+ Description: This function is a watered down version of PositionAtSet
+ which identifies tapes and works with the UI position
+ message handler to get the right tape in the drive.
+
+ Returns: TFLE_xxx error code.
+
+ Notes: If 'msg_in' is not zero, we pass this message on to the
+ UI, and act on their response before we make any attempt
+ to identify the tape in the drive.
+
+ If get_best is true, we accept any tape with the right
+ family ID, and a sequence number which is greater than
+ or equal to the requested sequence number.
+
+**/
+
+static INT GetTape(
+ CHANNEL_PTR channel,
+ BOOLEAN get_best,
+ INT msg_in )
+{
+ BOOLEAN done = FALSE ;
+ BOOLEAN tape_rewound = FALSE ;
+ INT ret_val = TFLE_NO_ERR ;
+ INT tmp ;
+ UINT16 ui_msg = 0 ;
+ DRIVE_PTR curDRV = channel->cur_drv ;
+ BOOLEAN is_tape_present ;
+ TPOS_PTR tpos = channel->ui_tpos ;
+ RET_BUF myret ;
+
+ /* loop until we get the right tape */
+ while( !done ) {
+
+ /* if need_next is TRUE, we know we don't have the right tape */
+ if( msg_in != 0 ) {
+ ret_val = msg_in ;
+ msg_in = 0 ;
+
+ /* if the tape isn't mounted, we don't have a tape */
+ } else if( !curDRV->tape_mounted ) {
+ ret_val = TF_NO_TAPE_PRESENT ;
+
+ } else {
+ /* if we don't have a valid vcb, get one now */
+ if( !curDRV->vcb_valid ) {
+ if( ( ret_val = ReadNewTape( channel, tpos, TRUE ) )
+ == TFLE_NO_ERR ) {
+ ret_val = ReadThisSet( channel ) ;
+ }
+ }
+
+ if( ret_val == TFLE_NO_ERR ) {
+ /* do we have the right tape family? */
+ if( FS_ViewTapeIDInVCB( &curDRV->cur_vcb ) == (UINT32)tpos->tape_id ) {
+
+ /* if 'get_best' is true, we'll be going after the
+ best set map we can get, so if they give us a
+ tape in the family with a seq number greater
+ than the one requested, we will accept it.
+ */
+ if( get_best ) {
+ if( FS_ViewTSNumInVCB( &curDRV->cur_vcb )
+ < (UINT16)tpos->tape_seq_num ) {
+
+ ret_val = TF_WRONG_TAPE ;
+ }
+ } else {
+ if( FS_ViewTSNumInVCB( &curDRV->cur_vcb )
+ != (UINT16)tpos->tape_seq_num ) {
+
+ ret_val = TF_WRONG_TAPE ;
+ }
+ }
+
+ } else {
+ ret_val = TF_WRONG_TAPE ;
+ }
+ }
+ }
+
+ if( ret_val == TF_NO_MORE_DATA ) {
+ ret_val = TF_EMPTY_TAPE ;
+ }
+
+ if( ret_val == TF_NEED_NEW_TAPE || ret_val == TF_WRONG_TAPE ||
+ ret_val == TF_INVALID_VCB || ret_val == TF_EMPTY_TAPE ) {
+
+ tape_rewound = TRUE ;
+
+ tmp = RewindDrive( curDRV, tpos, TRUE, TRUE, 0 ) ;
+
+ if( tmp == TFLE_NO_ERR &&
+ ( curDRV->thw_inf.drv_info.drv_features & TDI_UNLOAD ) ) {
+
+ if( TpEject( curDRV->drv_hdl ) == FAILURE ) {
+ tmp = TFLE_DRIVER_FAILURE ;
+ } else {
+ while( TpReceive( curDRV->drv_hdl, &myret ) == FAILURE ) {
+ (*tpos->UI_TapePosRoutine)( TF_IDLE_NOBREAK, tpos, curDRV->vcb_valid, &curDRV->cur_vcb, 0 ) ;
+ }
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( thw->the, myret.the ) ;
+
+ if( myret.gen_error != GEN_NO_ERR ) {
+ curDRV->thw_inf.drv_status = myret.status ;
+ tmp = TFLE_DRIVE_FAILURE ;
+ }
+ }
+ }
+ if( tmp != TFLE_NO_ERR ) {
+ ret_val = tmp ;
+ }
+ }
+
+ if( ret_val != TFLE_NO_ERR && curDRV->tape_mounted ) {
+ if( ( tmp = DisMountTape( curDRV, tpos, (BOOLEAN)( !tape_rewound && ret_val != TF_UNRECOGNIZED_MEDIA ) ) ) != TFLE_NO_ERR ) {
+ if( !( IsTFLE( ret_val ) ) ) {
+ ret_val = tmp ;
+ }
+ ResetDrivePosition( channel->cur_drv ) ;
+ FreeFormatEnv( &channel->cur_fmt, &channel->fmt_env ) ;
+ }
+ }
+
+ tape_rewound = FALSE ;
+
+ if( IsTFLE( ret_val ) || ret_val == TFLE_NO_ERR ) {
+ done = TRUE ;
+ continue ;
+ }
+
+ ui_msg = (*tpos->UI_TapePosRoutine)( (UINT16)ret_val, tpos, FALSE,
+ &curDRV->cur_vcb, 0 ) ;
+
+ switch( ui_msg ) {
+
+ case UI_END_POSITIONING :
+ done = TRUE ;
+ ret_val = MountTape( curDRV, tpos, &is_tape_present ) ;
+ if( ret_val == TFLE_NO_ERR ) {
+
+ if( ( !is_tape_present ) ||
+ ( curDRV->thw_inf.drv_status &
+ ( TPS_NEW_TAPE|TPS_RESET|TPS_NO_TAPE ) ) ) {
+
+ ret_val = DisMountTape( curDRV, tpos, TRUE ) ;
+ if( ret_val == TFLE_NO_ERR ) {
+ ret_val = TFLE_UI_HAPPY_ABORT ;
+ }
+ } else {
+ if( ( ret_val = ReadNewTape( channel, tpos, TRUE ) )
+ == TFLE_NO_ERR ) {
+ ret_val = ReadThisSet( channel ) ;
+ }
+
+ if( ret_val == TFLE_NO_ERR ) {
+ ret_val = TF_END_POSITIONING ;
+ } else {
+ if( IsTFLE( ret_val ) ) {
+ DisMountTape( curDRV, tpos, TRUE ) ;
+ } else {
+ ret_val = DisMountTape( curDRV, tpos, TRUE ) ;
+ }
+ ResetDrivePosition( channel->cur_drv ) ;
+ FreeFormatEnv( &channel->cur_fmt, &channel->fmt_env ) ;
+ if( ret_val == TFLE_NO_ERR ) {
+ ret_val = TFLE_UI_HAPPY_ABORT ;
+ }
+ }
+ }
+ } else if( ret_val == TF_UNRECOGNIZED_MEDIA ) {
+ ret_val = DisMountTape( curDRV, tpos, FALSE ) ;
+ ResetDrivePosition( channel->cur_drv ) ;
+ FreeFormatEnv( &channel->cur_fmt, &channel->fmt_env ) ;
+ if( ret_val == TFLE_NO_ERR ) {
+ ret_val = TFLE_UI_HAPPY_ABORT ;
+ }
+ }
+ break ;
+
+ case UI_ABORT_POSITIONING :
+ case UI_HAPPY_ABORT :
+ ret_val = TFLE_UI_HAPPY_ABORT ;
+ done = TRUE ;
+ break ;
+
+ case UI_NEW_TAPE_INSERTED :
+ ret_val = MountTape( curDRV, tpos, &is_tape_present ) ;
+
+ if( ret_val == TF_UNRECOGNIZED_MEDIA ) {
+ /* This is cheating, but it gets the job done! */
+ msg_in = ret_val ;
+ break ;
+ }
+
+ if( ret_val != TFLE_NO_ERR ) {
+ done = TRUE ;
+ } else {
+ if( is_tape_present ) {
+ ret_val = RewindDrive( curDRV, tpos, TRUE, FALSE, 0 ) ;
+ if( ret_val != TFLE_NO_ERR ) {
+ done = TRUE ;
+ }
+ }
+ }
+ break ;
+
+ default :
+ msassert( FALSE ) ;
+ ret_val = TFLE_PROGRAMMER_ERROR1 ;
+ done = TRUE ;
+ break ;
+ }
+ }
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Unit: Tape Format API's
+
+ Name: CloseChannel
+
+ Description: This function puts back the channel buffer, saves off
+ the format environment for the next operation if it is
+ valid, or frees it otherwise, and clears all the channel
+ status bits, including the one indicating the channel is
+ in use.
+
+ Returns: Most of the time.
+
+ Notes: None
+
+**/
+
+static VOID CloseChannel( BOOLEAN abort )
+{
+ CHANNEL_PTR channel = &lw_channels[0] ;
+
+ BM_Put( channel->cur_buff ) ;
+ channel->cur_buff = NULL ;
+ if( FatalError( channel ) || abort ) {
+ FreeFormatEnv( &channel->cur_fmt, &channel->fmt_env ) ;
+ ResetDrivePosition( channel->cur_drv ) ;
+ channel->cur_drv->force_rewind = TRUE ;
+ } else {
+ channel->cur_drv->last_cur_fmt = channel->cur_fmt ;
+ channel->cur_drv->last_fmt_env = channel->fmt_env ;
+ channel->cur_fmt = UNKNOWN_FORMAT ;
+ channel->fmt_env = NULL ;
+ }
+ ClrChannelStatus( channel, 0xFFFF ) ;
+}
+
diff --git a/private/utils/ntbackup/src/tfwrite.c b/private/utils/ntbackup/src/tfwrite.c
new file mode 100644
index 000000000..9510adea1
--- /dev/null
+++ b/private/utils/ntbackup/src/tfwrite.c
@@ -0,0 +1,1487 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: write.c
+
+ Description: Contains the Support for the Write Loop.
+
+
+ $Log: T:\logfiles\tfwrite.c_v $
+
+ Rev 1.72 13 Jan 1994 17:16:56 GREGG
+Don't call set aborted if we are at the end of a stream.
+
+ Rev 1.71 11 Jan 1994 13:32:50 GREGG
+Changed asserts to mscasserts.
+
+ Rev 1.70 26 Oct 1993 19:47:50 GREGG
+Stop needlessly calling FS_GetActualSizeDBLK!!!
+
+ Rev 1.69 08 Sep 1993 18:24:48 GREGG
+Reset channel->cur_dblk to req-> cur_dblk after EOM processing to fix EOM
+edge condition: EOM reported on AquireWriteBuffer call from WriteDBLK.
+
+ Rev 1.68 17 Jul 1993 17:57:14 GREGG
+Changed write translator functions to return INT16 TFLE_xxx errors instead
+of BOOLEAN TRUE/FALSE. Files changed:
+ MTF10WDB.C 1.23, TRANSLAT.H 1.22, F40PROTO.H 1.30, FMTENG.H 1.23,
+ TRANSLAT.C 1.43, TFWRITE.C 1.68, MTF10WT.C 1.18
+
+ Rev 1.67 21 Jun 1993 18:04:54 GREGG
+Don't set new_stream_completed flag if EOM hit in the middle.
+
+ Rev 1.66 26 May 1993 14:38:14 DON
+Removed threadswitch from AcquireWriteBuffer, wasn't needed afterall
+
+ Rev 1.65 21 May 1993 10:25:16 GREGG
+Fixed problem with EOM during FinishWrite. We were not flushing queued up
+buffers to tape if we didn't have a final one to write. Also replaced some
+asserts with msasserts.
+
+ Rev 1.64 20 May 1993 20:17:58 DON
+Needed a threadswitch when acquiring write buffers
+
+ Rev 1.63 26 Apr 1993 11:45:44 GREGG
+Seventh in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Changed handling of EOM processing during non-OTC EOS processing.
+
+Matches CHANNEL.H 1.17, MAYN40RD.C 1.60, TFWRITE.C 1.63, MTF.H 1.5,
+ TFLUTILS.C 1.44, MTF10WDB.C 1.10, MTF10WT.C 1.9
+
+ Rev 1.62 17 Apr 1993 19:38:58 GREGG
+Don't put entries in the DBLK map for CFDBs.
+
+ Rev 1.61 14 Apr 1993 02:00:12 GREGG
+Fixes to deal with non-ffr tapes in ffr drives (i.e. EXB2200 in EXB5000).
+
+ Rev 1.60 07 Apr 1993 16:34:26 GREGG
+Stop ignoring returns from WT_EndSet and WT_EndTape (they have meaning now)!
+
+ Rev 1.59 13 Mar 1993 17:01:14 GREGG
+Fixed so that EndData and NewStream expect buff_used to be zero.
+
+ Rev 1.58 10 Mar 1993 09:29:22 DON
+Fixed two occurances of if ret_val = NEED_NEW_BUFFER
+
+ Rev 1.57 09 Mar 1993 18:14:32 GREGG
+Initial changes for new stream and EOM processing.
+
+ Rev 1.56 06 Feb 1993 11:03:14 DON
+Also defined out optimization pragmas for OS_NLM
+
+ Rev 1.55 05 Feb 1993 12:20:22 GREGG
+Defined out optimization pragmas for OS_WIN32.
+
+ Rev 1.54 28 Jan 1993 15:01:24 GREGG
+Fixed assert in WriteRequest to check the right buffer.
+
+ Rev 1.53 21 Jan 1993 15:53:10 GREGG
+Added parameter to call to TpGetPosition.
+
+ Rev 1.52 18 Jan 1993 16:37:40 BobR
+Added MOVE_ESA macro calls.
+
+ Rev 1.51 13 Jan 1993 20:57:48 GREGG
+Removed tabs, spaces at end of lines and unused header entries.
+
+ Rev 1.50 18 Dec 1992 17:09:08 HUNTER
+Update for variable stream.
+
+ Rev 1.49 02 Dec 1992 13:47:56 GREGG
+Copy lst_osvcb into req_rep vcb after call to EOM_Write in DoWrite.
+
+ Rev 1.48 25 Nov 1992 10:21:10 HUNTER
+EOM fix.
+
+ Rev 1.47 23 Nov 1992 11:53:26 HUNTER
+Fix for eom handling.
+
+ Rev 1.46 20 Nov 1992 16:12:18 HUNTER
+Another eom fix
+
+ Rev 1.45 20 Nov 1992 12:30:44 HUNTER
+Fix for EOM handling
+
+ Rev 1.44 12 Nov 1992 10:16:10 HUNTER
+Fixed bug in DoWrite() for not enough data space.
+
+ Rev 1.43 09 Nov 1992 09:59:20 GREGG
+Added msassert that stream size is zero when FinishWrite is called.
+
+ Rev 1.42 03 Nov 1992 09:25:02 HUNTER
+Various fixes for streams
+
+ Rev 1.40 22 Oct 1992 10:25:54 HUNTER
+Added code for stream support
+
+ Rev 1.39 25 Sep 1992 09:46:56 GREGG
+Don't get the VCB buffer before calling WT_ContinueSet.
+
+ Rev 1.38 22 Sep 1992 09:02:52 GREGG
+Initial changes to handle physical block sizes greater than 1K.
+
+ Rev 1.37 17 Aug 1992 08:42:16 GREGG
+Changes to deal with block sizeing scheme.
+
+ Rev 1.36 06 Aug 1992 12:05:46 BURT
+Added fix to update data blk size and set channel to DATA PHASE
+when processing a VBLK delayed request.
+
+
+ Rev 1.35 04 Aug 1992 18:15:22 GREGG
+Removed line accidently copied from Turtle revision for last set of changes.
+
+ Rev 1.34 04 Aug 1992 15:12:18 GREGG
+Burt's fixes for variable length block support.
+
+ Rev 1.33 27 Jul 1992 12:17:36 GREGG
+Fixed ifndef.
+
+ Rev 1.32 23 Jul 1992 10:11:46 GREGG
+Fixed warnings.
+
+ Rev 1.31 15 Jul 1992 12:19:14 GREGG
+Removed annoying debug printf.
+
+ Rev 1.30 04 Jun 1992 16:17:38 GREGG
+Fixed receive loop in FinishWrite.
+
+ Rev 1.29 21 May 1992 13:15:06 GREGG
+Added parameter in calls to RD_TranslateDBLK.
+
+ Rev 1.28 13 May 1992 12:00:54 STEVEN
+40 format changes
+
+ Rev 1.27 29 Apr 1992 13:03:44 GREGG
+ROLLER BLADES - Changes for new EOM handling.
+
+ Rev 1.26 13 Apr 1992 14:12:52 GREGG
+ROLLER BLADES - Same fix as 1.24 in FinishWrite:the other half of the equation!
+
+ Rev 1.25 05 Apr 1992 19:07:28 GREGG
+ROLLER BLADES - Removed call to WriteInit.
+
+ Rev 1.24 28 Mar 1992 18:35:42 GREGG
+ROLLER BLADES - OTC integration, and fix for EOM problem in AcquireWriteBuffer.
+
+ Rev 1.23 25 Mar 1992 18:00:08 GREGG
+ROLLER BLADES - Initial Integration. Includes support for 4.0 format, 64
+ bit file sizes and tape block sizes > the logical block size.
+
+ Rev 1.22 25 Mar 1992 14:56:22 NED
+Suppressed 0-length writes in FinishWrite
+
+ Rev 1.21 20 Mar 1992 17:59:50 NED
+added exception updating after TpReceive calls
+
+ Rev 1.20 27 Feb 1992 10:07:06 NED
+updated channel->eom_lba inside finish_write() and used channel->lst_tblk
+to suppress incorrect read translation of non-existent DDBs or FDBs
+
+ Rev 1.19 08 Feb 1992 14:23:06 GREGG
+Removed references to lst_oper in drive stucture (it no longer exits).
+
+ Rev 1.18 15 Jan 1992 01:39:46 GREGG
+Added param to posatset calls indicating if only a VCB of the tape is required.
+
+ Rev 1.17 13 Jan 1992 19:56:06 NED
+accounted for separate VCB buffer in AcquireWriteBuffer
+
+ Rev 1.16 08 Jan 1992 22:00:20 NED
+Changed BM_Get call to BM_GetVCBBuff in EOM_Setup
+
+ Rev 1.15 03 Jan 1992 11:19:48 NED
+Added DumpDebug call
+
+ Rev 1.14 02 Jan 1992 14:54:48 NED
+Buffer Manager/UTF translator integration.
+
+ Rev 1.13 10 Dec 1991 17:03:20 GREGG
+Doing a QueueNext twice in a row was causing unpredictable results.
+
+ Rev 1.12 03 Dec 1991 11:46:18 GREGG
+SKATEBOARD - New Buff Mgr - Initial integration.
+
+ Rev 1.11 18 Nov 1991 20:10:30 GREGG
+When a backup is aborted, instead of writing an indication string on tape,
+we tell WT_EndSet about it so he can set an indication bit in the BSDB.
+Also corrected a bug where DATA_END case in DoWrite wasn't reseting the
+channel's DATA_PHASE and VAR_DATA bits or returning TRW_DB.
+
+ Rev 1.10 07 Nov 1991 15:29:56 HUNTER
+VBLK - Variable Length Block.
+
+
+ Rev 1.9 17 Oct 1991 01:28:40 GREGG
+BIGWHEEL - 8200sx - Initial integration.
+
+ Rev 1.8 22 Aug 1991 16:35:38 NED
+Changed all references to internals of the buffer structure to macros.
+
+ Rev 1.7 16 Aug 1991 09:13:32 GREGG
+Moved preservation of current format during continuation into PositionAtSet.
+
+ Rev 1.6 14 Aug 1991 11:26:48 GREGG
+Fixes for EOS at EOM handling.
+
+ Rev 1.5 01 Aug 1991 15:01:44 GREGG
+Save the current format before calling PosAtSet to handle EOM tape changes.
+
+ Rev 1.4 25 Jul 1991 11:31:16 GREGG
+Added logic to report EOM back to loops in FinishWrite, and handle EOM_ACK
+returning to function which encountered EOM.
+
+ Rev 1.3 15 Jul 1991 15:02:34 NED
+Added logic to set CH_CONTINUING channel status at apropriate times.
+
+ Rev 1.2 20 Jun 1991 14:41:40 GREGG
+Removed unnecessary call to SetupFormatEnv in StartWrite and added set of the
+REW_CLOSE position bit on a translation failure error.
+
+ Rev 1.1 10 May 1991 16:09:40 GREGG
+Ned's new stuff
+
+ Rev 1.0 10 May 1991 10:12:08 GREGG
+Initial revision.
+
+**/
+/* begin include list */
+#include <memory.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "queues.h"
+
+#include "drive.h"
+#include "channel.h"
+#include "lw_data.h"
+#include "tfl_err.h"
+#include "lwdefs.h"
+#include "tflopen.h"
+#include "lwprotos.h"
+#include "tflproto.h"
+#include "translat.h"
+
+/* Device Driver Interface Files */
+#include "retbuf.h"
+#include "special.h"
+#include "dilhwd.h"
+#include "drvinf.h"
+#include "generr.h"
+#include "genfuncs.h"
+#include "dil.h"
+#include "sx.h"
+
+#include "be_debug.h"
+
+/* $end$ include list */
+
+/* Pragmas */
+#if !defined( OS_WIN32 ) && !defined( OS_NLM )
+ #pragma loop_opt( on )
+ #pragma intrinsic( memcpy )
+#endif
+
+/* Static Functions */
+static INT16 _near StartWrite( CHANNEL_PTR );
+static INT16 _near WriteDBLK( CHANNEL_PTR, RR_PTR ) ;
+static INT16 _near AcquireWriteBuffer( CHANNEL_PTR, RR_PTR ) ;
+static INT16 _near EOM_Write( CHANNEL_PTR, BUF_PTR ) ;
+static VOID _near WriteRequest( CHANNEL_PTR, BUF_PTR, BOOLEAN ) ;
+static INT16 _near FinishWrite( CHANNEL_PTR, RR_PTR, BOOLEAN ) ;
+static VOID _near EOM_Setup( CHANNEL_PTR, RR_PTR ) ;
+static INT16 _near AbortWrite( CHANNEL_PTR, RR_PTR ) ;
+
+/**/
+/**
+
+ Name: StartWrite
+
+ Description: This function sets up the write function for a given
+ channel. This is called after an LRW_START message
+ is passed from the loops.
+
+ Returns:
+
+ Notes:
+
+ Declaration:
+
+**/
+
+static INT16 _near StartWrite( CHANNEL_PTR channel )
+{
+
+ INT16 ret_val = TFLE_NO_ERR ;
+ RET_BUF myret ;
+
+ /* We don't have a buffer, so lets get one */
+ if( channel->cur_buff == NULL ) {
+ if ( SnagBuffer( channel ) == NULL ) {
+ ret_val = TFLE_NO_FREE_BUFFERS ;
+ }
+ } else {
+ BM_InitBuf( channel->cur_buff ) ;
+ }
+
+ if( ret_val == TFLE_NO_ERR ) {
+ ClrChannelStatus( channel, CH_DATA_PHASE ) ;
+ channel->running_lba = 0L ;
+ channel->eom_lba = 0L ;
+ channel->buffs_enqd = 0 ;
+ ClrPosBit( channel->cur_drv, AT_BOT ) ;
+ channel->cur_drv->trans_started = FALSE ;
+ }
+
+ return( ret_val ) ;
+
+}
+
+
+/**/
+/**
+
+ Name: WriteDBLK
+
+ Description: Takes the current dblk and translates it to the output
+ format, and puts it in the write buffer.
+
+ Returns: An INT16 which is an error code.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+static INT16 _near WriteDBLK(
+ CHANNEL_PTR channel,
+ RR_PTR req )
+{
+ INT16 ret_val = TFLE_NO_ERR ;
+
+ /* Let's get some storage for the dblk */
+ if( BM_BytesFree( channel->cur_buff ) == 0 ) {
+ WriteRequest( channel, channel->cur_buff, FALSE ) ;
+ channel->cur_buff = NULL;
+ ret_val = AcquireWriteBuffer( channel, req ) ;
+ }
+
+ if( ret_val == TFLE_NO_ERR && !AtEOM( channel ) ) {
+ ret_val = GetDBLKMapStorage( channel, channel->cur_buff ) ;
+ }
+
+ /* We know everything is set to write, so let's do it */
+ if( ret_val == TFLE_NO_ERR && !AtEOM( channel ) ) {
+ channel->map_entry->blk_offset =
+ BM_NextByteOffset( channel->cur_buff ) ;
+ channel->map_entry->blk_data = lw_UINT64_ZERO ;
+ if( ( ret_val = WT_TranslateDBLK( channel, channel->cur_buff,
+ &channel->map_entry->blk_type ) )
+ == TFLE_NO_ERR ) {
+
+ /* If we've just translated the VCB, the id and sequence
+ number are known, and we can finnally consider whether
+ the SX file needs to be opened
+ */
+ if( channel->map_entry->blk_type == BT_VCB &&
+ channel->sx_info.cat_enabled &&
+ SX_IsOK( channel ) ) {
+
+ SX_StartSampling( channel ) ;
+ }
+
+ /* if this is a CFDB, we're going to ignore the entry */
+ if( channel->map_entry->blk_type != BT_CFDB ) {
+ BM_IncNoDblks( channel->cur_buff ) ;
+ }
+
+ } else {
+ SetPosBit( channel->cur_drv, REW_CLOSE ) ;
+ }
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Name: DoWrite
+
+ Description: called by TF_GetNextTapeRequest during write processing.
+
+ Returns: INT16, a TFLE_xxx code.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+INT16 DoWrite(
+ CHANNEL_PTR channel,
+ RR_PTR req )
+{
+ static INT16 prev_lp_message = 0 ;
+ static UINT16 prev_buff_used ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ BOOLEAN status ;
+ BOOLEAN new_stream_complete = FALSE ;
+
+ /* Set the current dblk pointer to the requests curDBLK */
+ channel->cur_dblk = req->cur_dblk ;
+
+ switch( req->lp_message ) {
+
+ case LRW_VCB:
+ /* It's a new set, increment the backup set num */
+ channel->bs_num++ ;
+ memcpy( channel->lst_osvcb, req->cur_dblk, sizeof( DBLK ) ) ;
+ SetChannelStatus( channel, CH_VCB_DBLK ) ;
+
+ /* fall through */
+
+ case LRW_FDB:
+ case LRW_DDB:
+ case LRW_IDB:
+ case LRW_CFDB:
+ prev_buff_used = 0 ;
+ ClrChannelStatus( channel, CH_DATA_PHASE ) ;
+ if( ( ret_val = WriteDBLK( channel, req ) ) == TFLE_NO_ERR ) {
+ if( !AtEOM( channel ) ) {
+ req->tf_message = TRW_DATA ;
+ }
+ }
+
+ break ;
+
+ case LRW_NEW_STREAM:
+
+ msassert( req->buff_used == 0 ) ;
+
+ /* If the last Stream was variable, finish it out */
+ if( channel->current_stream.tf_attrib & STREAM_VARIABLE ) {
+ WT_EndVarStream( channel, channel->cur_buff, prev_buff_used ) ;
+
+ /* If we were holding a buffer for the translator, it is now
+ safe to send it off to tape.
+ */
+ if( channel->hold_buff != NULL ) {
+ WriteRequest( channel, channel->hold_buff, FALSE ) ;
+ channel->hold_buff = NULL;
+ }
+ }
+ prev_buff_used = 0 ;
+
+ /* Copy Stream Stuff */
+ channel->current_stream = req->stream ;
+
+ SetChannelStatus( channel, CH_DATA_PHASE ) ;
+ req->buff_used = 0 ;
+
+ if( ( ret_val = WT_NewDataStream( channel, channel->cur_buff,
+ &channel->current_stream ) )
+ == NEED_NEW_BUFFER ) {
+
+ /* If channel->hold_buff is not NULL, the translator needs us
+ to hold on to the old buffer, otherwise we send it off to
+ tape.
+ */
+ if( channel->hold_buff == NULL ) {
+ WriteRequest( channel, channel->cur_buff, FALSE ) ;
+ }
+
+ channel->cur_buff = NULL ;
+ ret_val = AcquireWriteBuffer( channel, req ) ;
+ if( ret_val == TFLE_NO_ERR && !AtEOM( channel ) ) {
+ if( ( ret_val = WT_NewDataStream( channel,
+ channel->cur_buff,
+ &channel->current_stream ) )
+ == NEED_NEW_BUFFER ) {
+
+ msassert( FALSE ) ;
+ ret_val = TFLE_TRANSLATION_FAILURE ;
+ } else {
+ new_stream_complete = TRUE ;
+ }
+ }
+ } else {
+ new_stream_complete = TRUE ;
+ }
+
+ /* Fall Thru */
+
+ case LRW_DATA:
+
+ if( ret_val == TFLE_NO_ERR && !AtEOM( channel ) ) {
+ BM_UpdCnts( channel->cur_buff, req->buff_used ) ;
+
+ prev_buff_used = req->buff_used ;
+
+ channel->current_stream.size =
+ U64_Sub( channel->current_stream.size,
+ U32_To_U64( (UINT32)req->buff_used ),
+ &status ) ;
+
+ if( ( req->buff_ptr = GetDATAStorage( channel,
+ &req->buff_size ) ) == NULL ) {
+
+ /* If we were holding a buffer for the translator, it
+ is now safe to send it off to tape.
+ */
+ if( channel->hold_buff != NULL ) {
+ WriteRequest( channel, channel->hold_buff, FALSE ) ;
+ channel->hold_buff = NULL;
+ }
+
+ WriteRequest( channel, channel->cur_buff, FALSE ) ;
+ channel->cur_buff = NULL;
+ ret_val = AcquireWriteBuffer( channel, req ) ;
+ if( ret_val == TFLE_NO_ERR && !AtEOM( channel ) ) {
+ if( channel->current_stream.tf_attrib & STREAM_VARIABLE ) {
+ ret_val = WT_ContVarStream( channel, channel->cur_buff ) ;
+ }
+ if( ret_val == TFLE_NO_ERR ) {
+ req->buff_ptr = GetDATAStorage( channel, &req->buff_size ) ;
+ if( req->buff_ptr == NULL ) {
+ msassert( FALSE ) ;
+ ret_val = TFLE_NO_MEMORY ;
+ }
+ }
+ }
+ }
+ }
+ break ;
+
+
+ case LRW_DATA_END:
+
+ ClrChannelStatus( channel, CH_DATA_PHASE ) ;
+ msassert( req->buff_used == 0 ) ;
+
+ if( channel->current_stream.tf_attrib & STREAM_VARIABLE ) {
+ WT_EndVarStream( channel, channel->cur_buff, prev_buff_used ) ;
+
+ /* If we were holding a buffer for the translator, it is now
+ safe to send it off to tape.
+ */
+ if( channel->hold_buff != NULL ) {
+ WriteRequest( channel, channel->hold_buff, FALSE ) ;
+ channel->hold_buff = NULL;
+ }
+ }
+ prev_buff_used = 0 ;
+
+ if( ( ret_val = WT_EndData( channel, channel->cur_buff ) )
+ == NEED_NEW_BUFFER ) {
+
+ /* If channel->hold_buff is not NULL, the translator needs us
+ to hold on to the old buffer, otherwise we send it off to
+ tape.
+ */
+ if( channel->hold_buff == NULL ) {
+ WriteRequest( channel, channel->cur_buff, FALSE ) ;
+ }
+
+ channel->cur_buff = NULL ;
+ ret_val = AcquireWriteBuffer( channel, req ) ;
+ if( ret_val == TFLE_NO_ERR && !AtEOM( channel ) ) {
+ if( ( ret_val = WT_EndData( channel, channel->cur_buff ) )
+ != TFLE_NO_ERR ) {
+
+ if( ret_val == NEED_NEW_BUFFER ) {
+ msassert( FALSE ) ;
+ ret_val = TFLE_TRANSLATION_FAILURE ;
+ }
+ } else {
+ /* If we were holding a buffer for the translator,
+ it is now safe to send it off to tape.
+ */
+ if( channel->hold_buff != NULL ) {
+ WriteRequest( channel, channel->hold_buff, FALSE ) ;
+ channel->hold_buff = NULL;
+ }
+ }
+ }
+ }
+
+ req->tf_message = TRW_DB ;
+
+ break ;
+
+
+ case LRW_START:
+ if( ( ret_val = StartWrite( channel ) ) == TFLE_NO_ERR ) {
+ req->tf_message = TRW_DB ;
+ }
+ break ;
+
+
+ case LRW_EOM_ACK:
+
+ /* End of Volume Processing */
+ msassert( ( AtEOM( channel ) ) ) ;
+ msassert( channel->cur_buff == NULL ) ;
+
+ if( AtEOM( channel ) ) {
+ if( ( ret_val = EOM_Write( channel, channel->eom_buff ) ) == TFLE_NO_ERR ) {
+ *req->vcb_ptr = *( (DBLK_PTR)channel->lst_osvcb ) ;
+ channel->eom_buff = NULL ;
+ /* We're done EOM, lets start anew */
+ ClrChannelStatus( channel, CH_AT_EOM ) ;
+ channel->cur_dblk = req->cur_dblk ;
+
+ switch( prev_lp_message ) {
+
+ case LRW_ABORT:
+ case LRW_END:
+ /* We were in FinishWrite */
+ ClrChannelStatus( channel, CH_EOS_AT_EOM ) ;
+ ret_val = FinishWrite( channel, req, (BOOLEAN)(prev_lp_message == LRW_ABORT) ) ;
+ if( ret_val == TFLE_NO_ERR && !AtEOM( channel ) ) {
+ req->tf_message = TRW_DB ;
+ if( prev_lp_message == LRW_ABORT ) {
+ ret_val = TFLE_USER_ABORT ;
+ }
+ }
+ break ;
+
+ case LRW_VCB:
+ case LRW_FDB:
+ case LRW_DDB:
+ case LRW_IDB:
+ case LRW_CFDB:
+
+ if( ( ret_val = AcquireWriteBuffer( channel, req ) ) == TFLE_NO_ERR ) {
+ if( ( ret_val = WriteDBLK( channel, req ) ) == TFLE_NO_ERR ) {
+ req->tf_message = TRW_DATA ;
+ }
+ }
+ break ;
+
+
+ case LRW_NEW_STREAM:
+
+ if( ( ret_val = AcquireWriteBuffer( channel, req ) ) == TFLE_NO_ERR ) {
+ if( ( ret_val = WT_NewDataStream( channel,
+ channel->cur_buff,
+ &channel->current_stream ) )
+ == NEED_NEW_BUFFER ) {
+
+ msassert( FALSE ) ;
+ ret_val = TFLE_TRANSLATION_FAILURE ;
+ }
+ if( ret_val == TFLE_NO_ERR ) {
+ req->buff_ptr = GetDATAStorage( channel, &req->buff_size ) ;
+ msassert( req->buff_ptr != NULL ) ;
+ req->tf_message = TRW_DATA ;
+ }
+ }
+ break ;
+
+
+ case LRW_DATA:
+
+ if( ( ret_val = AcquireWriteBuffer( channel, req ) ) == TFLE_NO_ERR ) {
+ if( channel->current_stream.tf_attrib & STREAM_VARIABLE ) {
+ ret_val = WT_ContVarStream( channel, channel->cur_buff ) ;
+ }
+ if( ret_val == TFLE_NO_ERR ) {
+ req->buff_ptr = GetDATAStorage( channel, &req->buff_size ) ;
+ msassert( req->buff_ptr != NULL ) ;
+ req->tf_message = TRW_DATA ;
+ }
+ }
+ break ;
+
+
+ case LRW_DATA_END:
+
+ if( ( ret_val = AcquireWriteBuffer( channel, req ) ) == TFLE_NO_ERR ) {
+ if( ( ret_val = WT_EndData( channel, channel->cur_buff ) )
+ != TFLE_NO_ERR ) {
+
+ if( ret_val == NEED_NEW_BUFFER ) {
+ msassert( FALSE ) ;
+ ret_val = TFLE_TRANSLATION_FAILURE ;
+ }
+ } else {
+ /* If we were holding a buffer for the
+ translator, it is now safe to send it
+ off to tape.
+ */
+ if( channel->hold_buff != NULL ) {
+ WriteRequest( channel, channel->hold_buff, FALSE ) ;
+ channel->hold_buff = NULL;
+ }
+ req->tf_message = TRW_DB ;
+ }
+ }
+ break ;
+
+
+ case LRW_START:
+ case LRW_EOM_ACK:
+ case LRW_CATALOG:
+ default:
+ msassert( FALSE ) ;
+ ret_val = TFLE_PROGRAMMER_ERROR1 ;
+ break ;
+
+ }
+ }
+ }
+ break ;
+
+ case LRW_ABORT:
+ ret_val = AbortWrite( channel, req ) ;
+ if( !AtEOM( channel ) && ret_val == TFLE_NO_ERR ) {
+ ret_val = TFLE_USER_ABORT ;
+ }
+ break ;
+
+ case LRW_END:
+ ret_val = FinishWrite( channel, req, FALSE ) ;
+ break ;
+
+ case LRW_CATALOG:
+ break ;
+
+ }
+
+ /* An EOM Occurred Somewhere, so tell the Mud Pie */
+ if( AtEOM( channel ) && ret_val == TFLE_NO_ERR ) {
+ req->tf_message = TRW_EOM ;
+ req->buff_size = 0 ;
+
+ /* Setup EOM Pointers for the Loops */
+ *req->vcb_ptr = *( (DBLK_PTR)channel->lst_osvcb ) ;
+
+ switch( channel->lst_tblk ) {
+
+ case BT_FDB:
+ *req->fdb_ptr = *( (DBLK_PTR)channel->lst_osfdb ) ;
+
+ /* fall through */
+
+ case BT_DDB:
+ *req->ddb_ptr = *( (DBLK_PTR)channel->lst_osddb ) ;
+ break ;
+
+ case BT_IDB:
+ *req->idb_ptr = *( (DBLK_PTR)channel->lst_osfdb ) ;
+ break ;
+ }
+
+ }
+
+ if( ret_val != TFLE_NO_ERR ) {
+ req->tf_message = TRW_FATAL_ERR ;
+ req->error_locus = ret_val ;
+ }
+
+ if( req->lp_message != LRW_EOM_ACK ) {
+ if( req->lp_message == LRW_NEW_STREAM && new_stream_complete ) {
+ prev_lp_message = LRW_DATA ;
+ } else {
+ prev_lp_message = (INT16)req->lp_message ;
+ }
+ }
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Name: AcquireWriteBuffer
+
+ Description: This function attempts to get a new buffer for writing.
+ EOV processing is done from this function. Further, this
+ function switches drives in channel.
+
+ Returns: INT16, a TFLE_xxx code
+
+ Notes: IT IS ASSUMED THAT THE VALID POINTERS IN THE CHANNEL
+ LIST ARE NO LONGER VALID. THIS CAN BE ASSURED WITH A
+ CALL TO "WriteRequest()". IF YOU DON'T CALL "WriteRequest()"
+ BEFORE CALLING THIS FUNCTION, YOU WILL LOSE THE LAST FILLED
+ BUFFER.
+
+ Declaration:
+
+**/
+
+static INT16 _near AcquireWriteBuffer(
+ CHANNEL_PTR channel,
+ RR_PTR req_rep )
+{
+
+ INT16 drv_hdl = channel->cur_drv->drv_hdl, ret_val = TFLE_NO_FREE_BUFFERS ;
+ DRIVE_PTR curDRV = channel->cur_drv ;
+ BUF_PTR tmpBUF ;
+ RET_BUF myret ;
+
+ /* check to see if we can get any more buffers */
+ if ( BM_ListCount( &channel->buffer_list ) > QueueCount( &channel->cur_drv->inproc_q ) ) {
+ ret_val = TFLE_NO_ERR ;
+ }
+
+ /* Assume we can't get any buffers, and let's attempt to poll the
+ driver. */
+
+ do {
+
+ while( TpReceive( drv_hdl, &myret ) == SUCCESS ) {
+
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( channel->cur_drv->thw_inf.the, myret.the ) ;
+
+ /* check to see if this is a TpSpecial( ) call made for an EXABYTE 8200SX - MaynStream 2200+ */
+ if( myret.call_type == GEN_SPECIAL ) {
+ if( !myret.gen_error ) {
+ /* write the positioning information sample to the SX file */
+ SX_WriteTmpFile( channel ) ;
+ }
+ } else {
+
+ tmpBUF = QueuePtr( DeQueueElem( &curDRV->inproc_q ) );
+
+ /* This is here to deal with the the fact that
+ we have to write full logical blocks and
+ drives that write 512 blocks might stop in
+ the middle.
+ */
+ if( ( myret.gen_error == GEN_ERR_EOM ) &&
+ ( myret.len_got % (UINT32)channel->lb_size != 0UL ) ) {
+
+ UINT32 got = myret.len_got ;
+ UINT32 req = myret.len_req ;
+
+ BM_SetNextByteOffset( tmpBUF, (UINT16)myret.len_got ) ;
+ TpWrite( channel->cur_drv->drv_hdl,
+ BM_NextBytePtr( tmpBUF ),
+ (UINT32)channel->lb_size -
+ myret.len_got % (UINT32)channel->lb_size ) ;
+
+ while( TpReceive( channel->cur_drv->drv_hdl, &myret ) == FAILURE ) {
+ ThreadSwitch( ) ;
+ }
+
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( channel->cur_drv->thw_inf.the, myret.the ) ;
+
+ myret.len_got += got ;
+ myret.len_req = req ;
+ if( myret.gen_error == GEN_NO_ERR ) {
+ myret.gen_error = GEN_ERR_EOM ;
+ }
+ }
+
+ WT_ParseWrittenBuffer( channel, tmpBUF, (UINT16)myret.len_got ) ;
+
+ channel->eom_lba += (UINT32)( myret.len_got /
+ channel->lb_size ) ;
+
+ /* For correct statistics */
+ if( myret.gen_error ) {
+ BE_Zprintf( DEBUG_TAPE_FORMAT, RES_DEVICE_ERROR, myret.gen_error ) ;
+ DumpDebug( drv_hdl ) ;
+ curDRV->thw_inf.drv_status = myret.status ;
+ curDRV->cur_stats.underruns = myret.underruns ;
+ curDRV->cur_stats.dataerrs = myret.readerrs ;
+ }
+
+ switch( myret.gen_error ) {
+
+ case GEN_NO_ERR:
+ BM_Put( tmpBUF ) ;
+ ret_val = TFLE_NO_ERR ;
+ break ;
+
+ case GEN_ERR_EOM:
+ SetChannelStatus( channel, CH_AT_EOM ) ;
+ SetPosBit( curDRV, ( AT_EOM | TAPE_FULL ) ) ;
+ if( myret.len_req != myret.len_got ) {
+ BM_SetNextByteOffset( tmpBUF, (UINT16)myret.len_got ) ;
+ channel->eom_buff = tmpBUF ;
+ } else {
+ BM_Put( tmpBUF ) ;
+ channel->eom_buff = NULL ;
+ }
+
+ PuntBuffer( channel ) ;
+ /* First We Need to write the closing VCB */
+ EOM_Setup( channel, req_rep ) ;
+ ret_val = WT_EndTape( channel ) ;
+ break ;
+
+ case GEN_ERR_NO_MEDIA:
+ BM_Put( tmpBUF ) ;
+ ret_val = TFLE_NO_TAPE ;
+ break ;
+
+ default:
+ BM_Put( tmpBUF ) ;
+ ret_val = TFLE_DRIVE_FAILURE ;
+ break ;
+
+ }
+ }
+ }
+ } while( ret_val == TFLE_NO_FREE_BUFFERS ) ;
+
+ /* Okay Let's get a buffer */
+ if( ret_val == TFLE_NO_ERR && !AtEOM( channel ) ) {
+ if ( SnagBuffer( channel ) == NULL ) {
+ ret_val = TFLE_NO_MEMORY ;
+ }
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Name: EOM_Write
+
+ Description: Does the EOM write. It does the following:
+ 1) Switches drive to next drive in channel ( if there are any ).
+ 2) Writes the continuation VCB.
+ 3) Up the tape sequence number.
+ 4) Writes the appropriate continuation blocks.
+
+ Returns: INT16, a TFLE_xxx code
+
+ Notes: THE LST OS DBLK FIELDS MUST BE FILLED BEFORE CALLING THIS
+ ROUTINE.
+ ALSO, THE CLOSING VCB ON THE CURRENT EOM TAPE MUST ALREADY
+ BE WRITTEN.
+
+ Declaration:
+
+**/
+
+static INT16 _near EOM_Write(
+ CHANNEL_PTR channel, /* the current channel */
+ BUF_PTR lst_buff ) /* the last buffer put to tape */
+{
+ INT16 ret_val, i ;
+ DRIVE_PTR old_drv = channel->cur_drv ;
+ Q_HEADER tmp_q ;
+ Q_ELEM_PTR qe_ptr;
+ DBLKMAP_PTR tmp_map ;
+ UINT16 unwritten ;
+
+ if( !IsChannelStatus( channel, CH_EOS_AT_EOM ) ) {
+ InitQueue( &tmp_q ) ;
+ /* time to place an ending sample in the SX file */
+ if( SX_TmpFileIsOK( channel ) ) {
+ SX_EndSampling( channel ) ;
+ }
+ }
+
+ /* Ok, now lets switch to a new drive */
+ ret_val = NextDriveInChannel( channel, TRUE ) ;
+
+ if ( ret_val == TF_END_CHANNEL ) {
+ ret_val = ResetChannelList( channel, FALSE ) ;
+ }
+ if ( ret_val != TFLE_NO_ERR ) {
+ return( ret_val ) ;
+ }
+
+ /* Let's do some more positioning */
+ if( ( ret_val = PositionAtSet( channel, channel->ui_tpos, TRUE ) ) != TFLE_NO_ERR ) {
+ return( ret_val ) ;
+ }
+
+ if( !IsChannelStatus( channel, CH_EOS_AT_EOM ) ) {
+ /* Save the inproc queue and put them on the temp. queue */
+ MoveQueue( &old_drv->inproc_q, &tmp_q ) ;
+ }
+
+ /* Positioning was apparently successful, lets rewrite
+ the header information
+ */
+ channel->ts_num++ ;
+
+ /* we're about to process the continuation blocks so we need to
+ consider whether the SX file needs to be opened
+ */
+ if( SX_IsOK( channel ) ) {
+ SX_StartSampling( channel ) ;
+ }
+
+ if( (ret_val = WT_ContinueSet( channel ) ) != TFLE_NO_ERR ) {
+ return( ret_val ) ;
+ }
+
+ channel->cur_drv->cur_vcb = *( (DBLK_PTR)channel->lst_osvcb ) ;
+
+ /* Write the Remaining portion of the buffer, if one
+ was left over
+ */
+ if( lst_buff != NULL ) {
+ /* total amount - unused amount - amount we wrote */
+ unwritten = BM_XferSize( lst_buff ) - BM_BytesFree( lst_buff )
+ - BM_NextByteOffset( lst_buff ) ;
+
+ /* Adjust the offsets for the new position in the buffer */
+ i = (INT16)BM_NoDblks( lst_buff ) ;
+ while( i ) {
+ tmp_map = (DBLKMAP_PTR)BM_AuxBase( lst_buff ) + i - 1 ;
+ tmp_map->blk_offset -= BM_NextByteOffset( lst_buff ) ;
+ i-- ;
+ }
+ /* slide unwritten data down to start of buffer */
+ memmove( BM_XferBase( lst_buff ), BM_NextBytePtr( lst_buff ), unwritten ) ;
+ BM_SetNextByteOffset( lst_buff, unwritten ) ;
+ WriteRequest( channel, lst_buff, TRUE ) ;
+ }
+
+ if( !IsChannelStatus( channel, CH_EOS_AT_EOM ) ) {
+
+ while( ( qe_ptr = DeQueueElem( &tmp_q ) ) != NULL ) {
+ WriteRequest( channel, QueuePtr( qe_ptr ), FALSE ) ;
+ }
+ }
+ return( TFLE_NO_ERR ) ;
+}
+
+/**/
+/**
+
+ Name: WriteRequest
+
+ Description: Enqueues a request on the current drives in process queues
+ and if the number on the queue is equal to the hiwater mark,
+ starts pumping the data to tape.
+
+ Returns: Nothing
+
+ Notes: This function uses the "q_priority" field in the queue
+ element section of the buffer header to specify whether
+ the buffer has actually been given to the device driver.
+ If the field is set to '1' it has been written, and if
+ it has been set to '0' it has not.
+
+ Declaration:
+
+**/
+
+static VOID _near WriteRequest(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer,
+ BOOLEAN flush )
+{
+
+ INT16 drv_hdl = channel->cur_drv->drv_hdl ;
+ DRIVE_PTR curDRV = channel->cur_drv ;
+ BUF_PTR tmpBUF ;
+ Q_ELEM_PTR qe_ptr ;
+
+ BM_QElem( buffer ).q_priority = 0 ;
+ EnQueueElem( &curDRV->inproc_q, &BM_QElem( buffer ), FALSE ) ;
+ channel->buffs_enqd++ ;
+
+ if( curDRV->trans_started && TpSpecial( drv_hdl, (INT16)SS_IS_INQ_EMPTY, 0L ) ) {
+ curDRV->trans_started = FALSE ;
+ }
+
+ if( curDRV->trans_started ) {
+ /* Setting the priority to 1, says this has been written */
+ channel->buffs_enqd-- ;
+ BM_QElem( buffer ).q_priority = 1 ;
+ mscassert( BM_NextByteOffset( buffer ) % ChannelBlkSize( channel ) == 0 ) ;
+
+ /* check to see if it is time to sample the position for an EXABYTE 8200SX - MaynStream 2200+ */
+ if( SX_TmpFileIsOK( channel ) ) {
+ SX_SamplingProcessing( channel, ( UINT32 ) buffer->next_byte ) ;
+ }
+
+ TpWrite( drv_hdl, BM_XferBase( buffer ), (UINT32)BM_NextByteOffset( buffer ) ) ;
+ } else if( channel->buffs_enqd == channel->hiwater || flush ) {
+
+ for( qe_ptr = QueueHead( &curDRV->inproc_q ) ; qe_ptr != NULL ; qe_ptr = QueueNext( qe_ptr ) ) {
+ tmpBUF = QueuePtr( qe_ptr );
+ if ( qe_ptr->q_priority == 0 ) {
+ qe_ptr->q_priority = 1 ;
+ mscassert( BM_NextByteOffset( tmpBUF ) % ChannelBlkSize( channel ) == 0 ) ;
+
+ /* check to see if it is time to sample the position for an EXABYTE 8200SX - MaynStream 2200+ */
+ if( SX_TmpFileIsOK( channel ) ) {
+ SX_SamplingProcessing( channel, ( UINT32 ) tmpBUF->next_byte ) ;
+ }
+
+ TpWrite( drv_hdl, BM_XferBase( tmpBUF ), (UINT32)BM_NextByteOffset( tmpBUF ) ) ;
+ }
+ }
+ channel->buffs_enqd = 0 ;
+ curDRV->trans_started = TRUE ;
+ }
+}
+
+/**/
+/**
+
+ Name: FinishWrite
+
+ Description: This function is called when the Loops has specified the
+ end of a BackupSet.
+
+ Returns: INT16, a TFLE_xxx code
+
+ Notes: THERE SHOULD ONLY BE ONE BUFFER TO WRITE AND THAT SHOULD
+ "cur_buff".
+
+ Declaration:
+
+**/
+
+static INT16 _near FinishWrite(
+ CHANNEL_PTR channel,
+ RR_PTR req,
+ BOOLEAN abort )
+{
+ INT16 drv_hdl = channel->cur_drv->drv_hdl ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ DRIVE_PTR curDRV = channel->cur_drv ;
+ BUF_PTR tmpBUF ;
+ RET_BUF myret ;
+ BOOLEAN hit_eom = FALSE ;
+ BOOLEAN done = FALSE ; /* set upon receiving error */
+ Q_ELEM_PTR qe_ptr ;
+
+ /* # of buffers left should be <= 1 */
+
+ if( channel->cur_buff != NULL &&
+ BM_NextByteOffset( channel->cur_buff ) == 0 ) {
+
+ PuntBuffer( channel ) ;
+ }
+
+ if( channel->cur_buff != NULL ) {
+
+ /* The last buffer may only be partially full, and may not be
+ filled to an even physical block boundary (in the case where
+ the physical block size is greater than the logical block size).
+ If this is the case, we call the translator to lay down an "end
+ block" to pad out to the next physical block boundary.
+ */
+ if( BM_NextByteOffset( channel->cur_buff ) %
+ ChannelBlkSize( channel ) != 0 ) {
+ WT_EOSPadBlk( channel ) ;
+ }
+
+ WriteRequest( channel, channel->cur_buff, TRUE ) ;
+ channel->cur_buff = NULL ;
+
+ /* There may be buffers queued up attemting to reach the "high water
+ mark". We need to flush them now.
+ */
+ } else if( channel->buffs_enqd != 0 ) {
+
+ for( qe_ptr = QueueHead( &curDRV->inproc_q ) ; qe_ptr != NULL ; qe_ptr = QueueNext( qe_ptr ) ) {
+ tmpBUF = QueuePtr( qe_ptr );
+ if ( qe_ptr->q_priority == 0 ) {
+ qe_ptr->q_priority = 1 ;
+ mscassert( BM_NextByteOffset( tmpBUF ) % ChannelBlkSize( channel ) == 0 ) ;
+
+ /* check to see if it is time to sample the position for an EXABYTE 8200SX - MaynStream 2200+ */
+ if( SX_TmpFileIsOK( channel ) ) {
+ SX_SamplingProcessing( channel, ( UINT32 ) tmpBUF->next_byte ) ;
+ }
+
+ TpWrite( drv_hdl, BM_XferBase( tmpBUF ), (UINT32)BM_NextByteOffset( tmpBUF ) ) ;
+ }
+ }
+ channel->buffs_enqd = 0 ;
+ tmpBUF = NULL ;
+ }
+
+ /* Clear New */
+ while( !done ) {
+
+ while ( TpReceive( drv_hdl, &myret ) == FAILURE ) {
+ if ( TpSpecial( drv_hdl, (INT16)SS_IS_INQ_EMPTY, 0L ) == SUCCESS ) {
+ if ( TpReceive( drv_hdl, &myret ) == FAILURE ) {
+ done = TRUE ;
+ }
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( channel->cur_drv->thw_inf.the, myret.the ) ;
+
+ break ;
+ }
+ ThreadSwitch() ; /* for non-preemptive operating systems */
+ }
+
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( channel->cur_drv->thw_inf.the, myret.the ) ;
+
+ if ( done ) {
+ break ;
+ }
+
+ /* check to see if this is a TpSpecial( ) call made for an EXABYTE 8200SX - MaynStream 2200+ */
+ if( myret.call_type == GEN_SPECIAL ) {
+
+ if( !myret.gen_error ) {
+ /* write the positioning information sample to the SX file */
+ SX_WriteTmpFile( channel ) ;
+ }
+
+ } else if( myret.call_type == GEN_WRITE ) {
+
+ tmpBUF = QueuePtr( DeQueueElem( &channel->cur_drv->inproc_q ) ) ;
+ msassert( tmpBUF != NULL && myret.buffer == BM_XferBase( tmpBUF ) ) ;
+
+ /* This is here to deal with the the fact that
+ we have to write full logical blocks and
+ drives that write 512 blocks might stop in
+ the middle.
+ */
+ if( ( myret.gen_error == GEN_ERR_EOM ) &&
+ ( myret.len_got % (UINT32)channel->lb_size != 0UL ) ) {
+
+ UINT32 got = myret.len_got ;
+ UINT32 req = myret.len_req ;
+
+ BM_SetNextByteOffset( tmpBUF, (UINT16)myret.len_got ) ;
+ TpWrite( channel->cur_drv->drv_hdl,
+ BM_NextBytePtr( tmpBUF ),
+ (UINT32)channel->lb_size -
+ myret.len_got % (UINT32)channel->lb_size ) ;
+
+ while( TpReceive( channel->cur_drv->drv_hdl, &myret ) == FAILURE ) {
+ ThreadSwitch( ) ;
+ }
+
+ /* Move ESA info from RET_BUF to THW */
+ MOVE_ESA( channel->cur_drv->thw_inf.the, myret.the ) ;
+
+ myret.len_got += got ;
+ myret.len_req = req ;
+ if( myret.gen_error == GEN_NO_ERR ) {
+ myret.gen_error = GEN_ERR_EOM ;
+ }
+ }
+
+ WT_ParseWrittenBuffer( channel, tmpBUF, (UINT16)myret.len_got ) ;
+
+ channel->eom_lba += (UINT32)( myret.len_got / channel->lb_size ) ;
+
+ /* For correct statistics */
+ if( myret.gen_error ) {
+ BE_Zprintf( DEBUG_TAPE_FORMAT, RES_DEVICE_ERROR, myret.gen_error ) ;
+ DumpDebug( drv_hdl ) ;
+ curDRV->thw_inf.drv_status = myret.status ;
+ curDRV->cur_stats.underruns = myret.underruns ;
+ curDRV->cur_stats.dataerrs = myret.readerrs ;
+ }
+
+ switch( myret.gen_error ) {
+
+ case GEN_ERR_EOM:
+ SetChannelStatus( channel, CH_AT_EOM ) ;
+ SetPosBit( curDRV, ( AT_EOM | TAPE_FULL ) ) ;
+ if ( channel->cur_drv->inproc_q.q_count == 0 && myret.len_got == myret.len_req ) {
+ /* oops, we got the whole set written on this tape... */
+ BM_Put( tmpBUF ) ;
+ channel->eom_buff = NULL ;
+ SetChannelStatus( channel, CH_EOS_AT_EOM ) ;
+ } else {
+ if( myret.len_req != myret.len_got ) {
+ BM_SetNextByteOffset( tmpBUF, (UINT16)myret.len_got ) ;
+ channel->eom_buff = tmpBUF ;
+ } else {
+ BM_Put( tmpBUF ) ;
+ channel->eom_buff = NULL ;
+ }
+ EOM_Setup( channel, req ) ;
+ ret_val = WT_EndTape( channel ) ;
+ hit_eom = TRUE ;
+ }
+
+ break ;
+
+ case GEN_NO_ERR:
+ BM_Put( tmpBUF ) ;
+ break ;
+
+ case GEN_ERR_NO_MEDIA:
+ ret_val = TFLE_NO_TAPE ;
+ break ;
+
+ case GEN_ERR_BAD_DATA:
+ case GEN_ERR_TIMEOUT:
+ case GEN_ERR_INVALID_CMD:
+ case GEN_RESET:
+ case GEN_ERR_HARDWARE:
+ case GEN_ERR_UNDETERMINED:
+ default:
+ ret_val = TFLE_DRIVE_FAILURE ;
+ break ;
+
+ }
+ }
+ }
+
+ /* No Error so fix it all up */
+ if( ret_val == TFLE_NO_ERR && !hit_eom ) {
+
+ /* time to place an ending sample in the SX file */
+ if( SX_TmpFileIsOK( channel ) ) {
+ SX_EndSampling( channel ) ;
+ }
+
+ /* Finish up the formatting stuff */
+ ret_val = WT_EndSet( channel, abort ) ;
+
+ if( AtEOM( channel ) && ret_val == TFLE_NO_ERR &&
+ ( lw_fmtdescr[channel->cur_fmt].attributes & MUST_WRITE_CONT ) ) {
+ EOM_Setup( channel, req ) ;
+ hit_eom = TRUE ;
+ }
+ }
+
+ if( ret_val == TFLE_NO_ERR && !hit_eom ) {
+
+ /* So We Can get the underruns */
+ UpdateDriveStatus( curDRV ) ;
+
+ /* We are at EOD ... This may not be a valid assumption on devices which
+ allow overwriting of data. */
+ SetPosBit( curDRV, ( AT_EOD | AT_EOS ) ) ;
+
+ /* Copy the last backup vcb into the current drive holder */
+ curDRV->cur_vcb = *( (DBLK_PTR)channel->lst_osvcb ) ;
+ curDRV->vcb_valid = TRUE ;
+
+ }
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Name: EOM_Setup
+
+ Description: Sets up the TFL for EOM stuff.
+ Calls RD_TranslateDBLK to translate the last tape blocks
+ stored in channel->lst_osXXX into DBLKs.
+
+ Returns: Nothing ...
+
+ Notes: It's raining today.
+
+ Declaration:
+**/
+
+static VOID _near EOM_Setup(
+ CHANNEL_PTR channel,
+ RR_PTR rr_buf )
+{
+ DBLK_PTR hold_dblk = channel->cur_dblk ;
+ UINT16 block_size = MinSizeForTapeBlk( channel->cur_fmt );
+ VOID_PTR save_mem_ptr ; /* used to save allocation in buffer */
+ BUF_PTR buf_ptr ; /* a temporary buffer */
+ UINT16 blk_type ;
+
+ /* get a temporary buffer, save its primary allocation pointer */
+ buf_ptr = BM_GetVCBBuff( &channel->buffer_list );
+ msassert( buf_ptr != NULL );
+ save_mem_ptr = BM_XferBase( buf_ptr );
+
+ /* Translate the Last VCB */
+ if ( !IsChannelStatus( channel, CH_VCB_DBLK ) ) {
+ BM_SetBytesFree( buf_ptr, block_size ) ;
+ BM_SetNextByteOffset( buf_ptr, 0 ) ;
+ BM_XferBase( buf_ptr ) = channel->lst_osvcb ;
+ channel->cur_dblk = rr_buf->vcb_ptr ;
+ SetChannelStatus( channel, CH_VCB_DBLK ) ;
+ (void) RD_TranslateDBLK( channel, buf_ptr, &blk_type ) ;
+ *( (DBLK_PTR)channel->lst_osvcb ) = *rr_buf->vcb_ptr ;
+ }
+
+ /* Translate the DDB (or IDB) */
+ if ( channel->lst_tblk != BT_VCB && !IsChannelStatus( channel, CH_DDB_DBLK ) ) {
+ BM_SetBytesFree( buf_ptr, block_size ) ;
+ BM_SetNextByteOffset( buf_ptr, 0 ) ;
+ BM_XferBase( buf_ptr ) = channel->lst_osddb ;
+ channel->cur_dblk = rr_buf->ddb_ptr ;
+ SetChannelStatus( channel, CH_DDB_DBLK ) ;
+ (void) RD_TranslateDBLK( channel, buf_ptr, &blk_type ) ;
+ *( (DBLK_PTR)channel->lst_osddb ) = *rr_buf->ddb_ptr ;
+ }
+
+ /* Translate the FDB only if needed */
+ if ( channel->lst_tblk == BT_FDB && !IsChannelStatus( channel, CH_FDB_DBLK ) ) {
+ BM_SetBytesFree( buf_ptr, block_size ) ;
+ BM_SetNextByteOffset( buf_ptr, 0 ) ;
+ BM_XferBase( buf_ptr ) = channel->lst_osfdb ;
+ channel->cur_dblk = rr_buf->fdb_ptr ;
+ SetChannelStatus( channel, CH_FDB_DBLK ) ;
+ (void) RD_TranslateDBLK( channel, buf_ptr, &blk_type ) ;
+ *( (DBLK_PTR)channel->lst_osfdb ) = *rr_buf->fdb_ptr ;
+ }
+
+ /* Return the buffer to the channel pool */
+ BM_XferBase( buf_ptr ) = save_mem_ptr ;
+ BM_Put( buf_ptr ) ;
+
+ channel->cur_dblk = hold_dblk ;
+}
+
+/**/
+/**
+
+ Name: AbortWrite
+
+ Description: Contains the code to abort a write operation.
+
+ Returns: INT16, a TFLE_xxx code
+
+ Notes:
+
+ Declaration:
+
+**/
+
+static INT16 _near AbortWrite( CHANNEL_PTR channel, RR_PTR req )
+{
+ UINT16 size = ChannelBlkSize( channel ) ;
+ UINT16 offset ;
+ INT16 ret_val ;
+ BOOLEAN abort_flag = TRUE ;
+
+ msassert( channel->cur_buff != NULL ) ;
+
+ /* pad the buffer out to the next block boundry */
+ offset = BM_NextByteOffset( channel->cur_buff ) ;
+ if( offset % size != 0 ) {
+ BM_UpdCnts( channel->cur_buff, (UINT16)( size - ( offset % size ) ) ) ;
+ }
+
+ /* If we finished out the file, don't call it an abort */
+ if( U64_EQ( channel->current_stream.size, lw_UINT64_ZERO ) ) {
+ abort_flag = FALSE ;
+ }
+
+ ret_val = FinishWrite( channel, req, abort_flag ) ;
+
+ return ret_val ;
+}
+
diff --git a/private/utils/ntbackup/src/tgetinfo.c b/private/utils/ntbackup/src/tgetinfo.c
new file mode 100644
index 000000000..779feb9ab
--- /dev/null
+++ b/private/utils/ntbackup/src/tgetinfo.c
@@ -0,0 +1,258 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tgetinfo.c
+
+ Description: This file contains code to completely fills out a
+ minimalized DBLK.
+
+
+ $Log: M:/LOGFILES/TGETINFO.C_V $
+
+ Rev 1.20 23 Jan 1994 14:02:10 BARRY
+Added debug code
+
+ Rev 1.19 01 Dec 1993 13:41:08 STEVEN
+Path in stream bit was incorrectly cleared
+
+ Rev 1.18 13 Sep 1993 17:22:22 BARRY
+Fixed last fix.
+
+ Rev 1.17 19 Feb 1993 09:40:10 STEVEN
+if get dir info finds file return not found
+
+ Rev 1.16 27 Jan 1993 13:50:56 STEVEN
+updates from msoft
+
+ Rev 1.15 09 Dec 1992 14:11:14 STEVEN
+getinfo for files was not using correct path
+
+ Rev 1.14 07 Dec 1992 14:17:10 STEVEN
+updates from msoft
+
+ Rev 1.13 24 Nov 1992 16:39:44 STEVEN
+fix loose name structures
+
+ Rev 1.12 11 Nov 1992 09:52:44 GREGG
+Unicodeized literals.
+
+ Rev 1.11 10 Nov 1992 08:19:46 STEVEN
+removed path and name from dblk now use full_name_ptr
+
+ Rev 1.10 06 Nov 1992 15:48:54 STEVEN
+test write of path in stream
+
+ Rev 1.9 23 Oct 1992 13:33:22 STEVEN
+Fixed problem referencing f.name with DDB; path-in-stream fixes for DDBs.
+
+ Rev 1.8 08 Oct 1992 14:21:40 DAVEV
+Unicode strlen verfication
+
+ Rev 1.7 24 Sep 1992 13:43:28 BARRY
+Changes for huge file name support.
+
+ Rev 1.6 21 Sep 1992 16:51:54 BARRY
+Change over from path_complete to name_complete.
+
+ Rev 1.5 27 May 1992 18:48:38 STEVEN
+need to set field in DDB correctly
+
+ Rev 1.4 21 May 1992 13:51:02 STEVEN
+more long path stuff
+
+ Rev 1.3 04 May 1992 09:28:38 LORIB
+Changes for variable length paths and fixes for structure member names.
+
+ Rev 1.2 12 Mar 1992 15:50:12 STEVEN
+64 bit changes
+
+ Rev 1.1 28 Feb 1992 13:03:32 STEVEN
+step one for varible length paths
+
+ Rev 1.0 17 Jan 1992 17:50:08 STEVEN
+Initial revision.
+
+**/
+#include <windows.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "stdmacro.h"
+
+#include "fsys.h"
+#include "fsys_err.h"
+#include "ntfsdblk.h"
+#include "ntfs_fs.h"
+#include "msassert.h"
+
+/**/
+/**
+
+ Name: NTFS_GetObjInfo()
+
+ Description: This funciton fills out the missing information
+ in a DBLK.
+
+ Modified: 7/26/1989
+
+ Returns: Error Codes:
+ FS_NOT_FOUND
+ FS_ACCESS_DENIED
+ SUCCESS
+
+ Notes: For FDBs this funciton will check the current
+ directory for the specified file.
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 NTFS_GetObjInfo( fsh, dblk )
+FSYS_HAND fsh ; /* I - File system handle */
+DBLK_PTR dblk ; /*I/O- On entry it is minimal on exit Complete */
+{
+ INT16 ret_val ;
+ NTFS_DBLK_PTR ddblk;
+ HANDLE old_scan_hand ;
+ CHAR_PTR path_string ;
+ WIN32_FIND_DATA find_data ;
+
+ msassert( dblk != NULL );
+
+ ddblk = (NTFS_DBLK_PTR) dblk;
+
+ dblk->com.os_id = FS_NTFS_ID ;
+ dblk->com.os_ver = FS_NTFS_VER ;
+
+ msassert( fsh->attached_dle != NULL ) ;
+
+ switch( dblk->blk_type ){
+
+ case FDB_ID :
+ if ( ! ddblk->os_info_complete ) {
+
+ ret_val = NTFS_SetupWorkPath( fsh,
+ fsh->cur_dir,
+ ddblk->full_name_ptr->name,
+ &path_string ) ;
+
+ if ( ret_val != SUCCESS ) {
+ return ret_val ;
+ }
+
+ memset( &find_data, 0, sizeof( find_data ) ) ;
+ old_scan_hand = FindFirstFile( path_string, &find_data ) ;
+
+ if ( old_scan_hand != INVALID_HANDLE_VALUE ) {
+
+ ddblk->dta.size = U64_Init( find_data.nFileSizeLow,
+ find_data.nFileSizeHigh ) ;
+ ddblk->dta.os_attr = find_data.dwFileAttributes ;
+ ddblk->dta.create_time = find_data.ftCreationTime ;
+ ddblk->dta.modify_time = find_data.ftLastWriteTime ;
+ ddblk->dta.access_time = find_data.ftLastAccessTime ;
+ FindClose( old_scan_hand ) ;
+ } else {
+ NTFS_DebugPrint( TEXT("NTFS_GetObjInfo: ")
+ TEXT("FindFirstFile error %d, ")
+ TEXT("on FDB \"%s\""),
+ (int)GetLastError(),
+ path_string );
+
+ ret_val = FS_NOT_FOUND ;
+ }
+
+ NTFS_ReleaseWorkPath( fsh ) ;
+
+ } else {
+ ret_val = SUCCESS;
+ }
+
+ ddblk->os_info_complete = TRUE;
+ ddblk->name_complete = TRUE;
+
+ break ;
+
+ case DDB_ID :
+
+ if ( ! ddblk->os_info_complete ) {
+
+ if( ddblk->full_name_ptr->name[0] == TEXT('\0') ) { //root dir
+
+ ddblk->dta.os_attr = 0 ;
+ ddblk->dta.size = U64_Init( 0, 0 ) ;
+ ddblk->dta.create_time.dwLowDateTime = 0 ;
+ ddblk->dta.create_time.dwHighDateTime = 0 ;
+ ddblk->dta.modify_time.dwLowDateTime = 0 ;
+ ddblk->dta.modify_time.dwHighDateTime = 0 ;
+ ddblk->dta.access_time.dwLowDateTime = 0 ;
+ ddblk->dta.access_time.dwHighDateTime = 0 ;
+
+ ddblk->b.d.ddb_attrib = 0;
+ ret_val = SUCCESS ;
+
+ } else {
+
+ ddblk->b.d.ddb_attrib = 0;
+
+ if ( ddblk->full_name_ptr->name_size > NTFS_MAX_DSIZE ) {
+ ddblk->b.d.ddb_attrib |= (DIR_PATH_IN_STREAM_BIT) ;
+ }
+ ret_val = NTFS_SetupWorkPath( fsh, ddblk->full_name_ptr->name, NULL, &path_string ) ;
+
+ if ( ret_val != SUCCESS ) {
+ return ret_val ;
+ }
+
+ memset( &find_data, 0, sizeof( find_data ) );
+ old_scan_hand = FindFirstFile( path_string, &find_data ) ;
+
+ if ( (old_scan_hand != INVALID_HANDLE_VALUE ) &&
+ (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) ) {
+
+ ddblk->dta.size = U64_Init( 0, 0 ) ;
+ ddblk->dta.os_attr = find_data.dwFileAttributes ;
+ ddblk->dta.create_time = find_data.ftCreationTime ;
+ ddblk->dta.modify_time = find_data.ftLastWriteTime ;
+ ddblk->dta.access_time = find_data.ftLastAccessTime ;
+ FindClose( old_scan_hand ) ;
+
+ ret_val = SUCCESS ;
+
+ } else {
+ NTFS_DebugPrint( TEXT("NTFS_GetObjInfo: ")
+ TEXT("FindFirstFile error %d, ")
+ TEXT("on DDB \"%s\""),
+ (int)GetLastError(),
+ path_string );
+
+ ret_val = FS_NOT_FOUND ;
+ }
+ NTFS_ReleaseWorkPath( fsh ) ;
+ }
+
+ ddblk->blk_type = DDB_ID ;
+
+ ddblk->name_complete = TRUE;
+ ddblk->os_info_complete = TRUE;
+
+ } else {
+ ret_val = SUCCESS;
+ }
+
+ break ;
+
+
+ case VCB_ID:
+ ret_val = SUCCESS ;
+ break ;
+
+ default :
+
+ ret_val = FS_NOT_FOUND ;
+ }
+
+ return( ret_val ) ;
+}
diff --git a/private/utils/ntbackup/src/tgetnext.c b/private/utils/ntbackup/src/tgetnext.c
new file mode 100644
index 000000000..f7ba3a703
--- /dev/null
+++ b/private/utils/ntbackup/src/tgetnext.c
@@ -0,0 +1,638 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tgetnext.c
+
+ Description: This file contains code to enumerate the contents of
+ a directory.
+
+
+ $Log: N:\logfiles\tgetnext.c_v $
+
+ Rev 1.33.1.1 15 Jul 1994 19:51:30 STEVEN
+fix more net errors
+
+ Rev 1.33.1.0 17 Jun 1994 20:05:20 STEVEN
+fix bug with net dissconect
+
+ Rev 1.33 23 Jan 1994 14:04:00 BARRY
+Added debug code; cleaned up bogus use of -1 and NULL for handle values
+
+ Rev 1.32 18 Oct 1993 19:14:20 STEVEN
+add support for PERIOD & SPACE
+
+ Rev 1.31 29 Sep 1993 11:47:56 BARRY
+Don't return dead net on ERROR_PATH_NOT_FOUND.
+
+ Rev 1.30 17 Aug 1993 17:50:02 BARRY
+More cases for the net going bye-bye.
+
+ Rev 1.29 27 Jul 1993 17:33:20 BARRY
+Based on experimentation, cleaned up the error codes one more time.
+
+ Rev 1.28 26 Jul 1993 18:30:28 STEVEN
+another place to check for SPACE
+
+ Rev 1.27 26 Jul 1993 17:10:56 STEVEN
+fix files ending in SPACE
+
+ Rev 1.26 23 Jul 1993 13:48:00 BARRY
+Better error support.
+
+ Rev 1.25 21 Jul 1993 16:10:28 BARRY
+Don't return FS_NOT_FOUND from FindFirst/Next.
+
+ Rev 1.24 16 Jul 1993 14:20:50 BARRY
+If FindFirst/Next on a remote drive returns any error other than
+ERROR_NO_MORE_FILES assume something has gone really wrong and
+return FS_COMM_FAILURE. (This is a kludge because there is no good
+way to know if a device has truly died.)
+
+ Rev 1.23 30 Jun 1993 15:12:54 BARRY
+Handle those pesky Mac names.
+
+ Rev 1.22 20 May 1993 17:39:58 BARRY
+[Steve] Kludge fix for handling Unicode file names in an ASCII app.
+
+ Rev 1.21 27 Jan 1993 13:51:02 STEVEN
+updates from msoft
+
+ Rev 1.20 07 Dec 1992 14:18:46 STEVEN
+updates from msoft
+
+ Rev 1.19 11 Nov 1992 09:52:24 GREGG
+Unicodeized literals.
+
+ Rev 1.18 10 Nov 1992 08:20:54 STEVEN
+removed path and name from dblk now use full_name_ptr
+
+ Rev 1.17 06 Nov 1992 16:27:44 STEVEN
+test unlimited file sizes
+
+ Rev 1.16 19 Oct 1992 17:53:32 BARRY
+Was testing directory bit in wrong attribute word.
+
+ Rev 1.15 08 Oct 1992 14:21:34 DAVEV
+Unicode strlen verfication
+
+ Rev 1.14 07 Oct 1992 18:00:44 BARRY
+Use common function for FindFirst/FindNext to fill out DBLK.
+
+ Rev 1.13 05 Oct 1992 11:57:26 BARRY
+Forgot to init huge fname pointer.
+
+ Rev 1.12 24 Sep 1992 13:43:30 BARRY
+Changes for huge file name support.
+
+ Rev 1.11 21 Sep 1992 16:51:56 BARRY
+Change over from path_complete to name_complete.
+
+ Rev 1.10 17 Aug 1992 15:42:34 STEVEN
+fix warnings
+
+ Rev 1.9 20 Jul 1992 10:43:02 STEVEN
+backup short file name
+
+ Rev 1.8 09 Jun 1992 15:10:24 BURT
+Sync with NT stuff
+
+ Rev 1.6 21 May 1992 13:49:24 STEVEN
+more long path support
+
+ Rev 1.5 04 May 1992 09:32:12 LORIB
+Changes for variable length paths.
+
+ Rev 1.4 12 Mar 1992 15:50:16 STEVEN
+64 bit changes
+
+ Rev 1.3 28 Feb 1992 13:03:42 STEVEN
+step one for varible length paths
+
+ Rev 1.2 12 Feb 1992 10:46:52 STEVEN
+fix warning
+
+ Rev 1.1 05 Feb 1992 15:47:40 STEVEN
+added support for FindHandle Queue
+
+ Rev 1.0 17 Jan 1992 17:50:08 STEVEN
+Initial revision.
+
+**/
+/* begin include list */
+#include <windows.h>
+#include <string.h>
+#include <malloc.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "std_err.h"
+#include "queues.h"
+
+#include "msassert.h"
+#include "fsys.h"
+#include "fsys_err.h"
+#include "ntfsdblk.h"
+#include "ntfs_fs.h"
+#include "tfldefs.h"
+
+static VOID NTFS_ClearFindHand(
+FSYS_HAND fsh, /* I - File system handle */
+DBLK_PTR dblk ) ; /* I - discriptor block which contains scan hand */
+
+static INT16 NTFS_EnQueueScanHand(
+FSYS_HAND fsh, /* I - File system handle */
+DBLK_PTR dblk ) ; /* I - discriptor block which contains scan hand */
+
+static INT16 TranslateFindError( FSYS_HAND fsh, DWORD err );
+
+/**/
+/**
+
+ Name: NTFS_FindFirst()
+
+ Description: This function calls WIN32S to find the entry in the
+ current directory which matches the search name (s_name).
+ This function returns an initialized FDB or DDB.
+
+ Modified: 1/10/1992 15:24:39
+
+ Returns: Error codes:
+ FS_NO_MORE
+ SUCCESS
+
+ Notes: This function will NOT return directories "." and ".."
+
+ See also: NTFS_FindNext()
+
+**/
+INT16 NTFS_FindFirst(
+FSYS_HAND fsh, /* I - file system handle */
+DBLK_PTR dblk, /* O - pointer to place to put the dblk data */
+CHAR_PTR sname, /* I - search name */
+UINT16 obj_type) /* I - objects to search for (dirs, all, etc)*/
+{
+ GENERIC_DLE_PTR dle = fsh->attached_dle ;
+ NTFS_DBLK_PTR ddblk = (NTFS_DBLK_PTR)dblk ;
+ INT16 ret_val = SUCCESS;
+ NTFS_FSYS_RESERVED_PTR ntfs_fsh = fsh->reserved.ptr ;
+ WIN32_FIND_DATA find_data ;
+ CHAR_PTR path_string ;
+ DWORD findError = NO_ERROR;
+
+ msassert( dle != NULL ) ;
+
+ dblk->com.os_id = FS_NTFS_ID ;
+ dblk->com.os_ver = FS_NTFS_VER ;
+ ntfs_fsh->file_scan_mode = obj_type ;
+ memset( &find_data, 0, sizeof( find_data ) ) ;
+
+ /* form BASE_PATH */
+ if ( NTFS_SetupWorkPath( fsh, fsh->cur_dir, sname, &path_string ) != SUCCESS)
+ {
+ return OUT_OF_MEMORY ;
+ }
+
+ ddblk->dta.scan_hand = FindFirstFile( path_string, &find_data ) ;
+
+ if ( ddblk->dta.scan_hand != INVALID_HANDLE_VALUE )
+ {
+ ret_val = NTFS_EnQueueScanHand( fsh, dblk ) ;
+ }
+ else
+ {
+ findError = GetLastError();
+ }
+
+ if ( (findError == NO_ERROR) && (ret_val == SUCCESS) )
+ {
+ if ( find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
+ {
+ if ( ( find_data.cFileName[0]==TEXT('.')) &&
+ ( ( find_data.cFileName[1]==TEXT('\0')) ||
+ ( ( find_data.cFileName[1]==TEXT('.')) &&
+ ( find_data.cFileName[2]==TEXT('\0')) ) ) ) /* if dir = ".." or "." */
+ {
+
+ ret_val = NTFS_FindNext( fsh, dblk ) ;
+ }
+ else
+ {
+ ret_val = NTFS_FillOutDBLK( fsh, dblk, &find_data );
+ }
+ }
+ else
+ {
+ ret_val = NTFS_FillOutDBLK( fsh, dblk, &find_data );
+ }
+ }
+ else if ( ret_val == SUCCESS )
+ {
+ ret_val = TranslateFindError( fsh, findError );
+ if ( findError != ERROR_NO_MORE_FILES )
+ {
+ NTFS_DebugPrint( TEXT("NTFS_FindFirst: ")
+ TEXT("FindFirstFile error %d, ")
+ TEXT("path = \"%s\""),
+ (int)findError,
+ path_string );
+ }
+ }
+
+ NTFS_ReleaseWorkPath( fsh ) ;
+ return ret_val;
+}
+
+/**/
+/**
+
+ Name: NTFS_FindNext()
+
+ Description: This function calls WIN32 to get the "NEXT" directory
+ element in the current directory.
+
+ The dblk passed in must be initialized by a call to NTFS_GetFirst()
+
+ Modified: 1/10/1992 15:46:20
+
+ Returns: Error code:
+ SUCCESS
+ FILE_NOT_FOUND
+
+ Notes: This function will NOT return "." and ".."
+
+ See also: NTFS_FindFirst()
+
+**/
+INT16 NTFS_FindNext( fsh, dblk )
+FSYS_HAND fsh; /* I - File system handle */
+DBLK_PTR dblk; /* O - Discriptor block */
+{
+ INT16 ret_val = SUCCESS;
+ BOOLEAN try_again ;
+ NTFS_DBLK_PTR ddblk;
+ WIN32_FIND_DATA find_data ;
+ NTFS_FSYS_RESERVED_PTR ntfs_fsh ;
+
+ msassert( fsh->attached_dle != NULL ) ;
+
+ ddblk = (NTFS_DBLK_PTR) dblk;
+
+ ntfs_fsh = fsh->reserved.ptr ;
+
+ dblk->com.os_id = FS_NTFS_ID ;
+ dblk->com.os_ver = FS_NTFS_VER ;
+
+ do {
+ try_again = FALSE ;
+
+ if ( !FindNextFile( ddblk->dta.scan_hand, &find_data ) )
+ {
+ DWORD err = GetLastError( );
+
+ ret_val = TranslateFindError( fsh, err );
+
+ if ( ret_val != FS_NO_MORE )
+ {
+ NTFS_DebugPrint( TEXT("NTFS_FindNext: ")
+ TEXT("FindNextFile failed with %d"),
+ (int)err );
+ }
+
+ NTFS_ClearFindHand( fsh, dblk ) ;
+ ddblk->dta.scan_hand = INVALID_HANDLE_VALUE ;
+ break ;
+ }
+
+ if ( find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
+ {
+ if ( ( find_data.cFileName[0]==TEXT('.')) &&
+ ( ( find_data.cFileName[1]==TEXT('\0')) ||
+ ( ( find_data.cFileName[1]==TEXT('.')) &&
+ ( find_data.cFileName[2]==TEXT('\0')) ) ) )
+ {
+ /* dir is ".." or "." */
+ try_again = TRUE ;
+ }
+ }
+ } while (try_again ) ;
+
+ if ( ret_val == SUCCESS )
+ {
+ ret_val = NTFS_FillOutDBLK( fsh, dblk, &find_data );
+ }
+ return ret_val ;
+}
+
+
+/**/
+/**
+
+ Name: NTFS_FillOutDBLK()
+
+ Description: Common function to properly fill out a DBLK.
+
+ Modified: 06-Oct-92
+
+ Returns:
+
+**/
+INT16 NTFS_FillOutDBLK( FSYS_HAND fsh,
+ DBLK_PTR dblk,
+ WIN32_FIND_DATA *find_data )
+{
+ NTFS_DBLK_PTR ddblk = (NTFS_DBLK_PTR)dblk;
+ INT16 ret_val = SUCCESS;
+
+ dblk->com.os_name = NULL ;
+
+ ddblk->dta.size = U64_Init( find_data->nFileSizeLow,
+ find_data->nFileSizeHigh ) ;
+ ddblk->dta.os_attr = find_data->dwFileAttributes ;
+ ddblk->dta.create_time = find_data->ftCreationTime ;
+ ddblk->dta.modify_time = find_data->ftLastWriteTime ;
+ ddblk->dta.access_time = find_data->ftLastAccessTime ;
+ ddblk->name_complete = TRUE;
+
+ if ( ddblk->dta.os_attr & FILE_ATTRIBUTE_DIRECTORY ) /* if directory */
+ {
+ ddblk->blk_type = DDB_ID ;
+ ddblk->b.d.ddb_attrib = 0;
+
+ if ( strsize( fsh->cur_dir ) + strsize(find_data->cFileName) > NTFS_MAX_DSIZE )
+ {
+ ddblk->b.d.ddb_attrib |= (DIR_PATH_IN_STREAM_BIT) ;
+
+ }
+
+ if ( ! fsh->attached_dle->info.ntfs->mac_name_syntax &&
+ ( strchr( find_data->cFileName, TEXT('?') ) ||
+ ( find_data->cFileName[ strlen( find_data->cFileName ) - 1 ] == TEXT('.') ) ||
+ ( find_data->cFileName[ strlen( find_data->cFileName ) - 1 ] == TEXT(' ') ) ) ) {
+
+ ret_val = NTFS_SetupPathInDDB( fsh, dblk, &fsh->cur_dir[1], find_data->cAlternateFileName, 0 ) ;
+ } else {
+ ret_val = NTFS_SetupPathInDDB( fsh, dblk, &fsh->cur_dir[1], find_data->cFileName, 0 ) ;
+ }
+
+ if ( ret_val != SUCCESS )
+ {
+ NTFS_ClearFindHand( fsh, dblk ) ;
+ }
+
+ }
+ else
+ {
+ ddblk->blk_type = FDB_ID ;
+ ddblk->b.f.fdb_attrib = 0;
+
+ if ( find_data->cAlternateFileName[0] != TEXT('\0') ) {
+
+ ddblk->b.f.PosixFile = FALSE ;
+
+ memcpy( ddblk->b.f.alt_name,
+ find_data->cAlternateFileName,
+ sizeof( find_data->cAlternateFileName ) ) ;
+
+ } else {
+ ddblk->b.f.PosixFile = TRUE ;
+ memset( ddblk->b.f.alt_name, 0, sizeof( ddblk->b.f.alt_name ) ) ;
+
+ }
+
+ if ( (strlen( find_data->cFileName ) + 2) > NTFS_MAX_FSIZE )
+ {
+ ddblk->b.f.fdb_attrib |= (FILE_NAME_IN_STREAM_BIT) ;
+ }
+
+ // files with a '?' have a non mapable unicode character //
+ // files which end in '.' or ' ' are not accessable using WIN32 //
+
+ if ( ! fsh->attached_dle->info.ntfs->mac_name_syntax &&
+ ( strchr( find_data->cFileName, TEXT('?') ) ||
+ ( find_data->cFileName[ strlen( find_data->cFileName ) - 1 ] == TEXT('.') ) ||
+ ( find_data->cFileName[ strlen( find_data->cFileName ) - 1 ] == TEXT(' ') ) ) ) {
+
+ ret_val = NTFS_SetupFileNameInFDB( fsh,
+ dblk,
+ find_data->cAlternateFileName,
+ 0 );
+ } else {
+ ret_val = NTFS_SetupFileNameInFDB( fsh,
+ dblk,
+ find_data->cFileName,
+ 0 );
+ }
+
+ if ( ret_val != SUCCESS )
+ {
+ NTFS_ClearFindHand( fsh, dblk );
+ }
+
+ ddblk->b.f.handle = NULL ;
+ }
+ ddblk->os_info_complete = TRUE;
+ return ret_val;
+}
+
+/**/
+/**
+
+ Name: NTFS_FindClose()
+
+ Description: This function calls WIN32 to get the end the
+ scan for the specified directory.
+
+ The dblk passed in must be initialized by a call to NTFS_GetFirst() or
+ NTFS_FindClose
+
+ Modified: 1/10/1992 15:46:20
+
+ Returns: Error code:
+ SUCCESS
+ FILE_NOT_FOUND
+
+ Notes: This function will NOT return "." and ".."
+
+ See also: NTFS_FindFirst()
+
+**/
+INT16 NTFS_FindClose( FSYS_HAND fsh,
+ DBLK_PTR dblk )
+{
+ NTFS_DBLK_PTR ddblk;
+ ddblk = (NTFS_DBLK_PTR) dblk;
+
+ (VOID)(fsh);
+
+ if ( ddblk->dta.scan_hand != INVALID_HANDLE_VALUE )
+ {
+ NTFS_ClearFindHand( fsh, dblk ) ;
+ }
+
+ ddblk->dta.scan_hand = INVALID_HANDLE_VALUE ;
+
+ return SUCCESS ;
+}
+
+static INT16 NTFS_EnQueueScanHand(
+FSYS_HAND fsh, /* I - File system handle */
+DBLK_PTR dblk ) /* I - discriptor block which contains scan hand */
+{
+ NTFS_DBLK_PTR ddblk;
+ NTFS_SCAN_Q_ELEM_PTR scan_q_elem ;
+ NTFS_FSYS_RESERVED_PTR ntfs_res ;
+
+ ddblk = (NTFS_DBLK_PTR) dblk;
+
+ ntfs_res = (NTFS_FSYS_RESERVED_PTR)( fsh->reserved.ptr ) ;
+
+ scan_q_elem = calloc( 1, sizeof( *scan_q_elem ) ) ;
+
+ if ( scan_q_elem == NULL )
+ {
+ FindClose( ddblk->dta.scan_hand ) ;
+ return OUT_OF_MEMORY ;
+ }
+ else
+ {
+ scan_q_elem->scan_hand = ddblk->dta.scan_hand ;
+ EnQueueElem( &ntfs_res->scan_q, &scan_q_elem->q, FALSE ) ;
+ }
+
+ return SUCCESS ;
+}
+static VOID NTFS_ClearFindHand(
+FSYS_HAND fsh, /* I - File system handle */
+DBLK_PTR dblk ) /* I - discriptor block which contains scan hand */
+{
+ NTFS_DBLK_PTR ddblk;
+ NTFS_SCAN_Q_ELEM_PTR scan_q_elem ;
+ NTFS_FSYS_RESERVED_PTR ntfs_res ;
+
+ ddblk = (NTFS_DBLK_PTR) dblk;
+
+ ntfs_res = (NTFS_FSYS_RESERVED_PTR)( fsh->reserved.ptr ) ;
+
+ scan_q_elem = (NTFS_SCAN_Q_ELEM_PTR)QueueHead( &ntfs_res->scan_q ) ;
+
+ while ( scan_q_elem ) {
+ if ( scan_q_elem->scan_hand == ddblk->dta.scan_hand ) {
+ RemoveQueueElem( &ntfs_res->scan_q, &scan_q_elem->q ) ;
+ free( scan_q_elem ) ;
+ break ;
+ } else {
+ scan_q_elem = ( NTFS_SCAN_Q_ELEM_PTR)QueueNext( &scan_q_elem->q) ;
+ }
+ }
+
+ if ( FindClose( ddblk->dta.scan_hand ) == FALSE )
+ {
+ NTFS_DebugPrint( TEXT("NTFS_ClearFindHand: FindClose error %d"),
+ (int)GetLastError() );
+ }
+}
+
+VOID NTFS_EmptyFindHandQ(
+FSYS_HAND fsh ) /* I - File system handle */
+{
+ NTFS_SCAN_Q_ELEM_PTR scan_q_elem ;
+ NTFS_FSYS_RESERVED_PTR ntfs_res ;
+
+ ntfs_res = (NTFS_FSYS_RESERVED_PTR)( fsh->reserved.ptr ) ;
+
+ scan_q_elem = (NTFS_SCAN_Q_ELEM_PTR)DeQueueElem( &ntfs_res->scan_q ) ;
+
+ while ( scan_q_elem )
+ {
+ if ( scan_q_elem->scan_hand != INVALID_HANDLE_VALUE )
+ {
+ FindClose( scan_q_elem->scan_hand ) ;
+ }
+ free( scan_q_elem ) ;
+ scan_q_elem = (NTFS_SCAN_Q_ELEM_PTR)DeQueueElem( &ntfs_res->scan_q ) ;
+ }
+}
+
+/**/
+/**
+
+ Name: TranslateFindError()
+
+ Description: Performs mapping from NT errors to FS errors
+ for problems on find operations.
+
+ Modified: 22-Jul-93
+
+ Returns: FS error code
+
+ Notes: Too specific to FindFirst/Next operations to use for
+ any other operations.
+
+**/
+static INT16 TranslateFindError( FSYS_HAND fsh, DWORD err )
+{
+ INT16 ret;
+ BOOLEAN remote = DLE_HasFeatures( fsh->attached_dle, DLE_FEAT_REMOTE_DRIVE );
+
+ switch ( err )
+ {
+ case NO_ERROR:
+ ret = SUCCESS;
+ break;
+
+ case ERROR_FILE_NOT_FOUND: // 2
+ case ERROR_NO_MORE_FILES: // 18
+ case ERROR_NO_MORE_ITEMS:
+ ret = FS_NO_MORE;
+ break;
+
+ case ERROR_PATH_NOT_FOUND: // 3 (cannot access directory)
+ case ERROR_ACCESS_DENIED: // 5 example: no rights to scan
+ ret = FS_ACCESS_DENIED;
+ break;
+
+ case ERROR_NETNAME_DELETED:
+ case ERROR_BAD_NETPATH:
+ case ERROR_BAD_NET_NAME:
+ case ERROR_UNEXP_NET_ERR:
+ if ( remote )
+ {
+ ret = FS_COMM_FAILURE;
+ }
+ else
+ {
+ ret = FS_ACCESS_DENIED;
+ }
+ break;
+
+
+ case ERROR_HANDLE_EOF: // kludge: we get EOF if device dies
+ if ( remote )
+ {
+ ret = FS_COMM_FAILURE;
+ }
+ else
+ {
+ ret = FS_NO_MORE;
+ }
+ break;
+
+ case ERROR_DEV_NOT_EXIST:
+ case ERROR_NOT_DOS_DISK:
+ case ERROR_READ_FAULT:
+ case ERROR_DISK_CORRUPT:
+ case ERROR_FILE_CORRUPT:
+ case ERROR_FILE_INVALID:
+ case ERROR_SEEK:
+ ret = FS_DEVICE_ERROR;
+ break;
+
+ default:
+ ret = FS_ACCESS_DENIED;
+ break;
+ }
+ return ret;
+}
+
+
diff --git a/private/utils/ntbackup/src/tgetpath.c b/private/utils/ntbackup/src/tgetpath.c
new file mode 100644
index 000000000..398269c7e
--- /dev/null
+++ b/private/utils/ntbackup/src/tgetpath.c
@@ -0,0 +1,500 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tgetpath.c
+
+ Description: This file contains code to get the current directory
+ path and the complete directory path from the file system handle.
+
+
+ $Log: M:/LOGFILES/TGETPATH.C_V $
+
+ Rev 1.23.1.1 19 Jan 1994 12:52:06 BARRY
+Supress warnings
+
+ Rev 1.23.1.0 18 Oct 1993 19:21:56 STEVEN
+add support for SPACE & PERIOD
+
+ Rev 1.23 30 Jul 1993 13:19:14 STEVEN
+if dir too deep make new one
+
+ Rev 1.22 19 Feb 1993 09:21:46 STEVEN
+fix some bugs
+
+ Rev 1.21 14 Jan 1993 13:33:52 STEVEN
+added stream_id to error message
+
+ Rev 1.20 11 Nov 1992 09:52:40 GREGG
+Unicodeized literals.
+
+ Rev 1.19 10 Nov 1992 14:54:22 STEVEN
+
+
+ Rev 1.18 10 Nov 1992 14:03:52 STEVEN
+do not queue invalid stuff
+
+ Rev 1.17 10 Nov 1992 08:19:04 STEVEN
+removed path and name from dblk now use full_name_ptr
+
+ Rev 1.16 06 Nov 1992 15:49:56 STEVEN
+test write of path in stream
+
+ Rev 1.15 29 Oct 1992 16:54:18 BARRY
+Some path-in-stream changes.
+
+ Rev 1.14 14 Oct 1992 14:40:06 BARRY
+Fixed spelling errors.
+
+ Rev 1.13 09 Oct 1992 14:52:22 BARRY
+Name-in-stream changes.
+
+ Rev 1.12 07 Oct 1992 14:26:08 STEVEN
+removed base_path
+
+ Rev 1.11 07 Oct 1992 13:50:58 DAVEV
+unicode strlen verification
+
+ Rev 1.10 24 Sep 1992 13:43:34 BARRY
+Changes for huge file name support.
+
+ Rev 1.9 04 Sep 1992 17:15:00 STEVEN
+fix warnings
+
+ Rev 1.8 09 Jun 1992 15:06:52 BURT
+Sync with NT stuff
+
+ Rev 1.6 22 May 1992 16:05:26 STEVEN
+
+
+ Rev 1.5 21 May 1992 13:49:08 STEVEN
+more long path support
+
+ Rev 1.4 18 May 1992 14:28:42 STEVEN
+fixed release blk
+
+ Rev 1.3 04 May 1992 09:20:50 LORIB
+Changes for variable length paths.
+
+ Rev 1.2 28 Feb 1992 13:03:48 STEVEN
+step one for varible length paths
+
+ Rev 1.1 05 Feb 1992 15:47:42 STEVEN
+added support for FindHandle Queue
+
+ Rev 1.0 17 Jan 1992 17:50:10 STEVEN
+Initial revision.
+
+**/
+#include <windows.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "queues.h"
+
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "ntfs_fs.h"
+#include "ntfsdblk.h"
+/**/
+/**
+
+ Name: NTFS_GetCurrentPath()
+
+ Description: This function sets a string to describes the current
+ path.
+
+ Modified: 1/10/1992 14:2:3
+
+ Returns: Error Codes :
+ FS_DLE_NOT_ATTACHED
+ FS_BUFFER_TO_SMALL
+ SUCCESS
+
+ Notes: The delimiter between directories is '\0'
+
+**/
+INT16 NTFS_GetCurrentPath( fsh, path, size )
+FSYS_HAND fsh ; /* I - file system to get current path from */
+CHAR_PTR path ; /* O - buffer to place this path */
+INT16 *size ; /*I/O- size of buffer on entry & on exit */
+{
+ GENERIC_DLE_PTR dle ;
+ CHAR_PTR p ;
+ INT16 ret_val ;
+ INT16 temp_size ;
+
+ dle = fsh->attached_dle ;
+
+ msassert( dle != NULL ) ;
+
+ temp_size = (INT16)strsize( fsh->cur_dir ) ; /* count the last '\0' */
+
+ if ( *size < temp_size ) {
+
+ ret_val = FS_BUFFER_TO_SMALL ;
+
+ }
+ else {
+
+ /* copy the whole cur_dir over and then...*/
+
+ strcpy( path, &(fsh->cur_dir[1]) ) ;
+
+ /* ...replace backslashes with nulls */
+
+ p = strchr( path, TEXT('\\') ) ;
+ while ( p != NULL ) {
+ *p = TEXT('\0');
+ p = strchr( p+1, TEXT('\\') ) ;
+ }
+
+ ret_val = SUCCESS ;
+ }
+
+ *size = temp_size ;
+
+ return ret_val ;
+}
+/**/
+/**
+
+ Name: NTFS_GetBasePath()
+
+ Description: This function returns the base (root) path.
+
+ Modified: 1/10/1992 14:44:28
+
+ Returns: Error codes:
+ FS_BUFFER_TO_SMALL
+ SUCCESS
+
+ Notes: This can be used for display purposes.
+
+**/
+INT16 NTFS_GetBasePath( fsh, full_path, size )
+FSYS_HAND fsh; /* I - file system to get base path from */
+CHAR_PTR full_path ; /* O - buffer to place this path */
+INT16 *size ; /*I/O- size of buffer on entry & on exit */
+{
+ INT16 ret_val ;
+
+ msassert( fsh->attached_dle != NULL ) ;
+
+ if ( *size < 1 ) {
+
+ ret_val = FS_BUFFER_TO_SMALL ;
+
+ }
+ else {
+
+ *full_path = TEXT('\0');
+
+ ret_val = SUCCESS ;
+ }
+ *size = 1 ;
+
+ return ret_val ;
+}
+
+/**/
+/**
+
+ Name: NTFS_GetCurrentDDB()
+
+ Description: This function initializes the provided DDB with the
+ information for the current directory.
+
+
+ Modified: 1/10/1992 14:45:26
+
+ Returns: Error code:
+ FS_INVALID_DIR
+ SUCCESS
+ OUT_OF_MEMORY
+
+ Notes:
+
+**/
+INT16 NTFS_GetCurrentDDB( fsh, dblk )
+FSYS_HAND fsh ; /* I - file system to get DDB from */
+DBLK_PTR dblk ; /* O - place to put the DDB data */
+{
+ GENERIC_DLE_PTR dle ;
+ NTFS_DBLK_PTR ddblk ;
+ INT16 ret_val = SUCCESS ;
+
+ dle = fsh->attached_dle ;
+
+ msassert( dle != NULL ) ;
+
+ ddblk = (NTFS_DBLK_PTR) dblk ;
+ ddblk->blk_type = DDB_ID ;
+ ddblk->os_info_complete = FALSE ;
+ dblk->com.os_name = NULL ;
+
+ if ( strsize( fsh->cur_dir ) > NTFS_MAX_DSIZE ) {
+ ddblk->b.d.ddb_attrib |= (DIR_PATH_IN_STREAM_BIT) ;
+ }
+ ret_val = NTFS_SetupPathInDDB( fsh, dblk, &fsh->cur_dir[1], NULL, 0 ) ;
+
+ if ( (ret_val == SUCCESS) && (NTFS_GetObjInfo( fsh, dblk ) != SUCCESS) ) {
+ ret_val = FS_INVALID_DIR ;
+ }
+
+ return( ret_val ) ;
+}
+
+
+VOID NTFS_GetRealBasePath( FSYS_HAND fsh, CHAR_PTR path )
+{
+ path[0] = fsh->attached_dle->info.ntfs->drive ;
+ path[1] = TEXT(':');
+ path[2] = TEXT('\0');
+}
+INT16 NTFS_SetupWorkPath(
+FSYS_HAND fsh,
+CHAR_PTR cur_dir,
+CHAR_PTR sname,
+CHAR_PTR *path_string )
+{
+ UINT16 req_size ;
+ NTFS_FSYS_RESERVED_PTR nt_fsh ;
+ CHAR_PTR path ;
+ INT16 ret_val = SUCCESS ;
+
+ nt_fsh = (NTFS_FSYS_RESERVED_PTR)( fsh->reserved.ptr ) ;
+
+ while( nt_fsh->work_buf_in_use ) ; /* wait on semaphore */
+
+ nt_fsh->work_buf_in_use = 1 ;
+
+ req_size = 10 * sizeof (CHAR) ;
+ req_size += strlen( cur_dir ) * sizeof (CHAR);
+
+ if ( sname != NULL ) {
+ //DAVEV: note: this line was 1 + strlen() - the 1 was added to
+ // allow for an additional backslash - when using strsize()
+ // this one is automatically added since the trailing NULL
+ // is counted. This may not be obvious - hence this note.
+
+ req_size += strsize( sname ) ;
+ }
+
+ if ( nt_fsh->work_buf_size < req_size ) {
+ nt_fsh->work_buf_size = (UINT16)(req_size + 100) ;
+ nt_fsh->work_buf = realloc( nt_fsh->work_buf, nt_fsh->work_buf_size ) ;
+ }
+
+ if ( nt_fsh->work_buf ) {
+
+ INT index = 0 ;
+
+ path = nt_fsh->work_buf ;
+
+ if ( fsh->attached_dle->info.ntfs->mac_name_syntax ) {
+ path[0] = path[1] = path[3] = TEXT('\\') ;
+ path[2] = TEXT('?') ;
+ index = 4 ;
+ }
+
+ path[index + 0] = fsh->attached_dle->info.ntfs->drive ;
+ path[index + 1] = TEXT(':');
+ path[index + 2] = TEXT('\0');
+
+ if( *cur_dir != TEXT('\\') ) {
+ strcat( path, TEXT("\\") ) ;
+ }
+ strcat( path, cur_dir );
+
+ if ( sname != NULL ) {
+ if ( cur_dir[1] != TEXT('\0') ) {
+ strcat( path, TEXT("\\") ) ;
+ }
+ strcat( path, sname ) ;
+ }
+
+ *path_string = path ;
+
+ } else {
+ nt_fsh->work_buf_size = 0 ;
+ nt_fsh->work_buf_in_use = 0 ;
+ ret_val = OUT_OF_MEMORY ;
+ }
+
+ return ret_val ;
+
+}
+VOID NTFS_ReleaseWorkPath(
+FSYS_HAND fsh )
+{
+ NTFS_FSYS_RESERVED_PTR nt_fsh ;
+
+ nt_fsh = (NTFS_FSYS_RESERVED_PTR)( fsh->reserved.ptr ) ;
+
+ nt_fsh->work_buf_in_use = 0 ;
+}
+
+INT16 NTFS_SetupPathInDDB(
+FSYS_HAND fsh,
+DBLK_PTR dblk,
+CHAR_PTR cur_dir,
+CHAR_PTR sub_dir_name,
+UINT16 buf_req_size )
+{
+ UINT16 req_size = 0 ;
+ NTFS_DBLK_PTR ddblk ;
+ FS_NAME_Q_ELEM_PTR path_q_elem ;
+ INT16 ret_val = SUCCESS ;
+
+ ddblk = (NTFS_DBLK_PTR)dblk ;
+
+ if ( cur_dir != NULL ) {
+ req_size = (UINT16)(strsize( cur_dir ) ) ;
+ }
+
+ if ( sub_dir_name != NULL ) {
+ req_size += (UINT16)( strsize( sub_dir_name ) ) ;
+ }
+
+ if ( req_size < buf_req_size ) {
+ req_size = buf_req_size ;
+ }
+
+ path_q_elem = FS_AllocPathOrName( fsh, req_size ) ;
+ if ( path_q_elem == NULL ) {
+ return OUT_OF_MEMORY ;
+ }
+
+ ddblk->full_name_ptr = path_q_elem ;
+
+ if ( cur_dir != NULL || sub_dir_name != NULL ) {
+
+ if ( cur_dir != NULL ) {
+ strcpy( path_q_elem->name, cur_dir ) ;
+ }
+
+ if ( sub_dir_name != NULL ) {
+
+ if ( path_q_elem->name[0] != TEXT('\0') ) {
+ strcat( path_q_elem->name, TEXT("\\") ) ;
+ }
+ strcat( path_q_elem->name, sub_dir_name ) ;
+ }
+
+ path_q_elem->name_size = strsize( path_q_elem->name );
+
+ }
+
+ return ret_val ;
+}
+
+
+
+
+
+INT16 NTFS_SetupFileNameInFDB( FSYS_HAND fsh,
+ DBLK_PTR dblk,
+ CHAR_PTR fname,
+ UINT16 bufMinSize )
+{
+ INT16 ret_val = SUCCESS;
+ UINT16 minSize;
+ NTFS_DBLK_PTR ddblk = (NTFS_DBLK_PTR)dblk;
+ FS_NAME_Q_ELEM_PTR name_q_elem ;
+
+
+ if ( fname != NULL )
+ {
+ /* Need enough memory for name and terminator */
+ minSize = max( bufMinSize, strsize( fname ) + sizeof(CHAR) );
+ }
+ else
+ {
+ minSize = bufMinSize;
+ }
+
+
+ name_q_elem = FS_AllocPathOrName( fsh, minSize );
+
+ if ( name_q_elem == NULL )
+ {
+ return OUT_OF_MEMORY ;
+ }
+ else
+ {
+ strcpy( name_q_elem->name, fname );
+ name_q_elem->name_size = strsize( name_q_elem->name );
+ ddblk->full_name_ptr = name_q_elem ;
+ }
+
+
+ return ret_val ;
+}
+
+
+
+
+/**/
+/**
+
+ Name: NTFS_ReleaseBlk()
+
+ Description: This function releases any resources connected to a DBLK.
+ For this OS the only resource is the Path connected to the DDB
+
+ Modified: 5/18/1992 10:27:34
+
+ Returns: none
+
+**/
+VOID NTFS_ReleaseBlk(
+FSYS_HAND fsh,
+DBLK_PTR dblk )
+{
+ NTFS_DBLK_PTR ddblk ;
+
+ fsh ;
+
+ ddblk = (NTFS_DBLK_PTR)dblk ;
+
+ FS_ReleaseOSPathOrNameInDBLK( fsh, dblk ) ;
+
+ if ( ddblk->full_name_ptr != NULL ) {
+ if ( RemoveQueueElem( &fsh->in_use_name_q,
+ &ddblk->full_name_ptr->q ) == SUCCESS ) {
+
+ EnQueueElem( &fsh->avail_name_q,
+ &ddblk->full_name_ptr->q,
+ FALSE ) ;
+ }
+ ddblk->full_name_ptr = NULL ;
+ }
+}
+
+INT16 NTFS_DupBlk( FSYS_HAND fsh, DBLK_PTR db_org, DBLK_PTR db_dup )
+{
+ NTFS_DBLK_PTR ddblk = (NTFS_DBLK_PTR)db_org ;
+
+ *db_dup = *db_org ;
+
+ if ( FS_SetupOSPathOrNameInDBLK( fsh,
+ db_dup,
+ (BYTE_PTR)db_org->com.os_name->name,
+ db_org->com.os_name->name_size ) == SUCCESS ) {
+
+
+ return NTFS_SetupPathInDDB( fsh,
+ db_dup,
+ ddblk->full_name_ptr->name,
+ NULL,
+ ddblk->full_name_ptr->alloc_size ) ;
+ } else {
+
+ return (OUT_OF_MEMORY) ;
+ }
+
+}
+
diff --git a/private/utils/ntbackup/src/tgetspec.c b/private/utils/ntbackup/src/tgetspec.c
new file mode 100644
index 000000000..5c92f890f
--- /dev/null
+++ b/private/utils/ntbackup/src/tgetspec.c
@@ -0,0 +1,211 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tgetspec.c
+
+ Description: This file contains code to return DBLKS for the regestry
+ files. The object returned will be:
+ DDB -> <REGESTRY>
+
+
+ $Log: M:/LOGFILES/TGETSPEC.C_V $
+
+ Rev 1.10 04 Jan 1994 11:09:38 BARRY
+With the change in the calls for Mac name support, the pattern "*."
+no longer matches files with no extension (registry files). Fixed
+this problem by scanning all files and checking the names.
+
+
+ Rev 1.9 14 Jun 1993 18:12:22 BARRY
+Fixed last edit that required both backup/restore rights to backup registry
+
+ Rev 1.8 11 Jun 1993 14:21:36 BARRY
+Replace old PromptForBindery with new feature bits.
+
+ Rev 1.7 07 Dec 1992 14:17:02 STEVEN
+updates from msoft
+
+ Rev 1.6 10 Nov 1992 08:20:50 STEVEN
+removed path and name from dblk now use full_name_ptr
+
+ Rev 1.5 28 Oct 1992 10:30:42 STEVEN
+add registry support
+
+ Rev 1.4 24 Jul 1992 15:55:24 STEVEN
+fix warnings
+
+ Rev 1.2 27 May 1992 18:50:16 STEVEN
+registry api is not implemented
+
+ Rev 1.1 21 May 1992 16:45:18 STEVEN
+added support for special files
+
+ Rev 1.0 21 May 1992 13:51:22 STEVEN
+Initial revision.
+
+**/
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "stdmath.h"
+#include "msassert.h"
+
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "ntfsdblk.h"
+#include "ntfs_fs.h"
+
+/**/
+
+/**
+
+ Name: NTFS_GetSpecDBLKS()
+
+ Description: This function is used to return the control blocks for
+ the NTFS regestry. The CBLKs returned are:
+ DDB - <REGISTRY>
+
+ Modified: 5/21/1992 15:25:12
+
+ Returns: Error codes:
+ FS_NO_MORE
+ SUCCESS
+
+ Notes: We need to add code to exclude these files from regular
+ processing.
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 NTFS_GetSpecDBLKS( FSYS_HAND fsh,
+ DBLK_PTR dblk,
+ INT32 *index )
+{
+ INT16 ret_val = SUCCESS ;
+ NTFS_DBLK_PTR ddblk = (NTFS_DBLK_PTR)dblk;
+ GENERIC_DLE_PTR dle = fsh->attached_dle ;
+
+ // special files are now handled differently for NtBackup
+
+ return FS_NO_MORE ;
+
+
+ /* does this device have special files */
+ if ( DLE_HasFeatures( dle, DLE_FEAT_BKUP_SPECIAL_FILES ) == FALSE )
+ {
+ return FS_NO_MORE ;
+ }
+
+
+ switch ( (INT16)*index ) {
+
+ case 0:
+ case 1:
+ {
+ CHAR_PTR reg_path ;
+ CHAR_PTR path_ptr ;
+ FS_NAME_Q_ELEM_PTR name_q_elem ;
+ INT16 psize ;
+
+ *index = 2 ;
+
+ /* return DDB for system\config directory */
+ reg_path = NTFS_GetRegistryPath( dle ) ;
+
+ path_ptr = reg_path + strlen( dle->device_name ) + 1 ;
+
+ psize = strsize( path_ptr ) ;
+
+ name_q_elem = FS_AllocPathOrName( fsh, psize ) ;
+
+ if ( name_q_elem == NULL ) {
+ *index = 4 ;
+ ret_val = OUT_OF_MEMORY ;
+ break ;
+
+ }
+
+ ddblk->full_name_ptr = name_q_elem ;
+ ddblk->blk_type = DDB_ID ;
+
+ strcpy( ddblk->full_name_ptr ->name, path_ptr ) ;
+
+ ddblk->full_name_ptr->name_size = psize ;
+
+ ddblk->os_info_complete = FALSE ;
+
+ ret_val = NTFS_GetObjInfo( fsh, dblk ) ;
+
+ if ( ret_val != SUCCESS )
+ {
+ ret_val = FS_NO_MORE ;
+ *index = 4 ;
+ }
+ }
+ break ;
+
+ case 2:
+ {
+ CHAR_PTR sname = dle->info.ntfs->mac_name_syntax ? TEXT("*.*") : TEXT("*.");
+
+ *index = 3 ;
+
+ /* make sure current dir is registry dir */
+
+ if ( stricmp( NTFS_GetRegistryPath(dle) + strlen( dle->device_name ),
+ fsh->cur_dir ) )
+ {
+ ret_val = FS_NO_MORE ;
+ *index = 4 ;
+ }
+
+ ret_val = NTFS_FindFirst( fsh, dblk, sname, OBJECT_ALL ) ;
+
+ while ( ( ret_val == SUCCESS ) &&
+ (( dblk->blk_type != FDB_ID ) ||
+ ( strchr( ddblk->full_name_ptr->name, TEXT('.') ) != NULL )) )
+ {
+ ret_val = NTFS_FindNext( fsh, dblk ) ;
+ }
+
+ if ( ret_val != SUCCESS )
+ {
+ ret_val = FS_NO_MORE ;
+ *index = 4 ;
+ }
+ }
+ break ;
+
+ case 3:
+
+ /* return FS_FindNext( ) */
+ do
+ {
+ ret_val = NTFS_FindNext( fsh, dblk ) ;
+ }
+ while ( ( ret_val == SUCCESS ) &&
+ (( dblk->blk_type != FDB_ID ) ||
+ ( strchr( ddblk->full_name_ptr->name, TEXT('.') ) != NULL )) );
+
+ if ( ret_val != SUCCESS )
+ {
+ ret_val = FS_NO_MORE ;
+ *index = 4 ;
+ }
+ break ;
+
+ case 4:
+ default:
+ ret_val = FS_NO_MORE ;
+ break ;
+
+ }
+
+ return ret_val ;
+}
diff --git a/private/utils/ntbackup/src/timers.c b/private/utils/ntbackup/src/timers.c
new file mode 100644
index 000000000..48ad04939
--- /dev/null
+++ b/private/utils/ntbackup/src/timers.c
@@ -0,0 +1,511 @@
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: timers.c
+
+ Description: This file contains the functions for UI poll drive.
+
+ $Log: G:\UI\LOGFILES\TIMERS.C_V $
+
+ Rev 1.15.1.0 24 May 1994 12:22:12 Glenn
+Added frame window handle to set and kill timer.
+
+ Rev 1.15 28 Jul 1993 18:34:52 MARINA
+enable c++
+
+ Rev 1.14 18 May 1993 09:49:00 Aaron
+Fixed comments and return values for WM_InitTimer
+
+ Rev 1.13 18 Nov 1992 11:43:30 GLENN
+Increased the speed as an enhancement for the callers.
+
+ Rev 1.12 07 Oct 1992 15:11:36 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.11 04 Oct 1992 19:41:18 DAVEV
+Unicode Awk pass
+
+ Rev 1.10 17 Aug 1992 13:24:20 DAVEV
+MikeP's changes at Microsoft
+
+ Rev 1.9 28 Jul 1992 14:45:26 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.8 29 May 1992 15:59:24 JOHNWT
+PCH updates
+
+ Rev 1.7 12 May 1992 21:21:20 MIKEP
+NT pass 1
+
+ Rev 1.6 11 Feb 1992 17:30:38 GLENN
+Fixed no prototype warning.
+
+ Rev 1.5 31 Jan 1992 15:04:24 GLENN
+Added reset logic to the deinit. Added mw to module-wide variables.
+
+ Rev 1.4 19 Dec 1991 15:24:20 GLENN
+Added windows.h
+
+ Rev 1.3 12 Dec 1991 17:08:12 DAVEV
+16/32 bit port -2nd pass
+
+ Rev 1.2 02 Dec 1991 17:52:20 DAVEV
+16/32 bit Windows port changes
+
+ Rev 1.1 27 Nov 1991 12:11:12 GLENN
+Clean-up.
+
+ Rev 1.0 20 Nov 1991 19:32:38 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+#define MAX_TIMERS 16 // Up to 16 -- the number of bits in a WORD
+#define ALL_TIMERS_USED 0xFFFF // All timers used bitmask
+
+typedef struct TIMERTABLE {
+
+ PF_VOID pfnCallBack;
+ INT nTimerLength;
+ INT nTimeRemaining;
+
+} TIMERTABLE;
+
+
+static TIMERTABLE TimerTable [ MAX_TIMERS ];
+
+static WORD mwwTimerMask;
+static INT mwnUsedTimers;
+static INT mwnUnusedTicks = 0;
+static HTIMER mwhMasterTimerInst = 0;
+static BOOL mwfTimerInUse = FALSE;
+static INT mwnBaseFrequency = TIMER_BASE;
+static INT mwnMasterFrequency = TIMER_FREQUENCY;
+static WNDPROC fnTimerInst = (WNDPROC)NULL;
+
+static FARPROC pfnTimerCallBack ;
+
+// FUNCTION PROTOTYPES
+
+static BOOL WM_ChangeMasterFrequency ( INT );
+static INT WM_CalculateFrequency ( INT );
+static UINT APIENTRY WM_TimerFunct ( HWND, MSGID, MP1, MP2 );
+
+/******************************************************************************
+
+ Name: WM_InitTimer()
+
+ Description:
+
+ Returns: TRUE if successful, FALSE otherwise
+
+******************************************************************************/
+
+BOOL WM_InitTimer ( VOID )
+
+{
+ INT i;
+
+ if ( mwhMasterTimerInst ) {
+ return FALSE;
+ }
+
+ // Clear out the timer in use flag, the timer mask and callback table.
+
+ mwfTimerInUse = FALSE;
+ mwwTimerMask = 0;
+ mwnUsedTimers = 0;
+
+ for ( i = 0; i < MAX_TIMERS; i++ ) {
+
+ TimerTable[i].pfnCallBack = (PF_VOID)0;
+ TimerTable[i].nTimerLength = 0;
+ TimerTable[i].nTimeRemaining = 0;
+ }
+
+ // Create a timer call-back function instance if one has not been created.
+
+ if ( ! fnTimerInst ) {
+
+ fnTimerInst = (WNDPROC)MakeProcInstance ( (FARPROC)WM_TimerFunct, ghInst );
+ }
+
+ // Start the master timer.
+
+ mwhMasterTimerInst = SetTimer ( ghWndFrame,
+ (INT)1,
+ mwnMasterFrequency,
+ (TIMERPROC)fnTimerInst );
+
+ if ( ! mwhMasterTimerInst ) {
+
+ mwwTimerMask = ALL_TIMERS_USED;
+ }
+
+ return (BOOL)( mwwTimerMask == 0 );
+
+} /* end WM_InitTimer() */
+
+
+/******************************************************************************
+
+ Name: WM_ChangeMasterFrequency()
+
+ Description:
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+static BOOL WM_ChangeMasterFrequency (
+
+INT nFrequency ) // I - the new frequency
+
+{
+ INT i;
+
+ if ( nFrequency == mwnMasterFrequency ) {
+ return TRUE;
+ }
+
+ mwfTimerInUse = TRUE;
+
+ for ( i = 0; i < MAX_TIMERS; i++ ) {
+
+ if ( TimerTable[i].pfnCallBack ) {
+
+ // Reset the values based on the new frequency.
+
+ TimerTable[i].nTimerLength = 0;
+ TimerTable[i].nTimeRemaining = 0;
+ }
+ }
+
+ // Create a timer call-back function instance if one has not been created.
+
+ if ( ! fnTimerInst ) {
+
+ fnTimerInst = (WNDPROC)MakeProcInstance ( (FARPROC)WM_TimerFunct, ghInst );
+ }
+
+ mwnMasterFrequency = nFrequency;
+
+ // Kill the old and start an the new master timer.
+
+ KillTimer ( ghWndFrame, mwhMasterTimerInst );
+
+ mwhMasterTimerInst = SetTimer ( ghWndFrame, (INT)1, mwnMasterFrequency, (TIMERPROC)fnTimerInst );
+
+ if ( ! mwhMasterTimerInst ) {
+
+ mwwTimerMask = ALL_TIMERS_USED;
+ }
+
+ return (BOOL)( ! mwhMasterTimerInst );
+
+} /* end WM_ChangeMasterFrequency() */
+
+
+/******************************************************************************
+
+ Name: WM_DeinitTimer()
+
+ Description:
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+BOOL WM_DeinitTimer ( VOID )
+
+{
+ INT i;
+ BOOL fResult;
+
+ // We can't deinit if there is no timer instance.
+
+ if ( ! mwhMasterTimerInst ) {
+ return FAILURE;
+ }
+
+ // Set the timer in use flag and clear out the timer mask and
+ // callback table.
+
+ mwfTimerInUse = TRUE;
+ mwwTimerMask = 0;
+ mwnUsedTimers = 0;
+
+ for ( i = 0; i < MAX_TIMERS; i++ ) {
+
+ TimerTable[i].pfnCallBack = (PF_VOID)0;
+ TimerTable[i].nTimerLength = 0;
+ TimerTable[i].nTimeRemaining = 0;
+ }
+
+ // Kill the timer.
+
+ fResult = ! KillTimer ( ghWndFrame, mwhMasterTimerInst );
+
+ mwhMasterTimerInst = 0;
+
+ return fResult;
+
+} /* end WM_DeinitTimer() */
+
+
+/******************************************************************************
+
+ Name: WM_HookTimer()
+
+ Description:
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+HTIMER WM_HookTimer (
+
+PF_VOID pfnCallBack,
+INT nFrequency )
+
+{
+ WORD wTempMask = 1;
+ UINT i;
+
+ // If no timer, create one.
+
+ if ( ! mwwTimerMask ) {
+ WM_InitTimer ();
+ }
+
+ nFrequency = WM_CalculateFrequency ( nFrequency );
+
+ if ( mwwTimerMask == ALL_TIMERS_USED ) {
+
+ return INVALID_TIMER_HANDLE;
+ }
+
+ // Stuff the table with the callback function and the number of seconds.
+
+ for ( i = 0; i < MAX_TIMERS; i++ ) {
+
+ // If there is an available timer space, hook it.
+
+ if ( ! ( wTempMask & mwwTimerMask ) ) {
+
+ TimerTable[i].pfnCallBack = pfnCallBack;
+ TimerTable[i].nTimerLength = TimerTable[i].nTimeRemaining = nFrequency;
+ mwnUsedTimers++;
+ break;
+ }
+
+ wTempMask <<= 1;
+ }
+
+ // Set the appropriate bit in the bitmask.
+
+ mwwTimerMask |= wTempMask;
+
+ return (HTIMER)i;
+
+} /* end WM_HookTimer() */
+
+
+/******************************************************************************
+
+ Name: WM_SetTimerFrequency()
+
+ Description: Changes the specified timers frequency.
+
+ Returns: The timer's old frequency.
+
+******************************************************************************/
+
+INT WM_SetTimerFrequency (
+
+HTIMER hTimer, // I - timer handle
+INT nFrequency ) // I - the new frequency
+
+{
+ INT nOldFrequency;
+
+ // If it is an invalid timer handle, bug out.
+
+ if ( hTimer >= MAX_TIMERS || ! ( ( 1 << hTimer ) & mwwTimerMask ) ) {
+ return 0;
+ }
+
+ nOldFrequency = TimerTable[hTimer].nTimerLength;
+
+ mwfTimerInUse = TRUE;
+
+ nFrequency = WM_CalculateFrequency ( nFrequency );
+
+ TimerTable[hTimer].nTimerLength = TimerTable[hTimer].nTimeRemaining = nFrequency;
+
+ mwfTimerInUse = FALSE;
+
+ // Figure out the original callers frequency.
+
+ if ( nOldFrequency < ONE_SECOND ) {
+ nOldFrequency = ( -nOldFrequency );
+ }
+ else {
+ nOldFrequency = nOldFrequency / ONE_SECOND;
+ }
+
+ return nOldFrequency;
+
+} /* end WM_SetTimerFrequency() */
+
+
+/******************************************************************************
+
+ Name: WM_CalculateFrequency()
+
+ Description: Changes the specified timers frequency.
+
+ Returns: The timer's old frequency.
+
+******************************************************************************/
+
+static INT WM_CalculateFrequency (
+
+INT nFrequency ) // I - the new frequency
+
+{
+ if ( ! nFrequency ) {
+ nFrequency++;
+ }
+
+ if ( nFrequency > 0 ) {
+ nFrequency *= ONE_SECOND;
+ }
+ else {
+ nFrequency = abs( nFrequency );
+ }
+
+ return nFrequency;
+
+} /* end WM_CalculateFrequency() */
+
+
+/******************************************************************************
+
+ Name: WM_UnhookTimer()
+
+ Description:
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+BOOL WM_UnhookTimer (
+
+HTIMER i )
+
+{
+ WORD wTempMask = 1;
+
+ // Bug out, if there is no such timer.
+
+ if ( i >= MAX_TIMERS ) {
+ return TRUE;
+ }
+
+ TimerTable[i].pfnCallBack = (PF_VOID)0;
+ TimerTable[i].nTimerLength = 0;
+ TimerTable[i].nTimeRemaining = 0;
+ mwnUsedTimers--;
+
+ // Clear the appropriate bit in the bitmask.
+
+ mwwTimerMask &= ~( wTempMask <<= i );
+
+ return FALSE;
+
+} /* end WM_UnhookTimer() */
+
+
+
+
+// NEVER CALLED DIRECTLY FROM THE APPLICATION,
+// CALLED INTERNALLY AS A FUNCTION INSTANCE BY WINDOWS.
+
+static UINT APIENTRY WM_TimerFunct (
+
+HWND hWnd, // I - NOT USED - REQUIRED FOR WINDOWS
+MSGID msg, // I - NOT USED - REQUIRED FOR WINDOWS
+MP1 mp1, // I - NOT USED - REQUIRED FOR WINDOWS
+MP2 mp2 ) // I - first parameter - contains the time
+
+{
+ DWORD dwTime = (DWORD) mp2;
+
+ UNREFERENCED_PARAMETER ( hWnd );
+ UNREFERENCED_PARAMETER ( msg );
+ UNREFERENCED_PARAMETER ( mp1 );
+
+ // Make sure that we are not already in this timer function.
+
+ if ( mwfTimerInUse ) {
+ return 0;
+ }
+
+ mwfTimerInUse = TRUE;
+
+ // Determine if there is a function to call back.
+
+ if ( mwwTimerMask ) {
+
+ // The following is done for speed.
+
+ register INT i;
+ register WORD wTempMask = mwwTimerMask;
+
+ for ( i = 0; wTempMask; i++ ) {
+
+ if ( wTempMask & 0x01 ) {
+
+ if ( --TimerTable[i].nTimeRemaining <= 0 ) {
+
+ pfnTimerCallBack = (FARPROC)(TimerTable[i].pfnCallBack);
+
+ pfnTimerCallBack ( );
+
+ TimerTable[i].nTimeRemaining = TimerTable[i].nTimerLength;
+ }
+ }
+
+ wTempMask >>= 1;
+ }
+
+ }
+ else {
+
+ // If we have had a timer going without a hook for more than
+ // 10 seconds, we probably don't need it.
+
+ mwnUnusedTicks++;
+
+ if ( mwnUnusedTicks > ( mwnMasterFrequency * TEN_SECONDS ) ) {
+
+ WM_DeinitTimer ();
+ mwnUnusedTicks = 0;
+ return 0;
+ }
+
+ }
+
+ mwfTimerInUse = FALSE;
+
+ return 0;
+
+} /* end WM_TimerFunct() */
diff --git a/private/utils/ntbackup/src/tinitfs.c b/private/utils/ntbackup/src/tinitfs.c
new file mode 100644
index 000000000..136014698
--- /dev/null
+++ b/private/utils/ntbackup/src/tinitfs.c
@@ -0,0 +1,973 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tinitfs.c
+
+ Description: This file contains code to add NTFS dles to the
+ drive list.
+
+ $Log: N:/LOGFILES/TINITFS.C_V $
+
+ Rev 1.56.1.13 16 Jun 1994 15:40:52 STEVEN
+setup CDFS drives as readonly
+
+ Rev 1.56.1.12 26 Apr 1994 19:02:48 STEVEN
+fix floppy drive problem
+
+ Rev 1.56.1.11 20 Apr 1994 12:32:16 GREGG
+Fixed memory leak.
+
+ Rev 1.56.1.10 08 Feb 1994 18:52:04 STEVEN
+trust the fsize returned from the FS
+
+ Rev 1.56.1.9 01 Feb 1994 12:28:30 STEVEN
+when checking flopies share the open
+
+ Rev 1.56.1.8 31 Jan 1994 12:22:40 BARRY
+Make CDROMs and net drives work
+
+ Rev 1.56.1.7 25 Jan 1994 19:46:24 STEVEN
+add support for removeable media
+
+ Rev 1.56.1.6 20 Jan 1994 10:02:46 BARRY
+Change thread wait from sem to thread handle; increased wait time
+
+ Rev 1.56.1.5 19 Jan 1994 17:08:32 BARRY
+Add CDROM DLEs
+
+ Rev 1.56.1.4 14 Jan 1994 16:00:22 BARRY
+Create DLEs for removable drives
+
+ Rev 1.56.1.3 04 Jan 1994 11:04:52 BARRY
+Use flags from OS to set up feature bits where possible. Create DLEs
+for CD-ROM drives. Added Init/Deinit functions that set up the temp
+file name stuff.
+
+ Rev 1.56.1.2 02 Dec 1993 00:47:34 GREGG
+Barry's fixes for NTFS_SupportMacSyntax.
+
+ Rev 1.56.1.1 04 Nov 1993 16:04:08 STEVEN
+changes from WA
+
+ Rev 1.56 29 Sep 1993 18:26:06 BARRY
+Unicode fix
+
+ Rev 1.55 24 Aug 1993 19:42:38 STEVEN
+fix no default drive bug
+
+ Rev 1.54 18 Aug 1993 15:03:06 STEVEN
+fix unicode bug
+
+ Rev 1.53 12 Aug 1993 16:24:20 BARRY
+Make a DLE even if access is denied
+
+ Rev 1.52 04 Aug 1993 18:51:34 BARRY
+#ifdef the dle tossing based on product.
+
+ Rev 1.51 26 Jul 1993 17:05:04 STEVEN
+fixe restore active file with registry
+
+ Rev 1.50 19 Jul 1993 10:17:30 BARRY
+The UI wants a DLE thrown away even if BSDs are pointing to it.
+
+ Rev 1.49 16 Jun 1993 10:47:14 CARLS
+force the current directory to upper case
+
+ Rev 1.48 11 Jun 1993 14:20:08 BARRY
+Separated backup user and restore user into two separate flags.
+
+ Rev 1.47 07 Jun 1993 14:54:58 STEVEN
+need to assert the restore priv
+
+ Rev 1.46 03 Jun 1993 18:58:20 BARRY
+Need not have both backup and restore priviliges to backup registry.
+
+ Rev 1.45 03 Jun 1993 14:51:18 STEVEN
+added reconition for HPFS386
+
+ Rev 1.44 20 May 1993 17:22:32 BARRY
+[Steve's change] Only get user name once.
+
+ Rev 1.43 15 May 1993 16:30:14 BARRY
+Don't throw away DLEs that have attach/bsd counts.
+
+ Rev 1.42 14 May 1993 16:08:46 BARRY
+Assume that all non-FAT drives are case preserving.
+
+ Rev 1.41 16 Apr 1993 13:44:40 MIKEP
+add case feature bit
+
+ Rev 1.40 04 Apr 1993 17:09:24 BARRY
+Fixed default DLE bug.
+
+ Rev 1.39 29 Mar 1993 14:43:36 TIMN
+Added code to assign default DLE
+
+ Rev 1.38 24 Mar 1993 11:27:58 STEVEN
+if username is bad use no name
+
+ Rev 1.37 17 Mar 1993 16:03:30 BARRY
+Removed IsDriveWriteable code.
+
+ Rev 1.36 14 Mar 1993 18:30:22 BARRY
+Fix warning.
+
+ Rev 1.35 11 Mar 1993 14:02:56 BARRY
+Put in temporary kludge to determine if device is read-only.
+
+ Rev 1.34 26 Feb 1993 10:43:30 STEVEN
+need to set access date feature bit
+
+ Rev 1.33 27 Jan 1993 13:51:06 STEVEN
+updates from msoft
+
+ Rev 1.32 15 Jan 1993 13:19:18 BARRY
+added support for new error messages and backup priviladge
+
+ Rev 1.31 14 Jan 1993 13:33:48 STEVEN
+added stream_id to error message
+
+ Rev 1.30 30 Dec 1992 11:04:42 STEVEN
+fixed registry support to check for backup_user priviladge.
+
+ Rev 1.29 29 Dec 1992 17:21:36 STEVEN
+fix multi-thread so it calls ThreadSwitch
+
+ Rev 1.28 09 Dec 1992 14:19:28 STEVEN
+fix user_name_size
+
+ Rev 1.27 16 Nov 1992 13:52:54 STEVEN
+more unicode fixes
+
+ Rev 1.26 13 Nov 1992 15:57:56 STEVEN
+fixes for unicode
+
+ Rev 1.25 11 Nov 1992 22:26:38 GREGG
+Unicodeized literals.
+
+ Rev 1.24 04 Nov 1992 17:59:04 BARRY
+Added fs_name to dle.
+
+ Rev 1.23 21 Oct 1992 12:40:56 STEVEN
+setup feature bits
+
+ Rev 1.22 20 Oct 1992 14:32:44 STEVEN
+Registry path should include drive
+
+ Rev 1.21 07 Oct 1992 14:01:06 STEVEN
+added registry stuff
+
+ Rev 1.20 05 Oct 1992 15:04:40 STEVEN
+add registry call to NT's initfsys
+
+ Rev 1.19 05 Oct 1992 13:26:44 DAVEV
+Unicode strlen verification
+
+ Rev 1.18 08 Sep 1992 16:09:00 STEVEN
+dev_name for Net call can not have \
+
+ Rev 1.17 03 Sep 1992 17:06:30 STEVEN
+add support for volume name
+
+ Rev 1.15 20 Aug 1992 13:53:30 BURT
+fix warnings
+
+ Rev 1.14 17 Aug 1992 15:46:44 STEVEN
+fix warnings
+
+ Rev 1.13 23 Jul 1992 16:43:18 STEVEN
+fix warnings
+
+ Rev 1.12 23 Jul 1992 12:36:42 STEVEN
+fix warnings
+
+ Rev 1.11 21 Jul 1992 14:25:32 STEVEN
+added support for user name in VCB
+
+ Rev 1.10 16 Jul 1992 11:26:46 STEVEN
+fix typo
+
+ Rev 1.9 16 Jul 1992 08:58:52 STEVEN
+fix default drive code
+
+ Rev 1.8 09 Jul 1992 13:58:20 STEVEN
+BE_Unicode updates
+
+ Rev 1.7 02 Jul 1992 10:32:38 MIKEP
+add remote bit to dle features
+
+ Rev 1.6 25 Jun 1992 11:24:12 STEVEN
+do not support CDROMS
+
+ Rev 1.5 12 Jun 1992 15:18:46 STEVEN
+remove floppies
+
+ Rev 1.4 09 Jun 1992 14:54:38 BURT
+Use changes made in Redmond
+
+ Rev 1.3 21 May 1992 13:50:54 STEVEN
+more long path stuff
+
+ Rev 1.2 05 Feb 1992 15:47:44 STEVEN
+added support for FindHandle Queue
+
+ Rev 1.1 23 Jan 1992 13:18:30 STEVEN
+
+ Rev 1.0 17 Jan 1992 17:50:12 STEVEN
+Initial revision.
+
+**/
+#include <windows.h>
+#include <winioctl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "stdwcs.h"
+
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "ntfs_fs.h"
+#include "gen_fs.h"
+
+BOOLEAN NTFS_SupportMacSyntax( GENERIC_DLE_PTR dle );
+
+static VOID AddNTFS_DLE( DLE_HAND hand,
+ CHAR drive,
+ UINT32 type,
+ BOOLEAN backup_user,
+ BOOLEAN restore_user,
+ GENERIC_DLE_PTR *current_dle );
+
+static VOID RemoveNTFS_DLE( DLE_HAND hand, CHAR drive ) ;
+
+BOOL MAYN_GetUserName (
+ LPSTR *pUser,
+ LPDWORD pcbUser
+ );
+
+typedef struct THREAD_PARMS {
+ DLE_HAND dle_hand;
+} THREAD_PARMS, *THREAD_PARMS_PTR ;
+
+DWORD NTFS_ThreadFindDrives( THREAD_PARMS_PTR thread_parms_ptr ) ;
+
+#define MAX_NAME_SIZE 200
+
+/**/
+/**
+
+ Name: AddDLEsForNTFS()
+
+ Description: This function creates a DLE for each mapped NTFS drive.
+
+ Modified: 12/2/1991 16:29:59
+
+ Returns: none
+
+ Declaration:
+**/
+INT16 NTFS_FindDrives( DLE_HAND hand, BE_CFG_PTR cfg, UINT32 fsys_mask )
+{
+ HANDLE hThread ;
+ DWORD pthread_id ;
+ THREAD_PARMS thread_parms ;
+
+ (VOID)cfg ;
+ (VOID)fsys_mask ;
+
+ thread_parms.dle_hand = hand ;
+
+ hThread = CreateThread( NULL,
+ 0,
+ NTFS_ThreadFindDrives,
+ &thread_parms,
+ 0,
+ &pthread_id ) ;
+
+ if ( hThread != NULL )
+ {
+ while ( WaitForSingleObject( hThread, 100 ) == WAIT_TIMEOUT )
+ {
+ ThreadSwitch( ) ;
+ }
+ CloseHandle( hThread ) ;
+ }
+ else
+ {
+ NTFS_ThreadFindDrives( &thread_parms ) ;
+ }
+ return SUCCESS ;
+}
+
+DWORD NTFS_ThreadFindDrives( THREAD_PARMS_PTR thread_parms_ptr )
+{
+ CHAR path[]=TEXT("C:\\") ;
+ CHAR drive ;
+ UINT32 type ;
+ DLE_HAND hand ;
+ LONG prev_val ;
+ BOOLEAN backup_user;
+ BOOLEAN restore_user;
+ CHAR cwd[ MAX_PATH ] ; // current working directory buffer
+ DWORD cwdSize = MAX_PATH ; // size of cwd data less '\0'
+ GENERIC_DLE_PTR pCurrentDLE ; // ptr to current DLE
+
+ hand = thread_parms_ptr->dle_hand ;
+
+ backup_user = (REG_AssertBackupPrivilege() == SUCCESS);
+ restore_user = (REG_AssertRestorePrivilege() == SUCCESS);
+
+ /* get the current working drive */
+ cwdSize = GetCurrentDirectory( cwdSize, cwd ) ;
+
+ if ( cwdSize == 0 ) {
+ // what to do if we couldn't get the drive letter
+ cwd[ 0 ] = TEXT('C') ;
+ } else {
+ strupr( cwd ) ;
+ }
+
+
+ for ( drive = TEXT('A'); drive <= TEXT('Z'); drive++ ) {
+
+ *path = drive ;
+ type = GetDriveType( path ) ;
+
+ if ( type != 1 ) { /* 1 specifies does not exist */
+ AddNTFS_DLE( hand,
+ drive,
+ type,
+ backup_user,
+ restore_user,
+ &pCurrentDLE );
+
+ // is this dle the default one
+ if ( ( pCurrentDLE != NULL ) && ( drive == cwd[ 0 ] ) ) {
+ hand->default_drv = pCurrentDLE ;
+ } else if( hand->default_drv == NULL ) {
+ hand->default_drv = pCurrentDLE ;
+ }
+ } else {
+
+ RemoveNTFS_DLE( hand, drive ) ;
+ }
+ }
+
+ return SUCCESS ;
+}
+/**/
+/**
+
+ Name: AddDLEsForNTFS()
+
+ Description: This function creates a DLE for each mapped NTFS drive.
+
+ Modified: 12/2/1991 16:29:59
+
+ Returns: none
+
+ Declaration:
+**/
+static VOID AddNTFS_DLE(
+DLE_HAND hand, /* I - Handle to DLE list */
+CHAR drive, /* I - drive letter for dle */
+UINT32 type,
+BOOLEAN backup_user,
+BOOLEAN restore_user,
+GENERIC_DLE_PTR *pCurrentDLE /* O - current dle */ )
+{
+ GENERIC_DLE_PTR dle ;
+ static LPSTR user_name = NULL ;
+ INT user_name_size = MAX_NAME_SIZE ;
+ CHAR machine[ MAX_NAME_SIZE ] = { TEXT('\0') };
+
+ CHAR vol_name[MAX_NAME_SIZE] = {TEXT('\0')} ;
+ CHAR fs_name[MAX_NAME_SIZE] = {TEXT('\0')} ;
+ CHAR dev_name[] = TEXT("C:\0");
+ UINT32 fsize ;
+ UINT32 sflags ;
+ BOOLEAN remote_flag;
+ DWORD name_size ;
+ UINT errorMode;
+
+ *pCurrentDLE = NULL ;
+
+ remote_flag = (type == DRIVE_REMOTE);
+ errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+
+ switch( type ) {
+
+ // This is a kludge to allow Bernoullis, etc., but discard
+ // floppies.
+ case DRIVE_REMOVABLE:
+ case DRIVE_CDROM:
+ {
+ INT status ;
+ CHAR buffer[200] ;
+ HANDLE deviceHandle ;
+ DWORD dummy;
+
+ strcpy( buffer, TEXT("\\\\.\\C:") ) ;
+ buffer[4] = drive ;
+
+ deviceHandle = CreateFile( buffer,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL ) ;
+
+ status = DeviceIoControl( deviceHandle, IOCTL_DISK_CHECK_VERIFY,
+ NULL, 0, NULL, 0, &dummy, NULL ) ;
+
+
+ CloseHandle( deviceHandle );
+
+
+ if ( !status ) {
+ RemoveNTFS_DLE( hand, drive ) ;
+ errorMode = SetErrorMode(errorMode);
+ return ;
+ }
+
+ }
+
+ case DRIVE_REMOTE:
+ case DRIVE_FIXED:
+ case DRIVE_RAMDISK:
+ dev_name[0] = drive ;
+
+ if ( DLE_FindByName( hand, dev_name, ANY_DRIVE_TYPE, &dle ) == SUCCESS ) {
+
+ if ( dle->attach_count ) {
+ errorMode = SetErrorMode(errorMode);
+ return ;
+ } else {
+ NTFS_RemoveDLE( dle ) ;
+ }
+ }
+
+ dev_name[2] = TEXT('\\') ;
+
+ if ( GetVolumeInformation( dev_name,
+ vol_name,
+ MAX_NAME_SIZE,
+ NULL,
+ &fsize,
+ &sflags,
+ fs_name,
+ MAX_NAME_SIZE ) == FALSE )
+ {
+ DWORD error = GetLastError( );
+
+ if ( error == ERROR_ACCESS_DENIED )
+ {
+ /*
+ * Kludge so the UI can show a device, even though
+ * they'll never be able to do anything with it.
+ */
+
+ fsize = 12;
+ sflags = 0;
+ vol_name[0] = TEXT( '\0' );
+ strcpy( fs_name, TEXT("FAT") );
+
+ }
+ else
+ {
+ errorMode = SetErrorMode(errorMode);
+ return ;
+ }
+ }
+
+ if ( !strcmp( fs_name, TEXT("RAW") ) ) {
+ errorMode = SetErrorMode(errorMode);
+ return ;
+ }
+
+ if ( remote_flag ) {
+ name_size = MAX_NAME_SIZE ;
+
+ dev_name[2] = TEXT('\0') ;
+ if ( WNetGetConnection( dev_name,
+ vol_name,
+ (LPDWORD)&name_size ) ) {
+
+ vol_name[0] = TEXT('\0') ;
+ } else {
+
+ CHAR *s ;
+
+ strcpy( machine, vol_name );
+ s = machine;
+ s += 2;
+ while ( *s && *s != TEXT('\\') ) s++;
+ *s = TEXT( '\0' );
+ }
+ }
+ break ;
+
+ default:
+ errorMode = SetErrorMode(errorMode);
+ return ;
+ }
+
+ errorMode = SetErrorMode(errorMode);
+
+ // Make a string "NtWins/Kevinp"
+
+ if ( user_name || MAYN_GetUserName( (LPSTR*)&user_name, (LPDWORD)&user_name_size ) ) {
+
+ user_name_size = strsize( user_name ) ;
+
+ } else {
+ user_name_size = sizeof(CHAR) ;
+ user_name = TEXT("\0") ;
+ }
+
+ /* Allocate space for DLE and device_name string */
+
+ dle = calloc ( 1, sizeof( GENERIC_DLE ) +
+ sizeof( struct LOCAL_NTFS_DRV_DLE_INFO ) +
+ user_name_size ) ;
+
+ if ( dle != NULL ) {
+
+ dle->device_name = calloc( 4, sizeof(CHAR ) ) ;
+
+ if ( dle->device_name == NULL ) {
+ free( dle ) ;
+ dle = NULL ;
+
+ } else {
+ dle->info.ntfs = (LOCAL_NTFS_DRV_DLE_INFO_PTR)(dle + 1) ;
+ dle->info.ntfs->registry_path_size = MAX_NAME_SIZE * sizeof(CHAR) ;
+ dle->info.ntfs->registry_path = calloc( 1,
+ dle->info.ntfs->registry_path_size ) ;
+
+ if ( dle->info.ntfs->registry_path == NULL ) {
+ free( dle->device_name ) ;
+ free( dle ) ;
+ dle = NULL ;
+
+ }
+ }
+ }
+
+ if ( dle != NULL ) {
+
+ /* Since memory was allocated with calloc, it is already */
+ /* initialized to zero. Therefore initializations to zero */
+ /* are not necessary. */
+
+ InitQElem( &(dle->q) ) ;
+ dle->handle = hand ;
+ /* dle->parent = NULL ; */
+ dle->type = LOCAL_NTFS_DRV ;
+ dle->path_delim = TEXT('\\') ;
+ /* dle->pswd_required = FALSE */
+ /* dle->pswd_saved = FALSE ; */
+ /* dle->attach_count = 0 ; */
+ /* dle->bsd_use_count = 0 ; */
+ /* dle->dynamic_info = FALSE ; */
+ dle->device_name[0] = drive ;
+ dle->device_name[1] = TEXT(':') ;
+ /* dle->device_name[2] = TEXT('\0'); */
+
+ dle->feature_bits = DLE_FEAT_MAPPED_DRIVE ;
+
+ if ( remote_flag ) {
+ dle->feature_bits |= DLE_FEAT_REMOTE_DRIVE;
+ }
+
+ dle->device_name_leng = strsize( dle->device_name ) ; // 8/20/92 BBB
+
+ if ( *vol_name != TEXT('\0') ) {
+ dle->info.ntfs->volume_label = calloc( 1, strsize(vol_name) ) ;
+ }
+
+ if ( dle->info.ntfs->volume_label != NULL ) {
+ strcpy (dle->info.ntfs->volume_label, vol_name ) ;
+ }
+
+ if ( (dle->info.ntfs->fs_name = calloc( 1, strsize( fs_name ))) != NULL )
+ {
+ strcpy( dle->info.ntfs->fs_name, fs_name );
+ }
+
+ dle->info.ntfs->fname_leng = (UINT16)fsize ;
+ dle->info.ntfs->vol_flags = sflags ;
+
+
+ /*
+ * The sflags we got from the GetVolumeInfo call above
+ * tell us a little about the FS. Namely, if it's case
+ * preserving, if it's case sensitive, and if it supports
+ * Unicode.
+ */
+
+ if ( strcmp( fs_name, TEXT("FAT") ) ) { // force FAT to not case preserved
+
+ dle->feature_bits |= (sflags & FS_CASE_IS_PRESERVED)
+ ? DLE_FEAT_CASE_PRESERVING
+ : 0;
+ }
+
+ dle->feature_bits |= (sflags & FS_CASE_SENSITIVE)
+ ? DLE_FEAT_CASE_SENSITIVE
+ : 0;
+
+ dle->feature_bits |= (sflags & FS_UNICODE_STORED_ON_DISK)
+ ? DLE_FEAT_UNICODE_NAMES
+ : 0;
+
+ if ( !strcmp( fs_name, TEXT("NTFS") ) )
+ {
+ dle->feature_bits |= DLE_FEAT_ACCESS_DATE |
+ DLE_FEAT_DATA_SECURITY;
+ }
+ else if ( !strcmp( fs_name, TEXT("HPFS") ) ||
+ !strcmp( fs_name, TEXT("HPFS386") ) )
+ {
+ dle->feature_bits |= DLE_FEAT_ACCESS_DATE;
+ }
+
+ dle->info.ntfs->drive = dle->device_name[0] ;
+
+ strcpy( dle->info.ntfs->user_name, user_name ) ;
+
+ dle->user_name = dle->info.ntfs->user_name ;
+ dle->user_name_leng = strsize( dle->info.ntfs->user_name ) ;
+ if ( dle->user_name == TEXT('\0') ) {
+ dle->user_name_leng = 0 ;
+ }
+
+ strcpy( dle->info.ntfs->registry_path, dle->device_name ) ;
+ dle->info.ntfs->registry_path_size -= strsize( dle->device_name ) ;
+ REG_GetRegistryPath( machine,
+ drive,
+ dle->info.ntfs->registry_path + strlen( dle->device_name ),
+ &(dle->info.ntfs->registry_path_size) ) ;
+
+ if ( strcmp( fs_name, TEXT("CDFS") ) ) { /* CDFS drives are not writable */
+ dle->dle_writeable = TRUE;
+ }
+
+ dle->info.ntfs->LastSysRegPath = NULL ;
+
+ if ( dle->info.ntfs->registry_path_size != 0 ) {
+
+ if ( backup_user ) {
+ dle->feature_bits |= DLE_FEAT_BKUP_SPECIAL_FILES ;
+ }
+
+ if ( restore_user ) {
+ dle->feature_bits |= DLE_FEAT_REST_SPECIAL_FILES ;
+ }
+
+ dle->info.ntfs->registry_path_size = strsize( dle->info.ntfs->registry_path ) ;
+ } else {
+ free( dle->info.ntfs->registry_path ) ;
+ dle->info.ntfs->registry_path = NULL ;
+ dle->info.ntfs->registry_path_size = 0 ;
+ }
+
+ DLE_QueueInsert( hand, dle ) ;
+
+ dle->info.ntfs->mac_name_syntax = NTFS_SupportMacSyntax( dle ) ;
+
+ }
+
+ /* assign current dle */
+ *pCurrentDLE = dle ;
+
+}
+
+static VOID RemoveNTFS_DLE(
+DLE_HAND hand, /* I - Handle to DLE list */
+CHAR drive) /* I - drive letter for dle */
+{
+ GENERIC_DLE_PTR dle ;
+ CHAR dev_name[] = { TEXT('A'), TEXT(':'), TEXT('\0') } ;
+
+ dev_name[0] = drive ;
+
+ DLE_FindByName( hand, dev_name, ANY_DRIVE_TYPE, &dle ) ;
+
+ if ( dle != NULL )
+ {
+ msassert( dle->parent == NULL ) ;
+
+ /* Don't remove DLEs that are busy. */
+ if ( dle->attach_count == 0 )
+ {
+ RemoveQueueElem( &(dle->handle->q_hdr), &(dle->q) ) ;
+
+ free( dle->device_name ) ;
+ free( dle->info.ntfs->registry_path ) ;
+ free( dle->info.ntfs->volume_label ) ;
+ free( dle->info.ntfs->fs_name );
+ free( dle ) ;
+ }
+ }
+
+}
+/**/
+/**
+
+ Name: NTFS_RemoveDLE()
+
+ Description: This function removes the specified DLE ;
+
+ Modified: 12/2/1991 16:29:59
+
+ Returns: none
+
+**/
+VOID NTFS_RemoveDLE( GENERIC_DLE_PTR dle )
+{
+
+ free( dle->device_name ) ;
+ free( dle->info.ntfs->registry_path ) ;
+ free( dle->info.ntfs->volume_label ) ;
+ free( dle->info.ntfs->fs_name );
+
+ GEN_RemoveDLE( dle );
+}
+
+
+BOOL
+MAYN_GetUserName (
+ LPSTR *pUser,
+ LPDWORD pcbUser
+ )
+
+/*++
+
+Routine Description:
+
+ This returns the name of the user currently being impersonated.
+
+Arguments:
+
+ pBuffer - Points to the buffer that is to receive the
+ null-terminated character string containing the user name.
+
+ pcbBuffer - Specifies the maximum size (in characters) of the buffer. This
+ value should be set to at least MAX_USERNAME_LENGTH to allow
+ sufficient room in the buffer for the computer name. The length
+ of the string is returned in pcbBuffer.
+
+Return Value:
+
+ TRUE on success, FALSE on failure.
+
+
+--*/
+{
+ HANDLE TokenHandle;
+ DWORD cbNeeded;
+ TOKEN_USER *pUserToken;
+ BOOL ReturnValue=FALSE;
+ SID_NAME_USE SidNameUse;
+ DWORD cbName ;
+ DWORD cbDomain ;
+ LPSTR pName ;
+ LPSTR pDomain ;
+
+ if (!OpenThreadToken(GetCurrentThread(),
+ TOKEN_QUERY,
+ FALSE,
+ &TokenHandle)) {
+
+ if (GetLastError() == ERROR_NO_TOKEN) {
+
+ // This means we are not impersonating anybody.
+ // Instead, lets get the token out of the process.
+
+ if (!OpenProcessToken(GetCurrentProcess(),
+ TOKEN_QUERY,
+ &TokenHandle)) {
+
+ return FALSE;
+ }
+
+ } else
+
+ return FALSE;
+ }
+
+ if (!GetTokenInformation(TokenHandle, TokenUser, NULL, 0, &cbNeeded)) {
+
+ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+
+ if (pUserToken = malloc(cbNeeded) ) {
+
+ if (GetTokenInformation(TokenHandle, TokenUser, pUserToken,
+ cbNeeded, &cbNeeded)) {
+
+ cbName = 0 ;
+ cbDomain = 0 ;
+ pName = NULL ;
+ pDomain = NULL ;
+
+ if (!LookupAccountSid(NULL, pUserToken->User.Sid,
+ NULL, &cbName, NULL,
+ &cbDomain, &SidNameUse)) {
+
+
+ if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+
+ cbDomain *= sizeof(CHAR) ;
+ cbName *= sizeof(CHAR) ;
+
+ if ( *pcbUser >= cbDomain + cbName + sizeof(CHAR) ) {
+
+ pDomain = malloc( cbDomain ) ;
+ if ( pDomain ) {
+ pName = malloc( cbName ) ;
+ }
+
+ if (pName) {
+
+ ReturnValue = LookupAccountSid(NULL,
+ pUserToken->User.Sid,
+ pName, &cbName,
+ pDomain, &cbDomain,
+ &SidNameUse);
+
+ cbDomain *= sizeof(CHAR) ;
+ cbName *= sizeof(CHAR) ;
+
+ }
+ if ( ReturnValue ) {
+ /*
+ * Need space for the names, backslash,
+ * and a null terminator
+ */
+ *pUser = malloc( cbDomain + cbName + sizeof(CHAR) * 2 ) ;
+ }
+ if ( *pUser ) {
+ strcpy( *pUser, pDomain ) ;
+ strcat( *pUser, TEXT("\\") ) ;
+ strcat( *pUser, pName ) ;
+
+ }
+ }
+
+ *pcbUser = cbDomain + cbName + sizeof(CHAR) ;
+ }
+
+ } else {
+
+ ReturnValue = TRUE;
+ }
+
+ free(pName) ;
+ free(pDomain) ;
+ }
+
+ free(pUserToken);
+ }
+ }
+ }
+
+ CloseHandle(TokenHandle) ;
+
+ return ReturnValue ;
+}
+
+BOOLEAN NTFS_SupportMacSyntax( GENERIC_DLE_PTR dle )
+{
+#if defined( UNICODE )
+ static BOOLEAN firstTime = TRUE;
+ static BOOLEAN ret_val = FALSE;
+
+ /*
+ * This function will only work on DLEs that are drive letter
+ * type DLEs. The tip of this file works correctly for all DLE
+ * types.
+ */
+ if ( firstTime )
+ {
+ CHAR path[] = TEXT("\\\\?\\C:\\");
+
+ path[4] = dle->device_name[0] ;
+
+ if ( GetFileAttributes( path ) != 0xffffffff )
+ {
+ ret_val = TRUE;
+ }
+ firstTime = FALSE;
+ }
+ return ret_val;
+#else
+ (void)dle;
+ return FALSE;
+#endif
+}
+
+/**/
+/**
+
+ Name: NTFS_InitFileSys()
+
+ Description: Performs initializations for the NT file system
+ that need be done only once per process invocation.
+
+ Modified: 04-Nov-93
+
+ Returns:
+
+ Notes:
+
+**/
+INT16 NTFS_InitFileSys( DLE_HAND hand,
+ BE_CFG_PTR cfg,
+ UINT32 fsys_mask )
+{
+ (void)hand;
+ (void)cfg;
+ (void)fsys_mask;
+
+ /*
+ * Initialize the temporary file name thingy.
+ */
+ NTFS_InitTemp();
+
+ return SUCCESS;
+}
+
+/**/
+/**
+
+ Name: NTFS_DeInitFileSys()
+
+ Description: Performs any cleanup that must be done for the
+ NT file system
+
+ Modified: 04-Nov-93
+
+ Returns: Nothing
+
+ Notes:
+
+**/
+VOID NTFS_DeInitFileSys( DLE_HAND hand )
+{
+ (void)hand;
+
+ /*
+ * Reclaim memory used by the temporary file name thingy
+ */
+ NTFS_DeinitTemp();
+}
+
+
+
+
diff --git a/private/utils/ntbackup/src/tminddb.c b/private/utils/ntbackup/src/tminddb.c
new file mode 100644
index 000000000..dcb10a160
--- /dev/null
+++ b/private/utils/ntbackup/src/tminddb.c
@@ -0,0 +1,178 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tminddb.c
+
+ Description: This file contains code to save and restore the minimal
+ information contained in a DDB.
+
+
+ $Log: N:\logfiles\tminddb.c_v $
+
+ Rev 1.9 12 Aug 1993 21:27:34 MIKEP
+fix delete bug
+
+ Rev 1.8 26 Jul 1993 13:10:14 CARLS
+added name_size to PopMinDDB call
+
+ Rev 1.7 10 Nov 1992 08:18:54 STEVEN
+removed path and name from dblk now use full_name_ptr
+
+ Rev 1.6 07 Oct 1992 15:54:58 DAVEV
+unicode strlen verification
+
+ Rev 1.5 24 Sep 1992 13:43:54 BARRY
+Changes for huge file name support.
+
+ Rev 1.4 21 May 1992 13:49:14 STEVEN
+more long path support
+
+ Rev 1.3 04 May 1992 09:27:36 LORIB
+Changes for variable length paths.
+
+ Rev 1.2 12 Mar 1992 15:50:20 STEVEN
+64 bit changes
+
+ Rev 1.1 28 Feb 1992 13:03:46 STEVEN
+step one for varible length paths
+
+ Rev 1.0 28 Jan 1992 14:40:46 STEVEN
+Initial revision.
+
+**/
+#include <windows.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "queues.h"
+
+#include "fsys.h"
+#include "fsys_err.h"
+#include "ntfsdblk.h"
+#include "ntfs_fs.h"
+#include "tfldefs.h"
+
+/**/
+/**
+
+ Name: NTFS_PushMinDDB()
+
+ Description: This function saves the specified DDB. It only saves
+ enough data to allow the restored DDB be used as a
+ parameter to a subset of the File System Calls.
+ This subset includes the following functions:
+
+ NTFS_FindNext(), NTFS_GetBlockType(),
+ NTFS_GetPathFromDDB(),
+ NTFS_RemoveDir(), and NTFS_FDBMatch()
+
+ The expected use of this function is to recursively
+ traverse a directory tree using the least amount of
+ memory.
+
+
+ Modified: 1/28/1992 12:31:14
+
+ Returns: Error codes:
+ OUT_OF_MEMMORY
+ FS_BAD_DBLK
+
+
+**/
+INT16 NTFS_PushMinDDB( fsh, dblk )
+FSYS_HAND fsh;
+DBLK_PTR dblk;
+{
+ NTFS_DBLK_PTR ddblk ;
+ NTFS_MIN_DDB_PTR mddb ;
+ INT16 ret_val ;
+ CHAR_PTR path ;
+
+ ddblk = (NTFS_DBLK_PTR) dblk ;
+
+ msassert( fsh->attached_dle != NULL ) ;
+
+ msassert( dblk->blk_type == DDB_ID ) ;
+
+ path = ddblk->full_name_ptr->name ;
+
+ mddb = calloc( 1, sizeof(NTFS_MIN_DDB) + strsize( path ) ) ;
+
+ if ( mddb != NULL ) {
+
+ InitQElem( &(mddb->q) ) ;
+ mddb->scan_hand = ddblk->dta.scan_hand ;
+ mddb->path_in_stream = (BOOLEAN)(ddblk->b.d.ddb_attrib & DIR_PATH_IN_STREAM_BIT) ;
+ mddb->path = (CHAR_PTR)(mddb + 1) ;
+ mddb->psize = (INT16)(strlen( path ) * sizeof (CHAR)) ;
+ strcpy( mddb->path, path ) ;
+
+ PushElem( &(fsh->min_ddb_stk), &(mddb->q) ) ;
+
+ ret_val = SUCCESS ;
+
+ }
+
+ return( ret_val ) ;
+}
+/**/
+/**
+
+ Name: NTFS_PopMinDDB()
+
+ Description: This function returns a DDB which contains the minimal
+ data saved by NTFS_PushMinDDB(). The DDB returned can
+ be used as input for the following function:
+ NTFS_FindFNext(), NTFS_GetInfo(),
+
+ Modified: 1/28/1992 12:43:17
+
+ Returns: Error codes:
+ FS_STACK_EMPTY
+ SUCCESS
+
+ Notes:
+
+**/
+INT16 NTFS_PopMinDDB( fsh, dblk )
+FSYS_HAND fsh ;
+DBLK_PTR dblk ;
+{
+ NTFS_DBLK_PTR ddblk ;
+ NTFS_MIN_DDB_PTR mddb ;
+ INT16 ret_val = SUCCESS ;
+
+ ddblk = (NTFS_DBLK_PTR) dblk ;
+
+ mddb = (NTFS_MIN_DDB_PTR) PopElem( &(fsh->min_ddb_stk) );
+
+ if ( mddb != NULL ) {
+
+ dblk->blk_type = DDB_ID ;
+ ddblk->dta.scan_hand = mddb->scan_hand ;
+
+ ret_val = NTFS_SetupPathInDDB( fsh, dblk, mddb->path, NULL, 0 ) ;
+
+ if ( mddb->path_in_stream ) {
+ ddblk->b.d.ddb_attrib = DIR_PATH_IN_STREAM_BIT ;
+ } else {
+ ddblk->b.d.ddb_attrib = 0 ;
+ }
+
+ dblk->com.os_name = NULL ;
+ ddblk->os_info_complete = FALSE;
+ ddblk->name_complete = TRUE;
+
+ free( mddb );
+
+ } else {
+ ret_val = FS_STACK_EMPTY ;
+ }
+
+ return ret_val ;
+}
+
+
diff --git a/private/utils/ntbackup/src/tmkdblk.c b/private/utils/ntbackup/src/tmkdblk.c
new file mode 100644
index 000000000..def737257
--- /dev/null
+++ b/private/utils/ntbackup/src/tmkdblk.c
@@ -0,0 +1,718 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tmkdblk.c
+
+ Description: This file contains functions for the tape format
+ layer to use to create DBLKs. The structure's passed
+ to the create functions includes generic information which
+ is common to most file systems and os specific information.
+ The os specific information was saved when the file system
+ for that os was used to make a backup. The information in
+ the os specific portion could potentially be translated into
+ a useable format for this file system. Each file system defines
+ the format for its os specific information in the header file
+ osinfo.h.
+
+
+ $Log: M:/LOGFILES/TMKDBLK.C_V $
+
+ Rev 1.42 15 Jan 1994 19:25:08 BARRY
+Call SetupOSPathOrName with BYTE_PTRs instead of CHAR_PTRs
+
+ Rev 1.41 24 Nov 1993 14:36:22 BARRY
+Unicode fixes
+
+ Rev 1.40 20 Jul 1993 10:03:00 BARRY
+Initialize temp file name pointer used for MoveFileEx calls.
+
+ Rev 1.39 07 Jun 1993 19:43:52 BARRY
+Must convert back from local time.
+
+ Rev 1.38 14 Mar 1993 15:02:28 BARRY
+Fixed problems with making long names shorter.
+
+ Rev 1.37 07 Dec 1992 14:17:36 STEVEN
+updates from msoft
+
+ Rev 1.36 19 Nov 1992 11:19:18 STEVEN
+fix unicode fixes
+
+ Rev 1.35 16 Nov 1992 13:47:38 STEVEN
+fix unicode bug
+
+ Rev 1.33 11 Nov 1992 09:52:18 GREGG
+Unicodeized literals.
+
+ Rev 1.32 10 Nov 1992 08:19:58 STEVEN
+removed path and name from dblk now use full_name_ptr
+
+ Rev 1.31 29 Oct 1992 16:45:28 BARRY
+Return KEEP_ALL_DATA on dirs; minor path-in-stream changes.
+
+ Rev 1.30 20 Oct 1992 19:26:04 GREGG
+Removed line accidently block copied in during last change.
+
+ Rev 1.29 20 Oct 1992 17:20:28 STEVEN
+fix typo
+
+ Rev 1.28 20 Oct 1992 15:51:32 STEVEN
+added support for otc / catalog interface through DBLK
+
+ Rev 1.27 15 Oct 1992 11:39:04 STEVEN
+fix typos
+
+ Rev 1.26 13 Oct 1992 14:03:00 BARRY
+Wasn't setting up path length in MakeDDB.
+
+ Rev 1.25 13 Oct 1992 11:31:04 STEVEN
+Fixed support for UNICODE
+
+ Rev 1.24 09 Oct 1992 10:47:14 BARRY
+Name length updates.
+
+ Rev 1.23 01 Oct 1992 13:26:50 STEVEN
+fixes from Msoft
+
+ Rev 1.22 01 Oct 1992 13:03:44 BARRY
+Huge path/file name changes.
+
+ Rev 1.21 10 Sep 1992 09:30:36 STEVEN
+fix bugs in restore
+
+ Rev 1.20 04 Sep 1992 17:14:56 STEVEN
+fix warnings
+
+ Rev 1.19 17 Aug 1992 16:04:08 STEVEN
+fix warnings
+
+ Rev 1.17 04 Aug 1992 17:37:10 STEVEN
+fix buggs
+
+ Rev 1.16 30 Jul 1992 19:18:32 STEVEN
+fix fix_fname bug
+
+ Rev 1.15 23 Jul 1992 16:43:30 STEVEN
+fix warnings
+
+ Rev 1.14 23 Jul 1992 13:11:16 STEVEN
+fix warnings
+
+ Rev 1.13 20 Jul 1992 10:43:46 STEVEN
+backup short file name
+
+ Rev 1.12 17 Jul 1992 14:58:30 STEVEN
+fix NT bugs
+
+ Rev 1.11 16 Jul 1992 15:27:46 STEVEN
+fix type-o
+
+ Rev 1.10 09 Jul 1992 13:58:10 STEVEN
+BE_Unicode updates
+
+ Rev 1.9 09 Jun 1992 15:41:42 BURT
+Sync with NT and fixes
+
+ Rev 1.6 22 May 1992 16:05:22 STEVEN
+
+
+ Rev 1.5 21 May 1992 13:49:06 STEVEN
+more long path support
+
+ Rev 1.4 04 May 1992 09:30:36 LORIB
+Preliminary changes for variable length paths.
+
+ Rev 1.3 12 Mar 1992 15:50:18 STEVEN
+64 bit changes
+
+ Rev 1.2 28 Feb 1992 13:03:34 STEVEN
+step one for varible length paths
+
+ Rev 1.0 12 Feb 1992 12:55:12 STEVEN
+Initial revision.
+
+**/
+#include <windows.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "stdwcs.h"
+#include "std_err.h"
+#include "stdmath.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "ntfsdblk.h"
+#include "ntfs_fs.h"
+#include "tfldefs.h"
+#include "osinfo.h"
+#include "gen_fs.h"
+
+static VOID NTFS_FixFname(
+CHAR_PTR name,
+UINT16 max_size ) ;
+
+static VOID ConvertMaynTimeToSysTime( DATE_TIME *buf, FILETIME *filetime ) ;
+
+/**/
+/**
+
+ Name: NTFS_CreateFDB
+
+ Description: This function creates a FDB based on the information
+ passed in the GEN_FDB_DATA structure. This function
+ allows the tape format layer to create DBLKs without
+ knowing their structure.
+
+ Modified: 8/24/1989
+
+ Returns: TF_KEEP_GEN_DATA_ONLY
+
+**/
+INT16 NTFS_CreateFDB( fsh, dat )
+FSYS_HAND fsh;
+GEN_FDB_DATA_PTR dat;
+{
+ NTFS_DBLK_PTR ddblk;
+ UINT16 nam_size ;
+ INT8_PTR input_str ;
+ INT cb_input_str_sz ;
+ BOOLEAN input_str_allocated = FALSE ;
+ GENERIC_DLE_PTR dle ;
+ FS_NAME_Q_ELEM_PTR os_name_q_elem ;
+ FS_NAME_Q_ELEM_PTR name_q_elem ;
+ DBLK_PTR dblk ;
+ INT16 ret_val ;
+
+ dle = fsh->attached_dle ;
+
+ dat->std_data.dblk->blk_type = FDB_ID ;
+ dat->std_data.dblk->com.blkid = dat->std_data.blkid;
+ dat->std_data.dblk->com.f_d.did = dat->std_data.did ;
+ dat->std_data.dblk->com.ba.lba = dat->std_data.lba ;
+ dat->std_data.dblk->com.continue_obj = dat->std_data.continue_obj ;
+ dat->std_data.dblk->com.os_id = dat->std_data.os_id ;
+ dat->std_data.dblk->com.os_ver = dat->std_data.os_ver ;
+
+ dat->std_data.dblk->com.tape_seq_num = dat->std_data.tape_seq_num ;
+
+ ddblk = (NTFS_DBLK_PTR)dat->std_data.dblk;
+ dblk = dat->std_data.dblk ;
+ dblk->com.string_type = dat->std_data.string_type ;
+
+ ddblk->blk_type = FDB_ID;
+ ddblk->b.f.fdb_attrib = dat->std_data.attrib ;
+ ddblk->b.f.PosixFile = FALSE ;
+
+ ConvertMaynTimeToSysTime( dat->mod_date, &ddblk->dta.modify_time ) ;
+ ConvertMaynTimeToSysTime( dat->creat_date, &ddblk->dta.create_time ) ;
+ ConvertMaynTimeToSysTime( dat->access_date, &ddblk->dta.access_time ) ;
+
+ ddblk->dta.size = dat->std_data.disp_size;
+ ddblk->dta.os_attr = FILE_ATTRIBUTE_NORMAL ;
+ ddblk->dta.scan_hand = NULL;
+
+ ddblk->os_info_complete = FALSE;
+ ddblk->name_complete = TRUE;
+ ddblk->b.f.handle = NULL;
+ ddblk->b.f.hand_temp_name = NULL;
+ ddblk->b.f.linkOnly = FALSE;
+ ddblk->b.f.alt_name[0] = TEXT('\0');
+ ddblk->b.f.idHi = 0;
+ ddblk->b.f.idLo = 0;
+ ddblk->b.f.linkCount = 0;
+ ddblk->b.f.linkOnly = FALSE;
+ ddblk->b.f.PosixFile = FALSE;
+
+
+ /* convert name to destination type UNICODE/ASCII */
+
+ if ( !( dat->std_data.attrib & FILE_NAME_IN_STREAM_BIT ) )
+ {
+ ret_val = FS_SetupOSPathOrNameInDBLK( fsh,
+ dblk,
+ (BYTE_PTR)dat->fname,
+ dat->fname_size ) ;
+ if ( ret_val != SUCCESS )
+ {
+ return OUT_OF_MEMORY ;
+ }
+
+ name_q_elem = FS_AllocPathOrName( fsh, dblk->com.os_name->name_size ) ;
+ if ( name_q_elem == NULL )
+ {
+ return OUT_OF_MEMORY ;
+ }
+
+ ddblk->full_name_ptr = name_q_elem ;
+ memcpy( ddblk->full_name_ptr->name,
+ dblk->com.os_name->name,
+ dblk->com.os_name->name_size ) ;
+
+
+ NTFS_FixFname( ddblk->full_name_ptr->name, (UINT16)dle->info.ntfs->fname_leng ) ;
+
+ ddblk->full_name_ptr->name_size = strsize( ddblk->full_name_ptr->name ) ;
+
+ ddblk->name_complete = TRUE ;
+
+ }
+ else
+ {
+ ddblk->name_complete = FALSE ;
+ }
+
+
+ if ( input_str_allocated )
+ {
+ free( input_str ) ;
+ }
+
+ switch ( dat->std_data.os_id )
+ {
+
+ case FS_NTFS_ID:
+ {
+ NT_FILE_OS_INFO_PTR nt_inf ;
+
+ nt_inf = (NT_FILE_OS_INFO_PTR)dat->std_data.os_info ;
+
+ ddblk->dta.os_attr = nt_inf->file_attributes ;
+ ddblk->b.f.linkOnly = nt_inf->linkOnly;
+
+ if ( ( dle->info.ntfs->fname_leng <= 12 ) &&
+ ( nt_inf->short_name_size != 0 ) )
+ {
+ BYTE_PTR pb_short_name;
+
+ pb_short_name = (UINT8_PTR)(nt_inf) + nt_inf->short_name_offset ;
+
+ ret_val = FS_SetupOSPathOrNameInDBLK( fsh,
+ dblk,
+ pb_short_name,
+ nt_inf->short_name_size ) ;
+ if ( ret_val != SUCCESS )
+ {
+ return OUT_OF_MEMORY ;
+ }
+
+ name_q_elem = FS_AllocPathOrName( fsh, dblk->com.os_name->name_size ) ;
+
+ if ( name_q_elem == NULL )
+ {
+ return OUT_OF_MEMORY ;
+ }
+
+ ddblk->full_name_ptr = name_q_elem ;
+ memcpy( ddblk->full_name_ptr->name,
+ dblk->com.os_name->name,
+ dblk->com.os_name->name_size ) ;
+
+
+ NTFS_FixFname( ddblk->full_name_ptr->name, (UINT16)dle->info.ntfs->fname_leng ) ;
+
+ ddblk->full_name_ptr->name_size = strsize( ddblk->full_name_ptr->name ) ;
+
+ ddblk->name_complete = TRUE ;
+
+ }
+ else if ( nt_inf->short_name_size == 0 )
+ {
+ ddblk->b.f.PosixFile = TRUE ;
+ }
+ break ;
+ }
+ }
+ return TF_KEEP_ALL_DATA ;
+}
+
+
+/**/
+/**
+
+ Name: NTFS_CreateDDB
+
+ Description: This function creates a DDB based on the information
+ passed in the GEN_DDB_DATA structure. This function
+ allows the tape format layer to create DBLKs without
+ knowing their structure.
+
+ Modified: 8/24/1989
+
+ Returns: TF_SKIP_ALL_DATA
+
+**/
+INT16 NTFS_CreateDDB( fsh, dat )
+FSYS_HAND fsh;
+GEN_DDB_DATA_PTR dat;
+
+{
+ NTFS_DBLK_PTR ddblk;
+ INT16 dir_size ;
+ INT16 ret_val ;
+ INT8_PTR input_str ;
+ INT cb_input_str_sz ;
+ BOOLEAN input_str_allocated = FALSE ;
+ FS_NAME_Q_ELEM_PTR name_q_elem ;
+ FS_NAME_Q_ELEM_PTR os_name_q_elem ;
+ DBLK_PTR dblk ;
+
+ dat->std_data.dblk->blk_type = DDB_ID ;
+ dat->std_data.dblk->com.blkid = dat->std_data.blkid;
+ dat->std_data.dblk->com.f_d.did = dat->std_data.did ;
+ dat->std_data.dblk->com.ba.lba = dat->std_data.lba ;
+ dat->std_data.dblk->com.os_id = dat->std_data.os_id ;
+ dat->std_data.dblk->com.os_ver = dat->std_data.os_ver ;
+
+ dat->std_data.dblk->com.continue_obj = dat->std_data.continue_obj ;
+ dat->std_data.dblk->com.tape_seq_num = dat->std_data.tape_seq_num ;
+
+ ddblk = (NTFS_DBLK_PTR)dat->std_data.dblk;
+ dblk = dat->std_data.dblk;
+ dblk->com.string_type = dat->std_data.string_type ;
+
+ ddblk->blk_type = DDB_ID;
+
+ ddblk->b.d.ddb_attrib = dat->std_data.attrib ;
+ if ( ddblk->b.d.ddb_attrib & DIR_PATH_IN_STREAM_BIT ) {
+ dat->std_data.dblk->com.stream_offset = 0 ;
+ ddblk->name_complete = FALSE ;
+ } else {
+ ddblk->name_complete = TRUE ;
+ }
+
+ ddblk->dta.scan_hand = NULL;
+ ddblk->dta.size = U64_Init( 0, 0 ) ;
+ ddblk->dta.os_attr = FILE_ATTRIBUTE_NORMAL ;
+
+ ConvertMaynTimeToSysTime( dat->mod_date, &ddblk->dta.modify_time ) ;
+ ConvertMaynTimeToSysTime( dat->creat_date, &ddblk->dta.create_time ) ;
+ ConvertMaynTimeToSysTime( dat->access_date, &ddblk->dta.access_time ) ;
+
+ ddblk->os_info_complete = FALSE;
+
+ if ( ddblk->name_complete ) {
+
+ ret_val = FS_SetupOSPathOrNameInDBLK( fsh,
+ dblk,
+ (BYTE_PTR)dat->path_name,
+ dat->path_size ) ;
+ if ( ret_val != SUCCESS ) {
+ return OUT_OF_MEMORY ;
+ }
+
+ name_q_elem = FS_AllocPathOrName( fsh, dblk->com.os_name->name_size ) ;
+
+ if ( name_q_elem == NULL ) {
+ return OUT_OF_MEMORY ;
+
+ }
+
+ ddblk->full_name_ptr = name_q_elem ;
+ memcpy( ddblk->full_name_ptr->name,
+ dblk->com.os_name->name,
+ dblk->com.os_name->name_size ) ;
+
+
+ dir_size = dblk->com.os_name->name_size ;
+
+ NTFS_FixPath( ddblk->full_name_ptr->name,
+ &dir_size,
+ (UINT16)fsh->attached_dle->info.ntfs->fname_leng ) ;
+
+ ddblk->full_name_ptr->name_size = strsize( ddblk->full_name_ptr->name );
+
+ ddblk->name_complete = TRUE ;
+
+
+ } else {
+
+ ddblk->name_complete = FALSE ;
+ }
+
+ if ( input_str_allocated ) {
+ free( input_str ) ;
+ }
+
+ switch ( dat->std_data.os_id ) {
+
+ case FS_NTFS_ID:
+ ddblk->dta.os_attr = ((NT_DIR_OS_INFO_PTR)dat->std_data.os_info)->dir_attributes ;
+ break ;
+ }
+
+
+ return TF_KEEP_ALL_DATA ;
+
+}
+
+
+
+/* The purpose of this function is to handle pathnames that have
+ members that are either longer than 8 chars or not of the form
+ 8.3 which is the FAT/DOS format. It does this by calling the
+ NTFS_FixFname() function to do the bulk of the work.
+
+ Entry: CHAR_PTR to the path string.
+ INT16_PTR to the size of the path string, includes terminating
+ NUL.
+ INT16 maximum size for a file name/directory path member.
+
+ Returns: Nothing. The path string is modified in place, and the passed
+ path size is altered to reflect the changed path string
+ length.
+
+ paths like: 1) \foo\fahdeedah\foo.foo
+ 2) \foo\fahdeedah.abc.def\foo.foo
+ 3) \foo\fahdeeda.h\foo.foo
+ 4) \foo\fahdeedahabcdefgh\foo.foo
+
+ will convert to: 1) \foo\fahdeeda\foo.foo
+ 2) \foo\fahdeeda\foo.foo
+ 3) \foo\fahdeeda.h\foo.foo
+ 4) \foo\fahdeeda\foo.foo
+
+*/
+
+VOID NTFS_FixPath( CHAR_PTR path,
+ INT16_PTR size,
+ INT16 fname_size )
+{
+ CHAR_PTR src;
+ CHAR_PTR member;
+ CHAR_PTR dest;
+ INT16 src_size;
+ INT16 member_size;
+
+ member = src = dest = path ;
+ src_size = *size ;
+ *size = member_size = (INT16)0 ;
+
+ if ( src_size <= sizeof(CHAR) )
+ {
+ *dest = TEXT('\0');
+ *size = sizeof(CHAR) ;
+ return ;
+ }
+
+ do
+ {
+ if ( *src == TEXT('\0') )
+ {
+ *dest = TEXT('\0');
+ if ( member_size != (INT16)0 )
+ {
+ NTFS_FixFname( member, (UINT16)fname_size ) ;
+
+ (*size) += strsize( member ) ;
+ dest = member + strlen( member );
+ member = dest + 1 ;
+ member_size = (INT16)0 ;
+ }
+
+ if ( src_size > sizeof(CHAR) )
+ {
+ *dest = TEXT('\\') ;
+ }
+ else
+ {
+ *dest = TEXT('\0') ;
+ }
+ }
+ else
+ {
+
+ *dest = *src ;
+ }
+ src++ ;
+ dest++ ;
+ src_size-=sizeof(CHAR) ;
+ member_size+=sizeof(CHAR) ;
+
+ } while ( src_size != 0 ) ;
+}
+
+
+/*
+ The purpose of this function is to insure that no member portion of
+ a pathname is more than max_size in length. This will attempt to
+ perform this action using the existing buffer which is passed in as
+ name. Illegal characters are replaced with the underscore.
+
+ Entry: CHAR_PTR to file or directory path member name string. This is
+ expected to be NUL terminated.
+ INT16 Maximum size allowed for the member name string.
+
+*/
+static VOID NTFS_FixFname(
+ CHAR_PTR name,
+ UINT16 max_size )
+{
+ CHAR_PTR badChars = TEXT(" <>\\?*|");
+ INT i ;
+
+ /* Check for potential problems with the characters in the name */
+ if ( strcspn( name, badChars ) != strlen( name ) )
+ {
+ CHAR_PTR src = name;
+ CHAR_PTR dst = name;
+ CHAR_PTR ext = strchr( name, TEXT('.') );
+
+ /*
+ * Set up definition of what characters we want to remove from
+ * name. Only remove spaces from name if the name is obviously
+ * a long name and it is being restored to a FAT drive; otherwise
+ * we could be removing spaces from a FAT name that are there
+ * for a good reason.
+ */
+
+ // Remove spaces if max_size <= 12 && (name.ext > 12 or name > 8)
+
+ if ( max_size > 12 )
+ {
+ /* Don't remove spaces -- we probably have room for them. */
+ badChars = TEXT("<>\\?*|");
+ }
+ else
+ {
+ BOOLEAN maxed;
+
+ /* Check for overflowing the 8.3 format */
+ if ( ext != NULL )
+ {
+ maxed = ((ext - name - 1) > 8) || (strlen( ext + 1 ) > 3);
+ }
+ else
+ {
+ maxed = strlen( name ) > 8;
+ }
+
+ /*
+ * If the name length doesn't exceed the max of the FAT drive,
+ * then we will not remove spaces.
+ */
+ if ( !maxed )
+ {
+ badChars = TEXT("<>\\?*|");
+ }
+ }
+
+ /*
+ * Remove bad characters by scrunching the string, not by
+ * replacement with a filler (like '_').
+ */
+ while ( *src != TEXT('\0') )
+ {
+ if ( strchr( badChars, *src ) == NULL )
+ {
+ *dst++ = *src++;
+ }
+ else
+ {
+ src++;
+ }
+ }
+
+ /* Make sure string is terminated. */
+ *dst = TEXT('\0');
+ }
+
+
+ if ( max_size == 12 ) /* FAT/DOS based 8.3 max name size. */
+ {
+ CHAR_PTR p ;
+ CHAR_PTR p1 ;
+
+ p = strchr( name, TEXT('.') ) ;
+ if ( p != NULL ) /* '.' found */
+ {
+ if ( p - name > (8*sizeof(CHAR)) ) /* name portion is > 8 chars */
+ {
+ p1 = strchr( p+1, TEXT('.') ) ;
+ if ( p1 != NULL )
+ {
+ *p1 = TEXT('\0') ; /* Kill any portion that had an additional '.' */
+ }
+ }
+ }
+
+ if ( strlen( name ) < 9 )
+ {
+ if ( p == NULL || (p - name <= 8) )
+ {
+ return; /* All should be well with the world */
+ }
+ }
+
+ /*
+ * Now we know that the name portion is greater than 8 chars
+ * if we are going to move up we would need to allow the
+ * source buffer to grow as '.'s are added. This is not likely
+ * to be the case. So.... we can't just move things around in
+ * the buffer. Basically we need to evaluate to see if we have
+ * no '.' and, if so place one at [8], overwritting the existing
+ * character.
+ */
+
+ if ( p == NULL || ((p - name) > (8*sizeof(CHAR))) ) /* No '.' */
+ {
+ if ( p != NULL )
+ {
+ name[8] = TEXT('.') ; /* Place '.' */
+ p1 = strchr( p+1, TEXT('.' ) ) ;
+ if ( p1 != NULL )
+ {
+ /* Kill any portion that had an additional '.' */
+ *p1 = TEXT('\0') ;
+ }
+ }
+
+ /* If more than 8 chars and no '.' */
+ if ( p == NULL && (strlen( name ) > 8) )
+ {
+ name[8] = TEXT('\0') ;
+ }
+ }
+
+ /* Now we need to see if we have more than 3 chars before the nul */
+ if ( strlen( &name[9] ) > 3 )
+ {
+ /*
+ * Go upstream and let fix path deal with it. But
+ * of course we are called from other spots so that
+ * won't work either.
+ */
+ name[8] = TEXT('\0') ; /* Force path processing */
+ return ;
+ }
+
+ }
+ else if ( max_size != (UINT16)0xffff )
+ {
+ if ( (UINT16)strlen( name ) > max_size )
+ {
+ name[ max_size] = TEXT('\0') ;
+ }
+ }
+}
+
+
+static VOID ConvertMaynTimeToSysTime( DATE_TIME *buf, FILETIME *filetime )
+{
+ SYSTEMTIME systime ;
+ FILETIME temp;
+
+ systime.wYear = buf->year ;
+ systime.wMonth = buf->month ;
+ systime.wDay = buf->day ;
+ systime.wHour = buf->hour ;
+ systime.wMinute= buf->minute ;
+ systime.wSecond= buf->second ;
+
+ systime.wDayOfWeek = 0 ;
+ systime.wMilliseconds = 0 ;
+
+ SystemTimeToFileTime( &systime, &temp ) ;
+ LocalFileTimeToFileTime( &temp, filetime ) ;
+
+}
diff --git a/private/utils/ntbackup/src/tmoddblk.c b/private/utils/ntbackup/src/tmoddblk.c
new file mode 100644
index 000000000..f10018c85
--- /dev/null
+++ b/private/utils/ntbackup/src/tmoddblk.c
@@ -0,0 +1,1174 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tmoddblk.c
+
+ Description: This file contains code to get/set generic information
+ from/to a NTFS FDB or DDB.
+
+
+ $Log: M:/LOGFILES/TMODDBLK.C_V $
+
+ Rev 1.39 24 Nov 1993 15:00:52 BARRY
+Changed CHAR_PTRs in I/O functions to BYTE_PTRs
+
+ Rev 1.38 06 Jul 1993 14:59:54 BARRY
+No, the nt_ddb is not necessarily the current dir.
+
+ Rev 1.37 11 Jun 1993 14:20:54 BARRY
+Only enumerate special files when dle has restore special files bit set.
+
+ Rev 1.36 03 Jun 1993 16:20:40 STEVEN
+fix time and date to local time
+
+ Rev 1.35 04 May 1993 22:56:28 BARRY
+Fixed invalid dates/times.
+
+ Rev 1.34 01 Apr 1993 14:30:02 TIMN
+Replace constant with define
+
+ Rev 1.33 11 Feb 1993 11:27:46 STEVEN
+fix CHAR_PTR to CHAR
+
+ Rev 1.32 08 Feb 1993 10:36:42 STEVEN
+we always want to process directories
+
+ Rev 1.31 04 Feb 1993 11:24:50 BARRY
+Steve's registry fixes to EnumSpecialFiles.
+
+ Rev 1.30 17 Dec 1992 13:26:56 STEVEN
+we need to backup the short names
+
+ Rev 1.29 11 Nov 1992 09:52:12 GREGG
+Unicodeized literals.
+
+ Rev 1.28 10 Nov 1992 08:20:36 STEVEN
+removed path and name from dblk now use full_name_ptr
+
+ Rev 1.27 06 Nov 1992 16:28:06 STEVEN
+test unlimited file sizes
+
+ Rev 1.26 06 Nov 1992 15:49:10 STEVEN
+test write of path in stream
+
+ Rev 1.25 04 Nov 1992 18:00:36 BARRY
+Moved the temporary MSOFT stream id definitions elsewhere.
+
+ Rev 1.24 29 Oct 1992 16:50:24 BARRY
+Translate ULNK IDs; add linkOnly to osinfo.
+
+ Rev 1.23 21 Oct 1992 11:52:54 STEVEN
+added SpecialExclude
+
+ Rev 1.22 14 Oct 1992 14:38:52 BARRY
+Added MSoft stream IDs (until they are public.).
+
+ Rev 1.21 09 Oct 1992 15:18:10 BARRY
+Name-in-stream changes.
+
+ Rev 1.20 07 Oct 1992 16:15:34 STEVEN
+forgot the structure
+
+ Rev 1.19 07 Oct 1992 16:10:54 STEVEN
+added MsofttoMayn
+
+ Rev 1.18 07 Oct 1992 15:54:30 DAVEV
+unicode strlen verification
+
+ Rev 1.17 01 Oct 1992 13:26:46 STEVEN
+fixes from Msoft
+
+ Rev 1.16 01 Oct 1992 13:03:48 BARRY
+Huge path/file name changes.
+
+ Rev 1.15 22 Sep 1992 15:36:18 BARRY
+Got rid of GetTotalSizeDBLK.
+
+ Rev 1.14 21 Sep 1992 16:51:58 BARRY
+Change over from path_complete to name_complete.
+
+ Rev 1.13 17 Aug 1992 16:09:20 STEVEN
+fix warnings
+
+ Rev 1.12 12 Aug 1992 17:47:44 STEVEN
+fixed bugs at microsoft
+
+ Rev 1.11 20 Jul 1992 10:43:32 STEVEN
+backup short file name
+
+ Rev 1.10 25 Jun 1992 11:21:52 STEVEN
+need to properly initialize the attribute structure
+
+ Rev 1.8 09 Jun 1992 15:14:04 BURT
+Sync with NT stuff
+
+ Rev 1.7 01 Jun 1992 10:30:56 STEVEN
+specify the file size for now
+
+ Rev 1.6 27 May 1992 18:49:30 STEVEN
+getting wrong os path
+
+ Rev 1.5 22 May 1992 16:05:38 STEVEN
+
+
+ Rev 1.4 21 May 1992 13:49:12 STEVEN
+more long path support
+
+ Rev 1.3 04 May 1992 09:22:20 LORIB
+Fixes to structure member names.
+
+ Rev 1.2 12 Mar 1992 15:50:10 STEVEN
+64 bit changes
+
+ Rev 1.1 23 Jan 1992 13:54:14 STEVEN
+fix typo of NTTS instead of NTFS
+
+ Rev 1.0 17 Jan 1992 17:50:02 STEVEN
+Initial revision.
+
+**/
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+
+#include "stdtypes.h"
+#include "stdwcs.h"
+#include "stdmath.h"
+#include "tfldefs.h"
+#include "datetime.h"
+#include "fsys.h"
+#include "ntfsdblk.h"
+#include "ntfs_fs.h"
+#include "fsys_err.h"
+#include "osinfo.h"
+
+typedef struct {
+ UINT32 maynID;
+ UINT32 msoftID;
+} ID_TRANS_TABLE, ID_TRANS_TABLE_PTR;
+
+/**/
+/**
+
+ Name: NTFS_ModFnameFDB()
+
+ Description: This function gets/sets the file name in an FDB
+
+ Modified: 1/14/1992 10:28:22
+
+ Returns: Error codes:
+ FS_BUFFER_TO_SMALL
+ FS_BAD_INPUT_DATA
+ SUCCESS
+
+ Notes: For getting file name, be aware that this function
+ will copy a '\0' into the buffer but does not count it
+ in the size returned. For example:
+ the file name - FRED.BKS
+ we will copy - FRED.BKS\0
+ and size will equal - 8
+
+ See also: NTFS_ModPathDDB()
+
+**/
+INT16 NTFS_ModFnameFDB(
+FSYS_HAND fsh , /* I - File system handle */
+BOOLEAN set_it , /* I - TRUE if setting file name, FALSE if getting */
+DBLK_PTR dblk , /* I - Descriptor block to get file name from */
+CHAR_PTR buf , /*I/O- file name to read (or to write) */
+INT16 *size ) /*I/O- byte size buffer on entry and exit */
+{
+ UINT16 cch_temp_size ; // len of temp_name in CHARs w/o NULL term
+ CHAR temp_name[13] ;
+ INT16 ret_val = SUCCESS ;
+ NTFS_DBLK_PTR ddblk ;
+
+ fsh ;
+
+ ddblk = (NTFS_DBLK_PTR) dblk;
+
+ if ( set_it ) {
+
+ if ( size == NULL ) {
+ cch_temp_size = (INT16)strlen( buf ) ;
+ }
+ else {
+ cch_temp_size = *size / sizeof (CHAR);
+ }
+
+
+ ret_val = NTFS_SetupFileNameInFDB( fsh, dblk, buf, 0 );
+
+ ddblk->name_complete = TRUE ;
+
+ } else { /* get data from FDB */
+
+ strcpy( buf, ddblk->full_name_ptr->name );
+ }
+
+ return ret_val ;
+}
+/**/
+/**
+
+ Name: NTFS_ModPathDDB()
+
+ Description: This function gets/sets the path in an DDB
+
+ Modified: 1/14/1992 10:30:16
+
+ Returns: Error Codes:
+ FS_BUFFER_TO_SMALL
+ FS_BAD_INPUT_DATA
+ SUCCESS
+
+ Notes:
+
+ See also: NTFS_ModFnameFDB()
+
+**/
+INT16 NTFS_ModPathDDB(
+FSYS_HAND fsh , /* I - File system handle */
+BOOLEAN set_it , /* I - TRUE if setting path, FALSE if getting */
+DBLK_PTR dblk , /* I - Descriptor block to get path from */
+CHAR_PTR buf , /*I/O- path to read (or to write) */
+INT16 *size ) /*I/O- byte size of buffer on entry and exit */
+{
+ INT16 ret_val = SUCCESS ;
+ CHAR_PTR pos ;
+ NTFS_DBLK_PTR ddblk ;
+
+ fsh ;
+
+ ddblk = (NTFS_DBLK_PTR) dblk ;
+
+ if ( set_it ) {
+
+ ret_val = NTFS_SetupPathInDDB( fsh, dblk, NULL, NULL, *size ) ;
+
+ if ( ret_val == SUCCESS ) {
+ memcpy( ddblk->full_name_ptr->name, buf, *size ) ;
+ ddblk->full_name_ptr->name_size = *size ;
+
+ NTFS_FixPath( ddblk->full_name_ptr->name,
+ &ddblk->full_name_ptr->name_size,
+ fsh->attached_dle->info.ntfs->fname_leng );
+
+ ddblk->name_complete = TRUE ;
+
+ }
+
+
+ } else { /* get path */
+
+ strcpy( buf, ddblk->full_name_ptr->name ) ;
+
+ pos = strchr( buf, TEXT('\\') ) ;
+ while ( pos != NULL ) {
+
+ *pos = TEXT('\0') ;
+
+ pos = strchr( pos + 1, TEXT('\\') ) ;
+ }
+ }
+
+ return ret_val ;
+}
+
+/**/
+/**
+
+ Name: NTFS_GetOSFnameFDB()
+
+ Description: This function copies the OS file name in the specified
+ FDB to the specified buffer. The OS file name is the same as
+ the "normal" file name during backup. During restore, the
+ OS file name is the name stored on tape.
+
+ Modified: 1/14/1992 11:8:26
+
+ Returns: Error codes
+ FS_BUFFER_TO_SMALL
+ SUCCESS
+
+ Notes:
+
+ See also: NTFS_ModFnameFDB()
+
+**/
+INT16 NTFS_GetOSFnameFDB( dblk, buf )
+DBLK_PTR dblk ; /* I - Descriptor block to get path from */
+CHAR_PTR buf ; /* O - buffer to place path in */
+{
+ NTFS_DBLK_PTR ddblk = (NTFS_DBLK_PTR)dblk;
+ CHAR_PTR os_name ;
+ UINT16 os_name_size ;
+
+ if ( dblk->com.os_name != NULL )
+ {
+ os_name = dblk->com.os_name->name ;
+ os_name_size = dblk->com.os_name->name_size ;
+ }
+ else
+ {
+ os_name = ddblk->full_name_ptr->name ;
+ os_name_size = ddblk->full_name_ptr->name_size ;
+ }
+
+ memcpy( buf, os_name, os_name_size ) ;
+
+ return SUCCESS ;
+}
+
+/**/
+/**
+
+ Name: NTFS_GetOSPathDDB()
+
+ Description: This function copies the OS path in the specified
+ DDB to the specified buffer. The OS path is the same as
+ the "normal" path during backup. During restore, the
+ OS path name is the name stored on tape.
+
+ Modified: 1/14/1992 11:9:5
+
+ Returns: Error codes:
+ FS_BUFFER_TO_SMALL
+ SUCCESS
+
+ Notes:
+
+ See also: NTFS_GetOSFnameFDB()
+
+**/
+INT16 NTFS_GetOSPathDDB( fsh, dblk, buf )
+FSYS_HAND fsh ; /* I - File System handle */
+DBLK_PTR dblk ; /* I - Descriptor block to get path from */
+CHAR_PTR buf ; /*I/O- path to read (or to write) */
+{
+ CHAR_PTR pos ;
+ CHAR_PTR os_name ;
+ INT16 os_name_size ;
+ NTFS_DBLK_PTR ddblk ;
+
+ (VOID)fsh ;
+
+ ddblk = (NTFS_DBLK_PTR) dblk;
+
+ if ( dblk->com.os_name != NULL )
+ {
+ os_name = dblk->com.os_name->name ;
+ os_name_size = dblk->com.os_name->name_size ;
+ }
+ else
+ {
+ os_name = ddblk->full_name_ptr->name ;
+ os_name_size = ddblk->full_name_ptr->name_size ;
+ }
+
+
+ memcpy( buf, os_name, os_name_size ) ;
+
+ if ( dblk->com.os_name == NULL ) // Backup only
+ {
+
+ pos = strchr( buf, TEXT('\\') );
+ while ( pos != NULL )
+ {
+ *pos = TEXT('\0') ;
+ pos = strchr( pos+1, TEXT('\\') ) ;
+ }
+ }
+
+ return SUCCESS ;
+}
+/**/
+/**
+
+ Name: NTFS_GetFileVerFDB()
+
+ Description: Since DOS does not support file versions, this
+ function simply sets the version number to 0.
+
+ Modified: 1/14/1992 11:9:39
+
+ Returns: SUCCESS
+
+ Notes:
+
+**/
+INT16 NTFS_GetFileVerFDB( dblk, version )
+DBLK_PTR dblk ;
+UINT32 *version ;
+{
+ dblk ;
+ *version = 0 ;
+ return SUCCESS ;
+}
+/**/
+/**
+
+ Name: NTFS_GetCdateDBLK()
+
+ Description: Pretend Creation date is same as Modify date
+
+ Modified: 1/14/1992 11:10:9
+
+ Returns: SUCCESS
+
+ Notes:
+
+ See also: NTFS_ModBdate(), NTFS_GetMdate(), NTFS_ModAdate()
+
+**/
+INT16 NTFS_GetCdateDBLK( dblk, buf )
+DBLK_PTR dblk ; /* I - Descriptor block to get creation date */
+DATE_TIME_PTR buf ; /*I/O- createion date to read (or to write) */
+{
+ NTFS_DBLK_PTR ddblk = (NTFS_DBLK_PTR)dblk ;
+ SYSTEMTIME systime ;
+
+ // Make sure date is valid -- some dblk date/times are set to zero
+ // for invalidity
+ if ( (ddblk->dta.create_time.dwLowDateTime == 0) &&
+ (ddblk->dta.create_time.dwHighDateTime == 0) )
+ {
+ // TF doesn't want noise in their structures
+ memset( buf, 0, sizeof(*buf) );
+ }
+ else
+ {
+ FILETIME local_time ;
+
+ FileTimeToLocalFileTime( &ddblk->dta.create_time, &local_time ) ;
+ FileTimeToSystemTime( &local_time, &systime ) ;
+
+ buf->date_valid = TRUE ;
+ buf->year = systime.wYear ;
+ buf->month = systime.wMonth ;
+ buf->day = systime.wDay ;
+ buf->hour = systime.wHour ;
+ buf->minute = systime.wMinute ;
+ buf->second = systime.wSecond ;
+ buf->day_of_week = systime.wDayOfWeek ;
+ }
+
+ return SUCCESS ;
+}
+
+/**/
+/**
+
+ Name: NTFS_GetMdateDBLK()
+
+ Description: This function copies the modified date/time into (or out of)
+ the provided buffer.
+
+ Modified: 1/14/1992 11:20:6
+
+ Returns: SUCCESS
+
+ Notes:
+
+ See also: NTFS_GetCdate(), NTFS_ModBdate(), NTFS_ModAdate()
+
+**/
+INT16 NTFS_GetMdateDBLK( dblk, buf )
+DBLK_PTR dblk ; /* I - Descriptor block to get creation date */
+DATE_TIME_PTR buf ; /* O - modify date to write */
+{
+ NTFS_DBLK_PTR ddblk = (NTFS_DBLK_PTR)dblk ;
+ SYSTEMTIME systime ;
+
+ // Make sure date is valid -- some dblk date/times are set to zero
+ // for invalidity
+
+ if ( (ddblk->dta.modify_time.dwLowDateTime == 0) &&
+ (ddblk->dta.modify_time.dwHighDateTime == 0) )
+ {
+ // TF doesn't want noise in their structures
+ memset( buf, 0, sizeof(*buf) );
+ }
+ else
+ {
+ FILETIME local_time ;
+
+ FileTimeToLocalFileTime( &ddblk->dta.modify_time, &local_time ) ;
+ FileTimeToSystemTime( &local_time, &systime ) ;
+
+ buf->date_valid = TRUE ;
+ buf->year = systime.wYear ;
+ buf->month = systime.wMonth ;
+ buf->day = systime.wDay ;
+ buf->hour = systime.wHour ;
+ buf->minute = systime.wMinute ;
+ buf->second = systime.wSecond ;
+ buf->day_of_week = systime.wDayOfWeek ;
+ }
+
+ return SUCCESS ;
+}
+
+
+/**/
+/**
+
+ Name: NTFS_ModBdateDBLK()
+
+ Description: This function copies the backup date/time into (or out of)
+ the provided buffer.
+
+ Modified: 8/15/1989
+
+ Returns: SUCCESS
+
+ Notes:
+
+ See also: $/SEE( NTFS_GetCdate(), NTFS_GetMdate(), NTFS_ModAdate()
+
+**/
+INT16 NTFS_ModBdateDBLK(
+BOOLEAN set_it , /* I - TRUE if setting creation date, FALSE if getting */
+DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+DATE_TIME_PTR buf ) /*I/O- createion date to read (or to write) */
+{
+ dblk;
+
+ if ( !set_it ) {
+
+ buf->date_valid = FALSE;
+ }
+
+ return SUCCESS ;
+}
+/**/
+/**
+
+ Name: NTFS_ModAdateDBLK()
+
+ Description: This function copies the access date/time into (or out ot )
+ the provided buffer.
+
+ Modified: 1/14/1992 11:21:53
+
+ Returns: SUCCESS
+
+ See also: NTFS_GetCdate(), NTFS_GetMdate(), NTFS_ModBdate()
+
+**/
+INT16 NTFS_ModAdateDBLK(
+BOOLEAN set_it , /* I - TRUE if setting creation date, FALSE if getting */
+DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+DATE_TIME_PTR buf ) /*I/O- createion date to read (or to write) */
+{
+ NTFS_DBLK_PTR ddblk = (NTFS_DBLK_PTR)dblk ;
+ SYSTEMTIME systime;
+
+ if ( set_it )
+ {
+ FILETIME local_time ;
+
+ systime.wYear = buf->year ;
+ systime.wMonth = buf->month ;
+ systime.wDay = buf->day ;
+ systime.wHour = buf->hour ;
+ systime.wMinute = buf->minute ;
+ systime.wSecond = buf->second ;
+
+ SystemTimeToFileTime( &systime, &local_time ) ;
+ LocalFileTimeToFileTime( &local_time, &ddblk->dta.access_time ) ;
+ }
+ else
+ {
+ // Make sure date is valid -- some dblk date/times are set to zero
+ // for invalidity
+
+ if ( (ddblk->dta.access_time.dwLowDateTime == 0) &&
+ (ddblk->dta.access_time.dwHighDateTime == 0) )
+ {
+ // TF doesn't want noise in their structures
+ memset( buf, 0, sizeof(*buf) );
+ }
+ else
+ {
+ FILETIME local_time ;
+
+ FileTimeToLocalFileTime( &ddblk->dta.access_time, &local_time ) ;
+ FileTimeToSystemTime( &local_time, &systime ) ;
+
+ buf->date_valid = TRUE ;
+ buf->year = systime.wYear ;
+ buf->month = systime.wMonth ;
+ buf->day = systime.wDay ;
+ buf->hour = systime.wHour ;
+ buf->minute = systime.wMinute ;
+ buf->second = systime.wSecond ;
+ buf->day_of_week = systime.wDayOfWeek ;
+ }
+ }
+ return SUCCESS ;
+}
+/**/
+/**
+
+ Name: NTFS_GetDisplaySizeDBLK()
+
+ Description: This function returns the generic size of a DBLK.
+ For a file, this is the file size. For a directory this is
+ allways 0.
+
+ Modified: 1/14/1992 12:15:33
+
+ Returns: Number of generic data bytes.
+
+ Notes:
+
+**/
+UINT64 NTFS_GetDisplaySizeDBLK( fsh, dblk )
+FSYS_HAND fsh ; /* I - File system handle */
+DBLK_PTR dblk ; /* I - Descriptor block to get generic data size for */
+{
+ UINT64 size ;
+ NTFS_DBLK_PTR ddblk;
+
+ fsh ;
+
+ ddblk = (NTFS_DBLK_PTR) dblk;
+
+ size = U64_Init( 0, 0 ) ;
+
+ if ( ddblk->blk_type == FDB_ID ) {
+
+ size = ddblk->dta.size ;
+
+ }
+
+ return size;
+}
+
+/**/
+/**
+
+ Name: NTFS_ModAttribDBLK()
+
+ Description: This function copies the generic attributes into
+ (or out of) the specified DBLK.
+
+ Modified: 1/14/1992 12:15:59
+
+ Returns: SUCCESS
+
+ Notes: This only supports FDBs and DDBs. This should be called
+ by the FS_... function NOT by a macro.
+
+**/
+INT16 NTFS_ModAttribDBLK(
+BOOLEAN set_it , /* I - TRUE if we are seting data */
+DBLK_PTR dblk , /*I/O- dblk to read or write data from */
+UINT32 *attrib ) /*I/O- attributre read or written */
+{
+ NTFS_DBLK_PTR ddblk ;
+ UINT32 temp_atrib = *attrib ;
+
+ ddblk = (NTFS_DBLK_PTR) dblk;
+
+ if ( set_it ) {
+
+ switch ( dblk->blk_type ) {
+ case CFDB_ID:
+ ((CFDB_PTR)dblk)->attributes = *attrib ;
+ break ;
+ case VCB_ID:
+ ((VCB_PTR)dblk)->vcb_attributes = *attrib ;
+ break ;
+ case DDB_ID:
+ case FDB_ID:
+ if ( dblk->blk_type == DDB_ID ) {
+ ddblk->b.d.ddb_attrib = *attrib ;
+ } else {
+ ddblk->b.f.fdb_attrib = *attrib ;
+ }
+
+ if ( *attrib & OBJ_HIDDEN_BIT ) {
+ ddblk->dta.os_attr |= FILE_ATTRIBUTE_HIDDEN ;
+ } else {
+ ddblk->dta.os_attr &= ~FILE_ATTRIBUTE_HIDDEN ;
+ }
+ if ( *attrib & OBJ_READONLY_BIT ) {
+ ddblk->dta.os_attr |= FILE_ATTRIBUTE_READONLY ;
+ } else {
+ ddblk->dta.os_attr &= ~FILE_ATTRIBUTE_READONLY ;
+ }
+ if ( *attrib & OBJ_SYSTEM_BIT ) {
+ ddblk->dta.os_attr |= FILE_ATTRIBUTE_SYSTEM ;
+ } else {
+ ddblk->dta.os_attr &= ~FILE_ATTRIBUTE_SYSTEM ;
+ }
+ if ( *attrib & OBJ_MODIFIED_BIT ) {
+ ddblk->dta.os_attr |= FILE_ATTRIBUTE_ARCHIVE ;
+ } else {
+ ddblk->dta.os_attr &= ~FILE_ATTRIBUTE_ARCHIVE ;
+ }
+ break ;
+ default :
+ break ;
+ }
+
+ }
+ else { /* get data */
+ switch ( dblk->blk_type ) {
+ case CFDB_ID:
+ *attrib = ((CFDB_PTR)dblk)->attributes ;
+ break ;
+ case VCB_ID:
+ *attrib = ((VCB_PTR)dblk)->vcb_attributes ;
+ break ;
+ case DDB_ID:
+ case FDB_ID:
+ if ( dblk->blk_type == DDB_ID ) {
+ *attrib = ddblk->b.d.ddb_attrib ;
+ } else if ( dblk->blk_type == FDB_ID ) {
+ *attrib = ddblk->b.f.fdb_attrib ;
+ }
+
+ if ( ddblk->dta.os_attr & FILE_ATTRIBUTE_READONLY ) {
+ *attrib |= OBJ_READONLY_BIT ;
+ } else {
+ *attrib &= ~OBJ_READONLY_BIT ;
+ }
+
+ if ( ddblk->dta.os_attr & FILE_ATTRIBUTE_ARCHIVE ) {
+ *attrib |= OBJ_MODIFIED_BIT ;
+ } else {
+ *attrib &= ~OBJ_MODIFIED_BIT ;
+ }
+
+ if ( ddblk->dta.os_attr & FILE_ATTRIBUTE_HIDDEN ) {
+ *attrib |= OBJ_HIDDEN_BIT ;
+ } else {
+ *attrib &= ~OBJ_HIDDEN_BIT ;
+ }
+
+ if ( ddblk->dta.os_attr & FILE_ATTRIBUTE_SYSTEM ) {
+ *attrib |= OBJ_SYSTEM_BIT ;
+ } else {
+ *attrib &= ~OBJ_SYSTEM_BIT ;
+ }
+
+ break ;
+ default:
+ *attrib = 0 ;
+ }
+ }
+ return SUCCESS ;
+}
+/**/
+/**
+
+ Name: NTFS_GetObjTypeDBLK()
+
+ Description: This function looks at the os_id in the provided DBLK
+ and returns the type of the object.
+
+ Modified: 1/14/1992 12:16:32
+
+ Returns: SUCCESS
+
+ Notes: If the os_id is unknown then type is UNKNOWN_OBJECT
+
+**/
+/* begin declaration */
+INT16 NTFS_GetObjTypeDBLK( dblk, type )
+DBLK_PTR dblk ; /* I - Descriptor block to get type of */
+OBJECT_TYPE *type ; /* O - type of DBLK */
+{
+ msassert( type != NULL );
+
+ dblk ;
+ *type = DOS_OBJECT ;
+
+ return( SUCCESS ) ;
+}
+
+
+/**/
+/**
+
+ Name: NTFS_GetOS_InfoDBLK()
+
+ Description: This function returns the OS info for the DOS
+ file system
+
+ Modified: 1/14/1992 12:16:55
+
+ Returns: Error Code
+ FS_BUFFER_TO_SMALL
+ SUCCESS
+
+ Notes: This file system has no OS info.
+
+**/
+/* begin declaration */
+INT16 NTFS_GetOS_InfoDBLK( dblk, os_info, size )
+DBLK_PTR dblk ; /* I - DBLK to get the info from */
+BYTE_PTR os_info ; /* O - Buffer to place data */
+INT16 *size ; /*I/O- Buffer size / data length */
+{
+ NT_FILE_OS_INFO UNALIGNED *file_info ;
+ NT_DIR_OS_INFO UNALIGNED *dir_info ;
+ NTFS_DBLK_PTR ddblk ;
+
+ ddblk = (NTFS_DBLK_PTR) dblk ;
+
+ if ( dblk->blk_type == BT_DDB ) {
+
+ dir_info = (NT_DIR_OS_INFO UNALIGNED *) os_info ;
+ dir_info->dir_attributes = ddblk->dta.os_attr ;
+ *size = sizeof ( NT_DIR_OS_INFO ) ;
+
+ } else if ( ddblk->blk_type == BT_FDB ) {
+
+ file_info = (NT_FILE_OS_INFO UNALIGNED *) os_info ;
+ file_info->file_attributes = ddblk->dta.os_attr ;
+ file_info->linkOnly = ddblk->b.f.linkOnly;
+ *size = sizeof ( NT_FILE_OS_INFO ) ;
+
+ // if short name exist then back it up
+
+ if ( ddblk->b.f.alt_name[0] != TEXT('\0') ) {
+
+ file_info->short_name_size = strsize( ddblk->b.f.alt_name ) ;
+ file_info->short_name_offset = sizeof( *file_info ) ;
+ memcpy( (INT8_PTR)(file_info + 1),
+ ddblk->b.f.alt_name,
+ file_info->short_name_size ) ;
+ *size += file_info->short_name_size ;
+
+ } else {
+ file_info->short_name_size = 0 ;
+ file_info->short_name_offset = 0 ;
+ }
+
+ } else {
+
+ *size = 0 ;
+ }
+
+ return SUCCESS ;
+}
+
+/**/
+/**
+
+ Name: NTFS_GetActualSizeDBLK
+
+ Description: This function returns the actual size of a DBLK.
+
+ Modified: 1/14/1992 12:17:33
+
+ Returns: The number of bytes
+
+ Notes:
+
+**/
+/* begin declaration */
+INT16 NTFS_GetActualSizeDBLK( fsh, dblk )
+FSYS_HAND fsh ;
+DBLK_PTR dblk ;
+{
+
+ NTFS_DBLK *ddb ;
+ INT16 size ;
+
+ fsh ;
+
+ ddb = (NTFS_DBLK_PTR)dblk ;
+ size = sizeof( NTFS_DBLK ) ;
+
+ switch( dblk->blk_type ) {
+
+ case DDB_ID:
+ case FDB_ID :
+ break ;
+
+ default:
+ size = 0 ;
+ break ;
+
+ }
+
+ return size ;
+}
+
+/**/
+/**
+
+ Name: NTFS_SetOwnerId()
+
+ Description: does nothing
+
+ Modified: 1/14/1992 12:18:25
+
+ Returns: none
+
+ Notes:
+
+**/
+VOID NTFS_SetOwnerId( fsh, dblk, id )
+FSYS_HAND fsh ; /* I - File system handle */
+DBLK_PTR dblk ; /* O - DBLK to modify */
+UINT32 id ; /* I - value to set it to */
+{
+ fsh ;
+ dblk ;
+ id ;
+}
+
+/**/
+/**
+
+ Name: NTFS_ProcessDDB()
+
+ Description: This function allways returns FALSE to
+ specify that directories should not be restored
+ if there are no file to restore into the directory.
+
+ Modified: 10/23/1989
+
+ Returns: FALSE
+
+ Notes:
+
+**/
+/* begin declaration */
+BOOLEAN NTFS_ProcessDDB( fsh, ddb )
+FSYS_HAND fsh; /* I - file system handle */
+DBLK_PTR ddb; /* I - Directory information */
+{
+ fsh;
+ ddb;
+
+ return TRUE ;
+}
+
+
+/**/
+/**
+
+ Name: NTFS_EnumSpecialFiles()
+
+ Description: This function enumerates the special files. For NT
+ the application asks if registry files are to be included
+ before the restore process starts... Thus this function has
+ no purpose.
+
+ Modified: 5/21/1992 19:28:51
+
+ Returns: FS_NO_MORE
+
+ Notes: Starting index must be 0
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 NTFS_EnumSpecFiles( dle, index, path, psize, fname )
+GENERIC_DLE_PTR dle ;
+UINT16 *index ;
+CHAR_PTR *path ;
+INT16 *psize ;
+CHAR_PTR *fname ;
+{
+ CHAR_PTR p ;
+ static CHAR registry_path[ MAX_PATH ] ;
+ BOOLEAN hasSpecialFiles;
+
+ hasSpecialFiles = DLE_HasFeatures( dle, DLE_FEAT_REST_SPECIAL_FILES );
+
+ if ( (*index < 2) && hasSpecialFiles ) {
+
+ *fname = TEXT( "*.") ;
+
+ strcpy( registry_path, dle->info.ntfs->registry_path + strlen( dle->device_name ) + 1 ) ;
+ *psize = strsize( registry_path ) ;
+
+ for( p = registry_path; *p != TEXT('\0'); p++ ) {
+ if ( *p == '\\' ) {
+ *p = TEXT('\0') ;
+ p++ ;
+ }
+ }
+
+ *path = registry_path ;
+
+ *index = 2 ;
+ return SUCCESS ;
+ } else {
+ return FS_NO_MORE ;
+ }
+}
+/**/
+/**
+
+ Name: NTFS_SpecExcludeObj
+
+ Description: This function tells the caller what kind of file a file is.
+ The possibilities are:
+ FS_NORMAL_FILE
+ FS_SPECIAL_DIR
+ FS_SPECIAL_FILE
+ FS_EXCLUDE_FILE
+
+ This function is used to exclude / include the registry. The
+ assumptions are that the nt_system directory contains the following
+ files:
+ Active registry files
+ Inactive registry files
+ Useless .LOG and .ALT files
+ Event logger data files.
+
+
+ Modified: 1/10/1990
+
+ Returns: FS_NORMAL_FILE because this file system has no special
+ files.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 NTFS_SpecExcludeObj(
+FSYS_HAND fsh, /* I - File system handle */
+DBLK_PTR ddb, /* I - Descriptor block of ddb */
+DBLK_PTR fdb ) /* I - Descriptor block of fdb */
+{
+ NTFS_DBLK_PTR nt_fdb = (NTFS_DBLK_PTR)fdb;
+ NTFS_DBLK_PTR nt_ddb = (NTFS_DBLK_PTR)ddb;
+ CHAR_PTR name ;
+ BOOLEAN is_reg_dir = FALSE ;
+
+ return FS_NORMAL_FILE ;
+
+ //Special files are handled differently for ntbackup
+
+ if ( ( nt_fdb != NULL ) && ( nt_ddb != NULL ) ) {
+
+ if ( NTFS_GetRegistryPathSize(fsh->attached_dle) != 0 ) {
+
+ CHAR *p ;
+
+ p = strchr( NTFS_GetRegistryPath( fsh->attached_dle ), TEXT( '\\' ) ) ;
+
+ if ( (p != NULL ) && !stricmp( p+1, nt_ddb->full_name_ptr->name ) ) {
+ is_reg_dir = TRUE ;
+ }
+ }
+
+
+ if ( is_reg_dir ) {
+
+ name = strrchr( nt_fdb->full_name_ptr->name, TEXT('.') ) ;
+
+ if ( name != NULL ) {
+ if ( !stricmp( name, TEXT(".ALT") ) ||
+ !stricmp( name, TEXT(".LOG") ) ) {
+
+ return FS_EXCLUDE_FILE ;
+ }
+ }
+
+ if ( ( name == NULL ) || ( name[1] == TEXT('\0') ) ) {
+ return FS_SPECIAL_FILE ;
+ }
+ }
+ }
+ return FS_NORMAL_FILE ;
+}
+/**/
+/**
+
+ Name: NTFS_MaynToMSoft()
+
+ Description: Translates a Maynard MTF stream ID to a Microsoft
+ BackupRead/BackupWrite stream ID.
+
+ Modified: 05-Oct-92
+
+ Returns: Translated ID if translateable,
+ source ID passed if not.
+
+**/
+UINT32 NTFS_MaynToMSoft( UINT32 maynID )
+{
+ int i;
+ UINT32 ret = maynID;
+ static ID_TRANS_TABLE transTable[] =
+ /* source id ========> result ID */
+ { { STRM_GENERIC_DATA, BACKUP_DATA },
+ { STRM_NT_EA, BACKUP_EA_DATA },
+ { STRM_NT_ACL, BACKUP_SECURITY_DATA },
+ { STRM_NTFS_ALT_DATA, BACKUP_ALTERNATE_DATA },
+ { STRM_NTFS_LINK, BACKUP_LINK },
+ { STRM_INVALID, 0 } /* End of table */
+ };
+
+ for ( i = 0; ( transTable[i].maynID != STRM_INVALID ); i++ )
+ {
+ if ( transTable[i].maynID == maynID )
+ {
+ ret = transTable[i].msoftID;
+ break;
+ }
+ }
+ return ret;
+}
+
+/**/
+/**
+
+ Name: NTFS_MSoftToMayn()
+
+ Description: Translates a Microsoft BackupRead/BackupWrite stream ID
+ to a Maynard MTF stream ID.
+
+ Modified: 05-Oct-92
+
+ Returns: Translated ID if translateable,
+ source ID passed if not.
+
+**/
+UINT32 NTFS_MSoftToMayn( UINT32 msoftID )
+{
+ int i;
+ UINT32 ret = msoftID;
+ static ID_TRANS_TABLE transTable[] =
+ /* result id <=========== source ID */
+ { { STRM_GENERIC_DATA, BACKUP_DATA },
+ { STRM_NT_EA, BACKUP_EA_DATA },
+ { STRM_NT_ACL, BACKUP_SECURITY_DATA },
+ { STRM_NTFS_ALT_DATA, BACKUP_ALTERNATE_DATA },
+ { STRM_NTFS_LINK, BACKUP_LINK },
+ { STRM_INVALID, 0 }
+ };
+
+ for ( i = 0; ( transTable[i].maynID != STRM_INVALID ); i++ )
+ {
+ if ( transTable[i].msoftID == msoftID )
+ {
+ ret = transTable[i].maynID;
+ break;
+ }
+ }
+ return ret;
+}
+
+
diff --git a/private/utils/ntbackup/src/tname.c b/private/utils/ntbackup/src/tname.c
new file mode 100644
index 000000000..e7284a3fa
--- /dev/null
+++ b/private/utils/ntbackup/src/tname.c
@@ -0,0 +1,185 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tname.c
+
+
+ Description: This file contains code to get the device name and
+ volume name for the given DLE.
+
+
+ $Log: T:/LOGFILES/TNAME.C_V $
+
+ Rev 1.6 11 Nov 1992 09:53:44 GREGG
+Unicodeized literals.
+
+ Rev 1.5 07 Oct 1992 14:14:50 STEVEN
+check if volume_label is NULL
+
+ Rev 1.4 07 Oct 1992 13:50:52 DAVEV
+unicode strlen verification
+
+ Rev 1.3 04 Sep 1992 14:28:58 STEVEN
+volume name was wrong
+
+ Rev 1.2 03 Sep 1992 17:06:32 STEVEN
+add support for volume name
+
+ Rev 1.1 21 May 1992 13:50:56 STEVEN
+more long path stuff
+
+ Rev 1.0 18 May 1992 14:29:14 STEVEN
+Initial revision.
+
+ Rev 1.1 16 Dec 1991 17:26:48 STEVEN
+move common functions to tables
+
+ Rev 1.0 10 Dec 1991 09:06:54 STEVEN
+Initial revision.
+
+**/
+#include <windows.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "stdtypes.h"
+#include "msassert.h"
+#include "fsys.h"
+
+/**/
+/**
+
+ Name: NTFS_DeviceDispName()
+
+ Description: This function gets the displayable device name for
+ a DLE. This name is displayed for drive select.
+
+ Modified: 9/13/1989
+
+ Returns: SUCCESS
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+INT16 NTFS_DeviceDispName( dle, dev_name, size, type )
+GENERIC_DLE_PTR dle;
+CHAR_PTR dev_name;
+INT16 size ;
+INT16 type ;
+{
+ INT16 req_size = 0 ;
+ CHAR_PTR path = NULL ;
+ INT16 temp_size = 0 ;
+
+ (VOID)type;
+
+ req_size = (INT16)(3 * sizeof(CHAR) ) ;
+ if ( dle->info.ntfs->volume_label != NULL ) {
+ req_size += strsize( dle->info.ntfs->volume_label ) ;
+ }
+
+ if ( size < req_size ) {
+ return FS_BUFFER_TO_SMALL ;
+ }
+
+ strcpy( dev_name, dle->device_name ) ;
+ if ( dle->info.ntfs->volume_label != NULL ) {
+ strcat( dev_name, TEXT(" ") ) ;
+ strcat( dev_name, dle->info.ntfs->volume_label ) ;
+ }
+
+ return SUCCESS ;
+}
+/**/
+/**
+
+ Name: GEN_GetVolName()
+
+ Description: This function coppies the volume name
+ of the specified drive to the buffer provided.
+
+ Modified: 12/4/1991 9:45:49
+
+**/
+VOID NTFS_GetVolName( dle, buffer )
+GENERIC_DLE_PTR dle;
+CHAR_PTR buffer ;
+{
+ if ( dle->type & HAND_MADE_MASK ) {
+ strcpy( buffer, dle->info.user->vol_name ) ;
+
+ } else {
+
+ if ( dle->info.ntfs->volume_label != NULL ) {
+ strcpy( buffer, dle->device_name ) ;
+ strcat( buffer, TEXT(" ") ) ;
+ strcat( buffer, dle->info.ntfs->volume_label ) ;
+ } else {
+ strcpy( buffer, dle->device_name ) ;
+ }
+ }
+}
+
+/**/
+/**
+
+ Name: NTFS_SizeofVolName()
+
+ Description: This function returns the size of the volume name
+ which will be created by DLE_GetVolName()
+
+ Modified: 12/4/1991 11:14:25
+
+ Returns: size of string including \0;
+
+**/
+INT16 NTFS_SizeofVolName( dle )
+GENERIC_DLE_PTR dle ;
+{
+ INT16 size ;
+
+ if ( dle->type & HAND_MADE_MASK ) {
+ size = (INT16)strsize( dle->info.user->vol_name ) ;
+
+ } else if ( dle->info.ntfs->volume_label == NULL ) {
+ size = 3 * sizeof (CHAR);
+
+ } else {
+ size = (INT16)((strlen( dle->info.ntfs->volume_label ) + 4) * sizeof(CHAR)) ;
+
+ }
+
+ return( size ) ;
+}
+
+/**/
+/**
+
+ Name: NTFS_InitMakeData()
+
+ Description: This function is used to initialize the parameter block
+ which is passed to CreateDBLK.
+
+ Modified: 12/4/1991 14:57:3
+
+ Returns: NONE
+
+ Notes:
+
+**/
+VOID NTFS_InitMakeData(
+FSYS_HAND fsh,
+INT16 blk_type,
+CREATE_DBLK_PTR data ) {
+
+ data->v.std_data.os_id = FS_NTFS_ID ;
+ data->v.std_data.os_ver = FS_NTFS_VER ;
+
+
+ return ;
+}
diff --git a/private/utils/ntbackup/src/topen.c b/private/utils/ntbackup/src/topen.c
new file mode 100644
index 000000000..4b477abec
--- /dev/null
+++ b/private/utils/ntbackup/src/topen.c
@@ -0,0 +1,1339 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: topen.c
+
+ Description: This file contains code to open files
+ and directories.
+
+ $Log: N:\logfiles\topen.c_v $
+
+ Rev 1.56.1.3 15 Jul 1994 19:50:54 STEVEN
+fix more net errors
+
+ Rev 1.56.1.2 17 Jun 1994 20:05:10 STEVEN
+fix bug with net dissconect
+
+ Rev 1.56.1.1 06 May 1994 18:06:36 STEVEN
+fix bug with CONFIG dir on NTFS
+
+ Rev 1.56.1.0 26 Apr 1994 19:01:12 STEVEN
+fis dissconnect bug
+
+ Rev 1.56 04 Jan 1994 20:20:40 BARRY
+Revised fix for access date/time for read-only files and shares
+
+ Rev 1.55 03 Jan 1994 18:42:16 BARRY
+Open files on FS_READ and FS_VERIFY with GENERIC_READ | GENERIC_WRITE.
+(We have to "write" to the file to reset the access date/time
+upon close.)
+
+ Rev 1.54 03 Jan 1994 18:12:18 BARRY
+Changed open flags for increased performance
+
+ Rev 1.53 30 Nov 1993 16:17:12 BARRY
+Added call NTFS_GetTempName for verify in case file has a temp name
+
+ Rev 1.52 24 Nov 1993 14:46:38 BARRY
+Unicode fixes
+
+ Rev 1.51 19 Jul 1993 11:39:28 BARRY
+Open directories for share_write
+
+ Rev 1.50 16 Jul 1993 11:43:20 BARRY
+Don't verify event files.
+
+ Rev 1.49 29 Jun 1993 16:17:04 BARRY
+Skip registry files on verify.
+
+ Rev 1.48 02 Jun 1993 14:40:14 BARRY
+Link fixes.
+
+ Rev 1.47 03 May 1993 20:44:44 BARRY
+Clean up error handling when a remote machine goes away.
+
+ Rev 1.46 02 May 1993 19:46:50 BARRY
+Incorporated Steve's fix for skipping .LOG files on floating registries.
+
+ Rev 1.45 24 Apr 1993 17:24:52 BARRY
+Release the work path semaphore on linked files before returning.
+
+ Rev 1.44 02 Apr 1993 11:49:16 BARRY
+Return more appropriate values on errors in OpenDir
+
+ Rev 1.43 31 Mar 1993 22:10:16 BARRY
+Fixed problem opening read-only directories for WRITE.
+
+ Rev 1.42 12 Mar 1993 15:26:44 STEVEN
+added support for ERROR BAD PATHNAME
+
+ Rev 1.41 24 Feb 1993 15:37:12 BARRY
+Fixed restore of active files when write errors occur.
+
+ Rev 1.40 18 Feb 1993 12:43:50 TIMN
+Report error msg for unsuccessful file open calls EPR(0008)
+
+ Rev 1.39 04 Feb 1993 15:10:42 BARRY
+Fixed open of files in POSIX mode.
+
+ Rev 1.38 01 Feb 1993 19:46:26 STEVEN
+bug fixes
+
+ Rev 1.37 15 Jan 1993 13:18:38 BARRY
+added support for new error messages and backup priviladge
+
+ Rev 1.36 29 Dec 1992 13:32:56 DAVEV
+unicode fixes (3)
+
+ Rev 1.35 14 Dec 1992 16:36:48 STEVEN
+directories not in use just access denied
+
+ Rev 1.34 07 Dec 1992 14:18:38 STEVEN
+updates from msoft
+
+ Rev 1.33 25 Nov 1992 16:42:28 BARRY
+Fix MakeTempFile and restore over active files.
+
+ Rev 1.32 25 Nov 1992 09:09:12 STEVEN
+OpenEventLog returns NULL if file cannot be opened
+
+ Rev 1.31 24 Nov 1992 11:01:56 BARRY
+Changes to make LINK streams null-impregnated.
+
+ Rev 1.30 23 Nov 1992 09:32:12 STEVEN
+fix support for event log
+
+ Rev 1.29 17 Nov 1992 16:13:58 BARRY
+Null-out link path on each new object.
+
+ Rev 1.28 11 Nov 1992 09:53:34 GREGG
+Unicodeized literals.
+
+ Rev 1.27 10 Nov 1992 13:59:44 STEVEN
+fix open change dir problem
+
+ Rev 1.26 10 Nov 1992 10:12:52 BARRY
+Initialize new structure members for verify changes.
+
+ Rev 1.25 10 Nov 1992 08:19:00 STEVEN
+removed path and name from dblk now use full_name_ptr
+
+ Rev 1.24 30 Oct 1992 14:02:40 BARRY
+Fixed a syntactical mistake.
+
+ Rev 1.23 29 Oct 1992 16:53:00 BARRY
+Do nothing for linked files.
+
+ Rev 1.22 28 Oct 1992 12:13:20 STEVEN
+add support for EventLogs
+
+ Rev 1.21 23 Oct 1992 14:59:56 BARRY
+add init for needStreamHeader
+
+ Rev 1.20 20 Oct 1992 14:22:26 STEVEN
+temp names should not have .TMP extension
+
+ Rev 1.16 12 Oct 1992 17:46:00 STEVEN
+now processes ACL
+
+ Rev 1.15 08 Oct 1992 12:25:00 STEVEN
+initialize the hand
+
+ Rev 1.14 07 Oct 1992 15:40:38 STEVEN
+added stdmath.h
+
+ Rev 1.13 07 Oct 1992 14:22:08 STEVEN
+fix typos
+
+ Rev 1.12 07 Oct 1992 13:50:34 DAVEV
+unicode strlen verification
+
+ Rev 1.11 01 Oct 1992 13:27:12 STEVEN
+lets open us some directories
+
+ Rev 1.10 24 Sep 1992 13:24:02 BARRY
+Changes for huge file name support.
+
+ Rev 1.9 20 Aug 1992 14:02:44 BURT
+fix warnings
+
+ Rev 1.8 17 Aug 1992 16:17:24 STEVEN
+fix warnings
+
+ Rev 1.7 12 Aug 1992 17:48:16 STEVEN
+fixed bugs at microsoft
+
+ Rev 1.6 29 May 1992 13:45:26 STEVEN
+fixes
+
+ Rev 1.5 22 May 1992 16:05:18 STEVEN
+
+
+ Rev 1.4 21 May 1992 13:50:58 STEVEN
+more long path stuff
+
+ Rev 1.3 04 May 1992 09:25:16 LORIB
+Changes for variable length paths.
+
+ Rev 1.2 12 Mar 1992 15:50:14 STEVEN
+64 bit changes
+
+ Rev 1.1 28 Feb 1992 13:03:36 STEVEN
+step one for varible length paths
+
+ Rev 1.0 07 Feb 1992 16:41:12 STEVEN
+Initial revision.
+
+**/
+#include <windows.h>
+#include <winioctl.h>
+#include <string.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "std_err.h"
+
+#include "beconfig.h"
+#include "msassert.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "fsys_err.h"
+#include "ntfsdblk.h"
+#include "ntfs_fs.h"
+#include "tfldefs.h"
+
+/* Maximum number of attempts to create a temporary file */
+
+#define MAX_ATTEMPTS 65535
+
+
+/*
+ * Common flags for open. In other words, flags we ALWAYS want to use
+ * on calls to CreateFile
+ */
+#define NTFS_OPEN_FLAGS ( FILE_ATTRIBUTE_NORMAL | \
+ FILE_FLAG_BACKUP_SEMANTICS | \
+ FILE_FLAG_SEQUENTIAL_SCAN )
+
+
+static INT16 NTFS_OpenFile( FSYS_HAND fsh, FILE_HAND hand, NTFS_DBLK_PTR fdb, INT16 MODE );
+static INT16 NTFS_OpenDir( FSYS_HAND fsh, FILE_HAND hand, NTFS_DBLK_PTR fdb, INT16 MODE );
+
+static HANDLE NTFS_TryOpenNormal( FSYS_HAND fsh,
+ FILE_HAND hand,
+ NTFS_DBLK_PTR ddblk,
+ CHAR_PTR path,
+ INT16 mode,
+ BOOLEAN in_use,
+ INT posix_flag,
+ INT_PTR status ) ;
+
+static HANDLE NTFS_TryOpenRegistryFile( FILE_HAND fsh, NTFS_DBLK_PTR ddblk, CHAR_PTR path, BOOLEAN *log_file ) ;
+static HANDLE NTFS_TryOpenEventFile( FILE_HAND fsh, NTFS_DBLK_PTR ddblk, CHAR_PTR path ) ;
+static INT16 TranslateOpenError( FILE_HAND hand, DWORD error );
+
+/**/
+
+/**
+
+ Name: NTFS_OpenObj()
+
+ Description: This function opens files or directories.
+
+ Modified: 7/28/1989
+
+ Returns: Error Codes
+ OUT_OF_MEMORY
+ FS_NOT_FOUND
+ FS_ACCESS_DENIED
+ FS_IN_USE_ERROR
+ FS_OPENED_INUSE
+ SUCCESS
+
+ Notes: Valid modes are : READ, WRITE, & VERIFY
+ If a VCB is passed in then this function returns SUCCESS
+
+ See also: $/SEE( NTFS_OpenFile() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 NTFS_OpenObj( fsh, hand, dblk, mode )
+FSYS_HAND fsh ; /* I - file system that the file is opened on */
+FILE_HAND *hand ; /* O - allocated handle */
+DBLK_PTR dblk; /*I/O- describes the file to be opened */
+OPEN_MODE mode ; /* I - open mode */
+{
+ GENERIC_DLE_PTR dle ;
+ INT16 hand_size ;
+ INT16 ret_val = SUCCESS;
+ NTFS_DBLK_PTR ddblk;
+
+ msassert( dblk != NULL );
+
+ ddblk = (NTFS_DBLK_PTR) dblk;
+
+ msassert( fsh->attached_dle != NULL );
+ msassert( (dblk->blk_type == FDB_ID) || (dblk->blk_type == DDB_ID) ) ;
+
+ dle = fsh->attached_dle ;
+
+ if ( fsh->hand_in_use ) {
+ hand_size = sizeof( FILE_HAND_STRUCT ) + sizeof ( NTFS_OBJ_HAND );
+ *hand = (FILE_HAND) calloc( 1, hand_size ) ;
+ if ( *hand == NULL ) {
+ ret_val = OUT_OF_MEMORY ;
+ }
+
+ } else {
+ *hand = fsh->file_hand ;
+ fsh->hand_in_use = TRUE ;
+ }
+
+ (*hand)->obj_hand.ptr = (VOID_PTR)((*hand) + 1) ;
+ memset( (*hand)->obj_hand.ptr, 0, sizeof( NTFS_OBJ_HAND ) ) ;
+
+
+ if ( ret_val == SUCCESS ) {
+
+ NTFS_OBJ_HAND_PTR nt_hand = (*hand)->obj_hand.ptr;
+ NTFS_FSYS_RESERVED_PTR res = fsh->reserved.ptr;
+
+ (*hand)->fsh = fsh ;
+ (*hand)->mode = (INT16)mode ;
+ (*hand)->dblk = dblk ;
+
+ nt_hand->nameComplete = FALSE;
+ nt_hand->needStreamHeader = TRUE;
+ nt_hand->streamsAllVisited = FALSE;
+ nt_hand->verifyStreamPos = 0;
+ nt_hand->sawSecurity = FALSE;
+ nt_hand->writeError = FALSE;
+ res->streamIDCount = 0;
+
+ if ( nt_hand->linkBuffer != NULL )
+ {
+ *nt_hand->linkBuffer = TEXT ('\0');
+ }
+ nt_hand->linkNameLen = 0;
+
+
+ switch( dblk->blk_type ){
+
+ case FDB_ID :
+
+ ret_val = NTFS_OpenFile( fsh, *hand, ddblk, (INT16)mode ) ;
+ break ;
+
+ case DDB_ID :
+ ret_val = FS_SavePath( fsh, (UINT8_PTR)TEXT("\\"), 2 * sizeof(CHAR) ) ;
+ if ( ret_val == SUCCESS ) {
+ ret_val = FS_AppendPath( fsh,
+ (UINT8_PTR)ddblk->full_name_ptr->name,
+ (INT16)(strsize( ddblk->full_name_ptr->name )) ) ;
+ }
+
+ if ( ret_val == SUCCESS ) {
+ ret_val = NTFS_OpenDir( fsh, *hand, ddblk, (INT16)mode ) ;
+ }
+ break ;
+
+ case VCB_ID :
+
+ ret_val = SUCCESS ;
+ break ;
+
+ default :
+
+ ret_val = FS_BAD_DBLK ;
+ }
+ }
+
+ if ( ( fsh->attached_dle->info.ntfs->vol_flags & FS_FILE_COMPRESSION ) &&
+ ( mode == FS_WRITE ) &&
+ !(ddblk->b.f.linkOnly) &&
+ ( ret_val == SUCCESS ) ) {
+
+ INT16 compress_mode= 0 ;
+ INT bytes_returned ;
+
+ if ( ddblk->dta.os_attr & FILE_ATTRIBUTE_COMPRESSED ) {
+ compress_mode = 1 ;
+ }
+ if ( !DeviceIoControl(
+ ((NTFS_OBJ_HAND_PTR)(*hand)->obj_hand.ptr)->fhand,
+ FSCTL_SET_COMPRESSION,
+ &compress_mode,
+ 2,
+ NULL,
+ 0,
+ &bytes_returned,
+ NULL) ) {
+
+ ret_val = FS_COMPRES_RESET_FAIL;
+ }
+ }
+
+ if ( ( ret_val != FS_COMPRES_RESET_FAIL ) &&
+ ( ret_val != SUCCESS ) &&
+ ( ret_val != FS_OPENED_INUSE ) ) {
+ if( fsh->file_hand == *hand ) {
+ fsh->hand_in_use = FALSE ;
+ memset( *hand, 0, sizeof( FILE_HAND_STRUCT ) ) ;
+ } else {
+ free( *hand ) ;
+ }
+ }
+
+ return ret_val ;
+}
+/**/
+/**
+
+ Name: NTFS_OpenFile()
+
+ Description: This function opens a file in the current directory.
+ If the file is in use AND we are opening for READ then we
+ will attempt to open the file in DENY_NONE mode. If this
+ is successful then we lock all the records of the file.
+ For VERIFY we allways open in DENY_NONE
+ mode.
+
+ Modified: 7/28/1989
+
+ Returns: Error Codes.
+ FS_NOT_FOUND
+ FS_ACCESS_DENIED
+ FS_IN_USE_ERROR
+ FS_OPENED_INUSE
+ SUCCESS
+
+ Declaration:
+
+**/
+/* begin declaration */
+static INT16 NTFS_OpenFile(
+FSYS_HAND fsh , /* I - file system that the file is opened on */
+FILE_HAND hand , /* O - allocated handle */
+NTFS_DBLK_PTR ddblk , /*I/O- describes the file to be opened */
+INT16 mode ) /* I - open mode */
+{
+ DWORD new_size_low ;
+ DWORD new_size_high ;
+ CHAR_PTR path ;
+ DWORD open_mode ;
+ DWORD open_share ;
+ DWORD create_mode ;
+ HANDLE temp_hand ;
+ INT16 ret_val ;
+ NTFS_OBJ_HAND_PTR nt_hand ;
+ INT posix_flag = 0 ;
+ BOOLEAN log_file ;
+ INT status ;
+
+ nt_hand = ((NTFS_OBJ_HAND_PTR)hand->obj_hand.ptr) ;
+
+ hand->opened_in_use = FALSE ;
+ hand->fsh = fsh ;
+ hand->size = 0 ;
+ hand->obj_pos = 0 ;
+
+ if ( (mode == FS_WRITE) && ((NTFS_DBLK_PTR)(hand->dblk))->b.f.linkOnly )
+ {
+ return SUCCESS;
+ }
+
+ if ( NTFS_SetupWorkPath( fsh,
+ fsh->cur_dir,
+ ddblk->full_name_ptr->name,
+ &path ) != SUCCESS) {
+ return OUT_OF_MEMORY ;
+ }
+
+ if ( ddblk->b.f.PosixFile ) {
+ posix_flag = FILE_FLAG_POSIX_SEMANTICS ;
+ }
+
+ if( ( mode == FS_WRITE ) && ( ddblk->b.f.handle != 0 ) )
+ {
+ temp_hand = (HANDLE)ddblk->b.f.handle ;
+ nt_hand->registry_file = ddblk->b.f.hand_registry ;
+ nt_hand->temp_file = ddblk->b.f.hand_temp_name ;
+ ret_val = SUCCESS ;
+ }
+ else
+ {
+ if ( mode == FS_VERIFY )
+ {
+ path = NTFS_GetTempName( path );
+ }
+
+
+ temp_hand = NTFS_TryOpenNormal( fsh, hand, ddblk, path, mode, FALSE, posix_flag, &status ) ;
+
+ if ( temp_hand != INVALID_HANDLE_VALUE )
+ {
+ ret_val = SUCCESS ;
+ }
+ else
+ {
+ ret_val = TranslateOpenError( hand, status );
+
+ }
+
+ if ( (ret_val == FS_IN_USE_ERROR ) &&
+ (mode == FS_READ) &&
+ (BEC_GetBackupFilesInUse(fsh->cfg)) )
+ {
+ /*
+ * If the file is in use, opening with ability to reset
+ * attributes and dates is pointless.
+ */
+ temp_hand = NTFS_TryOpenNormal( fsh,
+ hand,
+ ddblk,
+ path,
+ mode,
+ TRUE,
+ posix_flag,
+ &status ) ;
+
+
+ if ( temp_hand != INVALID_HANDLE_VALUE )
+ {
+
+ ret_val = SUCCESS ;
+ }
+ else
+ {
+
+ ret_val = TranslateOpenError( hand, status );
+
+ }
+
+
+ if ( ret_val == SUCCESS )
+ {
+ if ( LockFile( temp_hand, 0L, 0L, 0xffffffffL, 0x7fffffffL ) )
+ {
+ hand->opened_in_use = TRUE ;
+ ddblk->b.f.fdb_attrib |= FILE_IN_USE_BIT ;
+ ret_val = FS_OPENED_INUSE ;
+ }
+ else
+ {
+ NTFS_DebugPrint( TEXT("NTFS_OpenFile: LockFile error %d")
+ TEXT(" on file \"%s\""),
+ (int)GetLastError(),
+ path );
+
+ CloseHandle( temp_hand ) ;
+ ret_val = FS_IN_USE_ERROR ;
+ }
+ }
+ }
+
+ if ( ( temp_hand == INVALID_HANDLE_VALUE ) && ( mode != FS_WRITE ) ) {
+
+ CHAR event_name[256] ;
+
+ if ( (mode == FS_VERIFY) &&
+ (REG_IsRegistryFile( hand->fsh->attached_dle, path ) ||
+ REG_IsEventFile( hand->fsh->attached_dle, path, &event_name[0] ))) {
+
+ NTFS_ReleaseWorkPath( fsh ) ;
+
+ return FS_SKIP_OBJECT;
+
+ } else {
+
+ temp_hand = NTFS_TryOpenRegistryFile( hand, ddblk, path, &log_file ) ;
+
+ if ( temp_hand != INVALID_HANDLE_VALUE ) {
+ ret_val = SUCCESS ;
+ } else {
+ if ( log_file ) {
+ ret_val = FS_NOT_FOUND ;
+ }
+ }
+ }
+ }
+
+ if ( ( temp_hand == INVALID_HANDLE_VALUE ) && ( mode != FS_WRITE ) ) {
+
+ temp_hand = NTFS_TryOpenEventFile( hand, ddblk, path ) ;
+
+ if ( temp_hand != INVALID_HANDLE_VALUE ) {
+ ret_val = SUCCESS ;
+ }
+ }
+ }
+
+ if ( ( mode == FS_READ ) && ( temp_hand != INVALID_HANDLE_VALUE ) ) {
+ new_size_low = GetFileSize( temp_hand, &new_size_high ) ;
+ if ( ( new_size_low != 0xffffffff ) || !GetLastError() ) {
+ ddblk->dta.size = U64_Init( (UINT32)new_size_low, (UINT32)new_size_high ) ;
+ }
+ }
+
+ NTFS_ReleaseWorkPath( fsh ) ;
+
+ if( ( ret_val == SUCCESS ) || ( ret_val == FS_OPENED_INUSE ) ) {
+
+ ((NTFS_OBJ_HAND_PTR)hand->obj_hand.ptr)->fhand = temp_hand ;
+ ((NTFS_OBJ_HAND_PTR)hand->obj_hand.ptr)->context = NULL ;
+
+ hand->size = 0 ;
+ }
+
+ /* Let's collect the link information for this file */
+ if ( (mode == FS_READ) &&
+ ((ret_val == SUCCESS) || (ret_val == FS_OPENED_INUSE)) )
+ {
+ BY_HANDLE_FILE_INFORMATION info;
+ HANDLE fhand;
+
+ fhand = ((NTFS_OBJ_HAND_PTR)hand->obj_hand.ptr)->fhand;
+
+ if ( GetFileInformationByHandle( fhand, &info ) )
+ {
+ NTFS_LINK_Q_ELEM_PTR linkElem = NULL;
+
+ ddblk->b.f.idHi = info.nFileIndexHigh;
+ ddblk->b.f.idLo = info.nFileIndexLow;
+ ddblk->b.f.linkCount = info.nNumberOfLinks;
+
+ if ( ddblk->b.f.linkCount > 1 )
+ {
+ linkElem = NTFS_SearchLinkQueue( fsh,
+ ddblk->b.f.idHi,
+ ddblk->b.f.idLo );
+ }
+
+ /*
+ * If there is a file with the same ID in the link q already,
+ * then set up the linkOnly flag in the DBLK. When ReadObj
+ * is called, only the path and file name will be backed up.
+ */
+ ddblk->b.f.linkOnly = (linkElem != NULL);
+ ((NTFS_OBJ_HAND_PTR)hand->obj_hand.ptr)->linkPtr = linkElem;
+ }
+ else
+ {
+ /*
+ * If we can't get the info, then we better do what's
+ * necessary for the file to be backed up normally.
+ */
+ ddblk->b.f.idLo = 0;
+ ddblk->b.f.idHi = 0;
+ ddblk->b.f.linkOnly = FALSE;
+ ddblk->b.f.linkCount = 1;
+ }
+ }
+ return ret_val ;
+}
+
+/**/
+/**
+
+ Name: NTFS_TryOpenNormalFile()
+
+ Description: This function opens a file a "normal" file specified
+ by the path passed in. A "normal" file is one that can be
+ opened with CreateFile(). It is not a Registry file or an
+ event file.
+
+ Since we want to open with the most possible access, we have to
+ try the highest access mode and then move to less access as we
+ get failures.
+
+ Modified: 1/7/95
+
+ Returns: NT file handle
+
+ Declaration:
+
+**/
+static HANDLE NTFS_TryOpenNormal( FSYS_HAND fsh,
+ FILE_HAND hand,
+ NTFS_DBLK_PTR ddblk,
+ CHAR_PTR path,
+ INT16 mode,
+ BOOLEAN in_use,
+ INT posix_flag,
+ INT_PTR status ) {
+
+ DWORD open_mode ;
+ DWORD open_share ;
+ DWORD create_mode ;
+ HANDLE temp_hand ;
+ INT16 ret_val ;
+
+ open_share = FILE_SHARE_READ ;
+
+ switch ( mode ) {
+
+ case FS_VERIFY:
+ open_share |= FILE_SHARE_WRITE ;
+ case FS_READ:
+ open_mode = GENERIC_READ | FILE_WRITE_ATTRIBUTES | ACCESS_SYSTEM_SECURITY ;
+ create_mode = OPEN_EXISTING ;
+
+ if ( in_use ) {
+ open_share |= FILE_SHARE_WRITE ;
+ open_mode &= ~FILE_WRITE_ATTRIBUTES ;
+ }
+
+ break ;
+
+ case FS_WRITE:
+ default :
+ msassert( FALSE );
+ }
+
+
+ temp_hand = CreateFile( path,
+ open_mode,
+ open_share,
+ NULL,
+ create_mode,
+ NTFS_OPEN_FLAGS | posix_flag,
+ NULL ) ;
+
+
+ if ( temp_hand == INVALID_HANDLE_VALUE )
+ {
+ *status = GetLastError();
+
+ NTFS_DebugPrint( TEXT("NTFS_OpenFile: CreateFile(1) error %d")
+ TEXT(" on file \"%s\""),
+ *status,
+ path );
+
+ ret_val = TranslateOpenError( hand, *status );
+
+ /*
+ * If we opened with the POSIX bit and the file wasn't found,
+ * let's try to open without POSIX and see what happens.
+ */
+
+ if ( posix_flag && ddblk->b.f.PosixFile && (ret_val == FS_NOT_FOUND) ) {
+
+ posix_flag = 0;
+
+ temp_hand = NTFS_TryOpenNormal( fsh, hand, ddblk, path, mode, in_use, posix_flag, status ) ;
+
+ } else if ( mode == FS_WRITE ) {
+ return ( temp_hand ) ;
+
+ } else {
+ ret_val = SUCCESS ;
+ if ( open_mode & FILE_WRITE_ATTRIBUTES ) {
+ open_mode &= ~FILE_WRITE_ATTRIBUTES ;
+
+ temp_hand = CreateFile( path,
+ open_mode,
+ open_share,
+ NULL,
+ create_mode,
+ NTFS_OPEN_FLAGS | posix_flag,
+ NULL ) ;
+ }
+
+
+ if ( temp_hand == INVALID_HANDLE_VALUE )
+ {
+ *status = GetLastError();
+
+ NTFS_DebugPrint( TEXT("NTFS_OpenFile: CreateFile(2) error %d")
+ TEXT(" on file \"%s\""),
+ *status,
+ path );
+
+ ret_val = TranslateOpenError( hand, *status );
+ }
+
+ if ( ret_val == FS_ACCESS_DENIED )
+ {
+
+ ret_val = SUCCESS ;
+ if ( !in_use ) {
+ open_mode |= FILE_WRITE_ATTRIBUTES ;
+ }
+ open_mode &= ~ACCESS_SYSTEM_SECURITY ;
+
+ temp_hand = CreateFile( path,
+ open_mode,
+ open_share,
+ NULL,
+ create_mode,
+ NTFS_OPEN_FLAGS | posix_flag,
+ NULL ) ;
+
+
+ if ( temp_hand == INVALID_HANDLE_VALUE )
+ {
+ *status = GetLastError();
+
+ NTFS_DebugPrint( TEXT("NTFS_OpenFile: CreateFile(3) error %d")
+ TEXT(" on file \"%s\""),
+ *status,
+ path );
+
+ ret_val = TranslateOpenError( hand, *status );
+ }
+ }
+
+ if ( !in_use && (ret_val == FS_ACCESS_DENIED) )
+ {
+
+ ret_val = SUCCESS ;
+ open_mode &= ~FILE_WRITE_ATTRIBUTES ;
+
+ temp_hand = CreateFile( path,
+ open_mode,
+ open_share,
+ NULL,
+ create_mode,
+ NTFS_OPEN_FLAGS | posix_flag,
+ NULL ) ;
+
+
+ if ( temp_hand == INVALID_HANDLE_VALUE )
+ {
+ *status = GetLastError();
+
+ NTFS_DebugPrint( TEXT("NTFS_OpenFile: CreateFile(4) error %d")
+ TEXT(" on file \"%s\""),
+ *status,
+ path );
+
+ }
+ }
+ }
+ }
+ return temp_hand ;
+}
+
+
+/**/
+/**
+
+ Name: NTFS_OpenDir()
+
+ Description: This function opens a directory for for processing.
+ If this is a special Object we will open the special file.
+ Otherwise we will process any long path followed by any
+ data associated with the object.
+
+ Modified: 5/21/1992 17:54:42
+
+ Returns: Error Codes.
+ FS_NOT_FOUND
+ SUCCESS
+
+ Declaration:
+
+**/
+/* begin declaration */
+static INT16 NTFS_OpenDir(
+FSYS_HAND fsh , /* I - file system that the file is opened on */
+FILE_HAND hand , /* O - allocated handle */
+NTFS_DBLK_PTR ddblk, /*I/O- describes the file to be opened */
+INT16 mode ) /* I - open mode */
+{
+ CHAR_PTR path ;
+ DWORD open_mode ;
+ DWORD create_mode ;
+ DWORD share_write = 0 ;
+ HANDLE temp_hand ;
+ INT16 ret_val = SUCCESS ;
+ DWORD osError = NO_ERROR;
+
+ hand->opened_in_use = FALSE ;
+ hand->fsh = fsh ;
+ hand->size = 0 ;
+ hand->obj_pos = 0 ;
+
+ if ( NTFS_SetupWorkPath( fsh, fsh->cur_dir, NULL, &path ) != SUCCESS)
+ {
+ return OUT_OF_MEMORY ;
+ }
+
+ switch ( mode ) {
+
+ case FS_READ:
+ case FS_VERIFY:
+ open_mode = GENERIC_READ | ACCESS_SYSTEM_SECURITY ;
+ create_mode = OPEN_EXISTING ;
+ break ;
+
+ case FS_WRITE:
+ open_mode = GENERIC_WRITE | ACCESS_SYSTEM_SECURITY | WRITE_DAC | WRITE_OWNER ;
+ create_mode = OPEN_ALWAYS ;
+ share_write = FILE_SHARE_WRITE ;
+ break ;
+
+ default :
+ msassert( FALSE );
+
+ }
+
+ temp_hand = CreateFile( path,
+ open_mode,
+ FILE_SHARE_READ | share_write,
+ NULL,
+ create_mode,
+ NTFS_OPEN_FLAGS,
+ NULL ) ;
+
+
+ if ( temp_hand == INVALID_HANDLE_VALUE )
+ {
+ DWORD dirAttrs;
+
+ osError = GetLastError();
+
+ NTFS_DebugPrint( TEXT("NTFS_OpenDir: CreateFile(1) error %d")
+ TEXT(" on dir \"%s\""),
+ (int)osError,
+ path );
+
+
+ dirAttrs = GetFileAttributes( path );
+
+ /*
+ * If the open failed, examine the attributes to see if maybe
+ * the directory has some funny attributes set on it that are
+ * preventing us for opening with write permission. If that's
+ * the case, clear all the attributes and try again. If the
+ * open still failed, restore the attributes to what they were.
+ */
+
+ if ( (dirAttrs != FILE_ATTRIBUTE_NORMAL) &&
+ (dirAttrs != 0xffffffff) && ( mode == FS_WRITE ) )
+ {
+
+ SetFileAttributes( path, FILE_ATTRIBUTE_NORMAL );
+
+ temp_hand = CreateFile( path,
+ open_mode,
+ FILE_SHARE_READ | share_write,
+ NULL,
+ create_mode,
+ NTFS_OPEN_FLAGS,
+ NULL ) ;
+
+ if ( temp_hand == INVALID_HANDLE_VALUE )
+ {
+ osError = GetLastError();
+
+ NTFS_DebugPrint( TEXT("NTFS_OpenDir: CreateFile(2) error %d")
+ TEXT(" on dir \"%s\""),
+ (int)osError,
+ path );
+
+ open_mode &= ~ACCESS_SYSTEM_SECURITY ;
+
+ temp_hand = CreateFile( path,
+ open_mode,
+ FILE_SHARE_READ | share_write,
+ NULL,
+ create_mode,
+ NTFS_OPEN_FLAGS,
+ NULL ) ;
+ }
+
+ if ( temp_hand == INVALID_HANDLE_VALUE )
+ {
+ osError = GetLastError();
+ SetFileAttributes( path, dirAttrs );
+
+ NTFS_DebugPrint( TEXT("NTFS_OpenDir: CreateFile(3) error %d")
+ TEXT(" on dir \"%s\""),
+ (int)osError,
+ path );
+
+
+ }
+ }
+ else
+ {
+
+ open_mode &= ~ACCESS_SYSTEM_SECURITY ;
+
+ temp_hand = CreateFile( path,
+ open_mode,
+ FILE_SHARE_READ | share_write,
+ NULL,
+ create_mode,
+ NTFS_OPEN_FLAGS,
+ NULL ) ;
+
+
+ if ( temp_hand == INVALID_HANDLE_VALUE )
+ {
+ DWORD dirAttrs;
+
+ osError = GetLastError();
+
+ NTFS_DebugPrint( TEXT("NTFS_OpenDir: CreateFile(4) error %d")
+ TEXT(" on dir \"%s\""),
+ (int)osError,
+ path );
+ }
+ }
+ }
+
+
+ NTFS_ReleaseWorkPath( fsh ) ;
+
+ if ( temp_hand != INVALID_HANDLE_VALUE )
+ {
+ ((NTFS_OBJ_HAND_PTR)hand->obj_hand.ptr)->fhand = temp_hand ;
+ ((NTFS_OBJ_HAND_PTR)hand->obj_hand.ptr)->context = NULL ;
+ hand->size = 0 ;
+ ret_val = SUCCESS ;
+ }
+ else
+ {
+ ret_val = TranslateOpenError( hand, osError );
+ }
+ return ret_val ;
+}
+
+static HANDLE NTFS_TryOpenRegistryFile(
+FILE_HAND hand,
+NTFS_DBLK_PTR ddblk,
+CHAR_PTR path,
+BOOLEAN *log_file )
+{
+ CHAR_PTR temp_name ;
+ HANDLE temp_hand = INVALID_HANDLE_VALUE ;
+ NTFS_OBJ_HAND_PTR nt_hand ;
+
+ *log_file = FALSE ;
+
+ nt_hand = ((NTFS_OBJ_HAND_PTR)hand->obj_hand.ptr) ;
+
+ if ( !REG_IsRegistryFile( hand->fsh->attached_dle, path ) )
+ {
+ CHAR *p ;
+ p = strrchr( path, TEXT('.')) ;
+ if ( p != NULL )
+ {
+ *p = TEXT('\0') ;
+
+ if ( REG_IsRegistryFile( hand->fsh->attached_dle, path ) )
+ {
+ *log_file = TRUE ;
+ }
+ *p = TEXT('.') ;
+ }
+ return INVALID_HANDLE_VALUE ;
+ }
+ else
+ { // the file is a registry file
+
+ temp_name = NTFS_MakeTempName( path, TEXT("REG") ) ;
+ if ( temp_name == NULL )
+ {
+ return INVALID_HANDLE_VALUE ;
+ }
+
+ if ( REG_BackupRegistryFile( hand->fsh->attached_dle,
+ path,
+ temp_name ) != SUCCESS )
+ {
+ CHAR *p;
+
+ free( temp_name ) ;
+
+ p = strrchr( path, TEXT('\\') ) ;
+ if ( p== NULL ) {
+ return INVALID_HANDLE_VALUE ;
+ }
+
+ *p = TEXT('\0') ;
+ temp_name = NTFS_MakeTempName( path, TEXT("REG") ) ;
+ *p = TEXT('\\') ;
+
+ if ( temp_name == NULL )
+ {
+ return INVALID_HANDLE_VALUE ;
+ }
+
+ if ( REG_BackupRegistryFile( hand->fsh->attached_dle,
+ path,
+ temp_name ) != SUCCESS )
+ {
+ free( temp_name ) ;
+ return INVALID_HANDLE_VALUE ;
+ }
+ }
+
+ temp_hand = CreateFile( temp_name,
+ GENERIC_READ | FILE_WRITE_ATTRIBUTES,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ NTFS_OPEN_FLAGS,
+ NULL ) ;
+
+ if ( temp_hand != INVALID_HANDLE_VALUE )
+ {
+ nt_hand->temp_file = temp_name ;
+ nt_hand->registry_file = TRUE ;
+ }
+ else
+ {
+ NTFS_DebugPrint( TEXT("NTFS_TryOpenRegistryFile: CreateFile error %d")
+ TEXT(" on file \"%s\" as temp file \"%s\""),
+ GetLastError(),
+ path,
+ temp_name );
+ }
+ }
+ return temp_hand;
+}
+static HANDLE NTFS_TryOpenEventFile(
+FILE_HAND hand,
+NTFS_DBLK_PTR ddblk,
+CHAR_PTR path )
+{
+ CHAR_PTR temp_name ;
+ HANDLE temp_hand = INVALID_HANDLE_VALUE ;
+ NTFS_OBJ_HAND_PTR nt_hand ;
+ HANDLE evt_hand ;
+ CHAR event_name[256] ;
+
+ nt_hand = ((NTFS_OBJ_HAND_PTR)hand->obj_hand.ptr) ;
+
+ if ( REG_IsEventFile( hand->fsh->attached_dle, path, &event_name[0] ) )
+ {
+ evt_hand = OpenEventLog( NULL, event_name ) ;
+
+ if ( evt_hand == NULL )
+ {
+ return INVALID_HANDLE_VALUE ;
+ }
+ else
+ { // the file is a registry file
+
+ temp_name = NTFS_MakeTempName( path, TEXT("REG") ) ;
+ if ( temp_name == NULL )
+ {
+ return INVALID_HANDLE_VALUE ;
+ }
+
+ if ( BackupEventLog( evt_hand,
+ temp_name ) != TRUE )
+ {
+ CHAR *p;
+
+ free( temp_name ) ;
+ p = strrchr( path, TEXT('\\') ) ;
+ if ( p == NULL ) {
+ CloseEventLog( evt_hand ) ;
+ return INVALID_HANDLE_VALUE ;
+ }
+
+ *p = TEXT('\0') ;
+ temp_name = NTFS_MakeTempName( path, TEXT("REG") ) ;
+ *p = TEXT('\\') ;
+
+ if ( temp_name == NULL )
+ {
+ CloseEventLog( evt_hand ) ;
+ return INVALID_HANDLE_VALUE ;
+ }
+
+ if ( BackupEventLog( evt_hand,
+ temp_name ) != TRUE )
+ {
+
+
+ NTFS_DebugPrint( TEXT("NTFS_TryOpenEventFile: BackupEventLog error %d")
+ TEXT(" on file \"%s\" as temp file \"%s\""),
+ GetLastError(),
+ path,
+ temp_name );
+
+ free( temp_name ) ;
+ CloseEventLog( evt_hand ) ;
+ return INVALID_HANDLE_VALUE ;
+ }
+ }
+
+ CloseEventLog( evt_hand ) ;
+
+ temp_hand = CreateFile( temp_name,
+ GENERIC_READ | FILE_WRITE_ATTRIBUTES,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ NTFS_OPEN_FLAGS,
+ NULL ) ;
+
+ if ( temp_hand != INVALID_HANDLE_VALUE )
+ {
+ nt_hand->temp_file = temp_name ;
+ nt_hand->registry_file = TRUE ;
+ }
+ else
+ {
+ NTFS_DebugPrint( TEXT("NTFS_TryOpenEventFile: CreateFile error %d")
+ TEXT(" on file \"%s\" as temp file \"%s\""),
+ GetLastError(),
+ path,
+ temp_name );
+ }
+ }
+ }
+ return temp_hand;
+}
+
+CHAR_PTR NTFS_MakeTempName(
+CHAR_PTR path,
+CHAR_PTR prefix)
+{
+ static unsigned int counter = 0;
+ unsigned int attempts = 0;
+ CHAR_PTR template ;
+ CHAR_PTR fileName;
+ HANDLE fHandle;
+ BOOLEAN ret = FALSE;
+
+ /* Make sure the path and file name are separated by backslash. */
+
+ template = malloc( strsize( path ) + 15 * sizeof(CHAR) ) ;
+ if ( template == NULL )
+ {
+ return NULL ;
+ }
+ strcpy( template, path );
+
+ if ( (fileName = strrchr( template, TEXT('\\'))) != NULL )
+ {
+ fileName++;
+ }
+ else
+ {
+ fileName = template ;
+ }
+
+ do {
+ if ( counter >= 65535 )
+ {
+ counter = 0; /* Wrap the counter at 16 bits */
+ }
+
+ sprintf( fileName, TEXT("%s%05u"), prefix, counter++ );
+
+ fHandle = CreateFile( template,
+ GENERIC_READ, /* Mode */
+ 0, /* No sharing */
+ NULL, /* Security */
+ OPEN_EXISTING, /* Check only */
+ 0, /* Attributes */
+ 0 ); /* Template file */
+
+ if ( fHandle == INVALID_HANDLE_VALUE )
+ {
+ DWORD lastError;
+
+ /*
+ * This little scheme probably won't work unless the reason
+ * we couldn't open the file is because it wasn't found. If
+ * it wasn't found, we'll assume that we have a shot at
+ * creating it. Otherwise, there's probably no point in
+ * iterating 64K times hunting for a unique file name.
+ */
+
+ lastError = GetLastError( );
+
+ if ( lastError == ERROR_FILE_NOT_FOUND )
+ {
+ ret = TRUE;
+ break;
+ }
+ else if ( lastError != ERROR_SHARING_VIOLATION )
+ {
+ break;
+ }
+ }
+ else
+ {
+ /* We were able to open it, so it exists. Let's try again. */
+ CloseHandle( fHandle );
+ }
+
+ } while ( attempts++ < MAX_ATTEMPTS );
+
+ return template ;
+}
+
+
+static INT16 TranslateOpenError( FILE_HAND hand, DWORD error )
+{
+ INT16 ret_val;
+
+ switch ( error )
+ {
+ case ERROR_SUCCESS:
+ ret_val = SUCCESS;
+ break;
+
+ case ERROR_PRIVILEGE_NOT_HELD :
+ case ERROR_ACCESS_DENIED:
+ ret_val = FS_ACCESS_DENIED;
+ break;
+
+ case ERROR_PATH_NOT_FOUND:
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_INVALID_NAME:
+ case ERROR_BAD_PATHNAME:
+ ret_val = FS_NOT_FOUND;
+ break;
+
+ case ERROR_NETNAME_DELETED:
+ case ERROR_BAD_NET_NAME:
+ case ERROR_BAD_NETPATH:
+ case ERROR_UNEXP_NET_ERR:
+ {
+ GENERIC_DLE_PTR dle = hand->fsh->attached_dle;
+
+ if ( DLE_HasFeatures( dle, DLE_FEAT_REMOTE_DRIVE ) )
+ {
+ // Might be nice to somehow see if the net is really dead.
+ ret_val = FS_COMM_FAILURE;
+ }
+ else
+ {
+ ret_val = FS_ACCESS_DENIED;
+ }
+ break;
+ }
+
+ default:
+ if ( hand->dblk->blk_type == FDB_ID )
+ {
+ // The UI can only handle this error on FDBs -- it
+ // never examines the block type!
+ ret_val = FS_IN_USE_ERROR;
+ }
+ else
+ {
+ ret_val = FS_ACCESS_DENIED;
+ }
+ break;
+ }
+ return ret_val;
+}
+
+
diff --git a/private/utils/ntbackup/src/tposmisc.c b/private/utils/ntbackup/src/tposmisc.c
new file mode 100644
index 000000000..975f6e21b
--- /dev/null
+++ b/private/utils/ntbackup/src/tposmisc.c
@@ -0,0 +1,460 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: tposmisc.c
+
+ Description: Various miscellaneous functions used by the
+ tape positioners.
+
+ $Log: J:\ui\logfiles\tposmisc.c_v $
+
+ Rev 1.27 07 Feb 1994 02:06:08 GREGG
+Fixed and expanded 'extended error reporting'.
+
+ Rev 1.26 28 Jan 1994 10:57:24 MIKEP
+preserve YESYES flag when prompting for tapes
+
+ Rev 1.25 21 Apr 1993 08:46:56 CARLS
+changed ViewDescriptionInVCB to ViewSetName in function UI_DisplayVCB
+
+ Rev 1.24 12 Apr 1993 16:05:54 MIKEP
+fix null pointer check
+
+ Rev 1.23 07 Mar 1993 16:34:26 GREGG
+Call _sleep for OS_WIN32 only.
+
+ Rev 1.22 17 Feb 1993 10:43:50 STEVEN
+changes from mikep
+
+ Rev 1.21 07 Oct 1992 14:54:02 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.20 04 Oct 1992 19:41:22 DAVEV
+Unicode Awk pass
+
+ Rev 1.19 27 Jul 1992 11:10:52 JOHNWT
+ChuckB checked in for John Wright, who is no longer with us.
+
+ Rev 1.18 14 May 1992 17:24:04 MIKEP
+nt pass 2
+
+ Rev 1.17 02 Mar 1992 17:13:42 CARLS
+changes to UI_CheckUserAbort
+
+ Rev 1.16 29 Feb 1992 08:48:16 CARLS
+change to UI_CheckUserAbort - spelling error
+
+ Rev 1.15 29 Feb 1992 08:44:42 CARLS
+change to UI_CheckUserAbort
+
+ Rev 1.14 27 Feb 1992 15:58:06 MIKEP
+remove promptnexttape
+
+ Rev 1.13 25 Feb 1992 21:07:50 GLENN
+Overhauled UI_AskUserForTape and related calls, Replaced gszTprinfBuffer with
+RSM_Sprintf to fix problem with overwriting buffer.
+
+ Rev 1.12 14 Feb 1992 16:28:00 MIKEP
+header changes for NT
+
+ Rev 1.11 22 Jan 1992 16:56:58 JOHNWT
+fixed next tape prompt
+
+ Rev 1.10 21 Jan 1992 16:54:34 JOHNWT
+removed checkyy flag
+
+ Rev 1.9 14 Jan 1992 13:58:44 JOHNWT
+fixed -1 tape # in DISPLAY_BSD_VCB
+
+ Rev 1.8 10 Jan 1992 13:37:10 JOHNWT
+internationalization round 2
+
+ Rev 1.7 10 Jan 1992 12:38:50 JOHNWT
+added UI_DisplayBSDVCB
+
+ Rev 1.6 20 Dec 1991 09:32:58 DAVEV
+16/32 bit port - 2nd pass
+
+ Rev 1.5 18 Dec 1991 14:08:20 GLENN
+Added windows.h
+
+ Rev 1.4 04 Dec 1991 09:19:38 JOHNWT
+changed RES_TAPE_REQUEST format
+
+ Rev 1.3 03 Dec 1991 18:14:28 JOHNWT
+added UI_RequestTape
+
+ Rev 1.2 02 Dec 1991 11:17:18 JOHNWT
+NT full tape msgs
+
+ Rev 1.1 25 Nov 1991 15:29:04 JOHNWT
+removed yprompt
+
+ Rev 1.0 20 Nov 1991 19:28:26 SYSTEM
+Initial revision.
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+static INT16 UI_AskUserForTape( INT, CHAR_PTR );
+
+/*****************************************************************************
+
+ Name: UI_UpdateTpos
+
+ Description: This function updates the TPOS structure used by the
+ tape positioners and Tape Format to reflect the current
+ location on tape for subsequent positioning requests. If
+ the next set is desired by the user, the TPOS backup set
+ entry is incremented from the current VCB set value.
+
+ Returns: UI_NEW_POSITION_REQUESTED or UI_END_POSITIONING
+
+*****************************************************************************/
+UINT16 UI_UpdateTpos(
+TPOS_PTR tpos,
+DBLK_PTR cur_vcb,
+BOOLEAN next_set_desired )
+{
+
+ /* set current tape position defined by the vcb in the tpos structure */
+
+ tpos->tape_id = FS_ViewTapeIDInVCB( cur_vcb );
+ tpos->tape_seq_num = FS_ViewTSNumInVCB( cur_vcb );
+
+ if ( next_set_desired ) {
+ tpos->backup_set_num = (INT16) (FS_ViewBSNumInVCB( cur_vcb ) + 1);
+ return( UI_NEW_POSITION_REQUESTED );
+ }
+ else {
+ tpos->backup_set_num = FS_ViewBSNumInVCB( cur_vcb );
+ return( UI_END_POSITIONING );
+ }
+
+}
+
+/*****************************************************************************
+
+ Name: UI_DisplayVCB
+
+ Description: This function displays the current VCB in the status window
+ and is used by the tape positioners.
+
+ Returns: N/A
+
+*****************************************************************************/
+VOID UI_DisplayVCB( DBLK_PTR vcb_ptr )
+{
+ CHAR date_str[ MAX_UI_DATE_SIZE ];
+ CHAR time_str[ MAX_UI_TIME_SIZE ];
+ DATE_TIME_PTR dt = FS_ViewBackupDateInVCB( vcb_ptr );
+
+ UI_MakeDateString( date_str, dt->month, dt->day, dt->year % 100 );
+ UI_MakeShortTimeString( time_str, dt->hour, dt->minute );
+
+ yresprintf( RES_DISPLAY_VCB,
+ FS_ViewVolNameInVCB( vcb_ptr ),
+ date_str,
+ time_str,
+ FS_ViewBSNumInVCB( vcb_ptr ),
+ FS_ViewTSNumInVCB( vcb_ptr ),
+ FS_ViewSetNameInVCB( vcb_ptr ) );
+
+ JobStatusBackupRestore(JOB_STATUS_LISTBOX);
+
+}
+
+/*****************************************************************************
+
+ Name: UI_DisplayBSDVCB
+
+ Description: This function displays the VCB in the BSD in the status
+ window and is used by the tape positioners.
+
+ Returns: N/A
+
+*****************************************************************************/
+VOID UI_DisplayBSDVCB( BSD_PTR bsd_ptr )
+{
+ CHAR date_str[ MAX_UI_DATE_SIZE ];
+ CHAR time_str[ MAX_UI_TIME_SIZE ];
+ QTC_BSET_PTR bset_ptr;
+
+ INT16 tape_seq_num = -1;
+
+ DATE_TIME_PTR dt = BSD_ViewDate( bsd_ptr );
+
+ UI_MakeDateString( date_str, dt->month, dt->day, dt->year % 100 );
+ UI_MakeShortTimeString( time_str, dt->hour, dt->minute );
+
+
+ bset_ptr = QTC_FindBset( BSD_GetTapeID( bsd_ptr ),
+ BSD_GetTapeNum( bsd_ptr ),
+ BSD_GetSetNum( bsd_ptr ) );
+
+ if ( bset_ptr != NULL ) {
+ tape_seq_num = (INT16)bset_ptr->tape_seq_num;
+ }
+
+ yresprintf( RES_DISPLAY_BSD_VCB,
+ tape_seq_num,
+ BSD_GetTapeLabel( bsd_ptr ),
+ date_str,
+ time_str,
+ BSD_GetSetNum( bsd_ptr ),
+ BSD_GetBackupLabel( bsd_ptr ) );
+
+ JobStatusBackupRestore( JOB_STATUS_LISTBOX );
+
+ lresprintf( LOGGING_FILE, LOG_MSG, SES_ENG_MSG, RES_DISPLAY_BSD_VCB,
+ tape_seq_num,
+ BSD_GetTapeLabel( bsd_ptr ),
+ date_str,
+ time_str,
+ BSD_GetSetNum( bsd_ptr ),
+ BSD_GetBackupLabel( bsd_ptr ) );
+
+}
+
+/*****************************************************************************
+
+ Name: UI_InsertTape
+
+ Description: This function prompts the user to insert a tape into the
+ drive when one had not been supplied previously.
+
+ Returns: ( UI_AskUserForTape() )
+
+*****************************************************************************/
+INT16 UI_InsertTape( CHAR_PTR drive_name )
+{
+
+ return( UI_AskUserForTape( RES_TAPE_NOT_INSERTED, drive_name ) );
+}
+
+/*****************************************************************************
+
+ Name: UI_ReplaceTape
+
+ Description: This function prompts the user if they wish to replace
+ a given tape. A prior call to UI_DisplayVCB should be
+ performed prior to calling this function.
+
+ Returns: ( UI_AskUserForTape() )
+
+*****************************************************************************/
+INT16 UI_ReplaceTape( CHAR_PTR drive_name )
+{
+ return( UI_AskUserForTape( RES_REPLACE_OLD_TAPE, drive_name ) );
+}
+
+/*****************************************************************************
+
+ Name: UI_ReplaceBlankTape
+
+ Description: This function prompts the user to supply a tape with
+ data on it for read functions
+
+ Returns: ( UI_ReplaceTape() )
+
+*****************************************************************************/
+INT16 UI_ReplaceBlankTape( CHAR_PTR drive_name )
+{
+
+ return( UI_AskUserForTape( RES_BLANK_TAPE, drive_name ) );
+}
+
+/*****************************************************************************
+
+ Name: UI_ReplaceForeignTape
+
+ Description: This function prompts the user to replace the tape in
+ the drive with a non-foreign tape
+
+ Returns: ( UI_ReplaceTape() )
+
+*****************************************************************************/
+INT16 UI_ReplaceForeignTape( CHAR_PTR drive_name )
+{
+
+ return( UI_AskUserForTape( RES_FOREIGN_TAPE_MSG, drive_name ) );
+}
+
+/*****************************************************************************
+
+ Name: UI_CheckUserAbort
+
+ Description: Function to check current status of global abort flag and
+ return disposition indicator
+
+ Returns: TRUE or FALSE to indicate user abort should be processed
+
+ Notes: The current TF message is passed to this function, and if
+ the current message is TF_IDLE_NOBREAK, a beep() will be
+ called and the abort condition reset
+
+*****************************************************************************/
+BOOLEAN UI_CheckUserAbort( UINT16 message )
+{
+
+ if ( gb_abort_flag != CONTINUE_PROCESSING ) {
+
+ if ( message == TF_IDLE_NOBREAK ) {
+
+// gb_abort_flag = CONTINUE_PROCESSING ;
+ return FALSE; /* don't abort the operation */
+ }
+ else {
+ return TRUE; /* abort the operation */
+ }
+ }
+ else {
+ return FALSE; /* don't abort the operation */
+ }
+
+}
+
+/*****************************************************************************
+
+ Name: UI_ProcessVCBatEOD
+
+ Description: This function process responses at EOD for read operations.
+ We either for TF back to BOT, or prompt user to supply a
+ new tape.
+
+ Returns: UI_BOT, UI_ABORT_POSITIONING or ( UI_ReplaceTape() )
+
+*****************************************************************************/
+INT16 UI_ProcessVCBatEOD( TPOS_PTR tpos, CHAR_PTR drive_name )
+{
+
+ /* check for needing to get TF to position back to BOT */
+
+ if ( ( tpos->tape_id == -1 ) &&
+ ( tpos->tape_seq_num == -1 ) &&
+ ( tpos->backup_set_num == -1 ) ) {
+ return( (UINT16) UI_BOT );
+ }
+
+ /* we ran out of data on current tape, what does user want to do */
+
+ if ( WM_MessageBox( ID( IDS_MSGTITLE_CONTINUE ),
+ ID( RES_NO_MORE_TAPE_INFO ),
+ WMMB_YESNO,
+ WMMB_ICONQUESTION,
+ ID( RES_CONTINUE_QUEST ), 0, 0 ) ) {
+ return( UI_ReplaceTape( drive_name ) );
+ }
+ else {
+ return( (UINT16) UI_ABORT_POSITIONING );
+ }
+
+}
+
+/*****************************************************************************
+
+ Name: UI_HandleTapeReadError
+
+ Description: Function to produce tape read error message, and prompt
+ user for another tape.
+
+ Returns: UI_NEW_TAPE_INSERTED or UI_ABORT_POSITIONING
+
+*****************************************************************************/
+INT16 UI_HandleTapeReadError( CHAR_PTR drive_name )
+{
+ CHAR text[MAX_UI_RESOURCE_SIZE] ;
+
+ if( UI_GetExtendedErrorString( TFLE_BAD_TAPE, text ) ) {
+ lprintf( LOGGING_FILE, text ) ;
+ WM_MsgBox( ID(IDS_GENERR_TITLE), text, WMMB_OK, WMMB_ICONSTOP ) ;
+ } else {
+ eresprintf( RES_FATAL_TAPE_READ_ERR, drive_name ) ;
+ }
+
+ return( UI_ReplaceTape( drive_name ) ) ;
+}
+
+
+/*****************************************************************************
+
+ Name: UI_AskUserForTape
+
+ Description: Prompt user for new tape, and ask if they wish to continue.
+
+ Returns: UI_NEW_TAPE_INSERTED or UI_ABORT_POSITIONING
+
+*****************************************************************************/
+
+static INT16 UI_AskUserForTape (
+INT res_id,
+CHAR_PTR drive_name )
+{
+ CHAR temp[ MAX_UI_RESOURCE_SIZE ];
+ INT answer;
+ INT OldFlag;
+ UINT16 status;
+
+ RSM_Sprintf( temp, ID( res_id ), drive_name );
+
+ OldFlag = CDS_GetYesFlag( CDS_GetCopy() );
+
+ CDS_SetYesFlag( CDS_GetCopy( ), NO_FLAG );
+
+ answer = WM_MessageBox( ID( IDS_MSGTITLE_INSERT ),
+ temp,
+ WMMB_YESNO,
+ WMMB_ICONQUESTION,
+ ID( RES_CONTINUE_QUEST ),
+ 0l,
+ 0
+ );
+
+ CDS_SetYesFlag( CDS_GetCopy( ), OldFlag );
+
+ if ( answer ) {
+#ifdef OS_WIN32
+ Sleep( (DWORD)3000 );
+#endif
+ status = UI_NEW_TAPE_INSERTED ;
+ }
+ else {
+ status = UI_ABORT_POSITIONING ;
+ }
+ return( (INT16)status );
+}
+
+
+/*****************************************************************************
+
+ Name: UI_ReturnToTOC
+
+ Description: Function to check if within a multi-drive environment and
+ based upon sensitivity to tape change in current drive,
+ return an indication to the caller that TOC is required.
+
+ Returns: BOOLEAN (TRUE or FALSE)
+
+*****************************************************************************/
+BOOLEAN UI_ReturnToTOC( UINT16 channel, BOOLEAN check_tape_change )
+{
+ THW_PTR thw_ptr = BE_GetCurrentDevice( channel );
+
+ if ( thw_ptr->channel_link.q_prev ) {
+ if ( check_tape_change ) {
+ return( (BOOLEAN)( ( thw_ptr->drv_status == TPS_NEW_TAPE ) ||
+ ( thw_ptr->drv_status == TPS_NO_TAPE )) );
+ }
+ else {
+ return( TRUE );
+ }
+ }
+ else {
+ return( FALSE );
+ }
+}
diff --git a/private/utils/ntbackup/src/tprintf.c b/private/utils/ntbackup/src/tprintf.c
new file mode 100644
index 000000000..a8e53f394
--- /dev/null
+++ b/private/utils/ntbackup/src/tprintf.c
@@ -0,0 +1,139 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: tprintf.c
+
+ Description: tprintf functions for "T" commands that perform word wrapping but
+ do not use windows
+
+ $Log: G:/UI/LOGFILES/TPRINTF.C_V $
+
+ Rev 1.9 14 Dec 1993 14:34:12 BARRY
+Fixed an error in last edit for ANSI builds
+
+ Rev 1.8 14 Dec 1993 11:12:26 BARRY
+Changed print buffer to dynamic memory on Unicode
+
+ Rev 1.7 07 Oct 1992 14:50:22 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.6 04 Oct 1992 19:41:24 DAVEV
+Unicode Awk pass
+
+ Rev 1.5 21 May 1992 12:03:32 MIKEP
+change assert to msassert
+
+ Rev 1.4 19 May 1992 11:58:48 MIKEP
+mips changes
+
+ Rev 1.3 18 May 1992 09:06:46 MIKEP
+header
+
+ Rev 1.2 27 Apr 1992 16:14:16 CHUCKB
+Fixed size of print buffer.
+
+ Rev 1.1 29 Jan 1992 18:04:16 DAVEV
+
+
+ * added include <windows.h>
+
+ Rev 1.0 20 Nov 1991 19:35:34 SYSTEM
+Initial revision.
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+#if defined( UNICODE )
+
+#define PRINTF_BUFFER_CHUNK 512 // chunk size for buff realloc
+CHAR_PTR gszTprintfBuffer = NULL;
+static size_t printfBufferCount = 0; // # chars above can hold
+
+#else
+
+#define MAX_WIN_WIDTH 512
+CHAR gszTprintfBuffer[ MAX_WIN_WIDTH + 1 ];
+
+#endif
+
+
+static VOID insert_string( CHAR_PTR buf, CHAR_PTR buf_index, CHAR_PTR insertion ) ;
+
+/*****************************************************************************
+
+ Name: tprintf
+
+ Description: This function is the lowest level print function which handles word wrapping
+ for the "T" commands.
+
+ THIS IS A SPECIAL FUNCTION SPECIFICALLY
+ FOR THE "T" COMMANDS...NO WINDOWS ARE USED
+
+ Returns: VOID
+
+ Notes: Any changes to this code should be coordinated with changes to wwrap( ) in wprintf.c
+
+*****************************************************************************/
+VOID tprintf( CHAR_PTR fmt, va_list arg_ptr )
+{
+#if !defined( UNICODE )
+ /* use sprintf to fill buffer */
+ vsprintf( gszTprintfBuffer, fmt, arg_ptr ) ;
+
+ msassert( strlen( gszTprintfBuffer ) <= MAX_WIN_WIDTH ) ;
+#else
+ CHAR_PTR newBuff;
+
+ /*
+ * Be prepared to print some really large strings
+ */
+ while ( _vsnwprintf( gszTprintfBuffer, printfBufferCount, fmt, arg_ptr ) == -1 )
+ {
+ /* Buffer wasn't big enough. Realloc and try again. */
+ printfBufferCount += PRINTF_BUFFER_CHUNK;
+ newBuff = realloc( gszTprintfBuffer, printfBufferCount * sizeof(CHAR) );
+
+ if ( newBuff != NULL )
+ {
+ gszTprintfBuffer = newBuff;
+ }
+ else
+ {
+ free( gszTprintfBuffer );
+ gszTprintfBuffer = NULL;
+ printfBufferCount = 0;
+ break;
+ }
+ }
+
+#endif
+}
+
+/*****************************************************************************
+
+ Name: typrintf
+
+ Description: This function displays a message
+
+ THIS IS A SPECIAL FUNCTION SPECIFICALLY
+ FOR THE "T" COMMANDS...NO WINDOWS ARE USED
+
+ Returns: VOID
+
+ Notes: calls tprintf( )
+
+*****************************************************************************/
+VOID typrintf( CHAR_PTR fmt, ... )
+{
+ va_list arg_ptr ;
+
+ va_start( arg_ptr, fmt ) ;
+ tprintf( fmt, arg_ptr ) ;
+ va_end( arg_ptr ) ;
+}
+
diff --git a/private/utils/ntbackup/src/translat.c b/private/utils/ntbackup/src/translat.c
new file mode 100644
index 000000000..b2fb9fbac
--- /dev/null
+++ b/private/utils/ntbackup/src/translat.c
@@ -0,0 +1,1690 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: translat.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+
+ $Log: T:\logfiles\translat.c_v $
+
+ Rev 1.45 07 Feb 1994 02:06:56 GREGG
+Fixed and expanded 'extended error reporting'.
+
+ Rev 1.44 08 Sep 1993 18:18:44 GREGG
+Changed WT_InitTape to match new func tab init_tape proto in fmteng.h r1.24.
+
+ Rev 1.43 17 Jul 1993 17:57:06 GREGG
+Changed write translator functions to return INT16 TFLE_xxx errors instead
+of BOOLEAN TRUE/FALSE. Files changed:
+ MTF10WDB.C 1.23, TRANSLAT.H 1.22, F40PROTO.H 1.30, FMTENG.H 1.23,
+ TRANSLAT.C 1.43, TFWRITE.C 1.68, MTF10WT.C 1.18
+
+ Rev 1.42 22 Jun 1993 10:53:12 GREGG
+Added API to change the catalog directory path.
+
+ Rev 1.41 07 Jun 1993 23:50:42 GREGG
+Handle EOM exception in current buffer in MoveToVCB.
+
+ Rev 1.40 17 May 1993 20:49:44 GREGG
+Added logic to deal with the fact that the app above tape format doesn't
+keep track of the lba of the vcb.
+
+ Rev 1.39 22 Apr 1993 03:31:22 GREGG
+Third in a series of incremental changes to bring the translator in line
+with the MTF spec:
+
+ - Removed all references to the DBLK element 'string_storage_offset',
+ which no longer exists.
+ - Check for incompatable versions of the Tape Format and OTC and deals
+ with them the best it can, or reports tape as foreign if they're too
+ far out. Includes ignoring the OTC and not allowing append if the
+ OTC on tape is a future rev, different type, or on an alternate
+ partition.
+ - Updated OTC "location" attribute bits, and changed definition of
+ CFIL to store stream number instead of stream ID.
+
+Matches: TFL_ERR.H 1.9, MTF10WDB.C 1.7, TRANSLAT.C 1.39, FMTINF.H 1.11,
+ OTC40RD.C 1.24, MAYN40RD.C 1.56, MTF10WT.C 1.7, OTC40MSC.C 1.20
+ DETFMT.C 1.13, MTF.H 1.4
+
+ Rev 1.38 18 Apr 1993 17:23:16 GREGG
+Added handling of BT_UDB type blocks to RD_TranslateDBLK.
+
+ Rev 1.37 09 Mar 1993 18:15:02 GREGG
+Initial changes for new stream and EOM processing.
+
+ Rev 1.36 26 Jan 1993 01:30:38 GREGG
+Added Fast Append functionality.
+
+ Rev 1.35 17 Nov 1992 22:17:56 DAVEV
+unicode fixes
+
+ Rev 1.34 11 Nov 1992 10:53:50 GREGG
+Unicodeized literals.
+
+ Rev 1.33 09 Nov 1992 11:01:00 GREGG
+Added entry points for accessing tape catalogs.
+
+ Rev 1.32 03 Nov 1992 09:27:36 HUNTER
+Added prototype for ending data stream
+
+ Rev 1.31 22 Oct 1992 10:49:32 HUNTER
+New data stream changes
+
+ Rev 1.30 20 Oct 1992 14:02:42 HUNTER
+Deleted reference to tdata_size
+
+ Rev 1.29 22 Sep 1992 08:58:34 GREGG
+Initial changes to handle physical block sizes greater than 1K.
+
+ Rev 1.28 14 Aug 1992 16:33:28 GREGG
+Removed MinSizeForTapeBlk and SizeForTapeEomBlk functions.
+
+ Rev 1.27 20 May 1992 20:00:58 GREGG
+Translator read functions now return INT16 - TFLE_xxx instead of BOOLEAN.
+
+ Rev 1.26 13 May 1992 11:47:28 BURT
+Oops, cut and paste strikes again. Added channel_ptr-> to the
+cur_fmt referenced in the pasted code. All better now.
+
+
+
+ Rev 1.25 13 May 1992 10:35:40 BURT
+Added logic to StartRead to prevent calling start_read if current
+format is UNKNOWN, which may happen if a blank tape is in the drive.
+
+
+ Rev 1.24 28 Apr 1992 16:41:26 GREGG
+ROLLER BLADES - Added DetBlockType function, added a BUF_PTR parameter to
+Wt_InitTape and took out all the TABS.
+
+ Rev 1.23 05 Apr 1992 17:17:36 GREGG
+ROLLER BLADES - Initial OTC integration.
+
+ Rev 1.22 25 Mar 1992 19:04:10 GREGG
+ROLLER BLADES - 64 bit support and SizeForTapeEomBlk entry point.
+
+ Rev 1.21 13 Feb 1992 13:26:04 NED
+added check for channel->cur_buff being null prior to exception handling
+within MoveToVCB() to fix QS1.9x bug with repeated VCB motion.
+
+ Rev 1.20 11 Feb 1992 17:14:16 NED
+changed buffman/translator interface parameters
+
+ Rev 1.19 04 Feb 1992 21:24:04 NED
+Changes to Buffer Management translator hooks.
+
+ Rev 1.18 16 Jan 1992 18:39:34 NED
+Skateboard: buffer manager changes
+
+ Rev 1.17 02 Jan 1992 14:48:22 NED
+Buffer Manager/UTF translator integration.
+
+ Rev 1.16 05 Dec 1991 14:03:36 GREGG
+SKATEBOARD - New Buff Mgt - Initial Integration.
+
+ Rev 1.15 18 Nov 1991 19:54:18 GREGG
+Added BOOLEAN abort parameter to Wt_CloseSet and passed it in calls to
+wt_mk_vcb and wt_close_set with appropriate values.
+
+ Rev 1.14 07 Nov 1991 15:30:52 HUNTER
+VBLK - Added support for Variable Blocks
+
+
+ Rev 1.13 17 Sep 1991 13:43:46 GREGG
+SetupFormatEnv now returns TFLE_xxx.
+
+ Rev 1.12 28 Aug 1991 09:53:48 GREGG
+Report GEN_ERR_NO_DATA as a tape incnsistancy in RD_Exception.
+
+ Rev 1.11 22 Aug 1991 16:31:18 NED
+Changed all references to internals of the buffer structure to macros.
+
+ Rev 1.10 22 Jul 1991 12:51:08 GREGG
+Modified WT_EndSet to set the AT_EOM channel status if the drive EOM status
+is set.
+
+ Rev 1.9 15 Jul 1991 14:39:28 NED
+Removed unreferenced channel status bit.
+
+ Rev 1.8 09 Jul 1991 15:54:04 NED
+Don't call FreeFormatEnv from SetupFormatEnv if there is no current format.
+
+ Rev 1.7 01 Jul 1991 15:55:30 NED
+set AT_EOM bit in drive as well as in channel at EOM.
+
+ Rev 1.6 26 Jun 1991 16:21:08 NED
+removed setting of CH_DONE from RD_Exception()
+added handling of GEN_ERR_NO_DATA as TFLE_NO_ERR in RD_Exception()
+
+ Rev 1.5 24 Jun 1991 19:49:38 GREGG
+In MoveToVCB, handle exceptions in current buffer before calling the
+translators move routine.
+
+ Rev 1.4 17 Jun 1991 11:48:56 NED
+added REW_CLOSE logic on error
+added BE_Zprintf() calls
+interpreted UNEXPECTED_EOM error as TF_NEED_NEW_TAPE
+
+ Rev 1.3 07 Jun 1991 00:32:50 GREGG
+New parameters for the deinitializeers and FreeFormatEnv, and code changes to
+accommodate the parameter changes. Changes to MoveToVCB due to Teac problems
+and other missed cases in original logic.
+
+ Rev 1.2 14 May 1991 11:22:14 GREGG
+Changed order of includes.
+
+ Rev 1.1 10 May 1991 11:55:32 GREGG
+Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:18:58 GREGG
+Initial revision.
+
+**/
+/* begin include list */
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "stdmacro.h"
+#include "tbe_defs.h"
+#include "datetime.h"
+#include "drive.h"
+#include "channel.h"
+#include "fmteng.h"
+#include "translat.h"
+#include "transprt.h"
+#include "transutl.h"
+#include "fsys.h"
+#include "tloc.h"
+#include "lw_data.h"
+#include "tfldefs.h"
+#include "tfl_err.h"
+#include "generr.h"
+#include "be_debug.h"
+#include "lwprotos.h"
+#include "minmax.h"
+
+/**/
+/**
+
+ Name: DetermineFormat
+
+ Description: This determines which tape format we are currently using.
+
+ Returns: UINT16, the tape format index number.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+UINT16 DetermineFormat(
+ VOID_PTR buf_ptr,
+ UINT32 buf_len )
+{
+ UINT16 ret = UNKNOWN_FORMAT ;
+ UINT16 i ;
+
+ if ( buf_len != 0L ) {
+ for( i = 0 ; i < lw_num_supported_fmts ; i++ ) {
+ if( (*supported_fmts[i].determiner)( buf_ptr ) ) {
+ ret = i ;
+ break ;
+ }
+ }
+ }
+
+ return( ret ) ;
+}
+/**/
+/**
+
+ Name: FreeFormatEnv
+
+ Description: Frees the Format Environment by calling the deinit
+ routine, if any. Otherwise, just frees the env mem.
+
+ Modified: 10/24/90 NK
+
+ Returns: Nothing
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+VOID FreeFormatEnv( UINT16_PTR cur_fmt, VOID_PTR *fmt_env )
+{
+ VOID (*deinitialize)( VOID_PTR * ) ;
+
+ BE_Zprintf( 0, TEXT("FreeFormatEnv( cur_fmt=%d )\n"), *cur_fmt ) ;
+
+ if ( *cur_fmt == UNKNOWN_FORMAT || *fmt_env == NULL ) {
+ return ;
+ }
+
+ if ( ( deinitialize = supported_fmts[*cur_fmt].deinitializer ) != NULL ) {
+ deinitialize( fmt_env ) ;
+ }
+
+ if ( *fmt_env != NULL ) {
+ free( *fmt_env ) ;
+ *fmt_env = NULL ;
+ }
+
+ *cur_fmt = UNKNOWN_FORMAT ;
+}
+
+/**/
+/**
+
+ Name: SetupFormatEnv
+
+ Description: Allocates space for the Format Environment
+ initializes it. Sets up for FreeFormatEnv().
+
+ Modified: 10/24/90 NK
+
+ Returns: UINT16, TFLE_xxx code.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+INT16 SetupFormatEnv( CHANNEL_PTR channel )
+{
+ UINT16 fmt = channel->cur_fmt ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ BOOLEAN (*initializer)(CHANNEL_PTR);
+
+ BE_Zprintf( 0, TEXT("SetupFormatEnv( fmt=%d )\n"), fmt ) ;
+
+ initializer = supported_fmts[fmt].initializer ;
+ if ( initializer != NULL ) {
+ ret_val = supported_fmts[fmt].initializer( channel ) ;
+ }
+
+ if ( ret_val != TFLE_NO_ERR ) {
+ channel->cur_fmt = UNKNOWN_FORMAT ;
+ }
+ return ret_val ;
+}
+/**/
+/**
+
+ Name: NewTape
+
+ Description: Called prior to any translate operations on a tape.
+ May do translator-specific things. If no new_tape
+ routine, returns TRUE
+
+ Returns: UINT16, TFLE_xxx or TF_xxx code.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+INT16 NewTape(
+ CHANNEL_PTR channel_ptr,
+ BOOLEAN_PTR need_read )
+{
+ INT16 (*func)( CHANNEL_PTR, BUF_PTR, BOOLEAN_PTR ) =
+ supported_fmts[ channel_ptr->cur_fmt ].new_tape ;
+ INT16 ret_val ;
+
+ /* Fix for the app not knowing the LBA for a continuation VCB */
+ channel_ptr->cross_set = 0 ;
+ channel_ptr->cross_lba = 0UL ;
+
+ if ( func == NULL ) {
+ * need_read = FALSE ;
+ return TFLE_NO_ERR ;
+ }
+
+ ret_val = func( channel_ptr, channel_ptr->cur_buff, need_read ) ;
+
+ if ( * need_read ) {
+ /* this is required so when the buffer is Punted,
+ our blocks_used count is properly updated. */
+ BM_SetBytesFree( channel_ptr->cur_buff, 0 ) ;
+ BM_SetNextByteOffset( channel_ptr->cur_buff, 0 ) ;
+ BM_SetReadError( channel_ptr->cur_buff, GEN_NO_ERR ) ;
+ }
+
+ return ret_val ;
+}
+/**/
+/**
+
+ Name: MoveToVCB
+
+ Description: Called to change the translator's idea of the current VCB.
+ When called with "really_move" set to TRUE,
+ guaranteed to position tape at proper point
+ to begin reading.
+
+ Modified: 6/4/1991 NK
+
+ Returns: success code, further info in *status: need a read,
+ misc TFLE_xxx codes if something failed. Returns
+ TFLE_NO_ERR if no move_to_vcb routine in table.
+
+ Notes: If we're moving backwards and the translator sees that
+ reverse filemarking is unavailable on this drive, translator
+ may return TF_NEED_REWIND_FIRST, signaling that we need to
+ rewind and process sets one at a time in the forward direction.
+
+**/
+INT16 MoveToVCB(
+ CHANNEL_PTR channel,
+ INT16 number, /* how many VCBs to move (signed) */
+ BOOLEAN_PTR need_read, /* do we need to read tape? */
+ BOOLEAN really_move ) /* is this at StartRead time? */
+{
+ INT16 (*move_to_vcb)( CHANNEL_PTR, INT16, BOOLEAN_PTR, BOOLEAN ) ;
+ INT16 ret_val ;
+ BOOLEAN was_at_bot = ( IsPosBitSet( channel->cur_drv, AT_BOT ) != 0 ) ;
+ UINT16 exception_type ;
+
+ if ( channel->cur_fmt == UNKNOWN_FORMAT ) {
+ SetPosBit( channel->cur_drv, REW_CLOSE ) ;
+ return TFLE_UNKNOWN_FMT ;
+ }
+
+ if ( ( move_to_vcb = supported_fmts[ channel->cur_fmt ].move_to_vcb ) == NULL ) {
+ return TFLE_NO_ERR ;
+ }
+
+ /* give the translator a chance to interpret the exception */
+ if ( !really_move && channel->cur_buff != NULL && BM_ReadError( channel->cur_buff ) != GEN_NO_ERR ) {
+ ret_val = RD_Exception( channel, BM_ReadError( channel->cur_buff ), &exception_type ) ;
+ if ( ret_val != TFLE_NO_ERR ) {
+ return ret_val ;
+ }
+
+ if( exception_type == FMT_EXC_EOM ) {
+ /* Undo what the stupid exception handler did, and tell the
+ caller we need a new tape.
+ */
+ ClrChannelStatus( channel, CH_AT_EOM ) ;
+ ClrPosBit( channel->cur_drv, ( TAPE_FULL | AT_EOM ) ) ;
+ return( TF_NEED_NEW_TAPE ) ;
+ }
+ }
+
+ ret_val = move_to_vcb( channel, number, need_read, really_move ) ;
+
+ if ( ret_val == TFLE_NO_ERR && *need_read == TRUE && channel->cur_buff != NULL ) {
+ /* this is required so when the buffer is Punted,
+ our blocks_used count is properly updated. */
+ BM_SetBytesFree( channel->cur_buff, 0 ) ;
+ BM_SetNextByteOffset( channel->cur_buff, 0 ) ;
+ BM_SetReadError( channel->cur_buff, GEN_NO_ERR ) ;
+ }
+
+ if ( number > 0 && was_at_bot && ret_val == TFLE_NO_ERR ) {
+ ClrPosBit( channel->cur_drv, AT_BOT ) ;
+ }
+
+ if ( ret_val == TFLE_UNEXPECTED_EOM && number > 0 ) {
+ ret_val = TF_NEED_NEW_TAPE ;
+ }
+
+ return ret_val ;
+}
+/**/
+/**
+
+ Name: SeekEOD
+
+ Description: Seek directly to end of data for fast append. Sets up
+ for the pending append operation including loading in
+ the Set Map if there is one.
+
+ Returns: TFLE_xxx error code or TF_xxx message.
+
+ Notes:
+
+**/
+INT16 SeekEOD( CHANNEL_PTR channel )
+{
+ INT16 (*func)( CHANNEL_PTR ) ;
+
+ if ( channel->cur_fmt == UNKNOWN_FORMAT ) {
+ msassert( FALSE ) ;
+ return( TFLE_PROGRAMMER_ERROR1 ) ;
+ }
+
+ if ( ( func = supported_fmts[channel->cur_fmt].seek_eod ) == NULL ) {
+ msassert( FALSE ) ;
+ return( TFLE_PROGRAMMER_ERROR1 ) ;
+ }
+
+ if( lw_fmtdescr[channel->cur_fmt].attributes & APPEND_SUPPORTED ) {
+ return( func( channel ) ) ;
+ } else {
+ return( TFLE_APPEND_NOT_ALLOWED ) ;
+ }
+}
+/**/
+/**
+
+ Name: GetCurrentVCB
+
+ Description: Fills in the channel->cur_dblk struct. Must have called
+ MoveToVCB( channel, n, & status, TRUE ) before
+ calling this.
+
+ Modified: 10/25/1990 NK
+
+ Returns: TFLE_xxx error code
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+INT16 GetCurrentVCB(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+ INT16 (*get_current_vcb)( CHANNEL_PTR, BUF_PTR ) ;
+
+ if ( channel->cur_fmt == UNKNOWN_FORMAT ) {
+ return TFLE_TRANSLATION_FAILURE ;
+ }
+
+ if ( ( get_current_vcb = supported_fmts[ channel->cur_fmt ].get_current_vcb ) == NULL ) {
+ return TFLE_TRANSLATION_FAILURE ;
+ } else {
+ return get_current_vcb( channel, buffer ) ;
+ }
+}
+/**/
+/**
+
+ Name: RD_TranslateDBLK
+
+ Description: During a read operation, this translates a DBLK.
+
+ Modified: 10/25/90 NK
+
+ Returns: TFLE_xxx error code
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+INT16 RD_TranslateDBLK(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer,
+ UINT16_PTR blk_type )
+{
+ INT16 ret_val ;
+ UINT16 cur_fmt = channel->cur_fmt ;
+ INT16 (*func)( CHANNEL_PTR, BUF_PTR ) = NULL ;
+ INT16 (*parse_func)( CHANNEL_PTR, BUF_PTR, UINT16_PTR ) ;
+
+ if ( cur_fmt == UNKNOWN_FORMAT || ( parse_func = supported_fmts[cur_fmt].parser ) == NULL ) {
+ msassert( FALSE ) ;
+ *blk_type = BT_HOSED ;
+ return( TFLE_TRANSLATION_FAILURE ) ;
+ }
+
+ if( ( ret_val = parse_func( channel, buffer, blk_type ) ) != TFLE_NO_ERR ) {
+ *blk_type = BT_HOSED ;
+ return( ret_val ) ;
+ }
+
+ switch( *blk_type ) {
+
+ case BT_STREAM:
+ func = supported_fmts[cur_fmt].rd_mk_stream ;
+ break ;
+
+ case BT_FDB:
+ func = supported_fmts[cur_fmt].rd_mk_fdb ;
+ break ;
+
+ case BT_DDB:
+ func = supported_fmts[cur_fmt].rd_mk_ddb ;
+ break ;
+
+ case BT_MDB:
+ func = supported_fmts[cur_fmt].rd_mk_mdb ;
+ break ;
+
+ case BT_VCB:
+ func = supported_fmts[cur_fmt].rd_mk_vcb ;
+ break ;
+
+ case BT_IDB:
+ func = supported_fmts[cur_fmt].rd_mk_idb ;
+ break ;
+
+ case BT_CFDB:
+ func = supported_fmts[cur_fmt].rd_mk_cfdb ;
+ break ;
+
+ case BT_BSDB:
+ func = supported_fmts[cur_fmt].rd_mk_bsdb ;
+ break ;
+
+ case BT_UDB:
+ func = supported_fmts[cur_fmt].rd_mk_osudb ;
+ break ;
+
+ default:
+ msassert( FALSE ) ;
+ break ;
+ }
+
+ if( func == NULL ) {
+ msassert( FALSE ) ;
+ *blk_type = BT_HOSED ;
+ return( TFLE_TRANSLATION_FAILURE ) ;
+ }
+
+ return( func( channel, buffer ) ) ;
+}
+/**/
+/**
+
+ Name: DetBlockType
+
+ Description: Determines the type of the next block in the buffer.
+
+ Returns: TFLE_xxx error code
+
+ Notes:
+
+**/
+
+INT16 DetBlockType(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer,
+ UINT16_PTR blk_type )
+{
+ INT16 (*func)( CHANNEL_PTR, BUF_PTR, UINT16_PTR ) ;
+
+ if( channel->cur_fmt == UNKNOWN_FORMAT ||
+ ( func = supported_fmts[channel->cur_fmt].parser ) == NULL ) {
+
+ msassert( FALSE ) ;
+ *blk_type = BT_HOSED ;
+ return( TFLE_TRANSLATION_FAILURE ) ;
+ }
+
+ return( func( channel, buffer, blk_type ) ) ;
+}
+/**/
+/**
+
+ Name: RD_RetranslateDBLK
+
+ Description: Handles retranslating the dblk
+
+ Modified: 4/12/1990 15:4:7
+
+ Returns: TFLE_xxx error code
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+BOOLEAN RD_ReTranslateDBLK(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+ UINT16 cur_fmt = channel->cur_fmt ;
+ BOOLEAN (*recall)( CHANNEL_PTR, BUF_PTR ) ;
+
+ if ( cur_fmt == UNKNOWN_FORMAT || ( recall = supported_fmts[cur_fmt].rd_recall ) == NULL ) {
+ return FALSE ;
+ }
+ return recall( channel, buffer ) ;
+}
+
+
+/**/
+/**
+
+ Name: RD_ContinuationTape
+
+ Description: Reads a continuation tape and updates the buffer.
+
+ Modified: 10/24/90 NK
+
+ Returns: TRUE for success, and FALSE for failure.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+BOOLEAN RD_ContinuationTape(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+ UINT16 cur_fmt = channel->cur_fmt ;
+ BOOLEAN (*func)( CHANNEL_PTR, BUF_PTR ) ;
+
+ if ( cur_fmt == UNKNOWN_FORMAT ) {
+ return FALSE ;
+ }
+
+ func = supported_fmts[cur_fmt].rd_cont_tape ;
+
+ return ( func == NULL ) ? TRUE : func( channel, buffer ) ;
+}
+
+/**/
+/**
+
+ Name: RD_Exception
+
+ Description: Calls the filemark action routine, if any.
+
+ Modified: 10/24/90 NK
+
+ Returns: TFLE_xxx codes
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+INT16 RD_Exception( CHANNEL_PTR channel, INT16 exception, UINT16_PTR ptype )
+{
+ UINT16 (*func)( CHANNEL_PTR, INT16 ) ;
+ INT16 ret_val = TFLE_NO_ERR ;
+ Q_ELEM_PTR qe_ptr ;
+
+ if ( channel->cur_fmt == UNKNOWN_FORMAT ) {
+ msassert( FALSE ) ;
+ return TFLE_PROGRAMMER_ERROR1 ;
+ }
+
+ func = supported_fmts[channel->cur_fmt].exception_action ;
+ msassert( func != NULL ) ;
+
+ /* Put all the buffers back from the inproc_q since they are dead anyway */
+ while ( ( qe_ptr = DeQueueElem( &channel->cur_drv->inproc_q ) ) != NULL ) {
+ BM_Put( ((BUF_PTR)QueuePtr( qe_ptr )) );
+ }
+
+ /* ask the translator to interpret this exception */
+ switch ( *ptype = func( channel, exception ) ) {
+
+ case FMT_EXC_EOS: /* means end of set */
+ SetPosBit( channel->cur_drv, AT_EOS ) ;
+ if( DataPhase( channel ) &&
+ U64_GT( channel->current_stream.size, U64_Init( 0L, 0L ) ) )
+ {
+ ret_val = TFLE_UNEXPECTED_EOS ;
+ }
+ break ;
+
+ case FMT_EXC_EOM: /* means end of medium */
+ SetChannelStatus( channel, CH_AT_EOM ) ;
+ SetPosBit( channel->cur_drv, ( TAPE_FULL | AT_EOM ) ) ;
+ channel->eom_filter = channel->active_filter ;
+ break ;
+
+ case FMT_EXC_HOSED: /* translator didn't recognize exception */
+
+ switch ( exception ) { /* map our own error messages */
+
+ case GEN_ERR_EOM:
+ SetPosBit( channel->cur_drv, TAPE_FULL ) ;
+
+ /* fall through */
+
+ case GEN_ERR_ENDSET:
+ case GEN_ERR_NO_DATA:
+ SetPosBit( channel->cur_drv, REW_CLOSE ) ;
+ ret_val = TFLE_TAPE_INCONSISTENCY ;
+ break ;
+
+ case GEN_ERR_NO_MEDIA:
+ ret_val = TFLE_NO_TAPE ;
+ break ;
+
+ case GEN_ERR_BAD_DATA:
+ ret_val = TFLE_BAD_TAPE ;
+ break ;
+
+ default:
+ ret_val = TFLE_DRIVE_FAILURE ;
+ break ;
+ }
+ break ;
+
+ case FMT_EXC_IGNORE :
+ break ;
+
+ default :
+ ret_val = TFLE_PROGRAMMER_ERROR1 ;
+ break ;
+ }
+
+ if ( *ptype != FMT_EXC_IGNORE ) {
+ BM_UseAll( channel->cur_buff ) ;
+ PuntBuffer( channel ) ; /* so we don't handle exception again */
+ }
+
+ return ret_val ;
+}
+
+/**/
+/**
+
+ Name: WT_TranslateDBLK
+
+ Description:
+
+ Modified: 10/25/90 NK
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+INT16 WT_TranslateDBLK(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer,
+ UINT16_PTR blk_type )
+{
+ INT16 ret_val = TFLE_NO_ERR ;
+ UINT16 cur_fmt = channel->cur_fmt ;
+ INT16 (*func)( CHANNEL_PTR, BUF_PTR, BOOLEAN ) = NULL ;
+
+ if ( cur_fmt == UNKNOWN_FORMAT || channel->cur_dblk == NULL ) {
+ msassert( FALSE ) ;
+ return( TFLE_TRANSLATION_FAILURE ) ;
+ }
+
+ switch( FS_GetBlockType( channel->cur_dblk ) ) {
+
+ case FDB_ID:
+ func = supported_fmts[cur_fmt].wt_mk_fdb ;
+ *blk_type = BT_FDB ;
+ break ;
+
+ case DDB_ID:
+ func = supported_fmts[cur_fmt].wt_mk_ddb ;
+ *blk_type = BT_DDB ;
+ break ;
+
+ case IDB_ID:
+ func = supported_fmts[cur_fmt].wt_mk_idb ;
+ *blk_type = BT_IDB ;
+ break ;
+
+ case VCB_ID:
+ func = supported_fmts[cur_fmt].wt_mk_vcb ;
+ *blk_type = BT_VCB ;
+ break ;
+
+ case CFDB_ID:
+ func = supported_fmts[cur_fmt].wt_mk_cfdb ;
+ *blk_type = BT_CFDB ;
+ break ;
+
+ default:
+ msassert( FALSE ) ;
+ return( TFLE_TRANSLATION_FAILURE ) ;
+ break ;
+ }
+
+ if( func == NULL ) {
+ msassert( FALSE ) ;
+ return( TFLE_TRANSLATION_FAILURE ) ;
+ }
+
+ return( func( channel, buffer, FALSE ) ) ;
+}
+
+
+/**/
+/**
+
+ Name: WT_EndTape
+
+ Description: Dispatches to the appropriate function for closing a
+ tape.
+
+ Modified: 10/3/1989 9:9:6
+
+ Returns: An error code if an error.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+INT16 WT_EndTape( CHANNEL_PTR channel )
+{
+ INT16 ret_val ;
+ UINT16 cur_fmt = channel->cur_fmt ;
+ DBLK_PTR hold_dblk = channel->cur_dblk ;
+ INT16 (*func)(CHANNEL_PTR);
+
+ if ( cur_fmt == UNKNOWN_FORMAT ) {
+ return TFLE_UNKNOWN_FMT ;
+ }
+
+ if ( ( func = supported_fmts[cur_fmt].wt_close_tape ) == NULL ) {
+ return TFLE_NO_ERR ;
+ }
+
+ ret_val = func( channel ) ;
+
+ channel->cur_dblk = hold_dblk ;
+
+ return ret_val ;
+}
+
+/**/
+/**
+
+ Name: WT_EndSet
+
+ Description: Dispatches to do appropriate tape end stuff.
+
+ Modified: 10/3/1989 9:12:13
+
+ Returns: An error code if appropriate.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+INT16 WT_EndSet( CHANNEL_PTR channel,
+ BOOLEAN abort )
+{
+ INT16 (*func)(CHANNEL_PTR, BOOLEAN);
+ INT16 ret_val ;
+ UINT16 cur_fmt = channel->cur_fmt ;
+
+ if ( cur_fmt == UNKNOWN_FORMAT ) {
+ ret_val = TFLE_UNKNOWN_FMT ;
+ } else if ( ( func = supported_fmts[cur_fmt].wt_close_set ) == NULL ) {
+ ret_val = TFLE_NO_ERR ;
+ } else {
+ ret_val = func( channel, abort ) ;
+ if( IsPosBitSet( channel->cur_drv, AT_EOM ) ) {
+ SetChannelStatus( channel, CH_AT_EOM ) ;
+ }
+ }
+ return ret_val ;
+}
+
+
+/**/
+/**
+
+ Name: WT_ContinueSet
+
+ Description:
+
+ Modified: 10/3/1989 9:14:37
+
+ Returns:
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+INT16 WT_ContinueSet( CHANNEL_PTR channel )
+{
+ INT16 (*func)(CHANNEL_PTR);
+ UINT16 cur_fmt = channel->cur_fmt ;
+
+ if ( cur_fmt == UNKNOWN_FORMAT ) {
+ return TFLE_UNKNOWN_FMT ;
+ }
+
+ if ( ( func = supported_fmts[cur_fmt].wt_cont_set ) == NULL ) {
+ return TFLE_NO_ERR ;
+ }
+
+ return( func( channel ) ) ;
+}
+
+/**/
+/**
+
+ Name: WT_ContVarStream
+
+ Description: Writes a Variable Stream continuation.
+
+ Modified:
+
+ Returns:
+
+ Notes:
+
+ See also:
+
+ Declaration:
+
+**/
+
+INT16 WT_ContVarStream(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+ INT16 (*func)( CHANNEL_PTR, BUF_PTR ) ;
+
+ if( channel->cur_fmt == UNKNOWN_FORMAT ) {
+ msassert( FALSE ) ;
+ return( TFLE_PROGRAMMER_ERROR1 ) ;
+ }
+ if( ( func = supported_fmts[channel->cur_fmt].wt_cont_vstrm ) == NULL ) {
+ msassert( FALSE ) ;
+ return( TFLE_PROGRAMMER_ERROR1 ) ;
+ }
+ return( func( channel, buffer ) ) ;
+}
+
+/**/
+/**
+
+ Name: WT_EndVarStream
+
+ Description: Writes a Ending Variable Stream Header.
+
+ Modified:
+
+ Returns:
+
+ Notes:
+
+ See also:
+
+ Declaration:
+
+**/
+
+VOID WT_EndVarStream(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer,
+ UINT16 used )
+{
+ VOID (*func)( CHANNEL_PTR, BUF_PTR, UINT16 ) ;
+
+ if( channel->cur_fmt == UNKNOWN_FORMAT ) {
+ msassert( FALSE ) ;
+ return ;
+ }
+ if( ( func = supported_fmts[channel->cur_fmt].wt_end_vstrm ) == NULL ) {
+ msassert( FALSE ) ;
+ return ;
+ }
+ func( channel, buffer, used ) ;
+}
+
+
+/**/
+/**
+
+ Name: WT_ParseWrittenBuffer
+
+ Description: Post processing of buffer written to tape.
+
+ Modified:
+
+ Returns:
+
+ Notes:
+
+ See also:
+
+ Declaration:
+
+**/
+
+VOID WT_ParseWrittenBuffer(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer,
+ UINT16 written )
+{
+ VOID (*func)( CHANNEL_PTR, BUF_PTR, UINT16 ) ;
+
+ if( channel->cur_fmt == UNKNOWN_FORMAT ) {
+ msassert( FALSE ) ;
+ return ;
+ }
+ if( ( func = supported_fmts[channel->cur_fmt].wt_parse_written ) == NULL ) {
+ msassert( FALSE ) ;
+ return ;
+ }
+ func( channel, buffer, written ) ;
+}
+
+
+/**/
+/**
+
+ Name: SizeofTapeBlock
+
+ Description: Given a buffer, returns the amount of space the tape
+ control block takes up.
+
+ Modified: 10/5/1989 10:30:49
+
+ Returns: The size in bytes of the tape control block.
+
+ Notes: THE POINTER MUST POINT TO A VALID TBLK OF THE SPECIFIED
+ FORMAT OR ELSE THE RESULTS WILL BE BOGUS.
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+UINT16 SizeofTapeBlock(
+ UINT16 fmt,
+ VOID_PTR buffer )
+{
+ return( (*supported_fmts[fmt].sizeof_tblk)( buffer ) ) ;
+}
+
+/**/
+/**
+
+ Name: VerifyVCB
+
+ Description: Used to double-check format (for appended
+ dissimilar formats)
+
+ Modified: 11/13/1990 NK
+
+ Returns: TRUE if VCB is OK.
+
+ Notes: Usually calls same routine as DetermineFormat().
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+BOOLEAN VerifyVCB(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+ BOOLEAN (*verify_vcb)(VOID_PTR) ;
+
+ if ( channel->cur_fmt == UNKNOWN_FORMAT ) {
+ return FALSE ;
+ }
+ verify_vcb = supported_fmts[ channel->cur_fmt ].verify_vcb ;
+
+ if ( verify_vcb == NULL ) {
+ return TRUE ; /* and let someone else catch it */
+ } else {
+ return verify_vcb( BM_XferBase( buffer ) ) ;
+ }
+}
+
+/**
+ * Unit: Tape Format
+ *
+ * Name: TF_GetVCBBufferRequirements
+ *
+ * Modified: Thursday, January 16, 1992
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Returns: VOID
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ **/
+
+VOID TF_GetVCBBufferRequirements(
+ BUF_REQ_PTR dest, /* O - destination structure */
+ Q_ELEM_PTR drive_head, /* I - master drive list */
+ UINT16 suggested_buff_size ) /* I - size from config */
+{
+ UINT16 block_size = 0 ;
+ Q_ELEM_PTR qe_ptr ;
+ UINT16 i ;
+/*
+** Examine drive list for maximum block size
+*/
+ for ( qe_ptr = drive_head; qe_ptr != NULL; qe_ptr = QueueNext( qe_ptr ) ) {
+ THW_PTR thw_ptr = (THW_PTR)(VOID_PTR)qe_ptr ;
+ block_size = MAX( block_size, thw_ptr->drv_info.drv_bsize );
+ }
+/*
+** Set starting dest requirements
+*/
+ BM_ClearRequirements( dest );
+ dest->tf_size =
+ dest->rw_size =
+ dest->a.min_size = MAX( suggested_buff_size, block_size ) ;
+ dest->a.block = block_size ;
+ dest->a.align = BR_ALIGN_WORD ;
+/*
+** For each translator
+*/
+ for ( i = 0 ; i < lw_num_supported_fmts ; i++ ) {
+ BM_TR_GET_VCB_REQ_FUNC_PTR buf_req_func = supported_fmts[i].set_buffer_requirements ;
+ BUF_REQ new_reqs;
+/*
+** If the translator cares, ask it what it needs for VCB buffer
+*/
+ if ( buf_req_func != NULL ) {
+ BM_ClearRequirements( &new_reqs ) ;
+
+ if ( buf_req_func( &new_reqs, drive_head, suggested_buff_size ) ) {
+ if ( BM_AddRequirements( dest, &new_reqs ) != BR_NO_ERR ) {
+ msassert( FALSE ) ;
+ break;
+ }
+ }
+ }
+ }
+}
+
+/**/
+/**
+ * Unit: Tape Format
+ *
+ * Name: TF_GetPreferredBufferSpace
+ *
+ * Modified: Monday, February 3, 1992
+ *
+ * Description:
+ *
+ * Notes:
+ *
+ * Returns: VOID
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ **/
+
+VOID TF_GetPreferredBufferSpace(
+ Q_ELEM_PTR drive_head, /* I - master drive list */
+ UINT16 suggested_number_of_buffers, /* I -- from config */
+ UINT32 suggested_buffer_size, /* I -- from config */
+ UINT32_PTR preferred_memory /* O - preferred total memory size */
+)
+{
+ UINT16 i ;
+
+ *preferred_memory = 0UL;
+/*
+** for each translator
+*/
+ for ( i = 0 ; i < lw_num_supported_fmts ; i++ ) {
+ BM_TR_GET_PREF_FUNC_PTR get_pref_func = supported_fmts[i].get_preferred_space ;
+/*
+** If the translator cares, ask it what it wants for total buffer space
+*/
+ if ( get_pref_func != NULL ) {
+ get_pref_func( drive_head,
+ suggested_number_of_buffers,
+ suggested_buffer_size,
+ preferred_memory );
+ }
+ }
+}
+
+/**/
+/**
+ * Unit: Tape Format
+ *
+ * Name: TF_ReadBufferHook
+ *
+ * Modified: Tuesday, November 12, 1991
+ *
+ * Description: Called upon reading a new buffer
+ *
+ * Notes:
+ *
+ * Returns: VOID
+ *
+ * Global Data:
+ *
+ * Processing:
+ *
+ **/
+
+VOID TF_ReadBufferHook(
+ CHANNEL_PTR channel, /* I - which channel */
+ BUF_PTR buffer ) /* O - current buffer */
+{
+ UINT16 cur_fmt = channel->cur_fmt ;
+ VOID (*func)( CHANNEL_PTR, BUF_PTR ) ;
+
+ if ( cur_fmt != UNKNOWN_FORMAT && ( func = supported_fmts[cur_fmt].read_buffer_hook ) != NULL ) {
+ func( channel, buffer ) ;
+ }
+}
+
+
+/**/
+/**
+
+ Name: StartRead
+
+ Description: Move to OTC when applicable
+
+ Returns: TFLE_xxx error code.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+INT16 StartRead(
+ CHANNEL_PTR channel_ptr )
+{
+ INT16 (*func)( CHANNEL_PTR ) ;
+
+ /* Added logic to insure that we don't attempt to call start_read
+ if cur_fmt is unknown. (BBB 5/13/92)
+ */
+ if ( channel_ptr->cur_fmt != UNKNOWN_FORMAT &&
+ ( func = supported_fmts[channel_ptr->cur_fmt].start_read ) != NULL ) {
+ return( func( channel_ptr ) ) ;
+ }
+ return TFLE_NO_ERR ;
+}
+
+/**/
+/**
+
+ Name: WT_InitTape
+
+ Description: Write a tape header, if required.
+
+ Returns: TFLE_xxx error code.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+INT16 WT_InitTape(
+ CHANNEL_PTR channel_ptr,
+ INT16 continuation )
+{
+ INT16 (*func)( CHANNEL_PTR, BOOLEAN, BUF_PTR ) =
+ supported_fmts[ channel_ptr->cur_fmt ].init_tape ;
+
+ if ( func == NULL ) {
+ return TFLE_NO_ERR ;
+ }
+ return( func( channel_ptr, continuation, channel_ptr->cur_buff ) ) ;
+}
+
+
+/**/
+/**
+
+ Name: WT_WriteInit
+
+ Description: Initialize OTC temporary files.
+
+ Returns: TFLE_xxx error code.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+INT16 WT_WriteInit(
+ CHANNEL_PTR channel,
+ UINT16 otc_level,
+ BUF_PTR buffer )
+{
+ INT16 (*func)( CHANNEL_PTR, UINT16, BUF_PTR ) ;
+
+ if( channel->cur_fmt == UNKNOWN_FORMAT ) {
+ return TFLE_NO_ERR ;
+ }
+
+ if( ( func = supported_fmts[ channel->cur_fmt ].write_init ) == NULL ) {
+ return TFLE_NO_ERR ;
+ }
+
+ return( func( channel, otc_level, buffer ) ) ;
+}
+
+
+/**/
+/**
+
+ Name: WT_EOSPadBlk
+
+ Description: Write special ending block to pad the buffer out to an
+ even physical block boundary.
+
+ Returns: Nothing.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+VOID WT_EOSPadBlk(
+ CHANNEL_PTR channel )
+{
+ VOID (*func)( CHANNEL_PTR ) ;
+
+ if( channel->cur_fmt == UNKNOWN_FORMAT ) {
+ msassert( FALSE ) ;
+ return ;
+ }
+
+ if( ( func = supported_fmts[ channel->cur_fmt ].wt_eos_pad_blk ) == NULL ) {
+ msassert( FALSE ) ;
+ return ;
+ }
+
+ func( channel ) ;
+}
+
+/**/
+/**
+
+ Name: WT_NewDataStream
+
+ Description: Writes a new data stream header
+
+ Returns: Nothing.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+INT16 WT_NewDataStream(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer,
+ STREAM_INFO_PTR newStream )
+{
+ INT16 (*func)( CHANNEL_PTR, BUF_PTR, STREAM_INFO_PTR ) ;
+
+ if( channel->cur_fmt == UNKNOWN_FORMAT ) {
+ msassert( FALSE ) ;
+ return( FAILURE ) ;
+ }
+
+ if( ( func = supported_fmts[ channel->cur_fmt ].wt_mk_stream ) == NULL ) {
+ msassert( FALSE ) ;
+ return( FAILURE ) ;
+ }
+
+ return( func( channel, buffer, newStream ) ) ;
+}
+
+/**/
+/**
+
+ Name: WT_EndData
+
+ Description: Writes a pad data stream header
+
+ Returns: Nothing.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+INT16 WT_EndData(
+ CHANNEL_PTR channel,
+ BUF_PTR buffer )
+{
+ INT16 (*func)( CHANNEL_PTR, BUF_PTR ) ;
+
+ if( channel->cur_fmt == UNKNOWN_FORMAT ) {
+ msassert( FALSE ) ;
+ return( FAILURE ) ;
+ }
+
+ if( ( func = supported_fmts[ channel->cur_fmt ].wt_mk_enddata ) == NULL ) {
+ msassert( FALSE ) ;
+ return( FAILURE ) ;
+ }
+
+ return( func( channel, buffer ) ) ;
+}
+
+
+/**/
+/**
+
+ Name: LoadSetMap
+
+ Description:
+
+ Returns: TFLE_xxx error code or TF_xxx message.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+INT LoadSetMap(
+ CHANNEL_PTR channel,
+ BOOLEAN_PTR complete,
+ BOOLEAN get_best )
+{
+ INT (*func)( CHANNEL_PTR, BOOLEAN_PTR, BOOLEAN ) ;
+
+ if( channel->cur_fmt == UNKNOWN_FORMAT ) {
+ msassert( FALSE ) ;
+ return( TFLE_PROGRAMMER_ERROR1 ) ;
+ }
+
+ if( ( func = supported_fmts[channel->cur_fmt].load_set_map ) == NULL ) {
+ return( TF_NO_SM_FOR_FAMILY ) ;
+ }
+
+ return( func( channel, complete, get_best ) ) ;
+}
+
+/**/
+/**
+
+ Name: LoadSetCat
+
+ Description:
+
+ Returns: TFLE_xxx error code or TF_xxx message.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+INT LoadSetCat(
+ CHANNEL_PTR channel )
+{
+ INT (*func)( CHANNEL_PTR ) ;
+
+ if( channel->cur_fmt == UNKNOWN_FORMAT ) {
+ msassert( FALSE ) ;
+ return( TFLE_PROGRAMMER_ERROR1 ) ;
+ }
+
+ if( ( func = supported_fmts[channel->cur_fmt].load_set_cat ) == NULL ) {
+ return( TF_NO_SC_FOR_SET ) ;
+ }
+
+ return( func( channel ) ) ;
+}
+
+
+/**/
+/**
+
+ Name: GetNextSMEntry
+
+ Description:
+
+ Returns: TFLE_xxx error code or TF_xxx message.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+INT GetNextSMEntry( CHANNEL_PTR channel )
+{
+ INT (*func)( CHANNEL_PTR ) ;
+
+ if( channel->cur_fmt == UNKNOWN_FORMAT ) {
+ msassert( FALSE ) ;
+ return( TFLE_PROGRAMMER_ERROR1 ) ;
+ }
+
+ if( ( func = supported_fmts[channel->cur_fmt].get_next_sm_entry ) == NULL ) {
+ msassert( FALSE ) ;
+ return( TFLE_PROGRAMMER_ERROR1 ) ;
+ }
+
+ return( func( channel ) ) ;
+}
+
+
+/**/
+/**
+
+ Name: GetNextSCEntry
+
+ Description:
+
+ Returns: TFLE_xxx error code or TF_xxx message.
+
+ Notes:
+
+ Declaration:
+
+**/
+
+INT GetNextSCEntry( CHANNEL_PTR channel )
+{
+ INT (*func)( CHANNEL_PTR ) ;
+
+ if( channel->cur_fmt == UNKNOWN_FORMAT ) {
+ msassert( FALSE ) ;
+ return( TFLE_PROGRAMMER_ERROR1 ) ;
+ }
+
+ if( ( func = supported_fmts[channel->cur_fmt].get_next_sc_entry ) == NULL ) {
+ msassert( FALSE ) ;
+ return( TFLE_PROGRAMMER_ERROR1 ) ;
+ }
+
+ return( func( channel ) ) ;
+}
+
+
+/**/
+/**
+
+ Name: CloseTapeCatalogs
+
+ Description: This function deletes any temporary tape catalog files
+ in the current catalog directory.
+
+ Returns: Nothing
+
+ Notes:
+
+ Declaration:
+
+**/
+
+VOID CloseTapeCatalogs( INT16 cur_fmt, VOID_PTR env_ptr )
+{
+ VOID (*func)( VOID_PTR ) ;
+
+ if( cur_fmt == UNKNOWN_FORMAT ) {
+ msassert( FALSE ) ;
+ return ;
+ }
+
+ if( ( func = supported_fmts[cur_fmt].close_catalogs ) == NULL ) {
+ msassert( FALSE ) ;
+ return ;
+ }
+
+ func( env_ptr ) ;
+}
+
diff --git a/private/utils/ntbackup/src/transutl.c b/private/utils/ntbackup/src/transutl.c
new file mode 100644
index 000000000..a454813a4
--- /dev/null
+++ b/private/utils/ntbackup/src/transutl.c
@@ -0,0 +1,382 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: transutl.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+
+ $Log: T:/LOGFILES/TRANSUTL.C_V $
+
+ Rev 1.7 22 Oct 1992 10:44:50 HUNTER
+Changes for new stream headers
+
+ Rev 1.6 22 Sep 1992 08:57:00 GREGG
+Initial changes to handle physical block sizes greater than 1K.
+
+ Rev 1.5 17 Aug 1992 08:35:12 GREGG
+Added AllocChannelTmpBlks function.
+
+ Rev 1.4 24 Jul 1992 16:47:00 NED
+Incorporated Skateboard and BigWheel changed into Graceful Red code,
+including MTF4.0 translator support, adding 3.1 file-system structures
+support to the 3.1 translator, additions to GOS to support non-4.0 translators.
+Also did Unicode and 64-bit filesize changes.
+
+ Rev 1.3 25 Mar 1992 19:38:34 GREGG
+ROLLER BLADES - 64 bit support.
+
+ Rev 1.2 17 Jan 1992 14:40:22 DON
+if OS_NLM, need to clib LongSwap instead of our macro BSwapLong
+
+ Rev 1.1 10 May 1991 11:57:24 GREGG
+Ned's new stuff.
+
+ Rev 1.0 10 May 1991 10:18:52 GREGG
+Initial revision.
+
+**/
+/* begin include list */
+
+#if defined(OS_NLM)
+ #include <nwmisc.h>
+#endif
+
+#include <malloc.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+
+#include "channel.h"
+#include "tfldefs.h"
+#include "transutl.h"
+#include "datetime.h"
+#include "stdmacro.h"
+#include "tfl_err.h"
+
+/* $end$ include list */
+
+/**/
+/**
+
+ Name: CalcChecksum
+
+ Description: This routine will calculate the checksum for "length"
+ words starting at location pointed to by "start_ptr".
+ This routine supports both INTEL and MOTOROLA byte
+ ordering as byte order is unimportant.
+
+ Modified: August 17, 1989 (2:07pm)
+
+ Returns:
+
+ Notes: If the "checksum_ptr" is within the area being checksumed then
+ it starts out with a zero value and is updated after the checksum
+ has been calculated.
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+UINT16 CalcChecksum(
+ UINT16_PTR start_ptr ,
+ UINT16 length ) /* In 16 bit words */
+{
+ UINT16 result_so_far = 0 ;
+
+ while( length-- ) {
+ result_so_far ^= *start_ptr++ ;
+ }
+
+ return( result_so_far ) ;
+}
+
+
+/**/
+/**
+
+ Name: SwapBlock
+
+ Description: This routine will take an "fmt_blk" array and a Data Block and convert
+ the Data Block to the correct format for the given machine. The process
+ continues until the next "fmt_blk" entry is zero.
+
+ Modified: 9/20/1989 10:45:53
+
+ Returns: Nothing
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+VOID SwapBlock(
+ UINT16_PTR fmt_blk ,
+ UINT8_PTR data_blk )
+{
+ UINT16 i ;
+ UINT16_PTR word_ptr ;
+ UINT32_PTR dword_ptr ;
+ UINT16 length ;
+
+ /* while more to process */
+ for( ; *fmt_blk ; fmt_blk++ ) {
+ /* How many items? */
+ length = ( *fmt_blk & ~MASK_UNUSED ) ;
+ /* what must we convert? */
+ switch( *fmt_blk & MASK_UNUSED ) {
+ /* do not convert double word */
+ case SIZE_DATE_TIME :
+ data_blk += ( sizeof( DATE_TIME ) * length ) ;
+ break ;
+ case SIZE_DWORD :
+ data_blk += ( sizeof( UINT32 ) * length ) ;
+ break ;
+ case SIZE_WORD :
+ data_blk += ( sizeof( UINT16 ) * length ) ;
+ break ;
+ case SIZE_DWORD + CNV :
+ for( i = 0 ; ( i < length ) ; i++ ) {
+ dword_ptr = ( UINT32_PTR ) data_blk ;
+#if defined(OS_NLM)
+ *dword_ptr = LongSwap( *dword_ptr ) ;
+#else
+ *dword_ptr = BSwapLong( *dword_ptr ) ;
+#endif
+ data_blk += sizeof( UINT32 ) ;
+ }
+ break ;
+ case SIZE_DATE_TIME + CNV :
+ length *= ( sizeof( DATE_TIME ) / 2 ) ;
+ /* fall through */
+ case SIZE_WORD + CNV :
+ for( i = 0 ; ( i < length ) ; i++ ) {
+ word_ptr = ( UINT16_PTR ) data_blk ;
+ *word_ptr = BSwapWord( *word_ptr ) ;
+ data_blk += sizeof( UINT16 ) ;
+ }
+ break ;
+ default :
+ data_blk += ( sizeof( CHAR ) * length ) ;
+ break ;
+ }
+ }
+ return ;
+}
+
+/**/
+/**
+
+ Name: ProcessDataFilter
+
+ Description: This decides how much data to allow to be transfered.
+
+ Modified: 9/20/1989 16:2:39
+
+ Returns: Nothing
+
+ Notes: THIS FUNCTION SHOULD NOT BE CALLED FOR CONTINUATION
+ BLOCKS. ALSO TDATA MUST BE FILLED BEFORE CALLING.
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+VOID ProcessDataFilter(
+ CHANNEL_PTR channel ,
+ UINT16 filter )
+{
+
+ ClrChannelStatus( channel, ( CH_SKIP_ALL_STREAMS | CH_SKIP_CURRENT_STREAM ) ) ;
+
+ /* Let's resolve the Filters */
+ if( channel->perm_filter == TF_SKIP_ALL_DATA ||
+ channel->loop_filter == TF_SKIP_ALL_DATA ) {
+
+ filter = TF_SKIP_ALL_DATA ;
+ }
+
+ switch( filter ) {
+
+ case TF_KEEP_ALL_DATA:
+ break ;
+
+ case TF_SKIP_ALL_DATA:
+ SetChannelStatus( channel, CH_SKIP_ALL_STREAMS ) ;
+ break ;
+
+
+ case TF_SKIP_DATA_STREAM:
+ SetChannelStatus( channel, CH_SKIP_CURRENT_STREAM ) ;
+ break ;
+
+ default:
+ msassert( FALSE ) ;
+
+
+ }
+
+ channel->active_filter = filter ;
+
+ return ;
+
+}
+
+/**/
+/**
+
+ Name: F25_Chksm
+
+ Description: Calculate a checksum by the 2.0 algorilla.
+
+ Modified: 8/13/1989
+
+ Returns: The checksum.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+
+UINT16 F25_Chksm(
+ CHAR_PTR ptr ,
+ UINT16 len )
+{
+ UINT16_PTR wptr = (UINT16_PTR)ptr ;
+ UINT16 wlen = len / 2 ;
+ UINT16 result = 0 ;
+ UINT16 i ;
+
+ /* start with result being 0, then XOR with previous */
+ for( i = 0 ; i < wlen ; i++ ) result ^= wptr[i] ;
+
+ return( ( 0 - result ) ) ;
+}
+
+/**/
+/**
+
+ Name: AllocChannelTmpBlks
+
+ Description: Allocates the memory for the temporary DBLK storage in
+ the channel.
+
+ Returns: TFLE_xxx
+
+ Notes:
+
+**/
+
+INT16 AllocChannelTmpBlks(
+ CHANNEL_PTR channel,
+ UINT size )
+{
+ if( channel->lst_osvcb != NULL ) {
+ free( channel->lst_osvcb ) ;
+ channel->lst_osvcb = NULL ;
+ }
+ if( channel->lst_osddb != NULL ) {
+ free( channel->lst_osddb ) ;
+ channel->lst_osddb = NULL ;
+ }
+ if( channel->lst_osfdb != NULL ) {
+ free( channel->lst_osfdb ) ;
+ channel->lst_osfdb = NULL ;
+ }
+ if( ( channel->lst_osvcb = (UINT8_PTR)calloc( 1, size ) ) == NULL ) {
+ return( TFLE_NO_MEMORY ) ;
+ }
+ if( ( channel->lst_osddb = (UINT8_PTR)calloc( 1, size ) ) == NULL ) {
+ return( TFLE_NO_MEMORY ) ;
+ }
+ if( ( channel->lst_osfdb = (UINT8_PTR)calloc( 1, size ) ) == NULL ) {
+ return( TFLE_NO_MEMORY ) ;
+ }
+ return( TFLE_NO_ERR ) ;
+}
+
+
+
+
+/* string substitute routines */
+
+INT16 cstrcmp( UINT8_PTR str1, UINT8_PTR str2 )
+{
+ while ( *str1 && *str2 && *str1 == *str2 ) {
+ str1++;
+ str2++;
+ }
+ return *str1 - *str2;
+}
+
+INT16 cstrncmp( UINT8_PTR str1, UINT8_PTR str2, UINT16 maxlen )
+{
+ while ( maxlen > 0 && *str1 && *str2 && *str1 == *str2 ) {
+ str1++;
+ str2++;
+ maxlen--;
+ }
+ return *str1 - *str2;
+}
+
+UINT8_PTR cstrcpy( UINT8_PTR dest, UINT8_PTR src )
+{
+ UINT8_PTR d = dest;
+
+ while ( ( *d++ = *src++ ) != '\0' )
+ /* empty loop */;
+ return dest;
+}
+
+UINT16 cstrlen( UINT8_PTR str )
+{
+ UINT16 len = 0;
+
+ while ( *str++ ) {
+ len++;
+ }
+ return len;
+}
+
+UINT8_PTR cstrncat( UINT8_PTR dest, UINT8_PTR src, UINT16 maxlen )
+{
+ UINT8_PTR d = dest;
+
+ while ( *d++ ) /* search for end of dest */
+ /* empty loop */ ;
+
+ while ( maxlen > 0 && ( *d = *src ) != '\0' ) {
+ d++;
+ src++;
+ maxlen--;
+ }
+
+ *d = 0;
+ return dest;
+}
+
+UINT8_PTR cstrncpy( UINT8_PTR dest, UINT8_PTR src, UINT16 maxlen )
+{
+ UINT8_PTR d = dest;
+
+ while ( maxlen > 0 && ( *d = *src ) != '\0' ) {
+ d++;
+ src++;
+ maxlen--;
+ }
+
+ *d = 0;
+ return dest;
+}
diff --git a/private/utils/ntbackup/src/treadobj.c b/private/utils/ntbackup/src/treadobj.c
new file mode 100644
index 000000000..b71e44c89
--- /dev/null
+++ b/private/utils/ntbackup/src/treadobj.c
@@ -0,0 +1,841 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: treadobj.c
+
+ Description: This file contains code to read data from an object
+
+ $Log: M:/LOGFILES/TREADOBJ.C_V $
+
+ Rev 1.39.1.0 03 Mar 1994 10:39:38 BARRY
+Defend against buffers zero bytes in length
+
+ Rev 1.39 26 Jan 1994 19:25:40 BARRY
+Shut up debug on GetLastError returning 0
+
+ Rev 1.38 23 Jan 1994 14:25:10 BARRY
+Added debug code
+
+ Rev 1.37 11 Jan 1994 19:14:42 BARRY
+Make sure path read size is a multiple of the character size
+
+ Rev 1.36 10 Dec 1993 14:32:00 BARRY
+Use correct stream IDs for path/file
+
+ Rev 1.35 01 Dec 1993 13:57:42 STEVEN
+fix delimiter replacment code
+
+ Rev 1.34 24 Nov 1993 14:46:36 BARRY
+Unicode fixes
+
+ Rev 1.33 18 Aug 1993 19:27:46 BARRY
+Kludge: if a read error occurs on dirs, null out the stream.
+
+ Rev 1.32 16 Aug 1993 22:02:22 BARRY
+If read of stream failed for any reason, and we didn't get it all, it's corrupt.
+
+ Rev 1.31 12 Aug 1993 14:37:06 BARRY
+Don't return data and errors at the same time.
+
+ Rev 1.30 16 Jul 1993 11:59:12 BARRY
+Return FS_STREAM_CORRUPT on premature FS_EOF_REACHED.
+
+ Rev 1.29 27 Jan 1993 13:51:12 STEVEN
+updates from msoft
+
+ Rev 1.28 15 Jan 1993 13:18:34 BARRY
+added support for new error messages and backup priviladge
+
+ Rev 1.27 07 Dec 1992 14:18:00 STEVEN
+updates from msoft
+
+ Rev 1.26 24 Nov 1992 11:02:02 BARRY
+Changes to make LINK streams null-impregnated.
+
+ Rev 1.25 17 Nov 1992 22:19:24 DAVEV
+unicode fixes
+
+ Rev 1.24 11 Nov 1992 09:57:08 GREGG
+Changed INT8_PTR to CHAR_PTR for unicode compliance.
+
+ Rev 1.23 10 Nov 1992 08:18:50 STEVEN
+removed path and name from dblk now use full_name_ptr
+
+ Rev 1.22 06 Nov 1992 15:49:42 STEVEN
+test write of path in stream
+
+ Rev 1.21 02 Nov 1992 11:18:04 BARRY
+Don't back up path streams with leading null.
+
+ Rev 1.20 21 Oct 1992 19:44:06 BARRY
+Backup references to original on linked files.
+
+ Rev 1.19 19 Oct 1992 17:54:04 BARRY
+Made changes for latest incarnation of stream header functionality.
+
+ Rev 1.18 16 Oct 1992 16:42:08 STEVEN
+fix streams to UINT64
+
+ Rev 1.17 14 Oct 1992 14:37:06 BARRY
+Fixes for alternate data streams.
+
+ Rev 1.16 09 Oct 1992 14:31:26 BARRY
+Path-in-stream changes.
+
+ Rev 1.14 06 Oct 1992 11:12:30 BARRY
+BackupRead stream size corrections; bug fixes in stream header redesign.
+
+ Rev 1.13 24 Sep 1992 13:24:04 BARRY
+Changes for huge file name support.
+
+ Rev 1.12 18 Sep 1992 15:37:32 BARRY
+Changes for Stream Header redesign.
+
+ Rev 1.11 04 Sep 1992 17:14:58 STEVEN
+fix warnings
+
+ Rev 1.10 02 Sep 1992 07:48:32 STEVEN
+fix typo
+
+ Rev 1.9 01 Sep 1992 16:10:48 STEVEN
+added stream headers to fsys API
+
+ Rev 1.8 17 Aug 1992 16:21:06 STEVEN
+fix warnings
+
+ Rev 1.7 12 Aug 1992 17:47:52 STEVEN
+fixed bugs at microsoft
+
+ Rev 1.6 23 Jul 1992 13:13:12 STEVEN
+fix warnings
+
+ Rev 1.5 29 May 1992 13:45:22 STEVEN
+fixes
+
+ Rev 1.4 22 May 1992 16:05:44 STEVEN
+
+
+ Rev 1.3 21 May 1992 13:49:16 STEVEN
+more long path support
+
+ Rev 1.2 26 Feb 1992 12:35:08 STEVEN
+retval not initialized
+
+ Rev 1.1 12 Feb 1992 13:00:38 STEVEN
+fix buffer size passed in
+
+ Rev 1.0 10 Feb 1992 16:57:46 STEVEN
+Initial revision.
+
+**/
+#include <windows.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "msassert.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "fsys_err.h"
+#include "ntfsdblk.h"
+#include "ntfs_fs.h"
+
+static INT16 NTFS_ReadPathStream( FILE_HAND hand,
+ BYTE_PTR buf,
+ UINT16 *size,
+ UINT16 *blk_size,
+ STREAM_INFO_PTR s_info );
+
+static INT16 NTFS_ReadFileNameStream( FILE_HAND hand,
+ BYTE_PTR buf,
+ UINT16 *size,
+ UINT16 *blk_size,
+ STREAM_INFO_PTR s_info );
+
+static INT16 NTFS_ReadData(
+ FILE_HAND hand,
+ BYTE_PTR buf,
+ UINT16 *size,
+ UINT16 *blk_size,
+ STREAM_INFO_PTR s_info );
+
+static INT16 NTFS_ReadLinkInfo( FILE_HAND hand,
+ BYTE_PTR buff,
+ UINT16 *size,
+ UINT16 *blk_size,
+ STREAM_INFO_PTR s_info );
+
+static INT16 BackStreamHeader(
+ FILE_HAND hand,
+ STREAM_INFO_PTR s_info );
+
+static UINT16 CalcReadSize( UINT64 startPos,
+ UINT64 endPos,
+ UINT16 buffSize );
+
+/**/
+/**
+
+ Name: NTFS_ReadObj()
+
+ Description: This function reads data from an opened object.
+
+ Modified: 7/31/1989
+
+ Returns: Error Codes:
+ FS_DEVICE_ERROR
+ FS_OBJECT_NOT_OPENED
+ FS_EOF_REACHED
+ SUCCESS
+
+ Notes: This function reads data in "chunks". If the buffer
+ is not a multiple of the "chunk" size then the buffer will not
+ be filled. The "Chunk" size is returned.
+
+**/
+INT16 NTFS_ReadObj(
+ FILE_HAND hand, /* I - handle of object to read from */
+ BYTE_PTR buf, /* O - buffer to place data into */
+ UINT16 *size , /*I/O- Entry: size of buf; Exit: number of bytes read */
+ UINT16 *blk_size , /* O - Block size needed for next read */
+ STREAM_INFO_PTR s_info) /* O - Stream information for the data returned */
+{
+ NTFS_OBJ_HAND_PTR nt_hand = (NTFS_OBJ_HAND_PTR)(hand->obj_hand.ptr ) ;
+ NTFS_DBLK_PTR ddblk = (NTFS_DBLK_PTR)hand->dblk ;
+ INT16 ret_val ;
+
+ msassert( hand->mode == FS_READ ) ;
+
+ if ( (nt_hand->needStreamHeader == FALSE) && (*size == 0) )
+ {
+ /*
+ * Someone asked us to read zero bytes. According to
+ * our rules this is not allowed, but we'll be defensive
+ * anyway.
+ */
+ msassert( FALSE );
+ *blk_size = 1;
+ ret_val = SUCCESS;
+ }
+ else
+ {
+ switch ( hand->dblk->blk_type )
+ {
+
+ case FDB_ID:
+ if ( (ddblk->b.f.fdb_attrib & FILE_NAME_IN_STREAM_BIT) &&
+ (nt_hand->nameComplete == FALSE) )
+ {
+ ret_val = NTFS_ReadFileNameStream( hand, buf, size, blk_size, s_info );
+ }
+ else
+ {
+ if ( ddblk->b.f.linkOnly )
+ {
+ ret_val = NTFS_ReadLinkInfo( hand, buf, size, blk_size, s_info );
+ }
+ else
+ {
+ ret_val = NTFS_ReadData( hand, buf, size, blk_size, s_info ) ;
+ }
+ }
+ nt_hand->needStreamHeader = U64_EQ( nt_hand->curPos, nt_hand->nextStreamHeaderPos);
+ break ;
+
+ case DDB_ID:
+ if ( (ddblk->b.d.ddb_attrib & DIR_PATH_IN_STREAM_BIT) &&
+ (nt_hand->nameComplete == FALSE) )
+ {
+ ret_val = NTFS_ReadPathStream( hand, buf, size, blk_size, s_info );
+ }
+ else
+ {
+ ret_val = NTFS_ReadData( hand, buf, size, blk_size, s_info ) ;
+ }
+ nt_hand->needStreamHeader = U64_EQ( nt_hand->curPos, nt_hand->nextStreamHeaderPos);
+ break;
+
+
+ case VCB_ID:
+ ret_val = FS_EOF_REACHED ;
+ break ;
+
+ default:
+ ret_val = FS_OBJECT_NOT_OPENED;
+ }
+ }
+ return ret_val;
+}
+
+/**/
+/**
+
+ Name: NTFS_ReadData()
+
+ Description: This function calls the NT Backup APIs to read data from
+ an open object.
+
+ Modified: 2/10/1992 16:48:9
+
+ Returns: FS_DEVICE_ERROR
+ FS_OBJECT_NOT_OPENED
+ FS_EOF_REACHED
+ SUCCESS
+
+**/
+static INT16 NTFS_ReadData(
+ FILE_HAND hand, /* I - handle of object to read from */
+ BYTE_PTR buf, /* O - buffer to place data into */
+ UINT16 *size, /*I/O- Entry: size of buf; Exit: number of bytes read */
+ UINT16 *blk_size, /* O - Block size needed for next read */
+ STREAM_INFO_PTR s_info ) /* O - Stream information for the data returned */
+{
+ NTFS_OBJ_HAND_PTR nt_hand ;
+ INT16 ret_val = SUCCESS ;
+ INT status ;
+ INT sizeout ;
+ UINT16 buffSize;
+ BOOLEAN dummy;
+
+ *blk_size = 1 ;
+ nt_hand = (NTFS_OBJ_HAND_PTR)(hand->obj_hand.ptr ) ;
+
+ buffSize = *size;
+ *size = 0;
+
+ if ( nt_hand->needStreamHeader )
+ {
+ ret_val = BackStreamHeader( hand, s_info );
+ }
+ else
+ {
+ UINT16 readSize;
+
+ s_info->id = STRM_INVALID;
+
+ if ( (nt_hand->streamHeader.name_leng > 0) &&
+ U64_EQ( nt_hand->curPos, U64_Init( 0, 0 ) ) )
+ {
+ UINT16 nameSize;
+
+ /* CBN -- Need the real Microsoft #define here */
+ msassert( nt_hand->streamHeader.id == 4 );
+ msassert( nt_hand->streamHeader.name_leng <= NT_MAX_STREAM_NAME_LENG );
+
+ nameSize = (UINT16)(nt_hand->streamHeader.name_leng +
+ sizeof(nt_hand->streamHeader.name_leng));
+
+ if ( buffSize < nameSize )
+ {
+ *blk_size = nameSize;
+ return SUCCESS;
+ }
+
+ status = BackupRead( nt_hand->fhand,
+ (LPBYTE)&nt_hand->streamHeader.name[0],
+ nt_hand->streamHeader.name_leng,
+ (LPDWORD)&sizeout,
+ FALSE,
+ TRUE,
+ &nt_hand->context ) ;
+
+ if ( !status || (sizeout < (INT)nt_hand->streamHeader.name_leng) )
+ {
+ NTFS_DebugPrint( TEXT("NTFS_ReadData: BackupRead error (alt stream name) %d")
+ TEXT(" on \"%s\""),
+ (int)GetLastError(),
+ ((NTFS_DBLK_PTR)hand->dblk)->full_name_ptr->name );
+
+ ret_val = FS_EOF_REACHED;
+ }
+ else
+ {
+ UINT16 nameSize;
+
+ nameSize = (UINT16)(nt_hand->streamHeader.name_leng +
+ sizeof(nt_hand->streamHeader.name_leng));
+
+ *size += nameSize;
+
+ memcpy( buf,
+ &nt_hand->streamHeader.name_leng,
+ sizeof(nt_hand->streamHeader.name_leng) );
+
+ buf += sizeof( nt_hand->streamHeader.name_leng );
+
+ memcpy( buf,
+ nt_hand->streamHeader.name,
+ nt_hand->streamHeader.name_leng );
+
+ buf += nt_hand->streamHeader.name_leng;
+
+ }
+ }
+ else
+ {
+ /* Only read up until the next stream. */
+
+ readSize = CalcReadSize( nt_hand->curPos,
+ nt_hand->nextStreamHeaderPos,
+ buffSize );
+
+ status = BackupRead( nt_hand->fhand,
+ buf,
+ readSize,
+ (LPDWORD)&sizeout,
+ FALSE,
+ TRUE,
+ &nt_hand->context ) ;
+
+ if ( sizeout != 0 )
+ {
+ /* We got data; only return SUCCESS or FS_EOF_REACHED */
+
+ if ( !status )
+ {
+ ret_val = NTFS_TranslateBackupError( GetLastError( ) );
+ if ( ret_val != FS_EOF_REACHED )
+ {
+ ret_val = SUCCESS;
+ }
+ }
+ }
+ else
+ {
+ NTFS_DebugPrint( TEXT("NTFS_ReadData: BackupRead error %d")
+ TEXT(" on \"%s\""),
+ (int)GetLastError(),
+ ((NTFS_DBLK_PTR)hand->dblk)->full_name_ptr->name );
+
+ if ( hand->dblk->blk_type == FDB_ID )
+ {
+ if ( !status )
+ {
+ ret_val = NTFS_TranslateBackupError( GetLastError( ) );
+ }
+
+ if ( ret_val == SUCCESS )
+ {
+ ret_val = FS_EOF_REACHED;
+ }
+ }
+ else
+ {
+ UINT32 seek;
+
+ /*
+ * This is a dir and we had problems. We can't
+ * very well write a CFDB or report a problem,
+ * so pad the bloody stream with zeros.
+ */
+
+ memset( buf, 0, readSize );
+ sizeout = readSize;
+
+ /*
+ * Seek in case, by some miracle, a following read
+ * really does work.
+ */
+
+ seek = (UINT32)readSize;
+ NTFS_SeekObj( hand, &seek );
+ }
+ }
+ *size += sizeout;
+ }
+ nt_hand->curPos = U64_Add( nt_hand->curPos,
+ U32_To_U64( (UINT32)*size ),
+ &dummy );
+
+ /*
+ * It seems that if a share dies (or is killed), the
+ * the only "error" we get is EOF reached (which isn't
+ * an error at all). So, if we get EOF reached, we
+ * better make sure we're at the end of the stream --
+ * if not, that's a corruption.
+ */
+
+ if ( (ret_val != SUCCESS) &&
+ !U64_EQ( nt_hand->curPos, nt_hand->nextStreamHeaderPos) )
+ {
+ ret_val = FS_STREAM_CORRUPT;
+ }
+ }
+ return ret_val;
+}
+
+/**/
+/**
+
+ Name: NTFS_ReadPathStream()
+
+ Description: This function copies the path into the provided buffer.
+ It will prepare the stream info at the beginning of the
+ stream.
+
+ Modified: 08-Sep-92
+
+ Returns: SUCCESS
+
+**/
+static INT16 NTFS_ReadPathStream( FILE_HAND hand,
+ BYTE_PTR buf,
+ UINT16 *size,
+ UINT16 *blk_size,
+ STREAM_INFO_PTR s_info )
+{
+ NTFS_OBJ_HAND_PTR nt_hand ;
+ NTFS_DBLK_PTR ddblk;
+ BYTE_PTR p ;
+ UINT16 p_offset ;
+ UINT16 sizeRead;
+ BOOLEAN dummy;
+
+ ddblk = (NTFS_DBLK_PTR)(hand->dblk) ;
+ nt_hand = (NTFS_OBJ_HAND_PTR)(hand->obj_hand.ptr ) ;
+
+ *blk_size = 1 ;
+
+ if ( nt_hand->needStreamHeader )
+ {
+ s_info->id = STRM_PATH_NAME;
+ s_info->fs_attrib = 0;
+ s_info->tf_attrib = 0;
+ s_info->size = U64_Init( ddblk->full_name_ptr->name_size, 0 );
+ nt_hand->nextStreamHeaderPos = s_info->size ;
+ nt_hand->needStreamHeader = FALSE ;
+ nt_hand->curPos = U64_Init( 0, 0 );
+ }
+ else
+ {
+ UINT16 pathLength = (UINT16)ddblk->full_name_ptr->name_size;
+
+ s_info->id = STRM_INVALID;
+
+ p = (BYTE_PTR)ddblk->full_name_ptr->name;
+
+ p_offset = (UINT16)U64_Lsw( nt_hand->curPos );
+ p += p_offset ;
+
+ if ( p_offset < pathLength )
+ {
+ sizeRead = min( *size, pathLength );
+
+ if ( sizeRead && (sizeRead % sizeof(CHAR)) )
+ {
+ sizeRead--;
+ }
+
+ if ( sizeRead > 0 )
+ {
+ UINT16 i;
+
+ for ( i = 0; (i < sizeRead/sizeof(CHAR) ); i++ )
+ {
+ CHAR_PTR p1, p2;
+ p1 = (CHAR_PTR)p;
+ p2 = (CHAR_PTR)buf;
+
+ if ( *p1 == TEXT('\\') )
+ {
+ *p2 = TEXT('\0');
+ }
+ else
+ {
+ *p2 = *p1;
+ }
+ buf+=sizeof(CHAR) ;
+ p+=sizeof(CHAR) ;
+ }
+ }
+ }
+ else
+ {
+ sizeRead = 0;
+ }
+ nt_hand->nameComplete = ((UINT16)(p_offset + sizeRead) == pathLength);
+
+ nt_hand->curPos = U64_Add( nt_hand->curPos,
+ U32_To_U64( (UINT32)sizeRead ),
+ &dummy );
+
+ *size = sizeRead;
+ }
+ return SUCCESS;
+}
+
+/**/
+/**
+
+ Name: NTFS_ReadFileNameStream()
+
+ Description: This function copies the file name into the provided
+ buffer. It will prepare the stream info at the beginning
+ of the stream.
+
+ Modified: 24-Sep-92
+
+ Returns: FS_EOF_REACHED
+ SUCCESS
+
+**/
+static INT16 NTFS_ReadFileNameStream( FILE_HAND hand,
+ BYTE_PTR buf,
+ UINT16 *size,
+ UINT16 *blk_size,
+ STREAM_INFO_PTR s_info )
+{
+ NTFS_OBJ_HAND_PTR nt_hand = (NTFS_OBJ_HAND_PTR)(hand->obj_hand.ptr ) ;
+ NTFS_DBLK_PTR ddblk = (NTFS_DBLK_PTR)(hand->dblk) ;
+ BYTE_PTR p ;
+ UINT16 p_offset ;
+ BOOLEAN dummy;
+ UINT16 sizeRead ;
+
+ *blk_size = 1 ;
+
+ if ( nt_hand->needStreamHeader )
+ {
+ s_info->id = STRM_FILE_NAME;
+ s_info->fs_attrib = 0;
+ s_info->tf_attrib = 0;
+ s_info->size = U64_Init( ddblk->full_name_ptr->name_size, 0 ) ;
+ nt_hand->nextStreamHeaderPos = s_info->size ;
+ }
+ else
+ {
+ UINT16 nameSize = (UINT16)ddblk->full_name_ptr->name_size;
+
+ s_info->id = STRM_INVALID;
+
+ p = (INT8_PTR)ddblk->full_name_ptr->name ;
+ p_offset = (UINT16)U64_Lsw( nt_hand->curPos );
+ p += p_offset ;
+
+ if ( p_offset < nameSize )
+ {
+ sizeRead = min( *size,
+ (UINT16)(ddblk->full_name_ptr->name_size - p_offset) ) ;
+
+ memcpy( buf, p, (size_t)sizeRead );
+ }
+ else
+ {
+ sizeRead = 0;
+ }
+
+ nt_hand->nameComplete = (p_offset + sizeRead) == nameSize;
+ nt_hand->curPos = U64_Add( nt_hand->curPos,
+ U32_To_U64( (UINT32)sizeRead ),
+ &dummy );
+ *size = sizeRead;
+ }
+
+ return SUCCESS;
+}
+
+
+/**/
+/**
+
+ Name: NTFS_ReadLinkInfo()
+
+ Description: Backs up the data stream for linked files.
+
+ Modified: 20-Oct-92
+
+ Returns: SUCCESS
+ FS_EOF_REACHED
+
+ Notes: Because it returns FS_EOF_REACHED at the end of the
+ stream, there is an implicit assumption that the link
+ information is the last stream for linked files.
+
+**/
+static INT16 NTFS_ReadLinkInfo( FILE_HAND hand,
+ BYTE_PTR buff,
+ UINT16 *size,
+ UINT16 *blk_size,
+ STREAM_INFO_PTR s_info )
+{
+ NTFS_OBJ_HAND_PTR nt_hand = (NTFS_OBJ_HAND_PTR)(hand->obj_hand.ptr ) ;
+ INT16 ret = SUCCESS;
+ UINT16 buffSize;
+
+ buffSize = *size;
+ *size = 0;
+
+ nt_hand->sawSecurity = TRUE ;
+
+ if ( nt_hand->needStreamHeader &&
+ U64_EQ( nt_hand->curPos, U64_Init( 0, 0 ) ) )
+ {
+ /* Prepare the link stream info */
+ s_info->id = STRM_NTFS_LINK;
+ s_info->size = U64_Init( (UINT32)nt_hand->linkPtr->linkNameLen, 0 );
+ s_info->fs_attrib = 0;
+ s_info->tf_attrib = 0;
+
+ nt_hand->curPos = U64_Init( 0, 0 );
+ nt_hand->nextStreamHeaderPos = s_info->size;
+ }
+ else
+ {
+ s_info->id = STRM_INVALID;
+
+ if ( U64_EQ( nt_hand->curPos, nt_hand->nextStreamHeaderPos ) )
+ {
+ ret = FS_EOF_REACHED;
+ }
+ else
+ {
+ UINT16 readSize;
+ BOOLEAN dummy;
+
+ /* Transfer the link stream to the buffer */
+
+ readSize = CalcReadSize( nt_hand->curPos,
+ nt_hand->nextStreamHeaderPos,
+ buffSize );
+ memcpy( buff,
+ (BYTE_PTR)nt_hand->linkPtr->linkName + U64_Lsw( nt_hand->curPos ),
+ readSize );
+
+ nt_hand->curPos = U64_Add( nt_hand->curPos,
+ U32_To_U64( (UINT32)readSize ),
+ &dummy );
+ *size = readSize;
+ }
+ }
+ return ret;
+}
+
+
+/**/
+/**
+
+ Name: BackStreamHeader()
+
+ Description: This function reads an NT stream header from the
+ Backup API and translates it to STREAM_INFO.
+
+ Modified: 08-Sep-92
+
+ Returns: FS_EOF_REACHED
+ SUCCESS
+
+ Notes:
+
+**/
+static INT16 BackStreamHeader(
+ FILE_HAND hand, /* I - handle of object to read from */
+ STREAM_INFO_PTR s_info ) /* O - Stream information for the data returned */
+{
+ NTFS_OBJ_HAND_PTR nt_hand = (NTFS_OBJ_HAND_PTR)(hand->obj_hand.ptr ) ;
+ INT16 ret_val = SUCCESS ;
+ INT status ;
+ INT sizeout ;
+
+ nt_hand->curPos = U64_Init( 0, 0 );
+
+ status = BackupRead( nt_hand->fhand,
+ (LPBYTE)&nt_hand->streamHeader,
+ NT_SIZEOF_NAMELESS_STREAM_HEAD,
+ (LPDWORD)&sizeout,
+ FALSE,
+ TRUE,
+ &nt_hand->context ) ;
+
+ if ( !status || (sizeout < NT_SIZEOF_NAMELESS_STREAM_HEAD) )
+ {
+ DWORD error = GetLastError();
+
+ if ( (error != NO_ERROR) &&
+ (error != ERROR_HANDLE_EOF) &&
+ (error != ERROR_INVALID_PARAMETER) )
+ {
+ NTFS_DebugPrint( TEXT("NTFS_BackStreamHeader: BackupRead error %d")
+ TEXT(" on \"%s\""),
+ (int)error,
+ ((NTFS_DBLK_PTR)hand->dblk)->full_name_ptr->name );
+ }
+
+ s_info->id = STRM_INVALID;
+ ret_val = FS_EOF_REACHED;
+ }
+ else
+ {
+ s_info->id = NTFS_MSoftToMayn( nt_hand->streamHeader.id );
+ s_info->fs_attrib = (UINT16)nt_hand->streamHeader.attrib;
+ s_info->tf_attrib = 0 ;
+ s_info->size = U64_Init( nt_hand->streamHeader.size_lo,
+ nt_hand->streamHeader.size_hi ) ;
+
+ if ( nt_hand->streamHeader.attrib & STREAM_CONTAINS_SECURITY ) {
+ nt_hand->sawSecurity = TRUE ;
+ }
+
+ nt_hand->needStreamHeader = FALSE;
+
+ if ( nt_hand->streamHeader.name_leng > 0 )
+ {
+ BOOLEAN dummy;
+ UINT16 nameSize;
+
+ nameSize = (UINT16)(nt_hand->streamHeader.name_leng +
+ sizeof(nt_hand->streamHeader.name_leng));
+
+ s_info->size = U64_Add( s_info->size,
+ U32_To_U64( (UINT32)nameSize ),
+ &dummy ) ;
+ }
+ nt_hand->nextStreamHeaderPos = s_info->size ;
+ }
+ return ret_val;
+}
+
+/**/
+/**
+
+ Name: CalcReadSize()
+
+ Description: Calculates 16-bit read size from 64-bit position
+ information and 16-bit buffer size.
+
+ Modified: 08-Sep-92
+
+ Returns: Amount of data to read.
+
+ Notes:
+
+**/
+static UINT16 CalcReadSize( UINT64 startPos,
+ UINT64 endPos,
+ UINT16 buffSize )
+{
+ UINT16 readSize;
+ BOOLEAN mathStat;
+
+ if ( U64_GT( U64_Add( startPos,
+ U32_To_U64( (UINT32)buffSize ),
+ &mathStat ),
+ endPos ) )
+ {
+ UINT64 rs;
+
+ rs = U64_Sub( endPos,
+ startPos,
+ &mathStat );
+
+ msassert( mathStat && (U64_Msw( rs ) == 0) && (U64_Lsw(rs) < 65536) );
+
+ readSize = (UINT16)U64_Lsw( rs );
+ } else {
+ readSize = buffSize;
+ }
+
+ return readSize;
+}
+
diff --git a/private/utils/ntbackup/src/tree.ico b/private/utils/ntbackup/src/tree.ico
new file mode 100644
index 000000000..bac427399
--- /dev/null
+++ b/private/utils/ntbackup/src/tree.ico
Binary files differ
diff --git a/private/utils/ntbackup/src/treefile.ico b/private/utils/ntbackup/src/treefile.ico
new file mode 100644
index 000000000..f7e72496c
--- /dev/null
+++ b/private/utils/ntbackup/src/treefile.ico
Binary files differ
diff --git a/private/utils/ntbackup/src/tseekobj.c b/private/utils/ntbackup/src/tseekobj.c
new file mode 100644
index 000000000..663c733c7
--- /dev/null
+++ b/private/utils/ntbackup/src/tseekobj.c
@@ -0,0 +1,143 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tseekobj.c
+
+ Description: This file contains code to Seek to specific portion of
+ an opened object.
+
+
+ $Log: M:/LOGFILES/TSEEKOBJ.C_V $
+
+ Rev 1.4 22 Mar 1994 16:18:38 BARRY
+Update needStreamHeader flag after seeking on a handle opened for READ
+
+ Rev 1.3 16 Aug 1993 22:32:30 BARRY
+Allow seek of zero bytes without error.
+
+ Rev 1.2 02 Nov 1992 14:52:16 BARRY
+Added BackupSeek functionality.
+
+ Rev 1.1 21 May 1992 13:49:18 STEVEN
+more long path support
+
+ Rev 1.0 12 Feb 1992 10:48:20 STEVEN
+Initial revision.
+
+**/
+#include <windows.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "msassert.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "fsys_err.h"
+#include "ntfsdblk.h"
+#include "ntfs_fs.h"
+
+/**/
+/**
+
+ Name: NTFS_SeekObj()
+
+ Description: This function seeks to the specified location of an
+ opened object.
+
+ Modified: 02-Nov-92
+
+ Returns: Error Codes :
+ FS_OBJECT_NOT_OPENED
+ FS_EOF_REACHED
+ SUCCESS
+
+**/
+INT16 NTFS_SeekObj(
+ FILE_HAND hand, /* I - Opened object to seek into */
+ UINT32 *offset ) /*I/O- Offset to seek; bytes actually seeked */
+{
+ NTFS_OBJ_HAND_PTR nt_hand = hand->obj_hand.ptr;
+ INT16 ret;
+
+ switch ( hand->dblk->blk_type )
+ {
+ case FDB_ID:
+ case DDB_ID:
+ {
+ DWORD wentLo;
+ DWORD wentHi;
+ BOOLEAN stat;
+
+ /*
+ * Make sure we don't seek into the next stream header
+ */
+ if ( U64_GT( U64_Add( nt_hand->curPos,
+ U32_To_U64( *offset ),
+ &stat ),
+ nt_hand->nextStreamHeaderPos ) )
+ {
+ UINT64 seek;
+
+ seek = U64_Sub( nt_hand->nextStreamHeaderPos,
+ nt_hand->curPos,
+ &stat );
+
+ msassert( stat && (U64_Msw(seek) == 0) );
+ *offset = U64_Lsw( seek );
+ }
+
+ if ( *offset == 0 )
+ {
+ /*
+ * A seek of zero bytes should be OK
+ */
+ ret = SUCCESS;
+ }
+ else
+ {
+ stat = BackupSeek( nt_hand->fhand,
+ *offset,
+ 0,
+ &wentLo,
+ &wentHi,
+ &nt_hand->context );
+ if ( stat )
+ {
+ ret = SUCCESS;
+ *offset = wentLo;
+ msassert( wentHi == 0 );
+ nt_hand->curPos = U64_Add( nt_hand->curPos,
+ U32_To_U64( *offset ),
+ &stat );
+ }
+ else
+ {
+ ret = FS_EOF_REACHED;
+ }
+ }
+ break;
+ }
+
+ default:
+ *offset = 0;
+ ret = FS_OBJECT_NOT_OPENED;
+ break;
+ }
+
+ /*
+ * Since we may have moved the curPos, we need to update the flag
+ * that indicates whether we're ready for another stream header.
+ * (The only place we look at this is in the ReadObj code.)
+ */
+ if ( hand->mode == FS_READ )
+ {
+ nt_hand->needStreamHeader = U64_EQ( nt_hand->curPos,
+ nt_hand->nextStreamHeaderPos);
+ }
+ return ret;
+}
+
+
diff --git a/private/utils/ntbackup/src/tsetinfo.c b/private/utils/ntbackup/src/tsetinfo.c
new file mode 100644
index 000000000..29d7b9e7c
--- /dev/null
+++ b/private/utils/ntbackup/src/tsetinfo.c
@@ -0,0 +1,237 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tsetinfo.c
+
+ Description: This file contains code to write the OS specific
+ data stored in the DBLKS to the OS
+
+
+ $Log: N:/LOGFILES/TSETINFO.C_V $
+
+ Rev 1.8 07 Dec 1992 14:18:24 STEVEN
+updates from msoft
+
+ Rev 1.7 17 Nov 1992 22:18:44 DAVEV
+unicode fixes
+
+ Rev 1.6 11 Nov 1992 09:53:38 GREGG
+Unicodeized literals.
+
+ Rev 1.5 10 Nov 1992 08:20:38 STEVEN
+removed path and name from dblk now use full_name_ptr
+
+ Rev 1.4 24 Sep 1992 13:43:56 BARRY
+Changes for huge file name support.
+
+ Rev 1.3 21 May 1992 13:51:02 STEVEN
+more long path stuff
+
+ Rev 1.2 04 May 1992 09:24:22 LORIB
+Changes to variable length paths and fixes for structure member names.
+
+ Rev 1.1 28 Feb 1992 13:03:50 STEVEN
+step one for varible length paths
+
+ Rev 1.0 10 Feb 1992 16:45:24 STEVEN
+Initial revision.
+
+**/
+#include <windows.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "fsys.h"
+#include "fsys_err.h"
+#include "ntfsdblk.h"
+#include "ntfs_fs.h"
+#include "msassert.h"
+
+static INT16 NTFS_SetFileInfo( FSYS_HAND fsh, NTFS_DBLK_PTR ddblk ) ;
+static INT16 NTFS_SetDirInfo( FSYS_HAND fsh, NTFS_DBLK_PTR ddblk ) ;
+
+/**/
+/**
+
+ Name: NTFS_SetObjInfo()
+
+ Description: This funciton writes the OS info in a DBLK to disk
+
+ Modified: 2/10/1992 16:31:17
+
+ Returns: Error codes:
+ FS_NOT_FOUND
+ FS_ACCESS_DENIED
+ SUCCESS
+
+ Notes: Only type supported are FDBs and DDBs
+
+**/
+INT16 NTFS_SetObjInfo( fsh, dblk )
+FSYS_HAND fsh ; /* I - file system handle */
+DBLK_PTR dblk ; /* I - data to write to disk */
+{
+ INT16 ret_val;
+ NTFS_DBLK_PTR ddblk;
+
+ ddblk = (NTFS_DBLK_PTR) dblk;
+
+
+ msassert( fsh->attached_dle != NULL ) ;
+
+ switch ( ddblk->blk_type ) {
+
+ case FDB_ID :
+
+ ret_val = NTFS_SetFileInfo( fsh, ddblk ) ;
+ break ;
+
+ case DDB_ID:
+
+ ret_val = NTFS_SetDirInfo( fsh, ddblk ) ;
+ break ;
+
+ break;
+
+ default:
+
+ ret_val = FS_NOT_FOUND ;
+ }
+
+ return ret_val ;
+}
+
+
+/**/
+/**
+
+ Name: NTFS_SetFileInfo()
+
+ Description: This funciton writes the file information
+ in the FDB to disk. The file is assumed to already
+ be closed.
+
+ Modified: 2/10/1992 16:32:55
+
+ Returns: Error codes:
+ FS_NOT_FOUND
+ FS_ACCESS_DENIED
+ SUCCESS
+
+ Notes:
+
+**/
+static INT16 NTFS_SetFileInfo( fsh, ddblk )
+FSYS_HAND fsh ; /* I - File system handle */
+NTFS_DBLK_PTR ddblk ; /* I - Data to write to disk */
+{
+ INT16 ret_val = SUCCESS ;
+ CHAR_PTR path ;
+
+ if ( NTFS_SetupWorkPath( fsh,
+ fsh->cur_dir,
+ ddblk->full_name_ptr->name,
+ &path ) != SUCCESS) {
+
+ return OUT_OF_MEMORY ;
+ }
+
+ ddblk->b.f.handle = CreateFile( path,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL| FILE_FLAG_BACKUP_SEMANTICS,
+ NULL ) ;
+
+
+ if ( ddblk->b.f.handle != INVALID_HANDLE_VALUE ) {
+ DWORD attrib;
+
+ SetFileTime( ddblk->b.f.handle,
+ &(ddblk->dta.create_time),
+ &(ddblk->dta.access_time),
+ &(ddblk->dta.modify_time) ) ;
+
+ CloseHandle( ddblk->b.f.handle ) ;
+
+ attrib = ddblk->dta.os_attr ;
+ if (attrib == 0 ) {
+ attrib = FILE_ATTRIBUTE_NORMAL ;
+ }
+
+ if ( !SetFileAttributes( path, attrib ) ) {
+ ret_val = FS_ACCESS_DENIED ;
+ }
+
+ } else {
+ ret_val = FS_ACCESS_DENIED ;
+ }
+
+ NTFS_ReleaseWorkPath( fsh ) ;
+
+ return ret_val ;
+}
+
+
+/**/
+/**
+
+ Name: NTFS_SetDirInfo()
+
+ Description: This funciton sets the attributes of a NTFS directory.
+
+ Modified: 7/26/1989
+
+ Returns: Error codes:
+ FS_NOT_FOUND
+ FS_ACCESS_DENIED
+ SUCCESS
+
+ Notes:
+
+ See also: $/SEE( DOS_SetDirInfo() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+static INT16 NTFS_SetDirInfo( fsh, ddblk )
+FSYS_HAND fsh ; /* I - File system handle */
+NTFS_DBLK_PTR ddblk ; /* I - Data to write to disk */
+{
+ INT16 ret_val = SUCCESS ;
+ CHAR_PTR path ;
+ DWORD attrib ;
+
+ path = ddblk->full_name_ptr->name ;
+
+ if ( NTFS_SetupWorkPath( fsh, path, NULL, &path ) != SUCCESS) {
+ return OUT_OF_MEMORY ;
+ }
+
+ if ( path[3] != TEXT('\0') ) {
+
+ attrib = ddblk->dta.os_attr ;
+ if ( attrib == 0 ) {
+ attrib = FILE_ATTRIBUTE_NORMAL ;
+ }
+ if ( !SetFileAttributes( path, attrib ) ) {
+ ret_val = FS_ACCESS_DENIED ;
+ }
+
+ /* Setting the time and date for a DOS directory */
+ /* would require a disk write over the directory file. */
+ /* (see DOS 3.3 Tech Ref manual page 5-10) The directory */
+ /* entries have different structures in different version of */
+ /* DOS. */
+
+ }
+
+ NTFS_ReleaseWorkPath( fsh ) ;
+
+ return ret_val ;
+}
diff --git a/private/utils/ntbackup/src/tsize.c b/private/utils/ntbackup/src/tsize.c
new file mode 100644
index 000000000..256746783
--- /dev/null
+++ b/private/utils/ntbackup/src/tsize.c
@@ -0,0 +1,253 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tsize.c
+
+ Description: This file contains code to get the size of the
+ variable length fields in FDBs and DDBs
+
+
+ $Log: N:/LOGFILES/TSIZE.C_V $
+
+ Rev 1.13 21 Feb 1994 20:53:54 STEVEN
+inconsistance between info and infoSize
+
+ Rev 1.12 10 Nov 1992 08:20:42 STEVEN
+removed path and name from dblk now use full_name_ptr
+
+ Rev 1.11 06 Nov 1992 16:27:54 STEVEN
+test unlimited file sizes
+
+ Rev 1.10 06 Nov 1992 15:49:28 STEVEN
+test write of path in stream
+
+ Rev 1.9 09 Oct 1992 14:33:34 BARRY
+Name-in-stream changes.
+
+ Rev 1.7 24 Sep 1992 13:43:58 BARRY
+Changes for huge file name support.
+
+ Rev 1.6 20 Jul 1992 10:43:14 STEVEN
+backup short file name
+
+ Rev 1.5 09 Jun 1992 15:15:08 BURT
+Sync with NT stuff
+
+ Rev 1.3 22 May 1992 16:05:30 STEVEN
+
+
+ Rev 1.2 21 May 1992 13:49:10 STEVEN
+more long path support
+
+ Rev 1.1 04 May 1992 09:19:14 LORIB
+Changed structure member "dta" to "b.f".
+
+ Rev 1.0 17 Jan 1992 17:50:02 STEVEN
+Initial revision.
+
+**/
+#include <windows.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "stdwcs.h"
+#include "msassert.h"
+#include "tfldefs.h"
+#include "fsys.h"
+#include "ntfsdblk.h"
+#include "ntfs_fs.h"
+#include "osinfo.h"
+
+
+/**/
+/**
+
+ Name: NTFS_SizeofFname()
+
+ Description: This function returns the size of the file
+ name contained in the FDB bassed in
+
+ Modified: 9/11/1989
+
+ Returns: number of bytes including terminating NULL.
+
+ Notes:
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 NTFS_SizeofFname( fsh, fdb )
+FSYS_HAND fsh; /* I - file system in use */
+DBLK_PTR fdb ; /* I - dblk to get fname from */
+{
+ NTFS_DBLK_PTR ddblk = (NTFS_DBLK_PTR)fdb;
+ INT16 size ;
+
+ (void)fsh ;
+
+ msassert( fdb->blk_type == FDB_ID ) ;
+
+ size = (INT16)ddblk->full_name_ptr->name_size ;
+
+ return size ;
+}
+
+/**/
+/**
+
+ Name: NTFS_SizeofOSFname()
+
+ Description: This function returns the size of the file
+ name (as it appears on tape) contained in the FDB bassed in
+
+ Modified: 9/11/1989
+
+ Returns: number of bytes including terminating NULL.
+
+ Notes:
+
+**/
+INT16 NTFS_SizeofOSFname( fsh, fdb )
+FSYS_HAND fsh; /* I - file system in use */
+DBLK_PTR fdb ; /* I - dblk to get fname from */
+{
+ NTFS_DBLK_PTR ddblk = (NTFS_DBLK_PTR)fdb;
+ INT16 size ;
+
+ (void)fsh ;
+
+ msassert( fdb->blk_type == FDB_ID ) ;
+
+ if ( fdb->com.os_name == NULL ) // backup only
+ {
+ size = (INT16)strsize( ddblk->full_name_ptr->name ) ;
+ }
+ else
+ {
+ size = (INT16)fdb->com.os_name->name_size ;
+
+ }
+ return size ;
+}
+
+/**/
+/**
+
+ Name: NTFS_SizeofPath()
+
+ Description: This function return the size of the path saved in the
+ DDB.
+
+ Modified: 9/11/1989
+
+ Returns: Number of bytes in path string
+
+ Notes:
+
+**/
+INT16 NTFS_SizeofPath( fsh, ddb )
+FSYS_HAND fsh ; /* I - File system handle */
+DBLK_PTR ddb ; /* I - DBLK to get path size from */
+{
+ NTFS_DBLK_PTR ddblk ;
+ INT16 size;
+
+ (VOID)fsh ;
+
+ msassert( ddb->blk_type == DDB_ID ) ;
+
+ ddblk = ( NTFS_DBLK_PTR) ddb ;
+
+ size = (INT16)ddblk->full_name_ptr->name_size;
+
+ return size;
+}
+/**/
+/**
+
+ Name: NTFS_SizeofOSPath()
+
+ Description: This function return the size of the path saved in the
+ DDB.
+
+ Modified: 9/11/1989
+
+ Returns: Number of bytes in path string
+
+ Notes:
+
+ Declaration:
+
+**/
+INT16 NTFS_SizeofOSPath( fsh, ddb )
+FSYS_HAND fsh ; /* I - File system handle */
+DBLK_PTR ddb ; /* I - DBLK to get path size from */
+{
+ NTFS_DBLK_PTR dddb = (NTFS_DBLK_PTR)ddb ;
+ INT16 size;
+
+ (void)fsh ;
+ msassert( ddb->blk_type == DDB_ID ) ;
+
+
+ if ( ddb->com.os_name != NULL )
+ {
+ size = ddb->com.os_name->name_size ;
+ }
+ else
+ {
+ size = (INT16)dddb->full_name_ptr->name_size ;
+ }
+ return size;
+}
+
+
+/**/
+/**
+
+ Name: NTFS_SizeofOSInfo()
+
+ Description: This function returns the size of the OS info for
+ an FDB or a DDB
+
+ Modified: 9/11/1989
+
+ Returns: Size in bytes.
+
+ Notes:
+
+ Declaration:
+
+**/
+INT16 NTFS_SizeofOSInfo( fsh, dblk)
+FSYS_HAND fsh ; /* I - File system handle */
+DBLK_PTR dblk; /* I - DBLK to get size of OS info for */
+{
+ NTFS_DBLK_PTR ddblk ;
+ INT16 size ;
+
+ (void)fsh ;
+
+ ddblk = (NTFS_DBLK_PTR)dblk ;
+
+ if ( dblk->blk_type == BT_FDB ) {
+
+ size = sizeof( NT_FILE_OS_INFO ) ;
+
+ if ( ddblk->b.f.alt_name[0] != TEXT('\0') ) {
+
+ size += strsize( ddblk->b.f.alt_name ) ;
+ }
+
+ } else if ( dblk->blk_type == BT_DDB ) {
+ size = (INT16)sizeof( NT_DIR_OS_INFO ) ;
+
+ } else {
+
+ size = 0;
+
+ }
+ return size;
+}
diff --git a/private/utils/ntbackup/src/tverinfo.c b/private/utils/ntbackup/src/tverinfo.c
new file mode 100644
index 000000000..f7b6355d8
--- /dev/null
+++ b/private/utils/ntbackup/src/tverinfo.c
@@ -0,0 +1,279 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tverinfo.c
+
+ Description: This file contains code to verify the DBLKS
+
+ $Log: N:\logfiles\tverinfo.c_v $
+
+ Rev 1.20.1.2 15 Jul 1994 19:52:32 STEVEN
+fix more net errors
+
+ Rev 1.20.1.1 17 Jun 1994 20:05:16 STEVEN
+fix bug with net dissconect
+
+ Rev 1.20.1.0 26 Apr 1994 19:01:42 STEVEN
+fix disconnect bug
+
+ Rev 1.20 22 Feb 1994 16:27:24 STEVEN
+GetFileAttributes does not check Backup Priv
+
+ Rev 1.19 23 Jan 1994 14:04:56 BARRY
+Added debug code
+
+ Rev 1.18 04 Nov 1993 17:07:00 BARRY
+Make errors a little different when we can't get object info
+
+ Rev 1.17 18 Aug 1993 12:01:42 BARRY
+Don't do FindFirst for dirs, call GetFileAttributes instead.
+
+ Rev 1.16 29 Jun 1993 16:14:08 BARRY
+If info fails to verify, check to see if it's a registry file. If so, skip it.
+
+ Rev 1.15 01 Jun 1993 16:20:06 STEVEN
+fix posix bugs
+
+ Rev 1.14 08 Apr 1993 17:01:38 BARRY
+Don't check date/time on files.
+
+ Rev 1.13 11 Mar 1993 21:06:34 BARRY
+Now report file size and date/time differences.
+
+ Rev 1.12 24 Feb 1993 17:33:02 BARRY
+Fixed improper return code when files not found.
+
+ Rev 1.11 27 Jan 1993 13:51:16 STEVEN
+updates from msoft
+
+ Rev 1.10 11 Jan 1993 08:48:46 STEVEN
+fix bugs from microsoft
+
+ Rev 1.9 11 Nov 1992 09:53:42 GREGG
+Unicodeized literals.
+
+ Rev 1.8 10 Nov 1992 08:18:58 STEVEN
+removed path and name from dblk now use full_name_ptr
+
+ Rev 1.7 24 Sep 1992 13:43:58 BARRY
+Changes for huge file name support.
+
+ Rev 1.6 25 Jun 1992 11:20:08 STEVEN
+dates compared in wrong units
+
+ Rev 1.5 21 May 1992 13:51:00 STEVEN
+more long path stuff
+
+ Rev 1.4 04 May 1992 09:23:36 LORIB
+Changes for variable length paths.
+
+ Rev 1.3 12 Mar 1992 15:50:38 STEVEN
+64 bit changes
+
+ Rev 1.2 28 Feb 1992 13:03:30 STEVEN
+step one for varible length paths
+
+ Rev 1.0 12 Feb 1992 14:28:20 STEVEN
+Initial revision.
+
+**/
+#include <windows.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "std_err.h"
+#include "fsys.h"
+#include "fsys_err.h"
+#include "ntfsdblk.h"
+#include "ntfs_fs.h"
+#include "msassert.h"
+
+#define ATTR_MSK ( FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM )
+
+/**/
+/**
+
+ Name: NTFS_VerObjInfo()
+
+ Description: This funciton compares the data in a DBLK with
+ the data returned by the operating system.
+
+ Modified: 2/12/1992 13:6:5
+
+ Returns: Error Codes:
+ FS_NOT_FOUND
+ FS_ACCESS_DENIED
+ FS_INFO_DIFFERENT
+ SUCCESS
+
+ Notes: For FDBs this funciton will check the current
+ directory for the specified file.
+
+**/
+INT16 NTFS_VerObjInfo( fsh, dblk )
+FSYS_HAND fsh ; /* I - File system handle */
+DBLK_PTR dblk ; /* I - On entry it is minimal on exit Complete */
+{
+ INT16 ret_val = SUCCESS ;
+ NTFS_DBLK_PTR ddblk;
+ HANDLE old_scan_hand ;
+ WIN32_FIND_DATA find_data ;
+ CHAR_PTR path_string ;
+ CHAR_PTR org_path_string ;
+
+ msassert( dblk != NULL );
+ msassert( fsh->attached_dle != NULL ) ;
+
+ /* form BASE_PATH */
+
+ ddblk = (NTFS_DBLK_PTR) dblk;
+
+ switch( dblk->blk_type ){
+
+ case DDB_ID :
+
+ path_string = ddblk->full_name_ptr->name ;
+
+ if ( path_string[ 0 ] != TEXT('\0') )
+ {
+
+ if ( NTFS_SetupWorkPath( fsh, path_string, NULL, &path_string ) != SUCCESS)
+ {
+ return OUT_OF_MEMORY ;
+ }
+
+ memset( &find_data, 0, sizeof( find_data ) ) ;
+ old_scan_hand = FindFirstFile( path_string, &find_data ) ;
+
+ if ( old_scan_hand == (HANDLE)-1 )
+ {
+ DWORD error = GetLastError();
+
+ if ( ( error == ERROR_NETNAME_DELETED ) ||
+ ( error == ERROR_BAD_NETPATH ) ||
+ ( error == ERROR_UNEXP_NET_ERR ) ||
+ ( error == ERROR_BAD_NET_NAME ) )
+ {
+ ret_val = FS_COMM_FAILURE ;
+ }
+
+ else if ( error == ERROR_FILE_NOT_FOUND )
+ {
+ ret_val = FS_NOT_FOUND;
+ }
+ else
+ {
+ ret_val = FS_ACCESS_DENIED;
+ }
+ }
+ else
+ {
+ if ( (find_data.dwFileAttributes & ATTR_MSK) != (ddblk->dta.os_attr & ATTR_MSK) )
+ {
+ ret_val = FS_INFO_DIFFERENT;
+ }
+ FindClose( old_scan_hand ) ;
+
+ }
+
+ NTFS_ReleaseWorkPath( fsh ) ;
+
+ }
+ else
+ {
+ /* info about NTFS root directories cannot be modified */
+ ret_val = SUCCESS ;
+ }
+ break;
+
+
+
+ case FDB_ID :
+
+ if ( NTFS_SetupWorkPath( fsh,
+ fsh->cur_dir,
+ ddblk->full_name_ptr->name,
+ &path_string ) != SUCCESS)
+ {
+ return OUT_OF_MEMORY ;
+ }
+
+ org_path_string = path_string ;
+ path_string = NTFS_GetTempName( path_string );
+
+ memset( &find_data, 0, sizeof( find_data ) ) ;
+ old_scan_hand = FindFirstFile( path_string, &find_data ) ;
+
+ /*
+ * if the names differ only by case then look for another
+ * file with same name
+ */
+ if ( ( old_scan_hand != INVALID_HANDLE_VALUE ) &&
+ ( fsh->attached_dle->feature_bits & DLE_FEAT_CASE_PRESERVING ) &&
+ ( path_string == org_path_string ) &&
+ strcmp( ddblk->full_name_ptr->name, find_data.cFileName ) ) {
+
+
+ if ( !FindNextFile( old_scan_hand, &find_data ) )
+ {
+ old_scan_hand = INVALID_HANDLE_VALUE;
+ }
+ }
+
+ if ( old_scan_hand == INVALID_HANDLE_VALUE )
+ {
+ DWORD error = GetLastError();
+
+ NTFS_DebugPrint( TEXT("NTFS_VerObjInfo: FindFirst/NextFile")
+ TEXT(" error = %d, path = \"%s\""),
+ (int)GetLastError(),
+ path_string );
+
+ if ( ( error == ERROR_NETNAME_DELETED ) ||
+ ( error == ERROR_BAD_NET_NAME ) )
+ {
+ ret_val = FS_COMM_FAILURE ;
+ }
+ else if ( error == ERROR_FILE_NOT_FOUND )
+ {
+ ret_val = FS_NOT_FOUND;
+ }
+ else
+ {
+ ret_val = FS_ACCESS_DENIED;
+ }
+ }
+ else
+ {
+ UINT64 fsize;
+
+ fsize = U64_Init( find_data.nFileSizeLow, find_data.nFileSizeHigh ) ;
+
+ if ( ((find_data.dwFileAttributes & ATTR_MSK) != (ddblk->dta.os_attr & ATTR_MSK)) ||
+ (!U64_EQ( fsize, ddblk->dta.size)) )
+ {
+ if ( REG_IsRegistryFile( fsh->attached_dle, path_string ) )
+ {
+ ret_val = FS_SKIP_OBJECT;
+ }
+ else
+ {
+ ret_val = FS_INFO_DIFFERENT ;
+ }
+ }
+ FindClose( old_scan_hand ) ;
+ }
+ NTFS_ReleaseWorkPath( fsh ) ;
+ break ;
+
+ case VCB_ID:
+ ret_val = SUCCESS ;
+ break ;
+
+ default :
+ ret_val = FS_NOT_FOUND ;
+ }
+ return ret_val ;
+}
diff --git a/private/utils/ntbackup/src/tverobj.c b/private/utils/ntbackup/src/tverobj.c
new file mode 100644
index 000000000..39a3ff2a4
--- /dev/null
+++ b/private/utils/ntbackup/src/tverobj.c
@@ -0,0 +1,920 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tverobj.c
+
+ Description: This file verifies the object data.
+
+
+ $Log: M:/LOGFILES/TVEROBJ.C_V $
+
+ Rev 1.26.2.1 24 Mar 1994 20:28:58 BARRY
+Fix frag on alt stream names
+
+ Rev 1.26.2.0 21 Mar 1994 18:34:10 GREGG
+Steve's fix of bug with verify and mac info.
+
+ Rev 1.26 28 Jan 1994 10:34:20 GREGG
+More Warning Fixes
+
+ Rev 1.25 23 Jan 1994 14:21:34 BARRY
+Added debug code
+
+ Rev 1.24 06 Jan 1994 12:35:50 BARRY
+Don't bother calling the OS if a zero-byte buffer comes down
+
+ Rev 1.23 10 Dec 1993 14:31:16 BARRY
+Use correct stream IDs for path/file
+
+ Rev 1.22 24 Nov 1993 15:00:54 BARRY
+Changed CHAR_PTRs in I/O functions to BYTE_PTRs
+
+ Rev 1.21 14 Oct 1993 17:50:08 STEVEN
+fix unicode bugs
+
+ Rev 1.20 12 Aug 1993 16:01:12 BARRY
+Don't do infinite loop on zero bytes read.
+
+ Rev 1.19 08 Jul 1993 12:20:08 BARRY
+Don't verify CRC streams
+
+ Rev 1.18 29 Jun 1993 16:21:10 BARRY
+Don't verify registry files.
+
+ Rev 1.17 03 Jun 1993 18:44:06 BARRY
+Got rid of redundant local var.
+
+ Rev 1.16 01 Jun 1993 16:20:24 STEVEN
+fix posix bugs
+
+ Rev 1.15 26 May 1993 14:44:38 STEVEN
+alignment bug with mips
+
+ Rev 1.14 11 Mar 1993 12:09:54 BARRY
+Fixed to uniquely identify alternate data streams.
+
+ Rev 1.13 08 Feb 1993 11:49:44 BARRY
+Discard NACL streams if restoreSecurity in config is FALSE.
+
+ Rev 1.12 27 Jan 1993 13:51:20 STEVEN
+updates from msoft
+
+ Rev 1.11 08 Dec 1992 10:30:56 STEVEN
+fix verify of alt data stream
+
+ Rev 1.10 07 Dec 1992 14:16:16 STEVEN
+updates from msoft
+
+ Rev 1.9 09 Nov 1992 17:37:42 BARRY
+Make verify stream-aware.
+
+ Rev 1.8 02 Nov 1992 10:38:24 STEVEN
+needed to set blk_size
+
+ Rev 1.7 18 Sep 1992 15:39:12 BARRY
+Changes for Stream Header redesign.
+
+ Rev 1.6 02 Sep 1992 07:48:34 STEVEN
+fix typo
+
+ Rev 1.5 01 Sep 1992 16:11:14 STEVEN
+added stream headers to fsys API
+
+ Rev 1.4 17 Aug 1992 16:22:50 STEVEN
+fix warnings
+
+ Rev 1.3 12 Aug 1992 17:48:00 STEVEN
+fixed bugs at microsoft
+
+ Rev 1.2 11 Jun 1992 16:34:28 STEVEN
+verify was failing
+
+ Rev 1.1 21 May 1992 13:49:22 STEVEN
+more long path support
+
+ Rev 1.0 12 Feb 1992 14:34:36 STEVEN
+Initial revision.
+
+**/
+#define FS_DEBUG 1
+#include <windows.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "stdmath.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "fsys_err.h"
+#include "ntfsdblk.h"
+#include "ntfs_fs.h"
+#include "msassert.h"
+
+
+static INT16 NTFS_VerData( FILE_HAND hand,
+ BYTE *buf,
+ BYTE *data,
+ UINT16 *size,
+ UINT16 *blk_size,
+ STREAM_INFO_PTR s_info );
+
+static INT16 SeekToStream( FILE_HAND hand,
+ NT_STREAM_HEADER *inputHeader,
+ NT_STREAM_HEADER *outputHeader );
+
+static INT16 SeekForward( FILE_HAND hand,
+ NT_STREAM_HEADER *inputHeader,
+ NT_STREAM_HEADER *outputHeader );
+
+static INT16 Rewind( FILE_HAND hand );
+
+static INT16 ReadStreamHeader( FILE_HAND hand, NT_STREAM_HEADER *sh );
+
+static INT16 GetStreamPos( FILE_HAND hand, NT_STREAM_HEADER *sh );
+
+static INT16 EnqueueStreamID( FILE_HAND hand, NT_STREAM_HEADER *sh );
+
+static INT16 ClassifyError( FILE_HAND hand, UINT32 streamID );
+
+static BOOLEAN ExtractNameFromBuffer( NTFS_OBJ_HAND_PTR nt_hand,
+ NT_STREAM_HEADER_PTR streamHeader,
+ BYTE_PTR data,
+ UINT16 *size,
+ UINT16 *blk_size );
+/**/
+/**
+
+ Name: NTFS_VerObj()
+
+ Description: This function verifies the data in an object.
+
+ Modified: 2/12/1992 14:29:33
+
+ Returns: Error Codes:
+ FS_DEVICE_ERROR
+ FS_EOF_REACHED
+ FS_GDATA_DIFFERENT
+ FS_SECURITY_DATA_DIFFERENT
+ SUCCESS
+
+**/
+/* begin declaration */
+INT16 NTFS_VerObj(
+FILE_HAND hand, /* I - file handle to verify data with */
+BYTE_PTR buf, /* I - buffer needed to perform verify */
+BYTE_PTR data, /* I - data to verify against */
+UINT16 *size, /*I/O- size of buffers / amount verified */
+UINT16 *blk_size, /* O - minum size of block for next call */
+STREAM_INFO_PTR s_info ) /* I - Stream information for the data to be written */
+{
+ INT16 ret_val ;
+
+ msassert( hand != NULL );
+ msassert( hand->mode == FS_VERIFY ) ;
+
+ switch (hand->dblk->blk_type) {
+
+ case FDB_ID:
+ case DDB_ID:
+ ret_val = NTFS_VerData( hand, (BYTE_PTR)buf, (BYTE_PTR)data, size, blk_size, s_info ) ;
+ break ;
+
+ case VCB_ID:
+ ret_val = FS_EOF_REACHED ;
+ break ;
+
+ default:
+ ret_val = FS_OBJECT_NOT_OPENED;
+ }
+
+ return( ret_val ) ;
+}
+
+/**/
+/**
+
+ Name: NTFS_VerData()
+
+ Description: This function verifies the data in an open file with
+ the specified data. If a difference is found then the
+ size parameter passed in specifies the location of the
+ first difference.
+
+ Modified: 09-Mar-93
+
+ Returns:
+ FS_DEVICE_ERROR
+ FS_EOF_REACHED
+ FS_GDATA_DIFFERENT
+ FS_EADATA_DIFFERENT
+ FS_SECURITY_DIFFERENT
+ SUCCESS
+
+**/
+INT16 NTFS_VerData(
+ FILE_HAND hand, /* I - file handle to verify data with */
+ BYTE_PTR buf, /* I - buffer needed to perform verify */
+ BYTE_PTR data, /* I - data to verify against */
+ UINT16 *size, /*I/O- size of buffers / amount verified */
+ UINT16 *blk_size,/* O - minum size of block for next call */
+ STREAM_INFO_PTR s_info ) /* I - Stream information for the data */
+{
+ NTFS_OBJ_HAND_PTR nt_hand = hand->obj_hand.ptr;
+ INT16 ret_val = SUCCESS;
+ UINT16 bufferSize = *size;
+ INT status;
+ DWORD sizeout;
+ BOOLEAN dummy;
+
+ *blk_size = 1;
+ *size = 0;
+
+ if ( s_info->id != STRM_INVALID )
+ {
+ if ( nt_hand->registry_file )
+ {
+ return FS_DONT_WANT_STREAM;
+ }
+
+ switch ( s_info->id )
+ {
+ case STRM_PATH_NAME : /* Don't verify these streams */
+ case STRM_FILE_NAME :
+ case STRM_NTFS_LINK :
+ case STRM_OS2_ACL :
+ case STRM_OS2_EA :
+ case STRM_CHECKSUM_DATA:
+ ret_val = FS_DONT_WANT_STREAM;
+ break;
+
+ case STRM_NT_ACL :
+ /*
+ * If we don't want to process security, let's stop now.
+ * Otherwise, we'll fall through and process normally.
+ */
+ if ( BEC_GetRestoreSecurity( hand->fsh->cfg ) == FALSE )
+ {
+ ret_val = FS_DONT_WANT_STREAM;
+ break;
+ }
+
+ default:
+ { /* Let's move to the proper stream so we can verify. */
+ if ( U64_EQ( nt_hand->curPos, nt_hand->nextStreamHeaderPos ) )
+ {
+ nt_hand->streamHeader.id = NTFS_MaynToMSoft( s_info->id );
+ nt_hand->streamHeader.size_lo = U64_Lsw( s_info->size );
+ nt_hand->streamHeader.size_hi = U64_Msw( s_info->size );
+ nt_hand->streamHeader.name_leng = 0 ;
+ nt_hand->streamHeader.attrib = (UINT32)s_info->tf_attrib << 16 |
+ s_info->fs_attrib;
+
+ nt_hand->curPos = U64_Init( 0, 0 );
+ nt_hand->nextStreamHeaderPos = U64_Init( nt_hand->streamHeader.size_lo,
+ nt_hand->streamHeader.size_hi );
+ nt_hand->altNameComplete = FALSE;
+ }
+ else
+ {
+ ret_val = FAILURE;
+ }
+
+ if ( (ret_val != SUCCESS) && (ret_val != OUT_OF_MEMORY) )
+ {
+ ret_val = ClassifyError( hand,
+ nt_hand->streamHeader.id );
+ }
+ }
+ break;
+ }
+ }
+ else
+ {
+ /* Check to see if we need to pull the alternate name from data */
+ if ( bufferSize > 0 )
+ {
+ BOOLEAN needAltName;
+
+ if ( (nt_hand->streamHeader.id == BACKUP_ALTERNATE_DATA) &&
+ (nt_hand->altNameComplete == FALSE) )
+ {
+ needAltName = TRUE;
+ }
+ else
+ {
+ needAltName = FALSE;
+ }
+
+
+ if ( needAltName || U64_EQ( nt_hand->curPos, U64_Init(0,0) ) )
+ {
+ NT_STREAM_HEADER diskHeader;
+
+ /*
+ * Check to see if we need to pull the alternate
+ * stream's name from data
+ */
+ if ( needAltName )
+ {
+ UINT16 bsize = bufferSize;
+
+ status = ExtractNameFromBuffer( nt_hand,
+ &nt_hand->streamHeader,
+ data,
+ &bsize,
+ blk_size );
+ if ( !status )
+ {
+ NTFS_DebugPrint( TEXT("Had to frag on %s"),
+ ((NTFS_DBLK_PTR)hand->dblk)->full_name_ptr->name );
+ return SUCCESS;
+ }
+ else
+ {
+ *size = bsize;
+ buf += *size;
+ data += *size;
+ bufferSize -= *size;
+ }
+
+ if ( nt_hand->altNameComplete == FALSE )
+ {
+ return SUCCESS;
+ }
+ }
+ ret_val = SeekToStream( hand,
+ &nt_hand->streamHeader,
+ &diskHeader );
+ }
+ }
+
+ if ( (ret_val == SUCCESS) && (bufferSize > 0) )
+ {
+ status = BackupRead( nt_hand->fhand,
+ buf,
+ bufferSize,
+ &sizeout,
+ FALSE,
+ TRUE,
+ &nt_hand->context );
+
+ *size += (UINT16)sizeout;
+
+ if ( status && *size > 0 )
+ {
+ UINT16 offset = (UINT16)sizeout;
+
+ ret_val = SUCCESS;
+ if ( memver( buf, data, &offset ) )
+ {
+ ret_val = ClassifyError( hand,
+ nt_hand->streamHeader.id );
+ if ( ret_val != SUCCESS )
+ {
+ /* compute proper offset for failure? */
+ }
+ }
+ nt_hand->curPos = U64_Add( nt_hand->curPos,
+ U32_To_U64( (UINT32)sizeout ),
+ &dummy );
+
+ }
+ else if ( status )
+ {
+ ret_val = FS_EOF_REACHED;
+ }
+ else
+ {
+ NTFS_DebugPrint( TEXT("NTFS_VerData: BackupRead error (data) %d")
+ TEXT(" on \"%s\""),
+ (int)GetLastError(),
+ ((NTFS_DBLK_PTR)hand->dblk)->full_name_ptr->name );
+
+ ret_val = FS_DEVICE_ERROR;
+ }
+ }
+ }
+ return ret_val;
+}
+
+
+/**/
+/**
+
+ Name: SeekToStream()
+
+ Description: Given a stream ID, seeks the object described by "hand"
+ to the given stream.
+
+ Modified: 06-Nov-92
+
+ Returns: SUCCESS Found stream
+ FS_EOF_REACHED Didn't find stream.
+ OUT_OF_MEMORY Couldn't enqueue stream IDs.
+
+ Notes: Assumes that for a given object that there will be
+ only one occurrence of a given stream type.
+
+**/
+static INT16 SeekToStream( FILE_HAND hand,
+ NT_STREAM_HEADER *inputHeader,
+ NT_STREAM_HEADER *diskHeader )
+{
+ NTFS_OBJ_HAND_PTR nt_hand = hand->obj_hand.ptr;
+ INT16 ret = SUCCESS;
+ INT16 desiredPos;
+
+ desiredPos = GetStreamPos( hand, inputHeader );
+
+ if ( nt_hand->streamsAllVisited && (desiredPos != -1) )
+ {
+ ret = FS_EOF_REACHED;
+ }
+ else
+ {
+ if ( (desiredPos != -1) && (desiredPos < nt_hand->verifyStreamPos) )
+ {
+ ret = Rewind( hand );
+ }
+
+ if ( ret == SUCCESS )
+ {
+ ret = SeekForward( hand, inputHeader, diskHeader );
+ }
+ }
+ return ret;
+}
+
+
+/**/
+/**
+
+ Name: SeekForward()
+
+ Description: Seeks forward in the object until it reaches
+ the stream specified by "streamID."
+
+ Modified: 06-Nov-92
+
+ Returns: FS_EOF_REACHED
+ OUT_OF_MEMORY
+ SUCCESS
+
+ Notes: Assumes that upon entry, if a read is performed, a
+ stream header will be returned.
+
+ Assumes that for a given object that there will be
+ only one occurrence of a given stream type.
+
+**/
+static INT16 SeekForward( FILE_HAND hand,
+ NT_STREAM_HEADER *inputHeader,
+ NT_STREAM_HEADER *diskHeader )
+{
+ NTFS_OBJ_HAND_PTR nt_hand = hand->obj_hand.ptr;
+ INT16 ret = SUCCESS;
+
+ while ( ret == SUCCESS )
+ {
+ ret = ReadStreamHeader( hand, diskHeader );
+
+ if ( ret != SUCCESS )
+ {
+ nt_hand->streamsAllVisited = TRUE;
+ }
+ else
+ {
+ DWORD wentHi;
+ DWORD wentLo;
+
+ nt_hand->verifyStreamPos++;
+
+ ret = EnqueueStreamID( hand, diskHeader );
+
+ if ( inputHeader->id == diskHeader->id )
+ {
+ LARGE_INTEGER disk_size ;
+ LARGE_INTEGER tape_size ;
+
+ disk_size.LowPart = diskHeader->size_lo ;
+ disk_size.HighPart = diskHeader->size_hi ;
+
+ tape_size.LowPart = inputHeader->size_lo ;
+ tape_size.HighPart = inputHeader->size_hi ;
+
+ //only for streams with names.
+ if ( diskHeader->name_leng ) {
+ tape_size.QuadPart -= (inputHeader->name_leng + 4) ;
+ }
+
+ if ( tape_size.QuadPart == disk_size.QuadPart )
+ {
+
+ if ( inputHeader->name_leng == diskHeader->name_leng )
+ {
+ if ( (inputHeader->name_leng == 0) ||
+ (memcmp(inputHeader->name,
+ diskHeader->name,
+ inputHeader->name_leng) == 0) )
+ {
+ break;
+ }
+ }
+ }
+ }
+ BackupSeek( nt_hand->fhand,
+ 0xffffffff, /* Seek to next stream */
+ 0xffffffff,
+ &wentHi,
+ &wentLo,
+ &nt_hand->context );
+ }
+ }
+ return ret;
+}
+
+/**/
+/**
+
+ Name: ReadStreamHeader()
+
+ Description: Reads a complete stream header using BackupRead.
+
+ Modified: 09-Mar-93
+
+ Returns: SUCCESS
+ FS_EOF_REACHED
+
+ Notes: Assumes that if a backup read is performed, a stream
+ header will be returned from BackupRead.
+
+**/
+static INT16 ReadStreamHeader( FILE_HAND hand,
+ NT_STREAM_HEADER *streamHeader )
+{
+ NTFS_OBJ_HAND_PTR nt_hand = hand->obj_hand.ptr;
+ BOOLEAN status;
+ INT16 ret = FS_EOF_REACHED;
+ DWORD sizeout;
+
+ status = BackupRead( nt_hand->fhand,
+ (BYTE_PTR)streamHeader,
+ NT_SIZEOF_NAMELESS_STREAM_HEAD,
+ (LPDWORD)&sizeout,
+ FALSE,
+ TRUE,
+ &nt_hand->context );
+
+ if ( status && (sizeout == NT_SIZEOF_NAMELESS_STREAM_HEAD) )
+ {
+ if ( streamHeader->id != BACKUP_ALTERNATE_DATA )
+ {
+ ret = SUCCESS;
+ }
+ else
+ {
+ /* Now read the stream name itself */
+ status = BackupRead( nt_hand->fhand,
+ (INT8_PTR)&streamHeader->name,
+ streamHeader->name_leng,
+ (LPDWORD)&sizeout,
+ FALSE,
+ TRUE,
+ &nt_hand->context );
+
+ if ( status && (sizeout == streamHeader->name_leng) )
+ {
+ /* Everything went OK */
+ ret = SUCCESS;
+ }
+ }
+ }
+
+ if ( !status )
+ {
+ DWORD error = GetLastError();
+
+ if ( (error != ERROR_HANDLE_EOF) &&
+ (error != ERROR_INVALID_PARAMETER) )
+ {
+ NTFS_DebugPrint( TEXT("NTFS_ReadStreamHeader: BackupRead error (stream header) %d")
+ TEXT(" on \"%s\""),
+ (int)error,
+ ((NTFS_DBLK_PTR)hand->dblk)->full_name_ptr->name );
+ }
+
+ }
+ return ret;
+}
+
+/**/
+/**
+
+ Name: Rewind()
+
+ Description: Seeks the object back to the beginning.
+
+ Modified: 06-Nov-92
+
+ Returns: SUCCESS
+ FS_EOF_REACHED (if object can't be rewound)
+
+ Notes:
+
+**/
+static INT16 Rewind( FILE_HAND hand )
+{
+ NTFS_OBJ_HAND_PTR nt_hand = hand->obj_hand.ptr;
+ DWORD sizeout;
+ BOOLEAN status;
+
+ status = BackupRead( nt_hand->fhand,
+ NULL,
+ 0,
+ (LPDWORD)&sizeout,
+ TRUE,
+ FALSE,
+ &nt_hand->context );
+
+ nt_hand->context = NULL;
+
+ return status ? SUCCESS : FS_EOF_REACHED;
+}
+
+
+/**/
+/**
+
+ Name: EnqueueStreamID()
+
+ Description: Enqueues on the hand a stream ID. Later, verify can
+ search for a stream ID to determine if it has been
+ visited, and if so, what is its relative position.
+
+ Modified: 06-Nov-92
+
+ Returns: SUCCESS
+ OUT_OF_MEMORY
+
+ Notes: Assumes that for a given object that there will be
+ only one occurrence of a given stream type.
+
+**/
+static INT16 EnqueueStreamID( FILE_HAND hand,
+ NT_STREAM_HEADER *streamHeader )
+{
+ NTFS_FSYS_RESERVED_PTR resInfo = hand->fsh->reserved.ptr;
+ INT16 ret = SUCCESS;
+
+ if ( GetStreamPos( hand, streamHeader ) == -1 ) /* Is stream enqueued? */
+ {
+ if ( resInfo->streamIDCount >= resInfo->streamIDBufferSize )
+ {
+ resInfo->streamIDBufferSize += 8;
+ resInfo->streamIDs = realloc( resInfo->streamIDs,
+ resInfo->streamIDBufferSize *
+ sizeof( NTFS_STREAM_ID ) );
+
+ if ( resInfo->streamIDs == NULL )
+ {
+ resInfo->streamIDBufferSize = 0;
+ ret = OUT_OF_MEMORY;
+ }
+ }
+ if ( ret == SUCCESS )
+ {
+ NTFS_STREAM_ID *streamIdentifier;
+
+ streamIdentifier = resInfo->streamIDs + resInfo->streamIDCount;
+
+ streamIdentifier->streamID = streamHeader->id;
+ streamIdentifier->nameLength = streamHeader->name_leng;
+ memcpy( streamIdentifier->name,
+ streamHeader->name,
+ streamHeader->name_leng );
+
+ resInfo->streamIDCount++;
+ }
+ }
+ return ret;
+}
+
+/**/
+/**
+
+ Name: GetStreamPos()
+
+ Description: Determines relative position in the object of a
+ given stream.
+
+ Modified: 09-Nov-92
+
+ Returns: Position within the object, or -1 if not found.
+
+**/
+static INT16 GetStreamPos( FILE_HAND hand,
+ NT_STREAM_HEADER *streamHeader )
+{
+ NTFS_FSYS_RESERVED_PTR resInfo = hand->fsh->reserved.ptr;
+ NTFS_STREAM_ID *streams;
+ INT16 ret = -1;
+ INT16 i;
+
+ /* Return relative position [0 - (n-1)] of stream */
+
+ for ( streams = resInfo->streamIDs, i = 0;
+ (i < resInfo->streamIDCount);
+ i++, streams++ )
+ {
+ if ( streams->streamID == streamHeader->id )
+ {
+ if ( streams->nameLength == streamHeader->name_leng )
+ {
+ if ( (streams->nameLength == 0) ||
+ (memcmp(streams->name,
+ streamHeader->name,
+ streams->nameLength) == 0) )
+ {
+ ret = i;
+ break;
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+/**/
+/**
+
+ Name: ExtractNameFromBuffer()
+
+ Description: Extracts a stream size & name from buffer.
+
+ Modified: 09-Mar-93
+
+ Returns: TRUE if success,
+ FALSE if failure
+
+ Notes: Upon failure, *blk_size will contain the size needed
+ to successfully extract the name.
+
+ Upon success, *size will contain the number of bytes
+ extracted from the stream.
+
+**/
+static BOOLEAN ExtractNameFromBuffer( NTFS_OBJ_HAND_PTR nt_hand,
+ NT_STREAM_HEADER_PTR streamHeader,
+ BYTE_PTR data,
+ UINT16 *size,
+ UINT16 *blk_size )
+{
+ BOOLEAN status = TRUE;
+ BOOLEAN gotDataThisPass = FALSE;
+ UINT16 bufferSize = *size;
+ BOOLEAN dummy;
+
+ *size = 0;
+ *blk_size = 1;
+
+ /*
+ * Determine what we are supposed to read. This is either
+ * 1) the size of the name of alternate data stream
+ * 2) the name stream itself
+ *
+ * We can determine which we are supposed to read based on
+ * our current position.
+ * If it is zero, we have to get the size name.
+ * If it is non-zero, we can assume we got the name earlier.
+ *
+ * If we could read either one, we return success.
+ * If we lacked room for one, we return false and set blk_size.
+ *
+ * Once we have the name filled out in the stream header in its
+ * entirety, we set nt_hand->altNameComplete to TRUE;
+ */
+
+ if ( U64_EQ( nt_hand->curPos, U64_Init(0,0) ) )
+ {
+ UINT16 nameLenSize; /* Size of stream header name length field */
+
+ nameLenSize = sizeof( streamHeader->name_leng );
+
+ if ( bufferSize >= nameLenSize )
+ {
+ memcpy( &streamHeader->name_leng, data, nameLenSize );
+
+ nt_hand->curPos = U64_Add( nt_hand->curPos,
+ U32_To_U64( (UINT32)nameLenSize ),
+ &dummy );
+ data += nameLenSize;
+ bufferSize -= nameLenSize;
+ *size += nameLenSize;
+ gotDataThisPass = TRUE;
+ }
+ else
+ {
+ *blk_size = nameLenSize;
+ status = FALSE;
+ }
+ }
+
+ if ( (status == TRUE) && !U64_EQ( nt_hand->curPos, U64_Init(0,0) ) )
+ {
+ if ( bufferSize >= streamHeader->name_leng )
+ {
+ memcpy( &streamHeader->name,
+ data,
+ streamHeader->name_leng );
+
+ nt_hand->curPos = U64_Add( nt_hand->curPos,
+ U32_To_U64(streamHeader->name_leng),
+ &dummy );
+
+ data += streamHeader->name_leng;
+ bufferSize -= (UINT16)streamHeader->name_leng;
+ *size += (UINT16)streamHeader->name_leng;
+
+ gotDataThisPass = TRUE;
+ nt_hand->altNameComplete = TRUE;
+ }
+ else
+ {
+ if ( gotDataThisPass == FALSE )
+ {
+ *blk_size = (UINT16)streamHeader->name_leng;
+ status = FALSE;
+ }
+ }
+ }
+ return status;
+}
+
+
+/**/
+/**
+
+ Name: ClassifyError()
+
+ Description: Returns the proper file system error code upon
+ a verify error (based on stream type).
+
+ Modified: 09-Nov-92
+
+ Returns: FS error code
+
+**/
+static INT16 ClassifyError( FILE_HAND hand, UINT32 streamID )
+{
+ INT16 ret;
+
+ switch ( streamID )
+ {
+ case BACKUP_DATA :
+ ret = FS_GDATA_DIFFERENT;
+ break;
+
+ case BACKUP_EA_DATA :
+ ret = FS_EADATA_DIFFERENT;
+ break;
+
+ case BACKUP_SECURITY_DATA :
+ ret = FS_SECURITY_DIFFERENT;
+ break;
+
+ case BACKUP_ALTERNATE_DATA :
+ if ( strcmp( TEXT("NTFS"), hand->fsh->attached_dle->info.ntfs->fs_name ) == 0 )
+ {
+ NTFS_OBJ_HAND_PTR nt_hand = hand->obj_hand.ptr;
+
+ if ( (nt_hand->streamHeader.name_leng != 0) &&
+ (wcscmp( L":AFP_AfpInfo:$DATA",
+ (WCHAR *)nt_hand->streamHeader.name ) == 0) )
+ {
+ /*
+ * It's just Finder info -- ignore the error
+ */
+ ret = SUCCESS;
+ }
+ else
+ {
+ ret = FS_GDATA_DIFFERENT;
+ }
+ }
+ else
+ {
+ ret = SUCCESS;
+ }
+ break;
+
+ default:
+ ret = FAILURE; /* CBN -- ??? */
+ break;
+ }
+ return ret;
+}
+
+
diff --git a/private/utils/ntbackup/src/twritobj.c b/private/utils/ntbackup/src/twritobj.c
new file mode 100644
index 000000000..be28f0da8
--- /dev/null
+++ b/private/utils/ntbackup/src/twritobj.c
@@ -0,0 +1,676 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: twritobj.c
+
+ Description: This function writes data to an open object.
+
+
+ $Log: M:/LOGFILES/TWRITOBJ.C_V $
+
+ Rev 1.30.1.0 03 Mar 1994 10:39:36 BARRY
+Defend against buffers zero bytes in length
+
+ Rev 1.30 28 Jan 1994 10:34:24 GREGG
+More Warning Fixes
+
+ Rev 1.29 23 Jan 1994 14:01:22 BARRY
+Added debug code
+
+ Rev 1.28 24 Nov 1993 14:59:02 BARRY
+Changed CHAR_PTRs in I/O functions to BYTE_PTRs
+
+ Rev 1.27 14 Oct 1993 17:49:58 STEVEN
+fix unicode bugs
+
+ Rev 1.26 08 Jul 1993 12:18:38 BARRY
+Don't send CRC streams to the BackupWrite
+
+ Rev 1.25 02 Jun 1993 14:17:28 STEVEN
+fix alignment fault
+
+ Rev 1.24 13 May 1993 20:32:34 BARRY
+Checked in Steve's changes for restoration of OS/2 EAs.
+
+ Rev 1.23 24 Feb 1993 15:37:22 BARRY
+Fixed restore of active files when write errors occur.
+
+ Rev 1.22 17 Feb 1993 14:59:16 STEVEN
+fix bug with security after alt data
+
+ Rev 1.21 11 Feb 1993 14:47:04 STEVEN
+fix restore of mult alt data streams
+
+ Rev 1.20 08 Feb 1993 11:49:48 BARRY
+Discard NACL streams if restoreSecurity in config is FALSE.
+
+ Rev 1.19 27 Jan 1993 13:51:26 STEVEN
+updates from msoft
+
+ Rev 1.18 15 Jan 1993 13:19:00 BARRY
+added support for new error messages and backup priviladge
+
+ Rev 1.17 07 Dec 1992 14:16:40 STEVEN
+updates from msoft
+
+ Rev 1.16 24 Nov 1992 11:02:08 BARRY
+Changes to make LINK streams null-impregnated.
+
+ Rev 1.15 11 Nov 1992 10:54:22 GREGG
+Unicodeized literals.
+
+ Rev 1.14 29 Oct 1992 16:46:44 BARRY
+Restore links.
+
+ Rev 1.13 21 Oct 1992 19:44:30 BARRY
+Got rid of warnings.
+
+ Rev 1.12 16 Oct 1992 16:48:16 STEVEN
+fix streams to UINT64
+
+ Rev 1.11 14 Oct 1992 14:37:46 BARRY
+Fixes for alternate data streams.
+
+ Rev 1.10 09 Oct 1992 14:31:28 BARRY
+Path-in-stream changes.
+
+ Rev 1.8 06 Oct 1992 11:12:34 BARRY
+BackupRead stream size corrections; bug fixes in stream header redesign.
+
+ Rev 1.7 18 Sep 1992 15:37:50 BARRY
+Changes for Stream Header redesign.
+
+ Rev 1.6 02 Sep 1992 07:48:36 STEVEN
+fix typo
+
+ Rev 1.5 01 Sep 1992 16:11:02 STEVEN
+added stream headers to fsys API
+
+ Rev 1.4 17 Aug 1992 15:36:54 STEVEN
+fix warnings
+
+ Rev 1.3 12 Aug 1992 17:47:30 STEVEN
+fixed bugs at microsoft
+
+ Rev 1.2 22 May 1992 16:05:12 STEVEN
+
+
+ Rev 1.1 21 May 1992 13:50:50 STEVEN
+more long path stuff
+
+ Rev 1.0 12 Feb 1992 13:04:50 STEVEN
+Initial revision.
+
+**/
+#include <windows.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "stdmath.h"
+#include "msassert.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "fsys_err.h"
+#include "ntfsdblk.h"
+#include "ntfs_fs.h"
+
+static INT16 NTFS_WriteData(
+ FILE_HAND hand,
+ BYTE_PTR buf,
+ UINT16 *size,
+ UINT16 *blk_size,
+ STREAM_INFO_PTR s_info );
+
+static INT16 CollectLinkName( FILE_HAND hand,
+ BYTE_PTR buff,
+ UINT16 *size,
+ STREAM_INFO *s_info );
+
+static UINT16 CalcWriteSize( UINT64 startPos,
+ UINT64 endPos,
+ UINT16 buffSize );
+
+/**/
+/**
+
+ Name: NTFS_WriteObj()
+
+ Description: This function writes data to an opened object on
+ disk.
+
+ Modified: 2/12/1992 12:57:2
+
+ Returns: Error Codes:
+ FS_DEVICE_ERROR
+ FS_OBJECT_NOT_OPENED
+ FS_OUT_OF_SPACE
+ SUCCESS
+
+ Notes:
+
+**/
+INT16 NTFS_WriteObj(
+ FILE_HAND hand, /* I - handle of object to read from */
+ BYTE_PTR buf, /* O - buffer to place data into */
+ UINT16 *size, /*I/O- Entry: size of buf; Exit: number of bytes read */
+ UINT16 *blk_size, /* O - Block size need for next read */
+ STREAM_INFO_PTR s_info ) /* I - Stream information for the data to be written */
+{
+ INT16 ret_val;
+
+ msassert( hand->mode == FS_WRITE );
+
+ if ( (s_info->id == STRM_INVALID) && (*size == 0) )
+ {
+ /*
+ * Someone asked us to write zero bytes. According to
+ * our rules this is not allowed, but we'll be defensive
+ * anyway.
+ */
+ msassert( FALSE );
+ *blk_size = 1;
+ ret_val = SUCCESS;
+ }
+ else
+ {
+ switch (hand->dblk->blk_type)
+ {
+ case FDB_ID:
+ {
+ NTFS_DBLK_PTR fdb = (NTFS_DBLK_PTR)hand->dblk;
+
+ if ( fdb->b.f.linkOnly ) {
+ *blk_size = 1;
+ ret_val = CollectLinkName( hand, buf, size, s_info );
+ } else {
+ ret_val = NTFS_WriteData( hand, buf, size, blk_size, s_info ) ;
+ }
+ break;
+ }
+
+ case DDB_ID:
+ ret_val = NTFS_WriteData( hand, buf, size, blk_size, s_info ) ;
+ break ;
+
+ case VCB_ID:
+ ret_val = FS_EOF_REACHED ;
+ break ;
+
+ default:
+ ret_val = FS_OBJECT_NOT_OPENED;
+ }
+ }
+ return ret_val;
+}
+
+/**/
+/**
+
+ Name: NTFS_WriteData()
+
+ Description: This function writes data to an open NTFS object.
+
+ Modified: 10-Sep-92
+
+ Returns: FS_OUT_OF_SPACE
+ SUCCESS
+
+ Notes:
+
+**/
+static INT16 NTFS_WriteData(
+ FILE_HAND hand, /* I - handle of object to read from */
+ BYTE_PTR buf, /* I - buffer to write */
+ UINT16 *size, /*I/O- Entry: size of buf; Exit: bytes written */
+ UINT16 *blk_size, /* O - Block size need for next write */
+ STREAM_INFO_PTR s_info ) /* I - Stream information for the data */
+{
+ NT_STREAM_NAME UNALIGNED *namePtr = (NT_STREAM_NAME UNALIGNED *)buf;
+ NTFS_OBJ_HAND_PTR nt_hand ;
+ INT16 ret_val = SUCCESS ;
+ UINT16 bufferSize;
+ DWORD sizeout;
+ INT status;
+ UINT16 writeSize; /* Size sent to BackupWrite */
+ NT_STREAM_HEADER streamHeader; /* Composed from s_info */
+ BOOLEAN dummy;
+
+ nt_hand = (NTFS_OBJ_HAND_PTR)(hand->obj_hand.ptr ) ;
+ bufferSize = *size;
+ *size = 0;
+ *blk_size = 1;
+
+ if ( s_info->id != STRM_INVALID )
+ {
+ UINT16 buffUsed = 0; /* Amount of buf we wrote (name) */
+
+ writeSize = NT_SIZEOF_NAMELESS_STREAM_HEAD;
+
+ streamHeader.id = NTFS_MaynToMSoft( s_info->id );
+
+ streamHeader.attrib = (s_info->tf_attrib << 16) |
+ s_info->fs_attrib;
+
+ streamHeader.size_lo = FS_GetStrmSizeLo( s_info ) ;
+ streamHeader.size_hi = FS_GetStrmSizeHi( s_info ) ;
+ streamHeader.name_leng = 0;
+
+ if ( s_info->id == STRM_NT_ACL )
+ {
+ if ( BEC_GetRestoreSecurity( hand->fsh->cfg ) == FALSE )
+ {
+ return FS_DONT_WANT_STREAM;
+ }
+ }
+ else if ( s_info->id == STRM_OS2_ACL )
+ {
+ return FS_DONT_WANT_STREAM;
+ }
+ else if ( s_info->id == STRM_CHECKSUM_DATA )
+ {
+ return FS_DONT_WANT_STREAM;
+ }
+ else if ( s_info->id == STRM_OS2_EA )
+ {
+ if ( nt_hand->os2_ea_buffer == NULL ) {
+ nt_hand->os2_ea_buffer = malloc( 0xfff0 ) ;
+ }
+ if ( nt_hand->os2_ea_buffer == NULL ) {
+ return FS_DONT_WANT_STREAM;
+ }
+ streamHeader.id = BACKUP_EA_DATA ;
+ nt_hand->processing_os2_ea = TRUE ;
+ nt_hand->curPos = U64_Init( 0, 0 );
+ nt_hand->streamHeader = streamHeader ;
+
+ return SUCCESS ;
+ }
+ else if ( s_info->id == STRM_NTFS_ALT_DATA )
+ {
+
+ if ( strcmp( hand->fsh->attached_dle->info.ntfs->fs_name, TEXT("NTFS") ) ) {
+ UINT32 seeked_low ;
+ UINT32 seeked_hi ;
+
+ BackupSeek( nt_hand->fhand,
+ 0xFFFFFFFF, 0xFFFFFFFF,
+ &seeked_low, &seeked_hi,
+ &nt_hand->context ) ;
+
+
+ return FS_DONT_WANT_STREAM ;
+ }
+
+
+ nt_hand->curPos = U64_Init( 0, 0 );
+ nt_hand->streamHeader = streamHeader ;
+ nt_hand->nextStreamHeaderPos = U64_Init( streamHeader.size_lo,
+ streamHeader.size_hi );
+ return SUCCESS ;
+ }
+
+ status = BackupWrite( nt_hand->fhand,
+ (LPBYTE)&streamHeader,
+ writeSize,
+ (LPDWORD)&sizeout,
+ FALSE,
+ BEC_GetRestoreSecurity( hand->fsh->cfg ),
+ &nt_hand->context );
+
+ nt_hand->streamHeader = streamHeader ;
+
+ if ( status && (sizeout == writeSize) )
+ {
+ nt_hand->curPos = U64_Init( 0, 0 );
+ nt_hand->nextStreamHeaderPos = U64_Init( streamHeader.size_lo,
+ streamHeader.size_hi );
+ }
+ else
+ {
+ if ( !status )
+ {
+ NTFS_DebugPrint( TEXT("NTFS_WriteData: BackupWrite error (stream header) %d")
+ TEXT(" on \"%s\""),
+ (int)GetLastError(),
+ ((NTFS_DBLK_PTR)hand->dblk)->full_name_ptr->name );
+
+ ret_val = NTFS_TranslateBackupError( GetLastError( ) );
+ }
+ else
+ {
+ /* CBN -- is this right */
+ if ( sizeout != writeSize )
+ {
+ ret_val = FS_DONT_WANT_STREAM;
+ }
+ else
+ {
+ ret_val = SUCCESS;
+ }
+ }
+ }
+
+ }
+ else
+ {
+ if ( nt_hand->processing_os2_ea ) {
+
+ *size = bufferSize ;
+
+ ret_val = SUCCESS ;
+
+ streamHeader = nt_hand->streamHeader ;
+
+ memcpy( nt_hand->os2_ea_buffer + U64_Lsw( nt_hand->curPos ),
+ buf, *size ) ;
+
+ nt_hand->curPos = U64_Add( nt_hand->curPos,
+ U32_To_U64( (UINT32)*size ),
+ &dummy );
+
+ if ( U64_Lsw(nt_hand->curPos) == streamHeader.size_lo ) {
+ int index ;
+ int delta ;
+ int stream_size ;
+ struct FEA_STR {
+ UINT32 next_ea ;
+ BYTE fea ;
+ BYTE name_size ;
+ UINT16 value_size ;
+ } *fea_data ;
+
+
+ stream_size = nt_hand->streamHeader.size_lo ;
+ fea_data = NULL ;
+
+ for ( index = 0 ; index < stream_size ; ) {
+
+ delta = 0 ;
+
+ if ( index % sizeof( UINT32 ) ) {
+ delta = sizeof(UINT32 ) - (index % sizeof(UINT32) ) ;
+ fea_data->next_ea += delta ;
+ }
+ if ( index != 0 ) {
+ delta += sizeof(UINT32) ;
+ }
+
+ if ( delta ) {
+ stream_size += delta ;
+ memmove( nt_hand->os2_ea_buffer+index+delta,
+ nt_hand->os2_ea_buffer+index,
+ stream_size - index ) ;
+
+ if ( index != 0 ) {
+ index += delta - sizeof(UINT32) ;
+ } else {
+ index += delta ;
+ }
+
+ }
+
+ fea_data = (struct FEA_STR *)(&nt_hand->os2_ea_buffer[index]) ;
+
+ index += fea_data->value_size + (fea_data->name_size+1) + sizeof(struct FEA_STR ) ;
+
+ fea_data->next_ea = fea_data->value_size + (fea_data->name_size+1) + sizeof(struct FEA_STR ) ;
+
+ }
+
+ fea_data->next_ea = 0 ;
+
+ streamHeader.size_lo = stream_size ;
+ streamHeader.size_hi = 0 ;
+ writeSize = NT_SIZEOF_NAMELESS_STREAM_HEAD;
+
+ status = BackupWrite( nt_hand->fhand,
+ (LPBYTE)&streamHeader,
+ writeSize,
+ (LPDWORD)&sizeout,
+ FALSE,
+ BEC_GetRestoreSecurity( hand->fsh->cfg ),
+ &nt_hand->context );
+
+ if ( status ) {
+ status = BackupWrite( nt_hand->fhand,
+ (LPBYTE)nt_hand->os2_ea_buffer,
+ stream_size,
+ (LPDWORD)&sizeout,
+ FALSE,
+ BEC_GetRestoreSecurity( hand->fsh->cfg ),
+ &nt_hand->context );
+ }
+
+ free( nt_hand->os2_ea_buffer ) ;
+ nt_hand->os2_ea_buffer = NULL ;
+ nt_hand->processing_os2_ea = FALSE ;
+
+ if ( !status ) {
+ ret_val = FS_DEVICE_ERROR ;
+ }
+
+ }
+
+ return ret_val ;
+ }
+
+ if ( ( nt_hand->streamHeader.id == BACKUP_ALTERNATE_DATA ) &&
+ U64_EQ( nt_hand->curPos, U64_Init( 0, 0 ) ) )
+ {
+ UINT16 nameSize;
+
+ writeSize = NT_SIZEOF_NAMELESS_STREAM_HEAD;
+ nameSize = sizeof( namePtr->name_leng );
+
+ if ( bufferSize < nameSize )
+ {
+ *blk_size = nameSize;
+ *size = 0 ;
+ return SUCCESS;
+ }
+ else
+ {
+ UINT64 u64StreamSize ;
+ UINT64 u64_namesize ;
+
+ streamHeader = nt_hand->streamHeader ;
+
+ u64StreamSize = U64_Init( streamHeader.size_lo,
+ streamHeader.size_hi ) ;
+
+ u64_namesize = U64_Init( namePtr->name_leng + nameSize, 0 ) ;
+
+ u64StreamSize = U64_Sub( u64StreamSize, u64_namesize, &dummy ) ;
+
+ streamHeader.size_lo = U64_Lsw( u64StreamSize ) ;
+ streamHeader.size_hi = U64_Msw( u64StreamSize ) ;
+
+ streamHeader.name_leng = namePtr->name_leng ;
+
+ status = BackupWrite( nt_hand->fhand,
+ (LPBYTE)&streamHeader,
+ writeSize,
+ (LPDWORD)&sizeout,
+ FALSE,
+ BEC_GetRestoreSecurity( hand->fsh->cfg ),
+ &nt_hand->context );
+
+ if ( status )
+ {
+ *size += nameSize ;
+ buf += nameSize ;
+ bufferSize -= nameSize ;
+ }
+ else
+ {
+ ret_val = FS_DONT_WANT_STREAM;
+ }
+ }
+ }
+ }
+
+ if ( (ret_val == SUCCESS) && (s_info->id == STRM_INVALID) )
+ {
+ BOOLEAN dummy;
+
+ bufferSize = CalcWriteSize( nt_hand->curPos,
+ nt_hand->nextStreamHeaderPos,
+ bufferSize );
+
+ status = BackupWrite( nt_hand->fhand,
+ buf,
+ bufferSize,
+ (LPDWORD)&sizeout,
+ FALSE,
+ BEC_GetRestoreSecurity( hand->fsh->cfg ),
+ &nt_hand->context ) ;
+
+ if ( !status )
+ {
+ DWORD error = GetLastError();
+
+ nt_hand-> writeError = TRUE;
+ ret_val = NTFS_TranslateBackupError( error );
+
+ NTFS_DebugPrint( TEXT("NTFS_WriteData: BackupWrite error (data) %d")
+ TEXT(" on \"%s\""),
+ (int)error,
+ ((NTFS_DBLK_PTR)hand->dblk)->full_name_ptr->name );
+ }
+ else
+ {
+ ret_val = SUCCESS;
+ }
+
+ *size += (UINT16)sizeout;
+ nt_hand->curPos = U64_Add( nt_hand->curPos,
+ U32_To_U64( (UINT32)*size ),
+ &dummy );
+ }
+ return ret_val;
+}
+
+
+/**/
+/**
+
+ Name: CollectLinkName()
+
+ Description: Pulls a full path for a linked file from the stream
+ and saves it. All other streams are simply discarded.
+
+ Modified: 28-Oct-92
+
+ Returns: SUCCESS
+ FS_DONT_WANT_STREAM
+ OUT_OF_MEMORY
+
+ Notes:
+
+**/
+static INT16 CollectLinkName( FILE_HAND hand,
+ BYTE_PTR buff,
+ UINT16 *size,
+ STREAM_INFO *s_info )
+{
+ NTFS_OBJ_HAND_PTR nt_hand = hand->obj_hand.ptr;
+ INT16 ret = SUCCESS;
+
+ if ( s_info->id != STRM_INVALID )
+ {
+ if ( s_info->id == STRM_NTFS_LINK )
+ {
+ size_t buffSizeNeeded;
+
+ nt_hand->curPos = U64_Init( 0, 0 );
+ nt_hand->nextStreamHeaderPos = s_info->size;
+
+ /* Make sure everything's kosher with the sizes */
+ msassert( U64_Msw( s_info->size ) == 0 );
+ msassert( U64_Lsw( s_info->size ) < 65536 );
+
+ buffSizeNeeded = (size_t)U64_Lsw( s_info->size );
+ buffSizeNeeded += strsize( DLE_GetDeviceName( hand->fsh->attached_dle ) );
+ buffSizeNeeded += sizeof( CHAR ) * 10; /* path separator(s) */
+
+ if ( nt_hand->linkBufferSize < buffSizeNeeded )
+ {
+ nt_hand->linkBufferSize = buffSizeNeeded;
+ nt_hand->linkBuffer = realloc( nt_hand->linkBuffer,
+ buffSizeNeeded );
+
+ }
+
+ if ( nt_hand->linkBuffer != NULL )
+ {
+ strcpy( nt_hand->linkBuffer,
+ DLE_GetDeviceName( hand->fsh->attached_dle ) );
+ strcat( nt_hand->linkBuffer, TEXT("\\") );
+
+ nt_hand->linkNameLen = strlen( nt_hand->linkBuffer ) * sizeof( CHAR );
+ nt_hand->curPos = U64_Init( nt_hand->linkNameLen, 0 );
+ nt_hand->linkNameLen += (UINT16)U64_Lsw( s_info->size );
+ }
+ else
+ {
+ nt_hand->linkBufferSize = 0;
+ ret = OUT_OF_MEMORY;
+ }
+ }
+ else
+ {
+ ret = FS_DONT_WANT_STREAM;
+ }
+ *size = 0;
+ }
+ else
+ {
+ if ( *size > 0 )
+ {
+ BOOLEAN dummy;
+
+ memcpy( nt_hand->linkBuffer + U64_Lsw( nt_hand->curPos)/sizeof(CHAR),
+ buff,
+ (size_t)*size );
+
+ nt_hand->curPos = U64_Add( nt_hand->curPos,
+ U32_To_U64( (UINT32)*size ),
+ &dummy );
+ msassert( dummy == TRUE );
+ }
+ }
+ return ret;
+}
+
+
+static UINT16 CalcWriteSize( UINT64 startPos,
+ UINT64 endPos,
+ UINT16 buffSize )
+{
+ UINT16 writeSize;
+ BOOLEAN mathStat;
+
+ if ( U64_GT( U64_Add( startPos,
+ U32_To_U64( (UINT32)buffSize ),
+ &mathStat ),
+ endPos ) )
+ {
+ UINT64 rs;
+
+ rs = U64_Sub( endPos,
+ startPos,
+ &mathStat );
+
+ msassert( mathStat && (U64_Msw( rs ) == 0) && (U64_Lsw(rs) < 65536) );
+
+ writeSize = (UINT16)U64_Lsw( rs );
+ } else {
+ writeSize = buffSize;
+ }
+
+ return writeSize;
+}
diff --git a/private/utils/ntbackup/src/uadd_dle.c b/private/utils/ntbackup/src/uadd_dle.c
new file mode 100644
index 000000000..0d6d270b2
--- /dev/null
+++ b/private/utils/ntbackup/src/uadd_dle.c
@@ -0,0 +1,119 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: uadd_dle.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This file contains code to add a HAND_MADE dle to the drive list.
+
+
+ $Log: O:/LOGFILES/UADD_DLE.C_V $
+
+ Rev 1.7 04 Feb 1993 14:56:36 TIMN
+Added Unicode header to resolve link errors
+
+ Rev 1.6 11 Nov 1992 22:26:58 GREGG
+Unicodeized literals.
+
+ Rev 1.5 06 Oct 1992 13:24:28 DAVEV
+Unicode strlen verification
+
+ Rev 1.4 18 Aug 1992 10:24:14 STEVEN
+fix warnings
+
+ Rev 1.3 13 Jan 1992 18:46:24 STEVEN
+changes for WIN32 compile
+
+ Rev 1.2 01 Oct 1991 11:17:54 BARRY
+Include standard headers.
+
+ Rev 1.1 25 Jun 1991 09:35:02 BARRY
+Changes for new config.
+
+ Rev 1.0 09 May 1991 13:38:52 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "stdwcs.h"
+
+#include "fsys.h"
+#include "fsys_prv.h"
+/* $end$ include list */
+
+/**/
+/**
+
+ Name FS_AddTempDLE()
+
+ Description: This function creates a DLE with the data specified
+ and adds this DLE to the DLE list.
+
+ Modified: 7/12/1989
+
+ Returns: Error codes
+ SUCCESS
+ FAILURE
+
+ Notes:
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 FS_AddTempDLE(
+DLE_HAND hand, /* I - Handle to DLE list */
+CHAR_PTR name, /* I - device name */
+CHAR_PTR vol_name, /* I - volume name */
+INT16 type ) /* I - type of DLE */
+{
+ INT16 cb_dle_size ; //size of dle buffer in bytes
+ GENERIC_DLE_PTR dle ;
+
+ type |= HAND_MADE_MASK ;
+
+ /* Allocate space for DLE and device_name string */
+
+ cb_dle_size = sizeof( GENERIC_DLE ) ;
+ cb_dle_size += strsize( name ) ;
+ cb_dle_size += strsize( vol_name ) ;
+
+ dle = calloc ( 1, cb_dle_size ) ;
+
+ if ( dle != NULL ) {
+
+ /* Since memory was allocated with calloc, it is already */
+ /* initialized to zero. Therefore initializations to zero */
+ /* are not necessary. */
+
+ InitQElem( &((dle)->q) ) ;
+ (dle)->handle = hand ;
+ /* (dle)->parent = NULL ; */
+ (dle)->type = (INT8)type ;
+ (dle)->path_delim = TEXT('\\') ;
+ /* (dle)->pswd_required = FALSE */
+ /* (dle)->pswd_saved = FALSE ; */
+ /* (dle)->dle_writeable = FALSE ; */
+ /* (dle)->attach_count = 0 ; */
+ /* (dle)->bsd_use_count = 0 ; */
+ /* (dle)->dynamic_info = FALSE ; */
+ (dle)->device_name = (CHAR *) (dle) + sizeof ( GENERIC_DLE );
+ strcpy( (dle)->device_name, name ) ;
+
+ (dle)->info.user = (HAND_MADE_DLE_INFO_PTR)((dle)->device_name + strlen(name) + 1 ) ;
+ strcpy( (dle)->info.user->vol_name, vol_name ) ;
+
+ EnQueueElem( &(hand->q_hdr), &((dle)->q), FALSE ) ;
+
+ return( SUCCESS ) ;
+ } else {
+ return( FAILURE ) ;
+ }
+}
diff --git a/private/utils/ntbackup/src/unicode.c b/private/utils/ntbackup/src/unicode.c
new file mode 100644
index 000000000..12a5b7e95
--- /dev/null
+++ b/private/utils/ntbackup/src/unicode.c
@@ -0,0 +1,892 @@
+/**
+
+ Name: unicode.c
+
+ Description: Wide character versions of standard C library functions.
+
+
+ $Log: M:/LOGFILES/UNICODE.C_V $
+
+ Rev 1.3 16 Dec 1993 10:20:20 BARRY
+Replaced asserts with msasserts -- return errors on same conditions
+
+ Rev 1.2 24 Nov 1993 13:03:58 BARRY
+Undefine OpenFile in OpenFileW to prevent infinite recursion
+
+ Rev 1.1 22 Nov 1993 11:22:04 BARRY
+Free path buffer allocated in OpenFile
+
+ Rev 1.0 08 Nov 1993 18:50:52 GREGG
+Initial revision.
+
+**/
+
+#ifdef UNICODE
+
+#include <wchar.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <malloc.h>
+#include <io.h>
+#include <direct.h>
+#include <share.h>
+#include <ctype.h>
+#include <windows.h>
+#include <sys\types.h>
+#include <sys\stat.h>
+#include <stdarg.h>
+
+
+#define INCL_MS_INTERNALS //include defines from MS internal headers...
+
+#include <unic_io.h> //fcn prototypes for unicode-supporting io functions.
+
+#include "msassert.h"
+
+
+long _CRTAPI1 atolW(
+ const wchar_t *nptr
+ )
+{
+ wchar_t c; /* current char */
+ long total; /* current total */
+ wchar_t sign; /* if '-', then negative, otherwise positive */
+
+ /* skip whitespace */
+ while (iswspace(*nptr))
+ ++nptr;
+
+ c = *nptr++;
+ sign = c; /* save sign indication */
+ if (c == L'-' || c == L'+')
+ c = *nptr++; /* skip sign */
+
+ total = 0;
+
+ while (iswdigit(c)) {
+ total = 10 * total + (c - '0'); /* accumulate digit */
+ c = *nptr++; /* get next char */
+ }
+
+ if (sign == L'-')
+ return -total;
+ else
+ return total; /* return result, negated if necessary */
+}
+
+
+int _CRTAPI1 atoiW(
+ const wchar_t *nptr
+ )
+{
+ return (int)atolW(nptr);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+
+
+
+
+
+////////////////////////////////////////////////////////////////
+
+
+static wchar_t _inc ( FILE *fileptr );
+
+wchar_t * _CRTAPI1 fgetsW (
+ wchar_t *string,
+ int count,
+ FILE *str
+ )
+{
+ FILE *stream;
+ wchar_t *pointer = string;
+ wchar_t *retval = string;
+ wchar_t ch;
+
+ msassert(string != NULL);
+ msassert(str != NULL);
+
+ if ( string == NULL || str == NULL )
+ {
+ return NULL;
+ }
+
+ if (count <= 0)
+ return(NULL);
+
+ /* Init stream pointer */
+ stream = str;
+
+ _lock_str(index);
+
+ while (--count)
+ {
+ if ((ch = _inc(stream)) == WEOF)
+ {
+ if (pointer == string) {
+ retval=NULL;
+ goto done;
+ }
+
+ break;
+ }
+
+ if ((*pointer++ = (char)ch) == L'\n')
+ break;
+ }
+
+ *pointer = L'\0';
+
+/* Common return */
+done:
+ _unlock_str(index);
+ return(retval);
+}
+
+/*
+ * Manipulate wide-chars in a file.
+ * A wide-char is hard-coded to be two chars for efficiency.
+ */
+
+static wchar_t _inc ( FILE *fileptr )
+{
+ wchar_t c1, c2;
+
+ c1 = (wchar_t)_getc_lk(fileptr);
+ c2 = (wchar_t)_getc_lk(fileptr);
+ return (wchar_t)((feof(fileptr) || ferror(fileptr)) ? WEOF : c2<<8 | c1);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////////////
+
+
+#define CMASK 0644 /* rw-r--r-- */
+
+//////////////////////////////////////////////////////////////////////////
+
+
+int _CRTAPI1 _chdirW(
+ const wchar_t *path
+ )
+{
+ char *envcurdir;
+ char dirtmp[4];
+ unsigned dirlen;
+
+ _mlock(_ENV_LOCK);
+
+ if ( SetCurrentDirectoryW( (LPWSTR) path ) ) {
+
+ /*
+ * Try to update the environment variable that specifies the
+ * current directory for the drive which is the current drive.
+ * To do this, get the full current directory, build the
+ * environment variable string and call _putenv(). If an error
+ * occurs, just return to the caller.
+ *
+ * The current directory should have the form of the example
+ * below:
+ *
+ * D:\nt\private\mytests
+ *
+ * so that the environment variable should be of the form:
+ *
+ * =D:=D:\nt\private\mytests
+ *
+ */
+
+ // NTKLUG: note that the environment does not support Unicode strings!
+ // NTKLUG: so we put in a MBCS string into the local environment.
+
+ if ( (dirlen = GetCurrentDirectoryA(0L, dirtmp)) &&
+ ((envcurdir = malloc(dirlen + 5)) != NULL) ) {
+
+ if ( GetCurrentDirectoryA(dirlen, &envcurdir[4])&&
+ (envcurdir[5] == ':') ) {
+ /*
+ * The current directory string has been
+ * copied into &envcurdir[3]. Prepend the
+ * special environment variable name and the
+ * '='.
+ */
+ envcurdir[0] = envcurdir[3] = '=';
+ envcurdir[1] = envcurdir[4];
+ envcurdir[2] = ':';
+ if ( _putenv_lk(envcurdir) )
+ free(envcurdir);
+ }
+ else
+ free(envcurdir);
+
+ }
+ _munlock(_ENV_LOCK);
+ return 0;
+ }
+ else {
+// _dosmaperr(GetLastError());
+ _munlock(_ENV_LOCK);
+ return -1;
+ }
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////
+//
+//
+//int _CRTAPI1 _mkdirW (
+// const wchar_t *path
+// )
+//{
+// unsigned long dosretval;
+//
+// /* ask OS to create directory */
+// if (!CreateDirectoryW((LPWSTR)path, (LPSECURITY_ATTRIBUTES)NULL))
+// {
+// dosretval = GetLastError();
+// }
+// else
+// {
+// dosretval = 0;
+// }
+// if (dosretval)
+// {
+// /* error occured -- map error code and return */
+// _dosmaperr(dosretval);
+// return -1;
+// }
+// return 0;
+//}
+
+
+///////////////////////////////////////////////////////////////////////
+
+
+int _CRTAPI1 removeW (
+ const wchar_t *path
+ )
+{
+ unsigned long dosretval;
+
+
+ /* ask OS/2 to remove the file */
+
+ if (!DeleteFileW((LPWSTR)path))
+ dosretval = GetLastError();
+ else
+ dosretval = 0;
+
+
+ if (dosretval) {
+ /* error occured -- map error code and return */
+// _dosmaperr(dosretval);
+ return -1;
+ }
+
+ return 0;
+}
+
+int _CRTAPI1 _unlinkW (
+ const wchar_t *path
+ )
+{
+ /* remove is synonym for unlink */
+ return removeW(path);
+}
+
+
+/////////////////////////////////////////////////////////////////////
+
+
+
+wchar_t * _CRTAPI1 _getcwdW (
+ wchar_t *pnbuf,
+ int maxlen
+ )
+{
+ wchar_t *retval;
+
+ _mlock(_ENV_LOCK);
+
+ retval = _getdcwdW_lk(0, pnbuf, maxlen);
+
+ _munlock(_ENV_LOCK);
+
+ return retval;
+}
+
+
+wchar_t * _CRTAPI1 _getdcwdW (
+ int drive,
+ wchar_t *pnbuf,
+ int maxlen // number of characters
+ )
+
+{
+ wchar_t *p;
+ wchar_t dirbuf[1];
+ int len; // number of characters
+ char DirOnDriveVar[8];
+ char *envval;
+
+ /*
+ * Only works for default drive in Win32 environment.
+ */
+ if ( drive != 0 )
+ {
+ DWORD sys_flags ;
+ DWORD fname_leng ;
+ DWORD serial_num ;
+ wchar_t vol_name[256];
+ wchar_t fsys_name[256] ;
+ wchar_t root_path[256] ;
+
+ /*
+ * Not the default drive - make sure it's valid.
+ */
+
+ root_path[0] = (wchar_t)('A' + (wchar_t)drive - (wchar_t)1);
+ root_path[1] = ':' ;
+ root_path[2] = '\\' ;
+ root_path[3] = 0;
+
+ if ( !GetVolumeInformation( root_path, vol_name, 255, &serial_num, &fname_leng, &sys_flags,
+ fsys_name, 255) )
+ {
+ errno = EACCES;
+ return NULL;
+ }
+
+ /*
+ * Get special environment variable that specifies the current
+ * directory on drive.
+ */
+ DirOnDriveVar[0] = '=';
+ DirOnDriveVar[1] = (char)('A' + (char)drive - (char)1);
+ DirOnDriveVar[2] = ':';
+ DirOnDriveVar[3] = '\0';
+
+ if ( (envval = _getenv_lk(DirOnDriveVar)) == NULL )
+ {
+ /*
+ * Environment variable not defined! Define it to be the
+ * root on that drive.
+ */
+ DirOnDriveVar[3] = '=';
+ DirOnDriveVar[4] = (char)('A' + (char)drive - (char)1);
+ DirOnDriveVar[5] = ':';
+ DirOnDriveVar[6] = '\\';
+ DirOnDriveVar[7] = '\0';
+
+ if ( _putenv_lk(DirOnDriveVar) != 0 )
+ {
+ errno = ENOMEM; /* must be out of heap memory */
+ return NULL;
+ }
+ envval = &DirOnDriveVar[4];
+ }
+
+ len = strlen(envval) + 1;
+
+ }
+ else // get directory for current drive
+ {
+
+ /*
+ * Ask OS the length of the current directory string
+ */
+ len = GetCurrentDirectoryW(sizeof(dirbuf)/sizeof(wchar_t),
+ (LPWSTR)dirbuf) + 1;
+ }
+
+ /*
+ * Set up the buffer.
+ */
+ if ( (p = pnbuf) == NULL )
+ {
+ /*
+ * Allocate a buffer for the user.
+ */
+ maxlen = __max(len, maxlen);
+ if ( (p = malloc(maxlen * sizeof(wchar_t))) == NULL )
+ {
+ errno = ENOMEM;
+ return NULL;
+ }
+ }
+ else if ( len > maxlen )
+ {
+ /*
+ * Won't fit in the user-supplied buffer!
+ */
+ errno = ERANGE; /* Won't fit in user buffer */
+ return NULL;
+ }
+
+ /*
+ * Place the current directory string into the user buffer
+ */
+
+ if ( drive != 0 )
+ {
+ /*
+ * Copy value of special environment variable into user buffer
+ * and convert it to unicode.
+ */
+ mbstowcs (p, envval, maxlen+1);
+ }
+ else
+ {
+ /*
+ * Get the current directory directly from the OS
+ */
+ if ( GetCurrentDirectoryW(len,p) == 0 )
+ {
+ /*
+ * Oops. For lack of a better idea, assume some sort
+ * of access error has occurred.
+ */
+ errno = EACCES;
+ _doserrno = GetLastError();
+ return NULL;
+ }
+ }
+ return p;
+}
+
+//////////////////////////////////////////////////////////////
+
+
+
+///////////////////////////////////////////////////////////////////////////
+
+int _CRTAPI1 _accessW (
+ const wchar_t *path,
+ int amode
+ )
+{
+ DWORD attr;
+
+
+ attr = GetFileAttributesW((LPWSTR)path);
+
+ if (attr == 0xffffffff)
+ {
+ /* error occured -- map error code and return */
+ errno = ENOENT ;
+// _dosmaperr(GetLastError());
+ return -1;
+ }
+
+ /* no error; see if returned premission settings OK */
+ if (attr & FILE_ATTRIBUTE_READONLY && (amode & 2))
+ {
+ /* no write permission on file, return error */
+ errno = EACCES;
+// _doserrno = E_access;
+ return -1;
+ }
+ else
+ {
+ /* file exists and has requested permission setting */
+ return 0;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////
+
+
+int _CRTAPI1 _chmodW (
+ const wchar_t *path,
+ int mode
+ )
+{
+ DWORD attr;
+
+ attr = GetFileAttributesW((LPWSTR)path);
+ if (attr == 0xffffffff)
+ {
+ /* error occured -- map error code and return */
+// _dosmaperr(GetLastError());
+ return -1;
+ }
+
+ if (mode & _S_IWRITE)
+ {
+ /* clear read only bit */
+ attr &= ~FILE_ATTRIBUTE_READONLY;
+ }
+ else
+ {
+ /* set read only bit */
+ attr |= FILE_ATTRIBUTE_READONLY;
+ }
+
+ /* set new attribute */
+ if (!SetFileAttributesW((LPWSTR)path, attr))
+ {
+ /* error occured -- map error code and return */
+// _dosmaperr(GetLastError());
+ return -1;
+ }
+ return 0;
+}
+
+
+/////////////////////////////////////////////////////////////
+
+
+//static wchar_t * _stripquoteW (wchar_t * src );
+//
+//#define TMP_BUF_SIZE 256 //size of buffer for TMP environment variable
+//
+//wchar_t * _CRTAPI1 _tempnamW (
+// wchar_t *dir,
+// wchar_t *pfx
+// )
+//{
+//
+// wchar_t *ptr;
+// unsigned int pfxlength=0;
+// wchar_t * s;
+// wchar_t * pfin;
+// unsigned int first;
+// wchar_t * qptr = NULL; /* ptr to TMP path with quotes stripped out */
+//
+// wchar_t szTmp[TMP_BUF_SIZE] = L"";
+// int cchTmp = 0;
+//
+//
+//
+// /* try TMP path */
+// if ((cchTmp = GetEnvironmentVariableW (L"TMP", szTmp, sizeof (szTmp)))
+// && (-1 != _accessW (szTmp, 0)) )
+// {
+// dir = szTmp;
+// }
+// else /* try stripping quotes out of TMP path */
+// if ( (cchTmp != 0)
+// && (qptr = _stripquoteW(szTmp))
+// && (-1 != _accessW(qptr, 0)) )
+// {
+// dir = qptr;
+// }
+// else /* TMP path not available, use alternatives */
+// if (!( dir != NULL && ( _accessW( dir, 0 ) != -1 ) ) )
+// {
+// /* do not "simplify" this depends on side effects!! */
+// free(qptr); /* free buffer, if non-NULL */
+//
+// /* convert global variable to a Unicode string */
+// cchTmp = mbstowcs ( szTmp, _P_tmpdir, strlen (_P_tmpdir)+1 );
+//
+// if ((cchTmp > 0)
+// && (_accessW( szTmp, 0 ) != -1 ))
+// {
+// dir = szTmp;
+// }
+// else
+// {
+// dir = L".";
+// }
+// }
+//
+//
+// if (pfx)
+// {
+// pfxlength = wcslen(pfx);
+// }
+// /* the 8 below allows for a backslash, 6 char temp string and */
+// /* a null terminator */
+//
+// if ( ( s = malloc (wcslen(dir) + pfxlength + 8*sizeof(wchar_t)) ) == NULL )
+// {
+// goto done2;
+// }
+// *s = L'\0';
+// wcscat( s, dir );
+// pfin = &(dir[ wcslen( dir ) - 1 ]);
+//
+// if ( ( *pfin != L'\\' ) && ( *pfin != L'/' ) )
+// {
+// wcscat( s, L"\\" );
+// }
+// if ( pfx != NULL )
+// {
+// wcscat( s, pfx );
+// }
+// ptr = &s [ wcslen( s ) ];
+//
+// /*
+// Re-initialize _tempoff if necessary. If we don't re-init _tempoff, we
+// can get into an infinate loop (e.g., (a) _tempoff is a big number on
+// entry, (b) prefix is a long string (e.g., 8 chars) and all tempfiles
+// with that prefix exist, (c) _tempoff will never equal first and we'll
+// loop forever).
+//
+// [NOTE: To avoid a conflict that causes the same bug as that discussed
+// above, _tempnam() uses _tempoff; tmpnam() uses _tmpoff]
+// */
+//
+// _mlock(_TMPNAM_LOCK); /* Lock access to _old_pfxlen and _tempoff */
+//
+// if (_old_pfxlen < pfxlength)
+// {
+// _tempoff = 1;
+// }
+// _old_pfxlen = pfxlength;
+//
+// first = _tempoff;
+//
+// do {
+// if ( ++_tempoff == first ) {
+// free(s);
+// s = NULL;
+// goto done1;
+// }
+// swprintf ( ptr, L"%d", _tempoff );
+// //_itoa( _tempoff, ptr, 10 );
+//
+// if ( wcslen( ptr ) + pfxlength > 8 )
+// {
+// *ptr = L'\0';
+// _tempoff = 0;
+// }
+// }
+// while ( (_accessW( s, 0 ) == 0 ) || (errno == EACCES) );
+//
+//
+// /* Common return */
+//done1:
+// _munlock(_TMPNAM_LOCK); /* release tempnam lock */
+//done2:
+// free(qptr); /* free temp ptr, if non-NULL */
+// return(s);
+//}
+//
+//
+//static wchar_t * _stripquoteW (wchar_t * src )
+//{
+// wchar_t * dst;
+// wchar_t * ret;
+// unsigned int q = 0;
+//
+//
+// /* get a buffer for the new string */
+//
+// if ((dst = malloc((wcslen(src)+1)*sizeof(wchar_t)) ) == NULL)
+// {
+// return(NULL);
+// }
+// /* copy the string stripping out the quotes */
+//
+// ret = dst; /* save base ptr */
+//
+// while (*src)
+// {
+//
+// if (*src == L'\"')
+// {
+// src++; q++;
+// }
+// else
+// {
+// *dst++ = *src++;
+// }
+// }
+// if (q)
+// {
+// *dst = L'\0'; /* final nul */
+// return(ret);
+// }
+// else
+// {
+// free(ret);
+// return(NULL);
+// }
+//
+//}
+
+///////////////////////////////////////////////////////
+
+int _CRTAPI1 renameW (
+ const wchar_t *oldname,
+ const wchar_t *newname
+ )
+{
+ ULONG dosretval;
+
+ /* ask OS to move file */
+
+ if (!MoveFileW((LPWSTR)oldname, (LPWSTR)newname))
+ dosretval = GetLastError();
+ else
+ dosretval = 0;
+
+ if (dosretval) {
+ /* error occured -- map error code and return */
+// _dosmaperr(dosretval);
+ return -1;
+ }
+
+ return 0;
+}
+
+FILE * UNI_fopen( wchar_t *fname, unsigned long flags )
+{
+ int mode = GENERIC_READ ;
+ int append = OPEN_ALWAYS ;
+ HANDLE fhand;
+ INT crt_hand = -1 ;
+ FILE *strm_hand = NULL ;
+
+ if ( (flags & _O_RDONLY) == 0 ) {
+ mode |= GENERIC_WRITE ;
+ if ( (flags & _O_APPEND) == 0 ) {
+ append = CREATE_ALWAYS ;
+ }
+ }
+ fhand = CreateFileW(fname, mode, FILE_SHARE_READ, NULL, append, FILE_ATTRIBUTE_NORMAL, NULL ) ;
+
+ if ( fhand != INVALID_HANDLE_VALUE ) {
+ crt_hand = _open_osfhandle( (long)fhand, flags&~_O_APPEND ) ;
+ if ( crt_hand == -1 ) {
+ CloseHandle( fhand) ;
+ } else {
+ if ( (flags & _O_RDONLY) == 0 ) {
+ if ( (flags & _O_APPEND) == 0 ) {
+ if ( (flags & _O_TEXT) == 0 ) {
+ strm_hand = _fdopen( crt_hand, "wb+" ) ;
+ } else {
+ strm_hand = _fdopen( crt_hand, "wt+" ) ;
+ }
+ } else {
+ if ( (flags & _O_TEXT) == 0 ) {
+ strm_hand = _fdopen( crt_hand, "ab+" ) ;
+ } else {
+ strm_hand = _fdopen( crt_hand, "at+" ) ;
+ }
+ fseek( strm_hand, 0L, SEEK_END ) ;
+ }
+ } else {
+ if ( (flags & _O_TEXT) == 0 ) {
+ strm_hand = _fdopen( crt_hand, "rb" ) ;
+ } else {
+ strm_hand = _fdopen( crt_hand, "rt" ) ;
+ }
+ strm_hand = _fdopen( crt_hand, "rb" ) ;
+ }
+ }
+ }
+
+ return strm_hand ;
+}
+
+
+
+
+///////////////////////////////////////////////////////////////
+
+/*
+ * Let's undefine OpenFile (from OpenFileW) so we don't call ourselves.
+ * This is a total kludge, though. We should be using CreateFile on Win32.
+ */
+
+///////////////////////////////////////////////////////////////////
+
+
+static void xtoa (
+ unsigned long val,
+ wchar_t *buf,
+ unsigned radix,
+ int is_neg
+ )
+{
+ wchar_t *p; /* pointer to traverse string */
+ wchar_t *firstdig; /* pointer to first digit */
+ wchar_t temp; /* temp char */
+ unsigned digval; /* value of digit */
+
+ p = buf;
+
+ if (is_neg) {
+ long l;
+
+ /* negative, so output '-' and negate */
+ *p++ = L'-';
+ l = (long)val;
+ val = (unsigned long)(-l);
+ }
+
+ firstdig = p; /* save pointer to first digit */
+
+ do {
+ digval = (unsigned) (val % radix);
+ val /= radix; /* get next digit */
+
+ /* convert to ascii and store */
+ if (digval > 9)
+ *p++ = (wchar_t) (digval - 10 + L'a'); /* a letter */
+ else
+ *p++ = (wchar_t) (digval + L'0'); /* a digit */
+ } while (val > 0);
+
+ /* We now have the digit of the number in the buffer, but in reverse
+ order. Thus we reverse them now. */
+
+ *p-- = '\0'; /* terminate string; p points to last digit */
+
+ do {
+ temp = *p;
+ *p = *firstdig;
+ *firstdig = temp; /* swap *p and *firstdig */
+ --p;
+ ++firstdig; /* advance to next two digits */
+ } while (firstdig < p); /* repeat until halfway */
+}
+
+
+/* Actual functions just call conversion helper with neg flag set correctly,
+ and return pointer to buffer. */
+
+wchar_t * _CRTAPI1 _itoaW (
+ int val,
+ wchar_t *buf,
+ int radix
+ )
+{
+ if (radix == 10 && val < 0)
+ xtoa((unsigned long)val, buf, radix, 1);
+ else
+ xtoa((unsigned long)(unsigned int)val, buf, radix, 0);
+ return buf;
+}
+
+wchar_t * _CRTAPI1 _ltoaW (
+ long val,
+ wchar_t *buf,
+ int radix
+ )
+{
+ xtoa((unsigned long)val, buf, radix, (radix == 10 && val < 0));
+ return buf;
+}
+
+wchar_t * _CRTAPI1 _ultoaW (
+ unsigned long val,
+ wchar_t *buf,
+ int radix
+ )
+{
+ xtoa(val, buf, radix, 0);
+ return buf;
+}
+
+#endif //UNICODE
diff --git a/private/utils/ntbackup/src/unitinit.c b/private/utils/ntbackup/src/unitinit.c
new file mode 100644
index 000000000..a6865ffaf
--- /dev/null
+++ b/private/utils/ntbackup/src/unitinit.c
@@ -0,0 +1,480 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: unitinit.c
+
+ Description: This file contains the user interface arbitrator entry
+ point function (UI_UnitsInit) that handles setting up
+ to call the backup engine init entry point (BE_Init).
+
+ $Log: G:/UI/LOGFILES/UNITINIT.C_V $
+
+ Rev 1.26 03 Aug 1993 18:09:38 MARINA
+enable c++
+
+ Rev 1.25 23 Jul 1993 14:25:26 GLENN
+Replaced the app name of the software name string with the long app name.
+
+ Rev 1.24 22 Jul 1993 12:04:36 GLENN
+Added software name support to pass to TF layer for identifying software on tape.
+
+ Rev 1.23 15 Jun 1993 12:05:44 GLENN
+Added support for the NT dummy device driver.
+
+ Rev 1.22 23 Dec 1992 15:39:46 GLENN
+Now displaying no config warning during unattended jobs.
+
+ Rev 1.21 07 Oct 1992 14:50:56 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.20 04 Oct 1992 19:41:26 DAVEV
+Unicode Awk pass
+
+ Rev 1.19 30 Sep 1992 10:44:56 DAVEV
+Unicode strlen verification, MikeP's chgs from MS
+
+ Rev 1.18 08 Aug 1992 09:39:54 MIKEP
+start changes for nt hw config
+
+ Rev 1.17 25 Jun 1992 14:06:56 DAVEV
+mwDil is specific to OS_WIN32, not OEM_MSOFT
+
+ Rev 1.16 10 Jun 1992 10:25:50 STEVEN
+would not compile for mips
+
+ Rev 1.15 27 May 1992 18:44:48 STEVEN
+switch should be WIN32 not MSOFT
+
+ Rev 1.14 14 May 1992 17:23:52 MIKEP
+nt pass 2
+
+ Rev 1.13 11 May 1992 14:25:56 DAVEV
+OS_WIN32: chgd STEVE's OEM_MSOFT changes to OS_WIN32, 'cause they's NT specific
+
+ Rev 1.12 27 Apr 1992 14:30:30 CARLS
+changed tdemo number of tapes from 1 to 3
+
+ Rev 1.11 22 Apr 1992 17:48:54 GLENN
+Added TdemoInit() call for TDEMO version only.
+
+ Rev 1.10 30 Mar 1992 18:12:18 GLENN
+Changed return code when no driver string is found.
+
+ Rev 1.9 26 Mar 1992 16:55:02 STEVEN
+update for OEM_MSOFT
+
+ Rev 1.8 03 Mar 1992 18:26:44 GLENN
+Added a change to exe dir call just before reiniting the TF layer for reading .DLLs
+
+ Rev 1.7 11 Feb 1992 17:29:30 GLENN
+Put hardware warning message in string table.
+
+ Rev 1.6 27 Jan 1992 12:48:16 GLENN
+Changed dialog support calls.
+
+ Rev 1.5 17 Jan 1992 16:48:40 JOHNWT
+changed data to cat path
+
+ Rev 1.4 10 Jan 1992 15:46:46 CARLS
+removed strings
+
+ Rev 1.3 07 Jan 1992 17:31:58 GLENN
+Added support for polldrive retry after hwinit failure
+
+ Rev 1.2 19 Dec 1991 17:41:30 DAVEV
+16/32 bit port - 2nd pass
+
+ Rev 1.1 18 Dec 1991 14:07:02 GLENN
+Added windows.h
+
+ Rev 1.0 20 Nov 1991 19:18:54 SYSTEM
+Initial revision.
+
+*****************************************************************************/
+
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+// PRIVATE STATIC VARIABLES
+
+static BOOLEAN mwfTFInitialized = FALSE;
+
+/* Definition of resources for the loadable DriverDetermine module */
+
+#if !defined( TDEMO ) && !defined( OS_WIN32 )
+
+ static STD_RESOURCES_INIT detres = {
+ #if !defined( MAYN_OS2)
+ ( PF_intdosx )intdosx,
+ ( PF_free )free,
+ ( PF_memset )memset,
+ ( PF_inp )inp,
+ ( PF_inpw )inpw,
+ ( PF_outp )outp,
+ ( PF_outpw )outpw,
+ ( PF_calloc )calloc,
+ ( PF_int86 )int86,
+ ( PF_int86x )int86x,
+ #endif
+ ( PF_DriverLoad )DriverLoad,
+ ( PF_CDS_GetMaynFolder )CDS_GetExePath
+ } ;
+
+#endif /* TDEMO */
+
+/*****************************************************************************
+
+ Name: UI_UnitsInit
+
+ Description:
+
+ Returns: error returned from BE_Init, or controller related error
+
+ See also: $/SEE( init.c be_init.c hwconf.c )$
+
+*****************************************************************************/
+INT16 UI_UnitsInit (
+
+BE_INIT_STR_PTR pBE, // I - Backup Engine Init Structure pointer
+INT16 nInitType ) // I - Init TYPE
+
+{
+ INT nErrorBE ;
+ INT nErrorUI = FALSE ;
+ CHAR szDriverName[9] ;
+ INT nNumDILs = 0 ;
+ INT rc = 1;
+
+#ifdef MAYN_OS2
+
+ // First attempt to apply a lock to the backup engine.
+
+ if ( ( nInitType & INIT_TFL ) && ( UI_LockBackupEngine( ) != SUCCESS ) ) {
+ return BENGINE_IN_USE ;
+ }
+
+#endif
+
+ WM_ShowWaitCursor ( TRUE );
+
+ // Initialize be_init structure elements.
+
+ pBE->critical_error_handler = NULL;
+ pBE->debug_print = ( VOID ( * )( UINT16, CHAR_PTR, va_list ) )zvprintf;
+ pBE->units_to_init = 0;
+ pBE->dle_list_ptr = &dle_list;
+ pBE->bsd_list_ptr = &bsd_list;
+ pBE->remote_filter = NRL_LANBACK_DRIVE;
+
+ pBE->driver_directory = ( CHAR_PTR )calloc( ( strlen( CDS_GetExePath() ) + sizeof ( CHAR ) ), sizeof ( CHAR ) );
+ strcpy( pBE->driver_directory, CDS_GetExePath( ) );
+
+ pBE->catalog_directory = ( CHAR_PTR )calloc( ( strlen( CDS_GetCatDataPath() ) + sizeof ( CHAR ) ), sizeof ( CHAR ) );
+ strcpy( pBE->catalog_directory, CDS_GetCatDataPath( ) );
+
+ // Get the software application name, version, and revision for the
+ // tape format to write on tape.
+
+ {
+ CHAR szSoftwareName[MAX_UI_RESOURCE_SIZE];
+ CHAR szAppName[120];
+ CHAR szAppExeName[20];
+ CHAR szAppVersion[60];
+ CHAR szAppVerNum[10];
+ CHAR szAppRevNum[10];
+
+ RSM_StringCopy ( IDS_LONGAPPNAME, szAppName, sizeof ( szAppName ) );
+ RSM_StringCopy ( IDS_EXEFILENAME, szAppExeName, sizeof ( szAppExeName ) );
+ RSM_StringCopy ( IDS_APPVERSION, szAppVersion, sizeof ( szAppVersion ) );
+ RSM_StringCopy ( IDS_APPEXEVER, szAppVerNum, sizeof ( szAppVerNum ) );
+ RSM_StringCopy ( IDS_APPENGREL, szAppRevNum, sizeof ( szAppRevNum ) );
+
+ strcat ( szAppName, TEXT(" (") );
+ strcat ( szAppName, szAppExeName );
+ strcat ( szAppName, TEXT(") ") );
+ strcat ( szAppName, szAppVersion );
+
+ sprintf ( szSoftwareName, szAppName, szAppVerNum, szAppRevNum );
+
+ pBE->software_name = ( CHAR_PTR )calloc ( ( strlen ( szSoftwareName ) + sizeof ( CHAR ) ), sizeof ( CHAR ) );
+
+ if ( pBE->software_name ) {
+ strcpy( pBE->software_name, szSoftwareName );
+ }
+
+ }
+
+ if ( ( nInitType & REINIT_TFL ) || ( nInitType & INIT_TFL ) ) {
+
+# if !defined( OS_WIN32 )
+
+ // Simply get the currently defined device driver from config.
+
+ strcpy ( szDriverName, ( CDS_GetActiveDriver( CDS_GetPerm() ) ) );
+
+ WM_ShowWaitCursor ( FALSE );
+
+ while ( ( ! strlen ( szDriverName ) ) && ( ! (BOOL)( nErrorUI) ) ) {
+
+ if ( ! CDS_GetAdvToConfig ( CDS_GetPerm () ) ) {
+
+ rc = WM_MsgBox ( ID(IDS_HWC_WARNING_TITLE),
+ ID(IDS_HWC_NO_CONFIG),
+ WMMB_YESNO | WMMB_NOYYCHECK,
+ WMMB_ICONQUESTION );
+
+ if ( rc == WMMB_IDYES ) {
+
+ CDS_SetAdvToConfig ( CDS_GetPerm (), TRUE );
+ rc = DM_ShowDialog ( ghWndFrame, IDD_SETTINGSHARDWARE, (PVOID)0 );
+ CDS_SetAdvToConfig ( CDS_GetPerm (), FALSE );
+
+ // Try again to get the currently defined device
+ // driver from config.
+
+ strcpy ( szDriverName, ( CDS_GetActiveDriver ( CDS_GetPerm() ) ) );
+ }
+ else {
+
+ nErrorUI = HW_ERROR_DETECTED;
+ }
+ }
+ }
+
+ WM_ShowWaitCursor ( TRUE );
+
+ if ( strlen ( szDriverName ) ) {
+
+ zprintf ( DEBUG_DEVICE_DRIVER, RES_LOADING_DRIVER, szDriverName );
+
+ // Call user interface hardware support routine to fill out
+ // the DIL HW structure.
+
+ nErrorUI = HWC_InitDILHWD( &gb_dhw_ptr, &nNumDILs );
+
+ if ( nErrorUI == SUCCESS ) {
+
+ /* Setup the tape format init parameters in the be_init structure */
+
+ strcpy( pBE->driver_name, CDS_GetExePath( ) ) ;
+ strcat( pBE->driver_name, szDriverName ) ;
+ strcat( pBE->driver_name, DLL_EXTENSION ) ;
+
+ pBE->dhwd_ptr = gb_dhw_ptr ;
+ pBE->number_of_cards = (INT16) nNumDILs ; /* number of dil structures allocated */
+ pBE->thw_list_ptr = &thw_list ; /* TF fills this out */
+ pBE->max_channels = 1 ; /* ms 3.0 only supports a single channel */
+ pBE->tf_buffer_size = CDS_GetTFLBuffSize ( CDS_GetPerm() ) ;
+ }
+ }
+# else
+
+ if ( gfDummyDriver ) {
+
+ CHAR szDriverName [MAX_UI_SMALLRES_SIZE];
+
+ RSM_StringCopy ( IDS_HWC_DUMMY_DEVICE_DLL, szDriverName, sizeof ( szDriverName ) );
+
+ strcpy ( pBE->driver_name, CDS_GetExePath( ) ) ;
+ strcat ( pBE->driver_name, szDriverName ) ;
+
+ }
+ else {
+ strcpy ( pBE->driver_name, TEXT("") );
+ }
+
+ gb_dhw_ptr = &gb_NTDIL ;
+ memset( gb_dhw_ptr, 0, sizeof(gb_NTDIL) ) ;
+
+ pBE->dhwd_ptr = gb_dhw_ptr ;
+ pBE->number_of_cards = (UINT16) 1 ;
+ pBE->thw_list_ptr = &thw_list ; /* TF fills this out */
+ pBE->max_channels = 1 ; /* ms 3.0 only supports a single channel */
+ pBE->tf_buffer_size = CDS_GetTFLBuffSize ( CDS_GetPerm() ) ;
+
+# endif //OS_WIN32
+
+ }
+
+ /* If NO driver determination error has occurred, init the entire backup */
+ /* engine, otherwise, init backup engine excluding initing Tape Format */
+
+ if ( ! nErrorUI ) {
+
+ switch ( nInitType ) {
+
+ case INIT_ALL:
+ case INIT_FSYS_BSDU:
+
+# if defined( TDEMO )
+ {
+ TdemoInit ( CDS_GetUserDataPath (), /* TDEMO?.DAT directory */
+ 3, /* number of tapes ( 3 max ) */
+ (VOID_PTR)1, /* workstation resource */
+ (VOID_PTR)1, /* alias resource */
+ FALSE /* demo speed */
+ );
+
+
+ }
+# endif // TDEMO
+
+ zprintf ( DEBUG_USER_INTERFACE, RES_INIT_FILE_SYSTEM );
+
+ STM_SetIdleText ( IDS_INITFILESYS );
+
+ pBE->units_to_init |= BE_INIT_FSYS ;
+ pBE->units_to_init |= BE_INIT_BSDU ;
+ nErrorBE = BE_Init( pBE, CDS_GetPermBEC() ) ;
+ break ;
+
+ case INIT_TFL:
+ case REINIT_TFL:
+
+# if !defined( OS_WIN32 )
+
+ if ( !strlen ( szDriverName ) ) {
+ break ;
+ }
+# endif
+
+
+ zprintf ( DEBUG_USER_INTERFACE, RES_INIT_HARDWARE );
+
+ STM_SetIdleText ( IDS_INITHARDWARE );
+
+ CDS_ChangeToExeDir ();
+
+ if ( gfDummyDriver ) {
+ WM_ShowWaitCursor ( SWC_PAUSE );
+ }
+
+ nErrorBE = BE_ReinitTFLayer( pBE, CDS_GetPermBEC() ) ;
+
+ if ( gfDummyDriver ) {
+ WM_ShowWaitCursor ( SWC_RESUME );
+ }
+
+ // Quality check the expected number of drives attached
+ // and define the logical drive channel.
+
+ if( nErrorBE == BE_INIT_SUCCESS ) {
+ DefineChannel( pBE ) ;
+ }
+
+ // If this is the firt time for INIT_TFL or REINIT_TFL, add
+ // the UI_UnitsDeInit () to the exit list. This must be
+ // done so that the atexit() call in the DriverLoad() call
+ // can be placed in the list before the this modules call.
+
+ if ( ! mwfTFInitialized ) {
+
+ mwfTFInitialized = TRUE;
+ }
+
+
+ break ;
+
+ }
+
+ nErrorUI = nErrorBE ;
+ }
+
+ if ( pBE->software_name ) {
+ free ( pBE->software_name );
+ }
+
+ WM_ShowWaitCursor ( FALSE );
+
+ return (INT16) nErrorUI ;
+}
+
+#ifdef MAYN_OS2
+
+/*****************************************************************************
+
+ Name: UI_LockBackupEngine
+
+ Description: Creates a system semaphore which indicates that the Backup
+ Engine is in use. If the semaphore has already been
+ created, the engine is already in use and locked and the
+ caller is returned FALSE.
+
+ Returns: SUCCESS (0) or FAILURE (!0).
+
+*****************************************************************************/
+INT16 UI_LockBackupEngine( VOID )
+{
+ INT16 rc = SUCCESS ;
+
+ if ( rc = DosCreateSem( SHARED, &mw_bengine_sem, BENGINE_SEM ) )
+ {
+ mw_bengine_locked = FALSE ;
+ }
+ else
+ {
+ mw_bengine_locked = TRUE ;
+ };
+
+ return( rc );
+
+} /* end UI_LockBackupEngine() */
+
+/*****************************************************************************
+
+ Name: UI_UnlockBackupEngine
+
+ Description: Closes the system semaphore which indicates that the Backup
+ Engine is in use, only if the semaphore exists.
+
+ Returns: SUCCESS (0) or FAILURE (!0).
+
+*****************************************************************************/
+INT16 UI_UnlockBackupEngine( VOID )
+{
+ INT16 rc = SUCCESS ;
+
+ /****************************************************************
+ * If the Backup Engine semaphore is open, close it. *
+ ****************************************************************/
+
+ if ( mw_bengine_locked ) {
+ rc = DosCloseSem( mw_bengine_sem ) ;
+ }
+
+ return( rc ) ;
+
+} /* end UI_UnlockBackupEngine() */
+
+#endif
+
+
+/*****************************************************************************
+
+ Name: UI_UnitsDeInit
+
+ Description: This function is automatically called at exit time because
+ UI_UnitsInit set it up as an atexit function. This function
+ should reverse the effect of UI_UnitsInit.
+
+ Returns: nothing
+
+ Notes: atexit functions cannot take any parameters.
+
+*****************************************************************************/
+VOID UI_UnitsDeInit( VOID )
+{
+
+ BE_Deinit( dle_list );
+
+#ifdef MAYN_OS2
+ UI_UnlockBackupEngine() ;
+#endif
+
+}
+
+
diff --git a/private/utils/ntbackup/src/version.rc b/private/utils/ntbackup/src/version.rc
new file mode 100644
index 000000000..0102dbd2c
--- /dev/null
+++ b/private/utils/ntbackup/src/version.rc
@@ -0,0 +1,43 @@
+/*
+** Version resources for NTBackup.
+**
+** Ntverp.h defines several global values that don't need to be
+** changed except for official releases such as betas, sdk updates, etc.
+**
+** Common.ver has the actual version resource structure that all these
+** #defines eventually initialize.
+*/
+
+#include <ntverp.h>
+
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR
+ * and VER_INTERNALNAME_STR must be defined before including COMMON.VER
+ * The strings don't need a '\0', since common.ver has them.
+ */
+#define VER_FILETYPE VFT_APP
+/* possible values: VFT_UNKNOWN
+ VFT_APP
+ VFT_DLL
+ VFT_DRV
+ VFT_FONT
+ VFT_VXD
+ VFT_STATIC_LIB
+*/
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+/* possible values VFT2_UNKNOWN
+ VFT2_DRV_PRINTER
+ VFT2_DRV_KEYBOARD
+ VFT2_DRV_LANGUAGE
+ VFT2_DRV_DISPLAY
+ VFT2_DRV_MOUSE
+ VFT2_DRV_NETWORK
+ VFT2_DRV_SYSTEM
+ VFT2_DRV_INSTALLABLE
+ VFT2_DRV_SOUND
+ VFT2_DRV_COMM
+*/
+#define VER_FILEDESCRIPTION_STR "NT Tape Backup Utility"
+#define VER_INTERNALNAME_STR "NTBackup.Exe"
+#define VER_ORIGINALFILENAME_STR "NTBackup.Exe"
+
+#include "common.ver"
diff --git a/private/utils/ntbackup/src/very_dle.c b/private/utils/ntbackup/src/very_dle.c
new file mode 100644
index 000000000..0c04b16ff
--- /dev/null
+++ b/private/utils/ntbackup/src/very_dle.c
@@ -0,0 +1,270 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: very_dle.c
+
+ Description: this file contains the routine to process a single dle for verify.
+
+ $Log: N:\logfiles\very_dle.c_v $
+
+ Rev 1.15.1.1 26 Apr 1994 18:59:28 STEVEN
+fix dissconect bug
+
+ Rev 1.15.1.0 07 Feb 1994 02:06:46 GREGG
+Fixed and expanded 'extended error reporting'.
+
+ Rev 1.15 14 Jan 1993 13:33:06 STEVEN
+added stream_id to error message
+
+ Rev 1.14 08 Apr 1992 17:39:58 NED
+added handling of TFLE_USER_ABORT
+from LP_StartTPEDialog().
+Marilyn made me do it!
+
+ Rev 1.13 16 Mar 1992 16:23:28 STEVEN
+initialize the DBLKS
+
+ Rev 1.12 24 Feb 1992 10:00:32 GREGG
+Call TF_OpenTape at beginning of loop, Open/Close Set in loop, CloseTape at end.
+
+ Rev 1.11 19 Feb 1992 16:00:46 GREGG
+Added vcb_only parameter to call to TF_OpenSet.
+
+ Rev 1.10 06 Nov 1991 18:21:50 GREGG
+BIGWHEEL - 8200sx - Get cat_enabled from lp instead of lis.
+
+ Rev 1.9 17 Oct 1991 01:52:04 ED
+BIGWHEEL - 8200sx - Initial integration.
+
+ Rev 1.8 16 Aug 1991 17:11:34 STEVEN
+Could not Verify or Restore multiple sets
+
+ Rev 1.7 24 Jul 1991 15:55:18 DAVIDH
+Cleared up warnings under Watcom.
+
+ Rev 1.6 27 Jun 1991 13:12:16 STEVEN
+use config for write format
+
+ Rev 1.5 24 Jun 1991 17:22:44 STEVEN
+remove date time from StartBS
+
+ Rev 1.4 21 Jun 1991 08:49:12 STEVEN
+new config unit
+
+ Rev 1.3 30 May 1991 09:11:08 STEVEN
+bsdu_err.h no longer exists
+
+ Rev 1.2 24 May 1991 13:19:02 STEVEN
+updates from BSDU redesign
+
+ Rev 1.1 15 May 1991 11:00:48 DAVIDH
+Cleared up type mismatch found by Watcom compiler.
+
+ Rev 1.0 09 May 1991 13:37:06 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "queues.h"
+#include "msassert.h"
+#include "tbe_defs.h"
+#include "tbe_err.h"
+#include "bsdu.h"
+#include "fsys.h"
+#include "tflproto.h"
+#include "tfldefs.h"
+#include "loops.h"
+#include "loop_prv.h"
+#include "lis.h"
+#include "get_next.h"
+#include "beconfig.h"
+/* $end$ include list */
+
+/**/
+/**
+
+ Name: LP_VerifyDLE()
+
+ Description: this routine process a single dle for verification
+
+ Modified: 5/24/1991 10:58:3
+
+ Returns: tape backup engine error
+
+ Notes: none
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 LP_VerifyDLE(
+BSD_PTR bsd_ptr, /* I - The verify selections */
+register LP_ENV_PTR lp, /* I - The Loop Environment struct */
+BOOLEAN reuse_bsd, /* I - TRUE if this is the same BSD */
+INT16 channel_no, /* I - The channel number */
+THW_PTR sdrv ) /* I - The starting drive */
+{
+ INT16 return_status ;
+ DBLK_PTR curr_blk ;
+ TFL_OPBLK pb ;
+ DATA_FRAGMENT data_frag ;
+ LBA_ELEM lba_elem ;
+ BOOLEAN lba_empty ;
+
+ /* setup requested tape id and tape seq number */
+ if( ( ( BSD_GetTapeID( bsd_ptr ) != -1 ) ||
+ ( BSD_GetTapeNum( bsd_ptr ) != -1 ) ) &&
+ ( !reuse_bsd ) ) {
+ lp->tpos.tape_id = BSD_GetTapeID( bsd_ptr ) ;
+ lp->tpos.tape_seq_num = BSD_GetTapeNum( bsd_ptr ) ;
+ }
+
+ memset( lp->curr_ddb, 0, sizeof(DBLK) ) ;
+ memset( lp->curr_blk, 0, sizeof(DBLK) ) ;
+
+ lp->lis_ptr->curr_bsd_ptr = bsd_ptr ;
+ pb.tape_position = &lp->tpos ;
+ pb.sdrv = sdrv ;
+ pb.channel = channel_no ;
+ pb.rewind_sdrv = FALSE ;
+ pb.perm_filter = TF_KEEP_ALL_DATA ;
+ pb.attributes = 0L ;
+ pb.fsh = lp->curr_fsys ;
+ pb.mode = TF_READ_OPERATION ;
+ pb.ignore_clink = FALSE ;
+ pb.wrt_format = BEC_GetWriteFormat( BSD_GetConfigData(bsd_ptr) ) ;
+ pb.idle_call = NULL ;
+ pb.cat_enabled = lp->cat_enabled ;
+
+ memset( &data_frag, 0, sizeof( data_frag ) ) ;
+
+ if( !reuse_bsd ) {
+ /* Setup for FFR based operation... */
+ lp->tpos.tape_loc.pba_vcb = BSD_GetPBA( bsd_ptr );
+ lp->rr.tape_loc.pba_vcb = BSD_GetPBA( bsd_ptr );
+ }
+
+ lba_empty = BSD_GetFirstLBA( bsd_ptr, &lba_elem ) ;
+
+ if ( !reuse_bsd && !lba_empty ) {
+ lp->tpos.tape_loc.tape_seq = LBA_GetTapeNum( &lba_elem ) ;
+ lp->tpos.tape_loc.lba = LBA_GetLBA( &lba_elem ) ;
+ lp->rr.tape_loc.tape_seq = LBA_GetTapeNum( &lba_elem ) ;
+ lp->rr.tape_loc.lba = LBA_GetLBA( &lba_elem ) ;
+ pb.tape_position->tape_seq_num = LBA_GetTapeNum( &lba_elem ) ;
+ pb.tape_position->tape_id = BSD_GetTapeID( bsd_ptr ) ;
+
+ } else {
+
+ /* If not a FFR drive, nor a drive which can mode switch to FFR, nor an SX drive then
+ make sure that PBA of the VCB has been cleared */
+ if( !( BSD_HardwareSupportsFeature( bsd_ptr, TDI_FAST_NBLK ) ||
+ BSD_HardwareSupportsFeature( bsd_ptr, TDI_MODE_CHANGE ) ||
+ BSD_HardwareSupportsFeature( bsd_ptr, TDI_FIND_BLK ) ) ) {
+ lp->tpos.tape_loc.pba_vcb = 0 ;
+ lp->rr.tape_loc.pba_vcb = 0 ;
+ }
+
+ }
+
+
+ /* Now open the backup set */
+ if( ( return_status = TF_OpenSet( &pb, FALSE ) ) == SUCCESS ) {
+
+ /* store the channel */
+ lp->channel = pb.channel ;
+
+ if( ( return_status = LP_StartTPEDialogue( lp, FALSE ) ) == SUCCESS ) {
+
+ /* log start of backup set */
+ LP_MsgStartBS( lp->lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, lp->curr_blk ) ;
+
+ if( return_status == SUCCESS ) {
+
+ /* Now we have the GetNextItemLoop */
+ do {
+ if( ( return_status = LP_GetNextTPEBlock( lp, &curr_blk ) ) == SUCCESS ) {
+
+ if ( curr_blk != NULL ) {
+
+ return_status = LP_VerifyOBJ( lp, curr_blk, &data_frag ) ;
+ if( FS_GetBlockType( curr_blk ) == IDB_ID ) {
+ /* This is a kludge to cover for the fact that */
+ /* the image is treated as a single object. */
+ break ;
+ }
+ } else {
+ break ;
+ }
+
+ }
+
+ /* check for abort conditions */
+ switch( LP_GetAbortFlag( lp->lis_ptr ) ) {
+
+ case CONTINUE_PROCESSING:
+ break ;
+
+ case ABORT_CTRL_BREAK:
+ LP_MsgError( lp->lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, LP_USER_ABORT_ERROR, NULL, NULL, 0L ) ;
+
+ /* falling through (no break) */
+
+ case ABORT_PROCESSED:
+ return_status = USER_ABORT ;
+ break ;
+
+ case ABORT_AT_EOM:
+ return_status = USER_ABORT ;
+ break ;
+ }
+
+ } while( !return_status &&
+ (curr_blk != NULL) &&
+ (lp->rr.tf_message != TRR_END ) ) ;
+
+ }
+
+ /* Log end of backup set */
+ LP_MsgEndBS( lp->lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos ) ;
+
+
+ /* Process last tape format request as long as no fatal error occurred */
+ if( ( return_status != SUCCESS ) && ( LP_GetAbortFlag( lp->lis_ptr ) != ABORT_AT_EOM ) ) {
+ lp->rr.lp_message = LRR_ABORT ;
+ if( ( return_status = TF_GetNextTapeRequest( &lp->rr ) ) != SUCCESS ) {
+ LP_MsgError( lp->lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, return_status, NULL, NULL, 0L ) ;
+ }
+ }
+ } else if ( return_status == TFLE_USER_ABORT ) {
+ LP_MsgError( lp->lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, LP_USER_ABORT_ERROR, NULL, NULL, 0L ) ;
+ }
+
+ /* Close set, save current tape device and post tape stats */
+ LP_CloseSet( pb.channel ) ;
+
+ }
+ else {
+ TF_CloseSet( lp->channel, NULL ) ;
+ if( return_status == TFLE_USER_ABORT ) {
+ LP_MsgError( lp->lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, LP_USER_ABORT_ERROR, NULL, NULL, 0L ) ;
+
+ } else if( return_status != TFLE_UI_HAPPY_ABORT ) {
+ LP_MsgError( lp->lis_ptr->pid, bsd_ptr, lp->curr_fsys, &lp->tpos, return_status, NULL, NULL, 0L ) ;
+ }
+ }
+
+ free( data_frag.buffer ) ;
+
+ return( return_status ) ;
+
+}
+
diff --git a/private/utils/ntbackup/src/very_obj.c b/private/utils/ntbackup/src/very_obj.c
new file mode 100644
index 000000000..6a68a1d92
--- /dev/null
+++ b/private/utils/ntbackup/src/very_obj.c
@@ -0,0 +1,494 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: very_obj.c
+
+ Description: contains routine to verify single object
+
+ $Log: N:\logfiles\very_obj.c_v $
+
+ Rev 1.27.1.0 26 Apr 1994 18:59:34 STEVEN
+fix dissconect bug
+
+ Rev 1.27 29 Jun 1993 16:16:08 BARRY
+Now can skip files at the time they're opened.
+
+ Rev 1.26 01 Jun 1993 16:19:58 STEVEN
+fix posix bugs
+
+ Rev 1.25 09 Mar 1993 12:29:08 STEVEN
+we need to break out of loop if an error occurs
+
+ Rev 1.24 09 Feb 1993 09:27:48 STEVEN
+parameters to macro were wrong.
+
+ Rev 1.23 20 Jan 1993 16:36:42 DON
+fixed bug in macro LP_MsgLogDifference for special IDB logic
+
+ Rev 1.22 14 Jan 1993 16:40:14 STEVEN
+fix bugs in last checkin
+
+ Rev 1.21 14 Jan 1993 13:34:04 STEVEN
+added stream_id to error message
+
+ Rev 1.20 04 Nov 1992 13:23:44 STEVEN
+fix various bugs with read
+
+ Rev 1.19 04 Nov 1992 09:29:08 STEVEN
+fix initial receive
+
+ Rev 1.18 03 Nov 1992 10:09:20 STEVEN
+change the way we skip data
+
+ Rev 1.17 28 Oct 1992 15:05:30 STEVEN
+very buffer is buffer size
+
+ Rev 1.16 05 Oct 1992 10:29:34 STEVEN
+remove TotalSize
+
+ Rev 1.15 16 Sep 1992 16:55:34 STEVEN
+added support for stream info struct for Tpfmt
+
+ Rev 1.14 01 Sep 1992 16:11:42 STEVEN
+added stream headers to fsys API
+
+ Rev 1.13 23 Jul 1992 13:16:52 STEVEN
+fix warnings
+
+ Rev 1.12 14 May 1992 12:40:48 TIMN
+Changed CHAR to INT8
+
+ Rev 1.11 05 May 1992 17:19:08 STEVEN
+fixed typos and misc bugs
+
+ Rev 1.10 16 Mar 1992 16:34:56 STEVEN
+more 64 bit support for format 40
+
+ Rev 1.9 13 Mar 1992 09:23:16 STEVEN
+4.0 tape format 64 bit
+
+ Rev 1.8 04 Feb 1992 10:35:56 DON
+if NOT defined FS_IMAGE then Images should be ignored
+
+ Rev 1.7 17 Jan 1992 17:42:18 STEVEN
+fix warnings for WIN32
+
+ Rev 1.6 11 Dec 1991 14:09:28 STEVEN
+read converted to FS_READ
+
+ Rev 1.5 27 Jun 1991 13:07:06 STEVEN
+removed unused parm to ReceiveData
+
+ Rev 1.4 21 Jun 1991 08:48:52 STEVEN
+new config unit
+
+ Rev 1.3 30 May 1991 09:11:40 STEVEN
+bsdu_err.h no longer exists
+
+ Rev 1.2 24 May 1991 13:19:16 STEVEN
+updates from BSDU redesign
+
+ Rev 1.1 15 May 1991 11:01:36 DAVIDH
+Initialized blk_size to clear Watcom compiler warning.
+
+
+ Rev 1.0 09 May 1991 13:38:54 HUNTER
+Initial revision.
+
+**/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "queues.h"
+#include "beconfig.h"
+#include "msassert.h"
+#include "tbe_defs.h"
+#include "tbe_err.h"
+#include "bsdu.h"
+#include "fsys.h"
+#include "datetime.h"
+#include "tflproto.h"
+#include "tfldefs.h"
+#include "loops.h"
+#include "loop_prv.h"
+#include "lis.h"
+#include "sleep.h"
+
+/* static dblk used for comparing dblk information */
+static DBLK disk_dblk ;
+
+/**/
+/**
+
+ Name: LP_VerifyOBJ()
+
+ Description: this routine verifies a single object
+
+ Modified: 5/24/1991 11:12:39
+
+ Returns: tape backup engine error
+
+ Notes: none
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 LP_VerifyOBJ(
+register LP_ENV_PTR lp, /* I - Loop Environment structure */
+DBLK_PTR tape_dblk_ptr, /* I - The object to verify */
+DATA_FRAGMENT_PTR frag_ptr ) /* I - Buffer to user for fragments */
+{
+ UINT64 amount_verified ;
+ UINT16 very_size ;
+ UINT16 blk_size = 0 ;
+ INT16 error = SUCCESS ;
+ FILE_HAND hdl ;
+ BOOLEAN info_different_flag ;
+ INT8_PTR tape_data_buf ;
+ INT16 buffer_used_size ;
+ UINT16 read_size ;
+ BSD_PTR bsd_ptr;
+ FSYS_HAND fsh ;
+ UINT32 pid ;
+ BE_CFG_PTR cfg ;
+ BOOLEAN math_status ;
+
+ fsh = lp->curr_fsys ;
+ bsd_ptr = lp->lis_ptr->curr_bsd_ptr ;
+ pid = lp->lis_ptr->pid ;
+
+ cfg = BSD_GetConfigData( bsd_ptr ) ;
+
+ amount_verified = U64_Init(0,0) ;
+
+#ifndef FS_IMAGE
+
+ if( FS_GetBlockType( tape_dblk_ptr ) == BT_IDB ) {
+ LP_SkipData( lp ) ;
+ LP_MsgBlockSkipped( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, lp->curr_ddb ) ;
+ LP_MsgBytesSkipped( pid, bsd_ptr, fsh, &lp->tpos, FS_GetDisplaySizeFromDBLK( fsh, tape_dblk_ptr ) ) ;
+ LP_FinishedOper( lp ) ;
+ return SUCCESS ;
+ }
+
+#endif
+
+ /* anything that's done is considered processed ... */
+ LP_MsgBlockProcessed( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr ) ;
+
+ disk_dblk = *tape_dblk_ptr ;
+
+ /* make sure the disk based DBLK is properly set for display purposes */
+ FS_GetObjInfo( fsh, &disk_dblk ) ;
+
+ /* if the current directory is invalid AND it is a file ... */
+ if( lp->ddb_create_error && FS_GetBlockType( tape_dblk_ptr ) == FDB_ID ) {
+
+ /* ... but skip the data and log it not found ... */
+ LP_SkipData( lp ) ;
+
+ LP_MsgBlkNotFound( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, lp->curr_ddb ) ;
+
+ LP_MsgBlockSkipped( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, lp->curr_ddb ) ;
+ LP_MsgBytesSkipped( pid, bsd_ptr, fsh, &lp->tpos, FS_GetDisplaySizeFromDBLK( fsh, tape_dblk_ptr ) ) ;
+
+ return SUCCESS ;
+
+ }
+
+ /* do a verify info on the object to compare dates, attributes, sizes, etc for mismatch */
+ error = FS_VerObjInfo( fsh, tape_dblk_ptr );
+ switch( error ) {
+
+ case SUCCESS:
+ info_different_flag = FALSE ;
+
+ /* if it is a directory ... */
+ if( FS_GetBlockType( tape_dblk_ptr ) == DDB_ID ) {
+ lp->ddb_create_error = SUCCESS ;
+ }
+ break ;
+
+ case FS_COMM_FAILURE:
+
+ LP_MsgCommFailure( pid,
+ bsd_ptr,
+ fsh,
+ &lp->tpos,
+ lp->curr_ddb,
+ tape_dblk_ptr,
+ 0L );
+
+ return (error) ;
+
+ case FS_INFO_DIFFERENT:
+ case FS_OS_ATTRIB_DIFFER:
+ info_different_flag = error ;
+
+ if( FS_GetBlockType( tape_dblk_ptr ) == DDB_ID ) {
+ lp->ddb_create_error = SUCCESS;
+ }
+ break ;
+
+ case FS_NO_MORE:
+ case FS_NOT_FOUND:
+ LP_MsgBlkNotFound( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, lp->curr_ddb ) ;
+
+ if( FS_GetBlockType( tape_dblk_ptr ) == DDB_ID ) {
+ lp->ddb_create_error = error ;
+ }
+
+ LP_MsgBlockSkipped( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, lp->curr_ddb ) ;
+ LP_MsgBytesSkipped( pid, bsd_ptr, fsh, &lp->tpos, FS_GetDisplaySizeFromDBLK( fsh, tape_dblk_ptr ) ) ;
+
+ case FS_SKIP_OBJECT:
+ /* skip the data and log it not found ... */
+ LP_SkipData( lp ) ;
+
+ return SUCCESS ;
+
+ case FS_DEVICE_ERROR:
+ case FS_ACCESS_DENIED:
+ default:
+ LP_MsgLogDifference( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, lp->curr_ddb, 0L, error ) ;
+ LP_MsgBlockSkipped( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, lp->curr_ddb ) ;
+ LP_MsgBytesSkipped( pid, bsd_ptr, fsh, &lp->tpos,
+ FS_GetDisplaySizeFromDBLK( fsh, tape_dblk_ptr ) ) ;
+
+ /* skip the data and log it inaccessable ... */
+ LP_SkipData( lp ) ;
+
+ return SUCCESS ;
+
+ }
+
+ /* special IDB logic */
+ if( FS_GetBlockType( tape_dblk_ptr ) == IDB_ID ) {
+ if( info_different_flag ) {
+ LP_MsgBlkDifferent( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, &disk_dblk, (info_different_flag == FS_OS_ATTRIB_DIFFER), error ) ;
+ LP_MsgLogDifference( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, lp->curr_ddb, 0L, LP_DATA_VERIFIED ) ;
+
+ /* skip the data and log it inaccessable ... */
+ LP_SkipData( lp ) ;
+
+ return SUCCESS ;
+
+ }
+ }
+
+ error = FS_OpenObj( fsh, &hdl, tape_dblk_ptr, FS_VERIFY ) ;
+
+ LP_MsgLogBlock( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr ) ;
+
+ if( error != SUCCESS ) {
+
+ /* skip the data and log it ... */
+ LP_SkipData( lp ) ;
+
+ if ( error == FS_COMM_FAILURE ) {
+ LP_MsgCommFailure( pid,
+ bsd_ptr,
+ fsh,
+ &lp->tpos,
+ lp->curr_ddb,
+ tape_dblk_ptr,
+ 0L );
+
+ return (error) ;
+
+ }
+
+ if ( error == FS_INCOMPATIBLE_OBJECT ) {
+ LP_MsgBlkNotFound( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, lp->curr_ddb ) ;
+
+ } else {
+ if ( error != FS_SKIP_OBJECT ) {
+
+ if( info_different_flag ) {
+ LP_MsgBlkDifferent( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, &disk_dblk, (info_different_flag == FS_OS_ATTRIB_DIFFER), error ) ;
+ }
+
+ LP_MsgLogDifference( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, lp->curr_ddb, 0L, error ) ;
+ LP_MsgBlockSkipped( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, lp->curr_ddb ) ;
+ LP_MsgBytesSkipped( pid, bsd_ptr, fsh, &lp->tpos, FS_GetDisplaySizeFromDBLK( fsh, tape_dblk_ptr ) ) ;
+ }
+ }
+
+ if( FS_GetBlockType( tape_dblk_ptr ) == IDB_ID ) {
+
+ LP_FinishedOper( lp ) ;
+ return( error ) ;
+
+ } else {
+ return SUCCESS ;
+
+ }
+
+ } else {
+
+ /* verify the object here */
+ if ( !lp->ignore_data_for_ddb ) {
+ buffer_used_size = lp->initial_tape_buf_used ;
+
+ /* get initial data */
+ if( ( error = LP_ReceiveData( lp, (UINT32)buffer_used_size ) ) != ABORT_OPERATION ) {
+ tape_data_buf = lp->rr.buff_ptr ;
+ very_size = lp->rr.buff_size ;
+ }
+ }
+
+ while( !lp->ignore_data_for_ddb && !error && lp->rr.tf_message == TRR_DATA ) {
+
+ read_size = very_size;
+#ifdef TDEMO
+ if ( (FAST_TDEMO & BEC_GetSpecialWord( cfg )) == 0 ) {
+ sleep( (UINT32) (very_size / 130) );
+ }
+ error = SUCCESS ;
+#else
+ error = FS_VerifyObj( hdl, lp->very_buff, tape_data_buf, &very_size, &blk_size, &lp->rr.stream ) ;
+#endif
+ amount_verified = U64_Add( amount_verified, U64_Init( very_size, 0 ), &math_status ) ;
+
+ if( error == FS_DONT_WANT_STREAM ) {
+ LP_SkipStream( lp ) ;
+ error = SUCCESS ;
+
+ } else if( error != SUCCESS ) {
+ LP_MsgBlkDifferent( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, &disk_dblk, FALSE, error ) ;
+ LP_MsgLogDifference( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, lp->curr_ddb,
+ lp->current_stream_id, error ) ;
+ LP_MsgBlockSkipped( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, lp->curr_ddb ) ;
+ LP_MsgBytesSkipped( pid, bsd_ptr, fsh, &lp->tpos, FS_GetDisplaySizeFromDBLK( fsh, tape_dblk_ptr ) ) ;
+
+ if( FS_GetBlockType( tape_dblk_ptr ) == IDB_ID ) {
+ LP_FinishedOper( lp ) ;
+ FS_CloseObj( hdl ) ;
+ return( SUCCESS ) ;
+
+ }
+
+ } else {
+ if( FS_GetBlockType( tape_dblk_ptr ) == IDB_ID ) {
+ /* let's lie about the number of bytes processed ( so that we can handle 2.5 images ) */
+ /* the msg handlers must know that we are lying */
+#ifdef TDEMO
+ LP_MsgBytesProcessed( pid, bsd_ptr, fsh, &lp->tpos, amount_verified ) ;
+#else
+ LP_MsgBytesProcessed( pid, bsd_ptr, fsh, &lp->tpos, U64_Init(FS_GetObjPosition( hdl ),0) ) ;
+#endif
+ } else {
+ LP_MsgBytesProcessed( pid, bsd_ptr, fsh, &lp->tpos, U64_Init(very_size, 0) ) ;
+ }
+
+ if ( tape_data_buf == lp->rr.buff_ptr ) { /* INT8 = UINT8, cast or change UINT8, Error??? TIMN */
+ buffer_used_size = very_size ;
+ }
+
+ if ( ( read_size != very_size ) &&
+ ( (UINT16)(read_size - very_size) < blk_size ) ) {
+
+ if ( frag_ptr->memory_allocated < blk_size ) {
+
+ free( frag_ptr->buffer ) ;
+
+ frag_ptr->buffer = calloc( 1, blk_size ) ;
+ if( frag_ptr->buffer == NULL ) {
+#ifndef TDEMO
+ FS_CloseObj( hdl ) ;
+#endif
+ LP_FinishedOper( lp ) ;
+ return OUT_OF_MEMORY ;
+ }
+
+ frag_ptr->memory_allocated = blk_size ;
+ }
+
+ frag_ptr->buffer_used = read_size - very_size ;
+ memcpy( frag_ptr->buffer, tape_data_buf + very_size,
+ frag_ptr->buffer_used ) ;
+ buffer_used_size = read_size ;
+ }
+ }
+
+ if ( !error ) {
+ /* get more data */
+ error = LP_ReceiveData( lp, (UINT32)buffer_used_size ) ;
+
+ if ( ( error != ABORT_OPERATION) && ( frag_ptr->buffer_used != 0 ) ) {
+
+ if ( lp->rr.buff_size < (UINT16)(blk_size - frag_ptr->buffer_used) ) {
+ memcpy( frag_ptr->buffer + frag_ptr->buffer_used, lp->rr.buff_ptr,
+ lp->rr.buff_size ) ;
+ frag_ptr->buffer_used += lp->rr.buff_size ;
+ buffer_used_size = lp->rr.buff_size ;
+ very_size = 0 ;
+
+ } else {
+ memcpy( frag_ptr->buffer + frag_ptr->buffer_used, lp->rr.buff_ptr,
+ blk_size - frag_ptr->buffer_used ) ;
+ tape_data_buf = frag_ptr->buffer ;
+ very_size = blk_size ;
+ buffer_used_size = blk_size - frag_ptr->buffer_used ;
+ frag_ptr->buffer_used = 0 ;
+ }
+
+ } else {
+ very_size = lp->rr.buff_size ;
+ tape_data_buf = lp->rr.buff_ptr ; /* INT8 = UINT8, cast or change UINT8, Error??? TIMN */
+ }
+ }
+
+ /* check for abort conditions */
+ switch( LP_GetAbortFlag( lp->lis_ptr ) ) {
+
+ case CONTINUE_PROCESSING:
+ break ;
+
+ case ABORT_CTRL_BREAK:
+ LP_MsgError( pid, bsd_ptr, fsh, &lp->tpos, LP_USER_ABORT_ERROR, NULL, NULL, 0L ) ;
+
+ /* falling through */
+
+ case ABORT_PROCESSED:
+ case ABORT_AT_EOM:
+ error = USER_ABORT ;
+ break ;
+ }
+ }
+
+ FS_CloseObj( hdl ) ;
+
+ }
+
+ if( ( error == SUCCESS ) && ( FS_GetBlockType( tape_dblk_ptr ) != IDB_ID ) ) {
+
+ if( info_different_flag ) {
+ LP_MsgBlkDifferent( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, &disk_dblk, (info_different_flag == FS_OS_ATTRIB_DIFFER), error ) ;
+ LP_MsgLogDifference( pid, bsd_ptr, fsh, &lp->tpos, tape_dblk_ptr, lp->curr_ddb, LP_DATA_VERIFIED, error ) ;
+ }
+
+ } else if( error == ABORT_OPERATION ) {
+
+ return( error ) ;
+
+ } else if( error != USER_ABORT ) {
+
+ /* skip the data but do not log it as skipped since the attempt to verify was performed */
+ LP_SkipData( lp ) ;
+
+ return SUCCESS ;
+
+ }
+
+ return( error ) ;
+
+}
+
+
diff --git a/private/utils/ntbackup/src/viewproc.c b/private/utils/ntbackup/src/viewproc.c
new file mode 100644
index 000000000..245c86b07
--- /dev/null
+++ b/private/utils/ntbackup/src/viewproc.c
@@ -0,0 +1,460 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+RCG
+
+ Name: viewproc.c
+
+ Description: This file contains the functions for processing messages
+ sent by Windows to a View class window.
+
+
+ The following routines are in this module:
+
+ WM_ViewWndProc
+
+ $Log: G:/UI/LOGFILES/VIEWPROC.C_V $
+
+ Rev 1.11 14 Jan 1993 16:22:38 DAVEV
+chg LPLONG to INT32_PTR
+
+ Rev 1.10 01 Nov 1992 16:10:06 DAVEV
+Unicode changes
+
+ Rev 1.9 14 Oct 1992 15:46:10 GLENN
+Added some.h
+
+ Rev 1.8 04 Oct 1992 19:41:30 DAVEV
+Unicode Awk pass
+
+ Rev 1.7 07 Jul 1992 15:41:46 MIKEP
+unicode changes
+
+ Rev 1.6 18 May 1992 09:00:50 MIKEP
+header
+
+ Rev 1.5 02 Apr 1992 16:25:18 ROBG
+Modified logic to change tabs to spaces on a view log file.
+
+ Rev 1.4 24 Mar 1992 10:36:02 ROBG
+Added logic to use system colors when displaying text.
+
+ Rev 1.3 12 Mar 1992 11:37:42 ROBG
+changed
+
+ Rev 1.2 10 Mar 1992 08:19:52 ROBG
+changed
+
+ Rev 1.1 09 Mar 1992 15:57:26 ROBG
+changed
+
+ Rev 1.0 09 Mar 1992 15:49:16 ROBG
+Initial Release
+
+
+
+/******************************************************************************
+
+ Name: WM_ViewWndProc()
+
+ Description: This function is called internally by Windows when events
+ occur relating to the log view MDI document windows.
+
+ Returns: NULL or a default message handler's return code.
+
+******************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+static VOID WM_SetUpScrolls ( HWND hWnd, DLM_LOGITEM_PTR pDlm ) ;
+
+
+WINRESULT APIENTRY WM_ViewWndProc (
+
+register HWND hWnd, // I - window handle of the list box
+ MSGID msg, // I - message
+register MP1 mp1, // I - another message parameter
+ MP2 mp2) // I - yet another message parameter
+
+{
+
+ PDS_WMINFO pInfoPtr ;
+ DLM_LOGITEM_PTR pDlm ;
+ HWND hParent ;
+
+
+
+ hParent = GetParent( hWnd ) ;
+
+ pInfoPtr = WM_GetInfoPtr( hWnd ) ;
+ pInfoPtr = WM_GetInfoPtr( hParent ) ;
+
+ if ( pInfoPtr ) {
+ pDlm = (DLM_LOGITEM_PTR) WMDS_GetAppInfo( pInfoPtr ) ;
+ }
+
+ // Both memory areas must exist.
+
+ if ( !pInfoPtr || !pDlm ) {
+ return DefWindowProc (hWnd, msg, mp1, mp2 ) ;
+ }
+
+ switch (msg) {
+
+ case WM_CREATE: { /* Begin of Block */
+
+ HDC hDC ;
+ TEXTMETRIC tm ;
+ HANDLE hSaveObject ;
+
+ hDC = GetDC ( hWnd ) ;
+
+ hSaveObject = SelectObject( hDC, L_GetFont( pDlm ) ) ;
+
+ GetTextMetrics (hDC, &tm) ;
+
+ L_SetCharWidth ( pDlm, tm.tmAveCharWidth ) ;
+ L_SetCharWidthCaps( pDlm, (tm.tmPitchAndFamily & 1 ? 3 : 2) * L_GetCharWidth( pDlm ) / 2 ) ;
+ L_SetCharHeight ( pDlm, tm.tmHeight + tm.tmExternalLeading ) ;
+
+ SelectObject( hDC, hSaveObject ) ;
+
+ ReleaseDC (hWnd, hDC ) ;
+
+ L_SetMaxWidth ( pDlm, L_GetMaxWidth( pDlm ) * 2 * L_GetCharWidth( pDlm ) ) ;
+
+ return(0) ;
+
+ } /* End of Block */
+
+
+ case WM_SIZE:
+
+ L_SetClientHeight( pDlm, HIWORD (mp2) ) ;
+ L_SetClientWidth ( pDlm , LOWORD (mp2) ) ;
+
+ WM_SetUpScrolls( hWnd, pDlm ) ;
+
+ return(0) ;
+
+
+ case WM_VSCROLL: { /* Begin of Block */
+
+ INT nVscrollInc ;
+
+ switch (mp1) {
+
+ case SB_TOP:
+ nVscrollInc = -L_GetVscrollPos( pDlm ) ;
+ break ;
+
+ case SB_BOTTOM:
+ nVscrollInc = L_GetVscrollMax( pDlm ) - L_GetVscrollPos( pDlm ) ;
+ break ;
+
+ case SB_LINEUP:
+ nVscrollInc = -1 ;
+ break ;
+
+ case SB_LINEDOWN:
+ nVscrollInc = 1 ;
+ break ;
+
+ case SB_PAGEUP:
+ nVscrollInc = min (-1, -(L_GetClientHeight( pDlm ) ) / L_GetCharHeight( pDlm ) ) ;
+ break ;
+
+ case SB_PAGEDOWN:
+ nVscrollInc = max (1, L_GetClientHeight ( pDlm ) / L_GetCharHeight( pDlm ) ) ;
+ break ;
+
+ case SB_THUMBTRACK:
+ nVscrollInc = LOWORD (mp2) - L_GetVscrollPos( pDlm ) ;
+ break ;
+
+ default:
+ nVscrollInc = 0 ;
+ }
+
+ if ( nVscrollInc = max (-L_GetVscrollPos( pDlm ),
+ min ( nVscrollInc, L_GetVscrollMax( pDlm ) - L_GetVscrollPos( pDlm )))) {
+
+ L_SetVscrollPos( pDlm , L_GetVscrollPos( pDlm) + nVscrollInc ) ;
+ ScrollWindow (hWnd, 0, -(L_GetCharHeight( pDlm )) * nVscrollInc, NULL, NULL) ;
+ SetScrollPos (hWnd, SB_VERT, L_GetVscrollPos( pDlm ), TRUE) ;
+ UpdateWindow (hWnd) ;
+ }
+
+ return (0) ;
+
+ } /* End of Block */
+
+
+
+ case WM_HSCROLL: { /* Begin of Block */
+
+ INT nHscrollInc ;
+
+ switch (mp1) {
+
+ case SB_LINEUP:
+ nHscrollInc = -1 ;
+ break ;
+
+ case SB_LINEDOWN:
+ nHscrollInc = 1 ;
+ break ;
+
+ case SB_PAGEUP:
+ nHscrollInc = -(L_GetCharWidth( pDlm ) );
+ break ;
+
+ case SB_PAGEDOWN:
+ nHscrollInc = L_GetCharWidth( pDlm ) ;
+ break ;
+
+ case SB_THUMBPOSITION:
+ nHscrollInc = LOWORD (mp2) - L_GetHscrollPos( pDlm ) ;
+ break ;
+
+ default:
+ nHscrollInc = 0 ;
+ }
+
+ if (nHscrollInc = max (-L_GetHscrollPos( pDlm ),
+ min (nHscrollInc, L_GetHscrollMax( pDlm ) - L_GetHscrollPos( pDlm )))) {
+
+ L_SetHscrollPos( pDlm, L_GetHscrollPos( pDlm) + nHscrollInc ) ;
+ ScrollWindow (hWnd, -(L_GetCharWidth( pDlm ) * nHscrollInc), 0, NULL, NULL) ;
+ SetScrollPos (hWnd, SB_HORZ, L_GetHscrollPos( pDlm ), TRUE) ;
+ }
+
+ return (0) ;
+
+ } /* End of Block */
+
+ case WM_KEYDOWN:
+
+ if ( HM_KeyDown ( hWnd, mp1 ) ) {
+ return(0) ;
+ }
+
+ switch (mp1) {
+
+ case VK_HOME:
+ SendMessage (hWnd, WM_VSCROLL, SB_TOP, 0L) ;
+ break ;
+
+ case VK_END:
+ SendMessage (hWnd, WM_VSCROLL, SB_BOTTOM, 0L) ;
+ break ;
+
+ case VK_PRIOR:
+ SendMessage (hWnd, WM_VSCROLL, SB_PAGEUP, 0L) ;
+ break ;
+
+ case VK_NEXT:
+ SendMessage (hWnd, WM_VSCROLL, SB_PAGEDOWN, 0L) ;
+ break ;
+
+ case VK_UP:
+ SendMessage (hWnd, WM_VSCROLL, SB_LINEUP, 0L) ;
+ break ;
+
+ case VK_DOWN:
+ SendMessage (hWnd, WM_VSCROLL, SB_LINEDOWN, 0L) ;
+ break ;
+
+ case VK_LEFT:
+ SendMessage (hWnd, WM_HSCROLL, SB_PAGEUP, 0L) ;
+ break ;
+
+ case VK_RIGHT:
+ SendMessage (hWnd, WM_HSCROLL, SB_PAGEDOWN, 0L) ;
+ break ;
+ }
+ return (0) ;
+
+
+ case WM_PAINT: { /* Begin Block */
+
+ HDC hDC ;
+ INT i ;
+ INT y ;
+ INT x ;
+ INT nPaintBeg ;
+ INT nPaintEnd ;
+ INT nBlock ;
+ INT nRec ;
+ INT32_PTR pBlock ;
+ HANDLE hSaveObject ;
+ PAINTSTRUCT ps ;
+ LPSTR pszBuffer ;
+ LPSTR pStr ;
+ CHAR szLineNo[ 30 ] ;
+ INT nOffset ;
+
+ L_SetFilePtr ( pDlm, UNI_fopen ( L_GetFileName( pDlm ), _O_RDONLY ) ) ;
+
+ if ( L_GetFilePtr( pDlm ) == NULL ) {
+
+ // Problem opening log file .
+
+ CHAR szFormat[ MAX_UI_RESOURCE_SIZE ] ;
+ CHAR szString[ MAX_UI_RESOURCE_SIZE ] ;
+
+ RSM_StringCopy( IDS_CANTOPEN, szFormat, MAX_UI_RESOURCE_LEN ) ;
+ wsprintf( szString, szFormat, L_GetFileName( pDlm ) );
+ WM_MsgBox( ID(IDS_LOGVIEWMINWINDOWNAME), szString,
+ (WORD)WMMB_OK, (WORD)WMMB_ICONINFORMATION ) ;
+ return( 0 ) ;
+ }
+
+
+ hDC = BeginPaint (hWnd, &ps) ;
+
+ nPaintBeg = max (0, L_GetVscrollPos( pDlm ) + ps.rcPaint.top / L_GetCharHeight( pDlm ) - 1) ;
+ nPaintEnd = min ( (INT) L_GetTrackMax( pDlm ),
+ L_GetVscrollPos( pDlm ) + ps.rcPaint.bottom / L_GetCharHeight( pDlm ) ) ;
+
+ L_SetPaintBeg( pDlm, nPaintBeg ) ;
+ L_SetPaintEnd( pDlm, nPaintEnd ) ;
+
+ // Set Font.
+
+ hSaveObject = SelectObject( hDC, L_GetFont( pDlm ) );
+
+ pszBuffer = L_GetBuffer( pDlm ) ;
+ nOffset = L_GetCharWidth( pDlm ) ;
+
+ SetBkColor ( hDC, gColorBackGnd ) ;
+ SetTextColor( hDC, gColorForeGnd ) ;
+
+ for (i = nPaintBeg ; i < nPaintEnd ; i++) {
+
+ x = L_GetCharWidth ( pDlm ) * (1 - L_GetHscrollPos( pDlm )) ;
+ y = L_GetCharHeight( pDlm ) * (1 - L_GetVscrollPos( pDlm ) + i) ;
+
+ if ( i < LOG_NUMHEADERLINES ) {
+
+ LOG_GetViewHdrLine( pDlm, i, pszBuffer ) ;
+
+ strcpy( szLineNo, TEXT(" ") ) ;
+ TextOut ( hDC, x, y, szLineNo, strlen( szLineNo ) ) ;
+ TextOut ( hDC, x+10*nOffset, y , pszBuffer, strlen( pszBuffer ) ) ;
+ continue ;
+ }
+
+ nBlock = i / L_GetRecsPerBlock( pDlm ) ;
+ nRec = i % L_GetRecsPerBlock( pDlm ) ;
+
+ pBlock = L_GetBlockPtr( pDlm, nBlock ) ;
+
+ fseek ( L_GetFilePtr( pDlm ),*(pBlock+nRec), SEEK_SET ) ;
+
+ fgets( pszBuffer, (L_GetMaxStringLen( pDlm )-1), L_GetFilePtr( pDlm ) ) ;
+
+ // Get rid of CR, new pages, and end-of-file markers.
+
+ if ( pStr = strrchr( pszBuffer, 0x0d )) *pStr = 0 ;
+ if ( pStr = strrchr( pszBuffer, 0x0c )) *pStr = TEXT(' ') ;
+ if ( pStr = strrchr( pszBuffer, 0x1a )) *pStr = TEXT(' ') ;
+
+ // Change all tabs to spaces
+
+ while ( pStr = strrchr( pszBuffer, 0x09 ) ) {
+ *pStr = TEXT(' ') ;
+ }
+
+ wsprintf(szLineNo, TEXT("%5d "), i+1-LOG_NUMHEADERLINES );
+
+ TextOut ( hDC, x, y, szLineNo, strlen( szLineNo ) ) ;
+
+ TextOut ( hDC, x+10*nOffset, y , pszBuffer, strlen( pszBuffer ) ) ;
+
+ }
+
+ SelectObject( hDC, hSaveObject ) ;
+
+ if ( L_GetFilePtr( pDlm ) ) {
+ fclose( L_GetFilePtr( pDlm ) ) ;
+ L_SetFilePtr( pDlm, NULL ) ;
+ }
+
+
+ EndPaint (hWnd, &ps) ;
+ return (0) ;
+
+ } /* End Block */
+
+ case WM_LBUTTONDOWN:
+
+ if ( HM_ContextLbuttonDown( hWnd, mp1, mp2 ) == TRUE ) {
+ return (0) ;
+ }
+
+ break ;
+
+ case WM_SETCURSOR: /* Begin of Block */
+
+ // In help mode it is necessary to reset the cursor in response
+ // to every WM_SETCURSOR message.Otherwise, by default, Windows
+ // will reset the cursor to that of the window class.
+
+ if ( HM_SetCursor( hWnd ) == TRUE ) {
+ return (0) ;
+ }
+ default :
+ break ;
+ }
+
+ return DefWindowProc (hWnd, msg, mp1, mp2) ;
+
+}
+
+
+
+
+static VOID WM_SetUpScrolls (
+
+HWND hWnd ,
+DLM_LOGITEM_PTR pDlm )
+
+{
+
+ L_SetHscrollMax( pDlm, max (0, 2 + (L_GetMaxWidth( pDlm ) - L_GetClientWidth( pDlm )) / L_GetCharWidth( pDlm ) ) );
+
+ // See if the parent window is maximized.
+
+ if ( WM_IsMaximized( GetParent( hWnd ) ) ) {
+
+ // Set Window to the left most position.
+
+ L_GetHscrollPos( pDlm ) = 0 ;
+
+ // Erase the background of the parent.
+
+ InvalidateRect( GetParent( hWnd), NULL, TRUE ) ;
+
+ }
+
+ L_SetHscrollPos( pDlm, min (L_GetHscrollPos( pDlm ), L_GetHscrollMax( pDlm ) ) ) ;
+
+ SetScrollRange (hWnd, SB_HORZ, 0, L_GetHscrollMax( pDlm ), FALSE) ;
+ SetScrollPos (hWnd, SB_HORZ, L_GetHscrollPos( pDlm ), TRUE) ;
+
+ // Vertical Settings
+
+ L_SetVscrollMax( pDlm , max (0, L_GetTrackMax( pDlm ) + 2 + LOG_NUMHEADERLINES - L_GetClientHeight( pDlm ) / L_GetCharHeight( pDlm ) ) ) ;
+ L_SetVscrollPos( pDlm , min (L_GetVscrollPos( pDlm ), L_GetVscrollMax( pDlm )) ) ;
+
+ SetScrollRange (hWnd, SB_VERT, 0, L_GetVscrollMax( pDlm ), FALSE) ;
+ SetScrollPos (hWnd, SB_VERT, L_GetVscrollPos( pDlm ), TRUE) ;
+
+}
+
+
diff --git a/private/utils/ntbackup/src/vlm_bset.c b/private/utils/ntbackup/src/vlm_bset.c
new file mode 100644
index 000000000..9f04aa21e
--- /dev/null
+++ b/private/utils/ntbackup/src/vlm_bset.c
@@ -0,0 +1,2797 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: VLM_BSET.C
+
+ Description:
+
+ This file contains most of the code for processing the BSETS
+ window and lists.
+
+ $Log: G:\UI\LOGFILES\VLM_BSET.C_V $
+
+ Rev 1.85.1.2 31 Jan 1994 17:01:02 Glenn
+Now setting UI catalog button when catalogging an unknown BSET.
+
+ Rev 1.85.1.1 08 Dec 1993 11:19:06 MikeP
+deep pathes and unicode support
+
+ Rev 1.85 29 Jul 1993 16:02:38 MIKEP
+support sms sets
+
+ Rev 1.84 19 Jul 1993 21:12:04 MIKEP
+support ecc sets
+
+ Rev 1.83 13 Jul 1993 10:19:40 MIKEP
+start fixing MAX_SIZE vs MAX_LEN problems
+
+ Rev 1.82 14 Jun 1993 21:00:22 MIKEP
+enable c++
+
+ Rev 1.81 04 Jun 1993 10:50:58 GLENN
+Now setting the focus to the runtime dialog after a real catalog.
+
+ Rev 1.80 24 May 1993 15:21:58 BARRY
+Unicode fixes.
+
+ Rev 1.79 23 May 1993 14:50:42 MIKEP
+Fix epr's 357-0315 and 357-341.
+
+ Rev 1.78 21 May 1993 13:44:28 GLENN
+Fixed hard coded text strings.
+
+ Rev 1.77 06 May 1993 13:52:50 MIKEP
+Fix size display of 0 byte sets. Not needed for nostraddamus
+but won't make any differenece if taken.
+
+ Rev 1.76 26 Apr 1993 08:52:16 MIKEP
+Add numerous changes to fully support the font case selection
+for various file system types. Also add refresh for tapes window
+and sorting of tapes window.
+
+ Rev 1.74 16 Apr 1993 13:53:28 MIKEP
+fix for 1K sets again
+
+ Rev 1.73 11 Apr 1993 13:03:40 MIKEP
+ fix display size for sets < 1K
+
+ Rev 1.72 05 Apr 1993 16:59:50 chrish
+Added one line "gbCurrentOperation = OPERATION_CATALOG" for CAYMAN NT.
+
+
+
+ Rev 1.71 17 Mar 1993 16:04:52 chrish
+Added one liner to set gbCurrentOperation flag where we are coming from.
+
+ Rev 1.70 17 Mar 1993 15:28:14 DARRYLP
+EPR fix for 357-0041, pretty text in display windows.
+
+ Rev 1.69 13 Mar 1993 18:41:00 MIKEP
+fix bset size display
+
+ Rev 1.68 10 Mar 1993 13:26:50 MIKEP
+fix to display set size
+
+ Rev 1.67 09 Mar 1993 11:34:04 MIKEP
+fix to display set #, if no set name
+
+ Rev 1.66 23 Feb 1993 12:42:48 ROBG
+Added "Cataloging the tape..." when double clicking on a save-set
+in Tapes Window.
+
+ Rev 1.65 20 Jan 1993 21:38:12 MIKEP
+floppy support
+
+ Rev 1.64 06 Jan 1993 10:52:16 MIKEP
+remove set size for msoft
+
+ Rev 1.62 14 Dec 1992 12:24:10 DAVEV
+Enabled for Unicode compile
+
+ Rev 1.61 24 Nov 1992 21:02:32 MIKEP
+fix bug with multitape set display
+
+ Rev 1.60 17 Nov 1992 20:00:56 MIKEP
+add unformat display
+
+ Rev 1.59 11 Nov 1992 16:35:16 DAVEV
+UNICODE: remove compile warnings
+
+ Rev 1.58 01 Nov 1992 16:10:30 DAVEV
+Unicode changes
+
+ Rev 1.57 20 Oct 1992 14:32:08 MIKEP
+changes for otc
+
+ Rev 1.56 12 Oct 1992 13:24:40 MIKEP
+cataloging a set fix
+
+ Rev 1.55 09 Oct 1992 13:30:34 MIKEP
+add daily copy backup type
+
+ Rev 1.54 09 Oct 1992 12:56:56 MIKEP
+catalog a set changes for NT
+
+ Rev 1.53 07 Oct 1992 15:02:24 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.52 04 Oct 1992 19:41:36 DAVEV
+Unicode Awk pass
+
+ Rev 1.51 02 Sep 1992 21:25:50 CHUCKB
+Added Mike P.'s changes from Microsoft, Part II.
+
+ Rev 1.50 17 Aug 1992 13:25:06 DAVEV
+MikeP's changes at Microsoft
+
+ Rev 1.49 04 Aug 1992 11:43:04 MIKEP
+chnage .. to /
+
+ Rev 1.48 03 Aug 1992 19:37:48 MIKEP
+multitape changes for NT
+
+ Rev 1.47 29 Jul 1992 09:42:14 MIKEP
+ChuckB checked in after NT warnings were fixed.
+
+ Rev 1.46 22 Jul 1992 10:18:00 MIKEP
+warning fixes
+
+ Rev 1.45 10 Jul 1992 08:34:56 JOHNWT
+more gas guage work
+
+ Rev 1.44 08 Jul 1992 15:35:04 STEVEN
+Unicode BE changes
+
+ Rev 1.43 30 Jun 1992 13:18:56 JOHNWT
+dynamically alloc stats
+
+ Rev 1.42 29 Jun 1992 10:43:42 JOHNWT
+added selected dir counts
+
+ Rev 1.41 19 Jun 1992 14:44:20 JOHNWT
+more gas
+
+ Rev 1.40 14 May 1992 18:06:00 MIKEP
+nt pass 2
+
+ Rev 1.39 11 May 1992 09:13:38 MIKEP
+64Bit support
+
+ Rev 1.38 06 May 1992 14:41:42 MIKEP
+unicode pass two
+
+ Rev 1.37 04 May 1992 13:38:58 MIKEP
+unicode pass 1
+
+ Rev 1.36 23 Apr 1992 09:47:12 MIKEP
+fix null poinmter access
+
+
+*****************************************************/
+
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+// the number of items displayed in the bsets window for each bset
+
+#ifndef OEM_MSOFT
+#define BSET_NUM_DISPLAY_ITEMS 10
+#else
+#define BSET_NUM_DISPLAY_ITEMS 9
+#endif
+
+
+// The max number of characters displayed for the kbytes in a set
+
+#define MAX_BSET_KBYTES_SIZE 20
+
+
+// Static local function prototypes.
+
+static BYTE VLM_BsetGetSelect( BSET_OBJECT_PTR );
+static VOID_PTR VLM_BsetSetTag( BSET_OBJECT_PTR, BYTE );
+static BYTE VLM_BsetGetTag( BSET_OBJECT_PTR );
+static USHORT VLM_BsetGetItemCount( Q_HEADER_PTR );
+static VOID_PTR VLM_BsetGetFirstItem( Q_HEADER_PTR );
+static VOID_PTR VLM_BsetGetPrevItem( BSET_OBJECT_PTR );
+static VOID_PTR VLM_BsetGetNextItem( BSET_OBJECT_PTR );
+static VOID_PTR VLM_BsetGetObjects( BSET_OBJECT_PTR );
+
+static BSET_OBJECT_PTR VLM_CreateBSET( INT, INT, INT, INT, INT, INT, INT, INT, INT, INT );
+static VOID VLM_SetBsetStringMaxValues( TAPE_OBJECT_PTR, BSET_OBJECT_PTR );
+static BOOLEAN VLM_SetBsetFlags( BSET_OBJECT_PTR, QTC_BSET_PTR, BOOLEAN, INT16 );
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+VOID VLM_FillInBSD( BSD_PTR bsd_ptr )
+{
+ BSET_OBJECT_PTR bset;
+ TAPE_OBJECT_PTR tape;
+ UINT32 tape_fid;
+ INT16 bset_num;
+
+ if ( bsd_ptr == NULL ) {
+ return;
+ }
+
+ tape_fid = BSD_GetTapeID( bsd_ptr );
+ bset_num = BSD_GetSetNum( bsd_ptr );
+
+ bset = NULL;
+ tape = VLM_GetFirstTAPE( );
+
+ while ( bset == NULL ) {
+
+ if ( tape->tape_fid == tape_fid ) {
+
+ bset = VLM_GetFirstBSET( &tape->bset_list );
+
+ while ( bset != NULL ) {
+
+ if ( bset->bset_num == bset_num ) {
+ break;
+ }
+
+ bset = VLM_GetNextBSET( bset );
+ }
+ }
+
+ if ( bset == NULL ) {
+ tape = VLM_GetNextTAPE( tape );
+ }
+
+ }
+
+ BSD_SetTapeLabel( bsd_ptr, (INT8_PTR)TAPE_GetName( tape ),
+ (INT16)strsize(TAPE_GetName( tape )) );
+ BSD_SetBackupLabel( bsd_ptr, (INT8_PTR)BSET_GetName( bset ),
+ (INT16)strsize(BSET_GetName(bset)) );
+ BSD_SetBackupDescript( bsd_ptr, (INT8_PTR)BSET_GetName( bset ),
+ (INT16)strsize(BSET_GetName(bset)) );
+ BSD_SetUserName( bsd_ptr, (INT8_PTR)BSET_GetUserName( bset ),
+ (INT16)strsize(BSET_GetUserName( bset )) );
+}
+
+
+
+/*********************
+
+ Name: VLM_FindBset
+
+ Description: Get the backup set.
+
+ Returns:
+
+**********************/
+
+BSET_OBJECT_PTR VLM_FindBset(
+UINT32 tape_fid, // I - tape fid
+INT16 bset_num ) // I - bset number
+{
+ TAPE_OBJECT_PTR tape;
+ BSET_OBJECT_PTR bset;
+
+ tape = VLM_GetFirstTAPE( );
+
+ while ( tape != NULL ) {
+
+ if ( TAPE_GetFID( tape ) == tape_fid ) {
+
+ bset = VLM_GetFirstBSET( &TAPE_GetBsetQueue( tape ) );
+
+ while ( bset != NULL ) {
+
+ if ( BSET_GetBsetNum( bset ) == bset_num ) {
+
+ return( bset ); // Return what they want
+ }
+
+ bset = VLM_GetNextBSET( bset );
+ }
+
+ }
+ tape = VLM_GetNextTAPE( tape );
+ }
+
+ return( NULL );
+}
+
+
+/*********************
+
+ Name: VLM_GetBsetName
+
+ Description: Get the name of a backup set.
+
+ Returns: Pointer to that name.
+
+**********************/
+
+CHAR_PTR VLM_GetBsetName(
+UINT32 tape_fid, // I - tape fid
+INT16 bset_num ) // I - bset number
+{
+ BSET_OBJECT_PTR bset;
+
+ bset = VLM_FindBset( tape_fid, bset_num );
+
+ if ( bset != NULL ) {
+ return( BSET_GetName( bset ) ); // Return what they want
+ }
+
+ return( NULL );
+}
+
+
+/*********************
+
+ Name: VLM_GetSortDate
+
+ Description: Get the date/time.
+
+ Returns: A pointer to the user name.
+
+**********************/
+
+
+VOID VLM_GetSortDate(
+UINT32 tape_fid, // I - tape fid
+INT16 bset_num, // I - bset number
+DATE_TIME_PTR sort_date )
+{
+ BSET_OBJECT_PTR bset;
+
+ bset = VLM_FindBset( tape_fid, bset_num );
+
+ if ( bset != NULL ) {
+ DateTimeDOS( bset->backup_date, bset->backup_time, sort_date );
+ }
+ else {
+ memset( sort_date, 0, sizeof( DATE_TIME ) );
+ }
+
+}
+
+
+/*********************
+
+ Name: VLM_GetUserName
+
+ Description: Get the user name string from a bset.
+
+ Returns: A pointer to the user name.
+
+**********************/
+
+
+CHAR_PTR VLM_GetUserName(
+UINT32 tape_fid, // I - tape fid
+INT16 bset_num ) // I - bset number
+{
+ BSET_OBJECT_PTR bset;
+
+ bset = VLM_FindBset( tape_fid, bset_num );
+
+ if ( bset != NULL ) {
+ return( BSET_GetUserName( bset ) );
+ }
+
+ return( NULL );
+}
+
+/*********************
+
+ Name: VLM_GetBackupDate
+
+ Description: Return the DOS format backup date.
+
+ Returns:
+
+**********************/
+
+UINT16 VLM_GetBackupDate(
+UINT32 tape_fid, // I - tape fid
+INT16 bset_num ) // I - bset number
+{
+ BSET_OBJECT_PTR bset;
+
+ bset = VLM_FindBset( tape_fid, bset_num );
+
+ if ( bset != NULL ) {
+ return( BSET_GetDate( bset ) );
+ }
+
+ return( (UINT16)0 );
+}
+
+
+
+/*********************
+
+ Name: VLM_GetBackupTime
+
+ Description: Return the DOS format backup time for a bset.
+
+ Returns:
+
+**********************/
+
+
+UINT16 VLM_GetBackupTime(
+UINT32 tape_fid, // I - tape fid
+INT16 bset_num ) // I - bset number
+{
+ BSET_OBJECT_PTR bset;
+
+ bset = VLM_FindBset( tape_fid, bset_num );
+
+ if ( bset != NULL ) {
+ return( BSET_GetTime( bset ) );
+ }
+
+ return( (UINT16)0 );
+}
+
+
+/*********************
+
+ Name: VLM_GetBackupType
+
+ Description: Return the backup type, defined in QTC.H
+
+ Returns:
+
+**********************/
+
+
+INT VLM_GetBackupType(
+UINT32 tape_fid, // I - tape fid
+INT16 bset_num ) // I - bset number
+{
+ BSET_OBJECT_PTR bset;
+
+ bset = VLM_FindBset( tape_fid, bset_num );
+
+ if ( bset != NULL ) {
+ return( BSET_GetBackupType( bset ) );
+ }
+
+ return( 0 );
+}
+
+
+
+/*********************
+
+ Name: VLM_RemoveBset
+
+ Description:
+
+ A backup set has been removed, through catalog maintenance or overwriting
+ a tape. This function is called to remove all references to the set from
+ the VLM area. It will close any windows that happen to be open from this
+ set, remove any BSD's, and call the search code to delete any references
+ to this set in the search results window.
+
+ Returns: Nothing.
+
+****************/
+
+VOID VLM_RemoveBset(
+UINT32 tape_fid, // I - the tape family id
+INT16 tape_num, // I - the tape number or -1
+INT16 bset_num,
+BOOLEAN UpdateScreen ) // I - the backup set number
+{
+ BSET_OBJECT_PTR bset;
+ TAPE_OBJECT_PTR tape;
+ BSET_OBJECT_PTR temp_bset;
+ TAPE_OBJECT_PTR temp_tape;
+ APPINFO_PTR appinfo;
+ WININFO_PTR wininfo;
+ BSD_PTR bsd;
+ APPINFO_PTR temp_appinfo;
+ WININFO_PTR temp_wininfo;
+ HWND win;
+
+
+ // Currently the UI does not support the removal of a single member
+ // of a tape family. When it does this param will be used.
+
+ DBG_UNREFERENCED_PARAMETER ( tape_num );
+
+ // See if tapes window has been created yet !
+
+ if ( gb_tapes_win == (HWND)NULL ) {
+ return;
+ }
+
+ wininfo = WM_GetInfoPtr( gb_tapes_win );
+ appinfo = (APPINFO_PTR)WM_GetAppPtr( gb_tapes_win );
+
+ tape = VLM_GetFirstTAPE( );
+
+ while ( tape != NULL ) {
+
+ if ( TAPE_GetFID( tape ) == tape_fid ) {
+ break;
+ }
+ tape = VLM_GetNextTAPE( tape );
+ }
+
+ if ( tape == NULL ) {
+ return;
+ }
+
+ bset = VLM_GetFirstBSET( &TAPE_GetBsetQueue( tape ) );
+
+ while ( bset != NULL ) {
+
+ if ( BSET_GetBsetNum( bset ) == bset_num ) {
+ break;
+ }
+ bset = VLM_GetNextBSET( bset );
+ }
+
+ if ( bset != NULL ) {
+
+ if ( appinfo->open_tape->tape_fid == tape_fid ) {
+
+ temp_bset = VLM_GetPrevBSET( bset );
+
+ if ( UpdateScreen ) {
+ DLM_Update( gb_tapes_win,
+ DLM_FLATLISTBOX,
+ WM_DLMDELETEITEMS,
+ (LMHANDLE)temp_bset, 1 );
+ }
+ }
+
+ RemoveQueueElem( &TAPE_GetBsetQueue( tape ), &(bset->q_elem) );
+ free( bset );
+ }
+
+ if ( QueueCount( &TAPE_GetBsetQueue( tape ) ) == 0 ) {
+
+ /*
+ Remove this tape since no bsets are left.
+ If this was the active tape change it here !
+ */
+
+ temp_tape = VLM_GetPrevTAPE( tape );
+
+ if ( UpdateScreen ) {
+ DLM_Update( gb_tapes_win,
+ DLM_TREELISTBOX,
+ WM_DLMDELETEITEMS,
+ (LMHANDLE)temp_tape, 0 );
+ }
+
+ RemoveQueueElem( WMDS_GetTreeList( wininfo ), &(tape->q_elem) );
+
+ if ( appinfo->open_tape == tape ) {
+
+ appinfo->open_tape = VLM_GetFirstTAPE( );
+
+ if ( appinfo->open_tape != NULL ) {
+
+ TAPE_SetStatus( appinfo->open_tape,
+ appinfo->open_tape->status | (UINT16)INFO_OPEN );
+ WMDS_SetFlatList( wininfo, &TAPE_GetBsetQueue( appinfo->open_tape ) );
+ }
+ else {
+ WMDS_SetFlatList( wininfo, NULL );
+ }
+ if ( UpdateScreen ) {
+ DLM_Update( gb_tapes_win,
+ DLM_FLATLISTBOX,
+ WM_DLMUPDATELIST,
+ (LMHANDLE)WMDS_GetFlatList( wininfo ), 0 );
+ }
+ }
+
+ free( tape );
+ }
+
+ // If any windows are open for this tape/bset then close them
+
+ win = WM_GetNext( (HWND)NULL );
+
+ while ( win != (HWND)NULL ) {
+
+ temp_wininfo = WM_GetInfoPtr( win );
+
+ if ( WMDS_GetWinType( temp_wininfo ) == WMTYPE_TAPETREE ) {
+
+ temp_appinfo = (APPINFO_PTR)WM_GetAppPtr( win );
+
+ if ( ( temp_appinfo->tape_fid == tape_fid ) &&
+ ( temp_appinfo->bset_num == bset_num ) ) {
+
+ WM_Destroy( win );
+ break;
+ }
+ }
+ win = WM_GetNext( win );
+ }
+
+ // Remove the bsd from the tape_bsd_list for this tape/bset
+
+ bsd = BSD_FindByTapeID( tape_bsd_list, tape_fid, bset_num );
+
+ if ( bsd != NULL ) {
+ BSD_Remove( bsd );
+ }
+
+ // Remove any search results entries from this bset.
+
+ VLM_SearchRemoveSet( tape_fid, bset_num );
+
+}
+
+
+/**********************
+
+ NAME : VLM_GetFirstBSET
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+BSET_OBJECT_PTR VLM_GetFirstBSET( Q_HEADER_PTR qhdr )
+{
+ Q_ELEM_PTR q_elem_ptr;
+
+ if ( qhdr == NULL ) {
+ return( NULL );
+ }
+
+ q_elem_ptr = QueueHead( qhdr );
+
+ if ( q_elem_ptr != NULL ) {
+ return( (BSET_OBJECT_PTR)q_elem_ptr->q_ptr );
+ }
+
+ return( NULL );
+}
+
+/**********************
+
+ NAME : VLM_GetLastBSET
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+BSET_OBJECT_PTR VLM_GetLastBSET( Q_HEADER_PTR qhdr )
+{
+ Q_ELEM_PTR q_elem_ptr;
+
+ if ( qhdr == NULL ) {
+ return( NULL );
+ }
+
+ q_elem_ptr = QueueTail( qhdr );
+
+ if ( q_elem_ptr != NULL ) {
+ return( (BSET_OBJECT_PTR)q_elem_ptr->q_ptr );
+ }
+
+ return( NULL );
+}
+
+/**********************
+
+ NAME : VLM_GetNextBSET
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+BSET_OBJECT_PTR VLM_GetNextBSET( BSET_OBJECT_PTR bset_ptr )
+{
+ Q_ELEM_PTR q_elem_ptr;
+
+ q_elem_ptr = QueueNext( &(bset_ptr->q_elem) );
+
+ if ( q_elem_ptr != NULL ) {
+ return( (BSET_OBJECT_PTR)q_elem_ptr->q_ptr );
+ }
+
+ return( NULL );
+}
+
+/**********************
+
+ NAME : VLM_GetPrevBSET
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+BSET_OBJECT_PTR VLM_GetPrevBSET( BSET_OBJECT_PTR bset_ptr )
+{
+ Q_ELEM_PTR q_elem_ptr;
+
+ q_elem_ptr = QueuePrev( &(bset_ptr->q_elem) );
+
+ if ( q_elem_ptr != NULL ) {
+ return( (BSET_OBJECT_PTR)q_elem_ptr->q_ptr );
+ }
+
+ return( NULL );
+}
+
+
+/**********************
+
+ NAME : VLM_SetBsetStringMaxValues
+
+ DESCRIPTION :
+
+ The bset passed in is the new one, if it doesn't change anything, then
+ don't change all the others.
+
+ RETURNS :
+
+**********************/
+
+static VOID VLM_SetBsetStringMaxValues(
+TAPE_OBJECT_PTR tape,
+BSET_OBJECT_PTR new_bset )
+{
+ BSET_OBJECT_PTR bset;
+ BOOLEAN change = FALSE;
+ UINT max_name = 0;
+ UINT max_user = 0;
+ UINT max_date = 0;
+ UINT max_time = 0;
+ UINT max_set = 0;
+ UINT max_volume = 0;
+ UINT max_tape = 0;
+ UINT max_kbytes = 0;
+
+ bset = VLM_GetFirstBSET( &tape->bset_list );
+
+ if ( QueueCount( &tape->bset_list ) != 1 ) {
+
+ // Just see what they are all currently set to.
+
+ while ( bset->bset_num == new_bset->bset_num ) {
+
+ bset = VLM_GetNextBSET( bset );
+ }
+
+ max_name = (UINT)bset->max_name;
+ max_user = (UINT)bset->max_user;
+ max_volume = (UINT)bset->max_volume;
+ max_date = (UINT)bset->max_date;
+ max_time = (UINT)bset->max_time;
+ max_set = (UINT)bset->max_set;
+ max_tape = (UINT)bset->max_tapes;
+ max_kbytes = (UINT)bset->max_kbytes;
+ }
+
+ if ( strlen( new_bset->name ) > max_name ) {
+ change = TRUE;
+ max_name = (UINT)strlen( new_bset->name );
+ }
+ if ( strlen( new_bset->user_name ) > max_user ) {
+ change = TRUE;
+ max_user = (UINT)strlen( new_bset->user_name );
+ }
+ if ( strlen( new_bset->volume_name ) > max_volume ) {
+ change = TRUE;
+ max_volume = (UINT)strlen( new_bset->volume_name );
+ }
+ if ( strlen( new_bset->date_str ) > max_date ) {
+ change = TRUE;
+ max_date = (UINT)strlen( new_bset->date_str );
+ }
+ if ( strlen( new_bset->time_str ) > max_time ) {
+ change = TRUE;
+ max_time = (UINT)strlen( new_bset->time_str );
+ }
+ if ( strlen( new_bset->bset_num_str ) > max_set ) {
+ change = TRUE;
+ max_set = (UINT)strlen( new_bset->bset_num_str );
+ }
+ if ( strlen( new_bset->tape_num_str ) > max_tape ) {
+ change = TRUE;
+ max_tape = (UINT)strlen( new_bset->tape_num_str );
+ }
+ if ( strlen( new_bset->kbytes_str ) > max_kbytes ) {
+ change = TRUE;
+ max_kbytes = (UINT)strlen( new_bset->kbytes_str );
+ }
+ // Note: For better looking listboxes, we will reset our spaces to
+ // 8 minimum for dates (MM-DD-YY(, and 11 for time (HH:MM:YY XM).
+
+ if (max_date < 8)
+ {
+ change = TRUE;
+ max_date = 8;
+ }
+ if (max_time < 11)
+ {
+ change = TRUE;
+ max_time = 11;
+ }
+ if (max_kbytes < 10)
+ {
+ change = TRUE;
+ max_kbytes = 10;
+ }
+ // Now we have the max sizes.
+
+ if ( change ) {
+
+ // Change the entire list.
+
+ bset = VLM_GetFirstBSET( &tape->bset_list );
+
+ while ( bset != NULL ) {
+
+ bset->max_name = (UINT16) max_name;
+ bset->max_user = (UINT16) max_user;
+ bset->max_volume = (UINT16) max_volume;
+ bset->max_date = (UINT16) max_date;
+ bset->max_time = (UINT16) max_time;
+ bset->max_set = (UINT16) max_set;
+ bset->max_tapes = (UINT16) max_tape;
+ bset->max_kbytes = (UINT16) max_kbytes;
+
+ bset = VLM_GetNextBSET( bset );
+ }
+ }
+ else {
+ // Now set just the new guy.
+
+ new_bset->max_name = (UINT16) max_name;
+ new_bset->max_user = (UINT16) max_user;
+ new_bset->max_volume = (UINT16) max_volume;
+ new_bset->max_date = (UINT16) max_date;
+ new_bset->max_time = (UINT16) max_time;
+ new_bset->max_set = (UINT16) max_set;
+ new_bset->max_tapes = (UINT16) max_tape;
+ new_bset->max_kbytes = (UINT16) max_kbytes;
+ }
+}
+
+
+
+INT VLM_InsertTapeInQueue(
+Q_HEADER_PTR tape_list,
+TAPE_OBJECT_PTR tape )
+{
+ TAPE_OBJECT_PTR temp;
+
+ if ( ( tape == NULL ) || ( tape_list == NULL ) ) {
+ return( FAILURE );
+ }
+
+ if ( QueueCount( tape_list ) == 0 ) {
+ EnQueueElem( tape_list, &(tape->q_elem), FALSE );
+ return( SUCCESS );
+ }
+
+ if ( tape->fake_tape ) {
+
+ // Blank or foriegn tape, or tape drive busy/empty.
+ // Put it at the end.
+ EnQueueElem( tape_list, &(tape->q_elem), FALSE );
+ }
+ else {
+
+ // Insert alphabetically
+
+ temp = VLM_GetFirstTAPE( );
+
+ while ( temp ) {
+
+ if ( stricmp( FLM_GetName( tape ),
+ FLM_GetName( temp ) ) < 0 ) {
+ break;
+ }
+ temp = VLM_GetNextTAPE( temp );
+ }
+
+ if ( temp == NULL ) {
+ InsertElem( tape_list, QueueTail( tape_list ), &(tape->q_elem), AFTER );
+ }
+ else {
+ InsertElem( tape_list, &(temp->q_elem), &(tape->q_elem), BEFORE );
+ }
+ }
+
+ return( SUCCESS );
+}
+
+
+
+/*********************
+
+ Name: VLM_AddBset
+
+ Description:
+
+ The catalogs have added a new backup set and they are calling the VLM
+ to annouce its birth. If the tape exists then it will be added to it,
+ otherwise the tape will be added first.
+
+ It is also possible that the bset has been recataloged and only its
+ attributes have changed.
+
+ A third possibility is that the catalogs are telling us about another
+ piece of this set that is on another tape, ie. it spanned tapes.
+
+**********************/
+
+VOID VLM_AddBset(
+UINT32 tape_fid, // I
+INT16 tape_seq_num, // I
+INT16 bset_num, // I
+VOID_PTR init_qtc, // I
+BOOLEAN UpdateScreen ) // I
+{
+ BSET_OBJECT_PTR bset;
+ BSET_OBJECT_PTR temp_bset;
+ TAPE_OBJECT_PTR tape;
+ QTC_BSET_PTR qtc;
+ QTC_HEADER_PTR header = NULL;
+ QTC_HEADER_PTR qtc_header = NULL;
+ QTC_TAPE_PTR qtc_tape;
+ QTC_BSET_PTR qtc_bset;
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ WININFO_PTR temp_wininfo;
+ APPINFO_PTR temp_appinfo;
+ INT16 last_seq_num;
+ UINT64 temp64;
+ UINT64 total64;
+ BOOLEAN u64_stat;
+ BOOLEAN changed = FALSE;
+ BOOLEAN ScreenNeedsUpdating = FALSE;
+ BOOLEAN make_new_tape_current = FALSE;
+ HWND win;
+ CHAR tape_name[ MAX_TAPE_NAME_SIZE ];
+ CHAR bset_name[ MAX_BSET_NAME_SIZE ];
+ CHAR tape_num_str[ MAX_BSET_NAME_SIZE ];
+ CHAR buffer[ VLM_BUFFER_SIZE ];
+ CHAR text[ MAX_UI_RESOURCE_SIZE ];
+ CHAR *unknown_kbytes_string = TEXT( " ?K" );
+ CHAR numeral[ MAX_UI_RESOURCE_SIZE ];
+
+
+ // The guy who called us had access to the actual qtc set pointer
+ // so he passed it to us to save look up time.
+
+ if ( init_qtc != NULL ) {
+ qtc = (QTC_BSET_PTR)init_qtc;
+ }
+ else {
+ qtc = QTC_FindBset( tape_fid, tape_seq_num, bset_num );
+ }
+
+ // Someone lied the set wasn't there.
+
+ if ( qtc == NULL ) {
+ return;
+ }
+
+ header = QTC_LoadHeader( qtc );
+ if ( header == NULL ) {
+ return;
+ }
+
+ wininfo = WM_GetInfoPtr( gb_tapes_win );
+ appinfo = (APPINFO_PTR)WM_GetAppPtr( gb_tapes_win );
+
+ // Look for the tape in our list
+
+ tape = VLM_GetFirstTAPE( );
+
+ while ( tape != NULL ) {
+
+ if ( tape->tape_fid == tape_fid ) {
+ break;
+ }
+ tape = VLM_GetNextTAPE( tape );
+ }
+
+ if ( tape == NULL ) {
+
+ // Add the tape first
+
+ if ( strlen( header->tape_name ) == 0 ) {
+
+ // Generate a tape name, must be DOS, OS/2 or NLM tape.
+
+ RSM_StringCopy( IDS_VLMTAPENAME, tape_name, MAX_TAPE_NAME_LEN );
+ }
+ else {
+ strncpy( tape_name, header->tape_name, MAX_TAPE_NAME_LEN );
+ tape_name[ MAX_TAPE_NAME_LEN ] = TEXT( '\0' );
+ }
+
+ tape = VLM_CreateTAPE( (INT16)((strlen( tape_name ) + 1) * sizeof(CHAR)) );
+ if ( tape == NULL ) {
+ return;
+ }
+
+ tape->tape_fid = tape_fid;
+ tape->tape_num = tape_seq_num;
+ tape->fake_tape = FALSE;
+ tape->status = INFO_DISPLAY;
+ tape->current = FALSE;
+ TAPE_SetXtraBytes( tape, wininfo );
+ TAPE_SetMultiTape( tape, FALSE );
+ TAPE_SetName( tape, tape_name );
+
+ if ( qtc->status & QTC_FLOPPY ) {
+ tape->status |= INFO_FLOPPY;
+ }
+
+ VLM_InsertTapeInQueue( WMDS_GetTreeList( wininfo ), tape );
+
+ // Add the new tape to the display.
+ if ( UpdateScreen ) {
+ DLM_Update( gb_tapes_win,
+ DLM_TREELISTBOX,
+ WM_DLMADDITEMS,
+ (LMHANDLE)VLM_GetPrevTAPE( tape ), 1 );
+ }
+
+ // See if he is the only tape or the current tape is a fake tape.
+
+ if ( QueueCount( WMDS_GetTreeList( wininfo ) ) == 1 ) {
+
+ make_new_tape_current = TRUE;
+ }
+ else {
+
+ if ( appinfo->open_tape != NULL ) {
+
+ if ( appinfo->open_tape->fake_tape ) {
+ make_new_tape_current = TRUE;
+ }
+ }
+ }
+
+ if ( make_new_tape_current ) {
+
+ // Make him the open tape.
+
+ appinfo->open_tape = VLM_GetFirstTAPE( );
+
+ appinfo->open_tape->status |= INFO_OPEN;
+ wininfo->pFlatList = &appinfo->open_tape->bset_list;
+
+ if ( UpdateScreen ) {
+ DLM_Update( gb_tapes_win, DLM_TREELISTBOX, WM_DLMUPDATEITEM,
+ (LMHANDLE)appinfo->open_tape, 0 );
+
+ DLM_SetAnchor( WMDS_GetWinTreeList( wininfo ),
+ 0,
+ (LMHANDLE)appinfo->open_tape );
+ }
+ }
+ }
+
+ // See if it's already in our list.
+
+ bset = VLM_GetLastBSET( &tape->bset_list );
+
+ if ( bset != NULL ) {
+
+ if ( bset->bset_num > bset_num ) {
+
+ bset = VLM_GetFirstBSET( &tape->bset_list );
+ }
+ }
+
+ temp_bset = bset;
+
+ // Look for the backup set in our list
+
+ while ( bset != NULL ) {
+
+ if ( bset->bset_num == bset_num ) {
+ break;
+ }
+
+ if ( bset->bset_num > bset_num ) {
+ bset = NULL;
+ break;
+ }
+
+ bset = VLM_GetNextBSET( bset );
+ temp_bset = bset;
+
+ }
+
+ do {
+
+ if ( header->tape_seq_num > 1 ) {
+ if ( ! TAPE_GetMultiTape( tape ) ) {
+ ScreenNeedsUpdating = TRUE;
+ }
+ TAPE_SetMultiTape( tape, TRUE );
+ }
+
+ if ( bset == NULL ) {
+
+ UI_IntToDate( buffer, (INT16)header->backup_date );
+ UI_IntToTime( &buffer[40], (UINT16)header->backup_time );
+
+ // Initialize with longest possible
+
+ RSM_StringCopy( IDS_VLMONTAPES, text, MAX_UI_RESOURCE_LEN );
+
+ sprintf( tape_num_str, text, 999, 999 );
+
+ // Add a new backup set
+
+ if ( ! strlen( header->bset_name ) ) {
+
+ RSM_StringCopy( IDS_VLMSETNUMBER, text, MAX_BSET_NAME_LEN );
+
+ sprintf( bset_name, text, bset_num );
+ }
+ else {
+ strncpy( bset_name, header->bset_name, MAX_BSET_NAME_LEN );
+ bset_name[ MAX_BSET_NAME_LEN ] = TEXT( '\0' );
+ }
+
+ bset = VLM_CreateBSET( (strlen( bset_name ) + 1) * sizeof(CHAR),
+ (INT16)header->user_name_size,
+ (INT16)header->volume_name_size,
+ (strlen( tape_num_str ) + 1 ) * sizeof(CHAR),
+ (strlen( buffer ) + 1) * sizeof(CHAR),
+ (strlen( &buffer[40] ) + 1) * sizeof(CHAR),
+ MAX_BSET_KBYTES_SIZE * sizeof(CHAR),
+ (INT16)max( header->tape_password_size,
+ header->bset_password_size),
+ header->OS_id,
+ header->OS_ver);
+
+ if ( bset == NULL ) {
+ return;
+ }
+
+ // Fill in the set name.
+
+ strcpy( bset->name, bset_name );
+
+ // Fill in size of the bset in kilobytes
+ // This doesn't handle crossing sets yet !
+
+ bset->total_bytes = U64_Init( header->num_bytes, header->num_bytes_msw );
+
+ U64_Litoa( bset->total_bytes, numeral, (INT16) 10, &u64_stat );
+
+ UI_BuildNumeralWithCommas( numeral );
+
+ if ( header->num_bytes_msw || header->num_bytes ) {
+
+
+ // Display a size for the set.
+
+ if ( strlen( numeral ) < 5 ) {
+ strcpy( numeral, TEXT( "1" ) );
+ }
+ else {
+ numeral[ strlen( numeral ) - 4 ] = TEXT( '\0' );
+ }
+
+ sprintf( bset->kbytes_str, TEXT( "%sK" ), numeral );
+
+ }
+ else {
+
+ if ( header->status & QTC_PARTIAL ) {
+ // We don't know how big it is.
+ strcpy( bset->kbytes_str, unknown_kbytes_string );
+ }
+ else {
+
+ // If its not partial and the byte count is really 0.
+ strcpy( bset->kbytes_str, TEXT( "0K" ) );
+ }
+ }
+
+ bset->status = INFO_DISPLAY;
+
+ BSET_SetBaseTape( bset, 0 );
+ BSET_SetFullMask( bset, 0 );
+ BSET_SetIncoMask( bset, 0 );
+ BSET_SetTapeMask( bset, 0 ); // Init for SetBsetFlags
+ BSET_SetNumTapes( bset, 0 );
+
+ VLM_SetBsetFlags( bset, qtc, FALSE, (INT16)0 );
+
+ msassert( bset->base_tape != 0 );
+
+ if ( header->OS_id == FS_NOV_SMS ) {
+ bset->status |= INFO_SMS;
+ }
+ if ( header->status & QTC_IMAGE ) {
+ bset->status |= INFO_IMAGE;
+ }
+ if ( header->status & QTC_FUTURE_VER ) {
+ }
+ if ( header->status & QTC_COMPRESSED ) {
+ bset->status |= INFO_COMPRESSED;
+ }
+ if ( header->status & QTC_ENCRYPTED ) {
+ bset->status |= INFO_ENCRYPTED;
+ }
+
+ bset->backup_time = (INT16)header->backup_time;
+ bset->backup_date = (INT16)header->backup_date;
+
+ if ( bset->num_tapes > 1 ) {
+ if ( ! TAPE_GetMultiTape( tape ) ) {
+ ScreenNeedsUpdating = TRUE;
+ }
+ TAPE_SetMultiTape( tape, TRUE );
+ RSM_StringCopy( IDS_VLMONTAPES, text, MAX_UI_RESOURCE_LEN );
+ sprintf( tape_num_str, text, bset->base_tape, bset->base_tape + bset->num_tapes - 1 );
+ }
+ else {
+ RSM_StringCopy( IDS_VLMONTAPE, text, MAX_UI_RESOURCE_LEN );
+ sprintf( tape_num_str, text, bset->base_tape );
+ }
+
+ BSET_SetTapeNumStr( bset, tape_num_str );
+ BSET_SetDateStr( bset, buffer );
+ BSET_SetTimeStr( bset, &buffer[40] );
+
+ RSM_StringCopy( IDS_VLMSETNUMBER, text, MAX_UI_RESOURCE_LEN );
+
+ sprintf( buffer, text, bset_num );
+ BSET_SetBsetNumStr( bset, buffer );
+
+ bset->backup_type = (UINT8)header->backup_type;
+
+ bset->num_files = (UINT32)header->num_files ;
+ bset->num_dirs = (UINT32)header->num_dirs ;
+ bset->num_corrupt = (UINT32)header->num_corrupt_files ;
+
+ // which password to use
+
+ bset->encrypt_algor = (UINT16)header->encrypt_algor;
+
+ if ( header->bset_password_size ) {
+ memcpy( bset->password,
+ header->bset_password,
+ (INT)header->bset_password_size );
+ bset->password_size = (INT16)header->bset_password_size;
+ bset->bset_password = TRUE;
+ }
+ else {
+ memcpy( bset->password,
+ header->tape_password,
+ (INT)header->tape_password_size);
+ bset->password_size = (INT16)header->tape_password_size;
+ bset->bset_password = FALSE;
+ }
+
+ bset->tape_fid = tape->tape_fid;
+ bset->bset_num = bset_num;
+
+ BSET_SetXtraBytes( bset, wininfo );
+
+ strcpy( bset->user_name, header->user_name );
+ strcpy( bset->volume_name, header->volume_name );
+
+ if ( QueueCount( &tape->bset_list ) == 0 ) {
+
+ EnQueueElem( &(tape->bset_list), &(bset->q_elem), FALSE );
+ }
+ else {
+ if ( temp_bset ) {
+ InsertElem( &tape->bset_list, &(temp_bset->q_elem), &(bset->q_elem), BEFORE );
+ }
+ else {
+ temp_bset = VLM_GetLastBSET( &tape->bset_list );
+ InsertElem( &tape->bset_list, &(temp_bset->q_elem), &(bset->q_elem), AFTER );
+ }
+ }
+
+ VLM_SetBsetStringMaxValues( tape, bset );
+
+ // See if its the active tape
+
+ if ( appinfo->open_tape != NULL ) {
+
+ if ( appinfo->open_tape->tape_fid == tape_fid ) {
+
+ if ( UpdateScreen ) {
+ DLM_Update( gb_tapes_win,
+ DLM_FLATLISTBOX,
+ WM_DLMADDITEMS,
+ (LMHANDLE)VLM_GetPrevBSET( bset ), 1 );
+
+ if ( QueueCount( &tape->bset_list ) == 1 ) {
+ DLM_SetAnchor( WMDS_GetWinFlatList( wininfo ),
+ 0,
+ (LMHANDLE)bset );
+ }
+ }
+ }
+ }
+ }
+ else {
+
+ // The "new" backup set is already in our list, so some attribute
+ // must have changed or hopefully we wouldn't have been called.
+ // Or we got another piece of it.
+
+
+ // First to handle the crossing set size problem. If it is
+ // a crossing set, then add up all the known pieces to get
+ // the set size.
+
+ if ( ( header->status & QTC_SPLIT ) ||
+ ( header->status & QTC_CONTINUATION ) ) {
+
+ total64 = U64_Init( 0L, 0L );
+
+ qtc_tape = QTC_GetFirstTape();
+
+ while ( qtc_tape != NULL ) {
+
+ if ( qtc_tape->tape_fid == tape_fid ) {
+
+ qtc_bset = QTC_GetFirstBset( qtc_tape );
+
+ while ( qtc_bset != NULL ) {
+
+ if ( qtc_bset->bset_num == header->bset_num ) {
+
+
+ qtc_header = QTC_LoadHeader( qtc_bset );
+
+ if ( qtc_header ) {
+
+ temp64 = U64_Init( qtc_header->num_bytes,
+ qtc_header->num_bytes_msw );
+
+ total64 = U64_Add( total64, temp64, &u64_stat );
+
+ free( qtc_header );
+ }
+ }
+
+ qtc_bset = QTC_GetNextBset( qtc_bset );
+ }
+
+ }
+
+ qtc_tape = QTC_GetNextTape( qtc_tape );
+ }
+
+
+ bset->total_bytes = total64;
+
+ }
+ else {
+
+ if ( ( U64_Msw( bset->total_bytes ) == 0L ) &&
+ ( U64_Lsw( bset->total_bytes ) == 0L ) ) {
+
+ // Fill in size of the bset in bytes.
+
+ bset->total_bytes = U64_Init( header->num_bytes, header->num_bytes_msw );
+ }
+
+ }
+
+
+ if ( bset->num_files != (INT32)header->num_files ) {
+ bset->num_files = (INT32)header->num_files ;
+ changed = TRUE ;
+ }
+
+ if ( bset->num_dirs != (INT32)header->num_dirs ) {
+ bset->num_dirs = (INT32)header->num_dirs ;
+ changed = TRUE ;
+ }
+
+ if ( bset->num_corrupt != (INT32)header->num_corrupt_files ) {
+ bset->num_corrupt = (INT32)header->num_corrupt_files ;
+ changed = TRUE ;
+ }
+
+ if ( VLM_SetBsetFlags( bset, qtc, FALSE, (INT16)0 ) == TRUE ) {
+ changed = TRUE;
+ }
+
+ if ( bset->num_tapes > 1 ) {
+ RSM_StringCopy( IDS_VLMONTAPES, text, MAX_UI_RESOURCE_LEN );
+ sprintf( tape_num_str, text, bset->base_tape, bset->base_tape + bset->num_tapes - 1 );
+ BSET_SetTapeNumStr( bset, tape_num_str );
+ }
+
+
+ // Display the correct set size string.
+
+
+ U64_Litoa( bset->total_bytes, numeral, (INT16) 10, &u64_stat );
+
+ UI_BuildNumeralWithCommas( numeral );
+
+ if ( U64_Lsw( bset->total_bytes ) || U64_Msw( bset->total_bytes ) ) {
+
+ if ( strlen( numeral ) < 5 ) {
+ strcpy( numeral, TEXT( "1K" ) );
+ }
+ else {
+
+ // truncate down to kilobytes.
+ numeral[ strlen( numeral ) - 4 ] = TEXT( '\0' );
+ }
+
+ sprintf( bset->kbytes_str, TEXT( "%sK" ), numeral );
+ }
+ else {
+
+ if ( header->status & QTC_PARTIAL ) {
+ strcpy( bset->kbytes_str, unknown_kbytes_string );
+ }
+ else {
+
+ // If its not partial and the byte count is really 0.
+ strcpy( bset->kbytes_str, TEXT( "0K" ) );
+ }
+
+ }
+
+ if ( header->OS_id == FS_NOV_SMS ) {
+ bset->status |= INFO_SMS;
+ }
+ if ( header->status & QTC_IMAGE ) {
+ bset->status |= INFO_IMAGE;
+ }
+ if ( header->status & QTC_FUTURE_VER ) {
+ }
+ if ( header->status & QTC_COMPRESSED ) {
+ bset->status |= INFO_COMPRESSED;
+ }
+ if ( header->status & QTC_ENCRYPTED ) {
+ bset->status |= INFO_ENCRYPTED;
+ }
+
+ VLM_SetBsetStringMaxValues( tape, bset );
+
+ // See if its the active tape
+
+ if ( ( appinfo->open_tape != NULL ) && ( changed == TRUE ) ) {
+
+ if ( appinfo->open_tape->tape_fid == tape_fid ) {
+
+ if ( UpdateScreen ){
+ DLM_Update( gb_tapes_win,
+ DLM_FLATLISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)bset, 0 );
+ }
+ }
+ }
+ }
+
+ last_seq_num = (INT16)header->tape_seq_num;
+
+ qtc = NULL;
+
+ if ( tape_seq_num == -1 ) {
+
+ // try for another one.
+
+ qtc = QTC_FindBset( tape_fid, (INT16)(last_seq_num + 1), bset_num );
+
+ if ( qtc ) {
+ free( header );
+ header = QTC_LoadHeader( qtc );
+ }
+ }
+
+ } while ( qtc != NULL && header != NULL );
+
+ free( header );
+
+ if ( ScreenNeedsUpdating ) {
+
+ // It's possible that we received this message because the bset was just
+ // converted from full cataloging to partial. If this is the case then
+ // we need to close the tree window for this bset, if its open.
+
+ if ( ! bset->full ) {
+
+ win = WM_GetNext( (HWND)NULL );
+
+ while ( win != (HWND)NULL ) {
+
+ temp_wininfo = WM_GetInfoPtr( win );
+
+ if ( temp_wininfo->wType == WMTYPE_TAPETREE ) {
+
+ temp_appinfo = (APPINFO_PTR)WM_GetAppPtr( win );
+
+ if ( ( temp_appinfo->tape_fid == tape_fid ) &&
+ ( temp_appinfo->bset_num == bset_num ) ) {
+
+ WM_Destroy( win );
+ break;
+ }
+ }
+ win = WM_GetNext( win );
+ }
+
+ }
+
+ // Update the check marks for the tape.
+
+ VLM_UpdateTapeStatus( tape, UpdateScreen );
+ }
+
+}
+
+
+/**********************
+
+ NAME : VLM_SetBsetFlags
+
+ DESCRIPTION :
+
+ We get sent the pieces of a bset, that spans tapes, one at a time, in
+ no particular order. We need to determine in this routine if we have
+ all the pieces of it. If we don't, we mark it as missing.
+ We are also required to keep track of knowing if all the parts
+ are fully cataloged or not.
+
+ NOTE:
+
+ The goal here is to set three flags correctly at all times for each set.
+ They are "incomplete", "missing", and "full".
+
+ full - "One or more pieces are fully or incompletely cataloged".
+
+ Incomplete - "One or more pieces are incompletely cataloged".
+
+ Missing - "One or more pieces are missing", ie. NOT in the catalogs.
+
+ To keep track of all this we use three arrays of 32 bits. The assumption
+ is that no ONE set will end up on more than 32 tapes. Each bit in the
+ arrays represents a tape in the family. BIT32 is the first tape the
+ set starts on and works to the right.
+
+ The three arrays:
+ tapes_mask - A bit is set if the tape is in the catalogs.
+ full_mask - A bit is set if the piece is fully cataloged.
+ inco_mask - A bit is set if the piece is cataloged, but not completely.
+
+ Now your thinking how do I know which bit to use for tape X. Good
+ question. Each set we get has the tape number its on and a type
+ designation.
+
+ The designation is one of:
+
+ NOTHING - This set is only on 1 tape.
+ SPLIT - This tape is the first part of a multi tape set.
+ CONTINUATION - This tape is the last part of a multi tape set.
+ SPLIT & CONTINUATION - This tape is a middle piece of at least a
+ three piece set.
+
+ In addition, in the bset we use what we think the starting tape of
+ a family is in 'base_tape' and the current guess about how many
+ tapes the set is on in 'num_tapes'. The first real tape we have
+ present is in tape_num.
+
+ So with all this information the work is in keeping all your bits
+ set correctly. And then setting the flags based on the bits.
+
+ NOTE TWO:
+
+ This code correct handles the removal of sets, and flag setting. But
+ the current UI doesn't designate which tape of a family was deleted
+ or overwritten. So if any part of a set goes away, the whole set
+ goes away for the duration of the session. It will reappear next time
+ if there are any parts of it left.
+
+ NOTE THREE:
+
+ Keep in mind that the same piece may be sent multiple times, with or
+ without changing.
+
+ RETURNS : TRUE if the status changed.
+
+**********************/
+
+static BOOLEAN VLM_SetBsetFlags(
+BSET_OBJECT_PTR bset, // I - the bset changing
+QTC_BSET_PTR qtc, // I - the new piece if an insertion
+BOOLEAN removal, // I - TRUE if a removal, not an insertion
+INT16 tape_seq_num ) // I - Valid only if removal is TRUE.
+{
+ BOOLEAN old_full;
+ BOOLEAN old_missing;
+ BOOLEAN old_incomplete;
+ UINT32 mask;
+ INT i;
+ INT shift;
+
+ // If its not FULL it's partial.
+ // If its FULL, it can also be "FULL INCOMPLETE" or "FULL MISSING",
+ // or "FULL INCOMPLETE MISSING".
+
+ old_full = BSET_GetFull( bset );
+ old_missing = BSET_GetMissing( bset );
+ old_incomplete = BSET_GetIncomplete( bset );
+
+ if ( removal ) {
+
+ // A set has been deleted.
+
+ mask = 0x80000000 >> ( tape_seq_num - bset->base_tape );
+
+ bset->full_mask &= ~mask;
+ bset->inco_mask &= ~mask;
+ bset->tape_mask &= ~mask;
+
+ }
+ else {
+
+ // Simple case first, doesn't cross tape.
+
+ if ( ! ( qtc->status & ( QTC_SPLIT | QTC_CONTINUATION ) ) ) {
+
+ BSET_SetBaseTape( bset, (INT16)qtc->tape_seq_num );
+ BSET_SetNumTapes( bset, 1 );
+ mask = 0x80000000;
+ }
+
+ // Last tape in multiple tape set.
+
+ if ( ! ( qtc->status & QTC_SPLIT ) &&
+ ( qtc->status & QTC_CONTINUATION ) ) {
+
+ if ( bset->tape_mask ) {
+
+ if ( ( bset->base_tape + bset->num_tapes - 1 ) != (INT)qtc->tape_seq_num ) {
+ bset->num_tapes += (INT16)qtc->tape_seq_num -
+ ( bset->base_tape + bset->num_tapes - 1 );
+ }
+
+ }
+ else {
+ bset->base_tape = (INT)qtc->tape_seq_num - (INT16)1;
+ bset->num_tapes = 2;
+ }
+
+ }
+
+ // First part in multiple tape set.
+
+ if ( ( qtc->status & QTC_SPLIT ) &&
+ ! ( qtc->status & QTC_CONTINUATION ) ) {
+
+ if ( bset->tape_mask ) {
+
+ if ( bset->base_tape != (INT)qtc->tape_seq_num ) {
+
+ shift = (INT)qtc->tape_seq_num - bset->base_tape;
+
+ // shift all arrays by 'shift' to the right
+
+ bset->full_mask >>= shift;
+ bset->tape_mask >>= shift;
+ bset->inco_mask >>= shift;
+
+ bset->num_tapes += shift;
+ }
+
+ }
+ else {
+ bset->base_tape = (INT16)qtc->tape_seq_num;
+ bset->num_tapes = 2;
+ }
+
+ }
+
+ // Middle set, not first or last.
+
+ if ( ( qtc->status & QTC_SPLIT ) &&
+ ( qtc->status & QTC_CONTINUATION ) ) {
+
+ if ( bset->tape_mask ) {
+
+ if ( (INT16)qtc->tape_seq_num <= bset->base_tape ) {
+
+ // shift everything right because the base is wrongly
+ // set it to high a tape number. And lower the base.
+
+ shift = bset->base_tape - (INT16)qtc->tape_seq_num + 1;
+
+ bset->full_mask >>= shift;
+ bset->tape_mask >>= shift;
+ bset->inco_mask >>= shift;
+
+ bset->num_tapes += shift;
+ bset->base_tape -= shift;
+ }
+ else {
+
+ if ( ( bset->base_tape + bset->num_tapes - 1 ) <= (INT16)qtc->tape_seq_num ) {
+
+ // It goes after the known end. Bump where the end is to a
+ // a higher number.
+
+ bset->num_tapes += (INT16)qtc->tape_seq_num - bset->base_tape + 2;
+ }
+ }
+ }
+ else {
+
+ bset->base_tape = (INT16)qtc->tape_seq_num - (INT16)1;
+ bset->num_tapes = 3;
+ }
+
+ }
+
+ mask = 0x80000000 >> ( qtc->tape_seq_num - bset->base_tape );
+
+ // Now we have determine the position in the array that this
+ // new item goes, 'mask'. Use mask to set the array flags
+ // correctly. Keep in mind this could be a repeat set, so
+ // clear any bits that shouldn't be set.
+
+ bset->tape_mask |= mask;
+
+ if ( ! ( qtc->status & QTC_PARTIAL ) ) {
+
+ if ( qtc->status & QTC_INCOMPLETE ) {
+ bset->inco_mask |= mask;
+ bset->full_mask &= ~mask;
+ }
+ else {
+ bset->full_mask |= mask;
+ bset->inco_mask &= ~mask;
+ }
+ }
+ else {
+ bset->full_mask &= ~mask;
+ bset->inco_mask &= ~mask;
+ }
+ }
+
+
+ // Now that all the array bits have been properly updated we can set
+ // the full, incomplete, and missing flags as they should be now.
+
+ if ( bset->full_mask || bset->inco_mask ) {
+ bset->full = TRUE;
+ }
+ else {
+ bset->full = FALSE;
+ }
+
+ // Now set incomplete and missing flags
+
+ bset->incomplete = FALSE;
+
+ bset->missing = FALSE;
+
+ mask = 0x80000000;
+
+ for ( i = 0; i < bset->num_tapes; i++ ) {
+
+ if ( ! ( bset->tape_mask & mask ) ) {
+ bset->missing = TRUE;
+ }
+ else {
+ if ( ! ( bset->full_mask & mask ) ) {
+ bset->incomplete = TRUE;
+ }
+ }
+
+ mask >>= 1;
+ }
+
+ // Set the tape_num to be the lowest numbered tape that is present.
+
+ bset->tape_num = bset->base_tape;
+ mask = 0x80000000;
+
+ for ( i = 0; i < 32; i++ ) {
+ if ( bset->tape_mask & mask ) {
+ break;
+ }
+ bset->tape_num++;
+ mask >>= 1;
+ }
+
+ if ( ( bset->missing != old_missing ) ||
+ ( bset->full != old_full ) ||
+ ( bset->incomplete != old_incomplete ) ) {
+
+ return( TRUE );
+ }
+
+ return( FALSE ); // If status changed
+}
+
+
+
+
+/**********************
+
+ NAME : VLM_CreateBSET
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static BSET_OBJECT_PTR VLM_CreateBSET(
+INT name_size,
+INT user_name_size,
+INT volume_name_size,
+INT tape_num_size,
+INT date_size,
+INT time_size,
+INT bytes_size,
+INT password_size,
+INT os_id,
+INT os_ver )
+{
+ BSET_OBJECT_PTR bset;
+
+ // sizes are in bytes
+
+ bset = (BSET_OBJECT_PTR)malloc( sizeof(BSET_OBJECT) + name_size +
+ user_name_size +
+ volume_name_size +
+ tape_num_size +
+ date_size +
+ time_size +
+ bytes_size +
+ password_size );
+
+ if ( bset != NULL ) {
+
+ bset->q_elem.q_ptr = bset;
+ bset->name = (CHAR_PTR)(((INT8_PTR)bset) + sizeof(BSET_OBJECT));
+ bset->user_name = bset->name + name_size / sizeof(CHAR);
+ bset->volume_name = bset->user_name + user_name_size / sizeof(CHAR);
+ bset->tape_num_str = bset->volume_name + volume_name_size / sizeof( CHAR );
+ bset->date_str = bset->tape_num_str + tape_num_size / sizeof(CHAR);
+ bset->time_str = bset->date_str + date_size / sizeof(CHAR);
+ bset->kbytes_str = bset->time_str + time_size / sizeof(CHAR);
+ bset->password = bset->kbytes_str + bytes_size / sizeof(CHAR);
+ bset->os_id = (INT)((INT16)os_id) ;
+ bset->os_ver = os_ver ;
+ }
+
+ return( bset );
+}
+
+/**********************
+
+ NAME : VLM_BsetFillInDLM
+
+ DESCRIPTION :
+
+ This window is actually created in the VLM_TAPE file, but by filling in
+ the DLM structure in this file, I can make all the callback functions
+ static.
+
+ RETURNS : nothing
+
+**********************/
+
+
+VOID VLM_BsetFillInDLM( VOID_PTR dlm )
+{
+ DLM_INIT *flat_dlm;
+
+ flat_dlm = (DLM_INIT *)dlm;
+
+ DLM_ListBoxType( flat_dlm, DLM_FLATLISTBOX );
+ DLM_Mode( flat_dlm, DLM_SINGLECOLUMN );
+ DLM_Display( flat_dlm, DLM_SMALL_BITMAPS );
+ DLM_DispHdr( flat_dlm, NULL );
+ DLM_TextFont( flat_dlm, DLM_SYSTEM_FONT );
+ DLM_GetItemCount( flat_dlm, VLM_BsetGetItemCount );
+ DLM_GetFirstItem( flat_dlm, VLM_BsetGetFirstItem );
+ DLM_GetNext( flat_dlm, VLM_BsetGetNextItem );
+ DLM_GetPrev( flat_dlm, VLM_BsetGetPrevItem );
+ DLM_GetTag( flat_dlm, VLM_BsetGetTag );
+ DLM_SetTag( flat_dlm, VLM_BsetSetTag );
+ DLM_GetSelect( flat_dlm, VLM_BsetGetSelect );
+ DLM_SetSelect( flat_dlm, VLM_BsetSetSelect );
+ DLM_GetObjects( flat_dlm, VLM_BsetGetObjects );
+ DLM_SetObjects( flat_dlm, VLM_BsetSetObjects );
+ DLM_SSetItemFocus( flat_dlm, NULL );
+ DLM_MaxNumObjects( flat_dlm, BSET_NUM_DISPLAY_ITEMS );
+}
+
+
+
+
+/**********************
+
+ NAME : VLM_SelectBsets
+
+ DESCRIPTION :
+
+ The user has tagged one or more backup sets and hit the
+ select or unselect button. This function does the processing for that
+ command.
+
+ RETURNS :
+
+**********************/
+
+
+VOID VLM_SelectBsets(
+BYTE attr ) // I - select or deselect ?
+{
+ BSET_OBJECT_PTR bset;
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+
+ wininfo = WM_GetInfoPtr( gb_tapes_win );
+ appinfo = (APPINFO_PTR)WM_GetAppPtr( gb_tapes_win );
+
+ if ( WM_IsFlatActive( wininfo ) ) {
+
+ // Have the display list manager update our tags for us.
+
+ DLM_UpdateTags( gb_tapes_win, DLM_FLATLISTBOX );
+
+ bset = VLM_GetFirstBSET( wininfo->pFlatList );
+
+ while ( bset != NULL ) {
+
+ if ( bset->status & INFO_TAGGED ) {
+
+ VLM_BsetSetSelect( bset, attr );
+ }
+ bset = VLM_GetNextBSET( bset );
+ }
+ }
+
+ if ( WM_IsTreeActive( wininfo ) ) {
+
+ if ( appinfo->open_tape ) {
+
+ VLM_TapeSetSelect( appinfo->open_tape, attr );
+ }
+ }
+
+}
+
+/**********************
+
+ NAME : VLM_BsetSetSelect
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+VOID_PTR VLM_BsetSetSelect( BSET_OBJECT_PTR bset, BYTE attr )
+{
+ TAPE_OBJECT_PTR tape;
+ APPINFO_PTR appinfo;
+ WININFO_PTR wininfo;
+ BSD_PTR bsd_ptr;
+ FSE_PTR fse_ptr;
+ HWND win;
+ INT16 error;
+ BOOL all_subdirs;
+ BE_CFG_PTR bec_config;
+ UINT16 status;
+ DATE_TIME sort_date;
+ SLM_OBJECT_PTR slm;
+ BOOLEAN open_win;
+ QTC_BSET_PTR qtc_bset;
+ QTC_HEADER_PTR header;
+ INT16 tape_num;
+ CHAR_PTR server_name;
+
+ gbCurrentOperation = OPERATION_CATALOG; // chs:04-05-93
+
+ // You can't select these bsets, no matter how hard you try.
+
+ if ( bset->status & (INFO_SMS|INFO_IMAGE|INFO_COMPRESSED|INFO_ENCRYPTED ) ) {
+ return( NULL );
+ }
+
+ // Check for password protected set.
+
+ if ( attr ) {
+ if ( PSWD_CheckForPassword( bset->tape_fid, bset->bset_num ) ) {
+ return( NULL );
+ }
+ }
+
+ all_subdirs = CDS_GetIncludeSubdirs( CDS_GetPerm() );
+
+ // we need to find this guys parent and mark him also
+
+ wininfo = WM_GetInfoPtr( bset->XtraBytes->hWnd );
+
+ if ( attr ) {
+ if ( all_subdirs ) {
+ status = INFO_SELECT;
+ }
+ else {
+ status = (INFO_PARTIAL|INFO_SELECT);
+ }
+ }
+ else {
+ status = 0;
+ }
+
+ if ( (UINT16)(bset->status & (UINT16)(INFO_PARTIAL|INFO_SELECT) ) != status ) {
+
+ bset->status &= ~(INFO_PARTIAL|INFO_SELECT);
+ bset->status |= status;
+
+ DLM_Update( gb_tapes_win, DLM_FLATLISTBOX, WM_DLMUPDATEITEM,
+ (LMHANDLE)bset, 0 );
+ }
+
+ // Add code to create FSE for this Bset
+
+ if ( attr ) {
+ error = BSD_CreatFSE( &fse_ptr, (INT16)INCLUDE,
+ (INT8_PTR)TEXT(""), (INT16) sizeof(CHAR),
+ (INT8_PTR)ALL_FILES, ALL_FILES_LENG,
+ (BOOLEAN)USE_WILD_CARD,
+ (BOOLEAN) all_subdirs );
+ }
+ else {
+ error = BSD_CreatFSE( &fse_ptr, (INT16) EXCLUDE,
+ (INT8_PTR)TEXT(""), (INT16) sizeof(CHAR),
+ (INT8_PTR)ALL_FILES, ALL_FILES_LENG,
+ (BOOLEAN) USE_WILD_CARD,
+ (BOOLEAN) TRUE );
+ }
+
+ if ( error ) {
+ return( NULL );
+ }
+
+ tape = VLM_GetFirstTAPE( );
+
+ while ( tape->tape_fid != bset->tape_fid ) {
+
+ tape = VLM_GetNextTAPE( tape );
+ }
+
+ bsd_ptr = BSD_FindByTapeID( tape_bsd_list,
+ bset->tape_fid, bset->bset_num );
+
+ if ( bsd_ptr == NULL ) {
+
+ bec_config = BEC_CloneConfig( CDS_GetPermBEC() );
+ BEC_UnLockConfig( bec_config );
+
+ DateTimeDOS( bset->backup_date, bset->backup_time, &sort_date );
+
+ BSD_Add( tape_bsd_list, &bsd_ptr, bec_config, NULL,
+ NULL, bset->tape_fid, bset->tape_num, bset->bset_num,
+ NULL, &sort_date );
+
+ if ( bsd_ptr ) {
+ BSD_SetOsId(bsd_ptr, bset->os_id) ;
+ BSD_SetOsVer(bsd_ptr, bset->os_ver) ;
+
+ server_name = bset->volume_name;
+ while ( *server_name ) server_name++;
+
+ while ( ( *server_name != TEXT( '\\' ) ) &&
+ ( server_name != bset->volume_name ) )
+ server_name--;
+
+ if ( server_name != bset->volume_name ) {
+
+ *server_name = TEXT( '\0' );
+
+ while ( ( *server_name != TEXT( '\\' ) ) &&
+ ( server_name != bset->volume_name ) )
+ server_name--;
+ if ( server_name != bset->volume_name ) {
+
+ server_name++;
+ }
+
+ BSD_SetVolumeLabel( bsd_ptr, server_name, (UINT16)strsize( server_name ) );
+
+ while ( *server_name ) server_name++;
+ *server_name = TEXT( '\\' );
+
+ } else {
+
+ BSD_SetVolumeLabel( bsd_ptr, server_name, (UINT16)strsize( server_name ) );
+ }
+ }
+
+ VLM_FillInBSD( bsd_ptr );
+ }
+
+ if ( bsd_ptr != NULL ) {
+ BSD_AddFSE( bsd_ptr, fse_ptr );
+ }
+
+ VLM_UpdateTapeStatus( tape, TRUE );
+
+ // see if we have an open window for the bset
+
+ open_win = FALSE;
+ win = WM_GetNext( (HWND)NULL );
+
+ while ( win != (HWND)NULL ) {
+
+ wininfo = WM_GetInfoPtr( win );
+
+ if ( WMDS_GetWinType( wininfo ) == WMTYPE_TAPETREE ) {
+
+ appinfo = (APPINFO_PTR)WM_GetAppPtr( win );
+
+ if ( ( appinfo->bset_num == bset->bset_num ) &&
+ ( appinfo->tape_fid == bset->tape_fid ) ) {
+
+ open_win = TRUE;
+
+ if ( attr ) {
+ VLM_SubdirListManager( win, SLM_SEL_ALL );
+ if ( bsd_ptr != NULL ) {
+ VLM_MatchSLMList( wininfo, bsd_ptr, FALSE );
+ }
+ }
+ else {
+ VLM_SubdirListManager( win, SLM_SEL_NONE );
+ VLM_DeselectAll( wininfo, FALSE );
+ }
+ break;
+ }
+ }
+
+ win = WM_GetNext( win );
+ }
+
+ // update search window selections
+
+ VLM_UpdateSearchSelections( bset->tape_fid, bset->bset_num );
+
+ return( NULL );
+}
+
+
+/**********************
+
+ NAME : VLM_BsetGetSelect
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static BYTE VLM_BsetGetSelect( BSET_OBJECT_PTR bset )
+{
+ if ( BSET_GetStatus( bset ) & INFO_SELECT ) {
+ return( 1 );
+ }
+ else {
+ return( 0 );
+ }
+}
+
+/**********************
+
+ NAME : VLM_BsetSetTag
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static VOID_PTR VLM_BsetSetTag( BSET_OBJECT_PTR bset, BYTE attr )
+{
+ if ( attr ) {
+ bset->status |= INFO_TAGGED;
+ }
+ else {
+ bset->status &= ~INFO_TAGGED;
+ }
+ return( NULL );
+}
+
+/**********************
+
+ NAME : VLM_BsetGetTag
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static BYTE VLM_BsetGetTag( BSET_OBJECT_PTR bset )
+{
+ if ( INFO_TAGGED & BSET_GetStatus( bset ) ) {
+ return( 1 );
+ }
+ return( 0 );
+}
+
+/**********************
+
+ NAME : VLM_BsetGetItemCount
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static USHORT VLM_BsetGetItemCount( Q_HEADER_PTR bset_list )
+{
+
+ if ( bset_list == NULL ) {
+ return( 0 );
+ }
+
+ return( QueueCount( bset_list ) );
+}
+
+/**********************
+
+ NAME : VLM_BsetGetFirstItem
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static VOID_PTR VLM_BsetGetFirstItem( Q_HEADER_PTR bset_list )
+{
+ if ( bset_list == NULL ) {
+ return( NULL );
+ }
+
+ return( (VOID_PTR)VLM_GetFirstBSET( bset_list) );
+}
+
+/**********************
+
+ NAME : VLM_BsetGetPrevItem
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static VOID_PTR VLM_BsetGetPrevItem( BSET_OBJECT_PTR bset )
+{
+ return( (VOID_PTR)VLM_GetPrevBSET( bset ) );
+}
+
+/**********************
+
+ NAME : VLM_BsetGetNextItem
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static VOID_PTR VLM_BsetGetNextItem( BSET_OBJECT_PTR bset )
+{
+ return( (VOID_PTR)VLM_GetNextBSET( bset ) );
+}
+
+/**********************
+
+ NAME : VLM_BsetGetObjects
+
+ DESCRIPTION :
+
+ For a given object get the information that needs to be displayed.
+
+ RETURNS :
+
+**********************/
+
+static VOID_PTR VLM_BsetGetObjects( BSET_OBJECT_PTR bset )
+{
+ BYTE item_num = 1;
+ BYTE_PTR memblk;
+ DLM_ITEM_PTR item;
+ WININFO_PTR wininfo;
+ CHAR text[ MAX_UI_RESOURCE_SIZE ];
+
+ /* malloc enough room to store info */
+
+ wininfo = WM_GetInfoPtr( gb_tapes_win );
+ memblk = (BYTE_PTR)DLM_GetObjectsBuffer( wininfo->hWndFlatList );
+
+ /* Store the number of items in the first two bytes. */
+
+ *memblk = BSET_NUM_DISPLAY_ITEMS;
+
+ /* Set up check box. */
+
+ item = (DLM_ITEM_PTR)( memblk + 6 );
+
+ DLM_ItemcbNum( item ) = item_num++;
+ DLM_ItembType( item ) = DLM_CHECKBOX;
+ if ( bset->status & INFO_SELECT ) {
+ DLM_ItemwId( item ) = IDRBM_SEL_ALL;
+ if ( bset->status & INFO_PARTIAL ) {
+ DLM_ItemwId( item ) = IDRBM_SEL_PART;
+ }
+ }
+ else {
+ DLM_ItemwId( item ) = IDRBM_SEL_NONE;
+ }
+ DLM_ItembMaxTextLen( item ) = 0;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+
+ item++;
+ DLM_ItemcbNum( item ) = item_num++;
+ DLM_ItembType( item ) = DLM_BITMAP;
+
+ switch ( bset->os_id ) {
+
+ case FS_EMS_MDB_ID:
+ if (bset->num_dirs == 0) {
+ DLM_ItemwId( item ) = IDRBM_EMS_MDBP;
+ } else if ( bset->num_corrupt == 0 ) {
+ DLM_ItemwId( item ) = IDRBM_EMS_MDB;
+ } else {
+ DLM_ItemwId( item ) = IDRBM_EMS_MDBX;
+ }
+ break;
+
+ case FS_EMS_DSA_ID:
+ if (bset->num_dirs == 0) {
+ DLM_ItemwId( item ) = IDRBM_EMS_DSAP;
+ } else if ( bset->num_corrupt == 0 ) {
+ DLM_ItemwId( item ) = IDRBM_EMS_DSA;
+ } else {
+ DLM_ItemwId( item ) = IDRBM_EMS_DSAX;
+ }
+ break;
+
+ default:
+ DLM_ItemwId( item ) = IDRBM_BSET;
+ if ( ! bset->full ) {
+ DLM_ItemwId( item ) = IDRBM_BSETPART;
+ }
+ }
+
+ // Don't display encrypted or compressed or newer version sets as full
+
+ if ( bset->status & (INFO_COMPRESSED | INFO_ENCRYPTED ) ) {
+
+ DLM_ItemwId( item ) = IDRBM_BSETPART;
+ }
+
+ if ( bset->status & INFO_IMAGE ) {
+ DLM_ItemwId( item ) = IDRBM_IMAGE;
+ }
+
+ DLM_ItembMaxTextLen( item ) = 0;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+
+ /* Set up the text string to be displayed. */
+
+ item++;
+ DLM_ItemcbNum( item ) = item_num++;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = (BYTE)bset->max_volume;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+ strcpy( (CHAR_PTR)DLM_ItemqszString( item ), (CHAR_PTR)bset->volume_name );
+
+
+ item++;
+ DLM_ItemcbNum( item ) = item_num++;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = (BYTE)bset->max_set;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+ strcpy( (CHAR_PTR)DLM_ItemqszString( item ), (CHAR_PTR)BSET_GetBsetNumStr( bset ) );
+
+ item++;
+ DLM_ItemcbNum( item ) = item_num++;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = (BYTE)bset->max_tapes;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+ strcpy( (CHAR_PTR)DLM_ItemqszString( item ), (CHAR_PTR)BSET_GetTapeNumStr( bset ) );
+
+ item++;
+ DLM_ItemcbNum( item ) = item_num++;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = 5;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+
+ if ( bset->backup_type == QTC_NORM_BACKUP ) {
+ RSM_StringCopy ( IDS_VLMNORM, text, MAX_UI_RESOURCE_LEN );
+ strcpy( (CHAR_PTR)DLM_ItemqszString( item ), text );
+ }
+ if ( bset->backup_type == QTC_DIFF_BACKUP ) {
+ RSM_StringCopy ( IDS_VLMDIFF, text, MAX_UI_RESOURCE_LEN );
+ strcpy( (CHAR_PTR)DLM_ItemqszString( item ), text );
+ }
+ if ( bset->backup_type == QTC_COPY_BACKUP ) {
+ RSM_StringCopy ( IDS_VLMCOPY, text, MAX_UI_RESOURCE_LEN );
+ strcpy( (CHAR_PTR)DLM_ItemqszString( item ), text );
+ }
+ if ( bset->backup_type == QTC_INCR_BACKUP ) {
+ RSM_StringCopy ( IDS_VLMINCR, text, MAX_UI_RESOURCE_LEN );
+ strcpy( (CHAR_PTR)DLM_ItemqszString( item ), text );
+ }
+ if ( bset->backup_type == QTC_DAIL_BACKUP ) {
+ RSM_StringCopy ( IDS_VLMDAILY, text, MAX_UI_RESOURCE_LEN );
+ strcpy( (CHAR_PTR)DLM_ItemqszString( item ), text );
+ }
+ if ( bset->status & INFO_IMAGE ) {
+ RSM_StringCopy ( IDS_VLMIMAGE, text, MAX_UI_RESOURCE_LEN );
+ strcpy( (CHAR_PTR)DLM_ItemqszString( item ), text );
+ }
+
+#ifndef OEM_MSOFT
+ item++;
+ DLM_ItemcbNum( item ) = item_num++;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItembTextMode( item ) = DLM_RIGHT_JUSTIFY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = (BYTE)bset->max_kbytes;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+ sprintf(text, TEXT("%10s"), (CHAR_PTR)bset->kbytes_str);
+ strcpy( (CHAR_PTR)DLM_ItemqszString( item ), (CHAR_PTR)text );
+#endif
+
+ item++;
+ DLM_ItemcbNum( item ) = item_num++;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItembTextMode( item ) = DLM_RIGHT_JUSTIFY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = (BYTE)bset->max_date;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+ sprintf(text, TEXT("%8s"), (CHAR_PTR)bset->date_str);
+ strcpy( (CHAR_PTR)DLM_ItemqszString( item ), (CHAR_PTR)text );
+
+ item++;
+ DLM_ItemcbNum( item ) = item_num++;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItembTextMode( item ) = DLM_RIGHT_JUSTIFY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = (BYTE)bset->max_time;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+ sprintf(text, TEXT("%11s"), (CHAR_PTR)bset->time_str);
+ strcpy( (CHAR_PTR)DLM_ItemqszString( item ), (CHAR_PTR)text );
+
+ item++;
+ DLM_ItemcbNum( item ) = item_num++;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = (BYTE)bset->max_name;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+ strcpy( (CHAR_PTR)DLM_ItemqszString( item ), (CHAR_PTR)bset->name );
+
+ return( memblk );
+}
+
+/**********************
+
+ NAME : VLM_BsetSetObjects
+
+ DESCRIPTION :
+
+ Handle that we got a click or a double click.
+
+ RETURNS :
+
+**********************/
+
+BOOLEAN VLM_BsetSetObjects(
+BSET_OBJECT_PTR bset,
+WORD operation,
+WORD ObjectNum )
+{
+ BOOLEAN found = FALSE;
+ HWND win;
+ BSET_OBJECT_PTR temp_bset;
+ APPINFO_PTR appinfo;
+ WININFO_PTR wininfo;
+ CHAR keyb_char;
+ CHAR title[ MAX_UI_RESOURCE_SIZE ];
+ CHAR text[ MAX_UI_RESOURCE_SIZE ];
+
+
+ gbCurrentOperation = OPERATION_CATALOG; // chs:03-16-93
+
+ if ( operation == WM_DLMCHAR ) {
+
+ keyb_char = (CHAR)ObjectNum;
+
+ keyb_char = (CHAR)toupper( keyb_char );
+
+ temp_bset = bset;
+
+ do {
+
+ temp_bset = VLM_GetNextBSET( temp_bset );
+
+ if ( temp_bset != NULL ) {
+
+ if ( keyb_char == (CHAR)toupper( *BSET_GetName( temp_bset ) ) ) {
+
+ DLM_SetAnchor( WMDS_GetWinFlatList( BSET_GetXtraBytes( temp_bset ) ),
+ 0,
+ (LMHANDLE)temp_bset );
+ return( TRUE );
+ }
+ }
+
+ } while ( temp_bset != NULL );
+
+ temp_bset = VLM_GetFirstBSET( WMDS_GetFlatList( BSET_GetXtraBytes( bset ) ) );
+
+ while ( temp_bset != NULL && temp_bset != bset ) {
+
+ if ( keyb_char == (CHAR)toupper( *BSET_GetName( temp_bset ) ) ) {
+
+ DLM_SetAnchor( WMDS_GetWinFlatList( BSET_GetXtraBytes( temp_bset ) ),
+ 0,
+ (LMHANDLE)temp_bset );
+ return( TRUE );
+ }
+
+ temp_bset = VLM_GetNextBSET( temp_bset );
+ }
+
+ DLM_SetAnchor( WMDS_GetWinFlatList( BSET_GetXtraBytes( bset ) ),
+ 0,
+ (LMHANDLE)bset );
+ }
+
+ if ( ( operation == WM_DLMDBCLK ) &&
+ ( ObjectNum >= 2 ) ) {
+
+#ifdef OEM_EMS
+ if ( ( bset->os_id == FS_EMS_MDB_ID ) ||
+ ( bset->os_id == FS_EMS_DSA_ID ) ) {
+
+ return TRUE;
+ }
+#endif
+
+ win = WM_GetNext( (HWND)NULL );
+
+ while ( win != (HWND)NULL ) {
+
+ wininfo = WM_GetInfoPtr( win );
+
+ if ( wininfo->wType == WMTYPE_TAPETREE ) {
+
+ appinfo = (APPINFO_PTR)WM_GetAppPtr( win );
+
+ if ( ( appinfo->bset_num == bset->bset_num ) &&
+ ( appinfo->tape_fid == bset->tape_fid ) ) {
+ found = TRUE;
+ WM_DocActivate( win );
+ break;
+ }
+ }
+
+ win = WM_GetNext( win );
+ }
+
+ if ( ! found ) {
+
+ if ( bset->status & INFO_IMAGE ) {
+
+ RSM_StringCopy( IDS_VLMCATWARNING, title, MAX_UI_RESOURCE_LEN );
+ RSM_StringCopy( IDS_VLMSETIMAGE, text, MAX_UI_RESOURCE_LEN );
+
+ WM_MsgBox( title,
+ text,
+ WMMB_OK,
+ WMMB_ICONEXCLAMATION );
+
+ return( FALSE );
+ }
+ if ( bset->status & INFO_COMPRESSED ) {
+
+ RSM_StringCopy( IDS_VLMCATWARNING, title, MAX_UI_RESOURCE_LEN );
+ RSM_StringCopy( IDS_VLMSETCOMPRESSED, text, MAX_UI_RESOURCE_LEN );
+
+ WM_MsgBox( title,
+ text,
+ WMMB_OK,
+ WMMB_ICONEXCLAMATION );
+
+ return( FALSE );
+ }
+ if ( bset->status & INFO_ENCRYPTED ) {
+
+ RSM_StringCopy( IDS_VLMCATWARNING, title, MAX_UI_RESOURCE_LEN );
+ RSM_StringCopy( IDS_VLMSETENCRYPT, text, MAX_UI_RESOURCE_LEN );
+
+ WM_MsgBox( title,
+ text,
+ WMMB_OK,
+ WMMB_ICONEXCLAMATION );
+
+ return( FALSE );
+ }
+ if ( bset->status & INFO_SMS ) {
+
+ RSM_StringCopy( IDS_VLMCATWARNING, title, MAX_UI_RESOURCE_LEN );
+ RSM_StringCopy( IDS_VLMSETSMS, text, MAX_UI_RESOURCE_LEN );
+
+ WM_MsgBox( title,
+ text,
+ WMMB_OK,
+ WMMB_ICONEXCLAMATION );
+
+ return( FALSE );
+ }
+
+ if ( PSWD_CheckForPassword( bset->tape_fid, bset->bset_num ) ) {
+ return( FALSE );
+ }
+
+ if ( ! bset->full ) {
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+ {
+
+ RSM_StringCopy( IDS_VLMCATWARNING, title, MAX_UI_RESOURCE_LEN );
+ RSM_StringCopy( IDS_VLMSETPARTIAL, text, MAX_UI_RESOURCE_LEN );
+
+ if ( WM_MsgBox( title,
+ text,
+ WMMB_OKCANCEL,
+ WMMB_ICONQUESTION ) != WMMB_IDOK ) {
+
+ return( FALSE );
+ }
+
+ if ( ! MUI_DisableOperations( IDM_OPERATIONSCATALOG ) ) {
+
+ if ( ! HWC_TapeHWProblem( bsd_list ) ) {
+
+ do_catalog( bset->tape_fid,
+ bset->tape_num,
+ bset->bset_num );
+
+ VLM_CatalogSync( VLM_SYNCMORE );
+ }
+
+ MUI_EnableOperations( IDM_OPERATIONSCATALOG );
+ }
+
+
+ }
+# else
+ {
+
+ if ( ! MUI_DisableOperations( IDM_OPERATIONSCATALOG ) ) {
+
+ if ( ! HWC_TapeHWProblem( bsd_list ) ) {
+
+ // WM_ShowWaitCursor( TRUE );
+ STM_SetIdleText( IDS_CATALOGING );
+ VLM_CatalogSet( bset->tape_fid,
+ bset->tape_num,
+ bset->bset_num );
+ STM_SetIdleText( IDS_READY );
+ // WM_ShowWaitCursor( FALSE );
+
+ }
+
+ MUI_EnableOperations( 0 );
+ }
+
+ }
+# endif // !defined ( OEM_MSOFT ) // unsupported feature
+
+ if ( bset->full ) {
+
+ WM_ShowWaitCursor( TRUE );
+
+ VLM_SubdirListCreate( (GENERIC_DLE_PTR)NULL,
+ bset->tape_fid,
+ bset->bset_num,
+ bset->tape_num,
+ gb_tapes_win );
+
+ WM_ShowWaitCursor( FALSE );
+ }
+
+ }
+ else {
+
+ if ( bset->incomplete || bset->missing ) {
+
+ RSM_StringCopy( IDS_VLMCATWARNING, title, MAX_UI_RESOURCE_LEN );
+ RSM_StringCopy( IDS_VLMSETINCOMPLETE, text, MAX_UI_RESOURCE_LEN );
+
+ WM_MsgBox( title,
+ text,
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ }
+
+ WM_ShowWaitCursor( TRUE );
+
+ VLM_SubdirListCreate( (GENERIC_DLE_PTR)NULL,
+ bset->tape_fid,
+ bset->bset_num,
+ bset->tape_num,
+ gb_tapes_win );
+
+ WM_ShowWaitCursor( FALSE );
+ }
+
+ if ( IsWindow ( ghModelessDialog ) ) {
+ SetFocus ( ghModelessDialog );
+ }
+ }
+ }
+
+ return( FALSE );
+}
diff --git a/private/utils/ntbackup/src/vlm_cat.c b/private/utils/ntbackup/src/vlm_cat.c
new file mode 100644
index 000000000..41fdc3aeb
--- /dev/null
+++ b/private/utils/ntbackup/src/vlm_cat.c
@@ -0,0 +1,571 @@
+
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: VLM_CAT.C
+
+ Description:
+
+ VLM's interface to the catalogs.
+
+
+ $Log: G:\ui\logfiles\vlm_cat.c_v $
+
+ Rev 1.40.1.1 16 Jun 1994 15:30:06 STEVEN
+return if wondow not present
+
+ Rev 1.40.1.0 08 Dec 1993 11:26:50 MikeP
+deep pathes and unicode
+
+ Rev 1.40 03 Aug 1993 17:52:16 BARRY
+Don't sort the BSD that's added for the catalog -- it should always be last.
+
+ Rev 1.39 27 Jul 1993 12:41:46 MARINA
+enable c++
+
+ Rev 1.38 07 Jun 1993 08:11:12 MIKEP
+fix warnings due to typo.
+
+ Rev 1.37 15 May 1993 13:47:12 MIKEP
+Change to code to fix bug in cayman when changing catalog data path live.
+
+ Rev 1.36 02 May 1993 17:36:38 MIKEP
+add call to support catalog data path changing.
+
+ Rev 1.35 26 Apr 1993 08:51:08 MIKEP
+Add numerous changes to fully support the font case selection
+for various file system types. Also add refresh for tapes window
+and sorting of tapes window.
+
+ Rev 1.34 26 Jan 1993 17:18:20 MIKEP
+change to .D?? catalog names
+
+
+*****************************************************/
+
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+
+static INT VLM_CatalogSyncLess( VOID );
+static INT VLM_CatalogSyncMore( VOID );
+
+/***************************
+
+ The user through the ever more powerful features we provide has
+ dynamicly changed the catalog data path while the app is running.
+ We need to shutdown the old catalogs and then start up new ones.
+
+****************************/
+
+
+INT VLM_CatalogDataPathChanged( )
+{
+
+ // Shutdown the old catalo unit.
+
+ QTC_Deinit( (INT) FALSE );
+
+ // Init a new one.
+
+ QTC_Init( CDS_GetCatDataPath(), NULL );
+
+ // Now have the VLM area see what files are lying in
+ // the current catalog directory.
+
+ VLM_LookForCatalogFiles( );
+
+ // Add tape in the drive to new data location
+
+ if ( VLM_GetDriveStatus( NULL ) == VLM_VALID_TAPE ) {
+ VLM_AddTapeIfUnknown( FALSE );
+ }
+
+ // Align the VLM and QTC queues. And update screen.
+
+ VLM_CatalogSync( VLM_SYNCMORE|VLM_SYNCLESS );
+
+ return( SUCCESS );
+}
+
+
+/************************
+
+ The user wishes to fully catalog a single set.
+
+ Call do_catalog with the right parameters and then sync the windows.
+
+*************************/
+
+
+INT VLM_CatalogSet(
+UINT32 tape_fid,
+INT16 tape_num,
+INT16 bset_num )
+{
+
+ do_catalog( tape_fid,
+ tape_num,
+ bset_num );
+
+ VLM_CatalogSync( VLM_SYNCMORE );
+
+ return( SUCCESS );
+}
+
+
+
+/**********************
+
+ NAME : VLM_LookForCatalogFiles
+
+ DESCRIPTION :
+
+ Used at startup time to go out and look for any catalog files that we
+ need to read in.
+
+ RETURNS :
+
+**********************/
+
+VOID VLM_LookForCatalogFiles( )
+{
+ VLM_FIND_PTR vlm_find = NULL;
+ CHAR *path;
+ CHAR file[ VLM_MAXFNAME ];
+
+ path = malloc( strsize( CDS_GetCatDataPath() ) + 256 );
+
+ if ( path ) {
+#ifndef UNICODE
+ sprintf( path, TEXT("%s????????.D??"), CDS_GetCatDataPath() );
+#else //UNICODE
+ sprintf( path, TEXT("%s????????.U??"), CDS_GetCatDataPath() );
+#endif //UNICODE
+
+ vlm_find = VLM_FindFirst( path, VLMFIND_NORMAL, file );
+
+ if ( vlm_find != NULL ) {
+
+ do {
+
+ QTC_LoadBsetInfo( file, NULL );
+
+ } while ( VLM_FindNext( vlm_find, file ) );
+ }
+
+ VLM_FindClose( &vlm_find );
+ free( path );
+ }
+}
+
+
+
+
+/*
+ A catalog operation has occurred which could have changed the known tapes
+ and bsets lists. So we need to update the VLM's list of tapes and bsets
+ to match the catalog's list.
+*/
+
+VOID VLM_CatalogSync( INT msg )
+{
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ INT16 tape_seq_num;
+
+ // This code takes advantage of the fact that only whole tapes go
+ // away. By erase or a replace operation.
+
+ if ( msg & VLM_SYNCLESS ) {
+
+ // Operation could have removed stuff from the catalogs.
+
+ VLM_CatalogSyncLess();
+ }
+
+ if ( msg & VLM_SYNCMORE ) {
+
+ // Operation could have added stuff to the catalogs.
+
+ VLM_CatalogSyncMore();
+ }
+
+ // Completely update both lists.
+
+ if ( !IsWindow(gb_tapes_win) ) {
+ return ;
+ }
+ wininfo = WM_GetInfoPtr( gb_tapes_win );
+ appinfo = (APPINFO_PTR)WM_GetAppPtr( gb_tapes_win );
+
+ DLM_Update( gb_tapes_win,
+ DLM_TREELISTBOX,
+ WM_DLMUPDATELIST,
+ (LMHANDLE)wininfo->pTreeList, 0 );
+
+ DLM_Update( gb_tapes_win,
+ DLM_FLATLISTBOX,
+ WM_DLMUPDATELIST,
+ (LMHANDLE)wininfo->pFlatList, 0 );
+
+ // Set the anchor item.
+
+ DLM_SetAnchor( WMDS_GetWinTreeList( wininfo ),
+ 0,
+ (LMHANDLE)appinfo->open_tape );
+ return;
+}
+
+
+
+
+static INT VLM_CatalogSyncLess( )
+{
+ QTC_BSET_PTR qtc_bset;
+ TAPE_OBJECT_PTR vlm_tape;
+ BSET_OBJECT_PTR vlm_bset;
+ BSET_OBJECT_PTR temp_bset;
+
+ // Get rid of any tapes/bsets that no longer exist in the QTC.
+
+ vlm_tape = VLM_GetFirstTAPE( );
+
+ while ( vlm_tape != NULL ) {
+
+ qtc_bset = QTC_FindBset( vlm_tape->tape_fid, (INT16)-1, (INT16)-1 );
+
+ if ( qtc_bset == NULL && ! TAPE_GetFake( vlm_tape ) ) {
+
+ // NO bsets found for this whole tape, so yank it.
+
+ VLM_RemoveTape( vlm_tape->tape_fid, (INT16)-1, FALSE );
+
+ vlm_tape = VLM_GetFirstTAPE( );
+ }
+ else {
+
+ // They could have yanked only 1 tape from a multitape
+ // family. Handle that case.
+
+ vlm_bset = VLM_GetFirstBSET( &vlm_tape->bset_list );
+
+ while ( vlm_bset != NULL ) {
+
+ temp_bset = vlm_bset;
+
+ vlm_bset = VLM_GetNextBSET( vlm_bset );
+
+ // See if this set exists at all anymore.
+
+ qtc_bset = QTC_FindBset( temp_bset->tape_fid, (INT16)-1, temp_bset->bset_num );
+
+ if ( qtc_bset == NULL ) {
+
+ // remove the vlm set from this tape.
+
+ VLM_RemoveBset( temp_bset->tape_fid, (INT16)-1, temp_bset->bset_num, FALSE );
+ }
+ }
+
+ // Move to the next tape.
+
+ vlm_tape = VLM_GetNextTAPE( vlm_tape );
+ }
+
+ }
+
+ return( SUCCESS );
+}
+
+
+static INT VLM_CatalogSyncMore( )
+{
+ QTC_BSET_PTR bset;
+ QTC_TAPE_PTR tape;
+
+ /*
+ Now do it the other way around and make sure that we add
+ any that are in the QTC and not the VLM.
+ Calling VLM_AddBset() twice doesn't hurt, it's just slow.
+ */
+
+ tape = QTC_GetFirstTape( );
+
+ while ( tape != NULL ) {
+
+ bset = QTC_GetFirstBset( tape );
+
+ while ( bset != NULL ) {
+
+ // WM_MultiTask();
+
+ VLM_AddBset( bset->tape_fid,
+ (INT16)bset->tape_seq_num,
+ (INT16)bset->bset_num, bset, FALSE );
+
+ bset = QTC_GetNextBset( bset );
+ }
+
+ tape = QTC_GetNextTape( tape );
+ }
+
+ return( SUCCESS );
+}
+
+
+
+/**************
+ This function will create a new BSD for the drive the catalogs are being
+ kept on and insert it at the end of the BSD list. This allows us to
+ include the catalogs in a backup. An FSE is inserted for each of the
+ known catalog files. If the backup operation is a REPLACE and not an
+ APPEND then another catalog file will be created during the backup and
+ it will need to be added also.
+**************/
+
+INT VLM_IncludeCatalogs( )
+{
+ QTC_TAPE_PTR tape;
+ BSD_PTR bsd_ptr;
+ BE_CFG_PTR bec_config;
+ GENERIC_DLE_PTR dle_ptr;
+ DATE_TIME sortdate;
+ CHAR *path;
+ INT16 path_size;
+ BOOLEAN dummy;
+ CHAR bset_name[ MAX_BSET_NAME_SIZE ];
+
+
+ path_size = strsize( CDS_GetCatDataPath() );
+
+ path = malloc( path_size );
+ if ( path == NULL ) {
+ return( FAILURE );
+ }
+
+
+ // We need to know the drive the catalogs are on
+ // and create a new bsd for it. Set the date for
+ // the year 2025 so that it will be added to the
+ // end of the bsd list. Then add FSE's for all
+ // the known catalog files. If a new catalog file
+ // is created or removed during the backup operation
+ // then the FSE list will need to be updated also.
+
+ sortdate.date_valid = TRUE;
+ sortdate.year = 2025; /* year since 1900 */
+ sortdate.month = 10; /* 1 to 12 */
+ sortdate.day = 16; /* 1 to 31 */
+ sortdate.hour = 0; /* 0 to 23 */
+ sortdate.minute = 0; /* 0 to 59 */
+ sortdate.second = 0; /* 0 to 59 */
+ sortdate.day_of_week = 1; /* 1 to 7 for Sunday to Saturday */
+
+ /* find the dle based on the user path */
+
+ if ( FS_ParsePath( dle_list, CDS_GetCatDataPath(), &dle_ptr, path,
+ &path_size, NULL, &dummy ) != SUCCESS ) {
+ free( path );
+ return( FAILURE );
+ }
+
+ free( path );
+
+ bec_config = BEC_CloneConfig( CDS_GetPermBEC() );
+ BEC_UnLockConfig( bec_config );
+
+ BEC_SetSortBSD( bec_config, FALSE );
+
+ BSD_Add( bsd_list, &bsd_ptr, bec_config, NULL,
+ dle_ptr, (UINT32)-1L, (UINT16)-1, (INT16)-1, NULL, &sortdate );
+
+
+ if ( bsd_ptr == NULL ) {
+ return( FAILURE );
+ }
+
+ /* get name for the catalog set and update the bsd */
+
+ RSM_StringCopy( IDS_CATALOGSETNAME, bset_name, MAX_BSET_NAME_SIZE );
+
+ BSD_SetBackupDescript( bsd_ptr, (INT8_PTR)bset_name, (INT16)strsize(bset_name) );
+ BSD_SetBackupLabel( bsd_ptr, (INT8_PTR)bset_name, (INT16)strsize(bset_name) );
+ BSD_SetFullyCataloged( bsd_ptr, TRUE );
+ BSD_SetTapePos( bsd_ptr, (UINT32)-1L, (UINT16)-1, (UINT16)-1 );
+ BSD_SetTHW( bsd_ptr, thw_list );
+
+ tape = QTC_GetFirstTape();
+
+ while ( tape ) {
+ VLM_AddFileForInclude( tape->tape_fid, tape->tape_seq_num, FALSE );
+ tape = QTC_GetNextTape( tape );
+ }
+
+ return( SUCCESS );
+}
+
+
+INT VLM_AddFileForInclude(
+UINT32 tape_fid,
+INT16 tape_seq_num,
+BOOLEAN wild_flag )
+{
+ BSD_PTR bsd_ptr;
+ FSE_PTR fse_ptr;
+ CHAR_PTR filename;
+ CHAR_PTR path;
+ CHAR_PTR buffer;
+ DATE_TIME_PTR sortdate;
+ INT16 path_size;
+
+
+ // We need to add the filename for the family id and sequence number
+ // passed in. We first locate the right BSD by matching the 2025
+ // date. If it is found, we add the QTC filename as an include fse.
+ // If the wild flag is set, we make the sequence number a wild card.
+ // ie - famid.C??
+
+ // See if we can find the right BSD
+
+ bsd_ptr = BSD_GetFirst( bsd_list );
+
+ // Look for correct BSD
+
+ while ( bsd_ptr != NULL ) {
+
+ sortdate = BSD_ViewDate( bsd_ptr );
+
+ if ( sortdate != NULL ) {
+ if ( sortdate->date_valid ) {
+ if ( sortdate->year == 2025 ) {
+ break;
+ }
+ }
+ }
+
+ bsd_ptr = BSD_GetNext( bsd_ptr );
+ }
+
+ // Not really a bad error, happens sometimes.
+
+ if ( bsd_ptr == NULL ) {
+ return( FAILURE );
+ }
+
+ // 512 should be way more than enough to handle "xxxxxxxx.D01"
+
+ buffer = malloc( strsize( CDS_GetCatDataPath() ) + 512 );
+
+ if ( buffer == NULL ) {
+ return( FAILURE );
+ }
+
+ QTC_GetFileName( tape_fid, tape_seq_num, buffer );
+
+ /* locate the filename at the end of the buffer */
+
+ filename = buffer;
+ while ( *filename ) filename++;
+ while ( *filename != TEXT('\\') ) filename--;
+ *filename = 0; /* set the end of the path portion to null */
+ filename++;
+
+ /* if the wild_flag is set, make the sequence number wild cards */
+ /* QTC names are always 8.3 */
+
+ if ( wild_flag == USE_WILD_CARD ) {
+ *(filename + 10) = TEXT('?');
+ *(filename + 11) = TEXT('?');
+ }
+
+ /* make path NULL impregnated and calculate the size */
+
+ path = &buffer[ 2 ];
+ path_size = 1;
+
+ if ( *path != 0 ) {
+ path++;
+ while( buffer[path_size+2] != 0 ) {
+ if( buffer[path_size+2] == TEXT('\\') ) {
+ buffer[path_size+2] = 0 ;
+ }
+ path_size++ ;
+ }
+ }
+
+ path_size *= sizeof(CHAR); // convert to bytes
+
+ /* create and add the bsd */
+
+ if ( BSD_CreatFSE( &fse_ptr, INCLUDE, (INT8_PTR)path, path_size,
+ (INT8_PTR)filename, (INT16)strsize( filename ),
+ wild_flag, FALSE ) ) {
+ return( FAILURE );
+ }
+
+ BSD_AddFSE( bsd_ptr, fse_ptr );
+
+ return( SUCCESS );
+
+}
+
+
+INT VLM_CheckForCatalogError( QTC_BUILD_PTR qtc_ptr )
+{
+ CHAR text[ MAX_UI_RESOURCE_SIZE ];
+ CHAR title[ MAX_UI_RESOURCE_SIZE ];
+
+ if ( qtc_ptr == NULL ) {
+ return( SUCCESS );
+ }
+
+ switch ( QTC_GetErrorCondition( qtc_ptr ) ) {
+
+ case SUCCESS:
+ return( SUCCESS );
+ break;
+
+ case QTC_DISK_FULL:
+ RSM_StringCopy ( IDS_VLMCATFULLERROR, text, MAX_UI_RESOURCE_LEN );
+ break;
+
+ case QTC_OPEN_FAILED:
+ RSM_StringCopy ( IDS_VLMCATOPENERROR, text, MAX_UI_RESOURCE_LEN );
+ break;
+
+ case QTC_WRITE_FAILED:
+ RSM_StringCopy ( IDS_VLMCATWRITEERROR, text, MAX_UI_RESOURCE_LEN );
+ break;
+
+ case QTC_READ_FAILED:
+ RSM_StringCopy ( IDS_VLMCATREADERROR, text, MAX_UI_RESOURCE_LEN );
+ break;
+
+ case QTC_SEEK_FAILED:
+ RSM_StringCopy ( IDS_VLMCATSEEKERROR, text, MAX_UI_RESOURCE_LEN );
+ break;
+
+ case QTC_NO_MEMORY:
+ RSM_StringCopy ( IDS_VLMCATMEMERROR, text, MAX_UI_RESOURCE_LEN );
+ break;
+
+ case QTC_NO_FILE_HANDLES:
+ RSM_StringCopy ( IDS_VLMCATHANDLEERROR, text, MAX_UI_RESOURCE_LEN );
+ break;
+
+ default:
+ RSM_StringCopy ( IDS_VLMCATUNKNOWNERROR, text, MAX_UI_RESOURCE_LEN );
+ break;
+ }
+
+ RSM_StringCopy ( IDS_VLMCATERROR, title, MAX_UI_RESOURCE_LEN );
+ WM_MsgBox( title, text, WMMB_OK, WMMB_ICONINFORMATION );
+
+ return( FAILURE );
+}
diff --git a/private/utils/ntbackup/src/vlm_disk.c b/private/utils/ntbackup/src/vlm_disk.c
new file mode 100644
index 000000000..db5f99a28
--- /dev/null
+++ b/private/utils/ntbackup/src/vlm_disk.c
@@ -0,0 +1,1180 @@
+
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: VLM_DISK.C
+
+ Description:
+
+ This file contains the functions needed to maintain the
+ selections in the DISKS window. These are LOCAL or
+ MAPPED drives.
+
+ $Log: G:\UI\LOGFILES\VLM_DISK.C_V $
+
+ Rev 1.43.1.2 26 Jan 1994 11:17:08 Glenn
+Added CD ROM support.
+
+ Rev 1.43.1.1 08 Dec 1993 11:15:16 MikeP
+very deep pathes and unicode
+
+ Rev 1.43.1.0 21 Sep 1993 15:56:52 BARRY
+Unicode fix.
+
+ Rev 1.43 27 Jul 1993 12:58:20 MARINA
+enable c++
+
+ Rev 1.42 26 Jul 1993 17:25:44 MIKEP
+one last time at refresh fix
+
+ Rev 1.41 26 Jul 1993 16:52:30 MIKEP
+fix drive refresh if same letter, but diff map
+
+ Rev 1.40 20 Jul 1993 11:07:02 MIKEP
+
+ Rev 1.39 07 May 1993 18:18:40 MIKEP
+remove cdrom ifdef
+
+ Rev 1.38 04 May 1993 10:18:34 Aaron
+Changed condition from !OS_WIN32 to OS_WIN32 && !OEM_MSOFT
+
+ Rev 1.37 23 Apr 1993 10:17:06 MIKEP
+Fix invalid window handle reference epr and upper/lower case
+support.
+
+ Rev 1.36 25 Feb 1993 12:34:06 STEVEN
+fix more stuff
+
+ Rev 1.35 24 Feb 1993 11:07:06 STEVEN
+make net drive icon the default
+
+ Rev 1.34 11 Nov 1992 16:35:52 DAVEV
+UNICODE: remove compile warnings
+
+ Rev 1.33 01 Nov 1992 16:11:12 DAVEV
+Unicode changes
+
+ Rev 1.32 30 Oct 1992 15:46:44 GLENN
+Added Frame and MDI Doc window size and position saving and restoring.
+
+ Rev 1.31 07 Oct 1992 15:02:58 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.30 04 Oct 1992 19:41:56 DAVEV
+Unicode Awk pass
+
+ Rev 1.29 03 Sep 1992 13:17:30 MIKEP
+nt fixes for display
+
+ Rev 1.27 29 Jul 1992 09:41:56 MIKEP
+ChuckB checked in after NT warnings were fixed.
+
+ Rev 1.26 22 Jul 1992 10:16:48 MIKEP
+warning fixes
+
+ Rev 1.25 20 Jul 1992 09:59:08 JOHNWT
+gas gauge display work
+
+ Rev 1.24 10 Jul 1992 08:36:42 JOHNWT
+more gas guage work
+
+ Rev 1.23 08 Jul 1992 15:32:06 STEVEN
+Unicode BE changes
+
+ Rev 1.22 06 Jul 1992 10:36:38 MIKEP
+started adding ramdrive and cdrom icons
+
+ Rev 1.21 14 May 1992 18:05:14 MIKEP
+nt pass 2
+
+ Rev 1.20 06 May 1992 14:41:08 MIKEP
+unicode pass two
+
+ Rev 1.19 04 May 1992 13:39:52 MIKEP
+unicode pass 1
+
+ Rev 1.18 24 Mar 1992 14:42:30 DAVEV
+OEM_MSOFT: Removed Servers windows and associated code
+
+
+*****************************************************/
+
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+/*
+ Local function prototypes.
+*/
+
+static BYTE VLM_VlmGetSelect( VLM_OBJECT_PTR );
+static VOID_PTR VLM_VlmSetSelect( VLM_OBJECT_PTR, BYTE );
+static VOID_PTR VLM_VlmSetTag( VLM_OBJECT_PTR, BYTE );
+static BYTE VLM_VlmGetTag( VLM_OBJECT_PTR );
+static USHORT VLM_VlmGetItemCount( Q_HEADER_PTR );
+static VOID_PTR VLM_VlmGetFirstItem( Q_HEADER_PTR );
+static VOID_PTR VLM_VlmGetPrevItem( VLM_OBJECT_PTR );
+static VOID_PTR VLM_VlmGetNextItem( VLM_OBJECT_PTR );
+static VOID_PTR VLM_VlmGetObjects( VLM_OBJECT_PTR );
+static BOOLEAN VLM_VlmSetObjects( VLM_OBJECT_PTR, WORD, WORD );
+static VOID VLM_VlmSetItemFocus( VLM_OBJECT_PTR );
+
+
+// used to tell DLM how wide to make columns
+
+static INT mwMaxVolumeLabelLength = 0;
+
+/*
+ Fast access to primary windows.
+*/
+
+
+HWND gb_servers_win = (HWND)NULL;
+HWND gb_tapes_win = (HWND)NULL;
+HWND gb_disks_win = (HWND)NULL;
+HWND gb_search_win = (HWND)NULL;
+
+#ifdef OEM_EMS
+Q_HEADER gq_exchange_win;
+#endif
+
+
+VOID VLM_SetMaxVolumeLabelLength( Q_HEADER_PTR vlm_list )
+{
+ VLM_OBJECT_PTR vlm;
+
+ // Look for VLM drives we have that no longer exist.
+
+ vlm = VLM_GetFirstVLM( vlm_list );
+
+ // kludge
+
+ mwMaxVolumeLabelLength = 0;
+
+ while ( vlm != NULL ) {
+
+ if ( (INT)strlen( vlm->label ) > mwMaxVolumeLabelLength ) {
+ mwMaxVolumeLabelLength = strlen( vlm->label );
+ }
+
+ vlm = VLM_GetNextVLM( vlm );
+ }
+
+}
+
+
+/********************
+
+ Name: VLM_DisksSync
+
+ Description:
+
+ The user has done a refresh call and we have performed a DLE_Update
+ call. Now we need to see which VLM's are no longer around and get
+ rid of them. We also need to check and see if any new ones popped
+ up, which need to be included.
+
+ Returns: nothing
+
+*********************/
+
+VOID VLM_DisksSync( )
+{
+ VLM_OBJECT_PTR vlm;
+ VLM_OBJECT_PTR temp_vlm;
+ GENERIC_DLE_PTR dle;
+ WININFO_PTR wininfo;
+ BSD_PTR bsd_ptr;
+ BOOLEAN change_made = FALSE;
+ INT16 vlm_count;
+ CHAR szVolName[ 256 ];
+
+
+ wininfo = WM_GetInfoPtr( gb_disks_win );
+
+ // Look for VLM drives we have that no longer exist.
+
+ vlm = VLM_GetFirstVLM( WMDS_GetFlatList( wininfo ) );
+
+ while ( vlm != NULL ) {
+
+ temp_vlm = vlm;
+
+ vlm = VLM_GetNextVLM( vlm );
+
+ DLE_FindByName( dle_list, VLM_GetName( temp_vlm ), ANY_DRIVE_TYPE, &dle );
+
+
+ if ( dle != NULL ) {
+
+ // make sure it's the same one.
+
+ VLM_GetDriveLabel( dle, szVolName, sizeof( szVolName )/sizeof(CHAR) );
+
+ if ( stricmp( szVolName, VLM_GetLabel( temp_vlm ) ) ) {
+
+ // Yes there is still a G: drive but it is not mapped
+ // to the same place. Force it to refresh.
+
+ dle = NULL;
+ }
+ }
+
+
+ if ( dle == NULL ) {
+
+ // Drive went away so remove it.
+
+ change_made = TRUE;
+
+ bsd_ptr = BSD_FindByName( bsd_list, VLM_GetName( temp_vlm ) );
+
+ if ( bsd_ptr != NULL ) {
+
+ BSD_Remove( bsd_ptr );
+ }
+
+ RemoveQueueElem( WMDS_GetFlatList( wininfo ), &(temp_vlm->q_elem) );
+ free( temp_vlm );
+ }
+ }
+
+ // Look for new DLE's that aren't in the VLM queue.
+
+ vlm_count = QueueCount( WMDS_GetFlatList( wininfo ) );
+
+ VLM_BuildVolumeList( WMDS_GetFlatList( wininfo ), wininfo );
+
+ if ( vlm_count != QueueCount( WMDS_GetFlatList( wininfo ) ) ) {
+ change_made = TRUE;
+ }
+
+ if ( change_made ) {
+
+ DLM_Update( gb_disks_win, DLM_FLATLISTBOX,
+ WM_DLMUPDATELIST,
+ (LMHANDLE)WMDS_GetFlatList( wininfo ), 0 );
+ }
+}
+
+
+/********************
+
+ Name: VLM_UpdateDiskStatus
+
+ Description:
+
+ Set the checkbox on the disk to match the BSD status.
+
+ Returns: nothing
+
+*********************/
+
+VOID VLM_UpdateDiskStatus(
+VLM_OBJECT_PTR vlm ) // I - vlm of disk to update
+{
+ UINT16 new_status = 0;
+ BSD_PTR bsd;
+ GENERIC_DLE_PTR dle;
+
+
+ DLE_FindByName( dle_list, VLM_GetName( vlm ), ANY_DRIVE_TYPE, &dle );
+
+ if ( dle != NULL ) {
+
+ bsd = BSD_FindByDLE( bsd_list, dle );
+
+ if ( bsd != NULL ) {
+
+ switch ( BSD_GetMarkStatus( bsd ) ) {
+
+ case SOME_SELECTED:
+ new_status = INFO_SELECT | INFO_PARTIAL;
+ break;
+
+ case ALL_SELECTED:
+ new_status = INFO_SELECT;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ if ( (UINT16)( VLM_GetStatus( vlm ) & (UINT16)(INFO_SELECT|INFO_PARTIAL) ) !=
+ new_status ) {
+
+ VLM_SetStatus( vlm, VLM_GetStatus( vlm ) & (UINT16)~( INFO_SELECT|INFO_PARTIAL ) );
+ VLM_SetStatus( vlm, VLM_GetStatus( vlm ) | (UINT16)new_status );
+
+ DLM_Update( gb_disks_win, DLM_FLATLISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)vlm, 0 );
+ }
+
+}
+
+
+
+/************
+
+ Name: VLM_SelectDisks
+
+ Description:
+
+ The user has tagged one or more drives and hit the select or deselect
+ button to do them all at once.
+
+ Returns: Nothing
+
+*****/
+
+VOID VLM_SelectDisks(
+BYTE attr ) // I - select or deselect ?
+{
+ VLM_OBJECT_PTR vlm;
+ WININFO_PTR wininfo;
+
+ wininfo = WM_GetInfoPtr( gb_disks_win );
+
+ // Have the display list manager update our tags for us.
+
+ DLM_UpdateTags( gb_disks_win, DLM_FLATLISTBOX );
+
+
+ // Now look for the ones that are selected.
+
+ vlm = VLM_GetFirstVLM( WMDS_GetFlatList( wininfo ) );
+
+ while ( vlm != NULL ) {
+
+ if ( VLM_GetStatus( vlm ) & INFO_TAGGED ) {
+
+ VLM_VlmSetSelect( vlm, attr ); // select the drive
+ }
+
+ vlm = VLM_GetNextVLM( vlm );
+ }
+
+}
+
+
+/*********************
+
+ Name: VLM_ClearAllDiskSelections
+
+ Description:
+
+ Run through the disks queue and make all the drives check boxes clear.
+
+ Returns: Nothing.
+
+**********************/
+
+VOID VLM_ClearAllDiskSelections( )
+{
+ VLM_OBJECT_PTR vlm;
+ WININFO_PTR wininfo;
+
+ // Get the wininfo, to get our queue header
+
+ wininfo = WM_GetInfoPtr( gb_disks_win );
+
+
+ // Loop through entire queue.
+
+ vlm = VLM_GetFirstVLM( WMDS_GetFlatList( wininfo ) );
+
+ while ( vlm != NULL ) {
+
+
+ // If it's set, clear it.
+
+ if ( VLM_GetStatus( vlm ) & (INFO_SELECT|INFO_PARTIAL) ) {
+
+ VLM_SetStatus( vlm, VLM_GetStatus( vlm ) & (UINT16)~(INFO_PARTIAL|INFO_SELECT) );
+
+ DLM_Update( gb_disks_win, DLM_FLATLISTBOX, WM_DLMUPDATEITEM,
+ (LMHANDLE)vlm, 0 );
+
+ }
+
+ vlm = VLM_GetNextVLM( vlm );
+ }
+
+}
+
+
+/*********************
+
+ Name: VLM_DisksListCreate
+
+ Description:
+
+ Create the window and lists for the Disks window.
+
+ Returns: SUCCESS or FAILURE.
+
+**********************/
+
+BOOLEAN VLM_DisksListCreate()
+{
+ WININFO_PTR wininfo;
+ Q_HEADER_PTR vlm_list;
+ DLM_INIT dlm;
+ CHAR title[ MAX_UI_RESOURCE_SIZE ];
+ CDS_PTR pCDS = CDS_GetPerm ();
+
+ // Initialize our queue.
+
+ vlm_list = (Q_HEADER_PTR)malloc( sizeof(Q_HEADER) );
+
+ if ( vlm_list == NULL ) {
+ return( FAILURE );
+ }
+
+ InitQueue( vlm_list );
+
+ // Create the window.
+
+ wininfo = ( WININFO_PTR )malloc( sizeof( WININFO ) );
+
+ if ( wininfo == NULL ) {
+ return( FAILURE );
+ }
+
+ // Build our queue from the DLE list created by the backup engine.
+
+ VLM_BuildVolumeList( vlm_list, wininfo );
+
+ /* fill in the wininfo structure. */
+
+ WMDS_SetWinType( wininfo, WMTYPE_DISKS );
+ WMDS_SetCursor( wininfo, RSM_CursorLoad( IDRC_HSLIDER ) );
+ WMDS_SetDragCursor( wininfo, 0 );
+ WMDS_SetIcon( wininfo, RSM_IconLoad( IDRI_DISKS ) );
+ WMDS_SetWinHelpID( wininfo, 0 );
+ WMDS_SetStatusLineID( wininfo, 0 );
+ WMDS_SetRibbonState( wininfo, 0 );
+ WMDS_SetRibbon( wininfo, NULL );
+ WMDS_SetFlatList( wininfo, (Q_HEADER_PTR)vlm_list );
+ WMDS_SetAppInfo( wininfo, NULL );
+
+ /* Fill in the display manager stuff. */
+
+ DLM_ListBoxType( &dlm, DLM_FLATLISTBOX );
+ DLM_Mode( &dlm, DLM_MULTICOLUMN );
+ DLM_Display( &dlm, DLM_LARGEBITMAPSLTEXT );
+ DLM_DispHdr( &dlm, vlm_list );
+ DLM_TextFont( &dlm, DLM_SYSTEM_FONT );
+ DLM_GetItemCount( &dlm, VLM_VlmGetItemCount );
+ DLM_GetFirstItem( &dlm, VLM_VlmGetFirstItem );
+ DLM_GetNext( &dlm, VLM_VlmGetNextItem );
+ DLM_GetPrev( &dlm, VLM_VlmGetPrevItem );
+ DLM_GetTag( &dlm, VLM_VlmGetTag );
+ DLM_SetTag( &dlm, VLM_VlmSetTag );
+ DLM_GetSelect( &dlm, VLM_VlmGetSelect );
+ DLM_SetSelect( &dlm, VLM_VlmSetSelect );
+ DLM_GetObjects( &dlm, VLM_VlmGetObjects );
+ DLM_SetObjects( &dlm, VLM_VlmSetObjects );
+ DLM_SSetItemFocus( &dlm, VLM_VlmSetItemFocus );
+
+
+ // Tell the display manager what the maximum number of objects
+ // we will tell him to display per item. His minimum is 6.
+
+ DLM_MaxNumObjects( &dlm, 6 );
+
+
+
+ DLM_DispListInit( wininfo, &dlm );
+
+ /* Create the window. */
+
+ RSM_StringCopy ( IDS_VLMDISKTITLE, title, MAX_UI_RESOURCE_LEN );
+
+ gb_disks_win = WM_Create( (WORD)(WM_MDIPRIMARY | WM_FLATLISTMC | (WORD)CDS_GetDiskInfo ( pCDS ).nSize),
+ title,
+ (LPSTR)NULL,
+ (INT)CDS_GetDiskInfo ( pCDS ).x,
+ (INT)CDS_GetDiskInfo ( pCDS ).y,
+ (INT)CDS_GetDiskInfo ( pCDS ).cx,
+ (INT)CDS_GetDiskInfo ( pCDS ).cy,
+ wininfo );
+
+ if ( gb_disks_win == (HWND)NULL ) {
+ return( FAILURE );
+ }
+
+ /* Start up the Display Manager. */
+
+ DLM_DispListProc( WMDS_GetWinFlatList( wininfo ), 0, NULL );
+
+ if ( VLM_GetFirstVLM( vlm_list ) ) {
+ DLM_SetAnchor( WMDS_GetWinFlatList( wininfo ),
+ 0,
+ (LMHANDLE)VLM_GetFirstVLM( vlm_list ) );
+ }
+
+ return( SUCCESS );
+}
+
+
+
+/***************************************************
+
+ Name: VLM_GetFirstVLM
+
+ Description:
+
+ Get the first drive element off a queue of known drives.
+
+ Returns: Pointer to first drive.
+
+*****************************************************/
+
+VLM_OBJECT_PTR VLM_GetFirstVLM(
+Q_HEADER_PTR qhdr) // I - queue header to work from
+{
+ Q_ELEM_PTR q_elem;
+
+ if ( qhdr != NULL ) {
+
+ q_elem = QueueHead( qhdr );
+
+ if ( q_elem != NULL ) {
+ return ( VLM_OBJECT_PTR )( q_elem->q_ptr ) ;
+ }
+ }
+
+ return( NULL );
+}
+
+/***************************************************
+
+ Name: VLM_GetNextVLM
+
+ Description:
+
+ Get the next drive element off a queue of known drives.
+
+ Returns: Pointer to next drive element or NULL.
+
+*****************************************************/
+
+VLM_OBJECT_PTR VLM_GetNextVLM(
+VLM_OBJECT_PTR vlm ) // I - current vlm
+{
+ Q_ELEM_PTR q_elem;
+
+ q_elem = QueueNext( &(vlm->q_elem) );
+
+ if ( q_elem != NULL ) {
+ return (VLM_OBJECT_PTR )( q_elem->q_ptr ) ;
+ }
+ return( NULL );
+}
+
+/***************************************************
+
+ Name: VLM_GetPrevVLM
+
+ Description:
+
+ Get the previous drive element off a queue of known drives.
+
+ Returns: Pointer to next drive element or NULL.
+
+*****************************************************/
+
+VLM_OBJECT_PTR VLM_GetPrevVLM(
+VLM_OBJECT_PTR vlm ) // I - current vlm
+{
+ Q_ELEM_PTR q_elem;
+
+ q_elem = QueuePrev( &(vlm->q_elem) );
+
+ if ( q_elem != NULL ) {
+ return ( VLM_OBJECT_PTR )( q_elem->q_ptr );
+ }
+
+ return( NULL );
+}
+
+
+/***************************************************
+
+ Name: VLM_VlmSetSelect
+
+ Description:
+
+ The callback function for the display manager to tell me that the
+ selection status on a disk has changed.
+
+*****************************************************/
+
+static VOID_PTR VLM_VlmSetSelect(
+VLM_OBJECT_PTR vlm, // I - vlm to change
+BYTE attr ) // I - what to change it to
+{
+ CHAR title[ VLM_BUFFER_SIZE ]; // this works with deep pathes
+ GENERIC_DLE_PTR dle;
+ WININFO_PTR wininfo;
+ FSYS_HAND temp_fsh;
+ BSD_PTR bsd_ptr;
+ FSE_PTR fse_ptr;
+ HWND win;
+ INT16 error;
+ INT length;
+ BOOL all_subdirs;
+ BE_CFG_PTR bec_config;
+ UINT16 status;
+ BOOLEAN open_win;
+ SLM_OBJECT_PTR slm;
+ INT16 bset_num;
+ QTC_BSET_PTR qtc_bset;
+ QTC_HEADER_PTR header;
+
+#ifdef OEM_EMS
+ UNREFERENCED_PARAMETER( slm );
+ UNREFERENCED_PARAMETER( qtc_bset );
+ UNREFERENCED_PARAMETER( header );
+ UNREFERENCED_PARAMETER( bset_num );
+#endif
+
+ all_subdirs = CDS_GetIncludeSubdirs( CDS_GetPerm() );
+
+ // change the status
+
+ if ( attr ) {
+
+ if ( all_subdirs ) {
+ status = INFO_SELECT;
+ }
+ else {
+ status = (INFO_PARTIAL|INFO_SELECT);
+ }
+ }
+ else {
+ status = 0;
+ }
+
+ if ( (UINT16)( VLM_GetStatus( vlm ) & (UINT16)(INFO_PARTIAL|INFO_SELECT)) != status ) {
+
+ VLM_SetStatus( vlm, VLM_GetStatus( vlm ) & (UINT16)~(INFO_PARTIAL|INFO_SELECT) );
+ VLM_SetStatus( vlm, VLM_GetStatus( vlm ) | (UINT16)status );
+
+ DLM_Update( gb_disks_win,
+ DLM_FLATLISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)vlm, 0 );
+ }
+
+ // Create an FSE entry for the backup engine
+
+ if ( attr ) {
+ error = BSD_CreatFSE( &fse_ptr, (INT16) INCLUDE,
+ (INT8_PTR)TEXT(""), (INT16)sizeof(CHAR),
+ (INT8_PTR)ALL_FILES, ALL_FILES_LENG,
+ (BOOLEAN)USE_WILD_CARD, (BOOLEAN) all_subdirs );
+ }
+ else {
+ error = BSD_CreatFSE( &fse_ptr, (INT16) EXCLUDE,
+ (INT8_PTR)TEXT(""), (INT16) sizeof(CHAR),
+ (INT8_PTR)ALL_FILES, ALL_FILES_LENG,
+ (BOOLEAN)USE_WILD_CARD, (BOOLEAN) TRUE );
+ }
+
+ if ( error ) {
+ return( NULL );
+ }
+
+ DLE_FindByName( dle_list, VLM_GetName( vlm ), ANY_DRIVE_TYPE, &dle );
+
+ if ( dle == NULL ) {
+ msassert( FALSE );
+ return( NULL );
+ }
+
+ bsd_ptr = BSD_FindByDLE( bsd_list, dle );
+
+ if ( bsd_ptr == NULL ) {
+
+ // Do a quick attach/detach so that the backup engine knows
+ // the volume name.
+
+ if ( UI_AttachDrive( &temp_fsh, dle, FALSE ) ) {
+ return( NULL );
+ }
+
+ bec_config = BEC_CloneConfig( CDS_GetPermBEC() );
+
+ BEC_UnLockConfig( bec_config );
+
+ BSD_Add( bsd_list, &bsd_ptr, bec_config,
+ NULL, dle, (UINT32)-1L, (UINT16)-1, (INT16)-1, NULL, NULL );
+
+ FS_DetachDLE( temp_fsh );
+ }
+
+ if ( bsd_ptr != NULL ) {
+ BSD_AddFSE( bsd_ptr, fse_ptr );
+ }
+
+ // See if this drive has any open file display windows
+ // If we find one then all its entries will need updating
+
+ open_win = FALSE;
+ win = WM_GetNext( (HWND)NULL );
+
+ while ( win != (HWND)NULL ) {
+
+ wininfo = WM_GetInfoPtr( win );
+
+ /* Is it a directory list ? */
+
+ if ( WMDS_GetWinType( wininfo ) == WMTYPE_DISKTREE ) {
+
+ WM_GetTitle( win, title, VLM_BUFFER_SIZE );
+
+ length = strlen( VLM_GetName( vlm ) );
+
+ if ( ! strnicmp( title, VLM_GetName( vlm ), length ) ) {
+
+ open_win = TRUE;
+
+ if ( attr ) {
+ VLM_SubdirListManager( win, SLM_SEL_ALL );
+ if ( bsd_ptr != NULL ) {
+ VLM_MatchSLMList( wininfo, bsd_ptr, FALSE );
+ }
+ }
+ else {
+ VLM_SubdirListManager( win, SLM_SEL_NONE );
+ VLM_DeselectAll( wininfo, FALSE );
+ }
+ break;
+ }
+ }
+
+ win = WM_GetNext( win );
+ }
+
+ return(NULL);
+}
+
+/***************************************************
+
+ Name: VLM_VlmGetSelect
+
+ Description:
+
+ A callback function for the display manager to get the selection
+ status of a disk.
+
+*****************************************************/
+
+static BYTE VLM_VlmGetSelect(
+VLM_OBJECT_PTR vlm ) // I - vlm to get the status of
+{
+ if ( VLM_GetStatus( vlm ) & INFO_SELECT ) {
+ return( 1 );
+ }
+
+ return( 0 );
+}
+
+/***************************************************
+
+ Name: VLM_VlmSetTag
+
+ Description:
+
+ A callback function for the display manager to set the tag status
+ of a disk for me.
+
+*****************************************************/
+
+static VOID_PTR VLM_VlmSetTag(
+VLM_OBJECT_PTR vlm, // I - vlm to work with
+BYTE attr ) // I - what to set it to
+{
+ if ( attr ) {
+ VLM_SetStatus( vlm, VLM_GetStatus( vlm ) | (UINT16)INFO_TAGGED );
+ }
+ else {
+ VLM_SetStatus( vlm, VLM_GetStatus( vlm ) & (UINT16)~INFO_TAGGED );
+ }
+
+ return(NULL);
+}
+
+/***************************************************
+
+ Name: VLM_VlmGetTag
+
+ Description:
+
+ A callback function for the display manager to get the tag status
+ of a disk from me.
+
+*****************************************************/
+
+static BYTE VLM_VlmGetTag(
+VLM_OBJECT_PTR vlm ) // I - vlm to work with
+{
+ if ( VLM_GetStatus( vlm ) & INFO_TAGGED ) {
+ return( 1 );
+ }
+ return( 0 );
+}
+
+/***************************************************
+
+ Name: VLM_VlmGetItemCount
+
+ Description:
+
+ A callback function for the display manager to get the
+ number of displayable drives.
+
+*****************************************************/
+
+static USHORT VLM_VlmGetItemCount(
+Q_HEADER_PTR vlm_list ) // I - queue header to get count from
+{
+ return( QueueCount( vlm_list ) );
+}
+
+/***************************************************
+
+ Name: VLM_VlmGetFirstItem
+
+ Description:
+
+ A callback function for the display manager to get the first drive
+ to display.
+
+*****************************************************/
+
+static VOID_PTR VLM_VlmGetFirstItem(
+Q_HEADER_PTR vlm_list ) // I - queue to get first item from
+{
+ return( VLM_GetFirstVLM( vlm_list ) );
+}
+
+/***************************************************
+
+ Name: VLM_VlmGetPrevItem
+
+ Description:
+
+ A callback function for the display manager to get the previous
+ disk in a list of disks.
+
+*****************************************************/
+
+static VOID_PTR VLM_VlmGetPrevItem(
+VLM_OBJECT_PTR vlm ) // I - current vlm
+{
+ return( VLM_GetPrevVLM( vlm ) );
+}
+
+/***************************************************
+
+ Name: VLM_VlmGetNextItem
+
+ Description:
+
+ A callback function for the display manager to get the next
+ disk in a list of disks.
+
+*****************************************************/
+
+static VOID_PTR VLM_VlmGetNextItem(
+VLM_OBJECT_PTR vlm ) // I - current vlm
+{
+ return( VLM_GetNextVLM( vlm ) );
+}
+
+/***************************************************
+
+ Name: VLM_VlmGetObjects
+
+ Description:
+
+ A callback function for the display manager to get the object list
+ to display for a given disk.
+
+*****************************************************/
+
+static VOID_PTR VLM_VlmGetObjects(
+VLM_OBJECT_PTR vlm ) // I - current vlm
+{
+ BYTE_PTR memblk;
+ CHAR_PTR s;
+ DLM_ITEM_PTR item;
+ WORD type;
+
+
+ // get the buffer to fill for this window
+
+ memblk = ( BYTE_PTR )DLM_GetObjectsBuffer( WMDS_GetWinFlatList( vlm->XtraBytes ) );
+
+
+ /* Store the number of items to display in the first two bytes. */
+
+
+#ifdef OS_WIN32
+ *memblk = 4;
+#else
+ *memblk = 3;
+#endif
+
+ /* Set up check box. */
+
+ item = (DLM_ITEM_PTR)( memblk + 6 );
+
+ DLM_ItemcbNum( item ) = 1;
+ DLM_ItembType( item ) = DLM_CHECKBOX;
+ if ( VLM_GetStatus( vlm ) & INFO_SELECT ) {
+ DLM_ItemwId( item ) = IDRBM_SEL_ALL;
+ if ( VLM_GetStatus( vlm ) & INFO_PARTIAL ) {
+ DLM_ItemwId( item ) = IDRBM_SEL_PART;
+ }
+ }
+ else {
+ DLM_ItemwId( item ) = IDRBM_SEL_NONE;
+ }
+ DLM_ItembMaxTextLen( item ) = 0;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+
+ /* Set up Bitmap, ie. Floppy, Hard, Network. */
+
+ item++;
+ DLM_ItemcbNum( item ) = 2;
+ DLM_ItembType( item ) = DLM_BITMAP;
+
+ s = VLM_GetName( vlm );
+
+#ifdef OS_WIN32
+ {
+ CHAR dir[4] = TEXT(" :\\");
+
+ dir[ 0 ] = *s;
+ type = (WORD)GetDriveType( dir );
+ }
+#else
+
+ type = (WORD)GetDriveType( (INT)(toupper( *s ) - TEXT('A')) );
+
+#endif
+
+ switch ( type ) {
+
+ case DRIVE_REMOVABLE:
+ DLM_ItemwId( item ) = IDRBM_FLOPPYDRIVE;
+ break;
+
+ case DRIVE_FIXED:
+ DLM_ItemwId( item ) = IDRBM_HARDDRIVE;
+ break;
+
+ case DRIVE_CDROM:
+ DLM_ItemwId( item ) = IDRBM_CDROM;
+ break;
+
+ case DRIVE_REMOTE:
+ default:
+ DLM_ItemwId( item ) = IDRBM_NETDRIVE;
+ break;
+
+ }
+
+ DLM_ItembMaxTextLen( item ) = 0;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+
+ /* Set up the text string to be displayed. */
+
+ item++;
+ DLM_ItemcbNum( item ) = 3;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = 2;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+ strcpy( (CHAR_PTR)DLM_ItemqszString( item ), (CHAR_PTR)vlm->name );
+
+#ifdef OS_WIN32
+ item++;
+ DLM_ItemcbNum( item ) = 4;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = mwMaxVolumeLabelLength;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+ strcpy( (CHAR_PTR)DLM_ItemqszString( item ), (CHAR_PTR)vlm->label );
+#endif
+
+ return( memblk );
+}
+
+/***************************************************
+
+ Name: VLM_VlmSetObjects
+
+ Description:
+
+ A callback function for the display manager to tell me that the
+ user tried to do something with this drive.
+
+*****************************************************/
+
+static BOOLEAN VLM_VlmSetObjects(
+VLM_OBJECT_PTR vlm, // I - current vlm
+WORD operation, // I - operation the user did
+WORD ObjectNum ) // I - object he did it on
+{
+ HWND win;
+ VLM_OBJECT_PTR temp_vlm;
+ GENERIC_DLE_PTR dle;
+ WININFO_PTR wininfo;
+ CHAR title[ VLM_BUFFER_SIZE ]; // this works with deep pathes
+ BOOLEAN found = FALSE;
+ CHAR keyb_char;
+
+ if ( operation == WM_DLMCHAR ) {
+
+ keyb_char = (CHAR)ObjectNum;
+
+ keyb_char = (CHAR)toupper( keyb_char );
+
+ temp_vlm = vlm;
+
+ do {
+
+ temp_vlm = VLM_GetNextVLM( temp_vlm );
+
+ if ( temp_vlm != NULL ) {
+
+ if ( keyb_char == (CHAR)toupper( *VLM_GetName( temp_vlm ) ) ) {
+
+ DLM_SetAnchor( WMDS_GetWinFlatList( VLM_GetXtraBytes( temp_vlm ) ),
+ 0,
+ (LMHANDLE)temp_vlm );
+ return( TRUE );
+ }
+ }
+
+ } while ( temp_vlm != NULL );
+
+ temp_vlm = VLM_GetFirstVLM( WMDS_GetFlatList( VLM_GetXtraBytes( vlm ) ) );
+
+ while ( temp_vlm != NULL && temp_vlm != vlm ) {
+
+ if ( keyb_char == (CHAR)toupper( *VLM_GetName( temp_vlm ) ) ) {
+
+ DLM_SetAnchor( WMDS_GetWinFlatList( VLM_GetXtraBytes( temp_vlm ) ),
+ 0,
+ (LMHANDLE)temp_vlm );
+ return( TRUE );
+ }
+
+ temp_vlm = VLM_GetNextVLM( temp_vlm );
+ }
+
+ }
+
+
+ if ( ( operation == WM_DLMDBCLK ) &&
+ ( ObjectNum >= 2 ) ) {
+
+ /*
+ If a hierarchical exists for this drive then make it active
+ else create one by calling SubdirListCreate().
+ */
+
+ win = WM_GetNext( (HWND)NULL );
+
+ while ( win != (HWND)NULL ) {
+
+ wininfo = WM_GetInfoPtr( win );
+
+ if ( WMDS_GetWinType( wininfo ) == WMTYPE_DISKTREE ) {
+
+ WM_GetTitle( win, title, VLM_BUFFER_SIZE );
+
+ if ( ! strnicmp( title,
+ VLM_GetName( vlm ),
+ strlen( VLM_GetName( vlm ) ) ) ) {
+ found = TRUE;
+ WM_DocActivate( win );
+ break;
+ }
+ }
+
+ win = WM_GetNext( win );
+ }
+
+ DLE_FindByName( dle_list, VLM_GetName( vlm ), ANY_DRIVE_TYPE, &dle );
+
+ if ( ! found ) {
+ WM_ShowWaitCursor( TRUE );
+ VLM_SubdirListCreate( dle, (UINT16)0, (UINT16)0, (UINT16)0, gb_disks_win );
+ WM_ShowWaitCursor( FALSE );
+ }
+ }
+
+ return( FALSE );
+}
+
+/*********************
+
+ Name: VLM_VlmSetItemFocus
+
+ Description:
+
+ Update the status line with the drive name for the active drive.
+
+ Returns:
+
+**********************/
+
+static VOID VLM_VlmSetItemFocus( VLM_OBJECT_PTR vlm )
+{
+#ifndef OS_WIN32
+ GENERIC_DLE_PTR dle;
+ CHAR buffer[ VLM_BUFFER_SIZE ]; // this works with deep pathes
+
+ if ( vlm == NULL ) { // Safety precaution
+ return;
+ }
+
+ if ( strlen( VLM_GetLabel( vlm ) ) ) {
+
+ STM_DrawText( VLM_GetLabel( vlm ) );
+
+ }
+ else {
+
+ DLE_FindByName( dle_list, VLM_GetName( vlm ), ANY_DRIVE_TYPE, &dle );
+
+ if ( dle == NULL ) {
+ return;
+ }
+
+ if ( DLE_SizeofVolName( dle ) ) {
+
+ DLE_GetVolName( dle, buffer );
+
+ STM_DrawText( buffer );
+ }
+ }
+#endif
+}
diff --git a/private/utils/ntbackup/src/vlm_file.c b/private/utils/ntbackup/src/vlm_file.c
new file mode 100644
index 000000000..232738578
--- /dev/null
+++ b/private/utils/ntbackup/src/vlm_file.c
@@ -0,0 +1,3496 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: VLM_FILE.C
+
+ Description:
+
+ This file contains most of the code for processing file lists
+ in the right hand window.
+
+ $Log: J:/UI/LOGFILES/VLM_FILE.C_V $
+
+ Rev 1.87.1.3 16 Mar 1994 15:35:16 GREGG
+Fixed memory leak during file selection.
+
+ Rev 1.87.1.2 14 Jan 1994 14:36:48 MIKEP
+fix refresh and up arrow display
+
+ Rev 1.87.1.1 10 Jan 1994 11:15:24 MikeP
+fix epr 253 & 179
+
+ Rev 1.87.1.0 08 Dec 1993 10:52:30 MikeP
+very deep path support
+
+ Rev 1.87 16 Aug 1993 15:05:56 BARRY
+Don't do the search stuff for NTBACKUP.
+
+ Rev 1.86 01 Aug 1993 13:55:56 MIKEP
+fix info button trap on empty window
+
+ Rev 1.85 27 Jul 1993 23:20:02 MIKEP
+fix access denied handling
+
+ Rev 1.84 27 Jul 1993 13:22:44 MARINA
+enable c++
+
+ Rev 1.83 26 Jul 1993 16:31:32 MIKEP
+try again to display huge file sizes
+
+ Rev 1.82 23 Jul 1993 15:43:26 MIKEP
+handle file system error codes
+
+ Rev 1.81 23 Jul 1993 15:02:38 MIKEP
+Fix display of huge files. Use 64 bit routines to build size string.
+
+ Rev 1.80 20 Jul 1993 14:07:26 BARRY
+Need to call FS_FindObjClose.
+
+ Rev 1.79 15 Jul 1993 09:24:00 KEVINS
+When sorting files by date, sort newest to oldest.
+
+ Rev 1.78 01 Jul 1993 09:14:44 KEVINS
+Corrected sorting logic problems.
+
+ Rev 1.77 19 Jun 1993 13:55:48 MIKEP
+add msg box for info button if no file with focus
+
+ Rev 1.76 23 May 1993 20:24:34 BARRY
+Unicode fixes.
+
+ Rev 1.75 01 May 1993 19:02:30 MIKEP
+fix lack of scroll bar in files window if file name really long. Fix
+useful to nostrad and cayman.
+
+ Rev 1.74 23 Apr 1993 10:15:30 MIKEP
+Continue work on upper/lower case font support. Plus
+added ability to sort files by name, date, size, and type.
+
+ Rev 1.72 02 Apr 1993 08:30:34 MIKEP
+fix last change
+
+ Rev 1.71 01 Apr 1993 19:48:38 MIKEP
+add display info stuff
+
+ Rev 1.70 17 Mar 1993 18:11:24 DARRYLP
+Cleaned up display of time/date and file sizes.
+
+ Rev 1.69 10 Mar 1993 14:52:42 MIKEP
+fix directory contents display
+
+*****************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+static int bug1, bug2;
+
+
+#define SORT_BY_NAME 0
+#define SORT_BY_SIZE 1
+#define SORT_BY_DATE 2
+#define SORT_BY_TYPE 3
+
+
+// files for the flat list
+
+static VOID_PTR VLM_FlmSetSelect( FLM_OBJECT_PTR, BYTE );
+static BYTE VLM_FlmGetSelect( FLM_OBJECT_PTR );
+static VOID_PTR VLM_FlmSetTag( FLM_OBJECT_PTR, BYTE );
+static BYTE VLM_FlmGetTag( FLM_OBJECT_PTR );
+static USHORT VLM_FlmGetItemCount( Q_HEADER_PTR );
+static VOID_PTR VLM_FlmGetFirstItem( Q_HEADER_PTR );
+static VOID_PTR VLM_FlmGetPrevItem( FLM_OBJECT_PTR );
+static VOID_PTR VLM_FlmGetNextItem( FLM_OBJECT_PTR );
+static VOID_PTR VLM_FlmGetObjects( FLM_OBJECT_PTR );
+static BOOLEAN VLM_FlmSetObjects( FLM_OBJECT_PTR, WORD, WORD );
+
+// Local prototypes
+
+static CHAR * VLM_GetFlmNameExt( FLM_OBJECT_PTR );
+static FLM_OBJECT_PTR VLM_CreateFlm( INT, INT, INT, INT );
+static FLM_OBJECT_PTR VLM_FindFLM( Q_HEADER_PTR, CHAR_PTR, BOOLEAN, FLM_OBJECT_PTR * );
+static VOID VLM_SetMaxFlmSize( Q_HEADER_PTR );
+static VOID VLM_InsertFlmInQueue( Q_HEADER_PTR, FLM_OBJECT_PTR, FLM_OBJECT_PTR, INT );
+static VOID VLM_InsertFlmByName( Q_HEADER_PTR, FLM_OBJECT_PTR, FLM_OBJECT_PTR );
+static VOID VLM_InsertFlmBySize( Q_HEADER_PTR, FLM_OBJECT_PTR, FLM_OBJECT_PTR );
+static VOID VLM_InsertFlmByDate( Q_HEADER_PTR, FLM_OBJECT_PTR, FLM_OBJECT_PTR );
+static VOID VLM_InsertFlmByExtn( Q_HEADER_PTR, FLM_OBJECT_PTR, FLM_OBJECT_PTR );
+static CHAR_PTR VLM_GetPathForSLM( SLM_OBJECT_PTR, CHAR_PTR, INT *, INT16_PTR );
+
+
+/***********************
+
+ We have been asked to resort an active file list. The user has changed
+ sorting by name to date, size, etc. Move all the entries to a temp
+ queue, and then reinsert them.
+
+************************/
+
+INT VLM_ResortFileList( HWND win )
+{
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ FLM_OBJECT_PTR flm;
+ FLM_OBJECT_PTR prev_flm;
+ Q_HEADER temp_list;
+ Q_HEADER_PTR flm_list;
+ Q_ELEM_PTR q_elem;
+ INT SortType = SORT_BY_NAME;
+
+
+ InitQueue( &temp_list );
+
+ wininfo = WM_GetInfoPtr( win );
+ appinfo = ( APPINFO_PTR )WMDS_GetAppInfo( wininfo );
+
+
+ if ( WMDS_GetMenuState( wininfo ) & MMDOC_SORTNAME ) {
+ SortType = SORT_BY_NAME;
+ }
+ if ( WMDS_GetMenuState( wininfo ) & MMDOC_SORTSIZE ) {
+ SortType = SORT_BY_SIZE;
+ }
+ if ( WMDS_GetMenuState( wininfo ) & MMDOC_SORTDATE ) {
+ SortType = SORT_BY_DATE;
+ }
+ if ( WMDS_GetMenuState( wininfo ) & MMDOC_SORTTYPE ) {
+ SortType = SORT_BY_TYPE;
+ }
+
+
+ flm_list = WMDS_GetFlatList( wininfo );
+
+ // Release all the old FLM structures in the queue
+
+ q_elem = DeQueueElem( flm_list );
+
+ while ( q_elem != NULL ) {
+
+ if ( QueueCount( &temp_list ) ) {
+ InsertElem( &temp_list, QueueHead(&temp_list), q_elem, BEFORE );
+ }
+ else {
+ EnQueueElem( &temp_list, q_elem, FALSE );
+ }
+
+ q_elem = DeQueueElem( flm_list );
+ }
+
+
+ prev_flm = NULL;
+
+ q_elem = DeQueueElem( &temp_list );
+
+ while ( q_elem != NULL ) {
+
+ flm = (FLM_OBJECT_PTR)q_elem->q_ptr;
+
+ VLM_InsertFlmInQueue( flm_list, flm, prev_flm, SortType );
+
+ prev_flm = flm;
+
+ q_elem = DeQueueElem( &temp_list );
+
+ }
+
+
+ // Now update the screen to show the new list
+
+ // if flm_list has more than one item and its not at level 1
+ // then set the anchor to the second item.
+
+ flm = VLM_GetFirstFLM( flm_list );
+
+ if ( flm != NULL ) {
+
+ if ( ! strcmp( FLM_GetName( flm ), TEXT("..") ) ) {
+ flm = VLM_GetNextFLM( flm );
+ }
+ }
+
+ DLM_Update( win, DLM_FLATLISTBOX, WM_DLMUPDATELIST, NULL, 0 );
+
+ if ( flm != NULL ) {
+ DLM_SetAnchor( WMDS_GetWinFlatList( wininfo ), 0, (LMHANDLE)flm );
+ }
+
+
+ return( SUCCESS );
+}
+
+
+/***********************
+
+Return a pointer to the file name's extension. Really useful for
+sorting files by name extension.
+
+************************/
+
+static CHAR * VLM_GetFlmNameExt( FLM_OBJECT_PTR flm )
+{
+ CHAR *s;
+
+ s = NULL;
+
+ if ( flm ) {
+ s = FLM_GetName( flm );
+ while ( *s && ( *s != TEXT( '.' ) ) ) s++;
+ if ( *s == TEXT( '.' ) ) s++;
+ }
+
+ return( s );
+}
+
+
+#if !defined( OEM_MSOFT ) // Unsupported feature in Microsoft App
+/**********************
+
+ NAME : VLM_DisplayInfo()
+
+ DESCRIPTION :
+
+ RETURNS : nothing
+
+**********************/
+
+INT VLM_DisplayInfo ( VOID )
+{
+ HWND window;
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ FLM_OBJECT_PTR flm;
+ CHAR *s;
+ CHAR *directory;
+ INT BytesNeeded;
+ BOOL Error = TRUE;
+
+ window = WM_GetActiveDoc();
+ wininfo = WM_GetInfoPtr( window );
+
+ if ( WM_IsFlatActive( wininfo ) ) {
+
+ flm = ( FLM_OBJECT_PTR )DLM_GetFocusItem( wininfo->hWndFlatList );
+
+ if ( flm != NULL ) {
+
+ if ( ! ( FLM_GetStatus( flm ) & INFO_ISADIR ) ) {
+
+ appinfo = ( APPINFO_PTR )WMDS_GetAppInfo( wininfo );
+
+ BytesNeeded = WM_GetTitle( window, directory, 0 );
+ BytesNeeded += 1;
+ BytesNeeded *= sizeof(CHAR);
+
+ directory = malloc( BytesNeeded );
+
+ if ( directory != NULL ) {
+
+ WM_GetTitle( window, directory, BytesNeeded / sizeof(CHAR ) );
+
+ s = directory;
+ while ( *s ) {
+ s++;
+ }
+
+ while ( *s != TEXT('\\') ) {
+ s--; // skip over *.*
+ }
+
+ s++;
+ strcpy( s, FLM_GetName( flm ) );
+ while ( *s != TEXT(':') ) {
+ s--;
+ }
+
+ s++;
+
+ // Pass "\dos\bin\cl.exe"
+
+ VLM_StartSearch( s );
+ Error = FALSE;
+ }
+ }
+ }
+ }
+
+ if ( Error ) {
+
+ WM_MsgBox( ID( IDS_VLMINFOTITLE ),
+ ID( IDS_VLMINFONOFILE ),
+ WMMB_OK,
+ WMMB_ICONEXCLAMATION );
+ }
+
+ return 0;
+}
+#endif // !defined( OEM_MSOFT )
+
+/**********************
+
+ NAME : VLM_IsInfoAvailable()
+
+ DESCRIPTION :
+
+ RETURNS : TRUE, if information can be displayed. Otherwise, FALSE.
+
+**********************/
+
+BOOL VLM_IsInfoAvailable ( VOID )
+
+{
+ WININFO_PTR wininfo;
+ FLM_OBJECT_PTR flm;
+
+ wininfo = WM_GetInfoPtr( WM_GetActiveDoc() );
+
+ if ( WM_IsFlatActive( wininfo ) ) {
+
+ flm = ( FLM_OBJECT_PTR )DLM_GetFocusItem( wininfo->hWndFlatList );
+
+ if ( flm != NULL ) {
+ if ( ! ( FLM_GetStatus( flm ) & INFO_ISADIR ) ) {
+ return( TRUE );
+ }
+ }
+ }
+
+ return( FALSE );
+}
+
+
+/**********************
+
+ NAME : VLM_SelectFiles
+
+ DESCRIPTION :
+
+ The user has tagged a group of files and hit select or deselect. Find
+ out which ones are tagged and perform the selection on them.
+
+ RETURNS : nothing
+
+**********************/
+
+VOID VLM_SelectFiles(
+HWND win, // I - Tree window
+BYTE attr ) // I - select or deselect ?
+{
+ WININFO_PTR wininfo;
+ FLM_OBJECT_PTR flm;
+
+ wininfo = WM_GetInfoPtr( win );
+
+ if ( WM_IsFlatActive( wininfo ) ) {
+
+ // Have the display list manager update our tags for us.
+
+ DLM_UpdateTags( win, DLM_FLATLISTBOX );
+
+ // Process the list of file.
+
+ flm = VLM_GetFirstFLM( WMDS_GetFlatList( wininfo ) );
+
+ while ( flm != NULL ) {
+
+ if ( FLM_GetStatus( flm ) & INFO_TAGGED ) {
+
+ VLM_FlmSetSelect( flm, attr );
+ }
+
+ flm = VLM_GetNextFLM( flm );
+ }
+ }
+}
+
+
+
+
+/**********************
+
+ NAME : VLM_FlmFillInDLM
+
+ DESCRIPTION :
+
+ This window is actually created in the VLM_TREE file, but by filling in
+ the DLM structure in this file, I can make all the callback functions
+ static.
+
+ RETURNS : nothing
+
+**********************/
+
+
+VOID VLM_FlmFillInDLM( VOID_PTR dlm )
+{
+ DLM_INIT *flat_dlm;
+
+ flat_dlm = (DLM_INIT *)dlm;
+
+ DLM_GetItemCount( flat_dlm, VLM_FlmGetItemCount );
+ DLM_GetFirstItem( flat_dlm, VLM_FlmGetFirstItem );
+ DLM_GetNext( flat_dlm, VLM_FlmGetNextItem );
+ DLM_GetPrev( flat_dlm, VLM_FlmGetPrevItem );
+ DLM_GetTag( flat_dlm, VLM_FlmGetTag );
+ DLM_SetTag( flat_dlm, VLM_FlmSetTag );
+ DLM_GetSelect( flat_dlm, VLM_FlmGetSelect );
+ DLM_SetSelect( flat_dlm, VLM_FlmSetSelect );
+ DLM_GetObjects( flat_dlm, VLM_FlmGetObjects );
+ DLM_SetObjects( flat_dlm, VLM_FlmSetObjects );
+ DLM_SSetItemFocus( flat_dlm, NULL );
+ DLM_MaxNumObjects( flat_dlm, 8 );
+}
+
+
+
+/***************************************************
+
+ Name: VLM_GetFirstFLM
+
+ Description:
+
+ Get the first flm element from a queue of flm's.
+
+*****************************************************/
+
+FLM_OBJECT_PTR VLM_GetFirstFLM(
+Q_HEADER_PTR qhdr ) // I - queue header
+{
+ Q_ELEM_PTR q_elem_ptr;
+
+ if ( qhdr != NULL ) {
+
+ q_elem_ptr = QueueHead( qhdr );
+
+ if ( q_elem_ptr != NULL ) {
+ return ( FLM_OBJECT_PTR )( q_elem_ptr->q_ptr );
+ }
+ }
+ return( NULL ) ;
+}
+
+/***************************************************
+
+ Name: VLM_GetLastFLM
+
+ Description:
+
+ Get the last flm element from a queue of flm's.
+
+*****************************************************/
+
+FLM_OBJECT_PTR VLM_GetLastFLM(
+Q_HEADER_PTR qhdr ) // I - queue header
+{
+ Q_ELEM_PTR q_elem_ptr;
+
+ if ( qhdr != NULL ) {
+
+ q_elem_ptr = QueueTail( qhdr );
+
+ if ( q_elem_ptr != NULL ) {
+ return ( FLM_OBJECT_PTR )( q_elem_ptr->q_ptr );
+ }
+ }
+ return( NULL );
+}
+
+/***************************************************
+
+ Name: VLM_GetNextFLM
+
+ Description:
+
+ Get the next flm element from a queue of flm's.
+
+*****************************************************/
+
+FLM_OBJECT_PTR VLM_GetNextFLM(
+FLM_OBJECT_PTR flm_ptr ) // I - current flm
+{
+ Q_ELEM_PTR q_elem_ptr;
+
+ q_elem_ptr = QueueNext( &(flm_ptr->q_elem) );
+
+ if ( q_elem_ptr != NULL ) {
+ return ( FLM_OBJECT_PTR )( q_elem_ptr->q_ptr );
+ }
+
+ return( NULL );
+}
+
+/***************************************************
+
+ Name: VLM_GetPrevFLM
+
+ Description:
+
+ Get the previous flm element from a queue of flm's.
+
+*****************************************************/
+
+FLM_OBJECT_PTR VLM_GetPrevFLM(
+FLM_OBJECT_PTR flm_ptr ) // I - current flm
+{
+ Q_ELEM_PTR q_elem_ptr;
+
+ q_elem_ptr = QueuePrev( &(flm_ptr->q_elem) );
+
+ if ( q_elem_ptr != NULL ) {
+ return ( FLM_OBJECT_PTR )( q_elem_ptr->q_ptr );
+ }
+
+ return( NULL );
+}
+
+
+
+/***************************************************
+
+ Name: VLM_FileListReuse
+
+ Description:
+
+ Every time the user clicks on a different subdirectory this guy gets
+ called to free the previous flm list and create a new one from the
+ new path passed to it.
+
+*****************************************************/
+
+INT VLM_FileListReuse(
+HWND win, // I - tree window to use
+CHAR_PTR path ) // I - new path to display
+{
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ FLM_OBJECT_PTR flm;
+ Q_HEADER_PTR flm_list;
+ Q_ELEM_PTR q_elem;
+ INT ret;
+
+ wininfo = WM_GetInfoPtr( win );
+ appinfo = ( APPINFO_PTR )WMDS_GetAppInfo( wininfo );
+
+ flm_list = WMDS_GetFlatList( wininfo );
+
+ // Release all the old FLM structures in the queue
+
+ q_elem = DeQueueElem( flm_list );
+
+ while ( q_elem != NULL ) {
+ free( q_elem->q_ptr );
+ q_elem = DeQueueElem( flm_list );
+ }
+
+ // Now build a new FLM list
+
+ if ( appinfo->dle != NULL ) {
+
+ ret = VLM_BuildFileList( appinfo->fsh,
+ path,
+ flm_list,
+ wininfo );
+ }
+ else {
+
+ ret = VLM_BuildTapeFileList( path,
+ flm_list,
+ appinfo->tape_fid,
+ appinfo->bset_num,
+ wininfo );
+ }
+
+ // Now update the screen to show the new list
+
+ // if flm_list has more than one item and its not at level 1
+ // then set the anchor to the second item.
+
+ flm = VLM_GetFirstFLM( flm_list );
+
+ if ( flm != NULL ) {
+
+ if ( ! strcmp( FLM_GetName( flm ), TEXT("..") ) ) {
+ flm = VLM_GetNextFLM( flm );
+ }
+ }
+
+ DLM_Update( win, DLM_FLATLISTBOX, WM_DLMUPDATELIST, NULL, 0 );
+
+ if ( flm != NULL ) {
+ DLM_SetAnchor( WMDS_GetWinFlatList( wininfo ), 0, (LMHANDLE)flm );
+ }
+
+ return( ret );
+}
+
+/***************************************************
+
+ Name: VLM_FileListManager
+
+ Description:
+
+ This guy is called to force a fast selection/deselection of all
+ the files in the flat list.
+
+*****************************************************/
+
+VOID VLM_FileListManager(
+HWND win, // I - window to work with
+WORD msg ) // I - message of what to do
+{
+ WININFO_PTR wininfo;
+ FLM_OBJECT_PTR flm;
+ BOOLEAN all_subdirs;
+
+
+ all_subdirs = (BOOLEAN) CDS_GetIncludeSubdirs( CDS_GetPerm() );
+
+ wininfo = WM_GetInfoPtr( win );
+
+ if ( msg == FLM_SEL_ALL ) {
+
+ flm = VLM_GetFirstFLM( WMDS_GetFlatList( wininfo ) );
+
+ while ( flm != NULL ) {
+
+ // mark this item as selected if its a file or were including
+ // all subdirectories.
+
+ if ( ! ( FLM_GetStatus( flm ) & INFO_ISADIR ) ||
+ ( all_subdirs ) ) {
+
+ if ( ( FLM_GetStatus( flm ) & (INFO_SELECT|INFO_PARTIAL) ) != INFO_SELECT ) {
+
+ FLM_SetStatus( flm, flm->status | (UINT16)INFO_SELECT );
+ FLM_SetStatus( flm, flm->status & (UINT16)~INFO_PARTIAL );
+
+ DLM_Update( win, DLM_FLATLISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)flm, 0 );
+ }
+ }
+
+ flm = VLM_GetNextFLM( flm );
+ }
+ }
+
+ if ( msg == FLM_SEL_NONE ) {
+
+ flm = VLM_GetFirstFLM( WMDS_GetFlatList( wininfo ) );
+
+ while ( flm != NULL ) {
+
+ // mark this item as NOT selected
+
+ if ( FLM_GetStatus( flm ) & (INFO_SELECT|INFO_PARTIAL) ) {
+
+ FLM_SetStatus( flm, flm->status & (UINT16)~(INFO_SELECT|INFO_PARTIAL) );
+
+ DLM_Update( win, DLM_FLATLISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)flm, 0 );
+ }
+
+ flm = VLM_GetNextFLM( flm );
+ }
+ }
+
+}
+
+/***************************************************
+
+ Name: VLM_FillInDetails
+
+ Description:
+
+ This routine will allocate and fill in the details fields that
+ are displayed whenever the user requests to view file details.
+ To save space its not called until its needed.
+
+*****************************************************/
+
+VOID VLM_FillInDetails(
+CHAR_PTR date_buffer,
+UINT16 date,
+CHAR_PTR time_buffer,
+UINT16 time,
+CHAR_PTR attr_buffer,
+UINT32 attribute,
+BOOLEAN is_it_a_dir,
+BOOLEAN is_it_afp )
+{
+ CHAR_PTR s;
+
+ s = attr_buffer;
+
+ UI_IntToDate( date_buffer, date );
+ UI_IntToTime( time_buffer, time );
+
+ if ( is_it_a_dir ) {
+
+ if ( attribute & OBJ_READONLY_BIT ) {
+ *s++ = TEXT('R');
+ }
+ if ( attribute & OBJ_HIDDEN_BIT ) {
+ *s++ = TEXT('H');
+ }
+ if ( attribute & OBJ_SYSTEM_BIT ) {
+ *s++ = TEXT('S');
+ }
+ }
+ else {
+
+ if ( is_it_afp ) {
+ *s++ = TEXT('A');
+ *s++ = TEXT('F');
+ *s++ = TEXT('P');
+ }
+ if ( attribute & OBJ_READONLY_BIT ) {
+ *s++ = TEXT('R');
+ }
+ if ( attribute & OBJ_HIDDEN_BIT ) {
+ *s++ = TEXT('H');
+ }
+ if ( attribute & OBJ_SYSTEM_BIT ) {
+ *s++ = TEXT('S');
+ }
+ if ( attribute & OBJ_MODIFIED_BIT ) {
+ *s++ = TEXT('A');
+ }
+ if ( attribute & FILE_IN_USE_BIT ) {
+ *s++ = TEXT('I');
+ }
+ }
+ *s = 0;
+}
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+static FLM_OBJECT_PTR VLM_FindFLM(
+Q_HEADER_PTR flm_list,
+CHAR_PTR name,
+BOOLEAN directory,
+FLM_OBJECT_PTR *prev_flm )
+{
+ FLM_OBJECT_PTR flm;
+
+ // Directories are put first so if it's a dir start at the beginning.
+ // For a file start at the end and work backwards.
+ // This let's you stop quicker and search less.
+
+ if ( directory ) {
+
+ *prev_flm = NULL;
+
+ flm = VLM_GetFirstFLM( flm_list );
+
+ while ( flm ) {
+
+ // Look for end of directories.
+
+ if ( ! ( flm->status & INFO_ISADIR ) ) {
+ flm = NULL;
+ break;
+ }
+
+ if ( stricmp( name, flm->name ) < 0 ) {
+ flm = NULL;
+ break;
+ }
+
+ if ( ! stricmp( name, flm->name ) ) {
+ break;
+ }
+
+ *prev_flm = flm;
+
+ flm = VLM_GetNextFLM( flm );
+ }
+ }
+ else {
+
+ *prev_flm = NULL;
+
+ flm = VLM_GetLastFLM( flm_list );
+
+ while ( flm ) {
+
+ // Look for start of directories.
+
+ if ( flm->status & INFO_ISADIR ) {
+ flm = NULL;
+ break;
+ }
+
+ if ( stricmp( name, flm->name ) > 0 ) {
+ flm = NULL;
+ break;
+ }
+
+ if ( ! stricmp( name, flm->name ) ) {
+ break;
+ }
+
+ *prev_flm = flm;
+
+ flm = VLM_GetPrevFLM( flm );
+ }
+ }
+
+ return( flm );
+}
+
+/***************************************************
+
+ Name: VLM_BuildTapeFileList
+
+ Description:
+
+ For the given path and tape and bset info, query the catalogs
+ and build an flm list to display.
+
+*****************************************************/
+
+INT VLM_BuildTapeFileList(
+CHAR_PTR path, // I - path to get files from
+Q_HEADER_PTR flm_list, // I - queue to put items in
+UINT32 tape_fid, // I - tape family to use
+INT16 bset_num, // I - bset to use
+WININFO_PTR XtraBytes ) // I - pointer to windows xtra bytes
+{
+ INT16 result;
+ INT16 psize;
+ INT level;
+ INT BytesNeeded;
+ INT buffer_size;
+ CHAR_PTR s;
+ CHAR_PTR buffer;
+ CHAR details_buffer[ VLM_BUFFER_SIZE ];
+ QTC_QUERY_PTR query;
+ FLM_OBJECT_PTR flm;
+ FLM_OBJECT_PTR prev_flm = NULL;
+ BSD_PTR bsd_ptr;
+ FSE_PTR fse;
+ DATE_TIME acc_date;
+ DATE_TIME mod_date;
+ INT16 search_path_length;
+ CHAR_PTR search_path;
+ BOOLEAN dir_flag;
+ BOOLEAN afp_flag;
+ BOOLEAN stat ;
+ CHAR text[ MAX_UI_RESOURCE_SIZE ];
+ CHAR format_string[ MAX_UI_RESOURCE_SIZE ];
+ APPINFO_PTR appinfo;
+ BOOLEAN fLowerCase = FALSE;
+ INT SortType = SORT_BY_NAME;
+
+
+ if ( WMDS_GetMenuState( XtraBytes ) & MMDOC_SORTNAME ) {
+ SortType = SORT_BY_NAME;
+ }
+ if ( WMDS_GetMenuState( XtraBytes ) & MMDOC_SORTSIZE ) {
+ SortType = SORT_BY_SIZE;
+ }
+ if ( WMDS_GetMenuState( XtraBytes ) & MMDOC_SORTDATE ) {
+ SortType = SORT_BY_DATE;
+ }
+ if ( WMDS_GetMenuState( XtraBytes ) & MMDOC_SORTTYPE ) {
+ SortType = SORT_BY_TYPE;
+ }
+
+
+
+ RSM_StringCopy( IDS_VLMFILESSCANNED, format_string, MAX_UI_RESOURCE_LEN );
+
+ acc_date.date_valid = FALSE;
+
+ // DON'T trash the path that is passed in. It is used in the title.
+
+ buffer_size = strsize( path );
+ buffer = malloc( buffer_size );
+ if ( buffer == NULL ) {
+ return( SUCCESS );
+ }
+
+ strcpy( buffer, path );
+
+ // Tell the catalogs which bset & tape family to use
+
+ query = QTC_InitQuery();
+
+ if ( query == NULL ) {
+ free( buffer );
+ return( SUCCESS );
+ }
+
+ QTC_SetTapeFID( query, tape_fid );
+ QTC_SetTapeSeq( query, -1 );
+ QTC_SetBsetNum( query, bset_num );
+
+ // separate path from title
+
+ s = buffer;
+ s += strlen( buffer ); // work backwords from end
+
+ while ( *s != TEXT(':') ) {
+ s--;
+ }
+ while ( *s != TEXT('\\') && *s ) {
+ s++;
+ }
+ if ( *s ) {
+ s++;
+ }
+
+ search_path_length = (INT16)strsize( s );
+ search_path = s;
+
+ level = 1;
+ if ( *s ) {
+ level++;
+ }
+ while ( *s ) {
+ if ( (*s == TEXT('\\')) || (*s == 0) ) {
+ *s = 0;
+ level++;
+ }
+ s++;
+ }
+
+ QTC_SetSearchPath( query, search_path, search_path_length );
+
+ // Find the BSD for this BSET so we can do the matching later
+
+ if ( tape_fid == 0L ) {
+ appinfo = ( APPINFO_PTR )WMDS_GetAppInfo( XtraBytes );
+ bsd_ptr = BSD_FindByDLE( bsd_list, appinfo->dle );
+ }
+ else {
+ bsd_ptr = BSD_FindByTapeID( tape_bsd_list, tape_fid, bset_num );
+ }
+
+
+ // If they want to lower case everything then we will lowercase tapes.
+ // I can't tell what kind of file system it was to determine if it was
+ // FAT or not.
+
+ if ( CDS_GetFontCase( CDS_GetPerm() ) ) {
+ fLowerCase = TRUE;
+ }
+
+ result = (INT16) QTC_GetFirstObj( query );
+
+ // Check for it returning the root.
+
+ if ( strlen( QTC_GetItemName( query) ) == 0 ) {
+ strcpy( QTC_GetItemName( query ), TEXT("\\") ); // <<-- FIX THIS !!!!
+ }
+
+ while ( ! result ) {
+
+ if ( QTC_GetItemStatus( query ) & QTC_DIRECTORY ) {
+ dir_flag = TRUE;
+ }
+ else {
+ dir_flag = FALSE;
+ }
+
+ if ( QTC_GetItemStatus( query ) & QTC_AFP ) {
+ afp_flag = TRUE;
+ }
+ else {
+ afp_flag = FALSE;
+ }
+
+ VLM_FillInDetails( details_buffer, QTC_GetItemDate( query ),
+ &details_buffer[ 20 ], QTC_GetItemTime( query ),
+ &details_buffer[ 40 ], QTC_GetItemAttrib( query ),
+ dir_flag, afp_flag );
+
+ // If it doesn't find this entry already in the queue, then it
+ // will set prev_flm to the element right before where this new
+ // one should go. That way we can do an immediate insertion.
+
+ flm = VLM_FindFLM( flm_list, QTC_GetItemName( query ), dir_flag, &prev_flm );
+
+
+ // Repeated roots will have strlen == 0, don't add them.
+
+
+ if ( ( flm == NULL ) && strlen( QTC_GetItemName( query ) ) ) {
+
+ // Create the new flm and fill in some fields.
+
+ flm = VLM_CreateFlm( strsize( QTC_GetItemName( query ) ),
+ strsize( details_buffer ),
+ strsize( &details_buffer[ 20 ] ),
+ strsize( &details_buffer[ 40 ] ));
+
+ if ( flm == NULL ) {
+ break;
+ }
+
+ FLM_SetAttribute( flm, QTC_GetItemAttrib( query ) );
+ FLM_SetStatus( flm, INFO_DISPLAY | INFO_TAPE );
+ if ( QTC_GetItemStatus( query ) & QTC_CORRUPT ) {
+ FLM_SetStatus( flm, flm->status | (UINT16) INFO_CORRUPT );
+ }
+ FLM_SetLevel( flm, level );
+ FLM_SetSize( flm, QTC_GetItemSize( query ) );
+ FLM_SetXtraBytes( flm, XtraBytes );
+ FLM_SetName( flm, QTC_GetItemName( query ) );
+ FLM_SetDateString( flm, details_buffer );
+ FLM_SetTimeString( flm, &details_buffer[ 20 ] );
+ FLM_SetAttribString( flm, &details_buffer[ 40 ] );
+
+
+ U64_Litoa( FLM_GetSize( flm ), details_buffer, (INT16) 10, &stat );
+ details_buffer[ FLM_MAX_FILE_SIZE - 1 ] = 0;
+ FLM_SetSizeString( flm, details_buffer );
+
+ // Convert to the big date time structure
+ // from the compressed DOS structure the catalogs store
+
+ FLM_SetModDate( flm, QTC_GetItemDate( query ) );
+ FLM_SetModTime( flm, QTC_GetItemTime( query ) );
+
+
+ // Lowercase it
+
+ if ( fLowerCase ) {
+
+ strlwr( FLM_GetName( flm ) );
+ strlwr( FLM_GetAttribString( flm ) );
+ }
+
+ // See if we can set any special flags
+
+ if ( QTC_GetItemStatus( query ) & QTC_CORRUPT ) {
+ FLM_SetStatus( flm, flm->status | (UINT16)INFO_CORRUPT );
+ }
+
+#if !defined ( OEM_MSOFT ) //unsupported feature
+
+ if ( QTC_GetItemStatus( query ) & QTC_EMPTY ) {
+ FLM_SetStatus( flm, flm->status | (UINT16)INFO_EMPTY );
+ }
+
+#endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ if ( dir_flag ) {
+ FLM_SetStatus( flm, flm->status | (UINT16)INFO_ISADIR );
+ }
+ else {
+
+ s = FLM_GetName( flm );
+
+ while ( *s && *s != TEXT('.') ) s++;
+
+ if ( ! stricmp( s, TEXT(".EXE") ) || ! stricmp( s, TEXT(".COM") ) ||
+#if defined ( WIN32 )
+ ! stricmp( s, TEXT(".CMD") ) ||
+#endif
+ ! stricmp( s, TEXT(".BAT") ) || ! stricmp( s, TEXT(".PIF") ) ) {
+ FLM_SetStatus( flm, flm->status | (UINT16)INFO_EXEFILE );
+ }
+ }
+
+ // Now use the BSD_Match function to see if it's selected already
+
+ if ( bsd_ptr != NULL ) {
+
+ DateTimeDOS( FLM_GetModDate( flm ),
+ FLM_GetModTime( flm ), &mod_date );
+
+ if ( dir_flag ) {
+
+ BytesNeeded = query->path_size + strsize( FLM_GetName( flm ) );
+ if ( BytesNeeded > buffer_size ) {
+ free( buffer );
+ buffer = malloc( BytesNeeded );
+ buffer_size = BytesNeeded;
+ }
+
+ if ( query->path_size != sizeof (CHAR) ) {
+ memcpy( buffer, QTC_GetPath( query ), QTC_GetPathLength( query ) );
+ strcpy( &buffer[ QTC_GetPathLength( query )/sizeof (CHAR) ], flm->name );
+ psize = (INT16)(QTC_GetPathLength( query ) + strsize(flm->name) );
+ }
+ else {
+ strcpy( buffer, FLM_GetName( flm ) );
+ psize = (UINT16)strsize( FLM_GetName( flm ));
+ }
+
+
+ result = BSD_MatchPathAndFile( bsd_ptr, &fse, NULL,
+ buffer,
+ psize,
+ FLM_GetAttribute( flm ),
+ &mod_date, &acc_date, NULL,
+ FALSE, TRUE );
+
+ if ( result == BSD_PROCESS_OBJECT ) {
+
+ FLM_SetStatus( flm, flm->status | (UINT16)(INFO_SELECT | INFO_PARTIAL) );
+ }
+
+ if ( result == BSD_PROCESS_ENTIRE_DIR ) {
+
+ FLM_SetStatus( flm, flm->status | (UINT16)INFO_SELECT ); // turn red check mark on
+ }
+
+ }
+ else {
+
+ result = BSD_MatchPathAndFile( bsd_ptr, &fse,
+ FLM_GetName( flm ),
+ QTC_GetPath( query ),
+ (INT16) QTC_GetPathLength( query ),
+ FLM_GetAttribute( flm ),
+ &mod_date, &acc_date, NULL,
+ FALSE, TRUE );
+
+ if ( result == BSD_PROCESS_OBJECT ) {
+
+ // turn red check mark on
+
+ FLM_SetStatus( flm, flm->status | (UINT16)INFO_SELECT );
+ }
+ }
+
+ }
+
+ // Insert the new flm in the queue in the proper place. 75 % of
+ // the time we will insert the new one after the last one we
+ // inserted. So we use prev_flm to speed up the "find the right
+ // location to insert" process. And it really works.
+
+ VLM_InsertFlmInQueue( flm_list, flm, prev_flm, SortType );
+
+ prev_flm = flm;
+ }
+
+ // tell the user how many files we've found so far.
+
+ if ( ! ( QueueCount( flm_list ) % 10 ) ) {
+ sprintf( text, format_string, QueueCount( flm_list ) ) ;
+ STM_DrawText( text ) ;
+ }
+
+ // get the next file/dir.
+
+ result = (INT16) QTC_GetNextObj( query );
+ }
+
+ free( buffer );
+
+ QTC_CloseQuery( query );
+
+ // We need to insert a ".." fake entry here if we are not in the root.
+
+ if ( level != 1 ) {
+
+ flm = VLM_CreateFlm( strsize( TEXT("..") ),
+ sizeof(CHAR),
+ sizeof(CHAR),
+ sizeof(CHAR) );
+
+ if ( flm != NULL ) {
+
+ FLM_SetStatus( flm, INFO_DISPLAY | INFO_TAPE | INFO_ISADIR );
+ FLM_SetLevel( flm, level );
+ FLM_SetXtraBytes( flm, XtraBytes );
+ FLM_SetName( flm, TEXT("..") );
+ FLM_SetDateString( flm, TEXT("") );
+ FLM_SetTimeString( flm, TEXT("") );
+ FLM_SetAttribString( flm, TEXT("") );
+
+ if ( QueueCount( flm_list ) ) {
+ InsertElem( flm_list, QueueHead(flm_list), &(flm->q_elem), BEFORE );
+ }
+ else {
+ EnQueueElem( flm_list, &(flm->q_elem), FALSE );
+ }
+ }
+ }
+
+ VLM_SetMaxFlmSize( flm_list );
+
+ STM_DrawIdle( );
+
+ return( SUCCESS );
+}
+
+
+/***************************************************
+
+ Name: VLM_CreateFlm
+
+ Description:
+
+ Create a new FLM structure.
+
+ Returns: Null or the new pointer.
+
+*****************************************************/
+
+static FLM_OBJECT_PTR VLM_CreateFlm(
+INT name_size,
+INT date_size,
+INT time_size,
+INT attrib_size )
+{
+ FLM_OBJECT_PTR flm;
+
+ // All sizes are in bytes.
+
+ flm = ( FLM_OBJECT_PTR )malloc( sizeof(FLM_OBJECT) + name_size +
+ date_size +
+ time_size +
+ attrib_size );
+
+ if ( flm != NULL ) {
+
+ flm->name = (CHAR_PTR)((INT8_PTR)flm + sizeof(FLM_OBJECT));
+ flm->date_str = (CHAR_PTR)((INT8_PTR)flm->name + name_size);
+ flm->time_str = (CHAR_PTR)((INT8_PTR)flm->date_str + date_size );
+ flm->attrib_str = (CHAR_PTR)((INT8_PTR)flm->time_str + time_size );
+ flm->q_elem.q_ptr = flm;
+ }
+
+ return( flm );
+}
+
+/***************************************************
+
+ Name: VLM_BuildFileList
+
+ Description:
+
+ For the fsh and base passed, build a list of all the files so that
+ they can be displayed.
+
+ Returns: last FS_xxx code from the file system
+
+ usually FS_NO_MORE or FS_ACCESS_DENIED
+
+
+*****************************************************/
+
+INT VLM_BuildFileList(
+FSYS_HAND fsh, // I - file system handle
+CHAR_PTR base, // I - base path to use
+Q_HEADER_PTR flm_list, // I - queue to add stuff to
+WININFO_PTR XtraBytes ) // I - windows xtrabytes pointer
+{
+ INT16 ret;
+ INT16 psize;
+ INT16 orig_psize;
+ INT16 path_len;
+ CHAR details_buffer[ VLM_BUFFER_SIZE ];
+ CHAR_PTR buffer = NULL;
+ CHAR_PTR path = NULL;
+ CHAR_PTR name = NULL;
+ CHAR_PTR s;
+ FLM_OBJECT_PTR flm;
+ FLM_OBJECT_PTR prev_flm = NULL;
+ APPINFO_PTR appinfo;
+ FSE_PTR fse;
+ BSD_PTR bsd_ptr;
+ DBLK dblk;
+ DATE_TIME acc_date;
+ DATE_TIME mod_date;
+ BOOLEAN dir_flag;
+ BOOLEAN afp_flag;
+ BOOLEAN stat;
+ OBJECT_TYPE object_type;
+ CHAR text[ MAX_UI_RESOURCE_SIZE ];
+ CHAR format_string[ MAX_UI_RESOURCE_SIZE ];
+ SLM_OBJECT_PTR slm;
+ BOOLEAN fLowerCase = FALSE;
+ INT SortType = SORT_BY_NAME;
+ INT buffer_size = 0;
+
+ RSM_StringCopy( IDS_VLMFILESSCANNED, format_string, MAX_UI_RESOURCE_LEN );
+
+ buffer = malloc( VLM_BUFFER_SIZE );
+ buffer_size = VLM_BUFFER_SIZE;
+
+ path = malloc( strsize( base ) );
+
+ if ( path == NULL || buffer == NULL ) {
+ free( buffer );
+ free( path );
+ return( FAILURE );
+ }
+
+ s = base;
+ s += strlen( base ); // go to the end
+
+ while ( *s != TEXT(':') ) {
+ s--;
+ }
+
+ while ( *s != TEXT('\\') && *s ) {
+ s++;
+ }
+
+ if ( *s ) {
+ s++;
+ }
+
+ strcpy( path, s );
+
+ // determine the path length and turn \'s into 0's
+
+ path_len = 0;
+
+ while ( path[ path_len ] ) {
+
+ if ( path[ path_len ] == TEXT('\\') ) {
+ path[ path_len ] = 0;
+ }
+ path_len++;
+ }
+ path_len++;
+
+ path_len *= sizeof(CHAR);
+
+ appinfo = ( APPINFO_PTR )WMDS_GetAppInfo( XtraBytes );
+
+
+ if ( WMDS_GetMenuState( XtraBytes ) & MMDOC_SORTNAME ) {
+ SortType = SORT_BY_NAME;
+ }
+ if ( WMDS_GetMenuState( XtraBytes ) & MMDOC_SORTSIZE ) {
+ SortType = SORT_BY_SIZE;
+ }
+ if ( WMDS_GetMenuState( XtraBytes ) & MMDOC_SORTDATE ) {
+ SortType = SORT_BY_DATE;
+ }
+ if ( WMDS_GetMenuState( XtraBytes ) & MMDOC_SORTTYPE ) {
+ SortType = SORT_BY_TYPE;
+ }
+
+
+ // make sure the dirs have been blown out for this parent
+
+ slm = VLM_FindSLM( WMDS_GetTreeList( XtraBytes ), path, path_len );
+
+ VLM_BlowOutDir( slm );
+
+ ret = FS_ChangeDir( fsh, path, path_len );
+
+ if ( ret != SUCCESS ) {
+
+ zprintf ( DEBUG_TEMPORARY, TEXT("FS_ChangeDir failed %04X"), ret );
+ return( ret );
+ }
+
+ // Try to find the BSD for use with BSD_Match later
+
+ bsd_ptr = BSD_FindByDLE( bsd_list, appinfo->dle );
+
+ if ( CDS_GetFontCase( CDS_GetPerm() ) ) {
+ fLowerCase = TRUE;
+ }
+ else {
+ if ( CDS_GetFontCaseFAT( CDS_GetPerm() ) ) {
+
+ // Change this to DLE_FEATURE_FAT_DRIVE
+
+ if ( ! DLE_HasFeatures( appinfo->dle, DLE_FEAT_CASE_PRESERVING ) ) {
+ fLowerCase = TRUE;
+ }
+ }
+ }
+
+ ret = FS_FindFirstObj( fsh, &dblk, TEXT("*.*") );
+
+
+ if ( ret != SUCCESS ) {
+
+ // Only insert this FLM if there are no items in this directory
+ // Otherwise wait till your done sorting, then insert it.
+ // Insert the special ".." entry.
+
+ if ( path_len != sizeof ( CHAR ) ) {
+
+ flm = VLM_CreateFlm( strsize(TEXT("..")),
+ sizeof(CHAR),
+ sizeof(CHAR),
+ sizeof(CHAR) );
+
+ if ( flm ) {
+ FLM_SetStatus( flm, INFO_DISPLAY | INFO_ISADIR );
+ FLM_SetAttribute( flm, 0 );
+ FLM_SetSize( flm, U64_Init(0L, 0L) );
+ FLM_SetXtraBytes( flm, XtraBytes );
+ FLM_SetName( flm, TEXT("..") );
+ FLM_SetDateString( flm, TEXT("") );
+ FLM_SetTimeString( flm, TEXT("") );
+ FLM_SetAttribString( flm, TEXT("") );
+ EnQueueElem( flm_list, &(flm->q_elem), FALSE );
+ }
+ }
+
+ VLM_SetMaxFlmSize( flm_list );
+
+ STM_DrawIdle( );
+
+ return( ret );
+ }
+
+ do {
+
+ // Was it a directory name we got ?
+
+ if ( FS_GetBlockType( &dblk ) == DDB_ID ) {
+
+ orig_psize = FS_SizeofOSPathInDDB( fsh, &dblk );
+
+ if ( buffer_size < orig_psize ) {
+ free( buffer );
+ buffer = malloc( orig_psize + 256 );
+ buffer_size = orig_psize + 256;
+ }
+
+ FS_GetOSPathFromDDB( fsh, &dblk, buffer );
+
+ psize = (INT16) (orig_psize - sizeof(CHAR));
+ psize /= sizeof(CHAR);
+
+ do {
+ psize--;
+ } while ( psize && buffer[ psize ] );
+
+ if ( psize ) {
+ psize++;
+ }
+ name = &buffer[ psize ];
+
+ slm = VLM_FindSLM( WMDS_GetTreeList( XtraBytes ), buffer, orig_psize );
+ }
+
+ // Was it a file we got ?
+
+ if ( FS_GetBlockType( &dblk ) == FDB_ID ) {
+ FS_GetOSFnameFromFDB( fsh, &dblk, buffer );
+ name = buffer;
+ dir_flag = FALSE;
+ }
+ else {
+ dir_flag = TRUE;
+ }
+
+ FS_GetObjTypeDBLK( fsh, &dblk, &object_type );
+
+ if ( object_type == AFP_OBJECT ) {
+ afp_flag = TRUE;
+ }
+ else {
+ afp_flag = FALSE;
+ }
+
+ FS_GetMDateFromDBLK( fsh, &dblk, &mod_date );
+
+ VLM_FillInDetails( details_buffer, ConvertDateDOS( &mod_date ),
+ &details_buffer[ 20 ], ConvertTimeDOS( &mod_date ),
+ &details_buffer[ 40 ], FS_GetAttribFromDBLK( fsh, &dblk ),
+ dir_flag, afp_flag );
+
+
+ if ( fLowerCase ) {
+ strlwr( &details_buffer[ 40 ] ); // lower case attributes
+ strlwr( name ); // lower case file name
+ }
+
+
+ flm = VLM_CreateFlm( strsize( name ),
+ strsize( details_buffer ),
+ strsize( &details_buffer[ 20 ] ),
+ strsize( &details_buffer[ 40 ] ) );
+
+ if ( flm == NULL ) {
+ break;
+ }
+
+ FLM_SetStatus( flm, INFO_DISPLAY );
+ FLM_SetAttribute( flm, FS_GetAttribFromDBLK( fsh, &dblk ) );
+ FLM_SetSize( flm, FS_GetDisplaySizeFromDBLK( fsh, &dblk ) );
+ FLM_SetXtraBytes( flm, XtraBytes );
+ FLM_SetName( flm, name );
+ FLM_SetDateString( flm, details_buffer );
+ FLM_SetTimeString( flm, &details_buffer[ 20 ] );
+ FLM_SetAttribString( flm, &details_buffer[ 40 ] );
+
+ U64_Litoa( FLM_GetSize( flm ), details_buffer, (INT16) 10, &stat );
+ details_buffer[ FLM_MAX_FILE_SIZE - 1 ] = 0;
+ FLM_SetSizeString( flm, details_buffer );
+
+ FLM_SetModDate( flm, ConvertDateDOS( &mod_date ) );
+ FLM_SetModTime( flm, ConvertTimeDOS( &mod_date ) );
+
+ FS_GetADateFromDBLK( fsh, &dblk, &acc_date );
+ FLM_SetAccDate( flm, ConvertDateDOS( &acc_date ) );
+ FLM_SetAccTime( flm, ConvertTimeDOS( &acc_date ) );
+
+ // Try to set some special flags
+
+ if ( FS_GetBlockType( &dblk ) == DDB_ID ) {
+ FLM_SetStatus( flm, flm->status | (UINT16)INFO_ISADIR );
+
+#if !defined ( OEM_MSOFT ) //unsupported feature
+
+ if ( SLM_GetStatus( slm ) & INFO_EMPTY ) {
+ FLM_SetStatus( flm, flm->status | (UINT16)INFO_EMPTY );
+ }
+
+#endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ }
+ else {
+
+ s = flm->name;
+
+ while ( *s && *s != TEXT('.') ) s++;
+
+ if ( ! stricmp( s, TEXT(".EXE") ) || ! stricmp( s, TEXT(".COM") ) ||
+ ! stricmp( s, TEXT(".CMD") ) ||
+ ! stricmp( s, TEXT(".BAT") ) || ! stricmp( s, TEXT(".PIF") ) ) {
+
+ FLM_SetStatus( flm, flm->status | (UINT16)INFO_EXEFILE );
+ }
+ }
+
+ // See if this guys already selected
+
+ if ( bsd_ptr != NULL ) {
+
+ if ( FLM_GetStatus( flm ) & INFO_ISADIR ) {
+
+ ret = BSD_MatchPathAndFile( bsd_ptr, &fse, NULL,
+ buffer,
+ orig_psize,
+ FLM_GetAttribute( flm ),
+ &mod_date, &acc_date,
+ NULL, FALSE, TRUE );
+
+ if ( ret == BSD_PROCESS_OBJECT ) {
+
+ FLM_SetStatus( flm, flm->status | (UINT16) (INFO_SELECT | INFO_PARTIAL) );
+ }
+ if ( ret == BSD_PROCESS_ENTIRE_DIR ) {
+
+ FLM_SetStatus( flm, flm->status | (UINT16)INFO_SELECT ); // turn red check mark on
+ }
+ }
+ else {
+ ret = BSD_MatchPathAndFile( bsd_ptr, &fse,
+ FLM_GetName( flm ),
+ path, path_len,
+ FLM_GetAttribute( flm ),
+ &mod_date, &acc_date,
+ NULL, FALSE, TRUE );
+
+ if ( ret == BSD_PROCESS_OBJECT ) {
+ FLM_SetStatus( flm, flm->status | (UINT16)INFO_SELECT ); // set the little red check mark
+ }
+ }
+ }
+
+ VLM_InsertFlmInQueue( flm_list, flm, prev_flm, SortType );
+
+ prev_flm = flm;
+
+ if ( ! ( QueueCount( flm_list ) % 10 ) ) {
+ sprintf( text, format_string, QueueCount( flm_list ) ) ;
+ STM_DrawText( text ) ;
+ }
+
+ FS_ReleaseDBLK( fsh, &dblk );
+
+ ret = FS_FindNextObj( fsh, &dblk );
+
+ } while ( ret == SUCCESS );
+
+ FS_FindObjClose( fsh, &dblk );
+
+ free( path );
+ free( buffer );
+
+ // Now after sorting insert first element at start !
+
+ if ( path_len != sizeof(CHAR) ) {
+
+ flm = VLM_CreateFlm( strsize( TEXT("..") ),
+ sizeof(CHAR),
+ sizeof(CHAR),
+ sizeof(CHAR) );
+
+ if ( flm ) {
+ FLM_SetStatus( flm, INFO_DISPLAY | INFO_ISADIR );
+ FLM_SetAttribute( flm, 0 );
+ FLM_SetSize( flm, U64_Init(0L, 0L) );
+ FLM_SetXtraBytes( flm, XtraBytes );
+ FLM_SetName( flm, TEXT("..") );
+ FLM_SetDateString( flm, TEXT("") );
+ FLM_SetTimeString( flm, TEXT("") );
+ FLM_SetAttribString( flm, TEXT("") );
+
+ if ( QueueCount( flm_list ) ) {
+ InsertElem( flm_list, QueueHead(flm_list), &(flm->q_elem), BEFORE );
+ }
+ else {
+ EnQueueElem( flm_list, &(flm->q_elem), FALSE );
+ }
+ }
+ }
+
+ VLM_SetMaxFlmSize( flm_list );
+
+ STM_DrawIdle( );
+
+ return( ret );
+}
+
+/**********************
+
+ NAME : VLM_InsertFlmInQueue
+
+ DESCRIPTION :
+
+ This routine handles all the sorting.
+
+
+ RETURNS :
+
+**********************/
+
+static VOID VLM_InsertFlmInQueue(
+Q_HEADER_PTR flm_list,
+FLM_OBJECT_PTR flm,
+FLM_OBJECT_PTR prev_flm,
+INT SortType )
+{
+ if ( ! strcmp( FLM_GetName( flm ), TEXT("..") ) ) {
+ if ( QueueCount( flm_list ) == 0 ) {
+ EnQueueElem( flm_list, &(flm->q_elem), FALSE );
+ }
+ else {
+ InsertElem( flm_list, QueueHead(flm_list), &(flm->q_elem), BEFORE );
+ }
+ }
+
+ else if ( QueueCount( flm_list ) == 0 ) {
+ EnQueueElem( flm_list, &(flm->q_elem), FALSE );
+ }
+
+ else {
+
+ switch ( SortType ) {
+
+ case SORT_BY_SIZE:
+ VLM_InsertFlmBySize( flm_list, flm, prev_flm );
+ break;
+
+ case SORT_BY_DATE:
+ VLM_InsertFlmByDate( flm_list, flm, prev_flm );
+ break;
+
+ case SORT_BY_TYPE:
+ VLM_InsertFlmByExtn( flm_list, flm, prev_flm );
+ break;
+
+ case SORT_BY_NAME:
+ default:
+ VLM_InsertFlmByName( flm_list, flm, prev_flm );
+ break;
+ }
+ }
+ return;
+}
+
+/**********************
+
+ NAME : VLM_InsertFlmByName
+
+ DESCRIPTION : Insert a new flm entry sorted by name.
+
+ RETURNS : nothing.
+
+**********************/
+
+static VOID VLM_InsertFlmByName(
+Q_HEADER_PTR flm_list,
+FLM_OBJECT_PTR flm,
+FLM_OBJECT_PTR prev_flm )
+{
+ FLM_OBJECT_PTR flm1, flm2;
+
+ if ( ! ( flm->status & INFO_ISADIR ) ) {
+
+ flm1 = VLM_GetLastFLM( flm_list );
+
+ if ( prev_flm ) {
+ if ( ! ( prev_flm->status & INFO_ISADIR ) ) {
+
+ if ( stricmp( FLM_GetName( flm ),
+ FLM_GetName( prev_flm ) ) < 0 ) {
+
+ // We got lucky !
+
+ flm1 = prev_flm;
+ }
+ }
+ }
+
+ while ( flm1 ) {
+
+ if ( flm1->status & INFO_ISADIR ) {
+ break;
+ }
+
+ if ( stricmp( FLM_GetName( flm ),
+ FLM_GetName( flm1 ) ) >= 0 ) {
+ break;
+ }
+
+ flm2 = flm1;
+ flm1 = VLM_GetPrevFLM( flm1 );
+ }
+
+ if ( flm1 == NULL ) {
+ InsertElem( flm_list, &(flm2->q_elem), &(flm->q_elem), BEFORE );
+ }
+ else {
+ InsertElem( flm_list, &(flm1->q_elem), &(flm->q_elem), AFTER );
+ }
+
+ }
+ else {
+
+ flm1 = VLM_GetFirstFLM( flm_list );
+
+ // Try to start positioning at last flm inserted.
+
+ if ( prev_flm ) {
+ if ( prev_flm->status & INFO_ISADIR ) {
+
+ if ( stricmp( FLM_GetName( flm ),
+ FLM_GetName( prev_flm ) ) >= 0 ) {
+
+ // We got lucky !
+
+ flm1 = prev_flm;
+ }
+ }
+ }
+
+ while ( flm1 ) {
+
+ if ( ! ( flm1->status & INFO_ISADIR ) ) {
+ break;
+ }
+ if ( stricmp( FLM_GetName( flm ),
+ FLM_GetName( flm1 ) ) < 0 ) {
+ break;
+ }
+ flm2 = flm1;
+ flm1 = VLM_GetNextFLM( flm1 );
+ }
+
+ if ( flm1 == NULL ) {
+ InsertElem( flm_list, &(flm2->q_elem), &(flm->q_elem), AFTER );
+ }
+ else {
+ InsertElem( flm_list, &(flm1->q_elem), &(flm->q_elem), BEFORE );
+ }
+ }
+
+ return;
+}
+
+/**********************
+
+ NAME : VLM_InsertFlmByDate
+
+ DESCRIPTION : Insert a new flm entry sorted by date.
+
+ RETURNS : nothing.
+
+**********************/
+
+static VOID VLM_InsertFlmByDate(
+Q_HEADER_PTR flm_list,
+FLM_OBJECT_PTR flm,
+FLM_OBJECT_PTR prev_flm )
+{
+ FLM_OBJECT_PTR flm1, flm2;
+
+ if ( ! ( flm->status & INFO_ISADIR ) ) {
+
+ flm1 = VLM_GetLastFLM( flm_list );
+
+ if ( prev_flm ) {
+ if ( ! ( prev_flm->status & INFO_ISADIR ) ) {
+
+ if ( FLM_GetModDate( flm ) == FLM_GetModDate( prev_flm ) ) {
+ if ( FLM_GetModTime( flm ) > FLM_GetModTime( prev_flm ) ) {
+ // We got lucky !
+ flm1 = prev_flm;
+ }
+ }
+ else {
+ if ( FLM_GetModDate( flm ) > FLM_GetModDate( prev_flm ) ) {
+ // We got lucky !
+ flm1 = prev_flm;
+ }
+ }
+ }
+ }
+
+ while ( flm1 ) {
+
+ if ( flm1->status & INFO_ISADIR ) {
+ break;
+ }
+
+ if ( FLM_GetModDate( flm ) == FLM_GetModDate( flm1 ) ) {
+ if ( FLM_GetModTime( flm ) <= FLM_GetModTime( flm1 ) ) {
+ break;
+ }
+ }
+ else {
+ if ( FLM_GetModDate( flm ) <= FLM_GetModDate( flm1 ) ) {
+ break;
+ }
+ }
+
+ flm2 = flm1;
+ flm1 = VLM_GetPrevFLM( flm1 );
+ }
+
+ if ( flm1 == NULL ) {
+ InsertElem( flm_list, &(flm2->q_elem), &(flm->q_elem), BEFORE );
+ }
+ else {
+ InsertElem( flm_list, &(flm1->q_elem), &(flm->q_elem), AFTER );
+ }
+
+ }
+ else {
+
+ flm1 = VLM_GetFirstFLM( flm_list );
+
+ // Try to start positioning at last flm inserted.
+
+ if ( prev_flm ) {
+ if ( prev_flm->status & INFO_ISADIR ) {
+
+ if ( FLM_GetModDate( flm ) == FLM_GetModDate( prev_flm ) ) {
+ if ( FLM_GetModTime( flm ) <= FLM_GetModTime( prev_flm ) ) {
+
+ // We got lucky !
+ flm1 = prev_flm;
+ }
+ }
+ else {
+ if ( FLM_GetModDate( flm ) <= FLM_GetModDate( prev_flm ) ) {
+
+ // We got lucky !
+ flm1 = prev_flm;
+ }
+ }
+ }
+ }
+
+ while ( flm1 ) {
+
+ if ( ! ( flm1->status & INFO_ISADIR ) ) {
+ break;
+ }
+ if ( FLM_GetModDate( flm ) == FLM_GetModDate( flm1 ) ) {
+
+ if ( FLM_GetModTime( flm ) > FLM_GetModTime( flm1 ) ) {
+ break;
+ }
+ }
+ else {
+ if ( FLM_GetModDate( flm ) > FLM_GetModDate( flm1 ) ) {
+ break;
+ }
+ }
+ flm2 = flm1;
+ flm1 = VLM_GetNextFLM( flm1 );
+ }
+
+ if ( flm1 == NULL ) {
+ InsertElem( flm_list, &(flm2->q_elem), &(flm->q_elem), AFTER );
+ }
+ else {
+ InsertElem( flm_list, &(flm1->q_elem), &(flm->q_elem), BEFORE );
+ }
+ }
+
+ return;
+}
+
+/**********************
+
+ NAME : VLM_InsertFlmBySize
+
+ DESCRIPTION : Insert a new flm entry sorted by size.
+
+ RETURNS : nothing.
+
+**********************/
+
+static VOID VLM_InsertFlmBySize(
+Q_HEADER_PTR flm_list,
+FLM_OBJECT_PTR flm,
+FLM_OBJECT_PTR prev_flm )
+{
+ FLM_OBJECT_PTR flm1, flm2;
+
+ if ( ! ( flm->status & INFO_ISADIR ) ) {
+
+ flm1 = VLM_GetLastFLM( flm_list );
+
+ if ( prev_flm ) {
+ if ( ! ( prev_flm->status & INFO_ISADIR ) ) {
+
+ if ( U64_GE( FLM_GetSize( flm ), FLM_GetSize( prev_flm ) ) ) {
+
+ // We got lucky !
+
+ flm1 = prev_flm;
+ }
+ }
+ }
+
+ while ( flm1 ) {
+
+ if ( flm1->status & INFO_ISADIR ) {
+ break;
+ }
+
+ if ( U64_LT( FLM_GetSize( flm ), FLM_GetSize( flm1 ) ) ) {
+ break;
+ }
+
+ flm2 = flm1;
+ flm1 = VLM_GetPrevFLM( flm1 );
+ }
+
+ if ( flm1 == NULL ) {
+ InsertElem( flm_list, &(flm2->q_elem), &(flm->q_elem), BEFORE );
+ }
+ else {
+ InsertElem( flm_list, &(flm1->q_elem), &(flm->q_elem), AFTER );
+ }
+
+ }
+ else {
+
+ flm1 = VLM_GetFirstFLM( flm_list );
+
+ // Try to start positioning at last flm inserted.
+
+ if ( prev_flm ) {
+
+ if ( prev_flm->status & INFO_ISADIR ) {
+
+ if ( U64_LT( FLM_GetSize( flm ), FLM_GetSize( prev_flm ) ) ) {
+
+ // We got lucky !
+
+ flm1 = prev_flm;
+ }
+ }
+ }
+
+ while ( flm1 ) {
+
+ if ( ! ( flm1->status & INFO_ISADIR ) ) {
+ break;
+ }
+ if ( U64_GE( FLM_GetSize( flm ), FLM_GetSize( flm1 ) ) ) {
+ break;
+ }
+ flm2 = flm1;
+ flm1 = VLM_GetNextFLM( flm1 );
+ }
+
+ if ( flm1 == NULL ) {
+ InsertElem( flm_list, &(flm2->q_elem), &(flm->q_elem), AFTER );
+ }
+ else {
+ InsertElem( flm_list, &(flm1->q_elem), &(flm->q_elem), BEFORE );
+ }
+ }
+
+ return;
+}
+
+
+
+
+
+/**********************
+
+ NAME : VLM_InsertFlmByExtn
+
+ DESCRIPTION : Insert a new flm entry sorted by extension.
+
+ RETURNS : nothing.
+
+**********************/
+
+static VOID VLM_InsertFlmByExtn(
+Q_HEADER_PTR flm_list,
+FLM_OBJECT_PTR flm,
+FLM_OBJECT_PTR prev_flm )
+{
+ FLM_OBJECT_PTR flm1, flm2;
+ CHAR *ext, *ext1, *prev_ext; // pointers to file extensions
+
+ ext = VLM_GetFlmNameExt( flm );
+
+ if ( ! ( flm->status & INFO_ISADIR ) ) {
+
+ flm1 = VLM_GetLastFLM( flm_list );
+
+ if ( prev_flm ) {
+
+ prev_ext = VLM_GetFlmNameExt( prev_flm );
+
+ if ( ! ( prev_flm->status & INFO_ISADIR ) ) {
+
+ if ( stricmp( ext, prev_ext ) < 0 ) {
+
+ // We got lucky !
+
+ flm1 = prev_flm;
+ ext1 = VLM_GetFlmNameExt( flm1 );;
+ }
+ }
+ }
+
+ while ( flm1 ) {
+
+ ext1 = VLM_GetFlmNameExt( flm1 );
+
+ if ( flm1->status & INFO_ISADIR ) {
+ break;
+ }
+
+ if ( stricmp( ext, ext1 ) == 0 ) {
+ if ( stricmp( FLM_GetName( flm ), FLM_GetName( flm1 ) ) > 0 ) {
+ break;
+ }
+ }
+
+ else if ( stricmp( ext, ext1 ) > 0 ) {
+ break;
+ }
+
+ flm2 = flm1;
+ flm1 = VLM_GetPrevFLM( flm1 );
+
+ }
+
+ if ( flm1 == NULL ) {
+ InsertElem( flm_list, &(flm2->q_elem), &(flm->q_elem), BEFORE );
+ }
+ else {
+ InsertElem( flm_list, &(flm1->q_elem), &(flm->q_elem), AFTER );
+ }
+
+ }
+ else {
+
+ flm1 = VLM_GetFirstFLM( flm_list );
+
+ // Try to start positioning at last flm inserted.
+
+ if ( prev_flm ) {
+
+ prev_ext = VLM_GetFlmNameExt( prev_flm );
+
+ if ( prev_flm->status & INFO_ISADIR ) {
+
+ if ( stricmp( ext, prev_ext ) > 0 ) {
+
+ // We got lucky !
+
+ flm1 = prev_flm;
+ ext1 = VLM_GetFlmNameExt( flm1 );
+ }
+ }
+ }
+
+ while ( flm1 ) {
+
+ ext1 = VLM_GetFlmNameExt( flm1 );
+
+ if ( ! ( flm1->status & INFO_ISADIR ) ) {
+ break;
+ }
+
+ if ( stricmp( ext, ext1 ) == 0 ) {
+ if ( stricmp( FLM_GetName( flm ), FLM_GetName( flm1 ) ) < 0 ) {
+ break;
+ }
+ }
+
+ else if ( stricmp( ext, ext1 ) < 0 ) {
+ break;
+ }
+
+ flm2 = flm1;
+ flm1 = VLM_GetNextFLM( flm1 );
+ }
+
+ if ( flm1 == NULL ) {
+ InsertElem( flm_list, &(flm2->q_elem), &(flm->q_elem), AFTER );
+ }
+ else {
+ InsertElem( flm_list, &(flm1->q_elem), &(flm->q_elem), BEFORE );
+ }
+ }
+
+ return;
+}
+
+
+/**********************
+
+ NAME : VLM_SetMaxFlmSize
+
+ DESCRIPTION : Set the max name string length in all the flm's.
+
+ RETURNS : nothing.
+
+**********************/
+
+static VOID VLM_SetMaxFlmSize( Q_HEADER_PTR flm_list )
+{
+ UINT name_max = 0;
+ UINT date_max = 0;
+ UINT time_max = 0;
+ UINT attr_max = 0;
+ UINT size_max = 3;
+ FLM_OBJECT_PTR flm;
+ UINT64 kilo;
+ UINT64 mega;
+ UINT64 giga;
+
+ // I know there must be an easier way !
+
+ kilo = U64_Init( 999L , 0L );
+ mega = U64_Init( 999999L, 0L );
+ giga = U64_Init( 999999999L, 0L );
+
+ // Calculate the max.
+
+ flm = VLM_GetFirstFLM( flm_list );
+
+ while ( flm != NULL ) {
+
+ if ( U64_GE( flm->size, kilo ) && ( size_max < 6 ) ) {
+ size_max = 6;
+ }
+
+ if ( U64_GE( flm->size, mega ) && ( size_max < 9 ) ) {
+ size_max = 9;
+ }
+
+ if ( U64_GE( flm->size, giga ) && ( size_max < 12 ) ) {
+ size_max = 12;
+ }
+
+ if ( strlen( FLM_GetName( flm ) ) > name_max ) {
+ name_max = strlen( FLM_GetName( flm ) );
+ }
+ if ( strlen( FLM_GetDateString( flm ) ) > date_max ) {
+ date_max = strlen( FLM_GetDateString( flm ) );
+ }
+ if ( strlen( FLM_GetTimeString( flm ) ) > time_max ) {
+ time_max = strlen( FLM_GetTimeString( flm ) );
+ }
+ if ( strlen( FLM_GetAttribString( flm ) ) > attr_max ) {
+ attr_max = strlen( FLM_GetAttribString( flm ) );
+ }
+
+ // Note: For better looking listboxes, we will reset our spaces to
+ // 8 minimum for dates (MM-DD-YY(, and 11 for time (HH:MM:YY XM).
+
+ if (date_max < 8)
+ {
+ date_max = 8;
+ }
+ if (time_max < 11)
+ {
+ time_max = 11;
+ }
+
+ flm = VLM_GetNextFLM( flm );
+ }
+
+ // Set the max.
+
+ flm = VLM_GetFirstFLM( flm_list );
+
+ while ( flm != NULL ) {
+
+ FLM_SetMaxName( flm, name_max );
+ FLM_SetMaxDate( flm, date_max );
+ FLM_SetMaxTime( flm, time_max );
+ FLM_SetMaxAttr( flm, attr_max );
+ FLM_SetMaxSize( flm, size_max );
+
+ flm = VLM_GetNextFLM( flm );
+ }
+
+}
+
+
+/**********************
+
+ NAME : VLM_GetPathForSLM
+
+ DESCRIPTION :
+
+ GIven an slm pointer fill in the buffer with it's complete path.
+
+ RETURNS : nothing
+
+**********************/
+
+static CHAR_PTR VLM_GetPathForSLM(
+SLM_OBJECT_PTR slm, // I
+CHAR_PTR path, // O
+INT *path_size,
+INT16_PTR path_len ) // O
+{
+ CHAR_PTR temp_path;
+ INT level;
+ INT StringLength;
+ INT BytesNeeded;
+ INT16 i;
+
+ if ( slm->level == 0 ) {
+
+ if ( *path_size < sizeof(CHAR) ) {
+ free( path );
+ path = malloc( sizeof(CHAR) );
+ *path_size = sizeof(CHAR);
+ }
+
+ strcpy( path, TEXT("") );
+ *path_len = sizeof(CHAR);
+ }
+ else {
+
+ *path_len = 0;
+
+ level = SLM_GetLevel( slm );
+
+ while ( SLM_GetLevel( slm ) != 0 ) {
+
+ if ( SLM_GetLevel( slm ) == level ) {
+
+ // Add this slm->name into path here
+
+ BytesNeeded = *path_len + strsize( SLM_GetName( slm ) );
+
+ if ( *path_size < BytesNeeded ) {
+ temp_path = malloc( BytesNeeded );
+ *path_size = BytesNeeded;
+ memcpy( temp_path, path, *path_len );
+ free( path );
+ path = temp_path;
+ }
+
+ StringLength = strlen( SLM_GetName( slm ) );
+ for ( i = *path_len / sizeof(CHAR); i > 0; i-- ) {
+ path[ i + StringLength ] = path[ i - 1 ];
+ }
+
+ strcpy( path, SLM_GetName( slm ) );
+
+ *path_len += strsize( SLM_GetName( slm ) );
+
+ level--;
+ }
+
+ slm = VLM_GetPrevSLM( slm );
+ }
+
+ }
+
+ return( path );
+}
+
+
+
+/***************************************************
+
+ Name: VLM_FlmSetSelect
+
+ Description:
+
+ The user has selected or deselected the given file or directory
+ in the flat list. Either way the whole tree of parents will
+ need to be updated.
+
+*****************************************************/
+
+static VOID_PTR VLM_FlmSetSelect(
+FLM_OBJECT_PTR flm, // I - current flm
+BYTE attr ) // I - what to set it to
+{
+ CHAR_PTR path;
+ CHAR_PTR s;
+ CHAR_PTR parent_dir;
+ INT16 path_len;
+ INT path_size;
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ BSET_OBJECT_PTR bset;
+ SLM_OBJECT_PTR slm;
+ SLM_OBJECT_PTR matching_slm;
+ FSE_PTR fse_ptr;
+ BSD_PTR bsd_ptr;
+ UINT16 status = 0;
+ UINT16 new_status;
+ INT level;
+ INT16 error;
+ INT16 result;
+ BOOLEAN all_subdirs;
+ BE_CFG_PTR bec_config;
+ DATE_TIME sort_date;
+ INT total_dirs;
+ INT total_files;
+ UINT64 total_bytes;
+ BOOLEAN u64_stat;
+
+
+ all_subdirs = (BOOLEAN) CDS_GetIncludeSubdirs( CDS_GetPerm() );
+
+ // No, you can't select this guy no matter how hard you try.
+
+ if ( ! strcmp( FLM_GetName( flm ), TEXT("..") ) ) {
+ return( NULL );
+ }
+
+ wininfo = FLM_GetXtraBytes( flm );
+ appinfo = ( APPINFO_PTR )WMDS_GetAppInfo( wininfo );
+
+ // Find the same directory in the hierarchical list if the flm is a
+ // directory. There is no garantee that the subdirectory is in the
+ // tree yet, so you may not find it.
+
+ if ( FLM_GetStatus( flm ) & INFO_ISADIR ) {
+
+ matching_slm = appinfo->open_slm;
+
+ while ( ( SLM_GetLevel( matching_slm ) !=
+ ( SLM_GetLevel( appinfo->open_slm ) + 1 ) ) ||
+ stricmp( FLM_GetName( flm ), SLM_GetName( matching_slm ) ) ) {
+
+ matching_slm = VLM_GetNextSLM( matching_slm );
+
+ if ( matching_slm == NULL ) break;
+ if ( matching_slm->level == appinfo->open_slm->level ) {
+ matching_slm = NULL;
+ break;
+ }
+ }
+ }
+
+ // determine path length
+ // insert 0's for \'s
+
+ path_size = strlen( WMDS_GetWinTitle( WM_GetInfoPtr( appinfo->win ) ) );
+ path_size += strlen( FLM_GetName( flm ) );
+ path_size += 256;
+ path_size *= sizeof(CHAR);
+
+ path = malloc( path_size );
+ if ( path == NULL ) {
+ return NULL;
+ }
+
+ WM_GetTitle( appinfo->win, path, path_size / sizeof(CHAR) );
+
+ path_len = 0;
+
+ s = path + strlen( path );
+ while ( *s != TEXT(':') ) s--;
+ s++;
+ while ( *s != TEXT('*') && *s ) {
+ path_len++;
+ if ( *s == TEXT('\\') ) {
+ *s = 0;
+ }
+ s++;
+ }
+ if ( path_len == 0 ) {
+ path_len = 1;
+ }
+ else {
+ path_len--;
+ }
+ *s = 0;
+
+
+ // point to start of path, skipping over drive
+
+ parent_dir = path;
+ while ( *parent_dir++ ) ;
+
+ if ( FLM_GetStatus( flm ) & INFO_ISADIR ) {
+
+ if ( path_len == 1 ) {
+ path_len--;
+ }
+ strcpy( parent_dir + path_len , FLM_GetName( flm ) );
+ path_len += strlen( FLM_GetName( flm ) ) + 1;
+ path_len *= sizeof(CHAR); // change to bytes
+
+ if ( attr ) {
+ error = BSD_CreatFSE( &fse_ptr, INCLUDE,
+ (INT8_PTR)parent_dir, path_len,
+ (INT8_PTR)ALL_FILES, ALL_FILES_LENG,
+ USE_WILD_CARD,
+ all_subdirs );
+ }
+ else {
+ error = BSD_CreatFSE( &fse_ptr, EXCLUDE,
+ (INT8_PTR)parent_dir, path_len,
+ (INT8_PTR)ALL_FILES, ALL_FILES_LENG,
+ USE_WILD_CARD,
+ TRUE );
+ }
+ }
+ else {
+
+ if ( path_len == 0 ) {
+ path_len++;
+ }
+ path_len *= sizeof(CHAR); // change to bytes
+
+ if ( attr ) {
+ error = BSD_CreatFSE( &fse_ptr, INCLUDE,
+ (INT8_PTR)parent_dir, path_len,
+ (INT8_PTR)FLM_GetName( flm ),
+ (INT16)strsize( FLM_GetName( flm ) ),
+ USE_WILD_CARD, FALSE );
+ }
+ else {
+ error = BSD_CreatFSE( &fse_ptr, EXCLUDE,
+ (INT8_PTR)parent_dir, path_len,
+ (INT8_PTR)FLM_GetName( flm ),
+ (INT16)strsize( FLM_GetName( flm ) ),
+ USE_WILD_CARD, FALSE );
+ }
+ }
+
+ if ( error ) {
+ free( path );
+ return NULL;
+ }
+
+ if ( appinfo->dle != NULL ) {
+
+ bsd_ptr = BSD_FindByDLE( bsd_list, appinfo->dle );
+
+ if ( bsd_ptr == NULL ) {
+
+ bec_config = BEC_CloneConfig( CDS_GetPermBEC() );
+ BEC_UnLockConfig( bec_config );
+
+ BSD_Add( bsd_list, &bsd_ptr, bec_config, NULL,
+ appinfo->dle, (UINT32)-1L, (UINT16)-1, (INT16)-1, NULL, NULL );
+ }
+
+ }
+ else {
+
+ bsd_ptr = BSD_FindByTapeID( tape_bsd_list,
+ appinfo->tape_fid,
+ appinfo->bset_num );
+
+ if ( bsd_ptr == NULL ) {
+
+ bec_config = BEC_CloneConfig( CDS_GetPermBEC() );
+ BEC_UnLockConfig( bec_config );
+
+ VLM_GetSortDate( appinfo->tape_fid, appinfo->bset_num, &sort_date );
+
+ bset = VLM_FindBset( appinfo->tape_fid, appinfo->bset_num );
+
+ BSD_Add( tape_bsd_list, &bsd_ptr, bec_config, NULL,
+ NULL, bset->tape_fid, bset->tape_num, bset->bset_num, NULL, &sort_date );
+
+ VLM_FillInBSD( bsd_ptr );
+
+ }
+ }
+
+ if ( bsd_ptr != NULL ) {
+ BSD_AddFSE( bsd_ptr, fse_ptr );
+ }
+
+ // Set the new selection status
+ // return if nothing is going to change
+
+ new_status = 0;
+
+ if ( attr ) {
+
+ attr = 1;
+
+ if ( ( FLM_GetStatus( flm ) & INFO_ISADIR ) &&
+ ( ! all_subdirs ) ) {
+
+ new_status = (INFO_SELECT|INFO_PARTIAL);
+ }
+ else {
+
+ new_status = INFO_SELECT;
+ }
+ }
+
+ if ( (UINT16)( FLM_GetStatus( flm ) & (INFO_SELECT|INFO_PARTIAL) ) != new_status ) {
+
+ FLM_SetStatus( flm, flm->status & (UINT16)~(INFO_SELECT|INFO_PARTIAL) );
+ FLM_SetStatus( flm, flm->status | new_status );
+
+ DLM_Update( appinfo->win,
+ DLM_FLATLISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)flm, 0 );
+
+ }
+
+ if ( appinfo->dle == NULL ) {
+ VLM_UpdateSearchSelections( appinfo->tape_fid, appinfo->bset_num );
+ }
+
+ // Now we taken care of the fse list, let's turn our attention
+ // to getting all those stupid check boxes right.
+
+ if ( BSD_GetMarkStatus( bsd_ptr ) == NONE_SELECTED ) {
+
+ VLM_DeselectAll( wininfo, TRUE );
+ free( path ) ;
+ return NULL;
+
+ }
+
+ // If the flm we just selected/deselected was a directory then all his
+ // subdirectories will need to be checked in the tree.
+
+ if ( ( FLM_GetStatus( flm ) & INFO_ISADIR ) &&
+ ( matching_slm != NULL ) ) {
+
+ VLM_MarkAllSLMChildren( matching_slm, attr, &total_dirs, &total_files, &total_bytes );
+
+ if ( ( SLM_GetStatus( matching_slm ) & (INFO_SELECT|INFO_PARTIAL) ) !=
+ ( FLM_GetStatus( flm ) & (INFO_SELECT|INFO_PARTIAL) ) ) {
+
+ SLM_SetStatus( matching_slm, matching_slm->status & (UINT16)~(INFO_SELECT|INFO_PARTIAL) );
+ SLM_SetStatus( matching_slm, matching_slm->status | (flm->status & (UINT16)(INFO_SELECT|INFO_PARTIAL) ) );
+
+ DLM_Update( appinfo->win,
+ DLM_TREELISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)matching_slm, 0 );
+ }
+
+ }
+
+ slm = appinfo->open_slm;
+ level = SLM_GetLevel( slm );
+
+ // Adjust all the slm's parents
+
+ do {
+
+ // Is it a parent directory ?
+
+ if ( SLM_GetLevel( slm ) == level ) {
+
+ path = VLM_GetPathForSLM( slm, path, &path_size, &path_len );
+
+ // this path_len is in bytes.
+
+ result = BSD_MatchPathAndFile( bsd_ptr, &fse_ptr, NULL,
+ path,
+ path_len,
+ SLM_GetAttribute( slm ),
+ NULL, NULL, NULL,
+ FALSE, TRUE );
+ status = 0;
+
+ if ( result == BSD_PROCESS_OBJECT ) {
+ status = INFO_SELECT|INFO_PARTIAL;
+ }
+
+ if ( result == BSD_PROCESS_ENTIRE_DIR ) {
+ status = INFO_SELECT;
+ }
+
+ if ( (UINT16)(SLM_GetStatus( slm ) & (UINT16)(INFO_PARTIAL|INFO_SELECT)) != status ) {
+
+ SLM_SetStatus( slm, slm->status & (UINT16)~( INFO_SELECT | INFO_PARTIAL ) );
+ SLM_SetStatus( slm, slm->status | status );
+
+ DLM_Update( appinfo->win,
+ DLM_TREELISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)slm, 0 );
+ }
+
+
+ if ( SLM_GetLevel( slm ) == 0 ) {
+ VLM_UpdateRoot( appinfo->win );
+ }
+
+ level = SLM_GetLevel( slm ) - 1; // New level to look for
+ }
+
+ slm = VLM_GetPrevSLM( slm );
+
+ } while ( slm != NULL );
+
+ free( path ) ;
+ return NULL;
+
+}
+
+
+/***************************************************
+
+ Name: VLM_FlmGetSelect
+
+ Description:
+
+ A callback function for the display manager to get the selection
+ status for this flm.
+
+*****************************************************/
+
+static BYTE VLM_FlmGetSelect(
+FLM_OBJECT_PTR flm ) // I - flm of interest
+{
+ if ( FLM_GetStatus( flm ) & INFO_SELECT ) {
+ return( 1 );
+ }
+
+ return( 0 );
+}
+
+
+/***************************************************
+
+ Name: VLM_FlmSetTag
+
+ Description:
+
+ A callback function for the display manager to set the tag status.
+
+*****************************************************/
+
+static VOID_PTR VLM_FlmSetTag(
+FLM_OBJECT_PTR flm, // I - flm to set
+BYTE attr ) // I - what to set it to
+{
+ if ( attr ) {
+ FLM_SetStatus( flm, flm->status | (UINT16)INFO_TAGGED );
+ }
+ else {
+ FLM_SetStatus( flm, flm->status & (UINT16)~INFO_TAGGED );
+ }
+
+ return( NULL );
+}
+
+/***************************************************
+
+ Name: VLM_FlmGetTag
+
+ Description:
+
+ A callback function for the display manager to get the tag status.
+
+*****************************************************/
+
+static BYTE VLM_FlmGetTag(
+FLM_OBJECT_PTR flm ) // I - flm of interest
+{
+ if ( FLM_GetStatus( flm ) & INFO_TAGGED ) {
+ return( 1 );
+ }
+ return( 0 );
+}
+
+/***************************************************
+
+ Name: VLM_FlmGetItemCount
+
+ Description:
+
+ A callback function for the display manager to see how many
+ items we are going to display.
+
+*****************************************************/
+
+static USHORT VLM_FlmGetItemCount(
+Q_HEADER_PTR QHdr ) // I - queue to use
+{
+ return( QueueCount(QHdr) );
+}
+
+/***************************************************
+
+ Name: VLM_FlmGetFirstItem
+
+ Description:
+
+ A callback function for the display manager to get the first flm
+ to display.
+
+*****************************************************/
+
+static VOID_PTR VLM_FlmGetFirstItem(
+Q_HEADER_PTR Q_hdr ) // I - queue to use
+{
+ return( VLM_GetFirstFLM( Q_hdr ) );
+}
+
+/***************************************************
+
+ Name: VLM_FlmGetPrevItem
+
+ Description:
+
+ A callback function for the display manager to get the previous
+ flm to display.
+
+*****************************************************/
+
+static VOID_PTR VLM_FlmGetPrevItem(
+FLM_OBJECT_PTR flm ) // I - current flm
+{
+
+ return( VLM_GetPrevFLM( flm ) );
+
+}
+
+/***************************************************
+
+ Name: VLM_FlmGetNextItem
+
+ Description:
+
+ A callback function for the display manager to get the next
+ flm to display.
+
+*****************************************************/
+
+static VOID_PTR VLM_FlmGetNextItem(
+FLM_OBJECT_PTR flm ) // I - current flm
+{
+
+ return( VLM_GetNextFLM( flm ) );
+
+}
+
+
+/***************************************************
+
+ Name: VLM_FlmGetObjects
+
+ Description:
+
+ A callback function for the display manager to get the objects
+ that I want displayed for this flm.
+
+*****************************************************/
+
+
+static VOID_PTR VLM_FlmGetObjects(
+FLM_OBJECT_PTR flm ) // I - flm to use
+{
+ BYTE_PTR memblk;
+ DLM_ITEM_PTR item;
+ WININFO_PTR wininfo;
+ INT uparrow = FALSE;
+ INT directory = FALSE;
+ CHAR text[ MAX_UI_RESOURCE_SIZE ];
+ static BYTE NT_Kludge[ 1000 ];
+
+
+ /***********
+
+ Some how under NT only the app is acting more multithreaded than normal
+ When the file list is changed, the old one is thrown out, but the DLM
+ calls me from DLM_WMMeasureItem before I have told him the list has been
+ updated. I have been unable to solve this bug. The NT_Kludge variable
+ covers it up.
+
+ ************/
+
+ // data area has a 6 byte header
+
+ wininfo = FLM_GetXtraBytes( flm );
+
+ memblk = ( BYTE_PTR )DLM_GetObjectsBuffer( WMDS_GetWinFlatList( wininfo ) );
+
+ if ( memblk == NULL ) {
+ memblk = NT_Kludge;
+ }
+
+ // skip over 6 bytes before starting
+
+ item = (DLM_ITEM_PTR)(memblk + 6);
+
+ if ( WMDS_GetMenuState( wininfo ) & MMDOC_NAMEONLY ) {
+ *memblk = 3; // number of items in list
+ }
+ else {
+ *memblk = 7; // number of items in list
+ }
+
+
+ if ( FLM_GetStatus( flm ) & INFO_ISADIR ) {
+ directory = TRUE;
+ }
+
+ DLM_ItemcbNum( item ) = 1;
+ DLM_ItembMaxTextLen( item ) = (BYTE)FLM_GetMaxSize( flm );
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembType( item ) = DLM_CHECKBOX;
+
+ // Patch it, if it was a fake parent directory entry.
+
+ if ( strcmp( TEXT(".."), FLM_GetName( flm ) ) ) {
+
+ if ( FLM_GetStatus( flm ) & INFO_SELECT ) {
+ DLM_ItemwId( item ) = IDRBM_SEL_ALL;
+ if ( FLM_GetStatus( flm ) & INFO_PARTIAL ) {
+ DLM_ItemwId( item ) = IDRBM_SEL_PART;
+ }
+ }
+ else {
+ DLM_ItemwId( item ) = IDRBM_SEL_NONE;
+ }
+ }
+ else {
+
+ // No check box if up arrow at top of list.
+
+ DLM_ItemwId( item ) = 0;
+ }
+
+ item++;
+ DLM_ItembMaxTextLen( item ) = 0;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItemcbNum( item ) = 2;
+ DLM_ItembType( item ) = DLM_BITMAP;
+
+ if ( FLM_GetStatus( flm ) & INFO_ISADIR ) {
+
+ if ( FLM_GetStatus( flm ) & INFO_EMPTY ) {
+
+ if ( flm->status & INFO_CORRUPT ) {
+ DLM_ItemwId( item ) = IDRBM_FOLDER_ECN;
+ }
+ else {
+ DLM_ItemwId( item ) = IDRBM_FOLDER_EN;
+ }
+ }
+ else {
+
+ if ( flm->status & INFO_CORRUPT ) {
+ DLM_ItemwId( item ) = IDRBM_FOLDERC;
+ }
+ else {
+ DLM_ItemwId( item ) = IDRBM_FOLDER;
+ }
+ }
+ }
+ else {
+
+ if ( FLM_GetAttribute( flm ) & OBJ_HIDDEN_BIT ) {
+
+ if ( FLM_GetStatus( flm ) & INFO_EXEFILE ) {
+ DLM_ItemwId( item ) = IDRBM_HEXEFILE;
+ }
+ else {
+ DLM_ItemwId( item ) = IDRBM_HFILE;
+ }
+
+ if ( FLM_GetStatus( flm ) & INFO_CORRUPT ) {
+ DLM_ItemwId( item ) = IDRBM_HCRPTFILE;
+ }
+ }
+ else {
+ if ( FLM_GetStatus( flm ) & INFO_EXEFILE ) {
+ DLM_ItemwId( item ) = IDRBM_EXE;
+ }
+ else {
+ DLM_ItemwId( item ) = IDRBM_FILE;
+ }
+
+ if ( FLM_GetStatus( flm ) & INFO_CORRUPT ) {
+ DLM_ItemwId( item ) = IDRBM_CORRUPTFILE;
+ }
+ }
+ }
+
+
+ // Patch it, if it was a fake parent directory entry.
+
+ if ( ! strcmp( TEXT(".."), FLM_GetName( flm ) ) ) {
+ DLM_ItemwId( item ) = IDRBM_PARENTDIR;
+ uparrow = TRUE;
+ }
+
+
+ item++;
+ DLM_ItemcbNum( item ) = 3;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = (BYTE)FLM_GetMaxName( flm );
+ DLM_ItembLevel( item ) = 0;
+ if ( uparrow ) {
+ strcpy( (CHAR_PTR)DLM_ItemqszString( item ), TEXT("") );
+ }
+ else {
+ strcpy( (CHAR_PTR)DLM_ItemqszString( item ), (CHAR_PTR)FLM_GetName( flm ) );
+ }
+
+
+
+ // Now fill in the other 4 fields if we are going to display them.
+
+
+ if ( ! ( WMDS_GetMenuState( wininfo ) & MMDOC_NAMEONLY ) ) {
+
+ item++;
+ DLM_ItemcbNum( item ) = 4;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItembTextMode( item ) = DLM_RIGHT_JUSTIFY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = (BYTE)FLM_GetMaxSize( flm );
+ DLM_ItembLevel( item ) = 0;
+ if ( directory || uparrow ) {
+ sprintf((CHAR_PTR)text, TEXT("%12s"), TEXT("") );
+ }
+ else {
+ sprintf((CHAR_PTR)text, TEXT("%12s"), (CHAR_PTR)flm->size_str );
+ }
+ strcpy((CHAR_PTR)DLM_ItemqszString( item ), (CHAR_PTR)text);
+
+ item++;
+ DLM_ItemcbNum( item ) = 5;
+ DLM_ItembTextMode( item ) = DLM_RIGHT_JUSTIFY;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = (BYTE)flm->max_date;
+ DLM_ItembLevel( item ) = 0;
+ if ( uparrow ) {
+ sprintf((CHAR_PTR)text, TEXT("%8s"), TEXT("") );
+ }
+ else {
+ sprintf((CHAR_PTR)text, TEXT("%8s"), (CHAR_PTR)flm->date_str );
+ }
+ strcpy( (CHAR_PTR)DLM_ItemqszString( item ), (CHAR_PTR)text);
+
+ item++;
+ DLM_ItemcbNum( item ) = 6;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = (BYTE)flm->max_time;
+ DLM_ItembTextMode( item ) = DLM_RIGHT_JUSTIFY;
+ DLM_ItembLevel( item ) = 0;
+ if ( uparrow ) {
+ sprintf((CHAR_PTR)text, TEXT("%8s"), TEXT("") );
+ }
+ else {
+ sprintf((CHAR_PTR)text, TEXT("%8s"), (CHAR_PTR)flm->time_str );
+ }
+ strcpy( (CHAR_PTR)DLM_ItemqszString( item ), (CHAR_PTR)text);
+
+ item++;
+ DLM_ItemcbNum( item ) = 7;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = (BYTE)FLM_GetMaxAttr( flm );
+ DLM_ItembLevel( item ) = 0;
+ if ( uparrow ) {
+ strcpy( (CHAR_PTR)DLM_ItemqszString( item ), TEXT("") );
+ }
+ else {
+ strcpy( (CHAR_PTR)DLM_ItemqszString( item ), (CHAR_PTR)flm->attrib_str );
+ }
+
+ }
+
+ return( memblk );
+}
+
+
+/***************************************************
+
+ Name: VLM_FlmSetObjects
+
+ Description:
+
+ A callback function for the display manager to tell me that the
+ user click or double clicked on an flm item.
+
+*****************************************************/
+
+static BOOLEAN VLM_FlmSetObjects(
+FLM_OBJECT_PTR flm, // I - flm to use
+WORD operation, // I - what user did
+WORD ObjectNum ) // I - what item he did it to
+{
+ CHAR_PTR s;
+ FLM_OBJECT_PTR temp_flm;
+ SLM_OBJECT_PTR slm;
+ CHAR keyb_char;
+ CHAR *directory;
+ INT directory_size;
+ APPINFO_PTR appinfo;
+ WININFO_PTR wininfo;
+ HWND window;
+ CHAR msg_title[ MAX_UI_RESOURCE_SIZE ];
+ CHAR msg_text[ MAX_UI_RESOURCE_SIZE ];
+
+
+ if ( operation == WM_DLMCHAR ) {
+
+ keyb_char = (CHAR)ObjectNum;
+
+ keyb_char = (CHAR)toupper( keyb_char );
+
+ // Work forward from current location.
+
+ temp_flm = flm;
+
+ do {
+
+ temp_flm = VLM_GetNextFLM( temp_flm );
+
+ if ( temp_flm != NULL ) {
+
+ if ( keyb_char == toupper( *FLM_GetName( temp_flm ) ) ) {
+
+ DLM_SetAnchor( WMDS_GetWinFlatList( FLM_GetXtraBytes( temp_flm ) ),
+ 0,
+ (LMHANDLE)temp_flm );
+ return( TRUE );
+ }
+ }
+
+ } while ( temp_flm != NULL );
+
+ // Start at the beginning again.
+
+ temp_flm = VLM_GetFirstFLM( WMDS_GetFlatList( FLM_GetXtraBytes( flm ) ) );
+
+ while ( temp_flm != flm && temp_flm != NULL ) {
+
+ if ( temp_flm != NULL ) {
+
+ if ( keyb_char == *FLM_GetName( temp_flm ) ) {
+
+ DLM_SetAnchor( WMDS_GetWinFlatList( FLM_GetXtraBytes( temp_flm ) ),
+ 0,
+ (LMHANDLE)temp_flm );
+ return( TRUE );
+ }
+
+ temp_flm = VLM_GetNextFLM( temp_flm );
+ }
+
+ }
+
+ DLM_SetAnchor( WMDS_GetWinFlatList( FLM_GetXtraBytes( flm ) ),
+ 0,
+ (LMHANDLE)flm );
+ }
+
+ // If the item was a directory, then make that the active directory
+ // otherwise do nothing.
+
+ if ( ( operation == WM_DLMDBCLK ) &&
+ ( ObjectNum >= 2 ) ) {
+
+ if ( FLM_GetStatus( flm ) & INFO_ISADIR ) {
+
+ WM_ShowWaitCursor( TRUE );
+
+ wininfo = FLM_GetXtraBytes( flm );
+ appinfo = ( APPINFO_PTR )WMDS_GetAppInfo( wininfo );
+ window = WMDS_GetWin( wininfo );
+
+ directory_size = WM_GetTitle( window, NULL, 0 );
+ directory_size += strlen( FLM_GetName( flm ) );
+ directory_size += 256;
+ directory_size *= sizeof(CHAR);
+
+ directory = malloc( directory_size );
+
+ WM_GetTitle( window, directory, directory_size / sizeof(CHAR ) );
+
+ s = directory;
+ while ( *s ) {
+ s++;
+ }
+
+ while ( *s != TEXT('\\') ) {
+ s--; // skip over *.*
+ }
+
+ if ( strcmp( TEXT(".."), FLM_GetName( flm ) ) ) {
+ s++;
+ strcpy( s, FLM_GetName( flm ) ); // add new dir
+ }
+ else {
+ s--;
+ while ( *s != TEXT('\\') ) s--; // skip over last dir
+ *s = TEXT( '\0' );
+ }
+
+ slm = VLM_RetrieveSLM( directory, window );
+
+ if ( slm != NULL ) {
+
+ SLM_SetStatus( appinfo->open_slm, appinfo->open_slm->status & (UINT16)~INFO_OPEN );
+ appinfo->open_slm = slm;
+
+ SLM_SetStatus( appinfo->open_slm, appinfo->open_slm->status | (UINT16)INFO_OPEN );
+
+ // Make our new open_slm the active one.
+
+ VLM_MakeSLMActive( appinfo->open_slm );
+
+ // Now redo the file list to match the open slm
+
+ VLM_HandleFSError( VLM_FileListReuse( window, directory ) );
+
+ // Change the title
+
+ strcat( directory, TEXT("\\*.*") );
+ WM_SetTitle( window, directory );
+ }
+ else {
+
+ // They need a refresh command.
+ // New directories are around that are not in the tree.
+ }
+
+ free( directory );
+
+ WM_ShowWaitCursor( FALSE );
+ }
+ else {
+
+#ifndef OEM_MSOFT
+
+ wininfo = FLM_GetXtraBytes( flm );
+ appinfo = ( APPINFO_PTR )WMDS_GetAppInfo( wininfo );
+ window = WMDS_GetWin( wininfo );
+
+ directory_size = WM_GetTitle( window, directory, 0 );
+ directory_size += strlen( FLM_GetName( flm ) );
+ directory_size += 256;
+
+ directory_size *= sizeof(CHAR);
+
+ directory = malloc( directory_size );
+
+ WM_GetTitle( window, directory, directory_size / sizeof(CHAR) );
+
+ s = directory;
+ while ( *s ) {
+ s++;
+ }
+
+ while ( *s != TEXT('\\') ) {
+ s--; // skip over *.*
+ }
+
+ s++;
+ strcpy( s, FLM_GetName( flm ) );
+
+ while ( *s != TEXT(':') ) {
+ s--;
+ }
+
+ s++;
+
+ // Pass "\dos\bin\cl.exe"
+
+ VLM_StartSearch( s );
+
+ free( directory );
+#endif
+ }
+ }
+
+ return( FALSE );
+}
+
+/***************************************************
+
+ Name: VLM_MakeSLMActive
+
+ Description:
+
+ Take the given slm and make it the currently tagged one. If we
+ have not checked it for children that will have to be done. Also
+ if its not displayed, it will need to be.
+
+*****************************************************/
+
+VOID VLM_MakeSLMActive(
+SLM_OBJECT_PTR slm ) // I - slm to use
+{
+ WININFO_PTR wininfo;
+ INT level;
+ HWND window;
+ SLM_OBJECT_PTR anchor_slm;
+ SLM_OBJECT_PTR start_slm;
+
+ // To make this guy displayable we have to make all his brothers
+ // displayable also. And if any of them haven't been checked for
+ // children they must be.
+
+ wininfo = SLM_GetXtraBytes( slm );
+ window = WMDS_GetWin( wininfo );
+
+ anchor_slm = slm;
+
+ // find the earliest related brother !
+
+ level = SLM_GetLevel( slm );
+
+ start_slm = slm;
+
+ slm = VLM_GetPrevSLM( slm );
+
+ while ( slm != NULL ) {
+
+ if ( SLM_GetLevel( slm ) < level ) {
+ SLM_SetStatus( slm, slm->status | (UINT16)INFO_EXPAND); // change parent to a minus
+ break;
+ }
+ start_slm = slm;
+ slm = VLM_GetPrevSLM( slm );
+ }
+
+ slm = start_slm;
+
+ while ( slm != NULL ) {
+
+ if ( SLM_GetLevel( slm ) < level ) {
+ break;
+ }
+
+ if ( ( SLM_GetLevel( slm ) == level ) ) {
+
+ if ( ! ( SLM_GetStatus( slm ) & INFO_DISPLAY ) ) {
+
+ SLM_SetStatus( slm, slm->status | (UINT16)INFO_DISPLAY );
+ }
+
+ slm = slm->next_brother;
+ }
+ else {
+ slm = VLM_GetNextSLM( slm );
+ }
+ }
+
+ VLM_UpdateBrothers( WMDS_GetTreeList( wininfo ) );
+
+ DLM_Update( window, DLM_TREELISTBOX,
+ WM_DLMUPDATELIST,
+ (LMHANDLE)anchor_slm, 0 );
+
+ DLM_SetAnchor( WMDS_GetWinTreeList( wininfo ), 0, (LMHANDLE)anchor_slm );
+}
+
+
+/***************************************************
+
+ Name: VLM_RetrieveSLM
+
+ Description:
+
+ Given the path and window, find the slm which is the deepest
+ directory in that path.
+
+*****************************************************/
+
+SLM_OBJECT_PTR VLM_RetrieveSLM(
+CHAR_PTR path, // I - path of interest
+HWND win ) // I - window path is from
+{
+ INT level = 0;
+ INT height = 0;
+ SLM_OBJECT_PTR slm;
+ CHAR_PTR s;
+ CHAR_PTR local_path;
+ WININFO_PTR wininfo;
+ CHAR *temp_path;
+ INT16 ret;
+
+ local_path = ( LPSTR )malloc( strsize(path) );
+
+ if ( local_path == NULL ) {
+ return( (SLM_OBJECT_PTR)NULL );
+ }
+
+ s = path + strlen( path );
+ while ( *s != TEXT(':') ) s--;
+ s++;
+ strcpy( local_path, s );
+ s = local_path;
+ while ( *s ) {
+ if ( *s == TEXT('\\') ) {
+ level++;
+ *s = 0;
+ }
+ s++;
+ }
+
+ wininfo = WM_GetInfoPtr( win );
+
+ slm = VLM_GetFirstSLM( WMDS_GetTreeList( wininfo ) );
+
+ s = local_path;
+
+ while ( height <= level ) {
+
+ do {
+
+ if ( SLM_GetLevel( slm ) == height ) {
+
+ if ( ! stricmp( s, SLM_GetName( slm ) ) ||
+ ((height == 0) && (SLM_GetLevel( slm ) == 0)) ) {
+
+ if ( ! ( slm->status & INFO_VALID ) && ( height < level ) ) {
+
+ // The desired SLM is not in the tree yet.
+
+ temp_path = VLM_BuildPath( slm );
+
+ ret = VLM_CheckForChildren( WMDS_GetTreeList( wininfo ),
+ slm, temp_path,
+ 1, // <- depth to look
+ FALSE );
+
+ free( temp_path );
+
+ slm->status |= INFO_VALID;
+ }
+
+ height++;
+ break;
+ }
+ else {
+ slm = slm->next_brother;
+ }
+ }
+ else {
+ slm = VLM_GetNextSLM( slm );
+ }
+
+ if ( slm == NULL ) { // could happen !
+ return( NULL ); // if refresh needed.
+ }
+
+ } while ( TRUE );
+
+ while ( *s++ ) ;
+ }
+
+ free( local_path );
+ return( slm );
+}
+
+
+/***************************************************
+
+ Name: VLM_UpdateFlmItem
+
+ Description:
+
+ A user selected or deselected a subdirectory in the tree list that
+ also is currently displayed in the file list. This routine finds
+ the correct flm, and updates it.
+
+*****************************************************/
+
+VOID VLM_UpdateFLMItem(
+HWND window, // I - window flm is in
+SLM_OBJECT_PTR slm ) // I - what to set it to
+{
+ WININFO_PTR wininfo;
+ FLM_OBJECT_PTR flm;
+ BOOLEAN all_subdirs;
+
+ all_subdirs = (BOOLEAN) CDS_GetIncludeSubdirs( CDS_GetPerm() );
+
+ wininfo = WM_GetInfoPtr( window );
+
+ flm = VLM_GetFirstFLM( WMDS_GetFlatList( wininfo ) );
+
+ while ( flm != NULL ) {
+
+ if ( ! stricmp( SLM_GetName( slm ), FLM_GetName( flm ) ) ) {
+ break;
+ }
+
+ flm = VLM_GetNextFLM( flm );
+ }
+
+ if ( flm != NULL ) {
+
+ if ( ( FLM_GetStatus( flm ) & (INFO_SELECT|INFO_PARTIAL) ) !=
+ ( SLM_GetStatus( slm ) & (INFO_SELECT|INFO_PARTIAL) ) ) {
+
+ FLM_SetStatus( flm, flm->status & (UINT16)~(INFO_SELECT|INFO_PARTIAL) );
+ FLM_SetStatus( flm, flm->status | (slm->status & (UINT16)(INFO_SELECT|INFO_PARTIAL)) );
+
+ DLM_Update( window,
+ DLM_FLATLISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)flm, 0 );
+ }
+ }
+
+}
diff --git a/private/utils/ntbackup/src/vlm_find.c b/private/utils/ntbackup/src/vlm_find.c
new file mode 100644
index 000000000..4c758d89d
--- /dev/null
+++ b/private/utils/ntbackup/src/vlm_find.c
@@ -0,0 +1,480 @@
+
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: VLM_FIND.C
+
+ Description:
+
+ This file contains file find routines which use the file
+ manager for searching directories.
+
+ The following public functions are implemented in this file:
+
+ VLM_FindFirst - Find first matching file or subdirectory
+ VLM_FindNext - Find next file in set
+ VLM_FindClose - Terminate a FindFirst/FindNext sequence
+
+ $Log: G:/UI/LOGFILES/VLM_FIND.C_V $
+
+ Rev 1.11 27 Jul 1993 14:14:04 MARINA
+enable c++
+
+ Rev 1.10 23 Jul 1993 11:19:20 MIKEP
+Fix logfile dates to match the logfile times.
+
+ Rev 1.9 18 Feb 1993 11:16:58 BURT
+Change to convert from universal time to local file time/date
+for Cayman (OS_WIN32)
+
+
+ Rev 1.8 07 Oct 1992 15:08:58 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.7 04 Oct 1992 19:42:22 DAVEV
+Unicode Awk pass
+
+ Rev 1.6 14 May 1992 18:05:30 MIKEP
+nt pass 2
+
+ Rev 1.5 06 May 1992 14:41:18 MIKEP
+unicode pass two
+
+ Rev 1.4 04 May 1992 13:40:04 MIKEP
+unicode pass 1
+
+ Rev 1.3 05 Feb 1992 14:57:18 DAVEV
+NT-Only: return value from FindFirstFile is -1 if no files found - not 0
+
+ Rev 1.1.1.1 03 Feb 1992 14:28:12 DAVEV
+fixes for NT
+
+ Rev 1.1 07 Jan 1992 15:31:26 DAVEV
+Change dos_findfirst,etc. to VLM_FindFirst,etc.
+
+ Rev 1.0 23 Dec 1991 14:03:06 DAVEV
+first revision
+
+
+*****************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+// VLM_ValidateAttr -- compare a found file to the specified attributes
+// -----------------------------------------------------------------------
+
+// Compare the attributes of a found file to the Inclusion/Exclusion
+// flags and return TRUE if the file is ok, FALSE otherwise.
+
+// If it is subdirectory or system or hidden, these types
+// are never returned unless explicitly specified in the
+// find attributes, otherwise, this is a normal file. Check
+// if the normal file inclusion flag is specified.
+
+// Next check to see if it is an excluded type. If not, this
+// is an acceptable entry, so copy it into the buffer and
+// we are done.
+
+// Input:USHORT targ inclusion/exclusion attribute flags
+// USHORT attr attributes of file to validate
+
+// Return: TRUE file is validated as acceptable
+// FALSE file is not of proper type
+
+
+#ifdef OS_WIN32 //32-bit Windows / NT version:
+
+
+# define VLM_ValidateAttr(targ,attr) \
+ ( ( ( ((targ) & VLMFIND_SUBDIR ) \
+ && ((attr) & FILE_ATTRIBUTE_DIRECTORY) ) \
+ || ( ((targ) & VLMFIND_NORMAL ) \
+ && !((attr) & FILE_ATTRIBUTE_DIRECTORY) ) ) \
+ && ( ((targ) & VLMFIND_HIDDEN ) \
+ || !((attr) & FILE_ATTRIBUTE_HIDDEN ) ) \
+ && ( ((targ) & VLMFIND_SYSTEM ) \
+ || !((attr) & FILE_ATTRIBUTE_SYSTEM ) ) \
+ && !( ((targ) & VLMFIND_NOARCH ) \
+ && ((attr) & FILE_ATTRIBUTE_ARCHIVE ) ) \
+ && !( ((targ) & VLMFIND_NORDONLY) \
+ && ((attr) & FILE_ATTRIBUTE_READONLY ) ) )
+
+#else // 16-bit Windows/DOS version:
+
+# define VLM_ValidateAttr(targ,attr) \
+ ( ( ( (attr) & ( _A_HIDDEN | _A_SYSTEM | _A_SUBDIR ) ) \
+ || ( (targ) & VLMFIND_NORMAL ) ) \
+ && !( ( (targ) & VLMFIND_NOARCH ) && ( (attr) & _A_ARCH ) ) \
+ && !( ( (targ) & VLMFIND_NORDONLY ) && ( (attr) & _A_RDONLY ) ) )
+
+#endif
+
+/**********************
+
+ NAME : VLM_FindFirst, VLM_FindNext, VLM_FindClose
+
+ PROTOTYPE:
+
+ #include <stdtypes.h>
+ #include <vlm.h>
+
+ VLM_FIND_PTR VLM_FindFirst (
+ TCHAR_PTR file, // I - name of file or subdirectory
+ // may contain (OS specific) wildcards
+ VLM_FINDATTR findAttr, // I - search criteria flags
+ TCHAR_PTR first); // O - First matching file name found
+ // (without drive or path)
+
+ BOOLEAN VLM_FindNext (
+ VLM_FIND_PTR find, // IO- Find data structure returned from
+ // a previous VLM_FindFirst
+ TCHAR_PTR next); // O - File name of next file found
+
+ VOID VLM_FindClose (
+ VLM_FIND_PTR *find); // IO- Find data structure returned from
+ // a previous VLM_FindFirst
+
+ DESCRIPTION :
+
+ Find all files or subdirectories in a set specified using
+ an Operating Sysytem specific file name path which may contain any wild
+ cards normally allowed by the operating system.
+
+ VLM_FindFirst must be called first to get the first file found in
+ the set. VLM_FindNext may then be repeatedly called to obtain all
+ subsequent files in the set. The order of the file names returned
+ may be arbitrary.
+
+ VLM_FindClose MUST be called to free system resources after the program
+ has finished.
+
+ VLM_FindFirst RETURNS :
+
+ NULL - if an error occurred, otherwise
+ VLM_FIND_PTR - pointer to an internal data structure required for
+ subsequent calls to VLM_FindNext and VLM_FindClose.
+
+ NOTE: This pointer should never be accessed by the
+ calling program!
+
+ file - The buffer provided by the caller is filled with the
+ file name (sans path or drive) of the first file
+ found matching the specifications.
+
+ VLM_FindNext RETURNS:
+
+ TRUE - A matching file was found and placed in the pszNext
+ buffer.
+ FALSE - The list of matching files is exhausted. VLM_FindClose
+ should now be called to free system resources.
+
+ next - The buffer provided by the caller is filled with the
+ next file found in the set specified by the initial
+ VLM_FindFirst call.
+
+ VLM_FindClose RETURNS:
+
+ Nothing. The VLM_FIND_PTR pointed to in the function parameter is
+ set to NULL.
+
+ NOTES:
+
+ file - The form used to specify the filename pattern is
+ operating system dependant.
+ For DOS, OS/2 and NT, it is a standard drive, path and
+ file name string:
+ [d:][path]fname
+
+ The path must utilize backslashes as unit seperators,
+ like normal. The file name may contain ? and * wildcards
+ in the normal maner.
+
+ findAttr - This parameter may contain one or more of the following
+ flags logically or'd together:
+
+ VLMFIND_NORMAL - Include matching files
+ VLMFIND_SUBDIR - Include matching subdirs
+
+ VLMFIND_NORDONLY - Exclude read-only files/subdirs
+ VLMFIND_NOARCH - Exclude archived files/subdirs
+
+ VLMFIND_HIDDEN - Include hidden files/subdirs
+ VLMFIND_SYSTEM - Include system files/subdirs
+
+ Notice that these flags are divided into three groups.
+ The first group (NORMAL and SUBDIR) determine whether
+ (normal) files, subdirectories or both are to be
+ retrieved. If neither of these flags are specified,
+ VLMFIND_NORMAL is presumed (only files will be
+ retrieved - no subdirectories.)
+
+ The second group specifies whether read-only and/or
+ archive files or subdirectories should be excluded from
+ the retrieved list. These types will be included
+ unless otherwise specified.
+
+ Finally, the last group determines whether hidden or
+ system files or subdirectories are to be included.
+ These types will be excluded unless specified.
+
+ Examples:
+ VLMFIND_NORMAL | VLMFIND_SUBDIR
+ This will find all files and subdirectories which
+ do not have thier hidden or system flags set.
+
+ VLMFIND_NORMAL | VLMFIND_NORDONLY | VLMFIND_NOARCH
+ This will find only those files (no subdirectories)
+ which have no flags set at all.
+
+
+ VLMFIND_SUBDIR
+ This will only find subdirectories (no files)
+ which are neither hidden nor system.
+
+ first - These must point to a character buffer which MUST be
+ long enough to hold the largest possible returned
+ next file name. This length is defined by VLM_MAXFNAME
+ in VLM_FIND.H. The following declaration is
+ recommended:
+
+ CHAR szName [VLM_MAXFNAME];
+
+**********************/
+
+VLM_FIND_PTR VLM_FindFirst (
+ CHAR_PTR file, // I - name of file or subdirectory
+ // may contain (OS specific) wildcards
+ VLM_FINDATTR findAttr, // I - search criteria flags
+ CHAR_PTR first) // O - First matching file name found
+ // (without drive or path)
+
+{
+ VLM_FIND_PTR find_ptr = NULL;
+
+ if ( file && *file && first &&
+ ( find_ptr = (VLM_FIND_PTR)calloc( 1, sizeof( VLM_FIND ) ) ) )
+ {
+ *first = 0;
+
+ find_ptr->attr = findAttr;
+
+ // Use VLMFIND_NORMAL as the default if no inclusion type is specified
+
+ if ( !( find_ptr->attr & ( VLMFIND_SUBDIR | VLMFIND_NORMAL ) ) )
+ find_ptr->attr = ( VLM_FINDATTR )( (find_ptr->attr) | VLMFIND_NORMAL );
+
+
+# if defined (OS_WIN32) //32-bit Windows/NT version...
+ {
+ find_ptr->hFind = NULL;
+ // Get the first matching entry ...
+
+ find_ptr->hFind = FindFirstFile( file,
+ &find_ptr->nt_findbuf );
+
+ if ( find_ptr->hFind != (HANDLE)-1 )
+ {
+ do {
+ // compare the file type to the specified attributes...
+
+ if ( VLM_ValidateAttr ( find_ptr->attr,
+ find_ptr->nt_findbuf.dwFileAttributes ) )
+ {
+ // We have found the first match!
+ strcpy (first, find_ptr->nt_findbuf.cFileName);
+ }
+
+ // Otherwise, keep trying files to find the first good one...
+
+ } while ( ! *first &&
+ FindNextFile( find_ptr->hFind, &find_ptr->nt_findbuf ) );
+ }
+ }
+# else //16 bit Windows & DOS version...
+ {
+ unsigned usAttr = _A_NORMAL; //_dos_findfirst attributes
+
+ if ( find_ptr->attr & VLMFIND_SUBDIR ) usAttr |= _A_SUBDIR;
+ if ( find_ptr->attr & VLMFIND_HIDDEN ) usAttr |= _A_HIDDEN;
+ if ( find_ptr->attr & VLMFIND_SYSTEM ) usAttr |= _A_SYSTEM;
+
+ // Get the first matching entry ...
+
+ if ( !_dos_findfirst( file, usAttr, &find_ptr->dos_findbuf ) )
+ {
+ do {
+ // compare the file type to the specified attributes...
+
+ if ( VLM_ValidateAttr( find_ptr->attr,
+ find_ptr->dos_findbuf.attrib ) )
+ {
+ // We have found the first match!
+ strcpy( first, find_ptr->dos_findbuf.name );
+ }
+
+ // Otherwise, keep trying files to find the first good one...
+
+ } while ( !*first && !_dos_findnext ( &find_ptr->dos_findbuf ) );
+ }
+ }
+# endif
+
+ if ( !*first )
+ {
+ VLM_FindClose( &find_ptr );
+ }
+ }
+
+ return( find_ptr );
+}
+
+
+BOOLEAN VLM_FindNext (
+ VLM_FIND_PTR find_ptr, // IO- Find data structure returned from
+ // a previous VLM_FindFirst
+ CHAR_PTR next_ptr) // O - File name of next file in set
+
+{
+ if ( find_ptr && next_ptr)
+ {
+ *next_ptr = 0;
+
+# if defined ( OS_WIN32 ) //32-bit Windows/NT version...
+ {
+ while ( !*next_ptr && FindNextFile ( find_ptr->hFind,
+ &find_ptr->nt_findbuf ) )
+ {
+ // compare the file type to the specified attributes...
+
+ if ( VLM_ValidateAttr ( find_ptr->attr,
+ find_ptr->nt_findbuf.dwFileAttributes ) )
+ {
+ // We have found the first match!
+ strcpy( next_ptr, find_ptr->nt_findbuf.cFileName);
+ }
+ }
+ }
+# else //16-bit Windows/DOS version ...
+ {
+ while ( !*next_ptr && !_dos_findnext ( &find_ptr->dos_findbuf ) )
+ {
+ // compare the file type to the specified attributes...
+
+ if ( VLM_ValidateAttr( find_ptr->attr,
+ find_ptr->dos_findbuf.attrib ) )
+ {
+ // We have found the next match!
+ strcpy (next_ptr, find_ptr->dos_findbuf.name);
+ }
+ }
+ }
+# endif
+ }
+ return ( *next_ptr != 0 );
+}
+
+
+VOID VLM_FindClose (
+ VLM_FIND_PTR FAR * find_ptr) // IO- Find data structure returned from
+ // a previous VLM_FindFirst
+{
+ if ( find_ptr && *find_ptr )
+ {
+# if defined ( OS_WIN32 )
+ {
+ if ( (*find_ptr)->hFind )
+ {
+ FindClose ( (*find_ptr)->hFind );
+ }
+ }
+# endif
+
+ free ( *find_ptr );
+ *find_ptr = NULL;
+ }
+}
+
+#if defined ( OS_WIN32 ) //These functions are unique to 32-bit Windows/NT
+
+ /*
+ * VLM_FindDosTime, VLM_FindDosDate
+ *
+ * Given an NT-style file time structure, return the DOS-style
+ * file date or time. Note that the file's date/time stamp must be
+ * between 1/1/1980 and 12/31/2099 for these functions to work
+ * properly. If the file date/time stamp is outside of this range
+ * the returned values will be 0.
+ *
+ * THESE FUNCTIONS ARE A KLUDGE. THEY AND THE VLM_FindXxxxXxxx()
+ * DATE/TIME MACROS IN VLM_FIND.H NEED TO BE FIXED IN THE FUTURE.
+ */
+
+ USHORT VLM_FindDosTime (FILETIME ft)
+ {
+ USHORT usDosDate;
+ USHORT usDosTime;
+#ifdef OS_WIN32
+ FILETIME tft ; // Needed to convert to local time from U time.
+
+ FileTimeToLocalFileTime( &ft, &tft ) ; // Do the conversion
+ // Must use temp FILETIME var since can't use the input arg
+ // as the target of the previous conversion.
+ if (!FileTimeToDosDateTime ( &tft, &usDosDate, &usDosTime ))
+ {
+ return 0;
+ }
+#else
+
+ if (!FileTimeToDosDateTime ( &ft, &usDosDate, &usDosTime ))
+ {
+ return 0;
+ }
+#endif
+ return usDosTime;
+ }
+
+ USHORT VLM_FindDosDate (FILETIME ft)
+ {
+ USHORT usDosDate;
+ USHORT usDosTime;
+
+#ifdef OS_WIN32
+ FILETIME tft ; // Needed to convert to local time from U time.
+
+ FileTimeToLocalFileTime( &ft, &tft ) ; // Do the conversion
+ // Must use temp FILETIME var since can't use the input arg
+ // as the target of the previous conversion.
+ if (!FileTimeToDosDateTime ( &tft, &usDosDate, &usDosTime ))
+ {
+ return 0;
+ }
+#else
+
+ if (!FileTimeToDosDateTime ( &ft, &usDosDate, &usDosTime ))
+ {
+ return 0;
+ }
+
+#endif
+ return usDosDate;
+ }
+
+#endif //end 32-bit Windows/NT unique functions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/private/utils/ntbackup/src/vlm_init.c b/private/utils/ntbackup/src/vlm_init.c
new file mode 100644
index 000000000..aec48efe5
--- /dev/null
+++ b/private/utils/ntbackup/src/vlm_init.c
@@ -0,0 +1,144 @@
+
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: VLM_INIT.C
+
+ Description:
+
+ VLM init code.
+
+ $Log: G:/UI/LOGFILES/VLM_INIT.C_V $
+
+ Rev 1.18 07 Oct 1992 15:04:56 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.17 04 Oct 1992 19:42:24 DAVEV
+Unicode Awk pass
+
+ Rev 1.16 29 Jul 1992 09:51:44 MIKEP
+ChuckB checked in after NT warnings were fixed.
+
+ Rev 1.15 27 Jun 1992 17:58:34 MIKEP
+changes for qtc
+
+ Rev 1.14 14 May 1992 18:06:14 MIKEP
+nt pass 2
+
+ Rev 1.13 06 May 1992 14:40:46 MIKEP
+unicode pass two
+
+ Rev 1.12 04 May 1992 13:39:34 MIKEP
+unicode pass 1
+
+ Rev 1.11 27 Apr 1992 16:20:30 JOHNWT
+added flag for reading startup.bks
+
+ Rev 1.10 09 Mar 1992 16:32:38 ROBG
+no changes
+
+ Rev 1.9 14 Jan 1992 12:59:12 MIKEP
+vcs header
+
+
+*****************************************************/
+
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+/*
+ The function to init and create the primary windows.
+*/
+
+BOOL VLM_Init( BOOL read_startup )
+
+{
+ BSD_PTR bsd;
+
+ WM_ShowWaitCursor( TRUE );
+
+ zprintf( DEBUG_USER_INTERFACE, RES_INIT_VLM );
+
+ // Load up the catalogs
+
+ VLM_LookForCatalogFiles();
+
+ // Call the backup engine init stuff
+
+ bsd = BSD_GetFirst( bsd_list );
+
+ while ( bsd != NULL ) {
+
+ BSD_SetTHW( bsd, thw_list );
+ bsd = BSD_GetNext( bsd );
+ }
+
+ // Init bsd_list for tapes, This is NEW for GUI.
+
+ tape_bsd_list = (BSD_HAND)malloc( sizeof(BSD_LIST) );
+
+ if ( tape_bsd_list == NULL ) {
+ goto failure;
+ }
+
+ InitQueue( &(tape_bsd_list->current_q_hdr) );
+ InitQueue( &(tape_bsd_list->last_q_hdr) );
+
+ if ( VLM_DisksListCreate() != SUCCESS ) {
+ goto failure;
+ }
+
+ // If needed create the servers window
+
+ if ( gfServers ) {
+
+ if ( VLM_ShowServers( TRUE ) != SUCCESS ) {
+ goto failure;
+ }
+ }
+
+#ifdef OEM_EMS // Initialize the exchange window queue and add any entries.
+
+ if ( VLM_ExchangeInit( ) != SUCCESS ) {
+ goto failure;
+ }
+#endif //OEM_EMS
+
+ // Create the tapes window
+
+ if ( VLM_TapesListCreate( ) != SUCCESS ) {
+ goto failure;
+ }
+
+ // Init the Password list.
+
+ if ( PSWD_InitPSWDList() != SUCCESS ) {
+ goto failure;
+ }
+
+ // Load the default file selections.
+
+ if ( read_startup ) {
+ VLM_LoadDefaultSelections();
+ }
+
+ WM_ShowWaitCursor( FALSE );
+
+ return( SUCCESS );
+
+failure:
+
+ WM_ShowWaitCursor( FALSE );
+
+ return( FAILURE );
+
+}
+
+
+
+
diff --git a/private/utils/ntbackup/src/vlm_menu.c b/private/utils/ntbackup/src/vlm_menu.c
new file mode 100644
index 000000000..29aa58dd9
--- /dev/null
+++ b/private/utils/ntbackup/src/vlm_menu.c
@@ -0,0 +1,1041 @@
+
+/*******************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: VLM_MENU.C
+
+ Description:
+
+ This file contains the functions used when a user initiates an action
+ with a menu selection or ribbon button. These include things like
+ expanding directory trees, selecting all tagged files, or adding an
+ advanced FSE selection.
+
+ $Log: G:\UI\LOGFILES\VLM_MENU.C_V $
+
+ Rev 1.52.1.0 08 Dec 1993 11:23:26 MikeP
+very deep pathes and unicode
+
+ Rev 1.52 27 Jul 1993 14:40:02 MARINA
+enable c++
+
+ Rev 1.51 15 Jul 1993 10:39:50 BARRY
+Don't create a second fse fred* when fred*.* is created; need bsdmatch.c fix.
+
+ Rev 1.50 07 Jul 1993 15:22:46 CARLS
+added WM_ShowWaitCursor to password prompt
+
+ Rev 1.49 07 May 1993 14:22:00 DARRYLP
+Added Rob's fixes for Windows double clicks and ID_DELETE key trappings.
+
+ Rev 1.48 27 Apr 1993 05:20:34 GREGG
+Don't do the fancy sort stuff for OEM_MSOFT.
+
+ Rev 1.47 26 Apr 1993 08:52:30 MIKEP
+Add numerous changes to fully support the font case selection
+for various file system types. Also add refresh for tapes window
+and sorting of tapes window.
+
+ Rev 1.46 23 Apr 1993 10:20:38 MIKEP
+Add ability to refresh tapes window.
+Add support for sorting files window by various methods.
+Fix refresh of sorting windows.
+
+ Rev 1.45 24 Mar 1993 17:50:14 STEVEN
+fix dot problem
+
+ Rev 1.44 11 Nov 1992 16:36:44 DAVEV
+UNICODE: remove compile warnings
+
+ Rev 1.43 01 Nov 1992 16:12:12 DAVEV
+Unicode changes
+
+ Rev 1.42 07 Oct 1992 15:07:14 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.41 04 Oct 1992 19:42:28 DAVEV
+Unicode Awk pass
+
+ Rev 1.40 29 Jul 1992 09:32:18 MIKEP
+ChuckB checked in after NT warnings were fixed.
+
+ Rev 1.39 10 Jul 1992 08:37:28 JOHNWT
+more gas guage work
+
+ Rev 1.38 07 Jul 1992 15:31:40 MIKEP
+unicode changes
+
+ Rev 1.37 30 Jun 1992 13:18:32 JOHNWT
+dynamically alloc stats
+
+ Rev 1.36 29 Jun 1992 10:42:16 JOHNWT
+added selected dir counts
+
+ Rev 1.35 19 Jun 1992 14:43:54 JOHNWT
+more gas
+
+ Rev 1.34 14 May 1992 18:05:32 MIKEP
+nt pass 2
+
+ Rev 1.33 13 May 1992 11:42:02 MIKEP
+NT changes
+
+ Rev 1.32 06 May 1992 14:41:36 MIKEP
+unicode pass two
+
+ Rev 1.31 04 May 1992 13:40:00 MIKEP
+unicode pass 1
+
+ Rev 1.30 30 Apr 1992 14:40:24 DAVEV
+OEM_MSOFT: Fix View-All File Details
+
+
+*******************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+// function prototypes for use in this file ONLY
+
+static VOID VLM_SelectButton( BYTE );
+
+
+/**********************
+
+ NAME : VLM_UpdateRoot
+
+ DESCRIPTION :
+
+ Update the parent device to match the selection status of the root
+ directory in the tree.
+
+ RETURNS :
+
+**********************/
+
+VOID VLM_UpdateRoot(
+HWND win ) // I - window to update root on
+{
+ VLM_OBJECT_PTR vlm;
+ VLM_OBJECT_PTR server_vlm;
+ TAPE_OBJECT_PTR tape;
+ BSET_OBJECT_PTR bset;
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ APPINFO_PTR server_appinfo;
+ SLM_OBJECT_PTR root;
+
+ (VOID)server_vlm ;
+ (VOID)server_appinfo ;
+
+ wininfo = WM_GetInfoPtr( win );
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( win );
+
+ if ( ( wininfo->wType != WMTYPE_DISKTREE ) &&
+ ( wininfo->wType != WMTYPE_TAPETREE ) ) {
+
+ // I told you NOT to do this !
+
+ return;
+ }
+
+ root = VLM_GetFirstSLM( wininfo->pTreeList );
+
+ if ( root == NULL ) {
+
+ // I can't imagine how you managed this
+
+ return;
+ }
+
+ // Update status of server/volume, disk, or tape/bset
+ // to match root.
+
+ if ( wininfo->wType == WMTYPE_DISKTREE ) {
+
+#ifndef OEM_MSOFT //unsupported feature
+
+ if ( appinfo->parent == gb_servers_win ) { // SERVERS
+
+ wininfo = WM_GetInfoPtr( gb_servers_win );
+ server_appinfo = ( APPINFO_PTR )WM_GetAppPtr( gb_servers_win );
+
+ server_vlm = VLM_GetFirstVLM( wininfo->pTreeList );
+
+ while ( server_vlm != NULL ) {
+
+ if ( QueueCount( &server_vlm->children ) ) {
+
+ vlm = VLM_GetFirstVLM( &server_vlm->children );
+
+ while ( vlm != NULL ) {
+
+ if ( ! strcmp( DLE_GetDeviceName(appinfo->dle),
+ vlm->name ) ) {
+
+ if ( ( vlm->status & (INFO_SELECT|INFO_PARTIAL) ) !=
+ ( root->status & (INFO_SELECT|INFO_PARTIAL) ) ) {
+
+ vlm->status &= ~(INFO_SELECT|INFO_PARTIAL);
+ vlm->status |= root->status & (INFO_SELECT|INFO_PARTIAL);
+
+ if ( ! stricmp( DLE_GetDeviceName( server_appinfo->dle),
+ server_vlm->name ) ) {
+
+ DLM_Update( gb_servers_win,
+ DLM_FLATLISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)vlm, 0 );
+ }
+ VLM_UpdateServerStatus( server_vlm );
+ }
+ return;
+ }
+ vlm = VLM_GetNextVLM( vlm );
+ }
+ }
+ server_vlm = VLM_GetNextVLM( server_vlm );
+ } /*while*/
+
+ }
+ else // DISKS
+
+#endif //OEM_MSOFT //unsupported feature
+
+ {
+ wininfo = WM_GetInfoPtr( gb_disks_win );
+ vlm = VLM_GetFirstVLM( wininfo->pFlatList );
+
+ while ( vlm != NULL ) {
+
+ if ( ! stricmp( DLE_GetDeviceName( appinfo->dle ), vlm->name ) ) {
+
+ if ( ( vlm->status & (INFO_SELECT|INFO_PARTIAL) ) !=
+ ( root->status & (INFO_SELECT|INFO_PARTIAL) ) ) {
+
+ vlm->status &= ~(INFO_SELECT|INFO_PARTIAL);
+ vlm->status |= root->status & (INFO_SELECT|INFO_PARTIAL);
+
+ DLM_Update( gb_disks_win,
+ DLM_FLATLISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)vlm, 0 );
+ }
+
+ return;
+ }
+ vlm = VLM_GetNextVLM( vlm );
+ }
+ }
+ }
+ else { // TAPES
+
+ wininfo = WM_GetInfoPtr( gb_tapes_win );
+
+ tape = VLM_GetFirstTAPE( );
+
+ while ( tape != NULL ) {
+
+ if ( tape->tape_fid == appinfo->tape_fid ) {
+
+ bset = VLM_GetFirstBSET( &tape->bset_list );
+
+ while ( bset != NULL ) {
+
+ if ( appinfo->bset_num == bset->bset_num ) {
+
+ if ( ( bset->status & (INFO_SELECT|INFO_PARTIAL) ) !=
+ ( root->status & (INFO_SELECT|INFO_PARTIAL) ) ) {
+
+ bset->status &= ~(INFO_SELECT|INFO_PARTIAL);
+ bset->status |= root->status & (INFO_SELECT|INFO_PARTIAL);
+
+ if ( tape->status & INFO_OPEN ) {
+
+ DLM_Update( gb_tapes_win,
+ DLM_FLATLISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)bset, 0 );
+ }
+
+ VLM_UpdateTapeStatus( tape, TRUE );
+ }
+
+ return;
+ }
+ bset = VLM_GetNextBSET( bset );
+ }
+ }
+ tape = VLM_GetNextTAPE( tape );
+ }
+
+ }
+
+}
+
+/**********************
+
+ NAME : VLM_CloseAll
+
+ DESCRIPTION :
+
+ The poor user has managed to open so many windows at once that he has
+ requested we just go ahead and close them all for him to start over.
+ This will NOT lose any of his selections, just close all the windows.
+
+ RETURNS :
+
+**********************/
+
+VOID VLM_CloseAll()
+{
+ WM_MinimizeDocs();
+}
+
+
+
+/**********************
+
+ NAME : VLM_AddAdvancedSelection
+
+ DESCRIPTION :
+
+ The user wants to add an advanced selection to the FSE list. This
+ routine takes the information from the data structure that the dialogs
+ filled out and creates the FSE.
+
+ RETURNS :
+
+**********************/
+
+VOID VLM_AddAdvancedSelection(
+HWND worthless, // I - worthless window
+DS_ADVANCED_PTR pds ) // I - advanced selection data
+{
+ GENERIC_DLE_PTR dle;
+ VLM_OBJECT_PTR vlm;
+ BSD_PTR bsd_ptr;
+ FSE_PTR fse_ptr;
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ INT16 path_len;
+ CHAR_PTR path_ptr;
+ CHAR_PTR s;
+ BOOLEAN was_slash;
+ BSET_OBJECT_PTR bset;
+ INT16 predate = 0, postdate = 0;
+ HWND win;
+ BE_CFG_PTR bec_config;
+ DATE_TIME sort_date;
+
+ DBG_UNREFERENCED_PARAMETER( worthless );
+
+ path_len = 0;
+ path_ptr = pds->Path;
+ if ( *path_ptr == TEXT('\\') ) path_ptr++;
+
+ s = path_ptr;
+ was_slash = FALSE; // Used to NOT count trailing TEXT('\\')
+ while ( *s != 0 ) {
+ if ( *s == TEXT('\\') ) {
+ *s = 0;
+ was_slash = TRUE;
+ }
+ else {
+ was_slash = FALSE;
+ }
+ s++;
+ path_len++;
+ }
+
+ if ( was_slash ) {
+ path_len--; // was it a trailing slash
+ }
+
+ path_len++; // count final zero
+
+ path_len *= sizeof(CHAR); // convert to bytes
+
+ vlm = (VLM_OBJECT_PTR)pds->vlm;
+
+ if ( vlm == NULL ) {
+
+ // It's a restore request, see if they know the password.
+
+ WM_ShowWaitCursor ( SWC_PAUSE );
+ if ( PSWD_CheckForPassword( pds->tape_fid, (INT16)pds->bset_num ) ) {
+ WM_ShowWaitCursor ( SWC_RESUME );
+ return;
+ }
+ WM_ShowWaitCursor ( SWC_RESUME );
+ }
+
+// Create the new FSE
+
+ if ( pds->Include ) {
+
+ if ( BSD_CreatFSE( &fse_ptr, (INT16)INCLUDE,
+ (INT8_PTR) path_ptr, (INT16)path_len,
+ (INT8_PTR) pds->File,
+ (INT16) strsize( pds->File ),
+ (BOOLEAN) USE_WILD_CARD,
+ (BOOLEAN) pds->Subdirs ) ) {
+ return;
+ }
+ }
+ else {
+
+ if ( BSD_CreatFSE( &fse_ptr, (INT16)EXCLUDE,
+ (INT8_PTR) path_ptr, (INT16)path_len,
+ (INT8_PTR) pds->File,
+ (INT16) strsize( pds->File ),
+ (BOOLEAN) USE_WILD_CARD,
+ (BOOLEAN) pds->Subdirs ) ) {
+ return;
+ }
+ }
+
+ // Right here set the complex info, Modified, Dates
+
+ switch ( pds->criteria ) {
+
+ case ADV_MOD:
+
+ FSE_SetAttribInfo( fse_ptr, OBJ_MODIFIED_BIT, 0L );
+ break;
+
+ case ADV_ACCESS:
+
+ FSE_SetAccDate( fse_ptr, &(pds->LastAccessDate) );
+ break;
+
+ case ADV_DATES:
+
+ FSE_SetModDate( fse_ptr, &(pds->AfterDate), &(pds->BeforeDate) );
+ break;
+
+ default:
+ break;
+ }
+
+ // Find the BSD to add it to
+
+ if ( vlm != NULL ) {
+
+ DLE_FindByName( dle_list, vlm->name, ANY_DRIVE_TYPE, &dle );
+
+ bsd_ptr = BSD_FindByDLE( bsd_list, dle );
+
+ if ( bsd_ptr == NULL ) {
+
+ bec_config = BEC_CloneConfig( CDS_GetPermBEC() );
+ BEC_UnLockConfig( bec_config );
+
+ BSD_Add( bsd_list, &bsd_ptr, bec_config, NULL,
+ dle, (UINT32)-1L, (UINT16)-1, (INT16)-1, NULL, NULL );
+ }
+
+ }
+else {
+
+ bsd_ptr = BSD_FindByTapeID( tape_bsd_list,
+ (UINT32)pds->tape_fid,
+ (UINT16)pds->bset_num );
+
+ if ( bsd_ptr == NULL ) {
+
+ bec_config = BEC_CloneConfig( CDS_GetPermBEC() );
+ BEC_UnLockConfig( bec_config );
+
+ VLM_GetSortDate( (UINT32)pds->tape_fid, (INT16)pds->bset_num, &sort_date );
+
+ bset = VLM_FindBset( pds->tape_fid, (INT16)pds->bset_num );
+
+ BSD_Add( tape_bsd_list, &bsd_ptr,
+ bec_config, NULL,
+ NULL, (UINT32)pds->tape_fid, (UINT16)bset->tape_num, (INT16)pds->bset_num, NULL, &sort_date );
+
+ VLM_FillInBSD( bsd_ptr );
+ }
+ }
+
+ // Add the new FSE
+
+ if ( bsd_ptr != NULL ) {
+
+ BSD_AddFSE( bsd_ptr, fse_ptr );
+
+ // Now we have NO idea which selections may have changed because of the
+ // addition of this FSE. So the best we can do is to completely
+ // rematch the entire list of files and subdirectories.
+
+ win = WM_GetNext( (HWND)NULL );
+
+ while ( win != (HWND)NULL ) {
+
+ wininfo = WM_GetInfoPtr( win );
+
+ if ( ( wininfo->wType == WMTYPE_DISKTREE ) && ( vlm != NULL ) ) {
+
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( win );
+
+ if ( ! stricmp( DLE_GetDeviceName( appinfo->dle ), vlm->name ) ) {
+ VLM_RematchList( win );
+ }
+ }
+
+ if ( ( wininfo->wType == WMTYPE_TAPETREE ) && ( vlm == NULL ) ) {
+
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( win );
+
+ if ( ( appinfo->tape_fid == (UINT32)pds->tape_fid ) &&
+ ( appinfo->bset_num == (INT16) pds->bset_num ) ) {
+ VLM_RematchList( win );
+ }
+ }
+ win = WM_GetNext( win );
+ }
+
+ if ( vlm != NULL ) {
+ if ( vlm->parent != NULL ) {
+ VLM_UpdateServers();
+ }
+ else {
+ VLM_UpdateDisks();
+ }
+ }
+ else {
+ VLM_UpdateTapes( );
+ VLM_UpdateSearchSelections( (UINT32)pds->tape_fid, (INT16)pds->bset_num );
+ }
+ }
+}
+
+
+
+
+/**********************
+
+ NAME : VLM_SelectButton
+
+ DESCRIPTION :
+
+ The user has pressed a select button. We need to go find all the tagged
+ items for that window and process the selections. We have to look at the
+ type of the window, to determine how to handle it. The current types
+ supported are:
+
+ - files lists
+ - bsets
+ - servers volumes
+ - disks
+
+ RETURNS :
+
+**********************/
+
+
+static VOID VLM_SelectButton(
+BYTE attr ) // I - select or deselect ?
+{
+ WININFO_PTR wininfo;
+
+ // attr == 0, unselect all taggged files
+ // == 1, select all tagged files
+
+ wininfo = WM_GetInfoPtr( WM_GetActiveDoc() );
+
+ switch ( wininfo->wType ) {
+
+ case WMTYPE_DISKTREE:
+ case WMTYPE_TAPETREE:
+ VLM_SelectTree( WM_GetActiveDoc(), attr );
+ break;
+ case WMTYPE_DISKS:
+ VLM_SelectDisks( attr );
+ break;
+#ifdef OEM_EMS
+ case WMTYPE_EXCHANGE:
+ VLM_SelectExchangeShares( attr, wininfo );
+ break;
+#endif
+ case WMTYPE_SERVERS:
+ VLM_SelectVolumes( attr );
+ break;
+ case WMTYPE_TAPES:
+ VLM_SelectBsets( attr );
+ break;
+
+ case WMTYPE_SEARCH:
+ VLM_SelectSearch( attr );
+ break;
+
+ default:
+ break;
+ }
+
+}
+
+
+/**********************
+
+ NAME : VLM_ChangeSettings
+
+ DESCRIPTION :
+
+ Someone somewhere has changed something !
+ Its our job to now update everything to reflect that change.
+ A job which can only be handled by a real manly man, because the
+ the skills required are massive, and the pitfalls many. If you
+ are a little girly man then turn back now. At least remember you were
+ warned, when you go crawling away later in total humiliation, your sense
+ of self worth completely destroyed, while little girl scouts point
+ and laugh at you. After that no one will doubt just what kind of man
+ you really are.
+
+ RETURNS :
+
+**********************/
+
+VOID VLM_ChangeSettings(
+INT16 msg, // I - what changed
+INT32 lParam ) // I - nothing
+{
+ WININFO_PTR wininfo;
+ UNREFERENCED_PARAMETER(lParam);
+
+ switch ( msg ) {
+
+ case ID_VIEWFONT:
+ WM_ShowWaitCursor( TRUE );
+ VLM_FontCaseChange( );
+ WM_ShowWaitCursor( FALSE );
+ break;
+
+#ifndef OEM_MSOFT
+ case ID_SORTNAME:
+ case ID_SORTDATE:
+ case ID_SORTSIZE:
+ case ID_SORTTYPE:
+
+ // Change the order of the file list.
+
+ wininfo = WM_GetInfoPtr( WM_GetActiveDoc() );
+ if ( ( wininfo->wType == WMTYPE_DISKTREE ) ||
+ ( wininfo->wType == WMTYPE_TAPETREE ) ) {
+ VLM_ResortFileList( WM_GetActiveDoc() );
+ }
+ break;
+#endif
+
+ case ID_TREEANDFLAT:
+
+ // User has requested we display both the tree and flat lists
+ // Just change the icon.
+
+ wininfo = WM_GetInfoPtr( WM_GetActiveDoc() );
+ if ( ( wininfo->wType == WMTYPE_DISKTREE ) ||
+ ( wininfo->wType == WMTYPE_TAPETREE ) ) {
+ wininfo->hIcon = RSM_IconLoad( IDRI_TREEFILE );
+ }
+ break;
+
+ case ID_TREEONLY:
+
+ // User has requested we display only the tree list
+ // Just change the icon.
+
+ wininfo = WM_GetInfoPtr( WM_GetActiveDoc() );
+ if ( ( wininfo->wType == WMTYPE_DISKTREE ) ||
+ ( wininfo->wType == WMTYPE_TAPETREE ) ) {
+ wininfo->hIcon = RSM_IconLoad( IDRI_TREE );
+ }
+ break;
+
+ case ID_FLATONLY:
+
+ // User has requested we display only the flat list
+ // Just change the icon.
+
+ wininfo = WM_GetInfoPtr( WM_GetActiveDoc() );
+ if ( ( wininfo->wType == WMTYPE_DISKTREE ) ||
+ ( wininfo->wType == WMTYPE_TAPETREE ) ) {
+ wininfo->hIcon = RSM_IconLoad( IDRI_FILES );
+ }
+ break;
+
+ case ID_FILEDETAILS:
+
+ // User has requested we display all file details
+
+ wininfo = WM_GetInfoPtr( WM_GetActiveDoc() );
+ if ( ( wininfo->wType == WMTYPE_DISKTREE ) ||
+ ( wininfo->wType == WMTYPE_TAPETREE ) ) {
+ DLM_DispListModeSet( WM_GetActiveDoc(),
+ DLM_FLATLISTBOX,
+ DLM_SINGLECOLUMN );
+ }
+ break;
+
+
+ case ID_NAMEONLY:
+
+ // User has requested we display file names only
+
+ wininfo = WM_GetInfoPtr( WM_GetActiveDoc() );
+ if ( ( wininfo->wType == WMTYPE_DISKTREE ) ||
+ ( wininfo->wType == WMTYPE_TAPETREE ) ) {
+ DLM_DispListModeSet( WM_GetActiveDoc(),
+ DLM_FLATLISTBOX,
+ DLM_COLUMN_VECTOR );
+ }
+ break;
+
+# if !defined ( OEM_MSOFT ) // - unsupported feature
+
+ case ID_SERVERS:
+
+ // user has requested to toggle servers on or off
+
+ VLM_ShowServers( FALSE );
+ break;
+
+# endif // !defined ( OEM_MSOFT ) // - unsupported feature
+
+
+ case ID_SELECT:
+
+ // User hit select button
+ VLM_SelectButton( 1 );
+ break;
+
+ case ID_DESELECT:
+
+ // User hit deselect button
+ VLM_SelectButton( 0 );
+ break;
+
+ case ID_EXPANDALL:
+
+ // Expand the whole tree and display it
+
+ wininfo = WM_GetInfoPtr( WM_GetActiveDoc() );
+ if ( ( wininfo->wType == WMTYPE_DISKTREE ) ||
+ ( wininfo->wType == WMTYPE_TAPETREE ) ) {
+
+ WM_ShowWaitCursor( TRUE );
+ VLM_ExpandTree( WM_GetActiveDoc() );
+ WM_ShowWaitCursor( FALSE );
+ }
+#ifdef OEM_EMS
+ if ( wininfo->wType == WMTYPE_EXCHANGE ) {
+ SLM_EMSExpandTree( WM_GetActiveDoc() );
+ }
+#endif
+ break;
+
+ case ID_EXPANDONE:
+
+ // Expand one level from current node
+
+ wininfo = WM_GetInfoPtr( WM_GetActiveDoc() );
+ if ( ( wininfo->wType == WMTYPE_DISKTREE ) ||
+ ( wininfo->wType == WMTYPE_TAPETREE ) ) {
+ VLM_ExpandOne( WM_GetActiveDoc() );
+ }
+
+#ifdef OEM_EMS
+ if ( wininfo->wType == WMTYPE_EXCHANGE ) {
+ SLM_EMSExpandOne( WM_GetActiveDoc() );
+ }
+#endif
+ break;
+
+ case ID_EXPANDBRANCH:
+
+ // Expand this branch only all the way
+
+ wininfo = WM_GetInfoPtr( WM_GetActiveDoc() );
+ if ( ( wininfo->wType == WMTYPE_DISKTREE ) ||
+ ( wininfo->wType == WMTYPE_TAPETREE ) ) {
+ WM_ShowWaitCursor( TRUE );
+ VLM_ExpandBranch( WM_GetActiveDoc() );
+ WM_ShowWaitCursor( FALSE );
+ }
+#ifdef OEM_EMS
+ if ( wininfo->wType == WMTYPE_EXCHANGE ) {
+ SLM_EMSExpandBranch( WM_GetActiveDoc() );
+ }
+#endif
+ break;
+
+ case ID_COLLAPSEBRANCH:
+
+ // Close off this branch, ie. hide it
+
+ wininfo = WM_GetInfoPtr( WM_GetActiveDoc() );
+ if ( ( wininfo->wType == WMTYPE_DISKTREE ) ||
+ ( wininfo->wType == WMTYPE_TAPETREE ) ) {
+ VLM_CollapseBranch( WM_GetActiveDoc() );
+ }
+#ifdef OEM_EMS
+ if ( wininfo->wType == WMTYPE_EXCHANGE ) {
+ SLM_EMSCollapseBranch( WM_GetActiveDoc() );
+ }
+#endif
+ break;
+
+ case ID_CLOSEALL:
+
+ // User has requested all windows be closed for him.
+
+ VLM_CloseAll();
+ break;
+
+ case ID_CTRLARROWUP:
+ wininfo = WM_GetInfoPtr( WM_GetActiveDoc() );
+ if ( ( wininfo->wType == WMTYPE_DISKTREE ) ||
+ ( wininfo->wType == WMTYPE_TAPETREE ) ) {
+
+ VLM_PrevBrotherDir( WM_GetActiveDoc() );
+ }
+#ifdef OEM_EMS
+ if ( wininfo->wType == WMTYPE_EXCHANGE ) {
+ SLM_EMSPrevBrotherDir( WM_GetActiveDoc() );
+ }
+#endif
+ break;
+
+ case ID_CTRLARROWDOWN:
+ wininfo = WM_GetInfoPtr( WM_GetActiveDoc() );
+ if ( ( wininfo->wType == WMTYPE_DISKTREE ) ||
+ ( wininfo->wType == WMTYPE_TAPETREE ) ) {
+
+ VLM_NextBrotherDir( WM_GetActiveDoc() );
+ }
+#ifdef OEM_EMS
+ if ( wininfo->wType == WMTYPE_EXCHANGE ) {
+ SLM_EMSNextBrotherDir( WM_GetActiveDoc() );
+ }
+#endif
+ break;
+
+ case ID_ARROWLEFT:
+ wininfo = WM_GetInfoPtr( WM_GetActiveDoc() );
+ if ( ( wininfo->wType == WMTYPE_DISKTREE ) ||
+ ( wininfo->wType == WMTYPE_TAPETREE ) ) {
+
+ VLM_UpOneDir( WM_GetActiveDoc() );
+ }
+#ifdef OEM_EMS
+ if ( wininfo->wType == WMTYPE_EXCHANGE ) {
+ SLM_EMSUpOneDir( WM_GetActiveDoc() );
+ }
+#endif
+ break;
+
+ case ID_ARROWRIGHT:
+ wininfo = WM_GetInfoPtr( WM_GetActiveDoc() );
+ if ( ( wininfo->wType == WMTYPE_DISKTREE ) ||
+ ( wininfo->wType == WMTYPE_TAPETREE ) ) {
+
+ VLM_DownOneDir( WM_GetActiveDoc() );
+ }
+#ifdef OEM_EMS
+ if ( wininfo->wType == WMTYPE_EXCHANGE ) {
+ SLM_EMSDownOneDir( WM_GetActiveDoc() );
+ }
+#endif
+ break;
+
+ case ID_DELETE:
+ break;
+
+ default:
+
+ // Someone added a new message and didn't tell me !
+ break;
+ }
+}
+
+
+
+
+/**********************
+
+ NAME : VLM_FreeVLMList
+
+ DESCRIPTION :
+
+ Every time the user flips servers on/off we have to remove all the
+ mapped drives or add them in to our vlm_list. It easier to just free
+ the whole list and rebuild it from scratch. This function does that
+ freeing process, so it can be rebuilt.
+
+ RETURNS :
+
+**********************/
+
+VOID VLM_FreeVLMList(
+Q_HEADER_PTR vlm_list ) // I - queue to use
+{
+ VLM_OBJECT_PTR vlm;
+ Q_ELEM_PTR ptr;
+ Q_ELEM_PTR ptr2;
+
+ // Why would you pass me a NULL vlm_list pointer ?
+
+ if ( vlm_list != NULL ) {
+
+ ptr = DeQueueElem( vlm_list );
+
+ while ( ptr != NULL ) {
+
+ vlm = ( VLM_OBJECT_PTR )ptr->q_ptr; // Get a VLM
+
+ // Now try to free her children
+
+ ptr2 = DeQueueElem( &vlm->children ); // Get her first child
+
+ while ( ptr2 != NULL ) {
+ free( ptr2->q_ptr );
+ ptr2 = DeQueueElem( &vlm->children ); // get next child
+ }
+
+ free( vlm ); // free the vlm
+
+ ptr = DeQueueElem( vlm_list ); // get next vlm
+ }
+ }
+
+
+}
+
+/**********************
+
+ NAME : VLM_ShowServers
+
+ DESCRIPTION :
+
+ User has toggled between servers and mapped drives, close off one
+ and then open the other.
+
+ RETURNS :
+
+**********************/
+
+BOOLEAN VLM_ShowServers( BOOLEAN init )
+{
+ GENERIC_DLE_PTR dle;
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ BSD_PTR bsd;
+ HWND win;
+ HWND bad_win;
+
+
+ // close all mapped drive/server volume disktree windows
+
+ win = WM_GetNext( (HWND)NULL );
+
+ while ( win != (HWND)NULL ) {
+
+ bad_win = (HWND)NULL;
+ wininfo = WM_GetInfoPtr( win );
+
+ if ( wininfo->wType == WMTYPE_DISKTREE ) {
+
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( win );
+
+ if ( DLE_HasFeatures( appinfo->dle, DLE_FEAT_REMOTE_DRIVE ) ) {
+
+ bad_win = win;
+ }
+ }
+
+ win = WM_GetNext( win );
+
+ if ( bad_win ) {
+ WM_Destroy( bad_win );
+ }
+ }
+
+ // Now look for bsd's that should not be around.
+
+ bsd = BSD_GetFirst( bsd_list );
+
+ while ( bsd != NULL ) {
+
+ dle = BSD_GetDLE( bsd );
+
+ if ( ( DLE_GetDeviceType( dle ) != LOCAL_DOS_DRV ) &&
+ ( DLE_GetDeviceType( dle ) != LOCAL_NTFS_DRV ) ) {
+
+ BSD_ClearAllFSE( bsd );
+ BSD_Remove( bsd );
+ bsd = BSD_GetFirst( bsd_list );
+ }
+ else {
+ bsd = BSD_GetNext( bsd );
+ }
+ }
+
+
+ // Now that you have closed off all the offending windows
+
+ if ( ! init ) {
+
+ // remove or add mapped drives from drive window list
+
+ wininfo = WM_GetInfoPtr( gb_disks_win );
+
+ // trash the whole list
+
+ VLM_FreeVLMList( wininfo->pFlatList );
+
+ // and the rebuild it
+
+ VLM_BuildVolumeList( wininfo->pFlatList, wininfo );
+
+ // Update the screen
+
+ DLM_Update( gb_disks_win, DLM_FLATLISTBOX, WM_DLMUPDATELIST,
+ (LMHANDLE)wininfo->pFlatList, 0 );
+
+ // update selection boxes
+
+ VLM_UpdateDisks( );
+ }
+
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ if ( gfServers ) {
+
+ // open up server window
+ if ( gb_servers_win == (HWND)NULL ) {
+ VLM_ServerListCreate( );
+ }
+ }
+ else {
+
+ if ( gb_servers_win != (HWND)NULL ) {
+
+ wininfo = WM_GetInfoPtr( gb_servers_win );
+ wininfo->wClosable = TRUE;
+
+ // close server window
+
+ WM_Destroy( gb_servers_win );
+ gb_servers_win = (HWND)NULL;
+ }
+ }
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ return( SUCCESS );
+
+}
diff --git a/private/utils/ntbackup/src/vlm_poll.c b/private/utils/ntbackup/src/vlm_poll.c
new file mode 100644
index 000000000..92fbfb86f
--- /dev/null
+++ b/private/utils/ntbackup/src/vlm_poll.c
@@ -0,0 +1,722 @@
+
+
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: VLM_POLL.C
+
+ Description:
+
+ Poll drive stuff
+
+ $Log: J:\ui\logfiles\vlm_poll.c_v $
+
+ Rev 1.48.1.1 07 Feb 1994 02:05:58 GREGG
+Fixed and expanded 'extended error reporting'.
+
+ Rev 1.48.1.0 01 Dec 1993 14:16:24 mikep
+add SQL recognition support to poll drive
+
+ Rev 1.48 27 Jul 1993 22:05:26 MIKEP
+add out of seq msg
+
+ Rev 1.47 27 Jul 1993 14:44:18 MARINA
+enable c++
+
+ Rev 1.46 19 Jul 1993 21:06:00 MIKEP
+add support for ecc, future ver, and encrypted tapes.
+
+ Rev 1.45 07 Jul 1993 08:51:32 MIKEP
+fix epr 357-463. It was repainting the sets side of the
+tape window when it didn't need to.
+
+ Rev 1.44 27 Jun 1993 14:07:20 MIKEP
+continue work on status monitor stuff
+
+ Rev 1.43 08 Jun 1993 11:04:44 CARLS
+Remove VLM_GetFirstSSETonTapeAttributes - not needed
+
+ Rev 1.42 07 Jun 1993 08:12:52 MIKEP
+fix transfer so afterwards there is an active tape displayed.
+
+ Rev 1.41 27 May 1993 15:39:28 CARLS
+Added function call VLM_GetSSETonTapeAttribute and
+code in VLM_TapeChanged to save the first SSET attribute.
+
+ Rev 1.40 12 May 1993 08:26:24 MIKEP
+change way addfake tape works.
+
+ Rev 1.39 06 May 1993 14:51:06 MIKEP
+fix the tapes window to be more accurate to tape drive state.
+
+ Rev 1.38 03 May 1993 16:13:30 MIKEP
+Put current tape as focus tape in tapes window.
+
+ Rev 1.37 28 Apr 1993 16:36:32 CARLS
+added code for drive failure in GetDriveStatus call
+
+ Rev 1.36 26 Apr 1993 08:52:34 MIKEP
+Add numerous changes to fully support the font case selection
+for various file system types. Also add refresh for tapes window
+and sorting of tapes window.
+
+ Rev 1.34 02 Apr 1993 15:52:30 CARLS
+changes for DC2000 unformatted tape
+
+ Rev 1.33 30 Mar 1993 16:24:18 GREGG
+Changed PD_UNFORMATTED_TAPE to PD_UNRECOGNIZED_MEDIA.
+
+ Rev 1.32 13 Mar 1993 16:28:50 MIKEP
+foreign tape prompt
+
+ Rev 1.31 12 Mar 1993 15:17:40 MIKEP
+add unformated tape support
+
+ Rev 1.30 12 Mar 1993 14:43:16 MIKEP
+auto call erase if foreign tape
+
+ Rev 1.29 14 Dec 1992 12:24:56 DAVEV
+Enabled for Unicode compile
+
+ Rev 1.28 17 Nov 1992 20:00:48 MIKEP
+add unformat display
+
+ Rev 1.27 27 Oct 1992 17:07:52 MIKEP
+display fixes
+
+ Rev 1.26 07 Oct 1992 15:08:22 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.25 04 Oct 1992 19:42:32 DAVEV
+Unicode Awk pass
+
+ Rev 1.24 02 Sep 1992 16:32:30 GLENN
+MikeP changes for NT.
+
+ Rev 1.23 29 Jul 1992 09:53:52 MIKEP
+ChuckB checked in after NT warnings were fixed.
+
+ Rev 1.22 19 Jun 1992 16:42:30 MIKEP
+add drive empty to tapes window
+
+ Rev 1.21 31 May 1992 11:12:14 MIKEP
+auto catalog changes
+
+ Rev 1.20 28 May 1992 15:22:50 MIKEP
+auto cat try #1
+
+ Rev 1.19 14 May 1992 18:05:58 MIKEP
+nt pass 2
+
+ Rev 1.18 11 May 1992 09:13:56 MIKEP
+64Bit support
+
+ Rev 1.17 06 May 1992 14:40:42 MIKEP
+unicode pass two
+
+ Rev 1.16 04 May 1992 13:39:32 MIKEP
+unicode pass 1
+
+ Rev 1.15 09 Apr 1992 08:46:14 MIKEP
+speed up lots of sets
+
+
+****************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+// Used to maintain the info about the current tape in the drive.
+
+static DBLK current_vcb;
+static INT16 current_status = VLM_NO_TAPE;
+
+/**********************
+
+ NAME : VLM_GetDriveStatus
+
+ DESCRIPTION :
+
+ This function is used by all the dialogs and other areas that want to
+ know the status of the tape in the drive. If there is a valid vcb, it
+ will set thier vcb pointer to point to the vcb we save.
+
+ RETURNS :
+
+ VLM_VALID_TAPE - a good vcb is available
+ VLM_FOREIGN_TAPE - tape has unknown format
+ VLM_BLANK_TAPE - blank tape in drive
+ VLM_NO_TAPE - drive is empty
+ VLM_BUSY - drive is busy vcb'ing a tape
+ VLM_BAD_TAPE - read failed, propably exabyte tape in wrong type of drive
+ VLM_GOOFY_TAPE - must have tape 1 to tell what it is
+ VLM_DISABLED - poll drive is no longer working
+ VLM_UNFORMATED - dc2000 tape
+ VLM_FUTURE_VER - made with a future version of the software
+ VLM_ECC_TAPE - encrypted tape
+
+
+**********************/
+
+INT VLM_GetDriveStatus( DBLK_PTR *vcb )
+{
+
+ if ( ! gfPollDrive ) {
+ return( VLM_DISABLED );
+ }
+
+ if ( vcb != NULL ) {
+ if ( current_status == VLM_VALID_TAPE ) {
+ *vcb = &current_vcb;
+ }
+ else {
+ *vcb = NULL;
+ }
+ }
+
+ return( current_status );
+}
+
+
+
+/**********************
+
+ NAME : VLM_ClearCurrentTape
+
+ DESCRIPTION :
+ Clear any tape's current status if it's tape fid is not the
+ one passed in.
+
+ RETURNS :
+
+**********************/
+
+VOID VLM_ClearCurrentTape( UINT32 tape_fid, BOOLEAN UpdateScreen )
+{
+ TAPE_OBJECT_PTR tape;
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ BOOL UpdateFlatList = FALSE;
+
+ wininfo = WM_GetInfoPtr( gb_tapes_win );
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( gb_tapes_win );
+
+ tape = VLM_GetFirstTAPE();
+
+ while ( tape != NULL ) {
+
+ // If it was current change the bitmap on it.
+
+ if ( ( tape->current ) && ( tape->tape_fid != tape_fid ) ) {
+
+ tape->current = FALSE;
+ if ( UpdateScreen ) {
+ DLM_Update( gb_tapes_win,
+ DLM_TREELISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)tape, 0 );
+ }
+ }
+
+ // Remove any fake tapes.
+
+ if ( tape->fake_tape ) {
+
+ // If it was active then pick a new active.
+
+ if ( appinfo->open_tape == tape ) {
+
+ UpdateFlatList = TRUE;
+
+ appinfo->open_tape = VLM_GetFirstTAPE( );
+
+ while ( appinfo->open_tape ) {
+
+ if ( appinfo->open_tape->fake_tape ) {
+ appinfo->open_tape = VLM_GetNextTAPE( appinfo->open_tape );
+ }
+ else {
+ break;
+ }
+ }
+
+ if ( appinfo->open_tape != NULL ) {
+ appinfo->open_tape->status |= INFO_OPEN;
+ wininfo->pFlatList = &appinfo->open_tape->bset_list;
+ }
+ else {
+ wininfo->pFlatList = NULL;
+ }
+ }
+
+ // Remove it from queue and memory
+
+ RemoveQueueElem( wininfo->pTreeList, &(tape->q_elem) );
+ free( tape );
+
+ // Update the lists.
+ if ( UpdateScreen ) {
+ DLM_Update( gb_tapes_win,
+ DLM_TREELISTBOX,
+ WM_DLMUPDATELIST,
+ (LMHANDLE)wininfo->pTreeList, 0 );
+
+ if ( UpdateFlatList ) {
+ DLM_Update( gb_tapes_win,
+ DLM_FLATLISTBOX,
+ WM_DLMUPDATELIST,
+ (LMHANDLE)wininfo->pFlatList, 0 );
+ }
+ }
+
+ tape = VLM_GetFirstTAPE();
+ }
+ else {
+ tape = VLM_GetNextTAPE( tape );
+ }
+
+ }
+}
+
+/**********************
+
+ NAME : VLM_AddFakeTape
+
+ DESCRIPTION :
+
+ The user has a blank, foriegn or bad tape in the drive. So place a dummy
+ entry in the tapes list for it.
+
+ RETURNS :
+
+**********************/
+
+VOID VLM_AddFakeTape( INT16 status )
+{
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ TAPE_OBJECT_PTR tape;
+ CHAR name[ MAX_UI_RESOURCE_SIZE ];
+
+ switch ( status ) {
+
+ case VLM_ECC_TAPE:
+ RSM_StringCopy( RES_VLM_ECC_TAPE, name, MAX_UI_RESOURCE_LEN );
+ break;
+
+ case VLM_FUTURE_VER:
+ RSM_StringCopy( RES_VLM_FUTURE_TAPE, name, MAX_UI_RESOURCE_LEN );
+ break;
+
+ case VLM_SQL_TAPE:
+ RSM_StringCopy( RES_VLM_SQL_TAPE, name, MAX_UI_RESOURCE_LEN );
+ break;
+
+ case VLM_BLANK_TAPE:
+ RSM_StringCopy( RES_VLM_BLANK_TAPE, name, MAX_UI_RESOURCE_LEN );
+ break;
+
+ case VLM_BAD_TAPE:
+ RSM_StringCopy( RES_VLM_BAD_TAPE, name, MAX_UI_RESOURCE_LEN );
+ break;
+
+ case VLM_FOREIGN_TAPE:
+ RSM_StringCopy( RES_VLM_FOREIGN_TAPE, name, MAX_UI_RESOURCE_LEN );
+ break;
+
+ case VLM_NO_TAPE:
+ RSM_StringCopy( RES_VLM_NO_TAPE, name, MAX_UI_RESOURCE_LEN );
+ break;
+
+ case VLM_BUSY:
+ RSM_StringCopy( RES_VLM_BUSY_DRIVE, name, MAX_UI_RESOURCE_LEN );
+ break;
+
+ case VLM_GOOFY_TAPE:
+ RSM_StringCopy( RES_VLM_GOOFY_TAPE, name, MAX_UI_RESOURCE_LEN );
+ break;
+
+ case VLM_UNFORMATED:
+ RSM_StringCopy( RES_VLM_UNFORMATED_TAPE, name, MAX_UI_RESOURCE_LEN );
+ break;
+
+ default:
+ return;
+ }
+
+ wininfo = WM_GetInfoPtr( gb_tapes_win );
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( gb_tapes_win );
+
+ tape = VLM_CreateTAPE( (INT16) strsize( name ) );
+
+ if ( tape == NULL ) {
+
+ // We tried.
+ return;
+ }
+
+ TAPE_SetFID( tape, 0 );
+ TAPE_SetTapeNum( tape, 0 );
+ TAPE_SetFake( tape, TRUE );
+ TAPE_SetStatus( tape, INFO_DISPLAY );
+ TAPE_SetCurrent( tape, TRUE );
+ TAPE_SetXtraBytes( tape, wininfo );
+ TAPE_SetName( tape, name );
+
+ VLM_InsertTapeInQueue( wininfo->pTreeList, tape );
+
+ DLM_Update( gb_tapes_win,
+ DLM_TREELISTBOX,
+ WM_DLMUPDATELIST,
+ (LMHANDLE)wininfo->pTreeList, 0 );
+
+ if ( QueueCount( wininfo->pTreeList ) == 1 ) {
+
+ appinfo->open_tape = tape;
+
+ DLM_SetAnchor( WMDS_GetWinTreeList( wininfo ),
+ 0, (LMHANDLE)tape );
+ }
+}
+
+
+/**********************
+
+ NAME : VLM_TapeChanged
+
+ DESCRIPTION :
+
+ Poll drive has returned that a change has occurred in the status of the
+ tape drive. The UI is being told.
+
+ RETURNS :
+
+**********************/
+
+VOID VLM_TapeChanged( INT16 msg, DBLK_PTR vcb, FSYS_HAND fsh )
+{
+
+ DBG_UNREFERENCED_PARAMETER ( fsh );
+
+
+ //
+ // Always set the current_status before calling MUI_TapeInDrive() it will query it for button state.
+ //
+
+
+ switch ( msg ) {
+
+ case PD_DRIVE_FAILURE:
+ case PD_DRIVER_FAILURE:
+ SetStatusBlock( IDSM_DRIVESTATUS, STAT_DRIVE_ERROR );
+ SetStatusBlock( IDSM_TAPEFAMILY, (DWORD)0 );
+ SetStatusBlock( IDSM_TAPESEQNUMBER, (DWORD)0 );
+ SetStatusBlock( IDSM_BACKUPSET, (DWORD)0 );
+ current_status = VLM_DRIVE_FAILURE;
+ MUI_TapeInDrive( FALSE );
+ break;
+
+ case PD_NEW_TAPE:
+ current_status = VLM_BUSY;
+ SetStatusBlock( IDSM_DRIVESTATUS, STAT_DRIVE_BUSY );
+ SetStatusBlock( IDSM_TAPEFAMILY, (DWORD)0 );
+ SetStatusBlock( IDSM_TAPESEQNUMBER, (DWORD)0 );
+ SetStatusBlock( IDSM_BACKUPSET, (DWORD)0 );
+ MUI_TapeInDrive( TRUE );
+ VLM_ClearCurrentTape( 0L, TRUE );
+ VLM_AddFakeTape( current_status );
+ break;
+
+ case PD_FOREIGN_TAPE:
+ SetStatusBlock( IDSM_DRIVESTATUS, STAT_DRIVE_FOREIGN );
+ SetStatusBlock( IDSM_TAPEFAMILY, (DWORD)0 );
+ SetStatusBlock( IDSM_TAPESEQNUMBER, (DWORD)0 );
+ SetStatusBlock( IDSM_BACKUPSET, (DWORD)0 );
+ if ( current_status != VLM_FOREIGN_TAPE ) {
+ current_status = VLM_FOREIGN_TAPE;
+ MUI_TapeInDrive ( TRUE );
+ VLM_ClearCurrentTape( 0L, TRUE );
+ VLM_AddFakeTape( current_status );
+
+ WM_ShowWaitCursor( FALSE ) ;
+
+ WM_MsgBox( ID( IDS_VLMFOREIGNTITLE ),
+ ID( IDS_VLMFOREIGNTEXT ),
+ WMMB_IDOK,
+ WMMB_ICONEXCLAMATION ) ;
+ }
+ break;
+
+ case PD_SQL_TAPE:
+ SetStatusBlock( IDSM_DRIVESTATUS, STAT_DRIVE_FOREIGN );
+ SetStatusBlock( IDSM_TAPEFAMILY, (DWORD)0 );
+ SetStatusBlock( IDSM_TAPESEQNUMBER, (DWORD)0 );
+ SetStatusBlock( IDSM_BACKUPSET, (DWORD)0 );
+ if ( current_status != VLM_SQL_TAPE ) {
+ current_status = VLM_SQL_TAPE;
+ MUI_TapeInDrive ( TRUE );
+ VLM_ClearCurrentTape( 0L, TRUE );
+ VLM_AddFakeTape( current_status );
+
+ WM_MsgBox( ID( IDS_VLMFOREIGNTITLE ),
+ ID( IDS_VLMSQLTEXT ),
+ WMMB_IDOK,
+ WMMB_ICONEXCLAMATION ) ;
+ }
+ break;
+
+
+ case PD_FUTURE_REV_MTF:
+ SetStatusBlock( IDSM_DRIVESTATUS, STAT_DRIVE_FOREIGN );
+ SetStatusBlock( IDSM_TAPEFAMILY, (DWORD)0 );
+ SetStatusBlock( IDSM_TAPESEQNUMBER, (DWORD)0 );
+ SetStatusBlock( IDSM_BACKUPSET, (DWORD)0 );
+ if ( current_status != VLM_FUTURE_VER ) {
+ current_status = VLM_FUTURE_VER;
+ MUI_TapeInDrive ( TRUE );
+ VLM_ClearCurrentTape( 0L, TRUE );
+ VLM_AddFakeTape( current_status );
+
+ WM_MsgBox( ID( IDS_VLMFOREIGNTITLE ),
+ ID( IDS_VLMFUTURETEXT ),
+ WMMB_IDOK,
+ WMMB_ICONEXCLAMATION ) ;
+ }
+ break;
+
+ case PD_MTF_ECC_TAPE:
+ SetStatusBlock( IDSM_DRIVESTATUS, STAT_DRIVE_FOREIGN );
+ SetStatusBlock( IDSM_TAPEFAMILY, (DWORD)0 );
+ SetStatusBlock( IDSM_TAPESEQNUMBER, (DWORD)0 );
+ SetStatusBlock( IDSM_BACKUPSET, (DWORD)0 );
+ if ( current_status != VLM_ECC_TAPE ) {
+ current_status = VLM_ECC_TAPE;
+ MUI_TapeInDrive ( TRUE );
+ VLM_ClearCurrentTape( 0L, TRUE );
+ VLM_AddFakeTape( current_status );
+
+ WM_MsgBox( ID( IDS_VLMFOREIGNTITLE ),
+ ID( IDS_VLMECCTEXT ),
+ WMMB_IDOK,
+ WMMB_ICONEXCLAMATION ) ;
+ }
+ break;
+
+
+ case PD_UNRECOGNIZED_MEDIA:
+ SetStatusBlock( IDSM_DRIVESTATUS, STAT_DRIVE_UNFORMATTED );
+ SetStatusBlock( IDSM_TAPEFAMILY, (DWORD)0 );
+ SetStatusBlock( IDSM_TAPESEQNUMBER, (DWORD)0 );
+ SetStatusBlock( IDSM_BACKUPSET, (DWORD)0 );
+ if ( current_status != VLM_UNFORMATED ) {
+ current_status = VLM_UNFORMATED;
+ MUI_TapeInDrive ( TRUE );
+ VLM_ClearCurrentTape( 0L, TRUE );
+ VLM_AddFakeTape( current_status );
+
+ WM_MsgBox( ID( IDS_VLMUNFORMATEDTITLE ),
+ ID( IDS_VLMUNFORMATEDTEXT ),
+ WMMB_IDOK,
+ WMMB_ICONEXCLAMATION ) ;
+
+
+ }
+ break;
+
+
+ case PD_BLANK_TAPE:
+ SetStatusBlock( IDSM_DRIVESTATUS, STAT_DRIVE_BLANK );
+ SetStatusBlock( IDSM_TAPEFAMILY, (DWORD)0 );
+ SetStatusBlock( IDSM_TAPESEQNUMBER, (DWORD)0 );
+ SetStatusBlock( IDSM_BACKUPSET, (DWORD)0 );
+ if ( current_status != VLM_BLANK_TAPE ) {
+ current_status = VLM_BLANK_TAPE;
+ MUI_TapeInDrive( TRUE );
+ VLM_ClearCurrentTape( 0L, TRUE );
+ VLM_AddFakeTape( current_status );
+ }
+ break;
+
+ case PD_NO_TAPE:
+ SetStatusBlock( IDSM_DRIVESTATUS, STAT_DRIVE_EMPTY );
+ SetStatusBlock( IDSM_TAPEFAMILY, (DWORD)0 );
+ SetStatusBlock( IDSM_TAPESEQNUMBER, (DWORD)0 );
+ SetStatusBlock( IDSM_BACKUPSET, (DWORD)0 );
+ if ( current_status != VLM_NO_TAPE ) {
+ current_status = VLM_NO_TAPE;
+ MUI_TapeInDrive( FALSE );
+ VLM_ClearCurrentTape( 0L, TRUE );
+ VLM_AddFakeTape( current_status );
+ }
+ break;
+
+ case PD_BUSY:
+ SetStatusBlock( IDSM_DRIVESTATUS, STAT_DRIVE_BUSY );
+ SetStatusBlock( IDSM_TAPEFAMILY, (DWORD)0 );
+ SetStatusBlock( IDSM_TAPESEQNUMBER, (DWORD)0 );
+ SetStatusBlock( IDSM_BACKUPSET, (DWORD)0 );
+ if ( current_status != VLM_BUSY ) {
+ current_status = VLM_BUSY;
+ MUI_TapeInDrive( FALSE );
+ VLM_ClearCurrentTape( 0L, TRUE );
+ VLM_AddFakeTape( current_status );
+ }
+ break;
+
+ case PD_VALID_VCB:
+ SetStatusBlock( IDSM_DRIVESTATUS, STAT_DRIVE_VALID );
+ SetStatusBlock( IDSM_TAPEFAMILY, (DWORD)FS_ViewTapeIDInVCB( vcb ) );
+ SetStatusBlock( IDSM_TAPESEQNUMBER, (DWORD)FS_ViewTSNumInVCB( vcb ) );
+ SetStatusBlock( IDSM_BACKUPSET, (DWORD)FS_ViewBSNumInVCB( vcb ) );
+
+ current_status = VLM_VALID_TAPE;
+ MUI_TapeInDrive ( TRUE );
+ memcpy( &current_vcb, vcb, sizeof( DBLK ) );
+ VLM_AddTapeIfUnknown( TRUE );
+
+ break;
+
+ case PD_BAD_TAPE:
+ SetStatusBlock( IDSM_DRIVESTATUS, STAT_DRIVE_BAD );
+ SetStatusBlock( IDSM_TAPEFAMILY, (DWORD)0 );
+ SetStatusBlock( IDSM_TAPESEQNUMBER, (DWORD)0 );
+ SetStatusBlock( IDSM_BACKUPSET, (DWORD)0 );
+ if ( current_status != VLM_BAD_TAPE ) {
+ current_status = VLM_BAD_TAPE;
+ MUI_TapeInDrive ( TRUE );
+ VLM_ClearCurrentTape( 0L, TRUE );
+ VLM_AddFakeTape( current_status );
+ }
+ break;
+
+ case PD_OUT_OF_SEQUENCE:
+ SetStatusBlock( IDSM_DRIVESTATUS, STAT_DRIVE_VALID );
+ SetStatusBlock( IDSM_TAPEFAMILY, (DWORD)0 );
+ SetStatusBlock( IDSM_TAPESEQNUMBER, (DWORD)0 );
+ SetStatusBlock( IDSM_BACKUPSET, (DWORD)0 );
+ if ( current_status != VLM_GOOFY_TAPE ) {
+ current_status = VLM_GOOFY_TAPE;
+ MUI_TapeInDrive( TRUE );
+ VLM_ClearCurrentTape( 0L, TRUE );
+ VLM_AddFakeTape( current_status );
+
+ WM_MsgBox( ID( IDS_VLMGOOFYTITLE ),
+ ID( IDS_VLMGOOFYTEXT ),
+ WMMB_IDOK,
+ WMMB_ICONEXCLAMATION ) ;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+
+/**********************
+
+ NAME : VLM_AddTapeIfUnknown
+
+ DESCRIPTION :
+
+ This function will add the tape in the drive to the cats/vlm if it is
+ not known and/or make it the current tape. It is called when poll
+ drive reports a new tape.
+
+ RETURNS :
+
+**********************/
+
+VOID VLM_AddTapeIfUnknown( BOOLEAN UpdateScreen )
+{
+ TAPE_OBJECT_PTR tape;
+ QTC_BUILD_PTR qtc;
+ UINT32 tape_fid;
+ INT16 tape_num;
+ INT16 bset_num;
+
+ if ( current_status == VLM_VALID_TAPE ) {
+
+ // See which tape it is.
+
+ tape_fid = FS_ViewTapeIDInVCB( &current_vcb );
+ tape_num = FS_ViewTSNumInVCB( &current_vcb );
+ bset_num = FS_ViewBSNumInVCB( &current_vcb );
+
+ // Clear the old current tape, if its not the same one.
+
+ VLM_ClearCurrentTape( tape_fid, UpdateScreen );
+
+ // See if the catalogs know of this set already.
+
+ if ( QTC_FindBset( tape_fid, tape_num, bset_num ) == NULL ) {
+
+ // Add the new tape to QTC and VLM here
+ // because we've never seen it before.
+
+ qtc = QTC_GetBuildHandle( );
+ QTC_DoFullCataloging( qtc, FALSE );
+ QTC_StartBackup( qtc, &current_vcb );
+
+ VLM_CheckForCatalogError( qtc );
+
+ QTC_FreeBuildHandle( qtc );
+
+ VLM_AddBset( tape_fid, tape_num, bset_num, NULL, UpdateScreen );
+ }
+
+ if ( VLM_FindBset( tape_fid, bset_num ) == NULL ) {
+
+ VLM_AddBset( tape_fid, tape_num, bset_num, NULL, UpdateScreen );
+ }
+
+ // Now that we know the tape should be around, find it.
+
+ tape = VLM_GetFirstTAPE();
+
+ while ( tape != NULL ) {
+
+ if ( tape->tape_fid == tape_fid ) {
+ break;
+ }
+ tape = VLM_GetNextTAPE( tape );
+ }
+
+ if ( tape != NULL ) {
+
+ // Make this tape the current tape.
+
+ if ( ! tape->current ) {
+
+ tape->current = TRUE;
+
+ if ( UpdateScreen ) {
+
+ // Add the tape to the current list.
+
+ DLM_Update( gb_tapes_win,
+ DLM_TREELISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)tape, 0 );
+
+ // Let's make it viewable.
+
+ DLM_SetAnchor( WMDS_GetWinTreeList( TAPE_GetXtraBytes( tape ) ),
+ 0,
+ (LMHANDLE)tape );
+
+ // Make it the active tape.
+
+ VLM_TapeSetObjects( tape, WM_DLMDOWN, 2 );
+
+ }
+ }
+ }
+
+ }
+
+}
diff --git a/private/utils/ntbackup/src/vlm_refr.c b/private/utils/ntbackup/src/vlm_refr.c
new file mode 100644
index 000000000..a19009e1c
--- /dev/null
+++ b/private/utils/ntbackup/src/vlm_refr.c
@@ -0,0 +1,735 @@
+
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: VLM_REFR.C
+
+ Description:
+
+ This file contains the functions needed to perform
+ the refresh call.
+
+ $Log: G:\UI\LOGFILES\VLM_REFR.C_V $
+
+ Rev 1.31.1.2 14 Jan 1994 14:36:24 MIKEP
+fix refresh and up arrow display
+
+ Rev 1.31.1.1 14 Dec 1993 15:25:34 GREGG
+Go deeper!!!
+
+ Rev 1.31.1.0 08 Dec 1993 11:28:54 MikeP
+deep pathes and unicode
+
+ Rev 1.31 05 Aug 1993 10:52:36 MIKEP
+fix refresh epr
+
+ Rev 1.30 27 Jul 1993 14:51:00 MARINA
+enable c++
+
+ Rev 1.29 15 Jul 1993 16:05:50 MIKEP
+fix refresh tapes window call.
+
+ Rev 1.28 21 Jun 1993 15:58:00 KEVINS
+Allow a refresh of Log files window, when it is active.
+
+ Rev 1.27 01 Jun 1993 15:51:36 MIKEP
+make drive letter support match winfile.
+
+ Rev 1.26 20 May 1993 17:20:12 KEVINS
+Made VLM_RefreshDLE static again. Overlooked VLM_Refresh.
+
+ Rev 1.25 12 May 1993 17:58:26 KEVINS
+Made VLM_RefreshDLE public.
+
+ Rev 1.24 12 May 1993 08:28:44 MIKEP
+fix upper/lower case support for drives.
+
+ Rev 1.23 02 May 1993 15:28:30 MIKEP
+Fix pointer exception bug. Everyone needs this.
+
+ Rev 1.22 01 May 1993 16:26:22 MIKEP
+Fix case support for tree windows. You need vlm.h, vlm_tree.c, vlm_refr.c,
+and qtc.h.
+
+ Rev 1.21 26 Apr 1993 11:26:18 MIKEP
+Fix bug in last check in. If you took the last one, you really want
+this one instead. I was using a dle pointer right off the stack.
+
+ Rev 1.20 26 Apr 1993 08:52:46 MIKEP
+Add numerous changes to fully support the font case selection
+for various file system types. Also add refresh for tapes window
+and sorting of tapes window.
+
+ Rev 1.19 23 Apr 1993 10:20:32 MIKEP
+Add ability to refresh tapes window.
+Add support for sorting files window by various methods.
+Fix refresh of sorting windows.
+
+ Rev 1.18 22 Dec 1992 08:52:42 MIKEP
+fixes from msoft
+
+ Rev 1.17 07 Oct 1992 15:08:38 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.16 04 Oct 1992 19:42:36 DAVEV
+Unicode Awk pass
+
+ Rev 1.15 29 Jul 1992 09:32:26 MIKEP
+ChuckB checked in after NT warnings were fixed.
+
+ Rev 1.14 14 May 1992 18:06:08 MIKEP
+nt pass 2
+
+ Rev 1.13 06 May 1992 14:41:12 MIKEP
+unicode pass two
+
+ Rev 1.12 04 May 1992 13:40:06 MIKEP
+unicode pass 1
+
+ Rev 1.11 24 Mar 1992 14:41:52 DAVEV
+OEM_MSOFT: Removed Servers windows and associated code
+
+
+*****************************************************/
+
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+// Local static prototypes
+
+static INT VLM_FontCaseChangeDisks( HWND );
+static INT VLM_FontCaseChangeTree( HWND );
+static VOID VLM_RefreshDLE( VOID );
+static VOID VLM_RefreshTree( HWND );
+static INT VLM_RefreshDirList( Q_HEADER_PTR );
+static VOID VLM_ResetNextBrothers( Q_HEADER_PTR );
+
+/************************************
+
+ The user has changed the font case and we need to paint all the
+ windows if they need it. After adjusting any strings that need it.
+
+ Applies to Disks, Tape/Disk Tree, Search windows.
+
+*************************************/
+
+VOID VLM_FontCaseChange( )
+{
+ HWND win;
+ WININFO_PTR wininfo;
+
+ WM_ShowWaitCursor( TRUE );
+
+ win = WM_GetNext( (HWND)NULL );
+
+ while ( win != (HWND)NULL ) {
+
+ wininfo = WM_GetInfoPtr( win );
+
+ switch ( wininfo->wType ) {
+
+ case WMTYPE_TAPETREE:
+ case WMTYPE_DISKTREE:
+
+ // Refresh a tree window.
+
+ VLM_FontCaseChangeTree( win );
+
+ break;
+
+ case WMTYPE_DISKS:
+
+ // Refresh the disks window.
+
+ VLM_FontCaseChangeDisks( win );
+
+ break;
+
+ default:
+ // We don't handle anything else right now.
+
+ break;
+ }
+
+ win = WM_GetNext( win );
+ }
+
+ WM_ShowWaitCursor( FALSE );
+
+ return;
+}
+
+static INT VLM_FontCaseChangeTree( HWND win )
+{
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ Q_HEADER_PTR slm_list;
+ SLM_OBJECT_PTR slm;
+ BOOLEAN fLowerCase;
+ CHAR temp_buff[ VLM_BUFFER_SIZE ];
+ CHAR *temp;
+ CHAR *title;
+ CHAR *directory;
+ CHAR *s;
+ INT title_size;
+
+#ifdef OEM_EMS
+ UNREFERENCED_PARAMETER( s );
+#endif
+
+ wininfo = WM_GetInfoPtr( win );
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( win );
+
+ fLowerCase = FALSE;
+
+ // If new display name is different then the old one,
+ // update that item.
+
+ if ( CDS_GetFontCase( CDS_GetPerm() ) ) {
+ fLowerCase = TRUE;
+ }
+ else {
+ if ( CDS_GetFontCaseFAT( CDS_GetPerm() ) &&
+ appinfo->fFatDrive ) {
+ fLowerCase = TRUE;
+ }
+ }
+
+ slm_list = WMDS_GetTreeList( wininfo );
+
+ slm = VLM_GetFirstSLM( slm_list );
+
+ while ( slm ) {
+ if ( fLowerCase ) {
+ strlwr( SLM_GetName( slm ) );
+ }
+ else {
+ strcpy( SLM_GetName( slm ), SLM_GetOriginalName( slm ) );
+ if ( appinfo->fFatDrive ) {
+ strupr( SLM_GetName( slm ) );
+ }
+ }
+ slm = VLM_GetNextSLM( slm );
+ }
+
+ title_size = WM_GetTitle( win, NULL, 0 );
+
+ title = malloc( ( title_size + 1 ) * sizeof(CHAR ) );
+
+ if ( fLowerCase ) {
+ WM_GetTitle( win, title, title_size + 1 );
+ strlwr( title );
+ WM_SetTitle( win, title );
+ }
+ else {
+ WM_GetTitle( win, title, title_size + 1 );
+ strupr( title );
+ WM_SetTitle( win, title );
+ }
+
+ free( title );
+
+ DLM_Update( win,
+ DLM_TREELISTBOX,
+ WM_DLMUPDATELIST,
+ (LMHANDLE)wininfo->pTreeList, 0 );
+
+ // Set the anchor item.
+
+ DLM_SetAnchor( WMDS_GetWinTreeList( wininfo ),
+ 0,
+ (LMHANDLE)appinfo->open_slm );
+
+
+ // Do a file list reuse here of the same directory.
+ // to redo the files list on the screen.
+
+ if ( appinfo->dle != NULL ) {
+
+ DLE_GetVolName( appinfo->dle, temp_buff );
+
+ if ( temp_buff[ strlen( temp_buff ) - 1 ] != TEXT(':') ) {
+ strcat( temp_buff, TEXT(":") );
+ }
+
+ }
+ else {
+
+ sprintf( temp_buff, TEXT("%s-%s:"),
+ VLM_GetTapeName( appinfo->tape_fid ),
+ VLM_GetBsetName( appinfo->tape_fid, appinfo->bset_num ) );
+ }
+
+ temp = VLM_BuildPath( appinfo->open_slm );
+
+ directory = malloc( strsize( temp_buff ) + strsize( temp ) + 256 );
+
+ strcpy( directory, temp_buff );
+
+ if ( SLM_GetLevel( appinfo->open_slm ) != 0 ) {
+ strcat( directory, TEXT("\\") );
+ strcat( directory, temp );
+ }
+
+ free( temp );
+
+ // Change the displayed files
+
+ VLM_HandleFSError( VLM_FileListReuse( appinfo->win, directory ) ) ;
+
+ free( directory );
+
+ return( SUCCESS );
+}
+
+
+static INT VLM_FontCaseChangeDisks( HWND win )
+{
+
+ return( SUCCESS );
+}
+
+
+
+/**********************
+
+ NAME : VLM_Refresh
+
+ DESCRIPTION :
+
+ Refresh the current window. Determines type of window and calls
+ appropriate function to do work.
+
+ RETURNS : nothing.
+
+**********************/
+
+VOID VLM_Refresh( )
+{
+ WININFO_PTR wininfo;
+
+ wininfo = WM_GetInfoPtr( WM_GetActiveDoc() );
+
+ if ( wininfo == NULL ) {
+ msassert( FALSE );
+ return;
+ }
+
+ switch ( WMDS_GetWinType( wininfo ) ) {
+
+#ifdef OEM_EMS
+ case WMTYPE_EXCHANGE:
+#endif //OEM_EMS
+
+ case WMTYPE_SERVERS:
+ case WMTYPE_DISKS:
+ WM_ShowWaitCursor( TRUE );
+ VLM_RefreshDLE();
+ WM_ShowWaitCursor( FALSE );
+ break;
+
+ case WMTYPE_TAPES:
+ WM_ShowWaitCursor( TRUE );
+ VLM_CatalogDataPathChanged();
+ WM_ShowWaitCursor( FALSE );
+ break;
+
+ case WMTYPE_DISKTREE:
+ WM_ShowWaitCursor( TRUE );
+ VLM_RefreshTree( WM_GetActiveDoc() );
+ WM_ShowWaitCursor( FALSE );
+ break;
+
+ case WMTYPE_LOGFILES:
+ WM_ShowWaitCursor( TRUE );
+ LOG_Refresh( );
+ WM_ShowWaitCursor( FALSE );
+ break;
+
+ default:
+ break;
+
+ }
+
+}
+
+INT VLM_RefreshTapesWindow()
+{
+ return( SUCCESS );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static VOID VLM_RefreshDLE( )
+{
+ GENERIC_DLE_PTR dle;
+ GENERIC_DLE_PTR child_dle;
+
+ // We increment the bsd count on all server volume dle's to keep
+ // them around when we detach from the server. To allow the call
+ // to UpdateList to work we have to decrement the bsd count first
+ // because no dle's deemed "inuse" will be removed. Also our code
+ // expects that child dle's will be present. And the update call
+ // will yank any dle not inuse, ie. selections made. So after
+ // the update call we need to reattach and bump the bsd count.
+
+ DLE_GetFirst( dle_list, &dle );
+
+ while ( dle ) {
+
+ if ( DLE_GetDeviceType( dle ) == NOVELL_SERVER_ONLY ) {
+
+ DLE_GetFirstChild( dle, &child_dle );
+
+ while ( child_dle ) {
+
+ DLE_DecBSDCount( child_dle );
+ DLE_GetNext( &child_dle );
+ }
+ }
+
+ DLE_GetNext( &dle );
+ }
+
+ DLE_UpdateList( dle_list, CDS_GetPermBEC() );
+
+ if ( gb_disks_win != (HWND)NULL ) {
+
+ VLM_DisksSync( );
+ }
+
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ if ( gb_servers_win != (HWND)NULL ) {
+
+ VLM_ServersSync( );
+ }
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+#ifdef OEM_EMS
+ if ( gfExchange ) {
+
+ VLM_ExchangeSync( );
+ }
+#endif // OEM_EMS
+
+}
+
+/**********************
+
+ NAME : VLM_RefreshTree
+
+ DESCRIPTION :
+
+ Refresh the tree by making sure that all the files and directories present
+ are still on disk and new ones on disk are added.
+
+ RETURNS : nothing.
+
+**********************/
+
+static VOID VLM_RefreshTree( HWND win )
+{
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ Q_HEADER_PTR slm_list;
+ SLM_OBJECT_PTR slm;
+ SLM_OBJECT_PTR temp_slm;
+ FLM_OBJECT_PTR flm;
+ BOOLEAN something_added = FALSE;
+ BOOLEAN something_removed = FALSE;
+ CHAR_PTR directory;
+ CHAR focus_item[ VLM_BUFFER_SIZE ];
+ CHAR_PTR s;
+ CHAR title[ MAX_UI_RESOURCE_SIZE ];
+ CHAR text[ MAX_UI_RESOURCE_SIZE ];
+ CHAR *temp;
+
+#ifdef OEM_EMS
+ UNREFERENCED_PARAMETER( s );
+ UNREFERENCED_PARAMETER( text );
+ UNREFERENCED_PARAMETER( title );
+#endif
+
+ wininfo = WM_GetInfoPtr( win );
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( win );
+
+ slm_list = WMDS_GetTreeList( wininfo );
+
+ // Mark all the SLM's as NOT present.
+
+ slm = VLM_GetFirstSLM( slm_list );
+
+ while ( slm ) {
+
+ SLM_SetStatus( slm, (UINT16)INFO_OLD | SLM_GetStatus( slm ) );
+ SLM_SetStatus( slm, (UINT16)~INFO_NEW & SLM_GetStatus( slm ) );
+
+ slm = VLM_GetNextSLM( slm );
+ }
+
+ // See which SLM's are still there.
+
+ VLM_RefreshDirList( WMDS_GetTreeList( wininfo ) );
+
+ // See if the open directory went away.
+
+ if ( SLM_GetStatus( appinfo->open_slm ) & INFO_OLD ) {
+
+ slm = VLM_GetFirstSLM( slm_list );
+ slm->status |= INFO_OPEN;
+ appinfo->open_slm = slm;
+ }
+
+ temp = VLM_BuildPath( appinfo->open_slm );
+
+ directory = malloc( strsize( temp ) + 256 );
+ if ( directory == NULL ) {
+ free( temp );
+ return;
+ }
+
+ DLE_GetVolName( appinfo->dle, directory );
+
+ if ( directory[ strlen( directory ) - 1 ] != TEXT(':') ) {
+ strcat( directory, TEXT(":") );
+ }
+
+ // Change the title
+
+ if ( SLM_GetLevel( appinfo->open_slm ) != 0 ) {
+ strcat( directory, TEXT("\\") );
+ }
+
+ strcat( directory, temp );
+ free( temp );
+
+ flm = ( FLM_OBJECT_PTR )DLM_GetFocusItem( wininfo->hWndFlatList );
+
+ if ( flm != NULL ) {
+ strcpy( focus_item, FLM_GetName( flm ) );
+ }
+ else {
+ focus_item[0] = TEXT( '\0' );
+ }
+
+ VLM_HandleFSError( VLM_FileListReuse( appinfo->win, directory ) ) ;
+
+ strcat( directory, TEXT("\\*.*") );
+ WM_SetTitle( appinfo->win, directory );
+
+ free( directory );
+
+ flm = VLM_GetFirstFLM( WMDS_GetFlatList( wininfo ) );
+
+ while ( flm != NULL ) {
+
+ if ( ! ( stricmp( focus_item, FLM_GetName( flm ) ) ) ) {
+ break;
+ }
+ flm = VLM_GetNextFLM( flm );
+ }
+
+ if ( flm != NULL ) {
+
+ DLM_SetAnchor( WMDS_GetWinFlatList( wininfo ),
+ 0,
+ (LMHANDLE)flm );
+ }
+
+
+ // Remove any that are no longer presnt.
+
+ slm = VLM_GetFirstSLM( slm_list );
+
+ temp_slm = NULL;
+
+ while ( slm ) {
+
+ if ( SLM_GetStatus( slm ) & INFO_NEW ) {
+ something_added = TRUE;
+ }
+
+ if ( SLM_GetStatus( slm ) & INFO_OLD ) {
+
+ temp_slm = slm;
+ something_removed = TRUE;
+ }
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) & (UINT16)~INFO_NEW );
+
+ if ( slm != NULL ) {
+ slm = VLM_GetNextSLM( slm );
+ }
+
+ if ( temp_slm ) {
+ RemoveQueueElem( slm_list, &(temp_slm->q_elem) );
+ free( temp_slm );
+ temp_slm = NULL;
+ }
+ }
+
+ if ( something_removed ) {
+ VLM_ResetNextBrothers( slm_list );
+ }
+
+ // Update the lines on the left of the screen.
+ // Items could have been removed or inserted.
+
+ if ( something_added || something_removed ) {
+
+ VLM_UpdateBrothers( WMDS_GetTreeList( wininfo ) );
+
+ DLM_Update( win, DLM_TREELISTBOX, WM_DLMUPDATELIST, NULL, 0 );
+
+ DLM_SetAnchor( WMDS_GetWinTreeList( wininfo ),
+ 0,
+ (LMHANDLE)appinfo->open_slm );
+ }
+
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static INT VLM_RefreshDirList(
+Q_HEADER_PTR slm_list ) // I - queue to fill in
+{
+ SLM_OBJECT_PTR slm;
+ WININFO_PTR XtraBytes;
+ APPINFO_PTR appinfo;
+ BSD_PTR bsd_ptr;
+ FSE_PTR fse;
+ INT16 ret;
+
+ /*
+ 2. Mark all the slm's as old
+ 3. Call check for children with root
+ 4. remove any slm's that are still marked as old.
+ 5. New SLM's that have INFO_DISPLAY set need to be displayed.
+ 6. If the current path slm still exists
+ A. Save focus flm
+ B. Refresh flm list same way.
+ Else switch to the root for files.
+ */
+
+
+ slm = VLM_GetFirstSLM( slm_list );
+
+ XtraBytes = SLM_GetXtraBytes( slm );
+
+ appinfo = ( APPINFO_PTR )XtraBytes->pAppInfo;
+
+ FS_ChangeDir( appinfo->fsh, TEXT(""), (UINT16)sizeof(CHAR) );
+
+ bsd_ptr = BSD_FindByDLE( bsd_list, appinfo->dle );
+
+ // Mark root as being present.
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) & (UINT16)~INFO_OLD );
+
+ // Now let check for children do the rest
+
+ if ( VLM_CheckForChildren( slm_list, slm, TEXT(""), 10000, TRUE ) ) {
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) | (UINT16)INFO_SUBS );
+ }
+ else {
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) & (UINT16)~INFO_SUBS );
+ }
+
+ if ( bsd_ptr != NULL ) {
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) & (UINT16)~( INFO_PARTIAL | INFO_SELECT ) );
+
+ ret = BSD_MatchPathAndFile( bsd_ptr, &fse, NULL, TEXT(""),
+ (UINT16)sizeof(CHAR), SLM_GetAttribute( slm ),
+ NULL, NULL, NULL, FALSE, TRUE );
+
+ if ( ret == BSD_PROCESS_OBJECT ) {
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) | (UINT16)(INFO_SELECT | INFO_PARTIAL) );
+ }
+
+ if ( ret == BSD_PROCESS_ENTIRE_DIR ) {
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) | (UINT16)INFO_SELECT );
+ }
+ }
+
+ return( 0 );
+}
+
+
+/**********************
+
+ NAME : VLM_ResetNextBrothers
+
+ DESCRIPTION :
+
+ Correctly sets all the next_brother pointers in the slm list. Used after
+ an slm removal, which only happens during a refresh call.
+
+ RETURNS :
+
+**********************/
+
+VOID VLM_ResetNextBrothers( Q_HEADER_PTR slm_list )
+{
+
+// It won't blow up if you go deeper than this, but tree performance will
+// suffer. Display accuracy may suffer also.
+
+#define MAX_DEPTH 4000
+
+ SLM_OBJECT_PTR slm;
+ SLM_OBJECT_PTR array[ MAX_DEPTH ];
+ INT i;
+
+ for ( i = 0; i < MAX_DEPTH; i++ ) {
+ array[ i ] = NULL;
+ }
+
+ slm = VLM_GetLastSLM( slm_list );
+
+ while ( slm ) {
+
+ if ( slm->level > (UINT8)MAX_DEPTH ) {
+
+ slm->next_brother = NULL;
+ }
+ else {
+
+ slm->next_brother = array[ slm->level ];
+
+ array[ slm->level ] = slm;
+
+ for ( i = slm->level + 1; i < MAX_DEPTH; i++ ) {
+ array[ i ] = NULL;
+ }
+ }
+
+ slm = VLM_GetPrevSLM( slm );
+ }
+}
diff --git a/private/utils/ntbackup/src/vlm_srch.c b/private/utils/ntbackup/src/vlm_srch.c
new file mode 100644
index 000000000..21c52ed15
--- /dev/null
+++ b/private/utils/ntbackup/src/vlm_srch.c
@@ -0,0 +1,1997 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: VLM_SRCH.C
+
+ Description:
+
+ This file contains the functions needed to maintain the
+ search results window.
+
+ $Log: G:\UI\LOGFILES\VLM_SRCH.C_V $
+
+ Rev 1.49.1.0 08 Dec 1993 11:14:04 MikeP
+deep paths and unicode support
+
+ Rev 1.47 27 Jul 1993 15:14:34 MARINA
+enable c++
+
+ Rev 1.46 23 Jul 1993 15:10:36 MIKEP
+
+ Rev 1.45 22 Jun 1993 11:15:26 KEVINS
+Corrected another backup set password problem.
+
+ Rev 1.44 25 May 1993 17:20:44 KEVINS
+Corrected password checking logic regarding the searching of backup sets.
+
+ Rev 1.43 24 May 1993 15:22:12 BARRY
+Unicode fixes.
+
+ Rev 1.42 21 May 1993 13:42:34 GLENN
+Fixed hard coded text strings.
+
+ Rev 1.41 19 May 1993 14:54:00 KEVINS
+Correct problem of not searhing all catalogs when user double clicked on file.
+
+ Rev 1.40 18 May 1993 11:11:52 KEVINS
+Set first item in the search results window as the tagged item.
+
+ Rev 1.39 14 May 1993 14:15:38 KEVINS
+Don't create search results window if there are no search results.
+
+ Rev 1.38 27 Apr 1993 18:18:30 KEVINS
+Fixed compile error on line 661.
+
+ Rev 1.36 27 Apr 1993 14:38:02 KEVINS
+Shorten the history for test of pvcs get/put.
+
+ Rev 1.35 17 Mar 1993 18:12:22 DARRYLP
+Cleaned up display of file/date/time.
+
+ Rev 1.34 02 Mar 1993 16:49:08 ROBG
+Added *.CMD files to be displayed as executables for WIN32 apps.
+
+
+*****************************************************/
+
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+
+// How many objects are we going to display for each item:
+// check box, icon, name, path, size, date, time, attrib,
+// tape name, bset name, bset number
+
+#define NUM_DISPLAY_OBJECTS 11
+
+// This file only, there is ONLY ONE search window.
+
+static UINT8 mw_max_name_str; // max length of any srch name
+static UINT8 mw_max_path_str; // max length of any srch path
+static UINT8 mw_max_tape_str; // max length of any srch tape name
+static UINT8 mw_max_bset_str; // max length of any srch bset name
+static UINT8 mw_max_date_str; // max length of any srch date
+static UINT8 mw_max_time_str; // max length of any srch time
+static UINT8 mw_max_attr_str; // max length of any srch attribute
+static UINT8 mw_max_size_str; // max length of any srch size
+static UINT8 mw_max_set_str; // max length of any set size
+
+/*
+ The definition of a search object structure. Not currently used outside
+ this file.
+*/
+
+typedef struct srch_object {
+ Q_ELEM q_elem; // queue stuff
+ UINT16 status; // a bunch of bits
+ UINT32 attrib; // attributes
+ UINT16 mod_date; // date & time
+ UINT16 mod_time; // date & time
+ UINT64 size; // size in bytes
+ CHAR size_str[ FLM_MAX_FILE_SIZE ]; // size in text
+ CHAR_PTR date_str; // time,date,attr text
+ CHAR_PTR time_str; // time,date,attr text
+ CHAR_PTR attr_str; // time,date,attr text
+ CHAR_PTR name_str; // file name
+ CHAR_PTR path_str; // path
+ CHAR_PTR tape_str; // the tape it was found on
+ CHAR_PTR bset_str; // the bset it was found in
+ CHAR_PTR set_str; // set number;
+ UINT32 tape_fid; // tape family id
+ INT16 bset_num; // bset number
+ UINT8 level; // height in tree, 0 = root
+ WININFO_PTR XtraBytes; // pointer to xtrabytes
+
+} SRCH_OBJECT, *SRCH_OBJECT_PTR;
+
+
+// Local prototypes
+
+static INT VLM_CreateSearchWindowSpecs( PDS_WMINFO* );
+static INT VLM_FindSrchItem( Q_HEADER_PTR, QTC_QUERY_PTR );
+static VOID VLM_SetSelectionStatus( Q_HEADER_PTR, UINT32, INT16 );
+
+static SRCH_OBJECT_PTR VLM_GetFirstSRCH( Q_HEADER_PTR );
+static SRCH_OBJECT_PTR VLM_GetNextSRCH( SRCH_OBJECT_PTR );
+static SRCH_OBJECT_PTR VLM_GetPrevSRCH( SRCH_OBJECT_PTR );
+
+// Display call backs
+
+static BYTE VLM_SrchGetSelect( SRCH_OBJECT_PTR );
+static VOID_PTR VLM_SrchSetTag( SRCH_OBJECT_PTR, BYTE );
+static BYTE VLM_SrchGetTag( SRCH_OBJECT_PTR );
+static USHORT VLM_SrchGetItemCount( Q_HEADER_PTR );
+static VOID_PTR VLM_SrchGetFirstItem( Q_HEADER_PTR );
+static VOID_PTR VLM_SrchGetPrevItem( SRCH_OBJECT_PTR );
+static VOID_PTR VLM_SrchGetNextItem( SRCH_OBJECT_PTR );
+static VOID_PTR VLM_SrchGetObjects( SRCH_OBJECT_PTR );
+static BOOLEAN VLM_SrchSetObjects( SRCH_OBJECT_PTR, WORD, WORD );
+static VOID_PTR VLM_SrchSetSelect( SRCH_OBJECT_PTR, BYTE );
+
+/*********************
+
+ NAME : VLM_SelectSearch
+
+ DESCRIPTION :
+
+ The user has tagged one or more files in the search window and hit the
+ select or unselect button. This function does the processing for that
+ command.
+
+ RETURNS: nothing.
+
+*****/
+
+
+VOID VLM_SelectSearch(
+BYTE attr ) // I - select or deselect ?
+{
+#ifndef OEM_MSOFT
+ SRCH_OBJECT_PTR srch;
+ WININFO_PTR wininfo;
+
+ wininfo = WM_GetInfoPtr( gb_search_win );
+
+ // Have the display list manager update our tags for us.
+
+ DLM_UpdateTags( gb_search_win, DLM_FLATLISTBOX );
+
+ srch = VLM_GetFirstSRCH( wininfo->pFlatList );
+
+ while ( srch != NULL ) {
+
+ if ( srch->status & INFO_TAGGED ) {
+
+ VLM_SrchSetSelect( srch, attr );
+ }
+ srch = VLM_GetNextSRCH( srch );
+ }
+#endif
+}
+
+
+/**********************
+
+ NAME : VLM_ClearAllSearchSelections
+
+ DESCRIPTION :
+
+ Clear all the check boxes in the search window.
+
+ RETURNS : nothing
+
+**********************/
+
+
+VOID VLM_ClearAllSearchSelections( )
+{
+#ifndef OEM_MSOFT
+ WININFO_PTR wininfo;
+ SRCH_OBJECT_PTR srch;
+
+ if ( gb_search_win != (HWND)NULL ) {
+
+ wininfo = WM_GetInfoPtr( gb_search_win );
+
+ srch = VLM_GetFirstSRCH( wininfo->pFlatList );
+
+ while ( srch != NULL ) {
+
+ if ( srch->status & (INFO_SELECT|INFO_PARTIAL) ) {
+
+ srch->status &= ~(INFO_SELECT|INFO_PARTIAL);
+
+ DLM_Update( gb_search_win, DLM_FLATLISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)srch, 0 );
+ }
+ srch = VLM_GetNextSRCH( srch );
+ }
+
+ }
+#endif
+}
+
+
+
+/**********************
+
+ NAME : VLM_CreateSearchWindowSpecs
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+static INT VLM_CreateSearchWindowSpecs( PDS_WMINFO* winspecs )
+{
+#ifndef OEM_MSOFT
+ Q_HEADER_PTR srch_list;
+ WININFO_PTR wininfo;
+ DLM_INIT dlm;
+
+ srch_list = (Q_HEADER_PTR)malloc( sizeof(Q_HEADER) );
+
+ if ( srch_list == NULL ) {
+ return( FAILURE );
+ }
+
+ InitQueue( srch_list );
+
+ wininfo = ( WININFO_PTR )malloc( sizeof( WININFO ) );
+ *winspecs = wininfo;
+
+ if ( wininfo == NULL ) {
+ return( FAILURE );
+ }
+
+ /* fill in the wininfo structure. */
+
+ wininfo->wType = WMTYPE_SEARCH;
+ wininfo->hCursor = RSM_CursorLoad( IDRC_HSLIDER );
+ wininfo->hDragCursor = 0;
+ wininfo->hIcon = RSM_IconLoad( IDRI_SEARCH );
+ wininfo->wHelpID = 0;
+ wininfo->wStatusLineID = 0;
+ wininfo->dwRibbonState = 0;
+ wininfo->hRibbon = NULL;
+ wininfo->pFlatList = (Q_HEADER_PTR)srch_list;
+ wininfo->pAppInfo = NULL;
+
+ /* Fill in the display manager stuff. */
+
+ DLM_ListBoxType( &dlm, DLM_FLATLISTBOX );
+ DLM_Mode( &dlm, DLM_SINGLECOLUMN );
+ DLM_Display( &dlm, DLM_SMALL_BITMAPS );
+ DLM_DispHdr( &dlm, srch_list );
+ DLM_TextFont( &dlm, DLM_SYSTEM_FONT );
+ DLM_GetItemCount( &dlm, VLM_SrchGetItemCount );
+ DLM_GetFirstItem( &dlm, VLM_SrchGetFirstItem );
+ DLM_GetNext( &dlm, VLM_SrchGetNextItem );
+ DLM_GetPrev( &dlm, VLM_SrchGetPrevItem );
+ DLM_GetTag( &dlm, VLM_SrchGetTag );
+ DLM_SetTag( &dlm, VLM_SrchSetTag );
+ DLM_GetSelect( &dlm, VLM_SrchGetSelect );
+ DLM_SetSelect( &dlm, VLM_SrchSetSelect );
+ DLM_GetObjects( &dlm, VLM_SrchGetObjects );
+ DLM_SetObjects( &dlm, VLM_SrchSetObjects );
+ DLM_SSetItemFocus( &dlm, NULL );
+ DLM_MaxNumObjects( &dlm, NUM_DISPLAY_OBJECTS );
+
+ DLM_DispListInit( wininfo, &dlm );
+
+#endif
+ return( SUCCESS );
+}
+
+
+/**********************
+
+ NAME : VLM_FillInSrchDetails
+
+ DESCRIPTION :
+
+ Fills in the date, size, and attribute fields.
+
+ RETURNS : nothing.
+
+**********************/
+
+static VOID VLM_FillInSrchDetails(
+CHAR_PTR date_buffer,
+UINT16 date,
+CHAR_PTR time_buffer,
+UINT16 time,
+CHAR_PTR attr_buffer,
+UINT32 attribute )
+{
+#ifndef OEM_MSOFT
+ CHAR_PTR s;
+
+ s = attr_buffer;
+
+ UI_IntToDate( date_buffer, date );
+ UI_IntToTime( time_buffer, time );
+
+ if ( attribute & OBJ_READONLY_BIT ) {
+ *s++ = TEXT('R');
+ }
+ if ( attribute & OBJ_HIDDEN_BIT ) {
+ *s++ = TEXT('H');
+ }
+ if ( attribute & OBJ_SYSTEM_BIT ) {
+ *s++ = TEXT('S');
+ }
+ if ( attribute & OBJ_MODIFIED_BIT ) {
+ *s++ = TEXT('A');
+ }
+
+ *s = TEXT( '\0' );
+#endif
+}
+
+
+static SRCH_OBJECT_PTR VLM_CreateSrch(
+INT name_size,
+INT path_size,
+INT date_size,
+INT time_size,
+INT attr_size,
+INT tape_size,
+INT bset_size,
+INT set_size )
+{
+ SRCH_OBJECT_PTR srch;
+#ifndef OEM_MSOFT
+
+ // All these sizes are in bytes.
+
+ srch = ( SRCH_OBJECT_PTR )malloc( sizeof( SRCH_OBJECT) +
+ name_size +
+ path_size +
+ date_size +
+ time_size +
+ attr_size +
+ tape_size +
+ bset_size +
+ set_size
+ );
+
+ if ( srch != NULL ) {
+
+ srch->name_str = (CHAR_PTR)((UINT8_PTR)srch + sizeof( SRCH_OBJECT ));
+ srch->path_str = (CHAR_PTR)((UINT8_PTR)srch->name_str + name_size);
+ srch->date_str = (CHAR_PTR)((UINT8_PTR)srch->path_str + path_size);
+ srch->time_str = (CHAR_PTR)((UINT8_PTR)srch->date_str + date_size);
+ srch->attr_str = (CHAR_PTR)((UINT8_PTR)srch->time_str + time_size);
+ srch->tape_str = (CHAR_PTR)((UINT8_PTR)srch->attr_str + attr_size);
+ srch->bset_str = (CHAR_PTR)((UINT8_PTR)srch->tape_str + tape_size);
+ srch->set_str = (CHAR_PTR)((UINT8_PTR)srch->bset_str + bset_size);
+
+ srch->q_elem.q_ptr = srch;
+
+ }
+
+#endif
+ return( srch );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+VOID VLM_SetMaxSizes( Q_HEADER_PTR srch_list )
+{
+#ifndef OEM_MSOFT
+ SRCH_OBJECT_PTR srch;
+ UINT64 kilo;
+ UINT64 mega;
+ UINT64 giga;
+
+ // I know there must be an easier way !
+
+ kilo = U64_Init( 999L , 0L );
+ mega = U64_Init( 999999L, 0L );
+ giga = U64_Init( 999999999L, 0L );
+
+ mw_max_name_str = 0;
+ mw_max_path_str = 0;
+ mw_max_date_str = 0;
+ mw_max_time_str = 0;
+ mw_max_attr_str = 0;
+ mw_max_tape_str = 0;
+ mw_max_bset_str = 0;
+ mw_max_size_str = 3;
+ mw_max_set_str = 0;
+
+ srch = VLM_GetFirstSRCH( srch_list );
+
+ while ( srch != NULL ) {
+
+ if ( U64_GE( srch->size, kilo ) && ( mw_max_size_str < 6 ) ) {
+ mw_max_size_str = 6;
+ }
+
+ if ( U64_GE( srch->size, mega ) && ( mw_max_size_str < 9 ) ) {
+ mw_max_size_str = 9;
+ }
+
+ if ( U64_GE( srch->size, giga ) && ( mw_max_size_str < 12 ) ) {
+ mw_max_size_str = 12;
+ }
+
+ if ( strlen( srch->name_str ) > mw_max_name_str ) {
+ mw_max_name_str = (UINT8)strlen( srch->name_str );
+ }
+
+ if ( strlen( srch->path_str ) > mw_max_path_str ) {
+ mw_max_path_str = (UINT8)strlen( srch->path_str );
+ }
+
+ if ( strlen( srch->date_str ) > mw_max_date_str ) {
+ mw_max_date_str = (UINT8)strlen( srch->date_str );
+ }
+
+ if ( strlen( srch->time_str ) > mw_max_time_str ) {
+ mw_max_time_str = (UINT8)strlen( srch->time_str );
+ }
+
+ if ( strlen( srch->attr_str ) > mw_max_attr_str ) {
+ mw_max_attr_str = (UINT8)strlen( srch->attr_str );
+ }
+
+ if ( strlen( srch->tape_str ) > mw_max_tape_str ) {
+ mw_max_tape_str = (UINT8)strlen( srch->tape_str );
+ }
+
+ if ( strlen( srch->bset_str ) > mw_max_bset_str ) {
+ mw_max_bset_str = (UINT8)strlen( srch->bset_str );
+ }
+
+ if ( strlen( srch->set_str ) > mw_max_set_str ) {
+ mw_max_set_str = (UINT8)strlen( srch->set_str );
+ }
+
+ srch = VLM_GetNextSRCH( srch );
+ }
+
+#endif
+}
+
+
+/**********************
+
+ NAME : VLM_FindSrchItem
+
+ DESCRIPTION :
+
+ See if this item is already in our list. On sets that cross tape the
+ catalogs can return the same file twice.
+
+ RETURNS :
+
+**********************/
+
+static INT VLM_FindSrchItem(
+Q_HEADER_PTR srch_list,
+QTC_QUERY_PTR query )
+{
+#ifndef OEM_MSOFT
+ SRCH_OBJECT_PTR srch;
+ CHAR *buffer = NULL;
+ INT buffer_size = 0;
+ INT i;
+ INT BytesNeeded;
+
+ srch = VLM_GetFirstSRCH( srch_list );
+
+ // Look through all known search results.
+
+ while ( srch ) {
+
+ // Look for same tape/set first.
+
+ if ( ( QTC_GetTapeFID( query ) == srch->tape_fid ) &&
+ ( QTC_GetBsetNum( query ) == srch->bset_num ) ) {
+
+ // Then look for same file name.
+
+ if ( ! stricmp( srch->name_str, QTC_GetItemName( query ) ) ) {
+
+ // Now check the path.
+
+ BytesNeeded = QTC_GetPathLength( query ) + 256;
+
+ if ( buffer_size < BytesNeeded ) {
+ free( buffer );
+ buffer = malloc( BytesNeeded );
+ buffer_size = BytesNeeded;
+ if ( buffer == NULL ) {
+ return( FAILURE );
+ }
+ }
+
+ strcpy( buffer, TEXT("\\") );
+
+ if ( QTC_GetPathLength( query ) != sizeof(CHAR) ) {
+
+ memcpy( &buffer[1],
+ QTC_GetPath( query ),
+ QTC_GetPathLength( query ) );
+
+ for ( i = 0; i < QTC_GetPathLength( query )/(INT)sizeof(CHAR); i++ ) {
+
+ if ( buffer[i] == TEXT( '\0' ) ) {
+ buffer[i] = TEXT('\\');
+ }
+ }
+ }
+
+ if ( ! stricmp( srch->path_str, buffer ) ) {
+ free( buffer );
+ return( SUCCESS );
+ }
+ }
+
+ }
+
+ srch = VLM_GetNextSRCH( srch );
+ }
+
+ free( buffer );
+
+#endif
+
+ return( FAILURE );
+}
+
+/**********************
+
+ NAME : VLM_StartSearch
+
+ DESCRIPTION :
+
+ Start a search operation. If a filename has been passed in then default
+ to searching for that file, and don't prompt the user.
+
+ RETURNS : nothing
+
+**********************/
+
+VOID VLM_StartSearch( CHAR_PTR filename )
+{
+#ifndef OEM_MSOFT
+ QTC_QUERY_PTR query;
+ Q_HEADER_PTR srch_list;
+ Q_HEADER_PTR tape_list;
+ Q_ELEM_PTR curr_elem = NULL;
+ SRCH_OBJECT_PTR srch;
+ TAPE_OBJECT_PTR tape;
+ BSET_OBJECT_PTR bset;
+ INT path_length; // num characters in path buffer.
+ INT path_size = 0; // bytes allocated in path buffer.
+ INT i;
+ INT result;
+ INT bsets_searched = 0;
+ CHAR_PTR path = NULL;
+ CHAR_PTR s;
+ WININFO_PTR wininfo;
+ DS_SEARCH_PTR pds = NULL;
+ CDS_PTR pPermCDS = CDS_GetPerm () ;
+ CHAR set_number_str[ 50 ];
+ CHAR buff[ VLM_BUFFER_SIZE ]; // ok, with deep pathes.
+ CHAR volume[ VLM_BUFFER_SIZE ]; // ok, with deep pathes.
+ CHAR text[ MAX_UI_RESOURCE_SIZE ];
+ CHAR title[ MAX_UI_RESOURCE_SIZE ];
+ CHAR DirectSrchMethod = FALSE;
+ BOOLEAN stat;
+
+ wininfo = WM_GetInfoPtr( gb_tapes_win );
+ tape_list = wininfo->pTreeList;
+
+ tape = VLM_GetFirstTAPE( );
+
+ if ( tape == NULL ) {
+
+ // Tell the user there are no tapes
+
+ RSM_StringCopy( IDS_VLMSRCHOOPS, title, MAX_UI_RESOURCE_LEN );
+ RSM_StringCopy( IDS_VLMSRCHNOCATALOGS, text, MAX_UI_RESOURCE_LEN );
+ WM_MsgBox( title, text, WMMB_OK, WMMB_ICONINFORMATION );
+ return;
+ }
+
+ if ( filename == NULL ) {
+
+ // Ask the user what to search for and where to search for it.
+
+ pds = DM_GetSearchItem();
+
+ if ( pds == NULL ) {
+
+ return; // User hit cancel
+ }
+ }
+
+ // let's fake out the user entered search criteria via dialog box
+
+ else {
+
+ DirectSrchMethod = TRUE;
+
+ pds = (DS_SEARCH_PTR) calloc ( 1, sizeof ( DS_SEARCH ) );
+
+ pds->MaxSrchResults = CDS_GetSearchLimit ( pPermCDS );
+
+ pds->SrchPasswProtTapes = CDS_GetSearchPwdTapes ( pPermCDS );
+ }
+
+ query = QTC_InitQuery( );
+
+ if ( query == NULL ) {
+
+ // Couldn't get a catalog handle
+
+ return;
+ }
+
+ WM_ShowWaitCursor( TRUE );
+
+ if ( gb_search_win == (HWND)NULL ) {
+
+ // Create search window structures and display manager items
+
+ if ( VLM_CreateSearchWindowSpecs( & wininfo ) ) {
+
+ // Create failed.
+
+ return;
+ }
+
+ srch_list = wininfo->pFlatList;
+ }
+
+ else {
+
+ // empty previous list
+
+ wininfo = WM_GetInfoPtr( gb_search_win );
+ srch_list = wininfo->pFlatList;
+
+ curr_elem = DeQueueElem( srch_list );
+
+ while ( curr_elem != NULL ) {
+ free( curr_elem->q_ptr );
+ curr_elem = DeQueueElem( srch_list );
+ }
+
+ DLM_Update( gb_search_win, DLM_FLATLISTBOX,
+ WM_DLMUPDATELIST,
+ (LMHANDLE)NULL, 0 );
+ }
+
+ // Also need to parse out drive\volume name and sanity check
+
+ if ( filename == NULL ) {
+
+ QTC_SetSubdirs( query, CDS_GetSearchSubdirs ( pPermCDS ) );
+
+ s = pds->Path;
+ while ( *s == TEXT(' ') ) s++;
+
+ if ( ! *s ) {
+ strcpy( pds->Path, TEXT("\\") );
+ s = pds->Path;
+ }
+
+ volume[0] = TEXT( '\0' );
+
+ if ( strchr( s, TEXT(':') ) ) {
+ i = 0;
+ while ( *s != TEXT(':') ) {
+ volume[i] = *s++;
+ i++;
+ }
+ volume[i++] = *s++; // copy TEXT(':')
+ volume[i] = TEXT( '\0' );
+ }
+
+ if ( *s == TEXT('\\') ) {
+ s++;
+ }
+
+ path_size = strsize( s ) + 256;
+ path = malloc( path_size );
+
+ if ( path == NULL ) {
+ if ( gb_search_win ) {
+ WM_Destroy( gb_search_win );
+ gb_search_win = (HWND)NULL;
+ }
+ WM_ShowWaitCursor( FALSE );
+ return;
+ }
+
+ strcpy( path, s );
+
+ path_length = strlen( path ) + 1;
+
+ for ( i = 0; i < path_length; i++ ) {
+ if ( path[i] == TEXT('\\') ) {
+ path[i] = TEXT( '\0' );
+ }
+ }
+
+ filename = pds->File;
+ while ( *filename == TEXT(' ') ) {
+ filename++;
+ }
+
+ if ( ! strlen( filename ) ) {
+
+ // Tell user invalid filename was entered
+
+ RSM_StringCopy ( IDS_VLMSRCHOOPS, title, MAX_UI_RESOURCE_LEN );
+ RSM_StringCopy ( IDS_VLMSRCHBADFILENAME, text, MAX_UI_RESOURCE_LEN );
+
+ WM_MsgBox( title, text, WMMB_OK, WMMB_ICONINFORMATION );
+
+ QTC_CloseQuery( query );
+
+ if ( gb_search_win ) {
+ WM_Destroy( gb_search_win );
+ gb_search_win = (HWND)NULL;
+ }
+ WM_ShowWaitCursor( FALSE );
+ free( path );
+ return;
+ }
+ }
+ else {
+
+ QTC_SetSubdirs( query, FALSE );
+
+ volume[0] = TEXT( '\0' );
+
+ s = filename;
+ while ( *s ) s++;
+ while ( *s != TEXT('\\') ) s--;
+ *s = TEXT( '\0' );
+
+ path_size = strsize( filename ) + 256;
+ path = malloc( path_size );
+
+ if ( path == NULL ) {
+
+ QTC_CloseQuery( query );
+
+ if ( gb_search_win ) {
+ WM_Destroy( gb_search_win );
+ gb_search_win = (HWND)NULL;
+ }
+ WM_ShowWaitCursor( FALSE );
+ return;
+ }
+
+ if ( strlen( filename ) == 0 ) {
+
+ // "\config.sys"
+
+ filename++;
+ path[0] = TEXT( '\0' );
+ path_length = 1;
+ }
+ else {
+
+ // "\dos\format.exe"
+
+ strcpy( path, &filename[1] );
+ path_length = strlen( path ) + 1;
+
+ for ( i = 0; i < path_length; i++ ) {
+ if ( path[i] == TEXT('\\') ) {
+ path[ i ] = TEXT( '\0' );
+ }
+ }
+
+ s++;
+ filename = s;
+ }
+ }
+
+ // Set up the catalog search criteria
+
+ QTC_SetSearchPath( query, path, path_length * sizeof(CHAR) );
+ QTC_SetSearchName( query, filename ); // TEXT("*.C")
+ QTC_SetPreDate( query, 0 );
+ QTC_SetPostDate( query, 0 );
+ QTC_SetTapeSeq( query, -1 );
+
+ free( path );
+
+ // Find the starting tape/bset to search.
+
+ tape = VLM_GetFirstTAPE( );
+
+ do {
+
+ if ( ( DirectSrchMethod ) || ( tape == NULL ) ) {
+ break;
+ }
+
+ if ( ( pds->Tape == tape->tape_fid ) || ( pds->Tape == -1 ) ) {
+ break;
+ }
+
+ tape = VLM_GetNextTAPE( tape );
+
+ } while ( TRUE );
+
+ // Now loop until we have nothing left to search.
+
+ while ( tape != NULL ) {
+
+ QTC_SetTapeFID( query, tape->tape_fid );
+
+ bset = VLM_GetFirstBSET( &tape->bset_list );
+
+ while ( bset != NULL ) {
+
+ // Look for bset from correct path/volume !!!
+ // If this bset is not from the correct volume skip it.
+
+ if ( strlen( volume ) ) {
+
+ if ( strnicmp( volume, bset->volume_name, strlen( volume ) ) ) {
+ bset = VLM_GetNextBSET( bset );
+ continue;
+ }
+ }
+
+ if ( ( bset != NULL ) && ( bset->password_size ) ) {
+
+ if ( pds->SrchPasswProtTapes ) {
+
+ if ( PSWD_CheckForPassword( bset->tape_fid, bset->bset_num ) ) {
+
+ // skip all subsequent password protected backup sets
+ pds->SrchPasswProtTapes = FALSE;
+
+ // password failure
+ bset = VLM_GetNextBSET( bset );
+ continue;
+ }
+ }
+
+ else {
+ bset = VLM_GetNextBSET( bset );
+ continue;
+ }
+ }
+
+ if ( ( bset != NULL ) && ( QueueCount( srch_list ) < pds->MaxSrchResults ) ) {
+
+ bsets_searched++;
+
+ QTC_SetBsetNum( query, bset->bset_num );
+
+ // Tell status line what we are searching.
+
+
+ RSM_StringCopy ( IDS_VLMSRCHINGWHAT, text, MAX_UI_RESOURCE_LEN );
+
+ sprintf( buff, text, tape->name, bset->bset_num );
+
+ STM_DrawText( buff );
+
+ RSM_StringCopy ( IDS_VLMSETNUMBER, text, MAX_UI_RESOURCE_LEN );
+
+ sprintf( set_number_str, text, bset->bset_num );
+
+ result = QTC_SearchFirstItem( query );
+
+ while ( ! result && ( QueueCount( srch_list ) < pds->MaxSrchResults ) ) {
+
+ if ( VLM_FindSrchItem( srch_list,
+ query ) != SUCCESS ) {
+
+ VLM_FillInSrchDetails( buff, QTC_GetItemDate( query ),
+ &buff[20], QTC_GetItemTime( query ),
+ &buff[40], QTC_GetItemAttrib( query ) );
+
+ srch = VLM_CreateSrch( (strlen( QTC_GetItemName( query ) ) + 1) * sizeof(CHAR),
+ QTC_GetPathLength( query ) + 1 * sizeof(CHAR),
+ (strlen( buff ) + 1) * sizeof(CHAR),
+ (strlen( &buff[20] ) + 1) * sizeof(CHAR),
+ (strlen( &buff[40] ) + 1) * sizeof(CHAR),
+ (strlen( tape->name ) + 1) * sizeof(CHAR),
+ (strlen( bset->name ) + 1) * sizeof(CHAR),
+ (strlen( set_number_str ) + 1) * sizeof(CHAR) );
+
+ if ( srch == NULL ) {
+ break;
+ }
+
+ srch->attrib = QTC_GetItemAttrib( query );
+ srch->status = INFO_DISPLAY | INFO_TAPE;
+ if ( QTC_GetItemStatus( query ) & QTC_CORRUPT ) {
+ srch->status |= INFO_CORRUPT;
+ }
+ srch->size = QTC_GetItemSize( query );
+ srch->XtraBytes = wininfo;
+ srch->tape_fid = QTC_GetTapeFID( query );
+ srch->bset_num = (INT16)QTC_GetBsetNum( query );
+
+ U64_Litoa( srch->size, srch->size_str, (INT16) 10, &stat );
+
+ strcpy( srch->date_str, buff );
+ strcpy( srch->time_str, &buff[20] );
+ strcpy( srch->attr_str, &buff[40] );
+ strcpy( srch->tape_str, tape->name );
+ strcpy( srch->bset_str, bset->name );
+ strcpy( srch->set_str, set_number_str );
+
+ strcpy( srch->name_str, QTC_GetItemName( query ) );
+
+ s = srch->name_str;
+ while ( *s ) {
+ *s = (CHAR)toupper( *s );
+ s++;
+ }
+
+ strcpy( srch->path_str, TEXT("\\") );
+
+ if ( QTC_GetPathLength( query ) != sizeof(CHAR) ) {
+
+ memcpy( &srch->path_str[1],
+ QTC_GetPath( query ),
+ QTC_GetPathLength( query ) );
+
+ for ( i = 0; i < QTC_GetPathLength( query )/(INT)sizeof(CHAR); i++ ) {
+
+ if ( srch->path_str[i] == TEXT( '\0' ) ) {
+ srch->path_str[i] = TEXT('\\');
+ }
+ srch->path_str[i] = (CHAR)toupper( srch->path_str[i] );
+ }
+ }
+
+ // Convert to the big date time structure
+ // from the compressed DOS structure the catalogs store
+
+ srch->mod_date = QTC_GetItemDate( query );
+ srch->mod_time = QTC_GetItemTime( query );
+
+ // See if we can set any special flags, date and time.
+
+ s = srch->name_str;
+ while ( *s && *s != TEXT('.') ) s++;
+ if ( ! stricmp( s, TEXT(".EXE") ) ||
+ ! stricmp( s, TEXT(".COM") ) ||
+ ! stricmp( s, TEXT(".BAT") ) ||
+ ! stricmp( s, TEXT(".CMD") ) ||
+ ! stricmp( s, TEXT(".PIF") ) ) {
+ srch->status |= INFO_EXEFILE;
+ }
+
+ // Add this new item to our list.
+
+ if ( curr_elem == NULL ) {
+ EnQueueElem( srch_list, &(srch->q_elem), FALSE );
+ }
+ else {
+ InsertElem( srch_list, curr_elem, &(srch->q_elem), AFTER );
+ }
+
+ curr_elem = &(srch->q_elem);
+
+ }
+
+ result = QTC_SearchNextItem( query );
+ }
+
+ }
+
+ bset = VLM_GetNextBSET( bset );
+ }
+
+ // There are multiple tapes for each tape family
+ // See if there are anymore in this family to search
+
+ do {
+
+ tape = VLM_GetNextTAPE( tape );
+
+ if ( ( DirectSrchMethod ) || ( tape == NULL ) || ( pds == NULL ) ) {
+ break;
+ }
+
+ } while ( (tape->tape_fid != pds->Tape) && (pds->Tape != -1 ) );
+
+ }
+
+ // Searching is done, let's see what we got.
+
+ STM_SetIdleText( IDS_READY );
+
+ if ( QueueCount( srch_list ) == pds->MaxSrchResults ) {
+
+ // Message box to inform user that search
+ // generated too many solutions to finish.
+
+ RSM_StringCopy( IDS_VLMSRCHOOPS, title, MAX_UI_RESOURCE_LEN );
+ RSM_StringCopy( IDS_VLMSRCHTOOMANY, text, MAX_UI_RESOURCE_LEN );
+ WM_MsgBox( title, text, WMMB_OK, WMMB_ICONINFORMATION );
+ }
+
+ QTC_CloseQuery( query );
+
+ if ( pds != NULL ) {
+ free( pds );
+ }
+
+ if ( QueueCount( srch_list ) ) {
+
+ // Create the window, if necessary
+
+ if ( gb_search_win == (HWND)NULL ) {
+
+ RSM_StringCopy ( IDS_VLMSEARCHTITLE, title, MAX_UI_RESOURCE_LEN );
+
+ gb_search_win = WM_Create( WM_MDISECONDARY | WM_FLATLISTSC ,
+ title,
+ NULL,
+ WM_DEFAULT,
+ WM_DEFAULT,
+ WM_DEFAULT,
+ WM_DEFAULT,
+ wininfo );
+
+ if ( gb_search_win == (HWND)NULL ) {
+ WM_ShowWaitCursor( FALSE );
+ return;
+ }
+ }
+
+ VLM_SetMaxSizes( srch_list );
+
+ VLM_SetSelectionStatus( srch_list, (UINT32)-1L, -1 );
+
+ /* Start up the Display Manager. */
+ DLM_DispListProc( wininfo->hWndFlatList, 0, NULL );
+
+ DLM_SetAnchor ( WMDS_GetWinFlatList( wininfo ),
+ 0,
+ (LMHANDLE) VLM_GetFirstSRCH( srch_list ) );
+
+ WM_DocActivate( gb_search_win );
+ }
+ else {
+
+ if ( bsets_searched != 0 ) {
+
+ // MessageBox to tell user no matches were found.
+
+ RSM_StringCopy( IDS_VLMSRCHOOPS, title, MAX_UI_RESOURCE_LEN );
+ RSM_StringCopy( IDS_VLMSRCHNOFILESFOUND, text, MAX_UI_RESOURCE_LEN );
+ }
+ else {
+
+ // MessageBox to tell user no bsets were searched.
+
+ RSM_StringCopy( IDS_VLMSRCHOOPS, title, MAX_UI_RESOURCE_LEN );
+ RSM_StringCopy( IDS_VLMSRCHNOMATCHINGSETS, text, MAX_UI_RESOURCE_LEN );
+ }
+
+ WM_MsgBox( title, text, WMMB_OK, WMMB_ICONINFORMATION );
+
+ if ( gb_search_win ) {
+ WM_Destroy( gb_search_win );
+ }
+
+ }
+
+ WM_ShowWaitCursor( FALSE );
+
+#endif
+}
+
+
+/**********************
+
+ NAME : VLM_UpdateSearchSelections
+
+ DESCRIPTION :
+
+ The user has selected or deselected, some files on tape somewhere,
+ somehow. The exact tape and backup set that chenged are passed in
+ and we need to see if any of our results were affected.
+
+ RETURNS : nothing
+
+**********************/
+
+VOID VLM_UpdateSearchSelections( UINT32 tape_fid, INT16 bset_num )
+{
+#ifndef OEM_MSOFT
+ WININFO_PTR wininfo;
+ BSD_PTR bsd_ptr;
+ FSE_PTR fse;
+ SRCH_OBJECT_PTR srch;
+ CHAR_PTR path;
+ CHAR_PTR buff = NULL;
+ INT16 result;
+ INT16 i;
+ INT16 path_length;
+ UINT16 status;
+ INT BytesNeeded;
+ INT buff_size = 0;
+ DATE_TIME mod_date;
+
+ if ( gb_search_win == (HWND)NULL ) {
+
+ // There isn't a search window.
+
+ return;
+ }
+
+ wininfo = WM_GetInfoPtr( gb_search_win );
+
+ if ( wininfo != NULL ) {
+
+ srch = VLM_GetFirstSRCH( wininfo->pFlatList );
+
+ while ( srch ) {
+
+ if ( ( ( tape_fid == srch->tape_fid ) || ( tape_fid == -1 ) ) &&
+ ( ( bset_num == srch->bset_num ) || ( bset_num == -1 ) ) ) {
+
+ bsd_ptr = BSD_FindByTapeID( tape_bsd_list,
+ srch->tape_fid,
+ srch->bset_num );
+
+ if ( bsd_ptr != NULL ) {
+
+ BytesNeeded = strsize( srch->path_str ) + 256;
+
+ if ( buff_size < BytesNeeded ) {
+ free( buff );
+ buff = malloc( BytesNeeded );
+ buff_size = BytesNeeded;
+
+ if ( buff == NULL ) {
+ return;
+ }
+ }
+
+ strcpy( buff, srch->path_str );
+
+ // set path
+ path = buff;
+ if ( *path == TEXT('\\') ) path++;
+
+ // and path_length
+ path_length = (INT16) (strlen( path ) + 1);
+
+ for ( i = 0; i < path_length; i++ ) {
+ if ( path[i] == TEXT('\\') ) path[ i ] = TEXT( '\0' );
+ }
+
+ mod_date.date_valid = FALSE;
+
+ result = BSD_MatchPathAndFile( bsd_ptr, &fse, srch->name_str,
+ path,
+ (INT16)(path_length * sizeof(CHAR)),
+ srch->attrib,
+ &mod_date,
+ NULL, NULL, FALSE, TRUE );
+
+ status = 0;
+
+ if ( result == BSD_PROCESS_OBJECT ) {
+ status = INFO_SELECT;
+ }
+
+ if ( ( srch->status & (UINT16)INFO_SELECT ) != status ) {
+
+ srch->status &= ~(INFO_SELECT|INFO_PARTIAL);
+ srch->status |= status;
+
+ DLM_Update( gb_search_win,
+ DLM_FLATLISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)srch, 0 );
+ }
+ }
+ }
+ srch = VLM_GetNextSRCH( srch );
+ }
+
+ }
+#endif
+}
+
+
+/**********************
+
+ NAME : VLM_SearchRemoveSet
+
+ DESCRIPTION :
+
+ Removes all the items in the search window that were from a certain
+ backup set. Usually because that set went away ...
+
+ RETURNS : Number of items removed.
+
+**********************/
+
+INT VLM_SearchRemoveSet( UINT32 tape_fid, INT16 bset_num )
+{
+ INT16 count = 0;
+
+#ifndef OEM_MSOFT
+
+ SRCH_OBJECT_PTR srch;
+ WININFO_PTR wininfo;
+
+ if ( gb_search_win == (HWND)NULL ) {
+ return( 0 );
+ }
+
+ wininfo = WM_GetInfoPtr( gb_search_win );
+
+ if ( wininfo != NULL ) {
+
+ srch = VLM_GetFirstSRCH( wininfo->pFlatList );
+
+ }
+
+ while ( srch ) {
+
+ if ( ( srch->tape_fid == tape_fid ) &&
+ ( ( srch->bset_num == bset_num ) || ( bset_num == -1 ) ) ) {
+
+ RemoveQueueElem( wininfo->pFlatList, &(srch->q_elem) );
+ free( srch );
+ count++;
+ srch = VLM_GetFirstSRCH( wininfo->pFlatList );
+ }
+ else {
+ srch = VLM_GetNextSRCH( srch );
+ }
+ }
+
+ if ( count ) {
+
+ DLM_Update( gb_search_win,
+ DLM_FLATLISTBOX,
+ WM_DLMUPDATELIST,
+ (LMHANDLE)NULL, 0 );
+
+ }
+
+ if ( ! QueueCount( wininfo->pFlatList ) ) {
+ if ( gb_search_win ) {
+ WM_Destroy( gb_search_win );
+ }
+ }
+#endif
+ return( count );
+}
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static VOID VLM_SetSelectionStatus( Q_HEADER_PTR srch_list,
+ UINT32 tape_fid,
+ INT16 bset_num )
+{
+#ifndef OEM_MSOFT
+ BSD_PTR bsd_ptr;
+ FSE_PTR fse;
+ SRCH_OBJECT_PTR srch;
+ CHAR_PTR path;
+ CHAR_PTR buff = NULL;
+ INT BytesNeeded;
+ INT buff_size = 0;
+ INT16 result;
+ INT16 i;
+ INT16 path_length;
+ DATE_TIME mod_date;
+
+
+ srch = VLM_GetFirstSRCH( srch_list );
+
+ while ( srch ) {
+
+ if ( ( ( tape_fid == srch->tape_fid ) &&
+ ( bset_num == srch->bset_num ) ) ||
+ ( bset_num == -1 ) ) {
+
+ srch->status &= ~(INFO_SELECT|INFO_PARTIAL);
+
+ bsd_ptr = BSD_FindByTapeID( tape_bsd_list,
+ srch->tape_fid,
+ srch->bset_num );
+
+ if ( bsd_ptr != NULL ) {
+
+ BytesNeeded = strsize( srch->path_str ) + 256;
+ if ( buff_size < BytesNeeded ) {
+ buff_size = BytesNeeded;
+ free( buff );
+ buff = malloc( BytesNeeded );
+ if ( buff == NULL ) {
+ return;
+ }
+ }
+
+ strcpy( buff, srch->path_str );
+
+ // set path
+ path = buff;
+ if ( *path == TEXT('\\') ) path++;
+
+ // and path_length
+ path_length = (INT16)(strlen( path ) + 1);
+
+ for ( i = 0; i < path_length; i++ ) {
+ if ( path[i] == TEXT('\\') ) path[ i ] = TEXT( '\0' );
+ }
+
+ mod_date.date_valid = FALSE;
+
+ result = BSD_MatchPathAndFile( bsd_ptr, &fse, srch->name_str,
+ path,
+ (INT16)(path_length * sizeof(CHAR)),
+ srch->attrib,
+ &mod_date, NULL, NULL, FALSE, TRUE );
+
+ if ( result == BSD_PROCESS_OBJECT ) {
+ srch->status |= INFO_SELECT;
+ }
+
+ }
+ }
+ srch = VLM_GetNextSRCH( srch );
+ }
+
+ free( buff );
+#endif
+}
+
+
+
+/***************************************************
+
+ Name: VLM_GetFirstSRCH
+
+ Description:
+
+ Get the first drive element off a queue of known drives.
+
+*****************************************************/
+
+
+static SRCH_OBJECT_PTR VLM_GetFirstSRCH(
+Q_HEADER_PTR qhdr) // I - queue header to work from
+{
+ Q_ELEM_PTR q_elem;
+
+ if ( qhdr != NULL ) {
+
+ q_elem = QueueHead( qhdr );
+
+ if ( q_elem != NULL ) {
+ return ( SRCH_OBJECT_PTR )( q_elem->q_ptr );
+ }
+ }
+
+ return( NULL );
+}
+
+/***************************************************
+
+ Name: VLM_GetNextSRCH
+
+ Description:
+
+ Get the next drive element off a queue of known drives.
+
+*****************************************************/
+
+static SRCH_OBJECT_PTR VLM_GetNextSRCH(
+SRCH_OBJECT_PTR srch ) // I - current vlm
+{
+ Q_ELEM_PTR q_elem;
+
+ q_elem = QueueNext( &(srch->q_elem) );
+
+ if ( q_elem != NULL ) {
+ return (SRCH_OBJECT_PTR )( q_elem->q_ptr );
+ }
+ else {
+ return( NULL );
+ }
+}
+
+/***************************************************
+
+ Name: VLM_GetFirstSRCH
+
+ Description:
+
+ Get the previous drive element off a queue of known drives.
+
+*****************************************************/
+
+static SRCH_OBJECT_PTR VLM_GetPrevSRCH(
+SRCH_OBJECT_PTR srch ) // I - current vlm
+{
+ Q_ELEM_PTR q_elem;
+
+ q_elem = QueuePrev( &(srch->q_elem) );
+
+ if ( q_elem != NULL ) {
+ return( SRCH_OBJECT_PTR )( q_elem->q_ptr );
+ }
+ else {
+ return( NULL );
+ }
+}
+
+
+
+
+
+/***************************************************
+
+ Name: VLM_SrchSetSelect
+
+ Description:
+
+ The callback function for the display manager to tell me that the
+ selection status on a disk has changed.
+
+*****************************************************/
+
+static VOID_PTR VLM_SrchSetSelect(
+SRCH_OBJECT_PTR srch, // I - srch to change
+BYTE attr ) // I - what to change it to
+{
+#ifndef OEM_MSOFT
+ CHAR_PTR buff;
+ CHAR_PTR path;
+ INT16 path_len;
+ FSE_PTR fse_ptr;
+ BSD_PTR bsd_ptr;
+ INT16 error;
+ INT16 i;
+ UINT16 status;
+ HWND win;
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ BE_CFG_PTR bec_config;
+ DATE_TIME sort_date;
+ BSET_OBJECT_PTR bset;
+
+ // change the status
+
+ if ( attr ) {
+ status = INFO_SELECT;
+ }
+ else {
+ status = 0;
+ }
+
+ // determine path length
+ // insert 0's for \'s
+
+ buff = malloc( strsize( srch->path_str ) );
+ if ( buff == NULL ) {
+ return;
+ }
+
+ strcpy( buff, srch->path_str );
+ path = buff;
+ if ( *path == TEXT('\\') ) {
+ path++;
+ }
+
+ path_len = (INT16)(strlen( path ) + 1);
+
+ for ( i = 0; i < path_len; i++ ) {
+ if ( path[i] == TEXT('\\') ) path[i] = TEXT( '\0' );
+ }
+
+ path_len *= sizeof(CHAR);
+
+ if ( attr ) {
+ error = BSD_CreatFSE( &fse_ptr, INCLUDE, path, path_len,
+ srch->name_str,
+ (INT16) strsize(srch->name_str),
+ USE_WILD_CARD, FALSE );
+ }
+ else {
+ error = BSD_CreatFSE( &fse_ptr, EXCLUDE, path, path_len,
+ srch->name_str,
+ (INT16) strsize(srch->name_str),
+ USE_WILD_CARD, FALSE );
+ }
+
+ free( buff );
+
+ if ( error ) {
+ return NULL;
+ }
+
+ bsd_ptr = BSD_FindByTapeID( tape_bsd_list,
+ srch->tape_fid,
+ srch->bset_num );
+
+ if ( bsd_ptr == NULL ) {
+
+ bec_config = BEC_CloneConfig( CDS_GetPermBEC() );
+ BEC_UnLockConfig( bec_config );
+
+ VLM_GetSortDate( srch->tape_fid, srch->bset_num, &sort_date );
+
+ bset = VLM_FindBset( srch->tape_fid, srch->bset_num );
+
+ BSD_Add( tape_bsd_list, &bsd_ptr, bec_config,
+ NULL, NULL,
+ bset->tape_fid, bset->tape_num, bset->bset_num,
+ NULL, &sort_date );
+
+ }
+
+ if ( bsd_ptr != NULL ) {
+
+ VLM_FillInBSD( bsd_ptr );
+ BSD_AddFSE( bsd_ptr, fse_ptr );
+ }
+
+ if ( (srch->status & (UINT16)INFO_SELECT) == status ) {
+
+ return( NULL );
+ }
+
+ srch->status &= ~(INFO_SELECT|INFO_PARTIAL);
+ srch->status |= status;
+
+ DLM_Update( gb_search_win,
+ DLM_FLATLISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)srch, 0 );
+
+ // Now check to see if any other WMTYPE_TAPETREE windows are open and update
+ // them accordingly.
+
+ win = WM_GetNext( (HWND)NULL );
+
+ while ( win != (HWND)NULL ) {
+
+ wininfo = WM_GetInfoPtr( win );
+
+ if ( wininfo->wType == WMTYPE_TAPETREE ) {
+
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( win );
+
+ if ( ( appinfo->tape_fid == srch->tape_fid ) &&
+ ( appinfo->bset_num == srch->bset_num ) ) {
+
+ VLM_RematchList( win );
+ break;
+ }
+ }
+
+ win = WM_GetNext( (HWND)win );
+ }
+
+ VLM_UpdateTapes( );
+
+#endif
+ return( NULL );
+}
+
+/***************************************************
+
+ Name: VLM_SrchGetSelect
+
+ Description:
+
+ A callback function for the display manager to get the selection
+ status of a disk.
+
+*****************************************************/
+
+static BYTE VLM_SrchGetSelect(
+SRCH_OBJECT_PTR srch ) // I - vlm to get the status of
+{
+ if ( srch->status & INFO_SELECT ) {
+ return( 1 );
+ }
+ else {
+ return( 0 );
+ }
+}
+
+/***************************************************
+
+ Name: VLM_VlmSetTag
+
+ Description:
+
+ A callback function for the display manager to set the tag status
+ of a disk for me.
+
+*****************************************************/
+
+static VOID_PTR VLM_SrchSetTag(
+SRCH_OBJECT_PTR srch, // I - srch to work with
+BYTE attr ) // I - what to set it to
+{
+ if ( attr ) {
+ srch->status |= INFO_TAGGED;
+ }
+ else {
+ srch->status &= ~INFO_TAGGED;
+ }
+ return(NULL);
+}
+
+/***************************************************
+
+ Name: VLM_SrchGetTag
+
+ Description:
+
+ A callback function for the display manager to get the tag status
+ of a disk from me.
+
+*****************************************************/
+
+static BYTE VLM_SrchGetTag(
+SRCH_OBJECT_PTR srch ) // I - srch to work with
+{
+ if ( srch->status & INFO_TAGGED ) {
+ return( 1 );
+ }
+ else {
+ return( 0 );
+ }
+}
+
+/***************************************************
+
+ Name: VLM_SrchGetItemCount
+
+ Description:
+
+ A callback function for the display manager to get the
+ number of displayable drives.
+
+*****************************************************/
+
+static USHORT VLM_SrchGetItemCount(
+Q_HEADER_PTR srch_list ) // I - queue header to get count from
+{
+ return( QueueCount( srch_list ) );
+}
+
+/***************************************************
+
+ Name: VLM_SrchGetFirstItem
+
+ Description:
+
+ A callback function for the display manager to get the first drive
+ to display.
+
+*****************************************************/
+
+static VOID_PTR VLM_SrchGetFirstItem(
+Q_HEADER_PTR srch_list ) // I - queue to get first item from
+{
+ return( VLM_GetFirstSRCH( srch_list ) );
+}
+
+/***************************************************
+
+ Name: VLM_SrchGetPrevItem
+
+ Description:
+
+ A callback function for the display manager to get the previous
+ disk in a list of disks.
+
+*****************************************************/
+
+static VOID_PTR VLM_SrchGetPrevItem(
+SRCH_OBJECT_PTR srch ) // I - current srch
+{
+ return( VLM_GetPrevSRCH( srch ) );
+}
+
+/***************************************************
+
+ Name: VLM_SrchGetNextItem
+
+ Description:
+
+ A callback function for the display manager to get the next
+ disk in a list of disks.
+
+*****************************************************/
+
+static VOID_PTR VLM_SrchGetNextItem(
+SRCH_OBJECT_PTR srch ) // I - current srch
+{
+ return( VLM_GetNextSRCH( srch ) );
+}
+
+/***************************************************
+
+ Name: VLM_SrchGetObjects
+
+ Description:
+
+ A callback function for the display manager to get the object list
+ to display for a given disk.
+
+*****************************************************/
+
+static VOID_PTR VLM_SrchGetObjects(
+SRCH_OBJECT_PTR srch ) // I - current srch
+{
+ BYTE_PTR memblk;
+ CHAR text[ MAX_UI_RESOURCE_SIZE ];
+
+#ifndef OEM_MSOFT
+
+ DLM_ITEM_PTR item;
+ WININFO_PTR wininfo;
+
+
+ wininfo = WM_GetInfoPtr( gb_search_win );
+
+ // get the buffer to fill for this window
+
+ memblk = ( BYTE_PTR )DLM_GetObjectsBuffer( wininfo->hWndFlatList );
+
+ /* Store the number of items in the first two bytes. */
+
+ *memblk = NUM_DISPLAY_OBJECTS;
+
+ /* Set up check box. */
+
+ item = (DLM_ITEM_PTR)( memblk + 6 );
+
+ DLM_ItemcbNum( item ) = 1;
+ DLM_ItembType( item ) = DLM_CHECKBOX;
+ if ( srch->status & INFO_SELECT ) {
+ DLM_ItemwId( item ) = IDRBM_SEL_ALL;
+ if ( srch->status & INFO_PARTIAL ) {
+ DLM_ItemwId( item ) = IDRBM_SEL_PART;
+ }
+ }
+ else {
+ DLM_ItemwId( item ) = IDRBM_SEL_NONE;
+ }
+ DLM_ItembMaxTextLen( item ) = 0;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+
+ /* Set up Bitmap, ie. Floppy, Hard, Network. */
+
+ item++;
+ DLM_ItemcbNum( item ) = 2;
+ DLM_ItembType( item ) = DLM_BITMAP;
+
+ if ( srch->attrib & OBJ_HIDDEN_BIT ) {
+
+ if ( srch->status & INFO_EXEFILE ) {
+ DLM_ItemwId( item ) = IDRBM_HEXEFILE;
+ }
+ else {
+ DLM_ItemwId( item ) = IDRBM_HFILE;
+ }
+ if ( srch->status & INFO_CORRUPT ) {
+ DLM_ItemwId( item ) = IDRBM_HCRPTFILE;
+ }
+ }
+ else {
+ if ( srch->status & INFO_EXEFILE ) {
+ DLM_ItemwId( item ) = IDRBM_EXE;
+ }
+ else {
+ DLM_ItemwId( item ) = IDRBM_FILE;
+ }
+ if ( srch->status & INFO_CORRUPT ) {
+ DLM_ItemwId( item ) = IDRBM_CORRUPTFILE;
+ }
+ }
+ DLM_ItembMaxTextLen( item ) = 0;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+
+ /* Set up the text strings to be displayed. */
+
+ item++;
+ DLM_ItemcbNum( item ) = 3;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = mw_max_name_str;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+ strcpy( ( LPSTR )DLM_ItemqszString( item ), srch->name_str );
+
+ item++;
+ DLM_ItemcbNum( item ) = 4;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItembTextMode( item ) = DLM_RIGHT_JUSTIFY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = mw_max_size_str;
+ DLM_ItembLevel( item ) = 0;
+ strcpy( ( LPSTR )DLM_ItemqszString( item ), srch->size_str );
+
+ item++;
+ DLM_ItemcbNum( item ) = 5;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = mw_max_date_str;
+ DLM_ItembLevel( item ) = 0;
+ sprintf(text, TEXT("%8s"), (CHAR_PTR)srch->date_str);
+ strcpy( ( LPSTR )DLM_ItemqszString( item ), (CHAR_PTR)text );
+
+ item++;
+ DLM_ItemcbNum( item ) = 6;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = mw_max_time_str;
+ DLM_ItembLevel( item ) = 0;
+ sprintf(text, TEXT("%11s"), (CHAR_PTR)srch->time_str);
+ strcpy( ( LPSTR )DLM_ItemqszString( item ), (CHAR_PTR)text );
+
+ item++;
+ DLM_ItemcbNum( item ) = 7;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = mw_max_attr_str;
+ DLM_ItembLevel( item ) = 0;
+ strcpy( ( LPSTR )DLM_ItemqszString( item ), srch->attr_str );
+
+
+ item++;
+ DLM_ItemcbNum( item ) = 8;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = mw_max_path_str;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+ strcpy( ( LPSTR )DLM_ItemqszString( item ), srch->path_str );
+
+ item++;
+ DLM_ItemcbNum( item ) = 9;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = mw_max_set_str;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+ strcpy( ( LPSTR )DLM_ItemqszString( item ), srch->set_str );
+
+ item++;
+ DLM_ItemcbNum( item ) = 10;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = mw_max_tape_str;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+ strcpy( ( LPSTR )DLM_ItemqszString( item ), srch->tape_str );
+
+ item++;
+ DLM_ItemcbNum( item ) = 11;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = mw_max_bset_str;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+ strcpy( ( LPSTR )DLM_ItemqszString( item ), srch->bset_str );
+
+#endif
+ return( memblk );
+}
+
+/***************************************************
+
+ Name: VLM_VlmSetObjects
+
+ Description:
+
+ A callback function for the display manager to tell me that the
+ user tried to do something with this drive.
+
+*****************************************************/
+
+static BOOLEAN VLM_SrchSetObjects(
+SRCH_OBJECT_PTR srch, // I - current srch
+WORD operation, // I - operation the user did
+WORD ObjectNum ) // I - object he did it on
+{
+#ifndef OEM_MSOFT
+
+ CHAR keyb_char;
+ SRCH_OBJECT_PTR temp_srch;
+
+ if ( operation == WM_DLMCHAR ) {
+
+ keyb_char = (CHAR)ObjectNum;
+
+ keyb_char = (CHAR)toupper( keyb_char );
+
+ temp_srch = srch;
+
+ do {
+
+ temp_srch = VLM_GetNextSRCH( temp_srch );
+
+ if ( temp_srch != NULL ) {
+
+ if ( keyb_char == (CHAR)toupper( temp_srch->name_str[0] ) ) {
+
+ DLM_SetAnchor( WMDS_GetWinFlatList( temp_srch->XtraBytes ),
+ 0,
+ (LMHANDLE)temp_srch );
+ return( TRUE );
+ }
+ }
+
+ } while ( temp_srch != NULL );
+
+ temp_srch = VLM_GetFirstSRCH( WMDS_GetFlatList( srch->XtraBytes ) );
+
+ while ( temp_srch != srch && temp_srch != NULL ) {
+
+ if ( keyb_char == (CHAR)toupper( temp_srch->name_str[0] ) ) {
+
+ DLM_SetAnchor( WMDS_GetWinFlatList( temp_srch->XtraBytes ),
+ 0,
+ (LMHANDLE)temp_srch );
+ return( TRUE );
+ }
+
+ temp_srch = VLM_GetNextSRCH( temp_srch );
+ }
+
+ DLM_SetAnchor( WMDS_GetWinFlatList( srch->XtraBytes ),
+ 0,
+ (LMHANDLE)srch );
+
+
+ }
+
+#endif
+ return( FALSE );
+}
+
diff --git a/private/utils/ntbackup/src/vlm_srv.c b/private/utils/ntbackup/src/vlm_srv.c
new file mode 100644
index 000000000..cca0dcb5e
--- /dev/null
+++ b/private/utils/ntbackup/src/vlm_srv.c
@@ -0,0 +1,1897 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: VLM_SRV.C
+
+ Description:
+
+ This file contains most of the code for processing the servers
+ window and list.
+
+ $Log: G:\UI\LOGFILES\VLM_SRV.C_V $
+
+ Rev 1.37.1.0 08 Dec 1993 11:20:34 MikeP
+very deep pathes
+
+ Rev 1.37 27 Jul 1993 15:34:56 MARINA
+enable c++
+
+ Rev 1.36 11 Nov 1992 16:37:00 DAVEV
+UNICODE: remove compile warnings
+
+ Rev 1.35 07 Oct 1992 15:06:00 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.34 04 Oct 1992 19:42:56 DAVEV
+Unicode Awk pass
+
+ Rev 1.33 29 Jul 1992 09:51:48 MIKEP
+ChuckB checked in after NT warnings were fixed.
+
+ Rev 1.32 20 Jul 1992 09:58:50 JOHNWT
+gas gauge display work
+
+ Rev 1.31 08 Jul 1992 15:33:54 STEVEN
+Unicode BE changes
+
+ Rev 1.30 14 May 1992 18:05:36 MIKEP
+nt pass 2
+
+ Rev 1.29 13 May 1992 11:42:18 MIKEP
+NT changes
+
+ Rev 1.28 06 May 1992 14:41:22 MIKEP
+unicode pass two
+
+ Rev 1.27 04 May 1992 13:39:44 MIKEP
+unicode pass 1
+
+ Rev 1.26 24 Mar 1992 14:45:18 DAVEV
+OEM_MSOFT: Removed Servers windows and associated code
+
+
+*****************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+// Local Prototypes
+
+static VOID_PTR VLM_SrvSetSelect( VLM_OBJECT_PTR, BYTE );
+static BYTE VLM_SrvGetSelect( VLM_OBJECT_PTR );
+static VOID_PTR VLM_SrvSetTag( VLM_OBJECT_PTR, BYTE );
+static BYTE VLM_SrvGetTag( VLM_OBJECT_PTR );
+static USHORT VLM_SrvGetItemCount( Q_HEADER_PTR );
+static VOID_PTR VLM_SrvGetFirstItem( Q_HEADER_PTR );
+static VOID_PTR VLM_SrvGetPrevItem( VLM_OBJECT_PTR );
+static VOID_PTR VLM_SrvGetNextItem( VLM_OBJECT_PTR );
+static VOID_PTR VLM_SrvGetObjects( VLM_OBJECT_PTR );
+static BOOLEAN VLM_SrvSetObjects( VLM_OBJECT_PTR, WORD, WORD );
+
+static VOID_PTR VLM_VolSetSelect( VLM_OBJECT_PTR, BYTE );
+static BYTE VLM_VolGetSelect( VLM_OBJECT_PTR );
+static VOID_PTR VLM_VolSetTag( VLM_OBJECT_PTR, BYTE );
+static BYTE VLM_VolGetTag( VLM_OBJECT_PTR );
+static USHORT VLM_VolGetItemCount( Q_HEADER_PTR );
+static VOID_PTR VLM_VolGetFirstItem( Q_HEADER_PTR );
+static VOID_PTR VLM_VolGetPrevItem( VLM_OBJECT_PTR );
+static VOID_PTR VLM_VolGetNextItem( VLM_OBJECT_PTR );
+static VOID_PTR VLM_VolGetObjects( VLM_OBJECT_PTR );
+static BOOLEAN VLM_VolSetObjects( VLM_OBJECT_PTR, WORD, WORD );
+static VOID_PTR VLM_DoVolSetSelect( VLM_OBJECT_PTR, BYTE );
+
+static BOOLEAN VLM_MayWeAttachToVolume( GENERIC_DLE_PTR );
+
+
+/**********************
+
+ NAME : VLM_MayWeAttachToVolume
+
+ DESCRIPTION :
+
+ There is one reason that we would not be allowed to attach to a
+ volume:
+
+ 1. This server has a mixture of AFP and NON-AFP volumes and one of
+ the opposite type is already open. This is a NOVELL bug.
+
+ RETURNS : TRUE/FALSE
+
+**********************/
+
+static BOOLEAN VLM_MayWeAttachToVolume( GENERIC_DLE_PTR dle )
+{
+ HWND win;
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ GENERIC_DLE_PTR parent_dle;
+
+
+ if ( ( DLE_GetDeviceType( dle ) != NOVELL_AFP_DRV ) &&
+ ( DLE_GetDeviceType( dle ) != NOVELL_DRV ) ) {
+ return( TRUE );
+ }
+
+ parent_dle = DLE_GetParent( dle );
+
+ if ( parent_dle == NULL ) {
+ return( TRUE );
+ }
+
+ win = WM_GetNext( (HWND)NULL );
+
+ while ( win != (HWND)NULL ) {
+
+ wininfo = WM_GetInfoPtr( win );
+
+ if ( wininfo->wType == WMTYPE_DISKTREE ) {
+
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( win );
+
+ if ( parent_dle == DLE_GetParent( appinfo->dle ) ) {
+
+ if ( DLE_GetDeviceType( appinfo->dle ) !=
+ DLE_GetDeviceType( dle ) ) {
+
+ // NO, NO, NO !
+ // You may not open afp and non-afp volumes on the same
+ // server at the same time, its a novell bug.
+
+ return( FALSE );
+ }
+ }
+ }
+
+ win = WM_GetNext( win );
+ }
+
+ return( TRUE );
+}
+
+
+/**********************
+
+ NAME : VLM_ServersSync
+
+ DESCRIPTION :
+
+ The user has performed a refresh call and it is our job to see to it that
+ any servers no longer on line are removed and any new ones are inserted.
+ Any server with a window open will not go away, because we are attached
+ to it. Also any server with selections made will not go away. All server
+ children dle's need there bsd count incremented to keep them around.
+
+ RETURNS : nothing.
+
+**********************/
+
+VOID VLM_ServersSync( )
+{
+#if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ VLM_OBJECT_PTR vlm;
+ VLM_OBJECT_PTR temp_vlm;
+ VLM_OBJECT_PTR child_vlm;
+ VLM_OBJECT_PTR parent_vlm;
+ GENERIC_DLE_PTR dle;
+ GENERIC_DLE_PTR child_dle;
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ BOOLEAN change_made = FALSE;
+ INT16 vlm_count;
+ FSYS_HAND temp_fsh;
+
+ wininfo = WM_GetInfoPtr( gb_servers_win );
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( gb_servers_win );
+
+ // Look for VLM drives we have that no longer exist.
+
+ vlm = VLM_GetFirstVLM( wininfo->pTreeList );
+
+ while ( vlm != NULL ) {
+
+ parent_vlm = vlm;
+
+ vlm = VLM_GetNextVLM( vlm );
+
+ DLE_FindByName( dle_list, VLM_GetName( parent_vlm ), -1, &dle );
+
+ if ( dle == NULL ) {
+
+ // Server/Drive went away so remove it.
+
+ change_made = TRUE;
+
+ RemoveQueueElem( WMDS_GetTreeList( wininfo ), &(parent_vlm->q_elem) );
+
+ VLM_FreeVLMList( &VLM_GetChildren( parent_vlm ) );
+ free( parent_vlm );
+ }
+ else {
+
+
+ // Make sure all this servers old volumes are still on line.
+
+ child_vlm = VLM_GetFirstVLM( &parent_vlm->children );
+
+ if ( child_vlm ) {
+
+ if ( ! UI_AttachDrive( &temp_fsh, dle, FALSE ) ) {
+
+ // Keep children around by faking a bsd.
+
+ DLE_GetFirstChild( dle, &child_dle );
+
+ while ( child_dle ) {
+
+ // Only increment those that we previously decremented.
+ // NOT the new volume that just appeared.
+
+ if ( VLM_FindVLMByName( &parent_vlm->children,
+ DLE_GetDeviceName( child_dle ) ) != NULL ) {
+ DLE_IncBSDCount( child_dle );
+ }
+ DLE_GetNext( &child_dle );
+ }
+
+ FS_DetachDLE( temp_fsh );
+ }
+ }
+
+ while ( child_vlm ) {
+
+ temp_vlm = child_vlm;
+
+ child_vlm = VLM_GetNextVLM( child_vlm );
+
+ DLE_FindByName( dle_list, VLM_GetName( temp_vlm ), -1, &dle );
+
+ if ( dle == NULL ) {
+
+ change_made = TRUE;
+
+ RemoveQueueElem( &parent_vlm->children, &(temp_vlm->q_elem) );
+
+ free( temp_vlm );
+ }
+ }
+ }
+
+ }
+
+ // Look for new DLE's that aren't in the VLM queue.
+
+ vlm_count = QueueCount( WMDS_GetTreeList( wininfo ) );
+
+ VLM_BuildServerList( WMDS_GetTreeList( wininfo ), wininfo );
+
+ if ( vlm_count != QueueCount( WMDS_GetTreeList( wininfo ) ) ) {
+ change_made = TRUE;
+ }
+
+ if ( change_made ) {
+
+ DLM_Update( gb_servers_win, DLM_TREELISTBOX,
+ WM_DLMUPDATELIST,
+ (LMHANDLE)WMDS_GetTreeList( wininfo ), 0 );
+ }
+ }
+#endif //!defined ( OEM_MSOFT ) //unsupported feature
+}
+
+
+/*****
+
+ NAME : VLM_UpdateServerStatus
+
+ DESCRIPTION :
+
+ We have changed the selection status on one of this server's volumes. So
+ let's quickly update his status based on the selction status of all his
+ volumes. Run through the list and stop as soon as you hit a partially
+ selected one.
+
+*****/
+
+VOID VLM_UpdateServerStatus(
+VLM_OBJECT_PTR server_vlm ) // I - vlm of server to update
+{
+#if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ UINT16 status = 0;
+ VLM_OBJECT_PTR vlm;
+
+ vlm = VLM_GetFirstVLM( &VLM_GetChildren( server_vlm ) );
+
+ // Set up our start state
+
+ if ( vlm == NULL ) {
+
+ // OK, how did you ask for an update on a server with NO volumes ?
+
+ return;
+ }
+
+ if ( vlm->status & INFO_PARTIAL ) {
+ status = 1;
+ }
+ else {
+ if ( vlm->status & INFO_SELECT ) {
+ status = 2;
+ }
+ }
+
+ while ( vlm != NULL && status != 1 ) {
+
+ if ( vlm->status & INFO_PARTIAL ) {
+ status = 1;
+ }
+ else {
+
+ if ( ( vlm->status & INFO_SELECT ) &&
+ ( status == 0 ) ) {
+ status = 1;
+ }
+ if ( ! ( vlm->status & INFO_SELECT ) &&
+ ( status == 2 ) ) {
+ status = 1;
+ }
+ }
+
+ // get next volume
+
+ vlm = VLM_GetNextVLM( vlm );
+ }
+
+ // reset server selection status
+
+ switch ( status ) {
+
+ case 0:
+ status = 0;
+ break;
+ case 1:
+ status |= (INFO_SELECT|INFO_PARTIAL);
+ break;
+ case 2:
+ status |= INFO_SELECT;
+ break;
+ }
+
+ // Update the screen
+
+ if ( ( server_vlm->status & (UINT16)(INFO_SELECT|INFO_PARTIAL) ) != status ) {
+
+ server_vlm->status &= ~(INFO_SELECT|INFO_PARTIAL);
+ server_vlm->status |= status;
+
+ DLM_Update( gb_servers_win, DLM_TREELISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)server_vlm, 0 );
+ }
+ }
+#endif //!defined ( OEM_MSOFT ) //unsupported feature
+}
+
+
+/**********************
+
+ NAME : VLM_ClearAllServerSelections
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+VOID VLM_ClearAllServerSelections( )
+{
+#if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ VLM_OBJECT_PTR vlm;
+ VLM_OBJECT_PTR child_vlm;
+ GENERIC_DLE_PTR dle;
+
+ if ( gb_servers_win != (HWND)NULL ) {
+
+ wininfo = WM_GetInfoPtr( gb_servers_win );
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( gb_servers_win );
+
+ vlm = VLM_GetFirstVLM( WMDS_GetTreeList( wininfo ) );
+
+ while ( vlm != NULL ) {
+
+ DLE_FindByName( dle_list, VLM_GetName( vlm ), -1, &dle );
+
+ if ( VLM_GetStatus( vlm ) & (INFO_SELECT|INFO_PARTIAL) ) {
+
+ VLM_SetStatus( vlm, vlm->status & (UINT16)~(INFO_PARTIAL|INFO_SELECT|INFO_OPEN) );
+ child_vlm = VLM_GetFirstVLM( &VLM_GetChildren( vlm ) );
+
+ while ( child_vlm != NULL ) {
+
+ if ( VLM_GetStatus( child_vlm ) & (INFO_SELECT|INFO_PARTIAL) ) {
+
+ VLM_SetStatus( child_vlm, child_vlm->status & (UINT16)~(INFO_PARTIAL|INFO_SELECT) );
+
+ if ( dle == appinfo->dle ) {
+
+ DLM_Update( gb_servers_win, DLM_FLATLISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)child_vlm, 0 );
+ }
+
+ }
+ child_vlm = VLM_GetNextVLM( child_vlm );
+ }
+
+ DLM_Update( gb_servers_win, DLM_TREELISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)vlm, 0 );
+ }
+
+ vlm = VLM_GetNextVLM( vlm );
+ }
+ }
+ }
+#endif //!defined ( OEM_MSOFT ) //unsupported feature
+}
+
+
+
+/**********************
+
+ NAME : VLM_ServerListCreate
+
+ DESCRIPTION :
+
+ Create the servers window.
+
+ RETURNS : nothing
+
+**********************/
+
+VOID VLM_ServerListCreate( )
+{
+#if !defined ( OEM_MSOFT )
+ {
+
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ DLM_INIT tree_dlm;
+ DLM_INIT flat_dlm;
+ Q_HEADER_PTR srv_list;
+ VLM_OBJECT_PTR vlm;
+ GENERIC_DLE_PTR dle;
+ CHAR title[ MAX_UI_RESOURCE_SIZE ];
+
+
+ srv_list = (Q_HEADER_PTR)malloc( sizeof(Q_HEADER) );
+
+ if ( srv_list == NULL ) {
+ return;
+ }
+
+ InitQueue( srv_list );
+
+ appinfo = ( APPINFO_PTR )malloc( sizeof( APPINFO ) );
+
+ if ( appinfo == NULL ) {
+ return;
+ }
+
+ appinfo->dle = NULL;
+
+ // initialize directory list queue
+
+ wininfo = ( WININFO_PTR )malloc( sizeof( WININFO ) );
+
+ if ( wininfo == NULL ) {
+ return;
+ }
+
+ VLM_BuildServerList( srv_list, wininfo );
+
+ // fill in wininfo structure
+
+ WMDS_SetWinType( wininfo, WMTYPE_SERVERS );
+ WMDS_SetCursor( wininfo, RSM_CursorLoad( IDRC_HSLIDER ) );
+ WMDS_SetDragCursor( wininfo, 0 );
+ WMDS_SetIcon( wininfo, RSM_IconLoad( IDRI_SERVERS ) );
+ WMDS_SetWinHelpID( wininfo, 0 );
+ WMDS_SetStatusLineID( wininfo, 0 );
+ WMDS_SetRibbonState( wininfo, 0 );
+ WMDS_SetMenuState( wininfo, 0 );
+ WMDS_SetRibbon( wininfo, NULL );
+ WMDS_SetTreeList( wininfo, srv_list );
+ WMDS_SetFlatList( wininfo, ( Q_HEADER_PTR )NULL );
+ WMDS_SetTreeDisp( wininfo, NULL );
+ WMDS_SetFlatDisp( wininfo, NULL );
+ WMDS_SetAppInfo( wininfo, appinfo );
+
+ // Init display list
+
+ DLM_ListBoxType( &tree_dlm, DLM_TREELISTBOX );
+ DLM_Mode( &tree_dlm, DLM_HIERARCHICAL );
+ DLM_Display( &tree_dlm, DLM_SMALL_BITMAPS );
+ DLM_DispHdr( &tree_dlm, srv_list );
+ DLM_TextFont( &tree_dlm, DLM_SYSTEM_FONT );
+ DLM_GetItemCount( &tree_dlm, VLM_SrvGetItemCount );
+ DLM_GetFirstItem( &tree_dlm, VLM_SrvGetFirstItem );
+ DLM_GetNext( &tree_dlm, VLM_SrvGetNextItem );
+ DLM_GetPrev( &tree_dlm, VLM_SrvGetPrevItem );
+ DLM_GetTag( &tree_dlm, VLM_SrvGetTag );
+ DLM_SetTag( &tree_dlm, VLM_SrvSetTag );
+ DLM_GetSelect( &tree_dlm, VLM_SrvGetSelect );
+ DLM_SetSelect( &tree_dlm, VLM_SrvSetSelect );
+ DLM_GetObjects( &tree_dlm, VLM_SrvGetObjects );
+ DLM_SetObjects( &tree_dlm, VLM_SrvSetObjects );
+ DLM_SSetItemFocus( &tree_dlm, NULL );
+ DLM_MaxNumObjects( &tree_dlm, 6 );
+
+ DLM_DispListInit( wininfo, &tree_dlm );
+
+ DLM_ListBoxType( &flat_dlm, DLM_FLATLISTBOX );
+ DLM_Mode( &flat_dlm, DLM_SINGLECOLUMN );
+ DLM_Display( &flat_dlm, DLM_SMALL_BITMAPS );
+ DLM_DispHdr( &flat_dlm, NULL );
+ DLM_TextFont( &flat_dlm, DLM_SYSTEM_FONT );
+ DLM_GetItemCount( &flat_dlm, VLM_VolGetItemCount );
+ DLM_GetFirstItem( &flat_dlm, VLM_VolGetFirstItem );
+ DLM_GetNext( &flat_dlm, VLM_VolGetNextItem );
+ DLM_GetPrev( &flat_dlm, VLM_VolGetPrevItem );
+ DLM_GetTag( &flat_dlm, VLM_VolGetTag );
+ DLM_SetTag( &flat_dlm, VLM_VolSetTag );
+ DLM_GetSelect( &flat_dlm, VLM_VolGetSelect );
+ DLM_SetSelect( &flat_dlm, VLM_VolSetSelect );
+ DLM_GetObjects( &flat_dlm, VLM_VolGetObjects );
+ DLM_SetObjects( &flat_dlm, VLM_VolSetObjects );
+ DLM_SSetItemFocus( &flat_dlm, NULL );
+ DLM_MaxNumObjects( &flat_dlm, 6 );
+
+ DLM_DispListInit( wininfo, &flat_dlm );
+
+ // open a new window
+ RSM_StringCopy ( IDS_VLMSERVERTITLE, title, MAX_UI_RESOURCE_LEN );
+
+ gb_servers_win = WM_Create( WM_MDIPRIMARY |
+ WM_TREELIST | WM_FLATLISTSC | WM_MIN,
+ title,
+ NULL,
+ WM_DEFAULT,
+ WM_DEFAULT,
+ WM_DEFAULT,
+ WM_DEFAULT,
+ wininfo );
+
+ appinfo->win = gb_servers_win;
+
+ // Start display manager up.
+
+ DLM_DispListProc( WMDS_GetWinTreeList( wininfo ), 0, NULL );
+ DLM_DispListProc( WMDS_GetWinFlatList( wininfo ), 0, NULL );
+
+ // Now that it is all set up, find the first logged in server
+ // and send myself a double click message on it.
+
+ vlm = VLM_GetFirstVLM( srv_list );
+
+ while ( vlm != NULL ) {
+
+ DLE_FindByName( dle_list, vlm->name, -1, &dle );
+ if ( dle != NULL ) {
+ if ( DLE_ServerLoggedIn( dle ) ) {
+ break;
+ }
+ }
+ vlm = VLM_GetNextVLM( vlm );
+ }
+
+ if ( vlm != NULL ) {
+ // make it active.
+
+ DLM_SetAnchor( WMDS_GetWinTreeList( wininfo ),
+ 0,
+ (LMHANDLE)vlm );
+
+ VLM_SrvSetObjects( vlm, WM_DLMDBCLK, 2 );
+ }
+ }
+#endif
+}
+
+
+
+/**********************
+
+ NAME : VLM_BuildServerList
+
+ DESCRIPTION :
+
+ Go through the global DLE list and create VLM entries for all the
+ servers you find.
+
+ RETURNS : nothing
+
+**********************/
+
+VOID VLM_BuildServerList(
+Q_HEADER_PTR srv_list, // I - queue of servers
+WININFO_PTR XtraBytes ) // I
+{
+ GENERIC_DLE_PTR server_dle;
+ GENERIC_DLE_PTR temp_dle;
+ VLM_OBJECT_PTR server_vlm;
+
+ DLE_GetFirst( dle_list, &server_dle );
+
+ do {
+
+ do {
+
+ if ( DLE_GetDeviceType( server_dle ) == NOVELL_SERVER_ONLY ) {
+ break;
+ }
+
+ DLE_GetNext( &server_dle );
+
+ } while ( server_dle != NULL );
+
+ if ( server_dle != NULL ) {
+
+ temp_dle = server_dle;
+ DLE_GetNext( &server_dle );
+
+ if ( VLM_FindVLMByName( srv_list,
+ DLE_GetDeviceName( temp_dle ) ) == NULL ) {
+
+ server_vlm = VLM_CreateVLM( DLE_SizeofVolName( temp_dle ),
+ (INT16)(strlen( DLE_GetDeviceName( temp_dle ) ) * sizeof(CHAR)) );
+
+ if ( server_vlm != NULL ) {
+
+ VLM_SetName( server_vlm, DLE_GetDeviceName( temp_dle ) );
+ VLM_SetXtraBytes( server_vlm, XtraBytes );
+ DLE_GetVolName( temp_dle, server_vlm->label ) ;
+
+ EnQueueElem( srv_list, &(server_vlm->q_elem), FALSE );
+
+ // Ideally this would handle dynamic logins too.
+
+ if ( DLE_ServerLoggedIn( temp_dle ) ) {
+
+ // Attach so that we get child dle's created
+
+ VLM_FindServerChildren( server_vlm );
+ }
+ }
+ }
+ }
+
+ } while ( server_dle != NULL );
+
+ SortQueue( srv_list, VLM_VlmCompare );
+
+}
+
+/**********************
+
+ NAME : VLM_VlmCompare
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT16 VLM_VlmCompare(
+Q_ELEM_PTR e1, // I - queue element 1
+Q_ELEM_PTR e2 ) // I - queue element 2
+{
+ VLM_OBJECT_PTR vlm1, vlm2;
+ CHAR_PTR s;
+
+ vlm1 = ( VLM_OBJECT_PTR )e1->q_ptr;
+ vlm2 = ( VLM_OBJECT_PTR )e2->q_ptr;
+
+ // Always put SYS: first
+
+ s = strrchr( VLM_GetName( vlm1 ), TEXT('/') );
+
+ if ( s != NULL ) {
+
+ if ( ! stricmp( s, TEXT("/SYS:") ) ) {
+ return( (INT16)-1 );
+ }
+
+ }
+
+ s = strrchr( VLM_GetName( vlm2 ), TEXT('/') );
+
+ if ( s != NULL ) {
+
+ if ( ! stricmp( s, TEXT("/SYS:") ) ) {
+ return( (INT16)1 );
+ }
+
+ }
+
+ // sort by alphabet
+
+ return( (INT16)stricmp( VLM_GetName( vlm1 ), VLM_GetName( vlm2 ) ) );
+}
+
+
+/**********************
+
+ NAME : VLM_FindServerChildren
+
+ DESCRIPTION :
+
+ We wish to see what children exist for a given server. So do a quick
+ attach to make the children visible and build VLM structures for them.
+
+ RETURNS : number of children (volumes) found.
+
+**********************/
+
+
+INT VLM_FindServerChildren( VLM_OBJECT_PTR server_vlm )
+{
+ FSYS_HAND temp_fsh;
+ GENERIC_DLE_PTR dle;
+
+ DLE_FindByName( dle_list, server_vlm->name, ANY_DRIVE_TYPE, &dle );
+
+ if ( dle == NULL ) {
+ return( 0 );
+ }
+
+ if ( UI_AttachDrive( &temp_fsh, dle, FALSE ) ) {
+ return( 0 );
+ }
+
+ VLM_AddInServerChildren( server_vlm );
+
+ FS_DetachDLE( temp_fsh );
+
+ return( QueueCount( &server_vlm->children ) );
+}
+
+/**********************
+
+ NAME : VLM_AddInServerChildren
+
+ DESCRIPTION :
+
+ Adds VLM structures for all the Servers volumes.
+
+
+ RETURNS : nothing.
+
+**********************/
+
+VOID VLM_AddInServerChildren(
+VLM_OBJECT_PTR parent_vlm ) // I - server vlm
+{
+ GENERIC_DLE_PTR parent_dle;
+ GENERIC_DLE_PTR dle;
+ VLM_OBJECT_PTR vlm;
+
+
+ DLE_FindByName( dle_list, VLM_GetName( parent_vlm ), ANY_DRIVE_TYPE, &parent_dle );
+
+ if ( parent_dle == NULL ) {
+ return;
+ }
+
+ DLE_GetFirstChild( parent_dle, &dle );
+
+ while ( dle != NULL ) {
+
+ if ( VLM_FindVLMByName( &VLM_GetChildren( parent_vlm ),
+ DLE_GetDeviceName( dle ) ) == NULL ) {
+
+ vlm = VLM_CreateVLM( DLE_SizeofVolName( dle ),
+ (INT16)(strlen( DLE_GetDeviceName( dle ) ) * sizeof(CHAR)) );
+
+ if ( vlm != NULL ) {
+ VLM_SetName( vlm, DLE_GetDeviceName( dle ) );
+ DLE_GetVolName( dle, vlm->label ) ;
+ DLE_IncBSDCount( dle );
+ VLM_SetParent( vlm, parent_vlm );
+ VLM_SetXtraBytes( vlm, VLM_GetXtraBytes( parent_vlm ) );
+ EnQueueElem( &VLM_GetChildren( parent_vlm ), &(vlm->q_elem), FALSE );
+ }
+ }
+
+ DLE_GetNext( &dle );
+ }
+
+ SortQueue( & VLM_GetChildren( parent_vlm ), VLM_VlmCompare );
+}
+
+/**********************
+
+ NAME : VLM_SrvSetSelect
+
+ DESCRIPTION :
+
+ RETURNS : nothing
+
+**********************/
+
+static VOID_PTR VLM_SrvSetSelect(
+VLM_OBJECT_PTR server_vlm,
+BYTE attr )
+{
+#if !defined ( OEM_MSOFT )
+ {
+ VLM_OBJECT_PTR vlm;
+ APPINFO_PTR appinfo;
+ UINT16 status;
+ FSYS_HAND temp_fsh;
+ BOOLEAN all_subdirs;
+ GENERIC_DLE_PTR server_dle;
+
+
+ all_subdirs = (BOOLEAN) CDS_GetIncludeSubdirs( CDS_GetPerm() );
+
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( gb_servers_win );
+
+ DLE_FindByName( dle_list, server_vlm->name, -1, &server_dle );
+
+ if ( server_dle == NULL ) {
+ return( NULL );
+ }
+
+ if ( QueueCount( &server_vlm->children ) == 0 ) {
+
+ if ( UI_AttachDrive( &temp_fsh, server_dle, FALSE ) ) {
+ return( NULL );
+ }
+
+ VLM_AddInServerChildren( server_vlm );
+
+ FS_DetachDLE( temp_fsh );
+ }
+
+ if ( QueueCount( &server_vlm->children ) == 0 ) {
+ return( NULL );
+ }
+
+ if ( attr ) {
+ if ( all_subdirs ) {
+ status = INFO_SELECT;
+ }
+ else {
+ status = (INFO_PARTIAL|INFO_SELECT);
+ }
+ }
+ else {
+ status = 0;
+ }
+
+ if ( (server_vlm->status & (UINT16)(INFO_PARTIAL|INFO_SELECT) ) != status ) {
+
+ server_vlm->status &= ~(INFO_PARTIAL|INFO_SELECT);
+ server_vlm->status |= status;
+
+ DLM_Update( gb_servers_win, DLM_TREELISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)server_vlm, 0 );
+ }
+
+ // update the vol list if this server is the currently selected
+
+ if ( server_dle == appinfo->dle ) {
+ DLM_Update( gb_servers_win, DLM_FLATLISTBOX,
+ WM_DLMUPDATELIST,
+ (LMHANDLE)&server_vlm->children, 0 );
+ }
+
+ // do all the volumes
+
+ vlm = VLM_GetFirstVLM( &server_vlm->children );
+
+ while ( vlm != NULL ) {
+
+ VLM_DoVolSetSelect( vlm, attr );
+
+ vlm = VLM_GetNextVLM( vlm );
+ }
+
+ }
+#endif
+
+ return( NULL );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+static BYTE VLM_SrvGetSelect( VLM_OBJECT_PTR vlm )
+{
+ if ( vlm->status & INFO_SELECT ) {
+ return( 1 );
+ }
+ else {
+ return( 0 );
+ }
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+static VOID_PTR VLM_SrvSetTag( VLM_OBJECT_PTR vlm, BYTE attr )
+{
+
+ if ( attr ) {
+ vlm->status |= INFO_TAGGED;
+ }
+ else {
+ vlm->status &= ~INFO_TAGGED;
+ }
+ return(NULL);
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+static BYTE VLM_SrvGetTag( VLM_OBJECT_PTR vlm )
+{
+ if ( INFO_TAGGED & vlm->status ) {
+ return( 1 );
+ }
+ else {
+ return( 0 );
+ }
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+static USHORT VLM_SrvGetItemCount( Q_HEADER_PTR srv_list )
+{
+ return( QueueCount( srv_list ) );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+static VOID_PTR VLM_SrvGetFirstItem( Q_HEADER_PTR srv_list )
+{
+ return( VLM_GetFirstVLM( srv_list ) );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+static VOID_PTR VLM_SrvGetPrevItem( VLM_OBJECT_PTR vlm )
+{
+ return( VLM_GetPrevVLM( vlm ) );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+static VOID_PTR VLM_SrvGetNextItem( VLM_OBJECT_PTR vlm )
+{
+ return( VLM_GetNextVLM( vlm ) );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+static VOID_PTR VLM_SrvGetObjects( VLM_OBJECT_PTR vlm )
+{
+#if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ BYTE_PTR memblk;
+ DLM_ITEM_PTR item;
+ WININFO_PTR wininfo;
+ GENERIC_DLE_PTR dle;
+
+ DLE_FindByName( dle_list, vlm->name, -1, &dle );
+
+ /* malloc enough room to store info */
+
+ wininfo = WM_GetInfoPtr( gb_servers_win );
+ memblk = ( BYTE_PTR )DLM_GetObjectsBuffer( wininfo->hWndFlatList );
+
+ /* Store the number of items in the first two bytes. */
+
+ *memblk = 3;
+
+ /* Set up check box. */
+
+ item = (DLM_ITEM_PTR)( memblk + 6 );
+
+ DLM_ItemcbNum( item ) = 1;
+ DLM_ItembType( item ) = DLM_CHECKBOX;
+ if ( vlm->status & INFO_SELECT ) {
+ DLM_ItemwId( item ) = IDRBM_SEL_ALL;
+ if ( vlm->status & INFO_PARTIAL ) {
+ DLM_ItemwId( item ) = IDRBM_SEL_PART;
+ }
+ }
+ else {
+ DLM_ItemwId( item ) = IDRBM_SEL_NONE;
+ }
+ DLM_ItembMaxTextLen( item ) = 0;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+
+ /* Set up Bitmap, ie. Floppy, Hard, Network. */
+
+ item++;
+ DLM_ItemcbNum( item ) = 2;
+ DLM_ItembType( item ) = DLM_BITMAP;
+ DLM_ItemwId( item ) = IDRBM_SERVERDETACHED;
+ if ( dle ) {
+ if ( DLE_ServerLoggedIn( dle ) ) {
+ DLM_ItemwId( item ) = IDRBM_SERVER;
+ }
+ }
+ DLM_ItembMaxTextLen( item ) = 0;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+
+ /* Set up the text string to be displayed. */
+
+ item++;
+ DLM_ItemcbNum( item ) = 3;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = (BYTE)strlen( vlm->name );
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+ strcpy( ( LPSTR )DLM_ItemqszString( item ), vlm->name );
+
+ return( memblk );
+ }
+#else //if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ return NULL;
+ }
+#endif //!defined ( OEM_MSOFT ) //unsupported feature
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+static BOOLEAN VLM_SrvSetObjects(
+VLM_OBJECT_PTR vlm,
+WORD operation,
+WORD ObjectNum )
+{
+ APPINFO_PTR appinfo;
+ WININFO_PTR wininfo;
+ INT16 result;
+ GENERIC_DLE_PTR dle;
+ VLM_OBJECT_PTR old_vlm;
+ VLM_OBJECT_PTR temp_vlm;
+ CHAR keyb_char;
+ BOOLEAN ret_val = FALSE;
+ CHAR text[ MAX_UI_RESOURCE_SIZE ];
+
+ (void)old_vlm ;
+ (void)text ;
+ (void)dle ;
+ (void)wininfo ;
+ (void)result ;
+ (void)appinfo ;
+
+
+ if ( operation == WM_DLMCHAR ) {
+
+ keyb_char = (CHAR)ObjectNum;
+
+ keyb_char = (CHAR)toupper( keyb_char );
+
+ temp_vlm = vlm;
+
+ do {
+
+ temp_vlm = VLM_GetNextVLM( temp_vlm );
+
+ if ( temp_vlm != NULL ) {
+
+ if ( keyb_char == (CHAR)toupper( *VLM_GetName( temp_vlm ) ) ) {
+
+ DLM_SetAnchor( WMDS_GetWinFlatList( VLM_GetXtraBytes( temp_vlm ) ),
+ 0,
+ (LMHANDLE)temp_vlm );
+ vlm = temp_vlm;
+ operation = WM_DLMDOWN;
+ ObjectNum = 2;
+ ret_val = TRUE;
+ break;
+ }
+ }
+
+ } while ( temp_vlm != NULL );
+
+ if ( ret_val == FALSE ) {
+ temp_vlm = VLM_GetFirstVLM( WMDS_GetTreeList( VLM_GetXtraBytes( vlm ) ) );
+
+ while ( temp_vlm != NULL && temp_vlm != vlm ) {
+
+ if ( keyb_char == (CHAR)toupper( *VLM_GetName( temp_vlm ) ) ) {
+
+ DLM_SetAnchor( WMDS_GetWinFlatList( VLM_GetXtraBytes( temp_vlm ) ),
+ 0,
+ (LMHANDLE)temp_vlm );
+ vlm = temp_vlm;
+ operation = WM_DLMDOWN;
+ ObjectNum = 2;
+ ret_val = TRUE;
+ }
+
+ temp_vlm = VLM_GetNextVLM( temp_vlm );
+
+ }
+ }
+
+ if ( ret_val == FALSE ) {
+
+ DLM_SetAnchor( WMDS_GetWinFlatList( VLM_GetXtraBytes( vlm ) ),
+ 0,
+ (LMHANDLE)vlm );
+
+ }
+ }
+
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ if ( ( operation == WM_DLMDBCLK || operation == WM_DLMDOWN ) &&
+ ( ObjectNum >= 2 ) ) {
+
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( gb_servers_win );
+ wininfo = WM_GetInfoPtr( gb_servers_win );
+
+ // if current server then do nothing
+
+ DLE_FindByName( dle_list, VLM_GetName( vlm ), -1, &dle );
+
+ if ( ( dle == NULL ) || ( dle == appinfo->dle ) ) {
+ return( ret_val );
+ }
+
+ if ( ( appinfo->server_fsh != NULL ) && ( appinfo->dle != NULL ) ) {
+
+ FS_DetachDLE( appinfo->server_fsh );
+ appinfo->server_fsh = NULL;
+
+ old_vlm = VLM_FindVLMByName( wininfo->pTreeList,
+ DLE_GetDeviceName( appinfo->dle ) );
+
+ DLM_Update( gb_servers_win,
+ DLM_TREELISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)old_vlm, 0 );
+ }
+
+ result = FAILURE;
+
+ if ( ( operation == WM_DLMDBCLK ) ||
+ ( DLE_ServerLoggedIn( dle ) ) ) {
+
+ result = UI_AttachDrive( &appinfo->server_fsh, dle, FALSE ) ;
+ }
+
+ if ( result != SUCCESS ) {
+
+
+ RSM_StringCopy( IDS_VLMSERVERNOTLOGGEDIN, text, MAX_UI_RESOURCE_LEN );
+
+ STM_DrawText( text );
+
+ appinfo->server_fsh = NULL;
+ appinfo->dle = NULL;
+ wininfo->pFlatList = NULL;
+
+ DLM_Update( gb_servers_win, DLM_FLATLISTBOX,
+ WM_DLMUPDATELIST,
+ (LMHANDLE)NULL, 0 );
+ return( ret_val );
+ }
+
+ // See if any new volumes have come on line.
+
+ VLM_AddInServerChildren( vlm );
+
+ STM_SetIdleText( IDS_READY );
+
+ appinfo->dle = dle;
+
+ // change pointer for volume list to this dle
+
+ wininfo->pFlatList = &VLM_GetChildren( vlm );
+
+ // update server
+
+ DLM_Update( gb_servers_win,
+ DLM_TREELISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)vlm, 0 );
+
+ // update volume list
+
+ DLM_Update( gb_servers_win,
+ DLM_FLATLISTBOX,
+ WM_DLMUPDATELIST,
+ (LMHANDLE)&VLM_GetChildren( vlm ), 0 );
+ }
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ return( ret_val );
+}
+
+//************
+// VOLUMES
+//************
+
+/*****
+ In my terminology, a volume is a server volume and a disk is a mapped or
+ local dos drive. The user has tagged one or more volumes and hit the
+ select or unselect button. This function does the processing for that
+ command.
+*****/
+
+/**********************
+
+ NAME : VLM_SelectVolumes
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+VOID VLM_SelectVolumes(
+BYTE attr ) // I - select or deselect ?
+{
+#if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ VLM_OBJECT_PTR vlm;
+ VLM_OBJECT_PTR server_vlm;
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+
+ wininfo = WM_GetInfoPtr( gb_servers_win );
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( gb_servers_win );
+
+ if ( WM_IsFlatActive( wininfo ) ) {
+
+ // Have the display list manager update our tags for us.
+
+ DLM_UpdateTags( gb_servers_win, DLM_FLATLISTBOX );
+
+ vlm = VLM_GetFirstVLM( wininfo->pFlatList );
+
+ while ( vlm != NULL ) {
+
+ if ( vlm->status & INFO_TAGGED ) {
+
+ VLM_VolSetSelect( vlm, attr );
+ }
+ vlm = VLM_GetNextVLM( vlm );
+ }
+ }
+
+ if ( WM_IsTreeActive( wininfo ) ) {
+
+ server_vlm = VLM_GetFirstVLM( wininfo->pTreeList );
+
+ while ( server_vlm != NULL ) {
+
+ if ( server_vlm->status & INFO_TAGGED ) {
+
+ VLM_SrvSetSelect( server_vlm, attr );
+ }
+
+ server_vlm = VLM_GetNextVLM( server_vlm );
+ }
+ }
+ }
+#endif //!defined ( OEM_MSOFT ) //unsupported feature
+}
+
+/**********************
+
+ NAME : VLM_VolSetSelect
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+static VOID_PTR VLM_VolSetSelect( VLM_OBJECT_PTR vlm, BYTE attr )
+{
+ // we need mark this guys parent
+
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ DLM_Update( gb_servers_win, DLM_FLATLISTBOX, WM_DLMUPDATEITEM,
+ (LMHANDLE)vlm, 0 );
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ VLM_UpdateServerStatus( vlm->parent );
+
+ return( VLM_DoVolSetSelect( vlm, attr ) );
+}
+
+
+/**********************
+
+ NAME : VLM_DoVolSetSelect
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+static VOID_PTR VLM_DoVolSetSelect( VLM_OBJECT_PTR vlm, BYTE attr )
+{
+ GENERIC_DLE_PTR dle;
+ CHAR title[VLM_BUFFER_SIZE];
+ INT16 length;
+ WININFO_PTR wininfo;
+ BSD_PTR bsd_ptr;
+ FSE_PTR fse_ptr;
+ HWND win;
+ INT16 error;
+ BOOLEAN all_subdirs;
+ BE_CFG_PTR bec_config;
+ BOOLEAN open_win;
+ SLM_OBJECT_PTR slm;
+ INT16 bset_num;
+ QTC_BSET_PTR qtc_bset;
+ QTC_HEADER_PTR header;
+
+
+ all_subdirs = (BOOLEAN) CDS_GetIncludeSubdirs( CDS_GetPerm() );
+
+ // change the status
+
+ if ( attr ) {
+
+ if ( all_subdirs ) {
+ vlm->status &= ~INFO_PARTIAL;
+ vlm->status |= INFO_SELECT;
+ }
+ else {
+ vlm->status |= (INFO_PARTIAL|INFO_SELECT);
+ }
+ }
+ else {
+ vlm->status &= ~(INFO_PARTIAL|INFO_SELECT);
+ }
+
+ if ( attr ) {
+ error = BSD_CreatFSE( &fse_ptr, INCLUDE,
+ (INT8_PTR)TEXT(""), (UINT16)sizeof(CHAR),
+ (INT8_PTR)ALL_FILES, ALL_FILES_LENG,
+ USE_WILD_CARD, TRUE );
+ }
+ else {
+ error = BSD_CreatFSE( &fse_ptr, EXCLUDE,
+ (INT8_PTR)TEXT(""), (UINT16)sizeof(CHAR),
+ (INT8_PTR)ALL_FILES, ALL_FILES_LENG,
+ USE_WILD_CARD, TRUE );
+ }
+
+ if ( error ) {
+ return( NULL );
+ }
+
+
+ DLE_FindByName( dle_list, vlm->name, ANY_DRIVE_TYPE, &dle );
+
+ if ( dle == NULL ) {
+ return( NULL );
+ }
+
+ bsd_ptr = BSD_FindByDLE( bsd_list, dle );
+
+ if ( bsd_ptr == NULL ) {
+
+ bec_config = BEC_CloneConfig( CDS_GetPermBEC() );
+ BEC_UnLockConfig( bec_config );
+
+ BSD_Add( bsd_list, &bsd_ptr, bec_config,
+ NULL, dle, (UINT32)-1L, (UINT16)-1, (INT16)-1, NULL, NULL );
+ }
+
+ if ( bsd_ptr != NULL ) {
+ BSD_AddFSE( bsd_ptr, fse_ptr );
+ }
+
+ // See if this drive has any open file display windows
+ // If we find one then all its entries will need updating
+
+ open_win = FALSE;
+ win = WM_GetNext( (HWND)NULL );
+ length = (INT16)strlen( vlm->name );
+
+ while ( win != (HWND)NULL ) {
+
+ wininfo = WM_GetInfoPtr( win );
+
+ /* Is it a directory list ? */
+
+ if ( WMDS_GetWinType( wininfo ) == WMTYPE_DISKTREE ) {
+
+ WM_GetTitle( win, title, VLM_BUFFER_SIZE );
+
+ if ( ! strnicmp( title, VLM_GetName( vlm ), length) ) {
+
+ open_win = TRUE;
+
+ if ( attr ) {
+ VLM_SubdirListManager( win, SLM_SEL_ALL );
+ if ( bsd_ptr != NULL ) {
+ VLM_MatchSLMList( wininfo, bsd_ptr, FALSE );
+ }
+ }
+ else {
+ VLM_SubdirListManager( win, SLM_SEL_NONE );
+ VLM_DeselectAll( wininfo, FALSE );
+ }
+ break;
+ }
+ }
+
+ win = WM_GetNext( win );
+ }
+
+ return( NULL );
+}
+
+
+/*
+ Get the selection status for the Display Manager.
+*/
+/**********************
+
+ NAME : VLM_VolGetSelect
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static BYTE VLM_VolGetSelect( VLM_OBJECT_PTR vlm )
+{
+ if ( vlm->status & INFO_SELECT ) {
+ return( 1 );
+ }
+ else {
+ return( 0 );
+ }
+}
+
+/*
+ Set the tag status for the Display Manager.
+*/
+/**********************
+
+ NAME : VLM_VolSetTag
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static VOID_PTR VLM_VolSetTag( VLM_OBJECT_PTR vlm, BYTE attr )
+{
+ if ( attr ) {
+ vlm->status |= INFO_TAGGED;
+ }
+ else {
+ vlm->status &= ~INFO_TAGGED;
+ }
+
+ return( NULL );
+}
+
+/*
+ Get the tag status for the Display Manager.
+*/
+/**********************
+
+ NAME : VLM_VolGetTag
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static BYTE VLM_VolGetTag( VLM_OBJECT_PTR vlm )
+{
+ if ( INFO_TAGGED & vlm->status ) {
+ return( 1 );
+ }
+ else {
+ return( 0 );
+ }
+}
+
+/*
+ Get the item count in our list for the Display Manager.
+*/
+/**********************
+
+ NAME : VLM_VolGetItemCount
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static USHORT VLM_VolGetItemCount( Q_HEADER_PTR vol_list )
+{
+ if ( vol_list == NULL ) {
+ return( 0 );
+ }
+ return( QueueCount(vol_list) );
+}
+
+/*
+ Return the first item for the Display Manager.
+*/
+/**********************
+
+ NAME : VLM_VolGetFirstItem
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static VOID_PTR VLM_VolGetFirstItem( Q_HEADER_PTR vol_list )
+{
+ if ( vol_list == NULL ) {
+ return( NULL );
+ }
+ return( QueueHead( vol_list ) );
+}
+
+/*
+ Get the previous list item for the Display Manager.
+*/
+/**********************
+
+ NAME : VLM_VolGetPrevItem
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static VOID_PTR VLM_VolGetPrevItem( VLM_OBJECT_PTR vlm )
+{
+ return( VLM_GetPrevVLM( vlm ) );
+}
+
+/*
+ Get the next list item for the Display Manager.
+*/
+/**********************
+
+ NAME : VLM_VolGetNextItem
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static VOID_PTR VLM_VolGetNextItem( VLM_OBJECT_PTR vlm )
+{
+ return( VLM_GetNextVLM( vlm ) );
+}
+
+/*
+ For a given object get the information that needs to be displayed.
+*/
+/**********************
+
+ NAME : VLM_VolGetObjects
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static VOID_PTR VLM_VolGetObjects( VLM_OBJECT_PTR vlm )
+{
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ BYTE_PTR memblk;
+ DLM_ITEM_PTR item;
+ WININFO_PTR wininfo;
+
+ /* malloc enough room to store info */
+
+ wininfo = WM_GetInfoPtr( gb_servers_win );
+ memblk = ( BYTE_PTR )DLM_GetObjectsBuffer( wininfo->hWndTreeList );
+
+ /* Store the number of items in the first two bytes. */
+
+ *memblk = 3;
+
+ /* Set up check box. */
+
+ item = (DLM_ITEM_PTR)( memblk + 6 );
+
+ DLM_ItemcbNum( item ) = 1;
+ DLM_ItembType( item ) = DLM_CHECKBOX;
+ if ( vlm->status & INFO_SELECT ) {
+ DLM_ItemwId( item ) = IDRBM_SEL_ALL;
+ if ( vlm->status & INFO_PARTIAL ) {
+ DLM_ItemwId( item ) = IDRBM_SEL_PART;
+ }
+ }
+ else {
+ DLM_ItemwId( item ) = IDRBM_SEL_NONE;
+ }
+ DLM_ItembMaxTextLen( item ) = 0;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+
+ item++;
+ DLM_ItemcbNum( item ) = 2;
+ DLM_ItembType( item ) = DLM_BITMAP;
+ DLM_ItemwId( item ) = IDRBM_SDISK;
+ DLM_ItembMaxTextLen( item ) = 0;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+
+ /* Set up the text string to be displayed. */
+
+ item++;
+ DLM_ItemcbNum( item ) = 3;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = (BYTE)strlen( VLM_GetName( vlm ) );
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+ strcpy( ( LPSTR )DLM_ItemqszString( item ), VLM_GetName( vlm ) );
+
+ return( memblk );
+ }
+# else //if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ return NULL;
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+}
+
+/*
+ Handle that we got a click or a double click.
+*/
+/**********************
+
+ NAME : VLM_VolSetObjects
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static BOOLEAN VLM_VolSetObjects(
+VLM_OBJECT_PTR vlm, // I
+WORD operation, // I
+WORD ObjectNum ) // I
+{
+ INT16 length;
+ VLM_OBJECT_PTR temp_vlm;
+ BOOLEAN found = FALSE;
+ HWND win;
+ WININFO_PTR wininfo;
+ GENERIC_DLE_PTR dle;
+ CHAR keyb_char;
+ CHAR title[ VLM_BUFFER_SIZE ];
+ CHAR text[ MAX_UI_RESOURCE_SIZE ];
+
+ if ( operation == WM_DLMCHAR ) {
+
+ keyb_char = (CHAR)ObjectNum;
+
+ keyb_char = (CHAR)toupper( keyb_char );
+
+ temp_vlm = vlm;
+
+ do {
+
+ temp_vlm = VLM_GetNextVLM( temp_vlm );
+
+ if ( temp_vlm != NULL ) {
+
+ if ( keyb_char == (CHAR)toupper( *VLM_GetName( temp_vlm ) ) ) {
+
+ DLM_SetAnchor( WMDS_GetWinFlatList( VLM_GetXtraBytes( temp_vlm ) ),
+ 0,
+ (LMHANDLE)temp_vlm );
+ return( TRUE );
+ }
+ }
+
+ } while ( temp_vlm != NULL );
+
+ temp_vlm = VLM_GetFirstVLM( WMDS_GetFlatList( VLM_GetXtraBytes( vlm ) ) );
+
+ while ( temp_vlm != NULL && temp_vlm != vlm ) {
+
+ if ( keyb_char == (CHAR)toupper( *VLM_GetName( temp_vlm ) ) ) {
+
+ DLM_SetAnchor( WMDS_GetWinFlatList( VLM_GetXtraBytes( temp_vlm ) ),
+ 0,
+ (LMHANDLE)temp_vlm );
+ return( TRUE );
+ }
+
+ temp_vlm = VLM_GetNextVLM( temp_vlm );
+
+ }
+
+ DLM_SetAnchor( WMDS_GetWinFlatList( VLM_GetXtraBytes( vlm ) ),
+ 0,
+ (LMHANDLE)vlm );
+ return( TRUE );
+ }
+
+ if ( ( operation == WM_DLMDBCLK || operation == WM_DLMCLICK ) &&
+ ( ObjectNum >= 2 ) ) {
+
+ length = (INT16)strlen( VLM_GetName( vlm ) );
+
+ win = WM_GetNext( (HWND)NULL );
+
+ while ( win != (HWND)NULL ) {
+
+ wininfo = WM_GetInfoPtr( win );
+
+ if ( WMDS_GetWinType( wininfo ) == WMTYPE_DISKTREE ) {
+
+ WM_GetTitle( win, title, VLM_BUFFER_SIZE );
+
+ if ( ! strnicmp( title, VLM_GetName( vlm ), length ) ) {
+ found = TRUE;
+ WM_DocActivate( win );
+ break;
+ }
+ }
+
+ win = WM_GetNext( win );
+ }
+
+ if ( ! found ) {
+
+ WM_ShowWaitCursor( TRUE );
+
+ DLE_FindByName( dle_list, VLM_GetName( vlm ), -1, &dle );
+
+ if ( dle != NULL ) {
+
+ if ( VLM_MayWeAttachToVolume( dle ) ) {
+
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ VLM_SubdirListCreate( dle, 0, 0, 0, gb_servers_win );
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+ }
+ else {
+
+ RSM_StringCopy( IDS_VLMAFPTITLE, title, MAX_UI_RESOURCE_LEN );
+ RSM_StringCopy( IDS_VLMAFPTEXT, text, MAX_UI_RESOURCE_LEN );
+
+ WM_MsgBox( title,
+ text,
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ }
+ }
+
+ WM_ShowWaitCursor( FALSE );
+ }
+
+ }
+
+ return( FALSE );
+}
diff --git a/private/utils/ntbackup/src/vlm_strt.c b/private/utils/ntbackup/src/vlm_strt.c
new file mode 100644
index 000000000..02510e1a0
--- /dev/null
+++ b/private/utils/ntbackup/src/vlm_strt.c
@@ -0,0 +1,684 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: VLM_STRT.C
+
+ Description:
+
+ This file contains the functions needed to start operations.
+
+ $Log: G:/UI/LOGFILES/VLM_STRT.C_V $
+
+ Rev 1.48.2.1 16 Jun 1994 15:32:40 STEVEN
+print to log if nothing selected
+
+ Rev 1.48.2.0 15 Mar 1994 22:54:02 STEVEN
+exclude registry files on restore-veryf
+
+ Rev 1.48 18 Jun 1993 16:50:20 CARLS
+added NtDemoChangeTape calls for NtDemo
+
+ Rev 1.47 26 Apr 1993 08:52:36 MIKEP
+Add numerous changes to fully support the font case selection
+for various file system types. Also add refresh for tapes window
+and sorting of tapes window.
+
+ Rev 1.46 21 Apr 1993 16:10:56 GLENN
+Status line now shows when deleting transferred files.
+
+ Rev 1.45 06 Apr 1993 17:54:16 GLENN
+Now changing the status line to say Verifying when verify is called during opertion.
+
+ Rev 1.44 25 Mar 1993 15:47:50 CARLS
+added RestoreSecurity in start backup for verify after
+
+ Rev 1.43 12 Mar 1993 14:42:50 CARLS
+changes for format tape
+
+ Rev 1.42 10 Mar 1993 12:49:08 CARLS
+Changes to move Format tape to the Operations menu
+
+ Rev 1.41 11 Feb 1993 16:21:04 STEVEN
+do not verify registry files
+
+ Rev 1.40 08 Feb 1993 15:28:50 CARLS
+Fixed the problem were the tape window showed a blank tape
+and the user canceled from the target backup screen,
+causing the blank tape entry to go away.
+
+ Rev 1.39 08 Feb 1993 11:24:36 CARLS
+add BSD_SetProcElemOnlyFlg to False to process security info on verify after backup
+
+ Rev 1.38 17 Nov 1992 21:22:52 DAVEV
+unicode fixes
+
+ Rev 1.37 26 Oct 1992 13:45:14 MIKEP
+fix replace on blank tape
+
+ Rev 1.36 20 Oct 1992 14:32:18 MIKEP
+changes for otc
+
+ Rev 1.35 12 Oct 1992 13:24:54 MIKEP
+cataloging a set fix
+
+ Rev 1.34 09 Oct 1992 12:57:04 MIKEP
+catalog a set changes for NT
+
+ Rev 1.33 07 Oct 1992 15:06:34 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.32 04 Oct 1992 19:43:04 DAVEV
+Unicode Awk pass
+
+ Rev 1.31 02 Sep 1992 21:13:46 CHUCKB
+Put in changes from MikeP from Microsoft.
+
+ Rev 1.30 29 Jul 1992 09:34:16 MIKEP
+ChuckB checked in after NT warnings were fixed.
+
+ Rev 1.29 14 May 1992 18:05:40 MIKEP
+nt pass 2
+
+ Rev 1.28 06 May 1992 14:40:22 MIKEP
+unicode pass two
+
+ Rev 1.27 04 May 1992 13:40:08 MIKEP
+unicode pass 1
+
+ Rev 1.26 09 Apr 1992 08:46:18 MIKEP
+speed up lots of sets
+
+
+*****************************************************/
+
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+/**********************
+
+ NAME : VLM_StartCatalog
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+INT VLM_StartCatalog( )
+{
+ INT error = SUCCESS;
+
+ if ( ! HWC_TapeHWProblem( bsd_list ) ) {
+
+ error = do_catalog( (UINT32)-1L, (UINT16)-1, (UINT16)-1 );
+ VLM_CatalogSync( VLM_SYNCMORE );
+ }
+
+ return( error );
+}
+
+
+/**********************
+
+ NAME : VLM_StartBackup
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+INT VLM_StartBackup( )
+{
+ BSD_PTR bsd_ptr;
+ BSD_PTR nxt_bsd_ptr;
+ INT error = SUCCESS;
+ TCHAR bset_name[ MAX_BSET_NAME_SIZE ];
+
+ /* First, verify that the tape hardware was initialized successfully */
+
+ if ( ! HWC_TapeHWProblem( bsd_list ) ) {
+
+ VLM_RemoveUnusedBSDs( bsd_list );
+
+ bsd_ptr = BSD_GetFirst( bsd_list );
+
+ if ( bsd_ptr == NULL ) {
+ if ( CDS_GetYesFlag ( CDS_GetCopy() ) == YESYES_FLAG ) {
+ lresprintf( LOGGING_FILE, LOG_START, FALSE );
+ lresprintf( LOGGING_FILE, LOG_ERROR, (UINT) SES_ENG_ERR, RES_BACKUP_NO_SELECTIONS );
+ lresprintf( LOGGING_FILE, LOG_END );
+ } else {
+ eresprintf( RES_BACKUP_NO_SELECTIONS );
+ }
+ return( -1 );
+ }
+
+ while ( bsd_ptr != NULL ) {
+ nxt_bsd_ptr = bsd_ptr;
+ nxt_bsd_ptr = BSD_GetNext( nxt_bsd_ptr );
+ BSD_SetTapePos( bsd_ptr, (UINT32)-1L, (UINT16)-1, (UINT16)-1 );
+ BSD_SetTHW( bsd_ptr, thw_list );
+ bsd_ptr = nxt_bsd_ptr;
+ }
+
+ /* perform backup operation */
+ gb_error_during_operation = FALSE;
+
+ error = do_backup( BACKUP_OPER );
+
+ if ( error != ABNORMAL_TERMINATION ) {
+ if ( CDS_GetAutoVerifyBackup( CDS_GetCopy() ) ) {
+
+#ifdef OS_WIN32
+ bsd_ptr = BSD_GetFirst( bsd_list );
+ while ( bsd_ptr != NULL ) {
+
+ /* process security info */
+ BSD_SetProcElemOnlyFlg( bsd_ptr, FALSE );
+ if ( BSD_GetProcSpecialFlg( bsd_ptr ) ) {
+
+ UI_AddSpecialIncOrExc( bsd_ptr, FALSE ) ;
+ BSD_SetProcSpecialFlg( bsd_ptr, FALSE );
+ }
+ BEC_SetRestoreSecurity( BSD_GetConfigData( bsd_ptr ), TRUE );
+
+ bsd_ptr = BSD_GetNext( bsd_ptr );
+ }
+#endif // OS_WIN32
+
+ STM_SetIdleText ( IDS_VERIFYING );
+ do_verify( VERIFY_LAST_BACKUP_OPER );
+ }
+ BSD_ClearCurrOper( bsd_list );
+ error = SUCCESS;
+ }
+ else {
+ bsd_ptr = BSD_GetFirst( bsd_list );
+ while ( bsd_ptr != NULL ) {
+
+ /* reset the flag indicating the file was backed up */
+ BSD_ClearDelete( bsd_ptr );
+
+ bsd_ptr = BSD_GetNext( bsd_ptr );
+ }
+
+ /* if backup was canceled, remove the catalog BSD */
+ /* get name for the catalog set */
+ RSM_StringCopy( IDS_CATALOGSETNAME, bset_name, MAX_BSET_NAME_SIZE );
+
+ bsd_ptr = BSD_GetFirst( bsd_list );
+
+ while( bsd_ptr != NULL ) {
+
+ /* if this is a catalog BSD - remove from BSD list */
+ /* the Do_back routine will insert it back in the list */
+
+ /* if there was a description, check if catalog */
+ if( BSD_GetBackupDescript( bsd_ptr ) ) {
+
+ if(! strcmp( bset_name, (CHAR_PTR)BSD_GetBackupDescript( bsd_ptr ) ) ) {
+ BSD_Remove( bsd_ptr ) ;
+ break;
+ }
+ }
+
+ bsd_ptr = BSD_GetNext( bsd_ptr );
+ }
+ }
+
+ /* if the user canceled the backup - don't clear the tape window */
+
+ if( error == SUCCESS ) {
+
+ // I have no idea why this was here.
+ // VLM_ClearCurrentTape( (UINT32)0 );
+
+ }
+ VLM_CatalogSync( VLM_SYNCMORE | VLM_SYNCLESS );
+ }
+
+ return( error );
+}
+
+
+
+
+/**********************
+
+ NAME : VLM_StartVerify
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+INT VLM_StartVerify( )
+{
+ INT error;
+ BSD_PTR bsd;
+
+ if ( ! HWC_TapeHWProblem( bsd_list ) ) {
+
+ VLM_RemoveUnusedBSDs( tape_bsd_list );
+
+ bsd = BSD_GetFirst( tape_bsd_list );
+
+ if ( bsd == NULL ) {
+ eresprintf( RES_VERIFY_NO_SELECTIONS );
+ return( -1 );
+ }
+
+ if ( DM_StartVerifyBackupSet() ) {
+ error = ABORT_OPERATION;
+ }
+ else {
+ gb_error_during_operation = FALSE;
+
+ error = do_verify( VERIFY_OPER );
+ if ( error != ABNORMAL_TERMINATION ) {
+
+ BSD_ClearCurrOper( tape_bsd_list );
+ error = SUCCESS;
+ }
+ }
+
+ }
+ return( error );
+}
+
+
+
+/**********************
+
+ NAME : VLM_StartRestore
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT VLM_StartRestore( )
+{
+ INT error = SUCCESS;
+ BSD_PTR bsd;
+
+ if ( ! HWC_TapeHWProblem( bsd_list ) ) {
+
+ VLM_RemoveUnusedBSDs( tape_bsd_list );
+
+ bsd = BSD_GetFirst( tape_bsd_list );
+
+ if ( bsd == NULL ) {
+ eresprintf( RES_RESTORE_NO_SELECTIONS );
+ return( -1 );
+ }
+
+ gb_error_during_operation = FALSE;
+
+ error = do_restore( RESTORE_OPER );
+
+ if ( error != ABNORMAL_TERMINATION ) {
+ if ( CDS_GetAutoVerifyRestore( CDS_GetCopy() ) ) {
+
+ bsd = BSD_GetFirst( tape_bsd_list );
+ while ( bsd != NULL ) {
+
+ /* reset the flag indicating the file was backed up */
+ BSD_ClearDelete( bsd );
+ if ( BSD_GetProcSpecialFlg( bsd ) ) {
+
+ UI_AddSpecialIncOrExc( bsd, FALSE ) ;
+ BSD_SetProcSpecialFlg( bsd, FALSE );
+ }
+
+ bsd = BSD_GetNext( bsd ) ;
+ }
+
+ STM_SetIdleText ( IDS_VERIFYING );
+ do_verify( VERIFY_LAST_RESTORE_OPER );
+ }
+ BSD_ClearCurrOper( tape_bsd_list );
+ error = SUCCESS;
+ }
+
+ if ( !error ) {
+ FSYS_HAND fsh = NULL ;
+ GENERIC_DLE_PTR dle ;
+ INT status = FAILURE ;
+ BSD_PTR bsd ;
+
+ bsd = BSD_GetFirst( tape_bsd_list );
+ while ( bsd != NULL ) {
+
+ dle = BSD_GetDLE( bsd ) ;
+ if ( dle ) {
+ status = FS_AttachToDLE( &fsh,
+ dle,
+ BSD_GetConfigData(bsd),
+ NULL,
+ NULL ) ;
+ }
+ if ( !status ) {
+ status = FS_EndOperationOnDLE( fsh ) ;
+ }
+
+ if ( status == LP_END_OPER_FAILED ) {
+ eresprintf_cancel( RES_ERROR_EMS_RESTART, DLE_GetDeviceName( dle ) ) ;
+ gb_error_during_operation = TRUE;
+ }
+
+ if ( fsh ) {
+ FS_DetachDLE( fsh ) ;
+ }
+
+ bsd = BSD_GetNext( bsd ) ;
+ }
+ }
+ }
+ return( error );
+}
+
+
+/**********************
+
+ NAME : VLM_StartTension
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+VOID VLM_StartTension()
+{
+ INT status;
+
+ /* display the retension message dialog */
+
+ status = WM_MessageBox( (CHAR_PTR) ID( IDS_MSGTITLE_RETENSION ),
+ (CHAR_PTR) ID( RES_RETENSION_MESSAGE ),
+ (WORD) WMMB_CONTCANCEL,
+ (WORD) WMMB_ICONEXCLAMATION,
+ (CHAR_PTR) NULL,
+ (WORD) 0,
+ (WORD) HELPID_DIALOGTENSION );
+
+ if( status == WMMB_IDCONTINUE) {
+
+ lresprintf( LOGGING_FILE, LOG_END );
+
+ if ( ! HWC_TapeHWProblem( bsd_list ) ) {
+ do_tension( TENSION_OPER );
+ }
+ }
+}
+
+
+/**********************
+
+ NAME : VLM_StartErase
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+VOID VLM_StartErase()
+{
+
+ if ( ! HWC_TapeHWProblem( bsd_list ) ) {
+
+ if ( DM_StartErase () ) {
+
+ lresprintf( LOGGING_FILE, LOG_END );
+
+ if ( CDS_GetEraseFlag( CDS_GetCopy() ) == ERASE_LONG ) {
+
+ if ( CDS_GetYesFlag( CDS_GetPerm() ) == YESYES_FLAG ) {
+
+ do_tension( SEC_ERASE_NO_READ_OPER );
+ }
+ else {
+ do_tension( SECURITY_ERASE_OPER );
+ }
+
+ }
+ else {
+
+ if ( CDS_GetYesFlag( CDS_GetPerm() ) == YESYES_FLAG ) {
+
+ do_tension( ERASE_NO_READ_OPER );
+ }
+ else {
+ do_tension( ERASE_OPER );
+ }
+ }
+
+ VLM_CatalogSync( VLM_SYNCLESS );
+ }
+ }
+}
+
+#ifdef OS_WIN32
+
+/**********************
+
+ NAME : VLM_StartFormat
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+VOID VLM_StartFormat()
+{
+
+ if ( ! HWC_TapeHWProblem( bsd_list ) ) {
+
+ if ( DM_StartFormat () ) {
+
+ lresprintf( LOGGING_FILE, LOG_END );
+
+ do_tension( FORMAT_OPER );
+ VLM_CatalogSync( VLM_SYNCLESS );
+ }
+ }
+}
+#endif // OS_WIN32
+
+
+/**********************
+
+ NAME : VLM_StartTransfer
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+INT VLM_StartTransfer( )
+{
+ BSD_PTR bsd_ptr;
+ BSD_PTR nxt_bsd_ptr;
+ INT error = SUCCESS;
+ BOOLEAN make_copy = FALSE;
+ BOOLEAN delete_flag = FALSE ;
+ TCHAR bset_name[ MAX_BSET_NAME_SIZE ];
+
+
+ /* First, verify that the tape hardware was initialized successfully */
+
+ if ( ! HWC_TapeHWProblem( bsd_list ) ) {
+
+ VLM_RemoveUnusedBSDs( bsd_list );
+
+ bsd_ptr = BSD_GetFirst( bsd_list );
+
+ if ( bsd_ptr == NULL ) {
+ eresprintf( RES_ARCHIVE_NO_SELECTIONS );
+ return( -1 );
+ }
+
+ while ( bsd_ptr != NULL ) {
+ nxt_bsd_ptr = bsd_ptr;
+ nxt_bsd_ptr = BSD_GetNext( nxt_bsd_ptr );
+ BSD_SetTapePos( bsd_ptr, (UINT32)-1L, (UINT16)-1, (UINT16)-1 );
+ BSD_SetTHW( bsd_ptr, thw_list );
+ bsd_ptr = nxt_bsd_ptr;
+ }
+
+ /* perform backup operation */
+ gb_error_during_operation = FALSE;
+
+ do {
+
+ error = do_backup( ARCHIVE_BACKUP_OPER );
+
+ if ( error == SUCCESS ) {
+
+ STM_SetIdleText ( IDS_VERIFYING );
+
+ error = do_verify( ARCHIVE_VERIFY_OPER );
+
+ if ( error == SUCCESS ) {
+
+ /* if the backup and the verify operation was successful */
+ /* then set the delete flag to prompt to delete files */
+
+ delete_flag = TRUE ;
+
+ /* if the YESYES flag is set - assume this is a job */
+ /* and don't ask to make another copy */
+
+ if ( CDS_GetYesFlag( CDS_GetPerm() ) == YESYES_FLAG ) {
+ make_copy = FALSE;
+ }
+ else {
+ if ( WM_MessageBox( ID( IDS_MSGTITLE_COPY ),
+ ID( RES_WAIT_AND_REPLACE_TAPE ),
+ WMMB_YESNO,
+ WMMB_ICONQUESTION,
+ ID( RES_MAKE_ANOTHER_COPY ),
+ 0, 0 ) ) {
+#ifdef OS_WIN32
+ NtDemoChangeTape( 1u ) ;
+#endif
+
+ make_copy = TRUE;
+
+ /* Reset bsd tape position values */
+
+ bsd_ptr = BSD_GetFirst( bsd_list );
+
+ while( bsd_ptr != NULL ) {
+
+ /* reset the flag indicating the file was backed up */
+ BSD_ClearDelete( bsd_ptr );
+
+ BSD_SetTapePos( bsd_ptr, (UINT32)-1, (UINT16)-1, (UINT16)-1 );
+
+ bsd_ptr = BSD_GetNext( bsd_ptr );
+ }
+
+ /* if makeing another copy, remove the catalog BSD */
+ /* get name for the catalog set */
+ RSM_StringCopy( IDS_CATALOGSETNAME, bset_name, MAX_BSET_NAME_SIZE );
+
+ bsd_ptr = BSD_GetFirst( bsd_list );
+
+ while( bsd_ptr != NULL ) {
+
+ /* if this is a catalog BSD - remove from BSD list */
+ /* the Do_back routine will insert it back in the list */
+
+ /* if there was a description, check if catalog */
+ if( BSD_GetBackupDescript( bsd_ptr ) ) {
+
+ if(! strcmp( bset_name, (CHAR_PTR)BSD_GetBackupDescript( bsd_ptr ) ) ) {
+ BSD_Remove( bsd_ptr ) ;
+ break;
+ }
+ }
+
+ bsd_ptr = BSD_GetNext( bsd_ptr );
+ }
+ }
+ else {
+ make_copy = FALSE;
+ }
+ }
+ }
+ }
+ /* there was and error or user aborted, so remove the catalogs BSD */
+ else {
+
+ /* get name for the catalog set */
+ RSM_StringCopy( IDS_CATALOGSETNAME, bset_name, MAX_BSET_NAME_SIZE );
+
+ bsd_ptr = BSD_GetFirst( bsd_list );
+
+ while( bsd_ptr != NULL ) {
+
+ /* if this is a catalog BSD - remove from BSD list */
+ /* the Do_back routine will insert it back in the list */
+
+ /* if there was a description, check if catalog */
+ if( BSD_GetBackupDescript( bsd_ptr ) ) {
+
+ if(! strcmp( bset_name, (CHAR_PTR)BSD_GetBackupDescript( bsd_ptr ) ) ) {
+ BSD_Remove( bsd_ptr ) ;
+ break;
+ }
+ }
+
+ /* reset the flag indicating the file was backed up */
+ BSD_ClearDelete( bsd_ptr );
+
+ BSD_SetTapePos( bsd_ptr, (UINT32)-1, (UINT16)-1, (UINT16)-1 );
+
+ bsd_ptr = BSD_GetNext( bsd_ptr );
+ }
+ }
+
+ } while ( (error == SUCCESS) && make_copy );
+
+ /* the delete flag will be set if there was a successful backup */
+ /* and verify operation */
+
+ if ( delete_flag == TRUE ) {
+
+ bsd_ptr = BSD_GetFirst( bsd_list );
+
+ while( bsd_ptr != NULL ) {
+
+ /* reset the flag indicating the file was backed up */
+ BSD_ClearDelete( bsd_ptr );
+
+ bsd_ptr = BSD_GetNext( bsd_ptr );
+ }
+
+ /* Do the delete step... */
+
+# ifndef OEM_MSOFT
+ {
+ STM_SetIdleText ( IDS_DELAFTERTRANS );
+ }
+# endif
+
+ do_delete( ARCHIVE_DELETE_OPER );
+
+ BSD_ClearCurrOper( bsd_list );
+ }
+
+ VLM_CatalogSync( VLM_SYNCMORE | VLM_SYNCLESS );
+
+ }
+
+ return( error );
+}
diff --git a/private/utils/ntbackup/src/vlm_tape.c b/private/utils/ntbackup/src/vlm_tape.c
new file mode 100644
index 000000000..c68839a7b
--- /dev/null
+++ b/private/utils/ntbackup/src/vlm_tape.c
@@ -0,0 +1,1382 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: VLM_TAPE.C
+
+ Description:
+
+ This file contains most of the code for processing the TAPES
+ window and lists.
+
+ $Log: G:/UI/LOGFILES/VLM_TAPE.C_V $
+
+ Rev 1.51 03 Aug 1993 19:47:50 MARINA
+updated param type cast
+
+ Rev 1.50 28 Jul 1993 14:10:30 MARINA
+enable c++
+
+ Rev 1.49 03 May 1993 16:15:46 MIKEP
+make current tape the focus tape.
+
+ Rev 1.48 26 Apr 1993 13:28:16 MIKEP
+Update tapes window at app start up. I broke this
+with my last checkin.
+
+ Rev 1.47 26 Apr 1993 08:52:42 MIKEP
+Add numerous changes to fully support the font case selection
+for various file system types. Also add refresh for tapes window
+and sorting of tapes window.
+
+ Rev 1.46 22 Mar 1993 20:12:42 CHUCKB
+Fixed #ifdef for next_tape functionality.
+
+ Rev 1.45 20 Jan 1993 21:38:26 MIKEP
+floppy support
+
+ Rev 1.44 17 Nov 1992 21:21:08 DAVEV
+unicode fixes
+
+ Rev 1.43 17 Nov 1992 20:01:06 MIKEP
+add unformat display
+
+ Rev 1.42 11 Nov 1992 16:37:20 DAVEV
+UNICODE: remove compile warnings
+
+ Rev 1.41 01 Nov 1992 16:13:14 DAVEV
+Unicode changes
+
+ Rev 1.40 30 Oct 1992 15:46:26 GLENN
+Added Frame and MDI Doc window size and position saving and restoring.
+
+ Rev 1.39 20 Oct 1992 14:31:58 MIKEP
+changes for otc
+
+ Rev 1.38 16 Oct 1992 15:29:10 MIKEP
+Added Bitmap width and height size info to tapes window.(GLENN)
+
+ Rev 1.37 07 Oct 1992 15:06:52 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.36 04 Oct 1992 19:43:10 DAVEV
+Unicode Awk pass
+
+ Rev 1.35 02 Sep 1992 21:14:02 CHUCKB
+Put in changes from MikeP from Microsoft.
+
+ Rev 1.34 04 Aug 1992 13:02:14 GLENN
+Changed to multitape bitmap IDs.
+
+ Rev 1.33 03 Aug 1992 19:38:10 MIKEP
+multitape changes for NT
+
+ Rev 1.32 29 Jul 1992 09:50:20 MIKEP
+ChuckB checked in after NT warnings were fixed.
+
+ Rev 1.31 20 Jul 1992 09:58:26 JOHNWT
+gas gauge display work
+
+ Rev 1.30 16 Jun 1992 16:00:08 MIKEP
+fix rentrantcy problem to tape operations
+
+ Rev 1.29 01 Jun 1992 08:40:18 MIKEP
+auto catalog fix
+
+ Rev 1.28 31 May 1992 11:12:16 MIKEP
+auto catalog changes
+
+ Rev 1.27 14 May 1992 18:05:42 MIKEP
+nt pass 2
+
+ Rev 1.26 06 May 1992 14:41:16 MIKEP
+unicode pass two
+
+ Rev 1.25 04 May 1992 13:39:56 MIKEP
+unicode pass 1
+
+ Rev 1.24 09 Apr 1992 08:46:12 MIKEP
+speed up lots of sets
+
+
+*****************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+// Static local function prototypes.
+
+static BYTE VLM_TapeGetSelect( TAPE_OBJECT_PTR );
+static VOID_PTR VLM_TapeSetTag( TAPE_OBJECT_PTR, BYTE );
+static BYTE VLM_TapeGetTag( TAPE_OBJECT_PTR );
+static USHORT VLM_TapeGetItemCount( Q_HEADER_PTR );
+static VOID_PTR VLM_TapeGetFirstItem( Q_HEADER_PTR );
+static VOID_PTR VLM_TapeGetPrevItem( TAPE_OBJECT_PTR );
+static VOID_PTR VLM_TapeGetNextItem( TAPE_OBJECT_PTR );
+static VOID_PTR VLM_TapeGetObjects( TAPE_OBJECT_PTR );
+
+static VOID VLM_BuildTapeList( VOID );
+
+
+
+/*********************
+
+ Name: VLM_GetTapeName
+
+ Description: Get the name of a tape family.
+
+ Returns: Pointer to the tape name.
+
+**********************/
+
+CHAR_PTR VLM_GetTapeName(
+UINT32 tape_fid ) // I - tape fid to find
+{
+ TAPE_OBJECT_PTR tape;
+
+ tape = VLM_GetFirstTAPE( );
+
+ while ( tape != NULL ) {
+
+ if ( TAPE_GetFID( tape ) == tape_fid ) {
+
+ return( TAPE_GetName( tape ) ); // Return what they wanted
+ }
+ tape = VLM_GetNextTAPE( tape );
+ }
+
+ return( NULL );
+}
+
+
+/*********************
+
+ Name: VLM_PartializeTape
+
+ Description:
+
+ The user has asked the catalogs to partialize a tape. Now the VLM Tapes
+ window must be partialized for this tape family also.
+
+ Returns:
+
+**********************/
+
+
+VOID VLM_PartializeTape( UINT32 tape_fid )
+{
+ TAPE_OBJECT_PTR tape;
+ BSET_OBJECT_PTR bset;
+ APPINFO_PTR appinfo;
+ WININFO_PTR wininfo;
+ HWND win;
+ BSD_PTR bsd;
+
+ if ( gb_tapes_win == (HWND)NULL ) {
+ return;
+ }
+
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( gb_tapes_win );
+
+ tape = VLM_GetFirstTAPE( );
+
+ while ( tape != NULL ) {
+
+ if ( TAPE_GetFID( tape ) == tape_fid ) {
+
+ // We've found the right tape, now yank all the bsets.
+
+ bset = VLM_GetFirstBSET( &TAPE_GetBsetQueue( tape ) );
+
+ while ( bset != NULL ) {
+
+ // Remove any selections that have been made.
+
+ bsd = BSD_FindByTapeID( tape_bsd_list,
+ tape_fid,
+ BSET_GetBsetNum( bset ) );
+
+ if ( bsd != NULL ) {
+ BSD_Remove( bsd );
+ }
+
+ // Now make the icon partial.
+ // Tell the icon generator that there are no
+ // pieces that are fully cataloged.
+
+ bset->full_mask = 0;
+
+ VLM_AddBset( tape_fid, (UINT16)-1, BSET_GetBsetNum( bset ), NULL, TRUE );
+
+ bset = VLM_GetNextBSET( bset );
+ }
+
+ break;
+ }
+
+ tape = VLM_GetNextTAPE( tape );
+ }
+
+ /*
+ Remove any windows that are open from this tape family.
+ */
+
+ win = WM_GetNext( (HWND)NULL );
+
+ while ( win != (HWND)NULL ) {
+
+ wininfo = WM_GetInfoPtr( win );
+
+ if ( WMDS_GetWinType( wininfo ) == WMTYPE_TAPETREE ) {
+
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( win );
+
+ if ( appinfo->tape_fid == tape_fid ) {
+
+ WM_Destroy( win );
+ win = (HWND)NULL;
+ }
+ }
+ win = WM_GetNext( win );
+ }
+
+}
+
+
+/**********************
+
+ NAME : VLM_UpdateTapes
+
+ DESCRIPTION :
+
+ Recheck all the selection status indicators on all the bsets and tapes
+ and update the tapes window.
+
+ RETURNS : nothing.
+
+**********************/
+
+VOID VLM_UpdateTapes( )
+{
+ BSD_PTR bsd;
+ TAPE_OBJECT_PTR tape;
+ BSET_OBJECT_PTR bset;
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ UINT32 old_bset_status;
+ UINT32 new_tape_status;
+
+ wininfo = WM_GetInfoPtr( gb_tapes_win );
+
+ if ( wininfo != NULL ) {
+
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( gb_tapes_win );
+
+ tape = VLM_GetFirstTAPE( );
+
+ while ( tape != NULL ) {
+
+ new_tape_status = (UINT16)-1;
+
+ bset = VLM_GetFirstBSET( &TAPE_GetBsetQueue( tape ) );
+
+ while ( bset != NULL ) {
+
+ old_bset_status = bset->status & (UINT16)(INFO_SELECT|INFO_PARTIAL);
+ bset->status &= ~( INFO_PARTIAL | INFO_SELECT );
+
+ bsd = BSD_FindByTapeID( tape_bsd_list,
+ bset->tape_fid, bset->bset_num );
+
+ if ( bsd != NULL ) { // not likely, but possible nonetheless
+
+ switch ( BSD_GetMarkStatus( bsd ) ) {
+
+ case ALL_SELECTED:
+ bset->status |= INFO_SELECT;
+ break;
+
+ case SOME_SELECTED:
+ bset->status |= (INFO_SELECT|INFO_PARTIAL);
+ break;
+
+ default:
+ break;
+ }
+
+ }
+
+ if ( new_tape_status == (UINT16)-1 ) {
+ new_tape_status = bset->status & (UINT16)(INFO_SELECT|INFO_PARTIAL);
+ }
+ else {
+
+ if ( ( new_tape_status & (INFO_SELECT|INFO_PARTIAL) ) !=
+ ( bset->status & (INFO_SELECT|INFO_PARTIAL) ) ) {
+
+ new_tape_status |= (INFO_PARTIAL | INFO_SELECT);
+ }
+ }
+
+
+// if ( ( bset->status & INFO_SELECT ) &&
+// CDS_GetEnableStatsFlag ( CDS_GetPerm () ) ) {
+//
+// check for a non-open (displayed) bset here, if you find one -
+// this is a problem, we have a selection (most likely partial) and no
+// SLM list to match it against to get totals
+//
+// }
+
+
+ if ( tape == appinfo->open_tape ) {
+
+ if ( old_bset_status != (UINT16)(bset->status & (INFO_SELECT|INFO_PARTIAL) ) ) {
+
+ DLM_Update( gb_tapes_win,
+ DLM_FLATLISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)bset, 0 );
+ }
+ }
+
+ bset = VLM_GetNextBSET( bset );
+ }
+
+ if ( new_tape_status != (UINT16)(tape->status & (INFO_SELECT|INFO_PARTIAL) ) ) {
+
+ tape->status &= ~(INFO_SELECT|INFO_PARTIAL);
+
+ if ( ! tape->fake_tape ) {
+ tape->status |= new_tape_status;
+ }
+
+ DLM_Update( gb_tapes_win,
+ DLM_TREELISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)tape, 0 );
+ }
+
+ tape = VLM_GetNextTAPE( tape );
+ }
+
+ }
+
+}
+
+
+/*********************
+
+ Name: VLM_UpdateTapeStatus
+
+ Description:
+
+ Make the tape's selection box match the selection boces of its bsets.
+ Make it red if all bsets are red, clear if all bsets are clear, otherwise
+ make it gray.
+
+ Returns: nothing.
+
+**********************/
+
+
+VOID VLM_UpdateTapeStatus(
+TAPE_OBJECT_PTR tape, // I - Tape to update
+BOOLEAN UpdateScreen )
+{
+ UINT16 status = 0;
+ BSET_OBJECT_PTR bset;
+
+ bset = VLM_GetFirstBSET( &TAPE_GetBsetQueue( tape ) );
+
+ if ( bset == NULL ) {
+
+ // This tape has no known bsets !, Can't happen, except fake tapes.
+ return;
+ }
+
+ if ( BSET_GetStatus( bset ) & INFO_PARTIAL ) {
+ status = 1;
+ }
+ else {
+ if ( BSET_GetStatus( bset ) & INFO_SELECT ) {
+ status = 2;
+ }
+ }
+
+ while ( ( bset != NULL ) && ( status != 1 ) ) {
+
+ if ( BSET_GetStatus( bset ) & INFO_PARTIAL ) {
+ status = 1;
+ }
+ else {
+ if ( ( BSET_GetStatus( bset ) & INFO_SELECT ) &&
+ ( status == 0 ) ) {
+ status = 1;
+ }
+ if ( ! ( BSET_GetStatus( bset ) & INFO_SELECT ) &&
+ ( status == 2 ) ) {
+ status = 1;
+ }
+ }
+
+ bset = VLM_GetNextBSET( bset );
+ }
+
+ // Update tape selection status
+
+ switch ( status ) {
+ case 0:
+ status = 0;
+ break;
+ case 1:
+ status = (INFO_SELECT|INFO_PARTIAL);
+ break;
+ case 2:
+ status = INFO_SELECT;
+ break;
+ }
+
+ // Update screen
+
+ if ( ((UINT16)( TAPE_GetStatus( tape ) & (INFO_SELECT|INFO_PARTIAL) )) != status ) {
+
+ TAPE_SetStatus( tape, TAPE_GetStatus( tape ) & (UINT16)~(INFO_SELECT|INFO_PARTIAL) );
+ TAPE_SetStatus( tape, TAPE_GetStatus( tape ) | status );
+
+ if ( UpdateScreen ) {
+ DLM_Update( gb_tapes_win,
+ DLM_TREELISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)tape, 0 );
+ }
+ }
+}
+
+
+
+/*********************
+
+ Name: VLM_ClearAllTapeSelections
+
+ Description:
+
+ Clear all the check boxes for all the tapes, and free thier BSD's.
+
+ Returns:
+
+**********************/
+
+
+VOID VLM_ClearAllTapeSelections( )
+{
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ TAPE_OBJECT_PTR tape;
+ BSET_OBJECT_PTR bset;
+
+ if ( gb_tapes_win != (HWND)NULL ) {
+
+ wininfo = WM_GetInfoPtr( gb_tapes_win );
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( gb_tapes_win );
+
+ tape = VLM_GetFirstTAPE( );
+
+ while ( tape != NULL ) {
+
+ if ( TAPE_GetStatus( tape ) & (INFO_SELECT|INFO_PARTIAL) ) {
+
+ TAPE_SetStatus( tape, tape->status & (UINT16)~(INFO_PARTIAL|INFO_SELECT) );
+ bset = VLM_GetFirstBSET( &TAPE_GetBsetQueue( tape ) );
+
+ while ( bset != NULL ) {
+
+ if ( BSET_GetStatus( bset ) & (INFO_SELECT|INFO_PARTIAL) ) {
+
+ BSET_SetStatus( bset, bset->status & (UINT16)~(INFO_SELECT|INFO_PARTIAL) );
+
+ if ( tape == appinfo->open_tape ) {
+
+ DLM_Update( gb_tapes_win,
+ DLM_FLATLISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)bset, 0 );
+ }
+ }
+
+ bset = VLM_GetNextBSET( bset );
+ }
+
+ DLM_Update( gb_tapes_win, DLM_TREELISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)tape, 0 );
+ }
+ tape = VLM_GetNextTAPE( tape );
+ }
+ }
+}
+
+
+/*********************
+
+ Name: VLM_RemoveTape
+
+ Description:
+
+ A tape has been removed, through catalog maintenance or overwriting
+ a tape. This function is called to remove all references to the tape from
+ the VLM area. It will close any windows that happen to be open from this
+ tape, remove any BSD's, and call the search code to delete any references
+ to this tape in the search results window.
+
+ Returns:
+
+****************/
+
+VOID VLM_RemoveTape( UINT32 tape_fid, INT16 tape_num, BOOLEAN UpdateScreen )
+{
+ BSET_OBJECT_PTR bset;
+ BSET_OBJECT_PTR temp_bset;
+ TAPE_OBJECT_PTR tape;
+ APPINFO_PTR appinfo;
+ WININFO_PTR wininfo;
+ BSD_PTR bsd;
+ APPINFO_PTR temp_appinfo;
+ WININFO_PTR temp_wininfo;
+ HWND win;
+
+ // See if tapes window has been created yet !
+
+ if ( gb_tapes_win == (HWND)NULL ) {
+ return;
+ }
+
+ wininfo = WM_GetInfoPtr( gb_tapes_win );
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( gb_tapes_win );
+
+ // Find the right tape in list
+
+ tape = VLM_GetFirstTAPE( );
+
+ while ( tape != NULL ) {
+
+ if ( TAPE_GetFID( tape ) == tape_fid ) {
+ break;
+ }
+ tape = VLM_GetNextTAPE( tape );
+ }
+
+ if ( tape == NULL ) {
+ return;
+ }
+
+ // Free each backup set that this tape had.
+
+ bset = VLM_GetFirstBSET( &TAPE_GetBsetQueue( tape ) );
+
+ while ( bset != NULL ) {
+
+ temp_bset = bset;
+
+ bset = VLM_GetNextBSET( bset );
+
+ if ( ( ( BSET_GetTapeNum( temp_bset ) <= tape_num ) &&
+ ( temp_bset->tape_num + temp_bset->num_tapes > tape_num ) ) ||
+ ( tape_num == -1 ) ) {
+
+ // Remove the bsd from the tape_bsd_list for this tape
+
+ bsd = BSD_FindByTapeID( tape_bsd_list,
+ tape_fid,
+ BSET_GetBsetNum( temp_bset ) );
+
+ if ( bsd != NULL ) {
+ BSD_Remove( bsd );
+ }
+
+ RemoveQueueElem( &TAPE_GetBsetQueue( tape ), &(temp_bset->q_elem) );
+ free( temp_bset );
+
+ }
+ }
+
+ // If any windows are open for this tape then close them
+
+ win = WM_GetNext( (HWND)NULL );
+
+ while ( win != (HWND)NULL ) {
+
+ temp_wininfo = WM_GetInfoPtr( win );
+
+ if ( WMDS_GetWinType( temp_wininfo ) == WMTYPE_TAPETREE ) {
+
+ temp_appinfo = ( APPINFO_PTR )WM_GetAppPtr( win );
+
+ if ( ( temp_appinfo->tape_fid == tape_fid ) &&
+ ( ( temp_appinfo->tape_num == tape_num ) ||
+ ( tape_num == -1 ) ) ) {
+
+ WM_Destroy( win );
+ win = (HWND)NULL;
+ }
+ }
+ win = WM_GetNext( win );
+ }
+
+ // See if the reference to this tape can be removed also.
+
+ if ( QueueCount( &TAPE_GetBsetQueue( tape ) ) == 0 ) {
+
+ RemoveQueueElem( WMDS_GetTreeList( wininfo ), &(tape->q_elem) );
+
+ // See if the tape being removed is the currently open one.
+
+ if ( appinfo->open_tape == tape ) {
+
+ appinfo->open_tape = VLM_GetFirstTAPE( );
+
+ if ( appinfo->open_tape != NULL ) {
+ appinfo->open_tape->status |= INFO_OPEN;
+ WMDS_SetFlatList( wininfo, &TAPE_GetBsetQueue( appinfo->open_tape ) );
+ }
+ else {
+ WMDS_SetFlatList( wininfo, NULL );
+ }
+ }
+
+ free( tape );
+ }
+
+ // Update both lists on the screen
+
+ if ( UpdateScreen ) {
+
+ DLM_Update( gb_tapes_win,
+ DLM_TREELISTBOX,
+ WM_DLMUPDATELIST,
+ (LMHANDLE)WMDS_GetTreeList( wininfo ), 0 );
+
+ DLM_Update( gb_tapes_win,
+ DLM_FLATLISTBOX,
+ WM_DLMUPDATELIST,
+ (LMHANDLE)WMDS_GetFlatList( wininfo ), 0 );
+ }
+
+ // Remove any search results entries from this tape.
+
+ VLM_SearchRemoveSet( tape_fid, (INT16)-1 );
+}
+
+
+/**********************
+
+ NAME : VLM_GetFirstTAPE
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+TAPE_OBJECT_PTR VLM_GetFirstTAPE( )
+{
+ Q_ELEM_PTR q_elem_ptr;
+ WININFO_PTR wininfo;
+
+ if ( gb_tapes_win == (HWND)NULL ) {
+ return( NULL );
+ }
+
+ wininfo = WM_GetInfoPtr( gb_tapes_win );
+
+ q_elem_ptr = QueueHead( WMDS_GetTreeList( wininfo ) );
+
+ if ( q_elem_ptr != NULL ) {
+ return ( TAPE_OBJECT_PTR )( q_elem_ptr->q_ptr );
+ }
+ return( NULL );
+}
+
+
+/**********************
+
+ NAME : VLM_GetNextTAPE
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+TAPE_OBJECT_PTR VLM_GetNextTAPE( TAPE_OBJECT_PTR tape_ptr )
+{
+ Q_ELEM_PTR q_elem_ptr;
+
+ q_elem_ptr = QueueNext( &(tape_ptr->q_elem) );
+
+ if ( q_elem_ptr != NULL ) {
+ return ( TAPE_OBJECT_PTR )( q_elem_ptr->q_ptr );
+ }
+ return( NULL );
+}
+
+/**********************
+
+ NAME : VLM_GetPrevTAPE
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+TAPE_OBJECT_PTR VLM_GetPrevTAPE( TAPE_OBJECT_PTR tape_ptr )
+{
+ Q_ELEM_PTR q_elem_ptr;
+
+ q_elem_ptr = QueuePrev( &(tape_ptr->q_elem) );
+
+ if ( q_elem_ptr != NULL ) {
+ return ( TAPE_OBJECT_PTR )( q_elem_ptr->q_ptr );
+ }
+ return( NULL );
+}
+
+/**********************
+
+ NAME : VLM_CreateTAPE
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+TAPE_OBJECT_PTR VLM_CreateTAPE( INT16 name_size )
+{
+ TAPE_OBJECT_PTR tape;
+
+ tape = ( TAPE_OBJECT_PTR )malloc( sizeof(TAPE_OBJECT) + name_size );
+
+ if ( tape != NULL ) {
+ InitQueue( &tape->bset_list );
+ tape->name = (CHAR_PTR)(((INT8_PTR)tape) + sizeof(TAPE_OBJECT));
+ tape->q_elem.q_ptr = tape;
+ }
+
+ return( tape );
+}
+
+
+
+/**********************
+
+ NAME : VLM_BuildTapeList
+
+ DESCRIPTION :
+
+ The app has just started and we need to initialize the tape/bset list
+ by asking the catalogs what tapes/bsets they know about.
+
+ RETURNS :
+
+**********************/
+
+static VOID VLM_BuildTapeList( )
+{
+ QTC_TAPE_PTR tape;
+ QTC_BSET_PTR bset;
+
+ // Ask the catalogs for a list of tapes and bsets
+
+ tape = QTC_GetFirstTape();
+
+ while ( tape != NULL ) {
+
+ bset = QTC_GetFirstBset( tape );
+
+ while ( bset != NULL ) {
+
+ VLM_AddBset( bset->tape_fid,
+ (INT16)bset->tape_seq_num,
+ (INT16)bset->bset_num,
+ bset, FALSE );
+
+ bset = QTC_GetNextBset( bset );
+ }
+
+ tape = QTC_GetNextTape( tape );
+ }
+}
+
+/**********************
+
+ NAME : VLM_TapesListCreate
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+BOOLEAN VLM_TapesListCreate( )
+{
+ DLM_INIT tree_dlm;
+ DLM_INIT flat_dlm;
+ Q_HEADER_PTR tape_list;
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ CHAR title[ MAX_UI_RESOURCE_SIZE ];
+ INT nWidth;
+ INT nHeight;
+ CDS_PTR pCDS = CDS_GetPerm ();
+
+
+ appinfo = ( APPINFO_PTR )calloc( sizeof( APPINFO ), 1 );
+ wininfo = (WININFO_PTR)calloc( sizeof(WININFO), 1 );
+
+ // initialize tape list queue
+
+ tape_list = (Q_HEADER_PTR)calloc( sizeof(Q_HEADER), 1 );
+
+ if ( tape_list == NULL ) {
+ return( FAILURE );
+ }
+
+ InitQueue( tape_list );
+
+ // Fill in wininfo data structure.
+
+ WMDS_SetWinType ( wininfo, WMTYPE_TAPES );
+ WMDS_SetCursor ( wininfo, RSM_CursorLoad( IDRC_HSLIDER ) );
+ WMDS_SetDragCursor ( wininfo, 0 );
+ WMDS_SetIcon ( wininfo, RSM_IconLoad( IDRI_TAPES ) );
+ WMDS_SetWinHelpID ( wininfo, 0 );
+ WMDS_SetStatusLineID ( wininfo, 0 );
+ WMDS_SetRibbonState ( wininfo, 0 );
+ WMDS_SetMenuState ( wininfo, 0 );
+ WMDS_SetRibbon ( wininfo, NULL );
+ WMDS_SetTreeList ( wininfo, tape_list );
+ WMDS_SetFlatList ( wininfo, NULL );
+ WMDS_SetTreeDisp ( wininfo, NULL );
+ WMDS_SetFlatDisp ( wininfo, NULL );
+ WMDS_SetAppInfo ( wininfo, appinfo );
+ WMDS_SetSliderPos ( wininfo, CDS_GetTapeInfo ( pCDS ).nSliderPos );
+
+ // Fill in and init the display list structure.
+
+ DLM_ListBoxType( &tree_dlm, DLM_TREELISTBOX );
+ DLM_Mode( &tree_dlm, DLM_HIERARCHICAL );
+ DLM_Display( &tree_dlm, DLM_SMALL_BITMAPS );
+ DLM_DispHdr( &tree_dlm, tape_list );
+ DLM_TextFont( &tree_dlm, DLM_SYSTEM_FONT );
+ DLM_GetItemCount( &tree_dlm, VLM_TapeGetItemCount );
+ DLM_GetFirstItem( &tree_dlm, VLM_TapeGetFirstItem );
+ DLM_GetNext( &tree_dlm, VLM_TapeGetNextItem );
+ DLM_GetPrev( &tree_dlm, VLM_TapeGetPrevItem );
+ DLM_GetTag( &tree_dlm, VLM_TapeGetTag );
+ DLM_SetTag( &tree_dlm, VLM_TapeSetTag );
+ DLM_GetSelect( &tree_dlm, VLM_TapeGetSelect );
+ DLM_SetSelect( &tree_dlm, VLM_TapeSetSelect );
+ DLM_GetObjects( &tree_dlm, VLM_TapeGetObjects );
+ DLM_SetObjects( &tree_dlm, VLM_TapeSetObjects );
+ DLM_SSetItemFocus( &tree_dlm, NULL );
+ DLM_MaxNumObjects( &tree_dlm, 6 );
+
+ DLM_DispListInit( wininfo, &tree_dlm );
+
+ if ( ! RSM_GetBitmapSize( IDRBM_TAPES, ( LPINT )&nWidth, ( LPINT )&nHeight ) ) {
+
+ DLM_SetBitMapWidth ( WMDS_GetTreeDisp ( wininfo ), (USHORT) nWidth ) ;
+ DLM_SetBitMapHeight( WMDS_GetTreeDisp ( wininfo ), (USHORT) nHeight ) ;
+
+ }
+
+ VLM_BsetFillInDLM( &flat_dlm );
+
+ DLM_DispListInit( wininfo, &flat_dlm );
+
+ if ( ! RSM_GetBitmapSize( IDRBM_BSET, ( LPINT )&nWidth, ( LPINT )&nHeight ) ) {
+
+ DLM_SetBitMapWidth ( WMDS_GetFlatDisp ( wininfo ), (USHORT) nWidth ) ;
+ DLM_SetBitMapHeight( WMDS_GetFlatDisp ( wininfo ), (USHORT) nHeight ) ;
+
+ }
+
+ // open a new window
+
+ RSM_StringCopy( IDS_VLMTAPETITLE, title, MAX_UI_RESOURCE_LEN );
+
+ gb_tapes_win = WM_Create( (WORD)(WM_MDIPRIMARY | WM_TREELIST |
+ WM_MIN |
+ WM_FLATLISTSC | (WORD)CDS_GetTapeInfo ( pCDS ).nSize),
+ title,
+ NULL,
+ (INT)CDS_GetTapeInfo ( pCDS ).x,
+ (INT)CDS_GetTapeInfo ( pCDS ).y,
+ (INT)CDS_GetTapeInfo ( pCDS ).cx,
+ (INT)CDS_GetTapeInfo ( pCDS ).cy,
+ wininfo );
+
+
+ if ( gb_tapes_win == (HWND)NULL ) {
+ return( FAILURE );
+ }
+
+ appinfo->win = gb_tapes_win;
+ appinfo->open_tape = NULL;
+
+ DLM_DispListProc( wininfo->hWndTreeList, 0, NULL );
+ DLM_DispListProc( wininfo->hWndFlatList, 0, NULL );
+
+ // You can't add the new bsets until the window is created.
+
+ VLM_BuildTapeList( );
+
+ DLM_Update( gb_tapes_win,
+ DLM_TREELISTBOX,
+ WM_DLMUPDATELIST,
+ (LMHANDLE)wininfo->pTreeList, 0 );
+
+ DLM_Update( gb_tapes_win,
+ DLM_FLATLISTBOX,
+ WM_DLMUPDATELIST,
+ (LMHANDLE)wininfo->pFlatList, 0 );
+
+ // Set the anchor item.
+
+ DLM_SetAnchor( WMDS_GetWinTreeList( wininfo ),
+ 0,
+ (LMHANDLE)appinfo->open_tape );
+
+
+ return( SUCCESS );
+}
+
+
+/**********************
+
+ NAME : VLM_TapeSetSelect
+
+ DESCRIPTION :
+
+ Callback function for Display Manager. To set select status of drive.
+
+ RETURNS :
+
+**********************/
+
+VOID_PTR VLM_TapeSetSelect( TAPE_OBJECT_PTR tape, BYTE attr )
+{
+ BSET_OBJECT_PTR bset;
+
+ // Check to see if the user tried to select a "BLANK" or "FOREIGN" tape.
+
+ if ( tape->fake_tape ) {
+ return( NULL );
+ }
+
+ // Add code to backup up this whole tape here
+
+ bset = VLM_GetFirstBSET( &tape->bset_list );
+
+ while ( bset != NULL ) {
+
+ if ( attr ) {
+
+ if ( PSWD_CheckForPassword( bset->tape_fid, bset->bset_num ) ) {
+ break;
+ }
+ }
+
+ VLM_BsetSetSelect( bset, attr );
+
+ bset = VLM_GetNextBSET( bset );
+ }
+
+ // Update the search window
+
+ VLM_UpdateSearchSelections( tape->tape_fid, (INT16)-1 );
+ return ( NULL ) ;
+
+}
+
+/**********************
+
+ NAME : VLM_TapeGetSelect
+
+ DESCRIPTION :
+
+ Get the selection status for the Display Manager.
+
+ RETURNS :
+
+**********************/
+
+static BYTE VLM_TapeGetSelect( TAPE_OBJECT_PTR tape )
+{
+ if ( tape->status & INFO_SELECT ) {
+ return( 1 );
+ }
+ else {
+ return( 0 );
+ }
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static VOID_PTR VLM_TapeSetTag( TAPE_OBJECT_PTR tape, BYTE attr )
+{
+ if ( attr ) {
+ tape->status |= INFO_TAGGED;
+ }
+ else {
+ tape->status &= ~INFO_TAGGED;
+ }
+
+ return( NULL );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static BYTE VLM_TapeGetTag( TAPE_OBJECT_PTR tape )
+{
+ if ( INFO_TAGGED & tape->status ) {
+ return( 1 );
+ }
+ else {
+ return( 0 );
+ }
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static USHORT VLM_TapeGetItemCount( Q_HEADER_PTR tape_list )
+{
+ return( QueueCount( tape_list ) );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static VOID_PTR VLM_TapeGetFirstItem( Q_HEADER_PTR tape_list )
+{
+ DBG_UNREFERENCED_PARAMETER (tape_list);
+
+ return( (VOID_PTR)VLM_GetFirstTAPE( ) );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static VOID_PTR VLM_TapeGetPrevItem( TAPE_OBJECT_PTR tape )
+{
+ tape = VLM_GetPrevTAPE( tape );
+
+ return( (VOID_PTR)tape );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static VOID_PTR VLM_TapeGetNextItem( TAPE_OBJECT_PTR tape )
+{
+ tape = VLM_GetNextTAPE( tape );
+
+ return( (VOID_PTR)tape );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static VOID_PTR VLM_TapeGetObjects( TAPE_OBJECT_PTR tape )
+{
+ BYTE_PTR memblk;
+ DLM_ITEM_PTR item;
+ WININFO_PTR wininfo;
+
+ /* malloc enough room to store info */
+
+ wininfo = WM_GetInfoPtr( gb_tapes_win );
+ memblk = ( BYTE_PTR )DLM_GetObjectsBuffer( wininfo->hWndTreeList );
+
+ /* Store the number of items in the first two bytes. */
+
+ *memblk = 3;
+
+ /* Set up check box. */
+
+ item = (DLM_ITEM_PTR)( memblk + 6 );
+
+ DLM_ItemcbNum( item ) = 1;
+ DLM_ItembType( item ) = DLM_CHECKBOX;
+ if ( tape->status & INFO_SELECT ) {
+ DLM_ItemwId( item ) = IDRBM_SEL_ALL;
+ if ( tape->status & INFO_PARTIAL ) {
+ DLM_ItemwId( item ) = IDRBM_SEL_PART;
+ }
+ }
+ else {
+ DLM_ItemwId( item ) = IDRBM_SEL_NONE;
+ }
+ DLM_ItembMaxTextLen( item ) = 0;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+
+ /* Set up Bitmap, ie. Floppy, Hard, Network. */
+
+ item++;
+ DLM_ItemcbNum( item ) = 2;
+ DLM_ItembType( item ) = DLM_BITMAP;
+
+
+ if ( TAPE_GetIsFloppy( tape ) ) {
+ if ( tape->current ) {
+ if ( TAPE_GetMultiTape( tape ) ) {
+ DLM_ItemwId( item ) = IDRBM_FLOPPYSINDRIVE;
+ }
+ else {
+ DLM_ItemwId( item ) = IDRBM_FLOPPYINDRIVE;
+ }
+ }
+ else {
+ if ( TAPE_GetMultiTape( tape ) ) {
+ DLM_ItemwId( item ) = IDRBM_FLOPPYS;
+ }
+ else {
+ DLM_ItemwId( item ) = IDRBM_FLOPPY;
+ }
+ }
+ }
+ else {
+ if ( tape->current ) {
+ if ( TAPE_GetMultiTape( tape ) ) {
+ DLM_ItemwId( item ) = IDRBM_TAPESINDRIVE;
+ }
+ else {
+ DLM_ItemwId( item ) = IDRBM_TAPEINDRIVE;
+ }
+ }
+ else {
+ if ( TAPE_GetMultiTape( tape ) ) {
+ DLM_ItemwId( item ) = IDRBM_TAPES;
+ }
+ else {
+ DLM_ItemwId( item ) = IDRBM_TAPE;
+ }
+ }
+ }
+
+
+
+ DLM_ItembMaxTextLen( item ) = 0;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+
+ /* Set up the text string to be displayed. */
+
+ item++;
+ DLM_ItemcbNum( item ) = 3;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = (UINT8)(strlen( tape->name ) + 1);
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+ strcpy( (CHAR_PTR)DLM_ItemqszString( item ), (CHAR_PTR)tape->name);
+
+ return( memblk );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+BOOLEAN VLM_TapeSetObjects(
+TAPE_OBJECT_PTR tape,
+WORD operation,
+WORD ObjectNum )
+{
+ APPINFO_PTR appinfo;
+ WININFO_PTR wininfo;
+ TAPE_OBJECT_PTR temp_tape;
+ CHAR keyb_char;
+ BOOLEAN ret_val = FALSE;
+
+
+ if ( operation == WM_DLMCHAR ) {
+
+ keyb_char = (CHAR)ObjectNum;
+
+ keyb_char = (CHAR)toupper( keyb_char );
+
+ temp_tape = tape;
+
+ do {
+
+ temp_tape = VLM_GetNextTAPE( temp_tape );
+
+ if ( temp_tape != NULL ) {
+
+ if ( keyb_char == (CHAR)toupper( *TAPE_GetName( temp_tape ) ) ) {
+
+ DLM_SetAnchor( WMDS_GetWinTreeList( TAPE_GetXtraBytes( temp_tape ) ),
+ 0,
+ (LMHANDLE)temp_tape );
+ operation = WM_DLMDBCLK;
+ ObjectNum = 2;
+ ret_val = TRUE;
+ break;
+ }
+ }
+
+ } while ( temp_tape != NULL );
+
+ temp_tape = VLM_GetFirstTAPE( );
+
+ while ( temp_tape != NULL && temp_tape != tape && ret_val != TRUE ) {
+
+ if ( keyb_char == (CHAR)toupper( *TAPE_GetName( temp_tape ) ) ) {
+
+ DLM_SetAnchor( WMDS_GetWinTreeList( TAPE_GetXtraBytes( temp_tape ) ),
+ 0,
+ (LMHANDLE)temp_tape );
+ operation = WM_DLMDOWN;
+ ObjectNum = 2;
+ ret_val = TRUE;
+ break;
+ }
+
+ temp_tape = VLM_GetNextTAPE( temp_tape );
+ }
+
+ if ( ret_val != TRUE ) {
+
+ DLM_SetAnchor( WMDS_GetWinTreeList( TAPE_GetXtraBytes( tape ) ),
+ 0,
+ (LMHANDLE)tape );
+ }
+ }
+
+ if ( ( operation == WM_DLMDBCLK || operation == WM_DLMDOWN ) &&
+ ( ObjectNum >= 2 ) ) {
+
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( gb_tapes_win );
+ wininfo = WM_GetInfoPtr( gb_tapes_win );
+
+ if ( tape != appinfo->open_tape ) {
+
+ if ( appinfo->open_tape != NULL ) {
+ appinfo->open_tape->status &= ~INFO_OPEN;
+ DLM_Update( gb_tapes_win, DLM_TREELISTBOX, WM_DLMUPDATEITEM,
+ (LMHANDLE)appinfo->open_tape, 0 );
+ }
+ appinfo->open_tape = tape;
+ tape->status |= INFO_OPEN;
+
+ DLM_Update( gb_tapes_win, DLM_TREELISTBOX, WM_DLMUPDATEITEM,
+ (LMHANDLE)appinfo->open_tape, 0 );
+
+ wininfo->pFlatList = &tape->bset_list;
+
+ DLM_Update( gb_tapes_win, DLM_FLATLISTBOX, WM_DLMUPDATELIST,
+ (LMHANDLE)&tape->bset_list, 0 );
+ }
+
+ if ( ( operation == WM_DLMDBCLK ) && ( TAPE_GetCurrent( tape ) ) &&
+ ( ! tape->fake_tape ) ) {
+
+# if !defined( OS_WIN32 )
+ if ( ! MUI_DisableOperations( IDM_OPERATIONSCATALOG ) ) {
+
+ if ( ! HWC_TapeHWProblem( bsd_list ) ) {
+
+ DM_StartNextSet( );
+ }
+
+ MUI_EnableOperations( IDM_OPERATIONSCATALOG );
+ }
+# else
+ if ( ! MUI_DisableOperations( 0 ) ) {
+
+ if ( ! HWC_TapeHWProblem( bsd_list ) ) {
+
+ STM_SetIdleText( IDS_CATALOGING );
+
+ VLM_StartCatalog( );
+
+ STM_SetIdleText( IDS_READY );
+
+ MUI_EnableOperations( 0 );
+ }
+ }
+# endif
+ }
+ }
+
+ return( ret_val );
+}
+
diff --git a/private/utils/ntbackup/src/vlm_tree.c b/private/utils/ntbackup/src/vlm_tree.c
new file mode 100644
index 000000000..fb05d5671
--- /dev/null
+++ b/private/utils/ntbackup/src/vlm_tree.c
@@ -0,0 +1,3830 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: VLM_TREE.C
+
+ Description:
+ This code handles the hierarchical directory list and processes most of
+ the commands sent to it. The same code is used for DISK and TAPE trees.
+
+ $Log: G:\ui\logfiles\vlm_tree.c_v $
+
+ Rev 1.75.1.5 21 Mar 1994 12:42:00 STEVEN
+change title from device error to something better
+
+ Rev 1.75.1.4 25 Jan 1994 08:41:30 MIKEP
+fix warnings in orcas
+
+ Rev 1.75.1.3 14 Jan 1994 14:36:34 MIKEP
+fix refresh and up arrow display
+
+ Rev 1.75.1.2 14 Dec 1993 15:25:10 GREGG
+Go deeper!!!
+
+ Rev 1.75.1.1 08 Dec 1993 10:50:46 MikeP
+very deep path support
+
+ Rev 1.75 18 Aug 1993 15:00:26 STEVEN
+fix unicode bug
+
+ Rev 1.74 28 Jul 1993 15:00:24 MARINA
+enable c++
+
+ Rev 1.73 27 Jul 1993 23:20:28 MIKEP
+fix access denied handling
+
+ Rev 1.72 24 Jul 1993 15:18:14 GLENN
+Fixed list creation type.
+
+ Rev 1.71 23 Jul 1993 17:21:36 MIKEP
+fix ; missing
+
+ Rev 1.70 23 Jul 1993 15:41:08 MIKEP
+handle error return codes from file system.
+
+*****************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+// functions local to this source file
+
+static INT VLM_BuildDirList( Q_HEADER_PTR, WININFO_PTR );
+static VOID VLM_BuildTapeDirList( Q_HEADER_PTR, UINT32, INT16, WININFO_PTR );
+static VOID VLM_InsertTapeSLM( Q_HEADER_PTR, SLM_OBJECT_PTR, SLM_OBJECT_PTR );
+static VOID VLM_InsertDiskSLM( Q_HEADER_PTR, SLM_OBJECT_PTR, SLM_OBJECT_PTR, SLM_OBJECT_PTR );
+static CHAR_PTR VLM_ReplaceEntry( CHAR_PTR, INT *, CHAR_PTR, INT );
+static INT VLM_MatchSLM( SLM_OBJECT_PTR, BSD_PTR );
+
+// Display manager call backs
+
+static VOID_PTR VLM_SlmSetSelect( SLM_OBJECT_PTR, BYTE );
+static BYTE VLM_SlmGetSelect( SLM_OBJECT_PTR );
+static VOID_PTR VLM_SlmSetTag( SLM_OBJECT_PTR, BYTE );
+static BYTE VLM_SlmGetTag( SLM_OBJECT_PTR );
+static USHORT VLM_SlmGetItemCount( Q_HEADER_PTR );
+static VOID_PTR VLM_SlmGetFirstItem( Q_HEADER_PTR );
+static VOID_PTR VLM_SlmGetPrevItem( SLM_OBJECT_PTR );
+static VOID_PTR VLM_SlmGetNextItem( SLM_OBJECT_PTR );
+static VOID_PTR VLM_SlmGetObjects( SLM_OBJECT_PTR );
+static BOOLEAN VLM_SlmSetObjects( SLM_OBJECT_PTR, WORD, WORD );
+
+
+
+
+
+/**********************
+
+ NAME : VLM_PrevBrotherDir
+
+ DESCRIPTION :
+
+ User hit CTRL-Up Arrow, go to previous brother.
+
+ RETURNS : nothing
+
+**********************/
+
+VOID VLM_PrevBrotherDir( HWND win )
+{
+ SLM_OBJECT_PTR old_slm;
+ SLM_OBJECT_PTR new_slm;
+ WININFO_PTR wininfo;
+
+ wininfo = WM_GetInfoPtr( win );
+
+ // Get the active directory slm.
+
+ old_slm = ( SLM_OBJECT_PTR )DLM_GetFocusItem( wininfo->hWndTreeList );
+
+ if ( old_slm == NULL ) {
+ return;
+ }
+
+ // Try to find a previous brother and make him active directory.
+
+ new_slm = VLM_GetPrevSLM( old_slm );
+
+ while ( new_slm != NULL ) {
+
+ if ( SLM_GetLevel( new_slm ) < SLM_GetLevel( old_slm ) ) {
+
+ // No previous brother.
+ break;
+ }
+
+ if ( SLM_GetLevel( new_slm ) == SLM_GetLevel( old_slm ) ) {
+
+ SLM_SetStatus( old_slm, old_slm->status & (UINT16)~INFO_TAGGED );
+ SLM_SetStatus( new_slm, new_slm->status | (UINT16)INFO_TAGGED );
+
+ DLM_SetAnchor( WMDS_GetWinTreeList( wininfo ),
+ 0,
+ (LMHANDLE)new_slm );
+
+ // Fake a single click call to make this guy active.
+ VLM_SlmSetObjects( new_slm, WM_DLMDOWN, 2 );
+ break;
+ }
+
+ new_slm = VLM_GetPrevSLM( new_slm );
+ }
+
+}
+/**********************
+
+ NAME : VLM_NextBrotherDir
+
+ DESCRIPTION :
+
+ User hit Ctrl-Down Arrow. Go to next brother down the tree.
+
+ RETURNS : nothing
+
+**********************/
+
+VOID VLM_NextBrotherDir( HWND win )
+{
+ SLM_OBJECT_PTR old_slm;
+ SLM_OBJECT_PTR new_slm;
+ WININFO_PTR wininfo;
+
+ wininfo = WM_GetInfoPtr( win );
+
+ // get the active directory slm.
+
+ old_slm = ( SLM_OBJECT_PTR )DLM_GetFocusItem( wininfo->hWndTreeList );
+
+ if ( old_slm == NULL ) {
+ return;
+ }
+
+ // Get his next brother.
+
+ new_slm = old_slm->next_brother;
+
+ if ( new_slm != NULL ) {
+
+ SLM_SetStatus( old_slm, old_slm->status & (UINT16)~INFO_TAGGED );
+ SLM_SetStatus( new_slm, new_slm->status | (UINT16)INFO_TAGGED );
+
+ // Make him the active item.
+
+ DLM_SetAnchor( WMDS_GetWinTreeList( wininfo ),
+ 0,
+ (LMHANDLE)new_slm );
+
+ // Fake a single click message to myself.
+
+ VLM_SlmSetObjects( new_slm, WM_DLMDOWN, 2 );
+ }
+
+}
+
+/**********************
+
+ NAME : VLM_DownOneDir
+
+ DESCRIPTION :
+
+ Move down the tree one level deeper to the active directories first
+ child, if there is one.
+
+ RETURNS : nothing
+
+**********************/
+
+VOID VLM_DownOneDir( HWND win )
+{
+ SLM_OBJECT_PTR old_slm;
+ SLM_OBJECT_PTR new_slm;
+ SLM_OBJECT_PTR temp_slm;
+ Q_HEADER_PTR slm_list;
+ WININFO_PTR wininfo;
+ INT count = 0;
+
+ wininfo = WM_GetInfoPtr( win );
+
+ slm_list = WMDS_GetTreeList( wininfo );
+
+ // Get active directory slm.
+
+ old_slm = ( SLM_OBJECT_PTR )DLM_GetFocusItem( wininfo->hWndTreeList );
+
+ if ( old_slm == NULL ) {
+ return;
+ }
+
+ if ( ! ( SLM_GetStatus( old_slm ) & INFO_SUBS ) ) {
+
+ // The guy has no subs.
+ return;
+ }
+
+ WM_ShowWaitCursor( TRUE );
+
+ // check to make sure this dir has been blown out
+
+ VLM_BlowOutDir( old_slm );
+
+ old_slm->status |= INFO_EXPAND;
+
+ // now set the subdirs to DISPLAY
+
+ temp_slm = VLM_GetNextSLM( old_slm );
+
+ while ( temp_slm &&
+ ( temp_slm->level == old_slm->level + 1 ) ) {
+
+ if ( ! ( temp_slm->status & INFO_DISPLAY ) ) {
+
+ count++;
+ temp_slm->status |= INFO_DISPLAY;
+ }
+
+ temp_slm = temp_slm->next_brother;
+ }
+
+ STM_DrawIdle();
+
+ if ( count ) {
+ VLM_UpdateBrothers( slm_list );
+
+ DLM_Update( win, DLM_TREELISTBOX, WM_DLMADDITEMS,
+ (LMHANDLE)old_slm, (USHORT)count );
+ }
+
+ WM_ShowWaitCursor( FALSE );
+
+ // Now make the first child active.
+
+ new_slm = VLM_GetNextSLM( old_slm );
+
+ while ( new_slm != NULL ) {
+
+ if ( SLM_GetLevel( new_slm ) <= SLM_GetLevel( old_slm ) ) {
+ break;
+ }
+
+ if ( SLM_GetLevel( new_slm ) == SLM_GetLevel( old_slm ) + 1 ) {
+
+ // We've found the right one.
+
+ SLM_SetStatus( old_slm, old_slm->status & (UINT16)~INFO_TAGGED );
+ SLM_SetStatus( new_slm, new_slm->status | (UINT16)INFO_TAGGED );
+
+ DLM_SetAnchor( WMDS_GetWinTreeList( wininfo ),
+ 0,
+ (LMHANDLE)new_slm );
+
+ // Fake a single click message to myself.
+
+ VLM_SlmSetObjects( new_slm, WM_DLMDOWN, 2 );
+ break;
+ }
+
+ new_slm = VLM_GetNextSLM( new_slm );
+ }
+
+}
+
+
+/**********************
+
+ NAME : VLM_BlowOutDir
+
+ DESCRIPTION :
+
+ Blow out a dir without displaying it.
+
+ RETURNS : nothing
+
+**********************/
+
+VOID VLM_BlowOutDir( SLM_OBJECT_PTR slm )
+{
+ WININFO_PTR wininfo;
+ CHAR *new_path;
+
+
+ // if he has no subs or he has already been blown-out, return
+
+ if ( ( ! ( SLM_GetStatus( slm ) & INFO_SUBS ) ) ||
+ ( SLM_GetStatus( slm ) & INFO_EXPAND ) ||
+ ( SLM_GetStatus( slm ) & INFO_VALID ) ) {
+ return;
+ }
+
+ wininfo = SLM_GetXtraBytes( slm );
+
+ new_path = VLM_BuildPath( slm );
+
+ if ( VLM_CheckForChildren( WMDS_GetTreeList( wininfo ),
+ slm,
+ new_path,
+ 1, // <- depth to look
+ FALSE) ) {
+
+ slm->status |= INFO_SUBS;
+ }
+
+ slm->status |= INFO_VALID;
+
+ free( new_path );
+}
+
+
+/**********************
+
+ NAME : VLM_UpOneDir
+
+ DESCRIPTION :
+
+ Make the parent of the active directory the active directory.
+
+ RETURNS : nothing
+
+**********************/
+
+VOID VLM_UpOneDir( HWND win )
+{
+ SLM_OBJECT_PTR old_slm;
+ SLM_OBJECT_PTR new_slm;
+ WININFO_PTR wininfo;
+
+ wininfo = WM_GetInfoPtr( win );
+
+ old_slm = ( SLM_OBJECT_PTR )DLM_GetFocusItem( wininfo->hWndTreeList );
+
+ if ( old_slm == NULL ) {
+ return;
+ }
+
+ new_slm = VLM_GetPrevSLM( old_slm );
+
+ while ( new_slm != NULL ) {
+
+ if ( SLM_GetLevel( new_slm ) == SLM_GetLevel( old_slm ) - 1 ) {
+
+ SLM_SetStatus( old_slm, old_slm->status & (UINT16)~INFO_TAGGED );
+ SLM_SetStatus( new_slm, new_slm->status | (UINT16)INFO_TAGGED );
+
+ DLM_SetAnchor( WMDS_GetWinTreeList( wininfo ),
+ 0,
+ (LMHANDLE)new_slm );
+
+ VLM_SlmSetObjects( new_slm, WM_DLMDOWN, 2 );
+ break;
+ }
+
+ new_slm = VLM_GetPrevSLM( new_slm );
+ }
+
+}
+
+
+
+/**********************
+
+ NAME : VLM_ExpandTree
+
+ DESCRIPTION :
+
+ Blow out the whole tree of subdirectories.
+ A fairly simple process, go through the list and mark everything as
+ displayed, expanded, and valid. Of course any ~valid items will need
+ to be checked for child subdirectories.
+
+ RETURNS : nothing.
+
+**********************/
+
+VOID VLM_ExpandTree( HWND win )
+{
+
+ Q_HEADER_PTR slm_list;
+ SLM_OBJECT_PTR slm;
+ SLM_OBJECT_PTR focus_slm;
+ WININFO_PTR wininfo;
+ CHAR *path;
+
+
+ wininfo = WM_GetInfoPtr( win );
+
+ if ( ( WMDS_GetWinType( wininfo ) != WMTYPE_DISKTREE ) &&
+ ( WMDS_GetWinType( wininfo ) != WMTYPE_TAPETREE ) ) {
+
+ // The menu screwed up, we shouldn't have been called.
+
+ return;
+ }
+
+ focus_slm = ( SLM_OBJECT_PTR )DLM_GetFocusItem( wininfo->hWndTreeList );
+
+ slm_list = WMDS_GetTreeList( wininfo );
+
+ slm = VLM_GetFirstSLM( slm_list );
+
+ while ( slm != NULL ) {
+
+ // Do branch processing.
+
+ do {
+
+ if ( ! ( SLM_GetStatus( slm ) & INFO_VALID ) ) {
+
+ path = VLM_BuildPath( slm );
+
+ if ( VLM_CheckForChildren( slm_list, slm,
+ path,
+ 1, FALSE ) ) {
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) | (UINT16)INFO_SUBS );
+ }
+
+ free( path );
+ }
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) | (UINT16)(INFO_DISPLAY | INFO_EXPAND | INFO_VALID) );
+
+ slm = VLM_GetNextSLM( slm );
+
+ } while ( slm != NULL && SLM_GetLevel( slm ) > 1 );
+
+ // Find next level 1
+
+ while ( slm && ( SLM_GetLevel ( slm ) != 1 ) ) {
+ slm = VLM_GetNextSLM( slm );
+ }
+ }
+
+ STM_SetIdleText( IDS_READY );
+
+ // Update where the lines go down the left side of screen
+
+ VLM_UpdateBrothers( slm_list );
+
+ // Update the directory window display
+
+ DLM_Update( win, DLM_TREELISTBOX, WM_DLMUPDATELIST, NULL, 0 );
+
+ DLM_SetAnchor( WMDS_GetWinTreeList( wininfo ), 0, (LMHANDLE)focus_slm );
+
+ return;
+
+}
+
+
+/**********************
+
+ NAME : VLM_CollapseBranch
+
+ DESCRIPTION :
+
+ Collapse a single branch on the tree and undisplay it.
+ Until you hit a brother at the same level or the end of the list, mark
+ all items as undisplayed and unexpanded.
+
+ RETURNS : nothing.
+
+**********************/
+
+VOID VLM_CollapseBranch( HWND win )
+{
+ INT level;
+ WININFO_PTR wininfo;
+ SLM_OBJECT_PTR slm;
+ SLM_OBJECT_PTR focus_slm;
+
+
+ wininfo = WM_GetInfoPtr( win );
+
+ if ( ( WMDS_GetWinType( wininfo ) != WMTYPE_DISKTREE ) &&
+ ( WMDS_GetWinType( wininfo ) != WMTYPE_TAPETREE )
+ ) {
+
+ // The menu screwed up, we shouldn't have been called.
+
+ return;
+ }
+
+ focus_slm = ( SLM_OBJECT_PTR )DLM_GetFocusItem( wininfo->hWndTreeList );
+
+ slm = focus_slm;
+
+ if ( slm == NULL ) {
+ return;
+ }
+
+ if ( ! ( SLM_GetStatus( slm ) & INFO_EXPAND ) ) {
+ return;
+ }
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) & (UINT16)~INFO_EXPAND );
+
+ level = SLM_GetLevel( slm );
+
+ slm = VLM_GetNextSLM( slm );
+
+ if ( slm != NULL ) {
+
+ do {
+
+ if ( SLM_GetLevel( slm ) <= level ) {
+ break;
+ }
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) & (UINT16)~(INFO_DISPLAY | INFO_EXPAND) );
+
+ slm = VLM_GetNextSLM( slm );
+
+ } while ( slm != NULL );
+ }
+
+ // Redisplay the new list on the screen
+
+ DLM_Update( win, DLM_TREELISTBOX, WM_DLMUPDATELIST, NULL, 0 );
+ DLM_SetAnchor( WMDS_GetWinTreeList( wininfo ), 0, (LMHANDLE)focus_slm );
+}
+
+/**********************
+
+ NAME : VLM_ExpandBranch
+
+ DESCRIPTION :
+
+ Display an entire branch on a tree, after finding any children that
+ we don't know about yet. Stop the process when you hit a brother
+ at the same level or the end of the list.
+
+ RETURNS : nothing.
+
+**********************/
+
+VOID VLM_ExpandBranch( HWND win )
+{
+ Q_HEADER_PTR slm_list;
+ SLM_OBJECT_PTR slm;
+ SLM_OBJECT_PTR focus_slm;
+ WININFO_PTR wininfo;
+ CHAR *path;
+ INT level;
+
+ wininfo = WM_GetInfoPtr( win );
+
+ if ( ( WMDS_GetWinType( wininfo ) != WMTYPE_DISKTREE ) &&
+ ( WMDS_GetWinType( wininfo ) != WMTYPE_TAPETREE )
+ ) {
+
+ // The menu screwed up, we shouldn't have been called.
+
+ return;
+ }
+
+ focus_slm = ( SLM_OBJECT_PTR )DLM_GetFocusItem( wininfo->hWndTreeList );
+
+ slm_list = WMDS_GetTreeList( wininfo );
+
+ // Look for the tagged directory
+
+ slm = focus_slm;
+
+ if ( slm == NULL ) { // This should never happen !
+ return;
+ }
+
+ level = SLM_GetLevel( slm ); // Save the level to stop at
+
+ WM_ShowWaitCursor( TRUE );
+
+ do {
+
+ if ( ! ( SLM_GetStatus( slm ) & INFO_VALID ) ) {
+
+ path = VLM_BuildPath( slm );
+
+ if ( VLM_CheckForChildren( slm_list, slm,
+ path,
+ 10000, FALSE ) ) {
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) | (UINT16)INFO_SUBS );
+ }
+
+ free( path );
+ }
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) | (UINT16)(INFO_DISPLAY | INFO_EXPAND | INFO_VALID) );
+
+ slm = VLM_GetNextSLM( slm );
+
+ } while ( slm != NULL && SLM_GetLevel( slm ) > level );
+
+ // Update where the lines on the screen go for subdirectories
+
+ VLM_UpdateBrothers( slm_list );
+
+ WM_ShowWaitCursor( FALSE );
+
+ // Update the screen
+
+ DLM_Update( win, DLM_TREELISTBOX, WM_DLMUPDATELIST, NULL, 0 );
+ DLM_SetAnchor( WMDS_GetWinTreeList( wininfo ), 0, (LMHANDLE)focus_slm );
+
+ STM_SetIdleText( IDS_READY );
+}
+
+/**********************
+
+ NAME : VLM_ExpandOne
+
+ DESCRIPTION :
+
+ Expand current branch one level deeper.
+
+ RETURNS : nothing.
+
+**********************/
+
+VOID VLM_ExpandOne( HWND win )
+{
+ Q_HEADER_PTR slm_list;
+ SLM_OBJECT_PTR slm;
+ SLM_OBJECT_PTR focus_slm;
+ WININFO_PTR wininfo;
+ CHAR *path;
+ INT level;
+
+ wininfo = WM_GetInfoPtr( win );
+
+ if ( ( WMDS_GetWinType( wininfo ) != WMTYPE_DISKTREE ) &&
+ ( WMDS_GetWinType( wininfo ) != WMTYPE_TAPETREE )
+ ) {
+
+ // The menu screwed up, we shouldn't have been called.
+
+ return;
+ }
+
+ slm_list = WMDS_GetTreeList( wininfo );
+
+ // look for current branch
+
+ focus_slm = ( SLM_OBJECT_PTR )DLM_GetFocusItem( wininfo->hWndTreeList );
+
+ slm = focus_slm;
+
+ if ( slm == NULL ) {
+ return;
+ }
+ // Is it already expanded ?
+
+ if ( SLM_GetStatus( slm ) & INFO_EXPAND ) {
+ return;
+ }
+
+ // Expand it
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) | (UINT16)INFO_EXPAND );
+
+ level = SLM_GetLevel( slm ); // Save starting/stopping level
+
+ WM_ShowWaitCursor( TRUE );
+
+ do {
+
+ if ( ! ( SLM_GetStatus( slm ) & INFO_VALID ) ) {
+
+ if ( ( SLM_GetLevel( slm ) <= level + 1 ) ) {
+
+ path = VLM_BuildPath( slm );
+
+ if ( VLM_CheckForChildren( slm_list, slm,
+ path,
+ 1, // <- depth to look
+ FALSE ) ) {
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) | (UINT16)INFO_SUBS );
+ }
+
+ free( path );
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) | (UINT16)INFO_VALID );
+ }
+ }
+
+ if ( SLM_GetLevel( slm ) == level + 1 ) {
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) | (UINT16)INFO_DISPLAY );
+ }
+
+ slm = VLM_GetNextSLM( slm );
+
+ } while ( slm != NULL && SLM_GetLevel( slm ) > level );
+
+ // Update the lines again
+
+ VLM_UpdateBrothers( slm_list );
+
+ // Update the actual screen display
+
+ DLM_Update( win, DLM_TREELISTBOX, WM_DLMUPDATELIST, NULL, 0 );
+ DLM_SetAnchor( WMDS_GetWinTreeList( wininfo ), 0, (LMHANDLE)focus_slm );
+
+ STM_SetIdleText( IDS_READY );
+ WM_ShowWaitCursor( FALSE );
+}
+
+/**********************
+
+ NAME : VLM_SelectTree
+
+ DESCRIPTION :
+
+ The user has selected one or more files and directories that were
+ displayed in a disk or tape tree window. And then he hit the select
+ or deselect button. This function does the work.
+
+ RETURNS : nothing.
+
+**********************/
+
+VOID VLM_SelectTree(
+HWND win, // I - Tree window
+BYTE attr ) // I - select or deselect ?
+{
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+
+ wininfo = WM_GetInfoPtr( win );
+
+ // See which side of the window was active.
+
+ if ( WM_IsFlatActive( wininfo ) ) {
+
+ VLM_SelectFiles( win, attr );
+ }
+
+ if ( WM_IsTreeActive( wininfo ) ) {
+
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( win );
+
+ VLM_SlmSetSelect( appinfo->open_slm, attr );
+ }
+}
+
+
+/**********************
+
+ NAME : VLM_ClearAllTreeSelections
+
+ DESCRIPTION :
+
+ Run through all the windows clearing all the checkboxes in TREE
+ windows.
+
+ RETURNS : nothing.
+
+**********************/
+
+VOID VLM_ClearAllTreeSelections( )
+{
+ HWND win;
+ WININFO_PTR wininfo;
+
+ win = WM_GetNext( (HWND) NULL );
+
+ while ( win != (HWND)NULL ) {
+
+ wininfo = WM_GetInfoPtr( win );
+
+ if ( ( WMDS_GetWinType( wininfo ) == WMTYPE_DISKTREE ) ||
+ ( WMDS_GetWinType( wininfo ) == WMTYPE_TAPETREE ) ) {
+
+ VLM_DeselectAll( wininfo, TRUE );
+
+ }
+
+ win = WM_GetNext( win );
+ }
+
+}
+
+/***************************************************
+
+ Name: VLM_GetFirstSLM
+
+ Description:
+
+ A function to return the first slm entry from an slm queue.
+ Which must ALWAYS be the root.
+
+*****************************************************/
+
+SLM_OBJECT_PTR VLM_GetFirstSLM(
+Q_HEADER_PTR qhdr ) // I - Queue header to work on
+{
+ Q_ELEM_PTR q_elem_ptr;
+
+ if ( qhdr != NULL ) {
+
+ q_elem_ptr = QueueHead( qhdr );
+
+ if ( q_elem_ptr != NULL ) {
+ return ( SLM_OBJECT_PTR )( q_elem_ptr->q_ptr );
+ }
+ }
+ return( NULL );
+}
+
+/***************************************************
+
+ Name: VLM_GetLastSLM
+
+ Description:
+
+ A function to return the last slm entry from an slm queue.
+
+*****************************************************/
+
+SLM_OBJECT_PTR VLM_GetLastSLM(
+Q_HEADER_PTR qhdr ) // I - queue header to work on
+{
+ Q_ELEM_PTR q_elem_ptr;
+
+ q_elem_ptr = QueueTail( qhdr );
+
+ if ( q_elem_ptr != NULL ) {
+ return ( SLM_OBJECT_PTR )( q_elem_ptr->q_ptr );
+ }
+
+ return( NULL );
+}
+
+/***************************************************
+
+ Name: VLM_GetNextSLM
+
+ Description:
+
+ A function to return the next slm entry from an slm queue.
+
+*****************************************************/
+
+SLM_OBJECT_PTR VLM_GetNextSLM(
+SLM_OBJECT_PTR slm_ptr ) // I - current slm
+{
+ Q_ELEM_PTR q_elem_ptr;
+
+ q_elem_ptr = QueueNext( &(slm_ptr->q_elem) );
+
+ if ( q_elem_ptr != NULL ) {
+ return ( SLM_OBJECT_PTR )( q_elem_ptr->q_ptr );
+ }
+
+ return( NULL );
+}
+
+/***************************************************
+
+ Name: VLM_GetPrevSLM
+
+ Description:
+
+ A function to return the prev slm entry from an slm queue.
+
+*****************************************************/
+
+SLM_OBJECT_PTR VLM_GetPrevSLM(
+SLM_OBJECT_PTR slm_ptr ) // I - current slm
+{
+ Q_ELEM_PTR q_elem_ptr;
+
+ q_elem_ptr = QueuePrev( &(slm_ptr->q_elem) );
+
+ if ( q_elem_ptr != NULL ) {
+ return ( SLM_OBJECT_PTR )( q_elem_ptr->q_ptr );
+ }
+
+ return( NULL );
+}
+
+
+/***************************************************
+
+ Name: VLM_GetParentSLM
+
+ Description:
+
+ A function to return the parent slm entry for an slm entry.
+
+ This function can be dropped when parent pointers are put
+ in the slm entries.
+
+*****************************************************/
+
+SLM_OBJECT_PTR VLM_GetParentSLM(
+SLM_OBJECT_PTR slm_ptr ) // I - current slm
+{
+ SLM_OBJECT_PTR parent_ptr;
+
+ parent_ptr = VLM_GetPrevSLM( slm_ptr );
+
+ while ( parent_ptr &&
+ ( parent_ptr->level >= slm_ptr->level ) ) {
+
+ parent_ptr = VLM_GetPrevSLM( parent_ptr );
+ }
+
+ return( parent_ptr );
+}
+
+
+/***************************************************
+
+ Name: VLM_SubdirListCreate
+
+ Description:
+
+ A function to create a new subdirectory display window. It can be
+ called by the disks, tapes, or servers subsystem. If it's from
+ the tape subsystem then the dle parameter will be NULL. If it's
+ not from a TAPE, then check the parent to see if DISK or SERVER.
+
+*****************************************************/
+
+INT VLM_SubdirListCreate(
+GENERIC_DLE_PTR dle, // I - dle
+UINT32 tape_fid, // I - tape family
+INT16 bset_num, // I - bset number
+INT16 tape_num, // I - tape number in family
+HWND parent ) // I - parent window
+{
+ WININFO_PTR wininfo;
+ DLM_INIT tree_dlm;
+ DLM_INIT flat_dlm;
+ Q_HEADER_PTR slm_list;
+ Q_HEADER_PTR flm_list;
+ APPINFO_PTR appinfo;
+
+ CHAR path[ VLM_BUFFER_SIZE ]; // these should all survive deep pathes and unicode
+ CHAR win_title[ VLM_BUFFER_SIZE ]; // because they are only used on the create call,
+
+ QTC_BSET_PTR bset;
+ BSD_PTR bsd_ptr;
+ BYTE bMode;
+ WORD wDocListTypes;
+
+ // set up the app info stuff for this new window
+
+ appinfo = ( APPINFO_PTR )malloc( sizeof( APPINFO ) );
+ wininfo = ( WININFO_PTR )malloc( sizeof( WININFO ) );
+ slm_list = ( Q_HEADER_PTR )malloc( sizeof(Q_HEADER) );
+ flm_list = ( Q_HEADER_PTR )malloc( sizeof(Q_HEADER) );
+
+ if ( ( appinfo == NULL ) || ( wininfo == NULL ) ||
+ ( slm_list == NULL ) || ( flm_list == NULL ) ) {
+
+ goto failure;
+ }
+
+ appinfo->parent = parent;
+ appinfo->dle = dle;
+ appinfo->tape_fid = tape_fid;
+ appinfo->bset_num = bset_num;
+ appinfo->tape_num = tape_num;
+ appinfo->fsh = NULL;
+
+
+ if ( dle != NULL ) {
+
+ if ( UI_AttachDrive( &(appinfo->fsh), dle, FALSE ) ) {
+
+ goto failure;
+ }
+
+ if ( ! DLE_HasFeatures( appinfo->dle, DLE_FEAT_CASE_PRESERVING ) ) {
+ appinfo->fFatDrive = TRUE;
+ }
+ else {
+ appinfo->fFatDrive = FALSE;
+ }
+
+ DLE_GetVolName( dle, path );
+
+ if ( path[ strlen( path ) - 1 ] != TEXT(':') ) {
+ strcat( path, TEXT(":") );
+ }
+
+ sprintf( win_title, TEXT("%s"), path );
+
+ }
+ else {
+
+ bset = QTC_FindBset( tape_fid, tape_num, bset_num );
+
+ if ( bset != NULL ) {
+
+ if ( bset->status & QTC_FATDRIVE ) {
+ appinfo->fFatDrive = TRUE;
+ }
+ else {
+ appinfo->fFatDrive = FALSE;
+ }
+ }
+
+ wsprintf( win_title, TEXT("%s-%s:"), VLM_GetTapeName( tape_fid ),
+ VLM_GetBsetName( tape_fid, bset_num ) );
+ }
+
+ // initialize directory and file list queues
+
+ InitQueue( slm_list );
+ InitQueue( flm_list );
+
+ // fill in wininfo structure
+
+ if ( dle != NULL ) {
+ WMDS_SetWinType( wininfo, WMTYPE_DISKTREE );
+ }
+ else {
+ WMDS_SetWinType( wininfo, WMTYPE_TAPETREE );
+ }
+
+ WMDS_SetCursor( wininfo, RSM_CursorLoad( IDRC_HSLIDER ) );
+ WMDS_SetDragCursor( wininfo, 0 );
+ WMDS_SetIcon( wininfo, RSM_IconLoad( IDRI_TREEFILE ) );
+ WMDS_SetWinHelpID( wininfo, 0 );
+ WMDS_SetStatusLineID( wininfo, 0 );
+ WMDS_SetRibbonState( wininfo, 0 );
+ WMDS_SetRibbon( wininfo, NULL );
+ WMDS_SetTreeList( wininfo, slm_list );
+ WMDS_SetFlatList( wininfo, flm_list );
+ WMDS_SetTreeDisp( wininfo, NULL );
+ WMDS_SetFlatDisp( wininfo, NULL );
+ WMDS_SetAppInfo( wininfo, appinfo );
+
+ // Set up the menus state stuff.
+
+ {
+ CDS_PTR pCDS = CDS_GetPerm ();
+ DWORD dwTemp = 0;
+
+ // Set up the last known file detail option.
+
+ switch ( CDS_GetFileDetails ( pCDS ) ) {
+
+ case CDS_DISABLE:
+ dwTemp |= MMDOC_NAMEONLY;
+ bMode = DLM_COLUMN_VECTOR;
+ wDocListTypes = WM_TREEANDFLATMC;
+ break;
+
+ case CDS_ENABLE:
+ dwTemp |= MMDOC_FILEDETAILS;
+ bMode = DLM_SINGLECOLUMN;
+ wDocListTypes = WM_TREEANDFLATSC;
+ break;
+ }
+
+ // Set up the last known sort option.
+
+ switch ( CDS_GetSortOptions ( pCDS ) ) {
+
+ case ID_SORTNAME:
+ dwTemp |= MMDOC_SORTNAME;
+ break;
+
+ case ID_SORTTYPE:
+ dwTemp |= MMDOC_SORTTYPE;
+ break;
+
+ case ID_SORTSIZE:
+ dwTemp |= MMDOC_SORTSIZE;
+ break;
+
+ case ID_SORTDATE:
+ dwTemp |= MMDOC_SORTDATE;
+ break;
+ }
+
+ WMDS_SetMenuState( wininfo, MMDOC_TREEANDDIR | dwTemp );
+ }
+
+ // Fill in directory and file queues
+
+ strcpy( path, win_title );
+ strcat( path, TEXT("\\*.*") );
+
+ if ( dle != NULL ) {
+
+
+ VLM_BuildDirList( slm_list, wininfo );
+
+ VLM_HandleFSError( VLM_BuildFileList( appinfo->fsh, win_title,
+ flm_list, wininfo ) );
+
+ }
+ else {
+
+ VLM_BuildTapeDirList( slm_list, tape_fid, bset_num, wininfo );
+
+ bsd_ptr = BSD_FindByTapeID( tape_bsd_list, tape_fid, bset_num );
+
+ if ( bsd_ptr != NULL ) {
+ VLM_MatchSLMList( wininfo, bsd_ptr, FALSE );
+ }
+
+ VLM_BuildTapeFileList( win_title, flm_list, tape_fid, bset_num, wininfo );
+ }
+
+ if ( ! QueueCount( slm_list ) ) {
+
+ // We ran into problems, probably out of memory.
+ // Don't display window.
+
+ goto failure;
+ }
+
+ appinfo->open_slm = VLM_GetFirstSLM( slm_list );
+
+ // Init the display list stuff
+
+ DLM_ListBoxType( &tree_dlm, DLM_TREELISTBOX );
+ DLM_Mode( &tree_dlm, DLM_HIERARCHICAL );
+ DLM_Display( &tree_dlm, DLM_SMALL_BITMAPS );
+ DLM_DispHdr( &tree_dlm, slm_list );
+ DLM_TextFont( &tree_dlm, DLM_SYSTEM_FONT );
+ DLM_GetItemCount( &tree_dlm, VLM_SlmGetItemCount );
+ DLM_GetFirstItem( &tree_dlm, VLM_SlmGetFirstItem );
+ DLM_GetNext( &tree_dlm, VLM_SlmGetNextItem );
+ DLM_GetPrev( &tree_dlm, VLM_SlmGetPrevItem );
+ DLM_GetTag( &tree_dlm, VLM_SlmGetTag );
+ DLM_SetTag( &tree_dlm, VLM_SlmSetTag );
+ DLM_GetSelect( &tree_dlm, VLM_SlmGetSelect );
+ DLM_SetSelect( &tree_dlm, VLM_SlmSetSelect );
+ DLM_GetObjects( &tree_dlm, VLM_SlmGetObjects );
+ DLM_SetObjects( &tree_dlm, VLM_SlmSetObjects );
+ DLM_SSetItemFocus( &tree_dlm, NULL );
+
+ // Tell the DLM what the maximum number of objects we will display
+ // per item is.
+
+ DLM_MaxNumObjects( &tree_dlm, 6 );
+
+ DLM_DispListInit( wininfo, &tree_dlm );
+
+ DLM_ListBoxType( &flat_dlm, DLM_FLATLISTBOX );
+ DLM_Mode( &flat_dlm, bMode );
+ DLM_Display( &flat_dlm, DLM_SMALL_BITMAPS );
+ DLM_DispHdr( &flat_dlm, flm_list );
+ DLM_TextFont( &flat_dlm, DLM_SYSTEM_FONT );
+ VLM_FlmFillInDLM( &flat_dlm );
+
+ DLM_DispListInit( wininfo, &flat_dlm );
+
+
+ // open a new window
+
+
+ appinfo->win = WM_Create( (WORD)(WM_MDISECONDARY | wDocListTypes | WM_MENUS),
+ path,
+ win_title,
+ WM_DEFAULT, WM_DEFAULT,
+ WM_DEFAULT, WM_DEFAULT,
+ wininfo );
+
+ if ( appinfo->win == (HWND)NULL ) {
+ goto failure;
+ }
+
+ DLM_DispListProc( WMDS_GetWinTreeList( wininfo ), 0, NULL );
+ DLM_DispListProc( WMDS_GetWinFlatList( wininfo ), 0, NULL );
+
+ return( SUCCESS );
+
+failure:
+
+ if ( appinfo ) {
+ if ( appinfo->fsh ) {
+ FS_DetachDLE( appinfo->fsh );
+ }
+ }
+ free( appinfo );
+ free( wininfo );
+ free( slm_list );
+ free( flm_list );
+ return( FAILURE );
+
+}
+
+
+/***************************************************
+
+ Name: VLM_SubdirListManager
+
+ Description:
+
+ A function that other systems can call if they wish to select all
+ or none of a directory/file window. Usually this is called when
+ the user selects an entire drive/bset/volume and it has a window
+ already open displaying the dirs/files.
+
+*****************************************************/
+
+VOID VLM_SubdirListManager(
+HWND win, // I - window to work on
+WORD msg ) // I - message of what to do
+{
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ SLM_OBJECT_PTR slm;
+ BOOL all_subdirs;
+
+ all_subdirs = CDS_GetIncludeSubdirs( CDS_GetPerm() );
+
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( win );
+
+ if ( msg == SLM_SEL_ALL ) {
+
+ wininfo = WM_GetInfoPtr( win );
+
+ slm = VLM_GetFirstSLM( WMDS_GetTreeList( wininfo ) );
+
+ if ( ! all_subdirs ) {
+
+ // make the root partial
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) | (UINT16)(INFO_SELECT|INFO_PARTIAL) );
+
+ if ( SLM_GetStatus( slm ) & INFO_OPEN ) {
+ VLM_FileListManager( appinfo->win, FLM_SEL_ALL );
+ }
+
+ DLM_Update( win, DLM_TREELISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)slm, 0 );
+ }
+ else {
+
+ while ( slm != NULL ) {
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) | (UINT16)INFO_SELECT );
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) & (UINT16)~INFO_PARTIAL );
+
+ slm = VLM_GetNextSLM( slm );
+ }
+ VLM_FileListManager( appinfo->win, FLM_SEL_ALL );
+ DLM_Update( win, DLM_TREELISTBOX, WM_DLMUPDATELIST, NULL, 0 );
+ }
+
+ }
+
+ if ( msg == SLM_SEL_NONE ) {
+
+ wininfo = WM_GetInfoPtr( win );
+ slm = VLM_GetFirstSLM( WMDS_GetTreeList( wininfo ) );
+
+ while ( slm != NULL ) {
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) & (UINT16)~(INFO_SELECT | INFO_PARTIAL) );
+
+ slm = VLM_GetNextSLM( slm );
+ }
+
+ DLM_Update( win, DLM_TREELISTBOX, WM_DLMUPDATELIST, NULL, 0 );
+ VLM_FileListManager( appinfo->win, FLM_SEL_NONE );
+ }
+
+}
+
+/***************************************************
+
+ Name: VLM_BuildTapeDirList
+
+ Description:
+
+ Called to fill out a queue of directories so that a new directory
+ display window can be created. It will grab the whole list of
+ directories from the catalogs. This is slightly
+ different from the similar function that builds a list of dirs off
+ a disk.
+
+*****************************************************/
+
+static VOID VLM_BuildTapeDirList(
+Q_HEADER_PTR slm_list, // I - queue header to fill in
+UINT32 tape_fid, // I - tape to get info from
+INT16 bset_num, // I - bset to get info from
+WININFO_PTR XtraBytes ) // I - pointer to windows xtra bytes
+{
+ INT16 count = 0;
+ INT16 result;
+ INT16 i;
+ INT path_size = 0; // sizeof 'path' buffer in bytes
+ INT path_length; // length of the path in the buffer
+ INT level;
+ INT fLowerCase;
+ INT dir_count = 0;
+ INT BytesNeeded;
+ DATE_TIME mdate;
+ QTC_QUERY_PTR query;
+ SLM_OBJECT_PTR prev_slm = NULL;
+ SLM_OBJECT_PTR temp_slm;
+ SLM_OBJECT_PTR slm;
+ CHAR text[ MAX_UI_RESOURCE_SIZE ];
+ CHAR format_string[ MAX_UI_RESOURCE_SIZE ];
+ CHAR *path = NULL;
+ CHAR_PTR s;
+ APPINFO_PTR appinfo;
+
+
+ appinfo = ( APPINFO_PTR )XtraBytes->pAppInfo;
+
+ RSM_StringCopy( IDS_DIRSCANNED, format_string, MAX_UI_RESOURCE_LEN );
+
+ query = QTC_InitQuery( );
+ if ( query == NULL ) {
+ return;
+ }
+
+ QTC_SetTapeFID( query, tape_fid );
+ QTC_SetTapeSeq( query, -1 );
+ QTC_SetBsetNum( query, bset_num );
+
+ result = (INT16) QTC_GetFirstDir( query );
+
+ // Another one of those things that should never happen ...
+
+ if ( result ) {
+ QTC_CloseQuery( query );
+ return;
+ }
+
+ fLowerCase = FALSE;
+
+ if ( CDS_GetFontCase( CDS_GetPerm() ) ) {
+ fLowerCase = TRUE;
+ }
+ else {
+
+ if ( appinfo->fFatDrive && CDS_GetFontCase( CDS_GetPerm() ) ) {
+
+ fLowerCase = TRUE;
+ }
+ }
+
+ if ( strlen( QTC_GetItemName( query ) ) == 0 ) {
+ strcpy( QTC_GetItemName( query ), TEXT("\\") ); // <-- FIX THIS !!!
+ }
+
+ while ( ! result ) {
+
+ if ( ! (++dir_count % 10) ) {
+ sprintf( text, format_string, dir_count );
+ STM_DrawText( text );
+ }
+
+ if ( strcmp( QTC_GetItemName( query ), TEXT("\\") ) ) {
+
+ level = 1;
+
+ if ( QTC_GetPathLength( query ) != sizeof(CHAR) ) {
+
+ s = QTC_GetPath( query );
+
+ for ( i = 0; i < (INT16) QTC_GetPathLength( query ); i+=sizeof (CHAR) ) {
+ if ( *s == TEXT( '\0' ) ) {
+ level++;
+ }
+ s++;
+ }
+ }
+ }
+ else {
+ level = 0;
+ }
+
+ // Build complete path by adding new directory to end.
+
+ BytesNeeded = QTC_GetPathLength( query ) + strsize( QTC_GetItemName( query ) );
+
+ if ( BytesNeeded > path_size ) {
+ free( path );
+ path = malloc( BytesNeeded );
+ path_size = BytesNeeded;
+ }
+
+ if ( path == NULL ) {
+ break;
+ }
+
+ if ( QTC_GetPathLength( query ) != sizeof(CHAR) ) {
+
+ memcpy( path, QTC_GetPath( query ), QTC_GetPathLength( query ) );
+ strcpy( &path[ QTC_GetPathLength( query ) / sizeof(CHAR) ], QTC_GetItemName( query ) );
+ path_length = QTC_GetPathLength( query );
+ path_length += strsize( QTC_GetItemName( query ) );
+ }
+ else {
+
+ strcpy( path, QTC_GetItemName( query ) );
+ path_length = strsize( path );
+ }
+
+ slm = VLM_FindSLM( slm_list,
+ path,
+ path_length );
+
+ if ( slm == NULL ) {
+
+ slm = VLM_CreateSlm( (INT)( ( 4 * ( ( level / 32 ) + 1 ) ) ),
+ (INT)strsize( QTC_GetItemName( query ) ),
+ TRUE, appinfo->fFatDrive );
+
+ if ( slm == NULL ) {
+ break;
+ }
+
+ SLM_SetAttribute( slm, QTC_GetItemAttrib( query ) );
+ SLM_SetStatus( slm, INFO_VALID );
+
+ if ( QTC_GetItemStatus( query ) & QTC_CORRUPT ) {
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) | (UINT16)INFO_CORRUPT );
+ }
+
+#if !defined ( OEM_MSOFT ) //unsupported feature
+
+ if ( QTC_GetItemStatus( query ) & QTC_EMPTY ) {
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) | (UINT16)INFO_EMPTY );
+ }
+
+#endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ slm->next_brother = NULL;
+
+ SLM_SetLevel( slm, level );
+ SLM_SetDate( slm, QTC_GetItemDate( query ) );
+ SLM_SetTime( slm, QTC_GetItemTime( query ) );
+
+ DateTimeDOS( SLM_GetDate( slm ), SLM_GetTime( slm ), &mdate );
+
+ if ( SLM_GetLevel( slm ) < 2 ) {
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) | (UINT16)INFO_DISPLAY );
+ }
+ SLM_SetXtraBytes( slm, XtraBytes );
+ SLM_SetName( slm, QTC_GetItemName( query ) );
+ SLM_SetOriginalName( slm, QTC_GetItemName( query ) );
+
+
+ if ( fLowerCase ) {
+
+ strlwr( SLM_GetName( slm ) );
+ }
+
+ // Add this new slm to our list and be real smart about
+ // where it goes cause some bozo will have 3000 on a 10MHz AT.
+
+ VLM_InsertTapeSLM( slm_list, prev_slm, slm );
+
+ if ( prev_slm == NULL ) {
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) | (UINT16)(INFO_EXPAND | INFO_OPEN) );
+ }
+ else {
+
+ if ( SLM_GetLevel( slm ) > SLM_GetLevel( prev_slm ) ) {
+ SLM_SetStatus( prev_slm, SLM_GetStatus( prev_slm ) | (UINT16)INFO_SUBS );
+ }
+ }
+
+ prev_slm = slm;
+
+ // If this slm is corrupt then mark all his parents as corrupt
+
+ if ( SLM_GetStatus( slm ) & INFO_CORRUPT ) {
+
+ level = SLM_GetLevel( slm ) - 1;
+ temp_slm = slm;
+
+ while ( temp_slm != NULL ) {
+
+ if ( SLM_GetLevel( temp_slm ) == level ) {
+ SLM_SetStatus( temp_slm, SLM_GetStatus( temp_slm ) | (UINT16)INFO_CORRUPT );
+ level--;
+ }
+
+ temp_slm = VLM_GetPrevSLM( temp_slm );
+ }
+ }
+
+ }
+ else {
+
+ // Here's the deal ...
+ // If a directory is not going to be created because it is
+ // a duplicate, then we have to help our insertion cacheing
+ // algorithm out by telling it who the new "current" parent
+ // is. This way the upcoming children from this duplicate
+ // will get inserted in the right place.
+
+ VLM_InsertTapeSLM( NULL, NULL, slm );
+
+ prev_slm = slm; // <- this is just for fun.
+ }
+
+ result = (INT16)QTC_GetNextDir( query );
+ }
+
+ free( path );
+
+ QTC_CloseQuery( query );
+
+ VLM_UpdateBrothers( slm_list );
+}
+
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ Used for inserting an slm into a tape based tree.
+
+ RETURNS :
+
+**********************/
+
+static VOID VLM_InsertTapeSLM(
+Q_HEADER_PTR slm_list,
+SLM_OBJECT_PTR prev_slm,
+SLM_OBJECT_PTR new_slm )
+{
+ static SLM_OBJECT_PTR *parents = (SLM_OBJECT_PTR *)NULL;
+ static INT MaxParents = 0;
+
+ SLM_OBJECT_PTR *temp_parents;
+
+ SLM_OBJECT_PTR parent_slm; // parent of all this new guy's brothers
+ SLM_OBJECT_PTR temp_slm; // used to move through list
+ SLM_OBJECT_PTR best_slm; // insert after this guy
+ SLM_OBJECT_PTR last_brother; // new guy's prev brother after insertion
+ SLM_OBJECT_PTR next_brother; // new guy's next brother after insertion
+ INT level; // height of new guy in tree
+
+
+ if ( ( new_slm->level >= MaxParents ) || ( parents == (SLM_OBJECT_PTR *)NULL ) ) {
+
+ temp_parents = (SLM_OBJECT_PTR *)malloc( (MaxParents + 100 ) * sizeof(SLM_OBJECT_PTR) );
+
+ if ( temp_parents ) {
+
+ memcpy( temp_parents, parents, sizeof( SLM_OBJECT_PTR) * MaxParents );
+ free( parents );
+ parents = temp_parents;
+ MaxParents += 100;
+ }
+ else {
+ return;
+ }
+ }
+
+ // The code that calls us has decided not to create an slm because
+ // a duplicate already exists in the list. We have to use it as the
+ // correct parent for the possible upcoming children of the duplicate.
+
+ if ( slm_list == NULL ) {
+ parents[ new_slm->level ] = new_slm;
+ return;
+ }
+
+ // The parents array keeps us from having to look back through the queue
+ // to find this new guys parent. We need the parent so that we can
+ // insert this new guy as the possible first child.
+
+ if ( prev_slm == NULL ) {
+
+ // First entry, must be the root.
+
+ parents[ 0 ] = new_slm;
+ EnQueueElem( slm_list, &(new_slm->q_elem), FALSE );
+ return;
+ }
+
+ // Get height of new item.
+
+ level = new_slm->level;
+
+ // Set up for this guys possible children.
+
+ parents[ level ] = new_slm;
+
+ // Find this guys parent.
+
+ parent_slm = parents[ level - 1 ];
+
+ // Now find the right location to insert the new slm among his brothers.
+
+ best_slm = parent_slm;
+
+ last_brother = NULL;
+ next_brother = NULL;
+
+ // Try to skip a bunch of the brothers. Suppose ths guy has 20 brothers
+ // and the last slm inserted was his brother Jose. If this new guys
+ // name is Juan, then we can start looking with Jose.
+
+ if ( prev_slm->level == new_slm->level ) {
+
+ if ( stricmp( prev_slm->name, new_slm->name ) < 0 ) {
+ best_slm = prev_slm;
+ last_brother = best_slm;
+ }
+ }
+
+ temp_slm = best_slm;
+
+ if ( best_slm->level < level ) {
+
+ temp_slm = VLM_GetNextSLM( best_slm );
+ if ( ( temp_slm != NULL ) && ( temp_slm->level != level ) ) {
+ temp_slm = NULL;
+ }
+ }
+
+ // Now remember there may be children between the brothers that we
+ // don't care about and MUST ignore in determining where this slm
+ // should be located.
+
+ // temp_slm is NULL or first brother
+
+ while ( temp_slm ) {
+
+ next_brother = temp_slm;
+
+ if ( stricmp( temp_slm->name, new_slm->name ) >= 0 ) {
+
+ // Get out of while loop.
+ break;
+ }
+
+ last_brother = temp_slm;
+ best_slm = temp_slm;
+ temp_slm = temp_slm->next_brother;
+ }
+
+ // Insert after best_slm and any children > level.
+
+ if ( ( best_slm->level == level ) && ( best_slm->next_brother != NULL ) ) {
+
+ best_slm = VLM_GetPrevSLM( best_slm->next_brother );
+ }
+ else {
+
+ temp_slm = best_slm;
+
+ while ( temp_slm ) {
+
+ if ( temp_slm->level < level ) {
+ break;
+ }
+
+ best_slm = temp_slm;
+
+ if ( temp_slm->next_brother != NULL ) {
+ temp_slm = temp_slm->next_brother;
+ }
+ else {
+ temp_slm = VLM_GetNextSLM( temp_slm );
+ }
+
+ }
+ }
+
+ // Update next_brother pointers;
+
+ if ( last_brother != NULL ) {
+ new_slm->next_brother = last_brother->next_brother;
+ last_brother->next_brother = new_slm;
+ }
+ else {
+ new_slm->next_brother = next_brother;
+ }
+
+ InsertElem( slm_list, &(best_slm->q_elem), &(new_slm->q_elem), AFTER );
+
+}
+
+
+
+/***************************************************
+
+ Name: VLM_CreateSlm
+
+ Description:
+
+ Creates an SLM object for you.
+
+ Returns: either a pointer or NULL.
+
+*****************************************************/
+
+
+SLM_OBJECT_PTR VLM_CreateSlm(
+INT brother_bytes,
+INT name_size,
+BOOLEAN use_stats,
+BOOLEAN fat_drive )
+{
+ SLM_OBJECT_PTR slm;
+ INT slm_size;
+ INT stats_size;
+ INT original_name_size = 0;
+
+ // Everything must be 32 bit (4 byte) aligned for MIPs, so we
+ // round up all the sizes to the next 4 byte boundary (if
+ // required).
+
+ slm_size = sizeof( SLM_OBJECT );
+ if ( slm_size % 4 ) {
+ slm_size += 4 - ( slm_size % 4 );
+ }
+
+ if ( brother_bytes % 4 ) {
+ brother_bytes += 4 - ( brother_bytes % 4 );
+ }
+
+ if ( name_size % 4 ) {
+ name_size += 4 - ( name_size % 4 );
+ }
+
+ // If it is not a FAT drive we need to keep two name strings.
+ // This allows us to display the name in lower case.
+
+ if ( ! fat_drive ) {
+ original_name_size = name_size;
+ }
+
+ slm = ( SLM_OBJECT_PTR )malloc( slm_size +
+ brother_bytes +
+ name_size +
+ original_name_size +
+ 0 );
+
+ if ( slm != NULL ) {
+
+ // The seemingly redundant casting is for unicode support
+
+ slm->name = (CHAR_PTR) ( ((BYTE_PTR)slm) + slm_size );
+ if ( fat_drive ) {
+ slm->original_name = slm->name;
+ }
+ else {
+ slm->original_name = (CHAR_PTR)((BYTE_PTR)slm->name + name_size);
+ }
+ slm->brothers = ((BYTE_PTR)slm->original_name) + name_size;
+ slm->q_elem.q_ptr = slm;
+ }
+
+ return( slm );
+}
+
+
+/***************************************************
+
+ Name: VLM_BuildDirList
+
+ Description:
+
+ This function will build a sorted directory list from a disk for
+ displaying in the tree window. Most of the work is done by calling
+ check for children to blow out as much of the tree as needed.
+
+*****************************************************/
+
+static INT VLM_BuildDirList(
+Q_HEADER_PTR slm_list, // I - queue to fill in
+WININFO_PTR XtraBytes ) // I - windows extra bytes pointer
+{
+ SLM_OBJECT_PTR slm;
+ APPINFO_PTR appinfo;
+ BSD_PTR bsd_ptr;
+ FSE_PTR fse;
+ INT16 ret;
+
+
+ appinfo = ( APPINFO_PTR )XtraBytes->pAppInfo;
+
+ if ( ! DLE_HasFeatures( appinfo->dle, DLE_FEAT_CASE_PRESERVING ) ) {
+ appinfo->fFatDrive = TRUE;
+ }
+ else {
+ appinfo->fFatDrive = FALSE;
+ }
+
+ if ( FS_ChangeDir( appinfo->fsh, TEXT(""), (UINT16)sizeof(CHAR) ) ) {
+
+ return( 0 );
+ }
+
+ bsd_ptr = BSD_FindByDLE( bsd_list, appinfo->dle );
+
+ // Make the root and enter it into the list
+
+ slm = VLM_CreateSlm( (INT) 4,
+ (INT)(strlen(TEXT("..")) + 1) * sizeof(CHAR),
+ FALSE, appinfo->fFatDrive );
+
+ if ( slm == NULL ) {
+ return(0);
+ }
+
+ SLM_SetAttribute( slm, 0 );
+ SLM_SetLevel( slm, 0 );
+ SLM_SetXtraBytes( slm, XtraBytes );
+ SLM_SetName( slm, TEXT("\\") );
+ SLM_SetOriginalName( slm, TEXT("\\") );
+ SLM_SetNextBrother( slm, NULL );
+ SLM_SetStatus( slm, INFO_DISPLAY | INFO_VALID | INFO_OPEN | INFO_EXPAND );
+
+ EnQueueElem( slm_list, &(slm->q_elem), FALSE );
+
+ // Now let check for children do the rest
+
+ // The 1 is the depth to search.
+
+ if ( VLM_CheckForChildren( slm_list, slm, TEXT(""), 1, FALSE ) ) {
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) | (UINT16)INFO_SUBS );
+ }
+
+ if ( bsd_ptr != NULL ) {
+
+ ret = BSD_MatchPathAndFile( bsd_ptr, &fse, NULL, TEXT(""),
+ (UINT16)sizeof(CHAR),
+ SLM_GetAttribute( slm ),
+ NULL, NULL, NULL, FALSE, TRUE );
+
+ if ( ret == BSD_PROCESS_OBJECT ) {
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) | (UINT16)(INFO_SELECT | INFO_PARTIAL) );
+ }
+
+ if ( ret == BSD_PROCESS_ENTIRE_DIR ) {
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) | (UINT16)INFO_SELECT );
+ }
+ }
+
+ // Make the first two levels displayed
+
+ slm = VLM_GetFirstSLM( slm_list );
+
+ while ( slm != NULL ) {
+
+ if ( SLM_GetLevel( slm ) < 2 ) {
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) | (UINT16)INFO_DISPLAY );
+ }
+
+ slm = VLM_GetNextSLM( slm );
+ }
+
+ VLM_UpdateBrothers( slm_list );
+
+ return( 0 );
+}
+
+/***************************************************
+
+ NAME : VLM_UpdateBrothers
+
+ DESCRIPTION :
+
+ For each item in the list the DLM needs to know if brothers exist later
+ in the list at a deeper level in the tree. This allows the DLM to draw
+ pretty lines that run down the side of the tree. So we scan the list
+ backwards. This method supports an infinite depth of subdirectory levels,
+ by indicating each level with a single bit in double word(s) stored with
+ each item. Each double word can handle 32 levels and as many double words
+ are allocated as needed. As new nodes are expanded the entire list is
+ completely rescanned, this is not needed, but I haven't written the code
+ to handle sections at a time yet. This algorithm is very hard to under-
+ stand, so don't waste too much time trying unless it's important to you.
+
+ RETURNS : nothing.
+
+*****************************************************/
+
+VOID VLM_UpdateBrothers(
+Q_HEADER_PTR slm_list ) // I - Queue to update
+{
+ static UINT32 clr_masks[ 32 ] = {
+ 0x00000000, 0x80000000, 0xC0000000, 0xE0000000,
+ 0xf0000000, 0xf8000000, 0xfC000000, 0xfE000000,
+ 0xff000000, 0xff800000, 0xffC00000, 0xffE00000,
+ 0xfff00000, 0xfff80000, 0xfffC0000, 0xfffE0000,
+ 0xffff0000, 0xffff8000, 0xffffC000, 0xffffE000,
+ 0xfffff000, 0xfffff800, 0xfffffC00, 0xfffffE00,
+ 0xffffff00, 0xffffff80, 0xffffffC0, 0xffffffE0,
+ 0xfffffff0, 0xfffffff8, 0xfffffffC, 0xfffffffE };
+
+ static UINT32 set_masks[ 32 ] = {
+ 0x80000000, 0x40000000, 0x20000000, 0x10000000,
+ 0x08000000, 0x04000000, 0x02000000, 0x01000000,
+ 0x00800000, 0x00400000, 0x00200000, 0x00100000,
+ 0x00080000, 0x00040000, 0x00020000, 0x00010000,
+ 0x00008000, 0x00004000, 0x00002000, 0x00001000,
+ 0x00000800, 0x00000400, 0x00000200, 0x00000100,
+ 0x00000080, 0x00000040, 0x00000020, 0x00000010,
+ 0x00000008, 0x00000004, 0x00000002, 0x00000001 };
+
+ SLM_OBJECT_PTR slm;
+
+ INT16 working_block; // block of data to work on for this slm
+
+ INT prev_level; // height in tree of previous slm
+ INT curr_level; // height in tree of current slm
+
+ UINT32_PTR mask; // pointer into current mask buffer
+ UINT32_PTR last_mask; // pointer into previous mask buffer
+
+ INT16 mask_size; // current size of mask buffers
+ UINT32_PTR temp_mask; // temporary mask buffer
+ UINT32_PTR curr_mask; // current slm mask buffer
+ UINT32_PTR prev_mask; // previous slm mask buffer
+
+ UINT32_PTR brothers;
+
+ slm = VLM_GetLastSLM( slm_list );
+
+ while ( slm && ! ( slm->status & INFO_DISPLAY ) ) {
+ slm = VLM_GetPrevSLM( slm );
+ }
+
+ prev_level = SLM_GetLevel( slm );
+
+ mask_size = (INT16)(( SLM_GetLevel( slm ) / 32 ) + 1);
+
+ curr_mask = ( UINT32_PTR )calloc( mask_size * 4, 1 );
+ prev_mask = ( UINT32_PTR )calloc( mask_size * 4, 1 );
+
+ last_mask = prev_mask;
+
+ if ( ( curr_mask != NULL ) && ( prev_mask != NULL ) ) {
+
+ while ( slm != NULL ) {
+
+ // set this item
+
+ curr_level = SLM_GetLevel( slm );
+
+ working_block = (INT16)(( curr_level / 32 ) + 1);
+
+ if ( mask_size < working_block ) {
+
+ // expand current mask
+
+ temp_mask = ( UINT32_PTR )calloc( 4 * working_block, 1 );
+ if ( temp_mask == NULL ) {
+ break;
+ }
+ memcpy( temp_mask, curr_mask, mask_size * 4 );
+ free( curr_mask );
+ curr_mask = temp_mask;
+
+ // expand previous mask
+
+ temp_mask = ( UINT32_PTR )calloc( 4 * working_block, 1 );
+ if ( temp_mask == NULL ) {
+ break;
+ }
+ memcpy( temp_mask, prev_mask, mask_size * 4 );
+ free( prev_mask );
+ prev_mask = temp_mask;
+
+ mask_size = working_block;
+ }
+
+ mask = curr_mask;
+ mask += working_block - 1;
+
+ // clear everything higher than this bit
+
+ temp_mask = mask;
+ *temp_mask &= clr_masks[ curr_level & 0x1F ];
+
+ if ( working_block < mask_size ) {
+
+ // clear out the rest of the masks
+
+ temp_mask = curr_mask;
+ temp_mask += working_block;
+ memset( temp_mask, 0, 4 * (mask_size - working_block) );
+ }
+
+ // set a bit for this node
+
+ *mask |= set_masks[ curr_level & 0x1F ];
+
+ // Copy new mask into slm
+
+ brothers = (UINT32_PTR)SLM_GetBrothers( slm );
+ memcpy( brothers, curr_mask, working_block * 4 );
+
+ brothers += working_block - 1;
+
+ if ( ( prev_level < curr_level ) ||
+ ! ( *last_mask & set_masks[ curr_level & 0x1F ] ) ) {
+
+ *brothers &= ~set_masks[ curr_level & 0x1F ];
+ }
+
+ // Copy current mask and level to previous mask and level
+
+ last_mask = prev_mask;
+ last_mask += working_block - 1;
+
+ memcpy( prev_mask, curr_mask, 4 * working_block );
+
+ prev_level = curr_level;
+
+ do {
+ slm = VLM_GetPrevSLM( slm );
+ } while ( slm && ! ( slm->status & INFO_DISPLAY ) );
+ }
+ }
+
+ if ( prev_mask ) {
+ free( prev_mask );
+ }
+
+ if ( curr_mask ) {
+ free( curr_mask );
+ }
+ return;
+}
+
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+SLM_OBJECT_PTR VLM_FindSLM(
+Q_HEADER_PTR slm_list,
+CHAR_PTR path,
+INT path_size )
+{
+ SLM_OBJECT_PTR slm;
+ INT level;
+ INT index = 0;
+
+ if ( path_size == 0 ) {
+ msassert( FALSE );
+ }
+
+ slm = VLM_GetFirstSLM( slm_list );
+
+ if ( path_size == sizeof(CHAR) ) { // root
+ return( slm );
+ }
+
+ if ( path_size == ( 2 * sizeof(CHAR ) ) ) {
+ if ( ! strcmp( path, TEXT( "\\" ) ) ) {
+ return( slm );
+ }
+ }
+
+ level = 1;
+
+ if ( slm ) {
+ slm = VLM_GetNextSLM( slm );
+ }
+
+ while ( slm != NULL ) {
+
+ // We didn't find proper child, before next brother, so abort.
+
+ if ( slm->level < level ) {
+ return( NULL );
+ }
+
+ if ( slm->level == level ) {
+
+ if ( ! stricmp( slm->name, &path[ index ] ) ) {
+
+ while ( path[ index ] ) index++;
+ index++;
+
+ // Have we found the whole path ?
+
+ if ( (INT)(index * sizeof (CHAR)) == path_size ) {
+ return( slm );
+ }
+ level++;
+ }
+ else {
+ slm = slm->next_brother;
+ continue;
+ }
+ }
+
+ slm = VLM_GetNextSLM( slm );
+
+ }
+
+ return( slm );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+SLM_OBJECT_PTR VLM_GetNextBrotherSLM(
+SLM_OBJECT_PTR slm )
+{
+
+ // New faster method. Was a real function to new field was added.
+
+ return( slm->next_brother );
+}
+
+
+/***************************************************
+
+ Name: VLM_CheckForChildren
+
+ Description:
+
+ This is one of those recursive calls that descends down the tree as
+ deep as requested to locate all the brothers and sisters that exist
+ on the disk. For efficiency the directories at level N are found
+ and inserted in order, before descending deeper to locate any
+ children at level N+1.
+
+ Warning:
+
+ This function is designed to work only with DISK or SERVER windows.
+ However the code that processes TAPE windows also has calls to this
+ function. The idea here is that it will never be called because the
+ catalogs construct the entire tree for tapes and so all the children
+ are already known.
+
+ Returns:
+
+ Number of new directories found. This is only used to see if any
+ at all were found, so ZERO/NON-ZERO would work as well.
+
+*****************************************************/
+
+INT VLM_CheckForChildren(
+Q_HEADER_PTR slm_list, // I - queue to add children to
+SLM_OBJECT_PTR parent_slm, // I - slm to add children under
+CHAR_PTR base_path, // I - path of parent slm
+INT depth, // I - how much deeper to go
+BOOLEAN refresh ) // I - is it real or is it refreshing ?
+{
+ WININFO_PTR XtraBytes;
+ SLM_OBJECT_PTR slm;
+ SLM_OBJECT_PTR prev_slm_inserted = NULL;
+ SLM_OBJECT_PTR start_slm = NULL;
+ INT16 count = 0;
+ INT16 psize;
+ INT16 orig_psize;
+ INT16 ret;
+ INT16 dir_count;
+ INT16 fs_status;
+ CHAR_PTR buffer;
+ CHAR_PTR name;
+ CHAR_PTR path;
+ CHAR_PTR s;
+ APPINFO_PTR appinfo;
+ BSD_PTR bsd_ptr;
+ FSE_PTR fse;
+ DBLK_PTR dblk;
+ DATE_TIME mdate;
+ BOOLEAN displayed = FALSE;
+ static CHAR format_string[ MAX_UI_RESOURCE_SIZE ];
+ INT BytesNeeded;
+ INT level;
+ INT file_count = 0;
+ INT fLowerCase = FALSE;
+ INT buffer_size = 0;
+
+
+ level = SLM_GetLevel( parent_slm );
+ level++;
+
+ XtraBytes = SLM_GetXtraBytes( parent_slm );
+ appinfo = ( APPINFO_PTR )XtraBytes->pAppInfo;
+
+ RSM_StringCopy( IDS_DIRSCANNED, format_string, MAX_UI_RESOURCE_LEN );
+
+ buffer = ( CHAR_PTR )malloc( VLM_BUFFER_SIZE );
+ buffer_size = VLM_BUFFER_SIZE;
+
+ dblk = (DBLK_PTR)malloc( sizeof(DBLK ) );
+
+ psize = (INT16)strsize( base_path );
+
+ path = malloc( psize );
+
+ if ( path == NULL || dblk == NULL || buffer == NULL ) {
+ free( buffer );
+ free( dblk );
+ free( path );
+ return( 0 );
+ }
+
+ strcpy( path, base_path );
+
+ s = path;
+
+ while ( *s ) {
+ if ( *s == TEXT('\\') ) {
+ *s = TEXT( '\0' );
+ }
+ s++;
+ }
+
+ if ( CDS_GetFontCase( CDS_GetPerm() ) ) {
+ fLowerCase = TRUE;
+ }
+ else {
+ if ( CDS_GetFontCaseFAT( CDS_GetPerm() ) ) {
+
+ // Change this to DLE_FEATURE_FAT_DRIVE
+
+ if ( ! DLE_HasFeatures( appinfo->dle, DLE_FEAT_CASE_PRESERVING ) ) {
+ fLowerCase = TRUE;
+ }
+ }
+ }
+
+
+ if ( FS_ChangeDir( appinfo->fsh, path, psize ) ) {
+ free( buffer );
+ free( dblk );
+ free( path );
+ return( 0 );
+ }
+
+ free( path );
+
+ // WM_MultiTask(); <--- broke mikep 6/21/93
+
+ fs_status = FS_FindFirstObj( appinfo->fsh, dblk, TEXT("*.*") );
+
+ // VLM_HandleFSError( (INT)fs_status );
+
+ if ( fs_status == SUCCESS ) {
+
+ // Get the BSD pointer for this drive.
+
+ bsd_ptr = BSD_FindByDLE( bsd_list, appinfo->dle );
+
+ // Get the directory count for the status line
+
+ dir_count = QueueCount( XtraBytes->pTreeList );
+
+ // Add all the directories at this level
+
+ do {
+
+ if ( FS_GetBlockType( dblk ) == BT_DDB ) {
+ count++;
+ } else {
+ file_count++;
+ }
+
+ // If depth == 0 then they only wanted to know if there were subs.
+
+ if ( depth == 0 && count && file_count ) {
+ FS_ReleaseDBLK( appinfo->fsh, dblk );
+ break;
+ }
+
+ if ( ( FS_GetBlockType( dblk ) != BT_DDB ) || ( depth == 0 ) ) {
+ FS_ReleaseDBLK( appinfo->fsh, dblk );
+ }
+ else {
+
+ if ( ! (++dir_count % 5) ) {
+ sprintf( buffer, format_string, dir_count );
+ STM_DrawText( buffer );
+ }
+
+ orig_psize = FS_SizeofOSPathInDDB( appinfo->fsh, dblk );
+ if ( orig_psize > buffer_size ) {
+ free( buffer );
+ buffer = malloc( orig_psize );
+ }
+
+ FS_GetOSPathFromDDB( appinfo->fsh, dblk, buffer );
+
+ psize = (INT16) (orig_psize - sizeof(CHAR));
+ psize /= sizeof(CHAR);
+
+ do {
+ psize--;
+ } while ( psize && buffer[psize] );
+
+ if ( psize ) {
+ psize++;
+ }
+ name = &buffer[psize];
+
+ slm = VLM_FindSLM( slm_list, buffer, orig_psize );
+
+ if ( fLowerCase ) {
+
+ strlwr( name );
+ }
+
+ if ( slm == NULL ) {
+
+ slm = VLM_CreateSlm( (INT)(4 * ( ( level / 32 ) + 1 ) ),
+ (INT)strsize( name ),
+ FALSE, appinfo->fFatDrive );
+
+ if ( slm == NULL ) {
+ break;
+ }
+
+ SLM_SetStatus( slm, 0 );
+ }
+ else {
+ slm->status |= INFO_OLD;
+ }
+
+ slm->status |= INFO_NEW;
+
+ SLM_SetAttribute( slm, FS_GetAttribFromDBLK( appinfo->fsh, dblk ) );
+ SLM_SetLevel( slm, level );
+ SLM_SetXtraBytes( slm, XtraBytes );
+ SLM_SetName( slm, name );
+ SLM_SetOriginalName( slm, name );
+
+ FS_GetMDateFromDBLK( appinfo->fsh, dblk, &mdate );
+ SLM_SetDate( slm, ConvertDateDOS( &mdate ) );
+ SLM_SetTime( slm, ConvertTimeDOS( &mdate ) );
+
+ if ( bsd_ptr != NULL ) {
+
+ slm->status &= ~(INFO_SELECT|INFO_PARTIAL);
+
+ ret = BSD_MatchPathAndFile( bsd_ptr, &fse, NULL, buffer,
+ orig_psize,
+ slm->attrib,
+ &mdate, NULL, NULL, FALSE, TRUE );
+
+ if ( ret == BSD_PROCESS_OBJECT ) {
+ slm->status |= INFO_SELECT | INFO_PARTIAL;
+ }
+ if ( ret == BSD_PROCESS_ENTIRE_DIR ) {
+ slm->status |= INFO_SELECT;
+ }
+ }
+
+ // The idea now is to start at the first new item we've added and
+ // insert this new one in the right place.
+
+ // Don't reinsert an OLD SLM that's already there during refresh call.
+
+ if ( ! ( SLM_GetStatus( slm ) & INFO_OLD ) ) {
+
+ VLM_InsertDiskSLM( slm_list, parent_slm, prev_slm_inserted, slm );
+ }
+
+ prev_slm_inserted = slm;
+
+ FS_ReleaseDBLK( appinfo->fsh, dblk );
+
+ }
+
+ } while ( FS_FindNextObj( appinfo->fsh, dblk ) == SUCCESS );
+
+ FS_FindObjClose( appinfo->fsh, dblk );
+
+ // If we are refreshing and we added some new dirs, then we need to
+ // check to see if any old brothers are VALID to determine if we
+ // need to look deeper for subdirectories or not. If a brother knows
+ // if he has children, then this new guy MUST know too.
+
+ // In addition mark all found old slm's as neither OLD nor NEW.
+
+ if ( refresh ) {
+
+ depth = 0;
+
+ slm = VLM_GetNextSLM( parent_slm );
+
+ while ( slm ) {
+
+ if ( slm->status & INFO_OLD ) {
+
+ if ( slm->status & INFO_DISPLAY ) {
+ displayed = TRUE;
+ }
+
+ if ( slm->status & INFO_VALID ) {
+ depth = 10000;
+ }
+
+ if ( slm->status & INFO_NEW ) {
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) & (UINT16)~(INFO_OLD|INFO_NEW) );
+ }
+ }
+
+ slm = slm->next_brother;
+
+ }
+
+ }
+
+ // Now that we've found all the children at this level let's
+ // go look at lower levels for their kids if required.
+
+ if ( depth && count ) {
+
+ slm = VLM_GetNextSLM( parent_slm );
+
+ while ( slm ) {
+
+ if ( ! ( SLM_GetStatus( slm ) & INFO_VALID ) || refresh ) {
+
+ BytesNeeded = strsize( base_path ) + strsize( slm->name );
+ if ( buffer_size < BytesNeeded ) {
+ free( buffer );
+ buffer = malloc( BytesNeeded );
+ buffer_size = BytesNeeded;
+ }
+
+ if ( strlen( base_path ) ) {
+ strcpy( buffer, base_path );
+ strcat( buffer, TEXT("\\") );
+ strcat( buffer, slm->name );
+ }
+ else {
+ strcpy( buffer, slm->name );
+ }
+
+ if ( VLM_CheckForChildren( slm_list, slm, buffer,
+ depth - 1, refresh ) ) {
+ slm->status |= INFO_SUBS;
+ }
+ else {
+ slm->status &= ~INFO_SUBS;
+ slm->status |= INFO_VALID;
+ }
+
+ // Only for refresh.
+
+ if ( displayed ) {
+ slm->status |= INFO_DISPLAY;
+ }
+ }
+
+ // Step over the children found already
+
+ slm = slm->next_brother;
+ }
+ }
+
+ }
+
+#if !defined ( OEM_MSOFT ) //unsupported feature
+
+ if ( file_count ) {
+ SLM_SetStatus( parent_slm, SLM_GetStatus( parent_slm ) & (UINT16)~INFO_EMPTY );
+ }
+ else {
+ SLM_SetStatus( parent_slm, SLM_GetStatus( parent_slm ) | (UINT16)INFO_EMPTY );
+ }
+
+#endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ free( buffer );
+ free( dblk );
+ return( count );
+}
+
+
+INT VLM_HandleFSError( INT error ) {
+
+ switch ( error ) {
+
+ case FS_NO_MORE:
+ case FAILURE:
+ case SUCCESS:
+ default:
+ break;
+
+ case FS_ACCESS_DENIED:
+ WM_MsgBox( ID(IDS_BACKUPERRORTITLE ),
+ ID(IDS_VLMACCESSDENIEDMSG ),
+ WMMB_OK,
+ WMMB_ICONEXCLAMATION );
+ break;
+
+ case FS_DEVICE_ERROR:
+ case FS_COMM_FAILURE:
+
+ WM_MsgBox( ID( IDS_BACKUPERRORTITLE ),
+ ID(IDS_VLMDEVICEERRORMSG),
+ WMMB_OK,
+ WMMB_ICONEXCLAMATION );
+ break;
+
+ }
+
+ return( SUCCESS );
+}
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ Used to insert an slm into a disk based tree.
+
+ RETURNS :
+
+**********************/
+
+static VOID VLM_InsertDiskSLM(
+Q_HEADER_PTR slm_list,
+SLM_OBJECT_PTR parent_slm,
+SLM_OBJECT_PTR prev_slm,
+SLM_OBJECT_PTR new_slm )
+{
+
+ SLM_OBJECT_PTR temp_slm; // used to move through list
+ SLM_OBJECT_PTR best_slm; // insert after this guy
+ SLM_OBJECT_PTR last_brother; // new guy's prev brother after insertion
+ SLM_OBJECT_PTR next_brother; // new guy's next brother after insertion
+ INT level; // height of new guy in tree
+
+
+ // Get height of new item.
+
+ level = new_slm->level;
+
+ // Now find the right location to insert the new slm among his brothers.
+
+ best_slm = parent_slm;
+
+ last_brother = NULL;
+ next_brother = NULL;
+
+ // Try to skip a bunch of the brothers, to speed the insertion.
+
+ if ( prev_slm != NULL ) {
+
+ if ( stricmp( prev_slm->name, new_slm->name ) < 0 ) {
+
+ best_slm = prev_slm;
+ last_brother = best_slm;
+ }
+ }
+
+ temp_slm = best_slm;
+
+ if ( best_slm->level < level ) {
+
+ temp_slm = VLM_GetNextSLM( best_slm );
+ if ( ( temp_slm != NULL ) && ( temp_slm->level != level ) ) {
+ temp_slm = NULL;
+ }
+ }
+
+ // Look through all this guys brothers for correct insertion spot.
+ // temp_slm is NULL or first brother in family.
+
+ while ( temp_slm ) {
+
+ next_brother = temp_slm;
+
+ if ( stricmp( temp_slm->name, new_slm->name ) >= 0 ) {
+
+ // Get out of while loop, we have found the
+ // correct brother to insert before.
+ break;
+ }
+
+ last_brother = temp_slm;
+ best_slm = temp_slm;
+ temp_slm = temp_slm->next_brother;
+ }
+
+ // Insert after best_slm and any children > level.
+ // best_slm may have children and we need to insert after those kids.
+
+ if ( ( best_slm->level == level ) && ( best_slm->next_brother != NULL ) ) {
+
+ // If same height get last kid slm before next brother.
+
+ best_slm = VLM_GetPrevSLM( best_slm->next_brother );
+
+ }
+ else {
+
+ temp_slm = best_slm;
+
+ while ( temp_slm ) {
+
+ if ( temp_slm->level < level ) {
+
+ break;
+ }
+
+ best_slm = temp_slm;
+
+ if ( temp_slm->next_brother != NULL ) {
+ temp_slm = temp_slm->next_brother;
+ }
+ else {
+ temp_slm = VLM_GetNextSLM( temp_slm );
+ }
+
+ }
+ }
+
+ // Update the next_brother pointers.
+
+ if ( last_brother != NULL ) {
+
+ // new_slm is not the first brother.
+
+ new_slm->next_brother = last_brother->next_brother;
+ last_brother->next_brother = new_slm;
+ }
+ else {
+
+ // We need to set this guy's next brother if he has one.
+ // new_slm has become the first brother in the family.
+
+ new_slm->next_brother = next_brother;
+ }
+
+ // Perform insertion.
+
+ InsertElem( slm_list, &(best_slm->q_elem), &(new_slm->q_elem), AFTER );
+}
+
+
+/***************************************************
+
+ Name: VLM_SlmSetSelect
+
+ Description:
+
+ The callback function that is used when the display manager wants
+ me to change the selection status of a subdirectory. This function
+ is rather long and complicated so be careful changing it. When the
+ selection status of a subdirectory changes the changes must be
+ propagated everywhere, up and down the tree, and possibly in the
+ files display window also.
+
+*****************************************************/
+
+static VOID_PTR VLM_SlmSetSelect(
+SLM_OBJECT_PTR slm, // I - current slm
+BYTE attr ) // I - what to set him to
+{
+ APPINFO_PTR appinfo;
+ WININFO_PTR wininfo;
+ SLM_OBJECT_PTR temp_slm;
+ BSD_PTR bsd_ptr;
+ FSE_PTR fse_ptr;
+ CHAR_PTR s;
+ INT16 path_len;
+ UINT32 status;
+ INT16 error;
+ INT level;
+ HWND window;
+ BOOL all_subdirs;
+ BE_CFG_PTR bec_config;
+ DATE_TIME sort_date;
+ CHAR *path;
+ BSET_OBJECT_PTR bset;
+ INT total_dirs;
+ INT total_files;
+ UINT64 total_bytes;
+ BOOLEAN u64_stat;
+ UINT32 old_status;
+
+
+ all_subdirs = CDS_GetIncludeSubdirs( CDS_GetPerm() );
+
+ // Change the selection status of the item requested
+
+ if ( attr ) {
+
+ if ( all_subdirs ) {
+
+ // include all subdirs
+
+ status = INFO_SELECT;
+ }
+ else {
+ status = (INFO_SELECT|INFO_PARTIAL);
+ }
+ }
+ else {
+ status = 0;
+ }
+
+ window = slm->XtraBytes->hWnd;
+ wininfo = WM_GetInfoPtr( window );
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( window );
+
+ old_status = slm->status;
+
+ if ( status != (UINT16)( slm->status & (INFO_SELECT|INFO_PARTIAL) ) ) {
+
+ slm->status &= ~(INFO_SELECT|INFO_PARTIAL);
+ slm->status |= status;
+
+ DLM_Update( window, DLM_TREELISTBOX, WM_DLMUPDATEITEM, (LMHANDLE)slm, 0 );
+ }
+
+ // Find the correct BSD
+
+ if ( appinfo->dle != NULL ) {
+
+ bsd_ptr = BSD_FindByDLE( bsd_list, appinfo->dle );
+
+ if ( bsd_ptr == NULL ) {
+
+ bec_config = BEC_CloneConfig( CDS_GetPermBEC() );
+ BEC_UnLockConfig( bec_config );
+
+ BSD_Add( bsd_list, &bsd_ptr, bec_config,
+ NULL, appinfo->dle, (UINT32)-1L, (UINT16)-1, (INT16)-1, NULL, NULL );
+ }
+ }
+ else {
+
+ bsd_ptr = BSD_FindByTapeID( tape_bsd_list,
+ appinfo->tape_fid,
+ appinfo->bset_num );
+
+ if ( bsd_ptr == NULL ) {
+
+ bec_config = BEC_CloneConfig( CDS_GetPermBEC() );
+ BEC_UnLockConfig( bec_config );
+
+ VLM_GetSortDate( appinfo->tape_fid, appinfo->bset_num, &sort_date );
+
+ bset = VLM_FindBset( appinfo->tape_fid, appinfo->bset_num );
+
+ BSD_Add( tape_bsd_list, &bsd_ptr, bec_config, NULL,
+ NULL, bset->tape_fid, bset->tape_num, bset->bset_num, NULL, &sort_date );
+
+ if ( bsd_ptr != NULL ) {
+
+ VLM_FillInBSD( bsd_ptr );
+ }
+ }
+ }
+
+ // Add this new selection to the FSE list for this BSD
+
+ path = VLM_BuildPath( slm );
+ path_len = 2;
+ s = path;
+ while ( *s ) {
+ if ( *s == TEXT('\\') ) {
+ *s = TEXT( '\0' );
+ }
+ s++;
+ path_len += sizeof(CHAR);
+ }
+
+ if ( attr ) {
+ error = BSD_CreatFSE( &fse_ptr, (INT16) INCLUDE, (INT8_PTR)path, (INT16) path_len,
+ (INT8_PTR)ALL_FILES, ALL_FILES_LENG,
+ (BOOLEAN) USE_WILD_CARD,
+ (BOOLEAN) all_subdirs );
+ }
+ else {
+ error = BSD_CreatFSE( &fse_ptr, (INT16) EXCLUDE, (INT8_PTR)path, (INT16) path_len,
+ (INT8_PTR)ALL_FILES, ALL_FILES_LENG,
+ (BOOLEAN) USE_WILD_CARD,
+ (BOOLEAN) TRUE );
+ }
+
+ free( path );
+
+ if ( error ) {
+ return NULL;
+ }
+
+ if ( bsd_ptr != NULL ) {
+ BSD_AddFSE( bsd_ptr, fse_ptr );
+ }
+
+ if ( appinfo->dle == NULL ) {
+ VLM_UpdateSearchSelections( appinfo->tape_fid, appinfo->bset_num );
+ }
+
+ // If no fse's then clear whole window and return
+
+ if ( BSD_GetMarkStatus( bsd_ptr ) == NONE_SELECTED ) {
+
+ VLM_DeselectAll( wininfo, TRUE );
+ return NULL;
+ }
+
+ // save a pointer to the original slm
+
+ temp_slm = slm;
+
+ // see if the current files displayed are from this guy
+
+ if ( SLM_GetStatus( slm ) & INFO_OPEN ) {
+
+ // They are so select/deselect all of them
+
+ if ( attr ) {
+ VLM_FileListManager( appinfo->win, FLM_SEL_ALL );
+ }
+ else {
+ VLM_FileListManager( appinfo->win, FLM_SEL_NONE );
+ }
+ }
+ else {
+
+ // We need to find this guys parent and see if its the open slm.
+ // If so then we need to have the file window update the same item
+ // in it. This subdirectory name is in both windows at same time.
+
+ if ( (slm->level != 0) && ! (slm->status & INFO_OPEN) ) {
+
+ level = slm->level;
+
+ do {
+ slm = VLM_GetPrevSLM( slm );
+
+ } while ( slm->level != level - 1 );
+
+ if ( SLM_GetStatus( slm ) & INFO_OPEN ) {
+ VLM_UpdateFLMItem( window, temp_slm );
+ }
+ }
+ }
+
+ // mark all this guys child subdirectories
+
+ slm = temp_slm;
+
+ status = slm->status;
+ slm->status = old_status;
+ VLM_MarkAllSLMChildren( slm, attr, &total_dirs, &total_files, &total_bytes );
+ slm->status = status;
+
+ // Now lets start marking all this guys parents
+
+ if ( slm->level == 0 ) {
+
+ VLM_UpdateRoot( window );
+ }
+ else {
+
+ level = slm->level - 1;
+
+ do {
+
+ // Is it a parent directory ?
+
+ if ( slm->level == level ) {
+
+ if ( ! ( slm->status & INFO_SELECT ) ) {
+ total_dirs++;
+ }
+
+ if ( VLM_MatchSLM( slm, bsd_ptr ) == FALSE ) {
+ break;
+ }
+ else {
+
+ // It changed, if it's parent is the open SLM then
+ // this slm is also diplayed in the files window.
+
+ temp_slm = VLM_GetParentSLM( slm );
+
+ if ( temp_slm && ( SLM_GetStatus( temp_slm ) & INFO_OPEN ) ) {
+ VLM_UpdateFLMItem( window, slm );
+ }
+
+ }
+
+ // Special case root to set disk, tape, or server also.
+
+ if ( slm->level == 0 ) {
+ VLM_UpdateRoot( window );
+ }
+
+ level--;
+ }
+
+ slm = VLM_GetPrevSLM( slm );
+
+ } while ( slm != NULL );
+ }
+
+ return(NULL);
+}
+
+/*****************************
+
+ Update the selection status of a single slm. Return true if it
+ changed, false if it was correct already.
+
+******************************/
+
+INT VLM_MatchSLM(
+SLM_OBJECT_PTR slm,
+BSD_PTR bsd_ptr ) //I - BSD to match against
+{
+ HWND win;
+ WININFO_PTR wininfo;
+ FSE_PTR fse;
+ CHAR *path;
+ CHAR_PTR s;
+ INT16 result;
+ INT16 path_len;
+ UINT16 status;
+ DATE_TIME mod_date;
+ INT fChanged = FALSE;
+
+ if ( slm == NULL ) {
+ return( FALSE );
+ }
+
+ win = slm->XtraBytes->hWnd;
+
+ path = VLM_BuildPath( slm );
+ s = path;
+ path_len = 0;
+ while ( *s ) {
+ if ( *s == TEXT('\\') ) *s = TEXT( '\0' );
+ s++;
+ path_len++;
+ }
+ path_len++;
+
+ DateTimeDOS( slm->date, slm->time, &mod_date );
+
+ path_len *= sizeof( CHAR );
+
+ result = BSD_MatchPathAndFile( bsd_ptr, &fse, NULL,
+ path,
+ path_len,
+ slm->attrib,
+ &mod_date, NULL, NULL, FALSE, TRUE );
+
+ free( path );
+
+ status = 0;
+
+ if ( result == BSD_PROCESS_OBJECT ) {
+ status = INFO_SELECT | INFO_PARTIAL;
+ }
+
+ if ( result == BSD_PROCESS_ENTIRE_DIR ) {
+ status = INFO_SELECT;
+ }
+
+ // if selection status has changed, update it
+
+ if ( (UINT16)( slm->status & (INFO_SELECT|INFO_PARTIAL) ) != status ) {
+
+ fChanged = TRUE;
+ slm->status &= ~(INFO_SELECT|INFO_PARTIAL);
+ slm->status |= status;
+
+ DLM_Update( win, DLM_TREELISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)slm, 0 );
+
+ }
+
+ return( fChanged );
+}
+
+
+
+
+/***************************************************
+
+ Name: VLM_SlmGetSelect
+
+ Description:
+
+ The callback function that is used when the display manager wants
+ to get the selection status for a subdirectory.
+
+*****************************************************/
+
+static BYTE VLM_SlmGetSelect( SLM_OBJECT_PTR slm )
+{
+ if ( SLM_GetStatus( slm ) & INFO_SELECT ) {
+ return( 1 );
+ }
+
+ return( 0 );
+}
+
+/***************************************************
+
+ Name: VLM_SlmSetTag
+
+ Description:
+
+ The callback function that is used when the display manager wants
+ to set the tag status for a subdirectory.
+
+*****************************************************/
+
+static VOID_PTR VLM_SlmSetTag( SLM_OBJECT_PTR slm, BYTE attr )
+{
+ if ( attr ) {
+ slm->status |= INFO_TAGGED;
+ }
+ else {
+ slm->status &= ~INFO_TAGGED;
+ }
+ return(NULL);
+}
+
+/***************************************************
+
+ Name: VLM_SlmGetTag
+
+ Description:
+
+ The callback function that is used when the display manager wants
+ to get the tag status for a subdirectory.
+
+*****************************************************/
+
+static BYTE VLM_SlmGetTag( SLM_OBJECT_PTR slm )
+{
+ if ( SLM_GetStatus( slm ) & INFO_TAGGED ) {
+ return( 1 );
+ }
+ return( 0 );
+}
+
+
+/***************************************************
+
+ Name: VLM_SlmGetItemCount
+
+ Description:
+
+ The callback function that is used when the display manager wants
+ to get the number of currently displayable directories. There are
+ often directories in the tree which are NOT displayed and these
+ are not counted.
+
+*****************************************************/
+
+static USHORT VLM_SlmGetItemCount( Q_HEADER_PTR ListHdr )
+{
+ USHORT count = 0;
+ SLM_OBJECT_PTR slm;
+
+ slm = VLM_GetFirstSLM( ListHdr );
+
+ while ( slm != NULL ) {
+
+ if ( SLM_GetStatus( slm ) & INFO_DISPLAY ) {
+ count++;
+ }
+
+ slm = VLM_GetNextSLM( slm );
+ }
+
+ return( count );
+}
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+static VOID_PTR VLM_SlmGetFirstItem( Q_HEADER_PTR ListHdr )
+{
+ SLM_OBJECT_PTR slm;
+
+ slm = VLM_GetFirstSLM( ListHdr );
+
+ while ( slm != NULL ) {
+
+ if ( SLM_GetStatus( slm ) & INFO_DISPLAY ) {
+ return( slm );
+ }
+ slm = VLM_GetNextSLM( slm );
+ }
+
+ return( slm );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+static VOID_PTR VLM_SlmGetPrevItem( SLM_OBJECT_PTR slm )
+{
+
+ do {
+
+ slm = VLM_GetPrevSLM( slm );
+
+ if ( slm == NULL ) {
+ break;
+ }
+
+ } while ( ! ( SLM_GetStatus( slm ) & INFO_DISPLAY ) );
+
+ return( slm );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static VOID_PTR VLM_SlmGetNextItem( SLM_OBJECT_PTR slm )
+{
+ do {
+
+ slm = VLM_GetNextSLM( slm );
+
+ if ( slm == NULL ) {
+ break;
+ }
+ } while ( ! ( SLM_GetStatus( slm ) & INFO_DISPLAY ) );
+
+ return( slm );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static VOID_PTR VLM_SlmGetObjects( SLM_OBJECT_PTR slm )
+{
+ BYTE_PTR memblk;
+ BYTE_PTR buff;
+ BYTE_PTR source;
+ WININFO_PTR wininfo;
+ DLM_ITEM_PTR item;
+ INT16 num_blocks;
+ INT i;
+
+ wininfo = SLM_GetXtraBytes( slm );
+
+ memblk = ( BYTE_PTR )DLM_GetObjectsBuffer( WMDS_GetWinTreeList( wininfo ) );
+
+ buff = memblk;
+
+ *buff++ = 3; // number of objects in list to display
+
+ // pass DLM the hierarchical stuff he needs for lines
+
+
+ num_blocks = (UINT16)(( slm->level / 32 ) + 1);
+
+ *buff++ = (BYTE)num_blocks;
+
+ source = (BYTE_PTR)slm->brothers;
+
+ for ( i = 0; i < ( 4 * num_blocks ); i++ ) {
+ *buff++ = *source++;
+ }
+
+ // Now start passing object data to display
+
+ item = (DLM_ITEM_PTR)buff;
+
+ DLM_ItemcbNum( item ) = 1;
+ DLM_ItembType( item ) = DLM_CHECKBOX;
+
+ if ( slm->status & INFO_SELECT ) {
+ DLM_ItemwId( item ) = IDRBM_SEL_ALL;
+ if ( slm->status & INFO_PARTIAL ) {
+ DLM_ItemwId( item ) = IDRBM_SEL_PART;
+ }
+ }
+ else {
+ DLM_ItemwId( item ) = IDRBM_SEL_NONE;
+ }
+
+ DLM_ItembMaxTextLen( item ) = 0;
+ DLM_ItembLevel( item ) = (BYTE)SLM_GetLevel( slm );
+
+ item++;
+ DLM_ItemcbNum( item ) = 2;
+ DLM_ItembType( item ) = DLM_BITMAP;
+
+ switch ( slm->status & ( INFO_OPEN |
+ INFO_CORRUPT |
+ INFO_SUBS |
+ INFO_EXPAND |
+ INFO_EMPTY ) ) {
+
+ case ( INFO_EMPTY | INFO_CORRUPT | INFO_OPEN | INFO_SUBS | INFO_EXPAND ) :
+
+ DLM_ItemwId( item ) = IDRBM_FOLDER_EOCM;
+ break;
+
+ case ( INFO_EMPTY | INFO_CORRUPT | INFO_OPEN | INFO_SUBS ) :
+
+ DLM_ItemwId( item ) = IDRBM_FOLDER_EOCP;
+ break;
+
+ case ( INFO_EMPTY | INFO_CORRUPT | INFO_OPEN | INFO_EXPAND ) :
+ case ( INFO_EMPTY | INFO_CORRUPT | INFO_OPEN ) :
+
+ DLM_ItemwId( item ) = IDRBM_FOLDER_EOCN;
+ break;
+
+ case ( INFO_EMPTY | INFO_CORRUPT | INFO_SUBS | INFO_EXPAND ) :
+
+ DLM_ItemwId( item ) = IDRBM_FOLDER_ECM;
+ break;
+
+ case ( INFO_EMPTY | INFO_CORRUPT | INFO_SUBS ) :
+
+ DLM_ItemwId( item ) = IDRBM_FOLDER_ECP;
+ break;
+
+ case ( INFO_EMPTY | INFO_CORRUPT | INFO_EXPAND ) :
+ case ( INFO_EMPTY | INFO_CORRUPT ) :
+
+ DLM_ItemwId( item ) = IDRBM_FOLDER_ECN;
+ break;
+
+ case ( INFO_EMPTY | INFO_OPEN | INFO_SUBS | INFO_EXPAND ) :
+
+ DLM_ItemwId( item ) = IDRBM_FOLDER_EOM;
+ break;
+
+ case ( INFO_EMPTY | INFO_OPEN | INFO_SUBS ) :
+
+ DLM_ItemwId( item ) = IDRBM_FOLDER_EOP;
+ break;
+
+ case ( INFO_EMPTY | INFO_OPEN | INFO_EXPAND ) :
+ case ( INFO_EMPTY | INFO_OPEN ) :
+
+ DLM_ItemwId( item ) = IDRBM_FOLDER_EON;
+ break;
+
+ case ( INFO_EMPTY | INFO_SUBS | INFO_EXPAND ) :
+
+ DLM_ItemwId( item ) = IDRBM_FOLDER_EM;
+ break;
+
+ case ( INFO_EMPTY | INFO_SUBS ) :
+
+ DLM_ItemwId( item ) = IDRBM_FOLDER_EP;
+ break;
+
+ case ( INFO_EMPTY | INFO_EXPAND ) :
+ case ( INFO_EMPTY ) :
+
+ DLM_ItemwId( item ) = IDRBM_FOLDER_EN;
+ break;
+
+ case ( INFO_CORRUPT | INFO_OPEN | INFO_SUBS | INFO_EXPAND ) :
+
+ DLM_ItemwId( item ) = IDRBM_FOLDERMINUSOPENC;
+ break;
+
+ case ( INFO_CORRUPT | INFO_OPEN | INFO_SUBS ) :
+
+ DLM_ItemwId( item ) = IDRBM_FOLDERPLUSOPENC;
+ break;
+
+ case ( INFO_CORRUPT | INFO_OPEN | INFO_EXPAND ) :
+ case ( INFO_CORRUPT | INFO_OPEN ) :
+
+ DLM_ItemwId( item ) = IDRBM_FOLDEROPENC;
+ break;
+
+ case ( INFO_CORRUPT | INFO_SUBS | INFO_EXPAND ) :
+
+ DLM_ItemwId( item ) = IDRBM_FOLDERMINUSC;
+ break;
+
+ case ( INFO_CORRUPT | INFO_SUBS ) :
+
+ DLM_ItemwId( item ) = IDRBM_FOLDERPLUSC;
+ break;
+
+ case ( INFO_CORRUPT | INFO_EXPAND ) :
+ case ( INFO_CORRUPT ) :
+
+ DLM_ItemwId( item ) = IDRBM_FOLDERC;
+ break;
+
+ case ( INFO_OPEN | INFO_SUBS | INFO_EXPAND ) :
+
+ DLM_ItemwId( item ) = IDRBM_FOLDERMINUSOPEN;
+ break;
+
+ case ( INFO_OPEN | INFO_SUBS ) :
+
+ DLM_ItemwId( item ) = IDRBM_FOLDERPLUSOPEN;
+ break;
+
+ case ( INFO_OPEN | INFO_EXPAND ) :
+ case ( INFO_OPEN ) :
+
+ DLM_ItemwId( item ) = IDRBM_FOLDEROPEN;
+ break;
+
+ case ( INFO_SUBS | INFO_EXPAND ) :
+
+ DLM_ItemwId( item ) = IDRBM_FOLDERMINUS;
+ break;
+
+ case ( INFO_SUBS ) :
+
+ DLM_ItemwId( item ) = IDRBM_FOLDERPLUS;
+ break;
+
+ default :
+
+ DLM_ItemwId( item ) = IDRBM_FOLDER;
+ break;
+
+ }
+
+ DLM_ItembLevel( item ) = (BYTE)SLM_GetLevel( slm );
+ DLM_ItembMaxTextLen( item ) = 0;
+
+ item++;
+ DLM_ItemcbNum( item ) = 3;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = (BYTE)(strlen( SLM_GetName( slm ) ) + 1);
+ DLM_ItembLevel( item ) = (BYTE)SLM_GetLevel( slm );
+ strcpy( (CHAR_PTR)DLM_ItemqszString( item ), (CHAR_PTR)SLM_GetName( slm ) );
+
+ return( memblk );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static BOOLEAN VLM_SlmSetObjects(
+SLM_OBJECT_PTR slm, // I
+WORD operation, // I
+WORD ObjectNum ) // I
+{
+ HWND window;
+ INT level;
+ INT16 count;
+ INT ret;
+ WININFO_PTR wininfo;
+ CHAR volume_name[ VLM_BUFFER_SIZE ];
+ CHAR_PTR directory;
+ CHAR_PTR new_path;
+ CHAR_PTR s;
+ CHAR *path;
+ CHAR keyb_char;
+ SLM_OBJECT_PTR slm2;
+ SLM_OBJECT_PTR temp_slm;
+ BOOLEAN found = FALSE;
+ Q_HEADER_PTR slm_list;
+ APPINFO_PTR appinfo;
+
+ CHAR msg_title[ MAX_UI_RESOURCE_SIZE ];
+ CHAR msg_text[ MAX_UI_RESOURCE_SIZE ];
+
+
+ if ( operation == WM_DLMCHAR ) {
+
+ keyb_char = (CHAR)ObjectNum;
+
+ keyb_char = (CHAR)toupper( keyb_char );
+
+ temp_slm = slm;
+
+ do {
+
+ temp_slm = VLM_GetNextSLM( temp_slm );
+
+ if ( temp_slm != NULL ) {
+
+ if ( SLM_GetStatus( temp_slm ) & INFO_DISPLAY ) {
+
+ if ( keyb_char == (CHAR)toupper( *SLM_GetName( temp_slm ) ) ) {
+
+ DLM_SetAnchor( WMDS_GetWinTreeList( SLM_GetXtraBytes( temp_slm ) ),
+ 0,
+ (LMHANDLE)temp_slm );
+ return( TRUE );
+ }
+ }
+ }
+
+ } while ( temp_slm != NULL );
+
+ temp_slm = VLM_GetFirstSLM( WMDS_GetTreeList( SLM_GetXtraBytes( slm ) ) );
+
+ while ( temp_slm != NULL && temp_slm != slm ) {
+
+ if ( SLM_GetStatus( temp_slm ) & INFO_DISPLAY ) {
+
+ if ( keyb_char == (CHAR)toupper( *SLM_GetName( temp_slm ) ) ) {
+
+ DLM_SetAnchor( WMDS_GetWinTreeList( SLM_GetXtraBytes( temp_slm ) ),
+ 0,
+ (LMHANDLE)temp_slm );
+ return( TRUE );
+ }
+ }
+
+ temp_slm = VLM_GetNextSLM( temp_slm );
+
+ }
+
+ return( FALSE );
+ }
+
+
+ // If it's a single click then just change the file list. If its a
+ // double click then expand/contract the tree and don't change the
+ // file list. This works because whenever I'm sent a double click
+ // it is always preceeded by a single click on the same object.
+
+ // Contracting the tree is done by marking directory items as so
+ // they are not displayed. They are left in the list forever.
+
+ wininfo = SLM_GetXtraBytes( slm );
+
+ window = WMDS_GetWin( wininfo );
+ slm_list = WMDS_GetTreeList( wininfo );
+
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( window );
+
+ if ( ( operation == WM_DLMDOWN ) &&
+ ( ObjectNum == 3 || ObjectNum == 2 ) ) {
+
+ if ( slm != appinfo->open_slm ) {
+
+ WM_ShowWaitCursor( TRUE );
+
+ slm2 = appinfo->open_slm;
+ slm2->status &= ~INFO_OPEN;
+
+ DLM_Update( window, DLM_TREELISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)slm2, 0 );
+
+ slm->status |= INFO_OPEN;
+ appinfo->open_slm = slm;
+
+ path = VLM_BuildPath( slm );
+
+ directory = malloc( strsize( path ) + VLM_BUFFER_SIZE );
+
+ if ( appinfo->dle != NULL ) {
+
+ DLE_GetVolName( appinfo->dle, volume_name );
+
+ if ( volume_name[ strlen( volume_name ) - 1 ] != TEXT(':') ) {
+ strcat( volume_name, TEXT(":") );
+ }
+
+ sprintf( directory, TEXT("%s"), volume_name );
+ }
+ else {
+
+ sprintf( directory, TEXT("%s-%s:"),
+ VLM_GetTapeName( appinfo->tape_fid ),
+ VLM_GetBsetName( appinfo->tape_fid, appinfo->bset_num ) );
+ }
+
+ if ( SLM_GetLevel( slm ) != 0 ) {
+ strcat( directory, TEXT("\\") );
+ }
+
+ strcat( directory, path );
+ free( path );
+
+ // Change the displayed files
+
+ VLM_HandleFSError( VLM_FileListReuse( appinfo->win, directory ) ) ;
+
+ // Change the title
+
+ strcat( directory, TEXT("\\*.*") );
+ WM_SetTitle( window, directory );
+
+ free( directory );
+
+ DLM_Update( window, DLM_TREELISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)slm, 0 );
+
+ WM_ShowWaitCursor( FALSE );
+ }
+ }
+
+ // Look for an expansion or not
+
+ if ( ( operation == WM_DLMDBCLK ) &&
+ ( ObjectNum == 2 || ObjectNum == 3 ) ) {
+
+ if ( SLM_GetStatus( slm ) & INFO_SUBS ) {
+
+ if ( SLM_GetStatus( slm ) & INFO_EXPAND ) {
+
+ level = SLM_GetLevel( slm );
+ slm->status &= ~INFO_EXPAND;
+ slm2 = slm;
+ count = 0;
+
+ do {
+
+ slm2 = VLM_GetNextSLM( slm2 );
+
+ if ( slm2 == NULL ) break;
+
+ if ( SLM_GetLevel( slm2 ) <= level ) break;
+
+ if ( SLM_GetStatus( slm2 ) & INFO_DISPLAY ) {
+
+ slm2->status &= ~(INFO_DISPLAY|INFO_EXPAND);
+ count++;
+ }
+
+ } while ( TRUE );
+
+ DLM_Update( window, DLM_TREELISTBOX, WM_DLMDELETEITEMS,
+ (LMHANDLE)slm, count );
+ }
+ else {
+
+ WM_ShowWaitCursor( TRUE );
+
+ slm->status |= INFO_EXPAND;
+
+ if ( ! ( SLM_GetStatus( slm ) & INFO_VALID ) ) {
+
+ new_path = VLM_BuildPath( slm );
+
+ if ( VLM_CheckForChildren( slm_list,
+ slm,
+ new_path,
+ 1, // <- depth to search
+ FALSE) ) {
+
+ slm->status |= INFO_SUBS;
+ }
+
+ free( new_path );
+
+ slm->status |= INFO_VALID;
+
+ }
+
+ slm2 = slm;
+ level = SLM_GetLevel( slm );
+ count = 0;
+
+ do {
+
+ slm2 = VLM_GetNextSLM( slm2 );
+
+ if ( slm2 == NULL ) {
+ break;
+ }
+
+ if ( ( slm2->level == level + 1 ) &&
+ ! ( SLM_GetStatus( slm2 ) & INFO_DISPLAY ) ) {
+
+ count++;
+
+ slm2->status |= INFO_DISPLAY;
+ }
+ else {
+
+ if ( SLM_GetLevel( slm2 ) <= level ) {
+ break;
+ }
+ }
+
+ } while ( TRUE );
+
+ STM_DrawIdle();
+
+ VLM_UpdateBrothers( slm_list );
+
+ DLM_Update( window, DLM_TREELISTBOX, WM_DLMADDITEMS,
+ (LMHANDLE)slm, count );
+
+ WM_ShowWaitCursor( FALSE );
+ }
+ }
+ }
+
+ return( FALSE );
+}
+
+// The idea here is to work backwords up the list, throw away any entries
+// that are at a deeper level than the current one. And replace the
+// Nth level entry in our path with each new entry we hit at level N until
+// we finally hit the first level 1 entry, then stop.
+
+// finish with path[] = DOS\BRIEF\BACKUP
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+CHAR_PTR VLM_BuildPath( SLM_OBJECT_PTR slm ) // I
+{
+ INT level;
+ INT i;
+ INT path_size = 0;
+ INT BytesNeeded;
+ CHAR_PTR temp;
+ CHAR_PTR path;
+ CHAR_PTR s;
+
+
+ level = SLM_GetLevel( slm );
+
+ BytesNeeded = strsize( SLM_GetName( slm ) ) + ( level * sizeof(CHAR) );
+ path = malloc( BytesNeeded );
+ path_size = BytesNeeded;
+
+ if ( level == 0 ) {
+ *path = TEXT( '\0' );
+ return( path );
+ }
+
+ if ( level == 1 ) {
+ strcpy( path, SLM_GetName( slm ) );
+ return( path );
+ }
+
+ s = path;
+ for ( i = 1; i < level; i++ ) {
+ *s++ = TEXT('\\');
+ }
+ strcpy( s, SLM_GetName( slm ) ); // append the last entry in our new path.
+
+ while ( slm != NULL ) {
+
+ slm = VLM_GetPrevSLM( slm );
+
+ if ( slm == NULL ) {
+ break;
+ }
+
+ if ( SLM_GetLevel( slm ) >= level ) {
+ continue;
+ }
+
+ path = VLM_ReplaceEntry( path, &path_size, SLM_GetName( slm ), SLM_GetLevel( slm ) );
+
+ if ( SLM_GetLevel( slm ) == 1 ) {
+ break;
+ }
+
+ }
+
+ return( path );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ given JOHN \ PAUL \ HERB 0, MARGARET, 2
+ produces JOHN \ MARGARET \ HERB 0
+
+ RETURNS :
+
+**********************/
+
+static CHAR_PTR VLM_ReplaceEntry( CHAR_PTR path, INT *path_size, CHAR_PTR name, INT depth )
+{
+ INT i, start, index;
+ INT needed, avail;
+ INT BytesNeeded;
+ CHAR_PTR s, t1, t2;
+ CHAR_PTR temp;
+
+ start = 0;
+ s = path;
+ for ( i = 1; i < depth; i++ ) {
+ while ( *s && *s != TEXT('\\') ) {
+ s++;
+ start++;
+ }
+ s++;
+ start++;
+ }
+
+ avail = 0;
+ while ( s[avail] && s[avail] != TEXT('\\') ) {
+ avail++;
+ }
+
+ if ( avail != 0 ) {
+ return( path ); // someone screwed up !
+ }
+
+ needed = strlen( name );
+
+ if ( needed > avail ) {
+ BytesNeeded = *path_size + ((needed - avail) * sizeof(CHAR));
+ temp = (CHAR *)malloc( BytesNeeded );
+ memcpy( (BYTE *)temp, (BYTE *)path, *path_size );
+ *path_size = BytesNeeded;
+ free( path );
+ path = temp;
+ }
+
+ t1 = path + strlen(path) + needed - avail; // ...\abcdef\...0
+ t2 = path + strlen(path);
+ s = path + start;
+
+ index = strlen(path) - start - avail + 1;
+ for ( i = 0; i < index; i++ ) {
+ *t1-- = *t2--;
+ }
+ while ( *name ) {
+ *s++ = *name++;
+ }
+ if ( *s ) *s = TEXT('\\');
+
+ return( path );
+}
diff --git a/private/utils/ntbackup/src/vlm_util.c b/private/utils/ntbackup/src/vlm_util.c
new file mode 100644
index 000000000..d34be18c8
--- /dev/null
+++ b/private/utils/ntbackup/src/vlm_util.c
@@ -0,0 +1,2162 @@
+
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: VLM_UTIL.C
+
+ Description:
+
+ A lot of utility functions for dealing with the display lists for
+ disks, tapes, and servers.
+
+ $Log: G:\UI\LOGFILES\VLM_UTIL.C_V $
+
+ Rev 1.70.1.1 12 Dec 1993 19:58:58 MikeP
+put code back into vlm_validatepath
+
+ Rev 1.70.1.0 08 Dec 1993 11:44:30 MikeP
+very deep pathes and unicode
+
+ Rev 1.70 05 Aug 1993 17:35:42 MARINA
+enable c++
+
+ Rev 1.69 29 Jul 1993 23:27:42 MIKEP
+yank mapi.h
+
+ Rev 1.68 21 Jul 1993 17:10:08 CARLS
+change to tbrparse call
+
+ Rev 1.67 17 Jun 1993 15:33:56 Aaron
+Removed the meat of VLM_ValidatePath for Bimini (following lead of
+Nostradamus and Cayman).
+
+ Rev 1.66 15 Jun 1993 17:01:04 Aaron
+For display of local drives only, look at device type instead of
+lack of SUPPORTS_CHILDREN. Accept NTFS or DOS drive types.
+
+ Rev 1.65 01 Jun 1993 15:51:00 MIKEP
+make drive letter case match winfile
+
+ Rev 1.64 12 May 1993 08:27:38 MIKEP
+Fix upper/lower case support.
+
+ Rev 1.63 23 Apr 1993 10:19:22 MIKEP
+Add ability to refresh tapes window.
+Add support for sorting files window by various methods.
+Fix refresh of sorting windows.
+
+ Rev 1.62 05 Apr 1993 03:09:12 DARRYLP
+Prep work for email addition to Cayman.
+
+ Rev 1.61 30 Mar 1993 15:19:58 DARRYLP
+Added Net Connect and Disconnect.
+
+ Rev 1.60 11 Mar 1993 17:25:48 STEVEN
+fix trap on exit bug
+
+ Rev 1.59 18 Feb 1993 10:42:24 BURT
+Changes for CAYMAN
+
+
+ Rev 1.58 20 Jan 1993 20:47:22 MIKEP
+change status to 32bits
+
+ Rev 1.57 17 Nov 1992 21:22:32 DAVEV
+unicode fixes
+
+ Rev 1.56 15 Nov 1992 17:41:44 MIKEP
+cleanup and bug fixes
+
+ Rev 1.55 05 Nov 1992 17:23:14 DAVEV
+fix ts
+
+ Rev 1.53 30 Oct 1992 15:46:10 GLENN
+Added Frame and MDI Doc window size and position saving and restoring.
+
+ Rev 1.52 07 Oct 1992 15:07:34 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.51 07 Oct 1992 14:04:24 DAVEV
+various unicode chgs
+
+ Rev 1.50 05 Oct 1992 16:29:34 GLENN
+Reintegrated changes from 1.47 to the tip. DaveV checked in over 1.48.
+Added Net Connect and Disconnect. Now pulling BKS extension from resources.
+
+ Rev 1.49 04 Oct 1992 19:43:46 DAVEV
+Unicode Awk pass
+
+ Rev 1.48 30 Sep 1992 10:40:02 DAVEV
+Unicode strlen verification, MikeP's chgs from MS
+
+ Rev 1.46 11 Sep 1992 14:25:54 GLENN
+Changed DLE search to key off of Child Support.
+
+ Rev 1.45 03 Sep 1992 13:18:02 MIKEP
+nt fixes for volume labels
+
+ Rev 1.43 04 Aug 1992 17:00:28 CHUCKB
+Removed an errant (?) msassert.
+
+ Rev 1.42 29 Jul 1992 09:53:42 MIKEP
+ChuckB checked in after NT warnings were fixed.
+
+ Rev 1.41 20 Jul 1992 09:58:04 JOHNWT
+gas gauge display work
+
+ Rev 1.40 10 Jul 1992 08:34:30 JOHNWT
+more gas guage work
+
+ Rev 1.39 07 Jul 1992 15:41:24 MIKEP
+unicode changes
+
+ Rev 1.38 30 Jun 1992 13:17:32 JOHNWT
+dynamically alloc stats
+
+ Rev 1.37 29 Jun 1992 10:42:40 JOHNWT
+added selected dir counts
+
+ Rev 1.36 19 Jun 1992 14:43:30 JOHNWT
+more gas
+
+ Rev 1.35 10 Jun 1992 14:20:48 JOHNWT
+msoft'ed startup.bks processing
+
+ Rev 1.34 10 Jun 1992 11:49:24 JOHNWT
+gas guage changes
+
+ Rev 1.33 09 Jun 1992 15:14:36 JOHNWT
+gas gauge work
+
+ Rev 1.32 02 Jun 1992 08:05:52 MIKEP
+kludge to validate path
+
+ Rev 1.31 14 May 1992 18:05:28 MIKEP
+nt pass 2
+
+ Rev 1.30 06 May 1992 14:40:26 MIKEP
+unicode pass two
+
+ Rev 1.29 04 May 1992 13:39:38 MIKEP
+unicode pass 1
+
+
+****************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+#ifndef OEM_MSOFT
+// If we are doing Wind for Wkgrps (EMAIL would be more proper)
+#ifdef WFW
+ #include "mapinit.h"
+#ifndef CAYMAN
+ #define API FAR PASCAL
+ #include "winnet.h"
+#endif
+#endif
+
+#endif // OEM_MSOFT
+
+
+
+/**********************
+
+ NAME : VLM_DeselectAll
+
+ DESCRIPTION : remove all selections from SLM/FLM lists
+
+ RETURNS :
+
+**********************/
+
+VOID VLM_DeselectAll( WININFO_PTR wininfo, BOOLEAN display )
+{
+
+ SLM_OBJECT_PTR slm;
+ FLM_OBJECT_PTR flm;
+ HWND window;
+
+ slm = VLM_GetFirstSLM( WMDS_GetTreeList( wininfo ) );
+ window = slm->XtraBytes->hWnd;
+
+ while ( slm != NULL ) {
+
+ if ( SLM_GetStatus( slm ) & (INFO_SELECT|INFO_PARTIAL) ) {
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) & (UINT16)~(INFO_SELECT|INFO_PARTIAL) );
+
+ if ( display ) {
+ DLM_Update( window, DLM_TREELISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)slm, 0 );
+ }
+
+ }
+ slm = VLM_GetNextSLM( slm );
+ }
+
+ flm = VLM_GetFirstFLM( WMDS_GetFlatList( wininfo ) );
+
+ while ( flm != NULL ) {
+
+ if ( FLM_GetStatus( flm ) & (INFO_SELECT|INFO_PARTIAL) ) {
+
+ FLM_SetStatus( flm, FLM_GetStatus( flm ) & (UINT16)~(INFO_SELECT|INFO_PARTIAL) );
+
+ if ( display ) {
+ DLM_Update( window, DLM_FLATLISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)flm, 0 );
+ }
+ }
+ flm = VLM_GetNextFLM( flm );
+ }
+
+ if ( display ) {
+ VLM_UpdateRoot( window );
+ }
+
+ return;
+}
+
+
+/**********************
+
+ NAME : VLM_Deinit
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+VOID VLM_Deinit()
+{
+ HWND win;
+ HWND close_win = (HWND)NULL;
+ WININFO_PTR wininfo;
+
+ win = WM_GetNext( (HWND)NULL );
+ while ( win != (HWND)NULL ) {
+
+ wininfo = WM_GetInfoPtr( win );
+ if ( ( wininfo->wType == WMTYPE_DISKTREE ) ||
+ ( wininfo->wType == WMTYPE_TAPETREE )
+#ifdef OEM_EMS
+ || ( wininfo->wType == WMTYPE_EXCHANGE )
+#endif
+ ) {
+ close_win = win;
+ }
+
+ win = WM_GetNext( win );
+
+ if ( close_win ) {
+ WM_Destroy( close_win );
+ close_win = (HWND)NULL;
+ }
+ }
+
+ win = WM_GetNext( (HWND)NULL );
+
+ while ( win != (HWND)NULL ) {
+
+ wininfo = WM_GetInfoPtr( win );
+
+ if ( ( wininfo->wType == WMTYPE_DISKS ) ||
+ ( wininfo->wType == WMTYPE_SERVERS ) ||
+ ( wininfo->wType == WMTYPE_TAPES )
+#ifdef OEM_EMS
+ || ( wininfo->wType == WMTYPE_EXCHANGE )
+#endif
+ ) {
+ close_win = win;
+ }
+
+ switch ( wininfo->wType ) {
+
+ case WMTYPE_DISKS:
+ CDS_WriteDiskWinSize ( win );
+ break;
+
+#ifdef OEM_EMS
+ case WMTYPE_EXCHANGE:
+ break;
+#endif
+
+ case WMTYPE_SERVERS:
+ CDS_WriteServerWinSize ( win );
+ break;
+
+ case WMTYPE_TAPES:
+ CDS_WriteTapeWinSize ( win );
+ break;
+
+ }
+
+ win = WM_GetNext( win );
+
+ if ( close_win ) {
+ WM_Destroy( close_win );
+ close_win = (HWND)NULL;
+ }
+ }
+
+}
+
+
+/**********************
+
+ NAME : VLM_FindVLMByName
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+VLM_OBJECT_PTR VLM_FindVLMByName( Q_HEADER_PTR vlm_list, CHAR_PTR name )
+{
+ VLM_OBJECT_PTR vlm;
+
+ vlm = VLM_GetFirstVLM( vlm_list );
+
+ while ( vlm != NULL ) {
+
+ if ( ! stricmp( name, VLM_GetName( vlm ) ) ) {
+ return( vlm );
+ }
+
+ vlm = VLM_GetNextVLM( vlm );
+ }
+
+ return( vlm );
+
+}
+
+
+/**********************
+
+ NAME : VLM_BuildVolumeList
+
+ DESCRIPTION :
+
+ This function constructs a list of VLM's by looking at the dle_list
+ which is a global list of drives and servers. If the gfServers
+ flag is set then servers are being displayed and mapped drives are
+ not included. Otherwise local drives and mapped drives are included.
+
+***********************/
+
+VOID VLM_BuildVolumeList(
+Q_HEADER_PTR vlm_list, // I - queue to use
+WININFO_PTR XtraBytes ) // I
+{
+ GENERIC_DLE_PTR dle;
+ GENERIC_DLE_PTR temp_dle;
+ VLM_OBJECT_PTR vlm;
+ CHAR label_buffer[ 256 ];
+ BOOL fGoodDLE;
+
+ // Run through dle list
+
+ DLE_GetFirst( dle_list, &dle );
+
+ do {
+
+ if ( gfServers ) {
+
+ fGoodDLE = FALSE;
+
+ // Only display local drives, servers have their own window.
+
+ while ( ( ! fGoodDLE ) && ( dle != NULL ) ) {
+
+ if ( ( DLE_GetDeviceType( dle ) == LOCAL_NTFS_DRV ) ||
+ ( DLE_GetDeviceType( dle ) == LOCAL_DOS_DRV ) ) {
+ fGoodDLE = TRUE;
+ }
+ else {
+ DLE_GetNext( &dle );
+ }
+
+ }
+
+ }
+ else {
+
+ fGoodDLE = FALSE;
+
+ // Display locals and mapped drives, no server window.
+
+ while ( ( ! fGoodDLE ) && ( dle != NULL ) ) {
+
+ if ( ! DLE_HasFeatures( dle, DLE_FEAT_SUPPORTS_CHILDREN ) ) {
+ fGoodDLE = TRUE;
+ }
+ else {
+ DLE_GetNext( &dle );
+ }
+
+ }
+
+ }
+
+ // Add our new DLE to the list that we will work with
+
+ if ( dle != NULL ) {
+
+ temp_dle = dle;
+ DLE_GetNext( &dle );
+
+ if ( VLM_FindVLMByName( vlm_list,
+ DLE_GetDeviceName( temp_dle ) ) == NULL ) {
+
+ VLM_GetDriveLabel( temp_dle, label_buffer, 256 );
+
+ vlm = VLM_CreateVLM( (INT16)(strlen( label_buffer ) * sizeof (CHAR)),
+ (INT16)(strlen( DLE_GetDeviceName( temp_dle ) ) * sizeof (CHAR)) );
+
+ if ( vlm != NULL ) {
+
+ VLM_SetLabel( vlm, label_buffer );
+ VLM_SetName( vlm, DLE_GetDeviceName( temp_dle ) );
+
+ strupr( VLM_GetName( vlm ) ); // always upper case E:
+
+ if ( ! strncmp( VLM_GetLabel( vlm ), TEXT( "\\\\" ), 2 ) ) {
+ strlwr( VLM_GetLabel( vlm ) );
+ }
+
+ VLM_SetXtraBytes( vlm, XtraBytes );
+ EnQueueElem( vlm_list, &(vlm->q_elem), FALSE );
+ }
+ }
+ }
+
+ } while ( dle != NULL );
+
+
+ VLM_SetMaxVolumeLabelLength( vlm_list );
+
+ SortQueue( vlm_list, VLM_VlmCompare );
+
+
+}
+
+
+/**********************
+
+ NAME : VLM_CreateVLM
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+VLM_OBJECT_PTR VLM_CreateVLM( INT16 label_size, INT16 name_size )
+{
+ VLM_OBJECT_PTR vlm;
+
+ // We add two bytes for the 0's on the end of the strings in case
+ // the app forgets. We add another two bytes because the backup
+ // eng. under estimates the size of the volume name on AFP drives by
+ // 2 bytes.
+
+ vlm = (VLM_OBJECT_PTR)malloc( sizeof( VLM_OBJECT ) +
+ label_size + name_size + 4 * sizeof(CHAR) );
+
+ if ( vlm != NULL ) {
+
+ vlm->q_elem.q_ptr = vlm;
+ vlm->label = (CHAR_PTR)((INT8_PTR)vlm + sizeof( VLM_OBJECT ));
+ vlm->name = (CHAR_PTR)((INT8_PTR)vlm->label + label_size + 3*sizeof (CHAR));
+ vlm->parent = NULL;
+ InitQueue( &vlm->children );
+ vlm->status = 0;
+ }
+
+ return( vlm );
+}
+
+
+/******************
+
+
+ Try our best to get a label of some kind for the given drive.
+
+
+*******************/
+
+INT VLM_GetDriveLabel( GENERIC_DLE_PTR dle, CHAR_PTR buffer, INT buffer_size )
+{
+ INT i;
+
+ DLE_GetVolName( dle, buffer );
+
+ if ( strlen( buffer ) >= 3 ) {
+ for ( i = 0; i < buffer_size - 3; i++ ) {
+ buffer[ i ] = buffer[ i + 3 ];
+ }
+ }
+
+ return( SUCCESS );
+
+}
+
+/**********************
+
+ NAME : VLM_GetSetCreationDate
+
+ DESCRIPTION :
+
+ For the given tape family id and backup set, return the creation date of the lpwest numbered set available.
+
+**********************/
+
+
+BOOLEAN VLM_GetSetCreationDate( UINT32 tape_fid, INT16 bset_num, INT16 *date, INT16 *time )
+{
+
+ TAPE_OBJECT_PTR tape;
+ BSET_OBJECT_PTR bset;
+
+ tape = VLM_GetFirstTAPE( );
+
+ while ( tape != NULL ) {
+
+ if ( tape->tape_fid == tape_fid ) {
+
+ bset = VLM_GetFirstBSET( &tape->bset_list );
+
+ while ( bset != NULL ) {
+
+ if ( bset->bset_num == bset_num ) {
+ *date = bset->backup_date;
+ *time = bset->backup_time;
+ return( SUCCESS );
+ }
+
+ bset = VLM_GetNextBSET( bset );
+ }
+
+ }
+ tape = VLM_GetNextTAPE( tape );
+ }
+
+ return( FAILURE );
+}
+
+
+
+/**********************
+
+ NAME : VLM_GetTapeCreationDate
+
+ DESCRIPTION :
+
+ For the given tape family id and backup set, return the creation date of the lpwest numbered set available.
+
+**********************/
+
+
+BOOLEAN VLM_GetTapeCreationDate( UINT32 tape_fid, INT16 *date, INT16 *time )
+{
+
+ TAPE_OBJECT_PTR tape;
+ BSET_OBJECT_PTR bset = NULL;
+ BSET_OBJECT_PTR temp;
+
+ tape = VLM_GetFirstTAPE( );
+
+ while ( tape != NULL ) {
+
+ if ( tape->tape_fid == tape_fid ) {
+
+ temp = VLM_GetFirstBSET( &tape->bset_list );
+
+ if ( temp != NULL ) {
+
+ if ( bset == NULL ) {
+ bset = temp;
+ }
+
+ if ( temp->bset_num < bset->bset_num ) {
+ bset = temp;
+ }
+
+ }
+
+ }
+ tape = VLM_GetNextTAPE( tape );
+ }
+
+ if ( bset != NULL ) {
+ *time = bset->backup_time;
+ *date = bset->backup_date;
+ }
+
+ return( SUCCESS );
+}
+
+
+/**********************
+
+ NAME : VLM_GetTapeOwnersName
+
+ DESCRIPTION :
+
+ For the given tape family id and backup set, return the owners name.
+
+**********************/
+
+
+BOOLEAN VLM_GetTapeOwnersName( UINT32 tape_fid, CHAR_PTR buffer )
+{
+
+ TAPE_OBJECT_PTR tape;
+ BSET_OBJECT_PTR bset = NULL;
+ BSET_OBJECT_PTR temp;
+
+ tape = VLM_GetFirstTAPE( );
+
+ while ( tape != NULL ) {
+
+ if ( tape->tape_fid == tape_fid ) {
+
+ temp = VLM_GetFirstBSET( &tape->bset_list );
+
+ while ( temp != NULL ) {
+
+ if ( bset == NULL ) {
+ bset = temp;
+ }
+
+ if ( bset->bset_num >= temp->bset_num ) {
+
+ strcpy( buffer, bset->user_name );
+ }
+
+ temp = VLM_GetNextBSET( temp );
+ }
+
+ }
+ tape = VLM_GetNextTAPE( tape );
+ }
+
+
+ if ( bset == NULL ) {
+ strcpy( buffer, TEXT(" ") );
+ }
+
+ return( FAILURE );
+}
+
+
+/**********************
+
+ NAME : VLM_GetSetOwnersName
+
+ DESCRIPTION :
+
+ For the given tape family id and backup set, return the owners name.
+
+**********************/
+
+
+BOOLEAN VLM_GetSetOwnersName( UINT32 tape_fid, INT16 bset_num, CHAR_PTR buffer )
+{
+ TAPE_OBJECT_PTR tape;
+ BSET_OBJECT_PTR bset;
+
+ tape = VLM_GetFirstTAPE( );
+
+ while ( tape != NULL ) {
+
+ if ( tape->tape_fid == tape_fid ) {
+
+ bset = VLM_GetFirstBSET( &tape->bset_list );
+
+ while ( bset != NULL ) {
+
+ if ( bset->bset_num == bset_num ) {
+
+ strcpy( buffer, bset->user_name );
+ return( SUCCESS );
+ }
+
+ bset = VLM_GetNextBSET( bset );
+ }
+
+ }
+ tape = VLM_GetNextTAPE( tape );
+ }
+
+ strcpy( buffer, TEXT(" ") );
+ return( FAILURE );
+}
+
+
+/**********************
+
+ NAME : VLM_GetVolumeName
+
+ DESCRIPTION :
+
+ For the given tape family id and backup set, return the volume name.
+
+**********************/
+
+
+CHAR_PTR VLM_GetVolumeName( UINT32 tape_fid, INT16 bset_num )
+{
+ TAPE_OBJECT_PTR tape;
+ BSET_OBJECT_PTR bset;
+
+ tape = VLM_GetFirstTAPE( );
+
+ while ( tape != NULL ) {
+
+ if ( tape->tape_fid == tape_fid ) {
+
+ bset = VLM_GetFirstBSET( &tape->bset_list );
+
+ while ( bset != NULL ) {
+
+ if ( bset->bset_num == bset_num ) {
+ return( bset->volume_name );
+ }
+
+ bset = VLM_GetNextBSET( bset );
+ }
+
+ }
+ tape = VLM_GetNextTAPE( tape );
+ }
+
+ return( NULL );
+}
+
+
+/**********************
+
+ NAME : VLM_RemoveUnusedBSDs
+
+ DESCRIPTION :
+
+ A tape function is about to happen and we want to remove any BSD's that
+ are not important, because they have no FSE's.
+
+ RETURNS : nothing.
+
+**********************/
+
+
+VOID VLM_RemoveUnusedBSDs( BSD_HAND bsd_list )
+{
+ BSD_PTR bsd, bsd_to_remove;
+
+ bsd = BSD_GetFirst( bsd_list );
+
+ while ( bsd != NULL ) {
+
+ /* Check if the BSD has any selections */
+
+ if ( BSD_GetMarkStatus( bsd ) == NONE_SELECTED ) {
+
+ /* No, then remove it */
+ bsd_to_remove = bsd;
+ bsd = BSD_GetNext( bsd );
+ BSD_Remove( bsd_to_remove );
+ }
+ else {
+ bsd = BSD_GetNext( bsd );
+ }
+
+ }
+}
+
+
+/***************************************************
+
+ Name: VLM_AnySelFiles ()
+
+ Description: checks msii directory for the existence of
+ any files containing file selection scripts
+
+ Modified:
+
+ Returns: BOOL true if any selection files were found;
+ false otherwise
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+INT VLM_AnySelFiles( )
+{
+ BOOLEAN rtn = FALSE; //Return value
+ VLM_FIND_PTR vlm_find = NULL;
+ CHAR *path;
+ CHAR file[VLM_MAXFNAME];
+
+ path = (CHAR *)malloc( strsize( CDS_GetUserDataPath() ) + 256 );
+
+ if ( path != NULL ) {
+
+ strcpy( path, CDS_GetUserDataPath() );
+ strcat( path, SELECTION_EXTENSION );
+
+ if ( vlm_find = VLM_FindFirst( path, VLMFIND_NORMAL, file ) ) {
+ rtn = TRUE;
+ VLM_FindClose( &vlm_find );
+ }
+
+ free( path );
+ }
+
+ return( rtn );
+}
+
+
+/***************************************************
+
+ Name: VLM_AnyDiskSelections
+
+ Description: Tells whether any files have been selected for backup
+ from the disk list.
+
+ Modified: 19 July 1991
+
+ Returns: TRUE if any files are selected; FALSE otherwise
+
+ Notes:
+
+ See also: VLM_AnyTapeSelections()
+
+*****************************************************/
+
+INT VLM_AnyDiskSelections( )
+{
+ BSD_PTR bsd;
+
+ bsd = BSD_GetFirst( bsd_list );
+
+ while ( bsd != NULL ) {
+
+ if ( BSD_GetMarkStatus ( bsd ) != NONE_SELECTED ) {
+ return( TRUE );
+ }
+ bsd = BSD_GetNext ( bsd );
+ }
+
+ return( FALSE );
+}
+
+/***************************************************
+
+ Name: VLM_AnyTapeSelections ()
+
+ Description: Tells whether any files have been selected for restore
+ from the tape list.
+
+ Modified: 19 July 1991
+
+ Returns: TRUE if any files are selected; FALSE otherwise
+
+ Notes:
+
+ See also: VLM_AnyDiskSelections()
+
+*****************************************************/
+
+INT VLM_AnyTapeSelections( )
+{
+ BSD_PTR bsd;
+
+ bsd = BSD_GetFirst( tape_bsd_list );
+
+ while ( bsd != NULL ) {
+
+ if ( BSD_GetMarkStatus( bsd ) != NONE_SELECTED ) {
+ return( TRUE );
+ }
+ bsd = BSD_GetNext( bsd );
+ }
+
+ return( FALSE );
+}
+
+/***************************************************
+
+ Name: VLM_LoadDefaultSelections ()
+
+ Description: checks to see if there is a file called default.bks;
+ if there is, that file is parsed, and the files it
+ specifies are selected as defaults
+
+ Modified: 9-12-91
+
+ Returns: VOID
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+VOID VLM_LoadDefaultSelections ( )
+{
+#if !defined ( OEM_MSOFT ) //unsupported feature
+
+ CHAR *path;
+ CHAR file[ VLM_MAXFNAME ];
+ CHAR text[ MAX_UI_RESOURCE_SIZE ];
+ CHAR exten[ MAX_UI_SMALLRES_SIZE ];
+ HWND win;
+ CDS_PTR cds_ptr;
+ WININFO_PTR wininfo;
+ VLM_FIND_PTR vlm_find = NULL;
+
+
+ path = malloc( strsize( CDS_GetMaynFolder() ) + 256 );
+
+ if ( path == NULL ) {
+ return;
+ }
+
+ RSM_StringCopy( IDS_VLMSTARTUPBKS, text, MAX_UI_RESOURCE_LEN );
+ RSM_StringCopy( IDS_SELECTIONEXTENSION, exten, MAX_UI_SMALLRES_LEN );
+
+ strcpy( path, CDS_GetMaynFolder() );
+ strcat( path, text );
+ strcat( path, exten );
+
+ if ( vlm_find = VLM_FindFirst ( path, VLMFIND_NORMAL, file ) ) {
+
+ // re-write the path with a @ as the first character,
+ // and call the parser
+
+ strcpy( path, TEXT( '@' ) );
+ strcat( path, CDS_GetMaynFolder() );
+ strcat( path, text );
+ strcat( path, exten );
+
+ cds_ptr = CDS_GetPerm();
+ tbrparse( &cds_ptr, dle_list, bsd_list, path, TBACKUP, NULL );
+
+ // update the windows to show the selections
+
+ win = WM_GetNext( (HWND) NULL );
+
+ while ( win != (HWND) NULL ) {
+
+ wininfo = WM_GetInfoPtr( win );
+
+ if ( wininfo->wType == WMTYPE_DISKTREE ) {
+
+ VLM_RematchList( win );
+ }
+ win = WM_GetNext( win );
+ }
+
+ VLM_UpdateDisks( );
+ VLM_UpdateServers( );
+
+ VLM_FindClose( &vlm_find );
+ }
+
+#endif //!defined ( OEM_MSOFT ) //unsupported feature
+}
+
+/***************************************************
+
+ Name: VLM_UpdateDisks()
+
+ Description: Determines how to check a disk in the disk window
+ when a selection script is used, and updates the
+ disk window with the appropriate marks.
+
+ Modified: 19 July 1991
+
+ Returns: nuthin'
+
+ Notes:
+
+ See also:
+
+*****************************************************/
+
+
+VOID VLM_UpdateDisks( )
+{
+ GENERIC_DLE_PTR dle;
+ BSD_PTR bsd;
+ VLM_OBJECT_PTR vlm;
+ WININFO_PTR wininfo;
+ UINT32 old_status;
+ INT16 bset_num;
+ QTC_BSET_PTR qtc_bset;
+ QTC_HEADER_PTR header;
+
+#ifdef OEM_EMS
+ UNREFERENCED_PARAMETER( qtc_bset );
+ UNREFERENCED_PARAMETER( header );
+ UNREFERENCED_PARAMETER( bset_num );
+#endif
+
+ wininfo = WM_GetInfoPtr( gb_disks_win );
+
+ if ( wininfo != NULL ) {
+
+ vlm = VLM_GetFirstVLM( wininfo->pFlatList );
+
+
+ while ( vlm != NULL ) {
+
+ old_status = vlm->status & (UINT16)(INFO_SELECT|INFO_PARTIAL);
+ vlm->status &= ~( INFO_PARTIAL | INFO_SELECT );
+
+ DLE_FindByName( dle_list, vlm->name, ANY_DRIVE_TYPE, &dle );
+
+ bsd = BSD_FindByDLE( bsd_list, dle );
+
+ if ( bsd != NULL ) { // not likely, but possible nonetheless
+
+ switch ( BSD_GetMarkStatus( bsd ) ) {
+
+ case ALL_SELECTED:
+ vlm->status |= INFO_SELECT;
+ break;
+
+ case SOME_SELECTED:
+ vlm->status |= (INFO_SELECT|INFO_PARTIAL);
+ break;
+
+ default:
+ break;
+ }
+
+ }
+
+ // Update the check mark
+
+ if ( old_status != (UINT16)(vlm->status & (INFO_SELECT|INFO_PARTIAL) ) ) {
+
+ DLM_Update( gb_disks_win,
+ DLM_FLATLISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)vlm, 0 );
+ }
+
+ vlm = VLM_GetNextVLM( vlm );
+ }
+
+ }
+}
+
+
+/**********************
+
+ NAME : VLM_UpdateVolumes
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+VOID VLM_UpdateVolumes( VLM_OBJECT_PTR server_vlm )
+{
+ GENERIC_DLE_PTR dle;
+ BSD_PTR bsd;
+ VLM_OBJECT_PTR child_vlm;
+ INT16 bset_num;
+ QTC_BSET_PTR qtc_bset;
+ QTC_HEADER_PTR header;
+
+#ifdef OEM_EMS
+ UNREFERENCED_PARAMETER( qtc_bset );
+ UNREFERENCED_PARAMETER( header );
+ UNREFERENCED_PARAMETER( bset_num );
+#endif
+
+ child_vlm = VLM_GetFirstVLM( &server_vlm->children );
+
+ while ( child_vlm != NULL ) {
+
+ child_vlm->status &= ~(INFO_SELECT|INFO_PARTIAL);
+
+ DLE_FindByName( dle_list, child_vlm->name, ANY_DRIVE_TYPE, &dle );
+
+ bsd = BSD_FindByDLE( bsd_list, dle );
+
+ if ( bsd != NULL ) {
+
+ switch ( BSD_GetMarkStatus( bsd ) ) {
+
+ case ALL_SELECTED:
+ child_vlm->status |= INFO_SELECT;
+ break;
+
+ case SOME_SELECTED:
+ child_vlm->status |= (INFO_SELECT|INFO_PARTIAL);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ child_vlm = VLM_GetNextVLM( child_vlm );
+ }
+
+}
+
+
+/**********************
+
+ NAME : VLM_UpdateServers
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+VOID VLM_UpdateServers( )
+{
+#if !defined( CAYMAN )
+#if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ VLM_OBJECT_PTR vlm;
+ VLM_OBJECT_PTR child_vlm;
+ WININFO_PTR wininfo;
+ UINT16 status;
+
+ if ( gb_servers_win == (HWND)NULL ) {
+ return;
+ }
+
+ wininfo = WM_GetInfoPtr( gb_servers_win );
+
+ if ( wininfo ) {
+
+ vlm = VLM_GetFirstVLM( wininfo->pTreeList );
+
+ while ( vlm != NULL ) {
+
+ if ( QueueCount( &vlm->children ) ) {
+
+ VLM_UpdateVolumes( vlm );
+
+ child_vlm = VLM_GetFirstVLM( &vlm->children );
+
+ status = child_vlm->status & (UINT16)(INFO_SELECT|INFO_PARTIAL);
+
+ while ( child_vlm != NULL ) {
+
+ if ( status != ( child_vlm->status & (UINT16)(INFO_SELECT|INFO_PARTIAL) ) ) {
+ status = INFO_SELECT|INFO_PARTIAL;
+ break;
+ }
+ child_vlm = VLM_GetNextVLM( child_vlm );
+ }
+
+ vlm->status &= ~(INFO_SELECT|INFO_PARTIAL);
+ vlm->status |= status;
+ }
+ else {
+ vlm->status &= ~(INFO_SELECT|INFO_PARTIAL);
+ }
+
+ vlm = VLM_GetNextVLM( vlm );
+ }
+
+ DLM_Update( gb_servers_win, DLM_FLATLISTBOX, WM_DLMUPDATELIST,
+ (LMHANDLE)NULL, 0 );
+ DLM_Update( gb_servers_win, DLM_TREELISTBOX, WM_DLMUPDATELIST,
+ (LMHANDLE)NULL, 0 );
+ }
+ }
+#endif //!defined ( OEM_MSOFT ) //unsupported feature
+#endif
+}
+
+
+/**********************
+
+ NAME : VLM_CloseWin
+
+ DESCRIPTION :
+
+ Close the given window and free its lists.
+
+ RETURNS : nothing.
+
+**********************/
+
+VOID VLM_CloseWin(
+HWND win ) // I - window to close
+{
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ TAPE_OBJECT_PTR tape;
+ Q_ELEM_PTR q_elem;
+ Q_ELEM_PTR q_elem2;
+ DLM_LOGITEM_PTR dlm_ptr;
+ GENERIC_DLE_PTR enterprise_dle;
+
+ /* Now get the list so that it can be free'd */
+
+ wininfo = WM_GetInfoPtr( win );
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( win );
+
+ if ( ( appinfo != NULL ) && ( wininfo->wType != WMTYPE_LOGVIEW ) ) {
+
+ if ( appinfo->fsh != NULL ) {
+ FS_DetachDLE( appinfo->fsh );
+ }
+
+ if ( appinfo->server_fsh != NULL ) {
+ FS_DetachDLE( appinfo->server_fsh );
+ }
+ }
+
+ switch ( wininfo->wType ) {
+
+ case WMTYPE_LOGVIEW:
+
+ // Clear and free pointers of blocks.
+
+ dlm_ptr = (DLM_LOGITEM_PTR)WMDS_GetAppInfo( wininfo );
+
+ if ( dlm_ptr ) {
+
+ // Deallocate the memory blocks used in viewing the file.
+
+ LOG_ClearBlocks( dlm_ptr );
+
+ if ( L_GetFilePtr( dlm_ptr ) ) {
+ fclose( L_GetFilePtr( dlm_ptr ) );
+ }
+
+ if ( L_GetArrayPtr( dlm_ptr ) ) {
+ free( L_GetArrayPtr( dlm_ptr ) );
+ }
+
+ if ( L_GetBuffer( dlm_ptr ) ) {
+ free( L_GetBuffer( dlm_ptr ) );
+ }
+
+ if ( L_GetFilePtr( dlm_ptr ) ) {
+ fclose( L_GetFilePtr( dlm_ptr ) );
+ L_SetFilePtr( dlm_ptr, NULL );
+ }
+
+ }
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ ghWndLogFileView = (HWND)NULL;
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+
+ break;
+
+ case WMTYPE_DISKS:
+ VLM_FreeVLMList( wininfo->pFlatList );
+ free( wininfo->pFlatList );
+ break;
+
+#ifdef OEM_EMS
+ case WMTYPE_EXCHANGE:
+
+ // Check for closable because we may change this window type to MDISECONDARY later
+ if ( wininfo->wClosable ) {
+
+ if ( ( NULL != WMDS_GetTreeList( wininfo ) ) &&
+ ( NULL != VLM_GetFirstSLM( WMDS_GetTreeList( wininfo ) ) ) ) {
+
+ enterprise_dle = SLM_GetDle( VLM_GetFirstSLM( WMDS_GetTreeList( wininfo ) ) );
+ }
+
+ SLM_EMSFreeSLMList( wininfo->pTreeList );
+ free( wininfo->pFlatList );
+ SLM_EMSFreeSLMList( wininfo->pFlatList );
+ free( wininfo->pFlatList );
+
+
+ }
+ break;
+#endif //OEM_EMS
+
+ case WMTYPE_SERVERS:
+ VLM_FreeVLMList( wininfo->pTreeList );
+ free( wininfo->pTreeList );
+ break;
+
+ case WMTYPE_TAPES:
+ q_elem = DeQueueElem( wininfo->pTreeList );
+ while ( q_elem ) {
+
+ tape = (TAPE_OBJECT_PTR)q_elem->q_ptr;
+
+ // free all his bset's
+
+ q_elem2 = DeQueueElem( &TAPE_GetBsetQueue( tape ) );
+
+ while ( q_elem2 ) {
+ free( q_elem2->q_ptr );
+ q_elem2 = DeQueueElem( &TAPE_GetBsetQueue( tape ) );
+ }
+
+ free( q_elem->q_ptr );
+ q_elem = DeQueueElem( wininfo->pTreeList );
+ }
+ free( wininfo->pTreeList );
+ wininfo->pTreeList = NULL ;
+ break;
+
+ case WMTYPE_SEARCH:
+
+ q_elem = DeQueueElem( wininfo->pFlatList );
+
+ while ( q_elem ) {
+ free( q_elem->q_ptr );
+ q_elem = DeQueueElem( wininfo->pFlatList );
+ }
+ free( wininfo->pFlatList );
+ gb_search_win = (HWND)NULL;
+ break;
+
+ default:
+ if ( wininfo->pFlatList != NULL ) {
+
+ q_elem = DeQueueElem( wininfo->pFlatList );
+
+ while ( q_elem != NULL ) {
+
+ free( q_elem->q_ptr );
+ q_elem = DeQueueElem( wininfo->pFlatList );
+ }
+ free( wininfo->pFlatList );
+ }
+
+ if ( wininfo->pTreeList != NULL ) {
+
+ q_elem = DeQueueElem( wininfo->pTreeList );
+
+ while ( q_elem != NULL ) {
+
+ free( q_elem->q_ptr );
+ q_elem = DeQueueElem( wininfo->pTreeList );
+ }
+ free( wininfo->pTreeList );
+ wininfo->pTreeList = NULL ;
+ }
+ break;
+
+ }
+
+ // Clean exit routine up
+
+ if ( win == gb_tapes_win ) {
+ gb_tapes_win = (HWND)NULL;
+ }
+#if !defined ( CAYMAN )
+# if !defined ( OEM_MSOFT ) //unsupported feature
+ {
+ if ( win == gb_servers_win ) {
+ gb_servers_win = (HWND)NULL;
+ }
+ }
+# endif //!defined ( OEM_MSOFT ) //unsupported feature
+#endif // !defined ( CAYMAN )
+
+ if ( win == gb_disks_win ) {
+ gb_disks_win = (HWND)NULL;
+ }
+
+ if ( appinfo ) {
+ free( appinfo );
+ }
+
+ if ( wininfo ) {
+ free( wininfo );
+ WM_SetInfoPtr( win, NULL );
+ }
+}
+
+
+
+/**********************
+
+ NAME : VLM_MarkAllSLMChildren
+
+ DESCRIPTION :
+
+ Given an slm pointer, mark all his children as selected, unselected, or
+ partially selected.
+
+ attr: 2 = partial
+ 1 = selected
+ 0 = unselected
+
+ RETURNS :
+
+**********************/
+
+VOID VLM_MarkAllSLMChildren(
+
+SLM_OBJECT_PTR slm, // I - slm to use
+INT16 attr, // I - attribute to set
+INT_PTR total_dirs_ptr,
+INT_PTR total_files_ptr,
+UINT64_PTR total_bytes_ptr )
+
+{
+
+ BOOLEAN all_subdirs;
+ INT level;
+ HWND window;
+ INT new_files;
+ UINT64 new_bytes;
+ BOOLEAN u64_stat;
+ SLM_OBJECT_PTR parent_slm;
+ SLM_OBJECT_PTR orig_slm;
+
+#ifdef OEM_EMS
+ UNREFERENCED_PARAMETER( u64_stat );
+ UNREFERENCED_PARAMETER( parent_slm );
+ UNREFERENCED_PARAMETER( new_bytes );
+ UNREFERENCED_PARAMETER( new_files );
+#endif
+
+ window = slm->XtraBytes->hWnd;
+ all_subdirs = CDS_GetIncludeSubdirs( CDS_GetPerm() );
+ orig_slm = slm;
+
+ *total_dirs_ptr = 0;
+ *total_files_ptr = 0;
+ *total_bytes_ptr = U64_Init( 0L, 0L );
+
+ if ( attr && ( ! all_subdirs ) ) {
+
+ // Do nothing his subdirectories weren't selected.
+
+ }
+ else {
+
+ level = slm->level;
+
+ slm = VLM_GetNextSLM( slm );
+
+ while ( slm != NULL ) {
+
+ if ( slm->level <= level ) {
+ break;
+ }
+
+ if ( SLM_GetStatus( slm ) & INFO_OPEN ) {
+
+ if ( attr ) {
+ VLM_FileListManager( window, FLM_SEL_ALL );
+ }
+ else {
+ VLM_FileListManager( window, FLM_SEL_NONE );
+ }
+ }
+
+ if ( attr ) {
+
+ if ( ( SLM_GetStatus( slm ) & (INFO_PARTIAL|INFO_SELECT) ) != INFO_SELECT ) {
+
+ slm->status |= INFO_SELECT;
+ slm->status &= ~INFO_PARTIAL;
+
+ DLM_Update( window, DLM_TREELISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)slm, 0 );
+ }
+ }
+ else {
+
+ if ( slm->status & (INFO_PARTIAL|INFO_SELECT) ) {
+
+ slm->status &= ~(INFO_SELECT|INFO_PARTIAL);
+
+ DLM_Update( window, DLM_TREELISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)slm, 0 );
+ }
+ }
+
+ slm = VLM_GetNextSLM( slm );
+ }
+ }
+
+ return;
+
+}
+
+
+/**********************
+
+ NAME : VLM_MakeAllParentsPartial
+
+ DESCRIPTION :
+
+ Anytime we select or unselect a single file or directory all its
+ parent directories must be marked as partially selected. This
+ function will do that work for you. when you are moving up the
+ list, you can stop at the first partially selected directory.
+
+ RETURNS :
+
+**********************/
+
+VOID VLM_MakeAllParentsPartial(
+SLM_OBJECT_PTR slm ) // I - slm to use
+{
+ INT level;
+ APPINFO_PTR appinfo;
+
+ level = slm->level;
+ appinfo = ( APPINFO_PTR )( slm->XtraBytes->pAppInfo );
+
+ do {
+
+ // Is it a parent directory ?
+
+ if ( slm->level == level ) {
+
+ if ( ( slm->status & ( INFO_SELECT | INFO_PARTIAL ) ) ==
+ ( INFO_SELECT | INFO_PARTIAL ) ) {
+ break;
+ }
+ else {
+ slm->status |= ( INFO_SELECT | INFO_PARTIAL );
+ DLM_Update( appinfo->win, DLM_TREELISTBOX, WM_DLMUPDATEITEM,
+ (LMHANDLE)slm, 0 );
+ }
+
+ level--;
+ }
+
+ slm = VLM_GetPrevSLM( slm );
+
+ } while ( slm != NULL );
+
+}
+
+
+/**********************
+
+ NAME : VLM_ClearAllSelections
+
+ DESCRIPTION :
+
+ After we complete a backup or restore we need to clear out all our
+ selections so the user can start fresh. This routine does that for
+ you. Note that restore as well as backup selections are blown away
+ at the same time. Restore selections may have become invalid during
+ a transfer. And backup selections may be confused by a restore.
+
+ RETURNS :
+
+**********************/
+
+VOID VLM_ClearAllSelections( )
+{
+ BSD_PTR bsd;
+
+ bsd = BSD_GetFirst( tape_bsd_list );
+ while ( bsd != NULL ) {
+ BSD_Remove( bsd );
+ bsd = BSD_GetFirst( tape_bsd_list );
+ }
+
+ bsd = BSD_GetFirst( bsd_list );
+ while ( bsd != NULL ) {
+ BSD_Remove( bsd );
+ bsd = BSD_GetFirst( bsd_list );
+ }
+
+ VLM_ClearAllTapeSelections();
+ VLM_ClearAllTreeSelections();
+ VLM_ClearAllDiskSelections();
+ VLM_ClearAllSearchSelections();
+ VLM_ClearAllServerSelections();
+#ifdef OEM_EMS
+ VLM_ClearAllExchangeSelections();
+#endif //OEM_EMS
+}
+
+
+
+/**********************
+
+ NAME : VLM_RematchList
+
+ DESCRIPTION :
+
+ The user has added or removed an advanced selection to the FSE list.
+ Now since we have no clue, which directories and files are now selected
+ we need to rerun the entire SLM and FLM lists through BSD Match.
+
+ RETURNS :
+
+**********************/
+
+VOID VLM_RematchList(
+HWND win ) // I - window to rematch lists on
+{
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ BSD_PTR bsd_ptr;
+ FLM_OBJECT_PTR flm;
+ FSE_PTR fse;
+ CHAR *buffer = NULL;
+ CHAR *path = NULL;
+ CHAR_PTR s;
+ INT16 result;
+ INT16 path_len;
+ INT16 psize;
+ UINT16 status;
+ DATE_TIME mod_date;
+ DATE_TIME acc_date;
+
+ wininfo = WM_GetInfoPtr( win );
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( win );
+
+ // see if there is a BSD to match against
+
+ if ( appinfo->dle != NULL ) {
+
+ bsd_ptr = BSD_FindByDLE( bsd_list, appinfo->dle );
+
+ }
+ else {
+
+ bsd_ptr = BSD_FindByTapeID( tape_bsd_list,
+ appinfo->tape_fid,
+ appinfo->bset_num );
+ }
+
+ // if no BSD, no matches
+
+ if ( ( bsd_ptr == NULL ) ||
+ ( BSD_GetMarkStatus ( bsd_ptr ) == NONE_SELECTED ) ) {
+
+ VLM_DeselectAll( wininfo, TRUE );
+ return;
+
+ }
+
+ // match the SLM list and generate selected totals
+
+ VLM_MatchSLMList( wininfo, bsd_ptr, TRUE );
+
+ // Now do the flat list of files and directories
+
+ path = VLM_BuildPath( appinfo->open_slm );
+
+ s = path;
+ path_len = 0;
+ while ( *s ) {
+ if ( *s == TEXT('\\') ) *s = 0;
+ s++;
+ path_len++;
+ }
+
+ path_len++; // add in final zero
+
+ flm = VLM_GetFirstFLM( wininfo->pFlatList );
+
+ while ( flm != NULL ) {
+
+ DateTimeDOS( flm->mod_date, flm->mod_time, &mod_date );
+ DateTimeDOS( flm->acc_date, flm->acc_time, &acc_date );
+
+ if ( flm->status & INFO_ISADIR ) {
+
+ free( buffer );
+
+ buffer = malloc( ( path_len * 2 ) + strsize( flm->name ) );
+
+ if ( path_len != sizeof( CHAR ) ) {
+
+ memcpy( buffer, path, path_len * sizeof(CHAR) );
+ strcpy( &buffer[ path_len ], flm->name );
+ psize = (UINT16)(path_len + strlen(flm->name) + 1);
+ }
+ else {
+ strcpy( buffer, flm->name );
+ psize = (UINT16) (strlen( flm->name ) + 1);
+ }
+
+ psize *= sizeof( CHAR ); // convert to bytes
+
+ result = BSD_MatchPathAndFile( bsd_ptr, &fse, NULL,
+ buffer,
+ psize,
+ flm->attrib,
+ &mod_date, &acc_date, NULL,
+ FALSE, TRUE );
+ status = 0;
+
+ if ( result == BSD_PROCESS_OBJECT ) {
+ status = INFO_SELECT | INFO_PARTIAL;
+ }
+
+ if ( result == BSD_PROCESS_ENTIRE_DIR ) {
+ status = INFO_SELECT;
+ }
+
+ if ( (UINT16)( flm->status & (INFO_SELECT|INFO_PARTIAL) ) != status ) {
+
+ flm->status &= ~(INFO_SELECT|INFO_PARTIAL);
+ flm->status |= status;
+
+ DLM_Update( win, DLM_FLATLISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)flm, 0 );
+ }
+ }
+ else {
+
+ path_len *= sizeof( CHAR ); // convert to bytes
+
+ result = BSD_MatchPathAndFile( bsd_ptr, &fse, flm->name,
+ path,
+ path_len,
+ flm->attrib,
+ &mod_date, &acc_date,
+ NULL, FALSE, TRUE );
+
+ if ( result == BSD_PROCESS_OBJECT ) {
+ status = INFO_SELECT;
+ }
+ else {
+ status = 0;
+ }
+
+ if ( (UINT16)( flm->status & (INFO_SELECT|INFO_PARTIAL) ) != status ) {
+
+ flm->status &= ~(INFO_SELECT|INFO_PARTIAL);
+ flm->status |= status;
+
+ DLM_Update( win, DLM_FLATLISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)flm, 0 );
+ }
+
+ }
+
+ flm = VLM_GetNextFLM( flm );
+ }
+
+ free( path );
+ free( buffer );
+
+ VLM_UpdateRoot( win );
+
+ return;
+
+}
+
+
+/**********************
+
+ NAME : VLM_MatchSLMList
+
+ DESCRIPTION :
+
+ Run the entire SLM and file lists for partially selected directories
+ through BSD Match.
+
+ RETURNS :
+
+**********************/
+
+VOID VLM_MatchSLMList(
+
+WININFO_PTR wininfo, //I - wininfo structure
+BSD_PTR bsd_ptr, //I - BSD to match against
+BOOLEAN display ) //I - update display flag
+
+{
+ HWND win;
+ SLM_OBJECT_PTR slm;
+ FSE_PTR fse;
+ CHAR *path = NULL;
+ CHAR_PTR s;
+ INT16 result;
+ INT16 path_len;
+ UINT16 status;
+ DATE_TIME mod_date;
+ SLM_OBJECT_PTR parent_slm;
+
+#ifdef OEM_EMS
+ UNREFERENCED_PARAMETER( parent_slm );
+#endif
+
+ slm = VLM_GetFirstSLM( wininfo->pTreeList );
+
+ if ( display && ( slm != NULL ) ) {
+ win = slm->XtraBytes->hWnd;
+ }
+
+ while ( slm != NULL ) {
+
+ free( path );
+
+ path = VLM_BuildPath( slm );
+ s = path;
+ path_len = 0;
+ while ( *s ) {
+ if ( *s == TEXT('\\') ) *s = 0;
+ s++;
+ path_len++;
+ }
+ path_len++;
+
+ DateTimeDOS( slm->date, slm->time, &mod_date );
+
+ path_len *= sizeof( CHAR );
+
+ result = BSD_MatchPathAndFile( bsd_ptr, &fse, NULL,
+ path,
+ path_len,
+ slm->attrib,
+ &mod_date, NULL, NULL, FALSE, TRUE );
+
+ status = 0;
+
+ if ( result == BSD_PROCESS_OBJECT ) {
+ status = INFO_SELECT | INFO_PARTIAL;
+ }
+
+ if ( result == BSD_PROCESS_ENTIRE_DIR ) {
+ status = INFO_SELECT;
+ }
+
+ // if selection status has changed, update it
+
+ if ( (UINT16)( slm->status & (INFO_SELECT|INFO_PARTIAL) ) != status ) {
+
+ slm->status &= ~(INFO_SELECT|INFO_PARTIAL);
+ slm->status |= status;
+
+ if ( display ) {
+ DLM_Update( win, DLM_TREELISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)slm, 0 );
+ }
+
+ }
+
+ slm = VLM_GetNextSLM( slm );
+ }
+
+ free( path );
+
+ return;
+
+}
+
+
+/**********************
+
+ NAME : VLM_AddPartials
+
+ DESCRIPTION :
+
+ Run through the entire file list for a path and calculate the selected
+ file sizes.
+
+ RETURNS : SUCCESS
+ FAILURE
+
+**********************/
+
+INT VLM_AddPartials(
+
+CHAR_PTR path,
+INT16 path_length,
+BSD_PTR bsd_ptr,
+UINT32 tape_fid,
+INT16 bset_num,
+INT_PTR sel_files_ptr,
+UINT64_PTR sel_bytes_ptr )
+
+{
+ INT16 result;
+ QTC_QUERY_PTR query;
+ FSE_PTR fse;
+ DATE_TIME acc_date;
+ DATE_TIME mod_date;
+ BOOLEAN u64_stat;
+
+ // first set totals to zero
+
+ *sel_files_ptr = 0;
+ *sel_bytes_ptr = U64_Init( 0L, 0L );
+
+ acc_date.date_valid = FALSE;
+
+ // Tell the catalogs which bset & tape family to use
+
+ query = QTC_InitQuery();
+
+ if ( query == NULL ) {
+ return( FAILURE );
+ }
+
+ QTC_SetTapeFID( query, tape_fid );
+ QTC_SetTapeSeq( query, -1 );
+ QTC_SetBsetNum( query, bset_num );
+
+ QTC_SetSearchPath( query, path, path_length );
+
+ // start loop to get each file
+
+ result = (INT16) QTC_GetFirstObj( query );
+
+ while ( ! result ) {
+
+ if ( ! ( QTC_GetItemStatus( query ) & QTC_DIRECTORY ) ) {
+
+ // use the BSD_Match function to see if it's selected
+
+ DateTimeDOS( QTC_GetItemDate( query ),
+ QTC_GetItemTime( query ), &mod_date );
+
+ result = BSD_MatchPathAndFile( bsd_ptr, &fse,
+ QTC_GetItemName( query ),
+ QTC_GetPath( query ),
+ (INT16) QTC_GetPathLength( query ),
+ QTC_GetItemAttrib( query ),
+ &mod_date, &acc_date, NULL,
+ FALSE, TRUE );
+
+ if ( result == BSD_PROCESS_OBJECT ) {
+
+ // increment the number of files and add its size to the total
+
+ (*sel_files_ptr)++;
+ *sel_bytes_ptr = U64_Add( *sel_bytes_ptr, QTC_GetItemSize( query ), &u64_stat );
+
+ }
+
+ }
+
+ // get the next file/dir.
+
+ result = (INT16) QTC_GetNextObj( query );
+ }
+
+ QTC_CloseQuery( query );
+
+ return( SUCCESS );
+
+}
+
+
+/**********************
+
+ NAME : VLM_RematchAllSelections
+
+ DESCRIPTION :
+
+ Currently if an error occurs during backup, we occasionally save pieces
+ of the bsd list. This function will update every check box known to man.
+
+ RETURNS :
+
+**********************/
+
+VOID VLM_RematchAllLists( )
+{
+ HWND win;
+ WININFO_PTR wininfo;
+
+ win = WM_GetNext( (HWND)NULL );
+
+ while ( win ) {
+
+ wininfo = WM_GetInfoPtr( win );
+
+ switch ( wininfo->wType ) {
+
+ case WMTYPE_DISKTREE:
+ case WMTYPE_TAPETREE:
+ VLM_RematchList( win );
+ break;
+
+ case WMTYPE_TAPES:
+ VLM_UpdateTapes();
+ break;
+
+ case WMTYPE_DISKS:
+ VLM_UpdateDisks();
+ break;
+
+#ifdef OEM_EMS
+ case WMTYPE_EXCHANGE:
+ // VLM_UpdateExchange( win ); - Function doesn't do what is needed.
+ break;
+#endif //OEM_EMS
+
+ case WMTYPE_SERVERS:
+ VLM_UpdateServers();
+ break;
+
+ case WMTYPE_SEARCH:
+ VLM_UpdateSearchSelections( (UINT32)-1L, (INT16)-1 );
+ break;
+
+ default:
+ break;
+ }
+
+ win = WM_GetNext( win );
+ }
+}
+
+/******************************************************************************
+
+ Name: VLM_ValidatePath()
+
+ Description: Checks to see if a backup path is valid (NOT if it exists!!!)
+
+ Only checks for "\\server" and "E:", both of which we don't
+ allow.
+
+ Returns: INT non-zero for success, or zero for failure
+
+******************************************************************************/
+
+// the following code was stolen from tmenu
+
+INT VLM_ValidatePath(
+CHAR_PTR path,
+BOOLEAN allow_drive_spec,
+BOOLEAN use_dle )
+{
+ (VOID)allow_drive_spec;
+ (VOID)use_dle;
+
+ // skip white space
+
+ while ( *path && *path == TEXT( ' ' ) ) {
+ path++;
+ }
+
+ // skip first character
+
+ if ( *path ) {
+
+ // look for \\server\volume
+
+ if ( ! strncmp( path, TEXT("\\\\" ), 2 ) ) {
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE ),
+ ID( IDS_RESTOREPATHINVALID ),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ return( 0 );
+ }
+
+ path++;
+ }
+
+ // see if second character is a colon
+
+ if ( *path ) {
+ if ( *path == TEXT( ':' ) ) {
+ WM_MsgBox( ID( IDS_MSGTITLE_RESTORE ),
+ ID( IDS_RESTOREPATHINVALID ),
+ WMMB_OK, WMMB_ICONEXCLAMATION );
+ return( 0 );
+ }
+ }
+
+ return( -1 );
+}
+
+
+/******************************************************************************
+
+ Name: VLM_NetConnect ()
+
+ Description: Connects to a network drive.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID VLM_NetConnect ( VOID )
+
+{
+
+#ifndef OEM_MSOFT
+
+#ifdef CAYMAN
+ WNetConnectionDialog ( ghWndFrame, RESOURCETYPE_DISK );
+#else
+ WNetConnectionDialog ( ghWndFrame, WNBD_CONN_DISKTREE );
+#endif
+ if ( gb_disks_win != (HWND)NULL ) {
+
+ WM_SetActiveDoc( gb_disks_win );
+
+ VLM_Refresh ( );
+ }
+#endif
+
+} /* end VLM_NetConnect () */
+
+
+/******************************************************************************
+
+ Name: VLM_NetDisconnect ()
+
+ Description: Disconnects a network drive.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID VLM_NetDisconnect ( VOID )
+
+{
+
+#ifndef OEM_MSOFT
+
+#ifdef CAYMAN
+ WNetDisconnectDialog ( ghWndFrame, RESOURCETYPE_DISK );
+#else
+ WNetDisconnectDialog ( ghWndFrame, WNBD_CONN_DISKTREE );
+#endif
+ if ( gb_disks_win != (HWND)NULL ) {
+
+ WM_SetActiveDoc( gb_disks_win );
+
+ VLM_Refresh ( );
+ }
+#endif
+
+} /* end VLM_NetConnect () */
+
+
+
diff --git a/private/utils/ntbackup/src/vlm_xchg.c b/private/utils/ntbackup/src/vlm_xchg.c
new file mode 100644
index 000000000..7f9d15004
--- /dev/null
+++ b/private/utils/ntbackup/src/vlm_xchg.c
@@ -0,0 +1,3630 @@
+/***************************************************
+Copyright (C) Maynard, An Archive Company. 1991
+
+ Name: VLM_XCHG.C
+
+ Description:
+
+ This file contains most of the code for processing the Exchange
+ window and list.
+
+ $Log: $
+
+*****************************************************/
+
+#ifdef OEM_EMS // Entire File
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+
+// Local Prototypes
+static BOOLEAN DLE_EnterpriseInDleTree ( GENERIC_DLE_PTR, DLE_HAND );
+static SLM_OBJECT_PTR VLM_BuildExchangeList ( Q_HEADER_PTR, WININFO_PTR, GENERIC_DLE_PTR );
+static SLM_OBJECT_PTR SLM_FindSLMByName ( Q_HEADER_PTR, CHAR_PTR );
+static INT SLM_FindEnterpriseChildren ( Q_HEADER_PTR, SLM_OBJECT_PTR,
+ INT, GENERIC_DLE_PTR, SLM_OBJECT_PTR * );
+static SLM_OBJECT_PTR SLM_AddInExchangeChildren ( Q_HEADER_PTR, SLM_OBJECT_PTR,
+ INT, GENERIC_DLE_PTR );
+static VOID VLM_InsertXchgSLM ( Q_HEADER_PTR, SLM_OBJECT_PTR,
+ SLM_OBJECT_PTR, SLM_OBJECT_PTR );
+static VOID VLM_MarkAllEntSLMChildren ( SLM_OBJECT_PTR, BYTE );
+static INT SLM_XchgListReuse ( SLM_OBJECT_PTR );
+static WORD SLM_GetBitmap ( SLM_OBJECT_PTR );
+static INT SLM_AddBSD ( SLM_OBJECT_PTR );
+static VOID SLM_UpdateNodeList ( SLM_OBJECT_PTR ,BYTE );
+static VOID SLM_UpdateNode ( SLM_OBJECT_PTR );
+static VOID VLM_MarkAllEntSLMParents ( SLM_OBJECT_PTR, BYTE );
+static SLM_OBJECT_PTR SLM_FindByDLE ( GENERIC_DLE_PTR, SLM_OBJECT_PTR );
+static SLM_OBJECT_PTR SLM_CreateSLM ( INT, INT, INT, BOOLEAN, BOOLEAN );
+static HWND DLE_GetEnterpriseWindow ( GENERIC_DLE_PTR );
+static VOID SLM_EnterpriseRefresh ( SLM_OBJECT_PTR, GENERIC_DLE_PTR );
+
+static VOID_PTR SLM_EntSetSelect( SLM_OBJECT_PTR, BYTE );
+static BYTE SLM_EntGetSelect( SLM_OBJECT_PTR );
+static VOID_PTR SLM_EntSetTag( SLM_OBJECT_PTR, BYTE );
+static BYTE SLM_EntGetTag( SLM_OBJECT_PTR );
+static USHORT SLM_EntGetItemCount( Q_HEADER_PTR );
+static VOID_PTR SLM_EntGetFirstItem( Q_HEADER_PTR );
+static VOID_PTR SLM_EntGetPrevItem( SLM_OBJECT_PTR );
+static VOID_PTR SLM_EntGetNextItem( SLM_OBJECT_PTR );
+static VOID_PTR SLM_EntGetObjects( SLM_OBJECT_PTR );
+static BOOLEAN SLM_EntSetObjects( SLM_OBJECT_PTR, WORD, WORD );
+
+static VOID_PTR SLM_NodeSetSelect( SLM_OBJECT_PTR, BYTE );
+static BYTE SLM_NodeGetSelect( SLM_OBJECT_PTR );
+static VOID_PTR SLM_NodeSetTag( SLM_OBJECT_PTR, BYTE );
+static BYTE SLM_NodeGetTag( SLM_OBJECT_PTR );
+static USHORT SLM_NodeGetItemCount( Q_HEADER_PTR );
+static VOID_PTR SLM_NodeGetFirstItem( Q_HEADER_PTR );
+static VOID_PTR SLM_NodeGetPrevItem( SLM_OBJECT_PTR );
+static VOID_PTR SLM_NodeGetNextItem( SLM_OBJECT_PTR );
+static VOID_PTR SLM_NodeGetObjects( SLM_OBJECT_PTR );
+static BOOLEAN SLM_NodeSetObjects( SLM_OBJECT_PTR, WORD, WORD );
+static VOID_PTR SLM_DoNodeSetSelect( SLM_OBJECT_PTR, BYTE );
+static BOOLEAN VLM_ExchangeDleExist( VOID );
+
+
+/**********************
+
+ NAME : VLM_ExchangeInit
+
+ DESCRIPTION :
+
+ Creates the queue for the exchange enterprise windows and steps through
+ the enterprise server list, creating windows for any names found there.
+
+ RETURNS : SUCCESS if the windows could be created (if needed). FAILURE otherwise.
+
+**********************/
+
+BOOLEAN VLM_ExchangeInit ( )
+{
+ GENERIC_DLE_PTR dle;
+ Q_ELEM_PTR elem_ptr;
+ WININFO_PTR wininfo;
+ SLM_OBJECT_PTR slm;
+ HWND enterprise_win;
+
+ InitQueue( (Q_HEADER_PTR) &gq_exchange_win );
+
+ dle = (GENERIC_DLE_PTR)QueueHead( &(dle_list->q_hdr) ) ;
+
+ while ( dle ) {
+
+ if ( ( DLE_GetDeviceType( dle ) == FS_EMS_DRV ) &&
+ ( DLE_GetDeviceSubType( dle ) == EMS_ENTERPRISE ) ) {
+
+ if ( SUCCESS != VLM_ExchangeListCreate( DLE_GetDeviceName( dle ) ) ) {
+
+ return FAILURE;
+ }
+
+ // Blow out entire tree for the dle.
+ for ( elem_ptr = QueueHead( &gq_exchange_win );
+ NULL != elem_ptr;
+ elem_ptr = QueueNext( elem_ptr ) ) {
+
+ if ( !( enterprise_win = ( HWND )QueuePtr( elem_ptr ) ) ) {
+ // Something's wrong - we've got a queue entry but no window.
+ RemoveElem( &gq_exchange_win, elem_ptr );
+ continue;
+ }
+
+ if ( NULL == ( wininfo = WM_GetInfoPtr( enterprise_win ) ) ) {
+ // Something's wrong - we've got a window but no enterprise info.
+ SendMessage ( ghWndMDIClient, WM_MDIDESTROY, (MP1)enterprise_win, 0L );
+ continue;
+ }
+
+ if ( NULL == ( slm = VLM_GetFirstSLM( WMDS_GetTreeList( wininfo ) ) ) ) {
+ // Something's wrong - we've got info, but no entries in the slm list.
+ SendMessage ( ghWndMDIClient, WM_MDIDESTROY, (MP1)enterprise_win, 0L );
+ continue;
+ }
+
+ if ( dle == SLM_GetDle( slm ) ) {
+
+ SLM_EMSExpandTree( enterprise_win );
+ break;
+ }
+ }
+ }
+
+ dle = (GENERIC_DLE_PTR)QueueNext( &(dle->q) ) ;
+ }
+
+ return SUCCESS;
+}
+
+
+/**********************
+
+ NAME : VLM_ExchangeSync
+
+ DESCRIPTION :
+
+ The user has performed a refresh call and it is our job to see to it that
+ any servers no longer on line are removed and any new ones are inserted.
+ Any server with a window open will not go away, because we are attached
+ to it. Also any server with selections made will not go away. All server
+ children dle's need there bsd count incremented to keep them around.
+
+ RETURNS : nothing.
+
+**********************/
+
+VOID VLM_ExchangeSync( )
+{
+ HWND enterprise_win;
+ Q_ELEM_PTR elem_ptr;
+ WININFO_PTR wininfo;
+ SLM_OBJECT_PTR slm;
+ GENERIC_DLE_PTR enterprise_dle = NULL;
+
+ // Find and check the DLE tree for each enterprise window. We'll only check entire
+ // trees here and wait until we loop through the DLEs to make check individual elements
+ // of the trees.
+
+ for ( elem_ptr = QueueHead( &gq_exchange_win ); NULL != elem_ptr; elem_ptr = QueueNext( elem_ptr ) ) {
+
+ if ( !( enterprise_win = ( HWND )QueuePtr( elem_ptr ) ) ) {
+ // Something's wrong - we've got a queue entry but no window.
+ RemoveElem( &gq_exchange_win, elem_ptr );
+ continue;
+ }
+
+ if ( NULL == ( wininfo = WM_GetInfoPtr( enterprise_win ) ) ) {
+ // Something's wrong - we've got a window but no enterprise info.
+ SendMessage ( ghWndMDIClient, WM_MDIDESTROY, (MP1)enterprise_win, 0L );
+ continue;
+ }
+
+ if ( NULL == ( slm = VLM_GetFirstSLM( WMDS_GetTreeList( wininfo ) ) ) ) {
+ // Something's wrong - we've got info, but no entries in the slm list.
+ SendMessage ( ghWndMDIClient, WM_MDIDESTROY, (MP1)enterprise_win, 0L );
+ continue;
+ }
+
+ if ( NULL == ( enterprise_dle = SLM_GetDle( slm ) ) ) {
+ // Something's wrong - we've got an enterprise slm tree without DLEs
+ SendMessage ( ghWndMDIClient, WM_MDIDESTROY, (MP1)enterprise_win, 0L );
+ continue;
+ }
+
+ if ( !DLE_EnterpriseInDleTree( enterprise_dle, dle_list ) ) {
+ // We no longer have a connection to that DLE tree.
+ SendMessage ( ghWndMDIClient, WM_MDIDESTROY, (MP1)enterprise_win, 0L );
+ continue;
+ }
+
+ }
+
+ // Find and check the window for each DLE tree. Also check the individual elements of
+ // the tree.
+ for ( enterprise_dle = (GENERIC_DLE_PTR)QueueHead( &(dle_list->q_hdr) );
+ NULL != enterprise_dle;
+ enterprise_dle = (GENERIC_DLE_PTR)QueueNext( &(enterprise_dle->q) ) ) {
+
+ if ( ( DLE_GetDeviceType( enterprise_dle ) != FS_EMS_DRV ) ||
+ ( DLE_GetDeviceSubType( enterprise_dle ) != EMS_ENTERPRISE ) ) {
+ continue; // Try the next dle.
+ }
+
+ if ( !( enterprise_win = DLE_GetEnterpriseWindow( enterprise_dle ) ) ) {
+
+ // Create a new window because this DLE tree doesn't have one.
+ VLM_ExchangeListCreate( DLE_GetDeviceName( enterprise_dle ) );
+
+ } else {
+
+ // Match the slm tree to the dle tree.
+
+ if ( NULL == ( wininfo = WM_GetInfoPtr( enterprise_win ) ) ) {
+ // Something's wrong - we've got a window but no window display info.
+ SendMessage ( ghWndMDIClient, WM_MDIDESTROY, (MP1)enterprise_win, 0L );
+ VLM_ExchangeListCreate( DLE_GetDeviceName( enterprise_dle ) );
+ continue;
+ }
+
+ if ( NULL == ( slm = VLM_GetFirstSLM( WMDS_GetTreeList( wininfo ) ) ) ) {
+ // Something's wrong - we've got info, but no entries in the slm list.
+ SendMessage ( ghWndMDIClient, WM_MDIDESTROY, (MP1)enterprise_win, 0L );
+ VLM_ExchangeListCreate( DLE_GetDeviceName( enterprise_dle ) );
+ continue;
+ }
+
+ SLM_EnterpriseRefresh( slm, enterprise_dle );
+ }
+ }
+}
+
+
+/**********************
+
+ NAME : DLE_InDleTree
+
+ DESCRIPTION :
+
+ Checks to see if a DLE tree exists in a list of DLEs.
+
+ RETURNS : BOOLEAN.
+
+**********************/
+static BOOLEAN DLE_EnterpriseInDleTree(
+ GENERIC_DLE_PTR dle,
+ DLE_HAND hand
+)
+{
+ GENERIC_DLE_PTR temp_dle;
+
+ if ( ( dle == NULL ) ||
+ ( hand == NULL ) ) {
+ return FALSE;
+ }
+
+ temp_dle = (GENERIC_DLE_PTR)QueueHead( &(hand->q_hdr) ) ;
+
+ while ( temp_dle ) {
+
+ if ( temp_dle == dle ) {
+
+ return TRUE;
+ }
+
+ temp_dle = (GENERIC_DLE_PTR)QueueNext( &(temp_dle->q) ) ;
+ }
+
+ return FALSE;
+
+}
+
+/**********************
+
+ NAME : SLM_EnterpriseRefresh
+
+ DESCRIPTION :
+
+ Compares the SLM tree to it corresponding DLE tree, adding any new DLEs, if necessary.
+
+ RETURNS : nothing.
+
+**********************/
+static VOID SLM_EnterpriseRefresh(
+ SLM_OBJECT_PTR parent_slm,
+ GENERIC_DLE_PTR parent_dle
+)
+{
+ SLM_OBJECT_PTR child_slm;
+ GENERIC_DLE_PTR child_dle;
+ WININFO_PTR wininfo;
+
+ if ( ( parent_slm == NULL ) ||
+ ( parent_dle == NULL ) ) {
+ return;
+ }
+
+ wininfo = SLM_GetXtraBytes( parent_slm );
+
+ if ( SLM_GetMailType( parent_slm ) == EMS_SERVER ) {
+ return;
+ }
+
+ // We will step through the children at this level assuming that the slm and dle children
+ // are in the same (alphabetical) sort order. If this changes, then this routine will have
+ // to change. Another assumption is that nodes will never disappear from the dle tree. This
+ // means that a node cannot appear in the slm tree that does not appear in the dle tree.
+ for ( child_slm = VLM_GetNextSLM( parent_slm ), DLE_GetFirstChild( parent_dle, &child_dle )
+ ; ( NULL != child_dle )
+ ; DLE_GetNext( &child_dle ) ) {
+
+ // if we're out of slm children but there are still more dle children so these must
+ // be added.
+ if ( child_slm == NULL ) {
+
+ SLM_AddInExchangeChildren( WMDS_GetTreeList( wininfo ), parent_slm, -1, child_dle );
+ continue;
+ }
+
+ // Add any dle children that exist before the next known slm child.
+ while ( ( NULL != child_slm ) &&
+ ( SLM_GetDle( child_slm ) != child_dle ) ) {
+
+ SLM_AddInExchangeChildren( WMDS_GetTreeList( wininfo ), parent_slm, -1, child_dle );
+ DLE_GetNext( &child_dle );
+ }
+
+ // Recurse through the next level of children then go on to the next slm brother.
+ if ( child_slm != NULL ) {
+ SLM_EnterpriseRefresh( child_slm, child_dle );
+ child_slm = SLM_GetNextBrother( child_slm );
+ }
+ }
+}
+
+
+/**********************
+
+ NAME : SLM_EMSExpandTree
+
+ DESCRIPTION :
+
+ Expand entire exchange tree.
+
+ RETURNS : nothing.
+
+**********************/
+
+VOID SLM_EMSExpandTree( HWND win )
+{
+ SLM_OBJECT_PTR focus_slm;
+ SLM_OBJECT_PTR slm;
+ WININFO_PTR wininfo = WM_GetInfoPtr( win );
+
+ if ( ( NULL != wininfo ) &&
+ ( WMTYPE_EXCHANGE == WMDS_GetWinType( wininfo ) ) ) {
+
+ focus_slm = ( SLM_OBJECT_PTR )DLM_GetFocusItem( wininfo->hWndTreeList );
+ slm = VLM_GetFirstSLM( WMDS_GetTreeList( wininfo ) );
+
+ while ( slm ) {
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) | (UINT16)(INFO_DISPLAY | INFO_EXPAND | INFO_VALID) );
+
+ slm = VLM_GetNextSLM( slm );
+ }
+
+ VLM_UpdateBrothers( WMDS_GetTreeList( wininfo ) );
+
+ DLM_Update( win, DLM_TREELISTBOX, WM_DLMUPDATELIST, NULL, 0 );
+
+ SLM_EntSetObjects( focus_slm, WM_DLMDOWN, 2 );
+ }
+}
+
+
+/**********************
+
+ NAME : SLM_EMSExpandOne
+
+ DESCRIPTION :
+
+ Expand one node of the exchange tree.
+
+ RETURNS : nothing.
+
+**********************/
+
+VOID SLM_EMSExpandOne( HWND win )
+{
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ SLM_OBJECT_PTR focus_slm;
+
+ wininfo = WM_GetInfoPtr( win );
+
+ if ( wininfo) {
+ appinfo = WMDS_GetAppInfo( wininfo );
+ }
+
+ if ( appinfo ) {
+
+ focus_slm = appinfo->open_slm;
+
+ } else {
+
+ focus_slm = ( SLM_OBJECT_PTR )DLM_GetFocusItem( wininfo->hWndTreeList );
+
+ }
+
+ if ( focus_slm == NULL ) {
+
+ return;
+ }
+
+ if ( SLM_GetStatus( focus_slm ) & INFO_EXPAND ) {
+ return;
+ }
+
+ SLM_EntSetObjects( focus_slm, WM_DLMDBCLK, 2 );
+
+}
+
+
+/**********************
+
+ NAME : SLM_EMSExpandBranch
+
+ DESCRIPTION :
+
+ Expand one node of the exchange tree.
+
+ RETURNS : nothing.
+
+**********************/
+
+VOID SLM_EMSExpandBranch( HWND win )
+{
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ SLM_OBJECT_PTR focus_slm;
+ SLM_OBJECT_PTR child_slm;
+
+ wininfo = WM_GetInfoPtr( win );
+
+ if ( wininfo) {
+ appinfo = WMDS_GetAppInfo( wininfo );
+ }
+
+ if ( appinfo ) {
+
+ focus_slm = appinfo->open_slm;
+
+ } else {
+
+ focus_slm = ( SLM_OBJECT_PTR )DLM_GetFocusItem( wininfo->hWndTreeList );
+
+ }
+
+ if ( focus_slm == NULL ) {
+
+ return;
+ }
+
+ child_slm = VLM_GetNextSLM( focus_slm );
+
+ while ( child_slm &&
+ ( child_slm != SLM_GetNextBrother( focus_slm ) ) ) {
+
+ SLM_SetStatus( child_slm,
+ SLM_GetStatus( child_slm ) |
+ (UINT16)(INFO_DISPLAY | INFO_EXPAND | INFO_VALID) );
+
+ child_slm = VLM_GetNextSLM( child_slm );
+ }
+
+ DLM_Update( win, DLM_TREELISTBOX, WM_DLMUPDATELIST, NULL, 0 );
+}
+
+
+/**********************
+
+ NAME : SLM_EMSCollapseBranch
+
+ DESCRIPTION :
+
+ Collapses a branch of the exchange tree.
+
+ RETURNS : nothing.
+
+**********************/
+
+VOID SLM_EMSCollapseBranch( HWND win )
+{
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ SLM_OBJECT_PTR focus_slm;
+
+ wininfo = WM_GetInfoPtr( win );
+
+ if ( wininfo) {
+ appinfo = WMDS_GetAppInfo( wininfo );
+ }
+
+ if ( appinfo ) {
+
+ focus_slm = appinfo->open_slm;
+
+ } else {
+
+ focus_slm = ( SLM_OBJECT_PTR )DLM_GetFocusItem( wininfo->hWndTreeList );
+
+ }
+
+ if ( focus_slm == NULL ) {
+
+ return;
+ }
+
+ if ( !( SLM_GetStatus( focus_slm ) & INFO_EXPAND ) ) {
+ return;
+ }
+
+ SLM_EntSetObjects( focus_slm, WM_DLMDBCLK, 2 );
+
+}
+
+
+/**********************
+
+ NAME : SLM_EMSPrevBrotherDir
+
+ DESCRIPTION :
+
+ User hit CTRL-Up Arrow, go to previous brother.
+
+ RETURNS : nothing
+
+**********************/
+
+VOID SLM_EMSPrevBrotherDir( HWND win )
+{
+ SLM_OBJECT_PTR old_slm;
+ SLM_OBJECT_PTR new_slm;
+ WININFO_PTR wininfo;
+
+ wininfo = WM_GetInfoPtr( win );
+
+ // Get the active directory slm.
+
+ old_slm = ( SLM_OBJECT_PTR )DLM_GetFocusItem( wininfo->hWndTreeList );
+
+ if ( old_slm == NULL ) {
+ return;
+ }
+
+ // Try to find a previous brother and make him active directory.
+
+ new_slm = VLM_GetPrevSLM( old_slm );
+
+ while ( new_slm != NULL ) {
+
+ if ( SLM_GetLevel( new_slm ) < SLM_GetLevel( old_slm ) ) {
+
+ // No previous brother.
+ break;
+ }
+
+ if ( SLM_GetLevel( new_slm ) == SLM_GetLevel( old_slm ) ) {
+
+ SLM_SetStatus( old_slm, old_slm->status & (UINT16)~INFO_TAGGED );
+ SLM_SetStatus( new_slm, new_slm->status | (UINT16)INFO_TAGGED );
+
+ DLM_SetAnchor( WMDS_GetWinTreeList( wininfo ),
+ 0,
+ (LMHANDLE)new_slm );
+
+ // Fake a single click call to make this guy active.
+ SLM_EntSetObjects( new_slm, WM_DLMDOWN, 2 );
+ break;
+ }
+
+ new_slm = VLM_GetPrevSLM( new_slm );
+ }
+
+}
+
+/**********************
+
+ NAME : SLM_EMSNextBrotherDir
+
+ DESCRIPTION :
+
+ User hit Ctrl-Down Arrow. Go to next brother down the tree.
+
+ RETURNS : nothing
+
+**********************/
+
+VOID SLM_EMSNextBrotherDir( HWND win )
+{
+ SLM_OBJECT_PTR old_slm;
+ SLM_OBJECT_PTR new_slm;
+ WININFO_PTR wininfo;
+
+ wininfo = WM_GetInfoPtr( win );
+
+ // get the active directory slm.
+
+ old_slm = ( SLM_OBJECT_PTR )DLM_GetFocusItem( wininfo->hWndTreeList );
+
+ if ( old_slm == NULL ) {
+ return;
+ }
+
+ // Get his next brother.
+
+ new_slm = old_slm->next_brother;
+
+ if ( new_slm != NULL ) {
+
+ SLM_SetStatus( old_slm, old_slm->status & (UINT16)~INFO_TAGGED );
+ SLM_SetStatus( new_slm, new_slm->status | (UINT16)INFO_TAGGED );
+
+ // Make him the active item.
+
+ DLM_SetAnchor( WMDS_GetWinTreeList( wininfo ),
+ 0,
+ (LMHANDLE)new_slm );
+
+ // Fake a single click message to myself.
+
+ SLM_EntSetObjects( new_slm, WM_DLMDOWN, 2 );
+ }
+
+}
+
+
+/**********************
+
+ NAME : SLM_EMSUpOneDir
+
+ DESCRIPTION :
+
+ Make the parent of the active directory the active directory.
+
+ RETURNS : nothing
+
+**********************/
+
+VOID SLM_EMSUpOneDir( HWND win )
+{
+ SLM_OBJECT_PTR old_slm;
+ SLM_OBJECT_PTR new_slm;
+ WININFO_PTR wininfo;
+
+ wininfo = WM_GetInfoPtr( win );
+
+ old_slm = ( SLM_OBJECT_PTR )DLM_GetFocusItem( wininfo->hWndTreeList );
+
+ if ( old_slm == NULL ) {
+ return;
+ }
+
+ new_slm = SLM_GetParent( old_slm );
+
+ if ( new_slm != NULL ) {
+
+ SLM_SetStatus( old_slm, old_slm->status & (UINT16)~INFO_TAGGED );
+ SLM_SetStatus( new_slm, new_slm->status | (UINT16)INFO_TAGGED );
+
+ DLM_SetAnchor( WMDS_GetWinTreeList( wininfo ),
+ 0,
+ (LMHANDLE)new_slm );
+
+ SLM_EntSetObjects( new_slm, WM_DLMDOWN, 2 );
+ }
+
+}
+
+/**********************
+
+ NAME : SLM_EMSDownOneDir
+
+ DESCRIPTION :
+
+ Move down the tree one level deeper to the active directories first
+ child, if there is one.
+
+ RETURNS : nothing
+
+**********************/
+
+VOID SLM_EMSDownOneDir( HWND win )
+{
+ SLM_OBJECT_PTR old_slm;
+ SLM_OBJECT_PTR new_slm;
+ Q_HEADER_PTR slm_list;
+ WININFO_PTR wininfo;
+ INT count = 0;
+
+ wininfo = WM_GetInfoPtr( win );
+
+ slm_list = WMDS_GetTreeList( wininfo );
+
+ // Get active directory slm.
+
+ old_slm = ( SLM_OBJECT_PTR )DLM_GetFocusItem( wininfo->hWndTreeList );
+
+ if ( old_slm == NULL ) {
+ return;
+ }
+
+ if ( ! ( SLM_GetStatus( old_slm ) & INFO_SUBS ) ) {
+
+ // The guy has no subs.
+ return;
+ }
+
+
+ if( !( SLM_GetStatus( old_slm ) & INFO_EXPAND ) ) {
+
+ SLM_EntSetObjects( old_slm, WM_DLMDBCLK, 2 );
+ }
+
+ // Now make the first child active.
+
+ new_slm = VLM_GetNextSLM( old_slm );
+
+ while ( new_slm != NULL ) {
+
+ if ( SLM_GetLevel( new_slm ) <= SLM_GetLevel( old_slm ) ) {
+ break;
+ }
+
+ if ( SLM_GetLevel( new_slm ) == SLM_GetLevel( old_slm ) + 1 ) {
+
+ // We've found the right one.
+
+ SLM_SetStatus( old_slm, old_slm->status & (UINT16)~INFO_TAGGED );
+ SLM_SetStatus( new_slm, new_slm->status | (UINT16)INFO_TAGGED );
+
+ DLM_SetAnchor( WMDS_GetWinTreeList( wininfo ),
+ 0,
+ (LMHANDLE)new_slm );
+
+ // Fake a single click message to myself.
+
+ SLM_EntSetObjects( new_slm, WM_DLMDOWN, 2 );
+ break;
+ }
+
+ new_slm = VLM_GetNextSLM( new_slm );
+ }
+
+}
+
+/*****
+
+ NAME : VLM_UpdateEnterprise
+
+ DESCRIPTION :
+
+ We have changed the selection status on one of this enterprises's volumes. So
+ let's quickly update his status based on the selction status of all his
+ volumes. Run through the list and stop as soon as you hit a partially
+ selected one.
+
+*****/
+
+VOID VLM_UpdateExchange( HWND exchange_win )
+{
+ GENERIC_DLE_PTR dle;
+ BSD_PTR bsd;
+ SLM_OBJECT_PTR slm;
+ WININFO_PTR wininfo;
+ UINT32 old_status;
+
+ wininfo = WM_GetInfoPtr( exchange_win );
+
+ if ( wininfo != NULL ) {
+
+ slm = VLM_GetFirstSLM( wininfo->pTreeList );
+
+ while ( slm != NULL ) {
+
+ if ( ( EMS_MDB == SLM_GetMailType( slm ) ) ||
+ ( EMS_DSA == SLM_GetMailType( slm ) ) ) {
+
+ old_status = slm->status & (UINT16)(INFO_SELECT|INFO_PARTIAL);
+ slm->status &= ~( INFO_PARTIAL | INFO_SELECT );
+
+ dle = SLM_GetDle( slm );
+
+ bsd = BSD_FindByDLE( bsd_list, dle );
+
+ if ( bsd != NULL ) {
+
+ switch ( BSD_GetMarkStatus( bsd ) ) {
+
+ case ALL_SELECTED:
+ slm->status |= INFO_SELECT;
+ break;
+
+ case SOME_SELECTED:
+ slm->status |= (INFO_SELECT|INFO_PARTIAL);
+ break;
+
+ default:
+ break;
+ }
+
+ }
+
+ // Update the check mark
+
+ if ( old_status != (UINT16)(slm->status & (INFO_SELECT|INFO_PARTIAL) ) ) {
+
+ DLM_Update( exchange_win,
+ DLM_TREELISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)slm, 0 );
+ }
+ }
+
+ slm = VLM_GetNextSLM( slm );
+ }
+
+ // Update the flat list now
+ slm = VLM_GetFirstSLM( wininfo->pFlatList );
+
+ while ( slm != NULL ) {
+
+ if ( ( EMS_MDB == SLM_GetMailType( slm ) ) ||
+ ( EMS_DSA == SLM_GetMailType( slm ) ) ) {
+
+ old_status = slm->status & (UINT16)(INFO_SELECT|INFO_PARTIAL);
+ slm->status &= ~( INFO_PARTIAL | INFO_SELECT );
+
+ dle = SLM_GetDle( slm );
+
+ bsd = BSD_FindByDLE( bsd_list, dle );
+
+ if ( bsd != NULL ) {
+
+ switch ( BSD_GetMarkStatus( bsd ) ) {
+
+ case ALL_SELECTED:
+ slm->status |= INFO_SELECT;
+ break;
+
+ case SOME_SELECTED:
+ slm->status |= (INFO_SELECT|INFO_PARTIAL);
+ break;
+
+ default:
+ break;
+ }
+
+ }
+
+ // Update the check mark
+
+ if ( old_status != (UINT16)(slm->status & (INFO_SELECT|INFO_PARTIAL) ) ) {
+
+ DLM_Update( exchange_win,
+ DLM_FLATLISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)slm, 0 );
+ }
+ }
+
+ slm = VLM_GetNextSLM( slm );
+ }
+
+ }
+}
+
+
+/**********************
+
+ NAME : VLM_ClearAllExchangeSelections
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+VOID VLM_ClearAllExchangeSelections( )
+{
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ SLM_OBJECT_PTR slm;
+ Q_ELEM_PTR qp_elem;
+ HWND exchange_win;
+
+ if ( QueueCount( &gq_exchange_win ) > 0 ) {
+
+ qp_elem = QueueHead( &gq_exchange_win );
+ if ( qp_elem != NULL ) {
+
+ exchange_win = ( HWND ) GetQueueElemPtr( qp_elem );
+
+ } else {
+
+ return;
+ }
+
+ } else {
+
+ return;
+ }
+
+ while ( exchange_win != (HWND)NULL ) {
+
+ wininfo = WM_GetInfoPtr( exchange_win );
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( exchange_win );
+
+ slm = VLM_GetFirstSLM( WMDS_GetTreeList( wininfo ) );
+
+ while ( slm != NULL ) {
+
+ if ( SLM_GetStatus( slm ) & (INFO_SELECT|INFO_PARTIAL) ) {
+
+ SLM_SetStatus( slm, slm->status & (UINT16)~(INFO_PARTIAL|INFO_SELECT) );
+
+ DLM_Update( exchange_win, DLM_TREELISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)slm, 0 );
+ }
+
+ slm = VLM_GetNextSLM( slm );
+ }
+
+ slm = VLM_GetFirstSLM( WMDS_GetFlatList( wininfo ) );
+
+ while ( slm != NULL ) {
+
+ if ( SLM_GetStatus( slm ) & (INFO_SELECT|INFO_PARTIAL) ) {
+
+ SLM_SetStatus( slm, slm->status & (UINT16)~(INFO_PARTIAL|INFO_SELECT) );
+
+
+ DLM_Update( exchange_win, DLM_FLATLISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)slm, 0 );
+ }
+
+ slm = VLM_GetNextSLM( slm );
+ }
+
+ qp_elem = QueueNext( qp_elem );
+
+ if ( qp_elem != NULL ) {
+
+ exchange_win = ( HWND ) GetQueueElemPtr( qp_elem );
+
+ } else {
+
+ exchange_win = NULL;
+ }
+ }
+}
+
+
+
+/**********************
+
+ NAME : VLM_ExchangeListCreate
+
+ DESCRIPTION :
+
+ Create the Exchange window.
+
+ RETURNS : nothing
+
+**********************/
+
+BOOLEAN VLM_ExchangeListCreate( CHAR_PTR szServer )
+{
+
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ HWND hWnd;
+ Q_ELEM_PTR pQElem;
+ DLM_INIT tree_dlm;
+ DLM_INIT flat_dlm;
+ Q_HEADER_PTR xchg_list;
+ Q_HEADER_PTR node_list;
+ CHAR title[ MAX_UI_RESOURCE_SIZE ];
+ CHAR szBuffer[ MAX_UI_RESOURCE_SIZE ];
+ CDS_PTR pCDS = CDS_GetPerm ();
+ GENERIC_DLE_PTR server_dle;
+ SLM_OBJECT_PTR anchor_slm;
+ SLM_OBJECT_PTR enterprise_slm;
+ SLM_OBJECT_PTR temp_slm;
+ GENERIC_DLE_PTR enterprise_dle;
+
+
+ if ( ( SUCCESS == DLE_FindByName( dle_list, szServer, FS_EMS_DRV, &server_dle ) ) ) {
+
+ // DLE tree already exists for this server.
+ gfExchange = TRUE;
+
+ // First find enterprise DLE for the server
+ enterprise_dle = DLE_GetEnterpriseDLE( server_dle );
+
+ if ( NULL == enterprise_dle ) {
+
+ return SUCCESS;
+ }
+
+ // Then check to see if the enterprise DLE is in a window.
+ if ( hWnd = DLE_GetEnterpriseWindow( enterprise_dle ) ) {
+
+ // if the DLE has an SLM then display it.
+ if ( NULL != ( wininfo = WM_GetInfoPtr( hWnd ) ) ) {
+
+ if ( NULL != ( xchg_list = WMDS_GetTreeList( wininfo ) ) ) {
+
+ if ( NULL != ( enterprise_slm = VLM_GetFirstSLM( xchg_list ) ) ) {
+
+ if ( NULL != ( anchor_slm = SLM_FindByDLE( server_dle, enterprise_slm ) ) ) {
+
+ SLM_DisplayExchangeDLE( server_dle );
+
+ } else {
+
+ // No slm. Find the first DLE parent with a SLM and display from there down.
+ enterprise_dle = DLE_GetParent( server_dle );
+ temp_slm = NULL;
+
+ while ( ( enterprise_dle ) &&
+ ( NULL == temp_slm ) ) {
+
+ temp_slm = SLM_FindByDLE( enterprise_dle, enterprise_slm );
+ enterprise_dle = DLE_GetParent( enterprise_dle );
+ }
+
+ if ( NULL != temp_slm ) {
+
+ // We found an ancestor slm in the tree. Let's add its newly born branch.
+ if ( NULL != ( anchor_slm = SLM_AddInExchangeChildren( xchg_list,
+ temp_slm,
+ -1,
+ server_dle ) ) ) {
+
+ // Restore the window if it's iconic
+ if ( IsIconic( hWnd ) ) {
+
+ SendMessage( ghWndMDIClient, WM_MDIRESTORE, (MPARAM1) hWnd, (MPARAM2) 0 );
+ }
+
+ // Update the listbox in the window and set the anchor to the newfound slm.
+ VLM_UpdateBrothers( xchg_list );
+ DLM_Update( hWnd, DLM_TREELISTBOX, WM_DLMUPDATELIST, (LMHANDLE)xchg_list, 0 );
+
+ SLM_EntSetObjects( anchor_slm, WM_DLMDOWN, 2 );
+
+ }
+
+ else return SUCCESS;
+ }
+
+ else return SUCCESS;
+ }
+
+ }
+
+ else return SUCCESS;
+ }
+
+ else return SUCCESS;
+ }
+
+ return SUCCESS;
+ }
+ }
+
+ if ( NULL == server_dle ) {
+
+ return SUCCESS;
+ }
+
+ xchg_list = (Q_HEADER_PTR)malloc( sizeof(Q_HEADER) );
+
+ if ( xchg_list == NULL ) {
+
+ return FAILURE;
+ }
+
+ InitQueue( xchg_list );
+
+ node_list = (Q_HEADER_PTR)malloc( sizeof(Q_HEADER) );
+
+ if ( node_list == NULL ) {
+
+ return FAILURE;
+ }
+
+ InitQueue( node_list );
+
+ appinfo = ( APPINFO_PTR )malloc( sizeof( APPINFO ) );
+
+ if ( appinfo == NULL ) {
+ return FAILURE;
+ }
+
+ appinfo->dle = NULL;
+
+ // initialize directory list queue
+ // This is the enterprise list queue for OEM_EMS
+
+ wininfo = ( WININFO_PTR )malloc( sizeof( WININFO ) );
+
+ if ( wininfo == NULL ) {
+ return FAILURE;
+ }
+
+ // fill in wininfo structure
+
+ WMDS_SetWinType( wininfo, WMTYPE_EXCHANGE );
+ WMDS_SetCursor( wininfo, RSM_CursorLoad( IDRC_HSLIDER ) );
+ WMDS_SetDragCursor( wininfo, 0 );
+ WMDS_SetIcon( wininfo, RSM_IconLoad( IDRI_EXCHANGE ) );
+ WMDS_SetWinHelpID( wininfo, 0 );
+ WMDS_SetStatusLineID( wininfo, 0 );
+ WMDS_SetRibbonState( wininfo, 0 );
+ WMDS_SetMenuState( wininfo, MMDOC_TREEANDDIR );
+ WMDS_SetRibbon( wininfo, NULL );
+ WMDS_SetTreeList( wininfo, xchg_list );
+ WMDS_SetFlatList( wininfo, node_list );
+ WMDS_SetTreeDisp( wininfo, NULL );
+ WMDS_SetFlatDisp( wininfo, NULL );
+ WMDS_SetAppInfo( wininfo, appinfo );
+ WMDS_SetSliderPos ( wininfo, CDS_GetTapeInfo ( pCDS ).nSliderPos );
+
+ // Init display list
+
+ DLM_ListBoxType( &tree_dlm, DLM_TREELISTBOX );
+ DLM_Mode( &tree_dlm, DLM_HIERARCHICAL );
+ DLM_Display( &tree_dlm, DLM_SMALL_BITMAPS );
+ DLM_DispHdr( &tree_dlm, xchg_list );
+ DLM_TextFont( &tree_dlm, DLM_SYSTEM_FONT );
+ DLM_GetItemCount( &tree_dlm, SLM_EntGetItemCount );
+ DLM_GetFirstItem( &tree_dlm, SLM_EntGetFirstItem );
+ DLM_GetNext( &tree_dlm, SLM_EntGetNextItem );
+ DLM_GetPrev( &tree_dlm, SLM_EntGetPrevItem );
+ DLM_GetTag( &tree_dlm, SLM_EntGetTag );
+ DLM_SetTag( &tree_dlm, SLM_EntSetTag );
+ DLM_GetSelect( &tree_dlm, SLM_EntGetSelect );
+ DLM_SetSelect( &tree_dlm, SLM_EntSetSelect );
+ DLM_GetObjects( &tree_dlm, SLM_EntGetObjects );
+ DLM_SetObjects( &tree_dlm, SLM_EntSetObjects );
+ DLM_SSetItemFocus( &tree_dlm, NULL );
+ DLM_MaxNumObjects( &tree_dlm, 6 );
+
+ DLM_DispListInit( wininfo, &tree_dlm );
+
+ DLM_ListBoxType( &flat_dlm, DLM_FLATLISTBOX );
+ DLM_Mode( &flat_dlm, DLM_SINGLECOLUMN );
+ DLM_Display( &flat_dlm, DLM_SMALL_BITMAPS );
+ DLM_DispHdr( &flat_dlm, node_list );
+ DLM_TextFont( &flat_dlm, DLM_SYSTEM_FONT );
+ DLM_GetItemCount( &flat_dlm, SLM_NodeGetItemCount );
+ DLM_GetFirstItem( &flat_dlm, SLM_NodeGetFirstItem );
+ DLM_GetNext( &flat_dlm, SLM_NodeGetNextItem );
+ DLM_GetPrev( &flat_dlm, SLM_NodeGetPrevItem );
+ DLM_GetTag( &flat_dlm, SLM_NodeGetTag );
+ DLM_SetTag( &flat_dlm, SLM_NodeSetTag );
+ DLM_GetSelect( &flat_dlm, SLM_NodeGetSelect );
+ DLM_SetSelect( &flat_dlm, SLM_NodeSetSelect );
+ DLM_GetObjects( &flat_dlm, SLM_NodeGetObjects );
+ DLM_SetObjects( &flat_dlm, SLM_NodeSetObjects );
+ DLM_SSetItemFocus( &flat_dlm, NULL );
+ DLM_MaxNumObjects( &flat_dlm, 6 );
+
+ DLM_DispListInit( wininfo, &flat_dlm );
+
+ anchor_slm = VLM_BuildExchangeList( xchg_list, wininfo, server_dle );
+ enterprise_slm = VLM_GetFirstSLM( xchg_list );
+
+ appinfo->dle = SLM_GetDle( enterprise_slm );
+
+ // open a new window
+ RSM_StringCopy ( IDS_VLMEMSTITLE, title, MAX_UI_RESOURCE_LEN );
+ wsprintf( szBuffer, title, SLM_GetName( enterprise_slm ) );
+ strcpy ( title, SLM_GetName( enterprise_slm ) );
+
+ hWnd = WM_Create( WM_MDIPRIMARY | WM_TREELIST | WM_TREEANDFLATSC | WM_MENUS,
+ szBuffer,
+ title,
+ WM_DEFAULT,
+ WM_DEFAULT,
+ WM_DEFAULT,
+ WM_DEFAULT,
+ wininfo );
+
+ appinfo->win = hWnd;
+ WMDS_SetWin( wininfo, hWnd );
+
+ // Start display manager up.
+
+ DLM_DispListProc( WMDS_GetWinTreeList( wininfo ), 0, NULL );
+ DLM_DispListProc( WMDS_GetWinFlatList( wininfo ), 0, NULL );
+
+ DLM_Update( hWnd,
+ DLM_TREELISTBOX,
+ WM_DLMUPDATELIST,
+ (LMHANDLE)wininfo->pTreeList, 0 );
+
+ // Now that it is displayed, set the anchor.
+ anchor_slm = ( NULL != anchor_slm ) ? anchor_slm : enterprise_slm;
+ appinfo->open_slm = anchor_slm;
+ SLM_EntSetObjects( anchor_slm, WM_DLMDOWN, 2 );
+
+ DLM_Update( hWnd,
+ DLM_FLATLISTBOX,
+ WM_DLMUPDATELIST,
+ (LMHANDLE)wininfo->pFlatList, 0 );
+
+ pQElem = ( Q_ELEM_PTR ) malloc( sizeof( Q_ELEM ) );
+ InitQElem( pQElem );
+ QueuePtr( pQElem ) = (VOID *) hWnd;
+ EnQueueElem( &gq_exchange_win, pQElem, FALSE );
+
+ return SUCCESS;
+}
+
+
+/**********************
+
+ NAME : SLM_DisplayExchangeDLE
+
+ DESCRIPTION :
+
+ Open the window and set the anchor to the slm corresponding to the input dle
+
+ RETURNS :
+
+**********************/
+BOOLEAN SLM_DisplayExchangeDLE(
+ GENERIC_DLE_PTR dle
+)
+{
+
+ GENERIC_DLE_PTR enterprise_dle;
+ HWND enterprise_win;
+ WININFO_PTR wininfo;
+ Q_HEADER_PTR slm_list;
+ SLM_OBJECT_PTR enterprise_slm;
+ SLM_OBJECT_PTR slm;
+ SLM_OBJECT_PTR parent_slm;
+ SLM_OBJECT_PTR sib_slm;
+
+ // First, find the enterprise dle for the input dle.
+ if ( NULL == ( enterprise_dle = DLE_GetEnterpriseDLE( dle ) ) ) {
+
+ return FALSE;
+ }
+
+ // Next, get the enterprise window.
+ if ( ! ( enterprise_win = DLE_GetEnterpriseWindow( enterprise_dle ) ) ) {
+
+ return FALSE;
+ }
+
+ // Get the enterprise slm.
+ if ( NULL != ( wininfo = WM_GetInfoPtr( enterprise_win ) ) ) {
+
+ if ( NULL != ( slm_list = WMDS_GetTreeList( wininfo ) ) ) {
+
+ if ( NULL != ( enterprise_slm = VLM_GetFirstSLM( slm_list ) ) ) {
+
+ if ( NULL == ( slm = SLM_FindByDLE( dle, enterprise_slm ) ) ) {
+
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ // Set the display attributes for the slm, its parent, grandparents, and aunts and uncles
+ // Direct ancestors get display & expand, aunts, uncles and siblings get diplay.
+ if ( ! ( INFO_DISPLAY & SLM_GetStatus( slm ) ) ) {
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) | INFO_DISPLAY );
+
+ parent_slm = SLM_GetParent( slm );
+
+ while ( parent_slm ) {
+
+ // First the parent
+ SLM_SetStatus( parent_slm, SLM_GetStatus( slm ) | INFO_DISPLAY | INFO_EXPAND );
+
+ // Then the sibs
+ sib_slm = VLM_GetNextSLM( parent_slm );
+
+ while( sib_slm ) {
+
+ SLM_SetStatus( sib_slm, SLM_GetStatus( slm ) | INFO_DISPLAY );
+ sib_slm = sib_slm->next_brother;
+ }
+
+ parent_slm = SLM_GetParent( parent_slm );
+ }
+ }
+
+ // Restore the window if it's iconic
+ if ( IsIconic( enterprise_win ) ) {
+
+ SendMessage( ghWndMDIClient, WM_MDIRESTORE, (MPARAM1) enterprise_win, (MPARAM2) 0 );
+ }
+
+ // Update the listbox in the window and set the anchor to the newfound slm.
+ DLM_Update( enterprise_win, DLM_TREELISTBOX, WM_DLMUPDATELIST, (LMHANDLE)slm_list, 0 );
+
+ SLM_EntSetObjects( slm, WM_DLMDOWN, 2 );
+
+ return TRUE;
+
+}
+
+/**********************
+
+ NAME : SLM_FreeSLMList
+
+ DESCRIPTION :
+
+ The user has closed an Exchange window (or all of them) and we need to
+ free up the SLM lists displayed in the window.
+
+ RETURNS :
+
+**********************/
+
+VOID SLM_EMSFreeSLMList(
+ Q_HEADER_PTR pqHdr
+)
+{
+ SLM_OBJECT_PTR slm;
+ Q_ELEM_PTR pElem;
+
+ if ( pqHdr == NULL ) {
+
+ return;
+ }
+
+ pElem = DeQueueElem( pqHdr );
+
+ while ( pElem != NULL ) {
+
+ slm = ( SLM_OBJECT_PTR ) QueuePtr( pElem );
+
+ if( slm != NULL ) {
+
+ // Remove the BSD for this slm.
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) & ~INFO_SELECT );
+ SLM_AddBSD( slm );
+
+ free( slm );
+ }
+
+ pElem = DeQueueElem( pqHdr );
+ }
+}
+
+
+/**********************
+
+ NAME : VLM_BuildExchangeList
+
+ DESCRIPTION :
+
+ Go through the global DLE list and create VLM entries for all the
+ enterprises you find.
+
+ RETURNS : nothing
+
+**********************/
+
+static SLM_OBJECT_PTR VLM_BuildExchangeList(
+Q_HEADER_PTR enterprise_list, // I - queue of enterprises
+WININFO_PTR wininfo,
+GENERIC_DLE_PTR server_dle ) // I
+{
+ GENERIC_DLE_PTR enterprise_dle;
+ SLM_OBJECT_PTR enterprise_slm;
+ CHAR dev_name[MAX_DEVICE_NAME_LEN];
+ SLM_OBJECT_PTR return_slm = NULL;
+ // SLM_OBJECT_PTR brother_slm;
+
+ if ( NULL == server_dle ) {
+
+ return ( NULL );
+ }
+
+ // Find the enterprise DLE for the server
+ enterprise_dle = DLE_GetEnterpriseDLE( server_dle );
+
+ if ( enterprise_dle != NULL ) {
+
+ if ( ( SLM_FindSLMByName( enterprise_list,
+ DLE_GetDeviceName( enterprise_dle ) ) ) == NULL ) {
+
+ DLE_DeviceDispName( enterprise_dle, dev_name, MAX_DEVICE_NAME_LEN, 0 );
+
+ enterprise_slm = SLM_CreateSLM( strsize( dev_name ),
+ (INT16)(strsize( DLE_GetDeviceName( enterprise_dle ) ) ),
+ (INT) 4,
+ FALSE,
+ FALSE );
+
+ if ( enterprise_slm != NULL ) {
+
+ SLM_SetName( enterprise_slm, dev_name );
+ SLM_SetOriginalName( enterprise_slm, DLE_GetDeviceName( enterprise_dle ) );
+ SLM_SetStatus( enterprise_slm, INFO_DISPLAY | INFO_VALID | INFO_EXPAND );
+ SLM_SetLevel( enterprise_slm, 0 );
+ SLM_SetAttribute( enterprise_slm, 0 );
+ SLM_SetXtraBytes( enterprise_slm, wininfo );
+ SLM_SetNextBrother( enterprise_slm, NULL );
+ SLM_SetMailType( enterprise_slm, EMS_ENTERPRISE );
+ SLM_SetParent( enterprise_slm, NULL );
+ SLM_SetDle( enterprise_slm, enterprise_dle );
+
+ EnQueueElem( enterprise_list, &(enterprise_slm->q_elem), FALSE );
+
+ // Now let check for children do the rest
+
+ if ( SLM_FindEnterpriseChildren( enterprise_list, enterprise_slm, -1, server_dle, &return_slm ) ) {
+
+ SLM_SetStatus( enterprise_slm, SLM_GetStatus( enterprise_slm ) | (UINT16)INFO_SUBS );
+
+ VLM_UpdateBrothers( enterprise_list );
+ }
+ }
+ }
+ }
+
+ return ( return_slm );
+}
+
+
+/**********************
+
+ NAME : SLM_FindSLMByName
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static SLM_OBJECT_PTR SLM_FindSLMByName (
+ Q_HEADER_PTR slm_list, CHAR_PTR name
+ )
+{
+ SLM_OBJECT_PTR slm;
+
+ slm = VLM_GetFirstSLM( slm_list );
+
+ while ( slm != NULL ) {
+
+ if ( ! stricmp( name, SLM_GetOriginalName( slm ) ) ) {
+ return( slm );
+ }
+
+ slm = VLM_GetNextSLM( slm );
+ }
+
+ return( slm );
+
+}
+
+/**********************
+
+ NAME : SLM_XchgCompare
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+INT16 SLM_XchgCompare(
+Q_ELEM_PTR e1, // I - queue element 1
+Q_ELEM_PTR e2 ) // I - queue element 2
+{
+ SLM_OBJECT_PTR slm1, slm2;
+
+ slm1 = ( SLM_OBJECT_PTR )e1->q_ptr;
+ slm2 = ( SLM_OBJECT_PTR )e2->q_ptr;
+
+ // sort by alphabet
+
+ return( (INT16)stricmp( SLM_GetName( slm1 ), SLM_GetName( slm2 ) ) );
+}
+
+
+/**********************
+
+ NAME : SLM_FindExchangeChildren
+
+ DESCRIPTION :
+
+ We wish to see what children exist for a given enterprise. So do a quick
+ attach to make the children visible and build SLM structures for them.
+
+ RETURNS : number of children (volumes) found.
+
+**********************/
+
+
+static INT SLM_FindEnterpriseChildren(
+ Q_HEADER_PTR exchange_list,
+ SLM_OBJECT_PTR enterprise_slm,
+ INT level,
+ GENERIC_DLE_PTR server_dle,
+ SLM_OBJECT_PTR *return_slm
+ )
+{
+
+ *return_slm = SLM_AddInExchangeChildren( exchange_list, enterprise_slm, level, server_dle );
+
+ return( DLE_GetNumChild( SLM_GetDle( enterprise_slm) ) );
+}
+
+/**********************
+
+ NAME : SLM_AddInExchangeChildren
+
+ DESCRIPTION :
+
+ Adds SLM structures for all the Exchange volumes.
+
+
+ RETURNS : nothing.
+
+**********************/
+
+static SLM_OBJECT_PTR SLM_AddInExchangeChildren(
+ Q_HEADER_PTR exchange_list,
+ SLM_OBJECT_PTR parent_slm , // I - Exchange slm
+ INT level,
+ GENERIC_DLE_PTR server_dle
+ )
+{
+ GENERIC_DLE_PTR parent_dle;
+ GENERIC_DLE_PTR dle;
+ SLM_OBJECT_PTR slm;
+ SLM_OBJECT_PTR return_slm = NULL;
+ SLM_OBJECT_PTR prev_slm_inserted = NULL;
+ SLM_OBJECT_PTR sibling_slm = NULL;
+ WININFO_PTR wininfo;
+ CHAR dev_name[ MAX_DEVICE_NAME_LEN ];
+ UINT16 dev_name_len;
+ UINT32 server_status = INFO_VALID;
+
+ wininfo = SLM_GetXtraBytes ( parent_slm );
+ parent_dle = SLM_GetDle( parent_slm );
+
+ if ( parent_dle == NULL ) {
+ return ( NULL );
+ }
+
+ DLE_GetFirstChild( parent_dle, &dle );
+
+ while ( dle != NULL ) {
+
+ if ( ( DLE_GetDeviceSubType( dle ) != EMS_MDB ) &&
+ ( DLE_GetDeviceSubType( dle ) != EMS_DSA ) ) {
+
+ DLE_DeviceDispName( dle, dev_name, MAX_DEVICE_NAME_LEN, 0 );
+ dev_name_len = strsize( dev_name );
+
+ if ( ( (slm = SLM_FindSLMByName( WMDS_GetTreeList ( wininfo ),
+ dev_name )) == NULL) || slm->level <= parent_slm->level ) {
+
+ slm = SLM_CreateSLM( dev_name_len,
+ strsize( DLE_GetDeviceName( dle ) ) ,
+ (INT)( ( 4 * ( ( ( SLM_GetLevel( parent_slm ) + 1 ) / 32 ) + 1 ) ) ),
+ FALSE,
+ FALSE );
+
+ if ( slm != NULL ) {
+
+ SLM_SetName( slm, dev_name );
+ SLM_SetOriginalName( slm, DLE_GetDeviceName( dle ) );
+ SLM_SetLevel( slm, SLM_GetLevel( parent_slm ) + 1 );
+ SLM_SetAttribute( slm, 0 );
+ SLM_SetXtraBytes( slm, wininfo );
+ SLM_SetNextBrother( slm, NULL );
+ SLM_SetMailType( slm, DLE_GetDeviceSubType( dle ) );
+ SLM_SetParent( slm, parent_slm );
+ SLM_SetDle( slm, dle );
+
+ // Show all the siblings of the connected server
+ if ( dle == server_dle ) {
+
+ SLM_SetStatus( parent_slm, SLM_GetStatus( parent_slm ) | INFO_EXPAND );
+ server_status = INFO_VALID | INFO_DISPLAY;
+
+ // Get first child of the parent and mark it and all brothers.
+ sibling_slm = VLM_GetNextSLM( parent_slm );
+
+ while ( sibling_slm ) {
+
+ SLM_SetStatus ( sibling_slm, server_status );
+ sibling_slm = sibling_slm->next_brother;
+ }
+
+ // Save the current slm for returning.
+ return_slm = slm;
+ }
+
+ switch( DLE_GetDeviceSubType( dle ) ) {
+
+ case EMS_SERVER:
+ SLM_SetStatus( slm, server_status );
+ break;
+
+ case EMS_SITE:
+ SLM_SetStatus( slm, INFO_VALID | INFO_DISPLAY );
+ break;
+
+ default:
+ SLM_SetStatus( slm, INFO_VALID | INFO_DISPLAY | INFO_EXPAND );
+ break;
+
+ }
+
+ // Added the new slm to the total list and the parent's children.
+ VLM_InsertXchgSLM( exchange_list, parent_slm, prev_slm_inserted, slm );
+ prev_slm_inserted = slm;
+
+ if ( DLE_GetNumChild( dle ) > 0 ) {
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) | (UINT16)INFO_SUBS );
+
+ if ( 1 != level ) { // -1 means keep going until you run out of DLE children
+
+ sibling_slm = SLM_AddInExchangeChildren( exchange_list, slm, level - 1, server_dle );
+
+ if ( NULL != sibling_slm ) {
+ return_slm = sibling_slm;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ DLE_GetNext( &dle );
+ }
+
+ return ( return_slm );
+ // SortQueue( & SLM_GetChildren( parent_slm ), SLM_XchgCompare );
+}
+
+/***************************************************
+
+ Name: SLM_CreateSLM
+
+ Description:
+
+ Creates an SLM object for you.
+
+ Returns: either a pointer or NULL.
+
+*****************************************************/
+
+
+static SLM_OBJECT_PTR SLM_CreateSLM(
+ INT name_size,
+ INT original_name_size,
+ INT brother_bytes,
+ BOOLEAN use_stats,
+ BOOLEAN fat_drive )
+{
+ SLM_OBJECT_PTR slm;
+ INT slm_size;
+
+ // Everything must be 32 bit (4 byte) aligned for MIPs, so we
+ // round up all the sizes to the next 4 byte boundary (if
+ // required).
+
+ slm_size = sizeof( SLM_OBJECT );
+ if ( slm_size % 4 ) {
+ slm_size += 4 - ( slm_size % 4 );
+ }
+
+ if ( brother_bytes % 4 ) {
+ brother_bytes += 4 - ( brother_bytes % 4 );
+ }
+
+ if ( name_size % 4 ) {
+ name_size += 4 - ( name_size % 4 );
+ }
+
+ if ( original_name_size % 4 ) {
+ original_name_size += 4 - ( original_name_size % 4 );
+ }
+
+ slm = ( SLM_OBJECT_PTR )malloc( slm_size +
+ name_size +
+ original_name_size +
+ brother_bytes +
+ 0 );
+
+ if ( slm != NULL ) {
+
+ // The seemingly redundant casting is for unicode support
+
+ slm->name = (CHAR_PTR) ( ((BYTE_PTR)slm) + slm_size );
+ slm->original_name = (CHAR_PTR) ( ((BYTE_PTR)slm->name) + name_size );
+ slm->brothers = ((BYTE_PTR)slm->original_name) + original_name_size;
+ slm->q_elem.q_ptr = slm;
+ }
+
+ return( slm );
+}
+
+/**********************
+
+ NAME : VLM_InsertXchgSLM
+
+ DESCRIPTION :
+
+ Used to insert an slm into an Exchange based tree.
+
+ RETURNS :
+
+**********************/
+
+static VOID VLM_InsertXchgSLM(
+ Q_HEADER_PTR slm_list,
+ SLM_OBJECT_PTR parent_slm,
+ SLM_OBJECT_PTR prev_slm,
+ SLM_OBJECT_PTR new_slm
+ )
+{
+
+ SLM_OBJECT_PTR temp_slm; // used to move through list
+ SLM_OBJECT_PTR best_slm; // insert after this guy
+ SLM_OBJECT_PTR last_brother; // new guy's prev brother after insertion
+ SLM_OBJECT_PTR next_brother; // new guy's next brother after insertion
+ INT level; // height of new guy in tree
+
+
+ // Get height of new item.
+
+ level = new_slm->level;
+
+ // Now find the right location to insert the new slm among his brothers.
+
+ best_slm = parent_slm;
+
+ last_brother = NULL;
+ next_brother = NULL;
+
+ // Try to skip a bunch of the brothers, to speed the insertion.
+
+ if ( prev_slm != NULL ) {
+
+ if ( stricmp( prev_slm->name, new_slm->name ) < 0 ) {
+
+ best_slm = prev_slm;
+ last_brother = best_slm;
+ }
+ }
+
+ temp_slm = best_slm;
+
+ if ( best_slm->level < level ) {
+
+ temp_slm = VLM_GetNextSLM( best_slm );
+ if ( ( temp_slm != NULL ) && ( temp_slm->level != level ) ) {
+ temp_slm = NULL;
+ }
+ }
+
+ // Look through all this guys brothers for correct insertion spot.
+ // temp_slm is NULL or first brother in family.
+
+ while ( temp_slm ) {
+
+ next_brother = temp_slm;
+
+ if ( stricmp( temp_slm->name, new_slm->name ) >= 0 ) {
+
+ // Get out of while loop, we have found the
+ // correct brother to insert before.
+ break;
+ }
+
+ last_brother = temp_slm;
+ best_slm = temp_slm;
+ temp_slm = temp_slm->next_brother;
+ }
+
+ // Insert after best_slm and any children > level.
+ // best_slm may have children and we need to insert after those kids.
+
+ if ( ( best_slm->level == level ) && ( best_slm->next_brother != NULL ) ) {
+
+ // If same height get last kid slm before next brother.
+
+ best_slm = VLM_GetPrevSLM( best_slm->next_brother );
+
+ }
+ else {
+
+ temp_slm = best_slm;
+
+ while ( temp_slm ) {
+
+ if ( temp_slm->level < level ) {
+
+ break;
+ }
+
+ best_slm = temp_slm;
+
+ if ( temp_slm->next_brother != NULL ) {
+ temp_slm = temp_slm->next_brother;
+ }
+ else {
+ temp_slm = VLM_GetNextSLM( temp_slm );
+ }
+
+ }
+ }
+
+ // Update the next_brother pointers.
+
+ if ( last_brother != NULL ) {
+
+ // new_slm is not the first brother.
+
+ new_slm->next_brother = last_brother->next_brother;
+ last_brother->next_brother = new_slm;
+ }
+ else {
+
+ // We need to set this guy's next brother if he has one.
+ // new_slm has become the first brother in the family.
+
+ new_slm->next_brother = next_brother;
+ }
+
+ // Perform insertion.
+
+ InsertElem( slm_list, &(best_slm->q_elem), &(new_slm->q_elem), AFTER );
+}
+
+/**********************
+
+ NAME : SLM_EntSetSelect
+
+ DESCRIPTION :
+
+ RETURNS : nothing
+
+**********************/
+
+static VOID_PTR SLM_EntSetSelect(
+SLM_OBJECT_PTR enterprise_slm,
+BYTE attr )
+{
+ HWND window;
+ APPINFO_PTR appinfo;
+ WININFO_PTR wininfo;
+ UINT16 status;
+ BOOLEAN all_subdirs;
+ SLM_OBJECT_PTR parent_slm;
+
+ GENERIC_DLE_PTR dle = NULL;
+
+ all_subdirs = (BOOLEAN) CDS_GetIncludeSubdirs( CDS_GetPerm() );
+
+ if ( attr ) {
+
+ if ( all_subdirs ) {
+
+ // include all subdirs
+
+ status = INFO_SELECT;
+ }
+ else {
+ status = (INFO_SELECT|INFO_PARTIAL);
+ }
+ }
+ else {
+ status = 0;
+ }
+
+ window = enterprise_slm->XtraBytes->hWnd;
+ wininfo = WM_GetInfoPtr( window );
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( window );
+
+ if ( status != (UINT16)( enterprise_slm->status & (INFO_SELECT|INFO_PARTIAL) ) ) {
+
+ enterprise_slm->status &= ~(INFO_SELECT|INFO_PARTIAL);
+ enterprise_slm->status |= status;
+
+ if ( FALSE == SLM_AddBSD ( enterprise_slm ) ) {
+
+ DLM_Update( window, DLM_TREELISTBOX, WM_DLMUPDATEITEM, (LMHANDLE)enterprise_slm, 0 );
+ }
+ }
+
+ // If this node is open then update its children in the node list.
+ if ( SLM_GetStatus( enterprise_slm ) & INFO_OPEN ) {
+
+ SLM_UpdateNodeList( enterprise_slm, attr );
+
+ }
+
+ /* Mark the children correctly (this will also update the node list,
+ if any of the children are open). */
+
+ VLM_MarkAllEntSLMChildren( enterprise_slm, attr );
+
+ // If this one's parent is open, then update it counterpart in the node list.
+ parent_slm = SLM_GetParent( enterprise_slm );
+
+ if ( ( NULL != parent_slm ) &&
+ ( SLM_GetStatus ( parent_slm ) & INFO_OPEN ) ) {
+
+ SLM_UpdateNode ( enterprise_slm );
+
+ }
+
+ // Set the selection for the parents to partial, if necessary.
+ VLM_MarkAllEntSLMParents( enterprise_slm, attr );
+
+ return( NULL );
+}
+
+/**********************
+
+ NAME : SLM_AddBSD
+
+ DESCRIPTION :
+
+ Given an slm pointer, create or remove a bsd for its DLE, based on its status.
+
+ RETURNS : TRUE if there's an error, FALSE otherwise.
+
+**********************/
+static INT SLM_AddBSD (
+ SLM_OBJECT_PTR slm
+)
+
+{
+ BSET_OBJECT_PTR pbset = NULL;
+ BSD_PTR pbsd = NULL;
+ FSE_PTR pfse = NULL;
+ BE_CFG_PTR pbeConfig = NULL;
+ GENERIC_DLE_PTR dle;
+ GENERIC_DLE_PTR server_dle = SLM_GetDle( slm );
+
+ if( NULL == server_dle ) {
+
+ return TRUE;
+
+ }
+
+ switch ( SLM_GetMailType( slm ) ) {
+
+ case EMS_SERVER:
+ DLE_GetFirstChild( server_dle, &dle );
+ break;
+
+ case EMS_MDB:
+ case EMS_DSA:
+ dle = SLM_GetDle( slm );
+ break;
+
+ default:
+ dle = NULL;
+ }
+
+ while ( NULL != dle ) {
+
+ pbsd = BSD_FindByDLE ( bsd_list, dle );
+
+ if ( slm->status & INFO_SELECT ) {
+
+ if ( pbsd == NULL ) {
+
+ if ( BSD_CreatFSE( &pfse, (INT16)INCLUDE,
+ (CHAR_PTR) TEXT( "" ),
+ (INT16) sizeof( CHAR ),
+ (CHAR_PTR) ALL_FILES,
+ (INT16) ALL_FILES_LENG,
+ (BOOLEAN) USE_WILD_CARD,
+ (BOOLEAN) TRUE ) != SUCCESS ) {
+
+ return( TRUE );
+
+ }
+
+ pbeConfig = BEC_CloneConfig( CDS_GetPermBEC() );
+ BEC_UnLockConfig( pbeConfig );
+
+ BSD_Add( bsd_list, &pbsd, pbeConfig, NULL,
+ dle, (UINT32)-1L, (UINT16)-1, (INT16)-1, NULL, NULL );
+
+ if ( pbsd != NULL ) {
+
+ BSD_AddFSE( pbsd, pfse );
+ }
+ }
+
+ } else {
+
+ pbsd = BSD_FindByDLE ( bsd_list, dle );
+
+ if ( NULL != pbsd ) {
+
+ BSD_Remove ( pbsd );
+
+ }
+ }
+
+ switch ( SLM_GetMailType ( slm ) ) {
+
+ case EMS_SERVER:
+ DLE_GetNext( &dle );
+ break;
+
+ default:
+ dle = NULL;
+ }
+ }
+
+ return FALSE;
+}
+
+
+/**********************
+
+ NAME : VLM_MarkAllEntSLMChildren
+
+ DESCRIPTION :
+
+ Given an slm pointer, mark all his children as selected, unselected, or
+ partially selected.
+
+ attr: 2 = partial
+ 1 = selected
+ 0 = unselected
+
+ RETURNS :
+
+**********************/
+
+static VOID VLM_MarkAllEntSLMChildren(
+ SLM_OBJECT_PTR enterprise_slm, // I - slm to use
+ BYTE attr // I - attribute to set
+ )
+
+{
+
+ HWND window;
+ INT level;
+ WININFO_PTR wininfo;
+ Q_HEADER_PTR pNodeList;
+ SLM_OBJECT_PTR slm = enterprise_slm;
+
+ window = slm->XtraBytes->hWnd;
+ wininfo = SLM_GetXtraBytes ( slm );
+ pNodeList = WMDS_GetFlatList ( wininfo );
+
+ level = slm->level;
+
+ slm = VLM_GetNextSLM( slm );
+
+ while ( slm != NULL ) {
+
+ if ( slm->level <= level ) {
+ break;
+ }
+
+ if ( attr ) {
+
+ if ( ( SLM_GetStatus( slm ) & (INFO_PARTIAL|INFO_SELECT) ) != INFO_SELECT ) {
+
+ slm->status |= INFO_SELECT;
+ slm->status &= ~INFO_PARTIAL;
+
+ DLM_Update( window, DLM_TREELISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)slm, 0 );
+ }
+ }
+ else {
+
+ if ( slm->status & (INFO_PARTIAL|INFO_SELECT) ) {
+
+ slm->status &= ~(INFO_SELECT|INFO_PARTIAL);
+
+ DLM_Update( window, DLM_TREELISTBOX,
+ WM_DLMUPDATEITEM,
+ (LMHANDLE)slm, 0 );
+ }
+ }
+
+ if ( SLM_GetStatus( slm ) & INFO_OPEN ) {
+
+ SLM_UpdateNodeList( slm, attr );
+
+ }
+
+ SLM_AddBSD( slm );
+
+ slm = VLM_GetNextSLM( slm );
+ }
+
+ if ( SLM_GetStatus( enterprise_slm ) & INFO_OPEN ) {
+
+ SLM_UpdateNodeList( enterprise_slm, attr );
+
+ }
+
+ return;
+
+}
+
+/**********************
+
+ NAME : SLM_UpdateNodeList
+
+ DESCRIPTION :
+
+ Set the status on the list of nodes appearing in the node list window.
+
+ RETURNS :
+
+**********************/
+
+static VOID SLM_UpdateNodeList(
+ SLM_OBJECT_PTR slm,
+ BYTE attr
+)
+{
+ WININFO_PTR wininfo = SLM_GetXtraBytes ( slm );
+ HWND window = WMDS_GetWin ( wininfo );
+ Q_HEADER_PTR pNodeList = WMDS_GetFlatList ( wininfo );
+ SLM_OBJECT_PTR node_slm = VLM_GetFirstSLM( pNodeList );
+ UINT16 status = ( attr ) ? INFO_SELECT : 0;
+
+ while ( NULL != node_slm ) {
+
+ SLM_SetStatus ( node_slm, SLM_GetStatus ( node_slm ) & ~(INFO_SELECT | INFO_PARTIAL ) );
+ SLM_SetStatus ( node_slm, SLM_GetStatus ( node_slm ) | status );
+
+ node_slm = VLM_GetNextSLM( node_slm );
+
+ }
+
+ DLM_Update( window, DLM_FLATLISTBOX, WM_DLMUPDATELIST, (LMHANDLE)node_slm, 0 );
+}
+
+
+/**********************
+
+ NAME : SLM_UpdateNode
+
+ DESCRIPTION :
+
+ Set the status on a node from the tree list also appearing in the flat list.
+
+ RETURNS :
+
+**********************/
+
+static VOID SLM_UpdateNode (
+ SLM_OBJECT_PTR enterprise_slm
+)
+{
+ WININFO_PTR wininfo = SLM_GetXtraBytes ( enterprise_slm );
+ HWND window = WMDS_GetWin ( wininfo );
+ Q_HEADER_PTR pNodeList = WMDS_GetFlatList ( wininfo );
+ SLM_OBJECT_PTR node_slm = VLM_GetFirstSLM( pNodeList );
+ GENERIC_DLE_PTR dle = SLM_GetDle ( enterprise_slm );
+
+ while ( NULL != node_slm ) {
+
+ if ( dle == SLM_GetDle ( node_slm ) ) {
+
+ SLM_SetStatus ( node_slm, SLM_GetStatus ( enterprise_slm ) );
+ break;
+ }
+
+ node_slm = VLM_GetNextSLM( node_slm );
+
+ }
+
+ if ( NULL != node_slm ) {
+
+ DLM_Update( window, DLM_FLATLISTBOX, WM_DLMUPDATEITEM, (LMHANDLE)node_slm, 0 );
+ }
+
+}
+
+
+/**********************
+
+ NAME : VLM_MarkAllEntSLMParents
+
+ DESCRIPTION :
+
+ Marks all the parents of an slm node in the hierarchical tree.
+
+ RETURNS :
+
+**********************/
+
+static VOID VLM_MarkAllEntSLMParents(
+ SLM_OBJECT_PTR enterprise_slm,
+ BYTE attr
+)
+{
+ WININFO_PTR wininfo = SLM_GetXtraBytes ( enterprise_slm );
+ HWND window = WMDS_GetWin ( wininfo );
+ SLM_OBJECT_PTR parent_slm = SLM_GetParent ( enterprise_slm );
+ SLM_OBJECT_PTR child_slm;
+ UINT32 status;
+ UINT8 level;
+
+ while ( NULL != parent_slm ) {
+
+ level = SLM_GetLevel ( parent_slm );
+
+ // We can be sure one child exists so the next slm in the list is the first child.
+ child_slm = VLM_GetNextSLM ( parent_slm );
+
+ status = SLM_GetStatus ( child_slm ) & ( INFO_PARTIAL | INFO_SELECT );
+
+ while ( child_slm ) {
+
+ // If the child has a different selection status then the parent is partial
+ if ( ( SLM_GetStatus ( child_slm ) & ( INFO_PARTIAL | INFO_SELECT ) ) != status ) {
+
+ status = INFO_PARTIAL | INFO_SELECT;
+ break;
+ }
+
+ // If the child's level is less than or equal to the parent's level then it's not a child.
+ child_slm = VLM_GetNextSLM ( child_slm );
+
+ if ( ( NULL == child_slm ) ||
+ ( SLM_GetLevel ( child_slm ) <= level ) ) {
+
+ break ;
+ }
+ }
+
+ status |= SLM_GetStatus ( parent_slm ) & ~( INFO_PARTIAL | INFO_SELECT );
+ SLM_SetStatus ( parent_slm, status );
+
+ DLM_Update( window, DLM_TREELISTBOX, WM_DLMUPDATEITEM, (LMHANDLE)parent_slm, 0 );
+
+ // If this parent's parent is open then update its counterpart in the node window.
+ child_slm = parent_slm;
+
+ parent_slm = SLM_GetParent ( child_slm );
+
+ if ( ( NULL != parent_slm ) &&
+ ( SLM_GetStatus ( parent_slm ) & INFO_OPEN ) ) {
+
+ SLM_UpdateNode ( child_slm );
+ }
+ }
+}
+
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+static BYTE SLM_EntGetSelect( SLM_OBJECT_PTR slm )
+{
+ if ( slm->status & INFO_SELECT ) {
+ return( 1 );
+ }
+ else {
+ return( 0 );
+ }
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+static VOID_PTR SLM_EntSetTag( SLM_OBJECT_PTR slm, BYTE attr )
+{
+
+ if ( attr ) {
+ slm->status |= INFO_TAGGED;
+ }
+ else {
+ slm->status &= ~INFO_TAGGED;
+ }
+ return(NULL);
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+static BYTE SLM_EntGetTag( SLM_OBJECT_PTR slm )
+{
+ if ( INFO_TAGGED & slm->status ) {
+ return( 1 );
+ }
+ else {
+ return( 0 );
+ }
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+static USHORT SLM_EntGetItemCount( Q_HEADER_PTR exchange_list )
+{
+ USHORT count = 0;
+ SLM_OBJECT_PTR slm;
+
+ slm = VLM_GetFirstSLM( exchange_list );
+
+ while ( slm != NULL ) {
+
+ if ( SLM_GetStatus( slm ) & INFO_DISPLAY ) {
+ count++;
+ }
+
+ slm = VLM_GetNextSLM( slm );
+ }
+
+ return( count );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+static VOID_PTR SLM_EntGetFirstItem( Q_HEADER_PTR xchg_list )
+{
+ SLM_OBJECT_PTR slm;
+
+ slm = VLM_GetFirstSLM( xchg_list );
+
+ while ( slm != NULL ) {
+
+ if ( SLM_GetStatus( slm ) & INFO_DISPLAY ) {
+ return( slm );
+ }
+ slm = VLM_GetNextSLM( slm );
+ }
+
+ return( slm );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+static VOID_PTR SLM_EntGetPrevItem( SLM_OBJECT_PTR slm )
+{
+ do {
+
+ slm = VLM_GetPrevSLM( slm );
+
+ if ( slm == NULL ) {
+ break;
+ }
+
+ } while ( ! ( SLM_GetStatus( slm ) & INFO_DISPLAY ) );
+
+ return( slm );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+static VOID_PTR SLM_EntGetNextItem( SLM_OBJECT_PTR slm )
+{
+ do {
+
+ slm = VLM_GetNextSLM( slm );
+
+ if ( slm == NULL ) {
+ break;
+ }
+ } while ( ! ( SLM_GetStatus( slm ) & INFO_DISPLAY ) );
+
+ return( slm );
+}
+
+/**********************
+
+ NAME :
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+static VOID_PTR SLM_EntGetObjects( SLM_OBJECT_PTR slm )
+{
+
+ BYTE_PTR memblk;
+ BYTE_PTR buff;
+ BYTE_PTR source;
+ DLM_ITEM_PTR item;
+ WININFO_PTR wininfo;
+ INT16 num_blocks;
+ INT i;
+
+ /* malloc enough room to store info */
+
+ wininfo = SLM_GetXtraBytes( slm );
+ memblk = ( BYTE_PTR )DLM_GetObjectsBuffer( wininfo->hWndTreeList );
+
+ buff = memblk;
+
+ *buff++ = 3; // number of objects in list to display
+
+ // pass DLM the hierarchical stuff he needs for lines
+
+
+ num_blocks = (UINT16)(( slm->level / 32 ) + 1);
+
+ *buff++ = (BYTE)num_blocks;
+
+ source = (BYTE_PTR)slm->brothers;
+
+ for ( i = 0; i < ( 4 * num_blocks ); i++ ) {
+ *buff++ = *source++;
+ }
+
+ /* Set up check box. */
+
+ item = (DLM_ITEM_PTR)buff;
+
+ DLM_ItemcbNum( item ) = 1;
+ DLM_ItembType( item ) = DLM_CHECKBOX;
+ if ( slm->status & INFO_SELECT ) {
+ DLM_ItemwId( item ) = IDRBM_SEL_ALL;
+ if ( slm->status & INFO_PARTIAL ) {
+ DLM_ItemwId( item ) = IDRBM_SEL_PART;
+ }
+ }
+ else {
+ DLM_ItemwId( item ) = IDRBM_SEL_NONE;
+ }
+ DLM_ItembMaxTextLen( item ) = 0;
+ DLM_ItembLevel( item ) = (BYTE)SLM_GetLevel( slm );
+ // DLM_ItembTag( item ) = 0;
+
+ /* Set up Bitmap, ie. Floppy, Hard, Network. */
+
+ item++;
+
+ DLM_ItemcbNum( item ) = 2;
+ DLM_ItembType( item ) = DLM_BITMAP;
+ DLM_ItemwId( item ) = SLM_GetBitmap( slm );
+ DLM_ItembMaxTextLen( item ) = 0;
+ DLM_ItembLevel( item ) = (BYTE)SLM_GetLevel( slm );
+ DLM_ItembTag( item ) = 0;
+
+ /* Set up the text string to be displayed. */
+
+ item++;
+ DLM_ItemcbNum( item ) = 3;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = (BYTE)(strlen( SLM_GetName( slm ) ) + 1);
+ DLM_ItembLevel( item ) = (BYTE)SLM_GetLevel( slm );
+ DLM_ItembTag( item ) = 0;
+ strcpy( ( CHAR_PTR )DLM_ItemqszString( item ), (CHAR_PTR)SLM_GetName( slm ) );
+
+ return( memblk );
+
+}
+
+
+/**********************
+
+ NAME : SLM_GetBitmap
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static WORD SLM_GetBitmap( SLM_OBJECT_PTR slm )
+{
+
+ GENERIC_DLE_PTR dle;
+
+ dle = SLM_GetDle( slm );
+
+ if ( NULL == dle ) {
+
+ return IDRBM_EMS_ENTERPRISE;
+
+ } else {
+
+ switch ( DLE_GetDeviceSubType( dle ) ) {
+
+ case EMS_ENTERPRISE:
+ return IDRBM_EMS_ENTERPRISE;
+
+ case EMS_SITE:
+ return IDRBM_EMS_SITE;
+
+ case EMS_SERVER:
+ return IDRBM_EMS_SERVER;
+
+ case EMS_MDB:
+ return IDRBM_EMS_MDB;
+
+ case EMS_DSA:
+ return IDRBM_EMS_DSA;
+
+ default:
+ return IDRBM_EMS_ENTERPRISE;
+
+ }
+ }
+}
+
+
+/**********************
+
+ NAME : SLM_EntSetObjects
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+static BOOLEAN SLM_EntSetObjects(
+SLM_OBJECT_PTR slm,
+WORD operation,
+WORD ObjectNum )
+{
+ SLM_OBJECT_PTR temp_slm;
+ SLM_OBJECT_PTR slm2;
+ CHAR keyb_char;
+ Q_HEADER_PTR slm_list;
+ INT level;
+ USHORT count;
+ HWND window;
+
+ APPINFO_PTR appinfo;
+ WININFO_PTR wininfo;
+ GENERIC_DLE_PTR dle;
+ BOOLEAN ret_val = FALSE;
+ // CHAR text[ MAX_UI_RESOURCE_SIZE ];
+
+ wininfo = ( WININFO_PTR )SLM_GetXtraBytes( slm );
+ window = WMDS_GetWin( wininfo );
+ appinfo = ( APPINFO_PTR )WM_GetAppPtr( window );
+
+ if ( operation == WM_DLMCHAR ) {
+
+ keyb_char = (CHAR)ObjectNum;
+
+ keyb_char = (CHAR)toupper( keyb_char );
+
+ temp_slm = slm;
+
+ do {
+
+ temp_slm = VLM_GetNextSLM( temp_slm );
+
+ if ( temp_slm != NULL ) {
+
+ if ( SLM_GetStatus( temp_slm ) & INFO_DISPLAY ) {
+
+ if ( keyb_char == (CHAR)toupper( *SLM_GetName( temp_slm ) ) ) {
+
+ slm = temp_slm;
+ operation = WM_DLMDOWN;
+ ObjectNum = 2;
+ ret_val = TRUE;
+ break;
+ }
+ }
+ }
+
+ } while ( temp_slm != NULL );
+
+ if ( ret_val == FALSE ) {
+ temp_slm = VLM_GetFirstSLM( WMDS_GetTreeList( VLM_GetXtraBytes( slm ) ) );
+
+ while ( temp_slm != NULL && temp_slm != slm ) {
+
+ if ( SLM_GetStatus( temp_slm ) & INFO_DISPLAY ) {
+
+ if ( keyb_char == (CHAR)toupper( *SLM_GetName( temp_slm ) ) ) {
+
+ slm = temp_slm;
+ operation = WM_DLMDOWN;
+ ObjectNum = 2;
+ ret_val = TRUE;
+ }
+ }
+
+ temp_slm = VLM_GetNextSLM( temp_slm );
+
+ }
+ }
+ }
+
+ if ( ( operation == WM_DLMDBCLK || operation == WM_DLMDOWN ) &&
+ ( ObjectNum >= 2 ) ) {
+
+ slm2 = appinfo->open_slm;
+ slm2->status &= ~INFO_OPEN;
+
+ slm->status |= INFO_OPEN;
+ appinfo->open_slm = slm;
+
+ STM_SetIdleText( IDS_READY );
+
+ dle = SLM_GetDle( slm );
+ appinfo->dle = dle;
+
+ // Reset the slm list in the flat display for this slm
+
+ SLM_XchgListReuse( slm );
+
+ // Set the anchor in the Tree list.
+
+ DLM_SetAnchor( WMDS_GetWinTreeList( wininfo ), 0, (LMHANDLE)slm );
+
+ }
+
+ // Look for an expansion or not
+
+ if ( ( operation == WM_DLMDBCLK ) &&
+ ( ObjectNum == 2 || ObjectNum == 3 ) ) {
+
+ slm_list = WMDS_GetTreeList( wininfo );
+
+ if ( SLM_GetStatus( slm ) & INFO_SUBS ) {
+
+ if ( SLM_GetStatus( slm ) & INFO_EXPAND ) {
+
+ level = SLM_GetLevel( slm );
+ slm->status &= ~INFO_EXPAND;
+ slm2 = slm;
+ count = 0;
+
+ do { // while ( TRUE )
+
+ slm2 = VLM_GetNextSLM( slm2 );
+
+ if ( slm2 == NULL ) break;
+
+ if ( SLM_GetLevel( slm2 ) <= level ) break;
+
+ if ( SLM_GetStatus( slm2 ) & INFO_DISPLAY ) {
+
+ slm2->status &= ~(INFO_DISPLAY|INFO_EXPAND);
+ count++;
+ } // if ( SLM_GetStatus( slm2 ) & INFO_DISPLAY )
+
+ } while ( TRUE );
+
+ DLM_Update( window, DLM_TREELISTBOX, WM_DLMDELETEITEMS,
+ (LMHANDLE)slm, count );
+
+ } else {
+
+ // Node needs to be expanded.
+
+ if ( EMS_SERVER != SLM_GetMailType ( slm ) ) {
+
+ WM_ShowWaitCursor( TRUE );
+
+ slm->status |= INFO_EXPAND;
+
+ slm2 = slm;
+ level = SLM_GetLevel( slm );
+ count = 0;
+
+ do {
+
+ slm2 = VLM_GetNextSLM( slm2 );
+
+ if ( slm2 == NULL ) {
+ break;
+ }
+
+ if ( ( slm2->level == level + 1 ) &&
+ ! ( SLM_GetStatus( slm2 ) & INFO_DISPLAY ) ) {
+
+ count++;
+
+ slm2->status |= INFO_DISPLAY;
+ } else {
+
+ if ( SLM_GetLevel( slm2 ) <= level ) {
+ break;
+ }
+ }
+
+ } while ( TRUE );
+
+ STM_DrawIdle();
+
+ DLM_Update( window, DLM_TREELISTBOX, WM_DLMADDITEMS,
+ (LMHANDLE)slm, count );
+
+ WM_ShowWaitCursor( FALSE );
+ }
+ }
+
+ VLM_UpdateBrothers( slm_list );
+ }
+ }
+
+ // update node list display
+
+ slm = VLM_GetFirstSLM( WMDS_GetFlatList( wininfo ) );
+
+ DLM_Update( window, DLM_FLATLISTBOX, WM_DLMUPDATELIST, NULL, 0 );
+
+ if ( slm != NULL ) {
+ DLM_SetAnchor( WMDS_GetWinFlatList( wininfo ), 0, (LMHANDLE)slm );
+ }
+
+ return( ret_val );
+}
+
+/***************************************************
+
+ Name: SLM_XchgListReuse
+
+ Description:
+
+ Every time the user clicks on a different subdirectory this guy gets
+ called to free the previous slm list and create a new one from the
+ slm passed to it.
+
+*****************************************************/
+
+static INT SLM_XchgListReuse(
+ SLM_OBJECT_PTR parent_slm )
+{
+ WININFO_PTR wininfo;
+ APPINFO_PTR appinfo;
+ SLM_OBJECT_PTR slm;
+ SLM_OBJECT_PTR tree_slm;
+ Q_HEADER_PTR flat_list;
+ Q_ELEM_PTR q_elem;
+ GENERIC_DLE_PTR parent_dle;
+ GENERIC_DLE_PTR dle;
+ SLM_OBJECT_PTR prev_slm_inserted = NULL;
+ CHAR dev_name[ MAX_DEVICE_NAME_LEN ];
+
+ wininfo = SLM_GetXtraBytes ( parent_slm );
+ appinfo = ( APPINFO_PTR )WMDS_GetAppInfo( wininfo );
+
+ flat_list = WMDS_GetFlatList( wininfo );
+
+ // Release all the old Node structures in the queue
+
+ if ( !flat_list ) {
+ return SUCCESS ;
+ }
+
+ q_elem = DeQueueElem( flat_list );
+
+ while ( q_elem != NULL ) {
+ free( q_elem->q_ptr );
+ q_elem = DeQueueElem( flat_list );
+ }
+
+ // Now build a new Node list
+
+ parent_dle = SLM_GetDle( parent_slm );
+
+ if ( parent_dle == NULL ) {
+ return ( FAILURE );
+ }
+
+ /* If the parent is a server then the children don't appear in the tree list and need
+ to be created from the DLEs. */
+
+ if ( EMS_SERVER == SLM_GetMailType( parent_slm ) ) {
+
+ DLE_GetFirstChild( parent_dle, &dle );
+
+ while ( NULL != dle ) {
+
+ DLE_DeviceDispName( dle, dev_name, MAX_DEVICE_NAME_LEN, 0 );
+
+ if ( SLM_FindSLMByName( flat_list, DLE_GetDeviceName( dle ) ) == NULL ) {
+
+ slm = SLM_CreateSLM( strsize( dev_name ),
+ strsize( DLE_GetDeviceName( dle ) ),
+ (INT)( ( 4 * ( ( ( SLM_GetLevel( parent_slm ) + 1 ) / 32 ) + 1 ) ) ),
+ FALSE,
+ FALSE );
+
+ if ( slm != NULL ) {
+ SLM_SetName( slm, dev_name );
+ SLM_SetOriginalName( slm, DLE_GetDeviceName( dle ) );
+ SLM_SetStatus( slm, INFO_DISPLAY );
+ SLM_SetLevel( slm, SLM_GetLevel( parent_slm ) + 1 );
+ SLM_SetAttribute( slm, 0 );
+ SLM_SetXtraBytes( slm, wininfo );
+ SLM_SetNextBrother( slm, NULL );
+ SLM_SetMailType( slm, DLE_GetDeviceSubType( dle ) );
+ SLM_SetParent( slm, parent_slm );
+ SLM_SetDle( slm, dle );
+
+ DLE_IncBSDCount( dle );
+
+ // Added the new slm to the total list and the parent's children.
+ EnQueueElem( flat_list, &(slm->q_elem), 0 );
+
+ if ( NULL != BSD_FindByDLE( bsd_list, dle ) ) {
+
+ SLM_SetStatus( slm, SLM_GetStatus( slm ) | INFO_SELECT );
+
+ }
+
+ } else { // slm == NULL
+
+ return ( FAILURE );
+
+ } // if slm != NULL
+
+ } else {
+
+ return ( FAILURE );
+
+ }
+
+ DLE_GetNext( &dle );
+ }
+
+ } else {
+
+ // Children are already in tree list and should be copied.
+
+ tree_slm = VLM_GetNextSLM( parent_slm );
+
+ if ( !tree_slm ) {
+ return SUCCESS ;
+ }
+
+ if ( SLM_GetLevel( tree_slm ) <= SLM_GetLevel( parent_slm ) ) {
+ return SUCCESS;
+ }
+
+ while ( tree_slm != NULL ) {
+
+ dle = SLM_GetDle( tree_slm );
+
+ DLE_DeviceDispName( dle, dev_name, MAX_DEVICE_NAME_LEN, 0 );
+
+ if ( SLM_FindSLMByName( flat_list, DLE_GetDeviceName( dle ) ) == NULL ) {
+
+ slm = SLM_CreateSLM( strsize( dev_name ),
+ strsize( DLE_GetDeviceName( dle ) ),
+ (INT)( ( 4 * ( ( ( SLM_GetLevel( parent_slm ) + 1 ) / 32 ) + 1 ) ) ),
+ FALSE,
+ FALSE );
+
+ if ( slm != NULL ) {
+ SLM_SetName( slm, dev_name );
+ SLM_SetOriginalName( slm, DLE_GetDeviceName( dle ) );
+ SLM_SetStatus( slm, SLM_GetStatus( tree_slm ) );
+ SLM_SetLevel( slm, SLM_GetLevel( tree_slm ) );
+ SLM_SetAttribute( slm, SLM_GetAttribute( tree_slm ) );
+ SLM_SetXtraBytes( slm, wininfo );
+ SLM_SetNextBrother( slm, tree_slm );
+ SLM_SetMailType( slm, DLE_GetDeviceSubType( dle ) );
+ SLM_SetParent( slm, parent_slm );
+ SLM_SetDle( slm, dle );
+
+ DLE_IncBSDCount( dle );
+
+ // Added the new slm to the total list and the parent's children.
+ EnQueueElem( flat_list, &(slm->q_elem), 0 );
+
+ } else {
+
+ return ( FAILURE );
+
+ }
+
+ } else {
+
+ return ( FAILURE );
+
+ }
+
+ tree_slm = SLM_GetNextBrother( tree_slm );
+
+ }
+
+ }
+
+ SortQueue( flat_list, SLM_XchgCompare );
+
+ // Now update the screen to show the new list
+
+ return( SUCCESS );
+}
+
+
+//************
+// VOLUMES
+//************
+
+/*****
+ In my terminology, a volume is a server volume and a disk is a mapped or
+ local dos drive. The user has tagged one or more volumes and hit the
+ select or unselect button. This function does the processing for that
+ command.
+*****/
+
+/**********************
+
+ NAME : VLM_SelectExchangeShares
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+VOID VLM_SelectExchangeShares(
+ BYTE attr,
+ WININFO_PTR wininfo
+)
+{
+
+ SLM_OBJECT_PTR slm;
+ SLM_OBJECT_PTR exchange_slm;
+ HWND exchange_win;
+
+ exchange_win = WMDS_GetWin( wininfo );
+ if ( WM_IsFlatActive( wininfo ) ) {
+
+ // Have the display list manager update our tags for us.
+
+ DLM_UpdateTags( exchange_win, DLM_FLATLISTBOX );
+
+ slm = VLM_GetFirstSLM( wininfo->pFlatList );
+
+ while ( slm != NULL ) {
+
+ if ( slm->status & INFO_TAGGED ) {
+
+ SLM_NodeSetSelect( slm, attr );
+ }
+ slm = VLM_GetNextSLM( slm );
+ }
+ }
+
+ if ( WM_IsTreeActive( wininfo ) ) {
+
+ exchange_slm = VLM_GetFirstSLM( wininfo->pTreeList );
+
+ while ( exchange_slm != NULL ) {
+
+ if ( exchange_slm->status & INFO_TAGGED ) {
+
+ SLM_EntSetSelect( exchange_slm, attr );
+ }
+
+ exchange_slm = VLM_GetNextSLM( exchange_slm );
+ }
+ }
+}
+
+/**********************
+
+ NAME : SLM_NodeSetSelect
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+
+
+static VOID_PTR SLM_NodeSetSelect( SLM_OBJECT_PTR slm_node, BYTE attr )
+{
+
+ SLM_OBJECT_PTR tree_slm;
+ GENERIC_DLE_PTR dle;
+ WININFO_PTR wininfo = SLM_GetXtraBytes ( slm_node );
+ HWND window;
+ UINT32 status;
+
+ // Need to make changes for server children at this point (if that's what we're looking at)
+
+ if ( EMS_SERVER == ( SLM_GetMailType( SLM_GetParent( slm_node ) ) ) ) {
+
+ window = WMDS_GetWin( wininfo );
+
+ status = ( attr ) ? INFO_SELECT : 0;
+
+ if ( status != (UINT32)( SLM_GetStatus( slm_node ) & (INFO_SELECT) ) ) {
+
+ slm_node->status &= ~(INFO_SELECT);
+ slm_node->status |= status;
+
+ if ( FALSE == SLM_AddBSD ( slm_node ) ) {
+
+ DLM_Update( window, DLM_FLATLISTBOX, WM_DLMUPDATEITEM, (LMHANDLE)slm_node, 0 );
+ }
+ }
+
+ // Set the status for the server in the tree window.
+
+ dle = SLM_GetParent( SLM_GetDle( slm_node ) );
+
+ tree_slm = SLM_FindByDLE ( dle, VLM_GetFirstSLM( WMDS_GetTreeList( wininfo ) ) );
+
+ slm_node = VLM_GetFirstSLM ( WMDS_GetFlatList( wininfo ) );
+
+ status = SLM_GetStatus ( slm_node ) & ( INFO_PARTIAL | INFO_SELECT );
+
+ while ( NULL != slm_node ) {
+
+ // If the child has a different selection status then the parent is partial
+ if ( ( SLM_GetStatus ( slm_node ) & ( INFO_PARTIAL | INFO_SELECT ) ) != status ) {
+
+ status = INFO_PARTIAL | INFO_SELECT;
+ break;
+ }
+
+ slm_node = VLM_GetNextSLM ( slm_node );
+
+ }
+
+ status |= SLM_GetStatus ( tree_slm ) & ~( INFO_PARTIAL | INFO_SELECT );
+ SLM_SetStatus ( tree_slm, status );
+
+ DLM_Update( window, DLM_TREELISTBOX, WM_DLMUPDATEITEM, (LMHANDLE)tree_slm, 0 );
+
+ // Now go on up the line.
+ VLM_MarkAllEntSLMParents( tree_slm, attr );
+
+ return( NULL );
+
+ }
+
+ // Change the status in the tree window. This will update the flat window.
+
+ dle = SLM_GetDle( slm_node );
+
+ tree_slm = SLM_FindByDLE ( dle, VLM_GetFirstSLM( WMDS_GetTreeList ( wininfo ) ) );
+
+ if ( tree_slm == NULL ) {
+ return( NULL );
+ }
+
+ SLM_EntSetSelect( tree_slm, attr );
+
+ return( NULL );
+}
+
+
+/**********************
+
+ NAME : SLM_FindByDLE
+
+ DESCRIPTION : Finds the slm in a slm list with a matching DLE
+
+ RETURNS :
+
+**********************/
+
+static SLM_OBJECT_PTR SLM_FindByDLE (
+ GENERIC_DLE_PTR dle,
+ SLM_OBJECT_PTR slm
+)
+{
+ while ( NULL != slm ) {
+
+ if ( dle == SLM_GetDle ( slm ) ) {
+
+ return ( slm );
+ }
+
+ slm = VLM_GetNextSLM ( slm );
+ }
+
+ return ( NULL );
+}
+
+
+/*
+ Get the selection status for the Display Manager.
+*/
+/**********************
+
+ NAME : SLM_NodeGetSelect
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static BYTE SLM_NodeGetSelect( SLM_OBJECT_PTR slm )
+{
+ if ( slm->status & INFO_SELECT ) {
+ return( 1 );
+ }
+ else {
+ return( 0 );
+ }
+}
+
+/*
+ Set the tag status for the Display Manager.
+*/
+/**********************
+
+ NAME : SLM_NodeSetTag
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static VOID_PTR SLM_NodeSetTag( SLM_OBJECT_PTR slm, BYTE attr )
+{
+ if ( attr ) {
+ slm->status |= INFO_TAGGED;
+ }
+ else {
+ slm->status &= ~INFO_TAGGED;
+ }
+
+ return( NULL );
+}
+
+/*
+ Get the tag status for the Display Manager.
+*/
+/**********************
+
+ NAME : SLM_NodeGetTag
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static BYTE SLM_NodeGetTag( SLM_OBJECT_PTR slm )
+{
+ if ( INFO_TAGGED & slm->status ) {
+ return( 1 );
+ }
+ else {
+ return( 0 );
+ }
+}
+
+/*
+ Get the item count in our list for the Display Manager.
+*/
+/**********************
+
+ NAME : SLM_NodeGetItemCount
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static USHORT SLM_NodeGetItemCount( Q_HEADER_PTR vol_list )
+{
+ if ( vol_list == NULL ) {
+ return( 0 );
+ }
+ return( QueueCount(vol_list) );
+}
+
+/*
+ Return the first item for the Display Manager.
+*/
+/**********************
+
+ NAME : SLM_NodeGetFirstItem
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static VOID_PTR SLM_NodeGetFirstItem( Q_HEADER_PTR vol_list )
+{
+ if ( vol_list == NULL ) {
+ return( NULL );
+ }
+ return( QueueHead( vol_list ) );
+}
+
+/*
+ Get the previous list item for the Display Manager.
+*/
+/**********************
+
+ NAME : SLM_NodeGetPrevItem
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static VOID_PTR SLM_NodeGetPrevItem( SLM_OBJECT_PTR slm )
+{
+ return( VLM_GetPrevSLM( slm ) );
+}
+
+/*
+ Get the next list item for the Display Manager.
+*/
+/**********************
+
+ NAME : SLM_NodeGetNextItem
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static VOID_PTR SLM_NodeGetNextItem( SLM_OBJECT_PTR slm )
+{
+ return( VLM_GetNextSLM( slm ) );
+}
+
+/*
+ For a given object get the information that needs to be displayed.
+*/
+/**********************
+
+ NAME : SLM_NodeGetObjects
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static VOID_PTR SLM_NodeGetObjects( SLM_OBJECT_PTR slm )
+{
+ BYTE_PTR memblk;
+ DLM_ITEM_PTR item;
+ WININFO_PTR wininfo;
+
+ /* malloc enough room to store info */
+
+ wininfo = SLM_GetXtraBytes( slm );
+ memblk = ( BYTE_PTR )DLM_GetObjectsBuffer( wininfo->hWndFlatList );
+
+ /* Store the number of items in the first two bytes. */
+
+ *memblk = 3;
+
+ /* Set up check box. */
+
+ item = (DLM_ITEM_PTR)( memblk + 6 );
+
+ DLM_ItemcbNum( item ) = 1;
+ DLM_ItembType( item ) = DLM_CHECKBOX;
+ if ( slm->status & INFO_SELECT ) {
+ DLM_ItemwId( item ) = IDRBM_SEL_ALL;
+ if ( slm->status & INFO_PARTIAL ) {
+ DLM_ItemwId( item ) = IDRBM_SEL_PART;
+ }
+ }
+ else {
+ DLM_ItemwId( item ) = IDRBM_SEL_NONE;
+ }
+ DLM_ItembMaxTextLen( item ) = 0;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+
+ item++;
+ DLM_ItemcbNum( item ) = 2;
+ DLM_ItembType( item ) = DLM_BITMAP;
+ DLM_ItemwId( item ) = SLM_GetBitmap( slm );
+ DLM_ItembMaxTextLen( item ) = 0;
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+
+ /* Set up the text string to be displayed. */
+
+ item++;
+ DLM_ItemcbNum( item ) = 3;
+ DLM_ItembType( item ) = DLM_TEXT_ONLY;
+ DLM_ItemwId( item ) = 0;
+ DLM_ItembMaxTextLen( item ) = (BYTE)strlen( SLM_GetName( slm ) );
+ DLM_ItembLevel( item ) = 0;
+ DLM_ItembTag( item ) = 0;
+ strcpy( ( LPSTR )DLM_ItemqszString( item ), SLM_GetName( slm ) );
+
+ return( memblk );
+
+}
+
+/*
+ Handle that we got a click or a double click.
+*/
+/**********************
+
+ NAME : SLM_NodeSetObjects
+
+ DESCRIPTION :
+
+ RETURNS :
+
+**********************/
+
+static BOOLEAN SLM_NodeSetObjects(
+SLM_OBJECT_PTR slm, // I
+WORD operation, // I
+WORD ObjectNum ) // I
+{
+ Q_HEADER_PTR slm_list;
+ SLM_OBJECT_PTR temp_slm;
+ BOOLEAN ret_val = FALSE;
+ WININFO_PTR wininfo;
+ GENERIC_DLE_PTR dle;
+ GENERIC_DLE_PTR parent_dle;
+ CHAR keyb_char;
+
+ wininfo = ( WININFO_PTR )SLM_GetXtraBytes( slm );
+
+ if ( operation == WM_DLMCHAR ) {
+
+ keyb_char = (CHAR)ObjectNum;
+
+ keyb_char = (CHAR)toupper( keyb_char );
+
+ temp_slm = slm;
+
+ do {
+
+ temp_slm = VLM_GetNextSLM( temp_slm );
+
+ if ( temp_slm != NULL ) {
+
+ if ( SLM_GetStatus( temp_slm ) & INFO_DISPLAY ) {
+
+ if ( keyb_char == (CHAR)toupper( *SLM_GetName( temp_slm ) ) ) {
+
+ slm = temp_slm;
+ operation = WM_DLMDOWN;
+ ObjectNum = 2;
+ ret_val = TRUE;
+ break;
+ }
+ }
+ }
+
+ } while ( temp_slm != NULL );
+
+ if ( ret_val == FALSE ) {
+ temp_slm = VLM_GetFirstSLM( WMDS_GetFlatList( VLM_GetXtraBytes( slm ) ) );
+
+ while ( temp_slm != NULL && temp_slm != slm ) {
+
+ if ( SLM_GetStatus( temp_slm ) & INFO_DISPLAY ) {
+
+ if ( keyb_char == (CHAR)toupper( *SLM_GetName( temp_slm ) ) ) {
+
+ slm = temp_slm;
+ operation = WM_DLMDOWN;
+ ObjectNum = 2;
+ ret_val = TRUE;
+ }
+ }
+
+ temp_slm = VLM_GetNextSLM( temp_slm );
+
+ }
+ }
+ }
+
+ if ( ( operation == WM_DLMDBCLK || operation == WM_DLMDOWN ) &&
+ ( ObjectNum >= 2 ) ) {
+
+ STM_SetIdleText( IDS_READY );
+
+ DLM_SetAnchor( WMDS_GetWinFlatList( wininfo ), 0, (LMHANDLE)slm );
+
+ ret_val = TRUE;
+
+ }
+
+ // Double and single clicks are the same for MDB or DSA nodes.
+ if ( EMS_MDB == SLM_GetMailType( slm ) ||
+ EMS_DSA == SLM_GetMailType( slm ) ) {
+
+ return( ret_val );
+
+ }
+
+ if ( ( operation == WM_DLMDBCLK ) &&
+ ( ObjectNum == 2 || ObjectNum == 3 ) ) {
+
+ wininfo = SLM_GetXtraBytes( slm );
+ slm_list = WMDS_GetTreeList( wininfo );
+
+ dle = SLM_GetDle( slm );
+
+ if ( NULL != dle &&
+ NULL != slm_list ) {
+
+ parent_dle = DLE_GetParent( dle );
+
+ if ( NULL != parent_dle ) {
+
+ slm = SLM_FindByDLE ( parent_dle, VLM_GetFirstSLM( slm_list ) );
+
+ if ( NULL != slm ) {
+
+ if ( !(SLM_GetStatus( slm ) & INFO_EXPAND ) ) {
+
+ SLM_EntSetObjects( slm, WM_DLMDBCLK, 2 );
+ ret_val = TRUE;
+ }
+ }
+ }
+ }
+
+ if ( NULL != dle &&
+ NULL != slm_list ) {
+
+ slm = SLM_FindByDLE ( dle, slm ); // Start at the parent's slm
+
+ if ( NULL != slm ) {
+
+ SLM_EntSetObjects( slm, WM_DLMDOWN, 2 );
+ ret_val = TRUE;
+ }
+ }
+ }
+
+ return( ret_val );
+}
+
+
+/**********************
+
+ NAME : VLM_ExchangeDleExist
+
+ DESCRIPTION : Are there any Exchange DLEs in the dle list?
+
+ RETURNS : TRUE if there are, FALSE otherwise.
+
+**********************/
+
+BOOLEAN VLM_ExchangeDleExist()
+{
+ GENERIC_DLE_PTR pDLE;
+
+ if ( SUCCESS == DLE_GetFirst( dle_list, &pDLE ) ) {
+
+ do {
+
+ if ( FS_EMS_DRV == DLE_GetDeviceType( pDLE ) ) {
+
+ return TRUE;
+ }
+
+ } while ( SUCCESS == DLE_GetNext( &pDLE ) );
+ }
+
+ return FALSE;
+}
+
+
+GENERIC_DLE_PTR DLE_GetEnterpriseDLE(
+ GENERIC_DLE_PTR dle
+)
+{
+ if ( NULL == dle ) return NULL;
+
+ while ( NULL != DLE_GetParent( dle ) ) {
+
+ dle = DLE_GetParent( dle );
+ }
+ if ( DLE_GetDeviceSubType( dle ) == EMS_ENTERPRISE ) {
+
+ return dle;
+
+ } else {
+
+ return NULL;
+ }
+}
+
+static HWND DLE_GetEnterpriseWindow(
+ GENERIC_DLE_PTR enterprise_dle
+)
+{
+ Q_ELEM_PTR pqElem;
+ HWND exchange_win;
+ WININFO_PTR wininfo;
+ Q_HEADER_PTR slm_list;
+ SLM_OBJECT_PTR enterprise_slm;
+
+ pqElem = QueueHead( &gq_exchange_win );
+
+ while ( pqElem != NULL ) {
+
+ if ( exchange_win = ( HWND )QueuePtr( pqElem ) ) {
+
+ if ( NULL != ( wininfo = WM_GetInfoPtr( exchange_win ) ) ) {
+
+ if ( NULL != ( slm_list = WMDS_GetTreeList( wininfo ) ) ) {
+
+ if ( NULL != ( enterprise_slm = VLM_GetFirstSLM( slm_list ) ) ) {
+
+ if ( enterprise_dle == SLM_GetDle( enterprise_slm ) ) {
+
+ return exchange_win;
+ }
+ }
+ }
+ }
+ }
+
+ pqElem = QueueNext( pqElem );
+ }
+
+ return ( (HWND)0 );
+}
+
+#endif // OEM_EMS
+
diff --git a/private/utils/ntbackup/src/vmstubs.c b/private/utils/ntbackup/src/vmstubs.c
new file mode 100644
index 000000000..92017b485
--- /dev/null
+++ b/private/utils/ntbackup/src/vmstubs.c
@@ -0,0 +1,109 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: vmstubs.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description: This module replaces the virtual memory manager with
+ standard malloc.
+
+
+ $Log: J:/LOGFILES/VMSTUBS.C_V $
+
+ Rev 1.2 19 Nov 1992 16:29:50 CHARLIE
+Changed PSIZE to PAGESIZE to avoid NT conflict
+
+ Rev 1.1 16 May 1991 09:40:06 DAVIDH
+Referenced parameters in each function to avoid Watcom compiler warnings.
+
+ Rev 1.0 13 May 1991 10:34:54 STEVEN
+Initial revision.
+
+ Rev 1.0 09 May 1991 13:38:56 HUNTER
+Initial revision.
+
+**/
+/* begin include list */
+#include <stdio.h>
+#include <process.h>
+#include <stdlib.h>
+
+#include "stdtypes.h"
+#include "vm.h"
+#include "msassert.h"
+
+
+VM_HDL VM_InitVM(
+PAGE num_pages,
+PAGESIZE page_size,
+PAGE num_pages_in_mem,
+CHAR_PTR vm_filename,
+VM_PF_CERR critical_error,
+VOID_PTR app_ptr )
+{
+ /* Reference parameters to avoid compiler warnings. */
+ (VOID) num_pages ;
+ (VOID) page_size ;
+ (VOID) num_pages_in_mem ;
+ (VOID) vm_filename ;
+ (VOID) critical_error ;
+ (VOID) app_ptr ;
+
+ return NULL ;
+}
+
+VOID VM_RemoveVM(
+VM_HDL vm_hdl )
+{
+ /* Reference parameter to avoid compiler warnings. */
+ (VOID) vm_hdl ;
+
+ return ;
+}
+
+VM_PTR VM_Alloc(
+VM_HDL vm_hdl,
+UINT16 size )
+{
+ /* Reference parameter to avoid compiler warnings. */
+ (VOID) vm_hdl;
+
+ return( (VM_PTR)malloc( size ) ) ;
+}
+
+
+VOID VM_Free(
+VM_HDL vm_hdl,
+VM_PTR vm_buf )
+{
+ /* Reference parameter to avoid compiler warnings. */
+ (VOID) vm_hdl ;
+
+ free( (VOID_PTR) vm_buf ) ;
+ return;
+}
+
+VOID_PTR VM_MemLock(
+VM_HDL vm_hdl,
+VM_PTR vm_buf,
+INT16 mode )
+{
+ /* Reference parameters to avoid compiler warnings. */
+ (VOID) vm_hdl ;
+ (VOID) mode ;
+
+ return( (VOID_PTR)vm_buf ) ;
+}
+
+VOID VM_MemUnLock(
+VM_HDL vm_hdl,
+VM_PTR vm_buf )
+{
+ /* Reference parameter to avoid compiler warnings. */
+ (VOID) vm_hdl ;
+ (VOID) vm_buf ;
+
+ return;
+}
diff --git a/private/utils/ntbackup/src/vset.dlg b/private/utils/ntbackup/src/vset.dlg
new file mode 100644
index 000000000..2bfeb2979
--- /dev/null
+++ b/private/utils/ntbackup/src/vset.dlg
@@ -0,0 +1,87 @@
+/**************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+RCG
+
+ Name: vset.dlg
+
+ Description: This file contains a dialog template.
+
+ $Log: G:\ui\logfiles\vset.dlv $
+
+ Rev 1.13 16 Jul 1993 10:22:24 KEVINS
+ Allow displaying of the ampersand character.
+
+ Rev 1.12 19 May 1993 10:47:20 KEVINS
+ Added browse button.
+
+ Rev 1.11 15 Apr 1993 12:20:52 CHUCKB
+ Removed hot keys from OK and Cancel.
+
+ Rev 1.10 18 Dec 1992 11:24:26 chrish
+ Moved #include to dialogs.rc
+
+ Rev 1.9 22 Apr 1992 17:07:16 CHUCKB
+ Took out ... from help.
+
+ Rev 1.8 06 Apr 1992 07:38:12 CARLS
+ added DLGINCLUDE
+
+ Rev 1.7 12 Mar 1992 15:51:50 CHUCKB
+ Added ... to Help.
+
+ Rev 1.6 02 Mar 1992 15:39:50 CHUCKB
+ Fixed hotkeys.
+
+ Rev 1.5 25 Feb 1992 16:31:08 CARLS
+ changed combo box size
+
+ Rev 1.4 21 Feb 1992 15:37:30 CHUCKB
+ Changed backup set to backup label.
+
+ Rev 1.3 27 Jan 1992 00:45:24 CHUCKB
+ Updated dialog id's.
+
+ Rev 1.2 18 Dec 1991 11:12:44 CARLS
+
+ Rev 1.1 07 Dec 1991 12:15:38 CARLS
+
+ Rev 1.0 20 Nov 1991 19:18:06 SYSTEM
+ Initial revision.
+
+**************************************************************************/
+
+IDD_VERIFYSET DIALOG 7, 18, 325, 177
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Verify"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ GROUPBOX "Tape Information", IDD_RSET_SET_INFO, 5, 0, 260, 36
+ LTEXT "Tape Name:", IDD_RSET_TAPE_NAME_TEXT, 9, 17, 49, 10,
+ NOT WS_GROUP
+ LTEXT "", IDD_RSET_TAPE_NAME, 61, 17, 195, 10, SS_NOPREFIX |
+ NOT WS_GROUP
+ GROUPBOX "Set Information ", IDD_RSET_INFO_TITLE, 5, 44, 310, 105
+ LTEXT "Verify to &Drive:", IDD_RSET_DRIVE_TEXT, 10, 100, 60, 9,
+ NOT WS_GROUP
+ COMBOBOX IDD_RSET_DRIVE_BOX, 72, 98, 175, 60, CBS_DROPDOWNLIST |
+ CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Backup Label:", IDD_RSET_SET_TEXT, 10, 59, 50, 10, NOT
+ WS_GROUP
+ LTEXT "", IDD_RSET_SET_LINE_1, 60, 59, 193, 10, SS_NOPREFIX |
+ NOT WS_GROUP
+ LTEXT "", IDD_RSET_SET_LINE_2, 35, 72, 213, 22, SS_NOPREFIX |
+ NOT WS_GROUP
+ LTEXT "Verify &Path:", IDD_RSET_PATH_TEXT, 10, 118, 50, 9, NOT
+ WS_GROUP
+ PUSHBUTTON "&Browse", IDD_RSET_BROWSE_BUTTON, 255, 97, 40, 14
+ EDITTEXT IDD_RSET_RESTORE_PATH, 72, 116, 175, 12, ES_AUTOHSCROLL
+ SCROLLBAR IDD_RSET_SCROLLBAR, 304, 48, 11, 100, SBS_VERT |
+ WS_TABSTOP
+ DEFPUSHBUTTON "OK", IDD_RSET_OK_BUTTON, 68, 157, 40, 14
+ PUSHBUTTON "Cancel", IDD_RSET_CANCEL_BUTTON, 128, 157, 40, 14
+ PUSHBUTTON "&Help", IDD_RSET_HELP_BUTTON, 188, 157, 40, 14
+ CONTROL "", 0xFFFF, "Static", SS_BLACKRECT, 9, 149, 309, 4
+ CONTROL "", 0xFFFF, "Static", SS_BLACKRECT, 315, 53, 4, 98
+ CONTROL "", 0xFFFF, "Static", SS_BLACKRECT, 10, 36, 257, 3
+ CONTROL "", 0xFFFF, "Static", SS_BLACKRECT, 265, 9, 3, 30
+END
diff --git a/private/utils/ntbackup/src/winassrt.c b/private/utils/ntbackup/src/winassrt.c
new file mode 100644
index 000000000..843fe4dc1
--- /dev/null
+++ b/private/utils/ntbackup/src/winassrt.c
@@ -0,0 +1,167 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: winassrt.c
+
+ Date Updated: 23-Mar-93
+
+ Description: Some real Windows UI assert code. One must not use
+ the Backup Engine msassert.c in conjunction with this
+ module.
+
+ Notes: These functions do not operate on Unicode strings.
+ Since the compiler always generates ASCII strings
+ from __FILE__ and __LINE__, no attempt is made for
+ automatic remapping and the function parameters
+ must be "char *" not "CHAR_PTR".
+
+
+ $Log: G:/UI/LOGFILES/WINASSRT.C_V $
+
+ Rev 1.5 04 Jan 1994 10:55:46 BARRY
+Don't pass expression to function
+
+ Rev 1.0 04 Jan 1994 10:55:38 BARRY
+Don't pass expression to function
+
+ Rev 1.4 03 Dec 1993 11:27:38 mikep
+handle qtc dll building
+
+ Rev 1.3 16 Nov 1993 15:50:38 BARRY
+Fixes for Unicode; call MessageBox instead of WM_MessageBox
+
+ Rev 1.2 12 Aug 1993 12:53:04 BARRY
+How about checking the expression before asserting in mscassert?
+
+ Rev 1.1 24 May 1993 15:22:16 BARRY
+Unicode fixes.
+
+ Rev 1.0 23 Mar 1993 19:44:12 BARRY
+Initial revision.
+
+**/
+
+#include "all.h"
+
+#define MSASSERT_BUFFER_SIZE 512
+
+static CHAR fmtString[] = TEXT( "Assertion Failed in %s:\n\nExpression: %S\nFile: %S\nLine: %d\n\nSelect OK to continue or Cancel to abort" );
+
+
+/**/
+/**
+
+ Name: msassert_func()
+
+ Description: Creates a modal dialog with information about an
+ assertion failure. Can be used in Windows NT console
+ or Windows applications.
+
+ Modified: 11-Nov-93
+
+ Returns: Nothing
+
+**/
+VOID msassert_func( char *expString, char *fileName, int line )
+{
+ CHAR message[ MSASSERT_BUFFER_SIZE + 1 ];
+ BOOLEAN abort;
+ char *f;
+ STARTUPINFO startupInfo;
+
+ /*
+ * Get the startup info for the process so we can print the
+ * name of the app that's asserting.
+ */
+ GetStartupInfo( &startupInfo );
+
+ /*
+ * Since having the fully qualified path of the source file is of
+ * no real benefit (all source file names are unique), let's strip
+ * off the path. This may be kind of ugly, but it sure is easier
+ * for someone to read the dialog box that pops up.
+ */
+ if ( (f = strrchrA( fileName, '\\' )) != NULL )
+ {
+ f++;
+ }
+ else
+ {
+ f = fileName;
+ }
+
+ /*
+ * Make sure that we are not going to crash trying to do an assert.
+ * Check string sizes along with a guess of a 5 digit line number
+ * as the size of the string.
+ */
+ if ( MSASSERT_BUFFER_SIZE <
+ (strlen( fmtString ) +
+ wcslen( startupInfo.lpTitle ) +
+ strlenA( expString ) +
+ strlenA( f ) + 5) )
+ {
+ abort = TRUE;
+ }
+ else
+ {
+ INT choice = IDCANCEL;
+
+#ifndef QTCDLL
+ /* Form the text for the dialog. */
+ sprintf( message,
+ fmtString,
+ startupInfo.lpTitle,
+ expString,
+ f,
+ line );
+
+ choice = MessageBox( NULL,
+ message,
+ TEXT("Assertion Failed"),
+ MB_TASKMODAL | MB_OKCANCEL | MB_ICONSTOP | MB_DEFBUTTON2 );
+
+#endif
+ /*
+ * The user has the option to continue from the dialog.
+ * Only set the abort flag if they selected cancel.
+ */
+ abort = (choice == IDCANCEL);
+ }
+
+ if ( abort )
+ {
+ RaiseException( EXCEPTION_BREAKPOINT,
+ EXCEPTION_NONCONTINUABLE,
+ 0,
+ NULL ) ;
+ }
+}
+
+/**/
+/**
+
+ Name: mscassert_func()
+
+ Description: Critical assert function. Raises an exception without
+ any attempt to put up a fancy window.
+
+ Modified: 11-Nov-93
+
+ Returns: Nothing
+
+**/
+VOID mscassert_func( char *expString, char *fileName )
+{
+ (void)expString;
+ (void)fileName;
+
+ RaiseException( EXCEPTION_BREAKPOINT,
+ EXCEPTION_NONCONTINUABLE,
+ 0,
+ NULL ) ;
+
+}
+
+
diff --git a/private/utils/ntbackup/src/winmang.c b/private/utils/ntbackup/src/winmang.c
new file mode 100644
index 000000000..05f6a7ada
--- /dev/null
+++ b/private/utils/ntbackup/src/winmang.c
@@ -0,0 +1,2061 @@
+
+/******************************************************************************
+Copyright (c) Maynard, an Archive Company. 1991
+GSH
+
+ Name: winmang.c
+
+ Description: This file contains the functions for the GUI Window
+ Manager (WM).
+
+ The following routines are in this module:
+
+ WM_CloseAllDocs
+ WM_Create
+ WM_CreateObjects
+ WM_Deinit
+ WM_DeleteObjects
+ WM_GetNext
+ WM_Init
+ WM_QueryCloseAllDocs
+ WM_SetAppIcon
+ WM_SetMinTitle
+ WM_SetTitle
+ WM_SubClassListBox
+ WM_SubClassMDIClient
+ WM_ShowWaitCursor
+ WM_SetCursor
+
+ $Log: G:\UI\LOGFILES\WINMANG.C_V $
+
+ Rev 1.56.1.3 31 Jan 1994 10:34:18 Glenn
+Changed memcpy to strncpy - UNICODE fix.
+
+ Rev 1.56.1.2 26 Jan 1994 12:34:32 Glenn
+Invalidating rect when moving window so that a complete repaint occurs.
+
+ Rev 1.56.1.1 08 Dec 1993 20:20:44 GREGG
+Added Mikes deep path fix to Orcas branch.
+
+ Rev 1.56.1.0 04 Nov 1993 15:46:28 STEVEN
+japanese changes
+
+ Rev 1.56 05 Aug 1993 17:35:56 GLENN
+Now restoring docs only if minimized.
+
+ Rev 1.55 28 Jul 1993 18:55:16 MARINA
+enable c++
+
+ Rev 1.54 19 Jul 1993 11:14:50 GLENN
+Clearing out the menu state if not menu bits are specified. More objective way.
+
+ Rev 1.53 01 Jun 1993 15:43:34 DARRYLP
+Setting the Icon for the last Icon change.
+
+ Rev 1.52 26 May 1993 16:26:24 DARRYLP
+Reactivated the animated app icon.
+
+ Rev 1.51 18 May 1993 18:32:42 GLENN
+Changed RestoreDocs code to activate the existing top window if it was new (closable).
+
+ Rev 1.50 18 May 1993 14:56:00 GLENN
+Appended INI base name to the title of frame and runtime dialog.
+
+ Rev 1.49 06 May 1993 08:53:50 MIKEP
+Fix for epr 355 to bring cataloged set window to foreground after
+cataloging completes.
+
+ Rev 1.48 22 Apr 1993 15:57:48 GLENN
+Added file SORT option support.
+
+ Rev 1.47 18 Feb 1993 13:59:58 BURT
+Change for Cayman
+
+
+ Rev 1.46 16 Dec 1992 10:25:38 STEVEN
+fix mips bugs
+
+ Rev 1.45 14 Dec 1992 12:25:52 DAVEV
+Enabled for Unicode compile
+
+ Rev 1.44 18 Nov 1992 11:39:14 GLENN
+Release the cursor capture if the cursor point is outside of the frame.
+
+ Rev 1.43 01 Nov 1992 16:15:02 DAVEV
+Unicode changes
+
+ Rev 1.42 30 Oct 1992 15:47:24 GLENN
+Added Frame and MDI Doc window size and position saving and restoring.
+
+ Rev 1.41 14 Oct 1992 15:53:50 GLENN
+Added Font selection to Config and INI.
+
+ Rev 1.40 04 Oct 1992 19:44:08 DAVEV
+Unicode Awk pass
+
+ Rev 1.39 02 Oct 1992 16:52:26 GLENN
+Added WM_SetCursor() to help fix NT WM_ShowWaitCursor problems when leaving app.
+
+ Rev 1.38 28 Sep 1992 17:03:02 GLENN
+MikeP changes (strcpy to memcpy).
+
+ Rev 1.37 17 Sep 1992 15:54:14 DAVEV
+UNICODE modifications: strlen usage check
+
+ Rev 1.36 10 Sep 1992 17:05:54 GLENN
+Set the tool bar background color to be like FM.
+
+ Rev 1.35 09 Sep 1992 17:00:54 GLENN
+Updated NEW LOOK font stuff for BIMINI.
+
+ Rev 1.34 02 Sep 1992 15:13:14 GLENN
+Created a highlight brush and color. Moved the font stuff to font.c
+
+ Rev 1.33 29 Jul 1992 14:23:18 GLENN
+ChuckB checked in after NT fixes.
+
+ Rev 1.32 10 Jul 1992 10:13:52 GLENN
+In process of adding font selection support.
+
+ Rev 1.31 07 Jul 1992 15:32:24 MIKEP
+unicode changes
+
+ Rev 1.30 10 Jun 1992 16:14:54 GLENN
+Updated according to NT SPEC.
+
+ Rev 1.29 15 May 1992 13:32:26 MIKEP
+nt pass 2
+
+ Rev 1.28 05 May 1992 15:59:04 JOHNWT
+changed ternary thing
+
+ Rev 1.27 22 Apr 1992 17:50:36 GLENN
+Put in auto log to debug file when /z is used.
+
+ Rev 1.26 20 Apr 1992 13:48:22 GLENN
+Added status line get/set capability.
+
+ Rev 1.25 07 Apr 1992 15:39:22 GLENN
+Fixed WM_MakeAppActive() to bring up frame.
+
+ Rev 1.24 02 Apr 1992 15:44:18 GLENN
+NT font and class changes - TESTED in WP and NT.
+
+ Rev 1.23 31 Mar 1992 11:23:28 DAVEV
+OEM_MSOFT: no icon animation allowed
+
+ Rev 1.22 24 Mar 1992 10:34:28 ROBG
+Added logic to use system colors when creating a log file view.
+
+ Rev 1.21 19 Mar 1992 14:29:02 STEVEN
+do not subclass MDI client if getlong fails - NTKLUG
+
+ Rev 1.20 19 Mar 1992 11:44:54 JOHNWT
+added WM_MakeAppActive
+
+ Rev 1.19 10 Mar 1992 16:28:16 GLENN
+Added WM_MoveWindow().
+
+ Rev 1.18 03 Mar 1992 18:24:46 GLENN
+Updated animate icon. Added new log view window support.
+
+ Rev 1.17 23 Feb 1992 13:44:54 GLENN
+Added valid window check to ResoreDocs().
+
+ Rev 1.16 20 Feb 1992 11:16:58 GLENN
+Changed the MDI create maximized code for NT compatibility.
+
+ Rev 1.15 18 Feb 1992 21:02:28 GLENN
+Added support for min/max/restore docs before/after operations.
+
+ Rev 1.14 11 Feb 1992 17:30:18 GLENN
+Added support for MDI client subclassing.
+
+ Rev 1.13 05 Feb 1992 17:56:38 GLENN
+Yanked out win32 redundant code.
+
+ Rev 1.12 29 Jan 1992 18:02:30 GLENN
+Increased animate icon rect.
+
+ Rev 1.11 24 Jan 1992 14:54:00 GLENN
+Changed HM_Deinit call to match it's prototype.
+
+ Rev 1.10 23 Jan 1992 12:30:58 GLENN
+Added defs for array sizes.
+
+ Rev 1.9 23 Jan 1992 09:04:44 MIKEP
+fix title size
+
+ Rev 1.8 21 Jan 1992 13:32:26 GLENN
+Added WM_AnimateAppIcon() function.
+
+ Rev 1.7 10 Jan 1992 16:39:04 JOHNWT
+moved set idle text from GUI_Init to WM_Init
+
+ Rev 1.6 07 Jan 1992 17:40:32 GLENN
+Changed debug stuff
+
+ Rev 1.5 26 Dec 1991 13:46:28 GLENN
+Changed show flags to use CDS calls
+
+ Rev 1.4 11 Dec 1991 13:03:34 DAVEV
+16/32 bit port -2nd pass
+
+ Rev 1.3 10 Dec 1991 13:56:44 GLENN
+Added feature to WM_Create function to create single column FLAT list boxes
+
+ Rev 1.2 04 Dec 1991 15:20:42 DAVEV
+Modifications for 16/32-bit Windows port - 1st pass.
+
+
+ Rev 1.1 03 Dec 1991 15:58:58 GLENN
+Updated as per code review.
+
+ Rev 1.0 20 Nov 1991 19:25:44 SYSTEM
+Initial revision.
+
+******************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+// PRIVATE DEFINITIONS
+
+#define MAX_FONTFACENAME_LEN 30
+
+// MODULE-WIDE VARIABLES
+
+static HWND mwhWndLastTop = (HWND)NULL;
+static BOOL mwfWaiting = FALSE; // flag showing current show wait state
+static BOOL mwfDocsMinimized = FALSE;
+
+// PRIVATE FUNCTION PROTOTYPES
+
+
+// FUNCTIONS
+
+/******************************************************************************
+
+ Name: WM_CloseAllDocs()
+
+ Description: This function sends a destroy message to all MDI documents.
+ Effectively, all MDI primary document windows are minimized
+ and all secondary MDI document windows are destroyed.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID WM_CloseAllDocs ( VOID )
+{
+ HWND hWndTemp;
+
+ // Hide the MDI client window to avoid multiple repaints.
+
+ WM_Hide( ghWndMDIClient );
+
+ // As long as the MDI client has a child, minimize it or destroy it.
+
+ while ( hWndTemp = GetWindow ( ghWndMDIClient, GW_CHILD ) ) {
+
+ // Skip the icon title windows.
+
+ while ( hWndTemp && GetWindow ( hWndTemp, GW_OWNER ) ) {
+ hWndTemp = GetWindow ( hWndTemp, GW_HWNDNEXT );
+ }
+
+ if ( ! hWndTemp ) {
+ break;
+ }
+
+ // Destroy the window.
+
+ SendMessage ( ghWndMDIClient, WM_MDIDESTROY, (MP1)hWndTemp, 0L );
+ }
+
+} /* end WM_CloseAllDocs() */
+
+
+/******************************************************************************
+
+ Name: WM_Create()
+
+ Description: This function creates a window of the specified type.
+
+ Returns: A handle to the newly created window if successful.
+ Otherwise, returns NULL.
+
+ Notes: It is a good idea to refer to the GUI Window Manager
+ Documentation about this function. When creating a ribbon
+ window, the pdsWinInfo parameter will contain the parent
+ to the ribbon being created.
+
+******************************************************************************/
+
+HWND WM_Create (
+
+WORD wType, // I - type of window to create
+LPSTR pszTitle, // I - window title
+LPSTR pszMinTitle, // I - short version of the window title
+INT X, // I - upper left X position
+INT Y, // I - upper left Y position
+INT nWidth, // I - width
+INT nHeight, // I - height
+PDS_WMINFO pdsWinInfo ) // I - window info structure to be attached
+ // to the window's extra bytes
+
+{
+
+ HWND hWnd;
+ DWORD dwStyle;
+
+ // Determine the display window size.
+
+ switch ( wType & WM_MINMAX_BITS ) {
+
+ case WM_MIN:
+ dwStyle = WS_ICONIC;
+ break;
+
+ case WM_MAX:
+ dwStyle = WS_MAXIMIZE;
+ break;
+
+ default:
+ dwStyle = 0;
+ break;
+ }
+
+ // Determine and create the appropriate window.
+
+ switch ( wType & WM_TYPE_BITS ) {
+
+ case WM_FRAME: // Create the frame window.
+
+ dwStyle |= WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
+
+ hWnd = CreateWindow( WMCLASS_FRAME, // class name
+ pszTitle, // window title
+ dwStyle, // window style
+ X, // starting x position
+ Y, // starting y position
+ nWidth, // window width
+ nHeight, // window height
+ (HWND)NULL, // parent window handle
+ LoadMenu ( ghResInst, IDRM_MAINMENU ), // menu handle
+ ghInst, // instance (global)
+ (LPSTR)NULL // window creation parameter
+ );
+
+ break;
+
+ case WM_CLIENT: { // Create the client window.
+
+ CLIENTCREATESTRUCT ccs;
+
+ ccs.hWindowMenu = GetSubMenu ( GetMenu ( ghWndFrame ), WINDOWSMENUPOSITION );
+ ccs.idFirstChild = IDM_WINDOWSFIRSTCHILD;
+
+ dwStyle |= WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL;
+
+ hWnd = CreateWindow( WMCLASS_CLIENT, // class name
+ pszTitle, // window title
+ dwStyle, // window style
+ X, // starting x position
+ Y, // starting y position
+ nWidth, // window width
+ nHeight, // window height
+ ghWndFrame, // parent window handle
+ (HMENU)WM_CLIENT_ID, // menu handle
+ ghInst, // instance (global)
+ (LPSTR)&ccs // window creation parameter
+ );
+
+ break;
+
+ }
+
+ case WM_RIBBON: // Create a ribbon window window.
+
+// dwStyle |= WS_CHILD | WS_CLIPCHILDREN | SS_USERITEM;
+ dwStyle |= WS_CHILD | WS_CLIPCHILDREN;
+
+ hWnd = CreateWindow( WMCLASS_RIBBON, // class name
+ pszTitle, // window title
+ dwStyle, // window style
+ X, // starting x position
+ Y, // starting y position
+ nWidth, // window width
+ nHeight, // window height
+ EXTRACT_RIBBON_PARENT_HWND( pdsWinInfo ),
+ (HMENU)NULL, // menu handle
+ ghInst, // instance (global)
+ (LPSTR)NULL // window creation parameter
+ );
+
+ break;
+
+ case WM_DEBUG:
+ case WM_MDIPRIMARY: // Create a MDI document window.
+ case WM_MDISECONDARY: {
+
+ HWND hWndActive = WM_GetActiveDoc ();
+ MDICREATESTRUCT mcs;
+
+ msassert ( pdsWinInfo != (VOID_PTR)NULL );
+
+ // If the currently active MDI Doc is maximized, we need to
+ // follow suit and maximize this doc.
+
+ if ( hWndActive && WM_IsMaximized ( hWndActive ) ) {
+ dwStyle = WS_MAXIMIZE;
+ }
+
+ // Set the rest of the style.
+
+ dwStyle |= WS_CLIPSIBLINGS;
+
+ // Set the size indicator to the default.
+
+ WMDS_SetSize ( pdsWinInfo, WMSIZE_UNKNOWN );
+
+ // Determine the list box types.
+
+ switch ( wType & WM_STYLE_BITS ) {
+
+ case WM_VIEWWIN:
+ pdsWinInfo->dwWindowState = WMDOC_VIEWWIN;
+ break;
+
+ case WM_FLATLISTMC:
+ pdsWinInfo->dwWindowState = WMDOC_FLATMC;
+ break;
+
+ case WM_FLATLISTSC:
+ pdsWinInfo->dwWindowState = WMDOC_FLATSC;
+ break;
+
+ case WM_TREELISTSC:
+ pdsWinInfo->dwWindowState = WMDOC_TREESC;
+ break;
+
+ case WM_TREEANDFLATSC:
+ pdsWinInfo->dwWindowState = WMDOC_TREEANDFLAT | WMDOC_TREESC |
+ WMDOC_FLATSC | WMDOC_SLIDER;
+ break;
+
+ case WM_TREEANDFLATMC:
+ default:
+ pdsWinInfo->dwWindowState = WMDOC_TREEANDFLAT | WMDOC_TREESC |
+ WMDOC_FLATMC | WMDOC_SLIDER;
+ break;
+ }
+
+ // Clear out the menu state if not used.
+
+ if ( ! ( wType & WM_MENU_BITS ) ) {
+
+ pdsWinInfo->dwMenuState = 0L;
+ }
+
+ if ( ( wType & WM_TYPE_BITS ) == WM_MDIPRIMARY ) {
+ pdsWinInfo->wClosable = FALSE;
+ }
+ else {
+ pdsWinInfo->wClosable = TRUE;
+ }
+
+ if ( ! pdsWinInfo->nSliderPos ) {
+ pdsWinInfo->nSliderPos = WM_SLIDERUNKNOWN;
+ }
+
+ // Set up the NORMAL and MINIMIZED window titles.
+
+ if ( pszTitle ) {
+
+ pdsWinInfo->pTitle = ( CHAR_PTR )calloc ( sizeof ( CHAR ), strlen ( pszTitle ) + 1 );
+
+ if ( ! pdsWinInfo->pTitle ) {
+ return (HWND)NULL;
+ }
+
+ strcpy ( pdsWinInfo->pTitle, pszTitle );
+ }
+
+ if ( pszMinTitle ) {
+
+ pdsWinInfo->pMinTitle = ( CHAR_PTR )calloc ( sizeof ( CHAR ), strlen ( pszMinTitle ) + 1 );
+
+ if ( ! pdsWinInfo->pMinTitle ) {
+ return (HWND)NULL;
+ }
+
+ strcpy ( pdsWinInfo->pMinTitle, pszMinTitle );
+ }
+
+ // Use the appropriate window title.
+
+ if ( ( dwStyle & WS_ICONIC ) && pszMinTitle ) {
+ mcs.szTitle = pszMinTitle;
+ }
+ else {
+ mcs.szTitle = pszTitle;
+ }
+
+ mcs.szClass = WMCLASS_DOC;
+ mcs.hOwner = ghInst;
+ mcs.x = X;
+ mcs.y = Y;
+ mcs.cx = nWidth;
+ mcs.cy = nHeight;
+ mcs.style = WS_CHILD | dwStyle;
+ mcs.lParam = (LONG)pdsWinInfo;
+
+ hWnd = (HWND) SendMessage ( ghWndMDIClient,
+ WM_MDICREATE,
+ 0,
+ (MP2)&mcs
+ );
+
+ break;
+ }
+
+ case WM_DDECLIENT:
+
+ dwStyle |= WS_OVERLAPPEDWINDOW ;
+
+ hWnd = CreateWindow( WMCLASS_DDECLIENT, // class name
+ pszTitle, // window title
+ dwStyle, // window style
+ X, // starting x position
+ Y, // starting y position
+ nWidth, // window width
+ nHeight, // window height
+ (HWND)NULL, // parent window handle
+ (HMENU)NULL, // menu handle
+ ghInst, // instance (global)
+ (LPSTR)NULL // window creation parameter
+ );
+
+ break;
+
+ default: // THIS SHOULD NOT HAPPEN
+
+ msassert ( FALSE );
+
+ } /* end switch */
+
+
+ return hWnd;
+
+} /* end WM_Create() */
+
+
+/******************************************************************************
+
+ Name: WM_CreateObjects()
+
+ Description: This function creates the pens, brushes, and fonts, used
+ to display windows graphics.
+
+ Returns: SUCCESS, if successful. Otherwise, FAILURE.
+
+******************************************************************************/
+
+BOOL WM_CreateObjects ( VOID )
+
+{
+ CDS_PTR pCDS = CDS_GetPerm ();
+ CHAR szFontFace[MAX_FONTFACENAME_LEN + 1];
+ HDC hDC;
+ INT nFontHeight;
+ DWORD csfont ;
+
+ if (IS_JAPAN() ) {
+ CHARSETINFO csi;
+ DWORD dw = GetACP();
+
+ if (!TranslateCharsetInfo((DWORD*)dw, &csi, TCI_SRCCODEPAGE)){
+ csfont = csi.ciCharset = ANSI_CHARSET;
+ }
+ csfont = csi.ciCharset ;
+
+ } else {
+
+ csfont = ANSI_CHARSET ;
+ }
+
+ // Determine the font height.
+
+ hDC = GetDC ( (HWND)NULL );
+ nFontHeight = MulDiv ( -CDS_GetFontSize ( pCDS ), GetDeviceCaps ( hDC, LOGPIXELSY ), 72 );
+ ReleaseDC ( (HWND)NULL, hDC );
+
+
+ // Create a bunch of pens, brushes, and fonts for drawing.
+
+ gColorBackGnd = GetSysColor ( COLOR_WINDOW );
+ gColorForeGnd = GetSysColor ( COLOR_WINDOWTEXT );
+
+ gColorHighLight = GetSysColor ( COLOR_HIGHLIGHT );
+ gColorHighLightText = GetSysColor ( COLOR_HIGHLIGHTTEXT );
+
+ ghPenBlack = GetStockObject ( BLACK_PEN );
+ ghPenWhite = GetStockObject ( WHITE_PEN );
+ ghPenBackGnd = CreatePen ( PS_SOLID, 1, gColorBackGnd );
+ ghPenForeGnd = CreatePen ( PS_SOLID, 1, gColorForeGnd );
+ ghPenGray = CreatePen ( PS_SOLID, 1, GetSysColor ( COLOR_GRAYTEXT ) );
+ ghPenBtnText = CreatePen ( PS_SOLID, 1, GetSysColor ( COLOR_BTNTEXT ) );
+ ghPenLtGray = CreatePen ( PS_SOLID, 1, GetSysColor ( COLOR_BTNFACE ) );
+ ghPenDkGray = CreatePen ( PS_SOLID, 1, GetSysColor ( COLOR_BTNSHADOW ) );
+
+ ghBrushGray = GetStockObject ( GRAY_BRUSH );
+ ghBrushDkGray = GetStockObject ( DKGRAY_BRUSH );
+ ghBrushLtGray = CreateSolidBrush ( GetSysColor ( COLOR_BTNFACE ) );
+ ghBrushWhite = CreateSolidBrush ( gColorBackGnd );
+ ghBrushBlack = CreateSolidBrush ( gColorForeGnd );
+
+ ghBrushHighLight = CreateSolidBrush ( gColorHighLight );
+
+ if ( IS_JAPAN() ) {
+ RSM_StringCopy ( IDS_FONTSYSTEM, szFontFace, MAX_FONTFACENAME_LEN );
+ } else {
+ RSM_StringCopy ( IDS_FONTHELV, szFontFace, MAX_FONTFACENAME_LEN );
+ }
+
+ ghFontStatus = CreateFont( 16, // Height
+ 7, // Width
+ 0, // Escapement
+ 0, // Orientation
+ 400, // Weight
+ 0, // Italics?
+ 0, // Underline?
+ 0, // Strike out?
+ (IS_JAPAN()?csfont:ANSI_CHARSET ),
+ OUT_DEFAULT_PRECIS,
+ CLIP_DEFAULT_PRECIS,
+ DEFAULT_QUALITY,
+ DEFAULT_PITCH | FF_SWISS,
+ szFontFace
+ );
+
+ ghFontMsgBox = CreateFont( 13, // Height
+ 5, // Width
+ 0, // Escapement
+ 0, // Orientation
+ (IS_JAPAN()?400:FW_BOLD), //Weight
+ 0, // Italics?
+ 0, // Underline?
+ 0, // Strike out?
+ (IS_JAPAN()?csfont:ANSI_CHARSET ),
+ OUT_STRING_PRECIS, //
+ CLIP_STROKE_PRECIS,
+ DEFAULT_QUALITY,
+ VARIABLE_PITCH | FF_DONTCARE,
+ szFontFace
+ );
+
+ ghFontFiles = CreateFont ( nFontHeight,
+ 0, // Width
+ 0, // Escapement
+ 0, // Orientation
+ CDS_GetFontWeight ( pCDS ),
+ (BYTE)CDS_GetFontItalics ( pCDS ),
+ 0, // Underline?
+ 0, // Strike out?
+ (IS_JAPAN()?csfont:ANSI_CHARSET ),
+ OUT_STRING_PRECIS, //
+ CLIP_STROKE_PRECIS,
+ DEFAULT_QUALITY,
+ VARIABLE_PITCH | FF_SWISS,
+ CDS_GetFontFace ( pCDS )
+ );
+
+ ghFontIconLabels = ghFontFiles;
+
+ ghFontRibbon = CreateFont( 13, // Height
+ 5, // Width
+ 0, // Escapement
+ 0, // Orientation
+ (IS_JAPAN()?400:FW_BOLD),
+ 0, // Italics?
+ 0, // Underline?
+ 0, // Strike out?
+ (IS_JAPAN()?csfont:ANSI_CHARSET ),
+ OUT_STRING_PRECIS, //
+ CLIP_STROKE_PRECIS,
+ DEFAULT_QUALITY,
+ VARIABLE_PITCH | FF_DONTCARE,
+ szFontFace
+ );
+
+ if ( IS_JAPAN() ) {
+ RSM_StringCopy ( IDS_FONTSYSTEM, szFontFace, MAX_FONTFACENAME_LEN );
+ } else {
+ RSM_StringCopy ( IDS_FONTCOURIER, szFontFace, MAX_FONTFACENAME_LEN );
+ }
+
+ ghFontLog = CreateFont( 13, // Height
+ 8, // Width
+ 0, // Escapement
+ 0, // Orientation
+ 400, // Weight
+ 0, // Italics?
+ 0, // Underline?
+ 0, // Strike out?
+ (IS_JAPAN()?csfont:ANSI_CHARSET ),
+ OUT_STRING_PRECIS, //
+ CLIP_STROKE_PRECIS,
+ DEFAULT_QUALITY,
+ FIXED_PITCH | FF_MODERN,
+ szFontFace
+ );
+
+ // Initialize the bitmap resources.
+
+ RSM_BitmapInit ();
+
+ // Get the Windows border width so that it can be used in determining
+ // the MDI Document slider width.
+
+ gnBorderWidth = GetSystemMetrics ( SM_CXFRAME );
+
+ return SUCCESS;
+
+} /* end WM_CreateObjects() */
+
+
+/******************************************************************************
+
+ Name: WM_Deinit()
+
+ Description: This function deinitializes the GUI Window Manager by
+ unregistering window classes and deleting objects.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID WM_Deinit ( VOID )
+
+{
+ // Deinitialize the Help Manager.
+
+ HM_Deinit () ;
+
+ // Unregister the classes and delete the objects.
+
+ UnregisterClass ( WMCLASS_FRAME, ghInst );
+ UnregisterClass ( WMCLASS_DOC, ghInst );
+ UnregisterClass ( WMCLASS_RIBBON, ghInst );
+ UnregisterClass ( WMCLASS_DDECLIENT, ghInst );
+ UnregisterClass ( WMCLASS_VIEWWIN, ghInst );
+
+ WM_DeleteObjects ();
+
+} /* end WM_Deinit() */
+
+
+/******************************************************************************
+
+ Name: WM_DeleteObjects()
+
+ Description: This function deletes the pens, brushes, and fonts, used
+ to display windows graphics. It also deletes any bitmaps
+ in the bitmap table.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID WM_DeleteObjects ( VOID )
+
+{
+ // Delete only the NON-STOCK OBJECTS (pens, brushes, and fonts).
+
+ DeleteObject ( ghPenGray );
+ DeleteObject ( ghPenBackGnd );
+ DeleteObject ( ghPenForeGnd );
+ DeleteObject ( ghPenBtnText );
+ DeleteObject ( ghPenLtGray );
+ DeleteObject ( ghPenDkGray );
+
+ DeleteObject ( ghBrushLtGray );
+ DeleteObject ( ghBrushWhite );
+ DeleteObject ( ghBrushBlack );
+
+ DeleteObject ( ghFontStatus );
+ DeleteObject ( ghFontFiles );
+ DeleteObject ( ghFontRibbon );
+ DeleteObject ( ghFontMsgBox );
+ DeleteObject ( ghFontLog );
+
+ // Delete any bitmaps in the bitmap table.
+
+ RSM_BitmapFreeAll ();
+
+} /* end WM_DeleteObjects() */
+
+
+/******************************************************************************
+
+ Name: WM_GetNext()
+
+ Description: This function gets the next MDI document window handle.
+ If the current window handle is NULL, the call gets the
+ first MDI document window handle.
+
+ Returns: A handle to a MDI document window. It returns NULL or 0 if
+ there are no more MDI document windows.
+
+******************************************************************************/
+
+HWND WM_GetNext (
+
+register HWND hWndCurrent ) // I - the current window handle
+
+{
+ // If the current window handle is 0, get the first MDI doc.
+
+ if ( ! hWndCurrent ) {
+ hWndCurrent = GetWindow( ghWndMDIClient, GW_CHILD );
+ }
+ else {
+ hWndCurrent = GetWindow( hWndCurrent, GW_HWNDNEXT );
+ }
+
+ for ( ; hWndCurrent; hWndCurrent = GetWindow( hWndCurrent, GW_HWNDNEXT ) ) {
+
+ // Skip if the window is an icon title window.
+
+ if ( GetWindow( hWndCurrent, GW_OWNER ) ) {
+ continue;
+ }
+ else {
+ return hWndCurrent; // This is the next MDI child window.
+ }
+ }
+
+ return hWndCurrent; // The handle will be NULL by this point.
+
+
+} /* end WM_GetNext() */
+
+
+/******************************************************************************
+
+ Name: WM_Init()
+
+ Description: This function initializes the GUI Window Manager by
+ registering window classes, creating objects, and creating
+ the frame through which the MDI client is created.
+
+ Returns: SUCCESS, if successful. Otherwise, FAILURE.
+
+******************************************************************************/
+
+BOOL WM_Init (
+
+LPSTR lpCmdLine, // I - pointer to the command line
+INT nCmdShow ) // I - show parm from windows for describing how
+ // to show the frame window
+
+{
+ WNDCLASS wc;
+ CHAR szTitle[MAX_UI_RESOURCE_SIZE];
+ CDS_PTR pCDS = CDS_GetPerm ();
+ BOOL fOldShowStatus;
+
+ // Create Pens, Brushes, and Font objects.
+
+ if ( WM_CreateObjects () ) {
+
+ return FAILURE;
+ }
+
+ // Register the Frame class.
+
+ wc.style = 0;
+ wc.lpfnWndProc = WM_FrameWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = ghInst;
+ wc.hIcon = RSM_IconLoad ( IDRI_WNTRPARK );
+ wc.hCursor = RSM_CursorLoad ( ID(IDRC_ARROW) );
+ wc.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE + 1);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = WMCLASS_FRAME;
+
+ if ( ! RegisterClass( &wc ) ) {
+ return FAILURE;
+ }
+
+ // Register the MDI Doc class(es).
+
+ wc.style = CS_DBLCLKS;
+ wc.lpfnWndProc = WM_MDIDocWndProc;
+ wc.hIcon = (HICON)NULL;
+ wc.hCursor = (HCURSOR)NULL;
+ wc.hbrBackground = (HBRUSH) (COLOR_APPWORKSPACE + 1);
+ wc.lpszMenuName = NULL;
+ wc.cbWndExtra = sizeof(PDS_WMINFO);
+ wc.lpszClassName = WMCLASS_DOC;
+
+ if ( ! RegisterClass( &wc ) ) {
+ return FAILURE;
+ }
+
+ // Register the Ribbon class(es).
+
+# if !defined ( OEM_MSOFT )
+ {
+ wc.style = 0;
+ wc.lpfnWndProc = WM_RibbonWndProc;
+ wc.hIcon = (HICON)NULL;
+ wc.hCursor = RSM_CursorLoad ( IDRC_HAND );
+ wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
+ wc.lpszMenuName = NULL;
+ wc.cbWndExtra = sizeof(PDS_RIBINFO) + sizeof(WORD);
+ wc.lpszClassName = WMCLASS_RIBBON;
+ }
+# else
+ {
+ wc.style = 0;
+ wc.lpfnWndProc = WM_RibbonWndProc;
+ wc.hIcon = (HICON)NULL;
+ wc.hCursor = RSM_CursorLoad ( ID(IDRC_ARROW) );
+ wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
+ wc.lpszMenuName = NULL;
+ wc.cbWndExtra = sizeof(PDS_RIBINFO) + sizeof(WORD);
+ wc.lpszClassName = WMCLASS_RIBBON;
+ }
+# endif
+
+ if ( ! RegisterClass( &wc ) ) {
+ return FAILURE;
+ }
+
+ // Register the DDEclient class(es).
+
+ wc.style = 0;
+ wc.lpfnWndProc = WM_DDEClientWndProc;
+ wc.hIcon = (HICON)NULL;
+ wc.hCursor = (HCURSOR)NULL;
+ wc.hbrBackground = (HBRUSH)NULL;
+ wc.lpszMenuName = NULL;
+ wc.cbWndExtra = 0;
+ wc.lpszClassName = WMCLASS_DDECLIENT;
+
+ if ( ! RegisterClass( &wc ) ) {
+ return FAILURE;
+ }
+
+ // Register the Dumb Window class.
+
+ wc.style = 0;
+ wc.lpfnWndProc = WM_ViewWndProc;
+ wc.hIcon = (HICON)NULL;
+ wc.hCursor = RSM_CursorLoad ( ID(IDRC_ARROW) ) ;
+ wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
+ wc.lpszMenuName = NULL;
+ wc.cbWndExtra = sizeof(PVOID);
+ wc.lpszClassName = WMCLASS_VIEWWIN;
+
+ if ( ! RegisterClass( &wc ) ) {
+ return FAILURE;
+ }
+
+ // Load main menu accelerators.
+
+ if ( ! ( ghAccel = LoadAccelerators ( ghResInst, IDRA_ACCKEYS ) ) ) {
+ return FAILURE;
+ }
+
+ // Copy command line into our global variable.
+
+ if ( lpCmdLine ) {
+
+ glpCmdLine = (LPSTR)calloc( strlen( lpCmdLine ) + 1, sizeof ( CHAR ) );
+
+ if ( ! glpCmdLine ) {
+ return FAILURE;
+ }
+
+ strcpy ( glpCmdLine, lpCmdLine );
+
+ strupr ( glpCmdLine );
+
+ MUI_ProcessCommandLine ( glpCmdLine, &nCmdShow );
+
+ }
+ else {
+
+ glpCmdLine = (LPSTR)calloc( 1, sizeof ( CHAR ) );
+
+ if ( ! glpCmdLine ) {
+ return FAILURE;
+ }
+
+ glpCmdLine[0] = TEXT('\0');
+ }
+
+ // Get the frame window title and concatenate the command line INI
+ // file name if there was one found.
+
+ RSM_StringCopy( IDS_APPNAME, szTitle, MAX_UI_RESOURCE_LEN );
+
+ if ( CDS_UsingCmdLineINI () ) {
+
+ CHAR szTemp[MAX_UI_RESOURCE_SIZE];
+ LPSTR p;
+
+ CDS_GetIniFileName ( szTemp, sizeof ( szTemp ) );
+
+ p = strstr ( szTemp, TEXT(".INI") );
+
+ *p = (CHAR)NULL;
+
+ strcat ( szTitle, TEXT(" - ") );
+ strcat ( szTitle, szTemp );
+ }
+
+// strcat( szTitle, TEXT("-build 327.4") ) ;
+
+ // Create the frame.
+
+ ghWndFrame = WM_Create( (WORD)(WM_FRAME | CDS_GetFrameSize ( pCDS )),
+ szTitle,
+ (LPSTR)NULL,
+ (INT)CDS_GetFrameInfo ( pCDS ).x,
+ (INT)CDS_GetFrameInfo ( pCDS ).y,
+ (INT)CDS_GetFrameInfo ( pCDS ).cx,
+ (INT)CDS_GetFrameInfo ( pCDS ).cy,
+ (PDS_WMINFO)NULL );
+
+ if ( ( ! ghWndFrame ) || ( ! ghWndMDIClient ) ) {
+ return FAILURE;
+ }
+
+ // Show the WAIT cursor and capture all mouse messages to the frame
+ // window. Its complement is in frameproc.c after the app is initialized.
+
+ WM_ShowWaitCursor ( TRUE );
+
+ if ( ! gfDebug ) {
+
+ // If there is no debug option, remove the debug window settings from
+ // the settings menu.
+
+#if defined( CAYMAN )
+// Remove the Networks menu entry
+ DeleteMenu ( GetMenu( ghWndFrame ), IDM_SETTINGSNETWORK, MF_BYCOMMAND );
+#endif
+
+# if !defined ( OEM_MSOFT ) // unsupported feature
+ {
+ DeleteMenu ( GetMenu( ghWndFrame ), IDM_SETTINGSDEBUGWINDOW, MF_BYCOMMAND );
+ }
+# endif // !defined ( OEM_MSOFT ) // unsupported feature
+
+#if !defined ( OEM_MSOFT ) | defined( CAYMAN )
+ DrawMenuBar( ghWndFrame );
+#endif
+ }
+
+ // Create the MDI Client and MDI Document List Box sub-class Instances.
+
+ glpfnNewMDIClientProc = MakeProcInstance ( (WNDPROC)WM_MDIClientWndProc, ghInst );
+ glpfnNewListProc = MakeProcInstance ( (WNDPROC)WM_DocListWndProc, ghInst );
+
+ // Now, go ahead and SubClass the MDI Client.
+
+ WM_SubClassMDIClient ( ghWndMDIClient );
+
+ // We need the Jobs Pop-up Menu Handle so that we can attach Job Names
+ // to it. This must be done now, since windows MDI processing can
+ // add to or remove from the menu.
+
+ // Get the Jobs Menu handle for deleting and appending from/to this menu.
+
+ ghMenuJobs = GetSubMenu ( GetMenu ( ghWndFrame ), JOBSMENUPOSITION );
+
+ // Initialize the Display List Manager.
+
+ if ( DLM_Init ( ghWndFrame ) ) {
+ return FAILURE;
+ }
+
+ // Set status line to initializing
+
+ fOldShowStatus = gfShowStatusLine;
+ gfShowStatusLine = SUCCESS;
+ STM_SetIdleText ( IDS_INITIALIZING );
+ gfShowStatusLine = fOldShowStatus;
+
+ // Display the frame window as it is written in the INI file,
+ // unless the command line told us to show it minimized.
+
+ if ( nCmdShow == SW_SHOWNORMAL || nCmdShow == SW_SHOWMAXIMIZED ) {
+
+ if ( (WORD)CDS_GetFrameSize ( pCDS ) == WM_MAX ) {
+ nCmdShow = SW_SHOWMAXIMIZED;
+ }
+ else {
+ nCmdShow = SW_SHOWNORMAL;
+ }
+ }
+
+ ShowWindow ( ghWndFrame, nCmdShow );
+
+ // Update the client area.
+
+ WM_Update ( ghWndFrame );
+
+ // Initialize the GUI Help Manager.
+
+ HM_Init ();
+
+ return SUCCESS;
+
+} /* end WM_Init() */
+
+
+/******************************************************************************
+
+ Name: WM_QueryCloseAllDocs()
+
+ Description: This function asks if all secondary MDI document windows
+ can be closed.
+
+ Returns: TRUE, if all can be closed. Otherwise, FALSE.
+
+******************************************************************************/
+
+BOOL WM_QueryCloseAllDocs( VOID )
+{
+ HWND hWndTemp;
+
+ for ( hWndTemp = GetWindow ( ghWndMDIClient, GW_CHILD );
+ hWndTemp;
+ hWndTemp = GetWindow ( hWndTemp, GW_HWNDNEXT ) ) {
+
+ // Skip if an icon title window.
+
+ if ( GetWindow ( hWndTemp, GW_OWNER ) ) {
+ continue;
+ }
+
+ if ( ! SendMessage ( hWndTemp, WM_QUERYENDSESSION, 0, 0L ) ) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+
+} /* end WM_QueryCloseAllDocs() */
+
+
+/******************************************************************************
+
+ Name: WM_GetTitle()
+
+ Description: This function copies the long version of the MDI Doc title
+ from the WinInfo structure to the callers specified area.
+
+ Returns: The number of bytes copied.
+
+******************************************************************************/
+
+INT WM_GetTitle (
+
+HWND hWnd, // I - handle of a MDI document window
+LPSTR pDestTitle, // I - pointer to the destination title string.
+INT nDestLen ) // I - max # of characters to copy.
+
+
+{
+ PDS_WMINFO pdsWinInfo;
+ LPSTR pBuffer;
+
+ msassert ( hWnd != (HWND)NULL );
+
+ pdsWinInfo = WM_GetInfoPtr ( hWnd );
+
+ msassert ( pdsWinInfo != (VOID_PTR)NULL );
+
+ pBuffer = WMDS_GetWinTitle ( pdsWinInfo );
+
+ if ( pBuffer && nDestLen > 0 ) {
+ strncpy ( pDestTitle, pBuffer, nDestLen );
+ }
+
+ return strlen ( pBuffer );
+
+
+} /* end WM_GetTitle() */
+
+
+/******************************************************************************
+
+ Name: WM_SetMinTitle()
+
+ Description: This function sets the minimum title in the extra-bytes of a
+ MDI document window to the one specified, then changes the
+ caption title of the document window.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID WM_SetMinTitle (
+
+HWND hWnd, // I - handle of a MDI document window
+LPSTR pMinTitle ) // I - pointer to the minimum title to be copied to
+ // the window's extra-bytes.
+
+{
+ INT nLen;
+ PDS_WMINFO pdsWinInfo;
+ LPSTR pBuffer;
+
+ msassert ( hWnd != (HWND)NULL );
+
+ pdsWinInfo = WM_GetInfoPtr ( hWnd );
+
+ msassert ( pdsWinInfo != (VOID_PTR)NULL );
+
+ // Allocate space for the new title, then copy it.
+
+ nLen = strlen ( pMinTitle ) + 1;
+
+ pBuffer = ( LPSTR )calloc ( nLen, sizeof ( CHAR ) );
+
+ if ( ! pBuffer ) {
+ return;
+ }
+
+ strncpy ( pBuffer, pMinTitle, nLen );
+
+ // If there already is a title, trash it, then set it to the new one.
+
+ if ( pdsWinInfo->pMinTitle ) {
+ free ( pdsWinInfo->pMinTitle );
+ }
+
+ pdsWinInfo->pMinTitle = pBuffer;
+
+ SetWindowText ( hWnd, pBuffer );
+
+} /* end WM_SetMinTitle() */
+
+
+/******************************************************************************
+
+ Name: WM_SetTitle()
+
+ Description: This function sets the normal title in the extra-bytes of a
+ MDI document window to the one specified, then changes the
+ caption title of the document window.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID WM_SetTitle (
+
+HWND hWnd, // I - handle of a MDI document window
+LPSTR pTitle ) // I - pointer to the normal title to be copied to
+ // the window's extra-bytes.
+{
+ INT nLen;
+ PDS_WMINFO pdsWinInfo;
+ LPSTR pBuffer;
+ CHAR chTemp;
+
+ msassert ( hWnd != (HWND)NULL );
+
+ pdsWinInfo = WM_GetInfoPtr ( hWnd );
+
+ msassert ( pdsWinInfo != (VOID_PTR)NULL );
+
+ // Allocate space for the new title, then copy it.
+
+ nLen = strlen ( pTitle ) + 1;
+
+ pBuffer = ( LPSTR )calloc ( nLen, sizeof ( CHAR ) );
+
+ if ( ! pBuffer ) {
+ return;
+ }
+
+ strncpy ( pBuffer, pTitle, nLen );
+
+ // If there already is a title, trash it, then set it to the new one.
+
+ if ( pdsWinInfo->pTitle ) {
+ free ( pdsWinInfo->pTitle );
+ }
+
+ pdsWinInfo->pTitle = pBuffer;
+
+ // Guarantee that the title we send to Windows is less than or
+ // equal to the MAX_UI_WIN_TITLE_LEN, otherwise, Windows may blow up.
+
+ chTemp = 0;
+
+ if ( strlen ( pBuffer ) > MAX_UI_WIN_TITLE_LEN ) {
+ chTemp = pBuffer[ MAX_UI_WIN_TITLE_LEN ];
+ pBuffer[ MAX_UI_WIN_TITLE_LEN ] = 0;
+ }
+
+ SetWindowText ( hWnd, pBuffer );
+
+ if ( chTemp != 0 ) {
+ pBuffer[ MAX_UI_WIN_TITLE_LEN ] = chTemp;
+ }
+
+} /* end WM_SetTitle() */
+
+
+/******************************************************************************
+
+ Name: WM_SubClassListBox()
+
+ Description: This function is called by WM_DocCreate when a list box
+ must be created inside of a MDI document window.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID WM_SubClassListBox (
+
+register HWND hWnd ) // I - handle of the list box to sub-class
+
+{
+ // Grab the old procedure-instance for the MDI Document list boxes.
+ // (only if there wasn't one grabbed previously)
+
+ if ( ! glpfnOldListProc ) {
+
+ glpfnOldListProc = (WNDPROC) GetWindowLong ( hWnd, GWL_WNDPROC );
+ }
+
+ // Subclass the specified window.
+
+ SetWindowLong ( hWnd, GWL_WNDPROC, (DWORD)glpfnNewListProc );
+
+} /* end WM_SubClassListBox() */
+
+
+/******************************************************************************
+
+ Name: WM_SubClassMDIClient()
+
+ Description: This function is called after creating the Frame.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID WM_SubClassMDIClient (
+
+register HWND hWnd ) // I - handle of the MDI Client to sub-class
+
+{
+ // Grab the old procedure-instance for the MDI Client.
+ // (only if there wasn't one grabbed previously)
+
+ if ( ! glpfnOldMDIClientProc ) {
+
+ glpfnOldMDIClientProc = (WNDPROC) GetWindowLong ( hWnd, GWL_WNDPROC );
+ }
+
+ // Subclass the specified window.
+
+ if ( glpfnOldMDIClientProc ) {
+ SetWindowLong ( hWnd, GWL_WNDPROC, (DWORD)glpfnNewMDIClientProc );
+ }
+
+} /* end WM_SubClassMDIClient() */
+
+
+/******************************************************************************
+
+ Name: WM_ShowWaitCursor()
+
+ Description: This function captures the mouse and sets the cursor to
+ the common HOURGLASS, if the parameter passed is TRUE.
+ Otherwise, if currently waiting, and the parameter passed
+ is FALSE, the mouse is released from capture, and the
+ old cursor is restored.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID WM_ShowWaitCursor (
+
+BOOL fWait ) // I - flag indicating whether to wait or continue
+
+{
+ static UINT unWaitSem = 0; // counting semaphore
+ static HCURSOR hCursorFrame; // old frame window class cursor handle
+ static HCURSOR hCursorWindows; // old windows current cursor handle
+
+ // Check for the type of waiting.
+
+ switch ( fWait ) {
+
+ case SWC_SHOW:
+
+ unWaitSem++;
+
+ if ( ! mwfWaiting ) {
+
+ HCURSOR hCursorWait = RSM_CursorLoad ( ID(IDC_WAIT) );
+
+ // WAIT - iff told to wait and not already waiting.
+
+ hCursorWindows = SetCursor ( hCursorWait );
+ hCursorFrame = WM_SetClassCursor ( ghWndFrame, hCursorWait );
+ SetCapture ( ghWndFrame );
+ mwfWaiting = TRUE;
+ }
+
+ break;
+
+ case SWC_HIDE:
+
+ if ( unWaitSem ) {
+ unWaitSem--;
+ }
+
+ if ( mwfWaiting && ! unWaitSem ) {
+
+ // STOP WAIT - iff told to stop waiting and currently waiting.
+
+ WM_SetClassCursor ( ghWndFrame, hCursorFrame );
+ // SetCursor ( hCursorWindows );
+ SetCursor ( hCursorFrame );
+ ReleaseCapture ( );
+ mwfWaiting = FALSE;
+ }
+
+ break;
+
+ case SWC_PAUSE:
+
+ if ( mwfWaiting ) {
+
+ WM_SetClassCursor ( ghWndFrame, hCursorFrame );
+ SetCursor ( hCursorFrame );
+ ReleaseCapture ( );
+ mwfWaiting = FALSE;
+ }
+
+ break;
+
+ case SWC_RESUME:
+
+ if ( ! mwfWaiting && unWaitSem ) {
+
+ HCURSOR hCursorWait = RSM_CursorLoad ( ID(IDC_WAIT) );
+
+ // WAIT - iff told to wait and not already waiting.
+
+ hCursorWindows = SetCursor ( hCursorWait );
+ hCursorFrame = WM_SetClassCursor ( ghWndFrame, hCursorWait );
+ SetCapture ( ghWndFrame );
+ mwfWaiting = TRUE;
+ }
+
+ break;
+
+ } /* end switch() */
+
+} /* end WM_ShowWaitCursor() */
+
+
+/******************************************************************************
+
+ Name: WM_SetCursor ()
+
+ Description: Sets the cursor to the appropriate one. This function
+ should be smart enough to set the cursor to an hour glass,
+ the help cursor, and be able to detect when the cursor
+ moves outside of this applications windows and allow the
+ cursor to be changed by other apps, if the mode of this
+ app allows this.
+
+
+ Returns: TRUE, if no further processing should be done.
+ Otherwise, FALSE.
+
+******************************************************************************/
+
+BOOL WM_SetCursor (
+
+HWND hWnd )
+
+{
+ if ( mwfWaiting ) {
+
+ HWND hWndCapture = GetCapture ();
+
+ // If the app should be showing the wait cursor, make sure that we
+ // are still capturing while we are moving around here.
+
+ if ( ! hWndCapture ) {
+ SetCapture ( ghWndFrame );
+ }
+ else if ( hWndCapture == ghWndFrame ) {
+
+ POINT pt;
+
+ GetCursorPos ( &pt );
+
+ if ( ! IsChild ( ghWndFrame, WindowFromPoint ( pt ) ) ) {
+ ReleaseCapture();
+ }
+ }
+
+
+ SetCursor ( RSM_CursorLoad ( ID(IDC_WAIT) ) );
+ return TRUE;
+ }
+
+ return FALSE;
+
+} /* end WM_SetCursor() */
+
+
+/******************************************************************************
+
+ Name: WM_GetAppIcon()
+
+ Description: This function gets the icon that will be displayed when an
+ application is running.
+
+ Returns: The application icon.
+
+******************************************************************************/
+
+HICON WM_GetAppIcon ( VOID )
+
+{
+ return WM_GetClassIcon ( ghWndFrame );
+
+} /* end WM_GetAppIcon() */
+
+
+/******************************************************************************
+
+ Name: WM_SetAppIcon()
+
+ Description: This function sets the icon that will be displayed when an
+ application is running.
+
+ Returns: The old application icon.
+
+******************************************************************************/
+
+HICON WM_SetAppIcon (
+
+HICON hIcon ) // I - icon handle
+
+{
+# if !defined ( OEM_MSOFT ) // unsupported feature
+
+ HICON hOldIcon;
+
+ if ( IsIconic ( ghWndFrame ) ) {
+
+ RedrawWindow( ghWndFrame,
+ NULL,
+ NULL,
+ RDW_ERASE|RDW_FRAME|RDW_INTERNALPAINT|RDW_INVALIDATE|
+ RDW_ERASENOW);
+
+ }
+
+ hOldIcon = WM_SetClassIcon ( ghWndFrame, hIcon );
+
+ return hOldIcon;
+
+# else //if !defined ( OEM_MSOFT ) // unsupported feature
+
+ return WM_GetClassIcon ( ghWndFrame );
+
+# endif //!defined ( OEM_MSOFT ) // unsupported feature
+
+} /* end WM_SetAppIcon() */
+
+
+/******************************************************************************
+
+ Name: WM_AnimateAppIcon()
+
+ Description: This function animates the icon that will be displayed when
+ an application is running.
+
+ Returns: SUCCESS, if successful. Otherwise, FAILURE.
+
+******************************************************************************/
+
+BOOL WM_AnimateAppIcon (
+
+WORD wType, // I - type of animation sequence.
+BOOL fReset ) // I - flag to reset the animation sequence.
+
+{
+# if !defined ( OEM_MSOFT ) // unsupported feature
+
+ static WORD wLastAnimationType = 0;
+ static INT nLastSlideNumber = 0;
+
+ LPSTR lpIconID;
+
+ if ( IsIconic ( ghWndFrame ) ) {
+
+ if ( fReset || wType != wLastAnimationType ) {
+ nLastSlideNumber = 0;
+ }
+
+ wLastAnimationType = wType;
+
+ switch ( wType ) {
+
+ case IDM_OPERATIONSBACKUP:
+ case IDM_OPERATIONSTRANSFER:
+
+ switch ( nLastSlideNumber ) {
+
+ case 0:
+ lpIconID = IDRI_BKUP0;
+ break;
+
+ case 1:
+ lpIconID = IDRI_BKUP1;
+ break;
+
+ case 2:
+ lpIconID = IDRI_BKUP2;
+ break;
+
+ case 3:
+ lpIconID = IDRI_BKUP3;
+ break;
+
+ case 4:
+ lpIconID = IDRI_BKUP4;
+ break;
+
+ case 5:
+ lpIconID = IDRI_BKUP5;
+ break;
+
+ case 6:
+ lpIconID = IDRI_BKUP6;
+ break;
+
+ case 7:
+ lpIconID = IDRI_BKUP7;
+ break;
+
+ }
+
+ nLastSlideNumber = ++nLastSlideNumber % 8;
+ break;
+
+ case IDM_OPERATIONSRESTORE:
+
+ switch ( nLastSlideNumber ) {
+
+ case 0:
+ lpIconID = IDRI_BKUP0;
+ break;
+
+ case 1:
+ lpIconID = IDRI_BKUP7;
+ break;
+
+ case 2:
+ lpIconID = IDRI_BKUP6;
+ break;
+
+ case 3:
+ lpIconID = IDRI_BKUP5;
+ break;
+
+ case 4:
+ lpIconID = IDRI_BKUP4;
+ break;
+
+ case 5:
+ lpIconID = IDRI_BKUP3;
+ break;
+
+ case 6:
+ lpIconID = IDRI_BKUP2;
+ break;
+
+ case 7:
+ lpIconID = IDRI_BKUP1;
+ break;
+
+ }
+
+ nLastSlideNumber = ++nLastSlideNumber % 8;
+ break;
+
+
+ case IDM_OPERATIONSVERIFY:
+ case IDM_OPERATIONSCATALOG:
+
+ switch ( nLastSlideNumber ) {
+
+ case 0:
+ lpIconID = IDRI_SPIN0;
+ break;
+
+ case 1:
+ lpIconID = IDRI_SPIN1;
+ break;
+
+ case 2:
+ lpIconID = IDRI_SPIN2;
+ break;
+
+ case 3:
+ lpIconID = IDRI_SPIN3;
+ break;
+
+ }
+
+ nLastSlideNumber = ++nLastSlideNumber % 4;
+ break;
+
+ default:
+ return FAILURE;
+ }
+
+ WM_SetAppIcon ( RSM_IconLoad ( lpIconID ) );
+ return SUCCESS;
+ }
+ return FAILURE;
+
+# else // !defined ( OEM_MSOFT ) // unsupported feature
+
+ return SUCCESS;
+
+# endif // !defined ( OEM_MSOFT ) // unsupported feature
+
+} /* end WM_AnimateAppIcon() */
+
+
+/******************************************************************************
+
+ Name: WM_SetDocSizes()
+
+ Description: This function initializes the document sizes.
+
+ WMSIZE_NORMAL
+ WMSIZE_MIN
+ WMSIZE_MAX
+ WMSIZE_IGNORE *
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID WM_SetDocSizes ( VOID )
+
+{
+ HWND hWndThis = WM_GetNext( (HWND) NULL );
+ WININFO_PTR pdsWinInfo;
+
+ mwhWndLastTop = WM_GetActiveDoc ();
+
+ while ( hWndThis ) {
+
+ pdsWinInfo = WM_GetInfoPtr ( hWndThis );
+
+ WMDS_SetSize ( pdsWinInfo, WMSIZE_UNKNOWN );
+
+ hWndThis = WM_GetNext ( hWndThis );
+ }
+
+} /* end WM_SetDocSizes() */
+
+
+/******************************************************************************
+
+ Name: WM_MinimizeDocs()
+
+ Description: This function minimizes all primary docs, except the debug,
+ and destroys all secondary docs.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID WM_MinimizeDocs ( VOID )
+
+{
+ HWND hWndNext = WM_GetNext ( (HWND) NULL );
+ HWND hWndThis;
+ WININFO_PTR pdsWinInfo;
+ INT nSize;
+ CHAR szOldStatusLine[MAX_STATUS_LINE_SIZE];
+
+ // Save the old status line text.
+
+ strncpy ( szOldStatusLine, STM_GetStatusLineText (), MAX_STATUS_LINE_LEN );
+ szOldStatusLine [ MAX_STATUS_LINE_LEN ] = (CHAR)0;
+
+ while ( hWndNext ) {
+
+ hWndThis = hWndNext;
+ pdsWinInfo = WM_GetInfoPtr ( hWndThis );
+
+ // You have to grab the next one right away and hold on to it.
+
+ hWndNext = WM_GetNext ( hWndNext );
+
+ if ( WMDS_GetSize ( pdsWinInfo ) == WMSIZE_UNKNOWN ) {
+
+ if ( WM_IsMinimized ( hWndThis ) ) {
+ nSize = WMSIZE_MIN;
+ }
+ else if ( WM_IsMaximized ( hWndThis ) ) {
+ nSize = WMSIZE_MAX;
+ }
+ else {
+ nSize = WMSIZE_NORMAL;
+ }
+
+ // Minimize primary docs. Trash the secondary docs.
+
+ switch ( WMDS_GetWinType ( pdsWinInfo ) ) {
+
+#ifdef OEM_EMS
+ case WMTYPE_EXCHANGE:
+#endif //OEM_EMS
+ case WMTYPE_DISKS:
+ case WMTYPE_TAPES:
+ case WMTYPE_SERVERS:
+ case WMTYPE_LOGFILES:
+
+ WMDS_SetSize ( pdsWinInfo, nSize );
+ break;
+
+ case WMTYPE_DEBUG:
+
+ nSize = WMSIZE_IGNORE;
+ WMDS_SetSize ( pdsWinInfo, nSize );
+ break;
+
+ default:
+
+ nSize = WMSIZE_IGNORE;
+ WM_Destroy ( hWndThis );
+ break;
+
+ }
+
+ // Minimize if it is normal or maximized.
+
+ if ( nSize == WMSIZE_NORMAL || nSize == WMSIZE_MAX ) {
+ WM_MinimizeDoc ( hWndThis );
+ }
+ }
+ }
+
+ WM_MultiTask ();
+
+ // Restore the old status line text.
+
+ STM_SetStatusLineText ( szOldStatusLine );
+ STM_DrawText ( szOldStatusLine );
+
+ // Set the documents minimized flag.
+
+ mwfDocsMinimized = TRUE;
+
+} /* end WM_MinimizeDocs() */
+
+
+/******************************************************************************
+
+ Name: WM_RestoreDocs()
+
+ Description: This function Restores all primary docs, except the debug.
+
+ Last Change: Alter it to check to see if a tree type window is
+ already open. If so see to it it ends up on top of
+ pile of windows, rather than the bottom. This is
+ needed for slow cataloged sets. Otherwise the new
+ tree window ends up buried by the other windows.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID WM_RestoreDocs ( VOID )
+
+{
+ HWND hWndNext = WM_GetNext ( (HWND) NULL );
+ HWND hWndThis;
+ HWND hWndTop = (HWND) NULL;
+ WININFO_PTR pdsWinInfo;
+ INT nSize;
+ BOOL fActivateLastTop = FALSE;
+
+ // If the documents were never minimized, don't bother
+ // restoring them.
+
+ if ( ! mwfDocsMinimized ) {
+ return;
+ }
+
+ while ( hWndNext && ( hWndTop == (HWND)NULL ) ) {
+
+ pdsWinInfo = WM_GetInfoPtr ( hWndNext );
+
+ if ( pdsWinInfo->wClosable ) {
+ hWndTop = hWndNext;
+ }
+
+ hWndNext = WM_GetNext( hWndNext );
+ }
+
+ hWndNext = WM_GetNext ( (HWND) NULL );
+
+ while ( hWndNext ) {
+
+ hWndThis = hWndNext;
+ pdsWinInfo = WM_GetInfoPtr ( hWndThis );
+
+ // You have to grab the next one right away and hold on to it.
+
+ hWndNext = WM_GetNext ( hWndNext );
+
+ nSize = WMDS_GetSize ( pdsWinInfo );
+
+ if ( ( nSize == WMSIZE_NORMAL ) || ( nSize == WMSIZE_MAX ) ) {
+
+ // Set the flag to restore the doc if it was previously
+ // normal or maximized.
+
+ if ( mwhWndLastTop == hWndThis ) {
+ fActivateLastTop = TRUE;
+ }
+
+ if ( nSize == WMSIZE_NORMAL ) {
+ WM_RestoreDoc ( hWndThis );
+ WMDS_SetSize ( pdsWinInfo, WMSIZE_IGNORE );
+ }
+ else {
+ WM_MaximizeDoc ( hWndThis );
+ WMDS_SetSize ( pdsWinInfo, WMSIZE_IGNORE );
+ }
+ }
+ }
+
+ // Set the active window to the previous top window, if it still
+ // exists.
+
+ if ( hWndTop != (HWND)NULL ) {
+ WM_SetActiveDoc ( hWndTop );
+ }
+ else if ( fActivateLastTop ) {
+ WM_SetActiveDoc ( mwhWndLastTop );
+ }
+
+ mwfDocsMinimized = FALSE;
+
+} /* end WM_RestoreDocs() */
+
+
+/******************************************************************************
+
+ Name: WM_MoveWindow()
+
+ Description: This function moves a window. This function is a consistant
+ way of moving a window, apparently unlike WIN 3.0 vs WIN 3.1
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID WM_MoveWindow (
+
+HWND hWnd, // I - handle of a MDI document window
+INT x,
+INT y,
+INT nWidth,
+INT nHeight,
+BOOL fRepaint )
+
+{
+
+ WORD wFlags;
+
+ wFlags = ( fRepaint ) ? ( SWP_DRAWFRAME | SWP_NOZORDER ) : ( SWP_NOZORDER | SWP_NOREDRAW );
+
+ InvalidateRect ( hWnd, (LPRECT)NULL, fRepaint );
+
+ SetWindowPos ( hWnd, (HWND)NULL, x, y, nWidth, nHeight, wFlags );
+
+} /* end WM_MoveWindow() */
+
+
+/******************************************************************************
+
+ Name: WM_MakeAppActive()
+
+ Description: This makes our app the active app.
+
+ Returns: Nothing.
+
+******************************************************************************/
+
+VOID WM_MakeAppActive( VOID )
+
+{
+
+ // restore the app if minimized
+
+ if ( WM_IsMinimized ( ghWndFrame ) ) {
+
+ WM_Restore ( ghWndFrame );
+
+ } else {
+
+ HWND hWndTop = WM_GetActive ();
+
+ while ( hWndTop && hWndTop != ghWndFrame ) {
+ hWndTop = GetParent ( hWndTop );
+ }
+
+ // if our app is not active, make it active
+
+ if ( hWndTop != ghWndFrame ) {
+
+ WM_SetActive ( ghWndFrame );
+
+ if ( ghModelessDialog ) {
+
+ WM_SetActive ( ghModelessDialog );
+ }
+
+ }
+
+ }
+
+} /* end WM_MakeAppActive() */
+
diff --git a/private/utils/ntbackup/src/writescr.c b/private/utils/ntbackup/src/writescr.c
new file mode 100644
index 000000000..fb6781028
--- /dev/null
+++ b/private/utils/ntbackup/src/writescr.c
@@ -0,0 +1,298 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: writescr.c
+
+ Description: This file contains code to write a script to
+ a file
+
+ $Log: G:/UI/LOGFILES/WRITESCR.C_V $
+
+ Rev 1.12 11 Nov 1992 16:38:12 DAVEV
+UNICODE: remove compile warnings
+
+ Rev 1.11 05 Nov 1992 17:23:40 DAVEV
+fix ts
+
+ Rev 1.9 07 Oct 1992 14:19:18 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.8 07 Oct 1992 14:04:06 DAVEV
+various unicode chgs
+
+ Rev 1.7 04 Oct 1992 19:44:18 DAVEV
+Unicode Awk pass
+
+ Rev 1.6 28 Jul 1992 14:43:28 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.5 19 May 1992 13:01:18 MIKEP
+mips changes
+
+ Rev 1.4 18 May 1992 09:00:34 MIKEP
+header
+
+ Rev 1.3 15 May 1992 09:52:04 STEVEN
+40Format changes
+
+ Rev 1.2 04 Mar 1992 18:17:30 MIKEP
+fix attribute bug
+
+ Rev 1.1 11 Dec 1991 18:12:46 CHUCKB
+Removed unreferenced local variable.
+
+ Rev 1.0 20 Nov 1991 19:24:50 SYSTEM
+Initial revision.
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+static UINT16 WriteFlags( FILE *fptr, BE_CFG_PTR cfg );
+static VOID WriteDate( FILE *fptr, FSE_PTR fse );
+
+static VOID WriteScriptLine( FILE *, CHAR_PTR, ... );
+
+
+
+
+static BOOLEAN mw_write_err;
+
+/****************************************************************************
+
+ Name: WriteScriptFile
+
+ Description: This function writes the BSD information to
+ a script file .
+
+ Returns: SUCCESS or FAILURE
+
+*****************************************************************************/
+INT16 WriteScriptFile( BSD_HAND bsd_hand, CHAR_PTR fname )
+{
+ BOOLEAN file_opened = FALSE;
+ BSD_PTR cur_bsd;
+ INT16 ret_val = 0;
+ FILE *fptr;
+
+ mw_write_err = FALSE;
+
+ /* Now check to see if there is anything to save */
+
+ cur_bsd = BSD_GetFirst( bsd_hand );
+
+ while( cur_bsd != NULL ) {
+
+ if ( BSD_GetMarkStatus( cur_bsd ) != NONE_SELECTED ) {
+ if ( !file_opened ) {
+ fptr = UNI_fopen( fname, _O_TEXT );
+ if ( fptr == NULL ) {
+ ret_val = SCR_CANNOT_OPEN_SCRIPT;
+ break;
+ } else {
+
+ file_opened = TRUE;
+ WriteFlags( fptr, BSD_GetConfigData( cur_bsd ) );
+ }
+ }
+
+ SCR_ProcessBSD( fptr, cur_bsd );
+ }
+
+
+ cur_bsd = BSD_GetNext( cur_bsd );
+
+ }
+ if ( file_opened ) {
+ if ( fclose( fptr ) || ( mw_write_err ) ) {
+ ret_val = SCR_ERROR_WRITING_SCRIPT;
+ }
+ }
+
+ return ret_val;
+}
+
+INT16 SCR_ProcessBSD( FILE *fptr, BSD_PTR bsd )
+{
+ FSE_PTR cur_fse;
+ CHAR path[MAX_TOKEN_LEN + 1];
+ CHAR quoted_path[MAX_TOKEN_LEN + 1 + 2];
+ CHAR_PTR temp_path;
+ CHAR_PTR temp_fname;
+ CHAR_PTR qpath_ptr;
+ INT16 path_size;
+ UINT32 off_attrib;
+ UINT32 on_attrib;
+ INT16 status;
+
+ GENERIC_DLE_PTR dle;
+
+ dle = BSD_GetDLE( bsd );
+
+ cur_fse = BSD_GetFirstFSE( bsd );
+
+ while( cur_fse != NULL ) {
+ FSE_GetPath( cur_fse, &(INT8_PTR)temp_path, &path_size );
+ temp_fname = (CHAR_PTR)FSE_GetFname( cur_fse );
+
+ status = (INT16) FS_MakePath( path, (INT16)sizeof (path), dle,
+ temp_path, path_size, temp_fname );
+
+ if ( status != SUCCESS ) {
+ return( FAILURE );
+
+ } else {
+
+ /*
+ * Check path for spaces and plus signs: if neccessary,
+ * write a quoted path.
+ */
+ if ( ( strchr( path, TEXT(' ') ) != NULL ) ||
+ ( ( path[0] != TEXT('+') ) && ( strchr( path, TEXT('+') ) != NULL ) ) ) {
+
+ /* Let's not mess up a drive spec (these aren't quoted) */
+ if ( path[1] == TEXT(':') ) {
+ strncpy( quoted_path, path, 2 );
+ quoted_path[2] = TEXT('\0');
+ qpath_ptr = &path[2];
+ } else {
+ quoted_path[0] = TEXT('\0');
+ qpath_ptr = &path[0];
+ }
+
+ strcat( quoted_path, TEXT("\"") );
+ strcat( quoted_path, qpath_ptr );
+ strcat( quoted_path, TEXT("\"") );
+
+ WriteScriptLine( fptr, TEXT("%s"), quoted_path );
+
+ } else {
+
+ WriteScriptLine( fptr, TEXT("%s"), path );
+
+ }
+
+ if ( FSE_GetOperType( cur_fse ) == EXCLUDE ) {
+ WriteScriptLine( fptr, TEXT(" /XCLUDE") );
+ }
+
+ if ( FSE_GetIncSubFlag( cur_fse ) ) {
+ WriteScriptLine( fptr, TEXT(" /SUBDIR"));
+ }
+
+ FSE_GetAttribInfo( cur_fse, &on_attrib, &off_attrib );
+
+ if ( on_attrib & OBJ_MODIFIED_BIT ) {
+ WriteScriptLine( fptr, TEXT(" /MODIFIED") );
+ }
+
+ if ( off_attrib & OBJ_HIDDEN_BIT ) {
+ WriteScriptLine( fptr, TEXT(" /-HIDDEN") );
+ }
+
+ if ( ( off_attrib & OBJ_SYSTEM_BIT ) &&
+ ( off_attrib & OBJ_READONLY_BIT ) ) {
+ WriteScriptLine( fptr, TEXT(" /-SPECIAL") );
+ }
+
+ WriteDate( fptr, cur_fse );
+
+ WriteScriptLine( fptr, TEXT("\n") );
+ }
+
+ cur_fse = BSD_GetNextFSE( cur_fse );
+ }
+
+ return( SUCCESS );
+}
+
+
+/**/
+/**
+
+ write flags to file
+
+**/
+static UINT16 WriteFlags( FILE *fptr, BE_CFG_PTR cfg )
+{
+ /* if append flag is set, then write out Append parameter */
+ if ( CDS_GetAppendFlag( CDS_GetCopy() ) ) {
+ WriteScriptLine( fptr, TEXT(" /APPEND") );
+ }
+ if ( !BEC_GetSetArchiveFlag( cfg ) ) {
+ WriteScriptLine( fptr, TEXT(" /-ARCHIVE") );
+ }
+ if ( !BEC_GetHiddenFlag( cfg ) ) {
+ WriteScriptLine( fptr, TEXT(" /-HIDDEN") );
+ }
+ if ( !BEC_GetSpecialFlag( cfg ) ) {
+ WriteScriptLine( fptr, TEXT(" /-SPECIAL") );
+ }
+ WriteScriptLine( fptr, TEXT("\n") );
+ return TRUE;
+}
+
+/**/
+/**
+
+ This routine writes a date to the script file
+
+**/
+static VOID WriteDate( FILE *fptr, FSE_PTR fse )
+{
+ DATE_TIME_PTR before_date;
+ DATE_TIME_PTR after_date;
+ DATE_TIME_PTR access_date;
+ INT16 days_back;
+
+ FSE_GetModDate ( fse, &before_date, &after_date );
+ FSE_GetAccDate ( fse, &access_date );
+
+ if ( (before_date && before_date->date_valid) ||
+ (after_date && after_date->date_valid) ) {
+
+ WriteScriptLine( fptr, TEXT(" /DATE:") );
+
+ if ( after_date && after_date->date_valid ) {
+
+ WriteScriptLine( fptr, TEXT("%d/%02d/%4d"), after_date->month, after_date->day,
+ after_date->year );
+
+ }
+ if ( before_date && before_date->date_valid ) {
+
+ WriteScriptLine( fptr, TEXT(":%d/%02d/%4d"), before_date->month, before_date->day,
+ before_date->year );
+
+ }
+ }
+
+ if ( access_date && access_date->date_valid ) {
+ access_date->year -= 1900;
+ DU_CalcNumberDaysBackwd( access_date, &days_back );
+ access_date->year += 1900;
+ WriteScriptLine( fptr, TEXT(" /ADATE:%d"), days_back );
+ }
+}
+
+
+static VOID WriteScriptLine( FILE *fptr, CHAR_PTR fmt, ... )
+{
+ va_list arg_ptr;
+
+ va_start( arg_ptr, fmt );
+
+ if ( vfprintf( fptr, fmt, arg_ptr ) < 0 ) {
+ mw_write_err = TRUE;
+ }
+
+ va_end( arg_ptr );
+
+ return;
+}
+
+
diff --git a/private/utils/ntbackup/src/xattach.c b/private/utils/ntbackup/src/xattach.c
new file mode 100644
index 000000000..05e822410
--- /dev/null
+++ b/private/utils/ntbackup/src/xattach.c
@@ -0,0 +1,560 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: xattach.c
+
+ Description: This file contains code to attach and detattach to
+ a given EMS disk device. At Detach time, the server will be
+ 'kicked' if tye cfg specifies that it should. When the server
+ is 'kicked', we will violate layer boundaries and call the UI
+ directly. This is dirty but easy. The Exchange folks want
+ a "% complete" dialog for the kicking..
+
+
+ $Log: M:/LOGFILES/XATTACH.C_V $
+
+**/
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+
+#include "jet.h"
+#include "jetbcli.h"
+#include "edbmsg.h"
+
+#include "stdtypes.h"
+#include "ems_jet.h"
+#include "std_err.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "emsdblk.h"
+#include "ems_fs.h"
+#include "msassert.h"
+
+static INT16 EMS_StartOpenedService( SC_HANDLE serv_hand ) ;
+
+VOID XchgKickPct(
+ VOID_PTR pVoid,
+ GENERIC_DLE_PTR dle,
+ EC (* pfnPct)( PVOID, INT *, INT * ),
+ INT *status );
+
+INT EMS_RestorePercentComplete( PVOID a, INT *b, INT *c ) ;
+
+
+typedef struct KICK_PARMS {
+ FSYS_HAND fsh;
+ INT SetSize ;
+ INT SoFar ;
+ JET_RSTMAP jet_map[3] ;
+ EMS_FSYS_RESERVED_PTR res ;
+ VOID_PTR context ;
+ INT status ;
+} KICK_THREAD_PARMS, *KICK_THREAD_PARMS_PTR ;
+
+INT EMS_ThreadKickServer( KICK_THREAD_PARMS_PTR thread_parms_ptr ) ;
+
+
+
+/**/
+/**
+
+ Name: EMS_AttachToDLE()
+
+ Description: This function simply expands the OS specific
+ information in the DLE. At attach time we get all the
+ relevent paths that are saveed in the registry. These
+ paths are backed up as the first data stream. At restore
+ time these paths are used to determine how to match source
+ streams with destination paths.
+
+
+ Modified: 1/10/1992 10:45:57
+
+ Returns: Error Codes:
+ INSUFFICIENT_MEMORY
+ SUCCESS
+
+ Notes:
+
+ Declaration:
+
+**/
+INT16 EMS_AttachToDLE( fsh, dle, u_name, pswd )
+FSYS_HAND fsh ; /* I - File system handle */
+GENERIC_DLE_PTR dle; /*I/O- drive to attach to. list element expanded */
+CHAR_PTR u_name; /* I - user name NOT USED */
+CHAR_PTR pswd ; /* I - passowrd NOT USED */
+{
+ u_name ;
+ pswd ;
+ dle ;
+
+ msassert( dle != NULL );
+
+ /* Reserved field used for GetNext mode flag */
+ fsh->reserved.ptr = calloc( 1, sizeof( EMS_FSYS_RESERVED ) ) ;
+
+ BEC_SetSkipOpenFiles( fsh->cfg, BEC_SKIP_OPEN_FILES ) ;
+
+ if (BEC_GetModifiedOnlyFlag( fsh->cfg ) ) {
+ PVOID context ;
+ INT status ;
+ CHAR_PTR db_name ;
+
+ if ( dle->info.xserv->type == EMS_MDB ) {
+ db_name = TEXT("Exchange MDB Database") ;
+ } else{
+ db_name = TEXT("Exchange DS Database") ;
+ }
+
+ status = EMS_BackupPrepare( dle->parent->device_name,
+ db_name,
+ JET_bitBackupIncremental,
+ BACKUP_TYPE_LOGS_ONLY,
+ &context ) ;
+
+
+ if ( (status == hrInvalidParameter ) ||
+ (status == hrIncrementalBackupDisabled ) ||
+ (status == hrLogFileNotFound ) ) {
+ return FS_EMS_NO_LOG_BKUP ;
+ } else if ( status == hrCircularLogging ) {
+ return FS_EMS_CIRC_LOG;
+ } else if (!status) {
+ EMS_BackupEnd( context ) ;
+ }
+
+ }
+
+ if ( fsh->reserved.ptr != NULL ) {
+
+ if ( FS_SavePath( fsh, (BYTE_PTR)TEXT("\\"), 2 * sizeof( CHAR ) ) == SUCCESS ) {
+
+ fsh->file_hand = calloc( 1, sizeof( FILE_HAND_STRUCT ) + sizeof( EMS_OBJ_HAND ) ) ;
+ if ( fsh->file_hand != NULL ) {
+ fsh->file_hand->obj_hand.ptr = (VOID_PTR)(fsh->file_hand + 1) ;
+
+ return SUCCESS ;
+ }
+ }
+ }
+
+ return OUT_OF_MEMORY ;
+
+}
+
+/**/
+/**
+
+ Name: EMS_DetachDLE()
+
+ Description: This function detaches form the specified DLE.
+ Since MinDDB is not supported by this file system, we donn't have
+ to release PUSHED DDBs. Also we need to free any allocated path
+ buffers and open file scans.
+
+ At detach time on a restore, we will "kick" the attached server.
+ This is a 3+ hour process. During this time the server is fixing up
+ it's internal databse structures, and re-running the transaction
+ logs. We violate the layer boundary here so we can display a progress
+ dialog. This is the easist and cheepest way to do this...
+
+ Modified: 1/10/1992 11:16:11
+
+ Returns: SUCCESS
+
+**/
+INT16 EMS_DetachDLE( fsh )
+FSYS_HAND fsh ;
+{
+ DBLK_PTR dummy_dblk ;
+ EMS_FSYS_RESERVED_PTR res = fsh->reserved.ptr;
+
+ /* Release any pushed min DDBs */
+ // Push & Pop Min not implemented because Ntbackup suppot only.
+
+ /* Release any allocated path buffers */
+
+ FS_FreeOSPathOrNameQueueInHand( fsh ) ;
+
+
+ /* free the allocated file handle */
+ free( fsh->file_hand );
+
+ free( res->service_restart_list ) ;
+
+ free( fsh->reserved.ptr );
+
+ return SUCCESS ;
+}
+
+INT32 EMS_EndOperationOnDLE( FSYS_HAND fsh )
+{
+ EMS_FSYS_RESERVED_PTR res = fsh->reserved.ptr;
+ INT x;
+ CHAR_PTR db_name ;
+ INT status = 0;
+ KICK_THREAD_PARMS kick ;
+ HANDLE hThread ;
+ LPENUM_SERVICE_STATUS enum_list = res->service_restart_list ;
+ CHAR machine[256];
+ SC_HANDLE mach_hand ;
+ SC_HANDLE serv_hand ;
+ SERVICE_STATUS serv_status ;
+ INT i ;
+
+ kick.res = res ;
+ kick.context = NULL ;
+ kick.status = SUCCESS ;
+
+ if ( BEC_GetEmsRipKick( fsh->cfg ) ) {
+ CHAR_PTR sub_key_name ;
+
+ if ( fsh->attached_dle->info.xserv->type == EMS_MDB ) {
+ sub_key_name = REG_SUBKEY_MDB_RIP ;
+ } else {
+ sub_key_name = REG_SUBKEY_DSA_RIP ;
+ }
+
+ strcpy( machine, TEXT("\\\\") ) ;
+ strcat( machine, fsh->attached_dle->parent->device_name ) ;
+
+ mach_hand = OpenSCManager( machine, NULL, SC_MANAGER_ALL_ACCESS ) ;
+ if ( mach_hand == NULL ) {
+ status = FS_ACCESS_DENIED ;
+ return SUCCESS ;
+ }
+
+ if ( fsh->attached_dle->info.xserv->type == EMS_MDB ) {
+ serv_hand = OpenService( mach_hand, SERVICE_MESSAGE_DB,
+ SERVICE_START | SERVICE_QUERY_STATUS ) ;
+ } else {
+ serv_hand = OpenService( mach_hand, SERVICE_DIRECTORY,
+ SERVICE_START | SERVICE_QUERY_STATUS ) ;
+ }
+
+ if ( serv_hand == NULL ) {
+ CloseServiceHandle( mach_hand ) ;
+ status = FS_ACCESS_DENIED ;
+ return SUCCESS ;
+ }
+
+ if ( EMS_StartOpenedService( serv_hand ) != SUCCESS ) {
+ CloseServiceHandle( mach_hand ) ;
+ status = FS_ACCESS_DENIED ;
+ return SUCCESS ;
+ }
+
+ for (i = res->service_restart_list_size-1; i >=0; i-- ) {
+
+ serv_hand = OpenService( mach_hand, enum_list[i].lpServiceName,
+ SERVICE_START | SERVICE_QUERY_STATUS ) ;
+ if ( serv_hand == NULL ) {
+ status = FS_ACCESS_DENIED ;
+ return SUCCESS ;
+ }
+
+ if ( EMS_StartOpenedService( serv_hand ) != SUCCESS ) {
+ CloseServiceHandle( mach_hand ) ;
+
+ status = FS_ACCESS_DENIED ;
+ return SUCCESS ;
+ }
+
+ }
+ }
+
+ return kick.status ;
+
+}
+
+
+INT EMS_RestorePercentComplete( PVOID kick, INT *SetSize, INT *SoFar )
+{
+ static INT temp_size= 100;
+ static INT temp_sofar = 0;
+ KICK_THREAD_PARMS_PTR parms = kick;
+
+ if ( parms->context) {
+
+ if (temp_sofar > 100 ) {
+ temp_sofar = 0 ;
+ }
+
+ *SetSize= temp_size ;
+ *SoFar = temp_sofar ++ ;
+ } else {
+ *SetSize = parms->SetSize ;
+ *SoFar = parms->SoFar ;
+ }
+ return SUCCESS ;
+}
+
+INT16 EMS_StartOpenedService( SC_HANDLE serv_hand )
+{
+ SERVICE_STATUS serv_status ;
+ INT k ;
+
+
+ if ( !StartService( serv_hand, 0, NULL ) ) {
+ CloseServiceHandle( serv_hand ) ;
+ return FS_ACCESS_DENIED ;
+ }
+
+ for ( k = 0; k < 180; k++ ) {
+
+ if ( QueryServiceStatus( serv_hand, &serv_status ) &&
+ (serv_status.dwCurrentState != SERVICE_START_PENDING ) ) {
+
+ break ;
+ }
+ ThreadSwitch() ;
+ Sleep( 1000 ) ;
+ }
+
+ CloseServiceHandle( serv_hand ) ;
+
+ return SUCCESS ;
+
+}
+
+INT EMS_ThreadKickServer( KICK_THREAD_PARMS_PTR parms )
+{
+ INT stat ;
+ INT status = SUCCESS ;
+ FSYS_HAND fsh = parms->fsh ;
+ PVOID context = parms->context;
+ EMS_FSYS_RESERVED_PTR res = fsh->reserved.ptr;
+
+
+ // The backup log path is useless as maintained.
+ // In our case, the BackupLogPath and LogPath are the same
+ // go figure....
+
+// status = EMS_Restore(
+// parms->context,
+// parms->res->CheckpointFilePath,
+// parms->res->LogPath,
+// parms->jet_map,
+// parms->res->map_size,
+// parms->res->LogPath,
+// parms->res->low_log,
+// parms->res->high_log
+// );
+//
+//
+// parms->context = NULL ;
+ stat = EMS_RestoreEnd( context ) ;
+
+ parms->SetSize = 3 + res->service_restart_list_size *2;
+ parms->SoFar = 0 ;
+
+ /* lsts restart the services */
+ if ( !status ) {
+ LPENUM_SERVICE_STATUS enum_list = res->service_restart_list ;
+ CHAR machine[256];
+ SC_HANDLE mach_hand ;
+ SC_HANDLE serv_hand ;
+ SERVICE_STATUS serv_status ;
+ INT i ;
+
+ status = stat ;
+
+ strcpy( machine, TEXT("\\\\") ) ;
+ strcat( machine, fsh->attached_dle->parent->device_name ) ;
+
+ mach_hand = OpenSCManager( machine, NULL, SC_MANAGER_ALL_ACCESS ) ;
+ if ( mach_hand == NULL ) {
+ status = FS_ACCESS_DENIED ;
+ return SUCCESS ;
+ }
+
+ parms->SoFar++;
+
+ if ( fsh->attached_dle->info.xserv->type == EMS_MDB ) {
+ serv_hand = OpenService( mach_hand, SERVICE_MESSAGE_DB,
+ SERVICE_START | SERVICE_QUERY_STATUS ) ;
+ } else {
+ serv_hand = OpenService( mach_hand, SERVICE_DIRECTORY,
+ SERVICE_START | SERVICE_QUERY_STATUS ) ;
+ }
+
+ if ( serv_hand == NULL ) {
+ CloseServiceHandle( mach_hand ) ;
+ status = FS_ACCESS_DENIED ;
+ return SUCCESS ;
+ }
+
+ parms->SoFar++ ;
+
+ if ( EMS_StartOpenedService( serv_hand ) != SUCCESS ) {
+ CloseServiceHandle( mach_hand ) ;
+ status = FS_ACCESS_DENIED ;
+ return SUCCESS ;
+ }
+
+ parms->SoFar++ ;
+
+ for (i = res->service_restart_list_size-1; i >=0; i-- ) {
+
+ serv_hand = OpenService( mach_hand, enum_list[i].lpServiceName,
+ SERVICE_START | SERVICE_QUERY_STATUS ) ;
+ if ( serv_hand == NULL ) {
+ status = FS_ACCESS_DENIED ;
+ return SUCCESS ;
+ }
+
+ parms->SoFar++ ;
+ if ( EMS_StartOpenedService( serv_hand ) != SUCCESS ) {
+ CloseServiceHandle( mach_hand ) ;
+
+ status = FS_ACCESS_DENIED ;
+ return SUCCESS ;
+ }
+ parms->SoFar++ ;
+ }
+ }
+
+ parms->status = status ;
+
+ return 0 ;
+}
+
+
+
+/**/
+/**
+
+ Name: EMS_GetValFromReg()
+
+ Description: This is a really cool helper function that will return
+ the value for a given key and value name on a specific machine.
+ if any of the internal calls fail this function will return the
+ win32 error.
+
+**/
+
+INT EMS_GetValFromReg(
+CHAR_PTR machine,
+CHAR_PTR key_name,
+CHAR_PTR value_name,
+CHAR_PTR buffer,
+INT buf_size )
+{
+ HKEY key_machine;
+ HKEY requested_key;
+ INT status ;
+ CHAR machine_name[256] ;
+
+ // first lsts try to connect to the machine...
+
+ if ( machine ) {
+ strcpy( machine_name, TEXT("\\\\") );
+ strcat( machine_name, machine ) ;
+
+ status = RegConnectRegistry( machine_name,
+ HKEY_LOCAL_MACHINE,
+ &key_machine ) ;
+ } else {
+
+ status = RegConnectRegistry( machine,
+ HKEY_LOCAL_MACHINE,
+ &key_machine ) ;
+ }
+
+ if ( !status ) {
+ /* now lets open the specific Key.... */
+ status = RegOpenKeyEx( key_machine,
+ key_name,
+ 0,
+ KEY_QUERY_VALUE,
+ &requested_key );
+
+ if ( !status ) {
+ // finally lets try to read the value
+
+ status = RegQueryValueEx( requested_key,
+ value_name,
+ NULL,
+ NULL,
+ (LPBYTE)buffer,
+ &buf_size );
+
+ RegCloseKey( requested_key ) ;
+ }
+
+ RegCloseKey( key_machine ) ;
+ }
+
+ return status ;
+}
+
+/**/
+/**
+
+ Name: EMS_SetValFromReg()
+
+ Description: This is a really cool helper function that will set
+ the value for a given key and value name on a specific machine.
+ if any of the internal calls fail this function will return the
+ win32 error.
+
+**/
+
+INT EMS_SetValFromReg(
+CHAR_PTR machine,
+CHAR_PTR key_name,
+CHAR_PTR value_name,
+CHAR_PTR buffer)
+{
+ HKEY key_machine;
+ HKEY requested_key;
+ INT status ;
+ CHAR machine_name[256] ;
+
+ // First lets try to connect to the machine.
+ if ( machine ) {
+ strcpy( machine_name, TEXT("\\\\") );
+ strcat( machine_name, machine ) ;
+
+ status = RegConnectRegistry( machine_name,
+ HKEY_LOCAL_MACHINE,
+ &key_machine ) ;
+ } else {
+
+ status = RegConnectRegistry( machine,
+ HKEY_LOCAL_MACHINE,
+ &key_machine ) ;
+ }
+
+ if ( !status ) {
+ /* now lets open the specific key.... */
+ status = RegOpenKeyEx( key_machine,
+ key_name,
+ 0,
+ KEY_QUERY_VALUE,
+ &requested_key );
+
+ if ( !status ) {
+ // finaly lets set the value
+ status = RegSetValueEx( requested_key,
+ value_name,
+ 0,
+ REG_SZ,
+ (LPBYTE)buffer,
+ strsize(buffer) );
+
+ RegCloseKey( requested_key ) ;
+ }
+
+ RegCloseKey( key_machine ) ;
+ }
+
+ return status ;
+}
+
+
+
diff --git a/private/utils/ntbackup/src/xchgdir.c b/private/utils/ntbackup/src/xchgdir.c
new file mode 100644
index 000000000..2e3d71e38
--- /dev/null
+++ b/private/utils/ntbackup/src/xchgdir.c
@@ -0,0 +1,106 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: xchgdir.c
+
+ Description: Since EMS is a single object, we don't have a need to
+ change directories or any of that goo. The Object we backup is
+ a DDB. This ddb has a name that is not the root. This can be
+ rather flakey to the UI, but once again it is cheep and simple
+
+ $Log: M:/LOGFILES/XCHGDIR.C_V $
+
+
+**/
+/* begin include list */
+#include <windows.h>
+#include <malloc.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "emsdblk.h"
+#include "ems_fs.h"
+#include "msassert.h"
+/* $end$ include list */
+/**/
+/**
+
+ Name: EMS_ChangeDir()
+
+ Description: This function changes directories into the directory
+ pointed to by path.
+
+ Modified: 1/10/1992 12:45:35
+
+ Returns: Error codes:
+ SUCCESS
+ OUT_OF_MEMORY
+
+ Notes:
+
+**/
+INT16 EMS_ChangeDir(
+FSYS_HAND fsh, /* I - file system to changing directories on */
+CHAR_PTR path, /* I - describes the path of the new directory */
+INT16 psize ) /* I - specifies the length of the path */
+{
+ (void)fsh;
+ (void)path;
+ (void)psize;
+ return( SUCCESS ) ;
+}
+/**/
+/**
+
+ Name: EMS_UpDir()
+
+ Description: This function removes the last directory name from the
+ current directory path field of the "fsh"
+
+
+ Modified: 1/10/1992 12:47:23
+
+ Returns: Error codes:
+ FS_AT_ROOT
+ SUCCESS
+
+ Notes:
+
+**/
+INT16 EMS_UpDir( fsh )
+FSYS_HAND fsh ; /* I - file system to change directories in */
+{
+ (void)fsh ;
+ return( SUCCESS ) ;
+}
+
+/**/
+/**
+
+ Name: EMS_ChangeIntoDDB()
+
+ Description: This function changes into the directory specified in the
+ DBLK
+
+ Modified: 1/10/1992 12:48:54
+
+ Returns: OUT_OF_MEMORY
+ SUCCESS
+
+ Notes:
+
+**/
+INT16 EMS_ChangeIntoDDB( fsh, dblk )
+FSYS_HAND fsh ; /* I - File system handle */
+DBLK_PTR dblk ; /* I - contains directory path to change into */
+{
+ (void)fsh;
+ (void)dblk;
+
+
+ return SUCCESS ;
+}
diff --git a/private/utils/ntbackup/src/xclose.c b/private/utils/ntbackup/src/xclose.c
new file mode 100644
index 000000000..460f9078e
--- /dev/null
+++ b/private/utils/ntbackup/src/xclose.c
@@ -0,0 +1,153 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: xclose.c
+
+ Description: This file closes an opened object.
+
+
+ $Log: N:\logfiles\xclose.c_v $
+
+
+**/
+#include <stdio.h>
+#include <windows.h>
+#include <string.h>
+#include <malloc.h>
+
+
+#include "jet.h"
+#include "jetbcli.h"
+#include "ems_jet.h"
+#include "edbmsg.h"
+
+#include "stdtypes.h"
+#include "stdio.h"
+#include "std_err.h"
+#include "beconfig.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "fsys_err.h"
+#include "emsdblk.h"
+#include "ems_fs.h"
+
+
+/**/
+
+/**
+
+ Name: EMS_CloseObj()
+
+ Description: This funciton closes an object. If the object was opened
+ for an incremental or full backup we need to truncate the transaction
+ logs.
+
+ Modified: 2/7/1992 10:55:12
+
+ Returns: Error Codes:
+ FS_OBJECT_NOT_OPENED
+ SUCCESS
+
+ Notes:
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 EMS_CloseObj( hand )
+FILE_HAND hand ; /* I - handle of object to close */
+{
+ INT16 ret_val = SUCCESS;
+ FSYS_HAND fsh = hand->fsh ;
+ EMS_OBJ_HAND_PTR ems_hand = (EMS_OBJ_HAND_PTR)(hand->obj_hand.ptr ) ;
+ EMS_DBLK_PTR ddblk = (EMS_DBLK_PTR)hand->dblk ;
+
+ switch (hand->fsh->attached_dle->info.xserv->type) {
+
+ case EMS_MDB:
+ case EMS_DSA:
+
+ if ( hand->mode == FS_READ) {
+ if ( BEC_GetSetArchiveFlag( hand->fsh->cfg ) &&
+ ddblk->backup_completed ) {
+
+ EMS_TruncateLogs( ems_hand->context ) ;
+ }
+
+ if ( ems_hand->context ) {
+ EMS_BackupEnd( ems_hand->context ) ;
+ }
+
+ } else if ( hand->mode == FS_WRITE ) {
+
+ EMS_FSYS_RESERVED_PTR res = fsh->reserved.ptr;
+
+ if ( res->restore_context &&
+ ddblk->backup_completed ) {
+
+
+ if ( res->map_size != 0 ) {
+ EDB_RSTMAP rest_map[3] ;
+ int i ;
+ CHAR_PTR path;
+
+ path = res->jet_rstmap ;
+
+ for (i = 0; i < res->map_size; i ++ ) {
+ rest_map[i].wszDatabaseName = path ;
+
+ path += strlen(path) +1 ;
+ rest_map[i].wszNewDatabaseName = path ;
+
+ path += strlen(path) +1 ;
+ }
+
+ if (EMS_RestoreRegister( res->restore_context,
+ res->CheckpointFilePath,
+ res->LogPath,
+ rest_map,
+ res->map_size,
+ res->LogPath,
+ res->low_log,
+ res->high_log ) ) {
+ ret_val = FS_COMM_FAILURE ;
+ }
+ } else {
+ if (EMS_RestoreRegister( res->restore_context,
+ NULL,
+ NULL,
+ NULL,
+ 0,
+ res->LogPath,
+ res->low_log,
+ res->high_log ) ) {
+ ret_val = FS_COMM_FAILURE ;
+ }
+ }
+
+ EMS_RestoreComplete( res->restore_context, hrNone ) ;
+
+ }
+
+ if ( res->restore_context ) {
+
+ EMS_RestoreEnd( res->restore_context ) ;
+ }
+
+ CloseHandle( ems_hand->fhand ) ;
+
+ }
+
+ break ;
+
+ case EMS_BRICK:
+ default:
+ ret_val = FS_OBJECT_NOT_OPENED;
+ }
+
+
+ return ret_val ;
+}
+
+
diff --git a/private/utils/ntbackup/src/xcreate.c b/private/utils/ntbackup/src/xcreate.c
new file mode 100644
index 000000000..630282d19
--- /dev/null
+++ b/private/utils/ntbackup/src/xcreate.c
@@ -0,0 +1,310 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: xcreate.c
+
+ Description: Since Exchange does have files or directories and since the data
+ necessary to actually do anyting is in the first stream, all we can do here
+ is try to stop the service that is running at the server.
+
+
+ $Log: N:\logfiles\xcreate.c_v $
+
+**/
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+#include <malloc.h>
+#include <lm.h>
+
+#include <wtypes.h>
+
+#include "jet.h"
+#include "jetbcli.h"
+#include "ems_jet.h"
+#include "edbmsg.h"
+
+#include "stdtypes.h"
+#include "omevent.h"
+#include "std_err.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "fsys_err.h"
+#include "emsdblk.h"
+#include "ems_fs.h"
+#include "dle_str.h"
+#include "msassert.h"
+
+static INT16 EMS_ServiceShutdown( FSYS_HAND fsh, SC_HANDLE mach_hand, CHAR_PTR service_name ) ;
+
+/**/
+/**
+
+ Name: EMS_CreateObj()
+
+ Description: This function will simply stop the IS or DS service. If the System
+ Attendant is not running then the restore can not be performed and we will
+ return an approprate error.
+
+
+ Modified: 2/10/1992 15:49:17
+
+ Returns: Error Codes:
+ OUT_OF_MEMORY
+ FS_ACCESS_DENIED
+ FS_OUT_OF_SPACE
+ FS_BAD_DBLK
+ SUCCESS
+
+ Notes: This function will return FS_BAD_DBLK if an IDB is
+ passed in as the object.
+
+**/
+INT16 EMS_CreateObj( fsh, dblk )
+FSYS_HAND fsh ; /* I - File system to create object on */
+DBLK_PTR dblk ; /* I - Describes object to create */
+{
+ GENERIC_DLE_PTR dle = fsh->attached_dle;
+ INT16 ret_val = SUCCESS ;
+ EMS_DBLK_PTR ddblk = (EMS_DBLK_PTR)dblk;
+ EMS_FSYS_RESERVED_PTR resPtr = fsh->reserved.ptr;
+ BYTE_PTR dummy = NULL;
+ CHAR machine[256];
+ SC_HANDLE mach_hand ;
+ SC_HANDLE serv_hand ;
+ SERVICE_STATUS serv_status ;
+ INT i ;
+ INT status;
+ CHAR_PTR db_name;
+
+ msassert( dblk != NULL );
+ msassert( dle != NULL ) ;
+
+ resPtr->restore_context = NULL ;
+
+ if ( resPtr->attach_failed ) {
+ return FS_COMM_FAILURE ;
+ }
+
+ if ( dle->info.xserv->type == EMS_MDB ) {
+ db_name = TEXT("Exchange MDB Database") ;
+ } else{
+ db_name = TEXT("Exchange DS Database") ;
+ }
+
+ status = EMS_RestorePrepare( dle->parent->device_name,
+ db_name,
+ &resPtr->restore_context ) ;
+ if ( status ) {
+ return FS_COMM_FAILURE ;
+ }
+
+ strcpy( machine, TEXT("\\\\") ) ;
+ strcat( machine, dle->parent->device_name ) ;
+
+ // Make sure MAD (The system attendant) is running
+
+ mach_hand = OpenSCManager( machine, NULL, SC_MANAGER_ALL_ACCESS ) ;
+ if ( mach_hand == NULL ) {
+ if ( GetLastError() == ERROR_ACCESS_DENIED ) {
+ return FS_ACCESS_DENIED ;
+ } else {
+ return FS_COMM_FAILURE ;
+ }
+ }
+
+ serv_hand = OpenService( mach_hand, SERVICE_MAD, SERVICE_QUERY_STATUS ) ;
+ if ( serv_hand == NULL ) {
+ CloseServiceHandle( mach_hand ) ;
+ if ( GetLastError() == ERROR_ACCESS_DENIED ) {
+ return FS_ACCESS_DENIED ;
+ } else {
+ return FS_COMM_FAILURE ;
+ }
+ }
+
+ if ( !QueryServiceStatus( serv_hand, &serv_status ) ||
+ (serv_status.dwCurrentState!=SERVICE_RUNNING ) ) {
+
+ CloseServiceHandle( serv_hand ) ;
+ CloseServiceHandle( mach_hand ) ;
+ if ( GetLastError() == ERROR_ACCESS_DENIED ) {
+ return FS_ACCESS_DENIED ;
+ } else {
+ return FS_COMM_FAILURE ;
+ }
+ }
+
+ CloseServiceHandle( serv_hand ) ;
+
+ switch( dle->info.xserv->type ){
+
+ case EMS_MDB :
+
+ ret_val = EMS_ServiceShutdown( fsh, mach_hand, SERVICE_MESSAGE_DB ) ;
+ break ;
+
+ case EMS_DSA :
+ ret_val = EMS_ServiceShutdown( fsh, mach_hand, SERVICE_DIRECTORY ) ;
+
+ break ;
+
+ default :
+ ret_val = FS_INCOMPATIBLE_OBJECT ;
+ }
+
+
+ return ret_val;
+}
+
+INT16 EMS_ServiceShutdown( FSYS_HAND fsh, SC_HANDLE mach_hand, CHAR_PTR service_name )
+{
+ EMS_FSYS_RESERVED_PTR res = fsh->reserved.ptr;
+ INT16 ret_val = SUCCESS ;
+ SC_HANDLE dep_serv_hand ;
+ SC_HANDLE serv_hand ;
+ BYTE_PTR buffer;
+ LPENUM_SERVICE_STATUS enum_list;
+ SERVICE_STATUS serv_status ;
+ INT size_needed ;
+ INT num_services ;
+ INT i ,k ;
+ INT status;
+
+ buffer = malloc( 4096 ) ;
+ if ( buffer == NULL ) {
+ return OUT_OF_MEMORY ;
+ }
+
+ serv_hand = OpenService( mach_hand, service_name,
+ SERVICE_STOP | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS ) ;
+ if ( serv_hand == NULL ) {
+
+ OMEVENT_LogEMSError ( TEXT("OpenService()"), GetLastError(), service_name ) ;
+
+ if ( GetLastError() == ERROR_ACCESS_DENIED ) {
+ return FS_ACCESS_DENIED ;
+ } else {
+ return FS_COMM_FAILURE ;
+ }
+ }
+
+ enum_list = (LPENUM_SERVICE_STATUS)buffer ;
+
+ if (EnumDependentServices( serv_hand,
+ SERVICE_ACTIVE,
+ enum_list,
+ 4096,
+ &size_needed,
+ &num_services ) ) {
+
+ res->service_restart_list = buffer;
+ res->service_restart_list_size = num_services;
+
+ /* first close all dependant services */
+ for ( i = 0 ; i < num_services; i ++ ) {
+
+ dep_serv_hand = OpenService( mach_hand, enum_list[i].lpServiceName,
+ SERVICE_STOP | SERVICE_QUERY_STATUS ) ;
+
+ if ( dep_serv_hand == NULL ) {
+ OMEVENT_LogEMSError ( TEXT("OpenService()"),
+ GetLastError(),
+ enum_list[i].lpServiceName ) ;
+ CloseServiceHandle( serv_hand ) ;
+
+ if ( GetLastError() == ERROR_ACCESS_DENIED ) {
+ return FS_ACCESS_DENIED ;
+ } else {
+ return FS_COMM_FAILURE ;
+ }
+ }
+
+
+ if ( !ControlService( dep_serv_hand, SERVICE_CONTROL_STOP, &serv_status ) ||
+ ((serv_status.dwCurrentState != SERVICE_STOPPED) &&
+ (serv_status.dwCurrentState != SERVICE_STOP_PENDING ) ) ) {
+
+
+ status = GetLastError() ;
+ if ( status != ERROR_SERVICE_NOT_ACTIVE ) {
+ OMEVENT_LogEMSError ( TEXT("ControlService(STOP)"),
+ status,
+ enum_list[i].lpServiceName ) ;
+
+ CloseServiceHandle( dep_serv_hand ) ;
+ CloseServiceHandle( serv_hand ) ;
+ if ( GetLastError() == ERROR_ACCESS_DENIED ) {
+ return FS_ACCESS_DENIED ;
+ } else {
+ return FS_COMM_FAILURE ;
+ }
+ }
+ }
+
+ for ( k = 0; k < 240; k++ ) {
+
+ if ( QueryServiceStatus( dep_serv_hand, &serv_status ) &&
+ (serv_status.dwCurrentState != SERVICE_STOP_PENDING ) ) {
+ break ;
+ }
+ ThreadSwitch() ;
+ Sleep( 1000 ) ;
+ }
+
+ CloseServiceHandle( dep_serv_hand ) ;
+ }
+
+ if ( !ControlService( serv_hand, SERVICE_CONTROL_STOP, &serv_status ) ||
+ ((serv_status.dwCurrentState != SERVICE_STOPPED) &&
+ (serv_status.dwCurrentState != SERVICE_STOP_PENDING ) ) ) {
+
+ status = GetLastError() ;
+ if ( ( status != ERROR_SERVICE_NOT_ACTIVE ) &&
+ (status != ERROR_SERVICE_REQUEST_TIMEOUT ) ) {
+ OMEVENT_LogEMSError ( TEXT("ControlService(STOP)"),
+ status,
+ service_name ) ;
+
+ CloseServiceHandle( serv_hand ) ;
+ return FS_COMM_FAILURE ;
+ }
+ }
+
+ for ( k = 0; k < 240; k++ ) {
+
+ if ( QueryServiceStatus( serv_hand, &serv_status ) &&
+ (serv_status.dwCurrentState != SERVICE_STOP_PENDING ) ) {
+ break ;
+ }
+ ThreadSwitch() ;
+ Sleep( 1000 ) ;
+ }
+
+ CloseServiceHandle( serv_hand ) ;
+
+ if (serv_status.dwCurrentState == SERVICE_STOP_PENDING ) {
+ OMEVENT_LogEMSError ( TEXT("ControlService(STOP)"),
+ ERROR_SERVICE_REQUEST_TIMEOUT,
+ service_name ) ;
+ return FS_COMM_FAILURE ;
+ }
+
+
+ } else {
+ OMEVENT_LogEMSError ( TEXT("EnumDependentServices()"),
+ GetLastError(),
+ service_name ) ;
+
+ if ( GetLastError() == ERROR_ACCESS_DENIED ) {
+ return FS_ACCESS_DENIED ;
+ } else {
+ return FS_COMM_FAILURE ;
+ }
+ }
+
+ return SUCCESS ;
+}
+
+
diff --git a/private/utils/ntbackup/src/xgetinfo.c b/private/utils/ntbackup/src/xgetinfo.c
new file mode 100644
index 000000000..d5ebc06c0
--- /dev/null
+++ b/private/utils/ntbackup/src/xgetinfo.c
@@ -0,0 +1,51 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: xgetinfo.c
+
+ Description: This file contains code to completely fills out a
+ minimalized DBLK.
+
+
+ $Log: M:/LOGFILES/XGETINFO.C_V $
+
+**/
+#include <windows.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "stdmacro.h"
+
+#include "fsys.h"
+#include "fsys_err.h"
+#include "emsdblk.h"
+#include "ems_fs.h"
+#include "msassert.h"
+
+/**/
+/**
+
+ Name: EMS_GetObjInfo()
+
+ Description: This is a simple return. There is no exta info to get....
+
+ Modified: 7/26/1989
+
+ Returns: Error Codes:
+ SUCCESS
+
+ Notes: For FDBs this funciton will check the current
+ directory for the specified file.
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 EMS_GetObjInfo( fsh, dblk )
+FSYS_HAND fsh ; /* I - File system handle */
+DBLK_PTR dblk ; /*I/O- On entry it is minimal on exit Complete */
+{
+ return( SUCCESS ) ;
+}
diff --git a/private/utils/ntbackup/src/xgetnext.c b/private/utils/ntbackup/src/xgetnext.c
new file mode 100644
index 000000000..c732c5978
--- /dev/null
+++ b/private/utils/ntbackup/src/xgetnext.c
@@ -0,0 +1,86 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: xgetnext.c
+
+ Description: This file contains code that does nothing but return...
+ Excahnge has only one object and it is returned by GetCurrent DDB...
+
+ $Log: M:/LOGFILES/XGETNEXT.C_V $
+
+**/
+/* begin include list */
+#include <windows.h>
+#include <string.h>
+#include <malloc.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "std_err.h"
+#include "queues.h"
+
+#include "msassert.h"
+#include "fsys.h"
+#include "fsys_err.h"
+#include "emsdblk.h"
+#include "ems_fs.h"
+#include "tfldefs.h"
+
+
+/**/
+/**
+
+ Name: EMS_FindFirst()
+
+ Description: Returns FS_NO_MORE
+
+ Modified: 1/10/1992 15:24:39
+
+ Returns: Error codes:
+ FS_NO_MORE
+**/
+
+INT16 EMS_FindFirst(
+FSYS_HAND fsh, /* I - file system handle */
+DBLK_PTR dblk, /* O - pointer to place to put the dblk data */
+CHAR_PTR sname, /* I - search name */
+UINT16 obj_type) /* I - objects to search for (dirs, all, etc)*/
+{
+ return FS_NO_MORE ;
+}
+
+/**/
+/**
+
+ Name: EMS_FindNext()
+
+ Description: return FS_N_MORE
+
+**/
+INT16 EMS_FindNext( fsh, dblk )
+FSYS_HAND fsh; /* I - File system handle */
+DBLK_PTR dblk; /* O - Discriptor block */
+{
+ return FS_NO_MORE ;
+}
+
+
+
+/**/
+/**
+
+ Name: EMS_FindClose()
+
+ Description: Return Success
+
+**/
+INT16 EMS_FindClose( FSYS_HAND fsh,
+ DBLK_PTR dblk )
+{
+ (void)fsh;
+ (void)dblk;
+ return SUCCESS ;
+}
+
+
diff --git a/private/utils/ntbackup/src/xgetpath.c b/private/utils/ntbackup/src/xgetpath.c
new file mode 100644
index 000000000..85b48bef1
--- /dev/null
+++ b/private/utils/ntbackup/src/xgetpath.c
@@ -0,0 +1,189 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: xgetpath.c
+
+ Description: This file contains code to get the current directory
+ path and the complete directory path from the file system handle.
+ For exchange (monolithic) backup the only block that exists is the
+ one MDB or DSA block. GetCurrendDDB retuns this block.
+
+
+ $Log: M:/LOGFILES/XGETPATH.C_V $
+
+
+**/
+#include <windows.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "queues.h"
+
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "emsdblk.h"
+#include "ems_fs.h"
+/**/
+/**
+
+ Name: EMS_GetCurrentPath()
+
+ Description: This function sets a string to describes the current
+ path.
+
+ Modified: 1/10/1992 14:2:3
+
+ Returns: Error Codes :
+ FS_DLE_NOT_ATTACHED
+ FS_BUFFER_TO_SMALL
+ SUCCESS
+
+ Notes: The delimiter between directories is '\0'
+
+**/
+INT16 EMS_GetCurrentPath( fsh, path, size )
+FSYS_HAND fsh ; /* I - file system to get current path from */
+CHAR_PTR path ; /* O - buffer to place this path */
+INT16 *size ; /*I/O- size of buffer on entry & on exit */
+{
+ GENERIC_DLE_PTR dle ;
+ CHAR_PTR p ;
+ INT16 ret_val ;
+ INT16 temp_size ;
+
+ dle = fsh->attached_dle ;
+
+ msassert( dle != NULL ) ;
+
+ temp_size = (INT16)strsize( fsh->cur_dir ) ; /* count the last '\0' */
+
+ if ( *size < temp_size ) {
+
+ ret_val = FS_BUFFER_TO_SMALL ;
+
+ }
+ else {
+
+ /* copy the whole cur_dir over and then...*/
+
+ strcpy( path, &(fsh->cur_dir[1]) ) ;
+
+ /* ...replace backslashes with nulls */
+
+ p = strchr( path, TEXT('\\') ) ;
+ while ( p != NULL ) {
+ *p = TEXT('\0');
+ p = strchr( p+1, TEXT('\\') ) ;
+ }
+
+ ret_val = SUCCESS ;
+ }
+
+ *size = temp_size ;
+
+ return ret_val ;
+}
+
+/**/
+/**
+
+ Name: EMS_GetCurrentDDB()
+
+ Description: This function initializes the provided DDB with the
+ information for the current directory.
+
+
+ Modified: 1/10/1992 14:45:26
+
+ Returns: Error code:
+ FS_INVALID_DIR
+ SUCCESS
+ OUT_OF_MEMORY
+
+ Notes:
+
+**/
+INT16 EMS_GetCurrentDDB( fsh, dblk )
+FSYS_HAND fsh ; /* I - file system to get DDB from */
+DBLK_PTR dblk ; /* O - place to put the DDB data */
+{
+ GENERIC_DLE_PTR dle = fsh->attached_dle ;
+ EMS_DBLK_PTR ddblk = (EMS_DBLK_PTR)dblk ;
+ INT16 ret_val = SUCCESS ;
+
+ ddblk->ems_type = dle->info.xserv->type ;
+ ddblk->os_info_complete = TRUE ;
+ dblk->blk_type = DDB_ID ;
+
+ if ( dle->info.xserv->type == EMS_MDB ) {
+ dblk->com.os_id = FS_EMS_MDB_ID ;
+ dblk->com.os_ver = FS_EMS_MDB_VER ;
+
+ ret_val = FS_SetupOSPathOrNameInDBLK( fsh,
+ dblk,
+ (BYTE_PTR)EMS_String( MDB_Monolithic ),
+ (INT16)strsize(EMS_String( MDB_Monolithic ) ) ) ;
+
+
+ } else if ( dle->info.xserv->type == EMS_DSA ) {
+ dblk->com.os_id = FS_EMS_DSA_ID ;
+ dblk->com.os_ver = FS_EMS_DSA_VER ;
+ ret_val = FS_SetupOSPathOrNameInDBLK( fsh,
+ dblk,
+ (BYTE_PTR)EMS_String( DSA ),
+ (INT16)strsize(EMS_String( DSA ) ) ) ;
+
+
+ } else {
+ msassert( "We currently don't support bricked" == NULL ) ;
+ }
+
+ return( ret_val ) ;
+}
+
+
+/**/
+/**
+
+ Name: EMS_ReleaseBlk()
+
+ Description: This function releases any resources connected to a DBLK.
+ For this OS the only resource is the Path connected to the DDB
+
+ Modified: 5/18/1992 10:27:34
+
+ Returns: none
+
+**/
+VOID EMS_ReleaseBlk(
+FSYS_HAND fsh,
+DBLK_PTR dblk )
+{
+ EMS_DBLK_PTR ddblk ;
+
+ fsh ;
+
+ ddblk = (EMS_DBLK_PTR)dblk ;
+
+ FS_ReleaseOSPathOrNameInDBLK( fsh, dblk ) ;
+
+}
+
+INT16 EMS_DupBlk( FSYS_HAND fsh, DBLK_PTR db_org, DBLK_PTR db_dup )
+{
+ EMS_DBLK_PTR ddblk = (EMS_DBLK_PTR)db_org ;
+
+ *db_dup = *db_org ;
+
+ return( FS_SetupOSPathOrNameInDBLK( fsh,
+ db_dup,
+ (BYTE_PTR)db_org->com.os_name->name,
+ db_org->com.os_name->name_size ) );
+
+
+
+}
+
diff --git a/private/utils/ntbackup/src/xinitfs.c b/private/utils/ntbackup/src/xinitfs.c
new file mode 100644
index 000000000..eed7e68f5
--- /dev/null
+++ b/private/utils/ntbackup/src/xinitfs.c
@@ -0,0 +1,1192 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tinitfs.c
+
+ Description: This file contains code to add EMS dles to the
+ drive list.
+
+ $Log: N:/LOGFILES/TINITFS.C_V $
+
+
+**/
+#include <windows.h>
+#include <winioctl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+
+#include "sadapi.h"
+#include "jet.h"
+#include "jetbcli.h"
+#include "edbmsg.h"
+
+#include "stdtypes.h"
+#include "ems_jet.h"
+#include "omevent.h"
+
+#include "std_err.h"
+#include "stdwcs.h"
+
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "emsdblk.h"
+#include "ems_fs.h"
+#include "gen_fs.h"
+
+extern CHAR gszDleDsName[];
+extern CHAR gszDleIsName[];
+
+static EC (FAR PASCAL *ems_BackupPrepare) (LPSTR, LPSTR, unsigned long, INT , HBC *) = 0;
+static EC (FAR PASCAL *ems_BackupGetAttachmentInfo)( PVOID a, CHAR **b, LPDWORD c ) = 0;
+static EC (FAR PASCAL *ems_BackupRead)(PVOID, PVOID, DWORD, PDWORD ) = 0;
+static EC (FAR PASCAL *ems_BackupClose)(PVOID ) = 0;
+static EC (FAR PASCAL *ems_BackupOpen)(PVOID, LPSTR, DWORD, LARGE_INTEGER *) = 0;
+static EC (FAR PASCAL *ems_GetBackupLogs)( PVOID, LPSTR *, LPDWORD ) = 0;
+static EC (FAR PASCAL *ems_TruncateLogs)(PVOID ) = 0 ;
+static EC (FAR PASCAL *ems_BackupEnd)(PVOID ) = 0;
+static EC (FAR PASCAL *ems_BackupFree)(PVOID) ;
+static EC (FAR PASCAL *ems_RestorePrepare)( PVOID, PVOID, PVOID * ) ;
+static EC (FAR PASCAL *ems_RestoreRegister)( PVOID, PVOID, PVOID, PVOID, INT, PVOID, INT, INT ) ;
+static EC (FAR PASCAL *ems_RestoreLocations)( PVOID, PVOID, INT *);
+static EC (FAR PASCAL *ems_RestoreEnd)(PVOID) ;
+static EC (FAR PASCAL *ems_RestoreComplete)(PVOID, ULONG) ;
+
+VOID EMS_StartSAD( CHAR_PTR server_name ) ;
+
+BOOL MAYN_GetUserName (
+ LPSTR *pUser,
+ LPDWORD pcbUser
+ );
+
+
+CHAR_PTR gszEmsStringList[] = {
+ TEXT("MDB Bricked"), //MDB_Bricked
+ gszDleIsName, //MDB_Monolithic
+ gszDleDsName, //DSA
+ TEXT("Mailboxes"), //Mailboxes
+ TEXT("Public Folders") //Public_Folders
+ };
+
+
+#define EMS_SERVER_LIST_STOP -1
+static CHAR_PTR EMS_EnumServerInList( INT *index ) ;
+static VOID EMS_ZeroServerListEntry( INT index ) ;
+static VOID AddEMS_DLE( DLE_HAND hand,
+ CHAR_PTR drive,
+ UINT32 type,
+ GENERIC_DLE_PTR *current_dle );
+
+
+typedef struct THREAD_PARMS {
+ DLE_HAND dle_hand;
+} THREAD_PARMS, *THREAD_PARMS_PTR ;
+
+DWORD EMS_ThreadFindDrives( THREAD_PARMS_PTR thread_parms_ptr ) ;
+
+// this function is for debug only
+static VOID GetServerListForEnterprise( CHAR_PTR server_name, BackupListNode *node_root ) ;
+
+
+/**/
+/**
+
+ Name: AddDLEsForEMS()
+
+ Description: This function starts a thread that creates a DLE for each exchange
+ server on the enterprises of interest..
+
+ Modified: 12/2/1991 16:29:59
+
+ Returns: none
+
+ Declaration:
+**/
+INT16 EMS_FindDrives( DLE_HAND hand, BE_CFG_PTR cfg, UINT32 fsys_mask )
+{
+ HANDLE hThread ;
+ DWORD pthread_id ;
+ THREAD_PARMS thread_parms ;
+
+ (VOID)cfg ;
+ (VOID)fsys_mask ;
+
+ thread_parms.dle_hand = hand ;
+
+ hThread = CreateThread( NULL,
+ 0,
+ EMS_ThreadFindDrives,
+ &thread_parms,
+ 0,
+ &pthread_id ) ;
+
+ if ( hThread != NULL )
+ {
+ while ( WaitForSingleObject( hThread, 100 ) == WAIT_TIMEOUT )
+ {
+ ThreadSwitch( ) ;
+ }
+ CloseHandle( hThread ) ;
+ }
+ else
+ {
+ EMS_ThreadFindDrives( &thread_parms ) ;
+ }
+ return SUCCESS ;
+}
+
+/**/
+/**
+
+ Name: EMS_ThreadFindDrives()
+
+ Description: This function actuall call the System attendant on the servers of
+ interest asking for a list of sites and servers on the exchagne. Form this
+ info, this function will create the DLE tree.
+
+ Modified: 12/2/1991 16:29:59
+
+ Returns: none
+
+ Declaration:
+**/
+HINSTANCE JetApi = NULL ;
+
+DWORD EMS_ThreadFindDrives( THREAD_PARMS_PTR thread_parms_ptr )
+{
+ DLE_HAND hand = thread_parms_ptr->dle_hand ;
+ GENERIC_DLE_PTR pCurrentDLE ; // ptr to current DLE
+ INT index ;
+ CHAR_PTR server_name ;
+ INT status ;
+ CHAR machineName[256] ;
+
+ // With any luch, we will get a LIB to link with. When that happens we can
+ // get rid of the load library stuff
+
+ if ( !JetApi ) {
+ JetApi = LoadLibrary( TEXT("edbbcli.dll")) ;
+ }
+
+ if (JetApi ) {
+ ems_BackupPrepare = (VOID *)GetProcAddress( JetApi, "HrBackupPrepareW") ;
+ ems_BackupGetAttachmentInfo =
+ (VOID *)GetProcAddress( JetApi, "HrBackupGetDatabaseNamesW") ;
+ ems_BackupRead = (VOID *)GetProcAddress( JetApi, "HrBackupRead") ;
+ ems_BackupClose = (VOID *)GetProcAddress( JetApi, "HrBackupClose");
+ ems_BackupOpen = (VOID *)GetProcAddress( JetApi, "HrBackupOpenFileW") ;
+ ems_GetBackupLogs = (VOID *)GetProcAddress( JetApi, "HrBackupGetBackupLogsW");
+ ems_TruncateLogs = (VOID *)GetProcAddress( JetApi, "HrBackupTruncateLogs") ;
+ ems_BackupEnd = (VOID *)GetProcAddress( JetApi, "HrBackupEnd") ;
+ ems_BackupFree = (VOID *)GetProcAddress( JetApi, "BackupFree") ;
+ ems_RestorePrepare = (VOID *)GetProcAddress( JetApi, "HrRestorePrepareW") ;
+ ems_RestoreRegister = (VOID *)GetProcAddress( JetApi, "HrRestoreRegisterW") ;
+ ems_RestoreComplete = (VOID *)GetProcAddress( JetApi, "HrRestoreRegisterComplete") ;
+ ems_RestoreLocations = (VOID *)GetProcAddress( JetApi, "HrRestoreGetDatabaseLocationsW") ;
+ ems_RestoreEnd = (VOID *)GetProcAddress( JetApi, "HrRestoreEnd") ;
+ }
+
+ if ( !JetApi ||
+ !ems_BackupPrepare ||
+ !ems_BackupGetAttachmentInfo ||
+ !ems_BackupRead ||
+ !ems_BackupClose ||
+ !ems_BackupOpen ||
+ !ems_GetBackupLogs ||
+ !ems_TruncateLogs ||
+ !ems_BackupEnd ||
+ !ems_BackupFree ||
+ !ems_RestorePrepare ||
+ !ems_RestoreRegister ||
+ !ems_RestoreComplete ||
+ !ems_RestoreLocations ||
+ !ems_RestoreEnd )
+ {
+
+ return FAILURE ;
+ }
+
+
+ // lets add the current machine to the list of interesting servers.
+
+ memset( machineName, 0, sizeof(machineName) );
+
+ status = EMS_GetValFromReg(
+ NULL, // machine name
+ TEXT("SYSTEM\\CurrentControlSet\\Control\\ComputerName\\ActiveComputerName"),
+ TEXT("ComputerName"),
+ machineName,
+ sizeof(machineName));
+
+ EMS_AddToServerList( hand, machineName );
+
+
+ // Now lets ask each interesting server to provide a Enterprise tree.
+ index = EMS_SERVER_LIST_STOP ;
+
+ do {
+ BackupListNode *node_root, *Enterprise, *Site, *Server ;
+ GENERIC_DLE_PTR EnterpriseDLE = NULL ;
+ GENERIC_DLE_PTR SiteDLE = NULL ;
+ GENERIC_DLE_PTR ServerDLE = NULL ;
+ GENERIC_DLE_PTR temp_dle = NULL ;
+
+ server_name = EMS_EnumServerInList( &index ) ;
+
+ if ( server_name ) {
+
+ node_root = NULL ;
+
+ EMS_StartSAD( server_name ) ;
+
+ SAD_ScGetBackupListNodeW(server_name, &node_root);
+
+ if ( node_root == NULL ) {
+ /* if MAD servies is running then lets just add the server */
+ if (EMS_IsServiceRunning( server_name, SERVICE_MAD ) ) {
+
+ ServerDLE = NULL ;
+
+ AddEMS_DLE( hand,
+ server_name,
+ EMS_SERVER,
+ &ServerDLE );
+ } else {
+
+
+ EMS_ZeroServerListEntry( index ) ;
+ continue ;
+ }
+ }
+
+ Enterprise = node_root ;
+
+ while ( Enterprise ) {
+ BOOLEAN found = FALSE ;
+
+ EnterpriseDLE = NULL ;
+
+ // Lets verify that this DLE doesn't already exist
+
+ if ( SUCCESS == DLE_FindByName( hand, server_name, FS_EMS_DRV, &temp_dle ) ) {
+ if ( temp_dle->parent != NULL ) {
+
+ found = TRUE ;
+ EnterpriseDLE = temp_dle->parent->parent ;
+ } else {
+ EMS_RemoveDLE( temp_dle ) ;
+ }
+
+ }
+ if ( !found ) {
+
+ if ( SUCCESS == DLE_FindByName( hand,
+ Enterprise->szName,
+ FS_EMS_DRV,
+ &temp_dle ) )
+ {
+
+ DLE_GetFirstChild( temp_dle, &temp_dle ) ;
+ if( temp_dle ) {
+ DLE_GetFirstChild( temp_dle, &temp_dle ) ;
+ }
+ if ( temp_dle ) {
+ Site = Enterprise->pnodeChildren ;
+ while( Site ) {
+ Server = Site->pnodeChildren ;
+ while( Server ) {
+ if ( !stricmp( Server->szName, DLE_GetDeviceName( temp_dle ) ) ) {
+ EnterpriseDLE = temp_dle->parent->parent ;
+ }
+ Server = Server->pnodeNext ;
+ }
+ Site = Site->pnodeNext ;
+ }
+ }
+ }
+ }
+
+ if ( EnterpriseDLE == NULL ) {
+ AddEMS_DLE( hand,
+ Enterprise->szName,
+ EMS_ENTERPRISE,
+ &EnterpriseDLE );
+ }
+
+ Site = Enterprise->pnodeChildren ;
+
+ while ( EnterpriseDLE && Site ) {
+
+ DLE_GetFirstChild( EnterpriseDLE, &SiteDLE ) ;
+
+ while ( SiteDLE ) {
+ if ( !stricmp( Site->szName, DLE_GetDeviceName( SiteDLE ) ) ) {
+ break ;
+ }
+ DLE_GetNext( &SiteDLE ) ;
+ }
+
+ if ( !SiteDLE ) {
+ SiteDLE = EnterpriseDLE ;
+
+ AddEMS_DLE( hand,
+ Site->szName,
+ EMS_SITE,
+ &SiteDLE );
+ }
+
+ Server = Site->pnodeChildren ;
+
+ while (SiteDLE && Server) {
+
+ DLE_GetFirstChild( SiteDLE, &ServerDLE ) ;
+
+ while ( ServerDLE ) {
+ if ( !stricmp( Server->szName, DLE_GetDeviceName( ServerDLE ) ) ) {
+ break ;
+ }
+ DLE_GetNext( &ServerDLE ) ;
+ }
+
+ if ( !ServerDLE ) {
+
+ ServerDLE = SiteDLE ;
+
+ AddEMS_DLE( hand,
+ Server->szName,
+ EMS_SERVER,
+ &ServerDLE );
+ }
+
+ Server = Server->pnodeNext ;
+ }
+
+ Site = Site->pnodeNext ;
+ }
+
+ Enterprise = Enterprise->pnodeNext ;
+ }
+ }
+
+ } while ( index != EMS_SERVER_LIST_STOP ) ;
+
+
+ return SUCCESS ;
+}
+
+
+/**/
+/**
+
+ Name: AddDLEsForEMS()
+
+ Description: This function creates the DLE Exchange Enterprise/Site/Server/Store
+
+ For this function the pCurrentDLE must be the parent dle on entry and will be
+ set to the created DLE on exit. If an error occurs then pCurrentDLE is set
+ to NULL.
+
+ Modified: 12/2/1991 16:29:59
+
+ Returns: none
+
+ Declaration:
+**/
+static VOID AddEMS_DLE(
+DLE_HAND hand, /* I - Handle to DLE list */
+CHAR_PTR name, /* I - drive letter for dle */
+UINT32 type,
+GENERIC_DLE_PTR *pCurrentDLE /* O - current dle */ )
+{
+ GENERIC_DLE_PTR dle ;
+ BYTE_PTR dummy ;
+ GENERIC_DLE_PTR temp_dle = NULL;
+ static LPSTR user_name = NULL ;
+ INT user_name_size ;
+
+ // OK now since this is a new one, lets create it.
+
+ switch( type ) {
+
+ case EMS_ENTERPRISE:
+ case EMS_SITE:
+
+ dle = calloc ( 1, sizeof( GENERIC_DLE ) +
+ sizeof( struct EMS_SERVER_DLE_INFO ) ) ;
+
+ if ( dle != NULL ) {
+
+ dle->device_name = malloc ( strsize( name ) ) ;
+
+ if ( dle->device_name == NULL ) {
+ free( dle ) ;
+ dle = NULL ;
+ } else {
+ dle->info.xserv = (EMS_SERVER_DLE_INFO_PTR)(dle + 1) ;
+ dle->info.xserv->type = type ;
+ strcpy( dle->device_name, name ) ;
+ dle->info.xserv->server_name = dle->device_name ;
+ }
+ }
+
+ if ( dle != NULL ) {
+
+ /* Since memory was allocated with calloc, it is already */
+ /* initialized to zero. Therefore initializations to zero */
+ /* are not necessary. */
+
+ InitQElem( &(dle->q) ) ;
+ dle->os_id = 0 ;
+ dle->handle = hand ;
+ dle->parent = *pCurrentDLE ;
+ dle->type = FS_EMS_DRV ;
+ dle->subtype = (UINT8)type ;
+
+ dle->path_delim = TEXT('\\') ;
+ /* dle->pswd_required = FALSE */
+ /* dle->pswd_saved = FALSE ; */
+ /* dle->attach_count = 0 ; */
+ /* dle->bsd_use_count = 0 ; */
+ /* dle->dynamic_info = FALSE ; */
+
+ dle->device_name_leng = strsize( dle->device_name ) ;
+
+ dle->dle_writeable = TRUE;
+ dle->feature_bits = DLE_FEAT_SUPPORTS_CHILDREN |
+ DLE_FEAT_REMOTE_DRIVE ;
+
+ }
+
+ if ( dle ) {
+ if ( *pCurrentDLE ) {
+ DLE_QueueInsert( (HEAD_DLE *)(&((*pCurrentDLE)->child_q)), dle ) ;
+ } else {
+ DLE_QueueInsert( hand, dle ) ;
+ }
+ }
+
+ break ;
+
+ case EMS_SERVER:
+
+// if ( NetServiceGetInfo( name, SERVICE_MESSAGE_DB, 0, &dummy ) ) {
+// // the necessary service is not running on the requsted machine
+// return ;
+// }
+
+ dle = calloc ( 1, sizeof( GENERIC_DLE ) +
+ sizeof( struct EMS_SERVER_DLE_INFO ) ) ;
+
+ if ( dle != NULL ) {
+
+ dle->device_name = malloc ( strsize( name ) ) ;
+
+ if ( dle->device_name == NULL ) {
+ free( dle ) ;
+ dle = NULL ;
+
+ } else {
+ dle->info.xserv = (EMS_SERVER_DLE_INFO_PTR)(dle + 1) ;
+ dle->info.xserv->type = type ;
+ strcpy( dle->device_name, name ) ;
+ dle->info.xserv->server_name = dle->device_name ;
+ }
+ }
+
+ if ( dle != NULL ) {
+
+ /* Since memory was allocated with calloc, it is already */
+ /* initialized to zero. Therefore initializations to zero */
+ /* are not necessary. */
+
+ InitQElem( &(dle->q) ) ;
+ dle->handle = hand ;
+ dle->parent = *pCurrentDLE ;
+ dle->type = FS_EMS_DRV ;
+ dle->subtype = (UINT8)type ;
+ dle->path_delim = TEXT('\\') ;
+ /* dle->pswd_required = FALSE */
+ /* dle->pswd_saved = FALSE ; */
+ /* dle->attach_count = 0 ; */
+ /* dle->bsd_use_count = 0 ; */
+ /* dle->dynamic_info = FALSE ; */
+
+ dle->device_name_leng = strsize( dle->device_name ) ; // 8/20/92 BBB
+ dle->dle_writeable = TRUE;
+ dle->feature_bits = DLE_FEAT_SUPPORTS_CHILDREN |
+ DLE_FEAT_REMOTE_DRIVE ;
+
+ }
+
+ if ( dle ) {
+
+ if ( *pCurrentDLE ) {
+ DLE_QueueInsert( (HEAD_DLE *)(&((*pCurrentDLE)->child_q)), dle ) ;
+ } else {
+ DLE_QueueInsert( hand, dle ) ;
+ }
+
+ temp_dle = dle ;
+ AddEMS_DLE( hand, EMS_String(MDB_Monolithic), EMS_MDB, &temp_dle ) ;
+ temp_dle = dle ;
+ AddEMS_DLE( hand, EMS_String(DSA), EMS_DSA, &temp_dle ) ;
+ }
+
+ break ;
+
+ case EMS_MDB:
+ case EMS_DSA:
+
+ user_name_size = 200 ;
+ if ( user_name || MAYN_GetUserName( (LPSTR*)&user_name, (LPDWORD)&user_name_size ) ) {
+ user_name_size = strsize( user_name ) ;
+
+ } else {
+ user_name_size = 0 ;
+ user_name = NULL ;
+ }
+
+ dle = calloc ( 1, sizeof( GENERIC_DLE ) +
+ sizeof( struct EMS_MDB_DSA_DLE_INFO ) ) ;
+
+ if ( dle != NULL ) {
+ INT name_size ;
+
+ name_size = strsize(name);
+ if ( *pCurrentDLE ) {
+ name_size += strsize( (*pCurrentDLE)->device_name ) ;
+ }
+
+ dle->device_name = malloc ( name_size ) ;
+
+ if ( dle->device_name == NULL ) {
+ free( dle ) ;
+ dle = NULL ;
+
+ } else {
+ dle->user_name = user_name ;
+ dle->user_name_leng = user_name_size ;
+
+ dle->info.xmono = (EMS_MDB_DSA_DLE_INFO_PTR)(dle + 1) ;
+ dle->info.xmono->type = type ;
+ dle->info.xmono->server_name = (*pCurrentDLE)->info.xserv->server_name ;
+
+ if ( *pCurrentDLE ) {
+ strcpy( dle->device_name, (*pCurrentDLE)->device_name ) ;
+ strcat( dle->device_name, TEXT("\\") ) ;
+ strcat( dle->device_name, name ) ;
+ } else {
+ strcpy( dle->device_name, name ) ;
+ }
+ }
+ }
+
+ if ( dle != NULL ) {
+
+ /* Since memory was allocated with calloc, it is already */
+ /* initialized to zero. Therefore initializations to zero */
+ /* are not necessary. */
+
+ InitQElem( &(dle->q) ) ;
+ if ( type == EMS_MDB ) {
+ dle->os_id = FS_EMS_MDB_ID ;
+ } else {
+ dle->os_id = FS_EMS_DSA_ID ;
+ }
+
+ dle->handle = hand ;
+ dle->parent = *pCurrentDLE ;
+ dle->type = FS_EMS_DRV ;
+ dle->subtype = (UINT8)type ;
+ dle->path_delim = TEXT(' ') ;
+ /* dle->pswd_required = FALSE */
+ /* dle->pswd_saved = FALSE ; */
+ /* dle->attach_count = 0 ; */
+ /* dle->bsd_use_count = 0 ; */
+ /* dle->dynamic_info = FALSE ; */
+
+ dle->feature_bits = DLE_FEAT_NON_DISPLAYABLE_CONT |
+ DLE_FEAT_REMOTE_DRIVE ;
+
+ dle->device_name_leng = strsize( dle->device_name ) ; // 8/20/92 BBB
+
+ dle->dle_writeable = TRUE;
+
+ }
+
+ if ( dle ) {
+ // for now if the machine is the current machine add to root
+
+ if ( !*pCurrentDLE ) {
+
+ DLE_QueueInsert( hand, dle ) ;
+ } else {
+
+ DLE_QueueInsert( (HEAD_DLE*)(&((*pCurrentDLE)->child_q)), dle ) ;
+ }
+ }
+
+ break ;
+
+ case EMS_BRICK:
+ break ;
+
+ default:
+ return ;
+ }
+
+
+ /* assign current dle */
+ *pCurrentDLE = dle ;
+
+}
+
+
+/**/
+/**
+
+ Name: EMS_RemoveDLE()
+
+ Description: This function removes the specified DLE ;
+
+ Modified: 12/2/1991 16:29:59
+
+ Returns: none
+
+**/
+VOID EMS_RemoveDLE( GENERIC_DLE_PTR dle )
+{
+
+ free( dle->device_name ) ;
+ GEN_RemoveDLE( dle );
+}
+
+/**/
+/**
+
+ Name: EMS_AddToServerList() & EMS_EnumServerList()
+
+ Description: These funcitons will maintain the list of ems servers
+ Modified: 12/2/1991 16:29:59
+
+ Returns: none
+
+ Declaration:
+**/
+static CHAR_PTR *server_list = NULL ;
+static INT server_list_size = 0 ;
+static INT next_free_index = 0 ;
+
+#ifdef FS_EMS
+INT EMS_AddToServerList( DLE_HAND dle_list, CHAR_PTR server_name )
+{
+
+ INT i ;
+ GENERIC_DLE_PTR dle ;
+
+ if ( ( next_free_index == server_list_size ) ) {
+ server_list_size += 20;
+ server_list = realloc ( server_list, server_list_size * sizeof(CHAR_PTR) ) ;
+ }
+
+ if ( server_list == NULL ) {
+ server_list_size = 0 ;
+ next_free_index = 0 ;
+ }
+
+ if ( server_name ) {
+ server_list[ next_free_index ] = malloc( strsize( server_name ) ) ;
+ if ( server_list[ next_free_index ] ) {
+ strcpy( server_list[ next_free_index ], server_name ) ;
+ next_free_index ++ ;
+ } else {
+ return FAILURE ;
+ }
+ }
+
+ if ( next_free_index ) {
+ return SUCCESS ;
+ } else {
+ return FAILURE ;
+ }
+
+}
+#ifdef FS_EMS
+INT EMS_RemoveFromServerList( CHAR_PTR server_name )
+{
+
+ INT i;
+
+ for( i = next_free_index - 1; i >= 0; i-- ) {
+
+ if ( server_list[i] &&
+ !stricmp( server_name, server_list[i] ) ) {
+
+ EMS_ZeroServerListEntry( i );
+ break;
+ }
+ }
+
+ return SUCCESS;
+}
+#endif
+
+CHAR_PTR EMS_EnumSvrInList( INT *index )
+{
+ return EMS_EnumServerInList( index );
+}
+
+
+#endif
+CHAR_PTR EMS_EnumServerInList( INT *index )
+{
+ if ( *index == EMS_SERVER_LIST_STOP ) {
+ *index = 0 ;
+ } else {
+ *index += 1 ;
+ }
+
+ if ( *index >= next_free_index ) {
+ *index = EMS_SERVER_LIST_STOP ;
+ return NULL ;
+ } else {
+ return server_list[ *index ] ;
+ }
+}
+
+static VOID EMS_ZeroServerListEntry( INT index )
+{
+ if (index < next_free_index ) {
+ free( server_list[index] ) ;
+ server_list[index] = NULL ;
+ }
+}
+
+
+EC EMS_BackupPrepare(LPSTR a, LPSTR b, unsigned long c, INT d, HBC *e)
+{
+ EC status ;
+ status = (*ems_BackupPrepare)(a,b,c,d,e) ;
+
+ if ( status ) {
+ CHAR_PTR message = NULL;
+
+ if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
+ (HINSTANCE)JetApi, status, 0, (LPSTR)(&message), 0, NULL ) ) {
+
+ OMEVENT_LogEMSErrorText ( TEXT("BackupPrepare()"), message, a ) ;
+ LocalFree( message ) ;
+ } else if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, status, 0, (LPSTR)(&message), 0, NULL ) ) {
+
+ OMEVENT_LogEMSErrorText ( TEXT("BackupPrepare()"), message, a ) ;
+ LocalFree( message ) ;
+
+ } else {
+ OMEVENT_LogEMSError ( TEXT("BackupPrepare()"), status, a ) ;
+ }
+ }
+ return ( status ) ;
+}
+
+EC EMS_BackupGetAttachmentInfo( PVOID a, CHAR **b, LPDWORD c)
+{
+ EC status ;
+ status = (*ems_BackupGetAttachmentInfo)( a,b,c ) ;
+
+ if ( status ) {
+ CHAR_PTR message = NULL;
+
+ if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
+ (HINSTANCE)JetApi, status, 0, (LPSTR)(&message), 0, NULL ) ) {
+
+ OMEVENT_LogEMSErrorText( TEXT("BackupGetAttachmentInfo()"), message, TEXT(" - ") ) ;
+ LocalFree( message ) ;
+ } else if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, status, 0, (LPSTR)(&message), 0, NULL ) ) {
+
+ OMEVENT_LogEMSErrorText( TEXT("BackupGetAttachmentInfo()"), message, TEXT(" - ") ) ;
+ LocalFree( message ) ;
+ } else {
+ OMEVENT_LogEMSError ( TEXT("BackupGetAttachmentInfo()"), status, TEXT(" - ") ) ;
+ }
+ }
+ return ( status ) ;
+}
+
+EC EMS_BackupRead(PVOID a, PVOID b, DWORD c, PDWORD d)
+{
+ EC status ;
+ status = (*ems_BackupRead)(a,b,c,d) ;
+
+ return ( status ) ;
+}
+EC EMS_BackupClose(PVOID a )
+{
+ EC status = 0;
+
+ if ( a ) {
+ status = (*ems_BackupClose)(a) ;
+ }
+
+ if ( status ) {
+ CHAR_PTR message = NULL;
+
+ if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
+ (HINSTANCE)JetApi, status, 0, (LPSTR)(&message), 0, NULL ) ) {
+
+ OMEVENT_LogEMSErrorText( TEXT("BackupClose()"), message, TEXT(" - ") ) ;
+ LocalFree( message ) ;
+ } else if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, status, 0, (LPSTR)(&message), 0, NULL ) ) {
+
+ OMEVENT_LogEMSErrorText( TEXT("BackupClose()"), message, TEXT(" - ") ) ;
+ LocalFree( message ) ;
+ } else {
+ OMEVENT_LogEMSError ( TEXT("BackupClose()"), status, TEXT(" - ") ) ;
+ }
+ }
+ return ( status ) ;
+}
+EC EMS_BackupOpen(PVOID a, LPSTR b, DWORD c, LARGE_INTEGER *d )
+{
+ EC status ;
+ status = (*ems_BackupOpen)(a,b,c,d) ;
+
+ if ( status ) {
+ CHAR_PTR message = NULL;
+
+ if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
+ (HINSTANCE)JetApi, status, 0, (LPSTR)(&message), 0, NULL ) ) {
+
+ OMEVENT_LogEMSErrorText( TEXT("BackupOpen()"), message, b ) ;
+ LocalFree( message ) ;
+ } else if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, status, 0, (LPSTR)(&message), 0, NULL ) ) {
+
+ OMEVENT_LogEMSErrorText( TEXT("BackupOpen()"), message, b ) ;
+ LocalFree( message ) ;
+ } else {
+ OMEVENT_LogEMSError ( TEXT("BackupOpen()"), status, b ) ;
+ }
+ }
+ return ( status ) ;
+}
+EC EMS_GetBackupLogs( PVOID a, LPSTR *b, LPDWORD c)
+{
+ EC status ;
+ status = (*ems_GetBackupLogs)( a,b,c ) ;
+
+ if ( status ) {
+ CHAR_PTR message = NULL;
+
+ if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
+ (HINSTANCE)JetApi, status, 0, (LPSTR)(&message), 0, NULL ) ) {
+
+ OMEVENT_LogEMSErrorText( TEXT("BackupLogs()"), message, TEXT(" - ") ) ;
+ LocalFree( message ) ;
+ } else if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, status, 0, (LPSTR)(&message), 0, NULL ) ) {
+
+ OMEVENT_LogEMSErrorText( TEXT("BackupLogs()"), message, TEXT(" - ") ) ;
+ LocalFree( message ) ;
+ } else {
+ OMEVENT_LogEMSError ( TEXT("BackupLogs()"), status, TEXT(" - ") ) ;
+ }
+ }
+ return ( status ) ;
+}
+EC EMS_TruncateLogs( PVOID a )
+{
+ EC status ;
+ status = (*ems_TruncateLogs)(a) ;
+
+ if ( status ) {
+ CHAR_PTR message = NULL;
+
+ if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
+ (HINSTANCE)JetApi, status, 0, (LPSTR)(&message), 0, NULL ) ) {
+
+ OMEVENT_LogEMSErrorText( TEXT("TruncateLogs()"), message, TEXT(" - ") ) ;
+ LocalFree( message ) ;
+ } else if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, status, 0, (LPSTR)(&message), 0, NULL ) ) {
+
+ OMEVENT_LogEMSErrorText( TEXT("TruncateLogs()"), message, TEXT(" - ") ) ;
+ LocalFree( message ) ;
+ } else {
+ OMEVENT_LogEMSError ( TEXT("TruncateLogs()"), status, TEXT(" - ") ) ;
+ }
+ }
+ return ( status ) ;
+}
+
+EC EMS_BackupEnd(PVOID a )
+{
+ EC status ;
+ status = (*ems_BackupEnd)(a) ;
+
+ if ( status ) {
+ CHAR_PTR message = NULL;
+
+ if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
+ (HINSTANCE)JetApi, status, 0, (LPSTR)(&message), 0, NULL ) ) {
+
+ OMEVENT_LogEMSErrorText( TEXT("BackupEnd()"), message, TEXT(" - ") ) ;
+ LocalFree( message ) ;
+ } else if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, status, 0, (LPSTR)(&message), 0, NULL ) ) {
+
+ OMEVENT_LogEMSErrorText( TEXT("BackupEnd()"), message, TEXT(" - ") ) ;
+ LocalFree( message ) ;
+ } else {
+ OMEVENT_LogEMSError ( TEXT("BackupEnd()"), status, TEXT(" - ") ) ;
+ }
+ }
+ return ( status ) ;
+}
+
+VOID EMS_BackupFree(PVOID a)
+{
+ (*ems_BackupFree)(a) ;
+}
+
+EC EMS_RestoreEnd(PVOID a )
+{
+ EC status ;
+ status = (*ems_RestoreEnd)(a) ;
+
+ if ( status ) {
+ CHAR_PTR message = NULL;
+
+ if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
+ (HINSTANCE)JetApi, status, 0, (LPSTR)(&message), 0, NULL ) ) {
+
+ OMEVENT_LogEMSErrorText( TEXT("RestoreEnd()"), message, TEXT(" - ") ) ;
+ LocalFree( message ) ;
+ } else if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, status, 0, (LPSTR)(&message), 0, NULL ) ) {
+
+ OMEVENT_LogEMSErrorText( TEXT("RestoreEnd()"), message, TEXT(" - ") ) ;
+ LocalFree( message ) ;
+ } else {
+ OMEVENT_LogEMSError ( TEXT("RestoreEnd()"), status, TEXT(" - ") ) ;
+ }
+ }
+ return ( status ) ;
+}
+
+EC EMS_RestorePrepare( PVOID a, PVOID b, PVOID *c ) {
+ EC status ;
+ status = (*ems_RestorePrepare)(a,b,c);
+
+ if ( status ) {
+ CHAR_PTR message = NULL;
+
+ if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
+ (HINSTANCE)JetApi, status, 0, (LPSTR)(&message), 0, NULL ) ) {
+
+ OMEVENT_LogEMSErrorText( TEXT("RestorePrepare()"), message, a ) ;
+ LocalFree( message ) ;
+ } else if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, status, 0, (LPSTR)(&message), 0, NULL ) ) {
+
+ OMEVENT_LogEMSErrorText( TEXT("RestorePrepare()"), message, a ) ;
+ LocalFree( message ) ;
+ } else {
+ OMEVENT_LogEMSError ( TEXT("RestorePrepare()"), status, a ) ;
+ }
+ }
+ return ( status ) ;
+}
+
+EC EMS_RestoreRegister( PVOID a, PVOID b, PVOID c, PVOID d, INT e, PVOID f, INT g, INT h ) {
+ EC status ;
+ status = (*ems_RestoreRegister)(a,b,c,d,e,f,g,h) ;
+
+ if ( status ) {
+ CHAR_PTR message = NULL;
+
+ if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
+ (HINSTANCE)JetApi, status, 0, (LPSTR)(&message), 0, NULL ) ) {
+
+ OMEVENT_LogEMSErrorText( TEXT("RestoreRegister()"), message, TEXT(" - ") ) ;
+ LocalFree( message ) ;
+ } else if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, status, 0, (LPSTR)(&message), 0, NULL ) ) {
+
+ OMEVENT_LogEMSErrorText( TEXT("RestoreRegister()"), message, TEXT(" - ") ) ;
+ LocalFree( message ) ;
+ } else {
+ OMEVENT_LogEMSError ( TEXT("RestoreRegister()"), status, TEXT(" - ") ) ;
+ }
+ }
+ return ( status ) ;
+}
+
+EC EMS_RestoreLocations( PVOID a, PVOID b, INT *c ) {
+ EC status ;
+
+ status =(*ems_RestoreLocations)(a,b,c) ;
+
+ if ( status ) {
+ CHAR_PTR message = NULL;
+
+ if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
+ (HINSTANCE)JetApi, status, 0, (LPSTR)(&message), 0, NULL ) ) {
+
+ OMEVENT_LogEMSErrorText( TEXT("RestoreLocations()"), message, TEXT(" - ") ) ;
+ LocalFree( message ) ;
+ } else if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, status, 0, (LPSTR)(&message), 0, NULL ) ) {
+
+ OMEVENT_LogEMSErrorText( TEXT("RestoreLocations()"), message, TEXT(" - ") ) ;
+ LocalFree( message ) ;
+ } else {
+ OMEVENT_LogEMSError ( TEXT("RestoreLocations()"), status, TEXT(" - ") ) ;
+ }
+ }
+
+ return ( status ) ;
+
+}
+
+EC EMS_RestoreComplete( PVOID a, INT b ) {
+ EC status ;
+
+ status =(*ems_RestoreComplete)(a,b) ;
+
+ if ( status ) {
+ CHAR_PTR message = NULL;
+
+ if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
+ (HINSTANCE)JetApi, status, 0, (LPSTR)(&message), 0, NULL ) ) {
+
+ OMEVENT_LogEMSErrorText( TEXT("RestoreComplete()"), message, TEXT(" - ") ) ;
+ LocalFree( message ) ;
+ } else if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, status, 0, (LPSTR)(&message), 0, NULL ) ) {
+
+ OMEVENT_LogEMSErrorText( TEXT("RestoreComplete()"), message, TEXT(" - ") ) ;
+ LocalFree( message ) ;
+ } else {
+ OMEVENT_LogEMSError ( TEXT("RestoreComplete()"), status, TEXT(" - ") ) ;
+ }
+ }
+
+ return ( status ) ;
+
+}
+
+void __RPC_FAR * __RPC_API midl_user_allocate(size_t cb)
+{
+ void * pv;
+
+ pv = GlobalAlloc(GMEM_FIXED, cb);
+ if (!pv)
+ RpcRaiseException(RPC_S_OUT_OF_MEMORY);
+
+ return pv;;
+}
+
+void __RPC_API midl_user_free(void __RPC_FAR * pv)
+{
+ GlobalFree(pv);
+}
+
+
+
+
+BOOLEAN EMS_IsServiceRunning( CHAR_PTR server_name, CHAR_PTR service_name )
+{
+ CHAR machine[256] ;
+ SC_HANDLE mach_hand ;
+ SC_HANDLE serv_hand ;
+ SERVICE_STATUS serv_status ;
+
+ strcpy( machine, TEXT("\\\\") ) ;
+ strcat( machine, server_name ) ;
+
+ // Make sure MAD (The system attendant) is running
+
+ mach_hand = OpenSCManager( machine, NULL, SC_MANAGER_ALL_ACCESS ) ;
+ if ( mach_hand == NULL ) {
+ return FALSE ;
+ }
+
+ serv_hand = OpenService( mach_hand, service_name, SERVICE_QUERY_STATUS ) ;
+ if ( serv_hand == NULL ) {
+ CloseServiceHandle( mach_hand ) ;
+ return FALSE ;
+ }
+
+ if ( !QueryServiceStatus( serv_hand, &serv_status ) ||
+ (serv_status.dwCurrentState!=SERVICE_RUNNING ) ) {
+
+ CloseServiceHandle( serv_hand ) ;
+ CloseServiceHandle( mach_hand ) ;
+ return FALSE ;
+ }
+
+ CloseServiceHandle( serv_hand ) ;
+ CloseServiceHandle( mach_hand ) ;
+
+ return TRUE ;
+}
+
+VOID EMS_StartSAD( CHAR_PTR server_name )
+{
+ CHAR machine[256] ;
+ SC_HANDLE mach_hand ;
+ SC_HANDLE serv_hand ;
+ SERVICE_STATUS serv_status ;
+
+ strcpy( machine, TEXT("\\\\") ) ;
+ strcat( machine, server_name ) ;
+
+ // Make sure MAD (The system attendant) is running
+
+ mach_hand = OpenSCManager( machine, NULL, SC_MANAGER_ALL_ACCESS ) ;
+ if ( mach_hand == NULL ) {
+ return ;
+ }
+
+ serv_hand = OpenService( mach_hand, SERVICE_MAD,
+ SERVICE_START | SERVICE_QUERY_STATUS ) ;
+
+ if ( serv_hand == NULL ) {
+ CloseServiceHandle( mach_hand ) ;
+ return ;
+ }
+
+ if ( !QueryServiceStatus( serv_hand, &serv_status ) ||
+ (serv_status.dwCurrentState!=SERVICE_RUNNING ) ) {
+
+ INT k ;
+
+ if ( !StartService( serv_hand, 0, NULL ) ) {
+ CloseServiceHandle( serv_hand ) ;
+ return ;
+ }
+
+ for ( k = 0; k < 180; k++ ) {
+
+ if ( QueryServiceStatus( serv_hand, &serv_status ) &&
+ (serv_status.dwCurrentState != SERVICE_START_PENDING ) ) {
+
+ break ;
+ }
+ ThreadSwitch() ;
+ Sleep( 1000 ) ;
+ }
+
+ CloseServiceHandle( serv_hand ) ;
+ CloseServiceHandle( mach_hand ) ;
+ return ;
+ }
+
+ CloseServiceHandle( serv_hand ) ;
+
+}
+
diff --git a/private/utils/ntbackup/src/xmkdblk.c b/private/utils/ntbackup/src/xmkdblk.c
new file mode 100644
index 000000000..186460b5b
--- /dev/null
+++ b/private/utils/ntbackup/src/xmkdblk.c
@@ -0,0 +1,126 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: xmkdblk.c
+
+ Description: This file contains functions for the tape format
+ layer to use to create DBLKs. The structure's passed
+ to the create functions includes generic information which
+ is common to most file systems and os specific information.
+ The os specific information was saved when the file system
+ for that os was used to make a backup. The information in
+ the os specific portion could potentially be translated into
+ a useable format for this file system. Each file system defines
+ the format for its os specific information in the header file
+ osinfo.h.
+
+
+ $Log: M:/LOGFILES/XMKDBLK.C_V $
+
+
+**/
+#include <windows.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "stdwcs.h"
+#include "std_err.h"
+#include "stdmath.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "emsdblk.h"
+#include "ems_fs.h"
+#include "tfldefs.h"
+#include "osinfo.h"
+#include "gen_fs.h"
+
+
+/**/
+/**
+
+ Name: EMSCreateFDB
+
+ Description: This function creates a FDB based on the information
+ passed in the GEN_FDB_DATA structure. This function
+ allows the tape format layer to create DBLKs without
+ knowing their structure.
+
+ Modified: 8/24/1989
+
+ Returns: TF_KEEP_GEN_DATA_ONLY
+
+**/
+INT16 EMS_CreateFDB( fsh, dat )
+FSYS_HAND fsh;
+GEN_FDB_DATA_PTR dat;
+{
+ return TF_SKIP_ALL_DATA ;
+}
+
+
+/**/
+/**
+
+ Name: NTFS_CreateDDB
+
+ Description: This function creates a DDB based on the information
+ passed in the GEN_DDB_DATA structure. This function
+ allows the tape format layer to create DBLKs without
+ knowing their structure.
+
+ Modified: 8/24/1989
+
+ Returns: TF_SKIP_ALL_DATA
+
+**/
+INT16 EMS_CreateDDB( fsh, dat )
+FSYS_HAND fsh;
+GEN_DDB_DATA_PTR dat;
+
+{
+ EMS_DBLK_PTR ddblk;
+ INT16 ret_val ;
+ DBLK_PTR dblk ;
+
+ dat->std_data.dblk->blk_type = DDB_ID ;
+ dat->std_data.dblk->com.blkid = dat->std_data.blkid;
+ dat->std_data.dblk->com.f_d.did = dat->std_data.did ;
+ dat->std_data.dblk->com.ba.lba = dat->std_data.lba ;
+ dat->std_data.dblk->com.os_id = dat->std_data.os_id ;
+ dat->std_data.dblk->com.os_ver = dat->std_data.os_ver ;
+
+ dat->std_data.dblk->com.continue_obj = dat->std_data.continue_obj ;
+ dat->std_data.dblk->com.tape_seq_num = dat->std_data.tape_seq_num ;
+
+ ddblk = (EMS_DBLK_PTR)dat->std_data.dblk;
+ dblk = dat->std_data.dblk;
+ dblk->com.string_type = dat->std_data.string_type ;
+
+ ddblk->blk_type = DDB_ID;
+
+ ddblk->os_info_complete = TRUE ;
+
+ if ( dat->std_data.os_id == FS_EMS_MDB_ID ) {
+ ddblk->ems_type = EMS_MDB ;
+ } else if ( dat->std_data.os_id == FS_EMS_DSA_ID ) {
+ ddblk->ems_type = EMS_DSA ;
+ }
+
+ ret_val = FS_SetupOSPathOrNameInDBLK( fsh,
+ dblk,
+ (BYTE_PTR)dat->path_name,
+ dat->path_size ) ;
+
+ switch ( dat->std_data.os_id ) {
+
+ case FS_EMS_DSA_ID:
+ case FS_EMS_MDB_ID:
+ break ;
+ }
+
+
+ return TF_KEEP_ALL_DATA ;
+
+}
+
diff --git a/private/utils/ntbackup/src/xmoddblk.c b/private/utils/ntbackup/src/xmoddblk.c
new file mode 100644
index 000000000..ab191ec1d
--- /dev/null
+++ b/private/utils/ntbackup/src/xmoddblk.c
@@ -0,0 +1,618 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tmoddblk.c
+
+ Description: This file contains code to get/set generic information
+ from/to a EMS FDB or DDB.
+
+
+ $Log: M:/LOGFILES/TMODDBLK.C_V $
+
+
+**/
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+
+#include "stdtypes.h"
+#include "stdwcs.h"
+#include "stdmath.h"
+#include "tfldefs.h"
+#include "datetime.h"
+#include "fsys.h"
+#include "emsdblk.h"
+#include "ems_fs.h"
+#include "fsys_err.h"
+#include "osinfo.h"
+
+typedef struct {
+ UINT32 maynID;
+ UINT32 msoftID;
+} ID_TRANS_TABLE, ID_TRANS_TABLE_PTR;
+
+/**/
+/**
+
+ Name: EMS_ModFnameFDB()
+
+ Description: ASSERT!!! FDB are not supported!!!!
+
+ Modified: 1/14/1992 10:28:22
+
+ Returns: Error codes:
+ FAILURE
+
+**/
+INT16 EMS_ModFnameFDB(
+FSYS_HAND fsh , /* I - File system handle */
+BOOLEAN set_it , /* I - TRUE if setting file name, FALSE if getting */
+DBLK_PTR dblk , /* I - Descriptor block to get file name from */
+CHAR_PTR buf , /*I/O- file name to read (or to write) */
+INT16 *size ) /*I/O- byte size buffer on entry and exit */
+{
+ fsh ;
+ set_it;
+ dblk ;
+ buf ;
+ (void)*size ;
+
+ msassert( "EMS_ModFnameMDB should not be called" == NULL ) ;
+
+ return FAILURE ;
+}
+/**/
+/**
+
+ Name: EMS_ModPathDDB()
+
+ Description: This function gets/sets the path in an DDB
+
+ Modified: 1/14/1992 10:30:16
+
+ Returns: Error Codes:
+ FS_BUFFER_TO_SMALL
+ FS_BAD_INPUT_DATA
+ SUCCESS
+
+ Notes:
+
+ See also: EMS_ModFnameFDB()
+
+**/
+INT16 EMS_ModPathDDB(
+FSYS_HAND fsh , /* I - File system handle */
+BOOLEAN set_it , /* I - TRUE if setting path, FALSE if getting */
+DBLK_PTR dblk , /* I - Descriptor block to get path from */
+CHAR_PTR buf , /*I/O- path to read (or to write) */
+INT16 *size ) /*I/O- byte size of buffer on entry and exit */
+{
+ INT16 ret_val = SUCCESS ;
+ CHAR_PTR pos ;
+ EMS_DBLK_PTR ddblk ;
+ GENERIC_DLE_PTR dle = fsh->attached_dle ;
+
+ ddblk = (EMS_DBLK_PTR) dblk ;
+
+ if ( set_it ) {
+
+ msassert( dle->info.xserv->type == EMS_BRICKED ) ;
+ return SUCCESS ;
+
+ } else { /* get path */
+
+ if ( ( dle->info.xserv->type == EMS_MDB ) ||
+ ( dle->info.xserv->type == EMS_DSA ) ) {
+
+ strcpy( buf, dblk->com.os_name->name ) ;
+
+ } else { //bricked
+
+
+ }
+ }
+ return ret_val ;
+}
+
+/**/
+/**
+
+ Name: EMS_GetOSFnameFDB()
+
+ Description: Assert!! there are no FDBs
+
+ Modified: 1/14/1992 11:8:26
+
+ Returns: Error codes
+ FS_BUFFER_TO_SMALL
+ SUCCESS
+
+ Notes:
+
+ See also: EMS_ModFnameFDB()
+
+**/
+INT16 EMS_GetOSFnameFDB( dblk, buf )
+DBLK_PTR dblk ; /* I - Descriptor block to get path from */
+CHAR_PTR buf ; /* O - buffer to place path in */
+{
+
+ (void)dblk;
+ (void)buf;
+
+ msassert( "EMS_GetOSFnameFDB should not be called" == NULL ) ;
+ return FAILURE ;
+}
+
+/**/
+/**
+
+ Name: EMS_GetOSPathDDB()
+
+ Description: This function copies the OS path in the specified
+ DDB to the specified buffer. The OS path is the same as
+ the "normal" path during backup. During restore, the
+ OS path name is the name stored on tape.
+
+ Modified: 1/14/1992 11:9:5
+
+ Returns: Error codes:
+ FS_BUFFER_TO_SMALL
+ SUCCESS
+
+ Notes:
+
+ See also: EMS_GetOSFnameFDB()
+
+**/
+INT16 EMS_GetOSPathDDB( fsh, dblk, buf )
+FSYS_HAND fsh ; /* I - File System handle */
+DBLK_PTR dblk ; /* I - Descriptor block to get path from */
+CHAR_PTR buf ; /*I/O- path to read (or to write) */
+{
+ CHAR_PTR pos ;
+ CHAR_PTR os_name ;
+ INT16 os_name_size ;
+ EMS_DBLK_PTR ddblk ;
+
+ (VOID)fsh ;
+
+ ddblk = (EMS_DBLK_PTR) dblk;
+
+ if ( dblk->com.os_name != NULL )
+ {
+ os_name = dblk->com.os_name->name ;
+ os_name_size = dblk->com.os_name->name_size ;
+ }
+ else
+ {
+ os_name = ddblk->full_name_ptr->name ;
+ os_name_size = ddblk->full_name_ptr->name_size ;
+ }
+
+
+ memcpy( buf, os_name, os_name_size ) ;
+
+ return SUCCESS ;
+}
+/**/
+/**
+
+ Name: EMS_GetFileVerFDB()
+
+ Description: Since DOS does not support file versions, this
+ function simply sets the version number to 0.
+
+ Modified: 1/14/1992 11:9:39
+
+ Returns: SUCCESS
+
+ Notes:
+
+**/
+INT16 EMS_GetFileVerFDB( dblk, version )
+DBLK_PTR dblk ;
+UINT32 *version ;
+{
+ dblk ;
+ *version = 0 ;
+ msassert( "EMS_GetOSFnameFDB should not be called" == NULL ) ;
+ return SUCCESS ;
+}
+/**/
+/**
+
+ Name: EMS_GetCdateDBLK()
+
+ Description: Pretend Creation date is same as Modify date
+
+ Modified: 1/14/1992 11:10:9
+
+ Returns: SUCCESS
+
+ Notes:
+
+ See also: EMS_ModBdate(), EMS_GetMdate(), EMS_ModAdate()
+
+**/
+INT16 EMS_GetCdateDBLK( dblk, buf )
+DBLK_PTR dblk ; /* I - Descriptor block to get creation date */
+DATE_TIME_PTR buf ; /*I/O- createion date to read (or to write) */
+{
+ (void)dblk;
+
+ buf->date_valid = FALSE;
+
+ return SUCCESS ;
+}
+
+/**/
+/**
+
+ Name: EMS_GetMdateDBLK()
+
+ Description: This function copies the modified date/time into (or out of)
+ the provided buffer.
+
+ Modified: 1/14/1992 11:20:6
+
+ Returns: SUCCESS
+
+ Notes:
+
+ See also: EMS_GetCdate(), EMS_ModBdate(), EMS_ModAdate()
+
+**/
+INT16 EMS_GetMdateDBLK( dblk, buf )
+DBLK_PTR dblk ; /* I - Descriptor block to get creation date */
+DATE_TIME_PTR buf ; /* O - modify date to write */
+{
+ (void)dblk;
+
+ buf->date_valid = FALSE;
+
+ return SUCCESS ;
+}
+
+
+/**/
+/**
+
+ Name: EMS_ModBdateDBLK()
+
+ Description: This function copies the backup date/time into (or out of)
+ the provided buffer.
+
+ Modified: 8/15/1989
+
+ Returns: SUCCESS
+
+ Notes:
+
+ See also: $/SEE( EMS_GetCdate(), EMS_GetMdate(), EMS_ModAdate()
+
+**/
+INT16 EMS_ModBdateDBLK(
+BOOLEAN set_it , /* I - TRUE if setting creation date, FALSE if getting */
+DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+DATE_TIME_PTR buf ) /*I/O- createion date to read (or to write) */
+{
+ dblk;
+
+ if ( !set_it ) {
+
+ buf->date_valid = FALSE;
+ }
+
+ return SUCCESS ;
+}
+/**/
+/**
+
+ Name: EMS_ModAdateDBLK()
+
+ Description: This function copies the access date/time into (or out ot )
+ the provided buffer.
+
+ Modified: 1/14/1992 11:21:53
+
+ Returns: SUCCESS
+
+ See also: EMS_GetCdate(), EMS_GetMdate(), EMS_ModBdate()
+
+**/
+INT16 EMS_ModAdateDBLK(
+BOOLEAN set_it , /* I - TRUE if setting creation date, FALSE if getting */
+DBLK_PTR dblk , /* I - Descriptor block to get creation date */
+DATE_TIME_PTR buf ) /*I/O- createion date to read (or to write) */
+{
+ dblk;
+
+ if ( !set_it ) {
+
+ buf->date_valid = FALSE;
+ }
+
+ return SUCCESS ;
+}
+/**/
+/**
+
+ Name: EMS_GetDisplaySizeDBLK()
+
+ Description: This function returns the generic size of a DBLK.
+ For a file, this is the file size. For a directory this is
+ allways 0.
+
+ Modified: 1/14/1992 12:15:33
+
+ Returns: Number of generic data bytes.
+
+ Notes:
+
+**/
+UINT64 EMS_GetDisplaySizeDBLK( fsh, dblk )
+FSYS_HAND fsh ; /* I - File system handle */
+DBLK_PTR dblk ; /* I - Descriptor block to get generic data size for */
+{
+ EMS_DBLK_PTR ddblk = (EMS_DBLK_PTR) dblk;
+
+ (void)fsh ;
+
+ return ddblk->display_size;
+}
+
+/**/
+/**
+
+ Name: EMS_ModAttribDBLK()
+
+ Description: This function copies the generic attributes into
+ (or out of) the specified DBLK.
+
+ Modified: 1/14/1992 12:15:59
+
+ Returns: SUCCESS
+
+ Notes: This only supports FDBs and DDBs. This should be called
+ by the FS_... function NOT by a macro.
+
+**/
+INT16 EMS_ModAttribDBLK(
+BOOLEAN set_it , /* I - TRUE if we are seting data */
+DBLK_PTR dblk , /*I/O- dblk to read or write data from */
+UINT32 *attrib ) /*I/O- attributre read or written */
+{
+ if ( set_it ) {
+ return SUCCESS;
+ }
+ else { /* get data */
+ *attrib = 0 ;
+ }
+ return SUCCESS ;
+}
+/**/
+/**
+
+ Name: EMS_GetObjTypeDBLK()
+
+ Description: This function looks at the os_id in the provided DBLK
+ and returns the type of the object.
+
+ Modified: 1/14/1992 12:16:32
+
+ Returns: SUCCESS
+
+ Notes: If the os_id is unknown then type is UNKNOWN_OBJECT
+
+**/
+/* begin declaration */
+INT16 EMS_GetObjTypeDBLK( dblk, type )
+DBLK_PTR dblk ; /* I - Descriptor block to get type of */
+OBJECT_TYPE *type ; /* O - type of DBLK */
+{
+ msassert( type != NULL );
+
+ dblk ;
+ *type = DOS_OBJECT ;
+
+ return( SUCCESS ) ;
+}
+
+
+/**/
+/**
+
+ Name: EMS_GetOS_InfoDBLK()
+
+ Description: This function returns the OS info for the DOS
+ file system
+
+ Modified: 1/14/1992 12:16:55
+
+ Returns: Error Code
+ FS_BUFFER_TO_SMALL
+ SUCCESS
+
+ Notes: This file system has no OS info.
+
+**/
+/* begin declaration */
+INT16 EMS_GetOS_InfoDBLK( dblk, os_info, size )
+DBLK_PTR dblk ; /* I - DBLK to get the info from */
+BYTE_PTR os_info ; /* O - Buffer to place data */
+INT16 *size ; /*I/O- Buffer size / data length */
+{
+ (void)os_info;
+ (void)dblk ;
+ *size = 0 ;
+
+ return SUCCESS ;
+}
+
+/**/
+/**
+
+ Name: EMS_GetActualSizeDBLK
+
+ Description: This function returns the actual size of a DBLK.
+
+ Modified: 1/14/1992 12:17:33
+
+ Returns: The number of bytes
+
+ Notes:
+
+**/
+/* begin declaration */
+INT16 EMS_GetActualSizeDBLK( fsh, dblk )
+FSYS_HAND fsh ;
+DBLK_PTR dblk ;
+{
+
+ EMS_DBLK *ddb ;
+ INT16 size ;
+
+ fsh ;
+
+ ddb = (EMS_DBLK_PTR)dblk ;
+ size = sizeof( EMS_DBLK ) ;
+
+ return size ;
+}
+
+/**/
+/**
+
+ Name: EMS_SetOwnerId()
+
+ Description: does nothing
+
+ Modified: 1/14/1992 12:18:25
+
+ Returns: none
+
+ Notes:
+
+**/
+VOID EMS_SetOwnerId( fsh, dblk, id )
+FSYS_HAND fsh ; /* I - File system handle */
+DBLK_PTR dblk ; /* O - DBLK to modify */
+UINT32 id ; /* I - value to set it to */
+{
+ fsh ;
+ dblk ;
+ id ;
+}
+
+/**/
+/**
+
+ Name: EMS_ProcessDDB()
+
+ Description: This function allways returns FALSE to
+ specify that directories should not be restored
+ if there are no file to restore into the directory.
+
+ Modified: 10/23/1989
+
+ Returns: FALSE
+
+ Notes:
+
+**/
+/* begin declaration */
+BOOLEAN EMS_ProcessDDB( fsh, ddb )
+FSYS_HAND fsh; /* I - file system handle */
+DBLK_PTR ddb; /* I - Directory information */
+{
+ fsh;
+ ddb;
+
+ return TRUE ;
+}
+
+
+/**/
+/**
+
+ Name: EMS_EnumSpecialFiles()
+
+ Description: This function enumerates the special files. For NT
+ the application asks if registry files are to be included
+ before the restore process starts... Thus this function has
+ no purpose.
+
+ Modified: 5/21/1992 19:28:51
+
+ Returns: FS_NO_MORE
+
+ Notes: Starting index must be 0
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 EMS_EnumSpecFiles( dle, index, path, psize, fname )
+GENERIC_DLE_PTR dle ;
+UINT16 *index ;
+CHAR_PTR *path ;
+INT16 *psize ;
+CHAR_PTR *fname ;
+{
+ (void)index;
+ (void)path;
+ (void)psize;
+ (void)fname ;
+
+ return FS_NO_MORE ;
+}
+/**/
+/**
+
+ Name: EMS_SpecExcludeObj
+
+ Description: This function tells the caller what kind of file a file is.
+ The possibilities are:
+ FS_NORMAL_FILE
+ FS_SPECIAL_DIR
+ FS_SPECIAL_FILE
+ FS_EXCLUDE_FILE
+
+ This function is used to exclude / include the registry. The
+ assumptions are that the nt_system directory contains the following
+ files:
+ Active registry files
+ Inactive registry files
+ Useless .LOG and .ALT files
+ Event logger data files.
+
+
+ Modified: 1/10/1990
+
+ Returns: FS_NORMAL_FILE because this file system has no special
+ files.
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 EMS_SpecExcludeObj(
+FSYS_HAND fsh, /* I - File system handle */
+DBLK_PTR ddb, /* I - Descriptor block of ddb */
+DBLK_PTR fdb ) /* I - Descriptor block of fdb */
+{
+ (void)fsh;
+ (void)ddb;
+ (void)fdb;
+ return FS_NORMAL_FILE ;
+}
diff --git a/private/utils/ntbackup/src/xname.c b/private/utils/ntbackup/src/xname.c
new file mode 100644
index 000000000..2778fac9d
--- /dev/null
+++ b/private/utils/ntbackup/src/xname.c
@@ -0,0 +1,160 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tname.c
+
+
+ Description: This file contains code to get the device name and
+ volume name for the given DLE.
+
+
+**/
+#include <windows.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "stdtypes.h"
+#include "msassert.h"
+#include "fsys.h"
+#include "emsdblk.h"
+#include "ems_fs.h"
+
+/**/
+/**
+
+ Name: EMS_DeviceDispName()
+
+ Description: This function gets the displayable device name for
+ a DLE. This name is displayed for drive select.
+
+ Modified: 9/13/1989
+
+ Returns: SUCCESS
+
+ Notes:
+
+ See also: $/SEE( )$
+
+ Declaration:
+
+**/
+INT16 EMS_DeviceDispName( dle, dev_name, size, type )
+GENERIC_DLE_PTR dle;
+CHAR_PTR dev_name;
+INT16 size ;
+INT16 type ;
+{
+ CHAR_PTR p ;
+ (VOID)type;
+
+ if ( size < (INT16)strsize(dle->device_name) ) {
+ return FS_BUFFER_TO_SMALL ;
+ }
+
+
+ strcpy( dev_name, dle->device_name ) ;
+
+ if ( ( dle->os_id == FS_EMS_MDB_ID ) ||
+ ( dle->os_id == FS_EMS_DSA_ID ) ) {
+
+ p = strchr( dle->device_name, TEXT('\\') ) ;
+ if ( p ) {
+ strcpy( dev_name, p+1 ) ;
+ }
+ }
+
+ return SUCCESS ;
+}
+/**/
+/**
+
+ Name: EMS_GetVolName()
+
+ Description: This function coppies the volume name
+ of the specified drive to the buffer provided.
+
+ Modified: 12/4/1991 9:45:49
+
+**/
+VOID EMS_GetVolName( dle, buffer )
+GENERIC_DLE_PTR dle;
+CHAR_PTR buffer ;
+{
+
+ if (dle->parent ) {
+ EMS_GetVolName( dle->parent, buffer ) ;
+ strcat( buffer, TEXT("\\") ) ;
+
+ EMS_DeviceDispName(dle, buffer + strlen(buffer), 256, 1) ;
+
+ } else {
+ strcpy( buffer, dle->device_name ) ;
+ }
+
+}
+
+/**/
+/**
+
+ Name: EMS_SizeofVolName()
+
+ Description: This function returns the size of the volume name
+ which will be created by DLE_GetVolName()
+
+ Modified: 12/4/1991 11:14:25
+
+ Returns: size of string including \0;
+
+**/
+INT16 EMS_SizeofVolName( dle )
+GENERIC_DLE_PTR dle ;
+{
+ INT16 size ;
+
+
+ if (dle->parent ) {
+ size = EMS_SizeofVolName( dle->parent ) ;
+ return ( strsize( dle->device_name ) + 1 + size );
+ } else {
+ return ( strsize( dle->device_name ) );
+ }
+
+}
+
+/**/
+/**
+
+ Name: EMS_InitMakeData()
+
+ Description: This function is used to initialize the parameter block
+ which is passed to CreateDBLK.
+
+ Modified: 12/4/1991 14:57:3
+
+ Returns: NONE
+
+ Notes:
+
+**/
+VOID EMS_InitMakeData(
+FSYS_HAND fsh,
+INT16 blk_type,
+CREATE_DBLK_PTR data ) {
+
+ switch ( fsh->attached_dle->info.xserv->type ) {
+
+ case EMS_MDB:
+ data->v.std_data.os_id = FS_EMS_MDB_ID ;
+ data->v.std_data.os_ver = FS_EMS_MDB_VER ;
+ break ;
+
+ case EMS_DSA:
+ data->v.std_data.os_id = FS_EMS_DSA_ID ;
+ data->v.std_data.os_ver = FS_EMS_DSA_VER ;
+ break ;
+
+ }
+
+ return ;
+}
diff --git a/private/utils/ntbackup/src/xopen.c b/private/utils/ntbackup/src/xopen.c
new file mode 100644
index 000000000..4242533f9
--- /dev/null
+++ b/private/utils/ntbackup/src/xopen.c
@@ -0,0 +1,661 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: xopen.c
+
+ Description: This file contains code to open files
+ and directories.
+
+ $Log: N:/LOGFILES/XOPEN.C_V $
+
+
+**/
+#include <windows.h>
+#include <string.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <wtypes.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "std_err.h"
+
+#include "omevent.h"
+
+#include "ems_jet.h"
+
+#include "beconfig.h"
+#include "msassert.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "fsys_err.h"
+#include "emsdblk.h"
+#include "ems_fs.h"
+#include "tfldefs.h"
+
+#include "jet.h"
+#include "jetbcli.h"
+#include "edbmsg.h"
+
+/* Maximum number of attempts to create a temporary file */
+
+static INT16 EMS_OpenDSAorMDB( FSYS_HAND fsh, FILE_HAND hand, EMS_DBLK_PTR fdb, INT16 MODE );
+static INT16 EMS_LoadPathList( FSYS_HAND fsh, FILE_HAND hand ) ;
+static INT16 EMS_OpenBricked( FSYS_HAND fsh, FILE_HAND hand, EMS_DBLK_PTR fdb, INT16 MODE );
+
+static INT16 EMS_WipeLogFiles( FSYS_HAND fsh, CHAR_PTR log_dir ) ;
+
+/**/
+
+/**
+
+ Name: EMS_OpenObj()
+
+ Description: This function opens files or directories.
+
+ Modified: 7/28/1989
+
+ Returns: Error Codes
+ OUT_OF_MEMORY
+ FS_NOT_FOUND
+ FS_ACCESS_DENIED
+ FS_IN_USE_ERROR
+ FS_OPENED_INUSE
+ SUCCESS
+
+ Notes: Valid modes are : READ, WRITE, & VERIFY
+ If a VCB is passed in then this function returns SUCCESS
+
+ See also: $/SEE( EMS_OpenFile() )$
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 EMS_OpenObj( fsh, hand, dblk, mode )
+FSYS_HAND fsh ; /* I - file system that the file is opened on */
+FILE_HAND *hand ; /* O - allocated handle */
+DBLK_PTR dblk; /*I/O- describes the file to be opened */
+OPEN_MODE mode ; /* I - open mode */
+{
+ GENERIC_DLE_PTR dle = fsh->attached_dle;
+ INT16 hand_size ;
+ INT16 ret_val = SUCCESS;
+ EMS_DBLK_PTR ddblk = (EMS_DBLK_PTR) dblk;
+ EMS_FSYS_RESERVED_PTR resPtr = fsh->reserved.ptr;
+ EMS_OBJ_HAND_PTR ems_hand = NULL ;
+
+ msassert( dblk != NULL );
+ msassert( fsh->attached_dle != NULL );
+ msassert( dblk->blk_type == DDB_ID ) ;
+
+ if ( fsh->hand_in_use ) {
+ hand_size = sizeof( FILE_HAND_STRUCT ) + sizeof ( EMS_OBJ_HAND );
+ *hand = (FILE_HAND) calloc( 1, hand_size ) ;
+ if ( *hand == NULL ) {
+ ret_val = OUT_OF_MEMORY ;
+ }
+
+ } else {
+ *hand = fsh->file_hand ;
+ fsh->hand_in_use = TRUE ;
+ }
+
+ (*hand)->obj_hand.ptr = (VOID_PTR)((*hand) + 1) ;
+ memset( (*hand)->obj_hand.ptr, 0, sizeof( EMS_OBJ_HAND ) ) ;
+
+
+ if ( ret_val == SUCCESS ) {
+ EMS_FSYS_RESERVED_PTR res = fsh->reserved.ptr;
+
+ ems_hand = (*hand)->obj_hand.ptr;
+
+ (*hand)->fsh = fsh ;
+ (*hand)->mode = (INT16)mode ;
+ (*hand)->dblk = dblk ;
+
+ ems_hand->nameComplete = FALSE;
+ ems_hand->needPathList = TRUE;
+ ems_hand->needStreamHeader = TRUE;
+ ems_hand->name_list = NULL ;
+ ems_hand->name_list_offset = 0 ;
+
+ switch( dle->info.xserv->type ){
+
+ case EMS_MDB :
+ case EMS_DSA :
+
+ ret_val = EMS_OpenDSAorMDB( fsh, *hand, ddblk, (INT16)mode ) ;
+ ddblk->backup_completed = FALSE ;
+
+ if ( !ret_val && (mode == FS_WRITE) ) {
+ res->map_size = 0 ;
+ res->low_log = 0x7fffffff ;
+ res->high_log = 0 ;
+
+ *res->jet_rstmap = TEXT('\0') ;
+
+ }
+ break ;
+
+ case EMS_BRICK :
+
+ ret_val = FS_SavePath( fsh, (UINT8_PTR)TEXT("\\"), 2 * sizeof(CHAR) ) ;
+ if ( ret_val == SUCCESS ) {
+ ret_val = FS_AppendPath( fsh,
+ (UINT8_PTR)ddblk->full_name_ptr->name,
+ (INT16)(strsize( ddblk->full_name_ptr->name )) ) ;
+ }
+
+ if ( ret_val == SUCCESS ) {
+ ret_val = EMS_OpenBricked( fsh, *hand, ddblk, (INT16)mode ) ;
+ }
+ break ;
+
+ }
+ }
+
+ if ( ems_hand ) {
+ ems_hand->open_ret_val = ret_val ;
+ return SUCCESS ;
+ }
+
+ if( ( ret_val != SUCCESS ) && ( ret_val != FS_OPENED_INUSE ) ) {
+ if( fsh->file_hand == *hand ) {
+ fsh->hand_in_use = FALSE ;
+ memset( *hand, 0, sizeof( FILE_HAND_STRUCT ) ) ;
+ } else {
+ free( *hand ) ;
+ }
+ }
+
+ return ret_val ;
+}
+/**/
+/**
+
+ Name: EMS_OpenDSAorMDB()
+
+ Description: This function calls RestorePrepare in order to load the
+ path list and calls BackupPrepare in order the the
+ attached database list.
+
+ Modified: 7/28/1989
+
+ Returns: Error Codes.
+ FS_NOT_FOUND
+ FS_ACCESS_DENIED
+ FS_IN_USE_ERROR
+ FS_OPENED_INUSE
+ SUCCESS
+
+ Declaration:
+
+**/
+/* begin declaration */
+static INT16 EMS_OpenDSAorMDB(
+FSYS_HAND fsh , /* I - file system that the file is opened on */
+FILE_HAND hand , /* O - allocated handle */
+EMS_DBLK_PTR ddblk , /*I/O- describes the file to be opened */
+INT16 mode ) /* I - open mode */
+{
+ GENERIC_DLE_PTR dle = fsh->attached_dle ;
+ INT16 ret_val = SUCCESS;
+ EMS_OBJ_HAND_PTR ems_hand = ((EMS_OBJ_HAND_PTR)hand->obj_hand.ptr) ;
+ INT status = SUCCESS;
+ CHAR_PTR db_name;
+ INT buf_size ;
+ EMS_FSYS_RESERVED_PTR resPtr = fsh->reserved.ptr;
+ INT grebit = 0;
+ INT backup_type = BACKUP_TYPE_FULL ;
+
+
+ hand->opened_in_use = FALSE ;
+ hand->fsh = fsh ;
+ hand->size = 0 ;
+ hand->obj_pos = 0 ;
+
+ if ( dle->info.xserv->type == EMS_MDB ) {
+ db_name = TEXT("Exchange MDB Database") ;
+ } else{
+ db_name = TEXT("Exchange DS Database") ;
+ }
+
+ if ( mode == FS_WRITE ) {
+// moved this to create.
+// status = EMS_RestorePrepare( dle->parent->device_name,
+// db_name,
+// &resPtr->restore_context ) ;
+
+ } else {
+ resPtr->restore_context = NULL ;
+ }
+
+ if ( !status && ( mode == FS_READ ) ) {
+
+ if ( BEC_GetModifiedOnlyFlag( fsh->cfg ) ) {
+ grebit = JET_bitBackupIncremental ;
+ backup_type = BACKUP_TYPE_LOGS_ONLY ;
+ }
+ status = EMS_BackupPrepare( fsh->attached_dle->parent->device_name,
+ db_name,
+ grebit,
+ backup_type,
+ &(ems_hand->context) ) ;
+
+ }
+
+ if ( status ) {
+ ems_hand->context = NULL;
+ ret_val = EMS_ConvertJetError( status ) ;
+ if ( status == hrInvalidParameter ) {
+ ret_val = FS_EMS_NO_LOG_BKUP ;
+ }
+
+ } else {
+
+ if ( mode == FS_WRITE ) {
+ ret_val = EMS_LoadPathList( fsh, hand ) ;
+ }
+
+ if ( ( ret_val == SUCCESS ) && (mode == FS_WRITE ) &&
+ ( fsh->attached_dle->info.xserv->type == EMS_MDB ) ) {
+
+ if ( ( BEC_GetEmsPubPri( fsh->cfg) & BEC_EMS_PUBLIC ) &&
+ (*resPtr->paths.mdb.FnamePublic == TEXT('\0') ) ) {
+
+ ret_val = FS_EMS_NO_PUBLIC ;
+ }
+ if ( ( BEC_GetEmsPubPri( fsh->cfg) & BEC_EMS_PRIVATE ) &&
+ (*resPtr->paths.mdb.FnamePrivate == TEXT('\0') ) ) {
+
+ ret_val = FS_EMS_NO_PRIVATE ;
+ }
+ }
+ }
+
+ if ( !ret_val ) {
+
+ if ( mode == FS_READ ) {
+
+ if ( ( fsh->attached_dle->parent == NULL ) ||
+ ( fsh->attached_dle->parent->parent == NULL ) ) {
+
+ return FS_COMM_FAILURE ;
+ }
+
+ if ( BEC_GetModifiedOnlyFlag( fsh->cfg ) ) {
+ ret_val = EMS_LoadNameList( fsh, hand, EMS_DOING_LOGS ) ;
+ } else {
+ ret_val = EMS_LoadNameList( fsh, hand, EMS_DOING_DB ) ;
+ }
+
+ } else if ( (mode == FS_WRITE) && BEC_GetEmsWipeClean( fsh->cfg ) ) {
+
+ if ( dle->info.xserv->type == EMS_MDB ){
+ EMS_WipeLogFiles( fsh, resPtr->paths.mdb.LogDir ) ;
+ } else {
+ EMS_WipeLogFiles( fsh, resPtr->paths.dsa.LogDir ) ;
+ }
+ }
+ } else {
+ if ( resPtr->restore_context ) {
+ EMS_RestoreEnd( resPtr->restore_context ) ;
+ }
+ }
+
+ return ret_val ;
+}
+
+/**/
+/**
+
+ Name: EMS_OpenBricked()
+
+ Description: This function opens a directory for for processing.
+ If this is a special Object we will open the special file.
+ Otherwise we will process any long path followed by any
+ data associated with the object.
+
+ Modified: 5/21/1992 17:54:42
+
+ Returns: Error Codes.
+ FS_NOT_FOUND
+ SUCCESS
+
+ Declaration:
+
+**/
+/* begin declaration */
+static INT16 EMS_OpenBricked(
+FSYS_HAND fsh , /* I - file system that the file is opened on */
+FILE_HAND hand , /* O - allocated handle */
+EMS_DBLK_PTR ddblk, /*I/O- describes the file to be opened */
+INT16 mode ) /* I - open mode */
+{
+ return FS_ACCESS_DENIED ;
+}
+
+
+INT16 EMS_LoadNameList( FSYS_HAND fsh, FILE_HAND hand, INT list_type )
+{
+ GENERIC_DLE_PTR dle = fsh->attached_dle ;
+ INT16 ret_val = SUCCESS;
+ EMS_OBJ_HAND_PTR ems_hand = ((EMS_OBJ_HAND_PTR)hand->obj_hand.ptr) ;
+ INT status = SUCCESS;
+ CHAR *db_name;
+ INT buf_size ;
+ CHAR *buffer ;
+ INT i ;
+
+ if ( ems_hand->name_list != NULL ) {
+ free( ems_hand->name_list ) ;
+ ems_hand->name_list = NULL ;
+ }
+
+ buffer = NULL ;
+
+ if ( !status && (list_type == EMS_DOING_DB ) ) {
+
+ status = EMS_BackupGetAttachmentInfo( ems_hand->context,
+ &buffer,
+ &buf_size ) ;
+
+ } else if ( !status && (list_type == EMS_DOING_LOGS ) ) {
+
+ status = EMS_GetBackupLogs( ems_hand->context,
+ &buffer,
+ &buf_size ) ;
+
+ }
+
+
+ if ( !status ) {
+ INT i ;
+ INT num_files = 0 ;
+
+ ems_hand->name_list = malloc( buf_size ) ;
+
+ if ( ems_hand->name_list == NULL ) {
+
+ // lets do some major clean up...
+ EMS_BackupFree( buffer ) ;
+ if ( list_type == EMS_DOING_DB ) {
+ EMS_BackupClose( ems_hand->context ) ;
+ }
+
+ return OUT_OF_MEMORY ;
+ }
+
+ for ( i=0; i< (INT)(buf_size/sizeof(CHAR) -1); i++ ) {
+ ems_hand->name_list[i] = buffer[i] ;
+ if ( buffer[i] == TEXT('\0') ) {
+ num_files ++ ;
+ }
+ }
+
+ if ( list_type == EMS_DOING_DB ) {
+// if ( dle->info.xserv->type == EMS_MDB ) {
+// if ( num_files != 3 ) {
+//
+// OMEVENT_LogEMSToFewDbError ( num_files, 3 ) ;
+//
+// return FS_COMM_FAILURE ;
+// }
+// } else {
+// if ( num_files != 2 ) {
+// OMEVENT_LogEMSToFewDbError ( num_files, 2 ) ;
+// return FS_COMM_FAILURE ;
+// }
+// }
+ }
+
+ ems_hand->db_or_log = list_type ;
+ ems_hand->name_list_offset = 0 ;
+ EMS_BackupFree( buffer ) ;
+ } else {
+ BEC_SetSkipOpenFiles( fsh->cfg, BEC_SKIP_OPEN_FILES ) ;
+ }
+
+ ret_val = EMS_ConvertJetError( status ) ;
+
+ if ( ret_val == RPC_S_SERVER_TOO_BUSY ) {
+ ret_val = FS_COMM_FAILURE ;
+ }
+
+ return ret_val ;
+}
+
+
+INT16 EMS_ConvertJetError( INT status )
+{
+ INT16 ret_val ;
+
+ switch( status ) {
+
+ case SUCCESS :
+ ret_val = SUCCESS ;
+ break ;
+
+ case hrBFInUse:
+ case hrRestoreInProgress:
+ case hrBackupInProgress:
+ ret_val = FS_IN_USE_ERROR ;
+ break ;
+
+ case hrCouldNotConnect:
+ ret_val = FS_BAD_ATTACH_TO_SERVER ;
+ break ;
+
+ case hrTooManyIO:
+ ret_val = FS_COMM_FAILURE ;
+ break ;
+
+ case hrFileAccessDenied:
+ case hrAccessDenied:
+ ret_val = FS_ACCESS_DENIED;
+ break ;
+ case RPC_S_SERVER_TOO_BUSY :
+ ret_val = RPC_S_SERVER_TOO_BUSY ;
+ break ;
+ default:
+ ret_val = FS_COMM_FAILURE ;
+ break ;
+ }
+
+ return ret_val ;
+}
+
+
+
+
+static INT16 EMS_WipeLogFiles( FSYS_HAND fsh, CHAR_PTR log_dir )
+{
+ WIN32_FIND_DATA find_data ;
+ HANDLE scan_hand;
+ INT16 ret_val = SUCCESS ;
+ CHAR path[256] ;
+ CHAR_PTR file ;
+
+ strcpy(path, log_dir ) ;
+
+ strcat( path, TEXT("*") ) ;
+
+ scan_hand = FindFirstFile( path, &find_data ) ;
+
+ while (scan_hand != INVALID_HANDLE_VALUE ) {
+
+ file = EMS_BuildMungedName( fsh, log_dir, find_data.cFileName ) ;
+
+ if ( !FindNextFile( scan_hand, &find_data ) ) {
+ FindClose( scan_hand ) ;
+ scan_hand = INVALID_HANDLE_VALUE ;
+ }
+
+ if ( file != NULL ) {
+ if ( !DeleteFile( file ) ) {
+ ret_val = FS_ACCESS_DENIED;
+ }
+ free( file ) ;
+ } else {
+ return OUT_OF_MEMORY ;
+ }
+ }
+
+ FindClose( scan_hand ) ;
+
+ return ret_val ;
+
+}
+
+INT16 EMS_LoadPathList( FSYS_HAND fsh, FILE_HAND hand )
+{
+ EMS_FSYS_RESERVED_PTR resPtr = fsh->reserved.ptr;
+ CHAR_PTR paths = NULL ;
+ CHAR_PTR p ;
+ INT paths_size ;
+ INT status ;
+
+ status = EMS_RestoreLocations( resPtr->restore_context, &paths, &paths_size ) ;
+
+ memset (&resPtr->paths, 0, sizeof( resPtr->paths ) ) ;
+
+ if ( !status && (paths != NULL) && *paths ) {
+
+ if ( fsh->attached_dle->info.xserv->type == EMS_MDB ) {
+
+ if (*paths == TEXT('\\') ) {
+
+ strcpy( resPtr->paths.mdb.FnameSystem, paths ) ;
+
+ paths += strlen(paths) + 1 ;
+
+ if (!*paths) {
+ return FS_ACCESS_DENIED ;
+ }
+
+ strcpy( resPtr->paths.mdb.LogDir, paths ) ;
+
+ paths += strlen(paths) + 1 ;
+
+ if (!*paths) {
+ return FS_ACCESS_DENIED ;
+ }
+
+ strcpy( resPtr->paths.mdb.FnamePrivate, paths ) ;
+
+ paths += strlen(paths) + 1 ;
+
+ if (!*paths) {
+ return FS_ACCESS_DENIED ;
+ }
+
+ strcpy( resPtr->paths.mdb.FnamePublic, paths ) ;
+
+ strcpy( resPtr->CheckpointFilePath, resPtr->paths.mdb.FnameSystem ) ;
+
+ strcpy( resPtr->LogPath, resPtr->paths.mdb.LogDir ) ;
+
+ } else {
+ while (*paths ) {
+ switch(*(paths++)) {
+ case BFT_CHECKPOINT_DIR :/*checkpoint */
+ strcpy( resPtr->CheckpointFilePath, paths ) ;
+ strcpy( resPtr->paths.mdb.FnameSystem, paths ) ;
+ if ( paths[strlen(paths)-1] != TEXT('\\') ) {
+ strcat( resPtr->paths.mdb.FnameSystem, TEXT("\\") ) ;
+ }
+ break ;
+
+ case BFT_MDB_PUBLIC_DATABASE : /*public*/
+ strcpy( resPtr->paths.mdb.FnamePublic, paths ) ;
+ break ;
+
+ case BFT_MDB_PRIVATE_DATABASE: /*private*/
+ strcpy( resPtr->paths.mdb.FnamePrivate, paths ) ;
+ break ;
+
+ case BFT_LOG_DIR: /*logs*/
+ strcpy( resPtr->paths.mdb.LogDir, paths ) ;
+ if ( paths[strlen(paths)-1] != TEXT('\\') ) {
+ strcat( resPtr->paths.mdb.LogDir, TEXT("\\") ) ;
+ }
+ strcpy( resPtr->LogPath, paths ) ;
+ break ;
+
+ default:
+ status = hrInvalidParam ;
+ break ;
+ }
+ paths += strlen( paths ) + 1 ;
+ }
+ }
+
+ } else if ( fsh->attached_dle->info.xserv->type == EMS_DSA ) {
+
+ if (*paths == TEXT('\\') ) {
+ strcpy( resPtr->paths.dsa.SystemPath, paths ) ;
+
+ paths += strlen(paths) + 1 ;
+
+ if (!*paths) {
+ return FS_ACCESS_DENIED ;
+ }
+
+ strcpy( resPtr->paths.dsa.LogDir, paths ) ;
+
+ paths += strlen(paths) + 1 ;
+
+ if (!*paths) {
+ return FS_ACCESS_DENIED ;
+ }
+
+ strcpy( resPtr->paths.dsa.DbPath, paths ) ;
+
+ strcpy( resPtr->CheckpointFilePath, resPtr->paths.dsa.SystemPath ) ;
+
+ strcpy( resPtr->LogPath, resPtr->paths.dsa.LogDir ) ;
+ } else {
+ while (*paths ) {
+ switch(*(paths++)) {
+ case BFT_CHECKPOINT_DIR :/*checkpoint */
+ strcpy( resPtr->CheckpointFilePath, paths ) ;
+ strcpy( resPtr->paths.dsa.SystemPath, paths ) ;
+ if ( paths[strlen(paths)-1] != TEXT('\\') ) {
+ strcat( resPtr->paths.dsa.SystemPath, TEXT("\\") ) ;
+ }
+ break ;
+
+ case BFT_DSA_DATABASE : /*public*/
+ strcpy( resPtr->paths.dsa.DbPath, paths ) ;
+ break ;
+
+ case BFT_LOG_DIR: /*logs*/
+ strcpy( resPtr->paths.dsa.LogDir, paths ) ;
+ if ( paths[strlen(paths)-1] != TEXT('\\') ) {
+ strcat( resPtr->paths.dsa.LogDir, TEXT("\\") ) ;
+ }
+ strcpy( resPtr->LogPath, paths ) ;
+ break ;
+
+ default:
+ status = hrInvalidParam ;
+ break ;
+ }
+
+ paths += strlen( paths ) + 1 ;
+ }
+ }
+ }
+ }
+ if (status ) {
+ return EMS_ConvertJetError( status ) ;
+ } else {
+ return SUCCESS ;
+ }
+
+}
+
diff --git a/private/utils/ntbackup/src/xreadobj.c b/private/utils/ntbackup/src/xreadobj.c
new file mode 100644
index 000000000..eddc36565
--- /dev/null
+++ b/private/utils/ntbackup/src/xreadobj.c
@@ -0,0 +1,625 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: treadobj.c
+
+ Description: This file contains code to read data from an object
+
+ $Log: M:/LOGFILES/TREADOBJ.C_V $
+
+**/
+#include <windows.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "omevent.h"
+#include "ems_jet.h"
+#include "stdmath.h"
+#include "msassert.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "fsys_err.h"
+#include "emsdblk.h"
+#include "ems_fs.h"
+
+VOID EMS_ZeroCheckSum( FILE_HAND hand ) ;
+VOID EMS_CalcCheckSum( FILE_HAND hand, BYTE_PTR buf, INT size ) ;
+
+static INT16 EMS_ReadData(
+ FILE_HAND hand,
+ BYTE_PTR buf,
+ UINT16 *size,
+ UINT16 *blk_size,
+ STREAM_INFO_PTR s_info );
+
+static INT16 BackupCheckSum(
+ FILE_HAND hand,
+ BYTE_PTR buf,
+ UINT16 *size ,
+ UINT16 *blk_size ,
+ STREAM_INFO_PTR s_info) ;
+
+static INT16 BackupPathList(
+ FILE_HAND hand,
+ BYTE_PTR buf,
+ UINT16 *size ,
+ UINT16 *blk_size ,
+ STREAM_INFO_PTR s_info) ;
+
+static INT16 BackStreamHeader(
+ FILE_HAND hand,
+ STREAM_INFO_PTR s_info );
+
+static UINT16 CalcReadSize( UINT64 startPos,
+ UINT64 endPos,
+ UINT16 buffSize );
+
+/**/
+/**
+
+ Name: EMS_ReadObj()
+
+ Description: This function reads data from an opened object.
+
+ Modified: 7/31/1989
+
+ Returns: Error Codes:
+ FS_DEVICE_ERROR
+ FS_OBJECT_NOT_OPENED
+ FS_EOF_REACHED
+ SUCCESS
+
+ Notes: This function reads data in "chunks". If the buffer
+ is not a multiple of the "chunk" size then the buffer will not
+ be filled. The "Chunk" size is returned.
+
+**/
+INT16 EMS_ReadObj(
+ FILE_HAND hand, /* I - handle of object to read from */
+ BYTE_PTR buf, /* O - buffer to place data into */
+ UINT16 *size , /*I/O- Entry: size of buf; Exit: number of bytes read */
+ UINT16 *blk_size , /* O - Block size needed for next read */
+ STREAM_INFO_PTR s_info) /* O - Stream information for the data returned */
+{
+ EMS_OBJ_HAND_PTR ems_hand = (EMS_OBJ_HAND_PTR)(hand->obj_hand.ptr ) ;
+ EMS_DBLK_PTR ddblk = (EMS_DBLK_PTR)hand->dblk ;
+ INT16 ret_val ;
+
+ msassert( hand->mode == FS_READ ) ;
+
+ if ( ems_hand->open_ret_val ) {
+ if ( ems_hand->needStreamHeader ) {
+ ems_hand->needStreamHeader = FALSE ;
+ return FS_COMM_FAILURE ;
+ } else {
+ return FS_EOF_REACHED ;
+ }
+ }
+
+ if ( (ems_hand->needStreamHeader == FALSE) && (*size == 0) )
+ {
+ /*
+ * Someone asked us to read zero bytes. According to
+ * our rules this is not allowed, but we'll be defensive
+ * anyway.
+ */
+ msassert( FALSE );
+ *blk_size = 1;
+ ret_val = SUCCESS;
+ }
+ else
+ {
+ switch ( hand->fsh->attached_dle->info.xserv->type )
+ {
+
+ case EMS_DSA:
+ case EMS_MDB:
+
+ ret_val = EMS_ReadData( hand, buf, size, blk_size, s_info ) ;
+ break ;
+
+ case EMS_BRICK:
+ return FS_ACCESS_DENIED ;
+ break;
+
+ default:
+ ret_val = FS_OBJECT_NOT_OPENED;
+ }
+ }
+
+ return ret_val;
+}
+
+/**/
+/**
+
+ Name: EMS_ReadData()
+
+ Description: This function calls the NT Backup APIs to read data from
+ an open object.
+
+ Modified: 2/10/1992 16:48:9
+
+ Returns: FS_DEVICE_ERROR
+ FS_OBJECT_NOT_OPENED
+ FS_EOF_REACHED
+ SUCCESS
+
+**/
+static INT16 EMS_ReadData(
+ FILE_HAND hand, /* I - handle of object to read from */
+ BYTE_PTR buf, /* O - buffer to place data into */
+ UINT16 *size, /*I/O- Entry: size of buf; Exit: number of bytes read */
+ UINT16 *blk_size, /* O - Block size needed for next read */
+ STREAM_INFO_PTR s_info ) /* O - Stream information for the data returned */
+{
+ EMS_OBJ_HAND_PTR ems_hand = (EMS_OBJ_HAND_PTR)(hand->obj_hand.ptr ) ;
+ INT16 ret_val = SUCCESS ;
+ INT status ;
+ INT sizeout ;
+ UINT16 buffSize;
+ BOOLEAN dummy;
+ BYTE_PTR org_buf = buf ;
+
+ *blk_size = 1 ;
+
+ s_info->id = STRM_INVALID;
+
+ if ( ems_hand->needPathList )
+ {
+ ret_val = BackupPathList( hand, buf, size, blk_size, s_info ) ;
+ return ret_val ;
+ }
+ else if ( ems_hand->time_for_checksum )
+ {
+ ret_val = BackupCheckSum( hand, buf, size, blk_size, s_info ) ;
+ return ret_val ;
+
+ }
+ else if ( ems_hand->needStreamHeader )
+ {
+ EMS_ZeroCheckSum( hand ) ;
+ ret_val = BackStreamHeader( hand, s_info );
+ *size = 0 ;
+ if ( ret_val == RPC_S_SERVER_TOO_BUSY ) {
+ ems_hand->needStreamHeader = TRUE ;
+ return SUCCESS ;
+ }
+ }
+ else
+ {
+ UINT16 readSize;
+
+ buffSize = *size;
+ *size = 0;
+
+ s_info->id = STRM_INVALID;
+
+ if ( (ems_hand->strm_name.name_leng > 0) &&
+ U64_EQ( ems_hand->curPos, U64_Init( 0, 0 ) ) )
+ {
+ UINT16 nameSize;
+
+ nameSize = (UINT16)(ems_hand->strm_name.name_leng +
+ sizeof(ems_hand->strm_name.name_leng));
+
+ if ( buffSize < nameSize )
+ {
+ *blk_size = nameSize;
+ return SUCCESS;
+
+ } else {
+
+ memcpy( buf, &(ems_hand->strm_name.name_leng), nameSize ) ;
+ buffSize -= nameSize ;
+ buf += nameSize ;
+ *size = nameSize ;
+ }
+ }
+ // If I'm here then I have file data to read...
+
+ readSize = CalcReadSize( ems_hand->curPos,
+ ems_hand->nextStreamHeaderPos,
+ buffSize );
+
+ if ( readSize ) {
+
+ status = EMS_BackupRead( ems_hand->context,
+ buf,
+ readSize,
+ (LPDWORD)&sizeout ) ;
+ } else {
+ sizeout = 0 ;
+ status = SUCCESS ;
+ }
+
+ if ( status && (readSize & 4095) ) {
+
+ readSize -= (readSize%4096) ;
+
+ if ( !readSize ) {
+ if (*size==0) {
+ *blk_size = 4096 ;
+ }
+ status = SUCCESS;
+ sizeout = 0 ;
+
+ } else {
+ status = EMS_BackupRead( ems_hand->context,
+ buf,
+ readSize,
+ (LPDWORD)&sizeout ) ;
+ }
+
+ }
+
+ if ( status == RPC_S_SERVER_TOO_BUSY ) {
+ sizeout = 0 ;
+ status = SUCCESS ;
+ }
+
+ if ( !status ) {
+ *size += sizeout;
+ ems_hand->curPos = U64_Add( ems_hand->curPos,
+ U32_To_U64( (UINT32)*size ),
+ &dummy );
+ } else {
+ // translate the error
+ OMEVENT_LogEMSError ( TEXT("BackupRead()"), status, TEXT(" - ") ) ;
+ ret_val = EMS_ConvertJetError( status );
+ }
+
+ }
+
+ ems_hand->needStreamHeader = U64_EQ( ems_hand->curPos, ems_hand->nextStreamHeaderPos);
+
+ EMS_CalcCheckSum( hand, org_buf, (UINT32)*size ) ;
+
+ if ( ems_hand->needStreamHeader) {
+ EMS_BackupClose( ems_hand->context ) ;
+ ems_hand->time_for_checksum = TRUE ;
+ }
+
+ return ret_val;
+}
+
+VOID EMS_ZeroCheckSum( FILE_HAND hand )
+{
+ EMS_OBJ_HAND_PTR ems_hand = (EMS_OBJ_HAND_PTR) hand->obj_hand.ptr ;
+ ems_hand->check_sum = 0 ;
+ ems_hand->residule_byte_count = 0 ;
+}
+
+VOID EMS_CalcCheckSum( FILE_HAND hand, BYTE_PTR buf, INT size )
+{
+ EMS_OBJ_HAND_PTR ems_hand = (EMS_OBJ_HAND_PTR) hand->obj_hand.ptr ;
+ UINT32 UNALIGNED *word_ptr = (UINT32_PTR)buf ;
+ INT i ;
+
+ // handle residule from last call
+ if ( ems_hand->residule_byte_count ) {
+ UINT32 continue_word ;
+ INT bytes_to_integrate = sizeof(UINT32) - ems_hand->residule_byte_count;
+
+ for ( i = 0;
+ (i <size) && (i < bytes_to_integrate );
+ i++ ) {
+
+ INT shift_count ;
+
+ shift_count = i+ ems_hand->residule_byte_count ;
+
+ continue_word = *buf ;
+ continue_word <<= (8*shift_count) ;
+ ems_hand->check_sum ^= continue_word ;
+ buf ++ ;
+ }
+
+ if ( size < bytes_to_integrate ) {
+ ems_hand->residule_byte_count += size ;
+ size = 0 ;
+ return ;
+ } else {
+ size -= bytes_to_integrate ;
+ }
+ }
+
+ word_ptr = (UINT32_PTR)buf ;
+
+ // handle middle data
+ for ( i = 0; i < (INT)(size/sizeof(UINT32)); i++ ) {
+ ems_hand->check_sum ^= *word_ptr ;
+ word_ptr ++ ;
+ buf += sizeof(UINT32);
+ }
+
+ // handle the leftover
+ ems_hand->residule_byte_count = size%sizeof(UINT32) ;
+ if ( ems_hand->residule_byte_count ) {
+ UINT32 left_over ;
+
+ for ( i = 0; i < (INT)(size%sizeof(UINT32)); i++ ) {
+
+ left_over = *buf;
+ left_over <<= (8*i);
+ ems_hand->check_sum ^= left_over ;
+ buf ++ ;
+ }
+ }
+}
+
+
+static INT16 BackupCheckSum(
+ FILE_HAND hand, /* I - handle of object to read from */
+ BYTE_PTR buf, /* O - buffer to place data into */
+ UINT16 *size , /*I/O- Entry: size of buf; Exit: number of bytes read */
+ UINT16 *blk_size , /* O - Block size needed for next read */
+ STREAM_INFO_PTR s_info) /* O - Stream information for the data returned */
+{
+ EMS_OBJ_HAND_PTR ems_hand = (EMS_OBJ_HAND_PTR)(hand->obj_hand.ptr ) ;
+ INT16 ret_val = SUCCESS ;
+ INT status ;
+ INT sizeout ;
+ UINT16 buffSize;
+ BOOLEAN dummy;
+
+ if ( ems_hand->needStreamHeader ) {
+ s_info->id = STRM_CHECKSUM_DATA ;
+ s_info->fs_attrib = 0 ;
+ s_info->tf_attrib = 0 ;
+ s_info->size.lsw = sizeof(UINT32) ;
+ s_info->size.msw = 0 ;
+ ems_hand->needStreamHeader = FALSE ;
+ } else {
+ if ( *size < sizeof(UINT32) ) {
+ *blk_size = sizeof(UINT32) ;
+ *size = 0 ;
+ } else {
+ memcpy( buf, &ems_hand->check_sum, sizeof(UINT32) ) ;
+ *size = sizeof(UINT32) ;
+ ems_hand->needStreamHeader = TRUE ;
+ ems_hand->time_for_checksum = FALSE ;
+ }
+ }
+
+ return ret_val ;
+}
+
+static INT16 BackupPathList(
+ FILE_HAND hand, /* I - handle of object to read from */
+ BYTE_PTR buf, /* O - buffer to place data into */
+ UINT16 *size , /*I/O- Entry: size of buf; Exit: number of bytes read */
+ UINT16 *blk_size , /* O - Block size needed for next read */
+ STREAM_INFO_PTR s_info) /* O - Stream information for the data returned */
+{
+ EMS_OBJ_HAND_PTR ems_hand = (EMS_OBJ_HAND_PTR)(hand->obj_hand.ptr ) ;
+ EMS_FSYS_RESERVED_PTR resPtr = hand->fsh->reserved.ptr ;
+
+ if ( ems_hand->needStreamHeader ) {
+ int s_size = 0 ;
+
+ if ( hand->dblk->com.os_id == FS_EMS_MDB_ID ) {
+ s_size = strsize( resPtr->paths.mdb.FnamePrivate ) ;
+ s_size += strsize( resPtr->paths.mdb.FnamePublic ) ;
+ s_size += strsize( resPtr->paths.mdb.FnameSystem ) ;
+ s_size += strsize( resPtr->paths.mdb.LogDir ) ;
+ } else {
+
+ s_size = strsize( resPtr->paths.dsa.DbPath ) ;
+ s_size += strsize( resPtr->paths.dsa.SystemPath ) ;
+ s_size += strsize( resPtr->paths.dsa.LogDir ) ;
+ }
+
+ s_info->id = STRM_EMS_MONO_PATHS;
+ s_info->fs_attrib = 0 ;
+ s_info->tf_attrib = 0 ;
+
+ s_info->size.lsw = s_size ;
+ s_info->size.msw = 0 ;
+
+ ems_hand->pathListSize = s_size ;
+ ems_hand->needStreamHeader = FALSE ;
+
+ } else {
+ if ( *size < ems_hand->pathListSize ) {
+ *blk_size = ems_hand->pathListSize ;
+ *size = 0 ;
+ } else {
+ int s_size = 0 ;
+
+ if ( hand->dblk->com.os_id == FS_EMS_MDB_ID ) {
+ strcpy( (CHAR_PTR)(buf + s_size), resPtr->paths.mdb.FnamePrivate ) ;
+ s_size = strsize( resPtr->paths.mdb.FnamePrivate ) ;
+ strcpy( (CHAR_PTR)(buf + s_size), resPtr->paths.mdb.FnamePublic ) ;
+ s_size += strsize( resPtr->paths.mdb.FnamePublic ) ;
+ strcpy( (CHAR_PTR)(buf + s_size), resPtr->paths.mdb.FnameSystem ) ;
+ s_size += strsize( resPtr->paths.mdb.FnameSystem ) ;
+ strcpy( (CHAR_PTR)(buf + s_size), resPtr->paths.mdb.LogDir ) ;
+ s_size += strsize( resPtr->paths.mdb.LogDir ) ;
+ } else {
+
+ strcpy( (CHAR_PTR)(buf + s_size), resPtr->paths.dsa.DbPath ) ;
+ s_size = strsize( resPtr->paths.dsa.DbPath ) ;
+ strcpy( (CHAR_PTR)(buf + s_size), resPtr->paths.dsa.SystemPath ) ;
+ s_size += strsize( resPtr->paths.dsa.SystemPath ) ;
+ strcpy( (CHAR_PTR)(buf + s_size), resPtr->paths.dsa.LogDir ) ;
+ s_size += strsize( resPtr->paths.dsa.LogDir ) ;
+ }
+
+ *size = ems_hand->pathListSize ;
+ ems_hand->needStreamHeader = TRUE ;
+ ems_hand->needPathList = FALSE ;
+ ems_hand->time_for_checksum = FALSE ;
+ }
+ }
+
+ return SUCCESS ;
+}
+
+
+/**/
+/**
+
+ Name: BackStreamHeader()
+
+ Description: This function reads an NT stream header from the
+ Backup API and translates it to STREAM_INFO.
+
+ Modified: 08-Sep-92
+
+ Returns: FS_EOF_REACHED
+ SUCCESS
+
+ Notes:
+
+**/
+static INT16 BackStreamHeader(
+ FILE_HAND hand, /* I - handle of object to read from */
+ STREAM_INFO_PTR s_info ) /* O - Stream information for the data returned */
+{
+ EMS_OBJ_HAND_PTR ems_hand = (EMS_OBJ_HAND_PTR)(hand->obj_hand.ptr ) ;
+ EMS_DBLK_PTR ddblk = (EMS_DBLK_PTR)hand->dblk ;
+ INT16 ret_val = SUCCESS ;
+ INT status ;
+ CHAR filename[256] ;
+ INT fname_size ;
+ INT i ;
+ LARGE_INTEGER stream_size ;
+ BOOLEAN mathStat;
+ CHAR exch_id = 0 ;
+
+
+ ems_hand->curPos = U64_Init( 0, 0 );
+
+ if ( ems_hand->name_list[ems_hand->name_list_offset] ) {
+
+ if (ems_hand->name_list[ems_hand->name_list_offset] != TEXT('\\') ) {
+ exch_id = ems_hand->name_list[ems_hand->name_list_offset] ;
+ ems_hand->name_list_offset ++ ;
+ }
+
+ ems_hand->strm_name.name_leng =
+ strsize( &ems_hand->name_list[ems_hand->name_list_offset] ) + sizeof(CHAR);
+
+
+ strcpy( (CHAR_PTR)(ems_hand->strm_name.name),
+ &ems_hand->name_list[ems_hand->name_list_offset] ) ;
+
+ fname_size = strlen( &ems_hand->name_list[ems_hand->name_list_offset] ) ;
+
+ *(((CHAR_PTR)ems_hand->strm_name.name) + fname_size + 1) = exch_id ;
+
+ strcpy( filename, &ems_hand->name_list[ems_hand->name_list_offset] ) ;
+
+ ems_hand->name_list_offset += fname_size +1 ;
+
+ status = EMS_BackupOpen( ems_hand->context,
+ filename,
+ 32 * 1024,
+ &stream_size ) ;
+ if ( !status ) {
+ // lets initialize the stream header
+ if ( ems_hand->db_or_log == EMS_DOING_DB ) {
+ s_info->id = STRM_EMS_MONO_DB ;
+ } else {
+ s_info->id = STRM_EMS_MONO_LOG ;
+ }
+ s_info->fs_attrib = 0 ;
+ s_info->tf_attrib = 0 ;
+ s_info->size.lsw = stream_size.LowPart ;
+ s_info->size.msw = stream_size.HighPart ;
+
+ s_info->size = U64_Add( s_info->size,
+ U32_To_U64(ems_hand->strm_name.name_leng + sizeof(UINT32)) ,
+ &mathStat ) ;
+
+ ems_hand->nextStreamHeaderPos = s_info->size ;
+
+ return SUCCESS ;
+
+ } else {
+ return EMS_ConvertJetError( status ) ;
+ }
+ } else {
+ if ( ems_hand->db_or_log == EMS_DOING_DB ) {
+ ret_val = EMS_LoadNameList( hand->fsh, hand, EMS_DOING_LOGS ) ;
+ if ( ret_val == SUCCESS ) {
+ return (BackStreamHeader( hand, s_info ) );
+ } else {
+ return ret_val ;
+ }
+ }
+
+ ddblk->backup_completed = TRUE ;
+ s_info->id = STRM_INVALID;
+ return FS_EOF_REACHED ;
+ }
+
+ return SUCCESS ;
+}
+
+/**/
+/**
+
+ Name: CalcReadSize()
+
+ Description: Calculates 16-bit read size from 64-bit position
+ information and 16-bit buffer size.
+
+ Modified: 08-Sep-92
+
+ Returns: Amount of data to read.
+
+ Notes:
+
+**/
+static UINT16 CalcReadSize( UINT64 startPos,
+ UINT64 endPos,
+ UINT16 buffSize )
+{
+ UINT16 readSize;
+ BOOLEAN mathStat;
+
+ if ( U64_GT( U64_Add( startPos,
+ U32_To_U64( (UINT32)buffSize ),
+ &mathStat ),
+ endPos ) )
+ {
+ UINT64 rs;
+
+ rs = U64_Sub( endPos,
+ startPos,
+ &mathStat );
+
+ msassert( mathStat && (U64_Msw( rs ) == 0) && (U64_Lsw(rs) < 65536) );
+
+ readSize = (UINT16)U64_Lsw( rs );
+ } else {
+ readSize = buffSize;
+ }
+
+ return readSize;
+}
+
+#ifdef FS_EMS
+VOID
+EMS_GetStreamName(
+ FILE_HAND hand, /* I - handle of object to read from */
+ BYTE_PTR buf, /* O - buffer to place data into */
+ UINT16 *size ) /*I/O- Entry: size of buf; Exit: number of bytes read */
+{
+ EMS_OBJ_HAND_PTR ems_hand = (EMS_OBJ_HAND_PTR)(hand->obj_hand.ptr ) ;
+ UINT32 sizeout ;
+
+ sizeout = *size ;
+ if ( sizeout > ems_hand->strm_name.name_leng ) {
+ sizeout = ems_hand->strm_name.name_leng ;
+ }
+
+ memcpy( buf, ems_hand->strm_name.name, sizeout ) ;
+ *size = (UINT16)sizeout ;
+}
+
+#endif
diff --git a/private/utils/ntbackup/src/xseekobj.c b/private/utils/ntbackup/src/xseekobj.c
new file mode 100644
index 000000000..e881bcee9
--- /dev/null
+++ b/private/utils/ntbackup/src/xseekobj.c
@@ -0,0 +1,102 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: xseekobj.c
+
+ Description: This file contains code to Seek to specific portion of
+ an opened object.
+
+
+ $Log: M:/LOGFILES/XSEEKOBJ.C_V $
+
+
+**/
+#include <windows.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ems_jet.h"
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "msassert.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "fsys_err.h"
+#include "emsdblk.h"
+#include "ems_fs.h"
+
+/**/
+/**
+
+ Name: EMS_SeekObj()
+
+ Description: This function seeks to the specified location of an
+ opened object.
+
+ Modified: 02-Nov-92
+
+ Returns: Error Codes :
+ FS_OBJECT_NOT_OPENED
+ FS_EOF_REACHED
+ SUCCESS
+
+**/
+INT16 EMS_SeekObj(
+ FILE_HAND hand, /* I - Opened object to seek into */
+ UINT32 *offset ) /*I/O- Offset to seek; bytes actually seeked */
+{
+ EMS_OBJ_HAND_PTR ems_hand = hand->obj_hand.ptr;
+ BOOLEAN stat ;
+
+ /*
+ * Make sure we don't seek into the next stream header
+ */
+ if ( U64_GT( U64_Add( ems_hand->curPos,
+ U32_To_U64( *offset ),
+ &stat ),
+ ems_hand->nextStreamHeaderPos ) )
+ {
+ UINT64 seek;
+
+ seek = U64_Sub( ems_hand->nextStreamHeaderPos,
+ ems_hand->curPos,
+ &stat );
+
+ msassert( stat && (U64_Msw(seek) == 0) );
+ *offset = U64_Lsw( seek );
+ }
+
+ if ( *offset == 0 )
+ {
+ /*
+ * A seek of zero bytes should be OK
+ */
+ }
+ else
+ {
+ ems_hand->curPos = U64_Add( ems_hand->curPos,
+ U32_To_U64( *offset ),
+ &stat );
+ }
+
+ /*
+ * Since we may have moved the curPos, we need to update the flag
+ * that indicates whether we're ready for another stream header.
+ * (The only place we look at this is in the ReadObj code.)
+ */
+ if ( hand->mode == FS_READ )
+ {
+ ems_hand->needStreamHeader = U64_EQ( ems_hand->curPos,
+ ems_hand->nextStreamHeaderPos);
+
+ if ( ems_hand->needStreamHeader) {
+ EMS_BackupClose( ems_hand->context ) ;
+ }
+ }
+
+ return SUCCESS;
+}
+
+
diff --git a/private/utils/ntbackup/src/xsetinfo.c b/private/utils/ntbackup/src/xsetinfo.c
new file mode 100644
index 000000000..804c46435
--- /dev/null
+++ b/private/utils/ntbackup/src/xsetinfo.c
@@ -0,0 +1,50 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tsetinfo.c
+
+ Description: This file contains code to write the OS specific
+ data stored in the DBLKS to the OS
+
+
+ $Log: N:/LOGFILES/TSETINFO.C_V $
+
+
+**/
+#include <windows.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "fsys.h"
+#include "fsys_err.h"
+#include "emsdblk.h"
+#include "ems_fs.h"
+#include "msassert.h"
+
+/**/
+/**
+
+ Name: EMS_SetObjInfo()
+
+ Description: This funciton writes the OS info in a DBLK to disk
+
+ Modified: 2/10/1992 16:31:17
+
+ Returns: Error codes:
+ FS_NOT_FOUND
+ FS_ACCESS_DENIED
+ SUCCESS
+
+ Notes: Only type supported are FDBs and DDBs
+
+**/
+INT16 EMS_SetObjInfo( fsh, dblk )
+FSYS_HAND fsh ; /* I - file system handle */
+DBLK_PTR dblk ; /* I - data to write to disk */
+{
+
+ return SUCCESS ;
+}
diff --git a/private/utils/ntbackup/src/xsize.c b/private/utils/ntbackup/src/xsize.c
new file mode 100644
index 000000000..31cae79f5
--- /dev/null
+++ b/private/utils/ntbackup/src/xsize.c
@@ -0,0 +1,185 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tsize.c
+
+ Description: This file contains code to get the size of the
+ variable length fields in FDBs and DDBs
+
+
+ $Log: N:/LOGFILES/TSIZE.C_V $
+
+**/
+#include <windows.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "stdwcs.h"
+#include "msassert.h"
+#include "tfldefs.h"
+#include "fsys.h"
+#include "emsdblk.h"
+#include "ems_fs.h"
+#include "osinfo.h"
+
+
+/**/
+/**
+
+ Name: EMS_SizeofFname()
+
+ Description: This function returns the size of the file
+ name contained in the FDB bassed in
+
+ Modified: 9/11/1989
+
+ Returns: number of bytes including terminating NULL.
+
+ Notes:
+
+ Declaration:
+
+**/
+/* begin declaration */
+INT16 EMS_SizeofFname( fsh, fdb )
+FSYS_HAND fsh; /* I - file system in use */
+DBLK_PTR fdb ; /* I - dblk to get fname from */
+{
+ (void)fsh ;
+ (void)fdb ;
+
+ msassert( "EMS_SizeofFname()"==NULL ) ;
+
+ return 0 ;
+}
+
+/**/
+/**
+
+ Name: EMS_SizeofOSFname()
+
+ Description: This function returns the size of the file
+ name (as it appears on tape) contained in the FDB bassed in
+
+ Modified: 9/11/1989
+
+ Returns: number of bytes including terminating NULL.
+
+ Notes:
+
+**/
+INT16 EMS_SizeofOSFname( fsh, fdb )
+FSYS_HAND fsh; /* I - file system in use */
+DBLK_PTR fdb ; /* I - dblk to get fname from */
+{
+ (void)fsh ;
+ (void)fdb;
+ msassert( "EMS_SizeofOSFname()"==NULL ) ;
+ return 0 ;
+}
+
+/**/
+/**
+
+ Name: EMS_SizeofPath()
+
+ Description: This function return the size of the path saved in the
+ DDB.
+
+ Modified: 9/11/1989
+
+ Returns: Number of bytes in path string
+
+ Notes:
+
+**/
+INT16 EMS_SizeofPath( fsh, ddb )
+FSYS_HAND fsh ; /* I - File system handle */
+DBLK_PTR ddb ; /* I - DBLK to get path size from */
+{
+ EMS_DBLK_PTR ddblk ;
+ INT16 size;
+ GENERIC_DLE_PTR dle=fsh->attached_dle ;
+
+ msassert( ddb->blk_type == DDB_ID ) ;
+
+ ddblk = ( EMS_DBLK_PTR) ddb ;
+
+ if ( ( dle->info.xserv->type == EMS_MDB ) ||
+ ( dle->info.xserv->type == EMS_DSA ) ) {
+
+ size = ddb->com.os_name->name_size ;
+
+ } else { //bricked
+
+ size = (INT16)ddblk->full_name_ptr->name_size;
+ }
+
+ return size;
+}
+/**/
+/**
+
+ Name: EMS_SizeofOSPath()
+
+ Description: This function return the size of the path saved in the
+ DDB.
+
+ Modified: 9/11/1989
+
+ Returns: Number of bytes in path string
+
+ Notes:
+
+ Declaration:
+
+**/
+INT16 EMS_SizeofOSPath( fsh, ddb )
+FSYS_HAND fsh ; /* I - File system handle */
+DBLK_PTR ddb ; /* I - DBLK to get path size from */
+{
+ EMS_DBLK_PTR dddb = (EMS_DBLK_PTR)ddb ;
+ INT16 size;
+
+ (void)fsh ;
+ msassert( ddb->blk_type == DDB_ID ) ;
+
+
+ if ( ddb->com.os_name != NULL )
+ {
+ size = ddb->com.os_name->name_size ;
+ }
+ else
+ {
+ size = (INT16)dddb->full_name_ptr->name_size ;
+ }
+ return size;
+}
+
+
+/**/
+/**
+
+ Name: EMS_SizeofOSInfo()
+
+ Description: This function returns the size of the OS info for
+ an FDB or a DDB
+
+ Modified: 9/11/1989
+
+ Returns: Size in bytes.
+
+ Notes:
+
+ Declaration:
+
+**/
+INT16 EMS_SizeofOSInfo( fsh, dblk)
+FSYS_HAND fsh ; /* I - File system handle */
+DBLK_PTR dblk; /* I - DBLK to get size of OS info for */
+{
+ (void)fsh ;
+ (void)dblk ;
+ return 0 ;
+}
diff --git a/private/utils/ntbackup/src/xverinfo.c b/private/utils/ntbackup/src/xverinfo.c
new file mode 100644
index 000000000..ad92993ad
--- /dev/null
+++ b/private/utils/ntbackup/src/xverinfo.c
@@ -0,0 +1,50 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: tverinfo.c
+
+ Description: This file contains code to verify the DBLKS
+
+ $Log: N:/LOGFILES/TVERINFO.C_V $
+
+**/
+#include <windows.h>
+#include <string.h>
+
+#include "stdtypes.h"
+#include "stdmath.h"
+#include "std_err.h"
+#include "fsys.h"
+#include "fsys_err.h"
+#include "emsdblk.h"
+#include "ems_fs.h"
+#include "msassert.h"
+
+
+/**/
+/**
+
+ Name: EMS_VerObjInfo()
+
+ Description: This funciton compares the data in a DBLK with
+ the data returned by the operating system.
+
+ Modified: 2/12/1992 13:6:5
+
+ Returns: Error Codes:
+ FS_NOT_FOUND
+ FS_ACCESS_DENIED
+ FS_INFO_DIFFERENT
+ SUCCESS
+
+ Notes: For FDBs this funciton will check the current
+ directory for the specified file.
+
+**/
+INT16 EMS_VerObjInfo( fsh, dblk )
+FSYS_HAND fsh ; /* I - File system handle */
+DBLK_PTR dblk ; /* I - On entry it is minimal on exit Complete */
+{
+ return SUCCESS ;
+}
diff --git a/private/utils/ntbackup/src/xverobj.c b/private/utils/ntbackup/src/xverobj.c
new file mode 100644
index 000000000..b80b89cb5
--- /dev/null
+++ b/private/utils/ntbackup/src/xverobj.c
@@ -0,0 +1,100 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: xverobj.c
+
+ Description: This file verifies the object data.
+
+
+ $Log: M:/LOGFILES/XVEROBJ.C_V $
+
+
+**/
+#include <windows.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+
+#include "stdtypes.h"
+#include "std_err.h"
+#include "stdmath.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "fsys_err.h"
+#include "emsdblk.h"
+#include "ems_fs.h"
+#include "msassert.h"
+
+
+/**/
+/**
+
+ Name: EMS_VerObj()
+
+ Description: This function verifies the data in an object.
+
+ Modified: 2/12/1992 14:29:33
+
+ Returns: Error Codes:
+ FS_DEVICE_ERROR
+ FS_EOF_REACHED
+ FS_GDATA_DIFFERENT
+ FS_SECURITY_DATA_DIFFERENT
+ SUCCESS
+
+**/
+/* begin declaration */
+INT16 EMS_VerObj(
+FILE_HAND hand, /* I - file handle to verify data with */
+BYTE_PTR buf, /* I - buffer needed to perform verify */
+BYTE_PTR data, /* I - data to verify against */
+UINT16 *size, /*I/O- size of buffers / amount verified */
+UINT16 *blk_size, /* O - minum size of block for next call */
+STREAM_INFO_PTR s_info ) /* I - Stream information for the data to be written */
+{
+ INT16 ret_val = SUCCESS ;
+ EMS_OBJ_HAND_PTR ems_hand = hand->obj_hand.ptr;
+ *blk_size = 1 ;
+
+ msassert( hand != NULL );
+ msassert( hand->mode == FS_VERIFY ) ;
+
+ if ( s_info->id != STRM_INVALID ) {
+
+ if ( s_info->id == STRM_CHECKSUM_DATA ) {
+ ems_hand->time_for_checksum = TRUE ;
+
+ } else {
+
+ EMS_ZeroCheckSum( hand ) ;
+ }
+
+ } else {
+ if ( ems_hand->time_for_checksum ) {
+ if (*size < sizeof(UINT32) ) {
+ *blk_size = sizeof(UINT32) ;
+ *size = 0 ;
+ } else {
+ UINT32 csum = 0;
+ UINT32 hold = 0 ;
+ INT i;
+ for ( i=0; i < sizeof(UINT32); i++ ) {
+ hold = data[i] ;
+ hold <<= (8*i) ;
+ csum |= hold ;
+ }
+ if ( csum != ems_hand->check_sum ) {
+ ret_val = FS_GDATA_DIFFERENT;
+ }
+ ems_hand->time_for_checksum = FALSE ;
+ }
+ } else {
+ EMS_CalcCheckSum( hand, data, *size ) ;
+ }
+ }
+
+
+ return( ret_val ) ;
+}
+
diff --git a/private/utils/ntbackup/src/xwritobj.c b/private/utils/ntbackup/src/xwritobj.c
new file mode 100644
index 000000000..c9cb89e12
--- /dev/null
+++ b/private/utils/ntbackup/src/xwritobj.c
@@ -0,0 +1,724 @@
+/**
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+
+ Name: twritobj.c
+
+ Description: This function writes data to an open object.
+
+
+ $Log: M:/LOGFILES/TWRITOBJ.C_V $
+
+
+**/
+#include <windows.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+
+#include "stdtypes.h"
+#include "jetbcli.h"
+#include "std_err.h"
+#include "stdmath.h"
+#include "msassert.h"
+#include "fsys.h"
+#include "fsys_prv.h"
+#include "fsys_err.h"
+#include "emsdblk.h"
+#include "ems_fs.h"
+#include "omevent.h"
+
+static INT ua_strsize( BYTE_PTR name ) ;
+
+static INT16 EMS_WriteData(
+ FILE_HAND hand,
+ BYTE_PTR buf,
+ UINT16 *size,
+ UINT16 *blk_size,
+ STREAM_INFO_PTR s_info );
+
+static CHAR_PTR EMS_MungeFname( FSYS_HAND fsh, FILE_HAND hand, CHAR_PTR name, CHAR exch_id ) ;
+
+static BOOLEAN EMS_PathMatch( CHAR_PTR p_end, CHAR_PTR q_start ) ;
+
+static UINT16 CalcWriteSize( UINT64 startPos,
+ UINT64 endPos,
+ UINT16 buffSize );
+
+static VOID EMS_AddToJetRstmap( FILE_HAND hand, CHAR_PTR org_name, CHAR_PTR new_name ) ;
+
+static VOID EMS_UpdateRipLogKey( FILE_HAND hand, CHAR_PTR log_name, BOOLEAN low_able ) ;
+
+/**/
+/**
+
+ Name: EMS_WriteObj()
+
+ Description: This function writes data to an opened object on
+ disk.
+
+ Modified: 2/12/1992 12:57:2
+
+ Returns: Error Codes:
+ FS_DEVICE_ERROR
+ FS_OBJECT_NOT_OPENED
+ FS_OUT_OF_SPACE
+ SUCCESS
+
+ Notes:
+
+**/
+INT16 EMS_WriteObj(
+ FILE_HAND hand, /* I - handle of object to read from */
+ BYTE_PTR buf, /* O - buffer to place data into */
+ UINT16 *size, /*I/O- Entry: size of buf; Exit: number of bytes read */
+ UINT16 *blk_size, /* O - Block size need for next read */
+ STREAM_INFO_PTR s_info ) /* I - Stream information for the data to be written */
+{
+ INT16 ret_val;
+
+ msassert( hand->mode == FS_WRITE );
+
+ if ( (s_info->id == STRM_INVALID) && (*size == 0) )
+ {
+ /*
+ * Someone asked us to write zero bytes. According to
+ * our rules this is not allowed, but we'll be defensive
+ * anyway.
+ */
+ msassert( FALSE );
+ *blk_size = 1;
+ ret_val = SUCCESS;
+ }
+ else
+ {
+ ret_val = EMS_WriteData( hand, buf, size, blk_size, s_info ) ;
+ }
+ return ret_val;
+}
+
+/**/
+/**
+
+ Name: EMS_WriteData()
+
+ Description: This function writes data to an open NTFS object.
+
+ Modified: 10-Sep-92
+
+ Returns: FS_OUT_OF_SPACE
+ SUCCESS
+
+ Notes:
+
+**/
+static INT16 EMS_WriteData(
+ FILE_HAND hand, /* I - handle of object to read from */
+ BYTE_PTR buf, /* I - buffer to write */
+ UINT16 *size, /*I/O- Entry: size of buf; Exit: bytes written */
+ UINT16 *blk_size, /* O - Block size need for next write */
+ STREAM_INFO_PTR s_info ) /* I - Stream information for the data */
+{
+ EMS_OBJ_HAND_PTR ems_hand = (EMS_OBJ_HAND_PTR)(hand->obj_hand.ptr ) ;
+ EMS_FSYS_RESERVED_PTR res = hand->fsh->reserved.ptr;
+ INT16 ret_val = SUCCESS ;
+ UINT16 bufferSize;
+ DWORD sizeout;
+ INT status;
+ UINT16 writeSize; /* Size sent to BackupWrite */
+ BOOLEAN dummy;
+ CHAR_PTR server_name = hand->fsh->attached_dle->parent->device_name ;
+ EMS_DBLK_PTR ddblk = (EMS_DBLK_PTR)hand->dblk ;
+
+ bufferSize = *size;
+ *size = 0;
+ *blk_size = 1;
+
+ if ( s_info->id != STRM_INVALID )
+ {
+ UINT16 buffUsed = 0; /* Amount of buf we wrote (name) */
+
+ ems_hand->skip_data = FALSE ;
+
+ if ( (ems_hand->fhand != NULL) &&
+ (ems_hand->fhand != INVALID_HANDLE_VALUE) ) {
+ CloseHandle( ems_hand->fhand ) ;
+ ems_hand->fhand = INVALID_HANDLE_VALUE ;
+ }
+
+ if (s_info->id == STRM_EMS_MONO_PATHS ) {
+ ems_hand->needPathList = TRUE ;
+ ems_hand->pathListSize = s_info->size.lsw ;
+ } else {
+ ems_hand->needPathList = FALSE ;
+ }
+
+ if ( s_info->id == STRM_CHECKSUM_DATA ) {
+ ems_hand->skip_data = TRUE ;
+
+ } else if ( (s_info->id != STRM_EMS_MONO_DB ) &&
+ (s_info->id != STRM_EMS_MONO_PATHS ) &&
+ (s_info->id != STRM_EMS_MONO_LOG ) ) {
+
+ return FS_DONT_WANT_STREAM ;
+ }
+
+ ems_hand->currentStreamId = s_info->id ;
+ ems_hand->curPos = U64_Init( 0, 0 );
+ ems_hand->nextStreamHeaderPos = s_info->size ;
+
+ bufferSize = 0 ;
+
+ } else {
+
+ if ( ems_hand->skip_data ) {
+ *size = bufferSize ;
+ return SUCCESS ;
+
+ } else if ( ems_hand->needPathList ) {
+
+ if ( bufferSize < ems_hand->pathListSize ) {
+ *blk_size = ems_hand->pathListSize ;
+ return SUCCESS ;
+
+ } else {
+ INT byte_count ;
+
+ ddblk->backup_completed = FALSE ;
+
+ if ( hand->dblk->com.os_id == FS_EMS_MDB_ID ) {
+
+ byte_count = ua_strsize(buf) ;
+ memcpy( ems_hand->org_paths.mdb.FnamePrivate, buf, byte_count) ;
+ buf += byte_count ;
+
+ byte_count = ua_strsize(buf) ;
+ memcpy( ems_hand->org_paths.mdb.FnamePublic, buf, byte_count ) ;
+ buf += byte_count ;
+
+ byte_count = ua_strsize(buf) ;
+ memcpy( ems_hand->org_paths.mdb.FnameSystem, buf, byte_count ) ;
+ buf += byte_count ;
+
+ byte_count = ua_strsize(buf) ;
+ memcpy( ems_hand->org_paths.mdb.LogDir, buf, byte_count ) ;
+
+
+ } else {
+
+ byte_count = ua_strsize(buf) ;
+ memcpy( ems_hand->org_paths.dsa.DbPath, buf, byte_count ) ;
+ buf += byte_count ;
+
+ byte_count = ua_strsize(buf) ;
+ memcpy( ems_hand->org_paths.dsa.SystemPath, buf, byte_count ) ;
+
+ buf += byte_count ;
+
+ byte_count = ua_strsize(buf) ;
+ memcpy( ems_hand->org_paths.dsa.LogDir, buf, byte_count ) ;
+
+ }
+
+ *size = ems_hand->pathListSize ;
+ ems_hand->needPathList = FALSE ;
+ return SUCCESS ;
+ }
+
+
+ } else if ( (*((UINT32 UNALIGNED *)buf) > 0) &&
+ U64_EQ( ems_hand->curPos, U64_Init( 0, 0 ) ) ) {
+
+ EMS_STREAM_NAME UNALIGNED *stream_name = (EMS_STREAM_NAME *)buf;
+
+ if ( bufferSize < sizeof(UINT32) ) {
+ *blk_size = sizeof(UINT32) ;
+ bufferSize = 0 ;
+
+ } else if ( stream_name->name_leng + sizeof(UINT32) > bufferSize ) {
+ *blk_size = (UINT16)(stream_name->name_leng + sizeof( UINT32 )) ;
+ bufferSize = 0 ;
+
+ } else {
+ CHAR UNALIGNED *name ;
+ CHAR exch_id = 0 ;
+ CHAR UNALIGNED *p ;
+ CHAR str_name[EMS_MAX_STREAM_NAME_LENG] ;
+
+ p = (CHAR UNALIGNED *)stream_name->name ;
+
+ // name = strrchr((CHAR_PTR)stream_name->name, TEXT('\\') ) ;
+
+ while (*p ) {
+ if (*p == TEXT('\\') ) {
+ name = p ;
+ }
+ p++ ;
+ }
+
+ memcpy( str_name,
+ name,
+ ua_strsize( (char *)name ) ) ;
+
+
+ if ( ua_strsize((char *)stream_name->name) != (INT)stream_name->name_leng ){
+ p = (CHAR UNALIGNED *)stream_name->name ;
+ p += ua_strsize( stream_name->name ) / sizeof(CHAR) ;
+
+ exch_id = *p ;
+ }
+
+ if ( ems_hand->currentStreamId == STRM_EMS_MONO_LOG ) {
+
+ EMS_UpdateRipLogKey( hand,
+ str_name,
+ ems_hand->db_restored ) ;
+
+ } else if ( hand->dblk->com.os_id == FS_EMS_MDB_ID ) {
+
+ res->low_log = 0x7fffffff ;
+
+ ems_hand->db_restored = TRUE ;
+
+ if ( name && BEC_GetEmsPubPri(hand->fsh->cfg) == BEC_EMS_PUBLIC ) {
+ // if this is a private file then skip it.
+
+ if ((exch_id == BFT_MDB_PRIVATE_DATABASE) ||
+ !memcmp( (BYTE_PTR)name,
+ ems_hand->org_paths.mdb.FnamePrivate +
+ strlen(ems_hand->org_paths.mdb.FnamePrivate) -
+ strlen( str_name),
+ ua_strsize( (BYTE_PTR)name ) ) )
+ {
+
+ ems_hand->skip_data = TRUE ;
+ *size = bufferSize;
+ return FS_DONT_WANT_STREAM ;
+ }
+
+ } else if ( name && BEC_GetEmsPubPri(hand->fsh->cfg) == BEC_EMS_PRIVATE ) {
+ // if this is a public file then skip it.
+
+ if ((exch_id == BFT_MDB_PUBLIC_DATABASE) ||
+ !memcmp( (BYTE_PTR)name,
+ ems_hand->org_paths.mdb.FnamePublic +
+ strlen(ems_hand->org_paths.mdb.FnamePublic) -
+ strlen(str_name),
+ ua_strsize( (BYTE_PTR)name ) ) )
+ {
+
+ ems_hand->skip_data = TRUE ;
+ *size = bufferSize;
+ return FS_DONT_WANT_STREAM ;
+ }
+
+ }
+
+ } else if (hand->dblk->com.os_id == FS_EMS_DSA_ID ) {
+
+ res->low_log = 0x7fffffff ;
+ ems_hand->db_restored = TRUE ;
+
+ }
+
+ *size = (UINT16)(stream_name->name_leng + sizeof( UINT32 ) ) ;
+
+ memcpy( str_name,
+ stream_name->name,
+ ua_strsize( stream_name->name ) ) ;
+
+ name = EMS_MungeFname( hand->fsh, hand, str_name, exch_id ) ;
+ if ( name == NULL ) {
+ OMEVENT_LogEMSError ( TEXT("MungeFname()"), -1,str_name ) ;
+ return FS_DEVICE_ERROR ;
+ }
+
+ ems_hand->strm_name.name_leng = ua_strsize( (BYTE_PTR)name) ;
+ memcpy( ems_hand->strm_name.name,
+ (BYTE_PTR)name,
+ ems_hand->strm_name.name_leng ) ;
+
+ ems_hand->fhand = CreateFile( (CHAR_PTR)ems_hand->strm_name.name,
+ GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_SEQUENTIAL_SCAN | FILE_ATTRIBUTE_NORMAL,
+ NULL ) ;
+
+ if ( ems_hand->fhand == INVALID_HANDLE_VALUE ) {
+ ret_val = FS_COMM_FAILURE ;
+ }
+
+ free( name ) ;
+ bufferSize-= *size ;
+ buf += *size ;
+ }
+
+ }
+ }
+
+ if ( ret_val == SUCCESS && bufferSize ) {
+
+ bufferSize = CalcWriteSize( ems_hand->curPos,
+ ems_hand->nextStreamHeaderPos,
+ bufferSize );
+
+ status = WriteFile( ems_hand->fhand,
+ buf,
+ bufferSize,
+ (LPDWORD)&sizeout,
+ NULL ) ;
+
+
+ if ( status ) { // returns TRUE if success
+ *size +=(UINT16)sizeout ;
+ } else {
+ status = GetLastError() ;
+ if ( ( status == ERROR_DISK_FULL ) ||
+ ( status == ERROR_HANDLE_DISK_FULL ) ) {
+
+ return FS_OUT_OF_SPACE ;
+ }
+
+ ret_val = FS_COMM_FAILURE ;
+ OMEVENT_LogEMSError ( TEXT("BackupWrite()"), status, TEXT(" - ") ) ;
+ }
+
+ }
+
+ ems_hand->curPos = U64_Add( ems_hand->curPos,
+ U32_To_U64( (UINT32)*size ),
+ &dummy );
+
+ if ( U64_EQ( ems_hand->curPos, ems_hand->nextStreamHeaderPos ) ) {
+ ddblk->backup_completed = TRUE ;
+
+ if ( (ems_hand->fhand != NULL) &&
+ (ems_hand->fhand != INVALID_HANDLE_VALUE) ) {
+ CloseHandle( ems_hand->fhand ) ;
+ ems_hand->fhand = INVALID_HANDLE_VALUE ;
+ }
+ }
+
+
+ return ret_val ;
+}
+
+
+
+static UINT16 CalcWriteSize( UINT64 startPos,
+ UINT64 endPos,
+ UINT16 buffSize )
+{
+ UINT16 writeSize;
+ BOOLEAN mathStat;
+
+ if ( U64_GT( U64_Add( startPos,
+ U32_To_U64( (UINT32)buffSize ),
+ &mathStat ),
+ endPos ) )
+ {
+ UINT64 rs;
+
+ rs = U64_Sub( endPos,
+ startPos,
+ &mathStat );
+
+ msassert( mathStat && (U64_Msw( rs ) == 0) && (U64_Lsw(rs) < 65536) );
+
+ writeSize = (UINT16)U64_Lsw( rs );
+ } else {
+ writeSize = buffSize;
+ }
+
+ return writeSize;
+}
+
+static CHAR_PTR EMS_MungeFname( FSYS_HAND fsh, FILE_HAND hand, CHAR_PTR name, CHAR exch_id )
+{
+ EMS_OBJ_HAND_PTR ems_hand = (EMS_OBJ_HAND_PTR)(hand->obj_hand.ptr ) ;
+ EMS_FSYS_RESERVED_PTR resPtr = hand->fsh->reserved.ptr ;
+ CHAR_PTR new_name = NULL ;
+ CHAR_PTR p,q ;
+ CHAR_PTR fname ;
+ CHAR_PTR old_name ;
+
+ // first make sure the name is at least reasonable so our parsing can make some assumptions
+
+ if ( !strchr(name, TEXT('\\') ) ) {
+ return NULL ;
+ }
+
+ // I will compare the paths backwards. So I need the end of the input path.
+
+ old_name = calloc( strsize( name ), 1 ) ;
+ if ( old_name ) {
+ strcpy( old_name, name ) ;
+ }
+
+ fname = strrchr( name, TEXT('\\') ) ;
+
+ switch (exch_id ) {
+ case BFT_MDB_PRIVATE_DATABASE:
+ new_name = EMS_BuildMungedName( fsh, resPtr->paths.mdb.FnamePrivate, NULL ) ;
+ EMS_AddToJetRstmap( hand, old_name, new_name ) ;
+ break ;
+
+ case BFT_MDB_PUBLIC_DATABASE:
+ new_name = EMS_BuildMungedName( fsh, resPtr->paths.mdb.FnamePublic, NULL ) ;
+ EMS_AddToJetRstmap( hand, old_name, new_name ) ;
+ break ;
+
+ case BFT_DSA_DATABASE:
+ new_name = EMS_BuildMungedName( fsh, resPtr->paths.dsa.DbPath, NULL ) ;
+ EMS_AddToJetRstmap( hand, old_name, new_name ) ;
+ break ;
+
+ case BFT_LOG :
+ case BFT_PATCH_FILE :
+ if ( fsh->attached_dle->info.xserv->type == EMS_DSA ) {
+ new_name = EMS_BuildMungedName( fsh, resPtr->paths.dsa.LogDir, fname+1 ) ;
+ } else {
+ new_name = EMS_BuildMungedName( fsh, resPtr->paths.mdb.LogDir, fname+1 ) ;
+ }
+ break ;
+
+ default:
+ if ( fsh->attached_dle->info.xserv->type == EMS_DSA ) {
+ if ( EMS_PathMatch( name, ems_hand->org_paths.dsa.DbPath ) ) {
+ new_name = EMS_BuildMungedName( fsh, resPtr->paths.dsa.DbPath, NULL ) ;
+ EMS_AddToJetRstmap( hand, old_name, new_name ) ;
+
+
+ } else if ( EMS_PathMatch( name, ems_hand->org_paths.dsa.SystemPath ) ) {
+ new_name = EMS_BuildMungedName( fsh, resPtr->paths.dsa.SystemPath, NULL ) ;
+ EMS_AddToJetRstmap( hand, old_name, new_name ) ;
+
+ } else {
+
+ *fname = TEXT('\0') ;
+
+ if ( EMS_PathMatch( name, ems_hand->org_paths.dsa.LogDir ) ) {
+
+ strcpy( resPtr->BackupLogPath, name ) ;
+ *fname = TEXT('\\') ;
+ new_name = EMS_BuildMungedName( fsh, resPtr->paths.dsa.LogDir, fname+1 ) ;
+
+ } else if ( EMS_PathMatch( name, ems_hand->org_paths.dsa.SystemPath ) ) {
+
+ *fname = TEXT('\\') ;
+ new_name = EMS_BuildMungedName( fsh, resPtr->paths.dsa.SystemPath, fname+1 ) ;
+ }
+ }
+
+ } else {
+ if ( EMS_PathMatch( name, ems_hand->org_paths.mdb.FnameSystem ) ) {
+ new_name = EMS_BuildMungedName( fsh, resPtr->paths.mdb.FnameSystem, NULL ) ;
+ EMS_AddToJetRstmap( hand, old_name, new_name ) ;
+
+ } else if ( EMS_PathMatch( name, ems_hand->org_paths.mdb.FnamePublic ) ) {
+ new_name = EMS_BuildMungedName( fsh, resPtr->paths.mdb.FnamePublic, NULL ) ;
+ EMS_AddToJetRstmap( hand, old_name, new_name ) ;
+
+ } else if ( EMS_PathMatch( name, ems_hand->org_paths.mdb.FnamePrivate ) ) {
+ new_name = EMS_BuildMungedName( fsh, resPtr->paths.mdb.FnamePrivate, NULL ) ;
+ EMS_AddToJetRstmap( hand, old_name, new_name ) ;
+
+
+ } else {
+ *fname = TEXT('\0') ;
+
+ if ( EMS_PathMatch( name, ems_hand->org_paths.mdb.LogDir ) ) {
+ strcpy( resPtr->BackupLogPath, name ) ;
+ *fname = TEXT('\\') ;
+ new_name = EMS_BuildMungedName( fsh, resPtr->paths.mdb.LogDir, fname+1 ) ;
+
+ } else if ( EMS_PathMatch( name, ems_hand->org_paths.mdb.FnameSystem ) ) {
+ *fname = TEXT('\\') ;
+ new_name = EMS_BuildMungedName( fsh, resPtr->paths.mdb.FnameSystem, fname+1 ) ;
+
+ }
+
+ }
+ }
+ }
+
+ free( old_name ) ;
+
+ return new_name ;
+}
+
+BOOLEAN EMS_PathMatch( CHAR_PTR p_start, CHAR_PTR q_start )
+{
+ CHAR_PTR q_end ;
+ CHAR_PTR p_end ;
+
+ p_end = p_start + strlen(p_start) -1 ;
+ q_end = q_start + strlen(q_start) -1 ;
+
+ if (*p_end == TEXT('\\') ) {
+ p_end -- ;
+ }
+ if (*q_end == TEXT('\\') ) {
+ q_end -- ;
+ }
+
+ do {
+ if (toupper(*p_end) != toupper(*q_end) ) {
+ if ( *p_end == TEXT('$') ) {
+ if ( (*q_end != TEXT('$')) && (*q_end != TEXT(':')) ) {
+ return FALSE ;
+ }
+ p_end --; q_end -- ;
+ if ( toupper(*p_end) == toupper(*q_end) ) {
+ return TRUE ;
+ }
+ }
+ return FALSE ;
+ }
+ p_end --; q_end -- ;
+
+ } while ( q_end != q_start ) ;
+
+ return TRUE ;
+}
+
+
+CHAR_PTR EMS_BuildMungedName( FSYS_HAND fsh, CHAR_PTR new_path, CHAR_PTR fname )
+{
+ INT size ;
+ CHAR_PTR new_name ;
+ CHAR_PTR p ;
+
+ // sizeof "\\servername"
+ size = strsize( fsh->attached_dle->parent->device_name ) + 4;
+
+ // sizeof C$\path
+
+ size += strsize( new_path ) ;
+
+ if ( fname ) {
+ size += strsize(fname) ;
+ }
+
+ new_name = calloc( size, 1 ) ;
+
+ if ( new_name ) {
+ if ( strncmp( new_path, TEXT("\\\\"), 2 ) ) {
+ strcpy( new_name, TEXT("\\\\") ) ;
+ strcat( new_name, fsh->attached_dle->parent->device_name ) ;
+ strcat( new_name, TEXT("\\") ) ;
+ }
+ strcat( new_name, new_path ) ;
+ if ( fname) {
+ if ( new_name[strlen(new_name) -1] != TEXT('\\') ) {
+ strcat( new_name, TEXT("\\") ) ;
+ }
+ strcat( new_name, fname ) ;
+ }
+
+ p = strchr( new_name, TEXT(':') ) ;
+
+ if ( p ) {
+ *p = TEXT('$') ;
+ }
+ }
+
+ return ( new_name ) ;
+}
+
+
+
+VOID EMS_UpdateRipLogKey( FILE_HAND hand, CHAR_PTR log_name, BOOLEAN low_able )
+{
+ EMS_FSYS_RESERVED_PTR res = hand->fsh->reserved.ptr;
+ CHAR_PTR p, endp ;
+ CHAR_PTR dummy ;
+ CHAR_PTR key_name;
+ ULONG log_num = 0x7fffffff;
+
+ endp = p = strrchr( log_name, TEXT('.') ) ;
+ if (stricmp( endp, TEXT(".log") ) ) {
+ return ;
+ }
+
+ if (p) {
+ p-=5 ;
+ *endp = TEXT('\0') ;
+ log_num = wcstoul( p, &dummy, 16 ) ;
+
+ *endp = TEXT('.') ;
+ }
+
+ if ( low_able && log_num ) {
+ if ( log_num < res->low_log ) {
+ res->low_log = log_num ;
+ }
+ }
+
+ if ( log_num > res->high_log ) {
+ res->high_log = log_num ;
+ }
+
+}
+
+
+VOID EMS_AddToJetRstmap( FILE_HAND hand, CHAR_PTR old_name, CHAR_PTR new_name )
+{
+ EMS_FSYS_RESERVED_PTR res = hand->fsh->reserved.ptr;
+ CHAR_PTR name_ptr ;
+ INT i ;
+
+ name_ptr = res->jet_rstmap ;
+
+ if ( ( new_name == NULL ) || ( old_name == NULL ) ) {
+ return ;
+ }
+
+ for ( i = 0 ; i < 3; i ++ ) {
+
+ if (*name_ptr == TEXT('\0') ) {
+ break ;
+ }
+
+ if ( !stricmp( old_name, name_ptr ) ) {
+ return ;
+ }
+
+ /* this assumes that we always write in pares */
+ name_ptr += strlen( name_ptr ) + 1 ;
+ name_ptr += strlen( name_ptr ) + 1 ;
+ }
+
+ if ( i != 3 ) {
+ strcpy( name_ptr, old_name ) ;
+ name_ptr += strlen( name_ptr ) + 1 ;
+ strcpy( name_ptr, new_name ) ;
+ name_ptr += strlen( name_ptr ) + 1 ;
+ *name_ptr = TEXT('\0') ;
+ res->map_size = i+1 ;
+ }
+}
+
+
+static INT ua_strsize( BYTE_PTR buf )
+{
+ INT align_factor;
+ INT byte_count ;
+
+ align_factor = sizeof(CHAR) -1 ;
+
+ if ( (DWORD)buf & align_factor ) { // if unaligned
+ byte_count = sizeof(CHAR) ;
+ while( ( *buf != 0 ) && ( (*buf+1) != 0) ){
+ buf+=sizeof(CHAR) ;
+ byte_count +=sizeof(CHAR);
+ }
+ } else {
+ byte_count = strsize( (CHAR_PTR)buf ) ;
+ }
+ return byte_count ;
+}
+
+
diff --git a/private/utils/ntbackup/src/yprintf.c b/private/utils/ntbackup/src/yprintf.c
new file mode 100644
index 000000000..ad5723868
--- /dev/null
+++ b/private/utils/ntbackup/src/yprintf.c
@@ -0,0 +1,120 @@
+/*****************************************************************************
+ Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: yprintf.c
+
+ Description: Replacement status printf functions for "T" commands that
+ do not use windows
+
+
+ $Log: G:/UI/LOGFILES/YPRINTF.C_V $
+
+ Rev 1.10 26 Jul 1993 17:56:24 MARINA
+enable c++
+
+ Rev 1.9 07 Oct 1992 14:50:00 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.8 04 Oct 1992 19:44:20 DAVEV
+Unicode Awk pass
+
+ Rev 1.7 17 Aug 1992 13:25:44 DAVEV
+MikeP's changes at Microsoft
+
+ Rev 1.6 28 Jul 1992 14:53:26 CHUCKB
+Fixed warnings for NT.
+
+ Rev 1.5 10 Jun 1992 08:58:32 BURT
+Fixed prototype to be ANSI
+
+ Rev 1.4 19 May 1992 11:58:38 MIKEP
+mips changes
+
+ Rev 1.3 18 May 1992 09:06:44 MIKEP
+header
+
+ Rev 1.2 29 Jan 1992 17:58:42 DAVEV
+
+
+ * added include <windows.h>
+
+ Rev 1.1 10 Dec 1991 21:19:50 MIKEP
+fix msassert call
+
+ Rev 1.0 20 Nov 1991 19:17:10 SYSTEM
+Initial revision.
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+/*****************************************************************************
+
+ Name: yresprintf
+
+ Description: This function displays a message from SES_ENG_ERR
+
+ THIS IS A SPECIAL FUNCTION SPECIFICALLY
+ FOR THE "T" COMMANDS...NO WINDOWS ARE USED
+
+ Modified: 2/10/1990
+
+ Returns: VOID
+
+ Notes: calls tprintf( )
+
+*****************************************************************************/
+VOID yresprintf( INT res_id, ... )
+{
+ UINT16 error ;
+ CHAR_PTR fmt ;
+ UINT16 tmp ;
+ va_list arg_ptr ;
+
+ fmt = (LPSTR)RM_GetResource( rm, SES_ENG_MSG, res_id, &tmp, &error ) ;
+ msassert( fmt != NULL );
+
+ va_start( arg_ptr, res_id ) ;
+ tprintf( fmt, arg_ptr ) ;
+ va_end( arg_ptr ) ;
+
+ return ;
+
+}
+
+/*****************************************************************************
+
+ Name: yprintf
+
+ Description: This function displays a message
+
+ THIS IS A SPECIAL FUNCTION SPECIFICALLY
+ FOR THE "T" COMMANDS...NO WINDOWS ARE USED
+
+ Returns: VOID
+
+ Notes: calls tprintf( )
+
+*****************************************************************************/
+VOID yprintf( CHAR_PTR fmt, ... )
+{
+ va_list arg_ptr ;
+
+ va_start( arg_ptr, fmt ) ;
+ tprintf( fmt, arg_ptr ) ;
+ va_end( arg_ptr ) ;
+
+ return ;
+
+}
+
+
+
+
+
+
+
diff --git a/private/utils/ntbackup/src/zprintf.c b/private/utils/ntbackup/src/zprintf.c
new file mode 100644
index 000000000..2ac2195ca
--- /dev/null
+++ b/private/utils/ntbackup/src/zprintf.c
@@ -0,0 +1,111 @@
+/*****************************************************************************
+Copyright(c) Maynard Electronics, Inc. 1984-89
+
+ Name: zprintf.c
+
+ Date Updated: $./FDT$ $./FTM$
+
+ Description:
+
+ $Log: G:/UI/LOGFILES/ZPRINTF.C_V $
+
+ Rev 1.7 07 Oct 1992 14:49:46 DARRYLP
+Precompiled header revisions.
+
+ Rev 1.6 04 Oct 1992 19:44:22 DAVEV
+Unicode Awk pass
+
+ Rev 1.5 30 Sep 1992 10:41:24 DAVEV
+Unicode strlen verification, MikeP's chgs from MS
+
+ Rev 1.4 19 May 1992 11:58:50 MIKEP
+mips changes
+
+ Rev 1.3 14 May 1992 16:51:08 MIKEP
+nt pass 2
+
+ Rev 1.2 07 Feb 1992 16:23:20 JOHNWT
+removed use of tprint buffer
+
+ Rev 1.1 03 Feb 1992 16:37:40 DAVEV
+added include <windows.h> to resolve error in muiconf.h: WORD undefined
+
+ Rev 1.0 20 Nov 1991 19:17:16 SYSTEM
+Initial revision.
+
+*****************************************************************************/
+
+#include "all.h"
+
+#ifdef SOME
+#include "some.h"
+#endif
+
+/*****************************************************************************
+
+ Name: zprintf
+
+ Description: This function displays a debug message
+
+ Modified: 2/10/1990
+
+ Returns: VOID
+
+*****************************************************************************/
+
+VOID zprintf( UINT16 mask_bits, ... )
+{
+ va_list arg_ptr ;
+
+ va_start( arg_ptr, mask_bits ) ;
+
+ zvprintf( mask_bits, arg_ptr ) ;
+
+ va_end( arg_ptr ) ;
+
+ return ;
+}
+
+/*****************************************************************************
+
+ Name: zvprintf
+
+ Description: This function displays a debug message
+
+ Modified: 2/7/1992
+
+ Returns: VOID
+
+ Notes:
+
+*****************************************************************************/
+
+VOID zvprintf( UINT16 mask_bits, va_list arg_list )
+{
+ CDS_PTR conf_ptr = CDS_GetCopy( ) ;
+ CHAR_PTR fmt ;
+ UINT16 res_num ;
+ TCHAR buffer[ MAX_UI_RESOURCE_SIZE ];
+
+ if( ( CDS_GetDebugFlag( conf_ptr ) & mask_bits ) ||
+ ( (mask_bits == 0) && CDS_GetDebugFlag( conf_ptr ) ) ) {
+
+ if ( mask_bits != 0 ) {
+ res_num = va_arg( arg_list, UINT16 );
+ fmt = ( CHAR_PTR ) RM_GetResource( rm, SES_ENG_DBUG, res_num, NULL, NULL );
+ msassert( fmt != NULL );
+ }
+ else {
+ fmt = va_arg( arg_list, CHAR_PTR );
+ }
+
+ vsprintf( buffer, fmt, arg_list ) ;
+
+ msassert( strlen( buffer ) <= MAX_UI_RESOURCE_SIZE ) ;
+
+ DBM_InsertItem( buffer );
+
+ }
+
+ return ;
+}
diff --git a/private/utils/ntlib/dirs b/private/utils/ntlib/dirs
new file mode 100644
index 000000000..c4db5a979
--- /dev/null
+++ b/private/utils/ntlib/dirs
@@ -0,0 +1,16 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+!ENDIF
+
+DIRS= src
diff --git a/private/utils/ntlib/src/boothack.cxx b/private/utils/ntlib/src/boothack.cxx
new file mode 100644
index 000000000..f47ac1892
--- /dev/null
+++ b/private/utils/ntlib/src/boothack.cxx
@@ -0,0 +1,26 @@
+#include <pch.cxx>
+#include "ulib.hxx"
+
+PCCLASS_DESCRIPTOR BUFFER_STREAM_cd;
+PCCLASS_DESCRIPTOR BYTE_STREAM_cd;
+PCCLASS_DESCRIPTOR COMM_DEVICE_cd;
+PCCLASS_DESCRIPTOR FILE_STREAM_cd;
+PCCLASS_DESCRIPTOR FSNODE_cd;
+PCCLASS_DESCRIPTOR FSN_DIRECTORY_cd;
+PCCLASS_DESCRIPTOR FSN_FILE_cd;
+PCCLASS_DESCRIPTOR FSN_FILTER_cd;
+PCCLASS_DESCRIPTOR KEYBOARD_cd;
+PCCLASS_DESCRIPTOR MULTIPLE_PATH_ARGUMENT_cd;
+PCCLASS_DESCRIPTOR PATH_ARGUMENT_cd;
+PCCLASS_DESCRIPTOR PATH_cd;
+PCCLASS_DESCRIPTOR PIPE_cd;
+PCCLASS_DESCRIPTOR PIPE_STREAM_cd;
+PCCLASS_DESCRIPTOR PRINT_STREAM_cd;
+PCCLASS_DESCRIPTOR PROGRAM_cd;
+PCCLASS_DESCRIPTOR SCREEN_cd;
+PCCLASS_DESCRIPTOR STREAM_MESSAGE_cd;
+PCCLASS_DESCRIPTOR STREAM_cd;
+PCCLASS_DESCRIPTOR STRING_ARRAY_cd;
+PCCLASS_DESCRIPTOR TIMEINFO_ARGUMENT_cd;
+PCCLASS_DESCRIPTOR TIMEINFO_cd;
+PCCLASS_DESCRIPTOR REST_OF_LINE_ARGUMENT_cd;
diff --git a/private/utils/ntlib/src/makefile b/private/utils/ntlib/src/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/ntlib/src/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/ntlib/src/makefile.inc b/private/utils/ntlib/src/makefile.inc
new file mode 100644
index 000000000..bcd259757
--- /dev/null
+++ b/private/utils/ntlib/src/makefile.inc
@@ -0,0 +1,326 @@
+rtmsg.rc: msg00001.bin
+
+rtmsg.h msg00001.bin: rtmsg.mc
+ mc -v -h .\ rtmsg.mc
+
+
+
+#
+# From ULIB
+#
+achkmsg.cxx : ..\..\ulib\src\achkmsg.cxx
+ copy ..\..\ulib\src\achkmsg.cxx .
+
+array.cxx : ..\..\ulib\src\array.cxx
+ copy ..\..\ulib\src\array.cxx .
+
+arrayit.cxx : ..\..\ulib\src\arrayit.cxx
+ copy ..\..\ulib\src\arrayit.cxx .
+
+basesys.cxx : ..\..\ulib\src\basesys.cxx
+ copy ..\..\ulib\src\basesys.cxx .
+
+bitvect.cxx : ..\..\ulib\src\bitvect.cxx
+ copy ..\..\ulib\src\bitvect.cxx .
+
+contain.cxx : ..\..\ulib\src\contain.cxx
+ copy ..\..\ulib\src\contain.cxx .
+
+clasdesc.cxx : ..\..\ulib\src\clasdesc.cxx
+ copy ..\..\ulib\src\clasdesc.cxx .
+
+cmem.cxx : ..\..\ulib\src\cmem.cxx
+ copy ..\..\ulib\src\cmem.cxx .
+
+hmem.cxx : ..\..\ulib\src\hmem.cxx
+ copy ..\..\ulib\src\hmem.cxx .
+
+iterator.cxx : ..\..\ulib\src\iterator.cxx
+ copy ..\..\ulib\src\iterator.cxx .
+
+list.cxx : ..\..\ulib\src\list.cxx
+ copy ..\..\ulib\src\list.cxx .
+
+listit.cxx : ..\..\ulib\src\listit.cxx
+ copy ..\..\ulib\src\listit.cxx .
+
+machine.cxx : ..\..\ulib\src\machine.cxx
+ copy ..\..\ulib\src\machine.cxx .
+
+mem.cxx : ..\..\ulib\src\mem.cxx
+ copy ..\..\ulib\src\mem.cxx .
+
+membmgr.cxx : ..\..\ulib\src\membmgr.cxx
+ copy ..\..\ulib\src\membmgr.cxx .
+
+message.cxx : ..\..\ulib\src\message.cxx
+ copy ..\..\ulib\src\message.cxx .
+
+newdel.cxx : ..\..\ulib\src\newdel.cxx
+ copy ..\..\ulib\src\newdel.cxx .
+
+object.cxx : ..\..\ulib\src\object.cxx
+ copy ..\..\ulib\src\object.cxx .
+
+prnthack.cxx : ..\..\ulib\src\prnthack.cxx
+ copy ..\..\ulib\src\prnthack.cxx .
+
+rtmsg.mc : ..\..\ulib\src\rtmsg.mc
+ copy ..\..\ulib\src\rtmsg.mc .
+
+seqcnt.cxx : ..\..\ulib\src\seqcnt.cxx
+ copy ..\..\ulib\src\seqcnt.cxx .
+
+sortcnt.cxx : ..\..\ulib\src\sortcnt.cxx
+ copy ..\..\ulib\src\sortcnt.cxx .
+
+sortlist.cxx : ..\..\ulib\src\sortlist.cxx
+ copy ..\..\ulib\src\sortlist.cxx .
+
+sortlit.cxx : ..\..\ulib\src\sortlit.cxx
+ copy ..\..\ulib\src\sortlit.cxx .
+
+spackmsg.cxx : ..\..\ulib\src\spackmsg.cxx
+ copy ..\..\ulib\src\spackmsg.cxx .
+
+ulib.cxx : ..\..\ulib\src\ulib.cxx
+ copy ..\..\ulib\src\ulib.cxx .
+
+wstring.cxx : ..\..\ulib\src\wstring.cxx
+ copy ..\..\ulib\src\wstring.cxx .
+
+arg.cxx : ..\..\ulib\src\arg.cxx
+ copy ..\..\ulib\src\arg.cxx .
+
+
+
+#
+# From IFSUTIL
+#
+bigint.cxx : ..\..\ifsutil\src\bigint.cxx
+ copy ..\..\ifsutil\src\bigint.cxx .
+
+cache.cxx : ..\..\ifsutil\src\cache.cxx
+ copy ..\..\ifsutil\src\cache.cxx .
+
+cannedsd.cxx : ..\..\ifsutil\src\cannedsd.cxx
+ copy ..\..\ifsutil\src\cannedsd.cxx .
+
+digraph.cxx : ..\..\ifsutil\src\digraph.cxx
+ copy ..\..\ifsutil\src\digraph.cxx .
+
+drive.cxx : ..\..\ifsutil\src\drive.cxx
+ copy ..\..\ifsutil\src\drive.cxx .
+
+ifssys.cxx : ..\..\ifsutil\src\ifssys.cxx
+ copy ..\..\ifsutil\src\ifssys.cxx .
+
+ifsutil.cxx : ..\..\ifsutil\src\ifsutil.cxx
+ copy ..\..\ifsutil\src\ifsutil.cxx .
+
+intstack.cxx : ..\..\ifsutil\src\intstack.cxx
+ copy ..\..\ifsutil\src\intstack.cxx .
+
+numset.cxx : ..\..\ifsutil\src\numset.cxx
+ copy ..\..\ifsutil\src\numset.cxx .
+
+secrun.cxx : ..\..\ifsutil\src\secrun.cxx
+ copy ..\..\ifsutil\src\secrun.cxx .
+
+supera.cxx : ..\..\ifsutil\src\supera.cxx
+ copy ..\..\ifsutil\src\supera.cxx .
+
+volume.cxx : ..\..\ifsutil\src\volume.cxx
+ copy ..\..\ifsutil\src\volume.cxx .
+
+autoentr.cxx : ..\..\ifsutil\src\autoentr.cxx
+ copy ..\..\ifsutil\src\autoentr.cxx .
+
+autoreg.cxx : ..\..\ifsutil\src\autoreg.cxx
+ copy ..\..\ifsutil\src\autoreg.cxx .
+
+bootreg.c :
+ copy ..\..\ifsutil\src\bootreg.c
+
+dcache.cxx : ..\..\ifsutil\src\dcache.cxx
+ copy ..\..\ifsutil\src\dcache.cxx .
+
+rcache.cxx : ..\..\ifsutil\src\rcache.cxx
+ copy ..\..\ifsutil\src\rcache.cxx .
+
+rwcache.cxx : ..\..\ifsutil\src\rwcache.cxx
+ copy ..\..\ifsutil\src\rwcache.cxx .
+
+
+#
+# From UFAT
+#
+cluster.cxx : ..\..\ufat\src\cluster.cxx
+ copy ..\..\ufat\src\cluster.cxx .
+
+eaheader.cxx : ..\..\ufat\src\eaheader.cxx
+ copy ..\..\ufat\src\eaheader.cxx .
+
+easet.cxx : ..\..\ufat\src\easet.cxx
+ copy ..\..\ufat\src\easet.cxx .
+
+fat.cxx : ..\..\ufat\src\fat.cxx
+ copy ..\..\ufat\src\fat.cxx .
+
+fatdent.cxx : ..\..\ufat\src\fatdent.cxx
+ copy ..\..\ufat\src\fatdent.cxx .
+
+fatdir.cxx : ..\..\ufat\src\fatdir.cxx
+ copy ..\..\ufat\src\fatdir.cxx .
+
+fatsa.cxx : ..\..\ufat\src\fatsa.cxx
+ copy ..\..\ufat\src\fatsa.cxx .
+
+rfatsa.cxx : ..\..\ufat\src\rfatsa.cxx
+ copy ..\..\ufat\src\rfatsa.cxx .
+
+fatdbsa.cxx : ..\..\ufat\src\fatdbsa.cxx
+ copy ..\..\ufat\src\fatdbsa.cxx .
+
+cvfexts.cxx : ..\..\ufat\src\cvfexts.cxx
+ copy ..\..\ufat\src\cvfexts.cxx .
+
+fatsachk.cxx : ..\..\ufat\src\fatsachk.cxx
+ copy ..\..\ufat\src\fatsachk.cxx .
+
+fatsacnv.cxx : ..\..\ufat\src\fatsacnv.cxx
+ copy ..\..\ufat\src\fatsacnv.cxx .
+
+fatvol.cxx : ..\..\ufat\src\fatvol.cxx
+ copy ..\..\ufat\src\fatvol.cxx .
+
+fatdbvol.cxx : ..\..\ufat\src\fatdbvol.cxx
+ copy ..\..\ufat\src\fatdbvol.cxx .
+
+filedir.cxx : ..\..\ufat\src\filedir.cxx
+ copy ..\..\ufat\src\filedir.cxx .
+
+reloclus.cxx : ..\..\ufat\src\reloclus.cxx
+ copy ..\..\ufat\src\reloclus.cxx .
+
+rootdir.cxx : ..\..\ufat\src\rootdir.cxx
+ copy ..\..\ufat\src\rootdir.cxx .
+
+ufat.cxx : ..\..\ufat\src\ufat.cxx
+ copy ..\..\ufat\src\ufat.cxx .
+
+mrcf.c : ..\..\ufat\src\mrcf.c
+ copy ..\..\ufat\src\mrcf.c .
+
+
+
+#
+# From UNTFS
+#
+attrcol.cxx : ..\..\untfs\src\attrcol.cxx
+ copy ..\..\untfs\src\attrcol.cxx .
+
+attrdef.cxx : ..\..\untfs\src\attrdef.cxx
+ copy ..\..\untfs\src\attrdef.cxx .
+
+attrib.cxx : ..\..\untfs\src\attrib.cxx
+ copy ..\..\untfs\src\attrib.cxx .
+
+attrlist.cxx : ..\..\untfs\src\attrlist.cxx
+ copy ..\..\untfs\src\attrlist.cxx .
+
+attrrec.cxx : ..\..\untfs\src\attrrec.cxx
+ copy ..\..\untfs\src\attrrec.cxx .
+
+badfile.cxx : ..\..\untfs\src\badfile.cxx
+ copy ..\..\untfs\src\badfile.cxx .
+
+bitfrs.cxx : ..\..\untfs\src\bitfrs.cxx
+ copy ..\..\untfs\src\bitfrs.cxx .
+
+bootfile.cxx : ..\..\untfs\src\bootfile.cxx
+ copy ..\..\untfs\src\bootfile.cxx .
+
+clusrun.cxx : ..\..\untfs\src\clusrun.cxx
+ copy ..\..\untfs\src\clusrun.cxx .
+
+extents.cxx : ..\..\untfs\src\extents.cxx
+ copy ..\..\untfs\src\extents.cxx .
+
+format.cxx : ..\..\untfs\src\format.cxx
+ copy ..\..\untfs\src\format.cxx .
+
+frs.cxx : ..\..\untfs\src\frs.cxx
+ copy ..\..\untfs\src\frs.cxx .
+
+frsstruc.cxx : ..\..\untfs\src\frsstruc.cxx
+ copy ..\..\untfs\src\frsstruc.cxx .
+
+hackwc.cxx : ..\..\untfs\src\hackwc.cxx
+ copy ..\..\untfs\src\hackwc.cxx .
+
+indxbuff.cxx : ..\..\untfs\src\indxbuff.cxx
+ copy ..\..\untfs\src\indxbuff.cxx .
+
+indxchk.cxx : ..\..\untfs\src\indxchk.cxx
+ copy ..\..\untfs\src\indxchk.cxx .
+
+indxroot.cxx : ..\..\untfs\src\indxroot.cxx
+ copy ..\..\untfs\src\indxroot.cxx .
+
+indxtree.cxx : ..\..\untfs\src\indxtree.cxx
+ copy ..\..\untfs\src\indxtree.cxx .
+
+largemcb.c : ..\..\untfs\src\largemcb.c
+ copy ..\..\untfs\src\largemcb.c
+
+logfile.cxx : ..\..\untfs\src\logfile.cxx
+ copy ..\..\untfs\src\logfile.cxx .
+
+mft.cxx : ..\..\untfs\src\mft.cxx
+ copy ..\..\untfs\src\mft.cxx .
+
+mftfile.cxx : ..\..\untfs\src\mftfile.cxx
+ copy ..\..\untfs\src\mftfile.cxx .
+
+mftref.cxx : ..\..\untfs\src\mftref.cxx
+ copy ..\..\untfs\src\mftref.cxx .
+
+ntfsbit.cxx : ..\..\untfs\src\ntfsbit.cxx
+ copy ..\..\untfs\src\ntfsbit.cxx .
+
+ntfschk.cxx : ..\..\untfs\src\ntfschk.cxx
+ copy ..\..\untfs\src\ntfschk.cxx .
+
+ntfssa.cxx : ..\..\untfs\src\ntfssa.cxx
+ copy ..\..\untfs\src\ntfssa.cxx .
+
+ntfsvol.cxx : ..\..\untfs\src\ntfsvol.cxx
+ copy ..\..\untfs\src\ntfsvol.cxx .
+
+sdchk.cxx : ..\..\untfs\src\sdchk.cxx
+ copy ..\..\untfs\src\sdchk.cxx .
+
+untfs.cxx : ..\..\untfs\src\untfs.cxx
+ copy ..\..\untfs\src\untfs.cxx .
+
+upcase.cxx : ..\..\untfs\src\upcase.cxx
+ copy ..\..\untfs\src\upcase.cxx .
+
+upfile.cxx : ..\..\untfs\src\upfile.cxx
+ copy ..\..\untfs\src\upfile.cxx .
+
+
+
+#
+# From CUFAT
+#
+convfat.cxx : ..\..\cufat\src\convfat.cxx
+ copy ..\..\cufat\src\convfat.cxx .
+
+cufat.cxx : ..\..\cufat\src\cufat.cxx
+ copy ..\..\cufat\src\cufat.cxx .
+
+fatntfs.cxx : ..\..\cufat\src\fatntfs.cxx
+ copy ..\..\cufat\src\fatntfs.cxx .
+
diff --git a/private/utils/ntlib/src/pch.cxx b/private/utils/ntlib/src/pch.cxx
new file mode 100644
index 000000000..dd67a718f
--- /dev/null
+++ b/private/utils/ntlib/src/pch.cxx
@@ -0,0 +1,125 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ pch.cxx
+
+Abstract:
+
+ This module implements pre-compiled headers for ntlib.
+
+Author:
+
+ Matthew Bradburn (mattbr) 26-Apr-1994
+
+--*/
+
+//
+// ULIB headers.
+//
+
+#include "ulib.hxx"
+#if defined(JAPAN) && defined(_X86_)
+#include "machine.hxx"
+#endif // defined(JAPAN) && defined(_X86_)
+#include "smsg.hxx"
+#include "cmem.hxx"
+#include "basesys.hxx"
+#include "buffer.hxx"
+#include "contain.hxx"
+#include "hmem.hxx"
+#include "achkmsg.hxx"
+#include "error.hxx"
+#include "ifsentry.hxx"
+#include "ifsserv.hxx"
+#include "iterator.hxx"
+#include "list.hxx"
+#include "listit.hxx"
+#include "mem.hxx"
+#include "membmgr.hxx"
+#include "program.hxx"
+#include "rtmsg.h"
+#include "seqcnt.hxx"
+#include "sortcnt.hxx"
+#include "sortlist.hxx"
+#include "sortlit.hxx"
+#include "string.hxx"
+#include "stringar.hxx"
+#include "substrng.hxx"
+#include "ulibcl.hxx"
+#include "object.hxx"
+#include "clasdesc.hxx"
+
+
+//
+// IFSUTIL headers.
+//
+
+#include "autoentr.hxx"
+#include "autoreg.hxx"
+#include "bigint.hxx"
+#include "bpb.hxx"
+#include "cache.hxx"
+#include "cannedsd.hxx"
+#include "dcache.hxx"
+#include "digraph.hxx"
+#include "drive.hxx"
+#include "ifssys.hxx"
+#include "intstack.hxx"
+#include "mldcopy.hxx"
+#include "numset.hxx"
+#include "rcache.hxx"
+#include "rwcache.hxx"
+#include "secrun.hxx"
+#include "supera.hxx"
+#include "volume.hxx"
+
+//
+// UFAT headers.
+//
+
+#include "cluster.hxx"
+#include "eaheader.hxx"
+#include "easet.hxx"
+#include "fat.hxx"
+#include "fatdent.hxx"
+#include "fatdir.hxx"
+#include "fatsa.hxx"
+#include "fatvol.hxx"
+#include "filedir.hxx"
+#include "reloclus.hxx"
+#include "rfatsa.hxx"
+#include "rootdir.hxx"
+
+//
+// UNTFS headers.
+//
+
+#include "untfs.hxx"
+#include "attrcol.hxx"
+#include "attrdef.hxx"
+#include "attrib.hxx"
+#include "attrlist.hxx"
+#include "attrrec.hxx"
+#include "badfile.hxx"
+#include "bitfrs.hxx"
+#include "bootfile.hxx"
+#include "clusrun.hxx"
+#include "extents.hxx"
+#include "frs.hxx"
+#include "frsstruc.hxx"
+#include "hackwc.hxx"
+#include "indxbuff.hxx"
+#include "indxroot.hxx"
+#include "indxtree.hxx"
+#include "logfile.hxx"
+#include "mft.hxx"
+#include "mftfile.hxx"
+#include "mftref.hxx"
+#include "ntfsbit.hxx"
+#include "ntfssa.hxx"
+#include "ntfsvol.hxx"
+#include "upcase.hxx"
+#include "upfile.hxx"
diff --git a/private/utils/ntlib/src/sources b/private/utils/ntlib/src/sources
new file mode 100644
index 000000000..6fbaf5f50
--- /dev/null
+++ b/private/utils/ntlib/src/sources
@@ -0,0 +1,254 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in $(BASEDIR)\bak\bin\sources.tpl
+
+!ENDIF
+
+BLDCRT=1
+
+MAJORCOMP=utils
+MINORCOMP=ntlib
+
+TARGETNAME=ntlib
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+# The following is stuff so people do not have to enlisted in ofs to build the loader.
+!IF EXIST($(BASEDIR)\private\ofs\h\ofsdisk.h)
+OFS_INCLUDE=;$(BASEDIR)\private\ofs\h
+OFS_DEFINE=-DINCLUDE_OFS
+!ELSEIF EXIST($(BASEDIR)\private\ofs.pri\h\ofsdisk.h)
+OFS_INCLUDE=;$(BASEDIR)\private\ofs.pri\h
+OFS_DEFINE=-DINCLUDE_OFS
+!ENDIF
+
+PRECOMPILED_INCLUDE= pch.cxx
+
+SOURCES=rtmsg.rc \
+ achkmsg.cxx \
+ array.cxx \
+ arrayit.cxx \
+ bigint.cxx \
+ bitvect.cxx \
+ boothack.cxx \
+ cache.cxx \
+ cannedsd.cxx \
+ clasdesc.cxx \
+ cluster.cxx \
+ cmem.cxx \
+ contain.cxx \
+ digraph.cxx \
+ drive.cxx \
+ eaheader.cxx \
+ easet.cxx \
+ fat.cxx \
+ fatdent.cxx \
+ fatdir.cxx \
+ fatsa.cxx \
+ rfatsa.cxx \
+ fatsachk.cxx \
+ fatsacnv.cxx \
+ fatvol.cxx \
+ filedir.cxx \
+ hmem.cxx \
+ ifssys.cxx \
+ ifsutil.cxx \
+ intstack.cxx \
+ iterator.cxx \
+ largemcb.c \
+ list.cxx \
+ listit.cxx \
+ mem.cxx \
+ membmgr.cxx \
+ message.cxx \
+ newdel.cxx \
+ numset.cxx \
+ object.cxx \
+ reloclus.cxx \
+ rootdir.cxx \
+ secrun.cxx \
+ seqcnt.cxx \
+ sdchk.cxx \
+ sortcnt.cxx \
+ sortlist.cxx \
+ sortlit.cxx \
+ spackmsg.cxx \
+ supera.cxx \
+ basesys.cxx \
+ ufat.cxx \
+ ulib.cxx \
+ volume.cxx \
+ wstring.cxx \
+ fatntfs.cxx \
+ convfat.cxx \
+ cufat.cxx \
+ attrcol.cxx \
+ attrdef.cxx \
+ attrib.cxx \
+ attrlist.cxx \
+ attrrec.cxx \
+ badfile.cxx \
+ bitfrs.cxx \
+ bootfile.cxx \
+ clusrun.cxx \
+ extents.cxx \
+ format.cxx \
+ frs.cxx \
+ frsstruc.cxx \
+ hackwc.cxx \
+ indxbuff.cxx \
+ indxchk.cxx \
+ indxroot.cxx \
+ indxtree.cxx \
+ logfile.cxx \
+ mft.cxx \
+ mftfile.cxx \
+ mftref.cxx \
+ ntfsbit.cxx \
+ ntfschk.cxx \
+ ntfssa.cxx \
+ ntfsvol.cxx \
+ untfs.cxx \
+ upfile.cxx \
+ upcase.cxx \
+ autoentr.cxx \
+ autoreg.cxx \
+ bootreg.c \
+ arg.cxx \
+ dcache.cxx \
+ rcache.cxx \
+ rwcache.cxx
+
+NOT_SOURCES= \
+ mrcf.c \
+ fatdbsa.cxx \
+ cvfexts.cxx \
+ fatdbvol.cxx
+
+
+INCLUDES=.;..\..\ulib\inc;..\..\ifsutil\inc;..\..\ufat\inc;..\..\untfs\inc;..\..\cufat\inc;..\..\..\ntos\inc$(OFS_INCLUDE);$(BASEDIR)\public\sdk\inc
+C_DEFINES=-DCONDITION_HANDLING=1 -D_AUTOCHECK_ -D_AUTOCONV_ -DUNICODE=1 $(OFS_DEFINE)
+CXXFLAGS=
+UMLIBS=obj\*\ntlib.lib
+UMRES=obj\*\rtmsg.res
+
+UMAPPL=
+
+UMTYPE=nt
+
+NTTARGETFILE0=rtmsg.h \
+ achkmsg.cxx \
+ array.cxx \
+ arrayit.cxx \
+ bigint.cxx \
+ bitvect.cxx \
+ cache.cxx \
+ cannedsd.cxx \
+ clasdesc.cxx \
+ cluster.cxx \
+ cmem.cxx \
+ contain.cxx \
+ digraph.cxx \
+ drive.cxx \
+ eaheader.cxx \
+ easet.cxx \
+ fat.cxx \
+ fatdent.cxx \
+ fatdir.cxx \
+ fatsa.cxx \
+ rfatsa.cxx \
+ fatsachk.cxx \
+ fatsacnv.cxx \
+ fatvol.cxx \
+ filedir.cxx \
+ hmem.cxx \
+ ifssys.cxx \
+ ifsutil.cxx \
+ intstack.cxx \
+ iterator.cxx \
+ list.cxx \
+ listit.cxx \
+ mem.cxx \
+ membmgr.cxx \
+ message.cxx \
+ newdel.cxx \
+ numset.cxx \
+ object.cxx \
+ reloclus.cxx \
+ rootdir.cxx \
+ secrun.cxx \
+ seqcnt.cxx \
+ sortcnt.cxx \
+ sortlist.cxx \
+ sortlit.cxx \
+ spackmsg.cxx \
+ supera.cxx \
+ basesys.cxx \
+ ufat.cxx \
+ ulib.cxx \
+ volume.cxx \
+ wstring.cxx \
+ fatntfs.cxx \
+ convfat.cxx \
+ cufat.cxx \
+ attrcol.cxx \
+ attrdef.cxx \
+ attrib.cxx \
+ attrlist.cxx \
+ attrrec.cxx \
+ badfile.cxx \
+ bitfrs.cxx \
+ bootfile.cxx \
+ clusrun.cxx \
+ extents.cxx \
+ format.cxx \
+ frs.cxx \
+ frsstruc.cxx \
+ hackwc.cxx \
+ indxbuff.cxx \
+ indxchk.cxx \
+ indxroot.cxx \
+ indxtree.cxx \
+ logfile.cxx \
+ mft.cxx \
+ mftfile.cxx \
+ mftref.cxx \
+ ntfsbit.cxx \
+ ntfschk.cxx \
+ ntfssa.cxx \
+ ntfsvol.cxx \
+ untfs.cxx \
+ upfile.cxx \
+ upcase.cxx \
+ autoentr.cxx \
+ autoreg.cxx \
+ bootreg.c \
+ arg.cxx \
+ dcache.cxx \
+ rcache.cxx \
+ rwcache.cxx
+
+
+NOT_TARGETS= \
+ mrcf.c \
+ fatdbsa.cxx \
+ cvfexts.cxx \
+ fatdbvol.cxx
diff --git a/private/utils/pentbug/i386/sources b/private/utils/pentbug/i386/sources
new file mode 100644
index 000000000..d1bb2ffd6
--- /dev/null
+++ b/private/utils/pentbug/i386/sources
@@ -0,0 +1,49 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+BLDCRT=1
+
+MAJORCOMP=utils
+MINORCOMP=pentnt
+
+TARGETNAME=pentnt
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+INCLUDES=
+#GPSIZE=32
+
+i386_SOURCES=pentnt.c \
+ pentnt.rc
+
+
+UMTYPE=console
+UMAPPL=pentnt
+UMLIBS=\nt\public\sdk\lib\*\user32.lib obj\*\pentnt.lib
+
+TARGETLIBS=\nt\public\sdk\lib\*\binmode.obj
+
+UMRES=obj\*\pentnt.res
+
+NTTARGETFILE0=pbmsg.h
diff --git a/private/utils/pentbug/makefile b/private/utils/pentbug/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/pentbug/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/pentbug/makefile.inc b/private/utils/pentbug/makefile.inc
new file mode 100644
index 000000000..6d444ab72
--- /dev/null
+++ b/private/utils/pentbug/makefile.inc
@@ -0,0 +1,4 @@
+pbmsg.rc: msg00001.bin
+
+pbmsg.h msg00001.bin: pbmsg.mc
+ mc -v -h .\ pbmsg.mc
diff --git a/private/utils/pentbug/pbmsg.mc b/private/utils/pentbug/pbmsg.mc
new file mode 100644
index 000000000..38a15bfab
--- /dev/null
+++ b/private/utils/pentbug/pbmsg.mc
@@ -0,0 +1,189 @@
+;/*++
+;
+;Copyright (c) 1992 Microsoft Corporation
+;
+;Module Name:
+;
+; pbmsg.mc (will create pbmsg.h when compiled)
+;
+;Abstract:
+;
+; This file contains the pentnt messages.
+;
+;Author:
+;
+; Bryan Willman (bryanwi) 7-Dec-94
+;
+;Revision History:
+;
+;--*/
+
+MessageId=1 SymbolicName=MSG_PENTBUG_HELP
+Language=English
+Reports on whether local computer exhibits Intel(tm) Pentium
+Floating Point Division Error
+
+pentnt [-?] [-H] [-h] [-C] [-c] [-F] [-f] [-O] [-o]
+
+ Run without arguments this program will tell you if the
+ system exhibits the Pentium floating point division error
+ and whether floating point emulation is forced and whether floating
+ point hardware is disabled.
+
+ -? Print this help message
+ -h
+ -H
+
+ -c Turn on conditional emulation. This means that floating
+ -C point emulation will be forced on if and only if
+ the system detects the Pentium floating point division
+ error at boot. Reboot required before this takes effect.
+ This is what should generally be used.
+
+ -f Turn on forced emulation. This means that floating
+ -F point hardware is disabled and floating point emulation
+ will always be forced on, regardless of whether the system
+ exhibits the Pentium division error. Useful for testing
+ software emulators and for working around floating point
+ hardware defects unknown to the OS. Reboot required before
+ this takes effect.
+
+ -o Turn off forced emulation. Reenables floating point hardware
+ -O if present. Reboot required before this takes effect.
+
+The Floating Point Division error that this program addresses only
+occurs on certain Intel Pentium processors. It only affects floating
+point operations. The problem is described in detail in a white paper
+available from Intel. If you are doing critical work with programs that
+perform floating point division and certain related functions that
+use the same hardware (including remainder and transcendtal functions),
+you may wish to use this program to force emulation.
+
+Type "pentnt -? | more" if you need to see all the help text
+.
+
+MessageId=2 SymbolicName=MSG_PENTBUG_NO_FLOAT_HARDWARE
+Language=English
+This computer does not have any floating point hardware,
+therefore you do not need to run this program.
+.
+
+MessageId=3 SymbolicName=MSG_PENTBUG_NOT_NT
+Language=English
+This program is only useful on Windows NT.
+.
+
+MessageId=4 SymbolicName=MSG_PENTBUG_NEED_NTOK
+Language=English
+You are running a version of Windows NT that does not
+support forced emulation. You must upgrade to Service
+Pack 1 (or later) for Windows NT Version 3.5 or upgrade to
+Windows NT Version 3.51 or later, if you wish to
+use the forced emulation workaround for the Pentium
+floating point division error.
+.
+
+MessageId=5 SymbolicName=MSG_PENTBUG_SET_FAILED
+Language=English
+Unable to set the ForceNpxEmulation flag in the registry.
+Error code = %d.
+.
+
+MessageId=6 SymbolicName=MSG_PENTBUG_IS_OFF_OK
+Language=English
+Floating point hardware is not disabled.
+This program has not made any changes.
+.
+
+MessageId=7 SymbolicName=MSG_PENTBUG_IS_OFF_REBOOT
+Language=English
+Forced floating point emulation has already been turned off,
+but is still active. You must shut down and restart your
+system for this to take effect.
+.
+
+MessageId=8 SymbolicName=MSG_PENTBUG_TURNED_OFF
+Language=English
+Forced floating point emulation has been turned off.
+.
+
+MessageId=9 SymbolicName=MSG_PENTBUG_REBOOT
+Language=English
+You must shut down and restart your system for this change
+to take effect.
+.
+
+MessageId=10 SymbolicName=MSG_PENTBUG_IS_ON_COND_REBOOT
+Language=English
+Forced floating point emulation has already been conditionally
+enabled, but is not active. You must shut down and restart your
+system to activate emulation.
+.
+
+MessageId=11 SymbolicName=MSG_PENTBUG_IS_ON_COND_OK
+Language=English
+Forced floating point emulation is already conditionally enabled,
+and appears to be working. This program has not changed anything.
+.
+
+MessageId=12 SymbolicName=MSG_PENTBUG_TURNED_ON_CONDITIONAL
+Language=English
+Floating point emulation has been conditionally enabled.
+.
+
+MessageId=13 SymbolicName=MSG_PENTBUG_IS_ON_ALWAYS_OK
+Language=English
+Forced floating point emulation is already forced on.
+This program has not made any changes.
+.
+
+MessageId=14 SymbolicName=MSG_PENTBUG_IS_ON_ALWAYS_REBOOT
+Language=English
+Floating point emulation has already been unconditionally enabled,
+but is not active. You need to shut down and restart your
+system to activate emulation.
+.
+
+MessageId=15 SymbolicName=MSG_PENTBUG_TURNED_ON_ALWAYS
+Language=English
+Forced floating point emulation has been unconditionally enabled.
+.
+
+MessageId=16 SymbolicName=MSG_PENTBUG_FLOAT_WORKS
+Language=English
+The floating point hardware in this system does not
+exhibit the Pentium floating point division error.
+.
+
+MessageId=17 SymbolicName=MSG_PENTBUG_EMULATION_ON_AND_WORKS
+Language=English
+Floating point hardware is disabled and floating point emulation
+has been enabled.
+.
+
+MessageId=18 SymbolicName=MSG_PENTBUG_FDIV_ERROR
+Language=English
+The floating point hardware in this system exhibits
+the Pentium floating point division error.
+.
+
+MessageId=19 SymbolicName=MSG_PENTBUG_IS_ON_REBOOT
+Language=English
+Forced floating point emulation has already been enabled
+either conditionally or unconditionally, but you
+must shut down and restart the system before
+it will take effect.
+.
+
+MessageId=20 SymbolicName=MSG_PENTBUG_CRITICAL_WORK
+Language=English
+If you are doing critical work using applications that
+depend on floating point division, remainder or
+transcendental instructions, you may wish to disable
+floating point hardware and to force floating point emulation.
+Run "pentnt -c" and then shut down and restart your
+system to force floating point emulation on.
+If you do this, floating point operations will run
+much more slowly.
+.
+
diff --git a/private/utils/pentbug/pentnt.c b/private/utils/pentbug/pentnt.c
new file mode 100644
index 000000000..639b2e5ec
--- /dev/null
+++ b/private/utils/pentbug/pentnt.c
@@ -0,0 +1,694 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ pentnt.c
+
+Abstract:
+
+ This module contains a simple program to detect the Pentium FPU
+ FDIV precision error, and offers to force floating point emulation
+ on if the bug is present.
+
+Author:
+
+ Bryan M. Willman (bryanwi) 7-Dec-1994
+
+Revision History:
+
+--*/
+
+#define UNICODE
+#include <stdio.h>
+#include <time.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <io.h>
+#include <windows.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include <stdarg.h>
+#include "pbmsg.h"
+
+void SetForceNpxEmulation(ULONG setting);
+void TestForDivideError();
+void ScanArgs(int argc, char **argv);
+void GetSystemState();
+void printmessage (DWORD messageID, ...);
+int ms_p5_test_fdiv(void);
+
+//
+// Core control state vars
+//
+BOOLEAN NeedHelp;
+
+BOOLEAN Force;
+ULONG ForceValue;
+
+BOOLEAN FDivError;
+
+BOOLEAN NTOK;
+
+ULONG CurrentForceValue;
+
+ULONG FloatHardware;
+
+//
+// ForceValue and CurrentForceValue
+//
+#define FORCE_OFF 0 // User wants emulation turned off
+#define FORCE_CONDITIONAL 1 // User wants emulation iff we detect bad pentium
+#define FORCE_ALWAYS 2 // User wants emulation regardless
+
+//
+// hardware fp status
+//
+#define FLOAT_NONE 0 // No fp hardware
+#define FLOAT_ON 1 // Fp hardware is present and active
+#define FLOAT_OFF 2 // Fp hardware is present and disabled
+
+void
+_CRTAPI1
+main(
+ int argc,
+ char **argv
+ )
+/*++
+
+Routine Description:
+
+ Main procedure for pentnt.
+
+ First, we call a series of routines that build a state vector
+ in some booleans.
+
+ We'll then act on these control variables:
+
+ NeedHelp - User has asked for help, or made a command error
+
+ Force - True if user has asked to change a force setting
+ ForceValue - Has no meaning if Force is FALSE. Else says
+ what the user wants us to do.
+
+ FloatHardware - Indicates if there is any and whether it's on
+
+ NTOK - Indicates if first OS version with fix is what
+ we are running
+
+ FdivError - if TRUE, FP gives WRONG answer, else, gives right answer
+ CurrentForceValue - what the current force setting is
+
+ All of these will be set before we do any work.
+
+Arguments:
+
+ argc - count of arguments, including the name of our proggram
+
+ argv - argument list - see command line syntax above
+
+Return Value:
+
+ Exit(0) - nothing changed, and current state is OK
+
+ Exit(1) - either a state change was requested, or just help,
+ or the current state may have a problem.
+
+ Exit(2) - we hit something really weird....
+
+
+--*/
+{
+ //
+ // build up state vector in global booleans
+ //
+ ScanArgs(argc, argv);
+ GetSystemState();
+ TestForDivideError();
+
+ /*
+ printf("NeedHelp = %d Force = %d ForceValue = %d\n",
+ NeedHelp, Force, ForceValue);
+ printf("FDivError = %d NTOK = %d CurrentForceValue = %d FloatHardware = %d\n",
+ FDivError, NTOK, CurrentForceValue, FloatHardware);
+ */
+
+ //
+ // ok, we know the state of the command and the machine, do work
+ //
+
+ //
+ // if they asked for help, or did something that indicates they don't
+ // understand how the program works, print help and exit.
+ //
+ if (NeedHelp) {
+ printmessage(MSG_PENTBUG_HELP);
+ exit(1);
+ }
+
+ //
+ // never do anything if there's no floating point hardware in the box
+ //
+ if (FloatHardware == FLOAT_NONE) {
+ printmessage(MSG_PENTBUG_NO_FLOAT_HARDWARE);
+ exit(0);
+ }
+
+ //
+ // never do anything if it's the wrong version of NT.
+ //
+ if (!NTOK) {
+ printmessage(MSG_PENTBUG_NEED_NTOK);
+ exit(1);
+ }
+
+ assert(NTOK == TRUE);
+ assert(NeedHelp == FALSE);
+ assert((FloatHardware == FLOAT_ON) || (FloatHardware == FLOAT_OFF));
+
+ if (Force) {
+
+ switch (ForceValue) {
+
+ case FORCE_OFF:
+
+ if (CurrentForceValue == FORCE_OFF) {
+
+ if (FloatHardware == FLOAT_ON) {
+ //
+ // user wants fp on, fp is on, fp set to be on
+ // all is as it should be
+ //
+ printmessage(MSG_PENTBUG_IS_OFF_OK);
+ exit(FDivError);
+ }
+
+ if (FloatHardware == FLOAT_OFF) {
+ //
+ // user need to reboot to finish turning emulation off
+ //
+ printmessage(MSG_PENTBUG_IS_OFF_REBOOT);
+ exit(1);
+ }
+
+ } else {
+ //
+ // they want it off, it's not off, so turn it off
+ // remind them to reboot
+ //
+ SetForceNpxEmulation(FORCE_OFF);
+ printmessage(MSG_PENTBUG_TURNED_OFF);
+ printmessage(MSG_PENTBUG_REBOOT);
+ exit(1);
+ }
+ break;
+
+ case FORCE_CONDITIONAL:
+
+ if (CurrentForceValue == FORCE_CONDITIONAL) {
+
+ if (FDivError) {
+ //
+ // tell them to reboot
+ //
+ printmessage(MSG_PENTBUG_IS_ON_COND_REBOOT);
+ exit(1);
+ } else {
+ //
+ // tell them to be happy
+ //
+ printmessage(MSG_PENTBUG_IS_ON_COND_OK);
+ exit(0);
+ }
+
+ } else {
+ //
+ // set it to what they want and tell them to reboot
+ //
+ SetForceNpxEmulation(ForceValue);
+ printmessage(MSG_PENTBUG_TURNED_ON_CONDITIONAL);
+ printmessage(MSG_PENTBUG_REBOOT);
+ exit(1);
+ }
+ break;
+
+ case FORCE_ALWAYS:
+
+ if (CurrentForceValue == FORCE_ALWAYS) {
+
+ if (FloatHardware == FLOAT_OFF) {
+ //
+ // tell them to be happy
+ //
+ printmessage(MSG_PENTBUG_IS_ON_ALWAYS_OK);
+ exit(0);
+ } else {
+ //
+ // tell them to reboot to finish
+ //
+ printmessage(MSG_PENTBUG_IS_ON_ALWAYS_REBOOT);
+ exit(1);
+ }
+
+ } else {
+ SetForceNpxEmulation(ForceValue);
+ printmessage(MSG_PENTBUG_TURNED_ON_ALWAYS);
+ printmessage(MSG_PENTBUG_REBOOT);
+ exit(1);
+ }
+ break;
+
+ default:
+ printf("pentnt: INTERNAL ERROR\n");
+ exit(2);
+
+ } // switch
+ }
+
+
+
+ //
+ // no action requested, just report state and give advice
+ //
+ assert(Force == FALSE);
+
+ if (!FDivError) {
+
+ if (FloatHardware == FLOAT_ON) {
+ printmessage(MSG_PENTBUG_FLOAT_WORKS);
+ } else {
+ printmessage(MSG_PENTBUG_EMULATION_ON_AND_WORKS);
+ }
+ exit(0);
+ }
+
+ //
+ // since we're here, we have an fdiv error, tell user what to do about it
+ //
+ assert(FDivError);
+
+ printmessage(MSG_PENTBUG_FDIV_ERROR);
+
+ if ((CurrentForceValue == FORCE_CONDITIONAL) ||
+ (CurrentForceValue == FORCE_ALWAYS))
+ {
+ printmessage(MSG_PENTBUG_IS_ON_REBOOT);
+ exit(1);
+ }
+
+ printmessage(MSG_PENTBUG_CRITICAL_WORK);
+ exit(1);
+
+ assert((TRUE==FALSE));
+}
+
+VOID
+SetForceNpxEmulation(
+ ULONG Setting
+ )
+/*++
+
+Routine Description:
+
+ SetForceNpxEmulation will simply set the ForceNpxEmulation value
+ entry under the Session Manager key to the value passed in.
+ 0 = off
+ 1 = conditional
+ 2 = always
+
+ If the set attempt fails, exit with a message.
+
+--*/
+{
+ HKEY hkey;
+ LONG rc;
+
+ rc = RegOpenKeyEx(
+ HKEY_LOCAL_MACHINE,
+ TEXT("System\\CurrentControlSet\\Control\\Session Manager"),
+ 0,
+ KEY_WRITE,
+ &hkey
+ );
+
+ if (rc != ERROR_SUCCESS) {
+ printmessage(MSG_PENTBUG_SET_FAILED, rc);
+ exit(2);
+ }
+
+ rc = RegSetValueEx(
+ hkey,
+ TEXT("ForceNpxEmulation"),
+ 0,
+ REG_DWORD,
+ (unsigned char *)&Setting,
+ sizeof(ULONG)
+ );
+
+ if (rc != ERROR_SUCCESS) {
+ printmessage(MSG_PENTBUG_SET_FAILED, rc);
+ exit(2);
+ }
+
+ return;
+}
+
+VOID
+ScanArgs(
+ int argc,
+ char **argv
+ )
+/*++
+
+Routine Description:
+
+ ScanArgs - parse command line arguments, and set control flags
+ to reflect what we find.
+
+ Sets NeedHelp, Force, ForceValue.
+
+Arguments:
+
+ argc - count of command line args
+
+ argv - argument vector
+
+Return Value:
+
+--*/
+{
+ int i;
+
+ Force = FALSE;
+ NeedHelp = FALSE;
+
+ for (i = 1; i < argc; i++) {
+ if ( ! ((argv[i][0] == '-') ||
+ (argv[i][0] == '/')) )
+ {
+ NeedHelp = TRUE;
+ goto done;
+ }
+
+ switch (argv[i][1]) {
+
+ case '?':
+ case 'h':
+ case 'H':
+ NeedHelp = TRUE;
+ break;
+
+ case 'c':
+ case 'C':
+ if (Force) {
+ NeedHelp = TRUE;
+ } else {
+ Force = TRUE;
+ ForceValue = FORCE_CONDITIONAL;
+ }
+ break;
+
+ case 'f':
+ case 'F':
+ if (Force) {
+ NeedHelp = TRUE;
+ } else {
+ Force = TRUE;
+ ForceValue = FORCE_ALWAYS;
+ }
+ break;
+
+ case 'o':
+ case 'O':
+ if (Force) {
+ NeedHelp = TRUE;
+ } else {
+ Force = TRUE;
+ ForceValue = FORCE_OFF;
+ }
+ break;
+
+ default:
+ NeedHelp = TRUE;
+ goto done;
+ }
+ }
+
+done:
+ if (NeedHelp) {
+ Force = FALSE;
+ }
+ return;
+}
+
+VOID
+GetSystemState(
+ )
+/*++
+
+Routine Description:
+
+ GetSystemState - get the system version, whether the computer
+ has FP hardware or not, and whether the force
+ emulation switch is already set or not.
+
+ Sets FloatHardware, NTOK, CurrentForceValue
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ HKEY hkey;
+ TCHAR Buffer[32];
+ DWORD BufferSize = 32;
+ DWORD Type;
+ int major;
+ int minor;
+ LONG rc;
+ PULONG p;
+ OSVERSIONINFO OsVersionInfo;
+
+ NTOK = FALSE;
+
+ //
+ // decide if the system version is OK.
+ //
+ OsVersionInfo.dwOSVersionInfoSize = sizeof(OsVersionInfo);
+ GetVersionEx(&OsVersionInfo);
+
+ if (OsVersionInfo.dwPlatformId != VER_PLATFORM_WIN32_NT) {
+ printmessage(MSG_PENTBUG_NOT_NT);
+ exit(2);
+ }
+
+ if ( (OsVersionInfo.dwMajorVersion > 3) ||
+ ( (OsVersionInfo.dwMajorVersion == 3) &&
+ (OsVersionInfo.dwMinorVersion >= 51) ))
+ {
+ //
+ // build 3.51 or greater, it has the fix
+ //
+ NTOK = TRUE;
+
+ } else if ( (OsVersionInfo.dwMajorVersion == 3) &&
+ (OsVersionInfo.dwMinorVersion == 50))
+ {
+ if (OsVersionInfo.szCSDVersion[0] != (TCHAR)'\0') {
+ //
+ // we have a service pack for 3.5, since pack 1 and
+ // later have the fix, it's OK
+ //
+ NTOK = TRUE;
+ }
+ }
+ /*
+ printf("debug NTOK forced true for testing\n\n\n");
+ NTOK = TRUE;
+ */
+
+
+ //
+ // determine if float hardware is present
+ //
+ rc = RegOpenKeyEx(
+ HKEY_LOCAL_MACHINE,
+ TEXT("Hardware\\Description\\System\\FloatingPointProcessor"),
+ 0,
+ KEY_READ,
+ &hkey
+ );
+
+ if (rc == ERROR_SUCCESS) {
+
+ FloatHardware = FLOAT_ON;
+ RegCloseKey(hkey);
+
+ } else {
+
+ rc = RegOpenKeyEx(
+ HKEY_LOCAL_MACHINE,
+ TEXT("Hardware\\Description\\System\\DisabledFloatingPointProcessor"),
+ 0,
+ KEY_READ,
+ &hkey
+ );
+
+ if (rc == ERROR_SUCCESS) {
+
+ FloatHardware = FLOAT_OFF;
+ RegCloseKey(hkey);
+
+ } else {
+
+ FloatHardware = FLOAT_NONE;
+
+ }
+ }
+
+ //
+ // determine if emulation has been forced on
+ //
+ rc = RegOpenKeyEx(
+ HKEY_LOCAL_MACHINE,
+ TEXT("System\\CurrentControlSet\\Control\\Session Manager"),
+ 0,
+ KEY_READ,
+ &hkey
+ );
+
+ BufferSize = 32;
+ rc = RegQueryValueEx(
+ hkey,
+ TEXT("ForceNpxEmulation"),
+ 0,
+ &Type,
+ (unsigned char *)Buffer,
+ &BufferSize
+ );
+
+ if ( (rc == ERROR_SUCCESS) &&
+ (Type == REG_DWORD) )
+ {
+ p = (PULONG)Buffer;
+ CurrentForceValue = *p;
+ }
+
+ return;
+}
+
+//
+// these must be globals to make the compiler do the right thing
+//
+
+VOID
+TestForDivideError(
+ )
+/*++
+
+Routine Description:
+
+ Do a divide with a known divident/divisor pair, followed by
+ a multiply to see if we get the right answer back.
+
+ FDivError = TRUE if we get the WRONG answer, FALSE.
+Arguments:
+
+Return Value:
+
+
+--*/
+{
+ DWORD pick;
+ HANDLE ph;
+ DWORD processmask;
+ DWORD systemmask;
+ ULONG i;
+
+ //
+ // fetch the affinity mask, which is also effectively a list
+ // of processors
+ //
+ ph = GetCurrentProcess();
+ GetProcessAffinityMask(ph, &processmask, &systemmask);
+
+ //
+ // step through the mask, testing each cpu.
+ // if any is bad, we treat them all as bad
+ //
+ FDivError = FALSE;
+ for (i = 0; i < 32; i++) {
+ pick = 1 << i;
+
+ if ((systemmask & pick) != 0) {
+
+ //*//printf("pick = %08lx\n", pick);
+ SetThreadAffinityMask(GetCurrentThread(), pick);
+
+ //
+ // call the official test function
+ //
+ if (ms_p5_test_fdiv()) {
+ //
+ // do NOT just assign func to FDivError, that will reset
+ // it if a second cpu is good. must be one way flag
+ //
+ FDivError = TRUE;
+ }
+
+ } // IF
+ } // for
+ return;
+}
+
+/***
+* testfdiv.c - routine to test for correct operation of x86 FDIV instruction.
+*
+* Copyright (c) 1994, Microsoft Corporation. All rights reserved.
+*
+*Purpose:
+* Detects early steppings of Pentium with incorrect FDIV tables using
+* 'official' Intel test values. Returns 1 if flawed Pentium is detected,
+* 0 otherwise.
+*
+*/
+int ms_p5_test_fdiv(void)
+{
+ double dTestDivisor = 3145727.0;
+ double dTestDividend = 4195835.0;
+ double dRslt;
+
+ _asm {
+ fld qword ptr [dTestDividend]
+ fdiv qword ptr [dTestDivisor]
+ fmul qword ptr [dTestDivisor]
+ fsubr qword ptr [dTestDividend]
+ fstp qword ptr [dRslt]
+ }
+
+ return (dRslt > 1.0);
+}
+
+
+//
+// Call FormatMessage and dump the result. All messages to Stdout
+//
+void printmessage (DWORD messageID, ...)
+{
+ unsigned short messagebuffer[4096];
+ va_list ap;
+
+ va_start(ap, messageID);
+
+ FormatMessage(FORMAT_MESSAGE_FROM_HMODULE, NULL, messageID, 0,
+ messagebuffer, 4095, &ap);
+
+ wprintf(messagebuffer);
+
+ va_end(ap);
+}
+
diff --git a/private/utils/pentbug/pentnt.rc b/private/utils/pentbug/pentnt.rc
new file mode 100644
index 000000000..bd12f34e7
--- /dev/null
+++ b/private/utils/pentbug/pentnt.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Pentium Floating Point Divide Error Utility"
+#define VER_INTERNALNAME_STR "pentnt\0"
+#define VER_ORIGINALFILENAME_STR "pentnt.exe"
+
+#include "common.ver"
+
+#include "pbmsg.rc"
diff --git a/private/utils/pentbug/sources b/private/utils/pentbug/sources
new file mode 100644
index 000000000..16bad8971
--- /dev/null
+++ b/private/utils/pentbug/sources
@@ -0,0 +1,33 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+BLDCRT=1
+
+MAJORCOMP=utils
+MINORCOMP=pentnt
+
+TARGETNAME=pentnt
+TARGETPATH=obj
+TARGETTYPE=UMAPPL_NOLIB
+SOURCES=
diff --git a/private/utils/print/makefile b/private/utils/print/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/print/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/print/makefile.inc b/private/utils/print/makefile.inc
new file mode 100644
index 000000000..6c93eb38d
--- /dev/null
+++ b/private/utils/print/makefile.inc
@@ -0,0 +1,12 @@
+{}.cxx{obj\i386\}.obj:
+ $(386_COMPILER) -Fo$@ $(MAKEDIR)\$(<F)
+
+{}.cxx{obj\mips\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClMips $< " $(C_COMPILER) "
+ @$(C_COMPILER) -Fo$@ $(MAKEDIR)\$<
+
+{}.cxx{obj\alpha\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClAlpha $< " $(ALPHA_COMPILER) "
+ @$(ALPHA_COMPILER) -Fo$@ $(MAKEDIR)\$<
diff --git a/private/utils/print/print.cxx b/private/utils/print/print.cxx
new file mode 100644
index 000000000..6e5a089cb
--- /dev/null
+++ b/private/utils/print/print.cxx
@@ -0,0 +1,413 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ print.cxx
+
+Abstract:
+
+
+Author:
+
+ Jaime F. Sasson - jaimes - 14-Jun-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include "ulib.hxx"
+#include "arg.hxx"
+#include "path.hxx"
+#include "wstring.hxx"
+#include "system.hxx"
+#include "array.hxx"
+#include "arrayit.hxx"
+#include "smsg.hxx"
+#include "stream.hxx"
+#include "rtmsg.h"
+#include "prtstrm.hxx"
+#include "file.hxx"
+#include "print.hxx"
+
+extern "C" {
+#include <stdio.h>
+#include <string.h>
+}
+
+PSTREAM Get_Standard_Input_Stream();
+PSTREAM Get_Standard_Output_Stream();
+
+DEFINE_CONSTRUCTOR( PRINT, PROGRAM );
+
+
+BOOLEAN
+PRINT::Initialize(
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes a PRINT class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the initialization succeeded.
+
+
+--*/
+
+
+{
+ ARGUMENT_LEXEMIZER ArgLex;
+ ARRAY LexArray;
+
+ ARRAY ArgumentArray;
+ FLAG_ARGUMENT FlagDisplayHelp;
+
+ STRING_ARGUMENT ProgramNameArgument;
+ PWSTRING InvalidArgument;
+
+ PATH_ARGUMENT DeviceArgument;
+ PPATH DevicePath;
+ PCWSTRING DeviceString;
+ PPATH FilePath;
+ PCWSTRING FileString;
+ PARRAY PathArray;
+ PARRAY_ITERATOR PathArrayIterator;
+ PFSN_FILE FsnFile;
+
+
+ _StandardOutput = Get_Standard_Output_Stream();
+
+ //
+ // Initialize MESSAGE class
+ //
+ _Message.Initialize( _StandardOutput, Get_Standard_Input_Stream() );
+
+ //
+ // Parse command line
+ //
+ if ( !LexArray.Initialize() ) {
+ DebugAbort( "LexArray.Initialize() failed \n" );
+ return( FALSE );
+ }
+ if ( !ArgLex.Initialize( &LexArray ) ) {
+ DebugAbort( "ArgLex.Initialize() failed \n" );
+ return( FALSE );
+ }
+ ArgLex.PutSwitches( "/" );
+ ArgLex.SetCaseSensitive( FALSE );
+ ArgLex.PutStartQuotes( "\"" );
+ ArgLex.PutEndQuotes( "\"" );
+
+ if( !ArgLex.PrepareToParse() ) {
+ DebugAbort( "ArgLex.PrepareToParse() failed \n" );
+ return( FALSE );
+ }
+ if ( !ArgumentArray.Initialize() ) {
+ DebugAbort( "ArgumentArray.Initialize() failed \n" );
+ return( FALSE );
+ }
+ if( !ProgramNameArgument.Initialize("*") ||
+ !DeviceArgument.Initialize( "/D:*" ) ||
+ !_BufferSize.Initialize( "/B:*" ) ||
+ !_Ticks1.Initialize( "/U:*" ) ||
+ !_Ticks2.Initialize( "/M:*" ) ||
+ !_Ticks3.Initialize( "/S:*" ) ||
+ !_NumberOfFiles.Initialize( "/Q:*" ) ||
+ !_FlagRemoveFiles.Initialize( "/T" ) ||
+ !_Files.Initialize( "*", FALSE, TRUE ) ||
+ !_FlagCancelPrinting.Initialize( "/C" ) ||
+ !_FlagAddFiles.Initialize( "/P" ) ||
+ !FlagDisplayHelp.Initialize( "/?" ) ) {
+ DebugAbort( "Unable to initialize flag or string arguments \n" );
+ return( FALSE );
+ }
+ if( !ArgumentArray.Put( &ProgramNameArgument ) ||
+ !ArgumentArray.Put( &DeviceArgument ) ||
+ !ArgumentArray.Put( &_BufferSize ) ||
+ !ArgumentArray.Put( &_Ticks1 ) ||
+ !ArgumentArray.Put( &_Ticks2 ) ||
+ !ArgumentArray.Put( &_Ticks3 ) ||
+ !ArgumentArray.Put( &_NumberOfFiles ) ||
+ !ArgumentArray.Put( &_FlagRemoveFiles ) ||
+ !ArgumentArray.Put( &_Files ) ||
+ !ArgumentArray.Put( &_FlagCancelPrinting ) ||
+ !ArgumentArray.Put( &_FlagAddFiles ) ||
+ !ArgumentArray.Put( &FlagDisplayHelp ) ) {
+ DebugAbort( "ArgumentArray.Put() failed \n" );
+ return( FALSE );
+ }
+ if( !ArgLex.DoParsing( &ArgumentArray ) ) {
+ InvalidArgument = ArgLex.QueryInvalidArgument();
+ DebugPtrAssert( InvalidArgument );
+ _Message.Set( MSG_PRINT_INVALID_SWITCH );
+ _Message.Display( "%W", InvalidArgument );
+ return( FALSE );
+ }
+
+ //
+ // /B: /U: /M: /S: /Q: /T: /C: and /P: are not implemented
+ // if one of these arguments was found in the command line
+ // then inform user, and don't print anything
+ //
+ if( _BufferSize.IsValueSet() ) {
+ _Message.Set( MSG_PRINT_NOT_IMPLEMENTED );
+ _Message.Display( "%s", "/B:" );
+ return( FALSE );
+ }
+ if( _Ticks1.IsValueSet() ) {
+ _Message.Set( MSG_PRINT_NOT_IMPLEMENTED );
+ _Message.Display( "%s", "/U:" );
+ return( FALSE );
+ }
+ if( _Ticks2.IsValueSet() ) {
+ _Message.Set( MSG_PRINT_NOT_IMPLEMENTED );
+ _Message.Display( "%s", "/M:" );
+ return( FALSE );
+ }
+ if( _Ticks3.IsValueSet() ) {
+ _Message.Set( MSG_PRINT_NOT_IMPLEMENTED );
+ _Message.Display( "%s", "/S:" );
+ return( FALSE );
+ }
+ if( _NumberOfFiles.IsValueSet() ) {
+ _Message.Set( MSG_PRINT_NOT_IMPLEMENTED );
+ _Message.Display( "%s", "/Q:" );
+ return( FALSE );
+ }
+ if( _FlagRemoveFiles.IsValueSet() ) {
+ _Message.Set( MSG_PRINT_NOT_IMPLEMENTED );
+ _Message.Display( "%s", "/T:" );
+ return( FALSE );
+ }
+ if( _FlagCancelPrinting.IsValueSet() ) {
+ _Message.Set( MSG_PRINT_NOT_IMPLEMENTED );
+ _Message.Display( "%s", "/C:" );
+ return( FALSE );
+ }
+ if( _FlagAddFiles.IsValueSet() ) {
+ _Message.Set( MSG_PRINT_NOT_IMPLEMENTED );
+ _Message.Display( "%s", "/P:" );
+ return( FALSE );
+ }
+
+ //
+ // Displays help message if /? was found in the command line
+ //
+ if( FlagDisplayHelp.QueryFlag() ) {
+ _Message.Set( MSG_PRINT_HELP_MESSAGE );
+ _Message.Display( " " );
+ return( FALSE );
+ }
+
+ //
+ // If no filename was specified, display error message
+ //
+ if( _Files.QueryPathCount() == 0 ) {
+ _Message.Set( MSG_PRINT_NO_FILE );
+ _Message.Display( " " );
+ return( FALSE );
+ }
+
+ //
+ // Get device name if one exists. Otherwise use PRN as default
+ //
+ if( !DeviceArgument.IsValueSet() ) {
+ DevicePath = NEW( PATH );
+ DebugPtrAssert( DevicePath );
+ if( !DevicePath->Initialize( (LPWSTR)L"PRN" ) ) {
+ _Message.Set( MSG_PRINT_UNABLE_INIT_DEVICE );
+ _Message.Display( "%s", "PRN" );
+ return( FALSE );
+ }
+ } else {
+ DevicePath = DeviceArgument.GetPath();
+ DebugPtrAssert( DevicePath );
+ }
+ if( !_Printer.Initialize( DevicePath ) ) {
+ DeviceString = DevicePath->GetPathString();
+ DebugPtrAssert( DeviceString );
+ _Message.Set( MSG_PRINT_UNABLE_INIT_DEVICE );
+ _Message.Display( "%W", DeviceString );
+ if( !DeviceArgument.IsValueSet() ) {
+ DELETE( DevicePath );
+ }
+ return( FALSE );
+ }
+
+ //
+ // Get FSNODE of each file and put them in an array
+ //
+ PathArray = _Files.GetPathArray();
+ DebugPtrAssert( PathArray );
+ PathArrayIterator = ( PARRAY_ITERATOR )PathArray->QueryIterator();
+ DebugPtrAssert( PathArrayIterator );
+
+ if( !_FsnFileArray.Initialize() ) {
+ DebugAbort( "_FsnFileArray.Initialize() failed \n" );
+ return( FALSE );
+ }
+ while( ( FilePath = ( PPATH )PathArrayIterator->GetNext() ) != NULL ) {
+ FsnFile = SYSTEM::QueryFile( FilePath );
+ if( FsnFile != NULL ) {
+ _FsnFileArray.Put( ( POBJECT )FsnFile );
+ } else {
+ FileString = FilePath->GetPathString();
+ _Message.Set( MSG_PRINT_FILE_NOT_FOUND );
+ _Message.Display( "%W", FileString );
+ }
+ }
+ DELETE( PathArrayIterator );
+ return( TRUE );
+}
+
+
+BOOLEAN
+PRINT::PrintFiles(
+ )
+
+/*++
+
+Routine Description:
+
+ Prints the files specified by the user.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - TRUE if all files were printed.
+
+
+--*/
+
+{
+ PFSN_FILE FsnFile;
+ PSTREAM FileStream;
+ PARRAY_ITERATOR ArrayIterator;
+ PBYTE Buffer;
+ ULONG Size;
+ ULONG BytesRead;
+ ULONG BytesWritten;
+ PCPATH FilePath;
+ PCWSTRING FileName;
+ INT _BufferStreamType;
+ INT BytesConverted;
+ INT cbStuff;
+ LPSTR lpStuffANSI;
+ BOOL fUsedDefault;
+
+
+ Size = 512;
+ Buffer = ( PBYTE )MALLOC( ( size_t )Size );
+ lpStuffANSI = ( LPSTR )MALLOC( ( size_t )Size );
+ DebugPtrAssert( Buffer );
+ DebugPtrAssert( lpStuffANSI );
+ ArrayIterator = ( PARRAY_ITERATOR )_FsnFileArray.QueryIterator();
+ DebugPtrAssert( ArrayIterator );
+ while( ( FsnFile = ( PFSN_FILE )ArrayIterator->GetNext() ) != NULL ) {
+ FileStream = ( PSTREAM )FsnFile->QueryStream( READ_ACCESS );
+ DebugPtrAssert( FileStream );
+
+ FileName = FsnFile->GetPath()->GetPathString();
+ if( FileName != NULL ) {
+ _Message.Set( MSG_PRINT_PRINTING );
+ _Message.Display( "%W", FileName );
+ }
+
+ _BufferStreamType = -1;
+ while( !FileStream->IsAtEnd() ) {
+ FileStream->Read( Buffer, Size, &BytesRead );
+ // is file unicode?
+ if (_BufferStreamType < 0) {
+ if (IsTextUnicode((LPTSTR)Buffer, (INT)BytesRead,
+ NULL) ) {
+ _BufferStreamType = 1;
+ } else {
+ _BufferStreamType = 0;
+ }
+ }
+ // does the buffer need to be converted?
+ if (_BufferStreamType == 1) {
+
+ cbStuff = Size;
+ BytesConverted = WideCharToMultiByte(CP_ACP,0,
+ (LPTSTR)Buffer,BytesRead/sizeof(WCHAR),
+ lpStuffANSI,cbStuff,NULL,&fUsedDefault) ;
+ DebugAssert(cbStuff>0);
+ DebugAssert(BytesConverted >= 0);
+ _Printer.Write((PBYTE)lpStuffANSI,BytesConverted,&BytesWritten );
+ } else {
+ _Printer.Write( Buffer, BytesRead, &BytesWritten );
+ }
+ }
+ _Printer.WriteByte( '\f' );
+ DELETE( FileStream );
+ }
+ DELETE( ArrayIterator );
+ return( TRUE );
+}
+
+
+
+
+BOOL
+PRINT::Terminate(
+ )
+
+/*++
+
+Routine Description:
+
+ Deletes objects created during initialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ return( TRUE );
+}
+
+
+
+
+
+ULONG _CRTAPI1
+main()
+
+{
+ DEFINE_CLASS_DESCRIPTOR( PRINT );
+
+
+ {
+
+ PRINT Print;
+
+
+ if( Print.Initialize() ) {
+ Print.PrintFiles();
+ }
+ // Print.Terminate();
+ return( 0 );
+ }
+}
diff --git a/private/utils/print/print.hxx b/private/utils/print/print.hxx
new file mode 100644
index 000000000..b6a63c04c
--- /dev/null
+++ b/private/utils/print/print.hxx
@@ -0,0 +1,87 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ print.hxx
+
+Abstract:
+
+
+
+Author:
+
+ Jaime F. Sasson - jaimes - 12-Jun-1991
+
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if ! defined( _PRINT_ )
+
+#define _PRINT_
+
+#include "object.hxx"
+#include "keyboard.hxx"
+#include "program.hxx"
+
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( ARRAY );
+DECLARE_CLASS( ARRAY_ITERATOR );
+DECLARE_CLASS( PRINT_STREAM );
+
+DECLARE_CLASS( PRINT );
+
+class PRINT : public PROGRAM {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( PRINT );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintFiles (
+ );
+
+ NONVIRTUAL
+ BOOL
+ Terminate(
+ );
+
+ private:
+
+ PSTREAM _StandardOutput;
+
+ MULTIPLE_PATH_ARGUMENT _Files;
+ LONG_ARGUMENT _BufferSize;
+ LONG_ARGUMENT _Ticks1;
+ LONG_ARGUMENT _Ticks2;
+ LONG_ARGUMENT _Ticks3;
+ LONG_ARGUMENT _NumberOfFiles;
+ FLAG_ARGUMENT _FlagRemoveFiles;
+ FLAG_ARGUMENT _FlagCancelPrinting;
+ FLAG_ARGUMENT _FlagAddFiles;
+
+ ARRAY _FsnFileArray;
+
+ STREAM_MESSAGE _Message;
+
+ PRINT_STREAM _Printer;
+};
+
+
+#endif // _PRINT_
diff --git a/private/utils/print/print.rc b/private/utils/print/print.rc
new file mode 100644
index 000000000..3e3951f03
--- /dev/null
+++ b/private/utils/print/print.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Print Utility"
+#define VER_INTERNALNAME_STR "Print"
+#define VER_ORIGINALFILENAME_STR "Print.Exe"
+
+#include "common.ver"
diff --git a/private/utils/print/sources b/private/utils/print/sources
new file mode 100644
index 000000000..ac227a013
--- /dev/null
+++ b/private/utils/print/sources
@@ -0,0 +1,60 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+BLDCRT=1
+
+MAJORCOMP=utils
+MINORCOMP=print
+
+TARGETNAME=print
+TARGETPATH=obj
+TARGETTYPE=UMAPPL_NOLIB
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=print.cxx print.rc
+
+INCLUDES=..\ulib\inc;\nt\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+CXXFLAGS=+d
+UMLIBS=..\ulib\src\obj\*\ulib.lib \nt\public\sdk\lib\*\ntdll.lib
+
+UMTYPE=console
+
+UMAPPL=print
+UMRES=obj\*\print.res
diff --git a/private/utils/rdisk/config.c b/private/utils/rdisk/config.c
new file mode 100644
index 000000000..35e493fce
--- /dev/null
+++ b/private/utils/rdisk/config.c
@@ -0,0 +1,908 @@
+/*++
+
+Module Name:
+
+ config.c
+
+Abstract:
+
+ This module contains the functions that save the configuration files
+ into the repair directory, and copy these files to the Emergency
+ Repair disk.
+
+
+Author:
+
+ Jaime Sasson
+
+Environment:
+
+ Windows
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+#define SYSTEM_HIVE (LPWSTR)L"system"
+#define SOFTWARE_HIVE (LPWSTR)L"software"
+#define SECURITY_HIVE (LPWSTR)L"security"
+#define SAM_HIVE (LPWSTR)L"sam"
+#define DEFAULT_USER_HIVE (LPWSTR)L".default"
+#define DEFAULT_USER_HIVE_FILE (LPWSTR)L"default"
+#define NTUSER_HIVE_FILE (LPWSTR)L"ntuser.dat"
+#define REPAIR_DIRECTORY (LPWSTR)L"\\repair"
+#define PROFILES_DIRECTORY (LPWSTR)L"\\profiles"
+#define SETUP_LOG_FILE (LPWSTR)L"setup.log"
+
+#define SYSTEM_COMPRESSED_FILE_NAME ( LPWSTR )L"system._"
+#define SOFTWARE_COMPRESSED_FILE_NAME ( LPWSTR )L"software._"
+#define SOFTWARE_COMPRESSED_FILE_NAME ( LPWSTR )L"software._"
+#define SECURITY_COMPRESSED_FILE_NAME ( LPWSTR )L"security._"
+#define SAM_COMPRESSED_FILE_NAME ( LPWSTR )L"sam._"
+#define DEFAULT_COMPRESSED_FILE_NAME ( LPWSTR )L"default._"
+#define NTUSER_COMPRESSED_FILE_NAME ( LPWSTR )L"ntuser.da_"
+#define AUTOEXEC_NT_FILE_NAME ( LPWSTR )L"autoexec.nt"
+#define CONFIG_NT_FILE_NAME ( LPWSTR )L"config.nt"
+
+
+//
+// Relative costs to perform various actions,
+// to help make the gas gauge mean something.
+//
+#define COST_SAVE_HIVE 3
+#define COST_COMPRESS_HIVE 20
+#define COST_SAVE_VDM_FILE 1
+
+
+typedef enum _OPERATION_TYPE {
+ SaveConfiguration,
+ CopyConfigurationFiles,
+ } OPERATION_TYPE;
+
+typedef struct _PROGRESS_PARAMETERS {
+ OPERATION_TYPE OperationType;
+ WCHAR DriveLetter;
+ } PROGRESS_PARAMETERS, *PPROGRESS_PARAMETERS;
+
+typedef struct _THREAD_ARGUMENTS {
+ HWND hWnd;
+ WCHAR DriveLetter;
+ } THREAD_ARGUMENTS, *PTHREAD_ARGUMENTS;
+
+//
+// Structure used in the array of hives to be saved.
+// This structure contains the predefined key that contains the hive
+// to be saved, and the name of the hive root, and the name of the file
+// where the hive should be saved.
+//
+
+typedef struct _HIVE_INFO {
+ HKEY PredefinedKey;
+ PWSTR HiveName;
+ PWSTR FileName;
+ } HIVE_INFO, *PHIVE_INFO;
+
+
+FCenterDialogOnDesktop(HWND);
+
+BOOL
+NotifyCB(
+ IN PSTR src,
+ IN PSTR dst,
+ IN WORD code
+ )
+{
+ UNREFERENCED_PARAMETER(src);
+ UNREFERENCED_PARAMETER(dst);
+ UNREFERENCED_PARAMETER(code);
+ return(TRUE);
+}
+
+DWORD
+SaveOneHive(
+ IN LPWSTR DirectoryName,
+ IN LPWSTR HiveName,
+ IN HKEY hkey,
+ IN HWND hWnd,
+ IN OUT PDWORD GaugePosition,
+ IN DWORD GaugeDeltaUnit
+ )
+
+/*++
+
+Routine Description:
+
+ Save one registry hive. The way we will do this is to do a RegSaveKey
+ of the hive into a temporary localtion, and then call the LZ apis to
+ compress the file from that temporary location to the floppy.
+
+ LZ must have already been initialized via InitGloablBuffersEx()
+ BEFORE calling this routine.
+
+Arguments:
+
+ DirectoryName - Full path of the directory where the hive will be saved.
+
+ HiveName - base name of the hive file to save. The file will end up
+ compressed on disk with the name <HiveName>._.
+
+ hkey - supplies handle to open key of root of hive to save.
+
+ GaugePosition - in input, supplies current position of the gas gauge.
+ On output, supplies new position of gas gauge.
+
+ GaugeDeltaUnit - supplies cost of one unit of activity.
+
+Return Value:
+
+ DWORD - Return ERROR_SUCCESS if the hive was saved. Otherwise, it returns
+ an error code.
+
+--*/
+
+{
+ DWORD Status;
+ WCHAR SaveFilename[ MAX_PATH + 1 ];
+ WCHAR CompressPath[ MAX_PATH + 1 ];
+ CHAR SaveFilenameAnsi[ MAX_PATH + 1 ];
+ CHAR CompressPathAnsi[ MAX_PATH + 1 ];
+ LPWSTR TempName = ( LPWSTR )L"\\$$hive$$.tmp";
+
+ //
+ // Create the name of the file into which we will save the
+ // uncompressed hive.
+ //
+
+ wsprintf(SaveFilename,L"%ls\\$$hive$$.tmp",DirectoryName);
+ wsprintfA(SaveFilenameAnsi,"%ls\\$$hive$$.tmp",DirectoryName);
+
+ //
+ // Delete the file just in case, because RegSaveKey will fail if the file
+ // already exists.
+ //
+ SetFileAttributes(SaveFilename,FILE_ATTRIBUTE_NORMAL);
+ DeleteFile(SaveFilename);
+
+ //
+ // Save the registry hive into the temporary file.
+ //
+ Status = RegSaveKey(hkey,SaveFilename,NULL);
+
+ //
+ // Update the gas gauge.
+ //
+ *GaugePosition += GaugeDeltaUnit * COST_SAVE_HIVE;
+ SendDlgItemMessage( hWnd,
+ ID_BAR,
+ PBM_SETPOS,
+ *GaugePosition,
+ 0L
+ );
+
+ //
+ // If the hive was saved successfully, then compress it and update
+ // the gas gauge. Otherwise, update the gas gauge and return.
+ //
+
+ if(Status == ERROR_SUCCESS) {
+ //
+ // Form the name of the file into which the saved hive file is
+ // to be compressed.
+ //
+ wsprintf(CompressPath,L"%ls\\%ls._",DirectoryName,HiveName);
+ wsprintfA(CompressPathAnsi,"%ls\\%ls._",DirectoryName,HiveName );
+
+ //
+ // Delete the destination file just in case.
+ //
+ SetFileAttributes(CompressPath,FILE_ATTRIBUTE_NORMAL);
+ DeleteFile(CompressPath);
+
+ //
+ // Compress the hive into the destination file.
+ //
+ Status = DiamondCompressFile(
+ SaveFilenameAnsi,
+ CompressPathAnsi,
+ *GaugePosition,
+ GaugeDeltaUnit * COST_COMPRESS_HIVE,
+ hWnd
+ );
+
+ //
+ // Delete the temporary saved hive.
+ //
+ SetFileAttributes(SaveFilename,FILE_ATTRIBUTE_NORMAL);
+ DeleteFile(SaveFilename);
+ }
+
+ *GaugePosition += GaugeDeltaUnit * COST_COMPRESS_HIVE;
+ SendDlgItemMessage( hWnd,
+ ID_BAR,
+ PBM_SETPOS,
+ *GaugePosition,
+ 0L
+ );
+
+ return(Status);
+}
+
+
+VOID
+SaveConfigurationWorker(
+ IN PTHREAD_ARGUMENTS Arguments
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the thread that saves all system configuration
+ files into the repair directory. It first saves and compresses the
+ registry hives, and then it save the VDM configuration files (autoexec.nt
+ and config.nt).
+ If the application is running in the SilentMode (invoked by setup),
+ then system, software, default, security and sam hives will be saved
+ and compressed.
+ If the application was invoked by the user, then only system, software
+ and default will be saved.
+
+ This thread will send messages to the gas gauge dialog prcedure, so that
+ the gas gauge gets updated after each configuration file is saved.
+ This thread will also inform the user about errors that might have
+ occurred during the process of saving the configuration files.
+
+Arguments:
+
+ Arguments - Pointer to a structure that contains the parameters to be passed to
+ thread.
+
+
+Return Value:
+
+ None.
+ However, the this routine will send a message to the dialog procedure
+ that created the thread, informing the outcome the operation.
+
+--*/
+
+{
+ DWORD i;
+ HKEY hkey;
+ BOOL ErrorOccurred;
+ CHAR SourceUserHivePathAnsi[ MAX_PATH + 1 ];
+ CHAR CompressedUserHivePathAnsi[ MAX_PATH + 1 ];
+ WCHAR ProfilesDirectory[ MAX_PATH + 1 ];
+ WCHAR RepairDirectory[ MAX_PATH + 1 ];
+ WCHAR SystemDirectory[ MAX_PATH + 1 ];
+ WCHAR Source[ MAX_PATH + 1 ];
+ WCHAR Target[ MAX_PATH + 1 ];
+ DWORD GaugeDeltaUnit;
+ DWORD GaugePosition;
+ DWORD NumberOfHivesToSave;
+ DWORD NumberOfUserHivesToSave;
+ DWORD NumberOfVdmFiles;
+ HWND hWnd;
+ DWORD Error;
+ DWORD Status;
+ HANDLE Token;
+ BOOL b;
+ TOKEN_PRIVILEGES NewPrivileges;
+ LUID Luid;
+
+ //
+ // The array below contains the location and name of all hives that
+ // we need to save. When the utility is operating on the silent mode,
+ // (invoked from setup), then all hives will be saved. Otherwise, only
+ // system and software will be saved.
+ // For this reason, do not change the order of the hives in the array
+ // below. System and software must be the first elements of
+ // the array.
+ //
+ HIVE_INFO HiveList[] = { { HKEY_LOCAL_MACHINE, SYSTEM_HIVE, SYSTEM_HIVE },
+ { HKEY_LOCAL_MACHINE, SOFTWARE_HIVE, SOFTWARE_HIVE },
+ { HKEY_USERS, DEFAULT_USER_HIVE, DEFAULT_USER_HIVE_FILE },
+ { HKEY_LOCAL_MACHINE, SECURITY_HIVE, SECURITY_HIVE },
+ { HKEY_LOCAL_MACHINE, SAM_HIVE, SAM_HIVE }
+ };
+
+
+ PWSTR VdmFiles[] = {
+ AUTOEXEC_NT_FILE_NAME,
+ CONFIG_NT_FILE_NAME
+ };
+
+
+ Error = ERROR_SUCCESS;
+ hWnd = Arguments->hWnd;
+
+ ErrorOccurred = FALSE;
+ //
+ // Compute the cost of saving the hives and vdm files.
+ // For every hive we save, we have to save a key into a file and then
+ // compress the file. After each of these tasks is completed, we upgrade
+ // the gas gauge by the amount dicated by the COST_xxx values.
+ // The cost of saving the hives depends on the mode that the utility is
+ // running.
+ // In the silent mode we save system, software, security, sam and default.
+ // In the non-silent mode, we save system and software only.
+ //
+ NumberOfHivesToSave = ( _SilentMode )?
+ sizeof( HiveList ) / sizeof( HIVE_INFO ) :
+ (sizeof( HiveList ) / sizeof( HIVE_INFO ))-3;
+ NumberOfUserHivesToSave = 1;
+ NumberOfVdmFiles = sizeof( VdmFiles ) / sizeof( PWSTR );
+
+ GaugeDeltaUnit = GAUGE_BAR_RANGE / ( (COST_SAVE_HIVE * NumberOfHivesToSave)
+ + (COST_COMPRESS_HIVE * NumberOfHivesToSave)
+ + (COST_COMPRESS_HIVE * NumberOfUserHivesToSave)
+ + (COST_SAVE_VDM_FILE * NumberOfVdmFiles));
+
+ GaugePosition = 0;
+
+ //
+ // Enable BACKUP privilege
+ //
+ if(OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES,&Token)) {
+
+ if(LookupPrivilegeValue(NULL,SE_BACKUP_NAME,&Luid)) {
+
+ NewPrivileges.PrivilegeCount = 1;
+ NewPrivileges.Privileges[0].Luid = Luid;
+ NewPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+ AdjustTokenPrivileges(Token,FALSE,&NewPrivileges,0,NULL,NULL);
+ }
+ }
+
+ GetWindowsDirectory( RepairDirectory, sizeof( RepairDirectory ) / sizeof( WCHAR ) );
+ lstrcpy( ProfilesDirectory, RepairDirectory );
+ lstrcat( RepairDirectory, REPAIR_DIRECTORY );
+ lstrcat( ProfilesDirectory, PROFILES_DIRECTORY );
+
+ GetSystemDirectory( SystemDirectory, sizeof( SystemDirectory ) / sizeof( WCHAR ) );
+
+ //
+ // Make sure that the repair directory already exists.
+ // If it doesn't exist, then create one.
+ //
+ if( CreateDirectory( RepairDirectory, NULL ) ||
+ ( ( Error = GetLastError() ) == ERROR_ALREADY_EXISTS ) ||
+ ( Error == ERROR_ACCESS_DENIED )
+ ) {
+ //
+ // If the repair directory didn't exist and we were able to create it,
+ // or if the repair directory already exists, then save and compress
+ // the hives.
+ //
+
+ Error = ERROR_SUCCESS;
+ for( i=0; i < NumberOfHivesToSave; i++ ) {
+ //
+ // First open the root of the hive to be saved
+ //
+ Status = RegOpenKeyEx( HiveList[i].PredefinedKey,
+ HiveList[i].HiveName,
+ REG_OPTION_RESERVED,
+ READ_CONTROL,
+ &hkey );
+
+ //
+ // If unable to open the key, update the gas gauge to reflect
+ // that the operation on this hive was completed.
+ // Otherwise, save the hive. Note that Save hive will update
+ // the gas gauge, as it saves and compresses the hive.
+ //
+ if(Status != ERROR_SUCCESS) {
+ //
+ // If this is the first error while saving the hives,
+ // then save the error code, so that we can display the
+ // correct error message to the user.
+ //
+ if( Error == ERROR_SUCCESS ) {
+ Error = Status;
+ }
+
+ //
+ // Update the gas gauge
+ //
+ GaugePosition += GaugeDeltaUnit * (COST_SAVE_HIVE + COST_COMPRESS_HIVE);
+ SendMessage( hWnd,
+ AP_UPDATE_GAUGE,
+ GaugePosition,
+ 0L );
+
+ } else {
+ //
+ // Save and compress the hive.
+ // Note that the gas gauge will up be updated by SaveOneHive
+ // Note also that when we save the default user hive, we skip
+ // the first character of the
+ //
+
+ Status = SaveOneHive(RepairDirectory,
+ HiveList[i].FileName,
+ hkey,
+ hWnd,
+ &GaugePosition,
+ GaugeDeltaUnit );
+ //
+ // If this is the first error while saving the hives,
+ // then save the error code, so that we can display the
+ // correct error message to the user.
+ //
+
+ if( Error == ERROR_SUCCESS ) {
+ Error = Status;
+ }
+
+ RegCloseKey(hkey);
+ }
+ }
+
+ //
+ // Save the hive for the Default User
+ //
+
+ wsprintfA(SourceUserHivePathAnsi,"%ls\\%ls\\%ls",ProfilesDirectory,L"Default User",NTUSER_HIVE_FILE);
+ wsprintfA(CompressedUserHivePathAnsi,"%ls\\%ls",RepairDirectory,NTUSER_COMPRESSED_FILE_NAME);
+
+ //
+ // Delete the destination file just in case.
+ //
+ SetFileAttributesA(CompressedUserHivePathAnsi,FILE_ATTRIBUTE_NORMAL);
+ DeleteFileA(CompressedUserHivePathAnsi);
+
+ //
+ // Compress the hive into the destination file.
+ //
+ Status = DiamondCompressFile(
+ SourceUserHivePathAnsi,
+ CompressedUserHivePathAnsi,
+ GaugePosition,
+ GaugeDeltaUnit * COST_COMPRESS_HIVE,
+ hWnd
+ );
+ if( Status != ERROR_SUCCESS ) {
+ if( Error == ERROR_SUCCESS ) {
+ Error = Status;
+ }
+ }
+
+ GaugePosition += GaugeDeltaUnit * COST_COMPRESS_HIVE;
+ SendDlgItemMessage( hWnd,
+ ID_BAR,
+ PBM_SETPOS,
+ GaugePosition,
+ 0L
+ );
+
+
+ //
+ // Now that the hives are saved, save the vdm files
+ //
+
+ for( i = 0; i < NumberOfVdmFiles; i++ ) {
+ wsprintf(Source,L"%ls\\%ls",SystemDirectory,VdmFiles[i]);
+ wsprintf(Target,L"%ls\\%ls",RepairDirectory,VdmFiles[i]);
+ if( !CopyFile( Source, Target, FALSE ) ) {
+ Status = GetLastError();
+ if( Error != ERROR_SUCCESS ) {
+ Error = Status;
+ }
+ }
+ GaugePosition += GaugeDeltaUnit * COST_SAVE_VDM_FILE;
+ SendMessage( ( HWND )hWnd,
+ AP_UPDATE_GAUGE,
+ GaugePosition,
+ 0L );
+
+ }
+ }
+
+
+ //
+ // At this point, the operation was completed (successfully, or not).
+ // So update the gas gauge to 100%
+ //
+ SendMessage(hWnd,AP_UPDATE_GAUGE,GAUGE_BAR_RANGE,0L);
+
+ if( Error != ERROR_SUCCESS && !_SilentMode ) {
+ DisplayMsgBox(hWnd,
+ IDS_CANT_SAVE_CONFIGURATION,
+ MB_OK | MB_ICONEXCLAMATION,
+ _szApplicationName);
+ } else {
+ Sleep( 200 );
+ }
+
+ SendMessage( ( HWND )hWnd,
+ AP_TASK_COMPLETED,
+ (WPARAM)(Error == ERROR_SUCCESS),
+ 0L );
+ ExitThread( 0 );
+}
+
+VOID
+CopyFilesWorker(
+ IN PTHREAD_ARGUMENTS Arguments
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the thread that copiess all configuration information
+ from the repair directory to the repair disk.
+
+ This thread will send messages to the gas gauge dialog prcedure, so that
+ the gas gauge gets updated after each configuration file is copied.
+ This thread will also inform the user about errors that might have
+ occurred during the process of saving the configuration files.
+
+
+Arguments:
+
+ Arguments - Pointer to a structure that contains the parameters to be passed to
+ thread.
+
+
+Return Value:
+
+ None.
+ However, the this routine will send a message to the dialog procedure
+ that created the thread, informing the outcome the operation.
+
+--*/
+
+{
+ HWND hWnd;
+ WCHAR Drive;
+ WCHAR Buffer[ MAX_PATH + 1 ];
+ WCHAR Source[ MAX_PATH + 1 ];
+ WCHAR Target[ MAX_PATH + 1 ];
+ DWORD i;
+ DWORD GaugePosition = 0;
+ BOOLEAN AllFilesCopied = TRUE;
+ DWORD Error;
+
+
+ LPWSTR FileNames[] = { SETUP_LOG_FILE,
+ SYSTEM_COMPRESSED_FILE_NAME,
+ SOFTWARE_COMPRESSED_FILE_NAME,
+ SECURITY_COMPRESSED_FILE_NAME,
+ SAM_COMPRESSED_FILE_NAME,
+ DEFAULT_COMPRESSED_FILE_NAME,
+ NTUSER_COMPRESSED_FILE_NAME,
+ AUTOEXEC_NT_FILE_NAME,
+ CONFIG_NT_FILE_NAME
+ };
+
+ DWORD DeltaCompleted = GAUGE_BAR_RANGE / ( sizeof( FileNames )/sizeof( PWSTR ) );
+
+ hWnd = Arguments->hWnd;
+ Drive = Arguments->DriveLetter;
+
+ GetWindowsDirectory( Buffer, sizeof( Buffer ) / sizeof( WCHAR ) );
+ for( i=0;
+ i < ( sizeof( FileNames )/sizeof( PWCHAR ) );
+ i++) {
+
+ wsprintf(Source,L"%ls\\repair\\%ls",Buffer,FileNames[i] );
+ wsprintf(Target,L"%wc:\\%ls",Drive,FileNames[i]);
+
+ if( !CopyFile( Source, Target, FALSE ) ) {
+ AllFilesCopied = FALSE;
+ Error = GetLastError();
+ }
+ GaugePosition += DeltaCompleted;
+ SendMessage( ( HWND )hWnd,
+ AP_UPDATE_GAUGE,
+ GaugePosition,
+ 0L
+ );
+ }
+ SendMessage( ( HWND )hWnd,
+ AP_UPDATE_GAUGE,
+ GAUGE_BAR_RANGE,
+ 0L
+ );
+
+ if( !AllFilesCopied && !_SilentMode ) {
+ DWORD MsgId;
+
+ if( Error == ERROR_FILE_NOT_FOUND ) {
+ MsgId = IDS_FILE_NOT_FOUND;
+ } else if( Error == ERROR_DISK_FULL ) {
+ MsgId = IDS_DISK_FULL;
+ } else {
+ MsgId = IDS_UNABLE_TO_COPY_ALL_FILES;
+ }
+ DisplayMsgBox(hWnd,MsgId,MB_OK | MB_ICONEXCLAMATION,_szApplicationName);
+ } else {
+ Sleep( 200 );
+ }
+ SendMessage( ( HWND )hWnd,
+ AP_TASK_COMPLETED,
+ (WPARAM)AllFilesCopied,
+ 0L
+ );
+
+ ExitThread(0);
+}
+
+BOOL
+Progress2DlgProc(
+ IN HWND hdlg,
+ IN UINT Msg,
+ IN WPARAM wParam,
+ IN LONG lParam
+ )
+/*++
+
+Routine Description:
+
+ Dialog procedure for the dialog that contains the gas gauge that is
+ displayed while the utility is saving the system configuration, and
+ while it is copying the configuration information to the repair disk.
+
+Arguments:
+
+ Standard Windows' Proc parameters.
+
+Return Value:
+
+ long - Returns 0 if the message was handled.
+
+--*/
+
+{
+ static THREAD_ARGUMENTS ThreadArguments;
+
+ switch(Msg) {
+
+ case WM_INITDIALOG:
+ {
+ WCHAR Buffer[MAX_PATH];
+ LPTHREAD_START_ROUTINE StartAddress;
+ DWORD ThreadId;
+ PPROGRESS_PARAMETERS Parameters;
+
+ Parameters = ( PPROGRESS_PARAMETERS )lParam;
+
+ //
+ // set up range for percentage (0-100) display
+ //
+ SendDlgItemMessage(hdlg,ID_BAR,PBM_SETRANGE,0,MAKELPARAM(0,GAUGE_BAR_RANGE));
+
+ //
+ // Set the caption
+ //
+ switch( Parameters->OperationType ) {
+
+ case SaveConfiguration:
+
+ LoadString( _hModule,
+ IDS_SAVING_CONFIGURATION,Buffer,
+ sizeof(Buffer)/sizeof(WCHAR) );
+ StartAddress = ( LPTHREAD_START_ROUTINE )SaveConfigurationWorker;
+ break;
+
+ case CopyConfigurationFiles:
+
+ LoadString( _hModule,
+ IDS_COPYING_FILES,
+ Buffer,sizeof(Buffer)/sizeof(WCHAR) );
+ StartAddress = ( LPTHREAD_START_ROUTINE )CopyFilesWorker;
+ break;
+
+ default:
+ //
+ // Error condition!!
+ // Do something here
+ //
+ break;
+ }
+
+ SetWindowText( hdlg, Buffer);
+
+ //
+ // center the dialog relative to the desk top
+ //
+ FCenterDialogOnDesktop(hdlg);
+
+ ThreadArguments.hWnd = hdlg;
+ ThreadArguments.DriveLetter = Parameters->DriveLetter;
+ CreateThread( NULL,
+ 1024,
+ StartAddress,
+ &ThreadArguments,
+ 0,
+ &ThreadId );
+ break;
+ }
+
+ case AP_UPDATE_GAUGE:
+ SendDlgItemMessage( hdlg,
+ ID_BAR,
+ PBM_SETPOS,
+ wParam,
+ 0L );
+ break;
+
+ case AP_TASK_COMPLETED:
+ {
+ BOOLEAN MessagePosted;
+
+ SendDlgItemMessage( hdlg,
+ ID_BAR,
+ PBM_SETPOS,
+ GAUGE_BAR_RANGE,
+ 0L );
+ MessagePosted = FALSE;
+ while( !MessagePosted ) {
+ MessagePosted = PostMessage( hdlg,
+ AP_TERMINATE_DIALOG,
+ wParam,
+ 0 );
+ }
+ break;
+ }
+
+ case AP_TERMINATE_DIALOG:
+
+ EndDialog(hdlg, wParam);
+ break;
+
+ default:
+
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+
+BOOLEAN
+CopyFilesToRepairDisk(
+ IN WCHAR Drive
+ )
+
+/*++
+
+Routine Description:
+
+ Copy the files in the repair directory, to the emergency repair disk.
+
+Arguments:
+
+ Drive - Drive where the repair disk is.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeded, or FALSE otherwise.
+
+--*/
+
+{
+ PROGRESS_PARAMETERS Parameters;
+ BOOLEAN Result;
+
+ Parameters.OperationType = CopyConfigurationFiles;
+ Parameters.DriveLetter = Drive;
+
+ Result = (BOOLEAN)DialogBoxParam( _hModule,
+ MAKEINTRESOURCE( IDD_PROGRESS2 ),
+ _hWndMain,
+ ( DLGPROC )Progress2DlgProc,
+ ( LPARAM )&Parameters
+ );
+ return( Result );
+}
+
+
+BOOLEAN
+DetectConfigFilesInRepairDirectory(
+ )
+
+/*++
+
+Routine Description:
+
+ Determine whether or not the the repair directory contains at
+ least one configuration file.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if at least one configuration file is present.
+ Returns FALSE if no configuration files are present.
+
+
+--*/
+
+{
+ HANDLE Handle;
+ WIN32_FIND_DATA FindData;
+ WCHAR RepairDirectory[ MAX_PATH + 1];
+ WCHAR FileName[ MAX_PATH + 1];
+ DWORD i;
+ BOOLEAN AtLeastOneFilePresent = FALSE;
+
+ LPWSTR ConfigurationFiles[] = { AUTOEXEC_NT_FILE_NAME,
+ CONFIG_NT_FILE_NAME,
+ SYSTEM_COMPRESSED_FILE_NAME,
+ SOFTWARE_COMPRESSED_FILE_NAME,
+ SECURITY_COMPRESSED_FILE_NAME,
+ SAM_COMPRESSED_FILE_NAME,
+ DEFAULT_COMPRESSED_FILE_NAME,
+ NTUSER_COMPRESSED_FILE_NAME
+ };
+
+ GetWindowsDirectory( RepairDirectory, sizeof( RepairDirectory ) / sizeof( WCHAR ) );
+ wcscat( RepairDirectory, REPAIR_DIRECTORY );
+ for( i = 0;
+ i < sizeof( ConfigurationFiles ) / sizeof( PWSTR );
+ i++ ) {
+ wsprintf(FileName,L"%ls\\%ls",RepairDirectory,ConfigurationFiles[i]);
+
+ if( ( Handle = FindFirstFile(FileName, &FindData) ) != INVALID_HANDLE_VALUE ) {
+ AtLeastOneFilePresent = TRUE;
+ FindClose( Handle );
+ break;
+ }
+ }
+ return( AtLeastOneFilePresent );
+}
+
+
+BOOLEAN
+SaveCurrentConfiguration(
+ )
+
+/*++
+
+Routine Description:
+
+ Save all files that contain the current system configuration, into
+ the repair directory.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeded, or FALSE otherwise.
+
+--*/
+
+
+{
+ PROGRESS_PARAMETERS Parameters;
+ BOOLEAN Result;
+
+ Result = FALSE;
+ if( _SilentMode ||
+ !DetectConfigFilesInRepairDirectory() ||
+ ( DisplayMsgBox( _hWndMain,
+ IDS_CONFIRM_SAVE_CONFIGURATION,
+ MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2 ) == IDYES ) ) {
+
+ Parameters.OperationType = SaveConfiguration;
+ Parameters.DriveLetter = ( WCHAR )'\0';
+
+ Result = (BOOLEAN)DialogBoxParam( _hModule,
+ MAKEINTRESOURCE( IDD_PROGRESS2 ),
+ _hWndMain,
+ ( DLGPROC )Progress2DlgProc,
+ ( LPARAM )&Parameters
+ );
+ }
+ return( Result );
+}
+
diff --git a/private/utils/rdisk/dialogs.dlg b/private/utils/rdisk/dialogs.dlg
new file mode 100644
index 000000000..108f846e8
--- /dev/null
+++ b/private/utils/rdisk/dialogs.dlg
@@ -0,0 +1,27 @@
+1 DLGINCLUDE "dialogs.H"
+#include <commctrl.h>
+
+IDD_PROGRESS2 DIALOG 65, 85, 210, 30
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+STYLE WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CAPTION
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "", ID_BAR, PROGRESS_CLASS, 0x0000, 15, 10, 180, 10
+END
+
+
+IDD_REPAIR DIALOG 11, 18, 329, 86
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+STYLE WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Repair Disk Utility"
+FONT 8, "MS Shell Dlg"
+CLASS "Repair"
+BEGIN
+ ICON 200, IDI_MAIN_DLG_ICON, 16, 10, 18, 20
+ LTEXT "This utility updates the repair information saved when you installed the system, and creates an Emergency Repair disk. The repair information is used to recover a bootable system in case of failure. This utility should not be used as a backup tool.",
+ IDT_INFO_LINE, 45, 10, 258, 34
+ DEFPUSHBUTTON "&Update Repair Info", IDB_SAVE_CURRENT_INFO, 11, 63, 70, 14
+ PUSHBUTTON "&Create Repair Disk", IDB_CREATE_DISK, 90, 63, 70, 14
+ PUSHBUTTON "E&xit", IDB_EXIT, 169, 63, 70, 14
+ PUSHBUTTON "&Help", IDB_HELP, 248, 63, 70, 14
+END
diff --git a/private/utils/rdisk/dialogs.h b/private/utils/rdisk/dialogs.h
new file mode 100644
index 000000000..a69534d29
--- /dev/null
+++ b/private/utils/rdisk/dialogs.h
@@ -0,0 +1,10 @@
+#define IDD_PROGRESS2 1000
+#define ID_BAR 1001
+#define IDD_REPAIR 100
+#define IDB_SAVE_CURRENT_INFO 101
+#define IDB_CREATE_DISK 102
+#define IDB_HELP 103
+#define ID_GAS_GAUGE 104
+#define IDT_INFO_LINE 105
+#define IDI_MAIN_DLG_ICON 106
+#define IDB_EXIT 108
diff --git a/private/utils/rdisk/diamond.c b/private/utils/rdisk/diamond.c
new file mode 100644
index 000000000..4e77dae2d
--- /dev/null
+++ b/private/utils/rdisk/diamond.c
@@ -0,0 +1,476 @@
+/*++
+
+Module Name:
+
+ diamond.c
+
+Abstract:
+
+ Diamond compression interface.
+
+ This module contains functions to compress a file using
+ the mszip compression library.
+
+Author:
+
+ Ted Miller
+
+Environment:
+
+ Windows
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+typedef struct _COMPRESS_CONTEXT {
+ DWORD GaugeBasePosition;
+ DWORD GaugeRangeForFile;
+ HWND GaugeWindow;
+ DWORD FileSize;
+ DWORD BytesCompressedSoFar;
+} COMPRESS_CONTEXT, *PCOMPRESS_CONTEXT;
+
+DWORD DiamondLastError;
+
+//
+// Callback functions to perform memory allocation, io, etc.
+// We pass addresses of these functions to diamond.
+//
+int
+DIAMONDAPI
+fciFilePlacedCB(
+ OUT PCCAB Cabinet,
+ IN PSTR FileName,
+ IN LONG FileSize,
+ IN BOOL Continuation,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ Callback used by diamond to indicate that a file has been
+ comitted to a cabinet.
+
+ No action is taken and success is returned.
+
+Arguments:
+
+ Cabinet - cabinet structure to fill in.
+
+ FileName - name of file in cabinet
+
+ FileSize - size of file in cabinet
+
+ Continuation - TRUE if this is a partial file, continuation
+ of compression begun in a different cabinet.
+
+ Context - supplies context information.
+
+Return Value:
+
+ 0 (success).
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(Cabinet);
+ UNREFERENCED_PARAMETER(FileName);
+ UNREFERENCED_PARAMETER(FileSize);
+ UNREFERENCED_PARAMETER(Continuation);
+ UNREFERENCED_PARAMETER(Context);
+
+ return(0);
+}
+
+
+
+PVOID
+DIAMONDAPI
+fciAllocCB(
+ IN ULONG NumberOfBytes
+ )
+
+/*++
+
+Routine Description:
+
+ Callback used by diamond to allocate memory.
+
+Arguments:
+
+ NumberOfBytes - supplies desired size of block.
+
+Return Value:
+
+ Returns pointer to a block of memory or NULL
+ if memory cannot be allocated.
+
+--*/
+
+{
+ return((PVOID)LocalAlloc(LMEM_FIXED,NumberOfBytes));
+}
+
+
+VOID
+DIAMONDAPI
+fciFreeCB(
+ IN PVOID Block
+ )
+
+/*++
+
+Routine Description:
+
+ Callback used by diamond to free a memory block.
+ The block must have been allocated with fciAlloc().
+
+Arguments:
+
+ Block - supplies pointer to block of memory to be freed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LocalFree((HLOCAL)Block);
+}
+
+
+
+BOOL
+DIAMONDAPI
+fciTempFileCB(
+ OUT PSTR TempFileName,
+ IN int TempFileNameBufferSize
+ )
+
+/*++
+
+Routine Description:
+
+ Callback used by diamond to request a tempfile name.
+
+Arguments:
+
+ TempFileName - receives temp file name.
+
+ TempFileNameBufferSize - supplies size of memory block
+ pointed to by TempFileName.
+
+Return Value:
+
+ TRUE (success).
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(TempFileNameBufferSize);
+
+ if(GetTempFileNameA(".","dc",0,TempFileName)) {
+ //
+ // GetTempFileNameA will create the file, causing
+ // FCI to fail when it tries to open it using _O_EXCL.
+ //
+ DeleteFileA(TempFileName);
+ }
+
+ return(TRUE);
+}
+
+
+BOOL
+DIAMONDAPI
+fciNextCabinetCB(
+ OUT PCCAB Cabinet,
+ IN DWORD CabinetSizeEstimate,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ Callback used by diamond to request a new cabinet file.
+ This functionality is not used in our implementation as
+ we deal only with single-file cabinets.
+
+Arguments:
+
+ Cabinet - cabinet structure to be filled in.
+
+ CabinetSizeEstimate - estimated size of cabinet.
+
+ Context - supplies context information.
+
+Return Value:
+
+ FALSE (failure).
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(Cabinet);
+ UNREFERENCED_PARAMETER(CabinetSizeEstimate);
+ UNREFERENCED_PARAMETER(Context);
+
+ return(FALSE);
+}
+
+
+BOOL
+DIAMONDAPI
+fciStatusCB(
+ IN UINT StatusType,
+ IN DWORD Count1,
+ IN DWORD Count2,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ Callback used by diamond to give status on file compression
+ and cabinet operations, etc.
+
+ This routine has no effect.
+
+Arguments:
+
+ Status Type - supplies status type.
+
+ 0 = statusFile - compressing block into a folder.
+ Count1 = compressed size
+ Count2 = uncompressed size
+
+ 1 = statusFolder - performing AddFilder.
+ Count1 = bytes done
+ Count2 = total bytes
+
+ Context - supplies context info.
+
+Return Value:
+
+ TRUE (success).
+
+--*/
+
+{
+ PCOMPRESS_CONTEXT context;
+ DWORD delta;
+
+ UNREFERENCED_PARAMETER(Count1);
+
+ context = (PCOMPRESS_CONTEXT)Context;
+
+ if(StatusType == statusFile) {
+
+ //
+ // Update number of bytes compressed so far.
+ //
+ context->BytesCompressedSoFar += Count2;
+
+ //
+ // Calculate the gauge offset from the base position
+ // for this file. We do this carefully to avoid overflow.
+ //
+ delta = (DWORD)( (LONGLONG)context->GaugeRangeForFile
+ * (LONGLONG)context->BytesCompressedSoFar
+ / (LONGLONG)context->FileSize);
+
+ //
+ // Update the gas gauge.
+ //
+ SendDlgItemMessage( context->GaugeWindow,
+ ID_BAR,
+ PBM_SETPOS,
+ context->GaugeBasePosition + delta,
+ 0L
+ );
+ }
+
+ return(TRUE);
+}
+
+
+
+int
+DIAMONDAPI
+fciOpenInfoCB(
+ IN PSTR FileName,
+ OUT WORD *DosDate,
+ OUT WORD *DosTime,
+ OUT WORD *FileAttributes,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ Callback used by diamond to open a file and retreive information
+ about it.
+
+Arguments:
+
+ FileName - supplies filename of file about which information
+ is desired.
+
+ DosDate - receives last write date of the file if the file exists.
+
+ DosTime - receives last write time of the file if the file exists.
+
+ FileAttributes - receives file attributes if the file exists.
+
+ Context - supplies context information.
+
+Return Value:
+
+ C runtime handle to open file if success; -1 if file could
+ not be located or opened.
+
+--*/
+
+{
+ int h;
+ WIN32_FIND_DATAA FindData;
+ HANDLE FindHandle;
+ PCOMPRESS_CONTEXT context;
+
+ context = Context;
+
+ FindHandle = FindFirstFileA(FileName,&FindData);
+ if(FindHandle == INVALID_HANDLE_VALUE) {
+ DiamondLastError = GetLastError();
+ return(-1);
+ }
+ FindClose(FindHandle);
+
+ context->FileSize = FindData.nFileSizeLow;
+
+ FileTimeToDosDateTime(&FindData.ftLastWriteTime,DosDate,DosTime);
+ *FileAttributes = (WORD)FindData.dwFileAttributes;
+
+ h = _open(FileName,_O_RDONLY | _O_BINARY);
+ if(h == -1) {
+ DiamondLastError = GetLastError();
+ return(-1);
+ }
+
+ return(h);
+}
+
+
+
+DWORD
+DiamondCompressFile(
+ IN PSTR SourceFile,
+ IN PSTR TargetFile,
+ IN DWORD GaugeBasePosition,
+ IN DWORD GaugeRangeForThisFile,
+ IN HWND GaugeNotifyWindow
+ )
+{
+ BOOL b;
+ PSTR SourceFilenamePart,p;
+ HFCI FciContext;
+ ERF FciError;
+ CCAB ccab;
+ COMPRESS_CONTEXT GaugeContext;
+
+ //
+ // Isolate the filename part of the source file.
+ //
+ if(SourceFilenamePart = strrchr(SourceFile,'\\')) {
+ SourceFilenamePart++;
+ } else {
+ SourceFilenamePart = SourceFile;
+ }
+
+ //
+ // Fill in the cabinet structure.
+ //
+ ZeroMemory(&ccab,sizeof(ccab));
+
+ lstrcpyA(ccab.szCabPath,TargetFile);
+ if(p=strrchr(ccab.szCabPath,'\\')) {
+ lstrcpyA(ccab.szCab,++p);
+ *p = 0;
+ } else {
+ lstrcpyA(ccab.szCab,TargetFile);
+ ccab.szCabPath[0] = 0;
+ }
+
+ DiamondLastError = NO_ERROR;
+
+ GaugeContext.GaugeBasePosition = GaugeBasePosition;
+ GaugeContext.GaugeRangeForFile = GaugeRangeForThisFile;
+ GaugeContext.GaugeWindow = GaugeNotifyWindow;
+ GaugeContext.FileSize = 0;
+ GaugeContext.BytesCompressedSoFar = 0;
+
+ //
+ // Compress the file.
+ //
+ FciContext = FCICreate(
+ &FciError,
+ fciFilePlacedCB,
+ fciAllocCB,
+ fciFreeCB,
+ fciTempFileCB,
+ &ccab
+ );
+
+ if(FciContext) {
+
+ b = FCIAddFile(
+ FciContext,
+ SourceFile, // file to add to cabinet.
+ SourceFilenamePart, // filename part, name to store in cabinet.
+ FALSE, // fExecute on extract
+ fciNextCabinetCB, // routine for next cabinet (always fails)
+ fciStatusCB,
+ fciOpenInfoCB,
+ tcompTYPE_MSZIP,
+ &GaugeContext
+ );
+
+ if(b) {
+
+ b = FCIFlushCabinet(
+ FciContext,
+ FALSE,
+ fciNextCabinetCB,
+ fciStatusCB,
+ &GaugeContext
+ );
+
+ }
+
+ FCIDestroy(FciContext);
+ }
+
+ return(b ? NO_ERROR : ((DiamondLastError == NO_ERROR) ? ERROR_INVALID_FUNCTION : DiamondLastError));
+}
+
+
+#if 0
+#include <stdio.h>
+void __cdecl main(int argc,char *argv[])
+{
+
+ if(argc == 3) {
+ DiamondCompressFile(argv[1],argv[2]);
+ } else {
+ printf("bad args\n");
+ }
+}
+#endif
diff --git a/private/utils/rdisk/floppyop.c b/private/utils/rdisk/floppyop.c
new file mode 100644
index 000000000..1195aab97
--- /dev/null
+++ b/private/utils/rdisk/floppyop.c
@@ -0,0 +1,888 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ restore.c
+
+Abstract:
+
+ Code to handle interfacing with fmifs.dll for formatting and copying
+ floppy disks.
+
+Author:
+
+ Ted Miller (tedm) 28-July-1992
+
+Revision History:
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+VOID
+FmifsThread(
+ IN PVOID Arguments
+ );
+
+
+
+/*
+** Purpose:
+** To center a dialog on the desktop window.
+** Arguments:
+** hdlg: Handle to the dialog being centered
+** Returns:
+** fTrue: Centering succeeded.
+** fFalse: Error condition.
+**
+****************************************************************************/
+
+BOOL
+FCenterDialogOnDesktop(
+ HWND hdlg
+ )
+
+{
+
+ RECT DesktopRect, DlgRect;
+ BOOL bStatus;
+ HWND hwMaster ;
+ POINT pt,
+ ptCtr,
+ ptMax,
+ ptDlgSize ;
+ LONG l ;
+
+ ptMax.x = GetSystemMetrics( SM_CXFULLSCREEN ) ;
+ ptMax.y = GetSystemMetrics( SM_CYFULLSCREEN ) ;
+
+ //
+ // Determine area of shell and of dlg
+ //
+ // Center dialog over the "pseudo parent" if there is one.
+ //
+
+// hwMaster = hwPseudoParent
+// ? hwPseudoParent
+// : GetDesktopWindow() ;
+ hwMaster = GetDesktopWindow() ;
+
+ if ( ! GetWindowRect( hwMaster, & DesktopRect ) )
+ return FALSE ;
+
+ if ( ! GetWindowRect( hdlg, & DlgRect ) )
+ return FALSE ;
+
+ ptDlgSize.x = DlgRect.right - DlgRect.left ;
+ ptDlgSize.y = DlgRect.bottom - DlgRect.top ;
+
+ // Attempt to center our dialog on top of the "master" window.
+
+ ptCtr.x = DesktopRect.left + ((DesktopRect.right - DesktopRect.left) / 2) ;
+ ptCtr.y = DesktopRect.top + ((DesktopRect.bottom - DesktopRect.top) / 2) ;
+ pt.x = ptCtr.x - (ptDlgSize.x / 2) ;
+ pt.y = ptCtr.y - (ptDlgSize.y / 2) ;
+
+ // Force upper left corner back onto screen if necessary.
+
+ if ( pt.x < 0 )
+ pt.x = 0 ;
+ if ( pt.y < 0 )
+ pt.y = 0 ;
+
+ // Now check to see if the dialog is getting clipped
+ // to the right or bottom.
+
+ if ( (l = pt.x + ptDlgSize.x) > ptMax.x )
+ pt.x -= l - ptMax.x ;
+ if ( (l = pt.y + ptDlgSize.y) > ptMax.y )
+ pt.y -= l - ptMax.y ;
+
+ if ( pt.x < 0 )
+ pt.x = 0 ;
+ if ( pt.y < 0 )
+ pt.y = 0 ;
+
+ //
+ // center the dialog window in the shell window. Specify:
+ //
+ // SWP_NOSIZE : To ignore the cx,cy params given
+ // SWP_NOZORDER : To ignore the HwndInsert after parameter and retain the
+ // current z ordering.
+ // SWP_NOACTIVATE : To not activate the window.
+ //
+
+ bStatus = SetWindowPos
+ (
+ hdlg,
+ (HWND) NULL,
+ pt.x,
+ pt.y,
+ 0,
+ 0,
+ SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE
+ );
+
+ //
+ // return Status of operation
+ //
+
+ return(bStatus);
+
+}
+
+
+typedef enum _FLOPPY_OPERATION {
+ FloppyOpFormat,
+#ifdef FLOPPY_COPY
+ FloppyOpDiskcopy,
+#endif
+ FloppyOpMaximum
+} FLOPPY_OPERATION, *PFLOPPY_OPERATION;
+
+
+typedef struct _FLOPPY_OPERATION_PARAMS {
+
+ FLOPPY_OPERATION Operation;
+ WCHAR DriveLetter;
+ FMIFS_MEDIA_TYPE MediaType;
+ UINT CaptionResId;
+ UINT GeneralFailureResId;
+ UINT SrcDiskPromptResId;
+ UINT DstDiskPromptResId;
+
+} FLOPPY_OPERATION_PARAMS, *PFLOPPY_OPERATION_PARAMS;
+
+
+#define WM_FMIFS_CALLBACK (WM_USER+137)
+
+BOOL
+ProgressDlgProc(
+ IN HWND hdlg,
+ IN UINT Msg,
+ IN WPARAM wParam,
+ IN LONG lParam
+ );
+
+BOOLEAN
+FmifsCallbackRoutine(
+ IN FMIFS_PACKET_TYPE PacketType,
+ IN DWORD PacketLength,
+ IN PVOID PacketAddress
+ );
+
+
+HMODULE FmifsModule;
+
+PFMIFS_FORMAT_ROUTINE FmifsFormat;
+#ifdef FLOPPY_COPY
+PFMIFS_DISKCOPY_ROUTINE FmifsDiskCopy;
+#endif
+PFMIFS_QSUPMEDIA_ROUTINE FmifsQuerySupportedMedia;
+
+HWND ProgressDialog;
+
+BOOL
+InitializeFloppySup(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the floppy-disk support package for formatting and diskcopying.
+ Load the fmifs dll.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if initialization succeeded. FALSE otherwise. It is the caller's
+ responsibility to put up a msg box informing the user of the error.
+
+--*/
+
+{
+ ProgressDialog = NULL;
+
+ if(FmifsModule) {
+ // already initialized
+ return(TRUE);
+ }
+
+ //
+ // Load the fmifs dll.
+ //
+
+ if((FmifsModule = LoadLibrary(TEXT("fmifs"))) == NULL) {
+
+ return(FALSE);
+ }
+
+ //
+ // Get the addresses of relevent entry points.
+ //
+
+ FmifsFormat = (PFMIFS_FORMAT_ROUTINE)GetProcAddress( FmifsModule,
+ (LPCSTR)"Format"
+ );
+
+#ifdef FLOPPY_COPY
+ FmifsDiskCopy = (PFMIFS_DISKCOPY_ROUTINE)GetProcAddress( FmifsModule,
+ TEXT("DiskCopy")
+ );
+#endif
+
+ FmifsQuerySupportedMedia = (PFMIFS_QSUPMEDIA_ROUTINE)GetProcAddress( FmifsModule,
+ (LPCSTR)"QuerySupportedMedia"
+ );
+
+
+ if((FmifsFormat == NULL)
+#ifdef FLOPPY_COPY
+ || (FmifsDiskCopy == NULL)
+#endif
+ || (FmifsQuerySupportedMedia == NULL))
+ {
+ FreeLibrary(FmifsModule);
+ FmifsModule = NULL;
+
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+
+VOID
+TerminateFloppySup(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Terminate the floppy-disk support package for formatting and diskcopying.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ FreeLibrary(FmifsModule);
+ FmifsModule = NULL;
+}
+
+
+
+BOOL
+FormatFloppyDisk(
+ IN WCHAR DriveLetter,
+ IN HWND hwndOwner,
+ OUT PBOOL Fatal
+ )
+
+/*++
+
+Routine Description:
+
+ Top-level routine to format a floppy in the given drive. A floppy
+ disk must already be in the drive or this routine will fail.
+
+ This routine also makes sure that the drive can handle 1.2 or 1.44 meg
+ disks (ie fail if low-density drive) and format to one of those two
+ densities (ie, no 20.8 scsi flopticals).
+
+Arguments:
+
+ DriveLetter - supplies drive letter of drive to format, A-Z or a-z.
+
+ hwndOwner - supplies handle of window that is to own the progress dlg.
+
+ Fatal - see below.
+
+Return Value:
+
+ TRUE if the format succeeded.
+ FALSE if not. In this case, the Fatal flag will be filled in
+ appropriately -- the user should be allowed to retry in this case.
+
+--*/
+
+{
+ BOOL Flag;
+ WCHAR WideName[3];
+ DWORD cMediaTypes;
+ PFMIFS_MEDIA_TYPE MediaTypes;
+ FMIFS_MEDIA_TYPE MediaType;
+ FLOPPY_OPERATION_PARAMS FloppyOp;
+
+ *Fatal = TRUE;
+
+ //
+ // Determine which format to use (1.2 or 1.44). First determine how big
+ // we need the array of supported types to be, then allocate an array of
+ // that size and call QuerySupportedMedia.
+ //
+
+ WideName[0] = (WCHAR)DriveLetter; // BUGBUG check this
+ WideName[1] = L':';
+ WideName[2] = 0;
+
+ Flag = FmifsQuerySupportedMedia( WideName,
+ NULL,
+ 0,
+ &cMediaTypes
+ );
+
+ if(Flag == FALSE) {
+ *Fatal = FALSE; //allow retry
+ DisplayMsgBox(hwndOwner,
+ IDS_CANTDETERMINEFLOPTYPE,
+ MB_OK | MB_ICONEXCLAMATION,
+ _szApplicationName);
+ return(FALSE);
+ }
+
+ while((MediaTypes = (PFMIFS_MEDIA_TYPE)LocalAlloc(LMEM_FIXED,cMediaTypes * sizeof(FMIFS_MEDIA_TYPE))) == NULL) {
+ //
+ // BUGBUG -
+ //
+ // if(!FHandleOOM(hwndOwner)) {
+ // return(FALSE);
+ // }
+ }
+
+ Flag = FmifsQuerySupportedMedia( WideName,
+ MediaTypes,
+ cMediaTypes,
+ &cMediaTypes
+ );
+
+ if(Flag == FALSE) {
+ *Fatal = FALSE; //allow retry
+ LocalFree(MediaTypes);
+ DisplayMsgBox(hwndOwner,
+ IDS_CANTDETERMINEFLOPTYPE | MB_ICONEXCLAMATION,
+ MB_OK,
+ _szApplicationName);
+ return(FALSE);
+ }
+
+
+ //
+ // Zeroth entry is the highest capacity
+ //
+
+ switch(*MediaTypes) {
+
+ case FmMediaF5_1Pt2_512: // 5.25", 1.2MB, 512 bytes/sector
+
+ MediaType = FmMediaF5_1Pt2_512;
+ break;
+
+ case FmMediaF3_1Pt44_512: // 3.5", 1.44MB, 512 bytes/sector
+
+ MediaType = FmMediaF3_1Pt44_512;
+ break;
+
+ case FmMediaF3_2Pt88_512: // 3.5", 2.88MB, 512 bytes/sector
+ {
+ WCHAR VolumeNameBuffer[MAX_PATH + 1];
+ DWORD VolumeSerialNumber;
+ DWORD MaximumComponentLength;
+ DWORD FileSystemFlags;
+ WCHAR FileSystemName[128];
+ UINT ErrorMode;
+
+ //
+ // If the disk drive is a 2.88 Mb drive, then find out if the disk is formatted
+ // as a 2.88 Mb disk. If it is, then reformat the disk as a 2.88 Mb disk, otherwise,
+ // reformat it as a 1.44 Mb disk
+ //
+
+ //
+ // Initially, assume that the disk format is 1.44 Mb
+ //
+ MediaType = FmMediaF3_1Pt44_512;
+
+ //
+ // Find out whether or not the floppy should be formatted as a 2.88 Mb disk
+ //
+ ErrorMode = SetErrorMode( SEM_FAILCRITICALERRORS );
+ if( GetVolumeInformation( (LPWSTR)L"A:\\",
+ VolumeNameBuffer,
+ sizeof( VolumeNameBuffer ) / sizeof( WCHAR ),
+ &VolumeSerialNumber,
+ &MaximumComponentLength,
+ &FileSystemFlags,
+ FileSystemName,
+ sizeof( FileSystemName ) / sizeof( WCHAR ) ) &&
+ ( _wcsicmp( FileSystemName, (LPWSTR)L"RAW" ) != 0 )
+ ) {
+
+ //
+ // The disk is formatted. Check if it is formatted as a 2.88 Mb disk
+ //
+ DWORD BytesReturned;
+ DISK_GEOMETRY DiskGeometry;
+ HANDLE hDevice;
+
+
+ if( ( hDevice = CreateFile( L"\\\\.\\A:",
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL ) ) != INVALID_HANDLE_VALUE ) {
+ if( DeviceIoControl( hDevice,
+ IOCTL_DISK_GET_DRIVE_GEOMETRY,
+ NULL,
+ 0,
+ &DiskGeometry,
+ sizeof( DISK_GEOMETRY),
+ &BytesReturned,
+ NULL ) &&
+ ( DiskGeometry.MediaType == F3_2Pt88_512 )
+ ) {
+ //
+ // The disk is a 2.88 Mb
+ //
+ MediaType = FmMediaF3_2Pt88_512;
+ }
+ CloseHandle( hDevice );
+ }
+ }
+ SetErrorMode( ErrorMode );
+ }
+ break;
+
+ case FmMediaF3_120M_512: // 3.5", 120M Floppy
+ //
+ // We get this back *only* if there is a 120MB floppy
+ // actually in the drive right now.
+ //
+ // For SUR disallow these.
+ //
+ DisplayMsgBox(hwndOwner,
+ IDS_HUGEFLOPPYNOTSUPPORTED,
+ MB_OK | MB_ICONEXCLAMATION,
+ _szApplicationName);
+
+ LocalFree(MediaTypes);
+ *Fatal = FALSE; //allow retry
+ return(FALSE);
+
+ case FmMediaF3_20Pt8_512: // 3.5", 20.8MB, 512 bytes/sector
+
+#if i386
+ {
+ DWORD i;
+
+ //
+ // Look for a compatibility mode
+ //
+
+ for(i=1; i<cMediaTypes; i++) {
+
+ if((MediaTypes[i] == FmMediaF5_1Pt2_512)
+ || (MediaTypes[i] == FmMediaF3_1Pt44_512))
+ {
+ MediaType = MediaTypes[i];
+ break;
+ }
+ }
+
+ if(i < cMediaTypes) {
+ break;
+ }
+ }
+ // fall through
+
+#else
+ //
+ // On an ARC machine, use whatever floppies the user has since
+ // we aren't required to boot from it.
+ //
+
+ MediaType = *MediaTypes;
+ break;
+#endif
+
+ case FmMediaF5_160_512: // 5.25", 160KB, 512 bytes/sector
+ case FmMediaF5_180_512: // 5.25", 180KB, 512 bytes/sector
+ case FmMediaF5_320_512: // 5.25", 320KB, 512 bytes/sector
+ case FmMediaF5_320_1024: // 5.25", 320KB, 1024 bytes/sector
+ case FmMediaF5_360_512: // 5.25", 360KB, 512 bytes/sector
+ case FmMediaF3_720_512: // 3.5", 720KB, 512 bytes/sector
+ case FmMediaRemovable: // Removable media other than floppy
+ case FmMediaFixed:
+ case FmMediaUnknown:
+ default:
+
+ DisplayMsgBox(hwndOwner,
+ IDS_BADFLOPPYTYPE,
+ MB_OK | MB_ICONEXCLAMATION);
+ LocalFree(MediaTypes);
+
+ //
+ // Unknown can be returned in the case where the drive is an ATAPI floppy
+ // and there's no media in the drive. Allow retry.
+ //
+ if(*MediaTypes == FmMediaUnknown) {
+ *Fatal = FALSE;
+ }
+
+ return(FALSE);
+ }
+
+ LocalFree(MediaTypes);
+
+ //
+ // Start the modal dialog that will display the progress indicator.
+ //
+
+ FloppyOp.MediaType = MediaType;
+ FloppyOp.DriveLetter = (WCHAR)DriveLetter;
+ FloppyOp.Operation = FloppyOpFormat;
+ FloppyOp.CaptionResId = IDS_FORMATTINGDISK;
+ FloppyOp.GeneralFailureResId = IDS_FORMATGENERALFAILURE;
+
+ Flag = DialogBoxParam( GetModuleHandle(NULL),
+ MAKEINTRESOURCE( IDD_PROGRESS2 ), // TEXT("Progress2"),
+ hwndOwner,
+ ProgressDlgProc,
+ (LONG)&FloppyOp
+ );
+
+ *Fatal = FALSE;
+
+ return(Flag);
+}
+
+#ifdef FLOPPY_COPY
+BOOL
+CopyFloppyDisk(
+ IN CHAR DriveLetter,
+ IN HWND hwndOwner,
+ IN DWORD SourceDiskPromptId,
+ IN DWORD TargetDiskPromptId
+ )
+
+/*++
+
+Routine Description:
+
+ Top-level routine to copy a floppy in the given drive (src and dst
+ both in this drive). A floppy disk must already be in the drive or
+ this routine will fail.
+
+Arguments:
+
+ DriveLetter - supplies drive letter of drive to copy (A-Z or a-z)
+
+ hwndOwner - supplies handle of window that is to own the progress dlg.
+
+ SourceDiskPromptId - supplies the resource id of the prompt to display
+ when prompting for the source diskette
+
+ TargetDiskPromptId - supplies the resource id of the prompt to display
+ when prompting for the target diskette
+
+Return Value:
+
+ TRUE if the operation succeeded, FALSE if not.
+
+--*/
+
+{
+ BOOL Flag;
+ FLOPPY_OPERATION_PARAMS FloppyOp;
+
+ FloppyOp.DriveLetter = (WCHAR)DriveLetter;
+ FloppyOp.Operation = FloppyOpDiskcopy;
+ FloppyOp.CaptionResId = IDS_COPYINGDISK;
+ FloppyOp.GeneralFailureResId = IDS_COPYGENERALFAILURE;
+ FloppyOp.SrcDiskPromptResId = SourceDiskPromptId;
+ FloppyOp.DstDiskPromptResId = TargetDiskPromptId;
+
+ Flag = DialogBoxParam( GetModuleHandle(NULL),
+ TEXT("Progress2"),
+ hwndOwner,
+ ProgressDlgProc,
+ (LONG)&FloppyOp
+ );
+
+ return(Flag);
+}
+#endif
+
+BOOL
+ProgressDlgProc(
+ IN HWND hdlg,
+ IN UINT Msg,
+ IN WPARAM wParam,
+ IN LONG lParam
+ )
+{
+ static PFLOPPY_OPERATION_PARAMS FloppyOp;
+ static WCHAR WideDriveName[3];
+ static BOOL OpSucceeded;
+ PVOID PacketAddress;
+ FMIFS_PACKET_TYPE PacketType;
+ WCHAR Buffer[256];
+ DWORD ThreadId;
+
+ switch(Msg) {
+
+ case WM_INITDIALOG:
+
+ FloppyOp = (PFLOPPY_OPERATION_PARAMS)lParam;
+ WideDriveName[0] = FloppyOp->DriveLetter;
+ WideDriveName[1] = L':';
+ WideDriveName[2] = 0;
+
+ ProgressDialog = hdlg;
+
+ //
+ // set up range for percentage (0-100) display
+ //
+ SendDlgItemMessage(hdlg,ID_BAR,PBM_SETRANGE,0,MAKELPARAM(0,GAUGE_BAR_RANGE));
+
+ //
+ // Set the caption
+ //
+
+ LoadString(_hModule,FloppyOp->CaptionResId,Buffer,sizeof(Buffer)/sizeof(WCHAR));
+ SetWindowText(hdlg,Buffer);
+
+ OpSucceeded = TRUE;
+
+ // center the dialog relative to the parent window
+ //
+ // BUGBUG - commented out
+ //
+ FCenterDialogOnDesktop(hdlg);
+
+ CreateThread( NULL,
+ 1024,
+ ( LPTHREAD_START_ROUTINE )FmifsThread,
+ FloppyOp,
+ 0,
+ &ThreadId );
+
+
+
+ break;
+
+ case AP_TASK_COMPLETED:
+
+ SendDlgItemMessage( hdlg,
+ ID_BAR,
+ PBM_SETPOS,
+ GAUGE_BAR_RANGE,
+ 0L
+ );
+ PostMessage( hdlg,
+ AP_TERMINATE_DIALOG,
+ 0,
+ 0 );
+ break;
+
+ case AP_TERMINATE_DIALOG:
+
+ EndDialog(hdlg, OpSucceeded);
+ break;
+
+
+ case WM_FMIFS_CALLBACK:
+
+ //
+ // The callback routine is telling us something.
+ // wParam = packet type
+ // lParam = packet address
+ //
+
+ PacketType = wParam;
+ PacketAddress = (PVOID)lParam;
+
+ switch(PacketType) {
+
+ case FmIfsPercentCompleted:
+
+ //
+ // update gas gauge
+ //
+
+ SendDlgItemMessage( hdlg,
+ ID_BAR,
+ PBM_SETPOS,
+ (GAUGE_BAR_RANGE * ((PFMIFS_PERCENT_COMPLETE_INFORMATION)PacketAddress)->PercentCompleted) / 100,
+ 0L
+ );
+ break;
+
+ case FmIfsFinished:
+
+ {
+ BOOLEAN b;
+
+ //
+ // update gas gauge (100% complete)
+ //
+
+ SendDlgItemMessage( hdlg,
+ ID_BAR,
+ PBM_SETPOS,
+ GAUGE_BAR_RANGE,
+ 0L
+ );
+
+ b = ((PFMIFS_FINISHED_INFORMATION)PacketAddress)->Success;
+
+ //
+ // If the operation failed but the user hasn't already been
+ // informed, inform him.
+ //
+
+ if(OpSucceeded && !b) {
+ OpSucceeded = FALSE;
+ DisplayMsgBox( hdlg,
+ FloppyOp->GeneralFailureResId,
+ MB_OK | MB_ICONEXCLAMATION,
+ _szApplicationName
+ );
+
+ }
+ }
+ break;
+
+ case FmIfsFormatReport: // ignore
+
+ break;
+
+#ifdef FLOPPY_COPY
+ case FmIfsInsertDisk:
+
+ if(FloppyOp->Operation == FloppyOpDiskcopy) {
+ switch(((PFMIFS_INSERT_DISK_INFORMATION)PacketAddress)->DiskType) {
+ case DISK_TYPE_SOURCE:
+ ResId = FloppyOp->SrcDiskPromptResId;
+ break;
+ case DISK_TYPE_TARGET:
+ ResId = FloppyOp->DstDiskPromptResId;
+ break;
+ default:
+ return(TRUE);
+ }
+ xMsgBox(hdlg,IDS_INSERTDISKETTE,ResId,MB_OK,FloppyOp->DriveLetter);
+ }
+ break;
+
+ case FmIfsFormattingDestination:
+
+ // BUGBUG do something
+ break;
+#endif
+
+ case FmIfsMediaWriteProtected:
+
+ DisplayMsgBox(hdlg,IDS_FLOPPYWRITEPROT,MB_OK | MB_ICONEXCLAMATION);
+ OpSucceeded = FALSE;
+ break;
+
+ case FmIfsIoError:
+
+ DisplayMsgBox(hdlg,IDS_FLOPPYIOERR,MB_OK | MB_ICONEXCLAMATION);
+ OpSucceeded = FALSE;
+ break;
+
+ case FmIfsHiddenStatus: // ignore
+
+ break;
+
+ default:
+
+ DisplayMsgBox(hdlg,IDS_FLOPPYUNKERR,MB_OK | MB_ICONEXCLAMATION);
+ OpSucceeded = FALSE;
+ break;
+ }
+ break;
+
+ default:
+
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+
+BOOLEAN
+FmifsCallbackRoutine(
+ IN FMIFS_PACKET_TYPE PacketType,
+ IN DWORD PacketLength,
+ IN PVOID PacketAddress
+ )
+{
+ UNREFERENCED_PARAMETER(PacketLength);
+ //
+ // Package up the callback and send it on to the progress dialog.
+ // wParam = packet type
+ // lParam = packet address
+ //
+
+ SendMessage( ProgressDialog,
+ WM_FMIFS_CALLBACK,
+ PacketType,
+ (LONG)PacketAddress
+ );
+
+ return(TRUE); // keep going
+}
+
+VOID
+FmifsThread(
+ IN PVOID Arguments
+ )
+
+{
+ PFLOPPY_OPERATION_PARAMS FloppyOp;
+ WCHAR WideDriveName[3];
+
+
+ FloppyOp = ( PFLOPPY_OPERATION_PARAMS )Arguments;
+ WideDriveName[0] = FloppyOp->DriveLetter;
+ WideDriveName[1] = L':';
+ WideDriveName[2] = 0;
+
+ FmifsFormat( WideDriveName,
+ FloppyOp->MediaType,
+ L"fat",
+ L"",
+ FALSE, // not quick format
+ FmifsCallbackRoutine
+ );
+
+ SendMessage( ProgressDialog,
+ AP_TASK_COMPLETED,
+ 0,
+ 0L
+ );
+
+ ExitThread(0);
+}
diff --git a/private/utils/rdisk/format.c b/private/utils/rdisk/format.c
new file mode 100644
index 000000000..8530f2f26
--- /dev/null
+++ b/private/utils/rdisk/format.c
@@ -0,0 +1,347 @@
+#include "precomp.h"
+#pragma hdrstop
+
+BOOL
+InitializeFloppySup(
+ VOID
+ );
+
+BOOL
+FormatFloppyDisk(
+ IN WCHAR DriveLetter,
+ IN HWND hwndOwner,
+ OUT PBOOL Fatal
+ );
+
+BOOL
+InsertSpecialBootCode(
+ IN WCHAR Drive
+ );
+
+
+BOOLEAN
+FormatRepairDisk(
+ IN PWCHAR Drive
+ )
+
+/*++
+
+Routine Description:
+
+ Generate the repair diskette on a given drive.
+
+ The set of events that occurs is as follows:
+
+ - Log the registry files (place the hive files in the restore disk inf
+ file's list of files to check)
+
+ - prompt for and format the floppy disk supplied by the user
+
+ - Copy the setup log file to the floppy supplied by the user
+ The rerair inf file will be called restore.inf.
+
+ This operation also closes the log file and ends logging.
+
+Arguments:
+
+ Drive - the first character is the drive letter of the drive containing
+ the restore diskette.
+
+Return Value:
+
+ TRUE if success, FALSE otherwise.
+
+--*/
+
+{
+ HANDLE Handle;
+ WIN32_FIND_DATA FindData;
+
+ BOOL Fatal;
+ BOOL res;
+ WCHAR Warning[256];
+ UINT OldErrorMode;
+ HCURSOR Cursor;
+ WCHAR DriveLetter[3];
+
+ PWSTR SetupFloppyTags[4] = { L"?:\\DISK10?",
+ L"?:\\DISK*.S",
+ L"?:\\DISK*.W",
+ NULL
+ };
+ WCHAR FloppyTag[128];
+
+ unsigned i;
+
+
+ DriveLetter[0] = *Drive;
+ DriveLetter[1] = (WCHAR)':';
+ DriveLetter[2] = (WCHAR)'\0';
+
+ Cursor = DisplayHourGlass();
+
+ if(!InitializeFloppySup()) {
+ DisplayMsgBox(_hWndMain,
+ IDS_CANTINITFLOPPYSUP,
+ MB_OK | MB_ICONEXCLAMATION,
+ _szApplicationName);
+ RestoreCursor( Cursor );
+ return(FALSE);
+ }
+
+ RestoreCursor( Cursor );
+
+ OldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+
+ //
+ // Prompt the user to get a new disk into the drive
+ //
+ LoadString(GetModuleHandle(NULL),IDS_ALLDATAWILLBELOST,Warning,sizeof(Warning)/sizeof(WCHAR));
+ if( DisplayMsgBox( _hWndMain,
+ IDS_FIRSTREPAIRDISKPROMPT,
+ MB_OKCANCEL | MB_DEFBUTTON1 | MB_ICONEXCLAMATION,
+ DriveLetter,
+ Warning) != IDOK ) {
+ return( FALSE );
+ }
+
+ //
+ // Attempt to prevent the user from using a setup floppy
+ // as the repair disk by looking for known tag values on
+ // the floppy the user inserted.
+ //
+ do {
+
+ for(i=0; SetupFloppyTags[i]; i++) {
+ //
+ // Make writable copy of floppy tag before writing into it.
+ //
+ lstrcpy(FloppyTag,SetupFloppyTags[i]);
+ FloppyTag[0] = *Drive;
+
+ if((Handle = FindFirstFile(FloppyTag,&FindData)) != INVALID_HANDLE_VALUE) {
+
+ FindClose(Handle);
+
+ if( DisplayMsgBox( _hWndMain,
+ IDS_SECONDREPAIRDISKPROMPT,
+ MB_OKCANCEL | MB_DEFBUTTON1 | MB_ICONEXCLAMATION,
+ DriveLetter,
+ Warning) != IDOK ) {
+ return( FALSE );
+ }
+
+ break;
+ }
+ }
+
+ } while(Handle != INVALID_HANDLE_VALUE);
+
+ do {
+ if(!(res = FormatFloppyDisk(*Drive,_hWndMain,&Fatal))) {
+
+ if(Fatal) {
+ SetErrorMode(OldErrorMode);
+ return(FALSE);
+ }
+
+ //
+ // Get the user to retry.
+ //
+ if(DisplayMsgBox( _hWndMain,
+ IDS_RETRYFORMATREPAIRDISK,
+ MB_RETRYCANCEL | MB_ICONEXCLAMATION,
+ _szApplicationName,
+ DriveLetter) != IDRETRY) {
+ SetErrorMode(OldErrorMode);
+ return(FALSE);
+ }
+
+
+ }
+ } while(!res);
+
+ //
+ // Cause special boot code to be written to the disk, that makes it
+ // print a message when booted.
+ //
+ InsertSpecialBootCode(*Drive);
+
+ SetErrorMode(OldErrorMode);
+
+ return(TRUE);
+
+}
+
+//
+// Bootcode to be inserted, placed into a C array. See i386\readme.
+//
+#include "rdskboot.c"
+#define DRIVENAME_PREFIX L"\\\\.\\"
+
+BOOL
+InsertSpecialBootCode(
+ IN WCHAR Drive
+ )
+{
+ UCHAR UBuffer[1024];
+ PUCHAR Buffer = (PUCHAR)(((DWORD)UBuffer+512) & ~511);
+ HANDLE Handle;
+ WCHAR DriveName[(sizeof(DRIVENAME_PREFIX)/sizeof(WCHAR)) + 2 + 1];
+ BOOL b;
+ DWORD BytesXferred;
+ DWORD Offset;
+ PUCHAR MsgAddr;
+
+ wsprintf(DriveName,L"%ls%wc:",DRIVENAME_PREFIX,Drive);
+
+ //
+ // Open the drive DASD
+ //
+ Handle = CreateFile(
+ DriveName,
+ FILE_READ_DATA | FILE_WRITE_DATA,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL
+ );
+
+ if(Handle == INVALID_HANDLE_VALUE) {
+ return(FALSE);
+ }
+
+ //
+ // Read and validate the first 512 bytes from the drive.
+ //
+ b = ReadFile(Handle,Buffer,512,&BytesXferred,NULL);
+ if((b == FALSE)
+ || (BytesXferred != 512)
+ || (Buffer[0] != 0xeb)
+ || (Buffer[2] != 0x90)
+ || (Buffer[510] != 0x55)
+ || (Buffer[511] != 0xaa))
+ {
+ CloseHandle(Handle);
+ return(FALSE);
+ }
+
+ //
+ // Determine the offset of the bootcode.
+ //
+ Offset = Buffer[1] + 2;
+ if(Offset + REPAIR_DISK_BOOTSECTOR_SIZE > 510) {
+ CloseHandle(Handle);
+ return(FALSE);
+ }
+
+ //
+ // Wipe the boot code clean and reset the signature.
+ //
+ ZeroMemory(Buffer+Offset,510-Offset);
+
+ //
+ // Copy the new bootcode into the sector.
+ //
+ CopyMemory(
+ Buffer+Offset,
+ REPAIR_DISK_BOOTSECTOR,
+ REPAIR_DISK_BOOTSECTOR_SIZE
+ );
+
+ //
+ // Calculate the offset of the message within the boot sector.
+ //
+ MsgAddr = Buffer+Offset+REPAIR_DISK_BOOTSECTOR_SIZE;
+
+ //
+ // Fetch the boot sector's message from our resources and
+ // place it into the boot sector.
+ //
+ LoadStringA(
+ GetModuleHandle(NULL),
+ IDS_REPAIR_BOOTCODE_MSG,
+ MsgAddr,
+ 510-Offset-REPAIR_DISK_BOOTSECTOR_SIZE
+ );
+
+ Buffer[509] = 0; // just in case.
+
+ //
+ // The string in the resources will be ANSI text; we want OEM text
+ // in the boot sector on the floppy.
+ //
+ CharToOemA(MsgAddr,MsgAddr);
+
+ //
+ // Seek back to the beginning of the disk and
+ // write the bootsector back out to disk.
+ //
+ if(SetFilePointer(Handle,0,NULL,FILE_BEGIN)) {
+ CloseHandle(Handle);
+ return(FALSE);
+ }
+
+ b = WriteFile(Handle,Buffer,512,&BytesXferred,NULL);
+
+ CloseHandle(Handle);
+
+ return((b == TRUE) && (BytesXferred == 512));
+
+}
+
+
+
+BOOLEAN
+CreateRepairDisk(
+ IN BOOLEAN DisplayConfirmCreateDisk
+ )
+
+/*++
+
+Routine Description:
+
+ Create a repair disk on the 'A' drive, if the user wants to do so.
+
+Arguments:
+
+ DisplayConfirmCreateDisk - A flag that indicates whether or not rdisk
+ should ask the user to confirm the creation
+ of the repair disk. The dialog should not be
+ displayed if user selected 'Create Repair Disk'
+ button.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeded, or FALSE otherwise.
+
+--*/
+
+
+{
+ BOOLEAN Result;
+ WCHAR Drive;
+ PWSTR String;
+ WCHAR StringYou[64];
+
+ Result = FALSE;
+ if( !_SilentMode ) {
+ LoadString(_hModule,IDS_CONFIRM_CREATE_YOU,StringYou,sizeof(StringYou)/sizeof(WCHAR));
+ String = StringYou;
+ } else {
+ String = _szApplicationName;
+ }
+ if( !DisplayConfirmCreateDisk ||
+ DisplayMsgBox( _hWndMain,
+ IDS_CONFIRM_CREATE_DISK,
+ MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON1,
+ String
+ ) == IDYES ) {
+
+ Drive = ( WCHAR )'A';
+ Result = FormatRepairDisk( &Drive );
+ }
+
+ return( Result );
+}
diff --git a/private/utils/rdisk/help.c b/private/utils/rdisk/help.c
new file mode 100644
index 000000000..67ec72dd4
--- /dev/null
+++ b/private/utils/rdisk/help.c
@@ -0,0 +1,363 @@
+/*++
+
+Module Name:
+
+ help.c
+
+Abstract:
+
+
+Author:
+
+ Jaime Sasson - 10-Aug-1993
+
+Environment:
+
+ ULIB, Windows
+
+--*/
+
+#include "precomp.h"
+#pragma hdrstop
+
+
+//
+// Global variables used in the module
+//
+
+HHOOK _hHook;
+INT _HelpContext;
+WCHAR _HelpFile[ MAX_PATH + 1 ];
+
+
+
+LRESULT
+HelpHookProc(
+ IN INT nCode,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Hook proc to detect F1 key presses.
+
+Arguments:
+
+ Standard arguments of a hook procedure.
+
+Return Value:
+
+--*/
+
+{
+ PMSG pmsg = (PMSG)lParam;
+
+ if(nCode < 0) {
+ return( CallNextHookEx( _hHook, nCode, wParam, lParam ) );
+ }
+
+ if(((nCode == MSGF_DIALOGBOX) || (nCode == MSGF_MENU))
+ && (pmsg->message == WM_KEYDOWN)
+ && (LOWORD(pmsg->wParam) == VK_F1))
+ {
+ PostMessage( _hWndMain, AP_HELP_KEY, nCode, 0);
+ return(TRUE);
+ }
+ return(FALSE);
+}
+
+
+BOOLEAN
+InitializeHelp(
+ IN PCWSTR HelpFile
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the help module by initializing its global data.
+
+Arguments:
+
+ HelpFile - Name of the help file to be invoked.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the initialization succeeded.
+ returns FALSE otherwise.
+
+--*/
+
+{
+
+ wcscpy( _HelpFile, HelpFile );
+
+ _hHook = SetWindowsHookEx( WH_MSGFILTER,
+ HelpHookProc,
+ NULL,
+ GetCurrentThreadId() );
+
+ if( _hHook == NULL ) {
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+VOID
+CleanUpHelp(
+ )
+
+/*++
+
+Routine Description:
+
+ Clean up the HELP object, by unhooking HelpHookProc.
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UnhookWindowsHookEx( _hHook );
+}
+
+
+
+
+VOID
+DisplayHelp(
+ )
+
+/*++
+
+Routine Description:
+
+ Display context-sensitive help.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds. Otherwise, return FALSE.
+
+--*/
+
+{
+ if( _HelpContext != IDH_NONE ) {
+ WinHelp( _hWndMain,
+ _HelpFile,
+ (UINT)HELP_CONTEXT,
+ _HelpContext );
+ DrawMenuBar( _hWndMain );
+ }
+
+
+}
+
+
+
+VOID
+DisplayHelpIndex(
+ )
+
+/*++
+
+Routine Description:
+
+ Invoke winhelp to display the help file index.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ WinHelp( _hWndMain, _HelpFile, (UINT)HELP_INDEX, 0 );
+}
+
+
+VOID
+DisplayHelpOnHelp(
+ )
+
+/*++
+
+Routine Description:
+
+ Invoke winhelp to display help on help.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ WinHelp( _hWndMain, _HelpFile, (UINT)HELP_HELPONHELP, 0 );
+}
+
+
+
+VOID
+DisplayHelpSearch(
+ )
+
+/*++
+
+Routine Description:
+
+ Invoke winhelp so that it prompt the user to enter a key.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ WinHelp( _hWndMain, _HelpFile, (UINT)HELP_PARTIALKEY, (DWORD)"" );
+}
+
+
+VOID
+QuitHelp(
+ )
+
+/*++
+
+Routine Description:
+
+ Inform winhelp that help is no more needed.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ WinHelp( _hWndMain, _HelpFile, (UINT)HELP_QUIT, 0 );
+}
+
+
+INT
+GetHelpContext(
+ )
+
+/*++
+
+Routine Description:
+
+ Return the current help context.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ INT - Ireturns the current help id.
+
+--*/
+
+{
+ return( _HelpContext );
+}
+
+
+
+VOID
+SetHelpContext(
+ IN INT HelpId
+ )
+
+/*++
+
+Routine Description:
+
+ Set the current help context.
+
+Arguments:
+
+ HelpContext - Help context id.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _HelpContext = HelpId;
+}
+
+
+
+VOID
+SetMenuItemHelpContext(
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Routine to set help context based on which menu item is currently
+ selected.
+
+Arguments:
+
+ wParam,lParam - params to window proc in WM_MENUSELECT case
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if(HIWORD(lParam) == 0) { // menu closed
+ SetHelpContext( IDH_SAVE_REPAIR_INFO );
+
+ } else if (HIWORD(wParam) & MF_POPUP) { // popup selected
+ SetHelpContext( IDH_NONE );
+
+ } else if (HIWORD(wParam) & MF_SYSMENU) { // system menu
+ SetHelpContext( IDH_SYSTEM_MENU );
+
+ } else { // regular old menu item
+ SetHelpContext( IDH_NONE );
+
+ }
+}
diff --git a/private/utils/rdisk/help.h b/private/utils/rdisk/help.h
new file mode 100644
index 000000000..9fe1fb25d
--- /dev/null
+++ b/private/utils/rdisk/help.h
@@ -0,0 +1,78 @@
+/*++
+
+Module Name:
+
+ help.h
+
+Abstract:
+
+ This module contains the class declaration for the HELP class.
+
+Author:
+
+ Jaime Sasson - 16-Aug-1993
+
+Environment:
+
+ ULIB, Windows
+
+--*/
+
+
+#if ! defined( _HELP_ )
+
+#define _HELP_
+
+LRESULT
+HelpHookProc(
+ IN INT nCode,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+BOOLEAN
+InitializeHelp(
+ IN PCWSTR HelpFileName
+ );
+
+VOID
+CleanUpHelp(
+ );
+
+VOID
+DisplayHelp(
+ );
+
+VOID
+DisplayHelpIndex(
+ );
+
+VOID
+DisplayHelpOnHelp(
+ );
+
+VOID
+DisplayHelpSearch(
+ );
+
+VOID
+QuitHelp(
+ );
+
+INT
+GetHelpContext(
+ );
+
+VOID
+SetHelpContext(
+ IN INT HelpId
+ );
+
+VOID
+SetMenuItemHelpContext(
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+
+#endif // _HELP_
diff --git a/private/utils/rdisk/i386/rdskboot.asm b/private/utils/rdisk/i386/rdskboot.asm
new file mode 100644
index 000000000..aff397726
--- /dev/null
+++ b/private/utils/rdisk/i386/rdskboot.asm
@@ -0,0 +1,77 @@
+
+ ;
+ ; Program to be inserted on the boot sector of the emergency repair
+ ; disk. Prints out a message and hangs.
+ ;
+ ; The program is designed to be inserted around the existing BPB.
+ ; Whoever puts it in place should read the first three bytes of the
+ ; boot sector to determine the byte offset within the sector where the
+ ; program should be placed.
+ ;
+ ; See setup\src\restore.c.
+ ;
+
+TheSeg segment
+ assume cs:TheSeg,ds:nothing,es:nothing,ss:nothing
+
+ ;
+ ; Make link happy with /tiny by setting org to 100h.
+ ; The program itself is designed to run at 0:7c00h, so
+ ; the org is just a dummy.
+ ;
+ org 100h
+Start:
+
+ ;
+ ; Set up a stack and initialize necessary segment registers.
+ ;
+ xor bx,bx
+ mov ss,bx
+ mov ds,bx
+ mov sp,7c00h
+
+ ;
+ ; Set video mode -- 80x25 text.
+ ;
+ mov ax,3
+ int 10h
+
+ ;
+ ; Make ds:si point at the message to be displayed.
+ ;
+ call @f
+@@: pop si
+ add si,offset cs:msg - @b
+
+ ;
+ ; Print out the string via BIOS calls. Registers ds, si, and bx are
+ ; already set up.
+ ;
+ cld
+ mov ah,0eh
+@@: lodsb
+ or al,al
+ jz @f
+ int 10h
+ jmp @b
+
+ ;
+ ; Done. Hide the cursor and hang.
+ ; Register bh is already set up.
+ ;
+@@: mov ah,2
+ mov dl,bl
+ mov dh,19h
+ int 10h
+ sti
+@@: jmp @b
+
+ ;
+ ; The message to be printed. This will be inserted by setup from its
+ ; resources (IDS_REPAIR_BOOTCODE_MSG), and must be nul-terminated.
+ ;
+msg label byte
+
+TheSeg ends
+
+ end Start
diff --git a/private/utils/rdisk/i386/readme b/private/utils/rdisk/i386/readme
new file mode 100644
index 000000000..3cd7df911
--- /dev/null
+++ b/private/utils/rdisk/i386/readme
@@ -0,0 +1,17 @@
+The file rdskboot.asm contains the program to be inserted into the
+boot sector of the emergency repair disk. There is also a message that needs
+to go in that sector -- the message is contained in setup.exe's resources,
+with resource id IDS_REPAIR_BOOTCODE_MSG.
+
+I build rdskboot.com by using the following commands:
+
+ masm386 rdskboot,,nul,nul,,
+ link_60 /tiny rdskboot,,nul,,,
+
+
+I then ran bin2c.exe (in sdktools, part of standard idw) over rdskboot.com
+using the following command:
+
+ bin2c rdskboot.com 45 0 45 ..\rdskboot.c REPAIR_DISK_BOOTSECTOR
+
+This generated rdskboot.c in setup\src, which I checked in.
diff --git a/private/utils/rdisk/i386/x.bat b/private/utils/rdisk/i386/x.bat
new file mode 100644
index 000000000..b2a801e37
--- /dev/null
+++ b/private/utils/rdisk/i386/x.bat
@@ -0,0 +1,2 @@
+masm386 rdskboot,,nul,nul,,
+link_60 /tiny rdskboot,,nul,,,
diff --git a/private/utils/rdisk/makefile b/private/utils/rdisk/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/rdisk/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/rdisk/precomp.h b/private/utils/rdisk/precomp.h
new file mode 100644
index 000000000..3e5ecee72
--- /dev/null
+++ b/private/utils/rdisk/precomp.h
@@ -0,0 +1,14 @@
+#include <windows.h>
+#include <commctrl.h>
+#include <diamondc.h>
+#include <winioctl.h>
+#include <fcntl.h>
+#include <sys\types.h>
+#include <sys\stat.h>
+#include <io.h>
+
+#include "rdisk.h"
+#include "resource.h"
+#include "dialogs.h"
+#include "help.h"
+#include "..\fmifs\inc\fmifs.h"
diff --git a/private/utils/rdisk/rdisk.c b/private/utils/rdisk/rdisk.c
new file mode 100644
index 000000000..bfb3a3ecd
--- /dev/null
+++ b/private/utils/rdisk/rdisk.c
@@ -0,0 +1,619 @@
+/*++
+
+Module Name:
+
+ repair.c
+
+Abstract:
+
+ This module contains the functions that create the main window
+ of the Repair Utility.
+
+ The syntax of this utility is:
+
+ repair [-s]
+
+ -s: Operate in the silent mode. The apllication will not have a client
+ area, and some dialogs that allow the user to confirm some
+ operations are not displayed.
+ When the utility is operating in the silent mode, it will display
+ the name of Setup program in the title bar of all error and
+ warning dialogs displayed. This name to be displayed in the
+ title bar is defined on resource.rc under IDS_SETUP.
+
+ If this switch is not specified this utility will be run on
+ its normal mode, and it will wait for the user to start
+ the process of saving repair information.
+
+Author:
+
+ Jaime Sasson - 24-Jan-1994
+
+Environment:
+
+ ULIB, Windows
+
+--*/
+
+
+#include "precomp.h"
+#pragma hdrstop
+
+//
+// Global Variables
+//
+
+HWND _hWndMain = NULL;
+HANDLE _hModule = NULL;
+PWSTR _pszApplicationClass = (PWSTR)( L"Repair" );
+BOOLEAN _SilentMode = FALSE;
+WCHAR _szApplicationName[128];
+INT _ReturnCode;
+BOOLEAN _AutoSkipRepairDisk = FALSE;
+BOOLEAN _AutoDoRepairDisk = FALSE;
+
+
+BOOLEAN
+SaveCurrentConfiguration(
+ );
+
+BOOLEAN
+CopyFilesToRepairDisk(
+ IN WCHAR Drive
+ );
+
+
+BOOLEAN
+FormatRepairDisk(
+ IN PWCHAR Drive
+ );
+
+BOOLEAN
+CreateRepairDisk(
+ IN BOOLEAN DisplayConfirmCreateDisk
+ );
+
+
+HCURSOR
+DisplayHourGlass(
+ )
+
+/*++
+
+Routine Description:
+
+ Changes the cursor currently displayed to the hour glass.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ HCURSOR - Handle to the cursor currently displayed.
+
+--*/
+
+{
+ HCURSOR hCursor;
+
+ hCursor = SetCursor( LoadCursor( NULL, IDC_WAIT ) );
+ ShowCursor( TRUE );
+ return( hCursor );
+
+}
+
+
+
+VOID
+RestoreCursor(
+ IN HCURSOR Cursor
+ )
+
+/*++
+
+Routine Description:
+
+ Replace the currently selected cursor with the one whose handle was
+ received as parameter.
+
+Arguments:
+
+ Cursor - Handle to the new cursor to be displayed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ SetCursor( Cursor );
+ ShowCursor( FALSE );
+}
+
+
+PWSTR
+QueryFormattedString(
+ UINT MessageResId,
+ ...
+ )
+/*++
+
+Routine Description:
+
+ Retrieve, format a string.
+
+
+Arguments:
+
+ MessageResId - Id of the message to be displayed in the message box.
+
+ Optional list of strings to be inserted in the string to be retrieved.
+
+Return Value:
+
+ PWSTR - Retrurns a formatted string. The caller of this function must
+ free the buffer returned, using LocalFree().
+
+--*/
+
+
+{
+ WCHAR message[1024];
+ PWSTR FormattedString;
+ va_list arglist;
+
+
+ va_start(arglist, MessageResId);
+
+ LoadString(_hModule,MessageResId,message,sizeof(message)/sizeof(WCHAR));
+ FormatMessage( FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ message,
+ 0,
+ 0,
+ (PVOID)&FormattedString,
+ 1024,
+ &arglist );
+
+
+ va_end(arglist);
+
+ return(FormattedString);
+}
+
+
+
+UINT
+DisplayMsgBox(
+ HWND hwnd,
+ UINT MessageResId,
+ UINT MsgBoxFlags,
+ ...
+ )
+/*++
+
+Routine Description:
+
+ Retrieve, format and display a message in a message box.
+
+
+Arguments:
+
+ hWnd - Handle of the windows that is displaying the message box.
+
+ MessageResId - Id of the message to be displayed in the message box.
+
+ MsgBoxFlags - Flags that define the style of the message box.
+
+ Optional list of strings to be inserted in the text to be displayed in
+ the message box.
+
+Return Value:
+
+ UINT - Returns one of the following, depending on what the user chose:
+
+ IDABORT, IDCANCEL, IDIGNORE, IDNO, IDOK, IDRETRY, IDYES
+
+--*/
+
+
+{
+ WCHAR message[1024];
+ WCHAR msgbody[1024];
+ va_list arglist;
+
+ va_start(arglist, MsgBoxFlags);
+
+ LoadString(_hModule,MessageResId,message,sizeof(message)/sizeof(WCHAR));
+
+ FormatMessage( FORMAT_MESSAGE_FROM_STRING,
+ message,
+ 0,
+ 0,
+ msgbody,
+ sizeof( msgbody ) / sizeof( WCHAR ),
+ &arglist );
+
+
+ va_end(arglist);
+
+ return(MessageBox(hwnd,msgbody,_szApplicationName,MsgBoxFlags));
+}
+
+
+
+long
+MainWndProc(
+ IN HWND hWnd,
+ IN UINT message,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+
+/*++
+
+Routine Description:
+
+ MainWndProc is the WndProc for application's main window. It is primarily
+ responsible for creating the MDICLIENT window and servicing menu
+ commands.
+
+Arguments:
+
+ Standard Windows' Proc parameters.
+
+Return Value:
+
+ long - Returns 0 if the message was handled.
+
+--*/
+
+{
+
+ static HWND LastFocus = NULL;
+
+ switch( message ) {
+
+ case WM_CREATE:
+ {
+ int ScreenHeight;
+ int ScreenWidth;
+
+ //
+ // Display the main window in the center of the screen.
+ //
+
+ ScreenWidth = GetSystemMetrics( SM_CXSCREEN );
+ ScreenHeight = GetSystemMetrics( SM_CYSCREEN );
+
+ SetWindowPos( hWnd,
+ NULL,
+ ( ScreenWidth - (( LPCREATESTRUCT ) lParam )->cx ) / 2,
+ ( ScreenHeight - (( LPCREATESTRUCT ) lParam )->cy ) / 2,
+ 0,
+ 0,
+ SWP_NOSIZE | SWP_NOREDRAW | SWP_NOZORDER
+ );
+ return 0;
+ }
+
+ case WM_INITDIALOG:
+ {
+ if( !_SilentMode ) {
+
+ LastFocus = GetDlgItem( hWnd, IDB_SAVE_CURRENT_INFO );
+ SetFocus( LastFocus );
+ SetHelpContext( IDH_SAVE_REPAIR_INFO );
+
+ }
+ return 0;
+ }
+
+ case WM_KILLFOCUS:
+
+ LastFocus = GetFocus();
+ break;
+
+ case WM_SETFOCUS:
+
+ SetFocus( LastFocus );
+ break;
+
+ case WM_CLOSE:
+ //
+ // Save application settings
+ //
+#if 0
+ if( !_SilentMode && _SaveSettingsOnExit ) {
+ SaveApplicationSettings();
+ }
+#endif
+ return DefWindowProc( hWnd, message, wParam, lParam );
+
+ case WM_DESTROY:
+
+ if( !_SilentMode ) {
+ QuitHelp();
+ }
+ PostQuitMessage( 0 );
+ break;
+
+ case WM_INITMENUPOPUP:
+
+// InitializeMenuPopup( wParam, lParam );
+ break;
+
+ case WM_MENUSELECT:
+
+ if( !_SilentMode ) {
+ SetMenuItemHelpContext( wParam, lParam );
+ }
+ break;
+
+ case WM_COMMAND:
+
+ switch( LOWORD( wParam )) {
+
+ case IDB_SAVE_CURRENT_INFO:
+ {
+ HCURSOR Cursor;
+ WCHAR Drive;
+ INT SaveHelpContext;
+
+ SaveHelpContext = GetHelpContext();
+ SetHelpContext( IDH_REPLACE_PREVIOUS );
+
+ Drive = ( WCHAR )'A';
+ Cursor = DisplayHourGlass();
+ if( SaveCurrentConfiguration() ) {
+
+ SetHelpContext( IDH_CREATE_REPAIR );
+ if( CreateRepairDisk( TRUE ) ) {
+ CopyFilesToRepairDisk(Drive);
+ }
+ }
+ SetHelpContext( SaveHelpContext );
+ SetFocus( GetDlgItem( hWnd, IDB_SAVE_CURRENT_INFO ) );
+ RestoreCursor( Cursor );
+ break;
+ }
+
+ case IDB_CREATE_DISK:
+ {
+ HCURSOR Cursor;
+ WCHAR Drive;
+ INT SaveHelpContext;
+
+ SaveHelpContext = GetHelpContext();
+ SetHelpContext( IDH_CREATE_REPAIR );
+
+ Drive = ( WCHAR )'A';
+ Cursor = DisplayHourGlass();
+
+ if( CreateRepairDisk( FALSE ) ) {
+ CopyFilesToRepairDisk(Drive);
+ }
+ SetHelpContext( SaveHelpContext );
+ SetFocus( GetDlgItem( hWnd, IDB_CREATE_DISK ) );
+ RestoreCursor( Cursor );
+ break;
+ }
+
+ case IDB_EXIT:
+ {
+ if( !_SilentMode ) {
+ SendMessage( hWnd, WM_CLOSE, 0, 0 );
+ }
+ break;
+ }
+
+ case IDB_HELP:
+ {
+ if( !_SilentMode ) {
+ DisplayHelpIndex();
+ SetFocus( GetDlgItem( hWnd, IDB_HELP ) );
+ }
+ break;
+ }
+
+ default:
+
+ return DefWindowProc( hWnd, message, wParam, lParam );
+ }
+ break;
+
+ case AP_AUTOMATIC_MODE:
+ {
+ WCHAR Drive;
+ HCURSOR Cursor;
+ Drive = ( WCHAR )'A';
+ Cursor = DisplayHourGlass();
+
+ if(SaveCurrentConfiguration()
+ && ( _AutoSkipRepairDisk
+ || (CreateRepairDisk((BOOLEAN)(!_AutoDoRepairDisk)) && CopyFilesToRepairDisk(Drive))))
+ {
+ _ReturnCode = 1;
+ } else {
+ _ReturnCode = 0;
+ }
+ RestoreCursor( Cursor );
+ PostMessage( hWnd, WM_CLOSE, 0, 0L );
+ break;
+ }
+ case AP_HELP_KEY:
+
+ if( !_SilentMode ) {
+ DisplayHelp();
+ }
+ break;
+
+ default:
+
+ return DefWindowProc( hWnd, message, wParam, lParam );
+ }
+
+ return 0L;
+}
+
+BOOLEAN
+InitializeApp(
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the application by registering the main window class, the child
+ window class, and by creating the application's main window.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+
+ BOOLEAN - Returns TRUE if the application was successfully initialized.
+ Returns FALSE otherwise.
+
+--*/
+
+{
+ WNDCLASS wc;
+ ULONG StringId;
+
+ //
+ // Register application's main window class.
+ //
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.lpfnWndProc = ( WNDPROC )MainWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = DLGWINDOWEXTRA;
+ wc.hInstance = ( HINSTANCE )_hModule;
+ wc.hIcon = LoadIcon( ( HINSTANCE )_hModule, MAKEINTRESOURCE( IDI_REPAIR_UTILITY ));
+ wc.hCursor = LoadCursor( NULL, IDC_ARROW );
+ wc.hbrBackground = ( HBRUSH )( COLOR_BTNFACE + 1 );
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = _pszApplicationClass;
+
+ if( ! RegisterClass( &wc )) {
+ return FALSE;
+ }
+
+ InitCommonControls();
+
+ //
+ // Get the application name
+ //
+
+ StringId = ( _SilentMode )? IDS_SETUP : IDS_APPLICATION_NAME;
+ LoadString( _hModule,
+ StringId,
+ _szApplicationName,
+ sizeof(_szApplicationName)/sizeof(WCHAR));
+
+ //
+ // Create the main window.
+ //
+
+ _hWndMain = CreateDialog( _hModule,
+ MAKEINTRESOURCE( IDD_REPAIR ),
+ NULL,
+ MainWndProc );
+
+ if( _hWndMain == NULL ) {
+ GetLastError();
+ return FALSE;
+ }
+
+ UpdateWindow( _hWndMain );
+ if( !_SilentMode ) {
+ ShowWindow( _hWndMain, SW_SHOWNORMAL );
+ } else {
+ ShowWindow( _hWndMain, SW_HIDE );
+ PostMessage( _hWndMain, AP_AUTOMATIC_MODE, 0, 0 );
+ }
+ return TRUE;
+}
+
+
+INT _CRTAPI1
+main(
+ IN INT argc,
+ IN PCHAR argv[ ]
+ )
+
+/*++
+
+Routine Description:
+
+ Entry point to the application.
+
+Arguments:
+
+ Standard C program arguments.
+
+Return Value:
+
+
+--*/
+
+{
+ MSG msg;
+ HANDLE hAccel;
+
+ UNREFERENCED_PARAMETER( argc );
+ UNREFERENCED_PARAMETER( argv );
+
+ _SilentMode = FALSE;
+
+ if( argc > 1 ) {
+ PSTR p;
+
+ p = argv[ 1 ];
+
+ if( ( _strnicmp( p, ( LPSTR )"-s", 2 ) == 0 ) ||
+ ( _strnicmp( p, ( LPSTR )"/s", 2 ) == 0 ) ) {
+
+ _SilentMode = TRUE;
+
+ if( p[2] == '-' ) {
+ _AutoSkipRepairDisk = TRUE;
+ } else {
+ if( p[2] == '+' ) {
+ _AutoDoRepairDisk = TRUE;
+ }
+ }
+ }
+ }
+
+ _hModule = GetModuleHandle( NULL );
+
+ //
+ // Register window classes and create the main window
+ //
+ if( ! InitializeApp( )) {
+ return 0;
+ }
+
+ hAccel = LoadAccelerators( ( HINSTANCE )_hModule, MAKEINTRESOURCE( IDA_REPAIR_UTILITY ));
+ if( !_SilentMode ) {
+ InitializeHelp( (LPWSTR)L"rdisk.hlp" );
+ }
+
+ while( GetMessage( &msg, NULL, 0, 0 )) {
+
+ if( ! TranslateAccelerator( _hWndMain, ( HACCEL )hAccel, &msg ) &&
+ ! IsDialogMessage( _hWndMain, &msg )) {
+
+ TranslateMessage( &msg );
+ DispatchMessage( &msg );
+ }
+ }
+ if( !_SilentMode ) {
+ CleanUpHelp();
+ }
+ return _ReturnCode;
+}
diff --git a/private/utils/rdisk/rdisk.h b/private/utils/rdisk/rdisk.h
new file mode 100644
index 000000000..8b4295365
--- /dev/null
+++ b/private/utils/rdisk/rdisk.h
@@ -0,0 +1,65 @@
+/*++
+
+Module Name:
+
+ rdisk.h
+
+Abstract:
+
+ This module contains the declaration of the public functions, and
+ public variables defined on repair.c
+
+Author:
+
+ Jaime Sasson - 24-Jan-1994
+
+Environment:
+
+ ULIB, Windows
+
+--*/
+
+#if !defined( _REPAIR_DISK_ )
+#define _REPAIR_DISK_
+
+#include "windows.h"
+
+extern HWND _hWndMain;
+extern HANDLE _hModule;
+extern BOOLEAN _SilentMode;
+extern WCHAR _szApplicationName[];
+
+//
+// Range we will use for the gas gauge display.
+// This large range provides plenty of granularity.
+//
+#define GAUGE_BAR_RANGE 10000
+
+HCURSOR
+DisplayHourGlass(
+ );
+
+VOID
+RestoreCursor(
+ IN HCURSOR Cursor
+ );
+
+UINT
+DisplayMsgBox(
+ HWND hwnd,
+ UINT MessageResId,
+ UINT MsgBoxFlags,
+ ...
+ );
+
+DWORD
+DiamondCompressFile(
+ IN PSTR SourceFile,
+ IN PSTR TargetFile,
+ IN DWORD GaugeBasePosition,
+ IN DWORD GaugeRangeForThisFile,
+ IN HWND GaugeNotifyWindow
+ );
+
+#endif // _REPAIR_DISK_
+
diff --git a/private/utils/rdisk/rdisk.ico b/private/utils/rdisk/rdisk.ico
new file mode 100644
index 000000000..b447b8007
--- /dev/null
+++ b/private/utils/rdisk/rdisk.ico
Binary files differ
diff --git a/private/utils/rdisk/rdskboot.c b/private/utils/rdisk/rdskboot.c
new file mode 100644
index 000000000..74e72d58f
--- /dev/null
+++ b/private/utils/rdisk/rdskboot.c
@@ -0,0 +1,8 @@
+#define REPAIR_DISK_BOOTSECTOR_SIZE 45
+
+
+unsigned char REPAIR_DISK_BOOTSECTOR[] = {
+51,219,142,211,142,219,188,0,124,184,3,0,205,16,232,0,
+0,94,129,198,28,0,252,180,14,172,10,192,116,4,205,16,
+235,247,180,2,138,211,182,25,205,16,251,235,254
+};
diff --git a/private/utils/rdisk/resource.h b/private/utils/rdisk/resource.h
new file mode 100644
index 000000000..2bcb9e781
--- /dev/null
+++ b/private/utils/rdisk/resource.h
@@ -0,0 +1,70 @@
+//
+// Resource IDs.
+//
+
+#define IDA_REPAIR_UTILITY 110 // Accelerators
+#define IDM_REPAIR_UTILITY 100 // Menu
+#define IDI_REPAIR_UTILITY 200 // Icon
+
+
+
+#define IDM_ABOUT 403
+
+//
+// Help IDs
+//
+
+#define IDH_SYSTEM_MENU 8000
+#define IDH_SAVE_REPAIR_INFO 8001
+#define IDH_REPLACE_PREVIOUS 8002
+#define IDH_CREATE_REPAIR 8003
+#define IDH_NONE 8004
+
+
+//
+// String IDs (strings used on message boxes)
+//
+
+
+#define IDS_APPLICATION_NAME 7000 // Application Name
+#define IDS_SETUP 7001 // Name of setup.exe
+#define IDS_REPAIR_BOOTCODE_MSG 7002
+
+#define IDS_INSERTDISKETTE 7010
+#define IDS_FIRSTREPAIRDISKPROMPT 7011
+#define IDS_SECONDREPAIRDISKPROMPT 7012
+#define IDS_FORMATTINGDISK 7013
+#define IDS_FORMATGENERALFAILURE 7014
+#define IDS_CANTDETERMINEFLOPTYPE 7015
+#define IDS_BADFLOPPYTYPE 7016
+#define IDS_FLOPPYWRITEPROT 7017
+#define IDS_FLOPPYIOERR 7018
+#define IDS_FLOPPYUNKERR 7019
+#define IDS_RETRYFORMATREPAIRDISK 7020
+#define IDS_ALLDATAWILLBELOST 7021
+#define IDS_CANTINITFLOPPYSUP 7022
+#define IDS_HUGEFLOPPYNOTSUPPORTED 7023
+
+#define IDS_COPYING_FILES 7030
+#define IDS_SAVING_CONFIGURATION 7031
+#define IDS_UNABLE_TO_COPY_ALL_FILES 7032
+#define IDS_FILE_NOT_FOUND 7033
+#define IDS_DISK_FULL 7044
+#define IDS_CANT_SAVE_CONFIGURATION 7045
+#define IDS_CONFIRM_SAVE_CONFIGURATION 7046
+#define IDS_CONFIRM_CREATE_DISK 7047
+#define IDS_CONFIRM_CREATE_DISK_TEST 7048
+
+#define IDS_CONFIRM_CREATE_YOU 7049
+
+
+//
+// Application defined messages
+//
+
+#define AP_SAVE_SETTINGS WM_USER
+#define AP_HELP_KEY WM_USER + 1
+#define AP_AUTOMATIC_MODE WM_USER + 20
+#define AP_UPDATE_GAUGE WM_USER + 30
+#define AP_TASK_COMPLETED WM_USER + 40
+#define AP_TERMINATE_DIALOG WM_USER + 50
diff --git a/private/utils/rdisk/resource.rc b/private/utils/rdisk/resource.rc
new file mode 100644
index 000000000..d57af5114
--- /dev/null
+++ b/private/utils/rdisk/resource.rc
@@ -0,0 +1,74 @@
+#include <windows.h>
+#include "resource.h"
+
+//
+// Icon Definition
+//
+
+IDI_REPAIR_UTILITY ICON rdisk.ico
+
+//
+// Accelerator Definition
+//
+
+IDA_REPAIR_DISK ACCELERATORS
+BEGIN
+ VK_F1, IDM_ABOUT, VIRTKEY, CONTROL
+END
+
+//
+// String Table Definition
+//
+
+STRINGTABLE LOADONCALL MOVEABLE DISCARDABLE
+ {
+ IDS_SETUP, "Setup"
+ IDS_APPLICATION_NAME, "Repair Disk Utility"
+ IDS_CANTINITFLOPPYSUP, "%1 was unable to load required floppy disk operation support."
+ IDS_INSERTDISKETTE "Insert Disk"
+ IDS_FIRSTREPAIRDISKPROMPT, "Label a floppy disk 'Emergency Repair Disk' and insert it into drive %1. Select OK when the disk is in the drive.\n\n%2"
+ IDS_ALLDATAWILLBELOST "Warning: All data in the floppy disk will be erased."
+ IDS_SECONDREPAIRDISKPROMPT,"The Setup disk may not be used as the Emergency Repair Disk. Insert a different disk into drive %1.\n\n%2"
+ IDS_RETRYFORMATREPAIRDISK, "%1 was unable to create the Emergency Repair Disk from the disk you provided because the disk could not be formatted.\n\nInsert a new disk into drive %2 and select Retry."
+ IDS_CANTDETERMINEFLOPTYPE, "%1 is unable to get configuration information for the floppy disk drive."
+ IDS_BADFLOPPYTYPE, "The floppy drive is unable to support the required media type."
+ IDS_FORMATGENERALFAILURE, "%1 was unable to format the disk."
+ IDS_FLOPPYWRITEPROT, "The floppy cannot be written to because it is write-protected."
+ IDS_FLOPPYIOERR, "An error occurred reading from or writing to the disk.\n\nThe disk is unusable."
+ IDS_FLOPPYUNKERR, "An unknown error has occurred reading from or writing to the disk.\n\nThe disk is possibly unusable."
+ IDS_HUGEFLOPPYNOTSUPPORTED,"The Emergency Repair Disk cannot be a 120MB floppy disk."
+ IDS_REPAIR_BOOTCODE_MSG "The Emergency Repair Disk is not startable.\r\n\r\nRepairing a damaged Windows NT installation is an option\r\navailable at the beginning of Windows NT Setup.\r\nTo start Setup, insert the Windows NT Setup Disk into drive A:.\r\n\r\nPress control+alt+delete to restart your computer."
+
+ IDS_FORMATTINGDISK, "Formatting Disk"
+
+ IDS_COPYING_FILES, "Copying Configuration Files"
+ IDS_SAVING_CONFIGURATION, "Saving Configuration"
+ IDS_UNABLE_TO_COPY_ALL_FILES, "%1 could not copy all files to the Emergency Repair Disk."
+ IDS_FILE_NOT_FOUND, "%1 could not copy all files to the Emergency Repair Disk.\n\nOne or more configuration files were not found."
+ IDS_DISK_FULL, "%1 could not copy all files to the Emergency Repair Disk.\n\nThe Emergency Repair Disk is full. The configuration files were saved in your hard disk."
+ IDS_CANT_SAVE_CONFIGURATION, "%1 could not save all configuration files."
+ IDS_CONFIRM_SAVE_CONFIGURATION, "The repair information that was saved when you installed the system or when you last ran this utility will be deleted.\n\nDo you want to continue this operation?"
+ IDS_CONFIRM_CREATE_DISK, "%1 can create an Emergency Repair disk, which will contain a copy of the repair information in your system. This disk can be used in the future to repair Windows NT.\n\nDo you want to create the Emergency Repair disk?"
+ IDS_CONFIRM_CREATE_YOU, "You"
+ }
+
+
+
+//
+// Dialogs Definition
+//
+
+#include "dialogs.h"
+// #include "gauge.h"
+#include "dialogs.dlg"
+
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Repair Disk Utility"
+#define VER_INTERNALNAME_STR "rdisk.exe"
+#define VER_ORIGINALFILENAME_STR "rdisk.exe"
+
+#include "common.ver"
diff --git a/private/utils/rdisk/sources b/private/utils/rdisk/sources
new file mode 100644
index 000000000..ee7dbc915
--- /dev/null
+++ b/private/utils/rdisk/sources
@@ -0,0 +1,29 @@
+MAJORCOMP=utils
+MINORCOMP=rdisk
+
+TARGETNAME=rdisk
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+C_DEFINES=-DUNICODE
+
+SOURCES=resource.rc \
+ config.c \
+ format.c \
+ floppyop.c \
+ help.c \
+ diamond.c
+
+UMTYPE=windows
+UMAPPL=rdisk
+UMLIBS= $(BASEDIR)\public\sdk\lib\*\mci.lib \
+ $(BASEDIR)\public\sdk\lib\*\fci.lib \
+ $(BASEDIR)\public\sdk\lib\*\qstub.lib \
+ $(BASEDIR)\public\sdk\lib\*\comctl32.lib \
+ obj\*\rdisk.lib
+
+UMRES=obj\*\resource.res
+
+PRECOMPILED_INCLUDE=precomp.h
+PRECOMPILED_PCH=precomp.pch
+PRECOMPILED_OBJ=precomp.obj
diff --git a/private/utils/recover/makefile b/private/utils/recover/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/recover/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/recover/makefile.inc b/private/utils/recover/makefile.inc
new file mode 100644
index 000000000..6c93eb38d
--- /dev/null
+++ b/private/utils/recover/makefile.inc
@@ -0,0 +1,12 @@
+{}.cxx{obj\i386\}.obj:
+ $(386_COMPILER) -Fo$@ $(MAKEDIR)\$(<F)
+
+{}.cxx{obj\mips\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClMips $< " $(C_COMPILER) "
+ @$(C_COMPILER) -Fo$@ $(MAKEDIR)\$<
+
+{}.cxx{obj\alpha\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClAlpha $< " $(ALPHA_COMPILER) "
+ @$(ALPHA_COMPILER) -Fo$@ $(MAKEDIR)\$<
diff --git a/private/utils/recover/recover.cxx b/private/utils/recover/recover.cxx
new file mode 100644
index 000000000..cfa3e317c
--- /dev/null
+++ b/private/utils/recover/recover.cxx
@@ -0,0 +1,200 @@
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+#include "error.hxx"
+
+#include "arg.hxx"
+#include "smsg.hxx"
+#include "rtmsg.h"
+#include "wstring.hxx"
+#include "path.hxx"
+
+#include "system.hxx"
+#include "ifssys.hxx"
+#include "substrng.hxx"
+
+#include "ulibcl.hxx"
+#include "ifsentry.hxx"
+
+ERRSTACK* perrstk;
+
+int _CRTAPI1
+main(
+ )
+{
+ STREAM_MESSAGE Message;
+ DSTRING FsName;
+ DSTRING LibraryName;
+ HANDLE FsUtilityHandle;
+ DSTRING RecoverString;
+ RECOVER_FN Recover = NULL;
+
+ ARGUMENT_LEXEMIZER arglex;
+ ARRAY lex_array;
+ ARRAY arg_array;
+ STRING_ARGUMENT progname;
+ FLAG_ARGUMENT help_arg;
+ PATH_ARGUMENT path_arg;
+ PWSTRING dosdrive = NULL;
+ DSTRING ntdrive;
+ NTSTATUS Status;
+ PPATH CanonicalPath;
+ PWSTRING DirsAndName;
+ PWSTRING pwstring;
+
+ if (!(perrstk = NEW ERRSTACK)) {
+ return 1;
+ }
+
+ if (!Message.Initialize(Get_Standard_Output_Stream(),
+ Get_Standard_Input_Stream())) {
+ return 1;
+ }
+
+ if (!lex_array.Initialize() || !arg_array.Initialize()) {
+ return 1;
+ }
+
+ if (!arglex.Initialize(&lex_array)) {
+ return 1;
+ }
+
+ arglex.PutStartQuotes("\"");
+ arglex.PutEndQuotes("\"");
+ arglex.PutSeparators(" \t");
+ arglex.SetCaseSensitive(FALSE);
+
+ if (!arglex.PrepareToParse()) {
+ return 1;
+ }
+
+ if (!progname.Initialize("*") ||
+ !help_arg.Initialize("/?") ||
+ !path_arg.Initialize("*")) {
+ return 1;
+ }
+
+ if (!arg_array.Put(&progname) ||
+ !arg_array.Put(&help_arg) ||
+ !arg_array.Put(&path_arg)) {
+ return 1;
+ }
+
+ if (!arglex.DoParsing(&arg_array)) {
+ Message.Set(MSG_INVALID_PARAMETER);
+ Message.Display("%W", pwstring = arglex.QueryInvalidArgument());
+ DELETE(pwstring);
+ return 1;
+ }
+
+ if (help_arg.QueryFlag()) {
+ Message.Set(MSG_RECOV_INFO);
+ Message.Display("");
+ Message.Set(MSG_RECOV_USAGE);
+ Message.Display("");
+ Message.Set(MSG_RECOV_INFO2);
+ Message.Display("");
+ return 0;
+ }
+
+ if (!path_arg.IsValueSet()) {
+ Message.Set(MSG_RECOV_USAGE);
+ Message.Display("");
+ return 1;
+ }
+
+ // Make sure that the user has specified a file name
+
+ DirsAndName = path_arg.GetPath()->QueryDirsAndName();
+
+ if (!DirsAndName || DirsAndName->QueryChCount() == 0) {
+
+ Message.Set(MSG_RECOV_NOT_SUPPORTED);
+ Message.Display("");
+ DELETE(DirsAndName);
+ return 1;
+ }
+
+ DELETE(DirsAndName);
+
+ CanonicalPath = path_arg.GetPath()->QueryFullPath();
+
+ dosdrive = CanonicalPath->QueryDevice();
+
+
+ // Make sure that drive is not remote.
+
+ if (!dosdrive ||
+ SYSTEM::QueryDriveType(dosdrive) == RemoteDrive) {
+ Message.Set(MSG_RECOV_CANT_NETWORK);
+ Message.Display();
+ DELETE(dosdrive);
+ DELETE(CanonicalPath);
+ return 1;
+ }
+
+
+ if (!IFS_SYSTEM::DosDriveNameToNtDriveName(dosdrive, &ntdrive)) {
+ DELETE(dosdrive);
+ DELETE(CanonicalPath);
+ return 1;
+ }
+
+
+ if (!IFS_SYSTEM::QueryFileSystemName(&ntdrive, &FsName, &Status)) {
+
+ if( Status == STATUS_ACCESS_DENIED ) {
+
+ Message.Set( MSG_DASD_ACCESS_DENIED );
+ Message.Display( "" );
+
+ } else {
+
+ Message.Set( MSG_FS_NOT_DETERMINED );
+ Message.Display( "%W", dosdrive );
+ }
+
+ DELETE(dosdrive);
+ DELETE(CanonicalPath);
+ return 1;
+ }
+
+ Message.Set(MSG_FILE_SYSTEM_TYPE);
+ Message.Display("%W", &FsName);
+
+ if (!LibraryName.Initialize("U") ||
+ !LibraryName.Strcat(&FsName) ||
+ !RecoverString.Initialize("Recover")) {
+
+ Message.Set(MSG_FMT_NO_MEMORY);
+ Message.Display("");
+ DELETE(dosdrive);
+ DELETE(CanonicalPath);
+ return(1);
+ }
+
+
+ if ((Recover = (RECOVER_FN)SYSTEM::QueryLibraryEntryPoint(&LibraryName,
+ &RecoverString,
+ &FsUtilityHandle))
+ != NULL) {
+
+ Recover(CanonicalPath, &Message);
+
+ SYSTEM::FreeLibraryHandle(FsUtilityHandle);
+
+ } else {
+
+ Message.Set(MSG_FS_NOT_SUPPORTED);
+ Message.Display("%s%W", "RECOVER", &FsName);
+ Message.Set(MSG_BLANK_LINE);
+ Message.Display("");
+ DELETE(dosdrive);
+ DELETE(CanonicalPath);
+ return(1);
+ }
+
+ DELETE(dosdrive);
+ DELETE(CanonicalPath);
+ return(0);
+}
diff --git a/private/utils/recover/recover.rc b/private/utils/recover/recover.rc
new file mode 100644
index 000000000..ed8c88d5b
--- /dev/null
+++ b/private/utils/recover/recover.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Recover Files Utility"
+#define VER_INTERNALNAME_STR "Recover"
+#define VER_ORIGINALFILENAME_STR "Recover.Exe"
+
+#include "common.ver"
diff --git a/private/utils/recover/sources b/private/utils/recover/sources
new file mode 100644
index 000000000..7c723461d
--- /dev/null
+++ b/private/utils/recover/sources
@@ -0,0 +1,57 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=utils
+MINORCOMP=recover
+
+TARGETNAME=recover
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=recover.rc recover.cxx
+
+INCLUDES=..\ulib\inc;..\ifsutil\inc;\nt\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+TARGETLIBS= \
+ ..\ulib\src\obj\*\ulib.lib \
+ ..\ifsutil\src\obj\*\ifsutil.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+
+UMTYPE=console
diff --git a/private/utils/regedit/dirs b/private/utils/regedit/dirs
new file mode 100644
index 000000000..c4db5a979
--- /dev/null
+++ b/private/utils/regedit/dirs
@@ -0,0 +1,16 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+!ENDIF
+
+DIRS= src
diff --git a/private/utils/regedit/inc/datavw.hxx b/private/utils/regedit/inc/datavw.hxx
new file mode 100644
index 000000000..aa5c1361e
--- /dev/null
+++ b/private/utils/regedit/inc/datavw.hxx
@@ -0,0 +1,207 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ datavw.hxx
+
+Abstract:
+
+ This module contains the declaration for the DATA_VIEW
+ class. DATA_VIEW models the display of the values for a node.
+
+Author:
+
+ Bruce W. Wilson (w-wilson) 22-Aug-1991
+
+Environment:
+
+ Ulib, Regedit, Windows, User Mode
+
+--*/
+#if !defined( _DATA_VIEW_ )
+
+#define _DATA_VIEW_
+
+#include "window.hxx"
+#include "regedval.hxx"
+
+DECLARE_CLASS( REGEDIT_INTERNAL_REGISTRY );
+DECLARE_CLASS( REGEDIT_NODE );
+DECLARE_CLASS( DATA_VIEW );
+
+class DATA_VIEW : public WINDOW {
+
+ friend class REGISTRY_WINDOW;
+
+ public:
+
+ DECLARE_CONSTRUCTOR( DATA_VIEW );
+
+ DECLARE_CAST_MEMBER_FUNCTION( DATA_VIEW );
+
+ VOID
+ Resize(
+ IN INT NewX,
+ IN INT NewY,
+ IN INT NewWidth,
+ IN INT NewHeight
+ );
+
+ VOID
+ SetDataNode(
+ IN PCREGEDIT_NODE NewNode,
+ IN BOOLEAN ForceRefresh DEFAULT FALSE
+ );
+
+ private:
+
+ DECLARE_WNDPROC( DATA_VIEW );
+
+ NONVIRTUAL
+ VOID
+ ChangeItemHeight(
+ );
+
+
+ NONVIRTUAL
+ STATIC
+ BOOL
+ APIENTRY
+ EXPORT
+ AddValueDialogProc(
+ HWND hDlg,
+ WORD msg,
+ WPARAM wParam,
+ LONG lParam
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ IN HWND ParentHandle,
+ IN PREGEDIT_INTERNAL_REGISTRY InternalRegistry
+ );
+
+ NONVIRTUAL
+ VOID
+ DrawItem(
+ LPDRAWITEMSTRUCT lpLBItem
+ );
+
+ NONVIRTUAL
+ VOID
+ InitMenu(
+ IN HMENU Menu,
+ IN INT PopupMenu
+ );
+
+ NONVIRTUAL
+ VOID
+ EditValue(
+ IN REG_TYPE EditAsType
+ );
+
+ NONVIRTUAL
+ STATIC
+ BOOLEAN
+ Register (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DeleteCurrentItem(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AddValueEntry(
+ );
+
+ NONVIRTUAL
+ VOID
+ AdjustHorizontalScrollBar(
+ );
+
+ NONVIRTUAL
+ PCREGEDIT_FORMATTED_VALUE_ENTRY
+ GetCurrentValue(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SaveCurrentValueName(
+ );
+
+ STATIC
+ LPWSTR _WindowClassName;
+
+ STATIC
+ BOOLEAN _Registered;
+
+ HWND _hwndList;
+ BOOLEAN _HasFocus;
+
+ //
+ // some stuff cached for speed
+ //
+ LONG _Items;
+ INT _CurrentItem;
+ PCREGEDIT_NODE _Node;
+ PREGEDIT_INTERNAL_REGISTRY _IR;
+ LONG _MaxWidth;
+ PDSTRING _CurrentValueName;
+
+
+ STATIC
+ PWSTRING _RegBinaryString;
+ STATIC
+ PWSTRING _RegDwordString;
+ STATIC
+ PWSTRING _RegSzString;
+ STATIC
+ PWSTRING _RegMultiSzString;
+ STATIC
+ PWSTRING _RegExpandSzString;
+
+};
+
+
+INLINE
+VOID
+DATA_VIEW::AdjustHorizontalScrollBar(
+)
+/*++
+
+Routine Description:
+
+ Sets the extent of the horizontal scroll bar so that the longest
+ string in the listbox can be viewed.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ SendMessage( _hwndList, LB_SETHORIZONTALEXTENT, (UINT)_MaxWidth, 0 );
+}
+
+INLINE
+VOID
+DATA_VIEW::Resize(
+ IN INT NewX,
+ IN INT NewY,
+ IN INT NewWidth,
+ IN INT NewHeight
+) {
+ MoveWindow( _Handle, NewX, NewY, NewWidth, NewHeight, TRUE );
+}
+
+#endif // _DATA_VIEW_
diff --git a/private/utils/regedit/inc/defmsg.h b/private/utils/regedit/inc/defmsg.h
new file mode 100644
index 000000000..d56dc4e24
--- /dev/null
+++ b/private/utils/regedit/inc/defmsg.h
@@ -0,0 +1,276 @@
+#define MSG_WINDOW_NAME 0
+
+
+
+#define MSG_VALUE_TYPE_REG_SZ 10
+#define MSG_VALUE_TYPE_REG_BINARY 11
+#define MSG_VALUE_TYPE_REG_DWORD 12
+#define MSG_VALUE_TYPE_REG_COLOR_RGB 13
+#define MSG_VALUE_TYPE_REG_FILE_NAME 14
+#define MSG_VALUE_TYPE_REG_FILE_TIME 15
+#define MSG_VALUE_TYPE_REG_UNKNOWN 16
+#define MSG_VALUE_TYPE_REG_NONE 17
+#define MSG_VALUE_TYPE_REG_MULTI_SZ 18
+#define MSG_VALUE_TYPE_REG_EXPAND_SZ 19
+#define MSG_VALUE_TYPE_REG_RESOURCE_LIST 20
+#define MSG_VALUE_TYPE_REG_FULL_RESOURCE_DESCRIPTOR 21
+#define MSG_VALUE_TYPE_REG_RESOURCE_REQUIREMENTS_LIST 22
+
+#define MSG_FORMATTED_VALUE_SEPARATOR 100
+#define MSG_FORMATTED_VALUE_NO_NAME 101
+#define MSG_FORMATTED_VALUE_INVALID_DATA 102
+
+#define MSG_PRINT_DIALOG_TITLE 1000
+#define MSG_PRINT_SP_ERROR_LINE1 1001
+#define MSG_PRINT_SP_ERROR_LINE2 1002
+#define MSG_PRINT_SP_ERROR_LINE3 1003
+#define MSG_PRINT_SP_ERROR_LINE4 1004
+#define MSG_PRINT_SP_ERROR_LINE5 1005
+#define MSG_PRINT_SP_ERROR_LINE6 1006
+#define MSG_PRINT_SP_OUTOFDISK 1007
+#define MSG_PRINT_SP_OUTOFMEMORY 1008
+#define MSG_PRINT_SP_APPABORT 1009
+#define MSG_PRINT_SP_USERABORT 1010
+#define MSG_PRINT_UNKNOWN_ERROR 1011
+#define MSG_PRINT_ERROR_DIALOG_TITLE 1012
+#define MSG_PRINT_NODE_NAME 1013
+#define MSG_PRINT_NODE_CLASS_NAME 1014
+#define MSG_PRINT_NODE_TITLE_INDEX 1015
+#define MSG_PRINT_NODE_TITLE 1016
+#define MSG_PRINT_NODE_LAST_WRITE_TIME 1017
+#define MSG_PRINT_VALUE_NUMBER 1018
+#define MSG_PRINT_VALUE_NAME 1019
+#define MSG_PRINT_VALUE_TITLE_INDEX 1020
+#define MSG_PRINT_VALUE_TITLE 1021
+#define MSG_PRINT_VALUE_TYPE 1022
+#define MSG_PRINT_VALUE_DATA_SIZE 1023
+#define MSG_PRINT_VALUE_DATA 1024
+#define MSG_PRINT_VALUE_NO_NAME 1025
+#define MSG_PRINT_NODE_NO_CLASS 1026
+#define MSG_PRINT_FULL_DESCRIPTOR 1027
+#define MSG_PRINT_PARTIAL_DESCRIPTOR 1028
+#define MSG_PRINT_INTERFACE_TYPE 1029
+#define MSG_PRINT_BUS_NUMBER 1030
+#define MSG_PRINT_VERSION 1031
+#define MSG_PRINT_REVISION 1032
+#define MSG_PRINT_RESOURCE 1033
+#define MSG_PRINT_DISPOSITION 1034
+#define MSG_PRINT_TYPE 1035
+#define MSG_PRINT_START 1036
+#define MSG_PRINT_LENGTH 1037
+#define MSG_PRINT_LEVEL 1038
+#define MSG_PRINT_VECTOR 1039
+#define MSG_PRINT_AFFINITY 1040
+#define MSG_PRINT_CHANNEL 1041
+#define MSG_PRINT_PORT 1042
+#define MSG_PRINT_RESERVED1 1043
+#define MSG_PRINT_RESERVED2 1044
+#define MSG_PRINT_DEV_SPECIFIC_DATA 1045
+
+#define MSG_PRINT_IO_INTERFACE_TYPE 1046
+#define MSG_PRINT_IO_BUS_NUMBER 1047
+#define MSG_PRINT_IO_SLOT_NUMBER 1048
+#define MSG_PRINT_IO_LIST_NUMBER 1049
+#define MSG_PRINT_IO_DESCRIPTOR_NUMBER 1050
+#define MSG_PRINT_IO_OPTION 1051
+#define MSG_PRINT_IO_ALIGNMENT 1052
+#define MSG_PRINT_IO_MINIMUM_ADDRESS 1053
+#define MSG_PRINT_IO_MAXIMUM_ADDRESS 1054
+#define MSG_PRINT_IO_MINIMUM_VECTOR 1055
+#define MSG_PRINT_IO_MAXIMUM_VECTOR 1056
+#define MSG_PRINT_IO_MINIMUM_CHANNEL 1057
+#define MSG_PRINT_IO_MAXIMUM_CHANNEL 1058
+
+#define MSG_ADD_VALUE_ERROR_NO_NAME 2000
+#define MSG_ADD_VALUE_ERROR_NO_TITLE 2001
+#define MSG_ADD_VALUE_ERROR_NO_DATA 2002
+#define MSG_ADD_VALUE_WARN_OVERFLOW 2003
+#define MSG_ADD_VALUE_WARN_OVERFLOW_EX 2004
+#define MSG_ADD_VALUE_REMOVE_EMPTY_STRING_EX 2005
+#define MSG_ADD_VALUE_REMOVE_EMPTY_STRINGS_EX 2006
+#define MSG_ADD_VALUE_ALREADY_EXISTS_EX 2007
+#define MSG_ADD_VALUE_WARN_PADDING_EX 2008
+
+
+#define MSG_ADD_KEY_ERROR_NO_NAME 3000
+#define MSG_ADD_KEY_ERROR_NO_NAME_EX 3001
+#define MSG_ADD_KEY_ERROR_NO_TITLE 3002
+#define MSG_ADD_KEY_INVALID_KEY_NAME 3003
+#define MSG_ADD_KEY_INVALID_KEY_NAME_EX 3004
+#define MSG_ADD_KEY_ALREADY_EXISTS_EX 3005
+#define MSG_DELETE_KEY_CONFIRM_EX 3010
+#define MSG_WARNING_TITLE 3015
+#define MSG_DELETE_VALUE_CONFIRM_EX 3020
+#define MSG_READONLY_MODE_EDIT_VALUE_EX 3025
+#define MSG_READONLY_MODE_SET_SECURITY_EX 3030
+
+#define MSG_DISPLAY_BINARY_VALUE_TYPE 5000
+#define MSG_DISPLAY_BINARY_VALUE_NAME 5001
+
+
+
+#define MSG_ACCESS_DENIED 4000
+#define MSG_KEY_MARKED_FOR_DELETION 4001
+#define MSG_ACCESS_DENIED_EX 4002
+#define MSG_FAILED_OPERATION_EX 4003
+#define MSG_ADD_KEY_ACCESS_DENIED_EX 4004
+#define MSG_ADD_KEY_KEY_DELETED_EX 4005
+#define MSG_DELETE_KEY_ACCESS_DENIED_EX 4006
+#define MSG_DELETE_KEY_KEY_DELETED_EX 4007
+
+#define MSG_ADD_VALUE_ACCESS_DENIED_EX 4008
+#define MSG_ADD_VALUE_KEY_DELETED_EX 4009
+#define MSG_DELETE_VALUE_ACCESS_DENIED_EX 4010
+#define MSG_DELETE_VALUE_KEY_DELETED_EX 4011
+#define MSG_SAVE_VALUE_ACCESS_DENIED_EX 4012
+#define MSG_SAVE_VALUE_KEY_DELETED_EX 4013
+
+#define MSG_GET_SECURITY_ACCESS_DENIED_EX 4014
+#define MSG_GET_SECURITY_KEY_DELETED_EX 4015
+#define MSG_SET_SECURITY_ACCESS_DENIED_EX 4016
+#define MSG_SET_SECURITY_KEY_DELETED_EX 4017
+
+#define MSG_UNKNOWN_ERROR 4018
+
+#define MSG_SET_SECURITY_ACCESS_DENIED_RECURSIVE_EX 4019
+#define MSG_SET_SECURITY_KEY_DELETED_RECURSIVE_EX 4020
+#define MSG_SET_SECURITY_KEY_NOT_ACCESSIBLE_RECURSIVE_EX 4021
+#define MSG_SET_SECURITY_KEY_NOT_ACCESSIBLE_EX 4022
+#define MSG_GET_SECURITY_KEY_NOT_ACCESSIBLE_EX 4023
+
+#define MSG_ADD_KEY_KEY_NOT_ACCESSIBLE_EX 4024
+#define MSG_DELETE_KEY_KEY_NOT_ACCESSIBLE_EX 4025
+#define MSG_ADD_VALUE_KEY_NOT_ACCESSIBLE_EX 4026
+#define MSG_SAVE_VALUE_KEY_NOT_ACCESSIBLE_EX 4027
+#define MSG_DELETE_VALUE_KEY_NOT_ACCESSIBLE_EX 4028
+
+#define MSG_KEY_NOT_ACCESSIBLE 4029
+#define MSG_KEY_NOT_ACCESSIBLE_EX 4030
+
+#define MSG_KEY_VOLATILE 4031
+#define MSG_ADD_KEY_VOLATILE_EX 4032
+#define MSG_LOAD_KEY_VOLATILE_EX 4033
+
+#define MSG_SAVE_KEY_KEY_NOT_ACCESSIBLE_EX 4034
+#define MSG_RESTORE_KEY_KEY_NOT_ACCESSIBLE_EX 4035
+#define MSG_DISK_FULL 4036
+#define MSG_SAVE_SUBTREE_AS_DISK_FULL 4037
+#define MSG_SAVE_SUBTREE_AS_UNKNOWN_ERROR 4038
+
+#define MSG_REGISTRY_EDITOR 6000
+#define MSG_HELP_FILE_NAME 6001
+#define MSG_CANT_READ_CLASSES_ROOT 6002
+#define MSG_CANT_READ_LOCAL_MACHINE 6003
+#define MSG_CANT_READ_CURRENT_USER 6004
+#define MSG_CANT_READ_USERS 6005
+#define MSG_CANT_FIND_KEY 6010
+#define MSG_CANT_ACCESS_REMOTE_REGISTRY 6011
+#define MSG_CANT_ACCESS_REGISTRY 6012
+#define MSG_SERVER_UNAVAILABLE 6013
+#define MSG_DISABLING_AUTOREFRESH 6014
+#define MSG_CANT_READ_CURRENT_CONFIG 6015
+
+
+#define MSG_SEC_EDITOR_QUERY_VALUE 7000
+#define MSG_SEC_EDITOR_SET_VALUE 7001
+#define MSG_SEC_EDITOR_ENUM_SUBKEYS 7002
+#define MSG_SEC_EDITOR_NOTIFY 7003
+#define MSG_SEC_EDITOR_CREATE_SUBKEY 7004
+#define MSG_SEC_EDITOR_DELETE 7005
+#define MSG_SEC_EDITOR_WRITE_DAC 7006
+#define MSG_SEC_EDITOR_WRITE_OWNER 7007
+#define MSG_SEC_EDITOR_READ_CONTROL 7008
+#define MSG_SEC_EDITOR_READ 7009
+#define MSG_SEC_EDITOR_FULL_ACCESS 7010
+#define MSG_SEC_EDITOR_SPECIAL_ACCESS 7011
+#define MSG_SEC_EDITOR_REGISTRY_KEY 7012
+#define MSG_SEC_EDITOR_APPLY_TO_SUBKEYS 7013
+#define MSG_SEC_EDITOR_AUDIT_SUBKEYS 7014
+#define MSG_SEC_EDITOR_CONFIRM_APPLY_TO_SUBKEYS 7015
+#define MSG_SEC_EDITOR_CONFIRM_AUDIT_SUBKEYS 7016
+#define MSG_SEC_EDITOR_DEFAULT_PERM_NAME 7017
+#define MSG_SEC_EDITOR_CREATE_LINK 7018
+
+#define MSG_REG_WINDOW_TITLE_LOCAL 10000
+#define MSG_REG_WINDOW_TITLE_REMOTE 10001
+
+
+#define MSG_INI_FILE 9000
+#define MSG_SETTINGS 9001
+#define MSG_REGISTRY 9002
+#define MSG_KEYS 9003
+#define MSG_AUTO_REFRESH 9004
+#define MSG_READ_ONLY 9005
+#define MSG_REMOTE_ACCESS 9006
+#define MSG_CONFIRM_ON_DELETE 9007
+#define MSG_SAVE_SETTINGS 9008
+#define MSG_LEFT 9009
+#define MSG_TOP 9010
+#define MSG_WIDTH 9011
+#define MSG_HEIGHT 9012
+#define MSG_MAXIMIZED 9013
+#define MSG_FONT 9014
+#define MSG_FACE_NAME 9015
+#define MSG_KEY_LOCAL_MACHINE 9016
+#define MSG_KEY_CLASSES_ROOT 9017
+#define MSG_KEY_USERS 9018
+#define MSG_KEY_CURRENT_USER 9019
+#define MSG_DEFAULT_FACE_NAME 9020
+#define MSG_KEY_CURRENT_CONFIG 9021
+
+#define MSG_LOAD_HIVE_ALREADY_EXISTS_EX 11000
+#define MSG_LOAD_HIVE_ACCESS_DENIED_EX 11001
+#define MSG_LOAD_HIVE_BAD_FILE_EX 11002
+#define MSG_LOAD_HIVE_BAD_FILE 11003
+
+#define MSG_UNLOAD_HIVE_ACCESS_DENIED_EX 11004
+#define MSG_UNLOAD_HIVE_CONFIRM_EX 11005
+#define MSG_RESTORE_KEY_ACCESS_DENIED_EX 11006
+#define MSG_RESTORE_KEY_CONFIRM_EX 11007
+#define MSG_SAVE_KEY_ACCESS_DENIED_EX 11008
+#define MSG_SAVE_KEY_DLG_TITLE 11009
+#define MSG_RESTORE_KEY_DLG_TITLE 11010
+#define MSG_LOAD_HIVE_DLG_TITLE 11011
+
+#define MSG_FILTER_ALL_FILES 12000
+#define MSG_FILTER_TXT_FILES 12001
+#define MSG_FILTER_STAR_DOT_STAR 12002
+#define MSG_FILTER_STAR_DOT_TXT 12003
+
+#define MSG_EDITOR_HEX_RULER 13001
+#define MSG_EDITOR_BINARY_RULER 13002
+
+#define MSG_BUS_INTERNAL 14000
+#define MSG_BUS_ISA 14001
+#define MSG_BUS_EISA 14002
+#define MSG_BUS_MICRO_CHANNEL 14003
+#define MSG_BUS_TURBO_CHANNEL 14004
+#define MSG_BUS_PCI_BUS 14005
+#define MSG_BUS_VME_BUS 14006
+#define MSG_BUS_NU_BUS 14007
+#define MSG_BUS_PCMCIA_BUS 14008
+#define MSG_BUS_C_BUS 14009
+#define MSG_BUS_MPI_BUS 14010
+#define MSG_BUS_MPSA_BUS 14011
+
+#define MSG_INT_LEVEL_SENSITIVE 14050
+#define MSG_INT_LATCHED 14051
+#define MSG_MEM_READ_WRITE 14052
+#define MSG_MEM_READ_ONLY 14053
+#define MSG_MEM_WRITE_ONLY 14054
+#define MSG_PORT_MEMORY 14055
+#define MSG_PORT_PORT 14056
+#define MSG_INVALID 14057
+
+#define MSG_DEV_PORT 14058
+#define MSG_DEV_INTERRUPT 14059
+#define MSG_DEV_MEMORY 14060
+#define MSG_DEV_DMA 14061
+#define MSG_DEV_DEVICE_SPECIFIC 14062
+
+#define MSG_SHARE_UNDETERMINED 14063
+#define MSG_SHARE_DEVICE_EXCLUSIVE 14064
+#define MSG_SHARE_DRIVER_EXCLUSIVE 14065
+#define MSG_SHARE_SHARED 14066
+
+#define MSG_REGEDIT_DISABLED 14067
diff --git a/private/utils/regedit/inc/dialogs.h b/private/utils/regedit/inc/dialogs.h
new file mode 100644
index 000000000..3f15cb7f5
--- /dev/null
+++ b/private/utils/regedit/inc/dialogs.h
@@ -0,0 +1,103 @@
+#define ADD_KEY_DLG 100
+#define ADD_VALUE_DLG 300
+#define DISPLAY_BINARY_DATA 500
+#define IDD_ADD_KEY_NAME 104
+#define IDD_ADD_KEY_LOCALIZED_NAME 105
+#define IDD_ADD_KEY_CLASS 106
+#define IDD_DWORD_DATA 201
+#define IDD_DWORD_BINARY 203
+#define IDD_DWORD_DECIMAL 204
+#define IDD_DWORD_HEX 205
+#define IDD_ADD_VALUE_DATA_TYPE 301
+#define IDD_ADD_VALUE_NAME 302
+#define IDD_ADD_VALUE_LOCALIZED_NAME 303
+#define IDD_MULTI_SZ_EDIT_CONTROL 401
+#define IDD_DISPLAY_DATA_BINARY 501
+#define DWORD_EDITOR_DLG 200
+#define BINARY_EDITOR_DLG 700
+#define IDD_BINARY_DATA 701
+#define IDD_BINARY_EDITOR_BIN 702
+#define IDD_BINARY_EDITOR_DEC 703
+#define IDD_BIN_EDITOR_HEX 704
+#define STRING_EDITOR_DLG 800
+#define IDD_STRING_DATA 801
+#define MULTI_SZ_EDITOR_DLG 400
+#define ABOUT_DLG 600
+#define IDD_EDIT 705
+#define IDD_BINARY 706
+#define IDD_DECIMAL 707
+#define IDD_HEX 708
+#define IDB_HELP 109
+#define IDD_BINARY_RULER 709
+#define IDD_VERTICAL_RULER 710
+#define GET_KEY_DLG 1000
+
+
+
+#define IDC_LIST_DRIVES 1201
+#define IDC_PUSH_DRIVE_DETAILS 1215
+#define IDC_PUSH_DISPLAY_RESOURCES 1301
+#define IDC_PUSH_DISPLAY_DATA 1302
+#define IDD_RESOURCE_LIST 2100
+#define IDC_FULL_RES_TEXT_BUS_NUMBER 2511
+#define IDC_FULL_RES_TEXT_VERSION 2512
+#define IDC_FULL_RES_TEXT_REVISION 2513
+#define IDC_FULL_RES_TEXT_INTERFACE_TYPE 2510
+#define IDC_FULL_RES_LIST_DEVICE_SPECIFIC 2505
+#define IDD_FULL_RES_DESCRIPTOR 2500
+#define IDC_FULL_RES_LIST_DMA 2501
+#define IDC_FULL_RES_LIST_INTERRUPTS 2502
+#define IDC_FULL_RES_LIST_MEMORY 2503
+#define IDC_FULL_RES_LIST_PORTS 2504
+#define IDC_FULL_RES_TEXT_UNDETERMINED 2506
+#define IDC_FULL_RES_TEXT_SHARED 2507
+#define IDC_FULL_RES_TEXT_DEVICE_EXCLUSIVE 2508
+#define IDC_FULL_RES_TEXT_DRIVER_EXCLUSIVE 2509
+#define IDC_LIST_RESOURCE_LISTS 2101
+#define IDD_IO_REQUIREMENT_LISTS 2600
+#define IDD_IO_REQ_INTERFACE_TYPE 2602
+#define IDD_IO_REQ_BUS_NUMBER 2603
+#define IDD_IO_REQ_SLOT_NUMBER 2604
+
+#define IDD_IO_REQUIREMENTS_LIST 2700
+#define IDC_IO_LIST_ALTERNATIVE_LISTS 2701
+#define IDC_IO_REQ_TEXT_INTERFACE_TYPE 2702
+#define IDC_IO_REQ_TEXT_BUS_NUMBER 2703
+#define IDC_IO_REQ_TEXT_SLOT_NUMBER 2704
+#define IDC_IO_REQ_PUSH_DISPLAY_DEVICE 2705
+
+#define IDD_IO_MEMORY_RESOURCE 2800
+#define IDC_IO_TEXT_MEM_ACCESS 2801
+#define IDC_IO_TEXT_MEM_LENGTH 2803
+#define IDC_IO_TEXT_MEM_MIN_ADDRESS 2804
+#define IDC_IO_TEXT_MEM_MAX_ADDRESS 2805
+#define IDC_IO_TEXT_MEM_ALIGNMENT 2806
+
+#define IDD_IO_PORT_RESOURCE 2900
+#define IDC_IO_TEXT_PORT_TYPE 2901
+#define IDC_IO_TEXT_PORT_LENGTH 2903
+#define IDC_IO_TEXT_PORT_MIN_ADDRESS 2904
+#define IDC_IO_TEXT_PORT_MAX_ADDRESS 2905
+#define IDC_IO_TEXT_PORT_ALIGNMENT 2906
+
+
+#define IDD_IO_INTERRUPT_RESOURCE 3000
+#define IDC_IO_TEXT_INT_TYPE 3001
+#define IDC_IO_TEXT_INT_MIN_VECTOR 3003
+#define IDC_IO_TEXT_INT_MAX_VECTOR 3004
+
+
+#define IDD_IO_DMA_RESOURCE 3100
+#define IDC_IO_TEXT_DMA_MIN_CHANNEL 3102
+#define IDC_IO_TEXT_DMA_MAX_CHANNEL 3103
+
+#define IDC_IO_TEXT_DISPOSITION 3200
+#define IDC_IO_TEXT_OPTION_PREFERRED 3202
+#define IDC_IO_TEXT_OPTION_ALTERNATIVE 3203
+
+#define IDR_BINARY_DATA_BYTE 504
+#define IDR_BINARY_DATA_WORD 505
+#define IDR_BINARY_DATA_DWORD 506
+
+#define DISPLAY_BINARY_DATA_WITH_VALUE_TYPE 900
+#define IDT_VALUE_TYPE 901
diff --git a/private/utils/regedit/inc/editor.hxx b/private/utils/regedit/inc/editor.hxx
new file mode 100644
index 000000000..beb00b3b2
--- /dev/null
+++ b/private/utils/regedit/inc/editor.hxx
@@ -0,0 +1,183 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ Editor.hxx
+
+Abstract:
+
+ This module contains the definition for the EDITOR class. The main
+ purpose of this class is to provide editing support for the RegEdit
+ utility.
+
+Author:
+
+ Barry J. Gilhuly (w-barry) 31-Jul-1991
+
+Environment:
+
+ Ulib, Regedit, Windows, User Mode
+
+Notes:
+
+ When ported to the 32-bit version of windows, the third parameter of
+ the dialog procs must be changed from WORDs to LONGs.
+
+--*/
+
+#if !defined( _EDITOR_ )
+
+#define _EDITOR_
+
+#include "regvalue.hxx"
+
+// #include "value.hxx"
+
+//
+// Declare additional primitive type.
+//
+
+typedef PVOID* PPVOID;
+typedef PSTR* PPSTR;
+
+//
+// Define the masks required to extract the half bytes required...
+//
+
+#define HIMASK 0xF0
+#define LOMASK 0x0F
+#define HEX_WIDTH 4
+
+//
+// Define the message types required for passing and retriving the current
+// state.
+//
+
+#define EI_SETSTATE WM_USER
+#define EI_GETSTATE WM_USER + 1
+#define EI_VSCROLL WM_USER + 2
+
+
+//
+// Type of one of the parameters passed to IsValidBinaryString() and
+// IsValidDwordString()
+//
+
+typedef enum _BASE {
+ BASE_2,
+ BASE_10,
+ BASE_16
+ } BASE;
+
+
+
+//
+// Declare type for communication with Dialog Procs.
+//
+
+struct _DIALOGINFO {
+ PPVOID DataObject;
+ PULONG NumBytes;
+ REG_TYPE DataType;
+};
+
+DEFINE_TYPE( struct _DIALOGINFO, DIALOGINFO );
+
+DECLARE_CLASS( EDITOR );
+
+VOID
+BytesToHexString(
+ IN PBYTE InBytes,
+ IN INT NumBytes,
+ OUT LPWSTR OutString
+);
+
+
+class EDITOR : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( EDITOR );
+
+ DECLARE_CAST_MEMBER_FUNCTION( EDITOR );
+
+ PVOID
+ Edit(
+ IN HWND hwnd,
+ IN REG_TYPE DataType,
+ IN PVOID pData,
+ IN ULONG nBytesIn,
+ OUT PULONG nBytesOut,
+ IN REG_TYPE Type
+ );
+
+ PVOID
+ Edit(
+ IN HWND hwnd,
+ IN REG_TYPE DataType,
+ IN PVOID pData,
+ IN ULONG nBytesIn,
+ OUT PULONG nBytesOut,
+ IN WORD MessageId
+ );
+
+ private:
+
+ DECLARE_DLGPROC( EDITOR, BINARYDialogProc );
+
+ DECLARE_DLGPROC( EDITOR, DWORDDialogProc );
+
+ DECLARE_DLGPROC( EDITOR, SZDialogProc );
+
+ DECLARE_DLGPROC( EDITOR, MULTISZDialogProc );
+
+ STATIC
+ LONG
+ APIENTRY
+ EXPORT
+ EditInteger(
+ HWND hWnd,
+ WORD msg,
+ WPARAM wParam,
+ LONG lParam
+ );
+
+ STATIC
+ LONG
+ APIENTRY
+ EXPORT
+ EditDWORD(
+ HWND hWnd,
+ WORD msg,
+ WPARAM wParam,
+ LONG lParam
+ );
+
+ STATIC
+ BOOLEAN
+ IsClipboardDataValid(
+ IN HWND hWnd,
+ IN BOOLEAN DwordEditor,
+ IN BASE Base
+ );
+
+ STATIC
+ BOOLEAN
+ IsValidBinaryString(
+ IN PWSTR String,
+ IN BASE Base
+ );
+
+ STATIC
+ BOOLEAN
+ IsValidDwordString(
+ IN PWSTR String,
+ IN BASE Base
+ );
+
+
+};
+
+#endif // _EDITOR_
diff --git a/private/utils/regedit/inc/printman.hxx b/private/utils/regedit/inc/printman.hxx
new file mode 100644
index 000000000..deb7e4d2e
--- /dev/null
+++ b/private/utils/regedit/inc/printman.hxx
@@ -0,0 +1,400 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ printman.hxx
+
+Abstract:
+
+ This module contains the declarations for the PRINT_MANAGER class.
+ The PRINT_MANAGER class is responsible for displayning the Printer
+ Setup Dialog, for printing a registry.
+
+
+Author:
+
+ Jaime Sasson (jaimes) 18-Sep-1991
+
+
+Environment:
+
+
+
+--*/
+
+
+#if !defined( _PRINT_MANAGER_ )
+
+#define _PRINT_MANAGER_
+
+#include "regedir.hxx"
+#include "ulib.hxx"
+#include "uapp.hxx"
+#include "timeinfo.hxx"
+#include "wstring.hxx"
+#include "regresls.hxx"
+#include "regfdesc.hxx"
+#include "regdesc.hxx"
+#include "regioreq.hxx"
+#include "regiodls.hxx"
+#include "regiodsc.hxx"
+
+
+DECLARE_CLASS( PRINT_MANAGER );
+
+
+class PRINT_MANAGER : public OBJECT {
+
+
+ public:
+
+
+ DECLARE_CONSTRUCTOR( PRINT_MANAGER );
+
+ DECLARE_CAST_MEMBER_FUNCTION( PRINT_MANAGER );
+
+ VIRTUAL
+ ~PRINT_MANAGER(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN HWND Owner
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintRegistry(
+ IN HANDLE Instance,
+ IN HWND hWnd,
+ IN HWND MDIHandle,
+ IN PREGEDIT_INTERNAL_REGISTRY InternalRegistry,
+ IN PCREGEDIT_NODE StartNode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintToTextFile(
+ IN HANDLE Instance,
+ IN HWND hWnd,
+ IN HWND MDIHandle,
+ IN PREGEDIT_INTERNAL_REGISTRY InternalRegistry,
+ IN PCREGEDIT_NODE StartNode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrinterSetupDialog(
+ );
+
+ private:
+
+ DECLARE_DLGPROC( PRINT_MANAGER, PrintDlgProc );
+
+ NONVIRTUAL
+ BOOLEAN
+ InitializeTextMetrics(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ BuildHeaderFooter(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ EndPrint(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintDataRegBinary(
+ IN PCBYTE Buffer,
+ IN ULONG Size,
+ IN BOOLEAN PrintDataLabel DEFAULT TRUE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintDataRegMultiSz(
+ IN PCBYTE Buffer,
+ IN ULONG Size
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintDataRegResourceList(
+ IN PCBYTE Buffer,
+ IN ULONG Size
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintFullResourceDescriptor(
+ IN PCFULL_DESCRIPTOR FullDescriptor,
+ IN ULONG DescriptorNumber,
+ IN BOOLEAN PrintDescriptorNumber DEFAULT TRUE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintPartialDescriptor(
+ IN PCPARTIAL_DESCRIPTOR FullDescriptor,
+ IN ULONG DescriptorNumber
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintInterruptDescriptor(
+ IN PCINTERRUPT_DESCRIPTOR Descriptor
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintPortDescriptor(
+ IN PCPORT_DESCRIPTOR Descriptor
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintMemoryDescriptor(
+ IN PCMEMORY_DESCRIPTOR Descriptor
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintDmaDescriptor(
+ IN PCDMA_DESCRIPTOR Descriptor
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintDeviceSpecificDescriptor(
+ IN PCDEVICE_SPECIFIC_DESCRIPTOR Descriptor
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintDataRegRequirementsList(
+ IN PCBYTE Buffer,
+ IN ULONG Size
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintIoResourceList(
+ IN PCIO_DESCRIPTOR_LIST DescriptorList,
+ IN ULONG ListNumber
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintIoDescriptor(
+ IN PCIO_DESCRIPTOR IoDescriptor,
+ IN ULONG DescriptorNumber
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintIoInterruptDescriptor(
+ IN PCIO_INTERRUPT_DESCRIPTOR Descriptor
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintIoPortDescriptor(
+ IN PCIO_PORT_DESCRIPTOR Descriptor
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintIoMemoryDescriptor(
+ IN PCIO_MEMORY_DESCRIPTOR Descriptor
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintIoDmaDescriptor(
+ IN PCIO_DMA_DESCRIPTOR Descriptor
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintDataRegSz(
+ IN PCBYTE Data,
+ IN ULONG Size
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintDataRegUlong(
+ IN PCBYTE Data,
+ IN ULONG Size
+ );
+
+ NONVIRTUAL
+ VOID
+ PrintErrorDialog(
+ IN LONG ErrorCode
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintNode(
+ IN PCREGEDIT_NODE Node
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintString(
+ IN PCWSTRING String,
+ IN BOOLEAN Indent DEFAULT TRUE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintStringTruncate(
+ IN PCWSTRING String
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintSubTree(
+ IN PCREGEDIT_NODE Node
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintValue(
+ IN PCREGEDIT_FORMATTED_VALUE_ENTRY Value,
+ IN ULONG ValueNumber
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PrintValueType(
+ IN PCWSTRING ValueType
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ StartPrint(
+ IN PCWSTRING String
+ );
+
+ STATIC
+ NONVIRTUAL
+ BOOLEAN
+ EXPORT
+ AbortProc(
+ IN HDC PrinterDC,
+ IN SHORT Code
+ );
+
+
+ static BOOLEAN _UserAbort;
+ static HWND _DlgPrint;
+
+ HWND _hWnd;
+
+ PRINTDLG _pd;
+ PCWSTRING _PredefinedKey;
+
+ BOOLEAN _InitTextMetrics;
+ TEXTMETRIC _TextMetrics;
+ ULONG _TopMargin;
+ ULONG _CharacterHeight;
+ ULONG _BottomMargin;
+ ULONG _LinesPerPage;
+
+ ULONG _LeftMargin;
+ ULONG _CharacterWidth;
+ ULONG _RightMargin;
+ ULONG _CharactersPerLine;
+
+ ULONG _CurrentLine;
+ ULONG _CurrentPage;
+ PREGEDIT_INTERNAL_REGISTRY _IR;
+
+ PWSTRING _StringNodeName;
+ PWSTRING _StringClassName;
+ PWSTRING _StringTitleIndex;
+ PWSTRING _StringTitle;
+ PWSTRING _StringLastWriteTime;
+ PWSTRING _StringValue;
+ PWSTRING _StringValueName;
+ PWSTRING _StringValueTitleIndex;
+ PWSTRING _StringValueTitle;
+ PWSTRING _StringValueType;
+ PWSTRING _StringDataLength;
+ PWSTRING _StringData;
+ PWSTRING _StringTypeRegSZ;
+ PWSTRING _StringTypeRegExpandSZ;
+ PWSTRING _StringTypeRegMultiSZ;
+ PWSTRING _StringTypeRegBinary;
+ PWSTRING _StringTypeRegDWORD;
+ PWSTRING _StringTypeRegFullResourceDescriptor;
+ PWSTRING _StringTypeRegResourceList;
+ PWSTRING _StringTypeRegResourceRequirementsList;
+ PWSTRING _StringTypeRegColorRGB;
+ PWSTRING _StringTypeRegFileName;
+ PWSTRING _StringTypeRegFileTime;
+ PWSTRING _StringTypeRegUnknown;
+ PWSTRING _StringValueNoName;
+ PWSTRING _StringNodeNoClass;
+ PWSTRING _StringAllFiles;
+ PWSTRING _StringTextFiles;
+ PWSTRING _StringStarDotStar;
+ PWSTRING _StringStarDotTxt;
+ PWSTRING _StringFullDescriptor;
+ PWSTRING _StringPartialDescriptor;
+ PWSTRING _StringInterfaceType;
+ PWSTRING _StringBusNumber;
+ PWSTRING _StringVersion;
+ PWSTRING _StringRevision;
+
+ PWSTRING _StringResource;
+ PWSTRING _StringDisposition;
+ PWSTRING _StringType;
+ PWSTRING _StringStart;
+ PWSTRING _StringLength;
+ PWSTRING _StringLevel;
+ PWSTRING _StringVector;
+ PWSTRING _StringAffinity;
+ PWSTRING _StringChannel;
+ PWSTRING _StringPort;
+ PWSTRING _StringReserved1;
+ PWSTRING _StringReserved2;
+ PWSTRING _StringDevSpecificData;
+
+ PWSTRING _StringIoInterfaceType;
+ PWSTRING _StringIoBusNumber;
+ PWSTRING _StringIoSlotNumber;
+ PWSTRING _StringIoListNumber;
+ PWSTRING _StringIoOption;
+ PWSTRING _StringIoDescriptorNumber;
+ PWSTRING _StringIoAlignment;
+ PWSTRING _StringIoMinimumAddress;
+ PWSTRING _StringIoMaximumAddress;
+ PWSTRING _StringIoMinimumVector;
+ PWSTRING _StringIoMaximumVector;
+ PWSTRING _StringIoMinimumChannel;
+ PWSTRING _StringIoMaximumChannel;
+
+ DSTRING _Separator;
+ DSTRING _StringFooter;
+ DSTRING _EmptyLine;
+ DSTRING _IndentString;
+ DSTRING _DateTimeSeparator;
+
+ BOOLEAN _PrintToFile;
+ int _FileHandle;
+
+
+};
+
+
+#endif // _PRINT_MANAGER_
diff --git a/private/utils/regedit/inc/regdata.hxx b/private/utils/regedit/inc/regdata.hxx
new file mode 100644
index 000000000..b9d2072f0
--- /dev/null
+++ b/private/utils/regedit/inc/regdata.hxx
@@ -0,0 +1,346 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ regdata.hxx
+
+Abstract:
+
+ This module contains the declaration for the REGISTRY_DATA
+ class.
+ The REGISTRY_DATA class contains the methods that display
+ registry data of type REG_RESOURCE_LIST and REG_FULL_RESOURCE_DESCRIPTOR.
+
+Author:
+
+ Jaime Sasson (jaimes) 30-Nov-1993
+
+Environment:
+
+ Ulib, Regedit, Windows, User Mode
+
+--*/
+
+#if !defined( _REGISTRY_DATA_ )
+
+#define _REGISTRY_DATA_
+
+#include "ulib.hxx"
+#include "regvalue.hxx"
+#include "regfdesc.hxx"
+#include "regresls.hxx"
+#include "regdesc.hxx"
+#include "regiodsc.hxx"
+#include "regiodls.hxx"
+#include "regioreq.hxx"
+
+
+DECLARE_CLASS( REGISTRY_DATA );
+
+class REGISTRY_DATA : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( REGISTRY_DATA );
+
+ DECLARE_CAST_MEMBER_FUNCTION( REGISTRY_DATA );
+
+ NONVIRTUAL
+ STATIC
+ VOID
+ DisplayData(
+ IN HWND hWnd,
+ IN REG_TYPE Type,
+ IN PCBYTE Buffer,
+ IN ULONG Size,
+ IN BOOLEAN ForceDisplayBinary DEFAULT FALSE
+ );
+
+
+ private:
+
+ NONVIRTUAL
+ STATIC
+ BOOLEAN
+ InitializeStrings(
+ );
+
+ NONVIRTUAL
+ STATIC
+ VOID
+ DisplayResourceList(
+ IN HWND hWnd,
+ IN PCRESOURCE_LIST ResourceList
+ );
+
+ NONVIRTUAL
+ STATIC
+ VOID
+ DisplayFullResourceDescriptor(
+ IN HWND hWnd,
+ IN PCFULL_DESCRIPTOR FullResourcedescriptor
+ );
+
+ NONVIRTUAL
+ STATIC
+ VOID
+ DisplayRequirementsList(
+ IN HWND hWnd,
+ IN PCIO_REQUIREMENTS_LIST RequirementsList
+ );
+
+ NONVIRTUAL
+ STATIC
+ VOID
+ DisplayIoDescriptor(
+ IN HWND hWnd,
+ IN PCIO_DESCRIPTOR IoDescriptor
+ );
+
+ NONVIRTUAL
+ STATIC
+ VOID
+ DisplayBinaryData(
+ IN HWND hWnd,
+ IN PCBYTE Data,
+ IN ULONG DataSize,
+ IN BOOLEAN DisplayValueType DEFAULT FALSE,
+ IN ULONG ValueType DEFAULT 0
+ );
+
+ NONVIRTUAL
+ STATIC
+ BOOL
+ APIENTRY
+ DisplayResourceListDialogProc(
+ HWND hDlg,
+ DWORD Msg,
+ WPARAM wParam,
+ LONG lParam
+ );
+
+ NONVIRTUAL
+ STATIC
+ BOOL
+ APIENTRY
+ DisplayFullResourceDescriptorDialogProc(
+ HWND hDlg,
+ DWORD Msg,
+ WPARAM wParam,
+ LONG lParam
+ );
+
+ NONVIRTUAL
+ STATIC
+ BOOL
+ APIENTRY
+ DisplayRequirementsListDialogProc(
+ HWND hDlg,
+ DWORD Msg,
+ WPARAM wParam,
+ LONG lParam
+ );
+
+ NONVIRTUAL
+ STATIC
+ BOOL
+ APIENTRY
+ DisplayIoPortDialogProc(
+ HWND hDlg,
+ DWORD Msg,
+ WPARAM wParam,
+ LONG lParam
+ );
+
+ NONVIRTUAL
+ STATIC
+ BOOL
+ APIENTRY
+ DisplayIoMemoryDialogProc(
+ HWND hDlg,
+ DWORD Msg,
+ WPARAM wParam,
+ LONG lParam
+ );
+
+ NONVIRTUAL
+ STATIC
+ BOOL
+ APIENTRY
+ DisplayIoInterruptDialogProc(
+ HWND hDlg,
+ DWORD Msg,
+ WPARAM wParam,
+ LONG lParam
+ );
+
+ NONVIRTUAL
+ STATIC
+ BOOL
+ APIENTRY
+ DisplayIoDmaDialogProc(
+ HWND hDlg,
+ DWORD Msg,
+ WPARAM wParam,
+ LONG lParam
+ );
+
+ NONVIRTUAL
+ STATIC
+ BOOL
+ APIENTRY
+ DisplayBinaryDataDialogProc(
+ HWND hDlg,
+ DWORD Msg,
+ WPARAM wParam,
+ LONG lParam
+ );
+
+ NONVIRTUAL
+ STATIC
+ PVOID
+ GetSelectedItem(
+ IN HWND hDlg,
+ IN ULONG ClbId
+ );
+
+ NONVIRTUAL
+ STATIC
+ VOID
+ UpdateShareDisplay(
+ IN HWND hDlg,
+ IN PCPARTIAL_DESCRIPTOR Descriptor
+ );
+
+ NONVIRTUAL
+ STATIC
+ VOID
+ UpdateOptionDisplay(
+ IN HWND hDlg,
+ IN PCIO_DESCRIPTOR Descriptor
+ );
+
+ NONVIRTUAL
+ STATIC
+ VOID
+ DumpBinaryData(
+ IN HWND hDlg,
+ IN PCBYTE Data,
+ IN ULONG Size
+ );
+
+ NONVIRTUAL
+ STATIC
+ VOID
+ DumpBinaryDataAsWords(
+ IN HWND hDlg,
+ IN PCBYTE Data,
+ IN ULONG Size
+ );
+
+ NONVIRTUAL
+ STATIC
+ VOID
+ DumpBinaryDataAsDwords(
+ IN HWND hDlg,
+ IN PCBYTE Data,
+ IN ULONG Size
+ );
+
+
+ STATIC
+ BOOLEAN _StringsInitialized;
+
+ STATIC
+ PWSTRING _MsgBusInternal;
+
+ STATIC
+ PWSTRING _MsgBusIsa;
+
+ STATIC
+ PWSTRING _MsgBusEisa;
+
+ STATIC
+ PWSTRING _MsgBusMicroChannel;
+
+ STATIC
+ PWSTRING _MsgBusTurboChannel;
+
+ STATIC
+ PWSTRING _MsgBusPCIBus;
+
+ STATIC
+ PWSTRING _MsgBusVMEBus;
+
+ STATIC
+ PWSTRING _MsgBusNuBus;
+
+ STATIC
+ PWSTRING _MsgBusPCMCIABus;
+
+ STATIC
+ PWSTRING _MsgBusCBus;
+
+ STATIC
+ PWSTRING _MsgBusMPIBus;
+
+ STATIC
+ PWSTRING _MsgBusMPSABus;
+
+ STATIC
+ PWSTRING _MsgInvalid;
+
+ STATIC
+ PWSTRING _MsgDevPort;
+
+ STATIC
+ PWSTRING _MsgDevInterrupt;
+
+ STATIC
+ PWSTRING _MsgDevMemory;
+
+ STATIC
+ PWSTRING _MsgDevDma;
+
+#if 0
+ STATIC
+ PWSTRING _MsgDevDeviceSpecific;
+#endif
+ STATIC
+ PWSTRING _MsgIntLevelSensitive;
+
+ STATIC
+ PWSTRING _MsgIntLatched;
+
+ STATIC
+ PWSTRING _MsgMemReadWrite;
+
+ STATIC
+ PWSTRING _MsgMemReadOnly;
+
+ STATIC
+ PWSTRING _MsgMemWriteOnly;
+
+ STATIC
+ PWSTRING _MsgPortMemory;
+
+ STATIC
+ PWSTRING _MsgPortPort;
+
+ STATIC
+ PWSTRING _MsgShareUndetermined;
+
+ STATIC
+ PWSTRING _MsgShareDeviceExclusive;
+
+ STATIC
+ PWSTRING _MsgShareDriverExclusive;
+
+ STATIC
+ PWSTRING _MsgShareShared;
+
+};
+
+#endif // _REGISTRY_DATA_
diff --git a/private/utils/regedit/inc/regdesc.hxx b/private/utils/regedit/inc/regdesc.hxx
new file mode 100644
index 000000000..326b7443c
--- /dev/null
+++ b/private/utils/regedit/inc/regdesc.hxx
@@ -0,0 +1,1650 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ regdesc.hxx
+
+Abstract:
+
+ This module contains the declarations for the following base classes:
+ PARTIAL_DESCRIPTOR, PORT_DESCRIPTOR, INTERRUPT_DESCRIPTOR, MEMORY_DESCRIPTOR,
+ DMA_DESCRIPTOR and DEVICE_SPECIFIC_DESCRIPTOR. The last 5 classes are derived
+ from the first one.
+
+ These classes model a CM_PARTIAL_RESOURCE_DESCRIPTOR structure, used on registry
+ data of type REG_FULL_RESOURCE_DESCRIPTOR and REG_RESOURCE_LIST.
+
+
+Author:
+
+ Jaime Sasson (jaimes) 01-Dec-1993
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+
+#if !defined( _PARTIAL_DESCRIPTOR_ )
+
+#define _PARTIAL_DESCRIPTOR_
+
+#define _NTAPI_ULIB_
+#include "ulib.hxx"
+
+
+DECLARE_CLASS( PARTIAL_DESCRIPTOR );
+
+
+class PARTIAL_DESCRIPTOR : public OBJECT {
+
+
+ public:
+
+ VIRTUAL
+ ~PARTIAL_DESCRIPTOR(
+ );
+
+ VIRTUAL
+ UCHAR
+ GetShareDisposition(
+ ) CONST;
+
+ VIRTUAL
+ USHORT
+ GetFlags(
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ IsDescriptorTypePort(
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ IsDescriptorTypeInterrupt(
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ IsDescriptorTypeMemory(
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ IsDescriptorTypeDma(
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ IsDescriptorTypeDeviceSpecific(
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ IsResourceShareUndetermined(
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ IsResourceShareDeviceExclusive(
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ IsResourceShareDriverExclusive(
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ IsResourceShareShared(
+ ) CONST;
+
+ protected:
+
+
+ DECLARE_CONSTRUCTOR( PARTIAL_DESCRIPTOR );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN UCHAR Type,
+ IN UCHAR ShareDisposition,
+ IN USHORT Flags
+ );
+
+#if DBG
+ VIRTUAL
+ VOID
+ DbgDumpObject(
+ );
+#endif
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ UCHAR _Type;
+ UCHAR _ShareDisposition;
+ USHORT _Flags;
+};
+
+
+INLINE
+BOOLEAN
+PARTIAL_DESCRIPTOR::Initialize(
+ IN UCHAR Type,
+ IN UCHAR ShareDisposition,
+ IN USHORT Flags
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes an object of type PARTIAL_DESCRIPTOR.
+
+Arguments:
+
+ Type -
+
+ ShareDisposition -
+
+ Flags -
+
+
+Return Value:
+
+ Returns TRUE if the initialization succeeded, or FALSE otherwise.
+
+
+--*/
+
+
+{
+ _Type = Type;
+ _ShareDisposition = ShareDisposition;
+ _Flags = Flags;
+ return( TRUE );
+}
+
+
+INLINE
+UCHAR
+PARTIAL_DESCRIPTOR::GetShareDisposition(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the device descriptor's share disposition.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns the device descriptor's share disposition.
+
+
+--*/
+
+
+{
+ return( _ShareDisposition );
+}
+
+
+INLINE
+USHORT
+PARTIAL_DESCRIPTOR::GetFlags(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the device descriptor's flags.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns the device descriptor's flags.
+
+
+--*/
+
+
+{
+ return( _Flags );
+}
+
+
+INLINE
+BOOLEAN
+PARTIAL_DESCRIPTOR::IsDescriptorTypePort(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine whether or not this object represents a PORT_DESCRIPTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns TRUE if the object represents a PORT_DESCRIPTOR.
+
+
+--*/
+
+
+{
+ return( _Type == CmResourceTypePort );
+}
+
+
+INLINE
+BOOLEAN
+PARTIAL_DESCRIPTOR::IsDescriptorTypeInterrupt(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine whether or not this object represents a INTERRUPT_DESCRIPTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns TRUE if the object represents a INTERRUPT_DESCRIPTOR.
+
+
+--*/
+
+
+{
+ return( _Type == CmResourceTypeInterrupt );
+}
+
+
+INLINE
+BOOLEAN
+PARTIAL_DESCRIPTOR::IsDescriptorTypeMemory(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine whether or not this object represents a MEMORY_DESCRIPTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns TRUE if the object represents a MEMORY_DESCRIPTOR.
+
+
+--*/
+
+
+{
+ return( _Type == CmResourceTypeMemory );
+}
+
+
+INLINE
+BOOLEAN
+PARTIAL_DESCRIPTOR::IsDescriptorTypeDma(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine whether or not this object represents a DMA_DESCRIPTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns TRUE if the object represents a DMA_DESCRIPTOR.
+
+
+--*/
+
+
+{
+ return( _Type == CmResourceTypeDma );
+}
+
+
+INLINE
+BOOLEAN
+PARTIAL_DESCRIPTOR::IsDescriptorTypeDeviceSpecific(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine whether or not this object represents a DEVICE_SPECIFIC_DESCRIPTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns TRUE if the object represents a DEVICE_SPECIFIC_DESCRIPTOR.
+
+
+--*/
+
+
+{
+ return( _Type == CmResourceTypeDeviceSpecific );
+}
+
+
+INLINE
+BOOLEAN
+PARTIAL_DESCRIPTOR::IsResourceShareUndetermined(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine whether or not the share of the device represented by this object
+ is undetermined.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns TRUE if the share is undetermined.
+
+
+--*/
+
+
+{
+ return( _ShareDisposition == CmResourceShareUndetermined );
+}
+
+
+INLINE
+BOOLEAN
+PARTIAL_DESCRIPTOR::IsResourceShareDeviceExclusive(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine whether or not the share of the device represented by this object
+ is device exclusive.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns TRUE if the share is device exclusive.
+
+
+--*/
+
+
+{
+ return( _ShareDisposition == CmResourceShareDeviceExclusive );
+}
+
+
+INLINE
+BOOLEAN
+PARTIAL_DESCRIPTOR::IsResourceShareDriverExclusive(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine whether or not the share of the device represented by this object
+ is driver exclusive.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns TRUE if the share is driver exclusive.
+
+
+--*/
+
+
+{
+ return( _ShareDisposition == CmResourceShareDriverExclusive );
+}
+
+
+INLINE
+BOOLEAN
+PARTIAL_DESCRIPTOR::IsResourceShareShared(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine whether or not the share of the device represented by this object
+ is shared.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns TRUE if the share is shared.
+
+
+--*/
+
+
+{
+ return( _ShareDisposition == CmResourceShareShared );
+}
+
+// #endif // _PARTIAL_DESCRIPTOR_
+
+
+
+// #if !defined( _PORT_DESCRIPTOR_ )
+
+// #define _PORT_DESCRIPTOR_
+
+// #define _NTAPI_ULIB_
+// #include "ulib.hxx"
+
+
+DECLARE_CLASS( PORT_DESCRIPTOR );
+
+
+class PORT_DESCRIPTOR : public PARTIAL_DESCRIPTOR {
+
+ public:
+
+ NONVIRTUAL
+ ~PORT_DESCRIPTOR(
+ );
+
+ DECLARE_CONSTRUCTOR( PORT_DESCRIPTOR );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PPHYSICAL_ADDRESS PhysicalAddress,
+ IN ULONG Length,
+ IN UCHAR ShareDisposition,
+ IN USHORT Flags
+ );
+
+ NONVIRTUAL
+ PPHYSICAL_ADDRESS
+ GetPhysicalAddress(
+ ); // CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetLength(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsPortIo(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsPortMemory(
+ ) CONST;
+
+
+#if DBG
+ VIRTUAL
+ VOID
+ DbgDumpObject(
+ );
+#endif
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ PHYSICAL_ADDRESS _PhysicalAddress;
+ ULONG _Length;
+};
+
+
+
+INLINE
+BOOLEAN
+PORT_DESCRIPTOR::Initialize(
+ IN PPHYSICAL_ADDRESS PhysicalAddress,
+ IN ULONG Length,
+ IN UCHAR ShareDisposition,
+ IN USHORT Flags
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize a PORT_DESCRIPTOR object.
+
+Arguments:
+
+ PhysicalAddress -
+
+ Length -
+
+ ShareDisposition -
+
+ Flags -
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeeds.
+
+--*/
+
+
+{
+ _PhysicalAddress = *PhysicalAddress;
+ _Length = Length;
+ return( PARTIAL_DESCRIPTOR::Initialize( CmResourceTypePort,
+ ShareDisposition,
+ Flags ) );
+}
+
+
+INLINE
+PPHYSICAL_ADDRESS
+PORT_DESCRIPTOR::GetPhysicalAddress(
+ ) // CONST
+
+/*++
+
+Routine Description:
+
+ Returns the port's physical address.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PPHYSICAL_ADDRESS - Pointer to the structure that describes the port's
+ physical address.
+
+
+--*/
+
+
+{
+ return( &_PhysicalAddress );
+}
+
+
+INLINE
+ULONG
+PORT_DESCRIPTOR::GetLength(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the port's length.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - Return the port's length.
+
+--*/
+
+
+{
+ return( _Length );
+}
+
+
+INLINE
+BOOLEAN
+PORT_DESCRIPTOR::IsPortIo(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return whether or not the port is an I/O.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the port is an I/O.
+ Returns FALSE otherwise.
+
+--*/
+
+
+{
+ return( ( PARTIAL_DESCRIPTOR::GetFlags() & CM_RESOURCE_PORT_IO ) ==
+ CM_RESOURCE_PORT_IO );
+}
+
+
+INLINE
+BOOLEAN
+PORT_DESCRIPTOR::IsPortMemory(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return whether or not the port is mapped in memory.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the port is mapped in memory.
+ Returns FALSE otherwise.
+
+--*/
+
+
+{
+ return( PARTIAL_DESCRIPTOR::GetFlags() == CM_RESOURCE_PORT_MEMORY );
+}
+
+
+// #endif // _PORT_DESCRIPTOR_
+
+// #if !defined( _INTERRUPT_DESCRIPTOR_ )
+
+// #define _INTERRUPT_DESCRIPTOR_
+
+// #define _NTAPI_ULIB_
+// #include "ulib.hxx"
+
+
+DECLARE_CLASS( INTERRUPT_DESCRIPTOR );
+
+
+class INTERRUPT_DESCRIPTOR : public PARTIAL_DESCRIPTOR {
+
+ public:
+
+ NONVIRTUAL
+ ~INTERRUPT_DESCRIPTOR(
+ );
+
+ DECLARE_CONSTRUCTOR( INTERRUPT_DESCRIPTOR );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN ULONG Affinity,
+ IN ULONG Level,
+ IN ULONG Vector,
+ IN UCHAR ShareDisposition,
+ IN USHORT Flags
+ );
+
+ NONVIRTUAL
+ ULONG
+ GetAffinity(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetLevel(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetVector(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsInterruptLevelSensitive(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsInterruptLatched(
+ ) CONST;
+
+
+#if DBG
+ VIRTUAL
+ VOID
+ DbgDumpObject(
+ );
+#endif
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ ULONG _Affinity;
+ ULONG _Level;
+ ULONG _Vector;
+};
+
+
+INLINE
+BOOLEAN
+INTERRUPT_DESCRIPTOR::Initialize(
+ IN ULONG Affinity,
+ IN ULONG Level,
+ IN ULONG Vector,
+ IN UCHAR ShareDisposition,
+ IN USHORT Flags
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize an INTERRUPT_DESCRIPTOR object.
+
+Arguments:
+
+ Affinity -
+
+ Level -
+
+ Vector -
+
+ ShareDisposition -
+
+ Flags -
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeeds.
+
+--*/
+
+
+{
+ _Affinity = Affinity;
+ _Level = Level;
+ _Vector = Vector;
+ return( PARTIAL_DESCRIPTOR::Initialize( CmResourceTypeInterrupt,
+ ShareDisposition,
+ Flags ) );
+}
+
+
+INLINE
+ULONG
+INTERRUPT_DESCRIPTOR::GetAffinity(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the interrupt's affinity.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - Interrupt's affinity.
+
+
+--*/
+
+
+{
+ return( _Affinity );
+}
+
+
+INLINE
+ULONG
+INTERRUPT_DESCRIPTOR::GetLevel(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the interrupt's level.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - Return the interrupt's level.
+
+--*/
+
+
+{
+ return( _Level );
+}
+
+
+INLINE
+ULONG
+INTERRUPT_DESCRIPTOR::GetVector(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the interrupt's vector.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - Return the interrupt's vector.
+
+--*/
+
+
+{
+ return( _Vector );
+}
+
+
+INLINE
+BOOLEAN
+INTERRUPT_DESCRIPTOR::IsInterruptLevelSensitive(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return whether or not the interrupt is level sensitive.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Return TRUE if the interrupt is level sensitive.
+
+--*/
+
+
+{
+ return( PARTIAL_DESCRIPTOR::GetFlags() == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE );
+}
+
+
+INLINE
+BOOLEAN
+INTERRUPT_DESCRIPTOR::IsInterruptLatched(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return whether or not the interrupt is latched.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Return TRUE if the interrupt is latched.
+
+--*/
+
+
+{
+ return( ( PARTIAL_DESCRIPTOR::GetFlags() & CM_RESOURCE_INTERRUPT_LATCHED ) ==
+ CM_RESOURCE_INTERRUPT_LATCHED );
+}
+
+
+// #endif // _INTERRUPT_DESCRIPTOR_
+
+// #if !defined( _MEMORY_DESCRIPTOR_ )
+
+// #define _MEMORY_DESCRIPTOR_
+
+// #define _NTAPI_ULIB_
+// #include "ulib.hxx"
+
+DECLARE_CLASS( MEMORY_DESCRIPTOR );
+
+
+class MEMORY_DESCRIPTOR : public PARTIAL_DESCRIPTOR {
+
+ public:
+
+ NONVIRTUAL
+ ~MEMORY_DESCRIPTOR(
+ );
+
+ DECLARE_CONSTRUCTOR( MEMORY_DESCRIPTOR );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PPHYSICAL_ADDRESS StartAddress,
+ IN ULONG Length,
+ IN UCHAR ShareDisposition,
+ IN USHORT Flags
+ );
+
+ NONVIRTUAL
+ PPHYSICAL_ADDRESS
+ GetStartAddress(
+ ); // CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetLength(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsMemoryReadWrite(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsMemoryReadOnly(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsMemoryWriteOnly(
+ ) CONST;
+
+#if DBG
+ VIRTUAL
+ VOID
+ DbgDumpObject(
+ );
+#endif
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ PHYSICAL_ADDRESS _StartAddress;
+ ULONG _Length;
+};
+
+
+INLINE
+BOOLEAN
+MEMORY_DESCRIPTOR::Initialize(
+ IN PPHYSICAL_ADDRESS StartAddress,
+ IN ULONG Length,
+ IN UCHAR ShareDisposition,
+ IN USHORT Flags
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize a MEMORY_DESCRIPTOR object.
+
+Arguments:
+
+ StartAddress -
+
+ Length -
+
+ ShareDisposition -
+
+ Flags -
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeeds.
+
+--*/
+
+
+{
+ _StartAddress = *StartAddress;
+ _Length = Length;
+ return( PARTIAL_DESCRIPTOR::Initialize( CmResourceTypeMemory,
+ ShareDisposition,
+ Flags ) );
+}
+
+
+INLINE
+PPHYSICAL_ADDRESS
+MEMORY_DESCRIPTOR::GetStartAddress(
+ ) // CONST
+
+/*++
+
+Routine Description:
+
+ Returns the memory's start address.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - Memory's start address.
+
+
+--*/
+
+
+{
+ return( &_StartAddress );
+}
+
+
+INLINE
+ULONG
+MEMORY_DESCRIPTOR::GetLength(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the memory's length.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - Return the memory's length.
+
+--*/
+
+
+{
+ return( _Length );
+}
+
+
+INLINE
+BOOLEAN
+MEMORY_DESCRIPTOR::IsMemoryReadWrite(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return whether or not the memory is Read/Write.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Return TRUE if the memory is Read/Write.
+
+--*/
+
+
+{
+ return( PARTIAL_DESCRIPTOR::GetFlags() == CM_RESOURCE_MEMORY_READ_WRITE );
+}
+
+
+INLINE
+BOOLEAN
+MEMORY_DESCRIPTOR::IsMemoryReadOnly(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return whether or not the memory is ReadOnly.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Return TRUE if the memory is ReadOnly.
+
+--*/
+
+
+{
+ return( ( PARTIAL_DESCRIPTOR::GetFlags() & CM_RESOURCE_MEMORY_READ_ONLY ) ==
+ CM_RESOURCE_MEMORY_READ_ONLY );
+}
+
+
+INLINE
+BOOLEAN
+MEMORY_DESCRIPTOR::IsMemoryWriteOnly(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return whether or not the memory is WriteOnly.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Return TRUE if the memory is WriteOnly.
+
+--*/
+
+
+{
+ return( ( PARTIAL_DESCRIPTOR::GetFlags() & CM_RESOURCE_MEMORY_WRITE_ONLY ) ==
+ CM_RESOURCE_MEMORY_WRITE_ONLY );
+}
+
+
+// #endif // _MEMORY_DESCRIPTOR_
+
+// #if !defined( _DMA_DESCRIPTOR_ )
+
+// #define _DMA_DESCRIPTOR_
+
+// #define _NTAPI_ULIB_
+// #include "ulib.hxx"
+
+
+DECLARE_CLASS( DMA_DESCRIPTOR );
+
+
+class DMA_DESCRIPTOR : public PARTIAL_DESCRIPTOR {
+
+ public:
+
+ NONVIRTUAL
+ ~DMA_DESCRIPTOR(
+ );
+
+ DECLARE_CONSTRUCTOR( DMA_DESCRIPTOR );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN ULONG Channel,
+ IN ULONG Port,
+ IN ULONG Reserved1,
+ IN UCHAR ShareDisposition,
+ IN USHORT Flags
+ );
+
+ NONVIRTUAL
+ ULONG
+ GetChannel(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetPort(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetReserved(
+ ) CONST;
+
+#if DBG
+ VIRTUAL
+ VOID
+ DbgDumpObject(
+ );
+#endif
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ ULONG _Channel;
+ ULONG _Port;
+ ULONG _Reserved1;
+};
+
+
+INLINE
+BOOLEAN
+DMA_DESCRIPTOR::Initialize(
+ IN ULONG Channel,
+ IN ULONG Port,
+ IN ULONG Reserved1,
+ IN UCHAR ShareDisposition,
+ IN USHORT Flags
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize a DMA_DESCRIPTOR object.
+
+Arguments:
+
+ Channel -
+
+ Port -
+
+ Reserved1 -
+
+ ShareDisposition -
+
+ Flags -
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeeds.
+
+--*/
+
+
+{
+ _Channel = Channel;
+ _Port = Port;
+ _Reserved1 = Reserved1;
+ return( PARTIAL_DESCRIPTOR::Initialize( CmResourceTypeDma,
+ ShareDisposition,
+ Flags ) );
+}
+
+
+INLINE
+ULONG
+DMA_DESCRIPTOR::GetChannel(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the DMA's channel.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - DMA's channel.
+
+
+--*/
+
+
+{
+ return( _Channel );
+}
+
+
+INLINE
+ULONG
+DMA_DESCRIPTOR::GetPort(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the DMA's port.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - Return the DMA's length.
+
+--*/
+
+
+{
+ return( _Port );
+}
+
+
+INLINE
+ULONG
+DMA_DESCRIPTOR::GetReserved(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the DMA's reserved data.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - Return the DMA's reserved data.
+
+--*/
+
+
+{
+ return( _Reserved1 );
+}
+
+// #endif // _DMA_DESCRIPTOR_
+
+
+// #if !defined( _DEVICE_SPECIFIC_DESCRIPTOR_ )
+
+// #define _DEVICE_SPECIFIC_DESCRIPTOR_
+
+// #define _NTAPI_ULIB_
+// #include "ulib.hxx"
+
+
+DECLARE_CLASS( DEVICE_SPECIFIC_DESCRIPTOR );
+
+
+class DEVICE_SPECIFIC_DESCRIPTOR : public PARTIAL_DESCRIPTOR {
+
+ public:
+
+ NONVIRTUAL
+ ~DEVICE_SPECIFIC_DESCRIPTOR(
+ );
+
+ DECLARE_CONSTRUCTOR( DEVICE_SPECIFIC_DESCRIPTOR );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN ULONG Reserved1,
+ IN ULONG Reserved2,
+ IN ULONG DataSize,
+ IN PCBYTE Data,
+ IN UCHAR ShareDisposition,
+ IN USHORT Flags
+ );
+
+ NONVIRTUAL
+ ULONG
+ GetReserved1(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetReserved2(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetData(
+ IN OUT PCBYTE* Pointer
+ ) CONST;
+
+
+
+#if DBG
+ VIRTUAL
+ VOID
+ DbgDumpObject(
+ );
+#endif
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ ULONG _Reserved1;
+ ULONG _Reserved2;
+ PBYTE _Data;
+ ULONG _DataSize;
+};
+
+
+INLINE
+BOOLEAN
+DEVICE_SPECIFIC_DESCRIPTOR::Initialize(
+ IN ULONG Reserved1,
+ IN ULONG Reserved2,
+ IN ULONG DataSize,
+ IN PCBYTE Data,
+ IN UCHAR ShareDisposition,
+ IN USHORT Flags
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize a DEVICE_SPECIFIC_DESCRIPTOR object.
+
+Arguments:
+
+ Reserved1 -
+
+ Reserved2 -
+
+ Size -
+
+ Data -
+
+ ShareDisposition -
+
+ Flags -
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeeds.
+
+--*/
+
+
+{
+ _Reserved1 = Reserved1;
+ _Reserved2 = Reserved2;
+ _DataSize = DataSize;
+ if( Data != NULL ) {
+ _Data = ( PBYTE )MALLOC( _DataSize );
+ if( _Data == NULL ) {
+ return( FALSE );
+ }
+ memcpy( _Data, Data, _DataSize );
+ }
+ return( PARTIAL_DESCRIPTOR::Initialize( CmResourceTypeDeviceSpecific,
+ ShareDisposition,
+ Flags ) );
+}
+
+
+INLINE
+ULONG
+DEVICE_SPECIFIC_DESCRIPTOR::GetReserved1(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the first reserved device specific data.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - First reserved device specific data.
+
+
+--*/
+
+
+{
+ return( _Reserved1 );
+}
+
+
+INLINE
+ULONG
+DEVICE_SPECIFIC_DESCRIPTOR::GetReserved2(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the second reserved device specific data.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - Second reserved device specific data.
+
+
+--*/
+
+
+{
+ return( _Reserved2 );
+}
+
+
+INLINE
+ULONG
+DEVICE_SPECIFIC_DESCRIPTOR::GetData(
+ IN OUT PCBYTE* Pointer
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the device specific data.
+
+Arguments:
+
+ Pointer - Address of the variable that will contain the pointer to
+ the device specific data.
+
+Return Value:
+
+ ULONG - Return the number of bytes in the buffer.
+
+--*/
+
+
+{
+ if( Pointer != NULL ) {
+ *Pointer = _Data;
+ return( _DataSize );
+ } else {
+ return( 0 );
+ }
+}
+
+
+// #endif // _DEVICE_SPECIFIC_DESCRIPTOR_
+
+
+#endif // _PARTIAL_DESCRIPTOR_
diff --git a/private/utils/regedit/inc/regedhlp.h b/private/utils/regedit/inc/regedhlp.h
new file mode 100644
index 000000000..f31c07c25
--- /dev/null
+++ b/private/utils/regedit/inc/regedhlp.h
@@ -0,0 +1,91 @@
+/* Help IDs for Regedit.exe. 7/30/92. */
+/* Prepared by Steve Nason; NTUE */
+
+/* Help IDs for menu items */
+
+#define IDH_MENU_OPEN_REGED 8000
+#define IDH_MENU_CLOSE_REGED 8001
+#define IDH_MENU_SAVESUB_REGED 8002
+#define IDH_MENU_SAVEBIN_REGED 8003
+#define IDH_MENU_SELECT_REGED 8004
+#define IDH_MENU_PRINT_REGED 8005
+#define IDH_MENU_SETUP_REGED 8006
+#define IDH_MENU_FINDKEY_REGED 8007
+#define IDH_MENU_EXIT 8008
+#define IDH_MENU_ADDKEY_REGED 8009
+#define IDH_MENU_ADDVALUE_REGED 8010
+#define IDH_MENU_DELETE_REGED 8011
+#define IDH_MENU_BINARY_REGED 8012
+#define IDH_MENU_STRING_REGED 8013
+#define IDH_MENU_DWORD_REGED 8014
+#define IDH_MENU_MULTI_REGED 8015
+#define IDH_MENU_EXPANDONE_REGED 8016
+#define IDH_MENU_EXPANDBR_REGED 8017
+#define IDH_MENU_EXPANDALL_REGED 8018
+#define IDH_MENU_COLLAPSE_REGED 8019
+#define IDH_MENU_TREEDATA_REGED 8020
+#define IDH_MENU_TREE_REGED 8021
+#define IDH_MENU_DATA_REGED 8022
+#define IDH_MENU_SPLIT_REGED 8044
+#define IDH_MENU_DISPLAY_REGED 8023
+#define IDH_MENU_REFRESHALL_REGED 8024
+#define IDH_MENU_REFRESH_REGED 8025
+#define IDH_MENU_PERMISSION_REGED 8026
+#define IDH_MENU_AUDIT_REGED 8027
+#define IDH_MENU_OWNER_REGED 8028
+#define IDH_MENU_FONT_REGED 8029
+#define IDH_MENU_AUTO_REGED 8030
+#define IDH_MENU_READONLY_REGED 8031
+
+#define IDH_MENU_CONFIRM_REGED 8033
+#define IDH_MENU_SAVEXIT_REGED 8034
+#define IDH_SYSMENU 8035 /*system menu maps all items to one command*/
+#define IDH_HELPINDEX 8036 /*HELP MENU FOR CONTENTS*/
+#define IDH_KEYS 8037 /*HELP MENU FOR SEARCH FOR HELP ON...*/
+#define IDH_HELPHELP 8038 /*HELP MENU FOR HOW TO USE HELP */
+#define IDH_ABOUT 8039 /* HELP MENU FOR ABOUT... */
+#define IDH_MENU_CASCADE_REGED 8040
+#define IDH_MENU_TILE_REGED 8041
+#define IDH_MENU_ARRANGE_REGED 8042
+#define IDH_MENU_MORE_REGED 8043 /*HELP FOR LIST OF OPEN WINDOWS*/
+
+#define IDH_MENU_LOADHIVE_REGED 8045
+#define IDH_MENU_UNLOADHIVE_REGED 8046
+#define IDH_MENU_RESTORE_KEY_REGED 8047
+#define IDH_MENU_SAVE_KEY_REGED 8048
+#define IDH_MENU_RESTORE_VOLATILE_REGED 8049
+
+
+/*Help IDs for Regedit dialog boxes*/
+
+#define IDH_DB_SAVESUB_REGED 8100
+#define IDH_DB_SAVEBIN_REGED 8101
+#define IDH_DB_SELECT_REGED 8102
+#define IDH_DB_SETUP_REGED 8103
+#define IDH_DB_FINDKEY_REGED 8104
+#define IDH_DB_ADDKEY_REGED 8105
+#define IDH_DB_ADDVALUE_REGED 8106
+#define IDH_DB_BINARY_REGED 8107
+#define IDH_DB_STRING_REGED 8108
+#define IDH_DB_DWORD_REGED 8109
+#define IDH_DB_MULTI_REGED 8110
+#define IDH_DB_PERMISSION_REGED 8111
+#define IDH_DB_PERMADD_REGED 8112
+#define IDH_DB_AUDIT_REGED 8113
+#define IDH_DB_OWNER_REGED 8114
+#define IDH_DB_FONT_REGED 8115
+#define IDH_DB_PERMSPECIAL_REGED 8116
+#define IDH_DB_AUDITADD_REGED 8117
+
+#define IDH_DB_LOADHIVE_REGED 8119
+#define IDH_DB_SAVEKEY_REGED 8120
+#define IDH_DB_RESTOREKEY_REGED 8121
+
+
+
+#define IDH_DB_PERMMEMBERS_REGED 8125
+#define IDH_DB_PERMSEARCH_REGED 8126
+#define IDH_DB_AUDITMEMBERS_REGED 8127
+#define IDH_DB_AUDITSEARCH_REGED 8128
+#define IDH_DB_RESTOREVOLATILE_REGED 8129
+#define IDH_DB_LOADHIVE_KEYNAME_REGED 8130
diff --git a/private/utils/regedit/inc/regedir.hxx b/private/utils/regedit/inc/regedir.hxx
new file mode 100644
index 000000000..fc5ac88f4
--- /dev/null
+++ b/private/utils/regedit/inc/regedir.hxx
@@ -0,0 +1,1445 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ regedir.hxx
+
+Abstract:
+
+ This module contains the declarations for the REGEDIT_INTERNAL_REGISTRY
+ class.
+ The REGEDIT_INTERNAL_REGISTRY class manages the structure that represents
+ a sub tree of a real registry whose root is a predefined key.
+ It provides methods that allow clients to add, delete and change information
+ in a registry key.
+
+
+Author:
+
+ Jaime Sasson (jaimes) 01-Mar-1992
+
+
+Environment:
+
+ Regedit, Ulib, User Mode
+
+
+--*/
+
+
+#if !defined( _REGEDIT_INTERNAL_REGISTRY_ )
+
+#define _REGEDIT_INTERNAL_REGISTRY_
+
+
+#include "ulib.hxx"
+#include "array.hxx"
+#include "regednod.hxx"
+#include "regedval.hxx"
+#include "registry.hxx"
+
+
+//
+// The enumeration below contains the error codes that the methods in
+// the REGEDIT_INTERNAL_REGISTRY_CLASS class can return
+//
+
+
+typedef enum _REGEDIT_ERROR {
+ REGEDIT_ERROR_ACCESS_DENIED,
+ REGEDIT_ERROR_CANT_READ_OR_WRITE,
+ REGEDIT_ERROR_INITIALIZATION_FAILURE,
+ REGEDIT_ERROR_NODE_DOESNT_EXIST,
+ REGEDIT_ERROR_VALUE_EXISTS,
+ REGEDIT_ERROR_VALUE_DOESNT_EXIST,
+ REGEDIT_ERROR_NODE_NOT_UPDATED,
+ REGEDIT_ERROR_UNKNOWN_ERROR,
+ REGEDIT_ERROR_PRIVILEGE_NOT_HELD,
+ REGEDIT_RPC_S_SERVER_UNAVAILABLE,
+ REGEDIT_ERROR_KEY_DELETED,
+ REGEDIT_ERROR_BADDB,
+ REGEDIT_ERROR_NODE_NOT_FOUND,
+ REGEDIT_ERROR_CHILD_MUST_BE_VOLATILE
+ } REGEDIT_ERROR;
+
+
+
+DECLARE_CLASS( REGEDIT_INTERNAL_REGISTRY );
+
+
+class REGEDIT_INTERNAL_REGISTRY : public OBJECT {
+
+
+ public:
+
+ DECLARE_CONSTRUCTOR( REGEDIT_INTERNAL_REGISTRY );
+
+ DECLARE_CAST_MEMBER_FUNCTION( REGEDIT_INTERNAL_REGISTRY );
+
+ VIRTUAL
+ ~REGEDIT_INTERNAL_REGISTRY(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PREGISTRY Registry,
+ IN PCWSTRING RootName
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AddValue(
+ IN PCREGEDIT_NODE Node,
+ IN PREGEDIT_FORMATTED_VALUE_ENTRY Value,
+ IN BOOLEAN FailIfExists,
+ OUT PULONG ErrorCode
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AreHiveOperationsAllowed(
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ ChangeValueData(
+ IN PCREGEDIT_NODE Node,
+ IN PCREGEDIT_FORMATTED_VALUE_ENTRY Value,
+ IN PCBYTE NewData,
+ IN ULONG Size,
+ OUT PULONG ErrorCode
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AreChildrenInMemory(
+ IN PCREGEDIT_NODE Node
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ AreValuesInMemory(
+ IN PCREGEDIT_NODE Node
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ CreateChildNode(
+ IN PCREGEDIT_NODE ParentNode,
+ IN PREGISTRY_KEY_INFO ChildKeyInfo,
+ OUT PCREGEDIT_NODE* ChildNode,
+ OUT PULONG ErrorCode,
+ IN BOOLEAN Volatile DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DeleteNode(
+ IN PREGEDIT_NODE Node,
+ OUT PULONG ErrorCode
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DeleteValue(
+ IN PCREGEDIT_NODE Node,
+ IN PREGEDIT_FORMATTED_VALUE_ENTRY Value,
+ OUT PULONG ErrorCode
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DoesChildNodeExist(
+ IN PCREGEDIT_NODE Node,
+ IN PCWSTRING ChildName,
+ OUT PULONG ErrorCode
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DoesValueExist(
+ IN PCREGEDIT_NODE Node,
+ IN PCREGEDIT_FORMATTED_VALUE_ENTRY Value,
+ OUT PULONG ErrorCode
+ );
+
+ NONVIRTUAL
+ PCREGEDIT_NODE
+ FindNode(
+ IN PCWSTRING NodeName,
+ IN PCREGEDIT_NODE StartNode,
+ IN BOOLEAN FindNext,
+ IN BOOLEAN MatchCase,
+ IN BOOLEAN WholeWord
+ );
+
+ NONVIRTUAL
+ PSORTED_LIST
+ GetChildren(
+ IN PCREGEDIT_NODE Node,
+ OUT PULONG ErrorCode
+ );
+
+ NONVIRTUAL
+ PCREGEDIT_NODE
+ GetNextNode(
+ IN PCREGEDIT_NODE CurrentNode,
+ IN PCREGEDIT_NODE LastTraversedNode
+ );
+
+ NONVIRTUAL
+ PCWSTRING
+ GetMachineName(
+ ) CONST;
+
+ NONVIRTUAL
+ PCWSTRING
+ GetNodeClass(
+ IN PCREGEDIT_NODE Node
+ ) CONST;
+
+ NONVIRTUAL
+ PCTIMEINFO
+ GetNodeLastWriteTime(
+ IN PCREGEDIT_NODE Node
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetNodeLevel(
+ IN PCREGEDIT_NODE Node
+ ) CONST;
+
+ NONVIRTUAL
+ PCWSTRING
+ GetNodeName(
+ IN PCREGEDIT_NODE Node
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetNodeTitleIndex(
+ IN PCREGEDIT_NODE Node
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetNumberOfChildren(
+ IN PCREGEDIT_NODE Node
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetNumberOfValues(
+ IN PCREGEDIT_NODE Node
+ ) CONST;
+
+ NONVIRTUAL
+ PCREGEDIT_NODE
+ GetParent(
+ IN PCREGEDIT_NODE Node
+ ) CONST;
+
+ NONVIRTUAL
+ PCWSTRING
+ GetParentName(
+ IN PCREGEDIT_NODE Node
+ ) CONST;
+
+ NONVIRTUAL
+ PREDEFINED_KEY
+ GetPredefinedKey(
+ ) CONST;
+
+ NONVIRTUAL
+ PCREGEDIT_NODE
+ GetPreviousNode(
+ IN PCREGEDIT_NODE CurrentNode,
+ IN PCREGEDIT_NODE LastTraversedNode
+ );
+
+ NONVIRTUAL
+ PCWSTRING
+ GetRootName(
+ ) CONST;
+
+ NONVIRTUAL
+ PCREGEDIT_NODE
+ GetRootNode(
+ ) CONST;
+
+ NONVIRTUAL
+ PSORTED_LIST
+ GetValues(
+ IN PCREGEDIT_NODE Node,
+ OUT PULONG ErrorCode
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsFirstChild(
+ IN PCREGEDIT_NODE Node
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsLastChild(
+ IN PCREGEDIT_NODE Node
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsMasterHive(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsNodeExpanded(
+ IN PCREGEDIT_NODE Node
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsNodeViewable(
+ IN PCREGEDIT_NODE Node
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsRemoteRegistry(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ LoadHive(
+ IN PCREGEDIT_NODE ParentNode,
+ IN PREGISTRY_KEY_INFO HiveInfo,
+ IN PCWSTRING FileName,
+ OUT PCREGEDIT_NODE* HiveNode,
+ OUT PULONG ErrorCode
+ );
+
+/*
+ NONVIRTUAL
+ BOOLEAN
+ ReleaseNode(
+ IN PCREGEDIT_NODE Node
+ );
+*/
+ NONVIRTUAL
+ BOOLEAN
+ QueryCompleteNodeName(
+ IN PCREGEDIT_NODE Node,
+ OUT PWSTRING CompleteName
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryNodeSecurity(
+ IN PCREGEDIT_NODE Node,
+ IN SECURITY_INFORMATION SecurityInformation,
+ OUT PSECURITY_DESCRIPTOR* SecurityDescriptor,
+ OUT PULONG ErrorCode
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetNodeSecurity(
+ IN PCREGEDIT_NODE Node,
+ IN SECURITY_INFORMATION SecurityInformation,
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ OUT PULONG ErrorCode,
+ IN BOOLEAN Recurse
+ );
+
+ NONVIRTUAL
+ VOID
+ SetNodeExpansionState(
+ IN PCREGEDIT_NODE Node,
+ IN BOOLEAN NewState
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ UnloadChildren(
+ IN PCREGEDIT_NODE Node
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ UnloadValues(
+ IN PCREGEDIT_NODE Node
+ );
+
+ NONVIRTUAL
+ VOID
+ UpdateSubTree(
+ IN PREGEDIT_NODE Node
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ UnLoadHive(
+ IN PREGEDIT_NODE Node,
+ OUT PULONG ErrorCode
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SaveKeyToFile(
+ IN PCREGEDIT_NODE Node,
+ IN PCWSTRING FileName,
+ OUT PULONG ErrorCode
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ RestoreKeyFromFile(
+ IN PCREGEDIT_NODE Node,
+ IN PCWSTRING FileName,
+ IN BOOLEAN Volatile,
+ OUT PULONG ErrorCode
+ );
+
+
+
+
+/*
+ NONVIRTUAL
+ BOOLEAN
+ DidRootChange(
+ // IN PREDEFINED_KEY PredefinedKey
+ );
+*/
+ NONVIRTUAL
+ BOOLEAN
+ EnableRootNotification(
+ // IN PREDEFINED_KEY PredefinedKey,
+ IN HANDLE Event,
+ IN DWORD Filter,
+ IN BOOLEAN WatchTree DEFAULT TRUE
+// IN PVOID CallBackFunction DEFAULT NULL
+ );
+
+
+
+ NONVIRTUAL
+ BOOLEAN
+ IsAccessAllowed(
+ IN PCREGEDIT_NODE Node,
+ IN REGSAM SamDesired,
+ OUT PULONG ErrorCode
+ );
+
+
+
+
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ PREGISTRY_KEY_INFO
+ GetNodeKeyInfo(
+ IN PCREGEDIT_NODE Node
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsKeyInListOfChildren(
+ IN PCWSTRING KeyName,
+ IN PSORTED_LIST Children
+ );
+
+ NONVIRTUAL
+ ULONG
+ MapRegistryToRegeditError(
+ IN DWORD ErrorCode
+ ) CONST;
+
+
+
+ PREDEFINED_KEY _PredefinedKey;
+ PREGISTRY _Registry;
+ DSTRING _RootName;
+ REGEDIT_NODE _RootNode;
+
+
+};
+
+
+INLINE
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::AreChildrenInMemory(
+ IN PCREGEDIT_NODE Node
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Inform the caller whether the children of the specified node are
+ loaded in memory.
+
+
+Arguments:
+
+ Node - Pointer to REGEDIT_NODE object.
+
+
+Return Value:
+
+
+ BOOLEAN - Returns TRUE if the children are in memory, or FALSE otherwise.
+
+--*/
+
+{
+ DebugPtrAssert( Node );
+ return( Node->AreChildrenInMemory() );
+}
+
+
+
+INLINE
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::AreValuesInMemory(
+ IN PCREGEDIT_NODE Node
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Inform the caller whether the values of the specified node are
+ loaded in memory.
+
+
+Arguments:
+
+ Node - Pointer to REGEDIT_NODE object.
+
+
+Return Value:
+
+
+ BOOLEAN - Returns TRUE if the children are in memory, or FALSE otherwise.
+
+--*/
+
+{
+ DebugPtrAssert( Node );
+ return( Node->AreValuesInMemory() );
+}
+
+
+
+
+
+INLINE
+PCWSTRING
+REGEDIT_INTERNAL_REGISTRY::GetMachineName(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return to the client the name of the machine associated to the
+ registry represented by this object.
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+
+ PCWSTRING - The machine name.
+
+--*/
+
+{
+ DebugPtrAssert( _Registry );
+ return( _Registry->GetMachineName() );
+}
+
+
+
+INLINE
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::IsRemoteRegistry(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Inform to the client whether the registry represented by this object is on the remote machine.
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+
+ BOOLEAN - Returns TRUE if it is a registry on a remote machine. Otherwise, returns FALSE.
+
+--*/
+
+{
+ DebugPtrAssert( _Registry );
+ return( _Registry->IsRemoteRegistry() );
+}
+
+
+
+
+
+INLINE
+PCWSTRING
+REGEDIT_INTERNAL_REGISTRY::GetNodeClass(
+ IN PCREGEDIT_NODE Node
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return to the client the class of the node passed as argument.
+
+
+Arguments:
+
+ Node - Pointer to REGEDIT_NODE object.
+
+
+Return Value:
+
+
+ PCWSTRING - The node class.
+
+--*/
+
+{
+ DebugPtrAssert( Node );
+ return( Node->GetKeyInfo()->GetClass() );
+}
+
+
+
+
+INLINE
+PREGISTRY_KEY_INFO
+REGEDIT_INTERNAL_REGISTRY::GetNodeKeyInfo(
+ IN PCREGEDIT_NODE Node
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return to the client the REGISTRY_KEY_INFO object in this node.
+
+
+Arguments:
+
+ Node - Pointer to REGEDIT_NODE object.
+
+
+Return Value:
+
+
+ PREGISTRY_KEY_INFO - The node KeyInfo..
+
+--*/
+
+{
+ DebugPtrAssert( Node );
+ return( Node->GetKeyInfo() );
+}
+
+
+
+
+INLINE
+PCTIMEINFO
+REGEDIT_INTERNAL_REGISTRY::GetNodeLastWriteTime(
+ IN PCREGEDIT_NODE Node
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return to the client the last write time of the node passed as argument.
+
+
+Arguments:
+
+ Node - Pointer to REGEDIT_NODE object.
+
+
+Return Value:
+
+
+ PCTIMEINFO - The node last write time.
+
+--*/
+
+{
+ DebugPtrAssert( Node );
+ return( Node->GetKeyInfo()->GetLastWriteTime() );
+}
+
+
+
+INLINE
+ULONG
+REGEDIT_INTERNAL_REGISTRY::GetNodeLevel(
+ IN PCREGEDIT_NODE Node
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return to the client the level (depth in the tree) of the node
+ passed as argument.
+
+
+Arguments:
+
+ Node - Pointer to REGEDIT_NODE object.
+
+
+Return Value:
+
+
+ ULONG - Level of the node in the tree ( 0 ==> root ).
+
+--*/
+
+{
+ DebugPtrAssert( Node );
+ return( Node->GetLevel() );
+}
+
+
+
+INLINE
+PCWSTRING
+REGEDIT_INTERNAL_REGISTRY::GetNodeName(
+ IN PCREGEDIT_NODE Node
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return to the client the name of the node passed as argument.
+
+
+Arguments:
+
+ Node - Pointer to REGEDIT_NODE object.
+
+
+Return Value:
+
+
+ PCWSTRING - The node name
+
+--*/
+
+{
+ DebugPtrAssert( Node );
+ return( Node->GetKeyInfo()->GetName() );
+}
+
+
+
+INLINE
+ULONG
+REGEDIT_INTERNAL_REGISTRY::GetNodeTitleIndex(
+ IN PCREGEDIT_NODE Node
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return to the client the title index of the node passed as argument.
+
+
+Arguments:
+
+ Node - Pointer to REGEDIT_NODE object.
+
+
+Return Value:
+
+
+ ULONG - The title index of the node.
+
+--*/
+
+{
+ DebugPtrAssert( Node );
+ return( Node->GetKeyInfo()->GetTitleIndex() );
+}
+
+
+
+
+INLINE
+ULONG
+REGEDIT_INTERNAL_REGISTRY::GetNumberOfChildren(
+ IN PCREGEDIT_NODE Node
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return to the client the number of children in the node passed as argument.
+
+
+Arguments:
+
+ Node - Pointer to REGEDIT_NODE object.
+
+
+Return Value:
+
+
+ ULONG - The title index of the node.
+
+--*/
+
+{
+ DebugPtrAssert( Node );
+ return( Node->GetNumberOfChildren() );
+}
+
+
+
+INLINE
+ULONG
+REGEDIT_INTERNAL_REGISTRY::GetNumberOfValues(
+ IN PCREGEDIT_NODE Node
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return to the client the number of values in the node passed as argument.
+
+
+Arguments:
+
+ Node - Pointer to REGEDIT_NODE object.
+
+
+Return Value:
+
+
+ ULONG - The title index of the node.
+
+--*/
+
+{
+ DebugPtrAssert( Node );
+ return( Node->GetNumberOfValues() );
+}
+
+
+INLINE
+PCREGEDIT_NODE
+REGEDIT_INTERNAL_REGISTRY::GetParent(
+ PCREGEDIT_NODE Node
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the pointer to the parent node.
+
+
+Arguments:
+
+ Node - Pointer to the object that describes the node whose parent is
+ to be retrieved.
+
+
+Return Value:
+
+ PCREGEDIT_NODE - Pointer to REGEDIT_NODE object that represents the
+ parent node.
+
+
+--*/
+
+{
+ DebugPtrAssert( Node );
+ return( Node->GetParentNode() );
+}
+
+
+INLINE
+PCWSTRING
+REGEDIT_INTERNAL_REGISTRY::GetParentName(
+ PCREGEDIT_NODE Node
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the pointer to the parent's name.
+
+
+Arguments:
+
+ Node - Pointer to the object that describes the node whose parent name is
+ to be retrieved.
+
+
+Return Value:
+
+ PCWSTRING - Name of the parent node.
+
+
+--*/
+
+{
+ DebugPtrAssert( Node );
+ return( Node->GetParentName() );
+}
+
+
+INLINE
+PREDEFINED_KEY
+REGEDIT_INTERNAL_REGISTRY::GetPredefinedKey(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the predefined key stored in this object.
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+ PREDEFINED_KEY - The predeifined key stored in this object.
+
+
+--*/
+
+{
+ return( _PredefinedKey );
+}
+
+
+INLINE
+PCWSTRING
+REGEDIT_INTERNAL_REGISTRY::GetRootName(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the name of the the predefined key associated with this
+ REGEDIT_INTERNAL_REGISTRY object.
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+ PCWSTRING - Pointer to a WSTRING object that contains the machine name.
+
+
+--*/
+
+{
+ return( &_RootName );
+}
+
+
+INLINE
+PCREGEDIT_NODE
+REGEDIT_INTERNAL_REGISTRY::GetRootNode(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the pointer to the REGEDIT_NODE object that describes the
+ predefined key associated with this REGEDIT_INTERNAL_REGISTRY object.
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+ PCREGEDIT_NODE - Pointer to the REGEDIT_NODE object that describes
+ the predefined key represented by this object
+
+
+
+--*/
+
+{
+ return( &_RootNode );
+}
+
+
+
+INLINE
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::IsFirstChild(
+ IN PCREGEDIT_NODE Node
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Inform the caller if the node passed as argument is the first child of
+ its parent.
+
+
+Arguments:
+
+ Node - Pointer to a REGEDIT_NODE object.
+
+
+Return Value:
+
+ BOOLEAN - Returns true if it is the first child.
+
+
+
+--*/
+
+{
+ DebugPtrAssert( Node );
+ return( Node->IsFirstChild() );
+}
+
+
+
+INLINE
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::IsLastChild(
+ IN PCREGEDIT_NODE Node
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Inform the caller if the node passed as argument is the last child of
+ its parent.
+
+
+Arguments:
+
+ Node - Pointer to a REGEDIT_NODE object.
+
+
+Return Value:
+
+ BOOLEAN - Returns true if it is the last child.
+
+
+
+--*/
+
+{
+ DebugPtrAssert( Node );
+ return( Node->IsLastChild() );
+}
+
+
+
+INLINE
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::IsNodeExpanded(
+ IN PCREGEDIT_NODE Node
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Inform the client whether the node is being displayed in the tree
+ view as an expanded or as a collapsed node.
+
+
+Arguments:
+
+ Node - Pointer to a REGEDIT_NODE object.
+
+Return Value:
+
+
+ BOOLEAN - Returns TRUE if the node is expanded, or FALSE if the node
+ is collapsed.
+
+--*/
+
+{
+ DebugPtrAssert( Node );
+ return( Node->IsNodeExpanded() );
+}
+
+
+
+INLINE
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::IsNodeViewable(
+ IN PCREGEDIT_NODE Node
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Inform the client whether this node should be displayed in the tree
+ view as a grayed node, to indicate to the user the he cannot view it
+ or access it.
+
+
+Arguments:
+
+ Node - Pointer to a REGEDIT_NODE object.
+
+Return Value:
+
+
+ BOOLEAN - Returns TRUE if the node is viewable, or FALSE otherwise.
+
+--*/
+
+{
+ DebugPtrAssert( Node );
+ return( Node->IsNodeViewable() );
+}
+
+
+
+INLINE
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::QueryCompleteNodeName(
+ IN PCREGEDIT_NODE Node,
+ OUT PWSTRING CompleteName
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the complete name of the node passed as argument.
+
+
+Arguments:
+
+ Node - Pointer to a REGEDIT_NODE object.
+
+ CompleteName - Pointer to a non initialized WSTRING object that will
+ contain the complete node name.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds. Otherwise, returns
+ FALSE.
+
+
+
+--*/
+
+{
+ DebugPtrAssert( Node );
+ DebugPtrAssert( CompleteName );
+
+ return( Node->QueryCompleteName( CompleteName ) );
+}
+
+
+
+
+INLINE
+VOID
+REGEDIT_INTERNAL_REGISTRY::SetNodeExpansionState(
+ IN PCREGEDIT_NODE Node,
+ IN BOOLEAN NewExpansionState
+ )
+
+/*++
+
+Routine Description:
+
+ Save in the node the information that indivcates whether the node is
+ displayed as a an expanded or collapsed node.
+
+
+Arguments:
+
+ Node - Pointer to a REGEDIT_NODE object whose diplay status is to be
+ saved.
+
+ NewExpansionState - Contains the information on how the node is currently
+ displayed. TRUE indicates that the node is expanded,
+ and FALSE indicates that the node is collapsed.
+
+
+Return Value:
+
+
+ None.
+
+--*/
+
+{
+ DebugPtrAssert( Node );
+ ( ( PREGEDIT_NODE )Node )->SetNodeExpansionState( NewExpansionState );
+}
+
+
+
+INLINE
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::UnloadChildren(
+ IN PCREGEDIT_NODE Node
+ )
+
+/*++
+
+Routine Description:
+
+ Unload from memory the children of a node, if they are loaded in memory.
+
+
+Arguments:
+
+ Node - Pointer to a REGEDIT_NODE object whose children are to be unloaded
+ from memory.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeded.
+
+
+--*/
+
+{
+ DebugPtrAssert( Node );
+ return( ( ( PREGEDIT_NODE )Node )->DeleteListOfChildren() );
+}
+
+
+
+
+INLINE
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::UnloadValues(
+ IN PCREGEDIT_NODE Node
+ )
+
+/*++
+
+Routine Description:
+
+ Unload from memory the values of a node, if they are loaded in memory.
+
+
+Arguments:
+
+ Node - Pointer to a REGEDIT_NODE object whose values are to be unloaded
+ from memory.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeded.
+
+
+--*/
+
+{
+ DebugPtrAssert( Node );
+ return( ( ( PREGEDIT_NODE )Node )->DeleteListOfValues() );
+}
+
+
+
+#if 0
+
+INLINE
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::DidRootChange(
+ )
+
+/*++
+
+Routine Description:
+
+ Find out if the root node has changed
+
+Arguments:
+
+
+
+Return Value:
+
+
+
+--*/
+
+{
+ return( _Registry->DidRootChange( _PredefinedKey ) );
+}
+#endif
+
+
+INLINE
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::EnableRootNotification(
+ IN HANDLE Event,
+ IN DWORD Filter,
+ IN BOOLEAN WatchTree
+// IN PVOID CallBackFunction
+ )
+
+/*++
+
+Routine Description:
+
+ Enable notification in a predefined key.
+
+Arguments:
+
+
+
+Return Value:
+
+
+ None.
+
+--*/
+
+{
+ return( _Registry->EnableRootNotification( _PredefinedKey,
+ Event,
+ Filter,
+ WatchTree
+ /* CallBackFunction */ ) );
+}
+
+
+
+INLINE
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::AreHiveOperationsAllowed(
+ )
+
+/*++
+
+Routine Description:
+
+ Inform the client if its is possible to load/unload keys.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+
+ BOOLEAN - Returns TRUE if Load/Unload key is allowed.
+ Returns FALSE otherwise.
+
+--*/
+
+{
+ return( ( _PredefinedKey == PREDEFINED_KEY_LOCAL_MACHINE ) ||
+ ( _PredefinedKey == PREDEFINED_KEY_USERS ) ||
+ ( _PredefinedKey == PREDEFINED_KEY_CURRENT_USER ) );
+}
+
+
+
+INLINE
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::IsMasterHive(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Inform the client if the root node is a master hive.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+
+ BOOLEAN - Returns TRUE if the root node is a master hive.
+ Returns FALSE otherwise.
+
+--*/
+
+{
+ return( ( _PredefinedKey == PREDEFINED_KEY_LOCAL_MACHINE ) ||
+ ( _PredefinedKey == PREDEFINED_KEY_USERS ) );
+}
+
+
+
+
+
+#endif // _REGEDIT_INTERNAL_REGISTRY_
diff --git a/private/utils/regedit/inc/regedit.hxx b/private/utils/regedit/inc/regedit.hxx
new file mode 100644
index 000000000..00395409e
--- /dev/null
+++ b/private/utils/regedit/inc/regedit.hxx
@@ -0,0 +1,258 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ Regedit.hxx
+
+Abstract:
+
+
+Author:
+
+ David J. Gilman (davegi) 02-Aug-1991
+
+Environment:
+
+ Ulib, Regedit, Windows, User Mode
+
+--*/
+
+#if ! defined( _REGEDIT_ )
+
+#define _REGEDIT_
+
+
+#include "ulib.hxx"
+#include "uapp.hxx"
+#include "registry.hxx"
+
+
+extern HWND _MDIHandle;
+
+
+
+typedef struct _REGISTRY_WINDOW_SET {
+ PREGISTRY_WINDOW ClassesRoot;
+ PREGISTRY_WINDOW CurrentUser;
+ PREGISTRY_WINDOW CurrentConfig;
+ PREGISTRY_WINDOW LocalMachine;
+ PREGISTRY_WINDOW Users;
+ PREGISTRY Registry;
+ } REGISTRY_WINDOW_SET, *PREGISTRY_WINDOW_SET;
+
+
+typedef struct _WINDOW_POSITION {
+ INT X;
+ INT Y;
+ INT Width;
+ INT Height;
+ INT Style;
+ INT Split;
+ } WINDOW_POSITION, *PWINDOW_POSITION;
+
+
+VOID
+DisplayHelp(
+ );
+
+INT
+DisplayConfirmPopup(
+ IN HWND hWnd,
+ IN INT TextMessage,
+ IN INT CaptionMessage DEFAULT 0
+ );
+
+VOID
+DisplayWarningPopup(
+ IN HWND hWnd,
+ IN INT TextMessage,
+ IN INT CaptionMessage DEFAULT 0
+ );
+
+VOID
+DisplayInfoPopup(
+ IN HWND hWnd,
+ IN INT TextMessage,
+ IN INT CaptionMessage DEFAULT 0
+ );
+
+
+INLINE
+VOID
+CascadeRegistryWindows (
+ )
+
+/*++
+
+Routine Description:
+
+ Arrange all REGISTRY_WINDOWs in a cascaded fashion.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ SendMessage( _MDIHandle, WM_MDICASCADE, 0, 0 );
+}
+
+INLINE
+HWND
+QueryActiveRegistryWindow (
+ )
+
+/*++
+
+Routine Description:
+
+ Determine the active Registry Window (MDI Client).
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ HWND - Returns the handle for the active Registry Window.
+
+--*/
+
+{
+ return ( HWND )( LO_HANDLE( NULL, SendMessage ( _MDIHandle, WM_MDIGETACTIVE, 0, 0 ) ) );
+}
+
+INLINE
+VOID
+Copy (
+ )
+
+/*++
+
+Routine Description:
+
+ Send a copy message to the active REGISTRY_WINDOW.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ SendMessage( QueryActiveRegistryWindow( ), WM_COPY, 0, 0 );
+}
+
+INLINE
+VOID
+Cut (
+ )
+/*++
+
+Routine Description:
+
+ Send a cut message to the active REGISTRY_WINDOW.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+
+{
+ SendMessage( QueryActiveRegistryWindow( ), WM_CUT, 0, 0 );
+}
+
+INLINE
+VOID
+Delete (
+ )
+
+/*++
+
+Routine Description:
+
+ Send a delete (clear) message to the active REGISTRY_WINDOW.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ SendMessage( QueryActiveRegistryWindow( ), WM_CLEAR, 0, 0 );
+}
+
+INLINE
+VOID
+Paste (
+ )
+
+/*++
+
+Routine Description:
+
+ Send a paste message to the active REGISTRY_WINDOW.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ SendMessage( QueryActiveRegistryWindow( ), WM_PASTE, 0, 0 );
+}
+
+INLINE
+VOID
+TileRegistryWindows (
+ )
+
+/*++
+
+Routine Description:
+
+ Arrange all REGISTRY_WINDOWs in a tiled fashion.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ SendMessage( _MDIHandle, WM_MDITILE, 0, 0 );
+}
+
+
+#endif // _REGEDIT_
diff --git a/private/utils/regedit/inc/regednod.hxx b/private/utils/regedit/inc/regednod.hxx
new file mode 100644
index 000000000..04366b52d
--- /dev/null
+++ b/private/utils/regedit/inc/regednod.hxx
@@ -0,0 +1,887 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ regednod.hxx
+
+Abstract:
+
+ This module contains the declarations for the REGEDIT_NODE class.
+ REGEDIT_NODE class is a that contains all the information of a registry
+ key, such as:
+
+ -Key Name
+ -Parent Name
+ -Title Index
+ -Class
+ -Security Attribute
+ -Last Write Time
+ -Number of Sub-keys
+ -Number of Value Entries
+
+ and other information related to its position in the tree structure
+ (the tree structure under a predefinded key in the registry) where
+ it belongs, such as:
+
+ -Its level in the tree
+ -A pointer to a REGISTRY_NODE that represent its parent
+ -A flag indicating if it is the first child of its parent
+ -A flag indicating if it is the last child of its parent
+ -An array of pointers to its children (REGEDIT_NODE)
+ -An array of pointers to its values (REGEDIT_FORMATTED_VALUE_ENTRY)
+
+
+ Notes: 1. This class could be made derived from REGISTRY_KEY_INFO, but in
+ case the initialization of the array of values in
+ REGEDIT_INTERNAL_REGISTRY would be too slow.
+
+ 2. All methods in this class are private. REGEDIT_INTERNAL_REGISTRY
+ is the only class that can access the methods on this class
+ (including deletion).
+
+ 3. A REGEDIT_NODE class is initialized with a pointer to a
+ REGISTRY_KEY_INFO. It is responsibility of this cbject to
+ delete the REGISTRY_KEY_INFO when it is destroyed or
+ re-initialized.
+
+Author:
+
+ Jaime Sasson (jaimes) 01-Mar-1992
+
+
+Environment:
+
+ Regedit, Ulib, User Mode
+
+
+--*/
+
+
+#if !defined( _REGEDIT_NODE_ )
+
+#define _REGEDIT_NODE_
+
+#include "ulib.hxx"
+// #include "array.hxx"
+#include "regkey.hxx"
+#include "regedval.hxx"
+#include "sortlist.hxx"
+
+DECLARE_CLASS( REGEDIT_NODE );
+DECLARE_CLASS( REGEDIT_INTERNAL_REGISTRY );
+
+
+
+class REGEDIT_NODE : public OBJECT {
+
+
+FRIEND class REGEDIT_INTERNAL_REGISTRY;
+
+
+#if DBG
+
+ public:
+
+ NONVIRTUAL
+ VOID
+ DbgPrintRegeditNode(
+ );
+
+#endif // DBG
+
+
+
+ private:
+
+
+ DECLARE_CONSTRUCTOR( REGEDIT_NODE );
+
+ DECLARE_CAST_MEMBER_FUNCTION( REGEDIT_NODE );
+
+ VIRTUAL
+ ~REGEDIT_NODE(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PREGISTRY_KEY_INFO KeyInfo,
+ IN PCREGEDIT_NODE ParentNode,
+ IN ULONG Level,
+ IN BOOLEAN FirstChild,
+ IN BOOLEAN LastChild
+ );
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL // For add node
+ BOOLEAN
+ AddChildToListOfChildren(
+ IN PREGEDIT_NODE ChildNode
+// IN PREGEDIT_NODE ChildNode,
+// IN BOOLEAN FirstPosition DEFAULT TRUE
+ );
+
+ NONVIRTUAL // For add value
+ BOOLEAN
+ AddValueToListOfValues(
+ IN PREGEDIT_FORMATTED_VALUE_ENTRY Value
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AreChildrenInMemory(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ AreValuesInMemory(
+ ) CONST;
+
+ VIRTUAL
+ LONG
+ Compare(
+ IN PCOBJECT Node
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN // Used by memory manager
+ DeleteListOfChildren(
+ );
+
+ NONVIRTUAL // Used by memory manager
+ BOOLEAN
+ DeleteListOfValues(
+ );
+
+ NONVIRTUAL
+// PARRAY
+ PSORTED_LIST
+ GetChildren(
+ ) CONST;
+
+ NONVIRTUAL
+ PREGISTRY_KEY_INFO
+ GetKeyInfo(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetLevel(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetNumberOfChildren(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetNumberOfValues(
+ ) CONST;
+
+ NONVIRTUAL
+ PCWSTRING
+ GetParentName(
+ ) CONST;
+
+ NONVIRTUAL
+ PCREGEDIT_NODE
+ GetParentNode(
+ ) CONST;
+
+ NONVIRTUAL
+// PARRAY
+ PSORTED_LIST
+ GetValues(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsFirstChild(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsLastChild(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsNodeExpanded(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsNodeViewable(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryCompleteName(
+ OUT PWSTRING CompleteName
+ ) CONST;
+
+ NONVIRTUAL // for delete node
+ BOOLEAN
+ RemoveChildFromListOfChildren(
+ IN PCREGEDIT_NODE Node
+ );
+
+ NONVIRTUAL // for delete value
+ BOOLEAN
+ RemoveValueFromListOfValues(
+ IN PCREGEDIT_FORMATTED_VALUE_ENTRY Value
+ );
+
+ NONVIRTUAL
+ VOID
+ SetLevel(
+ IN ULONG Level,
+ IN BOOLEAN Recurse DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ VOID
+ SetChildren(
+// IN PARRAY Children
+ IN PSORTED_LIST Children
+ );
+
+ NONVIRTUAL
+ VOID
+ SetNodeExpansionState(
+ IN BOOLEAN NewState
+ );
+
+ NONVIRTUAL
+ VOID
+ SetParentNode(
+ IN PCREGEDIT_NODE ParentNode
+ );
+
+ NONVIRTUAL
+ VOID
+ SetPosition(
+ IN BOOLEAN FirstChild,
+ IN BOOLEAN LastChild
+ );
+
+ NONVIRTUAL
+ VOID
+ SetValues(
+// IN PARRAY Values
+ IN PSORTED_LIST Values
+ );
+
+
+
+ NONVIRTUAL
+ BOOLEAN
+ UpdateParentName(
+ IN PCWSTRING ParentName,
+ IN BOOLEAN Recurse DEFAULT FALSE
+ );
+
+
+ PREGISTRY_KEY_INFO _KeyInfo;
+ PCREGEDIT_NODE _ParentNode;
+ ULONG _Level;
+ BOOLEAN _FlagFirstChild;
+ BOOLEAN _FlagLastChild;
+// PARRAY _Values;
+// PARRAY _Children;
+ PSORTED_LIST _Values;
+ PSORTED_LIST _Children;
+ BOOLEAN _NodeIsExpanded;
+ STATIC
+ PWSTRING _Separator;
+
+
+};
+
+
+
+INLINE
+BOOLEAN
+REGEDIT_NODE::AreChildrenInMemory(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Inform the client whether the array with the children of this node
+ is loaded in memory.
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+
+ BOOLEAN - Returns TRUE if the children are in memory, or FALSE otherwise.
+
+--*/
+
+{
+ return( ( _Children == NULL )? FALSE : TRUE );
+}
+
+
+
+INLINE
+BOOLEAN
+REGEDIT_NODE::AreValuesInMemory(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Inform the client whether the array with the values of this node
+ is loaded in memory.
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+
+ BOOLEAN - Returns TRUE if the values are in memory, or FALSE otherwise.
+
+--*/
+
+{
+ return( ( _Values == NULL )? FALSE : TRUE );
+}
+
+
+
+INLINE
+PSORTED_LIST
+REGEDIT_NODE::GetChildren(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return to the client the pointer to the list that contains the children
+ of this node.
+
+ THE CALLER SHOULD NOT DELETE THIS ARRAY OR ANY OF ITS ELEMENTS!!!!!
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+
+ PARRAY - Pointer to the array that contains the children of this object.
+
+--*/
+
+{
+ return( _Children );
+}
+
+
+
+INLINE
+PREGISTRY_KEY_INFO
+REGEDIT_NODE::GetKeyInfo(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return to the client the pointer to the REGISTRY_KEY_INFO object
+ of this node.
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+
+ PREGISTRY_KEY_INFO - Pointer to the REGISTRY_KEY_INFO object
+
+--*/
+
+{
+ return( _KeyInfo );
+}
+
+
+
+INLINE
+ULONG
+REGEDIT_NODE::GetLevel(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return to the client the level (depth in the tree) of this node.
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+
+ ULONG - Level of this node in the tree ( 0 ==> root ).
+
+--*/
+
+{
+ return( _Level );
+}
+
+
+
+
+INLINE
+ULONG
+REGEDIT_NODE::GetNumberOfChildren(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return to the client the of children that this node has.
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+
+ ULONG - Number of children in this node.
+
+--*/
+
+{
+ return( _KeyInfo->GetNumberOfSubKeys() );
+}
+
+
+
+
+INLINE
+ULONG
+REGEDIT_NODE::GetNumberOfValues(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return to the client the number of values that this node has.
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+
+ ULONG - Number of values in this node.
+
+--*/
+
+{
+ return( _KeyInfo->GetNumberOfValues() );
+}
+
+
+
+
+INLINE
+PCWSTRING
+REGEDIT_NODE::GetParentName(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return to the client the pointer to the WSTRING object that contains
+ the parent's name.
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+
+ PCWSTRING - Pointer to the parent's name.
+
+--*/
+
+{
+ return( _KeyInfo->GetParentName() );
+}
+
+
+
+
+INLINE
+PCREGEDIT_NODE
+REGEDIT_NODE::GetParentNode(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return to the client the pointer to the parent of this node.
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+
+ PCREGEDIT_NODE - Pointer to the parent node.
+
+--*/
+
+{
+ return( _ParentNode );
+}
+
+
+
+
+INLINE
+PSORTED_LIST
+REGEDIT_NODE::GetValues(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return to the client the pointer to the list that contains the values
+ of this node.
+
+ THE CALLER SHOULD NOT DELETE THIS ARRAY OR ANY OF ITS ELEMENTS!!!!!
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+
+ PARRAY - Pointer to the array that contains the values of this object.
+
+--*/
+
+{
+ return( _Values );
+}
+
+
+
+INLINE
+BOOLEAN
+REGEDIT_NODE::IsFirstChild(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Inform the client whether this node is the first child of its parent.
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+
+ BOOLEAN - Returns TRUE if this object is the first child of its parent,
+ or FALSE otherwise.
+
+--*/
+
+{
+ return( _FlagFirstChild );
+}
+
+
+
+INLINE
+BOOLEAN
+REGEDIT_NODE::IsLastChild(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Inform the client whether this node is the last child of its parent.
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+
+ BOOLEAN - Returns TRUE if this object is the last child of its parent,
+ or FALSE otherwise.
+
+--*/
+
+{
+ return( _FlagLastChild );
+}
+
+
+
+INLINE
+BOOLEAN
+REGEDIT_NODE::IsNodeExpanded(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Inform the client whether this node is being displayed in the tree
+ view as an expanded or as a collapsed node.
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+
+ BOOLEAN - Returns TRUE if the node is expanded, or FALSE if the node
+ is collapsed.
+
+--*/
+
+{
+ return( _NodeIsExpanded );
+}
+
+
+
+INLINE
+BOOLEAN
+REGEDIT_NODE::IsNodeViewable(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Inform the client whether this node should be displayed in the tree
+ view as a grayed node, to indicate to the user the he cannot view it
+ or access it.
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+
+ BOOLEAN - Returns TRUE if the node is viewable, or FALSE otherwise.
+
+--*/
+
+{
+ return( _KeyInfo->IsKeyInitialized() );
+}
+
+
+
+INLINE
+VOID
+REGEDIT_NODE::SetChildren(
+// IN PARRAY Children
+ IN PSORTED_LIST Children
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the variable that points to the list of children of this object.
+
+
+Arguments:
+
+ Children - Pointer to the array that contains the children of this object.
+
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ DebugPtrAssert( Children );
+ _Children = Children;
+}
+
+
+
+INLINE
+VOID
+REGEDIT_NODE::SetParentNode(
+ PCREGEDIT_NODE ParentNode
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the variable that pointe to the parent node.
+
+
+Arguments:
+
+ ParentNode - Pointer to the object that represents the parent node.
+
+
+Return Value:
+
+
+ None.
+
+--*/
+
+{
+ _ParentNode = ParentNode;
+}
+
+
+
+INLINE
+VOID
+REGEDIT_NODE::SetPosition(
+ IN BOOLEAN FirstChild,
+ IN BOOLEAN LastChild
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the variables that indicate whether the node is the first or
+ last children of its parent.
+
+
+Arguments:
+
+ FirstChild - Indicates whether the node is the first children of its parent.
+
+ LastChild - Indicates whether the node is the lst children of its parent.
+
+
+Return Value:
+
+
+ None.
+
+--*/
+
+{
+ _FlagFirstChild = FirstChild;
+ _FlagLastChild = LastChild;
+}
+
+
+
+INLINE
+VOID
+REGEDIT_NODE::SetValues(
+// IN PARRAY Values
+ IN PSORTED_LIST Values
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the variable that points to the array of values of this object.
+
+
+Arguments:
+
+ Children - Pointer to the array that contains the values of this object.
+
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ DebugPtrAssert( Values );
+ _Values = Values;
+}
+
+#endif // _REGEDIT_NODE_
diff --git a/private/utils/regedit/inc/regedval.hxx b/private/utils/regedit/inc/regedval.hxx
new file mode 100644
index 000000000..b969ed3b1
--- /dev/null
+++ b/private/utils/regedit/inc/regedval.hxx
@@ -0,0 +1,389 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ regedval.hxx
+
+Abstract:
+
+
+ This module contains the declarations for the REGEDIT_FORMATTED_VALUE_ENTRY
+ class.
+ This class models a value entry of a registry key, and contains a
+ formatted string to be displayed in the data view of regedit.
+ It contains:
+
+ -a REGISTRY_VALUE_ENTRY object
+ -a formatted string to be displayed in regedit's data view
+
+ Note: This class could be derived from REGISTRY_KEY_INFO, but in this
+ case the initialzation of the araray of values in the
+ REGEDIT_INTERNAL_REGISTRY would be much slower.
+
+Author:
+
+ Jaime Sasson (jaimes) 03-Mar-1992
+
+
+Environment:
+
+
+ Ulib, Regedit, User Mode
+
+--*/
+
+
+#if !defined( _REGEDIT_FORMATTED_VALUE_ENTRY_ )
+
+#define _REGEDIT_FORMATTED_VALUE_ENTRY_
+
+#include "ulib.hxx"
+#include "regvalue.hxx"
+
+
+#define MAX_BUFFER 2048
+
+DECLARE_CLASS( REGEDIT_FORMATTED_VALUE_ENTRY );
+
+
+
+class REGEDIT_FORMATTED_VALUE_ENTRY : public OBJECT {
+
+ FRIEND class REGEDIT_INTERNAL_REGISTRY;
+
+ public:
+
+ DECLARE_CONSTRUCTOR( REGEDIT_FORMATTED_VALUE_ENTRY );
+
+ DECLARE_CAST_MEMBER_FUNCTION( REGEDIT_FORMATTED_VALUE_ENTRY );
+
+
+
+ VIRTUAL
+ ~REGEDIT_FORMATTED_VALUE_ENTRY(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PREGISTRY_VALUE_ENTRY RegistryValueEntry
+ );
+
+ VIRTUAL
+ LONG
+ Compare(
+ IN PCOBJECT Node
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetData(
+ OUT PCBYTE* Data
+ ) CONST;
+
+ NONVIRTUAL
+ PCWSTRING
+ GetFormattedString(
+ ) CONST;
+
+ NONVIRTUAL
+ PCWSTRING
+ GetName(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetTitleIndex(
+ ) CONST;
+
+
+ NONVIRTUAL
+ REG_TYPE
+ GetType(
+ ) CONST;
+/*
+ NONVIRTUAL
+ PCREGISTRY_VALUE_ENTRY
+ GetRegistryValueEntry(
+ ) CONST;
+*/
+
+#if DBG
+ NONVIRTUAL
+ VOID
+ DbgPrintFormattedValueEntry(
+ );
+#endif
+
+ NONVIRTUAL // This method should be private
+ BOOLEAN // It is public for debgug only.
+ FormatString(
+ );
+
+
+
+ private:
+
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ PWSTRING
+ FormatBinaryData(
+ IN PCBYTE Data,
+ IN ULONG Size
+ );
+
+ NONVIRTUAL // Used by REGEDIT_INTERNAL_REGISTRY only
+ PREGISTRY_VALUE_ENTRY
+ GetValueEntry(
+ ) CONST;
+
+
+ PREGISTRY_VALUE_ENTRY _ValueEntry;
+
+ DSTRING _FormattedString;
+
+ STATIC
+ PWSTRING _RegNoneString;
+
+ STATIC
+ PWSTRING _RegSzString;
+
+ STATIC
+ PWSTRING _RegExpandSzString;
+
+ STATIC
+ PWSTRING _RegBinaryString;
+
+ STATIC
+ PWSTRING _RegDwordString;
+
+ STATIC
+ PWSTRING _RegMultiSzString;
+
+ STATIC
+ PWSTRING _RegResourceListString;
+
+ STATIC
+ PWSTRING _RegFullResourceDescriptorString;
+
+ STATIC
+ PWSTRING _RegIoRequirementsListString;
+
+ STATIC
+ PWSTRING _RegTypeUnknownString;
+
+ STATIC
+ PWSTRING _Separator;
+
+ STATIC
+ PWSTRING _NoNameString;
+
+ STATIC
+ PWSTRING _InvalidDataString;
+
+ STATIC
+ BOOLEAN _StringsInitialized;
+
+};
+
+
+
+INLINE
+ULONG
+REGEDIT_FORMATTED_VALUE_ENTRY::GetData(
+ OUT PCBYTE* Data
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the buffer that contains the data stored in the value entry.
+
+
+Arguments:
+
+ Data - Variable that will contain the pointer to the buffer that
+ contains the data.
+
+Return Value:
+
+ ULONG - Number of bytes in the buffer (Data size)
+
+
+--*/
+
+
+{
+ DebugPtrAssert( Data );
+
+ return( _ValueEntry->GetData( Data ) );
+}
+
+
+
+
+INLINE
+PCWSTRING
+REGEDIT_FORMATTED_VALUE_ENTRY::GetFormattedString(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the pointer to a WSTRING object that contains a formatted string
+ that represents the information in a value entry.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PCWSTRING - The formatted string to be displayed in regedit's data view.
+
+
+--*/
+
+
+{
+ return( &_FormattedString );
+}
+
+
+
+INLINE
+PCWSTRING
+REGEDIT_FORMATTED_VALUE_ENTRY::GetName(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return a pointer to a WSTRING object that contains the value name.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The value name.
+
+
+--*/
+
+
+{
+ return( _ValueEntry->GetName() );
+}
+
+
+
+INLINE
+ULONG
+REGEDIT_FORMATTED_VALUE_ENTRY::GetTitleIndex(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the title index of this value.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - The title index.
+
+
+--*/
+
+
+{
+ return( _ValueEntry->GetTitleIndex() );
+}
+
+
+
+INLINE
+REG_TYPE
+REGEDIT_FORMATTED_VALUE_ENTRY::GetType(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the type of data stored in this object.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ REG_TYPE - The data type.
+
+
+--*/
+
+
+{
+ return( _ValueEntry->GetType() );
+}
+
+
+
+INLINE
+PREGISTRY_VALUE_ENTRY
+REGEDIT_FORMATTED_VALUE_ENTRY::GetValueEntry(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the pointer to the REGISTRY_VALUE_ENTRY object stored in this object.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PREGISTRY_VALUE_ENTRY - Pointer to the REGISTRY_VALUE_ENTRY object.
+
+
+--*/
+
+
+{
+ return( _ValueEntry );
+}
+
+
+
+
+#endif // _REGEDIT_FORMATTED_VALUE_ENTRY_
diff --git a/private/utils/regedit/inc/regfdesc.hxx b/private/utils/regedit/inc/regfdesc.hxx
new file mode 100644
index 000000000..7ccd7bea2
--- /dev/null
+++ b/private/utils/regedit/inc/regfdesc.hxx
@@ -0,0 +1,245 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ regfdesc.hxx
+
+Abstract:
+
+ This module contains the declarations for the FULL_RESOURCE_DESCRIPTOR
+ class. This class models models a CM_FULL_RESOURCE_DESCRIPTOR structure,
+ used on registry data of type REG_FULL_RESOURCE_DESCRIPTOR and REG_RESOURCE_LIST.
+
+
+Author:
+
+ Jaime Sasson (jaimes) 01-Dec-1993
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+
+#if !defined( _FULL_DESCRIPTOR_ )
+
+#define _FULL_DESCRIPTOR_
+
+#include "ulib.hxx"
+#include "array.hxx"
+
+DECLARE_CLASS( FULL_DESCRIPTOR );
+
+
+class FULL_DESCRIPTOR : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( FULL_DESCRIPTOR );
+
+ VIRTUAL
+ ~FULL_DESCRIPTOR(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PCBYTE Data,
+ IN ULONG DataSize,
+ OUT PULONG DescriptorSize DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ INTERFACE_TYPE
+ GetInterfaceType(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetBusNumber(
+ ) CONST;
+
+ NONVIRTUAL
+ USHORT
+ GetVersion(
+ ) CONST;
+
+ NONVIRTUAL
+ USHORT
+ GetRevision(
+ ) CONST;
+
+ NONVIRTUAL
+ PARRAY
+ GetResourceDescriptors(
+ ) CONST;
+
+#if DBG
+ NONVIRTUAL
+ VOID
+ DbgDumpObject(
+ );
+#endif
+
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ INTERFACE_TYPE _InterfaceType;
+ ULONG _BusNumber;
+ USHORT _Version;
+ USHORT _Revision;
+ PARRAY _ResourceDescriptors;
+};
+
+
+INLINE
+INTERFACE_TYPE
+FULL_DESCRIPTOR::GetInterfaceType(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the interface type of the full descriptor represented
+ by this object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns the interface type.
+
+
+--*/
+
+{
+ return( _InterfaceType );
+}
+
+
+INLINE
+ULONG
+FULL_DESCRIPTOR::GetBusNumber(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the bus number of the full descriptor represented
+ by this object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns the bus number.
+
+
+--*/
+
+{
+ return( _BusNumber );
+}
+
+
+INLINE
+USHORT
+FULL_DESCRIPTOR::GetVersion(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the version of the partial resource list.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ USHORT - Returns the version of the partial resource list
+
+
+--*/
+
+{
+ return( _Version );
+}
+
+
+INLINE
+USHORT
+FULL_DESCRIPTOR::GetRevision(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the revision of the partial resource list.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ USHORT - Returns the revisin of the partial resource list
+
+
+--*/
+
+{
+ return( _Revision );
+}
+
+
+INLINE
+PARRAY
+FULL_DESCRIPTOR::GetResourceDescriptors(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return a pointer to the array that contains the partial resource
+ descriptors.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PARRAY - Pointer to the array that contains the partial resource descriptors.
+
+--*/
+
+{
+ return( _ResourceDescriptors );
+}
+
+#endif // FULL_DESCRIPTOR
diff --git a/private/utils/regedit/inc/regiodls.hxx b/private/utils/regedit/inc/regiodls.hxx
new file mode 100644
index 000000000..246d0f68e
--- /dev/null
+++ b/private/utils/regedit/inc/regiodls.hxx
@@ -0,0 +1,177 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ regiodls.hxx
+
+Abstract:
+
+ This module contains the declarations for the IO_DESCRIPTOR_LIST
+ class. This class models models an IO_RESOURCE_LIST structure,
+ used on registry data of type REG_RESOURCE_REQUIREMENTS_LIST.
+
+
+Author:
+
+ Jaime Sasson (jaimes) 01-Dec-1993
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+
+#if !defined( _IO_DESCRIPTOR_LIST_ )
+
+#define _IO_DESCRIPTOR_LIST_
+
+#include "ulib.hxx"
+#include "array.hxx"
+
+DECLARE_CLASS( IO_DESCRIPTOR_LIST );
+
+
+class IO_DESCRIPTOR_LIST : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( IO_DESCRIPTOR_LIST );
+
+ VIRTUAL
+ ~IO_DESCRIPTOR_LIST(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PCBYTE Data,
+ IN ULONG DataSize,
+ OUT PULONG ListSize DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ USHORT
+ GetVersion(
+ ) CONST;
+
+ NONVIRTUAL
+ USHORT
+ GetRevision(
+ ) CONST;
+
+ NONVIRTUAL
+ PARRAY
+ GetDescriptorsList(
+ ) CONST;
+
+#if DBG
+ NONVIRTUAL
+ VOID
+ DbgDumpObject(
+ );
+#endif
+
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ USHORT _Version;
+ USHORT _Revision;
+ PARRAY _DescriptorsList;
+};
+
+
+INLINE
+USHORT
+IO_DESCRIPTOR_LIST::GetVersion(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the version of the resource list.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ USHORT - Returns the version of the resource list
+
+
+--*/
+
+{
+ return( _Version );
+}
+
+
+INLINE
+USHORT
+IO_DESCRIPTOR_LIST::GetRevision(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the revision of the resource list.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ USHORT - Returns the revisin of the resource list
+
+
+--*/
+
+{
+ return( _Revision );
+}
+
+
+INLINE
+PARRAY
+IO_DESCRIPTOR_LIST::GetDescriptorsList(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return a pointer to the array that contains the resource
+ descriptors.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PARRAY - Pointer to the array that contains the resource descriptors.
+
+--*/
+
+{
+ return( _DescriptorsList );
+}
+
+#endif // _IO_DESCRIPTOR_LIST_
diff --git a/private/utils/regedit/inc/regiodsc.hxx b/private/utils/regedit/inc/regiodsc.hxx
new file mode 100644
index 000000000..22632290c
--- /dev/null
+++ b/private/utils/regedit/inc/regiodsc.hxx
@@ -0,0 +1,1694 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ regdesc.hxx
+
+Abstract:
+
+ This module contains the declarations for the following
+ classes: IO_DESCRIPTOR, IO_PORT_DESCRIPTOR,
+ IO_INTERRUPT_DESCRIPTOR, IO_MEMORY_DESCRIPTOR and
+ IO_DMA_DESCRIPTOR. The last 4 classes are derived from
+ the first one.
+
+ These classes models an IO_RESOURCE_DESCRIPTOR structure
+ used in registry data of type REG_RESOURCE_REQUIREMENTS_LIST.
+
+Author:
+
+ Jaime Sasson (jaimes) 01-Dec-1993
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+
+#if !defined( _IO_DESCRIPTOR_ )
+
+#define _IO_DESCRIPTOR_
+
+#define _NTAPI_ULIB_
+#include "ulib.hxx"
+#include "ntconfig.h"
+
+#if 0
+//
+// BUGBUG - REMOVE!!!
+//
+//
+// Defines Resource Options
+//
+
+// #define IO_RESOURCE_FIXED 0x01
+#define IO_RESOURCE_PREFERRED 0x01
+#define IO_RESOURCE_ALTERNATIVE 0x08
+
+
+//
+// This structure defines one type of resource requested by the driver
+//
+
+typedef struct _IO_RESOURCE_DESCRIPTOR {
+ UCHAR Option;
+ UCHAR Type; // use CM_RESOURCE_TYPE
+ UCHAR ShareDisposition; // use CM_SHARE_DISPOSITION
+ UCHAR Spare1;
+ USHORT Flags; // use CM resource flag defines
+ USHORT Spare2; // align
+
+ union {
+ struct {
+// PHYSICAL_ADDRESS BaseAddress;
+ ULONG Length;
+ ULONG Alignment;
+ PHYSICAL_ADDRESS MinimumAddress;
+ PHYSICAL_ADDRESS MaximumAddress;
+ } Port;
+
+ struct {
+// PHYSICAL_ADDRESS BaseAddress;
+ ULONG Length;
+ ULONG Alignment;
+ PHYSICAL_ADDRESS MinimumAddress;
+ PHYSICAL_ADDRESS MaximumAddress;
+ } Memory;
+
+ struct {
+// ULONG Vector;
+ ULONG MinimumVector;
+ ULONG MaximumVector;
+ } Interrupt;
+
+ struct {
+// ULONG DmaWidth;
+ ULONG MinimumChannel;
+ ULONG MaximumChannel;
+ } Dma;
+
+ } u;
+
+// ULONG Reserved[2];
+
+} IO_RESOURCE_DESCRIPTOR, *PIO_RESOURCE_DESCRIPTOR;
+
+
+typedef struct _IO_RESOURCE_LIST {
+ USHORT Version;
+ USHORT Revision;
+
+ ULONG Count;
+ IO_RESOURCE_DESCRIPTOR Descriptors[1];
+} IO_RESOURCE_LIST, *PIO_RESOURCE_LIST;
+
+
+typedef struct _IO_RESOURCE_REQUIREMENTS_LIST {
+ ULONG ListSize;
+ INTERFACE_TYPE InterfaceType;
+ ULONG BusNumber;
+ ULONG SlotNumber;
+ ULONG Reserved[3];
+ ULONG AlternativeLists;
+ IO_RESOURCE_LIST List[1];
+} IO_RESOURCE_REQUIREMENTS_LIST, *PIO_RESOURCE_REQUIREMENTS_LIST;
+
+//
+// END OF BUGBUG
+//
+#endif
+
+
+DECLARE_CLASS( IO_DESCRIPTOR );
+
+
+class IO_DESCRIPTOR : public OBJECT {
+
+
+ public:
+
+ VIRTUAL
+ ~IO_DESCRIPTOR(
+ );
+
+ VIRTUAL
+ UCHAR
+ GetOption(
+ ) CONST;
+
+ VIRTUAL
+ UCHAR
+ GetShareDisposition(
+ ) CONST;
+
+ VIRTUAL
+ USHORT
+ GetFlags(
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ IsDescriptorTypePort(
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ IsDescriptorTypeInterrupt(
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ IsDescriptorTypeMemory(
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ IsDescriptorTypeDma(
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ IsResourceOptionPreferred(
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ IsResourceOptionAlternative(
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ IsResourceShareUndetermined(
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ IsResourceShareDeviceExclusive(
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ IsResourceShareDriverExclusive(
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ IsResourceShareShared(
+ ) CONST;
+
+ protected:
+
+
+ DECLARE_CONSTRUCTOR( IO_DESCRIPTOR );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN UCHAR Option,
+ IN UCHAR Type,
+ IN UCHAR ShareDisposition,
+ IN USHORT Flags
+ );
+
+#if DBG
+ VIRTUAL
+ VOID
+ DbgDumpObject(
+ );
+#endif
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ UCHAR _Option;
+ UCHAR _Type;
+ UCHAR _ShareDisposition;
+ USHORT _Flags;
+};
+
+
+INLINE
+BOOLEAN
+IO_DESCRIPTOR::Initialize(
+ IN UCHAR Option,
+ IN UCHAR Type,
+ IN UCHAR ShareDisposition,
+ IN USHORT Flags
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes an object of type IO_DESCRIPTOR.
+
+Arguments:
+
+ Option -
+
+ Type -
+
+ ShareDisposition -
+
+ Flags -
+
+
+Return Value:
+
+ Returns TRUE if the initialization succeeded, or FALSE otherwise.
+
+
+--*/
+
+
+{
+ _Option = Option;
+ _Type = Type;
+ _ShareDisposition = ShareDisposition;
+ _Flags = Flags;
+ return( TRUE );
+}
+
+
+INLINE
+UCHAR
+IO_DESCRIPTOR::GetOption(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the device descriptor's share disposition.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns the device descriptor's share disposition.
+
+
+--*/
+
+
+{
+ return( _Option );
+}
+
+
+INLINE
+UCHAR
+IO_DESCRIPTOR::GetShareDisposition(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the device descriptor's share disposition.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns the device descriptor's share disposition.
+
+
+--*/
+
+
+{
+ return( _ShareDisposition );
+}
+
+
+INLINE
+USHORT
+IO_DESCRIPTOR::GetFlags(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the device descriptor's flags.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns the device descriptor's flags.
+
+
+--*/
+
+
+{
+ return( _Flags );
+}
+
+
+INLINE
+BOOLEAN
+IO_DESCRIPTOR::IsDescriptorTypePort(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine whether or not this object represents a IO_PORT_DESCRIPTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns TRUE if the object represents a IO_PORT_DESCRIPTOR.
+
+
+--*/
+
+
+{
+ return( _Type == CmResourceTypePort );
+}
+
+
+INLINE
+BOOLEAN
+IO_DESCRIPTOR::IsDescriptorTypeInterrupt(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine whether or not this object represents a IO_INTERRUPT_DESCRIPTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns TRUE if the object represents a IO_INTERRUPT_DESCRIPTOR.
+
+
+--*/
+
+
+{
+ return( _Type == CmResourceTypeInterrupt );
+}
+
+
+INLINE
+BOOLEAN
+IO_DESCRIPTOR::IsDescriptorTypeMemory(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine whether or not this object represents a IO_DESCRIPTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns TRUE if the object represents a IO_MEMORY_DESCRIPTOR.
+
+
+--*/
+
+
+{
+ return( _Type == CmResourceTypeMemory );
+}
+
+
+INLINE
+BOOLEAN
+IO_DESCRIPTOR::IsDescriptorTypeDma(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine whether or not this object represents a IO_DMA_DESCRIPTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns TRUE if the object represents a IO_DMA_DESCRIPTOR.
+
+
+--*/
+
+
+{
+ return( _Type == CmResourceTypeDma );
+}
+
+
+INLINE
+BOOLEAN
+IO_DESCRIPTOR::IsResourceOptionPreferred(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine whether or not the option of the device represented by this object
+ has the IO_RESOURCE_PREFERRED bit set.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns TRUE if the resource option has IO_RESOURCE_PREFERRED bit set.
+
+
+--*/
+
+
+{
+ return( ( _Option & IO_RESOURCE_PREFERRED ) == IO_RESOURCE_PREFERRED );
+}
+
+
+INLINE
+BOOLEAN
+IO_DESCRIPTOR::IsResourceOptionAlternative(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine whether or not the option of the device represented by this object
+ has the IO_RESOURCE_ALTERNATIVE bit set.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns TRUE if the resource option has IO_RESOURCE_ALTERNATIVE bit set.
+
+
+--*/
+
+
+{
+ return( ( _Option & IO_RESOURCE_ALTERNATIVE ) == IO_RESOURCE_ALTERNATIVE );
+}
+
+
+INLINE
+BOOLEAN
+IO_DESCRIPTOR::IsResourceShareUndetermined(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine whether or not the share of the device represented by this object
+ is undetermined.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns TRUE if the share is undetermined.
+
+
+--*/
+
+
+{
+ return( _ShareDisposition == CmResourceShareUndetermined );
+}
+
+
+INLINE
+BOOLEAN
+IO_DESCRIPTOR::IsResourceShareDeviceExclusive(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine whether or not the share of the device represented by this object
+ is device exclusive.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns TRUE if the share is device exclusive.
+
+
+--*/
+
+
+{
+ return( _ShareDisposition == CmResourceShareDeviceExclusive );
+}
+
+
+INLINE
+BOOLEAN
+IO_DESCRIPTOR::IsResourceShareDriverExclusive(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine whether or not the share of the device represented by this object
+ is driver exclusive.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns TRUE if the share is driver exclusive.
+
+
+--*/
+
+
+{
+ return( _ShareDisposition == CmResourceShareDriverExclusive );
+}
+
+
+INLINE
+BOOLEAN
+IO_DESCRIPTOR::IsResourceShareShared(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine whether or not the share of the device represented by this object
+ is shared.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns TRUE if the share is shared.
+
+
+--*/
+
+
+{
+ return( _ShareDisposition == CmResourceShareShared );
+}
+
+// #endif // _IO_DESCRIPTOR_
+
+
+// #if !defined( _IO_PORT_DESCRIPTOR_ )
+
+// #define _IO_PORT_DESCRIPTOR_
+
+// #define _NTAPI_ULIB_
+// #include "ulib.hxx"
+// #include "ntconfig.h"
+
+DECLARE_CLASS( IO_PORT_DESCRIPTOR );
+
+
+class IO_PORT_DESCRIPTOR : public IO_DESCRIPTOR {
+
+ public:
+
+ NONVIRTUAL
+ ~IO_PORT_DESCRIPTOR(
+ );
+
+ DECLARE_CONSTRUCTOR( IO_PORT_DESCRIPTOR );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN ULONG Length,
+ IN ULONG Alignment,
+ IN PPHYSICAL_ADDRESS MinimumAddress,
+ IN PPHYSICAL_ADDRESS MaximumAddress,
+ IN UCHAR Option,
+ IN UCHAR ShareDisposition,
+ IN USHORT Flags
+ );
+
+ NONVIRTUAL
+ ULONG
+ GetAlignment(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetLength(
+ ) CONST;
+
+ NONVIRTUAL
+ PPHYSICAL_ADDRESS
+ GetMinimumAddress(
+ ); // CONST;
+
+ NONVIRTUAL
+ PPHYSICAL_ADDRESS
+ GetMaximumAddress(
+ ); // CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsPortIo(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsPortMemory(
+ ) CONST;
+
+
+#if DBG
+ VIRTUAL
+ VOID
+ DbgDumpObject(
+ );
+#endif
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ ULONG _Length;
+ ULONG _Alignment;
+ PHYSICAL_ADDRESS _MinimumAddress;
+ PHYSICAL_ADDRESS _MaximumAddress;
+};
+
+
+
+INLINE
+BOOLEAN
+IO_PORT_DESCRIPTOR::Initialize(
+ IN ULONG Length,
+ IN ULONG Alignment,
+ IN PPHYSICAL_ADDRESS MinimumAddress,
+ IN PPHYSICAL_ADDRESS MaximumAddress,
+ IN UCHAR Option,
+ IN UCHAR ShareDisposition,
+ IN USHORT Flags
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize a PORT_DESCRIPTOR object.
+
+Arguments:
+
+ Length -
+
+ Alignment -
+
+ MinimumAddress -
+
+ MaximumAddress -
+
+ Option -
+
+ ShareDisposition -
+
+ Flags -
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeeds.
+
+--*/
+
+
+{
+ _Length = Length;
+ _Alignment = Alignment;
+ _MinimumAddress = *MinimumAddress;
+ _MaximumAddress = *MaximumAddress;
+ return( IO_DESCRIPTOR::Initialize( Option,
+ CmResourceTypePort,
+ ShareDisposition,
+ Flags ) );
+}
+
+
+INLINE
+ULONG
+IO_PORT_DESCRIPTOR::GetLength(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the port's length.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - Return the port's length.
+
+--*/
+
+
+{
+ return( _Length );
+}
+
+
+INLINE
+ULONG
+IO_PORT_DESCRIPTOR::GetAlignment(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the port's alignment.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - Port's alignment.
+
+
+--*/
+
+
+{
+ return( _Alignment );
+}
+
+
+INLINE
+PPHYSICAL_ADDRESS
+IO_PORT_DESCRIPTOR::GetMinimumAddress(
+ ) // CONST
+
+/*++
+
+Routine Description:
+
+ Returns the port's minimum address.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PPHYSICAL_ADDRESS - Pointer to the structure that describes the port's
+ minimum address.
+
+
+--*/
+
+
+{
+ return( &_MinimumAddress );
+}
+
+
+INLINE
+PPHYSICAL_ADDRESS
+IO_PORT_DESCRIPTOR::GetMaximumAddress(
+ ) // CONST
+
+/*++
+
+Routine Description:
+
+ Returns the port's maximum address.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PPHYSICAL_ADDRESS - Pointer to the structure that describes the port's
+ maximum address.
+
+
+--*/
+
+
+{
+ return( &_MaximumAddress );
+}
+
+
+INLINE
+BOOLEAN
+IO_PORT_DESCRIPTOR::IsPortIo(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return whether or not the port is an I/O.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the port is an I/O.
+ Returns FALSE otherwise.
+
+--*/
+
+
+{
+ return( ( IO_DESCRIPTOR::GetFlags() & CM_RESOURCE_PORT_IO ) ==
+ CM_RESOURCE_PORT_IO );
+}
+
+
+INLINE
+BOOLEAN
+IO_PORT_DESCRIPTOR::IsPortMemory(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return whether or not the port is mapped in memory.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the port is mapped in memory.
+ Returns FALSE otherwise.
+
+--*/
+
+
+{
+ return( IO_DESCRIPTOR::GetFlags() == CM_RESOURCE_PORT_MEMORY );
+}
+
+
+// #endif // _IO_PORT_DESCRIPTOR_
+
+// #if !defined( _IO_INTERRUPT_DESCRIPTOR_ )
+
+// #define _IO_INTERRUPT_DESCRIPTOR_
+
+// #define _NTAPI_ULIB_
+// #include "ulib.hxx"
+// #include "ntconfig.h"
+
+
+DECLARE_CLASS( IO_INTERRUPT_DESCRIPTOR );
+
+
+class IO_INTERRUPT_DESCRIPTOR : public IO_DESCRIPTOR {
+
+ public:
+
+ NONVIRTUAL
+ ~IO_INTERRUPT_DESCRIPTOR(
+ );
+
+ DECLARE_CONSTRUCTOR( IO_INTERRUPT_DESCRIPTOR );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN ULONG MinimumVector,
+ IN ULONG MaximumVector,
+ IN UCHAR Option,
+ IN UCHAR ShareDisposition,
+ IN USHORT Flags
+ );
+
+ NONVIRTUAL
+ ULONG
+ GetMinimumVector(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetMaximumVector(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsInterruptLevelSensitive(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsInterruptLatched(
+ ) CONST;
+
+
+#if DBG
+ VIRTUAL
+ VOID
+ DbgDumpObject(
+ );
+#endif
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ ULONG _MinimumVector;
+ ULONG _MaximumVector;
+};
+
+
+INLINE
+BOOLEAN
+IO_INTERRUPT_DESCRIPTOR::Initialize(
+ IN ULONG MinimumVector,
+ IN ULONG MaximumVector,
+ IN UCHAR Option,
+ IN UCHAR ShareDisposition,
+ IN USHORT Flags
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize an IO_INTERRUPT_DESCRIPTOR object.
+
+Arguments:
+
+ MinimumVector -
+
+ MaximumVector -
+
+ Option -
+
+ ShareDisposition -
+
+ Flags -
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeeds.
+
+--*/
+
+
+{
+ _MinimumVector = MinimumVector;
+ _MaximumVector = MaximumVector;
+ return( IO_DESCRIPTOR::Initialize( Option,
+ CmResourceTypeInterrupt,
+ ShareDisposition,
+ Flags ) );
+}
+
+
+INLINE
+ULONG
+IO_INTERRUPT_DESCRIPTOR::GetMinimumVector(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the interrupt's minimum vector.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - Interrupt's minimum vector.
+
+
+--*/
+
+
+{
+ return( _MinimumVector );
+}
+
+
+INLINE
+ULONG
+IO_INTERRUPT_DESCRIPTOR::GetMaximumVector(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the interrupt's maximum vector.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - Return the interrupt's maximum vector.
+
+--*/
+
+
+{
+ return( _MaximumVector );
+}
+
+
+INLINE
+BOOLEAN
+IO_INTERRUPT_DESCRIPTOR::IsInterruptLevelSensitive(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return whether or not the interrupt is level sensitive.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Return TRUE if the interrupt is level sensitive.
+
+--*/
+
+
+{
+ return( IO_DESCRIPTOR::GetFlags() == CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE );
+}
+
+
+INLINE
+BOOLEAN
+IO_INTERRUPT_DESCRIPTOR::IsInterruptLatched(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return whether or not the interrupt is latched.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Return TRUE if the interrupt is latched.
+
+--*/
+
+
+{
+ return( ( IO_DESCRIPTOR::GetFlags() & CM_RESOURCE_INTERRUPT_LATCHED ) ==
+ CM_RESOURCE_INTERRUPT_LATCHED );
+}
+
+
+// #endif // _IO_INTERRUPT_DESCRIPTOR_
+
+// #if !defined( _IO_MEMORY_DESCRIPTOR_ )
+
+// #define _MEMORY_DESCRIPTOR_
+
+// #define _NTAPI_ULIB_
+// #include "ulib.hxx"
+// #include "ntconfig.h"
+
+
+DECLARE_CLASS( IO_MEMORY_DESCRIPTOR );
+
+
+class IO_MEMORY_DESCRIPTOR : public IO_DESCRIPTOR {
+
+ public:
+
+ NONVIRTUAL
+ ~IO_MEMORY_DESCRIPTOR(
+ );
+
+ DECLARE_CONSTRUCTOR( IO_MEMORY_DESCRIPTOR );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN ULONG Length,
+ IN ULONG Alignment,
+ IN PPHYSICAL_ADDRESS MinimumAddress,
+ IN PPHYSICAL_ADDRESS MaximumAddress,
+ IN UCHAR Option,
+ IN UCHAR ShareDisposition,
+ IN USHORT Flags
+ );
+
+ NONVIRTUAL
+ ULONG
+ GetAlignment(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetLength(
+ ) CONST;
+
+ NONVIRTUAL
+ PPHYSICAL_ADDRESS
+ GetMinimumAddress(
+ ); // CONST;
+
+ NONVIRTUAL
+ PPHYSICAL_ADDRESS
+ GetMaximumAddress(
+ ); // CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsMemoryReadWrite(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsMemoryReadOnly(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsMemoryWriteOnly(
+ ) CONST;
+
+#if DBG
+ VIRTUAL
+ VOID
+ DbgDumpObject(
+ );
+#endif
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ ULONG _Length;
+ ULONG _Alignment;
+ PHYSICAL_ADDRESS _MinimumAddress;
+ PHYSICAL_ADDRESS _MaximumAddress;
+};
+
+
+INLINE
+BOOLEAN
+IO_MEMORY_DESCRIPTOR::Initialize(
+ IN ULONG Length,
+ IN ULONG Alignment,
+ IN PPHYSICAL_ADDRESS MinimumAddress,
+ IN PPHYSICAL_ADDRESS MaximumAddress,
+ IN UCHAR Option,
+ IN UCHAR ShareDisposition,
+ IN USHORT Flags
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize an IO_MEMORY_DESCRIPTOR object.
+
+Arguments:
+
+ Length -
+
+ Alignment -
+
+ MinimumAddress -
+
+ MaximumAddress -
+
+ Option -
+
+ ShareDisposition -
+
+ Flags -
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeeds.
+
+--*/
+
+
+{
+ _Length = Length;
+ _Alignment = Alignment;
+ _MinimumAddress = *MinimumAddress;
+ _MaximumAddress = *MaximumAddress;
+ return( IO_DESCRIPTOR::Initialize( Option,
+ CmResourceTypeMemory,
+ ShareDisposition,
+ Flags ) );
+}
+
+
+INLINE
+ULONG
+IO_MEMORY_DESCRIPTOR::GetAlignment(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the memory's alignment.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - Memory's alignment.
+
+
+--*/
+
+
+{
+ return( _Alignment );
+}
+
+
+INLINE
+ULONG
+IO_MEMORY_DESCRIPTOR::GetLength(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the memory's length.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - Return the memory's length.
+
+--*/
+
+
+{
+ return( _Length );
+}
+
+
+INLINE
+PPHYSICAL_ADDRESS
+IO_MEMORY_DESCRIPTOR::GetMinimumAddress(
+ ) // CONST
+
+/*++
+
+Routine Description:
+
+ Returns the memory's minimum address.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PPHYSICAL_ADDRESS - Memory's minimum address.
+
+
+--*/
+
+
+{
+ return( &_MinimumAddress );
+}
+
+
+INLINE
+PPHYSICAL_ADDRESS
+IO_MEMORY_DESCRIPTOR::GetMaximumAddress(
+ ) // CONST
+
+/*++
+
+Routine Description:
+
+ Returns the memory's maximum address.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PPHYSICAL_ADDRESS - Memory's maximum address.
+
+
+--*/
+
+
+{
+ return( &_MaximumAddress );
+}
+
+
+INLINE
+BOOLEAN
+IO_MEMORY_DESCRIPTOR::IsMemoryReadWrite(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return whether or not the memory is Read/Write.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Return TRUE if the memory is Read/Write.
+
+--*/
+
+
+{
+ return( IO_DESCRIPTOR::GetFlags() == CM_RESOURCE_MEMORY_READ_WRITE );
+}
+
+
+INLINE
+BOOLEAN
+IO_MEMORY_DESCRIPTOR::IsMemoryReadOnly(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return whether or not the memory is ReadOnly.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Return TRUE if the memory is ReadOnly.
+
+--*/
+
+
+{
+ return( ( IO_DESCRIPTOR::GetFlags() & CM_RESOURCE_MEMORY_READ_ONLY ) ==
+ CM_RESOURCE_MEMORY_READ_ONLY );
+}
+
+
+INLINE
+BOOLEAN
+IO_MEMORY_DESCRIPTOR::IsMemoryWriteOnly(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return whether or not the memory is WriteOnly.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Return TRUE if the memory is WriteOnly.
+
+--*/
+
+
+{
+ return( ( IO_DESCRIPTOR::GetFlags() & CM_RESOURCE_MEMORY_WRITE_ONLY ) ==
+ CM_RESOURCE_MEMORY_WRITE_ONLY );
+}
+
+
+// #endif // _IO_MEMORY_DESCRIPTOR_
+
+// #if !defined( _IO_DMA_DESCRIPTOR_ )
+
+// #define _IO_DMA_DESCRIPTOR_
+
+// #define _NTAPI_ULIB_
+// #include "ulib.hxx"
+// #include "ntconfig.h"
+
+
+DECLARE_CLASS( IO_DMA_DESCRIPTOR );
+
+
+class IO_DMA_DESCRIPTOR : public IO_DESCRIPTOR {
+
+ public:
+
+ NONVIRTUAL
+ ~IO_DMA_DESCRIPTOR(
+ );
+
+ DECLARE_CONSTRUCTOR( IO_DMA_DESCRIPTOR );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN ULONG MinimumChannel,
+ IN ULONG MaximumChannel,
+ IN UCHAR Option,
+ IN UCHAR ShareDisposition,
+ IN USHORT Flags
+ );
+
+ NONVIRTUAL
+ ULONG
+ GetMinimumChannel(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetMaximumChannel(
+ ) CONST;
+
+#if DBG
+ VIRTUAL
+ VOID
+ DbgDumpObject(
+ );
+#endif
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ ULONG _MinimumChannel;
+ ULONG _MaximumChannel;
+};
+
+
+INLINE
+BOOLEAN
+IO_DMA_DESCRIPTOR::Initialize(
+ IN ULONG MinimumChannel,
+ IN ULONG MaximumChannel,
+ IN UCHAR Option,
+ IN UCHAR ShareDisposition,
+ IN USHORT Flags
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize an IO_DMA_DESCRIPTOR object.
+
+Arguments:
+
+ MinimumChannel -
+
+ MaximumChannel -
+
+ Option -
+
+ ShareDisposition -
+
+ Flags -
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeeds.
+
+--*/
+
+
+{
+ _MinimumChannel = MinimumChannel;
+ _MaximumChannel = MaximumChannel;
+ return( IO_DESCRIPTOR::Initialize( Option,
+ CmResourceTypeDma,
+ ShareDisposition,
+ Flags ) );
+}
+
+
+INLINE
+ULONG
+IO_DMA_DESCRIPTOR::GetMinimumChannel(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the DMA's minimum channel.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - Return the DMA's minimum channel.
+
+--*/
+
+
+{
+ return( _MinimumChannel );
+}
+
+
+INLINE
+ULONG
+IO_DMA_DESCRIPTOR::GetMaximumChannel(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the DMA's maximum channel.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - Return the DMA's maximum channel.
+
+--*/
+
+
+{
+ return( _MaximumChannel );
+}
+
+// #endif // _IO_DMA_DESCRIPTOR_
+
+
+#endif // _IO_DESCRIPTOR_
diff --git a/private/utils/regedit/inc/regioreq.hxx b/private/utils/regedit/inc/regioreq.hxx
new file mode 100644
index 000000000..71f48e67b
--- /dev/null
+++ b/private/utils/regedit/inc/regioreq.hxx
@@ -0,0 +1,308 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ regioreqr.hxx
+
+Abstract:
+
+ This module contains the declarations for the IO_REQUIREMENTS_LIST
+ class. This class models models an IO_RESOURCE_REQUIREMENTS_LIST
+ structure, used on registry data of type REG_IO_RESOURCE_REQUIREMENTS_LIST.
+
+
+Author:
+
+ Jaime Sasson (jaimes) 01-Dec-1993
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+
+#if !defined( _IO_REQUIREMENTS_LIST_ )
+
+#define _IO_REQUIREMENTS_LIST_
+
+#include "ulib.hxx"
+#include "array.hxx"
+
+DECLARE_CLASS( IO_REQUIREMENTS_LIST );
+
+
+class IO_REQUIREMENTS_LIST : OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( IO_REQUIREMENTS_LIST );
+
+ VIRTUAL
+ ~IO_REQUIREMENTS_LIST(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PCBYTE Data,
+ IN ULONG DataSize
+ );
+
+ NONVIRTUAL
+ INTERFACE_TYPE
+ GetInterfaceType(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetBusNumber(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetSlotNumber(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetReserved1(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetReserved2(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetReserved3(
+ ) CONST;
+
+ NONVIRTUAL
+ PARRAY
+ GetAlternativeLists(
+ ) CONST;
+
+#if DBG
+ NONVIRTUAL
+ VOID
+ DbgDumpObject(
+ );
+#endif
+
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ INTERFACE_TYPE _InterfaceType;
+ ULONG _BusNumber;
+ ULONG _SlotNumber;
+ ULONG _Reserved1;
+ ULONG _Reserved2;
+ ULONG _Reserved3;
+ PARRAY _AlternativeLists;
+};
+
+
+INLINE
+INTERFACE_TYPE
+IO_REQUIREMENTS_LIST::GetInterfaceType(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the interface type of the requirement lists represented
+ by this object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns the interface type.
+
+--*/
+
+{
+ return( _InterfaceType );
+}
+
+
+INLINE
+ULONG
+IO_REQUIREMENTS_LIST::GetBusNumber(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the bus number of the requirement lists represented
+ by this object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - Returns the bus number.
+
+--*/
+
+{
+ return( _BusNumber );
+}
+
+
+INLINE
+ULONG
+IO_REQUIREMENTS_LIST::GetSlotNumber(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the slot number of the requirement lists represented
+ by this object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - Returns the slot number.
+
+--*/
+
+{
+ return( _BusNumber );
+}
+
+
+INLINE
+ULONG
+IO_REQUIREMENTS_LIST::GetReserved1(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the first reserved data of the requirement lists represented
+ by this object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - Returns the first reserved data.
+
+--*/
+
+{
+ return( _Reserved1 );
+}
+
+
+INLINE
+ULONG
+IO_REQUIREMENTS_LIST::GetReserved2(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the second reserved data of the requirement lists represented
+ by this object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - Returns the second reserved data.
+
+--*/
+
+{
+ return( _Reserved2 );
+}
+
+
+INLINE
+ULONG
+IO_REQUIREMENTS_LIST::GetReserved3(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the third reserved data of the requirement lists represented
+ by this object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - Returns the third reserved data.
+
+--*/
+
+{
+ return( _Reserved3 );
+}
+
+
+INLINE
+PARRAY
+IO_REQUIREMENTS_LIST::GetAlternativeLists(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return a pointer to the array that contains the alternative
+ lists.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PARRAY - Pointer to the array that contains the full resource descriptors.
+
+--*/
+
+{
+ return( _AlternativeLists );
+}
+
+#endif // _IO_REQUIREMENTS_LIST_
diff --git a/private/utils/regedit/inc/regresls.hxx b/private/utils/regedit/inc/regresls.hxx
new file mode 100644
index 000000000..49ccdc9a8
--- /dev/null
+++ b/private/utils/regedit/inc/regresls.hxx
@@ -0,0 +1,110 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ regresls.hxx
+
+Abstract:
+
+ This module contains the declarations for the RESOURCE_LIST
+ class. This class models models a CM_RESOURCE_LIST structure,
+ used on registry data of type REG_RESOURCE_LIST.
+
+
+Author:
+
+ Jaime Sasson (jaimes) 01-Dec-1993
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+
+#if !defined( _RESOURCE_LIST_ )
+
+#define _RESOURCE_LIST_
+
+#include "ulib.hxx"
+#include "array.hxx"
+
+DECLARE_CLASS( RESOURCE_LIST );
+
+
+class RESOURCE_LIST : OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( RESOURCE_LIST );
+
+ VIRTUAL
+ ~RESOURCE_LIST(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PCBYTE Data,
+ IN ULONG DataSize
+ );
+
+ NONVIRTUAL
+ PARRAY
+ GetFullResourceDescriptors(
+ ) CONST;
+
+#if DBG
+ NONVIRTUAL
+ VOID
+ DbgDumpObject(
+ );
+#endif
+
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ PARRAY _FullResourceDescriptors;
+};
+
+
+INLINE
+PARRAY
+RESOURCE_LIST::GetFullResourceDescriptors(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return a pointer to the array that contains the full resource
+ descriptors.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PARRAY - Pointer to the array that contains the full resource descriptors.
+
+--*/
+
+{
+ return( _FullResourceDescriptors );
+}
+
+#endif // _RESOURCE_LIST_
diff --git a/private/utils/regedit/inc/regsys.hxx b/private/utils/regedit/inc/regsys.hxx
new file mode 100644
index 000000000..88a2b139a
--- /dev/null
+++ b/private/utils/regedit/inc/regsys.hxx
@@ -0,0 +1,67 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ basesys.hxx
+
+Abstract:
+
+ This class contains the methods thta retrieve a message from a
+ resource file.
+
+Author:
+
+ David J. Gilman (davegi) 13-Jan-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if !defined( _REGEDIT_BASE_SYSTEM_DEFN_ )
+
+#define _REGEDIT_BASE_SYSTEM_DEFN_
+
+// #include "message.hxx"
+
+#include "wstring.hxx"
+#include <stdarg.h>
+
+DEFINE_TYPE( ULONG, MSGID );
+
+
+class REGEDIT_BASE_SYSTEM {
+
+ public:
+
+ STATIC
+ BOOLEAN
+ QueryResourceString(
+ OUT PWSTRING ResourceString,
+ IN MSGID MsgId,
+ IN PCSTR Format ...
+ );
+
+ STATIC
+ BOOLEAN
+ QueryResourceStringV(
+ OUT PWSTRING ResourceString,
+ IN MSGID MsgId,
+ IN PCSTR Format,
+ IN va_list VarPointer
+ );
+
+ STATIC
+ PWSTRING
+ QueryString(
+ IN MSGID MsgId,
+ IN PCSTR Format ...
+ );
+
+};
+
+
+#endif // _REGEDIT_BASE_SYSTEM_DEFN_
diff --git a/private/utils/regedit/inc/regwin.hxx b/private/utils/regedit/inc/regwin.hxx
new file mode 100644
index 000000000..d511ee7f4
--- /dev/null
+++ b/private/utils/regedit/inc/regwin.hxx
@@ -0,0 +1,263 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ Regwin.hxx
+
+Abstract:
+
+ This module contains the declaration for the REGISTRY_WINDOW
+ window class. REGISTRY_WINDOW models the MDI client windows.
+ Only a REGEDIT window can construct and initialize a REGISTRY_WINDOW
+ object.
+
+Author:
+
+ David J. Gilman (davegi) 02-Aug-1991
+
+Environment:
+
+ Ulib, Regedit, Windows, User Mode
+
+--*/
+#if ! defined( _REGISTRY_WINDOW_ )
+
+#define _REGISTRY_WINDOW_
+
+#include "ulib.hxx"
+#include "uapp.hxx"
+#include "window.hxx"
+#include "wstring.hxx"
+#include "regedval.hxx"
+#include "datavw.hxx"
+#include "regedit.hxx"
+#include "commdlg.h"
+
+typedef struct _NOTIFICATION_THREAD_INFO {
+ PREGISTRY_WINDOW RegistryWindow;
+ HANDLE NotificationEvent;
+ HANDLE AutoRefreshEvent;
+ } NOTIFICATION_THREAD_INFO, *PNOTIFICATION_THREAD_INFO;
+
+
+DECLARE_CLASS( REGISTRY_WINDOW );
+DECLARE_CLASS( REGEDIT_INTERNAL_REGISTRY );
+DECLARE_CLASS( REGEDIT_NODE );
+
+
+LPDWORD NotificationThread( PVOID );
+
+
+class REGISTRY_WINDOW : public WINDOW {
+
+
+ friend LONG
+ APIENTRY
+ EXPORT
+ MainWndProc (
+ IN HWND hWnd,
+ IN WORD wMessage,
+ IN WPARAM wParam,
+ IN LONG lParam
+ );
+
+ friend BOOLEAN OpenRegistry( PCWSTRING );
+
+ friend PREGISTRY_WINDOW OpenRegistryWindow( PREDEFINED_KEY,
+ PREGISTRY_WINDOW_SET );
+
+ friend LPDWORD
+ NotificationThread(
+ IN PVOID NotificationInfo
+ );
+
+ friend BOOL
+ APIENTRY
+ EXPORT
+ CloseRemoteRegistries (
+ IN HWND hWnd,
+ IN LONG lParam
+ );
+
+ friend BOOL
+ APIENTRY
+ EXPORT
+ SaveRegistryWindowsInfo (
+ IN HWND hWnd,
+ IN LONG lParam
+ );
+
+
+
+
+
+ public:
+
+ DECLARE_CAST_MEMBER_FUNCTION( REGISTRY_WINDOW );
+
+
+ private:
+
+ DECLARE_CONSTRUCTOR( REGISTRY_WINDOW );
+
+ DECLARE_WNDPROC( REGISTRY_WINDOW );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ IN HWND MDIHandle,
+ IN PCWSTRING Title,
+ IN PREGEDIT_INTERNAL_REGISTRY InternalRegistry,
+ IN PREGISTRY_WINDOW_SET RegistryWindowSet,
+ IN PWINDOW_POSITION WindowPosition
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CreateNotificationThread(
+ );
+
+ NONVIRTUAL
+ VOID
+ DisableNotificationThread(
+ );
+
+ NONVIRTUAL
+ VOID
+ EnableNotificationThread(
+ );
+
+ NONVIRTUAL
+ PCREGEDIT_NODE
+ GetCurrentNode(
+ ) CONST;
+
+ NONVIRTUAL
+ PCREGEDIT_FORMATTED_VALUE_ENTRY
+ GetCurrentValue(
+ ) CONST;
+
+ NONVIRTUAL
+ PREGEDIT_INTERNAL_REGISTRY
+ GetInternalRegistry(
+ ) CONST;
+
+ VOID
+ InitMenu(
+ IN HMENU Menu,
+ IN INT PopupMenu
+ );
+
+ VOID
+ LButtonDown(
+ IN LONG XPos
+ );
+
+ NONVIRTUAL
+ STATIC
+ BOOLEAN
+ Register (
+ );
+
+ VOID
+ Resize(
+ IN INT NewWidth,
+ IN INT NewHeight
+ );
+
+
+ STATIC
+ LPWSTR _WindowClassName;
+
+ STATIC
+ BOOLEAN _Registered;
+
+ STATIC
+ HCURSOR _SplitCursor;
+
+ PREGEDIT_INTERNAL_REGISTRY _IR;
+
+ PTREE_STRUCTURE_VIEW _StructureView;
+ PDATA_VIEW _DataView;
+
+ INT _Split;
+
+ BOOLEAN _TreeViewFocus;
+
+ HANDLE _NotificationEvent;
+
+ STATIC
+ BOOLEAN _ProcessRefreshMessage;
+
+ BOOLEAN _ReceivedRefreshMessage;
+
+ HANDLE _NotificationThreadHandle;
+
+ PREGISTRY_WINDOW_SET _RegistryWindowSet;
+
+ BOOLEAN _RefreshFlag;
+
+
+
+};
+
+
+
+INLINE
+PREGEDIT_INTERNAL_REGISTRY
+REGISTRY_WINDOW::GetInternalRegistry (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the pointer to the INTERNAL_REGISTRY object that is displayed
+ in the current window
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PREGEDIT_INTERNAL_REGISTRY - Pointer to the internal registry
+
+--*/
+
+{
+ return _IR;
+}
+
+
+INLINE
+PCREGEDIT_FORMATTED_VALUE_ENTRY
+REGISTRY_WINDOW::GetCurrentValue (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the pointer to the value currently selected in the data view.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PCFORMATTED_VALUE_ENTRY - Pointer to the currently selected value
+
+--*/
+
+{
+ return( _DataView->GetCurrentValue() );
+}
+
+
+
+#endif // _REGISTRY_WINDOW_
diff --git a/private/utils/regedit/inc/resource.h b/private/utils/regedit/inc/resource.h
new file mode 100644
index 000000000..43a1a5e80
--- /dev/null
+++ b/private/utils/regedit/inc/resource.h
@@ -0,0 +1,120 @@
+#define FILE_MENU 0
+
+#define IDM_OPEN_REGISTRY 9
+#define IDM_CLOSE_REGISTRY 10
+#define IDM_SAVE_REGISTRY_ON 15
+#define IDM_PRINT 20
+#define IDM_PRINTER_SETUP 25
+#define IDM_EXIT 30
+#define IDM_SAVE_VALUE_BINARY 35
+#define IDM_SELECT_COMPUTER 40
+#define IDM_LOAD_HIVE 45
+#define IDM_UNLOAD_HIVE 50
+#define IDM_RESTORE_KEY 55
+#define IDM_RESTORE_KEY_VOLATILE 56
+#define IDM_SAVE_KEY 65
+
+#define EDIT_MENU 1
+#define IDM_CUT 105
+#define IDM_COPY 110
+#define IDM_PASTE 115
+#define IDM_INSERT 120
+#define IDM_ADD_KEY 121
+#define IDM_ADD_VALUE 122
+#define IDM_DELETE 125
+#define IDM_BINARY 130
+#define IDM_FILENAME 135
+#define IDM_RGB 140
+#define IDM_STRING 145
+#define IDM_ULONG 150
+#define IDM_MULTISZ 155
+
+#define TREE_MENU 2
+#define IDM_EXPAND_ONE_LEVEL 205
+#define IDM_EXPAND_BRANCH 210
+#define IDM_EXPAND_ALL 215
+#define IDM_COLLAPSE_BRANCH 220
+
+#define VIEW_MENU 3
+#define IDM_TREE_AND_DATA 305
+#define IDM_TREE_ONLY 310
+#define IDM_DATA_ONLY 315
+#define IDM_SPLIT 320
+#define IDM_DISPLAY_BINARY 325
+#define IDM_FONT 330
+#define IDM_REFRESH 335
+#define IDM_REFRESH_ALL 336
+#define ID_TOGGLE_FOCUS 340
+#define ID_ENTER_KEY 350
+#define IDM_FIND_KEY 355
+
+
+#define SECURITY_MENU 4
+#define IDM_PERMISSIONS 405
+#define IDM_AUDITING 410
+#define IDM_OWNER 415
+
+#define OPTIONS_MENU 5
+#define IDM_TOGGLE_AUTO_REFRESH 505
+#define IDM_TOGGLE_SAVE_SETTINGS 510
+#define IDM_TOGGLE_READ_ONLY_MODE 515
+#define IDM_TOGGLE_REMOTE_ACCESS 520
+#define IDM_TOGGLE_CONFIRM_ON_DELETE 525
+
+#define WINDOW_MENU 6 // 5
+#define IDM_CASCADE 605 // 505
+#define IDM_TILE 610 // 510
+#define IDM_ARRANGE 615
+
+#define HELP_MENU 7 // 6
+#define IDM_CONTENTS 701 // 601
+#define IDM_SEARCH_FOR_HELP 702 // 602
+#define IDM_HOW_TO_USE_HELP 703 // 603
+#define IDM_ABOUT 705 // 605
+
+
+#define IDI_REGEDIT 1313
+#define FIRST_CHILD 1000
+
+#if 0
+#define IDD_HELP 100
+#define IDD_EDIT 101
+#define IDD_DECIMAL 102
+#define IDD_BINARY 103
+#define IDD_HEX 104
+#endif
+
+//
+// BUGBUG - W-Barry - Define all user messages here....
+//
+#define TR_NEWCURSEL (WM_USER+0x100)
+
+#define DATAVW_DBL_CLICK (WM_USER+0x110)
+
+#define RE_OPEN_LOCAL_REGISTRY (WM_USER+0x200)
+
+#define INFORM_CHANGE_FONT (WM_USER+0x300)
+
+#define REFRESH_WINDOW (WM_USER+0x400)
+#define REFRESH_ALL_WINDOWS (WM_USER+0x401)
+
+#define TREE_VIEW_FOCUS (WM_USER+0x500)
+
+#define DATA_VIEW_FOCUS (WM_USER+0x600)
+
+#define TOGGLE_FOCUS (WM_USER+0x700)
+
+#define FIND_KEY (WM_USER+0x750)
+
+#define SELECT_NODE (WM_USER+0x800)
+
+#define REGEDIT_HELP_KEY (WM_USER+0x850)
+
+#define LOAD_HIVE (WM_USER+0x900)
+
+#define UNLOAD_HIVE (WM_USER+0x950)
+
+#define RESTORE_KEY (WM_USER+0xa00)
+#define RESTORE_KEY_VOLATILE (WM_USER+0xa01)
+
+#define SAVE_KEY (WM_USER+0xa50)
diff --git a/private/utils/regedit/inc/treevw.hxx b/private/utils/regedit/inc/treevw.hxx
new file mode 100644
index 000000000..a7a508ddd
--- /dev/null
+++ b/private/utils/regedit/inc/treevw.hxx
@@ -0,0 +1,362 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ treevw.hxx
+
+Abstract:
+
+ This module contains the declaration for the TREE_STRUCTURE_VIEW
+ class. TREE_STRUCTURE_VIEW models the display of the structure of a tree.
+
+Author:
+
+ Bruce W. Wilson (w-wilson) 14-Aug-1991
+
+Environment:
+
+ Ulib, Regedit, Windows, User Mode
+
+--*/
+#if ! defined( _TREE_STRUCTURE_VIEW_ )
+
+#define _TREE_STRUCTURE_VIEW_
+
+#include "ulib.hxx"
+#include "uapp.hxx"
+#include "window.hxx"
+#include "sedapi.h"
+
+DECLARE_CLASS( REGEDIT_NODE );
+DECLARE_CLASS( REGEDIT_INTERNAL_REGISTRY );
+DECLARE_CLASS( TREE_STRUCTURE_VIEW );
+
+class TREE_STRUCTURE_VIEW : public WINDOW {
+
+ friend class REGISTRY_WINDOW;
+
+ public:
+
+ DECLARE_CONSTRUCTOR( TREE_STRUCTURE_VIEW );
+
+ DECLARE_CAST_MEMBER_FUNCTION( TREE_STRUCTURE_VIEW );
+
+
+ VOID
+ Resize(
+ IN INT NewX,
+ IN INT NewY,
+ IN INT NewWidth,
+ IN INT NewHeight
+ );
+
+// private:
+
+ DECLARE_WNDPROC( TREE_STRUCTURE_VIEW );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ IN HWND ParentHandle,
+ IN PREGEDIT_INTERNAL_REGISTRY IR
+ );
+
+ NONVIRTUAL
+ STATIC
+ BOOL
+ APIENTRY
+ EXPORT
+ GetKeyNameDialogProc(
+ HWND hDlg,
+ WORD msg,
+ WPARAM wParam,
+ LONG lParam
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ AddNode(
+ );
+
+
+ VOID
+ CollapseCurrentItem(
+ );
+
+ VOID
+ DrawItem(
+ LPDRAWITEMSTRUCT lpLBItem
+ );
+
+ VOID
+ ExpandCurrentItem(
+ IN INT Depth DEFAULT 1
+ );
+
+ PCREGEDIT_NODE
+ GetCurrentNode(
+ );
+
+ PCREGEDIT_NODE
+ GetNode(
+ IN INT Item
+ );
+
+ VOID
+ InitMenu(
+ IN HMENU Menu,
+ IN INT PopupMenu
+ );
+
+ INT
+ InsertTreeToListBox(
+ IN PCREGEDIT_NODE root,
+ IN INT InsertPoint,
+ IN INT Depth
+ );
+
+ BOOL
+ IsItemAfterAChild(
+ IN INT Item
+ );
+
+ BOOL
+ IsItemAfterSibling(
+ IN INT Item
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ ProcessSaveKeyMessage(
+ IN PCWSTRING FileName
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ProcessRestoreKeyMessage(
+ IN PCWSTRING FileName,
+ IN BOOLEAN Volatile
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ProcessLoadHiveMessage(
+ IN PCWSTRING FileName
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ProcessUnLoadHiveMessage(
+ );
+
+ NONVIRTUAL
+ STATIC
+ BOOLEAN
+ Register (
+ );
+
+ VOID
+ ToggleCurrentItem(
+ );
+
+
+ NONVIRTUAL
+ VOID
+ RedisplayUpdatedSubTree(
+ IN PCREGEDIT_NODE Root
+ );
+
+ NONVIRTUAL
+ ULONG
+ InsertUpdatedSubTreeToListBox(
+ IN PCREGEDIT_NODE Root,
+ IN ULONG Position
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DeleteCurrentItem(
+ );
+
+ NONVIRTUAL
+ VOID
+ InvokeSecurityEditor(
+ IN BOOLEAN DaclEditor
+ );
+
+ NONVIRTUAL
+ VOID
+ InvokeTakeOwnershipEditor(
+ );
+
+ NONVIRTUAL
+ DWORD
+ SetSecurityDescriptor(
+ IN HWND hwndParent,
+ IN ULONG CallBackContext,
+ IN PSECURITY_DESCRIPTOR SecDesc,
+ IN PSECURITY_DESCRIPTOR SecDescNewObjects,
+ IN BOOLEAN ApplyToSubContainers,
+ IN BOOLEAN ApplyToSubObjects,
+ OUT LPDWORD StatusReturn
+ );
+
+ VOID
+ SelectNode(
+ IN PCREGEDIT_NODE Node
+ );
+
+
+
+
+
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ ChangeItemHeight(
+ );
+
+
+ NONVIRTUAL
+ VOID
+ AdjustHorizontalScrollBar(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ InitializeSedAppAccessArrays(
+ );
+
+
+ STATIC
+ LPWSTR _WindowClassName;
+
+ STATIC
+ BOOLEAN _Registered;
+
+ HWND _hwndList;
+ BOOLEAN _HasFocus;
+
+
+ //
+ // Data members related used by the permission editor and
+ // SACL editor
+ //
+
+ STATIC
+ BOOLEAN _SedAppAccessInitialized;
+
+ STATIC
+ ULONG _MsgIdKeyPermNames[];
+
+ STATIC
+ ULONG _MsgIdKeyAuditNames[];
+
+
+ STATIC
+ SED_APPLICATION_ACCESS _SedAppAccessKeyPerms[];
+
+ STATIC
+ SED_APPLICATION_ACCESS _SedAppAccessKeyAudits[];
+
+ STATIC
+ PWSTRING _MsgSpecialAccessTitle;
+
+ STATIC
+ PWSTRING _MsgObjectTypeName;
+
+ STATIC
+ PWSTRING _MsgHelpFileName;
+
+ STATIC
+ PWSTRING _MsgApplyPermissionToSubKeys;
+
+ STATIC
+ PWSTRING _MsgAuditPermissionOfSubKeys;
+
+ STATIC
+ PWSTRING _MsgConfirmApplyToSubKeys;
+
+ STATIC
+ PWSTRING _MsgConfirmAuditSubKeys;
+
+ STATIC
+ PWSTRING _MsgDefaultPermissionName;
+
+
+ //
+ // some stuff cached for speed
+ //
+ INT _Items;
+ INT _CurrentItem;
+ PCREGEDIT_NODE _CurrentNode;
+ PREGEDIT_INTERNAL_REGISTRY _IR;
+ LONG _CurrentWidth;
+ LONG _MaxWidth;
+
+};
+
+INLINE
+VOID
+TREE_STRUCTURE_VIEW::AdjustHorizontalScrollBar(
+)
+/*++
+
+Routine Description:
+
+ Sets the extent of the horizontal scroll bar so that the longest
+ string in the listbox can be viewed.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ SendMessage( _hwndList, LB_SETHORIZONTALEXTENT, (UINT)_MaxWidth, 0 );
+}
+
+
+
+
+
+
+INLINE
+VOID
+TREE_STRUCTURE_VIEW::Resize(
+ IN INT NewX,
+ IN INT NewY,
+ IN INT NewWidth,
+ IN INT NewHeight
+) {
+ _CurrentWidth = NewWidth;
+ MoveWindow( _Handle, NewX, NewY, NewWidth, NewHeight, TRUE );
+}
+
+INLINE
+PCREGEDIT_NODE
+TREE_STRUCTURE_VIEW::GetNode(
+ IN INT Item
+) {
+ return( (PCREGEDIT_NODE)::SendMessage( _hwndList, LB_GETITEMDATA, Item, 0 ) );
+}
+
+INLINE
+PCREGEDIT_NODE
+TREE_STRUCTURE_VIEW::GetCurrentNode(
+) {
+ return( _CurrentNode );
+}
+
+#endif // _TREE_STRUCTURE_VIEW_
diff --git a/private/utils/regedit/inc/uapp.hxx b/private/utils/regedit/inc/uapp.hxx
new file mode 100644
index 000000000..b76e66bc6
--- /dev/null
+++ b/private/utils/regedit/inc/uapp.hxx
@@ -0,0 +1,184 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Uapp.hxx
+
+Abstract:
+
+
+Author:
+
+ David J. Gilman (davegi) - Jul-1991
+
+Environment:
+
+ ULIB, User Mode, Windows
+
+--*/
+
+
+#if !defined( _USER_APPLICATION_ )
+
+#define _USER_APPLICATION_
+
+#include "ulib.hxx"
+
+
+//
+// Initialization routine for the class descriptors...
+//
+BOOLEAN
+InitializeUapp (
+);
+
+//
+// Additional macros required for porting...
+//
+
+
+#define LO_HANDLE( wp, lp ) ( lp )
+#define LPMBYTE LPBYTE
+#define WNDPROCFN WNDPROC
+
+
+
+//
+// Augmented (beyond standard headers) VOID pointer types
+//
+
+DEFINE_POINTER_TYPES( VOID );
+
+//
+// Function Modifiers
+//
+
+#define EXPORT
+
+
+DECLARE_CLASS( DATA_VIEW );
+DECLARE_CLASS( OBJECT );
+DECLARE_CLASS( PRINT_MANAGER );
+DECLARE_CLASS( REGISTRY_WINDOW );
+DECLARE_CLASS( TREE_STRUCTURE_VIEW );
+
+
+
+//
+// This Pointer Support
+//
+
+INLINE
+POBJECT
+GetObjectPointer (
+ IN HWND Handle
+ )
+
+{
+ return ( POBJECT )GetWindowLong( Handle, GWL_USERDATA );
+}
+
+INLINE
+DWORD
+SetObjectPointer (
+ IN HWND Handle,
+ IN PCOBJECT Object
+ )
+
+{
+ return( SetWindowLong( Handle, GWL_USERDATA, (DWORD)Object ) );
+}
+
+
+//
+// WndProc Declaration
+//
+
+#define DECLARE_WNDPROC( class ) \
+ NONVIRTUAL \
+ STATIC \
+ LONG \
+ APIENTRY \
+ EXPORT \
+ class::WndProc ( \
+ HWND hWnd, \
+ WORD iMessage, \
+ WPARAM wParam, \
+ LONG lParam )
+
+//
+// DlgProc Declaration
+//
+
+#define DECLARE_DLGPROC( class, name ) \
+ NONVIRTUAL \
+ STATIC \
+ BOOL \
+ APIENTRY \
+ EXPORT \
+ class::name ( \
+ HWND hWnd, \
+ WORD iMessage, \
+ WPARAM wParam, \
+ LONG lParam )
+
+//
+// Windows Debug Support
+//
+
+#if DBG==1
+
+#include <stdlib.h>
+
+#define DbgWinAssert( exp ) \
+ DebugWinAssert( exp, #exp, __FILE__, __LINE__ )
+
+#define DbgWinPrint( str ) \
+ DebugWinPrint( "Debug Message", str, (int)MB_ICONINFORMATION, \
+ __FILE__, __LINE__ )
+
+#define DbgWinAbort( str ) \
+ DebugWinPrint( "Abort Message", str, (int)MB_ICONSTOP, \
+ __FILE__, __LINE__ ); \
+ PostQuitMessage( -1 )
+
+#define DbgWinPtrAssert( ptr ) \
+ if( ptr == NULL ) { \
+ DbgWinPrint( "NULL Pointer" ); \
+ PostQuitMessage( -1 ); \
+ }
+
+
+VOID
+DebugWinAssert (
+ IN BOOL Expression,
+ IN PSTR ExpressionString,
+ IN PSTR FileName,
+ IN INT LineNumber
+ );
+
+VOID
+DebugWinPrint (
+ IN PSTR Caption,
+ IN PSTR String,
+ IN INT Style,
+ IN PSTR FileName,
+ IN INT LineNumber
+ );
+
+#else // DBG
+
+#define DbgWinAssert( exp )
+
+#define DbgWinPrint( str )
+
+#define DbgWinAbort( str )
+
+#define DbgWinPtrAssert( ptr )
+
+#endif // DBG
+
+
+#endif // _USER_APPLICATION_
diff --git a/private/utils/regedit/inc/winapp.hxx b/private/utils/regedit/inc/winapp.hxx
new file mode 100644
index 000000000..51086482b
--- /dev/null
+++ b/private/utils/regedit/inc/winapp.hxx
@@ -0,0 +1,1005 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ Winapp.hxx
+
+Abstract:
+
+ This module contains the declaration for the WINDOWS_APPLICATION
+ class.
+ The WINDOWS_APPLICATION class contains all variables global to
+ Regedit.
+
+Author:
+
+ David J. Gilman (davegi) 02-Aug-1991
+
+Environment:
+
+ Ulib, Regedit, Windows, User Mode
+
+--*/
+
+#if !defined( _WINDOWS_APPLICATION_ )
+
+#define _WINDOWS_APPLICATION_
+
+// DECLARE_CLASS( REGEDIT );
+DECLARE_CLASS( WINDOWS_APPLICATION );
+
+class WINDOWS_APPLICATION : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( WINDOWS_APPLICATION );
+
+ DECLARE_CAST_MEMBER_FUNCTION( WINDOWS_APPLICATION );
+
+ NONVIRTUAL
+ STATIC
+ BOOLEAN
+ Initialize (
+ IN HANDLE Instance,
+ IN HANDLE PreviousInstance,
+ IN INT ShowCommand,
+ IN LPWSTR CommandLine
+ );
+
+ NONVIRTUAL
+ STATIC
+ HCURSOR
+ DisplayHourGlass(
+ );
+
+ NONVIRTUAL
+ STATIC
+ BOOLEAN
+ IsAutoRefreshEnabled(
+ );
+
+ NONVIRTUAL
+ STATIC
+ VOID
+ EnableAutoRefresh(
+ );
+
+ NONVIRTUAL
+ STATIC
+ VOID
+ DisableAutoRefresh(
+ );
+
+ NONVIRTUAL
+ STATIC
+ BOOLEAN
+ IsConfirmOnDeleteEnabled(
+ );
+
+ NONVIRTUAL
+ STATIC
+ VOID
+ EnableConfirmOnDelete(
+ );
+
+ NONVIRTUAL
+ STATIC
+ VOID
+ DisableConfirmOnDelete(
+ );
+
+ NONVIRTUAL
+ STATIC
+ BOOLEAN
+ IsReadOnlyModeEnabled(
+ );
+
+ NONVIRTUAL
+ STATIC
+ VOID
+ EnableReadOnlyMode(
+ );
+
+ NONVIRTUAL
+ STATIC
+ VOID
+ DisableReadOnlyMode(
+ );
+
+// NONVIRTUAL
+// STATIC
+// BOOLEAN
+// IsRemoteAccessEnabled(
+// ) CONST;
+//
+// NONVIRTUAL
+// STATIC
+// VOID
+// EnableRemoteAccess(
+// );
+//
+// NONVIRTUAL
+// STATIC
+// VOID
+// DisableRemoteAccess(
+// );
+
+ NONVIRTUAL
+ STATIC
+ BOOLEAN
+ IsSaveSettingsEnabled(
+ );
+
+ NONVIRTUAL
+ STATIC
+ VOID
+ EnableSaveSettings(
+ );
+
+ NONVIRTUAL
+ STATIC
+ VOID
+ DisableSaveSettings(
+ );
+
+ NONVIRTUAL
+ STATIC
+ VOID
+ RestoreCursor(
+ IN HCURSOR Cursor
+ );
+
+ NONVIRTUAL
+ STATIC
+ HFONT
+ GetCurrentHFont(
+ );
+
+ NONVIRTUAL
+ STATIC
+ HANDLE
+ QueryInstance (
+ );
+
+ NONVIRTUAL
+ STATIC
+ HANDLE
+ QueryPreviousInstance (
+ );
+
+ NONVIRTUAL
+ STATIC
+ INT
+ QueryShowCommand (
+ );
+
+ NONVIRTUAL
+ STATIC
+ LPWSTR
+ QueryCmdLine (
+ );
+
+
+ NONVIRTUAL
+ STATIC
+ LPWSTR
+ GetApplicationName (
+ );
+
+ NONVIRTUAL
+ STATIC
+ VOID
+ SetCurrentHFont(
+ IN HFONT HFont
+ );
+
+ NONVIRTUAL
+ STATIC
+ LONG
+ GetHelpContext(
+ );
+
+ NONVIRTUAL
+ STATIC
+ VOID
+ SetHelpContext(
+ IN LONG HelpContext
+ );
+
+ NONVIRTUAL
+ STATIC
+ BOOLEAN
+ LoadBitmaps(
+ );
+
+ NONVIRTUAL
+ STATIC
+ VOID
+ DeleteBitmaps(
+ );
+
+ NONVIRTUAL
+ STATIC
+ HDC
+ GetCompatibleMemoryDeviceContext(
+ );
+
+ STATIC
+ BOOLEAN _ChildWindowMaximized;
+
+ STATIC
+ BOOLEAN _SACLEditorEnabled;
+
+
+ STATIC
+ HANDLE _AutoRefreshEvent;
+
+ STATIC
+ HWND _hDlgFindReplace;
+
+ STATIC
+ LONG _RestorePrivilege;
+
+ STATIC
+ LONG _BackupPrivilege;
+
+ STATIC
+ BOOLEAN _TakeOwnershipPrivilege;
+
+ STATIC
+ HBITMAP _hbmBitmaps;
+
+ STATIC
+ HBITMAP _hbmSave;
+
+ STATIC
+ HDC _hdcMem;
+
+
+
+ private:
+
+ STATIC
+ HANDLE _Instance;
+
+ STATIC
+ HANDLE _PreviousInstance;
+
+ STATIC
+ INT _ShowCommand;
+
+ STATIC
+ LPWSTR _CmdLine;
+
+ STATIC
+ LPWSTR _ApplicationName;
+
+ STATIC
+ HFONT _HFont;
+
+ STATIC
+ BOOLEAN _AutoRefreshEnabled;
+
+ STATIC
+ BOOLEAN _ReadOnlyMode;
+
+ STATIC
+ BOOLEAN _RemoteAccessEnabled;
+
+ STATIC
+ BOOLEAN _ConfirmOnDelete;
+
+ STATIC
+ BOOLEAN _SaveSettings;
+
+ STATIC
+ LONG _HelpContext;
+
+
+};
+
+INLINE
+HFONT
+WINDOWS_APPLICATION::GetCurrentHFont (
+ )
+
+/*++
+
+Routine Description:
+
+ Returns the value that identifies the current logical font.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ HFONT - The value that identifies the current font.
+
+--*/
+
+{
+ return _HFont;
+}
+
+
+INLINE
+VOID
+WINDOWS_APPLICATION::SetCurrentHFont (
+ IN HFONT HFont
+ )
+
+/*++
+
+Routine Description:
+
+ Save the value that identifies the current logical font.
+
+Arguments:
+
+ HFONT - Value that identifies the logical font
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _HFont = HFont;
+}
+
+
+
+
+INLINE
+HANDLE
+WINDOWS_APPLICATION::QueryInstance (
+ )
+
+/*++
+
+Routine Description:
+
+ Returns the instance handle.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ HANDLE - Returns the instance handle.
+
+--*/
+
+{
+ return _Instance;
+}
+
+INLINE
+HANDLE
+WINDOWS_APPLICATION::QueryPreviousInstance (
+ )
+
+/*++
+
+Routine Description:
+
+ Returns the previous instance handle.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ HANDLE - Returns the previous instance handle.
+
+--*/
+
+{
+ return _PreviousInstance;
+}
+
+INLINE
+INT
+WINDOWS_APPLICATION::QueryShowCommand (
+ )
+
+/*++
+
+Routine Description:
+
+ Returns the initial window state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ INT - Returns the initial window state.
+
+--*/
+
+{
+ return _ShowCommand;
+}
+
+
+
+INLINE
+LPWSTR
+WINDOWS_APPLICATION::QueryCmdLine (
+ )
+
+/*++
+
+Routine Description:
+
+ Returns the pointer to the command line.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ LPWSTR - Pointer to the command line.
+
+--*/
+
+{
+ return _CmdLine;
+}
+
+
+
+INLINE
+LPWSTR
+WINDOWS_APPLICATION::GetApplicationName (
+ )
+
+/*++
+
+Routine Description:
+
+ Returns the pointer to the application name.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ LPWSTR - Pointer to the application name.
+
+--*/
+
+{
+ return _ApplicationName;
+}
+
+
+
+INLINE
+BOOLEAN
+WINDOWS_APPLICATION::IsAutoRefreshEnabled (
+ )
+
+/*++
+
+Routine Description:
+
+ Inform the client whether the auto refresh mechanism is enabled.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ return( _AutoRefreshEnabled );
+}
+
+
+
+INLINE
+VOID
+WINDOWS_APPLICATION::EnableAutoRefresh(
+ )
+
+/*++
+
+Routine Description:
+
+ Enable the auto refresh mechanism.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _AutoRefreshEnabled = TRUE;
+ if( ( _AutoRefreshEvent != NULL ) &&
+ ( WaitForSingleObject( _AutoRefreshEvent, 0 ) != 0 ) ) {
+ SetEvent( _AutoRefreshEvent );
+ }
+}
+
+
+
+
+INLINE
+VOID
+WINDOWS_APPLICATION::DisableAutoRefresh(
+ )
+
+/*++
+
+Routine Description:
+
+ Disable the auto refresh mechanism.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _AutoRefreshEnabled = FALSE;
+ if( ( _AutoRefreshEvent != NULL ) &&
+ ( WaitForSingleObject( _AutoRefreshEvent, 0 ) == 0 ) ) {
+ ResetEvent( _AutoRefreshEvent );
+ }
+}
+
+
+
+
+INLINE
+BOOLEAN
+WINDOWS_APPLICATION::IsReadOnlyModeEnabled (
+ )
+
+/*++
+
+Routine Description:
+
+ Inform the client whether the regedit is operating in the read only mode.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if regedit is operating in the read only mode.
+ Otherwise, returns FALSE
+
+
+--*/
+
+{
+ return( _ReadOnlyMode );
+}
+
+
+
+INLINE
+VOID
+WINDOWS_APPLICATION::EnableReadOnlyMode(
+ )
+
+/*++
+
+Routine Description:
+
+ Make regedit operate in the read only mode.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _ReadOnlyMode = TRUE;
+}
+
+
+
+
+INLINE
+VOID
+WINDOWS_APPLICATION::DisableReadOnlyMode(
+ )
+
+/*++
+
+Routine Description:
+
+ Disable the read only mode.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _ReadOnlyMode = FALSE;
+}
+
+#if 0
+
+INLINE
+BOOLEAN
+WINDOWS_APPLICATION::IsRemoteAccessEnabled(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Inform the client whether the regedit can access the registry of a remote
+ machine.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if regedit can access the registry of a remote
+ machine. Otherwise, returns FALSE
+
+
+--*/
+
+{
+ return( _RemoteAccessEnabled );
+}
+
+
+
+INLINE
+VOID
+WINDOWS_APPLICATION::EnableRemoteAccess(
+ )
+
+/*++
+
+Routine Description:
+
+ Allow regedit access the registry of a remote machine.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _RemoteAccessEnabled = TRUE;
+}
+
+
+
+
+INLINE
+VOID
+WINDOWS_APPLICATION::DisableRemoteAccess(
+ )
+
+/*++
+
+Routine Description:
+
+ Disable access to the registry of a remote machine.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _RemoteAccessEnabled = FALSE;
+}
+#endif
+
+
+
+INLINE
+BOOLEAN
+WINDOWS_APPLICATION::IsConfirmOnDeleteEnabled(
+ )
+
+/*++
+
+Routine Description:
+
+ Inform the client whether regedit should display a warning popup
+ to the user, before it deletes a key or a value entry.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if regedit should display a warning popup.
+ Otherwise, returns FALSE
+
+
+--*/
+
+{
+ return( _ConfirmOnDelete );
+}
+
+
+
+INLINE
+VOID
+WINDOWS_APPLICATION::EnableConfirmOnDelete(
+ )
+
+/*++
+
+Routine Description:
+
+ Enable warning popup on deletion of a key or value entry.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _ConfirmOnDelete = TRUE;
+}
+
+
+
+
+INLINE
+VOID
+WINDOWS_APPLICATION::DisableConfirmOnDelete(
+ )
+
+/*++
+
+Routine Description:
+
+ Disable warning popup on deletion of a key or value entry.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _ConfirmOnDelete = FALSE;
+}
+
+
+
+
+INLINE
+BOOLEAN
+WINDOWS_APPLICATION::IsSaveSettingsEnabled(
+ )
+
+/*++
+
+Routine Description:
+
+ Inform the client whether regedit should save all the settings
+ in the file regedit.ini.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if save settins is enabled.
+ Otherwise, returns FALSE
+
+
+--*/
+
+{
+ return( _SaveSettings );
+}
+
+
+
+INLINE
+VOID
+WINDOWS_APPLICATION::EnableSaveSettings(
+ )
+
+/*++
+
+Routine Description:
+
+ Allow regedit to save settings on exit.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _SaveSettings = TRUE;
+}
+
+
+
+
+INLINE
+VOID
+WINDOWS_APPLICATION::DisableSaveSettings(
+ )
+
+/*++
+
+Routine Description:
+
+ Disable save settings on exit.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _SaveSettings = FALSE;
+}
+
+
+
+
+INLINE
+VOID
+WINDOWS_APPLICATION::SetHelpContext(
+ IN LONG HelpContext
+ )
+
+/*++
+
+Routine Description:
+
+ Set the current help context.
+
+Arguments:
+
+ HelpContext - The new help context for regedit.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _HelpContext = HelpContext;
+}
+
+
+
+
+INLINE
+LONG
+WINDOWS_APPLICATION::GetHelpContext(
+ )
+
+/*++
+
+Routine Description:
+
+ Returns to the client the currenthelp context.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ LONG - The current help context.
+
+--*/
+
+{
+ return( _HelpContext );
+}
+
+
+INLINE
+HDC
+WINDOWS_APPLICATION::GetCompatibleMemoryDeviceContext(
+ )
+
+/*++
+
+Routine Description:
+
+ Returns the current memory device context.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ HDC - Handle of memory device context
+
+--*/
+
+{
+ return( _hdcMem );
+}
+
+
+
+#endif // _WINDOWS_APPLICATION_
diff --git a/private/utils/regedit/inc/window.hxx b/private/utils/regedit/inc/window.hxx
new file mode 100644
index 000000000..072d4b37c
--- /dev/null
+++ b/private/utils/regedit/inc/window.hxx
@@ -0,0 +1,78 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ Window.hxx
+
+Abstract:
+
+ This module contains the declaration for the WINDOW class. This class
+ is very simple and abstarct is not meant to be the root of any sort of
+ sophistaicated framework.
+
+Author:
+
+ David J. Gilman (davegi) 02-Aug-1991
+
+Environment:
+
+ Ulib, Regedit, Windows, User Mode
+
+--*/
+
+#if ! defined( _WINDOW_ )
+
+#define _WINDOW_
+
+DECLARE_CLASS( WINDOW );
+
+class WINDOW : public OBJECT {
+
+ public:
+
+ DECLARE_CAST_MEMBER_FUNCTION( WINDOW );
+
+ NONVIRTUAL
+ HWND
+ QueryHandle (
+ ) CONST;
+
+ protected:
+
+ DECLARE_CONSTRUCTOR( WINDOW );
+
+ VOID
+ WINDOW::Construct(
+ );
+
+ HWND _Handle;
+};
+
+INLINE
+HWND
+WINDOW::QueryHandle (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the HWND for the window that this object models.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ HWND - Returns the handle for the window that this class models.
+
+--*/
+
+{
+ return _Handle;
+}
+
+#endif // WINDOW
diff --git a/private/utils/regedit/src/bitmap.bmp b/private/utils/regedit/src/bitmap.bmp
new file mode 100644
index 000000000..9e1cff309
--- /dev/null
+++ b/private/utils/regedit/src/bitmap.bmp
Binary files differ
diff --git a/private/utils/regedit/src/datavw.cxx b/private/utils/regedit/src/datavw.cxx
new file mode 100644
index 000000000..2a59bed14
--- /dev/null
+++ b/private/utils/regedit/src/datavw.cxx
@@ -0,0 +1,1758 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ datavw.cxx
+
+Abstract:
+
+ Methods for DATA_VIEW class.
+
+Author:
+
+ Bruce W. Wilson (w-wilson) 14-Aug-1991
+
+Environment:
+
+ Ulib, Regedit, Windows, User Mode
+
+--*/
+#include <wchar.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "uapp.hxx"
+
+#include "iterator.hxx"
+
+#include "winapp.hxx"
+
+#include "regedir.hxx"
+#include "datavw.hxx"
+#include "editor.hxx"
+#include "regsys.hxx"
+#include "wstring.hxx"
+
+#include "regedval.hxx"
+
+#include "defmsg.h"
+#include "resource.h"
+#include "regedit.hxx"
+#include "regedit.hxx"
+
+#include "dialogs.h"
+#include "regedhlp.h"
+#include "winuserp.h"
+
+#include "regdata.hxx"
+
+//
+// Initialize DATA_VIEW's window class name and note that it
+// has not been registered. Also define static class data members.
+//
+
+LPWSTR DATA_VIEW::_WindowClassName = (LPWSTR)L"DATA_VIEW";
+BOOLEAN DATA_VIEW::_Registered = FALSE;
+PWSTRING DATA_VIEW::_RegBinaryString;
+PWSTRING DATA_VIEW::_RegDwordString;
+PWSTRING DATA_VIEW::_RegSzString;
+PWSTRING DATA_VIEW::_RegMultiSzString;
+PWSTRING DATA_VIEW::_RegExpandSzString;
+
+#define ENTER(x)
+#define LEAVE(x)
+#define MSG(x)
+
+extern INT dxText;
+extern INT dyText;
+extern INT dyBorder;
+extern INT dyBorderx2;
+extern INT dxFrame;
+extern INT dxFolder;
+extern INT dyFolder;
+
+
+
+DEFINE_CONSTRUCTOR( DATA_VIEW, WINDOW );
+
+DEFINE_CAST_MEMBER_FUNCTION( DATA_VIEW );
+
+
+
+
+BOOLEAN
+DATA_VIEW::Initialize (
+ IN HWND ParentHandle,
+ IN PREGEDIT_INTERNAL_REGISTRY IR
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize a DATA_VIEW object by registering its window class,
+ creating its window. If each of these is successful, the
+ window is displayed and updated.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the registration and creation operations
+ are successful.
+
+--*/
+
+{
+ HWND hWnd;
+
+ _CurrentValueName = NULL;
+ if( Register( )) {
+
+ //
+ // If the window class was succesfully registered attempt to
+ // create the frame window. Note that we pass the 'this' pointer
+ // to the window.
+ //
+
+ _IR = IR;
+ _Node = IR->GetRootNode();
+ _HasFocus = FALSE;
+ _MaxWidth = 0;
+
+ if(( hWnd = CreateWindow( _WindowClassName, NULL,
+ WS_CHILD | WS_VISIBLE,
+ CW_USEDEFAULT, 0,
+ CW_USEDEFAULT, 0,
+ ParentHandle, (HMENU)1,
+ (HINSTANCE)WINDOWS_APPLICATION::QueryInstance( ),
+ this )) != NULL ) {
+
+ DbgWinAssert( hWnd == _Handle );
+
+ _RegBinaryString = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_BINARY, "" );
+ _RegDwordString = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_DWORD, "" );
+ _RegSzString = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_SZ, "" );
+ _RegMultiSzString = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_MULTI_SZ, "" );
+ _RegExpandSzString = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_EXPAND_SZ, "" );
+
+ return TRUE;
+
+ } else {
+
+ //
+ // Creating the window failed.
+ //
+
+ return FALSE;
+ }
+ }
+ return FALSE;
+}
+
+
+VOID
+DATA_VIEW::DrawItem(
+ LPDRAWITEMSTRUCT lpLBItem
+ )
+
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+
+
+Return Value:
+
+
+--*/
+
+{
+ INT x, y, dx, dy;
+ HDC hdc;
+ INT len;
+ RECT rc;
+ BOOL bDrawSelected, bFocus;
+ PCREGEDIT_FORMATTED_VALUE_ENTRY pValue;
+ DWORD rgbText;
+ DWORD rgbBackground;
+ INT ItemID;
+
+ PCWSTRING FormattedString;
+ PWSTR String;
+
+
+ HFONT hFont;
+ HFONT PreviousHFont;
+ SIZE Size;
+
+#if 0
+ DebugPrintf("DATA::DrawItem\n");
+ DebugPrintf("CtlType = %x\n", lpLBItem->CtlType);
+ DebugPrintf("CtlID = %x\n", lpLBItem->CtlID);
+ DebugPrintf("itemID = %x\n", lpLBItem->itemID);
+ DebugPrintf("itemAction = %x\n", lpLBItem->itemAction);
+ DebugPrintf("itemState = %x\n", lpLBItem->itemState);
+ DebugPrintf("hwndItem = %x\n", lpLBItem->hwndItem);
+ DebugPrintf("hDC = %x\n", lpLBItem->hDC);
+ DebugPrintf("rcItem = (%x, %x)\n", lpLBItem->rcItem.top, lpLBItem->rcItem.left);
+ DebugPrintf("itemData = %x\n\n", lpLBItem->itemData);
+#endif
+
+ DbgWinAssert( lpLBItem->CtlType & ODT_LISTBOX );
+ //
+ // itemID == -1 means empty list box so let defwndproc draw the dotted
+ // rectangle
+ //
+ if( (ItemID = lpLBItem->itemID) == -1) {
+ return;
+ }
+
+ //
+ // extract DC and pointer to node into IR from DRAWITEM struct
+ //
+ hdc = lpLBItem->hDC;
+ pValue = (PCREGEDIT_FORMATTED_VALUE_ENTRY)lpLBItem->itemData;
+
+ PreviousHFont = NULL;
+ if( ( hFont = WINDOWS_APPLICATION::GetCurrentHFont() ) != NULL ) {
+ PreviousHFont = (HFONT)SelectObject( hdc, hFont );
+ }
+
+ //
+ // determine length of name (in pixels?)
+ //
+ FormattedString = pValue->GetFormattedString();
+ DebugPtrAssert( FormattedString );
+ len = ( INT )FormattedString->QueryChCount();
+ String = FormattedString->QueryWSTR();
+ DebugPtrAssert( String );
+ if (!String) {
+ return;
+ }
+ GetTextExtentPoint( hdc, String, len, &Size );
+ dx = ( INT )Size.cx;
+
+ dx += dyBorder;
+
+ //
+ // determine size of rectangle we can draw in (or what we need?]
+ //
+ rc = lpLBItem->rcItem;
+ rc.left = 0;
+ rc.right = rc.left + dx + 4 * dyBorderx2;
+
+ if (lpLBItem->itemAction & (ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS)) {
+
+ x = dyBorderx2 - dxText;
+ dy = ( INT )( lpLBItem->rcItem.bottom - lpLBItem->rcItem.top );
+ y = ( INT )( lpLBItem->rcItem.top + (dy/2) );
+
+ bDrawSelected = (lpLBItem->itemState & ODS_SELECTED);
+ bFocus = (lpLBItem->itemState & ODS_FOCUS);
+
+ if (bDrawSelected) {
+ if (bFocus) {
+ rgbBackground = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
+ rgbText = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
+ } else {
+ rgbBackground = SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
+ rgbText = SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
+ }
+ } else {
+ rgbBackground = SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
+ rgbText = SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
+ }
+
+ ExtTextOut(hdc, x + dxText, y-(dyText/2), ETO_OPAQUE, &rc,
+ String, len, NULL);
+
+ if (bDrawSelected) {
+ HBRUSH hbr;
+ if (hbr = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT))) {
+ FrameRect(hdc, &rc, hbr);
+ DeleteObject(hbr);
+ }
+ SetTextColor(hdc, rgbText);
+ SetBkColor(hdc, rgbBackground);
+ }
+ }
+
+ if ((lpLBItem->itemAction & ODA_FOCUS) && (lpLBItem->itemState & ODS_FOCUS)) {
+ DrawFocusRect(hdc, &rc);
+ }
+
+ FREE( String );
+
+
+ if( dx > _MaxWidth ) {
+ _MaxWidth = dx+dxText;
+ AdjustHorizontalScrollBar();
+ }
+
+ if( PreviousHFont != NULL ) {
+
+ SelectObject( hdc, PreviousHFont );
+ }
+
+
+ return;
+}
+
+
+VOID
+DATA_VIEW::ChangeItemHeight(
+ )
+
+/*++
+
+Routine Description:
+
+ Change the height of an item in a list box, to reflect the change in
+ the font size.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ HDC hDC;
+ HFONT hFont;
+ HFONT PreviousHFont;
+ SIZE Size;
+
+
+ hDC = GetDC( _hwndList );
+ hFont = WINDOWS_APPLICATION::GetCurrentHFont();
+ PreviousHFont = (HFONT)SelectObject( hDC, hFont );
+ if( PreviousHFont != NULL ) {
+
+ GetTextExtentPoint(hDC, (LPWSTR)L"M", 1, &Size );
+ dxText = ( INT )Size.cx;
+ dyText = ( INT )Size.cy;
+
+ dyBorder = GetSystemMetrics(SM_CYBORDER);
+ dyBorderx2 = dyBorder * 2;
+ dxFrame = GetSystemMetrics(SM_CXFRAME) - dyBorder;
+ SendMessage( _hwndList, LB_SETITEMHEIGHT, 0, dyText );
+ InvalidateRect( _hwndList, NULL, TRUE );
+
+ SelectObject( hDC, PreviousHFont );
+ }
+ ReleaseDC( _hwndList, hDC );
+}
+
+
+
+VOID
+DATA_VIEW::EditValue(
+ IN REG_TYPE EditAsType
+ )
+
+/*++
+
+Routine Description:
+
+ Edit the currently selected value entry using the editor whose type
+ was received as parameter.
+ If there is no item currently selected, no editor is called.
+
+Arguments:
+
+ EditAsType - Indicates the type of editor to be used to edit the
+ currently selected value entry.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ EDITOR editor;
+ PCREGEDIT_FORMATTED_VALUE_ENTRY CurrentValue;
+ ULONG cb;
+ PCBYTE DataIn;
+ PBYTE DataOut;
+ ULONG ErrorCode;
+ LONG SelectedItem;
+ BOOLEAN Status;
+ HCURSOR Cursor;
+ REG_TYPE DataType;
+
+ INT TextMessage;
+ INT CaptionMessage;
+
+ //
+ // Check if there is an item selected in the listbox
+ // If there is an item selected, extract the PVALUE that was stuffed
+ // into the owner-draw listbox.
+ // If unable to retrieve the value, return
+ //
+
+ CurrentValue = NULL;
+ if( ( ( SelectedItem = SendMessage( _hwndList,
+ LB_GETCURSEL,
+ 0,
+ 0 ) ) == LB_ERR ) ||
+ ( SendMessage( _hwndList,
+ LB_GETTEXT,
+ ( WPARAM )SelectedItem,
+ (LONG)&CurrentValue ) == LB_ERR ) ||
+
+ ( CurrentValue == NULL ) ) {
+
+ return;
+ }
+
+ if( WINDOWS_APPLICATION::IsReadOnlyModeEnabled() ) {
+ DisplayWarningPopup(_hwndList,
+ MSG_READONLY_MODE_EDIT_VALUE_EX,
+ MSG_WARNING_TITLE );
+ }
+
+ //
+ // get the data buffer from the value
+ //
+ cb = CurrentValue->GetData( &DataIn );
+ DataType = CurrentValue->GetType();
+
+ DataOut = (PBYTE)editor.Edit( _Handle,
+ DataType,
+ (PVOID)DataIn,
+ (ULONG)cb,
+ (PULONG)&cb,
+ EditAsType );
+
+ if( !WINDOWS_APPLICATION::IsReadOnlyModeEnabled() ) {
+ if( DataOut != NULL ) {
+
+ Cursor = WINDOWS_APPLICATION::DisplayHourGlass();
+ Status = _IR->ChangeValueData( _Node, CurrentValue, DataOut, cb, &ErrorCode );
+ WINDOWS_APPLICATION::RestoreCursor( Cursor );
+ if( Status ) {
+ SetDataNode( _Node, TRUE );
+ if( SelectedItem != LB_ERR ) {
+ SendMessage( _hwndList,
+ LB_SETCURSEL,
+ (WPARAM)SelectedItem,
+ 0 );
+ }
+ } else {
+ if (ErrorCode == REGEDIT_ERROR_ACCESS_DENIED) {
+ TextMessage = MSG_SAVE_VALUE_ACCESS_DENIED_EX;
+ CaptionMessage = MSG_ACCESS_DENIED;
+ } else if( ErrorCode == REGEDIT_ERROR_NODE_NOT_FOUND ) {
+ TextMessage = MSG_SAVE_VALUE_KEY_NOT_ACCESSIBLE_EX;
+ CaptionMessage = MSG_KEY_NOT_ACCESSIBLE;
+ } else if( ErrorCode == REGEDIT_ERROR_KEY_DELETED ) {
+ TextMessage = MSG_SAVE_VALUE_KEY_DELETED_EX;
+ CaptionMessage = MSG_KEY_MARKED_FOR_DELETION;
+ } else if( ErrorCode == REGEDIT_RPC_S_SERVER_UNAVAILABLE ) {
+ TextMessage = MSG_CANT_ACCESS_REMOTE_REGISTRY;
+ CaptionMessage = MSG_SERVER_UNAVAILABLE;
+ } else {
+ DebugPrint( "Unknown error code" );
+ DebugPrintf( "ErrorCode = %d \n", ErrorCode );
+ TextMessage = MSG_FAILED_OPERATION_EX;
+ CaptionMessage = 0;
+ }
+ DisplayInfoPopup(_hwndList,
+ TextMessage,
+ CaptionMessage);
+ }
+
+ }
+ }
+}
+
+
+BOOLEAN
+DATA_VIEW::Register (
+ )
+
+/*++
+
+Routine Description:
+
+ If required register the DATA_VIEW window class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the DATA_VIEW window class is registered.
+
+--*/
+
+{
+ WNDCLASS wndclass;
+
+ if( !_Registered ) {
+ _Registered = TRUE;
+
+ //
+ // If RegEdit is not already running and REGEDIT was not already
+ // registered by this instance, register the REGEDIT window class.
+ //
+
+ wndclass.style = CS_HREDRAW | CS_VREDRAW;
+ wndclass.lpfnWndProc = (WNDPROCFN)DATA_VIEW::WndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = sizeof( DWORD );
+ wndclass.hInstance = (HINSTANCE)WINDOWS_APPLICATION::QueryInstance( );
+ wndclass.hIcon = NULL;
+ wndclass.hCursor = LoadCursor( NULL, IDC_ARROW );
+ wndclass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 );
+ wndclass.lpszMenuName = NULL;
+ wndclass.lpszClassName = _WindowClassName;
+
+ RegisterClass( &wndclass );
+ }
+ return TRUE;
+}
+
+
+VOID
+DATA_VIEW::InitMenu(
+ IN HMENU Menu,
+ IN INT PopupMenu
+ )
+
+/*++
+
+Routine Description:
+
+ Figures out which items of the pulldown menu which should be enabled
+ or grayed. Windows will generate a WM_INITMENUPOPUP just before a
+ pulldown menu is painted.
+
+ Passes the message along if it can't figure out the status of menu
+ items.
+
+
+Arguments:
+
+ Menu - handle of the main menu
+ PopupMenu - the item number of the pulldown menu. eg.
+ File menu is 0, Edit is 1.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ switch( PopupMenu ) {
+ case VIEW_MENU:
+ EnableMenuItem( Menu, ( UINT )IDM_DISPLAY_BINARY,
+ ( UINT )(_Items ? MF_ENABLED : MF_GRAYED));
+ break;
+
+ case EDIT_MENU:
+
+ if( WINDOWS_APPLICATION::IsReadOnlyModeEnabled() ) {
+ EnableMenuItem( Menu, ( UINT )IDM_ADD_VALUE, ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, ( UINT )IDM_ADD_KEY, ( UINT )MF_GRAYED );
+ } else {
+ EnableMenuItem( Menu, ( UINT )IDM_ADD_VALUE, ( UINT )MF_ENABLED );
+ EnableMenuItem( Menu, ( UINT )IDM_ADD_KEY, ( UINT )MF_ENABLED );
+ }
+ if( _Items == 0 ) {
+ EnableMenuItem( Menu, ( UINT )IDM_DISPLAY_BINARY, ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, ( UINT )IDM_DELETE, ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, ( UINT )IDM_BINARY, ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, ( UINT )IDM_STRING, ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, ( UINT )IDM_ULONG, ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, ( UINT )IDM_MULTISZ, ( UINT )MF_GRAYED );
+
+ } else {
+ EnableMenuItem( Menu, ( UINT )IDM_DISPLAY_BINARY, ( UINT )MF_ENABLED );
+ EnableMenuItem( Menu, ( UINT )IDM_BINARY, ( UINT )MF_ENABLED );
+ EnableMenuItem( Menu, ( UINT )IDM_STRING, ( UINT )MF_ENABLED );
+ EnableMenuItem( Menu, ( UINT )IDM_ULONG, ( UINT )MF_ENABLED );
+ EnableMenuItem( Menu, ( UINT )IDM_MULTISZ, ( UINT )MF_ENABLED );
+ if( WINDOWS_APPLICATION::IsReadOnlyModeEnabled() ) {
+ EnableMenuItem( Menu, ( UINT )IDM_DELETE, ( UINT )MF_GRAYED );
+ } else {
+ EnableMenuItem( Menu, ( UINT )IDM_DELETE, ( UINT )MF_ENABLED );
+ }
+ }
+ break;
+
+ case TREE_MENU:
+ EnableMenuItem( Menu, ( UINT )IDM_EXPAND_ONE_LEVEL, ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, ( UINT )IDM_EXPAND_BRANCH , ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, ( UINT )IDM_EXPAND_ALL , ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, ( UINT )IDM_COLLAPSE_BRANCH , ( UINT )MF_GRAYED );
+ break;
+
+ }
+}
+
+
+
+
+VOID
+DATA_VIEW::SetDataNode(
+ IN PCREGEDIT_NODE NewNode,
+ IN BOOLEAN ForceRefresh
+ )
+
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+
+
+Return Value:
+
+
+
+--*/
+
+{
+ PSORTED_LIST Values;
+ PITERATOR Iterator;
+ PCREGEDIT_FORMATTED_VALUE_ENTRY CurrentValue;
+ ULONG ErrorCode;
+
+ HCURSOR Cursor;
+ INT CurrentItem;
+ PCWSTRING TmpName;
+ INT Index;
+
+/*
+ if( NewNode == _Node && !ForceRefresh ) {
+ return;
+ }
+*/
+ _Node = NewNode;
+
+ // Disable redrawing.
+ SendMessage( _hwndList, WM_SETREDRAW, FALSE, 0L );
+
+ SendMessage( _hwndList, LB_RESETCONTENT, 0, 0L );
+
+ _MaxWidth = 0;
+ AdjustHorizontalScrollBar();
+
+//
+// FOR: preface entries in dataview (may contain parent/children
+// entries as well)
+//
+// ACTION: - add _PrefaceEntriesCount to object
+// - when handling a message determine if the item number
+// is > _PrefaceEntriesCount then pointer is PVALUE else ???
+// (see WM_DRAWITEM for more)
+// - stuff PNODE into listbox for entries in preface block,
+// PVALUE for value block
+//
+
+ if( ( _IR->AreValuesInMemory( NewNode ) ) ||
+ ( _IR->GetNumberOfValues( NewNode ) < 3 ) ) {
+ Values = _IR->GetValues( NewNode, &ErrorCode );
+ } else {
+ Cursor = WINDOWS_APPLICATION::DisplayHourGlass();
+ Values = _IR->GetValues( NewNode, &ErrorCode );
+ WINDOWS_APPLICATION::RestoreCursor( Cursor );
+ }
+ if( Values != NULL ) {
+ Iterator = Values->QueryIterator();
+ CurrentItem = LB_ERR;
+ Index = 0;
+ while( ( CurrentValue = (PCREGEDIT_FORMATTED_VALUE_ENTRY)Iterator->GetNext() ) != NULL ) {
+ SendMessage( _hwndList, LB_ADDSTRING, 0, (LONG)( CurrentValue ) );
+ TmpName = CurrentValue->GetName();
+ if( ( _CurrentValueName != NULL ) &&
+ ( TmpName != NULL ) &&
+ !_CurrentValueName->Stricmp( TmpName ) ) {
+ CurrentItem = Index;
+ DELETE( _CurrentValueName );
+ }
+ Index++;
+ }
+ DELETE( Iterator );
+ }
+
+ _Items = SendMessage( _hwndList, LB_GETCOUNT, 0, 0 );
+ if( CurrentItem != LB_ERR ){
+ SendMessage( _hwndList,
+ LB_SETCURSEL,
+ CurrentItem,
+ 0 );
+ }
+
+ // Re-enable redrawing and refresh the listbox
+ SendMessage( _hwndList, WM_SETREDRAW, TRUE, 0L );
+ InvalidateRect( _hwndList, NULL, TRUE );
+}
+
+
+
+LONG
+APIENTRY
+EXPORT
+DATA_VIEW::WndProc (
+ IN HWND hWnd,
+ IN WORD wMessage,
+ IN WPARAM wParam,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Handle all requests made of the DATA_VIEW window class.
+
+Arguments:
+
+ Standard Window's exported function signature.
+
+Return Value:
+
+ LONG - Returns 0 if the message was handled.
+
+--*/
+
+{
+ REGISTER PDATA_VIEW pDataView;
+ PCREGEDIT_FORMATTED_VALUE_ENTRY CurrentValue;
+ ULONG SelectedItem;
+ LONG SaveHelpContext;
+ PCBYTE Pointer;
+ ULONG Size;
+
+ //
+ // WM_CREATE is handled specially as it is when the connection between
+ // a Window and its associated object is established.
+ //
+
+ if( wMessage == WM_CREATE ) {
+
+ //
+ // Save 'this' to owning WINDOW Class and initialize the _Handle
+ // member data.
+ //
+
+ pDataView = ( PDATA_VIEW )
+ ((( LPCREATESTRUCT ) lParam )->lpCreateParams );
+ SetObjectPointer( hWnd, pDataView );
+ pDataView->_Handle = hWnd;
+
+
+ pDataView->_hwndList =
+ CreateWindow((LPWSTR)L"listbox",
+ NULL,
+ WS_CHILD | WS_VISIBLE | LBS_NOTIFY | WS_VSCROLL
+ | WS_HSCROLL | WS_BORDER | LBS_OWNERDRAWFIXED
+ | LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT,
+ CW_USEDEFAULT, 0,
+ CW_USEDEFAULT, 0,
+ hWnd, (HMENU)3,
+ (HINSTANCE)WINDOWS_APPLICATION::QueryInstance( ),
+ NULL);
+
+ pDataView->ChangeItemHeight();
+
+ pDataView->SetDataNode( pDataView->_Node, TRUE );
+ return 0;
+ }
+
+ //
+ // Retrieve 'this' pointer.
+ //
+
+ pDataView = ( PDATA_VIEW ) GetObjectPointer( hWnd );
+
+ //
+ // This 'if' clause is for all messages after WM_CREATE.
+ //
+
+ if( pDataView != NULL ) {
+
+ //
+ // Check the 'this' wasn't trampled.
+ //
+
+ DbgWinAssert( hWnd == pDataView->_Handle );
+
+ switch( wMessage ) {
+
+ case WM_DRAWITEM:
+//
+// ACTION: - add an if( item# > _PrefaceCount )
+// call DrawValueItem()
+// else
+// call DrawPrefaceItem()
+// - will do switch on item number to figure out
+// what data from node to draw
+
+ pDataView->DrawItem( (LPDRAWITEMSTRUCT)lParam );
+ break;
+
+ case WM_SETFOCUS:
+ pDataView->_HasFocus = TRUE;
+ SetFocus(pDataView->_hwndList);
+ SendMessage(GetParent(hWnd), DATA_VIEW_FOCUS, 0, 0);
+ break;
+
+ case WM_SIZE:
+ if( !IsIconic(GetParent(hWnd))) {
+
+
+
+ // size the window so it's left and bottom border fall outside
+ // it's parent and are thus clipped. this give the nice
+ // tight fitting scrollbar effect
+
+ //
+ // if we are maximized than we need to increase the height of
+ // the list box by two pixels so the top and bottom border
+ // won't show
+ // otherwise, increase by one pixel so top border won't show
+ //
+
+ MoveWindow(pDataView->_hwndList, 0, -1, LOWORD(lParam)+1, HIWORD(lParam)+2, TRUE);
+
+ }
+ break;
+
+ case INFORM_CHANGE_FONT:
+ pDataView->ChangeItemHeight();
+ break;
+
+ case DATAVW_DBL_CLICK:
+
+ if( ( pDataView->_Items != 0 ) &&
+ ( ( CurrentValue = pDataView->GetCurrentValue() ) != NULL ) ) {
+ if( ( CurrentValue->GetType() != TYPE_REG_RESOURCE_LIST ) &&
+ ( CurrentValue->GetType() != TYPE_REG_FULL_RESOURCE_DESCRIPTOR ) &&
+ ( CurrentValue->GetType() != TYPE_REG_RESOURCE_REQUIREMENTS_LIST )
+ ) {
+ //
+ // If there is a value entry currently selected,
+ // invoke the editor
+ //
+ pDataView->EditValue( CurrentValue->GetType() );
+ } else {
+
+ Size = CurrentValue->GetData( &Pointer );
+ REGISTRY_DATA::DisplayData( hWnd,
+ CurrentValue->GetType(),
+ Pointer,
+ Size );
+
+ }
+ }
+ break;
+
+
+ case WM_LBTRACKPOINT:
+ {
+ HDC hdc;
+ INT dx;
+ INT i;
+ INT len;
+ HFONT hFont;
+ HFONT PreviousHFont;
+ SIZE Size;
+
+ PCWSTRING FormattedString;
+ PWSTR String;
+
+
+ // wParam is the listbox index that we are over
+ // lParam is the mouse point
+
+ // Return 0 to do nothing,
+ // 1 to abort everything, or
+ // 2 to abort just dblclicks.
+
+
+ /* Get the node they clicked on. */
+ SendMessage(pDataView->_hwndList, LB_GETTEXT, wParam, (LONG)&CurrentValue);
+
+ // too FAR to the right?
+
+
+ hdc = GetDC(pDataView->_hwndList);
+
+ PreviousHFont = NULL;
+ if( ( hFont = WINDOWS_APPLICATION::GetCurrentHFont() ) != NULL ) {
+ PreviousHFont = (HFONT)SelectObject( hdc, hFont );
+ }
+
+
+ FormattedString = CurrentValue->GetFormattedString();
+ DebugPtrAssert( FormattedString );
+ len = ( INT )FormattedString->QueryChCount();
+ String = FormattedString->QueryWSTR();
+ DebugPtrAssert( String );
+ GetTextExtentPoint( hdc, String, len, &Size );
+ FREE( String );
+
+ dx = ( INT )Size.cx;
+ dx += dyBorderx2*2;
+
+ if( PreviousHFont != NULL ) {
+
+ SelectObject( hdc, PreviousHFont );
+ }
+ ReleaseDC( pDataView->_hwndList, hdc );
+
+ i = (WORD) lParam;
+ if( i > dx ) {
+ return 2; // yes
+ }
+
+ return DefWindowProc( hWnd, wMessage, wParam, lParam );
+ }
+
+
+ case WM_COMMAND:
+ if( ( HWND )lParam == 0 ) {
+ //
+ // this is a menu item command from above
+ //
+ switch( LOWORD( wParam ) ) {
+
+ case IDM_BINARY:
+ pDataView->EditValue( TYPE_REG_BINARY );
+ break;
+
+ case IDM_STRING:
+ pDataView->EditValue( TYPE_REG_SZ );
+ break;
+
+ case IDM_ULONG:
+ pDataView->EditValue( TYPE_REG_DWORD );
+ break;
+
+ case IDM_MULTISZ:
+ pDataView->EditValue( TYPE_REG_MULTI_SZ );
+ break;
+
+ case IDM_DELETE:
+
+ if( !WINDOWS_APPLICATION::IsReadOnlyModeEnabled() ) {
+ pDataView->DeleteCurrentItem();
+ }
+ break;
+
+ case IDM_INSERT:
+ case IDM_ADD_VALUE:
+
+ if( !WINDOWS_APPLICATION::IsReadOnlyModeEnabled() ) {
+ SaveHelpContext = WINDOWS_APPLICATION::GetHelpContext();
+ WINDOWS_APPLICATION::SetHelpContext( IDH_DB_ADDVALUE_REGED );
+ pDataView->AddValueEntry();
+ WINDOWS_APPLICATION::SetHelpContext( SaveHelpContext );
+ }
+ break;
+
+ case IDM_DISPLAY_BINARY:
+ if( ( pDataView->_Items != 0 ) &&
+ ( ( CurrentValue = pDataView->GetCurrentValue() ) != NULL ) ) {
+ Size = CurrentValue->GetData( &Pointer );
+ REGISTRY_DATA::DisplayData( hWnd,
+ CurrentValue->GetType(),
+ Pointer,
+ Size,
+ TRUE );
+ }
+ break;
+
+ case ID_ENTER_KEY:
+
+ if( ( pDataView->_Items != 0 ) &&
+ ( ( CurrentValue = pDataView->GetCurrentValue() ) != NULL ) ) {
+ if( ( CurrentValue->GetType() != TYPE_REG_RESOURCE_LIST ) &&
+ ( CurrentValue->GetType() != TYPE_REG_FULL_RESOURCE_DESCRIPTOR ) &&
+ ( CurrentValue->GetType() != TYPE_REG_RESOURCE_REQUIREMENTS_LIST )
+ ) {
+ //
+ // If there is a value entry currently selected,
+ // invoke the editor
+ //
+ pDataView->EditValue( CurrentValue->GetType() );
+
+ } else {
+
+ Size = CurrentValue->GetData( &Pointer );
+ REGISTRY_DATA::DisplayData( hWnd,
+ CurrentValue->GetType(),
+ Pointer,
+ Size );
+
+ }
+ }
+ break;
+
+
+ default:
+ return DefWindowProc( hWnd, wMessage, wParam, lParam );
+ }
+ } else {
+ //
+ // this is a notify from a child control (ie. the list box)
+ // so switch on the notification code
+ //
+ switch ( HIWORD( wParam ) ) {
+
+ case LBN_DBLCLK:
+
+ //
+ // Find out the currently selected item
+ // If unable to get it, ignore message
+ //
+
+ if( ( SelectedItem = SendMessage( pDataView->_hwndList,
+ LB_GETCURSEL,
+ 0,
+ 0 ) ) != LB_ERR ) {
+ //
+ // Send message to the registry window, so that
+ // it can disable the notification thrteads
+ //
+ SendMessage( GetParent( hWnd ),
+ DATAVW_DBL_CLICK,
+ 0,
+ 0 );
+ }
+ break;
+
+ case LBN_SETFOCUS:
+ pDataView->_HasFocus = TRUE;
+ SendMessage(GetParent(hWnd), DATA_VIEW_FOCUS, 0, 0);
+ break;
+
+ case LBN_KILLFOCUS:
+ pDataView->_HasFocus = FALSE;
+ break;
+
+ default:
+
+ //
+ // Let Windows handle this message.
+ //
+
+ return DefWindowProc( hWnd, wMessage, wParam, lParam );
+
+ } // end switch on cmd
+ } // end if
+ break;
+
+
+ case WM_CHARTOITEM:
+ {
+ LONG cItems;
+ LONG i, j;
+ WCHAR ch;
+ WCHAR szB[2];
+ PCREGEDIT_FORMATTED_VALUE_ENTRY Value;
+ WCHAR w[2];
+
+ cItems = pDataView->_Items;
+
+ i = ( LONG )SendMessage( pDataView->_hwndList, LB_GETCURSEL, 0, 0 );
+ if( i == LB_ERR ) {
+ i = 0;
+ }
+
+ ch = LOWORD( wParam );
+ if ( ( cItems == 0 ) ||
+ ( ch <= ( WCHAR )' ' ) ) // filter all other control chars
+ return -2L;
+
+ szB[1] = ( WCHAR )'\0';
+
+ for ( j = 1; j <= cItems; j++ ) {
+ SendMessage( pDataView->_hwndList, LB_GETTEXT, ( i+j ) % cItems, ( LONG )&Value);
+ szB[0] = *( ( Value->GetFormattedString() )->GetWSTR() );
+
+ /* Do it this way to be case insensitive. */
+ w[0] = ch;
+ w[1] = ( WCHAR )'\0';
+ if (!_wcsicmp( w, szB))
+ break;
+ }
+
+ if (j == cItems+1)
+ return -2L;
+
+ SendMessage( pDataView->_hwndList, LB_SETTOPINDEX, (i+j) % cItems, 0L);
+ return((i+j) % cItems);
+ }
+
+
+ default:
+
+ //
+ // Let Windows handle this message.
+ //
+
+ return DefWindowProc( hWnd, wMessage, wParam, lParam );
+ }
+
+ } else {
+
+ //
+ // No 'this' pointer (pDataView == NULL). Handle messages before
+ // WM_CREATE.
+ //
+ // Let Windows handle the message.
+ //
+
+ return DefWindowProc( hWnd, wMessage, wParam, lParam );
+ }
+
+ //
+ // Message handled...
+ //
+
+ return 0 ;
+}
+
+
+
+
+
+BOOL
+APIENTRY
+EXPORT
+DATA_VIEW::AddValueDialogProc(
+ HWND hDlg,
+ WORD msg,
+ WPARAM wParam,
+ LONG lParam
+)
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ hDlg - a handle to the dialog proceedure.
+
+ msg - the message passed from Windows.
+
+ wParam - extra message dependent data.
+
+ lParam - extra message dependent data.
+
+
+Return Value:
+
+ TRUE if the value was edited. FALSE if cancelled or if no
+ changes were made.
+
+--*/
+{
+ STATIC PREGEDIT_FORMATTED_VALUE_ENTRY* ReturnValue;
+
+ LPWSTR ValueName;
+ ULONG ValueSize;
+ REG_TYPE DataType;
+ ULONG DataSize;
+ PBYTE Data;
+ ULONG Index;
+
+ PWSTRING ValueId;
+
+ PREGISTRY_VALUE_ENTRY ValueEntry;
+ PREGEDIT_FORMATTED_VALUE_ENTRY FormattedValue;
+
+ EDITOR Editor;
+
+
+
+
+ switch( msg ) {
+
+ case WM_INITDIALOG:
+
+ ReturnValue = ( PREGEDIT_FORMATTED_VALUE_ENTRY* )lParam;
+ *ReturnValue = NULL;
+ SendDlgItemMessage( hDlg, IDD_ADD_VALUE_DATA_TYPE, CB_RESETCONTENT, 0, 0L );
+
+ if( _RegBinaryString != NULL ) {
+ Index = SendDlgItemMessage( hDlg,
+ IDD_ADD_VALUE_DATA_TYPE,
+ CB_ADDSTRING,
+ 0,
+ (LONG)_RegBinaryString->GetWSTR() );
+ if( ( Index != CB_ERR ) && ( Index != CB_ERRSPACE ) ) {
+ SendDlgItemMessage( hDlg,
+ IDD_ADD_VALUE_DATA_TYPE,
+ CB_SETITEMDATA,
+ ( UINT )Index,
+ (LONG)TYPE_REG_BINARY );
+ }
+ }
+
+ if( _RegDwordString != NULL ) {
+ Index = SendDlgItemMessage( hDlg,
+ IDD_ADD_VALUE_DATA_TYPE,
+ CB_ADDSTRING,
+ 0,
+ (LONG)_RegDwordString->GetWSTR() );
+ if( ( Index != CB_ERR ) && ( Index != CB_ERRSPACE ) ) {
+ SendDlgItemMessage( hDlg,
+ IDD_ADD_VALUE_DATA_TYPE,
+ CB_SETITEMDATA,
+ ( UINT )Index,
+ (LONG)TYPE_REG_DWORD );
+ }
+ }
+
+ if( _RegSzString != NULL ) {
+ Index = SendDlgItemMessage( hDlg,
+ IDD_ADD_VALUE_DATA_TYPE,
+ CB_ADDSTRING,
+ 0,
+ (LONG)_RegSzString->GetWSTR() );
+ if( ( Index != CB_ERR ) && ( Index != CB_ERRSPACE ) ) {
+ SendDlgItemMessage( hDlg,
+ IDD_ADD_VALUE_DATA_TYPE,
+ CB_SETITEMDATA,
+ ( UINT )Index,
+ (LONG)TYPE_REG_SZ );
+ }
+ }
+
+ if( _RegMultiSzString != NULL ) {
+ Index = SendDlgItemMessage( hDlg,
+ IDD_ADD_VALUE_DATA_TYPE,
+ CB_ADDSTRING,
+ 0,
+ (LONG)_RegMultiSzString->GetWSTR() );
+ if( ( Index != CB_ERR ) && ( Index != CB_ERRSPACE ) ) {
+ SendDlgItemMessage( hDlg,
+ IDD_ADD_VALUE_DATA_TYPE,
+ CB_SETITEMDATA,
+ ( UINT )Index,
+ (LONG)TYPE_REG_MULTI_SZ );
+ }
+ }
+
+ if( _RegExpandSzString != NULL ) {
+ Index = SendDlgItemMessage( hDlg,
+ IDD_ADD_VALUE_DATA_TYPE,
+ CB_ADDSTRING,
+ 0,
+ (LONG)_RegExpandSzString->GetWSTR() );
+ if( ( Index != CB_ERR ) && ( Index != CB_ERRSPACE ) ) {
+ SendDlgItemMessage( hDlg,
+ IDD_ADD_VALUE_DATA_TYPE,
+ CB_SETITEMDATA,
+ ( UINT )Index,
+ (LONG)TYPE_REG_EXPAND_SZ );
+ }
+ }
+
+ //
+ // Select REG_SZ as default
+ //
+ if( _RegSzString != 0 ) {
+ SendDlgItemMessage( hDlg,
+ IDD_ADD_VALUE_DATA_TYPE,
+ ( UINT )CB_SELECTSTRING,
+ ( WPARAM )-1,
+ (LONG)_RegSzString->GetWSTR() );
+ }
+
+ return( TRUE );
+
+
+ case WM_COMMAND:
+
+ switch( LOWORD( wParam ) ) {
+
+ case IDOK:
+ //
+ // The user hit OK
+ //
+
+ //
+ // Verifiy that the user entered a value name
+ //
+ ValueSize = SendDlgItemMessage( hDlg, IDD_ADD_VALUE_NAME, WM_GETTEXTLENGTH, 0, 0 );
+#if 0
+ if( ValueSize == 0 ) {
+ //
+ // If no name was entered, diplay error message
+ //
+ DisplayWarningPopup(hDlg, MSG_ADD_VALUE_ERROR_NO_NAME);
+ return( TRUE );
+ }
+#endif
+
+ //
+ // Let the user enter the data
+ //
+ Index = SendDlgItemMessage( hDlg, IDD_ADD_VALUE_DATA_TYPE, CB_GETCURSEL, 0, 0 );
+ DataType = ( REG_TYPE )SendDlgItemMessage( hDlg,
+ IDD_ADD_VALUE_DATA_TYPE,
+ ( UINT )CB_GETITEMDATA,
+ ( WPARAM )Index,
+ 0 );
+ Data = ( PBYTE )Editor.Edit( hDlg, DataType, NULL, 0, &DataSize, DataType );
+ if( Data == NULL ) {
+ //
+ // User hit cancel in the editor
+ //
+ EndDialog( hDlg, FALSE );
+ return( TRUE );
+ }
+
+ //
+ // Get all data that the user specified, and save them in a
+ // REGEDIT_FORMATTED_VALUE_ENTRY object
+ //
+ ValueSize = ValueSize + 1;
+ ValueName = ( LPWSTR )MALLOC( ( size_t )(ValueSize*sizeof( WCHAR )) );
+ DebugPtrAssert( ValueName );
+ SendDlgItemMessage( hDlg,
+ IDD_ADD_VALUE_NAME,
+ ( UINT )WM_GETTEXT,
+ ( WPARAM )ValueSize,
+ ( DWORD )ValueName );
+
+
+
+ ValueId = ( PWSTRING )NEW( DSTRING );
+ DebugPtrAssert( ValueId );
+ if( !ValueId->Initialize( ValueName ) ) {
+ DebugAbort( "ValueId->Initialize() failed \n" );
+ return( FALSE );
+ }
+ FREE( ValueName );
+
+ ValueEntry = ( PREGISTRY_VALUE_ENTRY )NEW( REGISTRY_VALUE_ENTRY );
+ DebugPtrAssert( ValueEntry );
+ if( !ValueEntry->Initialize( ValueId, 0, DataType, Data, DataSize ) ) {
+ DebugAbort( "ValueEntry->Initialize() failed \n" );
+ return( FALSE );
+ }
+
+ FormattedValue =
+ ( PREGEDIT_FORMATTED_VALUE_ENTRY )NEW( REGEDIT_FORMATTED_VALUE_ENTRY );
+ DebugPtrAssert( FormattedValue );
+
+ FormattedValue->Initialize( ValueEntry );
+ *ReturnValue = FormattedValue;
+ EndDialog( hDlg, TRUE );
+ return( TRUE );
+
+ case IDCANCEL:
+ //
+ // The user hit CANCEL
+ //
+
+ *ReturnValue = NULL;
+ EndDialog( hDlg, FALSE );
+ return( TRUE );
+
+ case IDB_HELP:
+ //
+ // The user hit HELP
+ //
+ DisplayHelp();
+ return( TRUE );
+ }
+ }
+ return( FALSE );
+}
+
+
+
+
+
+
+BOOLEAN
+DATA_VIEW::DeleteCurrentItem(
+ )
+
+/*++
+
+Routine Description:
+
+ Delete from the registry the the value entry currently selected
+ in the data view.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns TRUE if the operation succeeded.
+
+
+--*/
+
+{
+
+ PREGEDIT_FORMATTED_VALUE_ENTRY Value;
+ ULONG ErrorCode;
+ LONG SelectedItem;
+ BOOLEAN Status;
+ HCURSOR Cursor;
+ INT TextMessage;
+ INT CaptionMessage;
+
+
+ DbgWinAssert( _HasFocus );
+ DbgWinAssert( _Items == SendMessage( _hwndList, LB_GETCOUNT, 0, 0 ) );
+ DbgWinPtrAssert( _IR );
+ DbgWinPtrAssert( _Node );
+
+ Value = NULL;
+ //
+ // Get the value entry associated to the currently selected item.
+ // If unable to get the value entry, return
+ //
+ if( ( _Items > 0 ) &&
+ ( ( SelectedItem = ( LONG )SendMessage( _hwndList,
+ ( UINT )LB_GETCURSEL,
+ 0,
+ 0 ) ) != LB_ERR ) &&
+ ( SendMessage( _hwndList,
+ ( UINT )LB_GETTEXT,
+ ( WPARAM )SelectedItem,
+ ( LONG )&Value ) != LB_ERR ) &&
+
+ ( Value != NULL ) ) {
+
+ if( ( WINDOWS_APPLICATION::IsConfirmOnDeleteEnabled() &&
+ ( DisplayConfirmPopup( _hwndList,
+ MSG_DELETE_VALUE_CONFIRM_EX,
+ MSG_WARNING_TITLE ) == IDYES ) ) ||
+ ( !WINDOWS_APPLICATION::IsConfirmOnDeleteEnabled() ) ) {
+
+ Cursor = WINDOWS_APPLICATION::DisplayHourGlass();
+ Status = _IR->DeleteValue( _Node, Value, &ErrorCode );
+ WINDOWS_APPLICATION::RestoreCursor( Cursor );
+ if( Status ) {
+ //
+ // The value entry was deleted
+ //
+ _MaxWidth = 0;
+
+ if( SendMessage( _hwndList, LB_DELETESTRING, ( UINT )SelectedItem, 0 ) == LB_ERR ) {
+ DebugPrint( "SendMessage( _hwndList, LB_DELETESTRING, SelectedItem, 0 ) failed" );
+ return( FALSE );
+ }
+
+ _Items--;
+
+ //
+ // If the listbox still contains items, then put the selection
+ // on the appropriate item
+ //
+ if( ( _Items > 0 ) ) {
+
+ //
+ // If the last item was deleted, then make the current
+ // last item the current selected item
+ //
+ if( SelectedItem == _Items ) {
+ SelectedItem--;
+ }
+
+ if( SendMessage( _hwndList, LB_SETCURSEL, ( UINT )SelectedItem, 0 ) == LB_ERR ) {
+ DebugPrint( "SendMessage( _hwndList, LB_SETCURSEL, SelectedItem, 0 ) failed" );
+ }
+ }
+ AdjustHorizontalScrollBar();
+ } else {
+ //
+ // Couldn't delete the value entry
+ //
+ DebugPrint( "Value Entry was not deleted \n" );
+
+
+ if (ErrorCode == REGEDIT_ERROR_ACCESS_DENIED) {
+ TextMessage = MSG_DELETE_VALUE_ACCESS_DENIED_EX;
+ CaptionMessage = MSG_ACCESS_DENIED;
+ } else if( ErrorCode == REGEDIT_ERROR_NODE_NOT_FOUND ) {
+ TextMessage = MSG_DELETE_VALUE_KEY_NOT_ACCESSIBLE_EX;
+ CaptionMessage = MSG_KEY_NOT_ACCESSIBLE;
+ } else if( ErrorCode == REGEDIT_ERROR_KEY_DELETED ) {
+ TextMessage = MSG_DELETE_VALUE_KEY_DELETED_EX;
+ CaptionMessage = MSG_KEY_MARKED_FOR_DELETION;
+ } else if( ErrorCode == REGEDIT_RPC_S_SERVER_UNAVAILABLE ) {
+ TextMessage = MSG_CANT_ACCESS_REMOTE_REGISTRY;
+ CaptionMessage = MSG_SERVER_UNAVAILABLE;
+ } else {
+ DebugPrint( "Unknown error code" );
+ DebugPrintf( "ErrorCode = %d \n", ErrorCode );
+ TextMessage = MSG_FAILED_OPERATION_EX;
+ CaptionMessage = 0;
+ }
+ DisplayInfoPopup(_hwndList,
+ TextMessage,
+ CaptionMessage);
+
+
+
+ return( FALSE );
+ }
+ }
+ }
+ return( TRUE );
+}
+
+
+
+
+BOOLEAN
+DATA_VIEW::AddValueEntry(
+ )
+
+/*++
+
+Routine Description:
+
+ Add a value entry to a node.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+
+ Returns TRUE if the operation succeeded.
+
+
+--*/
+
+{
+ BOOLEAN AddValueEntry;
+ PREGEDIT_FORMATTED_VALUE_ENTRY Value;
+ ULONG ErrorCode;
+ BOOLEAN Status;
+ HCURSOR Cursor;
+ UINT SelectedItem;
+ INT TextMessage;
+ INT CaptionMessage;
+
+
+
+ Value = NULL;
+ AddValueEntry = TRUE;
+ while( AddValueEntry ) {
+ if( DialogBoxParam( (HINSTANCE)WINDOWS_APPLICATION::QueryInstance( ),
+ MAKEINTRESOURCE(ADD_VALUE_DLG),
+ _Handle,
+ ( DLGPROC )DATA_VIEW::AddValueDialogProc,
+ ( DWORD )&Value ) == -1 ) {
+ DebugPrint( "Unable to create dialog box" );
+ return( FALSE );
+ }
+ if( Value != NULL ) {
+
+ Cursor = WINDOWS_APPLICATION::DisplayHourGlass();
+ Status = _IR->DoesValueExist( _Node, Value, &ErrorCode );
+ WINDOWS_APPLICATION::RestoreCursor( Cursor );
+ if( Status ) {
+
+ DisplayWarningPopup(_hwndList, MSG_ADD_VALUE_ALREADY_EXISTS_EX);
+
+ } else {
+ Cursor = WINDOWS_APPLICATION::DisplayHourGlass();
+ Status = _IR->AddValue( _Node, Value, FALSE, &ErrorCode );
+ WINDOWS_APPLICATION::RestoreCursor( Cursor );
+ if( !Status ) {
+ DebugPrint( "New Value was not added to the registry" );
+
+ if (ErrorCode == REGEDIT_ERROR_ACCESS_DENIED) {
+ TextMessage = MSG_ADD_VALUE_ACCESS_DENIED_EX;
+ CaptionMessage = MSG_ACCESS_DENIED;
+ } else if( ErrorCode == REGEDIT_ERROR_NODE_NOT_FOUND ) {
+ TextMessage = MSG_ADD_VALUE_KEY_NOT_ACCESSIBLE_EX;
+ CaptionMessage = MSG_KEY_NOT_ACCESSIBLE;
+ } else if( ErrorCode == REGEDIT_ERROR_KEY_DELETED ) {
+ TextMessage = MSG_ADD_VALUE_KEY_DELETED_EX;
+ CaptionMessage = MSG_KEY_MARKED_FOR_DELETION;
+ } else if( ErrorCode == REGEDIT_RPC_S_SERVER_UNAVAILABLE ) {
+ TextMessage = MSG_CANT_ACCESS_REMOTE_REGISTRY;
+ CaptionMessage = MSG_SERVER_UNAVAILABLE;
+ } else {
+ DebugPrint( "Unknown error code" );
+ DebugPrintf( "ErrorCode = %d \n", ErrorCode );
+ TextMessage = MSG_FAILED_OPERATION_EX;
+ CaptionMessage = 0;
+ }
+ DisplayInfoPopup(_hwndList,
+ TextMessage,
+ CaptionMessage);
+ return( FALSE );
+ }
+ SelectedItem = (INT)SendMessage( _hwndList,
+ LB_GETCURSEL,
+ 0,
+ 0 );
+ SetDataNode( _Node, TRUE );
+ if( SelectedItem != LB_ERR ) {
+ SendMessage( _hwndList,
+ LB_SETCURSEL,
+ SelectedItem,
+ 0 );
+ }
+ AddValueEntry = FALSE;
+ }
+
+ } else {
+ AddValueEntry = FALSE;
+ }
+ }
+ return( TRUE );
+}
+
+
+
+PCREGEDIT_FORMATTED_VALUE_ENTRY
+DATA_VIEW::GetCurrentValue(
+ )
+
+/*++
+
+Routine Description:
+
+ Returns the pointer to the VALUE object that represents the value
+ currently selected in the data view.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+
+ PCREGEDIT_FORMATTED_VALUE_ENTRY - Returns the pointer to the value currently
+ selected, or NULL if there is no value selected.
+
+
+--*/
+
+{
+
+ PCREGEDIT_FORMATTED_VALUE_ENTRY Value;
+ LONG SelectedItem;
+
+
+ Value = NULL;
+ if( ( ( SelectedItem = SendMessage( _hwndList,
+ LB_GETCURSEL,
+ 0,
+ 0 ) ) == LB_ERR ) ||
+ ( SendMessage( _hwndList,
+ LB_GETTEXT,
+ ( WPARAM )SelectedItem,
+ (LONG)&Value ) == LB_ERR ) ||
+
+ ( Value == NULL ) ) {
+
+ return( NULL );
+ }
+ return( Value );
+}
+
+
+
+BOOLEAN
+DATA_VIEW::SaveCurrentValueName(
+ )
+
+/*++
+
+Routine Description:
+
+ Saves the name of the currently selected value entry, if any.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+
+ Returns TRUE if the operation succeeded.
+
+
+--*/
+
+{
+ INT CurrentItem;
+ PCREGEDIT_FORMATTED_VALUE_ENTRY ValueSelected;
+ PCWSTRING TmpName;
+
+ CurrentItem = (INT)SendMessage(_hwndList,
+ LB_GETCURSEL,
+ 0,
+ 0L);
+
+ if( CurrentItem == LB_ERR ) {
+ _CurrentValueName = NULL;
+ return TRUE;
+ }
+ ValueSelected = (PCREGEDIT_FORMATTED_VALUE_ENTRY)SendMessage(_hwndList,
+ LB_GETITEMDATA,
+ (WPARAM)CurrentItem,
+ 0);
+ if( ValueSelected == (PCREGEDIT_FORMATTED_VALUE_ENTRY)LB_ERR ) {
+ _CurrentValueName = NULL;
+ return TRUE;
+ }
+
+ TmpName = ValueSelected->GetName();
+ if( TmpName == NULL ) {
+ _CurrentValueName = NULL;
+ return FALSE;
+ }
+
+ _CurrentValueName = ( PDSTRING )NEW( DSTRING );
+ if( _CurrentValueName == NULL ) {
+ return FALSE;
+ }
+
+ if( !_CurrentValueName->Initialize( TmpName ) ) {
+ DELETE( _CurrentValueName );
+ return( FALSE );
+ }
+ return( TRUE );
+}
diff --git a/private/utils/regedit/src/debug.cxx b/private/utils/regedit/src/debug.cxx
new file mode 100644
index 000000000..c25d3d0c2
--- /dev/null
+++ b/private/utils/regedit/src/debug.cxx
@@ -0,0 +1,198 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ Debug.c
+
+Abstract:
+
+ This file contains the implementation of Windowed debugging functions.
+ The entire file is conditionally compiled based on the DBG compiler
+ symbol.
+
+Author:
+
+ David J. Gilman (davegi) 05-Aug-1991
+
+Environment:
+
+ Ulib, Windows, User Mode
+
+Notes:
+
+ All Debug functions should be invoked by their corresponding Dbg macros.
+ For example, if you want to use DebugWinAssert use DbgWinAssert instead.
+ This will ensure that they are compiled away in production code.
+
+--*/
+
+#if DBG==1
+
+#include "uapp.hxx"
+
+#include <stdio.h>
+
+//
+// Output buffer size.
+//
+
+CONST INT BufSize = 256;
+
+VOID
+DebugWinAssert (
+ IN BOOL Expression,
+ IN PSTR ExpressionString,
+ IN PSTR FileName,
+ IN INT LineNumber
+ )
+
+/*++
+
+Routine Description:
+
+ DebugWinAssert is a Windows version of the CRT assert macro. It displays
+ a message box if the assertion is FALSE. Along with the FALSE assertion
+ it also displays the file name and line number where the assertion was
+ made.
+
+
+Arguments:
+
+ Expression - Supplies the expression that is asserted to be TRUE.
+ ExpressionString - Supplies a string representation of the assertion
+ to be displayed.
+ FileName - Supplies the file name where the assertion was made.
+ LineNumber - Supplies the line number where the assertion was
+ made.
+
+Return Value:
+
+ None.
+
+Notes:
+
+ Use the DbgWinAssert macro to invoke this function.
+
+ Pushing the Retry or Ignore buttons merely return to the caller,
+ the Abort button terminates the application with exit code -1.
+ Any other return value terminates the application with exit code -2.
+
+--*/
+
+{
+
+ HWND Handle = GetActiveWindow();
+ STR Buffer[ BufSize ];
+
+ //
+ // Return if the expression (assertion) is TRUE.
+ //
+
+ if( ! Expression ) {
+
+ //
+ // Format the error message.
+ //
+
+ sprintf( Buffer, "%s in file %s at line %d",
+ ExpressionString, FileName, LineNumber );
+
+ //
+ // Display the message box and take action based on the
+ // pushed button.
+ //
+
+ switch( MessageBoxA( Handle, ( LPSTR ) Buffer, "Assertion Failure",
+ (UINT)(MB_APPLMODAL |
+ MB_DEFBUTTON1 |
+ MB_ABORTRETRYIGNORE |
+ MB_ICONEXCLAMATION)
+ )) {
+
+ case IDABORT:
+ PostQuitMessage( -1 );
+ break;
+
+ case IDRETRY:
+ return;
+
+ case IDIGNORE:
+ return;
+
+ default:
+ PostQuitMessage( -2 );
+ }
+ }
+}
+
+VOID
+DebugWinPrint (
+ IN PSTR Caption,
+ IN PSTR String,
+ IN INT Style,
+ IN PSTR FileName,
+ IN INT LineNumber
+ )
+
+/*++
+
+Routine Description:
+
+ DebugWinPrint displays a debug string along with the file name and
+ line number where the functions is called.
+
+Arguments:
+
+ Caption - Supplies the test for the message box's caption.
+ String - Supplies the text to be displayed.
+ Style - Supplies MB_ICONSTOP or MB_ICONINFORMATION.
+ FileName - Supplies the file name where the function was
+ called.
+ LineNumber - Supplies the line number where the function was
+ called.
+
+Return Value:
+
+ None.
+
+Notes:
+
+ Use the DbgWinPrint (or DbgWinAbort) macro to invoke this function.
+
+--*/
+
+{
+
+ HWND Handle = GetActiveWindow();
+ STR Buffer[ BufSize ];
+
+ //
+ // Format the message.
+ //
+
+ sprintf( Buffer, "%s\nIn file %s at line %d", String, FileName,
+ LineNumber );
+
+ //
+ // Force the style to MB_ICONSTOP or MB_ICONINFORMATION.
+ //
+
+ if(( Style != MB_ICONSTOP ) && ( Style != MB_ICONINFORMATION )) {
+
+ Style = ( UINT )MB_ICONSTOP;
+ }
+
+ //
+ // Display the message box until the OK button is pushed.
+ //
+
+ MessageBoxA( Handle, ( LPSTR ) Buffer, Caption,
+ (UINT)(MB_APPLMODAL |
+ MB_DEFBUTTON1 |
+ MB_OK |
+ Style) );
+}
+
+#endif // DBG
diff --git a/private/utils/regedit/src/dialogs.dlg b/private/utils/regedit/src/dialogs.dlg
new file mode 100644
index 000000000..69ffbfbde
--- /dev/null
+++ b/private/utils/regedit/src/dialogs.dlg
@@ -0,0 +1,322 @@
+1 DLGINCLUDE "dialogs.h"
+
+ADD_KEY_DLG DIALOG 6, 18, 235, 85
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Add Key"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Key Name:", -1, 7, 9, 37, 8
+ EDITTEXT IDD_ADD_KEY_NAME, 68, 8, 156, 12, ES_AUTOHSCROLL
+ LTEXT "&Class:", -1, 7, 47, 22, 8
+ EDITTEXT IDD_ADD_KEY_CLASS, 68, 44, 156, 12, ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK", IDOK, 50, 65, 40, 14, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, 97, 65, 40, 14
+ PUSHBUTTON "&Help", IDB_HELP, 144, 65, 40, 14
+END
+
+ADD_VALUE_DLG DIALOG 6, 19, 231, 83
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Add Value"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Value Name:", -1, 4, 10, 42, 8
+ EDITTEXT IDD_ADD_VALUE_NAME, 63, 7, 156, 12, ES_AUTOHSCROLL
+ LTEXT "&Data Type:", -1, 4, 46, 40, 8
+ COMBOBOX IDD_ADD_VALUE_DATA_TYPE, 63, 43, 98, 52,
+ CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ DEFPUSHBUTTON "OK", IDOK, 48, 63, 40, 14, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, 95, 63, 40, 14
+ PUSHBUTTON "&Help", IDB_HELP, 142, 63, 40, 14
+END
+
+MULTI_SZ_EDITOR_DLG DIALOG 6, 18, 250, 120
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Multi-String Editor"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Data:", 402, 8, 5, 20, 8
+ EDITTEXT IDD_MULTI_SZ_EDIT_CONTROL, 8, 15, 233, 74, ES_MULTILINE |
+ ES_AUTOVSCROLL | ES_AUTOHSCROLL | WS_VSCROLL |
+ WS_HSCROLL | 0x1000
+ DEFPUSHBUTTON "OK", IDOK, 58, 102, 40, 14, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, 105, 102, 40, 14
+ PUSHBUTTON "&Help", IDB_HELP, 152, 102, 40, 14
+END
+
+DISPLAY_BINARY_DATA DIALOG 5, 18, 440, 161
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Binary Data"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "D&ata:", 502, 4, 6, 20, 8
+ LISTBOX IDD_DISPLAY_DATA_BINARY, 4, 15, 433, 71, WS_VSCROLL |
+ WS_TABSTOP
+ GROUPBOX "Format", 503, 4, 92, 163, 35, WS_GROUP
+ AUTORADIOBUTTON "&Byte", IDR_BINARY_DATA_BYTE, 24, 105, 30, 10
+ AUTORADIOBUTTON "&Word", IDR_BINARY_DATA_WORD, 64, 105, 35, 10
+ AUTORADIOBUTTON "&Dword", IDR_BINARY_DATA_DWORD, 109, 105, 39, 10
+ DEFPUSHBUTTON "OK", IDOK, 161, 137, 40, 14, WS_GROUP
+END
+
+DWORD_EDITOR_DLG DIALOG 6, 18, 206, 73
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "DWORD Editor"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Data:", -1, 5, 7, 20, 8
+ EDITTEXT IDD_EDIT, 5, 18, 142, 12, ES_AUTOHSCROLL
+ GROUPBOX "Radix", 202, 5, 37, 131, 26, WS_GROUP
+ AUTORADIOBUTTON "&Binary", IDD_BINARY, 17, 48, 32, 10, WS_TABSTOP
+ AUTORADIOBUTTON "D&ecimal", IDD_DECIMAL, 55, 48, 38, 10
+ AUTORADIOBUTTON "He&x", IDD_HEX, 99, 48, 25, 10
+ DEFPUSHBUTTON "OK", IDOK, 155, 3, 40, 14, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, 155, 20, 40, 14
+ PUSHBUTTON "&Help", IDB_HELP, 155, 37, 40, 14
+END
+
+BINARY_EDITOR_DLG DIALOG 6, 18, 391, 167
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Binary Editor"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Data:", -1, 25, 3, 20, 8
+ LTEXT "", IDD_BINARY_RULER, 27, 20, 356, 13, NOT WS_GROUP
+ EDITTEXT IDD_EDIT, 25, 33, 357, 71, ES_MULTILINE | ES_AUTOVSCROLL |
+ WS_VSCROLL
+ GROUPBOX "Data Format", 202, 25, 116, 100, 25, WS_GROUP
+ AUTORADIOBUTTON "&Binary", IDD_BINARY, 40, 127, 35, 10, WS_TABSTOP
+ AUTORADIOBUTTON "He&x", IDD_HEX, 77, 127, 28, 10
+ DEFPUSHBUTTON "OK", IDOK, 103, 149, 40, 14, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, 150, 149, 40, 14
+ PUSHBUTTON "&Help", IDB_HELP, 197, 149, 40, 14
+ LTEXT "", IDD_VERTICAL_RULER, 3, 35, 22, 71
+END
+
+STRING_EDITOR_DLG DIALOG 6, 18, 248, 56
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "String Editor"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&String:", -1, 5, 5, 20, 8
+ EDITTEXT IDD_EDIT, 5, 14, 238, 12, ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK", IDOK, 57, 38, 40, 14, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, 104, 38, 40, 14
+ PUSHBUTTON "&Help", IDB_HELP, 151, 38, 40, 14
+END
+
+PRINTDLGBOX DIALOG 40, 40, 120, 40
+STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+BEGIN
+ CTEXT "Cancel Printing", -1, 4, 6, 120, 12
+ DEFPUSHBUTTON "Cancel", IDCANCEL, 44, 22, 32, 14, WS_GROUP
+END
+
+GET_KEY_DLG DIALOG 6, 18, 235, 85
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Load Hive"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Key Name:", -1, 7, 9, 37, 8
+ EDITTEXT IDD_ADD_KEY_NAME, 68, 8, 156, 12, ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK", IDOK, 50, 65, 40, 14, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, 97, 65, 40, 14
+ PUSHBUTTON "&Help", IDB_HELP, 144, 65, 40, 14
+END
+
+//
+// new dialogs
+//
+
+#include "clb.h"
+
+IDD_FULL_RES_DESCRIPTOR DIALOG 6, 18, 281, 283
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Resources"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "OK", IDOK, 92, 263, 40, 14
+ PUSHBUTTON "&Data...", IDC_PUSH_DISPLAY_DATA, 148, 263, 40, 14,
+ WS_DISABLED
+ CONTROL "Channel;Port", IDC_FULL_RES_LIST_DMA, "ColumnListBox",
+ CLBS_NOTIFY | CLBS_SORT | CLBS_VSCROLL | CLBS_BORDER |
+ LBS_OWNERDRAWFIXED | WS_TABSTOP, 10, 15, 261, 31
+ CONTROL "Vector;Level;Affinity;Type",
+ IDC_FULL_RES_LIST_INTERRUPTS, "ColumnListBox",
+ CLBS_NOTIFY | CLBS_SORT | CLBS_VSCROLL | CLBS_BORDER |
+ LBS_OWNERDRAWFIXED | WS_TABSTOP, 10, 58, 261, 31
+ CONTROL "Physical Address;Length;Access",
+ IDC_FULL_RES_LIST_MEMORY, "ColumnListBox", CLBS_NOTIFY |
+ CLBS_SORT | CLBS_VSCROLL | CLBS_BORDER |
+ LBS_OWNERDRAWFIXED | WS_TABSTOP, 10, 101, 261, 31
+ CONTROL "Physical Address;Length;Type", IDC_FULL_RES_LIST_PORTS,
+ "ColumnListBox", CLBS_NOTIFY | CLBS_SORT | CLBS_VSCROLL |
+ CLBS_BORDER | LBS_OWNERDRAWFIXED | WS_TABSTOP, 10, 144,
+ 261, 31
+ GROUPBOX "Share Disposition", -1, 10, 219, 125, 39
+ LTEXT "Undetermined", IDC_FULL_RES_TEXT_UNDETERMINED, 18, 230,
+ 46, 8, WS_DISABLED
+ LTEXT "Shared", IDC_FULL_RES_TEXT_SHARED, 18, 240, 24, 8,
+ WS_DISABLED
+ LTEXT "Device Exclusive", IDC_FULL_RES_TEXT_DEVICE_EXCLUSIVE,
+ 72, 230, 58, 8, WS_DISABLED
+ LTEXT "Driver Exclusive", IDC_FULL_RES_TEXT_DRIVER_EXCLUSIVE,
+ 72, 240, 54, 8, WS_DISABLED
+ LTEXT "DMA:", -1, 10, 5, 20, 8
+ LTEXT "Interrupt:", -1, 10, 48, 35, 8
+ LTEXT "Memory:", -1, 10, 91, 28, 8
+ LTEXT "Port:", -1, 10, 134, 17, 8
+ LTEXT "Device Specific Data:", -1, 10, 177, 74, 8
+ CONTROL "Reserved1;Reserved2;Data Size",
+ IDC_FULL_RES_LIST_DEVICE_SPECIFIC, "ColumnListBox",
+ CLBS_NOTIFY | CLBS_SORT | CLBS_VSCROLL | CLBS_BORDER |
+ LBS_OWNERDRAWFIXED | WS_TABSTOP, 10, 188, 261, 31
+ RTEXT "Bus Number:", -1, 151, 230, 51, 8
+ RTEXT "Interface Type:", -1, 151, 220, 51, 8
+ RTEXT "Version:", -1, 151, 240, 51, 8
+ RTEXT "Revision:", -1, 151, 250, 51, 8
+ LTEXT "", IDC_FULL_RES_TEXT_INTERFACE_TYPE, 205, 220, 66, 8
+ LTEXT "", IDC_FULL_RES_TEXT_BUS_NUMBER, 205, 230, 66, 8
+ LTEXT "", IDC_FULL_RES_TEXT_VERSION, 205, 240, 66, 8
+ LTEXT "", IDC_FULL_RES_TEXT_REVISION, 205, 250, 66, 8
+END
+
+IDD_RESOURCE_LIST DIALOG 13, 15, 170, 120
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Resource Lists"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ PUSHBUTTON "OK", IDOK, 37, 95, 40, 14
+ PUSHBUTTON "Display...", IDC_PUSH_DISPLAY_RESOURCES, 93, 95, 40, 14
+ CONTROL "Bus Number;Interface Type", IDC_LIST_RESOURCE_LISTS,
+ "ColumnListBox", CLBS_NOTIFY | CLBS_SORT | CLBS_VSCROLL |
+ CLBS_BORDER | LBS_OWNERDRAWFIXED | WS_TABSTOP, 10, 10,
+ 150, 75
+END
+
+IDD_IO_REQUIREMENTS_LIST DIALOG 13, 15, 220, 135
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Requirements List"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ PUSHBUTTON "OK", IDOK, 62, 115, 40, 14
+ PUSHBUTTON "Display...", IDC_IO_REQ_PUSH_DISPLAY_DEVICE, 118, 115,
+ 40, 14, WS_DISABLED
+ CONTROL "Alternative List;Resource List;Descriptor;Device Type",
+ IDC_IO_LIST_ALTERNATIVE_LISTS, "ColumnListBox",
+ CLBS_NOTIFY | CLBS_VSCROLL | CLBS_BORDER |
+ LBS_OWNERDRAWFIXED | WS_TABSTOP, 10, 10, 200, 62
+ RTEXT "Bus Number:", -1, 10, 87, 51, 8
+ RTEXT "Slot Number:", -1, 10, 97, 51, 8
+ RTEXT "Interface Type:", -1, 10, 77, 51, 8
+ LTEXT "", IDC_IO_REQ_TEXT_INTERFACE_TYPE, 64, 77, 66, 8
+ LTEXT "", IDC_IO_REQ_TEXT_BUS_NUMBER, 64, 87, 66, 8
+ LTEXT "", IDC_IO_REQ_TEXT_SLOT_NUMBER, 64, 97, 66, 8
+END
+
+IDD_IO_MEMORY_RESOURCE DIALOG 6, 18, 158, 135
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Memory"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "OK", IDOK, 58, 117, 40, 14
+ GROUPBOX "Option", -1, 10, 72, 83, 39
+ LTEXT "Preferred", IDC_IO_TEXT_OPTION_PREFERRED, 34, 96, 37, 8,
+ WS_DISABLED
+ LTEXT "Alternative", IDC_IO_TEXT_OPTION_ALTERNATIVE, 34, 86,
+ 35, 8, WS_DISABLED
+ RTEXT "Minimum Address:", -1, 10, 40, 61, 8
+ RTEXT "Maximum Address:", -1, 10, 50, 61, 8
+ RTEXT "Share Disposition:", -1, 10, 60, 61, 8
+ RTEXT "Access:", -1, 10, 10, 61, 8
+ LTEXT "", IDC_IO_TEXT_MEM_MAX_ADDRESS, 73, 50, 74, 8
+ RTEXT "Length:", -1, 10, 20, 61, 8
+ RTEXT "Alignment:", -1, 10, 30, 61, 8
+ LTEXT "", IDC_IO_TEXT_MEM_ACCESS, 73, 10, 74, 8
+ LTEXT "", IDC_IO_TEXT_MEM_LENGTH, 73, 20, 74, 8
+ LTEXT "", IDC_IO_TEXT_MEM_ALIGNMENT, 73, 30, 74, 8
+ LTEXT "", IDC_IO_TEXT_MEM_MIN_ADDRESS, 73, 40, 74, 8
+ LTEXT "", IDC_IO_TEXT_DISPOSITION, 73, 60, 74, 8
+END
+
+IDD_IO_INTERRUPT_RESOURCE DIALOG 6, 18, 158, 135
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Interrupt"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "OK", IDOK, 58, 117, 40, 14
+ GROUPBOX "Option", -1, 10, 72, 83, 39
+ LTEXT "Preferred", IDC_IO_TEXT_OPTION_PREFERRED, 34, 96, 37, 8,
+ WS_DISABLED
+ LTEXT "Alternative", IDC_IO_TEXT_OPTION_ALTERNATIVE, 34, 86,
+ 35, 8, WS_DISABLED
+ RTEXT "Maximum Vector:", -1, 10, 30, 61, 8
+ RTEXT "Share Disposition:", -1, 10, 40, 61, 8
+ RTEXT "Type:", -1, 10, 10, 61, 8
+ RTEXT "Minimum Vector:", -1, 10, 20, 61, 8
+ LTEXT "", IDC_IO_TEXT_INT_TYPE, 73, 10, 74, 8
+ LTEXT "", IDC_IO_TEXT_INT_MIN_VECTOR, 73, 20, 74, 8
+ LTEXT "", IDC_IO_TEXT_INT_MAX_VECTOR, 73, 30, 74, 8
+ LTEXT "", IDC_IO_TEXT_DISPOSITION, 73, 40, 74, 8
+END
+
+IDD_IO_DMA_RESOURCE DIALOG 6, 18, 158, 135
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "DMA"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "OK", IDOK, 58, 117, 40, 14
+ GROUPBOX "Option", -1, 10, 72, 83, 39
+ LTEXT "Preferred", IDC_IO_TEXT_OPTION_PREFERRED, 34, 96, 37, 8,
+ WS_DISABLED
+ LTEXT "Alternative", IDC_IO_TEXT_OPTION_ALTERNATIVE, 34, 86,
+ 35, 8, WS_DISABLED
+ RTEXT "Minimum Channel:", -1, 10, 10, 61, 8
+ RTEXT "Share Disposition:", -1, 10, 30, 61, 8
+ RTEXT "Maximum Channel:", -1, 10, 20, 61, 8
+ LTEXT "", IDC_IO_TEXT_DMA_MIN_CHANNEL, 73, 10, 74, 8
+ LTEXT "", IDC_IO_TEXT_DMA_MAX_CHANNEL, 73, 20, 74, 8
+ LTEXT "", IDC_IO_TEXT_DISPOSITION, 73, 30, 74, 8
+END
+
+IDD_IO_PORT_RESOURCE DIALOG 6, 18, 158, 135
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Port"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "OK", IDOK, 58, 117, 40, 14
+ GROUPBOX "Option", -1, 10, 72, 83, 39
+ LTEXT "Preferred", IDC_IO_TEXT_OPTION_PREFERRED, 34, 96, 37, 8,
+ WS_DISABLED
+ LTEXT "Alternative", IDC_IO_TEXT_OPTION_ALTERNATIVE, 34, 86,
+ 35, 8, WS_DISABLED
+ RTEXT "Minimum Address:", -1, 10, 40, 61, 8
+ RTEXT "Maximum Address:", -1, 10, 50, 61, 8
+ RTEXT "Share Disposition:", -1, 10, 60, 61, 8
+ RTEXT "Type:", -1, 10, 10, 61, 8
+ LTEXT "", IDC_IO_TEXT_PORT_MAX_ADDRESS, 73, 50, 74, 8
+ RTEXT "Length:", -1, 10, 20, 61, 8
+ RTEXT "Alignment:", -1, 10, 30, 61, 8
+ LTEXT "", IDC_IO_TEXT_PORT_TYPE, 73, 10, 74, 8
+ LTEXT "", IDC_IO_TEXT_PORT_LENGTH, 73, 20, 74, 8
+ LTEXT "", IDC_IO_TEXT_PORT_ALIGNMENT, 73, 30, 74, 8
+ LTEXT "", IDC_IO_TEXT_PORT_MIN_ADDRESS, 73, 40, 74, 8
+ LTEXT "", IDC_IO_TEXT_DISPOSITION, 73, 60, 74, 8
+END
+
+DISPLAY_BINARY_DATA_WITH_VALUE_TYPE DIALOG 5, 18, 440, 161
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Binary Data"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "D&ata:", 502, 4, 6, 20, 8
+ LISTBOX IDD_DISPLAY_DATA_BINARY, 4, 15, 433, 71, WS_VSCROLL |
+ WS_TABSTOP
+ GROUPBOX "Format", 503, 4, 92, 163, 35, WS_GROUP
+ AUTORADIOBUTTON "&Byte", IDR_BINARY_DATA_BYTE, 24, 105, 30, 10
+ AUTORADIOBUTTON "&Word", IDR_BINARY_DATA_WORD, 64, 105, 35, 10
+ AUTORADIOBUTTON "&Dword", IDR_BINARY_DATA_DWORD, 109, 105, 39, 10
+ DEFPUSHBUTTON "OK", IDOK, 161, 137, 40, 14, WS_GROUP
+ LTEXT "Value Type:", -1, 195, 98, 44, 8
+ LTEXT "", IDT_VALUE_TYPE, 243, 98, 58, 8 // , NOT WS_GROUP
+END
diff --git a/private/utils/regedit/src/editor.cxx b/private/utils/regedit/src/editor.cxx
new file mode 100644
index 000000000..c1f0e462f
--- /dev/null
+++ b/private/utils/regedit/src/editor.cxx
@@ -0,0 +1,2376 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ Editor.cxx
+
+Abstract:
+
+ These classes implement the editor functions required for modifying
+ primative data types withe the RegEdit utility.
+
+Author:
+
+ Barry J. Gilhuly (W-Barry) July 31, 1991
+
+Revision History:
+
+
+--*/
+
+#include <wchar.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "uapp.hxx"
+#include "editor.hxx"
+#include "winapp.hxx"
+
+#include "resource.h"
+
+#include "dialogs.h"
+#include "regedhlp.h"
+#include "defmsg.h"
+#include "regsys.hxx"
+#include "regedit.hxx"
+
+
+
+// extern "C" {
+// #include "commdlg.h"
+// }
+
+//
+// Define storage for the pointer to the old WndProc which
+// EditInteger replaces. This is necessarily global since
+// EditInteger must know where to send unprocessed messages.
+//
+
+WNDPROC OldWndLong;
+
+//
+// Define lookup tables for converting from numbers to text and for
+// converting HEX text to BINARY text....
+//
+
+static struct _NumLookup {
+ WCHAR Char;
+ WCHAR BinChar[ 4 ];
+} NumLookup[ 16 ] = {
+ { ( WCHAR )'0', { ( WCHAR )'0', ( WCHAR )'0', ( WCHAR )'0', ( WCHAR )'0' } },
+ { ( WCHAR )'1', { ( WCHAR )'0', ( WCHAR )'0', ( WCHAR )'0', ( WCHAR )'1' } },
+ { ( WCHAR )'2', { ( WCHAR )'0', ( WCHAR )'0', ( WCHAR )'1', ( WCHAR )'0' } },
+ { ( WCHAR )'3', { ( WCHAR )'0', ( WCHAR )'0', ( WCHAR )'1', ( WCHAR )'1' } },
+ { ( WCHAR )'4', { ( WCHAR )'0', ( WCHAR )'1', ( WCHAR )'0', ( WCHAR )'0' } },
+ { ( WCHAR )'5', { ( WCHAR )'0', ( WCHAR )'1', ( WCHAR )'0', ( WCHAR )'1' } },
+ { ( WCHAR )'6', { ( WCHAR )'0', ( WCHAR )'1', ( WCHAR )'1', ( WCHAR )'0' } },
+ { ( WCHAR )'7', { ( WCHAR )'0', ( WCHAR )'1', ( WCHAR )'1', ( WCHAR )'1' } },
+ { ( WCHAR )'8', { ( WCHAR )'1', ( WCHAR )'0', ( WCHAR )'0', ( WCHAR )'0' } },
+ { ( WCHAR )'9', { ( WCHAR )'1', ( WCHAR )'0', ( WCHAR )'0', ( WCHAR )'1' } },
+ { ( WCHAR )'A', { ( WCHAR )'1', ( WCHAR )'0', ( WCHAR )'1', ( WCHAR )'0' } },
+ { ( WCHAR )'B', { ( WCHAR )'1', ( WCHAR )'0', ( WCHAR )'1', ( WCHAR )'1' } },
+ { ( WCHAR )'C', { ( WCHAR )'1', ( WCHAR )'1', ( WCHAR )'0', ( WCHAR )'0' } },
+ { ( WCHAR )'D', { ( WCHAR )'1', ( WCHAR )'1', ( WCHAR )'0', ( WCHAR )'1' } },
+ { ( WCHAR )'E', { ( WCHAR )'1', ( WCHAR )'1', ( WCHAR )'1', ( WCHAR )'0' } },
+ { ( WCHAR )'F', { ( WCHAR )'1', ( WCHAR )'1', ( WCHAR )'1', ( WCHAR )'1' } }
+};
+
+
+//
+// Rulers used in the binary editor
+//
+
+STATIC PCWSTRING _HexRuler = NULL;
+STATIC PCWSTRING _BinaryRuler = NULL;
+
+
+
+VOID
+BytesToHexString(
+ IN PBYTE InBytes,
+ IN INT NumBytes,
+ OUT LPWSTR OutString
+)
+{
+ while( NumBytes-- ) {
+ *( OutString++ ) = NumLookup[ *InBytes >> HEX_WIDTH ].Char;
+ *( OutString++ ) = NumLookup[ *InBytes & LOMASK ].Char;
+ InBytes++;
+ }
+ *OutString = ( WCHAR )'\0'; // Terminate the newly converted string.
+}
+
+
+
+
+
+PWSTR
+ConvertMultiSzToSingleSz(
+ PBYTE Data,
+ ULONG Size
+ )
+
+{
+ ULONG NumberOfStrings;
+ PWSTR Pointer;
+ ULONG Count;
+ ULONG NumberOfWChar;
+ PWSTR Buffer;
+ ULONG BufferSize;
+ PWSTR SrcPointer;
+ PWSTR DestPointer;
+
+ //
+ // Find out the number of strings in the buffer by counting the
+ // number of NULs
+ //
+
+ NumberOfStrings = 0;
+ Pointer = ( PWSTR )Data;
+ NumberOfWChar = Size / sizeof( WCHAR );
+ if( ((Size % 2) == 0 ) &&
+ (*( Data + Size - sizeof( WCHAR ) ) == ( WCHAR )'\0') ) {
+ NumberOfWChar--;
+ }
+ for( Count = 0; Count < NumberOfWChar; Count++ ) {
+ if( *Pointer == ( WCHAR )'\0' ) {
+ NumberOfStrings++;
+ }
+ Pointer++;
+ }
+
+ //
+ // Copy the strings in the source buffer to a destination buffer,
+ // replacing NULs by CR LF
+ // Just in case, make the buffer 1 character bugger and set the last
+ // character to NUL. This is because the data may not be of type REG_MULTI_SZ,
+ // even though we think it is.
+ //
+ BufferSize = Size/sizeof( WCHAR ) + NumberOfStrings + 1;
+
+ Buffer = ( PWSTR )CALLOC( ( size_t )BufferSize, ( size_t )sizeof( WCHAR ) );
+ DebugPtrAssert( Buffer );
+ Buffer[BufferSize-1] = ( WCHAR )'\0';
+ SrcPointer = ( PWSTR )Data;
+ DestPointer = Buffer;
+ //
+ // Replace the NULs by CR LF, but not the last NUL
+ //
+ if( ( NumberOfWChar != 0 ) &&
+ ( Buffer[ NumberOfWChar - 1 ] == ( WCHAR )'\0' ) ){
+ NumberOfWChar--;
+ }
+
+ for( Count = 0; Count < NumberOfWChar; Count++ ) {
+ if( *SrcPointer == ( WCHAR )'\0' ) {
+ *DestPointer++ = ( WCHAR )'\r';
+ *DestPointer++ = ( WCHAR )'\n';
+ SrcPointer++;
+ } else {
+ *DestPointer++ = *SrcPointer++;
+ }
+ }
+
+ *DestPointer = ( WCHAR )'\0';
+ return( Buffer );
+
+}
+
+
+
+
+DEFINE_CONSTRUCTOR( EDITOR, OBJECT );
+
+DEFINE_CAST_MEMBER_FUNCTION( EDITOR );
+
+
+PVOID
+EDITOR::Edit (
+ IN HWND hWnd,
+ IN REG_TYPE DataType,
+ IN PVOID DataStream,
+ IN ULONG NumBytesIn,
+ OUT PULONG NumBytesOut,
+ IN REG_TYPE Type
+)
+
+/*++
+
+Routine Description:
+
+ Provides an interface between the user code and the editors. The module
+ calls an editor based on the passed in Type.
+
+Arguments:
+
+ hWnd - A handle to the owner window.
+
+ DataType - Indicates the type to be edited.
+
+ DataStream - A handle to the data segment to edit.
+
+ NumBytesIn - The number of bytes to edit.
+
+ NumBytesOut - The number of bytes being returned.
+
+ Type - The type of editor to call.
+
+Return Value:
+
+ Returns a HANDLE to the memory location holding the result if the
+ operation was successful. Otherwise, it returns NULL.
+
+Notes:
+
+ 1) This procedure depends on the fact that the program instance handle
+ is globally available.
+
+--*/
+
+{
+ PVOID DataStreamCopy;
+ DIALOGINFO DialogInfo;
+ BOOL retval;
+ LONG SaveHelpContext;
+
+ //
+ // Make a copy of the input data string...
+ //
+
+ if( NumBytesIn != 0 ) {
+ if( DataStream != NULL ) {
+ DataStreamCopy = MALLOC( ( size_t )NumBytesIn );
+ DebugPtrAssert( DataStreamCopy );
+ memset( DataStreamCopy, 0, ( size_t )NumBytesIn );
+ memcpy( DataStreamCopy, DataStream, ( size_t )NumBytesIn );
+ } else {
+ //
+ // This is an error condition.
+ // Assume that no data was passed
+ //
+ DebugPrint( "DataStream is a NULL pointer" );
+ NumBytesIn = 0;
+ DataStreamCopy = NULL;
+ }
+
+ } else {
+ DataStreamCopy = NULL;
+ }
+
+ //
+ // Set up the structure to be passed to the dialog.
+ //
+
+ DialogInfo.DataObject = &DataStreamCopy;
+ DialogInfo.NumBytes = &NumBytesIn;
+ DialogInfo.DataType = DataType;
+
+
+ //
+ // Determine the correct dialog to call and invoke it...
+ //
+
+ switch( Type ) {
+
+ case TYPE_REG_BINARY:
+
+ SaveHelpContext = WINDOWS_APPLICATION::GetHelpContext();
+ WINDOWS_APPLICATION::SetHelpContext( IDH_DB_BINARY_REGED );
+ retval = DialogBoxParam( (HINSTANCE)WINDOWS_APPLICATION::QueryInstance( ),
+ MAKEINTRESOURCE(BINARY_EDITOR_DLG),
+ hWnd,
+ ( DLGPROC ) EDITOR::BINARYDialogProc,
+ ( DWORD ) &DialogInfo );
+ WINDOWS_APPLICATION::SetHelpContext( SaveHelpContext );
+ break;
+
+ case TYPE_REG_SZ:
+ case TYPE_REG_EXPAND_SZ:
+
+ SaveHelpContext = WINDOWS_APPLICATION::GetHelpContext();
+ WINDOWS_APPLICATION::SetHelpContext( IDH_DB_STRING_REGED );
+ retval = DialogBoxParam( (HINSTANCE)WINDOWS_APPLICATION::QueryInstance( ),
+ MAKEINTRESOURCE(STRING_EDITOR_DLG),
+ hWnd,
+ ( DLGPROC ) EDITOR::SZDialogProc,
+ ( DWORD )&DialogInfo );
+ WINDOWS_APPLICATION::SetHelpContext( SaveHelpContext );
+ break;
+
+ case TYPE_REG_DWORD:
+
+ SaveHelpContext = WINDOWS_APPLICATION::GetHelpContext();
+ WINDOWS_APPLICATION::SetHelpContext( IDH_DB_DWORD_REGED );
+ retval = DialogBoxParam( (HINSTANCE)WINDOWS_APPLICATION::QueryInstance( ),
+ MAKEINTRESOURCE(DWORD_EDITOR_DLG),
+ hWnd,
+ ( DLGPROC ) EDITOR::DWORDDialogProc,
+ ( DWORD ) &DialogInfo );
+ WINDOWS_APPLICATION::SetHelpContext( SaveHelpContext );
+ break;
+
+
+ case TYPE_REG_MULTI_SZ:
+
+ SaveHelpContext = WINDOWS_APPLICATION::GetHelpContext();
+ WINDOWS_APPLICATION::SetHelpContext( IDH_DB_MULTI_REGED );
+ retval = DialogBoxParam( (HINSTANCE)WINDOWS_APPLICATION::QueryInstance( ),
+ MAKEINTRESOURCE(MULTI_SZ_EDITOR_DLG),
+ hWnd,
+ ( DLGPROC ) EDITOR::MULTISZDialogProc,
+ ( DWORD ) &DialogInfo );
+ WINDOWS_APPLICATION::SetHelpContext( SaveHelpContext );
+ break;
+
+
+
+ default:
+
+ SaveHelpContext = WINDOWS_APPLICATION::GetHelpContext();
+ WINDOWS_APPLICATION::SetHelpContext( IDH_DB_BINARY_REGED );
+ retval = DialogBoxParam( (HINSTANCE)WINDOWS_APPLICATION::QueryInstance( ),
+ MAKEINTRESOURCE(BINARY_EDITOR_DLG),
+ hWnd,
+ ( DLGPROC ) EDITOR::BINARYDialogProc,
+ ( DWORD ) &DialogInfo );
+ WINDOWS_APPLICATION::SetHelpContext( SaveHelpContext );
+ break;
+
+ }
+
+ //
+ // Test if the edit succeeded...if it did, return the newly created
+ // block. Otherwise, blow the copy away and return NULL.
+ //
+
+
+ if( !retval ) {
+ FREE( DataStreamCopy );
+ *NumBytesOut = 0;
+ return( NULL );
+ }
+
+ *NumBytesOut = NumBytesIn;
+ return( DataStreamCopy );
+}
+
+PVOID
+EDITOR::Edit(
+ IN HWND hWnd,
+ IN REG_TYPE DataType,
+ IN PVOID DataStream,
+ IN ULONG NumBytesIn,
+ OUT PULONG NumBytesOut,
+ IN WORD MessageId
+)
+
+/*++
+
+Routine Description:
+
+ Provides an interface between the user code and the editors. The module
+ maps the MessageId to a Type and calls the above Edit method.
+
+Arguments:
+
+ hWnd - A handle to the owner window.
+
+ DataType - The type of data to be edited.
+
+ DataStream - A pointer to the data to edit.
+
+ NumBytesIn - The number of bytes to edit.
+
+ NumBytesOut - The number of bytes being returned.
+
+ MessageId - The value from the menu indicating which type of editor to
+ call. NOTE: This parameter becomes a DWORD when everything is
+ ported to 32 bits.
+
+Return Value:
+
+ Returns a PVOID indicating the result of the edit. NULL if no changes
+ were made.
+
+--*/
+
+{
+ REG_TYPE Type;
+
+ switch( MessageId ) {
+
+ case IDM_BINARY:
+
+ Type = TYPE_REG_BINARY;
+ break;
+
+ case IDM_STRING:
+
+ Type = TYPE_REG_SZ;
+ break;
+
+ case IDM_ULONG:
+
+ Type = TYPE_REG_DWORD;
+ break;
+
+ case IDM_MULTISZ:
+
+ Type = TYPE_REG_MULTI_SZ;
+ break;
+
+ default:
+ Type = TYPE_REG_BINARY;
+ break;
+ }
+
+ //
+ // Call the Edit() method with the new Type...
+ //
+
+ return Edit( hWnd, DataType, DataStream, NumBytesIn, NumBytesOut, Type );
+}
+
+LONG
+APIENTRY
+EXPORT
+EDITOR::EditInteger(
+ HWND hWnd,
+ WORD msg,
+ WPARAM wParam,
+ LONG lParam
+)
+/*++
+
+Routine Description:
+
+ This routine preprocesses the messages that are sent to the edit box
+ in the dialogs. This version will only check that valid characters are
+ entered and it will switch the displayed radix.
+
+Arguments:
+
+ hDlg - a handle to the dialog proceedure.
+
+ msg - the message passed from Windows.
+
+ wParam - extra message dependent data.
+
+ lParam - extra message dependent data.
+
+
+Return Value:
+
+ TRUE if the value was edited. FALSE if cancelled or if no
+ changes were made.
+
+--*/
+{
+ STATIC WPARAM state = IDD_HEX;
+ LPWSTR BinBuf;
+ LPWSTR BinPtr;
+ LPWSTR HexBuf;
+ LPWSTR HexPtr;
+ ULONG HexSize;
+ ULONG BinSize;
+ ULONG Offset;
+ INT Index;
+ LONG Count;
+ HCURSOR Cursor;
+ BASE CurrentBase;
+
+
+ switch( msg ) {
+
+
+ case WM_CHAR:
+
+
+ if( ( wParam == ( WCHAR )'\t' ) || ( wParam == ( WCHAR )'\b' ) || ( GetKeyState( VK_CONTROL ) < 0 ) ) {
+ break;
+ }
+
+ switch( state ) {
+
+ case IDD_BINARY:
+
+ //
+ // Test for a valid binary number
+ //
+ if( wParam != ( WCHAR )'1' && wParam != ( WCHAR )'0' ) {
+ return( TRUE );
+ }
+ break;
+
+ case IDD_DECIMAL:
+
+ // Unimplemented...
+ break;
+
+ case IDD_HEX:
+
+ //
+ // Test for a valid hex character...
+ //
+ if( !( ( ( wParam >= ( WCHAR )'A' && wParam <= ( WCHAR )'F' ) ||
+ ( wParam >= ( WCHAR )'a' && wParam <= ( WCHAR )'f' ) ||
+ ( wParam >= ( WCHAR )'0' && wParam <= ( WCHAR )'9' ) ) ) ) {
+ return( TRUE );
+ }
+ break;
+
+ }
+ break;
+
+ case EI_SETSTATE:
+
+ //
+ // Check if the current state is already set correctly...
+ //
+ if( state == wParam ) {
+ return( TRUE );
+ }
+ state = wParam;
+
+ if( SendMessage( hWnd, WM_GETTEXTLENGTH, 0, 0L ) == 0 ) {
+ return( TRUE );
+ }
+ switch( state ) {
+
+ case IDD_BINARY:
+
+ //
+ // Get the current text string and convert it to binary
+ //
+
+ HexSize = SendMessage( hWnd, WM_GETTEXTLENGTH, 0, 0L );
+ if( HexSize > 512 ) {
+ Cursor = WINDOWS_APPLICATION::DisplayHourGlass();
+ }
+
+ //
+ // The size of the binary buffer needs to be four times
+ // the size of the hex buffer.
+ //
+
+ BinSize = HexSize * 4;
+
+ //
+ // Allocate memory for the buffer
+ //
+
+ HexBuf = (LPWSTR)MALLOC( (size_t)((HexSize + 1)*sizeof( WCHAR ) ) );
+ BinBuf = (LPWSTR)MALLOC( (size_t)((BinSize + 1)*sizeof( WCHAR ) ) );
+
+ //
+ // Get the text from the window
+ //
+
+ SendMessage( hWnd, WM_GETTEXT, (UINT)(HexSize + 1), (DWORD)HexBuf );
+ *( HexBuf + HexSize ) = ( WCHAR )'\0';
+ *( BinBuf + BinSize ) = ( WCHAR )'\0';
+ CharUpperBuff( ( LPWSTR )HexBuf, HexSize );
+
+ //
+ // Set up the pointers to the buffers...
+ //
+
+ HexPtr = HexBuf;
+ BinPtr = BinBuf;
+
+ //
+ // Traverse the string and lookup all values in the
+ // table for conversions.
+ //
+
+ for( Offset = 0; Offset < HexSize; Offset++, HexPtr++ ) {
+ DebugAssert( ( ( *HexPtr >= ( WCHAR )'0' ) && ( *HexPtr <= ( WCHAR )'9' ) ||
+ ( *HexPtr >= ( WCHAR )'A' ) && ( *HexPtr <= ( WCHAR )'F' ) ) );
+ Index = *HexPtr - ( WCHAR )'0';
+ if( Index > 9 ) {
+ Index -= 7;
+ }
+ *BinPtr++ = NumLookup[ Index ].BinChar[0];
+ *BinPtr++ = NumLookup[ Index ].BinChar[1];
+ *BinPtr++ = NumLookup[ Index ].BinChar[2];
+ *BinPtr++ = NumLookup[ Index ].BinChar[3];
+ }
+
+
+ //
+ // Reset the window text
+ //
+
+// DebugPrintf( "Calling SendMessage with WM_SETTEXT \n" );
+ SendMessage( hWnd, WM_SETTEXT, 0, (DWORD)BinBuf );
+// DebugPrintf( "SendMessage returned \n" );
+
+ //
+ // Free the buffers.
+ //
+
+ FREE( HexBuf );
+ FREE( BinBuf );
+
+ if( HexSize > 512 ) {
+ WINDOWS_APPLICATION::RestoreCursor( Cursor );
+ }
+ break;
+
+
+ case IDD_HEX:
+
+ //
+ // Get the current text string (binary)
+ //
+
+ BinSize = SendMessage( hWnd, WM_GETTEXTLENGTH, 0, 0L );
+
+ //
+ // Make sure that the size is in whole nibbles.
+ //
+
+ if( ( Offset = BinSize % 4 ) != 0 ) {
+ Offset = 4 - Offset;
+ }
+
+
+ //
+ // The size of the hex buffer needs to be a quarter of
+ // the size of the binary buffer.
+ //
+
+ HexSize = ( BinSize + Offset ) / 4;
+
+ //
+ // Allocate memory for the buffer
+ //
+
+ HexBuf = (LPWSTR)MALLOC( (size_t)( (HexSize + 1)*sizeof( WCHAR ) ) );
+ BinBuf = (LPWSTR)MALLOC( (size_t)( (BinSize + Offset + 1 )*sizeof( WCHAR ) ) );
+
+ //
+ // Get the text from the window
+ //
+
+ SendMessage( hWnd, WM_GETTEXT, (WPARAM)(BinSize + 1), (LPARAM)BinBuf );
+
+ //
+ // Add the zeros to the end (padding) - Borrowing HexPtr since
+ // a BYTE pointer is required instead of a LONG pointer.
+ //
+
+ BinPtr = ( LPWSTR )(BinBuf + BinSize);
+ for( ; Offset; Offset-- ) {
+ *BinPtr = ( WCHAR )'0';
+ BinPtr++;
+ }
+ *BinPtr = ( WCHAR )'\0'; // Terminate the string....
+
+ //
+ // Set up the pointers to the buffers...
+ //
+
+ HexPtr = HexBuf;
+ BinPtr = BinBuf;
+
+ //
+ // Traverse the string and lookup all values in the
+ // table for conversions.
+ //
+ Offset = 0;
+ while( Offset < BinSize ) {
+ Index = 0;
+ for( Count = 0; Count < 4; Count++, Offset++ ) {
+ Index <<= 1;
+ Index |= ( *BinPtr++ == ( WCHAR )'1' );
+ }
+ *HexPtr++ = NumLookup[ Index ].Char;
+ }
+ *HexPtr = ( WCHAR )'\0';
+
+
+ //
+ // Reset the window text
+ //
+
+ SendMessage( hWnd, WM_SETTEXT, 0, (LPARAM)HexBuf );
+
+ //
+ // Free the buffers.
+ //
+
+ FREE( HexBuf );
+ FREE( BinBuf );
+
+ break;
+
+#if 0
+ //
+ // Get the current text string (binary)
+ //
+
+ BinSize = SendMessage( hWnd, WM_GETTEXTLENGTH, 0, 0L );
+
+ //
+ // Make sure that the size is in whole nibbles.
+ //
+
+ if( ( Offset = BinSize % 4 ) != 0 ) {
+ Offset = 4 - Offset;
+ }
+
+
+ //
+ // The size of the hex buffer needs to be a quarter of
+ // the size of the binary buffer.
+ //
+
+ HexSize = ( BinSize + Offset ) / 4;
+
+ //
+ // Allocate memory for the buffer
+ //
+
+ HexBuf = (LPWSTR)CALLOC( (size_t)(HexSize + 1), (size_t)sizeof( WCHAR ) );
+ BinBuf = (LPWSTR)CALLOC( (size_t)( BinSize + Offset + 1 ), (size_t)sizeof( WCHAR ) );
+
+ //
+ // Get the text from the window
+ //
+
+ SendMessage( hWnd, WM_GETTEXT, (WORD)BinSize + 1, (DWORD)BinBuf );
+
+ //
+ // Add the zeros to the end (padding) - Borrowing HexPtr since
+ // a BYTE pointer is required instead of a LONG pointer.
+ //
+
+ HexPtr = ( LPWSTR )(BinBuf + BinSize);
+ for( ; Offset; Offset-- ) {
+ *( HexPtr++ ) = ( WCHAR )'0';
+ }
+ *( HexPtr ) = ( WCHAR )'\0'; // Terminate the string....
+
+ //
+ // Set up the pointers to the buffers...
+ //
+
+ HexPtr = HexBuf;
+ BinPtr = BinBuf;
+
+ //
+ // Traverse the string and lookup all values in the
+ // table for conversions.
+ //
+ Offset = 0;
+ while( Offset < BinSize ) {
+ Index = 0;
+ for( Count = 0; Count < 4; Count++, Offset++ ) {
+ Index <<= 1;
+ Index |= ( *BinPtr++ == ( WCHAR )'1' );
+ }
+ *HexPtr++ = NumLookup[ Index ].Char;
+ }
+
+
+ //
+ // Reset the window text
+ //
+
+ SendMessage( hWnd, WM_SETTEXT, 0, (DWORD)HexBuf );
+
+ //
+ // Free the buffers.
+ //
+
+ FREE( HexBuf );
+ FREE( BinBuf );
+
+ break;
+#endif
+
+
+
+
+ }
+ return( TRUE );
+
+ case EI_GETSTATE:
+
+ return( state );
+
+
+ case WM_VSCROLL:
+
+ SendMessage( GetParent( hWnd ), EI_VSCROLL, 0, 0 );
+ break;
+
+ case WM_KEYDOWN:
+
+ if( ( ( wParam == VK_INSERT ) && ( GetKeyState( VK_SHIFT ) < 0 ) ) ||
+ ( ( ( wParam == ( WCHAR )'V' ) || ( wParam == ( WCHAR )'v' ) ) && ( GetKeyState( VK_CONTROL ) < 0 ) )
+ ) {
+ CurrentBase = ( state == IDD_HEX )? BASE_16 : BASE_2;
+ if( !IsClipboardDataValid( hWnd, FALSE, CurrentBase ) ) {
+ Beep( 500, 100 );
+ return( FALSE );
+ }
+ }
+ break;
+ }
+ //
+ // Call the old window routine to deal with everything else...
+ //
+ return( CallWindowProc( OldWndLong, hWnd, msg, wParam, lParam ) );
+}
+
+BOOL
+APIENTRY
+EXPORT
+EDITOR::BINARYDialogProc(
+ HWND hDlg,
+ WORD msg,
+ WPARAM wParam,
+ LONG lParam
+)
+/*++
+
+Routine Description:
+
+ The dialog proceedure for editing freeform BINARY data.
+
+Arguments:
+
+ hDlg - a handle to the dialog proceedure.
+
+ msg - the message passed from Windows.
+
+ wParam - extra message dependent data.
+
+ lParam - extra message dependent data.
+
+
+Return Value:
+
+ TRUE if the value was edited. FALSE if cancelled or if no
+ changes were made.
+
+--*/
+{
+ BYTE Tmp;
+ INT i;
+ PBYTE ptr2;
+ LPWSTR ptr;
+ LPWSTR NumString;
+ STATIC PBYTE* ppData;
+ STATIC PULONG NumBytesIn;
+ ULONG state;
+ ULONG size;
+ WSTR Buffer[256];
+ LONG LineNumber;
+ STATIC LONG PreviousLine;
+ HDC hDC;
+ SIZE StringSize;
+ RECT EditControlRectangle;
+
+ switch( msg ) {
+
+
+ case WM_INITDIALOG:
+
+
+ //
+ // First send a message to change the font in the list box.
+ //
+
+ SendDlgItemMessage(hDlg, IDD_BINARY_RULER, WM_SETFONT,
+ (WPARAM) GetStockObject(ANSI_FIXED_FONT), FALSE);
+
+ if( _HexRuler == NULL ) {
+ _HexRuler =
+ REGEDIT_BASE_SYSTEM::QueryString( MSG_EDITOR_HEX_RULER, "" );
+ }
+ if( _HexRuler != NULL ) {
+ SetDlgItemText( hDlg, IDD_BINARY_RULER, _HexRuler->GetWSTR() );
+ }
+
+ SendDlgItemMessage(hDlg, IDD_EDIT, WM_SETFONT,
+ (WPARAM) GetStockObject(ANSI_FIXED_FONT), FALSE);
+
+ //
+ // Adjust width of the multi line edit control, if the system is
+ // using large fonts
+ //
+ hDC = GetDC( GetDlgItem( hDlg, IDD_EDIT ) );
+ GetTextExtentPoint32( hDC,
+ (LPWSTR)L"000000000000000000000000000000000000000000000000000000000000000000",
+ 66,
+ &StringSize );
+ SendDlgItemMessage( hDlg, IDD_EDIT, EM_GETRECT, 0, (LPARAM)&EditControlRectangle );
+ if( StringSize.cx < EditControlRectangle.right - EditControlRectangle.left ) {
+ EditControlRectangle.right = EditControlRectangle.left +
+ StringSize.cx;
+ SendDlgItemMessage( hDlg, IDD_EDIT, EM_SETRECTNP, 0, (LPARAM)&EditControlRectangle );
+ }
+ ReleaseDC( GetDlgItem( hDlg, IDD_EDIT ), hDC );
+
+ //
+ // Get the data from the passed structure
+ //
+ ppData = (PBYTE*)( ( ( DIALOGINFO * )lParam )->DataObject );
+ NumBytesIn = ( ( DIALOGINFO * )lParam )->NumBytes;
+
+ //
+ // Subclass the edit box so the type of input and other
+ // modifications can be made.
+ //
+
+ OldWndLong = (WNDPROC)GetWindowLong( GetDlgItem( hDlg, IDD_EDIT ), GWL_WNDPROC );
+
+ SetWindowLong( GetDlgItem( hDlg, IDD_EDIT ),
+ GWL_WNDPROC,
+ (DWORD)MakeProcInstance( (FARPROC)EditInteger,
+ WINDOWS_APPLICATION::QueryInstance() ) );
+ //
+ // Send a message to the
+ //
+ // The default display for the number will be in Hex...
+ //
+ SendDlgItemMessage( hDlg, IDD_EDIT, EI_SETSTATE, IDD_HEX, 0L );
+
+ CheckRadioButton( hDlg, IDD_BINARY, IDD_HEX, IDD_HEX );
+
+ //
+ // Convert the input number into a text string - length is #bytes in * 2 (when separators added, length req'd is BytesIn*3 - 1 )
+ //
+ if( *NumBytesIn != 0 ) {
+ NumString = (LPWSTR)MALLOC( ( size_t )( (*NumBytesIn * 2 + 1)*sizeof( WCHAR ) ) );
+ BytesToHexString( (PBYTE)*ppData, (INT)(*NumBytesIn), (LPTSTR)NumString );
+
+ //
+ // Place the text string in the dialog...
+ //
+ SetDlgItemText( hDlg, IDD_EDIT, NumString );
+ FREE( NumString );
+ }
+
+ LineNumber = SendDlgItemMessage( hDlg, IDD_EDIT, EM_GETFIRSTVISIBLELINE, 0, 0 );
+ PreviousLine = LineNumber;
+ swprintf( Buffer,
+ (LPWSTR)L"%04x\n%04x\n%04x\n%04x\n%04x\n%04x\n%04x\n%04x",
+ ( LineNumber )*32,
+ ( LineNumber+1 )*32,
+ ( LineNumber+2 )*32,
+ ( LineNumber+3 )*32,
+ ( LineNumber+4 )*32,
+ ( LineNumber+5 )*32,
+ ( LineNumber+6 )*32,
+ ( LineNumber+7 )*32 );
+
+ SendDlgItemMessage(hDlg, IDD_VERTICAL_RULER, WM_SETFONT,
+ (WPARAM) GetStockObject(ANSI_FIXED_FONT), FALSE);
+
+ SetDlgItemText( hDlg, IDD_VERTICAL_RULER, Buffer );
+
+ return( TRUE );
+
+ case WM_COMMAND:
+
+
+ switch( LOWORD( wParam ) ) {
+
+ case IDD_BINARY:
+
+ //
+ // Inform the editor that the radix has changed...
+ //
+ SendDlgItemMessage( hDlg, IDD_EDIT, EI_SETSTATE, wParam, 0L );
+
+ //
+ // Put a new ruler in the dialog
+ //
+ if( _BinaryRuler == NULL ) {
+ _BinaryRuler =
+ REGEDIT_BASE_SYSTEM::QueryString( MSG_EDITOR_BINARY_RULER, "" );
+ }
+ if( _BinaryRuler != NULL ) {
+ SetDlgItemText( hDlg, IDD_BINARY_RULER, _BinaryRuler->GetWSTR() );
+ }
+
+ LineNumber = SendDlgItemMessage( hDlg, IDD_EDIT, EM_GETFIRSTVISIBLELINE, 0, 0 );
+
+ swprintf( Buffer,
+ (LPWSTR)L"%04x\n%04x\n%04x\n%04x\n%04x\n%04x\n%04x\n%04x",
+ ( LineNumber )*8,
+ ( LineNumber+1 )*8,
+ ( LineNumber+2 )*8,
+ ( LineNumber+3 )*8,
+ ( LineNumber+4 )*8,
+ ( LineNumber+5 )*8,
+ ( LineNumber+6 )*8,
+ ( LineNumber+7 )*8 );
+
+
+ SetDlgItemText( hDlg, IDD_VERTICAL_RULER, Buffer );
+ return( TRUE );
+
+ case IDD_HEX:
+
+ //
+ // Inform the editor that the radix has changed...
+ //
+ SendDlgItemMessage( hDlg, IDD_EDIT, EI_SETSTATE, wParam, 0L );
+
+ //
+ // Put a new ruler in the dialog
+ //
+ if( _HexRuler == NULL ) {
+ _HexRuler =
+ REGEDIT_BASE_SYSTEM::QueryString( MSG_EDITOR_HEX_RULER, "" );
+ }
+ if( _HexRuler != NULL ) {
+ SetDlgItemText( hDlg, IDD_BINARY_RULER, _HexRuler->GetWSTR() );
+ }
+
+
+ LineNumber = SendDlgItemMessage( hDlg, IDD_EDIT, EM_GETFIRSTVISIBLELINE, 0, 0 );
+
+ swprintf( Buffer,
+ (LPWSTR)L"%04x\n%04x\n%04x\n%04x\n%04x\n%04x\n%04x\n%04x",
+ ( LineNumber )*32,
+ ( LineNumber+1 )*32,
+ ( LineNumber+2 )*32,
+ ( LineNumber+3 )*32,
+ ( LineNumber+4 )*32,
+ ( LineNumber+5 )*32,
+ ( LineNumber+6 )*32,
+ ( LineNumber+7 )*32 );
+
+
+ SetDlgItemText( hDlg, IDD_VERTICAL_RULER, Buffer );
+ return( TRUE );
+
+ case IDOK:
+
+ //
+ // Get the current size and state...
+ //
+ state = SendDlgItemMessage( hDlg, IDD_EDIT, EI_GETSTATE, 0, 0L );
+ size = SendDlgItemMessage( hDlg, IDD_EDIT, WM_GETTEXTLENGTH, 0, 0L );
+ if( size == 0 ) {
+ *NumBytesIn = 0;
+ EndDialog( hDlg, TRUE );
+ return( TRUE );
+ }
+
+ //
+ // If number of bytes isn't an even number for the current
+ // state, inform the user. If he/she decides to continue,
+ // increment the size until it is even and pad the end of the
+ // data with zeros.
+ //
+ if( ( ( i = (INT)( size % 8 ) ) && ( state == IDD_BINARY ) ) ||
+ ( ( i = (INT)( size % 2 ) ) && ( state == IDD_HEX ) ) ) {
+ //
+ // Padding will occur.
+ // Display popup to the user to inform about the
+ // padding
+ //
+ if( DisplayConfirmPopup( hDlg,
+ MSG_ADD_VALUE_WARN_PADDING_EX ) != IDYES ) {
+ //
+ // If the user hit Cancel, let him/her enter a new value
+ //
+ SetFocus( GetDlgItem( hDlg, IDD_EDIT ) );
+ return( TRUE );
+ }
+
+ if( state == IDD_BINARY ) {
+ i = 8 - i;
+ } else if( state == IDD_HEX ) {
+ i = 1;
+ }
+ }
+
+ //
+ // Allocate a buffer to store the string...
+ //
+ NumString = (LPWSTR)CALLOC( ( size_t )(size + i + 1), (size_t)sizeof( WCHAR ) );
+ GetDlgItemText( hDlg, IDD_EDIT, NumString, (INT)(size + 1) );
+
+ //
+ // Add the zeros to the end (padding)
+ //
+ ptr = NumString + size;
+ size += i;
+ for( ; i; i-- ) {
+ *( ptr++ ) = ( WCHAR )'0';
+ }
+ *( ptr ) = ( WCHAR )'\0'; // Terminate the string....
+
+ //
+ // Convert the displayed text back into a number...
+ //
+ if( state == IDD_BINARY ) {
+
+ //
+ // Calculate the new length of the string...
+ //
+ *NumBytesIn = size / 8;
+ if( *ppData != NULL ) {
+ *ppData = (PBYTE)REALLOC( *ppData, (size_t)(*NumBytesIn) );
+ } else {
+ *ppData = ( PBYTE )MALLOC( (size_t)(*NumBytesIn) );
+ }
+ ptr = NumString;
+ ptr2 = *ppData;
+ do {
+ for( i = 0, Tmp = 0; i < 8; i++, ptr++ ) {
+ if( !*ptr ) {
+ break;
+ }
+ Tmp <<= 1;
+ Tmp += ( *ptr != (WCHAR)'0' );
+ }
+ if( i ) {
+ *ptr2 = Tmp;
+ ptr2++;
+ }
+ } while( *ptr );
+
+ } else if( state == IDD_HEX ) {
+ CharUpperBuff( NumString, size );
+ *NumBytesIn = size / 2;
+ if( *ppData != NULL ) {
+ *ppData = (PBYTE)REALLOC( *ppData, (size_t)(*NumBytesIn) );
+ } else {
+ *ppData = ( PBYTE )MALLOC( ( size_t )(*NumBytesIn) );
+ }
+ ptr = NumString;
+ ptr2 = *ppData;
+ do {
+ for( i = 0, Tmp = 0; i < 2; i++, ptr++ ) {
+ if( !*ptr ) {
+ break;
+ }
+ Tmp <<= 4;
+ Tmp += IsCharAlpha( *ptr ) ? ( *ptr - (WCHAR)'A' + 10 ) : ( *ptr - ( WCHAR )'0' );
+ }
+ if( i ) {
+ *ptr2 = Tmp;
+ ptr2++;
+ }
+ } while( *ptr );
+
+ }
+
+ EndDialog( hDlg, TRUE );
+ return( TRUE );
+
+ case IDCANCEL:
+
+ EndDialog( hDlg, FALSE );
+ return( TRUE );
+
+ case IDB_HELP:
+ DisplayHelp();
+ return( TRUE );
+
+ case IDD_EDIT:
+
+ if( ( HIWORD( wParam ) == EN_VSCROLL ) ||
+ ( HIWORD( wParam ) == EN_CHANGE ) ) {
+ state = SendDlgItemMessage( hDlg, IDD_EDIT, EI_GETSTATE, 0, 0L );
+ LineNumber = SendDlgItemMessage( hDlg, IDD_EDIT, EM_GETFIRSTVISIBLELINE, 0, 0 );
+ if( PreviousLine != LineNumber ) {
+ PreviousLine = LineNumber;
+ if( state == IDD_BINARY ) {
+ swprintf( Buffer,
+ (LPWSTR)L"%04x\n%04x\n%04x\n%04x\n%04x\n%04x\n%04x\n%04x",
+ ( LineNumber )*8,
+ ( LineNumber+1 )*8,
+ ( LineNumber+2 )*8,
+ ( LineNumber+3 )*8,
+ ( LineNumber+4 )*8,
+ ( LineNumber+5 )*8,
+ ( LineNumber+6 )*8,
+ ( LineNumber+7 )*8 );
+ } else {
+ swprintf( Buffer,
+ (LPWSTR)L"%04x\n%04x\n%04x\n%04x\n%04x\n%04x\n%04x\n%04x",
+ ( LineNumber )*32,
+ ( LineNumber+1 )*32,
+ ( LineNumber+2 )*32,
+ ( LineNumber+3 )*32,
+ ( LineNumber+4 )*32,
+ ( LineNumber+5 )*32,
+ ( LineNumber+6 )*32,
+ ( LineNumber+7 )*32 );
+ }
+ SetDlgItemText( hDlg, IDD_VERTICAL_RULER, Buffer );
+ return( FALSE );
+ }
+ }
+ return( FALSE );
+ }
+ break;
+
+ case EI_VSCROLL:
+
+ state = SendDlgItemMessage( hDlg, IDD_EDIT, EI_GETSTATE, 0, 0L );
+ LineNumber = SendDlgItemMessage( hDlg, IDD_EDIT, EM_GETFIRSTVISIBLELINE, 0, 0 );
+ if( PreviousLine != LineNumber ) {
+ PreviousLine = LineNumber;
+ if( state == IDD_BINARY ) {
+ swprintf( Buffer,
+ (LPWSTR)L"%04x\n%04x\n%04x\n%04x\n%04x\n%04x\n%04x\n%04x",
+ ( LineNumber )*8,
+ ( LineNumber+1 )*8,
+ ( LineNumber+2 )*8,
+ ( LineNumber+3 )*8,
+ ( LineNumber+4 )*8,
+ ( LineNumber+5 )*8,
+ ( LineNumber+6 )*8,
+ ( LineNumber+7 )*8 );
+ } else {
+ swprintf( Buffer,
+ (LPWSTR)L"%04x\n%04x\n%04x\n%04x\n%04x\n%04x\n%04x\n%04x",
+ ( LineNumber )*32,
+ ( LineNumber+1 )*32,
+ ( LineNumber+2 )*32,
+ ( LineNumber+3 )*32,
+ ( LineNumber+4 )*32,
+ ( LineNumber+5 )*32,
+ ( LineNumber+6 )*32,
+ ( LineNumber+7 )*32 );
+ }
+ SetDlgItemText( hDlg, IDD_VERTICAL_RULER, Buffer );
+ return( TRUE );
+ }
+ return TRUE;
+ }
+ return( FALSE );
+}
+
+
+BOOL
+APIENTRY
+EXPORT
+EDITOR::SZDialogProc(
+ HWND hDlg,
+ WORD msg,
+ WPARAM wParam,
+ LONG lParam
+)
+/*++
+
+Routine Description:
+
+ The dialog proceedure for editing Zero-terminated strings.
+
+Arguments:
+
+ hDlg - a handle to the dialog proceedure.
+
+ msg - the message passed from Windows.
+
+ wParam - extra message dependent data.
+
+ lParam - extra message dependent data.
+
+
+Return Value:
+
+ TRUE if the value was edited. FALSE if cancelled or if no
+ changes were made.
+
+--*/
+{
+ STATIC PBYTE* ppData;
+ STATIC PULONG pnBytesIn;
+ ULONG nBytes;
+ DSTRING String;
+ PWSTR Pointer;
+
+ switch( msg ) {
+
+ case WM_INITDIALOG:
+
+ //
+ // Get the data from the passed structure
+ //
+
+ ppData = (PBYTE *)( ( ( DIALOGINFO * )lParam )->DataObject );
+ pnBytesIn = ( ( DIALOGINFO * )lParam )->NumBytes;
+
+ //
+ // Place the input text into the edit window
+ //
+ if( *pnBytesIn != 0 ) {
+ if( !String.Initialize( ( PWSTR )*ppData, *pnBytesIn / sizeof( WCHAR ) ) ) {
+ DebugPrint( "String.Initialize() failed" );
+ return( FALSE );
+ }
+ Pointer = String.QueryWSTR();
+ DebugPtrAssert( Pointer );
+ SetDlgItemText( hDlg, IDD_EDIT, Pointer );
+ FREE( Pointer );
+ }
+ return( TRUE );
+
+ case WM_COMMAND:
+
+ switch( LOWORD( wParam ) ) {
+
+ case IDOK:
+
+ //
+ // Get the number of characters currently in the edit window adding one
+ // for the terminating null.
+ //
+ nBytes = SendDlgItemMessage( hDlg, IDD_EDIT, WM_GETTEXTLENGTH, 0, 0L );
+ if( nBytes == 0 ) {
+ if( ( *pnBytesIn != 0 ) && ( *ppData != NULL ) ) {
+ // Must reallocate the buffer
+ *ppData = (PBYTE)REALLOC( *ppData, ( size_t )sizeof( WCHAR ) );
+ } else {
+ *ppData = ( PBYTE )MALLOC( ( size_t )sizeof( WCHAR ) );
+ }
+ //
+ // Put a UNICODE NULL in the buffer.
+ // Don't forget that *ppData is a PBYTE
+ //
+ *((PWCHAR)(*ppData)) = ( WCHAR )'\0';
+ *pnBytesIn = sizeof( WCHAR );
+
+ } else {
+ nBytes = nBytes + 1;
+ if( nBytes != *pnBytesIn/sizeof( WCHAR ) ) {
+ if( *ppData != NULL ) {
+ // Must reallocate the buffer
+ *ppData = (PBYTE)REALLOC( *ppData, ( size_t )(nBytes*sizeof(WCHAR)) );
+ } else {
+ *ppData = ( PBYTE )MALLOC( ( size_t ) (nBytes*sizeof( WCHAR )) );
+ }
+ }
+
+ GetDlgItemText( hDlg, IDD_EDIT, ( PWSTR )*ppData, ( INT ) nBytes );
+ if( !String.Initialize( ( PWSTR )*ppData ) ) {
+ DebugPrint( "String.Initialize() failed" );
+ return( FALSE );
+ }
+
+ FREE( *ppData );
+ *ppData = ( PBYTE )String.QueryWSTR();
+ DebugPtrAssert( *ppData );
+ *pnBytesIn = ( String.QueryChCount() + 1 )*sizeof( WCHAR );
+ }
+ EndDialog( hDlg, TRUE );
+ return( TRUE );
+
+ case IDCANCEL:
+
+ EndDialog( hDlg, FALSE );
+ return( TRUE );
+
+ case IDB_HELP:
+ DisplayHelp();
+ return( TRUE );
+ }
+ }
+ return( FALSE );
+}
+
+
+
+
+BOOL
+APIENTRY
+EXPORT
+EDITOR::MULTISZDialogProc(
+ HWND hDlg,
+ WORD msg,
+ WPARAM wParam,
+ LONG lParam
+)
+/*++
+
+Routine Description:
+
+ The dialog proceedure for editing multi-strings.
+
+Arguments:
+
+ hDlg - a handle to the dialog proceedure.
+
+ msg - the message passed from Windows.
+
+ wParam - extra message dependent data.
+
+ lParam - extra message dependent data.
+
+
+Return Value:
+
+ TRUE if the value was edited. FALSE if cancelled or if no
+ changes were made.
+
+--*/
+{
+ STATIC PBYTE* ppData;
+ STATIC PULONG pnBytesIn;
+ STATIC REG_TYPE DataType;
+
+
+ ULONG CharacterIndex;
+ ULONG NumberOfLines;
+ ULONG Line;
+ USHORT StringSize;
+ USHORT MaxStringSize;
+
+
+ DSTRING ConvertString;
+ PWSTR UnicodeString;
+ PWSTR SrcPointer;
+
+ PWSTR ReadBuffer;
+
+ PWSTR MultiSzBuffer;
+ ULONG MultiSzBufferSize;
+ PWSTR DestPointer;
+
+ PWSTR SingleSz;
+
+ ULONG EmptyStringsCount;
+
+
+
+ switch( msg ) {
+
+ case WM_INITDIALOG:
+
+ //
+ // Get the data from the passed structure
+ //
+
+ ppData = (PBYTE *)( ( ( DIALOGINFO * )lParam )->DataObject );
+ pnBytesIn = ( ( DIALOGINFO * )lParam )->NumBytes;
+ DataType = ( ( DIALOGINFO * )lParam )->DataType;
+
+ //
+ // Change maximum number of characters of the edit control, to its
+ // maximum limit (from 3000 characters to 4G characters).
+ //
+ SendDlgItemMessage( hDlg, IDD_MULTI_SZ_EDIT_CONTROL, EM_LIMITTEXT, 0, 0L );
+
+ //
+ // Place the input text into the edit window
+ //
+
+ if( *pnBytesIn != 0 ) {
+ if( DataType != TYPE_REG_SZ ) {
+ SingleSz = ConvertMultiSzToSingleSz( *ppData, *pnBytesIn );
+ DebugPtrAssert( SingleSz );
+#if 0
+ ConvertString.Initialize( SingleSz );
+ AnsiString = ConvertString.QuerySTR();
+ DebugPtrAssert( AnsiString );
+ SetDlgItemText( hDlg, IDD_MULTI_SZ_EDIT_CONTROL, AnsiString );
+ FREE( SingleSz );
+#endif
+ SetDlgItemText( hDlg, IDD_MULTI_SZ_EDIT_CONTROL, SingleSz );
+ FREE( SingleSz );
+ } else {
+#if 0
+ ConvertString.Initialize( ( PBYTE )*ppData, *pnBytesIn/sizeof( WCHAR ) );
+ AnsiString = ConvertString.QueryWSTR();
+ SetDlgItemText( hDlg, IDD_MULTI_SZ_EDIT_CONTROL, AnsiString );
+ FREE( AnsiString );
+#endif
+ SetDlgItemText( hDlg, IDD_MULTI_SZ_EDIT_CONTROL, (PWSTR)*ppData );
+ }
+ }
+ return( TRUE );
+
+ case WM_COMMAND:
+
+ switch( LOWORD( wParam ) ) {
+
+ case IDOK:
+
+#if 0
+ if( DataType == TYPE_REG_SZ ) {
+ //
+ // Special case for data of type REG_SZ that is edited
+ // with the MULTI_SZ editor.
+ // In this case ass empty lines and CR-LF are preserved
+ //
+ //
+ StringSize = SendDlgItemMessage( hDlg,
+ IDD_MULTI_SZ_EDIT_CONTROL,
+ WM_GETTEXTLENGTH,
+ NULL,
+ NULL );
+
+
+ ReadBuffer = ( PSTR )MALLOC( ( size_t )( StringSize + 1 ) );
+ DebugPtrAssert( ReadBuffer );
+
+ SendDlgItemMessage( hDlg,
+ IDD_MULTI_SZ_EDIT_CONTROL,
+ WM_GETTEXT,
+ StringSize+1,
+ ( LPARAM )ReadBuffer );
+
+
+ ConvertString.Initialize( ( PSTR )ReadBuffer, StringSize );
+
+ *ppData = ( PSTR )ConvertString.QueryWSTR();
+ *pnBytesIn = (StringSize+1)*sizeof( WCHAR );
+
+ EndDialog( hDlg, TRUE );
+ return( TRUE );
+ }
+#endif
+ //
+ // Find out the size of the buffer needed to build the REG_MULTISZ
+ // data
+ //
+
+ MaxStringSize = 0;
+ MultiSzBufferSize = 0;
+ NumberOfLines = SendDlgItemMessage( hDlg, IDD_MULTI_SZ_EDIT_CONTROL, EM_GETLINECOUNT, NULL, NULL );
+
+ for( Line = 0; Line < NumberOfLines; Line++ ) {
+ CharacterIndex = SendDlgItemMessage( hDlg, IDD_MULTI_SZ_EDIT_CONTROL, EM_LINEINDEX, (UINT)Line, NULL );
+ StringSize = (USHORT)SendDlgItemMessage( hDlg, IDD_MULTI_SZ_EDIT_CONTROL, EM_LINELENGTH, (UINT)CharacterIndex, NULL );
+
+ if( StringSize != 0 ) {
+ MultiSzBufferSize += StringSize + 1;
+
+ MaxStringSize = ( MaxStringSize > StringSize )? MaxStringSize : StringSize;
+ }
+ }
+ if( MultiSzBufferSize == 0 ) {
+ if( ( *ppData != NULL ) && ( *pnBytesIn != 0 ) ) {
+ FREE( *ppData );
+ }
+ *ppData = ( PBYTE )MALLOC( 2*sizeof( WCHAR ) );
+ DebugPtrAssert( *ppData );
+ if( *ppData == NULL ) {
+ *pnBytesIn = 0;
+ } else {
+ *pnBytesIn = sizeof( WCHAR );
+ **ppData = ( WCHAR )'\0';
+ *(*ppData + 1 ) = ( WCHAR )'\0';
+
+ }
+ EndDialog( hDlg, TRUE );
+ return( TRUE );
+ }
+ if( MaxStringSize <= 1 ) {
+ MaxStringSize = sizeof( WORD );
+ }
+
+ MultiSzBufferSize++;
+
+
+ //
+ // Create the buffers
+ //
+
+ MultiSzBuffer = ( PWSTR )MALLOC( ( size_t )( ( MultiSzBufferSize + 1 )*sizeof( WCHAR ) ) );
+ DebugPtrAssert( MultiSzBuffer );
+ ReadBuffer = ( PWSTR )MALLOC( ( size_t )( (MaxStringSize + 1)*sizeof(WCHAR) ) );
+ DebugPtrAssert( ReadBuffer );
+
+ DestPointer = MultiSzBuffer;
+
+ //
+ // Read each line and copy it to the buffer
+ //
+
+ EmptyStringsCount = 0;
+ for( Line = 0; Line < NumberOfLines; Line++ ) {
+
+ CharacterIndex = SendDlgItemMessage( hDlg, IDD_MULTI_SZ_EDIT_CONTROL, EM_LINEINDEX, (UINT)Line, NULL );
+
+ StringSize = (USHORT)SendDlgItemMessage( hDlg, IDD_MULTI_SZ_EDIT_CONTROL, EM_LINELENGTH, (UINT)CharacterIndex, NULL );
+ if( StringSize != 0 ) {
+ *ReadBuffer = (USHORT)( MaxStringSize + 1 );
+ StringSize = ( USHORT )SendDlgItemMessage( hDlg, IDD_MULTI_SZ_EDIT_CONTROL, EM_GETLINE, (UINT)Line, ( LPARAM )ReadBuffer );
+
+ ConvertString.Initialize( ( PWSTR )( ReadBuffer ), StringSize );
+ UnicodeString = ( PWSTR )ConvertString.QueryWSTR();
+ DebugPtrAssert( UnicodeString );
+ SrcPointer = UnicodeString;
+ while( *DestPointer++ = *SrcPointer++ );
+ FREE( UnicodeString );
+ } else {
+ if( Line != NumberOfLines - 1 ) {
+ EmptyStringsCount++;
+ }
+ }
+
+ }
+// if( DataType == TYPE_REG_SZ ) {
+// MultiSzBufferSize--;
+// } else {
+ *DestPointer = ( WCHAR )'\0';
+// }
+
+ FREE( *ppData );
+ *ppData = ( PBYTE )MultiSzBuffer;
+ *pnBytesIn = MultiSzBufferSize*sizeof( WCHAR );
+
+ if( EmptyStringsCount != 0 ) {
+ DisplayWarningPopup( hDlg,
+ ( EmptyStringsCount == 1 )?
+ MSG_ADD_VALUE_REMOVE_EMPTY_STRING_EX :
+ MSG_ADD_VALUE_REMOVE_EMPTY_STRINGS_EX,
+ MSG_WARNING_TITLE );
+ }
+
+ EndDialog( hDlg, TRUE );
+ return( TRUE );
+
+ case IDCANCEL:
+
+ EndDialog( hDlg, FALSE );
+ return( TRUE );
+
+ case IDB_HELP:
+ DisplayHelp();
+ return( TRUE );
+ }
+ }
+ return( FALSE );
+}
+
+
+
+BOOL
+APIENTRY
+EXPORT
+EDITOR::DWORDDialogProc(
+ HWND hDlg,
+ WORD msg,
+ WPARAM wParam,
+ LONG lParam
+)
+/*++
+
+Routine Description:
+
+ The dialog proceedure for editing DWORD data.
+
+Arguments:
+
+ hDlg - a handle to the dialog proceedure.
+
+ msg - the message passed from Windows.
+
+ wParam - extra message dependent data.
+
+ lParam - extra message dependent data.
+
+
+Return Value:
+
+ TRUE if the value was edited. FALSE if cancelled or if no
+ changes were made.
+
+--*/
+{
+ STATIC LPDWORD* Data;
+ STATIC PULONG NumBytesIn;
+ ULONG Count;
+ ULONG Mask;
+ LPWSTR NumString;
+ ULONG State;
+ ULONG Size;
+ DWORD Result;
+ LPWSTR Pointer;
+ ULONG EditLength;
+ BOOL translated;
+
+
+
+ PWSTR MaxValueString = (LPWSTR)L"4294967295"; // Maximum decimal value represented by a DWORD
+ WCHAR Buffer[ 8*sizeof( DWORD ) + 1 ]; // 32 binary digits + NULL
+
+ BYTE Array[ sizeof( DWORD ) ];
+ ULONG Index;
+
+ DSTRING ConvertString;
+
+ switch( msg ) {
+
+ case WM_INITDIALOG:
+
+ //
+ // Get the data from the passed structure
+ //
+ Data = ( LPDWORD* )( ( ( DIALOGINFO * )lParam )->DataObject );
+ NumBytesIn = ( ( DIALOGINFO * )lParam )->NumBytes;
+
+ //
+ // Subclass the edit box so the type of input and other
+ // modifications can be made.
+ //
+
+ OldWndLong = (WNDPROC)GetWindowLong( GetDlgItem( hDlg, IDD_EDIT ), GWL_WNDPROC );
+
+
+ SetWindowLong( GetDlgItem( hDlg, IDD_EDIT ),
+ GWL_WNDPROC,
+ (DWORD)MakeProcInstance( (FARPROC)EditDWORD,
+ WINDOWS_APPLICATION::QueryInstance() ) );
+ //
+ // Send a message to the
+ //
+ // The default display for the number will be in Hex...
+ //
+
+ SendDlgItemMessage( hDlg, IDD_EDIT, EI_SETSTATE, IDD_HEX, 0L );
+ CheckRadioButton( hDlg, IDD_BINARY, IDD_HEX, IDD_HEX );
+ SendDlgItemMessage( hDlg, IDD_EDIT, EM_LIMITTEXT, 8, 0L );
+
+
+ //
+ // Convert the input number into a text string
+ //
+ if( *NumBytesIn != 0 ) {
+ NumString = (LPWSTR)MALLOC( ( size_t )( (2*sizeof( DWORD ) + 1)*sizeof( WCHAR ) ) );
+ DebugPtrAssert( NumString );
+ if( *NumBytesIn >= sizeof( DWORD ) ) {
+ _itoa( (INT)(**Data), (PCHAR)NumString, 16 );
+ ConvertString.Initialize( (PSTR)NumString );
+ FREE( NumString );
+ NumString = ConvertString.QueryWSTR();
+
+ } else {
+ //
+ // Make sure we won't display garbage, if the number of
+ // bytes in the buffer is less than the size of a DWORD
+ //
+ for( Index = 0; Index < *NumBytesIn; Index++ ) {
+ Array[ Index ] = *( (PBYTE)(((PBYTE)*Data) + Index) );
+ }
+ for( ;Index < sizeof( DWORD ); Index++ ) {
+ Array[ Index ] = 0;
+ }
+ _itoa( ( int )( *Array ), (PCHAR)NumString, 16 );
+ ConvertString.Initialize( (PSTR)NumString );
+ FREE( NumString );
+ NumString = ConvertString.QueryWSTR();
+ }
+ //
+ // Place the text string in the dialog...
+ //
+ SetDlgItemText( hDlg, IDD_EDIT, NumString );
+ FREE( NumString );
+ }
+
+ return( TRUE );
+
+ case WM_COMMAND:
+
+
+ switch( LOWORD( wParam ) ) {
+
+ case IDD_BINARY:
+ case IDD_DECIMAL:
+ case IDD_HEX:
+
+ State = SendDlgItemMessage( hDlg, IDD_EDIT, EI_GETSTATE, 0, 0L );
+ if( ( State == IDD_DECIMAL ) &&
+ ( LOWORD( wParam ) != IDD_DECIMAL ) ) {
+ //
+ // If the radix changed from decimal to Hex or Binary,
+ // verify whether a truncation will occur.
+ //
+
+ Result = GetDlgItemInt(hDlg, IDD_EDIT, &translated,
+ FALSE);
+ if( ( Result == 0 ) &&
+ ( translated == 0 ) ) {
+ //
+ // If truncation will occur, find out if the user
+ // changed radix (from decimal to binary or hex) using
+ // the arrow keys, by examining if the radio button
+ // 'Decimal' is checked. If it is checked, the user
+ // used one of the arrow keys. Otherwise, the user
+ // used the mouse or one of the accelerators for the
+ // radio buttons.
+ //
+ // When the user changes the radix using the arrow keys
+ // windows will first move the focus from the 'decimal'
+ // radio button to 'binary' or 'hex' radio buttons, and
+ // then check the radio button.
+ // This will cause two identical BN_CLICKED messages to
+ // be sent, and we have to ignore one of them, otherwise
+ // the truncation warning dialog will be displayed twice.
+ // We decide which BN_CLICKED message we are processing
+ // by examining the state of the radio button 'hex'. If
+ // it is set, then it the message is the first one.
+ // Note that if the user uses the mouse or the accelerator
+ // keys to change radix, only one BN_CLICKED will be sent
+ // as the focus and the selection will be moved to the
+ // newly selected radio button, at the same time.
+ // According to ScottLu this is not a bug on windows,
+ // but it is just the way it works.
+ //
+ //
+ if( IsDlgButtonChecked( hDlg, IDD_DECIMAL ) == 1 ) {
+ return( TRUE );
+ }
+
+ //
+ // If truncation will occur, display popup to inform
+ // the user
+ //
+
+ if( DisplayConfirmPopup( hDlg,
+ MSG_ADD_VALUE_WARN_OVERFLOW_EX,
+ MSG_ADD_VALUE_WARN_OVERFLOW ) != IDYES ) {
+ //
+ // If the user hit Cancel, let him/her enter a new value
+ //
+ CheckRadioButton( hDlg, IDD_BINARY, IDD_HEX, IDD_DECIMAL );
+ SetFocus( GetDlgItem( hDlg, IDD_EDIT ) );
+ return( TRUE );
+ }
+ }
+
+ }
+
+ //
+ // Inform the editor that the radix has changed...
+ //
+ if( wParam == IDD_BINARY ) {
+ EditLength = 32;
+ } else if ( wParam == IDD_DECIMAL ) {
+ EditLength = 10;
+ } else {
+ EditLength = 8;
+ }
+ SendDlgItemMessage( hDlg, IDD_EDIT, EM_LIMITTEXT, ( WPARAM )EditLength, 0L );
+ SendDlgItemMessage( hDlg, IDD_EDIT, EI_SETSTATE, wParam, 0L );
+ return( TRUE );
+
+ case IDOK:
+
+ //
+ // Get the current size and state...
+ //
+ State = SendDlgItemMessage( hDlg, IDD_EDIT, EI_GETSTATE, 0, 0L );
+ Size = (USHORT)SendDlgItemMessage( hDlg, IDD_EDIT, WM_GETTEXTLENGTH, 0, 0L );
+
+ if( Size == 0 ) {
+ *NumBytesIn = 0;
+ } else {
+
+ switch( State ){
+
+
+ case IDD_BINARY:
+
+ NumString = (LPWSTR)CALLOC( (size_t)(8*sizeof( DWORD ) + 1),(size_t)sizeof(WCHAR) );
+ DebugPtrAssert( NumString );
+ for( Index = 0; Index < 8*sizeof( DWORD) - Size; Index++ ) {
+ NumString[ Index ] = ( WCHAR )'0';
+ }
+ GetDlgItemText( hDlg,
+ IDD_EDIT,
+ NumString + ( 8*sizeof( DWORD ) - Size ),
+ (INT)( Size + 1 ) );
+
+ Count = 0;
+ Result = 0;
+ Mask = 0x80000000;
+ Pointer = NumString;
+ while( Mask != 0 ) {
+ if( *Pointer != '0' ) {
+ Result |= Mask;
+ }
+ Pointer++;
+ Mask = Mask >> 1;
+ }
+ if( *NumBytesIn != sizeof( DWORD ) ) {
+ if( *Data != NULL ) {
+ *Data = ( LPDWORD )REALLOC( *Data, ( size_t)( sizeof( DWORD ) ) );
+ } else {
+ *Data = ( LPDWORD )MALLOC( ( size_t )sizeof( DWORD ) );
+ }
+ }
+ **Data = Result;
+ *NumBytesIn = sizeof( DWORD );
+ FREE( NumString );
+ break;
+
+
+ case IDD_DECIMAL:
+
+ Result = GetDlgItemInt(hDlg, IDD_EDIT, &translated,
+ FALSE);
+ if( ( Result == 0 ) &&
+ ( translated == 0 ) ) {
+ //
+ // If truncation will occur, display popup to inform
+ // the user
+ //
+ if( DisplayConfirmPopup( hDlg,
+ MSG_ADD_VALUE_WARN_OVERFLOW_EX,
+ MSG_ADD_VALUE_WARN_OVERFLOW ) != IDYES ) {
+ //
+ // If the user hit Cancel, let him/her enter a new value
+ //
+ CheckRadioButton( hDlg, IDD_BINARY, IDD_HEX, IDD_DECIMAL );
+ SetFocus( GetDlgItem( hDlg, IDD_EDIT ) );
+ return( TRUE );
+ }
+ Result = ( DWORD )-1;
+
+ }
+ if( *NumBytesIn != sizeof( DWORD ) ) {
+ if( *Data != NULL ) {
+ *Data = ( LPDWORD )REALLOC( *Data, ( size_t)( sizeof( DWORD ) ) );
+ } else {
+ *Data = ( LPDWORD )MALLOC( ( size_t )sizeof( DWORD ) );
+ }
+ }
+ **Data = Result;
+ *NumBytesIn = sizeof( DWORD );
+ break;
+
+
+
+
+
+ case IDD_HEX:
+
+ NumString = (LPWSTR)CALLOC( (size_t)(2*sizeof( DWORD ) + 1), (size_t)sizeof(WCHAR) );
+ DebugPtrAssert( NumString );
+ for( Index = 0; Index < 2*sizeof( DWORD) - Size; Index++ ) {
+ NumString[ Index ] = ( WCHAR )'0';
+ }
+ GetDlgItemText( hDlg,
+ IDD_EDIT,
+ NumString + ( 2*sizeof( DWORD ) - Size ),
+ (INT)Size + 1 );
+
+ Result = wcstoul(NumString, NULL, 16 );
+ if( *NumBytesIn != sizeof( DWORD ) ) {
+ if( *Data != NULL ) {
+ *Data = ( LPDWORD )REALLOC( *Data, ( size_t)( sizeof( DWORD ) ) );
+ } else {
+ *Data = ( LPDWORD )MALLOC( ( size_t )sizeof( DWORD ) );
+ }
+ }
+ **Data = Result;
+ *NumBytesIn = sizeof( DWORD );
+ FREE( NumString );
+
+ break;
+
+ }
+ }
+ EndDialog( hDlg, TRUE );
+ return( TRUE );
+
+
+ case IDCANCEL:
+
+ EndDialog( hDlg, FALSE );
+ return( TRUE );
+
+ case IDB_HELP:
+ DisplayHelp();
+ return( TRUE );
+ }
+ }
+ return( FALSE );
+}
+
+
+
+
+LONG
+APIENTRY
+EXPORT
+EDITOR::EditDWORD(
+ HWND hWnd,
+ WORD msg,
+ WPARAM wParam,
+ LONG lParam
+)
+/*++
+
+Routine Description:
+
+ This routine preprocesses the messages that are sent to the DWORD edit
+ box in the dialogs. This version will only check that valid characters
+ are entered and it will switch the displayed radix.
+
+Arguments:
+
+ hWnd - a handle to the dialog proceedure.
+
+ msg - the message passed from Windows.
+
+ wParam - extra message dependent data.
+
+ lParam - extra message dependent data.
+
+
+Return Value:
+
+ TRUE if the value was edited. FALSE if cancelled or if no
+ changes were made.
+
+--*/
+{
+ STATIC WPARAM state = IDD_HEX;
+
+ BASE CurrentBase;
+ WCHAR BufferOldBase[ 8*sizeof( DWORD ) + 1 ];
+ ULONG OldBufferSize;
+ WCHAR BufferNewBase[ 8*sizeof( DWORD ) + 1 ];
+ ULONG NewBufferSize;
+ ULONG OldBase;
+ ULONG NewBase;
+ ULONG Number;
+ DSTRING ConvertString;
+
+ switch( msg ) {
+
+ case WM_CHAR:
+
+// AnsiUpperBuff( (LPSTR)&wParam, 1 );
+
+ if( ( wParam == ( WCHAR )'\t' ) || ( wParam == ( WCHAR )'\b' ) || ( GetKeyState( VK_CONTROL ) < 0 ) ) {
+ break;
+ }
+
+ switch( state ) {
+
+ case IDD_BINARY:
+
+ //
+ // Test for a valid binary number
+ //
+ if( wParam != ( WCHAR )'1' && wParam != ( WCHAR )'0' ) {
+ return( TRUE );
+ }
+ break;
+
+ case IDD_DECIMAL:
+
+ if( wParam < ( WCHAR )'0' || wParam > ( WCHAR )'9' ) {
+ return( TRUE );
+ }
+ break;
+
+
+ case IDD_HEX:
+
+ //
+ // Test for a valid hex character...
+ //
+ if( !( ( ( wParam >= ( WCHAR )'A' && wParam <= ( WCHAR )'F' ) ||
+ ( wParam >= ( WCHAR )'a' && wParam <= ( WCHAR )'f' ) ||
+ ( wParam >= ( WCHAR )'0' && wParam <= ( WCHAR )'9' ) ) ) ) {
+ return( TRUE );
+ }
+ break;
+
+ }
+ break;
+
+
+ case EI_SETSTATE:
+
+
+ //
+ // Check if the current state is already set correctly...
+ //
+ if( state == wParam ) {
+ return( TRUE );
+ }
+
+ switch( wParam ) {
+
+ case IDD_BINARY:
+
+
+ NewBase = 2;
+ OldBase = ( state == IDD_HEX )? 16 : 10;
+ OldBufferSize = SendMessage( hWnd, WM_GETTEXTLENGTH, 0, 0L );
+ NewBufferSize = 8*sizeof( DWORD ); // 32 digits for binary
+ break;
+
+ case IDD_DECIMAL:
+
+ NewBase = 10;
+ OldBase = ( state == IDD_HEX )? 16 : 2;
+ OldBufferSize = SendMessage( hWnd, WM_GETTEXTLENGTH, 0, 0L );
+ NewBufferSize = 10; // 10 digits for decimal
+ break;
+
+
+ case IDD_HEX:
+
+ NewBase = 16;
+ OldBase = ( state == IDD_BINARY )? 2 : 10;
+ OldBufferSize = SendMessage( hWnd, WM_GETTEXTLENGTH, 0, 0L );
+ NewBufferSize = 8; // 8 digits for HEX number
+ break;
+
+ }
+
+ if( OldBufferSize >= 1 ) {
+ //
+ // Get the text from the window
+ //
+
+ SendMessage( hWnd,
+ WM_GETTEXT,
+ ( WPARAM )(sizeof( BufferOldBase)/sizeof( WCHAR )),
+ ( LONG )BufferOldBase );
+ Number = wcstoul( BufferOldBase, NULL, ( int )OldBase );
+ _ultoa( Number, ( PSTR )BufferNewBase, ( int )NewBase );
+ ConvertString.Initialize( (PSTR)BufferNewBase );
+
+
+ //
+ // Reset the window text
+ //
+
+ SendMessage( hWnd, WM_SETTEXT, 0, ( LONG )ConvertString.GetWSTR() );
+ }
+
+ state = wParam;
+ return( TRUE );
+
+
+ case EI_GETSTATE:
+
+ return( state );
+
+ case WM_KEYDOWN:
+
+ if( ( ( wParam == VK_INSERT ) && ( GetKeyState( VK_SHIFT ) < 0 ) ) ||
+ ( ( ( wParam == ( WCHAR )'V' ) || ( wParam == ( WCHAR )'v' ) ) && ( GetKeyState( VK_CONTROL ) < 0 ) )
+ ) {
+ //
+ // User wants to paste text from the clipboard
+ //
+ if( state == IDD_BINARY ) {
+ CurrentBase = BASE_2;
+ } else if( state == IDD_DECIMAL ) {
+ CurrentBase = BASE_10;
+ } else {
+ CurrentBase = BASE_16;
+ }
+ if( !IsClipboardDataValid( hWnd, TRUE, CurrentBase ) ) {
+ Beep( 500, 100 );
+ return( FALSE );
+ }
+ }
+ }
+ //
+ // Call the old window routine to deal with everything else...
+ //
+ return( CallWindowProc( OldWndLong, hWnd, msg, wParam, lParam ) );
+}
+
+
+
+BOOLEAN
+EDITOR::IsClipboardDataValid(
+ IN HWND hWnd,
+ IN BOOLEAN DwordEditor,
+ IN BASE Base
+)
+/*++
+
+Routine Description:
+
+ Verify whether the data on the clipboard can be pasted to the DWORD editor,
+ or to the binary editor.
+
+
+Arguments:
+
+ hWnd - Handle associated to the editor currently displayed
+
+ DwordEditor - If TRUE indicates that the data on the clipboard should
+ be validated for the DWORD Editor. If it is FALSE, the
+ clipboard data should be validated for the binary editor.
+
+ Base - The base used in the DWORD editor or binary editor.
+
+Return Value:
+
+ TRUE if the clipboard contains data that can be pasted to the binary or
+ binary editor.
+ Returns FALSE otherwise.
+
+
+--*/
+{
+
+ HANDLE ClipboardHandle;
+ PWSTR ClipboardData;
+ BOOLEAN Valid;
+
+
+ Valid = FALSE;
+ //
+ // Find out if there is data on the clipboard
+ //
+ if( IsClipboardFormatAvailable( CF_TEXT ) ) {
+ //
+ // Clipboard contains data of type CF_TEXT
+ //
+ if( OpenClipboard( hWnd ) ) {
+ ClipboardHandle = GetClipboardData( CF_UNICODETEXT );
+ if( ClipboardHandle != NULL ) {
+ ClipboardData = ( PWSTR )GlobalLock( ClipboardHandle );
+ if( ClipboardData != NULL ) {
+ if( DwordEditor ) {
+ //
+ // Determine whether the data in the clipboard is
+ // a valid representation of a DWORD
+ //
+ Valid = IsValidDwordString( ClipboardData, Base );
+ } else {
+ //
+ // Determine whether the data in the clipboard is
+ // a valid representation of a binary data
+ //
+ Valid = IsValidBinaryString( ClipboardData, Base );
+ }
+ GlobalUnlock( ClipboardHandle );
+ } else {
+ DebugPrintf( "GlobalLock() failed" );
+ }
+ } else {
+ DebugPrint( "GetClipboardData() failed" );
+ }
+ CloseClipboard();
+ } else {
+ //
+ // Unable to open the clipboard
+ //
+ DebugPrint( "OpenClipboard() failed" );
+ }
+ }
+ return( Valid );
+}
+
+
+
+BOOLEAN
+EDITOR::IsValidBinaryString(
+ PWSTR String,
+ BASE Base
+)
+/*++
+
+Routine Description:
+
+ Verify whether the string passed as argument is a valid
+ string representation of binary data (all its character represent
+ digits in a particular base).
+
+
+Arguments:
+
+ String - A string to be verified.
+
+ Base - The base used to represent the data.
+
+Return Value:
+
+ TRUE if String is a valid representation of data in the base specified
+ by Base. Returns FALSE otherwise.
+
+
+--*/
+{
+ PWSTR Digits;
+
+ if( String == NULL ){
+ DebugPrint( "IsValidBinaryString() received a NULL pointer" );
+ return( FALSE );
+ }
+ if( Base == BASE_2 ) {
+ Digits = (LPWSTR)L"01";
+ } else if( Base == BASE_10 ) {
+ Digits = (LPWSTR)L"0123456789";
+ } else {
+ Digits = (LPWSTR)L"0123456789ABCDEFabcdefg";
+ }
+ if( wcsspn( String, Digits ) < wcslen( String ) ) {
+ return( FALSE );
+ } else {
+ return( TRUE );
+ }
+}
+
+
+
+
+BOOLEAN
+EDITOR::IsValidDwordString(
+ PWSTR String,
+ BASE Base
+)
+/*++
+
+Routine Description:
+
+ Verify whether the string passed as argument is a valid
+ string representation of a DWORD.
+
+
+Arguments:
+
+ String - A string to be verified.
+
+ Base - The base used to represent the data.
+
+Return Value:
+
+ TRUE if String is a valid representation of a DWORD in the base specified
+ by Base. Returns FALSE otherwise.
+
+
+--*/
+{
+ ULONG MaxNumberOfDigits;
+
+ if( String == NULL ){
+ DebugPrint( "IsValidDwordString() received a NULL pointer" );
+ return( FALSE );
+ }
+ if( Base == BASE_2 ) {
+ MaxNumberOfDigits = 8*sizeof( DWORD );
+ } else if( Base == BASE_10 ) {
+ MaxNumberOfDigits = 10;
+ } else {
+ MaxNumberOfDigits = 2*sizeof( DWORD );
+ }
+ if( wcslen( String ) <= MaxNumberOfDigits ) {
+ return( IsValidBinaryString( String, Base ) );
+ } else {
+ return( FALSE );
+ }
+}
diff --git a/private/utils/regedit/src/makefile b/private/utils/regedit/src/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/regedit/src/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/regedit/src/makefile.inc b/private/utils/regedit/src/makefile.inc
new file mode 100644
index 000000000..6c93eb38d
--- /dev/null
+++ b/private/utils/regedit/src/makefile.inc
@@ -0,0 +1,12 @@
+{}.cxx{obj\i386\}.obj:
+ $(386_COMPILER) -Fo$@ $(MAKEDIR)\$(<F)
+
+{}.cxx{obj\mips\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClMips $< " $(C_COMPILER) "
+ @$(C_COMPILER) -Fo$@ $(MAKEDIR)\$<
+
+{}.cxx{obj\alpha\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClAlpha $< " $(ALPHA_COMPILER) "
+ @$(ALPHA_COMPILER) -Fo$@ $(MAKEDIR)\$<
diff --git a/private/utils/regedit/src/printman.cxx b/private/utils/regedit/src/printman.cxx
new file mode 100644
index 000000000..5edf40026
--- /dev/null
+++ b/private/utils/regedit/src/printman.cxx
@@ -0,0 +1,4102 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ printman.cxx
+
+Abstract:
+
+ This file contains the implementation of the member functions
+ of PRINT_MANAGER class.
+
+Author:
+
+ Jaime Sasson (jaimes) 18-Sep-1991
+
+
+Environment:
+
+ Ulib, Regedit, Windows, User Mode
+
+
+--*/
+
+
+#include "uapp.hxx"
+#include <commdlg.h>
+
+#include "winapp.hxx"
+#include "printman.hxx"
+#include "array.hxx"
+#include "arrayit.hxx"
+#include "system.hxx"
+#include "regsys.hxx"
+#include "defmsg.h"
+#include "regdesc.hxx"
+#include "regedit.hxx"
+
+#include <wchar.h>
+#include <stdio.h>
+#include <ctype.h>
+
+
+#define MAX_SIZE_OF_BINARY_DATA 8
+
+
+DEFINE_CONSTRUCTOR( PRINT_MANAGER, OBJECT );
+
+DEFINE_CAST_MEMBER_FUNCTION( PRINT_MANAGER );
+
+BOOLEAN PRINT_MANAGER::_UserAbort;
+HWND PRINT_MANAGER::_DlgPrint;
+
+
+PRINT_MANAGER::~PRINT_MANAGER(
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy a PRINT_MANAGER object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+}
+
+
+
+BOOLEAN
+PRINT_MANAGER::Initialize(
+ IN HWND Handle
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes a PRINT_MANAGER object.
+
+
+Arguments:
+
+ Handle -
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the object was correctly initialized.
+
+--*/
+
+{
+ PWSTR Buffer;
+ ULONG Size;
+ ULONG Count;
+
+ _pd.lStructSize = sizeof( PRINTDLG );
+ _pd.hwndOwner = Handle;
+ _pd.hDevMode = NULL;
+ _pd.hDevNames = NULL;
+ _pd.hDC = NULL;
+ _pd.Flags = 0;
+ _pd.nFromPage = 0;
+ _pd.nToPage = 0;
+ _pd.nMinPage = 0;
+ _pd.nMaxPage = 0;
+ _pd.nCopies = 0;
+ _pd.hInstance = NULL;
+ _pd.lCustData = NULL;
+ _pd.lpfnPrintHook = NULL;
+ _pd.lpfnSetupHook = NULL;
+ _pd.lpPrintTemplateName = NULL;
+ _pd.lpSetupTemplateName = NULL;
+ _pd.hPrintTemplate = NULL;
+ _pd.hSetupTemplate = NULL;
+
+ _TopMargin = 0;
+ _CharacterHeight = 0;
+ _BottomMargin = 0;
+ _LinesPerPage = 0;
+ _LeftMargin = 0;
+ _CharacterWidth = 0;
+ _RightMargin = 0;
+ _CharactersPerLine = 0;
+ _CurrentLine = 0;
+ _CurrentPage = 1;
+
+ _InitTextMetrics = TRUE;
+
+ if( !_EmptyLine.Initialize( ( PWSTR )L" " ) ) {
+ DebugPrint( "_EmptyLine.Initialize() failed \n" );
+ return( FALSE );
+ }
+
+ if( !_Separator.Initialize( ( PWSTR )L"\\" ) ) {
+ DebugPrint( "_Separator.Initialize() failed \n" );
+ return( FALSE );
+ }
+
+ if( !_DateTimeSeparator.Initialize( ( PWSTR )L" - " ) ) {
+ DebugPrint( "_DateTimeSeparator.Initialize() failed \n" );
+ return( FALSE );
+ }
+
+ _StringNodeName = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_NODE_NAME, "" );
+ DebugPtrAssert( _StringNodeName );
+ _StringClassName = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_NODE_CLASS_NAME, "" );
+ DebugPtrAssert( _StringClassName );
+ _StringTitleIndex = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_NODE_TITLE_INDEX, "" );
+ DebugPtrAssert( _StringTitleIndex );
+ _StringTitle = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_NODE_TITLE, "" );
+ DebugPtrAssert( _StringTitle );
+ _StringLastWriteTime = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_NODE_LAST_WRITE_TIME, "" );
+ DebugPtrAssert( _StringLastWriteTime );
+ _StringValue = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_VALUE_NUMBER, "" );
+ DebugPtrAssert( _StringValue );
+ _StringValueName = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_VALUE_NAME, "" );
+ DebugPtrAssert( _StringValueName );
+ _StringValueTitleIndex = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_VALUE_TITLE_INDEX, "" );
+ DebugPtrAssert( _StringValueTitleIndex );
+ _StringValueTitle = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_VALUE_TITLE, "" );
+ DebugPtrAssert( _StringValueTitle );
+ _StringValueType = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_VALUE_TYPE, "" );
+ DebugPtrAssert( _StringValueType );
+ _StringDataLength = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_VALUE_DATA_SIZE, "" );
+ DebugPtrAssert( _StringDataLength );
+ _StringData = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_VALUE_DATA, "" );
+ DebugPtrAssert( _StringData );
+
+ _StringTypeRegExpandSZ = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_EXPAND_SZ, "" );
+ DebugPtrAssert( _StringTypeRegExpandSZ );
+ _StringTypeRegMultiSZ = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_MULTI_SZ, "" );
+ DebugPtrAssert( _StringTypeRegMultiSZ );
+ _StringTypeRegSZ = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_SZ, "" );
+ DebugPtrAssert( _StringTypeRegSZ );
+ _StringTypeRegBinary = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_BINARY, "" );
+ DebugPtrAssert( _StringTypeRegBinary );
+ _StringTypeRegDWORD = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_DWORD, "" );
+ DebugPtrAssert( _StringTypeRegDWORD );
+ _StringTypeRegFullResourceDescriptor = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_FULL_RESOURCE_DESCRIPTOR, "" );
+ DebugPtrAssert( _StringTypeRegFullResourceDescriptor );
+ _StringTypeRegResourceList = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_RESOURCE_LIST, "" );
+ DebugPtrAssert( _StringTypeRegResourceList );
+ _StringTypeRegResourceRequirementsList = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_RESOURCE_REQUIREMENTS_LIST, "" );
+ DebugPtrAssert( _StringTypeRegResourceRequirementsList );
+ _StringTypeRegColorRGB = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_COLOR_RGB, "" );
+ DebugPtrAssert( _StringTypeRegColorRGB );
+ _StringTypeRegFileName = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_FILE_NAME, "" );
+ DebugPtrAssert( _StringTypeRegFileName );
+ _StringTypeRegFileTime = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_FILE_TIME, "" );
+ DebugPtrAssert( _StringTypeRegFileTime );
+ _StringTypeRegUnknown = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_UNKNOWN, "" );
+ DebugPtrAssert( _StringTypeRegUnknown );
+ _StringValueNoName = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_VALUE_NO_NAME, "" );
+ DebugPtrAssert( _StringValueNoName );
+ _StringNodeNoClass = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_NODE_NO_CLASS, "" );
+ DebugPtrAssert( _StringNodeNoClass );
+ _StringAllFiles = REGEDIT_BASE_SYSTEM::QueryString( MSG_FILTER_ALL_FILES, "" );
+ DebugPtrAssert( _StringAllFiles );
+ _StringTextFiles = REGEDIT_BASE_SYSTEM::QueryString( MSG_FILTER_TXT_FILES, "" );
+ DebugPtrAssert( _StringTextFiles );
+ _StringStarDotStar = REGEDIT_BASE_SYSTEM::QueryString( MSG_FILTER_STAR_DOT_STAR, "" );
+ DebugPtrAssert( _StringStarDotStar );
+ _StringStarDotTxt = REGEDIT_BASE_SYSTEM::QueryString( MSG_FILTER_STAR_DOT_TXT, "" );
+ DebugPtrAssert( _StringStarDotTxt );
+
+ _StringFullDescriptor = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_FULL_DESCRIPTOR, "" );
+ DebugPtrAssert( _StringFullDescriptor );
+ _StringPartialDescriptor = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_PARTIAL_DESCRIPTOR, "" );
+ DebugPtrAssert( _StringPartialDescriptor );
+ _StringInterfaceType = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_INTERFACE_TYPE, "" );
+ DebugPtrAssert( _StringInterfaceType );
+ _StringBusNumber = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_BUS_NUMBER, "" );
+ DebugPtrAssert( _StringBusNumber );
+ _StringVersion = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_VERSION, "" );
+ DebugPtrAssert( _StringVersion );
+ _StringRevision = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_REVISION, "" );
+ DebugPtrAssert( _StringRevision );
+
+ _StringResource = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_RESOURCE, "" );
+ DebugPtrAssert( _StringResource );
+ _StringDisposition = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_DISPOSITION, "" );
+ DebugPtrAssert( _StringDisposition );
+ _StringType = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_TYPE, "" );
+ DebugPtrAssert( _StringType );
+ _StringStart = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_START, "" );
+ DebugPtrAssert( _StringStart );
+ _StringLength = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_LENGTH, "" );
+ DebugPtrAssert( _StringLength );
+ _StringLevel = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_LEVEL, "" );
+ DebugPtrAssert( _StringLevel );
+ _StringVector = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_VECTOR, "" );
+ DebugPtrAssert( _StringVector );
+ _StringAffinity = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_AFFINITY, "" );
+ DebugPtrAssert( _StringAffinity );
+ _StringChannel = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_CHANNEL, "" );
+ DebugPtrAssert( _StringChannel );
+ _StringPort = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_PORT, "" );
+ DebugPtrAssert( _StringPort );
+ _StringReserved1 = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_RESERVED1, "" );
+ DebugPtrAssert( _StringReserved1 );
+ _StringReserved2 = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_RESERVED2, "" );
+ DebugPtrAssert( _StringReserved2 );
+ _StringDevSpecificData = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_DEV_SPECIFIC_DATA, "" );
+ DebugPtrAssert( _StringDevSpecificData );
+
+ _StringIoInterfaceType = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_IO_INTERFACE_TYPE, "" );
+ DebugPtrAssert( _StringIoInterfaceType );
+ _StringIoBusNumber = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_IO_BUS_NUMBER, "" );
+ DebugPtrAssert( _StringIoBusNumber );
+ _StringIoSlotNumber = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_IO_SLOT_NUMBER, "" );
+ DebugPtrAssert( _StringIoSlotNumber );
+ _StringIoListNumber = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_IO_LIST_NUMBER, "" );
+ DebugPtrAssert( _StringIoListNumber );
+ _StringIoOption = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_IO_OPTION, "" );
+ DebugPtrAssert( _StringIoOption );
+ _StringIoDescriptorNumber = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_IO_DESCRIPTOR_NUMBER, "" );
+ DebugPtrAssert( _StringIoDescriptorNumber );
+ _StringIoAlignment = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_IO_ALIGNMENT, "" );
+ DebugPtrAssert( _StringIoAlignment );
+ _StringIoMinimumAddress = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_IO_MINIMUM_ADDRESS, "" );
+ DebugPtrAssert( _StringIoMinimumAddress );
+ _StringIoMaximumAddress = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_IO_MAXIMUM_ADDRESS, "" );
+ DebugPtrAssert( _StringIoMaximumAddress );
+ _StringIoMinimumVector = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_IO_MINIMUM_VECTOR, "" );
+ DebugPtrAssert( _StringIoMinimumVector );
+ _StringIoMaximumVector = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_IO_MAXIMUM_VECTOR, "" );
+ DebugPtrAssert( _StringIoMaximumVector );
+ _StringIoMinimumChannel = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_IO_MINIMUM_CHANNEL, "" );
+ DebugPtrAssert( _StringIoMinimumChannel );
+ _StringIoMaximumChannel = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_IO_MAXIMUM_CHANNEL, "" );
+ DebugPtrAssert( _StringIoMaximumChannel );
+
+
+
+
+ Size = _StringNodeName->QueryChCount();
+ Buffer = ( PWSTR ) MALLOC( ( size_t )(( Size + 1 )*sizeof( WCHAR )) );
+ DebugPtrAssert( Buffer );
+ for( Count = 0; Count < Size; Count++ ) {
+ Buffer[ Count ] = ( WCHAR )' ';
+ }
+ Buffer[ Size ] = ( WCHAR )'\0';
+ if( !_IndentString.Initialize( Buffer ) ) {
+ DebugPrint( "_IndentString.Initialize() failed \n" );
+ FREE( Buffer );
+ return( FALSE );
+ }
+ FREE( Buffer );
+ return( TRUE );
+}
+
+
+BOOLEAN
+PRINT_MANAGER::InitializeTextMetrics(
+)
+
+/*++
+
+Routine Description:
+
+ Initializes the _TextMetrics structure, and other variables related
+ to page and character size.
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeded.
+
+--*/
+
+{
+ if( _InitTextMetrics ) {
+ if( !GetTextMetrics( _pd.hDC, &_TextMetrics ) ) {
+ DebugPrint( "GetTextMetrics failed" );
+ return( FALSE );
+ }
+ //
+ // The number '1' below, means 1 inch for the top margin
+ //
+ _TopMargin = 1*GetDeviceCaps( _pd.hDC, LOGPIXELSX );
+ _BottomMargin = _TopMargin;
+ //
+ // The multiplication by '3' and division by '4' means 3/4 inch
+ // for the left margin
+ //
+ _LeftMargin = 3*( ( GetDeviceCaps( _pd.hDC, LOGPIXELSY ) ) ) / 4;
+ _RightMargin = _LeftMargin;
+
+ _CharacterHeight = _TextMetrics.tmHeight + _TextMetrics.tmExternalLeading;
+ _LinesPerPage = ( GetDeviceCaps( _pd.hDC, VERTRES ) - _TopMargin - _BottomMargin ) / _CharacterHeight;
+
+ _CharacterWidth = _TextMetrics.tmAveCharWidth;
+ _CharactersPerLine = ( GetDeviceCaps( _pd.hDC, HORZRES ) - _LeftMargin - _RightMargin ) / _CharacterWidth;
+// DebugPrintf( "CharactersPerLine = %d \n", _CharactersPerLine );
+ _CurrentLine = 0;
+
+// _InitTextMetrics = FALSE;
+ }
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+PRINT_MANAGER::BuildHeaderFooter(
+)
+
+/*++
+
+Routine Description:
+
+ Build the strings for header and footer
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeded.
+
+--*/
+
+{
+ PWSTR Buffer;
+ ULONG Count;
+
+ //
+ // The magic number 10 is the maximum number of digits for the page number
+ //
+
+ Buffer = ( PWSTR )MALLOC( ( size_t )(( _CharactersPerLine - 10 + 1 )*sizeof( WCHAR )) );
+ DebugPtrAssert( Buffer );
+ for( Count = 0; Count < _CharactersPerLine - 10; Count++ ) {
+ *( Buffer + Count ) = ( WCHAR )' ';
+ }
+ *( Buffer + _CharactersPerLine - 10 ) = '\0';
+
+ if( !_StringFooter.Initialize( Buffer ) ) {
+ DebugPrint( "_StringFooter.Initialize() failed \n" );
+ FREE( Buffer );
+ return( FALSE );
+ }
+ FREE( Buffer );
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+PRINT_MANAGER::StartPrint(
+ IN PCWSTRING String
+ )
+
+/*++
+
+Routine Description:
+
+ Start a print process.
+
+
+Arguments:
+
+ PredefinedKey - A string associated to the predefined key
+ that represents the root of the tree to print.
+
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the object was correctly initialized.
+
+--*/
+
+{
+ PSTR RootName;
+ LONG Status;
+
+
+ DbgWinPtrAssert( String );
+ //
+ // Escape() expects LPSTR and not LPWSTR !!
+ //
+ RootName = String->QuerySTR();
+ DbgWinPtrAssert( RootName );
+
+ if( ( Status = Escape( _pd.hDC,
+ STARTDOC,
+ (INT)(String->QueryChCount()),
+ RootName, NULL ) ) == -1 ) {
+ FREE( RootName );
+ PrintErrorDialog( Status );
+ DebugPrint( "Escape( _pd.hDC, STARTDOC, String->QueryChCount(), RootName, NULL ) failed" );
+ return( FALSE );
+ }
+ FREE( RootName );
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+PRINT_MANAGER::PrintString(
+ IN PCWSTRING String,
+ IN BOOLEAN Indent
+ )
+
+/*++
+
+Routine Description:
+
+ Prints a string. If the string is wider than the page width, then
+ the string is split, and in this case the lines that follow the first
+ may be indented depending on the flag Indent.
+
+
+
+Arguments:
+
+ String - String to be printed.
+
+ Indent -
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeded.
+
+--*/
+
+{
+ ULONG StringLength;
+ DSTRING TmpString;
+ DSTRING NullString;
+ PSTR Pointer;
+
+
+ DbgWinPtrAssert( String );
+
+ if( _PrintToFile ) {
+ Pointer = String->QuerySTR();
+ DebugPtrAssert( Pointer );
+ if( ( _lwrite( _FileHandle, Pointer, ( INT )(String->QueryChCount()) ) == HFILE_ERROR ) ||
+ ( _lwrite( _FileHandle, "\r\n", 2 ) == HFILE_ERROR )
+ ) {
+ INT TextMessage;
+ INT CaptionMessage;
+
+ if( GetLastError() == ERROR_DISK_FULL ) {
+ TextMessage = MSG_SAVE_SUBTREE_AS_DISK_FULL;
+ CaptionMessage = MSG_DISK_FULL;
+ } else {
+ TextMessage = MSG_SAVE_SUBTREE_AS_UNKNOWN_ERROR;
+ CaptionMessage = MSG_UNKNOWN_ERROR;
+ }
+ DisplayInfoPopup(_hWnd,
+ TextMessage,
+ CaptionMessage);
+
+ DELETE( Pointer );
+ return( FALSE );
+ }
+ DELETE( Pointer );
+ return( TRUE );
+ }
+
+ if( _UserAbort ) {
+ return( FALSE );
+ }
+ //
+ // If string is not wider than the page, just print it and forget
+ // about breaking it
+ //
+ StringLength = String->QueryChCount();
+ if( StringLength <= _CharactersPerLine ) {
+ return( PrintStringTruncate( String ) );
+ }
+
+ //
+ // String is wider than the page
+ //
+
+ if( !TmpString.Initialize( String ) ) {
+ DebugPrint( "TmpString.Initialize() failed \n" );
+ return( FALSE );
+ }
+ if( !NullString.Initialize( (LPWSTR)L"" ) ) {
+ DebugPrint( "NullString.Initialize() failed \n" );
+ return( FALSE );
+ }
+ if( !PrintStringTruncate( &TmpString ) ) {
+ DebugPrint( "PrintStringTruncate() failed \n" );
+ return( FALSE );
+ }
+ if( !TmpString.Replace( 0, _CharactersPerLine, &NullString ) ) {
+ DebugPrint( "TmpString.Replace() failed \n" );
+ return( FALSE );
+ }
+
+ if( Indent ) {
+ if( !TmpString.Replace( 0, 0, &_IndentString ) ) {
+ DebugPrint( "TmpString.Replace() failed \n" );
+ return( FALSE );
+ }
+
+ do {
+ if( !PrintStringTruncate( &TmpString ) ) {
+ DebugPrint( "PrintStringTruncate() failed \n" );
+ return( FALSE );
+ }
+ StringLength = min( TmpString.QueryChCount(), _CharactersPerLine );
+ StringLength -= _IndentString.QueryChCount();
+ if( !TmpString.Replace( _IndentString.QueryChCount(), StringLength, &NullString ) ) {
+ DebugPrint( "TmpString.Replace() failed \n" );
+ return( FALSE );
+ }
+ } while( TmpString.QueryChCount() != _IndentString.QueryChCount() );
+
+ } else {
+ do {
+ if( !PrintStringTruncate( &TmpString ) ) {
+ DebugPrint( "PrintStringTruncate() failed \n" );
+ return( FALSE );
+ }
+ StringLength = min( TmpString.QueryChCount(), _CharactersPerLine );
+ if( !TmpString.Replace( 0, StringLength, &NullString ) ) {
+ DebugPrint( "TmpString.Replace() failed \n" );
+ return( FALSE );
+ }
+ } while( TmpString.QueryChCount() != 0 );
+ }
+ return( TRUE );
+}
+
+
+
+
+
+BOOLEAN
+PRINT_MANAGER::PrintStringTruncate(
+ IN PCWSTRING String
+ )
+
+/*++
+
+Routine Description:
+
+ Prints a string. If the string is wider than the page width, then
+ the string is split.
+
+
+
+Arguments:
+
+ String - String to be printed.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeded.
+
+--*/
+
+{
+ PWSTR PrintableString;
+ LONG Status;
+ DSTRING Footer;
+ DSTRING PageNumber;
+ PWSTR Buffer;
+ ULONG Length;
+
+
+ DbgWinPtrAssert( String );
+
+ if( _UserAbort ) {
+ return( FALSE );
+ }
+ if( ( Length = String->QueryChCount() ) > _CharactersPerLine ) {
+ Length = _CharactersPerLine;
+ }
+ PrintableString = String->QueryWSTR( 0, Length );
+ DbgWinPtrAssert( PrintableString );
+ if( TextOut( _pd.hDC,
+ ( int )_LeftMargin,
+ ( int )( _CurrentLine*_CharacterHeight + _TopMargin ),
+ PrintableString,
+ Length ) == 0 ) {
+ FREE( PrintableString );
+ DebugPrint( "TextOut() failed" );
+ return( FALSE );
+ }
+ FREE( PrintableString );
+ _CurrentLine++;
+ if( _CurrentLine >= _LinesPerPage ) {
+
+ if( !Footer.Initialize( &_StringFooter ) ) {
+ DebugPrint( "Footer.Initialize() failed \n" );
+ return( FALSE );
+ }
+ Buffer = ( PWSTR )MALLOC( (10 + 1)*sizeof( WCHAR ) );
+ DebugPtrAssert( Buffer );
+ swprintf( Buffer, (LPWSTR)L"%10d", _CurrentPage );
+ if( !PageNumber.Initialize( Buffer ) ) {
+ DebugPrint( "PageNumber.Initialize() failed \n" );
+ FREE( Buffer );
+ return( FALSE );
+ }
+ FREE( Buffer );
+ Footer.Strcat( &PageNumber );
+ PrintableString = Footer.QueryWSTR();
+ DebugPtrAssert( PrintableString );
+
+ if( TextOut( _pd.hDC,
+ ( int )_LeftMargin,
+ ( int )( _LinesPerPage*_CharacterHeight + _TopMargin + _BottomMargin/2 ),
+ PrintableString,
+ (INT)( Footer.QueryChCount() ) ) == 0 ) {
+ FREE( PrintableString );
+ DebugPrint( "TextOut() failed" );
+ return( FALSE );
+ }
+ FREE( PrintableString );
+
+ _CurrentPage++;
+ if( ( Status = Escape( _pd.hDC, NEWFRAME, NULL, NULL, NULL ) ) < 0 ) {
+ PrintErrorDialog( Status );
+ DebugPrint( "Escape( _pd.hDC, NEWFRAME, NULL, NULL, NULL ) failed" );
+ return( FALSE );
+ }
+ _CurrentLine = 0;
+ }
+ return( TRUE );
+}
+
+
+
+
+BOOLEAN
+PRINT_MANAGER::EndPrint(
+ )
+
+/*++
+
+Routine Description:
+
+ Ends the print process.
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeded.
+
+--*/
+
+{
+ LONG Status;
+
+ Status = Escape( _pd.hDC, NEWFRAME, NULL, NULL, NULL );
+ if( Status <= 0 ) {
+ PrintErrorDialog( Status );
+ DebugPrint( "Escape( _pd.hDC, NEWFRAME, NULL, NULL, NULL ) failed" );
+ }
+ Status = Escape( _pd.hDC, ENDDOC, NULL, NULL, NULL );
+ if( Status < 0 ) {
+ PrintErrorDialog( Status );
+ DebugPrint( "Escape( _pd.hDC, ENDDOC, NULL, NULL, NULL ) failed" );
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+PRINT_MANAGER::PrintToTextFile (
+ HANDLE Instance,
+ HWND hWnd,
+ HWND MDIHandle,
+ PREGEDIT_INTERNAL_REGISTRY InternalRegistry,
+ PCREGEDIT_NODE StartNode
+ )
+
+/*++
+
+Routine Description:
+
+ Save a regitry that is represented by InternalRegistry in a text file.
+
+
+Arguments:
+
+ Instance -
+
+ hWnd -
+
+ MDIHandle -
+
+ InternalRegistry - Pointer to the INTERNAL_REGISTRY object that contains
+ the representation of the registry to be printed.
+
+ StartNode - Root node of the subtree to be printed.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the Print operation was succesful.
+
+--*/
+
+{
+
+ DSTRING FormattedNodeName;
+ DSTRING FormattedNodeClass;
+ DSTRING ConvertString;
+ PSTR String;
+
+ HCURSOR Cursor;
+
+ OPENFILENAME ofn;
+ WSTR filename[ MAX_PATH ];
+ WSTR filetitle[ MAX_PATH ];
+
+
+ WCHAR filter[MAX_PATH];
+
+ Instance = Instance;
+ MDIHandle = MDIHandle;
+
+ _hWnd = hWnd;
+ _IR = InternalRegistry;
+
+
+
+ swprintf( filter,
+ (LPWSTR)L"%ws%wc%ws%wc%ws%wc%ws%wc%wc%wc",
+ _StringAllFiles->GetWSTR(), // (LPWSTR)L"AllFiles",
+ 0,
+ _StringStarDotStar->GetWSTR(), // (LPWSTR)L"*.*",
+ 0,
+ _StringTextFiles->GetWSTR(), // (LPWSTR)L"TextFiles",
+ 0,
+ _StringStarDotTxt->GetWSTR(), // (LPWSTR)L"*.txt",
+ 0,
+ 0, 0 );
+
+ //
+ // Setup the OPENFILENAME structure.
+ //
+
+ filename[0] =(WCHAR)'\0';
+
+ ofn.lStructSize = sizeof( OPENFILENAME );
+ ofn.hwndOwner = hWnd;
+ ofn.hInstance = NULL;
+ ofn.lpstrFilter = filter;
+ ofn.lpstrCustomFilter = NULL;
+ ofn.nMaxCustFilter = 0;
+ ofn.nFilterIndex = 0;
+ ofn.lpstrFile = filename;
+ ofn.nMaxFile = sizeof( filename )/sizeof( WCHAR );
+ ofn.lpstrFileTitle = filetitle;
+ ofn.nMaxFileTitle = sizeof( filetitle )/sizeof( WCHAR );
+ ofn.lpstrInitialDir = NULL;
+ ofn.lpstrTitle = NULL;
+ ofn.Flags = OFN_SHOWHELP | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_NOREADONLYRETURN | OFN_PATHMUSTEXIST;
+ ofn.nFileOffset = 0;
+ ofn.nFileExtension = 0;
+ ofn.lpstrDefExt = NULL;
+ ofn.lCustData = 0;
+ ofn.lpfnHook = NULL;
+ ofn.lpTemplateName = NULL;
+
+
+ if( !GetSaveFileName( &ofn ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Create file
+ //
+
+ _PrintToFile = TRUE;
+ ConvertString.Initialize( filename );
+ String = ConvertString.QuerySTR();
+
+ _FileHandle = _lcreat( String, 0 );
+ FREE( String );
+
+
+ //
+ // Write registry to file
+ //
+
+ Cursor = WINDOWS_APPLICATION::DisplayHourGlass();
+ PrintSubTree( StartNode );
+ WINDOWS_APPLICATION::RestoreCursor( Cursor );
+
+ //
+ // Close Handle
+ //
+
+ _lclose( _FileHandle );
+ _PrintToFile = FALSE;
+
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+PRINT_MANAGER::PrintRegistry (
+ HANDLE Instance,
+ HWND hWnd,
+ HWND MDIHandle,
+ PREGEDIT_INTERNAL_REGISTRY InternalRegistry,
+ PCREGEDIT_NODE StartNode
+ )
+
+/*++
+
+Routine Description:
+
+ Prints a registry that is represented by InternalRegistry.
+
+
+Arguments:
+
+ Instance -
+
+ hWnd -
+
+ MDIHandle -
+
+ InternalRegistry - Pointer to the INTERNAL_REGISTRY object that contains
+ the representation of the registry to be printed.
+
+ StartNode - Root node of the subtree to be printed.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the Print operation was succesful.
+
+--*/
+
+{
+ PCWSTRING NodeName;
+
+ FARPROC PointerToPrintDlgProc;
+ FARPROC PointerToAbortProc;
+ LONG Status;
+ BOOLEAN StartPrintFlag;
+
+ DebugPtrAssert( StartNode );
+
+ MDIHandle = MDIHandle;
+ _hWnd = hWnd;
+ _IR = InternalRegistry;
+ _PrintToFile = FALSE;
+ if( _IR->GetParent( StartNode ) == NULL ) {
+ NodeName = _IR->GetRootName();
+ DebugPtrAssert( NodeName );
+ } else {
+ NodeName = _IR->GetNodeName( StartNode );
+ DbgWinPtrAssert( NodeName );
+ }
+
+
+ if( _pd.hDC == NULL ) {
+ _pd.Flags = PD_RETURNDC | PD_RETURNDEFAULT;
+ if( !PrintDlg( &_pd ) ) {
+ return( FALSE );
+ }
+ }
+
+ if( !InitializeTextMetrics() ) {
+ DebugPrint( "InitializeTextMetrics failed" );
+ DbgWinPrint( "InitializeTextMetrics failed" );
+ return( FALSE );
+ }
+ //
+ // Sets an abort procedure
+ //
+ PointerToAbortProc = MakeProcInstance( (FARPROC)&PRINT_MANAGER::AbortProc, Instance );
+ Status = Escape( _pd.hDC, SETABORTPROC, 0, (LPSTR)PointerToAbortProc, NULL );
+ if( Status < 0 ) {
+ PrintErrorDialog( Status );
+ DebugPrint( "Escape( _pd.hDC, ENDDOC, NULL, NULL, NULL ) failed" );
+ return( FALSE );
+ }
+
+ //
+ // Displays an abort dialog
+ //
+ _UserAbort = FALSE;
+ PointerToPrintDlgProc = MakeProcInstance( ( FARPROC )&PRINT_MANAGER::PrintDlgProc, Instance );
+ _DlgPrint = CreateDialog( (HINSTANCE)Instance, (LPWSTR)L"PrintDlgBox", hWnd, (DLGPROC)PointerToPrintDlgProc );
+ if( _DlgPrint == 0 ) {
+ DebugPrint( "_DlgPrint == NULL" );
+ }
+ EnableWindow( hWnd, FALSE );
+
+ //
+ // Prints the registry
+ //
+ BuildHeaderFooter();
+ StartPrintFlag = StartPrint( NodeName );
+ if( StartPrintFlag ) {
+ PrintSubTree( StartNode );
+ }
+
+ if( StartPrintFlag ) {
+ EndPrint();
+ }
+
+ //
+ // If user didn't cancel the printing, destroy the Abort dialog box
+ //
+ if( !_UserAbort ) {
+ EnableWindow( hWnd, TRUE );
+ DestroyWindow( _DlgPrint );
+ }
+
+ //
+ // Clean up
+ //
+ FreeProcInstance( PointerToPrintDlgProc );
+ FreeProcInstance( PointerToAbortProc );
+ return( TRUE );
+}
+
+
+
+
+BOOLEAN
+PRINT_MANAGER::PrintSubTree(
+ IN PCREGEDIT_NODE Node
+ )
+
+/*++
+
+Routine Description:
+
+ Prints a subtree of a registry whose root node is received as parameter.
+
+Arguments:
+
+
+ Node - Pointer to the object that describes the root of the sub-tree.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeded.
+
+
+--*/
+
+{
+ PSORTED_LIST Children;
+ PITERATOR Iterator;
+ PCREGEDIT_NODE Child;
+ ULONG ErrorCode;
+ BOOLEAN UnloadChildrenFlag;
+
+
+
+ DebugPtrAssert( Node );
+
+ if( !PrintNode( Node ) ) {
+ return( FALSE );
+ }
+
+ if( _IR->GetNumberOfChildren( Node ) != 0 ) {
+// UnloadChildrenFlag = !_IR->AreChildrenInMemory( Node );
+ Children = _IR->GetChildren( Node, &ErrorCode );
+ Iterator = Children->QueryIterator();
+ DbgWinPtrAssert( Iterator );
+ while( ( Child = ( PCREGEDIT_NODE )( Iterator->GetNext() ) ) != NULL ) {
+ if( !PrintSubTree( Child ) ) {
+ DELETE( Iterator );
+/*
+ if( UnloadChildrenFlag ) {
+ _IR->UnloadChildren( Node );
+ }
+*/
+ return( FALSE );
+ }
+ }
+ DELETE( Iterator );
+/*
+ if( UnloadChildrenFlag ) {
+// DebugPrint( "UnloadChildrenFlag is TRUE" );
+ _IR->UnloadChildren( Node );
+ }
+// else {
+// DebugPrint( "UnloadChildrenFlag is FALSE" );
+// }
+*/
+ }
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+PRINT_MANAGER::PrinterSetupDialog (
+ )
+
+/*++
+
+Routine Description:
+
+ Displays the Printer Setup dialog and carries out the users
+ requests.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if Printer Setup operation is succesful.
+
+--*/
+
+{
+ BOOLEAN Status;
+ DWORD ErrorCode;
+ PRINTDLG pd;
+
+ pd.lStructSize = sizeof( PRINTDLG );
+ pd.hwndOwner = _pd.hwndOwner;
+ pd.hDevMode = NULL;
+ pd.hDevNames = NULL;
+ pd.hDC = NULL;
+ pd.Flags = 0;
+ pd.nFromPage = 0;
+ pd.nToPage = 0;
+ pd.nMinPage = 0;
+ pd.nMaxPage = 0;
+ pd.nCopies = 0;
+ pd.hInstance = NULL;
+ pd.lCustData = NULL;
+ pd.lpfnPrintHook = NULL;
+ pd.lpfnSetupHook = NULL;
+ pd.lpPrintTemplateName = NULL;
+ pd.lpSetupTemplateName = NULL;
+ pd.hPrintTemplate = NULL;
+ pd.hSetupTemplate = NULL;
+
+ if( _pd.hDC != NULL ) {
+ pd = _pd;
+ }
+
+ pd.Flags = ( PD_RETURNDC | PD_PRINTSETUP | PD_SHOWHELP );
+ if( PrintDlg( &pd ) != 0 ) {
+ Status = TRUE;
+ if( _pd.hDC != NULL ) {
+ if ( !DeleteDC( _pd.hDC ) ) {
+ DebugPrint( "DeleteDC() failed" );
+ }
+#if 0
+ if( GlobalFree( _pd.hDevMode ) != NULL ) {
+ DebugPrintf( "GlobalFree( _pd.hDevMode ) failed, Error = %#x \n", GetLastError() );
+ DebugPrint( "GlobalFree( _pd.hDevMode ) failed" );
+ }
+ if( GlobalFree( _pd.hDevNames ) != NULL ) {
+ DebugPrintf( "GlobalFree( _pd.hDevNames ) failed, Error = %#x \n", GetLastError() );
+ DebugPrint( "GlobalFree( _pd.hDevNames ) failed" );
+ }
+#endif
+ }
+ pd.Flags = 0;
+ _pd = pd;
+ } else {
+ Status = FALSE;
+ ErrorCode = CommDlgExtendedError();
+ if( ErrorCode != 0 ) {
+ DebugPrintf( "Common dialog PrintDlg() failed, ErrorCode = %#x \n", ErrorCode );
+ DebugPrint( "Common dialog PrintDlg() failed." );
+ }
+ }
+ return( Status );
+}
+
+
+
+BOOLEAN
+PRINT_MANAGER::PrintNode(
+ IN PCREGEDIT_NODE Node
+ )
+
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+
+ Node - Pointer to the object that describes the root of the sub-tree.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeded.
+
+
+--*/
+
+{
+ DSTRING Name;
+ DSTRING Title;
+ DSTRING Class;
+ DSTRING LastWriteTime;
+
+
+
+ DSTRING StringTitle;
+
+ PSORTED_LIST ValuesList;
+ PITERATOR Iterator;
+ PCREGEDIT_FORMATTED_VALUE_ENTRY Value;
+ ULONG Count;
+
+ PCWSTRING TmpClass;
+
+ PCWSTRING ParentName;
+ PCWSTRING KeyName;
+ PCWSTRING RootName;
+ PCTIMEINFO TimeInfo;
+ TIMEINFO LocalTimeInfo;
+ DSTRING DateString;
+ DSTRING TimeString;
+ ULONG ErrorCode;
+ BOOLEAN UnloadValuesFlag;
+
+
+ if( !Name.Initialize( _StringNodeName ) ) {
+ DebugPrint( "Name.Initialize() failed" );
+ return( FALSE );
+ }
+ if( !Title.Initialize( _StringTitleIndex ) ) {
+ DebugPrint( "Title.Initialize() failed" );
+ return( FALSE );
+ }
+ if( !Class.Initialize( _StringClassName ) ) {
+ DebugPrint( "Class.Initialize() failed" );
+ return( FALSE );
+ }
+ if( !LastWriteTime.Initialize( _StringLastWriteTime ) ) {
+ DebugPrint( "LastWriteTime.Initialize() failed" );
+ return( FALSE );
+ }
+
+
+ //
+ // Build a string that contains the node name, and print it.
+ //
+ ParentName = _IR->GetParentName( Node );
+ DebugPtrAssert( ParentName );
+ KeyName = _IR->GetNodeName( Node );
+ DebugPtrAssert( KeyName );
+
+ if( ( ParentName->QueryChCount() == 0 ) && ( KeyName->QueryChCount() == 0 ) ) {
+ //
+ // This is a root node
+ //
+ RootName = _IR->GetRootName();
+ DebugPtrAssert( RootName );
+ Name.Strcat( RootName );
+ } else if( ParentName->QueryChCount() == 0 ) {
+ //
+ // This is a child of the root node
+ //
+ Name.Strcat( KeyName );
+ } else {
+ Name.Strcat( ParentName );
+ Name.Strcat( &_Separator );
+ Name.Strcat( KeyName );
+ }
+ if( !PrintString( &Name ) ) {
+ return( FALSE );
+ }
+
+
+
+ //
+ // Build a string that contains the node class, and print it.
+ //
+ if( _IR->IsNodeViewable( Node ) ) {
+ TmpClass = _IR->GetNodeClass( Node );
+ DebugPtrAssert( TmpClass );
+ if( TmpClass->QueryChCount() != 0 ) {
+ Class.Strcat( TmpClass );
+ } else {
+ Class.Strcat( _StringNodeNoClass );
+ }
+ }
+ if( !PrintString( &Class ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Build a string that contains the node LastWriteTime, and print it.
+ //
+
+ if( _IR->IsNodeViewable( Node ) ) {
+ TimeInfo = _IR->GetNodeLastWriteTime( Node );
+ DebugPtrAssert( TimeInfo );
+
+ if( !SYSTEM::QueryLocalTimeFromUTime( TimeInfo, &LocalTimeInfo ) ||
+ !LocalTimeInfo.QueryDate( &DateString ) ||
+ !LocalTimeInfo.QueryTime( &TimeString ) ) {
+ DebugPrint( "TimeInfo.QueryDate() or TimeInfo.QueryTime() failed" );
+// return( FALSE );
+ }
+
+
+ LastWriteTime.Strcat( &DateString );
+ LastWriteTime.Strcat( &_DateTimeSeparator );
+ LastWriteTime.Strcat( &TimeString );
+ }
+ if( !PrintString( &LastWriteTime ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Now that the attributes of a node were printed, print each of its
+ // values if there is any.
+ //
+ if( ( _IR->IsNodeViewable( Node ) ) &&
+ ( _IR->GetNumberOfValues( Node ) != 0 ) ) {
+// UnloadValuesFlag = !_IR->AreValuesInMemory( Node );
+ ValuesList = _IR->GetValues( Node, &ErrorCode );
+ // DebugPtrAssert( ValuesList );
+ if( ValuesList != NULL ) {
+ Iterator = ValuesList->QueryIterator();
+ DbgWinPtrAssert( Iterator );
+
+ Count = 0;
+ while( ( Value = ( PCREGEDIT_FORMATTED_VALUE_ENTRY )( Iterator->GetNext() ) ) != NULL ) {
+ if( !PrintValue( Value, Count ) ) {
+ DELETE( Iterator );
+/*
+ if( UnloadValuesFlag ) {
+ _IR->UnloadValues( Node );
+ }
+*/
+ return( FALSE );
+ }
+ Count++;
+ }
+ DELETE( Iterator );
+/*
+ if( UnloadValuesFlag ) {
+// DebugPrint( "UnloadValuesFlag is TRUE" );
+ _IR->UnloadValues( Node );
+ }
+// else {
+// DebugPrint( "UnloadValuesFlag is FALSE" );
+// }
+*/
+ }
+ }
+ if( !PrintString( &_EmptyLine ) ) {
+ DebugPrint( "PrintString() failed \n" );
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+PRINT_MANAGER::PrintValue(
+ IN PCREGEDIT_FORMATTED_VALUE_ENTRY Value,
+ IN ULONG ValueNumber
+ )
+
+/*++
+
+Routine Description:
+
+ Print the contents of a VALUE object ( a value entry of a registry node ).
+
+Arguments:
+
+ Value - Pointer to a REGEDIT_FORMATTED_VALUE object that describes a value
+ entry of a registry key.
+
+ ValueNumber - Order of the value object in the array of values.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeded.
+
+
+--*/
+
+{
+ DSTRING ValueNumberString;
+ DSTRING AuxString;
+ DSTRING Name;
+ DSTRING NoName;
+ DSTRING Title;
+ PWSTR AuxNumber;
+ DSTRING StringTitle;
+ DSTRING Type;
+ PCWSTRING Pointer;
+
+ PCBYTE Data;
+ ULONG Size;
+
+
+
+ DbgWinPtrAssert( Value );
+
+ if( !ValueNumberString.Initialize( _StringValue ) ) {
+ DebugPrint( "ValueNumberString.Initialize() failed" );
+ return( FALSE );
+ }
+ if( !Name.Initialize( _StringValueName ) ) {
+ DebugPrint( "Name.Initialize() failed" );
+ return( FALSE );
+ }
+
+ if( !Type.Initialize( _StringValueType ) ) {
+ DebugPrint( "Type.Initialize() failed" );
+ return( FALSE );
+ }
+
+
+ //
+ // Build a string that contains the value number
+ // and print it
+ //
+ AuxNumber = ( PWSTR )MALLOC( (10 + 1)*sizeof( WCHAR ) );
+ DebugPtrAssert( AuxNumber );
+ wsprintf( AuxNumber, (LPWSTR)L"%d", ValueNumber );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ FREE( AuxNumber );
+ return( FALSE );
+ }
+ FREE( AuxNumber );
+
+ ValueNumberString.Strcat( &AuxString );
+ if( !PrintString( &ValueNumberString ) ) {
+ return( FALSE );
+ }
+
+
+
+ //
+ // Build a string that contains the value name, and print it.
+ //
+ Pointer = Value->GetName();
+ DebugPtrAssert( Pointer );
+ if( Pointer->QueryChCount() != 0 ) {
+ Name.Strcat( Pointer );
+ } else {
+ Name.Strcat( _StringValueNoName );
+ }
+ if( !PrintString( &Name ) ) {
+ return( FALSE );
+ }
+
+
+
+ //
+ // Build a string that contains the type, and print it.
+ //
+
+ Size = Value->GetData( &Data );
+
+
+
+ switch( Value->GetType() ) {
+
+ case TYPE_REG_SZ:
+ case TYPE_REG_EXPAND_SZ:
+
+ if( Value->GetType() == TYPE_REG_SZ ) {
+ Type.Strcat( _StringTypeRegSZ );
+ } else {
+ Type.Strcat( _StringTypeRegExpandSZ );
+ }
+ if( !PrintString( &Type ) ) {
+ return( FALSE );
+ }
+ if( !PrintDataRegSz( Data, Size ) ) {
+ return( FALSE );
+ }
+ break;
+
+
+ case TYPE_REG_MULTI_SZ:
+
+ Type.Strcat( _StringTypeRegMultiSZ );
+ if( !PrintString( &Type ) ) {
+ return( FALSE );
+ }
+ if( !PrintDataRegMultiSz( Data, Size ) ) {
+ return( FALSE );
+ }
+ break;
+
+ case TYPE_REG_BINARY:
+
+ Type.Strcat( _StringTypeRegBinary );
+ if( !PrintString( &Type ) ) {
+ return( FALSE );
+ }
+ if( !PrintDataRegBinary( Data, Size ) ) {
+ return( FALSE );
+ }
+ break;
+
+ case TYPE_REG_DWORD:
+
+ Type.Strcat( _StringTypeRegDWORD );
+ if( !PrintString( &Type ) ) {
+ return( FALSE );
+ }
+ if( !PrintDataRegUlong( Data, Size ) ) {
+ return( FALSE );
+ }
+ break;
+
+ case TYPE_REG_RESOURCE_LIST:
+
+ Type.Strcat( _StringTypeRegResourceList );
+ if( !PrintString( &Type ) ) {
+ return( FALSE );
+ }
+ if( !PrintDataRegResourceList( Data, Size ) ) {
+ return( FALSE );
+ }
+ break;
+
+ case TYPE_REG_FULL_RESOURCE_DESCRIPTOR:
+ {
+ FULL_DESCRIPTOR FullDescriptor;
+
+ Type.Strcat( _StringTypeRegFullResourceDescriptor );
+ if( !PrintString( &Type ) ) {
+ return( FALSE );
+ }
+ if( !FullDescriptor.Initialize( Data, Size ) ||
+ !PrintFullResourceDescriptor( &FullDescriptor, 0, FALSE ) ) {
+ return( FALSE );
+ }
+ break;
+ }
+
+ case TYPE_REG_RESOURCE_REQUIREMENTS_LIST:
+
+ Type.Strcat( _StringTypeRegResourceRequirementsList );
+ if( !PrintString( &Type ) ) {
+ return( FALSE );
+ }
+ if( !PrintDataRegRequirementsList( Data, Size ) ) {
+ return( FALSE );
+ }
+// if( !PrintDataRegBinary( Data, Size ) ) {
+// return( FALSE );
+// }
+ break;
+
+ default:
+
+ Type.Strcat( _StringTypeRegUnknown );
+ if( !PrintString( &Type ) ) {
+ return( FALSE );
+ }
+ if( !PrintDataRegBinary( Data, Size ) ) {
+ return( FALSE );
+ }
+ }
+
+ if( !PrintString( &_EmptyLine ) ) {
+ return( FALSE );
+ }
+
+ return( TRUE );
+}
+
+
+
+BOOL
+APIENTRY
+EXPORT
+PRINT_MANAGER::PrintDlgProc(
+ IN HWND Handle,
+ IN WORD Message,
+ IN WPARAM wParam,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Interpret messages that are received while the Abort Print Dialog is
+ displayed.
+
+
+Arguments:
+
+ Standard windows arguments:
+
+ Handle -
+
+ Message -
+
+ wParam -
+
+ lParam -
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the message received was proccessed by this
+ by this method (ie, Abort Print Dialog was created or
+ Abort Print Dialog is displayed and the user selected cancel.
+ It returns FALSE otherwise.
+
+--*/
+
+{
+
+ wParam = wParam;
+ lParam = lParam;
+
+ switch( Message ) {
+
+ case WM_INITDIALOG:
+
+ SetWindowText( Handle, (LPWSTR)L"Print" );
+ // EnableMenuItem( GetSystemMenu( Handle, FALSE ), SC_CLOSE, MF_GRAYED );
+ return( TRUE );
+
+
+ case WM_COMMAND:
+
+ _UserAbort = TRUE;
+ DebugPrint( "_UserAbort was set" );
+ EnableWindow( GetParent( Handle ), TRUE );
+ DestroyWindow( Handle );
+ _DlgPrint = 0;
+ return( TRUE );
+
+ }
+ return( FALSE );
+}
+
+
+
+BOOLEAN
+PRINT_MANAGER::AbortProc(
+ IN HDC PrinterDC,
+ IN SHORT Code
+ )
+
+/*++
+
+Routine Description:
+
+ This is a standard abort function that is passed to GDI before the
+ printing operation starts. GDI will call this function in special
+ situations
+
+
+
+Arguments:
+
+ Standard arguments for an Abort Procedure.
+
+ PrinterDC - A handle to the Printer device context.
+
+ Code - A code that informs the current printing status
+ ( 0 ............. No error in spooler operation,
+ SP_OUTOFDISK... Spooler ran out of disk space )
+
+
+Return Value:
+
+ BOOLEAN - Returns FALSE if the user wants to abort the printing
+ operation. Returns TRUE otherwise.
+
+
+--*/
+
+{
+ MSG Msg;
+
+ PrinterDC = PrinterDC;
+ Code = Code;
+
+ while( !_UserAbort && PeekMessage( &Msg, NULL, 0, 0, PM_REMOVE ) ) {
+ if( !_DlgPrint || !IsDialogMessage( _DlgPrint, &Msg ) ) {
+ TranslateMessage( &Msg );
+ DispatchMessage( &Msg );
+ }
+ }
+ return ( !_UserAbort );
+}
+
+
+
+
+VOID
+PRINT_MANAGER::PrintErrorDialog(
+ IN LONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+
+ Display a message box informing the user that an error occurred
+ during the printing process.
+
+
+
+Arguments:
+
+ ErrorCode - A code that indicates the nature of the error.
+ ErrorCode == 0 means that no error has occurred.
+
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ PWSTRING Message;
+ PWSTRING TmpString;
+ PWSTR String;
+ PWSTR Title;
+ HWND Handle;
+
+
+ //
+ // Decides which handle to use based on what is currently displayed
+ // to the user: an AbortDialogBox or a Registry Window
+ //
+ Handle = ( _DlgPrint )? _DlgPrint : _hWnd;
+ if( ( ErrorCode & SP_NOTREPORTED ) != 0 ) {
+ //
+ // The error hasn't been reported yet
+ //
+ switch( ErrorCode ) {
+
+ case SP_ERROR:
+
+ Message = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_SP_ERROR_LINE1, "" );
+ DebugPtrAssert( Message );
+ TmpString = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_SP_ERROR_LINE2, "" );
+ DebugPtrAssert( TmpString );
+ Message->Strcat( TmpString );
+ DELETE( TmpString );
+ TmpString = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_SP_ERROR_LINE3, "" );
+ DebugPtrAssert( TmpString );
+ Message->Strcat( TmpString );
+ DELETE( TmpString );
+ TmpString = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_SP_ERROR_LINE4, "" );
+ DebugPtrAssert( TmpString );
+ Message->Strcat( TmpString );
+ DELETE( TmpString );
+ TmpString = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_SP_ERROR_LINE5, "" );
+ DebugPtrAssert( TmpString );
+ Message->Strcat( TmpString );
+ DELETE( TmpString );
+
+
+ break;
+
+
+ case SP_OUTOFDISK:
+
+ Message = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_SP_OUTOFDISK, "" );
+ DebugPtrAssert( Message );
+ break;
+
+
+ case SP_OUTOFMEMORY:
+
+ Message = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_SP_OUTOFMEMORY, "" );
+ DebugPtrAssert( Message );
+ break;
+
+
+ case SP_APPABORT:
+
+ Message = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_SP_APPABORT, "" );
+ DebugPtrAssert( Message );
+ break;
+
+ case SP_USERABORT:
+
+ Message = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_SP_USERABORT, "" );
+ DebugPtrAssert( Message );
+ break;
+
+ default:
+
+ Message = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_UNKNOWN_ERROR, "" );
+ DebugPtrAssert( Message );
+ break;
+
+ }
+
+ String = Message->QueryWSTR();
+ DebugPtrAssert( String );
+ DELETE( Message );
+
+ Message = NULL;
+ Message = REGEDIT_BASE_SYSTEM::QueryString( MSG_PRINT_ERROR_DIALOG_TITLE, "" );
+ DebugPtrAssert( Message );
+ Title = Message->QueryWSTR();
+ DELETE( Message );
+ MessageBox( _DlgPrint, String, Title, ( UINT )( MB_APPLMODAL | MB_OK ) );
+ FREE( String );
+ FREE( Title );
+ }
+}
+
+
+
+
+BOOLEAN
+PRINT_MANAGER::PrintValueType(
+ IN PCWSTRING ValueType
+ )
+
+/*++
+
+Routine Description:
+
+ Prints a string that contains the type of a value entry in a registry
+ node.
+
+
+Arguments:
+
+ ValueType - Pointer to a WSTRING object that represents a type name.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ DSTRING Type;
+
+
+ if( !Type.Initialize( L"Value Type = " ) ) {
+ DebugPrint( "Type.Initialize() failed" );
+ return( FALSE );
+ }
+ Type.Strcat( ValueType );
+ if( !PrintString( &Type ) ) {
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+PRINT_MANAGER::PrintDataRegBinary(
+ IN PCBYTE ValueData,
+ IN ULONG ValueDataLength,
+ IN BOOLEAN PrintDataLabel
+ )
+
+/*++
+
+Routine Description:
+
+ Print a string that contains the binary data stored in a value entry
+ of a registry node.
+
+
+
+Arguments:
+
+ ValueData - Buffer that contains the binary data.
+
+ ValueDataLength - Number of bytes in the buffer.
+
+ PrintDataLabel - A flag indicating whether or not the 'Data:' label should
+ be printed.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ DSTRING Data;
+ PWSTR AuxData;
+ DSTRING FormattedData;
+
+
+ DWORD DataIndex;
+ DWORD DataIndex2;
+ WORD SeperatorChars;
+ ULONG Index;
+
+
+
+
+ //
+ // DataIndex2 tracks multiples of 16.
+ //
+
+ DataIndex2 = 0;
+
+ //
+ // Display label.
+ //
+
+ if( PrintDataLabel ) {
+ if( !PrintString( _StringData ) ) {
+ DebugPrint( "PrintString( &_StringData ) failed \n" );
+ return( FALSE );
+ }
+ }
+
+ if( ValueDataLength == 0 ) {
+ return( TRUE );
+ }
+
+ if( ValueData == NULL ) {
+ DebugPrint( "ValueData is NULL \n" );
+ return( TRUE );
+ }
+
+ //
+ // Display rows of 16 bytes of data.
+ //
+
+ AuxData = ( PWCHAR )MALLOC( 80*sizeof( WCHAR ) );
+
+ for(DataIndex = 0;
+ DataIndex < ( ValueDataLength >> 4 );
+ DataIndex++,
+ DataIndex2 = DataIndex << 4 ) {
+
+ //
+ // The string that contains the format in the sprintf below
+ // cannot be broken because cfront on mips doesn't like it.
+ //
+
+ swprintf(AuxData,
+ (LPWSTR)L"%08x %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x %02x %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
+ DataIndex2,
+ ValueData[ DataIndex2 + 0 ],
+ ValueData[ DataIndex2 + 1 ],
+ ValueData[ DataIndex2 + 2 ],
+ ValueData[ DataIndex2 + 3 ],
+ ValueData[ DataIndex2 + 4 ],
+ ValueData[ DataIndex2 + 5 ],
+ ValueData[ DataIndex2 + 6 ],
+ ValueData[ DataIndex2 + 7 ],
+ ValueData[ DataIndex2 + 8 ],
+ ValueData[ DataIndex2 + 9 ],
+ ValueData[ DataIndex2 + 10 ],
+ ValueData[ DataIndex2 + 11 ],
+ ValueData[ DataIndex2 + 12 ],
+ ValueData[ DataIndex2 + 13 ],
+ ValueData[ DataIndex2 + 14 ],
+ ValueData[ DataIndex2 + 15 ],
+ iswprint( ValueData[ DataIndex2 + 0 ] )
+ ? ValueData[ DataIndex2 + 0 ] : ( WCHAR )'.',
+ iswprint( ValueData[ DataIndex2 + 1 ] )
+ ? ValueData[ DataIndex2 + 1 ] : ( WCHAR )'.',
+ iswprint( ValueData[ DataIndex2 + 2 ] )
+ ? ValueData[ DataIndex2 + 2 ] : ( WCHAR )'.',
+ iswprint( ValueData[ DataIndex2 + 3 ] )
+ ? ValueData[ DataIndex2 + 3 ] : ( WCHAR )'.',
+ iswprint( ValueData[ DataIndex2 + 4 ] )
+ ? ValueData[ DataIndex2 + 4 ] : ( WCHAR )'.',
+ iswprint( ValueData[ DataIndex2 + 5 ] )
+ ? ValueData[ DataIndex2 + 5 ] : ( WCHAR )'.',
+ iswprint( ValueData[ DataIndex2 + 6 ] )
+ ? ValueData[ DataIndex2 + 6 ] : ( WCHAR )'.',
+ iswprint( ValueData[ DataIndex2 + 7 ] )
+ ? ValueData[ DataIndex2 + 7 ] : ( WCHAR )'.',
+ iswprint( ValueData[ DataIndex2 + 8 ] )
+ ? ValueData[ DataIndex2 + 8 ] : ( WCHAR )'.',
+ iswprint( ValueData[ DataIndex2 + 9 ] )
+ ? ValueData[ DataIndex2 + 9 ] : ( WCHAR )'.',
+ iswprint( ValueData[ DataIndex2 + 10 ] )
+ ? ValueData[ DataIndex2 + 10 ] : ( WCHAR )'.',
+ iswprint( ValueData[ DataIndex2 + 11 ] )
+ ? ValueData[ DataIndex2 + 11 ] : ( WCHAR )'.',
+ iswprint( ValueData[ DataIndex2 + 12 ] )
+ ? ValueData[ DataIndex2 + 12 ] : ( WCHAR )'.',
+ iswprint( ValueData[ DataIndex2 + 13 ] )
+ ? ValueData[ DataIndex2 + 13 ] : ( WCHAR )'.',
+ iswprint( ValueData[ DataIndex2 + 14 ] )
+ ? ValueData[ DataIndex2 + 14 ] : ( WCHAR )'.',
+ iswprint( ValueData[ DataIndex2 + 15 ] )
+ ? ValueData[ DataIndex2 + 15 ] : ( WCHAR )'.'
+ );
+ if( !FormattedData.Initialize( AuxData ) ) {
+ DebugPrint( "FormattedData.Initialize() failed \n" );
+ FREE( AuxData );
+ return( FALSE );
+ }
+
+ if( !PrintString( &FormattedData, FALSE ) ) {
+ DebugPrint( "PrintString( &FormattedData ) failed \n" );
+ FREE( AuxData );
+ return( FALSE );
+ }
+ }
+
+
+ //
+ // If the ValueDataLength is not an even multiple of 16
+ // then there is one additonal line of data to display.
+ //
+
+ if( ValueDataLength % 16 != 0 ) {
+
+ //
+ // No seperator characters displayed so far.
+ //
+
+ SeperatorChars = 0;
+
+ Index = swprintf( AuxData, (LPWSTR)L"%08x ", DataIndex << 4 );
+
+ //
+ // Display the remaining data, one byte at a time in hex.
+ //
+
+ for(DataIndex = DataIndex2;
+ DataIndex < ValueDataLength;
+ DataIndex++ ) {
+
+ Index += swprintf( ( AuxData + Index ), (LPWSTR)L"%02x ", ValueData[ DataIndex ] );
+
+ //
+ // If eight data values have been displayed, print
+ // the seperator.
+ //
+
+ if( DataIndex % 8 == 7 ) {
+
+ Index += swprintf( &AuxData[Index], (LPWSTR)L"%s", (LPWSTR)L"- " );
+
+ //
+ // Remember that two seperator characters were
+ // displayed.
+ //
+
+ SeperatorChars = 2;
+ }
+ }
+
+ //
+ // Fill with blanks to the printable characters position.
+ // That is position 63 less 8 spaces for the 'address',
+ // 3 blanks, 3 spaces for each value displayed, possibly
+ // two for the seperator plus two blanks at the end.
+ //
+
+ Index += swprintf( &AuxData[Index],
+ (LPWSTR)L"%*c",
+ 64
+ - ( 8 + 3
+ + (( DataIndex % 16 ) * 3 )
+ + SeperatorChars
+ + 2 ), ( WCHAR)' ' );
+
+ //
+ // Display the remaining data, one byte at a time as
+ // printable characters.
+ //
+
+ for(
+ DataIndex = DataIndex2;
+ DataIndex < ValueDataLength;
+ DataIndex++ ) {
+
+ Index += swprintf( &AuxData[ Index ],
+ (LPWSTR)L"%c",
+ iswprint( ValueData[ DataIndex ] )
+ ? ValueData[ DataIndex ] : (WCHAR)'.'
+ );
+
+ }
+ if( !FormattedData.Initialize( AuxData ) ) {
+ DebugPrint( "FormattedData.Initialize( AuxData ) failed \n" );
+ FREE( AuxData );
+ return( FALSE );
+ }
+ if( !PrintString( &FormattedData, FALSE ) ) {
+ DebugPrint( "PrintString( &FormattedData ) failed \n" );
+ FREE( AuxData );
+ return( FALSE );
+ }
+ }
+
+ FREE( AuxData );
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+PRINT_MANAGER::PrintDataRegUlong(
+ IN PCBYTE ValueData,
+ IN ULONG ValueDataLength
+ )
+
+/*++
+
+Routine Description:
+
+ Print a string that contains the ULONG stored in a value entry
+ of a registry node.
+
+
+Arguments:
+
+ ValueData - Buffer that contains the data.
+
+ ValueDataLength - Number of bytes in the buffer.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ DSTRING Data;
+ PWSTR AuxData;
+ DSTRING FormattedData;
+
+
+ if( !Data.Initialize( _StringData ) ) {
+ DebugPrint( "Data.Initialize() failed" );
+ return( FALSE );
+ }
+ if( ( ValueDataLength >= sizeof( DWORD ) ) &&
+ ( ValueData != NULL ) ) {
+ AuxData = ( PWSTR )MALLOC( (10 + 1)*sizeof( WCHAR ) );
+ DebugPtrAssert( AuxData );
+
+ swprintf( AuxData, (LPWSTR)L"%#x", *( ( PULONG )ValueData ) );
+
+ if( !FormattedData.Initialize( AuxData ) ) {
+ FREE( AuxData );
+ DebugPrint( "FormattedData.Initialize() failed" );
+ return( FALSE );
+ }
+ FREE( AuxData );
+ Data.Strcat( &FormattedData );
+ }
+ if( !PrintString( &Data ) ) {
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+PRINT_MANAGER::PrintDataRegMultiSz(
+ IN PCBYTE Data,
+ IN ULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ Print a REG_MULTI_SZ stored in a value entry of a registry node.
+
+
+Arguments:
+
+ Data - Pointer to the buffer that contais a REG_MULTI_SZ data.
+
+ Size - Number of bytes in the buffer.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ DSTRING FormattedData;
+ DSTRING AuxData;
+ PWSTR Pointer;
+ DSTRING String;
+ ULONG Length;
+
+
+
+ if( !FormattedData.Initialize( _StringData ) ) {
+ DebugPrint( "FormattedData.Initialize() failed" );
+ return( FALSE );
+ }
+
+ if( ( Size > sizeof( WCHAR ) ) && ( Data != NULL ) ) {
+ Pointer = ( PWSTR )Data;
+ //
+ //
+ //
+ if( !AuxData.Initialize( Pointer ) ) {
+ DebugPrint( "AuxData.Initialize() failed" );
+ return( FALSE );
+ }
+ Length = AuxData.QueryChCount();
+ FormattedData.Strcat( &AuxData );
+ if( !PrintString( &FormattedData, FALSE ) ) {
+ return( FALSE );
+ }
+
+ Pointer += Length + 1;
+ while( ( ULONG )Pointer < ( ULONG )( Data + Size ) ) {
+ if( !AuxData.Initialize( Pointer ) ) {
+ DebugPrint( "AuxData.Initialize() failed" );
+ return( FALSE );
+ }
+ Length = AuxData.QueryChCount();
+ if( !AuxData.Replace( 0, 0, &_IndentString ) ) {
+ DebugPrint( "TmpString.Replace() failed \n" );
+ return( FALSE );
+ }
+ if( !PrintString( &AuxData, FALSE ) ) {
+ return( FALSE );
+ }
+ Pointer += Length + 1;
+ }
+
+ } else {
+ if( !PrintString( &FormattedData ) ) {
+ return( FALSE );
+ }
+ }
+ return( TRUE );
+}
+
+
+BOOLEAN
+PRINT_MANAGER::PrintDataRegResourceList(
+ IN PCBYTE Data,
+ IN ULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ Print a REG_RESOURCE_LIST stored in a value entry of a registry node.
+
+
+Arguments:
+
+ Data - Pointer to the buffer that contais a REG_RESOURCE_LIST data.
+
+ Size - Number of bytes in the buffer.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ RESOURCE_LIST ResourceList;
+ DSTRING FormattedData;
+ PARRAY FullResourceDescriptors;
+ PITERATOR Iterator;
+ PCFULL_DESCRIPTOR FullDescriptor;
+ ULONG DescriptorNumber;
+
+
+ if( !FormattedData.Initialize( _StringData ) ) {
+ DebugPrint( "FormattedData.Initialize() failed" );
+ return( FALSE );
+ }
+
+ if( !PrintString( &FormattedData ) ) {
+ return( FALSE );
+ }
+
+ if( ( Size == 0 ) ||
+ ( Data == NULL ) ||
+ !ResourceList.Initialize( Data, Size ) ) {
+ DebugPrintf( "REGEDT32: Unable to initialize ResourceList \n" );
+ return( FALSE );
+ }
+
+ if( ( ( FullResourceDescriptors = ResourceList.GetFullResourceDescriptors() ) == NULL ) ||
+ ( ( Iterator = FullResourceDescriptors->QueryIterator() ) == NULL ) ) {
+ DebugPrintf( "REGEDT32: Out of memory! \n" );
+ return( FALSE );
+ }
+ DescriptorNumber = 0;
+ while( ( FullDescriptor = ( PCFULL_DESCRIPTOR )( Iterator->GetNext() ) ) != NULL ) {
+ if( !PrintFullResourceDescriptor( FullDescriptor, DescriptorNumber ) ) {
+ DELETE( Iterator );
+ return( FALSE );
+ }
+ DescriptorNumber++;
+ }
+ DELETE( Iterator );
+ return( TRUE );
+}
+
+
+BOOLEAN
+PRINT_MANAGER::PrintFullResourceDescriptor(
+ IN PCFULL_DESCRIPTOR FullDescriptor,
+ IN ULONG DescriptorNumber,
+ IN BOOLEAN PrintDescriptorNumber
+ )
+
+/*++
+
+Routine Description:
+
+ Print the contents of a FULL_DESCRIPTOR object.
+
+
+Arguments:
+
+ FullDescriptor - Pointer to object to be printed.
+
+ DescriptorNumber -
+
+ PrintDescriptorNumber - A flag that indicates whether or not the descriptor number should
+ be printed.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ DSTRING FullDescriptorNumberString;
+
+ DSTRING AuxString;
+ DSTRING InterfaceType;
+ DSTRING BusNumber;
+ DSTRING Version;
+ DSTRING Revision;
+ WCHAR AuxNumber[11];
+ PWSTRING TypeString;
+ ULONG InterfaceId;
+ PARRAY Descriptors;
+ PITERATOR Iterator;
+ PCPARTIAL_DESCRIPTOR PartialDescriptor;
+ ULONG Count;
+
+ if( !FullDescriptorNumberString.Initialize( &_IndentString ) ||
+ !FullDescriptorNumberString.Strcat( _StringFullDescriptor ) ||
+ !InterfaceType.Initialize( &_IndentString ) ||
+ !InterfaceType.Strcat( _StringInterfaceType ) ||
+ !BusNumber.Initialize( &_IndentString ) ||
+ !BusNumber.Strcat( _StringBusNumber ) ||
+ !Version.Initialize( &_IndentString ) ||
+ !Version.Strcat( _StringVersion ) ||
+ !Revision.Initialize( &_IndentString ) ||
+ !Revision.Strcat( _StringRevision )
+ ) {
+ DebugPrint( "REGEDT32: Initialization failure" );
+ return( FALSE );
+ }
+
+ //
+ // Build a string that contains the full descriptor number
+ // and print it
+ //
+ if( PrintDescriptorNumber ) {
+ wsprintf( AuxNumber, (LPWSTR)L"%d", DescriptorNumber );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ FullDescriptorNumberString.Strcat( &AuxString );
+ if( !PrintString( &FullDescriptorNumberString ) ) {
+ return( FALSE );
+ }
+ }
+
+ //
+ // Print the interface type
+
+ switch( FullDescriptor->GetInterfaceType() ) {
+
+ case Internal:
+
+ InterfaceId = MSG_BUS_INTERNAL;
+ break;
+
+ case Isa:
+
+ InterfaceId = MSG_BUS_ISA;
+ break;
+
+ case Eisa:
+
+ InterfaceId = MSG_BUS_EISA;
+ break;
+
+ case MicroChannel:
+
+ InterfaceId = MSG_BUS_MICRO_CHANNEL;
+ break;
+
+ case TurboChannel:
+
+ InterfaceId = MSG_BUS_TURBO_CHANNEL;
+ break;
+
+ case PCIBus:
+
+ InterfaceId = MSG_BUS_PCI_BUS;
+ break;
+
+ case VMEBus:
+
+ InterfaceId = MSG_BUS_VME_BUS;
+ break;
+
+ case NuBus:
+
+ InterfaceId = MSG_BUS_NU_BUS;
+ break;
+
+ case PCMCIABus:
+
+ InterfaceId = MSG_BUS_PCMCIA_BUS;
+ break;
+
+ case CBus:
+
+ InterfaceId = MSG_BUS_C_BUS;
+ break;
+
+ case MPIBus:
+
+ InterfaceId = MSG_BUS_MPI_BUS;
+ break;
+
+ case MPSABus:
+
+ InterfaceId = MSG_BUS_MPSA_BUS;
+ break;
+
+ default:
+
+ InterfaceId = MSG_INVALID;
+ break;
+ }
+
+ TypeString = REGEDIT_BASE_SYSTEM::QueryString( InterfaceId, "" );
+
+ if( TypeString == NULL ) {
+ DebugPrintf( "REGEDT32: Unable to retrieve string \n" );
+ return( FALSE );
+ }
+ InterfaceType.Strcat( TypeString );
+ DELETE( TypeString );
+ if( !PrintString( &InterfaceType ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print the bus number
+ //
+ wsprintf( AuxNumber, (LPWSTR)L"%d", FullDescriptor->GetBusNumber() );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ BusNumber.Strcat( &AuxString );
+
+ if( !PrintString( &BusNumber ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print version
+ //
+ wsprintf( AuxNumber, (LPWSTR)L"%d", FullDescriptor->GetVersion() );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ Version.Strcat( &AuxString );
+ if( !PrintString( &Version ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print revision
+ //
+ wsprintf( AuxNumber, (LPWSTR)L"%d", FullDescriptor->GetRevision() );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ Revision.Strcat( &AuxString );
+ if( !PrintString( &Revision ) ) {
+ return( FALSE );
+ }
+
+ Descriptors = FullDescriptor->GetResourceDescriptors();
+ if( ( Descriptors == NULL ) ||
+ ( ( Iterator = Descriptors->QueryIterator() ) == NULL )
+ ) {
+ return( FALSE );
+ }
+ Count = 0;
+ while( ( PartialDescriptor = ( PCPARTIAL_DESCRIPTOR )( Iterator->GetNext() ) ) != NULL ) {
+ if( !PrintPartialDescriptor( PartialDescriptor, Count ) ) {
+ DELETE( Iterator );
+ return( FALSE );
+ }
+ Count++;
+ }
+ DELETE( Iterator );
+
+ if( !PrintString( &_EmptyLine ) ) {
+ DebugPrint( "PrintString() failed \n" );
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+BOOLEAN
+PRINT_MANAGER::PrintPartialDescriptor(
+ IN PCPARTIAL_DESCRIPTOR PartialDescriptor,
+ IN ULONG DescriptorNumber
+ )
+
+/*++
+
+Routine Description:
+
+ Print the contents of a PARTIAL_DESCRIPTOR object.
+
+
+Arguments:
+
+ PartialDescriptor - Pointer to object to be printed.
+
+ DescriptorNumber -
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ DSTRING PartialDescriptorNumberString;
+
+ DSTRING AuxString;
+ WCHAR AuxNumber[11];
+ DSTRING ResourceString;
+ DSTRING DispositionString;
+ ULONG StringId;
+ PWSTRING String;
+
+ if( !PartialDescriptorNumberString.Initialize( &_IndentString ) ||
+ !PartialDescriptorNumberString.Strcat( _StringPartialDescriptor ) ||
+ !ResourceString.Initialize( &_IndentString ) ||
+ !ResourceString.Strcat( _StringResource ) ||
+ !DispositionString.Initialize( &_IndentString ) ||
+ !DispositionString.Strcat( _StringDisposition )
+ ) {
+ DebugPrint( "REGEDT32: Initialization failure" );
+ return( FALSE );
+ }
+
+ //
+ // Build a string that contains the full descriptor number
+ // and print it
+ //
+ wsprintf( AuxNumber, (LPWSTR)L"%d", DescriptorNumber );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ PartialDescriptorNumberString.Strcat( &AuxString );
+ if( !PrintString( &PartialDescriptorNumberString ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print the resource type
+ //
+ if( PartialDescriptor->IsDescriptorTypeDma() ) {
+ StringId = MSG_DEV_DMA;
+ } else if( PartialDescriptor->IsDescriptorTypeInterrupt() ) {
+ StringId = MSG_DEV_INTERRUPT;
+ } else if( PartialDescriptor->IsDescriptorTypeMemory() ) {
+ StringId = MSG_DEV_MEMORY;
+ } else if( PartialDescriptor->IsDescriptorTypePort() ) {
+ StringId = MSG_DEV_PORT;
+ } else if( PartialDescriptor->IsDescriptorTypeDeviceSpecific() ) {
+ StringId = MSG_DEV_DEVICE_SPECIFIC;
+ } else {
+ StringId = MSG_INVALID;
+ }
+ String = REGEDIT_BASE_SYSTEM::QueryString( StringId, "" );
+
+ if( String == NULL ) {
+ DebugPrintf( "REGEDT32: Unable to retrieve string \n" );
+ return( FALSE );
+ }
+ ResourceString.Strcat( String );
+ DELETE( String );
+ if( !PrintString( &ResourceString ) ) {
+ return( FALSE );
+ }
+
+
+ //
+ // Print the disposition
+ //
+ if( PartialDescriptor->IsResourceShareUndetermined() ) {
+ StringId = MSG_SHARE_UNDETERMINED;
+ } else if( PartialDescriptor->IsResourceShareDeviceExclusive() ) {
+ StringId = MSG_SHARE_DEVICE_EXCLUSIVE;
+ } else if( PartialDescriptor->IsResourceShareDriverExclusive() ) {
+ StringId = MSG_SHARE_DRIVER_EXCLUSIVE;
+ } else {
+ StringId = MSG_SHARE_SHARED;
+ }
+
+ String = REGEDIT_BASE_SYSTEM::QueryString( StringId, "" );
+
+ if( String == NULL ) {
+ DebugPrintf( "REGEDT32: Unable to retrieve string \n" );
+ return( FALSE );
+ }
+ DispositionString.Strcat( String );
+ DELETE( String );
+ if( !PrintString( &DispositionString ) ) {
+ return( FALSE );
+ }
+
+ if( PartialDescriptor->IsDescriptorTypeDma() ) {
+ if( !PrintDmaDescriptor( ( PCDMA_DESCRIPTOR )PartialDescriptor ) ) {
+ return( FALSE );
+ }
+ } else if( PartialDescriptor->IsDescriptorTypeInterrupt() ) {
+ if( !PrintInterruptDescriptor( ( PCINTERRUPT_DESCRIPTOR )PartialDescriptor ) ) {
+ return( FALSE );
+ }
+ } else if( PartialDescriptor->IsDescriptorTypeMemory() ) {
+ if( !PrintMemoryDescriptor( ( PCMEMORY_DESCRIPTOR )PartialDescriptor ) ) {
+ return( FALSE );
+ }
+ } else if( PartialDescriptor->IsDescriptorTypePort() ) {
+ if( !PrintPortDescriptor( ( PCPORT_DESCRIPTOR )PartialDescriptor ) ) {
+ return( FALSE );
+ }
+ } else if( PartialDescriptor->IsDescriptorTypeDeviceSpecific() ) {
+ if( !PrintDeviceSpecificDescriptor( ( PCDEVICE_SPECIFIC_DESCRIPTOR )PartialDescriptor ) ) {
+ return( FALSE );
+ }
+ }
+
+ if( !PrintString( &_EmptyLine ) ) {
+ DebugPrint( "PrintString() failed \n" );
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+BOOLEAN
+PRINT_MANAGER::PrintInterruptDescriptor(
+ IN PCINTERRUPT_DESCRIPTOR Descriptor
+ )
+
+/*++
+
+Routine Description:
+
+ Print the contents of a INTERRUPT_DESCRIPTOR object.
+
+
+Arguments:
+
+ Descriptor - Pointer to object to be printed.
+
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ DSTRING VectorString;
+ DSTRING LevelString;
+ DSTRING AffinityString;;
+ DSTRING TypeString;
+
+ DSTRING AuxString;
+ WCHAR AuxNumber[19];
+ ULONG StringId;
+ PWSTRING String;
+
+ if( !VectorString.Initialize( &_IndentString ) ||
+ !VectorString.Strcat( _StringVector ) ||
+ !LevelString.Initialize( &_IndentString ) ||
+ !LevelString.Strcat( _StringLevel ) ||
+ !AffinityString.Initialize( &_IndentString ) ||
+ !AffinityString.Strcat( _StringAffinity ) ||
+ !TypeString.Initialize( &_IndentString ) ||
+ !TypeString.Strcat( _StringType )
+ ) {
+ DebugPrint( "REGEDT32: Initialization failure" );
+ return( FALSE );
+ }
+
+ //
+ // Print the vector
+ //
+ wsprintf( AuxNumber, (LPWSTR)L"%d", Descriptor->GetVector() );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ VectorString.Strcat( &AuxString );
+ if( !PrintString( &VectorString ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print the level
+ //
+ wsprintf( AuxNumber, (LPWSTR)L"%d", Descriptor->GetLevel() );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ LevelString.Strcat( &AuxString );
+ if( !PrintString( &LevelString ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print the affinity
+ //
+ wsprintf( AuxNumber, (LPWSTR)L"0x%08x", Descriptor->GetAffinity() );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ AffinityString.Strcat( &AuxString );
+ if( !PrintString( &AffinityString ) ) {
+ return( FALSE );
+ }
+
+ StringId = ( Descriptor->IsInterruptLevelSensitive() )? MSG_INT_LEVEL_SENSITIVE :
+ MSG_INT_LATCHED;
+
+ String = REGEDIT_BASE_SYSTEM::QueryString( StringId, "" );
+ if( String == NULL ) {
+ DebugPrintf( "REGEDT32: Unable to retrieve string \n" );
+ return( FALSE );
+ }
+ TypeString.Strcat( String );
+ DELETE( String );
+ if( !PrintString( &TypeString ) ) {
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+BOOLEAN
+PRINT_MANAGER::PrintPortDescriptor(
+ IN PCPORT_DESCRIPTOR Descriptor
+ )
+
+/*++
+
+Routine Description:
+
+ Print the contents of a PORT_DESCRIPTOR object.
+
+
+Arguments:
+
+ Descriptor - Pointer to object to be printed.
+
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ DSTRING StartAddressString;
+ DSTRING LengthString;
+ DSTRING TypeString;
+
+ DSTRING AuxString;
+ WCHAR AuxNumber[19];
+ ULONG StringId;
+ PWSTRING String;
+
+ if( !StartAddressString.Initialize( &_IndentString ) ||
+ !StartAddressString.Strcat( _StringStart ) ||
+ !LengthString.Initialize( &_IndentString ) ||
+ !LengthString.Strcat( _StringLength ) ||
+ !TypeString.Initialize( &_IndentString ) ||
+ !TypeString.Strcat( _StringType )
+ ) {
+ DebugPrint( "REGEDT32: Initialization failure" );
+ return( FALSE );
+ }
+
+ //
+ // Print the start address
+ //
+ if( ( ( ( PPORT_DESCRIPTOR )Descriptor )->GetPhysicalAddress() )->HighPart != 0 ) {
+ wsprintf( AuxNumber,
+ (LPWSTR)L"0x%08x%08x",
+ ( ( ( PPORT_DESCRIPTOR )Descriptor )->GetPhysicalAddress() )->HighPart,
+ ( ( ( PPORT_DESCRIPTOR )Descriptor )->GetPhysicalAddress() )->LowPart );
+ } else {
+ wsprintf( AuxNumber, (LPWSTR)L"0x%08x", ( ( ( PPORT_DESCRIPTOR )Descriptor )->GetPhysicalAddress() )->LowPart );
+ }
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ StartAddressString.Strcat( &AuxString );
+ if( !PrintString( &StartAddressString ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print the length
+ //
+ wsprintf( AuxNumber, (LPWSTR)L"%#x", Descriptor->GetLength() );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ LengthString.Strcat( &AuxString );
+ if( !PrintString( &LengthString ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print the type
+ //
+
+ StringId = ( Descriptor->IsPortMemory() )? MSG_PORT_MEMORY :
+ MSG_PORT_PORT;
+
+ String = REGEDIT_BASE_SYSTEM::QueryString( StringId, "" );
+ if( String == NULL ) {
+ DebugPrintf( "REGEDT32: Unable to retrieve string \n" );
+ return( FALSE );
+ }
+ TypeString.Strcat( String );
+ DELETE( String );
+ if( !PrintString( &TypeString ) ) {
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+BOOLEAN
+PRINT_MANAGER::PrintMemoryDescriptor(
+ IN PCMEMORY_DESCRIPTOR Descriptor
+ )
+
+/*++
+
+Routine Description:
+
+ Print the contents of a MEMORY_DESCRIPTOR object.
+
+
+Arguments:
+
+ Descriptor - Pointer to object to be printed.
+
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ DSTRING StartAddressString;
+ DSTRING LengthString;
+ DSTRING TypeString;
+
+ DSTRING AuxString;
+ WCHAR AuxNumber[19];
+ ULONG StringId;
+ PWSTRING String;
+
+ if( !StartAddressString.Initialize( &_IndentString ) ||
+ !StartAddressString.Strcat( _StringStart ) ||
+ !LengthString.Initialize( &_IndentString ) ||
+ !LengthString.Strcat( _StringLength ) ||
+ !TypeString.Initialize( &_IndentString ) ||
+ !TypeString.Strcat( _StringType )
+ ) {
+ DebugPrint( "REGEDT32: Initialization failure" );
+ return( FALSE );
+ }
+
+ //
+ // Print the start address
+ //
+ if( ( ( ( PMEMORY_DESCRIPTOR )Descriptor )->GetStartAddress() )->HighPart != 0 ) {
+ wsprintf( AuxNumber,
+ (LPWSTR)L"0x%08x%08x",
+ ( ( ( PMEMORY_DESCRIPTOR )Descriptor )->GetStartAddress() )->HighPart,
+ ( ( ( PMEMORY_DESCRIPTOR )Descriptor )->GetStartAddress() )->LowPart );
+ } else {
+ wsprintf( AuxNumber, (LPWSTR)L"0x%08x", ( ( ( PMEMORY_DESCRIPTOR )Descriptor )->GetStartAddress() )->LowPart );
+ }
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ StartAddressString.Strcat( &AuxString );
+ if( !PrintString( &StartAddressString ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print the length
+ //
+ wsprintf( AuxNumber, (LPWSTR)L"%#x", Descriptor->GetLength() );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ LengthString.Strcat( &AuxString );
+ if( !PrintString( &LengthString ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print the type
+ //
+
+ StringId = ( Descriptor->IsMemoryReadWrite() )? MSG_MEM_READ_WRITE :
+ ( ( Descriptor->IsMemoryReadWrite() )? MSG_MEM_READ_ONLY :
+ MSG_MEM_WRITE_ONLY );
+
+ String = REGEDIT_BASE_SYSTEM::QueryString( StringId, "" );
+ if( String == NULL ) {
+ DebugPrintf( "REGEDT32: Unable to retrieve string \n" );
+ return( FALSE );
+ }
+ TypeString.Strcat( String );
+ DELETE( String );
+ if( !PrintString( &TypeString ) ) {
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+BOOLEAN
+PRINT_MANAGER::PrintDmaDescriptor(
+ IN PCDMA_DESCRIPTOR Descriptor
+ )
+
+/*++
+
+Routine Description:
+
+ Print the contents of a DMA_DESCRIPTOR object.
+
+
+Arguments:
+
+ Descriptor - Pointer to object to be printed.
+
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ DSTRING ChannelString;
+ DSTRING PortString;
+
+ DSTRING AuxString;
+ WCHAR AuxNumber[19];
+
+ if( !ChannelString.Initialize( &_IndentString ) ||
+ !ChannelString.Strcat( _StringChannel ) ||
+ !PortString.Initialize( &_IndentString ) ||
+ !PortString.Strcat( _StringPort )
+ ) {
+ DebugPrint( "REGEDT32: Initialization failure" );
+ return( FALSE );
+ }
+
+ //
+ // Print the channel
+ //
+ wsprintf( AuxNumber, (LPWSTR)L"%d", Descriptor->GetChannel() );
+
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ ChannelString.Strcat( &AuxString );
+ if( !PrintString( &ChannelString ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print the port
+ //
+ wsprintf( AuxNumber, (LPWSTR)L"%d", Descriptor->GetPort() );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ PortString.Strcat( &AuxString );
+ if( !PrintString( &PortString ) ) {
+ return( FALSE );
+ }
+
+ return( TRUE );
+}
+
+
+BOOLEAN
+PRINT_MANAGER::PrintDeviceSpecificDescriptor(
+ IN PCDEVICE_SPECIFIC_DESCRIPTOR Descriptor
+ )
+
+/*++
+
+Routine Description:
+
+ Print the contents of a DEVICE_SPECIFIC_DESCRIPTOR object.
+
+
+Arguments:
+
+ Descriptor - Pointer to object to be printed.
+
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ DSTRING Reserved1String;
+ DSTRING Reserved2String;
+ DSTRING DataString;
+
+ DSTRING AuxString;
+ WCHAR AuxNumber[19];
+
+ ULONG Size;
+ PCBYTE Data;
+
+ if( !Reserved1String.Initialize( &_IndentString ) ||
+ !Reserved1String.Strcat( _StringReserved1 ) ||
+ !Reserved2String.Initialize( &_IndentString ) ||
+ !Reserved2String.Strcat( _StringReserved2 ) ||
+ !DataString.Initialize( &_IndentString ) ||
+ !DataString.Strcat( _StringDevSpecificData )
+ ) {
+ DebugPrint( "REGEDT32: Initialization failure" );
+ return( FALSE );
+ }
+
+ //
+ // Print reserved1
+ //
+ wsprintf( AuxNumber, (LPWSTR)L"0x%08x", Descriptor->GetReserved1() );
+
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ Reserved1String.Strcat( &AuxString );
+ if( !PrintString( &Reserved1String ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print reserved2
+ //
+ wsprintf( AuxNumber, (LPWSTR)L"0x%08x", Descriptor->GetReserved2() );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ Reserved2String.Strcat( &AuxString );
+ if( !PrintString( &Reserved2String ) ) {
+ return( FALSE );
+ }
+
+ Size = Descriptor->GetData( &Data );
+ if( ( Size != 0 ) &&
+ ( Data != NULL ) ) {
+ if( !PrintString( &DataString ) ) {
+ return( FALSE );
+ }
+ if( !PrintDataRegBinary( Data, Size, FALSE ) ) {
+ return( FALSE );
+ }
+ }
+ return( TRUE );
+}
+
+
+BOOLEAN
+PRINT_MANAGER::PrintDataRegSz(
+ IN PCBYTE Data,
+ IN ULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ Print a string that contains the REG_SZ stored in a value entry
+ of a registry node.
+
+
+Arguments:
+
+ Data - Pointer to the buffer that contais a REG_SZ or REG_EXPAND_SZ
+ data.
+
+ Size - Number of bytes in the buffer.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ DSTRING FormattedData;
+ DSTRING AuxData;
+
+
+
+ if( !FormattedData.Initialize( _StringData ) ) {
+ DebugPrint( "FormattedData.Initialize() failed" );
+ return( FALSE );
+ }
+
+ if( ( Size != 0 ) && ( Data != NULL ) ) {
+ if( Size >= sizeof( WCHAR ) ) {
+ if( *( Data + Size - sizeof( WCHAR ) ) == ( WCHAR )'\0' ) {
+ if( !AuxData.Initialize( ( PWSTR )Data ) ) {
+ DebugPrint( "AuxData.Initialize() failed" );
+ return( FALSE );
+ }
+ } else {
+ if( !AuxData.Initialize( ( PWSTR )Data, Size/sizeof( WCHAR ) ) ) {
+ DebugPrint( "AuxData.Initialize() failed" );
+ return( FALSE );
+ }
+ }
+ } else {
+ if( !AuxData.Initialize( ( PWSTR )Data, Size ) ) {
+ DebugPrint( "AuxData.Initialize() failed" );
+ return( FALSE );
+ }
+ }
+ FormattedData.Strcat( &AuxData );
+ }
+ if( !PrintString( &FormattedData ) ) {
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+BOOLEAN
+PRINT_MANAGER::PrintDataRegRequirementsList(
+ IN PCBYTE Data,
+ IN ULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ Print a REG_RESOURCE_REQUIREMENTS_LIST stored in a value entry of a registry node.
+
+
+Arguments:
+
+ Data - Pointer to the buffer that contais a REG_RESOURCE_REQUIREMENTS_LIST data.
+
+ Size - Number of bytes in the buffer.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ IO_REQUIREMENTS_LIST RequirementsList;
+ DSTRING FormattedData;
+ PARRAY AlternativeLists;
+ PITERATOR Iterator;
+ PCIO_DESCRIPTOR_LIST ResourceList;
+ ULONG ListNumber;
+
+ DSTRING AuxString;
+ DSTRING InterfaceType;
+ DSTRING BusNumber;
+ DSTRING SlotNumber;
+ WCHAR AuxNumber[11];
+ PWSTRING TypeString;
+ ULONG InterfaceId;
+
+
+
+ if( !FormattedData.Initialize( _StringData ) ) {
+ DebugPrint( "FormattedData.Initialize() failed" );
+ return( FALSE );
+ }
+
+ if( !PrintString( &FormattedData ) ) {
+ return( FALSE );
+ }
+
+ if( ( Size == 0 ) ||
+ ( Data == NULL ) ||
+ !RequirementsList.Initialize( Data, Size ) ) {
+ DebugPrintf( "REGEDT32: Unable to initialize RequirementsList \n" );
+ return( FALSE );
+ }
+
+ if( !InterfaceType.Initialize( &_IndentString ) ||
+ !InterfaceType.Strcat( _StringIoInterfaceType ) ||
+ !BusNumber.Initialize( &_IndentString ) ||
+ !BusNumber.Strcat( _StringIoBusNumber ) ||
+ !SlotNumber.Initialize( &_IndentString ) ||
+ !SlotNumber.Strcat( _StringIoSlotNumber )
+ ) {
+ DebugPrint( "REGEDT32: Initialization failure" );
+ return( FALSE );
+ }
+
+ //
+ // Print the interface type
+ //
+
+ switch( RequirementsList.GetInterfaceType() ) {
+
+ case Internal:
+
+ InterfaceId = MSG_BUS_INTERNAL;
+ break;
+
+ case Isa:
+
+ InterfaceId = MSG_BUS_ISA;
+ break;
+
+ case Eisa:
+
+ InterfaceId = MSG_BUS_EISA;
+ break;
+
+ case MicroChannel:
+
+ InterfaceId = MSG_BUS_MICRO_CHANNEL;
+ break;
+
+ case TurboChannel:
+
+ InterfaceId = MSG_BUS_TURBO_CHANNEL;
+ break;
+
+ case PCIBus:
+
+ InterfaceId = MSG_BUS_PCI_BUS;
+ break;
+
+ case VMEBus:
+
+ InterfaceId = MSG_BUS_VME_BUS;
+ break;
+
+ case NuBus:
+
+ InterfaceId = MSG_BUS_NU_BUS;
+ break;
+
+ case PCMCIABus:
+
+ InterfaceId = MSG_BUS_PCMCIA_BUS;
+ break;
+
+ case CBus:
+
+ InterfaceId = MSG_BUS_C_BUS;
+ break;
+
+ case MPIBus:
+
+ InterfaceId = MSG_BUS_MPI_BUS;
+ break;
+
+ case MPSABus:
+
+ InterfaceId = MSG_BUS_MPSA_BUS;
+ break;
+
+ default:
+
+ InterfaceId = MSG_INVALID;
+ break;
+ }
+
+ TypeString = REGEDIT_BASE_SYSTEM::QueryString( InterfaceId, "" );
+
+ if( TypeString == NULL ) {
+ DebugPrintf( "REGEDT32: Unable to retrieve string \n" );
+ return( FALSE );
+ }
+ InterfaceType.Strcat( TypeString );
+ DELETE( TypeString );
+ if( !PrintString( &InterfaceType ) ) {
+ return( FALSE );
+ }
+
+
+ //
+ // Print the bus number
+ //
+ wsprintf( AuxNumber, (LPWSTR)L"%d", RequirementsList.GetBusNumber() );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ BusNumber.Strcat( &AuxString );
+
+ if( !PrintString( &BusNumber ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print the slot number
+ //
+ wsprintf( AuxNumber, (LPWSTR)L"%d", RequirementsList.GetSlotNumber() );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ SlotNumber.Strcat( &AuxString );
+
+ if( !PrintString( &SlotNumber ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print the resource lists
+ //
+
+ if( ( ( AlternativeLists = RequirementsList.GetAlternativeLists() ) == NULL ) ||
+ ( ( Iterator = AlternativeLists->QueryIterator() ) == NULL ) ) {
+ DebugPrintf( "REGEDT32: Out of memory! \n" );
+ return( FALSE );
+ }
+ ListNumber = 0;
+ while( ( ResourceList = ( PCIO_DESCRIPTOR_LIST )( Iterator->GetNext() ) ) != NULL ) {
+ if( !PrintIoResourceList( ResourceList, ListNumber ) ) {
+ DELETE( Iterator );
+ return( FALSE );
+ }
+ ListNumber++;
+ }
+ DELETE( Iterator );
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+PRINT_MANAGER::PrintIoResourceList(
+ IN PCIO_DESCRIPTOR_LIST DescriptorList,
+ IN ULONG ListNumber
+ )
+
+/*++
+
+Routine Description:
+
+ Print the contents of an IO_DESCRIPTOR_LIST object.
+
+
+Arguments:
+
+ Descriptor - Pointer to object to be printed.
+
+ DescriptorNumber -
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ DSTRING ListNumberString;
+
+ DSTRING AuxString;
+ WCHAR AuxNumber[11];
+ PARRAY Descriptors;
+ PITERATOR Iterator;
+ PCIO_DESCRIPTOR IoDescriptor;
+ ULONG Count;
+
+ if( !ListNumberString.Initialize( &_IndentString ) ||
+ !ListNumberString.Strcat( _StringIoListNumber )
+ ) {
+ DebugPrint( "REGEDT32: Initialization failure" );
+ return( FALSE );
+ }
+
+ //
+ // Build a string that contains the list number
+ // and print it
+ //
+ wsprintf( AuxNumber, (LPWSTR)L"%d", ListNumber );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ ListNumberString.Strcat( &AuxString );
+ if( !PrintString( &ListNumberString ) ) {
+ return( FALSE );
+ }
+ Descriptors = DescriptorList->GetDescriptorsList();
+ if( ( Descriptors == NULL ) ||
+ ( ( Iterator = Descriptors->QueryIterator() ) == NULL )
+ ) {
+ return( FALSE );
+ }
+ Count = 0;
+ while( ( IoDescriptor = ( PCIO_DESCRIPTOR )( Iterator->GetNext() ) ) != NULL ) {
+ if( !PrintIoDescriptor( IoDescriptor, Count ) ) {
+ DELETE( Iterator );
+ return( FALSE );
+ }
+ Count++;
+ }
+ DELETE( Iterator );
+
+ if( !PrintString( &_EmptyLine ) ) {
+ DebugPrint( "PrintString() failed \n" );
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+PRINT_MANAGER::PrintIoDescriptor(
+ IN PCIO_DESCRIPTOR IoDescriptor,
+ IN ULONG DescriptorNumber
+ )
+
+/*++
+
+Routine Description:
+
+ Print the contents of an IO_DESCRIPTOR object.
+
+
+Arguments:
+
+ IoDescriptor - Pointer to object to be printed.
+
+ DescriptorNumber -
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ DSTRING IoDescriptorNumberString;
+
+ DSTRING AuxString;
+ WCHAR AuxNumber[11];
+ DSTRING ResourceString;
+ DSTRING DispositionString;
+ DSTRING OptionString;
+ ULONG StringId;
+ PWSTRING String;
+
+ if( !IoDescriptorNumberString.Initialize( &_IndentString ) ||
+ !IoDescriptorNumberString.Strcat( _StringIoDescriptorNumber ) ||
+ !ResourceString.Initialize( &_IndentString ) ||
+ !ResourceString.Strcat( _StringResource ) ||
+ !OptionString.Initialize( &_IndentString ) ||
+ !OptionString.Strcat( _StringIoOption ) ||
+ !DispositionString.Initialize( &_IndentString ) ||
+ !DispositionString.Strcat( _StringDisposition )
+ ) {
+ DebugPrint( "REGEDT32: Initialization failure" );
+ return( FALSE );
+ }
+
+ //
+ // Build a string that contains the full descriptor number
+ // and print it
+ //
+ wsprintf( AuxNumber, (LPWSTR)L"%d", DescriptorNumber );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ IoDescriptorNumberString.Strcat( &AuxString );
+ if( !PrintString( &IoDescriptorNumberString ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print the resource type
+ //
+ if( IoDescriptor->IsDescriptorTypeDma() ) {
+ StringId = MSG_DEV_DMA;
+ } else if( IoDescriptor->IsDescriptorTypeInterrupt() ) {
+ StringId = MSG_DEV_INTERRUPT;
+ } else if( IoDescriptor->IsDescriptorTypeMemory() ) {
+ StringId = MSG_DEV_MEMORY;
+ } else if( IoDescriptor->IsDescriptorTypePort() ) {
+ StringId = MSG_DEV_PORT;
+ } else {
+ StringId = MSG_INVALID;
+ }
+ String = REGEDIT_BASE_SYSTEM::QueryString( StringId, "" );
+
+ if( String == NULL ) {
+ DebugPrintf( "REGEDT32: Unable to retrieve string \n" );
+ return( FALSE );
+ }
+ ResourceString.Strcat( String );
+ DELETE( String );
+ if( !PrintString( &ResourceString ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print the option
+ //
+
+ wsprintf( AuxNumber, (LPWSTR)L"0x%08x", IoDescriptor->GetOption() );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ OptionString.Strcat( &AuxString );
+ if( !PrintString( &OptionString ) ) {
+ return( FALSE );
+ }
+
+
+
+ //
+ // Print the disposition
+ //
+ if( IoDescriptor->IsResourceShareUndetermined() ) {
+ StringId = MSG_SHARE_UNDETERMINED;
+ } else if( IoDescriptor->IsResourceShareDeviceExclusive() ) {
+ StringId = MSG_SHARE_DEVICE_EXCLUSIVE;
+ } else if( IoDescriptor->IsResourceShareDriverExclusive() ) {
+ StringId = MSG_SHARE_DRIVER_EXCLUSIVE;
+ } else {
+ StringId = MSG_SHARE_SHARED;
+ }
+
+ String = REGEDIT_BASE_SYSTEM::QueryString( StringId, "" );
+
+ if( String == NULL ) {
+ DebugPrintf( "REGEDT32: Unable to retrieve string \n" );
+ return( FALSE );
+ }
+ DispositionString.Strcat( String );
+ DELETE( String );
+ if( !PrintString( &DispositionString ) ) {
+ return( FALSE );
+ }
+
+ if( IoDescriptor->IsDescriptorTypeDma() ) {
+ if( !PrintIoDmaDescriptor( ( PCIO_DMA_DESCRIPTOR )IoDescriptor ) ) {
+ return( FALSE );
+ }
+ } else if( IoDescriptor->IsDescriptorTypeInterrupt() ) {
+ if( !PrintIoInterruptDescriptor( ( PCIO_INTERRUPT_DESCRIPTOR )IoDescriptor ) ) {
+ return( FALSE );
+ }
+ } else if( IoDescriptor->IsDescriptorTypeMemory() ) {
+ if( !PrintIoMemoryDescriptor( ( PCIO_MEMORY_DESCRIPTOR )IoDescriptor ) ) {
+ return( FALSE );
+ }
+ } else if( IoDescriptor->IsDescriptorTypePort() ) {
+ if( !PrintIoPortDescriptor( ( PCIO_PORT_DESCRIPTOR )IoDescriptor ) ) {
+ return( FALSE );
+ }
+ }
+
+ if( !PrintString( &_EmptyLine ) ) {
+ DebugPrint( "PrintString() failed \n" );
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+PRINT_MANAGER::PrintIoInterruptDescriptor(
+ IN PCIO_INTERRUPT_DESCRIPTOR Descriptor
+ )
+
+/*++
+
+Routine Description:
+
+ Print the contents of an IO_INTERRUPT_DESCRIPTOR object.
+
+
+Arguments:
+
+ Descriptor - Pointer to object to be printed.
+
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ DSTRING MinimumVectorString;
+ DSTRING MaximumVectorString;
+ DSTRING TypeString;
+
+ DSTRING AuxString;
+ WCHAR AuxNumber[19];
+ ULONG StringId;
+ PWSTRING String;
+
+ if( !MinimumVectorString.Initialize( &_IndentString ) ||
+ !MinimumVectorString.Strcat( _StringIoMinimumVector ) ||
+ !MaximumVectorString.Initialize( &_IndentString ) ||
+ !MaximumVectorString.Strcat( _StringIoMaximumVector ) ||
+ !TypeString.Initialize( &_IndentString ) ||
+ !TypeString.Strcat( _StringType )
+ ) {
+ DebugPrint( "REGEDT32: Initialization failure" );
+ return( FALSE );
+ }
+
+ //
+ // Print the type
+ //
+
+ StringId = ( Descriptor->IsInterruptLevelSensitive() )? MSG_INT_LEVEL_SENSITIVE :
+ MSG_INT_LATCHED;
+
+ String = REGEDIT_BASE_SYSTEM::QueryString( StringId, "" );
+ if( String == NULL ) {
+ DebugPrintf( "REGEDT32: Unable to retrieve string \n" );
+ return( FALSE );
+ }
+ TypeString.Strcat( String );
+ DELETE( String );
+ if( !PrintString( &TypeString ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print the minimum vector
+ //
+ wsprintf( AuxNumber, (LPWSTR)L"%#x", Descriptor->GetMinimumVector() );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ MinimumVectorString.Strcat( &AuxString );
+ if( !PrintString( &MinimumVectorString ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print the maximum vector
+ //
+ wsprintf( AuxNumber, (LPWSTR)L"%#x", Descriptor->GetMaximumVector() );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ MaximumVectorString.Strcat( &AuxString );
+ if( !PrintString( &MaximumVectorString ) ) {
+ return( FALSE );
+ }
+
+ return( TRUE );
+}
+
+
+BOOLEAN
+PRINT_MANAGER::PrintIoPortDescriptor(
+ IN PCIO_PORT_DESCRIPTOR Descriptor
+ )
+
+/*++
+
+Routine Description:
+
+ Print the contents of an IO_PORT_DESCRIPTOR object.
+
+
+Arguments:
+
+ Descriptor - Pointer to object to be printed.
+
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ DSTRING MinimumAddressString;
+ DSTRING MaximumAddressString;
+ DSTRING LengthString;
+ DSTRING AlignmentString;
+ DSTRING TypeString;
+
+ DSTRING AuxString;
+ WCHAR AuxNumber[19];
+ ULONG StringId;
+ PWSTRING String;
+
+ if( !MinimumAddressString.Initialize( &_IndentString ) ||
+ !MinimumAddressString.Strcat( _StringIoMinimumAddress ) ||
+ !MaximumAddressString.Initialize( &_IndentString ) ||
+ !MaximumAddressString.Strcat( _StringIoMaximumAddress ) ||
+ !LengthString.Initialize( &_IndentString ) ||
+ !LengthString.Strcat( _StringLength ) ||
+ !AlignmentString.Initialize( &_IndentString ) ||
+ !AlignmentString.Strcat( _StringIoAlignment ) ||
+ !TypeString.Initialize( &_IndentString ) ||
+ !TypeString.Strcat( _StringType )
+ ) {
+ DebugPrint( "REGEDT32: Initialization failure" );
+ return( FALSE );
+ }
+
+ //
+ // Print the type
+ //
+
+ StringId = ( Descriptor->IsPortMemory() )? MSG_PORT_MEMORY :
+ MSG_PORT_PORT;
+
+ String = REGEDIT_BASE_SYSTEM::QueryString( StringId, "" );
+ if( String == NULL ) {
+ DebugPrintf( "REGEDT32: Unable to retrieve string \n" );
+ return( FALSE );
+ }
+ TypeString.Strcat( String );
+ DELETE( String );
+ if( !PrintString( &TypeString ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print the length
+ //
+ wsprintf( AuxNumber, (LPWSTR)L"%#x", Descriptor->GetLength() );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ LengthString.Strcat( &AuxString );
+ if( !PrintString( &LengthString ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print the alignment
+ //
+ wsprintf( AuxNumber, (LPWSTR)L"%#x", Descriptor->GetAlignment() );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ AlignmentString.Strcat( &AuxString );
+ if( !PrintString( &AlignmentString ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print the minimum address
+ //
+ if( ( ( ( PIO_PORT_DESCRIPTOR )Descriptor )->GetMinimumAddress() )->HighPart != 0 ) {
+ wsprintf( AuxNumber,
+ (LPWSTR)L"0x%08x%08x",
+ ( ( ( PIO_PORT_DESCRIPTOR )Descriptor )->GetMinimumAddress() )->HighPart,
+ ( ( ( PIO_PORT_DESCRIPTOR )Descriptor )->GetMinimumAddress() )->LowPart );
+ } else {
+ wsprintf( AuxNumber, (LPWSTR)L"0x%08x", ( ( ( PIO_PORT_DESCRIPTOR )Descriptor )->GetMinimumAddress() )->LowPart );
+ }
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ MinimumAddressString.Strcat( &AuxString );
+ if( !PrintString( &MinimumAddressString ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print the maximum address
+ //
+ if( ( ( ( PIO_PORT_DESCRIPTOR )Descriptor )->GetMaximumAddress() )->HighPart != 0 ) {
+ wsprintf( AuxNumber,
+ (LPWSTR)L"0x%08x%08x",
+ ( ( ( PIO_PORT_DESCRIPTOR )Descriptor )->GetMaximumAddress() )->HighPart,
+ ( ( ( PIO_PORT_DESCRIPTOR )Descriptor )->GetMaximumAddress() )->LowPart );
+ } else {
+ wsprintf( AuxNumber, (LPWSTR)L"0x%08x", ( ( ( PIO_PORT_DESCRIPTOR )Descriptor )->GetMaximumAddress() )->LowPart );
+ }
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ MaximumAddressString.Strcat( &AuxString );
+ if( !PrintString( &MaximumAddressString ) ) {
+ return( FALSE );
+ }
+
+ return( TRUE );
+}
+
+
+BOOLEAN
+PRINT_MANAGER::PrintIoMemoryDescriptor(
+ IN PCIO_MEMORY_DESCRIPTOR Descriptor
+ )
+
+/*++
+
+Routine Description:
+
+ Print the contents of an IO_MEMORY_DESCRIPTOR object.
+
+
+Arguments:
+
+ Descriptor - Pointer to object to be printed.
+
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ DSTRING MinimumAddressString;
+ DSTRING MaximumAddressString;
+ DSTRING LengthString;
+ DSTRING AlignmentString;
+ DSTRING TypeString;
+
+ DSTRING AuxString;
+ WCHAR AuxNumber[19];
+ ULONG StringId;
+ PWSTRING String;
+
+ if( !MinimumAddressString.Initialize( &_IndentString ) ||
+ !MinimumAddressString.Strcat( _StringIoMinimumAddress ) ||
+ !MaximumAddressString.Initialize( &_IndentString ) ||
+ !MaximumAddressString.Strcat( _StringIoMaximumAddress ) ||
+ !LengthString.Initialize( &_IndentString ) ||
+ !LengthString.Strcat( _StringLength ) ||
+ !AlignmentString.Initialize( &_IndentString ) ||
+ !AlignmentString.Strcat( _StringIoAlignment ) ||
+ !TypeString.Initialize( &_IndentString ) ||
+ !TypeString.Strcat( _StringType )
+ ) {
+ DebugPrint( "REGEDT32: Initialization failure" );
+ return( FALSE );
+ }
+
+ //
+ // Print the type
+ //
+
+ StringId = ( Descriptor->IsMemoryReadWrite() )? MSG_MEM_READ_WRITE :
+ ( ( Descriptor->IsMemoryReadWrite() )? MSG_MEM_READ_ONLY :
+ MSG_MEM_WRITE_ONLY );
+
+ String = REGEDIT_BASE_SYSTEM::QueryString( StringId, "" );
+ if( String == NULL ) {
+ DebugPrintf( "REGEDT32: Unable to retrieve string \n" );
+ return( FALSE );
+ }
+ TypeString.Strcat( String );
+ DELETE( String );
+ if( !PrintString( &TypeString ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print the length
+ //
+ wsprintf( AuxNumber, (LPWSTR)L"%#x", Descriptor->GetLength() );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ LengthString.Strcat( &AuxString );
+ if( !PrintString( &LengthString ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print the alignment
+ //
+ wsprintf( AuxNumber, (LPWSTR)L"%#x", Descriptor->GetAlignment() );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ AlignmentString.Strcat( &AuxString );
+ if( !PrintString( &AlignmentString ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print the minimum address
+ //
+ if( ( ( ( PIO_PORT_DESCRIPTOR )Descriptor )->GetMinimumAddress() )->HighPart != 0 ) {
+ wsprintf( AuxNumber,
+ (LPWSTR)L"0x%08x%08x",
+ ( ( ( PIO_PORT_DESCRIPTOR )Descriptor )->GetMinimumAddress() )->HighPart,
+ ( ( ( PIO_PORT_DESCRIPTOR )Descriptor )->GetMinimumAddress() )->LowPart );
+ } else {
+ wsprintf( AuxNumber, (LPWSTR)L"0x%08x", ( ( ( PIO_PORT_DESCRIPTOR )Descriptor )->GetMinimumAddress() )->LowPart );
+ }
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ MinimumAddressString.Strcat( &AuxString );
+ if( !PrintString( &MinimumAddressString ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print the maximum address
+ //
+ if( ( ( ( PIO_PORT_DESCRIPTOR )Descriptor )->GetMaximumAddress() )->HighPart != 0 ) {
+ wsprintf( AuxNumber,
+ (LPWSTR)L"0x%08x%08x",
+ ( ( ( PIO_PORT_DESCRIPTOR )Descriptor )->GetMaximumAddress() )->HighPart,
+ ( ( ( PIO_PORT_DESCRIPTOR )Descriptor )->GetMaximumAddress() )->LowPart );
+ } else {
+ wsprintf( AuxNumber, (LPWSTR)L"0x%08x", ( ( ( PIO_PORT_DESCRIPTOR )Descriptor )->GetMaximumAddress() )->LowPart );
+ }
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ MaximumAddressString.Strcat( &AuxString );
+ if( !PrintString( &MaximumAddressString ) ) {
+ return( FALSE );
+ }
+
+ return( TRUE );
+}
+
+
+BOOLEAN
+PRINT_MANAGER::PrintIoDmaDescriptor(
+ IN PCIO_DMA_DESCRIPTOR Descriptor
+ )
+
+/*++
+
+Routine Description:
+
+ Print the contents of an IO_DMA_DESCRIPTOR object.
+
+
+Arguments:
+
+ Descriptor - Pointer to object to be printed.
+
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ DSTRING MinimumChannelString;
+ DSTRING MaximumChannelString;
+
+ DSTRING AuxString;
+ WCHAR AuxNumber[19];
+
+ if( !MinimumChannelString.Initialize( &_IndentString ) ||
+ !MinimumChannelString.Strcat( _StringIoMinimumChannel ) ||
+ !MaximumChannelString.Initialize( &_IndentString ) ||
+ !MaximumChannelString.Strcat( _StringIoMaximumChannel )
+ ) {
+ DebugPrint( "REGEDT32: Initialization failure" );
+ return( FALSE );
+ }
+
+ //
+ // Print the minimum channel
+ //
+ wsprintf( AuxNumber, (LPWSTR)L"%#x", Descriptor->GetMinimumChannel() );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ MinimumChannelString.Strcat( &AuxString );
+ if( !PrintString( &MinimumChannelString ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Print the maximum channel
+ //
+ wsprintf( AuxNumber, (LPWSTR)L"%#x", Descriptor->GetMaximumChannel() );
+ if( !AuxString.Initialize( AuxNumber ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+ MaximumChannelString.Strcat( &AuxString );
+ if( !PrintString( &MaximumChannelString ) ) {
+ return( FALSE );
+ }
+
+ return( TRUE );
+}
diff --git a/private/utils/regedit/src/regdata.cxx b/private/utils/regedit/src/regdata.cxx
new file mode 100644
index 000000000..5680afcac
--- /dev/null
+++ b/private/utils/regedit/src/regdata.cxx
@@ -0,0 +1,3383 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ regdata.cxx
+
+Abstract:
+
+ This module contains the definition for the REGISTRY_DATA
+ class. This class is used to display registry data of type
+ REG_RESOURCE_LIST and REG_FULL_RESOURCE_DESCRIPTOR.
+
+Author:
+
+ Jaime Sasson (jaimes) - 30-Nov-1993
+
+Environment:
+
+ Ulib, Regedit, Windows, User Mode
+
+--*/
+#include "regdata.hxx"
+#include "winapp.hxx"
+#include "dialogs.h"
+#include "regdesc.hxx"
+#include "regfdesc.hxx"
+#include "regresls.hxx"
+#include "regiodsc.hxx"
+#include "regiodls.hxx"
+#include "regioreq.hxx"
+#include "iterator.hxx"
+#include "regsys.hxx"
+#include "defmsg.h"
+
+#include <stdio.h>
+ //
+extern "C" {
+ #include "clb.h" // on \nt\private\sdktools\wintools\clb
+ //
+}
+
+//
+// Definition of the structure used to pass information
+// to the DisplayBinaryDataDialogProc
+//
+
+typedef struct _BUFFER_INFORMATION {
+ PBYTE Buffer;
+ ULONG BufferSize;
+ BOOLEAN DisplayValueType;
+ ULONG ValueType;
+ } BUFFER_INFORMATION, *PBUFFER_INFORMATION;
+
+//
+// Constants that define buffer sizes for strings that represent a DWORD
+// and a BIG_INT.
+// These constants take into consideration the trailing '0x' and the terminating NUL
+// character.
+//
+
+#define MAX_LENGTH_DWORD_STRING 1+1+8+1 // 0x12345678'\0'
+#define MAX_LENGTH_BIG_INT_STRING 1+1+16+1 // 0x1234567812345678'\0'
+
+
+DEFINE_CONSTRUCTOR( REGISTRY_DATA, OBJECT );
+
+DEFINE_CAST_MEMBER_FUNCTION( REGISTRY_DATA );
+
+
+//
+// Static data
+//
+BOOLEAN REGISTRY_DATA::_StringsInitialized = FALSE;
+PWSTRING REGISTRY_DATA::_MsgBusInternal;
+PWSTRING REGISTRY_DATA::_MsgBusIsa;
+PWSTRING REGISTRY_DATA::_MsgBusEisa;
+PWSTRING REGISTRY_DATA::_MsgBusMicroChannel;
+PWSTRING REGISTRY_DATA::_MsgBusTurboChannel;
+PWSTRING REGISTRY_DATA::_MsgBusPCIBus;
+PWSTRING REGISTRY_DATA::_MsgBusVMEBus;
+PWSTRING REGISTRY_DATA::_MsgBusNuBus;
+PWSTRING REGISTRY_DATA::_MsgBusPCMCIABus;
+PWSTRING REGISTRY_DATA::_MsgBusCBus;
+PWSTRING REGISTRY_DATA::_MsgBusMPIBus;
+PWSTRING REGISTRY_DATA::_MsgBusMPSABus;
+PWSTRING REGISTRY_DATA::_MsgInvalid;
+PWSTRING REGISTRY_DATA::_MsgDevPort;
+PWSTRING REGISTRY_DATA::_MsgDevInterrupt;
+PWSTRING REGISTRY_DATA::_MsgDevMemory;
+PWSTRING REGISTRY_DATA::_MsgDevDma;
+#if 0
+PWSTRING REGISTRY_DATA::_MsgDevDeviceSpecific;
+#endif
+PWSTRING REGISTRY_DATA::_MsgIntLevelSensitive;
+PWSTRING REGISTRY_DATA::_MsgIntLatched;
+PWSTRING REGISTRY_DATA::_MsgMemReadWrite;
+PWSTRING REGISTRY_DATA::_MsgMemReadOnly;
+PWSTRING REGISTRY_DATA::_MsgMemWriteOnly;
+PWSTRING REGISTRY_DATA::_MsgPortMemory;
+PWSTRING REGISTRY_DATA::_MsgPortPort;
+PWSTRING REGISTRY_DATA::_MsgShareUndetermined;
+PWSTRING REGISTRY_DATA::_MsgShareDeviceExclusive;
+PWSTRING REGISTRY_DATA::_MsgShareDriverExclusive;
+PWSTRING REGISTRY_DATA::_MsgShareShared;
+
+
+
+BOOLEAN
+REGISTRY_DATA::InitializeStrings(
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize all strings used by this class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the initialization succeeds.
+
+--*/
+
+{
+ _MsgBusInternal = REGEDIT_BASE_SYSTEM::QueryString( MSG_BUS_INTERNAL, "" );
+ _MsgBusIsa = REGEDIT_BASE_SYSTEM::QueryString( MSG_BUS_ISA, "" );
+ _MsgBusEisa = REGEDIT_BASE_SYSTEM::QueryString( MSG_BUS_EISA, "" );
+ _MsgBusMicroChannel = REGEDIT_BASE_SYSTEM::QueryString( MSG_BUS_MICRO_CHANNEL, "" );
+ _MsgBusTurboChannel = REGEDIT_BASE_SYSTEM::QueryString( MSG_BUS_TURBO_CHANNEL, "" );
+ _MsgBusPCIBus = REGEDIT_BASE_SYSTEM::QueryString( MSG_BUS_PCI_BUS, "" );
+ _MsgBusVMEBus = REGEDIT_BASE_SYSTEM::QueryString( MSG_BUS_VME_BUS, "" );
+ _MsgBusNuBus = REGEDIT_BASE_SYSTEM::QueryString( MSG_BUS_NU_BUS, "" );
+ _MsgBusPCMCIABus = REGEDIT_BASE_SYSTEM::QueryString( MSG_BUS_PCMCIA_BUS, "" );
+ _MsgBusCBus = REGEDIT_BASE_SYSTEM::QueryString( MSG_BUS_C_BUS, "" );
+ _MsgBusMPIBus = REGEDIT_BASE_SYSTEM::QueryString( MSG_BUS_MPI_BUS, "" );
+ _MsgBusMPSABus = REGEDIT_BASE_SYSTEM::QueryString( MSG_BUS_MPSA_BUS, "" );
+ _MsgInvalid = REGEDIT_BASE_SYSTEM::QueryString( MSG_INVALID, "" );
+ _MsgDevPort = REGEDIT_BASE_SYSTEM::QueryString( MSG_DEV_PORT, "" );
+ _MsgDevInterrupt = REGEDIT_BASE_SYSTEM::QueryString( MSG_DEV_INTERRUPT, "" );
+ _MsgDevMemory = REGEDIT_BASE_SYSTEM::QueryString( MSG_DEV_MEMORY, "" );
+ _MsgDevDma = REGEDIT_BASE_SYSTEM::QueryString( MSG_DEV_DMA, "" );
+#if 0
+ _MsgDevDeviceSpecific = REGEDIT_BASE_SYSTEM::QueryString( , "" );
+#endif
+ _MsgIntLevelSensitive = REGEDIT_BASE_SYSTEM::QueryString( MSG_INT_LEVEL_SENSITIVE, "" );
+ _MsgIntLatched = REGEDIT_BASE_SYSTEM::QueryString( MSG_INT_LATCHED, "" );
+ _MsgMemReadWrite = REGEDIT_BASE_SYSTEM::QueryString( MSG_MEM_READ_WRITE, "" );
+ _MsgMemReadOnly = REGEDIT_BASE_SYSTEM::QueryString( MSG_MEM_READ_ONLY, "" );
+ _MsgMemWriteOnly = REGEDIT_BASE_SYSTEM::QueryString( MSG_MEM_WRITE_ONLY, "" );
+ _MsgPortMemory = REGEDIT_BASE_SYSTEM::QueryString( MSG_PORT_MEMORY, "" );
+ _MsgPortPort = REGEDIT_BASE_SYSTEM::QueryString( MSG_PORT_PORT, "" );
+ _MsgShareUndetermined = REGEDIT_BASE_SYSTEM::QueryString( MSG_SHARE_UNDETERMINED, "" );
+ _MsgShareDeviceExclusive = REGEDIT_BASE_SYSTEM::QueryString( MSG_SHARE_DEVICE_EXCLUSIVE, "" );
+ _MsgShareDriverExclusive = REGEDIT_BASE_SYSTEM::QueryString( MSG_SHARE_DRIVER_EXCLUSIVE, "" );
+ _MsgShareShared = REGEDIT_BASE_SYSTEM::QueryString( MSG_SHARE_SHARED, "" );
+
+ if ( ( _MsgBusInternal == NULL ) ||
+ ( _MsgBusIsa == NULL ) ||
+ ( _MsgBusEisa == NULL ) ||
+ ( _MsgBusMicroChannel == NULL ) ||
+ ( _MsgBusTurboChannel == NULL ) ||
+ ( _MsgBusPCIBus == NULL ) ||
+ ( _MsgBusVMEBus == NULL ) ||
+ ( _MsgBusNuBus == NULL ) ||
+ ( _MsgBusPCMCIABus == NULL ) ||
+ ( _MsgBusCBus == NULL ) ||
+ ( _MsgBusMPIBus == NULL ) ||
+ ( _MsgBusMPSABus == NULL ) ||
+ ( _MsgInvalid == NULL ) ||
+ ( _MsgDevPort == NULL ) ||
+ ( _MsgDevInterrupt == NULL ) ||
+ ( _MsgDevMemory == NULL ) ||
+ ( _MsgDevDma == NULL ) ||
+#if 0
+ ( _MsgDevDeviceSpecific == NULL ) ||
+#endif
+ ( _MsgIntLevelSensitive == NULL ) ||
+ ( _MsgIntLatched == NULL ) ||
+ ( _MsgMemReadWrite == NULL ) ||
+ ( _MsgMemReadOnly == NULL ) ||
+ ( _MsgMemWriteOnly == NULL ) ||
+ ( _MsgPortMemory == NULL ) ||
+ ( _MsgPortPort == NULL ) ||
+ ( _MsgShareUndetermined == NULL ) ||
+ ( _MsgShareDeviceExclusive == NULL ) ||
+ ( _MsgShareDriverExclusive == NULL ) ||
+ ( _MsgShareShared == NULL )
+ ) {
+
+ DELETE( _MsgBusInternal );
+ DELETE( _MsgBusIsa );
+ DELETE( _MsgBusEisa );
+ DELETE( _MsgBusMicroChannel );
+ DELETE( _MsgBusTurboChannel );
+ DELETE( _MsgBusPCIBus );
+ DELETE( _MsgBusVMEBus );
+ DELETE( _MsgBusNuBus );
+ DELETE( _MsgBusPCMCIABus );
+ DELETE( _MsgBusCBus );
+ DELETE( _MsgBusMPIBus );
+ DELETE( _MsgBusMPSABus );
+ DELETE( _MsgInvalid );
+ DELETE( _MsgDevPort );
+ DELETE( _MsgDevInterrupt );
+ DELETE( _MsgDevMemory );
+ DELETE( _MsgDevDma );
+#if 0
+ DELETE( _MsgDevDeviceSpecific );
+#endif
+ DELETE( _MsgIntLevelSensitive );
+ DELETE( _MsgIntLatched );
+ DELETE( _MsgMemReadWrite );
+ DELETE( _MsgMemReadOnly );
+ DELETE( _MsgMemWriteOnly );
+ DELETE( _MsgPortMemory );
+ DELETE( _MsgPortPort );
+ DELETE( _MsgShareUndetermined );
+ DELETE( _MsgShareDeviceExclusive );
+ DELETE( _MsgShareDriverExclusive );
+ DELETE( _MsgShareShared );
+
+ DebugPrintf( "REGEDT32: Unable to initialize strings on REGISTRY_DATA \n" );
+ _StringsInitialized = FALSE;
+ } else {
+ _StringsInitialized = TRUE;
+ }
+ return( _StringsInitialized );
+}
+
+
+VOID
+REGISTRY_DATA::DisplayData(
+ IN HWND hWnd,
+ IN REG_TYPE Type,
+ IN PCBYTE Buffer,
+ IN ULONG Size,
+ IN BOOLEAN ForceDisplayBinary
+ )
+
+/*++
+
+Routine Description:
+
+ Invoke the appropriate dialog that displays registry data of type
+ REG_RESOURCE_LIST and REG_FULL_RESOURCE_DESCRIPTOR.
+
+Arguments:
+
+ hWnd - A handle to the owner window.
+
+ DataType - Indicates the type of the data to be displayed.
+
+ Buffer - Contains the data to be displayed.
+
+ Size - Size of the data to be displayed.
+
+ ForceDisplayBinary - Indicates whether or not the data should be
+ displayed as binary data, independently of
+ the value type.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ FULL_DESCRIPTOR FullDescriptor;
+ RESOURCE_LIST ResourceList;
+ IO_REQUIREMENTS_LIST RequirementsList;
+
+ if( !_StringsInitialized ) {
+ if( !InitializeStrings() ) {
+ return;
+ }
+ }
+
+ if( !ForceDisplayBinary ) {
+ switch( Type ) {
+
+ case TYPE_REG_RESOURCE_LIST:
+
+ if( ResourceList.Initialize( Buffer, Size ) ) {
+#if DBG
+ //
+ // For debug only. Comment it out before check in.
+ //
+ // ResourceList.DbgDumpObject();
+ //
+#endif
+ DisplayResourceList( hWnd, &ResourceList );
+ }
+ break;
+
+ case TYPE_REG_FULL_RESOURCE_DESCRIPTOR:
+
+ if( FullDescriptor.Initialize( Buffer, Size ) ) {
+#if DBG
+ //
+ // For debug only. Comment it out before check in.
+ //
+ // FullDescriptor.DbgDumpObject();
+ //
+#endif
+ DisplayFullResourceDescriptor( hWnd, &FullDescriptor );
+ }
+ break;
+
+ case TYPE_REG_RESOURCE_REQUIREMENTS_LIST:
+
+ if( RequirementsList.Initialize( Buffer, Size ) ) {
+#if DBG
+ //
+ // For debug only. Comment it out before check in.
+ //
+ // RequirementsList.DbgDumpObject();
+ //
+#endif
+ DisplayRequirementsList( hWnd, &RequirementsList );
+ }
+ break;
+
+ case TYPE_REG_BINARY:
+
+ DisplayBinaryData( hWnd, Buffer, Size );
+ break;
+ }
+ } else {
+ DisplayBinaryData( hWnd, Buffer, Size, TRUE, ( ULONG )Type );
+ }
+}
+
+
+VOID
+REGISTRY_DATA::DisplayResourceList(
+ IN HWND hWnd,
+ IN PCRESOURCE_LIST ResourceList
+ )
+
+/*++
+
+Routine Description:
+
+ Invoke the dialog that displays registry data of type
+ REG_RESOURCE_LIST .
+
+Arguments:
+
+ hWnd - A handle to the owner window.
+
+ ResourceList - Pointer to a RESOURCE_LIST object to be displayed.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DialogBoxParam( (HINSTANCE)WINDOWS_APPLICATION::QueryInstance(),
+ MAKEINTRESOURCE( IDD_RESOURCE_LIST ),
+ hWnd,
+ ( DLGPROC )REGISTRY_DATA::DisplayResourceListDialogProc,
+ ( DWORD ) ResourceList );
+}
+
+
+VOID
+REGISTRY_DATA::DisplayFullResourceDescriptor(
+ IN HWND hWnd,
+ IN PCFULL_DESCRIPTOR FullDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ Invoke the dialog that displays registry data of type
+ REG_FULL_RESOURCE_DESCRIPTOR.
+
+Arguments:
+
+ hWnd - A handle to the owner window.
+
+ FullDescriptor - Pointer to a FULL_DESCRIPTOR object to be displayed.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DialogBoxParam( (HINSTANCE)WINDOWS_APPLICATION::QueryInstance( ),
+ MAKEINTRESOURCE(IDD_FULL_RES_DESCRIPTOR),
+ hWnd,
+ ( DLGPROC )REGISTRY_DATA::DisplayFullResourceDescriptorDialogProc,
+ ( DWORD ) FullDescriptor );
+}
+
+
+VOID
+REGISTRY_DATA::DisplayRequirementsList(
+ IN HWND hWnd,
+ IN PCIO_REQUIREMENTS_LIST RequirementsList
+ )
+
+/*++
+
+Routine Description:
+
+ Invoke the dialog that displays registry data of type
+ REG_IO_RESOURCE_REQUIREMENTS_LIST.
+
+Arguments:
+
+ hWnd - A handle to the owner window.
+
+ FullDescriptor - Pointer to an IO_REQUIREMENTS_LIST object to be displayed.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DialogBoxParam( (HINSTANCE)WINDOWS_APPLICATION::QueryInstance( ),
+ MAKEINTRESOURCE(IDD_IO_REQUIREMENTS_LIST),
+ hWnd,
+ ( DLGPROC )REGISTRY_DATA::DisplayRequirementsListDialogProc,
+ ( DWORD ) RequirementsList );
+}
+
+
+VOID
+REGISTRY_DATA::DisplayIoDescriptor(
+ IN HWND hWnd,
+ IN PCIO_DESCRIPTOR IoDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ Invoke appropriate that displays a Port, Memory, Interrupt or DMA,
+ depending on the type of the object received as parameter.
+
+Arguments:
+
+ hWnd - A handle to the owner window.
+
+ IoDescriptor - Pointer to the object to be displayed.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DLGPROC Pointer;
+ LPCWSTR Template;
+
+ if( IoDescriptor->IsDescriptorTypePort() ) {
+ Pointer = ( DLGPROC )REGISTRY_DATA::DisplayIoPortDialogProc;
+ Template = MAKEINTRESOURCE(IDD_IO_PORT_RESOURCE);
+ } else if( IoDescriptor->IsDescriptorTypeMemory() ) {
+ Pointer = ( DLGPROC )REGISTRY_DATA::DisplayIoMemoryDialogProc;
+ Template = MAKEINTRESOURCE(IDD_IO_MEMORY_RESOURCE);
+ } else if( IoDescriptor->IsDescriptorTypeInterrupt() ) {
+ Pointer = ( DLGPROC )REGISTRY_DATA::DisplayIoInterruptDialogProc;
+ Template = MAKEINTRESOURCE(IDD_IO_INTERRUPT_RESOURCE);
+ } else if( IoDescriptor->IsDescriptorTypeDma() ) {
+ Pointer = ( DLGPROC )REGISTRY_DATA::DisplayIoDmaDialogProc;
+ Template = MAKEINTRESOURCE(IDD_IO_DMA_RESOURCE);
+ } else {
+ Pointer = NULL;
+ }
+
+ if( Pointer != NULL ) {
+ DialogBoxParam( (HINSTANCE)WINDOWS_APPLICATION::QueryInstance( ),
+ Template,
+ hWnd,
+ Pointer,
+ ( DWORD ) IoDescriptor );
+ }
+}
+
+
+
+
+
+BOOL
+APIENTRY
+REGISTRY_DATA::DisplayResourceListDialogProc(
+ HWND hDlg,
+ DWORD Msg,
+ WPARAM wParam,
+ LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ The dialog proceedure for displaying data of type REG_RESOURCE_LIST.
+
+Arguments:
+
+ hDlg - a handle to the dialog proceedure.
+
+ Msg - the message passed from Windows.
+
+ wParam - extra message dependent data.
+
+ lParam - extra message dependent data.
+
+
+Return Value:
+
+ BOOL - Standard return code for dialog procedures.
+
+--*/
+
+{
+
+ switch( Msg ) {
+
+ case WM_INITDIALOG:
+ {
+ LPCWSTR InterfaceString;
+ ULONG StringSize;
+ PCRESOURCE_LIST ResourceList;
+ WCHAR BusNumber[ MAX_LENGTH_DWORD_STRING ];
+ PARRAY Descriptors;
+ PITERATOR Iterator;
+ PCFULL_DESCRIPTOR FullResourceDescriptor;
+
+ CLB_ROW ClbRow;
+ CLB_STRING ClbString[ ] = {
+ { BusNumber, 0, CLB_LEFT, NULL },
+ { NULL, 0, CLB_LEFT, NULL }
+ };
+
+ ULONG Widths[] = {
+ 14,
+ ( ULONG ) -1
+ };
+
+ if( ( ( ResourceList = ( PCRESOURCE_LIST )lParam ) == NULL ) ||
+ ( ( Descriptors = ResourceList->GetFullResourceDescriptors() ) == NULL ) ||
+ ( ( Iterator = Descriptors->QueryIterator() ) == NULL ) ) {
+ EndDialog( hDlg, 0 );
+ return( TRUE );
+ }
+
+ ClbSetColumnWidths( hDlg,
+ IDC_LIST_RESOURCE_LISTS,
+ Widths );
+
+ while( ( FullResourceDescriptor = ( PCFULL_DESCRIPTOR )Iterator->GetNext() ) != NULL ) {
+ switch( FullResourceDescriptor->GetInterfaceType() ) {
+
+ case Internal:
+
+ InterfaceString = _MsgBusInternal->GetWSTR();
+ StringSize = _MsgBusInternal->QueryChCount();
+ break;
+
+ case Isa:
+
+ InterfaceString = _MsgBusIsa->GetWSTR();
+ StringSize = _MsgBusIsa->QueryChCount();
+ break;
+
+ case Eisa:
+
+ InterfaceString = _MsgBusEisa->GetWSTR();
+ StringSize = _MsgBusEisa->QueryChCount();
+ break;
+
+ case MicroChannel:
+
+ InterfaceString = _MsgBusMicroChannel->GetWSTR();
+ StringSize = _MsgBusMicroChannel->QueryChCount();
+ break;
+
+ case TurboChannel:
+
+ InterfaceString = _MsgBusTurboChannel->GetWSTR();
+ StringSize = _MsgBusTurboChannel->QueryChCount();
+ break;
+
+ case PCIBus:
+
+ InterfaceString = _MsgBusPCIBus->GetWSTR();
+ StringSize = _MsgBusPCIBus->QueryChCount();
+ break;
+
+ case VMEBus:
+
+ InterfaceString = _MsgBusVMEBus->GetWSTR();
+ StringSize = _MsgBusVMEBus->QueryChCount();
+ break;
+
+ case NuBus:
+
+ InterfaceString = _MsgBusNuBus->GetWSTR();
+ StringSize = _MsgBusNuBus->QueryChCount();
+ break;
+
+ case PCMCIABus:
+
+ InterfaceString = _MsgBusPCMCIABus->GetWSTR();
+ StringSize = _MsgBusPCMCIABus->QueryChCount();
+ break;
+
+ case CBus:
+
+ InterfaceString = _MsgBusCBus->GetWSTR();
+ StringSize = _MsgBusCBus->QueryChCount();
+ break;
+
+ case MPIBus:
+
+ InterfaceString = _MsgBusMPIBus->GetWSTR();
+ StringSize = _MsgBusMPIBus->QueryChCount();
+ break;
+
+ case MPSABus:
+
+ InterfaceString = _MsgBusMPSABus->GetWSTR();
+ StringSize = _MsgBusMPSABus->QueryChCount();
+ break;
+
+ default:
+
+ InterfaceString = _MsgInvalid->GetWSTR();
+ StringSize = _MsgInvalid->QueryChCount();
+ break;
+ }
+
+ swprintf( BusNumber, ( LPWSTR )L"%d", FullResourceDescriptor->GetBusNumber() );
+
+ ClbString[ 0 ].Length = wcslen( BusNumber );
+ ClbString[ 0 ].Format = CLB_LEFT;
+ ClbString[ 1 ].String = ( LPWSTR )InterfaceString;
+ ClbString[ 1 ].Format = CLB_LEFT;
+ ClbString[ 1 ].Length = StringSize;
+
+ ClbRow.Count = 2;
+ ClbRow.Strings = ClbString;
+ ClbRow.Data = ( PVOID )FullResourceDescriptor;
+
+ ClbAddData( hDlg,
+ IDC_LIST_RESOURCE_LISTS,
+ &ClbRow );
+
+ }
+ DELETE( Iterator );
+ //
+ // Disble the Display button
+ //
+ EnableWindow( GetDlgItem( hDlg, IDC_PUSH_DISPLAY_RESOURCES ), FALSE );
+ return( TRUE );
+ }
+
+ case WM_COMPAREITEM:
+ {
+ LPCOMPAREITEMSTRUCT lpcis;
+ LPCLB_ROW ClbRow1;
+ LPCLB_ROW ClbRow2;
+ LONG Compare;
+
+ PCFULL_DESCRIPTOR FullDescriptor1;
+ PCFULL_DESCRIPTOR FullDescriptor2;
+
+ PWSTR String1;
+ PWSTR String2;
+
+ lpcis = ( LPCOMPAREITEMSTRUCT ) lParam;
+ DebugAssert( lpcis->CtlType == ODT_LISTBOX );
+
+ //
+ // Extract the rows to be compared.
+ // First compare by bus number, and if they
+ // are equal, compare by interface type
+ //
+
+ ClbRow1 = ( LPCLB_ROW ) lpcis->itemData1;
+ ClbRow2 = ( LPCLB_ROW ) lpcis->itemData2;
+
+ FullDescriptor1 = ( PCFULL_DESCRIPTOR )ClbRow1->Data;
+ FullDescriptor2 = ( PCFULL_DESCRIPTOR )ClbRow2->Data;
+
+ Compare = FullDescriptor1->GetBusNumber() -
+ FullDescriptor2->GetBusNumber();
+
+ if( Compare == 0 ) {
+ String1 = ClbRow1->Strings[1].String;
+ String2 = ClbRow2->Strings[1].String;
+ Compare = wcscmp( String1, String2 );
+ }
+
+ return Compare;
+ }
+
+ case WM_COMMAND:
+
+ switch( LOWORD( wParam ) ) {
+
+ case IDOK:
+ case IDCANCEL:
+
+ EndDialog( hDlg, TRUE );
+ return( TRUE );
+
+ case IDC_LIST_RESOURCE_LISTS:
+ {
+
+ switch( HIWORD( wParam )) {
+
+ case LBN_SELCHANGE:
+ {
+
+ //
+ // Enable the display drive details button
+ //
+
+ EnableWindow( GetDlgItem( hDlg, IDC_PUSH_DISPLAY_RESOURCES ),
+ TRUE );
+ return 0;
+ }
+
+ case LBN_DBLCLK:
+ {
+
+ //
+ // Simulate that the details button was pushed
+ //
+
+ SendMessage( hDlg,
+ WM_COMMAND,
+ MAKEWPARAM( IDC_PUSH_DISPLAY_RESOURCES, BN_CLICKED ),
+ ( LPARAM ) GetDlgItem( hDlg, IDC_PUSH_DISPLAY_RESOURCES ) );
+ return 0;
+ }
+ }
+ break;
+ }
+
+ case IDC_PUSH_DISPLAY_RESOURCES:
+ {
+ PCFULL_DESCRIPTOR FullDescriptor;
+
+ FullDescriptor = ( PCFULL_DESCRIPTOR )( GetSelectedItem ( hDlg, IDC_LIST_RESOURCE_LISTS ) );
+ if( FullDescriptor != NULL ) {
+ DisplayFullResourceDescriptor( hDlg, FullDescriptor );
+ }
+ return( TRUE );
+ }
+ }
+ }
+ return( FALSE );
+}
+
+
+
+BOOL
+APIENTRY
+REGISTRY_DATA::DisplayFullResourceDescriptorDialogProc(
+ HWND hDlg,
+ DWORD Msg,
+ WPARAM wParam,
+ LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ The dialog proceedure for displaying data of type REG_FULL_RESOURCE_DESCRIPTOR.
+
+Arguments:
+
+ hDlg - a handle to the dialog proceedure.
+
+ Msg - the message passed from Windows.
+
+ wParam - extra message dependent data.
+
+ lParam - extra message dependent data.
+
+
+Return Value:
+
+ BOOL - Standard return code for dialog procedures.
+
+--*/
+
+{
+ PCBYTE Pointer;
+ ULONG Size;
+ STATIC PCDEVICE_SPECIFIC_DESCRIPTOR LastSelectedDevSpecific;
+
+ switch( Msg ) {
+
+ case WM_INITDIALOG:
+ {
+ LPCWSTR InterfaceString;
+ WCHAR BusNumber[ MAX_LENGTH_DWORD_STRING ];
+ PARRAY PartialDescriptors;
+ PITERATOR Iterator;
+ PCFULL_DESCRIPTOR FullResourceDescriptor;
+ PCPARTIAL_DESCRIPTOR PartialDescriptor;
+ PCPORT_DESCRIPTOR Port;
+ PCINTERRUPT_DESCRIPTOR Interrupt;
+ PCMEMORY_DESCRIPTOR Memory;
+ PCDMA_DESCRIPTOR Dma;
+ PCDEVICE_SPECIFIC_DESCRIPTOR DeviceSpecific;
+
+ CLB_ROW ClbRow;
+ CLB_STRING ClbString[ ] = {
+ { NULL, 0, CLB_LEFT, NULL },
+ { NULL, 0, CLB_LEFT, NULL },
+ { NULL, 0, CLB_LEFT, NULL },
+ { NULL, 0, CLB_LEFT, NULL }
+ };
+
+ WCHAR PortAddressString[ MAX_LENGTH_BIG_INT_STRING ];
+ WCHAR PortLengthString[ MAX_LENGTH_DWORD_STRING ];
+ PCWSTRING PortType;
+
+ WCHAR InterruptVectorString[ MAX_LENGTH_DWORD_STRING ];
+ WCHAR InterruptLevelString[ MAX_LENGTH_DWORD_STRING ];
+ WCHAR InterruptAffinityString[ MAX_LENGTH_DWORD_STRING ];
+ PCWSTRING InterruptType;
+
+ WCHAR MemoryAddressString[ MAX_LENGTH_BIG_INT_STRING ];
+ WCHAR MemoryLengthString[ MAX_LENGTH_DWORD_STRING ];
+ PCWSTRING MemoryAccess;
+
+ WCHAR DmaChannelString[ MAX_LENGTH_DWORD_STRING ];
+ WCHAR DmaPortString[ MAX_LENGTH_DWORD_STRING ];
+
+ WCHAR Reserved1String[ MAX_LENGTH_DWORD_STRING ];
+ WCHAR Reserved2String[ MAX_LENGTH_DWORD_STRING ];
+ WCHAR DataSizeString[ MAX_LENGTH_DWORD_STRING ];
+ PCBYTE AuxPointer;
+
+ LastSelectedDevSpecific = NULL;
+
+ if( ( FullResourceDescriptor = ( PCFULL_DESCRIPTOR )lParam ) == NULL ) {
+ EndDialog( hDlg, 0 );
+ return( TRUE );
+ }
+
+ //
+ // Write the interface type
+ //
+ switch( FullResourceDescriptor->GetInterfaceType() ) {
+
+ case Internal:
+
+ InterfaceString = _MsgBusInternal->GetWSTR();
+ break;
+
+ case Isa:
+
+ InterfaceString = _MsgBusIsa->GetWSTR();
+ break;
+
+ case Eisa:
+
+ InterfaceString = _MsgBusEisa->GetWSTR();
+ break;
+
+ case MicroChannel:
+
+ InterfaceString = _MsgBusMicroChannel->GetWSTR();
+ break;
+
+ case TurboChannel:
+
+ InterfaceString = _MsgBusTurboChannel->GetWSTR();
+ break;
+
+ case PCIBus:
+
+ InterfaceString = _MsgBusPCIBus->GetWSTR();
+ break;
+
+ case VMEBus:
+
+ InterfaceString = _MsgBusVMEBus->GetWSTR();
+ break;
+
+ case NuBus:
+
+ InterfaceString = _MsgBusNuBus->GetWSTR();
+ break;
+
+ case PCMCIABus:
+
+ InterfaceString = _MsgBusPCMCIABus->GetWSTR();
+ break;
+
+ case CBus:
+
+ InterfaceString = _MsgBusCBus->GetWSTR();
+ break;
+
+ case MPIBus:
+
+ InterfaceString = _MsgBusMPIBus->GetWSTR();
+ break;
+
+ case MPSABus:
+
+ InterfaceString = _MsgBusMPSABus->GetWSTR();
+ break;
+
+ default:
+
+ InterfaceString = _MsgInvalid->GetWSTR();
+ break;
+ }
+
+ SendDlgItemMessage( hDlg,
+ IDC_FULL_RES_TEXT_INTERFACE_TYPE,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM )InterfaceString );
+
+ //
+ // Write the bus number
+ //
+ swprintf( BusNumber, ( LPWSTR )L"%d", FullResourceDescriptor->GetBusNumber() );
+
+ SendDlgItemMessage( hDlg,
+ IDC_FULL_RES_TEXT_BUS_NUMBER,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM )BusNumber );
+
+ //
+ // Write the version and revision
+ //
+
+ swprintf( BusNumber, ( LPWSTR )L"%d", FullResourceDescriptor->GetVersion() );
+
+ SendDlgItemMessage( hDlg,
+ IDC_FULL_RES_TEXT_VERSION,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM )BusNumber );
+
+ swprintf( BusNumber, ( LPWSTR )L"%d", FullResourceDescriptor->GetRevision() );
+
+ SendDlgItemMessage( hDlg,
+ IDC_FULL_RES_TEXT_REVISION,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM )BusNumber );
+
+
+
+ //
+ // Write partial descriptors
+ //
+ if( ( ( PartialDescriptors = FullResourceDescriptor->GetResourceDescriptors() ) == NULL ) ||
+ ( ( Iterator = PartialDescriptors->QueryIterator() ) == NULL ) ) {
+ EndDialog( hDlg, 0 );
+ return( TRUE );
+ }
+
+
+ ClbRow.Strings = ClbString;
+ while( ( PartialDescriptor = ( PCPARTIAL_DESCRIPTOR )Iterator->GetNext() ) != NULL ) {
+
+ ClbRow.Data = ( PVOID )PartialDescriptor;
+ if( PartialDescriptor->IsDescriptorTypePort() ) {
+ Port = ( PCPORT_DESCRIPTOR )PartialDescriptor;
+ if( ( ( ( PPORT_DESCRIPTOR )Port )->GetPhysicalAddress() )->HighPart != 0 ) {
+ swprintf( PortAddressString,
+ ( LPWSTR )L"0x%08x%08x",
+ ( ( ( PPORT_DESCRIPTOR )Port )->GetPhysicalAddress() )->HighPart,
+ ( ( ( PPORT_DESCRIPTOR )Port )->GetPhysicalAddress() )->LowPart );
+ } else {
+ swprintf( PortAddressString,
+ ( LPWSTR )L"0x%08x",
+ ( ( ( PPORT_DESCRIPTOR )Port )->GetPhysicalAddress() )->LowPart );
+ }
+ swprintf( PortLengthString,
+ ( LPWSTR )L"%#x",
+ Port->GetLength() );
+
+ ClbString[ 0 ].String = ( LPWSTR )PortAddressString;
+ ClbString[ 0 ].Format = CLB_LEFT;
+ ClbString[ 0 ].Length = wcslen( PortAddressString );
+ ClbString[ 1 ].String = ( LPWSTR )PortLengthString;
+ ClbString[ 1 ].Format = CLB_LEFT;
+ ClbString[ 1 ].Length = wcslen( PortLengthString );
+ if( Port->IsPortMemory() ) {
+ PortType = _MsgPortMemory;
+ } else {
+ PortType = _MsgPortPort;
+ }
+ ClbString[ 2 ].String = ( LPWSTR )PortType->GetWSTR();
+ ClbString[ 2 ].Format = CLB_LEFT;
+ ClbString[ 2 ].Length = PortType->QueryChCount();
+
+ ClbRow.Count = 3;
+
+ ClbAddData( hDlg,
+ IDC_FULL_RES_LIST_PORTS,
+ &ClbRow );
+
+ } else if( PartialDescriptor->IsDescriptorTypeInterrupt() ) {
+ Interrupt = ( PCINTERRUPT_DESCRIPTOR )PartialDescriptor;
+ swprintf( InterruptVectorString,
+ ( LPWSTR )L"%d",
+ Interrupt->GetVector() );
+ swprintf( InterruptLevelString,
+ ( LPWSTR )L"%d",
+ Interrupt->GetLevel() );
+ swprintf( InterruptAffinityString,
+ ( LPWSTR )L"0x%08x",
+ Interrupt->GetAffinity() );
+
+ ClbString[ 0 ].String = ( LPWSTR )InterruptVectorString;
+ ClbString[ 0 ].Length = wcslen( InterruptVectorString );
+ ClbString[ 0 ].Format = CLB_LEFT;
+ ClbString[ 1 ].String = ( LPWSTR )InterruptLevelString;
+ ClbString[ 1 ].Format = CLB_LEFT;
+ ClbString[ 1 ].Length = wcslen( InterruptLevelString );
+ ClbString[ 2 ].String = ( LPWSTR )InterruptAffinityString;
+ ClbString[ 2 ].Format = CLB_LEFT;
+ ClbString[ 2 ].Length = wcslen( InterruptAffinityString );
+ if( Interrupt->IsInterruptLatched() ) {
+ InterruptType = _MsgIntLatched;
+ } else {
+ InterruptType = _MsgIntLevelSensitive;
+ }
+ ClbString[ 3 ].String = ( LPWSTR )InterruptType->GetWSTR();
+ ClbString[ 3 ].Format = CLB_LEFT;
+ ClbString[ 3 ].Length = InterruptType->QueryChCount();
+
+ ClbRow.Count = 4;
+
+ ClbAddData( hDlg,
+ IDC_FULL_RES_LIST_INTERRUPTS,
+ &ClbRow );
+
+ } else if( PartialDescriptor->IsDescriptorTypeMemory() ) {
+ Memory = ( PCMEMORY_DESCRIPTOR )PartialDescriptor;
+ if( ( ( ( PMEMORY_DESCRIPTOR )Memory )->GetStartAddress() )->HighPart != 0 ) {
+ swprintf( MemoryAddressString,
+ ( LPWSTR )L"%#08x%08x",
+ ( ( ( PMEMORY_DESCRIPTOR )Memory )->GetStartAddress() )->HighPart,
+ ( ( ( PMEMORY_DESCRIPTOR )Memory )->GetStartAddress() )->LowPart );
+ } else {
+ swprintf( MemoryAddressString,
+ ( LPWSTR )L"%#08x",
+ ( ( ( PMEMORY_DESCRIPTOR )Memory )->GetStartAddress() )->LowPart );
+ }
+ swprintf( MemoryLengthString,
+ ( LPWSTR )L"%#x",
+ Memory->GetLength() );
+
+ ClbString[ 0 ].String = ( LPWSTR )MemoryAddressString;
+ ClbString[ 0 ].Length = wcslen( MemoryAddressString );
+ ClbString[ 0 ].Format = CLB_LEFT;
+ ClbString[ 1 ].String = ( LPWSTR )MemoryLengthString;
+ ClbString[ 1 ].Format = CLB_LEFT;
+ ClbString[ 1 ].Length = wcslen( MemoryLengthString );
+ if( Memory->IsMemoryReadWrite() ) {
+ MemoryAccess = _MsgMemReadWrite;
+ } else if( Memory->IsMemoryReadOnly() ){
+ MemoryAccess = _MsgMemReadOnly;
+ } else {
+ MemoryAccess = _MsgMemWriteOnly;
+ }
+ ClbString[ 2 ].String = ( LPWSTR )MemoryAccess->GetWSTR();
+ ClbString[ 2 ].Format = CLB_LEFT;
+ ClbString[ 2 ].Length = MemoryAccess->QueryChCount();
+
+ ClbRow.Count = 3;
+
+ ClbAddData( hDlg,
+ IDC_FULL_RES_LIST_MEMORY,
+ &ClbRow );
+
+ } else if( PartialDescriptor->IsDescriptorTypeDma() ) {
+ Dma = ( PDMA_DESCRIPTOR )PartialDescriptor;
+ swprintf( DmaChannelString,
+ ( LPWSTR )L"%d",
+ Dma->GetChannel() );
+ swprintf( DmaPortString,
+ ( LPWSTR )L"%d",
+ Dma->GetPort() );
+
+ ClbString[ 0 ].String = ( LPWSTR )DmaChannelString;
+ ClbString[ 0 ].Length = wcslen( DmaChannelString );
+ ClbString[ 0 ].Format = CLB_LEFT;
+ ClbString[ 1 ].String = ( LPWSTR )DmaPortString;
+ ClbString[ 1 ].Format = CLB_LEFT;
+ ClbString[ 1 ].Length = wcslen( DmaPortString );
+
+ ClbRow.Count = 2;
+
+ ClbAddData( hDlg,
+ IDC_FULL_RES_LIST_DMA,
+ &ClbRow );
+
+ } else if( PartialDescriptor->IsDescriptorTypeDeviceSpecific() ) {
+ DeviceSpecific = ( PDEVICE_SPECIFIC_DESCRIPTOR )PartialDescriptor;
+ swprintf( Reserved1String,
+ ( LPWSTR )L"0x%08x",
+ DeviceSpecific->GetReserved1() );
+ swprintf( Reserved2String,
+ ( LPWSTR )L"0x%08x",
+ DeviceSpecific->GetReserved1() );
+ swprintf( DataSizeString,
+ ( LPWSTR )L"%#x",
+ DeviceSpecific->GetData( &AuxPointer ) );
+
+ ClbString[ 0 ].String = ( LPWSTR )Reserved1String;
+ ClbString[ 0 ].Length = wcslen( Reserved1String );
+ ClbString[ 0 ].Format = CLB_LEFT;
+ ClbString[ 1 ].String = ( LPWSTR )Reserved2String;
+ ClbString[ 1 ].Format = CLB_LEFT;
+ ClbString[ 1 ].Length = wcslen( Reserved2String );
+ ClbString[ 2 ].String = ( LPWSTR )DataSizeString;
+ ClbString[ 2 ].Length = wcslen( DataSizeString );
+ ClbString[ 2 ].Format = CLB_LEFT;
+
+ ClbRow.Count = 3;
+
+ ClbAddData( hDlg,
+ IDC_FULL_RES_LIST_DEVICE_SPECIFIC,
+ &ClbRow );
+
+ } else {
+ DebugPrintf( "REGEDT32: Unknown Descriptor \n\n" );
+ continue;
+ }
+
+ }
+
+ DELETE( Iterator );
+ //
+ // Disble the Display button
+ //
+ // EnableWindow( GetDlgItem( hDlg, IDC_PUSH_DISPLAY_RESOURCES ), FALSE );
+ return( TRUE );
+ }
+
+ case WM_COMPAREITEM:
+ {
+ LPCOMPAREITEMSTRUCT lpcis;
+ LPCLB_ROW ClbRow1;
+ LPCLB_ROW ClbRow2;
+ LONG Compare;
+
+ PCPARTIAL_DESCRIPTOR Descriptor1;
+ PCPARTIAL_DESCRIPTOR Descriptor2;
+
+ lpcis = ( LPCOMPAREITEMSTRUCT ) lParam;
+ DebugAssert( lpcis->CtlType == ODT_LISTBOX );
+
+ //
+ // Extract the two rows to be compared.
+ //
+
+ ClbRow1 = ( LPCLB_ROW ) lpcis->itemData1;
+ ClbRow2 = ( LPCLB_ROW ) lpcis->itemData2;
+
+ Descriptor1 = ( PCPARTIAL_DESCRIPTOR ) ClbRow1->Data;
+ Descriptor2 = ( PCPARTIAL_DESCRIPTOR ) ClbRow2->Data;
+
+ //
+ // Sort the Clbs. In the case of DMA and INTERRUPT, sort by channel
+ // and vector respectively. For MEMORY and PORT sort by starting
+ // physical address.
+ //
+
+ switch( lpcis->CtlID ) {
+
+ case IDC_FULL_RES_LIST_DMA:
+
+ //
+ // For DMA, sort by channel and port
+ //
+
+ Compare = ( ( PCDMA_DESCRIPTOR )Descriptor1 )->GetChannel() -
+ ( ( PCDMA_DESCRIPTOR )Descriptor2 )->GetChannel();
+ if( Compare == 0 ) {
+ Compare = ( ( PCDMA_DESCRIPTOR )Descriptor1 )->GetPort() -
+ ( ( PCDMA_DESCRIPTOR )Descriptor2 )->GetPort();
+ }
+ break;
+
+ case IDC_FULL_RES_LIST_INTERRUPTS:
+
+ //
+ // For INTERRUPT, sort by vector and level
+ //
+
+ Compare = ( ( PCINTERRUPT_DESCRIPTOR )Descriptor1 )->GetVector() -
+ ( ( PCINTERRUPT_DESCRIPTOR )Descriptor2 )->GetVector();
+ if( Compare == 0 ) {
+ Compare = ( ( PCINTERRUPT_DESCRIPTOR )Descriptor1 )->GetLevel() -
+ ( ( PCINTERRUPT_DESCRIPTOR )Descriptor2 )->GetLevel();
+ }
+ break;
+
+ case IDC_FULL_RES_LIST_MEMORY:
+
+ //
+ // For MEMORY sort by physical address
+ //
+
+ Compare = ( ( ( PMEMORY_DESCRIPTOR )Descriptor1 )->GetStartAddress() )->HighPart -
+ ( ( ( PMEMORY_DESCRIPTOR )Descriptor2 )->GetStartAddress() )->HighPart;
+ if( Compare == 0 ) {
+ Compare = ( ( ( PMEMORY_DESCRIPTOR )Descriptor1 )->GetStartAddress() )->LowPart -
+ ( ( ( PMEMORY_DESCRIPTOR )Descriptor2 )->GetStartAddress() )->LowPart;
+ }
+ break;
+
+ case IDC_FULL_RES_LIST_PORTS:
+
+ //
+ // For PORT sort by physical address
+ //
+
+ Compare = ( ( ( PPORT_DESCRIPTOR )Descriptor1 )->GetPhysicalAddress() )->HighPart -
+ ( ( ( PPORT_DESCRIPTOR )Descriptor2 )->GetPhysicalAddress() )->HighPart;
+ if( Compare == 0 ) {
+ Compare = ( ( ( PPORT_DESCRIPTOR )Descriptor1 )->GetPhysicalAddress() )->LowPart -
+ ( ( ( PPORT_DESCRIPTOR )Descriptor2 )->GetPhysicalAddress() )->LowPart;
+ }
+ break;
+
+ }
+ return Compare;
+ }
+
+ case WM_COMMAND:
+
+ switch( LOWORD( wParam ) ) {
+
+ case IDOK:
+ case IDCANCEL:
+
+ EndDialog( hDlg, TRUE );
+ return( TRUE );
+
+ case IDC_FULL_RES_LIST_DMA:
+
+ switch( HIWORD( wParam )) {
+
+ case LBN_SELCHANGE:
+ {
+
+ PCPARTIAL_DESCRIPTOR Descriptor;
+
+ LastSelectedDevSpecific = NULL;
+ //
+ // Remove the selection from the other list boxes
+ //
+ SendDlgItemMessage( hDlg,
+ IDC_FULL_RES_LIST_INTERRUPTS,
+ LB_SETCURSEL,
+ (WPARAM) -1,
+ 0 );
+ SendDlgItemMessage( hDlg,
+ IDC_FULL_RES_LIST_MEMORY,
+ LB_SETCURSEL,
+ (WPARAM) -1,
+ 0 );
+
+ SendDlgItemMessage( hDlg,
+ IDC_FULL_RES_LIST_PORTS,
+ LB_SETCURSEL,
+ (WPARAM) -1,
+ 0 );
+
+ SendDlgItemMessage( hDlg,
+ IDC_FULL_RES_LIST_DEVICE_SPECIFIC,
+ LB_SETCURSEL,
+ (WPARAM) -1,
+ 0 );
+
+ //
+ // Get the PARTIAL_DESCRIPTOR for the currently selected
+ // resource and update the share disposition display.
+ //
+
+ Descriptor = ( PCPARTIAL_DESCRIPTOR )GetSelectedItem( hDlg,
+ LOWORD( wParam ) );
+
+ if( Descriptor != NULL ) {
+ UpdateShareDisplay( hDlg, Descriptor );
+ }
+ //
+ // Disable the Data... button.
+ //
+ EnableWindow( GetDlgItem( hDlg, IDC_PUSH_DISPLAY_DATA ),
+ FALSE );
+
+ return( TRUE );
+ }
+
+ }
+ break;
+
+ case IDC_FULL_RES_LIST_INTERRUPTS:
+
+ switch( HIWORD( wParam )) {
+
+ case LBN_SELCHANGE:
+ {
+
+ PCPARTIAL_DESCRIPTOR Descriptor;
+
+ LastSelectedDevSpecific = NULL;
+ //
+ // Remove the selection from the other list boxes
+ //
+ SendDlgItemMessage( hDlg,
+ IDC_FULL_RES_LIST_DMA,
+ LB_SETCURSEL,
+ (WPARAM) -1,
+ 0 );
+
+ SendDlgItemMessage( hDlg,
+ IDC_FULL_RES_LIST_MEMORY,
+ LB_SETCURSEL,
+ (WPARAM) -1,
+ 0 );
+
+ SendDlgItemMessage( hDlg,
+ IDC_FULL_RES_LIST_PORTS,
+ LB_SETCURSEL,
+ (WPARAM) -1,
+ 0 );
+
+ SendDlgItemMessage( hDlg,
+ IDC_FULL_RES_LIST_DEVICE_SPECIFIC,
+ LB_SETCURSEL,
+ (WPARAM) -1,
+ 0 );
+
+ //
+ // Get the PARTIAL_DESCRIPTOR for the currently selected
+ // resource and update the share disposition display.
+ //
+
+ Descriptor = ( PCPARTIAL_DESCRIPTOR )GetSelectedItem( hDlg,
+ LOWORD( wParam ) );
+
+ if( Descriptor != NULL ) {
+ UpdateShareDisplay( hDlg, Descriptor );
+ }
+ //
+ // Disable the Data... button.
+ //
+ EnableWindow( GetDlgItem( hDlg, IDC_PUSH_DISPLAY_DATA ),
+ FALSE );
+
+ return( TRUE );
+ }
+
+ }
+ break;
+
+ case IDC_FULL_RES_LIST_MEMORY:
+
+ switch( HIWORD( wParam )) {
+
+ case LBN_SELCHANGE:
+ {
+
+ PCPARTIAL_DESCRIPTOR Descriptor;
+
+ LastSelectedDevSpecific = NULL;
+ //
+ // Remove the selection from the other list boxes
+ //
+ SendDlgItemMessage( hDlg,
+ IDC_FULL_RES_LIST_DMA,
+ LB_SETCURSEL,
+ (WPARAM) -1,
+ 0 );
+
+ SendDlgItemMessage( hDlg,
+ IDC_FULL_RES_LIST_INTERRUPTS,
+ LB_SETCURSEL,
+ (WPARAM) -1,
+ 0 );
+
+ SendDlgItemMessage( hDlg,
+ IDC_FULL_RES_LIST_PORTS,
+ LB_SETCURSEL,
+ (WPARAM) -1,
+ 0 );
+
+ SendDlgItemMessage( hDlg,
+ IDC_FULL_RES_LIST_DEVICE_SPECIFIC,
+ LB_SETCURSEL,
+ (WPARAM) -1,
+ 0 );
+
+ //
+ // Get the PARTIAL_DESCRIPTOR for the currently selected
+ // resource and update the share disposition display.
+ //
+
+ Descriptor = ( PCPARTIAL_DESCRIPTOR )GetSelectedItem( hDlg,
+ LOWORD( wParam ) );
+
+ if( Descriptor != NULL ) {
+ UpdateShareDisplay( hDlg, Descriptor );
+ }
+ //
+ // Disable the Data... button.
+ //
+ EnableWindow( GetDlgItem( hDlg, IDC_PUSH_DISPLAY_DATA ),
+ FALSE );
+
+ return( TRUE );
+ }
+
+ }
+ break;
+
+ case IDC_FULL_RES_LIST_PORTS:
+
+ switch( HIWORD( wParam )) {
+
+ case LBN_SELCHANGE:
+ {
+ PCPARTIAL_DESCRIPTOR Descriptor;
+
+ LastSelectedDevSpecific = NULL;
+ //
+ // Remove the selection from the other list boxes
+ //
+ SendDlgItemMessage( hDlg,
+ IDC_FULL_RES_LIST_DMA,
+ LB_SETCURSEL,
+ (WPARAM) -1,
+ 0 );
+
+ SendDlgItemMessage( hDlg,
+ IDC_FULL_RES_LIST_INTERRUPTS,
+ LB_SETCURSEL,
+ (WPARAM) -1,
+ 0 );
+
+ SendDlgItemMessage( hDlg,
+ IDC_FULL_RES_LIST_MEMORY,
+ LB_SETCURSEL,
+ (WPARAM) -1,
+ 0 );
+
+ SendDlgItemMessage( hDlg,
+ IDC_FULL_RES_LIST_DEVICE_SPECIFIC,
+ LB_SETCURSEL,
+ (WPARAM) -1,
+ 0 );
+
+ //
+ // Get the PARTIAL_DESCRIPTOR for the currently selected
+ // resource and update the share disposition display.
+ //
+
+ Descriptor = ( PCPARTIAL_DESCRIPTOR )GetSelectedItem( hDlg,
+ LOWORD( wParam ) );
+
+ if( Descriptor != NULL ) {
+ UpdateShareDisplay( hDlg, Descriptor );
+ }
+ //
+ // Disable the Data... button.
+ //
+ EnableWindow( GetDlgItem( hDlg, IDC_PUSH_DISPLAY_DATA ),
+ FALSE );
+
+ return( TRUE );
+ }
+
+ }
+ break;
+
+ case IDC_FULL_RES_LIST_DEVICE_SPECIFIC:
+
+ switch( HIWORD( wParam )) {
+
+ case LBN_SELCHANGE:
+ {
+
+ PCPARTIAL_DESCRIPTOR Descriptor;
+ PCBYTE Pointer;
+
+ //
+ // Remove the selection from the other list boxes
+ //
+ SendDlgItemMessage( hDlg,
+ IDC_FULL_RES_LIST_DMA,
+ LB_SETCURSEL,
+ (WPARAM) -1,
+ 0 );
+
+ SendDlgItemMessage( hDlg,
+ IDC_FULL_RES_LIST_INTERRUPTS,
+ LB_SETCURSEL,
+ (WPARAM) -1,
+ 0 );
+
+ SendDlgItemMessage( hDlg,
+ IDC_FULL_RES_LIST_MEMORY,
+ LB_SETCURSEL,
+ (WPARAM) -1,
+ 0 );
+
+ SendDlgItemMessage( hDlg,
+ IDC_FULL_RES_LIST_PORTS,
+ LB_SETCURSEL,
+ (WPARAM) -1,
+ 0 );
+
+ //
+ // Get the PARTIAL_DESCRIPTOR for the currently selected
+ // resource and update the share disposition display.
+ //
+
+ Descriptor = ( PCPARTIAL_DESCRIPTOR )GetSelectedItem( hDlg,
+ LOWORD( wParam ) );
+ LastSelectedDevSpecific = ( PCDEVICE_SPECIFIC_DESCRIPTOR )Descriptor;
+
+ if( Descriptor != NULL ) {
+ UpdateShareDisplay( hDlg, Descriptor );
+ }
+ //
+ // Enable the Data... button if necessary.
+ //
+
+ EnableWindow( GetDlgItem( hDlg, IDC_PUSH_DISPLAY_DATA ),
+ ( ( Descriptor != NULL ) &&
+ Descriptor->IsDescriptorTypeDeviceSpecific() &&
+ ( ( ( PCDEVICE_SPECIFIC_DESCRIPTOR )Descriptor )->GetData( &Pointer ) != 0 )
+ )
+ );
+
+ return( TRUE );
+ }
+
+
+ case LBN_DBLCLK:
+ {
+
+ //
+ // Simulate that the details button was pushed
+ //
+
+ SendMessage( hDlg,
+ WM_COMMAND,
+ MAKEWPARAM( IDC_PUSH_DISPLAY_DATA, BN_CLICKED ),
+ ( LPARAM ) GetDlgItem( hDlg, IDC_PUSH_DISPLAY_DATA ) );
+ return( TRUE ); // 0;
+ }
+
+ }
+ break;
+
+ case IDC_PUSH_DISPLAY_DATA:
+ {
+ //
+ // Display the device specific data
+ //
+ if( ( LastSelectedDevSpecific != NULL ) &&
+ ( ( Size = LastSelectedDevSpecific->GetData( &Pointer ) ) != 0 )
+ ) {
+ DisplayBinaryData( hDlg, Pointer, Size );
+ }
+ return( TRUE );
+ }
+ break;
+ }
+ }
+ return( FALSE );
+}
+
+
+BOOL
+APIENTRY
+REGISTRY_DATA::DisplayRequirementsListDialogProc(
+ HWND hDlg,
+ DWORD Msg,
+ WPARAM wParam,
+ LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ The dialog procedure for displaying data of type REG_RESOURCE_REQUIREMENTS_LIST.
+
+Arguments:
+
+ hDlg - a handle to the dialog proceedure.
+
+ Msg - the message passed from Windows.
+
+ wParam - extra message dependent data.
+
+ lParam - extra message dependent data.
+
+
+Return Value:
+
+ BOOL - Standard return code for dialog procedures.
+
+--*/
+
+{
+
+ switch( Msg ) {
+
+ case WM_INITDIALOG:
+ {
+ LPCWSTR InterfaceString;
+ LPCWSTR DescriptorTypeString;
+ ULONG StringSize;
+ PCIO_REQUIREMENTS_LIST RequirementsList;
+ WCHAR BusNumberString[ MAX_LENGTH_DWORD_STRING ];
+ WCHAR SlotNumberString[ MAX_LENGTH_DWORD_STRING ];
+
+ PARRAY AlternativeLists;
+ PITERATOR AlternativeListsIterator;
+ ULONG AlternativeListNumber;
+ WCHAR AlternativeListNumberString[ MAX_LENGTH_DWORD_STRING ];
+
+ PCIO_DESCRIPTOR_LIST IoDescriptorList;
+
+ CLB_ROW ClbRow;
+ CLB_STRING ClbString[ ] = {
+ { NULL, 0, CLB_LEFT, NULL },
+ { NULL, 0, CLB_LEFT, NULL },
+ { NULL, 0, CLB_LEFT, NULL },
+ { NULL, 0, CLB_LEFT, NULL }
+ };
+
+
+ if( ( RequirementsList = ( PCIO_REQUIREMENTS_LIST )lParam ) == NULL ) {
+ EndDialog( hDlg, 0 );
+ return( TRUE );
+ }
+
+ //
+ // Write the interface type
+ //
+
+ switch( RequirementsList->GetInterfaceType() ) {
+
+ case Internal:
+
+ InterfaceString = _MsgBusInternal->GetWSTR();
+ break;
+
+ case Isa:
+
+ InterfaceString = _MsgBusIsa->GetWSTR();
+ break;
+
+ case Eisa:
+
+ InterfaceString = _MsgBusEisa->GetWSTR();
+ break;
+
+ case MicroChannel:
+
+ InterfaceString = _MsgBusMicroChannel->GetWSTR();
+ break;
+
+ case TurboChannel:
+
+ InterfaceString = _MsgBusTurboChannel->GetWSTR();
+ break;
+
+ case PCIBus:
+
+ InterfaceString = _MsgBusPCIBus->GetWSTR();
+ break;
+
+ case VMEBus:
+
+ InterfaceString = _MsgBusVMEBus->GetWSTR();
+ break;
+
+ case NuBus:
+
+ InterfaceString = _MsgBusNuBus->GetWSTR();
+ break;
+
+ case PCMCIABus:
+
+ InterfaceString = _MsgBusPCMCIABus->GetWSTR();
+ break;
+
+ case CBus:
+
+ InterfaceString = _MsgBusCBus->GetWSTR();
+ break;
+
+ case MPIBus:
+
+ InterfaceString = _MsgBusMPIBus->GetWSTR();
+ break;
+
+ case MPSABus:
+
+ InterfaceString = _MsgBusMPSABus->GetWSTR();
+ break;
+
+ default:
+
+ InterfaceString = _MsgInvalid->GetWSTR();
+ break;
+ }
+
+ SendDlgItemMessage( hDlg,
+ IDC_IO_REQ_TEXT_INTERFACE_TYPE,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM )InterfaceString );
+
+ //
+ // Write the bus number
+ //
+
+ swprintf( BusNumberString, ( LPWSTR )L"%d", RequirementsList->GetBusNumber() );
+
+ SendDlgItemMessage( hDlg,
+ IDC_IO_REQ_TEXT_BUS_NUMBER,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM )BusNumberString );
+
+ //
+ // Write the slot number
+ //
+
+ swprintf( SlotNumberString, ( LPWSTR )L"%d", RequirementsList->GetSlotNumber() );
+
+ SendDlgItemMessage( hDlg,
+ IDC_IO_REQ_TEXT_SLOT_NUMBER,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM )SlotNumberString );
+
+ //
+ // Write the entries in the column list box
+ //
+ if( ( ( AlternativeLists = RequirementsList->GetAlternativeLists() ) == NULL ) ||
+ ( ( AlternativeListsIterator = AlternativeLists->QueryIterator() ) == NULL ) ) {
+ EndDialog( hDlg, 0 );
+ return( TRUE );
+ }
+
+ AlternativeListNumber = 0;
+ while( ( IoDescriptorList = ( PCIO_DESCRIPTOR_LIST )AlternativeListsIterator->GetNext() ) != NULL ) {
+
+ PARRAY IoDescriptors;
+ PITERATOR IoDescriptorListIterator;
+ PCIO_DESCRIPTOR Descriptor;
+ ULONG SubListNumber;
+ WCHAR SubListNumberString[ MAX_LENGTH_DWORD_STRING ];
+ ULONG DescriptorNumber;
+ WCHAR DescriptorNumberString[ MAX_LENGTH_DWORD_STRING ];
+
+
+ if( ( ( IoDescriptors = ( PARRAY )IoDescriptorList->GetDescriptorsList() ) == NULL ) ||
+ ( ( IoDescriptorListIterator = IoDescriptors->QueryIterator() ) == NULL ) ) {
+ DELETE( AlternativeListsIterator );
+ EndDialog( hDlg, 0 );
+ return( TRUE );
+ }
+
+ AlternativeListNumber++;
+ swprintf( AlternativeListNumberString, ( LPWSTR )L"%d", AlternativeListNumber );
+
+ SubListNumber = 0;
+ while( ( Descriptor = ( PCIO_DESCRIPTOR )IoDescriptorListIterator->GetNext() ) != NULL ) {
+ if( ( !Descriptor->IsResourceOptionAlternative() ) ||
+ ( SubListNumber == 0 ) ) {
+ SubListNumber++;
+ DescriptorNumber = 0;
+ }
+ DescriptorNumber++;
+
+ swprintf( SubListNumberString, ( LPWSTR )L"%d", SubListNumber );
+
+ swprintf( DescriptorNumberString, ( LPWSTR )L"%d", DescriptorNumber );
+
+ if( Descriptor->IsDescriptorTypePort() ) {
+ DescriptorTypeString = _MsgDevPort->GetWSTR();
+ StringSize = _MsgDevPort->QueryChCount();
+ } else if( Descriptor->IsDescriptorTypeInterrupt() ) {
+ DescriptorTypeString = _MsgDevInterrupt->GetWSTR();
+ StringSize = _MsgDevInterrupt->QueryChCount();
+ } else if( Descriptor->IsDescriptorTypeMemory() ) {
+ DescriptorTypeString = _MsgDevMemory->GetWSTR();
+ StringSize = _MsgDevMemory->QueryChCount();
+ } else if( Descriptor->IsDescriptorTypeDma() ) {
+ DescriptorTypeString = _MsgDevDma->GetWSTR();
+ StringSize = _MsgDevDma->QueryChCount();
+ } else {
+ DescriptorTypeString = _MsgInvalid->GetWSTR();
+ StringSize = _MsgInvalid->QueryChCount();
+ }
+
+ ClbString[ 0 ].String = ( LPWSTR )AlternativeListNumberString;
+ ClbString[ 0 ].Length = wcslen( AlternativeListNumberString );
+ ClbString[ 0 ].Format = CLB_LEFT;
+ ClbString[ 1 ].String = ( LPWSTR )SubListNumberString;
+ ClbString[ 1 ].Format = CLB_LEFT;
+ ClbString[ 1 ].Length = wcslen( SubListNumberString );
+ ClbString[ 2 ].String = ( LPWSTR )DescriptorNumberString;
+ ClbString[ 2 ].Format = CLB_LEFT;
+ ClbString[ 2 ].Length = wcslen( DescriptorNumberString );
+ ClbString[ 3 ].String = ( LPWSTR )DescriptorTypeString;
+ ClbString[ 3 ].Format = CLB_LEFT;
+ ClbString[ 3 ].Length = StringSize;
+
+ ClbRow.Count = 4;
+ ClbRow.Strings = ClbString;
+ ClbRow.Data = ( PVOID )Descriptor;
+
+ ClbAddData( hDlg,
+ IDC_IO_LIST_ALTERNATIVE_LISTS,
+ &ClbRow );
+
+ }
+ DELETE( IoDescriptorListIterator );
+ }
+ DELETE( AlternativeListsIterator );
+
+ //
+ // Disble the Display button
+ //
+ EnableWindow( GetDlgItem( hDlg, IDC_IO_REQ_PUSH_DISPLAY_DEVICE ), FALSE );
+ return( TRUE );
+ }
+
+ case WM_COMMAND:
+
+ switch( LOWORD( wParam ) ) {
+
+ case IDOK:
+ case IDCANCEL:
+
+ EndDialog( hDlg, TRUE );
+ return( TRUE );
+
+ case IDC_IO_LIST_ALTERNATIVE_LISTS:
+ {
+
+ switch( HIWORD( wParam )) {
+
+ case LBN_SELCHANGE:
+ {
+
+ //
+ // Enable the display device details button
+ //
+
+ EnableWindow( GetDlgItem( hDlg, IDC_IO_REQ_PUSH_DISPLAY_DEVICE ),
+ TRUE );
+ return 0;
+ }
+
+ case LBN_DBLCLK:
+ {
+
+ //
+ // Simulate that the details button was pushed
+ //
+
+ SendMessage( hDlg,
+ WM_COMMAND,
+ MAKEWPARAM( IDC_IO_REQ_PUSH_DISPLAY_DEVICE, BN_CLICKED ),
+ ( LPARAM ) GetDlgItem( hDlg, IDC_IO_REQ_PUSH_DISPLAY_DEVICE ) );
+ return 0;
+ }
+ }
+ break;
+ }
+
+ case IDC_IO_REQ_PUSH_DISPLAY_DEVICE:
+ {
+ PCIO_DESCRIPTOR IoDescriptor;
+
+ IoDescriptor = ( PCIO_DESCRIPTOR )( GetSelectedItem ( hDlg, IDC_IO_LIST_ALTERNATIVE_LISTS ) );
+ if( IoDescriptor != NULL ) {
+ DisplayIoDescriptor( hDlg, IoDescriptor );
+ }
+ return( TRUE );
+ }
+ }
+ }
+ return( FALSE );
+}
+
+
+BOOL
+APIENTRY
+REGISTRY_DATA::DisplayIoPortDialogProc(
+ HWND hDlg,
+ DWORD Msg,
+ WPARAM wParam,
+ LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ The dialog proceedure for displaying an object of type IO_PORT.
+
+Arguments:
+
+ hDlg - a handle to the dialog proceedure.
+
+ Msg - the message passed from Windows.
+
+ wParam - extra message dependent data.
+
+ lParam - extra message dependent data.
+
+
+Return Value:
+
+ BOOL - Standard return code for dialog procedures.
+
+--*/
+
+{
+
+ switch( Msg ) {
+
+ case WM_INITDIALOG:
+ {
+ PCIO_PORT_DESCRIPTOR Port;
+ PCWSTRING String;
+ WCHAR AddressString[ MAX_LENGTH_BIG_INT_STRING ];
+
+ if( ( Port = ( PCIO_PORT_DESCRIPTOR )lParam ) == NULL ) {
+ EndDialog( hDlg, 0 );
+ return( TRUE );
+ }
+
+ //
+ // Write the port type
+ //
+
+ if( Port->IsPortMemory() ) {
+ String = _MsgPortMemory;
+ } else if( Port->IsPortIo() ){
+ String = _MsgPortPort;
+ } else {
+ String = _MsgInvalid;
+ }
+ SendDlgItemMessage( hDlg,
+ IDC_IO_TEXT_PORT_TYPE,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM ) String->GetWSTR() );
+
+ //
+ // Write the length
+ //
+ swprintf( AddressString,
+ ( LPWSTR )L"%#x",
+ Port->GetLength() );
+
+ SendDlgItemMessage( hDlg,
+ IDC_IO_TEXT_PORT_LENGTH,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM )AddressString );
+
+ //
+ // Write the alignment
+ //
+ swprintf( AddressString,
+ ( LPWSTR )L"%#x",
+ Port->GetAlignment() );
+
+ SendDlgItemMessage( hDlg,
+ IDC_IO_TEXT_PORT_ALIGNMENT,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM )AddressString );
+
+ //
+ // Write the minimum address
+ //
+
+ if( ( ( ( PIO_PORT_DESCRIPTOR )Port )->GetMinimumAddress() )->HighPart != 0 ) {
+ swprintf( AddressString,
+ ( LPWSTR )L"0x%08x%08x",
+ ( ( ( PIO_PORT_DESCRIPTOR )Port )->GetMinimumAddress() )->HighPart,
+ ( ( ( PIO_PORT_DESCRIPTOR )Port )->GetMinimumAddress() )->LowPart );
+ } else {
+ swprintf( AddressString,
+ ( LPWSTR )L"0x%08x",
+ ( ( ( PIO_PORT_DESCRIPTOR )Port )->GetMinimumAddress() )->LowPart );
+ }
+
+
+ SendDlgItemMessage( hDlg,
+ IDC_IO_TEXT_PORT_MIN_ADDRESS,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM )AddressString );
+
+ //
+ // Write the maximum address
+ //
+
+ if( ( ( ( PIO_PORT_DESCRIPTOR )Port )->GetMaximumAddress() )->HighPart != 0 ) {
+ swprintf( AddressString,
+ ( LPWSTR )L"0x%08x%08x",
+ ( ( ( PIO_PORT_DESCRIPTOR )Port )->GetMaximumAddress() )->HighPart,
+ ( ( ( PIO_PORT_DESCRIPTOR )Port )->GetMaximumAddress() )->LowPart );
+ } else {
+ swprintf( AddressString,
+ ( LPWSTR )L"0x%08x",
+ ( ( ( PIO_PORT_DESCRIPTOR )Port )->GetMaximumAddress() )->LowPart );
+ }
+ SendDlgItemMessage( hDlg,
+ IDC_IO_TEXT_PORT_MAX_ADDRESS,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM )AddressString );
+
+ //
+ // Write share disposition
+ //
+
+ if( Port->IsResourceShareUndetermined() ) {
+ String = _MsgShareUndetermined;
+ } else if( Port->IsResourceShareDeviceExclusive() ) {
+ String = _MsgShareDeviceExclusive;
+ } else if( Port->IsResourceShareDriverExclusive() ) {
+ String = _MsgShareDriverExclusive;
+ } else if( Port->IsResourceShareShared() ) {
+ String = _MsgShareShared;
+ } else {
+ String = _MsgInvalid;
+ }
+
+ SendDlgItemMessage( hDlg,
+ IDC_IO_TEXT_DISPOSITION,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM )String->GetWSTR() );
+ //
+ // Set the Options
+ //
+ UpdateOptionDisplay( hDlg, ( PCIO_DESCRIPTOR )Port );
+ return( TRUE );
+ }
+
+ case WM_COMMAND:
+
+ switch( LOWORD( wParam ) ) {
+
+ case IDOK:
+ case IDCANCEL:
+
+ EndDialog( hDlg, TRUE );
+ return( TRUE );
+
+ }
+ }
+ return( FALSE );
+}
+
+
+BOOL
+APIENTRY
+REGISTRY_DATA::DisplayIoMemoryDialogProc(
+ HWND hDlg,
+ DWORD Msg,
+ WPARAM wParam,
+ LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ The dialog proceedure for displaying an object of type IO_PORT.
+
+Arguments:
+
+ hDlg - a handle to the dialog proceedure.
+
+ Msg - the message passed from Windows.
+
+ wParam - extra message dependent data.
+
+ lParam - extra message dependent data.
+
+
+Return Value:
+
+ BOOL - Standard return code for dialog procedures.
+
+--*/
+
+{
+
+ switch( Msg ) {
+
+ case WM_INITDIALOG:
+ {
+ PCIO_MEMORY_DESCRIPTOR Memory;
+ PCWSTRING String;
+ WCHAR AddressString[ MAX_LENGTH_BIG_INT_STRING ];
+
+ if( ( Memory = ( PCIO_MEMORY_DESCRIPTOR )lParam ) == NULL ) {
+ EndDialog( hDlg, 0 );
+ return( TRUE );
+ }
+
+ //
+ // Write the memory access
+ //
+
+ if( Memory->IsMemoryReadWrite() ) {
+ String = _MsgMemReadWrite;
+ } else if( Memory->IsMemoryReadOnly() ){
+ String = _MsgMemReadOnly;
+ } else if( Memory->IsMemoryWriteOnly() ){
+ String = _MsgMemWriteOnly;
+ } else {
+ String = _MsgInvalid;
+ }
+ SendDlgItemMessage( hDlg,
+ IDC_IO_TEXT_MEM_ACCESS,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM ) String->GetWSTR() );
+
+ //
+ // Write the length
+ //
+ swprintf( AddressString,
+ ( LPWSTR )L"%#x",
+ Memory->GetLength() );
+
+ SendDlgItemMessage( hDlg,
+ IDC_IO_TEXT_MEM_LENGTH,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM )AddressString );
+
+ //
+ // Write the alignment
+ //
+ swprintf( AddressString,
+ ( LPWSTR )L"%#x",
+ Memory->GetAlignment() );
+
+ SendDlgItemMessage( hDlg,
+ IDC_IO_TEXT_MEM_ALIGNMENT,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM )AddressString );
+
+ //
+ // Write the minimum address
+ //
+ if( ( ( ( PIO_MEMORY_DESCRIPTOR )Memory )->GetMinimumAddress() )->HighPart != 0 ) {
+ swprintf( AddressString,
+ ( LPWSTR )L"0x%08x%08x",
+ ( ( ( PIO_MEMORY_DESCRIPTOR )Memory )->GetMinimumAddress() )->HighPart,
+ ( ( ( PIO_MEMORY_DESCRIPTOR )Memory )->GetMinimumAddress() )->LowPart );
+ } else {
+ swprintf( AddressString,
+ ( LPWSTR )L"0x%08x",
+ ( ( ( PIO_MEMORY_DESCRIPTOR )Memory )->GetMinimumAddress() )->LowPart );
+ }
+
+ SendDlgItemMessage( hDlg,
+ IDC_IO_TEXT_MEM_MIN_ADDRESS,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM )AddressString );
+
+ //
+ // Write the maximum address
+ //
+ if( ( ( ( PIO_MEMORY_DESCRIPTOR )Memory )->GetMaximumAddress() )->HighPart != 0 ) {
+ swprintf( AddressString,
+ ( LPWSTR )L"0x%08x%08x",
+ ( ( ( PIO_MEMORY_DESCRIPTOR )Memory )->GetMaximumAddress() )->HighPart,
+ ( ( ( PIO_MEMORY_DESCRIPTOR )Memory )->GetMaximumAddress() )->LowPart );
+ } else {
+ swprintf( AddressString,
+ ( LPWSTR )L"0x%08x",
+ ( ( ( PIO_MEMORY_DESCRIPTOR )Memory )->GetMaximumAddress() )->LowPart );
+ }
+ SendDlgItemMessage( hDlg,
+ IDC_IO_TEXT_MEM_MAX_ADDRESS,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM )AddressString );
+
+ //
+ // Write share disposition
+ //
+
+ if( Memory->IsResourceShareUndetermined() ) {
+ String = _MsgShareUndetermined;
+ } else if( Memory->IsResourceShareDeviceExclusive() ) {
+ String = _MsgShareDeviceExclusive;
+ } else if( Memory->IsResourceShareDriverExclusive() ) {
+ String = _MsgShareDriverExclusive;
+ } else if( Memory->IsResourceShareShared() ) {
+ String = _MsgShareShared;
+ } else {
+ String = _MsgInvalid;
+ }
+
+ SendDlgItemMessage( hDlg,
+ IDC_IO_TEXT_DISPOSITION,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM )String->GetWSTR() );
+ //
+ // Set the Options
+ //
+ UpdateOptionDisplay( hDlg, ( PCIO_DESCRIPTOR )Memory );
+ return( TRUE );
+ }
+
+ case WM_COMMAND:
+
+ switch( LOWORD( wParam ) ) {
+
+ case IDOK:
+ case IDCANCEL:
+
+ EndDialog( hDlg, TRUE );
+ return( TRUE );
+
+ }
+ }
+ return( FALSE );
+}
+
+
+BOOL
+APIENTRY
+REGISTRY_DATA::DisplayIoInterruptDialogProc(
+ HWND hDlg,
+ DWORD Msg,
+ WPARAM wParam,
+ LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ The dialog proceedure for displaying an object of type IO_PORT.
+
+Arguments:
+
+ hDlg - a handle to the dialog proceedure.
+
+ Msg - the message passed from Windows.
+
+ wParam - extra message dependent data.
+
+ lParam - extra message dependent data.
+
+
+Return Value:
+
+ BOOL - Standard return code for dialog procedures.
+
+--*/
+
+{
+
+ switch( Msg ) {
+
+ case WM_INITDIALOG:
+ {
+ PCIO_INTERRUPT_DESCRIPTOR Interrupt;
+ PCWSTRING String;
+ WCHAR AddressString[ MAX_LENGTH_DWORD_STRING ];
+
+ if( ( Interrupt = ( PCIO_INTERRUPT_DESCRIPTOR )lParam ) == NULL ) {
+ EndDialog( hDlg, 0 );
+ return( TRUE );
+ }
+
+ //
+ // Write the interrupt type
+ //
+
+ if( Interrupt->IsInterruptLevelSensitive() ) {
+ String = _MsgIntLevelSensitive;
+ } else if( Interrupt->IsInterruptLatched() ){
+ String = _MsgIntLatched;
+ } else {
+ String = _MsgInvalid;
+ }
+ SendDlgItemMessage( hDlg,
+ IDC_IO_TEXT_INT_TYPE,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM ) String->GetWSTR() );
+
+ //
+ // Write the minimum vector
+ //
+ swprintf( AddressString,
+ ( LPWSTR )L"%#x",
+ Interrupt->GetMinimumVector() );
+
+ SendDlgItemMessage( hDlg,
+ IDC_IO_TEXT_INT_MIN_VECTOR,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM )AddressString );
+
+ //
+ // Write the maximum vector
+ //
+ swprintf( AddressString,
+ ( LPWSTR )L"%#x",
+ Interrupt->GetMaximumVector() );
+
+ SendDlgItemMessage( hDlg,
+ IDC_IO_TEXT_INT_MAX_VECTOR,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM )AddressString );
+
+ //
+ // Write share disposition
+ //
+
+ if( Interrupt->IsResourceShareUndetermined() ) {
+ String = _MsgShareUndetermined;
+ } else if( Interrupt->IsResourceShareDeviceExclusive() ) {
+ String = _MsgShareDeviceExclusive;
+ } else if( Interrupt->IsResourceShareDriverExclusive() ) {
+ String = _MsgShareDriverExclusive;
+ } else if( Interrupt->IsResourceShareShared() ) {
+ String = _MsgShareShared;
+ } else {
+ String = _MsgInvalid;
+ }
+
+ SendDlgItemMessage( hDlg,
+ IDC_IO_TEXT_DISPOSITION,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM )String->GetWSTR() );
+ //
+ // Set the Options
+ //
+ UpdateOptionDisplay( hDlg, ( PCIO_DESCRIPTOR )Interrupt );
+ return( TRUE );
+ }
+
+ case WM_COMMAND:
+
+ switch( LOWORD( wParam ) ) {
+
+ case IDOK:
+ case IDCANCEL:
+
+ EndDialog( hDlg, TRUE );
+ return( TRUE );
+
+ }
+ }
+ return( FALSE );
+}
+
+
+BOOL
+APIENTRY
+REGISTRY_DATA::DisplayIoDmaDialogProc(
+ HWND hDlg,
+ DWORD Msg,
+ WPARAM wParam,
+ LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ The dialog proceedure for displaying an object of type IO_PORT.
+
+Arguments:
+
+ hDlg - a handle to the dialog proceedure.
+
+ Msg - the message passed from Windows.
+
+ wParam - extra message dependent data.
+
+ lParam - extra message dependent data.
+
+
+Return Value:
+
+ BOOL - Standard return code for dialog procedures.
+
+--*/
+
+{
+
+ switch( Msg ) {
+
+ case WM_INITDIALOG:
+ {
+ PCIO_DMA_DESCRIPTOR Dma;
+ PCWSTRING String;
+ WCHAR AddressString[ MAX_LENGTH_DWORD_STRING ];
+
+ if( ( Dma = ( PCIO_DMA_DESCRIPTOR )lParam ) == NULL ) {
+ EndDialog( hDlg, 0 );
+ return( TRUE );
+ }
+
+ //
+ // Write the minimum channel
+ //
+ swprintf( AddressString,
+ ( LPWSTR )L"%#x",
+ Dma->GetMinimumChannel() );
+
+ SendDlgItemMessage( hDlg,
+ IDC_IO_TEXT_DMA_MIN_CHANNEL,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM )AddressString );
+
+ //
+ // Write the maximum channel
+ //
+ swprintf( AddressString,
+ ( LPWSTR )L"%#x",
+ Dma->GetMaximumChannel() );
+
+ SendDlgItemMessage( hDlg,
+ IDC_IO_TEXT_DMA_MAX_CHANNEL,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM )AddressString );
+
+ //
+ // Write share disposition
+ //
+
+ if( Dma->IsResourceShareUndetermined() ) {
+ String = _MsgShareUndetermined;
+ } else if( Dma->IsResourceShareDeviceExclusive() ) {
+ String = _MsgShareDeviceExclusive;
+ } else if( Dma->IsResourceShareDriverExclusive() ) {
+ String = _MsgShareDriverExclusive;
+ } else if( Dma->IsResourceShareShared() ) {
+ String = _MsgShareShared;
+ } else {
+ String = _MsgInvalid;
+ }
+
+ SendDlgItemMessage( hDlg,
+ IDC_IO_TEXT_DISPOSITION,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM )String->GetWSTR() );
+ //
+ // Set the Options
+ //
+ UpdateOptionDisplay( hDlg, ( PCIO_DESCRIPTOR )Dma );
+ return( TRUE );
+ }
+
+ case WM_COMMAND:
+
+ switch( LOWORD( wParam ) ) {
+
+ case IDOK:
+ case IDCANCEL:
+
+ EndDialog( hDlg, TRUE );
+ return( TRUE );
+
+ }
+ }
+ return( FALSE );
+}
+
+
+
+
+PVOID
+REGISTRY_DATA::GetSelectedItem (
+ IN HWND hDlg,
+ IN ULONG ClbId
+ )
+
+/*++
+
+Routine Description:
+
+ Retrieve the object associated to the currently selected row in
+ a Clb.
+
+Arguments:
+
+ hDlg - Supplies the handle for the dialog that contains the selected
+ Clb.
+
+ ClbId - Id of the Clb that contains the selected row.
+
+
+Return Value:
+
+ PVOID - Returns the pointer to object associated to the row selected in a Clb.
+
+
+--*/
+
+{
+ LONG Index;
+ LPCLB_ROW ClbRow;
+ PVOID Descriptor;
+
+ //
+ // Get the index of the currently selected item.
+ //
+
+ Index = SendDlgItemMessage( hDlg,
+ ClbId,
+ LB_GETCURSEL,
+ 0,
+ 0 );
+ if( Index == LB_ERR ) {
+ return NULL;
+ }
+
+ //
+ // Get the CLB_ROW object for this row and extract the associated
+ // object.
+ //
+
+ ClbRow = ( LPCLB_ROW ) SendDlgItemMessage( hDlg,
+ ClbId,
+ LB_GETITEMDATA,
+ ( WPARAM ) Index,
+ 0 );
+ if(( ClbRow == NULL ) || (( LONG ) ClbRow ) == LB_ERR ) {
+ return NULL;
+ }
+
+ Descriptor = ClbRow->Data;
+ if( Descriptor == NULL ) {
+ return NULL;
+ }
+ return Descriptor;
+}
+
+
+VOID
+REGISTRY_DATA::UpdateShareDisplay(
+ IN HWND hDlg,
+ IN PCPARTIAL_DESCRIPTOR Descriptor
+ )
+
+/*++
+
+Routine Description:
+
+ UpdateShareDisplay hilights the appropriate sharing disposition text in
+ the supplied dialog based on the share disposition of the PARTIAL_DESCRIPTOR
+ object supplied.
+
+Arguments:
+
+ hWnd - Supplies window handle for the dialog box where share
+ display is being updated.
+ Descriptor - Supplies a pointer to a PARTIAL_DESCRIPTOR object whose
+ share disposition will be displayed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if( Descriptor != NULL ) {
+ EnableWindow( GetDlgItem( hDlg, IDC_FULL_RES_TEXT_UNDETERMINED ),
+ Descriptor->IsResourceShareUndetermined() );
+
+ EnableWindow( GetDlgItem( hDlg, IDC_FULL_RES_TEXT_DEVICE_EXCLUSIVE ),
+ Descriptor->IsResourceShareDeviceExclusive() );
+
+ EnableWindow( GetDlgItem( hDlg, IDC_FULL_RES_TEXT_DRIVER_EXCLUSIVE ),
+ Descriptor->IsResourceShareDriverExclusive() );
+
+ EnableWindow( GetDlgItem( hDlg,IDC_FULL_RES_TEXT_SHARED ),
+ Descriptor->IsResourceShareShared() );
+ }
+}
+
+
+VOID
+REGISTRY_DATA::UpdateOptionDisplay(
+ IN HWND hDlg,
+ IN PCIO_DESCRIPTOR Descriptor
+ )
+
+/*++
+
+Routine Description:
+
+ UpdateOptionDisplay highlights the appropriate Option text in
+ the supplied IO_DESCRIPTOR dialog based on the Option of the
+ IO_DESCRIPTOR object supplied.
+
+Arguments:
+
+ hWnd - Supplies window handle for the dialog box where share
+ display is being updated.
+ Descriptor - Supplies a pointer to an IO_DESCRIPTOR object whose
+ Option will be displayed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if( Descriptor != NULL ) {
+ EnableWindow( GetDlgItem( hDlg, IDC_IO_TEXT_OPTION_PREFERRED ),
+ Descriptor->IsResourceOptionPreferred() );
+
+ EnableWindow( GetDlgItem( hDlg, IDC_IO_TEXT_OPTION_ALTERNATIVE ),
+ Descriptor->IsResourceOptionAlternative() );
+ }
+}
+
+
+VOID
+REGISTRY_DATA::DisplayBinaryData(
+ IN HWND hWnd,
+ IN PCBYTE Data,
+ IN ULONG DataSize,
+ IN BOOLEAN DisplayValueType,
+ IN ULONG ValueType
+ )
+
+/*++
+
+Routine Description:
+
+ Display the contents of a buffer as binary data, in an hd-like format.
+
+Arguments:
+
+ hWnd - A handle to the owner window.
+
+ Data - Pointer to the buffer that contains the data to be displayed.
+
+ DataSize - Number of bytes in the buffer.
+
+ DisplayValueType - A flag that indicates whether or not the value type of the
+ data should be displayed as a binary number.
+
+ ValueType - A number representing the data type. This parameter is ignored if
+ DisplayValueTRype is FALSE.
+
+
+Return Value:
+
+
+ None.
+
+--*/
+
+{
+ BUFFER_INFORMATION BufferInfo;
+
+ BufferInfo.Buffer = ( PBYTE )Data;
+ BufferInfo.BufferSize = DataSize;
+ BufferInfo.DisplayValueType = DisplayValueType;
+ BufferInfo.ValueType = ValueType;
+ DialogBoxParam( (HINSTANCE)WINDOWS_APPLICATION::QueryInstance(),
+ ( BufferInfo.DisplayValueType )? MAKEINTRESOURCE( DISPLAY_BINARY_DATA_WITH_VALUE_TYPE ) :
+ MAKEINTRESOURCE( DISPLAY_BINARY_DATA ),
+ hWnd,
+ ( DLGPROC )REGISTRY_DATA::DisplayBinaryDataDialogProc,
+ ( LPARAM )&BufferInfo );
+}
+
+
+
+BOOL
+APIENTRY
+REGISTRY_DATA::DisplayBinaryDataDialogProc(
+ HWND hDlg,
+ DWORD Msg,
+ WPARAM wParam,
+ LONG lParam
+)
+/*++
+
+Routine Description:
+
+ This is the dialog procedure used in the dialog that displays
+ the data in a value entry as binary data, using a format similar
+ to the one used by the 'hd' utility.
+
+
+Arguments:
+
+ hDlg - a handle to the dialog proceedure.
+
+ Msg - the message passed from Windows.
+
+ wParam - extra message dependent data.
+
+ lParam - extra message dependent data.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the message was processed.
+ Otherwise, returns FALSE.
+
+--*/
+{
+
+ STATIC PCBYTE Data;
+ STATIC ULONG Size;
+ STATIC ULONG CurrentFormat;
+ STATIC BOOLEAN DisplayValueType;
+ STATIC ULONG ValueType;
+
+
+ switch( Msg ) {
+
+ case WM_INITDIALOG:
+ {
+ WCHAR AuxBuffer[16];
+ //
+ // Validate arguments and initialize static data
+ //
+ if( lParam == NULL ) {
+ EndDialog( hDlg, 0 );
+ return( TRUE );
+ }
+ Data = ( ( PBUFFER_INFORMATION )lParam )->Buffer;
+ Size = ( ( PBUFFER_INFORMATION )lParam )->BufferSize;
+ DisplayValueType = ( ( PBUFFER_INFORMATION )lParam )->DisplayValueType;
+ ValueType = ( ( PBUFFER_INFORMATION )lParam )->ValueType;
+
+ //
+ // Display value type as an hex number if necessary
+ //
+ if( DisplayValueType ) {
+ swprintf( AuxBuffer, ( LPWSTR )L"%#x", ValueType );
+ SendDlgItemMessage( hDlg,
+ IDT_VALUE_TYPE,
+ WM_SETTEXT,
+ 0,
+ ( LPARAM )AuxBuffer );
+ }
+ //
+ // Use fixed size font
+ //
+ SendDlgItemMessage( hDlg,
+ IDD_DISPLAY_DATA_BINARY,
+ WM_SETFONT,
+ ( WPARAM )GetStockObject( ANSI_FIXED_FONT ),
+ FALSE );
+
+ //
+ // Display the data in the listbox.
+ //
+
+
+ SendDlgItemMessage( hDlg,
+ IDR_BINARY_DATA_BYTE,
+ BM_SETCHECK,
+ ( WPARAM )TRUE,
+ 0 );
+
+ DumpBinaryData( hDlg, Data, Size );
+ CurrentFormat = IDR_BINARY_DATA_BYTE;
+ return( TRUE );
+ }
+
+ case WM_COMMAND:
+
+ switch( LOWORD( wParam ) ) {
+
+ case IDCANCEL:
+ case IDOK:
+ EndDialog( hDlg, TRUE );
+ return( TRUE );
+
+ case IDR_BINARY_DATA_BYTE:
+ case IDR_BINARY_DATA_WORD:
+ case IDR_BINARY_DATA_DWORD:
+
+ switch( HIWORD( wParam ) ) {
+
+ case BN_CLICKED:
+ {
+ ULONG TopIndex;
+ ULONG CurrentIndex;
+
+ //
+ // Ignore massage if new format is already the current format
+ //
+ if( CurrentFormat == LOWORD( wParam ) ) {
+ return( FALSE );
+ }
+
+ //
+ // Save the position of current selection
+ //
+ TopIndex = SendDlgItemMessage( hDlg,
+ IDD_DISPLAY_DATA_BINARY,
+ LB_GETTOPINDEX,
+ 0,
+ 0 );
+
+ CurrentIndex = ( ULONG )SendDlgItemMessage( hDlg,
+ IDD_DISPLAY_DATA_BINARY,
+ LB_GETCURSEL,
+ 0,
+ 0 );
+ //
+ // Reset the listbox
+ //
+ SendDlgItemMessage( hDlg,
+ IDD_DISPLAY_DATA_BINARY,
+ LB_RESETCONTENT,
+ 0,
+ 0 );
+ //
+ // Display the data in the appropriate format
+ //
+ if( LOWORD( wParam ) == IDR_BINARY_DATA_BYTE ) {
+ DumpBinaryData( hDlg, Data, Size );
+ CurrentFormat = IDR_BINARY_DATA_BYTE;
+ } else if( LOWORD( wParam ) == IDR_BINARY_DATA_WORD ) {
+ DumpBinaryDataAsWords( hDlg, Data, Size );
+ CurrentFormat = IDR_BINARY_DATA_WORD;
+ } else {
+ DumpBinaryDataAsDwords( hDlg, Data, Size );
+ CurrentFormat = IDR_BINARY_DATA_DWORD;
+ }
+
+ //
+ // Restore current selection
+ //
+ SendDlgItemMessage( hDlg,
+ IDD_DISPLAY_DATA_BINARY,
+ LB_SETTOPINDEX,
+ ( WPARAM )TopIndex,
+ 0 );
+
+ if( CurrentIndex != LB_ERR ) {
+ SendDlgItemMessage( hDlg,
+ IDD_DISPLAY_DATA_BINARY,
+ LB_SETCURSEL,
+ ( WPARAM )CurrentIndex,
+ 0 );
+ }
+ return( TRUE );
+ }
+
+ default:
+
+ break;
+ }
+ break;
+
+ default:
+
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ return( FALSE );
+}
+
+
+VOID
+REGISTRY_DATA::DumpBinaryData(
+ IN HWND hDlg,
+ IN PCBYTE Data,
+ IN ULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ Display the contents of a buffer in a list box, as binary data, using
+ an hd-like format.
+
+Arguments:
+
+ Data - Buffer that contains the binary data.
+
+ Size - Number of bytes in the buffer.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ WCHAR AuxData[80];
+
+
+ DWORD DataIndex;
+ DWORD DataIndex2;
+ WORD SeperatorChars;
+ ULONG Index;
+
+
+
+ if( ( Data == NULL ) ||
+ ( Size == 0 ) ) {
+ return;
+ }
+
+ //
+ // DataIndex2 tracks multiples of 16.
+ //
+
+ DataIndex2 = 0;
+
+ //
+ // Display rows of 16 bytes of data.
+ //
+
+ for(DataIndex = 0;
+ DataIndex < ( Size >> 4 );
+ DataIndex++,
+ DataIndex2 = DataIndex << 4 ) {
+
+ //
+ // The string that contains the format in the sprintf below
+ // cannot be broken because cfront on mips doesn't like it.
+ //
+
+ swprintf(AuxData,
+ (LPWSTR)L"%08x %02x %02x %02x %02x %02x %02x %02x %02x - %02x %02x %02x %02x %02x %02x %02x %02x %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c",
+ DataIndex2,
+ Data[ DataIndex2 + 0 ],
+ Data[ DataIndex2 + 1 ],
+ Data[ DataIndex2 + 2 ],
+ Data[ DataIndex2 + 3 ],
+ Data[ DataIndex2 + 4 ],
+ Data[ DataIndex2 + 5 ],
+ Data[ DataIndex2 + 6 ],
+ Data[ DataIndex2 + 7 ],
+ Data[ DataIndex2 + 8 ],
+ Data[ DataIndex2 + 9 ],
+ Data[ DataIndex2 + 10 ],
+ Data[ DataIndex2 + 11 ],
+ Data[ DataIndex2 + 12 ],
+ Data[ DataIndex2 + 13 ],
+ Data[ DataIndex2 + 14 ],
+ Data[ DataIndex2 + 15 ],
+ iswprint( Data[ DataIndex2 + 0 ] )
+ ? Data[ DataIndex2 + 0 ] : ( WCHAR )'.',
+ iswprint( Data[ DataIndex2 + 1 ] )
+ ? Data[ DataIndex2 + 1 ] : ( WCHAR )'.',
+ iswprint( Data[ DataIndex2 + 2 ] )
+ ? Data[ DataIndex2 + 2 ] : ( WCHAR )'.',
+ iswprint( Data[ DataIndex2 + 3 ] )
+ ? Data[ DataIndex2 + 3 ] : ( WCHAR )'.',
+ iswprint( Data[ DataIndex2 + 4 ] )
+ ? Data[ DataIndex2 + 4 ] : ( WCHAR )'.',
+ iswprint( Data[ DataIndex2 + 5 ] )
+ ? Data[ DataIndex2 + 5 ] : ( WCHAR )'.',
+ iswprint( Data[ DataIndex2 + 6 ] )
+ ? Data[ DataIndex2 + 6 ] : ( WCHAR )'.',
+ iswprint( Data[ DataIndex2 + 7 ] )
+ ? Data[ DataIndex2 + 7 ] : ( WCHAR )'.',
+ iswprint( Data[ DataIndex2 + 8 ] )
+ ? Data[ DataIndex2 + 8 ] : ( WCHAR )'.',
+ iswprint( Data[ DataIndex2 + 9 ] )
+ ? Data[ DataIndex2 + 9 ] : ( WCHAR )'.',
+ iswprint( Data[ DataIndex2 + 10 ] )
+ ? Data[ DataIndex2 + 10 ] : ( WCHAR )'.',
+ iswprint( Data[ DataIndex2 + 11 ] )
+ ? Data[ DataIndex2 + 11 ] : ( WCHAR )'.',
+ iswprint( Data[ DataIndex2 + 12 ] )
+ ? Data[ DataIndex2 + 12 ] : ( WCHAR )'.',
+ iswprint( Data[ DataIndex2 + 13 ] )
+ ? Data[ DataIndex2 + 13 ] : ( WCHAR )'.',
+ iswprint( Data[ DataIndex2 + 14 ] )
+ ? Data[ DataIndex2 + 14 ] : ( WCHAR )'.',
+ iswprint( Data[ DataIndex2 + 15 ] )
+ ? Data[ DataIndex2 + 15 ] : ( WCHAR )'.'
+ );
+ SendDlgItemMessage( hDlg, IDD_DISPLAY_DATA_BINARY, LB_ADDSTRING, 0, (LONG)AuxData );
+ }
+
+ //
+ // If the data size is not an even multiple of 16
+ // then there is one additonal line of data to display.
+ //
+
+ if( Size % 16 != 0 ) {
+
+ //
+ // No seperator characters displayed so far.
+ //
+
+ SeperatorChars = 0;
+
+ Index = swprintf( AuxData, (LPWSTR)L"%08x ", DataIndex << 4 );
+
+ //
+ // Display the remaining data, one byte at a time in hex.
+ //
+
+ for( DataIndex = DataIndex2;
+ DataIndex < Size;
+ DataIndex++ ) {
+
+ Index += swprintf( &AuxData[ Index ], (LPWSTR)L"%02x ", Data[ DataIndex ] );
+
+ //
+ // If eight data values have been displayed, print
+ // the seperator.
+ //
+
+ if( DataIndex % 8 == 7 ) {
+
+ Index += swprintf( &AuxData[Index], (LPWSTR)L"%s", (LPWSTR)L"- " );
+
+ //
+ // Remember that two seperator characters were
+ // displayed.
+ //
+
+ SeperatorChars = 2;
+ }
+ }
+
+ //
+ // Fill with blanks to the printable characters position.
+ // That is position 63 less 8 spaces for the 'address',
+ // 3 blanks, 3 spaces for each value displayed, possibly
+ // two for the seperator plus two blanks at the end.
+ //
+
+ Index += swprintf( &AuxData[ Index ],
+ (LPWSTR)L"%*c",
+ 64
+ - ( 8 + 3
+ + (( DataIndex % 16 ) * 3 )
+ + SeperatorChars
+ + 2 ), ' ' );
+
+ //
+ // Display the remaining data, one byte at a time as
+ // printable characters.
+ //
+
+ for(
+ DataIndex = DataIndex2;
+ DataIndex < Size;
+ DataIndex++ ) {
+
+ Index += swprintf( ( AuxData + Index ),
+ (LPWSTR)L"%c",
+ iswprint( Data[ DataIndex ] )
+ ? Data[ DataIndex ] : ( WCHAR )'.'
+ );
+
+ }
+
+ SendDlgItemMessage( hDlg, IDD_DISPLAY_DATA_BINARY, LB_ADDSTRING, 0, (LONG)AuxData );
+
+ }
+}
+
+
+
+
+VOID
+REGISTRY_DATA::DumpBinaryDataAsWords(
+ IN HWND hDlg,
+ IN PCBYTE Data,
+ IN ULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ Display the contents of a buffer in a list box, as WORDs, using
+ an hd-like format.
+
+Arguments:
+
+ Data - Buffer that contains the binary data.
+
+ Size - Number of bytes in the buffer.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ ULONG Index;
+ WCHAR Buffer[ 80 ];
+ ULONG DataIndex;
+ ULONG LineNumber;
+ ULONG WholeLines;
+
+
+ if( ( Data == NULL ) ||
+ ( Size == 0 ) ) {
+ return;
+ }
+
+ //
+ // Display all rows that contain 4 DWORDs.
+ //
+
+ WholeLines = Size / 16;
+ DataIndex = 0;
+ for( LineNumber = 0;
+ LineNumber < WholeLines;
+ LineNumber++,
+ DataIndex += 16 ) {
+
+ //
+ // The string that contains the format in the sprintf below
+ // cannot be broken because cfront on mips doesn't like it.
+ //
+
+ swprintf( Buffer,
+ ( LPWSTR )L"%08x %04x %04x %04x %04x %04x %04x %04x %04x",
+ DataIndex,
+ *( ( PUSHORT )( &Data[ DataIndex + 0 ] ) ),
+ *( ( PUSHORT )( &Data[ DataIndex + 2 ] ) ),
+ *( ( PUSHORT )( &Data[ DataIndex + 4 ] ) ),
+ *( ( PUSHORT )( &Data[ DataIndex + 6 ] ) ),
+ *( ( PUSHORT )( &Data[ DataIndex + 8 ] ) ),
+ *( ( PUSHORT )( &Data[ DataIndex + 10 ] ) ),
+ *( ( PUSHORT )( &Data[ DataIndex + 12 ] ) ),
+ *( ( PUSHORT )( &Data[ DataIndex + 14 ] ) )
+ );
+ SendDlgItemMessage( hDlg, IDD_DISPLAY_DATA_BINARY, LB_ADDSTRING, 0, (LONG)Buffer );
+ }
+
+ //
+ // If the data size is not an even multiple of 16
+ // then there is one additonal line of data to display.
+ //
+
+ if( Size % 16 != 0 ) {
+
+ ULONG NumberOfWords;
+ ULONG Count;
+
+ //
+ // Determine the number of WORDs in the last line
+ //
+
+ NumberOfWords = ( Size % 16 ) / 2;
+
+ //
+ // Build the offset
+ //
+
+ Index = swprintf( Buffer, (LPWSTR)L"%08x ", DataIndex );
+
+ //
+ // Display the remaining words, one at a time in hex.
+ //
+
+ for( Count = 0;
+ Count < NumberOfWords;
+ Count++,
+ DataIndex += 2 ) {
+
+ Index += swprintf( &Buffer[ Index ], (LPWSTR)L"%04x ", *( ( PUSHORT )( &Data[ DataIndex ] ) ) );
+
+ }
+
+ //
+ // Display the remaining byte, if any
+ //
+
+ if( Size % 2 != 0 ) {
+ swprintf( &Buffer[ Index ], (LPWSTR)L"%02x ", Data[ DataIndex ] );
+ }
+
+ SendDlgItemMessage( hDlg, IDD_DISPLAY_DATA_BINARY, LB_ADDSTRING, 0, (LONG)Buffer );
+
+ }
+}
+
+
+VOID
+REGISTRY_DATA::DumpBinaryDataAsDwords(
+ IN HWND hDlg,
+ IN PCBYTE Data,
+ IN ULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ Display the contents of a buffer in a list box, as DWORDs, using
+ an hd-like format.
+
+Arguments:
+
+ Data - Buffer that contains the binary data.
+
+ Size - Number of bytes in the buffer.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ ULONG Index;
+ WCHAR Buffer[ 80 ];
+ ULONG DataIndex;
+ ULONG LineNumber;
+ ULONG WholeLines;
+
+
+ if( ( Data == NULL ) ||
+ ( Size == 0 ) ) {
+ return;
+ }
+
+ //
+ // Display all rows that contain 4 DWORDs.
+ //
+
+ WholeLines = Size / 16;
+ DataIndex = 0;
+ for( LineNumber = 0;
+ LineNumber < WholeLines;
+ LineNumber++,
+ DataIndex += 16 ) {
+
+ //
+ // The string that contains the format in the sprintf below
+ // cannot be broken because cfront on mips doesn't like it.
+ //
+
+ swprintf( Buffer,
+ ( LPWSTR )L"%08x %08x %08x %08x %08x",
+ DataIndex,
+ *( ( PULONG )( &Data[ DataIndex + 0 ] ) ),
+ *( ( PULONG )( &Data[ DataIndex + 4 ] ) ),
+ *( ( PULONG )( &Data[ DataIndex + 8 ] ) ),
+ *( ( PULONG )( &Data[ DataIndex + 12 ] ) )
+ );
+ SendDlgItemMessage( hDlg, IDD_DISPLAY_DATA_BINARY, LB_ADDSTRING, 0, (LONG)Buffer );
+ }
+
+ //
+ // If the data size is not an even multiple of 16
+ // then there is one additonal line of data to display.
+ //
+
+ if( Size % 16 != 0 ) {
+
+ ULONG NumberOfDwords;
+ ULONG Count;
+
+ //
+ // Build the offset
+ //
+
+ Index = swprintf( Buffer, (LPWSTR)L"%08x ", DataIndex );
+
+ //
+ // Determine the number of DWORDs in the last line
+ //
+
+ NumberOfDwords = ( Size % 16 ) / 4;
+
+ //
+ // Display the remaining dwords, one at a time, if any.
+ //
+
+ for( Count = 0;
+ Count < NumberOfDwords;
+ Count++,
+ DataIndex += 4 ) {
+
+ Index += swprintf( &Buffer[ Index ], (LPWSTR)L"%08x ", *( ( PULONG )( &Data[ DataIndex ] ) ) );
+
+ }
+
+ //
+ // Display the remaining word, if any
+ //
+
+ if( ( Size % 16 ) % 4 >= 2 ) {
+ Index += swprintf( &Buffer[ Index ], (LPWSTR)L"%04x ", *( ( PUSHORT )( &Data[ DataIndex ] ) ) );
+ DataIndex += 2;
+ }
+
+ //
+ // Display the remaining byte, if any
+ //
+
+ if( Size % 2 != 0 ) {
+ swprintf( &Buffer[ Index ], (LPWSTR)L"%02x ", Data[ DataIndex ] );
+ }
+
+ SendDlgItemMessage( hDlg, IDD_DISPLAY_DATA_BINARY, LB_ADDSTRING, 0, (LONG)Buffer );
+
+ }
+}
diff --git a/private/utils/regedit/src/regdesc.cxx b/private/utils/regedit/src/regdesc.cxx
new file mode 100644
index 000000000..28d63e995
--- /dev/null
+++ b/private/utils/regedit/src/regdesc.cxx
@@ -0,0 +1,538 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ regdesc.cxx
+
+Abstract:
+
+ This module contains the definitions of the member functions
+ of the following classes: PARTIAL_DESCRIPTOR, PORT_DESCRIPTOR,
+ INTERRUPT_DESCRIPTOR, MEMORY_DESCRIPTOR, DMA_DESCRIPTOR, and
+ DEVICE_SPECIFIC_DESCRIPTOR.
+
+Author:
+
+ Jaime Sasson (jaimes) 02-Dec-1993
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include "ulib.hxx"
+#include "regdesc.hxx"
+
+
+DEFINE_CONSTRUCTOR ( PARTIAL_DESCRIPTOR, OBJECT );
+
+
+PARTIAL_DESCRIPTOR::~PARTIAL_DESCRIPTOR (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy a PARTIAL_DESCRIPTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+}
+
+VOID
+PARTIAL_DESCRIPTOR::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Construct a PARTIAL_DESCRIPTOR object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _Type = 0;
+ _ShareDisposition = 0;
+ _Flags = 0;
+}
+
+#if DBG
+VOID
+PARTIAL_DESCRIPTOR::DbgDumpObject(
+ )
+
+/*++
+
+Routine Description:
+
+ Print a PARTIAL_DESCRIPTOR object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DebugPrintf( "\t\tType = %x \n", _Type );
+ DebugPrintf( "\t\tShareDisposition = %x \n", _ShareDisposition );
+ DebugPrintf( "\t\tFlags = %x \n", _Flags );
+}
+#endif
+
+
+// #include "ulib.hxx"
+// #include "regdesc.hxx"
+
+
+DEFINE_CONSTRUCTOR ( PORT_DESCRIPTOR, PARTIAL_DESCRIPTOR );
+
+
+PORT_DESCRIPTOR::~PORT_DESCRIPTOR (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy a PORT_DESCRIPTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+}
+
+VOID
+PORT_DESCRIPTOR::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Construct a PORT_DESCRIPTOR object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _PhysicalAddress.LowPart = 0;
+ _PhysicalAddress.HighPart = 0;
+ _Length = 0;
+}
+
+#if DBG
+VOID
+PORT_DESCRIPTOR::DbgDumpObject(
+ )
+
+/*++
+
+Routine Description:
+
+ Print a PORT_DESCRIPTOR object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PARTIAL_DESCRIPTOR::DbgDumpObject();
+ DebugPrintf( "\t\tPhisycalAddress.HighPart = %#lx \n", _PhysicalAddress.HighPart );
+ DebugPrintf( "\t\tPhisycalAddress.LowPart = %#lx \n", _PhysicalAddress.LowPart );
+ DebugPrintf( "\t\tLength = %#lx \n\n", _Length );
+}
+#endif
+
+// #include "ulib.hxx"
+// #include "regdesc.hxx"
+
+
+DEFINE_CONSTRUCTOR ( INTERRUPT_DESCRIPTOR, PARTIAL_DESCRIPTOR );
+
+
+INTERRUPT_DESCRIPTOR::~INTERRUPT_DESCRIPTOR (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy a INTERRUPT_DESCRIPTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+}
+
+VOID
+INTERRUPT_DESCRIPTOR::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Construct an INTERRUPT_DESCRIPTOR object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _Affinity = 0;
+ _Level = 0;
+ _Vector = 0;
+}
+
+#if DBG
+VOID
+INTERRUPT_DESCRIPTOR::DbgDumpObject(
+ )
+
+/*++
+
+Routine Description:
+
+ Print a INTERRUPT_DESCRIPTOR object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PARTIAL_DESCRIPTOR::DbgDumpObject();
+ DebugPrintf( "\t\tLevel = %#lx \n", _Level );
+ DebugPrintf( "\t\tVector = %#lx \n", _Vector );
+ DebugPrintf( "\t\tAffinity = %#lx \n\n", _Affinity );
+}
+#endif
+
+
+
+// #include "ulib.hxx"
+// #include "regdesc.hxx"
+
+
+DEFINE_CONSTRUCTOR ( MEMORY_DESCRIPTOR, PARTIAL_DESCRIPTOR );
+
+
+MEMORY_DESCRIPTOR::~MEMORY_DESCRIPTOR (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy a MEMORY_DESCRIPTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+}
+
+VOID
+MEMORY_DESCRIPTOR::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Construct an MEMORY_DESCRIPTOR object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _StartAddress.LowPart = 0;
+ _StartAddress.HighPart = 0;
+ _Length = 0;
+}
+
+#if DBG
+VOID
+MEMORY_DESCRIPTOR::DbgDumpObject(
+ )
+
+/*++
+
+Routine Description:
+
+ Print a MEMORY_DESCRIPTOR object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PARTIAL_DESCRIPTOR::DbgDumpObject();
+ DebugPrintf( "\t\tStartAddress.HighPart = %#lx \n", _StartAddress.HighPart );
+ DebugPrintf( "\t\tStartAddress.LowPart = %#lx \n", _StartAddress.LowPart );
+ DebugPrintf( "\t\tLength = %#lx \n\n", _Length );
+}
+#endif
+
+// #include "ulib.hxx"
+// #include "regdesc.hxx"
+
+
+DEFINE_CONSTRUCTOR ( DMA_DESCRIPTOR, PARTIAL_DESCRIPTOR );
+
+
+DMA_DESCRIPTOR::~DMA_DESCRIPTOR (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy a DMA_DESCRIPTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+}
+
+VOID
+DMA_DESCRIPTOR::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Construct an MEMORY_DESCRIPTOR object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _Channel = 0;
+ _Port = 0;
+ _Reserved1 = 0;
+}
+
+#if DBG
+VOID
+DMA_DESCRIPTOR::DbgDumpObject(
+ )
+
+/*++
+
+Routine Description:
+
+ Print a DMA_DESCRIPTOR object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PARTIAL_DESCRIPTOR::DbgDumpObject();
+ DebugPrintf( "\t\tChannel = %#lx \n", _Channel );
+ DebugPrintf( "\t\tPort = %#lx \n", _Port );
+ DebugPrintf( "\t\tReserved1 = %#lx \n\n", _Reserved1 );
+}
+#endif
+
+
+
+// #include "ulib.hxx"
+// #include "regdesc.hxx"
+
+
+DEFINE_CONSTRUCTOR ( DEVICE_SPECIFIC_DESCRIPTOR, PARTIAL_DESCRIPTOR );
+
+
+DEVICE_SPECIFIC_DESCRIPTOR::~DEVICE_SPECIFIC_DESCRIPTOR (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy a DEVICE_SPECIFIC_DESCRIPTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _DataSize = 0;
+ if( _Data != NULL ) {
+ FREE( _Data );
+ }
+}
+
+VOID
+DEVICE_SPECIFIC_DESCRIPTOR::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Construct an DEVICE_SPECIFIC_DESCRIPTOR object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _Reserved1 = 0;
+ _Reserved2 = 0;
+ _Data = NULL;
+ _DataSize = 0;
+}
+
+#if DBG
+VOID
+DEVICE_SPECIFIC_DESCRIPTOR::DbgDumpObject(
+ )
+
+/*++
+
+Routine Description:
+
+ Print a DEVICE_SPECIFIC_DESCRIPTOR object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PARTIAL_DESCRIPTOR::DbgDumpObject();
+ DebugPrintf( "\t\tDataSize = %#lx \n", _DataSize );
+ DebugPrintf( "\t\tReserved1 = %#lx \n", _Reserved1 );
+ DebugPrintf( "\t\tReserved2 = %#lx \n\n", _Reserved2 );
+}
+#endif
diff --git a/private/utils/regedit/src/regedir.cxx b/private/utils/regedit/src/regedir.cxx
new file mode 100644
index 000000000..c81be95bb
--- /dev/null
+++ b/private/utils/regedit/src/regedir.cxx
@@ -0,0 +1,2353 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ regedir.cxx
+
+Abstract:
+
+ This module contains the methods for the REGEDIT_INTERNAL_REGISTRY class.
+
+Author:
+
+ Jaime Sasson (jaimes) 26-Aug-1991
+
+Environment:
+
+ Regedit, Ulib, Windows, User Mode
+
+--*/
+
+#include "regedir.hxx"
+#include "arrayit.hxx"
+
+
+DEFINE_CONSTRUCTOR( REGEDIT_INTERNAL_REGISTRY, OBJECT );
+
+DEFINE_CAST_MEMBER_FUNCTION( REGEDIT_INTERNAL_REGISTRY );
+
+
+
+REGEDIT_INTERNAL_REGISTRY::~REGEDIT_INTERNAL_REGISTRY(
+)
+/*++
+
+Routine Description:
+
+ Destroy a REGEDIT_INTERNAL_REGISTRY object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+REGEDIT_INTERNAL_REGISTRY::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Worker method for object construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _PredefinedKey = (PREDEFINED_KEY)0;
+ _Registry = NULL;
+}
+
+
+
+VOID
+REGEDIT_INTERNAL_REGISTRY::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Worker method for object destruction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _PredefinedKey = (PREDEFINED_KEY)0;
+ _Registry = NULL;
+}
+
+
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::Initialize(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PREGISTRY Registry,
+ IN PCWSTRING RootName
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize a REGEDIT_INTERNAL_REGISTRY object.
+
+Arguments:
+
+ PredefinedKey - Specifies the predefined key that this object will represent.
+
+ Registry - Pointer to an initialized REGISTRY object.
+
+ RootName - Name of the predefined key represented in this object.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+
+{
+ ULONG ErrorCode;
+ PREGISTRY_KEY_INFO KeyInfo;
+ DSTRING Class;
+ DSTRING Name;
+ DSTRING ParentName;
+
+ DebugPtrAssert( RootName );
+ DebugPtrAssert( Registry );
+
+ DebugAssert( ( PredefinedKey == PREDEFINED_KEY_CLASSES_ROOT ) ||
+ ( PredefinedKey == PREDEFINED_KEY_CURRENT_USER ) ||
+ ( PredefinedKey == PREDEFINED_KEY_LOCAL_MACHINE ) ||
+ ( PredefinedKey == PREDEFINED_KEY_USERS ) ||
+ ( PredefinedKey == PREDEFINED_KEY_CURRENT_CONFIG ) );
+
+ _PredefinedKey = PredefinedKey;
+ _Registry = Registry;
+ if( !_RootName.Initialize( RootName ) ) {
+ DebugPrint( "_RootName.Initialize() failed" );
+ return( FALSE );
+ }
+
+ if( !Name.Initialize( ( PSTR )"" ) ) {
+ DebugPrint( "Name.Initialize() failed" );
+ return( FALSE );
+ }
+ if( !ParentName.Initialize( ( PSTR )"" ) ) {
+ DebugPrint( "ParentName.Initialize() failed" );
+ return( FALSE );
+ }
+
+ if( !Class.Initialize( ( PSTR )"" ) ) {
+ DebugPrint( "Class.Initialize() failed" );
+ return( FALSE );
+ }
+
+ KeyInfo = ( PREGISTRY_KEY_INFO ) NEW( REGISTRY_KEY_INFO );
+ DebugPtrAssert( KeyInfo );
+
+ if( !_Registry->QueryKeyInfo( _PredefinedKey,
+ &ParentName,
+ &Name,
+ KeyInfo,
+ &ErrorCode ) ) {
+
+ DebugPrint( "_Registry->QueryKeyInfo() failed" );
+ DebugPrintf( "_Registry->QueryKeyInfo() failed, ErrorCode = %#x \n", ErrorCode );
+ DELETE( KeyInfo );
+ return( FALSE );
+ }
+
+ if( !_RootNode.Initialize( KeyInfo, NULL, 0, TRUE, TRUE ) ) {
+ DebugPrint( "_RootNode.Initialize() failed" );
+ return( FALSE );
+ }
+ //
+ // Note that KeyInfo is not deleted. This is because it is kept in
+ // _RootNode
+ //
+
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::AddValue(
+ IN PCREGEDIT_NODE Node,
+ IN PREGEDIT_FORMATTED_VALUE_ENTRY Value,
+ IN BOOLEAN FailIfExists,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Add a value entry to an existing node.
+
+Arguments:
+
+
+ Node - Pointer to the object that contains the information about the
+ the node where the value will be created. This object will be
+ updated to reflect the addition of a new value.
+
+ Value - Pointer to the object that contains the information about the
+ value to be created.
+
+ FailIfExists - A flag that indicates if the method should fail if a
+ value entry with the same name already exists.
+
+ ErrorCode - Pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+{
+ PREGISTRY_KEY_INFO KeyInfo;
+ PCREGISTRY_VALUE_ENTRY ValueEntry;
+ PSORTED_LIST TmpList;
+
+ DebugPtrAssert( Node );
+ DebugPtrAssert( Value );
+ DebugPtrAssert( ErrorCode );
+
+
+ //
+ // First check whether the list of values in Node are loaded in
+ // memory.
+ //
+ if( Node->GetNumberOfValues() == 0 ) {
+ //
+ // The node doesn't have any value
+ //
+ TmpList = ( PSORTED_LIST ) NEW( SORTED_LIST );
+ DebugPtrAssert( TmpList );
+ if( ( TmpList == NULL ) ||
+ ( !TmpList->Initialize() ) ) {
+ DebugPrint( "TmpList->Initilize() failed" );
+ *ErrorCode = REGEDIT_ERROR_INITIALIZATION_FAILURE;
+ DELETE( TmpList );
+ return( FALSE );
+ }
+ ( ( PREGEDIT_NODE )Node )->SetValues( TmpList );
+
+ }
+
+ //
+ // Now that there is a list of values in memory, create a new value
+ // in the registry
+ //
+
+ KeyInfo = Node->GetKeyInfo();
+ DebugPtrAssert( KeyInfo );
+
+ ValueEntry = Value->GetValueEntry();
+ DebugPtrAssert( ValueEntry );
+
+ if( !_Registry->AddValueEntry( _PredefinedKey,
+ KeyInfo,
+ ValueEntry,
+ FailIfExists,
+ ErrorCode ) ) {
+
+ DebugPrint( "Registry->AddValueEntry() failed" );
+ DebugPrintf( "Registry->AddValueEntry() failed, ErrorCode = %#x \n", *ErrorCode );
+ *ErrorCode = MapRegistryToRegeditError( *ErrorCode );
+ return( FALSE );
+ }
+
+ //
+ // If the value was created successfully, add Value to the list of
+ // values in Node
+ //
+
+ if( !( ( PREGEDIT_NODE )Node )->AddValueToListOfValues( Value ) ) {
+ DebugPrint( "Node-AddValueToListOfValues() failed" );
+ *ErrorCode = REGEDIT_ERROR_NODE_NOT_UPDATED;
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::ChangeValueData(
+ IN PCREGEDIT_NODE Node,
+ IN PCREGEDIT_FORMATTED_VALUE_ENTRY Value,
+ IN PCBYTE NewData,
+ IN ULONG Size,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Change the data of an existing value entry.
+
+Arguments:
+
+
+ Node - Pointer to the object that contains the information about the
+ the node that contains the value entry to be modified.
+ This object will be updated to reflect the modification on its
+ value entry.
+
+ Value - Pointer to the object that contains the information about the
+ value entry to be modified.
+
+ NewData - Pointer to the buffer that contains the new data.
+
+ Size - Size of the buffer that contains the new data.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+{
+ PREGISTRY_KEY_INFO KeyInfo;
+ PREGISTRY_VALUE_ENTRY NewValueEntry;
+
+ DebugPtrAssert( Node );
+ DebugPtrAssert( Value );
+ DebugPtrAssert( NewData );
+
+ //
+ // If a value is being modified, then the list of values should
+ // be loaded in memory.
+ //
+
+ DebugPtrAssert( Node->GetValues() );
+// DebugAssert( Node->GetNumberOfValues() != 0 );
+
+ //
+ // Now that there is a list of values in memory, create a new value
+ // in the registry
+ //
+
+ KeyInfo = Node->GetKeyInfo();
+ DebugPtrAssert( KeyInfo );
+
+ NewValueEntry = ( PREGISTRY_VALUE_ENTRY )NEW( REGISTRY_VALUE_ENTRY );
+ DebugPtrAssert( NewValueEntry );
+
+ if( !NewValueEntry->Initialize( Value->GetName(),
+ Value->GetTitleIndex(),
+ Value->GetType(),
+ NewData,
+ Size ) ) {
+ DebugPrint( "TmpNewValueEntry->Initilaize() failed" );
+ *ErrorCode = REGEDIT_ERROR_INITIALIZATION_FAILURE;
+ return( FALSE );
+ }
+
+ if( !_Registry->AddValueEntry( _PredefinedKey,
+ KeyInfo,
+ NewValueEntry,
+ FALSE,
+ ErrorCode ) ) {
+
+ DebugPrint( "Registry->AddValueEntry() failed" );
+ DebugPrintf( "Registry->AddValueEntry() failed, ErrorCode = %#x \n", *ErrorCode );
+ *ErrorCode = MapRegistryToRegeditError( *ErrorCode );
+ return( FALSE );
+ }
+
+ //
+ // If the value was created successfully, update the value entry that
+ // was modified so that it contains the new data.
+ //
+ if( !( ( PREGEDIT_FORMATTED_VALUE_ENTRY )Value )->Initialize( NewValueEntry ) ) {
+ DebugPrint( "Value->Initialize() failed" );
+ *ErrorCode = REGEDIT_ERROR_NODE_NOT_UPDATED;
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::CreateChildNode(
+ IN PCREGEDIT_NODE ParentNode,
+ IN PREGISTRY_KEY_INFO ChildKeyInfo,
+ OUT PCREGEDIT_NODE* ChildNode,
+ OUT PULONG ErrorCode,
+ IN BOOLEAN Volatile
+ )
+
+/*++
+
+Routine Description:
+
+ Copy all value entries from a key to another key.
+
+Arguments:
+
+
+ ParentNode - The node where a child is to be added.
+
+ ChildKeyInfo - A REGISTRY_KEY_INFO object that describes the key to be created.
+
+ ChildNode - Address of the pointer to a node object that will represent the
+ node just created.
+
+ ErrorCode - Pointer to a variable that will contain an error
+ code if the operation fails.
+
+ Volatile - Informs whether to create a volatile or non-volatile key.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+
+{
+ PREGISTRY_KEY_INFO KeyInfo;
+ PSORTED_LIST TmpList;
+ PREGEDIT_NODE TmpNode;
+
+ DebugPtrAssert( ParentNode );
+ DebugPtrAssert( ChildKeyInfo );
+ DebugPtrAssert( ChildNode );
+
+ //
+ // First check whether the list of children in Node is loaded in
+ // memory.
+ //
+ if( ParentNode->GetNumberOfChildren() == 0 ) {
+ //
+ // The node doesn't have any children
+ //
+ TmpList = ( PSORTED_LIST ) NEW( SORTED_LIST );
+ DebugPtrAssert( TmpList );
+ if( ( TmpList == NULL ) ||
+ ( !TmpList->Initialize() ) ) {
+ DebugPrint( "TmpList->Initilize() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGEDIT_ERROR_INITIALIZATION_FAILURE;
+ }
+ DELETE( TmpList );
+ return( FALSE );
+ }
+ ( ( PREGEDIT_NODE )ParentNode )->SetChildren( TmpList );
+
+ } else {
+ //
+ // The node has children
+ //
+ TmpList = GetChildren( ParentNode, ErrorCode );
+ DebugPtrAssert( TmpList );
+ }
+
+ //
+ // Now that there is a list of children is in memory, create a new
+ // sub key in the registry
+ //
+
+ KeyInfo = ParentNode->GetKeyInfo();
+ DebugPtrAssert( KeyInfo );
+
+ if( !_Registry->CreateKey( _PredefinedKey,
+ KeyInfo,
+ ChildKeyInfo,
+ ErrorCode,
+ Volatile ) ) {
+
+ DebugPrint( "Registry->CreateKey() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapRegistryToRegeditError( *ErrorCode );
+ DebugPrintf( "Registry->CreateKey() failed, ErrorCode = %#x \n", *ErrorCode );
+ }
+ return( FALSE );
+ }
+
+ //
+ // If the key was created successfully, add NewNode to the list of
+ // Children in Node
+ //
+ TmpNode = ( PREGEDIT_NODE ) NEW( REGEDIT_NODE );
+ DebugPtrAssert( TmpNode );
+
+ if( !TmpNode->Initialize( ChildKeyInfo,
+ ParentNode,
+ ParentNode->GetLevel() + 1,
+ TRUE,
+ FALSE ) ) {
+ DebugPrint( "TmpNode->Initialize() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGEDIT_ERROR_INITIALIZATION_FAILURE;
+ }
+ return( FALSE );
+ }
+ *ChildNode = TmpNode;
+
+ if( !( (PREGEDIT_NODE )ParentNode )->AddChildToListOfChildren( TmpNode ) ) {
+ DebugPrint( "ParentNode->AddValueToListOfValues() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGEDIT_ERROR_UNKNOWN_ERROR;
+ }
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+
+
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::DeleteNode(
+ IN PREGEDIT_NODE Node,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Delete a node and all its children.
+
+Arguments:
+
+
+ Node - The node to be deleted.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+{
+ PREGEDIT_NODE ParentNode;
+ PREGISTRY_KEY_INFO ParentKeyInfo;
+ PCWSTRING KeyName;
+
+
+
+ ParentNode = ( PREGEDIT_NODE )Node->GetParentNode();
+ if( ParentNode == NULL ) {
+ //
+ // Trying to delete a predefined key
+ //
+ *ErrorCode = REGEDIT_ERROR_ACCESS_DENIED;
+ return( FALSE );
+ }
+
+ ParentKeyInfo = ParentNode->GetKeyInfo();
+ DebugPtrAssert( ParentKeyInfo );
+
+ KeyName = Node->GetKeyInfo()->GetName();
+ DebugPtrAssert( KeyName );
+
+ if( !_Registry->DeleteKey( _PredefinedKey,
+ ParentKeyInfo,
+ KeyName,
+ ErrorCode ) ) {
+
+ ( ( PREGEDIT_NODE )Node )->DeleteListOfChildren();
+ DebugPrint( "_Registry->DeleteKey() failed" );
+ DebugPrintf( "_Registry->DeleteKey() failed, ErrorCode = %#x \n", *ErrorCode );
+ *ErrorCode = MapRegistryToRegeditError( *ErrorCode );
+ return( FALSE );
+ }
+
+ if( !ParentNode->RemoveChildFromListOfChildren( Node ) ) {
+ DebugPrint( "ParentNode->removeChildFromListOfChildren() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGEDIT_ERROR_UNKNOWN_ERROR;
+ }
+ return( FALSE );
+ }
+ DELETE( Node );
+ return( TRUE );
+}
+
+
+
+
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::DeleteValue(
+ IN PCREGEDIT_NODE Node,
+ IN PREGEDIT_FORMATTED_VALUE_ENTRY Value,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Delete a value entry from a key.
+
+Arguments:
+
+
+ Node - Pointer to the object that contains the information about the
+ the node that has the value to be deleted. This object will be
+ updated to reflect the deletion of a new value.
+
+ Value - Pointer to the object that represents the value to be deleted.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+{
+ DebugPtrAssert( Node );
+ DebugPtrAssert( Value );
+
+ PCWSTRING ValueName;
+ PREGISTRY_KEY_INFO KeyInfo;
+ PCREGISTRY_VALUE_ENTRY ValueEntry;
+
+
+ KeyInfo = Node->GetKeyInfo();
+ DebugPtrAssert( KeyInfo );
+
+ ValueEntry = Value->GetValueEntry();
+ DebugPtrAssert( ValueEntry );
+
+ ValueName = ValueEntry->GetName();
+ DebugPtrAssert( ValueName );
+
+ if( !_Registry->DeleteValueEntry( _PredefinedKey,
+ KeyInfo,
+ ValueName,
+ ErrorCode ) ) {
+ DebugPrint( "_Registry->DeleteValueEntry() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapRegistryToRegeditError( *ErrorCode );
+ DebugPrintf( "_Registry->DeleteValueEntry() failed, ErrorCode = %#x \n",
+ *ErrorCode );
+ }
+ return( FALSE );
+ }
+
+ if( !( ( PREGEDIT_NODE )Node )->RemoveValueFromListOfValues( Value ) ) {
+ DebugPrint( "Node->RemoveValueFromListOfValues() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGEDIT_ERROR_UNKNOWN_ERROR;
+ }
+ return( FALSE );
+ }
+ DELETE( Value );
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::DoesChildNodeExist(
+ IN PCREGEDIT_NODE Node,
+ IN PCWSTRING ChildName,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Determine whether a key exists.
+
+Arguments:
+
+
+ Node - Pointer to the object that represents the parent of the node
+ to be checked.
+
+ ChildName - Name of the node to be checked.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+{
+ DSTRING TmpName;
+
+ DebugPtrAssert( Node );
+ if( !Node->QueryCompleteName( &TmpName ) ) {
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGEDIT_ERROR_INITIALIZATION_FAILURE;
+ }
+ return( FALSE );
+ }
+ if( !_Registry->DoesKeyExist( _PredefinedKey,
+ &TmpName,
+ ChildName,
+ ErrorCode ) ) {
+ *ErrorCode = MapRegistryToRegeditError( *ErrorCode );
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::DoesValueExist(
+ IN PCREGEDIT_NODE Node,
+ IN PCREGEDIT_FORMATTED_VALUE_ENTRY Value,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Determine whether a value entry exists.
+
+Arguments:
+
+
+ Node - Pointer to the object that represents the key that conatins
+ the value to be checked.
+
+ Value - Pointer to the object that represents the object to be checked.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+{
+ PREGISTRY_KEY_INFO KeyInfo;
+ PCWSTRING ParentName;
+ PCWSTRING KeyName;
+ PCREGISTRY_VALUE_ENTRY ValueEntry;
+ PCWSTRING ValueName;
+
+
+ DebugPtrAssert( Node );
+ DebugPtrAssert( Value );
+
+ KeyInfo = Node->GetKeyInfo();
+ DebugPtrAssert( KeyInfo );
+
+ ParentName = KeyInfo->GetParentName();
+ DebugPtrAssert( ParentName );
+
+ KeyName = KeyInfo->GetName();
+ DebugPtrAssert( KeyName );
+
+ ValueEntry = Value->GetValueEntry();
+ DebugPtrAssert( ValueEntry );
+
+ ValueName = ValueEntry->GetName();
+ DebugPtrAssert( ValueName );
+
+ if( !_Registry->DoesValueExist( _PredefinedKey,
+ ParentName,
+ KeyName,
+ ValueName,
+ ErrorCode ) ) {
+ *ErrorCode = MapRegistryToRegeditError( *ErrorCode );
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+
+
+PSORTED_LIST
+REGEDIT_INTERNAL_REGISTRY::GetChildren(
+ IN PCREGEDIT_NODE Node,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Return a list of pointers to REGEDIT_NODE objects, each object containing
+ the information of a subkey.
+
+Arguments:
+
+
+ Node - Pointer to the object that represents the key that conatins
+ the subkeys to be retrieved.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ PSORTED_LIST - Returns the pointer to a list that contains the children, or
+ NULL if the operation fails
+
+
+--*/
+
+
+{
+ PSORTED_LIST TmpList;
+ PARRAY SubKeys;
+ PCWSTRING ParentName;
+ PCWSTRING KeyName;
+ PITERATOR Iterator;
+ ULONG Count;
+ ULONG Index;
+ ULONG ChildLevel;
+ PREGISTRY_KEY_INFO TmpKeyInfo;
+ PREGEDIT_NODE TmpNode;
+
+
+ DebugPtrAssert( Node );
+
+ //
+ // If node has no children, return NULL
+ //
+ if( Node->GetNumberOfChildren() == 0 ) {
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGEDIT_ERROR_UNKNOWN_ERROR;
+ }
+ return( NULL );
+ }
+
+ //
+ // If node has children and they are loaded in memory, return pointer
+ // to the list of children
+ //
+
+ if( ( TmpList = Node->GetChildren() ) != NULL ) {
+ return( TmpList );
+ }
+
+ //
+ // If node has children but they are not loaded in memory, load them
+ // in memory
+ //
+
+ SubKeys = ( PARRAY )NEW( ARRAY );
+ DebugPtrAssert( SubKeys );
+
+ if( !SubKeys->Initialize() ) {
+ DebugPrint( "SubKeys->Initialize() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = 0;
+ }
+ return( FALSE );
+ }
+
+ ParentName = Node->GetKeyInfo()->GetParentName();
+ DebugPtrAssert( ParentName );
+ KeyName = Node->GetKeyInfo()->GetName();
+ DebugPtrAssert( KeyName );
+
+ if( !_Registry->QuerySubKeysInfo( _PredefinedKey,
+ ParentName,
+ KeyName,
+ SubKeys,
+ ErrorCode ) ) {
+ *ErrorCode = MapRegistryToRegeditError( *ErrorCode );
+ DebugPrint( "QuerySubKeys() failed" );
+ DELETE( SubKeys );
+ return( NULL );
+ }
+
+ Count = SubKeys->QueryMemberCount();
+
+ Iterator = SubKeys->QueryIterator();
+ DebugPtrAssert( Iterator );
+
+ TmpList = ( PSORTED_LIST )NEW( SORTED_LIST );
+ DebugPtrAssert( TmpList );
+ if( ( TmpList == NULL ) ||
+ ( !TmpList->Initialize() ) ){
+ DebugPrint( "TmpList->Initialize() failed" );
+ DELETE( TmpList );
+ DELETE( Iterator );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGEDIT_ERROR_INITIALIZATION_FAILURE;
+ }
+ return( NULL );
+ }
+
+
+ ChildLevel = ( Node->GetLevel() ) + 1;
+ Index = 0;
+ while( ( TmpKeyInfo = ( PREGISTRY_KEY_INFO )Iterator->GetNext() ) != NULL ) {
+ TmpNode = ( PREGEDIT_NODE ) NEW( REGEDIT_NODE );
+ DebugPtrAssert( TmpNode );
+
+ TmpNode->Initialize( TmpKeyInfo,
+ Node,
+ ChildLevel,
+ FALSE, // ( Index == 0 )? TRUE : FALSE,
+ FALSE //( Index == Count-1 )? TRUE : FALSE
+ );
+
+
+ TmpList->Put( TmpNode );
+ Index++;
+ }
+
+ DELETE( Iterator );
+ DELETE( SubKeys );
+
+ Iterator = TmpList->QueryIterator();
+ if( Iterator == NULL ) {
+ DebugPrint( "Unable to get iterator" );
+ return( TmpList );
+ }
+ Index = 0;
+ Count = TmpList->QueryMemberCount();
+ while( ( TmpNode = ( PREGEDIT_NODE )Iterator->GetNext() ) != NULL ) {
+ TmpNode->SetPosition( ( Index == 0 )? TRUE : FALSE,
+ ( Index == Count - 1 )? TRUE : FALSE );
+ Index++;
+
+ }
+ DELETE( Iterator );
+
+ ( ( PREGEDIT_NODE )Node )->SetChildren( TmpList );
+ return( TmpList );
+}
+
+
+
+PSORTED_LIST
+REGEDIT_INTERNAL_REGISTRY::GetValues(
+ IN PCREGEDIT_NODE Node,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Return a list of pointers to REGEDIT_FORMATTED_VALUE_ENTRY objects, each
+ object containing the information of a value entry.
+
+Arguments:
+
+
+ Node - Pointer to the object that represents the key that conatins
+ the values to be retrieved.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ PSORTED_LIST - Returns the pointer to a list that contains the values, or
+ NULL if the operation fails
+
+
+--*/
+
+
+{
+ PSORTED_LIST TmpList;
+ PARRAY Values;
+ PCWSTRING ParentName;
+ PCWSTRING KeyName;
+ PITERATOR Iterator;
+ ULONG Count;
+ ULONG Index;
+ PREGEDIT_FORMATTED_VALUE_ENTRY TmpFormattedValue;
+ PREGISTRY_VALUE_ENTRY TmpValue;
+
+
+ DebugPtrAssert( Node );
+
+
+ //
+ // If node has no values, return NULL
+ //
+ if( Node->GetNumberOfValues() == 0 ) {
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGEDIT_ERROR_UNKNOWN_ERROR;
+ }
+ return( NULL );
+ }
+
+ //
+ // If node has values and they are loaded in memory, return pointer
+ // to the list of values
+ //
+
+ if( ( TmpList = Node->GetValues() ) != NULL ) {
+#if DBG
+ if( TmpList->QueryMemberCount() != Node->GetNumberOfValues() ) {
+
+ DebugPrintf( "TmpList->QueryMemberCount() = %d, Node->GetNumberOfValues() = %d, _PredefinedKey = %d \n",
+ TmpList->QueryMemberCount(),
+ Node->GetNumberOfValues(),
+ _PredefinedKey );
+ DebugPrint( "TmpList->QueryMemberCount() != Node->GetNumberOfValues()" );
+
+ }
+#endif
+ return( TmpList );
+ }
+
+ //
+ // If node has children but they are not loaded in memory, load them
+ // in memory
+ //
+
+ Values = ( PARRAY )NEW( ARRAY );
+ DebugPtrAssert( Values );
+
+ if( ( Values == NULL ) ||
+ ( !Values->Initialize() ) ) {
+ DebugPrint( "Values->Initialize() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = 0;
+ }
+ return( FALSE );
+ }
+
+ ParentName = Node->GetKeyInfo()->GetParentName();
+ DebugPtrAssert( ParentName );
+ KeyName = Node->GetKeyInfo()->GetName();
+ DebugPtrAssert( KeyName );
+
+ if( !_Registry->QueryValues( _PredefinedKey,
+ ParentName,
+ KeyName,
+ Values,
+ ErrorCode ) ) {
+ *ErrorCode = MapRegistryToRegeditError( *ErrorCode );
+ DebugPrint( "QueryValues() failed" );
+ DELETE( Values );
+ return( NULL );
+ }
+
+ Count = Values->QueryMemberCount();
+
+#if DBG
+ if( Count != Node->GetNumberOfValues() ) {
+ DebugPrintf( "Count = %d, Node->GetNumberOfValues() = %d \n",
+ Count,
+ Node->GetNumberOfValues() );
+
+ DebugPrint( "Count != Node->GetNumberOfValues()" );
+ }
+#endif
+ Iterator = Values->QueryIterator();
+ DebugPtrAssert( Iterator );
+
+ TmpList = ( PSORTED_LIST )NEW( SORTED_LIST );
+ DebugPtrAssert( TmpList );
+ if( ( TmpList == NULL ) ||
+ ( !TmpList->Initialize() ) ) {
+ DebugPrint( "TmpList->Initialize() failed" );
+ DELETE( TmpList );
+ DELETE( Iterator );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGEDIT_ERROR_INITIALIZATION_FAILURE;
+ }
+ return( NULL );
+ }
+
+ Index = 0;
+ while( ( TmpValue = ( PREGISTRY_VALUE_ENTRY )Iterator->GetNext() ) != NULL ) {
+ TmpFormattedValue = ( PREGEDIT_FORMATTED_VALUE_ENTRY ) NEW( REGEDIT_FORMATTED_VALUE_ENTRY );
+ DebugPtrAssert( TmpFormattedValue );
+
+ TmpFormattedValue->Initialize( TmpValue );
+
+ TmpList->Put( TmpFormattedValue );
+ Index++;
+ }
+
+#if DBG
+ if( Index != Count ) {
+ DebugPrintf( "ERROR: Index = %d, Count = %d \n", Index, Count );
+ }
+#endif
+ DELETE( Iterator );
+ DELETE( Values );
+ ( ( PREGEDIT_NODE )Node )->SetValues( TmpList );
+ return( TmpList );
+}
+
+
+
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::QueryNodeSecurity(
+ IN PCREGEDIT_NODE Node,
+ IN SECURITY_INFORMATION SecurityInformation,
+ OUT PSECURITY_DESCRIPTOR* SecurityDescriptor,
+ OUT PULONG ErrorCode
+ )
+/*++
+
+Routine Description:
+
+ Retrieve the security descriptor of a node.
+
+Arguments:
+
+ Node - Pointer to the object that represents the key whose security
+ descriptor is to be retrieved.
+
+
+ SecurityInformation - Indicates the type of security descriptor to
+ be retrieved.
+
+ SecurityDescriptor - Address of the variable that will contain the
+ pointer to the security descriptor, if the
+ operation succeeds.
+
+ ErrorCode - Will contain an error code if the operation fail.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the security descriptor could be retrieved.
+ Returns FALSE otherwise.
+
+--*/
+
+
+{
+ PREGISTRY_KEY_INFO KeyInfo;
+
+ DebugPtrAssert( Node );
+ DebugPtrAssert( SecurityDescriptor );
+
+ KeyInfo = Node->GetKeyInfo();
+ if( !_Registry->QueryKeySecurity( _PredefinedKey,
+ KeyInfo,
+ SecurityInformation,
+ SecurityDescriptor,
+ ErrorCode ) ) {
+ *ErrorCode = MapRegistryToRegeditError( *ErrorCode );
+ DebugPrint( "_Registry->QueryKeySecurity() failed" );
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::SetNodeSecurity(
+ IN PCREGEDIT_NODE Node,
+ IN SECURITY_INFORMATION SecurityInformation,
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ OUT PULONG ErrorCode,
+ IN BOOLEAN Recurse
+ )
+/*++
+
+Routine Description:
+
+ Set the security descriptor of a node.
+
+Arguments:
+
+ Node - Pointer to the object that represents the key whose security
+ descriptor is to be set.
+
+
+ SecurityInformation - Indicates the type of security descriptor to
+ be set.
+
+ SecurityDescriptor - Pointer to the security descriptor to be set.
+
+ ErrorCode - Will contain an error code if the operation fail.
+
+ Recurse - Indicates whether the new security descriptor is to be
+ appplied recursively to all subkeys.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the security descriptor could be set.
+ Returns FALSE otherwise.
+
+--*/
+
+
+{
+ PREGISTRY_KEY_INFO KeyInfo;
+
+ DebugPtrAssert( Node );
+ DebugPtrAssert( SecurityDescriptor );
+
+ KeyInfo = Node->GetKeyInfo();
+ if( !_Registry->SetKeySecurity( _PredefinedKey,
+ KeyInfo,
+ SecurityInformation,
+ SecurityDescriptor,
+ ErrorCode,
+ Recurse ) ) {
+ DebugPrint( "_Registry->SetKeySecurity() failed" );
+ *ErrorCode = MapRegistryToRegeditError( *ErrorCode );
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+
+
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::IsKeyInListOfChildren(
+ IN PCWSTRING NodeName,
+ IN PSORTED_LIST Children
+ )
+
+/*++
+
+Routine Description:
+
+ Determine whether the list of children received as parameter contains
+ a node of a particular name.
+
+Arguments:
+
+ NodeName - Name of the node to be checked.
+
+ Children - List of PREGEDIT_NODE objects.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the list of nodes contains a node with
+ the name specified. Returns FALSE otherwise.
+
+--*/
+
+{
+ ULONG Count;
+ PCREGEDIT_NODE TmpNode;
+ PCREGISTRY_KEY_INFO KeyInfo;
+ PCWSTRING TmpName;
+ PITERATOR Iterator;
+
+
+ DebugPtrAssert( Children );
+ DebugPtrAssert( NodeName );
+
+ if( ( Count = Children->QueryMemberCount() ) == 0 ) {
+ return( FALSE );
+ }
+ Iterator = Children->QueryIterator();
+ if( Iterator == NULL ) {
+ DebugPrint( "Unable to get iterator" );
+ return( FALSE );
+ }
+ while( ( ( TmpNode = ( PCREGEDIT_NODE )Iterator->GetNext() ) != NULL ) &&
+ ( ( KeyInfo = TmpNode->GetKeyInfo() ) != NULL ) &&
+ ( ( TmpName = KeyInfo->GetName() ) != NULL ) ) {
+ if( TmpName->Stricmp( NodeName ) == 0 ) {
+ DELETE( Iterator );
+ return( TRUE );
+ }
+ }
+ DELETE( Iterator );
+ return( FALSE );
+
+}
+
+
+
+
+VOID
+REGEDIT_INTERNAL_REGISTRY::UpdateSubTree(
+ IN PREGEDIT_NODE Root
+ )
+
+/*++
+
+Routine Description:
+
+ Determine if any changed occured in the subtree whose root is passed as
+ parameter, and update the subtree to reflect the new changes.
+
+Arguments:
+
+ Root - Node that represents the root of the tree to be updated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREGISTRY_KEY_INFO TmpKeyInfo;
+// PSTR DbgNodeNameSTR;
+// WSTRING DbgNodeName;
+ DSTRING CompleteNodeName;
+ PSORTED_LIST Children;
+ PITERATOR Iterator;
+ ULONG Count;
+ ULONG Index;
+ PREGEDIT_NODE TmpNode;
+ PREGEDIT_NODE RemovedNode;
+ PCWSTRING ParentName;
+ PCWSTRING KeyName;
+ ARRAY NewSubKeysInfo;
+
+
+
+ DebugPtrAssert( Root );
+
+ ( ( PREGEDIT_NODE )Root )->DeleteListOfValues();
+// ( ( PREGEDIT_NODE )Root )->QueryCompleteName( &DbgNodeName );
+// DbgNodeNameSTR = DbgNodeName.QuerySTR();
+// DebugPtrAssert( DbgNodeNameSTR );
+// DebugPrintf( "Removing values from %s \n", DbgNodeNameSTR );
+ TmpKeyInfo = ( ( PREGEDIT_NODE )Root )->GetKeyInfo();
+ DebugPtrAssert( TmpKeyInfo );
+ if( !_Registry->UpdateKeyInfo( _PredefinedKey, TmpKeyInfo ) ) {
+ ( ( PREGEDIT_NODE )Root )->DeleteListOfChildren();
+// DebugPrint( "Unable to update KeyInfo" );
+ return;
+ }
+
+ if( TmpKeyInfo->GetNumberOfSubKeys() == 0 ) {
+ ( ( PREGEDIT_NODE )Root )->DeleteListOfChildren();
+// DebugPrintf( "Number of Subkeys in node %s is 0 \n", DbgNodeNameSTR );
+ return;
+ }
+
+ Children = ( ( PREGEDIT_NODE )Root )->GetChildren();
+ if( Children == NULL ) {
+// DebugPrintf( "Children of %s are not in memory \n", DbgNodeNameSTR );
+ return;
+ }
+ Iterator = Children->QueryIterator();
+ if( Iterator == NULL ) {
+ DebugPrint( "Unable to get iterator" );
+ return;
+ }
+ while( ( TmpNode = ( PREGEDIT_NODE )Iterator->GetPrevious() ) != NULL ) {
+ KeyName = ( ( PREGEDIT_NODE )TmpNode )->GetKeyInfo()->GetName();
+ ParentName = ( ( PREGEDIT_NODE )TmpNode )->GetParentName();
+ if( !_Registry->DoesKeyExist( _PredefinedKey, ParentName, KeyName ) ) {
+ RemovedNode = ( PREGEDIT_NODE )Children->Remove( Iterator );
+// DebugPrintf( "Removing %s \n", DbgNodeNameSTR );
+ DELETE( RemovedNode );
+ } else {
+ UpdateSubTree( TmpNode );
+ }
+ }
+ DELETE( Iterator );
+
+ if( !NewSubKeysInfo.Initialize() ) {
+ DebugPrint( "NewKeyInfo.Initialize() failed" );
+ return;
+ }
+
+ KeyName = ( ( PREGEDIT_NODE )Root )->GetKeyInfo()->GetName();
+ ParentName = ( ( PREGEDIT_NODE )Root )->GetParentName();
+ if( !_Registry->QuerySubKeysInfo( _PredefinedKey, ParentName, KeyName, &NewSubKeysInfo ) ) {
+ ( ( PREGEDIT_NODE )Root )->DeleteListOfChildren();
+ return;
+ }
+
+
+ Iterator = NewSubKeysInfo.QueryIterator();
+ if( Iterator == NULL ) {
+ DebugPrint( "Unable to get iterator" );
+ return;
+ }
+ while( ( TmpKeyInfo = ( PREGISTRY_KEY_INFO )Iterator->GetPrevious() ) != NULL ) {
+// DebugPrintf( "Reading Sub Keys of node %s, Count = %d \n", DbgNodeNameSTR, Count );
+ KeyName = TmpKeyInfo->GetName();
+ DebugPtrAssert( KeyName );
+ if( IsKeyInListOfChildren( KeyName, Children ) ) {
+ NewSubKeysInfo.Remove( Iterator );
+ DELETE( TmpKeyInfo );
+ }
+ }
+
+ Iterator->Reset();
+
+// Count = NewSubKeysInfo.QueryMemberCount();
+// DebugPrintf( "New count in node %s is NewCount = %d \n", DbgNodeNameSTR, Count );
+ while( ( TmpKeyInfo = ( PREGISTRY_KEY_INFO )Iterator->GetNext() ) != NULL ) {
+ TmpNode = ( PREGEDIT_NODE )NEW( REGEDIT_NODE );
+ DebugPtrAssert( TmpNode );
+ if( ( TmpNode == NULL ) ||
+ !TmpNode->Initialize( TmpKeyInfo, Root, Root->GetLevel() + 1, FALSE, FALSE ) ) {
+ DebugPrint( "TmpNode->Initialize() failed" );
+ DELETE( TmpNode );
+ continue;
+ }
+ Children->Put( TmpNode );
+ }
+ DELETE( Iterator );
+
+ Iterator = Children->QueryIterator();
+ if( Iterator == NULL ) {
+ DebugPrint( "Unable to get iterator" );
+ return;
+ }
+ Index = 0;
+ Count = Children->QueryMemberCount();
+ while( ( TmpNode = ( PREGEDIT_NODE )Iterator->GetNext() ) != NULL ) {
+ TmpNode->SetPosition( ( Index == 0 )? TRUE : FALSE,
+ ( Index == Count - 1 )? TRUE : FALSE );
+ Index++;
+
+ }
+ DELETE( Iterator );
+// DebugPrintf( "Children of %s were updated \n", DbgNodeNameSTR );
+
+
+#if 0
+ ( ( PREGEDIT_NODE )Root )->DeleteListOfValues();
+// ( ( PREGEDIT_NODE )Root )->QueryCompleteName( &DbgNodeName );
+// DbgNodeNameSTR = DbgNodeName.QuerySTR();
+// DebugPtrAssert( DbgNodeNameSTR );
+// DebugPrintf( "Removing values from %s \n", DbgNodeNameSTR );
+ TmpKeyInfo = ( ( PREGEDIT_NODE )Root )->GetKeyInfo();
+ DebugPtrAssert( TmpKeyInfo );
+ if( !_Registry->UpdateKeyInfo( _PredefinedKey, TmpKeyInfo ) ) {
+ ( ( PREGEDIT_NODE )Root )->DeleteListOfChildren();
+ DebugPrint( "Unable to update KeyInfo" );
+ return;
+ }
+
+ if( TmpKeyInfo->GetNumberOfSubKeys() == 0 ) {
+ ( ( PREGEDIT_NODE )Root )->DeleteListOfChildren();
+// DebugPrintf( "Number of Subkeys in node %s is 0 \n", DbgNodeNameSTR );
+ return;
+ }
+
+ Children = ( ( PREGEDIT_NODE )Root )->GetChildren();
+ if( Children == NULL ) {
+// DebugPrintf( "Children of %s are not in memory \n", DbgNodeNameSTR );
+ return;
+ }
+ Count = Children->QueryMemberCount();
+ for( Index = Count; Index != 0; Index-- ) {
+ TmpNode = ( PREGEDIT_NODE )Children->GetAt( Index - 1 );
+ KeyName = ( ( PREGEDIT_NODE )TmpNode )->GetKeyInfo()->GetName();
+ ParentName = ( ( PREGEDIT_NODE )TmpNode )->GetParentName();
+ if( !_Registry->DoesKeyExist( _PredefinedKey, ParentName, KeyName ) ) {
+ Children->RemoveAt( Index - 1 );
+// DebugPrintf( "Removing %s \n", DbgNodeNameSTR );
+ } else {
+ UpdateSubTree( TmpNode );
+ }
+ }
+ if( !NewSubKeysInfo.Initialize() ) {
+ DebugPrint( "NewKeyInfo.Initialize() failed" );
+ return;
+ }
+
+
+ KeyName = ( ( PREGEDIT_NODE )Root )->GetKeyInfo()->GetName();
+ ParentName = ( ( PREGEDIT_NODE )Root )->GetParentName();
+ if( !_Registry->QuerySubKeysInfo( _PredefinedKey, ParentName, KeyName, &NewSubKeysInfo ) ) {
+ ( ( PREGEDIT_NODE )Root )->DeleteListOfChildren();
+ return;
+ }
+ Count = NewSubKeysInfo.QueryMemberCount();
+// DebugPrintf( "Reading Sub Keys of node %s, Count = %d \n", DbgNodeNameSTR, Count );
+ for( Index = Count; Index != 0; Index-- ) {
+ TmpKeyInfo = ( PREGISTRY_KEY_INFO )NewSubKeysInfo.GetAt( Index - 1 );
+ DebugPtrAssert( TmpKeyInfo );
+ KeyName = TmpKeyInfo->GetName();
+ DebugPtrAssert( KeyName );
+ if( IsKeyInListOfChildren( KeyName, Children ) ) {
+ NewSubKeysInfo.RemoveAt( Index - 1 );
+ DELETE( TmpKeyInfo );
+ }
+ }
+
+ Count = NewSubKeysInfo.QueryMemberCount();
+// DebugPrintf( "New count in node %s is NewCount = %d \n", DbgNodeNameSTR, Count );
+ for( Index = 0; Index < Count; Index++ ) {
+ TmpKeyInfo = ( PREGISTRY_KEY_INFO )NewSubKeysInfo.GetAt( Index );
+ DebugPtrAssert( TmpKeyInfo );
+ TmpNode = ( PREGEDIT_NODE )NEW( REGEDIT_NODE );
+ DebugPtrAssert( TmpNode );
+ if( !TmpNode->Initialize( TmpKeyInfo, Root, Root->GetLevel() + 1, FALSE, FALSE ) ) {
+ DebugPrint( "TmpNode->Initialize() failed" );
+ return;
+ }
+ Children->Put( TmpNode );
+ }
+ Count = Children->QueryMemberCount();
+ for( Index = 0; Index < Count; Index++ ) {
+ TmpNode = ( PREGEDIT_NODE )Children->GetAt( Index );
+ DebugPtrAssert( TmpNode );
+ TmpNode->SetPosition( ( Index == 0 )? TRUE : FALSE,
+ ( Index == Count - 1 )? TRUE : FALSE );
+ }
+// DebugPrintf( "Children of %s were updated \n", DbgNodeNameSTR );
+#endif
+}
+
+
+
+
+
+
+ULONG
+REGEDIT_INTERNAL_REGISTRY::MapRegistryToRegeditError(
+ IN DWORD Status
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Maps status codes returned by the REGISTRY class to Regedit error codes.
+
+Arguments:
+
+ Status - Supplies a REGISTRY error code.
+
+Return Value:
+
+ LONG - Returns a Regedit error code.
+
+
+ REGEDIT_ERROR_ACCESS_DENIED,
+ REGEDIT_ERROR_CANT_READ_OR_WRITE,
+ REGEDIT_INITIALIZATION_FAILURE,
+ REGEDIT_ERROR_NODE_DOESNT_EXIST,
+ REGEDIT_ERROR_VALUE_EXISTS,
+ REGEDIT_ERROR_VALUE_DOESNT_EXIST,
+ REGEDIT_ERROR_NODE_NOT_UPDATED,
+ REGEDIT_ERROR_UNKNOWN_ERROR
+
+
+--*/
+
+{
+
+ switch( Status ) {
+
+ case REGISTRY_ERROR_ACCESS_DENIED:
+
+ return( REGEDIT_ERROR_ACCESS_DENIED );
+
+
+
+ case REGISTRY_ERROR_BADDB:
+
+ return( REGEDIT_ERROR_BADDB );
+
+
+ case REGISTRY_ERROR_CANTOPEN:
+ case REGISTRY_ERROR_CANTREAD:
+ case REGISTRY_ERROR_INVALID_PARAMETER:
+ case REGISTRY_ERROR_OUTOFMEMORY:
+ case REGISTRY_ERROR_INITIALIZATION_FAILURE:
+
+ return( REGEDIT_ERROR_CANT_READ_OR_WRITE );
+
+
+
+ case REGISTRY_ERROR_KEY_DOESNT_EXIST:
+
+ return( REGEDIT_ERROR_NODE_DOESNT_EXIST );
+
+
+
+ case REGISTRY_ERROR_VALUE_EXISTS:
+
+ return( REGEDIT_ERROR_VALUE_EXISTS );
+
+
+
+ case REGISTRY_ERROR_VALUE_DOESNT_EXIST:
+
+ return( REGEDIT_ERROR_VALUE_DOESNT_EXIST );
+
+
+ case REGISTRY_ERROR_KEY_INFO_NOT_UPDATED:
+
+ return( REGEDIT_ERROR_NODE_NOT_UPDATED );
+
+
+ case REGISTRY_ERROR_KEY_DELETED:
+
+ return( REGEDIT_ERROR_KEY_DELETED );
+
+
+ case REGISTRY_RPC_S_SERVER_UNAVAILABLE:
+
+ return( REGEDIT_RPC_S_SERVER_UNAVAILABLE );
+
+
+ case REGISTRY_ERROR_UNKNOWN_ERROR:
+
+ return( REGEDIT_ERROR_UNKNOWN_ERROR );
+
+ case REGISTRY_ERROR_KEY_NOT_FOUND:
+
+ return( REGEDIT_ERROR_NODE_NOT_FOUND );
+
+ case REGISTRY_ERROR_CHILD_MUST_BE_VOLATILE:
+
+ return( REGEDIT_ERROR_CHILD_MUST_BE_VOLATILE );
+
+ default:
+
+ DebugPrintf( "Unknown Regedit %x\n", Status );
+ return( REGEDIT_ERROR_UNKNOWN_ERROR );
+ }
+}
+
+
+
+
+PCREGEDIT_NODE
+REGEDIT_INTERNAL_REGISTRY::GetNextNode(
+ IN PCREGEDIT_NODE CurrentNode,
+ IN PCREGEDIT_NODE LastTraversedNode
+ )
+
+/*++
+
+Routine Description:
+
+
+ Traverse a tree in pre-order traversal, to obtain the next element
+ in the tree.
+
+
+Arguments:
+
+
+ CurrentNode - Pointer to the object that represents current node.
+
+
+ LastTraversedNode - Pointer to the object that represents the last
+ traversed node in the search.
+
+
+
+Return Value:
+
+
+ Returns the pointer to the object that represents the next node
+ in the tree (relative to CurrentNode), or NULL if the node couldn't
+ be found.
+
+
+
+
+--*/
+
+
+{
+ PSORTED_LIST Children;
+ ULONG ErrorCode;
+ PCREGEDIT_NODE ParentNode;
+ PITERATOR Iterator;
+ PCREGEDIT_NODE TmpNode;
+
+
+ if( CurrentNode == NULL ) {
+ DebugPtrAssert( CurrentNode );
+ }
+
+ if( ( LastTraversedNode == NULL ) ||
+ ( LastTraversedNode == CurrentNode->GetParentNode() ) ) {
+ //
+ //
+ //
+ if( CurrentNode->GetNumberOfChildren() != 0 ) {
+ Children = GetChildren( CurrentNode, &ErrorCode );
+ if( Children == NULL ) {
+ DebugPrint( "CurrentNode->GetChildren() returned NULL pointer" );
+ DebugPrintf( "CurrentNode->GetChildren() returned NULL pointer, ErrorCode = %#x \n",
+ ErrorCode );
+ DebugPtrAssert( Children );
+ return( NULL );
+ }
+ if( ( Iterator = Children->QueryIterator() ) == NULL ) {
+ DebugPrint( "Unable to get iterator" );
+ return( NULL );
+ }
+ TmpNode = ( PCREGEDIT_NODE )Iterator->GetNext();
+ DELETE( Iterator );
+ return( TmpNode );
+ } else {
+ ParentNode = CurrentNode->GetParentNode();
+ if( ParentNode == NULL ) {
+ return( NULL );
+ } else {
+ return( GetNextNode( ParentNode, CurrentNode ) );
+ }
+ }
+ } else {
+
+ Children = GetChildren( CurrentNode, &ErrorCode );
+ if( ( Children == NULL ) ||
+ ( ( Iterator = Children->QueryIterator() ) == NULL ) ) {
+ DebugPrint( "CurrentNode->GetChildren() returned NULL pointer" );
+ DebugPrintf( "CurrentNode->GetChildren() returned NULL pointer, ErrorCode = %#x \n",
+ ErrorCode );
+ DebugPtrAssert( Children );
+ return( NULL );
+ }
+
+ TmpNode = ( PCREGEDIT_NODE )Iterator->FindNext( ( POBJECT )LastTraversedNode );
+ if( TmpNode == NULL ) {
+ DebugPrint( "ERROR: Object not member of list" );
+ DELETE( Iterator );
+ return( NULL );
+ }
+
+ TmpNode = ( PCREGEDIT_NODE )Iterator->GetNext();
+ DELETE( Iterator );
+ if( TmpNode != NULL ) {
+ return( TmpNode );
+ } else {
+ ParentNode = CurrentNode->GetParentNode();
+ if( ParentNode == NULL ) {
+ return( NULL );
+ } else {
+ return( GetNextNode( ParentNode, CurrentNode ) );
+ }
+ }
+ }
+}
+
+
+
+
+PCREGEDIT_NODE
+REGEDIT_INTERNAL_REGISTRY::GetPreviousNode(
+ IN PCREGEDIT_NODE CurrentNode,
+ IN PCREGEDIT_NODE LastTraversedNode
+ )
+
+/*++
+
+Routine Description:
+
+
+ Traverse a tree in pre-order traversal, to obtain the previous element
+ in the tree.
+
+
+Arguments:
+
+ CurrentNode - Pointer to the object that represents the current node.
+
+
+ LastTraversedNode - Pointer to the object that represents the last
+ traversed node in the search.
+
+
+Return Value:
+
+
+ Returns the pointer to the object that represents the previous node
+ in the tree (relative to CurrentNode), or NULL if the node couldn't
+ be found.
+
+
+
+--*/
+
+
+
+
+{
+ PSORTED_LIST Children;
+ ULONG Index;
+ ULONG ErrorCode;
+ PCREGEDIT_NODE ParentNode;
+ PITERATOR Iterator;
+ PCREGEDIT_NODE TmpNode;
+
+
+ if( CurrentNode == NULL ) {
+ DebugPtrAssert( CurrentNode );
+ }
+
+ if( LastTraversedNode == NULL ) {
+ ParentNode = CurrentNode->GetParentNode();
+ if( ParentNode == NULL ) {
+ return( NULL );
+ } else {
+ return( GetPreviousNode( ParentNode, CurrentNode ) );
+ }
+ } else if( LastTraversedNode == CurrentNode->GetParentNode() ) {
+ //
+ //
+ //
+ if( CurrentNode->GetNumberOfChildren() != 0 ) {
+ Children = GetChildren( CurrentNode, &ErrorCode );
+ if( Children == NULL ) {
+ DebugPrint( "CurrentNode->GetChildren() returned NULL pointer" );
+ DebugPrintf( "CurrentNode->GetChildren() returned NULL pointer, ErrorCode = %#x \n",
+ ErrorCode );
+ DebugPtrAssert( Children );
+ return( NULL );
+ }
+ Index = Children->QueryMemberCount();
+ if( Index == 0 ) {
+ DebugPrint( "Error: Index = 0" );
+ DebugAssert( Index != 0 );
+ return( NULL );
+ }
+
+ Iterator = Children->QueryIterator();
+ TmpNode = ( PCREGEDIT_NODE )Iterator->GetPrevious();
+ DELETE( Iterator );
+ return( GetPreviousNode( TmpNode, CurrentNode ) );
+
+ } else {
+ return( CurrentNode );
+ }
+ } else {
+
+ Children = GetChildren( CurrentNode, &ErrorCode );
+ if( Children == NULL ) {
+ DebugPrint( "CurrentNode->GetChildren() returned NULL pointer" );
+ DebugPrintf( "CurrentNode->GetChildren() returned NULL pointer, ErrorCode = %#x \n",
+ ErrorCode );
+ DebugPtrAssert( Children );
+ return( NULL );
+ }
+ Iterator = Children->QueryIterator();
+ if( Iterator == NULL ) {
+ DebugPrint( "Unable to get iterator" );
+ return( NULL );
+ }
+ TmpNode = ( PCREGEDIT_NODE )Iterator->FindNext( ( POBJECT )LastTraversedNode );
+ if( TmpNode == NULL ) {
+ DebugPrint( "ERROR: Object not member of list" );
+ DELETE( Iterator );
+ return( NULL );
+ }
+ TmpNode = ( PCREGEDIT_NODE )Iterator->GetPrevious();
+ DELETE( Iterator );
+ if( TmpNode != NULL ) {
+ return( GetPreviousNode( TmpNode, CurrentNode ) );
+ } else {
+ return( CurrentNode );
+ }
+ }
+}
+
+
+
+PCREGEDIT_NODE
+REGEDIT_INTERNAL_REGISTRY::FindNode(
+ IN PCWSTRING NodeName,
+ IN PCREGEDIT_NODE StartNode,
+ IN BOOLEAN FindNext,
+ IN BOOLEAN MatchCase,
+ IN BOOLEAN WholeWord
+ )
+
+/*++
+
+Routine Description:
+
+
+ Find a subkey in the tree of nodes represented in this object.
+
+
+Arguments:
+
+
+ NodeName - Name of the key to look for.
+
+ StartNode - Pointer to the object that represents the node in the tree
+ where the search should start.
+
+ FindNext - Indicates whether to look for the next or previous node in
+ the tree (pre-order traversal).
+
+ MatchCase - If TRUE, do case sensitive comparison in the search.
+
+ WholeWord - If TRUE, look for a key whose name match exactly NodeName.
+ If FALSE, look for a key whose name contains NodeName as
+ a substring.
+
+
+Return Value:
+
+
+ PCREGEDIT_NODE - Returns the pointer to the object that describes
+ the desired key, or NULL if the key couldn't be found.
+
+
+
+--*/
+
+
+
+
+{
+ PCREGEDIT_NODE Node;
+ LONG CompareResult;
+ DSTRING St1;
+ DSTRING St2;
+
+
+ DebugPtrAssert( NodeName );
+ DebugPtrAssert( StartNode );
+
+ Node = StartNode;
+ while( TRUE ) {
+ if( FindNext ) {
+ Node = GetNextNode( Node, NULL );
+ } else {
+ Node = GetPreviousNode( Node, NULL );
+ }
+
+ if( ( Node == NULL ) ) {
+ return( Node );
+ }
+
+ if( WholeWord ) {
+ CompareResult = MatchCase ?
+ GetNodeName(Node)->Strcmp(NodeName) :
+ GetNodeName(Node)->Stricmp(NodeName);
+
+ if( CompareResult == 0 ) {
+ return( Node );
+ }
+ }
+
+ if( ( !WholeWord && MatchCase &&
+ ( GetNodeName( Node )->Strstr( NodeName ) != INVALID_CHNUM ) ) ||
+ ( !WholeWord && !MatchCase &&
+ St1.Initialize( GetNodeName( Node ) ) &&
+ St1.Strupr() &&
+ St2.Initialize( NodeName ) &&
+ St2.Strupr() &&
+// ( St1.Strstr( &St2 ) != INVALID_CHNUM )
+ ( St1.Strstr( &St2 ) != INVALID_CHNUM )
+// ( GetNodeName( Node )->Strstr( NodeName ) != INVALID_CHNUM )
+ ) ) {
+ return( Node );
+ }
+ }
+}
+
+
+
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::LoadHive(
+ IN PCREGEDIT_NODE ParentNode,
+ IN PREGISTRY_KEY_INFO HiveInfo,
+ IN PCWSTRING FileName,
+ OUT PCREGEDIT_NODE* HiveNode,
+ OUT PULONG ErrorCode
+ )
+/*++
+
+Routine Description:
+
+ Load a hive in a particular key in the registry.
+
+Arguments:
+
+ CurrentNode - Pointer to the object that represents the key where the
+ hive is to be loaded.
+
+ HiveInfo -
+
+ FileName - Name of the file that contains the hive to be loaded.
+
+ HiveNode -
+
+ ErrorCode - Will contain an error code if the operation fail.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the hive was loaded.
+ Returns FALSE otherwise.
+
+--*/
+
+
+{
+ PSORTED_LIST TmpList;
+ PREGEDIT_NODE TmpNode;
+
+
+ DebugPtrAssert( ParentNode );
+ DebugPtrAssert( HiveInfo );
+ DebugPtrAssert( FileName );
+
+
+ //
+ // First check whether the list of children in Node is loaded in
+ // memory.
+ //
+ if( ParentNode->GetNumberOfChildren() == 0 ) {
+ //
+ // The node doesn't have any children
+ //
+ TmpList = ( PSORTED_LIST ) NEW( SORTED_LIST );
+ DebugPtrAssert( TmpList );
+ if( !TmpList->Initialize() ) {
+ DebugPrint( "TmpList->Initilize() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGEDIT_ERROR_INITIALIZATION_FAILURE;
+ }
+ DELETE( TmpList );
+ return( FALSE );
+ }
+ ( ( PREGEDIT_NODE )ParentNode )->SetChildren( TmpList );
+
+ } else {
+ //
+ // The node has children
+ //
+ TmpList = GetChildren( ParentNode, ErrorCode );
+ DebugPtrAssert( TmpList );
+ }
+
+ //
+ // Now that there is a list of children in memory, load the hive
+ //
+
+ if( !_Registry->LoadHive( _PredefinedKey,
+ HiveInfo,
+ FileName,
+ ErrorCode ) ) {
+ DebugPrint( "_Registry->LoadHive() failed" );
+ *ErrorCode = MapRegistryToRegeditError( *ErrorCode );
+ return( FALSE );
+ }
+
+ //
+ // If the hive was loaded successfully, add NewNode to the list of
+ // Children in Node
+ //
+ TmpNode = ( PREGEDIT_NODE ) NEW( REGEDIT_NODE );
+ DebugPtrAssert( TmpNode );
+
+ if( !TmpNode->Initialize( HiveInfo,
+ ParentNode,
+ ParentNode->GetLevel() + 1,
+ TRUE,
+ FALSE ) ) {
+ DebugPrint( "TmpNode->Initialize() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGEDIT_ERROR_INITIALIZATION_FAILURE;
+ }
+ return( FALSE );
+ }
+ *HiveNode = TmpNode;
+
+ if( !( (PREGEDIT_NODE )ParentNode )->AddChildToListOfChildren( TmpNode ) ) {
+ DebugPrint( "ParentNode->AddValueToListOfValues() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGEDIT_ERROR_INITIALIZATION_FAILURE;
+ }
+ return( FALSE );
+ }
+
+ return( TRUE );
+}
+
+
+
+
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::UnLoadHive(
+ IN PREGEDIT_NODE Node,
+ OUT PULONG ErrorCode
+ )
+/*++
+
+Routine Description:
+
+ Unload a hive in from the registry.
+
+Arguments:
+
+ Node - Pointer to the object that represents the key to be unloaded.
+
+ ErrorCode - Will contain an error code if the operation fail.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the key was unloaded.
+ Returns FALSE otherwise.
+
+--*/
+
+
+{
+ PREGISTRY_KEY_INFO KeyInfo;
+ PREGEDIT_NODE ParentNode;
+
+
+
+
+ DebugPtrAssert( Node );
+
+
+ ParentNode = ( PREGEDIT_NODE )Node->GetParentNode();
+ if( ParentNode == NULL ) {
+ //
+ // Trying to delete a predefined key
+ //
+ *ErrorCode = REGEDIT_ERROR_ACCESS_DENIED;
+ return( FALSE );
+ }
+
+
+ KeyInfo = Node->GetKeyInfo();
+ if( !_Registry->UnLoadHive( _PredefinedKey,
+ KeyInfo,
+ ErrorCode ) ) {
+ DebugPrint( "_Registry->UnLoadHive() failed" );
+ *ErrorCode = MapRegistryToRegeditError( *ErrorCode );
+ return( FALSE );
+ }
+
+ if( !ParentNode->RemoveChildFromListOfChildren( Node ) ) {
+ DebugPrint( "ParentNode->removeChildFromListOfChildren() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGEDIT_ERROR_UNKNOWN_ERROR;
+ }
+ return( FALSE );
+ }
+ DELETE( Node );
+ return( TRUE );
+}
+
+
+
+
+
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::SaveKeyToFile(
+ IN PCREGEDIT_NODE Node,
+ IN PCWSTRING FileName,
+ OUT PULONG ErrorCode
+ )
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+ ErrorCode - Will contain an error code if the operation fail.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the key was unloaded.
+ Returns FALSE otherwise.
+
+--*/
+
+
+{
+ PREGISTRY_KEY_INFO KeyInfo;
+
+
+
+
+ DebugPtrAssert( Node );
+ DebugPtrAssert( FileName );
+
+
+ KeyInfo = Node->GetKeyInfo();
+ if( !_Registry->SaveKeyToFile( _PredefinedKey,
+ KeyInfo,
+ FileName,
+ ErrorCode ) ) {
+ DebugPrint( "_Registry->SaveKeyToFile() failed" );
+ *ErrorCode = MapRegistryToRegeditError( *ErrorCode );
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+
+
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::RestoreKeyFromFile(
+ IN PCREGEDIT_NODE Node,
+ IN PCWSTRING FileName,
+ IN BOOLEAN Volatile,
+ OUT PULONG ErrorCode
+ )
+/*++
+
+Routine Description:
+
+ Restore the contents of a key stored in a file, to a particular
+ key in the registry
+
+Arguments:
+
+ Node - Pointer to the node where the information will be restored.
+
+ FileName - Name of the file that contains the information to be restored.
+
+ Volatile - Flag that indicates whether the information should be
+ restored as volatile or non-volatile.
+
+ ErrorCode - Will contain an error code if the operation fail.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the key was unloaded.
+ Returns FALSE otherwise.
+
+--*/
+
+
+{
+ PREGISTRY_KEY_INFO KeyInfo;
+
+
+
+
+ DebugPtrAssert( Node );
+ DebugPtrAssert( FileName );
+
+
+ KeyInfo = Node->GetKeyInfo();
+ if( !_Registry->RestoreKeyFromFile( _PredefinedKey,
+ KeyInfo,
+ FileName,
+ Volatile,
+ ErrorCode ) ) {
+ DebugPrint( "_Registry->RestoreKeyFromFile() failed" );
+ *ErrorCode = MapRegistryToRegeditError( *ErrorCode );
+ return( FALSE );
+ }
+ ((PREGEDIT_NODE)Node)->DeleteListOfValues();
+ ((PREGEDIT_NODE)Node)->DeleteListOfChildren();
+ if( !_Registry->UpdateKeyInfo( _PredefinedKey, KeyInfo ) ) {
+ DebugPrint( "Unable to update KeyInfo" );
+ }
+
+
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+REGEDIT_INTERNAL_REGISTRY::IsAccessAllowed(
+ IN PCREGEDIT_NODE Node,
+ IN DWORD SamDesired,
+ OUT PULONG ErrorCode
+ )
+/*++
+
+Routine Description:
+
+ Find out if the node allows a particular access.
+
+Arguments:
+
+ Node - Pointer to the object that represents the key whose access
+ is to beeverified.
+
+
+ SamDesired - Access to be verified.
+
+ ErrorCode - Will contain an error code if the operation faiis.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the key allows the access specified in SamDesired.
+
+--*/
+
+
+{
+ PREGISTRY_KEY_INFO KeyInfo;
+
+ DebugPtrAssert( Node );
+
+ KeyInfo = Node->GetKeyInfo();
+ if( !_Registry->IsAccessAllowed( _PredefinedKey,
+ KeyInfo,
+ SamDesired,
+ ErrorCode ) ) {
+ *ErrorCode = MapRegistryToRegeditError( *ErrorCode );
+ DebugPrint( "_Registry->QueryKeySecurity() failed" );
+ return( FALSE );
+ }
+ return( TRUE );
+}
diff --git a/private/utils/regedit/src/regedit.hlp b/private/utils/regedit/src/regedit.hlp
new file mode 100644
index 000000000..70f65e316
--- /dev/null
+++ b/private/utils/regedit/src/regedit.hlp
Binary files differ
diff --git a/private/utils/regedit/src/regedit.ico b/private/utils/regedit/src/regedit.ico
new file mode 100644
index 000000000..500298c11
--- /dev/null
+++ b/private/utils/regedit/src/regedit.ico
Binary files differ
diff --git a/private/utils/regedit/src/regedit.rc b/private/utils/regedit/src/regedit.rc
new file mode 100644
index 000000000..1f48cef57
--- /dev/null
+++ b/private/utils/regedit/src/regedit.rc
@@ -0,0 +1,406 @@
+#include <windows.h>
+#include <resource.h>
+
+RegEditAccel ACCELERATORS
+{
+ VK_F1, IDM_ABOUT, VIRTKEY, SHIFT
+ VK_F4, IDM_TILE, VIRTKEY, SHIFT
+ VK_F5, IDM_CASCADE, VIRTKEY, SHIFT
+ VK_DELETE, IDM_DELETE, VIRTKEY
+ VK_INSERT, IDM_INSERT, VIRTKEY
+ "+", IDM_EXPAND_ONE_LEVEL
+ "-", IDM_COLLAPSE_BRANCH
+ "*", IDM_EXPAND_BRANCH
+ "8", IDM_EXPAND_ALL, VIRTKEY, CONTROL, SHIFT
+ VK_MULTIPLY, IDM_EXPAND_ALL, VIRTKEY, CONTROL
+ VK_TAB, ID_TOGGLE_FOCUS, VIRTKEY
+ VK_TAB, ID_TOGGLE_FOCUS, VIRTKEY, SHIFT
+ VK_RETURN, ID_ENTER_KEY, VIRTKEY
+ VK_F6, IDM_REFRESH, VIRTKEY
+ VK_F6, IDM_REFRESH_ALL, VIRTKEY, SHIFT
+}
+
+BITMAP BITMAP PRELOAD MOVEABLE bitmap.bmp
+IDI_REGEDIT ICON regedit.ico
+SPLIT CURSOR PRELOAD MOVEABLE split.cur
+
+MAIN_MENU MENU LOADONCALL MOVEABLE PURE DISCARDABLE
+{
+ POPUP "&Registry"
+ {
+ MenuItem "&Open Local", IDM_OPEN_REGISTRY
+ MenuItem "&Close", IDM_CLOSE_REGISTRY
+ MenuItem SEPARATOR
+ MenuItem "&Load Hive...", IDM_LOAD_HIVE
+ MenuItem "&Unload Hive", IDM_UNLOAD_HIVE
+ MenuItem "R&estore...", IDM_RESTORE_KEY
+// MenuItem "Res&tore Volatile...", IDM_RESTORE_KEY_VOLATILE
+ MenuItem "Sa&ve Key...", IDM_SAVE_KEY
+ MenuItem SEPARATOR
+ MenuItem "&Select Computer...", IDM_SELECT_COMPUTER
+ MenuItem SEPARATOR
+ MenuItem "&Print Subtree", IDM_PRINT
+ MenuItem "P&rinter Setup...", IDM_PRINTER_SETUP
+ MenuItem "Save Subtree &As...", IDM_SAVE_REGISTRY_ON
+ MenuItem SEPARATOR
+ MenuItem "E&xit", IDM_EXIT
+ }
+ POPUP "&Edit"
+ {
+ MenuItem "Add &Key..." IDM_ADD_KEY
+ MenuItem "Add &Value..." IDM_ADD_VALUE
+ MenuItem "&Delete\tDel", IDM_DELETE
+ MenuItem SEPARATOR
+ MenuItem "&Binary...", IDM_BINARY
+ MenuItem "&String....", IDM_STRING
+ MenuItem "D&WORD...", IDM_ULONG
+ MenuItem "&Multi String..." IDM_MULTISZ
+ }
+ POPUP "&Tree"
+ {
+ MenuItem "E&xpand One Level\t+", IDM_EXPAND_ONE_LEVEL
+ MenuItem "Expand &Branch\t*", IDM_EXPAND_BRANCH
+ MenuItem "Expand &All\tCtrl+*", IDM_EXPAND_ALL
+ MenuItem "&Collapse Branch\t-", IDM_COLLAPSE_BRANCH
+ }
+ POPUP "&View"
+ {
+ MenuItem "Tree &and Data", IDM_TREE_AND_DATA
+ MenuItem "&Tree Only", IDM_TREE_ONLY
+ MenuItem "&Data Only", IDM_DATA_ONLY
+ MenuItem SEPARATOR
+ MenuItem "&Split", IDM_SPLIT
+ MenuItem SEPARATOR
+ MenuItem "Display &Binary Data", IDM_DISPLAY_BINARY
+ MenuItem SEPARATOR
+ MenuItem "R&efresh All\tShift+F6", IDM_REFRESH_ALL,
+ MenuItem "&Refresh Active\tF6", IDM_REFRESH
+ MenuItem SEPARATOR
+ MenuItem "&Find Key...", IDM_FIND_KEY
+ }
+ POPUP "&Security"
+ {
+ MenuItem "&Permissions...", IDM_PERMISSIONS
+ MenuItem "&Auditing...", IDM_AUDITING
+ MenuItem "&Owner..." IDM_OWNER
+ }
+ POPUP "&Options"
+ {
+ MenuItem "&Font..." IDM_FONT
+ MenuItem SEPARATOR
+ MenuItem "&Auto Refresh", IDM_TOGGLE_AUTO_REFRESH
+ MenuItem "&Read Only Mode", IDM_TOGGLE_READ_ONLY_MODE
+// MenuItem "Access Re&mote Registry",IDM_TOGGLE_REMOTE_ACCESS
+ MenuItem "&Confirm on Delete", IDM_TOGGLE_CONFIRM_ON_DELETE
+ MenuItem "&Save Settings on Exit", IDM_TOGGLE_SAVE_SETTINGS
+ }
+ POPUP "&Window"
+ {
+ MenuItem "&Cascade\tShift+F5", IDM_CASCADE
+ MenuItem "&Tile\tShift+F4", IDM_TILE
+ MenuItem "&Arrange Icons", IDM_ARRANGE
+ }
+ POPUP "&Help"
+ {
+ MenuItem "&Contents", IDM_CONTENTS
+ MenuItem "&Search for Help on...", IDM_SEARCH_FOR_HELP
+ MenuItem "&How to Use Help", IDM_HOW_TO_USE_HELP
+ MenuItem SEPARATOR
+ MenuItem "&About Registry Editor...", IDM_ABOUT
+ }
+}
+
+#include "regedhlp.h"
+
+//
+// Include all dialogs
+//
+
+#include "dialogs.h"
+#include "dialogs.dlg"
+
+
+#include "defmsg.h"
+STRINGTABLE
+ {
+ MSG_WINDOW_NAME, "Registry Editor"
+ MSG_VALUE_TYPE_REG_SZ, "REG_SZ"
+ MSG_VALUE_TYPE_REG_BINARY, "REG_BINARY"
+ MSG_VALUE_TYPE_REG_DWORD, "REG_DWORD"
+ MSG_VALUE_TYPE_REG_COLOR_RGB, "REG_COLOR_RGB"
+ MSG_VALUE_TYPE_REG_FILE_NAME, "REG_FILE_NAME"
+ MSG_VALUE_TYPE_REG_FILE_TIME, "REG_FILE_TIME"
+ MSG_VALUE_TYPE_REG_UNKNOWN, "REG_UNKNOWN"
+ MSG_VALUE_TYPE_REG_NONE, "REG_NONE"
+ MSG_VALUE_TYPE_REG_MULTI_SZ, "REG_MULTI_SZ"
+ MSG_VALUE_TYPE_REG_EXPAND_SZ, "REG_EXPAND_SZ"
+ MSG_VALUE_TYPE_REG_RESOURCE_LIST "REG_RESOURCE_LIST"
+ MSG_VALUE_TYPE_REG_FULL_RESOURCE_DESCRIPTOR "REG_FULL_RESOURCE_DESCRIPTOR"
+ MSG_VALUE_TYPE_REG_RESOURCE_REQUIREMENTS_LIST "REG_RESOURCE_REQUIREMENTS_LIST"
+ MSG_FORMATTED_VALUE_SEPARATOR, " : "
+ MSG_FORMATTED_VALUE_NO_NAME, "<No Name>"
+ MSG_FORMATTED_VALUE_INVALID_DATA, "<Invalid data>"
+
+
+ MSG_PRINT_DIALOG_TITLE, "Print"
+ MSG_PRINT_SP_ERROR_LINE1, "General Error has occurred \012 \012"
+ MSG_PRINT_SP_ERROR_LINE2, "Check if: \012"
+ MSG_PRINT_SP_ERROR_LINE3, " Printer is out of paper; \012"
+ MSG_PRINT_SP_ERROR_LINE4, " Printer is off line; \012"
+ MSG_PRINT_SP_ERROR_LINE5, " Printer is being used by another process."
+ MSG_PRINT_SP_OUTOFDISK, "Out of disk space"
+ MSG_PRINT_SP_OUTOFMEMORY, "Out of memory"
+ MSG_PRINT_SP_APPABORT, "Aborted by the user"
+ MSG_PRINT_SP_USERABORT, "Job cancelled from Print Manager"
+ MSG_PRINT_UNKNOWN_ERROR, "Unknown error"
+ MSG_PRINT_ERROR_DIALOG_TITLE, "Print Error"
+ MSG_PRINT_NODE_NAME, "Key Name: "
+ MSG_PRINT_NODE_CLASS_NAME, "Class Name: "
+ MSG_PRINT_NODE_TITLE_INDEX, "Title Index: "
+ MSG_PRINT_NODE_TITLE, "Title: "
+ MSG_PRINT_NODE_LAST_WRITE_TIME, "Last Write Time: "
+ MSG_PRINT_VALUE_NUMBER, "Value "
+ MSG_PRINT_VALUE_NAME, " Name: "
+ MSG_PRINT_VALUE_TITLE_INDEX, " Title Index: "
+ MSG_PRINT_VALUE_TITLE, " Title: "
+ MSG_PRINT_VALUE_TYPE, " Type: "
+ MSG_PRINT_VALUE_DATA_SIZE, " Data Size: "
+ MSG_PRINT_VALUE_DATA, " Data: "
+ MSG_PRINT_VALUE_NO_NAME, "<NO NAME>"
+ MSG_PRINT_NODE_NO_CLASS, "<NO CLASS>"
+
+ MSG_PRINT_FULL_DESCRIPTOR, "Full Resource Descriptor "
+ MSG_PRINT_PARTIAL_DESCRIPTOR, " Partial Descriptor "
+ MSG_PRINT_INTERFACE_TYPE, " Interface Type: "
+ MSG_PRINT_BUS_NUMBER, " Bus Number: "
+ MSG_PRINT_VERSION, " Version: "
+ MSG_PRINT_REVISION, " Revision: "
+
+ MSG_PRINT_RESOURCE, " Resource: "
+ MSG_PRINT_DISPOSITION, " Disposition: "
+ MSG_PRINT_TYPE, " Type: "
+ MSG_PRINT_START, " Start: "
+ MSG_PRINT_LENGTH, " Length: "
+ MSG_PRINT_LEVEL, " Level: "
+ MSG_PRINT_VECTOR, " Vector: "
+ MSG_PRINT_AFFINITY, " Affinity: "
+ MSG_PRINT_CHANNEL, " Channel: "
+ MSG_PRINT_PORT, " Port: "
+ MSG_PRINT_RESERVED1, " Reserved1: "
+ MSG_PRINT_RESERVED2, " Reserved2: "
+ MSG_PRINT_DEV_SPECIFIC_DATA, " Data:"
+
+ MSG_PRINT_IO_INTERFACE_TYPE, "Interface Type: "
+ MSG_PRINT_IO_BUS_NUMBER, "Bus Number: "
+ MSG_PRINT_IO_SLOT_NUMBER, "Slot Number: "
+ MSG_PRINT_IO_LIST_NUMBER, "List "
+ MSG_PRINT_IO_DESCRIPTOR_NUMBER, " Descriptor "
+ MSG_PRINT_IO_OPTION, " Option: "
+ MSG_PRINT_IO_ALIGNMENT, " Alignment: "
+ MSG_PRINT_IO_MINIMUM_ADDRESS, " Minimum Address: "
+ MSG_PRINT_IO_MAXIMUM_ADDRESS, " Maximum Address: "
+ MSG_PRINT_IO_MINIMUM_VECTOR, " Minimum Vector: "
+ MSG_PRINT_IO_MAXIMUM_VECTOR, " Maximum Vector: "
+ MSG_PRINT_IO_MINIMUM_CHANNEL, " Minimum Channel: "
+ MSG_PRINT_IO_MAXIMUM_CHANNEL, " Maximum Channel: "
+
+ MSG_ADD_VALUE_ERROR_NO_NAME, "Registry Editor cannot create a value entry without a name. \012 Please enter a value name."
+ MSG_ADD_VALUE_ERROR_NO_TITLE, "Cannot create a value entry without a title. \012 Please enter a title."
+ MSG_ADD_VALUE_ERROR_NO_DATA, "Cannot create a value entry without data. \012 Please enter the data."
+ MSG_ADD_VALUE_WARN_OVERFLOW, "Overflow"
+ MSG_ADD_VALUE_WARN_OVERFLOW_EX, "The decimal value entered is greater than the maximum value of a DWORD. \012 Registry Editor will truncate the value entered."
+ MSG_ADD_VALUE_REMOVE_EMPTY_STRING_EX, "Data of type MULTI_SZ cannot contain empty strings. \012 Registry Editor will remove the empty string found."
+ MSG_ADD_VALUE_REMOVE_EMPTY_STRINGS_EX, "Data of type MULTI_SZ cannot contain empty strings. \012 Registry Editor will remove all empty strings found."
+ MSG_ADD_VALUE_ALREADY_EXISTS_EX, "Registry Editor could not create the value entry. \012 The value entry already exists. \012Please enter a new name."
+ MSG_ADD_VALUE_WARN_PADDING_EX, "The binary data entered does not represent a whole number of bytes. \012 Registry Editor will pad the binary data with 0s."
+
+
+ MSG_ADD_KEY_ERROR_NO_NAME, "Registry Editor cannot create a key without a name. \012 Please enter a key name."
+ MSG_ADD_KEY_ERROR_NO_TITLE, "Cannot create a node without a title. \012 Please enter a title."
+ MSG_ADD_KEY_INVALID_KEY_NAME, "Invalid Name"
+ MSG_ADD_KEY_INVALID_KEY_NAME_EX,"The key name specified is not valid. \012 A key name cannot contain \\."
+ MSG_ADD_KEY_ALREADY_EXISTS_EX, "Registry Editor could not create the key. \012 The key already exists."
+ MSG_WARNING_TITLE, "Warning"
+ MSG_DELETE_KEY_CONFIRM_EX, "Registry Editor will delete the currently selected key and all its subkeys. \012 Do you want to continue the operation?"
+ MSG_DELETE_VALUE_CONFIRM_EX, "Registry Editor will delete the currently selected value entry. \012 Do you want to continue the operation?"
+ MSG_READONLY_MODE_EDIT_VALUE_EX, "Registry Editor is operating in the Read Only Mode. \012 Changes made to this value entry will not be saved in the registry."
+ MSG_READONLY_MODE_SET_SECURITY_EX, "Registry Editor is operating in the Read Only Mode. \012 Changes made to this key will not be saved in the registry."
+
+ MSG_DISPLAY_BINARY_VALUE_TYPE, "Value Type = "
+ MSG_DISPLAY_BINARY_VALUE_NAME, "Value Name = "
+
+ MSG_ACCESS_DENIED, "Access Denied"
+ MSG_UNKNOWN_ERROR, "Unknown Error"
+ MSG_KEY_MARKED_FOR_DELETION, "Key Marked For Deletion"
+ MSG_ACCESS_DENIED_EX, "Insufficient privilege to perform requested operation."
+
+ MSG_FAILED_OPERATION_EX, "Registry Editor could not accomplish the requested operation."
+
+ MSG_ADD_KEY_ACCESS_DENIED_EX, "Registry Editor could not create the subkey. \012The key currently selected does not give you access to create a subkey."
+ MSG_ADD_KEY_KEY_DELETED_EX, "Registry Editor could not create the subkey. \012The key currently selected is marked for deletion."
+ MSG_ADD_KEY_KEY_NOT_ACCESSIBLE_EX, "Registry Editor could not create the subkey. \012The key currently selected is not accessible."
+ MSG_DELETE_KEY_ACCESS_DENIED_EX, "Registry Editor could not delete the key currently selected. \012 The key, or one of its subkeys does not give you DELETE access."
+ MSG_DELETE_KEY_KEY_DELETED_EX, "Registry Editor could not delete the key currently selected. \012 The key, or one of its subkeys is marked for deletion."
+ MSG_DELETE_KEY_KEY_NOT_ACCESSIBLE_EX, "Registry Editor could not delete the key currently selected. \012 The key, or one of its subkeys is not accessible."
+ MSG_ADD_VALUE_ACCESS_DENIED_EX, "Registry Editor could not add the value entry. \012The key currently selected does not give you access to create a value entry."
+ MSG_ADD_VALUE_KEY_DELETED_EX, "Registry Editor could not add the value entry. \012The key currently selected is marked for deletion."
+ MSG_ADD_VALUE_KEY_NOT_ACCESSIBLE_EX, "Registry Editor could not add the value entry. \012The key currently selected is not accessible."
+ MSG_DELETE_VALUE_ACCESS_DENIED_EX, "Registry Editor could not delete the value entry. \012The Key currently selected does not give you access to delete a value entry."
+ MSG_DELETE_VALUE_KEY_DELETED_EX, "Registry Editor could not delete the value entry. \012 The key currently selected is marked for deletion."
+ MSG_DELETE_VALUE_KEY_NOT_ACCESSIBLE_EX, "Registry Editor could not delete the value entry. \012 The key currently selected is not accessible."
+ MSG_SAVE_VALUE_ACCESS_DENIED_EX, "Registry Editor could not save the value entry. \012The key currently selected does not give you access to set a value entry."
+ MSG_SAVE_VALUE_KEY_DELETED_EX, "Registry Editor could not save the value entry. \012The key currently selected is marked for deletion."
+ MSG_SAVE_VALUE_KEY_NOT_ACCESSIBLE_EX, "Registry Editor could not save the value entry. \012The key currently selected is not accessible."
+
+ MSG_GET_SECURITY_ACCESS_DENIED_EX, "Registry Editor could not retrieve the security information. \012The key currently selected does not give you access to retrieve such information."
+ MSG_GET_SECURITY_KEY_DELETED_EX, "Registry Editor could not retrieve the security information. \012The key currently selected is marked for deletion."
+ MSG_SET_SECURITY_ACCESS_DENIED_EX, "Registry Editor could not save the security information. \012The key currently selected does not give you access to save such information."
+ MSG_SET_SECURITY_KEY_DELETED_EX, "Registry Editor could not save the security information. \012The key currently selected is marked for deletion."
+
+ MSG_SET_SECURITY_ACCESS_DENIED_RECURSIVE_EX, "Registry Editor could not set security in the key currently selected, or some of its subkeys. \012These keys do not give you access to change security information."
+ MSG_SET_SECURITY_KEY_DELETED_RECURSIVE_EX, "Registry Editor could not set security in all subkeys. \012The key currently selected contains one or more subkeys marked for deletion."
+ MSG_SET_SECURITY_KEY_NOT_ACCESSIBLE_RECURSIVE_EX, "Registry Editor could not set security in all subkeys. \012The key currently selected contains one or more inaccessible subkeys."
+
+ MSG_GET_SECURITY_KEY_NOT_ACCESSIBLE_EX, "Registry Editor could not retrieve the security information. \012The key currently selected is not accessible."
+
+ MSG_KEY_NOT_ACCESSIBLE, "Key Inaccessible"
+ MSG_KEY_NOT_ACCESSIBLE_EX, "The key currently selected cannot be accessed."
+
+ MSG_KEY_VOLATILE, "Volatile Key"
+ MSG_ADD_KEY_VOLATILE_EX, "The key currently selected is volatile. \012Registry Editor cannot create a non-volatile subkey on a volatile key."
+ MSG_LOAD_KEY_VOLATILE_EX, "Registry Editor cannot restore a non-volatile key on top of a volatile key."
+
+ MSG_REGISTRY_EDITOR, "Registry Editor"
+ MSG_HELP_FILE_NAME, "regedt32.hlp"
+ MSG_CANT_READ_CLASSES_ROOT, "Registry Editor cannot read the predefined key HKEY_CLASSES_ROOT"
+ MSG_CANT_READ_LOCAL_MACHINE, "Registry Editor cannot read the predefined key HKEY_LOCAL_MACHINE"
+ MSG_CANT_READ_CURRENT_USER, "Registry Editor cannot read the predefined key HKEY_CURRENT_USER"
+ MSG_CANT_READ_USERS, "Registry Editor cannot read the predefined key HKEY_USERS"
+ MSG_CANT_READ_CURRENT_CONFIG, "Registry Editor cannot read the predefined key HKEY_CURRENT_CONFIG"
+ MSG_CANT_FIND_KEY, "Registry Editor cannot find the desired key"
+ MSG_CANT_ACCESS_REMOTE_REGISTRY, "Registry Editor cannot connect to the remote machine"
+ MSG_CANT_ACCESS_REGISTRY, "Registry Editor cannot access registry"
+ MSG_SERVER_UNAVAILABLE, "Server Unavailable"
+ MSG_DISABLING_AUTOREFRESH "AutoRefresh is not available for remote registries; Registry Editor will disable AutoRefresh mode."
+
+ MSG_SEC_EDITOR_CREATE_LINK, "Create Link"
+ MSG_SEC_EDITOR_QUERY_VALUE, "Query Value"
+ MSG_SEC_EDITOR_SET_VALUE, "Set Value"
+ MSG_SEC_EDITOR_ENUM_SUBKEYS, "Enumerate Subkeys"
+ MSG_SEC_EDITOR_NOTIFY, "Notify"
+ MSG_SEC_EDITOR_CREATE_SUBKEY, "Create Subkey"
+ MSG_SEC_EDITOR_DELETE, "Delete"
+ MSG_SEC_EDITOR_WRITE_DAC, "Write DAC"
+ MSG_SEC_EDITOR_WRITE_OWNER, "Write Owner"
+ MSG_SEC_EDITOR_READ_CONTROL, "Read Control"
+ MSG_SEC_EDITOR_READ, "Read"
+ MSG_SEC_EDITOR_FULL_ACCESS, "Full Control"
+ MSG_SEC_EDITOR_SPECIAL_ACCESS, "Special Access..."
+ MSG_SEC_EDITOR_REGISTRY_KEY, "Registry &Key"
+ MSG_SEC_EDITOR_APPLY_TO_SUBKEYS,"R&eplace Permission on Existing Subkeys"
+ MSG_SEC_EDITOR_AUDIT_SUBKEYS, "Audit Permission on Existing Subkeys"
+ MSG_SEC_EDITOR_CONFIRM_APPLY_TO_SUBKEYS, "Do you want to replace the permission on all existing subkeys within %1?"
+ MSG_SEC_EDITOR_CONFIRM_AUDIT_SUBKEYS, "Do you want to audit all existing subkeys within %1?"
+ MSG_SEC_EDITOR_DEFAULT_PERM_NAME, "Read"
+
+ MSG_REG_WINDOW_TITLE_LOCAL, "%1 on Local Machine"
+ MSG_REG_WINDOW_TITLE_REMOTE, "%1 on %2"
+
+ MSG_INI_FILE, "regedt32.ini"
+ MSG_SETTINGS, "Settings"
+ MSG_REGISTRY, "Registry"
+ MSG_KEYS, "Keys"
+ MSG_AUTO_REFRESH, "AutoRefresh"
+ MSG_READ_ONLY, "ReadOnly"
+ MSG_REMOTE_ACCESS, "RemoteAccess"
+ MSG_CONFIRM_ON_DELETE, "ConfirmOnDelete"
+ MSG_SAVE_SETTINGS, "SaveSettings"
+ MSG_LEFT, "Left"
+ MSG_TOP, "Top"
+ MSG_WIDTH, "Width"
+ MSG_HEIGHT, "Height"
+ MSG_MAXIMIZED, "Maximized"
+ MSG_FONT, "Font"
+ MSG_FACE_NAME, "FaceName"
+ MSG_DEFAULT_FACE_NAME, "MS Shell Dlg"
+ MSG_KEY_LOCAL_MACHINE, "HKEY_LOCAL_MACHINE"
+ MSG_KEY_CLASSES_ROOT, "HKEY_CLASSES_ROOT"
+ MSG_KEY_USERS, "HKEY_USERS"
+ MSG_KEY_CURRENT_USER, "HKEY_CURRENT_USER"
+ MSG_KEY_CURRENT_CONFIG, "HKEY_CURRENT_CONFIG"
+
+ MSG_LOAD_HIVE_ALREADY_EXISTS_EX, "Registry Editor could not load the key. \012 The key already exists."
+ MSG_LOAD_HIVE_ACCESS_DENIED_EX, "Insufficient privilege to load the key."
+ MSG_LOAD_HIVE_BAD_FILE_EX, "Registry Editor could not load the key. \012 The file is not a valid registry file."
+ MSG_LOAD_HIVE_BAD_FILE, "Invalid Registry File."
+
+ MSG_UNLOAD_HIVE_ACCESS_DENIED_EX, "Insufficient privilege to unload the key."
+ MSG_UNLOAD_HIVE_CONFIRM_EX, "Registry Editor will unload the currently selected key and all its subkeys. \012 Do you want to continue the operation?"
+ MSG_RESTORE_KEY_ACCESS_DENIED_EX, "The key cannot be restored; either you have insufficient privilege, or the key or one of its subkeys is in use by another process."
+ MSG_RESTORE_KEY_CONFIRM_EX, "Registry Editor will restore a key on top of the currently selected key. \012 All value entries and subkeys of this key will be deleted.\012 Do you want to continue the operation?"
+ MSG_SAVE_KEY_ACCESS_DENIED_EX, "Insufficient privilege to save the key."
+ MSG_SAVE_KEY_DLG_TITLE, "Save Key"
+ MSG_RESTORE_KEY_DLG_TITLE, "Restore Key"
+ MSG_LOAD_HIVE_DLG_TITLE, "Load Hive"
+
+ MSG_SAVE_KEY_KEY_NOT_ACCESSIBLE_EX, "Registry Editor could not save the key. \012The key currently selected is not accessible."
+ MSG_RESTORE_KEY_KEY_NOT_ACCESSIBLE_EX, "Registry Editor could not restore the key. \012The key currently selected is not accessible."
+
+ MSG_DISK_FULL, "Disk Full"
+ MSG_SAVE_SUBTREE_AS_DISK_FULL "Registry Editor could not save the subtree into a file. \012Delete some files from the disk and retry the operation."
+ MSG_SAVE_SUBTREE_AS_UNKNOWN_ERROR "Registry Editor could not save the subtree into a file."
+
+ MSG_FILTER_ALL_FILES, "All files"
+ MSG_FILTER_TXT_FILES, "Text files"
+ MSG_FILTER_STAR_DOT_STAR, "*.*"
+ MSG_FILTER_STAR_DOT_TXT, "*.txt"
+
+ MSG_EDITOR_HEX_RULER, "0 4 8 c 10 14 18 1c \n| | | | | | | | | | | | | | | | "
+ MSG_EDITOR_BINARY_RULER, "0 1 2 3 4 5 6 7 \n| | | | | | | | | | | | | | | | " )
+
+ MSG_BUS_INTERNAL, "Internal"
+ MSG_BUS_ISA, "Isa"
+ MSG_BUS_EISA, "Eisa"
+ MSG_BUS_MICRO_CHANNEL, "Micro Channel"
+ MSG_BUS_TURBO_CHANNEL, "Turbo Channel"
+ MSG_BUS_PCI_BUS, "PCI"
+ MSG_BUS_VME_BUS, "VME"
+ MSG_BUS_NU_BUS, "Nu"
+ MSG_BUS_PCMCIA_BUS, "PCMCIA"
+ MSG_BUS_C_BUS, "C Bus"
+ MSG_BUS_MPI_BUS, "MPI"
+ MSG_BUS_MPSA_BUS, "MPSA"
+
+ MSG_INT_LEVEL_SENSITIVE, "Level Sensitive"
+ MSG_INT_LATCHED, "Latched"
+ MSG_MEM_READ_WRITE, "Read / Write"
+ MSG_MEM_READ_ONLY, "Read Only"
+ MSG_MEM_WRITE_ONLY, "Write Only"
+ MSG_PORT_MEMORY, "Memory"
+ MSG_PORT_PORT, "Port"
+ MSG_INVALID, "Invalid"
+ MSG_DEV_PORT, "Port"
+ MSG_DEV_INTERRUPT, "Interrupt"
+ MSG_DEV_MEMORY, "Memory"
+ MSG_DEV_DMA, "DMA"
+ MSG_DEV_DEVICE_SPECIFIC, "Device Specific"
+
+ MSG_SHARE_UNDETERMINED, "Undetermined"
+ MSG_SHARE_DEVICE_EXCLUSIVE, "Device Exclusive"
+ MSG_SHARE_DRIVER_EXCLUSIVE, "Driver Exclusive"
+ MSG_SHARE_SHARED, "Shared"
+
+ MSG_REGEDIT_DISABLED, "Registry editing has been disabled by your administrator."
+ }
+
+
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Registry Editor Utility"
+#define VER_INTERNALNAME_STR "regedt32.exe"
+#define VER_ORIGINALFILENAME_STR "regedt32.exe"
+
+#include "common.ver"
diff --git a/private/utils/regedit/src/regednod.cxx b/private/utils/regedit/src/regednod.cxx
new file mode 100644
index 000000000..80a6fa66c
--- /dev/null
+++ b/private/utils/regedit/src/regednod.cxx
@@ -0,0 +1,878 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ regednod.hxx
+
+Abstract:
+
+ This module contains the member function definitions for REGEDIT_NODE
+ class.
+ REGEDIT_NODE class is class that contains all the information of a
+ registry key, such as:
+
+ -Key Name
+ -Title Index
+ -Class
+ -Security Attribute
+ -Last Write Time
+ -Number of Sub-keys
+ -Number of Value Entries
+
+ and other information related to its position in the tree structure
+ (the tree structure under a predefinded key in the registry) where
+ it belongs, such as:
+
+ -Its level in the tree
+ -A pointer to a REGISTRY_NODE that represent its parent
+ -A flag indicating if it is the first child of its parent
+ -A flag indicating if it is the last child of its parent
+ -An array of pointers to its children (REGEDIT_NODE)
+ -An array of pointers to its values (REGEDIT_FORMATTED_VALUE_ENTRY)
+
+
+Author:
+
+ Jaime Sasson (jaimes) 01-Mar-1992
+
+
+Environment:
+
+ Regedit, Ulib, User Mode
+
+
+--*/
+
+
+#include "regednod.hxx"
+#include "iterator.hxx"
+
+
+PWSTRING REGEDIT_NODE::_Separator = NULL;
+
+DEFINE_CONSTRUCTOR( REGEDIT_NODE, OBJECT );
+
+
+
+REGEDIT_NODE::~REGEDIT_NODE(
+
+)
+/*++
+
+Routine Description:
+
+ Destroy a REGEDIT_NODE object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+
+VOID
+REGEDIT_NODE::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Worker method for object construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _KeyInfo = NULL;
+ _ParentNode = NULL;
+ _Level = 0;
+ _FlagFirstChild = FALSE;
+ _FlagLastChild = FALSE;
+ _Values = NULL;
+ _Children = NULL;
+}
+
+
+
+VOID
+REGEDIT_NODE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Worker method for object destruction or reinitialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _ParentNode = NULL;
+ _Level = 0;
+ _FlagFirstChild = FALSE;
+ _FlagLastChild = FALSE;
+ if( _Values != NULL ) {
+ _Values->DeleteAllMembers();
+ DELETE( _Values );
+ }
+ if( _Children != NULL ) {
+ _Children->DeleteAllMembers();
+ DELETE( _Children );
+ }
+ DELETE( _KeyInfo );
+}
+
+
+BOOLEAN
+REGEDIT_NODE::Initialize(
+ IN PREGISTRY_KEY_INFO KeyInfo,
+ IN PCREGEDIT_NODE ParentNode,
+ IN ULONG Level,
+ IN BOOLEAN FirstChild,
+ IN BOOLEAN LastChild
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize a REGISTRY_NODE object.
+
+ NOTE: It is the responsibility of this object to delete KeyInfo
+ when it is destroyed
+
+Arguments:
+
+ KeyInfo - Pointer to a REGISTRY_KEY_INFO object that contains the
+ information about the key it represents.
+
+ ParentNode - Pointer to the object that represents the parent of this node.
+
+ Level - Level of this node in the tree (tree represented by a registry
+ predefined key) where it belongs.
+
+ FirstChild - Indicates whether this object is the first child of its parent.
+
+ LastChild - Indicates whether this object is the last child of its parent.
+
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+--*/
+
+{
+ //
+ // Check for NULL pointers
+ //
+ DebugPtrAssert( KeyInfo );
+
+ Destroy();
+
+ _KeyInfo = KeyInfo;
+ _ParentNode = ParentNode;
+ _Level = Level;
+ _FlagFirstChild = FirstChild;
+ _FlagLastChild = LastChild;
+ _NodeIsExpanded = FALSE;
+ if( _Separator == NULL ) {
+ _Separator = ( PWSTRING ) NEW( DSTRING );
+ DebugPtrAssert( _Separator );
+ if( !_Separator->Initialize( ( PSTR )"\\" ) ) {
+ DELETE( _Separator );
+ return( FALSE );
+ }
+ }
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+REGEDIT_NODE::AddChildToListOfChildren(
+ IN PREGEDIT_NODE ChildNode
+// IN PREGEDIT_NODE ChildNode,
+// IN BOOLEAN FirstPosition
+ )
+
+/*++
+
+Routine Description:
+
+ Add a node to the array of children of this object.
+
+
+Arguments:
+
+ ChildNode - Pointer to the node to be added to the list of children.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ PREGEDIT_NODE TmpNode;
+ ULONG Index;
+ ULONG Count;
+ PITERATOR Iterator;
+
+
+ DebugPtrAssert( _Children );
+
+
+ if( !_Children->Put( ( PREGEDIT_NODE )ChildNode ) ) {
+ DebugPrint( "_Children->Put() failed" );
+ return( FALSE );
+ }
+
+
+ //
+ // Update position of each child
+ //
+ Iterator = _Children->QueryIterator();
+ if( Iterator == NULL ) {
+ DebugPrint( "Unable to get iterator" );
+ return( TRUE );
+ }
+ Count = _Children->QueryMemberCount();
+
+ Index = 0;
+ while( ( TmpNode = ( PREGEDIT_NODE )(Iterator->GetNext()) ) != NULL ) {
+ TmpNode->SetPosition( ( Index == 0 )? TRUE : FALSE,
+ ( Index == Count -1 )? TRUE : FALSE ) ;
+ Index++;
+ }
+ DELETE( Iterator );
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+REGEDIT_NODE::AddValueToListOfValues(
+ IN PREGEDIT_FORMATTED_VALUE_ENTRY Value
+ )
+
+/*++
+
+Routine Description:
+
+ Add a formatted value to the array of values of this node.
+
+
+Arguments:
+
+ Value - Pointer to the value to be added to the list of values.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ DebugPtrAssert( _Values );
+
+
+ if( !_Values->Put( ( PREGEDIT_FORMATTED_VALUE_ENTRY )Value ) ) {
+ DebugPrint( "_Value->Put() failed" );
+ return( FALSE );
+ }
+
+
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+REGEDIT_NODE::DeleteListOfChildren(
+ )
+
+/*++
+
+Routine Description:
+
+ Delete the list of children and all its elements.
+ (Used by memory manager only ).
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ _NodeIsExpanded = FALSE;
+ if( _Children == NULL ) {
+ return( TRUE );
+ }
+ if( _Children->QueryMemberCount() > 0 ) {
+ if( !_Children->DeleteAllMembers() ) {
+ DebugPrint( "_Children->DeleteAllMembers() failed" );
+ return( FALSE );
+ }
+ }
+ DELETE( _Children );
+ _Children = NULL;
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+REGEDIT_NODE::DeleteListOfValues(
+ )
+
+/*++
+
+Routine Description:
+
+ Delete the list of values and all its elements.
+ (Used by memory manager only).
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ if( _Values != NULL ) {
+ if( _Values->QueryMemberCount() > 0 ) {
+ if( !_Values->DeleteAllMembers() ) {
+ DebugPrint( "_Values->DeleteAllMembers() failed" );
+ return( FALSE );
+ }
+ }
+ DELETE( _Values );
+ _Values = NULL;
+ }
+ return( TRUE );
+}
+
+
+
+
+BOOLEAN
+REGEDIT_NODE::RemoveChildFromListOfChildren(
+ IN PCREGEDIT_NODE Node
+ )
+
+/*++
+
+Routine Description:
+
+ Remove a particular node from the list of children.
+
+
+Arguments:
+
+ Node - Node to be removed from the list.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ PREGEDIT_NODE TmpNode;
+ ULONG Index;
+ ULONG Count;
+ PITERATOR Iterator;
+
+
+ DebugPtrAssert( _Children );
+ DebugPtrAssert( Node );
+
+ Count = _Children->QueryMemberCount();
+ DebugAssert( Count > 0 );
+
+ Iterator = _Children->QueryIterator();
+ if( Iterator == NULL ) {
+ DebugPrint( "Unable to get iterator" );
+ return( FALSE );
+ }
+ TmpNode = NULL;
+ Index = 0;
+ do {
+ TmpNode = (PREGEDIT_NODE)Iterator->GetNext();
+ } while( ( TmpNode != NULL ) && ( TmpNode != Node ) );
+
+
+ if( TmpNode != Node ) {
+ DebugPrint( "Node to be removed is not in the list of children" );
+ DELETE( Iterator );
+ return( FALSE );
+ }
+
+ _Children->Remove( Iterator );
+
+ if( ( Count = _Children->QueryMemberCount() ) == 0 ) {
+ //
+ // If list of children is empty, get rid of the array
+ //
+ DELETE( Iterator );
+ DELETE( _Children );
+ _Children = NULL;
+ } else {
+
+ //
+ // Otherwise, adjust the position of the children
+ //
+
+ Iterator->Reset();
+ Index = 0;
+ while( ( TmpNode = (PREGEDIT_NODE)Iterator->GetNext() ) != NULL ) {
+ TmpNode->SetPosition( ( Index == 0 )? TRUE : FALSE,
+ ( Index == Count -1 )? TRUE : FALSE ) ;
+ Index++;
+ }
+ DELETE( Iterator );
+ }
+ return( TRUE );
+
+}
+
+
+
+
+BOOLEAN
+REGEDIT_NODE::RemoveValueFromListOfValues(
+ IN PCREGEDIT_FORMATTED_VALUE_ENTRY Value
+ )
+
+/*++
+
+Routine Description:
+
+ Remove a particular value from the list of values.
+
+
+Arguments:
+
+ Value - Value to be removed from the list.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ PCREGEDIT_FORMATTED_VALUE_ENTRY TmpValue;
+ ULONG Index;
+ ULONG Count;
+ PITERATOR Iterator;
+
+
+ DebugPtrAssert( _Values );
+ DebugPtrAssert( Value );
+
+ Count = _Values->QueryMemberCount();
+ DebugAssert( Count > 0 );
+
+ Iterator = _Values->QueryIterator();
+ if( Iterator == NULL ) {
+ DebugPrint( "Unable to get iterator" );
+ return( FALSE );
+ }
+ TmpValue = NULL;
+ Index = 0;
+ do {
+ TmpValue = ( PCREGEDIT_FORMATTED_VALUE_ENTRY )Iterator->GetNext();
+ } while( ( TmpValue != NULL ) && ( TmpValue != Value ) );
+
+
+ if( TmpValue != Value ) {
+ DebugPrint( "Node to be removed is not in the list of children" );
+ DELETE( Iterator );
+ return( FALSE );
+ }
+
+ _Values->Remove( Iterator );
+
+ DELETE( Iterator );
+ if( ( Count = _Values->QueryMemberCount() ) == 0 ) {
+ //
+ // If list of values is empty, get rid of the array
+ //
+ DELETE( _Values );
+ _Values = NULL;
+ }
+ return( TRUE );
+
+
+
+
+}
+
+
+
+
+VOID
+REGEDIT_NODE::SetLevel(
+ IN ULONG Level,
+ IN BOOLEAN Recurse
+ )
+
+/*++
+
+Routine Description:
+
+ Set the node level (its depth in the tree where it belongs), and
+ optionally set the value of all its children.
+
+
+Arguments:
+
+ Level - Depth of this node in the tree where it belogs
+
+ Recurse - Indicates whether the level of the children are to be set.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ PREGEDIT_NODE TmpNode;
+ PITERATOR Iterator;
+
+ _Level = Level;
+
+ //
+ // If children are not loaded, set the level and return
+ //
+ if( _Children == NULL ) {
+ _Level = Level;
+ return;
+ }
+ if( Recurse ) {
+ Iterator = _Children->QueryIterator();
+ if( Iterator == NULL ) {
+ return;
+ }
+ while( ( TmpNode = ( PREGEDIT_NODE )Iterator->GetNext() ) != NULL ) {
+ TmpNode->SetLevel( Level + 1, TRUE );
+ }
+ DELETE( Iterator );
+ }
+ return;
+
+}
+
+
+
+VOID
+REGEDIT_NODE::SetNodeExpansionState(
+ IN BOOLEAN NewExpansionState
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the variable that indicates if the node is being displayed
+ in the tree view as an expanded node or as a collapsed node.
+ If the node is to be set collapsed, then all its children will also
+ be set as collapsed.
+
+
+Arguments:
+
+ NewExpansionState - Contains the information on how the node is currently
+ displayed. TRUE indicates that the node is expanded,
+ and FALSE indicates that the node is collapsed.
+
+
+Return Value:
+
+
+ None.
+
+--*/
+
+{
+ PREGEDIT_NODE TmpNode;
+ PITERATOR Iterator;
+
+ _NodeIsExpanded = NewExpansionState;
+
+ if( !NewExpansionState ) {
+ //
+ // If node was set collapsed, then collapse all children
+ //
+ if( ( _Children != NULL ) &&
+ ( ( Iterator = _Children->QueryIterator() ) != NULL ) ) {
+ while( ( TmpNode = ( PREGEDIT_NODE )Iterator->GetNext() ) != NULL ) {
+ TmpNode->SetNodeExpansionState( FALSE );
+ }
+ DELETE( Iterator );
+ }
+ }
+
+}
+
+
+
+BOOLEAN
+REGEDIT_NODE::QueryCompleteName(
+ OUT PWSTRING CompleteName
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the complete name of this node.
+
+
+Arguments:
+
+ CompleteName - Pointer to a non-initialized WSTRING object that will
+ contain the complete name of this node.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds. Otherwise, it
+ returns FALSE.
+
+
+--*/
+
+{
+ PCWSTRING ParentName;
+ PCWSTRING KeyName;
+
+ ParentName = _KeyInfo->GetParentName();
+ DebugPtrAssert( ParentName );
+ KeyName = _KeyInfo->GetName();
+ DebugPtrAssert( KeyName );
+
+ if( ParentName->QueryChCount() != 0 ) {
+ if( !CompleteName->Initialize( ParentName ) ) {
+ DebugPrint( "ParentName->Initialize() failed" );
+ return( FALSE );
+ }
+ CompleteName->Strcat( _Separator );
+ CompleteName->Strcat( KeyName );
+ return( TRUE );
+ } else {
+ if( !CompleteName->Initialize( KeyName ) ) {
+ DebugPrint( "ParentName->Initialize() failed" );
+ return( FALSE );
+ }
+ return( TRUE );
+ }
+}
+
+
+
+
+BOOLEAN
+REGEDIT_NODE::UpdateParentName(
+ IN PCWSTRING ParentName,
+ IN BOOLEAN Recurse
+ )
+
+/*++
+
+Routine Description:
+
+ Set the parent's name of this node, and optionally the parent's name of
+ all its children.
+
+
+Arguments:
+
+ ParentName - Complete name of this parent's node
+
+ Recurse - Indicates where the parent's name in the children nodes are
+ to be set.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ //
+ // Not implemented
+ //
+ ParentName = ParentName;
+ Recurse = Recurse;
+ return( FALSE );
+}
+
+
+
+
+
+
+
+
+#if DBG
+
+VOID
+REGEDIT_NODE::DbgPrintRegeditNode(
+ )
+
+/*++
+
+Routine Description:
+
+ Print the contents of a REGEDIT_NODE..
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSTR Pointer;
+ PCWSTRING TmpString;
+
+
+
+ DebugPrintf( "====Dumping a REGEDIT_NODE object ====\n \n" );
+ _KeyInfo->DbgPrintKeyInfo();
+
+ if( _ParentNode == NULL ) {
+ DebugPrintf(" The node does not have a parent \n" );
+ } else {
+ TmpString = _ParentNode->GetKeyInfo()->GetName();
+ DebugPtrAssert( TmpString );
+ Pointer = TmpString->QuerySTR();
+ DebugPtrAssert( Pointer );
+ DebugPrintf( " ParentNodeName = %s \n", Pointer );
+ FREE( Pointer );
+ }
+
+ DebugPrintf( " Level = %d \n", _Level );
+ if( _FlagFirstChild ) {
+ DebugPrintf( " FlagFirstChild = TRUE \n" );
+ } else {
+ DebugPrintf( " FlagFirstChild = FALSE \n" );
+ }
+
+ if( _FlagLastChild ) {
+ DebugPrintf( " FlagLastChild = TRUE \n" );
+ } else {
+ DebugPrintf( " FlagLastChild = FALSE \n" );
+ }
+
+ if( _Values == NULL ) {
+ DebugPrintf( " Values are not loaded in memory. \n" );
+ } else {
+ DebugPrintf( " Values are loaded in memory. \n" );
+ DebugPrintf( " Values = %x, MemberCount = %d \n", _Values, _Values->QueryMemberCount() );
+ }
+ if( _Children == NULL ) {
+ DebugPrintf( " Children are not loaded in memory. \n" );
+ } else {
+ DebugPrintf( " Children are loaded in memory. \n" );
+ DebugPrintf( " Children = %x, MemberCount = %d \n", _Children, _Children->QueryMemberCount() );
+ }
+
+ DebugPrintf( "\n\n" );
+}
+
+#endif // DBG
+
+
+LONG
+REGEDIT_NODE::Compare (
+ IN PCOBJECT Node
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Compare two nodes based on their key names.
+
+Arguments:
+
+ Object - Supplies the node to compare with.
+
+Return Value:
+
+ LONG < 0 - supplied REGEDIT_NODE has a higher key name
+ == 0 - supplied REGEDIT_NODE has same key name
+ > 0 - supplied REGEDIT_NODE has a lower key name
+
+
+--*/
+
+{
+ PCWSTRING Name1;
+ PCWSTRING Name2;
+
+ DebugPtrAssert( Node );
+
+ Name1 = _KeyInfo->GetName();
+ Name2 = ( (PCREGEDIT_NODE)Node )->GetKeyInfo()->GetName();
+
+ return( Name1->Stricmp( Name2 ) );
+}
diff --git a/private/utils/regedit/src/regedt32.cxx b/private/utils/regedit/src/regedt32.cxx
new file mode 100644
index 000000000..2629cd763
--- /dev/null
+++ b/private/utils/regedit/src/regedt32.cxx
@@ -0,0 +1,4094 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ Regedit.cxx
+
+Abstract:
+
+ This module contains the definition for the REGEDIT class as well as
+ the main program for the RegEdit utility. REGEDIT is derived from
+ the abstract WINDOW class and supplies an implementation for a frame
+ window.
+
+Author:
+
+ David J. Gilman (davegi) 02-Aug-1991
+
+Environment:
+
+ Ulib, Regedit, Windows, User Mode
+
+--*/
+
+#include "ulib.hxx"
+#include "ulibcl.hxx"
+#include "stream.hxx"
+#include "arg.hxx"
+#include "regedit.hxx"
+
+
+#include "winapp.hxx"
+#include "regedir.hxx"
+#include "registry.hxx"
+#include "editor.hxx"
+#include "regwin.hxx"
+#include "printman.hxx"
+
+#include "resource.h"
+#include "defmsg.h"
+#include "regsys.hxx"
+extern "C" {
+#include "uiexport.h"
+
+#include "dialogs.h"
+#include "regedhlp.h"
+}
+
+#include <wchar.h>
+#include <stdio.h>
+#include "shellapi.h"
+
+#define LOCAL_COMPUTER (LPWSTR)L"__Local_Computer"
+
+BOOLEAN ProcessLoadHiveMessage( HWND );
+BOOLEAN ProcessSaveRestoreKeyMessage( HWND, DWORD );
+
+
+
+//
+// Global Variables (global to the module)
+//
+
+
+HWND _WndMain = NULL;
+HWND _MDIHandle = NULL;
+HANDLE _Module = NULL;
+INT _RegeditFrameX;
+INT _RegeditFrameY;
+INT _RegeditFrameWidth;
+INT _RegeditFrameHeight;
+BOOLEAN _RegeditFrameMaximized;
+
+
+
+
+STATIC PRINT_MANAGER* _PrintManager;
+STATIC LOGFONT _lf;
+STATIC BOOLEAN _LogFontInitialized = FALSE;
+
+
+FINDREPLACE _FindReplace;
+
+UINT _FindReplaceMsg;
+
+WSTR _FindWhatBuffer[256];
+
+UINT _CommonDlgHelpMsg;
+
+
+STATIC PWSTRING _MsgHelpFile = NULL;
+STATIC PWSTR _HelpFileString = NULL;
+
+
+STATIC PWSTRING _MsgIniFile = NULL;
+STATIC PWSTRING _MsgSettings= NULL;
+STATIC PWSTRING _MsgRegistry= NULL;
+STATIC PWSTRING _MsgKeys= NULL;
+STATIC PWSTRING _KeyLocalMachine = NULL;
+STATIC PWSTRING _KeyClassesRoot = NULL;
+STATIC PWSTRING _KeyCurrentUser = NULL;
+STATIC PWSTRING _KeyCurrentConfig = NULL;
+STATIC PWSTRING _KeyUsers = NULL;
+STATIC PWSTRING _MsgAutoRefresh = NULL;
+STATIC PWSTRING _MsgReadOnly = NULL;
+// STATIC PWSTRING _MsgRemoteAccess = NULL;
+STATIC PWSTRING _MsgConfirmOnDelete = NULL;
+STATIC PWSTRING _MsgSaveSettings = NULL;
+STATIC PWSTRING _MsgLeft = NULL;
+STATIC PWSTRING _MsgTop = NULL;
+STATIC PWSTRING _MsgWidth = NULL;
+STATIC PWSTRING _MsgHeight = NULL;
+STATIC PWSTRING _MsgMaximized = NULL;
+STATIC PWSTRING _MsgFont = NULL;
+STATIC PWSTRING _MsgFaceName = NULL;
+STATIC PWSTRING _MsgDefaultFaceName = NULL;
+STATIC PWSTRING _SaveKeyTitle = NULL;
+STATIC PWSTRING _RestoreKeyTitle = NULL;
+STATIC PWSTRING _LoadHiveTitle = NULL;
+STATIC PWSTRING _AllFiles = NULL;
+STATIC PWSTRING _StarDotStar = NULL;
+
+
+
+//
+// Handle to windows hook for F1 key
+//
+HHOOK hHook;
+
+
+DWORD
+HookProc(
+ IN int nCode,
+ IN UINT wParam,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Hook proc to detect F1 key presses.
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ PMSG pmsg = (PMSG)lParam;
+
+ if(nCode < 0) {
+ return(CallNextHookEx(hHook,nCode,wParam,lParam));
+ }
+
+ if(((nCode == MSGF_DIALOGBOX) || (nCode == MSGF_MENU))
+ && (pmsg->message == WM_KEYDOWN)
+ && (LOWORD(pmsg->wParam) == VK_F1))
+ {
+ PostMessage(_WndMain,REGEDIT_HELP_KEY,nCode,0);
+ return(TRUE);
+ }
+
+ return(FALSE);
+}
+
+
+
+VOID
+SetMenuItemHelpContext(
+ IN LONG wParam,
+ IN DWORD lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Routine to set help context based on which menu item is currently
+ selected.
+
+Arguments:
+
+ wParam,lParam - params to window proc in WM_MENUSELECT case
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if(HIWORD(lParam) == 0) { // menu closed
+
+ WINDOWS_APPLICATION::SetHelpContext(-1);
+
+ } else if (HIWORD(wParam) & MF_POPUP) { // popup selected
+ WINDOWS_APPLICATION::SetHelpContext(-1);
+
+ } else if (HIWORD(wParam) & MF_SYSMENU) { // system menu
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_SYSMENU );
+
+ } else { // regular old menu item
+
+ switch( LOWORD(wParam) ) {
+
+ case IDM_OPEN_REGISTRY:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_OPEN_REGED );
+ break;
+
+
+ case IDM_CLOSE_REGISTRY:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_CLOSE_REGED );
+ break;
+
+ case IDM_SAVE_REGISTRY_ON:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_SAVESUB_REGED );
+ break;
+
+ case IDM_LOAD_HIVE:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_LOADHIVE_REGED );
+ break;
+
+ case IDM_UNLOAD_HIVE:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_UNLOADHIVE_REGED );
+ break;
+
+ case IDM_RESTORE_KEY:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_RESTORE_KEY_REGED );
+ break;
+
+ case IDM_RESTORE_KEY_VOLATILE:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_RESTORE_VOLATILE_REGED );
+ break;
+
+ case IDM_SAVE_KEY:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_SAVE_KEY_REGED );
+ break;
+
+ case IDM_PRINT:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_PRINT_REGED );
+ break;
+
+ case IDM_PRINTER_SETUP:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_SETUP_REGED );
+ break;
+
+ case IDM_EXIT:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_EXIT );
+ break;
+
+ case IDM_SAVE_VALUE_BINARY:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_SAVEBIN_REGED );
+ break;
+
+ case IDM_SELECT_COMPUTER:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_SELECT_REGED );
+ break;
+
+ case IDM_ADD_KEY:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_ADDKEY_REGED );
+ break;
+
+ case IDM_ADD_VALUE:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_ADDVALUE_REGED );
+ break;
+
+ case IDM_DELETE:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_DELETE_REGED );
+ break;
+
+ case IDM_BINARY:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_BINARY_REGED );
+ break;
+
+ case IDM_STRING:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_STRING_REGED );
+ break;
+
+ case IDM_ULONG:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_DWORD_REGED );
+ break;
+
+ case IDM_MULTISZ:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_MULTI_REGED );
+ break;
+
+ case IDM_EXPAND_ONE_LEVEL:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_EXPANDONE_REGED );
+ break;
+
+ case IDM_EXPAND_BRANCH:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_EXPANDBR_REGED );
+ break;
+
+ case IDM_EXPAND_ALL:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_EXPANDALL_REGED );
+ break;
+
+ case IDM_COLLAPSE_BRANCH:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_COLLAPSE_REGED );
+ break;
+
+ case IDM_TREE_AND_DATA:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_TREEDATA_REGED );
+ break;
+
+ case IDM_TREE_ONLY:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_TREE_REGED );
+ break;
+
+ case IDM_DATA_ONLY:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_DATA_REGED );
+ break;
+
+ case IDM_SPLIT:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_SPLIT_REGED );
+ break;
+
+ case IDM_DISPLAY_BINARY:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_DISPLAY_REGED );
+ break;
+
+ case IDM_FONT:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_FONT_REGED );
+ break;
+
+ case IDM_REFRESH:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_REFRESH_REGED );
+ break;
+
+ case IDM_REFRESH_ALL:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_REFRESHALL_REGED );
+ break;
+
+ case IDM_FIND_KEY:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_FINDKEY_REGED );
+ break;
+
+
+ case IDM_PERMISSIONS:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_PERMISSION_REGED );
+ break;
+
+ case IDM_AUDITING:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_AUDIT_REGED );
+ break;
+
+ case IDM_OWNER:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_OWNER_REGED );
+ break;
+
+ case IDM_TOGGLE_AUTO_REFRESH:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_AUTO_REGED );
+ break;
+
+ case IDM_TOGGLE_SAVE_SETTINGS:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_SAVEXIT_REGED );
+ break;
+
+ case IDM_TOGGLE_READ_ONLY_MODE:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_READONLY_REGED );
+ break;
+
+// case IDM_TOGGLE_REMOTE_ACCESS:
+//
+// WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_REMOTE_REGED );
+// break;
+
+ case IDM_TOGGLE_CONFIRM_ON_DELETE:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_CONFIRM_REGED );
+ break;
+
+
+ case IDM_CASCADE:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_CASCADE_REGED );
+ break;
+
+ case IDM_TILE:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_TILE_REGED );
+ break;
+
+ case IDM_ARRANGE:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_MENU_ARRANGE_REGED );
+ break;
+
+ case IDM_CONTENTS:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_HELPINDEX );
+ break;
+
+ case IDM_SEARCH_FOR_HELP:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_KEYS );
+ break;
+
+ case IDM_HOW_TO_USE_HELP:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_HELPHELP );
+ break;
+
+ case IDM_ABOUT:
+
+ WINDOWS_APPLICATION::SetHelpContext( IDH_ABOUT );
+ break;
+
+ default:
+ WINDOWS_APPLICATION::SetHelpContext(-1);
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+BOOLEAN
+InitializeGlobalStrings(
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize all global strings used in this module.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if all the strings were initialized.
+
+
+--*/
+
+{
+
+
+ _MsgHelpFile = REGEDIT_BASE_SYSTEM::QueryString( MSG_HELP_FILE_NAME, "" );
+ if( _MsgHelpFile != NULL ) {
+ _HelpFileString = _MsgHelpFile->QueryWSTR();
+ }
+ _MsgIniFile = REGEDIT_BASE_SYSTEM::QueryString( MSG_INI_FILE, "" );
+ _MsgSettings = REGEDIT_BASE_SYSTEM::QueryString( MSG_SETTINGS, "" );
+ _MsgRegistry = REGEDIT_BASE_SYSTEM::QueryString( MSG_REGISTRY, "" );
+ _MsgKeys = REGEDIT_BASE_SYSTEM::QueryString( MSG_KEYS, "" );
+ _MsgAutoRefresh = REGEDIT_BASE_SYSTEM::QueryString( MSG_AUTO_REFRESH, "" );
+ _MsgReadOnly = REGEDIT_BASE_SYSTEM::QueryString( MSG_READ_ONLY, "" );
+// _MsgRemoteAccess = REGEDIT_BASE_SYSTEM::QueryString( MSG_REMOTE_ACCESS, "" );
+ _MsgConfirmOnDelete = REGEDIT_BASE_SYSTEM::QueryString( MSG_CONFIRM_ON_DELETE, "" );
+ _MsgSaveSettings = REGEDIT_BASE_SYSTEM::QueryString( MSG_SAVE_SETTINGS, "" );
+ _MsgLeft = REGEDIT_BASE_SYSTEM::QueryString( MSG_LEFT, "" );
+ _MsgTop = REGEDIT_BASE_SYSTEM::QueryString( MSG_TOP, "" );
+ _MsgWidth = REGEDIT_BASE_SYSTEM::QueryString( MSG_WIDTH, "" );
+ _MsgHeight = REGEDIT_BASE_SYSTEM::QueryString( MSG_HEIGHT, "" );
+ _MsgMaximized = REGEDIT_BASE_SYSTEM::QueryString( MSG_MAXIMIZED, "" );
+ _MsgFont = REGEDIT_BASE_SYSTEM::QueryString( MSG_FONT, "" );
+ _MsgFaceName = REGEDIT_BASE_SYSTEM::QueryString( MSG_FACE_NAME, "" );
+ _MsgDefaultFaceName = REGEDIT_BASE_SYSTEM::QueryString( MSG_DEFAULT_FACE_NAME, "" );
+ _KeyLocalMachine = REGEDIT_BASE_SYSTEM::QueryString( MSG_KEY_LOCAL_MACHINE, "" );
+ _KeyClassesRoot = REGEDIT_BASE_SYSTEM::QueryString( MSG_KEY_CLASSES_ROOT, "" );
+ _KeyCurrentUser = REGEDIT_BASE_SYSTEM::QueryString( MSG_KEY_CURRENT_USER, "" );
+ _KeyCurrentConfig = REGEDIT_BASE_SYSTEM::QueryString( MSG_KEY_CURRENT_CONFIG, "" );
+ _KeyUsers = REGEDIT_BASE_SYSTEM::QueryString( MSG_KEY_USERS, "" );
+ _SaveKeyTitle = REGEDIT_BASE_SYSTEM::QueryString( MSG_SAVE_KEY_DLG_TITLE, "" );
+ _RestoreKeyTitle = REGEDIT_BASE_SYSTEM::QueryString( MSG_RESTORE_KEY_DLG_TITLE, "" );
+ _LoadHiveTitle = REGEDIT_BASE_SYSTEM::QueryString( MSG_LOAD_HIVE_DLG_TITLE, "" );
+ _AllFiles = REGEDIT_BASE_SYSTEM::QueryString( MSG_FILTER_ALL_FILES, "" );
+ _StarDotStar = REGEDIT_BASE_SYSTEM::QueryString( MSG_FILTER_STAR_DOT_STAR, "" );
+
+
+ if( ( _HelpFileString == NULL ) ||
+ ( _MsgIniFile == NULL ) ||
+ ( _MsgSettings == NULL ) ||
+ ( _MsgRegistry == NULL ) ||
+ ( _MsgKeys == NULL ) ||
+ ( _MsgAutoRefresh == NULL ) ||
+ ( _MsgReadOnly == NULL ) ||
+// ( _MsgRemoteAccess == NULL ) ||
+ ( _MsgConfirmOnDelete == NULL ) ||
+ ( _MsgSaveSettings == NULL ) ||
+ ( _MsgLeft == NULL ) ||
+ ( _MsgTop == NULL ) ||
+ ( _MsgWidth == NULL ) ||
+ ( _MsgHeight == NULL ) ||
+ ( _MsgMaximized == NULL ) ||
+ ( _MsgFont == NULL ) ||
+ ( _MsgFaceName == NULL ) ||
+ ( _MsgDefaultFaceName == NULL ) ||
+ ( _KeyLocalMachine == NULL ) ||
+ ( _KeyClassesRoot == NULL ) ||
+ ( _KeyCurrentUser == NULL ) ||
+ ( _KeyCurrentConfig == NULL ) ||
+ ( _KeyUsers == NULL ) ||
+ ( _SaveKeyTitle == NULL ) ||
+ ( _RestoreKeyTitle == NULL ) ||
+ ( _LoadHiveTitle == NULL ) ||
+ ( _AllFiles == NULL ) ||
+ ( _StarDotStar == NULL ) ) {
+ DebugPrint( "ERROR: Unable to create WSTRING objects" );
+ DELETE( _MsgHelpFile );
+ FREE( _HelpFileString );
+ DELETE( _MsgIniFile );
+ DELETE( _MsgSettings );
+ DELETE( _MsgRegistry );
+ DELETE( _MsgKeys );
+ DELETE( _MsgAutoRefresh );
+ DELETE( _MsgReadOnly );
+// DELETE( _MsgRemoteAccess );
+ DELETE( _MsgConfirmOnDelete );
+ DELETE( _MsgSaveSettings );
+ DELETE( _MsgLeft );
+ DELETE( _MsgTop );
+ DELETE( _MsgWidth );
+ DELETE( _MsgHeight );
+ DELETE( _MsgMaximized );
+ DELETE( _MsgFont );
+ DELETE( _MsgFaceName );
+ DELETE( _MsgDefaultFaceName );
+ DELETE( _KeyLocalMachine );
+ DELETE( _KeyClassesRoot );
+ DELETE( _KeyUsers );
+ DELETE( _KeyCurrentUser );
+ DELETE( _KeyCurrentConfig );
+ DELETE( _SaveKeyTitle );
+ DELETE( _RestoreKeyTitle );
+ DELETE( _LoadHiveTitle );
+ DELETE( _AllFiles );
+ DELETE( _StarDotStar );
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+
+
+
+
+BOOLEAN
+Register (
+ )
+
+/*++
+
+Routine Description:
+
+ Register Regedit's main window class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the REGEDIT window class is registered.
+
+--*/
+
+{
+ WNDCLASS wndclass;
+
+ //
+ // If RegEdit is not already running and REGEDIT was not already
+ // registered by this instance, register the REGEDIT window class.
+ //
+
+ wndclass.style = CS_HREDRAW | CS_VREDRAW;
+ wndclass.lpfnWndProc = (WNDPROCFN)MainWndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = 0;
+ wndclass.hInstance = (HINSTANCE)WINDOWS_APPLICATION::QueryInstance();
+ wndclass.hIcon = LoadIcon( (HINSTANCE)WINDOWS_APPLICATION::QueryInstance(),
+ MAKEINTRESOURCE( IDI_REGEDIT ) ); // "REGEDIT" );
+ wndclass.hCursor = LoadCursor( NULL, IDC_ARROW );
+ wndclass.hbrBackground = (HBRUSH)( COLOR_APPWORKSPACE + 1 );
+ wndclass.lpszMenuName = (LPWSTR)L"MAIN_MENU";
+ wndclass.lpszClassName = WINDOWS_APPLICATION::GetApplicationName();
+
+ if( !RegisterClass( &wndclass ) ) {
+ return( FALSE );
+ }
+
+ return TRUE;
+}
+
+
+
+
+
+
+BOOLEAN
+Initialize (
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize regedit object by registering its window class, creating
+ its window and the MDICLIENT window. If each of these is successful,
+ the window is displayed and updated.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the registeration and creation operations
+ are successful.
+
+--*/
+
+{
+ PWSTRING WindowName;
+ PWSTR String;
+ DWORD Style;
+
+ if( !Register( )) {
+ return( FALSE );
+ }
+
+ //
+ //
+ // If the main window class was succesfully registered attempt to
+ // create the frame window. Note that we pass the 'this' pointer
+ // to the window.
+ //
+
+ WindowName = REGEDIT_BASE_SYSTEM::QueryString( MSG_WINDOW_NAME, "" );
+ DbgWinPtrAssert( WindowName );
+ String = WindowName->QueryWSTR();
+ DbgWinPtrAssert( String );
+ Style = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN;
+
+ _WndMain = CreateWindow( WINDOWS_APPLICATION::GetApplicationName(),
+ String,
+ Style,
+ _RegeditFrameX,
+ _RegeditFrameY,
+ _RegeditFrameWidth,
+ _RegeditFrameHeight,
+ NULL,
+ NULL,
+ (HINSTANCE)WINDOWS_APPLICATION::QueryInstance(),
+ NULL );
+ FREE( String );
+ DELETE( WindowName );
+
+ if( _WndMain == NULL ) {
+ DebugPrint( "CreateWindow() failed" );
+ return( FALSE );
+ }
+
+ memset( &_FindReplace, 0, sizeof( FINDREPLACE ) );
+ memset( &_FindWhatBuffer, 0, sizeof( _FindWhatBuffer ) );
+ _FindReplace.lStructSize = sizeof( FINDREPLACE );
+ _FindReplace.hwndOwner = _WndMain;
+ _FindReplace.lpstrFindWhat = _FindWhatBuffer;
+ _FindReplace.wFindWhatLen = sizeof( _FindWhatBuffer );
+ _FindReplace.Flags = FR_WHOLEWORD | FR_DOWN | FR_SHOWHELP;
+ _FindReplaceMsg = RegisterWindowMessage( (LPWSTR)FINDMSGSTRING );
+ WINDOWS_APPLICATION::_hDlgFindReplace = NULL;
+
+ _CommonDlgHelpMsg = RegisterWindowMessage( ( LPWSTR )HELPMSGSTRING );
+ UpdateWindow( _WndMain );
+ if( _RegeditFrameMaximized ) {
+ ShowWindow( _WndMain, SW_SHOWMAXIMIZED );
+ } else {
+ ShowWindow( _WndMain, SW_SHOWDEFAULT );
+ }
+
+ return( TRUE );
+}
+
+
+BOOLEAN
+AddStringToSectionEntry (
+ IN PCWSTRING SectionName,
+ IN PCWSTRING KeyName,
+ IN PCWSTRING Name
+ )
+
+/*++
+
+Routine Description:
+
+ Add a string to an entry of a section in the regedit.ini file.
+ If the entry doesn't exist, then it is created.
+ If the entry already exists, then the string is inserted as the first
+ substring of the entry.
+ Substrings of the entry are separated by comma.
+
+
+Arguments:
+
+ SectionName - Name of the section where the string is to be saved.
+
+ KeyName - Entry in the section where the string is to be saved.
+
+ Name - String to be saved.
+
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeded.
+
+
+
+--*/
+
+{
+ PWSTR MsgIniFileString;
+ PWSTR SectionNameString;
+ PWSTR KeyNameString;
+ PWSTR NameString;
+ WSTR Buffer[2048];
+ WSTR Buffer1[2048];
+
+ DebugPtrAssert( SectionName );
+ DebugPtrAssert( KeyName );
+ DebugPtrAssert( Name );
+
+
+
+ if( ( ( MsgIniFileString = _MsgIniFile->QueryWSTR() ) == NULL ) ||
+ ( SectionName == NULL ) ||
+ ( ( SectionNameString = SectionName->QueryWSTR() ) == NULL ) ||
+ ( KeyName == NULL ) ||
+ ( ( KeyNameString = KeyName->QueryWSTR() ) == NULL ) ||
+ ( Name == NULL ) ||
+ ( ( NameString = Name->QueryWSTR() ) == NULL ) ) {
+ DebugPrint( "ERROR: Unable to retrieve strings" );
+
+ FREE( MsgIniFileString );
+ FREE( SectionNameString );
+ FREE( KeyNameString );
+ FREE( NameString );
+ return( FALSE );
+ }
+
+ Buffer[0] = ( WCHAR )'\0';
+
+ GetPrivateProfileString( SectionNameString,
+ KeyNameString,
+ Buffer,
+ Buffer,
+ sizeof( Buffer )/sizeof( WCHAR ),
+ MsgIniFileString );
+
+ if( Buffer[0] != ( WCHAR )'\0' ) {
+ if( wcsstr( Buffer, NameString ) == NULL ) {
+ swprintf( Buffer1, (LPWSTR)L"%s,%s", NameString, Buffer );
+ WritePrivateProfileString( SectionNameString,
+ KeyNameString,
+ ( LPWSTR )Buffer1,
+ MsgIniFileString );
+ }
+
+ } else {
+ WritePrivateProfileString( SectionNameString,
+ KeyNameString,
+ NameString,
+ MsgIniFileString );
+ }
+ FREE( MsgIniFileString );
+ FREE( SectionNameString );
+ FREE( KeyNameString );
+ FREE( NameString );
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+CloseRegistry (
+ IN PREGISTRY_WINDOW_SET RegistryWindowSet
+ )
+
+/*++
+
+Routine Description:
+
+ Close all registry windows associated to a particular registry.
+
+
+Arguments:
+
+ RegistryWindowSet - Pointer to a structure that contains the pointers
+ to the REGISTRY_WINDOW objects associated to a
+ particular registry.
+ This structure will be freed after all objects
+ in it are destroyed.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds, or FALSE otherwise.
+
+
+--*/
+
+{
+ PCREGISTRY Registry;
+ PCWSTRING MachineName;
+ PWSTR MachineNameString;
+ PWSTR MsgIniFileString;
+
+
+
+ DebugPtrAssert( RegistryWindowSet );
+
+
+ if( ( MsgIniFileString = _MsgIniFile->QueryWSTR() ) == NULL ) {
+ DebugPrint( "ERROR: Unable to retrieve string" );
+ return( FALSE );
+ }
+ if( RegistryWindowSet == NULL ) {
+ return( FALSE );
+ }
+
+ if( RegistryWindowSet->ClassesRoot != NULL ) {
+ SendMessage( _MDIHandle,
+ WM_MDIDESTROY,
+ (WPARAM)RegistryWindowSet->ClassesRoot->QueryHandle(),
+ 0 );
+ DELETE( RegistryWindowSet->ClassesRoot );
+ }
+
+ if( RegistryWindowSet->CurrentUser != NULL ) {
+ SendMessage( _MDIHandle,
+ WM_MDIDESTROY,
+ (WPARAM)RegistryWindowSet->CurrentUser->QueryHandle(),
+ 0 );
+ DELETE( RegistryWindowSet->CurrentUser );
+ }
+
+ if( RegistryWindowSet->LocalMachine != NULL ) {
+ SendMessage( _MDIHandle,
+ WM_MDIDESTROY,
+ (WPARAM)RegistryWindowSet->LocalMachine->QueryHandle(),
+ 0 );
+ DELETE( RegistryWindowSet->LocalMachine );
+ }
+
+ if( RegistryWindowSet->Users != NULL ) {
+ SendMessage( _MDIHandle,
+ WM_MDIDESTROY,
+ (WPARAM)RegistryWindowSet->Users->QueryHandle(),
+ 0 );
+ DELETE( RegistryWindowSet->Users );
+ }
+
+ if( RegistryWindowSet->CurrentConfig != NULL ) {
+ SendMessage( _MDIHandle,
+ WM_MDIDESTROY,
+ (WPARAM)RegistryWindowSet->CurrentConfig->QueryHandle(),
+ 0 );
+ DELETE( RegistryWindowSet->CurrentConfig );
+ }
+
+ if( WINDOWS_APPLICATION::IsSaveSettingsEnabled() ) {
+ Registry = RegistryWindowSet->Registry;
+ if( Registry == NULL ) {
+ DELETE( RegistryWindowSet->Registry );
+ FREE( RegistryWindowSet );
+ return( TRUE );
+ }
+ if( ( ( MachineName = Registry->GetMachineName() ) == NULL ) ||
+ ( ( MachineNameString = MachineName->QueryWSTR() ) == NULL ) ) {
+ DELETE( RegistryWindowSet->Registry );
+ FREE( RegistryWindowSet );
+ return( TRUE );
+ }
+
+
+ WritePrivateProfileString( MachineNameString,
+ NULL,
+ NULL,
+ MsgIniFileString );
+
+ FREE( MachineNameString );
+ }
+ DELETE( RegistryWindowSet->Registry );
+ FREE( RegistryWindowSet );
+ FREE( MsgIniFileString );
+ return( TRUE );
+}
+
+
+
+BOOL
+APIENTRY
+EXPORT
+CloseRemoteRegistries (
+ IN HWND hWnd,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Close all registry windows associated to remote registries.
+
+
+Arguments:
+
+ hWnd - Handle of a child window.
+
+ lParam - Not used.
+
+
+Return Value:
+
+ BOOLN - Returns always TRUE.
+
+
+--*/
+
+{
+ PREGISTRY_WINDOW RegistryWindow;
+ PREGISTRY_WINDOW_SET RegistryWindowSet;
+ PREGISTRY Registry;
+
+ lParam = lParam;
+
+ RegistryWindow = NULL;
+
+
+ //
+ // Fid out if hWnd is a handle to a REGISTRY_WINDOW
+ //
+ if( ( ( RegistryWindow = ( PREGISTRY_WINDOW )GetObjectPointer( hWnd ) ) != NULL ) &&
+ ( REGISTRY_WINDOW::Cast( RegistryWindow ) != NULL ) ) {
+
+ RegistryWindowSet = RegistryWindow->_RegistryWindowSet;
+ if( RegistryWindowSet == NULL ) {
+ DebugPrint( "RegistryWindowSet is NULL" );
+ DebugPtrAssert( RegistryWindowSet );
+ return( TRUE );
+ }
+ if( ( ( Registry = RegistryWindowSet->Registry ) != NULL ) &&
+ ( Registry->IsRemoteRegistry() ) ) {
+ CloseRegistry( RegistryWindowSet );
+ }
+ }
+ return TRUE;
+}
+
+
+BOOL
+APIENTRY
+EXPORT
+SaveRegistryWindowsInfo(
+ IN HWND hWnd,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Save the information about all registry windows currently opened,
+ in regedit.ini file.
+
+
+Arguments:
+
+ hWnd - Handle of a child window.
+
+ lParam - Not used.
+
+
+Return Value:
+
+ BOOLEAN - Returns always TRUE.
+
+
+--*/
+
+{
+ PREGISTRY_WINDOW RegistryWindow;
+ PCREGEDIT_INTERNAL_REGISTRY InternalRegistry;
+
+ PWSTR MsgIniFileString;
+ PCWSTRING MachineName;
+ PWSTR MachineNameString;
+ PCWSTRING RootName;
+ PWSTR RootNameString;
+ POINT Origin;
+ WCHAR Buffer[128];
+ WINDOWPLACEMENT WindowPlacement;
+ DSTRING PredefinedKey;
+ DSTRING LocalComputer;
+
+ lParam = lParam;
+
+ RegistryWindow = NULL;
+ RootNameString = NULL;
+ MachineNameString = NULL;
+
+
+ LocalComputer.Initialize( LOCAL_COMPUTER );
+
+ //
+ // Find out if hWnd is a handle to a REGISTRY_WINDOW
+ //
+ if( ( ( RegistryWindow = ( PREGISTRY_WINDOW )GetObjectPointer( hWnd ) ) != NULL ) &&
+ ( REGISTRY_WINDOW::Cast( RegistryWindow ) != NULL ) ) {
+
+ InternalRegistry = RegistryWindow->_IR;
+ if( InternalRegistry == NULL ) {
+ DebugPrint( "Error: InternalRegistry is NULL" );
+ DebugPtrAssert( InternalRegistry );
+ return( TRUE );
+ }
+
+ MsgIniFileString = _MsgIniFile->QueryWSTR();
+
+ if( InternalRegistry->IsRemoteRegistry() ) {
+ MachineName = InternalRegistry->GetMachineName();
+ } else {
+ MachineName = &LocalComputer;
+ }
+ RootName = InternalRegistry->GetRootName();
+ if( ( MsgIniFileString == NULL ) ||
+ ( MachineName == NULL ) ||
+ ( RootName == NULL ) ||
+ ( ( MachineNameString = MachineName->QueryWSTR() ) == NULL ) ||
+ ( ( RootNameString = RootName->QueryWSTR() ) == NULL ) ) {
+
+ DebugPrint( "ERROR: NULL pointer" );
+ FREE( MsgIniFileString );
+ FREE( MachineNameString );
+ FREE( RootNameString );
+ return( TRUE );
+ }
+
+ AddStringToSectionEntry( _MsgSettings, _MsgRegistry, MachineName );
+
+
+ swprintf( Buffer,
+ (LPWSTR)L"%d",
+ RegistryWindow->_IR->GetPredefinedKey() );
+
+ if( PredefinedKey.Initialize( Buffer ) ) {
+ AddStringToSectionEntry( MachineName,
+ _MsgKeys,
+ &PredefinedKey );
+ }
+
+ WindowPlacement.length=sizeof( WINDOWPLACEMENT );
+
+ if( GetWindowPlacement( hWnd, &WindowPlacement ) ) {
+
+ Origin.x = WindowPlacement.rcNormalPosition.left;
+ Origin.y = WindowPlacement.rcNormalPosition.top;
+ // ScreenToClient( _WndMain, &Origin );
+
+ swprintf( Buffer,
+ (LPWSTR)L"%d,%d,%d,%d,%d,%d",
+ Origin.x,
+ Origin.y,
+ WindowPlacement.rcNormalPosition.right-WindowPlacement.rcNormalPosition.left,
+ WindowPlacement.rcNormalPosition.bottom-WindowPlacement.rcNormalPosition.top,
+ ( IsIconic( hWnd ) )? 1 :
+ ( ( IsZoomed( hWnd ) )? 2 : 0 ),
+ RegistryWindow->_Split );
+
+
+ WritePrivateProfileString( MachineNameString,
+ RootNameString,
+ Buffer,
+ MsgIniFileString );
+
+ }
+
+ FREE( MachineNameString );
+ FREE( RootNameString );
+ FREE( MsgIniFileString );
+ }
+ return( TRUE );
+}
+
+
+
+BOOL
+APIENTRY
+EXPORT
+RefreshRegistryWindow (
+ IN HWND hWnd,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Informs a Registry Window to update itself.
+
+Arguments:
+
+ hWnd - Handle to the window to be informed.
+
+ lParam - Not used.
+
+Return Value:
+
+ BOOL - Returns always TRUE.
+
+--*/
+
+{
+ PREGISTRY_WINDOW RegistryWindow;
+
+ lParam = lParam;
+ RegistryWindow = NULL;
+
+ if( ( ( RegistryWindow = ( PREGISTRY_WINDOW )GetObjectPointer( hWnd ) ) != NULL ) &&
+ ( REGISTRY_WINDOW::Cast( RegistryWindow ) != NULL ) ) {
+
+ SendMessage( hWnd, REFRESH_WINDOW, NULL, NULL );
+ }
+ return TRUE;
+}
+
+
+
+
+BOOL
+APIENTRY
+EXPORT
+InformNewFont (
+ IN HWND hWnd,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Informs a Registry Window that the font was changed.
+
+Arguments:
+
+ hWnd - Handle to the window to be informed.
+
+ lParam - Not used.
+
+Return Value:
+
+ BOOL - Returns always TRUE.
+
+--*/
+
+{
+ lParam = lParam;
+
+ SendMessage( hWnd, INFORM_CHANGE_FONT, NULL, NULL );
+ return TRUE;
+}
+
+
+
+
+BOOLEAN
+SaveFont(
+ )
+
+/*++
+
+Routine Description:
+
+ Save the the font information in the file regedit.ini
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ PWSTR MsgFontString;
+ PWSTR MsgFaceNameString;
+ PWSTR MsgIniFileString;
+
+ WCHAR Buffer[256];
+
+
+ MsgFontString = _MsgFont->QueryWSTR();
+ MsgFaceNameString = _MsgFaceName->QueryWSTR();
+ MsgIniFileString = _MsgIniFile->QueryWSTR();
+
+ if( ( MsgFontString == NULL ) ||
+ ( MsgFaceNameString == NULL ) ||
+ ( MsgIniFileString == NULL ) ) {
+ DebugPrint( "ERROR: Unable to initialize strings" );
+ FREE( MsgFontString );
+ FREE( MsgFaceNameString );
+ FREE( MsgIniFileString );
+ return( FALSE );
+ }
+
+
+ swprintf( Buffer,
+ (LPWSTR)L"%d,%d,%d,%d,%d,%d,%d,%d",
+ _lf.lfHeight,
+ _lf.lfWidth,
+ _lf.lfWeight,
+ _lf.lfItalic,
+ _lf.lfUnderline,
+ _lf.lfStrikeOut,
+ _lf.lfCharSet,
+ _lf.lfPitchAndFamily );
+
+ WritePrivateProfileString( MsgFontString,
+ MsgFontString,
+ Buffer,
+ MsgIniFileString );
+
+ WritePrivateProfileString( MsgFontString,
+ MsgFaceNameString,
+ (_lf.lfFaceName),
+ MsgIniFileString );
+
+ FREE( MsgFontString );
+ FREE( MsgFaceNameString );
+ FREE( MsgIniFileString );
+
+ return( TRUE );
+}
+
+
+
+
+BOOLEAN
+InitializeFont(
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the global LOGFONT structure, based on what is found in the
+ [Font] section of regedit.ini file.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+{
+ PWSTR MsgFontString;
+ PWSTR MsgFaceNameString;
+ PWSTR MsgIniFileString;
+
+ WSTR Buffer[256];
+
+
+ INT Height;
+ INT Width;
+ INT Weight;
+ INT Italic;
+ INT Underline;
+ INT StrikeOut;
+ INT CharSet;
+ INT PitchAndFamily;
+
+ PWSTR DefaultFaceNameString;
+
+
+ MsgFontString = _MsgFont->QueryWSTR();
+ MsgFaceNameString = _MsgFaceName->QueryWSTR();
+ MsgIniFileString = _MsgIniFile->QueryWSTR();
+ DefaultFaceNameString = _MsgDefaultFaceName->QueryWSTR();
+
+ if( ( MsgFontString == NULL ) ||
+ ( MsgFaceNameString == NULL ) ||
+ ( DefaultFaceNameString == NULL ) ||
+ ( MsgIniFileString == NULL ) ) {
+ DebugPrint( "ERROR: Unable to initialize strings" );
+ FREE( MsgFontString );
+ FREE( MsgFaceNameString );
+ FREE( MsgIniFileString );
+ FREE( DefaultFaceNameString );
+ return( FALSE );
+ }
+
+
+ Height = -13;
+ Width = 0;
+ Weight = 300;
+ Italic = 0;
+ Underline = 0;
+ StrikeOut = 0;
+ CharSet = 0;
+ PitchAndFamily = 34;
+
+ swprintf( Buffer,
+ (LPWSTR)L"%d,%d,%d,%d,%d,%d,%d,%d",
+ Height,
+ Width,
+ Weight,
+ Italic,
+ Underline,
+ StrikeOut,
+ CharSet,
+ PitchAndFamily );
+
+
+ GetPrivateProfileString( MsgFontString,
+ MsgFontString,
+ Buffer,
+ Buffer,
+ sizeof( Buffer )/sizeof( WCHAR ),
+ MsgIniFileString );
+
+ swscanf( Buffer,
+ (LPWSTR)L"%d,%d,%d,%d,%d,%d,%d,%d",
+ &Height,
+ &Width,
+ &Weight,
+ &Italic,
+ &Underline,
+ &StrikeOut,
+ &CharSet,
+ &PitchAndFamily );
+
+
+
+
+ _lf.lfHeight = Height;
+ _lf.lfWidth = Width;
+ _lf.lfWeight = Weight;
+ _lf.lfItalic = Italic;
+ _lf.lfUnderline = Underline;
+ _lf.lfStrikeOut = StrikeOut;
+ _lf.lfCharSet = CharSet;
+ _lf.lfPitchAndFamily = PitchAndFamily;
+
+
+ GetPrivateProfileString( MsgFontString,
+ MsgFaceNameString,
+ DefaultFaceNameString,
+ (_lf.lfFaceName),
+ LF_FACESIZE,
+ MsgIniFileString );
+
+ WINDOWS_APPLICATION::SetCurrentHFont( CreateFontIndirect( &_lf ) );
+ _LogFontInitialized = TRUE;
+ FREE( MsgFontString );
+ FREE( MsgFaceNameString );
+ FREE( MsgIniFileString );
+ FREE( DefaultFaceNameString );
+ return( TRUE );
+}
+
+
+
+INT
+APIENTRY
+EXPORT
+ChangeFont (
+ IN HWND hWnd,
+ IN WORD wMessage,
+ IN WPARAM wParam,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Display the "Change Font" dialog and change the font used in all
+ registry windows.
+
+Arguments:
+
+ hWnd - Supplies the window handle for the child window.
+
+
+Return Value:
+
+ BOOL - Returns TRUE if succesful.
+
+
+--*/
+
+{
+ HDC hDC;
+// LOGFONT lf;
+ CHOOSEFONT chf;
+ HFONT HFont;
+ TEXTMETRIC tm;
+
+ wMessage = wMessage;
+ wParam = wParam;
+ lParam = lParam;
+
+ hDC = GetDC( hWnd );
+ if( !_LogFontInitialized ) {
+ GetTextMetrics( hDC, &tm );
+
+ _lf.lfHeight = tm.tmHeight;
+ _lf.lfWidth = tm.tmAveCharWidth;
+ _lf.lfWeight = tm.tmWeight;
+ _lf.lfItalic = tm.tmItalic;
+ _lf.lfUnderline = tm.tmUnderlined;
+ _lf.lfStrikeOut = tm.tmStruckOut;
+ _lf.lfCharSet = tm.tmCharSet;
+ _lf.lfPitchAndFamily = tm.tmPitchAndFamily;
+
+ GetTextFace( hDC, LF_FACESIZE, (_lf.lfFaceName) );
+ _LogFontInitialized = TRUE;
+ }
+
+ chf.lStructSize = sizeof( CHOOSEFONT );
+ chf.hwndOwner = hWnd;
+ chf.hDC = hDC;
+ chf.lpLogFont = &_lf;
+ chf.Flags = CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT | CF_SHOWHELP;
+ chf.rgbColors = RGB( 0, 255, 255 );
+ chf.lCustData = 0;
+ chf.lpfnHook = NULL;
+ chf.lpTemplateName = NULL;
+ chf.hInstance = (HINSTANCE)WINDOWS_APPLICATION::QueryInstance();
+ chf.lpszStyle = NULL;
+ chf.nFontType = SCREEN_FONTTYPE;
+ chf.nSizeMin = 0;
+ chf.nSizeMax = 0;
+
+ if( ChooseFont( &chf ) ) {
+ HFont = CreateFontIndirect( &_lf );
+ if( HFont != NULL ) {
+ if( WINDOWS_APPLICATION::IsSaveSettingsEnabled() ) {
+ SaveFont();
+ }
+ WINDOWS_APPLICATION::SetCurrentHFont( HFont );
+ EnumChildWindows( _MDIHandle, ( WNDENUMPROC )InformNewFont, NULL );
+
+ }
+ }
+ ReleaseDC( hWnd, hDC );
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+DeleteRegistrySections (
+ )
+
+/*++
+
+Routine Description:
+
+ Delete from the file regedit.ini all sections whose names are
+ machine names.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+--*/
+
+{
+ PWSTR MsgIniFileString;
+ PWSTR MsgSettingsString;
+ PWSTR MsgRegistryString;
+
+ WSTR Buffer[2048];
+ PWSTR Pointer;
+
+
+
+ if( ( ( MsgIniFileString = _MsgIniFile->QueryWSTR() ) == NULL ) ||
+ ( ( MsgSettingsString = _MsgSettings->QueryWSTR() ) == NULL ) ||
+ ( ( MsgRegistryString = _MsgRegistry->QueryWSTR() ) == NULL ) ) {
+ DebugPrint( "ERROR: Unable to retrieve strings" );
+ FREE( MsgIniFileString );
+ FREE( MsgSettingsString );
+ FREE( MsgRegistryString );
+ return( FALSE );
+ }
+
+
+ Buffer[0] = ( WCHAR )'\0';
+ GetPrivateProfileString( MsgSettingsString,
+ MsgRegistryString,
+ Buffer,
+ Buffer,
+ sizeof( Buffer )/sizeof( WCHAR ),
+ MsgIniFileString );
+
+ if( Buffer[0] != ( WCHAR )'\0' ) {
+ Pointer = wcstok( Buffer, (LPWSTR)L"," );
+ while( Pointer != NULL ) {
+ WritePrivateProfileString( Pointer,
+ NULL, // MsgKeysString,
+ NULL,
+ MsgIniFileString );
+ Pointer = wcstok( NULL, (LPWSTR)L"," );
+ }
+ }
+ FREE( MsgIniFileString );
+ FREE( MsgSettingsString );
+ FREE( MsgRegistryString );
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+SaveSettings (
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+--*/
+
+
+{
+ WINDOWPLACEMENT WindowPlacement;
+ PWSTR MsgIniFileString;
+ PWSTR MsgSettingsString;
+ PWSTR MsgLeftString;
+ PWSTR MsgTopString;
+ PWSTR MsgWidthString;
+ PWSTR MsgHeightString;
+ PWSTR MsgMaximizedString;
+ WCHAR Buffer[20];
+
+ PWSTR MsgAutoRefreshString;
+ PWSTR MsgReadOnlyString;
+// PSTR MsgRemoteAccessString;
+ PWSTR MsgConfirmOnDeleteString;
+ PWSTR MsgSaveSettingsString;
+
+
+ MsgIniFileString = _MsgIniFile->QueryWSTR();
+ MsgSettingsString = _MsgSettings->QueryWSTR();
+ MsgLeftString = _MsgLeft->QueryWSTR();
+ MsgTopString = _MsgTop->QueryWSTR();
+ MsgWidthString = _MsgWidth->QueryWSTR();
+ MsgHeightString = _MsgHeight->QueryWSTR();
+ MsgMaximizedString = _MsgMaximized->QueryWSTR();
+ MsgAutoRefreshString = _MsgAutoRefresh->QueryWSTR();
+ MsgReadOnlyString = _MsgReadOnly->QueryWSTR();
+// MsgRemoteAccessString = _MsgRemoteAccess->QueryWSTR();
+ MsgConfirmOnDeleteString = _MsgConfirmOnDelete->QueryWSTR();
+ MsgSaveSettingsString = _MsgSaveSettings->QueryWSTR();
+
+
+ if( ( MsgIniFileString == NULL ) ||
+ ( MsgSettingsString == NULL ) ||
+ ( MsgLeftString == NULL ) ||
+ ( MsgTopString == NULL ) ||
+ ( MsgWidthString == NULL ) ||
+ ( MsgHeightString == NULL ) ||
+ ( MsgMaximizedString == NULL ) ||
+ ( MsgAutoRefreshString == NULL ) ||
+ ( MsgReadOnlyString == NULL ) ||
+// ( MsgRemoteAccessString == NULL ) ||
+ ( MsgConfirmOnDeleteString == NULL ) ||
+ ( MsgSaveSettingsString == NULL ) ) {
+
+ FREE( MsgIniFileString );
+ FREE( MsgSettingsString );
+ FREE( MsgLeftString );
+ FREE( MsgTopString );
+ FREE( MsgWidthString );
+ FREE( MsgHeightString );
+ FREE( MsgMaximizedString );
+ FREE( MsgAutoRefreshString );
+ FREE( MsgReadOnlyString );
+// FREE( MsgRemoteAccessString );
+ FREE( MsgConfirmOnDeleteString );
+ FREE( MsgSaveSettingsString );
+
+ return( FALSE );
+ }
+
+
+
+ if( WINDOWS_APPLICATION::IsSaveSettingsEnabled() ) {
+
+ DeleteRegistrySections();
+
+ WritePrivateProfileString( MsgSettingsString,
+ NULL,
+ NULL,
+ MsgIniFileString );
+
+
+ WindowPlacement.length=sizeof( WINDOWPLACEMENT );
+ if( GetWindowPlacement( _WndMain, &WindowPlacement ) ) {
+ swprintf( Buffer, (LPWSTR)L"%d", WindowPlacement.rcNormalPosition.left );
+ WritePrivateProfileString( MsgSettingsString,
+ MsgLeftString,
+ Buffer,
+ MsgIniFileString );
+
+
+ swprintf( Buffer, (LPWSTR)L"%d", WindowPlacement.rcNormalPosition.top );
+ WritePrivateProfileString( MsgSettingsString,
+ MsgTopString,
+ Buffer,
+ MsgIniFileString );
+
+ swprintf( Buffer, (LPWSTR)L"%d", WindowPlacement.rcNormalPosition.right-WindowPlacement.rcNormalPosition.left );
+ WritePrivateProfileString( MsgSettingsString,
+ MsgWidthString,
+ Buffer,
+ MsgIniFileString );
+
+ swprintf( Buffer, (LPWSTR)L"%d", WindowPlacement.rcNormalPosition.bottom-WindowPlacement.rcNormalPosition.top );
+ WritePrivateProfileString( MsgSettingsString,
+ MsgHeightString,
+ Buffer,
+ MsgIniFileString );
+
+ if( IsZoomed( _WndMain ) ) {
+ swprintf( Buffer, (LPWSTR)L"%d", IsZoomed( _WndMain ) );
+ WritePrivateProfileString( MsgSettingsString,
+ MsgMaximizedString,
+ Buffer,
+ MsgIniFileString );
+ }
+ }
+
+ swprintf( Buffer,
+ (LPWSTR)L"%d",
+ WINDOWS_APPLICATION::IsAutoRefreshEnabled() );
+
+ WritePrivateProfileString( MsgSettingsString,
+ MsgAutoRefreshString,
+ Buffer,
+ MsgIniFileString );
+
+ swprintf( Buffer,
+ (LPWSTR)L"%d",
+ WINDOWS_APPLICATION::IsReadOnlyModeEnabled() );
+ WritePrivateProfileString( MsgSettingsString,
+ MsgReadOnlyString,
+ Buffer,
+ MsgIniFileString );
+
+// swprintf( Buffer,
+// (LPWSTR)L"%d",
+// WINDOWS_APPLICATION::IsRemoteAccessEnabled() );
+// WritePrivateProfileString( MsgSettingsString,
+// MsgRemoteAccessString,
+// Buffer,
+// MsgIniFileString );
+
+ swprintf( Buffer,
+ (LPWSTR)L"%d",
+ WINDOWS_APPLICATION::IsConfirmOnDeleteEnabled() );
+ WritePrivateProfileString( MsgSettingsString,
+ MsgConfirmOnDeleteString,
+ Buffer,
+ MsgIniFileString );
+ }
+ swprintf( Buffer,
+ (LPWSTR)L"%d",
+ WINDOWS_APPLICATION::IsSaveSettingsEnabled() );
+ WritePrivateProfileString( MsgSettingsString,
+ MsgSaveSettingsString,
+ Buffer,
+ MsgIniFileString );
+
+ FREE( MsgIniFileString );
+ FREE( MsgSettingsString );
+ FREE( MsgLeftString );
+ FREE( MsgTopString );
+ FREE( MsgWidthString );
+ FREE( MsgHeightString );
+ FREE( MsgMaximizedString );
+ FREE( MsgAutoRefreshString );
+ FREE( MsgReadOnlyString );
+// FREE( MsgRemoteAccessString );
+ FREE( MsgConfirmOnDeleteString );
+ FREE( MsgSaveSettingsString );
+
+ return( TRUE );
+}
+
+
+
+
+
+BOOLEAN
+SelectComputer (
+ IN HWND hWnd,
+ OUT PWSTRING Name
+ )
+
+/*++
+
+Routine Description:
+
+ Display the "Select Computer" dialog and open the registry of the
+ selected machine.
+
+Arguments:
+
+ hWnd - Supplies the window handle for the child window.
+
+ Name - Pointer to a WSTRING object that will contain a machine name
+
+
+Return Value:
+
+
+ BOOLEAN - Returns TRUE if the operation succeeds and Name is a valid
+ computer name.
+ Returns FALSE if the operation fails, or if the user doesn't
+ select any machine.
+
+--*/
+
+{
+ WSTR MachineName[ 4*MAX_PATH+1 ];
+ //
+ // A machine name (Fully Qualified Domain name, eg, \\machine_name.microsoft.com)
+ // can be huge (127 segments of 63 characters each.
+ // In practice, a buffer of 256 characters (MAX_PATH) will handle most
+ // cases. To be in the safe side, this buffer was made a 1024 characters
+ // long
+ //
+ BOOL OkPressed;
+ UINT BufferSize;
+ UINT Status;
+// PSTR DbgName;
+
+ BufferSize = sizeof( MachineName )/ sizeof( WCHAR );
+ if( (Status = I_SystemFocusDialog( hWnd,
+ FOCUSDLG_SERVERS_ONLY | FOCUSDLG_BROWSE_ALL_DOMAINS,
+ ( LPWSTR )MachineName,
+ BufferSize,
+ &OkPressed,
+ _HelpFileString,
+ IDH_DB_SELECT_REGED )) != 0 ) {
+ DebugPrint( "SystemFocusDialog() failed" );
+ DebugPrintf( "SystemFocusDialog() failed, Status = %d \n", Status );
+ return( FALSE );
+ }
+
+ if( !OkPressed ) {
+ return( FALSE );
+ }
+ //
+ // Initialize Name with the MachineName, but remove '\\'
+ //
+ if( !Name->Initialize( MachineName + 2 ) ) {
+ DebugPrint( "Name.Initialize( MachineName, BufferSize ) failed" );
+ return( FALSE );
+ }
+// DbgName = Name->QuerySTR();
+// DebugPrintf( "Name = %s \n", DbgName );
+// FREE( DbgName );
+ return( TRUE );
+}
+
+
+
+
+INT
+APIENTRY
+EXPORT
+CloseAllRegistryWindows (
+ IN HWND hWnd,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ CloseAllRegistryWindows is a callback function for the
+ EnumChildWindows API. It is indirectly called in order to close
+ all Registry Windows.
+
+Arguments:
+
+ hWnd - Supplies the window handle for the child window.
+ lParam - Supplies nothing.
+
+Return Value:
+
+ BOOL - Returns TRUE if succesful.
+
+
+--*/
+
+{
+ //
+ // Send a destroy message to each Registry Window.
+ //
+
+ lParam = lParam;
+
+ SendMessage( _MDIHandle, WM_MDIDESTROY, (INT)hWnd, 0 );
+ return TRUE;
+}
+
+
+
+BOOLEAN
+GetRegistryWindowPosition(
+ IN PCWSTRING MachineName,
+ IN PCWSTRING PredefinedKey,
+ OUT PWINDOW_POSITION WindowPosition
+ )
+
+/*++
+
+Routine Description:
+
+ Get the position of a registry window from 'regedit.ini'.
+
+Arguments:
+
+ MachineName - Pointer to a WSTRING object that contains the machine
+ name.
+
+ PredefinedKey - Pointer to a WSTRING object that contains the name of
+ the prdefined key whose position is to be retrieved.
+
+ WindowPosition - Pointer to the structure that will contain the
+ desired information of a registry window.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeded.
+ Returns FALSE otherwise.
+
+--*/
+
+{
+ PWSTR MsgIniFileString;
+ PWSTR MachineNameString;
+ PWSTR PredefinedKeyString;
+ WSTR Buffer[256];
+
+ DebugPtrAssert( MachineName );
+ DebugPtrAssert( PredefinedKey );
+ DebugPtrAssert( WindowPosition );
+
+ WindowPosition->X = CW_USEDEFAULT;
+ WindowPosition->Y = CW_USEDEFAULT;
+ WindowPosition->Width = CW_USEDEFAULT;
+ WindowPosition->Height = CW_USEDEFAULT;
+ WindowPosition->Style = 0;
+ WindowPosition->Split = CW_USEDEFAULT;
+
+
+
+ MachineNameString = NULL;
+ PredefinedKeyString = NULL;
+ MsgIniFileString = NULL;
+
+ if( ( MachineName == NULL ) ||
+ ( PredefinedKey == NULL ) ||
+ ( WindowPosition == NULL ) ||
+ ( ( MachineNameString = MachineName->QueryWSTR() ) == NULL ) ||
+ ( ( PredefinedKeyString = PredefinedKey->QueryWSTR() ) == NULL ) ||
+ ( ( MsgIniFileString = _MsgIniFile->QueryWSTR() ) == NULL ) ) {
+ DebugPrint( "ERROR: NULL pointer" );
+ FREE( MachineNameString );
+ FREE( PredefinedKeyString );
+ FREE( MsgIniFileString );
+ return( FALSE );
+ }
+
+ swprintf( Buffer,
+ (LPWSTR)L"%d,%d,%d,%d,%d,%d",
+ CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, CW_USEDEFAULT );
+ GetPrivateProfileString( MachineNameString,
+ PredefinedKeyString,
+ Buffer,
+ Buffer,
+ sizeof( Buffer )/sizeof( WCHAR ),
+ MsgIniFileString );
+ if( swscanf( Buffer,
+ (LPWSTR)L"%d,%d,%d,%d,%d,%d",
+ &( WindowPosition->X ),
+ &( WindowPosition->Y ),
+ &( WindowPosition->Width ),
+ &( WindowPosition->Height ),
+ &( WindowPosition->Style ),
+ &( WindowPosition->Split ) ) != 6 ) {
+ DebugPrint( "sscanf() failed" );
+ }
+
+ FREE( MachineNameString );
+ FREE( PredefinedKeyString );
+ FREE( MsgIniFileString );
+ return( TRUE );
+}
+
+
+
+
+PREGISTRY_WINDOW
+OpenRegistryWindow (
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PREGISTRY_WINDOW_SET RegistryWindowSet
+ )
+
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+ PredefinedKey - The name of the predefined key that the registry window
+ will display.
+
+
+ RegistryWindowSet -
+
+
+
+Return Value:
+
+
+
+
+--*/
+
+{
+ PREGISTRY Registry = NULL;
+ PREGISTRY_WINDOW pRegWin = NULL;
+ PREGEDIT_INTERNAL_REGISTRY InternalRegistry = NULL;
+ PWSTRING WindowTitle = NULL;
+ PCWSTRING MachineName = NULL;
+ PCWSTRING RootName = NULL;
+ WINDOW_POSITION WindowPosition;
+ FSTRING AuxString;
+
+ DebugAssert( ( PredefinedKey == PREDEFINED_KEY_CLASSES_ROOT ) ||
+ ( PredefinedKey == PREDEFINED_KEY_CURRENT_USER ) ||
+ ( PredefinedKey == PREDEFINED_KEY_LOCAL_MACHINE ) ||
+ ( PredefinedKey == PREDEFINED_KEY_USERS )
+ ( PredefinedKey == PREDEFINED_KEY_CURRENT_CONFIG ) );
+ DebugPtrAssert( RegistryWindowSet );
+
+
+ Registry = RegistryWindowSet->Registry;
+ if( !Registry->IsRemoteRegistry() ) {
+ AuxString.Initialize( LOCAL_COMPUTER );
+ MachineName = &AuxString;
+ } else {
+ MachineName = Registry->GetMachineName();
+ }
+
+ switch( PredefinedKey ) {
+
+ case PREDEFINED_KEY_CLASSES_ROOT:
+
+ RootName = _KeyClassesRoot;
+ break;
+
+ case PREDEFINED_KEY_CURRENT_USER:
+
+ RootName = _KeyCurrentUser;
+ break;
+
+ case PREDEFINED_KEY_LOCAL_MACHINE:
+
+ RootName = _KeyLocalMachine;
+ break;
+
+ case PREDEFINED_KEY_USERS:
+
+ RootName = _KeyUsers;
+ break;
+
+ case PREDEFINED_KEY_CURRENT_CONFIG:
+
+ RootName = _KeyCurrentConfig;
+ break;
+ }
+
+ GetRegistryWindowPosition( MachineName, RootName, &WindowPosition );
+
+ if( !Registry->IsRemoteRegistry() ) {
+ WindowTitle = REGEDIT_BASE_SYSTEM::QueryString( MSG_REG_WINDOW_TITLE_LOCAL,
+ "%W",
+ RootName->GetWSTR() );
+ DebugPtrAssert( WindowTitle );
+
+ } else {
+ WindowTitle = REGEDIT_BASE_SYSTEM::QueryString( MSG_REG_WINDOW_TITLE_REMOTE,
+ "%W %W",
+ RootName->GetWSTR(),
+ MachineName->GetWSTR() );
+ DebugPtrAssert( WindowTitle );
+ }
+
+ InternalRegistry = ( PREGEDIT_INTERNAL_REGISTRY )NEW( REGEDIT_INTERNAL_REGISTRY );
+ DebugPtrAssert( InternalRegistry );
+ if( ( InternalRegistry == NULL ) ||
+ ( !InternalRegistry->Initialize( PredefinedKey,
+ Registry,
+ RootName ) ) ) {
+ DebugPrint( "InternalRegistry->Initialize() failed" );
+ DELETE( InternalRegistry );
+ return( NULL );
+
+ } else {
+
+ pRegWin = (PREGISTRY_WINDOW)NEW( REGISTRY_WINDOW );
+ DebugPtrAssert( pRegWin );
+ if( ( pRegWin == NULL ) ||
+ ( !pRegWin->Initialize( _MDIHandle, WindowTitle, InternalRegistry, RegistryWindowSet, &WindowPosition ) ) ) {
+ DebugPrint( "pRegWin->Initialize() failed" );
+ DELETE( pRegWin );
+ DELETE( InternalRegistry );
+ DELETE( WindowTitle );
+ }
+ DELETE( WindowTitle );
+ }
+
+ switch( PredefinedKey ) {
+
+ case PREDEFINED_KEY_CLASSES_ROOT:
+
+ RegistryWindowSet->ClassesRoot = pRegWin;
+ break;
+
+ case PREDEFINED_KEY_CURRENT_USER:
+
+ RegistryWindowSet->CurrentUser = pRegWin;
+ break;
+
+ case PREDEFINED_KEY_LOCAL_MACHINE:
+
+ RegistryWindowSet->LocalMachine = pRegWin;
+ break;
+
+ case PREDEFINED_KEY_USERS:
+
+ RegistryWindowSet->Users = pRegWin;
+ RootName = _KeyUsers;
+ break;
+
+ case PREDEFINED_KEY_CURRENT_CONFIG:
+
+ RegistryWindowSet->CurrentConfig = pRegWin;
+ break;
+
+ }
+
+
+ return( pRegWin );
+}
+
+
+
+
+BOOLEAN
+OpenRegistry(
+ IN PCWSTRING MachineName
+ )
+
+/*++
+
+Routine Description:
+
+ Open and display the registry of a machine.
+
+Arguments:
+
+ MachineName - Pointer to a WSTRING object that contains the machine
+ name. This pointer can be NULL, and in this the registry
+ of the local machine will be opened.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeded and a registry
+ was opened and displayed.
+ Returns FALSE otherwise.
+
+--*/
+
+{
+ PREGISTRY_WINDOW pRegWin = NULL;
+ PREGEDIT_INTERNAL_REGISTRY InternalRegistry = NULL;
+ PREGISTRY Registry = NULL;
+ PREGISTRY_WINDOW_SET RegistryWindowSet = NULL;
+
+ ULONG Key0;
+ ULONG Key1;
+ ULONG Key2;
+ ULONG Key3;
+ ULONG Key4;
+ PWSTR MsgKeysString = NULL;
+ WCHAR Buffer[128];
+ PCWSTR MachineNameString;
+ PWSTR MsgIniFileString;
+ ULONG ErrorCode;
+
+
+
+ RegistryWindowSet =
+ ( PREGISTRY_WINDOW_SET )MALLOC( ( size_t )sizeof( REGISTRY_WINDOW_SET ) );
+ Registry = ( PREGISTRY )NEW( REGISTRY );
+ if( ( RegistryWindowSet == NULL ) ||
+ ( Registry == NULL ) ) {
+ DebugPtrAssert( RegistryWindowSet );
+ DebugPtrAssert( Registry );
+ FREE( RegistryWindowSet );
+ DELETE( Registry );
+ DebugPrint( "Out of memory" );
+ return( FALSE );
+ }
+
+ if( !Registry->Initialize( MachineName, &ErrorCode ) ) {
+ DebugPrint( "Registry->Initialize() failed" );
+ FREE( RegistryWindowSet );
+ DELETE( Registry );
+ if( ( ErrorCode == REGISTRY_RPC_S_SERVER_UNAVAILABLE ) ||
+ ( ErrorCode == REGISTRY_ERROR_ACCESS_DENIED ) ) {
+ DisplayWarningPopup( _WndMain, MSG_CANT_ACCESS_REMOTE_REGISTRY );
+ } else {
+ DisplayWarningPopup( _WndMain, MSG_CANT_ACCESS_REGISTRY );
+ }
+ return( FALSE );
+ }
+
+// if( Registry->IsRemoteRegistry() &&
+// !WINDOWS_APPLICATION::IsRemoteAccessEnabled() ) {
+// FREE( RegistryWindowSet );
+// DELETE( Registry );
+// return( FALSE );
+// }
+
+ RegistryWindowSet->ClassesRoot = NULL;
+ RegistryWindowSet->CurrentUser = NULL;
+ RegistryWindowSet->LocalMachine = NULL;
+ RegistryWindowSet->Users = NULL;
+ RegistryWindowSet->CurrentConfig = NULL;
+ RegistryWindowSet->Registry = Registry;
+
+
+ MsgKeysString = _MsgKeys->QueryWSTR();
+ MsgIniFileString = _MsgIniFile->QueryWSTR();
+ Buffer[0] = ( WCHAR )'\0';
+ if( Registry->IsRemoteRegistry() ) {
+ MachineNameString = MachineName->GetWSTR();
+ } else {
+ MachineNameString = LOCAL_COMPUTER;
+ }
+ if( ( MsgKeysString != NULL ) &&
+ ( MsgIniFileString != NULL ) ) {
+ GetPrivateProfileString( MachineNameString,
+ MsgKeysString,
+ ( Registry->IsRemoteRegistry() )?
+ (LPWSTR)L"2,3" :
+ (LPWSTR)L"2,3,4,0,1",
+ Buffer,
+ sizeof( Buffer )/sizeof( WCHAR ),
+ MsgIniFileString );
+ }
+ FREE( MsgKeysString );
+ FREE( MsgIniFileString );
+
+
+
+
+ if( Registry->IsRemoteRegistry() ) {
+ if( swscanf( Buffer,
+ (LPWSTR)L"%d,%d",
+ &Key0,
+ &Key1 ) != 2 ) {
+ Key0 = ( ULONG )PREDEFINED_KEY_LOCAL_MACHINE;
+ Key1 = ( ULONG )PREDEFINED_KEY_USERS;
+ }
+ } else {
+ if( swscanf( Buffer,
+ (LPWSTR)L"%d,%d,%d,%d,%d",
+ &Key0,
+ &Key1,
+ &Key2,
+ &Key3,
+ &Key4 ) != 5 ) {
+ Key0 = ( ULONG )PREDEFINED_KEY_LOCAL_MACHINE;
+ Key1 = ( ULONG )PREDEFINED_KEY_USERS;
+ Key2 = ( ULONG )PREDEFINED_KEY_CURRENT_CONFIG;
+ Key3 = ( ULONG )PREDEFINED_KEY_CLASSES_ROOT;
+ Key4 = ( ULONG )PREDEFINED_KEY_CURRENT_USER;
+ }
+ }
+
+
+ OpenRegistryWindow( PREDEFINED_KEY( Key0 ),
+ RegistryWindowSet );
+
+ OpenRegistryWindow( PREDEFINED_KEY( Key1 ),
+ RegistryWindowSet );
+
+ if( !Registry->IsRemoteRegistry() ) {
+ OpenRegistryWindow( PREDEFINED_KEY( Key2 ),
+ RegistryWindowSet );
+
+ OpenRegistryWindow( PREDEFINED_KEY( Key3 ),
+ RegistryWindowSet );
+
+ OpenRegistryWindow( PREDEFINED_KEY( Key4 ),
+ RegistryWindowSet );
+
+ }
+
+ if( Registry->IsRemoteRegistry() &&
+ WINDOWS_APPLICATION::IsAutoRefreshEnabled() ) {
+
+ // Since auto-refresh doesn't work for remote registries,
+ // turn it off.
+ //
+ DisplayWarningPopup( _WndMain, MSG_DISABLING_AUTOREFRESH, MSG_WARNING_TITLE );
+ WINDOWS_APPLICATION::DisableAutoRefresh();
+ }
+
+ return( TRUE );
+}
+
+
+
+
+
+BOOLEAN
+OpenSavedRegistries (
+ )
+
+/*++
+
+Routine Description:
+
+ Open the registries that were opened last time that regedit was run.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds
+
+
+--*/
+
+{
+ DSTRING MachineName;
+ WSTR Buffer[2048];
+ PWSTR Pointer;
+
+ Buffer[0] = ( WCHAR )'\0';
+ GetPrivateProfileString( _MsgSettings->GetWSTR(),
+ _MsgRegistry->GetWSTR(),
+ Buffer,
+ Buffer,
+ sizeof( Buffer ) / sizeof( WCHAR ),
+ _MsgIniFile->GetWSTR() );
+
+ if( Buffer[0] != ( WCHAR )'\0' ) {
+ Pointer = wcstok( Buffer, (LPWSTR)L"," );
+ while( Pointer != NULL ) {
+ if( _wcsicmp( Pointer, (PCWSTR)L"__Local_Computer" ) == 0 ) {
+ OpenRegistry( NULL );
+ } else {
+ if( MachineName.Initialize( Pointer ) ) {
+ OpenRegistry( &MachineName );
+ }
+ }
+ Pointer = wcstok( NULL, (LPWSTR)L"," );
+ }
+ } else {
+ OpenRegistry( NULL );
+ }
+ return( TRUE );
+}
+
+
+
+
+LONG
+APIENTRY
+EXPORT
+MainWndProc (
+ IN HWND hWnd,
+ IN WORD wMessage,
+ IN WPARAM wParam,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Handle all requests made of the REGEDIT window class.
+
+Arguments:
+
+ Standard Window's exported function signature.
+
+Return Value:
+
+ LONG - Returns 0 if the message was handled.
+
+--*/
+
+{
+ CLIENTCREATESTRUCT Ccs;
+
+
+ HWND CurrRegWin;
+ PREGISTRY_WINDOW ActiveWindow;
+ UINT ItemStatus;
+ INT PopupMenuId;
+ PWSTRING about_string;
+ PWSTR about_str;
+ DSTRING MachineName;
+ PREGISTRY_WINDOW_SET RegistryWindowSet;
+ HCURSOR Cursor;
+ DSTRING FindString;
+ LONG SaveHelpContext;
+
+
+
+ if( _MDIHandle != NULL ) {
+ CurrRegWin = (HWND)SendMessage( _MDIHandle, WM_MDIGETACTIVE, 0, 0 );
+ } else {
+ CurrRegWin = NULL;
+ }
+ //
+ // WM_CREATE is handled specially as it is when the connection between
+ // a Window and its associated object is established.
+ //
+
+ if( wMessage == WM_CREATE ) {
+
+ InitializeFont();
+
+ //
+ // Create the MDICLIENT window.
+ //
+
+ Ccs.hWindowMenu = GetSubMenu( GetMenu( hWnd ), WINDOW_MENU );
+ Ccs.idFirstChild = FIRST_CHILD;
+
+ _MDIHandle = CreateWindow( (LPWSTR)L"MDICLIENT",
+ NULL,
+ WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL,
+ 0,
+ 0,
+ 0,
+ 0,
+ hWnd, (
+ HMENU)1,
+ (HINSTANCE)WINDOWS_APPLICATION::QueryInstance(),
+ ( LPVOID ) &Ccs );
+ if( _MDIHandle == NULL ) {
+ DebugPrint( "Could not create MDICLIENT window\n" );
+ return( 0 );
+ }
+
+ _PrintManager = ( PRINT_MANAGER* )NEW( PRINT_MANAGER );
+ DebugPtrAssert( _PrintManager );
+ _PrintManager->Initialize( hWnd );
+
+ PostMessage( hWnd, RE_OPEN_LOCAL_REGISTRY, 0, 0 );
+
+ } else {
+
+ if( wMessage == _FindReplaceMsg ) {
+ if( CurrRegWin != NULL ) {
+
+ if( _FindReplace.Flags & FR_DIALOGTERM ) {
+ _FindReplace.Flags &= ~FR_DIALOGTERM;
+ WINDOWS_APPLICATION::_hDlgFindReplace = NULL;
+ WINDOWS_APPLICATION::SetHelpContext( -1 );
+ return( 0 );
+ }
+
+ if( !FindString.Initialize( _FindReplace.lpstrFindWhat ) ) {
+ DebugPrint( "FindString.Initialize() failed" );
+ return( 0 );
+ }
+ SendMessage( CurrRegWin,
+ FIND_KEY,
+ ( WPARAM )&FindString,
+ ( LPARAM )_FindReplace.Flags );
+ }
+ return( 0 );
+ }
+
+
+ if( wMessage == _CommonDlgHelpMsg ) {
+ DisplayHelp();
+ return( 0 );
+ }
+
+
+
+
+ if( _MDIHandle != NULL ) {
+ //
+ // Check the 'this' wasn't trampled.
+ //
+
+ DbgWinAssert( hWnd == _WndMain );
+
+ switch( wMessage ) {
+
+ case RE_OPEN_LOCAL_REGISTRY:
+
+ OpenSavedRegistries();
+ break;
+
+
+ case WM_INITMENUPOPUP:
+
+ if( HIWORD( lParam ) == 0 ) {
+ //
+ // init'ing a menu other than the system menu
+ //
+// ItemStatus = ( UINT )( ( CurrRegWin == NULL )? MF_GRAYED : MF_ENABLED);
+
+ PopupMenuId = LOWORD( lParam );
+ if (WINDOWS_APPLICATION::_ChildWindowMaximized) {
+ PopupMenuId--;
+ }
+
+ switch( PopupMenuId ) {
+
+ case FILE_MENU:
+
+ EnableMenuItem( ( HMENU )wParam, IDM_OPEN_REGISTRY, ( UINT )MF_ENABLED );
+ EnableMenuItem( ( HMENU )wParam, IDM_SELECT_COMPUTER, ( UINT )MF_ENABLED );
+ EnableMenuItem( ( HMENU )wParam, IDM_PRINTER_SETUP, ( UINT )MF_ENABLED );
+
+ ItemStatus = ( CurrRegWin == NULL )? ( UINT )MF_GRAYED : ( UINT )MF_ENABLED;
+ EnableMenuItem( ( HMENU )wParam, IDM_CLOSE_REGISTRY, ItemStatus );
+
+ if( ( CurrRegWin == NULL ) || IsIconic( CurrRegWin ) ) {
+ EnableMenuItem( ( HMENU )wParam, IDM_SAVE_REGISTRY_ON, ( UINT )MF_GRAYED );
+ EnableMenuItem( ( HMENU )wParam, IDM_PRINT, ( UINT )MF_GRAYED );
+ EnableMenuItem( ( HMENU )wParam, IDM_LOAD_HIVE, ( UINT )MF_GRAYED );
+ EnableMenuItem( ( HMENU )wParam, IDM_UNLOAD_HIVE, ( UINT )MF_GRAYED );
+ EnableMenuItem( ( HMENU )wParam, IDM_RESTORE_KEY, ( UINT )MF_GRAYED );
+ EnableMenuItem( ( HMENU )wParam, IDM_RESTORE_KEY_VOLATILE, ( UINT )MF_GRAYED );
+ EnableMenuItem( ( HMENU )wParam, IDM_SAVE_KEY, ( UINT )MF_GRAYED );
+ return( 0 );
+ } else {
+ EnableMenuItem( ( HMENU )wParam, IDM_SAVE_REGISTRY_ON, ( UINT )MF_ENABLED );
+ EnableMenuItem( ( HMENU )wParam, IDM_PRINT, ( UINT )MF_ENABLED );
+ }
+
+// if( WINDOWS_APPLICATION::IsRemoteAccessEnabled() ) {
+// EnableMenuItem( ( HMENU )wParam,
+// IDM_SELECT_COMPUTER,
+// ( UINT )MF_ENABLED );
+// } else {
+// EnableMenuItem( ( HMENU )wParam,
+// IDM_SELECT_COMPUTER,
+// ( UINT )MF_GRAYED );
+// }
+ break;
+
+
+ case EDIT_MENU:
+
+ if( ( CurrRegWin == NULL ) || IsIconic( CurrRegWin ) ) {
+ EnableMenuItem( ( HMENU )wParam, IDM_ADD_KEY, ( UINT )MF_GRAYED );
+ EnableMenuItem( ( HMENU )wParam, IDM_ADD_VALUE,( UINT )MF_GRAYED );
+ EnableMenuItem( ( HMENU )wParam, IDM_DELETE, ( UINT )MF_GRAYED );
+ EnableMenuItem( ( HMENU )wParam, IDM_BINARY, ( UINT )MF_GRAYED );
+ EnableMenuItem( ( HMENU )wParam, IDM_STRING, ( UINT )MF_GRAYED );
+ EnableMenuItem( ( HMENU )wParam, IDM_ULONG, ( UINT )MF_GRAYED );
+ EnableMenuItem( ( HMENU )wParam, IDM_MULTISZ, ( UINT )MF_GRAYED );
+ return( 0 );
+ }
+ break;
+
+
+ case TREE_MENU:
+
+ if( ( CurrRegWin == NULL ) || IsIconic( CurrRegWin ) ) {
+ EnableMenuItem( ( HMENU )wParam, IDM_EXPAND_ONE_LEVEL, ( UINT )MF_GRAYED );
+ EnableMenuItem( ( HMENU )wParam, IDM_EXPAND_BRANCH, ( UINT )MF_GRAYED );
+ EnableMenuItem( ( HMENU )wParam, IDM_EXPAND_ALL, ( UINT )MF_GRAYED );
+ EnableMenuItem( ( HMENU )wParam, IDM_COLLAPSE_BRANCH, ( UINT )MF_GRAYED );
+ return( 0 );
+ }
+ break;
+
+
+ case VIEW_MENU:
+
+ if( ( CurrRegWin == NULL ) || IsIconic( CurrRegWin ) ) {
+ EnableMenuItem( ( HMENU )wParam, IDM_TREE_ONLY, ( UINT )MF_GRAYED );
+ EnableMenuItem( ( HMENU )wParam, IDM_DATA_ONLY, ( UINT )MF_GRAYED );
+ EnableMenuItem( ( HMENU )wParam, IDM_TREE_AND_DATA, ( UINT )MF_GRAYED );
+ EnableMenuItem( ( HMENU )wParam, IDM_SPLIT, ( UINT )MF_GRAYED );
+ EnableMenuItem( ( HMENU )wParam, IDM_DISPLAY_BINARY,( UINT )MF_GRAYED );
+ EnableMenuItem( ( HMENU )wParam, IDM_REFRESH, ( UINT )MF_GRAYED );
+ EnableMenuItem( ( HMENU )wParam, IDM_REFRESH_ALL, ( UINT )MF_GRAYED );
+ EnableMenuItem( ( HMENU )wParam, IDM_FIND_KEY, ( UINT )MF_GRAYED );
+ return( 0 );
+ } else {
+ EnableMenuItem( ( HMENU )wParam, IDM_TREE_ONLY, (UINT) MF_ENABLED );
+ EnableMenuItem( ( HMENU )wParam, IDM_DATA_ONLY, (UINT) MF_ENABLED );
+ EnableMenuItem( ( HMENU )wParam, IDM_TREE_AND_DATA,(UINT) MF_ENABLED );
+ EnableMenuItem( ( HMENU )wParam, IDM_SPLIT, (UINT) MF_ENABLED );
+ if( WINDOWS_APPLICATION::IsAutoRefreshEnabled() ) {
+ EnableMenuItem( ( HMENU )wParam, IDM_REFRESH, (UINT) MF_GRAYED );
+ EnableMenuItem( ( HMENU )wParam, IDM_REFRESH_ALL, (UINT) MF_GRAYED );
+ } else {
+ EnableMenuItem( ( HMENU )wParam, IDM_REFRESH, (UINT) MF_ENABLED );
+ EnableMenuItem( ( HMENU )wParam, IDM_REFRESH_ALL, (UINT) MF_ENABLED );
+ }
+ EnableMenuItem( ( HMENU )wParam, ( UINT )IDM_FIND_KEY,(UINT) MF_ENABLED );
+ }
+ break;
+
+
+ case SECURITY_MENU:
+
+ EnableMenuItem( ( HMENU )wParam, IDM_AUDITING, ( UINT )MF_GRAYED );
+ if( ( CurrRegWin == NULL ) || IsIconic( CurrRegWin ) ) {
+ EnableMenuItem( ( HMENU )wParam, IDM_PERMISSIONS, ( UINT )MF_GRAYED );
+ EnableMenuItem( ( HMENU )wParam, IDM_OWNER, ( UINT )MF_GRAYED );
+ return( 0 );
+ }
+ break;
+
+
+ case OPTIONS_MENU:
+ if( WINDOWS_APPLICATION::IsAutoRefreshEnabled() ) {
+ ItemStatus = (UINT)MF_CHECKED;
+ } else {
+ ItemStatus = (UINT)MF_UNCHECKED;
+ }
+ CheckMenuItem( ( HMENU )wParam,
+ ( UINT )IDM_TOGGLE_AUTO_REFRESH,
+ ItemStatus );
+
+ if( WINDOWS_APPLICATION::IsReadOnlyModeEnabled() ) {
+ ItemStatus = (UINT)MF_CHECKED;
+ } else {
+ ItemStatus = (UINT)MF_UNCHECKED;
+ }
+ CheckMenuItem( ( HMENU )wParam,
+ ( UINT )IDM_TOGGLE_READ_ONLY_MODE,
+ ItemStatus );
+
+// if( WINDOWS_APPLICATION::IsRemoteAccessEnabled() ) {
+// ItemStatus = MF_CHECKED;
+// } else {
+// ItemStatus = MF_UNCHECKED;
+// }
+// CheckMenuItem( ( HMENU )wParam,
+// ( UINT )IDM_TOGGLE_REMOTE_ACCESS,
+// ItemStatus );
+
+
+ if( WINDOWS_APPLICATION::IsConfirmOnDeleteEnabled() ) {
+ ItemStatus = (UINT)MF_CHECKED;
+ } else {
+ ItemStatus = (UINT)MF_UNCHECKED;
+ }
+
+ CheckMenuItem( ( HMENU )wParam,
+ ( UINT )IDM_TOGGLE_CONFIRM_ON_DELETE,
+ ItemStatus );
+ if( WINDOWS_APPLICATION::IsReadOnlyModeEnabled() ) {
+ ItemStatus = (UINT)MF_GRAYED;
+ } else {
+ ItemStatus = (UINT)MF_ENABLED;
+ }
+ EnableMenuItem( ( HMENU )wParam,
+ ( UINT )IDM_TOGGLE_CONFIRM_ON_DELETE,
+ ItemStatus );
+
+ if( WINDOWS_APPLICATION::IsSaveSettingsEnabled() ) {
+ ItemStatus = (UINT)MF_CHECKED;
+ } else {
+ ItemStatus = (UINT)MF_UNCHECKED;
+ }
+ CheckMenuItem( ( HMENU )wParam,
+ ( UINT )IDM_TOGGLE_SAVE_SETTINGS,
+ ItemStatus );
+
+ break;
+
+ case WINDOW_MENU:
+
+ ItemStatus = ( CurrRegWin == NULL )? ( UINT )MF_GRAYED : ( UINT )MF_ENABLED;
+ EnableMenuItem( ( HMENU )wParam, IDM_CASCADE, ItemStatus );
+ EnableMenuItem( ( HMENU )wParam, IDM_TILE, ItemStatus );
+ EnableMenuItem( ( HMENU )wParam, IDM_ARRANGE, ItemStatus );
+ break;
+
+
+ default:
+
+ break;
+
+ }
+
+ if( CurrRegWin ) {
+ SendMessage( CurrRegWin, wMessage, wParam, lParam );
+ }
+ }
+ break;
+
+ case WM_MENUSELECT:
+
+ SetMenuItemHelpContext(wParam,lParam);
+ break;
+
+
+ case REGEDIT_HELP_KEY:
+ DisplayHelp();
+ break;
+
+
+
+ case WM_DESTROY:
+ WinHelp( _WndMain, _HelpFileString, (UINT)HELP_QUIT, 0 );
+ PostQuitMessage( 0 );
+ break;
+
+ case WM_SYSCOMMAND:
+
+ if( wParam == SC_CLOSE ) {
+
+ SaveSettings();
+ if( WINDOWS_APPLICATION::IsSaveSettingsEnabled() ) {
+ EnumChildWindows( _MDIHandle,
+ ( WNDENUMPROC )SaveRegistryWindowsInfo,
+ NULL );
+ }
+
+ SendMessage( hWnd, WM_CLOSE, 0, 0 );
+ } else {
+ return DefFrameProc( hWnd, _MDIHandle, wMessage, wParam, lParam );
+
+ }
+ break;
+
+
+ case WM_COMMAND:
+
+ switch( LOWORD( wParam ) ) {
+
+ //
+ // forward these menu messages to the active RegWin
+ //
+
+ case ID_ENTER_KEY:
+ case ID_TOGGLE_FOCUS:
+ case IDM_EXPAND_ONE_LEVEL:
+ case IDM_EXPAND_BRANCH:
+ case IDM_EXPAND_ALL:
+ case IDM_COLLAPSE_BRANCH:
+
+ case IDM_TREE_AND_DATA:
+ case IDM_TREE_ONLY:
+ case IDM_DATA_ONLY:
+ case IDM_SPLIT:
+
+ case IDM_BINARY:
+ case IDM_STRING:
+ case IDM_ULONG:
+ case IDM_MULTISZ:
+
+ case IDM_REFRESH:
+
+ DbgWinPtrAssert( CurrRegWin );
+ SendMessage( CurrRegWin, wMessage, wParam, lParam );
+ break;
+
+
+ case IDM_FIND_KEY:
+ SaveHelpContext = WINDOWS_APPLICATION::GetHelpContext();
+ WINDOWS_APPLICATION::SetHelpContext( IDH_DB_FINDKEY_REGED );
+ if( WINDOWS_APPLICATION::_hDlgFindReplace != NULL ) {
+ SetFocus( WINDOWS_APPLICATION::_hDlgFindReplace );
+ } else {
+ WINDOWS_APPLICATION::_hDlgFindReplace = FindText( &_FindReplace );
+ }
+// WINDOWS_APPLICATION::SetHelpContext( SaveHelpContext );
+ break;
+
+ case IDM_REFRESH_ALL:
+
+ EnumChildWindows( _MDIHandle,
+ ( WNDENUMPROC )RefreshRegistryWindow,
+ NULL );
+ break;
+
+ case IDM_TOGGLE_AUTO_REFRESH:
+
+ if( WINDOWS_APPLICATION::IsAutoRefreshEnabled() ) {
+ WINDOWS_APPLICATION::DisableAutoRefresh();
+ } else {
+ WINDOWS_APPLICATION::EnableAutoRefresh();
+ EnumChildWindows( _MDIHandle,
+ ( WNDENUMPROC )RefreshRegistryWindow,
+ NULL );
+
+ }
+ break;
+
+ case IDM_TOGGLE_READ_ONLY_MODE:
+
+ if( WINDOWS_APPLICATION::IsReadOnlyModeEnabled() ) {
+ WINDOWS_APPLICATION::DisableReadOnlyMode();
+ } else {
+ WINDOWS_APPLICATION::EnableReadOnlyMode();
+ }
+ break;
+
+
+// case IDM_TOGGLE_REMOTE_ACCESS:
+//
+//
+// if( WINDOWS_APPLICATION::IsRemoteAccessEnabled() ) {
+// WINDOWS_APPLICATION::DisableRemoteAccess();
+// EnumChildWindows( _MDIHandle,
+// ( FARPROC ) CloseRemoteRegistries, 0 );
+// } else {
+// WINDOWS_APPLICATION::EnableRemoteAccess();
+// }
+// break;
+
+
+ case IDM_TOGGLE_CONFIRM_ON_DELETE:
+
+ if( WINDOWS_APPLICATION::IsConfirmOnDeleteEnabled() ) {
+ WINDOWS_APPLICATION::DisableConfirmOnDelete();
+ } else {
+ WINDOWS_APPLICATION::EnableConfirmOnDelete();
+ }
+ break;
+
+
+ case IDM_TOGGLE_SAVE_SETTINGS:
+
+ if( WINDOWS_APPLICATION::IsSaveSettingsEnabled() ) {
+ WINDOWS_APPLICATION::DisableSaveSettings();
+ } else {
+ WINDOWS_APPLICATION::EnableSaveSettings();
+ }
+ break;
+
+
+ //
+ // Handle menu commands.
+ //
+
+ case IDM_OPEN_REGISTRY:
+
+ //
+ // Open registry of local machine
+ //
+ OpenRegistry( NULL );
+ break;
+
+ case IDM_SELECT_COMPUTER:
+
+ //
+ // Open registry of remote machine
+ //
+ if( SelectComputer( hWnd, &MachineName ) ) {
+ Cursor = WINDOWS_APPLICATION::DisplayHourGlass();
+ OpenRegistry( &MachineName );
+ WINDOWS_APPLICATION::RestoreCursor( Cursor );
+ }
+ break;
+
+
+ case IDM_CLOSE_REGISTRY:
+
+ if( CurrRegWin != NULL ) {
+ //
+ // If there is a registry window currently selected
+ // close all registry windows associated to it
+ //
+ ActiveWindow = ( PREGISTRY_WINDOW ) GetObjectPointer( CurrRegWin );
+ RegistryWindowSet = ActiveWindow->_RegistryWindowSet;
+ if( RegistryWindowSet == NULL ) {
+ DebugPrint( "RegistryWindowSet is NULL" );
+ DebugPtrAssert( RegistryWindowSet );
+ return( 0 );
+ }
+ CloseRegistry( RegistryWindowSet );
+ }
+
+
+ break;
+
+ case IDM_SAVE_REGISTRY_ON:
+
+ if( CurrRegWin != NULL ) {
+ SaveHelpContext = WINDOWS_APPLICATION::GetHelpContext();
+ WINDOWS_APPLICATION::SetHelpContext( IDH_DB_SAVESUB_REGED );
+ ActiveWindow = ( PREGISTRY_WINDOW ) GetObjectPointer( CurrRegWin );
+ DbgWinPtrAssert( ActiveWindow );
+ _PrintManager->PrintToTextFile( WINDOWS_APPLICATION::QueryInstance(),
+ hWnd,
+ _MDIHandle,
+ ActiveWindow->GetInternalRegistry(),
+ ActiveWindow->GetCurrentNode() );
+ WINDOWS_APPLICATION::SetHelpContext( SaveHelpContext );
+ }
+
+ break;
+
+ case IDM_FONT:
+
+ SaveHelpContext = WINDOWS_APPLICATION::GetHelpContext();
+ WINDOWS_APPLICATION::SetHelpContext( IDH_DB_FONT_REGED );
+ ChangeFont( hWnd, wMessage, wParam, lParam );
+ WINDOWS_APPLICATION::SetHelpContext( SaveHelpContext );
+ break;
+
+ case IDM_SAVE_KEY:
+ case IDM_RESTORE_KEY:
+ case IDM_RESTORE_KEY_VOLATILE:
+
+ if( CurrRegWin != NULL ) {
+ SaveHelpContext = WINDOWS_APPLICATION::GetHelpContext();
+ if( wParam == IDM_RESTORE_KEY ) {
+ WINDOWS_APPLICATION::SetHelpContext( IDH_DB_RESTOREKEY_REGED );
+ } else if( wParam == IDM_RESTORE_KEY_VOLATILE ) {
+ WINDOWS_APPLICATION::SetHelpContext( IDH_DB_RESTOREVOLATILE_REGED );
+ } else {
+ WINDOWS_APPLICATION::SetHelpContext( IDH_DB_SAVEKEY_REGED );
+ }
+ ProcessSaveRestoreKeyMessage( CurrRegWin, wParam );
+ WINDOWS_APPLICATION::SetHelpContext( SaveHelpContext );
+ }
+ break;
+
+ case IDM_LOAD_HIVE:
+ if( CurrRegWin != NULL ) {
+ SaveHelpContext = WINDOWS_APPLICATION::GetHelpContext();
+ WINDOWS_APPLICATION::SetHelpContext( IDH_DB_LOADHIVE_REGED );
+ ProcessLoadHiveMessage( CurrRegWin );
+ WINDOWS_APPLICATION::SetHelpContext( SaveHelpContext );
+ }
+ break;
+
+
+ case IDM_UNLOAD_HIVE:
+ if( CurrRegWin != NULL ) {
+ SendMessage( CurrRegWin, UNLOAD_HIVE, 0, 0 );
+ }
+ break;
+
+
+
+ case IDM_PRINT:
+
+ if( CurrRegWin != NULL ) {
+ ActiveWindow = ( PREGISTRY_WINDOW ) GetObjectPointer( CurrRegWin );
+ DbgWinPtrAssert( ActiveWindow );
+ ActiveWindow->DisableNotificationThread();
+ _PrintManager->PrintRegistry( WINDOWS_APPLICATION::QueryInstance(),
+ hWnd,
+ _MDIHandle,
+ ActiveWindow->GetInternalRegistry(),
+ ActiveWindow->GetCurrentNode() );
+ ActiveWindow->EnableNotificationThread();
+ }
+
+ break;
+
+ case IDM_PRINTER_SETUP:
+
+ SaveHelpContext = WINDOWS_APPLICATION::GetHelpContext();
+ WINDOWS_APPLICATION::SetHelpContext( IDH_DB_SETUP_REGED );
+ _PrintManager->PrinterSetupDialog();
+ WINDOWS_APPLICATION::SetHelpContext( SaveHelpContext );
+ break;
+
+
+ case IDM_EXIT:
+
+ SaveSettings();
+ if( WINDOWS_APPLICATION::IsSaveSettingsEnabled() ) {
+ EnumChildWindows( _MDIHandle,
+ ( WNDENUMPROC )SaveRegistryWindowsInfo,
+ NULL );
+ }
+
+ SendMessage( hWnd, WM_CLOSE, 0, 0 );
+ break;
+
+ case IDM_DELETE:
+ case IDM_INSERT:
+ case IDM_ADD_KEY:
+ case IDM_ADD_VALUE:
+ case IDM_DISPLAY_BINARY:
+
+ DbgWinPtrAssert( CurrRegWin );
+ SendMessage( CurrRegWin, wMessage, wParam, lParam );
+ break;
+
+ case IDM_PERMISSIONS:
+
+ SaveHelpContext = WINDOWS_APPLICATION::GetHelpContext();
+ WINDOWS_APPLICATION::SetHelpContext( IDH_DB_PERMISSION_REGED );
+
+ case IDM_AUDITING:
+
+ SaveHelpContext = WINDOWS_APPLICATION::GetHelpContext();
+ WINDOWS_APPLICATION::SetHelpContext( IDH_DB_AUDIT_REGED );
+
+ case IDM_OWNER:
+
+ DbgWinPtrAssert( CurrRegWin );
+ SaveHelpContext = WINDOWS_APPLICATION::GetHelpContext();
+ WINDOWS_APPLICATION::SetHelpContext( IDH_DB_OWNER_REGED );
+ SendMessage( CurrRegWin, wMessage, wParam, lParam );
+ WINDOWS_APPLICATION::SetHelpContext( SaveHelpContext );
+ break;
+
+ case IDM_CASCADE:
+
+ CascadeRegistryWindows( );
+ break;
+
+ case IDM_TILE:
+
+ TileRegistryWindows( );
+ break;
+
+ case IDM_ARRANGE:
+
+ SendMessage( _MDIHandle, WM_MDIICONARRANGE, 0, 0 );
+ break;
+
+ case IDM_CONTENTS:
+
+ if( !WinHelp( _WndMain, _HelpFileString, (UINT)HELP_FINDER, 0 ) ){
+ DebugPrint( "WinHelp() failed" );
+ }
+ break;
+
+ case IDM_SEARCH_FOR_HELP:
+ if( !WinHelp( _WndMain, _HelpFileString, (UINT)HELP_PARTIALKEY, (DWORD)"" ) ){
+ DebugPrint( "WinHelp() failed" );
+ }
+ break;
+
+
+ case IDM_HOW_TO_USE_HELP:
+ if( !WinHelp( _WndMain, _HelpFileString, (UINT)HELP_HELPONHELP, 0 ) ){
+ DebugPrint( "WinHelp() failed" );
+ }
+ break;
+
+ case IDM_ABOUT:
+
+ about_string = REGEDIT_BASE_SYSTEM::QueryString( MSG_REGISTRY_EDITOR, "" );
+ if (!about_string) {
+ break;
+ }
+
+ about_str = about_string->QueryWSTR();
+ DELETE(about_string);
+
+ ShellAbout( hWnd, about_str, NULL, 0 );
+ DELETE(about_str);
+ break;
+
+ default:
+ //
+ // Let Windows handle this message
+ //
+ return DefFrameProc( hWnd, _MDIHandle, wMessage, wParam, lParam );
+ }
+ break;
+
+ case WM_SYSCOLORCHANGE:
+
+ WINDOWS_APPLICATION::DeleteBitmaps();
+ WINDOWS_APPLICATION::LoadBitmaps();
+ break;
+
+ default:
+ //
+ // Let Windows handle this message
+ //
+ return DefFrameProc( hWnd, _MDIHandle, wMessage, wParam, lParam );
+ }
+ } else {
+
+ //
+ // Let Windows handle this message.
+ //
+
+ return DefFrameProc( hWnd, NULL, wMessage, wParam, lParam );
+ }
+
+ }
+ return 0 ;
+}
+
+
+BOOLEAN AdjustPrivilege( LPWSTR );
+
+
+
+BOOLEAN
+ParseCommandLine(
+ )
+
+/*++
+
+Routine Description:
+
+ Parse the command line, and initilize some of the global flags, based
+ on the arguments found in the command line
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the command line was successfuly parsed.
+
+
+--*/
+
+
+{
+ ARGUMENT_LEXEMIZER ArgLex;
+ ARRAY LexArray;
+ ARRAY ArgumentArray;
+ STRING_ARGUMENT ProgramNameArgument;
+ FLAG_ARGUMENT FlagReadOnlyMode; // FlagReverseSortOrder;
+ FLAG_ARGUMENT FlagAccessRemote; //
+
+ FLAG_ARGUMENT FlagDisplayHelp;
+
+
+
+ if ( !LexArray.Initialize( ) ) {
+ DebugPrint( "LexArray.Initialize() failed \n" );
+ return( FALSE );
+ }
+ if ( !ArgLex.Initialize( &LexArray ) ) {
+ DebugPrint( "ArgLex.Initialize() failed \n" );
+ return( FALSE );
+ }
+ ArgLex.PutSwitches( (PCSTR)L"/" );
+ ArgLex.SetCaseSensitive( FALSE );
+ if( !ArgLex.PrepareToParse() ) {
+ DebugPrint( "ArgLex.PrepareToParse() failed \n" );
+ return( FALSE );
+ }
+
+ if ( !ArgumentArray.Initialize() ) {
+ DebugPrint( "ArgumentArray.Initialize() failed \n" );
+ return( FALSE );
+ }
+ if( !ProgramNameArgument.Initialize((PSTR)L"*") ||
+ !FlagReadOnlyMode.Initialize( (PSTR)L"/R" ) ||
+ !FlagAccessRemote.Initialize( (PSTR)L"/N" ) ||
+ !FlagDisplayHelp.Initialize( (PSTR)L"/?" )) {
+ DebugPrint( "Unable to initialize flag or string arguments \n" );
+ return( FALSE );
+ }
+ if( !ArgumentArray.Put( &ProgramNameArgument ) ||
+ !ArgumentArray.Put( &FlagReadOnlyMode ) ||
+ !ArgumentArray.Put( &FlagAccessRemote ) ||
+ !ArgumentArray.Put( &FlagDisplayHelp ) ) {
+ DebugPrint( "ArgumentArray.Put() failed \n" );
+ return( FALSE );
+ }
+
+ ArgLex.DoParsing( &ArgumentArray );
+
+
+ if( FlagReadOnlyMode.QueryFlag() ) {
+ WINDOWS_APPLICATION::EnableReadOnlyMode();
+ }
+
+// if( FlagAccessRemote.QueryFlag() ) {
+// WINDOWS_APPLICATION::EnableRemoteAccess();
+// }
+ return( TRUE );
+}
+
+
+
+VOID
+GetSettings()
+
+/*++
+
+Routine Description:
+
+ Read the settings from regedit.ini file.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PWSTR MsgIniFileString;
+ PWSTR MsgSettingsString;
+ PWSTR MsgLeftString;
+ PWSTR MsgTopString;
+ PWSTR MsgWidthString;
+ PWSTR MsgHeightString;
+ PWSTR MsgMaximizedString;
+
+ PWSTR MsgAutoRefreshString;
+ PWSTR MsgReadOnlyString;
+// PWSTR MsgRemoteAccessString;
+ PWSTR MsgConfirmOnDeleteString;
+ PWSTR MsgSaveSettingsString;
+
+ INT Setting;
+
+
+
+
+ MsgIniFileString = _MsgIniFile->QueryWSTR();
+ MsgSettingsString = _MsgSettings->QueryWSTR();
+ MsgLeftString = _MsgLeft->QueryWSTR();
+ MsgTopString = _MsgTop->QueryWSTR();
+ MsgWidthString = _MsgWidth->QueryWSTR();
+ MsgHeightString = _MsgHeight->QueryWSTR();
+ MsgMaximizedString = _MsgMaximized->QueryWSTR();
+ MsgAutoRefreshString = _MsgAutoRefresh->QueryWSTR();
+ MsgReadOnlyString = _MsgReadOnly->QueryWSTR();
+// MsgRemoteAccessString = _MsgRemoteAccess->QueryWSTR();
+ MsgConfirmOnDeleteString = _MsgConfirmOnDelete->QueryWSTR();
+ MsgSaveSettingsString = _MsgSaveSettings->QueryWSTR();
+
+
+ if( ( MsgIniFileString == NULL ) ||
+ ( MsgSettingsString == NULL ) ||
+ ( MsgLeftString == NULL ) ||
+ ( MsgTopString == NULL ) ||
+ ( MsgWidthString == NULL ) ||
+ ( MsgHeightString == NULL ) ||
+ ( MsgMaximizedString == NULL ) ||
+ ( MsgAutoRefreshString == NULL ) ||
+ ( MsgReadOnlyString == NULL ) ||
+// ( MsgRemoteAccessString == NULL ) ||
+ ( MsgConfirmOnDeleteString == NULL ) ||
+ ( MsgSaveSettingsString == NULL ) ) {
+
+
+ DebugPrint( "Error: Unable to retrieve strings" );
+
+ FREE( MsgIniFileString );
+ FREE( MsgSettingsString );
+ FREE( MsgLeftString );
+ FREE( MsgTopString );
+ FREE( MsgWidthString );
+ FREE( MsgHeightString );
+ FREE( MsgMaximizedString );
+ FREE( MsgAutoRefreshString );
+ FREE( MsgReadOnlyString );
+// FREE( MsgRemoteAccessString );
+ FREE( MsgConfirmOnDeleteString );
+ FREE( MsgSaveSettingsString );
+
+ _RegeditFrameX = CW_USEDEFAULT;
+ _RegeditFrameY = CW_USEDEFAULT;
+ _RegeditFrameWidth = CW_USEDEFAULT;
+ _RegeditFrameHeight = CW_USEDEFAULT;
+ _RegeditFrameMaximized = FALSE;
+ WINDOWS_APPLICATION::EnableAutoRefresh();
+ WINDOWS_APPLICATION::DisableReadOnlyMode();
+// WINDOWS_APPLICATION::EnableRemoteAccess();
+ WINDOWS_APPLICATION::EnableConfirmOnDelete();
+ WINDOWS_APPLICATION::EnableSaveSettings();
+ return;
+ }
+
+
+
+
+ _RegeditFrameX = GetPrivateProfileInt( MsgSettingsString,
+ MsgLeftString,
+ CW_USEDEFAULT,
+ MsgIniFileString );
+
+ _RegeditFrameY = GetPrivateProfileInt( MsgSettingsString,
+ MsgTopString,
+ CW_USEDEFAULT,
+ MsgIniFileString );
+
+ _RegeditFrameWidth = GetPrivateProfileInt( MsgSettingsString,
+ MsgWidthString,
+ CW_USEDEFAULT,
+ MsgIniFileString );
+
+ _RegeditFrameHeight = GetPrivateProfileInt( MsgSettingsString,
+ MsgHeightString,
+ CW_USEDEFAULT,
+ MsgIniFileString );
+
+ _RegeditFrameMaximized = GetPrivateProfileInt( MsgSettingsString,
+ MsgMaximizedString,
+ FALSE,
+ MsgIniFileString );
+
+
+
+ Setting = GetPrivateProfileInt( MsgSettingsString,
+ MsgAutoRefreshString,
+ FALSE,
+ MsgIniFileString );
+
+ if( Setting != 0 ) {
+ WINDOWS_APPLICATION::EnableAutoRefresh();
+ } else {
+ WINDOWS_APPLICATION::DisableAutoRefresh();
+ }
+
+
+ Setting = GetPrivateProfileInt( MsgSettingsString,
+ MsgReadOnlyString,
+ FALSE,
+ MsgIniFileString );
+ if( Setting != 0 ) {
+ WINDOWS_APPLICATION::EnableReadOnlyMode();
+ } else {
+ WINDOWS_APPLICATION::DisableReadOnlyMode();
+ }
+
+// Setting = GetPrivateProfileInt( MsgSettingsString,
+// MsgRemoteAccessString,
+// TRUE,
+// MsgIniFileString );
+// if( Setting != 0 ) {
+// WINDOWS_APPLICATION::EnableRemoteAccess();
+// } else {
+// WINDOWS_APPLICATION::DisableRemoteAccess();
+// }
+
+ Setting = GetPrivateProfileInt( MsgSettingsString,
+ MsgConfirmOnDeleteString,
+ TRUE,
+ MsgIniFileString );
+ if( Setting != 0 ) {
+ WINDOWS_APPLICATION::EnableConfirmOnDelete();
+ } else {
+ WINDOWS_APPLICATION::DisableConfirmOnDelete();
+ }
+
+
+ Setting = GetPrivateProfileInt( MsgSettingsString,
+ MsgSaveSettingsString,
+ TRUE,
+ MsgIniFileString );
+ if( Setting != 0 ) {
+ WINDOWS_APPLICATION::EnableSaveSettings();
+ } else {
+ WINDOWS_APPLICATION::DisableSaveSettings();
+ }
+
+ FREE( MsgIniFileString );
+ FREE( MsgSettingsString );
+ FREE( MsgLeftString );
+ FREE( MsgTopString );
+ FREE( MsgWidthString );
+ FREE( MsgHeightString );
+ FREE( MsgMaximizedString );
+ FREE( MsgAutoRefreshString );
+ FREE( MsgReadOnlyString );
+// FREE( MsgRemoteAccessString );
+ FREE( MsgConfirmOnDeleteString );
+ FREE( MsgSaveSettingsString );
+}
+
+
+BOOL
+CheckPolicy()
+
+/*++
+
+Routine Description:
+
+ Checks if policy prevents regedt32 from running
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if regedt32 should terminate.
+ FALSE if not.
+
+--*/
+
+{
+ BOOL fRegistryToolDisabled = FALSE;
+ HKEY hKey;
+ DWORD Type;
+ DWORD ValueBuffer;
+ DWORD cbValueBuffer;
+ LONG lResult;
+
+ lResult = RegOpenKeyEx(HKEY_CURRENT_USER,
+ TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System"),
+ 0,
+ KEY_READ,
+ &hKey);
+
+ if (lResult != ERROR_SUCCESS) {
+ return FALSE;
+ }
+
+
+ cbValueBuffer = sizeof(DWORD);
+
+ lResult = RegQueryValueEx(hKey,
+ TEXT("DisableRegistryTools"),
+ NULL,
+ &Type,
+ (LPBYTE) &ValueBuffer,
+ &cbValueBuffer);
+
+
+ if (lResult == ERROR_SUCCESS &&
+ Type == REG_DWORD &&
+ cbValueBuffer == sizeof(DWORD) &&
+ ValueBuffer != FALSE) {
+
+ fRegistryToolDisabled = TRUE;
+ }
+
+ RegCloseKey(hKey);
+
+
+ if (fRegistryToolDisabled) {
+ TCHAR szTitle[100];
+ TCHAR szMsg[300];
+
+
+ LoadString ((HINSTANCE)_Module, MSG_REGISTRY_EDITOR, szTitle, 100);
+ LoadString ((HINSTANCE)_Module, MSG_REGEDIT_DISABLED, szMsg, 300);
+
+ MessageBox(NULL, szMsg, szTitle, MB_OK | MB_ICONERROR);
+
+ return TRUE;
+
+ }
+
+ return FALSE;
+
+}
+
+
+INT _CRTAPI1
+main()
+
+/*++
+
+Routine Description:
+
+ main is the entry point for RegEdit. It uses the WINDOWS_APPLICATION
+ class to store its global data, constructs and initializes a REGEDIT
+ window (i.e. frame window) and enters a message loop. The message loop
+ only exists when REGEDIT posts a quite message (usually as a result of
+ a user choosing Exit from the File menu).
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ INT - Returns the last wParam sent to RegEdit.
+
+--*/
+
+{
+ MSG msg;
+ HANDLE hAccel;
+ WCHAR Buffer[256];
+
+ WSTRING::SetAnsiConversions();
+
+ InitializeUapp();
+
+ _Module = GetModuleHandle( NULL );
+
+ if (CheckPolicy()) {
+ exit( 0 );
+ }
+
+
+ WINDOWS_APPLICATION::Initialize (
+ _Module,
+ NULL,
+ SW_SHOWDEFAULT,
+ NULL ); // MGetCmdLine()
+
+ WINDOWS_APPLICATION::SetHelpContext( -1 );
+
+
+ if( !InitializeGlobalStrings() ) {
+ DebugPrint( "InitializeGlobalStrings() failed" );
+ exit( 0 );
+ }
+ GetSettings();
+ ParseCommandLine();
+
+ WINDOWS_APPLICATION::_AutoRefreshEvent =
+ CreateEvent( NULL,
+ TRUE,
+ WINDOWS_APPLICATION::IsAutoRefreshEnabled(), // TRUE,
+ NULL );
+ Initialize( );
+
+ hAccel = LoadAccelerators( (HINSTANCE)WINDOWS_APPLICATION::QueryInstance(), (LPWSTR)L"RegEditAccel" );
+
+ hHook = SetWindowsHookEx(WH_MSGFILTER,(HOOKPROC)HookProc,NULL,GetCurrentThreadId());
+
+ WINDOWS_APPLICATION::_SACLEditorEnabled = AdjustPrivilege( (LPWSTR)SE_SECURITY_NAME );
+ WINDOWS_APPLICATION::_RestorePrivilege = AdjustPrivilege( (LPWSTR)SE_RESTORE_NAME );
+ WINDOWS_APPLICATION::_BackupPrivilege = AdjustPrivilege( (LPWSTR)SE_BACKUP_NAME );
+ WINDOWS_APPLICATION::_TakeOwnershipPrivilege = AdjustPrivilege( (LPWSTR)SE_TAKE_OWNERSHIP_NAME );
+
+// WINDOWS_APPLICATION::_RestorePrivilege = FALSE;
+// WINDOWS_APPLICATION::_BackupPrivilege = FALSE;
+
+ while( GetMessage( &msg, NULL, 0, 0 )) {
+
+ if( !WINDOWS_APPLICATION::_hDlgFindReplace ||
+ !IsDialogMessage( WINDOWS_APPLICATION::_hDlgFindReplace, &msg ) ) {
+ //
+ // Don't process the message if it is for the
+ // modeless Find dialog
+ //
+ if( ! TranslateMDISysAccel( _MDIHandle, &msg ) &&
+ ! TranslateAccelerator( _WndMain, (HACCEL)hAccel, &msg )) {
+
+ TranslateMessage( &msg );
+ DispatchMessage( &msg );
+ }
+ }
+ }
+ UnhookWindowsHookEx(hHook);
+ return msg.wParam;
+}
+
+
+
+INT
+DisplayConfirmPopup(
+ IN HWND hWnd,
+ IN INT TextMessage,
+ IN INT CaptionMessage
+ )
+/*++
+
+Routine Description:
+
+ This routine displays a application modal dialog box with
+ a warning icon and the given text. Two buttons (Yes and No) are displayed
+ in the dialog box.
+
+Arguments:
+
+ hWnd - Supplies the window handle.
+ TextMessage - Supplies the text for the dialog box.
+ CaptionMessage - Supplies the caption for the dialog box. If
+ this parameter is not supplied then the
+ system will use the default caption.
+
+Return Value:
+
+ UINT - Returns:
+
+ 0.......if an error has occurred
+ IDNO....if the user selected the button 'No'
+ IDYES...if the user selected the button 'Yes'
+
+--*/
+{
+ PWSTR textmsg = NULL;
+ PWSTR captionmsg = NULL;
+ PWSTRING t = NULL;
+ PWSTRING c = NULL;
+ INT rc = 0;
+ LONG SaveHelpContext;
+
+
+
+ if (!(t = REGEDIT_BASE_SYSTEM::QueryString(TextMessage, "")) ||
+ !(textmsg = t->QueryWSTR())) {
+
+ DELETE(t);
+ return 0;
+ }
+
+ if (CaptionMessage &&
+ (c = REGEDIT_BASE_SYSTEM::QueryString(CaptionMessage, ""))) {
+
+ captionmsg = c->QueryWSTR();
+ }
+
+ SaveHelpContext = WINDOWS_APPLICATION::GetHelpContext();
+ WINDOWS_APPLICATION::SetHelpContext( -1 );
+ rc = MessageBox(hWnd,
+ textmsg,
+ captionmsg,
+ (UINT)(MB_ICONQUESTION | MB_APPLMODAL | MB_YESNO | MB_DEFBUTTON2));
+ WINDOWS_APPLICATION::SetHelpContext( SaveHelpContext );
+
+ DELETE(t);
+ DELETE(textmsg);
+ DELETE(c);
+ DELETE(captionmsg);
+ return( rc );
+}
+
+
+
+
+
+
+VOID
+DisplayWarningPopup(
+ IN HWND hWnd,
+ IN INT TextMessage,
+ IN INT CaptionMessage
+ )
+/*++
+
+Routine Description:
+
+ This routine displays a application modal dialog box with
+ a warning icon and the given text.
+
+Arguments:
+
+ hWnd - Supplies the window handle.
+ TextMessage - Supplies the text for the dialog box.
+ CaptionMessage - Supplies the caption for the dialog box. If
+ this parameter is not supplied then the
+ system will use the default caption.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PWSTR textmsg = NULL;
+ PWSTR captionmsg = NULL;
+ PWSTRING t = NULL;
+ PWSTRING c = NULL;
+ LONG SaveHelpContext;
+
+ if (!(t = REGEDIT_BASE_SYSTEM::QueryString(TextMessage, "")) ||
+ !(textmsg = t->QueryWSTR())) {
+
+ DELETE(t);
+ return;
+ }
+
+ if (CaptionMessage &&
+ (c = REGEDIT_BASE_SYSTEM::QueryString(CaptionMessage, ""))) {
+
+ captionmsg = c->QueryWSTR();
+ }
+
+ SaveHelpContext = WINDOWS_APPLICATION::GetHelpContext();
+ WINDOWS_APPLICATION::SetHelpContext( -1 );
+ MessageBox(hWnd,
+ textmsg,
+ captionmsg,
+ (UINT)(MB_ICONEXCLAMATION | MB_APPLMODAL));
+ WINDOWS_APPLICATION::SetHelpContext( SaveHelpContext );
+
+ DELETE(t);
+ DELETE(textmsg);
+ DELETE(c);
+ DELETE(captionmsg);
+}
+
+
+
+
+
+VOID
+DisplayInfoPopup(
+ IN HWND hWnd,
+ IN INT TextMessage,
+ IN INT CaptionMessage
+ )
+/*++
+
+Routine Description:
+
+ This routine displays a application modal dialog box with
+ a info icon and the given text.
+
+Arguments:
+
+ hWnd - Supplies the window handle.
+ TextMessage - Supplies the text for the dialog box.
+ CaptionMessage - Supplies the caption for the dialog box. If
+ this parameter is not supplied then the
+ system will use the default caption.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PWSTR textmsg = NULL;
+ PWSTR captionmsg = NULL;
+ PWSTRING t = NULL;
+ PWSTRING c = NULL;
+ LONG SaveHelpContext;
+
+ if (!(t = REGEDIT_BASE_SYSTEM::QueryString(TextMessage, "")) ||
+ !(textmsg = t->QueryWSTR())) {
+
+ DELETE(t);
+ return;
+ }
+
+ if (CaptionMessage &&
+ (c = REGEDIT_BASE_SYSTEM::QueryString(CaptionMessage, ""))) {
+
+ captionmsg = c->QueryWSTR();
+ }
+
+ SaveHelpContext = WINDOWS_APPLICATION::GetHelpContext();
+ WINDOWS_APPLICATION::SetHelpContext( -1 );
+ MessageBox(hWnd,
+ textmsg,
+ captionmsg,
+ (UINT)(MB_ICONINFORMATION | MB_APPLMODAL));
+ WINDOWS_APPLICATION::SetHelpContext( SaveHelpContext );
+
+
+ DELETE(t);
+ DELETE(textmsg);
+ DELETE(c);
+ DELETE(captionmsg);
+}
+
+
+VOID
+DisplayHelp(
+ )
+
+/*++
+
+Routine Description:
+
+ Display context-sensitive help.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if( WINDOWS_APPLICATION::GetHelpContext() != -1 ) {
+ WinHelp( _WndMain,
+ _HelpFileString,
+ (UINT)HELP_CONTEXT,
+ WINDOWS_APPLICATION::GetHelpContext() );
+ DrawMenuBar( _WndMain );
+ }
+}
+
+
+
+
+
+BOOLEAN
+AdjustPrivilege(
+ PWSTR Privilege
+ )
+/*++
+
+Routine Description:
+
+ This routine tries to adjust the priviliege of the current process.
+
+
+Arguments:
+
+ Privilege - String with the name of the privilege to be adjusted.
+
+Return Value:
+
+ Returns TRUE if the privilege could be adjusted.
+ Returns FALSE, otherwise.
+
+
+--*/
+{
+ HANDLE TokenHandle;
+ LUID_AND_ATTRIBUTES LuidAndAttributes;
+
+ TOKEN_PRIVILEGES TokenPrivileges;
+
+
+ if( !OpenProcessToken( GetCurrentProcess(),
+ TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
+ &TokenHandle ) ) {
+ DebugPrint( "OpenProcessToken failed" );
+ return( FALSE );
+ }
+
+
+ if( !LookupPrivilegeValue( NULL,
+ Privilege, // (LPWSTR)SE_SECURITY_NAME,
+ &( LuidAndAttributes.Luid ) ) ) {
+ DebugPrintf( "LookupPrivilegeValue failed, Error = %#d \n", GetLastError() );
+ return( FALSE );
+ }
+
+ LuidAndAttributes.Attributes = SE_PRIVILEGE_ENABLED;
+ TokenPrivileges.PrivilegeCount = 1;
+ TokenPrivileges.Privileges[0] = LuidAndAttributes;
+
+ if( !AdjustTokenPrivileges( TokenHandle,
+ FALSE,
+ &TokenPrivileges,
+ 0,
+ NULL,
+ NULL ) ) {
+ DebugPrintf( "AdjustTokenPrivileges failed, Error = %#x \n", GetLastError() );
+ return( FALSE );
+ }
+
+ if( GetLastError() != NO_ERROR ) {
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+
+
+BOOLEAN
+ProcessLoadHiveMessage(
+ HWND CurrentRegistryWindow
+ )
+
+/*++
+
+Routine Description:
+
+ Process the message IDM_LOAD_HIVE.
+ This function will get a file name from the user, and load
+ it on the key currently selected.
+
+
+Arguments:
+
+
+ CurrentRegistryWindow - Handle to the registry window currently
+ active.
+
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the Print operation was succesful.
+
+--*/
+
+{
+ OPENFILENAME ofn;
+ WSTR filename[ MAX_PATH ];
+ WSTR filetitle[ MAX_PATH ];
+ WCHAR filter[ MAX_PATH ];
+#if 0
+ PWSTR filter[ ] = {
+ (LPWSTR)L"all", (LPWSTR)L"*.*",
+ (LPWSTR)L""
+ };
+#endif
+ DSTRING HiveName;
+ PCWSTR Title;
+
+
+
+ //
+ // Setup the OPENFILENAME structure.
+ //
+ swprintf( filter,
+ (LPWSTR)L"%ws%wc%ws%wc%wc%wc",
+ _AllFiles->GetWSTR(),
+ 0,
+ _StarDotStar->GetWSTR(),
+ 0,
+ 0, 0 );
+
+ filename[0] =( WCHAR )'\0';
+
+ Title = ( _LoadHiveTitle != NULL )? _LoadHiveTitle->GetWSTR() : NULL;
+
+
+ ofn.lStructSize = sizeof( OPENFILENAME );
+ ofn.hwndOwner = _WndMain;
+ ofn.hInstance = NULL;
+ ofn.lpstrFilter = filter;
+ ofn.lpstrCustomFilter = NULL;
+ ofn.nMaxCustFilter = 0;
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFile = filename;
+ ofn.nMaxFile = sizeof( filename )/sizeof( WCHAR );
+ ofn.lpstrFileTitle = filetitle;
+ ofn.nMaxFileTitle = sizeof( filetitle )/sizeof( WCHAR );
+ ofn.lpstrInitialDir = NULL;
+ ofn.lpstrTitle = Title;
+ ofn.Flags = OFN_SHOWHELP | OFN_HIDEREADONLY | OFN_NOREADONLYRETURN | OFN_FILEMUSTEXIST;
+ ofn.nFileOffset = 0;
+ ofn.nFileExtension = 0;
+ ofn.lpstrDefExt = NULL;
+ ofn.lCustData = 0;
+ ofn.lpfnHook = NULL;
+ ofn.lpTemplateName = NULL;
+
+
+ if( !GetOpenFileName( &ofn ) ) {
+ return( FALSE );
+ }
+
+ if( HiveName.Initialize( filename ) ) {
+ SendMessage( CurrentRegistryWindow,
+ LOAD_HIVE,
+ ( WPARAM )&HiveName,
+ NULL );
+ }
+
+ return( TRUE );
+}
+
+
+
+
+BOOLEAN
+ProcessSaveRestoreKeyMessage(
+ HWND CurrentRegistryWindow,
+ DWORD Msg
+ )
+
+/*++
+
+Routine Description:
+
+ Process the messages IDM_SAVE_KEY and IDM_RESTORE_KEY.
+ This function will get a file name from the user, and save or restore
+ a key on the key currently selected.
+
+
+Arguments:
+
+
+ CurrentRegistryWindow - Handle to the registry window currently
+ active.
+
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation was succesful.
+
+--*/
+
+{
+ OPENFILENAME ofn;
+ WSTR filename[ MAX_PATH ];
+ WSTR filetitle[ MAX_PATH ];
+#if 0
+ PWSTR filter[ ] = {
+ (LPWSTR)L"all", (LPWSTR)L"*.*",
+ (LPWSTR)L""
+ };
+#endif
+
+ WCHAR filter[ MAX_PATH ];
+
+ DWORD Flags;
+ DSTRING FileName;
+ PCWSTR Title;
+ DWORD Message;
+ HANDLE Handle;
+ WIN32_FIND_DATA FindData;
+
+
+ //
+ // Setup the OPENFILENAME structure.
+ //
+
+ swprintf( filter,
+ (LPWSTR)L"%ws%wc%ws%wc%wc%wc",
+ _AllFiles->GetWSTR(),
+ 0,
+ _StarDotStar->GetWSTR(),
+ 0,
+ 0, 0 );
+
+ Flags = OFN_SHOWHELP;
+ if( Msg != IDM_SAVE_KEY ) {
+ Flags |= OFN_FILEMUSTEXIST;
+ Title = ( _RestoreKeyTitle != NULL )? _RestoreKeyTitle->GetWSTR() :
+ NULL;
+ Message = ( Msg == IDM_RESTORE_KEY )? RESTORE_KEY : RESTORE_KEY_VOLATILE;
+ } else {
+ Flags |= OFN_OVERWRITEPROMPT | OFN_HIDEREADONLY | OFN_NOREADONLYRETURN;
+ Message = SAVE_KEY;
+ Title = ( _SaveKeyTitle != NULL )? _SaveKeyTitle->GetWSTR() :
+ NULL;
+ }
+
+ filename[0] =( WCHAR )'\0';
+
+ ofn.lStructSize = sizeof( OPENFILENAME );
+ ofn.hwndOwner = _WndMain;
+ ofn.hInstance = NULL;
+ ofn.lpstrFilter = filter;
+ ofn.lpstrCustomFilter = NULL;
+ ofn.nMaxCustFilter = 0;
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFile = filename;
+ ofn.nMaxFile = sizeof( filename )/sizeof( WCHAR );
+ ofn.lpstrFileTitle = filetitle;
+ ofn.nMaxFileTitle = sizeof( filetitle )/sizeof( WCHAR );
+ ofn.lpstrInitialDir = NULL;
+ ofn.lpstrTitle = Title;
+ ofn.Flags = Flags;
+ ofn.nFileOffset = 0;
+ ofn.nFileExtension = 0;
+ ofn.lpstrDefExt = NULL;
+ ofn.lCustData = 0;
+ ofn.lpfnHook = NULL;
+ ofn.lpTemplateName = NULL;
+
+
+ if( ( Msg == IDM_RESTORE_KEY ) ||
+ ( Msg == IDM_RESTORE_KEY_VOLATILE )) {
+ if( !GetOpenFileName( &ofn ) ) {
+ return( FALSE );
+ }
+ } else {
+ if( !GetSaveFileName( &ofn ) ) {
+ return( FALSE );
+ }
+ }
+
+ if( FileName.Initialize( filename ) ) {
+ if( Msg == IDM_SAVE_KEY ) {
+ //
+ // Delete the file if it already exists
+ //
+ Handle = FindFirstFile( filename,
+ &FindData );
+ if( Handle != INVALID_HANDLE_VALUE ) {
+ FindClose( Handle );
+ DeleteFile( filename );
+ }
+ }
+
+ SendMessage( CurrentRegistryWindow,
+ ( UINT )Message,
+ ( WPARAM )&FileName,
+ NULL );
+ }
+
+ return( TRUE );
+}
diff --git a/private/utils/regedit/src/regedval.cxx b/private/utils/regedit/src/regedval.cxx
new file mode 100644
index 000000000..4584c164f
--- /dev/null
+++ b/private/utils/regedit/src/regedval.cxx
@@ -0,0 +1,637 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ regedval.cxx
+
+Abstract:
+
+ This module contains the methods for the REGEDIT_FORMATTED_VALUE_ENTRY
+ class.
+
+Author:
+
+ Jaime Sasson (jaimes) 21-Mar-1992
+
+Environment:
+
+ Ulib, Regedit, Windows, User Mode
+
+--*/
+
+#include <stdio.h>
+
+#include "regedval.hxx"
+#include "regsys.hxx"
+#include "defmsg.h"
+
+
+//
+// Maximum number of bytes in a value of type REG_BINARY
+// that will be displayed in the data view
+//
+
+#define MAX_BYTES_DISPLAYED 8
+
+
+//
+// Initialization of STATIC data members
+//
+
+BOOLEAN REGEDIT_FORMATTED_VALUE_ENTRY::_StringsInitialized = FALSE;
+PWSTRING REGEDIT_FORMATTED_VALUE_ENTRY::_RegNoneString = NULL;
+PWSTRING REGEDIT_FORMATTED_VALUE_ENTRY::_RegSzString = NULL;
+PWSTRING REGEDIT_FORMATTED_VALUE_ENTRY::_RegExpandSzString = NULL;
+PWSTRING REGEDIT_FORMATTED_VALUE_ENTRY::_RegBinaryString = NULL;
+PWSTRING REGEDIT_FORMATTED_VALUE_ENTRY::_RegDwordString = NULL;
+PWSTRING REGEDIT_FORMATTED_VALUE_ENTRY::_RegMultiSzString = NULL;
+PWSTRING REGEDIT_FORMATTED_VALUE_ENTRY::_RegResourceListString = NULL;
+PWSTRING REGEDIT_FORMATTED_VALUE_ENTRY::_RegFullResourceDescriptorString = NULL;
+PWSTRING REGEDIT_FORMATTED_VALUE_ENTRY::_RegIoRequirementsListString = NULL;
+PWSTRING REGEDIT_FORMATTED_VALUE_ENTRY::_RegTypeUnknownString = NULL;
+PWSTRING REGEDIT_FORMATTED_VALUE_ENTRY::_Separator = NULL;
+PWSTRING REGEDIT_FORMATTED_VALUE_ENTRY::_NoNameString = NULL;
+PWSTRING REGEDIT_FORMATTED_VALUE_ENTRY::_InvalidDataString = NULL;
+
+
+
+
+DEFINE_CONSTRUCTOR( REGEDIT_FORMATTED_VALUE_ENTRY, OBJECT );
+
+DEFINE_CAST_MEMBER_FUNCTION( REGEDIT_FORMATTED_VALUE_ENTRY );
+
+
+
+REGEDIT_FORMATTED_VALUE_ENTRY::~REGEDIT_FORMATTED_VALUE_ENTRY(
+
+)
+/*++
+
+Routine Description:
+
+ Destroy a REGEDIT_FORMATTED_VALUE_ENTRY object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+REGEDIT_FORMATTED_VALUE_ENTRY::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Worker method for object construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _ValueEntry = NULL;
+}
+
+
+VOID
+REGEDIT_FORMATTED_VALUE_ENTRY::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Worker method for object destruction or reinitialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DELETE( _ValueEntry );
+}
+
+
+BOOLEAN
+REGEDIT_FORMATTED_VALUE_ENTRY::Initialize(
+ IN PREGISTRY_VALUE_ENTRY ValueEntry
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize or re-initialize a REGEDIT_FORMATTED_VALUE_ENTRY object.
+
+ Note: This class is reponsible for deleting the value entry passed
+ as argument during the initialization.
+
+Arguments:
+
+ ValueEntry - Pointer to a REGISTRY_VALUE_ENTRY object that contains
+ the information of a particular value entry in the registry.
+
+
+Return Value:
+
+ BOOLEAN - Returns always TRUE if the initialization succeeds.
+
+
+--*/
+
+
+{
+ DebugPtrAssert( ValueEntry );
+
+ Destroy();
+
+ _ValueEntry = ValueEntry;
+
+ //
+ // Initialize the STATIC data members
+ //
+
+ //
+ // Check if the strings used to formatt the data were already initialized.
+ // If not, initialize them.
+ //
+ if( !_StringsInitialized ) {
+ _RegNoneString = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_NONE, "" );
+ _RegSzString = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_SZ, "" );
+ _RegExpandSzString = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_EXPAND_SZ, "" );
+ _RegBinaryString = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_BINARY, "" );
+ _RegDwordString = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_DWORD, "" );
+ _RegMultiSzString = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_MULTI_SZ, "" );
+ _RegResourceListString = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_RESOURCE_LIST, "" );
+ _RegFullResourceDescriptorString = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_FULL_RESOURCE_DESCRIPTOR, "" );
+ _RegIoRequirementsListString = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_RESOURCE_REQUIREMENTS_LIST, "" );
+ _RegTypeUnknownString = REGEDIT_BASE_SYSTEM::QueryString( MSG_VALUE_TYPE_REG_UNKNOWN, "" );
+ _Separator = REGEDIT_BASE_SYSTEM::QueryString( MSG_FORMATTED_VALUE_SEPARATOR, "" );
+ _NoNameString = REGEDIT_BASE_SYSTEM::QueryString( MSG_FORMATTED_VALUE_NO_NAME, "" );
+ _InvalidDataString = REGEDIT_BASE_SYSTEM::QueryString( MSG_FORMATTED_VALUE_INVALID_DATA, "" );
+
+ //
+ // Verify that all strings were initialized
+ //
+
+ if( !_RegNoneString ||
+ !_RegSzString ||
+ !_RegBinaryString ||
+ !_RegDwordString ||
+ !_RegMultiSzString ||
+ !_RegResourceListString ||
+ !_RegFullResourceDescriptorString ||
+ !_RegIoRequirementsListString ||
+ !_RegTypeUnknownString ||
+ !_Separator ||
+ !_NoNameString ||
+ !_InvalidDataString ) {
+
+ //
+ // At least one of them wasn't initialized
+ //
+
+ DELETE( _RegNoneString );
+ DELETE( _RegSzString );
+ DELETE( _RegBinaryString );
+ DELETE( _RegDwordString );
+ DELETE( _RegMultiSzString );
+ DELETE( _RegResourceListString );
+ DELETE( _RegFullResourceDescriptorString );
+ DELETE( _RegIoRequirementsListString );
+ DELETE( _RegTypeUnknownString );
+ DELETE( _Separator );
+ DELETE( _NoNameString );
+ DELETE( _InvalidDataString );
+ _StringsInitialized = FALSE;
+ DebugPrint( "Unable to initialize string" );
+ return( FALSE );
+ }
+ //
+ // The initialization succeeded
+ //
+ _StringsInitialized = TRUE;
+
+ }
+ return( FormatString() );
+}
+
+
+
+PWSTRING
+REGEDIT_FORMATTED_VALUE_ENTRY::FormatBinaryData(
+ IN PCBYTE Data,
+ IN ULONG DataSize
+ )
+
+/*++
+
+Routine Description:
+
+ Build a string that contains the first 8 bytes of the data stored
+ in this object.
+ If the bynary data contains more than 8 bytes, append ... at the
+ end of the string.
+
+
+
+Arguments:
+
+ Data - Pointer to the buffer that contains the binary data.
+
+
+ Size - Number of bytes in the buffer.
+
+
+Return Value:
+
+ PWSTRING - Returns the string with the formatted data, or NULL
+ if the operation fails.
+
+
+--*/
+
+{
+ ULONG Index;
+ ULONG Count;
+ PWSTRING String;
+ CHAR Buffer[ 3*MAX_BYTES_DISPLAYED - 1 + 3 + 1 ];
+// | | | |
+// | | | |------> for the terminating '\0'
+// | | |----------> for the '...' at the end of the string
+// | |--------------> the space after the last byte
+// |-------------------> each byte is represented by two
+// digits followed by a 'space'
+//
+
+ DebugAssert( DataSize != 0 );
+ DebugPtrAssert( Data );
+
+ String = ( PWSTRING )NEW( DSTRING );
+ if( String == NULL ) {
+ DebugPrint( "Unable to allocate memory" );
+ return( NULL );
+ }
+
+ Index = 0;
+ for( Count = 0; ( Count < DataSize ) && ( Count < 8 ); Count++ ) {
+ Index += sprintf( Buffer + Index,
+ "%02x ",
+ Data[ Count ] );
+ }
+ if( DataSize > MAX_BYTES_DISPLAYED ) {
+ sprintf( Buffer + Index - 1, "%s", "..." );
+ }
+ if( !String->Initialize( Buffer ) ) {
+ DebugPrint( "String->Initialize( Buffer ) failed" );
+ FREE( String );
+ return( NULL );
+ }
+ return( String );
+}
+
+
+
+
+BOOLEAN
+REGEDIT_FORMATTED_VALUE_ENTRY::FormatString(
+ )
+
+/*++
+
+Routine Description:
+
+ Build a formatted string.
+
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+
+--*/
+
+
+{
+ FSTRING Dots;
+ BOOLEAN DataTruncated;
+ PWSTR MultiSzBuffer;
+ ULONG MultiSzNumberOfWChars;
+ PWSTR MultiSzPointer;
+ DSTRING MultiSzString;
+ PCWSTRING Name;
+ PCBYTE Data;
+ ULONG StringSize;
+ PWSTRING BinaryString;
+ ULONG DataSize;
+ REG_TYPE DataType;
+ DSTRING TmpString;
+ WCHAR TmpValue[ 2 + 2*sizeof( DWORD ) + 1 ];
+// | | |
+// | | |-----> for the '\0'
+// | |------------------> 8 bytes to represent
+// | a DWORD
+// |---------------------------> for the "0x"
+//
+//
+
+ Name = _ValueEntry->GetName();
+ DebugPtrAssert( Name );
+ DataType = _ValueEntry->GetType();
+ DataSize = _ValueEntry->GetData( &Data );
+
+ //
+ // Verify that the Data is not NULL when the DataSize is not zero
+ //
+ DebugAssert( ( DataSize == 0 ) || ( Data != NULL ) );
+
+ if( Name->QueryChCount() != 0 ) {
+ if( !_FormattedString.Initialize( Name ) ) {
+ DebugPrint( "_FormattedString.Initialize( Name )" );
+ return( FALSE );
+ }
+ } else {
+ if( !_FormattedString.Initialize( _NoNameString ) ) {
+ DebugPrint( "_FormattedString.Initialize( Name )" );
+ return( FALSE );
+ }
+ }
+ _FormattedString.Strcat( _Separator );
+
+
+ switch( DataType ) {
+
+ case TYPE_REG_NONE:
+
+ _FormattedString.Strcat( _RegNoneString );
+ break;
+
+ case TYPE_REG_SZ:
+ case TYPE_REG_EXPAND_SZ:
+
+ if( DataType == TYPE_REG_SZ ) {
+ _FormattedString.Strcat( _RegSzString );
+ } else {
+ _FormattedString.Strcat( _RegExpandSzString );
+ }
+ _FormattedString.Strcat( _Separator );
+ if( DataSize != 0 ) {
+ if( DataSize >= sizeof( WCHAR ) ) {
+ StringSize = DataSize/sizeof( WCHAR );
+ DataTruncated = FALSE;
+ if( StringSize > 512 ) {
+ StringSize = 512;
+ DataTruncated = TRUE;
+ }
+// if( *( ( PWCHAR )( Data + DataSize - sizeof( WCHAR ) ) ) == ( WCHAR )'\0' ) {
+ if( *( ( PWCHAR )( ( PWCHAR )Data + StringSize - 1 ) ) == ( WCHAR )'\0' ) {
+ //
+ // If the string is NUL-terminated, ignore the NUL
+ //
+ StringSize--;
+ }
+ } else {
+ StringSize = DataSize/sizeof( WCHAR );
+ }
+ if( !TmpString.Initialize( ( PWSTR )Data, StringSize ) ) {
+ DebugPrint( "TmpString.Initialize() failed" );
+ return( FALSE );
+ }
+ _FormattedString.Strcat( &TmpString );
+ if( DataTruncated ) {
+ Dots.Initialize( ( LPWSTR )L"..." );
+ _FormattedString.Strcat( &Dots );
+ }
+ }
+ break;
+
+ case TYPE_REG_BINARY:
+
+ _FormattedString.Strcat( _RegBinaryString );
+ _FormattedString.Strcat( _Separator );
+ if( DataSize != 0 ) {
+ if( DataSize != 0 ) {
+ BinaryString = FormatBinaryData( Data, DataSize );
+ if( BinaryString != NULL ) {
+ _FormattedString.Strcat( BinaryString );
+ DELETE( BinaryString );
+ }
+ }
+ }
+ break;
+
+ case TYPE_REG_DWORD:
+
+ _FormattedString.Strcat( _RegDwordString );
+ _FormattedString.Strcat( _Separator );
+ if( DataSize == sizeof( DWORD ) ) {
+ swprintf( TmpValue, ( LPWSTR )L"%#x", *( ( LPDWORD )Data ) );
+ if( !TmpString.Initialize( TmpValue ) ) {
+ DebugPrint( "TmpString.Initialize() failed" );
+ return( FALSE );
+ }
+ _FormattedString.Strcat( &TmpString );
+ } else {
+ _FormattedString.Strcat( _InvalidDataString );
+ }
+ break;
+
+ case TYPE_REG_MULTI_SZ:
+
+ _FormattedString.Strcat( _RegMultiSzString );
+ _FormattedString.Strcat( _Separator );
+ if( DataSize != 0 ) {
+ if( DataSize > 512 ) {
+ DataSize = 512;
+ DataTruncated = TRUE;
+ }
+ MultiSzBuffer = ( PWSTR )MALLOC( ( size_t )DataSize );
+ if( MultiSzBuffer == NULL ) {
+ DebugPrint( "Unable to allocate memory" );
+ return( FALSE );
+ }
+ MultiSzNumberOfWChars = DataSize / sizeof( WCHAR );
+ MultiSzNumberOfWChars--;
+ memcpy( MultiSzBuffer, Data, ( size_t ) DataSize );
+ MultiSzPointer = MultiSzBuffer;
+ while( MultiSzNumberOfWChars != 0 ) {
+ if( *MultiSzPointer == ( WCHAR )'\0' ) {
+ *MultiSzPointer = ( WCHAR )' ';
+ }
+ MultiSzPointer++;
+ MultiSzNumberOfWChars--;
+ }
+ if( !MultiSzString.Initialize( MultiSzBuffer, ( DataSize / sizeof( WCHAR ) ) - 1 ) ) {
+ DebugPrint( "MultiSzString.Initialize() failed" );
+ FREE( MultiSzBuffer );
+ return( FALSE );
+ }
+ FREE( MultiSzBuffer );
+ _FormattedString.Strcat( &MultiSzString );
+ if( DataTruncated ) {
+ Dots.Initialize( ( LPWSTR )L"..." );
+ _FormattedString.Strcat( &Dots );
+ }
+ }
+ break;
+
+ case TYPE_REG_RESOURCE_LIST:
+
+ _FormattedString.Strcat( _RegResourceListString );
+ _FormattedString.Strcat( _Separator );
+ if( DataSize != 0 ) {
+ if( DataSize != 0 ) {
+ Dots.Initialize( ( LPWSTR )L"..." );
+ _FormattedString.Strcat( &Dots );
+ }
+ }
+ break;
+
+ case TYPE_REG_FULL_RESOURCE_DESCRIPTOR:
+
+ _FormattedString.Strcat( _RegFullResourceDescriptorString );
+ _FormattedString.Strcat( _Separator );
+ if( DataSize != 0 ) {
+ if( DataSize != 0 ) {
+ Dots.Initialize( ( LPWSTR )L"..." );
+ _FormattedString.Strcat( &Dots );
+ }
+ }
+ break;
+
+ case TYPE_REG_RESOURCE_REQUIREMENTS_LIST:
+
+ _FormattedString.Strcat( _RegIoRequirementsListString );
+ _FormattedString.Strcat( _Separator );
+ if( DataSize != 0 ) {
+ if( DataSize != 0 ) {
+ Dots.Initialize( ( LPWSTR )L"..." );
+ _FormattedString.Strcat( &Dots );
+ }
+ }
+ break;
+
+ default:
+
+ _FormattedString.Strcat( _RegTypeUnknownString );
+ _FormattedString.Strcat( _Separator );
+ if( DataSize != 0 ) {
+ if( DataSize != 0 ) {
+ BinaryString = FormatBinaryData( Data, DataSize );
+ if( BinaryString != NULL ) {
+ _FormattedString.Strcat( BinaryString );
+ DELETE( BinaryString );
+ }
+ }
+ }
+ break;
+ }
+ return( TRUE );
+}
+
+
+
+
+#if DBG
+
+VOID
+REGEDIT_FORMATTED_VALUE_ENTRY::DbgPrintFormattedValueEntry(
+ )
+
+/*++
+
+Routine Description:
+
+ Display the contents of a formatted value entry object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+
+{
+
+ PSTR Pointer;
+
+ DebugPrintf( "======== Dumping a REGEDIT_FORMATTED_VALUE_ENTRY object ==== \n\n" );
+ _ValueEntry->DbgPrintValueEntry();
+ Pointer = _FormattedString.QuerySTR();
+ DebugPtrAssert( Pointer );
+ DebugPrintf( " _FormattedString = %s \n", Pointer );
+ FREE( Pointer );
+
+}
+
+#endif // DBG
+
+
+
+LONG
+REGEDIT_FORMATTED_VALUE_ENTRY::Compare (
+ IN PCOBJECT ValueEntry
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Compare two value entries based on their names.
+
+Arguments:
+
+ ValueEntry - Supplies the node to compare with.
+
+Return Value:
+
+ LONG < 0 - supplied object has a higher value name
+ == 0 - supplied object has same key name
+ > 0 - supplied object has a lower key name
+
+
+--*/
+
+{
+ PCWSTRING Name1;
+ PCWSTRING Name2;
+
+ DebugPtrAssert( ValueEntry );
+
+ Name1 = GetName();
+ Name2 = ( ( PCREGEDIT_FORMATTED_VALUE_ENTRY )ValueEntry )->GetName();
+
+ return( Name1->Stricmp( Name2 ) );
+}
diff --git a/private/utils/regedit/src/regfdesc.cxx b/private/utils/regedit/src/regfdesc.cxx
new file mode 100644
index 000000000..df10efafe
--- /dev/null
+++ b/private/utils/regedit/src/regfdesc.cxx
@@ -0,0 +1,399 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ regfdesc.cxx
+
+Abstract:
+
+ This module contains the definitions of the member functions
+ of FULL_DESCRIPTOR class.
+
+Author:
+
+ Jaime Sasson (jaimes) 02-Dec-1993
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include "regfdesc.hxx"
+#include "regdesc.hxx"
+#include "iterator.hxx"
+
+
+DEFINE_CONSTRUCTOR ( FULL_DESCRIPTOR, OBJECT );
+
+
+FULL_DESCRIPTOR::~FULL_DESCRIPTOR (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy a FULL_DESCRIPTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ Destroy();
+}
+
+
+VOID
+FULL_DESCRIPTOR::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Construct a FULL_DESCRIPTOR object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _InterfaceType = Internal;
+ _BusNumber = 0;
+ _Version = 0;
+ _Revision = 0;
+ _ResourceDescriptors = NULL;
+}
+
+
+VOID
+FULL_DESCRIPTOR::Destroy (
+ )
+
+/*++
+
+Routine Description:
+
+ Worker method for object destruction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _InterfaceType = Internal;
+ _BusNumber = 0;
+ _Version = 0;
+ _Revision = 0;
+ if( _ResourceDescriptors != NULL ) {
+ _ResourceDescriptors->DeleteAllMembers();
+ DELETE( _ResourceDescriptors );
+ }
+ _ResourceDescriptors = NULL;
+}
+
+
+
+BOOLEAN
+FULL_DESCRIPTOR::Initialize(
+ IN PCBYTE Data,
+ IN ULONG Size,
+ OUT PULONG DescriptorSize
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize an object of type FULL_DESCRIPTOR.
+
+Arguments:
+
+ Data - Pointer to a buffer that contains a CM_FULL_RESOURCE_DESCRIPTOR.
+
+ Size - Buffer size.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the initialization succeeds.
+
+--*/
+
+{
+ PCM_FULL_RESOURCE_DESCRIPTOR FullResource;
+ ULONG Count;
+ ULONG i;
+ ULONG j;
+
+ PARRAY TmpList;
+ PPORT_DESCRIPTOR PortDescriptor;
+ PINTERRUPT_DESCRIPTOR InterruptDescriptor;
+ PMEMORY_DESCRIPTOR MemoryDescriptor;
+ PDMA_DESCRIPTOR DmaDescriptor;
+ PDEVICE_SPECIFIC_DESCRIPTOR DeviceSpecificDescriptor;
+ ULONG DeviceSpecificDataSize;
+
+ if( Data == NULL ) {
+ return( FALSE );
+ }
+
+ Count = 1;
+ FullResource = ( PCM_FULL_RESOURCE_DESCRIPTOR )Data;
+
+ TmpList = ( PARRAY )NEW( ARRAY );
+ DebugPtrAssert( TmpList );
+ if( ( TmpList == NULL ) ||
+ ( !TmpList->Initialize() ) ) {
+ DebugPrintf("REGEDT32: Out of memory" );
+ DELETE( TmpList );
+ return( FALSE );
+ }
+
+ _InterfaceType = FullResource->InterfaceType;
+ _BusNumber = FullResource->BusNumber;
+ _Version = FullResource->PartialResourceList.Version;
+ _Revision = FullResource->PartialResourceList.Revision;
+
+ //
+ // For each CM_FULL_RESOURCE DESCRIPTOR in the current value...
+ //
+
+ for( i = 0; i < Count; i++ ) {
+
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResourceDescriptor;
+
+ //
+ // For each CM_PARTIAL_RESOURCE_DESCRIPTOR in the list...
+ //
+
+ DeviceSpecificDataSize = 0;
+ for( j = 0; j < FullResource->PartialResourceList.Count; j++ ) {
+
+ //
+ // Get a pointer to the current CM_PARTIAL_RESOURCE_DESCRIPTOR
+ // in the current CM_FULLRESOURCE_DESCRIPTOR in the list.
+ //
+
+ PartialResourceDescriptor = &( FullResource[ i ].PartialResourceList.PartialDescriptors[ j ]);
+ //
+ // Ignore invalid data
+ //
+ if( ( ULONG )PartialResourceDescriptor >
+ ( ULONG )( Data + Size - sizeof( CM_PARTIAL_RESOURCE_DESCRIPTOR ) ) ) {
+ DebugPrintf( "REGEDT32: Invalid CM_PARTIAL_RESOURCE_DESCRIPTOR, j = %d \n", j );
+ if( DescriptorSize != NULL ) {
+ *DescriptorSize = Size;
+ }
+ _ResourceDescriptors = TmpList;
+ return( TRUE );
+ }
+
+ switch( PartialResourceDescriptor->Type ) {
+
+ case CmResourceTypePort:
+
+ PortDescriptor = ( PPORT_DESCRIPTOR )NEW( PORT_DESCRIPTOR );
+ if( ( PortDescriptor == NULL ) ||
+ ( !PortDescriptor->Initialize( &PartialResourceDescriptor->u.Port.Start,
+ PartialResourceDescriptor->u.Port.Length,
+ PartialResourceDescriptor->ShareDisposition,
+ PartialResourceDescriptor->Flags ) )
+ ) {
+ DebugPrintf( "REGEDT32: Unable to create PORT_DESCRIPTOR" );
+ DELETE( PortDescriptor );
+ TmpList->DeleteAllMembers();
+ DELETE( TmpList );
+ return( FALSE );
+ }
+ TmpList->Put( PortDescriptor );
+ break;
+
+ case CmResourceTypeInterrupt:
+
+ InterruptDescriptor = ( PINTERRUPT_DESCRIPTOR )NEW( INTERRUPT_DESCRIPTOR );
+ if( ( InterruptDescriptor == NULL ) ||
+ ( !InterruptDescriptor->Initialize( PartialResourceDescriptor->u.Interrupt.Affinity,
+ PartialResourceDescriptor->u.Interrupt.Level,
+ PartialResourceDescriptor->u.Interrupt.Vector,
+ PartialResourceDescriptor->ShareDisposition,
+ PartialResourceDescriptor->Flags ) )
+ ) {
+ DebugPrintf( "REGEDT32: Unable to create INTERRUPT_DESCRIPTOR" );
+ DELETE( InterruptDescriptor );
+ TmpList->DeleteAllMembers();
+ DELETE( TmpList );
+ return( FALSE );
+ }
+ TmpList->Put( InterruptDescriptor );
+ break;
+
+ case CmResourceTypeMemory:
+
+ MemoryDescriptor = ( PMEMORY_DESCRIPTOR )NEW( MEMORY_DESCRIPTOR );
+ if( ( MemoryDescriptor == NULL ) ||
+ ( !MemoryDescriptor->Initialize( &PartialResourceDescriptor->u.Memory.Start,
+ PartialResourceDescriptor->u.Memory.Length,
+ PartialResourceDescriptor->ShareDisposition,
+ PartialResourceDescriptor->Flags ) )
+ ) {
+ DebugPrintf( "REGEDT32: Unable to create MEMORY_DESCRIPTOR" );
+ DELETE( MemoryDescriptor );
+ TmpList->DeleteAllMembers();
+ DELETE( TmpList );
+ return( FALSE );
+ }
+ TmpList->Put( MemoryDescriptor );
+ break;
+
+ case CmResourceTypeDma:
+
+ DmaDescriptor = ( PDMA_DESCRIPTOR )NEW( DMA_DESCRIPTOR );
+ if( ( DmaDescriptor == NULL ) ||
+ ( !DmaDescriptor->Initialize( PartialResourceDescriptor->u.Dma.Channel,
+ PartialResourceDescriptor->u.Dma.Port,
+ PartialResourceDescriptor->u.Dma.Reserved1,
+ PartialResourceDescriptor->ShareDisposition,
+ PartialResourceDescriptor->Flags ) )
+ ) {
+ DebugPrintf( "REGEDT32: Unable to create DMA_DESCRIPTOR" );
+ DELETE( DmaDescriptor );
+ TmpList->DeleteAllMembers();
+ DELETE( TmpList );
+ return( FALSE );
+ }
+ TmpList->Put( DmaDescriptor );
+ break;
+
+ case CmResourceTypeDeviceSpecific:
+
+ DeviceSpecificDataSize = PartialResourceDescriptor->u.DeviceSpecificData.DataSize;
+ DeviceSpecificDescriptor =
+ ( PDEVICE_SPECIFIC_DESCRIPTOR )NEW( DEVICE_SPECIFIC_DESCRIPTOR );
+ if( ( DeviceSpecificDescriptor == NULL ) ||
+ ( !DeviceSpecificDescriptor->Initialize(
+ PartialResourceDescriptor->u.DeviceSpecificData.Reserved1,
+ PartialResourceDescriptor->u.DeviceSpecificData.Reserved2,
+ PartialResourceDescriptor->u.DeviceSpecificData.DataSize,
+ ( PBYTE )&PartialResourceDescriptor->u.DeviceSpecificData +
+ 3*sizeof( ULONG ),
+ PartialResourceDescriptor->ShareDisposition,
+ PartialResourceDescriptor->Flags ) )
+ ) {
+ DebugPrintf( "REGEDT32: Unable to create DEVICE_SPECIFIC_DESCRIPTOR" );
+ DELETE( DeviceSpecificDescriptor );
+ TmpList->DeleteAllMembers();
+ DELETE( TmpList );
+ return( FALSE );
+ }
+ TmpList->Put( DeviceSpecificDescriptor );
+ break;
+
+ default:
+
+ DebugPrintf( "REGEDT32: Unknown PartialResourceDescriptor->Type == %#x \n",
+ PartialResourceDescriptor->Type );
+ continue;
+ }
+ }
+
+ _ResourceDescriptors = TmpList;
+ //
+ // Get the next CM_FULL_RESOURCE_DESCRIPTOR from the list.
+ //
+
+ FullResource = ( PCM_FULL_RESOURCE_DESCRIPTOR ) ( ( ULONG )FullResource +
+ sizeof( ULONG ) +
+ sizeof( ULONG ) +
+ sizeof( USHORT ) +
+ sizeof( USHORT ) +
+ sizeof( ULONG ) +
+ j*sizeof( CM_PARTIAL_RESOURCE_DESCRIPTOR ) +
+ DeviceSpecificDataSize );
+// FullResource = ( PCM_FULL_RESOURCE_DESCRIPTOR )( PartialResourceDescriptor + 1 );
+// FullResource = ( PCM_FULL_RESOURCE_DESCRIPTOR )( ( ULONG )FullResource +
+// DeviceSpecificDataSize );
+ }
+ if( DescriptorSize != NULL ) {
+ *DescriptorSize = ( ULONG )( ( ULONG )FullResource - ( ULONG )Data );
+#if DBG
+ if( *DescriptorSize > Size ) {
+ DebugPrintf( "REGEDT32: Invalid sizes, *DescriptorSize = %d, Size = %d \n", *DescriptorSize, Size );
+ }
+#endif
+ }
+ return( TRUE );
+}
+
+#if DBG
+VOID
+FULL_DESCRIPTOR::DbgDumpObject(
+ )
+
+/*++
+
+Routine Description:
+
+ Print a FULL_DESCRIPTOR object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PITERATOR Iterator;
+ PPARTIAL_DESCRIPTOR Descriptor;
+
+ DebugPrintf( "\tInterfaceType = %d \n", _InterfaceType );
+ DebugPrintf( "\tBusNumber = %#lx \n", _BusNumber );
+ DebugPrintf( "\tVersion = %#x \n", _Version );
+ DebugPrintf( "\tRevision = %#x \n", _Revision );
+ if( _ResourceDescriptors != NULL ) {
+ Iterator = _ResourceDescriptors->QueryIterator();
+ while( Descriptor = ( PPARTIAL_DESCRIPTOR ) Iterator->GetNext() ) {
+ if( Descriptor->IsDescriptorTypePort() ) {
+ ( ( PPORT_DESCRIPTOR )Descriptor )->DbgDumpObject();
+ } else if( Descriptor->IsDescriptorTypeInterrupt() ) {
+ ( ( PINTERRUPT_DESCRIPTOR )Descriptor )->DbgDumpObject();
+ } else if( Descriptor->IsDescriptorTypeMemory() ) {
+ ( ( PMEMORY_DESCRIPTOR )Descriptor )->DbgDumpObject();
+ } else if( Descriptor->IsDescriptorTypeDma() ) {
+ ( ( PDMA_DESCRIPTOR )Descriptor )->DbgDumpObject();
+ } else if( Descriptor->IsDescriptorTypeDeviceSpecific() ) {
+ ( ( PDEVICE_SPECIFIC_DESCRIPTOR )Descriptor )->DbgDumpObject();
+ } else {
+ DebugPrintf( "\tERROR: Unknown Descriptor \n\n" );
+ }
+ }
+ DELETE( Iterator );
+ }
+}
+#endif
diff --git a/private/utils/regedit/src/regiodls.cxx b/private/utils/regedit/src/regiodls.cxx
new file mode 100644
index 000000000..35ecff001
--- /dev/null
+++ b/private/utils/regedit/src/regiodls.cxx
@@ -0,0 +1,358 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ regiodls.cxx
+
+Abstract:
+
+ This module contains the definitions of the member functions
+ of IO_DESCRIPTOR_LIST class.
+
+Author:
+
+ Jaime Sasson (jaimes) 02-Dec-1993
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include "regiodls.hxx"
+#include "regiodsc.hxx"
+#include "iterator.hxx"
+
+
+DEFINE_CONSTRUCTOR ( IO_DESCRIPTOR_LIST, OBJECT );
+
+
+IO_DESCRIPTOR_LIST::~IO_DESCRIPTOR_LIST (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy an IO_DESCRIPTOR_LIST.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ Destroy();
+}
+
+
+VOID
+IO_DESCRIPTOR_LIST::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Construct an IO_DESCRIPTOR_LIST object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _Version = 0;
+ _Revision = 0;
+ _DescriptorsList = NULL;
+}
+
+
+VOID
+IO_DESCRIPTOR_LIST::Destroy (
+ )
+
+/*++
+
+Routine Description:
+
+ Worker method for object destruction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _Version = 0;
+ _Revision = 0;
+ if( _DescriptorsList != NULL ) {
+ _DescriptorsList->DeleteAllMembers();
+ DELETE( _DescriptorsList );
+ }
+ _DescriptorsList = NULL;
+}
+
+
+BOOLEAN
+IO_DESCRIPTOR_LIST::Initialize(
+ IN PCBYTE Data,
+ IN ULONG Size,
+ OUT PULONG DescriptorSize
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize an object of type IO_DESCRIPTOR_LIST.
+
+Arguments:
+
+ Data - Pointer to a buffer that contains an IO_RESOURCE_LIST.
+
+ Size - Buffer size.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the initialization succeeds.
+
+--*/
+
+{
+ PIO_RESOURCE_LIST IoResourceList;
+ ULONG Count;
+ ULONG i;
+ ULONG j;
+
+ PARRAY TmpList;
+ PIO_PORT_DESCRIPTOR PortDescriptor;
+ PIO_INTERRUPT_DESCRIPTOR InterruptDescriptor;
+ PIO_MEMORY_DESCRIPTOR MemoryDescriptor;
+ PIO_DMA_DESCRIPTOR DmaDescriptor;
+
+ if( Data == NULL ) {
+ return( FALSE );
+ }
+
+ Count = 1;
+ IoResourceList = ( PIO_RESOURCE_LIST )Data;
+
+ TmpList = ( PARRAY )NEW( ARRAY );
+ DebugPtrAssert( TmpList );
+ if( ( TmpList == NULL ) ||
+ ( !TmpList->Initialize() ) ) {
+ DebugPrintf("REGEDT32: Out of memory" );
+ DELETE( TmpList );
+ return( FALSE );
+ }
+
+ _Version = IoResourceList->Version;
+ _Revision = IoResourceList->Revision;
+
+ //
+ // For each CM_FULL_RESOURCE DESCRIPTOR in the current value...
+ //
+
+ for( i = 0; i < Count; i++ ) {
+
+ PIO_RESOURCE_DESCRIPTOR IoResourceDescriptor;
+
+ //
+ // For each IO_RESOURCE_DESCRIPTOR in the list...
+ //
+
+ for( j = 0; j < IoResourceList->Count; j++ ) {
+
+ //
+ // Get a pointer to the current IO_RESOURCE_DESCRIPTOR
+ // in the current IO_RESOURCE_LIST.
+ //
+
+ IoResourceDescriptor = &( IoResourceList->Descriptors[ j ]);
+ //
+ // Ignore invalid data
+ //
+ if( ( ULONG )IoResourceDescriptor >
+ ( ULONG )( Data + Size - sizeof( IO_RESOURCE_DESCRIPTOR ) ) ) {
+ DebugPrintf( "REGEDT32: Invalid IO_RESOURCE_DESCRIPTOR, j = %d \n", j );
+ if( DescriptorSize != NULL ) {
+ *DescriptorSize = Size;
+ }
+ _DescriptorsList = TmpList;
+ return( TRUE );
+ }
+
+ switch( IoResourceDescriptor->Type ) {
+
+ case CmResourceTypePort:
+
+ PortDescriptor = ( PIO_PORT_DESCRIPTOR )NEW( IO_PORT_DESCRIPTOR );
+ if( ( PortDescriptor == NULL ) ||
+ ( !PortDescriptor->Initialize( IoResourceDescriptor->u.Port.Length,
+ IoResourceDescriptor->u.Port.Alignment,
+ &IoResourceDescriptor->u.Port.MinimumAddress,
+ &IoResourceDescriptor->u.Port.MaximumAddress,
+ IoResourceDescriptor->Option,
+ IoResourceDescriptor->ShareDisposition,
+ IoResourceDescriptor->Flags ) )
+ ) {
+ DebugPrintf( "REGEDT32: Unable to create IO_PORT_DESCRIPTOR" );
+ DELETE( PortDescriptor );
+ TmpList->DeleteAllMembers();
+ DELETE( TmpList );
+ return( FALSE );
+ }
+ TmpList->Put( PortDescriptor );
+ break;
+
+ case CmResourceTypeInterrupt:
+
+ InterruptDescriptor = ( PIO_INTERRUPT_DESCRIPTOR )NEW( IO_INTERRUPT_DESCRIPTOR );
+ if( ( InterruptDescriptor == NULL ) ||
+ ( !InterruptDescriptor->Initialize( IoResourceDescriptor->u.Interrupt.MinimumVector,
+ IoResourceDescriptor->u.Interrupt.MaximumVector,
+ IoResourceDescriptor->Option,
+ IoResourceDescriptor->ShareDisposition,
+ IoResourceDescriptor->Flags ) )
+ ) {
+ DebugPrintf( "REGEDT32: Unable to create IO_INTERRUPT_DESCRIPTOR" );
+ DELETE( InterruptDescriptor );
+ TmpList->DeleteAllMembers();
+ DELETE( TmpList );
+ return( FALSE );
+ }
+ TmpList->Put( InterruptDescriptor );
+ break;
+
+ case CmResourceTypeMemory:
+
+ MemoryDescriptor = ( PIO_MEMORY_DESCRIPTOR )NEW( IO_MEMORY_DESCRIPTOR );
+ if( ( MemoryDescriptor == NULL ) ||
+ ( !MemoryDescriptor->Initialize( IoResourceDescriptor->u.Memory.Length,
+ IoResourceDescriptor->u.Memory.Alignment,
+ &IoResourceDescriptor->u.Memory.MinimumAddress,
+ &IoResourceDescriptor->u.Memory.MaximumAddress,
+ IoResourceDescriptor->Option,
+ IoResourceDescriptor->ShareDisposition,
+ IoResourceDescriptor->Flags ) )
+ ) {
+ DebugPrintf( "REGEDT32: Unable to create IO_MEMORY_DESCRIPTOR" );
+ DELETE( MemoryDescriptor );
+ TmpList->DeleteAllMembers();
+ DELETE( TmpList );
+ return( FALSE );
+ }
+ TmpList->Put( MemoryDescriptor );
+ break;
+
+ case CmResourceTypeDma:
+
+ DmaDescriptor = ( PIO_DMA_DESCRIPTOR )NEW( IO_DMA_DESCRIPTOR );
+ if( ( DmaDescriptor == NULL ) ||
+ ( !DmaDescriptor->Initialize( IoResourceDescriptor->u.Dma.MinimumChannel,
+ IoResourceDescriptor->u.Dma.MaximumChannel,
+ IoResourceDescriptor->Option,
+ IoResourceDescriptor->ShareDisposition,
+ IoResourceDescriptor->Flags ) )
+ ) {
+ DebugPrintf( "REGEDT32: Unable to create IO_DMA_DESCRIPTOR" );
+ DELETE( DmaDescriptor );
+ TmpList->DeleteAllMembers();
+ DELETE( TmpList );
+ return( FALSE );
+ }
+ TmpList->Put( DmaDescriptor );
+ break;
+
+ default:
+
+ DebugPrintf( "REGEDT32: Unknown IoResourceDescriptor->Type == %#x \n",
+ IoResourceDescriptor->Type );
+ continue;
+ }
+ }
+
+ _DescriptorsList = TmpList;
+
+ //
+ // Get the next IO_RESOURCE_LIST from the list.
+ //
+
+ IoResourceList = ( PIO_RESOURCE_LIST )( IoResourceDescriptor + 1 );
+ }
+ if( DescriptorSize != NULL ) {
+ *DescriptorSize = ( ULONG )( ( ULONG )IoResourceList - ( ULONG )Data );
+#if DBG
+ if( *DescriptorSize > Size ) {
+ DebugPrintf( "REGEDT32: Invalid sizes, *DescriptorSize = %d, Size = %d \n", *DescriptorSize, Size );
+ }
+#endif
+ }
+ return( TRUE );
+}
+
+#if DBG
+VOID
+IO_DESCRIPTOR_LIST::DbgDumpObject(
+ )
+
+/*++
+
+Routine Description:
+
+ Print an IO_DESCRIPTOR_LIST object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PITERATOR Iterator;
+ PIO_DESCRIPTOR Descriptor;
+
+ DebugPrintf( "\tVersion = %#x \n", _Version );
+ DebugPrintf( "\tRevision = %#x \n", _Revision );
+ if( _DescriptorsList != NULL ) {
+ Iterator = _DescriptorsList->QueryIterator();
+ while( Descriptor = ( PIO_DESCRIPTOR ) Iterator->GetNext() ) {
+ if( Descriptor->IsDescriptorTypePort() ) {
+ ( ( PIO_PORT_DESCRIPTOR )Descriptor )->DbgDumpObject();
+ } else if( Descriptor->IsDescriptorTypeInterrupt() ) {
+ ( ( PIO_INTERRUPT_DESCRIPTOR )Descriptor )->DbgDumpObject();
+ } else if( Descriptor->IsDescriptorTypeMemory() ) {
+ ( ( PIO_MEMORY_DESCRIPTOR )Descriptor )->DbgDumpObject();
+ } else if( Descriptor->IsDescriptorTypeDma() ) {
+ ( ( PIO_DMA_DESCRIPTOR )Descriptor )->DbgDumpObject();
+ } else {
+ DebugPrintf( "\tERROR: Unknown Descriptor \n\n" );
+ }
+ }
+ DELETE( Iterator );
+ }
+}
+#endif
diff --git a/private/utils/regedit/src/regiodsc.cxx b/private/utils/regedit/src/regiodsc.cxx
new file mode 100644
index 000000000..43902d631
--- /dev/null
+++ b/private/utils/regedit/src/regiodsc.cxx
@@ -0,0 +1,471 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ regiodsc.cxx
+
+Abstract:
+
+ This module contains the definitions of the member functions
+ of IO_DESCRIPTOR class.
+
+Author:
+
+ Jaime Sasson (jaimes) 02-Dec-1993
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include "ulib.hxx"
+#include "regiodsc.hxx"
+
+#include <ctype.h>
+
+DEFINE_CONSTRUCTOR ( IO_DESCRIPTOR, OBJECT );
+
+
+IO_DESCRIPTOR::~IO_DESCRIPTOR (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy a IO_DESCRIPTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+}
+
+VOID
+IO_DESCRIPTOR::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Construct a IO_DESCRIPTOR object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _Option = 0;
+ _Type = 0;
+ _ShareDisposition = 0;
+ _Flags = 0;
+}
+
+#if DBG
+VOID
+IO_DESCRIPTOR::DbgDumpObject(
+ )
+
+/*++
+
+Routine Description:
+
+ Print a IO_DESCRIPTOR object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DebugPrintf( "\t\tOption = %#x \n", _Option );
+ DebugPrintf( "\t\tType = %#x \n", _Type );
+ DebugPrintf( "\t\tShareDisposition = %#x \n", _ShareDisposition );
+ DebugPrintf( "\t\tFlags = %x \n", _Flags );
+}
+#endif
+
+// #include "ulib.hxx"
+// #include "regdesc.hxx"
+
+// extern "C" {
+// #include <ctype.h>
+// }
+
+DEFINE_CONSTRUCTOR ( IO_PORT_DESCRIPTOR, IO_DESCRIPTOR );
+
+
+IO_PORT_DESCRIPTOR::~IO_PORT_DESCRIPTOR (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy an IO_PORT_DESCRIPTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+}
+
+VOID
+IO_PORT_DESCRIPTOR::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Construct a IO_PORT_DESCRIPTOR object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _Length = 0;
+ _Alignment = 0;
+ _MinimumAddress.LowPart = 0;
+ _MinimumAddress.HighPart = 0;
+ _MaximumAddress.LowPart = 0;
+ _MaximumAddress.HighPart = 0;
+}
+
+#if DBG
+VOID
+IO_PORT_DESCRIPTOR::DbgDumpObject(
+ )
+
+/*++
+
+Routine Description:
+
+ Print a IO_PORT_DESCRIPTOR object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IO_DESCRIPTOR::DbgDumpObject();
+ DebugPrintf( "\t\tLength = %#lx \n", _Length );
+ DebugPrintf( "\t\tAlignment = %#lx \n", _Alignment );
+ DebugPrintf( "\t\tMinimumAddress.HighPart = %#lx \n", _MinimumAddress.HighPart );
+ DebugPrintf( "\t\tMinimumAddress.LowPart = %#lx \n", _MinimumAddress.LowPart );
+ DebugPrintf( "\t\tMaximumAddress.HighPart = %#lx \n", _MaximumAddress.HighPart );
+ DebugPrintf( "\t\tMaximumAddress.LowPart = %#lx \n", _MaximumAddress.LowPart );
+ DebugPrintf( "\n" );
+}
+#endif
+
+// #include "ulib.hxx"
+// #include "regdesc.hxx"
+
+// extern "C" {
+// #include <ctype.h>
+// }
+
+DEFINE_CONSTRUCTOR ( IO_INTERRUPT_DESCRIPTOR, IO_DESCRIPTOR );
+
+
+IO_INTERRUPT_DESCRIPTOR::~IO_INTERRUPT_DESCRIPTOR (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy an IO_INTERRUPT_DESCRIPTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+}
+
+VOID
+IO_INTERRUPT_DESCRIPTOR::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Construct an IO_INTERRUPT_DESCRIPTOR object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _MinimumVector = 0;
+ _MaximumVector = 0;
+}
+
+#if DBG
+VOID
+IO_INTERRUPT_DESCRIPTOR::DbgDumpObject(
+ )
+
+/*++
+
+Routine Description:
+
+ Print an IO_INTERRUPT_DESCRIPTOR object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IO_DESCRIPTOR::DbgDumpObject();
+ DebugPrintf( "\t\tMinimumVector = %#lx \n", _MinimumVector );
+ DebugPrintf( "\t\tMaximumVector = %#lx \n", _MaximumVector );
+ DebugPrintf( "\n" );
+}
+#endif
+
+
+
+// #include "ulib.hxx"
+// #include "regdesc.hxx"
+
+// extern "C" {
+// #include <ctype.h>
+// }
+
+DEFINE_CONSTRUCTOR ( IO_MEMORY_DESCRIPTOR, IO_DESCRIPTOR );
+
+
+IO_MEMORY_DESCRIPTOR::~IO_MEMORY_DESCRIPTOR (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy an IO_MEMORY_DESCRIPTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+}
+
+VOID
+IO_MEMORY_DESCRIPTOR::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Construct an IO_MEMORY_DESCRIPTOR object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _Length = 0;
+ _Alignment = 0;
+ _MinimumAddress.LowPart = 0;
+ _MinimumAddress.HighPart = 0;
+ _MaximumAddress.LowPart = 0;
+ _MaximumAddress.HighPart = 0;
+}
+
+#if DBG
+VOID
+IO_MEMORY_DESCRIPTOR::DbgDumpObject(
+ )
+
+/*++
+
+Routine Description:
+
+ Print an IO_MEMORY_DESCRIPTOR object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IO_DESCRIPTOR::DbgDumpObject();
+ DebugPrintf( "\t\tLength = %#lx \n", _Length );
+ DebugPrintf( "\t\tAlignment = %#lx \n", _Alignment );
+ DebugPrintf( "\t\tMinimumAddress.HighPart = %#lx \n", _MinimumAddress.HighPart );
+ DebugPrintf( "\t\tMinimumAddress.LowPart = %#lx \n", _MinimumAddress.LowPart );
+ DebugPrintf( "\t\tMaximumAddress.HighPart = %#lx \n", _MaximumAddress.HighPart );
+ DebugPrintf( "\t\tMaximumAddress.LowPart = %#lx \n", _MaximumAddress.LowPart );
+ DebugPrintf( "\n" );
+}
+#endif
+
+// #include "ulib.hxx"
+// #include "regdesc.hxx"
+
+// extern "C" {
+// #include <ctype.h>
+// }
+
+DEFINE_CONSTRUCTOR ( IO_DMA_DESCRIPTOR, IO_DESCRIPTOR );
+
+
+IO_DMA_DESCRIPTOR::~IO_DMA_DESCRIPTOR (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy a IO_DMA_DESCRIPTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+}
+
+VOID
+IO_DMA_DESCRIPTOR::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Construct an IO_DMA_DESCRIPTOR object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _MinimumChannel = 0;
+ _MaximumChannel = 0;
+}
+
+#if DBG
+VOID
+IO_DMA_DESCRIPTOR::DbgDumpObject(
+ )
+
+/*++
+
+Routine Description:
+
+ Print a IO_DMA_DESCRIPTOR object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ IO_DESCRIPTOR::DbgDumpObject();
+ DebugPrintf( "\t\tMinimumChannel = %#lx \n", _MinimumChannel );
+ DebugPrintf( "\t\tMaximumChannel = %#lx \n", _MaximumChannel );
+ DebugPrintf( "\n" );
+}
+#endif
diff --git a/private/utils/regedit/src/regioreq.cxx b/private/utils/regedit/src/regioreq.cxx
new file mode 100644
index 000000000..b71240271
--- /dev/null
+++ b/private/utils/regedit/src/regioreq.cxx
@@ -0,0 +1,252 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ regresls.cxx
+
+Abstract:
+
+ This module contains the definitions of the member functions
+ of IO_REQUIREMENTS_LIST class.
+
+Author:
+
+ Jaime Sasson (jaimes) 02-Dec-1993
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include "regioreq.hxx"
+#include "iterator.hxx"
+#include "regiodsc.hxx"
+#include "regiodls.hxx"
+
+
+DEFINE_CONSTRUCTOR ( IO_REQUIREMENTS_LIST, OBJECT );
+
+
+IO_REQUIREMENTS_LIST::~IO_REQUIREMENTS_LIST (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy a IO_REQUIREMENTS_LIST.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ Destroy();
+}
+
+
+VOID
+IO_REQUIREMENTS_LIST::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Construct an IO_REQUIREMENTS_LIST object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _InterfaceType = Internal;
+ _BusNumber = 0;
+ _SlotNumber = 0;
+ _Reserved1 = 0;
+ _Reserved2 = 0;
+ _Reserved3 = 0;
+ _AlternativeLists = NULL;
+}
+
+
+VOID
+IO_REQUIREMENTS_LIST::Destroy (
+ )
+
+/*++
+
+Routine Description:
+
+ Worker method for object destruction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if( _AlternativeLists != NULL ) {
+ _AlternativeLists->DeleteAllMembers();
+ DELETE( _AlternativeLists );
+ }
+ _AlternativeLists = NULL;
+}
+
+
+
+BOOLEAN
+IO_REQUIREMENTS_LIST::Initialize(
+ IN PCBYTE Data,
+ IN ULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize an object of type IO_REQUIREMENTS_LIST.
+
+Arguments:
+
+ Data - Pointer to a buffer that contains a IO_RESOURCE_REQUIREMETS_LIST.
+
+ Size - Buffer size.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the initialization succeeds.
+
+--*/
+
+{
+ PIO_RESOURCE_LIST ResourceList;
+ ULONG Count;
+ ULONG i;
+ PARRAY TmpList;
+ ULONG BufferSize;
+ ULONG ResourceListSize;
+
+ if( Data == NULL ) {
+ return( FALSE );
+ }
+
+ Count = ( ( PIO_RESOURCE_REQUIREMENTS_LIST )Data )->AlternativeLists;
+ ResourceList = ( ( PIO_RESOURCE_REQUIREMENTS_LIST )Data )->List;
+
+ TmpList = ( PARRAY )NEW( ARRAY );
+ DebugPtrAssert( TmpList );
+ if( ( TmpList == NULL ) ||
+ ( !TmpList->Initialize() ) ) {
+ DebugPrintf("REGEDT32: Out of memory" );
+ DELETE( TmpList );
+ return( FALSE );
+ }
+
+ //
+ // For each IO_RESOURCE_LIST in the current value...
+ //
+
+ BufferSize = Size - // Data size
+ sizeof( ULONG ) - // ListSize
+ sizeof( INTERFACE_TYPE ) - // InterdaceType
+ sizeof( ULONG ) - // BusNumber
+ sizeof( ULONG ) - // SlotNumber
+ 3*sizeof( ULONG ) - // Reserved1, 2 and 3
+ sizeof( ULONG ); // AlternativeLists
+
+ for( i = 0; i < Count; i++ ) {
+
+ PIO_DESCRIPTOR_LIST IoDescriptorList;
+
+ IoDescriptorList = ( PIO_DESCRIPTOR_LIST )NEW( IO_DESCRIPTOR_LIST );
+ if( ( IoDescriptorList == NULL ) ||
+ !IoDescriptorList->Initialize( ( PCBYTE )ResourceList,
+ BufferSize,
+ &ResourceListSize )
+ ) {
+ DebugPrint( "REGEDT32: Unable to create or initialize IoDescriptorList \n" );
+ DELETE( IoDescriptorList );
+ TmpList->DeleteAllMembers();
+ DELETE( TmpList );
+ return( FALSE );
+ }
+ TmpList->Put( IoDescriptorList );
+#if DBG
+ if( BufferSize < ResourceListSize ) {
+ DebugPrintf( "REGEDT32: incorrect sizes, BufferSize = %d, ResourceListSize = %d \n",
+ BufferSize, ResourceListSize );
+ }
+#endif
+ ResourceList = ( PIO_RESOURCE_LIST )( ( ULONG )ResourceList + ResourceListSize );
+ BufferSize -= ResourceListSize;
+ }
+ _AlternativeLists = TmpList;
+ return( TRUE );
+}
+
+#if DBG
+VOID
+IO_REQUIREMENTS_LIST::DbgDumpObject(
+ )
+
+/*++
+
+Routine Description:
+
+ Print an IO_REQUIREMENTS_LIST object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PITERATOR Iterator;
+ PIO_DESCRIPTOR_LIST DescriptorList;
+
+ DebugPrintf( "*** Dumping IO_REQUIREMENTS_LIST \n\n" );
+ DebugPrintf( "InterfaceType = %d \n", _InterfaceType );
+ DebugPrintf( "BusNumber = %#lx \n", _BusNumber );
+ DebugPrintf( "SlotNumber = %#lx \n", _SlotNumber );
+ DebugPrintf( "Reserved1 = %#x \n", _Reserved1 );
+ DebugPrintf( "Reserved2 = %#x \n", _Reserved2 );
+ DebugPrintf( "Reserved3 = %#x \n", _Reserved3 );
+ if( _AlternativeLists != NULL ) {
+ Iterator = _AlternativeLists->QueryIterator();
+ while( DescriptorList = ( PIO_DESCRIPTOR_LIST ) Iterator->GetNext() ) {
+ DescriptorList->DbgDumpObject();
+ }
+ DELETE( Iterator );
+ } else {
+ DebugPrintf( "IO_REQUIREMENTS_LIST is empty \n\n" );
+ }
+
+}
+#endif
diff --git a/private/utils/regedit/src/regresls.cxx b/private/utils/regedit/src/regresls.cxx
new file mode 100644
index 000000000..79e3fa44c
--- /dev/null
+++ b/private/utils/regedit/src/regresls.cxx
@@ -0,0 +1,236 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ regresls.cxx
+
+Abstract:
+
+ This module contains the definitions of the member functions
+ of RESOURCE_LIST class.
+
+Author:
+
+ Jaime Sasson (jaimes) 02-Dec-1993
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include "regresls.hxx"
+#include "iterator.hxx"
+#include "regdesc.hxx"
+#include "regfdesc.hxx"
+
+
+DEFINE_CONSTRUCTOR ( RESOURCE_LIST, OBJECT );
+
+
+RESOURCE_LIST::~RESOURCE_LIST (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy a RESOURCE_LIST.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ Destroy();
+}
+
+
+VOID
+RESOURCE_LIST::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Construct a RESOURCE_LIST object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _FullResourceDescriptors = NULL;
+}
+
+
+VOID
+RESOURCE_LIST::Destroy (
+ )
+
+/*++
+
+Routine Description:
+
+ Worker method for object destruction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if( _FullResourceDescriptors != NULL ) {
+ _FullResourceDescriptors->DeleteAllMembers();
+ DELETE( _FullResourceDescriptors );
+ }
+ _FullResourceDescriptors = NULL;
+}
+
+
+
+BOOLEAN
+RESOURCE_LIST::Initialize(
+ IN PCBYTE Data,
+ IN ULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize an object of type RESOURCE_LIST.
+
+Arguments:
+
+ Data - Pointer to a buffer that contains a CM_RESOURCE_LIST.
+
+ Size - Buffer size.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the initialization succeeds.
+
+--*/
+
+{
+ PCM_FULL_RESOURCE_DESCRIPTOR FullResource;
+ ULONG Count;
+ ULONG i;
+ PARRAY TmpList;
+ ULONG BufferSize;
+ ULONG FullDescriptorSize;
+
+ if( Data == NULL ) {
+ return( FALSE );
+ }
+
+ Count = ( ( PCM_RESOURCE_LIST )Data )->Count;
+ FullResource = ( ( PCM_RESOURCE_LIST )Data )->List;
+
+ TmpList = ( PARRAY )NEW( ARRAY );
+ DebugPtrAssert( TmpList );
+ if( ( TmpList == NULL ) ||
+ ( !TmpList->Initialize() ) ) {
+ DebugPrintf("REGEDT32: Out of memory" );
+ DELETE( TmpList );
+ return( FALSE );
+ }
+
+ //
+ // For each CM_FULL_RESOURCE DESCRIPTOR in the current value...
+ //
+
+ BufferSize = Size - // Data size
+ sizeof( ULONG ); // Count
+
+ for( i = 0; i < Count; i++ ) {
+
+ PFULL_DESCRIPTOR FullResourceDescriptor;
+
+ FullResourceDescriptor = ( PFULL_DESCRIPTOR )NEW( FULL_DESCRIPTOR );
+ if( ( FullResourceDescriptor == NULL ) ||
+ !FullResourceDescriptor->Initialize( ( PCBYTE )FullResource,
+ BufferSize,
+ &FullDescriptorSize )
+ ) {
+ DebugPrint( "REGEDT32: Unable to create or initialize FullResourcedescriptor \n" );
+ DELETE( FullResourceDescriptor );
+ TmpList->DeleteAllMembers();
+ DELETE( TmpList );
+ return( FALSE );
+ }
+ TmpList->Put( FullResourceDescriptor );
+#if DBG
+ if( BufferSize < FullDescriptorSize ) {
+ DebugPrintf( "REGEDT32: incorrect sizes, BufferSize = %d, FullDescriptorSize = %d \n",
+ BufferSize, FullDescriptorSize );
+ }
+#endif
+ FullResource = ( PCM_FULL_RESOURCE_DESCRIPTOR )( ( ULONG )FullResource + FullDescriptorSize );
+ BufferSize -= FullDescriptorSize;
+ }
+ _FullResourceDescriptors = TmpList;
+ return( TRUE );
+}
+
+#if DBG
+VOID
+RESOURCE_LIST::DbgDumpObject(
+ )
+
+/*++
+
+Routine Description:
+
+ Print a RESOURCE_LIST object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PITERATOR Iterator;
+ PFULL_DESCRIPTOR Descriptor;
+
+ DebugPrintf( "*** Dumping RESOURCE_LIST \n\n" );
+ DebugPrintf( "_FullResourceDescriptors = %#lx \n", _FullResourceDescriptors );
+ if( _FullResourceDescriptors != NULL ) {
+ Iterator = _FullResourceDescriptors->QueryIterator();
+ while( Descriptor = ( PFULL_DESCRIPTOR ) Iterator->GetNext() ) {
+ Descriptor->DbgDumpObject();
+ }
+ DELETE( Iterator );
+ } else {
+ DebugPrintf( "RESOURCE_LIST is empty \n\n" );
+ }
+
+}
+#endif
diff --git a/private/utils/regedit/src/regsys.cxx b/private/utils/regedit/src/regsys.cxx
new file mode 100644
index 000000000..a6369f2b1
--- /dev/null
+++ b/private/utils/regedit/src/regsys.cxx
@@ -0,0 +1,156 @@
+#include "ulib.hxx"
+#include "winapp.hxx"
+#include "regsys.hxx"
+
+#include <stdio.h>
+
+// #define FORMAT_MESSAGE_FROM_HMODULE 0x00000800
+
+
+
+BOOLEAN
+REGEDIT_BASE_SYSTEM::QueryResourceString(
+ OUT PWSTRING ResourceString,
+ IN MSGID MsgId,
+ IN PCSTR Format ...
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the resource string identified by the resource
+ identifier 'MsgId'. In addition to the 'printf' format strings
+ supported, 'QueryResourceString' supports :
+
+ 1. '%W' - Expects a pointer to a WSTRING.
+
+Arguments:
+
+ ResourceString - Returns the resource string.
+ MsgId - Supplies the message id of the resource string.
+ Format - Supplies a 'printf' style format descriptor for the
+ arguments to the resource string.
+ ... - Supplies the arguments to the resource string.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ va_list ap;
+ BOOLEAN r;
+
+ va_start(ap, Format);
+ r = QueryResourceStringV(ResourceString, MsgId, Format, ap);
+ va_end(ap);
+
+ return r;
+}
+
+
+BOOLEAN
+REGEDIT_BASE_SYSTEM::QueryResourceStringV(
+ OUT PWSTRING ResourceString,
+ IN MSGID MsgId,
+ IN PCSTR Format,
+ IN va_list VarPointer
+ )
+/*++
+
+Routine Description:
+
+ This is a 'varargs' implementation of 'QueryResourceString'.
+
+Arguments:
+
+ ResourceString - Returns the resource string.
+ MsgId - Supplies the message id of the resource string.
+ Format - Supplies a 'printf' style format descriptor for the
+ arguments to the resource string.
+ VarPointer - Supplies a varargs pointer to the arguments of the
+ resource string.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ WCHAR display_buffer[2048];
+ WCHAR UnformattedMessage[1024];
+ DWORD Status;
+
+ if( LoadStringW((HINSTANCE)WINDOWS_APPLICATION::QueryInstance(),
+ MsgId,
+ UnformattedMessage,
+ 1024 ) == 0 ) {
+ Status = GetLastError();
+ DebugPrint( "LoadStringW() failed" );
+ DebugPrintf("LoadStringW() failed. Error = %d \n", Status );
+ return FALSE;
+ }
+
+ if( FormatMessageW(FORMAT_MESSAGE_FROM_STRING,
+ (LPVOID)UnformattedMessage,
+ 0,
+ 0L,
+ display_buffer,
+ sizeof( display_buffer ),
+ &VarPointer ) == 0 ) {
+ Status = GetLastError();
+ DebugPrint( "FormatMessageW() failed" );
+ DebugPrintf("FormatMessageW() failed. Error = %d \n", Status );
+ return FALSE;
+ }
+
+ return ResourceString->Initialize(display_buffer);
+}
+
+
+
+PWSTRING
+REGEDIT_BASE_SYSTEM::QueryString(
+ IN MSGID MsgId,
+ IN PCSTR Format ...
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the resource string identified by the resource
+ identifier 'MsgId'. In addition to the 'printf' format strings
+ supported, 'QueryResourceString' supports :
+
+ 1. '%W' - Expects a pointer to a WSTRING.
+
+Arguments:
+
+ MsgId - Supplies the message id of the resource string.
+ Format - Supplies a 'printf' style format descriptor for the
+ arguments to the resource string.
+ ... - Supplies the arguments to the resource string.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ va_list ap;
+ BOOLEAN r;
+ PWSTRING String;
+
+ va_start(ap, Format);
+ String = NEW( DSTRING );
+ r = QueryResourceStringV(String, MsgId, Format, ap);
+ va_end(ap);
+ if( !r ) {
+ DELETE( String );
+ return( NULL );
+ }
+ return String;
+}
diff --git a/private/utils/regedit/src/regwin.cxx b/private/utils/regedit/src/regwin.cxx
new file mode 100644
index 000000000..f4c27a6e7
--- /dev/null
+++ b/private/utils/regedit/src/regwin.cxx
@@ -0,0 +1,1392 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ Regwin.cxx
+
+Abstract:
+
+ This module contains the definition for the REGISTRY_WINDOW class.
+ REGISTRY_WINDOW is derived from the abstract WINDOW class and supplies
+ an implementation for a MDI client window.
+
+Author:
+
+ David J. Gilman (davegi) 02-Aug-1991
+
+Environment:
+
+ Ulib, Regedit, Windows, User Mode
+
+--*/
+
+#include "uapp.hxx"
+#include "regwin.hxx"
+#include "winapp.hxx"
+#include "treevw.hxx"
+#include "datavw.hxx"
+#include "regedir.hxx"
+#include "resource.h"
+
+//
+// Initialize REGISTRY_WINDOW's window class name and note that it
+// has not been registered.
+//
+
+LPWSTR REGISTRY_WINDOW::_WindowClassName = (LPWSTR)L"REGISTRY_WINDOW";
+BOOLEAN REGISTRY_WINDOW::_Registered = FALSE;
+
+// HANDLE REGISTRY_WINDOW::_AutoRefreshEvent = NULL;
+
+BOOLEAN REGISTRY_WINDOW::_ProcessRefreshMessage = FALSE;
+HCURSOR REGISTRY_WINDOW::_SplitCursor;
+
+extern INT dxFrame;
+extern INT dyBorder;
+
+
+DEFINE_CONSTRUCTOR( REGISTRY_WINDOW, WINDOW );
+
+DEFINE_CAST_MEMBER_FUNCTION( REGISTRY_WINDOW );
+
+
+BOOLEAN
+REGISTRY_WINDOW::Initialize (
+ IN HWND MDIHandle,
+ IN PCWSTRING Title,
+ IN PREGEDIT_INTERNAL_REGISTRY InternalRegistry,
+ IN PREGISTRY_WINDOW_SET RegistryWindowSet,
+ IN PWINDOW_POSITION WindowPosition
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize a REGISTRY_WINDOW object by registering its window class,
+ creating its window and inititializing its internal state.
+
+Arguments:
+
+ MDIHandle - Supplies a handle to the MDICLIENT window used to
+ create the registry (mdi client) window.
+ Title - Supplies the title of the window (i.e. the name of
+ its root node and backing store).
+ InternalRegistry - Supplies a pointer to this REGISTRY_WINDOW's
+ REGEDIT_INTERNAL_REGISTRY object.
+ RegistryWindowSet - Pointer to a structure that contains the signature
+ of this registry window.
+ This signature will be used only by MainWinProc
+ in regedit.cxx, to close a set of registry windows.
+
+ WindowPosition - Pointer to a structure that contains size and
+ position of the MDI window to be created.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the registeration and creation operations
+ are successful.
+
+--*/
+
+{
+ MDICREATESTRUCT mdicreate;
+ HWND hWnd;
+ PWSTR String;
+
+ _RefreshFlag = FALSE;
+ _TreeViewFocus = TRUE;
+
+ DebugPtrAssert( Title );
+ DebugPtrAssert( WindowPosition );
+
+ if( Register( )) {
+
+ //
+ // If the window class was succesfully registered attempt to
+ // create the mdi client window. Note that we pass the 'this'
+ // pointer to the window.
+ //
+
+ //
+ // Initialize the REGISTRY_WINDOW's internal state.
+ //
+
+ _IR = InternalRegistry;
+ _RegistryWindowSet = RegistryWindowSet;
+
+ String = ( ( PWSTRING )Title )->QueryWSTR();
+ if( String == NULL ) {
+ DebugPrint( "Title->QuerySTR() failed" );
+ return( FALSE );
+ }
+ mdicreate.szClass = _WindowClassName;
+ mdicreate.szTitle = String;
+ mdicreate.hOwner = WINDOWS_APPLICATION::QueryInstance( );
+ mdicreate.x = WindowPosition->X;
+ mdicreate.y = WindowPosition->Y;
+ mdicreate.cx = WindowPosition->Width;
+ mdicreate.cy = WindowPosition->Height;
+ mdicreate.style = ( WindowPosition->Style == 1 )? WS_MINIMIZE :
+ ( ( WindowPosition->Style == 2 )? WS_MAXIMIZE : 0 );
+ mdicreate.lParam = ( LONG ) this;
+ _Split = WindowPosition->Split;
+
+ _ReceivedRefreshMessage = FALSE;
+ _ProcessRefreshMessage = TRUE;
+ if(( hWnd = (HWND)SendMessage( MDIHandle, WM_MDICREATE, 0,
+ ( DWORD ) (( LPMDICREATESTRUCT ) &mdicreate ))) != NULL ) {
+
+ //
+ // Double check that creation worked properly.
+ //
+
+ DbgWinAssert( hWnd == _Handle );
+
+ //
+ // Create the notification thread for this registry window
+ //
+
+ if( !CreateNotificationThread() ) {
+ DebugPrintf("Unable to create thread for %s \n", String );
+ DebugPrint( "CreateNotificationThread failed" );
+ }
+
+ //
+ // Return TRUE even if it was not able to create the notification
+ // thread. In this case we won't have auto-refresh
+ //
+ FREE( String );
+ return TRUE;
+
+ } else {
+ FREE( String );
+ return FALSE;
+ }
+ }
+ return FALSE;
+}
+
+
+
+
+BOOLEAN
+REGISTRY_WINDOW::CreateNotificationThread(
+ )
+
+/*++
+
+Routine Description:
+
+ Create the notification thread for the predefined key to be displayed
+ in this registry window, and all the events that control the notification
+ thread.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the notification thread was created.
+ Returns FALSE, otherwise.
+
+--*/
+
+{
+ PNOTIFICATION_THREAD_INFO ThreadInfo;
+ DWORD ThreadId;
+
+
+ _NotificationEvent = NULL;
+ _NotificationThreadHandle = NULL;
+
+ //
+ // Try to create the notification thread and returns TRUE
+ // even if it fails
+ //
+ //_NotificationEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+
+ //
+ // Create all events that control the notification thread, and
+ // allocate the structure used to pass information to the thread
+ //
+ _NotificationEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ ThreadInfo = ( PNOTIFICATION_THREAD_INFO )MALLOC( sizeof( NOTIFICATION_THREAD_INFO ) );
+
+ //
+ // Verify that the events were successfully created, and that the
+ // structure to pass information to the thread was allocated.
+ // Note that the notification thread will free this structure, after
+ // it copies its elements.
+ //
+ if( ( _NotificationEvent != NULL ) &&
+ ( ThreadInfo != NULL ) ) {
+
+ //
+ // Notification was set, so we can create the thread
+ //
+
+ ThreadInfo->RegistryWindow = this;
+ ThreadInfo->NotificationEvent = _NotificationEvent;
+ ThreadInfo->AutoRefreshEvent = WINDOWS_APPLICATION::_AutoRefreshEvent;
+ _NotificationThreadHandle = CreateThread( NULL,
+ 1024,
+ ( LPTHREAD_START_ROUTINE )NotificationThread,
+ ThreadInfo,
+ 0,
+ &ThreadId );
+
+ if( _NotificationThreadHandle == 0 ) {
+ //
+ // Unable to create the notification thread
+ //
+ DebugPrint( "CreateThread() failed" );
+ CloseHandle( _NotificationEvent );
+ _NotificationEvent = NULL;
+ FREE( ThreadInfo );
+ return( FALSE );
+ }
+ //
+ // Everything succeeded
+ //
+ return( TRUE );
+
+ } else {
+ //
+ // Unable to create one of the events, or unable to create
+ // the structure ThreadInfo
+ //
+
+ if( _NotificationEvent != NULL ) {
+ CloseHandle( _NotificationEvent );
+ _NotificationEvent = NULL;
+ } else {
+ DebugPrint( "Unable to create _NotificationEvent" );
+ }
+ if( ThreadInfo != NULL ) {
+ FREE( ThreadInfo );
+ } else {
+ DebugPrint( "Unable to allocate ThreadInfo" );
+ }
+ return( FALSE );
+ }
+}
+
+
+
+VOID
+REGISTRY_WINDOW::DisableNotificationThread(
+ )
+
+/*++
+
+Routine Description:
+
+ Disable the notification thread.
+ This method is used by the registry window to temporarily disable the
+ notification thread.
+ The notification thread should be disabled when a key is being added,
+ delete, or its security descriptor is being modified. Or when a value
+ entry is added, deleted or modified.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if( WINDOWS_APPLICATION::IsAutoRefreshEnabled() ) {
+ _ProcessRefreshMessage = FALSE;
+ _ReceivedRefreshMessage = FALSE;
+ }
+}
+
+
+
+
+VOID
+REGISTRY_WINDOW::EnableNotificationThread(
+ )
+
+/*++
+
+Routine Description:
+
+ Enable the notification thread.
+ The notification thread is disabled before a key is added, deleted,
+ or its security descriptor is modified. Or when a value, entry is added,
+ deleted or modified.
+
+ This method must be called after these operations are completed.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if( WINDOWS_APPLICATION::IsAutoRefreshEnabled() ) {
+ _ProcessRefreshMessage = TRUE;
+ if( _ReceivedRefreshMessage ) {
+ SendMessage( QueryHandle(), REFRESH_WINDOW, 0, 0 );
+ _ReceivedRefreshMessage = FALSE;
+ }
+ }
+}
+
+
+VOID
+REGISTRY_WINDOW::InitMenu(
+ IN HMENU Menu,
+ IN INT PopupMenu
+ )
+
+/*++
+
+Routine Description:
+
+ Figures out which items of the pulldown menu which should be enabled
+ or grayed. Windows will generate a WM_INITMENUPOPUP just before a
+ pulldown menu is painted.
+
+ Passes the message along if it can't figure out the status of menu
+ items.
+
+ This routine handles the status of menu items in the View pulldown.
+
+Arguments:
+
+ Menu - handle of the main menu
+ PopupMenu - the item number of the pulldown menu. eg.
+ File menu is 0, Edit is 1.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ HMENU SystemMenu;
+ PCREGEDIT_NODE Node;
+ ULONG NodeLevel;
+
+ SystemMenu = GetSystemMenu( _Handle, FALSE );
+ if( Menu == SystemMenu ) {
+ //
+ // If system menu, disable 'Close' option
+ //
+ EnableMenuItem( Menu, ( UINT )SC_CLOSE, ( UINT )MF_GRAYED );
+ return;
+ }
+ switch( PopupMenu ) {
+
+ case FILE_MENU:
+
+ if( _TreeViewFocus ) {
+ if( WINDOWS_APPLICATION::_RestorePrivilege ) {
+ EnableMenuItem( Menu, IDM_RESTORE_KEY, ( UINT )MF_ENABLED );
+ EnableMenuItem( Menu, IDM_RESTORE_KEY_VOLATILE, ( UINT )MF_ENABLED );
+
+ if( _IR->AreHiveOperationsAllowed() &&
+ ( Node = _StructureView->GetCurrentNode() ) != NULL
+ ) {
+ NodeLevel = _IR->GetNodeLevel( Node );
+ if( NodeLevel == 0 ) {
+ if( _IR->GetPredefinedKey() == PREDEFINED_KEY_CURRENT_USER ) {
+ EnableMenuItem( Menu, IDM_LOAD_HIVE, ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, IDM_UNLOAD_HIVE, ( UINT )MF_ENABLED );
+ } else {
+ EnableMenuItem( Menu, IDM_LOAD_HIVE, ( UINT )MF_ENABLED );
+ EnableMenuItem( Menu, IDM_UNLOAD_HIVE, ( UINT )MF_GRAYED );
+ }
+ } else if( NodeLevel == 1 ) {
+ EnableMenuItem( Menu, IDM_LOAD_HIVE, ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, IDM_UNLOAD_HIVE, ( UINT )MF_ENABLED );
+ } else {
+ EnableMenuItem( Menu, IDM_LOAD_HIVE, ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, IDM_UNLOAD_HIVE, ( UINT )MF_GRAYED );
+ }
+ } else {
+ EnableMenuItem( Menu, IDM_LOAD_HIVE, ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, IDM_UNLOAD_HIVE, ( UINT )MF_GRAYED );
+ }
+ } else {
+ EnableMenuItem( Menu, IDM_LOAD_HIVE, ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, IDM_UNLOAD_HIVE, ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, IDM_RESTORE_KEY, ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, IDM_RESTORE_KEY_VOLATILE, ( UINT )MF_GRAYED );
+ }
+ if( WINDOWS_APPLICATION::_BackupPrivilege ) {
+ EnableMenuItem( Menu, IDM_SAVE_KEY, ( UINT )MF_ENABLED );
+ } else {
+ EnableMenuItem( Menu, IDM_SAVE_KEY, ( UINT )MF_GRAYED );
+ }
+ } else {
+ EnableMenuItem( Menu, IDM_LOAD_HIVE, ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, IDM_UNLOAD_HIVE, ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, IDM_SAVE_KEY, ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, IDM_RESTORE_KEY, ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, IDM_RESTORE_KEY_VOLATILE, ( UINT )MF_GRAYED );
+ }
+ break;
+
+ case VIEW_MENU:
+ EnableMenuItem( Menu, ( UINT )IDM_SPLIT, ( UINT )MF_ENABLED );
+ if( _Split == 0 ) {
+ //
+ // splitter is at extreme left edge
+ // therefore we're in "Data Only" mode
+ //
+ CheckMenuItem( Menu, ( UINT )IDM_TREE_AND_DATA, ( UINT )MF_UNCHECKED );
+ CheckMenuItem( Menu, ( UINT )IDM_TREE_ONLY, ( UINT )MF_UNCHECKED );
+ CheckMenuItem( Menu, ( UINT )IDM_DATA_ONLY, ( UINT )MF_CHECKED );
+
+ } else if( _Split == -1 ) {
+ //
+ // splitter is at extreme right edge
+ // therefore we're in "Tree Only" mode
+ //
+ CheckMenuItem( Menu, ( UINT )IDM_TREE_AND_DATA, ( UINT )MF_UNCHECKED );
+ CheckMenuItem( Menu, ( UINT )IDM_TREE_ONLY, ( UINT )MF_CHECKED );
+ CheckMenuItem( Menu, ( UINT )IDM_DATA_ONLY, ( UINT )MF_UNCHECKED );
+
+ } else {
+ //
+ // in "both" mode
+ //
+ CheckMenuItem( Menu, ( UINT )IDM_TREE_AND_DATA, ( UINT )MF_CHECKED );
+ CheckMenuItem( Menu, ( UINT )IDM_TREE_ONLY, ( UINT )MF_UNCHECKED );
+ CheckMenuItem( Menu, ( UINT )IDM_DATA_ONLY, ( UINT )MF_UNCHECKED );
+ }
+ break;
+
+ case SECURITY_MENU:
+ if( _TreeViewFocus ) {
+ EnableMenuItem( Menu, ( UINT )IDM_PERMISSIONS, ( UINT )MF_ENABLED );
+ if( WINDOWS_APPLICATION::_SACLEditorEnabled ) {
+ EnableMenuItem( Menu, ( UINT )IDM_AUDITING, ( UINT )MF_ENABLED );
+ } else {
+ EnableMenuItem( Menu, ( UINT )IDM_AUDITING, ( UINT )MF_GRAYED );
+ }
+
+ EnableMenuItem( Menu, ( UINT )IDM_OWNER, ( UINT )MF_ENABLED );
+ } else {
+ EnableMenuItem( Menu, ( UINT )IDM_PERMISSIONS, ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, ( UINT )IDM_AUDITING, ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, ( UINT )IDM_OWNER, ( UINT )MF_GRAYED );
+ }
+ break;
+ }
+
+
+ // ACTION: change this to a SendMessage
+ if( _TreeViewFocus ) {
+ _StructureView->InitMenu( Menu, PopupMenu );
+ } else {
+ _DataView->InitMenu( Menu, PopupMenu );
+ }
+}
+
+
+VOID
+REGISTRY_WINDOW::LButtonDown(
+ IN LONG XPos
+ )
+
+/*++
+
+Routine Description:
+
+ Called when the left mouse button is depressed and the pointer is
+ in the RegWin's own client area.
+ The mouse is only in the client area of the RegWin when it is in the
+ area between the tree view and data view panes. We call this area the
+ splitter bar and this routine allows us to move it.
+
+ This routine is also called when View/Split is selected.
+
+Arguments:
+
+ XPos - x position of the mouse cursor when
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ MSG msg;
+ INT x, y, dx, dy;
+ RECT rc;
+ HDC hdc;
+
+ if (IsIconic(_Handle))
+ return;
+
+ y = 0;
+ x = ( INT )( LOWORD( XPos ) );
+
+ GetClientRect(_Handle, &rc);
+
+ dx = 4;
+ dy = ( INT )(rc.bottom - y); // the height of the client less the drives window
+
+ hdc = GetDC(_Handle);
+
+ // split bar loop
+
+ PatBlt(hdc, x - dx / 2, y, dx, dy, PATINVERT);
+
+ SetCapture(_Handle);
+
+ SetCursor( _SplitCursor );
+
+ while (GetMessage(&msg, NULL, 0, 0)) {
+
+ if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN ||
+ (msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST)) {
+
+ if (msg.message == WM_LBUTTONUP || msg.message == WM_LBUTTONDOWN)
+ break;
+
+ if (msg.message == WM_KEYDOWN) {
+
+ if (msg.wParam == VK_LEFT) {
+ msg.message = WM_MOUSEMOVE;
+ msg.pt.x -= 2;
+ } else if (msg.wParam == VK_RIGHT) {
+ msg.message = WM_MOUSEMOVE;
+ msg.pt.x += 2;
+ } else if (msg.wParam == VK_RETURN ||
+ msg.wParam == VK_ESCAPE) {
+ break;
+ }
+
+ SetCursorPos(( INT )msg.pt.x, ( INT )msg.pt.y);
+ }
+
+ if (msg.message == WM_MOUSEMOVE) {
+
+ // erase old
+
+ PatBlt(hdc, x - dx / 2, y, dx, dy, PATINVERT);
+ ScreenToClient(_Handle, &msg.pt);
+ x = ( INT )msg.pt.x;
+
+ // put down new
+
+ PatBlt(hdc, x - dx / 2, y, dx, dy, PATINVERT);
+ }
+ } else {
+ DispatchMessage(&msg);
+ }
+ }
+ ReleaseCapture();
+
+ // erase old
+
+ PatBlt(hdc, x - dx / 2, y, dx, dy, PATINVERT);
+ ReleaseDC(_Handle, hdc);
+
+ if (msg.wParam != VK_ESCAPE) {
+
+ if( x < 0 ) {
+ //
+ // the button was released left of the frame so set the user wants
+ // only a data window
+ //
+ _Split = 0;
+ } else {
+ _Split = x;
+ }
+
+ Resize( ( INT )rc.right, ( INT )rc.bottom );
+ }
+
+}
+
+
+BOOLEAN
+REGISTRY_WINDOW::Register (
+ )
+
+/*++
+
+Routine Description:
+
+ Register the REGISTRY_WINDOW window class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the REGISTRY_WINDOW window class
+ is registered.
+
+--*/
+
+{
+ WNDCLASS wndclass;
+
+ if( !_Registered ) {
+ _Registered = TRUE;
+ //
+ // Register the REGISTRY_WINDOW window class. This call
+ // may fail if the class has already been registered but this is
+ // usually OK because that's what we wanted to do anyway.
+ //
+
+ wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_NOCLOSE;
+ wndclass.lpfnWndProc = (WNDPROCFN)REGISTRY_WINDOW::WndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = sizeof( DWORD );
+ wndclass.hInstance = (HINSTANCE)WINDOWS_APPLICATION::QueryInstance( );
+ wndclass.hIcon = LoadIcon(
+ (HINSTANCE)WINDOWS_APPLICATION::QueryInstance( ),
+ MAKEINTRESOURCE( IDI_REGEDIT ) );
+
+ //
+ // save the cursor for use when we grab the cursor when moving
+ // the splitter bar with the keyboard
+ //
+ _SplitCursor =
+ wndclass.hCursor = LoadCursor(
+ (HINSTANCE)WINDOWS_APPLICATION::QueryInstance( ),
+ (LPWSTR)L"SPLIT");
+ wndclass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 );
+ wndclass.lpszMenuName = NULL;
+ wndclass.lpszClassName = _WindowClassName;
+
+ RegisterClass( &wndclass );
+ }
+ return TRUE;
+
+}
+
+
+VOID
+REGISTRY_WINDOW::Resize(
+ INT dxWindow,
+ INT dyWindow
+ )
+
+/*++
+
+Routine Description:
+
+ Resizes the RegWin to the size specified. Accounts for the
+ splitter bar being 'stuck' to the left or right edge.
+
+Arguments:
+
+ dxWindow - width of client area for regwin
+ dyWindow - height of client area
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ // bugbug: (w-wilson) change 0 to some threshold
+ if( _Split + dxFrame > dxWindow ) {
+ //
+ // the button was released right of the frame so set the user wants
+ // only a tree window
+ //
+ _Split = -1;
+ }
+ // otherwise,
+ // the button was released in between so leave the split position
+ //
+
+ //
+ // resize the treeview
+ // - position the treeview in the upper left corner (0,0)
+ // - use the splitter bar position as the width
+ // - use full height of client area
+ //
+ if( _Split >= 0 ) {
+ _StructureView->Resize( 0, 0, _Split, dyWindow );
+ } else {
+ _StructureView->Resize( 0, 0, dxWindow - dxFrame, dyWindow );
+ }
+
+ //
+ // resize the dataview
+ // - position the dataview beside the treeview and splitter bar
+ // -> X = treeview width(_Split) + splitter width(dxFrame)
+ // -> Y = 0
+ // -> width = full width - (treeview width + splitter width)
+ // -> height= full height of client area
+ //
+ if( _Split >= 0 ) {
+ _DataView->Resize( _Split + dxFrame, 0,
+ dxWindow - (_Split + dxFrame), dyWindow );
+ } else {
+ _DataView->Resize( 0, 0, 0, 0 );
+ }
+
+}
+
+
+
+
+LONG
+APIENTRY
+EXPORT
+REGISTRY_WINDOW::WndProc (
+ HWND hWnd,
+ WORD wMessage,
+ WPARAM wParam,
+ LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Handle all requests made of the REGISTRY_WINDOW window class.
+
+Arguments:
+
+ Standard Window's exported function signature.
+
+Return Value:
+
+ LONG - Returns 0 if the message was handled.
+
+--*/
+
+{
+ REGISTER PREGISTRY_WINDOW pRegWin;
+ RECT rc;
+ INT PopupMenuId;
+ DSTRING FindString;
+
+
+
+ //
+ // WM_CREATE is handled specially as it is when the connection between
+ // a Window and its associated object is established.
+ //
+
+ if( wMessage == WM_CREATE ) {
+
+ //
+ // Save 'this' to owning WINDOW Class and initialize the _Handle
+ // member data.
+ //
+
+ pRegWin =
+ ( PREGISTRY_WINDOW )
+ ((( LPMDICREATESTRUCT )
+ ((( LPCREATESTRUCT ) lParam )->lpCreateParams ))->lParam );
+ SetObjectPointer( hWnd, pRegWin );
+ pRegWin->_Handle = hWnd;
+
+ //
+ // - find out the size of the client area
+ // - calculate the initial splitter position as the middle
+ // - subtract dxFrame from width to allow for splitter bar
+ //
+ GetClientRect( hWnd, &rc );
+ if( pRegWin->_Split == CW_USEDEFAULT ) {
+ pRegWin->_Split = ( INT )( (rc.right - dxFrame) / 2 );
+ }
+
+ //
+ // initialize the treeview
+ //
+ pRegWin->_StructureView = NEW TREE_STRUCTURE_VIEW;
+ pRegWin->_StructureView->Initialize( hWnd,
+ pRegWin->_IR );
+ //
+ // initialize the dataview
+ //
+ pRegWin->_DataView = NEW DATA_VIEW;
+ pRegWin->_DataView->Initialize( hWnd,
+ pRegWin->_IR );
+
+ SetFocus( pRegWin->_StructureView->QueryHandle() );
+ //
+ // we don't need to call Resize() to set the sizes of the
+ // child windows because a WM_SIZE always follows a WM_CREATE
+ // and the handler for WM_SIZE calls Resize()
+ //
+ return 0;
+ }
+
+ //
+ // Retrieve 'this' pointer.
+ //
+
+ pRegWin = ( PREGISTRY_WINDOW ) GetObjectPointer( hWnd );
+
+
+ //
+ // This 'if' clause is for all messages after WM_CREATE.
+ //
+
+ if( pRegWin != NULL ) {
+
+ //
+ // Check the 'this' wasn't trampled.
+ //
+
+ DbgWinAssert( hWnd == pRegWin->_Handle );
+
+
+ switch( wMessage ) {
+
+ case LOAD_HIVE:
+ case UNLOAD_HIVE:
+ case RESTORE_KEY:
+ case RESTORE_KEY_VOLATILE:
+ case SAVE_KEY:
+
+ pRegWin->DisableNotificationThread();
+ SendMessage( pRegWin->_StructureView->QueryHandle(),
+ wMessage,
+ wParam,
+ lParam );
+ pRegWin->EnableNotificationThread();
+ break;
+
+
+
+ case DATAVW_DBL_CLICK:
+
+ pRegWin->DisableNotificationThread();
+ SendMessage( pRegWin->_DataView->QueryHandle(),
+ wMessage,
+ 0,
+ 0 );
+ pRegWin->EnableNotificationThread();
+ break;
+
+
+ case FIND_KEY:
+ pRegWin->DisableNotificationThread();
+ SendMessage( pRegWin->_StructureView->QueryHandle(),
+ wMessage, wParam, lParam );
+ pRegWin->EnableNotificationThread();
+ break;
+
+
+ case REFRESH_WINDOW:
+ if( pRegWin->_ProcessRefreshMessage ) {
+ if( IsIconic( hWnd ) ) {
+ pRegWin->_RefreshFlag = TRUE;
+ } else {
+ pRegWin->DisableNotificationThread();
+ pRegWin->_DataView->SaveCurrentValueName();
+ SendMessage( pRegWin->_StructureView->QueryHandle(),
+ wMessage, wParam, lParam );
+ pRegWin->EnableNotificationThread();
+ }
+ } else {
+ pRegWin->_ReceivedRefreshMessage = TRUE;
+ }
+ break;
+
+ case TREE_VIEW_FOCUS:
+ pRegWin->_TreeViewFocus = TRUE;
+ break;
+
+ case DATA_VIEW_FOCUS:
+ pRegWin->_TreeViewFocus = FALSE;
+ break;
+
+ case WM_SETFOCUS:
+ if (pRegWin->_TreeViewFocus) {
+ SetFocus( pRegWin->_StructureView->QueryHandle() );
+ } else {
+ SetFocus( pRegWin->_DataView->QueryHandle() );
+ }
+ return DefMDIChildProc( hWnd, wMessage, wParam, lParam );
+
+ case WM_INITMENUPOPUP:
+ PopupMenuId = LOWORD(lParam);
+ if (WINDOWS_APPLICATION::_ChildWindowMaximized) {
+ PopupMenuId--;
+ }
+ pRegWin->InitMenu( (HMENU) wParam, PopupMenuId );
+ break;
+
+ case WM_CLOSE:
+
+ // You can't close these guys.
+ //
+ break;
+
+
+ case WM_DESTROY:
+ if( pRegWin->_NotificationThreadHandle != NULL ) {
+ if( !TerminateThread( pRegWin->_NotificationThreadHandle,
+ 0 ) ) {
+ DebugPrintf( "TerminateThread() failed, Handle = %#x, Error = %#x \n",
+ pRegWin->_NotificationThreadHandle,
+ GetLastError );
+ DebugPrint( "TerminateThread() failed" );
+ }
+ if( !CloseHandle( pRegWin->_NotificationThreadHandle ) ) {
+ DebugPrintf( "CloseHandle() failed, Handle = %#x, Error = %#x \n",
+ pRegWin->_NotificationThreadHandle,
+ GetLastError );
+ DebugPrint( "TerminateThread() failed" );
+ }
+ }
+
+ if( !DestroyWindow( pRegWin->_DataView->QueryHandle() ) ) {
+ GetLastError();
+ }
+
+ if( !DestroyWindow( pRegWin->_StructureView->QueryHandle() ) ) {
+ GetLastError();
+ }
+
+ DELETE( pRegWin->_DataView );
+ DELETE( pRegWin->_StructureView );
+ DELETE( pRegWin->_IR );
+ return DefMDIChildProc( hWnd, wMessage, wParam, lParam );
+
+
+
+ case WM_COMMAND:
+
+ switch( LOWORD( wParam ) ) {
+
+
+ case ID_ENTER_KEY:
+ if( !IsIconic( hWnd ) ) {
+ pRegWin->DisableNotificationThread();
+ if (pRegWin->_DataView->_HasFocus) {
+ SendMessage( pRegWin->_DataView->QueryHandle(),
+ wMessage, wParam, lParam );
+ } else {
+ SendMessage( pRegWin->_StructureView->QueryHandle(),
+ wMessage, wParam, lParam );
+ }
+ pRegWin->EnableNotificationThread();
+ } else {
+ ShowWindow( hWnd, SW_RESTORE );
+ }
+ break;
+
+
+
+ case ID_TOGGLE_FOCUS:
+ if (pRegWin->_StructureView->_HasFocus) {
+ SetFocus( pRegWin->_DataView->QueryHandle() );
+ } else {
+ SetFocus( pRegWin->_StructureView->QueryHandle() );
+ }
+ break;
+
+
+ case IDM_REFRESH:
+ pRegWin->_DataView->SaveCurrentValueName();
+ SendMessage( pRegWin->_StructureView->QueryHandle(),
+ wMessage, wParam, lParam );
+ break;
+
+
+ case IDM_ADD_KEY:
+ pRegWin->DisableNotificationThread();
+ SendMessage( pRegWin->_StructureView->QueryHandle(),
+ wMessage, wParam, lParam );
+ pRegWin->EnableNotificationThread();
+ break;
+
+
+ case IDM_ADD_VALUE:
+ pRegWin->DisableNotificationThread();
+ SendMessage( pRegWin->_DataView->QueryHandle(),
+ wMessage, wParam, lParam );
+ pRegWin->EnableNotificationThread();
+ break;
+
+ case IDM_INSERT:
+ case IDM_DELETE:
+ pRegWin->DisableNotificationThread();
+ if( pRegWin->_DataView->_HasFocus ) {
+ SendMessage( pRegWin->_DataView->QueryHandle(),
+ wMessage, wParam, lParam );
+ if( pRegWin->_DataView->_Items == 0 ) {
+ SetFocus( pRegWin->_StructureView->QueryHandle() );
+ }
+ } else if( pRegWin->_StructureView->_HasFocus ) {
+ SendMessage( pRegWin->_StructureView->QueryHandle(),
+ wMessage, wParam, lParam );
+ }
+ pRegWin->EnableNotificationThread();
+ break;
+
+
+ case IDM_EXPAND_ONE_LEVEL:
+ case IDM_EXPAND_BRANCH:
+ case IDM_EXPAND_ALL:
+ case IDM_COLLAPSE_BRANCH:
+ pRegWin->DisableNotificationThread();
+ SendMessage( pRegWin->_StructureView->QueryHandle(),
+ wMessage, wParam, lParam );
+ pRegWin->EnableNotificationThread();
+ break;
+
+ case IDM_BINARY:
+ case IDM_STRING:
+ case IDM_ULONG:
+ case IDM_MULTISZ:
+ pRegWin->DisableNotificationThread();
+ SendMessage( pRegWin->_DataView->QueryHandle(),
+ wMessage, wParam, lParam );
+ pRegWin->EnableNotificationThread();
+ break;
+
+ //
+ // Handle menu commands.
+ //
+
+ case IDM_TREE_AND_DATA:
+ GetClientRect(hWnd, &rc);
+ pRegWin->_Split = ( INT )( (rc.right - dxFrame) / 2 );
+ pRegWin->Resize( ( INT )rc.right, ( INT )rc.bottom );
+ break;
+
+ case IDM_TREE_ONLY:
+ if( pRegWin->_Split != -1 ) {
+ GetClientRect(hWnd, &rc);
+ pRegWin->_Split = -1;
+ pRegWin->Resize( ( INT )rc.right, ( INT )rc.bottom );
+ }
+ break;
+
+ case IDM_DATA_ONLY:
+ if( pRegWin->_Split != 0 ) {
+ GetClientRect(hWnd, &rc);
+ pRegWin->_Split = 0;
+ pRegWin->Resize( ( INT )rc.right, ( INT )rc.bottom );
+ }
+ break;
+
+ case IDM_SPLIT:
+ pRegWin->LButtonDown( lParam );
+ break;
+
+
+
+ case IDM_DISPLAY_BINARY:
+ if( ( pRegWin->_DataView->_HasFocus ) &&
+ ( pRegWin->_DataView->_Items != 0 ) ) {
+ SendMessage( pRegWin->_DataView->QueryHandle(),
+ wMessage, wParam, lParam );
+ }
+ break;
+
+
+ case IDM_PERMISSIONS:
+ case IDM_AUDITING:
+ case IDM_OWNER:
+
+ pRegWin->DisableNotificationThread();
+ if( pRegWin->_StructureView->_HasFocus ) {
+ SendMessage( pRegWin->_StructureView->QueryHandle(),
+ wMessage, wParam, lParam );
+ }
+ pRegWin->EnableNotificationThread();
+ break;
+
+
+ default:
+ return DefMDIChildProc( hWnd, wMessage, wParam, lParam );
+ }
+ break;
+
+
+ case INFORM_CHANGE_FONT:
+ SendMessage( pRegWin->_StructureView->QueryHandle(),
+ wMessage, wParam, lParam );
+ SendMessage( pRegWin->_DataView->QueryHandle(),
+ wMessage, wParam, lParam );
+ break;
+
+ case TR_NEWCURSEL:
+ pRegWin->_DataView->SetDataNode( (PCREGEDIT_NODE)lParam );
+ break;
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HDC hdc;
+
+ hdc = BeginPaint(hWnd, &ps);
+
+ if( !IsIconic(hWnd) ) {
+
+ //
+ // we want to paint the bottom part of the splitter bar
+ //
+ GetClientRect(hWnd, &rc);
+
+ //
+ // - we leave bottom alone
+ // - top is the bottom - the height of a horiz scrollbar
+ //
+ rc.top = rc.bottom - GetSystemMetrics(SM_CYHSCROLL);
+
+ //
+ // - set the left edge of rect to the splitter position.
+ //
+ // This will be the correct position except when it's -1
+ // which indicates the bar is 'stuck' to the right edge
+ // of the RegWin. So, when it's -1, set the left edge
+ // the right edge less the width of the splitter and leave
+ // the right edge alone.
+ //
+ // If not -1 then the split position (left edge) is correct
+ // so just set the right edge to left + splitter width
+ //
+ rc.left = pRegWin->_Split;
+
+ if( rc.left == -1 ) {
+ rc.left = rc.right - dxFrame;
+ } else {
+ rc.right = rc.left + dxFrame;
+ }
+
+ // draw the black pane handle
+
+ FillRect(hdc, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH));
+ }
+
+ EndPaint(hWnd, &ps);
+ break;
+ }
+
+ case WM_LBUTTONDOWN:
+ pRegWin->LButtonDown( lParam );
+ break;
+
+ case WM_SIZE:
+ if (wParam != SIZEICONIC) {
+ pRegWin->Resize( LOWORD( lParam ), HIWORD( lParam ) );
+ }
+
+ if (wParam == SIZEFULLSCREEN) {
+ WINDOWS_APPLICATION::_ChildWindowMaximized = TRUE;
+ } else {
+ WINDOWS_APPLICATION::_ChildWindowMaximized = FALSE;
+ }
+
+ if( ( ( wParam == SIZEFULLSCREEN ) || ( wParam == SIZENORMAL ) ) &&
+ WINDOWS_APPLICATION::IsAutoRefreshEnabled() &&
+ pRegWin->_RefreshFlag ) {
+ pRegWin->_RefreshFlag = FALSE;
+ PostMessage( hWnd, REFRESH_WINDOW, 0, 0 );
+ }
+
+ //
+ // NOTE!!!!! MUST FALL THROUGH TO DefMDIChildProc!!!!
+ //
+ return DefMDIChildProc( hWnd, wMessage, wParam, lParam );
+
+ default:
+
+ //
+ // Let windows handle the message
+ //
+
+ return DefMDIChildProc( hWnd, wMessage, wParam, lParam );
+
+ }
+
+ } else {
+
+ //
+ // No 'this' pointer (pRegWin == NULL).
+ //
+ // Let Windows handle the message.
+ //
+
+ return DefMDIChildProc( hWnd, wMessage, wParam, lParam );
+ }
+
+ return( 0 );
+}
+
+
+
+PCREGEDIT_NODE
+REGISTRY_WINDOW::GetCurrentNode (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the pointer to the node currently selected in the tree view.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PNODE - Pointer to the current node
+
+--*/
+
+{
+ return( _StructureView->GetCurrentNode() );
+}
+
+
+
+
+LPDWORD
+NotificationThread(
+ PVOID NotificationInfo
+ )
+/*++
+
+Routine Description:
+
+ Send mesaage to the registry window that contains the predefined key
+ that this thread is monitoring, so that the tree view and data view
+ displayed can be uptadet.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns 0 when it terminates.
+
+--*/
+
+
+{
+ PREGISTRY_WINDOW RegistryWindow;
+ HANDLE NotificationEvent;
+ HANDLE AutoRefreshEvent;
+#if 0
+ PCWSTRING RootName;
+ PSTR RootNameSTR;
+#endif
+ BOOLEAN Flag;
+ HANDLE TimeOutEvent;
+
+ RegistryWindow = ( ( PNOTIFICATION_THREAD_INFO )NotificationInfo )->RegistryWindow;
+ NotificationEvent = ( ( PNOTIFICATION_THREAD_INFO )NotificationInfo )->NotificationEvent;
+ AutoRefreshEvent = ( ( PNOTIFICATION_THREAD_INFO )NotificationInfo )->AutoRefreshEvent;
+ //
+ // Free the NotificationInfo structure, after all its elements are copied
+ //
+ FREE( NotificationInfo );
+ TimeOutEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ if( TimeOutEvent == NULL ) {
+ DebugPrint( "Unable to create TimeOutEvent" );
+ DebugPrintf( "UnableToCreateTimeOutEvent, GetLastError() = %#x \n",
+ GetLastError() );
+ }
+
+
+#if 0
+ RootName = NULL;
+ RootNameSTR = NULL;
+ RootName = RegistryWindow->_IR->GetRootName();
+ if( ( RootName == NULL ) ||
+ ( ( RootNameSTR = RootName->QuerySTR() ) == NULL ) ) {
+ DebugPrint( "Unable to get RootName" );
+ }
+#endif
+ //
+ // Do forever
+ //
+ while( TRUE ) {
+ //
+ // Wait until auto refresh is enabled
+ //
+ WaitForSingleObject( AutoRefreshEvent, ( DWORD )-1 );
+ //
+ // Once auto refresh is set, enable notification
+ //
+ RegistryWindow->_IR->EnableRootNotification( NotificationEvent,
+ REG_NOTIFY_CHANGE_NAME |
+ REG_NOTIFY_CHANGE_ATTRIBUTES |
+ REG_NOTIFY_CHANGE_LAST_SET |
+ REG_NOTIFY_CHANGE_SECURITY,
+ TRUE );
+ //
+ // Wait for a change in the root node to occur
+ //
+ WaitForSingleObject( NotificationEvent, ( DWORD )( -1 ) );
+
+
+ //
+ // Wait for the registry to become stable
+ //
+ while( RegistryWindow->_IR->EnableRootNotification( TimeOutEvent,
+ REG_NOTIFY_CHANGE_NAME |
+ REG_NOTIFY_CHANGE_ATTRIBUTES |
+ REG_NOTIFY_CHANGE_LAST_SET |
+ REG_NOTIFY_CHANGE_SECURITY,
+ TRUE ) &&
+ WaitForSingleObject( TimeOutEvent, 1000 ) == 0 ) {
+
+// DebugPrint( "Registry is being modified" );
+ }
+ //
+ // Reset the event so thjat it is ready for the next time.
+ //
+ ResetEvent( TimeOutEvent );
+
+
+ //
+ // Double check whether auto refresh is still enabled
+ //
+ if( WaitForSingleObject( AutoRefreshEvent, 0 ) == 0 ) {
+ //
+ // If the auto refresh is still enabled, inform registry window
+ // that a change in the predefined key has occurred
+ // has occurred.
+ //
+#if 0
+ if( RootNameSTR != NULL ) {
+ DebugPrintf( "%s generated a notification \n", RootNameSTR );
+ }
+#endif
+
+ Flag = FALSE;
+ while( !Flag ) {
+ Flag = PostMessage( RegistryWindow->_Handle, REFRESH_WINDOW, 0, 0 );
+ }
+ }
+ }
+
+ return( 0 ); // To keep the compiler happy
+}
diff --git a/private/utils/regedit/src/sources b/private/utils/regedit/src/sources
new file mode 100644
index 000000000..0261c845e
--- /dev/null
+++ b/private/utils/regedit/src/sources
@@ -0,0 +1,119 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+
+!ENDIF
+
+BLDCRT=1
+
+MAJORCOMP=port
+MINORCOMP=regedt32
+
+TARGETNAME=regedt32
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+INCLUDES=..\inc;..\..\ulib\inc;..\..\ureg\inc;\nt\public\sdk\inc;\nt\private\inc;\nt\private\windows\inc;\nt\private\sdktools\wintools\clb
+#;\nt\private\ntos\inc;
+
+#
+# Debug support.
+#
+# We have 4 levels:
+#
+# 1.- FREE: Non-debug
+# 2.- NTDBG: Debug, no memleak
+# 3.- MEMLEAK: 2 + memleak
+# 4.- STACK_TRACE 3 + stack trace
+#
+#
+# By default, whenever the NTDEBUG symbol is defined, you get level
+# 3. In order to get level 2 you have to define the symbol NOMEMLEAK.
+# In order to get level 4, you have to the file the symbol STACK_TRACE
+#
+# In summary here is how to get each one:
+#
+# 1.- Undefine NTDEBUG
+# 2.- define NTDEBUG, define NOMEMLEAK
+# 3.- define NTDEBUG, undefine NOMEMLEAK
+# 4.- define NTDEBUG, undefine NOMEMLEAK, define STACK_TRACE
+#
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DWIN32 -DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1 -D_REGEDT32_
+!ELSE # NOMEMLEAK
+!IFDEF STACK_TRACE
+C_DEFINES=-DWIN32 -DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1 -D_REGEDT32_
+!ELSE # STACK_TRACE
+C_DEFINES=-DWIN32 -DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1 -D_REGEDT32_
+!ENDIF # STACK_TRACE
+!ENDIF # NOMEMLEAK
+!ELSE # NTDEBUG
+C_DEFINES=-DWIN32 -DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1 -D_REGEDT32_
+!ENDIF # NTDEBUG
+
+
+CXXFLAGS=+d
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES= \
+ datavw.cxx \
+ debug.cxx \
+ editor.cxx \
+ printman.cxx \
+ regdata.cxx \
+ regdesc.cxx \
+ regedir.cxx \
+ regedit.rc \
+ regednod.cxx \
+ regedval.cxx \
+ regfdesc.cxx \
+ regiodsc.cxx \
+ regiodls.cxx \
+ regioreq.cxx \
+ regresls.cxx \
+ regsys.cxx \
+ regwin.cxx \
+ treevw.cxx \
+ uapp.cxx \
+ winapp.cxx \
+ window.cxx
+
+
+
+
+UMTYPE=windows
+UMAPPL=regedt32
+UMLIBS=\nt\public\sdk\lib\*\pwin32.lib \
+ ..\..\ulib\src\obj\*\ulib.lib \
+ ..\..\ureg\src\obj\*\ureg.lib \
+ \nt\private\sdktools\wintools\clb\obj\*\clb.lib \
+ \nt\public\sdk\lib\*\comdlg32.lib \
+ \nt\public\sdk\lib\*\comctl32.lib \
+ \nt\public\sdk\lib\*\advapi32.lib \
+ \nt\public\sdk\lib\*\ntlanman.lib \
+ \nt\public\sdk\lib\*\acledit.lib \
+ \nt\public\sdk\lib\*\shell32.lib \
+ \nt\public\sdk\lib\*\ntdll.lib \
+ obj\*\regedt32.lib
+UMRES=obj\*\regedit.res
diff --git a/private/utils/regedit/src/split.cur b/private/utils/regedit/src/split.cur
new file mode 100644
index 000000000..beeec2b38
--- /dev/null
+++ b/private/utils/regedit/src/split.cur
Binary files differ
diff --git a/private/utils/regedit/src/treevw.cxx b/private/utils/regedit/src/treevw.cxx
new file mode 100644
index 000000000..8d46cc67a
--- /dev/null
+++ b/private/utils/regedit/src/treevw.cxx
@@ -0,0 +1,3774 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ treevw.cxx
+
+Abstract:
+
+ Methods for TREE_STRUCTURE_VIEW class.
+
+Author:
+
+ Bruce W. Wilson (w-wilson) 14-Aug-1991
+
+Environment:
+
+ Ulib, Regedit, Windows, User Mode
+
+--*/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "uapp.hxx"
+
+#include "iterator.hxx"
+
+#include "regedir.hxx"
+#include "regwin.hxx"
+#include "winapp.hxx"
+#include "treevw.hxx"
+#include "regsys.hxx"
+
+extern "C" {
+#include "defmsg.h"
+#include "resource.h"
+#include "windows.h"
+#include "sedapi.h"
+}
+#include "regedit.hxx"
+
+extern "C" {
+#include "dialogs.h"
+#include "regedhlp.h"
+#include "winuserp.h"
+}
+
+//
+// Definition of the structure used to exchange information between
+// the AddNode() function and the AddNodeDlgProc() function
+//
+
+typedef struct _ADD_NODE_DIALOG_INFO {
+ PWSTRING Name;
+ PWSTRING Title;
+ PWSTRING Class;
+ BOOLEAN ClassDisplayed;
+ BOOLEAN VolatileKey;
+ } ADD_NODE_DIALOG_INFO, *PADD_NODE_DIALOG_INFO;
+
+
+//
+// Definition of the structure used to pass information from the security
+// editor to the fucntion that will set the security descriptor of a key.
+//
+
+
+typedef struct _CALLBACK_CONTEXT {
+ PTREE_STRUCTURE_VIEW ThisPointer;
+ SECURITY_INFORMATION SecurityInfo;
+} CALLBACK_CONTEXT, *PCALLBACK_CONTEXT;
+
+
+
+
+//
+// Initialize TREE_STRUCTURE_VIEW's window class name and note that it
+// has not been registered.
+//
+
+LPWSTR TREE_STRUCTURE_VIEW::_WindowClassName = (LPWSTR)L"TREE_STRUCTURE_VIEW";
+BOOLEAN TREE_STRUCTURE_VIEW::_Registered = FALSE;
+PWSTRING TREE_STRUCTURE_VIEW::_MsgSpecialAccessTitle;
+PWSTRING TREE_STRUCTURE_VIEW::_MsgObjectTypeName;
+PWSTRING TREE_STRUCTURE_VIEW::_MsgHelpFileName;
+PWSTRING TREE_STRUCTURE_VIEW::_MsgApplyPermissionToSubKeys;
+PWSTRING TREE_STRUCTURE_VIEW::_MsgAuditPermissionOfSubKeys;
+PWSTRING TREE_STRUCTURE_VIEW::_MsgConfirmApplyToSubKeys;
+PWSTRING TREE_STRUCTURE_VIEW::_MsgConfirmAuditSubKeys;
+PWSTRING TREE_STRUCTURE_VIEW::_MsgDefaultPermissionName;
+
+
+//
+// Initialization of static arrays used by permission and SACL editors
+//
+
+
+BOOLEAN TREE_STRUCTURE_VIEW::_SedAppAccessInitialized = FALSE;
+
+
+ULONG TREE_STRUCTURE_VIEW::_MsgIdKeyPermNames[] =
+ {
+ MSG_SEC_EDITOR_QUERY_VALUE,
+ MSG_SEC_EDITOR_SET_VALUE,
+ MSG_SEC_EDITOR_CREATE_SUBKEY,
+ MSG_SEC_EDITOR_ENUM_SUBKEYS,
+ MSG_SEC_EDITOR_NOTIFY,
+ MSG_SEC_EDITOR_CREATE_LINK,
+ MSG_SEC_EDITOR_DELETE,
+ MSG_SEC_EDITOR_WRITE_DAC,
+ MSG_SEC_EDITOR_WRITE_OWNER,
+ MSG_SEC_EDITOR_READ_CONTROL,
+ MSG_SEC_EDITOR_READ,
+ MSG_SEC_EDITOR_FULL_ACCESS
+ };
+
+#define COUNT_MSG_ID_KEY_PERM_NAMES sizeof( _MsgIdKeyPermNames ) / sizeof( ULONG )
+
+
+
+ULONG TREE_STRUCTURE_VIEW::_MsgIdKeyAuditNames[] =
+ {
+ MSG_SEC_EDITOR_QUERY_VALUE,
+ MSG_SEC_EDITOR_SET_VALUE,
+ MSG_SEC_EDITOR_CREATE_SUBKEY,
+ MSG_SEC_EDITOR_ENUM_SUBKEYS,
+ MSG_SEC_EDITOR_NOTIFY,
+ MSG_SEC_EDITOR_CREATE_LINK,
+ MSG_SEC_EDITOR_DELETE ,
+ MSG_SEC_EDITOR_WRITE_DAC,
+// MSG_SEC_EDITOR_WRITE_OWNER,
+ MSG_SEC_EDITOR_READ_CONTROL
+ };
+
+
+#define COUNT_MSG_ID_KEY_AUDIT_NAMES sizeof( _MsgIdKeyAuditNames ) / sizeof( ULONG )
+
+
+
+
+SED_APPLICATION_ACCESS TREE_STRUCTURE_VIEW::_SedAppAccessKeyPerms[] =
+ {
+ { SED_DESC_TYPE_RESOURCE_SPECIAL, KEY_QUERY_VALUE, 0, NULL },
+ { SED_DESC_TYPE_RESOURCE_SPECIAL, KEY_SET_VALUE, 0, NULL },
+ { SED_DESC_TYPE_RESOURCE_SPECIAL, KEY_CREATE_SUB_KEY, 0, NULL },
+ { SED_DESC_TYPE_RESOURCE_SPECIAL, KEY_ENUMERATE_SUB_KEYS, 0, NULL },
+ { SED_DESC_TYPE_RESOURCE_SPECIAL, KEY_NOTIFY, 0, NULL },
+ { SED_DESC_TYPE_RESOURCE_SPECIAL, KEY_CREATE_LINK, 0, NULL },
+ { SED_DESC_TYPE_RESOURCE_SPECIAL, 0x00010000, /* DELETE, */ 0, NULL },
+ { SED_DESC_TYPE_RESOURCE_SPECIAL, WRITE_DAC, 0, NULL },
+ { SED_DESC_TYPE_RESOURCE_SPECIAL, WRITE_OWNER, 0, NULL },
+ { SED_DESC_TYPE_RESOURCE_SPECIAL, READ_CONTROL, 0, NULL },
+ { SED_DESC_TYPE_RESOURCE, KEY_READ, 0, NULL },
+ { SED_DESC_TYPE_RESOURCE, GENERIC_ALL, /* KEY_ALL_ACCESS, */ 0, NULL }
+ };
+
+#define COUNT_KEY_PERMS_ARRAY ( sizeof( _SedAppAccessKeyPerms ) / sizeof( SED_APPLICATION_ACCESS ) )
+
+
+
+SED_APPLICATION_ACCESS TREE_STRUCTURE_VIEW::_SedAppAccessKeyAudits[] =
+ {
+ { SED_DESC_TYPE_AUDIT, KEY_QUERY_VALUE, 0, NULL },
+ { SED_DESC_TYPE_AUDIT, KEY_SET_VALUE, 0, NULL },
+ { SED_DESC_TYPE_AUDIT, KEY_CREATE_SUB_KEY, 0, NULL },
+ { SED_DESC_TYPE_AUDIT, KEY_ENUMERATE_SUB_KEYS, 0, NULL },
+ { SED_DESC_TYPE_AUDIT, KEY_NOTIFY, 0, NULL },
+ { SED_DESC_TYPE_AUDIT, KEY_CREATE_LINK , 0, NULL },
+ { SED_DESC_TYPE_AUDIT, 0x00010000, /* DELETE, */ 0, NULL },
+ { SED_DESC_TYPE_AUDIT, WRITE_DAC, 0, NULL },
+// { SED_DESC_TYPE_AUDIT, WRITE_OWNER, 0, NULL },
+ { SED_DESC_TYPE_AUDIT, READ_CONTROL, 0, NULL }
+ };
+
+
+#define COUNT_KEY_AUDITS_ARRAY ( sizeof( _SedAppAccessKeyAudits ) / sizeof( SED_APPLICATION_ACCESS ) )
+
+
+
+
+
+#define EXPAND_TO_END -1
+#define BRANCH_EXPAND -1
+
+/* Indexes into the mondo bitmap */
+#define BM_IND_APP 0
+#define BM_IND_DOC 1
+#define BM_IND_FIL 2
+#define BM_IND_RO 3
+#define BM_IND_DIRUP 4
+#define BM_IND_CLOSE 5
+#define BM_IND_CLOSEPLUS 6
+#define BM_IND_OPEN 7
+#define BM_IND_OPENPLUS 8
+#define BM_IND_OPENMINUS 9
+#define BM_IND_CLOSEMINUS 10
+#define BM_IND_CLOSEDFS 11
+#define BM_IND_OPENDFS 12
+
+
+#define ENTER(x)
+#define LEAVE(x)
+#define MSG(x)
+
+#define FILES_WIDTH 16
+#define FILES_HEIGHT 16
+
+INT dxText;
+INT dyText;
+INT dyBorder;
+INT dyBorderx2;
+INT dxFrame;
+INT dxFolder;
+INT dyFolder;
+
+
+VOID
+InitGlobs(
+ HDC hdc
+ )
+
+/*++
+
+Routine Description:
+
+ Calculate and set some global (yuck) variables relating to border
+ width, font width, icon height.
+
+Arguments:
+
+ hdc - handle to relevent device context.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ SIZE Size;
+
+ GetTextExtentPoint(hdc, (LPWSTR)L"M", 1, &Size );
+ dxText = ( INT )Size.cx;
+ dyText = ( INT )Size.cy;
+
+ dyBorder = GetSystemMetrics(SM_CYBORDER);
+ dyBorderx2 = dyBorder * 2;
+ dxFrame = GetSystemMetrics(SM_CXFRAME) - dyBorder;
+
+ dxFolder = FILES_WIDTH;
+ dyFolder = FILES_HEIGHT;
+
+ WINDOWS_APPLICATION::LoadBitmaps( );
+}
+
+DEFINE_CONSTRUCTOR( TREE_STRUCTURE_VIEW, WINDOW );
+
+DEFINE_CAST_MEMBER_FUNCTION( TREE_STRUCTURE_VIEW );
+
+
+
+
+BOOLEAN
+TREE_STRUCTURE_VIEW::InitializeSedAppAccessArrays (
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the SED_APPLICATION_ACCESS arrays used in the security editors.
+ This method is called during the initialization of a TREE_STRUCTURE_VIEW
+ object.
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the initialization succeeds.
+ Returns FALSE otherwise.
+
+
+--*/
+
+{
+
+ PWSTRING MsgPermTitle;
+ PWSTR MsgPermTitleString;
+ ULONG Index;
+ DSTRING AuxString;
+
+
+ DebugAssert( COUNT_MSG_ID_KEY_PERM_NAMES == COUNT_KEY_PERMS_ARRAY );
+ DebugAssert( COUNT_MSG_ID_KEY_AUDIT_NAMES == COUNT_KEY_AUDITS_ARRAY );
+
+ if( !AuxString.Initialize( ( LPWSTR )( L"%1" ) ) ) {
+ DebugPrint( "AuxString.Initialize() failed" );
+ return( FALSE );
+ }
+
+
+ //
+ // Initialize PermissionTitle in _SedAppAccessKeyPerms
+ //
+
+ for( Index = 0; Index < COUNT_MSG_ID_KEY_PERM_NAMES; Index++ ) {
+ MsgPermTitle = REGEDIT_BASE_SYSTEM::QueryString( _MsgIdKeyPermNames[ Index ], "" );
+ if( MsgPermTitle == NULL ) {
+ DebugPrintf( "Unable to retrieve MsgPermTitle, Index = %d \n", Index );
+ DebugPrint( "Unable to retrieve MsgPermTitle" );
+ return( FALSE );
+ }
+ MsgPermTitleString = MsgPermTitle->QueryWSTR();
+ FREE( MsgPermTitle );
+ if( MsgPermTitleString == NULL ) {
+ DebugPrintf( "MsgPermTitle->QueryWSTR() failed, Index = %d \n", Index );
+ DebugPrint( "MsgPermTitle->QueryWSTR() failed" );
+ return( FALSE );
+ }
+ _SedAppAccessKeyPerms[ Index ].PermissionTitle = MsgPermTitleString;
+ }
+
+ //
+ // Initialize PermissionTitle in _SedAppAccessKeyAudits
+ //
+
+ for( Index = 0; Index < COUNT_MSG_ID_KEY_AUDIT_NAMES; Index++ ) {
+ MsgPermTitle = REGEDIT_BASE_SYSTEM::QueryString( _MsgIdKeyAuditNames[ Index ], "" );
+ if( MsgPermTitle == NULL ) {
+ DebugPrintf( "Unable to retrieve MsgPermTitle, Index = %d \n", Index );
+ DebugPrint( "Unable to retrieve MsgPermTitle" );
+ return( FALSE );
+ }
+ MsgPermTitleString = MsgPermTitle->QueryWSTR();
+ FREE( MsgPermTitle );
+ if( MsgPermTitleString == NULL ) {
+ DebugPrintf( "MsgPermTitle->QueryWSTR() failed, Index = %d \n", Index );
+ DebugPrint( "MsgPermTitle->QueryWSTR() failed" );
+ return( FALSE );
+ }
+ _SedAppAccessKeyAudits[ Index ].PermissionTitle = MsgPermTitleString;
+ }
+
+ //
+ // Initialize other strings needed by the security editor
+ //
+ _MsgSpecialAccessTitle = REGEDIT_BASE_SYSTEM::QueryString( MSG_SEC_EDITOR_SPECIAL_ACCESS, "" );
+ _MsgObjectTypeName = REGEDIT_BASE_SYSTEM::QueryString( MSG_SEC_EDITOR_REGISTRY_KEY, "" );
+ _MsgHelpFileName = REGEDIT_BASE_SYSTEM::QueryString( MSG_HELP_FILE_NAME, "" );
+ _MsgApplyPermissionToSubKeys =
+ REGEDIT_BASE_SYSTEM::QueryString( MSG_SEC_EDITOR_APPLY_TO_SUBKEYS, "" );
+ _MsgAuditPermissionOfSubKeys =
+ REGEDIT_BASE_SYSTEM::QueryString( MSG_SEC_EDITOR_AUDIT_SUBKEYS, "" );
+ _MsgConfirmApplyToSubKeys =
+ REGEDIT_BASE_SYSTEM::QueryString( MSG_SEC_EDITOR_CONFIRM_APPLY_TO_SUBKEYS, "%W", AuxString.GetWSTR() );
+ _MsgConfirmAuditSubKeys =
+ REGEDIT_BASE_SYSTEM::QueryString( MSG_SEC_EDITOR_CONFIRM_AUDIT_SUBKEYS, "%W", AuxString.GetWSTR() );
+ _MsgDefaultPermissionName =
+ REGEDIT_BASE_SYSTEM::QueryString( MSG_SEC_EDITOR_DEFAULT_PERM_NAME, "" );
+ if( ( _MsgSpecialAccessTitle == NULL ) ||
+ ( _MsgObjectTypeName == NULL ) ||
+ ( _MsgHelpFileName == NULL ) ||
+ ( _MsgApplyPermissionToSubKeys == NULL ) ||
+ ( _MsgAuditPermissionOfSubKeys == NULL ) ||
+ ( _MsgConfirmApplyToSubKeys == NULL ) ||
+ ( _MsgConfirmAuditSubKeys == NULL ) ||
+ ( _MsgDefaultPermissionName == NULL ) ) {
+ DebugPrint( "Unable to retrieve strings" );
+ FREE( _MsgSpecialAccessTitle );
+ FREE( _MsgObjectTypeName );
+ FREE( _MsgHelpFileName );
+ FREE( _MsgApplyPermissionToSubKeys );
+ FREE( _MsgAuditPermissionOfSubKeys );
+ FREE( _MsgConfirmApplyToSubKeys );
+ FREE( _MsgConfirmAuditSubKeys );
+ FREE( _MsgDefaultPermissionName );
+ return( FALSE );
+ }
+ _SedAppAccessInitialized = TRUE;
+ return( TRUE );
+}
+
+
+
+
+BOOLEAN
+TREE_STRUCTURE_VIEW::Initialize (
+ IN HWND ParentHandle,
+ IN PREGEDIT_INTERNAL_REGISTRY IR
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize a TREE_STRUCTURE_VIEW object by registering its window class,
+ creating its window. If each of these is successful, the
+ window is displayed and updated.
+
+Arguments:
+
+ ParentHandle -
+
+ IR -
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the registration and creation operations
+ are successful.
+
+--*/
+
+{
+ HWND hWnd;
+
+ if( Register( )) {
+
+ //
+ // If the window class was succesfully registered attempt to
+ // create the frame window. Note that we pass the 'this' pointer
+ // to the window.
+ //
+
+ _IR = IR;
+ _CurrentNode = (PREGEDIT_NODE)IR->GetRootNode();
+ _HasFocus = FALSE;
+ _MaxWidth = 0;
+
+ //
+ // the treeview is always positioned in the upper left corner
+ // of the RegWin's client area so X and Y should be 0
+ //
+ if(( hWnd = CreateWindow( _WindowClassName, NULL,
+ WS_CHILD | WS_VISIBLE,
+ CW_USEDEFAULT, 0,
+ CW_USEDEFAULT, 0,
+ ParentHandle, (HMENU)1,
+ (HINSTANCE)WINDOWS_APPLICATION::QueryInstance( ),
+ this )) != NULL ) {
+
+ DbgWinAssert( hWnd == _Handle );
+
+ if( !_SedAppAccessInitialized ) {
+ return( InitializeSedAppAccessArrays() );
+ }
+ return TRUE;
+
+ } else {
+
+ //
+ // Creating the window failed.
+ //
+
+ return FALSE;
+ }
+ }
+ return FALSE;
+}
+
+
+VOID
+TREE_STRUCTURE_VIEW::CollapseCurrentItem(
+ )
+
+/*++
+
+Routine Description:
+
+ Remove the descendents of the current node from the tree view
+ window.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Level;
+ INT ItemToDel;
+ PCREGEDIT_NODE CurNode;
+
+ //
+ // check that we've been called on a node that actually has
+ // some children viewable
+ //
+
+ if( !IsItemAfterAChild( _CurrentItem ) ) {
+ return;
+ }
+
+
+ Level = _IR->GetNodeLevel(_CurrentNode);
+
+ // Disable redrawing during updating of list box.
+ //
+ SendMessage( _hwndList, WM_SETREDRAW, FALSE, 0L );
+ _MaxWidth = 0;
+ AdjustHorizontalScrollBar();
+
+ //
+ // move down the list until you find an item with a smaller level (or
+ // equal), removing each item from the listbox as you go
+ //
+ ItemToDel = _CurrentItem + 1;
+ while( ItemToDel < _Items
+ && _IR->GetNodeLevel( CurNode = GetNode( ItemToDel ) ) > Level ) {
+ //
+ // remove from list box
+ //
+
+ SendMessage( _hwndList, LB_DELETESTRING, ItemToDel, 0 );
+ _Items--;
+ }
+ _IR->SetNodeExpansionState( _CurrentNode, FALSE );
+ // Re-enable redrawing and refresh the tree.
+ SendMessage( _hwndList, WM_SETREDRAW, TRUE, 0L );
+ InvalidateRect( _hwndList, NULL, TRUE );
+}
+
+
+VOID
+TREE_STRUCTURE_VIEW::DrawItem(
+ IN LPDRAWITEMSTRUCT lpLBItem
+ )
+
+/*++
+
+Routine Description:
+
+ This routine gets called every time Windows needs to output one line
+ in the list box for the tree view.
+
+Arguments:
+
+ lpLBItem - contains all the information needed to actually draw
+ the data - look in the SDK book, Vol2 for details
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ INT x, y, dx, dy;
+ INT nLevel;
+ HDC hdc;
+ ULONG len;
+ RECT rc;
+ BOOL bDrawSelected, bFocus;
+ PCREGEDIT_NODE pNode;
+ PCREGEDIT_NODE pNTemp;
+ DWORD rgbText;
+ DWORD rgbBackground;
+ HBRUSH hBrush, hOld;
+ INT iBitmap;
+ INT ItemID;
+
+ PWSTR NodeNameString;
+ PCWSTRING NodeName;
+ LONG Width;
+
+ HFONT hFont;
+ HFONT PreviousHFont;
+ SIZE Size;
+
+#if 0
+ DebugPrintf("TREE::DrawItem %s focus.\n", _HasFocus ? "has" : "does not have");
+ DebugPrintf("CtlType = %x\n", lpLBItem->CtlType);
+ DebugPrintf("CtlID = %x\n", lpLBItem->CtlID);
+ DebugPrintf("itemID = %x\n", lpLBItem->itemID);
+ DebugPrintf("itemAction = %x\n", lpLBItem->itemAction);
+ DebugPrintf("itemState = %x\n", lpLBItem->itemState);
+ DebugPrintf("hwndItem = %x\n", lpLBItem->hwndItem);
+ DebugPrintf("hDC = %x\n", lpLBItem->hDC);
+ DebugPrintf("rcItem = (%x, %x)\n", lpLBItem->rcItem.top, lpLBItem->rcItem.left);
+ DebugPrintf("itemData = %x\n\n", lpLBItem->itemData);
+#endif
+
+ //
+ // itemID == -1 means empty list box so let defwndproc draw the dotted
+ // rectangle
+ //
+ if( (ItemID = lpLBItem->itemID) == (WORD)-1) {
+ return;
+ }
+
+ //
+ // extract DC and pointer to node into IR from DRAWITEM struct
+ //
+ hdc = lpLBItem->hDC;
+ pNode = (PCREGEDIT_NODE)lpLBItem->itemData;
+
+
+ PreviousHFont = NULL;
+ if( ( hFont = WINDOWS_APPLICATION::GetCurrentHFont() ) != NULL ) {
+ PreviousHFont = (HFONT)SelectObject( hdc, hFont );
+ if( PreviousHFont != NULL ) {
+ GetTextExtentPoint(hdc, (LPWSTR)L"M", 1, &Size );
+ dxText = ( INT )Size.cx;
+ dyText =( INT ) Size.cy;
+
+ dyBorder = GetSystemMetrics(SM_CYBORDER);
+ dyBorderx2 = dyBorder * 2;
+ dxFrame = GetSystemMetrics(SM_CXFRAME) - dyBorder;
+
+ }
+ }
+
+
+ //
+ // determine length of name (in pixels?)
+ //
+
+
+ if( _IR->GetNodeLevel( pNode ) == 0 ) {
+ //
+ // This is the root node
+ //
+ NodeName = _IR->GetRootName();
+ DebugPtrAssert( NodeName );
+ } else {
+ NodeName = _IR->GetNodeName( pNode );
+ DebugPtrAssert( NodeName );
+ }
+ len = NodeName->QueryChCount();
+ NodeNameString = NodeName->QueryWSTR();
+
+ GetTextExtentPoint(hdc, NodeNameString, (INT)len, &Size );
+ dx = ( INT )Size.cx;
+
+ dx += dyBorder;
+
+ //
+ // determine size of rectangle we can draw in (or what we need?]
+ //
+ rc = lpLBItem->rcItem;
+ rc.left = _IR->GetNodeLevel(pNode) * dxText * 2;
+ rc.right = rc.left + dxFolder + dx + 4 * dyBorderx2;
+
+
+ //
+ // do we have to draw any items?
+ //
+ if (lpLBItem->itemAction & (ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS)) {
+
+ bDrawSelected = (lpLBItem->itemState & ODS_SELECTED);
+ bFocus = (lpLBItem->itemState & ODS_FOCUS);
+
+ //
+ // select the proper background or just a rect
+ // ACTION: look in datavw.cxx for more comments
+ //
+ if (bDrawSelected) {
+ if (bFocus) {
+ rgbBackground = SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
+ if( _IR->IsNodeViewable( pNode ) ) {
+ rgbText = SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
+ } else {
+ rgbText = SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
+ }
+ } else {
+ rgbBackground = SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
+ if( _IR->IsNodeViewable( pNode ) ) {
+ rgbText = SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
+ } else {
+ rgbText = SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
+ }
+ }
+ } else {
+ rgbBackground = SetBkColor(hdc, GetSysColor(COLOR_WINDOW));
+ if( _IR->IsNodeViewable( pNode ) ) {
+ rgbText = SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
+ } else {
+ rgbText = SetTextColor(hdc, GetSysColor(COLOR_GRAYTEXT));
+ }
+ }
+
+
+ //
+ // first draw the preceding branch symbols for this node
+ // - start with the symbol closest to the name then
+ // generate vertical lines if necessary (ie. work
+ // right to left -> from the leaf to the root)
+ //
+ nLevel = ( INT )_IR->GetNodeLevel(pNode);
+
+ x = (nLevel * dxText * 2) - dxText + dyBorderx2;
+ dy = ( INT )(lpLBItem->rcItem.bottom - lpLBItem->rcItem.top);
+ y = ( INT )lpLBItem->rcItem.top + (dy/2);
+
+ if (hBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOWTEXT))) {
+
+ hOld = (HBRUSH)SelectObject(hdc, hBrush);
+
+ if (_IR->GetParent(pNode)) {
+ /* Draw the horizontal line over to the (possible) folder. */
+ PatBlt(hdc, x, y, dyText, dyBorder, PATCOPY);
+
+ /* Draw the top part of the vertical line. */
+ PatBlt(hdc, x, lpLBItem->rcItem.top, dyBorder, dy/2, PATCOPY);
+
+ /* If not the end of a node, draw the bottom part... */
+ if( !_IR->IsLastChild( pNode ) )
+ PatBlt(hdc, x, y+dyBorder, dyBorder, dy/2, PATCOPY);
+
+ /* Draw the verticals on the left connecting other nodes. */
+ pNTemp = _IR->GetParent(pNode);
+ while (pNTemp) {
+ nLevel--;
+ if( !_IR->IsLastChild( pNTemp ) ) {
+ //
+ // this ancestor isn't the last child of it's level
+ // so draw the vertical line
+ PatBlt(hdc, (nLevel * dxText * 2) - dxText + dyBorderx2,
+ lpLBItem->rcItem.top, dyBorder,dy, PATCOPY);
+ }
+ pNTemp = _IR->GetParent(pNTemp);
+ }
+ }
+
+ if (hOld)
+ SelectObject(hdc, hOld);
+
+ DeleteObject(hBrush);
+ }
+
+ //
+ // - we're done drawing the branch symbols
+ // - now determine if we this item is eligible to be drawn in
+ // inverse
+ //
+
+ //
+ // now draw the text
+ //
+ ExtTextOut(hdc, x + dxText + dxFolder + 2 * dyBorderx2,
+ y-(dyText/2), ETO_OPAQUE, &rc,
+ NodeNameString, (INT)len, NULL);
+
+ //
+ // determine the correct folder icon to display
+ //
+ // - decide whether to put an empty folder or +/-
+ //
+
+ if( _IR->IsNodeViewable( pNode ) ) {
+ if( (_IR->GetNumberOfChildren(pNode) == 0) ) {
+ //
+ // no children -> draw an empty folder
+ //
+ iBitmap = (bDrawSelected) ? BM_IND_OPEN : BM_IND_CLOSE;
+ } else {
+
+ //
+ // check if the children are 'viewable' (in the listbox)
+ // - do this by looking at the level of the next item
+ //
+ if( IsItemAfterAChild(ItemID) ) {
+ //
+ // children ARE viewable so display '-' bitmap
+ //
+ iBitmap = (bDrawSelected) ? BM_IND_OPENMINUS : BM_IND_CLOSEMINUS;
+ } else {
+ iBitmap = (bDrawSelected) ? BM_IND_OPENPLUS : BM_IND_CLOSEPLUS;
+ }
+ }
+ } else {
+ iBitmap = BM_IND_CLOSEDFS;
+ }
+
+
+
+ //
+ // actually Blt the bitmap from memory context to client area
+ //
+
+ if( dy >= dyFolder ) {
+ BitBlt(hdc, x + dxText + dyBorder, y-(dyFolder/2), dxFolder, dyFolder,
+ WINDOWS_APPLICATION::GetCompatibleMemoryDeviceContext(), iBitmap * dxFolder, (bFocus && bDrawSelected) ? dyFolder : 0, SRCCOPY);
+
+ } else {
+
+ SetStretchBltMode( hdc, COLORONCOLOR );
+ StretchBlt(hdc, x + dxText + dyBorder, y-dy/2, dxFolder, dyText,
+ WINDOWS_APPLICATION::GetCompatibleMemoryDeviceContext(), iBitmap * dxFolder, (bFocus && bDrawSelected) ? FILES_HEIGHT : 0, FILES_WIDTH, FILES_HEIGHT, SRCCOPY);
+
+ }
+
+
+ // set text color and draw a rect if required
+ // ACTION: look in datavw.cxx for more comments
+
+ if (bDrawSelected) {
+ HBRUSH hbr;
+ if (hbr = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT))) {
+ FrameRect(hdc, &rc, hbr);
+ DeleteObject(hbr);
+ }
+ SetTextColor(hdc, rgbText);
+ SetBkColor(hdc, rgbBackground);
+ }
+ }
+
+ if ((lpLBItem->itemAction & ODA_FOCUS) && (lpLBItem->itemState & ODS_FOCUS)) {
+ DrawFocusRect(hdc, &rc);
+ }
+
+ FREE( NodeNameString );
+
+ if( rc.right > _MaxWidth ) {
+ _MaxWidth = rc.right;
+ AdjustHorizontalScrollBar();
+ }
+
+
+ Width = SendMessage( _hwndList, LB_GETHORIZONTALEXTENT, 0, 0 );
+ if( Width < rc.right ) {
+ SendMessage( _hwndList,
+ LB_SETHORIZONTALEXTENT,
+ (WPARAM)(rc.right+2*dxText),
+ 0 );
+ }
+ if( PreviousHFont != NULL ) {
+
+ SelectObject( hdc, PreviousHFont );
+ }
+ return;
+}
+
+
+VOID
+TREE_STRUCTURE_VIEW::ExpandCurrentItem(
+ IN INT Depth
+ )
+
+/*++
+
+Routine Description:
+
+ Adds descendants of the current item to the list box.
+
+Arguments:
+
+ Depth - determines the number of generations to include
+ in the expansion. 0 means don't add children,
+ 1 means just immediate children, ...
+ A depth of -1 will do a branch (all descendants)
+ expansion.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ HCURSOR Cursor;
+
+ // Disable redrawing.
+ SendMessage( _hwndList, WM_SETREDRAW, FALSE, 0L );
+
+ //
+ // remove from list box
+ //
+ SendMessage( _hwndList, LB_DELETESTRING, _CurrentItem, 0 );
+ if( ( _IR->AreChildrenInMemory( _CurrentNode ) ) &&
+ ( ( UINT )Depth < 2 ) ) {
+ InsertTreeToListBox( _CurrentNode, _CurrentItem, Depth );
+ } else {
+ Cursor = WINDOWS_APPLICATION::DisplayHourGlass();
+ InsertTreeToListBox( _CurrentNode, _CurrentItem, Depth );
+ WINDOWS_APPLICATION::RestoreCursor( Cursor );
+ }
+ _Items = ( INT )SendMessage( _hwndList, LB_GETCOUNT, 0, 0 );
+
+ // Re-enable redrawing and refresh the tree.
+ SendMessage( _hwndList, LB_SETCURSEL, _CurrentItem, 0 );
+ SendMessage( _hwndList, WM_SETREDRAW, TRUE, 0L );
+ InvalidateRect( _hwndList, NULL, TRUE );
+}
+
+
+VOID
+TREE_STRUCTURE_VIEW::InitMenu(
+ IN HMENU Menu,
+ IN INT PopupMenu
+ )
+
+/*++
+
+Routine Description:
+
+ Figures out which items of the pulldown menu which should be enabled
+ or grayed. Windows will generate a WM_INITMENUPOPUP just before a
+ pulldown menu is painted.
+
+ Passes the message along if it can't figure out the status of menu
+ items.
+
+ This routine handles the status of menu items in the Tree pulldown.
+
+Arguments:
+
+ Menu - handle of the main menu
+ PopupMenu - the item number of the pulldown menu. eg.
+ File menu is 0, Edit is 1.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ switch( PopupMenu ) {
+ case VIEW_MENU:
+ EnableMenuItem( Menu, ( UINT )IDM_DISPLAY_BINARY,( UINT )MF_GRAYED );
+ break;
+
+ case TREE_MENU:
+
+ EnableMenuItem( Menu, ( UINT )IDM_EXPAND_ALL, ( UINT )MF_ENABLED );
+
+ if( _IR->GetNumberOfChildren( _CurrentNode ) == 0 ) {
+ //
+ // has no children
+ // - disable all expand/collapse items
+ // - don't bother with EXPAND_ALL because we can't tell
+ // if it's valid or not
+ //
+ EnableMenuItem( Menu, ( UINT )IDM_EXPAND_ONE_LEVEL, ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, ( UINT )IDM_EXPAND_BRANCH, ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, ( UINT )IDM_COLLAPSE_BRANCH, ( UINT )MF_GRAYED );
+
+ } else {
+ //
+ // has children - check their visibility
+ //
+ if( IsItemAfterAChild( _CurrentItem ) ) {
+ //
+ // children *are* viewable (ie. expanded)
+ // - disable expansion items
+ // - enable collapse item
+ //
+ EnableMenuItem( Menu, ( UINT )IDM_EXPAND_ONE_LEVEL, ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, ( UINT )IDM_EXPAND_BRANCH, ( UINT )MF_ENABLED );
+ EnableMenuItem( Menu, ( UINT )IDM_COLLAPSE_BRANCH, ( UINT )MF_ENABLED );
+ } else {
+ //
+ // children *are not* viewable (ie. collapsed)
+ // - enable expansion items
+ // - disable collapse item
+ //
+ EnableMenuItem( Menu, ( UINT )IDM_EXPAND_ONE_LEVEL, ( UINT )MF_ENABLED );
+ EnableMenuItem( Menu, ( UINT )IDM_EXPAND_BRANCH, ( UINT )MF_ENABLED );
+ EnableMenuItem( Menu, ( UINT )IDM_COLLAPSE_BRANCH, ( UINT )MF_GRAYED );
+ }
+ }
+ break;
+
+ case EDIT_MENU:
+
+ if( WINDOWS_APPLICATION::IsReadOnlyModeEnabled() ) {
+ EnableMenuItem( Menu, ( UINT )IDM_ADD_KEY,( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, ( UINT )IDM_ADD_VALUE,( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, ( UINT )IDM_DELETE,( UINT )MF_GRAYED );
+ } else {
+ if( ( _CurrentItem != 0 ) ||
+ ( ( _CurrentItem == 0 ) &&
+ !_IR->IsMasterHive()
+ ) ) {
+ EnableMenuItem( Menu, ( UINT )IDM_ADD_KEY,( UINT )MF_ENABLED );
+ } else {
+ EnableMenuItem( Menu, ( UINT )IDM_ADD_KEY,( UINT )MF_GRAYED );
+ }
+ EnableMenuItem( Menu, ( UINT )IDM_ADD_VALUE,( UINT )MF_ENABLED );
+ if( _Items == 0 ) {
+ EnableMenuItem( Menu, ( UINT )IDM_DELETE,( UINT )MF_GRAYED );
+ } else {
+ EnableMenuItem( Menu, ( UINT )IDM_DELETE,( UINT )MF_ENABLED );
+ }
+ }
+
+ EnableMenuItem( Menu, ( UINT )IDM_BINARY,( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, ( UINT )IDM_STRING, ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, ( UINT )IDM_ULONG, ( UINT )MF_GRAYED );
+ EnableMenuItem( Menu, ( UINT )IDM_MULTISZ, ( UINT )MF_GRAYED );
+ break;
+ }
+}
+
+
+
+VOID
+TREE_STRUCTURE_VIEW::SelectNode(
+ IN PCREGEDIT_NODE Node
+ )
+
+/*++
+
+Routine Description:
+
+ Move the higlight to the line of the listbox that represents the node
+ received as parameter.
+
+
+Arguments:
+
+ Node - New node to be selected.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Index;
+ PCREGEDIT_NODE ParentNode;
+ PCREGEDIT_NODE AuxNode;
+
+
+ DebugPtrAssert( Node );
+
+ //
+ // Find out if the node is in the listbox
+ //
+ Index = SendMessage( _hwndList, LB_FINDSTRING, ( UINT )-1, ( LONG )Node );
+ if( Index == LB_ERR ) {
+ //
+ // The node is not in the listbox.
+ // Mark all ancestors of the Node as 'expanded', and redraw the
+ // tree view.
+ //
+ AuxNode = Node;
+ while( ( ( ParentNode = _IR->GetParent( AuxNode ) ) != NULL ) &&
+ !_IR->IsNodeExpanded( ParentNode ) ) {
+ _IR->SetNodeExpansionState( ParentNode, TRUE );
+ AuxNode = ParentNode;
+ }
+ Index = SendMessage( _hwndList,
+ LB_FINDSTRING,
+ ( UINT )-1,
+ ( LONG )AuxNode );
+
+
+ //
+ // Disable redrawing.
+ //
+ SendMessage( _hwndList, WM_SETREDRAW, FALSE, 0L );
+
+ //
+ // Insert the subtree that contains the desired node as child
+ //
+ SendMessage( _hwndList, LB_DELETESTRING, ( UINT )Index, 0 );
+
+ InsertUpdatedSubTreeToListBox( AuxNode, Index );
+
+ //
+ // Find out the position of the desired node
+ //
+ Index = SendMessage( _hwndList,
+ LB_FINDSTRING,
+ ( UINT )-1,
+ ( LONG )Node );
+
+ if( Index == LB_ERR ) {
+ DebugPrint( "Desired node doesn't exist in the listbox" );
+ }
+ _CurrentItem = (INT)Index;
+
+ //
+ // Find out number of items in the list box
+ //
+
+ _Items = ( INT )SendMessage( _hwndList, LB_GETCOUNT, 0, 0 );
+ _CurrentNode = (PREGEDIT_NODE)Node;
+ //
+ // Re-enable redrawing and refresh the tree.
+ //
+ SendMessage( _hwndList, LB_SETCURSEL, ( UINT )_CurrentItem, 0 );
+ SendMessage( _hwndList, WM_SETREDRAW, ( UINT )TRUE, 0 );
+ InvalidateRect( _hwndList, NULL, TRUE );
+
+ //
+ // Inform parent window to update the data view
+ //
+ SendMessage( GetParent( _Handle), TR_NEWCURSEL, 0, (LONG)_CurrentNode );
+
+ } else {
+ _CurrentItem = (INT)Index;
+ _CurrentNode = (PREGEDIT_NODE)Node;
+ SendMessage( _hwndList, LB_SETCURSEL, ( UINT )_CurrentItem, 0 );
+ //
+ // Inform parent window to update the data view
+ //
+ SendMessage( GetParent( _Handle), TR_NEWCURSEL, 0, (LONG)_CurrentNode );
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+ULONG
+TREE_STRUCTURE_VIEW::InsertUpdatedSubTreeToListBox(
+ IN PCREGEDIT_NODE Root,
+ IN ULONG LineNumber
+ )
+
+/*++
+
+Routine Description:
+
+ Insert the node received as parameter into a specified line of
+ the tree view. If the node is expanded, then it recursively insert
+ the node's children.
+ This method is used to redisplay a tree that had some og its nodes
+ updated.
+
+
+Arguments:
+
+ Root - Root of the sub-tree to insert into listbox
+
+ LineNumber - Line on the listbox where the node is to be inserted
+
+
+Return Value:
+
+ ULONG - The next available line in the listbox.
+
+
+--*/
+
+{
+ PSORTED_LIST Children;
+ PITERATOR Iterator;
+ PCREGEDIT_NODE CurrentChild;
+ ULONG ErrorCode;
+ ULONG NextLine;
+
+
+ DebugPtrAssert( Root );
+
+ //
+ // Insert the node in the listbox
+ //
+ SendMessage( _hwndList, LB_INSERTSTRING, ( UINT )LineNumber, ( LONG )Root );
+
+ NextLine = LineNumber + 1;
+ if( _IR->IsNodeExpanded( Root ) ) {
+ //
+ // If the node is expanded, then insert its children
+ //
+ if( ( ( Children = _IR->GetChildren( Root, &ErrorCode ) ) != NULL ) &&
+ ( ( Iterator = Children->QueryIterator() ) != NULL ) &&
+ ( Children->QueryMemberCount() != 0 ) ) {
+ while( ( CurrentChild = ( PCREGEDIT_NODE )Iterator->GetNext() ) != NULL ) {
+ //
+ // Insert each child
+ //
+ NextLine = InsertUpdatedSubTreeToListBox( CurrentChild, NextLine );
+ }
+ DELETE( Iterator );
+ }
+ }
+ //
+ // Return the next line available in the list box
+ //
+ return( NextLine );
+}
+
+
+
+VOID
+TREE_STRUCTURE_VIEW::RedisplayUpdatedSubTree(
+ IN PCREGEDIT_NODE Root
+ )
+
+/*++
+
+Routine Description:
+
+ Insert an updated subtree in the listbox, starting in its first line.
+ This method is used to redisplay a tree that had some of its nodes
+ updated.
+
+
+Arguments:
+
+ Root - Root of the sub-tree to insert into listbox
+
+
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ LONG Index;
+ LONG TopIndex;
+
+ //
+ // Disable redrawing.
+ //
+ SendMessage( _hwndList, WM_SETREDRAW, FALSE, 0L );
+
+ //
+ // Find out the position of the first visible node
+ //
+
+ TopIndex = SendMessage( _hwndList, LB_GETTOPINDEX, 0, 0 );
+
+ //
+ // Reset the listbox contents
+ //
+ SendMessage( _hwndList, LB_RESETCONTENT, 0, 0 );
+
+ //
+ // Insert the new tree in the listbox
+ //
+ InsertUpdatedSubTreeToListBox( Root, 0 );
+
+ //
+ // Find out number of items in the list box
+ //
+ _Items = ( INT )SendMessage( _hwndList, LB_GETCOUNT, 0, 0 );
+
+ //
+ // Restore the first visible node in the listbox
+ //
+ if( TopIndex != -1 ) {
+ SendMessage( _hwndList, LB_SETTOPINDEX, (UINT)TopIndex, 0 );
+ }
+
+ //
+ // Find out the current item
+ //
+ Index = SendMessage( _hwndList, LB_FINDSTRING, ( UINT )-1, ( LONG )_CurrentNode );
+ if( Index == LB_ERR ) {
+ //
+ // If the previously selected item couldn't be found, select the
+ // item that is located in the line that was previously selected,
+ // or select the last line in the listbox
+ //
+ if( _Items <= _CurrentItem ) {
+ _CurrentItem = _Items - 1;
+ }
+ _CurrentNode =
+ ( PREGEDIT_NODE )SendMessage( _hwndList, LB_GETITEMDATA, ( UINT )_CurrentItem, 0 );
+ } else {
+ _CurrentItem = ( INT )Index;
+ }
+ //
+ // Re-enable redrawing and refresh the tree.
+ //
+ SendMessage( _hwndList, LB_SETCURSEL, ( UINT )_CurrentItem, 0 );
+ SendMessage( _hwndList, WM_SETREDRAW, ( UINT )TRUE, 0 );
+ InvalidateRect( _hwndList, NULL, TRUE );
+
+ //
+ // Inform parent window to update the data view
+ //
+ SendMessage( GetParent( _Handle), TR_NEWCURSEL, 0, (LONG)_CurrentNode );
+
+}
+
+
+
+INT
+TREE_STRUCTURE_VIEW::InsertTreeToListBox(
+ IN PCREGEDIT_NODE root,
+ IN INT InsertPoint,
+ IN INT Depth
+ )
+
+/*++
+
+Routine Description:
+
+ The recursive routine that traverses the IR, inserting nodes into
+ the list box.
+
+Arguments:
+
+ root - root of the sub-tree to insert into listbox
+ InsertPoint - the entry in the list that will be shifted down
+ eg. Insert(node, 2, ...) sets entry #2 to 'node'
+ after shifting all entries >= 2 down.
+ Depth - determines the number of generations to include
+ in the expansion. 0 means don't add children,
+ 1 means just immediate children, ...
+ A depth of -1 will do a branch (all descendants)
+ expansion.
+
+Return Value:
+
+ INT - the next available spot for insertion
+
+--*/
+
+{
+ PCREGEDIT_NODE CurrentChild;
+ PSORTED_LIST Children;
+ PITERATOR Iterator;
+ ULONG ErrorCode;
+
+ //
+ // do traversal in 'prefix' order (adding node - then it's children)
+ //
+ SendMessage( _hwndList, LB_INSERTSTRING, InsertPoint, (LONG)(LPSTR)root );
+ if( InsertPoint != EXPAND_TO_END ) {
+ InsertPoint++;
+ }
+
+ //
+ // we've reached a leaf - start unwinding
+ //
+ if( Depth == 0 ) {
+ return( InsertPoint );
+ } else {
+ _IR->SetNodeExpansionState( root, TRUE );
+ }
+
+ //
+ // loop through children, recursing on each
+ //
+ if( ( Children = _IR->GetChildren( root, &ErrorCode ) ) != NULL ) {
+ Iterator = Children->QueryIterator();
+ while( ( CurrentChild = (PCREGEDIT_NODE)Iterator->GetNext() ) != NULL ) {
+ InsertPoint = InsertTreeToListBox( CurrentChild, InsertPoint,
+ Depth - 1 );
+ }
+ DELETE( Iterator );
+ }
+ return( InsertPoint );
+}
+
+
+
+BOOL
+TREE_STRUCTURE_VIEW::IsItemAfterAChild(
+ IN INT Item
+ )
+
+/*++
+
+Routine Description:
+
+ Takes an item number of the listbox and returns whether the
+ item after it is one of it's descendents.
+
+Arguments:
+
+ Item - item to check
+
+Return Value:
+
+ BOOL - TRUE - there is an item after 'item' and it is 'item's descendent
+ - FALSE - either this is the last item or the item after is
+ not a child
+
+--*/
+
+{
+
+ if( Item + 1 >= _Items ) {
+ return( FALSE );
+ }
+
+ //
+ // if the next item's level is strictly greater than the current
+ // item's level then return true
+ //
+ return( _IR->GetNodeLevel( GetNode( Item + 1 ) ) > _IR->GetNodeLevel( GetNode( Item ) ) );
+}
+
+
+
+BOOL
+TREE_STRUCTURE_VIEW::IsItemAfterSibling(
+ IN INT Item
+ )
+
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+
+
+Return Value:
+
+
+
+--*/
+
+{
+
+ if( Item + 1 >= _Items ) {
+ return( FALSE );
+ }
+
+ //
+ // if the next item's level is the same as the current
+ // item's level then return true
+ //
+ return( _IR->GetNodeLevel( GetNode( Item + 1 ) ) == _IR->GetNodeLevel( GetNode( Item ) ) );
+}
+
+
+
+BOOLEAN
+TREE_STRUCTURE_VIEW::Register (
+ )
+
+/*++
+
+Routine Description:
+
+ If required register the TREE_STRUCTURE_VIEW window class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the TREE_STRUCTURE_VIEW window class is registered.
+
+--*/
+
+{
+ WNDCLASS wndclass;
+
+ if( !_Registered ) {
+ _Registered = TRUE;
+
+ //
+ // If RegEdit is not already running and REGEDIT was not already
+ // registered by this instance, register the REGEDIT window class.
+ //
+
+ wndclass.style = CS_HREDRAW | CS_VREDRAW;
+ wndclass.lpfnWndProc = (WNDPROCFN)TREE_STRUCTURE_VIEW::WndProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = sizeof( DWORD );
+ wndclass.hInstance = (HINSTANCE)WINDOWS_APPLICATION::QueryInstance( );
+ wndclass.hIcon = NULL;
+ wndclass.hCursor = LoadCursor( NULL, IDC_ARROW );
+ wndclass.hbrBackground = (HBRUSH)( COLOR_WINDOW + 1 );
+ wndclass.lpszMenuName = NULL;
+ wndclass.lpszClassName = _WindowClassName;
+
+ RegisterClass( &wndclass );
+ }
+ return TRUE;
+}
+
+
+VOID
+TREE_STRUCTURE_VIEW::ToggleCurrentItem(
+ )
+
+/*++
+
+Routine Description:
+
+
+
+Arguments:
+
+
+
+Return Value:
+
+
+
+--*/
+
+{
+ //
+ // if the current node doesn't have any children then there isn't
+ // anything to toggle so just return
+ //
+ if( _IR->GetNumberOfChildren( _CurrentNode ) == 0 ) {
+ return;
+ }
+
+ if( IsItemAfterAChild( _CurrentItem ) ) {
+ //
+ // the children are in listbox -> collapse node
+ //
+ CollapseCurrentItem();
+ } else {
+ //
+ // the children aren't in listbox -> expand node
+ //
+ ExpandCurrentItem();
+ }
+}
+
+
+
+VOID
+TREE_STRUCTURE_VIEW::ChangeItemHeight(
+ )
+
+/*++
+
+Routine Description:
+
+ Change the height of an item in a list box, to reflect the change in
+ the font size.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ HDC hDC;
+ HFONT hFont;
+ HFONT PreviousHFont;
+ SIZE Size;
+
+
+ hDC = GetDC( _hwndList );
+ hFont = WINDOWS_APPLICATION::GetCurrentHFont();
+ PreviousHFont = (HFONT)SelectObject( hDC, hFont );
+ if( PreviousHFont != NULL ) {
+
+ GetTextExtentPoint(hDC, (LPWSTR)L"M", 1, &Size );
+ dxText = ( INT )Size.cx;
+ dyText = ( INT )Size.cy;
+
+ dyBorder = GetSystemMetrics(SM_CYBORDER);
+ dyBorderx2 = dyBorder * 2;
+ dxFrame = GetSystemMetrics(SM_CXFRAME) - dyBorder;
+ SendMessage( _hwndList, LB_SETITEMHEIGHT, 0, dyText );
+ InvalidateRect( _hwndList, NULL, TRUE );
+
+ SelectObject( hDC, PreviousHFont );
+ }
+ ReleaseDC( _hwndList, hDC );
+}
+
+
+
+
+
+LONG
+APIENTRY
+EXPORT
+TREE_STRUCTURE_VIEW::WndProc (
+ IN HWND hWnd,
+ IN WORD wMessage,
+ IN WPARAM wParam,
+ IN LONG lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Handle all requests made of the TREE_STRUCTURE_VIEW window class.
+
+Arguments:
+
+ Standard Window's exported function signature.
+
+Return Value:
+
+ LONG - Returns 0 if the message was handled.
+
+--*/
+
+{
+ REGISTER PTREE_STRUCTURE_VIEW pTreeView;
+ HDC hdc;
+ RECT rc;
+
+ HCURSOR Cursor;
+ PCREGEDIT_NODE NodeFound;
+ LONG SaveHelpContext;
+ INT TmpItem;
+
+ //
+ // WM_CREATE is handled specially as it is when the connection between
+ // a Window and its associated object is established.
+ //
+
+ if( wMessage == WM_CREATE ) {
+
+ //
+ // Save 'this' to owning WINDOW Class and initialize the _Handle
+ // member data.
+ //
+
+ pTreeView = ( PTREE_STRUCTURE_VIEW )
+ ((( LPCREATESTRUCT ) lParam )->lpCreateParams );
+ SetObjectPointer( hWnd, pTreeView );
+ pTreeView->_Handle = hWnd;
+
+ hdc = GetDC(hWnd);
+ InitGlobs( hdc );
+ ReleaseDC(hWnd, hdc);
+
+ //
+ // find out the size of the client area and make the treeview
+ // it's full size
+ //
+ GetClientRect(hWnd, &rc);
+
+
+
+ pTreeView->_hwndList = CreateWindow((LPWSTR)L"listbox", NULL,
+ WS_CHILD | WS_VISIBLE | LBS_NOTIFY | WS_VSCROLL
+ | WS_HSCROLL | LBS_OWNERDRAWFIXED | WS_BORDER
+ | LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT,
+ CW_USEDEFAULT, 0,
+ CW_USEDEFAULT, 0,
+ hWnd, (HMENU)2,
+ (HINSTANCE)WINDOWS_APPLICATION::QueryInstance( ),
+ NULL);
+
+ pTreeView->ChangeItemHeight();
+
+ pTreeView->InsertTreeToListBox( pTreeView->_CurrentNode, EXPAND_TO_END,
+ 1 );
+ pTreeView->_Items = ( INT )SendMessage( pTreeView->_hwndList, LB_GETCOUNT, 0, 0 );
+ SendMessage( pTreeView->_hwndList, LB_SETCURSEL, 0, 0 );
+ pTreeView->_CurrentItem = (INT)SendMessage( pTreeView->_hwndList,
+ LB_GETCURSEL, 0, 0L);
+ return 0;
+ }
+
+ //
+ // Retrieve 'this' pointer.
+ //
+
+ pTreeView = ( PTREE_STRUCTURE_VIEW ) GetObjectPointer( hWnd );
+
+ //
+ // This 'if' clause is for all messages after WM_CREATE.
+ //
+
+ if( pTreeView != NULL ) {
+
+ //
+ // Check the 'this' wasn't trampled.
+ //
+
+ DbgWinAssert( hWnd == pTreeView->_Handle );
+
+ switch( wMessage ) {
+ case WM_DRAWITEM:
+ pTreeView->DrawItem( (LPDRAWITEMSTRUCT)lParam );
+ break;
+
+ case LOAD_HIVE:
+
+ SaveHelpContext = WINDOWS_APPLICATION::GetHelpContext();
+ WINDOWS_APPLICATION::SetHelpContext( IDH_DB_LOADHIVE_KEYNAME_REGED );
+ pTreeView->ProcessLoadHiveMessage( ( PCWSTRING )wParam );
+ WINDOWS_APPLICATION::SetHelpContext( SaveHelpContext );
+ break;
+
+
+ case UNLOAD_HIVE:
+ Cursor = WINDOWS_APPLICATION::DisplayHourGlass();
+ pTreeView->ProcessUnLoadHiveMessage( );
+ WINDOWS_APPLICATION::RestoreCursor( Cursor );
+ break;
+
+ case SAVE_KEY:
+
+ pTreeView->ProcessSaveKeyMessage( ( PCWSTRING )wParam );
+ break;
+
+
+ case RESTORE_KEY:
+ case RESTORE_KEY_VOLATILE:
+
+ pTreeView->ProcessRestoreKeyMessage( ( PCWSTRING )wParam,
+ ( wMessage == RESTORE_KEY_VOLATILE )?
+ TRUE : FALSE );
+ break;
+
+ case WM_SETFOCUS:
+ pTreeView->_HasFocus = TRUE;
+ SetFocus(pTreeView->_hwndList);
+ SendMessage(GetParent(hWnd), TREE_VIEW_FOCUS, 0, 0);
+ break;
+
+ case REFRESH_WINDOW:
+ Cursor = WINDOWS_APPLICATION::DisplayHourGlass();
+ pTreeView->_IR->UpdateSubTree( ( PREGEDIT_NODE )( pTreeView->_IR->GetRootNode() ) );
+ pTreeView->RedisplayUpdatedSubTree( ( PCREGEDIT_NODE )( pTreeView->_IR->GetRootNode() ) );
+ WINDOWS_APPLICATION::RestoreCursor( Cursor );
+ break;
+
+
+
+ case FIND_KEY:
+
+ Cursor = WINDOWS_APPLICATION::DisplayHourGlass();
+ NodeFound =
+ pTreeView->_IR->FindNode( ( PCWSTRING )wParam,
+ pTreeView->_CurrentNode,
+ ( lParam & FR_DOWN )?
+ TRUE : FALSE,
+ ( lParam & FR_MATCHCASE )?
+ TRUE : FALSE,
+ ( lParam & FR_WHOLEWORD )?
+ TRUE : FALSE );
+
+ if( NodeFound != NULL ) {
+ pTreeView->SelectNode( NodeFound );
+
+ WINDOWS_APPLICATION::RestoreCursor( Cursor );
+ } else {
+ WINDOWS_APPLICATION::RestoreCursor( Cursor );
+
+ DisplayInfoPopup( ( WINDOWS_APPLICATION::_hDlgFindReplace )?
+ WINDOWS_APPLICATION::_hDlgFindReplace : pTreeView->_hwndList,
+ MSG_CANT_FIND_KEY,
+ MSG_WARNING_TITLE);
+
+ }
+ break;
+
+ case WM_SIZE:
+ if( !IsIconic(GetParent(hWnd))) {
+ INT iMax;
+
+ // size the window so it's left and bottom border fall outside
+ // it's parent and are thus clipped. this give the nice
+ // tight fitting scrollbar effect
+
+ //
+ // if we are maximized than we need to increase the height of
+ // the list box by two pixels so the top and bottom border
+ // won't show
+ // otherwise, increase by one pixel so top border won't show
+ //
+
+ MoveWindow(pTreeView->_hwndList, -1, -1, LOWORD(lParam)+1, HIWORD(lParam)+2, TRUE);
+
+ iMax = (INT)SendMessage(pTreeView->_hwndList, LB_GETCURSEL, 0, 0L);
+ if (iMax >= 0) {
+ RECT rc;
+ INT top, bottom;
+
+ GetClientRect(pTreeView->_hwndList, &rc);
+ top = (INT)SendMessage(pTreeView->_hwndList, LB_GETTOPINDEX, 0, 0L);
+
+ bottom = INT( top + rc.bottom / dyFolder );
+ if (iMax < top || iMax > bottom)
+ SendMessage(pTreeView->_hwndList, LB_SETTOPINDEX, iMax - ((bottom - top) / 2), 0L);
+ }
+ }
+ break;
+
+ case INFORM_CHANGE_FONT:
+ pTreeView->ChangeItemHeight();
+ break;
+
+
+ case WM_LBTRACKPOINT:
+ {
+ INT dx;
+ INT i;
+ INT len;
+ HFONT hFont;
+ HFONT PreviousHFont;
+ SIZE Size;
+
+ PCREGEDIT_NODE Node;
+ PCWSTRING NodeName;
+ PWSTR String;
+
+
+ // wParam is the listbox index that we are over
+ // lParam is the mouse point
+
+ // Return 0 to do nothing,
+ // 1 to abort everything, or
+ // 2 to abort just dblclicks.
+
+
+ /* Get the node they clicked on. */
+ SendMessage(pTreeView->_hwndList, LB_GETTEXT, wParam, (LONG)&Node);
+
+ // too FAR to the right?
+
+
+ dx = ( INT )pTreeView->_IR->GetNodeLevel(Node) * dxText * 2;
+ i = LOWORD(lParam);
+
+ if( i < dx ) {
+ return 2;
+ }
+
+ hdc = GetDC(pTreeView->_hwndList);
+
+ PreviousHFont = NULL;
+ if( ( hFont = WINDOWS_APPLICATION::GetCurrentHFont() ) != NULL ) {
+ PreviousHFont = (HFONT)SelectObject( hdc, hFont );
+ }
+
+ if( pTreeView->_IR->GetNodeLevel( Node ) == 0 ) {
+ //
+ // This is the root node
+ //
+ NodeName = pTreeView->_IR->GetRootName();
+ DebugPtrAssert( NodeName );
+ } else {
+ NodeName = pTreeView->_IR->GetNodeName( Node );
+ DebugPtrAssert( NodeName );
+ }
+ len = ( INT )NodeName->QueryChCount();
+ String = NodeName->QueryWSTR();
+
+ GetTextExtentPoint(hdc, String, (INT)len, &Size );
+
+ FREE( String );
+ if( PreviousHFont != NULL ) {
+
+ SelectObject( hdc, PreviousHFont );
+ }
+ ReleaseDC(pTreeView->_hwndList, hdc);
+
+ dx = (INT)( pTreeView->_IR->GetNodeLevel(Node) * dxText * 2 ) +
+ (INT)( dxFolder + 4 * dyBorderx2 ) +
+ ( INT )Size.cx;
+
+ if( i > dx ) {
+ return 2;
+ }
+ return DefWindowProc( hWnd, wMessage, wParam, lParam );
+ }
+
+
+ case WM_COMMAND:
+ {
+
+ if( HWND( lParam ) == 0 ) {
+ //
+ // this is a menu item command from above
+ //
+
+ switch( LOWORD( wParam ) ) {
+ case IDM_EXPAND_ONE_LEVEL:
+ pTreeView->ExpandCurrentItem();
+ break;
+
+ case IDM_EXPAND_BRANCH:
+ pTreeView->CollapseCurrentItem();
+ pTreeView->ExpandCurrentItem( -1 );
+ break;
+
+ case IDM_EXPAND_ALL:
+ pTreeView->_CurrentItem = 0;
+ pTreeView->_CurrentNode
+ = (PREGEDIT_NODE) pTreeView->GetNode( pTreeView->_CurrentItem );
+ pTreeView->CollapseCurrentItem();
+ pTreeView->ExpandCurrentItem( -1 );
+ break;
+
+ case IDM_COLLAPSE_BRANCH:
+ pTreeView->CollapseCurrentItem();
+ break;
+
+ case ID_ENTER_KEY:
+ pTreeView->ToggleCurrentItem();
+ break;
+
+ case IDM_DELETE:
+
+ if( !WINDOWS_APPLICATION::IsReadOnlyModeEnabled() ) {
+ pTreeView->DeleteCurrentItem();
+ }
+ break;
+
+ case IDM_INSERT:
+ case IDM_ADD_KEY:
+
+ if( !WINDOWS_APPLICATION::IsReadOnlyModeEnabled() &&
+ ( ( pTreeView->_CurrentItem != 0 ) ||
+ ( ( pTreeView->_CurrentItem == 0 ) &&
+ !pTreeView->_IR->IsMasterHive()
+ )
+ )
+ ) {
+ SaveHelpContext = WINDOWS_APPLICATION::GetHelpContext();
+ WINDOWS_APPLICATION::SetHelpContext( IDH_DB_ADDKEY_REGED );
+ pTreeView->AddNode();
+ WINDOWS_APPLICATION::SetHelpContext( SaveHelpContext );
+ }
+ break;
+
+ case IDM_PERMISSIONS:
+
+ pTreeView->InvokeSecurityEditor( TRUE );
+ break;
+
+ case IDM_AUDITING:
+
+ pTreeView->InvokeSecurityEditor( FALSE );
+ break;
+
+
+ case IDM_OWNER:
+
+ pTreeView->InvokeTakeOwnershipEditor();
+ break;
+
+ case IDM_REFRESH:
+
+ Cursor = WINDOWS_APPLICATION::DisplayHourGlass();
+ pTreeView->_IR->UpdateSubTree( ( PREGEDIT_NODE )( pTreeView->_IR->GetRootNode() ) );
+ pTreeView->RedisplayUpdatedSubTree( ( PCREGEDIT_NODE )( pTreeView->_IR->GetRootNode() ) );
+ WINDOWS_APPLICATION::RestoreCursor( Cursor );
+ break;
+
+
+ default:
+ return DefWindowProc( hWnd, wMessage, wParam, lParam );
+ }
+ } else {
+ //
+ // this is a notify from a child control (ie. the list box)
+ // so switch on the notification code
+ //
+ switch (HIWORD( wParam ) ) {
+ case LBN_DBLCLK:
+ pTreeView->ToggleCurrentItem();
+ break;
+
+ case LBN_SELCHANGE:
+ if( ( TmpItem = (INT)SendMessage( pTreeView->_hwndList,
+ LB_GETCURSEL, 0, 0L ) ) != LB_ERR ) {
+ if( TmpItem == pTreeView->_CurrentItem ) {
+ //
+ // If user clicked on the currently selected key
+ // then move the focus to the tree view.
+ // This ensures that if there is a value entry
+ // selected on the data view, the selection on be lost.
+ //
+ SetFocus( pTreeView->_Handle );
+ } else {
+ pTreeView->_CurrentItem = TmpItem;
+ pTreeView->_CurrentNode
+ = (PREGEDIT_NODE)pTreeView->GetNode( pTreeView->_CurrentItem );
+ SendMessage( GetParent( pTreeView->_Handle), TR_NEWCURSEL, 0,
+ (LONG)pTreeView->_CurrentNode );
+ }
+ }
+ break;
+
+ case LBN_SETFOCUS:
+ SendMessage(GetParent(hWnd), TREE_VIEW_FOCUS, 0, 0);
+ pTreeView->_HasFocus = TRUE;
+ break;
+
+ case LBN_KILLFOCUS:
+ pTreeView->_HasFocus = FALSE;
+ break;
+
+ default:
+
+ //
+ // Let Windows handle this message.
+ //
+
+ return DefWindowProc( hWnd, wMessage, wParam, lParam );
+
+ } // end switch on cmd
+ } // end if
+ } // end case
+ break;
+
+ case WM_CHARTOITEM:
+ {
+ LONG cItems;
+ LONG i, j;
+ WCHAR ch;
+ WCHAR szB[2];
+ PCREGEDIT_NODE Node;
+ WCHAR w[2];
+
+ cItems = pTreeView->_Items;
+
+ i = ( LONG )SendMessage( pTreeView->_hwndList, LB_GETCURSEL, 0, 0 );
+ if( i == LB_ERR ) {
+ i = 0;
+ }
+
+ ch = LOWORD( wParam );
+ if ( ( cItems == 0 ) ||
+ ( ch <= ( WCHAR )' ' ) ) // filter all other control chars
+ return -2L;
+
+ szB[1] = ( WCHAR )'\0';
+
+ for ( j = 1; j <= cItems; j++ ) {
+ SendMessage( pTreeView->_hwndList, LB_GETTEXT, ( i+j ) % cItems, ( LONG )&Node);
+ if( ( pTreeView->_IR )->GetNodeLevel( Node ) == 0 ) {
+ //
+ // This is the root node
+ //
+ szB[0] = *( ( ( pTreeView->_IR )->GetRootName() )->GetWSTR() );
+ } else {
+ szB[0] = *( ( ( pTreeView->_IR )->GetNodeName( Node ) )->GetWSTR() );
+ }
+
+ /* Do it this way to be case insensitive. */
+ w[0] = ch;
+ w[1] = ( WCHAR )'\0';
+ if (!_wcsicmp( w, szB))
+ break;
+ }
+
+ if (j == cItems+1)
+ return -2L;
+
+ SendMessage( pTreeView->_hwndList, LB_SETTOPINDEX, (i+j) % cItems, 0L);
+ return((i+j) % cItems);
+ }
+
+ default:
+ //
+ // Let Windows handle this message.
+ //
+
+ return DefWindowProc( hWnd, wMessage, wParam, lParam );
+ }
+
+ } else {
+
+ //
+ // No 'this' pointer (pTreeView == NULL). Handle messages before
+ // WM_CREATE.
+ //
+ // Let Windows handle the message.
+ //
+
+ return DefWindowProc( hWnd, wMessage, wParam, lParam );
+ }
+
+ //
+ // Message handled...
+ //
+
+ return 0 ;
+}
+
+
+
+BOOLEAN
+TREE_STRUCTURE_VIEW::DeleteCurrentItem(
+ )
+
+/*++
+
+Routine Description:
+
+ Delete from the registry the node currently selected
+ in the tree view.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns TRUE if the operation succeeded.
+
+
+--*/
+
+{
+ ULONG ErrorCode;
+ BOOLEAN Status;
+ HCURSOR Cursor;
+ LONG TopIndex;
+ INT TextMessage;
+ INT CaptionMessage;
+
+ DbgWinAssert( _HasFocus );
+ DbgWinAssert( _Items == SendMessage( _hwndList, LB_GETCOUNT, 0, 0 ) );
+ DbgWinAssert( _CurrentItem == SendMessage( _hwndList, LB_GETCURSEL, 0, 0 ) );
+ DbgWinAssert( _CurrentNode == (PCREGEDIT_NODE)SendMessage( _hwndList, LB_GETITEMDATA, _CurrentItem, 0 ) );
+ DbgWinPtrAssert( _IR );
+ DbgWinPtrAssert( _CurrentNode );
+
+ if( _Items >= 1 ) {
+ //
+ // The tree view has at least one item
+ //
+
+ if( ( WINDOWS_APPLICATION::IsConfirmOnDeleteEnabled() &&
+ ( DisplayConfirmPopup( _hwndList,
+ MSG_DELETE_KEY_CONFIRM_EX,
+ MSG_WARNING_TITLE ) == IDYES ) ) ||
+ ( !WINDOWS_APPLICATION::IsConfirmOnDeleteEnabled() ) ) {
+
+ //
+ // Collapse the current node before deletion
+ //
+ if( IsItemAfterAChild( _CurrentItem ) ) {
+ CollapseCurrentItem();
+ }
+ Cursor = WINDOWS_APPLICATION::DisplayHourGlass();
+ Status = _IR->DeleteNode( (PREGEDIT_NODE)_CurrentNode, &ErrorCode );
+ WINDOWS_APPLICATION::RestoreCursor( Cursor );
+ if( Status ) {
+ _MaxWidth = 0;
+
+ TopIndex = SendMessage( _hwndList, LB_GETTOPINDEX, 0, 0 );
+ _Items--;
+ SendMessage( _hwndList, LB_DELETESTRING, _CurrentItem, 0 );
+
+
+ //
+ // If the listbox still contains items, then put the selection
+ // on the appropriate item
+ //
+ if( ( _Items > 0 ) ) {
+
+ //
+ // If the last item was deleted, then make the current
+ // last item the current selected item
+ //
+ if( _CurrentItem == _Items ) {
+ _CurrentItem--;
+ }
+ if( TopIndex != -1 ) {
+ SendMessage( _hwndList, LB_SETTOPINDEX, (UINT)TopIndex, 0 );
+ }
+ SendMessage( _hwndList, LB_SETCURSEL, _CurrentItem, 0 );
+ }
+
+
+ _CurrentNode = GetNode( _CurrentItem );
+ SendMessage( GetParent( _Handle), TR_NEWCURSEL, 0, (LONG)_CurrentNode );
+
+
+
+ // Re-enable redrawing and refresh the tree.
+ SendMessage( _hwndList, WM_SETREDRAW, TRUE, 0L );
+ InvalidateRect( _hwndList, NULL, TRUE );
+ } else {
+ if (ErrorCode == REGEDIT_ERROR_ACCESS_DENIED) {
+ TextMessage = MSG_DELETE_KEY_ACCESS_DENIED_EX;
+ CaptionMessage = MSG_ACCESS_DENIED;
+ } else if( ErrorCode == REGEDIT_ERROR_NODE_NOT_FOUND ) {
+ TextMessage = MSG_DELETE_KEY_KEY_NOT_ACCESSIBLE_EX;
+ CaptionMessage = MSG_KEY_NOT_ACCESSIBLE;
+ } else if( ErrorCode == REGEDIT_ERROR_KEY_DELETED ) {
+ TextMessage = MSG_DELETE_KEY_KEY_DELETED_EX;
+ CaptionMessage = MSG_KEY_MARKED_FOR_DELETION;
+ } else if( ErrorCode == REGEDIT_RPC_S_SERVER_UNAVAILABLE ) {
+ TextMessage = MSG_CANT_ACCESS_REMOTE_REGISTRY;
+ CaptionMessage = MSG_SERVER_UNAVAILABLE;
+ } else {
+ DebugPrint( "Unknown error code" );
+ DebugPrintf( "ErrorCode = %d \n", ErrorCode );
+ TextMessage = MSG_FAILED_OPERATION_EX;
+ CaptionMessage = 0;
+ }
+ DisplayInfoPopup(_hwndList,
+ TextMessage,
+ CaptionMessage);
+
+ return( FALSE );
+ }
+ }
+ }
+ return( TRUE );
+}
+
+
+
+
+BOOLEAN
+TREE_STRUCTURE_VIEW::AddNode(
+ )
+
+/*++
+
+Routine Description:
+
+ Display a dialog that allows the user to add a key to the registry.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+
+ Returns TRUE if the operation succeeded.
+
+
+--*/
+
+
+
+{
+ BOOLEAN AddNodeFlag;
+ PREGISTRY_KEY_INFO NewKeyInfo;
+ PCREGEDIT_NODE NewNode;
+ ULONG ErrorCode;
+ ADD_NODE_DIALOG_INFO AddNodeInfo;
+ DSTRING CompleteParentName;
+ HCURSOR CurrentCursor;
+ BOOLEAN Status;
+ INT TextMessage;
+ INT CaptionMessage;
+
+
+
+ if( !_IR->QueryCompleteNodeName( _CurrentNode, &CompleteParentName ) ) {
+ DebugPrint( "_IR->QueryCompleteNodeName() failed" );
+ return( FALSE );
+ }
+
+
+ AddNodeFlag = TRUE;
+ while( AddNodeFlag ) {
+ AddNodeInfo.Name = NULL;
+ AddNodeInfo.Title = NULL;
+ AddNodeInfo.Class = NULL;
+ AddNodeInfo.ClassDisplayed = TRUE;
+ AddNodeInfo.VolatileKey = FALSE;
+ if( DialogBoxParam( (HINSTANCE)WINDOWS_APPLICATION::QueryInstance( ),
+ MAKEINTRESOURCE(ADD_KEY_DLG),
+ _Handle,
+ ( DLGPROC )TREE_STRUCTURE_VIEW::GetKeyNameDialogProc,
+ ( DWORD )&AddNodeInfo ) == -1 ) {
+ DebugPrint( "Unable to create dialog box" );
+ return( FALSE );
+ }
+ if( ( AddNodeInfo.Name != NULL ) &&
+ ( AddNodeInfo.Class != NULL ) ) {
+ if( _IR->DoesChildNodeExist( _CurrentNode,
+ AddNodeInfo.Name,
+ &ErrorCode ) ) {
+ DisplayWarningPopup( _Handle,
+ MSG_ADD_KEY_ALREADY_EXISTS_EX );
+
+ DELETE( AddNodeInfo.Name );
+ DELETE( AddNodeInfo.Class );
+
+ } else {
+ NewKeyInfo = ( PREGISTRY_KEY_INFO )NEW( REGISTRY_KEY_INFO );
+ DebugPtrAssert( NewKeyInfo );
+
+ if( !NewKeyInfo->Initialize( AddNodeInfo.Name,
+ &CompleteParentName,
+ 0, // TitleIndex
+ AddNodeInfo.Class ) ) {
+ DebugPrint( "NewKeyInfo->Initialize() failed" );
+ DELETE( AddNodeInfo.Name );
+ DELETE( AddNodeInfo.Title );
+ DELETE( AddNodeInfo.Class );
+ return( FALSE );
+ }
+ DELETE( AddNodeInfo.Name );
+ DELETE( AddNodeInfo.Title );
+ DELETE( AddNodeInfo.Class );
+
+ CurrentCursor = WINDOWS_APPLICATION::DisplayHourGlass();
+ Status = _IR->CreateChildNode( _CurrentNode, NewKeyInfo, &NewNode, &ErrorCode, AddNodeInfo.VolatileKey );
+ WINDOWS_APPLICATION::RestoreCursor( CurrentCursor );
+ if( !Status ) {
+ if (ErrorCode == REGEDIT_ERROR_ACCESS_DENIED) {
+ TextMessage = MSG_ADD_KEY_ACCESS_DENIED_EX;
+ CaptionMessage = MSG_ACCESS_DENIED;
+ } else if( ErrorCode == REGEDIT_ERROR_KEY_DELETED ) {
+ TextMessage = MSG_ADD_KEY_KEY_DELETED_EX;
+ CaptionMessage = MSG_KEY_MARKED_FOR_DELETION;
+ } else if( ErrorCode == REGEDIT_ERROR_NODE_NOT_FOUND ) {
+ CaptionMessage = MSG_KEY_NOT_ACCESSIBLE;
+ TextMessage = MSG_ADD_KEY_KEY_NOT_ACCESSIBLE_EX;
+ } else if( ErrorCode == REGEDIT_RPC_S_SERVER_UNAVAILABLE ) {
+ TextMessage = MSG_CANT_ACCESS_REMOTE_REGISTRY;
+ CaptionMessage = MSG_SERVER_UNAVAILABLE;
+ } else if( ErrorCode == REGEDIT_ERROR_CHILD_MUST_BE_VOLATILE ) {
+ TextMessage = MSG_ADD_KEY_VOLATILE_EX;
+ CaptionMessage = MSG_KEY_VOLATILE;
+ } else {
+ DebugPrint( "Unknown error code" );
+ DebugPrintf( "ErrorCode = %d \n", ErrorCode );
+ TextMessage = MSG_FAILED_OPERATION_EX;
+ CaptionMessage = 0;
+ }
+ DisplayInfoPopup(_hwndList,
+ TextMessage,
+ CaptionMessage);
+
+ return( FALSE );
+ }
+ if( IsItemAfterAChild( _CurrentItem ) ) {
+ // Disable redrawing.
+ SendMessage( _hwndList, WM_SETREDRAW, FALSE, 0L );
+
+ do {
+ SendMessage( _hwndList, LB_DELETESTRING, _CurrentItem + 1, 0 );
+ _Items--;
+ } while( IsItemAfterAChild( _CurrentItem ) );
+ SendMessage( _hwndList, LB_DELETESTRING, ( UINT )_CurrentItem, 0 );
+ _Items--;
+ InsertUpdatedSubTreeToListBox( _CurrentNode, _CurrentItem );
+ _Items = ( INT )SendMessage( _hwndList, LB_GETCOUNT, 0, 0 );
+ // Re-enable redrawing and refresh the tree.
+ SendMessage( _hwndList, LB_SETCURSEL, _CurrentItem, 0 );
+ SendMessage( _hwndList, WM_SETREDRAW, TRUE, 0L );
+ InvalidateRect( _hwndList, NULL, TRUE );
+
+
+// InsertTreeToListBox( NewNode, _CurrentItem+1, 0 );
+// _Items++;
+ } else {
+ ExpandCurrentItem( 1 );
+ }
+ AddNodeFlag = FALSE;
+ }
+ } else {
+ AddNodeFlag = FALSE;
+ }
+ }
+ return( TRUE );
+}
+
+
+
+
+DWORD
+SedCallBack(
+ HWND hwndParent,
+ HANDLE hInstance,
+ ULONG CallBackContext,
+ PSECURITY_DESCRIPTOR SecDesc,
+ PSECURITY_DESCRIPTOR SecDescNewObjects,
+ BOOLEAN ApplyToSubContainers,
+ BOOLEAN ApplyToSubObjects,
+ LPDWORD StatusReturn )
+
+/*++
+
+Routine Description:
+
+ This is a plain "C" function called by the security editor to save
+ the security descriptor of a registry key.
+
+
+Arguments:
+
+ hwndParent - Parent window handle to use for message boxes or subsequent
+ dialogs.
+ This parameter is not used.
+
+
+ hInstance - Instance handle suitable for retrieving resources from the
+ applications .exe or .dll.
+ This parameter is not used.
+
+
+ CallbackContext - This is the value passed as the CallbackContext argument
+ to the SedDiscretionaryAclEditor() or SedSystemAclEditor
+ api when the graphical editor was invoked.
+
+ SecDesc - This parameter points to a security descriptor
+ that should be applied to this object/container and optionally
+ sub-containers if the user selects the apply to tree option.
+
+ SecDescNewObjects - This parameter is used only when operating on a
+ resource that is a container and supports new
+ objects (for example, directories). If the user
+ chooses the apply to tree option, then this security
+ descriptor will have all of the "New Object" permission
+ ACEs contained in the primary container and the
+ inherit bits will be set appropriately.
+ This parameter is not used.
+
+
+ ApplyToSubContainers - When TRUE, indicates that Dacl/Sacl is to be applied
+ to sub-containers of the target container as well
+ as the target container.
+ This will only be TRUE if the target object is a
+ container object.
+ This parameter is not used.
+
+ ApplyToSubObjects - When TRUE, indicates the Dacl/Sacl is to be applied to
+ sub-objects of the target object. This will only be
+ TRUE if the target object is a container object and
+ supports new objects.
+ The SecDescNewObjects should be used for applying the
+ permissions in this instance.
+ This parameter is not used.
+
+
+ StatusReturn - This status flag indicates what condition the
+ resources permissions were left in after an error occurred.
+
+ SED_STATUS_MODIFIED - This (success) status code indicates
+ the protection has successfully
+ been modified.
+
+ SED_STATUS_NOT_ALL_MODIFIED - This (warning) status code
+ indicates an attempt to
+ modify the resource
+ permissions has only partially
+ succeeded.
+
+ SED_STATUS_FAILED_TO_MODIFY - This (error) status code
+ indicates an attempt to modify
+ the permissions has failed
+ completely.
+
+
+
+Return Value:
+
+
+ Returns TRUE if the operation succeeded.
+
+
+--*/
+
+
+{
+ PTREE_STRUCTURE_VIEW Pointer;
+ SECURITY_INFORMATION SecurityInformation;
+
+ hwndParent = hwndParent;
+ hInstance = hInstance;
+
+ if( WINDOWS_APPLICATION::IsReadOnlyModeEnabled() ) {
+ return( 0 );
+ }
+ Pointer = ( ( PCALLBACK_CONTEXT )CallBackContext )->ThisPointer;
+ SecurityInformation = ( ( PCALLBACK_CONTEXT )CallBackContext )->SecurityInfo;
+
+ Pointer->SetSecurityDescriptor( hwndParent,
+ ( ULONG )SecurityInformation,
+ SecDesc,
+ SecDescNewObjects,
+ ApplyToSubContainers,
+ ApplyToSubObjects,
+ StatusReturn );
+ return( 0 );
+}
+
+
+
+
+DWORD
+TREE_STRUCTURE_VIEW::SetSecurityDescriptor(
+ IN HWND hwndParent,
+ IN ULONG CallBackContext,
+ IN PSECURITY_DESCRIPTOR SecDesc,
+ IN PSECURITY_DESCRIPTOR SecDescNewObjects,
+ IN BOOLEAN ApplyToSubContainers,
+ IN BOOLEAN ApplyToSubObjects,
+ IN LPDWORD StatusReturn )
+
+/*++
+
+Routine Description:
+
+
+
+ Invoke a method in the REGEDIT_INTERNAL_REGISTRY_OBJECT to set the
+ new security descriptor of a key.
+
+
+Arguments:
+
+ hwndParent - Parent window handle to use for message boxes or subsequent
+ dialogs.
+
+ CallBackContext - Indicates the type of security descriptor that is being
+ applied to a key.
+
+ SecDesc - This parameter points to a security descriptor
+ that should be applied to this object/container and optionally
+ sub-containers if the user selects the apply to tree option.
+
+
+ SecDescNewObjects - Not used.
+
+ ApplyToSubContainers - Not used.
+
+ ApplyToSubObjects - Not used.
+
+ StatusReturn
+
+
+
+Return Value:
+
+ None.
+--*/
+
+
+{
+ ULONG ErrorCode;
+ INT TextMessage;
+ INT CaptionMessage;
+
+
+ SecDescNewObjects = SecDescNewObjects;
+ ApplyToSubObjects = ApplyToSubObjects;
+
+ if ( !_IR->SetNodeSecurity( _CurrentNode,
+ CallBackContext,
+ SecDesc,
+ &ErrorCode,
+ ApplyToSubContainers ) ) {
+ DebugPrint( "SetKeySecurity() failed" );
+ //
+ // Display error message indicating that the operation failed
+ //
+
+
+ if (ErrorCode == REGEDIT_ERROR_ACCESS_DENIED) {
+ CaptionMessage = MSG_ACCESS_DENIED;
+ if( ApplyToSubContainers ) {
+ TextMessage = MSG_SET_SECURITY_ACCESS_DENIED_RECURSIVE_EX;
+ } else {
+ TextMessage = MSG_SET_SECURITY_ACCESS_DENIED_EX;
+ }
+ } else if( ErrorCode == REGEDIT_ERROR_KEY_DELETED ) {
+ CaptionMessage = MSG_KEY_MARKED_FOR_DELETION;
+ if( ApplyToSubContainers ) {
+ TextMessage = MSG_SET_SECURITY_KEY_DELETED_RECURSIVE_EX;
+ } else {
+ TextMessage = MSG_SET_SECURITY_KEY_DELETED_EX;
+ }
+ } else if( ErrorCode == REGEDIT_ERROR_NODE_NOT_FOUND ) {
+ CaptionMessage = MSG_KEY_NOT_ACCESSIBLE;
+ if( ApplyToSubContainers ) {
+ TextMessage = MSG_SET_SECURITY_KEY_NOT_ACCESSIBLE_RECURSIVE_EX;
+ } else {
+ TextMessage = MSG_KEY_NOT_ACCESSIBLE_EX;
+ }
+ } else if( ErrorCode == REGEDIT_RPC_S_SERVER_UNAVAILABLE ) {
+ CaptionMessage = MSG_SERVER_UNAVAILABLE;
+ TextMessage = MSG_CANT_ACCESS_REMOTE_REGISTRY;
+ } else {
+ DebugPrint( "Unknown error code" );
+ DebugPrintf( "ErrorCode = %d \n", ErrorCode );
+ TextMessage = MSG_FAILED_OPERATION_EX;
+ CaptionMessage = MSG_UNKNOWN_ERROR;
+ }
+ DisplayInfoPopup(hwndParent,
+ TextMessage,
+ CaptionMessage);
+
+ *StatusReturn = SED_STATUS_FAILED_TO_MODIFY;
+ return( 1 );
+ }
+
+ *StatusReturn = SED_STATUS_MODIFIED;
+ return( 0 );
+}
+
+
+
+
+
+VOID
+TREE_STRUCTURE_VIEW::InvokeSecurityEditor(
+ IN BOOLEAN DaclEditor
+ )
+
+/*++
+
+Routine Description:
+
+ Invoke the DACL editor (permissions) or SACL editor (auditing), depending
+ on the parameter passed.
+
+
+Arguments:
+
+ DaclEditor - If TRUE, indicates that the permission editor is to be
+ invoked.
+ If FALSE, the SACL editor is invoked.
+
+
+Return Value:
+
+ None.
+
+
+--*/
+
+
+
+{
+ ULONG SecurityInformation;
+
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+
+
+ SED_OBJECT_TYPE_DESCRIPTOR SedObjDesc;
+ GENERIC_MAPPING GenericMapping;
+ DWORD rc;
+ DWORD StatusReturn;
+ CALLBACK_CONTEXT Context;
+ ULONG ErrorCode;
+ SED_HELP_INFO SedHelpInfo;
+
+ PCWSTRING NodeName;
+ PCWSTR NodeNameString;
+ PWSTR SpecialAccessString;
+ PWSTR HelpFileNameString;
+ PWSTR ObjectTypeNameString;
+ PWSTR ApplyToSubKeysString;
+ PWSTR ConfirmApplyString;
+ PWSTR DefaultPermissionName;
+ SED_APPLICATION_ACCESSES SedAppAccesses;
+ BOOLEAN Status;
+ HCURSOR Cursor;
+
+ INT TextMessage;
+ INT CaptionMessage;
+
+ PCWSTRING MachineName;
+ WCHAR ServerName[ 2 + MAX_COMPUTERNAME_LENGTH + 1 ];
+ PWSTR PointerToName;
+
+// PSTR DbgString;
+
+ if( WINDOWS_APPLICATION::IsReadOnlyModeEnabled() ) {
+ DisplayWarningPopup(_hwndList,
+ MSG_READONLY_MODE_SET_SECURITY_EX,
+ MSG_WARNING_TITLE );
+ }
+
+ //
+ // Initialize all strings needed
+ //
+
+ NodeName = ( _IR->GetNodeLevel( _CurrentNode ) != 0 )?
+ _IR->GetNodeName( _CurrentNode ) :
+ _IR->GetRootName();
+
+ if( NodeName ==NULL ) {
+ DebugPrint( "_IR->GetNodeName( _CurrentNode ) failed" );
+ return;
+ }
+ NodeNameString = NodeName->GetWSTR();
+ if( NodeNameString == NULL ) {
+ DebugPrint( "NodeName->GetWSTR() failed" );
+ return;
+ }
+
+ SpecialAccessString = _MsgSpecialAccessTitle->QueryWSTR();
+ HelpFileNameString = _MsgHelpFileName->QueryWSTR();
+ ObjectTypeNameString = _MsgObjectTypeName->QueryWSTR();
+ if( DaclEditor ) {
+ ApplyToSubKeysString = _MsgApplyPermissionToSubKeys->QueryWSTR();
+ ConfirmApplyString = _MsgConfirmApplyToSubKeys->QueryWSTR();
+ } else {
+ ApplyToSubKeysString = _MsgAuditPermissionOfSubKeys->QueryWSTR();
+ ConfirmApplyString = _MsgConfirmAuditSubKeys->QueryWSTR();
+ }
+ DefaultPermissionName = _MsgDefaultPermissionName->QueryWSTR();
+
+ if( ( SpecialAccessString == NULL ) ||
+ ( HelpFileNameString == NULL ) ||
+ ( ObjectTypeNameString == NULL ) ||
+ ( ApplyToSubKeysString == NULL ) ||
+ ( ConfirmApplyString == NULL ) ||
+ ( DefaultPermissionName == NULL ) ) {
+ DebugPrint( "Unable to initialize strings" );
+ FREE( SpecialAccessString );
+ FREE( HelpFileNameString );
+ FREE( ObjectTypeNameString );
+ FREE( ApplyToSubKeysString );
+ FREE( ConfirmApplyString );
+ FREE( DefaultPermissionName );
+ return;
+ }
+
+// DbgString = _MsgConfirmApplyToSubKeys->QuerySTR();
+// DebugPrintf( "Message = %s \n", DbgString );
+
+
+ //
+ // Initialization of variables to be passed to the editor
+ //
+
+ if( DaclEditor ) {
+ SedAppAccesses.Count = COUNT_KEY_PERMS_ARRAY;
+ SedAppAccesses.AccessGroup = _SedAppAccessKeyPerms;
+ } else {
+ SedAppAccesses.Count = COUNT_KEY_AUDITS_ARRAY;
+ SedAppAccesses.AccessGroup = _SedAppAccessKeyAudits;
+ }
+ SedAppAccesses.DefaultPermName = DefaultPermissionName;
+
+ SedHelpInfo.pszHelpFileName = HelpFileNameString;
+ if( DaclEditor ) {
+ SedHelpInfo.aulHelpContext[ HC_MAIN_DLG ] = IDH_DB_PERMISSION_REGED;
+ SedHelpInfo.aulHelpContext[ HC_SPECIAL_ACCESS_DLG ] = IDH_DB_PERMSPECIAL_REGED;
+ SedHelpInfo.aulHelpContext[ HC_NEW_ITEM_SPECIAL_ACCESS_DLG ] = IDH_DB_PERMISSION_REGED;
+ SedHelpInfo.aulHelpContext[ HC_ADD_USER_DLG ] = IDH_DB_PERMADD_REGED;
+ SedHelpInfo.aulHelpContext[ HC_ADD_USER_MEMBERS_LG_DLG ] = IDH_DB_PERMMEMBERS_REGED;
+ SedHelpInfo.aulHelpContext[ HC_ADD_USER_MEMBERS_GG_DLG ] = IDH_DB_PERMMEMBERS_REGED;
+ SedHelpInfo.aulHelpContext[ HC_ADD_USER_SEARCH_DLG ] = IDH_DB_PERMSEARCH_REGED;
+ // New help contexts
+ } else {
+ SedHelpInfo.aulHelpContext[ HC_MAIN_DLG ] = IDH_DB_AUDIT_REGED;
+ SedHelpInfo.aulHelpContext[ HC_SPECIAL_ACCESS_DLG ] = IDH_DB_AUDIT_REGED;
+ SedHelpInfo.aulHelpContext[ HC_NEW_ITEM_SPECIAL_ACCESS_DLG ] = IDH_DB_AUDIT_REGED;
+ SedHelpInfo.aulHelpContext[ HC_ADD_USER_DLG ] = IDH_DB_AUDITADD_REGED;
+ SedHelpInfo.aulHelpContext[ HC_ADD_USER_MEMBERS_LG_DLG ] = IDH_DB_AUDITMEMBERS_REGED;
+ SedHelpInfo.aulHelpContext[ HC_ADD_USER_MEMBERS_GG_DLG ] = IDH_DB_AUDITMEMBERS_REGED;
+ SedHelpInfo.aulHelpContext[ HC_ADD_USER_SEARCH_DLG ] = IDH_DB_AUDITSEARCH_REGED;
+ // New help contexts
+ }
+ GenericMapping.GenericRead = KEY_READ;
+ GenericMapping.GenericWrite = KEY_WRITE;
+ GenericMapping.GenericExecute = KEY_READ;
+ GenericMapping.GenericAll = KEY_ALL_ACCESS;
+
+ SedObjDesc.Revision = SED_REVISION1;
+
+ SedObjDesc.IsContainer = TRUE;
+ SedObjDesc.AllowNewObjectPerms = FALSE;
+ SedObjDesc.MapSpecificPermsToGeneric = FALSE;
+ SedObjDesc.GenericMapping = &GenericMapping;
+ SedObjDesc.GenericMappingNewObjects = &GenericMapping;
+ SedObjDesc.ObjectTypeName = ObjectTypeNameString;
+
+ SedObjDesc.ApplyToSubContainerTitle = ApplyToSubKeysString;
+ SedObjDesc.ApplyToSubContainerConfirmation = ConfirmApplyString;
+ SedObjDesc.HelpInfo = &SedHelpInfo;
+ SedObjDesc.ApplyToObjectsTitle = NULL;
+ SedObjDesc.SpecialObjectAccessTitle = SpecialAccessString;
+
+ SedObjDesc.SpecialNewObjectAccessTitle = NULL;
+ SedObjDesc.HelpInfo = &SedHelpInfo;
+
+ //
+ // Retrieve the security descriptor to be edited
+ //
+ if( DaclEditor ) {
+ SecurityInformation = DACL_SECURITY_INFORMATION |
+ OWNER_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION;
+ } else {
+ SecurityInformation = SACL_SECURITY_INFORMATION |
+ OWNER_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION;
+ }
+
+ Cursor = WINDOWS_APPLICATION::DisplayHourGlass();
+ Status = _IR->QueryNodeSecurity( _CurrentNode,
+ SecurityInformation,
+ &SecurityDescriptor,
+ &ErrorCode );
+ WINDOWS_APPLICATION::RestoreCursor( Cursor );
+
+ if ( !Status ) {
+
+ //
+ // Display error message indicating that the operation failed
+ //
+
+ if (ErrorCode == REGEDIT_ERROR_ACCESS_DENIED) {
+ TextMessage = MSG_GET_SECURITY_ACCESS_DENIED_EX;
+ CaptionMessage = MSG_ACCESS_DENIED;
+ } else if (ErrorCode == REGEDIT_ERROR_NODE_NOT_FOUND) {
+ TextMessage = MSG_GET_SECURITY_KEY_NOT_ACCESSIBLE_EX;
+ CaptionMessage = MSG_KEY_NOT_ACCESSIBLE;
+ } else if( ErrorCode == REGEDIT_ERROR_KEY_DELETED ) {
+ TextMessage = MSG_GET_SECURITY_KEY_DELETED_EX;
+ CaptionMessage = MSG_KEY_MARKED_FOR_DELETION;
+ } else if( ErrorCode == REGEDIT_RPC_S_SERVER_UNAVAILABLE ) {
+ TextMessage = MSG_CANT_ACCESS_REMOTE_REGISTRY;
+ CaptionMessage = MSG_SERVER_UNAVAILABLE;
+ } else {
+ DebugPrint( "Unknown error code" );
+ DebugPrintf( "ErrorCode = %d \n", ErrorCode );
+ TextMessage = MSG_FAILED_OPERATION_EX;
+ CaptionMessage = 0;
+ }
+ DisplayInfoPopup(_hwndList,
+ TextMessage,
+ CaptionMessage);
+
+ FREE( SpecialAccessString );
+ FREE( HelpFileNameString );
+ FREE( ObjectTypeNameString );
+ FREE( ApplyToSubKeysString );
+ FREE( ConfirmApplyString );
+ FREE( DefaultPermissionName );
+ return;
+ }
+
+ //
+ // Initialization of the structure to be passed to the CallBack function
+ //
+ Context.ThisPointer = this;
+ if( DaclEditor ) {
+ Context.SecurityInfo = DACL_SECURITY_INFORMATION;
+ } else {
+ Context.SecurityInfo = SACL_SECURITY_INFORMATION;
+ }
+
+ //
+ // Get the server name
+ //
+
+ MachineName = _IR->GetMachineName();
+ if( ( MachineName != NULL ) &&
+ ( MachineName->QueryWSTR( 0,
+ TO_END,
+ ServerName + 2,
+ sizeof( ServerName ) / sizeof( WCHAR ) ) != NULL )
+ ) {
+ ServerName[ 0 ] = ( WCHAR )'\\';
+ ServerName[ 1 ] = ( WCHAR )'\\';
+ PointerToName = ServerName;
+ } else {
+ PointerToName = NULL;
+ }
+
+
+ //
+ // Invoke the editor
+ //
+ Cursor = WINDOWS_APPLICATION::DisplayHourGlass();
+ if( DaclEditor ) {
+ //
+ // Invoke the DACL editor ( permissions )
+ //
+
+ rc = SedDiscretionaryAclEditor( _Handle,
+ WINDOWS_APPLICATION::QueryInstance(),
+ PointerToName,
+ &SedObjDesc,
+ &SedAppAccesses,
+ ( PWSTR )NodeNameString,
+ ( PSED_FUNC_APPLY_SEC_CALLBACK )SedCallBack,
+ ( ULONG )&Context,
+ SecurityDescriptor,
+ FALSE,
+ !_IR->IsAccessAllowed( _CurrentNode,
+ WRITE_DAC,
+ &ErrorCode ), // FALSE, // CantWriteDacl
+ &StatusReturn,
+ 0 );
+
+ } else {
+ //
+ // Invoke the SACL editor ( auditing )
+ //
+
+ rc = SedSystemAclEditor( _Handle,
+ WINDOWS_APPLICATION::QueryInstance(),
+ PointerToName,
+ &SedObjDesc,
+ &SedAppAccesses,
+ ( PWSTR )NodeNameString,
+ ( PSED_FUNC_APPLY_SEC_CALLBACK )SedCallBack,
+ ( ULONG )&Context,
+ SecurityDescriptor,
+ !_IR->IsAccessAllowed( _CurrentNode,
+ ACCESS_SYSTEM_SECURITY,
+ &ErrorCode ), // CantWriteDacl
+ &StatusReturn,
+ 0 );
+ }
+ WINDOWS_APPLICATION::RestoreCursor( Cursor );
+ FREE( SpecialAccessString );
+ FREE( HelpFileNameString );
+ FREE( ObjectTypeNameString );
+ FREE( ApplyToSubKeysString );
+ FREE( ConfirmApplyString );
+ FREE( DefaultPermissionName );
+}
+
+
+
+VOID
+TREE_STRUCTURE_VIEW::InvokeTakeOwnershipEditor(
+ )
+
+/*++
+
+Routine Description:
+
+ Invoke the take ownership dialog. This dialog is used to view or set
+ the owner of a security descriptor.
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+ None.
+
+
+--*/
+
+
+
+{
+ PCWSTR Name;
+ ULONG SecurityInformation;
+
+ PSECURITY_DESCRIPTOR SecurityDescriptor;
+ DWORD rc;
+ DWORD StatusReturn;
+ CALLBACK_CONTEXT Context;
+ ULONG ErrorCode;
+
+ PWSTRING MsgRegistryKey;
+ PWSTR MsgRegistryKeyString;
+ BOOLEAN Status;
+ HCURSOR Cursor;
+
+ INT TextMessage;
+ INT CaptionMessage;
+
+ PCWSTRING MachineName;
+ WCHAR ServerName[ 2 + MAX_COMPUTERNAME_LENGTH + 1 ];
+ PWSTR PointerToName;
+
+ BOOLEAN CantReadOwner;
+
+ CantReadOwner = FALSE;
+
+ if( WINDOWS_APPLICATION::IsReadOnlyModeEnabled() ) {
+ DisplayWarningPopup(_hwndList,
+ MSG_READONLY_MODE_SET_SECURITY_EX,
+ MSG_WARNING_TITLE );
+ }
+
+ //
+ // Retrieve some strings to be passed to the Take Ownership Editor
+ //
+ MsgRegistryKey = REGEDIT_BASE_SYSTEM::QueryString( MSG_SEC_EDITOR_REGISTRY_KEY, "" );
+ if( MsgRegistryKey == NULL ) {
+ DebugPrint( "Unable to retrieve MsgRegistryKey" );
+ return;
+ }
+ MsgRegistryKeyString = MsgRegistryKey->QueryWSTR();
+ if( MsgRegistryKeyString == NULL ) {
+ DebugPrint( "Unable to retrieve MsgRegistryKey" );
+ return;
+ }
+ FREE( MsgRegistryKey );
+
+
+
+ SecurityInformation = DACL_SECURITY_INFORMATION |
+ OWNER_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION;
+
+ Cursor = WINDOWS_APPLICATION::DisplayHourGlass();
+ Status = _IR->QueryNodeSecurity( _CurrentNode,
+ SecurityInformation,
+ &SecurityDescriptor,
+ &ErrorCode );
+ WINDOWS_APPLICATION::RestoreCursor( Cursor );
+
+ if( !Status ) {
+ SecurityDescriptor = NULL;
+ CantReadOwner = TRUE;
+ }
+ if ( !Status && ( Status != REGEDIT_ERROR_ACCESS_DENIED ) ) {
+
+ //
+ // Display error message indicating that the operation failed
+ //
+
+ if (ErrorCode == REGEDIT_ERROR_NODE_NOT_FOUND) {
+ TextMessage = MSG_GET_SECURITY_KEY_NOT_ACCESSIBLE_EX;
+ CaptionMessage = MSG_KEY_NOT_ACCESSIBLE;
+ } else if( ErrorCode == REGEDIT_ERROR_KEY_DELETED ) {
+ TextMessage = MSG_GET_SECURITY_KEY_DELETED_EX;
+ CaptionMessage = MSG_KEY_MARKED_FOR_DELETION;
+ } else if( ErrorCode == REGEDIT_RPC_S_SERVER_UNAVAILABLE ) {
+ TextMessage = MSG_CANT_ACCESS_REMOTE_REGISTRY;
+ CaptionMessage = MSG_SERVER_UNAVAILABLE;
+ } else {
+ DebugPrint( "Unknown error code" );
+ DebugPrintf( "ErrorCode = %d \n", ErrorCode );
+ TextMessage = MSG_FAILED_OPERATION_EX;
+ CaptionMessage = 0;
+ }
+ DisplayInfoPopup(_hwndList,
+ TextMessage,
+ CaptionMessage);
+
+ FREE( MsgRegistryKeyString );
+ return;
+ }
+ Name = ( _IR->GetNodeLevel( _CurrentNode ) != 0 )?
+ _IR->GetNodeName( _CurrentNode )->GetWSTR() :
+ _IR->GetRootName()->GetWSTR();
+
+
+ if( Name == NULL ) {
+ DebugPrint( "_CurrentNode->QueryWSTR() failed" );
+ FREE( SecurityDescriptor );
+ DebugPtrAssert( Name );
+ FREE( MsgRegistryKeyString );
+ return;
+ }
+
+ Context.ThisPointer = this;
+ Context.SecurityInfo = OWNER_SECURITY_INFORMATION;
+
+ //
+ // Get the server name
+ //
+
+ MachineName = _IR->GetMachineName();
+ if( ( MachineName != NULL ) &&
+ ( MachineName->QueryWSTR( 0,
+ TO_END,
+ ServerName + 2,
+ sizeof( ServerName ) / sizeof( WCHAR ) ) != NULL )
+ ) {
+ ServerName[ 0 ] = ( WCHAR )'\\';
+ ServerName[ 1 ] = ( WCHAR )'\\';
+ PointerToName = ServerName;
+ } else {
+ PointerToName = NULL;
+ }
+
+ SED_HELP_INFO SedHelpInfo;
+ SedHelpInfo.pszHelpFileName = (LPWSTR)_MsgHelpFileName->GetWSTR();
+ SedHelpInfo.aulHelpContext[ HC_MAIN_DLG ] = IDH_DB_OWNER_REGED;
+
+ rc = SedTakeOwnership( _Handle,
+ WINDOWS_APPLICATION::QueryInstance(),
+ PointerToName,
+ MsgRegistryKeyString,
+ ( PWSTR )Name,
+ 1,
+ ( PSED_FUNC_APPLY_SEC_CALLBACK )SedCallBack,
+ ( ULONG )&Context,
+ SecurityDescriptor,
+ CantReadOwner,
+ !WINDOWS_APPLICATION::_TakeOwnershipPrivilege,
+ &StatusReturn,
+ &SedHelpInfo,
+ 0 );
+ FREE( SecurityDescriptor );
+ FREE( MsgRegistryKeyString );
+}
+
+
+
+
+BOOLEAN
+TREE_STRUCTURE_VIEW::ProcessLoadHiveMessage(
+ IN PCWSTRING FileName
+ )
+
+/*++
+
+Routine Description:
+
+ Loads a hive to a predefined key.
+
+
+Arguments:
+
+ FileName - Name of the file that contains the hive to be loaded.
+
+
+Return Value:
+
+
+ Returns TRUE if the operation succeeded.
+
+
+--*/
+
+
+
+{
+ BOOLEAN LoadHiveFlag;
+ PREGISTRY_KEY_INFO NewKeyInfo;
+ PCREGEDIT_NODE NewNode;
+ ULONG ErrorCode;
+ ADD_NODE_DIALOG_INFO NodeInfo;
+ DSTRING CompleteParentName;
+ HCURSOR CurrentCursor;
+ BOOLEAN Status;
+ INT TextMessage;
+ INT CaptionMessage;
+
+
+
+ if( !_IR->QueryCompleteNodeName( _CurrentNode, &CompleteParentName ) ) {
+ DebugPrint( "_IR->QueryCompleteNodeName() failed" );
+ return( FALSE );
+ }
+
+
+ LoadHiveFlag = TRUE;
+ while( LoadHiveFlag ) {
+ NodeInfo.Name = NULL;
+ NodeInfo.Title = NULL;
+ NodeInfo.Class = NULL;
+ NodeInfo.ClassDisplayed = FALSE;
+ if( DialogBoxParam( (HINSTANCE)WINDOWS_APPLICATION::QueryInstance( ),
+ MAKEINTRESOURCE(GET_KEY_DLG),
+ _Handle,
+ ( DLGPROC )TREE_STRUCTURE_VIEW::GetKeyNameDialogProc,
+ ( DWORD )&NodeInfo ) == -1 ) {
+ DebugPrint( "Unable to create dialog box" );
+ return( FALSE );
+ }
+
+ if( NodeInfo.Name != NULL ) {
+ if( _IR->DoesChildNodeExist( _CurrentNode,
+ NodeInfo.Name,
+ &ErrorCode ) ) {
+ DisplayWarningPopup( _Handle,
+ MSG_LOAD_HIVE_ALREADY_EXISTS_EX );
+
+ DELETE( NodeInfo.Name );
+ DELETE( NodeInfo.Class );
+ } else {
+ NewKeyInfo = ( PREGISTRY_KEY_INFO )NEW( REGISTRY_KEY_INFO );
+ DebugPtrAssert( NewKeyInfo );
+
+ if( !NewKeyInfo->Initialize( NodeInfo.Name,
+ &CompleteParentName,
+ 0, // TitleIndex
+ NodeInfo.Class ) ) {
+ DebugPrint( "NewKeyInfo->Initialize() failed" );
+ DELETE( NodeInfo.Name );
+ DELETE( NodeInfo.Title );
+ DELETE( NodeInfo.Class );
+ return( FALSE );
+ }
+ DELETE( NodeInfo.Name );
+ DELETE( NodeInfo.Title );
+ DELETE( NodeInfo.Class );
+
+ CurrentCursor = WINDOWS_APPLICATION::DisplayHourGlass();
+ Status = _IR->LoadHive( _CurrentNode, NewKeyInfo, FileName, &NewNode, &ErrorCode );
+ WINDOWS_APPLICATION::RestoreCursor( CurrentCursor );
+ if( !Status ) {
+ if (ErrorCode == REGEDIT_ERROR_ACCESS_DENIED) {
+ TextMessage = MSG_LOAD_HIVE_ACCESS_DENIED_EX;
+ CaptionMessage = MSG_ACCESS_DENIED;
+ } else if( ErrorCode == REGEDIT_ERROR_BADDB ) {
+ TextMessage = MSG_LOAD_HIVE_BAD_FILE_EX;
+ CaptionMessage = MSG_LOAD_HIVE_BAD_FILE;
+ } else if( ErrorCode == REGEDIT_RPC_S_SERVER_UNAVAILABLE ) {
+ TextMessage = MSG_CANT_ACCESS_REMOTE_REGISTRY;
+ CaptionMessage = MSG_SERVER_UNAVAILABLE;
+ } else {
+ DebugPrint( "Unknown error code" );
+ DebugPrintf( "ErrorCode = %d \n", ErrorCode );
+ TextMessage = MSG_FAILED_OPERATION_EX;
+ CaptionMessage = 0;
+ }
+ DisplayInfoPopup(_hwndList,
+ TextMessage,
+ CaptionMessage);
+
+ return( FALSE );
+ }
+
+ if( IsItemAfterAChild( _CurrentItem ) ) {
+ // Disable redrawing.
+ SendMessage( _hwndList, WM_SETREDRAW, FALSE, 0L );
+
+ do {
+ SendMessage( _hwndList, LB_DELETESTRING, _CurrentItem + 1, 0 );
+ _Items--;
+ } while( IsItemAfterAChild( _CurrentItem ) );
+ SendMessage( _hwndList, LB_DELETESTRING, ( UINT )_CurrentItem, 0 );
+ _Items--;
+ InsertUpdatedSubTreeToListBox( _CurrentNode, _CurrentItem );
+ _Items = ( INT )SendMessage( _hwndList, LB_GETCOUNT, 0, 0 );
+ // Re-enable redrawing and refresh the tree.
+ SendMessage( _hwndList, LB_SETCURSEL, _CurrentItem, 0 );
+ SendMessage( _hwndList, WM_SETREDRAW, TRUE, 0L );
+ InvalidateRect( _hwndList, NULL, TRUE );
+
+ } else {
+ ExpandCurrentItem( 1 );
+ }
+
+ LoadHiveFlag = FALSE;
+ }
+ } else {
+ LoadHiveFlag = FALSE;
+ }
+ }
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+TREE_STRUCTURE_VIEW::ProcessUnLoadHiveMessage(
+ )
+
+/*++
+
+Routine Description:
+
+ Unloads the hive currently selected.
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+
+ Returns TRUE if the operation succeeded.
+
+
+--*/
+
+
+
+{
+ ULONG ErrorCode;
+ BOOLEAN Status;
+ HCURSOR Cursor;
+ LONG TopIndex;
+ INT TextMessage;
+ INT CaptionMessage;
+
+ DbgWinAssert( _HasFocus );
+ DbgWinAssert( _Items == SendMessage( _hwndList, LB_GETCOUNT, 0, 0 ) );
+ DbgWinAssert( _CurrentItem == SendMessage( _hwndList, LB_GETCURSEL, 0, 0 ) );
+ DbgWinAssert( _CurrentNode == (PCREGEDIT_NODE)SendMessage( _hwndList, LB_GETITEMDATA, _CurrentItem, 0 ) );
+ DbgWinPtrAssert( _IR );
+ DbgWinPtrAssert( _CurrentNode );
+
+ if( _Items >= 1 ) {
+ //
+ // The tree view has at least one item
+ //
+
+ if( ( WINDOWS_APPLICATION::IsConfirmOnDeleteEnabled() &&
+ ( DisplayConfirmPopup( _hwndList,
+ MSG_UNLOAD_HIVE_CONFIRM_EX,
+ MSG_WARNING_TITLE ) == IDYES ) ) ||
+ ( !WINDOWS_APPLICATION::IsConfirmOnDeleteEnabled() ) ) {
+
+ //
+ // Collapse the current node before deletion
+ //
+ if( IsItemAfterAChild( _CurrentItem ) ) {
+ CollapseCurrentItem();
+ }
+ Cursor = WINDOWS_APPLICATION::DisplayHourGlass();
+ Status = _IR->UnLoadHive( (PREGEDIT_NODE)_CurrentNode, &ErrorCode );
+ WINDOWS_APPLICATION::RestoreCursor( Cursor );
+ if( Status ) {
+ _MaxWidth = 0;
+
+ TopIndex = SendMessage( _hwndList, LB_GETTOPINDEX, 0, 0 );
+ _Items--;
+ SendMessage( _hwndList, LB_DELETESTRING, _CurrentItem, 0 );
+
+
+ //
+ // If the listbox still contains items, then put the selection
+ // on the appropriate item
+ //
+ if( ( _Items > 0 ) ) {
+
+ //
+ // If the last item was deleted, then make the current
+ // last item the current selected item
+ //
+ if( _CurrentItem == _Items ) {
+ _CurrentItem--;
+ }
+ if( TopIndex != -1 ) {
+ SendMessage( _hwndList, LB_SETTOPINDEX, (UINT)TopIndex, 0 );
+ }
+ SendMessage( _hwndList, LB_SETCURSEL, _CurrentItem, 0 );
+ }
+
+
+ _CurrentNode = GetNode( _CurrentItem );
+ SendMessage( GetParent( _Handle), TR_NEWCURSEL, 0, (LONG)_CurrentNode );
+
+
+
+ // Re-enable redrawing and refresh the tree.
+ SendMessage( _hwndList, WM_SETREDRAW, TRUE, 0L );
+ InvalidateRect( _hwndList, NULL, TRUE );
+ } else {
+ if (ErrorCode == REGEDIT_ERROR_ACCESS_DENIED) {
+ TextMessage = MSG_UNLOAD_HIVE_ACCESS_DENIED_EX;
+ CaptionMessage = MSG_ACCESS_DENIED;
+ } else if( ErrorCode == REGEDIT_RPC_S_SERVER_UNAVAILABLE ) {
+ TextMessage = MSG_CANT_ACCESS_REMOTE_REGISTRY;
+ CaptionMessage = MSG_SERVER_UNAVAILABLE;
+ } else {
+ DebugPrint( "Unknown error code" );
+ DebugPrintf( "ErrorCode = %d \n", ErrorCode );
+ TextMessage = MSG_FAILED_OPERATION_EX;
+ CaptionMessage = 0;
+ }
+ DisplayInfoPopup(_hwndList,
+ TextMessage,
+ CaptionMessage);
+
+ return( FALSE );
+ }
+ }
+ }
+ return( TRUE );
+
+}
+
+
+
+
+BOOLEAN
+TREE_STRUCTURE_VIEW::ProcessSaveKeyMessage(
+ IN PCWSTRING FileName
+ )
+
+/*++
+
+Routine Description:
+
+ Save the key currently selected and all it subkeys into a file.
+
+
+Arguments:
+
+
+ FileName - Pointer to the string object that contains a file name.
+
+
+Return Value:
+
+
+ Returns TRUE if the operation succeeded.
+
+
+--*/
+
+
+
+{
+ ULONG ErrorCode;
+ BOOLEAN Status;
+ HCURSOR Cursor;
+ INT TextMessage;
+ INT CaptionMessage;
+
+ DbgWinAssert( _HasFocus );
+ DbgWinAssert( _Items == SendMessage( _hwndList, LB_GETCOUNT, 0, 0 ) );
+ DbgWinAssert( _CurrentItem == SendMessage( _hwndList, LB_GETCURSEL, 0, 0 ) );
+ DbgWinAssert( _CurrentNode == (PCREGEDIT_NODE)SendMessage( _hwndList, LB_GETITEMDATA, _CurrentItem, 0 ) );
+ DbgWinPtrAssert( _IR );
+ DbgWinPtrAssert( _CurrentNode );
+
+ if( _Items >= 1 ) {
+ //
+ // The tree view has at least one item
+ //
+
+ Cursor = WINDOWS_APPLICATION::DisplayHourGlass();
+ Status = _IR->SaveKeyToFile( _CurrentNode, FileName, &ErrorCode );
+
+ WINDOWS_APPLICATION::RestoreCursor( Cursor );
+
+ if( !Status ) {
+ if (ErrorCode == REGEDIT_ERROR_ACCESS_DENIED) {
+ TextMessage = MSG_SAVE_KEY_ACCESS_DENIED_EX;
+ CaptionMessage = MSG_ACCESS_DENIED;
+ } else if( ErrorCode == REGEDIT_ERROR_NODE_NOT_FOUND ) {
+ TextMessage = MSG_SAVE_KEY_KEY_NOT_ACCESSIBLE_EX;
+ CaptionMessage = MSG_KEY_NOT_ACCESSIBLE;
+ } else if( ErrorCode == REGEDIT_RPC_S_SERVER_UNAVAILABLE ) {
+ TextMessage = MSG_CANT_ACCESS_REMOTE_REGISTRY;
+ CaptionMessage = MSG_SERVER_UNAVAILABLE;
+ } else {
+ DebugPrint( "Unknown error code" );
+ DebugPrintf( "ErrorCode = %d \n", ErrorCode );
+ TextMessage = MSG_FAILED_OPERATION_EX;
+ CaptionMessage = 0;
+ }
+ DisplayInfoPopup(_hwndList,
+ TextMessage,
+ CaptionMessage);
+
+ return( FALSE );
+ }
+
+ }
+ return( TRUE );
+
+}
+
+
+
+BOOLEAN
+TREE_STRUCTURE_VIEW::ProcessRestoreKeyMessage(
+ IN PCWSTRING FileName,
+ IN BOOLEAN Volatile
+ )
+
+/*++
+
+Routine Description:
+
+ Restore the contents of a file to the currently selected key.
+
+
+Arguments:
+
+
+ FileName - Pointer to the string object that contains a file name.
+
+ Volatile - Flag that indicates whether the key shoud be replaced as
+ volatile.
+
+
+Return Value:
+
+
+ Returns TRUE if the operation succeeded.
+
+
+--*/
+
+
+
+{
+ ULONG ErrorCode;
+ BOOLEAN Status;
+ HCURSOR Cursor;
+ INT TextMessage;
+ INT CaptionMessage;
+
+ DbgWinAssert( _HasFocus );
+ DbgWinAssert( _Items == SendMessage( _hwndList, LB_GETCOUNT, 0, 0 ) );
+ DbgWinAssert( _CurrentItem == SendMessage( _hwndList, LB_GETCURSEL, 0, 0 ) );
+ DbgWinAssert( _CurrentNode == (PCREGEDIT_NODE)SendMessage( _hwndList, LB_GETITEMDATA, _CurrentItem, 0 ) );
+ DbgWinPtrAssert( _IR );
+ DbgWinPtrAssert( _CurrentNode );
+
+ if( _Items >= 1 ) {
+ //
+ // The tree view has at least one item
+ //
+
+ if( ( WINDOWS_APPLICATION::IsConfirmOnDeleteEnabled() &&
+ ( DisplayConfirmPopup( _hwndList,
+ MSG_RESTORE_KEY_CONFIRM_EX,
+ MSG_WARNING_TITLE ) == IDYES ) ) ||
+ ( !WINDOWS_APPLICATION::IsConfirmOnDeleteEnabled() ) ) {
+
+ //
+ // Collapse the current node before restorating the key
+ //
+ if( IsItemAfterAChild( _CurrentItem ) ) {
+ CollapseCurrentItem();
+ }
+ Cursor = WINDOWS_APPLICATION::DisplayHourGlass();
+ Status = _IR->RestoreKeyFromFile( _CurrentNode,
+ FileName,
+ Volatile,
+ &ErrorCode );
+ WINDOWS_APPLICATION::RestoreCursor( Cursor );
+
+ if( !Status ) {
+ if (ErrorCode == REGEDIT_ERROR_ACCESS_DENIED) {
+ TextMessage = MSG_RESTORE_KEY_ACCESS_DENIED_EX;
+ CaptionMessage = MSG_ACCESS_DENIED;
+ } else if( ErrorCode == REGEDIT_ERROR_NODE_NOT_FOUND ) {
+ TextMessage = MSG_RESTORE_KEY_KEY_NOT_ACCESSIBLE_EX;
+ CaptionMessage = MSG_KEY_NOT_ACCESSIBLE;
+ } else if( ErrorCode == REGEDIT_RPC_S_SERVER_UNAVAILABLE ) {
+ TextMessage = MSG_CANT_ACCESS_REMOTE_REGISTRY;
+ CaptionMessage = MSG_SERVER_UNAVAILABLE;
+ } else {
+ DebugPrint( "Unknown error code" );
+ DebugPrintf( "ErrorCode = %d \n", ErrorCode );
+ TextMessage = MSG_FAILED_OPERATION_EX;
+ CaptionMessage = 0;
+ }
+ DisplayInfoPopup(_hwndList,
+ TextMessage,
+ CaptionMessage);
+
+ return( FALSE );
+ }
+
+ if( IsItemAfterAChild( _CurrentItem ) ) {
+ // Disable redrawing.
+ SendMessage( _hwndList, WM_SETREDRAW, FALSE, 0L );
+
+ do {
+ SendMessage( _hwndList, LB_DELETESTRING, _CurrentItem + 1, 0 );
+ _Items--;
+ } while( IsItemAfterAChild( _CurrentItem ) );
+ SendMessage( _hwndList, LB_DELETESTRING, ( UINT )_CurrentItem, 0 );
+ _Items--;
+ InsertUpdatedSubTreeToListBox( _CurrentNode, _CurrentItem );
+ _Items = ( INT )SendMessage( _hwndList, LB_GETCOUNT, 0, 0 );
+ // Re-enable redrawing and refresh the tree.
+ SendMessage( _hwndList, LB_SETCURSEL, _CurrentItem, 0 );
+ SendMessage( _hwndList, WM_SETREDRAW, TRUE, 0L );
+ InvalidateRect( _hwndList, NULL, TRUE );
+
+ } else {
+ InvalidateRect( _hwndList, NULL, TRUE );
+ }
+ SendMessage( GetParent( _Handle), TR_NEWCURSEL, 0, (LONG)_CurrentNode );
+
+ }
+ }
+ return( TRUE );
+
+}
+
+
+
+BOOL
+APIENTRY
+EXPORT
+TREE_STRUCTURE_VIEW::GetKeyNameDialogProc(
+ HWND hDlg,
+ WORD msg,
+ WPARAM wParam,
+ LONG lParam
+)
+/*++
+
+Routine Description:
+
+ Dialog procedure for the dialog that allows the user to enter a
+ key name, and a key class if necessary.
+ the registry.
+
+
+Arguments:
+
+ hDlg - a handle to the dialog proceedure.
+
+ msg - the message passed from Windows.
+
+ wParam - extra message dependent data.
+
+ lParam - extra message dependent data.
+
+
+Return Value:
+
+ Returns FALSE if the message received wasn't processed. Otherwise,
+ returns TRUE.
+
+--*/
+{
+ STATIC PADD_NODE_DIALOG_INFO ReturnNodeDlgInfo;
+ STATIC BOOLEAN ClassDisplayed;
+
+ LPWSTR NodeName;
+ ULONG NameSize;
+
+ LPWSTR Class;
+ ULONG ClassSize;
+
+ DSTRING TmpString;
+ DSTRING TmpString1;
+
+ PWSTRING NodeNameString;
+ PWSTRING NodeClassString;
+
+
+ switch( msg ) {
+
+ case WM_INITDIALOG:
+
+ ReturnNodeDlgInfo = ( PADD_NODE_DIALOG_INFO )lParam;
+ ClassDisplayed = ReturnNodeDlgInfo->ClassDisplayed;
+ SendDlgItemMessage( hDlg, IDD_ADD_KEY_NAME, EM_LIMITTEXT, 256, 0L );
+ return( TRUE );
+
+
+ case WM_COMMAND:
+
+ switch( LOWORD( wParam ) ) {
+
+ case IDOK:
+
+ //
+ // The user hit OK
+ //
+
+ //
+ // Verifiy that the user entered a node name
+ //
+ NameSize = SendDlgItemMessage( hDlg, IDD_ADD_KEY_NAME, WM_GETTEXTLENGTH, 0, 0 );
+ if( NameSize == 0 ) {
+ //
+ // If no name was entered, diplay error message
+ //
+ DisplayInfoPopup( hDlg,
+ MSG_ADD_KEY_ERROR_NO_NAME,
+ MSG_ADD_KEY_INVALID_KEY_NAME );
+
+ SetFocus( GetDlgItem( hDlg, IDD_ADD_KEY_NAME ) );
+ return( TRUE );
+ }
+
+
+ //
+ // Get all data that the user specified, and save them in a
+ // NODE object
+ //
+ NameSize = NameSize + 1;
+ NodeName = ( LPWSTR )MALLOC( ( size_t )(NameSize*sizeof( WCHAR )) );
+ DebugPtrAssert( NodeName );
+ SendDlgItemMessage( hDlg,
+ IDD_ADD_KEY_NAME,
+ ( UINT )WM_GETTEXT,
+ ( WPARAM )NameSize,
+ ( DWORD )NodeName );
+
+ if( wcschr( NodeName, (WCHAR)'\\' ) != NULL ) {
+ DisplayInfoPopup( hDlg,
+ MSG_ADD_KEY_INVALID_KEY_NAME_EX,
+ MSG_ADD_KEY_INVALID_KEY_NAME );
+ FREE( NodeName );
+ return( TRUE );
+ }
+
+ //
+ // Get the class
+ //
+
+ if( ReturnNodeDlgInfo->ClassDisplayed ) {
+ ClassSize = SendDlgItemMessage( hDlg,
+ IDD_ADD_KEY_CLASS,
+ ( UINT )WM_GETTEXTLENGTH,
+ 0,
+ 0 );
+ if( ClassSize != 0 ) {
+ ClassSize = ClassSize + 1;
+ Class = ( LPWSTR )MALLOC( ( size_t )(ClassSize*sizeof(WCHAR)) );
+ DbgWinPtrAssert( Class );
+ SendDlgItemMessage( hDlg,
+ IDD_ADD_KEY_CLASS,
+ ( UINT )WM_GETTEXT,
+ ( WPARAM )ClassSize,
+ ( DWORD )Class );
+ }
+
+ ReturnNodeDlgInfo->VolatileKey = FALSE;
+ // ReturnNodeDlgInfo->VolatileKey = SendDlgItemMessage( hDlg,
+ // IDD_ADD_KEY_VOLATILE,
+ // ( UINT )BM_GETCHECK,
+ // ( WPARAM )0,
+ // ( DWORD )0 );
+ }
+
+ NodeNameString = ( PWSTRING ) NEW( DSTRING );
+ DebugPtrAssert( NodeNameString );
+ NodeClassString = ( PWSTRING ) NEW( DSTRING );
+ DebugPtrAssert( NodeClassString );
+
+ if( !NodeNameString->Initialize( NodeName ) ) {
+ DebugPrint( "NodeNameString.Initialize( NodeName ) failed \n" );
+ EndDialog( hDlg, FALSE );
+ return( TRUE );
+ }
+ FREE( NodeName );
+
+ if( ReturnNodeDlgInfo->ClassDisplayed &&
+ ( ClassSize != 0 ) ) {
+ if( !NodeClassString->Initialize( Class, ClassSize ) ) {
+ FREE( Class );
+ DebugPrint( "NodeClassString->Initialize( Class ) failed \n" );
+ EndDialog( hDlg, FALSE );
+ return( TRUE );
+ }
+ FREE( Class );
+ } else {
+ if( !NodeClassString->Initialize( "" ) ) {
+ DebugPrint( "NodeClassString->Initialize() failed \n" );
+ EndDialog( hDlg, FALSE );
+ return( TRUE );
+ }
+ }
+
+ ReturnNodeDlgInfo->Name = NodeNameString;
+ ReturnNodeDlgInfo->Title = NULL;
+ ReturnNodeDlgInfo->Class = NodeClassString;
+
+ EndDialog( hDlg, TRUE );
+ return( TRUE );
+
+ case IDCANCEL:
+ //
+ // The user hit CANCEL
+ //
+
+ EndDialog( hDlg, FALSE );
+ return( TRUE );
+
+ case IDB_HELP:
+ //
+ // The user hit HELP
+ //
+ DisplayHelp();
+ return( TRUE );
+ }
+ }
+ return( FALSE );
+}
diff --git a/private/utils/regedit/src/uapp.cxx b/private/utils/regedit/src/uapp.cxx
new file mode 100644
index 000000000..f1732d3b4
--- /dev/null
+++ b/private/utils/regedit/src/uapp.cxx
@@ -0,0 +1,173 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Uapp.hxx
+
+Abstract:
+
+
+Author:
+
+ David J. Gilman (davegi) - Jul-1991
+
+Environment:
+
+ ULIB, User Mode, Windows
+
+--*/
+
+#include "uapp.hxx"
+
+#include "regedir.hxx"
+#include "regednod.hxx"
+#include "regedval.hxx"
+#include "regdata.hxx"
+#include "regdesc.hxx"
+#include "regfdesc.hxx"
+#include "regiodsc.hxx"
+#include "regiodls.hxx"
+#include "regioreq.hxx"
+#include "regresls.hxx"
+#include "datavw.hxx"
+#include "editor.hxx"
+#include "regwin.hxx"
+#include "treevw.hxx"
+#include "winapp.hxx"
+#include "window.hxx"
+
+
+
+DECLARE_CLASS( DATA_VIEW );
+DECLARE_CLASS( EDITOR );
+DECLARE_CLASS( REGEDIT_INTERNAL_REGISTRY );
+DECLARE_CLASS( REGEDIT_NODE );
+DECLARE_CLASS( REGEDIT_FORMATTED_VALUE_ENTRY );
+DECLARE_CLASS( PRINT_MANAGER );
+DECLARE_CLASS( REGISTRY_WINDOW );
+DECLARE_CLASS( TREE_STRUCTURE_VIEW );
+DECLARE_CLASS( WINDOW );
+DECLARE_CLASS( WINDOWS_APPLICATION );
+DECLARE_CLASS( REGISTRY_DATA );
+DECLARE_CLASS( PARTIAL_DESCRIPTOR );
+DECLARE_CLASS( PORT_DESCRIPTOR );
+DECLARE_CLASS( INTERRUPT_DESCRIPTOR );
+DECLARE_CLASS( MEMORY_DESCRIPTOR );
+DECLARE_CLASS( DMA_DESCRIPTOR );
+DECLARE_CLASS( DEVICE_SPECIFIC_DESCRIPTOR );
+DECLARE_CLASS( FULL_DESCRIPTOR );
+DECLARE_CLASS( RESOURCE_LIST );
+DECLARE_CLASS( IO_DESCRIPTOR );
+DECLARE_CLASS( IO_PORT_DESCRIPTOR );
+DECLARE_CLASS( IO_INTERRUPT_DESCRIPTOR );
+DECLARE_CLASS( IO_MEMORY_DESCRIPTOR );
+DECLARE_CLASS( IO_DMA_DESCRIPTOR );
+DECLARE_CLASS( IO_DESCRIPTOR_LIST );
+DECLARE_CLASS( IO_REQUIREMENTS_LIST );
+
+
+STATIC
+BOOLEAN
+DefineClassDescriptors (
+ )
+
+/*++
+
+Routine Description:
+
+ Defines all the class descriptors used by regedt32.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if all class descriptors were succesfully
+ constructed and initialized.
+
+--*/
+
+{
+
+ if( !( DEFINE_CLASS_DESCRIPTOR( DATA_VIEW ) &&
+ DEFINE_CLASS_DESCRIPTOR( EDITOR ) &&
+ DEFINE_CLASS_DESCRIPTOR( REGEDIT_INTERNAL_REGISTRY ) &&
+ DEFINE_CLASS_DESCRIPTOR( REGEDIT_NODE ) &&
+ DEFINE_CLASS_DESCRIPTOR( REGEDIT_FORMATTED_VALUE_ENTRY ) &&
+ DEFINE_CLASS_DESCRIPTOR( PRINT_MANAGER ) &&
+ DEFINE_CLASS_DESCRIPTOR( REGISTRY_WINDOW ) &&
+ DEFINE_CLASS_DESCRIPTOR( TREE_STRUCTURE_VIEW ) &&
+ DEFINE_CLASS_DESCRIPTOR( WINDOW ) &&
+ DEFINE_CLASS_DESCRIPTOR( WINDOWS_APPLICATION ) &&
+ DEFINE_CLASS_DESCRIPTOR( REGISTRY_DATA ) &&
+ DEFINE_CLASS_DESCRIPTOR( PARTIAL_DESCRIPTOR ) &&
+ DEFINE_CLASS_DESCRIPTOR( PORT_DESCRIPTOR ) &&
+ DEFINE_CLASS_DESCRIPTOR( INTERRUPT_DESCRIPTOR ) &&
+ DEFINE_CLASS_DESCRIPTOR( MEMORY_DESCRIPTOR ) &&
+ DEFINE_CLASS_DESCRIPTOR( DMA_DESCRIPTOR ) &&
+ DEFINE_CLASS_DESCRIPTOR( DEVICE_SPECIFIC_DESCRIPTOR ) &&
+ DEFINE_CLASS_DESCRIPTOR( FULL_DESCRIPTOR ) &&
+ DEFINE_CLASS_DESCRIPTOR( RESOURCE_LIST ) &&
+ DEFINE_CLASS_DESCRIPTOR( IO_DESCRIPTOR ) &&
+ DEFINE_CLASS_DESCRIPTOR( IO_PORT_DESCRIPTOR ) &&
+ DEFINE_CLASS_DESCRIPTOR( IO_INTERRUPT_DESCRIPTOR ) &&
+ DEFINE_CLASS_DESCRIPTOR( IO_MEMORY_DESCRIPTOR ) &&
+ DEFINE_CLASS_DESCRIPTOR( IO_DMA_DESCRIPTOR ) &&
+ DEFINE_CLASS_DESCRIPTOR( IO_DESCRIPTOR_LIST ) &&
+ DEFINE_CLASS_DESCRIPTOR( IO_REQUIREMENTS_LIST )
+ ) ) {
+ DebugPrint( "Could not initialize class descriptors!");
+ return( FALSE );
+ }
+ return TRUE;
+}
+
+
+BOOLEAN
+InitializeUapp (
+ )
+
+/*++
+
+Routine Description:
+
+ Initilize Ulib by constructing and initializing all global objects. These
+ include:
+
+ - all CLASS_DESCRIPTORs (class_cd)
+ - SYSTEM (System)
+ - Standard streams
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if all global objects were succesfully constructed
+ and initialized.
+
+--*/
+
+{
+
+ STATIC BOOLEAN fInit = FALSE;
+
+ if ( fInit ) {
+
+ return( TRUE );
+ }
+
+ fInit = TRUE;
+
+ if ( DefineClassDescriptors() ) {
+ return TRUE;
+ }
+
+ DebugAbort( "Regedt32 initialization failed!!!\n" );
+ return( FALSE );
+
+}
diff --git a/private/utils/regedit/src/winapp.cxx b/private/utils/regedit/src/winapp.cxx
new file mode 100644
index 000000000..28adf5dc7
--- /dev/null
+++ b/private/utils/regedit/src/winapp.cxx
@@ -0,0 +1,331 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ Winapp.cxx
+
+Abstract:
+
+ This module contains the definition for the WINDOWS_APPLICATION
+ class. This class is used to store global data and message loop.
+
+Author:
+
+ David J. Gilman (davegi) 02-Aug-1991
+
+Environment:
+
+ Ulib, Regedit, Windows, User Mode
+
+--*/
+#include "uapp.hxx"
+#include "regedit.hxx"
+#include "winapp.hxx"
+
+#define BACKGROUND 0x000000FFL // bright blue
+#define BACKGROUNDSEL 0x00FF00FFL // bright blue
+#define BUTTONFACE 0x00C0C0C0L // bright grey
+#define BUTTONSHADOW 0x00808080L // dark grey
+
+
+/*--------------------------------------------------------------------------*/
+/* */
+/* RGBToBGR() - */
+/* */
+/*--------------------------------------------------------------------------*/
+
+DWORD NEAR PASCAL RGBToBGR(DWORD rgb)
+{
+ BYTE green;
+ BYTE blue;
+
+ green = (BYTE)((WORD)rgb >> 8);
+ blue = (BYTE)(HIWORD(rgb));
+ return(RGB(blue, green, (BYTE)rgb));
+}
+
+DWORD NEAR PASCAL FlipColor(DWORD rgb)
+{
+ return RGB(GetBValue(rgb), GetGValue(rgb), GetRValue(rgb));
+}
+
+
+DEFINE_CONSTRUCTOR( WINDOWS_APPLICATION, OBJECT );
+
+DEFINE_CAST_MEMBER_FUNCTION( WINDOWS_APPLICATION );
+
+//
+// Definitions for static class data.
+//
+
+BOOLEAN WINDOWS_APPLICATION::_ChildWindowMaximized = FALSE;
+BOOLEAN WINDOWS_APPLICATION::_SACLEditorEnabled = FALSE;
+HANDLE WINDOWS_APPLICATION::_AutoRefreshEvent;
+HWND WINDOWS_APPLICATION::_hDlgFindReplace;
+LONG WINDOWS_APPLICATION::_RestorePrivilege;
+LONG WINDOWS_APPLICATION::_BackupPrivilege;
+BOOLEAN WINDOWS_APPLICATION::_TakeOwnershipPrivilege;
+HBITMAP WINDOWS_APPLICATION::_hbmBitmaps;
+HBITMAP WINDOWS_APPLICATION::_hbmSave;
+HDC WINDOWS_APPLICATION::_hdcMem = NULL;
+HANDLE WINDOWS_APPLICATION::_Instance = 0;
+HANDLE WINDOWS_APPLICATION::_PreviousInstance = 0;
+INT WINDOWS_APPLICATION::_ShowCommand = 0;
+LPWSTR WINDOWS_APPLICATION::_CmdLine = NULL;
+LPWSTR WINDOWS_APPLICATION::_ApplicationName = NULL;
+HFONT WINDOWS_APPLICATION::_HFont;
+BOOLEAN WINDOWS_APPLICATION::_AutoRefreshEnabled;
+BOOLEAN WINDOWS_APPLICATION::_ReadOnlyMode;
+BOOLEAN WINDOWS_APPLICATION::_RemoteAccessEnabled;
+BOOLEAN WINDOWS_APPLICATION::_ConfirmOnDelete;
+BOOLEAN WINDOWS_APPLICATION::_SaveSettings;
+LONG WINDOWS_APPLICATION::_HelpContext;
+
+
+
+BOOLEAN
+WINDOWS_APPLICATION::Initialize (
+ IN HANDLE Instance,
+ IN HANDLE PreviousInstance,
+ IN INT ShowCommand,
+ IN LPWSTR CmdLine
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the WINDOWS_APPLICATION class by initializing all of its
+ internal state variables.
+
+Arguments:
+
+ Instance - Supplies the instance handle for this application.
+ PreviousInstance - Supplies the previous instance handle for this
+ application.
+ ShowCommand - Supplies the initial window state.
+
+ CmdLine - Supplies the pointer to the command line.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE.
+
+--*/
+
+{
+ _Instance = Instance;
+ _PreviousInstance = PreviousInstance;
+ _ShowCommand = ShowCommand;
+ _CmdLine = CmdLine;
+ _ApplicationName = (LPWSTR)L"Regedt32";
+ _ChildWindowMaximized = FALSE;
+
+ return TRUE;
+}
+
+
+
+HCURSOR
+WINDOWS_APPLICATION::DisplayHourGlass(
+ )
+
+/*++
+
+Routine Description:
+
+ Changes the cursor currently isplayed to the hour glass.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ HCURSOR - Handle to the cursor currently displayed.
+
+--*/
+
+{
+ HCURSOR hCursor;
+
+ hCursor = SetCursor( LoadCursor( NULL, IDC_WAIT ) );
+ ShowCursor( TRUE );
+ return( hCursor );
+
+}
+
+
+
+VOID
+WINDOWS_APPLICATION::RestoreCursor(
+ IN HCURSOR Cursor
+ )
+
+/*++
+
+Routine Description:
+
+ Replace the currently selected cursor with the one whose handle was
+ received as parameter.
+
+Arguments:
+
+ Cursor - Handle to the new cursor to be displayed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ SetCursor( Cursor );
+ ShowCursor( FALSE );
+}
+
+
+
+BOOLEAN
+WINDOWS_APPLICATION::LoadBitmaps(
+ )
+/*++
+
+Routine Description:
+
+ This routine loads DIB bitmaps, and "fixes up" their color tables
+ so that folders in the tree view appear with the right collors.
+
+ This routine requires:
+ the DIB is a 16 color DIB authored with the standard windows colors
+ bright blue (00 00 FF) is converted to the background color!
+ light grey (C0 C0 C0) is replaced with the button face color
+ dark grey (80 80 80) is replaced with the button shadow color
+
+ this means you can't have any of these colors in your bitmap
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds
+
+--*/
+
+
+{
+ HDC hdc;
+ HANDLE h;
+ DWORD FAR *p;
+ LPMBYTE lpBits;
+ HANDLE hRes;
+ LPBITMAPINFOHEADER lpBitmapInfo;
+ INT numcolors;
+ DWORD rgbSelected;
+ DWORD rgbUnselected;
+ UINT cbBitmapSize;
+ LPBITMAPINFOHEADER lpBitmapData;
+
+ rgbSelected = RGBToBGR(GetSysColor(COLOR_HIGHLIGHT));
+ rgbUnselected = RGBToBGR(GetSysColor(COLOR_WINDOW));
+
+ h = FindResource((HINSTANCE)WINDOWS_APPLICATION::QueryInstance( ),
+ (LPWSTR)L"BITMAP", RT_BITMAP);
+ hRes = LoadResource((HINSTANCE)WINDOWS_APPLICATION::QueryInstance( ), (HRSRC)h);
+
+
+ /* Lock the bitmap and get a pointer to the color table. */
+ lpBitmapData = (LPBITMAPINFOHEADER)LockResource(hRes);
+ cbBitmapSize = (UINT)SizeofResource( (HINSTANCE)WINDOWS_APPLICATION::QueryInstance( ), (HRSRC)h );
+ lpBitmapInfo = (LPBITMAPINFOHEADER)MALLOC( cbBitmapSize );
+ if( lpBitmapInfo == NULL ) {
+ UnlockResource( hRes );
+ FreeResource( hRes );
+ return( FALSE );
+ }
+ memcpy( lpBitmapInfo, lpBitmapData, cbBitmapSize );
+
+
+ p = (DWORD FAR *)((LPSTR)(lpBitmapInfo) + lpBitmapInfo->biSize);
+
+ /* Search for the Solid Blue entry and replace it with the current
+ * background RGB.
+ */
+ numcolors = 16;
+
+ while (numcolors-- > 0) {
+ if (*p == BACKGROUND)
+ *p = rgbUnselected;
+ else if (*p == BACKGROUNDSEL)
+ *p = rgbSelected;
+ else if (*p == BUTTONFACE)
+ *p = FlipColor(GetSysColor(COLOR_BTNFACE));
+ else if (*p == BUTTONSHADOW)
+ *p = FlipColor(GetSysColor(COLOR_BTNSHADOW));
+
+ p++;
+ }
+ UnlockResource(hRes);
+
+ /* Now create the DIB. */
+
+ /* First skip over the header structure */
+ lpBits = (LPMBYTE)(lpBitmapInfo + 1);
+
+ /* Skip the color table entries, if any */
+ lpBits += (1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD);
+
+ /* Create a color bitmap compatible with the display device */
+ hdc = GetDC(NULL);
+ if (_hdcMem = CreateCompatibleDC(hdc)) {
+ if (_hbmBitmaps = CreateDIBitmap( hdc, lpBitmapInfo, (DWORD)CBM_INIT,
+ lpBits, (LPBITMAPINFO)lpBitmapInfo,
+ DIB_RGB_COLORS) ) {
+ _hbmSave = (HBITMAP)SelectObject(_hdcMem, _hbmBitmaps);
+ }
+
+ }
+ ReleaseDC(NULL, hdc);
+
+ LocalUnlock(hRes);
+ FreeResource(hRes);
+ return( TRUE );
+}
+
+
+
+VOID
+WINDOWS_APPLICATION::DeleteBitmaps(
+ )
+
+/*++
+
+Routine Description:
+
+ Release the loaded bitmaps and restore the previous object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if (_hdcMem) {
+
+ SelectObject(_hdcMem, _hbmSave);
+
+ if (_hbmBitmaps)
+ DeleteObject(_hbmBitmaps);
+ DeleteDC(_hdcMem);
+ }
+}
diff --git a/private/utils/regedit/src/window.cxx b/private/utils/regedit/src/window.cxx
new file mode 100644
index 000000000..0c9978c55
--- /dev/null
+++ b/private/utils/regedit/src/window.cxx
@@ -0,0 +1,56 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ Window.hxx
+
+Abstract:
+
+ This module contains the declaration for the WINDOW class. This class
+ is very simple and abstarct is not meant to be the root of any sort of
+ sophistaicated framework.
+
+Author:
+
+ David J. Gilman (davegi) 02-Aug-1991
+
+Environment:
+
+ Ulib, Regedit, Windows, User Mode
+
+--*/
+
+
+#include "uapp.hxx"
+#include "window.hxx"
+
+DEFINE_CONSTRUCTOR( WINDOW, OBJECT );
+
+DEFINE_CAST_MEMBER_FUNCTION( WINDOW );
+
+
+VOID
+WINDOW::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Construct a WINDOW object by initializaing its internal state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _Handle = NULL;
+}
diff --git a/private/utils/replace/argument.cxx b/private/utils/replace/argument.cxx
new file mode 100644
index 000000000..7c5f18e3b
--- /dev/null
+++ b/private/utils/replace/argument.cxx
@@ -0,0 +1,422 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Argument
+
+Abstract:
+
+ Argument processing for the Replace utility
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 01-May-1991
+
+Notes:
+
+ The arguments accepted by the Replace utility are:
+
+ Source path.- Source path.
+
+ Destination path.- Destination path.
+
+ Add switch.- Adds new files to the target directory instead of
+ replacing existing one. Cannot use with Subdir
+ switch or CompareTime switch.
+
+ Prompt switch.- Prompts before adding/replacing a file.
+
+ ReadOnly switch.- Replaces red-only files as well as regular files.
+
+ Subdir switch.- Recurses along the destination path.
+
+ CompareTime switch.-Replaces only thos files on the target path that
+ are older than the corresponding file in the
+ source path.
+
+ Wait switch.- Waits for the user to type any key before starting.
+
+ Help switch.- Displays usage
+
+Revision History:
+
+
+--*/
+
+
+#include "ulib.hxx"
+#include "arg.hxx"
+#include "arrayit.hxx"
+#include "file.hxx"
+#include "system.hxx"
+#include "replace.hxx"
+
+
+#define MATCH_ALL_PATTERN "*"
+#define CURRENT_DIRECTORY (LPWSTR)L"."
+
+
+
+//
+// Global variables (global to the module)
+//
+
+PPATH_ARGUMENT SourcePathArgument = NULL;
+PPATH_ARGUMENT DestinationPathArgument = NULL;
+PFLAG_ARGUMENT AddArgument = NULL;
+PFLAG_ARGUMENT PromptArgument = NULL;
+PFLAG_ARGUMENT ReadOnlyArgument = NULL;
+PFLAG_ARGUMENT SubdirArgument = NULL;
+PFLAG_ARGUMENT CompareTimeArgument = NULL;
+PFLAG_ARGUMENT WaitArgument = NULL;
+PFLAG_ARGUMENT HelpArgument = NULL;
+
+BOOLEAN HelpSwitch;
+
+
+
+VOID
+REPLACE::SetArguments(
+ )
+
+/*++
+
+Routine Description:
+
+ Obtains the arguments for the Replace utility
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+
+ //
+ // Allocate things
+ //
+ if (//
+ // Get the argument patterns
+ //
+ !_AddPattern.Initialize( (LPWSTR)L"/A" ) ||
+ !_PromptPattern.Initialize( (LPWSTR)L"/P" ) ||
+ !_ReadOnlyPattern.Initialize( (LPWSTR)L"/R" ) ||
+ !_SubdirPattern.Initialize( (LPWSTR)L"/S" ) ||
+ !_CompareTimePattern.Initialize( (LPWSTR)L"/U" ) ||
+ !_WaitPattern.Initialize( (LPWSTR)L"/W" ) ||
+ !_HelpPattern.Initialize( (LPWSTR)L"/?" ) ||
+
+ //
+ // Get our parsing preferences
+ //
+ !_Switches.Initialize( (LPWSTR)L"/-" ) ||
+ !_MultipleSwitch.Initialize( (LPWSTR)L"/APRSUW?" ) ||
+
+ //
+ // Create the arguments
+ //
+ ((SourcePathArgument = NEW PATH_ARGUMENT) == NULL ) ||
+ ((DestinationPathArgument = NEW PATH_ARGUMENT) == NULL ) ||
+ ((AddArgument = NEW FLAG_ARGUMENT) == NULL ) ||
+ ((PromptArgument = NEW FLAG_ARGUMENT) == NULL ) ||
+ ((ReadOnlyArgument = NEW FLAG_ARGUMENT) == NULL ) ||
+ ((SubdirArgument = NEW FLAG_ARGUMENT) == NULL ) ||
+ ((CompareTimeArgument = NEW FLAG_ARGUMENT) == NULL ) ||
+ ((WaitArgument = NEW FLAG_ARGUMENT) == NULL ) ||
+ ((HelpArgument = NEW FLAG_ARGUMENT) == NULL )
+ ) {
+
+ DisplayMessageAndExit ( REPLACE_ERROR_NO_MEMORY,
+ NULL,
+ EXIT_NO_MEMORY );
+ }
+
+
+ //
+ // Parse the arguments
+ //
+ GetArgumentsCmd();
+
+ //
+ // Verify the arguments
+ //
+ CheckArgumentConsistency();
+
+ //
+ // Clean up
+ //
+ DELETE( SourcePathArgument );
+ DELETE( DestinationPathArgument );
+ DELETE( AddArgument );
+ DELETE( PromptArgument );
+ DELETE( ReadOnlyArgument );
+ DELETE( SubdirArgument );
+ DELETE( CompareTimeArgument );
+ DELETE( WaitArgument );
+ DELETE( HelpArgument );
+}
+
+VOID
+REPLACE::GetArgumentsCmd(
+ )
+
+/*++
+
+Routine Description:
+
+ Obtains the arguments from the Command line
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None
+
+Notes:
+
+--*/
+
+{
+
+ ARRAY ArgArray;
+ PATH_ARGUMENT ProgramNameArgument;
+ DSTRING CmdLine;
+
+ //
+ // Prepare for parsing
+ //
+ if (//
+ // Initialize the arguments
+ //
+ !(CmdLine.Initialize( GetCommandLine() )) ||
+ !(ArgArray.Initialize( 10, 10 )) ||
+ !(ProgramNameArgument.Initialize( MATCH_ALL_PATTERN )) ||
+ !(SourcePathArgument->Initialize( MATCH_ALL_PATTERN, FALSE)) ||
+ !(DestinationPathArgument->Initialize( MATCH_ALL_PATTERN, TRUE )) ||
+ !(AddArgument->Initialize( &_AddPattern )) ||
+ !(PromptArgument->Initialize( &_PromptPattern )) ||
+ !(ReadOnlyArgument->Initialize( &_ReadOnlyPattern )) ||
+ !(SubdirArgument->Initialize( &_SubdirPattern )) ||
+ !(CompareTimeArgument->Initialize( &_CompareTimePattern )) ||
+ !(WaitArgument->Initialize( &_WaitPattern )) ||
+ !(HelpArgument->Initialize( &_HelpPattern )) ||
+
+ //
+ // Put the arguments in the argument array
+ //
+ !(ArgArray.Put( &ProgramNameArgument )) ||
+ !(ArgArray.Put( AddArgument )) ||
+ !(ArgArray.Put( PromptArgument )) ||
+ !(ArgArray.Put( ReadOnlyArgument )) ||
+ !(ArgArray.Put( SubdirArgument )) ||
+ !(ArgArray.Put( CompareTimeArgument )) ||
+ !(ArgArray.Put( WaitArgument )) ||
+ !(ArgArray.Put( HelpArgument )) ||
+ !(ArgArray.Put( SourcePathArgument )) ||
+ !(ArgArray.Put( DestinationPathArgument ))
+ ) {
+
+ DisplayMessageAndExit( REPLACE_ERROR_NO_MEMORY,
+ NULL,
+ EXIT_NO_MEMORY );
+ }
+
+ //
+ // Parse the arguments
+ //
+ ParseArguments( &CmdLine, &ArgArray );
+
+ //
+ // Set the switches
+ //
+ _AddSwitch = AddArgument->QueryFlag();
+ _PromptSwitch = PromptArgument->QueryFlag();
+ _ReadOnlySwitch = ReadOnlyArgument->QueryFlag();
+ _SubdirSwitch = SubdirArgument->QueryFlag();
+ _CompareTimeSwitch = CompareTimeArgument->QueryFlag();
+ _WaitSwitch = WaitArgument->QueryFlag();
+ HelpSwitch = HelpArgument->QueryFlag();
+
+ //
+ // Set the source and destination paths.
+ //
+ if ( SourcePathArgument->IsValueSet() ) {
+ if ((_SourcePath = SourcePathArgument->GetPath()->QueryPath()) == NULL ) {
+ DisplayMessageAndExit( REPLACE_ERROR_NO_MEMORY, NULL, EXIT_NO_MEMORY );
+ }
+ } else {
+ _SourcePath = NULL;
+ }
+
+ if ( DestinationPathArgument->IsValueSet() ) {
+ if ((_DestinationPath = DestinationPathArgument->GetPath()->QueryFullPath()) == NULL ) {
+ DisplayMessageAndExit( REPLACE_ERROR_NO_MEMORY, NULL, EXIT_NO_MEMORY );
+ }
+ } else {
+ _DestinationPath = NULL;
+ }
+
+}
+
+VOID
+REPLACE::ParseArguments(
+ IN PWSTRING CmdLine,
+ OUT PARRAY ArgArray
+ )
+
+/*++
+
+Routine Description:
+
+ Parses a group of arguments
+
+Arguments:
+
+ CmdLine - Supplies pointer to a command line to parse
+ ArgArray - Supplies pointer to array of arguments
+
+Return Value:
+
+ none
+
+Notes:
+
+--*/
+
+{
+ ARGUMENT_LEXEMIZER ArgLex;
+ ARRAY LexArray;
+
+ //
+ // Initialize lexeme array and the lexemizer.
+ //
+ if ( !(LexArray.Initialize( 8, 8 )) ||
+ !(ArgLex.Initialize( &LexArray )) ) {
+
+ DisplayMessageAndExit( REPLACE_ERROR_NO_MEMORY,
+ NULL,
+ EXIT_NO_MEMORY );
+
+ }
+
+ //
+ // Set our parsing preferences
+ //
+ ArgLex.PutMultipleSwitch( &_MultipleSwitch );
+ ArgLex.PutSwitches( &_Switches );
+ ArgLex.SetCaseSensitive( FALSE );
+ ArgLex.PutSeparators( " /\t" );
+ ArgLex.PutStartQuotes( "\"" );
+ ArgLex.PutEndQuotes( "\"" );
+
+
+ //
+ // Parse the arguments
+ //
+ if ( !(ArgLex.PrepareToParse( CmdLine ))) {
+
+ DisplayMessageAndExit( REPLACE_ERROR_PARSE,
+ NULL,
+ EXIT_COMMAND_LINE_ERROR );
+
+ }
+
+ if ( !ArgLex.DoParsing( ArgArray ) ) {
+
+ DisplayMessageAndExit( REPLACE_ERROR_INVALID_SWITCH,
+ ArgLex.QueryInvalidArgument(),
+ EXIT_COMMAND_LINE_ERROR );
+ }
+
+
+}
+
+VOID
+REPLACE::CheckArgumentConsistency (
+ )
+
+/*++
+
+Routine Description:
+
+ Checks the consistency of the arguments
+
+Arguments:
+
+ none
+
+Return Value:
+
+ none
+
+Notes:
+
+--*/
+
+{
+
+ PFSN_FILE File = NULL;
+
+ if ( HelpSwitch ) {
+ //
+ // Help requested
+ //
+ Usage();
+ }
+
+
+ //
+ // Make sure that we have a source path
+ //
+ if ( _SourcePath == NULL ) {
+
+ DisplayMessageAndExit( REPLACE_ERROR_SOURCE_PATH_REQUIRED,
+ NULL,
+ EXIT_COMMAND_LINE_ERROR );
+ }
+
+ //
+ // The add switch cannot be specified together with the Subdir or the
+ // CompareTime switch.
+ //
+ if ( _AddSwitch && (_SubdirSwitch || _CompareTimeSwitch)) {
+
+ DisplayMessageAndExit( REPLACE_ERROR_INVALID_PARAMETER_COMBINATION,
+ NULL,
+ EXIT_COMMAND_LINE_ERROR );
+
+ }
+
+ //
+ // If destination path is null, then the destination path is the
+ // current directory
+ //
+ if ( _DestinationPath == NULL ) {
+
+ if ( ((_DestinationPath = NEW PATH) == NULL ) ||
+ !_DestinationPath->Initialize( CURRENT_DIRECTORY, TRUE ) ) {
+
+ DisplayMessageAndExit( REPLACE_ERROR_NO_MEMORY,
+ NULL,
+ EXIT_NO_MEMORY );
+ }
+ } else if ( (_DestinationPath->HasWildCard()) ||
+ ((File = SYSTEM::QueryFile( _DestinationPath )) != NULL) ) {
+ DisplayMessageAndExit( REPLACE_ERROR_PATH_NOT_FOUND,
+ _DestinationPath->GetPathString(),
+ EXIT_PATH_NOT_FOUND );
+ }
+
+ DELETE( File );
+}
diff --git a/private/utils/replace/makefile b/private/utils/replace/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/replace/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/replace/makefile.inc b/private/utils/replace/makefile.inc
new file mode 100644
index 000000000..6c93eb38d
--- /dev/null
+++ b/private/utils/replace/makefile.inc
@@ -0,0 +1,12 @@
+{}.cxx{obj\i386\}.obj:
+ $(386_COMPILER) -Fo$@ $(MAKEDIR)\$(<F)
+
+{}.cxx{obj\mips\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClMips $< " $(C_COMPILER) "
+ @$(C_COMPILER) -Fo$@ $(MAKEDIR)\$<
+
+{}.cxx{obj\alpha\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClAlpha $< " $(ALPHA_COMPILER) "
+ @$(ALPHA_COMPILER) -Fo$@ $(MAKEDIR)\$<
diff --git a/private/utils/replace/replace.cxx b/private/utils/replace/replace.cxx
new file mode 100644
index 000000000..93301ea2e
--- /dev/null
+++ b/private/utils/replace/replace.cxx
@@ -0,0 +1,948 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Replace
+
+Abstract:
+
+ Replace utility
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 01-May-1991
+
+Revision History:
+
+--*/
+
+#include "ulib.hxx"
+#include "arrayit.hxx"
+#include "dir.hxx"
+#include "filter.hxx"
+#include "file.hxx"
+#include "fsnode.hxx"
+#include "stream.hxx"
+#include "substrng.hxx"
+#include "system.hxx"
+#include "replace.hxx"
+#include "error.hxx"
+
+
+
+
+//
+// Pattern that matches all files in a directory
+//
+#define MATCH_ALL_FILES "*.*"
+
+
+#define CTRL_C (WCHAR)3
+
+
+
+//
+// Size of buffers to hold path strings
+//
+#define INITIAL_PATHSTRING_BUFFER_SIZE MAX_PATH
+
+
+//
+// Needed by ULIB, but apparently not used by anyone.
+//
+ERRSTACK *perrstk;
+
+
+
+VOID _CRTAPI1
+main (
+ )
+
+/*++
+
+Routine Description:
+
+ Main function of the Replace utility
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ //
+ // Initialize stuff
+ //
+ DEFINE_CLASS_DESCRIPTOR( REPLACE );
+
+ //
+ // Now do the replacement
+ //
+ {
+ REPLACE Replace;
+
+ //
+ // Initialize the Replace object.
+ //
+ Replace.Initialize();
+
+ //
+ // Do our thing
+ //
+ Replace.DoReplace();
+ }
+}
+
+
+
+
+DEFINE_CONSTRUCTOR( REPLACE, PROGRAM );
+
+
+
+BOOLEAN
+REPLACE::Initialize (
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes the REPLACE object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if initialized, FALSE otherwise
+
+Notes:
+
+--*/
+
+{
+ //
+ // Initialize program object
+ //
+ PROGRAM::Initialize( REPLACE_MESSAGE_USAGE );
+
+ //
+ // Allocate global structures and initialize them
+ //
+ InitializeThings();
+
+ //
+ // Parse the arguments
+ //
+ SetArguments();
+
+ return TRUE;
+}
+
+REPLACE::~REPLACE (
+ )
+
+/*++
+
+Routine Description:
+
+ Destructs a REPLACE object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ //
+ // Deallocate the global structures previously allocated
+ //
+ DeallocateThings();
+
+ //
+ // Exit without error
+ //
+ DisplayMessageAndExit( 0, NULL, EXIT_NORMAL );
+
+}
+
+VOID
+REPLACE::InitializeThings (
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes the global variables that need initialization
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+
+ //
+ // Initialize the path string buffers
+ //
+ _PathString1 = (LPWSTR)MALLOC( INITIAL_PATHSTRING_BUFFER_SIZE );
+ _PathString2 = (LPWSTR)MALLOC( INITIAL_PATHSTRING_BUFFER_SIZE );
+
+ _PathString1Size = _PathString2Size = INITIAL_PATHSTRING_BUFFER_SIZE;
+
+ _Keyboard = NEW KEYBOARD;
+
+ if ( !_PathString1 || !_PathString2 || !_Keyboard ) {
+ DisplayMessageAndExit( REPLACE_ERROR_NO_MEMORY, NULL, EXIT_NO_MEMORY );
+ }
+
+ //
+ // initialize the keyboard and set ctrl-c handling
+ //
+ _Keyboard->Initialize();
+ _Keyboard->EnableBreakHandling();
+
+ //
+ // Initialize our data
+ //
+ _SourcePath = NULL;
+ _DestinationPath = NULL;
+ _FilesAdded = 0;
+ _FilesReplaced = 0;
+ _SourceDirectory = NULL;
+ _Pattern = NULL;
+ _FilesInSrc = NULL;
+
+ _AddSwitch = FALSE; // use by DisplayMessageAndExit before any
+ // of those boolean _*Switch is being initialized
+
+
+}
+
+VOID
+REPLACE::DeallocateThings (
+ )
+
+/*++
+
+Routine Description:
+
+ Deallocates the stuff that was initialized in InitializeThings()
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+
+ DELETE( _FilesInSrc );
+ DELETE( _SourceDirectory );
+ DELETE( _Pattern );
+ DELETE( _Keyboard );
+
+ FREE( _PathString1 );
+ FREE( _PathString2 );
+
+}
+
+BOOLEAN
+REPLACE::DoReplace (
+ )
+
+/*++
+
+Routine Description:
+
+ This is the function that performs the Replace.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE
+
+Notes:
+
+--*/
+
+{
+
+ PFSN_DIRECTORY DestinationDirectory;
+ FSN_FILTER Filter;
+ WCHAR Char;
+
+ //
+ // Get the source directory object and the pattern that we will use
+ // for file matching.
+ //
+ GetDirectoryAndPattern( _SourcePath, &_SourceDirectory, &_Pattern );
+
+ DebugPtrAssert( _SourceDirectory );
+ DebugPtrAssert( _Pattern );
+
+ //
+ // Get the destination directory
+ //
+ GetDirectory( _DestinationPath, &DestinationDirectory );
+
+ DebugPtrAssert( DestinationDirectory );
+
+ //
+ // Wait if requested
+ //
+ if ( _WaitSwitch ) {
+
+ DisplayMessage( REPLACE_MESSAGE_PRESS_ANY_KEY );
+ AbortIfCtrlC();
+
+ //
+ // All input is in raw mode.
+ //
+ _Keyboard->DisableLineMode();
+ GetStandardInput()->ReadChar( &Char );
+ _Keyboard->EnableLineMode();
+
+ GetStandardOutput()->WriteChar( Char );
+ GetStandardOutput()->WriteChar( (WCHAR)'\r');
+ GetStandardOutput()->WriteChar( (WCHAR)'\n');
+
+ //
+ // Check for ctrl-c
+ //
+ if ( Char == CTRL_C ) {
+ exit ( EXIT_PATH_NOT_FOUND );
+ }
+ }
+
+ //
+ // Get an array containing all the files in the source directory
+ // that match the pattern.
+ //
+ // This is so that Replacer() does not have to get the same
+ // information over and over when the Subdir switch is set.
+ //
+ _FilesInSrc = GetFileArray( _SourceDirectory, _Pattern );
+ DebugPtrAssert( _FilesInSrc );
+
+ if ( _SubdirSwitch ) {
+
+ //
+ // First, replace the files in the directory specified
+ //
+ Replacer( this, DestinationDirectory, NULL );
+
+ Filter.Initialize();
+ Filter.SetAttributes( (FSN_ATTRIBUTE)FILE_ATTRIBUTE_DIRECTORY );
+
+ //
+ // Now traverse the destination directory, calling the
+ // replacer function for each subdirectory.
+ //
+ DestinationDirectory->Traverse( this,
+ &Filter,
+ NULL,
+ REPLACE::Replacer );
+ } else {
+
+ //
+ // Call the replace function, which takes care of replacements
+ //
+ Replacer(this, DestinationDirectory, NULL );
+ }
+ DELETE( DestinationDirectory );
+
+ return TRUE;
+
+}
+
+VOID
+REPLACE::GetDirectoryAndPattern(
+ IN PPATH Path,
+ OUT PFSN_DIRECTORY *Directory,
+ OUT PWSTRING *Pattern
+ )
+
+/*++
+
+Routine Description:
+
+ Given a path, this function obtains a directory object and a pattern.
+
+ Normally, the pattern is the filename portion of the path, but if the
+ entire path refers to a directory, then the pattern is "*.*"
+
+Arguments:
+
+ Path - Supplies pointer to path
+ Directory - Supplies pointer to pointer to directory
+ Pattern - Supplies pointer to pointer to pattern
+
+Return Value:
+
+ TRUE
+
+Notes:
+
+--*/
+
+{
+ PATH TmpPath;
+ PWSTRING Name;
+ PFSN_DIRECTORY Dir;
+ PWSTRING Ptrn;
+
+ DebugAssert( Path );
+ DebugAssert( Directory );
+ DebugAssert( Pattern );
+
+ //
+ // If the name passed is a directory, it is an error.
+ // Otherwise, split the path into Directory and Pattern
+ // portions.
+ //
+ Dir = SYSTEM::QueryDirectory( Path );
+
+ if ( Dir ||
+ (Name = Path->QueryName()) == NULL ||
+ (Ptrn = Name->QueryString()) == NULL ) {
+
+ DisplayMessageAndExit( REPLACE_ERROR_NO_FILES_FOUND,
+ Path->GetPathString(),
+ EXIT_FILE_NOT_FOUND );
+
+ } else {
+
+ // We're finished with Name.
+ //
+ DELETE( Name );
+
+ //
+ // Get the directory
+ //
+ TmpPath.Initialize( Path, TRUE );
+ TmpPath.TruncateBase();
+
+ Dir = SYSTEM::QueryDirectory( &TmpPath );
+
+ if ( !Dir ) {
+
+ DisplayMessageAndExit( REPLACE_ERROR_PATH_NOT_FOUND,
+ Path->GetPathString(),
+ EXIT_PATH_NOT_FOUND );
+ }
+
+ *Directory = Dir;
+ *Pattern = Ptrn;
+ }
+}
+
+VOID
+REPLACE::GetDirectory(
+ IN PCPATH Path,
+ OUT PFSN_DIRECTORY *Directory
+ )
+
+/*++
+
+Routine Description:
+
+ Makes a directory out of a path.
+
+Arguments:
+
+ Path - Supplies pointer to path
+ Directory - Supplies pointer to pointer to directory
+
+Return Value:
+
+ TRUE
+
+Notes:
+
+--*/
+
+{
+ PFSN_DIRECTORY Dir;
+
+
+ if ( !(Dir = SYSTEM::QueryDirectory( Path )) ) {
+
+ DisplayMessageAndExit( REPLACE_ERROR_PATH_NOT_FOUND,
+ Path->GetPathString(),
+ EXIT_PATH_NOT_FOUND );
+ }
+
+ *Directory = Dir;
+
+}
+
+PARRAY
+REPLACE::GetFileArray(
+ IN PFSN_DIRECTORY Directory,
+ IN PWSTRING Pattern
+ )
+
+/*++
+
+Routine Description:
+
+ Gets an array of those files in a directory matching a pattern.
+
+Arguments:
+
+ Directory - Supplies pointer to directory
+ Pattern - Supplies pointer to pattern
+
+Return Value:
+
+ Pointer to the array of files
+
+Notes:
+
+--*/
+{
+
+ PARRAY Array;
+ FSN_FILTER Filter;
+
+ DebugPtrAssert( Directory );
+ DebugPtrAssert( Pattern );
+
+ Filter.Initialize();
+ Filter.SetFileName( Pattern );
+ Filter.SetAttributes( (FSN_ATTRIBUTE)0, (FSN_ATTRIBUTE)0, (FSN_ATTRIBUTE)FILE_ATTRIBUTE_DIRECTORY );
+
+ Array = Directory->QueryFsnodeArray( &Filter );
+
+ DebugPtrAssert( Array );
+
+ return Array;
+
+}
+
+BOOLEAN
+REPLACE::Replacer (
+ IN PVOID This,
+ IN OUT PFSNODE DirectoryNode,
+ IN PPATH DummyPath
+ )
+/*++
+
+Routine Description:
+
+ This is the heart of Replace. Given a destination directory, it
+ performs the replacement/additions according to the global switches
+ and the SourceDirectory and Pattern.
+
+Arguments:
+
+ This - Supplies pointer to the REPLACE object
+ Node - Supplies pointer to the directory node.
+ DummyPath - Required by FSN_DIRECTORY::Traverse(), must be
+ NULL.
+
+Return Value:
+
+ BOOLEAN - TRUE if operation successful.
+ FALSE otherwise
+
+Notes:
+
+--*/
+
+{
+
+ DebugAssert( DummyPath == NULL );
+ DebugAssert( DirectoryNode->IsDirectory() );
+
+ ((PREPLACE)This)->AbortIfCtrlC();
+
+ if ( ((PREPLACE)This)->_AddSwitch ) {
+ return ((PREPLACE)This)->AddFiles( (PFSN_DIRECTORY)DirectoryNode );
+ } else {
+ return ((PREPLACE)This)->ReplaceFiles( (PFSN_DIRECTORY)DirectoryNode );
+ }
+}
+
+BOOLEAN
+REPLACE::AddFiles (
+ IN OUT PFSN_DIRECTORY DestinationDirectory
+ )
+/*++
+
+Routine Description:
+
+ Adds those files from the SourceDirectory that match Pattern to the
+ DestinationDirectory. The array of files is already in the
+ FilesInSrc array.
+
+Arguments:
+
+ DestinationDirectory - Supplies pointer to destination
+ directory.
+
+Return Value:
+
+ BOOLEAN - TRUE if operation successful.
+ FALSE otherwise
+
+Notes:
+
+--*/
+
+{
+
+ PARRAY_ITERATOR Iterator;
+ PFSN_FILE File;
+ PFSN_FILE FileToCreate;
+ PATH DestinationPath;
+ PWSTRING Name;
+
+ DebugPtrAssert( DestinationDirectory );
+ DebugPtrAssert( _FilesInSrc );
+
+ //
+ // Get destination path
+ //
+ DestinationPath.Initialize( DestinationDirectory->GetPath() );
+
+ //
+ // Obtain an iterator for going thru the files
+ //
+ Iterator = ( PARRAY_ITERATOR )_FilesInSrc->QueryIterator( );
+ DebugPtrAssert( Iterator );
+
+ //
+ // For each file in the array, see if it exists in the destination
+ // directory, and if it does not, then copy it.
+ //
+ while ( File = (PFSN_FILE)Iterator->GetNext() ) {
+
+ DebugAssert( !(((PFSNODE)File)->IsDirectory()) );
+
+ Name = File->QueryName();
+ DebugPtrAssert( Name );
+
+ //
+ // Form the path in the target file
+ //
+ DestinationPath.AppendBase( Name );
+
+ //
+ // See if the file exists
+ //
+ FileToCreate = SYSTEM::QueryFile( &DestinationPath );
+
+ //
+ // If the file does not exist, then it has to be added
+ //
+ if ( !FileToCreate ) {
+
+ if ( !_PromptSwitch || Prompt( REPLACE_MESSAGE_ADD_YES_NO, &DestinationPath ) ) {
+
+ DisplayMessage( REPLACE_MESSAGE_ADDING, NORMAL_MESSAGE, "%W", DestinationPath.GetPathString() );
+
+ CopyTheFile( File->GetPath(), &DestinationPath );
+
+ _FilesAdded++;
+ }
+
+ }
+
+ DELETE( FileToCreate );
+
+ //
+ // Set the destination path back to what it originally was
+ // ( i.e. directory specification, no file ).
+ //
+ DestinationPath.TruncateBase();
+
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+REPLACE::ReplaceFiles (
+ IN OUT PFSN_DIRECTORY DestinationDirectory
+ )
+/*++
+
+Routine Description:
+
+ Replaces those files in the DestinationDirectory that match Pattern
+ by the corresponding files in SourceDirectory.
+
+Arguments:
+
+ DestinationDirectory - Supplies pointer to destination
+ directory.
+
+Return Value:
+
+ BOOLEAN - TRUE if operation successful.
+ FALSE otherwise
+
+Notes:
+
+--*/
+
+{
+
+ PARRAY_ITERATOR Iterator;
+ PFSN_FILE File;
+ PFSN_FILE FileToReplace;
+ PATH DestinationPath;
+ PWSTRING Name;
+ PTIMEINFO TimeSrc;
+ PTIMEINFO TimeDst;
+ BOOLEAN Proceed = TRUE;
+
+ DebugPtrAssert( DestinationDirectory );
+ DebugPtrAssert( _FilesInSrc );
+
+ //
+ // Get destination path
+ //
+ DestinationPath.Initialize( DestinationDirectory->GetPath() );
+
+ //
+ // Obtain an iterator for going thru the files
+ //
+ Iterator = ( PARRAY_ITERATOR )_FilesInSrc->QueryIterator( );
+ DebugPtrAssert( Iterator );
+
+ //
+ // For each file in the array, see if it exists in the destination
+ // directory, and if it does, replace it
+ //
+ while ( File = (PFSN_FILE)Iterator->GetNext() ) {
+
+ AbortIfCtrlC();
+
+ DebugAssert( !(((PFSNODE)File)->IsDirectory()) );
+
+ Name = File->QueryName();
+ DebugPtrAssert( Name );
+
+ //
+ // Form the path in the target file
+ //
+ DestinationPath.AppendBase( Name );
+
+ //
+ // See if the file exists
+ //
+ FileToReplace = SYSTEM::QueryFile( &DestinationPath );
+
+
+ if ( FileToReplace ) {
+
+ //
+ // If the CompareTime switch is set, then we only proceed if
+ // the destination file is older than the source file.
+ //
+ if ( _CompareTimeSwitch ) {
+
+ TimeSrc = File->QueryTimeInfo();
+ TimeDst = FileToReplace->QueryTimeInfo();
+
+ DebugPtrAssert( TimeSrc );
+ DebugPtrAssert( TimeDst );
+
+ Proceed = *TimeDst < *TimeSrc;
+
+ DELETE( TimeSrc );
+ DELETE( TimeDst );
+
+ }
+
+ if ( Proceed ) {
+
+ //
+ // We replace the file if it is NOT read-only
+ // (unless the ReadOnly switch is set )
+ //
+ if ( _ReadOnlySwitch || !(FileToReplace->IsReadOnly()) ) {
+
+ if ( !_PromptSwitch || Prompt( REPLACE_MESSAGE_REPLACE_YES_NO, &DestinationPath ) ) {
+
+ DisplayMessage( REPLACE_MESSAGE_REPLACING, NORMAL_MESSAGE, "%W", DestinationPath.GetPathString() );
+
+ //
+ // If the file is read-only, we reset the read-only attribute
+ // before copying.
+ //
+ if ( FileToReplace->IsReadOnly() ) {
+ FileToReplace->ResetReadOnlyAttribute();
+ }
+
+ CopyTheFile( File->GetPath(), &DestinationPath );
+
+ _FilesReplaced++;
+ }
+ } else {
+
+ //
+ // The file is read-only but the ReadOnly flag was
+ // not set, we error out.
+ //
+ DisplayMessageAndExit( REPLACE_ERROR_ACCESS_DENIED,
+ DestinationPath.GetPathString(),
+ EXIT_ACCESS_DENIED );
+ }
+ }
+ }
+
+ DELETE( FileToReplace );
+
+ //
+ // Set the destination path back to what it originally was
+ // ( i.e. directory specification, no file name part ).
+ //
+ DestinationPath.TruncateBase();
+
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+REPLACE::Prompt (
+ IN MSGID MessageId,
+ IN PCPATH Path
+ )
+
+/*++
+
+Routine Description:
+
+ Gets confirmation from the user about a file to be added/replaced
+
+Arguments:
+
+ MessageId - Supplies the Id of the message to use for prompting
+ Path - Supplies path to use as parameter for the message.
+
+Return Value:
+
+ BOOLEAN - TRUE if the user confirmed the add/replace
+ FALSE otherwise
+
+--*/
+
+{
+
+ DisplayMessage( MessageId, NORMAL_MESSAGE, "%W", Path->GetPathString() );
+ return _Message.IsYesResponse();
+
+}
+
+BOOLEAN
+REPLACE::CopyTheFile (
+ IN PCPATH SrcPath,
+ IN PCPATH DstPath
+ )
+
+/*++
+
+Routine Description:
+
+ Copies a file
+
+Arguments:
+
+ SrcPath - Supplies path of source file
+ DstFile - Supplies path of destination file
+
+Return Value:
+
+ BOOLEAN - TRUE
+
+--*/
+
+{
+
+ ULONG Size;
+
+ DebugPtrAssert( SrcPath );
+ DebugPtrAssert( DstPath );
+
+ //
+ // Make sure that the buffers are big enough to hold the
+ // paths
+ //
+ Size = (SrcPath->GetPathString()->QueryChCount() + 1) * 2;
+ if ( Size > _PathString1Size ) {
+ _PathString1 = (LPWSTR)REALLOC( _PathString1, (unsigned int)Size );
+ DebugPtrAssert( _PathString1 );
+ _PathString1Size = Size;
+ }
+
+ Size = (DstPath->GetPathString()->QueryChCount() + 1) * 2;
+ if ( Size > _PathString2Size ) {
+ _PathString2 = (LPWSTR)REALLOC( _PathString2, (unsigned int)Size );
+ DebugPtrAssert( _PathString2 );
+ _PathString2Size = Size;
+ }
+
+ if ( !_PathString1 || !_PathString2 ) {
+ DisplayMessageAndExit( REPLACE_ERROR_NO_MEMORY, NULL, EXIT_NO_MEMORY );
+
+ }
+
+ //
+ // Convert the paths to LPWSTR so that we can call CopyFile()
+ //
+ SrcPath->GetPathString()->QueryWSTR( 0, TO_END, _PathString1, _PathString1Size );
+ DstPath->GetPathString()->QueryWSTR( 0, TO_END, _PathString2, _PathString2Size );
+
+ //
+ // Now do the copy
+ //
+ if ( !CopyFile( _PathString1, _PathString2, FALSE ) ) {
+
+ ExitWithError( GetLastError() );
+
+ }
+
+ return TRUE;
+
+}
+
diff --git a/private/utils/replace/replace.hxx b/private/utils/replace/replace.hxx
new file mode 100644
index 000000000..ec93c462b
--- /dev/null
+++ b/private/utils/replace/replace.hxx
@@ -0,0 +1,289 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Replace
+
+Abstract:
+
+ This module contains the definition for the REPLACE class, which
+ implements the DOS5-compatible Replace utility.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 01-May-1990
+
+
+Revision History:
+
+
+--*/
+
+
+#if !defined( _REPLACE_ )
+
+#define _REPLACE_
+
+
+#include "object.hxx"
+#include "keyboard.hxx"
+#include "program.hxx"
+
+//
+// Exit codes
+//
+#define EXIT_NORMAL 0
+#define EXIT_FILE_NOT_FOUND 2
+#define EXIT_PATH_NOT_FOUND 3
+#define EXIT_ACCESS_DENIED 5
+#define EXIT_NO_MEMORY 8
+#define EXIT_COMMAND_LINE_ERROR 11
+#define EXIT_INVALID_DRIVE 15
+
+
+//
+// Forward references
+//
+DECLARE_CLASS( ARRAY );
+DECLARE_CLASS( FSN_DIRECTORY );
+DECLARE_CLASS( FSNODE );
+DECLARE_CLASS( KEYBOARD );
+DECLARE_CLSSS( PATH );
+DECLARE_CLASS( WSTRING );
+
+DECLARE_CLASS( REPLACE );
+
+class REPLACE : public PROGRAM {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( REPLACE );
+
+ NONVIRTUAL
+ ~REPLACE (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DoReplace (
+ );
+
+
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ AbortIfCtrlC(
+ VOID
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AddFiles (
+ IN OUT PFSN_DIRECTORY DestinationDirectory
+ );
+
+ NONVIRTUAL
+ VOID
+ CheckArgumentConsistency (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CopyTheFile (
+ IN PCPATH SrcPath,
+ IN PCPATH DstPath
+ );
+
+ NONVIRTUAL
+ VOID
+ CtrlCHandler (
+ IN ULONG CtrlType
+ );
+
+ NONVIRTUAL
+ VOID
+ DeallocateThings (
+ );
+
+ NONVIRTUAL
+ VOID
+ DisplayMessageAndExit (
+ IN MSGID MsgId,
+ IN PCWSTRING String,
+ IN ULONG ExitCode
+ );
+
+ NONVIRTUAL
+ VOID
+ ExitWithError(
+ IN DWORD ErrorCode
+ );
+
+ NONVIRTUAL
+ VOID
+ GetArgumentsCmd(
+ );
+
+ NONVIRTUAL
+ VOID
+ GetDirectoryAndPattern(
+ IN PPATH Path,
+ OUT PFSN_DIRECTORY *Directory,
+ OUT PWSTRING *Pattern
+ );
+
+ NONVIRTUAL
+ VOID
+ GetDirectory(
+ IN PCPATH Path,
+ OUT PFSN_DIRECTORY *Directory
+ );
+
+ NONVIRTUAL
+ PARRAY
+ GetFileArray(
+ IN PFSN_DIRECTORY Directory,
+ IN PWSTRING Pattern
+ );
+
+ NONVIRTUAL
+ VOID
+ InitializeThings (
+ );
+
+ NONVIRTUAL
+ VOID
+ ParseArguments(
+ IN PWSTRING CmdLine,
+ OUT PARRAY ArgArray
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Prompt (
+ IN MSGID MessageId,
+ IN PCPATH Path
+ );
+
+ NONVIRTUAL
+ PWSTRING
+ QueryMessageString (
+ IN MSGID MsgId
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ReplaceFiles (
+ IN OUT PFSN_DIRECTORY DestinationDirectory
+ );
+
+ STATIC
+ BOOLEAN
+ Replacer (
+ IN PVOID This,
+ IN OUT PFSNODE DirectoryNode,
+ IN PPATH DummyPath
+ );
+
+ NONVIRTUAL
+ VOID
+ SetArguments(
+ );
+ //
+ // Command-line things
+ //
+ PPATH _SourcePath;
+ PPATH _DestinationPath;
+ BOOLEAN _AddSwitch;
+ BOOLEAN _PromptSwitch;
+ BOOLEAN _ReadOnlySwitch;
+ BOOLEAN _SubdirSwitch;
+ BOOLEAN _CompareTimeSwitch;
+ BOOLEAN _WaitSwitch;
+
+ //
+ // Counter of Added/Replaced files
+ //
+ ULONG _FilesAdded;
+ ULONG _FilesReplaced;
+
+ //
+ // Source directory and corresponding filename pattern
+ //
+ PFSN_DIRECTORY _SourceDirectory;
+ PWSTRING _Pattern;
+
+ //
+ // Array of files in source directory
+ //
+ PARRAY _FilesInSrc;
+
+ //
+ // Buffers to hold strings in PSTR form
+ //
+ LPWSTR _PathString1;
+ ULONG _PathString1Size;
+ LPWSTR _PathString2;
+ ULONG _PathString2Size;
+
+ //
+ // The keyboard
+ //
+ PKEYBOARD _Keyboard;
+
+ DSTRING _AddPattern;
+ DSTRING _PromptPattern;
+ DSTRING _ReadOnlyPattern;
+ DSTRING _SubdirPattern;
+ DSTRING _CompareTimePattern;
+ DSTRING _WaitPattern;
+ DSTRING _HelpPattern;
+
+ DSTRING _Switches;
+ DSTRING _MultipleSwitch;
+
+
+};
+
+INLINE
+VOID
+REPLACE::AbortIfCtrlC (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Aborts the program if Ctrl-C was hit.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ if ( _Keyboard->GotABreak() ) {
+ exit( EXIT_PATH_NOT_FOUND );
+ }
+
+}
+
+
+#endif // _REPLACE_
diff --git a/private/utils/replace/replace.rc b/private/utils/replace/replace.rc
new file mode 100644
index 000000000..5653d4c92
--- /dev/null
+++ b/private/utils/replace/replace.rc
@@ -0,0 +1,11 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Replace File Utility"
+#define VER_INTERNALNAME_STR "replace\0"
+#define VER_ORIGINALFILENAME_STR "REPLACE.EXE"
+
+#include "common.ver"
+
diff --git a/private/utils/replace/sources b/private/utils/replace/sources
new file mode 100644
index 000000000..5a6dc5b8e
--- /dev/null
+++ b/private/utils/replace/sources
@@ -0,0 +1,62 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+BLDCRT=1
+
+MAJORCOMP=utils
+MINORCOMP=replace
+
+TARGETNAME=replace
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=argument.cxx \
+ support.cxx \
+ replace.rc
+
+INCLUDES=..\ulib\inc;\nt\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+CXXFLAGS=+d
+UMLIBS=..\ulib\src\obj\*\ulib.lib obj\*\replace.lib \nt\public\sdk\lib\*\ntdll.lib
+
+UMTYPE=console
+
+UMAPPL=replace
+UMRES=obj\*\replace.res
diff --git a/private/utils/replace/support.cxx b/private/utils/replace/support.cxx
new file mode 100644
index 000000000..190a45f7c
--- /dev/null
+++ b/private/utils/replace/support.cxx
@@ -0,0 +1,156 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Support
+
+Abstract:
+
+ Miscelaneous support functions for the Replace utility.
+
+ All functions that are not involved directly in the adding\replacing
+ of files go here.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 02-May-1991
+
+Revision History:
+
+--*/
+
+
+
+#include "ulib.hxx"
+#include "system.hxx"
+#include "replace.hxx"
+
+
+
+
+
+VOID
+REPLACE::DisplayMessageAndExit (
+ IN MSGID MsgId,
+ IN PCWSTRING String,
+ IN ULONG ExitCode
+ )
+
+/*++
+
+Routine Description:
+
+ Displays a message and exits the program with the supplied error code.
+ We support a maximum of one string parameter for the message.
+
+Arguments:
+
+ MsgId - Supplies the Id of the message to display.
+ String - Supplies a string parameter for the message.
+ ExitCode - Supplies the exit code with which to exit.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+
+ PATH Path;
+
+ if ( MsgId != 0 ) {
+ if ( String ) {
+ DisplayMessage( MsgId, ERROR_MESSAGE, "%W", String );
+ } else {
+ DisplayMessage( MsgId, ERROR_MESSAGE, "" );
+ }
+ }
+ //
+ // Display the number of files added/ replaced.
+ //
+ if ( _AddSwitch ) {
+
+ if ( _FilesAdded == 0 ) {
+ DisplayMessage( REPLACE_MESSAGE_NO_FILES_ADDED );
+ } else {
+ DisplayMessage( REPLACE_MESSAGE_FILES_ADDED, NORMAL_MESSAGE, "%d", _FilesAdded );
+ }
+
+ } else {
+
+ if ( _FilesReplaced == 0 ) {
+ DisplayMessage( REPLACE_MESSAGE_NO_FILES_REPLACED );
+ } else {
+ DisplayMessage( REPLACE_MESSAGE_FILES_REPLACED, NORMAL_MESSAGE, "%d", _FilesReplaced );
+ }
+ }
+
+ exit( (int)ExitCode );
+
+}
+
+PWSTRING
+REPLACE::QueryMessageString (
+ IN MSGID MsgId
+ )
+/*++
+
+Routine Description:
+
+ Obtains a string object initialized to the contents of some message
+
+Arguments:
+
+ MsgId - Supplies ID of the message
+
+Return Value:
+
+ PWSTRING - Pointer to initialized string object
+
+Notes:
+
+--*/
+
+{
+
+ PWSTRING String;
+
+ if ( ((String = NEW DSTRING) == NULL ) ||
+ !(SYSTEM::QueryResourceString( String, MsgId, "" )) ) {
+
+ DisplayMessageAndExit( REPLACE_ERROR_NO_MEMORY, NULL, EXIT_NO_MEMORY );
+ }
+
+ return String;
+
+}
+
+VOID
+REPLACE::ExitWithError(
+ IN DWORD ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Displays a message based on a WIN32 error code, and exits.
+
+Arguments:
+
+ ErrorCode - Supplies Windows error code
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ Fatal( EXIT_PATH_NOT_FOUND, REPLACE_ERROR_EXTENDED, "%d", ErrorCode );
+}
diff --git a/private/utils/restore/dirs b/private/utils/restore/dirs
new file mode 100644
index 000000000..49b768e24
--- /dev/null
+++ b/private/utils/restore/dirs
@@ -0,0 +1,25 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Steve Wood (stevewo) 17-Apr-1990
+
+
+!ENDIF
+
+DIRS=src
+
+
+OPTIONAL_DIRS=
diff --git a/private/utils/restore/inc/queue.h b/private/utils/restore/inc/queue.h
new file mode 100644
index 000000000..96f28d1ae
--- /dev/null
+++ b/private/utils/restore/inc/queue.h
@@ -0,0 +1,78 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ queue.h
+
+Abstract:
+
+ Queue manipulation functions for the restore utility.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 20-Feb-1991
+
+
+Revision History:
+
+
+--*/
+
+
+
+//
+// pointer to queue
+//
+typedef PVOID PQUEUE;
+
+
+
+
+
+//
+// Prototypes
+//
+PQUEUE
+CreateQueue (
+ void
+ );
+
+
+BOOL
+DeleteQueue (
+ OUT PQUEUE TheQueue
+ );
+
+
+BOOL
+Enqueue (
+ OUT PQUEUE TheQueue,
+ IN PVOID Info
+ );
+
+
+PVOID
+Dequeue (
+ OUT PQUEUE TheQueue
+ );
+
+
+void
+FlushWaiters (
+ OUT PQUEUE TheQueue,
+ IN BOOL All
+ );
+
+
+DWORD
+NumberOfNodes (
+ IN PQUEUE TheQueue
+ );
+
+
+DWORD
+NumberOfWaiters (
+ IN PQUEUE TheQueue
+ );
diff --git a/private/utils/restore/inc/restore.h b/private/utils/restore/inc/restore.h
new file mode 100644
index 000000000..573b1a5dd
--- /dev/null
+++ b/private/utils/restore/inc/restore.h
@@ -0,0 +1,46 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ restore.h
+
+Abstract:
+
+ Main header file for the restore utility.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 20-Feb-1991
+
+
+Revision History:
+
+
+--*/
+
+
+
+//
+// C-runtime header files
+//
+#include <ctype.h>
+#include <malloc.h>
+#include <string.h>
+#include <stdio.h>
+
+//
+// Windows header files
+//
+#include <windows.h>
+
+//
+// Restore-specific header files
+//
+#include "rtdef.h" // macro definitions
+#include "rttype.h" // Type definitions
+#include "rtmsg.h" // Message and error constants
+#include "rtfile.h" // Structure of the backup disk
+#include "rtglob.h" // Global variables
+#include "rtproto.h" // Prototypes
diff --git a/private/utils/restore/inc/rtdef.h b/private/utils/restore/inc/rtdef.h
new file mode 100644
index 000000000..6e413d82e
--- /dev/null
+++ b/private/utils/restore/inc/rtdef.h
@@ -0,0 +1,57 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ rtdef.h
+
+Abstract:
+
+ Miscelaneous macros and definitions used in the restore
+ utility.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 20-Feb-1991
+
+
+Revision History:
+
+
+--*/
+
+
+
+//
+// Exit codes of the restore utility, as defined in the MS-DOS manual
+//
+#define EXIT_NORMAL 0
+#define EXIT_NOFILES 1
+#define EXIT_USER 3
+#define EXIT_ERROR 4
+
+
+//
+// Codes for disk verification
+//
+#define DISK_OK 0x00000001
+#define DISK_NEW_FORMAT 0x00000010
+#define DISK_OLD_FORMAT 0x00000020
+#define DISK_UNKNOWN 0x00000100
+#define DISK_OUTOFSEQUENCE 0x00000200
+
+
+//
+// Standard Handles
+//
+#define STD_IN stdin
+#define STD_OUT stdout
+#define STD_ERR stderr
+
+
+//
+// Buffer big enough to hold a date in string format of the form
+// MM-DD-YYYY
+//
+#define STRING_DATE_LENGTH 12
diff --git a/private/utils/restore/inc/rtfile.h b/private/utils/restore/inc/rtfile.h
new file mode 100644
index 000000000..1269ce5a8
--- /dev/null
+++ b/private/utils/restore/inc/rtfile.h
@@ -0,0 +1,220 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ rtfile.h
+
+Abstract:
+
+ Definition of backup file structures used by the restore
+ and backup utilities.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 20-Feb-1991
+
+
+Revision History:
+
+
+--*/
+
+#pragma pack(1)
+
+// *******************************************************************
+//
+// Old format:
+//
+// Each backup disk contains a file called BACKUPID.@@@ wich
+// has information about the disk sequence and backup date.
+//
+// Then each disk contains a series of files, one for each
+// file backed up (and each file may expand several disks).
+// Each file has a header containing sequence information and
+// the original name of the file.
+//
+// *******************************************************************
+
+
+//
+// Structure of disk information, used by old format only.
+// There are 128 bytes totally in disk header of the old
+// format backup disk. Only the first 7 bytes contains
+// meaningful information.
+// This is the BACKUPID.@@@ file
+//
+typedef struct OLD_DISKINFO {
+ BYTE Flag; // 0FFh if last disk, 00h if not last disk.
+ // initialize it to 0FFh when BACKUP.@@@ is created,
+ // and zero it out when the disk is full
+ WORD SequenceNumber; // Sequence number of the disk. Least significant
+ // byte first.
+ WORD Year; // Year, LSB first.
+ BYTE Day; // Month (1 byte) and day (1 byte).
+ BYTE Month; // Month (1 byte) and day (1 byte).
+} OLD_DISKINFO, *POLD_DISKINFO;
+
+
+
+//
+// Structure of file header, used for old format only.
+// There are 128 bytes totally in file header of the old
+// format backup disk. Only the first 85 bytes contains
+// meaningful information.
+// This is the structure attached to the beginning of every
+// file backed up with DOS 2.0 through 3.2 inclusive.
+//
+typedef struct OLD_FILEHEADER {
+ BYTE Flag; // 0FFh is last sequence of file, 00h if not last
+ WORD SequenceNumber; // file sequence number
+ BYTE pad1[2]; // not used
+ BYTE Path[78]; // asciiz path and name without drive letter
+ WORD PathLen; // length of previous field, not used in this program
+ BYTE pad2[43]; // Filler
+} OLD_FILEHEADER, *POLD_FILEHEADER;
+
+//
+// Values for Flag in both OLD_DISKINFO and OLD_FILEHEADER
+//
+#define LAST_SEQUENCE ((BYTE)(-1))
+
+
+
+
+
+
+
+
+// *******************************************************************
+//
+// New format:
+//
+// There are 2 files in each backup disk:
+//
+// CONTROL.XXX Contains all backup information, except the
+// actual contents of the backed-up files.
+// BACKUP.XXX Contains the contents of the backed-up files,
+// the offset at which each file begins is
+// indicated in the control file.
+//
+//
+// The file CONTROL.XXX is composed of a header with sequence and
+// other control information, followed by directory and file records.
+//
+// *******************************************************************
+
+
+//
+// Structure of disk header in CONTROL.xxx,
+//
+typedef struct NEW_DISKINFO {
+ BYTE Length; // length, in byte , of disk header
+ BYTE Id[8]; // identifies disk as a backup
+ BYTE SequenceNumber; // backup diskette sequence num
+ // (binary 1-255)
+ BYTE CommandLine[128]; // save area for command line
+ // parameters.
+ BYTE Flag; // 0ffh if last target 0 otherwise
+} NEW_DISKINFO, *PNEW_DISKINFO;
+
+//
+// Values for Flag
+//
+#define LAST_BACKUP_DISK ((BYTE)(-1))
+#define BACKUP_ID "BACKUP"
+
+
+//
+// DOS Directory record
+//
+typedef struct DIR_RECORD {
+ BYTE Length; // length, in bytes, of dir block
+ BYTE Path[63]; // ascii path of this directory sans drive letter
+ WORD NumEntries; // num of filenames currently in list
+ DWORD NextDirRecord; // offset of next directory block
+} DIR_RECORD, *PDIR_RECORD;
+
+//
+// Values for NextDirRecord
+//
+#define LAST_DIR_RECORD ((DWORD)(-1))
+
+//
+// OS/2 1.1 Directory record
+//
+typedef struct DIR_RECORD_OS211 {
+ BYTE Length; // length, in bytes, of dir block
+ BYTE Path[126]; // ascii path of this directory sans drive letter
+ WORD NumEntries; // num of filenames currently in list
+ DWORD NextDirRecord; // offset of next directory block
+} DIR_RECORD_OS211, *PDIR_RECORD_OS211;
+
+//
+// OS/2 1.2 Directory record
+//
+typedef struct DIR_RECORD_OS212 {
+ WORD Length; // length, in bytes, of dir block
+ WORD NumEntries; // num of filenames in list
+ DWORD NextDirRecord; // Offset of next directory block
+ BYTE SystemVersion; // Version of operating system
+ DWORD EaOffset; // Offset of EA data
+ DWORD EaLength; // Length of EA data
+ WORD PathLength; // Length of path
+ BYTE Path[MAX_PATH]; // Path
+} DIR_RECORD_OS212, *PDIR_RECORD_OS212;
+
+//
+// Values for SystemVersion
+//
+#define SYSTEM_VERSION_OS2_12 ((BYTE)212)
+
+
+//
+// DOS File record
+//
+typedef struct FILE_RECORD {
+ BYTE Length; // Length, in bytes, of file header
+ BYTE FileName[12]; // ASCII file name (from directory)
+ BYTE Flag; // bit 0=1 if last part of file
+ // bit 1=1 if it is backed up successfully
+ // 3 bit 2=1 if Extended Attributes are backed(New for DOS4.00)
+ DWORD FileSize; // Total length of the file (from directory)
+ WORD SequenceNumber; // Sequence #, for files that span
+ DWORD FileOffset; // Offset in BACKUP.xxx where this segment begins
+ DWORD PartSize; // Length of part of file on current target
+ WORD Attr; // File attribute (from directory)
+ WORD Time; // Time when file was last Revised (from directory)
+ WORD Date; // Date when file was last Revised (from directory)
+} FILE_RECORD, *PFILE_RECORD;
+
+//
+// Values for Flag
+//
+#define LAST_FILECHUNK (BYTE)(0x01)
+#define FILE_OK (BYTE)(0x02)
+#define HAS_EAS (BYTE)(0x04)
+
+
+//
+// OS/2 1.2 File record
+//
+typedef struct FILE_RECORD_OS212 {
+ WORD Length; // Length, in bytes, of file header
+ BYTE Flag; // Flags (Same as DOS File record )
+ DWORD FileSize; // Length of file
+ WORD SequenceNumber; // Sequence #
+ DWORD FileOffset; // Offset where this segment begins
+ DWORD PartSize; // Length of this part of file
+ WORD Attr; // File attributes
+ WORD Time; // Time when file was created
+ WORD Date; // Date when file was created
+ DWORD EaOffset; // EA Offset
+ DWORD EaLength; // EA Length
+ WORD NameLength; // Length of filename
+ BYTE FileName[MAX_PATH]; // File name
+} FILE_RECORD_OS212, *PFILE_RECORD_OS212;
+
+
+#pragma pack()
diff --git a/private/utils/restore/inc/rtglob.h b/private/utils/restore/inc/rtglob.h
new file mode 100644
index 000000000..a2cc76cda
--- /dev/null
+++ b/private/utils/restore/inc/rtglob.h
@@ -0,0 +1,83 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ rtglob.h
+
+Abstract:
+
+ Global variables of the restore utility
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 20-Feb-1991
+
+
+Revision History:
+
+
+--*/
+
+
+//
+// Switches set in the command line
+//
+extern BOOL Flag_s; // Restore subdirs
+extern BOOL Flag_p; // Prompting
+extern BOOL Flag_b; // Before date
+extern BOOL Flag_a; // After date
+extern BOOL Flag_z; // Exact date
+extern BOOL Flag_e; // Before time
+extern BOOL Flag_L; // After time
+extern BOOL Flag_Y; // Exact time
+extern BOOL Flag_m; // Restore only modified files
+extern BOOL Flag_n; // Restore only nonexistent files
+extern BOOL Flag_d; // List files in backup disk
+
+//
+// WriteNewLine is true if we must write a newline after restoring a file
+//
+extern BOOL WriteNewLine;
+
+//
+// Dates and times set in the command line
+//
+extern FATDATE BeforeDate;
+extern FATDATE AfterDate;
+extern FATDATE ExactDate;
+
+extern FATTIME BeforeTime;
+extern FATTIME AfterTime;
+extern FATTIME ExactTime;
+
+
+//
+// The date of the backup
+//
+extern FATDATE BackupDate;
+extern FATTIME BackupTime;
+
+
+//
+// The source and destination specifications
+//
+extern PCHAR SourceSpec; // Source drive specification
+extern CHAR DestinationSpec[]; // Full destination Spec
+extern CHAR DestinationDrive[]; // Destination drive
+extern CHAR DestinationDir[]; // Destination directory
+extern CHAR DestinationFile[]; // Destination file
+
+
+//
+// Abort becomes TRUE when an error condition arises
+//
+extern BOOL Abort;
+
+
+//
+// The type of the source and target drives
+//
+extern DWORD SourceDriveType;
+extern DWORD TargetDriveType;
diff --git a/private/utils/restore/inc/rtproto.h b/private/utils/restore/inc/rtproto.h
new file mode 100644
index 000000000..e2fde735f
--- /dev/null
+++ b/private/utils/restore/inc/rtproto.h
@@ -0,0 +1,296 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ rtproto.h
+
+Abstract:
+
+ Prototypes of exported functions of the restore utility.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 20-Feb-1991
+
+
+Revision History:
+
+
+--*/
+
+
+
+
+//
+// parse.c
+//
+void
+ParseCommandLine (
+ IN int argc,
+ IN CHAR **argv
+ );
+
+
+
+
+
+//
+// msg.c
+//
+void
+Usage (
+ void
+ );
+
+void
+DisplayMsg (
+ IN FILE* f,
+ IN DWORD MsgNum,
+ ...
+ );
+
+CHAR
+GetKey (
+ IN PCHAR PossibleKeys,
+ IN FILE* StdHandleChar,
+ IN FILE* StdHandleNl
+ );
+
+
+
+
+//
+// exit.c
+//
+void
+ExitStatus (
+ IN DWORD Status
+ );
+
+
+#define AbortProgram() AbortTheProgram(__FILE__, __LINE__);
+
+void
+AbortTheProgram (
+ CHAR *FileName,
+ DWORD LineNumber
+ );
+
+
+
+
+
+//
+// generic.c
+//
+DWORD
+GetABackupDisk (
+ OUT PWORD Sequence
+ );
+
+BOOL
+IsLastBackupDisk (
+ void
+ );
+
+PFILE_INFO
+GetNextFile (
+ void
+ );
+
+BOOL
+RestoreFile (
+ IN PFILE_INFO FileInfo
+ );
+
+BOOL
+RecoverFile (
+ IN PFILE_INFO FileInfo
+ );
+
+
+
+
+
+//
+// new.c
+//
+DWORD
+New_VerifyDiskSequence (
+ OUT PWORD Sequence
+ );
+
+BOOL
+New_IsLastBackupDisk (
+ void
+ );
+
+PFILE_INFO
+New_GetNextFile (
+ void
+ );
+
+BOOL
+New_RestoreFile (
+ IN PFILE_INFO FileInfo
+ );
+
+
+
+
+
+
+//
+// old.c
+//
+DWORD
+Old_VerifyDiskSequence (
+ OUT PWORD Sequence
+ );
+
+BOOL
+Old_IsLastBackupDisk (
+ void
+ );
+
+PFILE_INFO
+Old_GetNextFile (
+ void
+ );
+
+BOOL
+Old_RestoreFile (
+ IN PFILE_INFO FileInfo
+ );
+
+
+
+
+
+//
+// filecopy.c
+//
+BOOL
+CopyData (
+ IN HANDLE Src,
+ IN HANDLE Dst,
+ IN DWORD Bytes
+ );
+
+
+
+//
+// match.c
+//
+BOOL
+FileMatch (
+ IN PFILE_INFO FileInfo
+ );
+
+DWORD
+ComparePath (
+ IN PCHAR Path1,
+ IN PCHAR Path2
+ );
+
+//
+// Result values from ComparePath
+//
+#define COMPARE_NOMATCH 0
+#define COMPARE_PREFIX 1
+#define COMPARE_MATCH 2
+
+
+
+
+
+//
+// misc.c
+//
+void
+MakeFullPath (
+ OUT CHAR *FullPath,
+ IN CHAR *Drive,
+ IN CHAR *Path,
+ IN CHAR *FileName
+ );
+
+void
+MakeTmpPath (
+ OUT CHAR *FullPath,
+ IN CHAR *Drive,
+ IN CHAR *Path,
+ IN DWORD Sequence
+ );
+
+PCHAR
+MakeStringDate(
+ OUT CHAR *StringDate,
+ IN FATDATE Date
+ );
+
+PCHAR
+MakeStringTime(
+ OUT CHAR *StringTime,
+ IN FATTIME Time
+ );
+
+PCHAR
+MakeStringNumber(
+ OUT CHAR *Buffer,
+ IN DWORD Number,
+ IN DWORD Width
+ );
+
+BOOL
+Rename (
+ IN CHAR *OriginalFile,
+ IN CHAR *NewFile
+ );
+
+BOOL
+Delete (
+ IN CHAR *FileName
+ );
+
+
+#if defined (DEBUG)
+
+void *
+DebugRealloc (
+ void *Mem,
+ size_t Size,
+ CHAR *FileName,
+ DWORD LineNumber
+ );
+
+void *
+DebugMalloc (
+ size_t Size,
+ CHAR *FileName,
+ DWORD LineNumber
+ );
+
+void
+DebugFree (
+ void *Mem,
+ CHAR *FileName,
+ DWORD LineNumber
+ );
+
+
+#define Realloc(x,y) DebugRealloc(x, y, __FILE__, __LINE__)
+#define Malloc(x) DebugMalloc(x, __FILE__, __LINE__)
+#define Free(x) DebugFree(x, __FILE__, __LINE__)
+
+
+
+#else
+
+#define Realloc(x,y) realloc(x,y)
+#define Malloc(x) malloc(x)
+#define Free(x) free(x)
+
+#endif
diff --git a/private/utils/restore/inc/rttype.h b/private/utils/restore/inc/rttype.h
new file mode 100644
index 000000000..ad24b1e3c
--- /dev/null
+++ b/private/utils/restore/inc/rttype.h
@@ -0,0 +1,94 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ rttype.h
+
+Abstract:
+
+ Type definitions for the restore utility
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 20-Feb-1991
+
+
+Revision History:
+
+
+--*/
+
+
+
+//
+// DOS date and time
+//
+typedef struct FATTIME {
+ unsigned DoubleSeconds : 5;
+ unsigned Minutes : 6;
+ unsigned Hours : 5;
+} FATTIME, *PFATTIME;
+
+
+typedef struct FATDATE {
+ unsigned Day : 5;
+ unsigned Month : 4;
+ unsigned Year : 7;
+} FATDATE, *PFATDATE;
+
+
+//
+// Casts for treating dates and times as WORDS
+//
+#define DATE_WORD(Date) (*((PWORD)&(Date)))
+#define TIME_WORD(Time) (*((PWORD)&(Time)))
+
+
+
+//
+// FILE_INFO
+//
+// The file information structure contains all the information
+// necessary for restoring one file.
+//
+typedef struct FILE_INFO {
+
+ //
+ // Generic things
+ //
+ DWORD FileSize; // File Size
+ DWORD Attr; // File attributes
+ DWORD Sequence; // Sequence number
+ DWORD Flag; // Misc. flags
+ FATDATE Date; // Fat Date (local time)
+ FATTIME Time; // Fat Time (local time)
+ BOOL TargetExists; // True if target exists
+ DWORD TargetAttributes; // Attributes of target
+ HANDLE RestoredEvent; // Set when restore complete
+ CHAR Path[MAX_PATH]; // Directory path (no drive)
+ CHAR FileName[MAX_PATH]; // File name
+ CHAR TargetPath[MAX_PATH]; // Full target path
+ CHAR TmpName[MAX_PATH]; // Name of temporary file
+
+ //
+ // Specific for New backup format:
+ //
+ DWORD Offset; // Offset within BACKUP.XXX
+ DWORD PartSize; // Chunk size in BACKUP.XXX
+
+ //
+ // Specific for Old backup format:
+ //
+ CHAR SourcePath[MAX_PATH]; // Name of source file (Old format)
+
+} FILE_INFO, *PFILE_INFO;
+
+
+//
+// Values for Flag field
+//
+#define FILEINFO_LAST 0x00000001
+#define FILEINFO_OK 0x00000002
+#define FILEINFO_EA 0x00000004
diff --git a/private/utils/restore/src/exit.c b/private/utils/restore/src/exit.c
new file mode 100644
index 000000000..3403c5e7b
--- /dev/null
+++ b/private/utils/restore/src/exit.c
@@ -0,0 +1,89 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ exit.c
+
+Abstract:
+
+ Exit and abort functions.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 20-Feb-1990
+
+
+Revision History:
+
+
+--*/
+
+
+#include "restore.h"
+#include <process.h>
+
+
+
+// **********************************************************************
+
+void
+ExitStatus (
+ DWORD Status
+ )
+/*++
+
+Routine Description:
+
+ Exits the program with certain status code
+
+Arguments:
+
+ Status - Error level with which to exit
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ exit(Status);
+}
+
+
+
+
+// **********************************************************************
+
+void
+AbortTheProgram (
+ CHAR *FileName,
+ DWORD LineNumber
+ )
+/*++
+
+Routine Description:
+
+ Sets the global variables that indicate an abort condition
+
+Arguments:
+
+ IN FileName - Supplies the file name
+ IN LineNumber - Supplie the line number
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ Abort = TRUE;
+
+#if defined (DEBUG)
+ DbgPrint("Program aborted in file %s, line %d\n", FileName, LineNumber);
+#endif
+
+}
diff --git a/private/utils/restore/src/filecopy.c b/private/utils/restore/src/filecopy.c
new file mode 100644
index 000000000..c180ddd9f
--- /dev/null
+++ b/private/utils/restore/src/filecopy.c
@@ -0,0 +1,736 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ filecopy.c
+
+Abstract:
+
+ Copy data from one handle to another.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 20-Feb-1991 Addapted from ztools
+
+
+Revision History:
+
+
+--*/
+
+#include "restore.h"
+
+//
+// Reader thread stack size
+//
+#define READER_STACK_SIZE 1024
+
+//
+// We copy in small chunks
+//
+#define COPY_BUFFER_SIZE (1024 * 32)
+
+
+//
+// A queue Node
+//
+typedef struct COPY_NODE *PCOPY_NODE;
+typedef struct COPY_NODE {
+ PCOPY_NODE Next; // Next in queue
+ DWORD BufferSize;
+ BYTE Buffer[1];
+} COPY_NODE;
+
+
+//
+// The queue structure
+//
+typedef struct QUEUE_STRUCTURE {
+ PCOPY_NODE Head; // First in queue
+ PCOPY_NODE Tail; // Last in queue
+ DWORD NumberOfNodes; // Number of nodes
+ HANDLE Semaphore; // Coordination semaphore
+ CRITICAL_SECTION CriticalSection; // Critical Section
+} QUEUE_STRUCTURE, *PQUEUE_STRUCTURE;
+
+
+//
+// Global data
+//
+BOOL QueueInitialized = FALSE;
+QUEUE_STRUCTURE Queue;
+HANDLE HandleSrc; // Handle of source file
+HANDLE HandleDst; // Handle of destination file
+DWORD NumberOfBytes; // Number of bytes to copy
+BOOL StatusCode; // Status code
+
+
+//
+// Local Prototypes
+//
+BOOL
+UseOneThread (
+ HANDLE Src,
+ HANDLE Dst,
+ DWORD Bytes
+ );
+
+BOOL
+UseTwoThreads (
+ HANDLE Src,
+ HANDLE Dst,
+ DWORD Bytes
+ );
+
+void
+Reader (
+ );
+
+void
+Writer (
+ );
+
+BOOL
+InitializeQueue (
+ void
+ );
+
+BOOL
+Enqueue (
+ PCOPY_NODE Node
+ );
+
+PCOPY_NODE
+Dequeue (
+ );
+
+void
+FlushWaiters (
+ );
+
+void
+PrintQueue(
+ );
+
+
+
+// **********************************************************************
+
+BOOL
+CopyData (
+ HANDLE Src,
+ HANDLE Dst,
+ DWORD Bytes
+ )
+/*++
+
+Routine Description:
+
+ Copies data from one handle to another
+
+Arguments:
+
+ IN Src - Supplies handle of source file
+ IN Dst - Supplies handle of destination file
+ IN Bytes - Supplies number of bytes to copy
+
+Return Value:
+
+ TRUE if all bytes copied, FALSE otherwise
+
+--*/
+{
+
+ if (!QueueInitialized) {
+ InitializeQueue();
+ }
+
+ if (Bytes < COPY_BUFFER_SIZE) {
+ //
+ // The chunk size is smaller than our buffer size, so there will
+ // only be one read and one copy. We use one thread.
+ //
+ return UseOneThread(Src, Dst, Bytes);
+
+ } else {
+ //
+ // Since several reads/writes will be involved, we will do the
+ // copy using two threads (one reader and one writer).
+ //
+ return UseTwoThreads(Src, Dst, Bytes);
+ }
+}
+
+
+
+
+
+// **********************************************************************
+
+BOOL
+UseOneThread (
+ HANDLE Src,
+ HANDLE Dst,
+ DWORD Bytes
+ )
+/*++
+
+Routine Description:
+
+ Copies data from one handle to another using one thread
+
+Arguments:
+
+ IN Src - Supplies handle of source file
+ IN Dst - Supplies handle of destination file
+ IN Bytes - Supplies number of bytes to copy
+
+Return Value:
+
+ TRUE uf all bytes copied, FALSE otherwise
+
+--*/
+{
+
+
+ PBYTE Buffer; // Pointer to buffer
+ DWORD NumRead; // Number of bytes read
+ DWORD NumWrite; // Number of bytes written
+ BOOL StatusOk; // Status of API
+
+
+ Buffer = (PBYTE)Malloc(Bytes);
+
+ if (!Buffer) {
+ //
+ // We could not get a buffer big enough, so we will have to split
+ // the request. We better use two threads to do this.
+ //
+ return UseTwoThreads(Src, Dst, Bytes);
+ }
+
+ //
+ // Read the data
+ //
+ StatusOk = ReadFile( Src,
+ Buffer,
+ Bytes,
+ &NumRead,
+ NULL );
+
+ if (!StatusOk || (NumRead != Bytes)) {
+
+ DisplayMsg( STD_OUT, REST_ERROR_READING_BACKUP );
+ return FALSE;
+ }
+
+
+ //
+ // Write the chunk
+ //
+ StatusOk = WriteFile( Dst,
+ Buffer,
+ Bytes,
+ &NumWrite,
+ NULL );
+
+
+ if (!StatusOk || (NumWrite != Bytes)) {
+
+ return FALSE;
+ }
+
+ Free(Buffer);
+
+ return TRUE;
+}
+
+
+
+
+
+// **********************************************************************
+
+BOOL
+UseTwoThreads (
+ HANDLE Src,
+ HANDLE Dst,
+ DWORD Bytes
+ )
+/*++
+
+Routine Description:
+
+ Copies data from one handle to another using two threads
+
+Arguments:
+
+ IN Src - Supplies handle of source file
+ IN Dst - Supplies handle of destination file
+ IN Bytes - Supplies number of bytes to copy
+
+Return Value:
+
+ TRUE if all bytes copied, FALSE otherwise
+
+--*/
+{
+
+
+ HANDLE ReaderHandle; // Handle of reader
+ DWORD ReaderId; // Thread Id of reader
+
+ HandleSrc = Src;
+ HandleDst = Dst;
+ NumberOfBytes = Bytes;
+ StatusCode = TRUE;
+
+
+ //
+ // We create the reader thread
+ //
+ ReaderHandle = CreateThread( NULL,
+ READER_STACK_SIZE,
+ (LPTHREAD_START_ROUTINE)Reader,
+ NULL,
+ 0,
+ &ReaderId );
+
+ if (ReaderHandle == INVALID_HANDLE_VALUE) {
+ return FALSE;
+ }
+
+ //
+ // We become the writer thread.
+ //
+ Writer();
+
+ //
+ // Dispose of the reader handle
+ //
+ CloseHandle(ReaderHandle);
+
+ return StatusCode;
+}
+
+
+
+
+
+// **********************************************************************
+
+void
+Reader (
+ )
+/*++
+
+Routine Description:
+
+ Reads a chunk of data from the source handle
+
+Arguments:
+
+ None
+
+Return Value:
+
+ none
+
+--*/
+{
+
+ DWORD BytesLeft; // Number of bytes left to copy
+ PCOPY_NODE Node; // Data buffer
+ DWORD BufferSize; // Buffer size
+ DWORD NumRead; // Number of bytes read
+ BOOL StatusOk;
+
+
+ BytesLeft = NumberOfBytes;
+
+
+ while (BytesLeft && (StatusCode)) {
+
+ //
+ // We will split the read in pieces as big as possible up to
+ // COPY_BUFFER_SIZE.
+ //
+ Node = NULL;
+ BufferSize = min(BytesLeft, COPY_BUFFER_SIZE);
+
+ while (!Node && (BufferSize > 0)) {
+ //
+ // Try to get a buffer of size BufferSize. If we can't, then
+ // keep trying, halving the BufferSize each time.
+ //
+ Node = (PCOPY_NODE)Malloc(BufferSize + sizeof(COPY_NODE));
+ if (!Node) {
+ BufferSize /= 2;
+ }
+ }
+
+ if (!Node) {
+ //
+ // We could not allocate the buffer.
+ // Let the writer know, then exit
+ //
+#if DBG==1
+ OutputDebugString("RESTORE: Out of memory\n");
+#endif
+ StatusCode = FALSE;
+ FlushWaiters();
+ return;
+ }
+
+ //
+ // Read the chunk
+ //
+ StatusOk = ReadFile( HandleSrc,
+ Node->Buffer,
+ BufferSize,
+ &NumRead,
+ NULL );
+
+ if (!StatusOk || (NumRead != BufferSize)) {
+ //
+ // We could not read the chunk. Let the writer know, then
+ // exit
+ //
+#if DBG==1
+ OutputDebugString("RESTORE: Cannot read.\n");
+#endif
+ DisplayMsg( STD_OUT, REST_ERROR_READING_BACKUP );
+ StatusCode = FALSE;
+ Free(Node);
+ FlushWaiters();
+ return;
+ }
+
+ //
+ // We got the data data. Put it in the writer queue and
+ // continue.
+ //
+ Node->BufferSize = BufferSize;
+ Enqueue(Node);
+ BytesLeft -= BufferSize;
+ }
+
+ //
+ // Our job is done
+ //
+ return;
+}
+
+
+
+
+
+// **********************************************************************
+
+void
+Writer (
+ )
+/*++
+
+Routine Description:
+
+ Writes a chunk of data to the destination handle
+
+Arguments:
+
+ None
+
+Return Value:
+
+ none
+
+--*/
+{
+
+ DWORD BytesLeft; // Number of bytes left to copy
+ PCOPY_NODE Node; // Data buffer
+ DWORD BytesWritten; // Number of bytes written
+
+ BytesLeft = NumberOfBytes;
+
+ while (BytesLeft) {
+
+ //
+ // Try to get a data buffer
+ //
+ Node = Dequeue();
+
+ if (Node) {
+
+ //
+ // We got a valid data buffer, but will only write it
+ // if we have found no errors so far.
+ //
+ if (StatusCode) {
+ //
+ // Got the buffer and everything has gone fine so
+ // far, write the data out
+ //
+ WriteFile( HandleDst,
+ Node->Buffer,
+ Node->BufferSize,
+ &BytesWritten,
+ NULL );
+
+ if (BytesWritten == Node->BufferSize) {
+ //
+ // Wrote the data successfully, continue
+ //
+ BytesLeft -= Node->BufferSize;
+
+ } else {
+ //
+ // We could not write the data. Set the status code
+ // to error, but keep dequeueing, so the queue
+ // won't be left in an inconsistent state. The reader
+ // will eventually stop enqueueing and we will get out.
+ //
+#if DBG==1
+ OutputDebugString("RESTORE: Cannot write file.\n");
+#endif
+ StatusCode = FALSE;
+ }
+ }
+
+ //
+ // Free the buffer
+ //
+ Free(Node);
+
+ } else {
+
+ //
+ // The queue is empty!. Something must have gone wrong.
+ // The StatusCode has the error status. We only have
+ // to get out of here
+ //
+ break;
+ }
+ }
+}
+
+
+
+
+
+// **********************************************************************
+
+BOOL
+InitializeQueue (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Initializes the copy queue
+
+Arguments:
+
+ none
+
+Return Value:
+
+ TRUE if initialized
+
+--*/
+{
+ Queue.Head = Queue.Tail = NULL;
+ Queue.NumberOfNodes = 0;
+ Queue.Semaphore = CreateSemaphore(NULL, 0, 0x7FFFFFFF,NULL);
+ InitializeCriticalSection(&(Queue.CriticalSection));
+
+ return QueueInitialized = TRUE;
+}
+
+
+
+// **********************************************************************
+
+BOOL
+Enqueue (
+ PCOPY_NODE Node
+ )
+/*++
+
+Routine Description:
+
+ Inserts a node in the queue
+
+Arguments:
+
+ Node - Supplies the node to add to queue
+
+Return Value:
+
+ TRUE if enqueued
+ FALSE otherwise
+
+--*/
+{
+ LONG PreviousCount;
+
+ Node->Next = NULL;
+
+ //
+ // Now insert in queue
+ //
+ EnterCriticalSection(&(Queue.CriticalSection));
+
+ // printf("ENQUEUE...\n");
+ if (!(Queue.Tail)) {
+ Queue.Head = Node;
+ } else {
+ (Queue.Tail)->Next = Node;
+ }
+ Queue.Tail = Node;
+
+ Queue.NumberOfNodes++;
+
+ ReleaseSemaphore(Queue.Semaphore, 1, &PreviousCount);
+
+ // PrintQueue();
+
+ LeaveCriticalSection(&(Queue.CriticalSection));
+
+ return TRUE;
+}
+
+
+
+
+// **********************************************************************
+
+PCOPY_NODE
+Dequeue (
+ )
+/*++
+
+Routine Description:
+
+ Gets a node from the queue
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Pointer to information or NULL is queue empty.
+
+--*/
+{
+
+ PCOPY_NODE Node = NULL;
+
+ if ( StatusCode ) {
+ //
+ // Wait for a node and dequeue it
+ //
+ WaitForSingleObject(Queue.Semaphore, INFINITE);
+
+ if ( StatusCode ) {
+
+ EnterCriticalSection(&(Queue.CriticalSection));
+ // printf("DEQUEUE...\n");
+
+ Node = (Queue.Head);
+
+ if (Node) {
+ //
+ // Something in Queue, Get the first node.
+ //
+ if (!(Queue.Head = Node->Next)) {
+ Queue.Tail = NULL;
+ }
+ Queue.NumberOfNodes--;
+ }
+
+ // PrintQueue();
+ LeaveCriticalSection(&(Queue.CriticalSection));
+ }
+ }
+
+ return Node;
+}
+
+
+
+
+
+// **********************************************************************
+
+void
+FlushWaiters (
+ )
+/*++
+
+Routine Description:
+
+ Wakes up people waiting on a queue
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+{
+ LONG PreviousCount;
+ ReleaseSemaphore(Queue.Semaphore, 1, &PreviousCount);
+}
+
+
+#if 0
+
+// **********************************************************************
+
+void
+PrintQueue(
+ )
+/*++
+
+Routine Description:
+
+ Prints queue contents
+
+Arguments:
+
+ IN Queue - Supplies pointer to queue
+
+Return Value:
+
+ none
+
+--*/
+{
+ PCOPY_NODE Node;
+ DWORD i = 0;
+ BOOL f = FALSE;
+
+ Node = Queue.Head;
+
+ printf("\tQueue contents: [%X]\n", Queue);
+ while (Node) {
+ printf("\t\t%d.- %X \n", i, (int)Node);
+ i++;
+ f = TRUE;
+ Node = Node->Next;
+ }
+
+ if (!f) {
+ printf("\t\tQueue is empty. [%X]\n", Queue);
+ }
+}
+
+#endif
diff --git a/private/utils/restore/src/generic.c b/private/utils/restore/src/generic.c
new file mode 100644
index 000000000..9dc3ea107
--- /dev/null
+++ b/private/utils/restore/src/generic.c
@@ -0,0 +1,536 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ generic.c
+
+Abstract:
+
+ Functions that interface with the functions that deal with the
+ backup-disk structures.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 20-Feb-1991
+
+
+Revision History:
+
+
+--*/
+
+
+
+#include <conio.h>
+#include "restore.h"
+
+
+
+//
+// SPECIFIC_FUNCTIONS contains pointers to the functions that
+// understand a specific backup format.
+//
+typedef struct SPECIFIC_FUNCTIONS {
+
+ //
+ // Verify a disk format and sequence
+ //
+ DWORD (*VerifyDiskSequence) (PWORD);
+
+ //
+ // Determine if a disk is the last in the backup set
+ //
+ BOOL (*IsLastBackupDisk) (void);
+
+ //
+ // Get the next backed-up file
+ //
+ PFILE_INFO (*GetNextFile) (void);
+
+ //
+ // Restore a file
+ //
+ BOOL (*RestoreFile) (PFILE_INFO);
+
+} SPECIFIC_FUNCTIONS, *PSPECIFIC_FUNCTIONS;
+
+
+
+
+//
+//
+// We access the specific functions thru these structures:
+//
+static SPECIFIC_FUNCTIONS Specific_Old = { Old_VerifyDiskSequence,
+ Old_IsLastBackupDisk,
+ Old_GetNextFile,
+ Old_RestoreFile
+ };
+
+static SPECIFIC_FUNCTIONS Specific_New = { New_VerifyDiskSequence,
+ New_IsLastBackupDisk,
+ New_GetNextFile,
+ New_RestoreFile
+ };
+
+
+//
+// Pointer to the current specific function structure
+//
+static PSPECIFIC_FUNCTIONS Specific_Current = NULL;
+
+
+
+
+
+//
+// Local Prototypes
+//
+DWORD
+GetFirstBackupDisk (
+ PWORD Sequence
+ );
+
+DWORD
+GetNextBackupDisk (
+ PWORD Sequence
+ );
+
+
+
+
+
+
+// **********************************************************************
+
+DWORD
+GetABackupDisk (
+ PWORD Sequence
+ )
+/*++
+
+Routine Description:
+
+ Mounts a backup disk and updates the disk sequence.
+
+Arguments:
+
+ OUT Sequence - Provides pointer to the sequence number of the backup disk desired
+
+Return Value:
+
+ DISK_OK if disk mounted
+ DISK_OUTOFSEQUENCE if disk is out of sequence
+ DISK_UNKNOWN if not a backup disk (or invalid format)
+
+--*/
+{
+ CHAR StringBuffer[16]; // Holds string representation of Sequence
+ DWORD DiskType; // Type of backup disk
+
+ //
+ // Ask the user to insert disk, if removable
+ //
+ if (SourceDriveType == DRIVE_REMOVABLE) {
+
+ MakeStringNumber(StringBuffer, *Sequence, 2);
+ putc( '\r', STD_OUT );
+ putc( '\r', STD_OUT );
+ putc( '\n', STD_OUT );
+ DisplayMsg(STD_ERR, REST_MSG_INSERT_SOURCE, StringBuffer, SourceSpec);
+ DisplayMsg(STD_ERR, REST_MSG_PRESS_ANY_KEY);
+ GetKey(NULL, STD_ERR, STD_ERR);
+ }
+
+ if (!Specific_Current) {
+ //
+ // We don't know the format of the backup disk.
+ // We must determine it.
+ //
+ DiskType = GetFirstBackupDisk(Sequence);
+
+ } else {
+ //
+ // We already accepted a previous backup disk, from now on
+ // we only accept disks in the same format.
+ //
+ DiskType = GetNextBackupDisk(Sequence);
+ }
+
+#if defined (DEBUG)
+ DbgPrint("The type of the backup disk is %X\n",DiskType);
+#endif
+
+ return DiskType;
+}
+
+
+
+
+
+// **********************************************************************
+
+DWORD
+GetFirstBackupDisk (
+ PWORD Sequence
+ )
+/*++
+
+Routine Description:
+
+ Gets the first backup disk. Determines disk format. Updates sequence.
+
+Arguments:
+
+ OUT Sequence - Provides pointer to the sequence number of the backup disk desired
+
+Return Value:
+
+ DISK_OK if format and sequence match,
+ DISK_OUTOFSEQUENCE if new format but wrong sequence
+ DISK_UNKNOWN if not in new format
+
+--*/
+{
+
+ DWORD DiskFormat; // Disk format
+ DWORD LastFormat = 0x00000000; // Format of last disk
+ WORD CurrentSequenceNumber = *Sequence; // Sequence of current disk
+ WORD LastSequenceNumber = *Sequence; // Sequence of last disk
+ CHAR StringBuffer[16]; // Holds Sequence in string format
+
+
+ while (TRUE) {
+ //
+ // Get the disk format of the current disk
+ //
+ DiskFormat = New_VerifyDiskSequence(&CurrentSequenceNumber);
+ if (DiskFormat & DISK_UNKNOWN) {
+ //
+ // Disk is not in the new format, see if it is in the old
+ // format
+ //
+ DiskFormat = Old_VerifyDiskSequence(&CurrentSequenceNumber);
+ if (DiskFormat & DISK_UNKNOWN) {
+ //
+ // Nope, this is not a backup disk
+ //
+ break;
+ }
+ }
+
+ //
+ // If the disk is out of sequence we must make sure that this
+ // is what the user wants.
+ //
+ if (DiskFormat & DISK_OUTOFSEQUENCE) {
+ if (CurrentSequenceNumber == *Sequence) {
+ //
+ // The disk has the sequence number that we asked for,
+ // this is our guy.
+ //
+ break;
+
+ } else if ((CurrentSequenceNumber == LastSequenceNumber) &&
+ (DiskFormat = LastFormat)) {
+ //
+ // We verified the disk twice in a row. We accept it.
+ //
+ break;
+
+ } else {
+ //
+ // We have an out of sequence disk, ask the user to
+ // confirm
+ //
+ MakeStringNumber(StringBuffer, *Sequence, 2);
+ DisplayMsg(STD_OUT, REST_WARNING_DISK_OUTOFSEQUENCE, StringBuffer, SourceSpec);
+ GetKey(NULL, STD_OUT, STD_OUT);
+
+ LastFormat = DiskFormat;
+ LastSequenceNumber = CurrentSequenceNumber;
+ }
+
+ } else {
+
+ //
+ // The disk is correct, accept it
+ //
+ break;
+ }
+ }
+
+ if (DiskFormat & DISK_NEW_FORMAT) {
+ //
+ // New format. Set FormatOfDisk and initialize pointer to
+ // specific functions.
+ //
+ Specific_Current = &Specific_New;
+
+ } else {
+ //
+ // Old format. Set FormatOfDisk and initialize pointer to
+ // specific functions.
+ //
+ Specific_Current = &Specific_Old;
+ }
+
+ return DiskFormat;
+}
+
+
+
+
+// **********************************************************************
+
+DWORD
+GetNextBackupDisk (
+ PWORD Sequence
+ )
+/*++
+
+Routine Description:
+
+ Gets the next backup disk. Updates sequence.
+
+Arguments:
+
+ OUT Sequence - Provides pointer to the sequence number of the backup disk desired
+
+Return Value:
+
+ DISK_OK if format and sequence match,
+ DISK_OUTOFSEQUENCE if new format but wrong sequence
+ DISK_UNKNOWN if not in new format
+
+--*/
+{
+
+ DWORD DiskFormat; // Disk format
+ WORD CurrentSequenceNumber = *Sequence; // Current Sequence
+ WORD LastSequenceNumber = *Sequence; // Last sequence
+ CHAR StringBuffer[16]; // Holds sequence in string format
+
+ //
+ // Note that at this point we know what format of disks we are
+ // expected to accept.
+ //
+ while (TRUE) {
+ //
+ // Verify current disk
+ //
+ DiskFormat = (*(Specific_Current->VerifyDiskSequence))(&CurrentSequenceNumber);
+
+ //
+ // If the disk is out of sequence we must make sure that this
+ // is what the user wants.
+ //
+ if (DiskFormat & DISK_OUTOFSEQUENCE) {
+ if (CurrentSequenceNumber == *Sequence) {
+ //
+ // The disk has the sequence number that we asked for,
+ // this is our guy.
+ //
+ break;
+
+ } else if ((CurrentSequenceNumber == LastSequenceNumber) &&
+ (CurrentSequenceNumber > *Sequence)) {
+ //
+ // We verified the disk twice in a row. We accept it.
+ //
+ break;
+
+ } else {
+ //
+ // We have an out of sequence disk, ask the user to
+ // confirm
+ //
+ MakeStringNumber(StringBuffer, *Sequence, 2);
+ DisplayMsg(STD_OUT, REST_WARNING_DISK_OUTOFSEQUENCE, StringBuffer, SourceSpec);
+ GetKey(NULL, STD_OUT, STD_OUT);
+
+ LastSequenceNumber = CurrentSequenceNumber;
+ }
+
+ } else if (DiskFormat & DISK_OK) {
+ //
+ // The disk is correct, accept it
+ //
+ *Sequence = CurrentSequenceNumber;
+ break;
+
+ } else {
+ //
+ // Not a backup disk in the correct format, get out
+ //
+ break;
+ }
+ }
+
+ return DiskFormat;
+}
+
+
+
+
+
+// **********************************************************************
+
+BOOL
+IsLastBackupDisk (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Determines if the backup disk is the last one.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ TRUE if disk is the last one, FALSE otherwise
+
+--*/
+{
+ return (*(Specific_Current->IsLastBackupDisk))();
+}
+
+
+
+
+// **********************************************************************
+
+PFILE_INFO
+GetNextFile (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Gets next file.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Pointer to file info
+
+--*/
+{
+ return (*(Specific_Current->GetNextFile))();
+}
+
+
+
+
+// **********************************************************************
+
+
+BOOL
+RestoreFile (
+ PFILE_INFO FileInfo
+ )
+/*++
+
+Routine Description:
+
+ Restores one file.
+
+Arguments:
+
+ IN FileInfo - Supplies pointer to information structure
+
+Return Value:
+
+ TRUE if file restored, FALSE otherwise
+
+--*/
+{
+
+ CHAR PathBuffer[MAX_PATH]; // For creating target directory
+ PCHAR PathPointer; // Pointer within pathBuffer.
+
+ if (FileInfo->TargetExists) {
+ if (FileInfo->Sequence == 1) {
+ //
+ // First chunk of a file, rename original file, so we can
+ // recover it in case of failure.
+ //
+ Rename(FileInfo->TargetPath, FileInfo->TmpName);
+ }
+ } else {
+ //
+ // The target directory might not exist, we have to create it.
+ //
+ MakeFullPath(PathBuffer, DestinationDrive, FileInfo->Path, "");
+
+ PathPointer = &PathBuffer[3];
+
+ while (*PathPointer) {
+ while (*PathPointer && *PathPointer != '\\') {
+ PathPointer++;
+ }
+ if (*PathPointer) {
+ *PathPointer = '\0';
+ CreateDirectory( PathBuffer, NULL );
+ *PathPointer++ = '\\';
+ }
+ }
+ }
+
+ //
+ // Have the specific function restore the file
+ //
+ return (*(Specific_Current->RestoreFile))(FileInfo);
+
+}
+
+
+
+
+
+// **********************************************************************
+
+
+BOOL
+RecoverFile (
+ PFILE_INFO FileInfo
+ )
+/*++
+
+Routine Description:
+
+ Recovers a Tmp file after a backup failed.
+
+Arguments:
+
+ IN FileInfo - Supplies pointer to information structure
+
+Return Value:
+
+ TRUE if recovered
+ FALSE otherwise
+
+--*/
+{
+ if (FileInfo->TargetExists) {
+
+ if (Rename(FileInfo->TmpName, FileInfo->TargetPath)) {
+ //
+ // Cannot rename, we cannot recover
+ //
+ return FALSE;
+ }
+
+ }
+ return TRUE;
+}
diff --git a/private/utils/restore/src/makefile b/private/utils/restore/src/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/restore/src/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/restore/src/makefile.inc b/private/utils/restore/src/makefile.inc
new file mode 100644
index 000000000..f7cbc888c
--- /dev/null
+++ b/private/utils/restore/src/makefile.inc
@@ -0,0 +1,4 @@
+restore.rc: rtmsg.rc msg00001.bin
+
+..\inc\rtmsg.h rtmsg.rc msg00001.bin: rtmsg.mc
+ mc -v -h ..\inc\ rtmsg.mc
diff --git a/private/utils/restore/src/match.c b/private/utils/restore/src/match.c
new file mode 100644
index 000000000..bda009018
--- /dev/null
+++ b/private/utils/restore/src/match.c
@@ -0,0 +1,841 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ misc.c
+
+Abstract:
+
+ Functions for file matching.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 14-Dec-1990
+
+
+Revision History:
+
+
+--*/
+
+
+#include "restore.h"
+
+
+
+
+//
+// Local Prototypes
+//
+void
+GetFileDateAndTime (
+ CHAR *FullPath,
+ PFATDATE Date,
+ PFATTIME Time
+ );
+
+BOOL
+NameMatch (
+ PCHAR Pattern,
+ PCHAR Path
+ );
+
+BOOL
+DateAndTimeMatch (
+ FATDATE BackupDate,
+ FATTIME BackupTime,
+ FATDATE CurrentDate,
+ FATTIME CurrentTime,
+ BOOL *ModifiedSinceLastBackup
+ );
+
+BOOL
+DateMatch (
+ FATDATE Date
+ );
+
+BOOL
+TimeMatch (
+ FATTIME Time
+ );
+
+BOOL
+IsSameDate (
+ FATDATE Date1,
+ FATDATE Date2
+ );
+
+BOOL
+IsSameTime (
+ FATTIME Time1,
+ FATTIME Time2
+ );
+
+BOOL
+IsBeforeDate(
+ FATDATE Date1,
+ FATDATE Date2
+ );
+
+BOOL
+IsBeforeTime(
+ FATTIME Time1,
+ FATTIME Time2
+ );
+
+
+
+
+
+// **********************************************************************
+
+
+BOOL
+FileMatch (
+ PFILE_INFO FileInfo
+ )
+/*++
+
+Routine Description:
+
+ Determines if a File Information packet matches the global file
+ specification
+
+Arguments:
+
+ IN FileInfo - Supplies the pointer to the file information structure
+
+Return Value:
+
+ TRUE: File matches
+ FALSE: No match
+
+--*/
+{
+
+ FATDATE CurrentFileDate; // Date of target file
+ FATTIME CurrentFileTime; // Time of target file
+ DWORD Attributes; // File Attributes
+ BOOL ModifiedSinceLastBackup; // True if modified since last backup
+ DWORD PathMatch; // True if paths match
+
+
+ //
+ // Check paths
+ //
+ PathMatch = ComparePath(DestinationDir, FileInfo->Path);
+
+ if ((PathMatch == COMPARE_PREFIX) && (!Flag_s)) {
+ //
+ // This is a subdirectory, but /s option not set.
+ //
+ return FALSE;
+
+ } else if (PathMatch == COMPARE_NOMATCH) {
+ //
+ // Not same path, there's no match
+ //
+ return FALSE;
+ }
+
+
+ //
+ // File Names must match
+ //
+ if (!NameMatch(DestinationFile, FileInfo->FileName)) {
+ //
+ // Nope, no match
+ //
+ return FALSE;
+ }
+
+
+ //
+ // The name matches. Get the attributes of the file (at the
+ // same time, we find out if the file exists)
+ //
+ FileInfo->TargetAttributes = Attributes = GetFileAttributes(FileInfo->TargetPath);
+
+ FileInfo->TargetExists = !(Attributes == (DWORD)-1);
+
+ if (Flag_n) {
+ //
+ // If /n flag specified, then we must only restore the file if
+ // it no longer exists
+ //
+ if (Attributes == (DWORD)-1) {
+ //
+ // File does not exist, restore it
+ //
+ return TRUE;
+
+ } else {
+ //
+ // The file exits, don't restore it
+ //
+ return FALSE;
+ }
+ }
+
+
+ if (Attributes == (DWORD)-1) {
+ //
+ // If the target does not exist, then we should restore it
+ //
+ return TRUE;
+ }
+
+ //
+ // Get date and time of target file and see if they match
+ //
+ GetFileDateAndTime( FileInfo->TargetPath,
+ &CurrentFileDate,
+ &CurrentFileTime );
+
+ if (!DateAndTimeMatch( BackupDate,
+ BackupTime,
+ CurrentFileDate,
+ CurrentFileTime,
+ &ModifiedSinceLastBackup)) {
+ //
+ // Date and time does not match, don't restore this file
+ //
+ return FALSE;
+ }
+
+ //
+ // If the /p option was specified and the file is read-only, or it has
+ // changed since the last backup, we prompt the user.
+ //
+ if ( Flag_p ) {
+ WriteNewLine = FALSE;
+ if ((Attributes & FILE_ATTRIBUTE_READONLY) || ModifiedSinceLastBackup) {
+
+ BOOL ReturnValue;
+
+ if (Attributes & FILE_ATTRIBUTE_READONLY) {
+
+ DisplayMsg(STD_ERR, REST_WARNING_READONLY, FileInfo->TargetPath);
+
+ } else {
+
+ DisplayMsg(STD_ERR, REST_WARNING_FILE_CHANGED, FileInfo->TargetPath);
+
+ }
+
+ if ( !(ReturnValue = ( GetKey("YN", STD_OUT, STD_ERR) == 'Y'))) {
+ putc( '\r', STD_ERR );
+ putc( '\n', STD_ERR );
+ } else {
+ WriteNewLine = TRUE;
+ }
+ return ReturnValue;
+ }
+ }
+
+ //
+ // If the /m option was specified, the file should only be restored
+ // if its archive bit is set.
+ //
+ if( Flag_m && !( Attributes & FILE_ATTRIBUTE_ARCHIVE ) ) {
+
+ // the /m option is specified but the archive bit is
+ // not set.
+ //
+ return FALSE;
+ }
+
+ //
+ // All tests pass, we must restore this file
+ //
+ return TRUE;
+}
+
+
+
+
+
+// **********************************************************************
+
+void
+GetFileDateAndTime (
+ CHAR *FullPath,
+ PFATDATE Date,
+ PFATTIME Time
+ )
+/*++
+
+Routine Description:
+
+ Gets the date and time of a file
+
+
+Arguments:
+
+ IN FullPath - Supplies pointer to file name
+ OUT Date - Supplies pointer to date
+ OUT Time - Supplies pointer to time
+
+
+Return Value:
+
+ none
+
+
+--*/
+{
+ HANDLE FileHandle; // File handle
+ FILETIME UtcFileTime; // Time of last modification (UTC)
+ FILETIME LocalFileTime; // Time of last modification (local)
+ BOOL StatusOk;
+
+ //
+ // We need to obtain a handle to the file
+ //
+ FileHandle = CreateFile( FullPath,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL );
+
+
+ if (FileHandle == INVALID_HANDLE_VALUE) {
+ return;
+ }
+
+ //
+ // Now get the date and time of last modification
+ //
+ StatusOk = GetFileTime( FileHandle,
+ NULL,
+ NULL,
+ &UtcFileTime );
+
+ // Convert the time to local time:
+ //
+ FileTimeToLocalFileTime( &UtcFileTime, &LocalFileTime );
+
+
+ FileTimeToDosDateTime( &LocalFileTime,
+ (LPWORD)Date,
+ (LPWORD)Time);
+
+ CloseHandle(FileHandle);
+}
+
+
+
+
+
+// **********************************************************************
+
+
+DWORD
+ComparePath (
+ PCHAR Path1,
+ PCHAR Path2
+ )
+/*++
+
+Routine Description:
+
+ Compares two paths
+
+Arguments:
+
+ IN Path1 - Supplies pointer to first path
+ IN Path2 - Supplies pointer to second path
+
+Return Value:
+
+ COMPARE_NOMATCH if paths don't match
+ COMPARE_PREFIX if Path1 is a prefix of Path2
+ COMPARE_MATCH if Path1 == Path2
+
+
+--*/
+{
+
+ if ( (*Path1 == '\\') &&
+ (*(Path1+1)=='\0') &&
+ (*Path2 == '\\' ) ) {
+
+ PCHAR p = Path2;
+#ifdef DBCS
+ PCHAR q = PrevChar( Path2, Path2 + strlen(Path2) );
+#else
+ PCHAR q = Path2 + strlen(Path2)-1;
+#endif
+
+ while ( (p != q) && (*q != '\\')) {
+#ifdef DBCS
+ q = PrevChar( p, q );
+#else
+ q--;
+#endif
+ }
+
+ if ( p == q ) {
+ return COMPARE_MATCH;
+ } else {
+ return COMPARE_PREFIX;
+ }
+ }
+
+
+ while (*Path1 && *Path2) {
+ if ((CHAR)(toupper(*Path1)) != (CHAR)(toupper(*Path2))) {
+ return COMPARE_NOMATCH;
+ }
+#ifdef DBCS
+ Path1 = NextChar( Path1 );
+ Path2 = NextChar( Path2 );
+#else
+ Path1++; Path2++;
+#endif
+ }
+
+
+ if (*Path1) {
+ //
+ // Path1 is not a prefix of Path2
+ //
+ return COMPARE_NOMATCH;
+ }
+
+ if (*Path2) {
+ //
+ // Path1 is a prefix of Path2
+ //
+ return COMPARE_PREFIX;
+ }
+
+ //
+ // We have an exact match
+ //
+ return COMPARE_MATCH;
+
+}
+
+
+
+
+// **********************************************************************
+
+
+BOOL
+NameMatch (
+ PCHAR Pattern,
+ PCHAR Path
+ )
+/*++
+
+Routine Description:
+
+ Determines if a pattern matches a file path
+
+Arguments:
+
+ IN Pattern - Supplies pointer to pattern (may include wildcards)
+ IN Path - Supplies pointer to path
+
+Return Value:
+
+ TRUE: match
+ FALSE: no match
+
+--*/
+{
+
+ switch (*Pattern) {
+ case '\0':
+ return *Path == '\0';
+
+ case '.':
+ if ( *Path == '\0' ) {
+#ifdef DBCS
+ return NameMatch( NextChar(Pattern), Path );
+#else
+ return NameMatch( Pattern+1, Path );
+#endif
+ } else if ( *Path == '.' ) {
+#ifdef DBCS
+ // Yes, both Pattern and Path point '.', we don't need NextChar().
+ // But it's a good idea to always call a right function.
+ //
+ return NameMatch( NextChar(Pattern), NextChar(Path) );
+#else
+ return NameMatch( Pattern+1, Path+1 );
+#endif
+ }
+ return FALSE;
+
+ case '?':
+#ifdef DBCS
+ return ( *Path != '\0') && NameMatch( NextChar(Pattern), NextChar(Path)) ;
+#else
+ return ( *Path != '\0') && NameMatch(Pattern+1, Path+1) ;
+#endif
+
+ case '*':
+#ifdef DBCS
+ {
+ PCHAR PathTmp;
+
+ do {
+ if ( NameMatch( NextChar(Pattern), Path) ) {
+ return TRUE;
+ }
+ PathTmp = Path;
+ Path = NextChar(Path);
+ } while ( *PathTmp );
+ }
+#else
+ do {
+ if (NameMatch(Pattern + 1, Path)) {
+ return TRUE;
+ }
+ } while (*Path++);
+#endif
+ return FALSE;
+
+ default:
+#ifdef DBCS
+ if ( IsDBCSLeadByte( *Pattern )) {
+ if ( *Path == *Pattern && *(Path+1) == *(Pattern+1) ) {
+ return NameMatch( Pattern + 2, Path + 2 );
+ } else {
+ return FALSE;
+ }
+ } else {
+ return ( toupper(*Path) == toupper(*Pattern)) &&
+ NameMatch(Pattern + 1, Path + 1);
+ }
+#else
+ return ( toupper(*Path) == toupper(*Pattern)) && NameMatch(Pattern + 1, Path + 1);
+#endif
+ }
+}
+
+
+
+
+// **********************************************************************
+
+BOOL
+DateAndTimeMatch (
+ FATDATE BackupDate,
+ FATTIME BackupTime,
+ FATDATE CurrentDate,
+ FATTIME CurrentTime,
+ BOOL *ModifiedSinceLastBackup
+ )
+/*++
+
+Routine Description:
+
+ Determines if Dates and times match
+
+
+Arguments:
+
+ IN BackupDate, - Supplies pointer to the backup date
+ IN BackupTime, - Supplies pointer to the backup time
+ IN CurrentDate, - Supplies pointer to the file date
+ IN CurrentTime, - Supplies pointer to the file time
+ OUT *ModifiedSinceLastBackup - Supplies pointer to boolean, which
+ becomes TRUE if the file has been
+ modified since last backup
+
+Return Value:
+
+ TRUE if Date and time match
+ FALSE otherwise
+
+
+--*/
+{
+
+ //
+ // First we determine if the file has been modified since the last
+ // backup by comparing the current date and the backup date
+ //
+ if ( (IsBeforeDate(BackupDate, CurrentDate)) ||
+ (IsSameDate(BackupDate, CurrentDate) && IsBeforeTime(BackupTime, CurrentTime))) {
+
+ *ModifiedSinceLastBackup = TRUE;
+
+ } else {
+
+ *ModifiedSinceLastBackup = FALSE;
+ }
+
+ //
+ // Now we check the current date and time to see if they match
+ // the criteria set in the command line.
+ //
+ return ( DateMatch(CurrentDate) &&
+ TimeMatch(CurrentTime) );
+
+}
+
+
+
+
+// **********************************************************************
+
+BOOL
+DateMatch (
+ FATDATE Date
+ )
+/*++
+
+Routine Description:
+
+ Determines if date matches
+
+
+Arguments:
+
+ IN Date - Supplies date
+
+Return Value:
+
+ TRUE if date matches
+ FALSE otherwise
+
+
+--*/
+{
+ BOOL Match = TRUE;
+
+ if (Flag_z) {
+ //
+ // /z - date must be exact
+ //
+ return IsSameDate(Date, ExactDate);
+ }
+
+ if (Flag_b) {
+ //
+ // /b - current date must be before or equal the specified date
+ //
+ Match &= IsBeforeDate(Date, BeforeDate) || IsSameDate(Date, BeforeDate);
+ }
+
+ if (Flag_a) {
+ //
+ // /a - current date must be equal or after specified date
+ //
+ Match &= IsBeforeDate(AfterDate, Date) || IsSameDate(AfterDate, Date);
+ }
+
+ return Match;
+
+}
+
+
+
+
+// **********************************************************************
+
+BOOL
+TimeMatch (
+ FATTIME Time
+ )
+/*++
+
+Routine Description:
+
+ Determines if a time matches
+
+
+Arguments:
+
+ IN Time - Supplies the time
+
+Return Value:
+
+ TRUE if time matches
+ FALSE otherwise
+
+
+--*/
+{
+ BOOL Match = TRUE;
+
+ if (Flag_Y) {
+ //
+ // /Y - times must be the same
+ //
+ return IsSameTime(Time, ExactTime);
+ }
+
+ if (Flag_e) {
+ //
+ // /e - current time must be equal or earlier than given time
+ //
+ Match &= IsBeforeTime(Time, BeforeTime) || IsSameTime(Time, BeforeTime);
+ }
+
+ if (Flag_L) {
+ //
+ // /L - current time must be equal or later than given time
+ //
+ Match &= IsBeforeTime(AfterTime, Time) || IsSameTime(AfterTime, Time);
+ }
+
+ return Match;
+}
+
+
+
+
+
+// **********************************************************************
+
+BOOL
+IsSameDate (
+ FATDATE Date1,
+ FATDATE Date2
+ )
+/*++
+
+Routine Description:
+
+ Determines if two dates are the same
+
+
+Arguments:
+
+ IN Date1 - Supplies First date
+ IN Date2 - Supplies second date
+
+Return Value:
+
+ TRUE if both dates are the same
+ FALSE otherwise
+
+
+--*/
+{
+
+ return (DATE_WORD(Date1) == DATE_WORD(Date2));
+
+}
+
+
+
+
+// **********************************************************************
+
+BOOL
+IsSameTime (
+ FATTIME Time1,
+ FATTIME Time2
+ )
+/*++
+
+Routine Description:
+
+ Determines if two times are the same
+
+
+Arguments:
+
+
+ IN Time1 - Supplies pointer to first time
+ IN Time2 - Supplies pointer to second time
+
+Return Value:
+
+ TRUE if both times are the same
+ FALSe otherwise
+
+--*/
+{
+
+ return (TIME_WORD(Time1) == TIME_WORD(Time2));
+
+}
+
+
+
+
+
+// **********************************************************************
+
+BOOL
+IsBeforeDate(
+ FATDATE Date1,
+ FATDATE Date2
+ )
+/*++
+
+Routine Description:
+
+ Determines if one date is before another date
+
+
+Arguments:
+
+ IN Date1 - Supplies pointer to first date
+ IN Date2 - Supplies pointer to second date
+
+Return Value:
+
+ TRUE if Date1 is before Date2
+ FALSE otherwise
+
+--*/
+{
+
+ return ((Date1.Year < Date2.Year) ||
+ ((Date1.Year == Date2.Year) &&
+ ((Date1.Month < Date2.Month) ||
+ ((Date1.Month == Date2.Month) && (Date1.Day < Date2.Day)))));
+
+}
+
+
+
+
+
+// **********************************************************************
+
+BOOL
+IsBeforeTime(
+ FATTIME Time1,
+ FATTIME Time2
+ )
+/*++
+
+Routine Description:
+
+ Determines if one time is before another time
+
+
+Arguments:
+
+ IN Time1 - Supplies pointer to first time
+ IN Time2 - Supplies pointer to second time
+
+Return Value:
+
+ TRUE if Time1 is before Time2
+ FALSE otherwise
+
+--*/
+{
+
+ return ((Time1.Hours < Time2.Hours) ||
+ ((Time1.Hours == Time2.Hours) &&
+ ((Time1.Minutes < Time2.Minutes) ||
+ ((Time1.Minutes == Time2.Minutes) && (Time1.DoubleSeconds < Time2.DoubleSeconds)))));
+
+}
+
diff --git a/private/utils/restore/src/mbcs.c b/private/utils/restore/src/mbcs.c
new file mode 100644
index 000000000..ad7bb1291
--- /dev/null
+++ b/private/utils/restore/src/mbcs.c
@@ -0,0 +1,94 @@
+#include "restore.h"
+
+#if defined JAPAN || defined DBCS
+
+/***************************************************************************\
+* NextChar()
+*
+*
+* History:
+* 04-26-93 takaok : stolen from user\client\strings.c and rename
+*
+\***************************************************************************/
+
+LPSTR NextChar( LPCSTR lpCurrentChar)
+{
+ if ( IsDBCSLeadByte( *lpCurrentChar ) )
+ lpCurrentChar += 2;
+ else if ( *lpCurrentChar )
+ lpCurrentChar++;
+ return (LPSTR)lpCurrentChar;
+}
+
+/***************************************************************************\
+* CharPrevA (API)
+*
+* Move to previous character in string, unless already at start
+*
+* History:
+* 04-26-93 takaok : stolen from user\client\strings.c and rename
+*
+\***************************************************************************/
+
+LPSTR PrevChar( LPCSTR lpStart, LPCSTR lpCurrentChar)
+{
+ LPCSTR lpCurrent = lpCurrentChar;
+
+ if (lpStart == lpCurrent)
+ return (LPSTR)lpStart;
+
+ if (--lpCurrent == lpStart)
+ return (LPSTR)lpStart;
+
+ // we assume lpCurrentChar never points the second byte of double byte character
+ // this check makes things a little bit faster [takaok]
+ if ( IsDBCSLeadByte(*lpCurrent) )
+ return ((LPSTR)(lpCurrent - 1));
+
+ do {
+ lpCurrent--;
+ if (!IsDBCSLeadByte(*lpCurrent)) {
+ lpCurrent++;
+ break;
+ }
+ } while(lpCurrent != lpStart);
+
+ return (LPSTR)(lpCurrentChar - (((lpCurrentChar - lpCurrent) & 1) ? 1 : 2));
+}
+
+/***************************************************************************\
+* AppendBackSlashIfNeeded( LPSTR path, INT length )
+*
+* check the last character of path, if it's not '\', append the '\'.
+*
+* History:
+* 04-26-93 takaok : created
+*
+\***************************************************************************/
+BOOL AppendBackSlashIfNeeded( LPCSTR path, INT length )
+{
+ PCSTR pc;
+ INT i;
+ BOOL bSlash;
+
+//
+// check if the last character is backslash
+//
+ bSlash = FALSE;
+ for ( pc = path, i = 0; *pc && i < length; i++, pc = NextChar( pc ) ) {
+ if ( *pc == '\\' )
+ bSlash = TRUE;
+ else
+ bSlash = FALSE;
+ }
+
+//
+// if the last character is not backslash, append "\\"
+//
+ if ( ! bSlash ) {
+ strcat("path", "\\");
+ }
+ return ( ! bSlash );
+}
+
+#endif // JAPAN || DBCS
diff --git a/private/utils/restore/src/misc.c b/private/utils/restore/src/misc.c
new file mode 100644
index 000000000..728d18acb
--- /dev/null
+++ b/private/utils/restore/src/misc.c
@@ -0,0 +1,503 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ misc.c
+
+Abstract:
+
+ Miscelaneous functions used by the restore utility.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 14-Dec-1990
+
+
+Revision History:
+
+
+--*/
+
+
+#include "restore.h"
+
+
+
+//
+// Template for temporary names
+//
+#define TMP_FILENAME "_REST%d.___"
+
+
+
+
+
+
+
+// **********************************************************************
+
+void
+MakeFullPath (
+ CHAR *FullPath,
+ CHAR *Drive,
+ CHAR *Path,
+ CHAR *FileName
+ )
+/*++
+
+Routine Description:
+
+ makes a full path out of a drive, a directory and a filename
+
+Arguments:
+
+ OUT FullPath - Supplies pointer to buffer
+ IN Drive - Supplies pointer to drive part
+ IN Path - Supplies pointer to directory path
+ IN FileName - Supplies pointer to file name
+
+
+Return Value:
+
+ none
+
+
+--*/
+{
+ CHAR *p;
+
+ strcpy(FullPath,Drive);
+ strcat(FullPath, Path);
+#ifdef DBCS
+ (VOID)AppendBackSlashIfNeeded(FullPath, strlen( FullPath ) );
+#else
+ p = FullPath + strlen(FullPath);
+ p--;
+ if (*p != '\\') {
+ strcat(FullPath, "\\");
+ }
+#endif
+ strcat(FullPath, FileName);
+}
+
+
+
+
+
+
+
+// **********************************************************************
+
+void
+MakeTmpPath (
+ CHAR *FullPath,
+ CHAR *Drive,
+ CHAR *Path,
+ DWORD Sequence
+ )
+/*++
+
+Routine Description:
+
+ makes a temporary file path
+
+
+Arguments:
+
+ OUT FullPath - Supplies pointer to buffer
+ IN Drive - Supplies pointer to drive part
+ IN Path - Supplies pointer to directory path
+ IN Sequence - Supplies sequence number
+
+
+Return Value:
+
+ none
+
+
+--*/
+{
+ CHAR *p;
+
+ strcpy(FullPath,Drive);
+ strcat(FullPath, Path);
+ p = FullPath + strlen(FullPath);
+ p--;
+ if (*p != '\\') {
+ strcat(FullPath, "\\");
+ }
+ p = p + strlen(p);
+ sprintf(p, TMP_FILENAME, Sequence);
+}
+
+
+
+
+
+
+
+
+// **********************************************************************
+
+PCHAR
+MakeStringDate(
+ CHAR *StringDate,
+ FATDATE Date
+ )
+/*++
+
+Routine Description:
+
+ Formats a date and puts its string representation in the given buffer
+
+
+Arguments:
+
+ OUT StringDate - Buffer where the date will be formated
+ IN Date - The date to format
+
+Return Value:
+
+ Pointer to StringDate
+
+--*/
+{
+
+ MakeStringNumber(StringDate, Date.Month, 2);
+ StringDate[2] = '-';
+ MakeStringNumber(&StringDate[3], Date.Day, 2);
+ StringDate[5] = '-';
+ MakeStringNumber(&StringDate[6], Date.Year+1980, 4);
+
+ return StringDate;
+}
+
+
+
+
+// **********************************************************************
+
+PCHAR
+MakeStringTime(
+ CHAR *StringTime,
+ FATTIME Time
+ )
+/*++
+
+Routine Description:
+
+ Formats a time and puts its string representation in the given buffer
+
+
+Arguments:
+
+ OUT StringTime - Buffer where the time will be formated
+ IN Time - The time to format
+
+Return Value:
+
+ Pointer to StringDate
+
+--*/
+{
+
+ MakeStringNumber(StringTime, Time.Hours, 2);
+ StringTime[2] = ':';
+ MakeStringNumber(&StringTime[3], Time.Minutes, 2);
+ StringTime[5] = ':';
+ MakeStringNumber(&StringTime[6], Time.DoubleSeconds * 2, 4);
+
+ return StringTime;
+}
+
+
+
+
+
+
+// **********************************************************************
+
+PCHAR
+MakeStringNumber(
+ CHAR *Buffer,
+ DWORD Number,
+ DWORD Width
+ )
+/*++
+
+Routine Description:
+
+ Formats a number and pads it with zeros
+
+
+Arguments:
+
+ OUT Buffer - Supplies the Buffer where the number will be formated
+ IN Number - Supplies the number
+ IN Width - Number of characters that the number must occupy
+
+Return Value:
+
+ Pointer to Buffer
+
+--*/
+
+{
+ CHAR LocalBuffer[16];
+ CHAR *p;
+
+ sprintf(LocalBuffer, "%14d", Number);
+
+ p = LocalBuffer + strlen(LocalBuffer) - 1;
+
+ while ((p >= LocalBuffer) && (*p != ' ')) {
+ p--;
+ }
+
+ while ((p >= LocalBuffer) && (strlen(p) <= Width)) {
+ *p-- = '0';
+ }
+
+ p++;
+
+ strcpy(Buffer, p);
+
+ return Buffer;
+}
+
+
+
+
+// **********************************************************************
+
+BOOL
+Rename (
+ CHAR *OriginalFile,
+ CHAR *NewFile
+ )
+/*++
+
+Routine Description:
+
+ Renames a file, conserving attributes. Renames the file even if the
+ target file exists.
+
+Arguments:
+
+ IN OriginalFile - Supplies name of original file
+ IN NewFile - Supplies name of new file
+
+Return Value:
+
+ TRUE if renamed
+ FALSE otherwise
+
+--*/
+{
+ DWORD Attributes;
+
+
+ //
+ // See if the original file exists
+ //
+ Attributes = GetFileAttributes(OriginalFile);
+
+ if (Attributes == -1) {
+ //
+ // OriginalFile does not exist!
+ //
+ return FALSE;
+ }
+
+
+ //
+ // Set the attributes so we can rename it
+ //
+ if (!SetFileAttributes(OriginalFile, FILE_ATTRIBUTE_NORMAL)) {
+ //
+ // Cannot set the attributes
+ //
+ return FALSE;
+ }
+
+ //
+ // Make sure that the target does not exist
+ //
+ Delete(NewFile);
+
+
+ //
+ // Now try to rename
+ //
+ if (!MoveFile(OriginalFile, NewFile)) {
+ //
+ // Could not rename, restore attributes
+ //
+ SetFileAttributes(OriginalFile, Attributes);
+ return FALSE;
+ }
+
+ //
+ // Rename worked, set attributes of new file
+ //
+ return SetFileAttributes(NewFile, Attributes);
+}
+
+
+
+
+
+// **********************************************************************
+
+BOOL
+Delete (
+ CHAR *FileName
+ )
+/*++
+
+Routine Description:
+
+ Deletes a file, disregarding its attributes
+
+Arguments:
+
+ IN FileName - Supplies name of file
+
+Return Value:
+
+ TRUE if deleted
+ FALSE otherwise
+
+--*/
+{
+
+
+ //
+ // Set the attributes of the file.
+ //
+ if (!SetFileAttributes(FileName, FILE_ATTRIBUTE_NORMAL)) {
+ //
+ // Cannot set the attributes.
+ //
+ return FALSE;
+ }
+
+ //
+ // Delete the file
+ //
+ return DeleteFile(FileName);
+
+}
+
+
+
+
+
+
+
+#if defined (DEBUG)
+
+
+//
+// The C-runtime functions for checking the heap (_heapchk) are not
+// working. The following functions just verify that we are not
+// freeing memory twice, or freeing memory that we have not allocated.
+//
+
+//
+// Memory block
+//
+typedef struct BLOCK {
+ DWORD Signature; // Allocated or free
+ DWORD Size; // Size requested - does not include this header
+ BYTE Data[0]; // What we return
+} BLOCK, *PBLOCK;
+
+
+#define BLOCK_MALLOC 0xBA110CED
+#define BLOCK_FREE 0xCACACACA
+
+
+void *
+DebugRealloc (
+ void *Mem,
+ size_t Size,
+ CHAR * FileName,
+ DWORD LineNumber
+ )
+{
+ PBLOCK b;
+
+ if (Mem) {
+
+ b = (PBLOCK)(((PBYTE)Mem) - sizeof(BLOCK));
+
+ if (b->Signature != BLOCK_MALLOC) {
+ DbgPrint(" ERROR: Realloc unallocated object %X ! File %s, Line %d\n", b, FileName, LineNumber);
+ }
+
+ b->Signature = BLOCK_FREE;
+
+ } else {
+
+ b = NULL;
+ }
+
+ b = realloc(b, Size + sizeof(BLOCK));
+
+ b->Signature = BLOCK_MALLOC;
+ b->Size = Size;
+
+ return (void *)(b->Data);
+}
+
+
+
+void *
+DebugMalloc (
+ size_t Size,
+ CHAR * FileName,
+ DWORD LineNumber
+ )
+{
+ PBLOCK b = (PBLOCK)malloc(Size + sizeof(BLOCK));
+
+ if (b) {
+
+ b->Signature = BLOCK_MALLOC;
+ b->Size = Size;
+
+ return (void *)(b->Data);
+ }
+
+ return NULL;
+
+}
+
+
+
+
+void
+DebugFree (
+ void *Mem,
+ CHAR * FileName,
+ DWORD LineNumber
+ )
+{
+ if (Mem) {
+ PBLOCK b = (PBLOCK)(((PBYTE)Mem) - sizeof(BLOCK));
+
+ if (b->Signature != BLOCK_MALLOC) {
+ DbgPrint(" ERROR: Freeing unallocated object %X ! File %s, Line %d\n", b, FileName, LineNumber);
+ } else {
+ b->Signature = BLOCK_FREE;
+ free(b);
+ }
+ }
+}
+
+
+
+#endif
diff --git a/private/utils/restore/src/msg.c b/private/utils/restore/src/msg.c
new file mode 100644
index 000000000..6546b6901
--- /dev/null
+++ b/private/utils/restore/src/msg.c
@@ -0,0 +1,214 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ msg.c
+
+Abstract:
+
+ Message displaying.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 20-Feb-1990
+
+
+Revision History:
+
+
+--*/
+
+
+#include <conio.h>
+#include "restore.h"
+#include <stdarg.h>
+
+
+#define DISPLAYBUFFER_SIZE 4096
+#define CTRL_C ((CHAR)3)
+
+//
+// We use one buffer to display messages. Note that this means that
+// no two threads should ever try to use the buffer at the same
+// time.
+//
+static CHAR DisplayBuffer[DISPLAYBUFFER_SIZE];
+
+
+// **********************************************************************
+
+void
+Usage (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Display program usage
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ DisplayMsg(STD_OUT, REST_MSG_USAGE, NULL);
+ ExitStatus(EXIT_NORMAL);
+}
+
+
+
+
+
+// **********************************************************************
+
+void
+DisplayMsg (
+ FILE* f,
+ DWORD MsgNum,
+ ...
+ )
+/*++
+
+Routine Description:
+
+ Display Message
+
+Arguments:
+
+ f - Stream to which to write message
+ MsgNum - Message number
+ ... - arguments
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+ va_list ap;
+
+ va_start(ap, MsgNum);
+
+ FormatMessage( FORMAT_MESSAGE_FROM_HMODULE,
+ NULL,
+ MsgNum,
+ 0,
+ DisplayBuffer,
+ DISPLAYBUFFER_SIZE,
+ &ap );
+
+ fprintf(f, DisplayBuffer);
+
+ va_end(ap);
+
+}
+
+
+
+
+
+
+// **********************************************************************
+
+CHAR
+GetKey (
+ PCHAR PossibleKeys,
+ FILE* StdHandleCh,
+ FILE* StdHandleNl
+ )
+/*++
+
+Routine Description:
+
+ Gets a key
+
+Arguments:
+
+ IN PossibleKeys - Set of acceptable characters
+ IN StdHandleCh - Handle to write the response to
+ IN StdHandleNl - Handle to write new line to
+
+Return Value:
+
+ Key pressed
+
+--*/
+{
+ CHAR c;
+ CHAR Orgc;
+ PCHAR p;
+ HANDLE StdIn;
+ DWORD Mode;
+ BOOLEAN IsConsole;
+
+ //
+ // Find out if stdin is a console
+ //
+ StdIn = GetStdHandle( STD_INPUT_HANDLE );
+ IsConsole = GetConsoleMode( StdIn, &Mode );
+
+
+ while (TRUE) {
+
+ if ( IsConsole ) {
+
+ Orgc = (CHAR)_getch();
+
+ //
+ // Some keypresses can result in the generation of two keycodes,
+ // eg the arrow keys. The getch() function stores the second
+ // keycode in the ungetch buffer. We want to discard that second
+ // keycode so it won't hose us the next time we want input from the
+ // user, but we don't want to call getch() if it might block for
+ // input. Thus this hack, which clears the ungetch buffer.
+ //
+
+ _ungetch(1);
+ _getch();
+
+ } else {
+ Orgc = (CHAR)getchar();
+ }
+ c = Orgc;
+
+ if (c == CTRL_C ) {
+ ExitStatus( EXIT_USER );
+ }
+
+ if (c == (CHAR)0) {
+ continue;
+ }
+
+ c = (CHAR)toupper(c);
+
+ if (PossibleKeys) {
+ p = PossibleKeys;
+ while (*p) {
+ if (c == *p++) {
+ p--;
+ break;
+ }
+ }
+ if (*p) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ putc( Orgc, StdHandleCh );
+ putc( '\r', StdHandleNl );
+ putc( '\n', StdHandleNl );
+
+ return c;
+}
diff --git a/private/utils/restore/src/new.c b/private/utils/restore/src/new.c
new file mode 100644
index 000000000..4f57fa0ff
--- /dev/null
+++ b/private/utils/restore/src/new.c
@@ -0,0 +1,751 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ new.c
+
+Abstract:
+
+ Functions dealing with new backup file format
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 20-Feb-1991
+
+
+Revision History:
+
+
+--*/
+
+
+#include "restore.h"
+
+
+//
+// A Disk in the "New" format can be either a DOS disk, an OS/2 1.1
+// disk, or an OS/2 1.2 disk.
+//
+typedef enum DISK_FORMAT {
+ FORMAT_DOS, // DOS Backup format
+ FORMAT_OS211, // OS/2 V1.1 Backup format
+ FORMAT_OS212 // OS/2 V1.2 Backup format
+} DISK_FORMAT;
+
+
+//
+// Global variables
+//
+NEW_DISKINFO NewDiskInfo; // Disk header
+BOOL DiskNew; // TRUE if this is a new disk
+HANDLE ControlHandle; // Handle of control file
+DISK_FORMAT DiskFormat; // Format of the backup disk
+WORD NumEntries; // Number of entries in current dir
+
+//
+// Buffers for containing directory and file records
+//
+BYTE DirBuffer [ sizeof( DIR_RECORD_OS212 ) ];
+BYTE FileBuffer [ sizeof( FILE_RECORD_OS212 ) ];
+
+//
+// The following macros are used to access the fields of the directory
+// and file records of the different backup formats.
+//
+#define DirRecord ( (PDIR_RECORD)DirBuffer )
+#define DirRecordOs211 ( (PDIR_RECORD_OS211)DirBuffer )
+#define DirRecordOs212 ( (PDIR_RECORD_OS212)DirBuffer )
+#define FileRecord ( (PFILE_RECORD)FileBuffer )
+#define FileRecordOs211 ( (PFILE_RECORD_OS211)FileBuffer )
+#define FileRecordOs212 ( (PFILE_RECORD_OS212)FileBuffer )
+
+//
+// Macro for obtaining the offset of the next directory record in the
+// control file.
+//
+#define NextDirRecord \
+ ( (DiskFormat == FORMAT_DOS) ? DirRecord->NextDirRecord : \
+ (DiskFormat == FORMAT_OS211) ? DirRecordOs211->NextDirRecord : \
+ DirRecordOs212->NextDirRecord )
+
+
+//
+// The names of the control and backup files. These are patched to
+// reflect drive and sequence number.
+//
+BOOLEAN UseSubdir = FALSE;
+CHAR ControlFile[] = "?:\\CONTROL.???";
+CHAR SubdirControlFile[] = "?:\\BACKUP\\CONTROL.???";
+CHAR BackupFile[] = "?:\\BACKUP.XXX";
+CHAR SubdirBackupFile[] = "?:\\BACKUP\\BACKUP.XXX";
+
+
+
+//
+// Local prototypes
+//
+static
+BOOL
+GetDirRecord (
+ );
+
+static
+BOOL
+GotOneFile (
+ PFILE_INFO FileInfo
+ );
+
+
+
+
+
+
+
+// **********************************************************************
+
+DWORD
+New_VerifyDiskSequence (
+ PWORD Sequence
+ )
+/*++
+
+Routine Description:
+
+ Verify that a certain backup disk is mounted.
+
+Arguments:
+
+ OUT Sequence - Supplies pointer to the desired sequence number.
+
+Return Value:
+
+ DISK_OK if format and sequence match,
+ DISK_OUTOFSEQUENCE if new format but wrong sequence
+ DISK_UNKNOWN if not in new format
+
+--*/
+{
+
+ DWORD NumRead; // Number of bytes read
+ FILETIME UtcLastTime; // Time last written, UTC
+ FILETIME LastTime; // Time last written, local time
+ HANDLE FindHandle; // Handle for FindFirstFile
+ WIN32_FIND_DATA FindData; // Buffer for FindFirstFile
+
+ //
+ // Patch the name of the control file.
+ //
+ ControlFile[0] = BackupFile[0] = *SourceSpec;
+ SubdirControlFile[0] = SubdirBackupFile[0] = *SourceSpec;
+
+ ControlFile[11] = ControlFile[12] = ControlFile[13] = '?';
+ SubdirControlFile[18] = SubdirControlFile[19] = SubdirControlFile[20] = '?';
+
+ //
+ // Try to find the control file
+ //
+ UseSubdir = FALSE;
+ FindHandle = FindFirstFile(ControlFile, &FindData);
+
+ if (FindHandle == INVALID_HANDLE_VALUE) {
+
+ // Did not find the control file in the root. If this
+ // is not a removable drive, look in the subdirectory
+ // BACKUP.
+ //
+ if( SourceDriveType != DRIVE_REMOVABLE &&
+ (FindHandle = FindFirstFile(SubdirControlFile, &FindData)) != INVALID_HANDLE_VALUE ) {
+
+ UseSubdir = TRUE;
+
+ } else {
+
+ //
+ // There is no control file, this is not a backup disk in the
+ // new format.
+ //
+ return DISK_UNKNOWN;
+ }
+ }
+
+ //
+ // Patch the control and backup file names.
+ //
+ ControlFile[13] = BackupFile[12] = FindData.cFileName[10];
+ ControlFile[12] = BackupFile[11] = FindData.cFileName[9];
+ ControlFile[11] = BackupFile[10] = FindData.cFileName[8];
+
+ SubdirControlFile[20] = SubdirBackupFile[19] = FindData.cFileName[10];
+ SubdirControlFile[19] = SubdirBackupFile[18] = FindData.cFileName[9];
+ SubdirControlFile[18] = SubdirBackupFile[17] = FindData.cFileName[8];
+
+ FindClose(FindHandle);
+
+ //
+ // Open the control file
+ //
+ ControlHandle = CreateFile( UseSubdir ? SubdirControlFile : ControlFile,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL );
+
+ if (ControlHandle == INVALID_HANDLE_VALUE) {
+ //
+ // We should never get here, because we know the file is there!
+ //
+ return DISK_UNKNOWN;
+ }
+
+
+ //
+ // Read the header of the control file and verify it.
+ //
+ ReadFile( ControlHandle, &NewDiskInfo, sizeof(NEW_DISKINFO), &NumRead, NULL);
+
+ if (NumRead != sizeof(NEW_DISKINFO)) {
+ //
+ // The Name might say otherwise, but this is not a valid control
+ // file.
+ //
+ CloseHandle(ControlHandle);
+ return DISK_UNKNOWN;
+ }
+
+
+ NewDiskInfo.Id[6] = '\0';
+ if (strcmp(NewDiskInfo.Id, BACKUP_ID)) {
+ //
+ // The control file does not have the correct signature.
+ //
+ CloseHandle(ControlHandle);
+ return DISK_UNKNOWN;
+ }
+
+ if (NewDiskInfo.SequenceNumber != (BYTE)*Sequence) {
+ //
+ // The disk is in the correct format, but has an incorrect
+ // sequence number.
+ //
+ CloseHandle(ControlHandle);
+ *Sequence = NewDiskInfo.SequenceNumber;
+ return (DISK_OUTOFSEQUENCE | DISK_NEW_FORMAT);
+ }
+
+ //
+ // The disk is O.K. obtain the backup date. (We disregard the time)
+ //
+ GetFileTime( ControlHandle,
+ NULL,
+ NULL,
+ &UtcLastTime );
+
+ // Convert the file time into local time:
+ //
+ FileTimeToLocalFileTime( &UtcLastTime, &LastTime );
+
+ FileTimeToDosDateTime( &LastTime,
+ (LPWORD)&BackupDate,
+ (LPWORD)&BackupTime );
+
+
+ DiskNew = TRUE;
+
+ //
+ // Determine if the disk is a DOS, OS211 or OS212 backup disk
+ //
+ SetFilePointer(ControlHandle, sizeof(NEW_DISKINFO), 0, FILE_BEGIN);
+
+ ReadFile( ControlHandle, DirRecord, sizeof(DIR_RECORD), &NumRead, NULL);
+
+
+ if ( NumRead != sizeof(DIR_RECORD)) {
+
+ if ( NumRead >= sizeof( DIR_RECORD_OS212 ) - MAX_PATH ) {
+ if ( DirRecordOs212->SystemVersion == SYSTEM_VERSION_OS2_12 ) {
+ DiskFormat = FORMAT_OS212;
+ } else {
+ return DiskFormat = DISK_UNKNOWN;
+ }
+ } else {
+ return DiskFormat = DISK_UNKNOWN;
+ }
+
+ } else {
+
+ if ( DirRecordOs212->SystemVersion == SYSTEM_VERSION_OS2_12 ) {
+ DiskFormat = FORMAT_OS212;
+ } else if ( DirRecord->Length > sizeof(DIR_RECORD) ) {
+ DiskFormat = FORMAT_OS211;
+ } else if ( DirRecord->Length == sizeof(DIR_RECORD) ) {
+ DiskFormat = FORMAT_DOS;
+ } else {
+ return DiskFormat = DISK_UNKNOWN;
+ }
+ }
+
+ return ( DISK_OK | DISK_NEW_FORMAT );
+
+}
+
+
+
+
+// **********************************************************************
+
+
+BOOL
+New_IsLastBackupDisk (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Determines if the backup disk is the last one.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ TRUE if disk is the last one, FALSE otherwise
+
+--*/
+{
+ return (NewDiskInfo.Flag == LAST_BACKUP_DISK);
+}
+
+
+
+
+
+// **********************************************************************
+
+PFILE_INFO
+New_GetNextFile (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Gets next file which meets the restore criteria.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Pointer to File info
+
+--*/
+{
+
+ PFILE_INFO FileInfo; // Pointer to FileInfo structure
+
+
+ if (DiskNew) {
+ //
+ // New disk. Read first Dir record
+ //
+ SetFilePointer(ControlHandle, sizeof(NEW_DISKINFO), 0, FILE_BEGIN);
+
+ if ( !GetDirRecord()) {
+ return NULL;
+ }
+
+ DiskNew = FALSE;
+ }
+
+ //
+ // Assume that we will find a suitable file. Allocate memory
+ // for its information structure. This memory must be freed after
+ // the file has been restored.
+ //
+ FileInfo = Malloc(sizeof(FILE_INFO));
+
+ if (GotOneFile(FileInfo)) {
+ //
+ // Found a file, return its information
+ //
+ return FileInfo;
+ } else {
+ //
+ // No luck.
+ //
+ Free(FileInfo);
+ return NULL;
+ }
+}
+
+
+
+// **********************************************************************
+
+BOOL
+GetDirRecord (
+ )
+/*++
+
+Routine Description:
+
+ Gets directory record
+
+Arguments:
+
+ None
+
+Return Value:
+
+ TRUE if directory record read, FALSE otherwise
+
+--*/
+{
+ DWORD NumRead; // Number of bytes read
+
+ switch ( DiskFormat ) {
+
+ case FORMAT_DOS:
+ ReadFile(ControlHandle, DirRecord, sizeof(DIR_RECORD), &NumRead, NULL);
+ if (NumRead != sizeof(DIR_RECORD)) {
+ return FALSE;
+ }
+ NumEntries = DirRecord->NumEntries;
+ break;
+
+ case FORMAT_OS211:
+ ReadFile(ControlHandle, DirRecordOs211, sizeof(DIR_RECORD_OS211), &NumRead, NULL);
+ if (NumRead != sizeof(DIR_RECORD_OS211)) {
+ return FALSE;
+ }
+ NumEntries = DirRecordOs211->NumEntries;
+ break;
+
+ case FORMAT_OS212:
+ ReadFile( ControlHandle,
+ DirRecordOs212,
+ sizeof(DIR_RECORD_OS212) - MAX_PATH,
+ &NumRead,
+ NULL );
+ if ( NumRead != sizeof(DIR_RECORD_OS212) - MAX_PATH ) {
+ return FALSE;
+ }
+ ReadFile( ControlHandle,
+ (PBYTE)DirRecordOs212 + sizeof(DIR_RECORD_OS212) - MAX_PATH,
+ DirRecordOs212->Length - sizeof(DIR_RECORD_OS212) + MAX_PATH,
+ &NumRead,
+ NULL );
+ if ( NumRead != DirRecordOs212->Length - sizeof(DIR_RECORD_OS212) + MAX_PATH ) {
+ return FALSE;
+ }
+ NumEntries = DirRecordOs212->NumEntries;
+ break;
+
+ default:
+ return FALSE;
+
+ }
+ return TRUE;
+}
+
+
+
+// **********************************************************************
+
+static
+BOOL
+GotOneFile (
+ PFILE_INFO FileInfo
+ )
+/*++
+
+Routine Description:
+
+ Gets next file which meets the restore criteria.
+
+Arguments:
+
+ OUT FileInfo - Supplies pointer to file information structure to
+ be filled-in.
+
+Return Value:
+
+ TRUE if a suitable file was found
+ FALSE otherwise
+
+--*/
+{
+
+ DWORD NumRead; // Number of bytes read
+
+
+ //
+ // Make sure that we hava a FileInfo structure
+ //
+ if (!FileInfo) {
+ return FALSE;
+ }
+
+
+ while ( TRUE ) {
+
+ if (NumEntries--) {
+ //
+ // There are more files under this directory
+ //
+ // Read file record
+ //
+
+ switch ( DiskFormat ) {
+
+ case FORMAT_DOS:
+ case FORMAT_OS211:
+ ReadFile(ControlHandle, FileRecord, sizeof(FILE_RECORD), &NumRead, NULL);
+ if (NumRead != sizeof(FILE_RECORD)) {
+ return FALSE;
+ }
+ //
+ // Initialize FileInfo structure
+ //
+ FileInfo->Path[0] = '\\';
+ if ( DiskFormat == FORMAT_DOS ) {
+ strcpy(&(FileInfo->Path[1]), DirRecord->Path);
+ if (strlen(DirRecord->Path) != 0) {
+ strcat(FileInfo->Path, "\\");
+ }
+ } else {
+ strcpy(&(FileInfo->Path[1]), DirRecordOs211->Path);
+ if (strlen(DirRecordOs211->Path) != 0) {
+ strcat(FileInfo->Path, "\\");
+ }
+ }
+ memcpy(FileInfo->FileName, FileRecord->FileName, 12);
+ FileInfo->FileName[12] = '\0';
+ FileInfo->Sequence = FileRecord->SequenceNumber;
+ FileInfo->Offset = FileRecord->FileOffset;
+ FileInfo->PartSize = FileRecord->PartSize;
+ FileInfo->Attr = FileRecord->Attr;
+ DATE_WORD(FileInfo->Date) = FileRecord->Date;
+ TIME_WORD(FileInfo->Time) = FileRecord->Time;
+ FileInfo->Flag = FILEINFO_OK;
+ if (FileRecord->Flag & LAST_FILECHUNK) {
+ FileInfo->Flag |= FILEINFO_LAST;
+ }
+ break;
+
+
+ case FORMAT_OS212:
+ ReadFile(ControlHandle,
+ FileRecordOs212,
+ sizeof(FILE_RECORD_OS212) - MAX_PATH,
+ &NumRead,
+ NULL);
+ if (NumRead != sizeof(FILE_RECORD_OS212) - MAX_PATH) {
+ return FALSE;
+ }
+ ReadFile(ControlHandle,
+ (PBYTE)FileRecordOs212 + sizeof(FILE_RECORD_OS212) - MAX_PATH,
+ FileRecordOs212->NameLength+1,
+ &NumRead,
+ NULL);
+ if (NumRead != (DWORD)(FileRecordOs212->NameLength+1)) {
+ return FALSE;
+ }
+ //
+ // Initialize FileInfo structure
+ //
+ FileInfo->Path[0] = '\\';
+ memcpy( &(FileInfo->Path[1]), DirRecordOs212->Path, DirRecordOs212->PathLength );
+ FileInfo->Path[ DirRecordOs212->PathLength+1] = '\0';
+ if (DirRecordOs212->PathLength != 0) {
+ strcat(FileInfo->Path, "\\");
+ }
+ memcpy(FileInfo->FileName, FileRecordOs212->FileName, FileRecordOs212->NameLength);
+ FileInfo->FileName[FileRecordOs212->NameLength] = '\0';
+ FileInfo->Sequence = FileRecordOs212->SequenceNumber;
+ FileInfo->Offset = FileRecordOs212->FileOffset;
+ FileInfo->PartSize = FileRecordOs212->PartSize;
+ FileInfo->Attr = FileRecordOs212->Attr;
+ DATE_WORD(FileInfo->Date) = FileRecordOs212->Date;
+ TIME_WORD(FileInfo->Time) = FileRecordOs212->Time;
+ FileInfo->Flag = FILEINFO_OK;
+ if (FileRecordOs212->Flag & LAST_FILECHUNK) {
+ FileInfo->Flag |= FILEINFO_LAST;
+ }
+ break;
+
+ default:
+ return FALSE;
+
+ }
+
+ MakeFullPath(FileInfo->TargetPath, DestinationDrive, FileInfo->Path, FileInfo->FileName);
+
+ //
+ // If this FileInfo matches restore criteria, we got our guy.
+ //
+ if (FileMatch(FileInfo)) {
+ return TRUE;
+ }
+
+ } else {
+ //
+ // No more files under current directory
+ //
+ if (NextDirRecord == LAST_DIR_RECORD) {
+ //
+ // No more entries in this disk
+ //
+ CloseHandle(ControlHandle);
+ return FALSE;
+ } else {
+ //
+ // Get next dir record
+ //
+ SetFilePointer(ControlHandle, NextDirRecord, 0, FILE_BEGIN);
+
+ if ( !GetDirRecord() ) {
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+
+
+
+
+// **********************************************************************
+
+BOOL
+New_RestoreFile (
+ PFILE_INFO FileInfo
+ )
+/*++
+
+Routine Description:
+
+ Restores one file.
+
+Arguments:
+
+ IN FileInfo - Supplies pointer to information structure
+
+Return Value:
+
+ TRUE if file restored, FALSE otherwise
+
+--*/
+{
+ DWORD CreationDisposition; // How to open the target file
+ HANDLE HandleSrc; // Handle to BACKUP.XXX
+ HANDLE HandleDst; // Handle to target file
+ FILETIME UtcFileTime; // Time to set (UTC)
+ FILETIME LocalFileTime; // Time to set (Local)
+ BOOL RestoreStatus = TRUE; // Status of restore;
+
+
+ //
+ // Open (or create) the target file
+ //
+ if (FileInfo->Sequence == 1 ) {
+ //
+ // First chunk of the file. Create a new target file (overwritting
+ // the existing one.
+ //
+ CreationDisposition = CREATE_ALWAYS;
+ } else {
+ //
+ // Not the first chunk of the file. Apend to the existing file
+ //
+ CreationDisposition = OPEN_EXISTING;
+ }
+
+ HandleDst = CreateFile( FileInfo->TargetPath,
+ GENERIC_WRITE,
+ 0,
+ NULL,
+ CreationDisposition,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL );
+
+ SetFilePointer( HandleDst,
+ 0,
+ 0,
+ FILE_END );
+
+
+
+ //
+ // Open the BACKUP.XXX file
+ //
+ HandleSrc = CreateFile( UseSubdir ? SubdirBackupFile : BackupFile,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL );
+
+ SetFilePointer( HandleSrc,
+ FileInfo->Offset,
+ 0,
+ FILE_BEGIN );
+
+
+ //
+ // Everything set. Now copy the file
+ //
+ if (!(RestoreStatus = CopyData(HandleSrc, HandleDst, FileInfo->PartSize))) {
+ CloseHandle(HandleSrc);
+ CloseHandle(HandleDst);
+ return RestoreStatus;
+ }
+
+ //
+ // If this is the last chunk of the file, the we set the
+ // attributes, date, etc. Note that the date and time stored
+ // in the FILE_INFO structure is local time, so it has to
+ // be converted to UTC before we can feed it to SetFileTime.
+ //
+ if (FileInfo->Flag & FILEINFO_LAST) {
+
+ BOOL StatusOk;
+
+ SetFileAttributes(FileInfo->TargetPath, FileInfo->Attr);
+
+ StatusOk = DosDateTimeToFileTime( DATE_WORD(FileInfo->Date),
+ TIME_WORD(FileInfo->Time),
+ &LocalFileTime );
+
+ LocalFileTimeToFileTime( &LocalFileTime, &UtcFileTime );
+
+ StatusOk |= SetFileTime( HandleDst,
+ &UtcFileTime,
+ &UtcFileTime,
+ &UtcFileTime );
+
+ if (!StatusOk) {
+ return FALSE;
+ } else {
+ // FileInfo->TargetPath,
+ // (DWORD)FileInfo->Date.Date.Day, (DWORD)FileInfo->Date.Date.Month, (DWORD)FileInfo->Date.Date.Year,
+ // (DWORD)FileInfo->Time.Time.Hours, (DWORD)FileInfo->Time.Time.Minutes, (DWORD)FileInfo->Time.Time.DoubleSeconds*2));
+ }
+ }
+
+ CloseHandle(HandleSrc);
+ CloseHandle(HandleDst);
+
+ return RestoreStatus;
+}
diff --git a/private/utils/restore/src/old.c b/private/utils/restore/src/old.c
new file mode 100644
index 000000000..be8a7be84
--- /dev/null
+++ b/private/utils/restore/src/old.c
@@ -0,0 +1,527 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ old.c
+
+Abstract:
+
+ Functions dealing with old format
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 20-Feb-1991
+
+
+Revision History:
+
+
+--*/
+
+#include "restore.h"
+
+
+
+
+//
+// Global variables
+//
+CHAR BackupId[] = "?:\\BACKUPID.@@@"; // Backup disk header file
+OLD_DISKINFO OldDiskInfo; // Contents of header file
+CHAR FindPath[] = "?:\\*.*"; // What to look for
+HANDLE FindHandle = INVALID_HANDLE_VALUE; // For FindFirst/Next
+CHAR Buffer[MAX_PATH]; // Scratch buffer
+
+
+
+
+
+//
+// Local prototypes
+//
+static
+BOOL
+GotOneFile (
+ PFILE_INFO FileInfo,
+ LPWIN32_FIND_DATA FindBuffer
+ );
+
+
+
+
+
+
+
+
+// **********************************************************************
+
+DWORD
+Old_VerifyDiskSequence (
+ PWORD Sequence
+ )
+/*++
+
+Routine Description:
+
+ Determine if structures are in old format.
+
+Arguments:
+
+ OUT Sequence - Provides the desired sequence number
+
+Return Value:
+
+ DISK_OK if format and sequence match,
+ DISK_OUTOFSEQUENCE if old format but wrong sequence
+ DISK_UNKNOWN if not in old format
+
+--*/
+{
+ HANDLE FileHandle;
+ DWORD NumRead;
+ FILETIME LocalLastTime;
+ FILETIME UtcLastTime;
+ FATTIME FatTime;
+
+
+ //
+ // Try to open the BACKUPID.@@@ file
+ //
+ BackupId[0] = *SourceSpec;
+
+ FileHandle = CreateFile( BackupId,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL );
+
+ if (FileHandle == INVALID_HANDLE_VALUE) {
+ return DISK_UNKNOWN;
+ }
+
+
+ //
+ // We now try to read the entire header
+ //
+ ReadFile( FileHandle, &OldDiskInfo, sizeof(OLD_DISKINFO), &NumRead, NULL);
+
+ if (NumRead != sizeof(OLD_DISKINFO)) {
+ //
+ // This is not a valid BackupId file
+ //
+ CloseHandle(FileHandle);
+ return DISK_UNKNOWN;
+ }
+
+ if (OldDiskInfo.SequenceNumber != *Sequence) {
+ //
+ // Bad sequence number
+ //
+ CloseHandle(FileHandle);
+ *Sequence = OldDiskInfo.SequenceNumber;
+ return (DISK_OUTOFSEQUENCE | DISK_OLD_FORMAT);
+ }
+
+
+ //
+ // The disk is O.K. (we assume). Obtain the backup date and
+ // convert it to local time.
+ //
+ GetFileTime( FileHandle,
+ NULL,
+ NULL,
+ &UtcLastTime );
+
+ FileTimeToLocalFileTime( &UtcLastTime, &LocalLastTime );
+
+
+ FileTimeToDosDateTime( &LocalLastTime,
+ (LPWORD)&BackupDate,
+ (LPWORD)&FatTime );
+
+
+ CloseHandle(FileHandle);
+
+ //
+ // If the FindHandle is valid, close it so we start afreash.
+ //
+ FindClose(FindHandle);
+
+ return (DISK_OK | DISK_OLD_FORMAT);
+}
+
+
+
+
+
+
+
+// **********************************************************************
+
+
+BOOL
+Old_IsLastBackupDisk (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Determines if the backup disk is the last one.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ TRUE if disk is the last one, FALSE otherwise
+
+--*/
+{
+
+ return (OldDiskInfo.Flag == LAST_SEQUENCE);
+
+}
+
+
+
+
+// **********************************************************************
+
+PFILE_INFO
+Old_GetNextFile (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Gets next file which meets the restore criteria.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Pointer to File info
+
+--*/
+{
+
+
+ PFILE_INFO FileInfo;
+ WIN32_FIND_DATA FindBuffer;
+ BOOL FoundIt;
+
+
+
+ FindPath[0] = *SourceSpec;
+
+ FileInfo = Malloc(sizeof(FILE_INFO));
+
+ while ( TRUE ) {
+
+ if (FindHandle == INVALID_HANDLE_VALUE) {
+ //
+ // Get the first file
+ //
+ FindHandle = FindFirstFile( FindPath,
+ &FindBuffer );
+
+ if (FindHandle == INVALID_HANDLE_VALUE) {
+ //
+ // Nothing to restore!
+ //
+ return NULL;
+ }
+ } else {
+ //
+ // Get the next file
+ //
+ FoundIt = FindNextFile( FindHandle,
+ &FindBuffer );
+
+ if (!FoundIt) {
+ //
+ // End of disk
+ //
+ Free(FileInfo);
+ FindClose(FindHandle);
+ FindHandle = INVALID_HANDLE_VALUE;
+ return NULL;
+ }
+ }
+
+ //
+ // We found something, see if it matches the restore criteria
+ //
+ if (GotOneFile(FileInfo, &FindBuffer)) {
+ return FileInfo;
+ }
+ }
+
+ Free(FileInfo);
+ return NULL;
+}
+
+
+
+
+// **********************************************************************
+
+static
+BOOL
+GotOneFile (
+ PFILE_INFO FileInfo,
+ LPWIN32_FIND_DATA FindBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ Fills in a FileInfo if the file meets the match criteria
+
+Arguments:
+
+ OUT FileInfo - Supplies pointer to file information
+ structure to be filled-in.
+ IN FindBuffer - Supplies a pointer to find buffer.
+
+Return Value:
+
+ TRUE if a suitable file was found
+ FALSE otherwise
+
+--*/
+{
+
+ HANDLE FileHandle;
+ OLD_FILEHEADER OldFileHeader;
+ FILETIME LocalFileTime; // file's last write time in local time
+ DWORD NumRead;
+ PCHAR Name;
+
+ if (!FileInfo) {
+ return FALSE;
+ }
+
+ //
+ // Get name of file to open
+ //
+ strcpy(FileInfo->SourcePath, "?:\\");
+ FileInfo->SourcePath[0] = *SourceSpec;
+ strcat(FileInfo->SourcePath, FindBuffer->cFileName);
+
+ //
+ // Open the file
+ //
+ FileHandle = CreateFile( FileInfo->SourcePath,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL );
+
+ if (FileHandle == INVALID_HANDLE_VALUE) {
+ return FALSE;
+ }
+
+
+ //
+ // We now try to read the file header
+ //
+ ReadFile( FileHandle, &OldFileHeader, sizeof(OLD_FILEHEADER), &NumRead, NULL);
+
+
+ if (NumRead != sizeof(OLD_FILEHEADER)) {
+ CloseHandle(FileHandle);
+ return FALSE;
+ }
+
+ //
+ // Initialize FileInfo structure
+ //
+ //
+ // Locate file component of name
+ //
+#ifdef DBCS
+ Name = (PCHAR)&(OldFileHeader.Path[OldFileHeader.PathLen]);
+ Name = PrevChar( (PCHAR)&(OldFileHeader.Path[ 0 ]), Name );
+ while (*Name != '\\' && Name >= (PCHAR)&(OldFileHeader.Path)) {
+ Name = PrevChar( (PCHAR)&(OldFileHeader.Path[0]), Name );
+ }
+#else
+ Name = (PCHAR)&(OldFileHeader.Path[OldFileHeader.PathLen-1]);
+ while (*Name != '\\' && Name >= (PCHAR)&(OldFileHeader.Path)) {
+ Name--;
+ }
+#endif
+
+ //if (Name != (PCHAR)&(OldFileHeader.Path)) {
+ // *Name = '\0';
+ //}
+#ifdef DBCS
+ Name = NextChar( Name );
+#else
+ Name++;
+#endif
+ strcpy(FileInfo->FileName, Name);
+ *Name = '\0';
+
+ strcpy(FileInfo->Path, OldFileHeader.Path);
+
+ FileTimeToLocalFileTime( &(FindBuffer->ftLastWriteTime),
+ &LocalFileTime );
+
+ FileTimeToDosDateTime( &LocalFileTime,
+ (LPWORD)&(FileInfo->Date),
+ (LPWORD)&(FileInfo->Time) );
+
+ FileInfo->PartSize = FindBuffer->nFileSizeLow;
+ MakeFullPath(FileInfo->TargetPath, DestinationDrive, FileInfo->Path, FileInfo->FileName);
+
+ //
+ // If this FileInfo matches restore criteria, we got our guy.
+ //
+ if (FileMatch(FileInfo)) {
+ FileInfo->Sequence = OldFileHeader.SequenceNumber;
+ FileInfo->Flag = FILEINFO_OK;
+ if (OldFileHeader.Flag & LAST_SEQUENCE) {
+ FileInfo->Flag |= FILEINFO_LAST;
+ }
+
+ return TRUE;
+ }
+}
+
+
+
+
+
+
+// **********************************************************************
+
+BOOL
+Old_RestoreFile (
+ PFILE_INFO FileInfo
+ )
+/*++
+
+Routine Description:
+
+ Restores one file.
+
+Arguments:
+
+ IN FileInfo - Supplies pointer to information structure
+
+Return Value:
+
+ TRUE if file restored, FALSE otherwise
+
+--*/
+{
+
+ DWORD CreationDisposition; // How to open the target file
+ HANDLE HandleSrc; // Handle to BACKUP.XXX
+ HANDLE HandleDst; // Handle to target file
+ FILETIME UtcFileTime; // File time to set (UTC)
+ FILETIME LocalFileTime; // File time to set (local)
+ BOOL RestoreStatus = TRUE; // Status of restore
+
+ //
+ // Open (or create) the target file
+ //
+ if (FileInfo->Sequence == 1 ) {
+ //
+ // First chunk of the file. Create a new target file (overwritting
+ // the existing one.
+ //
+ CreationDisposition = CREATE_ALWAYS;
+ } else {
+ //
+ // Not the first chunk of the file. Apend to the existing file
+ //
+ CreationDisposition = OPEN_EXISTING;
+ }
+
+ HandleDst = CreateFile( FileInfo->TargetPath,
+ GENERIC_WRITE,
+ 0,
+ NULL,
+ CreationDisposition,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL );
+
+
+ SetFilePointer( HandleDst,
+ 0,
+ 0,
+ FILE_END );
+
+
+
+
+ //
+ // Open the Source file
+ //
+ HandleSrc = CreateFile( FileInfo->SourcePath,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL );
+
+ SetFilePointer( HandleSrc,
+ sizeof(OLD_FILEHEADER),
+ 0,
+ FILE_BEGIN );
+
+
+ //
+ // Everything set. Now copy the file
+ //
+ if (!(RestoreStatus = CopyData(HandleSrc, HandleDst, FileInfo->PartSize - sizeof(OLD_FILEHEADER)))) {
+ CloseHandle(HandleSrc);
+ CloseHandle(HandleDst);
+ return RestoreStatus;
+ }
+
+ //
+ // If this is the last chunk of the file, the we set the
+ // attributes, time, etc. Note that the date and time stored
+ // in the FILE_INFO structure is local time, so it has to
+ // be converted to UTC before we can feed it to SetFileTime.
+ //
+ if (FileInfo->Flag & FILEINFO_LAST) {
+
+ SetFileAttributes(FileInfo->TargetPath, FileInfo->Attr);
+
+ DosDateTimeToFileTime( DATE_WORD(FileInfo->Date),
+ TIME_WORD(FileInfo->Time),
+ &LocalFileTime );
+
+ LocalFileTimeToFileTime( &LocalFileTime, &UtcFileTime );
+
+ SetFileTime( HandleDst,
+ &UtcFileTime,
+ &UtcFileTime,
+ &UtcFileTime );
+
+ }
+
+ CloseHandle(HandleSrc);
+ CloseHandle(HandleDst);
+
+ return RestoreStatus;
+}
+
diff --git a/private/utils/restore/src/parse.c b/private/utils/restore/src/parse.c
new file mode 100644
index 000000000..741317ea6
--- /dev/null
+++ b/private/utils/restore/src/parse.c
@@ -0,0 +1,787 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ parse.c
+
+Abstract:
+
+ parse command line arguments.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 20-Dec-1990
+
+
+Revision History:
+
+
+--*/
+
+
+#include <math.h>
+#include <stdlib.h>
+#include <sys\types.h>
+#include <sys\stat.h>
+#include "restore.h"
+
+
+
+//
+// Prototypes
+//
+void
+CheckForHelp (
+ int argc,
+ CHAR **argv
+ );
+
+void
+ParseArguments (
+ int NumArg,
+ PCHAR *ArgArray
+ );
+
+DWORD
+GetDate (
+ PCHAR String,
+ PFATDATE Date
+ );
+
+DWORD
+GetTime (
+ PCHAR String,
+ PFATTIME Time
+ );
+
+DWORD
+CheckDate (
+ FATDATE Date
+ );
+
+DWORD
+CheckTime (
+ FATTIME Time
+ );
+
+void
+VerifySourceAndDest (
+ void
+ );
+
+void
+DisplayParseError (
+ DWORD ParseError,
+ PCHAR pArg
+ );
+
+
+
+
+// **********************************************************************
+
+void
+ParseCommandLine (
+ int argc,
+ CHAR **argv
+ )
+/*++
+
+Routine Description:
+
+ Parse command line arguments.
+ The way this routine handles arguments is weird but it
+ reflects the way the DOS restore utility handled them.
+
+Arguments:
+
+ IN argc - Supplies the number of arguments in command line.
+ IN argv - Supplies array of pointers to arguments.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCHAR *ArgArray = NULL; // Array of arguments
+ int NumArg = 0; // Number of arguments
+ int i;
+
+ //
+ // If user wants help, then display usage.
+ //
+ CheckForHelp(argc, argv);
+
+
+ //
+ // Form new parameter array because of the way in which
+ // the old restore parsed parameters.
+ //
+ for (i=0; i<argc; i++) {
+
+ PCHAR pBegin = argv[i];
+ PCHAR pEnd = &argv[i][1];
+
+ while (pBegin) {
+
+ USHORT Size;
+
+ // Note that none of restore's flags start with a digit,
+ // so a slash followed by a digit is not the beginning of
+ // an argument (but it might appear in a date).
+ //
+ while (*pEnd != '\0' && (*pEnd != '/' || isdigit(*(pEnd+1))) ) {
+
+ pEnd++;
+ }
+
+ Size = (USHORT)(pEnd - pBegin);
+ ArgArray = Realloc(ArgArray, (NumArg+1) * sizeof(PCHAR));
+ ArgArray[NumArg] = Malloc(Size+1);
+ memcpy(ArgArray[NumArg], pBegin, Size);
+ ArgArray[NumArg][Size] = '\0';
+ NumArg++;
+ if (*pEnd == '\0') {
+
+ pBegin = NULL;
+
+ } else {
+
+ pBegin = pEnd;
+ pEnd++;
+ }
+ }
+ }
+
+ if (NumArg == 1) {
+ DisplayParseError( REST_ERROR_NO_SOURCE, NULL );
+ } else {
+ //
+ // Parse arguments and initialize everything.
+ //
+ ParseArguments(NumArg, ArgArray);
+
+ //
+ // Free memory
+ //
+ for (i = 0; i<NumArg; i++ ) {
+ Free(ArgArray[i]);
+ }
+ Free(ArgArray);
+
+ //
+ // Verify the source and destination specifications and
+ // initialize our path structures.
+ //
+ VerifySourceAndDest();
+
+ }
+}
+
+
+
+
+// **********************************************************************
+
+void
+CheckForHelp (
+ int argc,
+ CHAR **argv
+ )
+/*++
+
+Routine Description:
+
+ Check for help flag and display Usage if flag is present.
+
+Arguments:
+
+ IN argc - Supplies the number of arguments in command line.
+ IN argv - Supplies array of pointers to arguments.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ for (argc--, argv++; argc; argc--, argv++) {
+ if ((argv[0][0] == '/')
+ && argv[0][1] == '?' && argv[0][2] == '\0') {
+ Usage();
+ }
+ }
+}
+
+
+
+
+// **********************************************************************
+
+void
+ParseArguments (
+ int NumArg,
+ PCHAR *ArgArray
+ )
+/*++
+
+Routine Description:
+
+ Parse command line arguments.
+
+Arguments:
+
+ IN NumArg - Supplies the number of arguments in command line.
+ IN ArgArray - Supplies array of pointers to arguments.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ int i;
+ DWORD ParseError = 0;
+
+ for (i=1; i<NumArg && ParseError == 0; i++) {
+
+ PCHAR pArg = ArgArray[i];
+
+ if (*pArg == '/') {
+
+ //
+ // A switch, verify and set.
+ //
+ if (i < 2) {
+ //
+ // First argument must be drive
+ //
+ ParseError = REST_ERROR_INVALID_DRIVE;
+ } else {
+
+ switch (*(pArg+1)) {
+
+ case 's':
+ case 'S':
+ Flag_s = TRUE;
+ break;
+
+ case 'p':
+ case 'P':
+ Flag_p = TRUE;
+ break;
+
+ case 'b':
+ case 'B':
+ Flag_b = TRUE;
+ ParseError = GetDate((pArg+2), &BeforeDate);
+ break;
+
+ case 'a':
+ case 'A':
+ Flag_a = TRUE;
+ ParseError = GetDate((pArg+2), &AfterDate);
+ break;
+
+ case 'z':
+ case 'Z':
+ Flag_z = TRUE;
+ ParseError = GetDate((pArg+2), &ExactDate);
+ break;
+
+ case 'e':
+ case 'E':
+ Flag_e = TRUE;
+ ParseError = GetTime((pArg+2), &BeforeTime);
+ break;
+
+ case 'l':
+ case 'L':
+ Flag_L = TRUE;
+ ParseError = GetTime((pArg+2), &AfterTime);
+ break;
+
+ case 'y':
+ case 'Y':
+ Flag_Y = TRUE;
+ ParseError = GetTime((pArg+2), &ExactTime);
+ break;
+
+ case 'm':
+ case 'M':
+ Flag_m = TRUE;
+ break;
+
+ case 'n':
+ case 'N':
+ Flag_n = TRUE;
+ break;
+
+ case 'd':
+ case 'D':
+ Flag_d = TRUE;
+ break;
+
+ default:
+ ParseError = REST_ERROR_INVALID_SWITCH;
+ break;
+
+ }
+ }
+ } else {
+ //
+ // Not a switch, Initialize the appropiate stuff
+ //
+ switch (i) {
+ case 1:
+ SourceSpec = Malloc(strlen(pArg));
+ strcpy(SourceSpec, pArg);
+ break;
+
+ case 2:
+ strcpy(DestinationSpec, pArg);
+ break;
+
+
+ default:
+ ParseError = REST_ERROR_NUMBER_OF_PARAMETERS;
+ break;
+
+ }
+ }
+ }
+ if (ParseError) {
+ DisplayParseError(ParseError, ArgArray[i-1]);
+ }
+}
+
+
+
+
+// **********************************************************************
+
+DWORD
+GetDate (
+ PCHAR String,
+ PFATDATE Date
+ )
+/*++
+
+Routine Description:
+
+ Get a date specification.
+
+Arguments:
+
+ IN String - Supplies the Date in string form, first character must
+ be ':'.
+ OUT Date - Supplies pointer to DATE structure to fill.
+
+Return Value:
+
+ 0 or error code.
+
+--*/
+{
+ int NumAssigned;
+ DWORD Month;
+ DWORD Day;
+ DWORD Year;
+
+ //
+ // BUGBUG
+ //
+ // What about day-month-year and other variations?
+ //
+ NumAssigned = sscanf(String, ":%d-%d-%d", &Month, &Day, &Year);
+
+ if (NumAssigned != 3) {
+
+ NumAssigned = sscanf(String, ":%d/%d/%d", &Month, &Day, &Year);
+ }
+
+ if(NumAssigned != 3) {
+
+ return REST_ERROR_INVALID_DATE;
+ }
+
+ if( Year < 80 ) {
+
+ return REST_ERROR_INVALID_DATE;
+ }
+
+ if( Year < 100 ) {
+
+ Year += 1900;
+ }
+
+ Date->Year = (unsigned)Year-1980;
+ Date->Month = (unsigned)Month;
+ Date->Day = (unsigned)Day;
+
+ return CheckDate(*Date);
+
+}
+
+
+
+
+// **********************************************************************
+
+DWORD
+GetTime (
+ PCHAR String,
+ PFATTIME Time
+ )
+/*++
+
+Routine Description:
+
+ Get a time specification.
+
+Arguments:
+
+ IN String - Supplies the Date in string form, first character must
+ be ':'.
+ OUT Time - Supplies pointer to RT_TIME structure to fill.
+
+Return Value:
+
+ 0 or error code
+
+--*/
+{
+
+ int NumAssigned;
+ DWORD Hours = 0;
+ DWORD Minutes = 0;
+ DWORD Seconds = 0;
+
+ NumAssigned = sscanf(String, ":%d:%d:%d", &Hours, &Minutes, &Seconds);
+
+ if (NumAssigned == 0) {
+ return REST_ERROR_INVALID_TIME;
+ }
+
+ Time->Hours = (unsigned)Hours;
+ Time->Minutes = (unsigned)Minutes;
+ Time->DoubleSeconds = (unsigned)(Seconds/2);
+
+ return CheckTime(*Time);
+
+
+}
+
+
+
+
+// **********************************************************************
+
+DWORD
+CheckDate (
+ FATDATE Date
+ )
+/*++
+
+Routine Description:
+
+ Checks consistency of a date
+
+Arguments:
+
+ IN Date - Supplies the date to be checked
+
+Return Value:
+
+ 0 or error code
+
+--*/
+{
+
+ if (Date.Year > (2099-1980) || Date.Year < 0) {
+ return REST_ERROR_INVALID_DATE;
+ }
+
+ if (Date.Month > 12 || Date.Month < 1) {
+ return REST_ERROR_INVALID_DATE;
+ }
+
+ if (Date.Day > 31 || Date.Month < 1) {
+ return REST_ERROR_INVALID_DATE;
+ }
+
+
+ //
+ // Verify day not greater then 30 if Apr,Jun,Sep,Nov
+ //
+ if ((Date.Day>30) &&
+ (Date.Month==4 || Date.Month==6 || Date.Month==9 || Date.Month==11)) {
+ return REST_ERROR_INVALID_DATE;
+ }
+
+ if (Date.Month == 2) {
+ //
+ // Deal with February
+ //
+ if (Date.Day > 29) {
+ return REST_ERROR_INVALID_DATE;
+ }
+
+ if ((Date.Year % 4) != 0) {
+ if (Date.Day > 28) {
+ return REST_ERROR_INVALID_DATE;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+
+
+// **********************************************************************
+
+DWORD
+CheckTime (
+ FATTIME Time
+ )
+/*++
+
+Routine Description:
+
+ Checks consistency of a time
+
+Arguments:
+
+ IN Time - Supplies time to be checked
+
+Return Value:
+
+ 0 or error code
+
+--*/
+{
+
+ if (Time.Hours > 23 || Time.Hours < 0) {
+ return REST_ERROR_INVALID_TIME;
+
+ }
+
+ if (Time.Minutes >= 60 || Time.Minutes < 0) {
+ return REST_ERROR_INVALID_TIME;
+ }
+
+
+ if (Time.DoubleSeconds >= 30 || Time.DoubleSeconds < 0) {
+ return REST_ERROR_INVALID_TIME;
+ }
+
+ return 0;
+}
+
+
+
+
+
+// **********************************************************************
+
+void
+VerifySourceAndDest (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Verifies and/or initializes source and destination specifications.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+{
+
+ CHAR SrcD;
+ CHAR DstD;
+ CHAR c;
+ PCHAR p, q;
+ CHAR DriveRoot[] = "?:\\";
+ CHAR ThisDirectory[MAX_PATH];
+ LPSTR Last;
+ struct _stat StatBuffer;
+
+
+ //
+ // Get out current directory
+ //
+ GetCurrentDirectory(MAX_PATH, ThisDirectory);
+
+ //
+ // Must specify source drive
+ //
+ if (!SourceSpec) {
+ DisplayParseError(REST_ERROR_NO_SOURCE, NULL);
+ }
+ //
+ // If DestinationSpec not present, use current directory
+ //
+ if (!DestinationSpec) {
+ strcpy(DestinationSpec, ThisDirectory);
+ }
+
+ //
+ // If Destination has no drive specification, add current drive
+ //
+ //if ( ! ( *DestinationSpec == '\\' && *(DestinationSpec+1) == '\\' )) {
+ //
+ // if (*(DestinationSpec+1) != ':') {
+ //
+ // PCHAR pTmp = Malloc(MAX_PATH);
+ // PCHAR p;
+ //
+ // p = pTmp;
+ // *p++ = ThisDirectory[0];
+ // *p++ = ThisDirectory[1];
+ //
+ // strcpy(p,DestinationSpec);
+ // strcpy(DestinationSpec,pTmp);
+ // }
+ //} else {
+ // DisplayParseError( REST_ERROR_INVALID_DRIVE, DestinationSpec );
+ //}
+ //
+ if ( !GetFullPathName( DestinationSpec, MAX_PATH, ThisDirectory, &Last )) {
+ DisplayParseError( REST_ERROR_INVALID_DRIVE, ThisDirectory );
+ }
+ strcpy( DestinationSpec, ThisDirectory );
+
+ *SourceSpec = SrcD = (CHAR)toupper(*SourceSpec);
+
+ DstD = (CHAR)toupper(*DestinationSpec);
+
+ //
+ // Verify source
+ //
+ if (SrcD < 'A' || SrcD > 'Z' || *(SourceSpec+1) != ':') {
+ DisplayParseError(REST_ERROR_INVALID_DRIVE, SourceSpec);
+ }
+
+ //
+ // Get type of source and target drives
+ //
+ DriveRoot[0] = SrcD;
+ SourceDriveType = GetDriveType(DriveRoot);
+ if ((SourceDriveType == 0) || (SourceDriveType == 1)) {
+ DisplayParseError(REST_ERROR_INVALID_DRIVE, DriveRoot);
+ }
+
+ DriveRoot[0] = DstD;
+ TargetDriveType = GetDriveType(DriveRoot);
+ if ((TargetDriveType == 0) || (TargetDriveType == 1)) {
+ DisplayParseError(REST_ERROR_INVALID_DRIVE, DriveRoot);
+ }
+
+ //
+ // Source must be != destination
+ //
+ if (SrcD == DstD) {
+ DisplayParseError(REST_ERROR_SAME_DRIVES, SourceSpec);
+ }
+
+ //
+ // Now split the destination specification in the Drive, Dir and
+ // File components. e.g.
+ //
+ // D:\foo\bar.* => "D:", "\foo\", "bar.*"
+ //
+ if ( !_stat( DestinationSpec, &StatBuffer ) ) {
+ if (StatBuffer.st_mode & S_IFDIR ) {
+#ifdef DBCS
+ (VOID)AppendBackSlashIfNeeded( DestinationSpec, strlen(DestinationSpec) );
+#else
+ if (DestinationSpec[ strlen(DestinationSpec)-1] != '\\' ) {
+ strcat( DestinationSpec, "\\" );
+ }
+#endif
+ strcat( DestinationSpec, "*.*" );
+ }
+ }
+
+ DestinationDrive[0] = DstD;
+ DestinationDrive[1] = ':';
+ DestinationDrive[2] = '\0';
+
+ p = DestinationSpec + 2;
+#ifdef DBCS
+ q = DestinationSpec + strlen(DestinationSpec);
+ q = PrevChar( DestinationSpec, q );
+ while (p != q && *q != '\\') {
+ q = PrevChar( DestinationSpec, q );
+ }
+#else
+ q = DestinationSpec + strlen(DestinationSpec) - 1;
+ while (p != q && *q != '\\') {
+ q--;
+ }
+#endif
+
+ if ( (p == q) && ( *(p+1) == '\0' ) ) {
+ strcpy( DestinationDir, p );
+ strcpy( DestinationFile, "*.*" );
+ } else {
+ q++; // Off-by-one
+
+ c = *q;
+ *q = '\0';
+ strcpy(DestinationDir, p );
+ *q = c;
+ strcpy( DestinationFile, q );
+ }
+
+ MakeFullPath(DestinationSpec, DestinationDrive, DestinationDir, DestinationFile);
+}
+
+
+
+
+// **********************************************************************
+
+void
+DisplayParseError (
+ DWORD ParseError,
+ PCHAR pArg
+ )
+/*++
+
+Routine Description:
+
+ Displays error mesage from parser.
+
+Arguments:
+
+ IN ParseError - Supplies error code
+ IN pArg - Supplies pointer to argument that caused the error.
+
+Return Value:
+
+ None
+
+--*/
+{
+ DisplayMsg(STD_ERR, ParseError, pArg);
+
+ ExitStatus(EXIT_USER);
+}
diff --git a/private/utils/restore/src/restore.c b/private/utils/restore/src/restore.c
new file mode 100644
index 000000000..f024464e9
--- /dev/null
+++ b/private/utils/restore/src/restore.c
@@ -0,0 +1,481 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ restore.c
+
+Abstract:
+
+ Restore utility. Restores files backed up with the DOS and OS/2 backup
+ utilities.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) Feb-20-1990
+
+
+Revision History:
+
+
+--*/
+
+#include "restore.h"
+
+#include <fcntl.h>
+#include <io.h>
+
+
+
+// **********************************************************************
+
+//
+// The global data is to be initialized here
+//
+//
+// Switches set in the command line
+//
+BOOL Flag_s = FALSE; // Restore subdirs
+BOOL Flag_p = FALSE; // Prompting
+BOOL Flag_b = FALSE; // Before date
+BOOL Flag_a = FALSE; // After date
+BOOL Flag_z = FALSE; // Exact date
+BOOL Flag_e = FALSE; // Before time
+BOOL Flag_L = FALSE; // After time
+BOOL Flag_Y = FALSE; // Exact time
+BOOL Flag_m = FALSE; // Restore only modified files
+BOOL Flag_n = FALSE; // Restore only nonexistent files
+BOOL Flag_d = FALSE; // Display files on the backup disk that
+ // match specifications
+//
+// WriteNewLine is true if we must write a new line after restoring a file
+//
+BOOL WriteNewLine = FALSE;
+
+//
+// Dates and times set in the command line
+//
+FATDATE BeforeDate = {0, 0, 0};
+FATDATE AfterDate = {0, 0, 0};
+FATDATE ExactDate = {0, 0, 0};
+
+FATTIME BeforeTime = {0, 0, 0};
+FATTIME AfterTime = {0, 0, 0};
+FATTIME ExactTime = {0, 0, 0};
+
+
+//
+// The date of the backup
+//
+FATDATE BackupDate = {0, 0, 0};
+FATTIME BackupTime = {0, 0, 0};
+
+
+//
+// The source and destination specifications
+//
+PCHAR SourceSpec = NULL; // Source drive specification
+CHAR DestinationSpec[MAX_PATH] = {'\0'}; // Full Destination spec
+CHAR DestinationDrive[3] = {'\0'}; // Destination drive
+CHAR DestinationDir[MAX_PATH] = {'\0'}; // Destination directory
+CHAR DestinationFile[MAX_PATH] = {'\0'}; // Destination file
+
+
+//
+// Abort signals an abnormal termination condition
+//
+BOOL Abort = FALSE;
+
+
+//
+// Type of the source and target drives
+//
+DWORD SourceDriveType = 0;
+DWORD TargetDriveType = 0;
+
+
+
+// **********************************************************************
+
+//
+// The local data
+//
+WORD DiskSequence = 1; // Current disk sequence
+DWORD FilesFound = 0; // Number of files restored
+
+
+
+
+
+// **********************************************************************
+
+//
+// The local prototypes
+//
+void
+RestoreAllFiles (
+ );
+
+BOOL
+RestoreOneFile (
+ );
+
+
+
+
+
+
+// **********************************************************************
+
+void _CRTAPI1
+main (
+ int argc,
+ CHAR **argv
+ )
+/*++
+
+Routine Description:
+
+ restore utility main function.
+
+Arguments:
+
+ IN argc - Supplies the number of arguments in command line.
+ IN argv - Supplies array of pointers to arguments.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ DWORD DiskType; // Type of backup disk
+
+#if defined( JAPAN ) // v-junm - 06/03/93
+// This is a hack for FormatMessage. FormatMessage checks several variables
+// to determine which language message to display, and one is the TEB's
+// LanguageId. Since the LanguageId in the TEB is always initialized to
+// Japan's language id when a thread is created, we will change the value
+// to US's language id when we are not running in JP CP.
+
+ if ( GetConsoleOutputCP() == 932 )
+ SetThreadLocale(
+ MAKELCID(
+ MAKELANGID( LANG_JAPANESE, SUBLANG_ENGLISH_US ),
+ SORT_DEFAULT
+ )
+ );
+ else
+ SetThreadLocale(
+ MAKELCID(
+ MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ),
+ SORT_DEFAULT
+ )
+ );
+
+
+#endif // JAPAN
+
+ //
+ // Don't expand line-feed to carriage-return and line-feed.
+ //
+
+ _setmode(_fileno(stdout),O_BINARY);
+ _setmode(_fileno(stderr),O_BINARY);
+
+ //
+ // Get command-line options and set the global state.
+ //
+ ParseCommandLine( argc, argv );
+
+ //
+ // Determine the format of the backup disk.
+ //
+ DiskType = GetABackupDisk( &DiskSequence );
+
+ //
+ // If this is not a backup disk, get out.
+ //
+ if (!(DiskType & DISK_OK)) {
+ DisplayMsg( STD_ERR, REST_ERROR_NOT_BACKUP );
+ ExitStatus( EXIT_ERROR );
+ }
+
+ //
+ // Restore the files
+ //
+ RestoreAllFiles();
+
+ //
+ // Exit
+ //
+ if (Abort) {
+ ExitStatus(EXIT_ERROR);
+ } else if (FilesFound == 0) {
+ fprintf( STD_ERR , "\r\n\r\n");
+ DisplayMsg(STD_ERR, REST_WARNING_NOFILES);
+ ExitStatus(EXIT_NOFILES);
+ } else {
+ fprintf( STD_OUT, "\r\n");
+ ExitStatus(EXIT_NORMAL);
+ }
+}
+
+
+
+
+
+// **********************************************************************
+
+void
+RestoreAllFiles (
+ void
+ )
+/*++
+
+Routine Description:
+
+ Restore backed-up files.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ BOOL AllDisksRestored = FALSE; // Termination flag
+ CHAR StringDate[STRING_DATE_LENGTH];
+ CHAR StringBuffer[16];
+
+ //
+ // Note that at this point the first backup disk has already
+ // been verified.
+ //
+
+ //
+ // Ask for target, if removable
+ //
+ if (TargetDriveType == DRIVE_REMOVABLE) {
+ DisplayMsg(STD_OUT, REST_MSG_INSERT_TARGET, DestinationDrive);
+ DisplayMsg(STD_OUT, REST_MSG_PRESS_ANY_KEY);
+ GetKey(NULL, STD_OUT, STD_OUT);
+ }
+
+ //
+ // Display the backup date
+ //
+ DisplayMsg(STD_OUT, REST_MSG_FILES_WERE_BACKEDUP, MakeStringDate(StringDate, BackupDate));
+ putc( '\r', STD_OUT );
+ putc( '\n', STD_OUT );
+ if ( Flag_d ) {
+ DisplayMsg(STD_OUT, REST_MSG_LISTING, SourceSpec);
+ } else {
+ DisplayMsg(STD_OUT, REST_MSG_RESTORING, SourceSpec);
+ }
+
+ //
+ // Now do the restore, one disk at a time
+ //
+ while (!AllDisksRestored) {
+
+ if (SourceDriveType == DRIVE_REMOVABLE) {
+ MakeStringNumber(StringBuffer, DiskSequence, 2);
+ DisplayMsg(STD_OUT, REST_MSG_DISKETTE_NUMBER, StringBuffer);
+ }
+
+ //
+ // Restore all the restorable files on this disk.
+ //
+ while ( RestoreOneFile( ) );
+
+ if (IsLastBackupDisk()) {
+
+ //
+ // This is the last backup disk, our job is done
+ //
+ AllDisksRestored = TRUE;
+
+ } else {
+
+ //
+ // There are more disks, get and verify the next one
+ //
+ DiskSequence++;
+
+ if (!(GetABackupDisk(&DiskSequence) & DISK_OK)) {
+ DisplayMsg(STD_ERR, REST_ERROR_NOT_BACKUP);
+ AllDisksRestored = TRUE;
+ AbortProgram();
+ }
+ }
+ }
+}
+
+
+
+
+
+
+
+// **********************************************************************
+
+
+BOOL
+RestoreOneFile (
+ )
+/*++
+
+Routine Description:
+
+ Restores one file.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ TRUE if one file restored, FALSE otherwise
+
+--*/
+
+{
+ PFILE_INFO FileInfo; // Pointer to information structure
+ DWORD Status;
+static FILE_INFO LastFileInfo; // FileInfo of last chunk
+static DWORD TmpSequence = 0; // Tmp sequence
+static BOOL HaveLastChunk = FALSE; // have last part of file
+
+
+ while (TRUE) {
+
+ //
+ // Try to get the the information about a file to restore
+ //
+ FileInfo = GetNextFile();
+
+ if (FileInfo) {
+
+ //
+ // There is a file to restore. Determine if this is the first
+ // chunk of the file.
+ //
+ if (FileInfo->Sequence == 1) {
+
+ //
+ // This is the first chunk of a file. Assign it a temporary
+ // name.
+ //
+ MakeTmpPath(FileInfo->TmpName, DestinationDrive, FileInfo->Path, TmpSequence++);
+
+ //
+ // If this is not the last chunk of a file, then we save
+ // the FileInfo so that we can verify the next chunk.
+ //
+ if (!(FileInfo->Flag & FILEINFO_LAST)) {
+
+ //
+ // This is a multi-chunk file. We save
+ // the FileInfo.
+ //
+ memcpy(&LastFileInfo, FileInfo, sizeof(FILE_INFO));
+ HaveLastChunk = TRUE;
+
+ } else {
+
+ //
+ // Not a multi-chunk file
+ //
+ HaveLastChunk = FALSE;
+ }
+
+ } else {
+
+ //
+ // This is part of a multi-chunk file. We have to make
+ // sure that the last chunk that we copied was the
+ // previous chunk of this file.
+ //
+ if (!HaveLastChunk) {
+
+ //
+ // We don't have a previous chunk, so we will
+ // just skip this file
+ //
+ Free( FileInfo );
+ continue;
+ }
+
+ if (!((strcmp(LastFileInfo.Path, FileInfo->Path) == 0) &&
+ (strcmp(LastFileInfo.FileName, FileInfo->FileName) == 0) &&
+ (LastFileInfo.Sequence == FileInfo->Sequence -1))) {
+ //
+ // ERROR!, we have to recover the file and abort
+ //
+ DisplayMsg(STD_ERR,REST_ERROR_LAST_NOTRESTORED, FileInfo->TargetPath);
+ RecoverFile(&LastFileInfo);
+ AbortProgram();
+ return FALSE;
+
+ } else {
+
+ //
+ // Correct chunk. copy the FileInfo. Note that we only
+ // have to update the sequence number.
+ //
+ strcpy( FileInfo->TmpName, LastFileInfo.TmpName );
+ LastFileInfo.Sequence = FileInfo->Sequence;
+ }
+ }
+
+ //
+ // Restore it.
+ //
+ FilesFound++;
+
+ printf("%s%s ",FileInfo->Path, FileInfo->FileName);
+
+ if ( !Flag_d ) {
+ if ( !RestoreFile( FileInfo ) ) {
+
+ DisplayMsg(STD_ERR,REST_ERROR_LAST_NOTRESTORED, FileInfo->TargetPath);
+ RecoverFile(&LastFileInfo);
+ AbortProgram();
+ return FALSE;
+ } else if (FileInfo->TargetExists && (FileInfo->Flag & FILEINFO_LAST) ) {
+ //
+ // File restored, delete temporary file
+ //
+ DeleteFile( FileInfo->TmpName );
+ }
+ }
+
+ if ( Flag_p && WriteNewLine ) {
+ putc( '\r', STD_ERR );
+ putc( '\n', STD_ERR );
+ }
+ putc( '\r', STD_OUT );
+ putc( '\n', STD_OUT );
+
+ Free( FileInfo );
+
+ return TRUE;
+
+ } else {
+
+ //
+ // No more files, return
+ //
+ return FALSE;
+ }
+ }
+}
diff --git a/private/utils/restore/src/restore.rc b/private/utils/restore/src/restore.rc
new file mode 100644
index 000000000..1e8d24567
--- /dev/null
+++ b/private/utils/restore/src/restore.rc
@@ -0,0 +1,12 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "File Restore Utility"
+#define VER_INTERNALNAME_STR "restore\0"
+#define VER_ORIGINALFILENAME_STR "RESTORE.EXE"
+
+#include "common.ver"
+
+#include "rtmsg.rc"
diff --git a/private/utils/restore/src/rtmsg.mc b/private/utils/restore/src/rtmsg.mc
new file mode 100644
index 000000000..4b8eb1cf0
--- /dev/null
+++ b/private/utils/restore/src/rtmsg.mc
@@ -0,0 +1,191 @@
+;/*++ BUILD Version: 0001 // Increment this if a change has global effects
+;
+;Copyright (c) 1990 Microsoft Corporation
+;
+;Module Name:
+;
+; rtmsg.h
+;
+;Abstract:
+;
+; This file contains the message definitions for the Win32 restore
+; utility.
+;
+;Author:
+;
+; Ramon Juan San Andres (ramonsa) 20-Feb-1990
+;
+;Revision History:
+;
+;--*/
+;
+
+MessageId=0002 SymbolicName=REST_ERROR_SAME_DRIVES
+Language=English
+Source and target drives are the same
+.
+
+MessageId=0003 SymbolicName=REST_ERROR_NUMBER_OF_PARAMETERS
+Language=English
+Invalid number of parameters
+.
+
+MessageId=0005 SymbolicName=REST_ERROR_INVALID_PATH
+Language=English
+Invalid path
+.
+
+MessageId=0006 SymbolicName=REST_ERROR_INVALID_DRIVE
+Language=English
+Invalid drive specification
+.
+
+MessageId=0007 SymbolicName=REST_WARNING_NOFILES
+Language=English
+WARNING! No files were found to restore
+.
+
+MessageId=0008 SymbolicName=REST_MSG_INSERT_SOURCE
+Language=English
+Insert backup diskette %1 in drive %2
+.
+
+MessageId=0009 SymbolicName=REST_MSG_INSERT_TARGET
+Language=English
+Insert restore target in drive %1
+.
+
+MessageId=0010 SymbolicName=REST_MSG_PRESS_ANY_KEY
+Language=English
+Press any key to continue . . . %0
+.
+
+MessageId=0011 SymbolicName=REST_WARNING_DISK_OUTOFSEQUENCE
+Language=English
+WARNING! Diskette is out of sequence
+Replace diskette or continue if OK %0
+.
+
+MessageId=0012 SymbolicName=REST_ERROR_LAST_NOTRESTORED
+Language=English
+The last file was not restored
+.
+
+MessageId=0013 SymbolicName=REST_MSG_FILES_WERE_BACKEDUP
+Language=English
+*** Files were backed up %1 ***
+.
+
+MessageId=0014 SymbolicName=REST_ERROR_NOT_BACKUP
+Language=English
+Source does not contain backup files
+.
+
+MessageId=0015 SymbolicName=REST_ERROR_NO_MEMORY
+Language=English
+Insufficient memory
+.
+
+MessageId=0016 SymbolicName=REST_WARNING_READONLY
+Language=English
+WARNING! File %1
+Is a read only file
+Replace the file (Y/N)? %0
+.
+
+MessageId=0017 SymbolicName=REST_ERROR_FILE_SEQUENCE
+Language=English
+Restore file sequence error
+.
+
+MessageId=0018 SymbolicName=REST_ERROR_FILE_CREATION
+Language=English
+File creation error
+.
+
+MessageId=0019 SymbolicName=REST_ERROR_DISK_SPACE
+Language=English
+Insufficient disk space
+.
+
+MessageId=0020 SymbolicName=REST_ERROR_NOT_RESTORED
+Language=English
+*** Not able to restore file ***
+.
+
+MessageId=0021 SymbolicName=REST_MSG_RESTORING
+Language=English
+*** Restoring files from drive %1 ***
+.
+
+MessageId=0022 SymbolicName=REST_WARNING_FILE_CHANGED
+Language=English
+Warning! File %1
+was changed after it was backed up
+Replace the file (Y/N)? %0
+.
+
+MessageId=0023 SymbolicName=REST_MSG_DISKETTE_NUMBER
+Language=English
+Diskette: %1
+.
+
+MessageId=0027 SymbolicName=REST_ERROR_INVALID_DATE
+Language=English
+Invalid date
+.
+
+MessageId=0028 SymbolicName=REST_ERROR_INVALID_TIME
+Language=English
+Invalid time
+.
+
+MessageId=0029 SymbolicName=REST_ERROR_NO_SOURCE
+Language=English
+No source drive specified
+.
+
+MessageId=0030 SymbolicName=REST_ERROR_NO_TARGET
+Language=English
+No target drive specified
+.
+
+MessageId=0031 SymbolicName=REST_ERROR_INVALID_SWITCH
+Language=English
+Invalid Switch - %1
+.
+
+MessageId=0032 SymbolicName=REST_ERROR_READING_BACKUP
+Language=English
+Error reading backup file.
+.
+
+MessageId=0040 SymbolicName=REST_MSG_LISTING
+Language=English
+*** Listing files on drive %1 ***
+.
+
+
+MessageId=0050 SymbolicName=REST_MSG_USAGE
+Language=English
+Restores files that were backed up by using the DOS BACKUP command.
+
+RESTORE drive1: drive2:[path[filename]] [/S] [/P] [/B:date] [/A:date] [/E:time]
+ [/L:time] [/M] [/N] [/D]
+
+ drive1: Specifies the drive on which the backup files are stored.
+ drive2:[path[filename]]
+ Specifies the file(s) to restore.
+ /S Restores files in all subdirectories in the path.
+ /P Prompts before restoring read-only files or files changed since
+ the last backup (if appropriate attributes are set).
+ /B Restores only files last changed on or before the specified date.
+ /A Restores only files changed on or after the specified date.
+ /E Restores only files last changed at or earlier than the specified
+ time.
+ /L Restores only files changed at or later than the specified time.
+ /M Restores only files changed since the last backup.
+ /N Restores only files that no longer exist on the destination disk.
+ /D Displays files on the backup disk that match specifications.
+
+.
diff --git a/private/utils/restore/src/sources b/private/utils/restore/src/sources
new file mode 100644
index 000000000..3af46c8b4
--- /dev/null
+++ b/private/utils/restore/src/sources
@@ -0,0 +1,36 @@
+BLDCRT=1
+
+MAJORCOMP=sdktools
+MINORCOMP=restore
+
+TARGETNAME=restore
+TARGETPATH=obj
+TARGETTYPE=LIBRARY
+
+
+
+INCLUDES=..\inc
+
+
+
+SOURCES= restore.rc \
+ exit.c \
+ filecopy.c \
+ generic.c \
+ match.c \
+ misc.c \
+ msg.c \
+ new.c \
+ old.c \
+ parse.c \
+ mbcs.c
+
+
+C_DEFINES= -DNO_EXT_KEYS -DNT
+
+UMTYPE=console
+UMAPPL=restore
+UMLIBS=obj\*\restore.lib
+UMRES=obj\*\restore.res \nt\public\sdk\lib\*\binmode.obj
+
+NTTARGETFILE0=..\inc\rtmsg.h
diff --git a/private/utils/sort/makefile b/private/utils/sort/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/sort/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/sort/makefile.inc b/private/utils/sort/makefile.inc
new file mode 100644
index 000000000..6c93eb38d
--- /dev/null
+++ b/private/utils/sort/makefile.inc
@@ -0,0 +1,12 @@
+{}.cxx{obj\i386\}.obj:
+ $(386_COMPILER) -Fo$@ $(MAKEDIR)\$(<F)
+
+{}.cxx{obj\mips\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClMips $< " $(C_COMPILER) "
+ @$(C_COMPILER) -Fo$@ $(MAKEDIR)\$<
+
+{}.cxx{obj\alpha\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClAlpha $< " $(ALPHA_COMPILER) "
+ @$(ALPHA_COMPILER) -Fo$@ $(MAKEDIR)\$<
diff --git a/private/utils/sort/sort.cxx b/private/utils/sort/sort.cxx
new file mode 100644
index 000000000..c76cd4cb8
--- /dev/null
+++ b/private/utils/sort/sort.cxx
@@ -0,0 +1,315 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ sort.cxx
+
+Abstract:
+
+ This module contains the implentation of the sort utility
+ (Dos 5.0 compatible).
+ It sorts the input and writes the results to the screen, a file, or
+ another device.
+
+ SORT [/R] [/+n] [/?] < [drive1:][path1]filename1 [> [drive2:][path2]filename2]
+ [command |] SORT [/R] [/+n] [> [drive2:][path2]filename2]
+
+ /? Displays a help message.
+ /R Reverses the sort order; that is, sorts Z to A,
+ then 9 to 0.
+ /+n Sorts the file according to characters in
+ column n.
+ [drive1:][path1]filename1 Specifies a file to be sorted.
+ [drive2:][path2]filename2 Specifies a file where the sorted input is to be
+ stored.
+ command Specifies a comman whose output is to be sorted.
+
+
+Author:
+
+ Jaime F. Sasson
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include "ulib.hxx"
+#include "ulibcl.hxx"
+#include "stream.hxx"
+#include "error.hxx"
+#include "arg.hxx"
+#include "wstring.hxx"
+#include "substrng.hxx"
+#include "array.hxx"
+#include "arrayit.hxx"
+#include "smsg.hxx"
+#include "rtmsg.h"
+#include "stringar.hxx"
+#include "sort.hxx"
+
+extern "C" {
+#include <stdio.h>
+}
+
+
+ERRSTACK* perrstk;
+
+
+DEFINE_CONSTRUCTOR( SORT, PROGRAM );
+
+
+BOOLEAN
+SORT::Initialize(
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes a SORT object.
+ The initialization consists of:
+ .Initialization of STREAM_MESSAGE object;
+ .Parse the command line;
+ .Display the help message if the argument /? was present in the
+ command line;
+ .Initialize the flag that indicates if the sort is to be performed
+ in ascending or descending order;
+ .Initialize the variable that indicates the position in the string
+ that is to be sorted.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the initialization succeeded and the sort
+ is to be performed. Returns FALSE otherwise (invalid argument,
+ or /? found in the command line)
+
+
+--*/
+
+
+{
+ ARGUMENT_LEXEMIZER ArgLex;
+ ARRAY LexArray;
+ ARRAY ArgumentArray;
+ STRING_ARGUMENT ProgramNameArgument;
+ FLAG_ARGUMENT FlagReverseSortOrder;
+ LONG_ARGUMENT Column;
+ FLAG_ARGUMENT FlagDisplayHelp;
+
+
+ _Standard_Output_Stream = Get_Standard_Output_Stream();
+ _Standard_Input_Stream = Get_Standard_Input_Stream();
+ _Standard_Error_Stream = Get_Standard_Error_Stream();
+
+ if (NULL == (_Message = NEW STREAM_MESSAGE)) {
+ DebugAbort( "Operator new failed.\n" );
+ return( FALSE );
+ }
+
+ _Message->Initialize( _Standard_Output_Stream, _Standard_Input_Stream,
+ _Standard_Error_Stream );
+
+ if ( !LexArray.Initialize( ) ) {
+ DebugAbort( "LexArray.Initialize() failed \n" );
+ return( FALSE );
+ }
+ if ( !ArgLex.Initialize( &LexArray ) ) {
+ DebugAbort( "ArgLex.Initialize() failed \n" );
+ return( FALSE );
+ }
+ ArgLex.PutSwitches( "/" );
+ ArgLex.SetCaseSensitive( FALSE );
+ if( !ArgLex.PrepareToParse() ) {
+ DebugAbort( "ArgLex.PrepareToParse() failed \n" );
+ return( FALSE );
+ }
+
+ if ( !ArgumentArray.Initialize() ) {
+ DebugAbort( "ArgumentArray.Initialize() failed \n" );
+ return( FALSE );
+ }
+ if( !ProgramNameArgument.Initialize("*") ||
+ !FlagReverseSortOrder.Initialize( "/R" ) ||
+ !Column.Initialize( "/+*" ) ||
+ !FlagDisplayHelp.Initialize( "/?" )) {
+ DebugAbort( "Unable to initialize flag or string arguments \n" );
+ return( FALSE );
+ }
+ if( !ArgumentArray.Put( &ProgramNameArgument ) ||
+ !ArgumentArray.Put( &FlagReverseSortOrder ) ||
+ !ArgumentArray.Put( &Column ) ||
+ !ArgumentArray.Put( &FlagDisplayHelp ) ) {
+ DebugAbort( "ArgumentArray.Put() failed \n" );
+ return( FALSE );
+ }
+ if( !ArgLex.DoParsing( &ArgumentArray ) ) {
+ _Message->Set( MSG_SORT_INVALID_SWITCH, ERROR_MESSAGE );
+ _Message->Display( " " );
+ return( FALSE );
+ }
+ if( FlagDisplayHelp.QueryFlag() ) {
+ _Message->Set( MSG_SORT_HELP_MESSAGE );
+ _Message->Display( " " );
+ return( FALSE );
+ }
+
+ _AscendingOrder = !FlagReverseSortOrder.QueryFlag();
+ _Position = ( Column.IsValueSet() ) ? Column.QueryLong() : 1;
+ if( _Position <= 0 ) {
+ _Message->Set( MSG_SORT_VALUE_NOT_IN_RANGE, ERROR_MESSAGE );
+ _Message->Display( " " );
+ return( FALSE );
+ }
+ if( !_EndOfLineString.Initialize( (LPWSTR)L"\r\n" ) ) {
+ DebugPrint( "_EndOfLineString.Initialize() failed" );
+ return( FALSE );
+ }
+ _Position--;
+ return( TRUE );
+}
+
+
+
+
+BOOLEAN
+SORT::ReadSortAndWriteStrings(
+ )
+
+/*++
+
+Routine Description:
+
+ Sorts and displays all strings read from standard input.
+ The following steps are executed:
+ .initialize the array that will contain the strings to be sorted;
+ .read all the strings from standard input and save the in the
+ array;
+ .sort the strings;
+ .write them to the standard output.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - return always TRUE.
+
+
+--*/
+
+{
+ PWSTRING String;
+ PWSTRING StringToWrite;
+ WCHAR Wchar;
+ PITERATOR Iterator;
+ STRING_ARRAY StringArray;
+ CHNUM Length;
+ CHNUM l;
+
+ if( !StringArray.Initialize( _Position ) ) {
+ DebugAbort( "ArgumentArray.Put() failed \n" );
+ return( FALSE );
+ }
+ while( !_Standard_Input_Stream->IsAtEnd() ) {
+ if( ( String = NEW( DSTRING ) ) == NULL || !String->Initialize( "" ) ) {
+ _Message->Set( MSG_INSUFFICIENT_MEMORY, ERROR_MESSAGE );
+ _Message->Display();
+ DebugAbort( "String->Initialize() failed \n" );
+ return( FALSE );
+ }
+ if( !_Standard_Input_Stream->ReadLine( String ) ) {
+ DELETE( String );
+ _Message->Set( MSG_INSUFFICIENT_MEMORY, ERROR_MESSAGE );
+ _Message->Display();
+ DebugAbort( "ReadString() failed \n" );
+ return( FALSE );
+ }
+
+ // Don't count a null string if IsAtEnd is true
+ // to handle ^Z properly on input.
+
+ if (String->QueryChCount() == 0 &&
+ _Standard_Input_Stream->IsAtEnd()) {
+
+ break;
+ }
+
+ // If there's a ^Z in this string then we need to
+ // make this the end of input, regardless of whether
+ // or not there's more stuff left in the file.
+
+ l = String->Strchr(0x1A);
+ if (l != INVALID_CHNUM) {
+ String->Truncate(l);
+
+ if (l != 0) {
+ if (!StringArray.Put(String)) {
+ _Message->Set( MSG_INSUFFICIENT_MEMORY, ERROR_MESSAGE );
+ _Message->Display();
+ return FALSE;
+ }
+ }
+
+ break;
+ }
+
+ if( StringArray.Put( String ) == NULL ) {
+
+ _Message->Set( MSG_INSUFFICIENT_MEMORY, ERROR_MESSAGE );
+ _Message->Display();
+
+ DebugAbort( "StringArray.Put() failed \n" );
+ return( FALSE );
+ }
+ }
+
+ if( !StringArray.Sort( _AscendingOrder ) ) {
+ DebugAbort( "StringArray.Sort() failed \n" );
+ return( FALSE );
+ }
+ if( ( Iterator = StringArray.QueryIterator() ) == NULL ) {
+ DebugAbort( "StringArray.QueryIterator() failed \n" );
+ _Message->Set( MSG_INSUFFICIENT_MEMORY, ERROR_MESSAGE );
+ _Message->Display();
+ return( FALSE );
+ }
+ while( ( StringToWrite = ( PWSTRING )Iterator->GetNext() ) != NULL ) {
+ StringToWrite->Strcat( &_EndOfLineString );
+ Length = StringToWrite->QueryChCount();
+ if( !_Standard_Output_Stream->WriteString( StringToWrite, 0, Length ) ) {
+ DebugAbort( "_Standard_Output_Stream->WriteString() failed \n" );
+ return( FALSE );
+ }
+ }
+ DELETE( Iterator );
+ return( TRUE );
+}
+
+
+ULONG _CRTAPI1
+main()
+
+{
+ DEFINE_CLASS_DESCRIPTOR( SORT );
+
+ {
+ SORT Sort;
+
+ perrstk = NEW ERRSTACK;
+
+ if( Sort.Initialize() ) {
+ Sort.ReadSortAndWriteStrings();
+ }
+ DELETE( perrstk );
+ }
+ return( 0 );
+}
diff --git a/private/utils/sort/sort.hxx b/private/utils/sort/sort.hxx
new file mode 100644
index 000000000..6221a6551
--- /dev/null
+++ b/private/utils/sort/sort.hxx
@@ -0,0 +1,66 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ sort.hxx
+
+Abstract:
+
+ This module contains the definition of the SORT class.
+ SORT implements the sort utility, and has the same functionality
+ as the one in Dos 5.0.
+
+Author:
+
+ Jaime F. Sasson (jaimes) 02-May-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if ! defined( _SORT_ )
+
+#define _SORT_
+
+#include "object.hxx"
+#include "keyboard.hxx"
+#include "program.hxx"
+
+DECLARE_CLASS( SORT );
+
+class SORT : public PROGRAM {
+
+ public:
+
+
+ DECLARE_CONSTRUCTOR( SORT );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ReadSortAndWriteStrings (
+ );
+
+
+ private:
+
+ DSTRING _EndOfLineString;
+
+ BOOLEAN _AscendingOrder;
+ ULONG _Position;
+ PSTREAM _Standard_Input_Stream;
+ PSTREAM _Standard_Output_Stream;
+ PSTREAM _Standard_Error_Stream;
+ PSTREAM_MESSAGE _Message;
+};
+
+
+#endif // _SORT_
diff --git a/private/utils/sort/sort.rc b/private/utils/sort/sort.rc
new file mode 100644
index 000000000..5d1731f77
--- /dev/null
+++ b/private/utils/sort/sort.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Sort Utility"
+#define VER_INTERNALNAME_STR "Sort"
+#define VER_ORIGINALFILENAME_STR "Sort.Exe"
+
+#include "common.ver"
diff --git a/private/utils/sort/sources b/private/utils/sort/sources
new file mode 100644
index 000000000..302ecc7ef
--- /dev/null
+++ b/private/utils/sort/sources
@@ -0,0 +1,57 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=utils
+MINORCOMP=sort
+
+TARGETNAME=sort
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=sort.cxx sort.rc
+
+INCLUDES=..\ulib\inc;\nt\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+CXXFLAGS=+d
+TARGETLIBS= \
+ ..\ulib\src\obj\*\ulib.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+
+UMTYPE=console
diff --git a/private/utils/subst/makefile b/private/utils/subst/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/subst/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/subst/makefile.inc b/private/utils/subst/makefile.inc
new file mode 100644
index 000000000..6c93eb38d
--- /dev/null
+++ b/private/utils/subst/makefile.inc
@@ -0,0 +1,12 @@
+{}.cxx{obj\i386\}.obj:
+ $(386_COMPILER) -Fo$@ $(MAKEDIR)\$(<F)
+
+{}.cxx{obj\mips\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClMips $< " $(C_COMPILER) "
+ @$(C_COMPILER) -Fo$@ $(MAKEDIR)\$<
+
+{}.cxx{obj\alpha\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClAlpha $< " $(ALPHA_COMPILER) "
+ @$(ALPHA_COMPILER) -Fo$@ $(MAKEDIR)\$<
diff --git a/private/utils/subst/sources b/private/utils/subst/sources
new file mode 100644
index 000000000..436cd885a
--- /dev/null
+++ b/private/utils/subst/sources
@@ -0,0 +1,54 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=utils
+MINORCOMP=subst
+
+TARGETNAME=subst
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+SOURCES=subst.cxx subst.rc
+
+INCLUDES=..\ulib\inc;..\ifsutil\inc;$(BASEDIR)\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+TARGETLIBS= \
+ ..\ulib\src\obj\*\ulib.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+
+UMTYPE=console
diff --git a/private/utils/subst/subst.cxx b/private/utils/subst/subst.cxx
new file mode 100644
index 000000000..4c199ea71
--- /dev/null
+++ b/private/utils/subst/subst.cxx
@@ -0,0 +1,401 @@
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "arg.hxx"
+#include "array.hxx"
+#include "smsg.hxx"
+#include "rtmsg.h"
+#include "wstring.hxx"
+#include "path.hxx"
+#include "substrng.hxx"
+#include "system.hxx"
+#include "ulibcl.hxx"
+#include "subst.hxx"
+#include "dir.hxx"
+// #include "..\..\windows\inc\conapi.h"
+
+BOOLEAN
+QuerySubstedDrive(
+ IN DWORD DriveNumber,
+ OUT LPWSTR PhysicalDrive,
+ IN DWORD PhysicalDriveLength,
+ IN LPDWORD DosError
+ );
+
+
+
+ERRSTACK* perrstk;
+
+VOID
+DisplaySubstUsage(
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine displays the usage for the dos 5 label program.
+
+Arguments:
+
+ Message - Supplies an outlet for the messages.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Message->Set(MSG_SUBST_INFO);
+ Message->Display("");
+ Message->Set(MSG_SUBST_USAGE);
+ Message->Display("");
+}
+
+BOOLEAN
+DeleteSubst(
+ IN LPWSTR Drive,
+ IN OUT PMESSAGE Message
+ )
+{
+ BOOL Success;
+ FSTRING AuxString;
+
+ DWORD Status;
+ WCHAR Buffer[ MAX_PATH + 1 ];
+
+ Success = QuerySubstedDrive( *Drive - ( WCHAR )'@',
+ Buffer,
+ sizeof( Buffer ) / sizeof( WCHAR ),
+ &Status );
+
+ if( Success ) {
+ Success = DefineDosDevice( DDD_REMOVE_DEFINITION,
+ Drive,
+ NULL );
+ if( !Success ) {
+ Status = GetLastError();
+ }
+ }
+ if (!Success) {
+ if( Status == ERROR_ACCESS_DENIED ) {
+ AuxString.Initialize( Drive );
+ Message->Set(MSG_SUBST_ACCESS_DENIED);
+ Message->Display("%W",&AuxString);
+ } else {
+ AuxString.Initialize( Drive );
+ Message->Set(MSG_SUBST_INVALID_PARAMETER);
+ Message->Display("%W",&AuxString);
+ }
+ }
+ return Success;
+}
+
+BOOLEAN
+AddSubst(
+ IN LPWSTR Drive,
+ IN LPWSTR PhysicalDrive,
+ IN DWORD PhysicalDriveLength,
+ IN OUT PMESSAGE Message
+ )
+{
+ DWORD Status;
+ FSTRING AuxString;
+
+ WCHAR Buffer[ MAX_PATH + 1 ];
+
+ if( !QuerySubstedDrive( Drive[0] - '@',
+ Buffer,
+ sizeof( Buffer ) / sizeof( WCHAR ),
+ &Status ) ) {
+ if( Status == ERROR_FILE_NOT_FOUND ) {
+ if( !DefineDosDevice( 0, Drive, PhysicalDrive ) ) {
+ Status = GetLastError();
+ } else {
+ Status = ERROR_SUCCESS;
+ }
+ }
+ } else {
+ Status = ERROR_IS_SUBSTED;
+ }
+
+ if( Status != ERROR_SUCCESS ) {
+ if( Status == ERROR_IS_SUBSTED ) {
+ Message->Set(MSG_SUBST_ALREADY_SUBSTED);
+ Message->Display("");
+ } else if (Status == ERROR_FILE_NOT_FOUND) {
+ AuxString.Initialize( PhysicalDrive );
+ Message->Set(MSG_SUBST_PATH_NOT_FOUND);
+ Message->Display("%W", &AuxString);
+ } else if (Status == ERROR_ACCESS_DENIED) {
+ AuxString.Initialize( PhysicalDrive );
+ Message->Set(MSG_SUBST_ACCESS_DENIED);
+ Message->Display("%W", &AuxString);
+ } else {
+ AuxString.Initialize( Drive );
+ Message->Set(MSG_SUBST_INVALID_PARAMETER);
+ Message->Display("%W", &AuxString );
+ }
+ return( FALSE );
+ } else {
+ return( TRUE );
+ }
+}
+
+BOOLEAN
+QuerySubstedDrive(
+ IN DWORD DriveNumber,
+ OUT LPWSTR PhysicalDrive,
+ IN DWORD PhysicalDriveLength,
+ IN LPDWORD DosError
+ )
+{
+ WCHAR DriveName[3];
+ FSTRING DosDevicesPattern;
+ FSTRING DeviceName;
+ CHNUM Position;
+
+ DriveName[0] = ( WCHAR )( DriveNumber + '@' );
+ DriveName[1] = ( WCHAR )':';
+ DriveName[2] = ( WCHAR )'\0';
+
+ if( QueryDosDevice( DriveName,
+ PhysicalDrive,
+ PhysicalDriveLength ) != 0 ) {
+ DosDevicesPattern.Initialize( (LPWSTR)L"\\??\\" );
+ DeviceName.Initialize( PhysicalDrive );
+ Position = DeviceName.Strstr( &DosDevicesPattern );
+ if( Position == 0 ) {
+ DeviceName.DeleteChAt( 0, DosDevicesPattern.QueryChCount() );
+ *DosError = ERROR_SUCCESS;
+ return( TRUE );
+ } else {
+ //
+ // This is not a Dos device
+ //
+ *DosError = ERROR_INVALID_PARAMETER;
+ return( FALSE );
+ }
+ } else {
+ *DosError = GetLastError();
+ return( FALSE );
+ }
+}
+
+VOID
+DumpSubstedDrives (
+ IN OUT PMESSAGE Message
+ )
+{
+ DSTRING Source;
+ WCHAR LinkBuffer[MAX_PATH];
+ DWORD i;
+ FSTRING AuxString;
+ DWORD ErrorCode;
+
+ Source.Initialize(L"D:\\");
+ Message->Set(MSG_SUBST_SUBSTED_DRIVE);
+ for (i=1;i<=MAXIMUM_DRIVES;i++) {
+ if (QuerySubstedDrive(i,LinkBuffer,sizeof(LinkBuffer),&ErrorCode)) {
+ Source.SetChAt((WCHAR)(i+'@'),0);
+ AuxString.Initialize( LinkBuffer );
+ Message->Display("%W%W", &Source, &AuxString);
+ }
+ }
+}
+
+INT
+_CRTAPI1
+main(
+ )
+/*++
+
+Routine Description:
+
+ This routine emulates the dos 5 subst command for NT.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ 1 - An error occured.
+ 0 - Success.
+
+--*/
+{
+ STREAM_MESSAGE msg;
+ ARGUMENT_LEXEMIZER arglex;
+ ARRAY lex_array;
+ ARRAY arg_array;
+ STRING_ARGUMENT progname;
+ PATH_ARGUMENT virtualdrive_arg;
+ PATH_ARGUMENT physicaldrive_arg;
+ FLAG_ARGUMENT help_arg;
+ FLAG_ARGUMENT delete_arg;
+ PWSTRING p;
+ BOOL Success=TRUE;
+
+
+ if (!(perrstk = NEW ERRSTACK)) {
+ return 1;
+ }
+
+ if (!msg.Initialize(Get_Standard_Output_Stream(),
+ Get_Standard_Input_Stream(),
+ Get_Standard_Error_Stream())) {
+ return 1;
+ }
+
+ if (!lex_array.Initialize() || !arg_array.Initialize()) {
+ return 1;
+ }
+
+ if (!arglex.Initialize(&lex_array)) {
+ return 1;
+ }
+
+ arglex.PutSwitches( "/" );
+ arglex.PutStartQuotes( "\"" );
+ arglex.PutEndQuotes( "\"" );
+ arglex.PutSeparators( " \t" );
+ arglex.SetCaseSensitive(FALSE);
+
+ if (!arglex.PrepareToParse()) {
+ return 1;
+ }
+
+ if ( !arg_array.Initialize() ) {
+ return 1;
+ }
+
+ if (!progname.Initialize("*") ||
+ !help_arg.Initialize("/?") ||
+ !virtualdrive_arg.Initialize("*", FALSE) ||
+ !physicaldrive_arg.Initialize("*",FALSE) ||
+ !delete_arg.Initialize("/D") ) {
+ return 1;
+ }
+
+ if (!arg_array.Put(&progname) ||
+ !arg_array.Put(&virtualdrive_arg) ||
+ !arg_array.Put(&physicaldrive_arg) ||
+ !arg_array.Put(&help_arg) ||
+ !arg_array.Put(&delete_arg) ) {
+ return 1;
+ }
+
+ if (!arglex.DoParsing(&arg_array)) {
+ if (arglex.QueryLexemeCount() > MAXIMUM_SUBST_ARGS) {
+ msg.Set(MSG_SUBST_TOO_MANY_PARAMETERS);
+ msg.Display("%W", p = arglex.GetLexemeAt(MAXIMUM_SUBST_ARGS));
+ } else {
+ msg.Set(MSG_SUBST_INVALID_PARAMETER);
+ msg.Display("%W", p = arglex.QueryInvalidArgument());
+ }
+ DELETE(p);
+ return 1;
+ }
+
+ if (help_arg.QueryFlag()) {
+ DisplaySubstUsage(&msg);
+ return 0;
+ }
+
+ if (delete_arg.IsValueSet() &&
+ virtualdrive_arg.IsValueSet() &&
+ physicaldrive_arg.IsValueSet()) {
+ msg.Set(MSG_SUBST_TOO_MANY_PARAMETERS);
+ msg.Display("%W", delete_arg.GetPattern() );
+ return 1;
+ }
+
+ if (delete_arg.IsValueSet() &&
+ !virtualdrive_arg.IsValueSet() &&
+ !physicaldrive_arg.IsValueSet()) {
+ msg.Set(MSG_SUBST_INVALID_PARAMETER);
+ msg.Display("%W", delete_arg.GetPattern());
+ return 1;
+ }
+
+ //
+ // Validate virtual drive
+ // A virtual drive MUST have the format <drive letter>:
+ // Anything that doesn't have this format is considered an invalid parameter
+ //
+ if( virtualdrive_arg.IsValueSet() &&
+ ( ( virtualdrive_arg.GetPath()->GetPathString()->QueryChCount() != 2 ) ||
+ ( virtualdrive_arg.GetPath()->GetPathString()->QueryChAt( 1 ) != ( WCHAR )':' ) )
+ ) {
+ msg.Set(MSG_SUBST_INVALID_PARAMETER);
+ msg.Display("%W", virtualdrive_arg.GetPath()->GetPathString() );
+ return 1;
+ }
+
+ //
+ // Validate physical drive
+ // A physical drive CANNOT have the format <drive letter>:
+ //
+ if( physicaldrive_arg.IsValueSet() &&
+ ( physicaldrive_arg.GetPath()->GetPathString()->QueryChCount() == 2 ) &&
+ ( physicaldrive_arg.GetPath()->GetPathString()->QueryChAt( 1 ) == ( WCHAR )':' )
+ ) {
+ msg.Set(MSG_SUBST_INVALID_PARAMETER);
+ msg.Display("%W", physicaldrive_arg.GetPath()->GetPathString() );
+ return 1;
+ }
+
+//
+ if (virtualdrive_arg.IsValueSet()) {
+ DSTRING virtualdrivepath;
+ DSTRING colon;
+ PATH TmpPath;
+ PFSN_DIRECTORY Directory;
+
+ virtualdrivepath.Initialize(virtualdrive_arg.GetPath()->GetPathString());
+ if (virtualdrivepath.Strupr() ) {
+ if (delete_arg.IsValueSet()) {
+ Success = DeleteSubst(virtualdrivepath.QueryWSTR(),&msg);
+ } else if (physicaldrive_arg.IsValueSet()) {
+ LPWSTR physicaldrivepath;
+
+ //
+ // verify that the physical drive is an accessible path
+ //
+ Directory = SYSTEM::QueryDirectory( physicaldrive_arg.GetPath() );
+ if( !Directory ) {
+ msg.Set(MSG_SUBST_PATH_NOT_FOUND);
+ msg.Display("%W", physicaldrive_arg.GetPath()->GetPathString());
+ return 1;
+ }
+ DELETE( Directory );
+ TmpPath.Initialize( physicaldrive_arg.GetPath(), TRUE );
+ physicaldrivepath = ( TmpPath.GetPathString() )->QueryWSTR();
+ Success = AddSubst(virtualdrivepath.QueryWSTR(),
+ physicaldrivepath,
+ ( TmpPath.GetPathString() )->QueryChCount(),
+ &msg
+ );
+ DELETE(physicaldrivepath);
+ } else {
+ msg.Set(MSG_SUBST_INVALID_PARAMETER);
+ msg.Display("%W", p = arglex.GetLexemeAt(1));
+ DELETE(p);
+ return 1;
+ }
+ }
+ } else {
+ if (arglex.QueryLexemeCount() > 1) {
+ msg.Set(MSG_SUBST_INVALID_PARAMETER);
+ msg.Display("%W", p = arglex.GetLexemeAt(1));
+ DELETE(p);
+ return 1;
+ } else {
+ DumpSubstedDrives(&msg);
+ }
+ }
+
+ return !Success;
+}
diff --git a/private/utils/subst/subst.hxx b/private/utils/subst/subst.hxx
new file mode 100644
index 000000000..e9b1b38ef
--- /dev/null
+++ b/private/utils/subst/subst.hxx
@@ -0,0 +1,23 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ subst.hxx
+
+Abstract:
+
+ This module contains drive letter substitution routines.
+
+Author:
+
+ Therese Stowell (thereses) 07-Aug-92
+
+--*/
+
+
+DECLARE_CLASS( PATH );
+
+#define MAXIMUM_SUBST_ARGS 3
+#define MAXIMUM_DRIVES 26
diff --git a/private/utils/subst/subst.rc b/private/utils/subst/subst.rc
new file mode 100644
index 000000000..28638199c
--- /dev/null
+++ b/private/utils/subst/subst.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Subst Utility"
+#define VER_INTERNALNAME_STR "Subst"
+#define VER_ORIGINALFILENAME_STR "Subst.Exe"
+
+#include "common.ver"
diff --git a/private/utils/tree/makefile b/private/utils/tree/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/tree/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/tree/makefile.inc b/private/utils/tree/makefile.inc
new file mode 100644
index 000000000..6c93eb38d
--- /dev/null
+++ b/private/utils/tree/makefile.inc
@@ -0,0 +1,12 @@
+{}.cxx{obj\i386\}.obj:
+ $(386_COMPILER) -Fo$@ $(MAKEDIR)\$(<F)
+
+{}.cxx{obj\mips\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClMips $< " $(C_COMPILER) "
+ @$(C_COMPILER) -Fo$@ $(MAKEDIR)\$<
+
+{}.cxx{obj\alpha\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClAlpha $< " $(ALPHA_COMPILER) "
+ @$(ALPHA_COMPILER) -Fo$@ $(MAKEDIR)\$<
diff --git a/private/utils/tree/sources b/private/utils/tree/sources
new file mode 100644
index 000000000..1ff9c720b
--- /dev/null
+++ b/private/utils/tree/sources
@@ -0,0 +1,57 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=utils
+MINORCOMP=tree
+
+TARGETNAME=tree
+TARGETPATH=obj
+TARGETTYPE=UMAPPL_NOLIB
+
+SOURCES=tree.cxx tree.rc
+
+INCLUDES=..\ulib\inc;\nt\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+UMLIBS= \
+ ..\ulib\src\obj\*\ulib.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+
+UMTYPE=console
+UMAPPL=tree
+UMAPPLEXT=.com
+UMRES=obj\*\tree.res
diff --git a/private/utils/tree/tree.cxx b/private/utils/tree/tree.cxx
new file mode 100644
index 000000000..a701e439d
--- /dev/null
+++ b/private/utils/tree/tree.cxx
@@ -0,0 +1,880 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ tree.cxx
+
+Abstract:
+
+ This module contains the implementation of the TREE class.
+ The TREE class implements a tree utility functionally compatible
+ with the DOS 5 tree utility.
+ This utility displays the directory structure of a path or drive.
+
+ Usage:
+
+ TREE [drive:][path] [/F] [/A] [/?]
+
+ /F Display the names of files in each directory.
+
+ /A Uses ASCII instead of extended characters.
+
+ /? Displays a help message.
+
+
+Author:
+
+ Jaime F. Sasson - jaimes - 13-May-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "arg.hxx"
+#include "array.hxx"
+#include "path.hxx"
+#include "wstring.hxx"
+#include "substrng.hxx"
+#include "dir.hxx"
+#include "filter.hxx"
+#include "system.hxx"
+#include "arrayit.hxx"
+#include "smsg.hxx"
+#include "stream.hxx"
+#include "rtmsg.h"
+#include "tree.hxx"
+
+extern "C" {
+#include <stdio.h>
+#include <string.h>
+}
+
+
+#define UNICODE_SINGLE_LEFT_T 0x251c
+#define UNICODE_SINGLE_BOTTOM_LEFT_CORNER 0x2514
+#define UNICODE_SINGLE_BOTTOM_HORIZONTAL 0x2500
+#define UNICODE_SINGLE_VERTICAL 0x2502
+#define UNICODE_SPACE 0x0020
+
+
+PSTREAM Get_Standard_Input_Stream();
+PSTREAM Get_Standard_Output_Stream();
+
+ERRSTACK* perrstk;
+
+DEFINE_CONSTRUCTOR( TREE, PROGRAM );
+
+
+BOOLEAN
+TREE::Initialize(
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes a TREE class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the initialization succeeded.
+
+
+--*/
+
+
+{
+ ARGUMENT_LEXEMIZER ArgLex;
+ ARRAY LexArray;
+
+ ARRAY ArgumentArray;
+
+ STRING_ARGUMENT ProgramNameArgument;
+ PATH_ARGUMENT DirectoryPathArgument;
+ PWSTRING DirectoryNameString;
+ PATH DirectoryNamePath;
+ PWSTRING InvalidArgument;
+ PCWSTRING InvalidPath;
+ STRING_ARGUMENT InvalidSwitch;
+ PATH AuxPath;
+ STRING_ARGUMENT ParamNotCorrectFile;
+ STRING_ARGUMENT ParamNotCorrectAscii;
+ STRING_ARGUMENT ParamNotCorrectHelp;
+ BOOLEAN FlagInvalidPath;
+ PATH AuxInvPath;
+ PWSTRING InvPathNoDrive;
+ PWSTRING Device;
+ PATH DevPth;
+ PFSN_DIRECTORY DevDir;
+
+#if defined(JAPAN)
+ // How many
+ // columns
+ // is needed
+ // ?
+ WCHAR BufferMiddleBranch437[] = {
+ UNICODE_SINGLE_LEFT_T, // 1
+ UNICODE_SINGLE_BOTTOM_HORIZONTAL, // 1
+ UNICODE_SINGLE_BOTTOM_HORIZONTAL, // 1
+ UNICODE_SINGLE_BOTTOM_HORIZONTAL, // 1
+ UNICODE_NULL // 0
+ };
+ WCHAR BufferBottomBranch437[] = {
+ UNICODE_SINGLE_BOTTOM_LEFT_CORNER, // 1
+ UNICODE_SINGLE_BOTTOM_HORIZONTAL, // 1
+ UNICODE_SINGLE_BOTTOM_HORIZONTAL, // 1
+ UNICODE_SINGLE_BOTTOM_HORIZONTAL, // 1
+ UNICODE_NULL // 0
+ };
+
+ WCHAR BufferConnectingBranch437[] = {
+ UNICODE_SINGLE_VERTICAL, // 1
+ UNICODE_SPACE, // 1
+ UNICODE_SPACE, // 1
+ UNICODE_SPACE, // 1
+ UNICODE_NULL // 0
+ };
+
+ WCHAR BufferMiddleBranch932[] = {
+ UNICODE_SINGLE_LEFT_T, // 2
+ UNICODE_SINGLE_BOTTOM_HORIZONTAL, // 2
+ UNICODE_NULL // 0
+ };
+ WCHAR BufferBottomBranch932[] = {
+ UNICODE_SINGLE_BOTTOM_LEFT_CORNER, // 2
+ UNICODE_SINGLE_BOTTOM_HORIZONTAL, // 2
+ UNICODE_NULL // 0
+ };
+
+ WCHAR BufferConnectingBranch932[] = {
+ UNICODE_SINGLE_VERTICAL, // 2
+ UNICODE_SPACE, // 1
+ UNICODE_SPACE, // 1
+ UNICODE_NULL // 0
+ };
+
+ PWCHAR BufferMiddleBranch;
+ PWCHAR BufferBottomBranch;
+ PWCHAR BufferConnectingBranch;
+
+ if( ::GetConsoleOutputCP() == 932 ) {
+
+ BufferMiddleBranch = BufferMiddleBranch932;
+ BufferBottomBranch = BufferBottomBranch932;
+ BufferConnectingBranch = BufferConnectingBranch932;
+
+ } else {
+
+ BufferMiddleBranch = BufferMiddleBranch437;
+ BufferBottomBranch = BufferBottomBranch437;
+ BufferConnectingBranch = BufferConnectingBranch437;
+
+ }
+#else
+ WCHAR BufferMiddleBranch[] = {
+ UNICODE_SINGLE_LEFT_T,
+ UNICODE_SINGLE_BOTTOM_HORIZONTAL,
+ UNICODE_SINGLE_BOTTOM_HORIZONTAL,
+ UNICODE_SINGLE_BOTTOM_HORIZONTAL,
+ UNICODE_NULL
+ };
+ WCHAR BufferBottomBranch[] = {
+ UNICODE_SINGLE_BOTTOM_LEFT_CORNER,
+ UNICODE_SINGLE_BOTTOM_HORIZONTAL,
+ UNICODE_SINGLE_BOTTOM_HORIZONTAL,
+ UNICODE_SINGLE_BOTTOM_HORIZONTAL,
+ UNICODE_NULL
+ };
+
+ WCHAR BufferConnectingBranch[] = {
+ UNICODE_SINGLE_VERTICAL,
+ UNICODE_SPACE,
+ UNICODE_SPACE,
+ UNICODE_SPACE,
+ UNICODE_NULL
+ };
+#endif // defined(JAPAN)
+
+ _InitialDirectory = NULL;
+ FlagInvalidPath = FALSE;
+ _FlagAtLeastOneSubdir = TRUE;
+ _StandardOutput = Get_Standard_Output_Stream();
+
+ //
+ // Initialize MESSAGE class
+ //
+ _Message.Initialize( _StandardOutput, Get_Standard_Input_Stream() );
+
+ //
+ // Parse command line
+ //
+ if ( !LexArray.Initialize( ) ) {
+ DebugAbort( "LexArray.Initialize() failed \n" );
+ return( FALSE );
+ }
+ if ( !ArgLex.Initialize( &LexArray ) ) {
+ DebugAbort( "ArgLex.Initialize() failed \n" );
+ return( FALSE );
+ }
+ ArgLex.PutSwitches( "/" );
+ ArgLex.PutStartQuotes( "\"" );
+ ArgLex.PutEndQuotes( "\"" );
+ ArgLex.PutSeparators( " \t" );
+ ArgLex.SetCaseSensitive( FALSE );
+
+ if( !ArgLex.PrepareToParse() ) {
+ DebugAbort( "ArgLex.PrepareToParse() failed \n" );
+ return( FALSE );
+ }
+ if ( !ArgumentArray.Initialize() ) {
+ DebugAbort( "ArgumentArray.Initialize() failed \n" );
+ return( FALSE );
+ }
+ if( !ProgramNameArgument.Initialize("*") ||
+ !_FlagDisplayFiles.Initialize( "/F" ) ||
+ !_FlagUseAsciiCharacters.Initialize( "/A" ) ||
+ !_FlagDisplayHelp.Initialize( "/?" ) ||
+ !ParamNotCorrectFile.Initialize( "/F*" ) ||
+ !ParamNotCorrectAscii.Initialize( "/A*" ) ||
+ !ParamNotCorrectHelp.Initialize( "/?*" ) ||
+ !InvalidSwitch.Initialize( "/*" ) ||
+ !DirectoryPathArgument.Initialize( "*" ) ) {
+ DebugAbort( "Unable to initialize flag or string arguments \n" );
+ return( FALSE );
+ }
+ if( !ArgumentArray.Put( &ProgramNameArgument ) ||
+ !ArgumentArray.Put( &_FlagDisplayFiles ) ||
+ !ArgumentArray.Put( &_FlagUseAsciiCharacters ) ||
+ !ArgumentArray.Put( &_FlagDisplayHelp ) ||
+ !ArgumentArray.Put( &ParamNotCorrectFile ) ||
+ !ArgumentArray.Put( &ParamNotCorrectAscii ) ||
+ !ArgumentArray.Put( &ParamNotCorrectHelp ) ||
+ !ArgumentArray.Put( &InvalidSwitch ) ||
+ !ArgumentArray.Put( &DirectoryPathArgument ) ) {
+ DebugAbort( "ArgumentArray.Put() failed \n" );
+ return( FALSE );
+ }
+ if( !ArgLex.DoParsing( &ArgumentArray ) ) {
+ InvalidArgument = ArgLex.QueryInvalidArgument();
+ DebugPtrAssert( InvalidArgument );
+ _Message.Set( MSG_TREE_TOO_MANY_PARAMETERS );
+ _Message.Display( "%W", InvalidArgument );
+ return( FALSE );
+ }
+ if( InvalidSwitch.IsValueSet() ) {
+ InvalidArgument = InvalidSwitch.GetString();
+ DebugPtrAssert( InvalidArgument );
+ _Message.Set( MSG_TREE_INVALID_SWITCH );
+ _Message.Display( "%W", InvalidArgument );
+ return( FALSE );
+ }
+ if( ParamNotCorrectFile.IsValueSet() ) {
+ InvalidArgument = ParamNotCorrectFile.GetLexeme();
+ DebugPtrAssert( InvalidArgument );
+ _Message.Set( MSG_TREE_PARAMETER_NOT_CORRECT );
+ _Message.Display( "%W", InvalidArgument );
+ return( FALSE );
+ }
+ if( ParamNotCorrectAscii.IsValueSet() ) {
+ InvalidArgument = ParamNotCorrectAscii.GetLexeme();
+ DebugPtrAssert( InvalidArgument );
+ _Message.Set( MSG_TREE_PARAMETER_NOT_CORRECT );
+ _Message.Display( "%W", InvalidArgument );
+ return( FALSE );
+ }
+ if( ParamNotCorrectHelp.IsValueSet() ) {
+ InvalidArgument = ParamNotCorrectHelp.GetLexeme();
+ DebugPtrAssert( InvalidArgument );
+ _Message.Set( MSG_TREE_PARAMETER_NOT_CORRECT );
+ _Message.Display( "%W", InvalidArgument );
+ return( FALSE );
+ }
+
+
+ //
+ // Displays help message if /? was found in the command line
+ //
+ if( _FlagDisplayHelp.QueryFlag() ) {
+ _Message.Set( MSG_TREE_HELP_MESSAGE );
+ _Message.Display( " " );
+ return( FALSE );
+ }
+
+ //
+ // Find initial directory
+ //
+ if( !DirectoryPathArgument.IsValueSet() ) {
+ //
+ // User did't specify a path, so assume current directory
+ //
+ _FlagPathSupplied = FALSE;
+
+ if (!DirectoryNamePath.Initialize((LPWSTR)L".", TRUE )) {
+
+ DebugAbort( "DirectoryNamePath.Initialize() failed \n" );
+ return( FALSE );
+ }
+
+ } else {
+ //
+ // User specified a path
+ //
+
+ DirectoryNameString = DirectoryPathArgument.GetPath()->QueryFullPathString();
+ DebugPtrAssert( DirectoryNameString );
+ DirectoryNameString->Strupr();
+
+ if (!DirectoryNamePath.Initialize(DirectoryNameString, TRUE)) {
+ DebugAbort( "DirectoryNamePath.Initialize() failed \n" );
+ return( FALSE );
+ }
+
+ //
+ // Save the path specified by the user as he/she typed it
+ // (but in upper case)
+ //
+ if( !AuxPath.Initialize( DirectoryNameString, FALSE ) ) {
+ DebugAbort( "AuxPath.Initialize() failed \n" );
+ return( FALSE );
+ }
+
+ //
+ // Validate the device if one was supplied
+ // AuxPath represents the path as typed by the user, and
+ // it may or may not contain a device. If it doesn't contain
+ // a device, no verification is made. In this case and we are
+ // sure that the device is valid
+ //
+ if( ( Device = AuxPath.QueryDevice() ) != NULL ) {
+ if( !DevPth.Initialize( Device ) ) {
+ DebugAbort( "DevPth.Initialize() failed \n" );
+ return( FALSE );
+ }
+ if( !(DevDir = SYSTEM::QueryDirectory( &DevPth ) ) ) {
+ _Message.Set( MSG_TREE_INVALID_DRIVE );
+ _Message.Display( " " );
+ DELETE( Device );
+ return( FALSE );
+ }
+ DELETE( Device );
+ DELETE( DevDir );
+ }
+
+ //
+ // Find out if what the user specified is just a drive
+ //
+ if( AuxPath.IsDrive() ) {
+ _FlagPathSupplied = FALSE;
+ } else {
+ _FlagPathSupplied = TRUE;
+ }
+ }
+
+ if (NULL == (_InitialDirectory = SYSTEM::QueryDirectory( &DirectoryNamePath ))) {
+
+ InvalidPath = DirectoryNamePath.GetPathString();
+ FlagInvalidPath = TRUE;
+ _FlagAtLeastOneSubdir = FALSE;
+ }
+
+ //
+ // Initialize filter for directories
+ //
+
+ if( !_FsnFilterDirectory.Initialize() ) {
+ DELETE( _InitialDirectory );
+ DebugAbort( "_FsnFilterDirectory.Initialize() failed \n" );
+ return( FALSE );
+ }
+ if( !_FsnFilterDirectory.SetFileName( "*.*" ) ) {
+ DELETE( _InitialDirectory );
+ DebugAbort( "_FsnFilterDirectory.SetFilename() failed \n" );
+ return( FALSE );
+ }
+ if( !_FsnFilterDirectory.SetAttributes( FSN_ATTRIBUTE_DIRECTORY,
+ ( FSN_ATTRIBUTE )0,
+ FSN_ATTRIBUTE_HIDDEN |
+ FSN_ATTRIBUTE_SYSTEM ) ) {
+ DELETE( _InitialDirectory );
+ DebugAbort( "_FsnFilterDirectory.SetAttributes() failed \n" );
+ return( FALSE );
+ }
+
+ //
+ // Initilize filter for files
+ //
+
+ if( _FlagDisplayFiles.QueryFlag() ) {
+ if( !_FsnFilterFile.Initialize() ) {
+ DELETE( _InitialDirectory );
+ DebugAbort( "FsnFilter.Initialize() failed \n" );
+ return( FALSE );
+ }
+ if( !_FsnFilterFile.SetFileName( "*.*" ) ) {
+ DELETE( _InitialDirectory );
+ DebugAbort( "FsnFilter.SetFilename() failed \n" );
+ return( FALSE );
+ }
+ if( !_FsnFilterFile.SetAttributes( ( FSN_ATTRIBUTE )0,
+ ( FSN_ATTRIBUTE )0,
+ FSN_ATTRIBUTE_DIRECTORY |
+ FSN_ATTRIBUTE_HIDDEN |
+ FSN_ATTRIBUTE_SYSTEM ) ) {
+ DELETE( _InitialDirectory );
+ DebugAbort( "FsnFilter.SetAttributes() failed \n" );
+ return( FALSE );
+ }
+ }
+
+ //
+ // Find out what kind of characters should be used to display the tree
+ // and initialize the basic strings
+ //
+ if( _FlagUseAsciiCharacters.QueryFlag() ) {
+
+ _StringForDirectory.Initialize( (LPWSTR)L"+---" );
+ _StringForLastDirectory.Initialize( (LPWSTR)L"\\---" );
+ _StringForFile.Initialize( (LPWSTR)L"| " );
+
+ } else {
+
+ _StringForDirectory.Initialize( BufferMiddleBranch ); // "ÃÄÄÄ"
+ _StringForLastDirectory.Initialize( BufferBottomBranch ); // "ÀÄÄÄ"
+ _StringForFile.Initialize( BufferConnectingBranch ); // "³ "
+
+ }
+ _StringForFileNoDirectory.Initialize( (LPWSTR)L" " );
+
+ if( !_EndOfLineString.Initialize( (LPWSTR)L"\r\n" ) ) {
+ DebugPrint( "_EndOfLineString.Initialize() failed" );
+ DELETE( _InitialDirectory );
+ return( FALSE );
+ }
+
+ _VolumeName = SYSTEM::QueryVolumeLabel( &DirectoryNamePath, &_SerialNumber );
+ if (NULL == _VolumeName) {
+ _Message.Set( MSG_TREE_INVALID_DRIVE );
+ _Message.Display( " " );
+ DELETE( Device );
+ return( FALSE );
+ }
+ DebugPtrAssert( _VolumeName );
+ _FlagAtLeastOneSubdir = FALSE;
+ if( FlagInvalidPath ) {
+ //
+ // If user specified an invalid path, then display the same
+ // messages that Dos 5 does.
+ //
+ // First displays the volume info.
+ //
+
+ DisplayVolumeInfo();
+
+ //
+ // Then display the path that is invalid. This path must be
+ // displayed in capital letters, must always contain a device,
+ // and must be displayed as a relative or absolute path depending
+ // on what the user specified.
+ //
+ Device = DirectoryNamePath.QueryDevice();
+ AuxInvPath.Initialize( DirectoryNameString, FALSE );
+ InvPathNoDrive = AuxInvPath.QueryDirsAndName();
+ _StandardOutput->WriteString( Device );
+ _StandardOutput->WriteString( InvPathNoDrive );
+ _StandardOutput->WriteByte( '\r' );
+ _StandardOutput->WriteByte( '\n' );
+
+ //
+ // Display the message "Invalid Path - <path>"
+ // The path in this case cannot contain a drive even if the
+ // user specified a drive.
+ //
+ _Message.Set( MSG_TREE_INVALID_PATH );
+ _Message.Display( "%W", InvPathNoDrive );
+ DELETE( Device );
+ DELETE( InvPathNoDrive );
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+VOID
+TREE::Terminate(
+ )
+
+/*++
+
+Routine Description:
+
+ Deletes objects created during initialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ if( _InitialDirectory != NULL ) {
+ DELETE( _InitialDirectory );
+ }
+ if( !_FlagAtLeastOneSubdir ) {
+ _Message.Set( MSG_TREE_NO_SUBDIRECTORIES );
+ _Message.Display( "%s", "\r\n" );
+ }
+
+}
+
+
+
+
+BOOLEAN
+TREE::DisplayName (
+ IN PCFSNODE Fsn,
+ IN PCWSTRING String
+ )
+
+/*++
+
+Routine Description:
+
+ This method writes to the standard output the name of a file or
+ directory, preceded by a string that represents pieces of the
+ tree structure (pieces of the tree branches).
+
+Arguments:
+
+ Fsn - Pointer to a FSNODE that describes the file or directory whose
+ name is to be written.
+
+ String - Pointer to a WSTRING object that contains the string to
+ be written before the file or directory name.
+
+Return Value:
+
+ BOOLEAN - returns TRUE to indicate that the operation succeeded, or
+ FALSE otherwise.
+
+--*/
+
+
+{
+ PWSTRING Name;
+ PCPATH Path;
+ PCWSTRING InitialDirectory;
+ DSTRING InitialDirectoryUpperCase;
+ PWSTRING Device;
+ DSTRING EndOfLinePrecededByDot;
+
+ DebugPtrAssert( Fsn );
+
+ Path = Fsn->GetPath();
+ DebugPtrAssert( Path );
+ if( String != NULL ) {
+ if( !_StandardOutput->WriteString( String, 0, String->QueryChCount() ) ) {
+ DebugAbort( "_StandardOutput->WriteString() failed \n" );
+ return( FALSE );
+ }
+ if( ( Name=Path->QueryName() ) == NULL ) {
+ DebugAbort( "Path->QueryName() failed \n" );
+ return( FALSE );
+ }
+ Name->Strcat( &_EndOfLineString );
+
+ if( !_StandardOutput->WriteString( Name, 0, Name->QueryChCount() ) ) {
+ DebugAbort( "_StandardOutput->WriteString() failed \n" );
+ DELETE( Name );
+ return( FALSE );
+ }
+
+ DELETE( Name );
+ } else {
+ if( _FlagPathSupplied ) {
+ InitialDirectory = Path->GetPathString();
+ DebugPtrAssert( InitialDirectory );
+ InitialDirectoryUpperCase.Initialize( InitialDirectory );
+ InitialDirectoryUpperCase.Strupr();
+ InitialDirectoryUpperCase.Strcat( &_EndOfLineString );
+ if( !_StandardOutput->WriteString( &InitialDirectoryUpperCase ) ) {
+ DebugAbort( "_StandardOutput->WriteString() failed \n" );
+ return( FALSE );
+ }
+ } else {
+ Device = PPATH(Path)->QueryDevice();
+ DebugPtrAssert( Device );
+ EndOfLinePrecededByDot.Initialize( (LPWSTR)L".\r\n" );
+ Device->Strcat( &EndOfLinePrecededByDot );
+ if( !_StandardOutput->WriteString( Device, 0, TO_END ) ) {
+ DebugAbort( "_StandardOutput->WriteString() failed \n" );
+ DELETE( Device );
+ return( FALSE );
+ }
+ DELETE( Device );
+ }
+ }
+ return( TRUE );
+}
+
+
+VOID
+TREE::DisplayVolumeInfo (
+ )
+
+/*++
+
+Routine Description:
+
+ This method writes to the standard output the the volume name (if one
+ is found) and the serial number.
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Display volume name
+ //
+ if( _VolumeName->QueryChCount() == 0 ) {
+ _Message.Set( MSG_TREE_DIR_LISTING_NO_VOLUME_NAME );
+ _Message.Display( " " );
+ } else {
+ _Message.Set( MSG_TREE_DIR_LISTING_WITH_VOLUME_NAME );
+ _Message.Display( "%W", _VolumeName );
+ }
+
+ //
+ // Display serial number
+ //
+ if( _SerialNumber.HighOrder32Bits != 0 ) {
+ _Message.Set( MSG_TREE_64_BIT_SERIAL_NUMBER );
+ _Message.Display( "%08X%04X%04X",
+ _SerialNumber.HighOrder32Bits,
+ _SerialNumber.LowOrder32Bits >> 16,
+ ( _SerialNumber.LowOrder32Bits << 16 ) >> 16);
+ } else {
+ _Message.Set( MSG_TREE_32_BIT_SERIAL_NUMBER );
+ _Message.Display( "%04X%04X",
+ _SerialNumber.LowOrder32Bits >> 16,
+ ( _SerialNumber.LowOrder32Bits << 16 ) >> 16 );
+ }
+}
+
+
+BOOLEAN
+TREE::ExamineDirectory(
+ IN PCFSN_DIRECTORY Directory,
+ IN PCWSTRING String
+ )
+
+/*++
+
+Routine Description:
+
+ Displays all files and subdirectories in the directory whose
+ FSN_DIRECTORY was received as parameter.
+
+
+Arguments:
+
+ Directory - Pointer to an FSN_DIRECTORY that describes the
+ directory to be examined
+
+ String - Pointer to a WSTRING that contains part of the string
+ to be written in the left side of each subdiretory name
+ and file name found in the directory being examined
+ (the one whose FSN_DIRECTORY was received as parameter)
+
+Return Value:
+
+ BOOLEAN - Returns TRUE to indicate that the operation succeded.
+ Returns FALSE otherwise.
+
+--*/
+
+{
+ PARRAY DirectoryArray;
+ PFSN_DIRECTORY FsnDirectory;
+ PARRAY_ITERATOR DirectoryArrayIterator;
+ PARRAY FileArray;
+ PARRAY_ITERATOR FileArrayIterator;
+ PFSNODE FsnFile;
+#if 0
+ PWSTRING StringFile;
+#endif
+#if 0
+ PWSTRING StringDir;
+ PWSTRING StringLastDir;
+ PWSTRING StringSon;
+ PWSTRING StringLastSon;
+#endif
+ DSTRING StringFile;
+ DSTRING StringDir;
+ DSTRING StringLastDir;
+ DSTRING StringSon;
+ DSTRING StringLastSon;
+
+ DebugPtrAssert( Directory );
+
+ //
+ // Build list of directories (ie., an array of PFSN_DIRECTORY of all
+ // sub-directories in the current directory
+ //
+ DirectoryArray = Directory->QueryFsnodeArray( &_FsnFilterDirectory );
+ DebugPtrAssert( DirectoryArray );
+ DirectoryArrayIterator =
+ ( PARRAY_ITERATOR )( DirectoryArray->QueryIterator() );
+ DebugPtrAssert( DirectoryArrayIterator );
+
+ //
+ // If files are to be displayed (/F in the command line), then build
+ // an array of files (ie., an array of PFSNODEs of all files in the
+ // current directory)
+ //
+ if( _FlagDisplayFiles.QueryFlag() ) {
+ FileArray = Directory->QueryFsnodeArray( &_FsnFilterFile );
+ DebugPtrAssert( FileArray );
+ FileArrayIterator =
+ ( PARRAY_ITERATOR )( FileArray->QueryIterator() );
+ DebugPtrAssert( FileArrayIterator );
+
+ //
+ // If array of files is not empty, then we need the strings
+ // to be displayed in the left side of file names. These strings
+ // will contain the pieces of the branches of the tree diagram.
+ // These strings for files are created here.
+ //
+ if( FileArray->QueryMemberCount() > 0 ) {
+#if 0
+ StringFile = NEW( DSTRING );
+ DebugPtrAssert( StringFile );
+#endif
+ if( DirectoryArray->QueryMemberCount() > 0 ) {
+ if( String == NULL ) {
+ StringFile.Initialize( &_StringForFile );
+ } else {
+ StringFile.Initialize( String );
+ StringFile.Strcat( &_StringForFile );
+ }
+ } else {
+ if( String == NULL ) {
+ StringFile.Initialize( &_StringForFileNoDirectory );
+ } else {
+ StringFile.Initialize( String );
+ StringFile.Strcat( &_StringForFileNoDirectory );
+ }
+ }
+
+ //
+ // Display all file names
+ //
+ while( ( FsnFile = ( PFSNODE )( FileArrayIterator->GetNext( ) ) ) != NULL ) {
+ DisplayName( FsnFile, &StringFile );
+ DELETE( FsnFile );
+ }
+
+ //
+ // Display an empty line after the last file
+ //
+ _StandardOutput->WriteString( &StringFile, 0, StringFile.QueryChCount() );
+ _StandardOutput->WriteString( &_EndOfLineString, 0, _EndOfLineString.QueryChCount() );
+
+ }
+ DELETE( FileArrayIterator );
+ DELETE( FileArray );
+ }
+
+ //
+ // If list of directories is not empty
+ //
+ if( DirectoryArray->QueryMemberCount() > 0 ) {
+ _FlagAtLeastOneSubdir = TRUE;
+ //
+ // Build strings to be printed before directory name
+ //
+ if( String == NULL ) {
+ StringDir.Initialize( &_StringForDirectory );
+ StringLastDir.Initialize( &_StringForLastDirectory );
+ StringSon.Initialize( &_StringForFile );
+ StringLastSon.Initialize( &_StringForFileNoDirectory );
+ } else {
+ StringDir.Initialize( String );
+ StringDir.Strcat( &_StringForDirectory );
+ StringLastDir.Initialize( String );
+ StringLastDir.Strcat( &_StringForLastDirectory );
+ StringSon.Initialize( String );
+ StringSon.Strcat( &_StringForFile );
+ StringLastSon.Initialize( String );
+ StringLastSon.Strcat( &_StringForFileNoDirectory );
+ }
+ //
+ // Display name of all directories, and examine each one of them
+ //
+ while( ( FsnDirectory = ( PFSN_DIRECTORY )( DirectoryArrayIterator->GetNext( ) ) ) != NULL ) {
+ if( DirectoryArrayIterator->QueryCurrentIndex() != DirectoryArray->QueryMemberCount() - 1 ) {
+ DisplayName( ( PCFSNODE )FsnDirectory, &StringDir );
+ ExamineDirectory( FsnDirectory, &StringSon );
+ } else {
+ DisplayName( ( PCFSNODE )FsnDirectory, &StringLastDir );
+ ExamineDirectory( FsnDirectory, &StringLastSon );
+ }
+ DELETE( FsnDirectory );
+ }
+ }
+ DELETE( DirectoryArrayIterator );
+ DELETE( DirectoryArray );
+ return( TRUE );
+}
+
+
+
+ULONG _CRTAPI1
+main()
+
+{
+ DEFINE_CLASS_DESCRIPTOR( TREE );
+
+ {
+ TREE Tree;
+ PCFSN_DIRECTORY Directory;
+
+
+ perrstk = NEW ERRSTACK;
+
+ if( Tree.Initialize() ) {
+ Tree.DisplayVolumeInfo();
+ //
+ // Display directory name
+ //
+ Directory = Tree.GetInitialDirectory();
+ Tree.DisplayName( ( PCFSNODE )Directory, ( PCWSTRING )NULL );
+ Tree.ExamineDirectory( Directory, ( PCWSTRING )NULL );
+ }
+ Tree.Terminate();
+ DELETE( perrstk );
+ }
+ return( 0 );
+}
diff --git a/private/utils/tree/tree.hxx b/private/utils/tree/tree.hxx
new file mode 100644
index 000000000..f7b98462f
--- /dev/null
+++ b/private/utils/tree/tree.hxx
@@ -0,0 +1,156 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ tree.hxx
+
+Abstract:
+
+ This module contains the definition of the TREE class.
+ The TREE class implements a tree utility functionally compatible
+ with the DOS 5 tree utility.
+ This utility displays the directory structure of a path or drive.
+
+ Usage:
+
+ TREE [drive:][path] [/F] [/A] [/?]
+
+ /F Display the names of files in each directory.
+
+ /A Uses ASCII instead of extended characters.
+
+ /? Displays a help message.
+
+
+
+Author:
+
+ Jaime F. Sasson - jaimes - 13-May-1991
+
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if ! defined( _TREE_ )
+
+#define _TREE_
+
+#include "object.hxx"
+#include "keyboard.hxx"
+#include "program.hxx"
+
+DECLARE_CLASS( TREE );
+
+class TREE : public PROGRAM {
+
+ public:
+
+
+ DECLARE_CONSTRUCTOR( TREE );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ DisplayName (
+ IN PCFSNODE Fsn,
+ IN PCWSTRING String
+ );
+
+
+ NONVIRTUAL
+ VOID
+ DisplayVolumeInfo (
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ ExamineDirectory(
+ IN PCFSN_DIRECTORY Directory,
+ IN PCWSTRING String
+ );
+
+
+ NONVIRTUAL
+ PFSN_DIRECTORY
+ GetInitialDirectory(
+ ) CONST;
+
+
+ NONVIRTUAL
+ VOID
+ Terminate(
+ );
+
+
+ private:
+
+ PSTREAM _StandardOutput;
+
+ FLAG_ARGUMENT _FlagDisplayFiles;
+ FLAG_ARGUMENT _FlagUseAsciiCharacters;
+ FLAG_ARGUMENT _FlagDisplayHelp;
+
+ PFSN_DIRECTORY _InitialDirectory;
+
+ FSN_FILTER _FsnFilterDirectory;
+ FSN_FILTER _FsnFilterFile;
+
+ STREAM_MESSAGE _Message;
+
+ DSTRING _StringForDirectory;
+ DSTRING _StringForLastDirectory;
+ DSTRING _StringForFile;
+ DSTRING _StringForFileNoDirectory;
+
+ DSTRING _EndOfLineString;
+
+ PWSTRING _VolumeName;
+ VOL_SERIAL_NUMBER _SerialNumber;
+ BOOLEAN _FlagAtLeastOneSubdir;
+ BOOLEAN _FlagPathSupplied;
+};
+
+
+
+INLINE
+PFSN_DIRECTORY
+TREE::GetInitialDirectory(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns to the caller a pointer to the fsnode corresponding to
+ the directory to be used as the root of the tree.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PFSN_DIRECTORY - Pointer to the fsnode that describes the starting
+ directory.
+
+
+--*/
+
+{
+ return( _InitialDirectory );
+}
+
+
+#endif // _TREE_
diff --git a/private/utils/tree/tree.rc b/private/utils/tree/tree.rc
new file mode 100644
index 000000000..e325333e9
--- /dev/null
+++ b/private/utils/tree/tree.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Tree Walk Utility"
+#define VER_INTERNALNAME_STR "tree\0"
+#define VER_ORIGINALFILENAME_STR "TREE.COM"
+
+#include "common.ver"
diff --git a/private/utils/ufat/dirs b/private/utils/ufat/dirs
new file mode 100644
index 000000000..c4db5a979
--- /dev/null
+++ b/private/utils/ufat/dirs
@@ -0,0 +1,16 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+!ENDIF
+
+DIRS= src
diff --git a/private/utils/ufat/inc/cluster.hxx b/private/utils/ufat/inc/cluster.hxx
new file mode 100644
index 000000000..3c9a82288
--- /dev/null
+++ b/private/utils/ufat/inc/cluster.hxx
@@ -0,0 +1,178 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ cluster.hxx
+
+Abstract:
+
+ This class models a chain of clusters in a FAT file system. It gives
+ the ability to refer to a scattered chain of clusters as one contiguous
+ region of memory. This memory will be acquired from a MEM object at
+ initialization.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 27-Nov-90
+
+--*/
+
+#if !defined(CLUSTER_CHAIN_DEFN)
+
+#define CLUSTER_CHAIN_DEFN
+
+
+#include "secrun.hxx"
+#include "hmem.hxx"
+
+#if defined ( _AUTOCHECK_ )
+#define UFAT_EXPORT
+#elif defined ( _UFAT_MEMBER_ )
+#define UFAT_EXPORT __declspec(dllexport)
+#else
+#define UFAT_EXPORT __declspec(dllimport)
+#endif
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( CLUSTER_CHAIN );
+DECLARE_CLASS( FAT );
+DECLARE_CLASS( FAT_SA );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( MEM );
+
+class CLUSTER_CHAIN : public OBJECT {
+
+ public:
+
+ UFAT_EXPORT
+ DECLARE_CONSTRUCTOR( CLUSTER_CHAIN );
+
+ VIRTUAL
+ UFAT_EXPORT
+ ~CLUSTER_CHAIN(
+ );
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ BOOLEAN
+ Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN PFAT_SA FatSuperArea,
+ IN PCFAT Fat,
+ IN USHORT ClusterNumber,
+ IN USHORT LengthOfChain DEFAULT 0
+ );
+
+ VIRTUAL
+ UFAT_EXPORT
+ BOOLEAN
+ Read(
+ );
+
+ VIRTUAL
+ UFAT_EXPORT
+ BOOLEAN
+ Write(
+ );
+
+ NONVIRTUAL
+ PVOID
+ GetBuf(
+ );
+
+ NONVIRTUAL
+ USHORT
+ QueryLength(
+ ) CONST;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ PSECRUN* _secruns;
+ USHORT _num_secruns;
+ USHORT _length_of_chain;
+
+ //
+ // Stuff needed for compressed volumes.
+ //
+
+ BOOLEAN _is_compressed;
+ PSECRUN _secrun;
+ PUCHAR _buf;
+ HMEM _hmem;
+ PFAT_SA _fat_sa;
+ PCFAT _fat;
+ PLOG_IO_DP_DRIVE
+ _drive;
+ USHORT _starting_cluster;
+};
+
+
+INLINE
+PVOID
+CLUSTER_CHAIN::GetBuf(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the beginning of the memory map for
+ the cluster chain.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the beginning of the memory map for the cluster chain.
+
+--*/
+{
+ if (_is_compressed) {
+ return _buf;
+ }
+ return (_secruns && _secruns[0]) ? _secruns[0]->GetBuf() : NULL;
+}
+
+
+INLINE
+USHORT
+CLUSTER_CHAIN::QueryLength(
+ ) CONST
+/*++
+
+Routine Description:
+
+ Computes the number of clusters in the cluster chain.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of clusters in the cluster chain.
+
+--*/
+{
+ return _length_of_chain;
+}
+
+
+#endif // CLUSTER_CHAIN_DEFN
diff --git a/private/utils/ufat/inc/cvf.hxx b/private/utils/ufat/inc/cvf.hxx
new file mode 100644
index 000000000..e105beff8
--- /dev/null
+++ b/private/utils/ufat/inc/cvf.hxx
@@ -0,0 +1,251 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ cvf.hxx
+
+Abstract:
+
+ This module contains basic declarations and definitions for
+ the double-space file system format. Note that more extensive
+ description of the file system structures may be found in
+ ntos\fastfat\cvf.h
+
+Author:
+
+ Bill McJohn [BillMc] 24-September-1993
+
+Revision History:
+
+
+
+--*/
+
+#if !defined( _UFATDB_DEFN_ )
+#define _UFATDB_DEFN_
+
+#include "bpb.hxx"
+
+// Manifest constants for fixed values on a Double Space drive:
+//
+CONST DoubleSpaceBytesPerSector = 512;
+CONST DoubleSpaceLog2BytesPerSector = 9;
+CONST DoubleSpaceSectorsPerCluster = 16;
+CONST DoubleSpaceLog2SectorsPerCluster = 4;
+CONST DoubleSpaceReservedSectors = 16;
+CONST DoubleSpaceFats = 1;
+CONST DoubleSpaceSectorsInRootDir = 32;
+CONST DoubleSpaceRootEntries = 512;
+CONST DoubleSpaceMediaByte = 0xf8;
+CONST DoubleSpaceSectorsPerTrack = 0x11;
+CONST DoubleSpaceHeads = 6;
+CONST DoubleSpaceHiddenSectors = 0;
+CONST DoubleSpaceReservedSectors2 = 31;
+CONST DSBytesPerBitmapPage = 2048;
+CONST DSSectorsPerBitmapPage = 4;
+
+CONST ULONG EIGHT_MEG = 8 * 1024L * 1024L;
+
+CONST DbSignatureLength = 4;
+CONST UCHAR FirstDbSignature[DbSignatureLength] = { (UCHAR)0xf8, 'D', 'R', 0 };
+CONST UCHAR SecondDbSignature[DbSignatureLength] = "MDR";
+
+INLINE
+ULONG
+ComputeMaximumCapacity(
+ IN ULONG HostDriveSize
+ )
+/*++
+
+Routine Description:
+
+ This function computes the maximum capacity for a compressed
+ volume file on a host volume of a given size.
+
+Arguments:
+
+ HostDriveSize -- Supplies the size in bytes of the host drive.
+
+Return Value:
+
+ The appropriate Maximum Capacity.
+
+--*/
+{
+ ULONG MaxCap;
+
+ if( HostDriveSize < 20 * 1024L * 1024L ) {
+
+ MaxCap = 16 * HostDriveSize;
+
+ } else if ( HostDriveSize < 64 * 1024L * 1024L ) {
+
+ MaxCap = 8 * HostDriveSize;
+
+ } else {
+
+ MaxCap = 4 * HostDriveSize;
+ }
+
+ if( MaxCap < 4 * 1024L * 1024L ) {
+
+ MaxCap = 4 * 1024L * 1024L;
+
+ } else if( MaxCap > 512 * 1024L * 1024L ) {
+
+ MaxCap = 512 * 1024L * 1024L;
+ }
+
+ return MaxCap;
+}
+
+typedef struct _PACKED_CVF_HEADER {
+
+ //
+ // First a typical start of a boot sector
+ //
+
+ UCHAR Jump[1]; // offset = 0x000 0
+ UCHAR JmpOffset[2];
+ UCHAR Oem[8]; // offset = 0x003 3
+ PACKED_BIOS_PARAMETER_BLOCK PackedBpb; // offset = 0x00B 11
+
+ //
+ // Now the DblSpace extensions
+ //
+
+ UCHAR CvfFatExtensionsLbnMinus1[2]; // offset = 0x024 36
+ UCHAR LogOfBytesPerSector[1]; // offset = 0x026 38
+ UCHAR DosBootSectorLbn[2]; // offset = 0x027 39
+ UCHAR DosRootDirectoryOffset[2]; // offset = 0x029 41
+ UCHAR CvfHeapOffset[2]; // offset = 0x02B 43
+ UCHAR CvfFatFirstDataEntry[2]; // offset = 0x02D 45
+ UCHAR CvfBitmap2KSize[1]; // offset = 0x02F 47
+ UCHAR Reserved1[2]; // offset = 0x030 48
+ UCHAR LogOfSectorsPerCluster[1]; // offset = 0x032 50
+ UCHAR Reserved2[2]; // offset = 0x033
+ UCHAR MinFile[4]; // offset = 0x035
+ UCHAR Reserved3[4]; // offset = 0x039
+ UCHAR Is12BitFat[1]; // offset = 0x03D 61
+ UCHAR CvfMaximumCapacity[2]; // offset = 0x03E 62
+ UCHAR StartBootCode;
+
+} PACKED_CVF_HEADER; // sizeof = 0x040 64
+typedef PACKED_CVF_HEADER *PPACKED_CVF_HEADER;
+
+//
+// For the unpacked version we'll only define the necessary field and skip
+// the jump and oem fields.
+//
+
+typedef struct _CVF_HEADER {
+
+ UCHAR Jump;
+ USHORT JmpOffset;
+
+ UCHAR Oem[8];
+ BIOS_PARAMETER_BLOCK Bpb;
+
+ USHORT CvfFatExtensionsLbnMinus1;
+ UCHAR LogOfBytesPerSector;
+ USHORT DosBootSectorLbn;
+ USHORT DosRootDirectoryOffset;
+ USHORT CvfHeapOffset;
+ USHORT CvfFatFirstDataEntry;
+ UCHAR CvfBitmap2KSize;
+ UCHAR LogOfSectorsPerCluster;
+ UCHAR Is12BitFat;
+ ULONG MinFile;
+ USHORT CvfMaximumCapacity;
+
+} CVF_HEADER;
+typedef CVF_HEADER *PCVF_HEADER;
+
+//
+// Here is NT's typical routine/macro to unpack the cvf header because DOS
+// doesn't bother to naturally align anything.
+//
+// VOID
+// CvfUnpackCvfHeader (
+// IN OUT PCVF_HEADER UnpackedHeader,
+// IN PPACKED_CVF_HEADER PackedHeader
+// );
+//
+
+#define CvfUnpackCvfHeader(UH,PH) { \
+ \
+ memcpy( &(UH)->Jump, &(PH)->Jump, 1 ); \
+ memcpy( &(UH)->JmpOffset, &(PH)->JmpOffset, 2 ); \
+ memcpy( &(UH)->Oem, &(PH)->Oem, 8 ); \
+ UnpackBios( &(UH)->Bpb, &(PH)->PackedBpb ); \
+ CopyUchar2( &(UH)->CvfFatExtensionsLbnMinus1, &(PH)->CvfFatExtensionsLbnMinus1[0] ); \
+ CopyUchar1( &(UH)->LogOfBytesPerSector, &(PH)->LogOfBytesPerSector[0] ); \
+ CopyUchar2( &(UH)->DosBootSectorLbn, &(PH)->DosBootSectorLbn[0] ); \
+ CopyUchar2( &(UH)->DosRootDirectoryOffset, &(PH)->DosRootDirectoryOffset[0] ); \
+ CopyUchar2( &(UH)->CvfHeapOffset, &(PH)->CvfHeapOffset[0] ); \
+ CopyUchar2( &(UH)->CvfFatFirstDataEntry, &(PH)->CvfFatFirstDataEntry[0] ); \
+ CopyUchar1( &(UH)->CvfBitmap2KSize, &(PH)->CvfBitmap2KSize[0] ); \
+ CopyUchar1( &(UH)->LogOfSectorsPerCluster, &(PH)->LogOfSectorsPerCluster[0] ); \
+ CopyUchar1( &(UH)->Is12BitFat, &(PH)->Is12BitFat[0] ); \
+ CopyUchar4( &(UH)->MinFile, &(PH)->MinFile[0] ); \
+ CopyUchar2( &(UH)->CvfMaximumCapacity, &(PH)->CvfMaximumCapacity[0] ); \
+}
+
+
+#define CvfPackCvfHeader(PH,UH) { \
+ \
+ memcpy( &(PH)->Jump, &(UH)->Jump, 1 ); \
+ memcpy( &(PH)->JmpOffset, &(UH)->JmpOffset, 2 ); \
+ memcpy( &(PH)->Oem, &(UH)->Oem, 8 ); \
+ PackBios( &(UH)->Bpb, &(PH)->PackedBpb, ); \
+ CopyUchar2( (PH)->CvfFatExtensionsLbnMinus1, &(UH)->CvfFatExtensionsLbnMinus1 ); \
+ CopyUchar1( (PH)->LogOfBytesPerSector, &(UH)->LogOfBytesPerSector ); \
+ CopyUchar2( (PH)->DosBootSectorLbn, &(UH)->DosBootSectorLbn ); \
+ CopyUchar2( (PH)->DosRootDirectoryOffset, &(UH)->DosRootDirectoryOffset ); \
+ CopyUchar2( (PH)->CvfHeapOffset, &(UH)->CvfHeapOffset ); \
+ CopyUchar2( (PH)->CvfFatFirstDataEntry, &(UH)->CvfFatFirstDataEntry ); \
+ CopyUchar1( (PH)->CvfBitmap2KSize, &(UH)->CvfBitmap2KSize ); \
+ CopyUchar1( (PH)->LogOfSectorsPerCluster, &(UH)->LogOfSectorsPerCluster ); \
+ CopyUchar1( (PH)->Is12BitFat, &(UH)->Is12BitFat ); \
+ CopyUchar4( (PH)->MinFile, &(UH)->MinFile ); \
+ CopyUchar2( (PH)->CvfMaximumCapacity, &(UH)->CvfMaximumCapacity ); \
+ memset( (PH)->Reserved1, 0, 2 ); \
+ memset( (PH)->Reserved2, 0, 2 ); \
+ memset( (PH)->Reserved3, 0, 4 ); \
+}
+
+
+//
+// The CVF FAT EXTENSIONS is a table is ULONG entries. Each entry corresponds
+// to a FAT cluster. The entries describe where in the CVF_HEAP to locate
+// the data for the cluster. It indicates if the data is compressed and the
+// length of the compressed and uncompressed form.
+//
+
+typedef struct _CVF_FAT_EXTENSIONS {
+
+ ULONG CvfHeapLbnMinus1 : 21;
+ ULONG Reserved : 1;
+ ULONG CompressedSectorLengthMinus1 : 4;
+ ULONG UncompressedSectorLengthMinus1 : 4;
+ ULONG IsDataUncompressed : 1;
+ ULONG IsEntryInUse : 1;
+
+} CVF_FAT_EXTENSIONS;
+typedef CVF_FAT_EXTENSIONS *PCVF_FAT_EXTENSIONS;
+
+
+//
+// Some sizes are fixed so we'll declare them as manifest constants
+//
+#define CVF_MINIMUM_DISK_SIZE (512 * 1024L)
+#define CVF_FATFAILSAFE (1024L)
+#define CVF_MIN_HEAP_SECTORS (60)
+#define CVF_RESERVED_AREA_1_SECTOR_SIZE (1)
+#define CVF_RESERVED_AREA_2_SECTOR_SIZE (31)
+#define CVF_RESERVED_AREA_4_SECTOR_SIZE (2)
+
+
+#endif // _UFATDB_DEFN_
diff --git a/private/utils/ufat/inc/cvfexts.hxx b/private/utils/ufat/inc/cvfexts.hxx
new file mode 100644
index 000000000..7a7bcda9f
--- /dev/null
+++ b/private/utils/ufat/inc/cvfexts.hxx
@@ -0,0 +1,294 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ cvfexts.hxx
+
+Abstract:
+
+ A class to manage the CVF_FAT_EXTENSIONS (otherwise known as
+ the MDFAT) part of the doublespace volume.
+
+Author:
+
+ Matthew Bradburn (mattbr) 27-Sep-93
+
+--*/
+
+#ifndef CVF_EXTS_DEFN
+#define CVF_EXTS_DEFN
+
+//
+// secStart : 21 starting sector number, minus 1
+// Reserved : 1 unused
+// csecCoded : 4 number of compressed sectors required, minus 1
+// csecPlain : 4 number of uncompressed sectors required, minus 1
+// fUncoded : 1 0: data stored compressed 1: data uncompressed
+// fUsed : 1 0: mdfat entry not in use 1: mdfat entry in use
+//
+
+#define CFE_START_SHIFT 0
+#define CFE_START_MASK 0x001fffff
+
+#define CFE_RESVD_SHIFT 21
+#define CFE_RESVD_MASK 0x00200000
+
+#define CFE_CODED_SHIFT 22
+#define CFE_CODED_MASK 0x03c00000
+
+#define CFE_PLAIN_SHIFT 26
+#define CFE_PLAIN_MASK 0x3c000000
+
+#define CFE_UNCODED_SHIFT 30
+#define CFE_UNCODED_MASK 0x40000000
+
+#define CFE_USED_SHIFT 31
+#define CFE_USED_MASK 0x80000000
+
+
+DECLARE_CLASS( CVF_FAT_EXTENS );
+
+class CVF_FAT_EXTENS : public SECRUN {
+ public:
+ DECLARE_CONSTRUCTOR(CVF_FAT_EXTENS);
+
+ NONVIRTUAL
+ ~CVF_FAT_EXTENS();
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN LBN StartSetor,
+ IN ULONG NumberOfEntries,
+ IN ULONG FirstEntry
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Create(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsClusterInUse(
+ IN ULONG Cluster
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetClusterInUse(
+ IN ULONG Cluster,
+ IN BOOLEAN fInUse
+ );
+
+ NONVIRTUAL
+ ULONG
+ QuerySectorFromCluster(
+ IN ULONG Cluster,
+ OUT PUCHAR NumSectors DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ VOID
+ SetSectorForCluster(
+ IN ULONG Cluster,
+ IN ULONG Sector,
+ IN UCHAR SectorCount
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsClusterCompressed(
+ IN ULONG Cluster
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetClusterCompressed(
+ IN ULONG Cluster,
+ IN BOOLEAN fCompressed
+ );
+
+ NONVIRTUAL
+ UCHAR
+ QuerySectorsRequiredForPlainData(
+ IN ULONG Cluster
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetSectorsRequiredForPlainData(
+ IN ULONG Cluster,
+ IN UCHAR SectorsRequired
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ PULONG _mdfat;
+ ULONG _num_entries;
+ ULONG _first_entry;
+};
+
+INLINE BOOLEAN
+CVF_FAT_EXTENS::IsClusterInUse(
+ IN ULONG Cluster
+ ) CONST
+{
+ ULONG CfeEntry = _mdfat[Cluster];
+
+ return BOOLEAN((CfeEntry & CFE_USED_MASK) >> CFE_USED_SHIFT);
+}
+
+INLINE VOID
+CVF_FAT_EXTENS::SetClusterInUse(
+ IN ULONG Cluster,
+ IN BOOLEAN fInUse
+ )
+{
+ ULONG CfeEntry = _mdfat[Cluster];
+
+ CfeEntry &= ~CFE_USED_MASK;
+ CfeEntry |= fInUse << CFE_USED_SHIFT;
+
+ _mdfat[Cluster] = CfeEntry;
+}
+
+INLINE ULONG
+CVF_FAT_EXTENS::QuerySectorFromCluster(
+ IN ULONG Cluster,
+ OUT PUCHAR NumSectors
+ )
+/*++
+
+Routine Description:
+
+ This routine takes a cluster number and uses the mdfat to return
+ the sector number in which the data starts. Also the number of
+ sectors used to store the cluster data is returned. Works for
+ compressed and uncompressed sectors as well, and for clusters
+ whether they're "In Use" or not. The number returned is the
+ value from the CVF_FAT_EXTENSIONS plus 1.
+
+Arguments:
+
+ Cluster - the cluster to get info for.
+
+Return Value:
+
+ ULONG - the CVF starting sector number.
+
+--*/
+{
+ ULONG CfeEntry = _mdfat[Cluster];
+
+ if (NULL != NumSectors) {
+ *NumSectors = (UCHAR)((CfeEntry & CFE_CODED_MASK) >> CFE_CODED_SHIFT) + 1;
+ }
+
+ return ((CfeEntry & CFE_START_MASK) >> CFE_START_SHIFT) + 1;
+}
+
+INLINE VOID
+CVF_FAT_EXTENS::SetSectorForCluster(
+ IN ULONG Cluster,
+ IN ULONG Sector,
+ IN UCHAR SectorCount
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the cluster->sector mapping, as well as
+ the number of sectors required to store the compressed cluster.
+
+Arguments:
+
+ Cluster - cluster number
+ Sector - starting CVF sector number
+ SectorCount - number of sectors required
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG CfeEntry = _mdfat[Cluster];
+
+ DbgAssert(Sector > 0);
+ DbgAssert(SectorCount > 0);
+
+ CfeEntry &= ~CFE_START_MASK;
+ CfeEntry |= (Sector - 1) << CFE_START_SHIFT;
+
+ CfeEntry &= ~CFE_CODED_MASK;
+ CfeEntry |= ((ULONG)(SectorCount - 1) << CFE_CODED_SHIFT);
+
+ _mdfat[Cluster] = CfeEntry;
+}
+
+INLINE UCHAR
+CVF_FAT_EXTENS::QuerySectorsRequiredForPlainData(
+ IN ULONG Cluster
+ ) CONST
+{
+ ULONG CfeEntry = _mdfat[Cluster];
+
+ return (UCHAR)((CfeEntry & CFE_PLAIN_MASK) >> CFE_PLAIN_SHIFT) + 1;
+}
+
+INLINE VOID
+CVF_FAT_EXTENS::SetSectorsRequiredForPlainData(
+ IN ULONG Cluster,
+ IN UCHAR SectorsRequired
+ )
+{
+ ULONG CfeEntry = _mdfat[Cluster];
+
+ DbgAssert(SectorsRequired > 0);
+
+ CfeEntry &= ~CFE_PLAIN_MASK;
+ CfeEntry |= (ULONG)(SectorsRequired - 1) << CFE_PLAIN_SHIFT;
+
+ _mdfat[Cluster] = CfeEntry;
+}
+
+INLINE BOOLEAN
+CVF_FAT_EXTENS::IsClusterCompressed(
+ IN ULONG Cluster
+ ) CONST
+{
+ ULONG CfeEntry = _mdfat[Cluster];
+
+ return ! ((CfeEntry & CFE_UNCODED_MASK) >> CFE_UNCODED_SHIFT);
+}
+
+INLINE VOID
+CVF_FAT_EXTENS::SetClusterCompressed(
+ IN ULONG Cluster,
+ IN BOOLEAN fCompressed
+ )
+{
+ ULONG CfeEntry = _mdfat[Cluster];
+
+ CfeEntry &= ~CFE_UNCODED_MASK;
+ CfeEntry |= (ULONG)!fCompressed << CFE_UNCODED_SHIFT;
+
+ _mdfat[Cluster] = CfeEntry;
+}
+
+#endif // CVF_EXTS_DEFN
diff --git a/private/utils/ufat/inc/dblentry.hxx b/private/utils/ufat/inc/dblentry.hxx
new file mode 100644
index 000000000..05f514bea
--- /dev/null
+++ b/private/utils/ufat/inc/dblentry.hxx
@@ -0,0 +1,68 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ufatdb.hxx
+
+Abstract:
+
+ This module contains prototypes for the Double Space utility
+ entry points.
+
+Author:
+
+ Bill McJohn [BillMc] 24-September-1993
+
+Revision History:
+
+--*/
+
+DECLARE_CLASS( WSTRING );
+DECLARE_CLASS( MESSAGE );
+
+extern "C"
+BOOLEAN
+FAR APIENTRY
+FatDbFormat(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Quick,
+ IN MEDIA_TYPE MediaType,
+ IN PCWSTRING LabelString,
+ IN ULONG ClusterSize
+ );
+
+extern "C"
+BOOLEAN
+FAR APIENTRY
+FatDbChkdsk(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Fix,
+ IN BOOLEAN Verbose,
+ IN BOOLEAN OnlyIfDirty,
+ IN BOOLEAN Recover,
+ IN PCWSTRING PathToCheck
+ );
+
+extern "C"
+BOOLEAN
+FAR APIENTRY
+FatDbCreate(
+ IN PCWSTRING HostDriveName,
+ IN PCWSTRING HostFileName,
+ IN ULONG Size,
+ IN OUT PMESSAGE Message,
+ IN PCWSTRING Label,
+ OUT PWSTRING CreatedName
+ );
+
+extern "C"
+BOOLEAN
+FAR APIENTRY
+FatDbDelete(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message
+ );
diff --git a/private/utils/ufat/inc/eaheader.hxx b/private/utils/ufat/inc/eaheader.hxx
new file mode 100644
index 000000000..1323f78dd
--- /dev/null
+++ b/private/utils/ufat/inc/eaheader.hxx
@@ -0,0 +1,229 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ eaheader.hxx
+
+Abstract:
+
+ This class models the header and tables of the EA file.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 28-Nov-90
+
+Notes:
+
+ Luckily all the structures are well aligned.
+
+--*/
+
+#if !defined(EA_HEADER_DEFN)
+
+#define EA_HEADER_DEFN
+
+#include "cluster.hxx"
+
+#if defined ( _AUTOCHECK_ )
+#define UFAT_EXPORT
+#elif defined ( _UFAT_MEMBER_ )
+#define UFAT_EXPORT __declspec(dllexport)
+#else
+#define UFAT_EXPORT __declspec(dllimport)
+#endif
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( EA_HEADER );
+DECLARE_CLASS( FAT );
+DECLARE_CLASS( FAT_SA );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( MEM );
+
+
+struct _EA_FILE_HEADER {
+ USHORT Signature;
+ USHORT FormatType;
+ USHORT LogType;
+ USHORT Cluster1;
+ USHORT NewCValue1;
+ USHORT Cluster2;
+ USHORT NewCValue2;
+ USHORT Cluster3;
+ USHORT NewCValue3;
+ USHORT Handle;
+ USHORT NewHOffset;
+ UCHAR Reserved[10];
+};
+
+DEFINE_TYPE( struct _EA_FILE_HEADER, EA_FILE_HEADER );
+
+CONST BaseTableSize = 240;
+
+struct _EA_MAP_TBL {
+ USHORT BaseTab[BaseTableSize];
+ USHORT OffTab[1];
+};
+
+DEFINE_TYPE( struct _EA_MAP_TBL, EA_MAP_TBL );
+
+struct _EA_HEADER_AND_TABLE {
+ EA_FILE_HEADER Header;
+ EA_MAP_TBL Table;
+};
+
+DEFINE_TYPE( struct _EA_HEADER_AND_TABLE, EA_HEADER_AND_TABLE );
+
+CONST USHORT HeaderSignature = 0x4445;
+CONST USHORT CurrentFormatType = 0;
+CONST USHORT CurrentLogType = 0;
+CONST USHORT Bit15 = 0x8000;
+CONST USHORT InvalidHandle = 0xFFFF;
+
+
+class EA_HEADER : public CLUSTER_CHAIN {
+
+ public:
+ UFAT_EXPORT
+ DECLARE_CONSTRUCTOR( EA_HEADER );
+
+ VIRTUAL
+ UFAT_EXPORT
+ ~EA_HEADER(
+ );
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ BOOLEAN
+ Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN PFAT_SA FatSuperArea,
+ IN PCFAT Fat,
+ IN USHORT StartingCluster,
+ IN USHORT LengthOfChain DEFAULT 0
+ );
+
+ NONVIRTUAL
+ PEA_FILE_HEADER
+ GetEaFileHeader(
+ );
+
+ NONVIRTUAL
+ PEA_MAP_TBL
+ GetMapTable(
+ );
+
+ NONVIRTUAL
+ LONG
+ QueryOffTabSize(
+ ) CONST;
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ USHORT
+ QueryEaSetClusterNumber(
+ IN USHORT Handle
+ ) CONST;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ PEA_HEADER_AND_TABLE _ht;
+ LONG _off_tab_size;
+
+};
+
+
+INLINE
+PEA_FILE_HEADER
+EA_HEADER::GetEaFileHeader(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the EA file header. Dereferencing
+ this pointer will allow the client to examine and modify the
+ EA file header. These changes will take effect on disk when the
+ client issues a 'Write' command.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the EA file header.
+
+--*/
+{
+ return _ht ? &_ht->Header : NULL;
+}
+
+
+INLINE
+PEA_MAP_TBL
+EA_HEADER::GetMapTable(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the EA mapping table. Dereferencing
+ this pointer will allow the client to examine and modify the
+ EA mapping table. These changes will take effect on disk when the
+ client issues a 'Write' command.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the EA mapping table.
+
+--*/
+{
+ return _ht ? &_ht->Table : NULL;
+}
+
+
+INLINE
+LONG
+EA_HEADER::QueryOffTabSize(
+ ) CONST
+/*++
+
+Routine Description:
+
+ Computes the number of entries in the offset table.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns the number of entries in the offset table.
+
+--*/
+{
+ return _off_tab_size;
+}
+
+
+#endif // EA_HEADER_DEFN
diff --git a/private/utils/ufat/inc/easet.hxx b/private/utils/ufat/inc/easet.hxx
new file mode 100644
index 000000000..93208f4ca
--- /dev/null
+++ b/private/utils/ufat/inc/easet.hxx
@@ -0,0 +1,243 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ easet.hxx
+
+Abstract:
+
+ This class models an EA set.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 28-Nov-90
+
+Notes:
+
+ There are minor alignment problems here.
+
+--*/
+
+#if !defined(EA_SET_DEFN)
+
+#define EA_SET_DEFN
+
+#include "cluster.hxx"
+
+#if defined ( _AUTOCHECK_ )
+#define UFAT_EXPORT
+#elif defined ( _UFAT_MEMBER_ )
+#define UFAT_EXPORT __declspec(dllexport)
+#else
+#define UFAT_EXPORT __declspec(dllimport)
+#endif
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( EA_SET );
+DECLARE_CLASS( FAT );
+DECLARE_CLASS( FAT_SA );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( MEM );
+
+
+struct _EA_HDR {
+ USHORT Signature;
+ USHORT OwnHandle;
+ ULONG NeedCount;
+ UCHAR OwnerFileName[14];
+ ULONG Reserved;
+ LONG TotalSize;
+};
+
+DEFINE_TYPE( struct _EA_HDR, EA_HDR );
+
+struct _PACKED_EA_HDR {
+ USHORT Signature;
+ USHORT OwnHandle;
+ ULONG NeedCount;
+ UCHAR OwnerFileName[14];
+ UCHAR Reserved[4];
+ UCHAR TotalSize[4];
+};
+
+DEFINE_TYPE( struct _PACKED_EA_HDR, PACKED_EA_HDR );
+
+const SizeOfEaHdr = 30; // sizeof returns 32.
+
+struct _EA {
+ UCHAR Flag;
+ UCHAR NameSize;
+ UCHAR ValueSize[2]; // Was USHORT.
+ CHAR Name[1];
+};
+
+DEFINE_TYPE( struct _EA, EA );
+
+CONST USHORT EaSetSignature = 0x4145;
+CONST UCHAR NeedFlag = 0x80;
+
+
+class EA_SET : public CLUSTER_CHAIN {
+
+ public:
+
+ UFAT_EXPORT
+ DECLARE_CONSTRUCTOR( EA_SET );
+
+ VIRTUAL
+ UFAT_EXPORT
+ ~EA_SET(
+ );
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ BOOLEAN
+ Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN PFAT_SA FatSuperArea,
+ IN PCFAT Fat,
+ IN USHORT ClusterNumber,
+ IN USHORT LengthOfChain DEFAULT 0
+ );
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ BOOLEAN
+ Read(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Write(
+ );
+
+ NONVIRTUAL
+ PEA_HDR
+ GetEaSetHeader(
+ );
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ PEA
+ GetEa(
+ IN ULONG Index,
+ OUT PLONG EaSize DEFAULT NULL,
+ OUT PBOOLEAN PossiblyMore DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ VerifySignature(
+ ) CONST;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PackEaHeader(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ UnPackEaHeader(
+ );
+
+ EA_HDR _eahdr;
+ LONG _size;
+ BOOLEAN _size_imposed;
+ PEA _current_ea;
+ ULONG _current_index;
+
+};
+
+INLINE
+BOOLEAN
+EA_SET::Write(
+ )
+/*++
+
+Routine Description:
+
+ This routine packs the ea header and then writes the cluster chain to disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ return PackEaHeader() && CLUSTER_CHAIN::Write();
+}
+
+
+INLINE
+PEA_HDR
+EA_SET::GetEaSetHeader(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the unpacked ea set header.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the unpacked ea set header.
+
+--*/
+{
+ return &_eahdr;
+}
+
+
+INLINE
+BOOLEAN
+EA_SET::VerifySignature(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine verifies the signature on the EA set.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - The signature is invalid.
+ TRUE - The signature is valid.
+
+--*/
+{
+ return _eahdr.Signature == EaSetSignature;
+}
+
+
+#endif // EA_SET_DEFN
diff --git a/private/utils/ufat/inc/fat.hxx b/private/utils/ufat/inc/fat.hxx
new file mode 100644
index 000000000..565adb837
--- /dev/null
+++ b/private/utils/ufat/inc/fat.hxx
@@ -0,0 +1,904 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ fat.hxx
+
+Abstract:
+
+ This class models a file allocation table. The composition is of
+ virtual functions because there are two different kinds of file
+ allocation tables. A user of this class will be able to manipulate
+ the FAT regardless of the implementation.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 6-Dec-90
+
+--*/
+
+#if !defined(FAT_DEFN)
+
+#define FAT_DEFN
+
+#include "secrun.hxx"
+
+#if defined ( _AUTOCHECK_ )
+#define UFAT_EXPORT
+#elif defined ( _UFAT_MEMBER_ )
+#define UFAT_EXPORT __declspec(dllexport)
+#else
+#define UFAT_EXPORT __declspec(dllimport)
+#endif
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( FAT );
+DECLARE_CLASS( BITVECTOR );
+
+CONST FirstDiskCluster = 2;
+CONST MaxNumClusForSmallFat = 4085;
+
+class FAT : public SECRUN {
+
+ public:
+
+ DECLARE_CONSTRUCTOR(FAT);
+
+ VIRTUAL
+ ~FAT(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN LBN StartSector,
+ IN USHORT NumberOfEntries,
+ IN USHORT NumSectors DEFAULT 0
+ );
+
+ NONVIRTUAL
+ USHORT
+ QueryEntry(
+ IN USHORT ClusterNumber
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetEntry(
+ IN USHORT ClusterNumber,
+ IN USHORT Value
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsInRange(
+ IN USHORT ClusterNumber
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsClusterFree(
+ IN USHORT ClusterNumber
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetClusterFree(
+ IN USHORT ClusterNumber
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsEndOfChain(
+ IN USHORT ClusterNumber
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetEndOfChain(
+ IN USHORT ClusterNumber
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsClusterBad(
+ IN USHORT ClusterNumber
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetClusterBad(
+ IN USHORT ClusterNumber
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsClusterReserved(
+ IN USHORT ClusterNumber
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetClusterReserved(
+ IN USHORT ClusterNumber
+ );
+
+ NONVIRTUAL
+ VOID
+ SetEarlyEntries(
+ IN UCHAR MediaByte
+ );
+
+ NONVIRTUAL
+ UCHAR
+ QueryMediaByte(
+ ) CONST;
+
+ NONVIRTUAL
+ USHORT
+ QueryFreeClusters(
+ ) CONST;
+
+ NONVIRTUAL
+ USHORT
+ QueryBadClusters(
+ ) CONST;
+
+ NONVIRTUAL
+ USHORT
+ QueryReservedClusters(
+ ) CONST;
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ USHORT
+ QueryAllocatedClusters(
+ ) CONST;
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ USHORT
+ QueryNthCluster(
+ IN USHORT StartingCluster,
+ IN USHORT Index
+ ) CONST;
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ USHORT
+ QueryLengthOfChain(
+ IN USHORT StartingCluster,
+ OUT PUSHORT LastCluster DEFAULT NULL
+ ) CONST;
+
+ NONVIRTUAL
+ USHORT
+ QueryLengthOfChain(
+ IN USHORT StartingCluster,
+ IN USHORT EndingCluster
+ ) CONST;
+
+ NONVIRTUAL
+ USHORT
+ QueryPrevious(
+ IN USHORT Cluster
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ Scrub(
+ OUT PBOOLEAN ChangesMade DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ VOID
+ ScrubChain(
+ IN USHORT StartingCluster,
+ OUT PBOOLEAN ChangesMade
+ );
+
+ NONVIRTUAL
+ VOID
+ ScrubChain(
+ IN USHORT StartingCluster,
+ OUT PBITVECTOR UsedClusters,
+ OUT PBOOLEAN ChangesMade,
+ OUT PBOOLEAN CrossLinkDetected,
+ OUT PUSHORT CrossLinkPreviousCluster
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsValidChain(
+ IN USHORT StartingCluster
+ ) CONST;
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ USHORT
+ AllocChain(
+ IN USHORT Length,
+ OUT PUSHORT LastCluster DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ USHORT
+ ReAllocChain(
+ IN USHORT StartOfChain,
+ IN USHORT NewLength,
+ OUT PUSHORT LastCluster DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ VOID
+ FreeChain(
+ IN USHORT StartOfChain
+ );
+
+ NONVIRTUAL
+ USHORT
+ RemoveChain(
+ IN USHORT PreceedingCluster,
+ IN USHORT LastCluster
+ );
+
+ NONVIRTUAL
+ VOID
+ InsertChain(
+ IN USHORT StartOfChain,
+ IN USHORT EndOfChain,
+ IN USHORT PreceedingCluster
+ );
+
+ NONVIRTUAL
+ USHORT
+ InsertChain(
+ IN USHORT StartOfChain,
+ IN USHORT Cluster
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ USHORT
+ Index(
+ IN USHORT ClusterNumber
+ ) CONST;
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ USHORT
+ Index12(
+ IN USHORT ClusterNumber
+ ) CONST;
+
+ NONVIRTUAL
+ USHORT
+ Index16(
+ IN USHORT ClusterNumber
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ Set(
+ IN USHORT ClusterNumber,
+ IN USHORT Value
+ );
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ VOID
+ Set12(
+ IN USHORT ClusterNumber,
+ IN USHORT Value
+ );
+
+ NONVIRTUAL
+ VOID
+ Set16(
+ IN USHORT ClusterNumber,
+ IN USHORT Value
+ );
+
+ PVOID _fat;
+ USHORT _num_entries;
+ BOOLEAN _is_big;
+ USHORT _low_end_of_chain; // 0xFFF8 or 0x0FF8
+ USHORT _end_of_chain; // 0xFFFF or 0x0FFF
+ USHORT _bad_cluster; // 0xFFF7 or 0x0FF7
+ USHORT _low_reserved; // 0xFFF0 or 0x0FF0
+ USHORT _high_reserved; // 0xFFF6 or 0x0FF6
+
+};
+
+
+INLINE
+BOOLEAN
+FAT::IsInRange(
+ IN USHORT ClusterNumber
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes whether or not ClusterNumber is a cluster on
+ the disk.
+
+Arguments:
+
+ ClusterNumber - Supplies the cluster to be checked.
+
+Return Value:
+
+ FALSE - The cluster is not on the disk.
+ TRUE - The cluster is on the disk.
+
+--*/
+{
+ return FirstDiskCluster <= ClusterNumber && ClusterNumber < _num_entries;
+}
+
+
+INLINE
+USHORT
+FAT::Index16(
+ IN USHORT ClusterNumber
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine indexes the FAT as 16 bit little endian entries.
+
+Arguments:
+
+ ClusterNumber - Supplies the FAT entry desired.
+
+Return Value:
+
+ The value of the FAT entry at ClusterNumber.
+
+--*/
+{
+ DebugAssert(IsInRange(ClusterNumber));
+
+ return ((PUSHORT) _fat)[ClusterNumber];
+}
+
+
+INLINE
+USHORT
+FAT::Index(
+ IN USHORT ClusterNumber
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine indexes the FAT as 16 bit or 12 bit little endian entries.
+
+Arguments:
+
+ ClusterNumber - Supplies the FAT entry desired.
+
+Return Value:
+
+ The value of the FAT entry at ClusterNumber.
+
+--*/
+{
+ return _is_big ? Index16(ClusterNumber) : Index12(ClusterNumber);
+}
+
+
+INLINE
+VOID
+FAT::Set16(
+ IN USHORT ClusterNumber,
+ IN USHORT Value
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the ClusterNumber'th 16 bit FAT entry to Value.
+
+Arguments:
+
+ ClusterNumber - Supplies the FAT entry to set.
+ Value - Supplies the value to set the FAT entry to.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DebugAssert(IsInRange(ClusterNumber));
+ ((PUSHORT) _fat)[ClusterNumber] = Value;
+}
+
+
+INLINE
+VOID
+FAT::Set(
+ IN USHORT ClusterNumber,
+ IN USHORT Value
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the ClusterNumber'th 12 bit or 16 bit FAT entry to Value.
+
+Arguments:
+
+ ClusterNumber - Supplies the FAT entry to set.
+ Value - Supplies the value to set the FAT entry to.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _is_big ? Set16(ClusterNumber, Value) : Set12(ClusterNumber, Value);
+}
+
+
+INLINE
+USHORT
+FAT::QueryEntry(
+ IN USHORT ClusterNumber
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the FAT value for ClusterNumber.
+
+Arguments:
+
+ ClusterNumber - Supplies an index into the FAT.
+
+Return Value:
+
+ The FAT table entry at offset ClusterNumber.
+
+--*/
+{
+ return Index(ClusterNumber);
+}
+
+
+INLINE
+VOID
+FAT::SetEntry(
+ IN USHORT ClusterNumber,
+ IN USHORT Value
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the FAT entry at ClusterNumber to Value.
+
+Arguments:
+
+ ClusterNumber - Supplies the position in the FAT to update.
+ Value - Supplies the new value for that position.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Set(ClusterNumber, Value);
+}
+
+
+INLINE
+BOOLEAN
+FAT::IsClusterFree(
+ IN USHORT ClusterNumber
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes whether of not ClusterNumber is a free cluster.
+
+Arguments:
+
+ ClusterNumber - Supplies the cluster to be checked.
+
+Return Value:
+
+ FALSE - The cluster is not free.
+ TRUE - The cluster is free.
+
+--*/
+{
+ return Index(ClusterNumber) == 0;
+}
+
+
+INLINE
+VOID
+FAT::SetClusterFree(
+ IN USHORT ClusterNumber
+ )
+/*++
+
+Routine Description:
+
+ This routine marks the cluster ClusterNumber as free on the FAT.
+
+Arguments:
+
+ ClusterNumber - Supplies the number of the cluster to mark free.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Set(ClusterNumber, 0);
+}
+
+
+INLINE
+BOOLEAN
+FAT::IsEndOfChain(
+ IN USHORT ClusterNumber
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes whether or not the cluster ClusterNumber is the
+ end of its cluster chain.
+
+Arguments:
+
+ ClusterNumber - Supplies the cluster to be checked.
+
+Return Value:
+
+ FALSE - The cluster is not the end of a chain.
+ TRUE - The cluster is the end of a chain.
+
+--*/
+{
+ return Index(ClusterNumber) >= _low_end_of_chain;
+}
+
+
+INLINE
+VOID
+FAT::SetEndOfChain(
+ IN USHORT ClusterNumber
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the cluster ClusterNumber to the end of its cluster
+ chain.
+
+Arguments:
+
+ ClusterNumber - Supplies the cluster to be set to end of chain.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Set(ClusterNumber, _end_of_chain);
+}
+
+
+INLINE
+BOOLEAN
+FAT::IsClusterBad(
+ IN USHORT ClusterNumber
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes whether or not cluster ClusterNumber is bad.
+
+Arguments:
+
+ ClusterNumber - Supplies the number of the cluster to be checked.
+
+Return Value:
+
+ FALSE - The cluster is good.
+ TRUE - The cluster is bad.
+
+--*/
+{
+ return Index(ClusterNumber) == _bad_cluster;
+}
+
+
+INLINE
+VOID
+FAT::SetClusterBad(
+ IN USHORT ClusterNumber
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the cluster ClusterNumber to bad on the FAT.
+
+Arguments:
+
+ ClusterNumber - Supplies the cluster number to mark bad.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Set(ClusterNumber, _bad_cluster);
+}
+
+
+INLINE
+BOOLEAN
+FAT::IsClusterReserved(
+ IN USHORT ClusterNumber
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes whether or not the cluster ClusterNumber is
+ a reserved cluster.
+
+Arguments:
+
+ ClusterNumber - Supplies the cluster to check.
+
+Return Value:
+
+ FALSE - The cluster is not reserved.
+ TRUE - The cluster is reserved.
+
+--*/
+{
+ return Index(ClusterNumber) >= _low_reserved &&
+ Index(ClusterNumber) <= _high_reserved;
+}
+
+
+INLINE
+VOID
+FAT::SetClusterReserved(
+ IN USHORT ClusterNumber
+ )
+/*++
+
+Routine Description:
+
+ This routine marks the cluster ClusterNumber as reserved in the FAT.
+
+Arguments:
+
+ ClusterNumber - Supplies the cluster to mark reserved.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Set(ClusterNumber, _low_reserved);
+}
+
+
+INLINE
+UCHAR
+FAT::QueryMediaByte(
+ ) CONST
+/*++
+
+Routine Description:
+
+ The media byte for the partition is stored in the first character of the
+ FAT. This routine will return its value provided that the two following
+ bytes are 0xFF.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The media byte for the partition.
+
+--*/
+{
+ PUCHAR p;
+
+ p = (PUCHAR) _fat;
+
+ DebugAssert(p);
+
+ return (p[2] == 0xFF && p[1] == 0xFF &&
+ (_is_big ? p[3] == 0xFF : TRUE)) ? p[0] : 0;
+}
+
+
+INLINE
+VOID
+FAT::SetEarlyEntries(
+ IN UCHAR MediaByte
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the first two FAT entries as required by the
+ FAT file system. The first byte gets set to the media descriptor.
+ The remaining bytes gets set to FF.
+
+Arguments:
+
+ MediaByte - Supplies the media byte for the volume.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PUCHAR p;
+
+ p = (PUCHAR) _fat;
+
+ DebugAssert(p);
+
+ p[0] = MediaByte;
+ p[1] = p[2] = 0xFF;
+
+ if (_is_big) {
+ p[3] = 0xFF;
+ }
+}
+
+
+INLINE
+USHORT
+FAT::RemoveChain(
+ IN USHORT PreceedingCluster,
+ IN USHORT LastCluster
+ )
+/*++
+
+Routine Description:
+
+ This routine removes a subchain of length 'Length' from a containing
+ chain. This routine cannot remove subchains beginning at the head
+ of the containing chain. To do this use the routine named
+ 'SplitChain'.
+
+ This routine returns the number of the first cluster of the
+ removed subchain. The FAT is edited so that the removed subchain
+ is promoted to a full chain.
+
+Arguments:
+
+ PreceedingCluster - Supplies the cluster which preceeds the one to be
+ removed in the chain.
+ LastCluster - Supplies the last cluster of the chain to remove.
+
+Return Value:
+
+ The cluster number for the head of the chain removed.
+
+--*/
+{
+ USHORT r;
+
+ r = QueryEntry(PreceedingCluster);
+ SetEntry(PreceedingCluster, QueryEntry(LastCluster));
+ SetEndOfChain(LastCluster);
+ return r;
+}
+
+
+INLINE
+VOID
+FAT::InsertChain(
+ IN USHORT StartOfChain,
+ IN USHORT EndOfChain,
+ IN USHORT PreceedingCluster
+ )
+/*++
+
+Routine Description:
+
+ This routine inserts one chain into another chain. This routine
+ cannot insert a chain at the head of another chain. To do this
+ use the routine named 'JoinChains'.
+
+Arguments:
+
+ StartOfChain - Supplies the first cluster of the chain to insert.
+ EndOfChain - Supplies the last cluster of the chain to insert.
+ PreceedingCluster - Supplies the cluster immediately preceeding the
+ position where the chain is to be inserted.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ SetEntry(EndOfChain, QueryEntry(PreceedingCluster));
+ SetEntry(PreceedingCluster, StartOfChain);
+}
+
+
+INLINE
+USHORT
+FAT::InsertChain(
+ IN USHORT StartOfChain,
+ IN USHORT Cluster
+ )
+/*++
+
+Routine Description:
+
+ This routine inserts one cluster at the head of a chain.
+
+Arguments:
+
+ StartOfChain - Supplies the first cluster of the chain to insert.
+ Cluster - Supplies the cluster to be inserted
+
+Return Value:
+
+ USHORT - The new head of the chain (i.e. Cluster )
+
+--*/
+{
+ if ( StartOfChain ) {
+ SetEntry( Cluster, StartOfChain );
+ } else {
+ SetEndOfChain( Cluster );
+ }
+
+ return Cluster;
+}
+
+
+#endif // FAT_DEFN
diff --git a/private/utils/ufat/inc/fatdbsa.hxx b/private/utils/ufat/inc/fatdbsa.hxx
new file mode 100644
index 000000000..1465ec739
--- /dev/null
+++ b/private/utils/ufat/inc/fatdbsa.hxx
@@ -0,0 +1,789 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ fatsa.hxx
+
+Abstract:
+
+Author:
+
+ Matthew Bradburn (mattbr) 27-Sep-93
+
+--*/
+
+#if !defined(FATDB_SA_DEFN)
+#define FATDB_SA_DEFN
+
+//
+// Forward references
+//
+
+#include "fatsa.hxx"
+#include "cvfexts.hxx"
+#include "cvf.hxx"
+#include "bitvect.hxx"
+
+// the text for the oem data field
+#define OEMDBTEXT "MSDSP6.0"
+
+DECLARE_CLASS( ARRAY );
+DECLARE_CLASS( BITVECTOR );
+DECLARE_CLASS( FAT );
+DECLARE_CLASS( FAT_SA );
+DECLARE_CLASS( FATDIR );
+DECLARE_CLASS( FAT_DIRENT );
+DECLARE_CLASS( CVF_FAT_EXTENS );
+DECLARE_CLASS( MESSAGE );
+DECLARE_CLASS( ROOTDIR );
+DECLARE_CLASS( SORTED_LIST );
+DECLARE_CLASS( TIMEINFO );
+DECLARE_CLASS( WSTRING );
+DECLARE_CLASS( FATDB_SA );
+
+class FATDB_SA : public FAT_SA {
+
+ public:
+
+ DECLARE_CONSTRUCTOR(FATDB_SA);
+
+ VIRTUAL
+ ~FATDB_SA(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Formatted DEFAULT TRUE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Create(
+ IN PCNUMBER_SET BadSectors,
+ IN OUT PMESSAGE Message,
+ IN PCWSTRING Label DEFAULT NULL,
+ IN ULONG ClusterSize DEFAULT 0,
+ IN ULONG VirtualSize DEFAULT 0
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Read(
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Write(
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ PCVF_FAT_EXTENS
+ GetFatExtensions(
+ );
+
+ NONVIRTUAL
+ USHORT
+ QuerySectorsPerCluster(
+ ) CONST;
+
+ NONVIRTUAL
+ USHORT
+ QuerySectorsPerFat(
+ ) CONST;
+
+ NONVIRTUAL
+ USHORT
+ QueryFats(
+ ) CONST;
+
+ NONVIRTUAL
+ PARTITION_SYSTEM_ID
+ QuerySystemId(
+ ) CONST;
+
+ NONVIRTUAL
+ LBN
+ QueryStartDataLbn(
+ ) CONST;
+
+ NONVIRTUAL
+ USHORT
+ QueryClusterCount(
+ ) CONST;
+
+ NONVIRTUAL
+ SECTORCOUNT
+ QueryFreeSectors(
+ ) CONST;
+
+ NONVIRTUAL
+ FATTYPE
+ QueryFatType(
+ ) CONST;
+
+ NONVIRTUAL
+ BYTE
+ QueryVolumeFlags(
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetVolumeFlags(
+ BYTE Flags,
+ BOOLEAN ResetFlags
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryCensusAndRelocate (
+ OUT PCENSUS_REPORT CensusReport DEFAULT NULL,
+ IN OUT PINTSTACK RelocationStack DEFAULT NULL,
+ OUT PBOOLEAN Relocated DEFAULT NULL
+ );
+
+ STATIC
+ USHORT
+ ComputeSecClus(
+ IN SECTORCOUNT Sectors,
+ IN FATTYPE FatType,
+ IN MEDIA_TYPE MediaType
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsCompressed(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ ReadSectorZero(
+ );
+
+ NONVIRTUAL
+ ULONG
+ QuerySectorFromCluster(
+ IN ULONG Cluster,
+ OUT PUCHAR NumSectors DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsClusterCompressed(
+ IN ULONG Cluster
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetClusterCompressed(
+ IN ULONG Cluster,
+ IN BOOLEAN fCompressed
+ );
+
+ NONVIRTUAL
+ UCHAR
+ QuerySectorsRequiredForPlainData(
+ IN ULONG Cluster
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ VerifyFatExtensions(
+ IN FIX_LEVEL Fixlevel,
+ IN PMESSAGE Message,
+ IN OUT PBOOLEAN pfNeedMsg
+ );
+
+ //
+ // Routines related to the sector heap bitmap.
+ //
+
+ NONVIRTUAL
+ BOOLEAN
+ CheckSectorHeapAllocation(
+ IN FIX_LEVEL Fixlevel,
+ IN PMESSAGE Message,
+ IN OUT PBOOLEAN pfNeedMsg
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FreeClusterData(
+ ULONG Cluster
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AllocateClusterData(
+ ULONG Cluster,
+ UCHAR NumSectors,
+ BOOLEAN bCompressed,
+ UCHAR PlainSize
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetCvfSectorCount(
+ IN ULONG SectorCount
+ );
+
+ private:
+
+ HMEM _mem; // memory for SECRUN
+ USHORT _ClusterCount; // number of clusters in Super Area
+ PARTITION_SYSTEM_ID _sysid; // system id
+ ULONG _sec_per_boot; // sectors for boot code.
+
+ CVF_HEADER _cvf_header; // BPB + dblspace stuff
+ PCVF_FAT_EXTENS _cvf_extens; // fat extensions (mdfat)
+ EXTENDED_BIOS_PARAMETER_BLOCK
+ _dos_exbpb;
+
+ //
+ // This pointer tells us where the packed extended bpb
+ // resides in the secrun.
+ //
+
+ PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK
+ _pexbpb;
+
+ // _fat is inherited from FAT_SA
+ // _dir is inherited from FAT_SA
+
+ LBN _StartDataLbn; // LBN of files, or data area
+ PUCHAR _sector_sig; // sector signature, _cvf_header
+ PUCHAR _sector_sig2; // same but for _dos_exbpb
+
+ BITVECTOR _sector_heap_bitmap;
+ BOOLEAN _sector_heap_init;
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetBpb(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetExtendedBpb(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DupFats(
+ );
+
+ NONVIRTUAL
+ USHORT
+ ComputeRootEntries(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ SecPerBoot(
+ );
+
+ NONVIRTUAL
+ VOLID
+ QueryVolId(
+ ) CONST;
+
+ NONVIRTUAL
+ VOLID
+ SetVolId(
+ IN VOLID VolId
+ );
+
+ NONVIRTUAL
+ UCHAR
+ QueryMediaByte(
+ ) CONST;
+
+ VIRTUAL
+ VOID
+ SetMediaByte(
+ UCHAR MediaByte
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ VerifyBootSector(
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryVirtualSectors(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ CreateBootSector(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetOemData(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetSignature(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetBootSignature(
+ IN UCHAR Signature DEFAULT sigBOOTSTRAP
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetBootCode(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DosSaInit(
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN SECTORCOUNT NumberOfSectors,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetPhysicalDriveType(
+ IN PHYSTYPE PhysType
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ RecoverChain(
+ IN OUT PUSHORT StartingCluster,
+ OUT PBOOLEAN ChangesMade,
+ IN USHORT EndingCluster DEFAULT 0,
+ IN BOOLEAN Replace DEFAULT FALSE
+ );
+};
+
+INLINE
+USHORT
+FATDB_SA::QuerySectorsPerCluster(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of sectors per cluster for
+ the volume.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of sectors per cluster for the volume.
+
+--*/
+{
+ return _cvf_header.Bpb.SectorsPerCluster ?
+ _cvf_header.Bpb.SectorsPerCluster : 256;
+}
+
+
+INLINE
+USHORT
+FATDB_SA::QuerySectorsPerFat(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of sectors per FAT for the volume.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of sectors per FAT for the volume.
+
+--*/
+{
+ return _cvf_header.Bpb.SectorsPerFat;
+}
+
+
+INLINE
+USHORT
+FATDB_SA::QueryFats(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of FATs on the volume.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Doublespace drives always have just a single FAT.
+
+--*/
+{
+ return 1;
+}
+
+
+INLINE
+PARTITION_SYSTEM_ID
+FATDB_SA::QuerySystemId(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the system ID for the volume.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The system ID for the volume.
+
+--*/
+{
+ return _sysid;
+}
+
+
+INLINE
+LBN
+FATDB_SA::QueryStartDataLbn(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the LBN of the first logical cluster of the
+ volume.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The LBN of the first logical cluster of the volume.
+
+--*/
+{
+ return _StartDataLbn;
+}
+
+
+INLINE
+USHORT
+FATDB_SA::QueryClusterCount(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the total number of clusters for the volume.
+ That is to say that the largest addressable cluster on the disk
+ is cluster number 'QueryClusterCount() - 1'. Note that the
+ smallest addressable cluster on the disk is 2.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The total number of clusters for the volume.
+
+--*/
+{
+ return _ClusterCount;
+}
+
+INLINE
+BOOLEAN
+FATDB_SA::IsCompressed(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine always returns TRUE for DblSpace volumes. Comparable
+ classes for non-dblspace volumes will return FALSE.
+
+Arguments:
+
+Return Value:
+
+ TRUE - Compressed.
+ FALSE - Not compressed.
+
+--*/
+{
+ return TRUE;
+}
+
+INLINE
+BOOLEAN
+FATDB_SA::ReadSectorZero(
+ )
+/*++
+
+Routine Description:
+
+ This routine used to be DOS_SUPERAREA::Read().
+
+Arguments:
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure.
+
+--*/
+{
+ BOOLEAN f;
+ PPACKED_CVF_HEADER ph;
+
+ f = SECRUN::Read();
+ if (!f)
+ return f;
+
+ ph = (PPACKED_CVF_HEADER)SECRUN::GetBuf();
+
+ CvfUnpackCvfHeader(&_cvf_header, ph);
+ return TRUE;
+}
+
+INLINE
+UCHAR
+FATDB_SA::QueryMediaByte(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine fetches the media byte from the super area's data.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The media byte residing in the super area.
+
+--*/
+{
+ return _cvf_header.Bpb.Media;
+}
+
+INLINE
+VOID
+FATDB_SA::SetMediaByte(
+ UCHAR MediaByte
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the media byte in the super area's data.
+
+Arguments:
+
+ MediaByte -- Supplies the new media byte.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _cvf_header.Bpb.Media = MediaByte;
+}
+
+INLINE
+SECTORCOUNT
+FATDB_SA::QueryVirtualSectors(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of sectors on the volume according
+ to the file system.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of sectors on the volume according to the file system.
+
+--*/
+{
+ return _cvf_header.Bpb.LargeSectors;
+}
+
+INLINE
+VOLID
+FATDB_SA::QueryVolId(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine fetches the volume ID from the super area's data.
+ This routine will return 0 if volume serial numbers are not
+ supported by the partition.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The volume ID residing in the super area.
+
+--*/
+{
+ return (_dos_exbpb.Signature == 0x28 || _dos_exbpb.Signature == 0x29)
+ ? _dos_exbpb.SerialNumber : 0;
+}
+
+INLINE
+VOLID
+FATDB_SA::SetVolId(
+ IN VOLID VolId
+ )
+/*++
+
+Routine Description:
+
+ This routine does nothing; volume serial numbers are not supported
+ by FATDB.
+
+Arguments:
+
+ VolId - The new volume ID.
+
+Return Value:
+
+ The VolId.
+
+--*/
+{
+ return _dos_exbpb.SerialNumber = VolId;
+}
+
+INLINE
+BOOLEAN
+FATDB_SA::SetBootSignature(
+ IN UCHAR Signature
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the boot signature in the dos boot sector.
+
+Arguments:
+
+ Signature -- supplies the character to set the signature to.
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure.
+
+--*/
+{
+ _dos_exbpb.Signature = Signature;
+ return TRUE;
+}
+
+INLINE
+BYTE
+FATDB_SA::QueryVolumeFlags(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the volume flags byte from the bpb.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The flags.
+
+--*/
+{
+ return _cvf_header.Bpb.CurrentHead;
+}
+
+INLINE
+VOID
+FATDB_SA::SetVolumeFlags(
+ BYTE Flags,
+ BOOLEAN ResetFlags
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the volume flags in the bpb.
+
+Arguments:
+
+ Flags -- flags to set
+ ResetFlags -- if true, Flags are cleared instead of set
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if (ResetFlags) {
+ _cvf_header.Bpb.CurrentHead &= ~Flags;
+ } else {
+ _cvf_header.Bpb.CurrentHead |= Flags;
+ }
+}
+
+#endif // FATDB_SA_DEFN
diff --git a/private/utils/ufat/inc/fatdbvol.hxx b/private/utils/ufat/inc/fatdbvol.hxx
new file mode 100644
index 000000000..7eb7632d4
--- /dev/null
+++ b/private/utils/ufat/inc/fatdbvol.hxx
@@ -0,0 +1,97 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ dbvol.hxx
+
+Abstract:
+
+ This class implements Double Space only VOLUME items.
+
+Author:
+
+ Bill McJohn (billmc) 23-September 1993
+
+--*/
+
+#if !defined(_FATDB_VOL_DEFN_)
+
+#define _FATDB_VOL_DEFN_
+
+#include "volume.hxx"
+#include "fatdbsa.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( FATDB_VOL );
+DECLARE_CLASS( MESSAGE );
+
+
+class FATDB_VOL : public VOL_LIODPDRV {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( FATDB_VOL );
+
+ VIRTUAL
+ ~FATDB_VOL(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PCWSTRING NtDriveName,
+ IN PCWSTRING HostFileName,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN BOOLEAN ExclusiveWrite DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsFileContiguous(
+ IN PCWSTRING FullPathFileName,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ OUT PULONG NumBlocks DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ContiguityReport(
+ IN PCWSTRING DirectoryPath,
+ IN PCDSTRING FilesToCheck,
+ IN ULONG NumberOfFiles,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ PVOL_LIODPDRV
+ QueryDupVolume(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN BOOLEAN ExclusiveWrite DEFAULT FALSE,
+ IN BOOLEAN FormatMedia DEFAULT FALSE,
+ IN MEDIA_TYPE MediaType DEFAULT Unknown
+ ) CONST;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ FATDB_SA _fatdbsa;
+
+};
+
+
+#endif // _FATDB_VOL_DEFN_
diff --git a/private/utils/ufat/inc/fatdent.hxx b/private/utils/ufat/inc/fatdent.hxx
new file mode 100644
index 000000000..5364c5b00
--- /dev/null
+++ b/private/utils/ufat/inc/fatdent.hxx
@@ -0,0 +1,1052 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ fatdent.hxx
+
+Abstract:
+
+ This class models a FAT directory entry.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 4-Dec-90
+
+--*/
+
+#if !defined(FAT_DIRENT_DEFN)
+
+#define FAT_DIRENT_DEFN
+
+#if defined ( _AUTOCHECK_ )
+#define UFAT_EXPORT
+#elif defined ( _UFAT_MEMBER_ )
+#define UFAT_EXPORT __declspec(dllexport)
+#else
+#define UFAT_EXPORT __declspec(dllimport)
+#endif
+
+DECLARE_CLASS( FAT_DIRENT );
+DECLARE_CLASS( WSTRING );
+DECLARE_CLASS( WSTRING );
+DECLARE_CLASS( TIMEINFO );
+
+typedef struct _SHORT_FAT_DIRENT {
+
+ UCHAR Name[11];
+ UCHAR Attributes[1];
+ UCHAR NtByte[1];
+ UCHAR CreationMSec[1]; // actually count of 10msec's
+ UCHAR CreationTime[2]; // two-second resolution
+ UCHAR CreationDate[2];
+ UCHAR LastAccessDate[2];
+ UCHAR EaHandle[2];
+ UCHAR LastWriteTime[2];
+ UCHAR LastWriteDate[2];
+ UCHAR FirstCluster[2];
+ UCHAR Size[4];
+};
+
+DEFINE_TYPE( _SHORT_FAT_DIRENT, SHORT_FAT_DIRENT );
+
+typedef struct _LONG_FAT_DIRENT {
+
+ UCHAR Ordinal[1];
+ UCHAR Name1[10];
+ UCHAR Attribute[1];
+ UCHAR Type[1];
+ UCHAR Checksum[1];
+ UCHAR Name2[12];
+ UCHAR FirstCluster[2];
+ UCHAR Name3[4];
+};
+
+DEFINE_TYPE( _LONG_FAT_DIRENT, LONG_FAT_DIRENT );
+
+#define LONG_DIRENT_TYPE_NAME 0
+#define LONG_DIRENT_TYPE_CLASS 1
+
+class FAT_DIRENT : public OBJECT {
+
+ public:
+
+ UFAT_EXPORT
+ DECLARE_CONSTRUCTOR( FAT_DIRENT );
+
+ VIRTUAL
+ UFAT_EXPORT
+ ~FAT_DIRENT(
+ );
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ BOOLEAN
+ Initialize(
+ IN OUT PVOID Dirent
+ );
+
+ NONVIRTUAL
+ VOID
+ Clear(
+ );
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ VOID
+ QueryName(
+ OUT PWSTRING Name
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ SetName(
+ IN PCWSTRING Name
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsValidName(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsDot(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsDotDot(
+ ) CONST;
+
+ NONVIRTUAL
+ BYTE
+ QueryAttributeByte(
+ ) CONST;
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ BOOLEAN
+ IsValidLastWriteTime(
+ ) CONST;
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ BOOLEAN
+ QueryLastWriteTime(
+ OUT LARGE_INTEGER *TimeStamp
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ SetLastWriteTime(
+ );
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ BOOLEAN
+ IsValidCreationTime(
+ ) CONST;
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ BOOLEAN
+ QueryCreationTime(
+ OUT LARGE_INTEGER *TimeStamp
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ SetCreationTime(
+ );
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ BOOLEAN
+ IsValidLastAccessTime(
+ ) CONST;
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ BOOLEAN
+ QueryLastAccessTime(
+ OUT LARGE_INTEGER *TimeStamp
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ SetLastAccessTime(
+ );
+
+ NONVIRTUAL
+ USHORT
+ QueryStartingCluster(
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetStartingCluster(
+ IN USHORT NewStartingCluster
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryFileSize(
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetFileSize(
+ IN ULONG NewFileSize
+ );
+
+ NONVIRTUAL
+ USHORT
+ QueryEaHandle(
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetEaHandle(
+ IN USHORT NewHandle
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsEndOfDirectory(
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetEndOfDirectory(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsErased(
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetErased(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsHidden(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsSystem(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsVolumeLabel(
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetVolumeLabel(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsDirectory(
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetDirectory(
+ );
+
+ NONVIRTUAL
+ VOID
+ ResetDirectory(
+ );
+
+ NONVIRTUAL
+ UCHAR
+ QueryChecksum(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ Is8LowerCase(
+ ) CONST;
+
+
+ NONVIRTUAL
+ BOOLEAN
+ Is3LowerCase(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsLongEntry(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsLongNameEntry(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryLongOrdinal(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsLastLongEntry(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsWellTerminatedLongNameEntry(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryLongNameComponent(
+ OUT PWSTRING NameComponent
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ NameHasTilde(
+ ) CONST;
+
+
+ NONVIRTUAL
+ BOOLEAN
+ NameHasExtendedChars(
+ ) CONST;
+
+ private:
+
+ NONVIRTUAL
+ BOOLEAN
+ TimeStampsAreValid(
+ USHORT t,
+ USHORT d
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ PUCHAR _dirent;
+
+};
+
+
+INLINE
+VOID
+FAT_DIRENT::Clear(
+ )
+/*++
+
+Routine Description:
+
+ This routine zeros out the directory entry.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ memset(_dirent, 0, 32);
+}
+
+
+INLINE
+BOOLEAN
+FAT_DIRENT::IsDot(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes whether or not the directory entry is the "."
+ entry.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - The entry is not the "." entry.
+ TRUE - The entry is the "." entry.
+
+--*/
+{
+ return !memcmp(_dirent, ". ", 11);
+}
+
+
+INLINE
+BOOLEAN
+FAT_DIRENT::IsDotDot(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes whether or not the directory entry is the ".."
+ entry.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - The entry is not the ".." entry.
+ TRUE - The entry is the ".." entry.
+
+--*/
+{
+ return !memcmp(_dirent, ".. ", 11);
+}
+
+
+INLINE
+USHORT
+FAT_DIRENT::QueryStartingCluster(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the starting cluster number of the directory entry.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The starting cluster number of the directory entry.
+
+--*/
+{
+ DebugAssert(_dirent);
+ return *((PUSHORT) &_dirent[26]);
+}
+
+
+INLINE
+VOID
+FAT_DIRENT::SetStartingCluster(
+ IN USHORT NewStartingCluster
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the starting cluster number for the directory entry.
+
+Arguments:
+
+ NewStartingCluster - Supplies the starting cluster number for the
+ directory entry.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DebugAssert(_dirent);
+ *((PUSHORT) &_dirent[26]) = NewStartingCluster;
+}
+
+
+INLINE
+ULONG
+FAT_DIRENT::QueryFileSize(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the number of bytes in the file.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of bytes in the file.
+
+--*/
+{
+ DebugAssert(_dirent);
+ return *((PULONG) &_dirent[28]);
+}
+
+
+INLINE
+VOID
+FAT_DIRENT::SetFileSize(
+ IN ULONG NewFileSize
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the file size in the directory entry.
+
+Arguments:
+
+ NewFileSize - Supplies the new file size.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DebugAssert(_dirent);
+ *((PULONG) &_dirent[28]) = NewFileSize;
+}
+
+
+INLINE
+USHORT
+FAT_DIRENT::QueryEaHandle(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the EA handle for the file.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The EA handle for the file.
+
+--*/
+{
+ DebugAssert(_dirent);
+ return *((PUSHORT) &_dirent[20]);
+}
+
+
+INLINE
+VOID
+FAT_DIRENT::SetEaHandle(
+ IN USHORT NewHandle
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the EA handle for the file.
+
+Arguments:
+
+ NewHandle - Supplies the EA handle for the file.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DebugAssert(_dirent);
+ *((PUSHORT) &_dirent[20]) = NewHandle;
+}
+
+
+INLINE
+BOOLEAN
+FAT_DIRENT::IsEndOfDirectory(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes whether or not this directory entry marks
+ the end of the directory.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - This entry does not mark the end of the directory.
+ TRUE - This entry marks the end of the directory.
+
+--*/
+{
+ DebugAssert(_dirent);
+ return _dirent[0] ? FALSE : TRUE;
+}
+
+
+INLINE
+VOID
+FAT_DIRENT::SetEndOfDirectory(
+ )
+/*++
+
+Routine Description:
+
+ This routine sets this directory entry marks to the end of the
+ directory.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DebugAssert(_dirent);
+ _dirent[0] = 0;
+}
+
+
+INLINE
+BOOLEAN
+FAT_DIRENT::IsErased(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes whether or not the directory entry is erased or not.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - The directory entry is not erased.
+ TRUE - The directory entry is erased.
+
+--*/
+{
+ DebugAssert(_dirent);
+ return _dirent[0] == 0xE5 ? TRUE : FALSE;
+}
+
+
+INLINE
+VOID
+FAT_DIRENT::SetErased(
+ )
+/*++
+
+Routine Description:
+
+ This routine marks the directory entry as erased.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DebugAssert(_dirent);
+ _dirent[0] = 0xE5;
+}
+
+
+INLINE
+BOOLEAN
+FAT_DIRENT::IsHidden(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes whether or not the file is hidden.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - The file is not hidden.
+ TRUE - The file is hidden.
+
+--*/
+{
+ DebugAssert(_dirent);
+ return _dirent[11]&0x02 ? TRUE : FALSE;
+}
+
+
+INLINE
+BOOLEAN
+FAT_DIRENT::IsSystem(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes whether or not the file is a system file.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - The file is not a system file.
+ TRUE - The file is a system file.
+
+--*/
+{
+ DebugAssert(_dirent);
+ return _dirent[11]&0x04 ? TRUE : FALSE;
+}
+
+
+INLINE
+BOOLEAN
+FAT_DIRENT::IsVolumeLabel(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes whether or not the first 11 characters of the
+ directory entry are the volume label or not.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - The directory entry is not a volume label.
+ TRUE - The directory entry is a volume label.
+
+--*/
+{
+ DebugAssert(_dirent);
+ return ((_dirent[11]&0x08) && !IsLongEntry());
+}
+
+INLINE
+BOOLEAN
+FAT_DIRENT::IsLongEntry(
+ ) CONST
+/*++
+
+Routine Description;
+
+ This routine determines whether this entry is a
+ Long Directory Entry.
+
+ The entry is a Long Directory Entry if the attribute
+ field has all four low-order bits (read-only, hidden,
+ system, and volume-label) set. The four high-order
+ bits are ignored.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the entry is a Long Name Directory Entry.
+
+--*/
+{
+ return( (_dirent[11] & 0xF) == 0xF );
+}
+
+INLINE
+BOOLEAN
+FAT_DIRENT::IsLongNameEntry(
+ ) CONST
+/*++
+
+Routine Description;
+
+ This routine determines whether this entry is a
+ Long Name Directory Entry.
+
+ A Long Name directory entry is a Long Directory Entry
+ with a type field of LONG_DIRENT_TYPE_LONG_NAME.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the entry is a Long Name Directory Entry.
+
+--*/
+{
+ return( IsLongEntry() && (_dirent[12] == LONG_DIRENT_TYPE_NAME) );
+}
+
+INLINE
+BOOLEAN
+FAT_DIRENT::QueryLongOrdinal(
+ ) CONST
+/*++
+
+Routine Description;
+
+ This method returns the ordinal of a long directory entry.
+ If the directory entry is not a long entry, it returns
+ 0xFF. Note that this method strips off the Last Long Entry
+ flag before returning the ordinal. To determine if an entry
+ is the last of a set of long entries, call IsLastLongEntry.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The ordinal of this entry.
+
+--*/
+{
+ return( IsLongEntry() ? _dirent[0] & 0x3F: 0xFF );
+}
+
+INLINE
+BOOLEAN
+FAT_DIRENT::IsLastLongEntry(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method determines whether this entry is the last
+ of a set of long directory entries.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if this is the last of a set of long directory entries.
+
+--*/
+{
+ return( IsLongEntry() ? _dirent[0] & 0x40 : FALSE );
+}
+
+
+INLINE
+VOID
+FAT_DIRENT::SetVolumeLabel(
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the directory entry to be a volume label.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DebugAssert(_dirent);
+ _dirent[11] |= 0x08;
+}
+
+
+INLINE
+BOOLEAN
+FAT_DIRENT::IsDirectory(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes whether or not the directory entry is a directory.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - The directory entry is not a directory.
+ TRUE - The directory entry is a directory.
+
+--*/
+{
+ DebugAssert(_dirent);
+ return ((_dirent[11]&0x10) && !IsLongEntry());
+}
+
+
+INLINE
+VOID
+FAT_DIRENT::SetDirectory(
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the directory entry to be a directory.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DebugAssert(_dirent);
+ _dirent[11] |= 0x10;
+}
+
+
+INLINE
+VOID
+FAT_DIRENT::ResetDirectory(
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the directory entry to not be a directory.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DebugAssert(_dirent);
+ _dirent[11] &= ~0x10;
+}
+
+
+
+
+INLINE
+BYTE
+FAT_DIRENT::QueryAttributeByte(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the attribute byte of the directory entry
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Attribute byte
+
+--*/
+{
+ DebugAssert(_dirent);
+ return _dirent[11];
+}
+
+
+INLINE
+BOOLEAN
+FAT_DIRENT::Is8LowerCase(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine tells whether the first 8 bytes of the short name
+ should be downcased after being read from the disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE or FALSE
+
+--*/
+{
+
+ DebugAssert(_dirent);
+ return (_dirent[12] & 0x08) != 0;
+}
+
+
+INLINE
+BOOLEAN
+FAT_DIRENT::Is3LowerCase(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine tells whether the last 8 bytes of the short name
+ should be downcased after being read from the disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE or FALSE
+
+--*/
+{
+ DebugAssert(_dirent);
+ return (_dirent[12] & 0x10) != 0;
+}
+
+#endif // FAT_DIRENT_DEFN
diff --git a/private/utils/ufat/inc/fatdir.hxx b/private/utils/ufat/inc/fatdir.hxx
new file mode 100644
index 000000000..e38f1442b
--- /dev/null
+++ b/private/utils/ufat/inc/fatdir.hxx
@@ -0,0 +1,90 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ fatdir.hxx
+
+Abstract:
+
+ This class is a virtual template for a FAT directory. It will be
+ passed to functions who wish to query the directory entries from the
+ directory without knowledge of how or where the directory is stored.
+
+ The user of this class will not be able to read or write the
+ directory to disk.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 4-Dec-90
+
+--*/
+
+#if !defined(FATDIR_DEFN)
+
+#define FATDIR_DEFN
+
+#if defined ( _AUTOCHECK_ )
+#define UFAT_EXPORT
+#elif defined ( _UFAT_MEMBER_ )
+#define UFAT_EXPORT __declspec(dllexport)
+#else
+#define UFAT_EXPORT __declspec(dllimport)
+#endif
+
+DECLARE_CLASS( FATDIR );
+DECLARE_CLASS( WSTRING );
+DEFINE_POINTER_TYPES( PFATDIR );
+
+
+CONST BytesPerDirent = 32;
+
+
+class FATDIR : public OBJECT {
+
+ public:
+
+ VIRTUAL
+ PVOID
+ GetDirEntry(
+ IN LONG EntryNumber
+ ) PURE;
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ PVOID
+ SearchForDirEntry(
+ IN PCWSTRING FileName
+ );
+
+ NONVIRTUAL
+ PVOID
+ GetFreeDirEntry(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Read(
+ ) PURE;
+
+ VIRTUAL
+ BOOLEAN
+ Write(
+ ) PURE;
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ BOOLEAN
+ QueryLongName(
+ IN LONG EntryNumber,
+ OUT PWSTRING LongName
+ );
+
+ protected:
+
+ DECLARE_CONSTRUCTOR( FATDIR );
+
+};
+
+#endif // FATDIR_DEFN
diff --git a/private/utils/ufat/inc/fatsa.hxx b/private/utils/ufat/inc/fatsa.hxx
new file mode 100644
index 000000000..1f717feac
--- /dev/null
+++ b/private/utils/ufat/inc/fatsa.hxx
@@ -0,0 +1,754 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ fatsa.hxx
+
+Abstract:
+
+
+Author:
+
+ Matthew Bradburn (mattbr) 1-Oct-93
+
+--*/
+
+#ifndef FATSUPERA_DEFN
+#define FATSUPERA_DEFN
+
+#include "hmem.hxx"
+#include "supera.hxx"
+#include "message.hxx"
+
+#if defined ( _AUTOCHECK_ )
+#define UFAT_EXPORT
+#elif defined ( _UFAT_MEMBER_ )
+#define UFAT_EXPORT __declspec(dllexport)
+#else
+#define UFAT_EXPORT __declspec(dllimport)
+#endif
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( ARRAY );
+DECLARE_CLASS( BITVECTOR );
+DECLARE_CLASS( EA_HEADER );
+DECLARE_CLASS( FAT );
+DECLARE_CLASS( FAT_SA );
+DECLARE_CLASS( FAT_DIRENT );
+DECLARE_CLASS( FATDIR );
+DECLARE_CLASS( GENERIC_STRING );
+DECLARE_CLASS( INTSTACK );
+DECLARE_CLASS( NUMBER_SET );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( MESSAGE );
+DECLARE_CLASS( ROOTDIR );
+DECLARE_CLASS( SORTED_LIST );
+DECLARE_CLASS( TIMEINFO );
+DECLARE_CLASS( WSTRING );
+DEFINE_POINTER_TYPES( PFATDIR );
+
+
+enum FATTYPE {
+ SMALL, // 12 bit fat
+ LARGE // 16 bit fat
+};
+
+// the text for the oem data field
+#define OEMTEXT "MSDOS5.0"
+#define OEMTEXTLENGTH 8
+
+#define sigBOOTSTRAP (UCHAR)0x29 // boot strap signature
+
+CONST MaxSecPerClus = 128; // The maximum number of sectors per cluster.
+
+struct _EA_INFO {
+ USHORT OwnHandle;
+ USHORT PreceedingCn; // Clus num preceeding first cluster of set.
+ USHORT LastCn; // The number of the last cluster in the set.
+ STR OwnerFileName[14]; // Owner file name as found in ea set.
+ UCHAR UsedCount; // Number of files using ea set.
+ STR UserFileName[14]; // File name of ea set user.
+ USHORT UserFileEntryCn; // Clus num of directory for file.
+ ULONG UserFileEntryNumber; // Dirent num for file name.
+};
+
+DEFINE_TYPE( struct _EA_INFO, EA_INFO );
+
+struct _FATCHK_REPORT {
+ ULONG HiddenEntriesCount;
+ USHORT HiddenClusters;
+ ULONG FileEntriesCount;
+ USHORT FileClusters;
+ ULONG DirEntriesCount;
+ USHORT DirClusters;
+ ULONG ExitStatus;
+};
+
+DEFINE_TYPE( struct _FATCHK_REPORT, FATCHK_REPORT );
+
+
+struct _CENSUS_REPORT {
+ ULONG FileEntriesCount;
+ USHORT FileClusters;
+ ULONG DirEntriesCount;
+ USHORT DirClusters;
+ USHORT EaClusters;
+};
+
+DEFINE_TYPE( struct _CENSUS_REPORT, CENSUS_REPORT );
+
+
+class FAT_SA : public SUPERAREA {
+
+ public:
+
+ UFAT_EXPORT
+ DECLARE_CONSTRUCTOR(FAT_SA);
+
+ VIRTUAL
+ UFAT_EXPORT
+ ~FAT_SA(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Initialize(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Formatted
+ ) PURE;
+
+ VIRTUAL
+ BOOLEAN
+ Create(
+ IN PCNUMBER_SET BadSectors,
+ IN OUT PMESSAGE Message,
+ IN PCWSTRING Label DEFAULT NULL,
+ IN ULONG ClusterSize DEFAULT 0,
+ IN ULONG VirtualSize DEFAULT 0
+ ) PURE;
+
+ NONVIRTUAL
+ BOOLEAN
+ VerifyAndFix(
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose DEFAULT FALSE,
+ IN BOOLEAN OnlyIfDirty DEFAULT FALSE,
+ IN BOOLEAN RecoverFree DEFAULT FALSE,
+ IN BOOLEAN RecoverAlloc DEFAULT FALSE,
+ IN BOOLEAN Resize DEFAULT FALSE,
+ IN ULONG LogFileSize DEFAULT 0,
+ OUT PULONG ExitStatus DEFAULT NULL,
+ IN PCWSTRING DriveLetter DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ RecoverFile(
+ IN PCWSTRING FullPathFileName,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Read(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Read(
+ IN OUT PMESSAGE Message
+ ) PURE;
+
+ NONVIRTUAL
+ BOOLEAN
+ Write(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Write(
+ IN OUT PMESSAGE Message
+ ) PURE;
+
+ NONVIRTUAL
+ PFAT
+ GetFat(
+ );
+
+ NONVIRTUAL
+ PROOTDIR
+ GetRootDir(
+ );
+
+ VIRTUAL
+ USHORT
+ QuerySectorsPerCluster(
+ ) CONST PURE;
+
+
+ VIRTUAL
+ USHORT
+ QuerySectorsPerFat(
+ ) CONST PURE;
+
+ VIRTUAL
+ ULONG
+ QueryVirtualSectors(
+ ) CONST PURE;
+
+ VIRTUAL
+ USHORT
+ QueryFats(
+ ) CONST PURE;
+
+ VIRTUAL
+ PARTITION_SYSTEM_ID
+ QuerySystemId(
+ ) CONST PURE;
+
+ VIRTUAL
+ LBN
+ QueryStartDataLbn(
+ ) CONST PURE;
+
+ VIRTUAL
+ USHORT
+ QueryClusterCount(
+ ) CONST PURE;
+
+ NONVIRTUAL
+ SECTORCOUNT
+ QueryFreeSectors(
+ ) CONST;
+
+ NONVIRTUAL
+ FATTYPE
+ QueryFatType(
+ ) CONST;
+
+ VIRTUAL
+ BYTE
+ QueryVolumeFlags(
+ ) CONST PURE;
+
+ VIRTUAL
+ VOID
+ SetVolumeFlags(
+ BYTE Flags,
+ BOOLEAN ResetFlags
+ ) PURE;
+
+ VIRTUAL
+ BOOLEAN
+ RecoverChain(
+ IN OUT PUSHORT StartingCluster,
+ OUT PBOOLEAN ChangesMade,
+ IN USHORT EndingCluster DEFAULT 0,
+ IN BOOLEAN Replace DEFAULT FALSE
+ ) PURE;
+
+ VIRTUAL
+ BOOLEAN
+ QueryLabel(
+ OUT PWSTRING Label
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryLabel(
+ OUT PWSTRING Label,
+ OUT PTIMEINFO TimeInfo
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ SetLabel(
+ IN PCWSTRING NewLabel
+ );
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ USHORT
+ QueryFileStartingCluster(
+ IN PCWSTRING FullPathFileName,
+ OUT PHMEM Hmem DEFAULT NULL,
+ OUT PPFATDIR Directory DEFAULT NULL,
+ OUT PBOOLEAN DeleteDirectory DEFAULT NULL,
+ OUT PFAT_DIRENT DirEntry DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ BOOLEAN
+ QueryCensusAndRelocate (
+ OUT PCENSUS_REPORT CensusReport DEFAULT NULL,
+ IN OUT PINTSTACK RelocationStack DEFAULT NULL,
+ OUT PBOOLEAN Relocated DEFAULT NULL
+ );
+
+ STATIC
+ USHORT
+ ComputeSecClus(
+ IN SECTORCOUNT Sectors,
+ IN FATTYPE FatType,
+ IN MEDIA_TYPE MediaType
+ );
+
+ VIRTUAL
+ BOOLEAN
+ IsCompressed(
+ ) CONST PURE;
+
+ VIRTUAL
+ BOOLEAN
+ ReadSectorZero(
+ ) PURE;
+
+ STATIC BOOLEAN
+ FAT_SA::IsValidString(
+ IN PCWSTRING String
+ );
+
+ //
+ // These routines are used to access the CVF_EXTENSIONS on
+ // FATDB, and they do the minimal thing on REAL_FAT.
+ //
+
+ VIRTUAL
+ ULONG
+ QuerySectorFromCluster(
+ IN ULONG Cluster,
+ OUT PUCHAR NumSectors DEFAULT NULL
+ ) PURE;
+
+ VIRTUAL
+ BOOLEAN
+ IsClusterCompressed(
+ IN ULONG Cluster
+ ) CONST PURE;
+
+ VIRTUAL
+ VOID
+ SetClusterCompressed(
+ IN ULONG Cluster,
+ IN BOOLEAN fCompressed
+ ) PURE;
+
+ VIRTUAL
+ UCHAR
+ QuerySectorsRequiredForPlainData(
+ IN ULONG Cluster
+ ) PURE;
+
+ //
+ // These routines are used to manage the sector heap for
+ // FATDB, and do nothing on REAL_FAT.
+ //
+
+ VIRTUAL
+ BOOLEAN
+ FreeClusterData(
+ IN ULONG Cluster
+ ) PURE;
+
+ VIRTUAL
+ BOOLEAN
+ AllocateClusterData(
+ IN ULONG Cluster,
+ IN UCHAR NumSectors,
+ IN BOOLEAN bCompressed,
+ IN UCHAR PlainSize
+ ) PURE;
+
+ protected:
+
+ PFAT _fat; // Pointer to FAT;
+ FATTYPE _ft; // fat type required by area
+ PROOTDIR _dir; // Pointer to Root directory
+
+ VIRTUAL
+ BOOLEAN
+ SetBpb(
+ ) PURE;
+
+ VIRTUAL
+ ULONG
+ SecPerBoot(
+ ) PURE;
+
+ VIRTUAL
+ VOLID
+ QueryVolId(
+ ) CONST PURE;
+
+ VIRTUAL
+ VOLID
+ SetVolId(
+ IN VOLID VolId
+ ) PURE;
+
+ VIRTUAL
+ UCHAR
+ QueryMediaByte(
+ ) CONST PURE;
+
+ VIRTUAL
+ VOID
+ SetMediaByte(
+ UCHAR MediaByte
+ ) PURE;
+
+ NONVIRTUAL
+ PARTITION_SYSTEM_ID
+ ComputeSystemId(
+ ) CONST;
+
+ NONVIRTUAL
+ FATTYPE
+ ComputeFatType(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ RecoverOrphans(
+ IN OUT PBITVECTOR FatBitMap,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN NeedErrorsMessage
+ );
+
+ VIRTUAL
+ BOOLEAN
+ VerifyFatExtensions(
+ IN FIX_LEVEL FixLevel,
+ IN PMESSAGE Message,
+ IN PBOOLEAN pfNeedMsg
+ ) PURE;
+
+ VIRTUAL
+ BOOLEAN
+ CheckSectorHeapAllocation(
+ IN FIX_LEVEL FixLevel,
+ IN PMESSAGE Message,
+ IN PBOOLEAN pfNeedMsg
+ ) PURE;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ USHORT
+ ComputeRootEntries(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ PerformEaLogOperations(
+ IN USHORT EaFileCn,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN NeedErrorsMessage
+ );
+
+ NONVIRTUAL
+ PEA_INFO
+ RecoverEaSets(
+ IN USHORT EaFileCn,
+ OUT PUSHORT NumEas,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN NeedErrorsMessage
+ );
+
+ NONVIRTUAL
+ USHORT
+ VerifyAndFixEaSet(
+ IN USHORT PreceedingCluster,
+ OUT PEA_INFO EaInfo,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN NeedErrorsMessage
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ EaSort(
+ IN OUT PEA_INFO EaInfos,
+ IN USHORT NumEas,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN NeedErrorsMessage
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ RebuildEaHeader(
+ IN OUT PUSHORT StartingCluster,
+ IN OUT PEA_INFO EaInfos,
+ IN USHORT NumEas,
+ IN OUT PMEM EaHeaderMem,
+ OUT PEA_HEADER EaHeader,
+ IN OUT PBITVECTOR FatBitMap,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN NeedErrorsMessage
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ WalkDirectoryTree(
+ IN OUT PEA_INFO EaInfos,
+ IN USHORT NumEas,
+ IN OUT PBITVECTOR FatBitMap,
+ OUT PFATCHK_REPORT Report,
+ IN FIX_LEVEL FixLevel,
+ IN BOOLEAN RecoverAlloc,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ IN OUT PBOOLEAN NeedErrorsMessage
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ValidateDirent(
+ IN OUT PFAT_DIRENT Dirent,
+ IN PCWSTRING FilePath,
+ IN FIX_LEVEL FixLevel,
+ IN BOOLEAN RecoverAlloc,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN NeedErrorsMessage,
+ IN OUT PBITVECTOR FatBitMap,
+ OUT PBOOLEAN CrossLinkDetected,
+ OUT PUSHORT CrossLinkPreviousCluster,
+ OUT PULONG ExitStatus
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ValidateEaHandle(
+ IN OUT PFAT_DIRENT Dirent,
+ IN USHORT DirClusterNumber,
+ IN ULONG DirEntryNumber,
+ IN OUT PEA_INFO EaInfos,
+ IN USHORT NumEas,
+ IN PCWSTRING FilePath,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN NeedErrorsMessage
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CopyClusters(
+ IN USHORT SourceChain,
+ OUT PUSHORT DestChain,
+ IN OUT PBITVECTOR FatBitMap,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PurgeEaFile(
+ IN PCEA_INFO EaInfos,
+ IN USHORT NumEas,
+ IN OUT PBITVECTOR FatBitMap,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN NeedErrorsMessage
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ InitRelocationList(
+ IN OUT PINTSTACK RelocationStack,
+ IN OUT PUSHORT RelocatedChain,
+ IN OUT PSORTED_LIST ClustersToRelocate,
+ OUT PBOOLEAN Relocated
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ RelocateFirstCluster(
+ IN OUT PFAT_DIRENT Dirent
+ );
+
+ NONVIRTUAL
+ USHORT
+ RelocateOneCluster(
+ IN USHORT Cluster,
+ IN USHORT Previous
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DoDirectoryCensusAndRelocation(
+ IN OUT PFATDIR Directory,
+ IN OUT PCENSUS_REPORT CensusReport,
+ IN OUT PSORTED_LIST ClustersToRelocate,
+ IN OUT PUSHORT RelocatedChain,
+ OUT PBOOLEAN Relocated
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DoVolumeCensusAndRelocation(
+ IN OUT PCENSUS_REPORT CensusReport,
+ IN OUT PSORTED_LIST ClustersToRelocate,
+ IN OUT PUSHORT RelocatedChain,
+ OUT PBOOLEAN Relocated
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ RecoverFreeSpace(
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AllocSectorsForChain(
+ IN ULONG StartingCluster
+ );
+};
+
+
+INLINE
+BOOLEAN
+FAT_SA::Read(
+ )
+/*++
+
+Routine Description:
+
+ This routine simply calls the other read with the default message
+ object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ MESSAGE msg;
+
+ return Read(&msg);
+}
+
+
+INLINE
+BOOLEAN
+FAT_SA::Write(
+ )
+/*++
+
+Routine Description:
+
+ This routine simply calls the other write with the default message
+ object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ MESSAGE msg;
+
+ return Write(&msg);
+}
+
+
+INLINE
+PFAT
+FAT_SA::GetFat(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the FAT maintained by this class.
+ It is not necessary to read or write this FAT since it shares memory
+ with the FAT_SA class and thus performing FAT_SA::Read will read in
+ the FAT and performing FAT_SA::Write will write the FAT. Additionally,
+ performing a FAT_SA::Write will duplicate the information in the local
+ FAT object to all other FATs on the disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the FAT super area's FAT.
+
+--*/
+{
+ return _fat;
+}
+
+
+INLINE
+PROOTDIR
+FAT_SA::GetRootDir(
+ )
+/*++
+
+Routine Description:
+
+ This routine return a pointer to the FAT super area's root directory.
+ The memory of this root directory is shared with the FAT super area.
+ Hence, as with 'GetFat' it is not necessary to read or write the
+ root directory returned by this routine if a FAT_SA::Read or
+ FAT_SA::Write is being performed respecively.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the FAT super area's root directory.
+
+--*/
+{
+ return _dir;
+}
+
+extern BOOLEAN
+IsValidString(
+ IN PCWSTRING String
+ );
+
+#endif // FATSUPERA_DEFN
+
+extern VOID
+dofmsg(
+ IN PMESSAGE Message,
+ IN OUT PBOOLEAN NeedErrorsMessage
+ );
diff --git a/private/utils/ufat/inc/fatvol.hxx b/private/utils/ufat/inc/fatvol.hxx
new file mode 100644
index 000000000..9d043e75f
--- /dev/null
+++ b/private/utils/ufat/inc/fatvol.hxx
@@ -0,0 +1,151 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ fatvol.hxx
+
+Abstract:
+
+ This class implements FAT only VOLUME items.
+
+Author:
+
+ Mark Shavlik (marks) 13-Feb-90
+
+--*/
+
+#if !defined(FATVOL)
+
+#define FATVOL
+
+#include "volume.hxx"
+#include "rfatsa.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( FAT_VOL );
+DECLARE_CLASS( MESSAGE );
+
+
+#if ! defined( _SETUP_LOADER_ )
+
+
+class FAT_VOL : public VOL_LIODPDRV {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( FAT_VOL );
+
+ VIRTUAL
+ ~FAT_VOL(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN BOOLEAN ExclusiveWrite DEFAULT FALSE,
+ IN BOOLEAN FormatMedia DEFAULT FALSE,
+ IN MEDIA_TYPE MediaType DEFAULT Unknown
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsFileContiguous(
+ IN PCWSTRING FullPathFileName,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ OUT PULONG NumBlocks DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ContiguityReport(
+ IN PCWSTRING DirectoryPath,
+ IN PCDSTRING FilesToCheck,
+ IN ULONG NumberOfFiles,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ PVOL_LIODPDRV
+ QueryDupVolume(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN BOOLEAN ExclusiveWrite DEFAULT FALSE,
+ IN BOOLEAN FormatMedia DEFAULT FALSE,
+ IN MEDIA_TYPE MediaType DEFAULT Unknown
+ ) CONST;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ REAL_FAT_SA _fatsa;
+
+};
+
+
+#else // _SETUP_LOADER_ is defined
+
+
+class FAT_VOL : public VOL_LIODPDRV {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( FAT_VOL );
+
+ VIRTUAL
+ ~FAT_VOL(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN ULONG DeviceHandle
+ );
+
+ VIRTUAL
+ ARC_STATUS
+ MarkDirty(
+ );
+
+ VIRTUAL
+ ARC_STATUS
+ Flush(
+ IN BOOLEAN JustHandle
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ REAL_FAT_SA _fatsa;
+
+};
+
+
+
+#endif // _SETUP_LOADER_
+
+#endif
diff --git a/private/utils/ufat/inc/filedir.hxx b/private/utils/ufat/inc/filedir.hxx
new file mode 100644
index 000000000..0c8d6097a
--- /dev/null
+++ b/private/utils/ufat/inc/filedir.hxx
@@ -0,0 +1,213 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ filedir.hxx
+
+Abstract:
+
+ This class is an implementation of FATDIR for all FAT directories
+ that are implemented as files. In other words all FAT directories
+ besides the root directory.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 4-Dec-90
+
+--*/
+
+#if !defined(FILEDIR_DEFN)
+
+#define FILEDIR_DEFN
+
+#include "cluster.hxx"
+#include "drive.hxx"
+#include "fatdir.hxx"
+#include "mem.hxx"
+
+#if defined ( _AUTOCHECK_ )
+#define UFAT_EXPORT
+#elif defined ( _UFAT_MEMBER_ )
+#define UFAT_EXPORT __declspec(dllexport)
+#else
+#define UFAT_EXPORT __declspec(dllimport)
+#endif
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( FAT );
+DECLARE_CLASS( FAT_SA );
+DECLARE_CLASS( FILEDIR );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+
+class FILEDIR : public FATDIR {
+
+ public:
+
+ UFAT_EXPORT
+ DECLARE_CONSTRUCTOR( FILEDIR );
+
+ VIRTUAL
+ UFAT_EXPORT
+ ~FILEDIR(
+ );
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ BOOLEAN
+ Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN PFAT_SA FatSuperArea,
+ IN PCFAT Fat,
+ IN USHORT StartingCluster
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Read(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Write(
+ );
+
+ NONVIRTUAL
+ PVOID
+ GetDirEntry(
+ IN LONG EntryNumber
+ );
+
+ NONVIRTUAL
+ USHORT
+ QueryLength(
+ ) CONST;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ CLUSTER_CHAIN _cluster;
+ LONG _number_of_entries;
+
+};
+
+INLINE
+BOOLEAN
+FILEDIR::Read(
+ )
+/*++
+
+Routine Description:
+
+ This routine reads the directory in from disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ return _cluster.Read();
+}
+
+
+INLINE
+BOOLEAN
+FILEDIR::Write(
+ )
+/*++
+
+Routine Description:
+
+ This routine writes the directory to disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ return _cluster.Write();
+}
+
+
+INLINE
+PVOID
+FILEDIR::GetDirEntry(
+ IN LONG EntryNumber
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the beginning of the requested
+ directory entry. The data may then be interpreted with a fat
+ directory entry object. The return value will be NULL if a request
+ for a directory entry is beyond the size of the directory.
+
+Arguments:
+
+ EntryNumber - The desired entry number. The entries will be numbered
+ 0, 1, 2, ... , n-1.
+
+Return Value:
+
+ A pointer to the beginning of a directory entry or NULL.
+
+--*/
+{
+ return (EntryNumber < _number_of_entries) ?
+ (PCHAR) _cluster.GetBuf() + BytesPerDirent*EntryNumber : NULL;
+}
+
+
+INLINE
+USHORT
+FILEDIR::QueryLength(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the number of clusters in the underlying cluster
+ chain.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of clusters in the cluster chain.
+
+--*/
+{
+ return _cluster.QueryLength();
+}
+
+
+#endif // FILEDIR_DEFN
diff --git a/private/utils/ufat/inc/mrcf.h b/private/utils/ufat/inc/mrcf.h
new file mode 100644
index 000000000..0af302cdb
--- /dev/null
+++ b/private/utils/ufat/inc/mrcf.h
@@ -0,0 +1,99 @@
+/*++ BUILD Version: 0001 // Increment this if a change has global effects
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ Mrcf.h
+
+Abstract:
+
+ This module defines all of the double space compression routines
+
+Author:
+
+ Gary Kimura [GaryKi] 03-Jun-1993
+
+Revision History:
+
+--*/
+
+#ifndef _MRCF_
+#define _MRCF_
+
+//
+// To decompress/compress a block of data the user needs to
+// provide a work space as an extra parameter to all the exported
+// procedures. That way the routines will not need to use excessive
+// stack space and will still be multithread safe
+//
+
+//
+// Variables for reading and writing bits
+//
+
+typedef struct _MRCF_BIT_IO {
+
+ USHORT abitsBB; // 16-bit buffer being read
+ LONG cbitsBB; // Number of bits left in abitsBB
+
+ PUCHAR pbBB; // Pointer to byte stream being read
+ ULONG cbBB; // Number of bytes left in pbBB
+ ULONG cbBBInitial; // Initial size of pbBB
+
+} MRCF_BIT_IO;
+typedef MRCF_BIT_IO *PMRCF_BIT_IO;
+
+//
+// Decompression only needs the bit i/o structure
+//
+
+typedef struct _MRCF_DECOMPRESS {
+
+ MRCF_BIT_IO BitIo;
+
+} MRCF_DECOMPRESS;
+typedef MRCF_DECOMPRESS *PMRCF_DECOMPRESS;
+
+//
+// Standard compression uses a few more field to contain
+// the lookup table
+//
+
+#define cMAXSLOTS (8) // The maximum number of slots used in the algorithm
+
+#define ltUNUSED (0xE000) // Value of unused ltX table entry
+#define mruUNUSED (0xFF) // Value of unused MRU table entry
+#define bRARE (0xD5) // Rarely occuring character value
+
+typedef struct _MRCF_STANDARD_COMPRESS {
+
+ MRCF_BIT_IO BitIo;
+
+ ULONG ltX[256][cMAXSLOTS]; // Source text pointer look-up table
+ UCHAR abChar[256][cMAXSLOTS]; // Character look-up table
+ UCHAR abMRUX[256]; // Most Recently Used ltX/abChar entry
+
+} MRCF_STANDARD_COMPRESS;
+typedef MRCF_STANDARD_COMPRESS *PMRCF_STANDARD_COMPRESS;
+
+ULONG
+MrcfDecompress (
+ PUCHAR UncompressedBuffer,
+ ULONG UncompressedLength,
+ PUCHAR CompressedBuffer,
+ ULONG CompressedLength,
+ PMRCF_DECOMPRESS WorkSpace
+ );
+
+ULONG
+MrcfStandardCompress (
+ PUCHAR CompressedBuffer,
+ ULONG CompressedLength,
+ PUCHAR UncompressedBuffer,
+ ULONG UncompressedLength,
+ PMRCF_STANDARD_COMPRESS WorkSpace
+ );
+
+#endif // _MRCF_
+
diff --git a/private/utils/ufat/inc/reloclus.hxx b/private/utils/ufat/inc/reloclus.hxx
new file mode 100644
index 000000000..c59da72c8
--- /dev/null
+++ b/private/utils/ufat/inc/reloclus.hxx
@@ -0,0 +1,87 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ reloclus.hxx
+
+Abstract:
+
+ This modules contains the declaration of the RELOCATION_CLUSTER
+ class. A relocation cluster is a cluster that will be relocated
+ somewhere else.
+
+Author:
+
+ Ramon J. San Andres (ramonsa) 05-Nov-1991
+
+--*/
+
+#if !defined( _RELOCATION_CLUSTER_ )
+
+#define _RELOCATION_CLUSTER_
+
+DECLARE_CLASS( RELOCATION_CLUSTER);
+
+class RELOCATION_CLUSTER : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( RELOCATION_CLUSTER );
+ DECLARE_CAST_MEMBER_FUNCTION( RELOCATION_CLUSTER );
+
+ VIRTUAL
+ ~RELOCATION_CLUSTER(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ IN USHORT ClusterNumber
+ );
+
+ VIRTUAL
+ LONG
+ Compare (
+ IN PCOBJECT Object
+ ) CONST;
+
+ NONVIRTUAL
+ USHORT
+ QueryClusterNumber (
+ ) CONST;
+
+
+ private:
+
+ USHORT _Cluster; // Cluster
+
+};
+
+
+INLINE
+USHORT
+RELOCATION_CLUSTER::QueryClusterNumber (
+ ) CONST
+/*++
+
+Routine Description:
+
+ Obtains the cluster number of this relocation cluster
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ USHORT - cluster number
+
+--*/
+{
+ return _Cluster;
+}
+
+
+#endif // _RELOCATION_CLUSTER_
diff --git a/private/utils/ufat/inc/rfatsa.hxx b/private/utils/ufat/inc/rfatsa.hxx
new file mode 100644
index 000000000..192102af4
--- /dev/null
+++ b/private/utils/ufat/inc/rfatsa.hxx
@@ -0,0 +1,986 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ rfatsa.hxx
+
+Abstract:
+
+Author:
+
+ Mark Shavlik (marks) 27-Mar-90
+ Norbert Kusters (norbertk) 15-Jan-91
+ Matthew Bradburn (mattbr) 01-Oct-93
+
+--*/
+
+#ifndef REAL_FAT_SA_DEFN
+#define REAL_FAT_SA_DEFN
+
+#include "hmem.hxx"
+#include "message.hxx"
+#include "fatsa.hxx"
+#include "bpb.hxx"
+
+#if defined ( _AUTOCHECK_ )
+#define UFAT_EXPORT
+#elif defined ( _UFAT_MEMBER_ )
+#define UFAT_EXPORT __declspec(dllexport)
+#else
+#define UFAT_EXPORT __declspec(dllimport)
+#endif
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( ARRAY );
+DECLARE_CLASS( BITVECTOR );
+DECLARE_CLASS( EA_HEADER );
+DECLARE_CLASS( FAT );
+DECLARE_CLASS( FAT_SA );
+DECLARE_CLASS( FAT_DIRENT );
+DECLARE_CLASS( FATDIR );
+DECLARE_CLASS( GENERIC_STRING );
+DECLARE_CLASS( INTSTACK );
+DECLARE_CLASS( NUMBER_SET );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( MESSAGE );
+DECLARE_CLASS( ROOTDIR );
+DECLARE_CLASS( SORTED_LIST );
+DECLARE_CLASS( TIMEINFO );
+DECLARE_CLASS( WSTRING );
+DEFINE_POINTER_TYPES( PFATDIR );
+
+class REAL_FAT_SA : public FAT_SA {
+
+ public:
+
+ UFAT_EXPORT
+ DECLARE_CONSTRUCTOR(REAL_FAT_SA);
+
+ VIRTUAL
+ UFAT_EXPORT
+ ~REAL_FAT_SA(
+ );
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ BOOLEAN
+ Initialize(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Formatted DEFAULT TRUE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Create(
+ IN PCNUMBER_SET BadSectors,
+ IN OUT PMESSAGE Message,
+ IN PCWSTRING Label DEFAULT NULL,
+ IN ULONG ClusterSize DEFAULT 0,
+ IN ULONG VirtualSize DEFAULT 0
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ RecoverFile(
+ IN PCWSTRING FullPathFileName,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ BOOLEAN
+ Read(
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Write(
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ VOID
+ QueryGeometry(
+ OUT PUSHORT SectorSize,
+ OUT PUSHORT SectorsPerTrack,
+ OUT PUSHORT Heads,
+ OUT PULONG HiddenSectors
+ );
+
+ NONVIRTUAL
+ USHORT
+ QuerySectorsPerCluster(
+ ) CONST;
+
+ NONVIRTUAL
+ USHORT
+ QuerySectorsPerFat(
+ ) CONST;
+
+ NONVIRTUAL
+ USHORT
+ QueryReservedSectors(
+ ) CONST;
+
+ NONVIRTUAL
+ USHORT
+ QueryFats(
+ ) CONST;
+
+ NONVIRTUAL
+ USHORT
+ QueryRootEntries(
+ ) CONST;
+
+ NONVIRTUAL
+ PARTITION_SYSTEM_ID
+ QuerySystemId(
+ ) CONST;
+
+ NONVIRTUAL
+ LBN
+ QueryStartDataLbn(
+ ) CONST;
+
+ NONVIRTUAL
+ USHORT
+ QueryClusterCount(
+ ) CONST;
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ SECTORCOUNT
+ QueryFreeSectors(
+ ) CONST;
+
+ NONVIRTUAL
+ FATTYPE
+ QueryFatType(
+ ) CONST;
+
+ NONVIRTUAL
+ BYTE
+ QueryVolumeFlags(
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetVolumeFlags(
+ BYTE Flags,
+ BOOLEAN ResetFlags
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ RecoverChain(
+ IN OUT PUSHORT StartingCluster,
+ OUT PBOOLEAN ChangesMade,
+ IN USHORT EndingCluster DEFAULT 0,
+ IN BOOLEAN Replace DEFAULT FALSE
+ );
+
+ STATIC
+ USHORT
+ ComputeSecClus(
+ IN SECTORCOUNT Sectors,
+ IN FATTYPE FatType,
+ IN MEDIA_TYPE MediaType
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsCompressed(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ ReadSectorZero(
+ );
+
+ NONVIRTUAL
+ PBIOS_PARAMETER_BLOCK
+ GetBpb(
+ );
+
+ private:
+
+ HMEM _mem; // memory for SECRUN
+
+ // _fat inherited from FAT_SA
+ // _fattype inherited from FAT_SA
+ // _dir inherited from FAT_SA
+
+ LBN _StartDataLbn; // LBN of files, or data area
+ USHORT _ClusterCount; // number of clusters in Super Area
+ PARTITION_SYSTEM_ID _sysid; // system id
+ ULONG _sec_per_boot; // sectors for boot code.
+ EXTENDED_BIOS_PARAMETER_BLOCK
+ _sector_zero;
+ PUCHAR _sector_sig; // sector signature
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetBpb(
+ IN ULONG ClusterSize
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetBpb(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DupFats(
+ );
+
+ NONVIRTUAL
+ LBN
+ ComputeStartDataLbn(
+ ) CONST;
+
+ NONVIRTUAL
+ USHORT
+ ComputeRootEntries(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ ValidateDirent(
+ IN OUT PFAT_DIRENT Dirent,
+ IN PCWSTRING FilePath,
+ IN FIX_LEVEL FixLevel,
+ IN BOOLEAN RecoverAlloc,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN NeedErrorsMessage,
+ IN OUT PBITVECTOR FatBitMap,
+ OUT PBOOLEAN CrossLinkDetected,
+ OUT PUSHORT CrossLinkPreviousCluster
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CopyClusters(
+ IN USHORT SourceChain,
+ OUT PUSHORT DestChain,
+ IN OUT PBITVECTOR FatBitMap,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ InitRelocationList(
+ IN OUT PINTSTACK RelocationStack,
+ IN OUT PUSHORT RelocatedChain,
+ IN OUT PSORTED_LIST ClustersToRelocate,
+ OUT PBOOLEAN Relocated
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ RelocateFirstCluster(
+ IN OUT PFAT_DIRENT Dirent
+ );
+
+ NONVIRTUAL
+ USHORT
+ RelocateOneCluster(
+ IN USHORT Cluster,
+ IN USHORT Previous
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DoDirectoryCensusAndRelocation(
+ IN OUT PFATDIR Directory,
+ IN OUT PCENSUS_REPORT CensusReport,
+ IN OUT PSORTED_LIST ClustersToRelocate,
+ IN OUT PUSHORT RelocatedChain,
+ OUT PBOOLEAN Relocated
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DoVolumeCensusAndRelocation(
+ IN OUT PCENSUS_REPORT CensusReport,
+ IN OUT PSORTED_LIST ClustersToRelocate,
+ IN OUT PUSHORT RelocatedChain,
+ OUT PBOOLEAN Relocated
+ );
+
+ NONVIRTUAL
+ ULONG
+ SecPerBoot(
+ );
+
+ NONVIRTUAL
+ VOLID
+ QueryVolId(
+ ) CONST;
+
+ NONVIRTUAL
+ VOLID
+ SetVolId(
+ IN VOLID VolId
+ );
+
+ NONVIRTUAL
+ UCHAR
+ QueryMediaByte(
+ ) CONST;
+
+ VIRTUAL
+ VOID
+ SetMediaByte(
+ UCHAR MediaByte
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ VerifyBootSector(
+ );
+
+ NONVIRTUAL
+ SECTORCOUNT
+ QueryVirtualSectors(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ CreateBootSector(
+ IN ULONG ClusterSize
+ );
+
+ BOOLEAN
+ REAL_FAT_SA::SetBootCode(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetPhysicalDriveType(
+ IN PHYSTYPE PhysType
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetOemData(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetSignature(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetBootSignature(
+ IN UCHAR Signature DEFAULT sigBOOTSTRAP
+ );
+
+ BOOLEAN
+ DosSaInit(
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN SECTORCOUNT NumberOfSectors,
+ IN OUT PMESSAGE Message
+ );
+
+ BOOLEAN
+ DosSaSetBpb(
+ );
+
+ BOOLEAN
+ RecoverOrphans(
+ IN OUT PBITVECTOR FatBitMap,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN NeedErrorsMessage
+ );
+
+ NONVIRTUAL
+ ULONG
+ QuerySectorFromCluster(
+ IN ULONG Cluster,
+ OUT PUCHAR NumSectors DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsClusterCompressed(
+ IN ULONG Cluster
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetClusterCompressed(
+ IN ULONG Cluster,
+ IN BOOLEAN fCompressed
+ );
+
+ NONVIRTUAL
+ UCHAR
+ QuerySectorsRequiredForPlainData(
+ IN ULONG Cluster
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ VerifyFatExtensions(
+ IN FIX_LEVEL FixLevel,
+ IN PMESSAGE Message,
+ IN PBOOLEAN pfNeedMsg
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CheckSectorHeapAllocation(
+ IN FIX_LEVEL FixLevel,
+ IN PMESSAGE Message,
+ IN PBOOLEAN pfNeedMsg
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FreeClusterData(
+ ULONG Cluster
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AllocateClusterData(
+ ULONG Cluster,
+ UCHAR NumSectors,
+ BOOLEAN bCompressed,
+ UCHAR PlainSize
+ );
+
+
+};
+
+INLINE
+USHORT
+REAL_FAT_SA::QuerySectorsPerCluster(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of sectors per cluster for
+ the volume.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of sectors per cluster for the volume.
+
+--*/
+{
+ return _sector_zero.Bpb.SectorsPerCluster ?
+ _sector_zero.Bpb.SectorsPerCluster : 256;
+}
+
+
+INLINE
+USHORT
+REAL_FAT_SA::QuerySectorsPerFat(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of sectors per FAT for the volume.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of sectors per FAT for the volume.
+
+--*/
+{
+ return _sector_zero.Bpb.SectorsPerFat;
+}
+
+
+INLINE
+USHORT
+REAL_FAT_SA::QueryReservedSectors(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the volume's number of Reserved Sectors,
+ i.e. the number of sectors before the first FAT.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of Reserved Sectors.
+
+--*/
+{
+ return _sector_zero.Bpb.ReservedSectors;
+}
+
+INLINE
+USHORT
+REAL_FAT_SA::QueryFats(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of FATs on the volume.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of FATs on the volume.
+
+--*/
+{
+ return _sector_zero.Bpb.Fats;
+}
+
+INLINE
+USHORT
+REAL_FAT_SA::QueryRootEntries(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the number of entries in the root
+ directory.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of root directory entries.
+
+--*/
+{
+ return _sector_zero.Bpb.RootEntries;
+}
+
+
+INLINE
+PARTITION_SYSTEM_ID
+REAL_FAT_SA::QuerySystemId(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the system ID for the volume.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The system ID for the volume.
+
+--*/
+{
+ return _sysid;
+}
+
+
+INLINE
+LBN
+REAL_FAT_SA::QueryStartDataLbn(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the LBN of the first logical cluster of the
+ volume.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The LBN of the first logical cluster of the volume.
+
+--*/
+{
+ return _StartDataLbn;
+}
+
+
+INLINE
+USHORT
+REAL_FAT_SA::QueryClusterCount(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the total number of clusters for the volume.
+ That is to say that the largest addressable cluster on the disk
+ is cluster number 'QueryClusterCount() - 1'. Note that the
+ smallest addressable cluster on the disk is 2.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The total number of clusters for the volume.
+
+--*/
+{
+ return _ClusterCount;
+}
+
+INLINE BOOLEAN
+REAL_FAT_SA::IsCompressed(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine tells whether this volume is doublespaced or not.
+ Since the class is REAL_FAT_SA, we know it's not.
+
+Arguments:
+
+Return Value:
+
+ TRUE - Compressed.
+ FALSE - Not compressed.
+
+--*/
+{
+ return FALSE;
+}
+
+INLINE BOOLEAN
+REAL_FAT_SA::ReadSectorZero(
+ )
+/*++
+
+Routine Description:
+
+ This routine used to be DOS_SUPERAREA::Read().
+
+Arguments:
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure.
+
+--*/
+{
+ BOOLEAN b;
+ PEXTENDED_BIOS_PARAMETER_BLOCK Pbios;
+
+ b = SECRUN::Read();
+ if (!b)
+ return FALSE;
+
+ Pbios = (PEXTENDED_BIOS_PARAMETER_BLOCK)SECRUN::GetBuf();
+ UnpackExtendedBios(&_sector_zero, Pbios);
+
+ return TRUE;
+}
+
+INLINE
+PBIOS_PARAMETER_BLOCK
+REAL_FAT_SA::GetBpb(
+ )
+{
+ return &(_sector_zero.Bpb);
+}
+
+
+
+INLINE
+UCHAR
+REAL_FAT_SA::QueryMediaByte(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine fetches the media byte from the super area's data.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The media byte residing in the super area.
+
+--*/
+{
+ return _sector_zero.Bpb.Media;
+}
+
+INLINE
+VOID
+REAL_FAT_SA::SetMediaByte(
+ UCHAR MediaByte
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the media byte in the super area's data.
+
+Arguments:
+
+ MediaByte -- Supplies the new media byte.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _sector_zero.Bpb.Media = MediaByte;
+}
+
+INLINE
+SECTORCOUNT
+REAL_FAT_SA::QueryVirtualSectors(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of sectors on the volume according
+ to the file system.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of sectors on the volume according to the file system.
+
+--*/
+{
+ return _sector_zero.Bpb.Sectors ? _sector_zero.Bpb.Sectors :
+ _sector_zero.Bpb.LargeSectors;
+}
+
+INLINE
+VOLID
+REAL_FAT_SA::QueryVolId(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine fetches the volume ID from the super area's data.
+ This routine will return 0 if volume serial numbers are not
+ supported by the partition.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The volume ID residing in the super area.
+
+--*/
+{
+ return (_sector_zero.Signature == 0x28 || _sector_zero.Signature == 0x29) ?
+ _sector_zero.SerialNumber : 0;
+}
+
+INLINE
+VOLID
+REAL_FAT_SA::SetVolId(
+ IN VOLID VolId
+ )
+/*++
+
+Routine Description:
+
+ This routine puts the volume ID into the super area's data.
+
+Arguments:
+
+ VolId - The new volume ID.
+
+Return Value:
+
+ The volume ID that was put.
+
+--*/
+{
+ return _sector_zero.SerialNumber = VolId;
+}
+
+INLINE
+BOOLEAN
+REAL_FAT_SA::SetBootSignature(
+ IN UCHAR Signature
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the boot signature in the super area.
+
+Arguments:
+
+ Signature - Supplies the character to set the signature to.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ _sector_zero.Signature = Signature;
+ return TRUE;
+}
+
+INLINE
+VOID
+REAL_FAT_SA::QueryGeometry(
+ OUT PUSHORT SectorSize,
+ OUT PUSHORT SectorsPerTrack,
+ OUT PUSHORT Heads,
+ OUT PULONG HiddenSectors
+ )
+/*++
+
+Routine Description:
+
+ This method returns the geometry information stored in
+ the Bios Parameter Block.
+
+Arguments:
+
+ SectorSize -- Receives the recorded sector size.
+ SectorsPerTrack -- Receives the recorded sectors per track.
+ Heads -- Receives the recorded number of heads.
+ HiddenSectors -- Receives the recorded number of hidden sectors.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ *SectorSize = _sector_zero.Bpb.BytesPerSector;
+ *SectorsPerTrack = _sector_zero.Bpb.SectorsPerTrack;
+ *Heads = _sector_zero.Bpb.Heads;
+ *HiddenSectors = _sector_zero.Bpb.HiddenSectors;
+}
+
+INLINE
+BYTE
+REAL_FAT_SA::QueryVolumeFlags(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the volume flags byte from the bpb.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The flags.
+
+--*/
+{
+ return _sector_zero.CurrentHead;
+}
+
+INLINE
+VOID
+REAL_FAT_SA::SetVolumeFlags(
+ BYTE Flags,
+ BOOLEAN ResetFlags
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the volume flags in the bpb.
+
+Arguments:
+
+ Flags -- flags to set or clear
+ ResetFlags -- if true, Flags are cleared instead of set
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if (ResetFlags) {
+ _sector_zero.CurrentHead &= ~Flags;
+ } else {
+ _sector_zero.CurrentHead |= Flags;
+ }
+}
+
+INLINE
+BOOLEAN
+AllocateClusterData(
+ ULONG Cluster,
+ UCHAR NumSectors,
+ BOOLEAN bCompressed,
+ UCHAR PlainSize
+ )
+{
+ DebugAbort("Didn't expect REAL_FAT_SA::AllocateClusterData() to be called");
+ return FALSE;
+}
+
+#endif // REAL_FAT_SA_DEFN
diff --git a/private/utils/ufat/inc/rootdir.hxx b/private/utils/ufat/inc/rootdir.hxx
new file mode 100644
index 000000000..8741500d5
--- /dev/null
+++ b/private/utils/ufat/inc/rootdir.hxx
@@ -0,0 +1,173 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ rootdir.hxx
+
+Abstract:
+
+ This class is an implementation of FATDIR for the FAT root directory.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 4-Dec-90
+
+--*/
+
+#if !defined(ROOTDIR_DEFN)
+
+#define ROOTDIR_DEFN
+
+#include "drive.hxx"
+#include "fatdir.hxx"
+#include "mem.hxx"
+#include "secrun.hxx"
+
+#if defined ( _AUTOCHECK_ )
+#define UFAT_EXPORT
+#elif defined ( _UFAT_MEMBER_ )
+#define UFAT_EXPORT __declspec(dllexport)
+#else
+#define UFAT_EXPORT __declspec(dllimport)
+#endif
+
+DECLARE_CLASS( ROOTDIR );
+
+
+class ROOTDIR : public FATDIR {
+
+ public:
+
+ UFAT_EXPORT
+ DECLARE_CONSTRUCTOR( ROOTDIR );
+
+ UFAT_EXPORT
+ VIRTUAL
+ ~ROOTDIR(
+ );
+
+ NONVIRTUAL
+ UFAT_EXPORT
+ BOOLEAN
+ Initialize(
+ IN PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN LBN StartingSector,
+ IN LONG NumberOfEntries
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Read(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Write(
+ );
+
+ NONVIRTUAL
+ PVOID
+ GetDirEntry(
+ IN LONG EntryNumber
+ );
+
+ private:
+
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ SECRUN _secrun;
+ LONG _number_of_entries;
+
+};
+
+INLINE
+BOOLEAN
+ROOTDIR::Read(
+ )
+/*++
+
+Routine Description:
+
+ This routine reads the directory in from the disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ return _secrun.Read();
+}
+
+
+INLINE
+BOOLEAN
+ROOTDIR::Write(
+ )
+/*++
+
+Routine Description:
+
+ This routine writes the drirectory to the disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ return _secrun.Write();
+}
+
+
+INLINE
+PVOID
+ROOTDIR::GetDirEntry(
+ IN LONG EntryNumber
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the beginning of the requested
+ directory entry. The data may then be interpreted with a fat
+ directory entry object. The return value will be NULL if a request
+ for a directory entry is beyond the size of the directory.
+
+Arguments:
+
+ EntryNumber - The desired entry number. The entries will be numbered
+ 0, 1, 2, ... , n-1.
+
+Return Value:
+
+ A pointer to the beginning of a directory entry or NULL.
+
+--*/
+{
+ return (EntryNumber < _number_of_entries) ?
+ (PCHAR) _secrun.GetBuf() + BytesPerDirent*EntryNumber : NULL;
+}
+
+
+#endif // ROOTDIR_DEFN
diff --git a/private/utils/ufat/inc/ufat.hxx b/private/utils/ufat/inc/ufat.hxx
new file mode 100644
index 000000000..d3fa4219f
--- /dev/null
+++ b/private/utils/ufat/inc/ufat.hxx
@@ -0,0 +1,36 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ ufat.hxx
+
+Author:
+
+ Rafael Lisitsa (RafaelL) 23-Mar-1995
+
+
+--*/
+
+
+#if !defined ( _UFAT_INCLUDED_ )
+
+#define _UFAT_INCLUDED_
+
+
+// Set up the UFAT_EXPORT macro for exporting from UFAT (if the
+// source file is a member of UFAT) or importing from UFAT (if
+// the source file is a client of UFAT).
+//
+#if defined ( _AUTOCHECK_ )
+#define UFAT_EXPORT
+#elif defined ( _UFAT_MEMBER_ )
+#define UFAT_EXPORT __declspec(dllexport)
+#else
+#define UFAT_EXPORT __declspec(dllimport)
+#endif
+
+
+#endif // _UFAT_INCLUDED_
+
diff --git a/private/utils/ufat/src/cluster.cxx b/private/utils/ufat/src/cluster.cxx
new file mode 100644
index 000000000..3b878ed46
--- /dev/null
+++ b/private/utils/ufat/src/cluster.cxx
@@ -0,0 +1,523 @@
+#include <pch.cxx>
+
+#define _UFAT_MEMBER_
+#include "ufat.hxx"
+
+
+#include "cmem.hxx"
+
+extern "C" {
+#ifdef DBLSPACE_ENABLED
+#include "mrcf.h"
+#endif // DBLSPACE_ENABLED
+#include "ntrtl.h"
+}
+
+DEFINE_EXPORTED_CONSTRUCTOR( CLUSTER_CHAIN, OBJECT, UFAT_EXPORT );
+
+VOID
+CLUSTER_CHAIN::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Constructor for CLUSTER_CHAIN which initializes private data to
+ default values.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _secruns = NULL;
+ _num_secruns = 0;
+ _length_of_chain = 0;
+ _is_compressed = FALSE;
+ _buf = NULL;
+ _drive = NULL;
+ _fat_sa = NULL;
+ _secrun = NULL;
+}
+
+UFAT_EXPORT
+CLUSTER_CHAIN::~CLUSTER_CHAIN(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for CLUSTER_CHAIN. Frees memory and returns references.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+UFAT_EXPORT
+BOOLEAN
+CLUSTER_CHAIN::Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN PFAT_SA FatSuperArea,
+ IN PCFAT Fat,
+ IN USHORT ClusterNumber,
+ IN USHORT LengthOfChain
+ )
+/*++
+
+Routine Description:
+
+ Prepares the CLUSTER_CHAIN object for reads and writes to disk.
+ The length of the cluster chain may be specified by the
+ LengthOfChain argument. Setting this parameter to 0 will cause
+ the length of the chain to be until the end of file.
+
+Arguments:
+
+ Mem - Supplies memory for the cluster object.
+ Drive - Supplies the drive to which reads and writes will
+ take place.
+ FatSuperArea - Supplies the FAT super area which contains information
+ about the current FAT implementation.
+ Fat - Supplies the file allocation table for this drive.
+ ClusterNumber - Supplies the cluster number to map.
+ LengthOfChain - Supplies the number of clusters in the chain.
+ This value defaults to 0 which indicates that all
+ clusters until end of file will be addressed.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ CONT_MEM cmem;
+ SECTORCOUNT sec_per_clus;
+ USHORT clus;
+ LONG size;
+ PVOID buf;
+ ULONG i, j;
+ LBN lbn;
+
+ Destroy();
+
+ if (!Mem ||
+ !Drive ||
+ !FatSuperArea ||
+ !Fat ||
+ !Fat->IsInRange(ClusterNumber)) {
+ Destroy();
+ return FALSE;
+ }
+
+ if (LengthOfChain) {
+ _length_of_chain = LengthOfChain;
+ } else {
+ _length_of_chain = Fat->QueryLengthOfChain(ClusterNumber);
+ }
+
+ if (!_length_of_chain) {
+ Destroy();
+ return FALSE;
+ }
+
+ sec_per_clus = FatSuperArea->QuerySectorsPerCluster();
+ size = sec_per_clus*Drive->QuerySectorSize()*_length_of_chain;
+
+ _is_compressed = FatSuperArea->IsCompressed();
+ _fat_sa = FatSuperArea;
+
+#ifdef DBLSPACE_ENABLED
+ if (_is_compressed) {
+
+ _fat = Fat;
+ _drive = Drive;
+ _starting_cluster = ClusterNumber;
+
+ if (!(_secrun = NEW SECRUN)) {
+ Destroy();
+ return FALSE;
+ }
+
+ // This buf will hold the cluster chain's uncompressed data.
+
+ if (!(_buf = (PUCHAR)Mem->Acquire(size, Drive->QueryAlignmentMask()))) {
+ Destroy();
+ return FALSE;
+ }
+
+ if (!_hmem.Initialize()) {
+ Destroy();
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+#endif // DBLSPACE_ENABLED
+
+ if (!(_secruns = (PSECRUN*) MALLOC(_length_of_chain*sizeof(PSECRUN)))) {
+ Destroy();
+ return FALSE;
+ }
+
+ if (!(buf = Mem->Acquire(size, Drive->QueryAlignmentMask())) ||
+ !cmem.Initialize(buf, size)) {
+ Destroy();
+ return FALSE;
+ }
+
+ clus = ClusterNumber;
+ i = 0;
+ for (;;) {
+ lbn = _fat_sa->QuerySectorFromCluster(clus);
+
+ for (j = 1; !Fat->IsEndOfChain(clus) &&
+ (USHORT)(clus + 1) == Fat->QueryEntry(clus) &&
+ i + j < _length_of_chain; j++) {
+ clus++;
+ }
+ i += j;
+
+ if (!(_secruns[_num_secruns] = NEW SECRUN)) {
+ Destroy();
+ return FALSE;
+ }
+
+ if (!_secruns[_num_secruns]->Initialize(&cmem, Drive, lbn,
+ j*sec_per_clus)) {
+ Destroy();
+ return FALSE;
+ }
+
+ _num_secruns++;
+
+ if (i == _length_of_chain) {
+ break;
+ }
+
+ clus = Fat->QueryEntry(clus);
+ if (!Fat->IsInRange(clus)) {
+ Destroy();
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+UFAT_EXPORT
+BOOLEAN
+CLUSTER_CHAIN::Read(
+ )
+/*++
+
+Routine Description:
+
+ This routine reads the cluster chain into memory. This is done
+ by making repetitive use of SECRUN's Read routine.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG i;
+ BOOLEAN b = TRUE;
+ USHORT clus;
+ LBN lbn;
+ UCHAR nsec;
+#ifdef DBLSPACE_ENABLED
+ MRCF_DECOMPRESS
+ wkspc;
+#endif // DBLSPACE_ENABLED
+ ULONG u;
+ ULONG cluster_size;
+ ULONG sector_size;
+
+ if (!_is_compressed) {
+
+ if (!_secruns) {
+ return FALSE;
+ }
+
+ for (i = 0; i < _num_secruns; i++) {
+
+ b = (BOOLEAN)(_secruns[i]->Read() && b);
+ }
+
+ return b;
+ }
+
+#ifdef DBLSPACE_ENABLED
+ //
+ // The volume is compressed.
+ //
+
+ sector_size = _drive->QuerySectorSize();
+ cluster_size = sector_size * _fat_sa->QuerySectorsPerCluster();
+
+ clus = _starting_cluster;
+
+ i = 0;
+ for (;;) {
+
+ lbn = _fat_sa->QuerySectorFromCluster(clus, &nsec);
+
+ if (!_secrun->Initialize(&_hmem, _drive, lbn, nsec)) {
+ return FALSE;
+ }
+
+ if (!_secrun->Read()) {
+ return FALSE;
+ }
+
+ if (_fat_sa->IsClusterCompressed(clus)) {
+
+ RtlZeroMemory(&_buf[i * sector_size], cluster_size);
+
+ u = MrcfDecompress(&_buf[i * sector_size],
+ _fat_sa->QuerySectorsRequiredForPlainData(clus) * sector_size,
+ (PUCHAR)_secrun->GetBuf(),
+ nsec * sector_size, &wkspc);
+
+ if (0 == u) {
+ // error: can't decompress data
+ return TRUE;
+ }
+
+ } else {
+
+ // This cluster isn't compressed; just copy.
+
+ memcpy(&_buf[i * cluster_size], _secrun->GetBuf(), cluster_size);
+ }
+
+ if (++i == _length_of_chain) {
+ return TRUE;
+ }
+
+ clus = _fat->QueryEntry(clus);
+ if (!_fat->IsInRange(clus)) {
+ return FALSE;
+ }
+ }
+
+ //NOTREACHED
+#endif // DBLSPACE_ENABLED
+ return FALSE;
+}
+
+
+UFAT_EXPORT
+BOOLEAN
+CLUSTER_CHAIN::Write(
+ )
+/*++
+
+Routine Description:
+
+ This routine writes the cluster chain to disk. This is done
+ by making repetitive use of SECRUN's Write routine.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG i;
+ BOOLEAN b = TRUE;
+ UCHAR nsec, new_nsec;
+ USHORT clus;
+ LBN lbn;
+#ifdef DBLSPACE_ENABLED
+ MRCF_STANDARD_COMPRESS
+ wkspc;
+#endif // DBLSPACE_ENABLED
+ ULONG cluster_size;
+ ULONG sector_size;
+ ULONG u;
+ HMEM work_buf;
+
+ if (!_is_compressed) {
+ if (!_secruns) {
+ return FALSE;
+ }
+
+ for (i = 0; i < _num_secruns; i++) {
+
+ b = (BOOLEAN)(_secruns[i]->Write() && b);
+ }
+
+ return b;
+ }
+
+#ifdef DBLSPACE_ENABLED
+ //
+ // The volume is compressed.
+ //
+
+ sector_size = _drive->QuerySectorSize();
+ cluster_size = _fat_sa->QuerySectorsPerCluster() * sector_size;
+
+ if (!work_buf.Initialize() ||
+ !work_buf.Acquire(cluster_size, _drive->QueryAlignmentMask())) {
+ return FALSE;
+ }
+
+ clus = _starting_cluster;
+ i = 0;
+ for (;;) {
+ lbn = _fat_sa->QuerySectorFromCluster(clus, &nsec);
+
+ u = MrcfStandardCompress((PUCHAR)work_buf.GetBuf(), cluster_size,
+ &_buf[i * cluster_size], cluster_size, &wkspc);
+ if (0 == u) {
+ // the data could not be compressed
+
+ if (nsec < _fat_sa->QuerySectorsPerCluster()) {
+
+ //
+ // previously the data had been compressed; need to allocate
+ // more disk space.
+ //
+
+ nsec = _fat_sa->QuerySectorsPerCluster();
+ _fat_sa->FreeClusterData(clus);
+ if (!_fat_sa->AllocateClusterData(clus, nsec, FALSE,
+ _fat_sa->QuerySectorsPerCluster())) {
+ // error: no space
+ return FALSE;
+ }
+
+ lbn = _fat_sa->QuerySectorFromCluster(clus);
+ }
+ DbgAssert(nsec == _fat_sa->QuerySectorsPerCluster());
+
+ _fat_sa->SetClusterCompressed(clus, FALSE);
+
+ } else {
+ new_nsec = (u + sector_size - 1)/sector_size;
+
+ if (new_nsec != nsec) {
+
+ //
+ // The data has been changed, and it won't compress into
+ // the same size as it used to.
+ //
+
+ _fat_sa->FreeClusterData(clus);
+ if (!_fat_sa->AllocateClusterData(clus, new_nsec, TRUE,
+ _fat_sa->QuerySectorsPerCluster())) {
+
+ // error: not enough free space
+ return FALSE;
+ }
+ lbn = _fat_sa->QuerySectorFromCluster(clus, &nsec);
+ } else {
+
+ //
+ // The cluster may not have been compressed before,
+ // but we still need the same amount of space even though
+ // it's now compressed.
+ //
+
+ _fat_sa->SetClusterCompressed(clus, TRUE);
+ }
+ }
+
+ _hmem.Initialize();
+ if (!_secrun->Initialize(&_hmem, _drive, lbn, nsec)) {
+ return FALSE;
+ }
+
+ memcpy(_secrun->GetBuf(), work_buf.GetBuf(),
+ nsec * sector_size);
+
+ b = (BOOLEAN)(_secrun->Write() && b);
+
+ if (++i == _length_of_chain) {
+ return b;
+ }
+
+ clus = _fat->QueryEntry(clus);
+ if (!_fat->IsInRange(clus)) {
+ return FALSE;
+ }
+ }
+
+ //NOTREACHED
+#endif // DBLSPACE_ENABLED
+ return FALSE;
+}
+
+
+VOID
+CLUSTER_CHAIN::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine cleans up the objects internal components. It does not
+ need to be called before Init as Init does this automatically.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG i;
+
+#ifdef DBLSPACE_ENABLED
+ if (_is_compressed) {
+ DELETE(_secrun);
+ _num_secruns = 0;
+ _length_of_chain = 0;
+ _buf = NULL;
+ _drive = NULL;
+ return;
+ }
+#endif // DBLSPACE_ENABLED
+
+ for (i = 0; i < _num_secruns; i++) {
+ DELETE(_secruns[i]);
+ }
+
+ DELETE(_secruns);
+ _num_secruns = 0;
+ _length_of_chain = 0;
+}
diff --git a/private/utils/ufat/src/cvfexts.cxx b/private/utils/ufat/src/cvfexts.cxx
new file mode 100644
index 000000000..73286f400
--- /dev/null
+++ b/private/utils/ufat/src/cvfexts.cxx
@@ -0,0 +1,129 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ cvfexts.hxx
+
+Abstract:
+
+ A class to manage the CVF_FAT_EXTENSIONS (otherwise known as
+ the MDFAT) part of the doublespace volume.
+
+Author:
+
+ Matthew Bradburn (mattbr) 27-Sep-93
+
+--*/
+
+#include <pch.cxx>
+
+extern "C" {
+#include "ntdef.h"
+#include "nturtl.h"
+}
+
+DEFINE_CONSTRUCTOR( CVF_FAT_EXTENS, SECRUN );
+
+BOOLEAN
+CVF_FAT_EXTENS::Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN LBN StartSector,
+ IN ULONG NumberOfEntries,
+ IN ULONG FirstEntry
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes a CVF_FAT_EXTENS object.
+
+Arguments:
+
+ Mem - supplies the memory for the run of sectors.
+ Drive - supplies the drive to read and write from.
+ StartSector - supplies the start of the mdfat
+ NumberOfEntries - supplies the number of entries in the mdfat
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure.
+
+--*/
+{
+ ULONG sector_size;
+ SECTORCOUNT nsec;
+
+ Destroy();
+
+ DbgAssert(Mem);
+ DbgAssert(Drive);
+
+ if (0 == (sector_size = Drive->QuerySectorSize())) {
+ Destroy();
+ return FALSE;
+ }
+
+ nsec = (NumberOfEntries*sizeof(ULONG) + sector_size)/sector_size;
+
+ if (!SECRUN::Initialize(Mem, Drive, StartSector, nsec)) {
+ Destroy();
+ return FALSE;
+ }
+
+ _mdfat = (PULONG)GetBuf() + FirstEntry; // - FirstDiskCluster*sizeof(ULONG);
+
+ _num_entries = NumberOfEntries;
+ _first_entry = FirstEntry;
+
+ return TRUE;
+}
+
+CVF_FAT_EXTENS::~CVF_FAT_EXTENS(
+ )
+{
+ Destroy();
+}
+
+VOID
+CVF_FAT_EXTENS::Destroy(
+ )
+{
+ _mdfat = NULL;
+}
+
+VOID
+CVF_FAT_EXTENS::Construct(
+ )
+{
+ _mdfat = NULL;
+}
+
+BOOLEAN
+CVF_FAT_EXTENS::Create(
+ )
+/*++
+
+Routine Description:
+
+ This routine will make the CVF_FAT_EXTENSIONS to be valid
+ but empty.
+
+Arguments:
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure.
+
+--*/
+{
+ for (ULONG i = 0; i < _num_entries; ++i) {
+ _mdfat[i] = 0;
+ SetClusterInUse(i, FALSE);
+ }
+ return TRUE;
+}
diff --git a/private/utils/ufat/src/dblentry.cxx b/private/utils/ufat/src/dblentry.cxx
new file mode 100644
index 000000000..95802c0d1
--- /dev/null
+++ b/private/utils/ufat/src/dblentry.cxx
@@ -0,0 +1,1177 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ entry.cxx
+
+Abstract:
+
+ This module contains the entry points for UFAT.DLL:
+
+ FatDbCreate
+ FatDbDelete
+ FatDbFormat
+ FatDbChkdsk
+
+Author:
+
+ Bill McJohn (billmc) 31-05-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#include "hmem.hxx"
+#include "message.hxx"
+#include "wstring.hxx"
+#include "bigint.hxx"
+#include "ifssys.hxx"
+#include "drive.hxx"
+#include "ifsentry.hxx"
+
+#include "rtmsg.h"
+#include "ntstatus.h"
+
+extern "C" {
+#include <stdio.h>
+}
+
+
+// this is used to cancel out the definition of DeleteFile
+// as DeleteFileW, so that the DeleteFile member of the
+// FILE_DISPOSITION_INFORMATION structure can be visible.
+//
+#undef DeleteFile
+
+BOOLEAN
+QueryHostFileName(
+ IN PCWSTRING DriveName,
+ OUT PWSTRING HostFileName
+ )
+/*++
+
+Routine Description:
+
+ This function determines the host file name for a mounted
+ Double Space volume.
+
+Arguments:
+
+ DriveName -- Supplies the volume's NT Drive name
+ HostFileName -- Receives the fully qualified NT path to
+ the Compressed Volume File.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ DSTRING DblspaceString;
+ CHNUM position;
+
+ // By convention, the device name for a double space volume
+ // is "<host drive name>.DBLSPACE.nnn". Thus, this method
+ // traces down the symbolic links to the device name, and
+ // then replaces the dot before DBLSPACE with a backslash.
+ //
+ if( !DblspaceString.Initialize( "DBLSPACE" ) ||
+ !IFS_SYSTEM::QueryCanonicalNtDriveName( DriveName, HostFileName ) ) {
+
+ return FALSE;
+ }
+
+ position = HostFileName->Strstr( &DblspaceString );
+
+ if( position == INVALID_CHNUM ||
+ position == 0 ||
+ HostFileName->QueryChAt( position - 1 ) != '.' ) {
+
+ return FALSE;
+ }
+
+ HostFileName->SetChAt( '\\', position - 1 );
+
+ return TRUE;
+}
+
+#if !defined( _READ_WRITE_DOUBLESPACE_ )
+
+ULONG
+ComputeVirtualSectors(
+ IN PCVF_HEADER CvfHeader,
+ IN ULONG HostFileSize
+ )
+/*++
+
+Routine Description:
+
+ This function computes the appropriate number of virtual
+ sectors for the given Compressed Volume File. Note that
+ it always uses a ratio of 2.
+
+Arguments:
+
+ CvfHeader -- Supplies the Compressed Volume File Header.
+ HostFileSize -- Supplies the size of the host file in bytes.
+
+Return Value:
+
+ The number of virtual sectors appropriate to this Compressed
+ Volume File.
+
+--*/
+{
+ CONST DefaultRatio = 2;
+ ULONG SystemOverheadSectors, SectorsInFile,
+ VirtualSectors, MaximumSectors, VirtualClusters;
+
+ if( CvfHeader == NULL ||
+ CvfHeader->Bpb.BytesPerSector == 0 ||
+ CvfHeader->Bpb.SectorsPerCluster == 0 ) {
+
+ return 0;
+ }
+
+ SystemOverheadSectors = CvfHeader->DosBootSectorLbn +
+ CvfHeader->CvfHeapOffset +
+ 2;
+
+ SectorsInFile = HostFileSize / CvfHeader->Bpb.BytesPerSector;
+
+ if( SectorsInFile < SystemOverheadSectors ) {
+
+ return 0;
+ }
+
+ VirtualSectors = (SectorsInFile - SystemOverheadSectors) * DefaultRatio +
+ CvfHeader->CvfHeapOffset;
+
+ // VirtualSectors cannot result in more that 0xfff8 clusters on
+ // the volume, nor can it be greater than the volume's maximum
+ // capacity.
+ //
+ VirtualSectors = min( VirtualSectors,
+ 0xfff8L * CvfHeader->Bpb.SectorsPerCluster );
+
+ MaximumSectors = (CvfHeader->CvfMaximumCapacity * 1024L * 1024L) /
+ CvfHeader->Bpb.BytesPerSector;
+
+ VirtualSectors = min( VirtualSectors, MaximumSectors );
+
+ // To avoid problems with DOS, do not create a volume with
+ // a number-of-clusters value in the range [0xFEF, 0xFF7].
+ //
+ VirtualClusters = VirtualSectors / CvfHeader->Bpb.SectorsPerCluster;
+
+ if( VirtualClusters >= 0xFEF && VirtualClusters <= 0xFF7 ) {
+
+ VirtualSectors = 0xFEEL * CvfHeader->Bpb.SectorsPerCluster;
+ }
+
+ return VirtualSectors;
+}
+
+BOOLEAN
+CreateCvfHeader(
+ OUT PCVF_HEADER CvfHeader,
+ IN ULONG MaximumCapacity
+ )
+/*++
+
+Routine Description:
+
+ This function creates a Compressed Volume File and fills in
+ the first sector with a valid CVF Header. The number of sectors
+ in the DOS BPB is set to zero, to indicate that this volume
+ file is not initialized.
+
+Arguments:
+
+ CvfHeader -- Receives the created CVF header.
+ MaximumCapacity -- Supplies the maximum capacity for the
+ double-space volume, in bytes.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ if( MaximumCapacity % (8L * 1024L * 1024L) ) {
+
+ // The volume maximum capacity must be a multiple of
+ // eight megabytes.
+ //
+ return FALSE;
+ }
+ ULONG Sectors, Clusters, Offset, SectorsInBitmap, SectorsInCvfFatExtension;
+
+ // Most of the fields in the DOS BPB have fixed values:
+ //
+ CvfHeader->Jump = 0xEB;
+ CvfHeader->JmpOffset = 0x903c;
+
+ memcpy( CvfHeader->Oem, "MSDBL6.0", 8 );
+
+ CvfHeader->Bpb.BytesPerSector = DoubleSpaceBytesPerSector;
+ CvfHeader->Bpb.SectorsPerCluster = DoubleSpaceSectorsPerCluster;
+ // ReservedSectors computed below.
+ CvfHeader->Bpb.Fats = DoubleSpaceFats;
+ CvfHeader->Bpb.RootEntries = DoubleSpaceRootEntries;
+ CvfHeader->Bpb.Sectors = 0;
+ CvfHeader->Bpb.Media = DoubleSpaceMediaByte;
+ // SectorsPerFat computed below.
+ CvfHeader->Bpb.SectorsPerTrack = DoubleSpaceSectorsPerTrack;
+ CvfHeader->Bpb.Heads = DoubleSpaceHeads;
+ CvfHeader->Bpb.HiddenSectors = DoubleSpaceHiddenSectors;
+ CvfHeader->Bpb.LargeSectors = 0;
+
+ // Compute the number of sectors and clusters for the given
+ // maximum capacity:
+ //
+ Sectors = MaximumCapacity / CvfHeader->Bpb.BytesPerSector;
+ Clusters = Sectors / CvfHeader->Bpb.SectorsPerCluster;
+
+ // Reserve space for a 16-bit FAT that's big enough for the
+ // maximum number of clusters.
+ //
+ CvfHeader->Bpb.SectorsPerFat =
+ (2 * Clusters + CvfHeader->Bpb.BytesPerSector - 1)/
+ CvfHeader->Bpb.BytesPerSector;
+
+ // DOS 6.2 requires that the first sector of the Sector Heap
+ // be cluster aligned; since the Root Directory is one cluster,
+ // this means that ReservedSectors plus SectorsPerFat must be
+ // a multiple of SectorsPerCluster.
+ //
+ CvfHeader->Bpb.ReservedSectors = DoubleSpaceReservedSectors;
+
+ Offset = (CvfHeader->Bpb.ReservedSectors + CvfHeader->Bpb.SectorsPerFat) %
+ CvfHeader->Bpb.SectorsPerCluster;
+
+ if( Offset != 0 ) {
+
+ CvfHeader->Bpb.ReservedSectors +=
+ CvfHeader->Bpb.SectorsPerCluster - Offset;
+ }
+
+ // So much for the DOS BPB. Now for the Double Space
+ // BPB extensions. The location of the CVFFatExtension
+ // table is preceded by sector zero, the bitmap, and
+ // one reserved sector. Note that MaximumCapacity must
+ // be a multiple of 8 Meg (8 * 1024 * 1024), which simplifies
+ // calculation of SectorsInBitmap, SectorsInCvfFatExtension,
+ // and CvfBitmap2KSize.
+ //
+ SectorsInBitmap = (Sectors / 8) / CvfHeader->Bpb.BytesPerSector;
+ SectorsInCvfFatExtension = (Clusters * 4) / CvfHeader->Bpb.BytesPerSector;
+
+ CvfHeader->CvfFatExtensionsLbnMinus1 = SectorsInBitmap + 1;
+ CvfHeader->LogOfBytesPerSector = DoubleSpaceLog2BytesPerSector;
+ CvfHeader->DosBootSectorLbn = DoubleSpaceReservedSectors2 +
+ CvfHeader->CvfFatExtensionsLbnMinus1 + 1 +
+ SectorsInCvfFatExtension;
+ CvfHeader->DosRootDirectoryOffset =
+ CvfHeader->Bpb.ReservedSectors + CvfHeader->Bpb.SectorsPerFat;
+ CvfHeader->CvfHeapOffset =
+ CvfHeader->DosRootDirectoryOffset + DoubleSpaceSectorsInRootDir;
+ CvfHeader->CvfFatFirstDataEntry =
+ CvfHeader->CvfHeapOffset / CvfHeader->Bpb.SectorsPerCluster - 2;
+ CvfHeader->CvfBitmap2KSize = SectorsInBitmap / DSSectorsPerBitmapPage;
+ CvfHeader->LogOfSectorsPerCluster = DoubleSpaceLog2SectorsPerCluster;
+ CvfHeader->Is12BitFat = 1;
+
+ CvfHeader->MinFile = 32L * DoubleSpaceRootEntries +
+ ( CvfHeader->DosBootSectorLbn +
+ CvfHeader->Bpb.ReservedSectors +
+ CvfHeader->Bpb.SectorsPerFat +
+ CVF_MIN_HEAP_SECTORS ) *
+ CvfHeader->Bpb.BytesPerSector;
+
+ CvfHeader->CvfMaximumCapacity = (USHORT)(MaximumCapacity/(1024L * 1024L));
+
+ return TRUE;
+}
+
+BOOLEAN
+ZeroFillFile(
+ IN HANDLE FileHandle,
+ IN ULONG Size,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This function extends the file to the requested size by
+ writing zeroes, to ensure that all sectors are writeable.
+
+ BUGBUG billmc -- should it also read the file?
+
+Arguments:
+
+ FileHandle -- Supplies a handle to the file.
+ Size -- Supplies the size of the file.
+ Message -- Supplies an outlet for messages. May be NULL.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ LARGE_INTEGER L;
+ BIG_INT Offset;
+ HMEM Mem;
+ NTSTATUS Status;
+ BOOLEAN Result = TRUE;
+ ULONG Remainder, BytesToWrite;
+ PVOID Buffer;
+ CONST ULONG BufferSize = 32 * 1024;
+ CONST ULONG BufferAlignment = 0xfff;
+ ULONG Percent;
+
+ Offset = 0;
+ Remainder = Size;
+
+ // Align the write buffer on a 4K boundary.
+ //
+ if( !Mem.Initialize() ||
+ (Buffer = Mem.Acquire( BufferSize, BufferAlignment )) == NULL ) {
+
+ Message ? Message->Set( MSG_FMT_NO_MEMORY ) : 1;
+ Message ? Message->Display( "" ) : 1;
+ return FALSE;
+ }
+
+ memset( Buffer, 0, BufferSize );
+
+ while( Remainder ) {
+
+ BytesToWrite = ( BufferSize < Remainder ) ? BufferSize : Remainder;
+
+ L = Offset.GetLargeInteger();
+
+ Status = NtWriteFile( FileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ Buffer,
+ BytesToWrite,
+ &L,
+ NULL
+ );
+
+ // BUGBUG billmc -- this is a hack...
+ //
+ if( Status == STATUS_INVALID_USER_BUFFER ) {
+
+ LARGE_INTEGER DelayInterval;
+
+ // Wait half a second.
+ //
+ DelayInterval = RtlConvertLongToLargeInteger( -5000000 );
+ NtDelayExecution( TRUE, &DelayInterval );
+
+ Status = NtWriteFile( FileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ Buffer,
+ BytesToWrite,
+ &L,
+ NULL
+ );
+ }
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ Message ? Message->Set( MSG_DBLSPACE_CREATE_DISK_ERROR ) : 1;
+ Message ? Message->Display( "" ) : 1;
+ Result = FALSE;
+ break;
+ }
+
+ Offset += BytesToWrite;
+ Remainder -= BytesToWrite;
+
+ if( Message ) {
+
+ // Note that Remainder and Size are both divided by
+ // SectorSize to avoid ULONG overflow.
+ //
+ Percent = (100 * ((Size - Remainder)/DoubleSpaceBytesPerSector))/
+ (Size/DoubleSpaceBytesPerSector);
+
+ Message->Set( MSG_PERCENT_COMPLETE );
+ if( !Message->Display( "%d", Percent ) ) {
+
+ return FALSE;
+ }
+ }
+ }
+
+ return Result;
+}
+
+BOOLEAN
+FileExists(
+ IN PCWSTRING FileName,
+ OUT PBOOLEAN Error,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This function determines whether a file exists.
+
+Arguments:
+
+ FileName -- Supplies the file name.
+ Error -- Receives TRUE if the function failed due to
+ an error.
+ Message -- Supplies an outlet for messages (may be NULL).
+
+Return Value:
+
+ TRUE upon successful completion. If the function fails because
+ of an error, *Error is set to TRUE and the function returns FALSE.
+ Otherwise, the file does not exist.
+
+--*/
+{
+ NTSTATUS Status;
+ IO_STATUS_BLOCK IoStatusBlock;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE FileHandle;
+ UNICODE_STRING UnicodeString;
+
+ DbgPtrAssert( FileName );
+ DbgPtrAssert( Error );
+
+ *Error = FALSE;
+
+ UnicodeString.Buffer = (PWSTR)FileName->GetWSTR();
+ UnicodeString.Length = FileName->QueryChCount() * sizeof( WCHAR );
+ UnicodeString.MaximumLength = UnicodeString.Length;
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ &UnicodeString,
+ OBJ_CASE_INSENSITIVE,
+ 0,
+ 0 );
+
+ Status = NtOpenFile( &FileHandle,
+ FILE_GENERIC_READ,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ FILE_NON_DIRECTORY_FILE );
+
+ NtClose( FileHandle );
+
+ if( NT_SUCCESS( Status ) ) {
+
+ return TRUE;
+ }
+
+ if( Status == STATUS_ACCESS_DENIED ||
+ Status == STATUS_SHARING_VIOLATION ) {
+
+ *Error = FALSE;
+ return TRUE;
+ }
+
+ if( Status != STATUS_OBJECT_NAME_NOT_FOUND &&
+ Status != STATUS_OBJECT_PATH_NOT_FOUND &&
+ Status != STATUS_NO_SUCH_FILE ) {
+
+ *Error = TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
+BOOLEAN
+GenerateHostFileName(
+ IN PCWSTRING HostDriveName,
+ OUT PWSTRING HostFileName,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This function chooses a name for the host file. Names are of
+ the form DBLSPACE.xxx; DBLSPACE.000 is reserved for drives
+ created by compressing an existing drive.
+
+Arguments:
+
+ HostDriveName -- Supplies the NT name of the host drive.
+ HostFileName -- Receives the generated name.
+ Message -- Supplies an outlet for messages.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ ULONG i;
+ WCHAR NameBuffer[16];
+ DSTRING Current, BackSlash;
+ BOOLEAN Error;
+
+ DbgPtrAssert( HostDriveName );
+ DbgPtrAssert( HostFileName );
+
+ if( !BackSlash.Initialize( "\\" ) ) {
+
+ Message ? Message->Set( MSG_FMT_NO_MEMORY ) : 1;
+ Message ? Message->Display( "" ) : 1;
+ return FALSE;
+ }
+
+ for( i = 1; i < 255; i++ ) {
+
+ swprintf( NameBuffer, (LPCWSTR)L"DBLSPACE.%03d", i );
+
+ if( !HostFileName->Initialize( NameBuffer ) ||
+ !Current.Initialize( HostDriveName ) ||
+ !Current.Strcat( &BackSlash ) ||
+ !Current.Strcat( HostFileName ) ) {
+
+ Message ? Message->Set( MSG_FMT_NO_MEMORY ) : 1;
+ Message ? Message->Display( "" ) : 1;
+ return FALSE;
+ }
+
+ if( !FileExists( &Current, &Error, Message ) ) {
+
+ return !Error;
+ }
+ }
+
+ return FALSE;
+}
+
+BOOLEAN
+FatDbDeleteCvf(
+ IN PCWSTRING CvfFileName,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This method deletes a compressed volume file.
+
+Arguments:
+
+ CvfFileName -- Supplies the name of the file.
+ Message -- Supplies an outlet for messages.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ IO_STATUS_BLOCK IoStatusBlock;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING UnicodeString;
+ FILE_DISPOSITION_INFORMATION DispositionInfo;
+ HANDLE FileHandle;
+ NTSTATUS Status;
+
+ UnicodeString.Buffer = (PWSTR)CvfFileName->GetWSTR();
+ UnicodeString.Length = CvfFileName->QueryChCount() * sizeof( WCHAR );
+ UnicodeString.MaximumLength = UnicodeString.Length;
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ &UnicodeString,
+ OBJ_CASE_INSENSITIVE,
+ 0,
+ 0 );
+
+ Status = NtOpenFile( &FileHandle,
+ FILE_GENERIC_READ | FILE_GENERIC_WRITE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_DELETE,
+ FILE_NON_DIRECTORY_FILE );
+
+ if( NT_SUCCESS( Status ) ) {
+
+ DispositionInfo.DeleteFile = TRUE;
+
+ Status = NtSetInformationFile( FileHandle,
+ &IoStatusBlock,
+ &DispositionInfo,
+ sizeof( DispositionInfo ),
+ FileDispositionInformation );
+ }
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ if( Status == STATUS_ACCESS_DENIED ||
+ Status == STATUS_SHARING_VIOLATION ) {
+
+ Message->Set( MSG_DASD_ACCESS_DENIED );
+ Message->Display( "" );
+
+ } else {
+
+ Message->Set( MSG_DBLSPACE_CANT_DELETE_CVF );
+ Message->Display( "" );
+ }
+
+ return FALSE;
+ }
+
+ NtClose( FileHandle );
+ return TRUE;
+}
+
+
+BOOLEAN
+FAR APIENTRY
+FatDbCreateCvf(
+ IN PCWSTRING HostDriveName,
+ IN PCWSTRING HostFileName,
+ IN ULONG Size,
+ IN OUT PMESSAGE Message,
+ OUT PWSTRING CreatedName
+ )
+/*++
+
+Routine Description:
+
+ This function creates a Compressed Volume File to
+ hold a Double Space volume.
+
+Arguments:
+
+ HostDriveName -- Supplies the NT name of the drive which
+ will contain the new volume's Compressed
+ Volume File.
+ HostFileName -- Supplies the name of the Compressed Volume
+ File. If this parameter is NULL, this
+ function will choose a name.
+ Size -- Supplies the size of the Compressed Volume File.
+ Message -- Supplies an outlet for messages (may be NULL)
+ HostFileFullName -- Receives the unqualified name of the
+ newly-created host file.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ BYTE SectorZeroBuffer[512];
+ CVF_HEADER CvfHeader;
+ PPACKED_CVF_HEADER PackedCvfHeader;
+ IO_STATUS_BLOCK IoStatusBlock;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ UNICODE_STRING FileNameString;
+ DSTRING HostFileFullName, BackSlash;
+ DP_DRIVE HostDrive;
+ BIG_INT Offset, InitialSize;
+ LARGE_INTEGER L;
+ FILE_DISPOSITION_INFORMATION DispositionInfo;
+ HANDLE FileHandle;
+ ULONG MaximumCapacity;
+ ULONG OldAttributes = 0;
+ NTSTATUS Status;
+ MSGID MsgId;
+
+
+ // Make sure we have a file name.
+ //
+ if( HostFileName != NULL ) {
+
+ if( !CreatedName->Initialize( HostFileName ) ) {
+
+ Message ? Message->Set( MSG_FMT_NO_MEMORY ) : 1;
+ Message ? Message->Display( "" ) : 1;
+ return FALSE;
+ }
+
+ } else {
+
+ if( !GenerateHostFileName( HostDriveName, CreatedName, Message ) ) {
+
+ Message ? Message->Set( MSG_DBLSPACE_NO_CVF_NAME ) : 1;
+ Message ? Message->Display( "" ) : 1;
+ return FALSE;
+ }
+ }
+
+ // Construct the fully-qualified name of the Compressed Volume File.
+ //
+ if( !BackSlash.Initialize( "\\" ) ||
+ !HostFileFullName.Initialize( HostDriveName ) ||
+ !HostFileFullName.Strcat( &BackSlash ) ||
+ !HostFileFullName.Strcat( CreatedName ) ) {
+
+ Message ? Message->Set( MSG_FMT_NO_MEMORY ) : 1;
+ Message ? Message->Display( "" ) : 1;
+ return FALSE;
+ }
+
+
+ // The maximum capacity of the new file is based on the
+ // size of the host drive. Initialize the DP_DRIVE as
+ // a transient drive, so that it won't keep a handle open.
+ //
+ // Note that MaximumCapacity is rounded up to the next
+ // highest multiple of 8 Meg.
+ //
+ if( !HostDrive.Initialize( HostDriveName, Message, FALSE, FALSE ) ) {
+
+ return FALSE;
+ }
+
+ MaximumCapacity =
+ ComputeMaximumCapacity( HostDrive.QuerySectors().GetLowPart() *
+ HostDrive.QuerySectorSize() );
+
+ MaximumCapacity = ( (MaximumCapacity + EIGHT_MEG - 1 ) / EIGHT_MEG ) * EIGHT_MEG;
+
+
+ // Create the file.
+ //
+ FileNameString.Buffer = (PWSTR)HostFileFullName.GetWSTR();
+ FileNameString.Length = HostFileFullName.QueryChCount() * sizeof( WCHAR );
+ FileNameString.MaximumLength = FileNameString.Length;
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &FileNameString,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+ InitialSize = Size;
+ L = InitialSize.GetLargeInteger();
+
+ Status = NtCreateFile( &FileHandle,
+ FILE_GENERIC_READ | FILE_GENERIC_WRITE,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ &L,
+ FILE_ATTRIBUTE_NORMAL,
+ 0, // No sharing.
+ FILE_CREATE,
+ FILE_NON_DIRECTORY_FILE | FILE_WRITE_THROUGH,
+ NULL, // No EA's
+ 0
+ );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ if( Message ) {
+
+ if( Status == STATUS_OBJECT_NAME_COLLISION ||
+ Status == STATUS_FILE_IS_A_DIRECTORY ) {
+
+ MsgId = MSG_DBLSPACE_CVF_NAME_EXISTS;
+
+ } else if ( Status == STATUS_DISK_FULL ) {
+
+ MsgId = MSG_DBLSPACE_NO_SPACE_ON_HOST;
+
+ } else {
+
+ MsgId = MSG_DBLSPACE_CVF_CREATE_ERROR;
+ }
+
+ Message->Set( MsgId );
+ Message->Display( "" );
+ }
+
+ return FALSE;
+ }
+
+ // Fill the file with zeroes.
+ //
+ if( !ZeroFillFile( FileHandle, Size, Message ) ) {
+
+ DispositionInfo.DeleteFile = TRUE;
+
+ NtSetInformationFile( FileHandle,
+ &IoStatusBlock,
+ &DispositionInfo,
+ sizeof( DispositionInfo ),
+ FileDispositionInformation );
+
+ NtClose( FileHandle );
+ return FALSE;
+ }
+
+ // Create the Compressed Volume File Header:
+ //
+ if( !CreateCvfHeader( &CvfHeader, MaximumCapacity ) ) {
+
+ DispositionInfo.DeleteFile = TRUE;
+
+ NtSetInformationFile( FileHandle,
+ &IoStatusBlock,
+ &DispositionInfo,
+ sizeof( DispositionInfo ),
+ FileDispositionInformation );
+
+ NtClose( FileHandle );
+ return FALSE;
+ }
+
+ // Now fill in the value of Virtual Sectors.
+ //
+ CvfHeader.Bpb.LargeSectors = ComputeVirtualSectors( &CvfHeader, Size );
+
+ // Fill in the packed CVF Header and write it to the
+ // newly-created file.
+ //
+ memset( SectorZeroBuffer, 0, 512 );
+
+ PackedCvfHeader = (PPACKED_CVF_HEADER)SectorZeroBuffer;
+
+ CvfPackCvfHeader( PackedCvfHeader, &CvfHeader );
+
+
+ Offset = 0;
+ L = Offset.GetLargeInteger();
+
+ Status = NtWriteFile( FileHandle,
+ NULL,
+ NULL,
+ NULL,
+ &IoStatusBlock,
+ SectorZeroBuffer,
+ 512,
+ &L,
+ NULL );
+
+ if( !NT_SUCCESS( Status ) ) {
+
+ DispositionInfo.DeleteFile = TRUE;
+
+ NtSetInformationFile( FileHandle,
+ &IoStatusBlock,
+ &DispositionInfo,
+ sizeof( DispositionInfo ),
+ FileDispositionInformation );
+
+ NtClose( FileHandle );
+
+ Message ? Message->Set( MSG_DBLSPACE_CREATE_DISK_ERROR ) : 1;
+ Message ? Message->Display( "" ) : 1;
+ return FALSE;
+ }
+
+ NtClose( FileHandle );
+
+ IFS_SYSTEM::FileSetAttributes( &HostFileFullName,
+ FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM,
+ &OldAttributes );
+
+ return TRUE;
+}
+#endif
+
+
+BOOLEAN
+FAR APIENTRY
+FatDbCreate(
+ IN PCWSTRING HostDriveName,
+ IN PCWSTRING HostFileName,
+ IN ULONG Size,
+ IN OUT PMESSAGE Message,
+ IN PCWSTRING LabelString,
+ OUT PWSTRING CreatedName
+ )
+/*++
+
+Routine Description:
+
+ This function creates and formats a Double Space volume.
+
+Arguments:
+
+ HostDriveName -- Supplies the name of the host drive
+ HostFileName -- Supplies the unqualified file name for
+ the new Compressed Volume File. May be
+ NULL, in which case this function chooses
+ a name.
+ Size -- Supplies the initial size of the Compressed
+ Volume File.
+ LabelString -- Supplies the volume label. May be NULL.
+ Message -- Supplies an outlet for messages.
+ CreatedFile -- Receives the unqualified name of the
+ newly-created host file.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+#if !defined( _READ_WRITE_DOUBLESPACE_ )
+
+ return FALSE;
+
+#else // _READ_WRITE_DOUBLESPACE_
+
+ FATDB_VOL FatDbVol;
+ DSTRING FatString, FileSystemName, HostFileFullName, BackSlash;
+
+
+ // Make sure that the host volume is FAT.
+ //
+ if( !FatString.Initialize( "FAT" ) ) {
+
+ Message ? Message->Set( MSG_FMT_NO_MEMORY ) : 1;
+ Message ? Message->Display( "" ) : 1;
+ return FALSE;
+ }
+
+ if( !IFS_SYSTEM::QueryFileSystemName( HostDriveName, &FileSystemName ) ||
+ FileSystemName.Strcmp( &FatString ) != 0 ) {
+
+ Message ? Message->Set( MSG_DBLSPACE_HOST_NOT_FAT ) : 1;
+ Message ? Message->Display( "" ) : 1;
+ return FALSE;
+ }
+
+ // Create the Compressed Volume File:
+ //
+ if( !FatDbCreateCvf( HostDriveName,
+ HostFileName,
+ Size,
+ Message,
+ CreatedName ) ) {
+
+ return FALSE;
+ }
+
+ // Initialize a FATDB_VOL and Format it.
+ //
+ if( !BackSlash.Initialize( "\\" ) ||
+ !HostFileFullName.Initialize( HostDriveName ) ||
+ !HostFileFullName.Strcat( &BackSlash ) ||
+ !HostFileFullName.Strcat( CreatedName ) ) {
+
+ Message ? Message->Set( MSG_FMT_NO_MEMORY ) : 1;
+ Message ? Message->Display( "" ) : 1;
+ return FALSE;
+ }
+
+ if( !FatDbVol.Initialize( NULL,
+ &HostFileFullName,
+ Message ) ) {
+
+ return FALSE;
+ }
+
+ return( FatDbVol.Format( LabelString,
+ Message,
+ 0,
+ 0 ) );
+#endif
+}
+
+BOOLEAN
+FAR APIENTRY
+FatDbDelete(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This function deletes a mounted Double Space drive.
+
+Arguments:
+
+ NtDriveName -- Supplies the NT name of the compressed drive.
+ Message -- Supplies an outlet for messages.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+#if !defined( _READ_WRITE_DOUBLESPACE_ )
+
+ return FALSE;
+
+#else // _READ_WRITE_DOUBLESPACE_
+
+ DSTRING HostFileName;
+ DSTRING FileSystemName;
+ BOOLEAN IsCompressed;
+ PLOG_IO_DP_DRIVE Drive;
+
+ if( (Drive = NEW LOG_IO_DP_DRIVE) == NULL ) {
+
+ Message->Set( MSG_FMT_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Drive->Initialize( NtDriveName, Message ) ||
+ !Drive->QueryMountedFileSystemName( &FileSystemName, &IsCompressed ) ||
+ !IsCompressed ) {
+
+ DELETE( Drive );
+ Message->Set( MSG_DBLSPACE_NOT_COMPRESSED_NO_NAME );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !Drive->Lock() ) {
+
+ DELETE( Drive );
+ Message->Set( MSG_CANT_LOCK_THE_DRIVE );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+
+ if( !QueryHostFileName( NtDriveName, &HostFileName ) ) {
+
+ DELETE( Drive );
+ Message->Set( MSG_DBLSPACE_CANT_GET_CVF_NAME );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ // Delete the drive object to dismount the drive and
+ // close its handle.
+ //
+ DELETE( Drive );
+
+ Message->Set( MSG_DBLSPACE_DISMOUNTED_NO_NAME );
+ Message->Display( "" );
+
+ //
+ // Delete the host file.
+ //
+ return( FatDbDeleteCvf( &HostFileName, Message ) );
+ return TRUE;
+#endif
+}
+
+
+BOOLEAN
+FAR APIENTRY
+FatDbFormat(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Quick,
+ IN MEDIA_TYPE MediaType,
+ IN PCWSTRING LabelString,
+ IN ULONG ClusterSize
+ )
+/*++
+
+Routine Description:
+
+ This function formats an existing, mounted Compressed Volume.
+
+Arguments:
+
+ NtDriveName - Supplies the NT style drive name of the volume to format.
+ Message - Supplies an outlet for messages.
+ Quick - Supplies whether or not to do a quick format.
+ This parameter is ignored; Double-Space format
+ always uses quick format.
+ MediaType - Supplies the media type of the drive.
+ This parameter is ignored; Double-Space always
+ uses a media byte of 0xf8.
+ LabelString - Supplies a volume label to be set on the volume after
+ format.
+ ClusterSize - This parameter is ignored.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+#if !defined( _READ_WRITE_DOUBLESPACE_ )
+
+ return FALSE;
+
+#else // _READ_WRITE_DOUBLESPACE_
+
+ FATDB_VOL FatDbVol;
+ PDP_DRIVE DpDrive;
+ DSTRING HostFileName;
+
+ UNREFERENCED_PARAMETER( Quick );
+ UNREFERENCED_PARAMETER( MediaType );
+ UNREFERENCED_PARAMETER( ClusterSize );
+
+ if( !QueryHostFileName( NtDriveName, &HostFileName ) ) {
+
+ Message->Set( MSG_DBLSPACE_CANT_GET_CVF_NAME );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ return( !FatDbVol.Initialize( NtDriveName,
+ &HostFileName,
+ Message,
+ FALSE ) &&
+ !FatDbVol.Format( LabelString, Message, ClusterSize ) );
+#endif
+}
+
+BOOLEAN
+FAR APIENTRY
+FatDbChkdsk(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Fix,
+ IN BOOLEAN Verbose,
+ IN BOOLEAN OnlyIfDirty,
+ IN BOOLEAN Recover,
+ IN PCWSTRING PathToCheck
+ )
+{
+ FATDB_VOL FatDbVol;
+
+ UNREFERENCED_PARAMETER(PathToCheck);
+
+ return (!FatDbVol.Initialize(NtDriveName,
+ PathToCheck,
+ Message,
+ FALSE ) || /* ExclusiveWrite */
+ !FatDbVol.ChkDsk(Fix ? TotalFix : CheckOnly,
+ Message,
+ Verbose,
+ OnlyIfDirty,
+ Recover,
+ Recover
+ ) );
+}
diff --git a/private/utils/ufat/src/eaheader.cxx b/private/utils/ufat/src/eaheader.cxx
new file mode 100644
index 000000000..cbf1ed807
--- /dev/null
+++ b/private/utils/ufat/src/eaheader.cxx
@@ -0,0 +1,215 @@
+#include <pch.cxx>
+
+#define _UFAT_MEMBER_
+#include "ufat.hxx"
+
+#include "error.hxx"
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( EA_HEADER, CLUSTER_CHAIN, UFAT_EXPORT );
+
+VOID
+EA_HEADER::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Constructor for EA_HEADER. Initializes private data to default values.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _ht = NULL;
+ _off_tab_size = 0;
+}
+
+
+UFAT_EXPORT
+EA_HEADER::~EA_HEADER(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for EA_HEADER. Frees memory.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+UFAT_EXPORT
+BOOLEAN
+EA_HEADER::Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN PFAT_SA FatSuperArea,
+ IN PCFAT Fat,
+ IN USHORT StartingCluster,
+ IN USHORT LengthOfChain
+ )
+/*++
+
+Routine Description:
+
+ This routine prepares this object for reads and writes. It also
+ prepares the object with memory so that it can accept queries.
+
+ If the length of the cluster chain is not specified this routine
+ will read in the first cluster in order to compute the actual
+ length of the cluster chain.
+
+Arguments:
+
+ Mem - Supplies the memory for the cluster chain.
+ Drive - Supplies the drive that contains the EA file.
+ FatSuperArea - Supplies information about the FAT file system.
+ Fat - Supplies the file allocation table.
+ StartingCluster - Supplies the first cluster of the EA file.
+ LengthOfChain - Supplies the number of clusters necessary to contain
+ the EA file header, base table and offset table.
+
+Return Value:
+
+ FALSE - Initialization failed.
+ TRUE - Initialization succeeded.
+
+--*/
+{
+ HMEM hmem;
+ INT i;
+
+ Destroy();
+
+ // See if the length of the chain needs to be computed.
+ if (!LengthOfChain) {
+ if (!hmem.Initialize() ||
+ !CLUSTER_CHAIN::Initialize(&hmem, Drive, FatSuperArea, Fat,
+ StartingCluster, 1) ||
+ !(_ht = (PEA_HEADER_AND_TABLE) GetBuf()) ||
+ !CLUSTER_CHAIN::Read() ||
+ !(_ht->Header.Signature == HeaderSignature) ||
+ !(_ht->Header.FormatType == 0) ||
+ !(_ht->Header.LogType == 0)) {
+ perrstk->push(ERR_NOT_INIT, QueryClassId());
+ Destroy();
+ return FALSE;
+ }
+ for (i = 0; i < BaseTableSize && !_ht->Table.BaseTab[i]; i++) {
+ }
+ if (i == BaseTableSize) {
+ perrstk->push(ERR_NOT_INIT, QueryClassId());
+ Destroy();
+ return FALSE;
+ }
+ LengthOfChain = _ht->Table.BaseTab[i];
+ }
+
+ if (!CLUSTER_CHAIN::Initialize(Mem, Drive, FatSuperArea, Fat,
+ StartingCluster, LengthOfChain) ||
+ !(_ht = (PEA_HEADER_AND_TABLE) GetBuf())) {
+ perrstk->push(ERR_NOT_INIT, QueryClassId());
+ Destroy();
+ return FALSE;
+ }
+
+ // Compute the number of offset table entries.
+ _off_tab_size = Drive->QuerySectorSize()*
+ FatSuperArea->QuerySectorsPerCluster()*
+ LengthOfChain;
+ _off_tab_size -= sizeof(EA_FILE_HEADER);
+ _off_tab_size -= BaseTableSize*sizeof(USHORT);
+ _off_tab_size /= sizeof(USHORT);
+
+ if (_off_tab_size < 0) {
+ perrstk->push(ERR_NOT_INIT, QueryClassId());
+ Destroy();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+UFAT_EXPORT
+USHORT
+EA_HEADER::QueryEaSetClusterNumber(
+ IN USHORT Handle
+ ) CONST
+/*++
+
+Routine Description:
+
+ This function computes the EA cluster number for an EA set in the
+ EA file. This function will return 0 if the handle is invalid or
+ outside the range of the table.
+
+Arguments:
+
+ Handle - Supplies the handle for the desired EA set.
+
+Return Value:
+
+ Returns the EA cluster number for the EA set whose handle is 'Handle'.
+
+--*/
+{
+ USHORT off;
+
+ if (!_ht) {
+ perrstk->push(ERR_NOT_INIT, QueryClassId());
+ return 0;
+ }
+
+ Handle = (( Handle << 1 ) >> 1 );
+
+ if ((LONG)Handle >= _off_tab_size ||
+ (off = _ht->Table.OffTab[Handle]) == InvalidHandle) {
+ return 0;
+ }
+
+ return (( off << 1 ) >> 1 ) + _ht->Table.BaseTab[Handle>>7];
+}
+
+
+VOID
+EA_HEADER::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine puts this object in a blank state. It is not necessary
+ to call this routine between calls to Init because Init calls this
+ routine automatically.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _ht = NULL;
+ _off_tab_size = 0;
+}
diff --git a/private/utils/ufat/src/easet.cxx b/private/utils/ufat/src/easet.cxx
new file mode 100644
index 000000000..11b63c76b
--- /dev/null
+++ b/private/utils/ufat/src/easet.cxx
@@ -0,0 +1,404 @@
+#include <pch.cxx>
+
+#define _UFAT_MEMBER_
+#include "ufat.hxx"
+
+#include "error.hxx"
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( EA_SET, CLUSTER_CHAIN, UFAT_EXPORT );
+
+VOID
+EA_SET::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Constructor for EA_SET. Sets private data to default values.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ memset(&_eahdr, 0, sizeof(_eahdr));
+ _size = 0;
+ _size_imposed = FALSE;
+ _current_ea = NULL;
+ _current_index = 0;
+}
+
+
+UFAT_EXPORT
+EA_SET::~EA_SET(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for EA_SET. Frees memory.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+UFAT_EXPORT
+BOOLEAN
+EA_SET::Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN PFAT_SA FatSuperArea,
+ IN PCFAT Fat,
+ IN USHORT ClusterNumber,
+ IN USHORT LengthOfChain
+ )
+/*++
+
+Routine Description:
+
+ This routine initialize the EA_SET to model the EA set which resides
+ at FAT cluster 'ClusterNumber'.
+
+Arguments:
+
+ Mem - Supplies the memory for the cluster chain.
+ Drive - Supplies the drive where the EA set is contained.
+ FatSuperArea - Supplies the important drive parameters.
+ Fat - Supplies the file allocation table.
+ StartingCluster - Supplies the starting cluster of the EA set.
+ LengthOfChain - Supplies the length of the cluster chai which contains
+ the EA set.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ HMEM hmem;
+ ULONG cluster_size;
+ ULONG sector_size;
+
+ Destroy();
+
+ if (!FatSuperArea || !Drive || !(sector_size = Drive->QuerySectorSize())) {
+ perrstk->push(ERR_NOT_INIT, QueryClassId());
+ Destroy();
+ return FALSE;
+ }
+
+ cluster_size = sector_size*FatSuperArea->QuerySectorsPerCluster();
+
+ if (!LengthOfChain) {
+ if (!hmem.Initialize() ||
+ !CLUSTER_CHAIN::Initialize(&hmem, Drive, FatSuperArea, Fat,
+ ClusterNumber, 1) ||
+ !Read()) {
+ perrstk->push(ERR_NOT_INIT, QueryClassId());
+ Destroy();
+ return FALSE;
+ }
+
+ _size = _eahdr.TotalSize + SizeOfEaHdr - sizeof(LONG);
+ _size_imposed = TRUE;
+
+ if (_size%cluster_size) {
+ LengthOfChain = (USHORT) (_size/cluster_size + 1);
+ } else {
+ LengthOfChain = (USHORT) (_size/cluster_size);
+ }
+ } else {
+ _size = cluster_size*LengthOfChain;
+ _size_imposed = FALSE;
+ }
+
+
+ if (!CLUSTER_CHAIN::Initialize(Mem, Drive, FatSuperArea, Fat,
+ ClusterNumber, LengthOfChain)) {
+ perrstk->push(ERR_NOT_INIT, QueryClassId());
+ Destroy();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+UFAT_EXPORT
+BOOLEAN
+EA_SET::Read(
+ )
+/*++
+
+Routine Description:
+
+ This routine reads the cluster chain and then unpacks the ea header.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ LONG size;
+
+
+ if (!CLUSTER_CHAIN::Read() || !UnPackEaHeader()) {
+ return FALSE;
+ }
+
+ size = _eahdr.TotalSize + SizeOfEaHdr - sizeof(LONG);
+ if (size < _size) {
+ _size = size;
+ _size_imposed = TRUE;
+ }
+
+ return TRUE;
+}
+
+
+UFAT_EXPORT
+PEA
+EA_SET::GetEa(
+ IN ULONG Index,
+ OUT PLONG EaSize,
+ OUT PBOOLEAN PossiblyMore
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the Index'th EA. An Index of 0
+ indicates the first EA and so on. A NULL pointer will be returned if
+ the Index'th EA does not exist.
+
+ This routine will validate the EA before returning it. If the EA is
+ invalid then NULL will be returned.
+
+ The return value 'PossiblyMore' will only be computed in the event
+ that the EA at index 'Index' can't be found. It is used to indicate
+ that there may be another EA in the next cluster of the cluster chain.
+
+Arguments:
+
+ Index - Supplies which EA is requested.
+ EaSize - Returns the size of the EA.
+ PossiblyMore - Returns TRUE if there may possibly be more EAs in
+ a cluster beyond the boundary of the cluster chain.
+ Returns FALSE if this is impossible.
+
+Return Value:
+
+ A pointer to an EA structure or NULL.
+
+--*/
+{
+ ULONG i;
+ PEA r;
+ PCHAR p, b;
+ ULONG offset;
+
+ if (PossiblyMore) {
+ *PossiblyMore = FALSE;
+ }
+
+ if (!(b = (PCHAR) GetBuf())) {
+ perrstk->push(ERR_NOT_INIT, QueryClassId());
+ return NULL;
+ }
+
+ if (!_current_ea || Index < _current_index) {
+ p = (PCHAR) (r = (PEA) (b + SizeOfEaHdr));
+
+ if (!r->NameSize || !r->ValueSize[0] && !r->ValueSize[1]) {
+ return NULL;
+ }
+
+ offset = sizeof(EA) + r->NameSize + r->ValueSize[0] +
+ (r->ValueSize[1]<<8);
+
+ if (p - b + offset > (ULONG)_size) {
+ if (PossiblyMore && !_size_imposed) {
+ *PossiblyMore = TRUE;
+ }
+
+ return NULL;
+ }
+
+ if (p[sizeof(EA) + r->NameSize - 1]) {
+ return NULL;
+ }
+
+ _current_index = 0;
+ } else {
+ p = (PCHAR) (r = _current_ea);
+
+ offset = sizeof(EA) + r->NameSize + r->ValueSize[0] +
+ (r->ValueSize[1]<<8);
+ }
+
+ for (i = _current_index; i < Index; i++) {
+ r = (PEA) (p += offset);
+
+ if (p - b + sizeof(EA) > (ULONG)_size) {
+ if (PossiblyMore && !_size_imposed) {
+ *PossiblyMore = TRUE;
+ }
+
+ return NULL;
+ }
+
+ if (!r->NameSize || !r->ValueSize[0] && !r->ValueSize[1]) {
+ return NULL;
+ }
+
+ offset = sizeof(EA) + r->NameSize + r->ValueSize[0] +
+ (r->ValueSize[1]<<8);
+
+ if (p - b + offset > (ULONG)_size) {
+ if (PossiblyMore && !_size_imposed) {
+ *PossiblyMore = TRUE;
+ }
+
+ return NULL;
+ }
+
+ if (p[sizeof(EA) + r->NameSize - 1]) {
+ return NULL;
+ }
+ }
+
+ _current_index = i;
+ _current_ea = r;
+
+ if (EaSize) {
+ *EaSize = offset;
+ }
+
+ return r;
+}
+
+
+VOID
+EA_SET::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the object to its initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ memset(&_eahdr, 0, sizeof(_eahdr));
+ _size = 0;
+ _size_imposed = FALSE;
+ _current_ea = NULL;
+ _current_index = 0;
+}
+
+
+BOOLEAN
+EA_SET::PackEaHeader(
+ )
+/*++
+
+Routine Description:
+
+ This routine packs the EA set header.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PPACKED_EA_HDR peahdr;
+
+ if (!(peahdr = (PPACKED_EA_HDR) GetBuf())) {
+ perrstk->push(ERR_NOT_INIT, QueryClassId());
+ return FALSE;
+ }
+
+ peahdr->Signature = _eahdr.Signature;
+ peahdr->OwnHandle = _eahdr.OwnHandle;
+ peahdr->NeedCount = _eahdr.NeedCount;
+ memcpy(peahdr->OwnerFileName, _eahdr.OwnerFileName, 14);
+ memcpy(peahdr->Reserved, &_eahdr.Reserved, sizeof(ULONG));
+ memcpy(peahdr->TotalSize, &_eahdr.TotalSize, sizeof(LONG));
+
+ return TRUE;
+}
+
+
+BOOLEAN
+EA_SET::UnPackEaHeader(
+ )
+/*++
+
+Routine Description:
+
+ This routine unpacks the EA set header.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PPACKED_EA_HDR peahdr;
+
+ if (!(peahdr = (PPACKED_EA_HDR) GetBuf())) {
+ perrstk->push(ERR_NOT_INIT, QueryClassId());
+ return FALSE;
+ }
+
+ _eahdr.Signature = peahdr->Signature;
+ _eahdr.OwnHandle = peahdr->OwnHandle;
+ _eahdr.NeedCount = peahdr->NeedCount;
+ memcpy(_eahdr.OwnerFileName, peahdr->OwnerFileName, 14);
+ memcpy(&_eahdr.Reserved, peahdr->Reserved, sizeof(ULONG));
+ memcpy(&_eahdr.TotalSize, peahdr->TotalSize, sizeof(LONG));
+
+ return TRUE;
+}
diff --git a/private/utils/ufat/src/entry.cxx b/private/utils/ufat/src/entry.cxx
new file mode 100644
index 000000000..2e6c99bc8
--- /dev/null
+++ b/private/utils/ufat/src/entry.cxx
@@ -0,0 +1,496 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ entry.cxx
+
+Abstract:
+
+ This module contains the entry points for UFAT.DLL. These
+ include:
+
+ Chkdsk
+ Format
+
+Author:
+
+ Bill McJohn (billmc) 31-05-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#include "error.hxx"
+#include "path.hxx"
+#include "ifssys.hxx"
+#include "filter.hxx"
+#include "system.hxx"
+#include "dir.hxx"
+#include "rcache.hxx"
+#ifdef DBLSPACE_ENABLED
+#include "dblentry.hxx"
+#endif // DBLSPACE_ENABLED
+
+extern "C" {
+ #include "nturtl.h"
+}
+
+#include "message.hxx"
+#include "rtmsg.h"
+#include "ifsserv.hxx"
+#include "ifsentry.hxx"
+
+
+VOID
+ReportFileNotFoundError(
+ IN PPATH PathToCheck,
+ IN OUT PMESSAGE Message
+ )
+{
+ PWSTRING dirs_and_name;
+
+ if (dirs_and_name = PathToCheck->QueryDirsAndName()) {
+ Message->Set(MSG_FILE_NOT_FOUND);
+ Message->Display("%W", dirs_and_name);
+ DELETE(dirs_and_name);
+ }
+}
+
+
+BOOLEAN
+FAR APIENTRY
+Chkdsk(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Fix,
+ IN BOOLEAN Verbose,
+ IN BOOLEAN OnlyIfDirty,
+ IN BOOLEAN Recover,
+ IN PPATH PathToCheck,
+ IN BOOLEAN Extend,
+ IN BOOLEAN ResizeLogFile,
+ IN ULONG LogFileSize,
+ IN PULONG ExitStatus
+ )
+/*++
+
+Routine Description:
+
+ Check a FAT volume.
+
+Arguments:
+
+ DosDrivName supplies the name of the drive to check
+ Message supplies an outlet for messages
+ Fix TRUE if Chkdsk should fix errors
+ Verbose TRUE if Chkdsk should list every file it finds
+ OnlyIfDirty TRUE if the drive should be checked only if
+ it is dirty
+ Recover TRUE if Chkdsk should verify all of the sectors
+ on the disk.
+ PathToCheck Supplies a path to files Chkdsk should check
+ for contiguity
+ Extend Unused (should always be FALSE)
+ ExitStatus Returns exit status to chkdsk.exe
+
+Return Value:
+
+ TRUE if successful.
+
+--*/
+{
+ FAT_VOL FatVol;
+ BOOLEAN r;
+ PWSTRING dir_name;
+ PWSTRING name;
+ PWSTRING prefix_name;
+ FSN_FILTER filter;
+ PFSN_DIRECTORY directory;
+ PARRAY file_array;
+ PDSTRING files_to_check;
+ ULONG num_files;
+ ULONG i;
+ PFSNODE fsnode;
+ PATH dir_path;
+ DSTRING backslash;
+ PPATH full_path;
+ PREAD_CACHE read_cache;
+ ULONG exit_status;
+
+ if (NULL == ExitStatus) {
+ ExitStatus = &exit_status;
+ }
+
+ if (Extend || !FatVol.Initialize(NtDriveName, Message)) {
+ *ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
+ return FALSE;
+ }
+
+ if (Fix && !FatVol.Lock()) {
+
+ if (FatVol.IsFloppy()) {
+
+ Message->Set(MSG_CANT_LOCK_THE_DRIVE);
+ Message->Display();
+
+ } else {
+
+ // The client wants to fix the drive, but we can't lock it.
+ // Offer to fix it on next reboot.
+ //
+ Message->Set(MSG_CHKDSK_ON_REBOOT_PROMPT);
+ Message->Display("");
+
+ if( Message->IsYesResponse( FALSE ) ) {
+
+ if( FatVol.ForceAutochk( Recover, FALSE, 0, NtDriveName ) ) {
+
+ Message->Set(MSG_CHKDSK_SCHEDULED);
+ Message->Display();
+
+ } else {
+
+ Message->Set(MSG_CHKDSK_CANNOT_SCHEDULE);
+ Message->Display();
+ }
+ }
+ }
+
+ *ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
+
+ return FALSE;
+ }
+
+ // Try to enable caching, if there's not enough resources then
+ // just run without a cache.
+
+ if ((read_cache = NEW READ_CACHE) &&
+ read_cache->Initialize(&FatVol, 75)) {
+
+ FatVol.SetCache(read_cache);
+
+ } else {
+ DELETE(read_cache);
+ }
+
+
+ r = FatVol.ChkDsk( Fix ? TotalFix : CheckOnly,
+ Message,
+ Verbose,
+ OnlyIfDirty,
+ Recover,
+ Recover,
+ FALSE,
+ 0,
+ ExitStatus );
+
+ if (!r) {
+ return FALSE;
+ }
+
+ if (PathToCheck) {
+
+ if (!(name = PathToCheck->QueryName()) ||
+ name->QueryChCount() == 0) {
+
+ DELETE(name);
+ return TRUE;
+ }
+
+ if (!(full_path = PathToCheck->QueryFullPath())) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ DELETE(name);
+ return FALSE;
+ }
+
+ if (!FatVol.Initialize(NtDriveName, Message)) {
+ DELETE(full_path);
+ DELETE(name);
+ return FALSE;
+ }
+
+ if (!(prefix_name = full_path->QueryPrefix()) ||
+ !dir_path.Initialize(prefix_name)) {
+
+ ReportFileNotFoundError(full_path, Message);
+ DELETE(name);
+ DELETE(prefix_name);
+ DELETE(full_path);
+ return FALSE;
+ }
+
+ if (!(directory = SYSTEM::QueryDirectory(&dir_path)) ||
+ !filter.Initialize() ||
+ !filter.SetFileName(name)) {
+
+ ReportFileNotFoundError(full_path, Message);
+ DELETE(name);
+ DELETE(prefix_name);
+ DELETE(directory);
+ DELETE(full_path);
+ return FALSE;
+ }
+
+ DELETE(prefix_name);
+
+ if (!(file_array = directory->QueryFsnodeArray(&filter))) {
+
+ ReportFileNotFoundError(full_path, Message);
+ DELETE(name);
+ DELETE(directory);
+ DELETE(full_path);
+ return FALSE;
+ }
+
+ DELETE(directory);
+
+ if (!(num_files = file_array->QueryMemberCount())) {
+
+ ReportFileNotFoundError(full_path, Message);
+ DELETE(name);
+ DELETE(directory);
+ file_array->DeleteAllMembers();
+ DELETE(file_array);
+ DELETE(full_path);
+ return FALSE;
+ }
+
+ DELETE(name);
+
+ if (!(files_to_check = NEW DSTRING[num_files])) {
+
+ ReportFileNotFoundError(full_path, Message);
+ file_array->DeleteAllMembers();
+ DELETE(file_array);
+ DELETE(full_path);
+ return FALSE;
+ }
+
+ for (i = 0; i < num_files; i++) {
+
+ fsnode = (PFSNODE) file_array->GetAt(i);
+
+ if (!(name = fsnode->QueryName()) ||
+ !files_to_check[i].Initialize(name)) {
+
+ ReportFileNotFoundError(full_path, Message);
+ DELETE(name);
+ file_array->DeleteAllMembers();
+ DELETE(file_array);
+ DELETE(files_to_check);
+ DELETE(full_path);
+ return FALSE;
+ }
+
+ DELETE(name);
+ }
+
+ file_array->DeleteAllMembers();
+ DELETE(file_array);
+
+ if (!(dir_name = full_path->QueryDirs())) {
+
+ if (!backslash.Initialize("\\")) {
+ ReportFileNotFoundError(full_path, Message);
+ DELETE(files_to_check);
+ DELETE(full_path);
+ return FALSE;
+ }
+ }
+
+ r = FatVol.ContiguityReport(dir_name ? dir_name : &backslash,
+ files_to_check,
+ num_files,
+ Message);
+
+ DELETE(files_to_check);
+ DELETE(dir_name);
+ DELETE(full_path);
+ }
+
+ return r;
+}
+
+
+BOOLEAN
+FAR APIENTRY
+Format(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Quick,
+ IN MEDIA_TYPE MediaType,
+ IN PCWSTRING LabelString,
+ IN ULONG ClusterSize
+ )
+/*++
+
+Routine Description:
+
+ This routine formats a volume for the FAT file system.
+
+Arguments:
+
+ NtDriveName - Supplies the NT style drive name of the volume to format.
+ Message - Supplies an outlet for messages.
+ Quick - Supplies whether or not to do a quick format.
+ MediaType - Supplies the media type of the drive.
+ LabelString - Supplies a volume label to be set on the volume after
+ format.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PDP_DRIVE DpDrive;
+ FAT_VOL FatVol;
+ BIG_INT Sectors;
+ DSTRING FileSystemName;
+ BOOLEAN IsCompressed;
+
+
+ // Make sure the cluster size switch wasn't specified.
+ //
+ if (ClusterSize > 0 && ClusterSize <= 4096) {
+ Message->Set(MSG_FMT_VARIABLE_CLUSTERS_NOT_SUPPORTED);
+ Message->Display("%s", "FAT");
+ return FALSE;
+ }
+
+ if( !(DpDrive = NEW DP_DRIVE) ) {
+
+ Message->Set( MSG_FMT_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if (!DpDrive->Initialize(NtDriveName, Message, TRUE)) {
+ DELETE( DpDrive );
+ return FALSE;
+ }
+
+ // Check to see if the volume is too large and determine
+ // whether it's compressed. Volumes larger than 4GB are
+ // not supported by fastfat.
+ //
+
+ Sectors = DpDrive->QuerySectors();
+
+ if (Sectors.GetHighPart() != 0 ||
+ (Sectors * DpDrive->QuerySectorSize()).GetHighPart() != 0 ||
+ FAT_SA::ComputeSecClus(Sectors.GetLowPart(),
+ LARGE, MediaType) > MaxSecPerClus) {
+
+ DELETE( DpDrive );
+ Message->Set(MSG_DISK_TOO_LARGE_TO_FORMAT);
+ Message->Display();
+ return FALSE;
+ }
+
+#ifdef DBLSPACE_ENABLED
+ // Note that we don't care about the return value from
+ // QueryMountedFileSystemName, just whether the volume
+ // is compressed.
+ //
+ DpDrive->QueryMountedFileSystemName( &FileSystemName, &IsCompressed );
+#endif // DBLSPACE_ENABLED
+
+ // Delete the DP_DRIVE object so it's handle will go away.
+ //
+ DELETE( DpDrive );
+
+
+ // Volume is not too large, proceed with format.
+
+#ifdef DBLSPACE_ENABLED
+ if( IsCompressed ) {
+
+ return FatDbFormat( NtDriveName,
+ Message,
+ Quick,
+ MediaType,
+ LabelString,
+ ClusterSize );
+ }
+#endif // DBLSPACE_ENABLED
+
+ return( FatVol.Initialize( NtDriveName,
+ Message,
+ FALSE,
+ !Quick,
+ MediaType ) &&
+ FatVol.Format( LabelString, Message, ClusterSize ) );
+}
+
+
+BOOLEAN
+FAR APIENTRY
+Recover(
+ IN PPATH RecFilePath,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ Recover a file on a FAT disk.
+
+Arguments:
+
+Return Value:
+
+ TRUE if successful.
+
+--*/
+{
+ FAT_VOL FatVol;
+ PWSTRING fullpathfilename;
+ PWSTRING dosdrive;
+ DSTRING ntdrive;
+
+ fullpathfilename = RecFilePath->QueryDirsAndName();
+ dosdrive = RecFilePath->QueryDevice();
+ if (!dosdrive ||
+ !IFS_SYSTEM::DosDriveNameToNtDriveName(dosdrive, &ntdrive)) {
+ DELETE(dosdrive);
+ DELETE(fullpathfilename);
+ return FALSE;
+ }
+
+ if (!fullpathfilename) {
+ DELETE(dosdrive);
+ DELETE(fullpathfilename);
+ return FALSE;
+ }
+
+ Message->Set(MSG_RECOV_BEGIN);
+ Message->Display("%W", dosdrive);
+ Message->WaitForUserSignal();
+
+ if (!FatVol.Initialize(&ntdrive, Message)) {
+ DELETE(dosdrive);
+ DELETE(fullpathfilename);
+ return FALSE;
+ }
+
+ if (!FatVol.Recover(fullpathfilename, Message)) {
+ DELETE(dosdrive);
+ DELETE(fullpathfilename);
+ return FALSE;
+ }
+
+ DELETE(dosdrive);
+ DELETE(fullpathfilename);
+ return TRUE;
+}
+
diff --git a/private/utils/ufat/src/fat.cxx b/private/utils/ufat/src/fat.cxx
new file mode 100644
index 000000000..8407885f8
--- /dev/null
+++ b/private/utils/ufat/src/fat.cxx
@@ -0,0 +1,1024 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UFAT_MEMBER_
+
+#include "ulib.hxx"
+#include "ufat.hxx"
+
+#include "bitvect.hxx"
+#include "error.hxx"
+#include "fat.hxx"
+
+
+DEFINE_CONSTRUCTOR( FAT, SECRUN );
+
+
+FAT::~FAT(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for FAT.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+FAT::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Constructor for FAT.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _fat = NULL;
+ _num_entries = 0;
+ _is_big = FALSE;
+ _low_end_of_chain = 0;
+ _end_of_chain = 0;
+ _bad_cluster = 0;
+ _low_reserved = 0;
+ _high_reserved = 0;
+}
+
+
+VOID
+FAT::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a FAT object to its initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _fat = NULL;
+ _num_entries = 0;
+ _is_big = FALSE;
+ _low_end_of_chain = 0;
+ _end_of_chain = 0;
+ _bad_cluster = 0;
+ _low_reserved = 0;
+ _high_reserved = 0;
+}
+
+
+BOOLEAN
+FAT::Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN LBN StartSector,
+ IN USHORT NumberOfEntries,
+ IN USHORT NumSectors
+ )
+/*++
+
+Routine Description:
+
+ This routine initialize a FAT object.
+
+Arguments:
+
+ Mem - Supplies the memory for the run of sectors.
+ Drive - Supplies the drive to read and write from.
+ StartSector - Supplies the start of the fat.
+ NumberOfEntries - Supplies the number of entries in the FAT.
+ NumSectors - Supplies the number of sectors allocated for
+ the fat. If this parameter is not supplied
+ then this routine will compute this value
+ from the given number of entries.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+Notes:
+
+ The 'NumFatSectors' parameter is added to this function
+ DOS FORMAT does not always make the FAT large enough for
+ the volume. If this parameter is supported then the
+ number of entries supported by this FAT will be the lesser
+ or the actual number passed in that the maximum number that
+ the given FAT size will support.
+
+--*/
+{
+ SECTORCOUNT n;
+ ULONG sector_size;
+ ULONG max_num_entries;
+
+ DebugAssert(Mem);
+ DebugAssert(Drive);
+
+ Destroy();
+
+ if (!(sector_size = Drive->QuerySectorSize())) {
+ Destroy();
+ return FALSE;
+ }
+
+ _num_entries = NumberOfEntries;
+ _is_big = (BOOLEAN) (_num_entries >= FirstDiskCluster + MaxNumClusForSmallFat);
+
+ if (_is_big) {
+ _low_end_of_chain = 0xFFF8;
+ _end_of_chain = 0xFFFF;
+ _bad_cluster = 0xFFF7;
+ _low_reserved = 0xFFF0;
+ _high_reserved = 0xFFF6;
+
+ n = (_num_entries*2 - 1)/sector_size + 1;
+
+ } else {
+ _low_end_of_chain = 0x0FF8;
+ _end_of_chain = 0x0FFF;
+ _bad_cluster = 0x0FF7;
+ _low_reserved = 0x0FF0;
+ _high_reserved = 0x0FF6;
+
+ n = (_num_entries*3 - 1)/2/sector_size + 1;
+ }
+
+ if (NumSectors) {
+ n = NumSectors;
+ if (_is_big) {
+ max_num_entries = (n*sector_size/2);
+ } else {
+ max_num_entries = (n*sector_size*2/3);
+ }
+ _num_entries = (USHORT)min(_num_entries, max_num_entries);
+ }
+
+ if (!SECRUN::Initialize(Mem, Drive, StartSector, n)) {
+ Destroy();
+ return FALSE;
+ }
+
+ _fat = GetBuf();
+
+ return TRUE;
+}
+
+
+UFAT_EXPORT
+USHORT
+FAT::Index12(
+ IN USHORT ClusterNumber
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine indexes the FAT as 12 bit little endian entries.
+
+Arguments:
+
+ ClusterNumber - Supplies the FAT entry desired.
+
+Return Value:
+
+ The value of the FAT entry at ClusterNumber.
+
+--*/
+{
+ ULONG n;
+ PUCHAR p;
+
+ p = (PUCHAR) _fat;
+
+ DebugAssert(p);
+
+ n = ClusterNumber*3;
+ if (n%2) {
+ return (p[n/2]>>4) | (p[n/2 + 1]<<4);
+ } else {
+ return p[n/2] | ((p[n/2 + 1]&0x0F)<<8);
+ }
+}
+
+
+UFAT_EXPORT
+VOID
+FAT::Set12(
+ IN USHORT ClusterNumber,
+ IN USHORT Value
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the ClusterNumber'th 12 bit FAT entry to Value.
+
+Arguments:
+
+ ClusterNumber - Supplies the FAT entry to set.
+ Value - Supplies the value to set the FAT entry to.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG n;
+ PUCHAR p;
+
+ p = (PUCHAR) _fat;
+
+ DebugAssert(p);
+
+ n = ClusterNumber*3;
+ if (n%2) {
+ p[n/2] = (p[n/2]&0x0F) | ((Value&0x000F)<<4);
+ p[n/2 + 1] = (Value&0x0FF0)>>4;
+ } else {
+ p[n/2] = Value&0x00FF;
+ p[n/2 + 1] = (p[n/2 + 1]&0xF0) | ((Value&0x0F00)>>8);
+ }
+}
+
+
+
+
+
+USHORT
+FAT::QueryFreeClusters(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of free clusters on the disk by
+ scanning the FAT and counting the number of empty entries.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of free clusters on the disk.
+
+--*/
+{
+ USHORT i;
+ USHORT r;
+
+ r = 0;
+ for (i = FirstDiskCluster; IsInRange(i); i++) {
+ if (IsClusterFree(i)) {
+ r++;
+ }
+ }
+
+ return r;
+}
+
+
+USHORT
+FAT::QueryBadClusters(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of bad clusters on the disk by
+ scanning the FAT and counting the number of entries marked bad.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of bad clusters on the disk.
+
+--*/
+{
+ USHORT i;
+ USHORT r;
+
+ r = 0;
+ for (i = FirstDiskCluster; IsInRange(i); i++) {
+ if (IsClusterBad(i)) {
+ r++;
+ }
+ }
+
+ return r;
+}
+
+
+USHORT
+FAT::QueryReservedClusters(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of reserved clusters on the disk by
+ scanning the FAT and counting the number of entries marked reserved.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of reserved clusters on the disk.
+
+--*/
+{
+ USHORT i;
+ USHORT r;
+
+ r = 0;
+ for (i = FirstDiskCluster; IsInRange(i); i++) {
+ if (IsClusterReserved(i)) {
+ r++;
+ }
+ }
+
+ return r;
+}
+
+USHORT
+FAT::QueryAllocatedClusters(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of allocated clusters on the
+ disk by scanning the FAT and counting the entries marked allocated.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of allocated clusters on the disk.
+
+--*/
+{
+ USHORT i;
+ USHORT r;
+
+ r = 0;
+ for (i = FirstDiskCluster; IsInRange(i); i++) {
+ if (!IsClusterReserved(i) && !IsClusterBad(i) && !IsClusterFree(i)) {
+ r++;
+ }
+ }
+
+ return r;
+}
+
+
+UFAT_EXPORT
+USHORT
+FAT::QueryNthCluster(
+ IN USHORT StartingCluster,
+ IN USHORT Index
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the cluster number of the cluster that is in the
+ 'Index'th position in the cluster chain beginning at 'StartingCluster'.
+ The clusters in a chain are numbered beginning at zero.
+
+Arguments:
+
+ StartingCluster - Supplies the first cluster of a cluster chain.
+ Index - Supplies the number of the cluster in the chain
+ requested.
+
+Return Value:
+
+ The cluster number of the 'Index'th cluster in the cluster chain
+ beginning with cluster 'StartingCluster' or 0.
+
+--*/
+{
+ for (; Index; Index--) {
+
+ if (!IsInRange(StartingCluster)) {
+ return 0;
+ }
+
+ StartingCluster = QueryEntry(StartingCluster);
+ }
+
+ return StartingCluster;
+}
+
+
+UFAT_EXPORT
+USHORT
+FAT::QueryLengthOfChain(
+ IN USHORT StartingCluster,
+ OUT PUSHORT LastCluster
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the length of a cluster chain given the number
+ of its first cluster.
+
+ This routine depends on the chain being valid. In particular, if the
+ chain contains any cycles then this routine will not finish. The
+ routine 'ScrubChain' will turn an invalid chain into a valid one.
+
+Arguments:
+
+ StartingCluster - Supplies the first cluster of a cluster chain.
+ LastCluster - Returns the number of the last cluster in the chain.
+
+Return Value:
+
+ The length of the cluster chain beginning with 'StartingCluster'.
+
+--*/
+{
+ USHORT length;
+
+ if (!StartingCluster) {
+ if (LastCluster) {
+ *LastCluster = 0;
+ }
+ return 0;
+ }
+
+ for (length = 1; !IsEndOfChain(StartingCluster); length++) {
+ StartingCluster = QueryEntry(StartingCluster);
+ }
+
+ if (LastCluster) {
+ *LastCluster = StartingCluster;
+ }
+
+ return length;
+}
+
+
+USHORT
+FAT::QueryLengthOfChain(
+ IN USHORT StartingCluster,
+ IN USHORT EndingCluster
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the length of a cluster chain given the number
+ of its first cluster and the number of its last cluster. To compute
+ the length of a chain which is terminated by "end of chain", see
+ the one parameter version of this routine above. If 'EndingCluster'
+ is not a member of the chain beginning with 'StartingCluster' then
+ this routine will return 0.
+
+ This routine depends on the chain being valid.
+
+Arguments:
+
+ StartingCluster - Supplies the first cluster of the cluster chain.
+ EndingCluster - Supplies the last cluster of the cluster chain.
+
+Return Value:
+
+ The length of the cluster chain beginning with 'StartingCluster' and
+ ending with 'EndingCluster' or 0.
+
+--*/
+{
+ USHORT length;
+
+ if (!StartingCluster) {
+ return 0;
+ }
+
+ for (length = 1; StartingCluster != EndingCluster &&
+ !IsEndOfChain(StartingCluster); length++) {
+ StartingCluster = QueryEntry(StartingCluster);
+ }
+
+ return StartingCluster == EndingCluster ? length : 0;
+}
+
+
+USHORT
+FAT::QueryPrevious(
+ IN USHORT Cluster
+ ) CONST
+/*++
+
+Routine Description:
+
+ Obtains the previous cluster in a chain, i.e. the cluster that
+ references the given cluster.
+
+Arguments:
+
+ Cluster - Supplies the cluster whose predecesor we're looking for.
+
+Return Value:
+
+ The predecesor of the given cluster. 0 if there is no predecesor.
+
+--*/
+
+{
+ USHORT i;
+
+ DebugAssert( Cluster );
+
+ if ( !IsClusterFree( Cluster ) ) {
+ for (i = FirstDiskCluster; IsInRange(i); i++) {
+ if ( QueryEntry(i) == Cluster ) {
+ return i;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+VOID
+FAT::Scrub(
+ OUT PBOOLEAN ChangesMade
+ )
+/*++
+
+Routine Description:
+
+ This routine goes through all of the FAT entries changing invalid values
+ to reasonable values for the purposes of CHKDSK.
+
+ Illegal FAT entries are those that are set out of disk range and that
+ are not magic values. This routine will set all illegal FAT entries to
+ the "end of chain" magic value.
+
+Arguments:
+
+ ChangesMade - Returns TRUE if any changes were made to the FAT.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ USHORT i;
+
+ if (ChangesMade) {
+ *ChangesMade = FALSE;
+ }
+
+ for (i = FirstDiskCluster; IsInRange(i); i++) {
+ if (!IsInRange(QueryEntry(i)) &&
+ !IsClusterFree(i) &&
+ !IsEndOfChain(i) &&
+ !IsClusterBad(i) &&
+ !IsClusterReserved(i)) {
+
+ SetEndOfChain(i);
+
+ if (ChangesMade) {
+ *ChangesMade = TRUE;
+ }
+ }
+ }
+}
+
+
+VOID
+FAT::ScrubChain(
+ IN USHORT StartingCluster,
+ OUT PBOOLEAN ChangesMade
+ )
+/*++
+
+Routine Description:
+
+ This routine goes through all of the FAT entries in the chain beginning
+ with cluster 'StartingCluster'. It is expected that all of the entries
+ in this chain point to valid clusters on the disk. This routine will
+ mark the first invalid entry, if any, as the final cluster of the chain
+ thus transforming the invalid chain into a valid one.
+
+Arguments:
+
+ StartingCluster - Supplies the first cluster of the chain to
+ scrub.
+ ChangesMade - Returns TRUE if changes were made to correct
+ the chain.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ USHORT clus, next;
+
+ DebugAssert(IsInRange(StartingCluster));
+ DebugAssert(ChangesMade);
+
+ *ChangesMade = FALSE;
+
+ clus = StartingCluster;
+ while (!IsEndOfChain(clus)) {
+
+ next = QueryEntry(clus);
+ if (!IsInRange(next) || IsClusterFree(next)) {
+ SetEndOfChain(clus);
+ *ChangesMade = TRUE;
+ return;
+ }
+
+ clus = next;
+ }
+}
+
+
+VOID
+FAT::ScrubChain(
+ IN USHORT StartingCluster,
+ OUT PBITVECTOR FatBitMap,
+ OUT PBOOLEAN ChangesMade,
+ OUT PBOOLEAN CrossLinkDetected,
+ OUT PUSHORT CrossLinkPreviousCluster
+ )
+/*++
+
+Routine Description:
+
+ This routine goes through all of the FAT entries in the chain beginning
+ with cluster 'StartingCluster'. It is expected that all of the entries
+ in this chain point to valid clusters on the disk. This routine will
+ mark the first invalid entry, if any, as the final cluster of the chain
+ thus transforming the invalid chain into a valid one.
+
+ This routine will also eliminate any cycles in the cluster chain as well
+ as detect cross-links.
+
+Arguments:
+
+ StartingCluster - Supplies the first cluster of the chain to
+ scrub.
+ UsedClusters - Supplies a bitvector marking all used
+ clusters.
+ ChangesMade - Returns TRUE if changes were made to correct
+ the chain.
+ CrossLinkDetected - Returns TRUE if a cluster in the chain was
+ already claimed in the 'FatBitMap'.
+ CrossLinkPreviousCluster - Returns the cluster number previous to the
+ cross linked cluster number or 0 if the
+ cross linked cluster number was the first
+ in the chain.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ USHORT clus, next;
+
+ DebugAssert(IsInRange(StartingCluster));
+ DebugAssert(ChangesMade);
+ DebugAssert(CrossLinkDetected);
+ DebugAssert(CrossLinkPreviousCluster);
+
+ *ChangesMade = FALSE;
+ *CrossLinkDetected = FALSE;
+
+ if (FatBitMap->IsBitSet(StartingCluster)) {
+ *CrossLinkDetected = TRUE;
+ *CrossLinkPreviousCluster = 0;
+ return;
+ }
+
+ clus = StartingCluster;
+ while (!IsEndOfChain(clus)) {
+
+ FatBitMap->SetBit(clus);
+
+ next = QueryEntry(clus);
+ if (!IsInRange(next) || IsClusterFree(next)) {
+ SetEndOfChain(clus);
+ *ChangesMade = TRUE;
+ return;
+ }
+
+ if (FatBitMap->IsBitSet(next)) {
+
+ if (clus == next) { // Cluster points to itself.
+ *ChangesMade = TRUE;
+ SetEndOfChain(clus);
+ return;
+ }
+
+ while (StartingCluster != clus) {
+
+ if (StartingCluster == next) { // Cluster points to previous.
+ *ChangesMade = TRUE;
+ SetEndOfChain(clus);
+ return;
+ }
+
+ StartingCluster = QueryEntry(StartingCluster);
+ }
+
+ // Otherwise it's a cross link, not a cycle.
+
+ *CrossLinkDetected = TRUE;
+ *CrossLinkPreviousCluster = clus;
+ return;
+ }
+
+ clus = next;
+ }
+
+ FatBitMap->SetBit(clus);
+}
+
+NONVIRTUAL
+BOOLEAN
+FAT::IsValidChain(
+ IN USHORT StartingCluster
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method determines whether the chain is valid, ie. that it
+ consists of a chain of valid cluster numbers ending with an end
+ of chain entry.
+
+Arguments:
+
+ StartingCluster - Supplies the first cluster of the chain.
+
+Return Value:
+
+ TRUE if the chain is valid.
+
+--*/
+{
+ USHORT current;
+ USHORT clusters_in_chain = 0;
+
+ current = StartingCluster;
+
+ for( ;; ) {
+
+ if (!IsInRange(current) ||
+ clusters_in_chain++ > _num_entries ) {
+
+ // Either a bad entry or an infinite loop detected.
+ //
+ return FALSE;
+ }
+
+ if (IsEndOfChain(current)) {
+ break;
+ }
+
+ current = QueryEntry(current);
+ }
+
+ return TRUE;
+}
+
+
+UFAT_EXPORT
+USHORT
+FAT::AllocChain(
+ IN USHORT Length,
+ OUT PUSHORT LastCluster
+ )
+/*++
+
+Routine Description:
+
+ This routine attempts to allocate a chain of length 'Length' from the
+ FAT. If this routine is successful it will return the cluster number
+ of the beginning of the chain. Upon failure this routine will return
+ 0 and will make no changes to the FAT.
+
+Arguments:
+
+ Length - Supplies the length of the chain desired.
+ LastCluster - Returns the last cluster of the allocated chain.
+
+Return Value:
+
+ The cluster number of the beginning of the allocated chain or 0.
+
+--*/
+{
+ USHORT i, j;
+ USHORT start;
+ USHORT prev;
+
+ if (!Length) {
+ return 0;
+ }
+
+ start = 0;
+ prev = 0;
+ for (i = FirstDiskCluster; IsInRange(i); i++) {
+ if (IsClusterFree(i)) {
+ if (!start) {
+ start = i;
+ } else {
+ SetEntry(prev, i);
+ }
+ prev = i;
+ Length--;
+ if (!Length) {
+ SetEndOfChain(i);
+
+ if (LastCluster) {
+ *LastCluster = i;
+ }
+
+ return start;
+ }
+ }
+ }
+
+ // There is not enough disk space for the chain so free what was taken.
+ for (i = start; i != prev; ) {
+ j = QueryEntry(i);
+ SetClusterFree(i);
+ i = j;
+ }
+
+ return 0;
+}
+
+
+USHORT
+FAT::ReAllocChain(
+ IN USHORT StartOfChain,
+ IN USHORT NewLength,
+ OUT PUSHORT LastCluster
+ )
+/*++
+
+Routine Description:
+
+ This routine insures that the cluster chain beginning at cluster
+ 'StartOfChain' is of length greater than or equal to 'NewSize'.
+ If it is not then this routine will attempt to grow the chain by
+ allocating new clusters. Failure to allocate sufficient clusters
+ to grow the chain to 'NewSize' clusters will cause this routine to
+ restore the chain to its original length and state. This routine will
+ return the current length of the chain : either the old length or the
+ new length. If an error occurs then 0 will be returned.
+
+Arguments:
+
+ StartOfChain - Supplies the first cluster of the chain.
+ NewLength - Supplies the desired new length of the chain.
+ LastCluster - Returns the last cluster of the chain.
+
+Return Value:
+
+ The current length of the chain or 0.
+
+--*/
+{
+ USHORT length;
+ USHORT new_clusters_needed;
+ USHORT end_of_chain;
+ USHORT i, j;
+ USHORT start;
+
+ if (!IsInRange(StartOfChain)) {
+ return 0;
+ }
+
+ for (length = 1; !IsEndOfChain(StartOfChain); length++) {
+ StartOfChain = QueryEntry(StartOfChain);
+ if (!IsInRange(StartOfChain)) {
+ return 0;
+ }
+ }
+
+ if (length >= NewLength) {
+ if (LastCluster) {
+ *LastCluster = StartOfChain;
+ }
+ return length;
+ }
+
+ new_clusters_needed = NewLength - length;
+
+ start = end_of_chain = StartOfChain;
+ for (i = FirstDiskCluster; IsInRange(i); i++) {
+ if (IsClusterFree(i)) {
+ SetEntry(end_of_chain, i);
+ end_of_chain = i;
+ new_clusters_needed--;
+ if (!new_clusters_needed) {
+ SetEndOfChain(i);
+ if (LastCluster) {
+ *LastCluster = i;
+ }
+ return NewLength;
+ }
+ }
+ }
+
+ // There is not enough disk space to lengthen the new chain so
+ // settle for the old length.
+
+ for (i = start; i != end_of_chain; ) {
+ j = QueryEntry(i);
+ SetClusterFree(i);
+ i = j;
+ }
+
+ SetEndOfChain(start);
+
+ if (LastCluster) {
+ *LastCluster = start;
+ }
+
+ return length;
+}
+
+
+UFAT_EXPORT
+VOID
+FAT::FreeChain(
+ IN USHORT StartOfChain
+ )
+/*++
+
+Routine Description:
+
+ This routine sets free all of the clusters in the cluster chain
+ beginning with 'StartOfChain'.
+
+Arguments:
+
+ StartOfChain - Supplies the first cluster of the chain to free.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ USHORT tmp;
+
+ while (!IsEndOfChain(StartOfChain)) {
+ tmp = QueryEntry(StartOfChain);
+ SetClusterFree(StartOfChain);
+ StartOfChain = tmp;
+ }
+ SetClusterFree(StartOfChain);
+}
diff --git a/private/utils/ufat/src/fatdbsa.cxx b/private/utils/ufat/src/fatdbsa.cxx
new file mode 100644
index 000000000..5c6901eee
--- /dev/null
+++ b/private/utils/ufat/src/fatdbsa.cxx
@@ -0,0 +1,1593 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ fatdbsa.cxx
+
+Author:
+
+ Matthew Bradburn (mattbr) 30-Sep-93
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+#include "cluster.hxx"
+#include "cmem.hxx"
+#include "error.hxx"
+#include "fatdent.hxx"
+#include "fatdbsa.hxx"
+#include "rootdir.hxx"
+#include "rtmsg.h"
+#include "filedir.hxx"
+#include "fat.hxx"
+#include "drive.hxx"
+#include "cvf.hxx"
+
+#if !defined(_AUTOCHECK_) && !defined(_SETUP_LOADER_)
+#include "timeinfo.hxx"
+#endif
+
+extern UCHAR FatBootCode[512];
+
+// Control-C handling is not necessary for autocheck.
+#if !defined( _AUTOCHECK_ ) && !defined(_SETUP_LOADER_)
+
+#include "keyboard.hxx"
+
+#endif
+
+
+#define CSEC_FAT32MEG 65536
+#define CSEC_FAT16BIT 32680
+
+#define MIN_CLUS_BIG 4085 // Minimum clusters for a big FAT.
+#define MAX_CLUS_BIG 65525 // Maximum + 1 clusters for big FAT.
+
+#define sigSUPERSEC1 (UCHAR)0x55 // signature first byte
+#define sigSUPERSEC2 (UCHAR)0xAA // signature second byte
+
+DEFINE_CONSTRUCTOR( FATDB_SA, FAT_SA );
+
+
+VOID
+FATDB_SA::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Constructor for FAT_SA.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _fat = NULL;
+ _dir = NULL;
+ _cvf_extens = NULL;
+ _pexbpb = NULL;
+ _StartDataLbn = 0;
+ _ClusterCount = 0;
+ _sysid = SYSID_NONE;
+}
+
+
+FATDB_SA::~FATDB_SA(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for FAT_SA.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+BOOLEAN
+FATDB_SA::DosSaInit(
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN SECTORCOUNT NumberOfSectors,
+ IN OUT PMESSAGE Message
+ )
+{
+ if (!SUPERAREA::Initialize(Mem, Drive, NumberOfSectors, Message)) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ _sector_sig = (UCHAR *)SECRUN::GetBuf() + 510;
+
+ return TRUE;
+}
+
+
+BOOLEAN
+FATDB_SA::Initialize(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Formatted
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the FAT super area to an initial state. It
+ does so by first reading in the boot sector and verifying it with
+ the methods of DOS_SUPERAREA. Upon computing the super area's actual size,
+ the underlying SECRUN will be set to the correct size.
+
+ If the super area does not already exist on disk, then the other Init
+ function should be called.
+
+Arguments:
+
+ Drive - Supplies the drive where the super area resides.
+ Message - Supplies an outlet for messages
+ Formatted - Supplies a boolean which indicates whether or not
+ the volume is formatted.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ SECTORCOUNT sectors;
+ SECTORCOUNT sectors_in_sa;
+ CONT_MEM cmem;
+ SECTORCOUNT reserved;
+ SECTORCOUNT sec_per_fat;
+ SECTORCOUNT sec_per_root;
+ ULONG root_entries;
+ ULONG sector_size;
+ BOOLEAN success;
+ LBN fat_lbn;
+ ULONG DosRootDirSector;
+
+ Destroy();
+
+ _sec_per_boot = max(1, BYTES_PER_BOOT_SECTOR/Drive->QuerySectorSize());
+
+ if (!Formatted) {
+ return _mem.Initialize() &&
+ DosSaInit(&_mem, Drive, _sec_per_boot, Message);
+ }
+
+ if (!Drive ||
+ !(sector_size = Drive->QuerySectorSize()) ||
+ !_mem.Initialize() ||
+ !DosSaInit(&_mem, Drive, _sec_per_boot, Message) ||
+ !SECRUN::Read()) {
+ Message->Set(MSG_CANT_READ_BOOT_SECTOR);
+ Message->Display("");
+ Destroy();
+ return FALSE;
+ }
+
+ CvfUnpackCvfHeader(&_cvf_header, (PPACKED_CVF_HEADER)SECRUN::GetBuf());
+
+ if (!VerifyBootSector() || 0 == _cvf_header.Bpb.Fats) {
+ Destroy();
+ return FALSE;
+ }
+
+ reserved = _cvf_header.Bpb.ReservedSectors;
+ sec_per_fat = _cvf_header.Bpb.SectorsPerFat;
+ root_entries = _cvf_header.Bpb.RootEntries;
+ sec_per_root = (root_entries*BytesPerDirent - 1)/sector_size + 1;
+
+ _StartDataLbn = _cvf_header.DosBootSectorLbn + _cvf_header.CvfHeapOffset;
+
+ sectors = (0 == _cvf_header.Bpb.LargeSectors) ?
+ 0 : _cvf_header.Bpb.LargeSectors /* - _StartDataLbn */;
+
+ _ClusterCount = (USHORT)(sectors/QuerySectorsPerCluster() +
+ FirstDiskCluster);
+
+ _ft = (_ClusterCount >= 4087) ? LARGE : SMALL;
+
+ if (_ft == SMALL) {
+ _sysid = SYSID_FAT12BIT;
+ } else if (QueryVirtualSectors() < CSEC_FAT32MEG) {
+ _sysid = SYSID_FAT16BIT;
+ } else {
+ _sysid = SYSID_FAT32MEG;
+ }
+
+ //
+ // Note here that the CvfHeapOffset is measured from the DosBootSector,
+ // not from the beginning of the CVF.
+ //
+
+ sectors_in_sa = _cvf_header.DosBootSectorLbn + _cvf_header.CvfHeapOffset;
+
+
+ if (!_mem.Initialize() ||
+ !DosSaInit(&_mem, Drive, sectors_in_sa, Message)) {
+ Destroy();
+ return FALSE;
+ }
+
+ //
+ // Set up the FAT extensions
+ //
+
+ if (!cmem.Initialize((PCHAR)SECRUN::GetBuf() +
+ (_cvf_header.CvfFatExtensionsLbnMinus1 + 1) * sector_size,
+ (_cvf_header.DosBootSectorLbn -
+ (_cvf_header.CvfFatExtensionsLbnMinus1 + 1)) * sector_size)) {
+ Destroy();
+ return FALSE;
+ }
+
+ DELETE(_cvf_extens);
+ if (NULL == (_cvf_extens = NEW CVF_FAT_EXTENS)) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ Destroy();
+ return FALSE;
+ }
+
+ if (!_cvf_extens->Initialize(&cmem, _drive,
+ _cvf_header.CvfFatExtensionsLbnMinus1 + 1, _ClusterCount,
+ _cvf_header.CvfFatFirstDataEntry )) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ Destroy();
+ return FALSE;
+ }
+
+ //
+ // Set up the pointer to the second bpb, the DOS_BPB.
+ //
+
+ _pexbpb = (PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK)
+ ((PCHAR)SECRUN::GetBuf() + _cvf_header.DosBootSectorLbn * sector_size);
+
+ //
+ // Set up the fat.
+ //
+
+ fat_lbn = _cvf_header.DosBootSectorLbn + _cvf_header.Bpb.ReservedSectors;
+
+ if (!cmem.Initialize((PCHAR)SECRUN::GetBuf() + fat_lbn*sector_size,
+ QuerySectorsPerFat()*sector_size)) {
+ Destroy();
+ return FALSE;
+ }
+
+ if (!(_fat = NEW FAT)) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ Destroy();
+ return FALSE;
+ }
+
+ if (!_fat->Initialize(&cmem, _drive, fat_lbn, _ClusterCount,
+ QuerySectorsPerFat())) {
+ Destroy();
+ return FALSE;
+ }
+
+ //
+ // Set up root directory.
+ //
+
+ if (NULL == (_dir = NEW ROOTDIR)) {
+ Destroy();
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ DosRootDirSector = _cvf_header.DosBootSectorLbn +
+ _cvf_header.DosRootDirectoryOffset;
+
+ success = cmem.Initialize((PCHAR)SECRUN::GetBuf() +
+ DosRootDirSector * sector_size,
+ sec_per_root * sector_size);
+ if (!success) {
+ Destroy();
+ return FALSE;
+ }
+
+ success = _dir->Initialize(&cmem, Drive, DosRootDirSector, root_entries);
+ if (!success) {
+ Destroy();
+ return FALSE;
+ }
+
+ //
+ // Set up the bitmap for the sector heap.
+ //
+
+ _sector_heap_bitmap.Initialize(_cvf_header.Bpb.LargeSectors - _StartDataLbn);
+ _sector_heap_init = FALSE;
+
+ return TRUE;
+}
+
+
+BOOLEAN
+FATDB_SA::Create(
+ IN PCNUMBER_SET BadSectors,
+ IN OUT PMESSAGE Message,
+ IN PCWSTRING Label,
+ IN ULONG ClusterSize,
+ IN ULONG VirtualSize
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the FAT file system.
+
+Arguments:
+
+ BadSectors - Supplies a list of the bad sectors on the volume.
+ Message - Supplies an outlet for messages.
+ Label - Supplies an optional label.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+#if defined( _SETUP_LOADER_ )
+
+ return FALSE;
+
+#else
+
+ USHORT sector_size;
+ SECTORCOUNT sec_per_root;
+ CONT_MEM cmem;
+ HMEM hmem;
+ SECRUN secrun;
+ SECRUN small_secrun;
+ PUSHORT p;
+ USHORT cluster_count;
+ ULONG cluster_size;
+ DSTRING label;
+ USHORT free_count;
+ USHORT bad_count;
+ PPACKED_CVF_HEADER SourceBootSector, TargetBootSector;
+ ULONG BootCodeOffset;
+ BOOLEAN fReInit;
+ SECTORCOUNT sectors;
+ SECTORCOUNT sectors_in_sa;
+ LBN fat_lbn;
+ SECRUN last_sector;
+ HMEM last_sector_mem;
+ ULONG DosRootDirSector;
+ BOOLEAN success;
+
+ if (!_drive ||
+ !(sector_size = (USHORT) _drive->QuerySectorSize()) ||
+ (_sysid = ComputeSystemId()) == SYSID_NONE) {
+ return FALSE;
+ }
+
+ if (VirtualSize != 0) {
+ _cvf_header.Bpb.LargeSectors = VirtualSize;
+ } else if (_cvf_header.Bpb.LargeSectors == 0) {
+ if (_drive->QuerySectors().GetHighPart() != 0) {
+ // This should be checked before calling this procedure.
+ DbgAbort("Number of sectors exceeds 32 bits");
+ return FALSE;
+ }
+ _cvf_header.Bpb.LargeSectors = _drive->QuerySectors().GetLowPart();
+ }
+
+ sec_per_root = (_cvf_header.Bpb.RootEntries*BytesPerDirent - 1)/
+ sector_size + 1;
+
+ _StartDataLbn = _cvf_header.DosBootSectorLbn + _cvf_header.CvfHeapOffset;
+
+ //
+ // If the _ClusterCount is 0, we need to re-initialize the fat
+ // and fat extensions with the correct size.
+ //
+
+ fReInit = (0 == _ClusterCount);
+
+ sectors = _cvf_header.Bpb.LargeSectors - _StartDataLbn;
+
+ _ClusterCount = (USHORT)(sectors/QuerySectorsPerCluster() +
+ FirstDiskCluster);
+
+ if (fReInit) {
+ if (!_cvf_extens->Initialize(&cmem, _drive,
+ _cvf_header.CvfFatExtensionsLbnMinus1 + 1, _ClusterCount,
+ _cvf_header.CvfFatFirstDataEntry)) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ Destroy();
+ return FALSE;
+ }
+
+ fat_lbn = _cvf_header.DosBootSectorLbn + _cvf_header.Bpb.ReservedSectors;
+
+ if (!_fat->Initialize(&cmem, _drive, fat_lbn, _ClusterCount,
+ QuerySectorsPerFat())) {
+ Destroy();
+ return FALSE;
+ }
+ }
+
+ //
+ // Note here that the CvfHeapOffset is measured from the DosBootSector,
+ // not the beginning of the CVF.
+ //
+
+ sectors_in_sa = _cvf_header.DosBootSectorLbn + _cvf_header.CvfHeapOffset;
+
+ if (!_mem.Initialize() ||
+ !DosSaInit(&_mem, _drive, sectors_in_sa, Message)) {
+ return FALSE;
+ }
+
+ //
+ // Set up the FAT extensions
+ //
+
+ if (!cmem.Initialize((PCHAR)SECRUN::GetBuf() +
+ (_cvf_header.CvfFatExtensionsLbnMinus1 + 1) * sector_size,
+ (_cvf_header.DosBootSectorLbn -
+ (_cvf_header.CvfFatExtensionsLbnMinus1 + 1)) * sector_size)) {
+ Destroy();
+ return FALSE;
+ }
+
+ DELETE(_cvf_extens);
+ if (NULL == (_cvf_extens = NEW CVF_FAT_EXTENS)) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ Destroy();
+ return FALSE;
+ }
+
+ if (!_cvf_extens->Initialize(&cmem, _drive,
+ _cvf_header.CvfFatExtensionsLbnMinus1 + 1, _ClusterCount,
+ _cvf_header.CvfFatFirstDataEntry)) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ Destroy();
+ return FALSE;
+ }
+
+ //
+ // Set up the pointer to the second bpb, the DOS_BPB.
+ //
+
+ _pexbpb = (PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK)
+ ((PCHAR)SECRUN::GetBuf() + _cvf_header.DosBootSectorLbn * sector_size);
+
+ //
+ // Set up the fat.
+ //
+
+ fat_lbn = _cvf_header.DosBootSectorLbn + _cvf_header.Bpb.ReservedSectors;
+
+ if (!cmem.Initialize((PCHAR)SECRUN::GetBuf() + fat_lbn*sector_size,
+ QuerySectorsPerFat()*sector_size)) {
+ Destroy();
+ return FALSE;
+ }
+
+ if (!(_fat = NEW FAT)) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ Destroy();
+ return FALSE;
+ }
+
+ if (!_fat->Initialize(&cmem, _drive, fat_lbn, _ClusterCount,
+ QuerySectorsPerFat())) {
+ Destroy();
+ return FALSE;
+ }
+
+ //
+ // Set up root directory.
+ //
+
+ if (NULL == (_dir = NEW ROOTDIR)) {
+ Destroy();
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ DosRootDirSector = _cvf_header.DosBootSectorLbn +
+ _cvf_header.DosRootDirectoryOffset;
+
+ success = cmem.Initialize((PCHAR)SECRUN::GetBuf() +
+ DosRootDirSector * sector_size,
+ sec_per_root * sector_size);
+ if (!success) {
+ Destroy();
+ return FALSE;
+ }
+
+ success = _dir->Initialize(&cmem, _drive, DosRootDirSector, _cvf_header.Bpb.RootEntries);
+ if (!success) {
+ Destroy();
+ return FALSE;
+ }
+
+
+
+ //
+ // Zero fill the super area, excepting the CVF_HEADER, which we
+ // don't touch.
+ //
+
+ memset((PUCHAR)_mem.GetBuf() + sector_size,
+ 0, _mem.QuerySize() - sector_size);
+
+ if (!SetSystemId()) {
+ Message->Set(MSG_WRITE_PARTITION_TABLE);
+ Message->Display("");
+ return FALSE;
+ }
+
+ _cvf_extens->Create();
+
+ _fat->SetEarlyEntries(_cvf_header.Bpb.Media);
+
+ Message->Set(MSG_FORMAT_COMPLETE);
+ Message->Display("");
+
+ if (_drive->QueryMediaType() != F5_160_512 &&
+ _drive->QueryMediaType() != F5_320_512) {
+
+ if (Label) {
+ if (!label.Initialize(Label)) {
+ return FALSE;
+ }
+ } else {
+ switch (_drive->QueryRecommendedMediaType()) {
+ case F5_360_512:
+ case F5_320_512:
+ case F5_180_512:
+ case F5_160_512:
+ // These disk drives are lame and can't
+ // take the spin down without a verify
+ // so don't prompt for the label.
+ // This will avoid FORMAT failing.
+
+ label.Initialize();
+ break;
+
+ default:
+ Message->Set(MSG_VOLUME_LABEL_PROMPT);
+ Message->Display("");
+ Message->QueryStringInput(&label);
+ break;
+
+ }
+ }
+
+ while (!SetLabel(&label)) {
+
+ Message->Set(MSG_INVALID_LABEL_CHARACTERS);
+ Message->Display("");
+
+ Message->Set(MSG_VOLUME_LABEL_PROMPT);
+ Message->Display("");
+ Message->QueryStringInput(&label);
+ }
+ }
+
+ //
+ // Copy the boot code into the secrun's buffer.
+ // This is complicated by the fact that DOS_SA::Write
+ // packs the data from the unpacked boot sector into
+ // the packed boot sector, so we have to set the
+ // first few fields in the unpacked version.
+ //
+ SourceBootSector = (PPACKED_CVF_HEADER)FatBootCode;
+
+ CopyUchar2(&_cvf_header.JmpOffset,
+ SourceBootSector->JmpOffset);
+ CopyUchar1(&_cvf_header.Jump,
+ SourceBootSector->Jump);
+
+ //
+ // Copy the remainder of the boot code directly into
+ // the secrun.
+ //
+ TargetBootSector = (PPACKED_CVF_HEADER)SECRUN::GetBuf();
+
+ BootCodeOffset = FIELD_OFFSET( PACKED_CVF_HEADER, StartBootCode );
+
+ memcpy( (PUCHAR)TargetBootSector + BootCodeOffset,
+ (PUCHAR)SourceBootSector + BootCodeOffset,
+ sizeof( FatBootCode ) - BootCodeOffset );
+
+ //
+ // Write the second Double Space signature in the last
+ // sector of the CVF.
+ //
+ if( !last_sector_mem.Initialize() ||
+ !last_sector.Initialize( &last_sector_mem,
+ _drive,
+ _drive->QuerySectors() - 1,
+ 1 ) ) {
+
+ Message->Set(MSG_UNUSABLE_DISK);
+ Message->Display("");
+ return FALSE;
+ }
+
+ memset( last_sector.GetBuf(), 0, _drive->QuerySectorSize() );
+ memcpy( last_sector.GetBuf(), SecondDbSignature, DbSignatureLength );
+
+ if( !last_sector.Write() ) {
+
+ Message->Set(MSG_UNUSABLE_DISK);
+ Message->Display("");
+ return FALSE;
+ }
+
+
+ //
+ // Finally, write the changes to disk.
+ //
+ if (!Write(Message)) {
+ if (_drive->QueryLastNtStatus() == STATUS_MEDIA_WRITE_PROTECTED) {
+ Message->Set(MSG_FMT_WRITE_PROTECTED_MEDIA);
+ } else {
+ Message->Set(MSG_UNUSABLE_DISK);
+ }
+ Message->Display("");
+ return FALSE;
+ }
+
+ //
+ // Print an informative report.
+ //
+ cluster_count = QueryClusterCount() - FirstDiskCluster;
+ cluster_size = sector_size*QuerySectorsPerCluster();
+
+ Message->Set(MSG_TOTAL_DISK_SPACE);
+ Message->Display("%9u", cluster_count*cluster_size);
+
+ if (bad_count = _fat->QueryBadClusters()) {
+ Message->Set(MSG_BAD_SECTORS);
+ Message->Display("%9u", bad_count*cluster_size);
+ }
+
+ free_count = _fat->QueryFreeClusters();
+
+ Message->Set(MSG_AVAILABLE_DISK_SPACE);
+ Message->Display("%9u", free_count*cluster_size);
+
+ Message->Set(MSG_ALLOCATION_UNIT_SIZE);
+ Message->Display("%9u", cluster_size);
+
+ Message->Set(MSG_AVAILABLE_ALLOCATION_UNITS);
+ Message->Display("%9u", free_count);
+
+ if (QueryVolId()) {
+ Message->Set(MSG_BLANK_LINE);
+ Message->Display();
+ p = (PUSHORT)&_dos_exbpb.SerialNumber;
+ Message->Set(MSG_VOLUME_SERIAL_NUMBER);
+ Message->Display("%04X%04X", p[1], p[0]);
+ }
+
+ return TRUE;
+
+#endif
+}
+
+
+BOOLEAN
+FATDB_SA::Read(
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine reads the super area. It will succeed if it can
+ read the boot sector, the root directory, and at least one of
+ the FATs.
+
+ If the position of the internal FAT has not yet been determined,
+ this routine will attempt to map it to a readable FAT on the disk.
+
+Arguments:
+
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ SECRUN secrun;
+ CONT_MEM cmem;
+
+ if (!SECRUN::Read()) {
+
+ // Check to see if super area was allocated as formatted.
+ if (QueryLength() <= _sec_per_boot) {
+ Message->Set(MSG_CANT_READ_BOOT_SECTOR);
+ Message->Display("");
+ return FALSE;
+ }
+
+ // Check the boot sector.
+ if (!secrun.Initialize(&_mem, _drive, 0, _sec_per_boot) ||
+ !secrun.Read()) {
+ CvfUnpackCvfHeader(&_cvf_header,
+ (PPACKED_CVF_HEADER)SECRUN::GetBuf());
+ Message->Set(MSG_CANT_READ_BOOT_SECTOR);
+ Message->Display("");
+ return FALSE;
+ }
+
+ // Check the fat extensions.
+
+ if (!_cvf_extens->Read()) {
+ Message->Set(MSG_CANT_READ_FAT_EXTENS);
+ Message->Display("");
+ return FALSE;
+ }
+
+ // Check the root directory.
+ if (!_dir || !_dir->Read()) {
+ Message->Set(MSG_BAD_DIR_READ);
+ Message->Display("");
+ return FALSE;
+ }
+
+ // Check the fat.
+
+ if (!_fat->Read()) {
+ Message->Set(MSG_DISK_ERROR_READING_FAT);
+ Message->Display("%d", 1 +
+ (_fat->QueryStartLbn() - _cvf_header.Bpb.ReservedSectors)/
+ _cvf_header.Bpb.SectorsPerFat);
+ return FALSE;
+ }
+
+ } else {
+
+ CvfUnpackCvfHeader(&_cvf_header,
+ (PPACKED_CVF_HEADER)SECRUN::GetBuf());
+
+ UnpackExtendedBios(&_dos_exbpb, _pexbpb);
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+FATDB_SA::Write(
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine writes the super area. It will succeed if it can
+ write the boot sector, the root directory, and at least one of
+ the FATs.
+
+ This routine will duplicate the working FAT to all other FATs
+ in the super area.
+
+Arguments:
+
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ SECRUN secrun;
+
+ SetExtendedBpb();
+
+ //
+ // Pack the dos_bpb and CVF Header into the secrun at the
+ // right place. Put the two interesting signatures at the
+ // end of the DOS Boot Sector and the beginning of the next
+ // sector.
+ //
+ PackExtendedBios(&_dos_exbpb, _pexbpb);
+ *(((PUCHAR)_pexbpb) + 510) = 0x55;
+ *(((PUCHAR)_pexbpb) + 511) = 0xAA;
+ memcpy( ((PUCHAR)_pexbpb) + 512, FirstDbSignature, DbSignatureLength );
+
+ CvfPackCvfHeader((PPACKED_CVF_HEADER)SECRUN::GetBuf(),
+ &_cvf_header);
+
+
+ if (!SECRUN::Write()) {
+
+ if (!_fat || !_dir) {
+ Message->Set(MSG_CANT_WRITE_BOOT_SECTOR);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!secrun.Initialize(&_mem, _drive, 0, _sec_per_boot) ||
+ !secrun.Write()) {
+ Message->Set(MSG_CANT_WRITE_BOOT_SECTOR);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!_dir->Write()) {
+ Message->Set(MSG_CANT_WRITE_ROOT_DIR);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!_cvf_extens->Write()) {
+ Message->Set(MSG_CANT_WRITE_FAT_EXTENS);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!_fat->Write()) {
+ Message->Set(MSG_BAD_FAT_WRITE);
+ Message->Display("");
+ return FALSE;
+ } else {
+ Message->Set(MSG_SOME_FATS_UNWRITABLE);
+ Message->Display("");
+ }
+ }
+
+ return TRUE;
+}
+
+
+SECTORCOUNT
+FATDB_SA::QueryFreeSectors(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of unused sectors on disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of free sectors on disk.
+
+--*/
+{
+ if (!_fat) {
+ perrstk->push(ERR_NOT_READ, QueryClassId());
+ return 0;
+ }
+
+ return _fat->QueryFreeClusters()*QuerySectorsPerCluster();
+}
+
+
+FATTYPE
+FATDB_SA::QueryFatType(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the FATTYPE of the FAT for this volume.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The FATTYPE for the FAT.
+
+--*/
+{
+ return _ft;
+}
+
+
+VOID
+FATDB_SA::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine cleans up the local data in the fat super area.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DELETE(_fat);
+ DELETE(_dir);
+
+ _StartDataLbn = 0;
+ _ClusterCount = 0;
+ _sysid = SYSID_NONE;
+}
+
+#if !defined(_SETUP_LOADER_)
+
+USHORT
+FATDB_SA::ComputeRootEntries(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine uses the size of the disk and a standard table in
+ order to compute the required number of root directory entries.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The required number of root directory entries.
+
+--*/
+{
+ switch (_drive->QueryMediaType()) {
+
+ case F3_720_512:
+ case F5_360_512:
+ case F5_320_512:
+ case F5_320_1024:
+ case F5_180_512:
+ case F5_160_512:
+ return 112;
+
+ case F5_1Pt2_512:
+ case F3_1Pt44_512:
+ return 224;
+
+ case F3_2Pt88_512:
+ case F3_20Pt8_512:
+ return 240;
+ }
+
+ return 512;
+}
+
+
+USHORT
+FATDB_SA::ComputeSecClus(
+ IN SECTORCOUNT Sectors,
+ IN FATTYPE FatType,
+ IN MEDIA_TYPE MediaType
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the number of sectors per cluster required
+ based on the actual number of sectors.
+
+Arguments:
+
+ Sectors - Supplies the total number of sectors on the disk.
+ FatType - Supplies the type of FAT.
+ MediaType - Supplies the type of the media.
+
+Return Value:
+
+ The required number of sectors per cluster.
+
+--*/
+{
+ USHORT sec_per_clus;
+ SECTORCOUNT threshold;
+
+ if (FatType == SMALL) {
+ threshold = MIN_CLUS_BIG;
+ sec_per_clus = 1;
+ } else {
+ threshold = MAX_CLUS_BIG;
+ sec_per_clus = 1;
+ }
+
+ while (Sectors >= threshold) {
+ sec_per_clus *= 2;
+ threshold *= 2;
+ }
+
+ switch (MediaType) {
+
+ case F5_320_512:
+ case F5_360_512:
+ case F3_720_512:
+ case F3_2Pt88_512:
+ sec_per_clus = 2;
+ break;
+
+ case F3_20Pt8_512:
+ sec_per_clus = 4;
+ break;
+
+ default:
+ break;
+
+ }
+
+ return sec_per_clus;
+}
+
+#endif // _SETUP_LOADER_
+
+ULONG
+FATDB_SA::SecPerBoot()
+{
+ return _sec_per_boot;
+}
+
+INLINE
+BOOLEAN
+FATDB_SA::SetOemData(
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the OEM data in both the CVF MDBPB and
+ the DOS Sector 0 Extended BPB.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ memcpy( (void*)_cvf_header.Oem, (void*)OEMDBTEXT, OEMTEXTLENGTH);\
+ memcpy( (void*)_dos_exbpb.OemData, (void*)OEMDBTEXT, OEMTEXTLENGTH );
+ return TRUE;
+}
+
+BOOLEAN
+FATDB_SA::SetSignature(
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the sector zero signature in the super area.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ if (!_sector_sig) {
+ perrstk->push(ERR_NOT_INIT, QueryClassId());
+ return FALSE;
+ }
+
+ *_sector_sig = sigSUPERSEC1;
+ *(_sector_sig + 1) = sigSUPERSEC2;
+
+
+ return TRUE;
+}
+
+BOOLEAN
+FATDB_SA::SetBootCode(
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the boot code in the super area.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ _cvf_header.Jump = 0xEB;
+ _cvf_header.JmpOffset = 0x903C;
+ SetBootSignature();
+ return TRUE;
+}
+
+BOOLEAN
+FATDB_SA::VerifyBootSector(
+ )
+/*++
+
+Routine Description:
+
+ This routine checks key parts of sector 0 to insure that the data
+ being examined is indeed a zero sector.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Invalid sector zero.
+ TRUE - Valid sector zero.
+
+--*/
+{
+ PUCHAR p;
+
+// We don't check for 55 AA anymore because we have reason to
+// believe that there are versions of FORMAT out there that
+// don't put it down.
+
+#if 0
+ if (!IsFormatted()) {
+ return FALSE;
+ }
+#endif
+
+ p = (PUCHAR) GetBuf();
+
+ return p[0] == 0xE9 || (p[0] == 0xEB && p[2] == 0x90);
+}
+
+BOOLEAN
+FATDB_SA::SetPhysicalDriveType(
+ IN PHYSTYPE PhysType
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the physical drive type in the super area.
+
+Arguments:
+
+ PhysType -- Supplies the physical drive type.
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure.
+
+--*/
+{
+ _dos_exbpb.PhysicalDrive = (UCHAR)PhysType;
+ return TRUE;
+}
+
+BOOLEAN
+FATDB_SA::SetBpb(
+ )
+{
+ // BUGBUG billmc -- do we need this?
+ //
+ DbgPrintf( "UFAT: Unsupported function FATDB_SA::SetBpb called.\n" );
+ return FALSE;
+}
+
+BOOLEAN
+FATDB_SA::SetExtendedBpb(
+ )
+/*++
+
+Routine Description:
+
+ This routine sets fields in the extended dos bpb.
+
+Arguments:
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure.
+
+--*/
+{
+ //
+ // Copy the bpb to the dos_bpb, then set the fields that are
+ // different.
+ //
+ _dos_exbpb.IntelNearJumpCommand = _cvf_header.Jump;
+ _dos_exbpb.BootStrapJumpOffset = _cvf_header.JmpOffset;
+
+ memcpy(&_dos_exbpb.Bpb, &_cvf_header.Bpb, sizeof(_cvf_header.Bpb));
+
+ _dos_exbpb.Bpb.Fats = 2;
+ _dos_exbpb.Bpb.LargeSectors += _cvf_header.Bpb.SectorsPerFat;
+
+ SetVolId(ComputeVolId());
+
+ if (_ft == SMALL) {
+ memcpy(_dos_exbpb.SystemIdText, "FAT12 ", cSYSID);
+ } else {
+ memcpy(_dos_exbpb.SystemIdText, "FAT16 ", cSYSID);
+ }
+
+ memcpy(_dos_exbpb.Label, "DBLSPACE ", cLABEL);
+
+ return
+ SetPhysicalDriveType(_drive->IsRemovable() ?
+ PHYS_REMOVABLE : PHYS_FIXED) &&
+ SetOemData() &&
+ SetBootSignature() &&
+ SetSignature();
+}
+
+BOOLEAN
+FATDB_SA::RecoverChain(
+ IN OUT PUSHORT StartingCluster,
+ OUT PBOOLEAN ChangesMade,
+ IN USHORT EndingCluster,
+ IN BOOLEAN Replace
+ )
+{
+ // This is here to support FAT_SA::RecoverFile.
+ return TRUE;
+}
+
+BOOLEAN
+FATDB_SA::IsClusterCompressed(
+ IN ULONG Cluster
+ ) CONST
+{
+ return _cvf_extens->IsClusterCompressed(Cluster);
+}
+
+ULONG
+FATDB_SA::QuerySectorFromCluster(
+ IN ULONG Cluster,
+ IN OUT PUCHAR NumSectors
+ )
+{
+ return _cvf_extens->QuerySectorFromCluster(Cluster, NumSectors);
+}
+
+VOID
+FATDB_SA::SetClusterCompressed(
+ IN ULONG Cluster,
+ IN BOOLEAN bCompressed
+ )
+{
+ _cvf_extens->SetClusterCompressed(Cluster, bCompressed);
+}
+
+UCHAR
+FATDB_SA::QuerySectorsRequiredForPlainData(
+ IN ULONG Cluster
+ )
+{
+ return _cvf_extens->QuerySectorsRequiredForPlainData(Cluster);
+}
+
+BOOLEAN
+FATDB_SA::VerifyFatExtensions(
+ IN FIX_LEVEL FixLevel,
+ IN PMESSAGE Message,
+ IN PBOOLEAN pfNeedMsg
+ )
+/*++
+
+Routine Description:
+
+ This routine examines the fat extensions, changing entries if
+ necessary to ensure that they match the fat and that they are
+ valid.
+
+Arguments:
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure.
+
+--*/
+{
+ ULONG cluster;
+
+ for (cluster = FirstDiskCluster; cluster < _ClusterCount; ++cluster) {
+
+ if (!_cvf_extens->IsClusterInUse(cluster) &&
+ (_fat->IsClusterFree(cluster) || _fat->IsClusterBad(cluster) ||
+ _fat->IsClusterReserved(cluster))) {
+ continue;
+ }
+
+ if ((_fat->IsInRange(_fat->QueryEntry(cluster)) ||
+ _fat->IsEndOfChain(cluster)) &&
+ !_cvf_extens->IsClusterInUse(cluster)) {
+
+ //
+ // The fat thinks this entry is in use, but the fat extensions
+ // disagree. Clear the fat entry.
+ //
+
+ dofmsg(Message, pfNeedMsg);
+ Message->Set(MSG_DBLSPACE_FAT_EXTENS_MISMATCH);
+ Message->Display("%d", cluster);
+
+ _fat->SetClusterFree(cluster);
+ continue;
+ }
+
+ if (_cvf_extens->IsClusterInUse(cluster) &&
+ (_fat->IsClusterBad(cluster) || _fat->IsClusterReserved(cluster)
+ || _fat->IsClusterFree(cluster))) {
+
+ //
+ // The cvf_extens think this entry is in use, but the fat
+ // disagrees. Clear the cvf extens entry.
+ //
+
+ dofmsg(Message, pfNeedMsg);
+ Message->Set(MSG_DBLSPACE_FAT_EXTENS_MISMATCH);
+ Message->Display("%d", cluster);
+
+ _cvf_extens->SetClusterInUse(cluster, FALSE);
+ _cvf_extens->SetSectorForCluster(cluster, 1, 1);
+ _cvf_extens->SetClusterCompressed(cluster, FALSE);
+ _cvf_extens->SetSectorsRequiredForPlainData(cluster, 1);
+ continue;
+ }
+
+ //
+ // Ensure that the fat extensions entry is valid.
+ //
+
+ UCHAR nsec;
+ ULONG first_sector;
+
+ first_sector = _cvf_extens->QuerySectorFromCluster(cluster, &nsec);
+
+ if (first_sector > _cvf_header.Bpb.LargeSectors - _StartDataLbn ||
+ nsec == 0 || nsec > QuerySectorsPerCluster() ||
+ _cvf_extens->QuerySectorsRequiredForPlainData(cluster) >
+ QuerySectorsPerCluster()) {
+
+ // This entry is bogus.
+
+ dofmsg(Message, pfNeedMsg);
+ Message->Set(MSG_DBLSPACE_FAT_EXTENS_INVALID);
+ Message->Display("%d", cluster);
+
+ _fat->SetClusterFree(cluster);
+ _cvf_extens->SetClusterInUse(cluster, FALSE);
+ _cvf_extens->SetSectorForCluster(cluster, 1, 1);
+ _cvf_extens->SetClusterCompressed(cluster, FALSE);
+ _cvf_extens->SetSectorsRequiredForPlainData(cluster, 1);
+ }
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+FATDB_SA::CheckSectorHeapAllocation(
+ IN FIX_LEVEL FixLevel,
+ IN PMESSAGE Message,
+ IN OUT PBOOLEAN NeedMsg
+ )
+{
+ ULONG cluster;
+ ULONG first_sec;
+ UCHAR nsec;
+
+ DbgAssert(!_sector_heap_init);
+
+ for (cluster = FirstDiskCluster; cluster < _ClusterCount; ++cluster) {
+ if (!_cvf_extens->IsClusterInUse(cluster)) {
+ continue;
+ }
+
+ //
+ // the sector numbers in the fat extensions is from the beginning of
+ // the cvf, but the bitmap is from the beginning of the sector heap.
+ //
+
+ first_sec = _cvf_extens->QuerySectorFromCluster(cluster, &nsec)
+ - _StartDataLbn;
+
+ if (first_sec > _cvf_header.Bpb.LargeSectors - _StartDataLbn) {
+ //
+ // Sector number out of range. Clear this entry.
+ //
+DbgPrintf("clus 0x%x, lbn 0x%x\n", cluster, _cvf_extens->QuerySectorFromCluster(cluster));
+
+ dofmsg(Message, NeedMsg);
+ Message->Set(MSG_DBLSPACE_SECTOR_RANGE);
+ Message->Display("");
+
+ _fat->SetClusterFree(cluster);
+ _cvf_extens->SetClusterInUse(cluster, FALSE);
+ _cvf_extens->SetSectorForCluster(cluster, 1, 1);
+ _cvf_extens->SetClusterCompressed(cluster, FALSE);
+ _cvf_extens->SetSectorsRequiredForPlainData(cluster, 1);
+
+ continue;
+
+ }
+
+ for (ULONG i = first_sec; i < first_sec + nsec; ++i) {
+ if (_sector_heap_bitmap.IsBitSet(i)) {
+ //
+ // This sector is allocated to another cluster. Clear this
+ // entry.
+ //
+
+ dofmsg(Message, NeedMsg);
+ Message->Set(MSG_DBLSPACE_SECTOR_DUP_ALLOC);
+ Message->Display("");
+
+ _fat->SetClusterFree(cluster);
+ _cvf_extens->SetClusterInUse(cluster, FALSE);
+ _cvf_extens->SetSectorForCluster(cluster, 1, 1);
+ _cvf_extens->SetClusterCompressed(cluster, FALSE);
+ _cvf_extens->SetSectorsRequiredForPlainData(cluster, 1);
+
+ break;
+ }
+ }
+
+ if (_cvf_extens->IsClusterInUse(cluster)) {
+ _sector_heap_bitmap.SetBit(first_sec, nsec);
+ }
+ }
+
+ _sector_heap_init = TRUE;
+ return TRUE;
+}
+
+BOOLEAN
+FATDB_SA::AllocateClusterData(
+ IN ULONG Cluster,
+ IN UCHAR NumSectors,
+ IN BOOLEAN bCompressed,
+ IN UCHAR PlainSize
+ )
+{
+ DbgAssert(NumSectors <= PlainSize);
+ DbgAssert(bCompressed || NumSectors == PlainSize);
+ DbgAssert(_sector_heap_init);
+
+ for (ULONG i = 0; i < _sector_heap_bitmap.QuerySize() - NumSectors; ++i) {
+
+ for (int j = 0; j < NumSectors; ++j) {
+ if (_sector_heap_bitmap.IsBitSet(i + j))
+ break;
+ }
+
+ if (j == NumSectors) {
+
+ // We have found a suitable free space.
+
+ _sector_heap_bitmap.SetBit(i, NumSectors);
+ _cvf_extens->SetSectorForCluster(Cluster, i + _StartDataLbn,
+ NumSectors);
+ _cvf_extens->SetClusterCompressed(Cluster, bCompressed);
+ _cvf_extens->SetSectorsRequiredForPlainData(Cluster, PlainSize);
+ _cvf_extens->SetClusterInUse(Cluster, TRUE);
+
+ return TRUE;
+ }
+ }
+
+ // error: no space
+
+ return FALSE;
+}
+
+BOOLEAN
+FATDB_SA::FreeClusterData(
+ IN ULONG Cluster
+ )
+{
+ ULONG first_sector;
+ UCHAR nsec;
+
+ DbgAssert(_sector_heap_init);
+
+ first_sector = _cvf_extens->QuerySectorFromCluster(Cluster, &nsec)
+ - _StartDataLbn;
+
+ _cvf_extens->SetSectorForCluster(Cluster, 1, 1);
+ _cvf_extens->SetClusterInUse(Cluster, FALSE);
+
+ DbgAssert(_sector_heap_bitmap.IsBitSet(first_sector));
+ DbgAssert(_sector_heap_bitmap.IsBitSet(first_sector + nsec - 1));
+
+ _sector_heap_bitmap.ResetBit(first_sector, nsec);
+
+ return TRUE;
+}
+
+BOOLEAN
+FATDB_SA::SetCvfSectorCount(
+ IN ULONG NewSectorCount
+ )
+{
+ ULONG r;
+
+ _cvf_header.Bpb.LargeSectors = NewSectorCount;
+
+ r = _sector_heap_bitmap.SetSize(NewSectorCount - _StartDataLbn);
+ if (0 == r) {
+ return FALSE;
+ }
+
+ if (!Write(NULL)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/ufat/src/fatdbvol.cxx b/private/utils/ufat/src/fatdbvol.cxx
new file mode 100644
index 000000000..65b9d5f70
--- /dev/null
+++ b/private/utils/ufat/src/fatdbvol.cxx
@@ -0,0 +1,139 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "fatdbvol.hxx"
+
+#include "message.hxx"
+#include "rtmsg.h"
+#include "wstring.hxx"
+
+
+DEFINE_CONSTRUCTOR( FATDB_VOL, VOL_LIODPDRV );
+
+VOID
+FATDB_VOL::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Constructor for FATDB_VOL.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ // unreferenced parameters
+ (void)(this);
+}
+
+VOID
+FATDB_VOL::Destroy(
+ )
+{
+ (void)(this);
+}
+
+FATDB_VOL::~FATDB_VOL(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for FATDB_VOL.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+BOOLEAN
+FATDB_VOL::Initialize(
+ IN PCWSTRING NtDriveName,
+ IN PCWSTRING HostFileName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN ExclusiveWrite
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes a FATDB_VOL object.
+
+Arguments:
+
+ NtDriveName - Supplies the drive path for the volume.
+ HostFileName - Supplies the name of the file which contains
+ this volume.
+ Message - Supplies an outlet for messages.
+ ExclusiveWrite - Supplies whether or not the drive should be
+ opened for exclusive write.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ MESSAGE msg;
+
+ Destroy();
+
+ if (!VOL_LIODPDRV::Initialize(NtDriveName,
+ HostFileName,
+ &_fatdbsa,
+ Message,
+ ExclusiveWrite)) {
+ Destroy();
+ return FALSE;
+ }
+
+
+ if (!Message) {
+ Message = &msg;
+ }
+
+ if (!_fatdbsa.Initialize(this, &msg, TRUE)) {
+ Destroy();
+ return FALSE;
+ }
+
+ if (!_fatdbsa.Read(Message)) {
+ Destroy();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+PVOL_LIODPDRV
+FATDB_VOL::QueryDupVolume(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN ExclusiveWrite,
+ IN BOOLEAN FormatMedia,
+ IN MEDIA_TYPE MediaType
+ ) CONST
+{
+ DbgPrintf( "UFAT: Unsupported function FATDB_VOL::QueryDupVolume called.\n" );
+ return FALSE;
+}
diff --git a/private/utils/ufat/src/fatdent.cxx b/private/utils/ufat/src/fatdent.cxx
new file mode 100644
index 000000000..25718762c
--- /dev/null
+++ b/private/utils/ufat/src/fatdent.cxx
@@ -0,0 +1,1125 @@
+#include <pch.cxx>
+
+#define _UFAT_MEMBER_
+#include "ufat.hxx"
+
+#include "error.hxx"
+#include "ifssys.hxx"
+#include "wstring.hxx"
+
+// TimeInfo is full of windows stuff.
+#if !defined( _AUTOCHECK_ ) && !defined( _SETUP_LOADER_ )
+
+#include "timeinfo.hxx"
+
+#endif
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( FAT_DIRENT, OBJECT, UFAT_EXPORT );
+
+VOID
+FAT_DIRENT::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Constructor for FAT_DIRENT.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _dirent = NULL;
+}
+
+
+UFAT_EXPORT
+FAT_DIRENT::~FAT_DIRENT(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for FAT_DIRENT.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+UFAT_EXPORT
+BOOLEAN
+FAT_DIRENT::Initialize(
+ IN OUT PVOID Dirent
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the object to use the directory entry
+ pointed to by Dirent.
+
+Arguments:
+
+ Dirent - Supplies the directory entry.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ _dirent = (PUCHAR) Dirent;
+ return _dirent ? TRUE : FALSE;
+}
+
+
+UFAT_EXPORT
+VOID
+FAT_DIRENT::QueryName(
+ OUT PWSTRING Name
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine copies the directory entries name to 'Name' in an
+ appropriate format.
+
+ Directories and files will be returned in compressed 8.3 format.
+ Labels will be returned in compressed 11 character format.
+
+Arguments:
+
+ Name - Returns the name of the directory entry in the appropriate
+ format.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ CHNUM i;
+ STR buf[80];
+ DSTRING tmp_string;
+ DSTRING tmp2;
+ CHNUM l;
+
+ if (!_dirent) {
+ Name->Initialize("");
+ return;
+ }
+
+ if (IsVolumeLabel()) {
+ memcpy(buf, _dirent, 11);
+ buf[11] = 0;
+
+ if (buf[0] == 0x05) {
+ buf[0] = (UCHAR)0xE5;
+ }
+
+ tmp_string.Initialize(buf);
+
+ l = tmp_string.QueryChCount();
+
+ for (i = l - 1; i >= 0 && tmp_string.QueryChAt(i) == ' '; i--) {
+ }
+
+ Name->Initialize(&tmp_string, 0, i + 1);
+ return;
+ }
+
+ memcpy(buf, _dirent, 8);
+ buf[8] = 0;
+
+ if (buf[0] == 0x05) {
+ buf[0] = (UCHAR)0xE5;
+ }
+
+ tmp_string.Initialize(buf);
+
+ if (Is8LowerCase()) {
+ tmp_string.Strlwr(0);
+ }
+
+ l = tmp_string.QueryChCount();
+
+ for (i = l - 1; i >= 0 && tmp_string.QueryChAt(i) == ' '; i--) {
+ }
+
+ Name->Initialize(&tmp_string, 0, i + 1);
+
+ memcpy(buf, &_dirent[8], 3);
+ buf[3] = 0;
+
+ tmp_string.Initialize(buf);
+
+ if (Is3LowerCase()) {
+ tmp_string.Strlwr(0);
+ }
+
+ l = tmp_string.QueryChCount();
+
+ for (i = l - 1; i >= 0 && tmp_string.QueryChAt(i) == ' '; i--) {
+ }
+
+ if (i + 1) {
+ tmp2.Initialize(".");
+ Name->Strcat(&tmp2);
+ tmp2.Initialize(&tmp_string, 0, i + 1);
+ Name->Strcat(&tmp2);
+ }
+}
+
+
+BOOLEAN
+FAT_DIRENT::SetName(
+ IN PCWSTRING Name
+ )
+/*++
+
+Routine Description:
+
+ This routine expects a "compressed" null-terminated name in a format
+ compatible with the return value of 'QueryName'.
+
+ The validity of the characters in the name will not be checked
+ by this routine. Only that the name has the appropriate
+ structure. The routine "IsValidName" will check the validity
+ of the name characters.
+
+Arguments:
+
+ Name - Supplies the new name for the directory entry.
+
+Return Value:
+
+ FALSE - The name was invalid.
+ TRUE - The name was successfully set.
+
+--*/
+{
+ CHNUM i, j;
+ STR buf[40];
+ CHNUM l;
+ DSTRING tmp_string;
+
+ if (IsVolumeLabel()) {
+ if (!Name->QuerySTR( 0, TO_END, buf, 40) ||
+ (i = strlen(buf)) > 11) {
+ return FALSE;
+ }
+
+ if (!FAT_SA::IsValidString(Name)) {
+ return FALSE;
+ }
+
+ memset(&_dirent[i], ' ', (UINT) (11 - i));
+ memcpy(_dirent, buf, (UINT) i);
+
+ if (_dirent[0] == 0xE5) {
+ _dirent[0] = 0x05;
+ }
+
+ return TRUE;
+ }
+
+ l = Name->QueryChCount();
+
+ if (Name->QueryChAt(0) == '.' && l == 1) {
+ memcpy(_dirent, ". ", 11);
+ return TRUE;
+ } else if (Name->QueryChAt(0) == '.' &&
+ Name->QueryChAt(1) == '.' &&
+ l == 2) {
+ memcpy(_dirent, ".. ", 11);
+ return TRUE;
+ }
+
+
+ for (i = 0; i < l && Name->QueryChAt(i) != '.'; i++) {
+ }
+
+ if (!tmp_string.Initialize(Name, 0, i)) {
+ return FALSE;
+ }
+
+ if (!tmp_string.QuerySTR( 0, TO_END, buf, 40)) {
+ return FALSE;
+ }
+
+ if ((j = strlen(buf)) > 8) {
+ return FALSE;
+ }
+
+ memset(&buf[j], ' ', (UINT) (11 - j));
+
+ if (i < l) {
+ for (j = i + 1; j < l && Name->QueryChAt(j) != '.'; j++) {
+ }
+
+ if (j < l) {
+ return FALSE;
+ }
+
+ if (i + 1 < l) {
+ if (!tmp_string.Initialize(Name, i + 1)) {
+ return FALSE;
+ }
+
+ if (!tmp_string.QuerySTR( 0, TO_END, &buf[8], 32)) {
+ return FALSE;
+ }
+
+ if ((j = strlen(buf)) > 11) {
+ return FALSE;
+ }
+
+ memset(&buf[j], ' ', (UINT) (11 - j));
+ }
+ }
+
+ memcpy(_dirent, buf, 11);
+
+ if (_dirent[0] == 0xE5) {
+ _dirent[0] = 0x05;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+FAT_DIRENT::IsValidName(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine verifies that the name is composed of valid
+ characters.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - The name is not valid.
+ TRUE - The name is valid.
+
+--*/
+{
+ DSTRING tmp;
+ STR buf[40];
+
+ if (!_dirent) {
+ perrstk->push(ERR_NOT_INIT, QueryClassId());
+ return FALSE;
+ }
+
+ if (IsDot() || IsDotDot()) {
+ return IsDirectory();
+ }
+
+ memcpy(buf, _dirent, 11);
+ buf[11] = 0;
+
+ if (buf[0] == 0x05) {
+ buf[0] = (UCHAR)0xE5;
+ }
+
+ if (!tmp.Initialize(buf)) {
+ return FALSE;
+ }
+
+ return FAT_SA::IsValidString(&tmp);
+}
+
+
+UFAT_EXPORT
+BOOLEAN
+FAT_DIRENT::IsValidLastWriteTime(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine verifies the validity of the last write time.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Invalid time stamp.
+ TRUE - Valid time stamp.
+
+--*/
+{
+ USHORT t;
+ USHORT d;
+
+ DebugAssert(_dirent);
+
+ memcpy(&t, &_dirent[22], sizeof(USHORT)); // time field
+ memcpy(&d, &_dirent[24], sizeof(USHORT)); // date field
+
+ return TimeStampsAreValid(t, d);
+}
+
+UFAT_EXPORT
+BOOLEAN
+FAT_DIRENT::QueryLastWriteTime(
+ OUT LARGE_INTEGER *TimeStamp
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the last write time in the form of a time fields
+ structure.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+
+ TIME_FIELDS TimeFields;
+ USHORT t;
+ USHORT d;
+ USHORT year, month, day, hour, minute, second;
+
+ DebugAssert( _dirent );
+ DebugPtrAssert( TimeStamp );
+
+ memcpy(&t, &_dirent[22], sizeof(USHORT)); // time field
+ memcpy(&d, &_dirent[24], sizeof(USHORT)); // date field
+
+ second = (t&0x001F)*2; // seconds
+ minute = (t&0x07E0)>>5; // Minutes
+ hour = t>>11; // Hours
+ day = d&0x001F; // Day of month 1-31
+ month = (d&0x01E0)>>5; // Month
+ year = (d>>9) + 1980; // Year
+
+ TimeFields.Year = year;
+ TimeFields.Month = month;
+ TimeFields.Day = day;
+ TimeFields.Hour = hour;
+ TimeFields.Minute = minute;
+ TimeFields.Second = second;
+ TimeFields.Milliseconds = 0;
+
+ return RtlTimeFieldsToTime( &TimeFields, (PTIME)TimeStamp );
+}
+
+
+
+BOOLEAN
+FAT_DIRENT::SetLastWriteTime(
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the last write time to the current date and time.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Time stamp was not set successfully.
+ TRUE - Time stamp was set successfully.
+
+--*/
+{
+ USHORT fat_time;
+ USHORT fat_date;
+
+ DebugAssert(_dirent);
+
+ LARGE_INTEGER SystemTime, LocalTime;
+ TIME_FIELDS Time;
+
+
+#if !defined( _SETUP_LOADER_ )
+ IFS_SYSTEM::QueryNtfsTime( &SystemTime );
+ RtlSystemTimeToLocalTime( &SystemTime, &LocalTime );
+#else
+ IFS_SYSTEM::QueryNtfsTime( &LocalTime );
+#endif
+
+ RtlTimeToTimeFields(&LocalTime, &Time);
+
+ fat_time = Time.Second/2;
+ fat_time |= Time.Minute<<5;
+ fat_time |= Time.Hour<<11;
+
+ fat_date = Time.Day;
+ fat_date |= Time.Month<<5;
+ fat_date |= (Time.Year - 1980)<<9;
+
+ memcpy(&_dirent[22], &fat_time, sizeof(USHORT));
+ memcpy(&_dirent[24], &fat_date, sizeof(USHORT));
+
+ return TRUE;
+}
+
+UFAT_EXPORT
+BOOLEAN
+FAT_DIRENT::IsValidCreationTime(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine verifies the validity of the creation time.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Invalid time stamp.
+ TRUE - Valid time stamp.
+
+--*/
+{
+ USHORT t;
+ USHORT d;
+
+ DebugAssert(_dirent);
+
+ memcpy(&t, &_dirent[14], sizeof(USHORT)); // time field
+ memcpy(&d, &_dirent[16], sizeof(USHORT)); // date field
+
+ return TimeStampsAreValid(t, d);
+
+}
+
+UFAT_EXPORT
+BOOLEAN
+FAT_DIRENT::QueryCreationTime(
+ OUT LARGE_INTEGER *TimeStamp
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the creation time in the form of a time fields
+ structure.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ TIME_FIELDS TimeFields;
+ USHORT t;
+ USHORT d;
+ USHORT msec;
+ USHORT year, month, day, hour, minute, second;
+
+ DebugAssert( _dirent );
+ DebugPtrAssert( TimeStamp );
+
+ memcpy(&t, &_dirent[14], sizeof(USHORT)); // time field
+ memcpy(&d, &_dirent[16], sizeof(USHORT)); // date field
+ msec = _dirent[13] * 10; // msec field
+
+ second = (t&0x001F)*2; // seconds
+ minute = (t&0x07E0)>>5; // Minutes
+ hour = t>>11; // Hours
+ day = d&0x001F; // Day of month 1-31
+ month = (d&0x01E0)>>5; // Month
+ year = (d>>9) + 1980; // Year
+
+ if (msec >= 1000) {
+ second += 1;
+ msec -= 1000;
+ }
+
+ TimeFields.Year = year;
+ TimeFields.Month = month;
+ TimeFields.Day = day;
+ TimeFields.Hour = hour;
+ TimeFields.Minute = minute;
+ TimeFields.Second = second;
+ TimeFields.Milliseconds = msec;
+
+ return RtlTimeFieldsToTime( &TimeFields, (PTIME)TimeStamp );
+}
+
+BOOLEAN
+FAT_DIRENT::SetCreationTime(
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the creation time to the current date and time.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Time stamp was not set successfully.
+ TRUE - Time stamp was set successfully.
+
+--*/
+{
+ USHORT fat_time;
+ USHORT fat_date;
+
+ DebugAssert(_dirent);
+
+ LARGE_INTEGER SystemTime, LocalTime;
+ TIME_FIELDS Time;
+
+
+#if !defined( _SETUP_LOADER_ )
+ IFS_SYSTEM::QueryNtfsTime( &SystemTime );
+ RtlSystemTimeToLocalTime( &SystemTime, &LocalTime );
+#else
+ IFS_SYSTEM::QueryNtfsTime( &LocalTime );
+#endif
+
+ RtlTimeToTimeFields(&LocalTime, &Time);
+
+ fat_time = Time.Second/2;
+ fat_time |= Time.Minute<<5;
+ fat_time |= Time.Hour<<11;
+
+ fat_date = Time.Day;
+ fat_date |= Time.Month<<5;
+ fat_date |= (Time.Year - 1980)<<9;
+
+ memcpy(&_dirent[14], &fat_time, sizeof(USHORT));
+ memcpy(&_dirent[16], &fat_date, sizeof(USHORT));
+
+ return TRUE;
+}
+
+UFAT_EXPORT
+BOOLEAN
+FAT_DIRENT::IsValidLastAccessTime(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine verifies the validity of the last access time.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Invalid time stamp.
+ TRUE - Valid time stamp.
+
+--*/
+{
+ USHORT t = 0;
+ USHORT d;
+
+ DebugAssert(_dirent);
+
+ memcpy(&d, &_dirent[18], sizeof(USHORT)); // date field
+
+ return TimeStampsAreValid(t, d);
+}
+
+UFAT_EXPORT
+BOOLEAN
+FAT_DIRENT::QueryLastAccessTime(
+ OUT LARGE_INTEGER *TimeStamp
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the last access time in the form of a time fields
+ structure.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+
+ TIME_FIELDS TimeFields;
+ USHORT t;
+ USHORT d;
+ USHORT year, month, day, hour, minute, second;
+
+ DebugAssert( _dirent );
+ DebugPtrAssert( TimeStamp );
+
+ t = 0; // no time for last access; just date
+ memcpy(&d, &_dirent[18], sizeof(USHORT)); // date field
+
+ second = (t&0x001F)*2; // seconds
+ minute = (t&0x07E0)>>5; // Minutes
+ hour = t>>11; // Hours
+ day = d&0x001F; // Day of month 1-31
+ month = (d&0x01E0)>>5; // Month
+ year = (d>>9) + 1980; // Year
+
+ TimeFields.Year = year;
+ TimeFields.Month = month;
+ TimeFields.Day = day;
+ TimeFields.Hour = hour;
+ TimeFields.Minute = minute;
+ TimeFields.Second = second;
+ TimeFields.Milliseconds = 0;
+
+ return RtlTimeFieldsToTime( &TimeFields, (PTIME)TimeStamp );
+}
+
+BOOLEAN
+FAT_DIRENT::SetLastAccessTime(
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the last access time to the current date and time.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Time stamp was not set successfully.
+ TRUE - Time stamp was set successfully.
+
+--*/
+{
+ USHORT fat_date;
+
+ DebugAssert(_dirent);
+
+ LARGE_INTEGER SystemTime, LocalTime;
+ TIME_FIELDS Time;
+
+
+#if !defined( _SETUP_LOADER_ )
+ IFS_SYSTEM::QueryNtfsTime( &SystemTime );
+ RtlSystemTimeToLocalTime( &SystemTime, &LocalTime );
+#else
+ IFS_SYSTEM::QueryNtfsTime( &LocalTime );
+#endif
+
+ RtlTimeToTimeFields(&LocalTime, &Time);
+
+ fat_date = Time.Day;
+ fat_date |= Time.Month<<5;
+ fat_date |= (Time.Year - 1980)<<9;
+
+ memcpy(&_dirent[18], &fat_date, sizeof(USHORT));
+
+ return TRUE;
+}
+
+VOID
+FAT_DIRENT::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the object to its initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _dirent = NULL;
+}
+
+UCHAR
+RotateCharRight(
+ IN UCHAR Char,
+ IN INT Shift
+ )
+/*++
+
+Routine Description:
+
+ This function rotates an eight-bit character right by the
+ specified number of bits.
+
+Arguments:
+
+ Char -- Supplies the character to rotate
+ Shift -- Supplies the number of bits to shift
+
+Return Value:
+
+ The rotated character.
+
+--*/
+{
+ UCHAR low_bit;
+
+ Shift %= 8;
+
+ while( Shift-- ) {
+
+ low_bit = Char & 1;
+ Char >>= 1;
+ if( low_bit ) {
+ Char |= 0x80;
+ }
+ }
+
+ return (UCHAR)Char;
+}
+
+UCHAR
+FAT_DIRENT::QueryChecksum(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ This method gets the checksum from the directory entry. If
+ the entry is a short entry, the checksum is computed; if the
+ entry is long, the checksum field is returned.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The directory entry's checksum.
+
+--*/
+{
+ int name_length;
+ UCHAR sum;
+ PUCHAR name;
+
+ if( IsLongEntry() ) {
+
+ return( _dirent[13] );
+
+ } else {
+
+ sum = 0;
+ name = _dirent;
+ for( name_length = 11; name_length != 0; name_length-- ) {
+
+ sum = RotateCharRight(sum, 1) + *name++;
+ }
+
+ return( sum );
+ }
+}
+
+BOOLEAN
+FAT_DIRENT::IsWellTerminatedLongNameEntry(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method determines whether the entry is a well-terminated
+ long-name entry. A long-name entry is well terminated if:
+
+
+--*/
+{
+ ULONG i;
+ WCHAR Name[13];
+
+ if( IsErased() || !IsLongNameEntry() ) {
+
+ return FALSE;
+ }
+
+ // Assemble the bits and pieces of the name:
+ //
+ memcpy( &Name[0], &_dirent[1], 10 );
+ memcpy( &Name[5], &_dirent[14], 12 );
+ memcpy( &Name[11], &_dirent[28], 4 );
+
+ if( IsLastLongEntry() ) {
+
+ // Valid syntax for the last name entry is:
+ //
+ // N* {0 0xFFFF*}
+ //
+ // where N is the set of non-null characters.
+ //
+ for( i = 0; i < 13; i++ ) {
+
+ if( Name[i] == 0 ) {
+
+ break;
+ }
+ }
+
+ if( i < 13 ) {
+
+ // We hit a null character--step over it.
+ //
+ i++;
+ }
+
+ // The rest of the name-component must be 0xFFFF.
+ //
+ for( ; i < 13; i++ ) {
+
+ if( Name[i] != 0xFFFF ) {
+
+ return FALSE;
+ }
+ }
+
+ // This name-component was accepted.
+ //
+ return TRUE;
+
+ } else {
+
+#if 0
+ // This is an additional consistency check that
+ // could be performed; however, now (as of 3/28/94)
+ // the file-system doesn't care, so neither do we.
+
+ // This is not the last component of the name, so
+ // it can't have any NULL's in it.
+ //
+ for( i = 0; i < 13; i++ ) {
+
+ if( Name[i] == 0 ) {
+
+ return FALSE;
+ }
+ }
+#endif
+
+ return TRUE;
+ }
+}
+
+BOOLEAN
+FAT_DIRENT::QueryLongNameComponent(
+ OUT PWSTRING NameComponent
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method extracts the long-name component from a Long Name
+ Directory Entry.
+
+Arguments:
+
+ NameComponent -- Receives the long-name component
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ ULONG i;
+ WCHAR Name[13];
+
+ if( IsErased() || !IsLongNameEntry() ) {
+
+ return FALSE;
+ }
+
+ // Assemble the bits and pieces of the name:
+ //
+ memcpy( &Name[0], &_dirent[1], 10 );
+ memcpy( &Name[5], &_dirent[14], 12 );
+ memcpy( &Name[11], &_dirent[28], 4 );
+
+ // Long names may be zero terminated; however, if the
+ // name fits exactly into n long entries will not be
+ // zero terminated.
+ //
+ for( i = 0; i < 13 && Name[i]; i++ );
+
+ return( NameComponent->Initialize( Name, i ) );
+}
+
+BOOLEAN
+FAT_DIRENT::NameHasTilde(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine checks a short name entry to see if it contains a tilde.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE - Tilde.
+ FALSE - No tilde.
+
+--*/
+{
+ USHORT i;
+
+ if (IsErased() || IsLongNameEntry()) {
+ return FALSE;
+ }
+
+ for (i = 0; i < 11; ++i) {
+ if ('~' == _dirent[i]) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+BOOLEAN
+FAT_DIRENT::NameHasExtendedChars(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine determines whether there are any extended chars
+ (those with value >= 0x80) in the short file name.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE - There are one or more extended chars.
+ FALSE - There are no extended chars.
+
+--*/
+{
+ USHORT i;
+
+ if (IsErased() || IsLongNameEntry()) {
+ return FALSE;
+ }
+
+ for (i = 0; i < 11; ++i) {
+ if (_dirent[i] >= 0x80) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+BOOLEAN
+FAT_DIRENT::TimeStampsAreValid(
+ USHORT t,
+ USHORT d
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine examines the given time and date fields and
+ determines whether they represent valid dates.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE - The time and date are valid.
+ FALSE - One or both are invalid.
+
+--*/
+{
+ USHORT tmp;
+ tmp = t&0x001F; // 2-second increments
+ if (tmp > 29) {
+ return FALSE;
+ }
+
+ tmp = (t&0x07E0)>>5; // Minutes
+ if (tmp > 59) {
+ return FALSE;
+ }
+
+ tmp = (t&0xF800)>>11; // Hours
+ if (tmp > 23) {
+ return FALSE;
+ }
+
+ tmp = d&0x001F; // Day of month
+ if (tmp < 1 || tmp > 31) {
+ return FALSE;
+ }
+
+ tmp = (d&0x01E0)>>5; // Month
+ if (tmp < 1 || tmp > 12) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/ufat/src/fatdir.cxx b/private/utils/ufat/src/fatdir.cxx
new file mode 100644
index 000000000..3323389f7
--- /dev/null
+++ b/private/utils/ufat/src/fatdir.cxx
@@ -0,0 +1,201 @@
+#include <pch.cxx>
+
+#define _UFAT_MEMBER_
+#include "ufat.hxx"
+
+#include "error.hxx"
+#include "wstring.hxx"
+
+
+DEFINE_CONSTRUCTOR( FATDIR, OBJECT );
+
+UFAT_EXPORT
+PVOID
+FATDIR::SearchForDirEntry(
+ IN PCWSTRING FileName
+ )
+/*++
+
+Routine Description:
+
+ This routine gets the directory entry with the (null-terminated)
+ filename 'FileName'. If no such directory entry exists then
+ this routine return NULL.
+
+Arguments:
+
+ FileName - The name of the file searched for.
+
+Return Value:
+
+ A pointer to a directory entry or NULL.
+
+--*/
+{
+ FAT_DIRENT dirent;
+ ULONG i;
+ DSTRING filename;
+ PVOID p;
+
+ for (i = 0; dirent.Initialize(p = GetDirEntry(i)); i++) {
+
+ if (dirent.IsEndOfDirectory()) {
+ break;
+ }
+
+ if (dirent.IsErased()) {
+ continue;
+ }
+
+ dirent.QueryName(&filename);
+
+ if (dirent.IsVolumeLabel()) {
+ continue;
+ }
+
+ if (*FileName == filename) {
+ return p;
+ }
+
+ if (QueryLongName(i, &filename) && (*FileName == filename)) {
+ return p;
+ }
+ }
+
+ return NULL;
+}
+
+
+PVOID
+FATDIR::GetFreeDirEntry(
+ )
+/*++
+
+Routine Description:
+
+ This routine gets an unused directory entry, if one exists.
+ If one doesn't exist then this routine returns NULL.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to a directory entry or NULL.
+
+--*/
+{
+ FAT_DIRENT dirent;
+ ULONG i;
+ PVOID p;
+
+ for (i = 0; dirent.Initialize(p = GetDirEntry(i)); i++) {
+
+ if (dirent.IsEndOfDirectory()) {
+ if (dirent.Initialize(GetDirEntry(i + 1))) {
+ dirent.SetEndOfDirectory();
+ }
+ return p;
+ }
+
+ if (dirent.IsErased()) {
+ return p;
+ }
+ }
+
+ return NULL;
+}
+
+
+UFAT_EXPORT
+BOOLEAN
+FATDIR::QueryLongName(
+ IN LONG EntryNumber,
+ OUT PWSTRING LongName
+ )
+/*++
+
+Routine Description:
+
+ This method fetches the long file name associated with the
+ short directory entry at index EntryNumber.
+
+Arguments:
+
+ EntryNumber
+ LongName -- Receives the long name associated with this entry.
+ Receives "" if there is no long name.
+
+Return Value:
+
+ TRUE upon successful completion
+ FALSE to indicate failure or disk corruption.
+
+--*/
+{
+ DSTRING NameComponent;
+ FAT_DIRENT CurrentEntry;
+ LONG CurrentIndex;
+ ULONG Ordinal = 1;
+ UCHAR Checksum;
+
+ CurrentIndex = EntryNumber;
+
+ if( !CurrentEntry.Initialize( GetDirEntry( CurrentIndex ) ) ||
+ !LongName->Initialize( "" ) ) {
+
+ return FALSE;
+ }
+
+ Checksum = CurrentEntry.QueryChecksum();
+
+ CurrentIndex--;
+
+ for( ; CurrentIndex >= 0; CurrentIndex-- ) {
+
+ if( !CurrentEntry.Initialize( GetDirEntry( CurrentIndex ) ) ) {
+
+ return FALSE;
+ }
+
+ if( CurrentEntry.IsErased() || !CurrentEntry.IsLongEntry() ) {
+
+ // The long name entries are not valid--return an
+ // empty string for the long name.
+ //
+ return( LongName->Initialize( "" ) );
+ }
+
+ if( CurrentEntry.IsLongNameEntry() ) {
+
+ if( CurrentEntry.QueryLongOrdinal() != Ordinal ||
+ CurrentEntry.QueryChecksum() != Checksum ) {
+
+ // The long-name entries don't belong to the
+ // specified short entry.
+ //
+ return( LongName->Initialize( "" ) );
+ }
+
+ if( !CurrentEntry.QueryLongNameComponent( &NameComponent ) ||
+ !LongName->Strcat( &NameComponent ) ) {
+
+ return FALSE;
+ }
+
+ if( CurrentEntry.IsLastLongEntry() ) {
+
+ // This was the last entry.
+ //
+ return TRUE;
+ }
+
+ Ordinal++;
+ }
+ }
+
+ // There is no long name, or it is not valid.
+ //
+ return( LongName->Initialize( "" ) );
+}
diff --git a/private/utils/ufat/src/fatsa.cxx b/private/utils/ufat/src/fatsa.cxx
new file mode 100644
index 000000000..db3bd7ce5
--- /dev/null
+++ b/private/utils/ufat/src/fatsa.cxx
@@ -0,0 +1,866 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ fatsa.cxx
+
+Author:
+
+ Mark Shavlik (marks) 27-Mar-90
+ Norbert Kusters (norbertk) 15-Jan-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _UFAT_MEMBER_
+#include "ufat.hxx"
+
+#include "cmem.hxx"
+#include "error.hxx"
+#include "rtmsg.h"
+#include "drive.hxx"
+#include "bootfat.h"
+
+#if !defined(_AUTOCHECK_) && !defined(_SETUP_LOADER_)
+#include "timeinfo.hxx"
+#endif
+
+
+// Control-C handling is not necessary for autocheck.
+#if !defined( _AUTOCHECK_ ) && !defined(_SETUP_LOADER_)
+
+#include "keyboard.hxx"
+
+#endif
+
+
+#define CSEC_FAT32MEG 65536
+#define CSEC_FAT16BIT 32680
+
+#define MIN_CLUS_BIG 4085 // Minimum clusters for a big FAT.
+#define MAX_CLUS_BIG 65525 // Maximum + 1 clusters for big FAT.
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( FAT_SA, SUPERAREA, UFAT_EXPORT );
+
+VOID
+FAT_SA::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Constructor for FAT_SA.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _fat = NULL;
+ _dir = NULL;
+}
+
+
+UFAT_EXPORT
+FAT_SA::~FAT_SA(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for FAT_SA.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+BOOLEAN
+FAT_SA::RecoverFile(
+ IN PCWSTRING FullPathFileName,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine runs through the clusters for the file described by
+ 'FileName' and takes out bad sectors.
+
+Arguments:
+
+ FullPathFileName - Supplies a full path name of the file to recover.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+#if defined( _SETUP_LOADER_ )
+
+ return FALSE;
+
+#else // _SETUP_LOADER_
+
+
+ HMEM hmem;
+ USHORT clus;
+ BOOLEAN changes;
+ PFATDIR fatdir;
+ BOOLEAN need_delete;
+ FAT_DIRENT dirent;
+ ULONG old_file_size;
+ ULONG new_file_size;
+
+ if ((clus = QueryFileStartingCluster(FullPathFileName,
+ &hmem,
+ &fatdir,
+ &need_delete,
+ &dirent)) == 1) {
+ Message->Set(MSG_FILE_NOT_FOUND);
+ Message->Display("%W", FullPathFileName);
+ return FALSE;
+ }
+
+ if (clus == 0xFFFF) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (clus == 0) {
+ Message->Set(MSG_FILE_NOT_FOUND);
+ Message->Display("%W", FullPathFileName);
+ return FALSE;
+ }
+
+ if (dirent.IsDirectory()) {
+ old_file_size = _drive->QuerySectorSize()*
+ QuerySectorsPerCluster()*
+ _fat->QueryLengthOfChain(clus);
+ } else {
+ old_file_size = dirent.QueryFileSize();
+ }
+
+ if (!RecoverChain(&clus, &changes)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (dirent.IsDirectory() || changes) {
+ new_file_size = _drive->QuerySectorSize()*
+ QuerySectorsPerCluster()*
+ _fat->QueryLengthOfChain(clus);
+ } else {
+ new_file_size = old_file_size;
+ }
+
+ if (changes) {
+
+
+// Autochk doesn't need control C handling.
+#if !defined( _AUTOCHECK_ )
+
+ // Disable contol-C handling and
+
+ if (!KEYBOARD::EnableBreakHandling()) {
+ Message->Set(MSG_CANT_LOCK_THE_DRIVE);
+ Message->Display("");
+ return FALSE;
+ }
+
+#endif
+
+
+ // Lock the drive in preparation for writes.
+
+ if (!_drive->Lock()) {
+ Message->Set(MSG_CANT_LOCK_THE_DRIVE);
+ Message->Display("");
+ return FALSE;
+ }
+
+ dirent.SetStartingCluster(clus);
+
+ dirent.SetFileSize(new_file_size);
+
+ if (!fatdir->Write()) {
+ return FALSE;
+ }
+
+ if (!Write(Message)) {
+ return FALSE;
+ }
+
+
+// Autochk doesn't need control C handling.
+#if !defined( _AUTOCHECK_ )
+
+ KEYBOARD::DisableBreakHandling();
+
+#endif
+
+
+ }
+
+ Message->Set(MSG_RECOV_BYTES_RECOVERED);
+ Message->Display("%d%d", new_file_size, old_file_size);
+
+
+ if (need_delete) {
+ DELETE(fatdir);
+ }
+
+ return TRUE;
+
+#endif // _SETUP_LOADER_
+}
+
+
+SECTORCOUNT
+FAT_SA::QueryFreeSectors(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of unused sectors on disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of free sectors on disk.
+
+--*/
+{
+ if (!_fat) {
+ perrstk->push(ERR_NOT_READ, QueryClassId());
+ return 0;
+ }
+
+ return _fat->QueryFreeClusters()*QuerySectorsPerCluster();
+}
+
+
+FATTYPE
+FAT_SA::QueryFatType(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the FATTYPE of the FAT for this volume.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The FATTYPE for the FAT.
+
+--*/
+{
+ return _ft;
+}
+
+
+
+#if !defined( _AUTOCHECK_ ) && !defined(_SETUP_LOADER_)
+
+BOOLEAN
+FAT_SA::QueryLabel(
+ OUT PWSTRING Label
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine queries the label from the FAT superarea.
+ If the label is not present then 'Label' will return the null-string.
+ If the label is invalid then FALSE will be returned.
+
+Arguments:
+
+ Label - Returns a volume label.
+
+Return Value:
+
+ FALSE - The label is invalid.
+ TRUE - The label is valid.
+
+--*/
+{
+ return QueryLabel(Label, NULL);
+}
+
+
+BOOLEAN
+FAT_SA::QueryLabel(
+ OUT PWSTRING Label,
+ OUT PTIMEINFO TimeInfo
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine queries the label from the FAT superarea.
+ If the label is not present then 'Label' will return the null-string.
+ If the label is invalid then FALSE will be returned.
+
+Arguments:
+
+ Label - Returns a volume label.
+
+Return Value:
+
+ FALSE - The label is invalid.
+ TRUE - The label is valid.
+
+--*/
+{
+ INT i;
+ FAT_DIRENT dirent;
+ FILETIME TimeStamp;
+
+ DebugAssert(_dir);
+
+ for (i = 0; ; i++) {
+ if (!dirent.Initialize(_dir->GetDirEntry(i)) ||
+ dirent.IsEndOfDirectory()) {
+ return Label->Initialize("");
+ }
+
+ if (!dirent.IsErased() && dirent.IsVolumeLabel()) {
+ break;
+ }
+ }
+
+ dirent.QueryName(Label);
+
+ if ( TimeInfo ) {
+ return ( dirent.QueryLastWriteTime( (LARGE_INTEGER *)&TimeStamp ) &&
+ TimeInfo->Initialize( &TimeStamp ) );
+ }
+
+ return TRUE;
+}
+
+#else // _AUTOCHECK_ or _SETUP_LOADER_ is defined
+
+BOOLEAN
+FAT_SA::QueryLabel(
+ OUT PWSTRING Label
+ ) CONST
+{
+ INT i;
+ FAT_DIRENT dirent;
+
+ DebugAssert(_dir);
+
+ for (i = 0; ; i++) {
+ if (!dirent.Initialize(_dir->GetDirEntry(i)) ||
+ dirent.IsEndOfDirectory()) {
+ return Label->Initialize("");
+ }
+
+ if (!dirent.IsErased() && dirent.IsVolumeLabel()) {
+ break;
+ }
+ }
+
+ dirent.QueryName(Label);
+
+ return TRUE;
+}
+
+
+#endif // _AUTOCHECK_
+
+
+BOOLEAN
+FAT_SA::SetLabel(
+ IN PCWSTRING NewLabel
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the label for a FAT partition.
+
+Arguments:
+
+ NewLabel - Supplies the new volume label.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ FAT_DIRENT dirent;
+ INT i;
+ DSTRING label;
+
+ if (!_dir) {
+ return FALSE;
+ }
+
+ if (!label.Initialize(NewLabel)) {
+ return FALSE;
+ }
+
+ if (!label.Strupr()) {
+ return FALSE;
+ }
+
+ if (!IsValidString(&label)) {
+ return FALSE;
+ }
+
+ for (i = 0; dirent.Initialize(_dir->GetDirEntry(i)); i++) {
+ if (dirent.IsEndOfDirectory()) {
+ break;
+ }
+
+ if (dirent.IsErased()) {
+ continue;
+ }
+
+ if (dirent.IsVolumeLabel()) {
+ if (!label.QueryChCount()) {
+ dirent.SetErased();
+ return TRUE;
+ }
+
+ return (BOOLEAN) (dirent.SetLastWriteTime() &&
+ dirent.SetName(&label));
+ }
+ }
+
+ if (!label.QueryChCount()) {
+ return TRUE;
+ }
+
+ if (!dirent.Initialize(_dir->GetFreeDirEntry())) {
+ return FALSE;
+ }
+
+ dirent.Clear();
+ dirent.SetVolumeLabel();
+
+ return (BOOLEAN) (dirent.SetLastWriteTime() && dirent.SetName(&label));
+}
+
+
+UFAT_EXPORT
+USHORT
+FAT_SA::QueryFileStartingCluster(
+ IN PCWSTRING FullPathFileName,
+ OUT PHMEM Hmem,
+ OUT PPFATDIR Directory,
+ OUT PBOOLEAN DeleteDirectory,
+ OUT PFAT_DIRENT DirEntry
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the starting cluster number of the file described
+ by 'FileName' by tracing through the directories leading to the file.
+
+Arguments:
+
+ FullPathFileName - Supplies a full path file name that starts with
+ a '\' (i.e. no drive spec).
+
+Return Value:
+
+ The starting cluster for the file or 1 if the file is not found or
+ 0xFFFF if there was an error.
+
+--*/
+{
+ CHNUM i, j, l;
+ DSTRING component;
+ USHORT clus;
+ FAT_DIRENT the_dirent;
+ PFILEDIR filedir;
+ PFAT_DIRENT dirent;
+ HMEM hmem;
+
+
+ DebugAssert(_dir);
+ DebugAssert(_fat);
+
+ filedir = NULL;
+
+ if (!Hmem) {
+ Hmem = &hmem;
+ }
+
+ if (DirEntry) {
+ dirent = DirEntry;
+ } else {
+ dirent = &the_dirent;
+ }
+
+ l = FullPathFileName->QueryChCount();
+
+ for (i = 0; i < l && FullPathFileName->QueryChAt(i) != '\\'; i++) {
+ }
+
+ if (i == l) {
+ return 0xFFFF;
+ }
+
+ if (i == l - 1) { // root directory
+ return 0;
+ }
+
+ j = ++i;
+ for (; i < l && FullPathFileName->QueryChAt(i) != '\\'; i++) {
+ }
+
+ if (!component.Initialize(FullPathFileName, j, i - j) ||
+ !component.Strupr()) {
+ return 1;
+ }
+
+ if (!dirent->Initialize(_dir->SearchForDirEntry(&component))) {
+ return 1;
+ }
+
+ if (!(clus = dirent->QueryStartingCluster())) {
+ return 0;
+ }
+
+ while (i < l) {
+
+ if (!filedir &&
+ !(filedir = NEW FILEDIR)) {
+ return 0xFFFF;
+ }
+
+ if (!Hmem->Initialize() ||
+ !filedir->Initialize(Hmem, _drive, this, _fat, clus)) {
+ return 0xFFFF;
+ }
+
+ if (!filedir->Read()) {
+ return 1;
+ }
+
+ j = ++i;
+ for (; i < l && FullPathFileName->QueryChAt(i) != '\\'; i++) {
+ }
+
+ if (!component.Initialize(FullPathFileName, j, i - j) ||
+ !component.Strupr()) {
+ return 0xFFFF;
+ }
+
+ if (!dirent->Initialize(filedir->SearchForDirEntry(&component))) {
+ return 1;
+ }
+
+ if (!(clus = dirent->QueryStartingCluster())) {
+ return 1;
+ }
+ }
+
+ if (Directory) {
+ if (filedir) {
+ *Directory = filedir;
+ if (DeleteDirectory) {
+ *DeleteDirectory = TRUE;
+ }
+ } else {
+ *Directory = _dir;
+ if (DeleteDirectory) {
+ *DeleteDirectory = FALSE;
+ }
+ }
+ } else {
+ DELETE(filedir);
+ }
+
+ return clus;
+}
+
+
+VOID
+FAT_SA::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine cleans up the local data in the fat super area.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DELETE(_fat);
+ DELETE(_dir);
+}
+
+
+FATTYPE
+FAT_SA::ComputeFatType(
+ ) CONST
+/*++
+
+Routine Description:
+
+ Given the total number of clusters on the disk, this routine computes
+ whether the FAT will be a 16 bit FAT or a 12 bit FAT.
+
+Arguments:
+
+ ClusterCount - Supplies the number of clusters on the disk.
+
+Return Value:
+
+ SMALL - A 12 bit FAT is required.
+ LARGE - A 16 bit FAT is required.
+
+--*/
+{
+ return ComputeSystemId() == SYSID_FAT12BIT ? SMALL : LARGE;
+}
+
+
+PARTITION_SYSTEM_ID
+FAT_SA::ComputeSystemId(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the system id for a FAT file system with
+ the given number of sectors.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The correct system id for this partition.
+
+--*/
+{
+ SECTORCOUNT disk_size;
+
+ disk_size = QueryVirtualSectors();
+
+ return disk_size < CSEC_FAT16BIT ? SYSID_FAT12BIT :
+ disk_size < CSEC_FAT32MEG ? SYSID_FAT16BIT :
+ SYSID_FAT32MEG;
+}
+
+#if !defined(_SETUP_LOADER_)
+
+USHORT
+FAT_SA::ComputeRootEntries(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine uses the size of the disk and a standard table in
+ order to compute the required number of root directory entries.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The required number of root directory entries.
+
+--*/
+{
+ switch (_drive->QueryMediaType()) {
+
+ case F3_720_512:
+ case F5_360_512:
+ case F5_320_512:
+ case F5_320_1024:
+ case F5_180_512:
+ case F5_160_512:
+ return 112;
+
+ case F5_1Pt2_512:
+ case F3_1Pt44_512:
+ return 224;
+
+ case F3_2Pt88_512:
+ case F3_20Pt8_512:
+ return 240;
+ }
+
+ return 512;
+}
+
+
+USHORT
+FAT_SA::ComputeSecClus(
+ IN SECTORCOUNT Sectors,
+ IN FATTYPE FatType,
+ IN MEDIA_TYPE MediaType
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the number of sectors per cluster required
+ based on the actual number of sectors.
+
+Arguments:
+
+ Sectors - Supplies the total number of sectors on the disk.
+ FatType - Supplies the type of FAT.
+ MediaType - Supplies the type of the media.
+
+Return Value:
+
+ The required number of sectors per cluster.
+
+--*/
+{
+ USHORT sec_per_clus;
+ SECTORCOUNT threshold;
+
+ if (FatType == SMALL) {
+ threshold = MIN_CLUS_BIG;
+ sec_per_clus = 1;
+ } else {
+ threshold = MAX_CLUS_BIG;
+ sec_per_clus = 1;
+ }
+
+ while (Sectors >= threshold) {
+ sec_per_clus *= 2;
+ threshold *= 2;
+ }
+
+ switch (MediaType) {
+
+ case F5_320_512:
+ case F5_360_512:
+ case F3_720_512:
+ case F3_2Pt88_512:
+ sec_per_clus = 2;
+ break;
+
+ case F3_20Pt8_512:
+ sec_per_clus = 4;
+ break;
+
+ default:
+ break;
+
+ }
+
+ return sec_per_clus;
+}
+
+#endif // _SETUP_LOADER_
+
+
+BOOLEAN
+FAT_SA::IsValidString(
+ IN PCWSTRING String
+ )
+/*++
+
+Routine Description:
+
+ This routine determines whether or not the given null-terminated string
+ has any invalid characters in it.
+
+Arguments:
+
+ String - Supplies the string to validate.
+
+Return Value:
+
+ FALSE - The string contains invalid characters.
+ TRUE - The string is free from invalid characters.
+
+Notes:
+
+ The list of invalid characters is stricter than HPFS requires.
+
+--*/
+{
+ CHNUM i, l;
+
+ l = String->QueryChCount();
+
+ for (i = 0; i < l; i++) {
+ if (String->QueryChAt(i) < 32) {
+ return FALSE;
+ }
+
+ switch (String->QueryChAt(i)) {
+ case '*':
+ case '?':
+ case '/':
+ case '\\':
+ case '|':
+ case ',':
+ case ';':
+ case ':':
+ case '+':
+ case '=':
+ case '<':
+ case '>':
+ case '[':
+ case ']':
+ case '"':
+ case '.':
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/ufat/src/fatsachk.cxx b/private/utils/ufat/src/fatsachk.cxx
new file mode 100644
index 000000000..e285b2cdc
--- /dev/null
+++ b/private/utils/ufat/src/fatsachk.cxx
@@ -0,0 +1,3246 @@
+#include <pch.cxx>
+
+#include "bitvect.hxx"
+#include "error.hxx"
+#include "intstack.hxx"
+#include "rtmsg.h"
+#include "ifsentry.hxx"
+
+
+// Timeinfo is full of windows stuff.
+#if !defined( _AUTOCHECK_ ) && !defined( _SETUP_LOADER_ )
+
+#include "timeinfo.hxx"
+
+#endif
+
+#define FAT_BPB_RESERVED_DIRTY 0x01
+#define FAT_BPB_RESERVED_TEST_SURFACE 0x02
+
+extern "C" {
+ #include <stdio.h>
+}
+
+
+VOID
+dofmsg(
+ IN PMESSAGE Message,
+ IN OUT PBOOLEAN NeedErrorsMessage
+ )
+{
+ if (*NeedErrorsMessage) {
+ Message->Set(MSG_CORRECTIONS_WILL_NOT_BE_WRITTEN, NORMAL_MESSAGE, TEXT_MESSAGE);
+ Message->Display("");
+ *NeedErrorsMessage = FALSE;
+ }
+}
+
+STATIC VOID
+EraseAssociatedLongName(
+ PFATDIR Dir,
+ INT FirstLongEntry,
+ INT ShortEntry
+ )
+{
+ FAT_DIRENT dirent;
+
+ for (int j = FirstLongEntry; j < ShortEntry; ++j) {
+ dirent.Initialize(Dir->GetDirEntry(j));
+ dirent.SetErased();
+ }
+}
+
+STATIC BOOLEAN
+IsString8Dot3(
+ PCWSTRING s
+ )
+/*++
+
+Routine Description:
+
+ This routine is used to ensure that lfn's legally correspond
+ to their short names. The given string is examined to see if it
+ is a legal fat 8.3 name.
+
+Arguments:
+
+ s -- lfn to examine.
+
+Return Value:
+
+ TRUE - The string is a legal 8.3 name.
+ FALSE - Not legal.
+
+--*/
+{
+ USHORT i;
+ BOOLEAN extension_present = FALSE;
+ WCHAR c;
+
+ //
+ // The name can't be more than 12 characters (including a single dot).
+ //
+
+ if (s->QueryChCount() > 12) {
+ return FALSE;
+ }
+
+ for (i = 0; i < s->QueryChCount(); ++i) {
+
+ c = s->QueryChAt(i);
+
+#if 0
+ if (!FsRtlIsAnsiCharLegalFat(c, FALSE) {
+ return FALSE;
+ }
+#endif
+
+ if (c == '.') {
+
+ //
+ // We stepped onto a period. We require the following things:
+ //
+ // - it can't be the first character
+ // - there can be only one
+ // - there can't be more that 3 characters following it
+ // - the previous character can't be a space
+ //
+
+ if (i == 0 ||
+ extension_present ||
+ s->QueryChCount() - (i + 1) > 3 ||
+ s->QueryChAt(i - 1) == ' ') {
+
+ return FALSE;
+ }
+ extension_present = TRUE;
+ }
+
+ //
+ // The base part of the name can't be more than 8 characters long.
+ //
+
+ if (i >= 8 && !extension_present) {
+ return FALSE;
+ }
+
+ }
+
+ //
+ // The name cannot end in a space or a period.
+ //
+
+ if (c == ' ' || c == '.') {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+FAT_SA::VerifyAndFix(
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ IN BOOLEAN OnlyIfDirty,
+ IN BOOLEAN RecoverFree,
+ IN BOOLEAN RecoverAlloc,
+ IN BOOLEAN /* ResizeLogFile */,
+ IN ULONG /* LogFileSize */,
+ OUT PULONG ExitStatus,
+ IN PCWSTRING DriveLetter
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies the FAT superarea and if neccessary fixes
+ it to a correct state.
+
+Arguments:
+
+ FixLevel - Supplies the level of fixes that may be performed on
+ the disk.
+ Message - Supplies an outlet for messages.
+ Verbose - Supplies whether or not to be verbose.
+ OnlyIfDirty - Supplies whether or not to continue if the volume
+ is clean.
+ RecoverFree - Supplies whether or not to recover the free sectors on
+ the volume.
+ RecoverAlloc - Supplies whether or not to recover the allocated
+ sectors on the volume.
+ ExitStatus - Returns an indication of the result of the check
+ DriveLetter - For autocheck, supplies the letter of the volume
+ being checked
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ FAT_DIRENT eadent;
+ ULONG cluster_size;
+ USHORT ea_clus_num;
+ USHORT num_eas;
+ PEA_INFO ea_infos;
+ USHORT cluster_count;
+ HMEM ea_header_mem;
+ EA_HEADER ea_header;
+ BOOLEAN changes;
+ BITVECTOR fat_bitmap;
+ FATCHK_REPORT report;
+ PUSHORT p;
+ VOLID volid;
+ USHORT free_count, bad_count, total_count;
+ BOOLEAN fmsg;
+ DSTRING label;
+ DSTRING eafilename;
+ DSTRING eafilepath;
+ BOOLEAN tmp_bool;
+ USHORT tmp_ushort;
+ DSTRING date;
+ DSTRING time;
+ UCHAR dirty_byte, media_byte;
+
+ if (NULL == ExitStatus) {
+ ExitStatus = &report.ExitStatus;
+ }
+ report.ExitStatus = CHKDSK_EXIT_SUCCESS;
+ *ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
+
+ fmsg = TRUE;
+
+ if (FixLevel != CheckOnly) {
+ fmsg = FALSE;
+ }
+
+ if (QueryLength() <= SecPerBoot()) {
+ Message->Set(MSG_NOT_FAT);
+ Message->Display("");
+ return FALSE;
+ }
+
+ //
+ // Check to see if the dirty bit is set.
+ //
+
+ if (OnlyIfDirty) {
+ dirty_byte = QueryVolumeFlags();
+
+ if ((dirty_byte &
+ (FAT_BPB_RESERVED_DIRTY | FAT_BPB_RESERVED_TEST_SURFACE)) == 0) {
+ Message->Set(MSG_CHK_VOLUME_CLEAN);
+ Message->Display();
+ *ExitStatus = CHKDSK_EXIT_SUCCESS;
+ return TRUE;
+ }
+
+ // If the second bit of the dirty byte is set then
+ // also perform a full recovery of the free and allocated
+ // space.
+
+ if (dirty_byte & FAT_BPB_RESERVED_TEST_SURFACE) {
+ RecoverFree = TRUE;
+ RecoverAlloc = TRUE;
+ }
+
+ //
+ // The volume is not clean, so if we're autochecking we want to
+ // make sure that we're printing real messages on the console
+ // instead of just dots.
+ //
+
+#ifdef _AUTOCHECK_
+
+ BOOLEAN bPrev;
+
+ Message->SetLoggingEnabled();
+
+ bPrev = Message->SetDotsOnly(FALSE);
+
+ if (bPrev) {
+
+ if (NULL != DriveLetter) {
+ Message->Set(MSG_CHK_RUNNING);
+ Message->Display("%W", DriveLetter);
+ }
+
+ Message->Set(MSG_FILE_SYSTEM_TYPE);
+ Message->Display("%s", "FAT");
+ }
+
+#endif /* _AUTOCHECK */
+ }
+
+
+ // The BPB's Media Byte must be in the set accepted
+ // by the file system.
+ //
+ media_byte = QueryMediaByte();
+
+ if ((media_byte != 0xf0) &&
+ (media_byte != 0xf8) &&
+ (media_byte != 0xf9) &&
+ (media_byte != 0xfc) &&
+ (media_byte != 0xfd) &&
+ (media_byte != 0xfe) &&
+ (media_byte != 0xff)) {
+
+ SetMediaByte(_drive->QueryMediaByte());
+ }
+
+
+ // First print out the label and volume serial number.
+
+// We won't bother printing this message under autocheck.
+#if !defined( _AUTOCHECK_ ) && !defined( _SETUP_LOADER_ )
+
+ TIMEINFO timeinfo;
+
+ if ((QueryLabel(&label, &timeinfo) || label.Initialize("")) &&
+ label.QueryChCount() &&
+ timeinfo.QueryDate(&date) &&
+ timeinfo.QueryTime(&time)) {
+
+ Message->Set(MSG_VOLUME_LABEL_AND_DATE);
+ Message->Display("%W%W%W", &label, &date, &time);
+ }
+
+#else
+#if 0
+
+ if (QueryLabel(&label) && label.QueryChCount() > 0) {
+ Message->Set(MSG_VOLUME_LABEL);
+ Message->Display("%W", &label);
+ }
+
+#endif
+#endif // !_AUTOCHECK_ && !_SETUP_LOADER_
+
+
+ if (volid = QueryVolId()) {
+ p = (PUSHORT) &volid;
+ Message->Set(MSG_VOLUME_SERIAL_NUMBER);
+ Message->Display("%04X%04X", p[1], p[0]);
+ }
+
+
+
+ // Validate the FAT.
+
+ _fat->Scrub(&changes);
+
+ if (changes) {
+ dofmsg(Message, &fmsg);
+ Message->Set(MSG_CHK_ERRORS_IN_FAT);
+ Message->Display("");
+ }
+
+
+ // Make sure that the media type in the BPB is the same as at
+ // the beginning of the FAT.
+
+ if (QueryMediaByte() != _fat->QueryMediaByte()) {
+ dofmsg(Message, &fmsg);
+ Message->Set(MSG_PROBABLE_NON_DOS_DISK);
+ Message->Display("");
+ if (!Message->IsYesResponse(FALSE)) {
+ report.ExitStatus = CHKDSK_EXIT_SUCCESS;
+ return TRUE;
+ }
+
+ _fat->SetEarlyEntries(QueryMediaByte());
+ }
+
+
+ // Compute the cluster size and the number of clusters on disk.
+
+ cluster_size = _drive->QuerySectorSize()*QuerySectorsPerCluster();
+ cluster_count = QueryClusterCount();
+
+
+ // No EAs have been detected yet.
+
+ ea_infos = NULL;
+ num_eas = 0;
+
+
+ // Create an EA file name string.
+
+ if (!eafilename.Initialize("EA DATA. SF") ||
+ !eafilepath.Initialize("\\EA DATA. SF")) {
+ return FALSE;
+ }
+
+
+ // This bitmap will be reinitialized before 'WalkDirectoryTree'.
+ // Its contents will be ignored until then.
+
+ if (!fat_bitmap.Initialize(cluster_count)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+
+ // If there is an EA file on disk then...
+
+ if (eadent.Initialize(_dir->SearchForDirEntry(&eafilename))) {
+
+
+ // Validate the EA file directory entry.
+
+ if (!ValidateDirent(&eadent, &eafilepath, FixLevel, FALSE, Message,
+ &fmsg, &fat_bitmap, &tmp_bool, &tmp_ushort,
+ ExitStatus)) {
+ return FALSE;
+ }
+
+
+ // If the EA file directory entry was valid then...
+
+ if (!eadent.IsErased()) {
+
+
+ // The EA file should not have an EA handle.
+
+ if (eadent.QueryEaHandle()) {
+ dofmsg(Message, &fmsg);
+ Message->Set(MSG_CHK_EAFILE_HAS_HANDLE);
+ Message->Display("");
+ eadent.SetEaHandle(0);
+ *ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ }
+
+
+ // Compute the EA file's starting cluster.
+
+ ea_clus_num = eadent.QueryStartingCluster();
+
+
+ // Perform any log operations recorded at the beginning
+ // of the EA file.
+
+ if (!PerformEaLogOperations(ea_clus_num, FixLevel,
+ Message, &fmsg)) {
+ return FALSE;
+ }
+
+
+ // Validate the EA file's EA sets and return an array of
+ // information about them.
+
+ ea_infos = RecoverEaSets(ea_clus_num, &num_eas, FixLevel,
+ Message, &fmsg);
+
+
+ // If there are no valid EAs in the EA file then erase
+ // the EA file.
+
+ if (!ea_infos) {
+
+ if (num_eas) {
+ return FALSE;
+ }
+
+ eadent.SetErased();
+
+ dofmsg(Message, &fmsg);
+ Message->Set(MSG_CHK_EMPTY_EA_FILE);
+ Message->Display("");
+ *ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ }
+ }
+ }
+
+
+ // Initialize FAT bitmap to be used in detection of cross-links.
+
+ if (!fat_bitmap.Initialize(cluster_count)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display("");
+ DELETE(ea_infos);
+ return FALSE;
+ }
+
+ if (!CheckSectorHeapAllocation(FixLevel, Message, &fmsg)) {
+ DELETE(ea_infos);
+ return FALSE;
+ }
+
+ if (!VerifyFatExtensions(FixLevel, Message, &fmsg)) {
+ DELETE(ea_infos);
+ return FALSE;
+ }
+
+ // Validate all of the files on the disk.
+
+ if (!WalkDirectoryTree(ea_infos, num_eas, &fat_bitmap, &report,
+ FixLevel, RecoverAlloc, Message, Verbose, &fmsg)) {
+ DELETE(ea_infos);
+ return FALSE;
+ }
+
+
+ // If there are EAs on the disk then...
+
+ if (ea_infos) {
+
+ // Remove all unused EAs from EA file.
+
+ if (!PurgeEaFile(ea_infos, num_eas, &fat_bitmap, FixLevel, Message,
+ &fmsg)) {
+ DELETE( ea_infos );
+ return FALSE;
+ }
+
+
+ // Rebuild header portion of EA file.
+
+ if (!ea_header_mem.Initialize() ||
+ !RebuildEaHeader(&ea_clus_num, ea_infos, num_eas,
+ &ea_header_mem, &ea_header, &fat_bitmap,
+ FixLevel, Message, &fmsg)) {
+ DELETE( ea_infos );
+ return FALSE;
+ }
+
+ if (ea_clus_num) {
+ eadent.SetStartingCluster(ea_clus_num);
+ eadent.SetFileSize(cluster_size*
+ _fat->QueryLengthOfChain(ea_clus_num));
+ } else {
+ dofmsg(Message, &fmsg);
+ Message->Set(MSG_CHK_EMPTY_EA_FILE);
+ Message->Display("");
+
+ eadent.SetErased();
+ }
+ *ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ }
+
+ //
+ // If WalkDirectoryTree deleted any files, we need to sync the
+ // FAT_EXTENSIONS up with the FAT again.
+ //
+
+ if (!VerifyFatExtensions(FixLevel, Message, &fmsg)) {
+ DELETE(ea_infos);
+ return FALSE;
+ }
+
+
+ if (!RecoverOrphans(&fat_bitmap, FixLevel, Message, &fmsg)) {
+ DELETE(ea_infos);
+ return FALSE;
+ }
+
+ //
+ // RecoverOrphans may have cleared faulty entries from the FAT,
+ // and now we need to sync the FAT_EXTENSIONS again.
+ //
+
+ if (!VerifyFatExtensions(FixLevel, Message, &fmsg)) {
+ DELETE(ea_infos);
+ return FALSE;
+ }
+
+
+ // If requested, validate all of the free space on the volume.
+
+ if (RecoverFree && !RecoverFreeSpace(Message)) {
+ DELETE(ea_infos);
+ return FALSE;
+ }
+
+ total_count = cluster_count - FirstDiskCluster;
+
+ Message->Set(MSG_TOTAL_DISK_SPACE);
+ Message->Display("%9u", cluster_size*total_count);
+
+ if (report.HiddenEntriesCount) {
+ Message->Set(MSG_HIDDEN_FILES);
+ Message->Display("%9u%d",
+ cluster_size*report.HiddenClusters, report.HiddenEntriesCount);
+ }
+
+ if (report.DirEntriesCount) {
+ Message->Set(MSG_DIRECTORIES);
+ Message->Display("%9u%d",
+ cluster_size*report.DirClusters, report.DirEntriesCount);
+ }
+
+ if (report.FileEntriesCount) {
+ Message->Set(MSG_USER_FILES);
+ Message->Display("%9u%d",
+ cluster_size*report.FileClusters, report.FileEntriesCount);
+ }
+
+ if (bad_count = _fat->QueryBadClusters()) {
+ Message->Set(MSG_BAD_SECTORS);
+ Message->Display("%9u", cluster_size*bad_count);
+ }
+
+ if (ea_infos) {
+ Message->Set(MSG_CHK_EA_SIZE);
+ Message->Display("%9u",
+ cluster_size*_fat->QueryLengthOfChain(ea_clus_num));
+ }
+
+ free_count = _fat->QueryFreeClusters();
+
+ Message->Set(MSG_AVAILABLE_DISK_SPACE);
+ Message->Display("%9u", cluster_size*free_count);
+
+ Message->Set(MSG_ALLOCATION_UNIT_SIZE);
+ Message->Display("%9u", cluster_size);
+
+ Message->Set(MSG_TOTAL_ALLOCATION_UNITS);
+ Message->Display("%9u", total_count);
+
+ Message->Set(MSG_AVAILABLE_ALLOCATION_UNITS);
+ Message->Display("%9u", free_count);
+
+
+ if (FixLevel != CheckOnly && ea_infos && !ea_header.Write()) {
+ DELETE(ea_infos);
+ return FALSE;
+ }
+
+ // Clear the dirty bit.
+ //
+ if( RecoverAlloc ) {
+ SetVolumeFlags(FAT_BPB_RESERVED_DIRTY | FAT_BPB_RESERVED_TEST_SURFACE,
+ TRUE);
+ } else {
+ SetVolumeFlags(FAT_BPB_RESERVED_DIRTY, TRUE);
+ }
+
+
+ if (FixLevel != CheckOnly && !Write(Message)) {
+ DELETE(ea_infos);
+ return FALSE;
+ }
+
+ if (changes) {
+ report.ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ }
+
+ *ExitStatus = report.ExitStatus;
+
+ DELETE(ea_infos);
+ return TRUE;
+}
+
+
+BOOLEAN
+FAT_SA::PerformEaLogOperations(
+ IN USHORT EaFileCn,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN NeedErrorsMessage
+ )
+/*++
+
+Routine Description:
+
+ This routine reads the EA file log from the disk and then performs
+ any logged operations specified.
+
+Arguments:
+
+ EaFileCn - Supplies the first cluster of the EA file.
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages.
+ NeedErrorsMessage - Supplies whether or not an error has occurred
+ under check only conditions.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ HMEM hmem;
+ EA_HEADER ea_header;
+ PEA_FILE_HEADER pea_header;
+ ULONG cluster_size;
+ USHORT num_clus;
+
+ cluster_size = _drive->QuerySectorSize()*QuerySectorsPerCluster();
+ num_clus = sizeof(EA_FILE_HEADER) + BaseTableSize*sizeof(USHORT);
+ if (num_clus%cluster_size) {
+ num_clus = (USHORT) (num_clus/cluster_size + 1);
+ } else {
+ num_clus = (USHORT) (num_clus/cluster_size);
+ }
+
+ if (!hmem.Initialize() ||
+ !ea_header.Initialize(&hmem, _drive, this, _fat, EaFileCn, num_clus) ||
+ !(pea_header = ea_header.GetEaFileHeader())) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!ea_header.Read()) {
+ Message->Set(MSG_CHK_CANT_CHECK_EA_LOG);
+ Message->Display("");
+ return TRUE;
+ }
+
+ if (pea_header->Signature != HeaderSignature ||
+ pea_header->FormatType ||
+ pea_header->LogType) {
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_BAD_LOG, NORMAL_MESSAGE, TEXT_MESSAGE);
+ Message->Display("");
+ if (Message->IsYesResponse(TRUE)) {
+ pea_header->Signature = HeaderSignature;
+ pea_header->Cluster1 = 0;
+ pea_header->Cluster2 = 0;
+ pea_header->Cluster3 = 0;
+
+ if (FixLevel != CheckOnly) {
+ ea_header.Write();
+ }
+
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+
+ if (pea_header->Cluster1) {
+ if (_fat->IsInRange(pea_header->Cluster1) &&
+ _fat->IsInRange(pea_header->NewCValue1)) {
+ _fat->SetEntry(pea_header->Cluster1, pea_header->NewCValue1);
+ } else {
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_ERROR_IN_LOG);
+ Message->Display("");
+ }
+ }
+
+ if (pea_header->Cluster2) {
+ if (_fat->IsInRange(pea_header->Cluster2) &&
+ _fat->IsInRange(pea_header->NewCValue2)) {
+ _fat->SetEntry(pea_header->Cluster2, pea_header->NewCValue2);
+ } else {
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_ERROR_IN_LOG);
+ Message->Display("");
+ }
+ }
+
+ if (pea_header->Cluster3) {
+ if (_fat->IsInRange(pea_header->Cluster3) &&
+ _fat->IsInRange(pea_header->NewCValue3)) {
+ _fat->SetEntry(pea_header->Cluster3, pea_header->NewCValue3);
+ } else {
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_ERROR_IN_LOG);
+ Message->Display("");
+ }
+ }
+
+ return TRUE;
+}
+
+
+PEA_INFO
+FAT_SA::RecoverEaSets(
+ IN USHORT EaFileCn,
+ OUT PUSHORT NumEas,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN NeedErrorsMessage
+ )
+/*++
+
+Routine Description:
+
+ This routine validates and if necessary recovers the EA file.
+
+Arguments:
+
+ EaFileCn - Supplies the cluster number for the EA file.
+ NumEas - Returns the number of EA sets in the EA file.
+ FixLevel - Supplies the CHKDSK fix level.
+ Message - Supplies an outlet for messages.
+ NeedErrorsMessage - Supplies whether or not an error has occurred
+ under check only conditions.
+
+Return Value:
+
+ An allocated array containing 'NumberOfEaSets' entries documenting
+ important information about the EA sets. If there are no EAs then
+ 'NumberOfEaSets' is returned as 0 and NULL is returned. If there
+ is an error then NULL will be returned with a non-zero
+ 'NumberOfEaSets'.
+
+--*/
+{
+ PEA_INFO ea_infos;
+ USHORT clus, prev;
+ USHORT num_eas;
+ USHORT i;
+
+ DebugAssert(NumEas);
+
+ *NumEas = 1;
+
+ ea_infos = NEW EA_INFO[_fat->QueryLengthOfChain(EaFileCn)];
+ if (!ea_infos) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display("");
+ return NULL;
+ }
+
+
+ // Scan file for EA sets and validate them while updating the
+ // array.
+
+ num_eas = 0;
+ prev = EaFileCn;
+ while (!_fat->IsEndOfChain(prev)) {
+
+ clus = VerifyAndFixEaSet(prev, &ea_infos[num_eas], FixLevel,
+ Message, NeedErrorsMessage);
+
+ if (clus) {
+ num_eas++;
+ } else {
+ clus = _fat->QueryEntry(prev);
+ }
+
+ prev = clus;
+ }
+
+ if (!num_eas) {
+ DELETE( ea_infos );
+ *NumEas = 0;
+ return NULL;
+ }
+
+
+ // Go through and remove unused portions of the EA file.
+
+ for (i = 0; i < (USHORT)(num_eas - 1); i++) {
+ if (ea_infos[i].LastCn != ea_infos[i + 1].PreceedingCn) {
+
+ _fat->RemoveChain(ea_infos[i].LastCn,
+ ea_infos[i + 1].PreceedingCn);
+
+ dofmsg(Message, NeedErrorsMessage);
+
+ Message->Set(MSG_CHK_UNUSED_EA_PORTION);
+ Message->Display("");
+
+ ea_infos[i + 1].PreceedingCn = ea_infos[i].LastCn;
+ }
+ }
+
+ if (!_fat->IsEndOfChain(ea_infos[num_eas - 1].LastCn)) {
+
+ _fat->SetEndOfChain(ea_infos[num_eas - 1].LastCn);
+
+ dofmsg(Message, NeedErrorsMessage);
+
+ Message->Set(MSG_CHK_UNUSED_EA_PORTION);
+ Message->Display("");
+ }
+
+
+ // Sort the EAs in the EA file.
+
+ if (!EaSort(ea_infos, num_eas, Message, NeedErrorsMessage)) {
+ return NULL;
+ }
+
+ *NumEas = num_eas;
+
+ return ea_infos;
+}
+
+
+USHORT
+FAT_SA::VerifyAndFixEaSet(
+ IN USHORT PreceedingCluster,
+ OUT PEA_INFO EaInfo,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN NeedErrorsMessage
+ )
+/*++
+
+Routine Description:
+
+ This routine attempts to identify the clusters following the
+ 'PreceedingCluster' as an EA set. If this routine does not
+ recognize these clusters as an EA set then it will return 0.
+ Otherwise, it will return the last cluster of the validated EA set.
+
+ Changes may be made to the clusters if they are recognized as an EA
+ set with errors.
+
+Arguments:
+
+ PreceedingCluster - Supplies the cluster preceeding the EA set cluster.
+ Info - Returns information about the EA set.
+ FixLevel - Supplies the CHKDSK fix level.
+ Message - Supplies an outlet for messages.
+ NeedErrorsMessage - Supplies whether or not errors have occurred
+ under check only conditions.
+
+Return Value:
+
+ The cluster number of the last cluster in the EA set or 0.
+
+--*/
+{
+ HMEM hmem;
+ EA_SET easet;
+ USHORT clus;
+ PEA_HDR eahdr;
+ LONG i;
+ USHORT j;
+ ULONG need_count;
+ LONG total_size;
+ LONG size;
+ USHORT length;
+ BOOLEAN need_write;
+ PEA pea;
+ BOOLEAN more;
+ USHORT chain_length;
+
+ clus = _fat->QueryEntry(PreceedingCluster);
+ chain_length = _fat->QueryLengthOfChain(clus);
+
+ length = 1;
+ need_write = FALSE;
+
+ if (!hmem.Initialize() ||
+ !easet.Initialize(&hmem, _drive, this, _fat, clus, length) ||
+ !(eahdr = easet.GetEaSetHeader())) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display("");
+ return 0;
+ }
+
+ if (!easet.Read()) {
+ return 0;
+ }
+
+ if (!easet.VerifySignature()) {
+ return 0;
+ }
+
+ need_count = 0;
+ total_size = 4;
+ for (i = 0; ; i++) {
+ for (j = 0; !(pea = easet.GetEa(i, &size, &more)) && more &&
+ length + j < chain_length; ) {
+ j++;
+ if (!hmem.Initialize() ||
+ !easet.Initialize(&hmem, _drive, this, _fat, clus, length + j)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display("");
+ return 0;
+ }
+
+ if (!easet.Read()) {
+ return 0;
+ }
+ }
+
+ if (pea) {
+ length += j;
+ } else {
+ break;
+ }
+
+ total_size += size;
+
+ if (pea->Flag & NeedFlag) {
+ need_count++;
+ }
+ }
+
+ if (!i) {
+ return 0;
+ }
+
+ if (total_size != eahdr->TotalSize) {
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_EASET_SIZE);
+ Message->Display("%d", clus);
+ eahdr->TotalSize = total_size;
+ need_write = TRUE;
+ }
+
+ if (need_count != eahdr->NeedCount) {
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_EASET_NEED_COUNT);
+ Message->Display("%d", clus);
+ eahdr->NeedCount = need_count;
+ need_write = TRUE;
+ }
+
+ EaInfo->OwnHandle = eahdr->OwnHandle;
+ EaInfo->PreceedingCn = PreceedingCluster;
+ EaInfo->LastCn = _fat->QueryNthCluster(PreceedingCluster, length);
+ memcpy(EaInfo->OwnerFileName, eahdr->OwnerFileName, 14);
+ EaInfo->UsedCount = 0;
+
+ if (need_write) {
+ if (FixLevel != CheckOnly && !easet.Write()) {
+ return 0;
+ }
+ }
+
+ return EaInfo->LastCn;
+}
+
+
+BOOLEAN
+FAT_SA::EaSort(
+ IN OUT PEA_INFO EaInfos,
+ IN USHORT NumEas,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN NeedErrorsMessage
+ )
+/*++
+
+Routine Description:
+
+ This routine sorts the EaInfos array by 'OwnHandle' into ascending order.
+ It also edits the FAT with the changes in the EAs order.
+
+Arguments:
+
+ EaInfos - Supplies the array of EA_INFOs to sort.
+ NumEas - Supplies the number of elements in the array.
+ Message - Supplies an outlet for messages.
+ NeedErrorsMessage - Supplies whether or not errors have occurred
+ under check only conditions.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ BOOLEAN done;
+ EA_INFO tmp;
+ USHORT clus;
+ LONG i;
+ BOOLEAN change;
+
+ done = FALSE;
+ change = FALSE;
+ while (!done) {
+ done = TRUE;
+ for (i = 0; i < NumEas - 1; i++) {
+ if (EaInfos[i].OwnHandle > EaInfos[i + 1].OwnHandle) {
+ done = FALSE;
+
+ clus = _fat->RemoveChain(EaInfos[i + 1].PreceedingCn,
+ EaInfos[i + 1].LastCn);
+
+ _fat->InsertChain(clus,
+ EaInfos[i + 1].LastCn,
+ EaInfos[i].PreceedingCn);
+
+ EaInfos[i + 1].PreceedingCn = EaInfos[i].PreceedingCn;
+ EaInfos[i].PreceedingCn = EaInfos[i + 1].LastCn;
+ if (i + 2 < NumEas) {
+ EaInfos[i + 2].PreceedingCn = EaInfos[i].LastCn;
+ }
+
+ change = TRUE;
+
+ tmp = EaInfos[i];
+ EaInfos[i] = EaInfos[i + 1];
+ EaInfos[i + 1] = tmp;
+ }
+ }
+ }
+
+ if (change) {
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_UNORDERED_EA_SETS);
+ Message->Display("");
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+FAT_SA::RebuildEaHeader(
+ IN OUT PUSHORT StartingCluster,
+ IN OUT PEA_INFO EaInfos,
+ IN USHORT NumEas,
+ IN OUT PMEM EaHeaderMem,
+ OUT PEA_HEADER EaHeader,
+ IN OUT PBITVECTOR FatBitMap,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN NeedErrorsMessage
+ )
+/*++
+
+Routine Description:
+
+ This routine rebuilds the header and tables of the EA file base on the
+ information in the 'EaInfos' array. The header log is set to zero,
+ and the header itself is relocated if any of the clusters are bad.
+
+ The starting cluster may be relocated if there are bad clusters.
+
+Arguments:
+
+ StartingCluster - Supplies the first cluster of the EA file.
+ EaInfos - Supplies an array containing information for every
+ EA set.
+ NumberOfEas - Supplies the total number of EA sets.
+ EaHeaderMem - Supplies the memory for the EA header.
+ EaHeader - Returns the EA header.
+ FatBitMap - Supplies the cross-links bitmap.
+ FixLevel - Supplies the CHKDSK fix level.
+ Message - Supplies an outlet for messages.
+ NeedErrorsMessage - Supplies whether or not errors have occurred
+ under check only conditions.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG length;
+ ULONG cluster_size;
+ USHORT actual_length;
+ USHORT new_chain;
+ USHORT last_cluster;
+ BOOLEAN changes;
+ LONG i, j, k;
+ PEA_MAP_TBL table;
+ PEA_FILE_HEADER header;
+ LONG tmp;
+ BOOLEAN empty_ea_file;
+ USHORT clus;
+
+
+ // Compute the number of clusters necessary for the header portion of
+ // the EA file.
+
+ length = sizeof(EA_FILE_HEADER) +
+ BaseTableSize*sizeof(USHORT) +
+ EaInfos[NumEas - 1].OwnHandle*sizeof(USHORT);
+
+ cluster_size = _drive->QuerySectorSize()*QuerySectorsPerCluster();
+
+ if (length%cluster_size) {
+ length = length/cluster_size + 1;
+ } else {
+ length = length/cluster_size;
+ }
+
+
+ // Make sure that the header contains enough clusters to accomodate
+ // the size of the offset table.
+
+ last_cluster = EaInfos[0].PreceedingCn;
+
+ actual_length = _fat->QueryLengthOfChain(*StartingCluster, last_cluster);
+
+ if (length > actual_length) {
+
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_NEED_MORE_HEADER_SPACE);
+ Message->Display("");
+
+ new_chain = _fat->AllocChain((USHORT) (length - actual_length),
+ &last_cluster);
+ if (!new_chain) {
+ Message->Set(MSG_CHK_INSUFFICIENT_DISK_SPACE);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (IsCompressed() && !AllocSectorsForChain(new_chain)) {
+ _fat->FreeChain(new_chain);
+ Message->Set(MSG_CHK_INSUFFICIENT_DISK_SPACE);
+ Message->Display("");
+ return FALSE;
+ }
+
+ for (clus = new_chain;
+ !_fat->IsEndOfChain(clus);
+ clus = _fat->QueryEntry(clus)) {
+
+ FatBitMap->SetBit(clus);
+ }
+ FatBitMap->SetBit(clus);
+
+ _fat->InsertChain(new_chain, last_cluster, EaInfos[0].PreceedingCn);
+
+ EaInfos[0].PreceedingCn = last_cluster;
+
+ } else if (length < actual_length) {
+
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_UNUSED_EA_PORTION);
+ Message->Display("");
+
+ last_cluster = _fat->QueryNthCluster(*StartingCluster,
+ (USHORT) length - 1);
+
+ clus = _fat->RemoveChain(last_cluster, EaInfos[0].PreceedingCn);
+
+ EaInfos[0].PreceedingCn = last_cluster;
+
+ for (;
+ !_fat->IsEndOfChain(clus);
+ clus = _fat->QueryEntry(clus)) {
+
+ FatBitMap->ResetBit(clus);
+ }
+ FatBitMap->ResetBit(clus);
+
+ }
+
+
+ // Verify the cluster chain containing the header.
+
+ changes = FALSE;
+ if (FixLevel != CheckOnly &&
+ !RecoverChain(StartingCluster, &changes, last_cluster, TRUE)) {
+
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_INSUFFICIENT_DISK_SPACE);
+ Message->Display("");
+
+ return FALSE;
+ }
+
+ if (changes) {
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_RELOCATED_EA_HEADER);
+ Message->Display("");
+ }
+
+
+ // Compute the tables.
+
+ if (!EaHeader->Initialize(EaHeaderMem, _drive, this, _fat,
+ *StartingCluster, (USHORT) length) ||
+ !(table = EaHeader->GetMapTable()) ||
+ !(header = EaHeader->GetEaFileHeader())) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!EaHeader->Read()) {
+ if (FixLevel == CheckOnly) {
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_RELOCATED_EA_HEADER);
+ Message->Display("");
+ } else {
+ return FALSE;
+ }
+ }
+
+
+ // Set the log in the header to zero.
+
+ header->Signature = HeaderSignature;
+ header->FormatType = 0;
+ header->LogType = 0;
+ header->Cluster1 = 0;
+ header->NewCValue1 = 0;
+ header->Cluster2 = 0;
+ header->NewCValue2 = 0;
+ header->Cluster3 = 0;
+ header->NewCValue3 = 0;
+ header->Handle = 0;
+ header->NewHOffset = 0;
+
+
+ // Reconcile the tables with the EaInfo information.
+
+ changes = FALSE;
+
+ for (i = 0; i < BaseTableSize; i++) {
+ table->BaseTab[i] = 0;
+ }
+
+ j = 0;
+ empty_ea_file = TRUE;
+ for (i = 0; i < (LONG) NumEas; i++) {
+
+ if (EaInfos[i].UsedCount != 1) {
+ continue;
+ }
+
+ empty_ea_file = FALSE;
+
+ for (; j < (LONG) EaInfos[i].OwnHandle; j++) {
+ if (table->OffTab[j] != InvalidHandle) {
+ table->OffTab[j] = InvalidHandle;
+ changes = TRUE;
+ }
+ }
+
+ length = _fat->QueryLengthOfChain(*StartingCluster,
+ EaInfos[i].PreceedingCn);
+
+ for (k = j>>7; k >= 0 && !table->BaseTab[k]; k--) {
+ table->BaseTab[k] = (USHORT) length;
+ }
+
+ tmp = length - table->BaseTab[j>>7];
+
+ if ((LONG)table->OffTab[j] != tmp) {
+ table->OffTab[j] = (USHORT) tmp;
+ changes = TRUE;
+ }
+
+ j++;
+ }
+
+ if (empty_ea_file) {
+
+ for (clus = *StartingCluster;
+ !_fat->IsEndOfChain(clus);
+ clus = _fat->QueryEntry(clus)) {
+
+ FatBitMap->ResetBit(clus);
+
+ }
+ FatBitMap->ResetBit(clus);
+
+ *StartingCluster = 0;
+
+ return TRUE;
+ }
+
+ tmp = _fat->QueryLengthOfChain(*StartingCluster);
+ for (k = ((j - 1)>>7) + 1; k < BaseTableSize; k++) {
+ table->BaseTab[k] = (USHORT) tmp;
+ }
+
+ for (; j < (LONG) EaHeader->QueryOffTabSize(); j++) {
+ if (table->OffTab[j] != InvalidHandle) {
+ table->OffTab[j] = InvalidHandle;
+ changes = TRUE;
+ }
+ }
+
+ if (changes) {
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_ERROR_IN_EA_HEADER);
+ Message->Display("");
+ }
+
+ return TRUE;
+}
+
+
+VOID
+FreeSpaceInBitmap(
+ IN USHORT StartingCluster,
+ IN PCFAT Fat,
+ IN OUT PBITVECTOR FatBitMap
+ )
+{
+ if (!StartingCluster) {
+ return;
+ }
+
+ while (!Fat->IsEndOfChain(StartingCluster)) {
+ FatBitMap->ResetBit(StartingCluster);
+ StartingCluster = Fat->QueryEntry(StartingCluster);
+ }
+ FatBitMap->ResetBit(StartingCluster);
+}
+
+
+ULONG
+ComputeFileNameHashValue(
+ IN PVOID FileName
+ )
+{
+ ULONG i;
+ ULONG h;
+ PUCHAR p;
+
+ p = (PUCHAR) FileName;
+ h = 0;
+ for (i = 0; i < 11; i++) {
+ h += p[i];
+ }
+
+ return h;
+}
+
+
+BOOLEAN
+FAT_SA::WalkDirectoryTree(
+ IN OUT PEA_INFO EaInfos,
+ IN USHORT NumEas,
+ IN OUT PBITVECTOR FatBitMap,
+ OUT PFATCHK_REPORT Report,
+ IN FIX_LEVEL FixLevel,
+ IN BOOLEAN RecoverAlloc,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ IN OUT PBOOLEAN NeedErrorsMessage
+ )
+/*++
+
+Routine Description:
+
+ This routine walks all of the files on the volume by traversing
+ the directory tree. In doing so it validates all of the
+ directory entries on the disk. It also verifies the proper
+ chaining of all file cluster chains. This routine also validates
+ the integrity of the EA handles for all of the directory entries
+ on the disk.
+
+ The FatBitMap is used to find and eliminate cross-links in the file
+ system.
+
+Arguments:
+
+ EaInfos - Supplies the EA information.
+ NumEas - Supplies the number of EA sets.
+ FatBitMap - Supplies a bit map marking all of the clusters
+ currently in use.
+ Report - Returns a FAT CHKDSK report on the files of the disk.
+ FixLevel - Supplies the CHKDSK fix level.
+ Message - Supplies an outlet for messages.
+ Verbose - Supplies whether or not to be verbose.
+ NeedErrorsMessage - Supplies whether or not errors have occurred
+ under check only conditions.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ INTSTACK dirs_to_visit;
+ INTSTACK paths_of_dirs_tv;
+ USHORT current_dir;
+ PFATDIR dir;
+ FILEDIR filedir;
+ FAT_DIRENT dirent;
+ ULONG i, j;
+ USHORT clus, next;
+ DSTRING file_path;
+ PWSTRING new_path;
+ PWSTRING current_path;
+ USHORT new_dir;
+ DSTRING filename;
+ DSTRING long_name;
+ HMEM hmem;
+ CLUSTER_CHAIN cluster;
+ USHORT new_chain;
+ ULONG cluster_size;
+ USHORT length;
+ DSTRING backslash;
+ DSTRING eafilename;
+ DSTRING tmp_string;
+ BOOLEAN cross_link_detected;
+ USHORT cross_link_prevclus;
+ HMEM tmphmem;
+ FILEDIR tmpfiledir;
+ FAT_DIRENT tmpdirent1;
+ FAT_DIRENT tmpdirent2;
+ BOOLEAN non_zero_dirents;
+ BITVECTOR file_name_hash_table;
+ CONST hash_table_size = 256*11;
+ ULONG hash_value;
+ BOOLEAN has_long_entry = FALSE;
+ UCHAR chksum;
+ BOOLEAN broke;
+ ULONG first_long_entry;
+ FAT_DIRENT dirent2;
+ ULONG allocated_clusters;
+ ULONG percent, new_percent;
+
+ DebugAssert(sizeof(PUCHAR) <= sizeof(INT));
+ DebugAssert(sizeof(USHORT) <= sizeof(INT));
+
+ memset(Report, 0, sizeof(FATCHK_REPORT));
+ Report->ExitStatus = CHKDSK_EXIT_SUCCESS;
+
+ if (!dirs_to_visit.Initialize() ||
+ !paths_of_dirs_tv.Initialize() ||
+ !file_name_hash_table.Initialize(hash_table_size)) {
+ return FALSE;
+ }
+
+ cluster_size = _drive->QuerySectorSize()*QuerySectorsPerCluster();
+ allocated_clusters = _fat->QueryAllocatedClusters();
+
+ if (0 == allocated_clusters) {
+ allocated_clusters++;
+ }
+
+ if (!backslash.Initialize("\\") ||
+ !eafilename.Initialize("EA DATA. SF")) {
+ return FALSE;
+ }
+
+ if (!(current_path = NEW DSTRING) ||
+ !current_path->Initialize(&backslash)) {
+ return FALSE;
+ }
+
+ if (!dirs_to_visit.Push(0) ||
+ !paths_of_dirs_tv.Push((INT) current_path)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ Message->Set(MSG_CHK_CHECKING_FILES);
+ Message->Display("");
+
+ percent = 0;
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", percent)) {
+ return FALSE;
+ }
+
+ for (; dirs_to_visit.QuerySize(); DELETE( current_path )) {
+
+ current_dir = (USHORT) dirs_to_visit.Look().GetLowPart();
+ current_path = (PWSTRING) paths_of_dirs_tv.Look().GetLowPart();
+ dirs_to_visit.Pop();
+ paths_of_dirs_tv.Pop();
+ has_long_entry = FALSE;
+
+ if (current_dir) {
+ if (!hmem.Initialize() ||
+ !filedir.Initialize(&hmem, _drive, this, _fat, current_dir)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!filedir.Read()) {
+ Message->Set(MSG_BAD_DIR_READ);
+ Message->Display("");
+ return FALSE;
+ }
+
+ dir = &filedir;
+ } else {
+ dir = _dir;
+ }
+
+ file_name_hash_table.ResetAll();
+
+ for (i = (current_dir ? 2 : 0); ; i++) {
+
+ if (!dirent.Initialize(dir->GetDirEntry(i)) ||
+ dirent.IsEndOfDirectory()) {
+
+ if (has_long_entry) {
+ //
+ // There was an orphaned lfn at the end of the
+ // directory. Erase it now.
+ //
+
+ Report->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_BAD_LONG_NAME);
+ Message->Display( "%W", current_path );
+
+ EraseAssociatedLongName(dir, first_long_entry, i);
+
+ has_long_entry = FALSE;
+ }
+
+ // This code must make sure that all other directory
+ // entries are end of directory entries.
+
+ non_zero_dirents = FALSE;
+
+ for (; dirent.Initialize(dir->GetDirEntry(i)); i++) {
+
+ if (!dirent.IsEndOfDirectory()) {
+ non_zero_dirents = TRUE;
+ dirent.SetEndOfDirectory();
+ }
+ }
+
+ if (non_zero_dirents) {
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_TRAILING_DIRENTS);
+ Message->Display("%W", current_path);
+
+ Report->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ }
+
+ break;
+ }
+
+ if (dirent.IsErased()) {
+
+ if (has_long_entry) {
+
+ //
+ // The preceding lfn is orphaned. Remove it.
+ //
+
+ Report->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_BAD_LONG_NAME);
+ Message->Display( "%W", current_path );
+
+ EraseAssociatedLongName(dir, first_long_entry, i);
+
+ has_long_entry = FALSE;
+ }
+
+ continue;
+ }
+
+ if (dirent.IsLongEntry()) {
+
+ // skip long name entries; come back to them later
+
+ if (has_long_entry) {
+ // already amid long entry
+ continue;
+ }
+
+ // first long entry
+
+ has_long_entry = TRUE;
+ first_long_entry = i;
+ continue;
+ }
+
+ dirent.QueryName(&filename);
+
+ if (has_long_entry) {
+
+ DSTRING lfn;
+
+ //
+ // The current entry is short, and we've just finished
+ // skipping the associated long entry. Look back through
+ // the long entries, make sure they're okay.
+ //
+
+ broke = FALSE;
+
+ chksum = dirent.QueryChecksum();
+
+ for (j = i - 1; j >= first_long_entry; j--) {
+ dirent2.Initialize(dir->GetDirEntry(j));
+
+ if (!dirent2.IsLongNameEntry()) {
+ continue;
+ }
+
+ broke = (dirent2.QueryLongOrdinal() != i - j) ||
+ (dirent2.QueryChecksum() != chksum) ||
+ (dirent2.QueryStartingCluster() != 0);
+
+ broke = broke || !dirent2.IsWellTerminatedLongNameEntry();
+
+ if (broke || dirent2.IsLastLongEntry()) {
+ break;
+ }
+ }
+
+ broke = broke || (!dirent2.IsLastLongEntry());
+
+#if 0
+//MJB: We'll elide this code because Win95 isn't this strict and we
+// don't want to delete all their lfn's.
+
+ if (!broke && dir->QueryLongName(i, &lfn)) {
+
+ broke = !dirent.NameHasTilde() &&
+ (dirent.NameHasExtendedChars() ||
+ 0 != filename.Stricmp(&lfn)) &&
+ !IsString8Dot3(&lfn);
+ }
+#endif
+
+ if (broke) {
+
+ Report->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+
+ //
+ // Erase all the long name entries.
+ //
+
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_BAD_LONG_NAME);
+ Message->Display( "%W", current_path );
+
+ EraseAssociatedLongName(dir, first_long_entry, i);
+
+ has_long_entry = FALSE;
+
+ }
+
+ //
+ // Fall into code to check short name.
+ //
+ }
+
+ dirent.QueryName(&filename);
+
+ if (!file_path.Initialize(current_path)) {
+ return FALSE;
+ }
+
+ if (current_dir) {
+ if (!file_path.Strcat(&backslash)) {
+ return FALSE;
+ }
+ }
+
+ if (dir->QueryLongName(i, &long_name) &&
+ long_name.QueryChCount() != 0) {
+
+ if (!file_path.Strcat(&long_name)) {
+ return FALSE;
+ }
+
+ } else {
+
+ if (!file_path.Strcat(&filename)) {
+ return FALSE;
+ }
+ }
+
+ if (Verbose && !dirent.IsVolumeLabel()) {
+ Message->Set(MSG_CHK_FILENAME);
+ Message->Display("%W", &file_path);
+ }
+
+ if (!ValidateDirent(&dirent, &file_path, FixLevel, RecoverAlloc,
+ Message, NeedErrorsMessage, FatBitMap,
+ &cross_link_detected, &cross_link_prevclus,
+ &Report->ExitStatus)) {
+ return FALSE;
+ }
+
+ if (dirent.IsErased()) {
+
+ //
+ // ValidateDirent erased this entry, presumably because it's
+ // hosed. Remove corresponding long name, if any.
+ //
+
+ if (has_long_entry) {
+ EraseAssociatedLongName(dir, first_long_entry, i);
+ has_long_entry = FALSE;
+ }
+ continue;
+ }
+
+ //
+ // Analize for cross-links.
+ //
+
+ if (cross_link_detected) { // CROSSLINK !!
+
+ Report->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+
+ // Identify cross linked cluster.
+
+ clus = cross_link_prevclus;
+
+ next = cross_link_prevclus ?
+ _fat->QueryEntry(cross_link_prevclus) :
+ dirent.QueryStartingCluster();
+
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CROSS_LINK);
+ Message->Display("%W%d", &file_path, next);
+
+ if (dirent.IsDirectory()) {
+
+ Message->Set(MSG_CHK_DIR_TRUNC);
+ Message->Display("");
+
+ if (clus) {
+ _fat->SetEndOfChain(clus);
+ } else {
+ dirent.SetErased();
+ if (has_long_entry) {
+ EraseAssociatedLongName(dir, first_long_entry, i);
+ has_long_entry = FALSE;
+ }
+ continue;
+ }
+
+ } else {
+
+ if (!CopyClusters(next, &new_chain, FatBitMap,
+ FixLevel, Message)) {
+ return FALSE;
+ }
+
+ if (new_chain) {
+ Message->Set(MSG_CHK_CROSS_LINK_COPY);
+ Message->Display("");
+
+ if (clus) {
+ _fat->SetEntry(clus, new_chain);
+ } else {
+ dirent.SetStartingCluster(new_chain);
+ }
+
+ } else {
+
+ Message->Set(MSG_CHK_CROSS_LINK_TRUNC);
+ Message->Display("");
+
+ if (clus) {
+
+ _fat->SetEndOfChain(clus);
+ dirent.SetFileSize(
+ cluster_size*_fat->QueryLengthOfChain(
+ dirent.QueryStartingCluster()));
+
+ } else {
+ dirent.SetErased();
+
+ if (has_long_entry) {
+ EraseAssociatedLongName(dir, first_long_entry,
+ i);
+ has_long_entry = FALSE;
+ }
+ }
+ }
+ }
+ }
+
+
+ if (!ValidateEaHandle(&dirent, current_dir, i, EaInfos, NumEas,
+ &file_path, FixLevel, Message,
+ NeedErrorsMessage)) {
+ return FALSE;
+ }
+
+
+ if (!dirent.IsVolumeLabel()) {
+
+ // Make sure that the filename is unique.
+
+ hash_value = ComputeFileNameHashValue(dir->GetDirEntry(i))%
+ hash_table_size;
+
+ if (file_name_hash_table.IsBitSet(hash_value)) {
+
+ // search the directory since the hash values match.
+
+ for (j = 0; j < i; j++) {
+
+ FAT_DIRENT fd;
+
+ if (!fd.Initialize(dir->GetDirEntry(j)) ||
+ fd.IsVolumeLabel()) {
+ continue;
+ }
+
+ if (!memcmp(dir->GetDirEntry(j), dir->GetDirEntry(i), 11)) {
+
+ break;
+ }
+ }
+
+ if (j < i) {
+
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_REPEATED_ENTRY);
+ Message->Display("%W%W", &filename, current_path);
+
+ Report->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+
+ FreeSpaceInBitmap(dirent.QueryStartingCluster(), _fat,
+ FatBitMap);
+
+ dirent.SetErased();
+
+ if (has_long_entry) {
+ EraseAssociatedLongName(dir, first_long_entry, i);
+ has_long_entry = FALSE;
+ }
+ continue;
+ }
+
+ } else {
+ file_name_hash_table.SetBit(hash_value);
+ }
+ }
+
+
+ //
+ // Do special stuff if the current entry is a directory.
+ //
+
+ if (dirent.IsDirectory()) {
+
+ new_dir = dirent.QueryStartingCluster();
+
+ //
+ // Validate the integrity of the directory.
+ //
+
+ // Read the directory.
+
+ if (!tmphmem.Initialize() ||
+ !tmpfiledir.Initialize(&tmphmem, _drive, this, _fat,
+ new_dir) ||
+ !tmpfiledir.Read()) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+
+ return FALSE;
+ }
+
+ // Check the . and .. entries.
+
+ if (!tmpdirent1.Initialize(tmpfiledir.GetDirEntry(0)) ||
+ !tmpdirent2.Initialize(tmpfiledir.GetDirEntry(1))) {
+ DebugAbort("GetDirEntry of 0 and 1 failed!");
+ return FALSE;
+ }
+
+ if (!tmpdirent1.IsDot() ||
+ !tmpdirent2.IsDotDot() ||
+ !tmpdirent1.IsDirectory() ||
+ !tmpdirent2.IsDirectory()) {
+
+ Report->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_ERROR_IN_DIR);
+ Message->Display("%W", &file_path);
+ Message->Set(MSG_CHK_CONVERT_DIR_TO_FILE, NORMAL_MESSAGE, TEXT_MESSAGE);
+ Message->Display();
+
+ if (Message->IsYesResponse(TRUE)) {
+ dirent.ResetDirectory();
+ dirent.SetFileSize(
+ _fat->QueryLengthOfChain(new_dir)*
+ cluster_size);
+
+ } else {
+
+ FreeSpaceInBitmap(dirent.QueryStartingCluster(),
+ _fat, FatBitMap);
+
+ dirent.SetErased();
+
+ if (has_long_entry) {
+ EraseAssociatedLongName(dir, first_long_entry, i);
+ has_long_entry = FALSE;
+ }
+ continue;
+ }
+
+ } else { // Directory looks valid.
+
+ if (tmpdirent1.QueryStartingCluster() != new_dir ||
+ tmpdirent2.QueryStartingCluster() != current_dir ||
+ tmpdirent1.QueryFileSize() ||
+ tmpdirent2.QueryFileSize()) {
+
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_ERRORS_IN_DIR_CORR);
+ Message->Display("%W", &file_path);
+
+ Report->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+
+ tmpdirent1.SetStartingCluster(new_dir);
+ tmpdirent2.SetStartingCluster(current_dir);
+ tmpdirent1.SetFileSize(0);
+ tmpdirent2.SetFileSize(0);
+
+ if (FixLevel != CheckOnly && !tmpfiledir.Write()) {
+ DebugAbort("Could not write tmp file dir.");
+ return FALSE;
+ }
+ }
+
+ // Add the directory to the list of directories
+ // to validate.
+
+ if (!(new_path = NEW DSTRING) ||
+ !new_path->Initialize(&file_path)) {
+ return FALSE;
+ }
+
+ if (!dirs_to_visit.Push((ULONG) new_dir) ||
+ !paths_of_dirs_tv.Push((ULONG) new_path)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ }
+ }
+
+
+ //
+ // Generate report stats.
+ //
+
+ if (current_dir || !(filename == eafilename)) {
+ length = _fat->QueryLengthOfChain(dirent.QueryStartingCluster());
+ if (dirent.IsHidden()) {
+ Report->HiddenEntriesCount++;
+ Report->HiddenClusters += length;
+ } else if (dirent.IsDirectory()) {
+ Report->DirEntriesCount++;
+ Report->DirClusters += length;
+ } else if (!dirent.IsVolumeLabel()) {
+ Report->FileEntriesCount++;
+ Report->FileClusters += length;
+ }
+ }
+
+ new_percent = (Report->HiddenClusters + Report->DirClusters +
+ Report->FileClusters) * 100 / allocated_clusters;
+
+ if (new_percent > percent) {
+ percent = new_percent;
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", percent)) {
+ return FALSE;
+ }
+ }
+
+ has_long_entry = FALSE;
+ }
+
+ if (current_dir) {
+ if (FixLevel != CheckOnly && !filedir.Write()) {
+ return FALSE;
+ }
+ }
+ }
+
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", 100)) {
+ return FALSE;
+ }
+ Message->Set(MSG_CHK_DONE_CHECKING);
+ Message->Display("");
+
+ return TRUE;
+}
+
+
+BOOLEAN
+FAT_SA::ValidateDirent(
+ IN OUT PFAT_DIRENT Dirent,
+ IN PCWSTRING FilePath,
+ IN FIX_LEVEL FixLevel,
+ IN BOOLEAN RecoverAlloc,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN NeedErrorsMessage,
+ IN OUT PBITVECTOR FatBitMap,
+ OUT PBOOLEAN CrossLinkDetected,
+ OUT PUSHORT CrossLinkPreviousCluster,
+ OUT PULONG ExitStatus
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies that all components of a directory entry are
+ correct. If the time stamps are invalid then they will be corrected
+ to the current time. If the filename is invalid then the directory
+ entry will be marked as deleted. If the cluster number is out of
+ disk range then the directory entry will be marked as deleted.
+ Otherwise, the cluster chain will be validated and the length of
+ the cluster chain will be compared against the file size. If there
+ is a difference then the file size will be corrected.
+
+ If there are any strange errors then FALSE will be returned.
+
+Arguments:
+
+ Dirent - Supplies the directory entry to validate.
+ FilePath - Supplies the full path name for the directory
+ entry.
+ RecoverAlloc - Supplies whether or not to recover all
+ allocated space on the volume.
+ Message - Supplies an outlet for messages.
+ NeedErrorsMessage - Supplies whether or not an error has
+ occurred during check only mode.
+ FatBitMap - Supplies a bitmap marking in use all known
+ clusters.
+ CrossLinkDetected - Returns TRUE if the file is cross-linked with
+ another.
+ CrossLinkPreviousCluster - Returns the cluster previous to the
+ cross-linked one.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ USHORT start_clus;
+ BOOLEAN changes;
+ USHORT length;
+ ULONG file_size;
+ ULONG cluster_size;
+ BOOLEAN recover_status;
+
+ DebugAssert(CrossLinkDetected);
+ DebugAssert(CrossLinkPreviousCluster);
+
+ *CrossLinkDetected = FALSE;
+
+ if (Dirent->IsErased()) {
+ return TRUE;
+ }
+
+ cluster_size = _drive->QuerySectorSize()*QuerySectorsPerCluster();
+
+// Don't validate names or time stamps anymore.
+#if 0
+
+ if (!Dirent->IsValidName()) {
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_INVALID_NAME);
+ Message->Display("%W", FilePath);
+ Dirent->SetErased();
+ return TRUE;
+ }
+
+ if (!Dirent->IsValidTimeStamp()) {
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_INVALID_TIME_STAMP);
+ Message->Display("%W", FilePath);
+ if (!Dirent->SetTimeStamp()) {
+ return FALSE;
+ }
+ }
+
+#endif
+
+ if (Dirent->IsDirectory() && Dirent->QueryFileSize()) {
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_DIR_HAS_FILESIZE);
+ Message->Display("%W", FilePath);
+ Dirent->SetFileSize( 0 );
+ *ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ }
+
+ if ((start_clus = Dirent->QueryStartingCluster()) != 0 ) {
+ if (!_fat->IsInRange(start_clus) || _fat->IsClusterFree(start_clus)) {
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_BAD_FIRST_UNIT);
+ Message->Display("%W", FilePath);
+ Dirent->SetErased();
+ *ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ return TRUE;
+ }
+
+ if (Dirent->IsDirectory() || RecoverAlloc) {
+ _fat->ScrubChain(start_clus, &changes);
+
+ if (changes) {
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_BAD_LINK);
+ Message->Display("%W", FilePath);
+ *ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ }
+
+ // Validate the readability of the directory or file
+ // in the case that 'RecoverAlloc' is TRUE.
+
+ if (Dirent->IsDirectory()) {
+ if (!(recover_status = RecoverChain(&start_clus, &changes))) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ } else if (FixLevel != CheckOnly) {
+ recover_status = RecoverChain(&start_clus, &changes, 0, TRUE);
+ } else {
+ recover_status = TRUE;
+ changes = FALSE;
+ }
+
+ if (changes) {
+ *ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ dofmsg(Message, NeedErrorsMessage);
+ if (Dirent->IsDirectory()) {
+ if (!start_clus) {
+ Message->Set(MSG_CHK_BAD_DIR);
+ Message->Display("%W", FilePath);
+ Dirent->SetErased();
+ return TRUE;
+ } else {
+ Message->Set(MSG_CHK_BAD_CLUSTERS_IN_DIR);
+ Message->Display("%W", FilePath);
+ Dirent->SetStartingCluster(start_clus);
+ }
+ } else {
+ // In the file case, since we're replacing bad clusters
+ // with new ones, start_clus cannot be zero.
+ DebugAssert(start_clus);
+
+ if (recover_status) {
+ Message->Set(MSG_CHK_BAD_CLUSTERS_IN_FILE_SUCCESS);
+ Message->Display("%W", FilePath);
+ } else {
+ Message->Set(MSG_CHK_BAD_CLUSTERS_IN_FILE_FAILURE);
+ Message->Display();
+ }
+ Dirent->SetStartingCluster(start_clus);
+ }
+ }
+ }
+
+ _fat->ScrubChain(start_clus, FatBitMap, &changes,
+ CrossLinkDetected, CrossLinkPreviousCluster);
+
+ if (changes) {
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_BAD_LINK);
+ Message->Display("%W", FilePath);
+ *ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ }
+
+ length = _fat->QueryLengthOfChain(start_clus);
+
+ if (( file_size = Dirent->QueryFileSize()) != 0 ) {
+ if (file_size <= ((USHORT)(length - 1))*cluster_size ||
+ file_size > length*cluster_size) {
+
+ // Note that no message is displayed if the
+ // file size is less than the allocation--it
+ // is just silently corrected.
+ //
+ if (file_size > length*cluster_size) {
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_BAD_FILE_SIZE);
+ Message->Display("%W", FilePath);
+ }
+ Dirent->SetFileSize(length*cluster_size);
+ *ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ }
+ } else {
+ if (!Dirent->IsDirectory()) {
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_BAD_FILE_SIZE);
+ Message->Display("%W", FilePath);
+ Dirent->SetFileSize(length*cluster_size);
+ *ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ }
+ }
+ } else {
+ if (Dirent->IsDirectory() && !Dirent->IsDotDot()) {
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_BAD_LINK);
+ Message->Display("%W", FilePath);
+ Dirent->SetErased();
+ *ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ return TRUE;
+ }
+
+ if (Dirent->QueryFileSize()) {
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_BAD_FILE_SIZE);
+ Message->Display("%W", FilePath);
+ Dirent->SetFileSize(0);
+ *ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+FAT_SA::ValidateEaHandle(
+ IN OUT PFAT_DIRENT Dirent,
+ IN USHORT DirClusterNumber,
+ IN ULONG DirEntryNumber,
+ IN OUT PEA_INFO EaInfos,
+ IN USHORT NumEas,
+ IN PCWSTRING FilePath,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN NeedErrorsMessage
+ )
+/*++
+
+Routine Description:
+
+ This routine validates the EA handle in the directory entry 'Dirent'.
+ It ensures that it references an actual EA set. It also ensures
+ that it is the only directory entry which references the EA set.
+
+ If several entries try to reference the same EA set then ties will
+ be broken based on the 'OwnerFileName' entry in the EA set.
+
+Arguments:
+
+ Dirent - Supplies the directory entry to validate.
+ DirClusterNumber - Supplies the cluster number of the directory
+ containing the dirent.
+ DirEntryNumber - Supplies the position of the directory entry in
+ the directory.
+ EaInfos - Supplies the list of current EA information.
+ NumEas - Supplies the number of EA sets.
+ FilePath - Supplies the full path name for the directory entry.
+ FixLevel - Supplies the fix up level.
+ Message - Supplies an outlet for messages.
+ NeedErrorsMessage - Supplies whether or not an error has occurred
+ during check only mode.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ USHORT i;
+ USHORT handle;
+ DSTRING wfilename;
+ STR filename[14];
+ BOOLEAN remove_other_handle;
+ HMEM hmem;
+ FILEDIR filedir;
+ FAT_DIRENT other_dirent;
+
+
+ if (!(handle = Dirent->QueryEaHandle())) {
+ return TRUE;
+ }
+
+ if (!EaInfos) {
+ NumEas = 0;
+ }
+
+ for (i = 0; i < NumEas; i++) {
+ if (handle == EaInfos[i].OwnHandle) {
+ break;
+ }
+ }
+
+ if (i == NumEas) {
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_UNRECOG_EA_HANDLE);
+ Message->Display("%W", FilePath);
+ Dirent->SetEaHandle(0);
+ return TRUE;
+ }
+
+ if (EaInfos[i].UsedCount >= 2) {
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_SHARED_EA);
+ Message->Display("%W", FilePath);
+ Dirent->SetEaHandle(0);
+ return TRUE;
+ }
+
+ Dirent->QueryName(&wfilename);
+ if (!wfilename.QuerySTR( 0, TO_END, filename, 14)) {
+ return FALSE;
+ }
+
+ if (EaInfos[i].UsedCount == 0) {
+ memcpy(EaInfos[i].UserFileName, filename, 14);
+ EaInfos[i].UserFileEntryCn = DirClusterNumber;
+ EaInfos[i].UserFileEntryNumber = DirEntryNumber;
+ EaInfos[i].UsedCount = 1;
+ return TRUE;
+ }
+
+
+ // UsedCount == 1.
+
+ remove_other_handle = FALSE;
+
+ if (!strcmp(filename, EaInfos[i].OwnerFileName)) {
+
+ remove_other_handle = TRUE;
+
+ if (!strcmp(EaInfos[i].UserFileName,
+ EaInfos[i].OwnerFileName)) {
+ EaInfos[i].UsedCount = 2;
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_SHARED_EA);
+ Message->Display("%W", FilePath);
+ Dirent->SetEaHandle(0);
+ }
+
+ } else {
+
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_SHARED_EA);
+ Message->Display("%W", FilePath);
+ Dirent->SetEaHandle(0);
+
+ if (strcmp(EaInfos[i].UserFileName,
+ EaInfos[i].OwnerFileName)) {
+ EaInfos[i].UsedCount = 2;
+ remove_other_handle = TRUE;
+ }
+ }
+
+
+ if (remove_other_handle) {
+
+ if (EaInfos[i].UserFileEntryCn) {
+ if (!hmem.Initialize() ||
+ !filedir.Initialize(&hmem, _drive, this, _fat,
+ EaInfos[i].UserFileEntryCn) ||
+ !filedir.Read() ||
+ !other_dirent.Initialize(filedir.GetDirEntry(
+ EaInfos[i].UserFileEntryNumber))) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ } else {
+ if (!other_dirent.Initialize(_dir->GetDirEntry(
+ EaInfos[i].UserFileEntryNumber))) {
+ return FALSE;
+ }
+ }
+
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_SHARED_EA);
+ Message->Display("%W", FilePath);
+ other_dirent.SetEaHandle(0);
+
+ if (EaInfos[i].UserFileEntryCn && FixLevel != CheckOnly &&
+ !filedir.Write()) {
+ return FALSE;
+ }
+
+ strcpy(EaInfos[i].UserFileName, filename);
+ EaInfos[i].UserFileEntryCn = DirClusterNumber;
+ EaInfos[i].UserFileEntryNumber = DirEntryNumber;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+FAT_SA::CopyClusters(
+ IN USHORT SourceChain,
+ OUT PUSHORT DestChain,
+ IN OUT PBITVECTOR FatBitMap,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine copies the cluster chain beginning at 'SourceChain'
+ to a free portion of the disk. The beginning of the copied chain
+ will be returned in 'DestChain'. If there isn't enough free space
+ on the disk to copy the chain then 'DestChain' will return 0.
+
+Arguments:
+
+ SourceChain - Supplies the chain to copy.
+ DestChain - Returns the copy of the chain.
+ FatBitMap - Supplies the orphan and cross-link bitmap.
+ FixLevel - Supplies the CHKDSK fix level.
+ Message - Supplies an outlet for messages
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ HMEM hmem;
+ CLUSTER_CHAIN cluster;
+ USHORT src, dst;
+ BOOLEAN changes;
+ USHORT clus;
+
+ if (!hmem.Initialize()) {
+ return FALSE;
+ }
+
+ if (!(*DestChain = _fat->AllocChain(
+ _fat->QueryLengthOfChain(SourceChain)))) {
+ return TRUE;
+ }
+
+ changes = FALSE;
+ if (FixLevel != CheckOnly && !RecoverChain(DestChain, &changes, 0, TRUE)) {
+ if (*DestChain) {
+ _fat->FreeChain(*DestChain);
+ }
+ *DestChain = 0;
+ return TRUE;
+ }
+
+ if (IsCompressed() && !AllocSectorsForChain(*DestChain)) {
+ _fat->FreeChain(*DestChain);
+ *DestChain = 0;
+ return TRUE;
+ }
+
+ // Mark the new chain as "used" in the FAT bitmap.
+ for (clus = *DestChain;
+ !_fat->IsEndOfChain(clus);
+ clus = _fat->QueryEntry(clus)) {
+
+ FatBitMap->SetBit(clus);
+ }
+ FatBitMap->SetBit(clus);
+
+ src = SourceChain;
+ dst = *DestChain;
+ for (;;) {
+ if (!cluster.Initialize(&hmem, _drive, this, _fat, src, 1)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ cluster.Read();
+
+ if (!cluster.Initialize(&hmem, _drive, this, _fat, dst, 1)) {
+ return FALSE;
+ }
+
+ if (FixLevel != CheckOnly && !cluster.Write()) {
+ return FALSE;
+ }
+
+ if (_fat->IsEndOfChain(src)) {
+ break;
+ }
+
+ src = _fat->QueryEntry(src);
+ dst = _fat->QueryEntry(dst);
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+FAT_SA::PurgeEaFile(
+ IN PCEA_INFO EaInfos,
+ IN USHORT NumEas,
+ IN OUT PBITVECTOR FatBitMap,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN NeedErrorsMessage
+ )
+/*++
+
+Routine Description:
+
+ This routine is executed after the directory tree is walked. Stored,
+ in the EaInfos array, is information concerning which EAs get used
+ and by how many files.
+
+ If an EA set is not used, or is used by more than one file, then this
+ routine will eliminate it from the EA file.
+
+Arguments:
+
+ EaInfos - Supplies an array of EA information.
+ NumEas - Supplies the number of EA sets.
+ FatBitMap - Supplies the FAT cross-link detection bitmap.
+ FixLevel - Supplies the CHKDSK fix level.
+ Message - Supplies an outlet for messages.
+ NeedErrorsMessage - Supplies whether or not an error has occured
+ in check only mode.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ LONG i;
+ EA_SET easet;
+ HMEM hmem;
+ PEA_HDR eahdr;
+ USHORT clus;
+
+ if (!hmem.Initialize()) {
+ return FALSE;
+ }
+
+ for (i = NumEas - 1; i >= 0; i--) {
+
+ if (EaInfos[i].UsedCount != 1) {
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_UNUSED_EA_SET);
+ Message->Display("%d", EaInfos[i].OwnHandle);
+
+ // Mark the FAT entries of the removed chain as "not claimed",
+ // for the purposes of orphan recovery.
+
+ for (clus = _fat->QueryEntry(EaInfos[i].PreceedingCn);
+ clus != EaInfos[i].LastCn;
+ clus = _fat->QueryEntry(clus)) {
+
+ FatBitMap->ResetBit(clus);
+
+ }
+ FatBitMap->ResetBit(clus);
+
+
+ // Remove the unused EA chain from the EA file.
+
+ _fat->RemoveChain(EaInfos[i].PreceedingCn,
+ EaInfos[i].LastCn);
+
+
+ } else if (strcmp(EaInfos[i].OwnerFileName,
+ EaInfos[i].UserFileName)) {
+
+ if (!easet.Initialize(&hmem, _drive, this, _fat,
+ _fat->QueryEntry(EaInfos[i].PreceedingCn),
+ 1) ||
+ !easet.Read() ||
+ !(eahdr = easet.GetEaSetHeader())) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_NEW_OWNER_NAME);
+ Message->Display("%d%s%s", EaInfos[i].OwnHandle,
+ eahdr->OwnerFileName, EaInfos[i].UserFileName);
+
+ memcpy(eahdr->OwnerFileName, EaInfos[i].UserFileName, 14);
+
+ if (FixLevel != CheckOnly && !easet.Write()) {
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+FAT_SA::RecoverOrphans(
+ IN OUT PBITVECTOR FatBitMap,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN NeedErrorsMessage
+ )
+/*++
+
+Routine Description:
+
+ This routine examines the file system for cluster chains which are
+ not claimed by any file. These 'orphans' will then be recovered in
+ a subdirectory of the root or removed from the system.
+
+Arguments:
+
+ FatBitMap - Supplies a bit map marking all currently used
+ clusters.
+ FixLevel - Supplies the CHKDSK fix level.
+ Message - Supplies an outlet for messages.
+ NeedErrorsMessage - Supplies whether or not an error has occured
+ in check only mode.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+#if defined( _AUTOCHECK_ )
+ // Due to memory constraints, the maximum number of orphans to
+ // recover is less for Autochk than for run-time Chkdsk.
+ //
+ CONST maximum_orphans = 1000;
+#else
+ CONST maximum_orphans = 10000;
+#endif
+
+ USHORT i;
+ USHORT clus;
+ BOOLEAN changes;
+ HMEM hmem;
+ FILEDIR found_dir;
+ STR found_name[14];
+ DSTRING wfound_name;
+ STR filename[14];
+ FAT_DIRENT dirent;
+ USHORT found_cluster;
+ USHORT orphan_count;
+ ULONG cluster_size;
+ USHORT found_length;
+ USHORT next;
+ PUCHAR orphan_track;
+ USHORT cluster_count;
+ USHORT num_orphans;
+ USHORT num_orphan_clusters;
+ DSTRING tmp_string;
+ BITVECTOR tmp_bitvector;
+ BOOLEAN tmp_bool;
+ USHORT tmp_ushort;
+
+ cluster_count = QueryClusterCount();
+
+ if (!(orphan_track = NEW UCHAR[cluster_count])) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ memset(orphan_track, 0, cluster_count);
+
+ if (!tmp_bitvector.Initialize(cluster_count)) {
+ return FALSE;
+ }
+
+ cluster_size = _drive->QuerySectorSize()*QuerySectorsPerCluster();
+
+ num_orphans = 0;
+ num_orphan_clusters = 0;
+ for (i = FirstDiskCluster; _fat->IsInRange(i); i++) {
+ if (!_fat->IsClusterFree(i) &&
+ !FatBitMap->IsBitSet(i) &&
+ !_fat->IsClusterBad(i) &&
+ !_fat->IsClusterReserved(i)) {
+
+ num_orphans++;
+
+ tmp_bitvector.ResetAll();
+
+ _fat->ScrubChain(i, &tmp_bitvector, &changes,
+ &tmp_bool, &tmp_ushort);
+
+ if (changes) {
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_BAD_LINKS_IN_ORPHANS);
+ Message->Display("%d", i);
+ }
+
+ num_orphan_clusters++;
+
+ clus = i;
+ while (!_fat->IsEndOfChain(clus)) {
+ next = _fat->QueryEntry(clus);
+
+ if (orphan_track[next] == 1) {
+ num_orphans--;
+ orphan_track[next] = 2;
+ break;
+ }
+
+ if (FatBitMap->IsBitSet(next)) { // CROSSLINK !!
+
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CHK_CROSS_LINKED_ORPHAN);
+ Message->Display("%d", clus);
+
+ _fat->SetEndOfChain(clus);
+
+ break;
+ }
+
+ num_orphan_clusters++;
+
+ FatBitMap->SetBit(next);
+ orphan_track[next] = 2;
+
+ clus = next;
+ }
+ FatBitMap->SetBit(i);
+ orphan_track[i] = 1;
+ }
+ }
+
+
+ // Now scan throught the secondary pointers in search of orphans.
+
+ changes = FALSE;
+ for (i = FirstDiskCluster; _fat->IsInRange(i); i++) {
+ if (orphan_track[i]) {
+ changes = TRUE;
+ break;
+ }
+ }
+
+ if (!changes) {
+ // No orphans to recover.
+ return TRUE;
+ }
+
+ dofmsg(Message, NeedErrorsMessage);
+ Message->Set(MSG_CONVERT_LOST_CHAINS, NORMAL_MESSAGE, TEXT_MESSAGE);
+ Message->Display("");
+
+ if (!Message->IsYesResponse(TRUE)) {
+
+ if (FixLevel != CheckOnly) {
+
+ for (i = FirstDiskCluster; _fat->IsInRange(i); i++) {
+ if (orphan_track[i] == 1) {
+ _fat->FreeChain(i);
+ }
+ }
+
+ }
+
+ Message->Set((FixLevel == CheckOnly) ?
+ MSG_BYTES_WOULD_BE_FREED :
+ MSG_BYTES_FREED);
+
+
+ Message->Display("%d", cluster_size*num_orphan_clusters);
+
+ return TRUE;
+ }
+
+
+ // Set up for orphan recovery.
+
+
+ // Establish "FOUND.XXX" directory.
+ for (i = 0; i < 1000; i++) {
+ sprintf(found_name, "FOUND.%03d", i);
+ if (!wfound_name.Initialize(found_name)) {
+ return FALSE;
+ }
+
+ if (!_dir->SearchForDirEntry(&wfound_name)) {
+ break;
+ }
+ }
+
+ if (i == 1000) {
+ Message->Set(MSG_WOULD_BE_RECOVERED_FILES);
+ Message->Display("%d%d", cluster_size*num_orphan_clusters,
+ num_orphans);
+ return TRUE;
+ }
+
+ found_length = (USHORT)((min(num_orphans,maximum_orphans)*BytesPerDirent - 1)/cluster_size + 1);
+
+ if (!(found_cluster = _fat->AllocChain(found_length)) &&
+ !(found_cluster = _fat->AllocChain(found_length = 1))) {
+ Message->Set(MSG_ORPHAN_DISK_SPACE);
+ Message->Display("");
+ Message->Set(MSG_WOULD_BE_RECOVERED_FILES);
+ Message->Display("%d%d", cluster_size*num_orphan_clusters,
+ num_orphans);
+ return TRUE;
+ }
+
+ // Check the chain.
+ changes = FALSE;
+ if (FixLevel != CheckOnly &&
+ !RecoverChain(&found_cluster, &changes, 0, TRUE)) {
+ Message->Set(MSG_ORPHAN_DISK_SPACE);
+ Message->Display("");
+ Message->Set(MSG_WOULD_BE_RECOVERED_FILES);
+ Message->Display("%d%d", cluster_size*num_orphan_clusters,
+ num_orphans);
+ return TRUE;
+ }
+
+ if (!hmem.Initialize() ||
+ !found_dir.Initialize(&hmem, _drive, this, _fat, found_cluster)) {
+ DebugAbort( "Initialization failed" );
+ return FALSE;
+ }
+
+ // Allocate space for the cluster chain in the sector heap (fat_db)
+
+ if (IsCompressed() && !AllocSectorsForChain(found_cluster)) {
+ _fat->FreeChain(found_cluster);
+ Message->Set(MSG_ORPHAN_DISK_SPACE);
+ Message->Display("");
+
+ return TRUE;
+ }
+
+ memset(hmem.GetBuf(), 0, (UINT) hmem.QuerySize());
+
+ if (!dirent.Initialize(_dir->GetFreeDirEntry())) {
+ Message->Set(MSG_NO_ROOM_IN_ROOT);
+ Message->Display("");
+ Message->Set(MSG_WOULD_BE_RECOVERED_FILES);
+ Message->Display("%d%d", cluster_size*num_orphan_clusters,
+ num_orphans);
+ return TRUE;
+ }
+
+ dirent.Clear();
+
+ if (!dirent.SetName(&wfound_name)) {
+ return FALSE;
+ }
+
+ dirent.SetDirectory();
+
+ if (!dirent.SetLastWriteTime() || !dirent.SetCreationTime() ||
+ !dirent.SetLastAccessTime()) {
+ return FALSE;
+ }
+
+ dirent.SetStartingCluster(found_cluster);
+
+ if (!dirent.Initialize(found_dir.GetDirEntry(0))) {
+ return FALSE;
+ }
+
+ dirent.Clear();
+
+ if (!tmp_string.Initialize(".")) {
+ return FALSE;
+ }
+
+ if (!dirent.SetName(&tmp_string)) {
+ return FALSE;
+ }
+
+ dirent.SetDirectory();
+
+ if (!dirent.SetLastWriteTime() || !dirent.SetCreationTime() ||
+ !dirent.SetLastAccessTime()) {
+ return FALSE;
+ }
+
+ dirent.SetStartingCluster(found_cluster);
+
+ if (!dirent.Initialize(found_dir.GetDirEntry(1))) {
+ return FALSE;
+ }
+
+ dirent.Clear();
+
+ if (!tmp_string.Initialize("..")) {
+ return FALSE;
+ }
+
+ if (!dirent.SetName(&tmp_string)) {
+ return FALSE;
+ }
+
+ dirent.SetDirectory();
+
+ if (!dirent.SetLastWriteTime() || !dirent.SetCreationTime() ||
+ !dirent.SetLastAccessTime()) {
+ return FALSE;
+ }
+
+ dirent.SetStartingCluster(0);
+
+
+ // OK, now let's recover those orphans.
+
+ orphan_count = 0;
+ for (i = FirstDiskCluster; _fat->IsInRange(i); i++) {
+ if (orphan_track[i] != 1) {
+ continue;
+ }
+ if (orphan_count == maximum_orphans) {
+ Message->Set(MSG_TOO_MANY_ORPHANS);
+ Message->Display("");
+ break;
+ }
+
+ if (!dirent.Initialize(found_dir.GetFreeDirEntry())) {
+
+ if (_fat->ReAllocChain(found_cluster, ++found_length)
+ != found_length) {
+ Message->Set(MSG_ORPHAN_DISK_SPACE);
+ Message->Display("");
+ Message->Set(MSG_WOULD_BE_RECOVERED_FILES);
+ Message->Display("%d%d", cluster_size*num_orphan_clusters,
+ num_orphans);
+ break;
+ }
+
+//XXX.mjb: FATDB: need to get sectors for found_cluster + realloc.
+
+ changes = FALSE;
+ if (FixLevel != CheckOnly &&
+ !RecoverChain(&found_cluster, &changes, 0, TRUE)) {
+
+ Message->Set(MSG_ORPHAN_DISK_SPACE);
+ Message->Display("");
+ Message->Set(MSG_WOULD_BE_RECOVERED_FILES);
+ Message->Display("%d%d", cluster_size*num_orphan_clusters,
+ num_orphans);
+ return TRUE;
+ }
+
+ if (FixLevel != CheckOnly && !found_dir.Write()) {
+ return FALSE;
+ }
+
+ if (!hmem.Initialize() ||
+ !found_dir.Initialize(&hmem, _drive, this, _fat,
+ found_cluster) ||
+ !found_dir.Read()) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display("");
+ Message->Set(MSG_WOULD_BE_RECOVERED_FILES);
+ Message->Display("%d%d", cluster_size*num_orphan_clusters,
+ num_orphans);
+ return TRUE;
+ }
+
+ if (!dirent.Initialize(found_dir.GetDirEntry(2 + orphan_count))) {
+ return FALSE;
+ }
+
+ dirent.SetEndOfDirectory();
+
+ if (!dirent.Initialize(found_dir.GetFreeDirEntry())) {
+ return FALSE;
+ }
+ }
+
+ sprintf(filename, "FILE%04d.CHK", orphan_count);
+
+ if (!tmp_string.Initialize(filename)) {
+ return FALSE;
+ }
+
+ dirent.Clear();
+
+ if (!dirent.SetName(&tmp_string)) {
+ return FALSE;
+ }
+
+ if (!dirent.SetLastWriteTime() || !dirent.SetCreationTime() ||
+ !dirent.SetLastAccessTime()) {
+ return FALSE;
+ }
+
+ dirent.SetStartingCluster(i);
+ dirent.SetFileSize(cluster_size*_fat->QueryLengthOfChain(i));
+
+ orphan_count++;
+ }
+
+ // Set all dirents past the orphan count to end of directory.
+
+ for (i = 2 + orphan_count; dirent.Initialize(found_dir.GetDirEntry(i)); i++) {
+ dirent.SetEndOfDirectory();
+ }
+
+ if (FixLevel != CheckOnly && !found_dir.Write()) {
+ return FALSE;
+ }
+
+ Message->Set((FixLevel == CheckOnly) ?
+ MSG_WOULD_BE_RECOVERED_FILES :
+ MSG_RECOVERED_FILES);
+
+ Message->Display("%d%d", cluster_size*num_orphan_clusters,
+ num_orphans);
+
+ return TRUE;
+}
+
+
+BOOLEAN
+FAT_SA::AllocSectorsForChain(
+ ULONG ChainHead
+ )
+/*++
+
+Routine Description:
+
+ When VerifyAndFix needs to allocate a cluster chain in order
+ to create a new directory (such as \FOUND.000), it also needs to
+ allocate space in the sector heap for data blocks for those
+ clusters. This routine does that.
+
+Arguments:
+
+ ChainHead - a cluster chain; data blocks are allocated for each
+ cluster in this chain.
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure - not enough disk space
+
+--*/
+{
+ USHORT clus;
+ USHORT next;
+
+ clus = (USHORT)ChainHead;
+ for (;;) {
+ if (!AllocateClusterData(clus,
+ (UCHAR)QuerySectorsPerCluster(),
+ FALSE,
+ (UCHAR)QuerySectorsPerCluster())) {
+ break;
+ }
+
+ if (_fat->IsEndOfChain(clus)) {
+ return TRUE;
+ }
+
+ clus = _fat->QueryEntry(clus);
+ }
+
+ // Error: not enough disk space. XXX.mjb
+
+ // Free the sectors we already allocated
+
+ while (ChainHead != clus) {
+ FreeClusterData(ChainHead);
+ next = _fat->QueryEntry((USHORT)ChainHead);
+ _fat->SetClusterFree((USHORT)ChainHead);
+ ChainHead = next;
+ }
+
+ return FALSE;
+}
+
+#if defined( _SETUP_LOADER_ )
+
+BOOLEAN
+FAT_SA::RecoverFreeSpace(
+ IN OUT PMESSAGE Message
+ )
+{
+ return TRUE;
+}
+
+#else // _SETUP_LOADER_ not defined
+
+BOOLEAN
+FAT_SA::RecoverFreeSpace(
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine checks all of the space marked free in the FAT for
+ bad clusters. If any clusters are bad they are marked bad in the
+ FAT.
+
+Arguments:
+
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ USHORT clus, length, max_length;
+ ULONG start_sector, num_sectors, i;
+ NUMBER_SET bad_sectors;
+ LBN lbn;
+ ULONG percent_complete;
+ ULONG num_checked, total_to_check;
+
+ Message->Set(MSG_CHK_RECOVERING_FREE_SPACE, PROGRESS_MESSAGE);
+ Message->Display();
+
+ percent_complete = 0;
+ Message->Set(MSG_PERCENT_COMPLETE);
+ Message->Display("%d", percent_complete);
+
+ num_checked = 0;
+ total_to_check = _fat->QueryFreeClusters();
+ max_length = QueryClusterCount()/20 + 1;
+ for (clus = FirstDiskCluster; _fat->IsInRange(clus); clus++) {
+
+ for (length = 0; _fat->IsInRange(clus + length) &&
+ _fat->IsClusterFree(clus + length) &&
+ length < max_length; length++) {
+ }
+
+ if (length) {
+
+ start_sector = QueryStartDataLbn() +
+ (clus - FirstDiskCluster)*QuerySectorsPerCluster();
+ num_sectors = length*QuerySectorsPerCluster();
+
+ if (!bad_sectors.Initialize() ||
+ !_drive->Verify(start_sector, num_sectors, &bad_sectors)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ for (i = 0; i < bad_sectors.QueryCardinality(); i++) {
+ lbn = bad_sectors.QueryNumber(i).GetLowPart();
+ _fat->SetClusterBad((USHORT) ((lbn - QueryStartDataLbn())/
+ QuerySectorsPerCluster()) +
+ FirstDiskCluster );
+ }
+
+ clus += length - 1;
+ num_checked += length;
+
+ if (100*num_checked/total_to_check > percent_complete) {
+ percent_complete = 100*num_checked/total_to_check;
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", percent_complete)) {
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ percent_complete = 100;
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", percent_complete)) {
+ return FALSE;
+ }
+
+ Message->Set(MSG_CHK_DONE_RECOVERING_FREE_SPACE, PROGRESS_MESSAGE);
+ Message->Display();
+
+ return TRUE;
+}
+
+#endif // _SETUP_LOADER_
diff --git a/private/utils/ufat/src/fatsacnv.cxx b/private/utils/ufat/src/fatsacnv.cxx
new file mode 100644
index 000000000..0825ece7a
--- /dev/null
+++ b/private/utils/ufat/src/fatsacnv.cxx
@@ -0,0 +1,814 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UFAT_MEMBER_
+
+#include "ulib.hxx"
+#include "ufat.hxx"
+
+#include "cluster.hxx"
+#include "cmem.hxx"
+#include "error.hxx"
+#include "fatdent.hxx"
+#include "fatsa.hxx"
+#include "rootdir.hxx"
+#include "rtmsg.h"
+#include "sortlist.hxx"
+#include "sortlit.hxx"
+#include "filedir.hxx"
+#include "fat.hxx"
+#include "reloclus.hxx"
+#include "intstack.hxx"
+
+// #include "keyboard.hxx"
+
+
+
+UFAT_EXPORT
+BOOLEAN
+FAT_SA::QueryCensusAndRelocate (
+ OUT PCENSUS_REPORT CensusReport,
+ IN OUT PINTSTACK RelocationStack,
+ OUT PBOOLEAN Relocated
+ )
+
+/*++
+
+Routine Description:
+
+ This function serves a double purpose:
+
+ 1.- Generates a census report containing the number and size of different
+ FAT structures. This report is somewhat similar to the ChkDsk report.
+
+ 2.- Relocates clusters to free areas of the disk.
+
+ Depending on the input parameters, this method may generate the census
+ report, relocate clusters, both, or none.
+
+Arguments:
+
+ CensusReport - Supplies a pointer to the buffer that will contain
+ the census report.
+
+ RelocationStack - Supplies a stack with the runs to be relocated.
+ The runs have to be pushed onto the stack as
+ (Start, Size) tuples, with the Size value being
+ pushed first. Both values must be given in sectors.
+
+
+ Relocated - Supplies pointer to boolean which is set to TRUE
+ if any cluster was relocated.
+
+Return Value:
+
+ BOOLEAN - TRUE if (if requested) the census report was generated and
+ if (if requested) the clusters were relocated.
+--*/
+
+{
+ USHORT RelocatedChain; // Chain of relocated clusters
+ SORTED_LIST ClustersToRelocate; // List of clusters to relocate
+
+ *Relocated = FALSE;
+
+ //
+ // Initialize the list of clusters to relocate and the relocated chain.
+ // The Relocated chain is the chain of clusters that have been relocated,
+ // it exists so that the clusters that have been freed by relocation
+ // are not re-used while relocating other clusters.
+ //
+ if ( !ClustersToRelocate.Initialize( ) ) {
+ return FALSE;
+ }
+
+ RelocatedChain = 0;
+
+ //
+ // If a Relocation stack is provided, relocate all clusters that can
+ // be easily relocated and put all other clusters in the
+ // ClustersToRelocate list.
+ //
+ // The clusters that are easily relocated are those that are not the
+ // first cluster of a chain. These clusters can be relocated by copying
+ // their contents and then patching the chain. Clusters that are the
+ // head of a chain require us to traverse the filesystem tree in order
+ // to locate their corresponding directory entry.
+ //
+ if ( RelocationStack ) {
+
+ //
+ // InitRelocationList takes care of relocating all "easy" clusters.
+ // It puts the rest of the clusters (i.e. those that are head of
+ // chains) in the ClustersToRelocate list.
+ //
+ if ( !InitRelocationList( RelocationStack,
+ &RelocatedChain,
+ &ClustersToRelocate,
+ Relocated ) ) {
+
+ ClustersToRelocate.DeleteAllMembers( );
+
+ return FALSE;
+ }
+
+ //
+ // The RelocationStack should be empty. All the clusters that it
+ // specified have either been relocated or are now in the
+ // ClustersToRelocate list.
+ //
+ DebugAssert( RelocationStack->QuerySize() == 0 );
+
+ }
+
+ //
+ // If we need to, traverse the directory tree obtaining the census
+ // and/or relocating the clusters in the ClustersToRelocate list.
+ //
+ if ( CensusReport || (ClustersToRelocate.QueryMemberCount() > 0 ) ) {
+
+ if ( !DoVolumeCensusAndRelocation( CensusReport,
+ &ClustersToRelocate,
+ &RelocatedChain,
+ Relocated ) ) {
+
+ ClustersToRelocate.DeleteAllMembers( );
+
+ return FALSE;
+ }
+
+ DebugAssert( ClustersToRelocate.QueryMemberCount() == 0 );
+ }
+
+ //
+ // All the clusters in the relocation stack have been relocated,
+ // we can now free the clusters in the RelocatedChain.
+ //
+ if ( RelocatedChain ) {
+ _fat->FreeChain( RelocatedChain );
+ }
+
+ //
+ // Write the fat to disk
+ //
+ return Write();
+}
+
+
+
+
+BOOLEAN
+FAT_SA::InitRelocationList(
+ IN OUT PINTSTACK RelocationStack,
+ IN OUT PUSHORT RelocatedChain,
+ IN OUT PSORTED_LIST ClustersToRelocate,
+ OUT PBOOLEAN Relocated
+ )
+/*++
+
+Routine Description:
+
+ Takes runs of sectors out of a relocation stack and converts the sectors
+ into clusters. If a cluster is easily relocatable, this method relocates
+ the cluster and adds the cluster to the RelocatedChain. Otherwise the
+ cluster is added to the ClustersToRelocate list.
+
+ If everything goes right, upon return the RelocationStack is empty, and
+ every cluster it specified is either in the RelocatedChain or in the
+ ClustersToRelocate list.
+
+ Note that the relocation stack specifies runs of SECTORS. This method converts
+ the sectors to FAT clusters.
+
+Arguments:
+
+ RelocationStack - Supplies the Relocation stack
+ RelocatedChain - Supplies the chain of relocated clusters
+ ClustersToRelocate - Supplies the list of cluisters to relocate
+ Relocated - Supplies pointer to relocated flag
+
+Return Value:
+
+ BOOLEAN - TRUE if all the clusters in the runs were added to some
+ list.
+
+--*/
+
+{
+
+ SORTED_LIST RelocatedList; // List of relocated clusters
+ PSORTED_LIST_ITERATOR ToRelocateIterator; // Iterates over ClustersToRelocate
+ PSORTED_LIST_ITERATOR RelocatedIterator; // Iterates over RelocatedList
+ BIG_INT FirstSector; // First sector in run
+ BIG_INT Size; // Size of run
+ BIG_INT Sector; // Iterates over each run
+ ULONG Offset; // Offset within run
+ USHORT Cluster; // Cluster to move
+ USHORT Previous; // Previous in chain
+ RELOCATION_CLUSTER TmpCluster; // Tmp. Cluster
+ PRELOCATION_CLUSTER RelCluster; // To put in cluster list
+
+
+ DebugPtrAssert( RelocationStack );
+ DebugPtrAssert( RelocatedChain );
+ DebugPtrAssert( ClustersToRelocate);
+ DebugAssert( ( RelocationStack->QuerySize() % 2 ) == 0 );
+
+
+ if ( RelocatedList.Initialize() &&
+ (RelocatedIterator = (PSORTED_LIST_ITERATOR)(RelocatedList.QueryIterator()) ) &&
+ (ToRelocateIterator = (PSORTED_LIST_ITERATOR)(ClustersToRelocate->QueryIterator()) ) ) {
+
+ while ( RelocationStack->QuerySize() > 0 ) {
+
+ //
+ // Take a Run (i.e. a <FirstSector, Size> tuple) off the stack.
+ //
+ FirstSector = RelocationStack->Look( 0 );
+ Size = RelocationStack->Look( 1 );
+ RelocationStack->Pop( 2 );
+
+ DebugPrintf( " Relocating: Sector %X, size %X\n", FirstSector.GetLowPart(), Size.GetLowPart() );
+
+ //
+ // Convert the run into a sequence of clusters and determine
+ // what to do with those clusters.
+ //
+ Offset = 0;
+ while ( Offset < Size.GetLowPart() ) {
+
+ //
+ // Get the sector to relocate
+ //
+ Sector = FirstSector + Offset;
+
+ //
+ // Get the cluster in which that sector lives
+ //
+ Cluster = (USHORT)(((Sector - QueryStartDataLbn() )/ (ULONG)QuerySectorsPerCluster()).GetLowPart() + FirstDiskCluster);
+
+ //
+ // Initialize the tmp. cluster and reset iterators
+ //
+ TmpCluster.Initialize( Cluster );
+ RelocatedIterator->Reset();
+ ToRelocateIterator->Reset();
+
+ DebugPrintf( " Cluster to relocate: %X ( Sector %X ) Contents %X \n", Cluster, Sector.GetLowPart(), _fat->QueryEntry( Cluster ) );
+
+ //
+ // If the cluster is already in a list, ignore it.
+ //
+ if ( !RelocatedIterator->FindNext( &TmpCluster ) &&
+ !ToRelocateIterator->FindNext( &TmpCluster ) ) {
+
+ //
+ // New cluster. Determine what to do with it
+ //
+ if ( !(RelCluster = NEW RELOCATION_CLUSTER) ) {
+ break;
+ }
+
+ RelCluster->Initialize( Cluster );
+
+ if ( _fat->IsClusterFree( Cluster ) ) {
+
+ //
+ // The cluster is already free. Add it to the
+ // RelocatedChain.
+ //
+ DebugPrintf( " Cluster %X already free\n", Cluster );
+ *RelocatedChain = _fat->InsertChain( *RelocatedChain, Cluster );
+ RelocatedList.Put( RelCluster );
+
+ } else if ( Previous =
+ //
+ // Assume that the clusters in the run are part of
+ // a chain. If the previous cluster number is the
+ // previous in the chain, then we don't have to
+ // search the FAT
+ //
+ (_fat->QueryEntry( Cluster - 1 ) == Cluster) ?
+ ( Cluster - 1 ) :
+ _fat->QueryPrevious( Cluster ) ) {
+
+ //
+ // The cluster is not the first of a chain. We can
+ // relocate it right away.
+ //
+ DebugPrintf( " Cluster %X not head of chain\n", Cluster );
+ if ( !RelocateOneCluster( Cluster, Previous ) ) {
+ DELETE( RelCluster );
+ break;
+ }
+ *Relocated = TRUE;
+ *RelocatedChain = _fat->InsertChain( *RelocatedChain, Cluster );
+ RelocatedList.Put( RelCluster );
+
+ } else if ( _fat->IsClusterBad( Cluster ) ) {
+
+ //
+ // Bad cluster. We will stop relocating clusters.
+ //
+ DebugPrintf( " Cluster %X is Bad!\n", Cluster );
+ DELETE( RelCluster );
+ break;
+
+ } else {
+
+ //
+ // The first cluster of a chain. Some directory
+ // must make reference to it, but we don't know
+ // which directory, so we put the cluster in the
+ // ClusterToRelocate list.
+ //
+ DebugPrintf( " Cluster %X head of chain\n", Cluster );
+ ClustersToRelocate->Put( RelCluster );
+ }
+ }
+
+ Offset++;
+ }
+
+ //
+ // If could not process all the sectors in the run, something
+ // failed. Get out.
+ //
+ if ( Offset < Size.GetLowPart() ) {
+ break;
+ }
+ }
+
+ DELETE( RelocatedIterator );
+ DELETE( ToRelocateIterator );
+ RelocatedList.DeleteAllMembers();
+
+ return ((RelocationStack->QuerySize() == 0) && ( Offset >= Size.GetLowPart() ) );
+ }
+
+ return FALSE;
+}
+
+
+
+BOOLEAN
+FAT_SA::RelocateFirstCluster(
+ IN OUT PFAT_DIRENT Dirent
+ )
+
+/*++
+
+Routine Description:
+
+ Relocates the first cluster of the file described by a directory
+ entry.
+
+Arguments:
+
+ Dirent - Supplies the directory entry
+
+Return Value:
+
+ BOOLEAN - TRUE if cluster relocated.
+
+--*/
+{
+
+ HMEM Hmem; // Memory
+ USHORT OldCluster; // Original cluster
+ USHORT NewCluster; // New cluster
+ CLUSTER_CHAIN ClusterChain; // Cluster chain
+
+ DebugPtrAssert( Dirent );
+
+ //
+ // Allocate a free cluster
+ //
+ if ( !Hmem.Initialize() ||
+ !( NewCluster = _fat->AllocChain( 1 ) ) ) {
+ return FALSE;
+ }
+
+ //
+ // Copy the contents of the cluster to the new cluster
+ //
+ OldCluster = Dirent->QueryStartingCluster();
+
+ // DebugPrintf( " Relocating cluster %X -> %X\n", OldCluster, NewCluster );
+
+ if ( ClusterChain.Initialize( &Hmem, _drive, this, _fat, OldCluster, 1 ) &&
+ ClusterChain.Read() &&
+ ClusterChain.Initialize( &Hmem, _drive, this, _fat, NewCluster, 1 ) &&
+ ClusterChain.Write() ) {
+
+ //
+ // Patch the cluster chain
+ //
+ _fat->SetEntry( NewCluster, _fat->QueryEntry( OldCluster ) );
+
+ //
+ // Patch the directory entry. Note that if we crash, we're ok because
+ // the new cluster that we point to is valid. The original cluster would
+ // be an orphan and can be recovered by ChkDsk.
+ //
+ Dirent->SetStartingCluster( NewCluster );
+ _fat->SetClusterFree( OldCluster );
+
+ // DebugPrintf( " Directory entry patched.\n");
+ return TRUE;
+ }
+
+ //
+ // Could not relocate the cluster, Free the new cluster
+ //
+ _fat->FreeChain( NewCluster );
+ return FALSE;
+}
+
+
+
+
+
+
+USHORT
+FAT_SA::RelocateOneCluster(
+ IN USHORT Cluster,
+ IN USHORT Previous
+ )
+
+/*++
+
+Routine Description:
+
+ Relocates one cluster given its cluster number and the previous
+ cluster in its chain.
+
+Arguments:
+
+ Cluster - Supplies cluster to relocate
+ Previous - Supplies the previous cluster in the chain
+
+Return Value:
+
+ USHORT - Cluster where the cluster was relocated
+
+--*/
+{
+
+ HMEM Hmem; // Memory
+ USHORT NewCluster; // New cluster
+ CLUSTER_CHAIN ClusterChain; // Cluster chain
+
+ DebugAssert( Cluster );
+ DebugAssert( Previous );
+
+ //
+ // Allocate a free cluster
+ //
+ if ( !Hmem.Initialize() ||
+ !( NewCluster = _fat->AllocChain(1)) ) {
+ return FALSE;
+ }
+
+ // DebugPrintf( " Relocating cluster %X -> %X\n", Cluster, NewCluster );
+
+ //
+ // Copy the contents of the cluster to the new cluster
+ //
+ if ( ClusterChain.Initialize( &Hmem, _drive, this, _fat, Cluster, 1 ) &&
+ ClusterChain.Read() &&
+ ClusterChain.Initialize( &Hmem, _drive, this, _fat, NewCluster, 1 ) &&
+ ClusterChain.Write() ) {
+
+ //
+ // Patch the chain. We set the new cluster first, so that if we crash,
+ // the previous cluster will always point to a valid cluster (either the
+ // original one or the new one), the chain will remain consistent and
+ // ChkDsk will remove orphans.
+ //
+ _fat->SetEntry( NewCluster, _fat->QueryEntry( Cluster ) );
+ _fat->SetEntry( Previous, NewCluster );
+ _fat->SetClusterFree( Cluster );
+
+ // DebugPrintf( " Done, Chain: Prev[%X (%X)] - [%X (%X)]\n",
+ // Previous,
+ // _fat->QueryEntry(Previous),
+ // NewCluster,
+ // _fat->QueryEntry(NewCluster)
+ // );
+
+ return NewCluster;
+ }
+
+ //
+ // Could not relocate the cluster, Free the new cluster
+ //
+ _fat->FreeChain( NewCluster );
+ return 0;
+}
+
+
+
+
+
+
+BOOLEAN
+FAT_SA::DoVolumeCensusAndRelocation(
+ IN OUT PCENSUS_REPORT CensusReport,
+ IN OUT PSORTED_LIST ClustersToRelocate,
+ IN OUT PUSHORT RelocatedChain,
+ OUT PBOOLEAN Relocated
+ )
+/*++
+
+Routine Description:
+
+ Does a volume census and/or relocates clusters in the supplied
+ relocation list.
+
+Arguments:
+
+ CensusReport - Supplies pointer to the census report structure
+ ClustersToRelocate - Supplies pointer to list of clusters to relocate
+ RelocatedChain - Supplies pointer to chain of relocated clusters
+ Relocated - Supplies pointer to relocated flag
+
+Return Value:
+
+ BOOLEAN - TRUE if census report obtained (if requested) and all
+ the clusters in the relocation list were relocated (if
+ requested).
+
+--*/
+{
+ PFATDIR RootDir; // Root directory
+ FAT_DIRENT DirEnt; // Directory entry for iterating thru directory
+ DSTRING EAFile; // Name of EA file
+
+ DebugAssert( !ClustersToRelocate || RelocatedChain );
+
+ //
+ // If there is something to do, do it.
+ //
+ if ( CensusReport ||
+ (ClustersToRelocate && ClustersToRelocate->QueryMemberCount() > 0) ) {
+
+ //
+ // Initialize the Census report if requested
+ //
+ if ( CensusReport ) {
+ CensusReport->FileEntriesCount = 0;
+ CensusReport->FileClusters = 0;
+ CensusReport->DirEntriesCount = 0;
+ CensusReport->DirClusters = 0;
+ CensusReport->EaClusters = 0;
+ }
+
+ //
+ // Get root directory
+ //
+ RootDir = (PFATDIR)GetRootDir();
+ DebugPtrAssert( RootDir );
+
+ //
+ // Do the census of the volume by recursively obtaining the
+ // census of the root directory.
+ //
+ if ( DoDirectoryCensusAndRelocation( RootDir,
+ CensusReport,
+ ClustersToRelocate,
+ RelocatedChain,
+ Relocated ) ) {
+
+ //
+ // If a census report is requested, find out the size of
+ // the EA file (if it exists).
+ //
+ if ( CensusReport ) {
+ EAFile.Initialize( "EA DATA. SF" );
+
+ if ( DirEnt.Initialize( (PFAT_DIRENT)RootDir->SearchForDirEntry( &EAFile )) ) {
+
+ CensusReport->EaClusters =
+ (USHORT)((USHORT)DirEnt.QueryFileSize()/
+ (_drive->QuerySectorSize()*QuerySectorsPerCluster())+1);
+ }
+ }
+ } else {
+
+ //
+ // Could not do the directory census
+ //
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+
+}
+
+
+
+
+BOOLEAN
+FAT_SA::DoDirectoryCensusAndRelocation(
+ IN OUT PFATDIR Directory,
+ IN OUT PCENSUS_REPORT CensusReport,
+ IN OUT PSORTED_LIST ClustersToRelocate,
+ IN OUT PUSHORT RelocatedChain,
+ OUT PBOOLEAN Relocated
+ )
+/*++
+
+Routine Description:
+
+ Does the census and cluster relocation of a directory an all
+ its subdirectories.
+
+Arguments:
+
+ Directory - Supplies the directory
+ CensusReport - Supplies pointer to the census report structure
+ ClustersToRelocate - Supplies pointer to list of clusters to relocate
+ RelocatedChain - Supplies pointer to chain of relocated clusters
+ Relocated - Supplies pointer to relocated flag
+
+Return Value:
+
+ BOOLEAN - TRUE if census report obtained (if requested) and all
+ the clusters in the relocation list (if provided) that
+ were references by this directory (or a subdirectory)
+ were relocated.
+
+--*/
+
+{
+
+ FAT_DIRENT Dirent; // For iterating thru Dir
+ HMEM HMem; // Memory
+ FILEDIR FileDir; // Subdir
+ RELOCATION_CLUSTER TmpCluster; // Tmp. cluster
+ PRELOCATION_CLUSTER ClusterToRelocate; // Cluster to relocate
+ PRELOCATION_CLUSTER RelocatedCluster; // Cluster relocated
+ PITERATOR Iterator = NULL; // Iterates thru ClustersToRelocate
+ ULONG EntryNumber = 0; // Iterates thru Directorty
+ BOOLEAN Ok = TRUE; // FALSE if error
+ BOOLEAN RelocatedHere = FALSE; // True if relocated something
+
+ DebugPtrAssert( Directory );
+
+ //
+ // If there are clusters to relocate, get an iterator for searching
+ // thru the list.
+ //
+ if ( ClustersToRelocate && ClustersToRelocate->QueryMemberCount() > 0 ) {
+ Iterator = ClustersToRelocate->QueryIterator();
+ if ( !Iterator ) {
+ return FALSE;
+ }
+ }
+
+ while ( Ok &&
+ (CensusReport || (ClustersToRelocate && ClustersToRelocate->QueryMemberCount() > 0)) ) {
+
+ //
+ // Get next directory entry and get out if we reach the end.
+ //
+ if ( !Dirent.Initialize( Directory->GetDirEntry( EntryNumber ) ) ||
+ Dirent.IsEndOfDirectory()
+ ) {
+ break;
+ }
+
+ //
+ // Ignore the deleted, the "parent" and the "self" entries
+ // and any long directory entries
+ //
+ if ( !( Dirent.IsErased() ||
+ Dirent.IsDot() ||
+ Dirent.IsDotDot() ||
+ Dirent.IsLongEntry() ) ) {
+
+
+ //
+ // If a Relocation list is provided, and the first cluster
+ // of the entry is in the relocation list, then relocate
+ // the cluster.
+ //
+ if ( ClustersToRelocate && ClustersToRelocate->QueryMemberCount() > 0 ) {
+
+ Iterator->Reset();
+ TmpCluster.Initialize( Dirent.QueryStartingCluster() );
+
+ if ( ClusterToRelocate = (PRELOCATION_CLUSTER)Iterator->FindNext( &TmpCluster ) ) {
+
+ //
+ // Cluster is in the relocation list, relocate it.
+ //
+ if ( !RelocateFirstCluster( &Dirent ) ) {
+ DebugAssert( FALSE );
+ Ok = FALSE;
+ break;
+ }
+
+
+ //
+ // Cluster has been relocated. Remove the cluster from
+ // the relocation list and add it to the Relocated
+ // chain.
+ //
+ RelocatedCluster = (PRELOCATION_CLUSTER)ClustersToRelocate->Remove( Iterator );
+ DebugAssert( RelocatedCluster == ClusterToRelocate );
+ *RelocatedChain = _fat->InsertChain( *RelocatedChain, RelocatedCluster->QueryClusterNumber() );
+ DELETE( RelocatedCluster );
+
+ //
+ // Set the Relocated flag so that we remember to write out
+ // the directory when we are done traversing it.
+ //
+ *Relocated = TRUE;
+ RelocatedHere = TRUE;
+
+ }
+ }
+
+ if ( Dirent.IsDirectory() ) {
+
+ //
+ // This is a directory entry, update the census
+ // (if provided) and recurse.
+ //
+ if( !_fat->IsValidChain( Dirent.QueryStartingCluster() ) ) {
+
+ Ok = FALSE;
+ break;
+ }
+
+ if ( CensusReport ) {
+ CensusReport->DirEntriesCount++;
+ CensusReport->DirClusters += _fat->QueryLengthOfChain( Dirent.QueryStartingCluster() );
+ }
+
+ if ( !HMem.Initialize() ||
+
+ !FileDir.Initialize( &HMem,
+ _drive,
+ this,
+ _fat,
+ Dirent.QueryStartingCluster() ) ||
+
+ !FileDir.Read() ||
+
+ !DoDirectoryCensusAndRelocation( &FileDir,
+ CensusReport,
+ ClustersToRelocate,
+ RelocatedChain,
+ Relocated ) ) {
+
+ //
+ // Something went wrong, we return failure
+ //
+ Ok = FALSE;
+ break;
+ }
+
+ } else if ( !Dirent.IsVolumeLabel() ) {
+
+ //
+ // This is a file entry, update the census
+ // (if provided )
+ //
+ if( Dirent.QueryStartingCluster() != 0 &&
+ !_fat->IsValidChain( Dirent.QueryStartingCluster() ) ) {
+
+ Ok = FALSE;
+ break;
+ }
+
+ if ( CensusReport ) {
+ CensusReport->FileEntriesCount++;
+ CensusReport->FileClusters += _fat->QueryLengthOfChain( Dirent.QueryStartingCluster() );
+ }
+ }
+ }
+
+ EntryNumber++;
+ }
+
+ if ( Iterator ) {
+ DELETE( Iterator );
+ }
+
+ //
+ // If we relocated something, then we have patched some entry in this
+ // directory. Write it out to disk
+ //
+ if ( Ok && RelocatedHere ) {
+ Ok = Directory->Write();
+
+ DebugAssert( Ok );
+
+ }
+
+ return Ok;
+}
diff --git a/private/utils/ufat/src/fatvol.cxx b/private/utils/ufat/src/fatvol.cxx
new file mode 100644
index 000000000..eca57559c
--- /dev/null
+++ b/private/utils/ufat/src/fatvol.cxx
@@ -0,0 +1,435 @@
+#include <pch.cxx>
+
+#include "error.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+#include "wstring.hxx"
+
+
+DEFINE_CONSTRUCTOR( FAT_VOL, VOL_LIODPDRV );
+
+VOID
+FAT_VOL::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Constructor for FAT_VOL.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ // unreferenced parameters
+ (void)(this);
+}
+
+
+FAT_VOL::~FAT_VOL(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for FAT_VOL.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+BOOLEAN
+FAT_VOL::Initialize(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN ExclusiveWrite,
+ IN BOOLEAN FormatMedia,
+ IN MEDIA_TYPE MediaType
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes a FAT_VOL object.
+
+Arguments:
+
+ NtDriveName - Supplies the drive path for the volume.
+ Message - Supplies an outlet for messages.
+ ExclusiveWrite - Supplies whether or not the drive should be
+ opened for exclusive write.
+ FormatMedia - Supplies whether or not to format the media.
+ MediaType - Supplies the type of media to format to.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ MESSAGE msg;
+
+ Destroy();
+
+ if (!VOL_LIODPDRV::Initialize(NtDriveName, &_fatsa, Message,
+ ExclusiveWrite, FormatMedia,
+ MediaType)) {
+ Destroy();
+ return FALSE;
+ }
+
+ if (!Message) {
+ Message = &msg;
+ }
+
+ if (FormatMedia) {
+ if (!_fatsa.Initialize(this, Message, FALSE)) {
+ Destroy();
+ return FALSE;
+ }
+ } else {
+ if (!_fatsa.Initialize(this, &msg, TRUE) &&
+ !_fatsa.Initialize(this, Message, FALSE)) {
+ Destroy();
+ return FALSE;
+ }
+
+ if (!_fatsa.Read(Message)) {
+ Destroy();
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+FAT_VOL::IsFileContiguous(
+ IN PCWSTRING FullPathFileName,
+ IN OUT PMESSAGE Message,
+ OUT PULONG NumBlocks
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the number of contiguous blocks for the given
+ file. If the file has only one block then the file is contiguous and
+ this function returns TRUE. Otherwise this function returns FALSE and
+ the number of blocks is optionally returned into 'NumBlocks'.
+
+Arguments:
+
+ FullPathFileName - Supplies the file name of the file to check for
+ contiguity.
+ Message - Supplies an outlet for messages.
+ NumBlocks - Returns the number of contiguous blocks.
+
+Return Value:
+
+ FALSE - The file is not contiguous.
+ TRUE - The file is contiguous.
+
+--*/
+{
+ ULONG num_blocks;
+ PFAT fat;
+ USHORT clus;
+ DSTRING slash;
+
+ if (NumBlocks) {
+ *NumBlocks = 0;
+ }
+
+ if (!slash.Initialize("\\")) {
+ Message ? Message->Set(MSG_CHK_NO_MEMORY) : 1;
+ Message ? Message->Display("") : 1;
+ return FALSE;
+ }
+
+ if (*FullPathFileName == slash) {
+ *NumBlocks = 1;
+ return TRUE;
+ }
+
+ if ((clus = _fatsa.QueryFileStartingCluster(FullPathFileName)) == 1) {
+ Message ? Message->Set(MSG_FILE_NOT_FOUND) : 1;
+ Message ? Message->Display("%W", FullPathFileName) : 1;
+ return FALSE;
+ }
+
+ if (clus == 0xFFFF) {
+ Message ? Message->Set(MSG_CHK_NO_MEMORY) : 1;
+ Message ? Message->Display("") : 1;
+ return FALSE;
+ }
+
+ // Say that a zero length file is contiguous.
+
+ if (clus == 0) {
+ *NumBlocks = 1;
+ return TRUE;
+ }
+
+
+ fat = _fatsa.GetFat();
+
+ DebugAssert(fat);
+
+ for (num_blocks = 1; ; num_blocks++) {
+ while (!fat->IsEndOfChain(clus) &&
+ (USHORT)(clus + 1) == fat->QueryEntry(clus)) {
+ clus++;
+ }
+ if (fat->IsEndOfChain(clus)) {
+ break;
+ }
+ clus = fat->QueryEntry(clus);
+ }
+
+ if (NumBlocks) {
+ *NumBlocks = num_blocks;
+ }
+
+ return num_blocks == 1;
+}
+
+
+BOOLEAN
+FAT_VOL::ContiguityReport(
+ IN PCWSTRING DirectoryPath,
+ IN PCDSTRING FilesToCheck,
+ IN ULONG NumberOfFiles,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine generates a contiguity report for all of the 'FilesToCheck'.
+ These file are assumed to all be in the directory pointed to by
+ 'DirectoryPath'.
+
+Arguments:
+
+ DirectoryPath - Supplies the directory containing the files to check.
+ FilesToCheck - Supplies an array of files to check.
+ NumberOfFiles - Supplies the number of files in the preceeding array.
+ Message - Suppliea an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG num_blocks;
+ PFAT fat;
+ USHORT clus;
+ DSTRING slash;
+ FILEDIR filedir;
+ PFATDIR dir;
+ HMEM hmem;
+ BOOLEAN all_contig;
+ FAT_DIRENT fatdent;
+ DSTRING current_file;
+ ULONG i;
+ DSTRING directory_path;
+
+ if (!slash.Initialize("\\")) {
+ Message ? Message->Set(MSG_CHK_NO_MEMORY) : 1;
+ Message ? Message->Display() : 1;
+ return FALSE;
+ }
+
+ if ((clus = _fatsa.QueryFileStartingCluster(DirectoryPath)) == 1) {
+ Message->Set(MSG_FILE_NOT_FOUND);
+ Message->Display("%W", DirectoryPath);
+ return FALSE;
+ }
+
+ if (clus == 0xFFFF) {
+ Message ? Message->Set(MSG_CHK_NO_MEMORY) : 1;
+ Message ? Message->Display() : 1;
+ return FALSE;
+ }
+
+ fat = _fatsa.GetFat();
+
+ if (!clus) {
+ dir = _fatsa.GetRootDir();
+ } else {
+ dir = &filedir;
+ if (!hmem.Initialize() ||
+ !filedir.Initialize(&hmem, this, &_fatsa, fat, clus)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!filedir.Read()) {
+ Message->Set(MSG_FILE_NOT_FOUND);
+ Message->Display("%W", DirectoryPath);
+ return FALSE;
+ }
+ }
+
+ if (*DirectoryPath == slash) {
+
+ if (!directory_path.Initialize("")) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ } else {
+ if (!directory_path.Initialize(DirectoryPath)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+
+ all_contig = TRUE;
+ for (i = 0; i < NumberOfFiles; i++) {
+
+ if (!current_file.Initialize(&directory_path) ||
+ !current_file.Strcat(&slash) ||
+ !current_file.Strcat(&FilesToCheck[i])) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (fatdent.Initialize(dir->SearchForDirEntry(&FilesToCheck[i]))) {
+
+ if (clus = fatdent.QueryStartingCluster()) {
+
+ for (num_blocks = 1; ; num_blocks++) {
+ while (!fat->IsEndOfChain(clus) &&
+ (USHORT)(clus + 1) == fat->QueryEntry(clus)) {
+ clus++;
+ }
+ if (fat->IsEndOfChain(clus)) {
+ break;
+ }
+ clus = fat->QueryEntry(clus);
+ }
+
+ if (num_blocks != 1) {
+ Message->Set(MSG_CONTIGUITY_REPORT);
+ Message->Display("%W%d", &current_file, num_blocks);
+ all_contig = FALSE;
+ }
+
+ }
+
+ } else {
+ Message->Set(MSG_FILE_NOT_FOUND);
+ Message->Display("%W", &current_file);
+ all_contig = FALSE;
+ }
+ }
+
+ if (all_contig) {
+ Message->Set(MSG_ALL_FILES_CONTIGUOUS);
+ Message->Display("");
+ }
+
+ return TRUE;
+}
+
+
+PVOL_LIODPDRV
+FAT_VOL::QueryDupVolume(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN ExclusiveWrite,
+ IN BOOLEAN FormatMedia,
+ IN MEDIA_TYPE MediaType
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine allocates a FAT_VOL and initializes it to 'NtDriveName'.
+
+Arguments:
+
+ NtDriveName - Supplies the drive path for the volume.
+ Message - Supplies an outlet for messages.
+ ExclusiveWrite - Supplies whether or not the drive should be
+ opened for exclusive write.
+ FormatMedia - Supplies whether or not to format the media.
+ MediaType - Supplies the type of media to format to.
+
+Return Value:
+
+ A pointer to a newly allocated FAT volume.
+
+--*/
+{
+ PFAT_VOL vol;
+
+ // unreferenced parameters
+ (void)(this);
+
+ if (!(vol = NEW FAT_VOL)) {
+ Message ? Message->Set(MSG_FMT_NO_MEMORY) : 1;
+ Message ? Message->Display("") : 1;
+ return NULL;
+ }
+
+ if (!vol->Initialize(NtDriveName, Message, ExclusiveWrite,
+ FormatMedia, MediaType)) {
+ DELETE(vol);
+ return NULL;
+ }
+
+ return vol;
+}
+
+
+VOID
+FAT_VOL::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a FAT_VOL object to its initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ // unreferenced parameters
+ (void)(this);
+}
diff --git a/private/utils/ufat/src/filedir.cxx b/private/utils/ufat/src/filedir.cxx
new file mode 100644
index 000000000..cc307a26c
--- /dev/null
+++ b/private/utils/ufat/src/filedir.cxx
@@ -0,0 +1,132 @@
+#include <pch.cxx>
+
+#define _UFAT_MEMBER_
+#include "ufat.hxx"
+
+#include "error.hxx"
+
+DEFINE_EXPORTED_CONSTRUCTOR( FILEDIR, FATDIR, UFAT_EXPORT );
+
+VOID
+FILEDIR::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Constructor for FILEDIR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _number_of_entries = 0;
+}
+
+
+UFAT_EXPORT
+FILEDIR::~FILEDIR(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for FILEDIR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+UFAT_EXPORT
+BOOLEAN
+FILEDIR::Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN PFAT_SA FatSuperArea,
+ IN PCFAT Fat,
+ IN USHORT StartingCluster
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the FILEDIR object for use. It will enable
+ referencing the directory starting at StartingCluster.
+
+Arguments:
+
+ Mem - Supplies the memory for the cluster chain.
+ Drive - Supplies the drive on which the directory resides.
+ FatSuperArea - Supplies the super area for the FAT file system on
+ the drive.
+ Fat - Supplies the file allocation table for the drive.
+ StartingCluster - Supplies the first cluster of the directory.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ Destroy();
+
+ if (!_cluster.Initialize(Mem, Drive, FatSuperArea, Fat, StartingCluster)) {
+ perrstk->push(ERR_NOT_INIT, QueryClassId());
+ Destroy();
+ return FALSE;
+ }
+
+ _number_of_entries = Drive->QuerySectorSize()*
+ FatSuperArea->QuerySectorsPerCluster()*
+ _cluster.QueryLength()/
+ BytesPerDirent;
+
+ if (!_number_of_entries) {
+ perrstk->push(ERR_NOT_INIT, QueryClassId());
+ Destroy();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+VOID
+FILEDIR::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the object to its initial state. Memory will
+ be freed and all other function besided Init will be inoperative.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _number_of_entries = 0;
+}
diff --git a/private/utils/ufat/src/makefile b/private/utils/ufat/src/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/ufat/src/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/ufat/src/makefile.inc b/private/utils/ufat/src/makefile.inc
new file mode 100644
index 000000000..b1477410c
--- /dev/null
+++ b/private/utils/ufat/src/makefile.inc
@@ -0,0 +1,14 @@
+{}.cxx{obj\i386\}.obj:
+ $(386_COMPILER) -Fo$@ $(MAKEDIR)\$(<F)
+
+{}.cxx{obj\mips\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClMips $< " $(C_COMPILER) "
+ @$(C_COMPILER) -Fo$@ $(MAKEDIR)\$<
+
+{}.cxx{obj\alpha\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClAlpha $< " $(ALPHA_COMPILER) "
+ @$(ALPHA_COMPILER) -Fo$@ $(MAKEDIR)\$<
+
+dummy:
diff --git a/private/utils/ufat/src/mrcf.c b/private/utils/ufat/src/mrcf.c
new file mode 100644
index 000000000..39816b175
--- /dev/null
+++ b/private/utils/ufat/src/mrcf.c
@@ -0,0 +1,1726 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ Mrcf.c
+
+Abstract:
+
+ This module implements the Compress routines for the Double Space File System
+
+Author:
+
+ Gary Kimura [GaryKi] 26-May-1993
+
+Revision History:
+
+--*/
+
+#include <stdio.h>
+#include <nt.h>
+#include "mrcf.h"
+
+//XXX.mjb:
+#define DbgAssert(x) /* nothing */
+
+//
+// The debug macros
+//
+
+#ifdef MRCFDBG
+
+#define DbgDoit(X) {X;}
+#define ChPrint(b) (isprint(b) ? b : '.')
+#define DbgPrint printf
+
+#else
+
+#define DbgDoit(X) {NOTHING;}
+
+#endif // MRCFDBG
+
+
+//
+// Compress this much before each EOS
+//
+
+#define cbCOMPRESSCHUNK (512)
+
+//
+// Maximum back-pointer value, also used to indicate end of compressed stream!
+//
+
+#define wBACKPOINTERMAX (4415)
+
+//
+// bitsEND_OF_STREAM - bits that mark end of compressed stream (EOS)
+//
+// This pattern is used to indicate the end of a "chunk" in a compressed
+// data stream. The Compress code compresses up to 512 bytes, writes
+// this pattern, and continues.
+//
+// NOTE: This diagram is interpreted right to left.
+//
+// ? ---offset----
+//
+// ?.111-1111-1111-1.1.11
+//
+// \---7F---/ \----FF---/
+//
+// This is a 12-bit "match" code with a maximum offset.
+// NOTE: There is no length component!
+//
+// Define the EOS and also say how many bits it is.
+//
+
+#define bitsEND_OF_STREAM (0x7FFF)
+#define cbitsEND_OF_STREAM (15)
+
+//
+// MDSIGNATURE - Signature at start of each compressed block
+//
+// This 4-byte signature is used as a check to ensure that we
+// are decompressing data we compressed, and also to indicate
+// which compression method was used.
+//
+// NOTE: A compressed block consists of one or more "chunks", separated
+// by the bitsEND_OF_STREAM pattern.
+//
+// Byte Word
+// ----------- ---------
+// 0 1 2 3 0 1 Meaning
+// -- -- -- -- ---- ---- ----------------
+// 44 53 00 01 5344 0100 MaxCompression
+// 44 53 00 02 5344 0200 StandardCompression
+//
+// NOTE: The *WORD* values are listed to be clear about the
+// byte ordering!
+//
+
+typedef struct _MDSIGNATURE {
+
+ //
+ // Must be MD_STAMP
+ //
+
+ USHORT sigStamp;
+
+ //
+ // mdsSTANDARD or mdsMAX
+ //
+
+ USHORT sigType;
+
+} MDSIGNATURE;
+typedef MDSIGNATURE *PMDSIGNATURE;
+
+#define MD_STAMP 0x5344 // Signature stamp at start of compressed blk
+#define mdsSTANDARD 0x0200 // StandardCompressed block
+#define MASK_VALID_mds 0x0300 // All other bits must be zero
+
+
+//
+// Local procedure declarations and macros
+//
+
+#define min(a,b) (a < b ? a : b)
+
+//
+// PFNFINDMATCH - Lookup function type for XxxxCompression routines
+//
+
+typedef ULONG (*PFNFINDMATCH) (
+ ULONG UncompressedIndex,
+ PUCHAR UncompressedBuffer,
+ ULONG UncompressedLength,
+ PULONG MatchedStringIndex,
+ PMRCF_STANDARD_COMPRESS WorkSpace
+ );
+
+//
+// Local procedure prototypes
+//
+
+ULONG
+MrcfDoCompress (
+ PUCHAR CompressedBuffer,
+ ULONG CompressedLength,
+ PUCHAR UncompressedBuffer,
+ ULONG UncompressedLength,
+ PFNFINDMATCH FindMatchFunction,
+ PMRCF_STANDARD_COMPRESS WorkSpace
+ );
+
+ULONG
+MrcfCompressChunk (
+ PUCHAR UncompressedBuffer,
+ ULONG UncompressedIndex,
+ ULONG UncompressedLength,
+ PFNFINDMATCH FindMatchFunction,
+ PMRCF_STANDARD_COMPRESS WorkSpace
+ );
+
+ULONG
+MrcfFindMatchStandard (
+ ULONG UncompressedIndex,
+ PUCHAR UncompressedBuffer,
+ ULONG UncompressedLength,
+ PULONG MatchedStringIndex,
+ PMRCF_STANDARD_COMPRESS WorkSpace
+ );
+
+ULONG
+MrcfGetMatchLength (
+ PUCHAR UncompressedBuffer,
+ ULONG MatchIndex,
+ ULONG CurrentIndex,
+ ULONG UncompressedLength
+ );
+
+BOOLEAN
+MrcfEncodeByte (
+ UCHAR b,
+ PMRCF_BIT_IO BitIo
+ );
+
+BOOLEAN
+MrcfEncodeMatch (
+ ULONG off,
+ ULONG cb,
+ PMRCF_BIT_IO BitIo
+ );
+
+VOID
+MrcfSetBitBuffer (
+ PUCHAR pb,
+ ULONG cb,
+ PMRCF_BIT_IO BitIo
+ );
+
+VOID
+MrcfFillBitBuffer (
+ PMRCF_BIT_IO BitIo
+ );
+
+USHORT
+MrcfReadBit (
+ PMRCF_BIT_IO BitIo
+ );
+
+USHORT
+MrcfReadNBits (
+ LONG cbits,
+ PMRCF_BIT_IO BitIo
+ );
+
+BOOLEAN
+MrcfWriteBit (
+ ULONG bit,
+ PMRCF_BIT_IO BitIo
+ );
+
+BOOLEAN
+MrcfWriteNBits (
+ ULONG abits,
+ LONG cbits,
+ PMRCF_BIT_IO BitIo
+ );
+
+ULONG
+MrcfFlushBitBuffer (
+ PMRCF_BIT_IO BitIo
+ );
+
+//**** unconverted routines ****
+
+VOID
+MrcfDoInterMaxPairs (
+ ULONG ibU,
+ PUCHAR pbU,
+ ULONG cbMatch,
+ PVOID WorkSpace
+ );
+
+ULONG
+MrcfDoMaxPairLookup (
+ ULONG ibU,
+ PUCHAR pbU,
+ PVOID WorkSpace
+ );
+
+ULONG
+MrcfFindMatchMax (
+ ULONG ibU,
+ PUCHAR pbU,
+ ULONG cbU,
+ PULONG piPrev,
+ BOOLEAN fLast,
+ PVOID WorkSpace
+ );
+
+
+ULONG
+MrcfDecompress (
+ PUCHAR UncompressedBuffer,
+ ULONG UncompressedLength,
+ PUCHAR CompressedBuffer,
+ ULONG CompressedLength,
+ PMRCF_DECOMPRESS WorkSpace
+ )
+
+/*++
+
+Routine Description:
+
+ This routine decompresses a buffer of StandardCompressed or MaxCompressed
+ data.
+
+Arguments:
+
+ UncompressedBuffer - buffer to receive uncompressed data
+
+ UncompressedLength - length of UncompressedBuffer
+
+ NOTE: UncompressedLength must be the EXACT length of the uncompressed
+ data, as Decompress uses this information to detect
+ when decompression is complete. If this value is
+ incorrect, Decompress may crash!
+
+ CompressedBuffer - buffer containing compressed data
+
+ CompressedLength - length of CompressedBuffer
+
+ WorkSpace - pointer to a private work area for use by this operation
+
+Return Value:
+
+ ULONG - Returns the size of the decompressed data in bytes. Returns 0 if
+ there was an error in the decompress.
+
+--*/
+
+{
+ ULONG cbMatch; // Length of match string
+ ULONG i; // Index in UncompressedBuffer to receive decoded data
+ ULONG iMatch; // Index in UncompressedBuffer of matched string
+ ULONG k; // Number of bits in length string
+ ULONG off; // Offset from i in UncompressedBuffer of match string
+ USHORT x; // Current bit being examined
+ ULONG y;
+
+ //
+ // verify that compressed data starts with proper signature
+ //
+
+ if (CompressedLength < sizeof(MDSIGNATURE) || // Must have signature
+ ((PMDSIGNATURE)CompressedBuffer)->sigStamp != MD_STAMP || // Stamp must be OK
+ ((PMDSIGNATURE)CompressedBuffer)->sigType & (~MASK_VALID_mds)) { // Type must be OK
+
+ return 0;
+ }
+
+ //
+ // Skip over the valid signature
+ //
+
+ CompressedLength -= sizeof(MDSIGNATURE);
+ CompressedBuffer += sizeof(MDSIGNATURE);
+
+ //
+ // Set up for decompress, start filling UncompressedBuffer at front
+ //
+
+ i = 0;
+
+ //
+ // Set statics to save parm passing
+ //
+
+ MrcfSetBitBuffer(CompressedBuffer,CompressedLength,&WorkSpace->BitIo);
+
+ while (TRUE) {
+
+ DbgDoit( DbgPrint("UncompressedOffset i = %3x ",i) );
+ DbgDoit( DbgPrint("CompressedOffset = (%3x.%2x) ", WorkSpace->BitIo.cbBBInitial - WorkSpace->BitIo.cbBB, 16 - WorkSpace->BitIo.cbitsBB) );
+
+ y = MrcfReadNBits(2,&WorkSpace->BitIo);
+
+ //
+ // Check if next 7 bits are a byte
+ // 1 if 128..255 (0x80..0xff), 2 if 0..127 (0x00..0x7f)
+ //
+
+ if (y == 1 || y == 2) {
+
+ DbgAssert(i<UncompressedLength);
+
+ UncompressedBuffer[i] = (UCHAR)((y == 1 ? 0x80 : 0) | MrcfReadNBits(7,&WorkSpace->BitIo));
+
+ DbgDoit( DbgPrint("byte: %02x = '%c'\n",(USHORT)UncompressedBuffer[i],ChPrint(UncompressedBuffer[i])) );
+
+ i++;
+
+ } else {
+
+ //
+ // Have match sequence
+ //
+
+ DbgDoit( DbgPrint("offset(") );
+
+ //
+ // Get the offset
+ //
+
+ if (y == 0) {
+
+ //
+ // next 6 bits are offset
+ //
+
+ off = MrcfReadNBits(6,&WorkSpace->BitIo);
+
+ DbgDoit( DbgPrint("%x): %x",6,off) );
+
+ DbgAssert(off != 0);
+
+ } else {
+
+ x = MrcfReadBit(&WorkSpace->BitIo);
+
+ if (x == 0) {
+
+ //
+ // next 8 bits are offset-64 (0x40)
+ //
+
+ off = MrcfReadNBits(8, &WorkSpace->BitIo) + 64;
+
+ DbgDoit( DbgPrint("%x): %x",8,off) );
+
+ } else {
+
+ //
+ // next 12 bits are offset-320 (0x140)
+ //
+
+ off = MrcfReadNBits(12, &WorkSpace->BitIo) + 320;
+
+ DbgDoit( DbgPrint("%x): %x",12,off) );
+
+ if (off == wBACKPOINTERMAX) {
+
+ //
+ // EOS marker
+ //
+
+ DbgDoit( DbgPrint("; EOS\n") );
+
+ if (i >= UncompressedLength) {
+
+ //
+ // Done with entire buffer
+ //
+
+ DbgDoit( DbgPrint("Uncompressed Length = %x\n",i) );
+
+ return i;
+
+ } else {
+
+ //
+ // More to do
+ // Done with a 512-byte chunk
+ //
+
+ continue;
+ }
+ }
+ }
+ }
+
+ DbgAssert(i<UncompressedLength);
+ DbgAssert(off <= i);
+
+ //
+ // Get the length - logarithmically encoded
+ //
+
+ for (k=0; (x=MrcfReadBit(&WorkSpace->BitIo)) == 0; k++) { NOTHING; }
+
+ DbgAssert(k <= 8);
+
+ if (k == 0) {
+
+ //
+ // All matches at least 2 chars long
+ //
+
+ cbMatch = 2;
+
+ } else {
+
+ cbMatch = (1 << k) + 1 + MrcfReadNBits(k, &WorkSpace->BitIo);
+ }
+
+ DbgDoit( DbgPrint("; length=%x; '",cbMatch) );
+
+ DbgAssert((i - off + cbMatch - 1) <= UncompressedLength);
+
+ //
+ // Copy the matched string
+ //
+
+ iMatch = i - off;
+
+ while ( (cbMatch > 0) && (i<UncompressedLength) ) {
+
+ DbgDoit( DbgPrint("%c",ChPrint(UncompressedBuffer[iMatch])) );
+
+ UncompressedBuffer[i++] = UncompressedBuffer[iMatch++];
+ cbMatch--;
+ }
+
+ DbgDoit( DbgPrint("'\n") );
+
+ DbgAssert(cbMatch == 0);
+ }
+ }
+}
+
+
+ULONG
+MrcfStandardCompress (
+ PUCHAR CompressedBuffer,
+ ULONG CompressedLength,
+ PUCHAR UncompressedBuffer,
+ ULONG UncompressedLength,
+ PMRCF_STANDARD_COMPRESS WorkSpace
+ )
+
+/*++
+
+Routine Description:
+
+ This routine compresses a buffer using the standard compression algorithm.
+
+Arguments:
+
+ CompressedBuffer - buffer to receive compressed data
+
+ CompressedLength - length of CompressedBuffer
+
+ UncompressedBuffer - buffer containing uncompressed data
+
+ UncompressedLength - length of UncompressedBuffer
+
+ WorkSpace - pointer to a private work area for use by this operation
+
+Return Value:
+
+ ULONG - Returns the size of the compressed data in bytes. Returns 0 if
+ the data is not compressible
+
+--*/
+
+{
+ ULONG i,j;
+
+ //
+ // Fill lookup tables with initial values
+ //
+
+ for (i=0; i<256; i++) {
+
+ for (j = 0; j < cMAXSLOTS; j++) {
+
+ WorkSpace->ltX[i][j] = ltUNUSED; // Mark offset look-up entries unused
+ WorkSpace->abChar[i][j] = bRARE; // Mark match char entries unused
+ }
+
+ WorkSpace->abMRUX[i] = mruUNUSED; // MRU pointer = unused
+ }
+
+ //
+ // Do compression, first set type and then do the compression
+ //
+
+ ((PMDSIGNATURE)CompressedBuffer)->sigType = mdsSTANDARD;
+
+ return MrcfDoCompress( CompressedBuffer,
+ CompressedLength,
+ UncompressedBuffer,
+ UncompressedLength,
+ MrcfFindMatchStandard,
+ WorkSpace );
+}
+
+
+//
+// Internal Support Routine
+//
+
+ULONG
+MrcfDoCompress (
+ PUCHAR CompressedBuffer,
+ ULONG CompressedLength,
+ PUCHAR UncompressedBuffer,
+ ULONG UncompressedLength,
+ PFNFINDMATCH FindMatchFunction,
+ PMRCF_STANDARD_COMPRESS WorkSpace
+ )
+
+/*++
+
+Routine Description:
+
+ This routine compresses a data buffer
+
+Arguments:
+
+ CompressedBuffer - buffer to receive compressed data
+
+ CompressedLength - length of CompressedBuffer
+
+ UncompressedBuffer - buffer containing uncompressed data
+
+ UncompressedLength - length of UncompressedBuffer
+
+ FindMatchFunction - matching function
+
+ WorkSpace - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ ULONG - Returns the size of the compressed data in bytes. Returns 0 if
+ the data is not compressible
+
+--*/
+
+{
+ ULONG cbDone; // Count of uncompressed bytes processed so far
+ ULONG cb; // Count of bytes processed in a chunk
+
+ DbgAssert(CompressedLength >= UncompressedLength);
+
+ //
+ // Treat zero-length request specially as Not compressible
+ //
+
+ if (UncompressedLength == 0) { return 0; }
+
+ //
+ // Write signature to compressed data block
+ //
+
+ ((PMDSIGNATURE)CompressedBuffer)->sigStamp = MD_STAMP;
+
+ CompressedLength -= sizeof(MDSIGNATURE);
+ CompressedBuffer += sizeof(MDSIGNATURE);
+
+ //
+ // Set statics to save parm passing
+ //
+
+ MrcfSetBitBuffer(CompressedBuffer, CompressedLength, &WorkSpace->BitIo);
+
+ //
+ // Start with first chunk
+ // and process entire buffer
+ //
+
+ cbDone = 0;
+
+ while (cbDone < UncompressedLength) {
+
+ //
+ // Compress a chunk
+ //
+
+ cb = MrcfCompressChunk( UncompressedBuffer,
+ cbDone,
+ UncompressedLength,
+ FindMatchFunction,
+ WorkSpace );
+
+ //
+ // Check if we could not compress, i.e., Not compressible
+ //
+
+ if (cb == 0) { return 0; }
+
+ cbDone += cb;
+
+ if (FALSE) { //**** if (WorkSpace->fMaxCmp) {
+
+ //
+ // MAXCMP check
+ //
+
+ if ((cbDone < UncompressedLength) && (WorkSpace->BitIo.cbBB < 586)) { return 0; }
+
+ } else {
+
+ //
+ // RCOMP check
+ //
+
+ //**** if (WorkSpace->BitIo.cbBB <= 586) { return 0; }
+ }
+ }
+
+ DbgAssert(cbDone == UncompressedLength);
+
+ //
+ // Make sure we saved some space
+ //
+
+ cb = sizeof(MDSIGNATURE) + MrcfFlushBitBuffer( &WorkSpace->BitIo );
+
+ if (TRUE) { //**** if (!WorkSpace->fMaxCmp) {
+
+ if (cb+8 >= UncompressedLength) { return 0; }
+ }
+
+ if (cb < UncompressedLength) {
+
+ return cb;
+
+ } else {
+
+ return 0;
+ }
+}
+
+
+//
+// Internal Support Routine
+//
+
+ULONG
+MrcfCompressChunk (
+ PUCHAR UncompressedBuffer,
+ ULONG UncompressedIndex,
+ ULONG UncompressedLength,
+ PFNFINDMATCH FindMatchFunction,
+ PMRCF_STANDARD_COMPRESS WorkSpace
+ )
+
+/*++
+
+Routine Description:
+
+ This routine compresses a chunk of uncompressed data
+
+Arguments:
+
+ UncompressedBuffer - buffer containing uncompressed data
+
+ UncompressedIndex - index in UncompressedBuffer to start compressing (0 => first byte)
+
+ UncompressedLength - length of UncompressedBuffer
+
+ FindMatchFunction - matching function
+
+ WorkSpace - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ ULONG - Returns the non-zero count of uncompressed bytes processed.
+ Returns 0 if the data is not compressible
+
+--*/
+
+{
+ UCHAR b1; // First byte of pair
+ UCHAR b2; // Second byte of pair
+ ULONG cbChunk; // Count of bytes in chunk to compress
+ ULONG cbMatch; // Count of bytes matched
+ ULONG cbUChunk; // Phony buffer length, for compressing this chunk
+ BOOLEAN fLast; // TRUE if this is the last chunk
+ ULONG i; // Index in byte stream being compressed
+ ULONG iPrev; // Previous table entry
+
+ DbgAssert(UncompressedLength > 0);
+ DbgAssert(UncompressedBuffer != 0);
+ DbgAssert(UncompressedIndex < UncompressedLength);
+
+ //
+ // Only compress one chunk
+ //
+
+ cbChunk = min((UncompressedLength-UncompressedIndex),cbCOMPRESSCHUNK);
+
+ //
+ // Limit to chunk length
+ //
+
+ cbUChunk = UncompressedIndex + cbChunk;
+
+ DbgAssert(cbUChunk <= UncompressedLength);
+
+ //
+ // TRUE if last chunk of buffer
+ //
+
+ fLast = (cbUChunk == UncompressedLength);
+
+ //
+ // Limit to chunk length
+ //
+
+ UncompressedLength = cbUChunk;
+
+ //
+ // Scan each pair of bytes
+ //
+
+ //
+ // First byte of input
+ //
+
+ b2 = UncompressedBuffer[UncompressedIndex];
+
+ //
+ // Process all bytes in chunk
+ //
+
+ for (i=UncompressedIndex+1; i<UncompressedLength; ) {
+
+ //
+ // Set Last byte, Next byte, and find a match
+ //
+
+ b1 = b2;
+ b2 = UncompressedBuffer[i];
+
+ cbMatch = (*FindMatchFunction)(i,UncompressedBuffer,UncompressedLength,&iPrev,WorkSpace);
+
+ //
+ // Check if we got match
+ //
+
+ if (cbMatch >= 2) {
+
+ DbgDoit( DbgPrint("<Match>: '%c%c' at offset %x for length %x\n",
+ ChPrint(UncompressedBuffer[i-1]),ChPrint(UncompressedBuffer[i]),i-1, cbMatch) );
+
+ //
+ // Pass offset and length, and check for failure (i.e., data incompressible)
+ //
+
+ if (!MrcfEncodeMatch(i-iPrev,cbMatch,&WorkSpace->BitIo)) {
+
+ return 0;
+ }
+
+ //
+ // Now we have to continue with the first pair of bytes
+ // after the string we matched: mmmmmmm12
+ //
+
+ //
+ // i is index of 2nd byte after match!
+ //
+
+ i += cbMatch;
+
+ //
+ // Check if at least 1 byte still to compress, if so
+ // get 1st byte after match, for loop, otherwise put out EOS
+ //
+
+ if (i <= UncompressedLength) {
+
+ b2 = UncompressedBuffer[i-1];
+
+ } else {
+
+ goto WriteEOS;
+ }
+
+ } else {
+
+ //
+ // No match found, Store one byte and continue, and check
+ // for failure (i.e., data incompressible)
+ //
+
+ if (!MrcfEncodeByte(b1,&WorkSpace->BitIo)) {
+ return 0;
+ }
+
+ //
+ // Advance to next byte
+ //
+
+ i++;
+ }
+ }
+
+ //
+ // Store last byte, and again check for failure
+ //
+
+ if (!MrcfEncodeByte(b2,&WorkSpace->BitIo)) {
+
+ return 0;
+ }
+
+WriteEOS:
+
+ //
+ // write out EOS, and check for failure otherwise return how much
+ // data we processed
+ //
+
+ if (!MrcfWriteNBits( bitsEND_OF_STREAM,
+ cbitsEND_OF_STREAM,
+ &WorkSpace->BitIo )) {
+
+ return 0;
+
+ } else {
+
+ return cbChunk;
+ }
+}
+
+
+//
+// Internal Support Routine
+//
+
+ULONG
+MrcfFindMatchStandard (
+ ULONG UncompressedIndex,
+ PUCHAR UncompressedBuffer,
+ ULONG UncompressedLength,
+ PULONG MatchedStringIndex,
+ PMRCF_STANDARD_COMPRESS WorkSpace
+ )
+
+/*++
+
+Routine Description:
+
+ This routine does a standard compression lookup
+
+Arguments:
+
+ UncompressedIndex - index into UncompressedBuffer[] of *2nd* byte of pair to match
+
+ UncompressedBuffer - buffer containing uncompressed data
+
+ UncompressedLength - length of UncompressedBuffer
+
+ MatchedStringIndex - pointer to int to receive index of start of matched string
+
+ WorkSpace - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ ULONG - Returns length of match. If the return value is >= 2 then
+ *MatchedStringIndex = index of matched string (*2nd* byte in pair).
+ Otherwise the match length is 0 or 1
+
+--*/
+
+{
+ ULONG i;
+ ULONG iMRU;
+ ULONG iChar;
+ ULONG iPrev;
+
+ //
+ // Are there exactly two bytes left? If so then do not check for match.
+ //
+
+ if (UncompressedIndex == (UncompressedLength-1)) { return 0; }
+
+ //
+ // 1st char is index to look-up tables
+ //
+
+ iChar = UncompressedBuffer[UncompressedIndex-1];
+
+ //
+ // Can't match if 1st MRU ent is unused
+ //
+
+ if (WorkSpace->abMRUX[iChar] != mruUNUSED) {
+
+ for (i = 0; i < cMAXSLOTS; i++) {
+
+ if (WorkSpace->abChar[iChar][i] == UncompressedBuffer[UncompressedIndex]) {
+
+ iPrev = WorkSpace->ltX[iChar][i];
+ WorkSpace->ltX[iChar][i] = UncompressedIndex;
+
+ if ((UncompressedIndex - iPrev) >= wBACKPOINTERMAX) { return 0; }
+
+ *MatchedStringIndex = iPrev;
+
+ return MrcfGetMatchLength( UncompressedBuffer,
+ iPrev,
+ UncompressedIndex,
+ UncompressedLength );
+ }
+ }
+ }
+
+ //
+ // Cycle MRU index for char
+ // Update char match table
+ // Location of this char pair
+ //
+
+ iMRU = (WorkSpace->abMRUX[iChar] += 1) & (cMAXSLOTS - 1);
+ WorkSpace->abChar[iChar][iMRU] = UncompressedBuffer[UncompressedIndex];
+ WorkSpace->ltX[iChar][iMRU] = UncompressedIndex;
+
+ return 0;
+}
+
+
+//
+// Internal Support Routine
+//
+
+ULONG
+MrcfGetMatchLength (
+ PUCHAR UncompressedBuffer,
+ ULONG MatchIndex,
+ ULONG CurrentIndex,
+ ULONG UncompressedLength
+ )
+
+/*++
+
+Routine Description:
+
+ Find length of matching strings
+
+Arguments:
+
+ UncompressedBuffer - uncompressed data buffer
+
+ MatchIndex - index of 2nd byte in UncompressedBuffer of match (MatchIndex < CurrentIndex)
+
+ CurrentIndex - index of 2nd byte in UncompressedBuffer that is being compressed
+
+ UncompressedLength - length of UncompressedBuffer
+
+Return Value:
+
+ ULONG - Returns length of matching strings (0, or 2 or greater)
+
+--*/
+
+{
+ ULONG cb;
+
+ DbgAssert(MatchIndex >= 0);
+ DbgAssert(MatchIndex < CurrentIndex);
+ DbgAssert(CurrentIndex < UncompressedLength);
+
+ //
+ // Point back to start of both strings
+ //
+
+ MatchIndex--;
+ CurrentIndex--;
+
+ //
+ // No bytes matched, yet
+ //
+
+ cb = 0;
+
+ //
+ // Scan for end of match, or end of buffer
+ //
+
+ while ((CurrentIndex<UncompressedLength) && (UncompressedBuffer[MatchIndex] == UncompressedBuffer[CurrentIndex])) {
+
+ MatchIndex++;
+ CurrentIndex++;
+ cb++;
+ }
+
+ return cb;
+}
+
+
+//
+// Internal Support Routine
+//
+
+BOOLEAN
+MrcfEncodeByte (
+ UCHAR b,
+ PMRCF_BIT_IO BitIo
+ )
+
+/*++
+
+Routine Description:
+
+ Write one byte to compressed bit stream
+
+Arguments:
+
+ b - byte to write
+
+ BitIo - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ BOOLEAN - TRUE if the bit stream was updated and FALSE if overran buffer
+
+--*/
+
+{
+ ULONG abits;
+
+ DbgDoit( DbgPrint("<MrcfEncodeByte>: byte=%02x '%c'\n",b,ChPrint(b)) );
+
+ abits = ((b & 0x7F) << 2) | ((b < 128) ? 2 : 1);
+
+ //
+ // Write to bitstream
+ //
+
+ return MrcfWriteNBits(abits, 9, BitIo);
+}
+
+
+//
+// Internal Support Routine
+//
+
+BOOLEAN
+MrcfEncodeMatch (
+ ULONG off,
+ ULONG cb,
+ PMRCF_BIT_IO BitIo
+ )
+
+/*++
+
+Routine Description:
+
+ Write a match to compressed bit stream
+
+Arguments:
+
+ off - offset of match (must be greater than 0)
+
+ cb - length of match (must be at least 2)
+
+ BitIo - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ BOOLEAN - TRUE if the compress stream was updated and FALSE if overran buffer
+
+--*/
+
+{
+ ULONG abits;
+ ULONG cbits;
+ ULONG cbSave;
+ ULONG mask;
+
+ DbgAssert(off > 0);
+ DbgAssert(off < wBACKPOINTERMAX);
+ DbgAssert(cb >= 2);
+
+ DbgDoit( DbgPrint("<MrcfEncodeMatch>: off=%x len=%x\n",off,cb) );
+
+ //
+ // Encode the match bits and offset portion
+ //
+
+ if (off < 64) {
+
+ //
+ // Use 6-bit offset encoding
+ //
+
+ abits = (off << 2) | 0x0; // .00 = <offset>+<6-bit>+<match>
+
+ if (!MrcfWriteNBits(abits,6+2,BitIo)) {
+
+ //
+ // Opps overran the compression buffer
+ //
+
+ return FALSE;
+ }
+
+ } else if (off < 320) {
+
+ //
+ // Use 8-bit offset encoding
+ //
+
+ abits = ((off - 64) << 3) | 0x3; // 0.11 = <offset>+<8-bit>+<match>
+
+ if (!MrcfWriteNBits(abits,8+3,BitIo)) {
+
+ //
+ // Opps overran the compression buffer
+ //
+
+ return FALSE;
+ }
+
+ } else { // (off >= 320)
+
+ //
+ // Use 12-bit offset encoding
+ //
+
+ abits = ((off - 320) << 3) | 0x7; // 1.11 = <offset>+<12-bit>+<match>
+
+ if (!MrcfWriteNBits(abits,12+3,BitIo)) {
+
+ //
+ // Opps overran the compression buffer
+ //
+
+ return FALSE;
+ }
+ }
+
+ //
+ // Encode the length logarithmically
+ //
+
+ cb -= 1;
+ cbSave = cb; // Save to get remainder later
+ cbits = 0;
+
+ while (cb > 1) {
+
+ cbits++;
+
+ //
+ // Put out another 0 for the length, and
+ // watch for buffer overflow
+ //
+
+ if (!MrcfWriteBit(0, BitIo)) {
+
+ return FALSE;
+ }
+
+ //
+ // Shift count right (avoid sign bit)
+ //
+
+ ((USHORT)cb) >>= 1;
+ }
+
+ //
+ // Terminate length bit string
+ //
+
+ if (!MrcfWriteBit(1, BitIo)) {
+
+ return FALSE;
+ }
+
+ if (cbits > 0) {
+
+ //
+ // Mask for bits we want, and get remainder
+ //
+
+ mask = (1 << cbits) - 1;
+ abits = cbSave & mask;
+
+ if (!MrcfWriteNBits(abits,cbits,BitIo)) {
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+//
+// Internal Support Routine
+//
+
+VOID
+MrcfSetBitBuffer (
+ PUCHAR pb,
+ ULONG cb,
+ PMRCF_BIT_IO BitIo
+ )
+
+/*++
+
+Routine Description:
+
+ Set statics with coded buffer pointer and length
+
+Arguments:
+
+ pb - pointer to compressed data buffer
+
+ cb - length of compressed data buffer
+
+ BitIo - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ BitIo->pbBB = pb;
+ BitIo->cbBB = cb;
+ BitIo->cbBBInitial = cb;
+ BitIo->cbitsBB = 0;
+ BitIo->abitsBB = 0;
+}
+
+
+//
+// Internal Support Routine
+//
+
+VOID
+MrcfFillBitBuffer (
+ PMRCF_BIT_IO BitIo
+ )
+
+/*++
+
+Routine Description:
+
+ Fill abitsBB from static bit buffer
+
+Arguments:
+
+ BitIo - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DbgAssert((BitIo->cbitsBB) == 0);
+
+ switch (BitIo->cbBB) {
+
+ case 0:
+
+ DbgAssert(FALSE);
+
+ break;
+
+ case 1:
+
+ //
+ // Get last byte and adjust count
+ //
+
+ BitIo->cbitsBB = 8;
+ BitIo->abitsBB = *(BitIo->pbBB)++;
+ BitIo->cbBB--;
+
+ break;
+
+ default:
+
+ //
+ // Get word and adjust count
+ //
+
+ BitIo->cbitsBB = 16;
+ BitIo->abitsBB = *((USHORT *)(BitIo->pbBB))++;
+ BitIo->cbBB -= 2;
+
+ break;
+ }
+}
+
+
+//
+// Internal Support Routine
+//
+
+USHORT
+MrcfReadBit (
+ PMRCF_BIT_IO BitIo
+ )
+
+/*++
+
+Routine Description:
+
+ Get next bit from bit buffer
+
+Arguments:
+
+ BitIo - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ USHORT - Returns next bit (0 or 1)
+
+--*/
+
+{
+ USHORT bit;
+
+ //
+ // Check if no bits available
+ //
+
+ if ((BitIo->cbitsBB) == 0) {
+
+ MrcfFillBitBuffer(BitIo);
+ }
+
+ //
+ // Decrement the bit count
+ // get the bit, remove it, and return the bit
+ //
+
+ (BitIo->cbitsBB)--;
+ bit = (BitIo->abitsBB) & 1;
+ (BitIo->abitsBB) >>= 1;
+
+ return bit;
+}
+
+
+//
+// Internal Support Routine
+//
+
+USHORT
+MrcfReadNBits (
+ LONG cbits,
+ PMRCF_BIT_IO BitIo
+ )
+
+/*++
+
+Routine Description:
+
+ Get next N bits from bit buffer
+
+Arguments:
+
+ cbits - count of bits to get
+
+ BitIo - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ USHORT - Returns next cbits bits.
+
+--*/
+
+{
+ ULONG abits; // Bits to return
+ LONG cbitsPart; // Partial count of bits
+ ULONG cshift; // Shift count
+ ULONG mask; // Mask
+
+ //
+ // Largest number of bits we should read at one time is 12 bits for
+ // a 12-bit offset. The largest length field component that we
+ // read is 8 bits. If this routine were used for some other purpose,
+ // it can support up to 15 (NOT 16) bit reads, due to how the masking
+ // code works.
+ //
+
+ DbgAssert(cbits <= 12);
+
+ //
+ // No shift and no bits yet
+ //
+
+ cshift = 0;
+ abits = 0;
+
+ while (cbits > 0) {
+
+ //
+ // If not bits available get some bits
+ //
+
+ if ((BitIo->cbitsBB) == 0) {
+
+ MrcfFillBitBuffer(BitIo);
+ }
+
+ //
+ // Number of bits we can read
+ //
+
+ cbitsPart = min((BitIo->cbitsBB), cbits);
+
+ //
+ // Mask for bits we want, extract and store them
+ //
+
+ mask = (1 << cbitsPart) - 1;
+ abits |= ((BitIo->abitsBB) & mask) << cshift;
+
+ //
+ // Remember the next chunk of bits
+ //
+
+ cshift = cbitsPart;
+
+ //
+ // Update bit buffer, move remaining bits down and
+ // update count of bits left
+ //
+
+ (BitIo->abitsBB) >>= cbitsPart;
+ (BitIo->cbitsBB) -= cbitsPart;
+
+ //
+ // Update count of bits left to read
+ //
+
+ cbits -= cbitsPart;
+ }
+
+ //
+ // Return requested bits
+ //
+
+ return (USHORT)abits;
+}
+
+
+//
+// Internal Support Routine
+//
+
+BOOLEAN
+MrcfWriteBit (
+ ULONG bit,
+ PMRCF_BIT_IO BitIo
+ )
+
+/*++
+
+Routine Description:
+
+ Write a bit to the bit buffer
+
+Arguments:
+
+ bit - bit to write (0 or 1)
+ BitIo - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ BOOLEAN - returns TRUE if the compresed bit stream was updated and
+ FALSE if overran buffer.
+
+--*/
+
+{
+ DbgAssert((bit == 0) || (bit == 1));
+ DbgAssert((BitIo->cbitsBB) < 16);
+
+ DbgDoit( DbgPrint("<MrcfWriteBit>: bit=%x\n",bit) );
+
+ //
+ // Write one bit
+ //
+
+ (BitIo->abitsBB) |= bit << (BitIo->cbitsBB);
+ (BitIo->cbitsBB)++;
+
+ //
+ // Check if abitsBB is full and write compressed data buffer
+ //
+
+ if ((BitIo->cbitsBB) >= 16) {
+
+ return (MrcfFlushBitBuffer(BitIo) != 0);
+
+ } else {
+
+ return TRUE;
+ }
+}
+
+
+//
+// Internal Support Routine
+//
+
+BOOLEAN
+MrcfWriteNBits (
+ ULONG abits,
+ LONG cbits,
+ PMRCF_BIT_IO BitIo
+ )
+
+/*++
+
+Routine Description:
+
+ Write N bits to the bit buffer
+
+Arguments:
+
+ abits - bits to write
+
+ cbits - count of bits write
+
+ BitIo - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ BOOLEAN - returns TRUE if the compressed bit stream was updated and
+ FALSE if overran buffer
+
+--*/
+
+{
+ LONG cbitsPart;
+ ULONG mask;
+
+ DbgAssert(cbits > 0);
+ DbgAssert(cbits <= 16);
+ DbgAssert((BitIo->cbitsBB) < 16);
+
+ DbgDoit( DbgPrint("<MrcfWriteNBits>: bits=%04x count=%x\n",abits,cbits) );
+
+ while (cbits > 0) {
+
+ //
+ // Number of bits we can write
+ //
+
+ cbitsPart = min(16-(BitIo->cbitsBB), cbits);
+
+ mask = (1 << cbitsPart) - 1;
+
+ //
+ // Move part of bits to buffer
+ //
+
+ (BitIo->abitsBB) |= (abits & mask) << (BitIo->cbitsBB);
+
+ //
+ // Update count of bits written
+ //
+
+ (BitIo->cbitsBB) += cbitsPart;
+
+ //
+ // Check if buffer if full
+ //
+
+ if ((BitIo->cbitsBB) >= 16) {
+
+ //
+ // Write compressed data buffer
+ //
+
+ if (!MrcfFlushBitBuffer(BitIo)) {
+
+ return FALSE;
+ }
+ }
+
+ //
+ // Reduce number of bits left to write and move remaining bits over
+ //
+
+ cbits -= cbitsPart;
+ abits >>= cbitsPart;
+ }
+
+ return TRUE;
+}
+
+
+//
+// Internal Support Routine
+//
+
+ULONG
+MrcfFlushBitBuffer (
+ PMRCF_BIT_IO BitIo
+ )
+
+/*++
+
+Routine Description:
+
+ Write remaining bits to compressed data buffer
+
+Arguments:
+
+ BitIo - Supplies a pointer to the bit buffer statics
+
+Return Value:
+
+ ULONG - Returns total count of bytes written to the compressed data
+ buffer since the last call to MrcfSetBitBuffer(). Returns 0 if
+ overran buffer
+
+--*/
+
+{
+ DbgAssert((BitIo->cbitsBB) >= 0);
+ DbgAssert((BitIo->cbitsBB) <= 16);
+
+ //
+ // Move bits to the compressed data buffer
+ //
+
+ while ((BitIo->cbitsBB) > 0) {
+
+ //
+ // Process low and high half.
+ // Check if output buffer is out of room
+ //
+
+ if ((BitIo->cbBB) == 0) { return 0; }
+
+ //
+ // Store a byte, adjust the count, get high half, nd adjust
+ // count of bits remaining
+ //
+
+ *(BitIo->pbBB)++ = (UCHAR)((BitIo->abitsBB) & 0xFF);
+ (BitIo->cbBB)--;
+ (BitIo->abitsBB) >>= 8;
+ (BitIo->cbitsBB) -= 8;
+ }
+
+ //
+ // Reset bit buffer, "abitsBB >>= 8" guarantees abitsBB is clear
+ //
+
+ DbgAssert((BitIo->abitsBB) == 0);
+
+ (BitIo->cbitsBB) = 0;
+
+ return (BitIo->cbBBInitial)-(BitIo->cbBB);
+}
+
diff --git a/private/utils/ufat/src/pch.cxx b/private/utils/ufat/src/pch.cxx
new file mode 100644
index 000000000..39dee60df
--- /dev/null
+++ b/private/utils/ufat/src/pch.cxx
@@ -0,0 +1,36 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ pch.cxx
+
+Abstract:
+
+ This module is a precompiled header for ufat.
+
+Author:
+
+ Matthew Bradburn (mattbr) 01-Feb-1994
+
+--*/
+
+#define _NTAPI_ULIB_
+#define _UFAT_MEMBER_
+
+#include "ulib.hxx"
+#include "ufat.hxx"
+
+#include "cluster.hxx"
+#include "eaheader.hxx"
+#include "easet.hxx"
+#include "fat.hxx"
+#include "fatdent.hxx"
+#include "fatdir.hxx"
+#include "fatsa.hxx"
+#include "fatvol.hxx"
+#include "filedir.hxx"
+#include "reloclus.hxx"
+#include "rfatsa.hxx"
+#include "rootdir.hxx"
diff --git a/private/utils/ufat/src/reloclus.cxx b/private/utils/ufat/src/reloclus.cxx
new file mode 100644
index 000000000..79e79cc35
--- /dev/null
+++ b/private/utils/ufat/src/reloclus.cxx
@@ -0,0 +1,124 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ reloclus.cxx
+
+Abstract:
+
+ This module contains the definition of the RELOCATION_CLUSTER class.
+
+Author:
+
+ Ramon J. San Andres (ramonsa) 05-Nov-1991
+
+
+--*/
+
+#include <pch.cxx>
+
+
+
+DEFINE_CONSTRUCTOR( RELOCATION_CLUSTER, OBJECT );
+
+DEFINE_CAST_MEMBER_FUNCTION( RELOCATION_CLUSTER );
+
+
+
+
+RELOCATION_CLUSTER::~RELOCATION_CLUSTER (
+ )
+
+/*++
+
+Routine Description:
+
+ Destructor for the RELOCATION_CLUSTER object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+}
+
+
+
+BOOLEAN
+RELOCATION_CLUSTER::Initialize (
+ IN USHORT Cluster
+ )
+/*++
+
+Routine Description:
+
+ Initializes a relocation cluster
+
+Arguments:
+
+ Cluster - Supplies the cluster number
+
+Return Value:
+
+ BOOLEAN - TRUE
+
+--*/
+{
+ _Cluster = Cluster;
+
+ return TRUE;
+}
+
+
+
+
+LONG
+RELOCATION_CLUSTER::Compare (
+ IN PCOBJECT Object
+ ) CONST
+/*++
+
+Routine Description:
+
+ Compares this relocation cluster against another object
+
+Arguments:
+
+ Object - Supplies pointer to other object
+
+Return Value:
+
+ LONG - See Compare in OBJECT
+
+--*/
+{
+ PRELOCATION_CLUSTER OtherCluster;
+
+ DebugPtrAssert( Object );
+
+ //
+ // If the other object is a relocation cluster, we do the comparison,
+ // otherwise we let someone else do it.
+ //
+ if ( OtherCluster = RELOCATION_CLUSTER::Cast( Object ) ) {
+
+ if ( _Cluster < OtherCluster->QueryClusterNumber() ) {
+ return -1;
+ } else if ( _Cluster == OtherCluster->QueryClusterNumber() ) {
+ return 0;
+ } else {
+ return 1;
+ }
+ } else {
+
+ return OBJECT::Compare( Object );
+ }
+}
diff --git a/private/utils/ufat/src/rfatsa.cxx b/private/utils/ufat/src/rfatsa.cxx
new file mode 100644
index 000000000..c3eeca7ba
--- /dev/null
+++ b/private/utils/ufat/src/rfatsa.cxx
@@ -0,0 +1,1789 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ fatsa.cxx
+
+Author:
+
+ Mark Shavlik (marks) 27-Mar-90
+ Norbert Kusters (norbertk) 15-Jan-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _UFAT_MEMBER_
+#include "ufat.hxx"
+
+#include "cmem.hxx"
+#include "error.hxx"
+#include "rtmsg.h"
+#include "drive.hxx"
+#include "bpb.hxx"
+#include "bitvect.hxx"
+
+extern "C" {
+ #include <stdio.h>
+}
+
+extern UCHAR FatBootCode[512];
+
+#if !defined(_AUTOCHECK_) && !defined(_SETUP_LOADER_)
+#include "timeinfo.hxx"
+#endif
+
+
+// Control-C handling is not necessary for autocheck.
+#if !defined( _AUTOCHECK_ ) && !defined(_SETUP_LOADER_)
+
+#include "keyboard.hxx"
+
+#endif
+
+
+#define CSEC_FAT32MEG 65536
+#define CSEC_FAT16BIT 32680
+
+#define MIN_CLUS_BIG 4085 // Minimum clusters for a big FAT.
+#define MAX_CLUS_BIG 65525 // Maximum + 1 clusters for big FAT.
+
+#define sigSUPERSEC1 (UCHAR)0x55 // signature first byte
+#define sigSUPERSEC2 (UCHAR)0xAA // signature second byte
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( REAL_FAT_SA, FAT_SA, UFAT_EXPORT );
+
+BOOLEAN
+REAL_FAT_SA::DosSaInit(
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN SECTORCOUNT NumberOfSectors,
+ IN OUT PMESSAGE Message
+ )
+{
+ if (!SUPERAREA::Initialize(Mem, Drive, NumberOfSectors, Message)) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ _sector_sig = (UCHAR *)SECRUN::GetBuf() + 510;
+
+ return TRUE;
+}
+
+
+BOOLEAN
+REAL_FAT_SA::DosSaSetBpb(
+ )
+{
+#if defined _SETUP_LOADER_
+ return FALSE;
+#else
+ ULONG Sec32Meg; // num sectors in 32mb
+
+ DebugAssert(_drive);
+ DebugAssert(_drive->QuerySectors().GetHighPart() == 0);
+ DebugAssert(_drive->QueryHiddenSectors().GetHighPart() == 0);
+
+ _sector_zero.Bpb.BytesPerSector = (USHORT)_drive->QuerySectorSize();
+
+ Sec32Meg = (32<<20) / _drive->QuerySectorSize();
+
+ if (_drive->QuerySectors() >= Sec32Meg) {
+ // >= 32Mb -- set BPB for large partition
+
+ _sector_zero.Bpb.Sectors = 0;
+ _sector_zero.Bpb.LargeSectors = _drive->QuerySectors().GetLowPart();
+ } else {
+ // Size of DOS0 partition is < 32Mb
+ _sector_zero.Bpb.Sectors = (USHORT)_drive->QuerySectors().GetLowPart();
+ _sector_zero.Bpb.LargeSectors = 0;
+ }
+ _sector_zero.Bpb.Media = _drive->QueryMediaByte();
+ _sector_zero.Bpb.SectorsPerTrack = (USHORT)_drive->QuerySectorsPerTrack();
+ _sector_zero.Bpb.Heads = (USHORT)_drive->QueryHeads();
+ _sector_zero.Bpb.HiddenSectors = _drive->QueryHiddenSectors().GetLowPart();
+
+ return TRUE;
+#endif // _SETUP_LOADER_
+}
+
+VOID
+REAL_FAT_SA::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Constructor for FAT_SA.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _fat = NULL;
+ _dir = NULL;
+ _StartDataLbn = 0;
+ _ClusterCount = 0;
+ _sysid = SYSID_NONE;
+}
+
+
+UFAT_EXPORT
+REAL_FAT_SA::~REAL_FAT_SA(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for REAL_FAT_SA.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+UFAT_EXPORT
+BOOLEAN
+REAL_FAT_SA::Initialize(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Formatted
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the FAT super area to an initial state. It
+ does so by first reading in the boot sector and verifying it with
+ the methods of DOS_SUPERAREA. Upon computing the super area's actual size,
+ the underlying SECRUN will be set to the correct size.
+
+ If the super area does not already exist on disk, then the other Init
+ function should be called.
+
+Arguments:
+
+ Drive - Supplies the drive where the super area resides.
+ Message - Supplies an outlet for messages
+ Formatted - Supplies a boolean which indicates whether or not
+ the volume is formatted.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ SECTORCOUNT sectors;
+ CONT_MEM cmem;
+ SECTORCOUNT reserved;
+ SECTORCOUNT sec_per_fat;
+ ULONG num_fats;
+ SECTORCOUNT sec_per_root;
+ ULONG root_entries;
+ ULONG sector_size;
+
+ Destroy();
+
+ _sec_per_boot = max(1, BYTES_PER_BOOT_SECTOR/Drive->QuerySectorSize());
+
+ if (!Formatted) {
+ return _mem.Initialize() &&
+ DosSaInit(&_mem, Drive, _sec_per_boot, Message);
+ }
+
+ if (!Drive ||
+ !(sector_size = Drive->QuerySectorSize()) ||
+ !_mem.Initialize() ||
+ !DosSaInit(&_mem, Drive, _sec_per_boot, Message) ||
+ !SECRUN::Read()) {
+ Message->Set(MSG_CANT_READ_BOOT_SECTOR);
+ Message->Display("");
+ Destroy();
+ return FALSE;
+ }
+
+ UnpackExtendedBios(&_sector_zero,
+ (PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK)SECRUN::GetBuf());
+
+ if (!VerifyBootSector() || !_sector_zero.Bpb.Fats) {
+ Destroy();
+ return FALSE;
+ }
+
+ reserved = _sector_zero.Bpb.ReservedSectors;
+ sec_per_fat = _sector_zero.Bpb.SectorsPerFat;
+ num_fats = _sector_zero.Bpb.Fats;
+ root_entries = _sector_zero.Bpb.RootEntries;
+ sec_per_root = (root_entries*BytesPerDirent - 1)/sector_size + 1;
+
+ _StartDataLbn = ComputeStartDataLbn();
+
+ sectors = QueryVirtualSectors() - _StartDataLbn;
+ _ClusterCount = (USHORT) (sectors/QuerySectorsPerCluster() +
+ FirstDiskCluster);
+
+ _ft = (_ClusterCount >= 4087) ? LARGE : SMALL;
+
+ if (_ft == SMALL) {
+ _sysid = SYSID_FAT12BIT;
+ } else if (QueryVirtualSectors() < CSEC_FAT32MEG) {
+ _sysid = SYSID_FAT16BIT;
+ } else {
+ _sysid = SYSID_FAT32MEG;
+ }
+
+ if (!_mem.Initialize() ||
+ !DosSaInit(&_mem, Drive, _StartDataLbn, Message)) {
+ Destroy();
+ return FALSE;
+ }
+
+ if (!(_dir = NEW ROOTDIR)) {
+ Destroy();
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!cmem.Initialize((PCHAR) SECRUN::GetBuf() +
+ (reserved + sec_per_fat*num_fats)*sector_size,
+ sec_per_root*sector_size) ||
+ !_dir->Initialize(&cmem, Drive, reserved + sec_per_fat*num_fats,
+ root_entries)) {
+ Destroy();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+REAL_FAT_SA::CreateBootSector(
+ IN ULONG ClusterSize
+ )
+/*++
+
+Routine Description:
+
+ This routine updates fields in sector 0.
+
+Arguments:
+
+ ClusterSize - Supplies the desired number of bytes per cluster.
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure.
+
+--*/
+{
+#if defined _SETUP_LOADER_
+
+ return FALSE;
+
+#else
+
+ SetVolId(ComputeVolId());
+
+ return SetBpb(ClusterSize) &&
+ SetBootCode() &&
+ SetPhysicalDriveType(_drive->IsRemovable() ?
+ PHYS_REMOVABLE : PHYS_FIXED) &&
+ SetOemData() &&
+ SetSignature();
+
+#endif // _SETUP_LOADER_
+}
+
+BOOLEAN
+REAL_FAT_SA::SetBpb(
+ IN ULONG ClusterSize
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the BPB for the FAT file system.
+
+Arguments:
+
+ ClusterSize - Supplies the desired number of bytes per cluster.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+#if defined( _SETUP_LOADER_ )
+
+ return FALSE;
+
+#else // _SETUP_LOADER_
+
+ SECTORCOUNT sectors;
+ ULONG sector_size;
+ USHORT sec_per_clus, alt_spc;
+
+ if (!DosSaSetBpb()) {
+ DebugPrint("Could not do a DOS_SUPERAREA::SetBpb.\n");
+ return FALSE;
+ }
+
+ DebugAssert(_drive->QuerySectors().GetHighPart() == 0);
+
+ sectors = _drive->QuerySectors().GetLowPart();
+ sector_size = _drive->QuerySectorSize();
+
+ _ft = ComputeFatType();
+
+ _sector_zero.Bpb.RootEntries = ComputeRootEntries();
+ sec_per_clus = ComputeSecClus(sectors, _ft, _drive->QueryMediaType());
+
+ if (sec_per_clus > MaxSecPerClus) {
+ DebugAssert("Disk too large\n");
+ return FALSE;
+ }
+
+ alt_spc = (USHORT)(ClusterSize / sector_size);
+ if (alt_spc > MaxSecPerClus) {
+ alt_spc = MaxSecPerClus;
+ }
+
+ if (alt_spc > sec_per_clus) {
+ sec_per_clus = alt_spc;
+ }
+
+ _sector_zero.Bpb.SectorsPerCluster = (UCHAR) sec_per_clus;
+ _sector_zero.Bpb.ReservedSectors = (USHORT)_sec_per_boot;
+ _sector_zero.Bpb.Fats = 2;
+
+ // Formula for computing sectors per fat borrowed from fdisk.
+ if (_ft == SMALL) {
+ _sector_zero.Bpb.SectorsPerFat = (USHORT) (sectors/
+ (2 + sector_size*sec_per_clus*2/3));
+ } else {
+ _sector_zero.Bpb.SectorsPerFat = (USHORT) (sectors/
+ (2 + sector_size*sec_per_clus/2));
+ }
+ _sector_zero.Bpb.SectorsPerFat++;
+
+ if (_ft == SMALL) {
+ memcpy(_sector_zero.SystemIdText, "FAT12 ", cSYSID);
+ } else {
+ memcpy(_sector_zero.SystemIdText, "FAT16 ", cSYSID);
+ }
+
+ memcpy(_sector_zero.Label, "NO NAME ", cLABEL);
+
+ _sector_zero.CurrentHead = 0;
+
+ return TRUE;
+
+#endif // _SETUP_LOADER_
+}
+
+BOOLEAN
+REAL_FAT_SA::SetBpb(
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the BPB for the FAT file system.
+
+Arguments:
+
+ None:
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ return SetBpb(0);
+}
+
+BOOLEAN
+REAL_FAT_SA::Create(
+ IN PCNUMBER_SET BadSectors,
+ IN OUT PMESSAGE Message,
+ IN PCWSTRING Label,
+ IN ULONG ClusterSize,
+ IN ULONG VirtualSize
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the FAT file system.
+
+Arguments:
+
+ BadSectors - Supplies a list of the bad sectors on the volume.
+ Message - Supplies an outlet for messages.
+ Label - Supplies an optional label.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+#if defined( _SETUP_LOADER_ )
+
+ return FALSE;
+
+#else
+
+ USHORT sector_size;
+ SECTORCOUNT sec_per_root;
+ CONT_MEM cmem;
+ HMEM hmem;
+ SECRUN secrun;
+ SECRUN small_secrun;
+ PUSHORT p;
+ USHORT cluster_count;
+ ULONG cluster_size;
+ LBN lbn;
+ ULONG i;
+ DSTRING label;
+ USHORT free_count;
+ USHORT bad_count;
+ PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK
+ SourceBootSector, TargetBootSector;
+ ULONG BootCodeOffset;
+ ULONG allocation_size;
+
+
+ if (!CreateBootSector(ClusterSize)) {
+ return FALSE;
+ }
+
+ // calculate the actual cluster size
+ allocation_size = _sector_zero.Bpb.SectorsPerCluster *
+ _drive->QuerySectorSize();
+ if (ClusterSize && allocation_size != ClusterSize) {
+ // Issue a warning to the user
+ Message->Set(MSG_FMT_ALLOCATION_SIZE_CHANGED);
+ Message->Display("%d", allocation_size);
+ }
+
+ if (!_drive ||
+ !(sector_size = (USHORT) _drive->QuerySectorSize()) ||
+ (_sysid = ComputeSystemId()) == SYSID_NONE) {
+ return FALSE;
+ }
+
+ sec_per_root = (_sector_zero.Bpb.RootEntries*BytesPerDirent - 1)/
+ sector_size + 1;
+
+ _StartDataLbn = _sector_zero.Bpb.ReservedSectors +
+ _sector_zero.Bpb.Fats*_sector_zero.Bpb.SectorsPerFat +
+ sec_per_root;
+
+ if (_drive->QuerySectors().GetHighPart() != 0) {
+ // This should be checked before calling this procedure.
+ DebugAbort("Number of sectors exceeds 32 bits");
+ return FALSE;
+ }
+
+ _ClusterCount = (USHORT) (FirstDiskCluster +
+ (_drive->QuerySectors().GetLowPart() - _StartDataLbn)/
+ QuerySectorsPerCluster());
+
+ if (!_mem.Initialize() ||
+ !DosSaInit(&_mem, _drive, _StartDataLbn, Message)) {
+ return FALSE;
+ }
+
+ // Zero fill the super area.
+ memset(_mem.GetBuf(), 0, (UINT) _mem.QuerySize());
+
+ //
+ // Make sure the disk is not write-protected.
+ //
+
+ if (!_drive->Write(0, 1, _mem.GetBuf())) {
+ if (_drive->QueryLastNtStatus() == STATUS_MEDIA_WRITE_PROTECTED) {
+ Message->Set(MSG_FMT_WRITE_PROTECTED_MEDIA);
+ } else {
+ Message->Set(MSG_UNUSABLE_DISK);
+ }
+ Message->Display("");
+ return FALSE;
+ }
+
+ // Create the super area.
+ if (!CreateBootSector(ClusterSize)) {
+ return FALSE;
+ }
+
+ if (!SetSystemId()) {
+ Message->Set(MSG_WRITE_PARTITION_TABLE);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!cmem.Initialize((PCHAR) SECRUN::GetBuf() +
+ _sector_zero.Bpb.ReservedSectors*sector_size,
+ _sector_zero.Bpb.SectorsPerFat*sector_size)) {
+ return FALSE;
+ }
+
+ // These "Hidden Status" messages are a hack to allow WinDisk to
+ // cancel a quick format, which ordinarily doesn't send any status
+ // messages, but which might take a while and for which there is a
+ // cancel button. When using format.com, no message will be displayed
+ // for this.
+
+ Message->Set(MSG_HIDDEN_STATUS, NORMAL_MESSAGE, 0);
+ if (!Message->Display()) {
+ return FALSE;
+ }
+
+ // Create the FAT.
+ DELETE(_fat);
+ if (!(_fat = NEW FAT)) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!_fat->Initialize(&cmem, _drive, _sector_zero.Bpb.ReservedSectors,
+ _ClusterCount)) {
+ return FALSE;
+ }
+
+ if (!cmem.Initialize((PCHAR) SECRUN::GetBuf() +
+ (_sector_zero.Bpb.ReservedSectors +
+ _sector_zero.Bpb.Fats*_sector_zero.Bpb.SectorsPerFat)*
+ sector_size, sec_per_root*sector_size)) {
+ return FALSE;
+ }
+
+ DELETE(_dir);
+ if (!(_dir = NEW ROOTDIR)) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!_dir->Initialize(&cmem, _drive, _sector_zero.Bpb.ReservedSectors +
+ _sector_zero.Bpb.Fats*_sector_zero.Bpb.SectorsPerFat,
+ _sector_zero.Bpb.RootEntries)) {
+ return FALSE;
+ }
+
+ _fat->SetEarlyEntries(_sector_zero.Bpb.Media);
+
+ Message->Set(MSG_HIDDEN_STATUS, NORMAL_MESSAGE, 0);
+ if (!Message->Display()) {
+ return FALSE;
+ }
+
+ for (i = 0; i < BadSectors->QueryCardinality(); i++) {
+ if ((lbn = BadSectors->QueryNumber(i).GetLowPart()) < _StartDataLbn) {
+ Message->Set(MSG_UNUSABLE_DISK);
+ Message->Display("");
+ return FALSE;
+ } else {
+ _fat->SetClusterBad((USHORT) ((lbn - _StartDataLbn)/
+ QuerySectorsPerCluster()) +
+ FirstDiskCluster );
+ }
+ }
+
+ Message->Set(MSG_FORMAT_COMPLETE);
+ Message->Display("");
+
+ if (_drive->QueryMediaType() != F5_160_512 &&
+ _drive->QueryMediaType() != F5_320_512) {
+
+ if (Label) {
+ if (!label.Initialize(Label)) {
+ return FALSE;
+ }
+ } else {
+ switch (_drive->QueryRecommendedMediaType()) {
+ case F5_360_512:
+ case F5_320_512:
+ case F5_180_512:
+ case F5_160_512:
+ // These disk drives are lame and can't
+ // take the spin down without a verify
+ // so don't prompt for the label.
+ // This will avoid FORMAT failing.
+
+ label.Initialize();
+ break;
+
+ default:
+ Message->Set(MSG_VOLUME_LABEL_PROMPT);
+ Message->Display("");
+ Message->QueryStringInput(&label);
+ break;
+
+ }
+ }
+
+ while (!SetLabel(&label)) {
+
+ Message->Set(MSG_INVALID_LABEL_CHARACTERS);
+ Message->Display("");
+
+ Message->Set(MSG_VOLUME_LABEL_PROMPT);
+ Message->Display("");
+ Message->QueryStringInput(&label);
+ }
+ }
+
+ // Copy the boot code into the secrun's buffer.
+ // This is complicated by the fact that DOS_SA::Write
+ // packs the data from the unpacked boot sector into
+ // the packed boot sector, so we have to set the
+ // first few fields in the unpacked version.
+ //
+ SourceBootSector = (PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK)FatBootCode;
+
+ CopyUchar2(&_sector_zero.BootStrapJumpOffset,
+ SourceBootSector->BootStrapJumpOffset);
+ CopyUchar1(&_sector_zero.IntelNearJumpCommand,
+ SourceBootSector->IntelNearJumpCommand);
+
+ // Copy the remainder of the boot code directly into
+ // the secrun.
+ //
+ TargetBootSector = (PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK)SECRUN::GetBuf();
+
+ BootCodeOffset = FIELD_OFFSET( PACKED_EXTENDED_BIOS_PARAMETER_BLOCK,
+ StartBootCode );
+
+ memcpy( (PUCHAR)TargetBootSector + BootCodeOffset,
+ (PUCHAR)SourceBootSector + BootCodeOffset,
+ sizeof( FatBootCode ) - BootCodeOffset );
+
+ // Finally, write the changes to disk.
+ //
+ if (!Write(Message)) {
+ if (_drive->QueryLastNtStatus() == STATUS_MEDIA_WRITE_PROTECTED) {
+ Message->Set(MSG_FMT_WRITE_PROTECTED_MEDIA);
+ } else {
+ Message->Set(MSG_UNUSABLE_DISK);
+ }
+ Message->Display("");
+ return FALSE;
+ }
+
+ // Print an informative report.
+ //
+ cluster_count = QueryClusterCount() - FirstDiskCluster;
+ cluster_size = sector_size*QuerySectorsPerCluster();
+
+ Message->Set(MSG_TOTAL_DISK_SPACE);
+ Message->Display("%9u", cluster_count*cluster_size);
+
+ if (bad_count = _fat->QueryBadClusters()) {
+ Message->Set(MSG_BAD_SECTORS);
+ Message->Display("%9u", bad_count*cluster_size);
+ }
+
+ free_count = _fat->QueryFreeClusters();
+
+ Message->Set(MSG_AVAILABLE_DISK_SPACE);
+ Message->Display("%9u", free_count*cluster_size);
+
+ Message->Set(MSG_ALLOCATION_UNIT_SIZE);
+ Message->Display("%9u", cluster_size);
+
+ Message->Set(MSG_AVAILABLE_ALLOCATION_UNITS);
+ Message->Display("%9u", free_count);
+
+ if (QueryVolId()) {
+ Message->Set(MSG_BLANK_LINE);
+ Message->Display();
+ p = (PUSHORT) &_sector_zero.SerialNumber;
+ Message->Set(MSG_VOLUME_SERIAL_NUMBER);
+ Message->Display("%04X%04X", p[1], p[0]);
+ }
+
+ return TRUE;
+
+#endif
+}
+
+
+BOOLEAN
+REAL_FAT_SA::RecoverFile(
+ IN PCWSTRING FullPathFileName,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine runs through the clusters for the file described by
+ 'FileName' and takes out bad sectors.
+
+Arguments:
+
+ FullPathFileName - Supplies a full path name of the file to recover.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+#if defined( _SETUP_LOADER_ )
+
+ return FALSE;
+
+#else // _SETUP_LOADER_
+
+
+ HMEM hmem;
+ USHORT clus;
+ BOOLEAN changes;
+ PFATDIR fatdir;
+ BOOLEAN need_delete;
+ FAT_DIRENT dirent;
+ ULONG old_file_size;
+ ULONG new_file_size;
+
+ if ((clus = QueryFileStartingCluster(FullPathFileName,
+ &hmem,
+ &fatdir,
+ &need_delete,
+ &dirent)) == 1) {
+ Message->Set(MSG_FILE_NOT_FOUND);
+ Message->Display("%W", FullPathFileName);
+ return FALSE;
+ }
+
+ if (clus == 0xFFFF) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (clus == 0) {
+ Message->Set(MSG_FILE_NOT_FOUND);
+ Message->Display("%W", FullPathFileName);
+ return FALSE;
+ }
+
+ if (dirent.IsDirectory()) {
+ old_file_size = _drive->QuerySectorSize()*
+ QuerySectorsPerCluster()*
+ _fat->QueryLengthOfChain(clus);
+ } else {
+ old_file_size = dirent.QueryFileSize();
+ }
+
+ if (!RecoverChain(&clus, &changes)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (dirent.IsDirectory() || changes) {
+ new_file_size = _drive->QuerySectorSize()*
+ QuerySectorsPerCluster()*
+ _fat->QueryLengthOfChain(clus);
+ } else {
+ new_file_size = old_file_size;
+ }
+
+ if (changes) {
+
+
+// Autochk doesn't need control C handling.
+#if !defined( _AUTOCHECK_ )
+
+ // Disable contol-C handling and
+
+ if (!KEYBOARD::EnableBreakHandling()) {
+ Message->Set(MSG_CANT_LOCK_THE_DRIVE);
+ Message->Display("");
+ return FALSE;
+ }
+
+#endif
+
+
+ // Lock the drive in preparation for writes.
+
+ if (!_drive->Lock()) {
+ Message->Set(MSG_CANT_LOCK_THE_DRIVE);
+ Message->Display("");
+ return FALSE;
+ }
+
+ dirent.SetStartingCluster(clus);
+
+ dirent.SetFileSize(new_file_size);
+
+ if (!fatdir->Write()) {
+ return FALSE;
+ }
+
+ if (!Write(Message)) {
+ return FALSE;
+ }
+
+
+// Autochk doesn't need control C handling.
+#if !defined( _AUTOCHECK_ )
+
+ KEYBOARD::DisableBreakHandling();
+
+#endif
+
+
+ }
+
+ Message->Set(MSG_RECOV_BYTES_RECOVERED);
+ Message->Display("%d%d", new_file_size, old_file_size);
+
+
+ if (need_delete) {
+ DELETE(fatdir);
+ }
+
+ return TRUE;
+
+#endif // _SETUP_LOADER_
+}
+
+
+UFAT_EXPORT
+BOOLEAN
+REAL_FAT_SA::Read(
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine reads the super area. It will succeed if it can
+ read the boot sector, the root directory, and at least one of
+ the FATs.
+
+ If the position of the internal FAT has not yet been determined,
+ this routine will attempt to map it to a readable FAT on the disk.
+
+Arguments:
+
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ SECRUN secrun;
+ CONT_MEM cmem;
+ LBN fat_lbn;
+ ULONG sector_size;
+ PCHAR fat_pos;
+ SECTORCOUNT sec_per_fat;
+ SECTORCOUNT num_res;
+ ULONG i;
+ PFAT fat;
+
+ if (!SECRUN::Read()) {
+
+ // Check to see if super area was allocated as formatted.
+ if (QueryLength() <= _sec_per_boot) {
+ Message->Set(MSG_CANT_READ_BOOT_SECTOR);
+ Message->Display("");
+ return FALSE;
+ }
+
+ // Check the boot sector.
+ if (!secrun.Initialize(&_mem, _drive, 0, _sec_per_boot) ||
+ !secrun.Read()) {
+ UnpackExtendedBios(&_sector_zero,
+ (PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK)SECRUN::GetBuf());
+ Message->Set(MSG_CANT_READ_BOOT_SECTOR);
+ Message->Display("");
+ return FALSE;
+ }
+
+ // Check the root directory.
+ if (!_dir || !_dir->Read()) {
+ Message->Set(MSG_BAD_DIR_READ);
+ Message->Display("");
+ return FALSE;
+ }
+
+ // Check for one good FAT.
+ if (_fat) {
+ if (!_fat->Read()) {
+ Message->Set(MSG_DISK_ERROR_READING_FAT);
+ Message->Display("%d", 1 +
+ (_fat->QueryStartLbn() - _sector_zero.Bpb.ReservedSectors)/
+ _sector_zero.Bpb.SectorsPerFat);
+ return FALSE;
+ } else {
+ Message->Set(MSG_SOME_FATS_UNREADABLE);
+ Message->Display("");
+ }
+ } else {
+ sector_size = _drive->QuerySectorSize();
+ num_res = _sector_zero.Bpb.ReservedSectors;
+ fat_pos = (PCHAR) SECRUN::GetBuf() + num_res*sector_size;
+ sec_per_fat = _sector_zero.Bpb.SectorsPerFat;
+
+ for (i = 0; i < QueryFats(); i++) {
+
+ fat_lbn = num_res + i*sec_per_fat;
+ if (!cmem.Initialize(fat_pos + i*sec_per_fat*sector_size,
+ sec_per_fat*sector_size)) {
+ return FALSE;
+ }
+
+ if (!(fat = NEW FAT)) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!fat->Initialize(&cmem, _drive, fat_lbn, _ClusterCount)) {
+ return FALSE;
+ }
+
+ if (!fat->Read()) {
+ Message->Set(MSG_DISK_ERROR_READING_FAT);
+ Message->Display("%d", 1 +
+ (fat->QueryStartLbn() - _sector_zero.Bpb.ReservedSectors)/
+ _sector_zero.Bpb.SectorsPerFat);
+ DELETE(fat);
+ }
+
+ if (_fat) {
+ DELETE(fat);
+ } else {
+ _fat = fat;
+ }
+
+ }
+
+ if (!_fat) {
+ Message->Set(MSG_CANT_READ_ANY_FAT);
+ Message->Display("");
+ return FALSE;
+ }
+ }
+
+ } else {
+
+ UnpackExtendedBios(&_sector_zero,
+ (PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK)SECRUN::GetBuf());
+
+ if (!_fat && (QueryLength() > _sec_per_boot)) {
+
+ fat_lbn = _sector_zero.Bpb.ReservedSectors;
+ sector_size = _drive->QuerySectorSize();
+
+
+ if (!cmem.Initialize((PCHAR) SECRUN::GetBuf() + fat_lbn*sector_size,
+ QuerySectorsPerFat()*sector_size)) {
+ return FALSE;
+ }
+
+ if (!(_fat = NEW FAT)) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!_fat->Initialize(&cmem, _drive, fat_lbn, _ClusterCount,
+ QuerySectorsPerFat())) {
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+REAL_FAT_SA::Write(
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine writes the super area. It will succeed if it can
+ write the boot sector, the root directory, and at least one of
+ the FATs.
+
+ This routine will duplicate the working FAT to all other FATs
+ in the super area.
+
+Arguments:
+
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ SECRUN secrun;
+
+ DupFats();
+
+ PackExtendedBios(&_sector_zero,
+ (PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK)SECRUN::GetBuf());
+
+ if (!SECRUN::Write()) {
+ if (!_fat || !_dir) {
+ Message->Set(MSG_CANT_WRITE_BOOT_SECTOR);
+ Message->Display("");
+ return FALSE;
+ }
+
+ PackExtendedBios(&_sector_zero,
+ (PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK)SECRUN::GetBuf());
+
+ if (!secrun.Initialize(&_mem, _drive, 0, _sec_per_boot) ||
+ !secrun.Write()) {
+ Message->Set(MSG_CANT_WRITE_BOOT_SECTOR);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!_dir->Write()) {
+ Message->Set(MSG_CANT_WRITE_ROOT_DIR);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!_fat->Write()) {
+ Message->Set(MSG_BAD_FAT_WRITE);
+ Message->Display("");
+ return FALSE;
+ } else {
+ Message->Set(MSG_SOME_FATS_UNWRITABLE);
+ Message->Display("");
+ }
+ }
+
+ return TRUE;
+}
+
+
+UFAT_EXPORT
+SECTORCOUNT
+REAL_FAT_SA::QueryFreeSectors(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of unused sectors on disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of free sectors on disk.
+
+--*/
+{
+ if (!_fat) {
+ perrstk->push(ERR_NOT_READ, QueryClassId());
+ return 0;
+ }
+
+ return _fat->QueryFreeClusters()*QuerySectorsPerCluster();
+}
+
+
+FATTYPE
+REAL_FAT_SA::QueryFatType(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the FATTYPE of the FAT for this volume.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The FATTYPE for the FAT.
+
+--*/
+{
+ return _ft;
+}
+
+
+VOID
+REAL_FAT_SA::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine cleans up the local data in the fat super area.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DELETE(_fat);
+ DELETE(_dir);
+
+ _StartDataLbn = 0;
+ _ClusterCount = 0;
+ _sysid = SYSID_NONE;
+}
+
+BOOLEAN
+REAL_FAT_SA::DupFats(
+ )
+/*++
+
+Routine Description:
+
+ This routine will duplicate the current FAT to all other FATs
+ in the super area.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG i;
+ PCHAR fat_pos;
+ ULONG fat_size;
+ ULONG sector_size;
+ SECTORCOUNT num_res;
+ SECTORCOUNT sec_per_fat;
+
+ if (!_fat || !_drive || !(sector_size = _drive->QuerySectorSize())) {
+ return FALSE;
+ }
+
+ num_res = _sector_zero.Bpb.ReservedSectors;
+ sec_per_fat = _sector_zero.Bpb.SectorsPerFat;
+ fat_size = sec_per_fat*sector_size;
+ fat_pos = (PCHAR) SECRUN::GetBuf() + num_res*sector_size;
+
+ for (i = 0; i < QueryFats(); i++) {
+ if (num_res + i*sec_per_fat != _fat->QueryStartLbn()) {
+ memcpy(fat_pos + i*fat_size, _fat->GetBuf(), (UINT) fat_size);
+ }
+ }
+
+ return TRUE;
+}
+
+
+LBN
+REAL_FAT_SA::ComputeStartDataLbn(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the first LBN of the data part of a FAT disk.
+ In other words, the LBN of cluster 2.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The LBN of the start of data.
+
+--*/
+{
+ return _sector_zero.Bpb.ReservedSectors +
+ _sector_zero.Bpb.Fats*_sector_zero.Bpb.SectorsPerFat +
+ (_sector_zero.Bpb.RootEntries*BytesPerDirent - 1)/
+ _drive->QuerySectorSize() + 1;
+}
+
+
+#if !defined(_SETUP_LOADER_)
+
+USHORT
+REAL_FAT_SA::ComputeRootEntries(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine uses the size of the disk and a standard table in
+ order to compute the required number of root directory entries.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The required number of root directory entries.
+
+--*/
+{
+ switch (_drive->QueryMediaType()) {
+
+ case F3_720_512:
+ case F5_360_512:
+ case F5_320_512:
+ case F5_320_1024:
+ case F5_180_512:
+ case F5_160_512:
+ return 112;
+
+ case F5_1Pt2_512:
+ case F3_1Pt44_512:
+ return 224;
+
+ case F3_2Pt88_512:
+ case F3_20Pt8_512:
+ return 240;
+ }
+
+ return 512;
+}
+
+
+USHORT
+REAL_FAT_SA::ComputeSecClus(
+ IN SECTORCOUNT Sectors,
+ IN FATTYPE FatType,
+ IN MEDIA_TYPE MediaType
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the number of sectors per cluster required
+ based on the actual number of sectors.
+
+Arguments:
+
+ Sectors - Supplies the total number of sectors on the disk.
+ FatType - Supplies the type of FAT.
+ MediaType - Supplies the type of the media.
+
+Return Value:
+
+ The required number of sectors per cluster.
+
+--*/
+{
+ USHORT sec_per_clus;
+ SECTORCOUNT threshold;
+
+ if (FatType == SMALL) {
+ threshold = MIN_CLUS_BIG;
+ sec_per_clus = 1;
+ } else {
+ threshold = MAX_CLUS_BIG;
+ sec_per_clus = 1;
+ }
+
+ while (Sectors >= threshold) {
+ sec_per_clus *= 2;
+ threshold *= 2;
+ }
+
+ switch (MediaType) {
+
+ case F5_320_512:
+ case F5_360_512:
+ case F3_720_512:
+ case F3_2Pt88_512:
+ sec_per_clus = 2;
+ break;
+
+ case F3_20Pt8_512:
+ sec_per_clus = 4;
+ break;
+
+ default:
+ break;
+
+ }
+
+ return sec_per_clus;
+}
+
+#endif // _SETUP_LOADER_
+
+
+BOOLEAN
+REAL_FAT_SA::RecoverChain(
+ IN OUT PUSHORT StartingCluster,
+ OUT PBOOLEAN ChangesMade,
+ IN USHORT EndingCluster,
+ IN BOOLEAN Replace
+ )
+/*++
+
+Routine Description:
+
+ This routine will recover the chain beginning with 'StartingCluster'
+ in the following way. It will verify the readability of every cluster
+ until it reaches 'EndingCluster' or the end of the chain. If a cluster
+ is not readable then 'ChangesMade' will be set to TRUE, the FAT will
+ be marked to indicate that the cluster is bad, and the cluster will be
+ taken out of the chain. Additionally, if 'Replace' is set to TRUE,
+ the FAT will be scanned for a readable free cluster to replace the lost
+ ones with. Failure to accomplish this will result in a return value
+ of FALSE being returned.
+
+ If the very first cluster of the chain was bad then then
+ 'StartingCluster' will be set with the new starting cluster of the
+ chain even if this starting cluster is past 'EndingCluster'. If the
+ chain is left empty then 'StartingCluster' will be set to zero.
+
+Arguments:
+
+ StartingCluster - Supplies the first cluster of the chain to recover.
+ ChangesMade - Returns TRUE if changes to the chain were made.
+ EndingCluster - Supplies the final cluster to recover.
+ Replace - Supplies whether or not to replace bad clusters with
+ new ones.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ CONST max_transfer_bytes = 65536;
+
+ HMEM hmem;
+ CLUSTER_CHAIN cluster;
+ USHORT clus, prev;
+ USHORT replacement;
+ BOOLEAN finished;
+ USHORT max_clusters;
+ USHORT chain_length;
+ USHORT i;
+
+ DebugAssert(_fat);
+ DebugAssert(ChangesMade);
+ DebugAssert(StartingCluster);
+
+ if (!hmem.Initialize()) {
+ return FALSE;
+ }
+
+ *ChangesMade = FALSE;
+ finished = TRUE;
+
+ max_clusters = (USHORT)(max_transfer_bytes/
+ QuerySectorsPerCluster()/
+ _drive->QuerySectorSize());
+
+ if (!max_clusters) {
+ max_clusters = 1;
+ }
+
+ chain_length = _fat->QueryLengthOfChain(*StartingCluster);
+
+ for (i = 0; i < chain_length; i += max_clusters) {
+
+ if (!cluster.Initialize(&hmem, _drive, this, _fat,
+ _fat->QueryNthCluster(*StartingCluster, i),
+ min(max_clusters, chain_length - i))) {
+
+ return FALSE;
+ }
+
+ if (!cluster.Read()) {
+
+ // Since the quick analysis detected some errors do the slow
+ // analysis to pinpoint them.
+
+ finished = FALSE;
+ break;
+ }
+ }
+
+ prev = 0;
+ clus = *StartingCluster;
+
+ if (!clus) {
+ return TRUE;
+ }
+
+ while (!finished) {
+ if (!cluster.Initialize(&hmem, _drive, this, _fat, clus, 1)) {
+ return FALSE;
+ }
+
+ finished = (BOOLEAN) (_fat->IsEndOfChain(clus) || clus == EndingCluster);
+
+ if (!cluster.Read()) {
+
+ // There is a bad cluster so indicate that changes will be made.
+
+ *ChangesMade = TRUE;
+
+
+ // Take the bad cluster out of the cluster chain.
+
+ if (prev) {
+ _fat->SetEntry(prev, _fat->QueryEntry(clus));
+
+ _fat->SetClusterBad(clus);
+
+ clus = prev;
+ } else {
+ *StartingCluster = _fat->IsEndOfChain(clus) ? 0 :
+ _fat->QueryEntry(clus);
+
+ _fat->SetClusterBad(clus);
+
+ clus = 0;
+ }
+
+
+ // If a replacement cluster is wanted then get one.
+
+ if (Replace) {
+
+ if (!(replacement = _fat->AllocChain(1))) {
+ return FALSE;
+ }
+
+
+ // Zero fill and write the replacement.
+
+ cluster.Initialize(&hmem, _drive, this, _fat, replacement, 1);
+ memset(hmem.GetBuf(), 0, (UINT) hmem.QuerySize());
+ cluster.Write();
+
+
+ if (finished) {
+ EndingCluster = replacement;
+ finished = FALSE;
+ }
+
+
+ // Link in the replacement.
+
+ if (prev) {
+ _fat->InsertChain(replacement, replacement, prev);
+ } else {
+ if (*StartingCluster) {
+ _fat->SetEntry(replacement, *StartingCluster);
+ }
+ *StartingCluster = replacement;
+ }
+ }
+ }
+
+ prev = clus;
+ clus = clus ? _fat->QueryEntry(clus) : *StartingCluster;
+ }
+
+ return TRUE;
+}
+
+ULONG
+REAL_FAT_SA::SecPerBoot()
+{
+ return _sec_per_boot;
+}
+
+BOOLEAN
+REAL_FAT_SA::SetBootCode(
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the boot code in the super area.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ _sector_zero.IntelNearJumpCommand = 0xEB;
+ _sector_zero.BootStrapJumpOffset = 0x903C;
+ SetBootSignature();
+ return TRUE;
+}
+
+BOOLEAN
+REAL_FAT_SA::SetPhysicalDriveType(
+ IN PHYSTYPE PhysType
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the physical drive type in the super area.
+
+Arguments:
+
+ PhysType - Supplies the physical drive type.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ _sector_zero.PhysicalDrive = (UCHAR)PhysType;
+ return TRUE;
+}
+
+INLINE
+BOOLEAN
+REAL_FAT_SA::SetOemData(
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the OEM data in the super area.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ memcpy( (void*)_sector_zero.OemData, (void*)OEMTEXT, OEMTEXTLENGTH);
+ return TRUE;
+}
+
+BOOLEAN
+REAL_FAT_SA::SetSignature(
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the sector zero signature in the super area.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ if (!_sector_sig) {
+ perrstk->push(ERR_NOT_INIT, QueryClassId());
+ return FALSE;
+ }
+
+ *_sector_sig = sigSUPERSEC1;
+ *(_sector_sig + 1) = sigSUPERSEC2;
+
+ return TRUE;
+}
+
+BOOLEAN
+REAL_FAT_SA::VerifyBootSector(
+ )
+/*++
+
+Routine Description:
+
+ This routine checks key parts of sector 0 to insure that the data
+ being examined is indeed a zero sector.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Invalid sector zero.
+ TRUE - Valid sector zero.
+
+--*/
+{
+ PUCHAR p;
+
+// We don't check for 55 AA anymore because we have reason to
+// believe that there are versions of FORMAT out there that
+// don't put it down.
+
+#if 0
+ if (!IsFormatted()) {
+ return FALSE;
+ }
+#endif
+
+ p = (PUCHAR) GetBuf();
+
+ return p[0] == 0xE9 || (p[0] == 0xEB && p[2] == 0x90);
+}
+
+ULONG
+REAL_FAT_SA::QuerySectorFromCluster(
+ IN ULONG Cluster,
+ OUT PUCHAR NumSectors
+ )
+{
+ if (NULL != NumSectors) {
+ *NumSectors = (UCHAR)QuerySectorsPerCluster();
+ }
+
+ return (Cluster - FirstDiskCluster)*QuerySectorsPerCluster() +
+ QueryStartDataLbn();
+}
+
+BOOLEAN
+REAL_FAT_SA::IsClusterCompressed(
+ IN ULONG
+ ) CONST
+{
+ return FALSE;
+}
+
+VOID
+REAL_FAT_SA::SetClusterCompressed(
+ IN ULONG,
+ IN BOOLEAN fCompressed
+ )
+{
+ if (fCompressed)
+ DebugAssert("REAL_FAT_SA shouldn't have compressed clusters.");
+}
+
+UCHAR
+REAL_FAT_SA::QuerySectorsRequiredForPlainData(
+ IN ULONG
+ )
+{
+ DebugAssert("REAL_FAT_SA didn't expect call to QuerySectorsRequiredForPlainData\n");
+ return 0;
+
+}
+
+BOOLEAN
+REAL_FAT_SA::VerifyFatExtensions(
+ FIX_LEVEL, PMESSAGE, PBOOLEAN
+ )
+{
+ //
+ // We have no fat extensions, we're real.
+ //
+
+ return TRUE;
+}
+
+BOOLEAN
+REAL_FAT_SA::CheckSectorHeapAllocation(
+ FIX_LEVEL, PMESSAGE, PBOOLEAN
+ )
+{
+ //
+ // We have no sector heap, we're real.
+ //
+
+ return TRUE;
+}
+
+BOOLEAN
+REAL_FAT_SA::AllocateClusterData(
+ ULONG, UCHAR, BOOLEAN, UCHAR
+ )
+{
+ DebugAbort("Didn't expect REAL_FAT_SA::AllocateClusterData to be "
+ "called.");
+ return FALSE;
+}
+
+BOOLEAN
+REAL_FAT_SA::FreeClusterData(
+ ULONG
+ )
+{
+ DebugAbort("Didn't expect REAL_FAT_SA::FreeClusterData to be "
+ "called.");
+ return FALSE;
+}
diff --git a/private/utils/ufat/src/rootdir.cxx b/private/utils/ufat/src/rootdir.cxx
new file mode 100644
index 000000000..219612bc7
--- /dev/null
+++ b/private/utils/ufat/src/rootdir.cxx
@@ -0,0 +1,133 @@
+#include <pch.cxx>
+
+#define _UFAT_MEMBER_
+#include "ufat.hxx"
+
+#include "error.hxx"
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( ROOTDIR, FATDIR, UFAT_EXPORT );
+
+VOID
+ROOTDIR::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Constructor for ROOTDIR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _number_of_entries = 0;
+}
+
+
+UFAT_EXPORT
+ROOTDIR::~ROOTDIR(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for ROOTDIR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+UFAT_EXPORT
+BOOLEAN
+ROOTDIR::Initialize(
+ IN PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN LBN StartingSector,
+ IN LONG NumberOfEntries
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the ROOTDIR object by specifying a drive,
+ a position and a size.
+
+Arguments:
+
+ Mem - Supplies the memory for the run of sectors.
+ Drive - Supplies the drive where the root directory is.
+ StartingSector - Supplies the starting sector of the root directory.
+ NumberOfEntries - Supplies the number of entries in the root directory.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ LONG sector_size;
+ SECTORCOUNT n;
+
+ Destroy();
+
+ if (!Drive || !(sector_size = Drive->QuerySectorSize())) {
+ perrstk->push(ERR_NOT_INIT, QueryClassId());
+ Destroy();
+ return FALSE;
+ }
+
+ _number_of_entries = NumberOfEntries;
+
+ n = (BytesPerDirent*NumberOfEntries - 1)/sector_size + 1;
+
+ if (!_secrun.Initialize(Mem, Drive, StartingSector, n)) {
+ perrstk->push(ERR_NOT_INIT, QueryClassId());
+ Destroy();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+VOID
+ROOTDIR::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the object to its initial state. Init must be
+ called for this routine to be useful again. This routine will
+ free up memory.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _number_of_entries = 0;
+}
diff --git a/private/utils/ufat/src/sources b/private/utils/ufat/src/sources
new file mode 100644
index 000000000..8442c6844
--- /dev/null
+++ b/private/utils/ufat/src/sources
@@ -0,0 +1,93 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in $(BASEDIR)\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=utils
+MINORCOMP=ufat
+
+TARGETNAME=ufat
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ ..\..\ulib\src\obj\*\ulib.lib \
+ ..\..\ifsutil\src\obj\*\ifsutil.lib
+
+USE_CRTDLL=1
+BLDCRT=1
+
+DLLENTRY=InitializeUfat
+
+PRECOMPILED_INCLUDE= pch.cxx
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=cluster.cxx \
+ eaheader.cxx \
+ easet.cxx \
+ entry.cxx \
+ fat.cxx \
+ fatdent.cxx \
+ fatdir.cxx \
+ fatsa.cxx \
+ fatsachk.cxx \
+ fatsacnv.cxx \
+ fatvol.cxx \
+ filedir.cxx \
+ reloclus.cxx \
+ rfatsa.cxx \
+ rootdir.cxx \
+ ufat.cxx \
+ ufat.rc
+
+DBLSPACE_SOURCES= \
+ cvfexts.cxx \
+ dblentry.cxx \
+ fatdbsa.cxx \
+ mrcf.c \
+ fatdbvol.cxx
+
+INCLUDES=..\inc;..\..\ulib\inc;..\..\ifsutil\inc;$(BASEDIR)\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+CXXFLAGS=+d
+UMLIBS=obj\*\ufat.lib
+
+UMTYPE=console
+
+UMTEST=
+UMRES=obj\*\ufat.res
+
+DLLDEF=ufat.def
diff --git a/private/utils/ufat/src/ufat.cxx b/private/utils/ufat/src/ufat.cxx
new file mode 100644
index 000000000..6d79cba71
--- /dev/null
+++ b/private/utils/ufat/src/ufat.cxx
@@ -0,0 +1,167 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ufat.cxx
+
+Abstract:
+
+ This module contains run-time, global support for the
+ FAT IFS Utilities library (UFAT). This support includes:
+
+ - creation of CLASS_DESCRIPTORs
+ - Global objects
+
+Author:
+
+ Bill McJohn (billmc) 30-May-1991
+
+Environment:
+
+ User Mode
+
+Notes:
+
+--*/
+
+#include <pch.cxx>
+
+#define _UFAT_MEMBER_
+#include "ulib.hxx"
+#include "ufat.hxx"
+
+#include "error.hxx"
+
+#if !defined( _AUTOCHECK_ )
+
+ ERRSTACK* perrstk;
+
+#endif // _AUTOCHECK_
+
+// Local prototypes
+
+STATIC
+BOOLEAN
+DefineClassDescriptors(
+ );
+
+extern "C"
+UFAT_EXPORT
+BOOLEAN
+InitializeUfat (
+ PVOID DllHandle,
+ ULONG Reason,
+ PCONTEXT Context
+ );
+
+UFAT_EXPORT
+BOOLEAN
+InitializeUfat (
+ PVOID DllHandle,
+ ULONG Reason,
+ PCONTEXT Context
+ )
+/*++
+
+Routine Description:
+
+ Initialize Ufat by constructing and initializing all
+ global objects. These include:
+
+ - all CLASS_DESCRIPTORs (class_cd)
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if all global objects were succesfully constructed
+ and initialized.
+
+--*/
+
+{
+
+ STATIC BOOLEAN fInit = FALSE;
+
+ if ( fInit ) {
+
+ return( TRUE );
+ }
+
+ if ( DefineClassDescriptors() ) {
+
+ fInit = TRUE;
+ return TRUE;
+
+ } else {
+
+ DebugAbort( "Ufat initialization failed!!!\n" );
+ return( FALSE );
+ }
+}
+
+
+
+DECLARE_CLASS( CLUSTER_CHAIN );
+DECLARE_CLASS( EA_HEADER );
+DECLARE_CLASS( EA_SET );
+DECLARE_CLASS( FAT );
+DECLARE_CLASS( FATDIR );
+DECLARE_CLASS( FAT_DIRENT );
+DECLARE_CLASS( FAT_SA );
+DECLARE_CLASS( FAT_VOL );
+#ifdef DBLSPACE_ENABLED
+DECLARE_CLASS( FATDB_VOL );
+#endif // DBLSPACE_ENABLED
+DECLARE_CLASS( FILEDIR );
+DECLARE_CLASS( ROOTDIR );
+DECLARE_CLASS( RELOCATION_CLUSTER );
+#ifdef DBLSPACE_ENABLED
+DECLARE_CLASS( CVF_FAT_EXTENS );
+#endif // DBLSPACE_ENABLED
+DECLARE_CLASS( REAL_FAT_SA );
+#ifdef DBLSPACE_ENABLED
+DECLARE_CLASS( FATDB_SA );
+#endif // DBLSPACE_ENABLED
+
+
+STATIC
+BOOLEAN
+DefineClassDescriptors(
+ )
+{
+ if( DEFINE_CLASS_DESCRIPTOR( CLUSTER_CHAIN ) &&
+#ifdef DBLSPACE_ENABLED
+ DEFINE_CLASS_DESCRIPTOR( CVF_FAT_EXTENS ) &&
+#endif // DBLSPACE_ENABLED
+ DEFINE_CLASS_DESCRIPTOR( EA_HEADER ) &&
+ DEFINE_CLASS_DESCRIPTOR( EA_SET ) &&
+ DEFINE_CLASS_DESCRIPTOR( FAT ) &&
+#ifdef DBLSPACE_ENABLED
+ DEFINE_CLASS_DESCRIPTOR( FATDB_SA ) &&
+#endif // DBLSPACE_ENABLED
+ DEFINE_CLASS_DESCRIPTOR( FATDIR ) &&
+ DEFINE_CLASS_DESCRIPTOR( FAT_DIRENT ) &&
+ DEFINE_CLASS_DESCRIPTOR( FAT_SA ) &&
+ DEFINE_CLASS_DESCRIPTOR( FAT_VOL ) &&
+#ifdef DBLSPACE_ENABLED
+ DEFINE_CLASS_DESCRIPTOR( FATDB_VOL ) &&
+#endif // DBLSPACE_ENABLED
+ DEFINE_CLASS_DESCRIPTOR( FILEDIR ) &&
+ DEFINE_CLASS_DESCRIPTOR( RELOCATION_CLUSTER ) &&
+ DEFINE_CLASS_DESCRIPTOR( REAL_FAT_SA ) &&
+ DEFINE_CLASS_DESCRIPTOR( ROOTDIR )
+ ) {
+
+ return TRUE;
+
+ } else {
+
+ DebugPrint( "Could not initialize class descriptors!");
+ return FALSE;
+ }
+}
diff --git a/private/utils/ufat/src/ufat.def b/private/utils/ufat/src/ufat.def
new file mode 100644
index 000000000..94c50360e
--- /dev/null
+++ b/private/utils/ufat/src/ufat.def
@@ -0,0 +1,10 @@
+LIBRARY UFAT
+
+DESCRIPTION File System Utilities for FAT
+
+DATA NONSHARED
+
+EXPORTS
+ Chkdsk
+ Format
+ Recover
diff --git a/private/utils/ufat/src/ufat.rc b/private/utils/ufat/src/ufat.rc
new file mode 100644
index 000000000..de5186a47
--- /dev/null
+++ b/private/utils/ufat/src/ufat.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "FAT Utility DLL"
+#define VER_INTERNALNAME_STR "UFAT"
+#define VER_ORIGINALFILENAME_STR "UFAT.DLL"
+
+#include "common.ver"
diff --git a/private/utils/ufat/src/ufatalph.ded b/private/utils/ufat/src/ufatalph.ded
new file mode 100644
index 000000000..53226b4e4
--- /dev/null
+++ b/private/utils/ufat/src/ufatalph.ded
@@ -0,0 +1,9 @@
+ FatDbCreate
+ FatDbDelete
+ FatDbFormat
+ FatDbChkdsk
+ ??0FATDB_VOL@@QAA@XZ
+ ??1FATDB_VOL@@UAA@XZ
+ ?Initialize@FATDB_VOL@@QAAEPBVWSTRING@@0PAVMESSAGE@@E@Z
+ MrcfDecompress
+ ?SetCvfSectorCount@FATDB_SA@@QAAEK@Z
diff --git a/private/utils/ufat/src/ufatmips.ded b/private/utils/ufat/src/ufatmips.ded
new file mode 100644
index 000000000..4fc3aa9ba
--- /dev/null
+++ b/private/utils/ufat/src/ufatmips.ded
@@ -0,0 +1,9 @@
+ FatDbCreate
+ FatDbDelete
+ FatDbFormat
+ FatDbChkdsk
+ ??0FATDB_VOL@@QAA@XZ
+ ??1FATDB_VOL@@UAA@XZ
+ ?SetCvfSectorCount@FATDB_SA@@QAAEK@Z
+ ?Initialize@FATDB_VOL@@QAAEPBVWSTRING@@0PAVMESSAGE@@E@Z
+ MrcfDecompress
diff --git a/private/utils/ufat/src/ufatppc.ded b/private/utils/ufat/src/ufatppc.ded
new file mode 100644
index 000000000..4fc3aa9ba
--- /dev/null
+++ b/private/utils/ufat/src/ufatppc.ded
@@ -0,0 +1,9 @@
+ FatDbCreate
+ FatDbDelete
+ FatDbFormat
+ FatDbChkdsk
+ ??0FATDB_VOL@@QAA@XZ
+ ??1FATDB_VOL@@UAA@XZ
+ ?SetCvfSectorCount@FATDB_SA@@QAAEK@Z
+ ?Initialize@FATDB_VOL@@QAAEPBVWSTRING@@0PAVMESSAGE@@E@Z
+ MrcfDecompress
diff --git a/private/utils/ufat/src/ufatx86.ded b/private/utils/ufat/src/ufatx86.ded
new file mode 100644
index 000000000..5aceb73fd
--- /dev/null
+++ b/private/utils/ufat/src/ufatx86.ded
@@ -0,0 +1,9 @@
+ FatDbCreate
+ FatDbDelete
+ FatDbFormat
+ FatDbChkdsk
+ ??0FATDB_VOL@@QAE@XZ
+ ??1FATDB_VOL@@UAE@XZ
+ ?Initialize@FATDB_VOL@@QAEEPBVWSTRING@@0PAVMESSAGE@@E@Z
+ ?SetCvfSectorCount@FATDB_SA@@QAEEK@Z
+ _MrcfDecompress@20
diff --git a/private/utils/uhpfs/dirs b/private/utils/uhpfs/dirs
new file mode 100644
index 000000000..c4db5a979
--- /dev/null
+++ b/private/utils/uhpfs/dirs
@@ -0,0 +1,16 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+!ENDIF
+
+DIRS= src
diff --git a/private/utils/uhpfs/hpfsmsgs.txt b/private/utils/uhpfs/hpfsmsgs.txt
new file mode 100644
index 000000000..86ad32229
--- /dev/null
+++ b/private/utils/uhpfs/hpfsmsgs.txt
@@ -0,0 +1,314 @@
+---------- ULIB\SRC\rtmsg.mc next ----------
+791,795d790
+< MessageId=2082 SymbolicName=MSG_HPFS_FORMAT_BAD_SECTOR_SIZE
+< Language=English
+< HPFS will only run on volumes with 512 bytes per sector.
+< .
+<
+806,810d800
+< MessageId=2085 SymbolicName=MSG_HPFS_FORMAT_NO_FLOPPIES
+< Language=English
+< The HPFS file system does not support removable media.
+< .
+<
+888,892d877
+< MessageId=3001 SymbolicName=MSG_CANT_READ_HPFS_ROOT
+< Language=English
+< HPFS partition has unreadable root.
+< .
+<
+1083,1105d1067
+<
+< ;//------------------------------
+< ;//
+< ;// HPFS Chkdsk messages
+< ;//
+< ;//------------------------------
+<
+< MessageId=4001 SymbolicName=MSG_HPFS_CHKDSK_INSUFFICIENT_MEMORY
+< Language=English
+< There is not enough memory available to run CHKDSK.
+< .
+<
+< MessageId=4002 SymbolicName=MSG_HPFS_CHKDSK_INSUFFICIENT_MEMORY_ORPHANS
+< Language=English
+< There is not enough memory to attempt to recover lost data.
+< .
+<
+< MessageId=4003 SymbolicName=MSG_HPFS_CHKDSK_ELEMENTARY_CORRUPTION
+< Language=English
+< The elementary file-system structures are corrupt.
+< CHKDSK cannot check this drive.
+< .
+<
+1116,1286d1077
+< MessageId=4006 SymbolicName=MSG_HPFS_CHKDSK_ALLOCATION_ERROR
+< Language=English
+< CHKDSK fixed an allocation error for the file %1
+< .
+<
+< MessageId=4007 SymbolicName=MSG_HPFS_CHKDSK_DELETE_PATH_AND_FILE
+< Language=English
+< CHKDSK deleted the corrupt file %1\%2
+< .
+<
+< MessageId=4008 SymbolicName=MSG_HPFS_CHKDSK_PATH_AND_FILE
+< Language=English
+< %1\%2
+< .
+<
+< MessageId=4009 SymbolicName=MSG_HPFS_CHKDSK_TRUNCATED_DIRBLK
+< Language=English
+< CHKDSK truncated a corrupt directory block.
+< .
+<
+< MessageId=4010 SymbolicName=MSG_HPFS_CHKDSK_TRUNCATED_EAS
+< Language=English
+< CHKDSK truncated the corrupt Extended Attributes list for %1
+< .
+<
+< MessageId=4011 SymbolicName=MSG_HPFS_CHKDSK_REMOVED_EA
+< Language=English
+< CHKDSK removed a corrupt Extended Attribute from %1
+< .
+<
+< MessageId=4012 SymbolicName=MSG_HPFS_CHKDSK_SORT
+< Language=English
+< CHKDSK found and corrected an organization error
+< in the directory %1
+< .
+<
+< MessageId=4013 SymbolicName=MSG_HPFS_CHKDSK_INSUFF_MEMORY_TO_FIX
+< Language=English
+< There is not enough memory available for CHKDSK to fix the drive.
+< .
+<
+< MessageId=4014 SymbolicName=MSG_HPFS_CHKDSK_UNRESOLVED_HOTFIXES
+< Language=English
+< CHKDSK was not able to resolve all hotfix references on the drive.
+< .
+<
+< MessageId=4015 SymbolicName=MSG_HPFS_CHKDSK_UNRESOLVED_DELETES
+< Language=English
+< CHKDSK was not able to delete all corrupted files.
+< .
+<
+< MessageId=4016 SymbolicName=MSG_HPFS_CHKDSK_UNRESOLVED_SORTS
+< Language=English
+< CHKDSK was not able to sort all badly-ordered directories.
+< .
+<
+< MessageId=4017 SymbolicName=MSG_HPFS_CHKDSK_CANT_WRITE_BITMAP
+< Language=English
+< CHKDSK was not able to write the bitmap.
+< .
+<
+< MessageId=4018 SymbolicName=MSG_HPFS_CHKDSK_ORPHANS_FOUND
+< Language=English
+< CHKDSK found lost data on the disk.
+< .
+<
+< MessageId=4019 SymbolicName=MSG_HPFS_CHKDSK_ORPHANS_NO_MEM
+< Language=English
+< There is not enough memory available to CHKDSK to save lost data.
+< .
+<
+< MessageId=4020 SymbolicName=MSG_HPFS_CHKDSK_ORPHANS_NO_DISK
+< Language=English
+< There is not enough free space on disk to save lost data.
+< .
+<
+< MessageId=4021 SymbolicName=MSG_HPFS_CHKDSK_NO_FOUND_DIR
+< Language=English
+< CHKDSK could not create a directory to hold recovered files.
+< .
+<
+< MessageId=4022 SymbolicName=MSG_HPFS_CHKDSK_FOUND_DIR_NAME
+< Language=English
+< CHKDSK will place recovered files in %1
+< .
+<
+< MessageId=4023 SymbolicName=MSG_HPFS_CHKDSK_ORPHANS_CONSISTENCY
+< Language=English
+< CHKDSK could not ensure the consistency of the recovered files.
+< .
+<
+< MessageId=4024 SymbolicName=MSG_HPFS_CHKDSK_SEARCHING_FOR_ORPHANS
+< Language=English
+< CHKDSK is searching for lost data.
+< .
+<
+< MessageId=4025 SymbolicName=MSG_HPFS_CHKDSK_STATISTICS_TOTAL_SPACE
+< Language=English
+< %1 kilobytes total space.
+< .
+<
+< MessageId=4026 SymbolicName=MSG_HPFS_CHKDSK_STATISTICS_DIRECTORIES
+< Language=English
+< %1 kilobytes are in %2 directories.
+< .
+<
+< MessageId=4027 SymbolicName=MSG_HPFS_CHKDSK_STATISTICS_FILE_DATA
+< Language=English
+< %1 kilobytes are in %2 user files.
+< .
+<
+< MessageId=4028 SymbolicName=MSG_HPFS_CHKDSK_STATISTICS_EAS
+< Language=English
+< %1 kilobytes are in extended attributes.
+< .
+<
+< MessageId=4029 SymbolicName=MSG_HPFS_CHKDSK_STATISTICS_SYSTEM
+< Language=English
+< %1 kilobytes are reserved for system use.
+< .
+<
+< MessageId=4030 SymbolicName=MSG_HPFS_CHKDSK_STATISTICS_BAD
+< Language=English
+< %1 kilobytes are in bad blocks.
+< .
+<
+< MessageId=4031 SymbolicName=MSG_HPFS_CHKDSK_STATISTICS_FREE_SPACE
+< Language=English
+< %1 kilobytes are available for use.
+< .
+<
+< MessageId=4032 SymbolicName=MSG_HPFS_CHKDSK_RECOVERED_DIRECTORY
+< Language=English
+< CHKDSK recovered a lost directory as %1
+< .
+<
+< MessageId=4033 SymbolicName=MSG_HPFS_CHKDSK_RECOVERED_FILE
+< Language=English
+< CHKDSK placed recovered data in the file %1
+< .
+<
+< MessageId=4034 SymbolicName=MSG_HPFS_CHKDSK_ORPHANS_CANT_SAVE
+< Language=English
+< CHKDSK was not able to save all recovered data.
+< .
+<
+< MessageId=4035 SymbolicName=MSG_HPFS_CHKDSK_REMOVED_ACL
+< Language=English
+< CHKDSK removed a corrupt access control list from %1
+< .
+<
+< MessageId=4036 SymbolicName=MSG_HPFS_CHKDSK_ALLOCATION_ERROR_NOT_FIXED
+< Language=English
+< CHKDSK detected an allocation error on the volume.
+< .
+<
+< MessageId=4037 SymbolicName=MSG_HPFS_CHKDSK_ALLOCATION_ERROR_FIXED
+< Language=English
+< CHKDSK detected and fixed an allocation error on the volume.
+< .
+<
+< MessageId=4038 SymbolicName=MSG_HPFS_CHKDSK_WRONG_VERSION
+< Language=English
+< This volume cannot be checked with this version of UHPFS.DLL.
+< .
+<
+< MessageId=4039 SymbolicName=MSG_HPFS_CHKDSK_NO_RECOVER_MODE
+< Language=English
+< Recover mode not supported by HPFS CHKDSK.
+< .
+<
+2505,2517d2295
+<
+< ;//----------------------------------
+< ;//
+< ;// HPFS-specific recover messages
+< ;//
+< ;//----------------------------------
+<
+< MessageId=15201 SymbolicName=MSG_HPFS_RECOVER_DIRECTORY
+< Language=English
+< HPFS Recover does not support recovering directories.
+< .
+<
+<
+4195c3973
+< Converts FAT or HPFS volumes to NTFS.
+---
+> Converts FAT volumes to NTFS.
+4441,4473d4218
+<
+<
+< ;//--------------------------------
+< ;//
+< ;// HPFS-specific Convert methods
+< ;//
+< ;//--------------------------------
+<
+<
+< MessageId=30181 SymbolicName=MSG_CONV_HPFS_NOT_HPFS
+< Language=English
+< This volume is not a valid HPFS volume; it cannot be converted.
+< .
+<
+< MessageId=30182 SymbolicName=MSG_CONV_HPFS_DIRTY_VOLUME
+< Language=English
+< The specified volume is dirty; it cannot be converted. Run
+< CHKDSK /f to correct this problem.
+< .
+<
+< MessageId=30183 SymbolicName=MSG_CONV_HPFS_HOTFIXES_PRESENT
+< Language=English
+< The specified volume has hotfixes; it cannot be converted.
+< Run CHKDSK /f to resolve these references.
+< .
+<
+< MessageId=30184 SymbolicName=MSG_CONV_HPFS_CORRUPT_VOLUME
+< Language=English
+< The file system structures on the specified volume are
+< corrupt; the volume cannot be converted. Run CHKDSK /f
+< to correct this problem.
+< .
+<
+4479,4517d4223
+< MessageId=30186 SymbolicName=MSG_CONV_INCONVERTIBLE_NAME
+< Language=English
+< Convert encountered a name which could not be converted to Unicode
+< in the directory %1.
+< .
+<
+< MessageId=30187 SymbolicName=MSG_CONV_CONSTRUCTING_NAME_TABLE
+< Language=English
+< Constructing name translation table.
+< .
+<
+< MessageId=30188 SymbolicName=MSG_CONV_CANT_WRITE_NAME_TABLE
+< Language=English
+< Convert cannot write the name translation table to disk.
+< .
+<
+< MessageId=30189 SymbolicName=MSG_CONV_CANT_READ_NAME_TABLE
+< Language=English
+< Convert cannot read the name translation table from %1.
+< .
+<
+< MessageId=30190 SymbolicName=MSG_CONV_USE_NAMETABLE
+< Language=English
+< Rerun Convert with the NAMETABLE option.
+< .
+<
+< MessageId=30191 SymbolicName=MSG_CONV_DUPLICATE_NAME
+< Language=English
+< Convert encountered duplicate names in the
+< directory %1.
+< .
+<
+< MessageId=30192 SymbolicName=MSG_CONV_INCONVERTIBLE_NAME_IN_ROOT
+< Language=English
+< Convert encountered a name in the root directory which could not
+< be converted to Unicode.
+< .
+<
+<
+6520,6525d6225
+<
+<
+<
+<
+<
+<
diff --git a/private/utils/uhpfs/inc/alsec.hxx b/private/utils/uhpfs/inc/alsec.hxx
new file mode 100644
index 000000000..da389255b
--- /dev/null
+++ b/private/utils/uhpfs/inc/alsec.hxx
@@ -0,0 +1,209 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ alsec.hxx
+
+Abstract:
+
+ This module contains declarations for the ALSEC object,
+ which models an HPFS Allocation Sector.
+
+Author:
+
+ Bill McJohn (billmc) 01-Dec-1990
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#if !defined(ALSEC_DEFN)
+
+#define ALSEC_DEFN
+
+#include "defer.hxx"
+#include "hmem.hxx"
+#include "secrun.hxx"
+#include "store.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( ALSEC );
+DECLARE_CLASS( DEFERRED_ACTIONS_LIST );
+DECLARE_CLASS( HOTFIXLIST );
+DECLARE_CLASS( HPFS_BITMAP );
+DECLARE_CLASS( HPFS_CENSUS );
+DECLARE_CLASS( HPFS_MAIN_BITMAP );
+DECLARE_CLASS( HPFS_PATH );
+DECLARE_CLASS( HPFS_SA );
+DECLARE_CLASS( HPFS_ORPHANS );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( MESSAGE );
+
+struct _ALSECD { // alsec
+
+ ULONG sig; /* signature for CHKDSK to track */
+ LBN lbnSelf; /* sector number of block itself */
+ LBN lbnRent; /* sector number of parent block */
+ ALSEC_STORE std; // store data
+
+};
+
+DEFINE_TYPE( struct _ALSECD, ALSECD );
+
+class ALSEC : public SECRUN {
+
+ public:
+
+ NONVIRTUAL
+ ALSEC(
+ );
+
+ VIRTUAL
+ ~ALSEC(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN LBN Lbn
+ );
+
+ NONVIRTUAL
+ VOID
+ Create(
+ IN LBN ParentLbn,
+ IN BOOLEAN ParentIsFnode
+ );
+
+ NONVIRTUAL
+ VERIFY_RETURN_CODE
+ VerifyAndFix(
+ IN OUT PHPFS_SA SuperArea,
+ IN OUT PDEFERRED_ACTIONS_LIST DeferredActions,
+ IN OUT PHPFS_PATH CurrentPath,
+ IN LBN ExpectedParent,
+ IN OUT PLBN NextSectorNumber,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN ErrorsDetected,
+ IN BOOLEAN UpdateAllowed DEFAULT FALSE,
+ IN OUT PHPFS_ORPHANS OrphansList DEFAULT NULL,
+ IN BOOLEAN ParentIsFnode DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ScanStorage(
+ IN OUT PULONG NextSectorNumber,
+ IN BOOLEAN ParentIsFnode
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsAlsec(
+ );
+
+ NONVIRTUAL
+ VOID
+ MarkModified(
+ );
+
+ VOID
+ Flush(
+ IN BOOLEAN UpdateAllowed
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FindAndResolveHotfix(
+ IN OUT PHPFS_SA SuperArea,
+ IN DEFERRED_SECTOR_TYPE ChildSectorType
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ResolveCrosslink(
+ IN OUT PHPFS_SA SuperArea,
+ IN ULONG RunIndex
+ );
+
+ NONVIRTUAL
+ VOID
+ SetParent(
+ IN LBN ParentLbn,
+ IN OUT PULONG NextSectorNumber,
+ IN BOOLEAN ParentIsFnode
+ );
+
+ NONVIRTUAL
+ LBN
+ QueryPhysicalLbn(
+ IN LBN FileBlockNumber,
+ OUT PULONG RunLength
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Truncate(
+ IN LBN SectorCount
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryExtents(
+ IN ULONG MaximumNumberOfExtents,
+ IN OUT PVOID ExtentList,
+ IN OUT PULONG NumberOfExtents
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ StoreExtents(
+ IN ULONG NumberOfExtents,
+ IN PALLEAF ExtentList,
+ IN BOOLEAN ParentIsFnode,
+ IN OUT PHPFS_BITMAP VolumeBitmap
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ TakeCensusAndClear(
+ IN OUT PHPFS_BITMAP VolumeBitmap,
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap,
+ IN OUT PHPFS_CENSUS Census
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ReadData(
+ IN ULONG SectorOffset,
+ OUT PVOID OutputBuffer,
+ IN ULONG BytesToRead,
+ OUT PULONG BytesRead,
+ IN PHOTFIXLIST HotfixList
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ PLOG_IO_DP_DRIVE _Drive;// logical drive on which the sector resides
+ HMEM _mem; // memory buffer for allocation sector
+ STORE _Store; // pointer to storage area object
+ PALSECD _pals; // pointer to allocation sector data
+ BOOLEAN _IsModified;
+
+};
+
+#endif
diff --git a/private/utils/uhpfs/inc/badblk.hxx b/private/utils/uhpfs/inc/badblk.hxx
new file mode 100644
index 000000000..4221adf5f
--- /dev/null
+++ b/private/utils/uhpfs/inc/badblk.hxx
@@ -0,0 +1,238 @@
+/***************************************************************************\
+
+CLASS: BADBLOCK
+
+PURPOSE: The purpose of this class is to provide a "write through"
+ interface to the bad block list structure on disk.
+
+ This class reads and writes to disk to avoid the possible
+ memory problems which may arise if upon formatting a disk
+ with a large number of bad sectors.
+
+
+INTERFACE: Create Create a new and empty bad block list.
+ Add Add a new bad sector LBN entry to an existing
+ bad block list.
+ Flush Write the bad sectors LBN's still in memory
+ out to the disk.
+ QueryCount Read the bad block list in from disk to
+ determine the number of bad sectors on disk.
+ StartIterator Reset the iterator for going through the bad
+ block list found on disk.
+ QueryNextLBN Return the next bad sector LBN from the
+ existing bad block list on disk.
+
+NOTES:
+
+HISTORY:
+ 16-Aug-90 norbertk
+ Create
+
+ 27-Mar-90 marks
+ define protocol
+
+KEYWORDS: BAD BLOCKS BAD LBN
+
+SEEALSO:
+
+\***************************************************************************/
+
+#if ! defined (BADBLOCK_DEFN)
+
+#define BADBLOCK_DEFN
+
+#include "hmem.hxx"
+#include "secrun.hxx"
+#include "verify.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( BADBLOCKLIST );
+DECLARE_CLASS( HPFS_SA );
+DECLARE_CLASS( HPFS_BITMAP );
+DECLARE_CLASS( HPFS_MAIN_BITMAP );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+
+#define SECTORS_PER_BAD_BLOCK 4
+#define LBNS_IN_BADBLK 511 // Number of lbn's in a bad block list.
+
+
+struct _BADBLOCKD {
+
+ LBN lbnNext;
+ LBN lbn[LBNS_IN_BADBLK];
+};
+
+DEFINE_TYPE( struct _BADBLOCKD, BADBLOCKD );
+
+class BADBLOCKLIST : public OBJECT {
+
+public:
+
+ DECLARE_CONSTRUCTOR( BADBLOCKLIST );
+
+ NONVIRTUAL
+ ~BADBLOCKLIST (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PLOG_IO_DP_DRIVE LogicalDrive,
+ IN LBN StartLbn
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Create(
+ IN LBN Lbn
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ Add(
+ IN LBN BadLbn
+ );
+
+ NONVIRTUAL
+ VERIFY_RETURN_CODE
+ VerifyAndFix (
+ IN OUT PHPFS_SA SuperArea,
+ OUT PULONG BadSectors,
+ IN BOOLEAN UpdateAllowed = FALSE
+ );
+
+ NONVIRTUAL
+ VOID
+ Print (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AddRun (
+ IN LBN Lbn,
+ IN SECTORCOUNT SectorCount
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Write(
+ PHPFS_SA SuperArea
+ );
+
+ NONVIRTUAL
+ INT
+ QueryLength(
+ ) CONST;
+
+ NONVIRTUAL
+ LBN
+ QueryBadLbn(
+ IN INT Index
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryBadLbns(
+ IN ULONG MaximumBadLbns,
+ OUT PLBN Buffer,
+ OUT PULONG NumberOfBadLbns
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ TakeCensus(
+ IN PHPFS_BITMAP VolumeBitmap,
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap
+ );
+
+
+private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ExpandList (
+ );
+
+ // _Drive is supplied at initialization; the object allocates
+ // and maintains (and must release) *_BadBlocks.
+
+ PLOG_IO_DP_DRIVE _Drive; // Drive on which list resides
+
+ LBN _StartLbn; // LBN of the beginning of the on-disk list
+ LBN* _BadBlocks; // in memory list of bad block LBNs
+ INT _FirstFreeLbn; // index of first free LBN in list
+ INT _ListSize; // number of LBNs in list
+
+ SECRUN _LastBlock; // Last sector of the on-disk list
+ HMEM _LastBlockMem; // memory object for SECRUN
+ LBN _LastBlockLbn; // LBN of _LastSector
+ BOOLEAN _LastBlockRead; // TRUE if _LastBlock has been read
+ PBADBLOCKD _LastBlockData; // pointer to data in _LastBlock
+
+};
+
+INLINE
+INT
+BADBLOCKLIST::QueryLength(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the number of bad sectors recorded in this
+ object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of bad sectors recorded in this object.
+
+--*/
+{
+ return _FirstFreeLbn;
+}
+
+
+INLINE
+LBN
+BADBLOCKLIST::QueryBadLbn(
+ IN INT Index
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the bad sector recorded at the supplied index.
+
+Arguments:
+
+ Index - Supplies the index of the bad sector number queried.
+
+Return Value:
+
+ A bad sector number.
+
+--*/
+{
+ return (Index < _ListSize) ? _BadBlocks[Index] : 0;
+}
+
+
+#endif // BADBLOCK
diff --git a/private/utils/uhpfs/inc/bitmap.hxx b/private/utils/uhpfs/inc/bitmap.hxx
new file mode 100644
index 000000000..92517fc77
--- /dev/null
+++ b/private/utils/uhpfs/inc/bitmap.hxx
@@ -0,0 +1,363 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ bitmap.hxx
+
+Abstract:
+
+ Bitmaps for HPFS volumes.
+
+Author:
+
+ Mark Shavlik (marks) 22-Oct-90
+ Bill McJohn (billmc) 4-Jan-91
+
+--*/
+
+#if !defined(BITMAP_DEFN)
+
+#define BITMAP_DEFN
+
+#include "secrun.hxx"
+#include "cmem.hxx"
+#include "ods.hxx"
+#include "bitvect.hxx"
+#include "hmem.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( BITMAPINDIRECT );
+DECLARE_CLASS( HOTFIX_SECRUN );
+DECLARE_CLASS( HOTFIXLIST );
+DECLARE_CLASS( HPFS_BITMAP );
+DECLARE_CLASS( HPFS_DIR_BITMAP );
+DECLARE_CLASS( HPFS_MAIN_BITMAP );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+
+class HPFS_MAIN_BITMAP : public OBJECT {
+
+ public:
+
+ UHPFS_EXPORT
+ DECLARE_CONSTRUCTOR( HPFS_MAIN_BITMAP );
+
+ UHPFS_EXPORT
+ VIRTUAL
+ ~HPFS_MAIN_BITMAP(
+ );
+
+ UHPFS_EXPORT
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PLOG_IO_DP_DRIVE Drive,
+ IN PHOTFIXLIST HotfixList DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ VOID
+ SetHotfixList(
+ IN PHOTFIXLIST HotfixList
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Create(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Write(
+ IN PBITMAPINDIRECT BitmapIndirectBlock
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Read(
+ IN PCBITMAPINDIRECT BitmapIndirectBlock
+ );
+
+ UHPFS_EXPORT
+ NONVIRTUAL
+ BOOLEAN
+ SetFree(
+ IN LBN Lbn,
+ IN SECTORCOUNT sc = 1
+ );
+
+ UHPFS_EXPORT
+ NONVIRTUAL
+ BOOLEAN
+ SetAllocated(
+ IN LBN Lbn,
+ IN SECTORCOUNT sc = 1
+ );
+
+ NONVIRTUAL
+ SECTORCOUNT
+ QueryFreeSectors(
+ ) CONST;
+
+ UHPFS_EXPORT
+ NONVIRTUAL
+ BOOLEAN
+ IsFree(
+ IN LBN Lbn
+ ) CONST;
+
+ NONVIRTUAL
+ LBN
+ QueryNextAllocLBN(
+ IN LBN Lbn,
+ OUT PBOOLEAN fOk = NULL
+ ) CONST;
+
+ NONVIRTUAL
+ SECTORCOUNT
+ QuerySize(
+ ) CONST { return _NumberOfSectors; }
+
+ NONVIRTUAL
+ LBN
+ NearLBN(
+ IN LBN Lbn,
+ IN SECTORCOUNT sc,
+ IN SECTORCOUNT scAlign = 1,
+ IN BOOLEAN fBackward = FALSE
+ );
+
+ NONVIRTUAL
+ LBN
+ EarlyLBN(
+ IN SECTORCOUNT sc,
+ IN SECTORCOUNT scAlign = 1
+ ) { return NearLBN(0, sc, scAlign); }
+
+ NONVIRTUAL
+ LBN
+ MiddleLBN(
+ IN SECTORCOUNT sc,
+ IN SECTORCOUNT scAlign = 1
+ ) { return NearLBN(_NumberOfSectors/2/scAlign*scAlign,
+ sc, scAlign); }
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryNextOrphan(
+ IN PBITMAPINDIRECT BitmapIndirectBlock,
+ OUT PLBN NextOrphan,
+ IN OUT PBOOLEAN AllocationErrors
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AndWithDisk(
+ IN PBITMAPINDIRECT BitmapIndirectBlock
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ InitArray(
+ IN PCBITMAPINDIRECT BitmapIndirectBlock
+ );
+
+ NONVIRTUAL
+ LBN
+ ForwardLBN(
+ IN LBN Lbn,
+ IN SECTORCOUNT sc,
+ IN SECTORCOUNT scAlign
+ );
+
+ NONVIRTUAL
+ LBN
+ BackwardLBN(
+ IN LBN Lbn,
+ IN SECTORCOUNT sc,
+ IN SECTORCOUNT scAlign
+ );
+
+ // _Drive and _HotfixList are passed in at initialization;
+ // _Bitmap, _BitmapBuffer, and _BitmapBlocks are allocated
+ // inside the object, and must be released by it.
+
+ PLOG_IO_DP_DRIVE _Drive;
+ PHOTFIXLIST _HotfixList;
+
+ SECTORCOUNT _NumberOfSectors;
+
+ BITVECTOR _Bitmap;
+ HMEM _Mem1;
+ CONT_MEM _Mem2;
+
+ ULONG _NumberOfBlocks;
+ PHOTFIX_SECRUN _BitmapBlocks;
+
+ PHOTFIX_SECRUN _OrphanScanBlock;
+ HMEM _OrphanScanMem;
+ LBN _OrphanIndex;
+ BITVECTOR _OrphanBitmap;
+ LBN _OrphanBitmapNumber;
+
+};
+
+class HPFS_BITMAP : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( HPFS_BITMAP );
+
+ VIRTUAL
+ ~HPFS_BITMAP(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PLOG_IO_DP_DRIVE Drive,
+ LBN FirstLbnOfDirblkBitmap,
+ SECTORCOUNT NumberOfSectorsInDirblkBand,
+ LBN FirstLbnOfDirblkBand,
+ PHOTFIXLIST HotfixList DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetAllocated (
+ IN LBN StartLbn,
+ IN SECTORCOUNT SectorCount DEFAULT 1
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetFree(
+ IN LBN StartLbn,
+ IN SECTORCOUNT SectorCount DEFAULT 1
+ );
+
+ NONVIRTUAL
+ LBN
+ AllocateDirblk(
+ IN BOOLEAN Backward = FALSE
+ );
+
+ NONVIRTUAL
+ LBN
+ NearLBN(
+ LBN Lbn,
+ SECTORCOUNT sc,
+ SECTORCOUNT scAlign = 1,
+ BOOLEAN fBackward = FALSE
+ );
+
+ NONVIRTUAL
+ SECTORCOUNT
+ QueryFreeSectors(
+ ) CONST;
+
+ UHPFS_EXPORT
+ NONVIRTUAL
+ BOOLEAN
+ IsFree (
+ IN LBN StartLbn,
+ IN SECTORCOUNT SectorCount,
+ IN BOOLEAN IsDirblk = FALSE
+ ) CONST ;
+
+ NONVIRTUAL
+ BOOLEAN
+ CheckUsed(
+ IN LBN StartLbn,
+ IN SECTORCOUNT SectorCount
+ );
+
+ NONVIRTUAL
+ PHPFS_MAIN_BITMAP
+ GetBitmap (
+ ) CONST { return _MainBitmap; };
+
+ NONVIRTUAL
+ VOID
+ DumpInUse(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryNextOrphan(
+ IN PBITMAPINDIRECT BitmapIndirectBlock,
+ OUT PLBN NextOrphan,
+ IN OUT PBOOLEAN AllocationErrors
+ );
+
+ NONVIRTUAL
+ VOID
+ SetHotfixList(
+ PHOTFIXLIST HotfixList
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Write(
+ IN OUT PBITMAPINDIRECT BitmapIndirectBlock
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Read(
+ IN PBITMAPINDIRECT BitmapIndirectBlock
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AndWithDisk(
+ IN PBITMAPINDIRECT BitmapIndirectBlock
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CheckAvailableDirblks(
+ IN ULONG RequestedNumber
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ PHPFS_MAIN_BITMAP _MainBitmap;
+ PHPFS_DIR_BITMAP _DirBitmap;
+
+ LBN _FirstLbnOfDirblkBand;
+ LBN _LastLbnOfDirblkBand;
+ SECTORCOUNT _SectorsInDirblkBand;
+
+ BOOLEAN _QueriedOrphanDirblks;
+
+
+};
+
+#endif // HPFS_MAIN_BITMAP_DEFN
diff --git a/private/utils/uhpfs/inc/bmind.hxx b/private/utils/uhpfs/inc/bmind.hxx
new file mode 100644
index 000000000..3603dceda
--- /dev/null
+++ b/private/utils/uhpfs/inc/bmind.hxx
@@ -0,0 +1,141 @@
+/***************************************************************************\
+
+CLASS: BITMAPINDIRECT
+
+PURPOSE: Block of LBNs pointing to LBNs for each bitmap on the volume
+ called the Bitmap Indirect Block. The BITMAP class is used
+ to determine each bitmap location.
+
+INTERFACE: BITMAPINDIRECT Setup for creation or get of bitmap indirect
+
+ Create Create new Bitmap Indirect Block
+ QueryLbn Return LBN at named index position
+ QueryCount Return number of LBNs in block
+ QueryStartRSP Return location of start of block
+
+NOTES:
+
+HISTORY:
+ 01-Aug-90 norbertk
+ Create
+
+ 27-Mar-90 marks
+ define protocol
+
+KEYWORDS: Bitmap bands bit map indirect
+
+
+\***************************************************************************/
+
+#if ! defined (BITMAPINDIRECT_DEFN)
+
+#define BITMAPINDIRECT_DEFN
+
+#include "secrun.hxx"
+#include "hmem.hxx"
+#include "verify.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( BITMAPINDIRECT );
+DECLARE_CLASS( HPFS_BITMAP );
+DECLARE_CLASS( HPFS_MAIN_BITMAP );
+DECLARE_CLASS( HPFS_SA );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+
+// The length of the Bitmap Indirect Block is dependent on the size
+// of the volume; the volume has one (4-sector) bitmap block for each
+// 8M of disk space, and the bitmap indirect block has one LBN (DWORD)
+// for each bitmap block. Note that the disk space reserved for the
+// bitmap indirect block is rounded up to the next multiple of 4 sectors.
+
+// Note that the size of this structure is not useful.
+
+struct BITMAPINDIRECTD {
+
+ LBN lbn[1];
+};
+
+class BITMAPINDIRECT : public SECRUN {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( BITMAPINDIRECT );
+
+ VIRTUAL
+ ~BITMAPINDIRECT(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ PLOG_IO_DP_DRIVE Drive,
+ LBN IndirectBlockLbn
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Create(
+ PCLOG_IO_DP_DRIVE,
+ PHPFS_BITMAP
+ );
+
+ NONVIRTUAL
+ LBN
+ QueryLbn(
+ ULONG i
+ ) CONST { return (_pbid && i < _NumberOfBitmaps) ?
+ _pbid->lbn[i] : 0; }
+
+ NONVIRTUAL
+ VOID
+ SetLbn(
+ ULONG i, LBN NewLbn
+ ) { if( _pbid && i < _NumberOfBitmaps) {_pbid->lbn[i] = NewLbn;}}
+
+ NONVIRTUAL
+ ULONG
+ QueryCount(
+ ) CONST { return _NumberOfBitmaps; }
+
+ NONVIRTUAL
+ VERIFY_RETURN_CODE
+ VerifyAndFix (
+ PHPFS_SA SuperArea,
+ IN BOOLEAN UpdateAllowed = FALSE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ TakeCensus(
+ IN PHPFS_BITMAP VolumeBitmap,
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap
+ );
+
+ NONVIRTUAL
+ VOID
+ Print(
+ ) CONST;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ VOID
+ Destroy(
+ );
+
+ HMEM _Mem;
+ ULONG _NumberOfBitmaps; // current number of Bitmaps
+ ULONG _SectorsInBlock; // number of sectors in BMIND block
+ BITMAPINDIRECTD* _pbid; // description of BMIND block
+
+};
+
+
+#endif // BITMAPINDIRECT_DEFN
diff --git a/private/utils/uhpfs/inc/cpinfo.hxx b/private/utils/uhpfs/inc/cpinfo.hxx
new file mode 100644
index 000000000..1c0f585b1
--- /dev/null
+++ b/private/utils/uhpfs/inc/cpinfo.hxx
@@ -0,0 +1,597 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ codepage.hxx
+
+Abstract:
+
+ Container for HPFS Volume Codepage information
+
+Author:
+ Mark Shavlik (marks) Nov-90
+
+Environment:
+
+Notes:
+
+
+Revision History:
+
+--*/
+
+#if ! defined( UHPFS_CODEPAGE_DFN )
+
+#define UHPFS_CODEPAGE_DFN
+
+
+#include "hmem.hxx"
+#include "secrun.hxx"
+#include "verify.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( UHPFS_CODEPAGE );
+DECLARE_CLASS( CPDATA );
+DECLARE_CLASS( CODEPAGE_INFO );
+DECLARE_CLASS( CASEMAP );
+DECLARE_CLASS( HOTFIXLIST );
+DECLARE_CLASS( HPFS_BITMAP );
+DECLARE_CLASS( HPFS_MAIN_BITMAP );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+
+//
+// Codepage constants:
+
+#define CCS_ROT 7
+
+CONST EntriesPerCPInfoSector = 31;
+CONST EntriesPerCPDataSector = 3;
+CONST MaximumCodepagesOnVol = 128;
+
+CONST InvalidCountryCode = 0xffff;
+CONST InvalidCodepageID = 0xffff;
+
+CONST CaseTableSize = 256;
+
+CONST CharsInCasemap = 128;
+
+class UHPFS_CODEPAGE : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( UHPFS_CODEPAGE );
+
+ VIRTUAL
+ ~UHPFS_CODEPAGE();
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Create(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN LBN FirstInfoSectorLbn,
+ IN LBN DataSectorLbn
+ );
+
+ NONVIRTUAL
+ VERIFY_RETURN_CODE
+ VerifyAndFix (
+ IN PLOG_IO_DP_DRIVE LogicalDrive,
+ IN PHOTFIXLIST HotfixList,
+ IN PHPFS_BITMAP Bitmap,
+ IN LBN FirstInfoSectorLbn,
+ IN BOOLEAN UpdateAllowed,
+ OUT PBOOLEAN ErrorsDetected
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Read(
+ IN PLOG_IO_DP_DRIVE LogicalDrive,
+ IN LBN FirstInfoSectorLbn
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ TakeCensus(
+ IN PLOG_IO_DP_DRIVE LogicalDrive,
+ IN LBN FirstInfoSectorLbn,
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap
+ );
+
+ UHPFS_EXPORT
+ NONVIRTUAL
+ PCASEMAP
+ GetCasemap(
+ );
+
+ NONVIRTUAL
+ USHORT
+ QueryNumberOfCodepages (
+ );
+
+ VOID
+ Print (
+ );
+
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ // The CodePage object creates and maintains a _Casemap
+ // object; it is also responsible for destroying it.
+
+ PCASEMAP _Casemap;
+
+ USHORT mNumberOfCodepages;
+ USHORT mNumberOfValidCodepages;
+
+ BOOLEAN IsEntryValid[MaximumCodepagesOnVol];
+ USHORT CountryCodes[MaximumCodepagesOnVol];
+ USHORT CodepageIDs[MaximumCodepagesOnVol];
+
+
+};
+
+/*** Code Page - disk image
+ *
+ * Each volume has one or more sectors which contain information about
+ * the code pages stored on the volume. This information contains the
+ * ordering (index) of each code page, the country code, the code page
+ * id, lbn and offset of the code page information.
+ *
+ * Each Code Page Info sector contains up to 31 code page descriptions
+ * (including the locations of the code page data).
+ *
+ * Each Code Page Data sector contains up to 3 entries of code page data.
+ *
+ * Since all code pages case conversion is identical for character
+ * values 0-127, only 128 bytes are necessary for code page case
+ * conversion information.
+ *
+ * DBCS pairs are packed, with a trailing 0,0 pair terminating the list.
+ * No DBCS is indicated by a 0,0 pair.
+ *
+ * Currently no DBCS Code Page has more than 2 byte pairs, but we don't
+ * want to limit it to that.
+ *
+ * Code Page 850 is only stored once, since the case table is the same for
+ * ALL countries, and there is never DBCS support. It is stored with a
+ * 0 country code for easy matching.
+ *
+ */
+
+
+DEFINE_TYPE( ULONG, CHECKSUM );
+
+
+/** DBCS_Range - DBCS range byte pairs **/
+
+typedef struct _DBCS_Range {
+
+ UCHAR CDIB_DBCS_start;
+ UCHAR CDIB_DBCS_end;
+} DBCS_Range;
+
+
+typedef struct CPINFOENTRY { // cpinfoent
+ USHORT CountryCode; /* country code */
+ USHORT CodePageID; /* code page id */
+ CHECKSUM cksCP; /* checksum of code page data */
+ LBN lbnCPData; /* lbn containing code page data */
+ USHORT iCmphpfs; /* index of code page (on volume) */
+ USHORT cDBCSrange; /* # of DBCS ranges (0 -> no DBCS) */
+} *PCPINFOENTRY;
+
+
+typedef struct CPINFOSECTORD { // cpinfosecd
+
+ ULONG sig; // Data Sector Signature
+ ULONG cCodePage; // # of info entries in this sector
+ ULONG iFirstCP; // index on vol. of 1st entry in sector
+ LBN lbnNext; // lbn of next info sector
+ CPINFOENTRY cpinfoent[EntriesPerCPInfoSector]; // info entries
+
+} *PCPINFOSECTORD;
+
+
+/** CPDATAENTRY - Code Page Data entry
+ *
+ * For each code page, there is one of these structures. It contains
+ * the case conversion table for the upper half of the single-byte
+ * characters (the lower half is always translated using a fixed rule).
+ */
+
+typedef struct CPDATAENTRY { // cpdataent
+ USHORT CountryCode; /* country code */
+ USHORT CodePageID; /* code page id */
+ USHORT cDBCSrange; /* # of DBCS ranges */
+ BYTE bCaseMapTable [CharsInCasemap]; /* case conversion table for byte values
+ * greater than 127 */
+ DBCS_Range DBCS_RangeTable [1]; /* variable array of byte pairs
+ * (cDBCSrange + 1, with trailing 0,0)
+ */
+} *PCPDATAENTRY;
+
+typedef struct CPDATASECTOR { // cpdatasec
+
+ ULONG sig;
+ USHORT cCodePage;
+ USHORT iFirstCP;
+ CHECKSUM cksCP[EntriesPerCPDataSector];
+ USHORT offCPData[EntriesPerCPDataSector];
+ BYTE pData[1]; // pointer to first data
+
+} *PCPDATASECTOR;
+
+/***************************************************************************\
+
+CLASS: CPDATA
+
+PURPOSE: Define data used to describe code pages.
+
+INTERFACE: CPDATA Setup for creation or getting
+
+NOTES:
+
+HISTORY: 27-Mar-90 marks
+ define protocol
+
+KEYWORDS:
+
+SEEALSO:
+
+\***************************************************************************/
+
+class CPDATA : public SECRUN {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( CPDATA );
+
+ BOOLEAN
+ Initialize(
+ IN PLOG_IO_DP_DRIVE pliodpdrv
+ );
+
+ BOOLEAN
+ Create(
+ OUT PCHECKSUM CheckSum
+ );
+
+ VOID
+ Flush (
+ IN PLOG_IO_DP_DRIVE pliodpdrv,
+ IN USHORT Entries,
+ IN BOOLEAN UpdateAllowed,
+ OUT PBOOLEAN ErrorsDetected
+ );
+
+ BOOLEAN
+ NextEntryToCheck (
+ IN PLOG_IO_DP_DRIVE pliodpdrv,
+ IN LBN lbn,
+ IN PHPFS_BITMAP Bitmap,
+ IN BOOLEAN UpdateAllowed,
+ OUT PBOOLEAN ErrorsDetected
+ );
+
+ BOOLEAN
+ ReadNextEntry (
+ IN LBN lbn
+ );
+
+ CHECKSUM
+ ComputeChecksum (
+ );
+
+ BOOLEAN
+ VerifyAndFix (
+ IN PLOG_IO_DP_DRIVE pliodpdrv,
+ IN PCODEPAGE_INFO CurrentInfoEntry,
+ IN BOOLEAN UpdateAllowed,
+ OUT PBOOLEAN ErrorsDetected
+ );
+
+ BOOLEAN
+ IsValid ( );
+
+ PCPDATAENTRY
+ GetEntry(
+ ) CONST;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ CHECKSUM ComputeChkSum ( ) CONST;
+
+ PCPDATASECTOR pcpdatasecd;
+
+ BOOLEAN mIsModified;
+ BOOLEAN mIsInitialized;
+ BOOLEAN mValidEntry;
+ BOOLEAN mSectorIsValid;
+
+ LBN mCurrentLbn;
+ USHORT mCurrentIndexInSector;
+ USHORT mExpectedOffset;
+
+ HMEM _hmem;
+
+
+};
+
+
+/***************************************************************************\
+
+CLASS: CODEPAGE_INFO
+
+PURPOSE: Store information about CPs and LBN pointers to CP data. CP
+ data is described by the CPDATA class.
+
+INTERFACE: CODEPAGE_INFO Setup for creation or getting
+
+
+NOTES:
+
+HISTORY: 27-Mar-90 marks
+ define protocol
+
+KEYWORDS:
+
+SEEALSO:
+
+\***************************************************************************/
+
+
+class CODEPAGE_INFO : public SECRUN {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( CODEPAGE_INFO );
+
+ BOOLEAN
+ Initialize(
+ IN PLOG_IO_DP_DRIVE pliodpdrv,
+ IN LBN lbn
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Create(
+ IN LBN DataSectorLbn,
+ IN CHECKSUM CheckSum
+ );
+
+ VOID
+ Flush (
+ IN PLOG_IO_DP_DRIVE pliodpdrv,
+ IN USHORT Entries,
+ IN BOOLEAN UpdateAllowed,
+ OUT PBOOLEAN ErrorsDetected
+ );
+
+ BOOLEAN
+ NextEntryToCheck (
+ IN PLOG_IO_DP_DRIVE pliodpdrv,
+ IN PHOTFIXLIST HotfixList,
+ IN PHPFS_BITMAP Bitmap,
+ IN USHORT ExpectedIndex,
+ IN BOOLEAN UpdateAllowed,
+ OUT PBOOLEAN ErrorsDetected
+ );
+
+ BOOLEAN
+ ReadNextEntry (
+ );
+
+ VERIFY_RETURN_CODE
+ VerifyAndFix (
+ IN PHOTFIXLIST HotfixList,
+ IN USHORT ExpectedIndex,
+ OUT PBOOLEAN ErrorsDetected
+ );
+
+ VOID
+ MarkEntryBad(
+ );
+
+ LBN
+ QueryDataLbn (
+ );
+
+ LBN
+ QueryCurrentLbn (
+ ) CONST;
+
+ friend
+ BOOLEAN
+ CPDATA::VerifyAndFix (
+ IN PLOG_IO_DP_DRIVE pliodpdrv,
+ IN PCODEPAGE_INFO CurrentInfoEntry,
+ IN BOOLEAN UpdateAllowed,
+ OUT PBOOLEAN ErrorsDetected
+ );
+
+ USHORT
+ QueryCountry(
+ );
+
+ USHORT
+ QueryCPID (
+ );
+
+ NONVIRTUAL VOID
+ Print ( ) CONST;
+
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ PCPINFOSECTORD pcpinfosecd;
+
+ BOOLEAN mIsInitialized;
+ BOOLEAN mSectorIsValid;
+ BOOLEAN mIsModified;
+ BOOLEAN mFirstEntry;
+
+ LBN mCurrentLbn;
+ USHORT mCurrentIndexInSector;
+
+ HMEM _hmem;
+
+};
+
+INLINE
+LBN
+CODEPAGE_INFO::QueryCurrentLbn(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the LBN that contains the current information
+ entry.
+
+Arguments
+
+ None.
+
+Return Value:
+
+ The LBN that contains the current information entry. Zero indicates
+ failure.
+
+--*/
+{
+ return mCurrentLbn;
+}
+
+
+class CASEMAP : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( CASEMAP );
+
+ VIRTUAL
+ ~CASEMAP (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ HasDBCS(
+ IN ULONG CodePageIndex
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsDBCS(
+ ULONG CodePageIndex,
+ UCHAR Char
+ ) CONST;
+
+ NONVIRTUAL
+ UCHAR
+ UpperCase(
+ UCHAR Char,
+ ULONG CodePageIndex
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ AddCodepage (
+ ULONG CodepageIndex,
+ PCPDATAENTRY pcpdataent
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsCodpageIndexValid(
+ ULONG CodepageIndex
+ ) CONST;
+
+ NONVIRTUAL
+ USHORT
+ QueryCodepageId(
+ IN ULONG CodepageIndex
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ PUCHAR _CaseTable[ MaximumCodepagesOnVol ];
+ PBOOLEAN _IsDBCS [ MaximumCodepagesOnVol ];
+ USHORT _CodepageId[ MaximumCodepagesOnVol ];
+ BOOLEAN _IsValid[ MaximumCodepagesOnVol ];
+ BOOLEAN _HasDBCS[ MaximumCodepagesOnVol ];
+
+};
+
+INLINE
+USHORT
+CASEMAP::QueryCodepageId(
+ IN ULONG CodepageIndex
+ )
+/*++
+
+Routine Description:
+
+ This method returns the code page id for the specified
+ volume codepage.
+
+Arguments:
+
+ CodepageIndex -- Supplies the index on the volume of the
+ desired codepage.
+
+Return Value:
+
+ The codepage ID for the specified codepage.
+
+--*/
+{
+ return _CodepageId[CodepageIndex];
+}
+
+#endif
diff --git a/private/utils/uhpfs/inc/defer.hxx b/private/utils/uhpfs/inc/defer.hxx
new file mode 100644
index 000000000..249d41e8c
--- /dev/null
+++ b/private/utils/uhpfs/inc/defer.hxx
@@ -0,0 +1,270 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ defer.hxx
+
+Abstract:
+
+ While it is verifying a volume, HPFS Chkdsk may discover
+ errors or conditions which require the allocation of new
+ sectors. However, since it discovers these problems while
+ it is verifying the bitmap, it cannot immediately correct
+ them. Instead, they go in the deferred action pool, to be
+ resolved later.
+
+ Deferred actions include hotfix resolution, crosslink resolution,
+ directory-entry deletion, and directory sorting.
+
+Author:
+
+ Bill McJohn (billmc) 26-Dec-1990
+
+--*/
+
+#if !defined ( DEFERRED_ACTIONS_DEFN )
+
+#define DEFERRED_ACTIONS_DEFN
+
+#include "drive.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( DEFERRED_ACTIONS_LIST );
+DECLARE_CLASS( DIRBLK_CACHE );
+DECLARE_CLASS( HPFS_DIRECTORY_TREE );
+DECLARE_CLASS( HPFS_NAME );
+DECLARE_CLASS( HPFS_PATH );
+DECLARE_CLASS( HPFS_SA );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+
+
+
+enum DEFERRED_SECTOR_TYPE {
+
+ DEFER_DIRBLK,
+ DEFER_FNODE,
+ DEFER_ALSEC,
+ DEFER_STORE,
+ DEFER_EA_DATA,
+ DEFER_ACL_DATA
+};
+
+
+struct DEFERRED_HOTFIX {
+
+ LBN ParentLbn;
+ DEFERRED_SECTOR_TYPE ParentType;
+ DEFERRED_SECTOR_TYPE ChildType;
+};
+
+struct DEFERRED_XLINK {
+
+ LBN ParentLbn;
+ DEFERRED_SECTOR_TYPE ParentType;
+ HPFS_PATH* Path;
+ ULONG RunIndex;
+};
+
+
+// Maximum buffer sizes for deferred operations. Note that Chkdsk will
+// detect (and report) if these limits are exceeded.
+
+const MaximumDeferredHotfixes = 180;
+const MaximumDeferredXlinks = 180;
+const MaximumFnodesToSort = 1028;
+const MaximumNamesToDelete = 1028;
+
+class DEFERRED_ACTIONS_LIST : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( DEFERRED_ACTIONS_LIST );
+
+ VIRTUAL
+ ~DEFERRED_ACTIONS_LIST();
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ );
+
+ NONVIRTUAL
+ VOID
+ AddHotfixedLbn(
+ LBN ParentLbn,
+ DEFERRED_SECTOR_TYPE ParentSectorType,
+ DEFERRED_SECTOR_TYPE ChildSectorType
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AddCrosslinkedLbn(
+ LBN ParentLbn,
+ IN PHPFS_PATH Path,
+ DEFERRED_SECTOR_TYPE ParentSectorType,
+ ULONG RunIndex
+ );
+
+ NONVIRTUAL
+ VOID
+ AddNameToDelete(
+ PHPFS_PATH PathToDelete,
+ PHPFS_NAME NameToDelete
+ );
+
+ NONVIRTUAL
+ VOID
+ AddDirectoryToSort(
+ LBN LbnFnode
+ );
+
+ NONVIRTUAL
+ VOID
+ ResolveDeferredHotfixes(
+ PLOG_IO_DP_DRIVE Drive,
+ PHPFS_SA SuperArea
+ );
+
+ NONVIRTUAL
+ VOID
+ ResolveDeferredCrosslinks(
+ PLOG_IO_DP_DRIVE Drive,
+ PHPFS_SA SuperArea
+ );
+
+ NONVIRTUAL
+ VOID
+ Sort(
+ PLOG_IO_DP_DRIVE Drive,
+ PHPFS_SA SuperArea,
+ PDIRBLK_CACHE Cache,
+ LBN RootFnodeLbn,
+ PHPFS_DIRECTORY_TREE RootTree
+ );
+
+ NONVIRTUAL
+ VOID
+ Delete(
+ PLOG_IO_DP_DRIVE Drive,
+ PHPFS_SA SuperArea,
+ PDIRBLK_CACHE Cache,
+ PHPFS_DIRECTORY_TREE RootTree,
+ LBN RootFnodeLbn
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryUnresolvedHotfixes(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryUnresolvedSorts(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryUnresolvedDeletes(
+ );
+
+
+ // Statistical information:
+
+ NONVIRTUAL
+ VOID
+ StatDirectory(
+ IN BOOLEAN Remove = FALSE
+ );
+
+ NONVIRTUAL
+ VOID
+ StatDirblk(
+ IN BOOLEAN Remove = FALSE
+ );
+
+ NONVIRTUAL
+ VOID
+ StatFile(
+ IN ULONG SectorsInFile,
+ IN BOOLEAN Remove = FALSE
+ );
+
+ NONVIRTUAL
+ VOID
+ StatEaData(
+ IN ULONG SectorsInAllocation,
+ IN BOOLEAN Remove = FALSE
+ );
+
+ NONVIRTUAL
+ VOID
+ StatReport(
+ IN ULONG TotalSectors,
+ IN ULONG TotalFreeSectors,
+ IN ULONG BytesPerSector,
+ IN ULONG BadSectors,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ VOID
+ SetTargetSectorCount(
+ IN ULONG TargetSectors
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ RecordVisitedSectors(
+ IN ULONG SectorCount,
+ IN OUT PMESSAGE Message
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy();
+
+ DEFERRED_HOTFIX _Hotfixes[MaximumDeferredHotfixes];
+ DEFERRED_XLINK _Xlinks[MaximumDeferredXlinks];
+
+ HPFS_PATH* _PathsToDelete[MaximumNamesToDelete];
+ HPFS_NAME* _NamesToDelete[MaximumNamesToDelete];
+
+ LBN _FnodesToSort[MaximumFnodesToSort];
+
+ BOOLEAN _HotfixOverflow;
+ BOOLEAN _DeleteOverflow;
+ BOOLEAN _SortOverflow;
+
+ ULONG _NumberOfDirectories;
+ ULONG _NumberOfDirblks;
+ ULONG _NumberOfFiles;
+ ULONG _TotalFileSectors;
+ ULONG _TotalEaSectors;
+
+ ULONG _TargetSectors;
+ ULONG _VisitedSectors;
+ ULONG _PercentComplete;
+};
+
+INLINE
+VOID
+DEFERRED_ACTIONS_LIST::SetTargetSectorCount(
+ IN ULONG TargetSectors
+ )
+{
+ _TargetSectors = TargetSectors;
+}
+
+#endif
diff --git a/private/utils/uhpfs/inc/dirblk.hxx b/private/utils/uhpfs/inc/dirblk.hxx
new file mode 100644
index 000000000..9bdf5b74e
--- /dev/null
+++ b/private/utils/uhpfs/inc/dirblk.hxx
@@ -0,0 +1,474 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ dirblk.hxx
+
+Abstract:
+
+ This module contains declarations for the DIRBLK object,
+ which models a directory block in an HPFS directory B-Tree.
+
+Author:
+
+ Norbert Kusters (norbertk) 27-Aug-1990
+ Bill McJohn (billmc) 01-Dec-1990
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#if ! defined(DIRBLK_DEFN)
+
+#define DIRBLK_DEFN
+
+#include "hfsecrun.hxx"
+#include "hmem.hxx"
+#include "defer.hxx"
+#include "verify.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( CASEMAP );
+DECLARE_CLASS( DEFERRED_ACTIONS_LIST );
+DECLARE_CLASS( DIRBLK );
+DECLARE_CLASS( HOTFIXLIST );
+DECLARE_CLASS( HPFS_BITMAP );
+DECLARE_CLASS( HPFS_CENSUS );
+DECLARE_CLASS( HPFS_MAIN_BITMAP );
+DECLARE_CLASS( HPFS_NAME );
+DECLARE_CLASS( HPFS_ORPHANS );
+DECLARE_CLASS( HPFS_PATH );
+DECLARE_CLASS( HPFS_SA );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( MESSAGE );
+
+#define DIRBLK_SIZE 2048
+#define DOWNPOINTER_SIZE 4
+#define DIRBLK_HEADER_SIZE 20
+
+
+
+DEFINE_TYPE( ULONG, UHPFS_TIME );
+
+struct _DIRBLKD {
+
+ ULONG sig;
+ ULONG offulFirstFree;
+ ULONG culChange;
+ LBN lbnParent;
+ LBN lbnThisDir;
+ BYTE bFirst;
+
+ BYTE abDummy[DIRBLK_SIZE - (DIRBLK_HEADER_SIZE + 1)];
+
+};
+
+struct _DIRENTD {
+
+ USHORT cchThisEntry;
+ BYTE fFlags;
+ BYTE fAttr;
+ LBN lbnFnode;
+ UHPFS_TIME timLastMod;
+ ULONG cchFSize;
+ UHPFS_TIME timLastAccess;
+ UHPFS_TIME timCreate;
+ ULONG ulEALen;
+ BYTE fFlex;
+ BYTE bCodePage;
+ BYTE cchName;
+ BYTE bName[1];
+
+ // LBN BTree;
+};
+
+DEFINE_TYPE( struct _DIRBLKD, DIRBLKD );
+DEFINE_TYPE( struct _DIRENTD, DIRENTD );
+
+
+
+#define BTP( pde ) \
+ (*( (ULONG *)( (PBYTE)(pde) + \
+ (pde)->cchThisEntry - DOWNPOINTER_SIZE)))
+
+#define NEXT_ENTRY( pde ) \
+ ( (PDIRENTD)((PBYTE)(pde) + (pde)->cchThisEntry) )
+
+#define FIRST_ENTRY( pdb ) \
+ ( (PDIRENTD)(&((pdb)->bFirst)) )
+
+CONST LeafEndEntrySize = sizeof( DIRENTD );
+CONST MinimumDirentSize = sizeof( DIRENTD );
+CONST MaximumDirentSize = sizeof( DIRENTD ) +
+ 255 + // Maximum name
+ DOWNPOINTER_SIZE + // B-Tree pointer
+ 12; // ACLs.
+
+CONST MergeThreshhold = 2 * MaximumDirentSize + 2 * LeafEndEntrySize + 10;
+
+enum {
+ DF_SPEC = 0x0001, /* special .. entry */
+ DF_ACL = 0x0002, /* item has ACL */
+ DF_BTP = 0x0004, /* entry has a btree down pointer */
+ DF_END = 0x0008, /* is dummy end record */
+ DF_ATTR = 0x0010, /* has an extended attribute list */
+ DF_PERM = 0x0020, /* has an extended permission list */
+ DF_XACL = 0x0040, /* item has explicit ACL */
+ DF_NEEDEAS = 0x0080 /* item has "need" EAs */
+};
+
+
+#define ATTR_READ_ONLY (0x01)
+#define ATTR_HIDDEN (0x02)
+#define ATTR_SYSTEM (0x04)
+#define ATTR_DIRECTORY (0x10)
+#define ATTR_ARCHIVE (0x20)
+#define ATTR_NEWNAME (0x40)
+
+class DIRBLK : public HOTFIX_SECRUN {
+
+ public:
+
+ UHPFS_EXPORT
+ DECLARE_CONSTRUCTOR( DIRBLK );
+
+ UHPFS_EXPORT
+ VIRTUAL
+ ~DIRBLK (
+ );
+
+ UHPFS_EXPORT
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PLOG_IO_DP_DRIVE Drive,
+ IN PHOTFIXLIST HotfixList,
+ IN LBN lbn
+ );
+
+ BOOLEAN
+ CreateRoot (
+ IN LBN FnodeLbn
+ );
+
+ NONVIRTUAL
+ VERIFY_RETURN_CODE
+ VerifyAndFix(
+ IN PHPFS_SA SuperArea,
+ IN PDEFERRED_ACTIONS_LIST DeferredActions,
+ IN PHPFS_PATH CurrentPath,
+ IN OUT PHPFS_NAME PreviousName,
+ IN LBN ExpectedParentLbn,
+ IN LBN ParentFnodeLbn,
+ IN ULONG CurrentDepth,
+ IN OUT PULONG LeafDepth,
+ IN PMESSAGE Message,
+ OUT PBOOLEAN ErrorsDetected,
+ IN BOOLEAN UpdateAllowed = FALSE,
+ IN BOOLEAN Verbose = FALSE,
+ IN PHPFS_ORPHANS OrphansList = NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsDirblk(
+ );
+
+ NONVIRTUAL
+ VOID
+ Truncate(
+ IN PDIRENTD pde
+ );
+
+ NONVIRTUAL
+ VOID
+ VerifyAndFixEndEntry(
+ IN PDIRENTD pde,
+ IN OUT PBOOLEAN ErrorsDetected
+ );
+
+ NONVIRTUAL
+ VOID
+ MarkModified(
+ );
+
+ NONVIRTUAL
+ VOID
+ MarkUnmodified(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsModified(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FindName(
+ IN PHPFS_NAME Name,
+ OUT PDIRENTD* DirentFound,
+ IN PCASEMAP Casemap
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ FindAndResolveHotfix(
+ IN PHPFS_SA SuperArea,
+ IN DEFERRED_SECTOR_TYPE ChildSectorType
+ );
+
+
+ NONVIRTUAL
+ VOID
+ SetParents(
+ LBN ParentLbn,
+ LBN ParentFnodeLbn
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryEntryOffset(
+ IN PDIRENTD Entry
+ );
+
+ NONVIRTUAL
+ VOID
+ FixupChildren(
+ PHOTFIXLIST HotfixList = NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ TakeCensusAndClear(
+ IN OUT PHPFS_BITMAP VolumeBitmap,
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap,
+ IN OUT PHPFS_CENSUS Census
+ );
+
+ NONVIRTUAL
+ PDIRENTD
+ GetFirstEntry(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsEmptyDirectory(
+ );
+
+ friend class HPFS_DIRECTORY_TREE;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ InsertDirent(
+ IN PDIRENTD NewDirent,
+ OUT PBOOLEAN ErrorOccurred,
+ IN PCASEMAP Casemap,
+ IN PUCHAR InsertPoint = NULL,
+ IN ULONG NewDownPointer = 0
+ );
+
+ NONVIRTUAL
+ PDIRENTD
+ FindSplitPoint(
+ );
+
+ NONVIRTUAL
+ PDIRENTD
+ EndEntry(
+ );
+
+ NONVIRTUAL
+ PDIRENTD
+ LastNonEndEntry(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsEmpty(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ PDIRBLKD _pdb;
+
+ HMEM _mem;
+
+ PLOG_IO_DP_DRIVE _Drive;
+
+ BOOLEAN _IsModified;
+
+};
+
+
+INLINE
+BOOLEAN
+DIRBLK::IsDirblk(
+ )
+/*++
+
+Routine description:
+
+ Checks the signature of the Dirblk to make sure that this is
+ indeed an Dirblk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the signature is the Dirblk signature.
+
+--*/
+{
+ return( _pdb->sig == DirblkSignature );
+}
+
+
+
+INLINE
+VOID
+DIRBLK::MarkModified(
+ )
+/*++
+
+Routine description:
+
+ Mark the Dirblk as modified, so that when it comes time to flush
+ it we know we'd like to write it.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _IsModified = TRUE;
+}
+
+
+
+INLINE
+VOID
+DIRBLK::MarkUnmodified(
+ )
+/*++
+
+Routine description:
+
+ Mark the Dirblk as unmodified, so that when it comes time to flush
+ it we know we don't need to write it.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _IsModified = FALSE;
+}
+
+
+
+INLINE
+BOOLEAN
+DIRBLK::IsModified(
+ )
+/*++
+
+Routine description:
+
+ Query whether the Dirblk has been modified since our last I/O
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the Dirlblk has been modified.
+
+--*/
+{
+ return _IsModified;
+}
+
+
+
+INLINE
+ULONG
+DIRBLK::QueryEntryOffset(
+ IN PDIRENTD Entry
+ )
+/*++
+
+Routine Description:
+
+ Compute the offset into the dirblk of an entry
+
+Arguments:
+
+ Entry -- Supplies the entry whose offset we want
+
+Return Value:
+
+ Offset of entry into DIRBLK; zero if error.
+
+--*/
+{
+ ULONG Offset;
+
+ Offset = (PBYTE)Entry - (PBYTE)_pdb;
+
+ return (Offset >= DIRBLK_SIZE) ? 0 : Offset;
+}
+
+
+INLINE
+PDIRENTD
+DIRBLK::GetFirstEntry(
+ )
+{
+ return FIRST_ENTRY( _pdb );
+}
+
+
+INLINE
+BOOLEAN
+DIRBLK::IsEmpty(
+ )
+{
+ return( GetFirstEntry()->fFlags & DF_END );
+}
+
+
+
+
+#endif
diff --git a/private/utils/uhpfs/inc/dircache.hxx b/private/utils/uhpfs/inc/dircache.hxx
new file mode 100644
index 000000000..c0ceaab7a
--- /dev/null
+++ b/private/utils/uhpfs/inc/dircache.hxx
@@ -0,0 +1,169 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ dircache.hxx
+
+Abstract:
+
+ Definitions for the HPFS DIRBLK cache object
+
+Author:
+
+ Bill McJohn (billmc) 16-Jan-1989
+
+Notes:
+
+ The DIRBLK cache is used by the Directory Tree object.
+
+
+--*/
+
+#if ! defined(DIRBLK_CACHE_DEFN)
+
+#define DIRBLK_CACHE_DEFN
+
+#include "dirblk.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( DIRBLK_CACHE_ELEMENT );
+DECLARE_CLASS( DIRBLK_CACHE );
+DECLARE_CLASS( HOTFIXLIST );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+
+ULONG const DirblkCacheSize = 64;
+
+class DIRBLK_CACHE_ELEMENT : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( DIRBLK_CACHE_ELEMENT );
+
+ VIRTUAL
+ ~DIRBLK_CACHE_ELEMENT(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ PLOG_IO_DP_DRIVE Drive,
+ PHOTFIXLIST HotfixList
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Read(
+ LBN DirblkLbn,
+ BOOLEAN OmitRead
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Flush(
+ );
+
+ NONVIRTUAL
+ LBN
+ QueryLbn(
+ );
+
+ NONVIRTUAL
+ PDIRBLK
+ GetDirblk(
+ );
+
+ NONVIRTUAL
+ VOID
+ Hold(
+ );
+
+ NONVIRTUAL
+ VOID
+ Unhold(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsFree(
+ );
+
+ NONVIRTUAL
+ VOID
+ MarkModified(
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ BOOLEAN _IsUnused;
+ DIRBLK _Dirblk;
+ ULONG _HoldCount;
+
+};
+
+class DIRBLK_CACHE : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( DIRBLK_CACHE );
+
+ VIRTUAL
+ ~DIRBLK_CACHE(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ PLOG_IO_DP_DRIVE Drive,
+ PHOTFIXLIST HotfixList
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Flush(
+ );
+
+ NONVIRTUAL
+ PDIRBLK_CACHE_ELEMENT
+ GetCachedDirblk(
+ LBN DirblkLbn,
+ BOOLEAN OmitRead = FALSE
+ );
+
+ NONVIRTUAL
+ GetDrive(
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ ULONG _NextVictim;
+ DIRBLK_CACHE_ELEMENT _Cache[DirblkCacheSize];
+
+};
+
+
+#endif
diff --git a/private/utils/uhpfs/inc/dirmap.hxx b/private/utils/uhpfs/inc/dirmap.hxx
new file mode 100644
index 000000000..79ac3f6aa
--- /dev/null
+++ b/private/utils/uhpfs/inc/dirmap.hxx
@@ -0,0 +1,147 @@
+/***************************************************************************\
+
+CLASS: HPFS_DIR_BITMAP
+
+PURPOSE: To model the directory band bit map.
+
+INTERFACE:
+
+ Create Create a new dir band bit map.
+ GetDirblkLbn Returns the lbn of the next free dir block and
+ marks it as used.
+ SetFree Mark a dir block as free.
+ IsFree Returns true if dir block is free.
+ QueryDirblks Query the total number of dir blocks in dir band.
+
+NOTES:
+
+HISTORY:
+
+ 14-Jan-91 billmc
+ make it a hotfix_secrun
+
+ 27-Aug-90 norbertk
+ Create
+
+KEYWORDS:
+
+SEEALSO:
+
+\***************************************************************************/
+
+#if ! defined(HPFS_DIR_BITMAP_DEFN)
+
+#define HPFS_DIR_BITMAP_DEFN
+
+#include "bitvect.hxx"
+#include "hfsecrun.hxx"
+#include "hmem.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( HOTFIXLIST );
+DECLARE_CLASS( HPFS_DIR_BITMAP );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+
+#define DIRMAP_SIZE 2048 // The number of bytes in a dir band bit map.
+
+class HPFS_DIR_BITMAP : public HOTFIX_SECRUN {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( HPFS_DIR_BITMAP );
+
+ VIRTUAL
+ ~HPFS_DIR_BITMAP(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ PLOG_IO_DP_DRIVE Drive,
+ PHOTFIXLIST HotfixList,
+ LBN StartLbn,
+ SECTORCOUNT SectorsInBand,
+ LBN FirstDirblkLbn
+ );
+
+ BOOLEAN
+ Create(
+ );
+
+ LBN
+ GetDirblkLbn(
+ BOOLEAN Backward = FALSE
+ );
+
+ BOOLEAN
+ SetAllocated(
+ LBN Lbn,
+ SECTORCOUNT BlockCount
+ );
+
+ BOOLEAN
+ SetFree(
+ LBN Lbn,
+ SECTORCOUNT BlockCount
+ );
+
+ BOOLEAN
+ IsFree(
+ LBN lbn
+ ) const;
+
+ ULONG
+ QueryDirblks(
+ ) const { return _NumberOfDirblks; }
+
+ BOOLEAN
+ QueryNextOrphan(
+ OUT PLBN NextOrphan,
+ IN OUT PBOOLEAN AllocationErrors
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AndWithDisk(
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryFreeDirblks(
+ ) CONST;
+
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy();
+
+ HMEM _Mem;
+
+ PLOG_IO_DP_DRIVE _Drive;
+ PHOTFIXLIST _HotfixList;
+
+ BITVECTOR _Bitmap;
+
+
+ ULONG _NumberOfDirblks; // The total number of dirblks.
+ ULONG _idb; // Points to next free dirblk.
+ LBN _FirstDirblkLbn; // The starting lbn of the dir band.
+ LBN _DirblkMapLbn; // starting lbn of dirblk bitmap
+
+ PHOTFIX_SECRUN _OrphanScanBlock;
+ HMEM _OrphanScanMem;
+ LBN _OrphanIndex;
+ BITVECTOR _OrphanBitmap;
+};
+
+#endif
diff --git a/private/utils/uhpfs/inc/dirtree.hxx b/private/utils/uhpfs/inc/dirtree.hxx
new file mode 100644
index 000000000..71028eeea
--- /dev/null
+++ b/private/utils/uhpfs/inc/dirtree.hxx
@@ -0,0 +1,212 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ dirtree.hxx
+
+Abstract:
+
+ Definitions for the HPFS directory tree object
+
+Author:
+
+ Bill McJohn (billmc) 16-Jan-1989
+
+Notes:
+
+
+--*/
+
+#if ! defined(HPFS_DIRECTORY_TREE_DEFN)
+
+#define HPFS_DIRECTORY_TREE_DEFN
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( DIRBLK );
+DECLARE_CLASS( DIRBLK_CACHE );
+DECLARE_CLASS( DIRBLK_CACHE_ELEMENT );
+DECLARE_CLASS( HPFS_DIRECTORY_TREE );
+DECLARE_CLASS( HPFS_NAME );
+DECLARE_CLASS( HPFS_SA );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+
+
+// WorstCaseSplit is the number of dirblks we would need to allocate for
+// a worst-case split. Eight will allow us to split a five-level tree
+// even if we have to discard two due to hotfixing.
+
+CONST ULONG WorstCaseSplit = 8;
+
+class HPFS_DIRECTORY_TREE : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( HPFS_DIRECTORY_TREE );
+
+ VIRTUAL
+ ~HPFS_DIRECTORY_TREE(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PHPFS_SA SuperArea,
+ IN PDIRBLK_CACHE Cache,
+ IN LBN RootDirblkLbn,
+ IN LBN FnodeLbn
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Insert(
+ IN PDIRENTD NewDirent
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryDirentFromName(
+ IN PHPFS_NAME Name,
+ OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ OUT PBOOLEAN Error
+ );
+
+ NONVIRTUAL
+ LBN
+ QueryFnodeLbnFromName(
+ IN PHPFS_NAME Name
+ );
+
+ NONVIRTUAL
+ LBN
+ QueryRootDirblkLbn(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Delete(
+ IN PHPFS_NAME Name
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Sort(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CheckOrder(
+ PLOG_IO_DP_DRIVE Drive,
+ OUT PBOOLEAN IsBadlyOrdered
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ UpdateDirent(
+ IN PDIRENTD SourceDirent
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FindName(
+ IN PHPFS_NAME Name,
+ OUT PDIRENTD* DirentFound,
+ OUT PDIRBLK* DirblkFound,
+ OUT PDIRBLK_CACHE_ELEMENT* HeaderFound
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ InsertIntoDirblk(
+ PDIRENTD NewDirent,
+ PDIRBLK Dirblk,
+ PDIRBLK_CACHE_ELEMENT Header,
+ PBYTE InsertionPoint = NULL,
+ LBN NewDownpointer = 0
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CreateNewRoot(
+ PDIRENTD DirentToPromote,
+ LBN EndDownPointer
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Merge(
+ PDIRBLK FirstDirblk,
+ PDIRBLK_CACHE_ELEMENT FirstHeader,
+ PDIRBLK SecondDirblk,
+ PDIRBLK_CACHE_ELEMENT SecondHeader,
+ PDIRBLK ParentDirblk,
+ PDIRBLK_CACHE_ELEMENT ParentHeader,
+ PDIRENTD ParentEntry
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Balance(
+ PDIRBLK FirstDirblk,
+ PDIRBLK_CACHE_ELEMENT FirstHeader,
+ PDIRBLK SecondDirblk,
+ PDIRBLK_CACHE_ELEMENT SecondHeader,
+ PDIRBLK ParentDirblk,
+ PDIRBLK_CACHE_ELEMENT ParentHeader,
+ PDIRENTD ParentEntry
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Adjust(
+ PDIRBLK_CACHE_ELEMENT TargetHeader,
+ PDIRBLK TargetDirblk
+ );
+
+ NONVIRTUAL
+ VOID
+ FreeDirblks(
+ LBN DirblkLbn
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SortFromDirblk(
+ LBN DirblkLbn,
+ HPFS_DIRECTORY_TREE* TargetTree,
+ PDIRENTD Buffer
+ );
+
+ BOOLEAN
+ CheckOrderFromDirblk(
+ PLOG_IO_DP_DRIVE Drive,
+ IN LBN DirblkLbn,
+ IN OUT PHPFS_NAME PreviousName,
+ IN OUT PBOOLEAN IsBadlyOrdered
+ );
+
+ PDIRBLK_CACHE _Cache;
+ PHPFS_SA _SuperArea;
+ LBN _RootDirblkLbn;
+ LBN _FnodeLbn;
+
+};
+
+#endif
diff --git a/private/utils/uhpfs/inc/fnode.hxx b/private/utils/uhpfs/inc/fnode.hxx
new file mode 100644
index 000000000..e4291eead
--- /dev/null
+++ b/private/utils/uhpfs/inc/fnode.hxx
@@ -0,0 +1,461 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ fnode.hxx
+
+Abstract:
+
+ This module contains declarations for the FNODE object,
+ which models an HPFS file or directory FNode.
+
+Author:
+
+ Bill McJohn (billmc) 01-Dec-1990
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#if ! defined( FNODE_DEFN )
+
+#define FNODE_DEFN
+
+#include "hmem.hxx"
+#include "secrun.hxx"
+#include "store.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( DEFERRED_ACTIONS_LIST );
+DECLARE_CLASS( FNODE );
+DECLARE_CLASS( HOTFIXLIST );
+DECLARE_CLASS( HPFS_BITMAP );
+DECLARE_CLASS( HPFS_CENSUS );
+DECLARE_CLASS( HPFS_MAIN_BITMAP );
+DECLARE_CLASS( HFPS_ORPHANS );
+DECLARE_CLASS( HPFS_PATH );
+DECLARE_CLASS( HPFS_SA );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( MESSAGE );
+
+
+typedef ULONG HPFSSIG; // sig
+
+
+#define CUID 16
+#define CSPARE 10
+
+
+CONST USHORT cbFnodeName = 16;
+CONST USHORT FNF_DIR = 1; // is a directory fnode
+
+
+/** File Allocation Tracking
+ *
+ * File space is allocated as a list of extents, each extent as
+ * large as we can make it. This list is kept in a B+TREE format.
+ * Each B+TREE block consists of a single sector containing an
+ * ALSEC record, except for the top most block. The topmost block
+ * consists of just an ALBLK structure, is usually much smaller than
+ * 512 bytes, and is typically included in another structure.
+ *
+ * The leaf block(s) in the tree contain triples which indicate
+ * the logical to physical mapping for this file. Typically this
+ * extent list is small enough that it is wholy contained in the
+ * fnode ALBLK stucture. If more than ALCNT extents are required
+ * then the tree is split into two levels. Note that when the
+ * topmost B+TREE block is 'split' no actual split is necessary,
+ * since the new child block is much bigger than the parent block
+ * and can contain all of the old records plus the new one. Thus,
+ * we can have B+TREEs where the root block contains only one
+ * downpointer.
+ *
+ * The following rules apply:
+ *
+ * 1) if the file is not empty, there is at least one sector allocated
+ * to logical offset 0. This simplifys some critical loops.
+ *
+ * 2) The last entry in the last node block contains a AN_LOF value of
+ * FFFFFFFF. This allows us to extend that last leaf block
+ * without having to update the node block.
+ *
+ * 3) For the node records, the AN_SEC points to a node or leaf
+ * sector which describes extents which occur before that
+ * record's AN_LOF value.
+ */
+
+/** Fnode block definition
+ *
+ * Every file and directory has an FNODE. The file location
+ * stuff is only used for files; directories are kept in
+ * a BTREE of DIRBLK records pointed to by fst.alf [0].lbnPhys.
+ */
+
+struct _FNODE { // _fn
+
+ struct _FNODE_INFO { // _fni
+
+ HPFSSIG sig; // signature value
+ ULONG ulSRHist; // sequential read history
+ ULONG ulFRHist; // fast read history
+
+ // First bytes of file name. The first byte of this array is the
+ // DIR_NAML from a DIRENT. The remaining bytes are from the
+ // DIR_NAMA field. If FN_NAME[0] <= 15, the entire name follows.
+ // This info is for chkdsk; format should set up the root name as
+ // "."
+ CHAR achName[cbFnodeName];
+
+ LBN lbnContDir; // fnode of dir containing
+ // this file/dir
+
+ ULONG cbRunACL; // was AUXINFO / SPTR
+ LBN lbnACL; // :
+ USHORT usFNLACL; // :
+ BYTE bDatACL; // :
+
+ BYTE cHistBits; // count of valid history bits
+
+ ULONG cbRunEA; // was AUXINFO / SPTR
+ LBN lbnEA; // :
+ USHORT usFNLEA; // :
+ BYTE bDatEA; // :
+
+ BYTE bFlag; // FNODE flag byte
+
+ FNODE_STORE fn_store; // was FILESTORAGE
+ ULONG ulVlen; // :
+
+ ULONG ulRefCount; // number of "need" EAs in file
+ CHAR achUID[CUID]; // reserved for UID value
+ USHORT usACLBase; // offset of 1st ACE in fnode
+ BYTE abSpare[CSPARE];// more bytes emergency spares
+
+ } _fni;
+
+ // Free pool. ACLs and EAs are stored here via the AUXINFO structure
+ BYTE abFree[cbSector - sizeof(_FNODE_INFO)];
+
+};
+
+class FNODE : public SECRUN {
+
+ public:
+
+ UHPFS_EXPORT
+ DECLARE_CONSTRUCTOR( FNODE );
+
+ UHPFS_EXPORT
+ VIRTUAL
+ ~FNODE(
+ );
+
+ UHPFS_EXPORT
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PLOG_IO_DP_DRIVE,
+ IN LBN Lbn
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CreateRoot(
+ IN LBN DirblkLbn
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CreateFile(
+ IN LBN ParentFnodeLbn
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CreateNode(
+ IN LBN ParentFnodeLbn,
+ IN LBN AlsecLbn,
+ IN ULONG FileSize
+ );
+
+ NONVIRTUAL
+ LBN
+ QueryRootDirblkLbn(
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetRootDirblkLbn(
+ IN LBN NewRootLbn
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsValid (
+ ) CONST;
+
+ NONVIRTUAL
+ VERIFY_RETURN_CODE
+ VerifyAndFix(
+ IN PHPFS_SA SuperArea,
+ IN PDEFERRED_ACTIONS_LIST DeferredActions,
+ IN PHPFS_PATH CurrentPath,
+ IN LBN ExpectedParentLbn,
+ IN BOOLEAN IsDir,
+ IN OUT PULONG DirentFileSize,
+ OUT PULONG EaSize,
+ IN PMESSAGE Message,
+ IN OUT PBOOLEAN ErrorsDetected,
+ IN BOOLEAN UpdateAllowed DEFAULT FALSE,
+ IN BOOLEAN Verbose DEFAULT FALSE,
+ IN PHPFS_ORPHANS OrphansList DEFAULT NULL
+ );
+
+ UHPFS_EXPORT
+ NONVIRTUAL
+ BOOLEAN
+ IsFnode(
+ );
+
+ NONVIRTUAL
+ VOID
+ MarkModified(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsModified(
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryAllocatedSize(
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryValidLength(
+ );
+
+ NONVIRTUAL
+ VOID
+ SetValidLength(
+ ULONG NewValidLength
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryNumberOfNeedEas(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FindAndResolveHotfix(
+ IN PHPFS_SA SuperArea,
+ IN DEFERRED_SECTOR_TYPE ChildSectorType
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ResolveCrosslink(
+ IN PHPFS_SA SuperArea,
+ IN ULONG RunIndex
+ );
+
+ NONVIRTUAL
+ VOID
+ SetParent(
+ IN LBN ParentLbn
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FNODE::CheckParent(
+ IN LBN ParentLbn
+ );
+
+ NONVIRTUAL
+ LBN
+ QueryPhysicalLbn(
+ IN LBN FileBlockNumber,
+ OUT PULONG RunLength
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Truncate(
+ IN LBN SectorCount
+ );
+
+ UHPFS_EXPORT
+ NONVIRTUAL
+ BOOLEAN
+ QueryExtents(
+ IN ULONG MaximumNumberOfExtents,
+ OUT PVOID ExtentList,
+ OUT PULONG NumberOfExtents
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ StoreExtents(
+ IN ULONG NumberOfExtents,
+ IN PALLEAF ExtentList,
+ IN OUT PHPFS_BITMAP VolumeBitmap
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ TakeCensusAndClear(
+ IN BOOLEAN IsDir,
+ IN OUT PHPFS_BITMAP VolumeBitmap,
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap,
+ IN OUT PHPFS_CENSUS Census
+ );
+
+ UHPFS_EXPORT
+ NONVIRTUAL
+ BOOLEAN
+ QueryPackedEaList(
+ OUT PVOID OutputBuffer,
+ IN ULONG BufferLength,
+ OUT PULONG PackedLength,
+ OUT PBOOLEAN IsCorrupt,
+ IN PHOTFIXLIST HotfixList
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ PLOG_IO_DP_DRIVE _Drive;
+
+ HMEM _buf;
+ STORE _Store;
+
+ _FNODE* p_fn;
+ BOOLEAN _IsModified;
+
+};
+
+INLINE
+BOOLEAN
+FNODE::IsValid (
+ ) CONST
+/*++
+
+Routine Description:
+
+ Determine if this FNODE appears valid.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if FNODE appears valid
+--*/
+{
+
+ DebugAssert( p_fn != NULL );
+
+ if( p_fn ) {
+ return p_fn->_fni.sig == FnodeSignature;
+ } else {
+ return FALSE;
+ }
+}
+
+
+INLINE
+LBN
+FNODE::QueryRootDirblkLbn(
+ ) CONST
+/*++
+
+Routine Description:
+
+ Return the lbn of the root dirblk
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ the first physical LBN allocated by the FNode; if this is a
+ directory FNode, that is the LBN of the directory's root dirblk.
+--*/
+{
+ return p_fn ? p_fn->_fni.fn_store.a.alleaf[0].lbnPhys : 0;
+}
+
+
+INLINE
+ULONG
+FNODE::QueryValidLength(
+ )
+/*++
+
+Routine Description:
+
+ This method returns the FNode's Valid Data length. Note that
+ this value is not meaningful for directory FNodes.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The FNode's Valid Data length.
+
+--*/
+{
+ return p_fn->_fni.ulVlen;
+}
+
+INLINE
+VOID
+FNODE::SetValidLength(
+ ULONG NewValidLength
+ )
+/*++
+
+Routine Description:
+
+ This method sets the FNode's Valid Data length. Note that
+ this value is not meaningful for directory FNodes.
+
+Arguments:
+
+ NewValidLength -- Supplies the new valid length of the file.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ p_fn->_fni.ulVlen = NewValidLength;
+}
+
+
+#endif // FNODE_DEFN
diff --git a/private/utils/uhpfs/inc/hfsecrun.hxx b/private/utils/uhpfs/inc/hfsecrun.hxx
new file mode 100644
index 000000000..051bb1cad
--- /dev/null
+++ b/private/utils/uhpfs/inc/hfsecrun.hxx
@@ -0,0 +1,124 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ hfsecrun.hxx
+
+Abstract:
+
+ This class expands the functionality of SECRUN to cover runs of
+ sectors that may be replaced according to a hotfix-list.
+
+Author:
+
+ Bill McJohn (billmc) 30-Dec-90
+
+--*/
+
+#if !defined(HOTFIX_SECRUN_DEFN)
+
+#define HOTFIX_SECRUN_DEFN
+
+#include "secrun.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( HOTFIX_SECRUN );
+DECLARE_CLASS( HOTFIXLIST );
+DECLARE_CLASS( IO_DP_DRIVE );
+DECLARE_CLASS( MEM );
+
+class HOTFIX_SECRUN : public SECRUN {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( HOTFIX_SECRUN );
+
+ VIRTUAL
+ ~HOTFIX_SECRUN(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PIO_DP_DRIVE Drive,
+ IN PHOTFIXLIST HotfixList,
+ IN LBN StartSector,
+ IN SECTORCOUNT NumSectors
+ );
+
+ UHPFS_EXPORT
+ NONVIRTUAL
+ VOID
+ Relocate(
+ LBN NewLbn
+ );
+
+ UHPFS_EXPORT
+ NONVIRTUAL
+ BOOLEAN
+ Read(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Write(
+ );
+
+ NONVIRTUAL
+ VOID
+ SetHotfixList(
+ IN PHOTFIXLIST HotfixList
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ PIO_DP_DRIVE _drive;
+ PHOTFIXLIST _hotfix_list;
+ LBN _start_sector;
+ SECTORCOUNT _num_sectors;
+ PVOID _buf;
+
+};
+
+INLINE
+VOID
+HOTFIX_SECRUN::SetHotfixList(
+ IN PHOTFIXLIST HotfixList
+ )
+/*++
+
+Routine Description:
+
+ This routine updates the objects current hotfix list.
+
+Arguments:
+
+ HotfixList - Supplies a new hotfix list for this object.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _hotfix_list = HotfixList;
+}
+
+
+#endif // HOTFIX_SECRUN_DEFN
diff --git a/private/utils/uhpfs/inc/hotfix.hxx b/private/utils/uhpfs/inc/hotfix.hxx
new file mode 100644
index 000000000..e841d9b30
--- /dev/null
+++ b/private/utils/uhpfs/inc/hotfix.hxx
@@ -0,0 +1,216 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ hotfix.hxx
+
+Abstract:
+
+ A list of sectors that went bad after the last format. List
+ is cleared by chkdsk.
+
+Author:
+
+ Mark Shavlik (marks) 27-Mar-90
+
+--*/
+
+#if ! defined (HOTFIX_DEFN)
+
+#define HOTFIX_DEFN
+
+
+#include "hmem.hxx"
+#include "verify.hxx"
+#include "secrun.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( BADBLOCKLIST );
+DECLARE_CLASS( HPFS_BITMAP );
+DECLARE_CLASS( HPFS_MAIN_BITMAP );
+DECLARE_CLASS( HPFS_SA );
+DECLARE_CLASS( HOTFIXLIST );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( SPAREB );
+
+#define NUM_SECTIONS 3 // Bad, New, Reserved.
+
+#define HOTFIX_MAX_LBN 512
+#define SECTORS_IN_HOTFIX_BLOCK 4
+
+struct HOTFIXD { // hfd
+
+ LBN lbn[512];
+
+};
+
+class HOTFIXLIST : public SECRUN {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( HOTFIXLIST );
+
+ VIRTUAL
+ ~HOTFIXLIST(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ PLOG_IO_DP_DRIVE Drive,
+ PSPAREB SparesBlock
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Create(
+ PHPFS_BITMAP Bitmap,
+ LBN Lbn
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryHotFixCount(
+ ) CONST { return _NumberOfHotfixes; }
+
+ NONVIRTUAL
+ ULONG
+ QueryMaxHotFixes(
+ ) CONST { return _MaximumHotfixes; }
+
+ NONVIRTUAL
+ LBN
+ AddBad(
+ LBN lbnBad,
+ PSPAREB
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsInList(
+ IN LBN StartLbn,
+ IN SECTORCOUNT SectorCount
+ ) CONST;
+
+ NONVIRTUAL
+ LBN
+ GetLbnTranslation(
+ IN LBN CurrentLbn
+ ) CONST;
+
+ NONVIRTUAL
+ VERIFY_RETURN_CODE
+ VerifyAndFix(
+ IN PHPFS_SA SuperArea
+ );
+
+ NONVIRTUAL
+ VOID
+ Print(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ FirstHotfixInRun(
+ IN LBN StartLbn,
+ IN SECTORCOUNT SectorCount
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ MarkAllUsed(
+ IN OUT PHPFS_BITMAP Bitmap
+ );
+
+ NONVIRTUAL
+ VOID
+ ClearHotfix(
+ IN LBN BadLbn,
+ IN OUT PHPFS_SA SuperArea
+ );
+
+ NONVIRTUAL
+ VOID
+ ClearRun(
+ IN LBN StartLbn,
+ IN SECTORCOUNT Length,
+ IN OUT PHPFS_SA SuperArea
+ );
+
+ NONVIRTUAL
+ VOID
+ ClearList(
+ IN OUT PHPFS_BITMAP Bitmap,
+ IN OUT PBADBLOCKLIST BadBlockList,
+ IN BOOLEAN ClearAll
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ TakeCensus(
+ IN PHPFS_BITMAP VolumeBitmap,
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ LBN
+ QueryBadLbn(
+ ULONG ilbn
+ ) CONST { return (_HotfixData && ilbn < _MaximumHotfixes) ?
+ _HotfixData->lbn[ilbn] :
+ 0; }
+ LBN
+ QueryNewLbn(
+ ULONG ilbn
+ ) CONST
+ { return (_HotfixData && ilbn < _MaximumHotfixes) ?
+ _HotfixData->lbn[_MaximumHotfixes +
+ ilbn] :
+ 0;
+ }
+
+ NONVIRTUAL
+ BOOLEAN
+ SetNewLbn(
+ ULONG ilbn,
+ LBN Lbn
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetBadLbn(
+ ULONG ilbn,
+ LBN Lbn
+ );
+
+ // _Drive and _SparesBlock are handed to the object at
+ // initialization.
+
+ PLOG_IO_DP_DRIVE _Drive;
+ PSPAREB _SparesBlock;
+
+ HMEM _Mem;
+ HOTFIXD* _HotfixData;
+ ULONG _MaximumHotfixes;
+ ULONG _NumberOfHotfixes;
+
+};
+
+
+#endif // HOTFIX_DEFN
diff --git a/private/utils/uhpfs/inc/hpcensus.hxx b/private/utils/uhpfs/inc/hpcensus.hxx
new file mode 100644
index 000000000..90f7b7fc6
--- /dev/null
+++ b/private/utils/uhpfs/inc/hpcensus.hxx
@@ -0,0 +1,420 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+
+Module Name:
+
+ hpcensus.hxx
+
+
+Abstract:
+
+ This module contains the declarations for the HPFS Census object.
+ This object is a receptacle for the information needed by Convert,
+ when the source file system is HPFS.
+
+ Information flows through the census object in both directions. The
+ source file system (HPFS as it exists on the disk) informs the target
+ file system how many files, directories, and dirblks are on disk. The
+ target file system gives the source file system a list of sectors (LBNs)
+ which must be clear of file and EA data in order for conversion to
+ proceed.
+
+
+Author:
+
+ Bill McJohn (billmc) 05-Nov-1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#if ! defined( HPFS_CENSUS_DEFN )
+
+#define HPFS_CENSUS_DEFN
+
+enum HPFS_CENSUS_ERROR {
+
+ HPFS_CENSUS_NO_ERROR,
+ HPFS_CENSUS_INSUFFICIENT_MEMORY,
+ HPFS_CENSUS_CORRUPT_VOLUME,
+ HPFS_CENSUS_HOTFIXES_PRESENT,
+ HPFS_CENSUS_RELOCATION_FAILED
+};
+
+
+DECLARE_CLASS( HPFS_BITMAP );
+
+class HPFS_CENSUS : public OBJECT {
+
+ public:
+
+ UHPFS_EXPORT
+ DECLARE_CONSTRUCTOR( HPFS_CENSUS );
+
+ UHPFS_EXPORT
+ VIRTUAL
+ ~HPFS_CENSUS(
+ );
+
+ UHPFS_EXPORT
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ ULONG MaximumClearSectors
+ );
+
+ NONVIRTUAL
+ VOID
+ AddFile(
+ );
+
+ NONVIRTUAL
+ VOID
+ AddDirectory(
+ );
+
+ NONVIRTUAL
+ VOID
+ AddDirblk(
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryNumberOfFiles(
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryNumberOfDirectories(
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryNumberOfDirblks(
+ );
+
+ UHPFS_EXPORT
+ NONVIRTUAL
+ BOOLEAN
+ AddClearSector(
+ IN LBN Lbn
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ConflictWithClearSectors(
+ IN LBN StartLbn,
+ IN ULONG RunLength,
+ OUT PLBN FirstConflictingLbn
+ );
+
+ NONVIRTUAL
+ VOID
+ MarkClearSectors(
+ IN OUT PHPFS_BITMAP VolumeBitmap
+ );
+
+ NONVIRTUAL
+ VOID
+ SetError(
+ HPFS_CENSUS_ERROR Error
+ );
+
+ NONVIRTUAL
+ HPFS_CENSUS_ERROR
+ QueryError(
+ );
+
+ NONVIRTUAL
+ VOID
+ SetRelocationPerformed(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryRelocationPerformed(
+ );
+
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ ULONG _NumberOfFiles;
+ ULONG _NumberOfDirectories;
+ ULONG _NumberOfDirblks;
+
+ ULONG _MaximumClearSectors;
+ ULONG _NumberOfClearSectors;
+
+ PLBN _ClearSectors;
+
+ HPFS_CENSUS_ERROR _Error;
+ BOOLEAN _DataRelocated;
+};
+
+
+INLINE
+VOID
+HPFS_CENSUS::AddFile(
+ )
+/*++
+
+Routine Description:
+
+ This method increments the number of files found in the census.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _NumberOfFiles += 1;
+}
+
+
+
+INLINE
+VOID
+HPFS_CENSUS::AddDirectory(
+ )
+/*++
+
+Routine Description:
+
+ This method increments the number of directories found in the census.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _NumberOfDirectories += 1;
+}
+
+
+
+INLINE
+VOID
+HPFS_CENSUS::AddDirblk(
+ )
+/*++
+
+Routine Description:
+
+ This method increments the number of dirblks found in the census.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _NumberOfDirblks += 1;
+}
+
+
+
+INLINE
+ULONG
+HPFS_CENSUS::QueryNumberOfFiles(
+ )
+/*++
+
+Routine Description:
+
+ This method returns the number of files found in the census.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ return _NumberOfFiles;
+}
+
+
+
+INLINE
+ULONG
+HPFS_CENSUS::QueryNumberOfDirectories(
+ )
+/*++
+
+Routine Description:
+
+ This method returns the number of directories found in the census.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ return _NumberOfDirectories;
+}
+
+
+
+INLINE
+ULONG
+HPFS_CENSUS::QueryNumberOfDirblks(
+ )
+/*++
+
+Routine Description:
+
+ This method returns the number of dirblks found in the census.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ return _NumberOfDirblks;
+}
+
+
+
+INLINE
+VOID
+HPFS_CENSUS::SetError(
+ HPFS_CENSUS_ERROR Error
+ )
+/*++
+
+Routine Description:
+
+ This method is used to set the Census object's error code when
+ a census fails.
+
+Arguments:
+
+ HPFS_CENSUS_ERROR Error -- supplies the reason that the census failed.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _Error = Error;
+}
+
+
+INLINE
+HPFS_CENSUS_ERROR
+HPFS_CENSUS::QueryError(
+ )
+/*++
+
+Routine Description:
+
+ This method is used to fetch the Census object's error code.
+ If a census fails, the client may call this method to find
+ out why.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The current error code (ie. the last error-code passed to SetError).
+
+--*/
+{
+ return _Error;
+}
+
+
+INLINE
+VOID
+HPFS_CENSUS::SetRelocationPerformed(
+ )
+/*++
+
+Routine Description:
+
+ This method records the fact that data relocation has been performed.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _DataRelocated = TRUE;
+}
+
+
+INLINE
+BOOLEAN
+HPFS_CENSUS::QueryRelocationPerformed(
+ )
+/*++
+
+Routine Description:
+
+ This method determines whether data has been relocated during the
+ census (in order to resolve conflicts with the Clear Sectors).
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if data has been relocated.
+
+--*/
+{
+ return _DataRelocated;
+}
+
+#endif
diff --git a/private/utils/uhpfs/inc/hpfsacl.hxx b/private/utils/uhpfs/inc/hpfsacl.hxx
new file mode 100644
index 000000000..08ec1195b
--- /dev/null
+++ b/private/utils/uhpfs/inc/hpfsacl.hxx
@@ -0,0 +1,72 @@
+#if !defined(HPFS_ACL_DEFINED)
+
+#define HPFS_ACL_DEFINED
+
+#include "fnode.hxx"
+#include "verify.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( DEFERRED_ACTIONS_LIST );
+DECLARE_CLASS( HPFS_ACL );
+DECLARE_CLASS( HPFS_SA );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( MESSAGE );
+DECLARE_CLASS( HPFS_PATH );
+DECLARE_CLASS( HPFS_ORPHANS );
+
+
+class HPFS_ACL : public OBJECT {
+
+
+ public:
+
+ DECLARE_CONSTRUCTOR( HPFS_ACL );
+
+ VIRTUAL
+ ~HPFS_ACL(
+ );
+
+ BOOLEAN
+ Initialize(
+ PLOG_IO_DP_DRIVE Drive,
+ _FNODE* FnodeData,
+ LBN FnodeLbn
+ );
+
+ VERIFY_RETURN_CODE
+ VerifyAndFix(
+ IN HPFS_SA* SuperArea,
+ IN PDEFERRED_ACTIONS_LIST DeferredActions,
+ IN PHPFS_PATH CurrentPath,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN ErrorsDetected,
+ IN BOOLEAN UpdateAllowed = FALSE,
+ IN OUT PHPFS_ORPHANS OrphansList = NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryFnodeModified(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FindAndResolveHotfix(
+ IN PHPFS_SA SuperArea
+ );
+
+
+ private:
+
+ PLOG_IO_DP_DRIVE _Drive;
+ _FNODE* _FnodeData;
+ LBN _FnodeLbn;
+
+ BOOLEAN _FnodeModified;
+
+};
+
+#endif
diff --git a/private/utils/uhpfs/inc/hpfsea.hxx b/private/utils/uhpfs/inc/hpfsea.hxx
new file mode 100644
index 000000000..217146d5c
--- /dev/null
+++ b/private/utils/uhpfs/inc/hpfsea.hxx
@@ -0,0 +1,216 @@
+
+#if !defined(HPFS_EA_DEFN)
+
+#define HPFS_EA_DEFN
+
+#include "drive.hxx"
+#include "verify.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( DEFERRED_ACTIONS_LIST );
+DECLARE_CLASS( HPFS_EA );
+DECLARE_CLASS( HPFS_ORPHANS );
+DECLARE_CLASS( HPFS_SA );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( MESSAGE );
+DECLARE_CLASS( HOTFIXLIST );
+
+
+struct _EA_DATA { // FEA
+
+ BYTE fEA; /* flags byte */
+ BYTE cbName; /* length of name */
+ BYTE cbValue[2]; /* length of value */
+
+};
+
+DEFINE_TYPE( struct _EA_DATA, EA_DATA );
+
+// This constant is the size of an EA_DATA structure.
+
+#define EA_HEADER_SIZE 4
+
+
+/*
+ * If FF_BIGD is set in the flags byte, the EA's value is stored
+ * outside the EA stream; the value field in-stream is an
+ * EA_INDIRECT record. If FF_DAT is also set, the lbn field
+ * of the EA_INDIRECT record describes an allocation sector;
+ * otherwise, the EA's value is in a single run starting at the
+ * indirect record's lbn field.
+ */
+#define FF_BIGD 0x01
+#define FF_DAT 0x02
+#define FF_NEED 0x80
+
+struct _EA_INDIRECT {
+
+ BYTE cb[4];
+ BYTE lbn[4];
+};
+
+DEFINE_TYPE( struct _EA_INDIRECT, EA_INDIRECT );
+
+class HPFS_EA : public OBJECT {
+
+
+ public:
+
+ UHPFS_EXPORT
+ DECLARE_CONSTRUCTOR( HPFS_EA );
+
+ VIRTUAL
+ UHPFS_EXPORT
+ ~HPFS_EA(
+ );
+
+ NONVIRTUAL
+ UHPFS_EXPORT
+ BOOLEAN
+ Initialize(
+ PLOG_IO_DP_DRIVE Drive,
+ PEA_DATA Data,
+ LBN ParentLbn
+ );
+
+ NONVIRTUAL
+ BYTE
+ GetFlags(
+ );
+
+ NONVIRTUAL
+ VOID
+ SetFlags(
+ BYTE NewFlags
+ );
+
+ NONVIRTUAL
+ BYTE
+ GetNameLength(
+ );
+
+ NONVIRTUAL
+ VOID
+ SetNameLength(
+ BYTE NewNameLength
+ );
+
+ NONVIRTUAL
+ USHORT
+ GetValueLength(
+ );
+
+ NONVIRTUAL
+ VOID
+ SetValueLength(
+ USHORT NewValueLength
+ );
+
+ NONVIRTUAL
+ PBYTE
+ GetName(
+ );
+
+ NONVIRTUAL
+ PBYTE
+ GetValue(
+ );
+
+ NONVIRTUAL
+ VERIFY_RETURN_CODE
+ VerifyAndFix(
+ IN PHPFS_SA SuperArea,
+ IN PDEFERRED_ACTIONS_LIST DeferredActions,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN ErrorsDetected,
+ IN BOOLEAN UpdateAllowed = FALSE,
+ IN OUT PHPFS_ORPHANS OrphansList = NULL
+ );
+
+ NONVIRTUAL
+ VOID
+ MarkModified(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsModified(
+ );
+
+ NONVIRTUAL
+ ULONG
+ QuerySize(
+ );
+
+ NONVIRTUAL
+ UHPFS_EXPORT
+ USHORT
+ QueryLength(
+ );
+
+ NONVIRTUAL
+ UHPFS_EXPORT
+ BOOLEAN
+ IsNeedEa(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FindAndResolveHotfix(
+ PHPFS_SA SuperArea
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryPackedEa(
+ OUT PVOID OutputBuffer,
+ IN ULONG BufferLength,
+ IN OUT PULONG OffsetIntoBuffer,
+ OUT PBOOLEAN IsCorrupt,
+ IN PHOTFIXLIST HotfixList
+ );
+
+
+ private:
+
+ STATIC
+ LBN
+ GetLbnFromEaIndirect(
+ PEA_INDIRECT peaind
+ );
+
+ STATIC
+ ULONG
+ GetLengthFromEaIndirect(
+ PEA_INDIRECT peaind
+ );
+
+ STATIC
+ VOID
+ SetLbnInEaIndirect(
+ PEA_INDIRECT peaind,
+ LBN Lbn
+ );
+
+ STATIC
+ VOID
+ SetLengthInEaIndirect(
+ PEA_INDIRECT peaind,
+ ULONG cb
+ );
+
+
+ // _Drive and _Data are supplied on initialization
+
+ PLOG_IO_DP_DRIVE _Drive;
+ PEA_DATA _Data;
+ LBN _ParentLbn;
+
+ BOOLEAN _IsModified;
+
+};
+
+#endif
diff --git a/private/utils/uhpfs/inc/hpfseal.hxx b/private/utils/uhpfs/inc/hpfseal.hxx
new file mode 100644
index 000000000..8f9e369a2
--- /dev/null
+++ b/private/utils/uhpfs/inc/hpfseal.hxx
@@ -0,0 +1,154 @@
+#if !defined(HPFS_EA_LIST_DEFINED)
+
+#define HPFS_EA_LIST_DEFINED
+
+#include "fnode.hxx"
+#include "hmem.hxx"
+#include "secrun.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( DEFERRED_ACTIONS_LIST );
+DECLARE_CLASS( HPFS_EA_LIST );
+DECLARE_CLASS( HPFS_ORPHANS );
+DECLARE_CLASS( HPFS_PATH );
+DECLARE_CLASS( HPFS_SA );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( MESSAGE );
+DECLARE_CLASS( HOTFIXLIST );
+
+
+class HPFS_EA_LIST : public OBJECT {
+
+
+ public:
+
+ DECLARE_CONSTRUCTOR( HPFS_EA_LIST );
+
+ VIRTUAL
+ ~HPFS_EA_LIST(
+ );
+
+ BOOLEAN
+ Initialize(
+ PLOG_IO_DP_DRIVE Drive,
+ _FNODE* FnodeData,
+ LBN FnodeLbn
+ );
+
+ VERIFY_RETURN_CODE
+ VerifyAndFix(
+ IN OUT PHPFS_SA SuperArea,
+ IN OUT PDEFERRED_ACTIONS_LIST DeferredActions,
+ IN PHPFS_PATH CurrentPath,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN ErrorsDetected,
+ IN BOOLEAN UpdateAllowed = FALSE,
+ IN OUT PHPFS_ORPHANS OrphansList = NULL
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryNumberOfEas(
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryNumberOfNeedEas(
+ );
+
+ NONVIRTUAL
+ ULONG
+ QuerySizeOfEas(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryFnodeModified(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FindAndResolveHotfix(
+ IN OUT PHPFS_SA SuperArea
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryPackedEaList(
+ OUT PVOID OutputBuffer,
+ IN ULONG BufferLength,
+ OUT PULONG PackedLength,
+ OUT PBOOLEAN IsCorrupt,
+ IN PHOTFIXLIST HotfixList DEFAULT NULL
+ );
+
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VERIFY_RETURN_CODE
+ VerifyOnDiskRun(
+ IN OUT PHPFS_SA SuperArea,
+ IN OUT PDEFERRED_ACTIONS_LIST DeferredActions,
+ IN PHPFS_PATH CurrentPath,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN ErrorsDetected,
+ IN BOOLEAN UpdateAllowed,
+ IN OUT PHPFS_ORPHANS OrphansList
+ );
+
+ NONVIRTUAL
+ VERIFY_RETURN_CODE
+ VerifyInTree(
+ IN OUT PHPFS_SA SuperArea,
+ IN OUT PDEFERRED_ACTIONS_LIST DeferredActions,
+ IN PHPFS_PATH CurrentPath,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN ErrorsDetected,
+ IN BOOLEAN UpdateAllowed,
+ IN OUT PHPFS_ORPHANS OrphansList
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FindAndResolveHotfixOnDiskRun(
+ IN OUT PHPFS_SA SuperArea
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FindAndResolveHotfixInTree(
+ IN OUT PHPFS_SA SuperArea
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ HPFS_EA_LIST::ReadList(
+ IN OUT PVOID TargetBuffer,
+ IN ULONG TargetBufferLength,
+ IN PHOTFIXLIST HotfixList,
+ IN OUT PBOOLEAN IsCorrupt
+ );
+
+
+
+ PLOG_IO_DP_DRIVE _Drive;
+ _FNODE* _FnodeData;
+
+ LBN _FnodeLbn;
+
+ BOOLEAN _FnodeModified;
+ ULONG _NumberOfEas;
+ ULONG _NumberOfNeedEas;
+ ULONG _SizeOfEas;
+};
+
+#endif;
diff --git a/private/utils/uhpfs/inc/hpfsname.hxx b/private/utils/uhpfs/inc/hpfsname.hxx
new file mode 100644
index 000000000..0a98bdf05
--- /dev/null
+++ b/private/utils/uhpfs/inc/hpfsname.hxx
@@ -0,0 +1,248 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ hpfsname.hxx
+
+Abstract:
+
+ The names used by HPFS volumes require knowledge of the
+ volume codepages, and must meet certain validity constraints.
+ The HPFS_NAME and HPFS_PATH objects encapsulate thes information.
+
+Author:
+
+ Bill McJohn (billmc) 02-Jan-1991
+
+--*/
+
+#if !defined ( HPFS_NAME_DEFN )
+
+#define HPFS_NAME_DEFN
+
+#include "intstack.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( CASEMAP );
+DECLARE_CLASS( HPFS_NAME );
+DECLARE_CLASS( HPFS_PATH );
+
+CONST PremappedCodepage = 0xff00;
+CONST MaximumPathLength = 300;
+CONST MaximumNameLength = 256;
+
+enum NAME_COMPARE_RETURN {
+
+ NAME_IS_LESS_THAN, NAME_IS_EQUAL_TO, NAME_IS_GREATER_THAN
+};
+
+class HPFS_PATH : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( HPFS_PATH );
+
+ VIRTUAL
+ ~HPFS_PATH(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AddLevel(
+ PHPFS_NAME Name
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ StripLevel(
+ );
+
+ NONVIRTUAL
+ PHPFS_NAME
+ QueryFirstLevel(
+ );
+
+ NONVIRTUAL
+ PHPFS_NAME
+ QueryNextLevel(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Copy(
+ PHPFS_PATH OtherPath
+ );
+
+ NONVIRTUAL
+ PCUCHAR
+ GetString(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsRoot(
+ ) CONST;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ PBYTE _Buffer;
+ ULONG _CurrentLength;
+ ULONG _CurrentLevelIndex;
+
+ INTSTACK _ComponentOffsets;
+
+};
+
+INLINE
+BOOLEAN
+HPFS_PATH::IsRoot(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method determines whether the path is to the root directory.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the path is the root (ie. is empty)
+
+--*/
+{
+ return( _CurrentLength == 0 );
+}
+
+class HPFS_NAME : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( HPFS_NAME );
+
+ VIRTUAL
+ ~HPFS_NAME(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ ULONG Length,
+ PUCHAR String,
+ ULONG VolumeCodepageIndex,
+ PCASEMAP Casemap
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ ULONG Length,
+ PUCHAR String
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ HPFS_NAME* OtherName
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Swap(
+ PHPFS_NAME OtherName
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsNull(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsValid(
+ PCASEMAP Casemap,
+ ULONG CodepageIndex
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsNewName(
+ PCASEMAP Casemap,
+ ULONG CodepageIndex
+ );
+
+ NONVIRTUAL
+ NAME_COMPARE_RETURN
+ CompareName(
+ PHPFS_NAME OtherName
+ );
+
+ NONVIRTUAL
+ NAME_COMPARE_RETURN
+ CompareName(
+ ULONG Length,
+ PUCHAR String,
+ ULONG VolumeCodepageIndex,
+ PCASEMAP Casemap
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsCodepageInvariant(
+ ) CONST;
+
+ friend
+ BOOLEAN
+ HPFS_PATH::AddLevel(
+ PHPFS_NAME Name
+ );
+
+ NONVIRTUAL
+ PCUCHAR
+ GetString(
+ ) CONST;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ // _Buffer points at memory that is allocated by the object,
+ // and must be freed by it.
+
+ PBYTE _Buffer;
+ ULONG _BufferSize;
+ ULONG _Length;
+
+};
+
+#endif
diff --git a/private/utils/uhpfs/inc/hpfssa.hxx b/private/utils/uhpfs/inc/hpfssa.hxx
new file mode 100644
index 000000000..044daa2b0
--- /dev/null
+++ b/private/utils/uhpfs/inc/hpfssa.hxx
@@ -0,0 +1,820 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ hpfssa.hxx
+
+Abstract:
+
+ Models the Super Area of an HPFS volume. The Super Area consists
+ of the sectors used to define an HPFS volume.
+
+Author:
+
+ Mark Shavlik (marks) 19-oct-90
+
+ Norbert Kusters (norbertk) Oct-90, did the format relative work
+
+Notes:
+
+ HPFS_SA is derived from SUPERA_SA instead of HPFS_SECBUF. SUPER_SA
+ is derived from SECBUF_IOB. This derivation is done because
+ HPFS_SA shares code and data with SUPER_SA and HPFS_SA does not need
+ the benefits provided by the HPFS_SECBUF class because HPFS_SA uses
+ helper objects which are derived from HPFS_SECBUF.
+
+Enviroment
+
+ ULIB, user mode
+
+--*/
+
+#if ! defined( HPFSSUPERA_DEFN )
+
+#define HPFSSUPERA_DEFN
+
+#include "hmem.hxx"
+#include "supera.hxx"
+#include "superb.hxx"
+#include "spareb.hxx"
+#include "cpinfo.hxx"
+#include "bpb.hxx"
+
+
+// the text for the oem data field
+#define OEMTEXT "MSDOS5.0"
+#define OEMTEXTLENGTH 8
+
+#define sigBOOTSTRAP (UCHAR)0x29 // boot strap signature
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( BADBLOCKLIST );
+DECLARE_CLASS( BITMAPINDIRECT );
+DECLARE_CLASS( CASEMAP );
+DECLARE_CLASS( UHPFS_CODEPAGE );
+DECLARE_CLASS( DIRBLK );
+DECLARE_CLASS( FNODE );
+DECLARE_CLASS( HOTFIXLIST );
+DECLARE_CLASS( HPFS_BITMAP );
+DECLARE_CLASS( HPFS_CENSUS );
+DECLARE_CLASS( HPFS_DIR_BITMAP );
+DECLARE_CLASS( HPFS_MAIN_BITMAP );
+DECLARE_CLASS( HPFS_SA );
+DECLARE_CLASS( NUMBER_SET );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( MESSAGE );
+DECLARE_CLASS( SIDTABLE );
+
+CONST ULONG MEGABYTE = ( 1L << 20L );
+
+class HPFS_SA : public SUPERAREA {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( HPFS_SA );
+
+ VIRTUAL
+ ~HPFS_SA(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Create(
+ IN PCNUMBER_SET BadSectors,
+ IN OUT PMESSAGE Message,
+ IN PCWSTRING Label DEFAULT NULL,
+ IN ULONG ClusterSize DEFAULT 0,
+ IN ULONG VirtualSectors DEFAULT 0
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ VerifyAndFix(
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose DEFAULT FALSE,
+ IN BOOLEAN OnlyIfDirty DEFAULT FALSE,
+ IN BOOLEAN RecoverFree DEFAULT FALSE,
+ IN BOOLEAN RecoverAlloc DEFAULT FALSE,
+ OUT PULONG ExitStatus DEFAULT NULL,
+ IN PCWSTRING DriveLetter DEFAULT NULL
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Read(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Write(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ RecoverFile(
+ IN PCWSTRING FullPathFileName,
+ IN OUT PMESSAGE Message
+ );
+
+ UHPFS_EXPORT
+ PFNODE
+ QueryFnodeFromName(
+ IN PPATH RecFilePath,
+ IN PMESSAGE Message
+ );
+
+ BOOLEAN
+ AddBadBlocks(
+ IN OUT PNUMBER_SET BadBlocks,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ PARTITION_SYSTEM_ID
+ QuerySystemId(
+ ) CONST;
+
+ NONVIRTUAL
+ SECTORCOUNT
+ QueryFreeSectors(
+ ) CONST;
+
+ NONVIRTUAL
+ PHPFS_BITMAP
+ GetBitmap(
+ );
+
+ NONVIRTUAL
+ PBADBLOCKLIST
+ GetBadBlockList(
+ );
+
+ NONVIRTUAL
+ PHPFS_DIR_BITMAP
+ GetDirBitmap(
+ );
+
+ NONVIRTUAL
+ PHOTFIXLIST
+ GetHotfixList(
+ );
+
+ NONVIRTUAL
+ PUHPFS_CODEPAGE
+ GetCodepage(
+ );
+
+ NONVIRTUAL
+ PCASEMAP
+ GetCasemap(
+ );
+
+ NONVIRTUAL
+ PSUPERB
+ GetSuper(
+ );
+
+ NONVIRTUAL
+ PSPAREB
+ GetSpare(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CopyRun(
+ IN LBN StartLbn,
+ IN SECTORCOUNT LengthOfRun,
+ OUT PLBN NewStartLbn
+ );
+
+ UHPFS_EXPORT
+ NONVIRTUAL
+ BOOLEAN
+ QueryBadLbns(
+ IN ULONG MaximumBadLbns,
+ OUT PLBN Buffer,
+ OUT PULONG NumberOfBadLbns
+ );
+
+ UHPFS_EXPORT
+ NONVIRTUAL
+ BOOLEAN
+ TakeCensusAndClear(
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap,
+ IN OUT PHPFS_CENSUS Census
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsClean(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CheckSuperBlockSignatures(
+ );
+
+ UHPFS_EXPORT
+ NONVIRTUAL
+ BOOLEAN
+ ReadCodepage(
+ );
+
+ UHPFS_EXPORT
+ NONVIRTUAL
+ BOOLEAN
+ SetupHelpers(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ WriteBitmap(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ QueryLabel(
+ OUT PWSTRING Label
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ QueryGeometry(
+ OUT PUSHORT SectorSize,
+ OUT PUSHORT SectorsPerTrack,
+ OUT PUSHORT Heads,
+ OUT PULONG HiddenSectors
+ );
+
+ NONVIRTUAL
+ PBIOS_PARAMETER_BLOCK
+ GetBpb(
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ PHPFS_BITMAP
+ QueryBitMap(
+ ) CONST;
+
+ NONVIRTUAL
+ PSIDTABLE
+ QuerySidTable(
+ ) CONST;
+
+ NONVIRTUAL
+ PBITMAPINDIRECT
+ QueryBitMapInd(
+ ) CONST;
+
+ NONVIRTUAL
+ PHOTFIXLIST
+ QueryHotFixList(
+ ) CONST;
+
+ NONVIRTUAL
+ PBADBLOCKLIST
+ QueryBadBlockList(
+ );
+
+ NONVIRTUAL
+ PUHPFS_CODEPAGE
+ QueryCodePage(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ HpFormat(
+ IN OUT PHPFS_MAIN_BITMAP BitMap,
+ IN PCHPFS_MAIN_BITMAP BadSecBitMap
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetBpb(
+ );
+
+ HMEM _Mem;
+ SUPERB _SuperBlock;
+ SPAREB _SparesBlock;
+
+ PHPFS_BITMAP _Bitmap;
+ PBADBLOCKLIST _BadBlockList;
+ PHOTFIXLIST _HotfixList;
+ PUHPFS_CODEPAGE _Codepage;
+
+
+ //
+ // This data is from DOS_SUPERAREA
+ //
+
+ EXTENDED_BIOS_PARAMETER_BLOCK
+ _sector_zero;
+ PUCHAR _sector_sig; // sector signature
+
+ //
+ // These methods used to be in DOS_SUPERAREA
+ //
+
+ NONVIRTUAL
+ BOOLEAN
+ CreateBootSector(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ SetLabel(
+ IN PCWSTRING NewLabel
+ );
+
+ NONVIRTUAL
+ VOLID
+ SetVolId(
+ IN VOLID VolId
+ );
+
+ NONVIRTUAL
+ VOLID
+ QueryVolId(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ SetBootCode(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetPhysicalDriveType(
+ IN PHYSTYPE PhysType
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetOemData(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetSignature(
+ );
+
+ STATIC
+ BOOLEAN
+ IsValidString(
+ IN PCWSTRING String
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetBootSignature(
+ IN UCHAR Signature DEFAULT sigBOOTSTRAP
+ );
+//mjb
+};
+
+INLINE
+BOOLEAN
+HPFS_SA::Read(
+ )
+{
+ BOOLEAN Result;
+
+ Result = SECRUN::Read();
+
+ UnpackExtendedBios(&_sector_zero,
+ (PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK)SECRUN::GetBuf());
+
+ return Result;
+}
+
+INLINE
+BOOLEAN
+HPFS_SA::Write(
+ )
+{
+ PackExtendedBios(&_sector_zero,
+ (PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK)SECRUN::GetBuf());
+
+ return SECRUN::Write();
+}
+
+
+INLINE
+PSUPERB
+HPFS_SA::GetSuper(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the super block.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the super block.
+
+--*/
+{
+ return &_SuperBlock;
+}
+
+
+INLINE
+PSPAREB
+HPFS_SA::GetSpare(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the spare block.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the spare block.
+
+--*/
+{
+ return &_SparesBlock;
+}
+
+
+INLINE
+PHPFS_BITMAP
+HPFS_SA::GetBitmap(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the bit map.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the bit map.
+
+--*/
+{
+ return _Bitmap;
+}
+
+
+INLINE
+PBADBLOCKLIST
+HPFS_SA::GetBadBlockList(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the list of bad sectors.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the list of bad sectors.
+
+--*/
+{
+ return _BadBlockList;
+}
+
+
+INLINE
+PHOTFIXLIST
+HPFS_SA::GetHotfixList(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the hot fix list.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the hot fix list.
+
+--*/
+{
+ return _HotfixList;
+}
+
+
+INLINE
+PUHPFS_CODEPAGE
+HPFS_SA::GetCodepage(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the code page.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the code page.
+
+--*/
+{
+ return _Codepage;
+}
+
+
+INLINE
+PCASEMAP
+HPFS_SA::GetCasemap(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the case map object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the case map object.
+
+--*/
+{
+ return _Codepage->GetCasemap();
+}
+
+
+INLINE
+PARTITION_SYSTEM_ID
+HPFS_SA::QuerySystemId(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the system id for the volume.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The system ID for the volume.
+
+--*/
+{
+ // unreferenced parameters
+ (void)(this);
+
+ return SYSID_IFS;
+}
+
+INLINE
+BOOLEAN
+HPFS_SA::CheckSuperBlockSignatures(
+ )
+/*++
+
+Routine Description:
+
+ This method checks the super-block signature to make sure that the
+ volume is indeed HPFS. Note that this is not a sufficient condition,
+ merely a necessary one.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the superblock signatures are correct.
+
+--*/
+{
+ return( _SuperBlock.IsValid() );
+}
+
+
+INLINE
+BOOLEAN
+HPFS_SA::IsClean(
+ )
+/*++
+
+Routine Description:
+
+ This method determines whether the volume is marked as dirty.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the volume dirty bit is not set.
+
+Notes:
+
+ This method assumes that the volume is an HPFS volume.
+
+--*/
+{
+ return ( !_SparesBlock.IsFsDirty() );
+}
+
+INLINE
+VOLID
+HPFS_SA::SetVolId(
+ IN VOLID VolId
+ )
+/*++
+
+Routine Description:
+
+ This routine puts the volume ID into the super area's data.
+
+Arguments:
+
+ VolId - The new volume ID.
+
+Return Value:
+
+ The volume ID that was put.
+
+--*/
+{
+ return _sector_zero.SerialNumber = VolId;
+}
+
+
+INLINE
+VOLID
+HPFS_SA::QueryVolId(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine fetches the volume ID from the super area's data.
+ This routine will return 0 if volume serial numbers are not
+ supported by the partition.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The volume ID residing in the super area.
+
+--*/
+{
+ return (_sector_zero.Signature == 0x28 || _sector_zero.Signature == 0x29) ?
+ _sector_zero.SerialNumber : 0;
+}
+
+INLINE
+BOOLEAN
+HPFS_SA::SetOemData(
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the OEM data in the super area.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ memcpy( (void*)_sector_zero.OemData, (void*)OEMTEXT, OEMTEXTLENGTH);
+ return TRUE;
+}
+
+INLINE
+BOOLEAN
+HPFS_SA::SetBootSignature(
+ IN UCHAR Signature
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the boot signature in the super area.
+
+Arguments:
+
+ Signature - Supplies the character to set the signature to.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ _sector_zero.Signature = Signature;
+ return TRUE;
+}
+
+INLINE
+VOID
+HPFS_SA::QueryGeometry(
+ OUT PUSHORT SectorSize,
+ OUT PUSHORT SectorsPerTrack,
+ OUT PUSHORT Heads,
+ OUT PULONG HiddenSectors
+ )
+/*++
+
+Routine Description:
+
+ This method returns the geometry information stored in
+ the Bios Parameter Block.
+
+Arguments:
+
+ SectorSize -- Receives the recorded sector size.
+ SectorsPerTrack -- Receives the recorded sectors per track.
+ Heads -- Receives the recorded number of heads.
+ HiddenSectors -- Receives the recorded number of hidden sectors.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ *SectorSize = _sector_zero.Bpb.BytesPerSector;
+ *SectorsPerTrack = _sector_zero.Bpb.SectorsPerTrack;
+ *Heads = _sector_zero.Bpb.Heads;
+ *HiddenSectors = _sector_zero.Bpb.HiddenSectors;
+}
+
+INLINE
+PBIOS_PARAMETER_BLOCK
+HPFS_SA::GetBpb(
+ )
+{
+ return &(_sector_zero.Bpb);
+}
+
+
+
+#endif // HPFSSUPERA_DEFN
diff --git a/private/utils/uhpfs/inc/hpfsvol.hxx b/private/utils/uhpfs/inc/hpfsvol.hxx
new file mode 100644
index 000000000..ded2b43cd
--- /dev/null
+++ b/private/utils/uhpfs/inc/hpfsvol.hxx
@@ -0,0 +1,280 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ hpfsvol.hxx
+
+Abstract:
+
+ The class HPFS_VOL implements HPFS only volume items.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 5-Sept-90
+
+--*/
+
+#if !defined (HPFS_VOL_DEFN)
+
+#define HPFS_VOL_DEFN
+
+#if ! defined( _SETUP_LOADER_ )
+
+#include "volume.hxx"
+#include "hpfssa.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( HPFS_VOL );
+DECLARE_CLASS( MESSAGE );
+
+
+class HPFS_VOL : public VOL_LIODPDRV {
+
+ public:
+
+ UHPFS_EXPORT
+ DECLARE_CONSTRUCTOR( HPFS_VOL );
+
+ UHPFS_EXPORT
+ VIRTUAL
+ ~HPFS_VOL(
+ );
+
+ UHPFS_EXPORT
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN BOOLEAN ExclusiveWrite DEFAULT FALSE,
+ IN BOOLEAN FormatMedia DEFAULT FALSE,
+ IN MEDIA_TYPE MediaType DEFAULT Unknown
+ );
+
+ VIRTUAL
+ ULONG
+ QuerySectorSize(
+ ) CONST;
+
+ VIRTUAL
+ BIG_INT
+ QuerySectors(
+ ) CONST;
+
+ NONVIRTUAL
+ PVOL_LIODPDRV
+ QueryDupVolume(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN BOOLEAN ExclusiveWrite DEFAULT FALSE,
+ IN BOOLEAN FormatMedia DEFAULT FALSE,
+ IN MEDIA_TYPE MediaType DEFAULT Unknown
+ ) CONST;
+
+ NONVIRTUAL
+ PHPFS_SA
+ GetHPFSSuperArea(
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ HPFS_SA _hpfssa;
+
+};
+
+
+INLINE
+PHPFS_SA
+HPFS_VOL::GetHPFSSuperArea(
+ )
+/*++
+
+Routine Description:
+
+ get the superarea for an HPFS_VOL.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ pointer to superarea
+
+--*/
+{
+ return &_hpfssa;
+}
+
+#else // _SETUP_LOADER_ is defined
+
+#include "volume.hxx"
+#include "hpfssa.hxx"
+#include "dircache.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( HPFS_VOL );
+DECLARE_CLASS( MESSAGE );
+
+
+class HPFS_VOL : public VOL_LIODPDRV {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( HPFS_VOL );
+
+ VIRTUAL
+ ~HPFS_VOL(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN ULONG DeviceHandle
+ );
+
+ NONVIRTUAL
+ PVOL_LIODPDRV
+ QueryDupVolume(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN BOOLEAN ExclusiveWrite DEFAULT FALSE,
+ IN BOOLEAN FormatMedia DEFAULT FALSE,
+ IN MEDIA_TYPE MediaType DEFAULT Unknown
+ ) CONST;
+
+ NONVIRTUAL
+ PHPFS_SA
+ GetHPFSSuperArea(
+ );
+
+ NONVIRTUAL
+ PDIRBLK_CACHE
+ GetDirblkCache(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ IsHpfs(
+ );
+
+ VIRTUAL
+ ARC_STATUS
+ MarkDirty(
+ );
+
+ VIRTUAL
+ ARC_STATUS
+ Flush(
+ IN BOOLEAN JustHandle
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ HPFS_SA _hpfssa;
+ DIRBLK_CACHE _dirblk_cache;
+ BOOLEAN _IsDirty;
+ BOOLEAN _MountedDirty;
+};
+
+
+INLINE
+PHPFS_SA
+HPFS_VOL::GetHPFSSuperArea(
+ )
+/*++
+
+Routine Description:
+
+ get the superarea for an HPFS_VOL.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ pointer to superarea
+
+--*/
+{
+ return &_hpfssa;
+}
+
+INLINE
+PDIRBLK_CACHE
+HPFS_VOL::GetDirblkCache(
+ )
+/*++
+
+Return Value:
+
+ This method fetches the dirblk cache associated with this volume.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The volume's dirblk cache.
+
+--*/
+{
+ return &_dirblk_cache;
+}
+
+INLINE
+BOOLEAN
+HPFS_VOL::IsHpfs(
+ )
+/*++
+
+Routine Description:
+
+ This method determines whether the volume is HPFS.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if this volume is an HPFS volume (which, of course, it is).
+
+--*/
+{
+ return TRUE;
+}
+
+#endif
+
+#endif // HPFS_VOL_DEFN
diff --git a/private/utils/uhpfs/inc/ods.hxx b/private/utils/uhpfs/inc/ods.hxx
new file mode 100644
index 000000000..eac7f95b0
--- /dev/null
+++ b/private/utils/uhpfs/inc/ods.hxx
@@ -0,0 +1,61 @@
+#if ! defined( ODS_DFN )
+
+#define ODS_DFN
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ods.hxx
+
+Abstract:
+
+ On disk structures which have classes in ULIB use the types defined
+ in this header file.
+
+Author:
+ Mark Shavlik (marks) Nov-90
+
+Environment:
+
+Notes:
+
+Glossary:
+
+ HFL - HotFix list
+ BBL - Bad block list
+ BMP - Sector mapping HPFS bitmap
+ ODS - On disk structure. Any HPFS on disk item, like an Fnode or
+ a bitmap.
+
+Revision History:
+
+--*/
+
+typedef ULONG ODS_STATUS;
+
+// ODS states are defined here to make the mapping of bits easier
+
+// These ODS states apply to any file system, bits 0-7 reserved for these
+#define ODS_STABLE 0 // ODS has no problems
+#define ODS_CORRUPTED_NO_RECOVERY 1 // corruption not recoverable
+#define ODS_CORRUPTED_SOME_RECOVERY 2 // corruption partially recoverable
+#define ODS_CORRUPTED_FULL_RECOVERY 4 // corruption recoverable
+#define ODS_NOT_READABLE 8 // could not read ODS
+#define ODS_NOT_WRITABLE 0x10 // could not write ODS
+#define ODS_INTERNAL_ERROR 0x20 // code or resource problem
+
+// These ODS states apply to FAT and HPFS, bits 8-11 resevered for these
+#define ODS_XLINKED 0x100 // sharing sectors with ODS(s)
+
+// These ODS states apply to HPFS only
+#define ODS_HPFS_HOTFIXED 0x1000 // ODS hotfixed
+#define ODS_HPFS_INBADBLOCKLIST 0x2000 // ODS in bad block list
+#define ODS_HPFS_BITMAP 0x4000 // ODS already marked as in use
+
+#define ODS_STATUS_UNKNOWN 0xffff
+
+#endif
+
diff --git a/private/utils/uhpfs/inc/orphan.hxx b/private/utils/uhpfs/inc/orphan.hxx
new file mode 100644
index 000000000..25fb15eb9
--- /dev/null
+++ b/private/utils/uhpfs/inc/orphan.hxx
@@ -0,0 +1,442 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ orphan.hxx
+
+Abstract:
+
+ HPFS disk structures recognized as orphans.
+
+Author:
+
+ Bill McJohn (billmc) 22-Feb-91
+
+--*/
+
+#if !defined(HPFS_ORPHAN_DEFN)
+
+#define HPFS_ORPHAN_DEFN
+
+#include "alsec.hxx"
+#include "dirblk.hxx"
+#include "fnode.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( HPFS_ORPHAN );
+DECLARE_CLASS( HPFS_ORPHAN_LIST_HEAD );
+DECLARE_CLASS( HPFS_ORPHAN_FNODE );
+DECLARE_CLASS( HPFS_ORPHAN_DIRBLK );
+DECLARE_CLASS( HPFS_ORPHAN_ALSEC );
+DECLARE_CLASS( HPFS_ORPHANS );
+
+DECLARE_CLASS( DEFERRED_ACTIONS_LIST );
+DECLARE_CLASS( HPFS_DIRECTORY_TREE );
+DECLARE_CLASS( HPFS_SA );
+DECLARE_CLASS( HOTFIXLIST );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+
+
+enum ORPHAN_SECTOR_TYPE {
+
+ ORPHAN_DIRBLK,
+ ORPHAN_FNODE,
+ ORPHAN_ALSEC,
+ ORPHAN_LIST_HEAD
+};
+
+class HPFS_ORPHAN : public OBJECT {
+
+ public:
+
+ NONVIRTUAL
+ VOID
+ Detach(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ LookupFnode(
+ IN LBN DesiredLbn,
+ IN BOOLEAN fIsDir,
+ IN LBN ParentLbn,
+ IN OUT PULONG DirentFileSize,
+ OUT PULONG EaSize,
+ BOOLEAN UpdateAllowed
+ );
+
+ VIRTUAL
+ BOOLEAN
+ LookupDirblk(
+ IN LBN DesiredLbn,
+ IN LBN ParentLbn,
+ IN LBN ParentFnodeLbn,
+ BOOLEAN UpdateAllowed
+ );
+
+ VIRTUAL
+ BOOLEAN
+ LookupAlsec(
+ IN LBN DesiredLbn,
+ IN LBN ParentLbn,
+ IN OUT PULONG NextSectorNumber,
+ IN BOOLEAN UpdateAllowed,
+ IN BOOLEAN ParentIsFnode
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Save(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT PHPFS_SA SuperArea,
+ IN OUT PDIRENTD NewEntry,
+ IN LBN FoundTreeFnodeLbn,
+ OUT PBOOLEAN IsDir
+ );
+
+ friend class HPFS_ORPHANS;
+
+ protected:
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ );
+
+ DECLARE_CONSTRUCTOR( HPFS_ORPHAN );
+
+ ~HPFS_ORPHAN();
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy();
+
+ PHPFS_ORPHAN _Next;
+ PHPFS_ORPHAN _Previous;
+
+
+};
+
+class HPFS_ORPHAN_LIST_HEAD : public HPFS_ORPHAN {
+
+ // This class is a placeholder--every HPFS_ORPHANS object
+ // has one, to be the head of the doubly-linked list of
+ // orphans. This simplifies life for orphans that want
+ // to bail out of the list--since they aren't the list
+ // head, the just step out of the circle.
+
+ public:
+
+ DECLARE_CONSTRUCTOR( HPFS_ORPHAN_LIST_HEAD );
+
+ ~HPFS_ORPHAN_LIST_HEAD();
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ );
+
+ private:
+
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+};
+
+class HPFS_ORPHAN_DIRBLK : public HPFS_ORPHAN {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( HPFS_ORPHAN_DIRBLK );
+
+ ~HPFS_ORPHAN_DIRBLK();
+
+ BOOLEAN
+ Initialize(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN PHOTFIXLIST HotfixList,
+ LBN lbn
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ RecoverOrphan(
+ IN OUT PHPFS_SA SuperArea,
+ IN OUT PDEFERRED_ACTIONS_LIST DeferredActionsList,
+ IN OUT PHPFS_ORPHANS OrphansList,
+ IN BOOLEAN UpdateAllowed
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ LookupDirblk(
+ IN LBN DesiredLbn,
+ IN LBN ParentLbn,
+ IN LBN ParentFnodeLbn,
+ BOOLEAN UpdateAllowed
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Save(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT PHPFS_SA SuperArea,
+ IN OUT PDIRENTD NewEntry,
+ IN LBN FoundTreeFnodeLbn,
+ OUT PBOOLEAN IsDir
+ );
+
+ private:
+
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ DIRBLK _Dirblk;
+
+};
+
+class HPFS_ORPHAN_FNODE : public HPFS_ORPHAN {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( HPFS_ORPHAN_FNODE );
+
+ ~HPFS_ORPHAN_FNODE();
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN LBN Lbn,
+ IN BOOLEAN IsDir
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ RecoverOrphan(
+ IN OUT PHPFS_SA SuperArea,
+ IN OUT PDEFERRED_ACTIONS_LIST DeferredActionsList,
+ IN OUT PHPFS_ORPHANS OrphansList,
+ IN BOOLEAN UpdateAllowed
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ LookupFnode(
+ IN LBN DesiredLbn,
+ IN BOOLEAN fIsDir,
+ IN LBN ParentLbn,
+ IN OUT PULONG DirentFileSize,
+ OUT PULONG EaSize,
+ IN BOOLEAN UpdateAllowed
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Save(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT PHPFS_SA SuperArea,
+ IN OUT PDIRENTD NewEntry,
+ IN LBN FoundTreeFnodeLbn,
+ OUT PBOOLEAN IsDir
+ );
+
+ private:
+
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ FNODE _Fnode;
+
+ PLOG_IO_DP_DRIVE _Drive;
+ BOOLEAN _IsDir;
+ ULONG _FileSize;
+ ULONG _EaSize;
+
+};
+
+class HPFS_ORPHAN_ALSEC : public HPFS_ORPHAN {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( HPFS_ORPHAN_ALSEC );
+
+ ~HPFS_ORPHAN_ALSEC();
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN LBN Lbn
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ RecoverOrphan(
+ IN OUT PHPFS_SA SuperArea,
+ IN OUT PDEFERRED_ACTIONS_LIST DeferredActionsList,
+ IN OUT PHPFS_ORPHANS OrphansList,
+ IN BOOLEAN UpdateAllowed
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ LookupAlsec(
+ IN LBN DesiredLbn,
+ IN LBN ParentLbn,
+ IN OUT PULONG NextSectorNumber,
+ IN BOOLEAN UpdateAllowed,
+ IN BOOLEAN ParentIsFnode
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Save(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT PHPFS_SA SuperArea,
+ IN OUT PDIRENTD NewEntry,
+ IN LBN FoundTreeFnodeLbn,
+ OUT PBOOLEAN IsDir
+ );
+
+ private:
+
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ ALSEC _Alsec;
+ ULONG _NextSectorNumber;
+
+};
+
+class HPFS_ORPHANS : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( HPFS_ORPHANS );
+
+ VIRTUAL
+ ~HPFS_ORPHANS();
+
+ BOOLEAN
+ Initialize(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ RecoverOrphan(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT PHPFS_SA SuperArea,
+ IN OUT PDEFERRED_ACTIONS_LIST DeferredActionsList,
+ IN LBN OrphanLbn,
+ IN OUT PSECRUN OrphanSecrun,
+ IN BOOLEAN UpdateAllowed
+ );
+
+ NONVIRTUAL
+ VOID
+ AddOrphan(
+ IN OUT PHPFS_ORPHAN NewOrphan
+ );
+
+ NONVIRTUAL
+ PHPFS_ORPHAN
+ RemoveNextOrphan(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ LookupFnode(
+ IN LBN DesiredLbn,
+ IN BOOLEAN fIsDir,
+ IN LBN ParentLbn,
+ IN OUT PULONG DirentFileSize,
+ OUT PULONG EaSize,
+ IN BOOLEAN UpdateAllowed
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ LookupDirblk(
+ IN LBN DesiredLbn,
+ IN LBN ParentLbn,
+ IN LBN ParentFnodeLbn,
+ IN BOOLEAN UpdateAllowed
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ LookupAlsec(
+ IN LBN DesiredLbn,
+ IN LBN ParentLbn,
+ IN OUT PULONG NextSectorNumber,
+ IN BOOLEAN UpdateAllowed,
+ IN BOOLEAN ParentIsFnode
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Save(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT PHPFS_SA SuperArea,
+ IN OUT PDIRBLK_CACHE Cache,
+ IN OUT PHPFS_DIRECTORY_TREE RootTree,
+ IN LBN RootFnodeLbn,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryOrphansFound(
+ );
+
+ private:
+
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy();
+
+ HPFS_ORPHAN_LIST_HEAD _ListHead;
+};
+
+#endif
diff --git a/private/utils/uhpfs/inc/sid.hxx b/private/utils/uhpfs/inc/sid.hxx
new file mode 100644
index 000000000..64c629c7b
--- /dev/null
+++ b/private/utils/uhpfs/inc/sid.hxx
@@ -0,0 +1,78 @@
+/***************************************************************************\
+
+CLASS: SIDTABLE_SB
+
+PURPOSE: To model the SID table.
+
+INTERFACE: SIDTABLE_SB Construct an SID table.
+ Create Create an SID table.
+
+NOTES:
+
+HISTORY:
+ 10-Sep-90 norbertk
+ Create
+
+KEYWORDS:
+
+SEEALSO:
+
+\***************************************************************************/
+
+
+#if ! defined(SIDTABLE_DEFN)
+
+#define SIDTABLE_DEFN
+
+#include "hmem.hxx"
+#include "secrun.hxx"
+
+#define SECTORS_PER_SID 8
+
+struct SIDTABLED { // std
+
+ BYTE a[1];
+
+};
+
+DECLARE_CLASS( SIDTABLE );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+
+class SIDTABLE : public SECRUN {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( SIDTABLE );
+
+ VIRTUAL
+ ~SIDTABLE(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PLOG_IO_DP_DRIVE Drive,
+ IN LBN Lbn
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Create(
+ );
+
+ private:
+
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ HMEM _hmem;
+ SIDTABLED* _pstd;
+};
+
+#endif // SIDTABLE_DEFN
diff --git a/private/utils/uhpfs/inc/spareb.hxx b/private/utils/uhpfs/inc/spareb.hxx
new file mode 100644
index 000000000..70eed3acd
--- /dev/null
+++ b/private/utils/uhpfs/inc/spareb.hxx
@@ -0,0 +1,767 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ spareb.hxx
+
+Abstract:
+
+ SpareB contains various emergency supplies and fixup information
+ which isn't in the superblock since the Superblock
+ is read only and to decrease the liklihood that a flakey write
+ will cause the superblock to become unreadable.
+
+ This sector is located directly after the superblock - sector 17.
+
+ Note that the number of spare DIRBLKs is a format computed by
+ HPFS format.
+
+ Checksums are done on both Super Block and the Spare Block.
+ Both checksums are stored in the Spare Block. The checksum
+ field for the Super Block must be set when
+ calculating the checksum for the Spare Block. The checksum
+ field for the Spare Block must be zero when
+ calculating the checksum for the Spare Block.
+ If both checksum fields are zero, the checksums have not been
+ calculated for the volume.
+
+ The data in this object reflects the HPFS on disk super area,
+ which must be compatable w/ all other HPFS' so NOTHING can
+ be changed in this data structure that will change the on disk
+ format!
+
+ The Spare block use a number of helper objects to perform its
+ tasks:
+ HOTFIXLISTS
+ DIRBLKS
+ CODEPAGETABLE
+
+ These objects are Created by SpareB's Create method, and are gotten
+ by SpareB's Get method. SpareB stores only the LBNs for these
+ objects because the objects are LBN based. Queries for these
+ objects return LBNs, NOT object pointers since the LBN can be
+ used to create an object of the requested type.
+
+ NB The member 'Create' is to be used by FORMAT.
+ Beware!! It will trash your disk.
+
+Author:
+
+ Mark Shavlik (marks) 27-Mar-90
+
+--*/
+
+#if ! defined( SPAREB_DEFN )
+
+#define SPAREB_DEFN
+
+
+#include "secrun.hxx"
+
+DECLARE_CLASS( SPAREB );
+DECLARE_CLASS( HPFS_BITMAP );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( MEM );
+DECLARE_CLASS( SUPERB );
+
+
+// lbn where SPAREBLOCK is located
+#define lbnSPAREB 17
+
+// 1 sector size
+#define csecSPAREB 1
+
+#define DIRBLK_SIZE 2048 // The number of bytes in a dir block.
+
+// Spare Block information stored in a bit vector form in the bFlag
+// field of the _SPAREB data structure defined below.
+
+enum SPI {
+
+ SPI_DIRTY = 1, // File system is dirty
+ SPI_SPARE = 2, // spare DIRBLKs are used
+ SPI_HFUSED = 4, // Hot fix list used
+ SPI_BADSEC = 8, // bad sectors, corrupt disk
+ SPI_BADBM = 0x10, // bad bitmap block
+ SPI_FSVER = 0x80 // FS version < SuperBlocks version
+
+};
+
+
+// spare block data, the data layout must not change because this data
+// must be on disk compatable w/ all other HPFS'
+
+struct _SPAREB {
+
+ ULONG sig1; /* signature value 1 */
+ ULONG sig2; /* signature value 2 */
+
+ BYTE bFlag; /* cleanliness flag */
+ BYTE bAlign[3]; /* alignment */
+
+ LBN lbnHotFix; /* first hotfix list Psector */
+ ULONG culHotFixes; /* # of hot fixes in effect */
+ ULONG culMaxHotFixes; /* max size of hot fix list */
+
+ ULONG cdbSpares; /* # of spare dirblks */
+ ULONG cdbMaxSpare; /* max num of spare DB values. */
+ LBN lbnCPInfo; /* code page info sector */
+ ULONG culCP; /* number of code pages */
+ ULONG chkSuperBlock; /* Checksum of Super Block */
+ ULONG chkSpareBlock; /* Checksum of Spare Block */
+ ULONG aulExtra[15]; /* some extra space for future use */
+ LBN albnSpareDirblks[101];/* LBNs of spare dirblks */
+
+};
+
+class SPAREB : public SECRUN {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( SPAREB );
+
+ VIRTUAL
+ ~SPAREB(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Create(
+ IN PCLOG_IO_DP_DRIVE Drive,
+ IN OUT PHPFS_BITMAP BitMap,
+ IN PSUPERB SuperBlock,
+ IN LBN HotFixLbn,
+ IN SECTORCOUNT MaxHotFixes,
+ IN LBN CodePageSectorLbn,
+ IN ULONG NumCodePages,
+ IN LBN StartSparesLbn,
+ IN ULONG NumSpares
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Verify(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsValid(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ SetSpareDirblksUsed(
+ IN BOOLEAN Flag DEFAULT TRUE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetHotFixesUsed(
+ IN BOOLEAN Flag DEFAULT TRUE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetBadSectorsPresent(
+ IN BOOLEAN Flag DEFAULT TRUE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetBadBitMapBlock(
+ IN BOOLEAN Flag DEFAULT TRUE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetFsVersionDifferent(
+ IN BOOLEAN Flag DEFAULT TRUE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsSpareDirblksUsed(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsHotFixesUsed(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsBadSectorsPresent(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsBadBitMapBlock(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsFsDirty(
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetFsDirty(
+ BOOLEAN Dirty
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsFsVersionDifferent(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QueryHotFixCount(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QueryMaxHotFixes(
+ ) CONST;
+
+ NONVIRTUAL
+ LBN
+ QueryHotFixLbn(
+ ) CONST;
+
+ NONVIRTUAL
+ LBN
+ QueryCpInfoLbn(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QueryCodePageCount(
+ ) CONST;
+
+ NONVIRTUAL
+ LBN
+ QuerySpareDirblkLbn(
+ IN ULONG Index
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ SetHotFixCount(
+ IN ULONG HotFixCount
+ );
+
+ NONVIRTUAL
+ ULONG
+ SetMaxHotFixes(
+ IN ULONG MaxHotFixes
+ );
+
+ NONVIRTUAL
+ VOID
+ ComputeAndSetChecksums(
+ IN PSUPERB SuperBlock
+ );
+
+ NONVIRTUAL
+ VOID
+ SetFlags(
+ IN BOOLEAN IsClean
+ );
+
+ NONVIRTUAL
+ VOID
+ Print(
+ IN BOOLEAN TotalDump DEFAULT TRUE
+ ) CONST;
+
+ private:
+
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetFlag(
+ IN BOOLEAN Flag,
+ IN SPI Bit
+ );
+
+ STATIC
+ ULONG
+ ccs(
+ IN PVOID Buffer,
+ IN ULONG Size
+ );
+
+ _SPAREB* _pspd;
+
+};
+
+INLINE
+ULONG
+SPAREB::SetHotFixCount(
+ IN ULONG HotFixCount
+ )
+{
+ return (_pspd) ? (_pspd->culHotFixes = HotFixCount) : !HotFixCount;
+}
+
+INLINE
+ULONG
+SPAREB::SetMaxHotFixes(
+ IN ULONG MaxHotFixes
+ )
+{
+ return (_pspd) ? (_pspd->culMaxHotFixes = MaxHotFixes) : !MaxHotFixes;
+}
+
+
+
+
+/***************************************************************************\
+
+MEMBER: SetSpareDirblksUsed
+
+SYNOPSIS: Set spare block to reflect HPFS's usage of spare dir blocks
+
+ARGUMENTS:
+
+NOTES: Spare dirblks are only used when the normal pool of dir blocks
+ is exhausted.
+
+ALGORITHM:
+
+HISTORY: 26-July-90 marks
+ code
+\***************************************************************************/
+
+INLINE
+BOOLEAN
+SPAREB::SetSpareDirblksUsed (
+ IN BOOLEAN Flag
+) {
+ return SetFlag(Flag, SPI_SPARE);
+}
+
+
+/***************************************************************************\
+
+MEMBER: SetHotFixesUsed
+
+SYNOPSIS: Set spare block to reflect HPFS's usage of Hot Fixes
+
+ARGUMENTS:
+
+NOTES: Hot fixes occur when a sector goes bad after a format. Chkdsk
+ will clear hot fixes. A hot fix maps a bad sector to a good sector.
+
+ALGORITHM:
+
+HISTORY: 26-July-90 marks
+ code
+\***************************************************************************/
+
+INLINE
+BOOLEAN
+SPAREB::SetHotFixesUsed (
+ IN BOOLEAN Flag
+) {
+ return SetFlag(Flag, SPI_HFUSED);
+}
+
+
+/***************************************************************************\
+
+MEMBER: SetBadSectorsPresent
+
+SYNOPSIS: Set spare block to reflect existance of bad sectors
+
+ARGUMENTS:
+
+NOTES: If a volume has bad sectors this bit is set
+
+ALGORITHM:
+
+HISTORY: 26-July-90 marks
+ code
+\***************************************************************************/
+
+INLINE
+BOOLEAN
+SPAREB::SetBadSectorsPresent (
+ IN BOOLEAN Flag
+) {
+ return SetFlag(Flag, SPI_BADSEC);
+}
+
+
+/***************************************************************************\
+
+MEMBER: SetBadBitMapBlock
+
+SYNOPSIS: Set spare block to reflect existance of a bad bit map block
+
+ARGUMENTS:
+
+NOTES:
+
+ALGORITHM:
+
+HISTORY: 26-July-90 marks
+ code
+\***************************************************************************/
+
+INLINE
+BOOLEAN
+SPAREB::SetBadBitMapBlock (
+ IN BOOLEAN Flag
+) {
+ return SetFlag(Flag, SPI_BADBM);
+}
+
+
+/***************************************************************************\
+
+MEMBER: SetFSVersionDifferent
+
+SYNOPSIS: Set when the HPFS version differs from current OS version
+
+ARGUMENTS:
+
+NOTES:
+
+ALGORITHM:
+
+HISTORY: 26-July-90 marks
+ code
+\***************************************************************************/
+
+INLINE
+BOOLEAN
+SPAREB::SetFsVersionDifferent (
+ IN BOOLEAN Flag
+) {
+ return SetFlag(Flag, SPI_FSVER);
+}
+
+
+/***************************************************************************\
+
+MEMBER: IsFSDirty
+
+SYNOPSIS: FS dirty is set after improper shutdown of the file system
+
+ARGUMENTS:
+
+NOTES:
+
+ALGORITHM:
+
+HISTORY: 26-July-90 marks
+ code
+\***************************************************************************/
+
+INLINE
+BOOLEAN
+SPAREB::IsFsDirty (
+) CONST {
+ return (_pspd) ? (_pspd->bFlag & SPI_DIRTY) : FALSE;
+}
+
+INLINE
+VOID
+SPAREB::SetFsDirty(
+ BOOLEAN Dirty
+ )
+/*++
+
+Routine Description:
+
+ This method sets the volume dirty bit.
+
+Arguments:
+
+ Dirty -- supplies a flag which indicates, if TRUE, that the dirty
+ bit is to be set; if this flag is FALSE, the dirty bit is
+ to be reset.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DebugPtrAssert( _pspd);
+
+ if( Dirty ) {
+
+ _pspd->bFlag |= SPI_DIRTY;
+
+ } else {
+
+ _pspd->bFlag &= ~SPI_DIRTY;
+ }
+}
+
+
+/***************************************************************************\
+
+MEMBER: IsSpareDirblksUsed
+
+SYNOPSIS: Check spare block to reflect HPFS's usage of spare dir blocks
+
+ARGUMENTS:
+
+NOTES: Spare dirblks are only used when the normal pool of dir blocks
+ is exhausted.
+
+ALGORITHM:
+
+HISTORY: 26-July-90 marks
+ code
+\***************************************************************************/
+
+INLINE
+BOOLEAN
+SPAREB::IsSpareDirblksUsed (
+) CONST {
+ return (_pspd) ? (_pspd->bFlag & SPI_SPARE) : FALSE;
+}
+
+
+/***************************************************************************\
+
+MEMBER: IsHotFixesUsed
+
+SYNOPSIS: Check HPFS's usage of Hot Fixes
+
+ARGUMENTS:
+
+NOTES: Hot fixes occur when a sector goes bad after a format. Chkdsk
+ will clear hot fixes. A hot fix maps a bad sector to a good sector.
+
+ALGORITHM:
+
+HISTORY: 26-July-90 marks
+ code
+\***************************************************************************/
+
+INLINE
+BOOLEAN
+SPAREB::IsHotFixesUsed (
+) CONST {
+ return (_pspd) ? (_pspd->bFlag & SPI_HFUSED) : FALSE;
+}
+
+
+/***************************************************************************\
+
+MEMBER: IsBadSectorsPresent
+
+SYNOPSIS: Is spare block to reflect existance of bad sectors
+
+ARGUMENTS:
+
+NOTES: If a volume has bad sectors this bit is set
+
+ALGORITHM:
+
+HISTORY: 26-July-90 marks
+ code
+\***************************************************************************/
+
+INLINE
+BOOLEAN
+SPAREB::IsBadSectorsPresent (
+) CONST {
+ return (_pspd) ? (_pspd->bFlag & SPI_BADSEC) : FALSE;
+}
+
+
+/***************************************************************************\
+
+MEMBER: IsBadBitMapBlock
+
+SYNOPSIS: Check spare block to reflect existance of a bad bit map block
+
+ARGUMENTS:
+
+NOTES:
+
+ALGORITHM:
+
+HISTORY: 26-July-90 marks
+ code
+\***************************************************************************/
+
+INLINE
+BOOLEAN
+SPAREB::IsBadBitMapBlock (
+) CONST {
+ return (_pspd) ? (_pspd->bFlag & SPI_BADBM) : FALSE;
+}
+
+
+/***************************************************************************\
+
+MEMBER: IsFSVersionDifferent
+
+SYNOPSIS: Check if the HPFS version differs from current OS version
+
+ARGUMENTS:
+
+NOTES:
+
+ALGORITHM:
+
+HISTORY: 26-July-90 marks
+ code
+\***************************************************************************/
+
+INLINE
+BOOLEAN
+SPAREB::IsFsVersionDifferent (
+) CONST {
+ return (_pspd) ? (_pspd->bFlag & SPI_FSVER) : FALSE;
+}
+
+
+/***************************************************************************\
+
+MEMBER: QueryHotFixes
+
+SYNOPSIS: Query the number of hot fixes present in an HPFS instance
+
+ARGUMENTS:
+
+NOTES:
+
+ALGORITHM:
+
+HISTORY: 26-July-90 marks
+ code
+\***************************************************************************/
+
+INLINE
+ULONG
+SPAREB::QueryHotFixCount(
+) CONST {
+ return (_pspd) ? _pspd->culHotFixes : 0;
+};
+
+
+/***************************************************************************\
+
+MEMBER: QueryMaxHotFixes
+
+SYNOPSIS: Query maximum number of hot fixes that can occur
+
+ARGUMENTS:
+
+NOTES:
+
+ALGORITHM:
+
+HISTORY: 26-July-90 marks
+ code
+\***************************************************************************/
+
+INLINE
+ULONG
+SPAREB::QueryMaxHotFixes(
+) CONST {
+ return (_pspd) ? _pspd->culMaxHotFixes : 0;
+};
+
+
+/***************************************************************************\
+
+MEMBER: QueryLBNHotFixes
+
+SYNOPSIS: Query the LBN which starts the hot fix list
+
+ARGUMENTS:
+
+NOTES: Hotfixes are contained in a consecutive set of sectors
+
+ALGORITHM:
+
+HISTORY: 26-July-90 marks
+ code
+\***************************************************************************/
+
+INLINE
+LBN
+SPAREB::QueryHotFixLbn(
+) CONST {
+ return (_pspd) ? _pspd->lbnHotFix : 0;
+};
+
+
+/***************************************************************************\
+
+MEMBER: QueryLBNCPInfo
+
+SYNOPSIS: Query the LBN of Code page information
+
+ARGUMENTS:
+
+NOTES: CP information starts at this location and then the CP data
+ structures (or objects) map to the remaining CP data structures
+ in an on disk LBN linked list.
+
+ALGORITHM:
+
+HISTORY: 26-July-90 marks
+ code
+\***************************************************************************/
+
+INLINE
+LBN
+SPAREB::QueryCpInfoLbn (
+) CONST {
+ return (_pspd) ? _pspd->lbnCPInfo : 0;
+};
+
+
+/***************************************************************************\
+
+MEMBER: QueryUsedCPs
+
+SYNOPSIS: Query the number of code pages in use
+
+ARGUMENTS:
+
+NOTES:
+
+ALGORITHM:
+
+HISTORY: 26-July-90 marks
+ code
+\***************************************************************************/
+
+INLINE
+ULONG
+SPAREB::QueryCodePageCount(
+) CONST {
+ return (_pspd) ? _pspd->culCP : 0;
+};
+
+
+#endif
diff --git a/private/utils/uhpfs/inc/store.hxx b/private/utils/uhpfs/inc/store.hxx
new file mode 100644
index 000000000..458d92bf0
--- /dev/null
+++ b/private/utils/uhpfs/inc/store.hxx
@@ -0,0 +1,248 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ store.hxx
+
+Abstract:
+
+ This module contains declarations for the STORE object, which models
+ the allocation block which is common to Allocation Sectors and FNodes.
+
+Author:
+
+ Bill McJohn (billmc) 01-Dec-1990
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+
+// file storage
+
+#if !defined ( HPFS_FILESTORAGE_DEFN )
+#define HPFS_FILESTORAGE_DEFN
+
+#include "defer.hxx"
+#include "verify.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( DEFERRED_ACTIONS_LIST );
+DECLARE_CLASS( HPFS_BITMAP );
+DECLARE_CLASS( HPFS_CENSUS );
+DECLARE_CLASS( HPFS_MAIN_BITMAP );
+DECLARE_CLASS( HPFS_ORPHANS );
+DECLARE_CLASS( HPFS_PATH );
+DECLARE_CLASS( HPFS_SA );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( MESSAGE );
+DECLARE_CLASS( STORE );
+
+const BYTE LeavesPerAlsec = 40;
+const BYTE NodesPerAlsec = 60;
+const BYTE LeavesPerFnode = 8;
+const BYTE NodesPerFnode = 12;
+
+enum STATE {
+ STATE_OFF,
+ STATE_ON,
+ STATE_ERROR
+};
+
+typedef struct ALBLK { // alblk
+ BYTE bFlag; /* bit mask describing block. */
+ BYTE bPad[3]; /* align to 4 byte boundary */
+ BYTE cFree; /* count of free entries left */
+ BYTE cUsed; /* count of used entries */
+ USHORT oFree; /* offset to first free entry */
+} *PALBLK;
+
+typedef struct ALNODE {
+ LBN lbnLog; /* children have data below this pos */
+ LBN lbnPhys; /* disk sector number of child block */
+} *PALNODE;
+
+typedef struct ALLEAF {
+ LBN lbnLog; // file LBN
+ ULONG csecRun; // number of sectors in run
+ LBN lbnPhys; // volume relative start of run
+} *PALLEAF;
+
+enum {
+ ABF_NFG = 0x01, /* not a flag, high order bit of oFree */
+ ABF_FNP = 0x20, /* parent is an FNODE */
+ ABF_BIN = 0x40, /* suggest using binary search to find */
+ ABF_NODE = 0x80 /* if not a leaf node */
+};
+
+
+// Three types of storages structures are needed:
+//
+// 1. An FNODE storage structure
+// 2. An ALSEC storage structure
+// 3. A generic storage structure (unknown number of leaves or nodes)
+//
+// The first two types are used inside the definitions of FNodes and
+// Allocation Sectors to set aside the correct amount of space. The
+// third is used by the store object to deal with an arbitrary storage
+// structure.
+
+struct FNODE_STORE { // _fn_store
+
+ ALBLK alblk;
+ union {
+
+ ALLEAF alleaf[LeavesPerFnode];
+ ALNODE alnode[NodesPerFnode];
+
+ } a;
+
+};
+
+struct ALSEC_STORE { // _al_store
+
+ ALBLK alblk;
+ union {
+
+ ALLEAF alleaf[LeavesPerAlsec];
+ ALNODE alnode[NodesPerAlsec];
+
+ } a;
+};
+
+typedef struct STORED { // std
+ ALBLK alb;
+ union {
+ ALLEAF alleaf[1];
+ ALNODE alnode[1];
+ } a;
+} *PSTORED;
+
+class STORE : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( STORE );
+
+ VIRTUAL
+ ~STORE(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PLOG_IO_DP_DRIVE Drive,
+ IN PSTORED pstd,
+ IN LBN CurrentLBN,
+ IN BOOLEAN IsFnode
+ );
+
+ NONVIRTUAL
+ VERIFY_RETURN_CODE
+ VerifyAndFix(
+ IN PHPFS_SA SuperArea,
+ IN PDEFERRED_ACTIONS_LIST DeferredActions,
+ IN OUT PHPFS_PATH CurrentPath,
+ IN OUT PLBN NextSectorNumber,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN ErrorsDetected,
+ IN BOOLEAN UpdateAllowed = FALSE,
+ IN OUT PHPFS_ORPHANS OrphansList = NULL,
+ IN BOOLEAN ParentIsFnode = FALSE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ScanStorage(
+ IN OUT PULONG NextSectorNumber,
+ IN BOOLEAN ParentIsFnode
+ );
+
+ NONVIRTUAL
+ VOID
+ MarkModified(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryModified(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FindAndResolveHotfix(
+ PHPFS_SA SuperArea,
+ DEFERRED_SECTOR_TYPE ChildSectorType
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ResolveCrosslink(
+ PHPFS_SA SuperArea,
+ ULONG RunIndex
+ );
+
+ NONVIRTUAL
+ LBN
+ QueryPhysicalLbn(
+ IN LBN FileBlockNumber,
+ OUT PULONG RunLength
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Truncate(
+ IN LBN SectorCount
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryExtents(
+ IN ULONG MaximumNumberOfExtents,
+ IN OUT PVOID ExtentList,
+ IN OUT PULONG NumberOfExtents
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ StoreExtents(
+ IN ULONG NumberOfExtents,
+ IN PALLEAF ExtentList,
+ IN BOOLEAN ParentIsFnode,
+ IN OUT PHPFS_BITMAP VolumeBitmap
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ TakeCensusAndClear(
+ IN OUT PHPFS_BITMAP VolumeBitmap,
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap,
+ IN OUT PHPFS_CENSUS Census
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ PSTORED _pstd;
+ PLOG_IO_DP_DRIVE _Drive;
+
+ BOOLEAN _IsModified;
+ BOOLEAN _IsFnode;
+ LBN _CurrentLBN;
+
+};
+
+
+#endif
diff --git a/private/utils/uhpfs/inc/superb.hxx b/private/utils/uhpfs/inc/superb.hxx
new file mode 100644
index 000000000..4769da330
--- /dev/null
+++ b/private/utils/uhpfs/inc/superb.hxx
@@ -0,0 +1,536 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ superb.hxx
+
+Abstract:
+
+ This class models the super block on an HPFS volume.
+
+Author:
+
+ Dave Gilman (davegi) 23-Jul-90
+
+--*/
+
+
+#if ! defined( SUPERB_DEFN )
+
+#define SUPERB_DEFN
+
+#include "secrun.hxx"
+
+DECLARE_CLASS( BADBLOCKLIST );
+DECLARE_CLASS( HPFS_BITMAP );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( MEM );
+DECLARE_CLASS( SUPERB );
+
+typedef ULONG HPFSSIG;
+typedef BYTE HPFSVER;
+typedef ULONG HPFSDATE;
+
+#define SIGSB1 0xF995E849
+#define SIGSB2 0xFA53E9C5
+#define LBN_SUPERB 16
+#define SUPERB_VOLNAME 32
+#define SUPERB_SECTORS 1
+#define SUPERB_VERSION 2
+#define SUPERB_FVERSION_2 2
+#define SUPERB_FVERSION_3 3
+
+#define SUPERB_PWLEN 15
+
+
+struct _SUPERB {
+ struct _SUPERB_INFO {
+ HPFSSIG sig1;
+ HPFSSIG sig2;
+ HPFSVER bVersion;
+ HPFSVER bFuncVersion;
+ USHORT usDummy; // alignment bytes
+ LBN lbnRootFNode;
+ SECTORCOUNT culSectsOnVol;
+ SECTORCOUNT culNumBadSects;
+ LBN lbnMainrspBitMapIndBlk;
+ LBN lbnSparerspBitMapIndBlk;
+ LBN lbnMainrspBadBlkList;
+ LBN lbnSparerspBadBlkList;
+ HPFSDATE datLastChkdsk; // date of last CHKDSK
+ HPFSDATE datLastOptimize; // date of last Disk Optimize
+ SECTORCOUNT clbndbnd; // count LBN Dirblk Band
+ LBN lbndbndStart; // first LBN in DIRBLK band
+ LBN lbndbndEnd; // last LBN in DIRBLK band
+ LBN lbndbndbmStart; // first LBN of DIRBLK band
+ // bit map. Starts on a 2K
+ // boundary, 2K bytes maximum
+ CHAR achVolName[SUPERB_VOLNAME];
+ LBN lbnSidTab; // sector number of SID table
+ UCHAR bOldFuncVersion; // LM2.1 local security
+ UCHAR bFlags; // LM2.1 superblock flags
+ UCHAR Password[SUPERB_PWLEN]; // LM2.1 local security
+ UCHAR abPad[3]; // Padding to DWORD align
+ } _sbi;
+
+ BYTE abFill[cbSector - sizeof(_SUPERB_INFO)];
+};
+
+// Superblock flags: Note that UHPFS only uses SBF_BIGDISK.
+//
+#define SBF_LOCALSEC 1 /* Local security turned on */
+#define SBF_BIGDISK 2 /* Disk is >= 2Gig in size */
+#define SBF_TRKCNT 4 /* Dirty count tracking enabled */
+#define SBF_LM21 8 /* LanMan 2.1 has seen the disk */
+
+// Any volume larger than 2 Gigabytes will have the SBF_BIGDISK
+// flag set and the functional version set 3 to prevent earlier
+// versions of HPFS from mucking it up.
+//
+CONST ULONG BigDiskSectorCutoff = 0x400000;
+
+
+class SUPERB : public SECRUN {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( SUPERB );
+
+ VIRTUAL
+ ~SUPERB(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Create(
+ IN PCLOG_IO_DP_DRIVE Drive,
+ IN OUT PHPFS_BITMAP BitMap,
+ IN OUT PBADBLOCKLIST BadBlk,
+ IN LBN RootLbn,
+ IN LBN BmindLbn,
+ IN LBN BadBlkLbn,
+ IN SECTORCOUNT DirBandSc,
+ IN LBN FirstDirblkLbn,
+ IN LBN DirMapLbn,
+ IN LBN SidLbn
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Verify(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsValid(
+ ) CONST;
+
+ NONVIRTUAL
+ LBN
+ QueryRootFnodeLbn(
+ ) CONST;
+
+ NONVIRTUAL
+ HPFSVER
+ QueryVersion(
+ ) CONST;
+
+ NONVIRTUAL
+ HPFSVER
+ QueryFuncVersion(
+ ) CONST;
+
+ NONVIRTUAL
+ SECTORCOUNT
+ QueryBadSectors(
+ ) CONST;
+
+ NONVIRTUAL
+ LBN
+ QueryBitMapIndLbn(
+ ) CONST;
+
+ NONVIRTUAL
+ LBN
+ QueryBadBlkLbn(
+ ) CONST;
+
+ NONVIRTUAL
+ SECTORCOUNT
+ QueryDirBandSize(
+ ) CONST;
+
+ NONVIRTUAL
+ LBN
+ QueryDirBandLbn(
+ ) CONST;
+
+ NONVIRTUAL
+ LBN
+ QueryDirblkMapLbn(
+ ) CONST;
+
+ NONVIRTUAL
+ SECTORCOUNT
+ QuerySectors(
+ ) CONST;
+
+ NONVIRTUAL
+ LBN
+ QuerySidTableLbn(
+ ) CONST;
+
+ NONVIRTUAL
+ SECTORCOUNT
+ SetBadSectors(
+ IN SECTORCOUNT NewCount
+ );
+
+ NONVIRTUAL
+ VOID
+ Dump(
+ IN BOOLEAN TotalDump DEFAULT FALSE
+ ) CONST;
+
+ private:
+
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ _SUPERB* _psb;
+
+};
+
+
+INLINE
+BOOLEAN
+SUPERB::IsValid(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine verifies the two super block signatures.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - The signatures are invalid.
+ TRUE - The signatures are valid.
+
+--*/
+{
+ return _psb && _psb->_sbi.sig1 == SIGSB1 && _psb->_sbi.sig2 == SIGSB2;
+}
+
+
+INLINE
+LBN
+SUPERB::QueryRootFnodeLbn(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the root fnode lbn.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The LBN of the root fnode.
+
+--*/
+{
+ return _psb ? _psb->_sbi.lbnRootFNode : 0;
+}
+
+
+INLINE
+HPFSVER
+SUPERB::QueryVersion (
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the version number for the super block.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The version number of the super block.
+
+--*/
+{
+ return _psb ? _psb->_sbi.bVersion : 0;
+}
+
+
+INLINE
+HPFSVER
+SUPERB::QueryFuncVersion (
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the functional version number.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The functional version number.
+
+--*/
+{
+ return _psb ? _psb->_sbi.bFuncVersion : 0;
+}
+
+
+INLINE
+SECTORCOUNT
+SUPERB::QueryBadSectors (
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of bad sectors recorded in the super
+ block.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of bad sectors recorded in the super block.
+
+--*/
+{
+ return _psb ? _psb->_sbi.culNumBadSects : 0;
+}
+
+
+INLINE
+LBN
+SUPERB::QueryBitMapIndLbn(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the LBN of the bit map indirect.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The LBN of the bit map indirect.
+
+--*/
+{
+ return _psb ? _psb->_sbi.lbnMainrspBitMapIndBlk : 0;
+}
+
+
+INLINE
+LBN
+SUPERB::QueryBadBlkLbn(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the LBN of the bad block.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The LBN of the bad block.
+
+--*/
+{
+ return _psb ? _psb->_sbi.lbnMainrspBadBlkList : 0;
+}
+
+
+INLINE
+SECTORCOUNT
+SUPERB::QueryDirBandSize(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of sectors in the dir block band.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of sectors in the dir block band.
+
+--*/
+{
+ return _psb ? _psb->_sbi.clbndbnd : 0;
+}
+
+
+INLINE
+LBN
+SUPERB::QueryDirBandLbn(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the LBN of the first dir band sector.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The LBN of the first dir band sector.
+
+--*/
+{
+ return _psb ? _psb->_sbi.lbndbndStart : 0;
+}
+
+
+INLINE
+LBN
+SUPERB::QueryDirblkMapLbn(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the LBN of the dir block map.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The LBN of the dir block map.
+
+--*/
+{
+ return _psb ? _psb->_sbi.lbndbndbmStart : 0;
+}
+
+INLINE
+SECTORCOUNT
+SUPERB::QuerySectors(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the number of the sectors on the volume
+ according to the superblock.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The superblock's opinion on the number of sectors on the volume.
+
+--*/
+{
+ return _psb ? _psb->_sbi.culSectsOnVol : 0;
+}
+
+
+INLINE
+LBN
+SUPERB::QuerySidTableLbn(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the LBN of the sid table.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The LBN of the sid table.
+
+--*/
+{
+ return _psb ? _psb->_sbi.lbnSidTab : 0;
+}
+
+
+INLINE
+SECTORCOUNT
+SUPERB::SetBadSectors (
+ SECTORCOUNT NewCount
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the number of bad sectors recorded in the super
+ block.
+
+Arguments:
+
+ NewCount - the new number of bad sectors
+
+Return Value:
+
+ The number of bad sectors recorded in the super block.
+
+--*/
+{
+ return _psb ? (_psb->_sbi.culNumBadSects = NewCount) : 0;
+}
+
+
+#endif // SUPERB_DEFN
diff --git a/private/utils/uhpfs/inc/uhpfs.hxx b/private/utils/uhpfs/inc/uhpfs.hxx
new file mode 100644
index 000000000..0de531cf4
--- /dev/null
+++ b/private/utils/uhpfs/inc/uhpfs.hxx
@@ -0,0 +1,90 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Uhpfs.hxx
+
+Abstract:
+
+ This module contains declarations for HPFS file-system constants
+ and for the global data used within UHPFS.DLL.
+
+
+Author:
+
+ Bill McJohn (BillMc) 31-May-1990
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+
+#if !defined ( _UHPFS_INCLUDED_ )
+
+#define _UHPFS_INCLUDED_
+
+#define MAX_NUM_BITMAPS 512
+#define BITMAP_SIZE 2048
+
+#define MAX_DBS_PER_DIRBAND 4000
+#define SPB 4
+#define SPARE_DIR_BLKS 20
+
+CONST StartOfSuperArea = 0;
+CONST EndOfSuperArea = 19;
+
+CONST cbSector = 512; // The only allowable sector size for HPFS drives.
+
+
+// Number of sectors for various on-disk structures:
+
+CONST SectorsPerBitmap = 4;
+CONST SectorsPerDirblk = 4;
+CONST SectorsPerAlsec = 1;
+CONST SectorsPerFnode = 1;
+CONST SectorsPerCPInfoSector = 1;
+CONST SectorsPerCPDataSector = 1;
+
+// Signatures:
+
+CONST ULONG SparesBlockSignature1 = 0xf9911849;
+CONST ULONG SparesBlockSignature2 = 0xfa5229c5;
+
+CONST ULONG FnodeSignature = 0xF7E40AAE;
+CONST ULONG DirblkSignature = 0x77E40AAE;
+CONST ULONG AlsecSignature = 0x37E40AAE;
+
+CONST ULONG ValM1 = ((('M'-'A')*40+('A'-'A'))*40+'H'-'A');
+CONST ULONG ValM2 = ((('M'-'A')*40+('G'-'A'))*40+'H'-'A');
+CONST ULONG CPInfoSignature = ValM1*40*40*40+ValM2;
+CONST ULONG CPDataSignature = 0x40000000L+ValM1*40*40*40+ValM2;
+
+// Set up the UHPFS_EXPORT macro for exporting from UHPFS (if the
+// source file is a member of UHPFS) or importing from UHPFS (if
+// the source file is a client of UHPFS).
+//
+#if defined ( _AUTOCHECK_ )
+#define UHPFS_EXPORT
+#elif defined ( _UHPFS_MEMBER_ )
+#define UHPFS_EXPORT __declspec(dllexport)
+#else
+#define UHPFS_EXPORT __declspec(dllimport)
+#endif
+
+
+#if DBG==1
+
+// this global buffer is used to support printf-style debug output
+// (using sprintf).
+
+extern CHAR DbgPrintBuffer[];
+
+#endif
+
+
+
+#endif // _UHPFS_INCLUDED_
diff --git a/private/utils/uhpfs/inc/verify.hxx b/private/utils/uhpfs/inc/verify.hxx
new file mode 100644
index 000000000..99d8f3023
--- /dev/null
+++ b/private/utils/uhpfs/inc/verify.hxx
@@ -0,0 +1,35 @@
+#if !defined( VERIFY_DEFN )
+#define VERIFY_DEFN
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ verify.hxx
+
+Abstract:
+
+ This module defines a set of values which are used as
+ return codes by the various VerifyAndFix methods for
+ HPFS structures.
+
+Author:
+
+ Bill McJohn (billmc) 12-06-90
+
+--*/
+
+
+enum VERIFY_RETURN_CODE {
+
+ VERIFY_STRUCTURE_OK,
+ VERIFY_STRUCTURE_BADLY_ORDERED,
+ VERIFY_STRUCTURE_INVALID,
+ VERIFY_INSUFFICIENT_RESOURCES,
+ VERIFY_INTERNAL_ERROR
+
+};
+
+#endif
diff --git a/private/utils/uhpfs/src/alsec.cxx b/private/utils/uhpfs/src/alsec.cxx
new file mode 100644
index 000000000..663480734
--- /dev/null
+++ b/private/utils/uhpfs/src/alsec.cxx
@@ -0,0 +1,922 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ alsec.cxx
+
+Abstract:
+
+ This module contains member function definitions for the ALSEC
+ object, which models an HPFS Allocation Sector.
+
+Author:
+
+ Bill McJohn (billmc) 01-Dec-1990
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "alsec.hxx"
+#include "bitmap.hxx"
+#include "error.hxx"
+#include "hpcensus.hxx"
+#include "hpfsname.hxx"
+#include "hpfssa.hxx"
+#include "orphan.hxx"
+#include "badblk.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+
+
+
+DEFINE_CONSTRUCTOR( ALSEC, SECRUN );
+
+
+VOID
+ALSEC::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Constructs an ALSEC object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _Drive = NULL;
+ _pals = NULL;
+
+ _IsModified = FALSE;
+}
+
+ALSEC::~ALSEC(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for an ALSEC object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+}
+
+
+
+
+BOOLEAN
+ALSEC::Initialize(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN LBN Lbn
+ )
+/*++
+
+Routine Description:
+
+ Initialization function for an ALSEC object.
+
+Arguments:
+
+ Drive -- supplies the drive on which the ALSEC resides
+ Lbn -- supplies the ALSEC's logical block number on that drive
+
+Return Value:
+
+ TRUE if successful; FALSE if unsuccessful.
+
+--*/
+{
+ _Drive = Drive;
+
+ if( !SECRUN::Initialize( &(_mem), Drive, Lbn, SectorsPerAlsec ) ) {
+
+ return( FALSE );
+ }
+
+ _pals = (PALSECD)( _mem.GetBuf( ) );
+
+ if ( _pals == NULL ) {
+
+ return FALSE;
+ }
+
+ _IsModified = FALSE;
+ return TRUE;
+}
+
+
+VOID
+ALSEC::Create(
+ IN LBN ParentLbn,
+ IN BOOLEAN ParentIsFnode
+ )
+/*++
+
+Routine Description:
+
+ This method sets the memory for this ALSEC up to be an empty
+ leaf ALSEC.
+
+Arguments:
+
+ ParentLbn -- Supplies the LBN of this ALSEC's parent.
+ ParentIsFnode -- Supplies a flag which indicates, if TRUE,
+ that the parent of this ALSEC is the FNODE.
+
+Return Value:
+
+ None. (This method always succeeds.)
+
+--*/
+{
+ _pals->sig = AlsecSignature;
+ _pals->lbnSelf = QueryStartLbn();
+ _pals->lbnRent = ParentLbn;
+
+ _pals->std.alblk.bFlag = ( ParentIsFnode ? ABF_FNP : 0 );
+ _pals->std.alblk.cFree = LeavesPerFnode;
+ _pals->std.alblk.cUsed = 0;
+ _pals->std.alblk.oFree = sizeof( ALBLK );
+}
+
+
+VERIFY_RETURN_CODE
+ALSEC::VerifyAndFix(
+ IN OUT HPFS_SA* SuperArea,
+ IN OUT PDEFERRED_ACTIONS_LIST Defer,
+ IN OUT HPFS_PATH* CurrentPath,
+ IN LBN ExpectedParent,
+ IN OUT LBN* NextSectorNumber,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN ErrorsDetected,
+ IN BOOLEAN UpdateAllowed,
+ IN OUT PHPFS_ORPHANS OrphansList,
+ IN BOOLEAN ParentIsFnode
+ )
+/*++
+
+Routine Description:
+
+ Verify the validity of an ALSEC object, and fix recoverable errors
+
+Arguments:
+
+ SuperArea -- Supplies the super area for the volume being checked
+ Defer -- Supplies the deferred actions list for this pass of CHKDSK
+ CurrentPath -- Supplies the path to the object being checked
+ ExpectedParent -- Supplies the LBN of this ALSEC's parent
+ NextSectorNumber -- Supplies the number of sectors in the allocation
+ tree preceding this ALSEC
+ -- Receives the number of sector in the allocation
+ tree up to and including this ALSEC
+ Message -- Supplies a channel for output
+ ErrorsDetected -- Receives a flag which is set if errors are
+ detected which are not reported through the
+ Message channel
+ UpdateAllowed -- Supplies a flag which is TRUE if corrections
+ should be written to disk
+ OrphansList -- Supplies a list of orphaned structures which
+ may be searched for children. (May be NULL).
+ ParentIsFnode -- Supplies a flag which is TRUE if this sector's
+ parent is the file FNode.
+
+Return Value:
+
+ a VERIFY_RETURN_CODE indicating the status of the disk structure.
+
+--*/
+{
+ VERIFY_RETURN_CODE erc;
+
+ DebugPtrAssert( _pals );
+
+ // Determine whether sector is crosslinked, read it,
+ // check the signature, and mark it as in use in the bitmap.
+
+ if( !SuperArea->GetBitmap()->IsFree( QueryStartLbn(), 1L) ) {
+
+ // The structure is crosslinked
+
+ DebugPrintf( "Crosslinked Alsec at lbn %lx\n", QueryStartLbn() );
+ return VERIFY_STRUCTURE_INVALID;
+ }
+
+ if( !Read() ) {
+
+ DebugPrintf( "Unreadable Alsec at lbn %lx\n", QueryStartLbn() );
+ SuperArea->GetBitmap()->SetAllocated( QueryStartLbn(), 1 );
+ SuperArea->GetBadBlockList()->Add( QueryStartLbn() );
+ return VERIFY_STRUCTURE_INVALID;
+ }
+
+ if( _pals->sig != AlsecSignature ) {
+
+ return VERIFY_STRUCTURE_INVALID;
+ }
+
+ SuperArea->GetBitmap()->SetAllocated( QueryStartLbn(), 1L );
+
+ // Check the self and parent lbn fields
+
+ if( _pals->lbnSelf != QueryStartLbn() ) {
+
+ *ErrorsDetected = TRUE;
+
+ if( CurrentPath != NULL ) {
+
+ DebugPrintf( "%s: setting lbnSelf for Alsec at lbn %lx\n",
+ (PCHAR)CurrentPath->GetString(),
+ QueryStartLbn() );
+ }
+
+ _pals->lbnSelf = QueryStartLbn();
+ MarkModified();
+ }
+
+ if( _pals->lbnRent != ExpectedParent ) {
+
+
+ *ErrorsDetected = TRUE;
+
+ if( CurrentPath != NULL ) {
+
+ DebugPrintf( "%s: setting lbnRent for Alsec at lbn %lx\n",
+ (PCHAR)CurrentPath->GetString(),
+ QueryStartLbn() );
+ }
+
+ _pals->lbnRent = ExpectedParent;
+ MarkModified();
+ }
+
+
+ // Set up the storage object, and then ask it to verify itself.
+
+ if( !_Store.Initialize( _Drive,
+ (PSTORED)&(_pals->std ),
+ QueryStartLbn(),
+ FALSE ) ) {
+
+ SuperArea->GetBitmap()->SetFree( QueryStartLbn(), 1L );
+ return VERIFY_INSUFFICIENT_RESOURCES;
+ }
+
+ erc = _Store.VerifyAndFix ( SuperArea,
+ Defer,
+ CurrentPath,
+ NextSectorNumber,
+ Message,
+ ErrorsDetected,
+ UpdateAllowed,
+ OrphansList,
+ ParentIsFnode );
+
+ if ( erc != VERIFY_STRUCTURE_OK ) {
+
+ SuperArea->GetBitmap()->SetFree( QueryStartLbn(), 1L );
+ return erc;
+ }
+
+ if( _Store.QueryModified() ) {
+
+ MarkModified();
+ }
+
+ Flush( UpdateAllowed );
+
+ return VERIFY_STRUCTURE_OK;
+}
+
+
+BOOLEAN
+ALSEC::ScanStorage(
+ IN OUT PULONG NextSectorNumber,
+ IN BOOLEAN ParentIsFnode
+ )
+/*++
+
+Routine Description:
+
+ Traverses the allocation tree rooted at this ALSEC and
+ sets the File-Lbn fields in the storage structures.
+
+Arguments:
+
+ NextSectorNumber -- Supplies the number of sectors in the allocation
+ tree preceding this ALSEC
+ Receives the number of sectors in the allocation
+ tree up to and including this ALSEC
+ ParentIsFnode -- Supplies a flag which indicates whether the
+ parent of this ALSEC is the FNode (TRUE) or
+ another or EA structure (FALSE).
+
+Return Value:
+
+ TRUE if successful.
+
+--*/
+{
+
+ // Set up the storage object, and then ask it to scan itself
+
+ if( !_Store.Initialize( _Drive,
+ (PSTORED)&(_pals->std ),
+ QueryStartLbn(),
+ FALSE ) ) {
+
+ return FALSE;
+ }
+
+ return _Store.ScanStorage( NextSectorNumber, ParentIsFnode );
+}
+
+
+
+BOOLEAN
+ALSEC::IsAlsec(
+ )
+/*++
+
+Routine description:
+
+ Checks the signature of the Allocation sector to make sure
+ that this is indeed an Allocation sector.
+
+Return Value:
+
+ TRUE if the signature is the Allocation sector signature.
+
+--*/
+{
+ return( _pals->sig == AlsecSignature );
+}
+
+
+VOID
+ALSEC::MarkModified(
+ )
+/*++
+
+Routine Description:
+
+ Mark the ALSEC as modified
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _IsModified = TRUE;
+}
+
+
+
+VOID
+ALSEC::Flush(
+ IN BOOLEAN UpdateAllowed
+ )
+/*++
+
+Routine Description:
+
+ Write the ALSEC to disk if it is dirty and we have write permission
+
+Arguments:
+
+ UpdateAllowed -- Supplies a flag that indicates whether we have
+ write permission
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ if( _pals == NULL ) {
+
+ return;
+ }
+
+ if( UpdateAllowed && _IsModified ) {
+
+ Write();
+ _IsModified = FALSE;
+ }
+}
+
+
+
+BOOLEAN
+ALSEC::FindAndResolveHotfix(
+ IN OUT PHPFS_SA SuperArea,
+ IN DEFERRED_SECTOR_TYPE ChildSectorType
+ )
+/*++
+
+Routine Description:
+
+ Examine this ALSEC's children of a specific type to find any
+ which are hotfixed, and resolve those references.
+
+Arguments:
+
+ SuperaArea -- supplies superarea for the volume
+ ChildSectorType -- indicates what sort of child is hotfixed
+
+Return Value:
+
+ TRUE on successful completion
+
+Notes:
+
+ The only valid child type is:
+
+ store -- examine leaves. (If the alsec has node entries,
+ they would have been resolved on the fly.)
+--*/
+{
+ if( !Read() || _pals->sig != AlsecSignature ) {
+
+ // couldn't read it, or it's not an ALSEC
+ return FALSE;
+ }
+
+ switch ( ChildSectorType ) {
+
+ case DEFER_STORE :
+
+ // Set up the storage object, and let it deal with
+ // the deferred reference.
+
+ if( !_Store.Initialize( _Drive,
+ (PSTORED)&(_pals->std ),
+ QueryStartLbn(),
+ FALSE ) ) {
+
+ return FALSE;
+ }
+
+ if( !_Store.FindAndResolveHotfix( SuperArea, ChildSectorType ) ) {
+
+ return FALSE;
+ }
+
+ Write();
+ return TRUE;
+
+ default :
+
+ // Don't recognize this child type
+ return FALSE;
+ }
+}
+
+
+
+BOOLEAN
+ALSEC::ResolveCrosslink(
+ IN OUT HPFS_SA* SuperArea,
+ IN ULONG RunIndex
+ )
+/*++
+
+Routine Description:
+
+ Attempts to copy a crosslinked run
+
+Arguments:
+
+ SuperArea -- super area for the volume being fixed
+ RunIndex -- index in the storage object of the crosslinked run
+
+Return Value:
+
+ TRUE on successful completion
+
+--*/
+{
+
+ if( !Read() || _pals->sig != AlsecSignature ) {
+
+ // couldn't read it, or it's not an ALSEC--can't resolve.
+ return FALSE;
+ }
+
+
+ // Set up the storage object, and let it deal with
+ // the deferred reference.
+
+ if( !_Store.Initialize( _Drive,
+ (PSTORED)&(_pals->std ),
+ QueryStartLbn(),
+ FALSE ) ) {
+
+ return FALSE;
+ }
+
+ if( !_Store.ResolveCrosslink( SuperArea, RunIndex ) ) {
+
+ return FALSE;
+ }
+
+ Write();
+ return TRUE;
+}
+
+
+
+VOID
+ALSEC::SetParent(
+ IN LBN ParentLbn,
+ IN OUT PULONG NextSectorNumber,
+ IN BOOLEAN ParentIsFnode
+ )
+/*++
+
+Routine Description:
+
+ This function tells the ALSEC that it is now part of an allocation
+ tree and indicates its place in the tree. The ALSEC passes this
+ information to its children.
+
+Arguments:
+
+ ParentLbn -- supplies the ALSEC's new parent LBN
+ NextSectorNumber -- Supplies the number of sectors in the allocation
+ tree preceding this ALSEC
+ Receives the number of sectors in the allocation
+ tree up to and including this ALSEC
+ ParentIsFnode -- Supplies a flag which indicates whether the
+ parent of this ALSEC is the FNode (TRUE) or
+ another or EA structure (FALSE).
+
+--*/
+{
+ _pals->lbnRent = ParentLbn;
+
+ ScanStorage( NextSectorNumber, ParentIsFnode );
+}
+
+
+LBN
+ALSEC::QueryPhysicalLbn(
+ IN LBN FileBlockNumber,
+ OUT PULONG RunLength
+ )
+/*++
+
+Routine Description:
+
+ Returns the disk lbn of the FileBlockNumber-th block of the file (or
+ Extended Attribute) described by the allocation sector
+
+Arguments:
+
+ FileBlockNumber -- ordinal within the file or extended attribute
+ of the desired block
+
+Return Value:
+
+ The disk lbn of the desired block. Zero indicates error.
+
+Notes:
+
+ This method assumes that the allocation sector has been read and
+ is valid.
+
+--*/
+{
+ if( !_Store.Initialize( _Drive,
+ (PSTORED)&(_pals->std ),
+ QueryStartLbn(),
+ FALSE ) ) {
+
+ return 0;
+
+ } else {
+
+ return (_Store.QueryPhysicalLbn(FileBlockNumber, RunLength));
+ }
+}
+
+
+
+BOOLEAN
+ALSEC::Truncate(
+ IN LBN SectorCount
+ )
+/*++
+
+Routine Description:
+
+ Truncates the allocation of a file (or extended attribute)
+
+Arguments:
+
+ SectorCount -- number of sectors to retain
+
+Return value:
+
+ TRUE on successful completion
+
+--*/
+{
+ if( !_Store.Initialize( _Drive,
+ (PSTORED)&(_pals->std ),
+ QueryStartLbn(),
+ FALSE ) ||
+ !_Store.Truncate(SectorCount) ) {
+
+ return FALSE;
+
+ }
+
+ Write();
+ return TRUE;
+}
+
+
+
+BOOLEAN
+ALSEC::QueryExtents(
+ IN ULONG MaximumNumberOfExtents,
+ IN OUT PVOID ExtentList,
+ IN OUT PULONG NumberOfExtents
+ )
+/*++
+
+Routine Description:
+
+ This method fetches the list of extents covered by this
+ allocation sector.
+
+Arguments:
+
+ MaximumNumberOfExtents -- Supplies the maximum number of extents
+ that will fit in the client's buffer
+ ExtentList -- Supplies the client's buffer into which
+ extents will be placed.
+ NumberOfExtents -- Supplies the number of extents already
+ in the buffer. This value is updated.
+
+Return Value:
+
+ TRUE upon successful completion. Extents described by this allocation
+ sector (and its children, if any) are added to the buffer and the the
+ number of extents found.
+
+ If ExtentList is NULL and MaximumNumberOfExtents is zero, this method
+ will only return the number of extents associated with this Allocation
+ Sector.
+
+--*/
+{
+ // Set up the storage object and pass the request on down.
+
+ return( _Store.Initialize( _Drive,
+ (PSTORED)&(_pals->std ),
+ QueryStartLbn(),
+ FALSE ) &&
+ _Store.QueryExtents( MaximumNumberOfExtents,
+ ExtentList,
+ NumberOfExtents ) );
+}
+
+
+BOOLEAN
+ALSEC::StoreExtents(
+ IN ULONG NumberOfExtents,
+ IN PALLEAF ExtentList,
+ IN BOOLEAN ParentIsFnode,
+ IN OUT PHPFS_BITMAP VolumeBitmap
+ )
+/*++
+
+Routine Description:
+
+ This method stores a list of extents into this allocation buffer.
+
+Arguments:
+
+ NumberOfExtents -- Supplies the number of extents to be saved.
+ ExtentList -- Supplies the extents for the file.
+ ParentIsFnode -- Supplies a flag which indicates, if TRUE, that
+ the parent of the structure which contains this
+ storage object is the FNode.
+ VolumeBitmap -- Supplies the volume bitmap.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ // Set up the storage object and pass the request on down.
+
+ DebugAssert( NumberOfExtents == 0 || ExtentList != NULL );
+
+ return( _Store.Initialize( _Drive,
+ (PSTORED)&(_pals->std ),
+ QueryStartLbn(),
+ FALSE ) &&
+ _Store.StoreExtents( NumberOfExtents,
+ ExtentList,
+ ParentIsFnode,
+ VolumeBitmap ) &&
+ Write() );
+}
+
+
+BOOLEAN
+ALSEC::TakeCensusAndClear(
+ IN OUT PHPFS_BITMAP VolumeBitmap,
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap,
+ IN OUT PHPFS_CENSUS Census
+ )
+/*++
+
+Routine Description:
+
+ This method takes the census of this allocation sector and its
+ children.
+
+Arguments:
+
+ VolumeBitmap -- Supplies the volume bitmap.
+ HpfsOnlyBitmap -- Supplies the bitmap for sectors containing
+ file-system structures.
+ Census -- Supplies the census object.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+ If this method fails, the reason for failure may be determined
+ using Census->QueryError.
+
+--*/
+{
+ // Record this Allocation Sector in the bitmap of HPFS file
+ // system structures.
+
+ HpfsOnlyBitmap->SetAllocated( QueryStartLbn(), SectorsPerAlsec );
+
+ // Set up the storage object and pass the request on down.
+
+ if( !_Store.Initialize( _Drive,
+ (PSTORED)&(_pals->std ),
+ QueryStartLbn(),
+ FALSE ) ) {
+
+ Census->SetError( HPFS_CENSUS_INSUFFICIENT_MEMORY );
+ return FALSE;
+ }
+
+ if( !_Store.TakeCensusAndClear( VolumeBitmap,
+ HpfsOnlyBitmap,
+ Census ) ) {
+
+ return FALSE;
+ }
+
+
+ // If the storage object changed, write this allocation sector.
+
+ if( _Store.QueryModified() && !Write() ) {
+
+ Census->SetError( HPFS_CENSUS_CORRUPT_VOLUME );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+ALSEC::ReadData(
+ IN ULONG SectorOffset,
+ OUT PVOID OutputBuffer,
+ IN ULONG BytesToRead,
+ OUT PULONG BytesRead,
+ IN PHOTFIXLIST HotfixList
+ )
+/*++
+
+Routine Description:
+
+ This method reads data from the allocation described by this
+ allocation sector.
+
+Arguments:
+
+ SectorOffset -- Supplies the file logical sector to begin the read.
+ OutputBuffer -- Receives the data.
+ BytesToRead -- Supplies the maximum number of bytes to read.
+ BytesRead -- Receives the number of bytes actually read.
+ HotfixList -- Supplies the volume hotfix list. May be NULL,
+ in which case hotfixes are ignored.
+
+Return value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ If this method reaches the end of the data covered by this allocation
+ sector without encountering an error, it will return TRUE. In this
+ case, the value returned in *BytesRead may be less than the amount
+ requested.
+
+--*/
+{
+ HMEM TempBuffer;
+ HOTFIX_SECRUN TempSecrun;
+
+ ULONG SectorsToRead, StartOfRun, RunLength, ThisChunk;
+ ULONG BytesReadSoFar, SectorSize, BytesToCopy;
+
+ SectorSize = _Drive->QuerySectorSize();
+
+ // Determine the number of sectors to be read; note that this includes
+ // any partial trailing sector.
+
+ SectorsToRead = ( BytesToRead % SectorSize ) ?
+ BytesToRead / SectorSize + 1 :
+ BytesToRead / SectorSize;
+
+ BytesReadSoFar = 0;
+
+ while( SectorsToRead ) {
+
+ StartOfRun = QueryPhysicalLbn( SectorOffset, &RunLength );
+
+ if( StartOfRun == 0 ) {
+
+ break;
+ }
+
+ ThisChunk = ( RunLength < SectorsToRead ) ? RunLength : SectorsToRead;
+
+ if( !TempBuffer.Initialize() ||
+ !TempSecrun.Initialize( &TempBuffer,
+ _Drive,
+ HotfixList,
+ StartOfRun,
+ ThisChunk ) ||
+ !TempSecrun.Read() ) {
+
+ return FALSE;
+ }
+
+ BytesToCopy = ( BytesToRead < ThisChunk * SectorSize ) ?
+ BytesToRead :
+ ThisChunk * SectorSize;
+
+ memcpy( (PBYTE)OutputBuffer + BytesReadSoFar,
+ TempSecrun.GetBuf(),
+ BytesToCopy );
+
+ BytesToRead -= BytesToCopy;
+ BytesReadSoFar += BytesToCopy;
+ SectorsToRead -= ThisChunk;
+ SectorOffset += ThisChunk;
+ }
+
+ *BytesRead = BytesReadSoFar;
+ return TRUE;
+}
diff --git a/private/utils/uhpfs/src/badblk.cxx b/private/utils/uhpfs/src/badblk.cxx
new file mode 100644
index 000000000..5bd1ea0d1
--- /dev/null
+++ b/private/utils/uhpfs/src/badblk.cxx
@@ -0,0 +1,795 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ badblk.cxx
+
+Abstract:
+
+ This module contains the member function definitions for BADBLOCKLIST,
+ which models the bad-block list of an HPFS volume.
+
+ Additions to the list are kept in memory, and flushed when the list
+ is written. Note that I do not check for duplicate entries.
+
+Author:
+
+ Bill McJohn (billmc) 01-Dec-1990
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "badblk.hxx"
+#include "bitmap.hxx"
+#include "error.hxx"
+#include "hpfssa.hxx"
+
+
+DEFINE_CONSTRUCTOR( BADBLOCKLIST, OBJECT );
+
+VOID
+BADBLOCKLIST::Construct (
+ )
+
+/*++
+
+Method Description:
+
+ Construct the BADBLOCKLIST object and put it in a harmless state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ // initalize private data, list is empty until read from disk
+ _Drive = NULL;
+ _StartLbn = 0;
+ _LastBlockLbn = 0;
+ _LastBlockRead = FALSE;
+
+ _FirstFreeLbn = 0;
+ _ListSize = 0;
+ _BadBlocks = NULL;
+}
+
+BADBLOCKLIST::~BADBLOCKLIST (
+)
+/*++
+
+Method Description:
+
+ Destruct the BADBLOCKLIST object.
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+BADBLOCKLIST::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Clean up the object in preparation for destruction or reinitialization.
+
+Arguments:
+
+ None.
+
+Return value:
+
+ None.
+
+--*/
+{
+ if( _BadBlocks != NULL ) {
+
+ FREE( _BadBlocks );
+ }
+
+ _Drive = NULL;
+ _StartLbn = 0;
+ _LastBlockLbn = 0;
+ _LastBlockRead = FALSE;
+
+ _FirstFreeLbn = 0;
+ _ListSize = 0;
+ _BadBlocks = NULL;
+}
+
+
+BOOLEAN
+BADBLOCKLIST::Initialize(
+ IN PLOG_IO_DP_DRIVE LogicalDrive,
+ IN LBN StartLbn
+)
+/*++
+
+Routine Description:
+
+ Initialize the BADBLOCKLIST object, and set its private
+ data to meaningful values.
+
+Arguments:
+
+ LogicalDrive -- drive on which the list resides
+ StartLbn -- LBN of the beginning of the on-disk list
+
+Return Value:
+
+ TRUE on successful completion
+
+--*/
+{
+
+ Destroy();
+
+ _Drive = LogicalDrive;
+ _StartLbn = StartLbn;
+
+ if( !_LastBlockMem.Initialize() ||
+ !_LastBlock.Initialize( &_LastBlockMem,
+ _Drive,
+ _StartLbn,
+ SECTORS_PER_BAD_BLOCK ) ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ _LastBlockLbn = _StartLbn;
+ _LastBlockRead = FALSE;
+
+ return TRUE;
+}
+
+
+BOOLEAN
+BADBLOCKLIST::Create(
+ IN LBN Lbn
+ )
+/*++
+
+Routine Description:
+
+ This routine creates a new bad block list at the location specified.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of bad sectors recorded in this object.
+
+--*/
+{
+ HMEM hmem;
+ SECRUN secrun;
+
+ _StartLbn = Lbn;
+ _LastBlockLbn = Lbn;
+ _LastBlockRead = FALSE;
+ _LastBlock.Relocate(Lbn);
+
+ if (!hmem.Initialize() ||
+ !secrun.Initialize(&hmem, _Drive, Lbn, SECTORS_PER_BAD_BLOCK)) {
+ return FALSE;
+ }
+
+ memset(hmem.GetBuf(), 0, (UINT) hmem.QuerySize());
+
+ return secrun.Write();
+}
+
+
+BOOLEAN
+BADBLOCKLIST::AddRun (
+ IN LBN Lbn,
+ IN SECTORCOUNT SectorCount
+)
+/*++
+
+Method Description:
+
+ This method adds a run of sectors to the bad block list.
+
+Arguments:
+
+ Lbn - first sector in run
+ SectorCount - number of sectors in run
+
+Return Value:
+
+ TRUE if successful
+
+--*/
+{
+ // insert the run into the bad block list
+ while ( SectorCount-- > 0) {
+ if (!Add(Lbn++)) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+
+BOOLEAN
+BADBLOCKLIST::ExpandList (
+)
+/*++
+
+Method Description:
+
+ This method expands the memory used to store the list of bad
+ sectors.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ ULONG old_list_size;
+
+ old_list_size = _ListSize;
+
+ if (_ListSize > 0) {
+ _ListSize *= 2;
+ } else {
+ _ListSize = 512;
+ }
+
+ if (!(_BadBlocks = (LBN*) REALLOC(_BadBlocks, _ListSize*sizeof(LBN)))) {
+
+ _ListSize = old_list_size;
+ perrstk->push(NEW_ALLOC_FAILED, QueryClassId());
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+BADBLOCKLIST::Write(
+ HPFS_SA* SuperArea
+)
+/*++
+
+Method Description:
+
+ This method writes the bad block list, appending the contents
+ of the in-memory list to the on-disk list.
+
+Arguments:
+
+ SuperArea -- supplies the SuperArea for the volume
+
+Return Value:
+
+ BOOLEAN - TRUE if successful
+
+--*/
+{
+ REGISTER INT i; // loop index
+ ULONG OffsetInSector;
+ LBN NewLbn;
+ PHPFS_BITMAP Bitmap;
+
+ if( _BadBlocks == NULL || _FirstFreeLbn == 0 ) {
+
+ // Nothing to write--no problem.
+ return TRUE;
+ }
+
+ if( !_LastBlockRead ) {
+
+ if( !_LastBlock.Read() ) {
+
+ return FALSE;
+ }
+ }
+
+ Bitmap = SuperArea->GetBitmap();
+
+ _LastBlockRead = TRUE;
+
+ _LastBlockData = (PBADBLOCKD)_LastBlock.GetBuf();
+
+ while( _LastBlockData->lbnNext != 0 ) {
+
+ _LastBlockLbn = _LastBlockData->lbnNext;
+
+ _LastBlock.Relocate( _LastBlockLbn );
+
+ if( !_LastBlock.Read() ) {
+
+ _LastBlockRead = FALSE;
+ return FALSE;
+ }
+ }
+
+ OffsetInSector = 0;
+
+ while( OffsetInSector < LBNS_IN_BADBLK &&
+ _LastBlockData->lbn[OffsetInSector] != 0 ) {
+
+ OffsetInSector += 1;
+ }
+
+ // OK, we've read the last sector of the on-disk list, and
+ // OffsetInSector gives the the first open slot in that sector.
+
+ // for every LBN in the in memory list
+ for (i = 0; i < _FirstFreeLbn; ++i) {
+
+ DebugAssert(i < _ListSize);
+
+ if( OffsetInSector >= LBNS_IN_BADBLK ) {
+
+ // We've exhausted this block--allocate a new one
+
+ NewLbn = Bitmap->NearLBN( 0,
+ SECTORS_PER_BAD_BLOCK,
+ SECTORS_PER_BAD_BLOCK );
+
+ if( NewLbn == 0 ) {
+
+ // Out of space, can't finish flushing.
+ return FALSE;
+ }
+
+ _LastBlockData->lbnNext = NewLbn;
+
+ if( !_LastBlock.Write() ) {
+ return FALSE;
+ }
+
+ _LastBlockLbn = NewLbn;
+ _LastBlock.Relocate( _LastBlockLbn );
+
+ memset( _LastBlockData, '\0', sizeof( BADBLOCKD) );
+
+ OffsetInSector = 0;
+ }
+
+ _LastBlockData->lbn[OffsetInSector++] = _BadBlocks[i];
+ }
+
+ if( !_LastBlock.Write() ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+BADBLOCKLIST::Add (
+ IN LBN BadLbn
+)
+/*++
+
+Method Description:
+
+ Add the passed LBN to the in memory version of the bad block list.
+ If list is not yet read in, read it in.
+
+Arguments:
+
+ Lbn - sector location to add to list
+
+Return Value:
+
+ BOOLEAN - TRUE if work successful
+
+--*/
+{
+ INT i;
+
+
+ // If the lbn is out-of-range for the volume, don't add it.
+
+ if( BadLbn >= _Drive->QuerySectors().GetLowPart() ) {
+
+ return FALSE;
+ }
+
+ // if object has already allocated BadBlock as it should have
+ if( _BadBlocks == NULL ) {
+
+ _BadBlocks = (LBN *)MALLOC( 512 * sizeof( LBN ) );
+
+ if( _BadBlocks == NULL ) {
+
+ return FALSE;
+ }
+
+ _ListSize = 512;
+ _FirstFreeLbn = 0;
+ }
+
+ if ( _FirstFreeLbn >= _ListSize ) {
+
+ // We've run out of room for the list; we need to grow it.
+ if (!ExpandList()) {
+
+ // Couldn't grow the list.
+ return FALSE;
+ }
+ }
+
+ // Avoid duplicates:
+
+ for( i = 0; i < _FirstFreeLbn; i++ ) {
+
+ if( _BadBlocks[i] == BadLbn ) {
+
+ // This LBN is already in the list.
+
+ return TRUE;
+ }
+ }
+
+ _BadBlocks[_FirstFreeLbn++] = BadLbn;
+ return TRUE;
+}
+
+
+VERIFY_RETURN_CODE
+BADBLOCKLIST::VerifyAndFix (
+ IN OUT PHPFS_SA SuperArea,
+ OUT PULONG BadSectors,
+ IN BOOLEAN UpdateAllowed
+)
+/*++
+
+Method Description:
+
+ Verify and fix the bad block list. If the list resides in sectors
+ that can not be read or written the list will be held in memory only.
+ This differs from the parent class of BADBLOCKLIST which always goes
+ to the disk.
+
+Arguments:
+
+ SuperArea -- Supplies the volume super area.
+ BadSEctors -- Receives the number of bad sectors in the list.
+ UpdateAllowed -- Supplies a flag which indicates, if TRUE, that
+ corrections should be written to disk.
+
+Return Value:
+
+ Verification return code indicates if structure is OK or invalid
+
+Notes:
+
+ If this returns VERIFY_STRUCTURE_INVALID, the list is completely
+ corrupt--the superarea must allocate a new starting LBN and
+ build up a new list.
+
+--*/
+{
+ ULONG SectorsOnVolume;
+ LBN PreviousBlockLbn = 0;
+ ULONG i, SectorsInList = 0;
+
+ if( _Drive == NULL ) {
+
+ // The object is not initialized, or has been incorrectly
+ // initialized.
+ return VERIFY_INTERNAL_ERROR;
+ }
+
+ SectorsOnVolume = _Drive->QuerySectors().GetLowPart();
+
+ _LastBlockLbn = _StartLbn;
+
+ _LastBlock.Relocate( _LastBlockLbn );
+
+ if( !_LastBlock.Read() ) {
+
+ // can't read the first sector--give up.
+ return VERIFY_STRUCTURE_INVALID;
+ }
+
+ _LastBlockData = (PBADBLOCKD)_LastBlock.GetBuf();
+ _LastBlockRead = TRUE;
+
+ SuperArea->GetBitmap()->SetAllocated( _LastBlockLbn,
+ SECTORS_PER_BAD_BLOCK );
+
+ for( i = 0;
+ i < LBNS_IN_BADBLK && _LastBlockData->lbn[i] != 0;
+ i++ ) {
+
+ if( _LastBlockData->lbn[i] < SectorsOnVolume ) {
+
+ SuperArea->GetBitmap()->SetAllocated(_LastBlockData->lbn[i], 1);
+ }
+
+ SectorsInList += 1;
+ }
+
+
+ while( _LastBlockData->lbnNext != 0 ) {
+
+ PreviousBlockLbn = _LastBlockLbn;
+ _LastBlockLbn = _LastBlockData->lbnNext;
+
+ _LastBlock.Relocate( _LastBlockLbn );
+
+ if( !_LastBlock.Read() ) {
+
+ // Back up to the previous block and set its
+ // forward link to zero.
+
+ _LastBlockLbn = PreviousBlockLbn;
+ _LastBlock.Relocate( _LastBlockLbn );
+
+ if( !_LastBlock.Read() ) {
+
+ return VERIFY_STRUCTURE_INVALID;
+ }
+
+ _LastBlockData->lbnNext = 0;
+
+ if( UpdateAllowed ) {
+
+ _LastBlock.Write();
+ }
+ }
+
+ SuperArea->GetBitmap()->SetAllocated( _LastBlockLbn,
+ SECTORS_PER_BAD_BLOCK );
+
+ for( i = 0;
+ i < LBNS_IN_BADBLK && _LastBlockData->lbn[i] != 0;
+ i++ ) {
+
+ if( _LastBlockData->lbn[i] < SectorsOnVolume ) {
+
+ SuperArea->GetBitmap()->
+ SetAllocated(_LastBlockData->lbn[i], 1);
+ }
+
+ SectorsInList += 1;
+ }
+ }
+
+ *BadSectors = SectorsInList;
+ return VERIFY_STRUCTURE_OK;
+}
+
+
+BOOLEAN
+BADBLOCKLIST::QueryBadLbns(
+ IN ULONG MaximumBadLbns,
+ OUT PLBN Buffer,
+ OUT PULONG NumberOfBadLbns
+ )
+/*++
+
+Routine Description:
+
+ This method fetches the list of bad sectors for the volume
+ in a form usable by clients.
+
+Arguments:
+
+ MaximumBadLbns -- supplies the maximum number of LBNs that will
+ fit into the user's buffer.
+ Buffer -- receives the list of bad lbns.
+ NumberOfBadLbns -- receives the number of bad lbns in the list.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This method returns the LBNs in the on-disk structure; it does not
+ return LBNs in the in-memory structure.
+
+ If the user's buffer is too small to hold the entire list, this method
+ will fail.
+
+ If the list is inconsistent, or if any of its segments cannot be
+ read, this method fails.
+
+--*/
+{
+ LBN NextBlockLbn;
+ ULONG Count = 0;
+ ULONG i, SectorsOnVolume;
+
+ DebugPtrAssert( _Drive );
+
+ SectorsOnVolume = _Drive->QuerySectors().GetLowPart();
+
+
+ // Start with the first block in the list:
+
+ NextBlockLbn = _StartLbn;
+
+
+ while( NextBlockLbn != 0 ) {
+
+ // Read the next block.
+
+ _LastBlockLbn = NextBlockLbn;
+
+ _LastBlock.Relocate( _LastBlockLbn );
+
+ if( !_LastBlock.Read() ) {
+
+ _LastBlockLbn = 0;
+ _LastBlockRead = FALSE;
+ return FALSE;
+ }
+
+ _LastBlockData = (PBADBLOCKD)_LastBlock.GetBuf();
+
+
+ // Copy the bad lbns from this block to the client's buffer.
+ // Omit entries which are out of range.
+
+ for( i = 0;
+ i < LBNS_IN_BADBLK && _LastBlockData->lbn[i] != 0;
+ i++ ) {
+
+ if( _LastBlockData->lbn[i] < SectorsOnVolume ) {
+
+ if( Count >= MaximumBadLbns ) {
+
+ return FALSE;
+ }
+
+ Buffer[Count] = _LastBlockData->lbn[i];
+
+ Count += 1;
+ }
+ }
+
+ NextBlockLbn = _LastBlockData->lbnNext;
+ }
+
+
+ *NumberOfBadLbns = Count;
+ return TRUE;
+}
+
+BOOLEAN
+BADBLOCKLIST::TakeCensus(
+ IN PHPFS_BITMAP VolumeBitmap,
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap
+ )
+/*++
+
+Routine Description:
+
+ This method tallies the bad block list in the volume census. It
+ marks the sectors containing the list (but not the bad sectors
+ themselves) in the bitmap of HPFS-only structures; it also checks
+ to make sure that they are marked as in-use in the volume bitmap.
+
+Arguments:
+
+ VolumeBitmap -- Supplies the volume bitmap.
+ HpfsOnlyBitmap -- Supplies the bitmap of hpfs-only structures.
+
+Return value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This method reads the list, so any state information about
+ the current block is lost.
+
+--*/
+{
+ LBN NextBlockLbn;
+
+
+ // Start with the first block in the list:
+
+ NextBlockLbn = _StartLbn;
+
+ while( NextBlockLbn != 0 ) {
+
+ // Read the next block, check that it's correctly marked
+ // as allocated in the volume bitmap, and mark it in the
+ // hpfs-only bitmap.
+
+ if( !VolumeBitmap->CheckUsed( NextBlockLbn, SECTORS_PER_BAD_BLOCK ) ) {
+
+ return FALSE;
+ }
+
+ HpfsOnlyBitmap->SetAllocated( NextBlockLbn, SECTORS_PER_BAD_BLOCK );
+
+ // Read this block to determine the next one. If this block
+ // is unreadable, the volume is corrupt.
+
+ _LastBlockLbn = NextBlockLbn;
+
+ _LastBlock.Relocate( _LastBlockLbn );
+
+ if( !_LastBlock.Read() ) {
+
+ _LastBlockLbn = 0;
+ _LastBlockRead = FALSE;
+ return FALSE;
+ }
+
+ _LastBlockData = (PBADBLOCKD)_LastBlock.GetBuf();
+
+ NextBlockLbn = _LastBlockData->lbnNext;
+ }
+
+ return TRUE;
+}
+
+VOID
+BADBLOCKLIST::Print(
+)
+/*++
+
+Method Description:
+
+ Print the in memory bad block list.
+
+Arguments:
+
+Return Value:
+
+ VOID
+
+--*/
+{
+// REGISTER ULONG i;
+
+ if( _BadBlocks == NULL ) {
+
+ return;
+ }
+
+// printf("Print BBL\n");
+// for (i = 0; i < _FirstFreeLbn; ++i) {
+// printf("BadBlockList[%d]\n", i, _BadBlocks[i]);
+// }
+}
diff --git a/private/utils/uhpfs/src/bitmap.cxx b/private/utils/uhpfs/src/bitmap.cxx
new file mode 100644
index 000000000..a4344c84e
--- /dev/null
+++ b/private/utils/uhpfs/src/bitmap.cxx
@@ -0,0 +1,1977 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ bitmap.cxx
+
+Abstract:
+
+ This module contains member function definitions for HPFS_MAIN_BITMAP,
+ which models the main bitmap of an HPFS volume, and HPFS_BITMAP, which
+ coordinates the main bitmap with the dirblk bitmap.
+
+ Note that, typically, a client will have no contact with the
+ HPFS_MAIN_BITMAP (or, for that matter, with the HPFS_DIR_BITMAP).
+ Instead, all requests should be made through the HPFS_BITMAP, which
+ coordinates these two objects.
+
+Author:
+
+ Bill McJohn (billmc) 01-Dec-1990
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "bitmap.hxx"
+#include "bmind.hxx"
+#include "dirblk.hxx"
+#include "dirmap.hxx"
+#include "error.hxx"
+#include "hfsecrun.hxx"
+#include "hotfix.hxx"
+
+// included for definition of SPB
+
+#include "hpfssa.hxx"
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( HPFS_MAIN_BITMAP, OBJECT, UHPFS_EXPORT );
+
+
+UHPFS_EXPORT
+HPFS_MAIN_BITMAP::~HPFS_MAIN_BITMAP(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for HPFS_MAIN_BITMAP.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+HPFS_MAIN_BITMAP::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Helper routine for object construction. Sets private pointers to
+ safe values.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _Drive = NULL;
+ _HotfixList = NULL;
+ _BitmapBlocks = NULL;
+
+ _NumberOfBlocks = 0;
+ _NumberOfSectors = 0;
+
+ _OrphanScanBlock = NULL;
+ _OrphanIndex = 0;
+ _OrphanBitmapNumber = 0;
+}
+
+
+VOID
+HPFS_MAIN_BITMAP::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This method cleans up the object, in preparation for destruction or
+ reinitialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ delete[] _BitmapBlocks;
+ _BitmapBlocks = NULL;
+
+ DELETE( _OrphanScanBlock );
+ _OrphanScanBlock = NULL;
+
+ _Drive = NULL;
+ _HotfixList = NULL;
+ _NumberOfSectors = 0;
+ _NumberOfBlocks = 0;
+ _OrphanIndex = 0;
+ _OrphanBitmapNumber = 0;
+}
+
+
+UHPFS_EXPORT
+BOOLEAN
+HPFS_MAIN_BITMAP::Initialize(
+ PLOG_IO_DP_DRIVE Drive,
+ PHOTFIXLIST HotfixList
+ )
+/*++
+
+Routine Description:
+
+ This method initializes the HPFS_MAIN_BITMAP object.
+
+Arguments:
+
+ Drive -- Drive the bitmap describes, and on which it resides
+ HotfixList -- hotfix list for Drive
+
+Returns:
+
+ TRUE if successful; FALSE if not successful.
+
+Notes:
+
+ On initialization, all bits in the bitmap are zero (in use).
+ Note in particular that initialization does not include reading
+ the bitmap from disk.
+
+ This object is reinitializable.
+
+--*/
+{
+ SECTORCOUNT SectorSize;
+
+ Destroy();
+
+ if( Drive == NULL ||
+ (_NumberOfSectors = Drive->QuerySectors().GetLowPart() ) == 0 ) {
+
+ perrstk->push(ERR_NOT_INIT, QueryClassId());
+ Destroy();
+ return FALSE;
+ }
+
+ if( (SectorSize = Drive->QuerySectorSize()) == 0) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ _Drive = Drive;
+ _HotfixList = HotfixList;
+
+ // Determine the number of bitmap blocks required by the volume.
+
+ _NumberOfBlocks = _NumberOfSectors/(BITMAP_SIZE * 8);
+ if( _NumberOfSectors % (BITMAP_SIZE * 8) ) {
+
+ _NumberOfBlocks += 1;
+ }
+
+
+ // Use _Mem1 to allocate a suitably aligned buffer big enough
+ // for the volume bitmap
+
+ if( !_Mem1.Initialize() ||
+ !_Mem1.Acquire( _NumberOfBlocks * BITMAP_SIZE,
+ _Drive->QueryAlignmentMask() ) ) {
+
+ perrstk->push(ERR_NOT_INIT, QueryClassId());
+ Destroy();
+ return FALSE;
+ }
+
+ // Initialize the _Mem2, which will be used to dole this memory
+ // out to the constituent bitmap blocks. Note that we cannot
+ // resize _Mem1, since _Mem2 will cache a pointer to that same
+ // chunk of memory.
+
+ if( !_Mem2.Initialize( _Mem1.GetBuf(),
+ _NumberOfBlocks * BITMAP_SIZE ) ) {
+
+ perrstk->push(ERR_NOT_INIT, QueryClassId());
+ Destroy();
+ return FALSE;
+ }
+
+ if( ! _Bitmap.Initialize( _NumberOfBlocks * BITMAP_SIZE * 8,
+ RESET,
+ (PPT)_Mem1.GetBuf() )) {
+
+ perrstk->push(ERR_NOT_INIT, QueryClassId());
+ Destroy();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+VOID
+HPFS_MAIN_BITMAP::SetHotfixList(
+ PHOTFIXLIST HotfixList
+ )
+/*++
+
+Routine Description:
+
+ This method sets the object's Hotfix List. This allows clients to
+ initialize the object without a hotfix list, and then add the hotfix
+ list information when it becomes available. (This functionality
+ is particularly useful for format.)
+
+Arguments:
+
+ HotfixList -- supplies the volume hotfix list.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG i;
+
+ _HotfixList = HotfixList;
+
+ if (_BitmapBlocks != NULL) {
+
+ // The array of HOTFIX_SECRUN objects has been
+ // initialized, so we need to pass this hotfix
+ // list pointer to the individual bitmap blocks.
+
+ for( i = 0; i < _NumberOfBlocks; i++ ) {
+
+ _BitmapBlocks[i].SetHotfixList( HotfixList );
+ }
+ }
+}
+
+
+
+
+
+BOOLEAN
+HPFS_MAIN_BITMAP::InitArray(
+ PCBITMAPINDIRECT BitmapIndirectBlock
+ )
+/*++
+
+Routine Description:
+
+ This method initializes the array of HOTFIX_SECRUN objects, so that
+ we may perform I/O on the bitmap.
+
+Arguments:
+
+ BitmapIndirectBlock -- supplies the volume's Bitmap Indirect Block
+
+Returns:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ ULONG i;
+
+ if( BitmapIndirectBlock == NULL ) {
+
+ return FALSE;
+ }
+
+ // Allocate and initialize the HOTFIX_SECRUN objects. Note
+ // that the same CONT_MEM object (_Mem2, which refers to the bitmap
+ // buffer) is passed to each SECRUN in turn; each SECRUN will
+ // claim the next available bitmap-block-sized chunk of its
+ // memory.
+
+ // Note that we have to use lower-case new for arrays.
+
+ if( (_BitmapBlocks = NEW HOTFIX_SECRUN[_NumberOfBlocks]) == NULL ) {
+
+ return FALSE;
+ }
+
+ for ( i = 0; i < _NumberOfBlocks; i++ ) {
+
+ if( !_BitmapBlocks[i].Initialize( &_Mem2,
+ _Drive,
+ _HotfixList,
+ BitmapIndirectBlock->QueryLbn(i),
+ SectorsPerBitmap ) ) {
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+HPFS_MAIN_BITMAP::Create()
+/*++
+
+Routine Description:
+
+ This method sets up a new bitmap. All sectors are initially marked
+ as FREE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+
+ // Map everything to 1's. The initial state is 'everything is available'.
+ _Bitmap.SetBit(0, _NumberOfSectors & ~(SPB - 1));
+ return TRUE;
+}
+
+
+
+BOOLEAN
+HPFS_MAIN_BITMAP::Write(
+ PBITMAPINDIRECT BitmapIndirectBlock
+ )
+/*++
+
+Routine Description:
+
+ This method writes the main bitmap of an HPFS volume to disk.
+
+Arguments:
+
+ BitmapIndirectBlock -- supplies the bitmap indirect block for the volume.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ The bitmap indirect block specifies where on the disk the bitmap
+ should be written. However, a zero entry in the bitmap indirect
+ block indicates that that portion of the bitmap must be relocated.
+ If this is the case (or if a write fails), this method will allocate
+ a new block for the affected portion of the bitmap, and update the
+ bitmap indirect block.
+
+ Note that this recovery strategy is only pursued once; if the newly-
+ allocated block is also unwriteable, the write fails.
+
+--*/
+{
+ ULONG i;
+ LBN NewLbn;
+
+ if (_BitmapBlocks == NULL) {
+
+ // The array of HOTFIX_SECRUN objects needs to be initialized
+ if( !InitArray( BitmapIndirectBlock ) ) {
+
+ return FALSE;
+ }
+ }
+
+ // Write the blocks.
+
+ for( i = 0; i < _NumberOfBlocks; i++ ) {
+
+ if( _BitmapBlocks[i].QueryStartLbn() == 0 ||
+ !_BitmapBlocks[i].Write() ) {
+
+ // Either this chunk of the bitmap does not have a
+ // place to live, or we couldn't write it there--
+ // let's try and relocate it. Find a free block
+ // and write the bitmap there, instead (updating the
+ // bitmap indirect block, or course).
+
+ if( (NewLbn = NearLBN( BitmapIndirectBlock->QueryLbn(i),
+ SectorsPerBitmap,
+ SectorsPerBitmap )) == 0 ) {
+
+ // Couldn't allocate a replacement.
+ return FALSE;
+ }
+
+ // We've allocated a new location for the
+
+ BitmapIndirectBlock->SetLbn( i, NewLbn );
+
+ _BitmapBlocks[i].Relocate( NewLbn );
+
+ if( !_BitmapBlocks[i].Write() ) {
+
+ // We got a second failure--give up.
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+HPFS_MAIN_BITMAP::Read(
+ PCBITMAPINDIRECT BitmapIndirectBlock
+ )
+/*++
+
+Routine Description:
+
+ This method reads the main bitmap of an HPFS volume from disk.
+
+Arguments:
+
+ BitmapIndirectBlock -- supplies the bitmap indirect block for the volume.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+
+ ULONG i;
+
+ if (_BitmapBlocks == NULL) {
+
+ // The array of HOTFIX_SECRUN objects needs to be initialized
+ if( !InitArray( BitmapIndirectBlock ) ) {
+
+ return FALSE;
+ }
+ }
+
+ // Read the blocks.
+
+ for( i = 0; i < _NumberOfBlocks; i++ ) {
+
+ if( !_BitmapBlocks[i].Read() ) {
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+
+
+UHPFS_EXPORT
+BOOLEAN
+HPFS_MAIN_BITMAP::SetFree(
+ LBN Lbn,
+ SECTORCOUNT sc)
+/*++
+
+Routine Description:
+
+ This method marks a run of sectors as free.
+
+Arguments:
+
+ Lbn -- supplies the first block number in the run
+ sc -- supplies the number of blocks to mark
+
+Returns
+
+ TRUE upon successful completion.
+
+--*/
+{
+ _Bitmap.SetBit(Lbn, sc);
+ return TRUE;
+}
+
+
+
+UHPFS_EXPORT
+BOOLEAN
+HPFS_MAIN_BITMAP::SetAllocated(
+ LBN Lbn,
+ SECTORCOUNT sc)
+/*++
+
+Routine Description:
+
+ This method marks a run of sectors as allocated.
+
+Arguments:
+
+ Lbn -- supplies the first block number in the run
+ sc -- supplies the number of blocks to mark used.
+
+Returns
+
+ TRUE upon successful completion.
+
+--*/
+{
+ _Bitmap.ResetBit(Lbn, sc);
+ return TRUE;
+}
+
+
+SECTORCOUNT
+HPFS_MAIN_BITMAP::QueryFreeSectors(
+ ) const
+/*++
+
+Routine Description:
+
+ This method determines the number of free sectors in the bitmap.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of sector marked free in the bitmap.
+
+--*/
+{
+ return _Bitmap.QueryCountSet();
+}
+
+
+UHPFS_EXPORT
+BOOLEAN
+HPFS_MAIN_BITMAP::IsFree(
+ LBN Lbn ) const
+/*++
+
+Routine Description:
+
+ This method determines whether an LBN is free.
+
+Arguments:
+
+ Lbn -- supplies the LBN which is to be tested.
+
+Returns:
+
+ TRUE if the sector is free; FALSE if it is allocated or out of range.
+
+--*/
+{
+
+ if( Lbn < _NumberOfSectors ) {
+
+ return _Bitmap.IsBitSet( (PT)Lbn );
+
+ } else {
+
+ return FALSE;
+ }
+}
+
+
+
+
+LBN
+HPFS_MAIN_BITMAP::QueryNextAllocLBN(
+ LBN Lbn,
+ PBOOLEAN fOk) const
+/*++
+
+Routine Description:
+
+ Query next allocated sector. Find the next allocated sector
+ past 'LBN'. If the end of the bitmap is reached without finding
+ an allocated sector, then return 0.
+
+Arguments:
+
+ Lbn -- Lbn + 1 marks the first sector of the search.
+ fOk -- receives TRUE if everything went ok.
+
+Return Value:
+
+ The Lbn of the first allocated sector following 'Lbn' or 0.
+
+Notes:
+
+ You can't check sector zero with this routine. Use "IsFree".
+
+--*/
+{
+ // Set fOk to FALSE.
+ if (fOk)
+ *fOk = FALSE;
+
+ // While sector is free and not end of list.
+ for (Lbn++; _Bitmap.IsBitSet(Lbn) && Lbn < _NumberOfSectors; Lbn++)
+ ;
+
+ // Set fOk to TRUE.
+ if (fOk)
+ *fOk = TRUE;
+
+ return (Lbn < _NumberOfSectors) ? Lbn : 0;
+}
+
+
+
+LBN
+HPFS_MAIN_BITMAP::NearLBN(
+ LBN Lbn,
+ SECTORCOUNT sc,
+ SECTORCOUNT scAlign,
+ BOOLEAN fBackward)
+/*++
+
+Routine Description:
+
+ Allocate a cluster of sectors near the inputed LBN.
+
+ Searches forward, beginning at 'Lbn', for a free run of sectors
+ of length 'sc'. This routine ensures that the sectors are
+ allocated on a boundary that is a multiple of 'scAlign'.
+ If the search fails in the forward direction then the search
+ is attempted in the backward direction. If the 'fBackward'
+ flag is set then the the backward search is attempted first,
+ and then the forward one.
+
+Arguments:
+
+ Lbn -- supplies the recommended location of the sectors
+ to be allocated. This method will try to allocate
+ the new run near this Lbn.
+ sc -- supplies the number of sectors to be allocated.
+ scAlign -- supplies the alignment factor; the starting LBN of the
+ run must be a multiple of this value.
+ fBackward -- supplies a flag that indicated (if TRUE) that the
+ search should be performed backwards from Lbn.
+
+Return Value:
+
+ starting LBN of reserved sectors, zero for failure.
+
+--*/
+{
+ LBN FoundLbn;
+
+ // Check that scAlign is non-zero.
+ if (!scAlign) {
+
+ perrstk->push(ERR_BM_PARAMETER, QueryClassId());
+ return 0;
+ }
+
+ // Perform first search pattern.
+ FoundLbn = fBackward ? BackwardLBN(Lbn, sc, scAlign) :
+ ForwardLBN(Lbn, sc, scAlign);
+
+ // If first search failed then perform another.
+ if (!FoundLbn) {
+
+ FoundLbn = fBackward ? ForwardLBN(Lbn, sc, scAlign) :
+ BackwardLBN(Lbn, sc, scAlign);
+
+ }
+
+ // If both searches failed.
+ if (!FoundLbn) {
+
+ perrstk->push(ERR_BM_FULL, QueryClassId());
+ return 0;
+ }
+
+ return FoundLbn;
+}
+
+
+
+LBN
+HPFS_MAIN_BITMAP::ForwardLBN(
+ LBN Lbn,
+ SECTORCOUNT sc,
+ SECTORCOUNT scAlign)
+/*++
+
+Routine Description:
+
+ Allocate a cluster of sectors near the inputed LBN.
+
+ Searches forward, beginning at 'LBN', for a free run of sectors
+ of length 'sc'. This routine ensures that the sectors are
+ allocated on a boundary that is a multiple of 'scAlign'.
+
+Arguments:
+
+ Lbn -- supplies the recommended location of the sectors
+ to be allocated. This method will try to allocate
+ the new run near this Lbn.
+ sc -- supplies the number of sectors to be allocated.
+ scAlign -- supplies the alignment factor; the starting LBN of the
+ run must be a multiple of this value.
+
+Return Value:
+
+ starting LBN of reserved sectors or 0 on failure
+
+--*/
+{
+ LBN i;
+ SECTORCOUNT count;
+ LBN LbnForward;
+
+ // Perform a search forward for free sectors.
+ for (i = Lbn, count = sc; count && i < _NumberOfSectors; i++) {
+
+ // If the current sector is free.
+ if (_Bitmap.IsBitSet(i))
+ {
+ // If this is the first bit to be accepted and the alignment
+ // is incorrect.
+ if (count == sc && i%scAlign)
+ {
+ // Continue search at next bit.
+ continue;
+ }
+
+ // Decrement the number of sectors still required.
+ count--;
+ }
+ else
+ {
+ // Set the number of contiguous sectors still required to sc.
+ count = sc;
+ }
+ }
+
+ // If search was unsuccessful then return 0.
+ if (count)
+ return 0;
+
+ // Compute starting sector of free run.
+ LbnForward = i - sc;
+
+ // Claim the sectors as used.
+ _Bitmap.ResetBit(LbnForward, sc);
+
+ return LbnForward;
+}
+
+
+
+LBN
+HPFS_MAIN_BITMAP::BackwardLBN(
+ LBN Lbn,
+ SECTORCOUNT sc,
+ SECTORCOUNT scAlign)
+/*++
+
+Routine Description:
+
+ Allocate a cluster of sectors near the inputed LBN.
+
+ Searches backward, beginning at 'Lbn', for a free run of sectors
+ of length 'sc'. This routine ensures that the sectors are
+ allocated on a boundary that is a multiple of 'scAlign'.
+
+Arguments:
+
+ Lbn -- supplies the recommended location of the sectors
+ to be allocated. This method will try to allocate
+ the new run near this Lbn.
+ sc -- supplies the number of sectors to be allocated.
+ scAlign -- supplies the alignment factor; the starting LBN of the
+ run must be a multiple of this value.
+
+Return Value:
+
+ starting LBN of reserved sectors or 0 on failure
+
+--*/
+{
+ LBN i;
+ SECTORCOUNT count;
+ LBN LbnBackward;
+
+ // Perform a search backward for free sectors.
+
+ // Set i to end of wanted sectors or, if necessary, to end of disk.
+
+ i = (Lbn + sc <= _NumberOfSectors) ? Lbn + sc - 1 :
+ _NumberOfSectors - 1;
+
+ for (count = sc; count && i; i--) {
+
+ // If the current sector is free.
+ if (_Bitmap.IsBitSet(i))
+ {
+ // If this is the first bit to be accepted and the alignment
+ // is incorrect.
+ if (count == sc && (i - sc + 1)%scAlign)
+ {
+ // Continue search at next bit.
+ continue;
+ }
+
+ // Decrement the number of sectors still required.
+ count--;
+ }
+ else
+ {
+ // Set the number of contiguous sectors still required to sc.
+ count = sc;
+ }
+ }
+
+ // If search was unsuccessful then return 0.
+ if (count) {
+ return 0;
+ }
+
+ // Compute starting sector of free run.
+ LbnBackward = i + 1;
+
+ // Claim the sectors as used.
+ _Bitmap.ResetBit(LbnBackward, sc);
+
+ return LbnBackward;
+}
+
+
+
+BOOLEAN
+HPFS_MAIN_BITMAP::QueryNextOrphan(
+ IN PBITMAPINDIRECT BitmapIndirectBlock,
+ OUT PLBN NextOrphan,
+ IN OUT PBOOLEAN AllocationErrors
+ )
+/*++
+
+Routine Description:
+
+ This method returns the next potential orphan sector. A sector
+ is a potential orphan if it is marked as in-use in the on-disk
+ bitmap but as free in the in-memory bitmap.
+
+Arguments:
+
+ BitmapIndirectBlock -- supplies the volume's bitmap indirect block
+ NextOrphan -- receives the next potential orphan identified
+ AllocationErrors -- receives TRUE if an allocation error (ie.
+ a sector marked as in-use by in-memory bitmap
+ but free on disk) is detected.
+
+Return Value:
+
+ TRUE if successful--
+ *NextOrphan is set to the next potential orphan LBN, or zero
+ if there are no more
+
+ FALSE if error
+
+--*/
+{
+ LBN BitmapNumber, PotentialOrphan;
+ ULONG OrphanByteOffset, OffsetInBlock, BytesRemainingInBlock, i;
+ PBYTE ByteInMemory, ByteFromDisk;
+
+ if( _OrphanScanBlock == NULL ) {
+
+ if( !_OrphanScanMem.Initialize() ||
+ (_OrphanScanBlock = NEW HOTFIX_SECRUN) == NULL ||
+ !_OrphanScanBlock->Initialize( &_OrphanScanMem,
+ _Drive,
+ _HotfixList,
+ BitmapIndirectBlock->QueryLbn(0),
+ SectorsPerBitmap ) ) {
+
+ return FALSE;
+ }
+
+ if( ! _OrphanBitmap.Initialize( BITMAP_SIZE * 8,
+ RESET,
+ (PPT)(_OrphanScanBlock->GetBuf()))) {
+
+ // Couldn't initialize the bitvector
+ return FALSE;
+ }
+
+ if( !_OrphanScanBlock->Read() ) {
+
+ return FALSE;
+ }
+
+ _OrphanBitmapNumber = 0;
+ _OrphanIndex = 0;
+ }
+
+ // _OrphanIndex points at the last potential orphan found and reported,
+ // so we'll start our search there. Note that, since we search that
+ // byte again, we'll find that same orphan again, so we have to be careful
+ // not to return something we already returned.
+
+ OrphanByteOffset = _OrphanIndex / 8;
+
+ while( _OrphanIndex < _NumberOfSectors ) {
+
+ // Make sure we haven't fallen off the end of the world:
+
+ if( OrphanByteOffset * 8 >= _NumberOfSectors ) {
+
+ // No more orphans. Set _OrphanIndex to a value that will
+ // disable future calls to this method.
+
+ _OrphanIndex = _NumberOfSectors;
+ break;
+ }
+
+
+ // Determine the block-number of the bitmap block we're in and
+ // make sure that we have the correct block of the on-disk bitmap:
+
+ BitmapNumber = OrphanByteOffset / BITMAP_SIZE;
+
+ if( BitmapNumber != _OrphanBitmapNumber ) {
+
+ // We need to read a different bitmap block
+ _OrphanBitmapNumber = BitmapNumber;
+
+ _OrphanScanBlock->
+ Relocate( BitmapIndirectBlock->
+ QueryLbn( _OrphanBitmapNumber ));
+
+ if( !_OrphanScanBlock->Read() ) {
+
+ return FALSE;
+ }
+ }
+
+
+ // Scan the remainder of the current block for discrepancies. Note
+ // that the memory allocated for the bitmap is in bitmap-block sized
+ // chunks, so we can scan through an entire bitmap block without
+ // faulting. (However, we do have to check that the LBN is
+ // in range before consulting the bitvectors.)
+
+ OffsetInBlock = OrphanByteOffset % BITMAP_SIZE;
+ BytesRemainingInBlock = (ULONG)(BITMAP_SIZE - OffsetInBlock);
+
+ ByteInMemory = (PBYTE)(_Mem1.GetBuf()) + OrphanByteOffset;
+ ByteFromDisk = (PBYTE)(_OrphanScanMem.GetBuf()) + OffsetInBlock;
+
+ while( BytesRemainingInBlock-- ) {
+
+ if( *ByteInMemory != *ByteFromDisk ) {
+
+ // There's a discrepancy between the in-memory bitmap
+ // and the on-disk bitmap.
+
+ if( !*AllocationErrors ) {
+
+ // We haven't already detected and reported an
+ // allocation error, so we need to check for it
+ // here. An allocation error is a bit that's
+ // free (set) on disk and reset (in use) in memory.
+
+ for( i = 0; i < 8; i++ ) {
+
+ PotentialOrphan = OrphanByteOffset * 8 + i;
+
+ if( PotentialOrphan < _NumberOfSectors &&
+ !_Bitmap.IsBitSet( PotentialOrphan ) &&
+ _OrphanBitmap.IsBitSet( PotentialOrphan %
+ (BITMAP_SIZE * 8) ) ) {
+
+ // An allocation error has been found.
+
+ *AllocationErrors = TRUE;
+ }
+ }
+ }
+
+ // Now look for an orphan. An orphan is the inverse of
+ // an allocation error--a bit that is reset (in use) on
+ // disk but set (free) in memory.
+
+ for( i = 0; i < 8; i++ ) {
+
+ PotentialOrphan = OrphanByteOffset * 8 + i;
+
+ if( PotentialOrphan >= _NumberOfSectors ) {
+
+ // We're past the end of the disk--no more
+ // orphans. Set _OrphanIndex to a value that
+ // will end the search.
+
+ _OrphanIndex = _NumberOfSectors;
+ break;
+ }
+
+
+ if( PotentialOrphan > _OrphanIndex &&
+ _Bitmap.IsBitSet( PotentialOrphan ) &&
+ !_OrphanBitmap.IsBitSet( PotentialOrphan
+ % (BITMAP_SIZE * 8) ) ) {
+
+ // We've found an orphan.
+
+ _OrphanIndex = PotentialOrphan;
+ *NextOrphan = _OrphanIndex;
+ return TRUE;
+ }
+ }
+ }
+
+ // So much for that byte; bump the counters and pointers.
+
+ OrphanByteOffset += 1;
+ ByteInMemory += 1;
+ ByteFromDisk += 1;
+ }
+
+ // We've scanned the current block, so go back to the top of the
+ // loop and get the next one.
+
+ DebugAssert( (OrphanByteOffset % BITMAP_SIZE) == 0 );
+ }
+
+
+ // No more orphans
+
+ *NextOrphan = 0;
+ return TRUE;
+}
+
+
+
+BOOLEAN
+HPFS_MAIN_BITMAP::AndWithDisk (
+ PBITMAPINDIRECT BitmapIndirectBlock
+ )
+/*++
+
+Routine Description:
+
+ This method ANDs the in-memory bitmap with the on-disk bitmap.
+
+Arguments:
+
+ BitmapIndirectBlock -- supplies the volume's bitmap indirect block
+
+Return Value:
+
+ TRUE on successful completion
+
+--*/
+{
+ BITVECTOR DiskBits;
+ HOTFIX_SECRUN Secrun;
+ HMEM Mem;
+ LBN BitmapLbn;
+ ULONG BlockIndex, i;
+ LBN CurrentBase;
+
+
+ if( !Mem.Initialize() ||
+ !Secrun.Initialize( &Mem,
+ _Drive,
+ _HotfixList,
+ 0,
+ SectorsPerBitmap ) ) {
+
+ return FALSE;
+ }
+
+ if( !DiskBits.Initialize( BITMAP_SIZE * 8,
+ RESET,
+ (PPT)(Mem.GetBuf()) ) ) {
+
+ // unable to initialize the bit vector.
+
+ return FALSE;
+ }
+
+
+
+ for( BlockIndex = 0; BlockIndex < _NumberOfBlocks; BlockIndex++ ) {
+
+ // Read this block and AND it with the appropriate
+ // section of the bitmap. If it can't be read, don't
+ // bother.
+
+ BitmapLbn = BitmapIndirectBlock->QueryLbn(BlockIndex);
+
+ if( BitmapLbn != 0 ) {
+
+ Secrun.Relocate( BitmapLbn );
+
+ if( Secrun.Read() ) {
+
+ // AND it in.
+
+ CurrentBase = BlockIndex * BITMAP_SIZE * 8;
+
+ for( i = 0; i < BITMAP_SIZE * 8; i++ ) {
+
+ if( !DiskBits.IsBitSet(i) ) {
+
+ SetAllocated( CurrentBase + i, 1 );
+ }
+ }
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+
+DEFINE_CONSTRUCTOR( HPFS_BITMAP, OBJECT );
+
+
+VOID
+HPFS_BITMAP::Construct (
+ )
+
+/*++
+
+Method Description:
+
+ Construct the HPFS_BITMAP object. This class enhances the
+ HPFS_MAIN_BITMAP without deriving from it. This is done interfacing
+ to the distributed bitmaps is done by HPFS_MAIN_BITMAP only. All other
+ objects use this class to interface to the bitmap as on in memory
+ string of bits.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ _MainBitmap = NULL;
+ _DirBitmap = NULL;
+
+ _QueriedOrphanDirblks = FALSE;
+}
+
+
+HPFS_BITMAP::~HPFS_BITMAP(
+ )
+/*++
+
+Method Description:
+
+ This method destroys the HPFS_BITMAP object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+
+VOID
+HPFS_BITMAP::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This method cleans the HPFS_BITMAP object in preparation
+ for reinitialization or destruction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DELETE( _MainBitmap );
+ _MainBitmap = NULL;
+
+ DELETE( _DirBitmap );
+ _DirBitmap = NULL;
+
+ _QueriedOrphanDirblks = FALSE;
+
+}
+
+
+
+BOOLEAN
+HPFS_BITMAP::Initialize(
+ PLOG_IO_DP_DRIVE Drive,
+ LBN FirstLbnOfDirblkBitmap,
+ SECTORCOUNT NumberOfSectorsInDirblkBand,
+ LBN FirstLbnOfDirblkBand,
+ PHOTFIXLIST HotfixList
+ )
+/*++
+
+Routine Description:
+
+ This method initializes the HPFS bitmap.
+
+Arguments:
+
+ Drive -- supplies the drive on which the
+ bitmap resides.
+ FirstLbnOfDirblkBitmap -- supplies the starting lbn of the
+ volume's dirblk bitmap
+ NumberOfSectorsInDirblkBand -- supplies the number of sectors in the
+ volume's dirblk band
+ FirstLbnOfDirblkBand -- supplies the starting lbn of
+ the dirblk band
+ HotfixList -- supplies the volume's Hotfix list
+ (may be NULL).
+
+Return Value:
+
+ TRUE on successful completion
+
+--*/
+{
+
+ if( Drive == NULL ) {
+
+ return FALSE;
+ }
+
+ Destroy();
+
+ // Remember the location of the directory band
+
+ _FirstLbnOfDirblkBand = FirstLbnOfDirblkBand;
+
+ _LastLbnOfDirblkBand = FirstLbnOfDirblkBand +
+ NumberOfSectorsInDirblkBand - 1;
+
+ _SectorsInDirblkBand = NumberOfSectorsInDirblkBand;
+
+ if( (_MainBitmap = NEW HPFS_MAIN_BITMAP ) == NULL ||
+ !_MainBitmap->Initialize( Drive ) ||
+ (_DirBitmap = NEW HPFS_DIR_BITMAP ) == NULL ||
+ !_DirBitmap->Initialize( Drive,
+ HotfixList,
+ FirstLbnOfDirblkBitmap,
+ NumberOfSectorsInDirblkBand,
+ FirstLbnOfDirblkBand ) ) {
+
+ perrstk->push(ERR_NOT_INIT, QueryClassId());
+ Destroy();
+ return FALSE;
+ }
+
+ _MainBitmap->Create();
+ _MainBitmap->SetAllocated( FirstLbnOfDirblkBitmap, SectorsPerBitmap );
+ _MainBitmap->SetAllocated( FirstLbnOfDirblkBand,
+ NumberOfSectorsInDirblkBand );
+
+ _QueriedOrphanDirblks = FALSE;
+
+ return TRUE;
+}
+
+
+BOOLEAN
+HPFS_BITMAP::SetFree(
+ IN LBN StartLbn,
+ IN SECTORCOUNT SectorCount
+ )
+/*++
+
+Routine Description:
+
+ This method marks a run of sectors as free.
+
+Arguments:
+
+ StartLbn -- supplies the first LBN of the run.
+ SectorCount -- supplies the number of sectors in the run.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+
+ if( _MainBitmap == NULL || _DirBitmap == NULL ) {
+
+ return FALSE;
+ }
+
+ if( StartLbn >= _FirstLbnOfDirblkBand &&
+ StartLbn <= _LastLbnOfDirblkBand ) {
+
+ DebugAssert( SectorCount % SectorsPerDirblk == 0 );
+
+ return( _DirBitmap->SetFree(StartLbn,
+ SectorCount/SectorsPerDirblk) );
+
+ } else {
+
+ // We'll look in the main bitmap. Note that the sectors of
+ // the dirblk band are mark as 'USED' in the main bitmap.
+
+ return( _MainBitmap->SetFree( StartLbn, SectorCount) );
+ }
+}
+
+
+
+BOOLEAN
+HPFS_BITMAP::SetAllocated (
+ IN LBN StartLbn,
+ IN SECTORCOUNT SectorCount
+)
+/*++
+
+Method Description:
+
+ This method marks a run of sectors as used.
+
+Arguments:
+
+ StartLbn - supplies the starting LBN of the run
+ SectorCount - supplies the number of sectors in the run
+
+Return Value:
+
+ TRUE upon successful completion
+
+--*/
+{
+
+ if( _MainBitmap == NULL || _DirBitmap == NULL ) {
+
+ return FALSE;
+ }
+
+ if( StartLbn >= _FirstLbnOfDirblkBand &&
+ StartLbn <= _LastLbnOfDirblkBand ) {
+
+ return( _DirBitmap->SetAllocated( StartLbn,
+ SectorCount/SectorsPerDirblk ) );
+
+ } else {
+
+ // We'll look in the main bitmap. Note that the sectors of
+ // the dirblk band are mark as 'USED' in the main bitmap.
+
+ return( _MainBitmap->SetAllocated( StartLbn, SectorCount) );
+ }
+}
+
+
+
+
+LBN
+HPFS_BITMAP::AllocateDirblk(
+ IN BOOLEAN Backward
+ )
+/*++
+
+Routine Description:
+
+ This method allocates a directory block.
+
+Arguments:
+
+ Backward -- supplies a flag which if TRUE indicates that we should start
+ our search from the end of the dirblk band, rather than the
+ beginning. (If we overflow the dirblk band and allocate from
+ the main bitmap, this parameter is ignored.)
+
+Return Value:
+
+ LBN of the first sector in the DIRBLK allocated; zero if no
+ sectors are available.
+
+Notes:
+
+ This routine will allocate a directory block based on the state
+ of the bitmaps. First, it tries to allocate one from the dirblk
+ band; if that fails, it attempts to allocate from the main bitmap.
+ Note that a dirblk requires SectorsPerDirblk sectors aligned on
+ a SectorsPerDirblk boundary.
+
+--*/
+{
+ LBN NewLbn;
+
+ if( _DirBitmap == NULL || _MainBitmap == NULL ) {
+
+ return 0;
+ }
+
+ if( (NewLbn = _DirBitmap->GetDirblkLbn( Backward )) != 0 ) {
+
+ // got one from the dirblk band.
+ return NewLbn;
+
+ } else return ( _MainBitmap->MiddleLBN( SectorsPerDirblk,
+ SectorsPerDirblk) );
+}
+
+
+
+LBN
+HPFS_BITMAP::NearLBN(
+ LBN Lbn,
+ SECTORCOUNT sc,
+ SECTORCOUNT scAlign,
+ BOOLEAN fBackward
+ )
+/*++
+
+Routine Description:
+
+ Allocate a cluster of sectors near the inputed LBN.
+
+ Searches forward, beginning at 'Lbn', for a free run of sectors
+ of length 'sc'. This routine ensures that the sectors are
+ allocated on a boundary that is a multiple of 'scAlign'.
+ If the search fails in the forward direction then the search
+ is attempted in the backward direction. If the 'fBackward'
+ flag is set then the the backward search is attempted first,
+ and then the forward one.
+
+Arguments:
+
+ Lbn -- supplies the recommended location of the sectors
+ to be allocated. This method will try to allocate
+ the new run near this Lbn.
+ sc -- supplies the number of sectors to be allocated.
+ scAlign -- supplies the alignment factor; the starting LBN of the
+ run must be a multiple of this value.
+ fBackward -- supplies a flag that indicated (if TRUE) that the
+ search should be performed backwards from Lbn.
+
+Return Value:
+
+ starting LBN of reserved sectors, zero for failure.
+
+--*/
+{
+ return ( _MainBitmap->NearLBN( Lbn, sc, scAlign, fBackward ) );
+}
+
+
+SECTORCOUNT
+HPFS_BITMAP::QueryFreeSectors(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method determines the number of free sectors in the bitmap.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of sector marked free in the bitmap.
+
+--*/
+{
+ return _MainBitmap->QueryFreeSectors();
+}
+
+
+
+UHPFS_EXPORT
+BOOLEAN
+HPFS_BITMAP::IsFree (
+ IN LBN StartLbn,
+ IN SECTORCOUNT SectorCount,
+ IN BOOLEAN IsDirblk
+) CONST
+/*++
+
+Method Description:
+
+ This method determines whether a run of sectors is marked as free
+ in the bitmap.
+
+Arguments:
+
+ StartLbn - supplies the first LBN of the run.
+ SectorCount - supplies the length of the run.
+ IsDirblk - supplies a flag that indicates, if TRUE, that the allocation
+ may be taken from the Dirblk band.
+
+Return Value:
+
+ TRUE if the sectors are all free, false if any sector is allocated
+ or beyond the end of the disk, or if an error has occurred.
+
+--*/
+{
+ REGISTER LBN Lbn; // loop index
+ REGISTER LBN FinalLbn; // loop range
+
+
+ if( _MainBitmap == NULL || _DirBitmap == NULL ) {
+
+ return FALSE;
+ }
+
+ if( IsDirblk &&
+ StartLbn >= _FirstLbnOfDirblkBand &&
+ StartLbn <= _LastLbnOfDirblkBand ) {
+
+ DebugAssert( SectorCount == SectorsPerDirblk );
+
+ return( _DirBitmap->IsFree( StartLbn ) );
+
+ } else {
+
+ // We'll look in the main bitmap. Note that the sectors of
+ // the dirblk band are mark as 'USED' in the main bitmap.
+
+ FinalLbn = StartLbn + SectorCount - 1;
+
+ for( Lbn = StartLbn; Lbn <= FinalLbn; Lbn++ ) {
+
+ if( !_MainBitmap->IsFree( Lbn ) ) {
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+ }
+}
+
+BOOLEAN
+HPFS_BITMAP::CheckUsed(
+ IN LBN StartLbn,
+ IN SECTORCOUNT SectorCount
+ )
+/*++
+
+Routine Description:
+
+ This method checks to see that all sectors in the specified
+ range are in use. Note that it only checks the main bitmap,
+ it does not check the directory band bitmap.
+
+Arguments:
+
+ StartLbn -- supplies the first LBN of the range
+ SectorCount -- supplies the number of LBN's in the range.
+
+Return Value:
+
+ TRUE if all the sectors in the range are in range and in use in
+ the main bitmap.
+
+--*/
+{
+ LBN Lbn, FollowingLbn;
+
+ FollowingLbn = StartLbn + SectorCount;
+
+ for( Lbn = StartLbn; Lbn < FollowingLbn; Lbn++ ) {
+
+ if( Lbn >= _MainBitmap->QuerySize() ||
+ _MainBitmap->IsFree( Lbn ) ) {
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+VOID
+HPFS_BITMAP::DumpInUse(
+)
+/*++
+
+Method Description:
+
+ List all the sectors marked in use in a simple format.
+
+Arguments:
+
+Return Value:
+ VOID
+--*/
+{
+ // unreferenced parameters
+ (void)(this);
+
+// REGISTER LBN Lbn;
+// REGISTER ULONG RunLen;
+//
+// for (Lbn = 0; Lbn < _MainBitmap->QuerySize(); ++Lbn) {
+//
+// // if allocated sector found
+// if (!_MainBitmap->IsFree(Lbn)) {
+//
+// printf("Run starting at LBN %lxH,", Lbn);
+// // count the run length
+// for (RunLen = 0;
+// Lbn < _MainBitmap->QuerySize() && !_MainBitmap->IsFree(Lbn);
+// ++RunLen, ++Lbn)
+// ;
+// printf(" its length is %lxH\n", RunLen);
+// }
+// }
+
+}
+
+
+
+BOOLEAN
+HPFS_BITMAP::QueryNextOrphan (
+ IN PBITMAPINDIRECT BitmapIndirectBlock,
+ OUT PLBN NextOrphan,
+ IN OUT PBOOLEAN AllocationErrors
+ )
+/*++
+
+Routine Description:
+
+ This method returns the next potential orphan sector. A sector is a
+ potential orphan if it is marked as in-use in the on-disk bitmap but
+ as free in the in-memory bitmap.
+
+Arguments:
+
+ BitmapIndirectBlock -- supplies the volume's bitmap indirect block
+ NextOrphan -- receives the next potential orphan identified
+ AllocationErrors -- receives TRUE if an allocation error (ie.
+ a sector marked as in-use by in-memory bitmap
+ but free on disk) is detected.
+
+
+Return Value:
+
+ TRUE if successful--
+ *NextOrphan is set to the next potential orphan LBN, or zero
+ if there are no more
+
+ FALSE if error
+
+Notes:
+
+ The directory band bitmap is queried for orphans first, then
+ the regular bitmap.
+
+--*/
+{
+ if( !_QueriedOrphanDirblks ) {
+
+ if( _DirBitmap->QueryNextOrphan( NextOrphan, AllocationErrors ) ) {
+
+ if( *NextOrphan == 0 ) {
+
+ // There are no more potential orphan dirblks;
+ // remember that fact, and fall out to where
+ // we check the main bitmap.
+
+ _QueriedOrphanDirblks = TRUE;
+
+ } else {
+
+ // We successfully located a potential orphan dirblk.
+ // *NextOrphan is set already.
+
+ return TRUE;
+ }
+
+ } else {
+
+ return FALSE;
+ }
+ }
+
+ return ( _MainBitmap->
+ QueryNextOrphan( BitmapIndirectBlock,
+ NextOrphan,
+ AllocationErrors ) );
+}
+
+
+
+
+VOID
+HPFS_BITMAP::SetHotfixList(
+ PHOTFIXLIST HotfixList
+ )
+/*++
+
+Routine Description:
+
+ This method sets the object's Hotfix List. This allows clients to
+ initialize the object without a hotfix list, and then add the hotfix
+ list information when it becomes available. (This functionality
+ is particularly useful for format.)
+
+Arguments:
+
+ HotfixList -- supplies the volume hotfix list.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _MainBitmap->SetHotfixList( HotfixList );
+
+ _DirBitmap->SetHotfixList( HotfixList );
+}
+
+
+
+BOOLEAN
+HPFS_BITMAP::Read(
+ IN PBITMAPINDIRECT BitmapIndirectBlock
+ )
+/*++
+
+Routine Description:
+
+ This method reads the main bitmap and the directory band bitmap.
+
+Arguments:
+
+ BitmapIndirectBlock -- supplies the bitmap indirect block for the volume.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ return( _DirBitmap->Read() &&
+ _MainBitmap->Read( BitmapIndirectBlock ) );
+}
+
+
+
+BOOLEAN
+HPFS_BITMAP::Write(
+ IN OUT PBITMAPINDIRECT BitmapIndirectBlock
+ )
+/*++
+
+Routine Description:
+
+ This method writes the main bitmap and the directory band bitmap.
+
+Arguments:
+
+ BitmapIndirectBlock -- supplies the bitmap indirect block for the volume
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ The bitmap indirect block specifies where on the disk the bitmap
+ should be written. However, a zero entry in the bitmap indirect
+ block indicates that that portion of the bitmap must be relocated.
+ If this is the case (or if a write fails), this method will allocate
+ a new block for the affected portion of the bitmap, and update the
+ bitmap indirect block.
+
+ Note that this recovery strategy is only pursued once; if the newly-
+ allocated block is also unwriteable, the write fails.
+
+--*/
+{
+
+ return( _DirBitmap->Write() &&
+ _MainBitmap->Write( BitmapIndirectBlock ) );
+}
+
+
+
+BOOLEAN
+HPFS_BITMAP::AndWithDisk(
+ PBITMAPINDIRECT BitmapIndirectBlock
+ )
+/*++
+
+Routine Description:
+
+ AND the in-memory bitmap with the on-disk bitmap
+
+Arguments:
+
+ BitmapIndirectBlock -- supplies the volume's bitmap indirect block
+
+Return Value:
+
+ TRUE on successful completion
+
+--*/
+{
+
+ return( _DirBitmap->AndWithDisk() &&
+ _MainBitmap->AndWithDisk(BitmapIndirectBlock) );
+}
+
+
+CONST ULONG MaximumReservedDirblks = 32;
+
+BOOLEAN
+HPFS_BITMAP::CheckAvailableDirblks(
+ IN ULONG RequestedNumber
+ )
+/*++
+
+Routine Description:
+
+ This method checks to see that a certain number of dirblk-sized
+ chunks are available in the bitmap.
+
+Arguments:
+
+ RequestedNumber -- supplies the number of dirblks that the client
+ wants to be sure are available.
+
+Return Value:
+
+ TRUE if at least RequestedNumber dirblks could be allocated from
+ the bitmap.
+
+Notes:
+
+ This method leaves the bitmap in the same shape it found it, but
+ allocates and frees sectors in passing.
+
+ This method is a rare operation.
+
+--*/
+{
+ ULONG AvailableInDirblkBand, i, j;
+ LBN TemporaryAllocation[MaximumReservedDirblks];
+
+
+ DebugPtrAssert( _MainBitmap );
+ DebugPtrAssert( _DirBitmap );
+
+
+ // First, see how much is available in the dirblk band:
+
+ AvailableInDirblkBand = _DirBitmap->QueryFreeDirblks();
+
+ if( AvailableInDirblkBand >= RequestedNumber ) {
+
+ return TRUE;
+ }
+
+ RequestedNumber -= AvailableInDirblkBand;
+
+ if( RequestedNumber > MaximumReservedDirblks ) {
+
+ return FALSE;
+ }
+
+
+ // We need to check the remainder in the main bitmap. We'll do
+ // this through the simple expedient of allocating as many as
+ // we need, and then freeing them again.
+
+ for( i = 0; i < RequestedNumber; i++ ) {
+
+ if( (TemporaryAllocation[i] =
+ _MainBitmap->MiddleLBN( SectorsPerDirblk,
+ SectorsPerDirblk )) == 0 ) {
+
+ // Ran out of space--free up what we've allocated so
+ // far and return failure.
+
+ for( j = 0; j < i; j++ ) {
+
+ _MainBitmap->SetFree( TemporaryAllocation[j],
+ SectorsPerDirblk );
+ }
+
+ return FALSE;
+ }
+ }
+
+
+ // We were able to allocate the requested number of DIRBLKs;
+ // free them up again, and then return success.
+
+ for( i = 0; i < RequestedNumber; i++ ) {
+
+ _MainBitmap->SetFree( TemporaryAllocation[i], SectorsPerDirblk );
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/uhpfs/src/bmind.cxx b/private/utils/uhpfs/src/bmind.cxx
new file mode 100644
index 000000000..e20a34f98
--- /dev/null
+++ b/private/utils/uhpfs/src/bmind.cxx
@@ -0,0 +1,412 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ bmind.cxx
+
+Abstract:
+
+ This module contains member function definitions for BITMAPINDIRECT,
+ which models the bitmap indirect block of an HPFS volume.
+
+ The bitmap indirect block is an array of LBNs which indicates where
+ the bitmap blocks are located on disk. Its size depends on the size
+ of the volume, since it must be big enough to hold all the bitmap-block
+ LBNs. Its allocation is contiguous, and consists of a whole number
+ of blocks (ie. a multiple of four sectors).
+
+ If, during Chkdsk, an entry in the indirect block is found to be
+ invalid, that entry is set to zero, to indicate that that portion of
+ the bitmap must be relocated. The Bitmap itself will allocate
+ a new block for that portion of the bitmap when it is written.
+
+Author:
+
+ Bill McJohn (billmc) 01-Dec-1990
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "bitmap.hxx"
+#include "bmind.hxx"
+#include "error.hxx"
+#include "hpfssa.hxx"
+
+
+
+DEFINE_CONSTRUCTOR( BITMAPINDIRECT, SECRUN );
+
+BITMAPINDIRECT::~BITMAPINDIRECT(
+ )
+{
+ Destroy();
+}
+
+
+VOID
+BITMAPINDIRECT::Construct (
+ )
+/*++
+
+Routine Description:
+
+ This method is the helper routine for object construction. It sets
+ all of the private data to safe values.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _NumberOfBitmaps = 0;
+ _SectorsInBlock = 0;
+ _pbid = NULL;
+}
+
+
+VOID
+BITMAPINDIRECT::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This method cleans up the object in preparation for destruction
+ or reinitialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _NumberOfBitmaps = 0;
+ _SectorsInBlock = 0;
+ _pbid = NULL;
+}
+
+
+
+BOOLEAN
+BITMAPINDIRECT::Initialize(
+ PLOG_IO_DP_DRIVE Drive,
+ LBN IndirectBlockLbn
+ )
+/*++
+
+Routine Description:
+
+ This method initializes the object.
+
+Arguments:
+
+ Drive -- supplies the drive on which the bitmap
+ indirect block resides
+ IndirectBlockLbn -- supplies the LBN of the first sector of the
+ indirect block
+
+Return Value:
+
+ TRUE on successful completion.
+
+--*/
+{
+ ULONG SectorSize;
+
+ Destroy();
+
+ if( Drive == NULL ||
+ IndirectBlockLbn == 0 ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+
+ // Compute the number of bitmaps on the disk:
+ _NumberOfBitmaps = (Drive->QuerySectors().GetLowPart() +
+ 8*BITMAP_SIZE - 1)/(8*BITMAP_SIZE);
+
+ // Compute the size of the bitmap indirect block. It has one LBN
+ // for each bitmap, and is rounded up to a multiple of 4 sectors.
+
+ SectorSize = Drive->QuerySectorSize();
+
+ _SectorsInBlock = ( _NumberOfBitmaps * sizeof(LBN) + SectorSize - 1)/
+ SectorSize;
+
+ _SectorsInBlock = ( _SectorsInBlock + 3 ) & (~3);
+
+
+ if( !_Mem.Initialize() ||
+ !SECRUN::Initialize( &_Mem, Drive, IndirectBlockLbn, _SectorsInBlock ) ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ _pbid = (BITMAPINDIRECTD*) GetBuf();
+ return TRUE;
+}
+
+
+
+BOOLEAN
+BITMAPINDIRECT::Create(
+ PCLOG_IO_DP_DRIVE pliodpdrv,
+ PHPFS_BITMAP pbm)
+/*++
+
+Routine Description:
+
+ This method creates (ie. formats) a Bitmap Indirect Block.
+
+Arguments:
+
+ pliodpdrv -- supplies the drive on which the bitmap indirect
+ block resides.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ ULONG cbSectorSize; // number of bytes in one sector.
+ LBN lbnBMLoc; // where to put bitmap.
+ SECTORCOUNT scBandSize; // number of sectors in a Band.
+ SECTORCOUNT scBMSize; // number of sectors in a Bit Map.
+ ULONG i; // index into the Bit Map indirect.
+
+ // Check to make sure that pliodpdrv, _pbid, pbm are not null.
+ if (!pliodpdrv || !(cbSectorSize = pliodpdrv->QuerySectorSize()) ||
+ !pbm)
+ {
+ perrstk->push(ERR_BMIND_PARAMETER, QueryClassId());
+ return FALSE;
+ }
+
+ // Check to make sure that _pbid is not null
+ if (!_pbid)
+ {
+ perrstk->push(ERR_BMIND_INITIALIZATION, QueryClassId());
+ return FALSE;
+ }
+
+ // Zero fill bit map indirect.
+ memset( _pbid, '\0', (size_t)(cbSectorSize * _SectorsInBlock) );
+
+ // Set the number of sectors in a band. 8 bits per Byte.
+ scBandSize = 8*BITMAP_SIZE;
+
+ // Set the number of sectors for a bitmap.
+ scBMSize = BITMAP_SIZE/cbSectorSize;
+
+ // If disk is small.
+ if (_NumberOfBitmaps == 1)
+ {
+ // Allocate the bit map near the beginning of the disk.
+ _pbid->lbn[0] = pbm->NearLBN(20, scBMSize, scBMSize);
+ return _pbid->lbn[0] ? TRUE : FALSE;
+ }
+
+ // Find space on the disk for the bitmaps and initialize the bitmap
+ // indirection table.
+
+ for (i = 0; i < _NumberOfBitmaps; i++) {
+
+ // Go to beginning of the bitmap's band.
+ lbnBMLoc = i*scBandSize;
+
+ // If i is even.
+ if (i%2 == 0) {
+
+ // Shift to the end of the band.
+ lbnBMLoc += scBandSize - scBMSize;
+ }
+
+ // Allocate space on the disk for the band as near to lbnBMLoc
+ // as possible.
+ _pbid->lbn[i] = pbm->NearLBN(lbnBMLoc, scBMSize, scBMSize, i%2 == 0);
+ if (!_pbid->lbn[i])
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+VOID
+BITMAPINDIRECT::Print(
+) CONST
+{
+ // unreferenced parameters
+ (void)(this);
+
+// REGISTER ULONG i;
+//
+// printf("** Bmind **\n");
+//
+// for (i = 0; i < QueryCount(); ++i) {
+// printf("Bitmap %lu starts at LBN %lxH\n", i, QueryLbn(i));
+// }
+
+}
+
+
+VERIFY_RETURN_CODE
+BITMAPINDIRECT::VerifyAndFix (
+ PHPFS_SA SuperArea,
+ IN BOOLEAN UpdateAllowed
+)
+/*++
+
+Method Description:
+
+ Verify and the hot fix list by seeing if can be read and written.
+
+ WARNING: this methods does a read without looking at any read flags
+ which means any in memory data that is not written to the volume
+ will be destroyed. This is done because VerifyAndFix refers to
+ the target volume only.
+
+Arguments:
+
+ SuperArea -- supplies the super area of the volume on which
+ the indirect block resides.
+ UpdateAllowed -- supplies a flag which, if TRUE, indicates that
+ corrections should be written to disk.
+
+Return Value:
+
+ VERIFY_STRUCTURE_INVALID if the bitmap indirect block is
+ corrupt beyond recovery, otherwise VERIFY_STRUCTURE_OK.
+
+Notes:
+
+ If an entry in the indirect block is invalid, that entry is set
+ to zero. This indicates that that portion of the bitmap must
+ be relocated, which is done by HPFS_BITMAP::Write.
+
+--*/
+{
+ HPFS_BITMAP* Bitmap;
+ ULONG i;
+
+ (void) UpdateAllowed;
+
+ Bitmap = SuperArea->GetBitmap();
+
+ if( !Bitmap->IsFree( QueryStartLbn(), _SectorsInBlock ) ||
+ !Read() ) {
+
+ return VERIFY_STRUCTURE_INVALID;
+ }
+
+ Bitmap->SetAllocated( QueryStartLbn(), _SectorsInBlock );
+
+ // Check each bitmap to see if it's in range and free.
+ // If not, set that LBN to zero, for later re-allocation.
+
+ for( i = 0; i < _NumberOfBitmaps; i++ ) {
+
+ if( !Bitmap->IsFree( QueryLbn(i), SectorsPerBitmap ) ) {
+
+ SetLbn(i, 0);
+
+ } else {
+
+ Bitmap->SetAllocated( QueryLbn(i), SectorsPerBitmap );
+ }
+ }
+
+ return VERIFY_STRUCTURE_OK;
+}
+
+
+BOOLEAN
+BITMAPINDIRECT::TakeCensus(
+ IN PHPFS_BITMAP VolumeBitmap,
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap
+ )
+/*++
+
+Routine Description:
+
+ This method notes the bitmap indirect block's information in the
+ volume census. It checks to make sure that the bitmap indirect
+ block and the bitmap blocks are all marked as used in the volume
+ bitmap, and it marks them as used in the Hpfs-only bitmap.
+
+Arguments:
+
+ VolumeBitmap -- Supplies the volume bitmap.
+ HpfsOnlyBitmap -- Supplies the bitmap of hpfs-only structures.
+
+Return value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This method reads the bitmap indirect block, so any changes that
+ have been made to it will be lost.
+
+--*/
+{
+ ULONG i;
+
+ DebugPtrAssert( VolumeBitmap );
+ DebugPtrAssert( HpfsOnlyBitmap );
+
+
+ // First check the indirect block itself--it must be marked as in
+ // use in the volume bitmap. Then read it and mark it in the
+ // hpfs-only bitmap.
+
+ if( !VolumeBitmap->CheckUsed( QueryStartLbn(), _SectorsInBlock ) ||
+ !Read() ) {
+
+ DebugPrint( "Volume is corrupt--bitmap error." );
+ return FALSE;
+ }
+
+ HpfsOnlyBitmap->SetAllocated( QueryStartLbn(), _SectorsInBlock );
+
+ // Now spin through the bitmap blocks in the indirect list, checking
+ // that each one is marked as in use in the volume bitmap, and marking
+ // it in the hpfs-only bitmap.
+
+ for( i = 0; i < _NumberOfBitmaps; i++ ) {
+
+ if( !VolumeBitmap->CheckUsed( QueryLbn(i), SectorsPerBitmap ) ) {
+
+ DebugPrint( "Volume is corrupt--bitmap error." );
+ return FALSE;
+ }
+
+ HpfsOnlyBitmap->SetAllocated( QueryLbn(i), SectorsPerBitmap );
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/uhpfs/src/cpinfo.cxx b/private/utils/uhpfs/src/cpinfo.cxx
new file mode 100644
index 000000000..b56e627e3
--- /dev/null
+++ b/private/utils/uhpfs/src/cpinfo.cxx
@@ -0,0 +1,1937 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "bitmap.hxx"
+#include "cpinfo.hxx"
+#include "hotfix.hxx"
+#include "error.hxx"
+
+
+DEFINE_CONSTRUCTOR( UHPFS_CODEPAGE, OBJECT );
+
+VOID
+UHPFS_CODEPAGE::Construct (
+ )
+
+{
+
+ USHORT i;
+
+ _Casemap = NULL;
+
+ for ( i = 0; i < MaximumCodepagesOnVol; i++ ) {
+
+ IsEntryValid[i] = FALSE;
+ CountryCodes[i] = 0;
+ CodepageIDs[i] = 0;
+ }
+
+ mNumberOfCodepages = 0;
+ mNumberOfValidCodepages = 0;
+ _Casemap = NULL;
+}
+
+
+BOOLEAN
+UHPFS_CODEPAGE::Initialize(
+ )
+{
+ Destroy();
+ return TRUE;
+}
+
+
+BOOLEAN
+UHPFS_CODEPAGE::Create(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN LBN FirstInfoSectorLbn,
+ IN LBN DataSectorLbn
+ )
+/*++
+
+Routine Description:
+
+ This routine writes a valid code page to the disk.
+
+Arguments:
+
+ Drive - Supplies the drive.
+ FirstInfoSectorLbn - Supplies the first info sector lbn.
+ DataSectorLbn - Supplies the data sector lbn.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ CODEPAGE_INFO cpinfo;
+ CPDATA cpdata;
+ CHECKSUM chk;
+
+ // unreferenced parameters
+ (void)( this );
+
+ if (!cpinfo.Initialize(Drive, FirstInfoSectorLbn)) {
+ return FALSE;
+ }
+
+ if (!cpdata.Initialize(Drive)) {
+ return FALSE;
+ }
+
+ cpdata.Relocate(DataSectorLbn);
+
+ if (!cpdata.Create(&chk) || !cpinfo.Create(DataSectorLbn, chk)) {
+ return FALSE;
+ }
+
+ if (!cpinfo.Write() || !cpdata.Write()) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+VOID
+UHPFS_CODEPAGE::Destroy(
+ )
+{
+ USHORT i;
+
+ for ( i = 0; i < MaximumCodepagesOnVol; i++ ) {
+
+ IsEntryValid[i] = FALSE;
+ CountryCodes[i] = 0;
+ CodepageIDs[i] = 0;
+ }
+
+ mNumberOfCodepages = 0;
+ mNumberOfValidCodepages = 0;
+
+ DELETE( _Casemap );
+ _Casemap = NULL;
+
+}
+
+
+UHPFS_CODEPAGE::~UHPFS_CODEPAGE(
+ )
+{
+}
+
+
+
+VERIFY_RETURN_CODE
+UHPFS_CODEPAGE::VerifyAndFix (
+ IN PLOG_IO_DP_DRIVE LogicalDrive,
+ IN PHOTFIXLIST HotfixList,
+ IN PHPFS_BITMAP Bitmap,
+ IN LBN FirstInfoSectorLbn,
+ IN BOOLEAN UpdateAllowed,
+ OUT PBOOLEAN ErrorsDetected
+ )
+/*++
+
+Routine Description:
+
+ This method verifies and fixes the volume codepage structures.
+
+Arguments:
+
+ LogicalDrive -- supplies the drive on which the structures reside
+ HotfixList -- supplies the hotfix list for the volume
+ Bitmap -- supplies the volume bitmap
+ FirstInfoSectorLbn -- supplies the LBN of the first Code Page
+ Information Sector on the volume
+ UpdateAllowed -- supplies a flag indicating whether corrections
+ should be written to disk
+ ErrorsDetected -- receives TRUE if corruption is found in
+ the codepage structures.
+
+Return Value:
+
+ a VERIFY_RETURN_CODE indicating the disposition of the structures.
+
+--*/
+{
+
+ CODEPAGE_INFO CurrentInfoEntry;
+ CPDATA CurrentDataEntry;
+ USHORT CurrentIndex;
+
+ if( (_Casemap = NEW CASEMAP) == NULL ||
+ !_Casemap->Initialize() ) {
+
+ return VERIFY_INSUFFICIENT_RESOURCES;
+ }
+
+ if( !CurrentInfoEntry.Initialize( LogicalDrive, FirstInfoSectorLbn ) ||
+ !CurrentDataEntry.Initialize( LogicalDrive ) ) {
+
+ // Unable to initialize--insufficient resources.
+ return VERIFY_INSUFFICIENT_RESOURCES;
+ }
+
+ CurrentIndex = 0;
+
+ while ( CurrentInfoEntry.NextEntryToCheck( LogicalDrive,
+ HotfixList,
+ Bitmap,
+ CurrentIndex,
+ UpdateAllowed,
+ ErrorsDetected ) ) {
+
+
+ CurrentInfoEntry.VerifyAndFix ( HotfixList,
+ CurrentIndex,
+ ErrorsDetected );
+
+ if( !CurrentDataEntry.
+ NextEntryToCheck( LogicalDrive,
+ CurrentInfoEntry.QueryDataLbn(),
+ Bitmap,
+ UpdateAllowed,
+ ErrorsDetected ) ) {
+
+ *ErrorsDetected = TRUE;
+ CurrentInfoEntry.MarkEntryBad();
+
+ } else {
+
+ if( CurrentDataEntry.VerifyAndFix ( LogicalDrive,
+ &CurrentInfoEntry,
+ UpdateAllowed,
+ ErrorsDetected ) ) {
+
+ // The entry is good; add it to the
+ // CaseMap table
+ mNumberOfValidCodepages += 1;
+
+ _Casemap->AddCodepage( CurrentIndex,
+ CurrentDataEntry.GetEntry() );
+
+ IsEntryValid[CurrentIndex] = TRUE;
+ CountryCodes[CurrentIndex] = CurrentInfoEntry.QueryCountry();
+ CodepageIDs[CurrentIndex] = CurrentInfoEntry.QueryCPID();
+
+ } else {
+
+ *ErrorsDetected = TRUE;
+ CurrentInfoEntry.MarkEntryBad();
+ }
+ }
+
+ CurrentIndex += 1;
+ }
+
+ mNumberOfCodepages = CurrentIndex;
+
+ return VERIFY_STRUCTURE_OK;
+}
+
+
+BOOLEAN
+UHPFS_CODEPAGE::Read (
+ IN PLOG_IO_DP_DRIVE LogicalDrive,
+ IN LBN FirstInfoSectorLbn
+ )
+/*++
+--*/
+{
+ CODEPAGE_INFO CurrentInfoEntry;
+ CPDATA CurrentDataEntry;
+ USHORT CurrentIndex;
+
+ if( (_Casemap = NEW CASEMAP) == NULL ||
+ !_Casemap->Initialize() ) {
+
+ return FALSE;
+ }
+
+ if( !CurrentInfoEntry.Initialize( LogicalDrive, FirstInfoSectorLbn ) ||
+ !CurrentDataEntry.Initialize( LogicalDrive ) ) {
+
+ // Unable to initialize--insufficient resources.
+ return FALSE;
+ }
+
+ CurrentIndex = 0;
+
+ while ( CurrentInfoEntry.ReadNextEntry( ) ) {
+
+ if( !CurrentDataEntry.
+ ReadNextEntry( CurrentInfoEntry.QueryDataLbn() ) ) {
+
+ return FALSE;
+
+ } else {
+
+ // Add this entry to the Casemap table
+ mNumberOfValidCodepages += 1;
+
+ _Casemap->AddCodepage( CurrentIndex,
+ CurrentDataEntry.GetEntry() );
+
+ IsEntryValid[CurrentIndex] = TRUE;
+ CountryCodes[CurrentIndex] = CurrentInfoEntry.QueryCountry();
+ CodepageIDs[CurrentIndex] = CurrentInfoEntry.QueryCPID();
+ }
+
+ CurrentIndex += 1;
+ }
+
+ mNumberOfCodepages = CurrentIndex;
+
+ return TRUE;
+}
+
+BOOLEAN
+UHPFS_CODEPAGE::TakeCensus(
+ IN PLOG_IO_DP_DRIVE LogicalDrive,
+ IN LBN FirstInfoSectorLbn,
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap
+ )
+/*++
+
+Routine Description:
+
+ This method marks the sectors owned by the codepage structures as
+ used in the bitmap of hpfs-only structures.
+
+Arguments:
+
+ LogicalDrive -- Supplies the drive.
+ FirstInfoSectorLbn -- Supplies the lbn of the first Codepage
+ Information Sector.
+ HpfsOnlyBitmap -- Supplies the bitmap of HPFS-only structures.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ CODEPAGE_INFO CurrentInfoEntry;
+ LBN CurrentInfoLbn, CurrentDataLbn;
+
+
+ if( !CurrentInfoEntry.Initialize( LogicalDrive, FirstInfoSectorLbn ) ) {
+
+ // Unable to initialize.
+ return FALSE;
+ }
+
+
+ while ( CurrentInfoEntry.ReadNextEntry( ) ) {
+
+ CurrentInfoLbn = CurrentInfoEntry.QueryCurrentLbn();
+ CurrentDataLbn = CurrentInfoEntry.QueryDataLbn();
+
+ if( CurrentInfoLbn != 0 ) {
+
+ HpfsOnlyBitmap->SetAllocated( CurrentInfoLbn, 1 );
+ }
+
+ if( CurrentDataLbn != 0 ) {
+
+ HpfsOnlyBitmap->SetAllocated( CurrentDataLbn, 1 );
+ }
+ }
+
+ return TRUE;
+}
+
+UHPFS_EXPORT
+PCASEMAP
+UHPFS_CODEPAGE::GetCasemap(
+ )
+{
+ return _Casemap;
+}
+
+
+USHORT
+UHPFS_CODEPAGE::QueryNumberOfCodepages (
+ )
+/*++
+
+Routine Description:
+
+ Query the number of codepages on the volume.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Number of codepages found on the volume.
+
+Notes:
+
+ This method assumes that the codepages have been read (by
+ Read or by VerifyAndFix).
+
+--*/
+{
+ return mNumberOfCodepages;
+}
+
+
+VOID
+UHPFS_CODEPAGE::Print(
+ )
+{
+ // unreferenced parameters
+ (void)( this );
+
+// USHORT i;
+//
+//
+// printf( "%d Codepages on Volume (%d valid):\n",
+// mNumberOfCodepages, mNumberOfValidCodepages );
+//
+// for ( i = 0; i < mNumberOfCodepages; i++ ) {
+//
+// printf( " Country: %3d; ID %3d\n",
+// CountryCodes[i], CodepageIDs[i] );
+// }
+//
+}
+
+
+DEFINE_CONSTRUCTOR( CODEPAGE_INFO, SECRUN );
+
+VOID
+CODEPAGE_INFO::Construct (
+ )
+{
+ mIsInitialized = FALSE;
+ mIsModified = FALSE;
+ mSectorIsValid = FALSE;
+ mFirstEntry = FALSE;
+ mCurrentLbn = 0;
+ mCurrentIndexInSector = 0;
+}
+
+
+
+BOOLEAN
+CODEPAGE_INFO::Initialize(
+ IN PLOG_IO_DP_DRIVE pliodpdrv,
+ IN LBN lbn
+ )
+/*++
+
+Description of Routine:
+
+ Initializes the Current Code Page Info Entry object
+
+Arguments:
+
+ pliodpdrv -- drive on which the codepages reside
+ lbn -- lbn of the first Codepage Information Sector
+
+--*/
+{
+ if (!_hmem.Initialize() ||
+ !SECRUN::Initialize(&_hmem, pliodpdrv, lbn, SectorsPerCPInfoSector)) {
+ return FALSE;
+ }
+
+ pcpinfosecd = (PCPINFOSECTORD) GetBuf();
+
+ mIsInitialized = (BOOLEAN)( pcpinfosecd != NULL );
+
+ mCurrentLbn = lbn;
+ mFirstEntry = TRUE;
+ return (mIsInitialized);
+}
+
+BOOLEAN
+CODEPAGE_INFO::Create(
+ IN LBN DataSectorLbn,
+ IN ULONG CheckSum
+ )
+/*++
+
+Routine Description:
+
+ This routine creates a new code page info sector which points the
+ the supplied data sector.
+
+Arguments:
+
+ DataSectorLbn - Supplies the data sector lbn.
+ CheckSum - Supplies the check sum of the code page data.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ memset(_hmem.GetBuf(), 0, (UINT) _hmem.QuerySize());
+
+ pcpinfosecd->sig = CPInfoSignature;
+ pcpinfosecd->cCodePage = 1;
+ pcpinfosecd->iFirstCP = 0;
+ pcpinfosecd->lbnNext = 0;
+ pcpinfosecd->cpinfoent[0].CountryCode = 1;
+ pcpinfosecd->cpinfoent[0].CodePageID = 850;
+ pcpinfosecd->cpinfoent[0].cksCP = CheckSum;
+ pcpinfosecd->cpinfoent[0].lbnCPData = DataSectorLbn;
+ pcpinfosecd->cpinfoent[0].iCmphpfs = 0;
+ pcpinfosecd->cpinfoent[0].cDBCSrange = 0;
+
+ return TRUE;
+}
+
+
+VOID
+CODEPAGE_INFO::Print( ) CONST
+{
+ // unreferenced parameters
+ (void)( this );
+
+// printf("\n");
+// printf("Codepage Information Sector as LBN 0x%lx\n", mCurrentLbn );
+// printf("\n");
+// printf(" Signature: 0x%l8x\n", pcpinfosecd->sig );
+// printf(" Number of Entries: 0x%8x\n", pcpinfosecd->cCodePage );
+// printf(" Index of First Entry: 0x%8x\n", pcpinfosecd->iFirstCP );
+// printf(" LBN of next InfoSec: 0x%8lx\n", pcpinfosecd->lbnNext );
+// printf( "\n" );
+}
+
+
+BOOLEAN
+CODEPAGE_INFO::NextEntryToCheck (
+ IN PLOG_IO_DP_DRIVE pliodpdrv,
+ IN PHOTFIXLIST HotfixList,
+ IN PHPFS_BITMAP Bitmap,
+ IN USHORT ExpectedIndex,
+ IN BOOLEAN UpdateAllowed,
+ OUT PBOOLEAN ErrorsDetected
+ )
+/*++
+
+Routine Description:
+
+ Chkdsk's method for traversing the codepage information entry
+ list. Makes next entry the current entry (read codepage info
+ sectors and checking their headers as it goes).
+
+
+Arguments:
+
+ pliodpdrv -- supplies the drive on which these entries reside
+ HotfixList -- supplies the volume hotfix list
+ Bitmap -- supplies the volume bitmap
+ ExpectedIndex -- supplies the expected index on volume of next entry
+ UpdateAllowed -- supplies a flag indicating whether corrections
+ should be written to disk
+ ErrorsDetected -- receives TRUE if errors are found and fixed
+
+Return Value:
+
+ TRUE if valid entry found
+ FALSE if no valid entry found
+
+--*/
+{
+
+ LBN NewLbn, TempLbn, PreviousLbn;;
+
+ if ( !mIsInitialized ||
+ (!mSectorIsValid && !mFirstEntry) ) {
+
+ return FALSE;
+ }
+
+ if ( mIsInitialized && mFirstEntry ) {
+
+ // We are getting the first codepage information entry.
+ // mCurrentLbn has been set (by Init) to the LBN of the
+ // first codepage info sector; check that it isn't crosslinked,
+ // read it, and make sure that it is indeed a codepage
+ // information sector. If any of these tests fail, the current
+ // sector is invalid.
+ mFirstEntry = FALSE;
+
+
+ mSectorIsValid = (BOOLEAN)
+ ( Bitmap->IsFree( mCurrentLbn,
+ SectorsPerCPInfoSector ) &&
+ Read ( ) &&
+ pcpinfosecd->sig == CPInfoSignature );
+
+ if ( mSectorIsValid ) {
+
+ // since it's valid, mark it as in use.
+
+ Bitmap->SetAllocated ( mCurrentLbn, SectorsPerCPInfoSector );
+
+ } else {
+
+ return FALSE;
+ }
+
+ } else if ( mCurrentIndexInSector < EntriesPerCPInfoSector ) {
+
+ // There are more entries available in the current
+ // information sector, so we just bump the index.
+
+ mCurrentIndexInSector += 1;
+
+ } else {
+
+ // We need to go on to the next information sector
+
+ if ( pcpinfosecd->lbnNext == 0 ) {
+
+ // There are no more info sectors.
+
+ Flush( pliodpdrv,
+ mCurrentIndexInSector,
+ UpdateAllowed,
+ ErrorsDetected );
+
+ return( FALSE );
+
+ } else if ( !Bitmap->IsFree( pcpinfosecd->lbnNext,
+ SectorsPerCPInfoSector ) ) {
+
+ // lbnNext is crosslinked, so we can't use it.
+
+ *ErrorsDetected = TRUE;
+
+ pcpinfosecd->lbnNext = 0;
+ Flush( pliodpdrv,
+ mCurrentIndexInSector,
+ UpdateAllowed,
+ ErrorsDetected );
+
+ return( FALSE );
+
+ } else {
+
+ Flush( pliodpdrv,
+ mCurrentIndexInSector,
+ UpdateAllowed,
+ ErrorsDetected );
+
+ mCurrentIndexInSector = 0;
+
+ PreviousLbn = mCurrentLbn;
+ mCurrentLbn = pcpinfosecd->lbnNext;
+ Relocate( mCurrentLbn );
+
+ // read mCurrentLbn
+
+ mSectorIsValid = (BOOLEAN)
+ ( Read ( ) &&
+ pcpinfosecd->sig == CPInfoSignature );
+
+ if ( !mSectorIsValid ) {
+
+ // This is not a valid codepage information sector.
+
+ if( UpdateAllowed ) {
+
+ // We've been instructed to write corrections to
+ // disk, so we need to back up and fix the lbnNext
+ // field of the previous sector. We'll read it,
+ // update it, and write it back out immediately.
+ // If we can't read it, then don't bother. (Note
+ // that we just read and wrote it.)
+
+ TempLbn = mCurrentLbn;
+ mCurrentLbn = PreviousLbn;
+ Relocate( mCurrentLbn );
+
+ if( Read() ) {
+
+ pcpinfosecd->lbnNext = 0;
+ Write();
+ }
+
+ mCurrentLbn = TempLbn;
+ Relocate( mCurrentLbn );
+ }
+
+ return ( FALSE );
+ }
+
+ // Check the fields in the info sector header:
+ // lbnNext and iFirstCP.
+
+ // If lbnNext is hotfixed, resolve that reference.
+
+ NewLbn = HotfixList->GetLbnTranslation(pcpinfosecd->lbnNext);
+
+ if ( pcpinfosecd->lbnNext != NewLbn ) {
+
+ *ErrorsDetected = TRUE;
+
+ pcpinfosecd->lbnNext = NewLbn;
+ mIsModified = TRUE;
+ }
+
+
+ if ( pcpinfosecd->iFirstCP != ExpectedIndex ) {
+
+ // The index-of-first-entry does not match
+ // our expectation, so we'll force it.
+
+ *ErrorsDetected = TRUE;
+
+ pcpinfosecd->iFirstCP = ExpectedIndex;
+ mIsModified = TRUE;
+ }
+
+ Bitmap->SetAllocated ( mCurrentLbn, SectorsPerCPInfoSector );
+ }
+ }
+
+ // mCurrentIndexInSector now refers to the next info entry
+ // to be checked. If both the country and codepage ID fields
+ // are zero, there are no more entries.
+
+ if ( pcpinfosecd->
+ cpinfoent[mCurrentIndexInSector].CountryCode == 0 &&
+ pcpinfosecd->
+ cpinfoent[mCurrentIndexInSector].CodePageID == 0 ) {
+
+ // No more entries
+ Flush( pliodpdrv,
+ mCurrentIndexInSector,
+ UpdateAllowed,
+ ErrorsDetected );
+
+ return FALSE;
+
+ } else {
+
+ return TRUE;
+ }
+
+}
+
+BOOLEAN
+CODEPAGE_INFO::ReadNextEntry (
+ )
+/*++
+
+Routine Description:
+
+ Fetches the next codepage information entry
+
+Arguments:
+
+ None
+
+Return Value:
+
+ TRUE upon successful completion
+
+Notes:
+
+ This function assumes that the volume is valid.
+
+--*/
+{
+
+ if ( !mIsInitialized ||
+ (!mSectorIsValid && !mFirstEntry) ) {
+
+ return FALSE;
+ }
+
+ if ( mIsInitialized && mFirstEntry ) {
+
+ // We are getting the first codepage information entry.
+ // mCurrentLbn has been set (by Init) to the LBN of the
+ // first codepage info sector; check that it isn't crosslinked,
+ // read it, and make sure that it is indeed a codepage
+ // information sector. If any of these tests fail, the current
+ // sector is invalid.
+
+ mFirstEntry = FALSE;
+
+ mSectorIsValid = Read ( );
+
+ if ( !mSectorIsValid ) {
+
+ return FALSE;
+ }
+
+ } else if ( mCurrentIndexInSector < EntriesPerCPInfoSector ) {
+
+ // There are more entries available in the current
+ // information sector, so we just bump the index.
+
+ mCurrentIndexInSector += 1;
+
+ } else {
+
+ // We need to go on to the next information sector
+
+ if ( pcpinfosecd->lbnNext == 0 ) {
+
+ // There are no more info sectors.
+
+ return( FALSE );
+
+ } else {
+
+ mCurrentIndexInSector = 0;
+
+ mCurrentLbn = pcpinfosecd->lbnNext;
+ Relocate( mCurrentLbn );
+
+ // read mCurrentLbn
+
+ mSectorIsValid = Read ( );
+
+ if ( !mSectorIsValid ) {
+
+ return ( FALSE );
+ }
+ }
+ }
+
+ // mCurrentIndexInSector now refers to the next info entry
+ // to be checked. If both the country and codepage ID fields
+ // are zero, there are no more entries.
+
+ if ( pcpinfosecd->
+ cpinfoent[mCurrentIndexInSector].CountryCode == 0 &&
+ pcpinfosecd->
+ cpinfoent[mCurrentIndexInSector].CodePageID == 0 ) {
+
+ // No more entries
+
+ return FALSE;
+
+ } else {
+
+ return TRUE;
+ }
+
+}
+
+
+VOID
+CODEPAGE_INFO::Flush (
+ IN LOG_IO_DP_DRIVE* pliodpdrv,
+ IN USHORT Entries,
+ IN BOOLEAN UpdateAllowed,
+ OUT PBOOLEAN ErrorsDetected
+)
+/*++
+
+Description of Routine:
+
+ Flushes the current info sector--if it is valid, check the number
+ of entries and write if the sector has been modified.
+
+Arguments:
+
+ pliodpdrv -- supplies the drive on which the sector resides
+ Entries -- Supplies the number of entries actually found int
+ the codepage information sector.
+ UpdateAllowed -- Supplies a flag indicating whether corrections
+ should be written to disk.
+ ErrorsDetected -- Receives TRUE if an error is detected.
+
+RETURNS
+
+ no return value
+
+--*/
+{
+ // unreferenced parameters
+ (void)( pliodpdrv );
+
+ if( !mSectorIsValid || !mIsInitialized ) {
+
+ // Sector is not valid, don't diddle with it.
+ return;
+ }
+
+ // Ensure that the number of entries in the sector header
+ // matches the number of entries found during traversal.
+
+ if ( pcpinfosecd->cCodePage != Entries ) {
+
+ *ErrorsDetected = TRUE;
+
+ pcpinfosecd->cCodePage = Entries;
+ mIsModified = TRUE;
+ }
+
+ // If the sector has been modified, and we have write
+ // permission, write the sector to disk.
+ //
+
+ if ( mIsModified && UpdateAllowed ) {
+
+ Write ( );
+ }
+
+ mIsModified = FALSE;
+
+ return;
+}
+
+VERIFY_RETURN_CODE
+CODEPAGE_INFO::VerifyAndFix (
+ IN PHOTFIXLIST HotfixList,
+ IN USHORT ExpectedIndex,
+ OUT PBOOLEAN ErrorsDetected
+)
+/*++
+
+Description of Routine:
+
+ Checks certain fields of the current info entry. Note that the bulk
+ of the work is done by CPDATA::VerifyAndFix (which is a friend
+ of CODEPAGE_INFO).
+
+Arguments:
+
+ HotfixList -- supplies the volume hotfix list.
+ ExpectedIndex -- supplies the expected index of the current entry.
+ ErrorsDetected -- receives TRUE if corruption is detected (and
+ possibly fixed)
+
+Returns:
+
+ a VERIFY_RETURN_CODE indicating the state of the information entry.
+
+--*/
+{
+ LBN NewLbn;
+ PCPINFOENTRY pcpinfoent;
+
+
+ if( !mSectorIsValid || !mIsInitialized ) {
+
+ return VERIFY_INSUFFICIENT_RESOURCES;
+ }
+
+ pcpinfoent = &(pcpinfosecd->cpinfoent[mCurrentIndexInSector]);
+
+ NewLbn = HotfixList->GetLbnTranslation(pcpinfoent->lbnCPData);
+
+ if ( NewLbn != pcpinfoent->lbnCPData ) {
+
+ *ErrorsDetected = TRUE;
+
+ pcpinfoent->lbnCPData = NewLbn;
+ mIsModified = TRUE;
+ }
+
+
+ if ( pcpinfoent->iCmphpfs != ExpectedIndex ) {
+
+ *ErrorsDetected = TRUE;
+
+ pcpinfoent->iCmphpfs = ExpectedIndex;
+ mIsModified = TRUE;
+ }
+
+ return VERIFY_STRUCTURE_OK;
+}
+
+VOID
+CODEPAGE_INFO::MarkEntryBad(
+ )
+/*++
+
+Description of Routine:
+
+ This sets the country and codepage ID fields of the current
+ information entry to special values to indicate an invalid entry
+
+ Note that if the entry is already marked invalid, this routine
+ does nothing.
+
+Arguments: None
+
+Return: None
+
+--*/
+{
+
+ PCPINFOENTRY pcpinfoent;
+
+ pcpinfoent = &(pcpinfosecd->cpinfoent[mCurrentIndexInSector]);
+
+ if ( mIsInitialized &&
+ mSectorIsValid &&
+ ( pcpinfoent->CountryCode != InvalidCountryCode ||
+ pcpinfoent->CodePageID != InvalidCodepageID ) ) {
+
+ pcpinfoent->CountryCode = InvalidCountryCode;
+ pcpinfoent->CodePageID = InvalidCodepageID;
+
+ mIsModified = TRUE;
+ }
+}
+
+LBN
+CODEPAGE_INFO::QueryDataLbn (
+ )
+/*++
+--*/
+{
+ if( mIsInitialized && mSectorIsValid ) {
+
+ return pcpinfosecd->cpinfoent[mCurrentIndexInSector].lbnCPData;
+
+ } else {
+
+ return (LBN)(0L);
+ }
+}
+
+
+USHORT
+CODEPAGE_INFO::QueryCountry(
+ ) {
+
+
+ if( mIsInitialized && mSectorIsValid ) {
+
+ return pcpinfosecd->cpinfoent[mCurrentIndexInSector].CountryCode;
+
+ } else {
+
+ return 0;
+ }
+}
+
+
+USHORT
+CODEPAGE_INFO::QueryCPID (
+ )
+{
+ if( mIsInitialized && mSectorIsValid ) {
+
+ return pcpinfosecd->cpinfoent[mCurrentIndexInSector].CodePageID;
+
+ } else {
+
+ return 0;
+ }
+
+}
+
+DEFINE_CONSTRUCTOR( CPDATA, SECRUN );
+
+VOID
+CPDATA::Construct (
+ )
+{
+ mIsInitialized = FALSE;
+ mValidEntry = FALSE;
+ mSectorIsValid = FALSE;
+}
+
+
+BOOLEAN
+CPDATA::Initialize(
+ IN PLOG_IO_DP_DRIVE pliodpdrv
+ )
+{
+ if (!_hmem.Initialize() ||
+ !SECRUN::Initialize(&_hmem, pliodpdrv, 0, SectorsPerCPDataSector)) {
+ return FALSE;
+ }
+
+ pcpdatasecd = (PCPDATASECTOR) GetBuf();
+
+ mIsInitialized = (BOOLEAN)(pcpdatasecd != NULL);
+
+ return mIsInitialized;
+}
+
+
+BOOLEAN
+CPDATA::Create(
+ OUT PCHECKSUM CheckSum
+ )
+/*++
+
+Routine Description:
+
+ This routine create a new code page data sector.
+
+Arguments:
+
+ CheckSum - Returns the check sum for the code page data.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ static UCHAR table850[] = {
+ 0x80, 0x9A, 0x45, 0x41, 0x8E, 0x41, 0x8F, 0x80,
+ 0x45, 0x45, 0x45, 0x49, 0x49, 0x49, 0x8E, 0x8F,
+ 0x90, 0x92, 0x92, 0x4F, 0x99, 0x4F, 0x55, 0x55,
+ 0x59, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
+ 0x41, 0x49, 0x4F, 0x55, 0xA5, 0xA5, 0xA6, 0xA7,
+ 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
+ 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
+ 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
+ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
+ 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
+ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7,
+ 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
+ 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
+ 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF
+ };
+
+ PCPDATAENTRY dataentry;
+ ULONG i;
+
+ memset(_hmem.GetBuf(), 0, (UINT) _hmem.QuerySize());
+
+ pcpdatasecd->sig = CPDataSignature;
+ pcpdatasecd->cCodePage = 1;
+ pcpdatasecd->iFirstCP = 0;
+ pcpdatasecd->cksCP[0] = 0;
+ pcpdatasecd->offCPData[0] =
+ (USHORT)((PCHAR) pcpdatasecd->pData - ((PCHAR) pcpdatasecd));
+
+ dataentry = (PCPDATAENTRY) pcpdatasecd->pData;
+
+ dataentry->CountryCode = 1;
+ dataentry->CodePageID = 850;
+ dataentry->cDBCSrange= 0;
+
+ for (i = 0; i < 128; i++) {
+ dataentry->bCaseMapTable[i] = table850[i];
+ }
+
+ dataentry->DBCS_RangeTable[0].CDIB_DBCS_start = 0;
+ dataentry->DBCS_RangeTable[0].CDIB_DBCS_end = 0;
+
+ // Since we just put the sector together, we know
+ // that it's valid.
+
+ mSectorIsValid = TRUE;
+
+ //
+ // Do a check sum into the return value.
+ //
+ mCurrentIndexInSector = 0;
+ pcpdatasecd->cksCP[0] = *CheckSum = ComputeChecksum();
+
+ return TRUE;
+}
+
+
+VOID
+CPDATA::Flush (
+ IN PLOG_IO_DP_DRIVE pliodpdrv,
+ IN USHORT Entries,
+ IN BOOLEAN UpdateAllowed,
+ OUT PBOOLEAN ErrorsDetected
+)
+/*++
+
+Description of Routine:
+
+ Flushes the current data sector--if it is valid, check the number
+ of entries and write if the sector has been modified.
+
+Arguments:
+
+ pliodpdrv -- drive on which the sector resides
+ Entries -- number of entries
+ UpdateAllowed -- true if we have write permission
+ ErrorsDetected -- receives TRUE if errors are detected
+
+RETURNS
+
+ no return value
+
+--*/
+{
+ // unreferenced parameters
+ (void)( pliodpdrv );
+
+ if( !mIsInitialized || !mSectorIsValid ) {
+
+ // Sector is not valid, don't diddle with it.
+ return;
+ }
+
+ // Ensure that the number of entries in the sector header
+ // matches the number of entries found during traversal.
+
+ if ( pcpdatasecd->cCodePage != Entries ) {
+
+ *ErrorsDetected = TRUE;
+
+ pcpdatasecd->cCodePage = Entries;
+ mIsModified = TRUE;
+ }
+
+ // If the sector has been modified, and we have write
+ // permission, write the sector to disk.
+
+ if ( mIsModified && UpdateAllowed ) {
+
+ Write ( );
+ }
+
+ mIsModified = FALSE;
+
+ return;
+}
+
+BOOLEAN
+CPDATA::NextEntryToCheck (
+ IN LOG_IO_DP_DRIVE* pliodpdrv,
+ IN LBN lbn,
+ IN PHPFS_BITMAP Bitmap,
+ IN BOOLEAN UpdateAllowed,
+ OUT PBOOLEAN ErrorsDetected
+ )
+/*++
+
+Description of Routine:
+
+ Makes the next data entry the current entry so Chkdsk can check it.
+
+Arguments:
+
+ pliodpdrv -- supplies drive on which the codepages reside
+ lbn -- supplies the lbn in which the data entry resides
+ Bitmap -- supplies the volume bitmap
+ UpdateAllowed -- TRUE if we should write corrections to disk
+ ErrorsDetected -- receives TRUE if errors are detected
+
+Returns:
+
+ TRUE if the next entry is found; FALSE if there are no more entries.
+
+--*/
+{
+
+ DebugAssert( mIsInitialized );
+
+ if ( mSectorIsValid && lbn == mCurrentLbn ) {
+
+ mCurrentIndexInSector += 1;
+
+ if( mCurrentIndexInSector >= EntriesPerCPDataSector ) {
+
+ // Data sector has overflowed--this is not OK
+
+ Flush ( pliodpdrv,
+ mCurrentIndexInSector,
+ UpdateAllowed,
+ ErrorsDetected );
+
+ return FALSE;
+
+ } else {
+
+ return TRUE;
+ }
+
+ } else {
+
+ Flush ( pliodpdrv,
+ mCurrentIndexInSector+1,
+ UpdateAllowed,
+ ErrorsDetected );
+
+ mCurrentLbn = lbn;
+ Relocate( mCurrentLbn );
+
+ mSectorIsValid = (BOOLEAN)
+ ( Bitmap->IsFree( mCurrentLbn,
+ SectorsPerCPDataSector ) &&
+ Read() &&
+ pcpdatasecd->sig == CPDataSignature );
+
+ if ( !mSectorIsValid ) {
+
+ // The sector is crosslinked or unreadable, or
+ // it's not a codepage data sector.
+
+ return( FALSE );
+ }
+
+
+ Bitmap->SetAllocated ( mCurrentLbn, SectorsPerCPDataSector );
+
+ mCurrentIndexInSector = 0;
+
+ return TRUE;
+ }
+}
+
+
+BOOLEAN
+CPDATA::ReadNextEntry (
+ IN LBN lbn
+ )
+/*++
+
+Description of Routine:
+
+ Makes the next data entry the current entry so we can
+ get its information
+
+Arguments:
+
+ lbn -- lbn in which the data entry resides
+
+Notes:
+
+
+--*/
+{
+
+ DebugAssert( mIsInitialized );
+
+
+ if ( mSectorIsValid && lbn == mCurrentLbn ) {
+
+ mCurrentIndexInSector += 1;
+
+ if( mCurrentIndexInSector >= EntriesPerCPDataSector ) {
+
+ // Data sector has overflowed--this is not OK
+
+ return FALSE;
+
+ } else {
+
+ return TRUE;
+ }
+
+ } else {
+
+ mCurrentLbn = lbn;
+ Relocate( mCurrentLbn );
+
+ mSectorIsValid = Read();
+
+ if ( !mSectorIsValid ) {
+
+ // can't read the sector
+ return( FALSE );
+ }
+
+
+ // Set ExpectedOffset?
+ mCurrentIndexInSector = 0;
+
+ return TRUE;
+ }
+}
+
+
+CHECKSUM
+CPDATA::ComputeChecksum (
+ )
+/*++
+
+Description of Routine:
+
+ Computes the checksum for the current data entry
+
+Returns:
+
+ Checksum
+
+--*/
+{
+
+ PBYTE pb;
+ PCPDATAENTRY pcpdata;
+ CHECKSUM cks;
+ ULONG cb;
+
+ DebugAssert( mIsInitialized );
+ DebugAssert( mSectorIsValid );
+
+ pcpdata = (PCPDATAENTRY)((PBYTE)pcpdatasecd +
+ pcpdatasecd->offCPData[mCurrentIndexInSector]);
+
+ pb = (PBYTE) pcpdata;
+
+ cb = sizeof (CPDATAENTRY) + pcpdata->cDBCSrange * sizeof(DBCS_Range);
+
+ cks = 0;
+
+ while( cb-- ) {
+
+ cks += (ULONG)(*pb++);
+ cks = (cks << CCS_ROT) + (cks >> (32-CCS_ROT));
+ }
+
+ return (cks);
+}
+
+
+BOOLEAN
+CPDATA::VerifyAndFix (
+ IN PLOG_IO_DP_DRIVE pliodpdrv,
+ IN PCODEPAGE_INFO CurrentInfoEntry,
+ IN BOOLEAN UpdateAllowed,
+ OUT PBOOLEAN ErrorsDetected
+ )
+/*++
+
+Description of Routine:
+
+Arguments:
+
+ pliodbdrv -- supplies the drive on which this entry resides
+ CurrentInfoEntry -- supplies the matching Codepage Information Entry
+ UpdateAllowed -- supplies a flag indicating whether corrections
+ should be written to disk
+ ErrorsDetected -- receives TRUE if errors are found
+
+ Note that this routine is a friend of CurrentInfoEntry, and may
+ diddle its private data.
+
+Returns:
+
+ a VERIFY_RETURN_CODE indicating the state of the object.
+
+--*/
+{
+ PCPINFOENTRY pcpinfo;
+ PCPDATAENTRY pcpdata;
+ USHORT BytesPerDataSector;
+ USHORT Offset;
+ USHORT MaxRangeCount;
+ CHECKSUM cks;
+ BOOLEAN RangeCountsMatch;
+ USHORT OldcDBCSrange, OldCountry, OldID;
+
+ DebugAssert( mIsInitialized );
+ DebugAssert( mSectorIsValid );
+
+ (void)( UpdateAllowed );
+
+ BytesPerDataSector = (USHORT)(pliodpdrv->QuerySectorSize() *
+ SectorsPerCPDataSector);
+
+ // Look up the entry's offset into the data sector
+ // and make sure that it is reasonable (i.e. that the
+ // data entry could fit in the sector.
+
+ Offset = pcpdatasecd->offCPData[mCurrentIndexInSector];
+
+ if( Offset >= BytesPerDataSector - (USHORT)sizeof (CPDATAENTRY) ) {
+
+ // The offset is too large; there is no way this
+ // can be a valid entry.
+
+ return FALSE;
+ }
+
+
+ // Compute the greatest number of DBCS range pairs that
+ // the entry could have without overflowing the sector:
+
+ MaxRangeCount = (USHORT)
+ (( BytesPerDataSector - Offset - sizeof (CPDATAENTRY) ) /
+ sizeof(DBCS_Range));
+
+
+ // Set up pointers to the data entry and the info entry,
+ // for later use:
+
+ pcpinfo = &(CurrentInfoEntry->pcpinfosecd->
+ cpinfoent[CurrentInfoEntry->mCurrentIndexInSector]);
+
+ pcpdata = (PCPDATAENTRY)((PBYTE)pcpdatasecd +
+ pcpdatasecd->offCPData[mCurrentIndexInSector]);
+
+
+ // Since the number of DBCS range-pairs (the range count) affects
+ // computation of the checksum, we need to check it first.
+
+ RangeCountsMatch = (BOOLEAN)(pcpdata->cDBCSrange == pcpinfo->cDBCSrange );
+
+ if ( !RangeCountsMatch && (pcpdata->cDBCSrange <= MaxRangeCount) ) {
+
+ // The range counts in the data entry and the info
+ // entry disagree; we have to decide which to trust.
+ // Since the range count in the data entry isn't too large,
+ // compute the checksum based on that value; if that
+ // checksum matches the checksum in either the data entry or
+ // the info entry, assume that it's good.
+
+ cks = ComputeChecksum();
+
+ if ( cks == pcpinfo->cksCP ||
+ cks == pcpdatasecd->cksCP[mCurrentIndexInSector] ) {
+
+ // The data entry's range count gives a good checksum,
+ // so we'll keep it. Update the info entry accordingly.
+
+ *ErrorsDetected = TRUE;
+
+ pcpinfo->cDBCSrange = pcpdata->cDBCSrange;
+ CurrentInfoEntry->mIsModified = TRUE;
+ RangeCountsMatch = TRUE;
+ }
+ }
+
+ if ( !RangeCountsMatch && (pcpinfo->cDBCSrange <= MaxRangeCount) ) {
+
+ // The range counts still don't match. Since we rejected the
+ // value in the data entry, try the value in the info entry.
+ // Note that we have to substitute it into the data entry
+ // before we compute the checksum, and have to back that
+ // change out if we decide we don't like it.
+
+ OldcDBCSrange = pcpdata->cDBCSrange;
+ pcpdata->cDBCSrange = pcpinfo->cDBCSrange;
+
+ cks = ComputeChecksum();
+
+ if ( cks == pcpinfo->cksCP ||
+ cks == pcpdatasecd->cksCP[mCurrentIndexInSector] ) {
+
+ // The info entry's range count gives a good checksum,
+ // so we'll keep it. (We've already put it into the
+ // data entry.)
+
+ *ErrorsDetected = TRUE;
+
+ mIsModified = TRUE;
+ RangeCountsMatch = TRUE;
+
+ } else {
+
+ // Didn't work; back out the change.
+
+ pcpdata->cDBCSrange = OldcDBCSrange;
+ }
+ }
+
+ if ( !RangeCountsMatch || (pcpdata->cDBCSrange > MaxRangeCount) ) {
+
+ // Either the ranges still don't match, or they're both
+ // too big. Either way, this entry is invalid.
+
+ return FALSE;
+ }
+
+ // OK, we have a range-count value we're happy with; now we
+ // can compute the checksum.
+
+ cks = ComputeChecksum();
+
+ if ( cks != pcpinfo->cksCP &&
+ cks == pcpdatasecd->cksCP[mCurrentIndexInSector] ) {
+
+ // The checksum in the info entry is wrong, but the
+ // value in the data entry is OK, so we can just correct
+ // the info entry.
+
+ *ErrorsDetected = TRUE;
+
+ pcpinfo->cksCP = pcpdatasecd->cksCP[mCurrentIndexInSector];
+ CurrentInfoEntry->mIsModified = TRUE;
+
+ } else if ( cks == pcpinfo->cksCP &&
+ cks != pcpdatasecd->cksCP[mCurrentIndexInSector] ) {
+
+ // The checksum in the data entry is wrong, but the
+ // value in the info entry is OK, so we can just correct
+ // the data entry.
+
+ *ErrorsDetected = TRUE;
+
+ pcpdatasecd->cksCP[mCurrentIndexInSector] = pcpinfo->cksCP;
+ mIsModified = TRUE;
+
+ } else if ( cks != pcpinfo->cksCP &&
+ cks != pcpdatasecd->cksCP[mCurrentIndexInSector] ) {
+
+ // Both checksums are wrong. Our last resort is to copy the
+ // country code and codepage ID from the info entry into the
+ // data entry and recompute the checksum, to see if it matches
+ // either checksum. If this substitution fails, we have
+ // to back it out.
+
+ OldCountry = pcpdata->CountryCode;
+ OldID = pcpdata->CodePageID;
+
+ pcpdata->CountryCode = pcpinfo->CountryCode;
+ pcpdata->CodePageID = pcpinfo->CodePageID;
+
+ cks = ComputeChecksum();
+
+ if( cks == pcpinfo->cksCP ||
+ cks == pcpdatasecd->cksCP[mCurrentIndexInSector] ) {
+
+ // Saved at the last minute. Propagate the checksum
+ // as necessary.
+
+ if( pcpinfo->cksCP != cks ) {
+
+ pcpinfo->cksCP = cks;
+ CurrentInfoEntry->mIsModified = TRUE;
+ }
+
+ if( pcpdatasecd->cksCP[mCurrentIndexInSector] != cks ) {
+
+ pcpdatasecd->cksCP[mCurrentIndexInSector] = cks;
+ }
+
+ mIsModified = TRUE;
+
+ *ErrorsDetected = TRUE;
+
+ } else {
+
+ // Our method of last resort didn't work. Back out
+ // the change and give up.
+
+ pcpdata->CountryCode = OldCountry;
+ pcpdata->CodePageID = OldID;
+
+ return FALSE;
+ }
+ }
+
+
+ // At this point, we know the data entry is valid, so
+ // we can use it to check the Country Code and Codepage ID
+ // in the info entry.
+
+ if ( pcpinfo->CountryCode != pcpdata->CountryCode ||
+ pcpinfo->CodePageID != pcpdata->CodePageID ) {
+
+ pcpinfo->CountryCode = pcpdata->CountryCode;
+ pcpinfo->CodePageID = pcpdata->CodePageID;
+
+ *ErrorsDetected = TRUE;
+
+ CurrentInfoEntry->mIsModified = TRUE;
+ }
+
+ return TRUE;
+
+}
+
+
+PCPDATAENTRY
+CPDATA::GetEntry(
+ ) CONST
+/*++
+
+Routine Description:
+
+ Get a pointer to the current entry.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ A pointer to the current data entry
+
+Notes:
+
+ The current data entry is an ephemeral object; the client should
+ not cache this pointer, but should copy the data it needs immediately.
+
+
+--*/
+{
+ return (PCPDATAENTRY)((PBYTE)pcpdatasecd +
+ pcpdatasecd->offCPData[mCurrentIndexInSector]);
+}
+
+
+DEFINE_CONSTRUCTOR( CASEMAP, OBJECT );
+
+VOID
+CASEMAP::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Construct a Casemap object. The private data are set to
+ harmless values.
+
+--*/
+{
+ ULONG i;
+
+ for( i = 0; i < MaximumCodepagesOnVol; i++ ) {
+
+ _CaseTable[i] = NULL;
+ _IsDBCS[i] = NULL;
+ _HasDBCS[i] = FALSE;
+ _IsValid[i] = FALSE;
+ }
+}
+
+
+
+CASEMAP::~CASEMAP (
+ )
+{
+ Destroy();
+}
+
+
+BOOLEAN
+CASEMAP::Initialize (
+ )
+/*++
+
+Routine Description:
+
+ Initialize a casemap object.
+
+--*/
+{
+ Destroy();
+ return TRUE;
+}
+
+
+
+BOOLEAN
+CASEMAP::HasDBCS(
+ IN ULONG CodePageIndex
+ ) CONST
+/*++
+
+Routine Description:
+
+ Query whether a given codepage index has DBCS characters.
+
+Arguments:
+
+ CodePageIndex -- supplies the codepage's index on the volume
+
+Return Value:
+
+ TRUE if the codepage has DBCS characters; FALSE if not.
+
+--*/
+{
+ return _HasDBCS[CodePageIndex];
+}
+
+
+BOOLEAN
+CASEMAP::IsDBCS(
+ IN ULONG CodePageIndex,
+ IN UCHAR Char
+ ) CONST
+/*++
+
+Routine Description:
+
+ Query whether a particular character is a DBCS lead-byte in
+ a certain codepage
+
+Arguments:
+
+ CodePageIndex -- supplies the codepage's index on the volume
+ Char - supplies the byte in question
+
+Return Value:
+
+ TRUE if Char is a DBCS lead-byte for the specified codepage
+
+--*/
+{
+ if( !_IsValid[CodePageIndex] || !_HasDBCS[CodePageIndex] ) {
+
+ return FALSE;
+ }
+
+ return _IsDBCS[CodePageIndex][Char];
+}
+
+
+UCHAR
+CASEMAP::UpperCase(
+ IN UCHAR Char,
+ IN ULONG CodePageIndex
+ ) CONST
+/*++
+
+Routine Description:
+
+ Translate a character to upper-case
+
+Arguments:
+
+ CodePageIndex -- supplies the codepage's index on the volume
+ Char - supplies the byte in question
+
+Return Value:
+
+ The upper-case equivalent of Char.
+
+--*/
+{
+ if( !_IsValid[CodePageIndex] ) {
+
+ return Char;
+ }
+
+ return _CaseTable[CodePageIndex][Char];
+}
+
+
+BOOLEAN
+CASEMAP::AddCodepage (
+ ULONG CodePageIndex,
+ PCPDATAENTRY pcpdataent
+ )
+{
+
+ ULONG i;
+ UCHAR j;
+
+ if( _CaseTable[CodePageIndex] == NULL &&
+ (_CaseTable[CodePageIndex] =
+ (PUCHAR)MALLOC( CaseTableSize )) == NULL ) {
+
+ _HasDBCS[CodePageIndex] = FALSE;
+ _IsValid[CodePageIndex] = FALSE;
+ return FALSE;
+ }
+
+ _HasDBCS[CodePageIndex] = (BOOLEAN)(pcpdataent->cDBCSrange != 0);
+
+ if( _HasDBCS[CodePageIndex] &&
+ _IsDBCS[CodePageIndex] == NULL &&
+ (_IsDBCS[CodePageIndex] =
+ (PBOOLEAN)MALLOC( CaseTableSize )) == NULL ) {
+
+ FREE( _CaseTable[CodePageIndex] );
+ _CaseTable[CodePageIndex] = NULL;
+ _HasDBCS[CodePageIndex] = FALSE;
+ _IsValid[CodePageIndex] = FALSE;
+ return FALSE;
+ }
+
+ _CodepageId[CodePageIndex] = pcpdataent->CodePageID;
+ _IsValid[CodePageIndex] = TRUE;
+
+
+ // The first 128 characters of every casemap table are the same--
+ // 'a' - 'z' map to 'A' - 'Z' and everything else maps to itself.
+
+ for( i = 0; i < 128; i++ ) {
+
+ _CaseTable[CodePageIndex][i] = (UCHAR)i;
+
+ }
+
+ for( i = 'a', j = 'A'; i <= 'z' ; i++, j++ ) {
+
+ _CaseTable[CodePageIndex][i] = j;
+ }
+
+ // Copy the case-mapping information for the upper 128 bytes from
+ // the the codepage data entry.
+
+ memmove( _CaseTable[CodePageIndex] + 128, pcpdataent->bCaseMapTable,
+ CharsInCasemap );
+
+ if( _HasDBCS[CodePageIndex] ) {
+
+ // This codepage has DBCS characters; fill in the _IsDBCS array.
+ // First, initialize all the entries to FALSE. Then go back and
+ // fill each DBCS range in as TRUE.
+
+ for( i = 0; i < CaseTableSize; i++ ) {
+
+ _IsDBCS[CodePageIndex][i] = FALSE;
+ }
+
+
+ for( i = 0; i < pcpdataent->cDBCSrange; i++ ) {
+
+ for( j = pcpdataent->DBCS_RangeTable[i].CDIB_DBCS_start;
+ j <= pcpdataent->DBCS_RangeTable[i].CDIB_DBCS_end;
+ j++ ) {
+
+ _IsDBCS[CodePageIndex][j] = TRUE;
+ }
+ }
+ }
+
+
+ return TRUE;
+}
+
+
+BOOLEAN
+CASEMAP::IsCodpageIndexValid(
+ ULONG CodepageIndex
+ ) CONST
+{
+ return ( CodepageIndex < MaximumCodepagesOnVol &&
+ _IsValid[CodepageIndex] );
+}
+
+
+
+VOID
+CASEMAP::Destroy(
+ )
+{
+
+ ULONG i;
+
+ for( i = 0; i < MaximumCodepagesOnVol; i++ ) {
+
+ if( _CaseTable[i] != NULL ) {
+
+ FREE( _CaseTable[i] );
+ _CaseTable[i] = NULL;
+ }
+
+ if( _IsDBCS[i] != NULL ) {
+
+ FREE( _IsDBCS[i] );
+ _IsDBCS[i] = NULL;
+ }
+
+ _HasDBCS[i] = FALSE;
+ _IsValid[i] = FALSE;
+ }
+}
diff --git a/private/utils/uhpfs/src/defer.cxx b/private/utils/uhpfs/src/defer.cxx
new file mode 100644
index 000000000..fcc1462ab
--- /dev/null
+++ b/private/utils/uhpfs/src/defer.cxx
@@ -0,0 +1,1386 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ defer.cxx
+
+Abstract:
+
+ While it is verifying a volume, HPFS Chkdsk may discover
+ errors or conditions which require the allocation of new
+ sectors. However, since it discovers these problems while
+ it is verifying the bitmap, it cannot immediately correct
+ them. Instead, they go in the deferred action pool, to be
+ resolved later.
+
+ Actions which are deferred are: hotfix resolution, crosslink
+ resolution, directory-entry deletion, and directory sorting.
+
+Author:
+
+ Bill McJohn (billmc) 26-Dec-1990
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "alsec.hxx"
+#include "defer.hxx"
+#include "dirblk.hxx"
+#include "dircache.hxx"
+#include "dirtree.hxx"
+#include "error.hxx"
+#include "hpfssa.hxx"
+#include "hpfsname.hxx"
+#include "fnode.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+
+DEFINE_CONSTRUCTOR( DEFERRED_ACTIONS_LIST, OBJECT );
+
+DEFERRED_ACTIONS_LIST::~DEFERRED_ACTIONS_LIST(
+ )
+/*++
+
+Routine Description:
+
+ This method destroys the object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+DEFERRED_ACTIONS_LIST::Construct (
+ )
+/*++
+
+Routine Description:
+
+ This method is the helper routine for object construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ ULONG i;
+
+ _HotfixOverflow = FALSE;
+ _DeleteOverflow = FALSE;
+ _SortOverflow = FALSE;
+
+ for( i = 0; i < MaximumDeferredHotfixes; i++ ) {
+
+ _Hotfixes[i].ParentLbn = 0;
+ }
+
+ for( i = 0; i < MaximumDeferredXlinks; i++ ) {
+
+ _Xlinks[i].ParentLbn = 0;
+ }
+
+ for( i = 0; i < MaximumFnodesToSort; i++ ) {
+
+ _FnodesToSort[i] = 0;
+ }
+
+ _TargetSectors = 0;
+ _VisitedSectors = 0;
+ _PercentComplete = 0;
+}
+
+VOID
+DEFERRED_ACTIONS_LIST::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This method cleans up the object in preparation for destruction
+ or reinitialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ ULONG i;
+
+ _HotfixOverflow = FALSE;
+ _DeleteOverflow = FALSE;
+ _SortOverflow = FALSE;
+
+ for( i = 0; i < MaximumNamesToDelete; i ++ ) {
+
+ DELETE( _PathsToDelete[i] );
+ _PathsToDelete[i] = NULL;
+
+ DELETE( _NamesToDelete[i] );
+ _NamesToDelete[i] = NULL;
+ }
+
+ _TargetSectors = 0;
+ _VisitedSectors = 0;
+ _PercentComplete = 0;
+}
+
+
+
+
+BOOLEAN
+DEFERRED_ACTIONS_LIST::Initialize(
+ )
+/*++
+
+Routine Description:
+
+ This method initializes the object, preparing it for use.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+ This object may be reinitialized.
+
+--*/
+{
+ ULONG i;
+
+ _HotfixOverflow = FALSE;
+ _DeleteOverflow = FALSE;
+ _SortOverflow = FALSE;
+
+ for( i = 0; i < MaximumDeferredHotfixes; i++ ) {
+
+ _Hotfixes[i].ParentLbn = 0;
+ }
+
+ for( i = 0; i < MaximumDeferredXlinks; i++ ) {
+
+ _Xlinks[i].ParentLbn = 0;
+ }
+
+ for( i = 0; i < MaximumFnodesToSort; i++ ) {
+
+ _FnodesToSort[i] = 0;
+ }
+
+ for( i = 0; i < MaximumNamesToDelete; i++ ) {
+
+ _PathsToDelete[i] = NULL;
+ _NamesToDelete[i] = NULL;
+ }
+
+ _NumberOfDirectories = 0;
+ _NumberOfDirblks = 0;
+ _NumberOfFiles = 0;
+ _TotalFileSectors = 0;
+ _TotalEaSectors = 0;
+
+ _TargetSectors = 0;
+ _VisitedSectors = 0;
+ _PercentComplete = 0;
+
+ return TRUE;
+}
+
+
+
+VOID
+DEFERRED_ACTIONS_LIST::AddHotfixedLbn(
+ LBN ParentLbn,
+ DEFERRED_SECTOR_TYPE ParentSectorType,
+ DEFERRED_SECTOR_TYPE ChildSectorType
+ )
+/*++
+
+Routine Description:
+
+ This method adds an Lbn to the list of hotfix references to resolve.
+
+Arguments:
+
+ ParentLbn -- supplies the lbn of the hotfixed lbn's parent
+ ParentSectorType -- supplies the type of the parent sector
+ (Dirblk, FNode, or AlSec)
+ ChildSectorType -- supplies the type of the child lbn
+ (Dirblk, File data, ACL data, or EA data)
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG i;
+
+ // Find a free slot in the list of deferred hotfixes and
+ // put this entry there.
+
+ i = 0;
+
+ while( i < MaximumDeferredHotfixes &&
+ _Hotfixes[i].ParentLbn != 0 ) {
+
+ i += 1;
+ }
+
+ if( i >= MaximumDeferredHotfixes ) {
+
+ _HotfixOverflow = TRUE;
+ return;
+ }
+
+ _Hotfixes[i].ParentLbn = ParentLbn;
+ _Hotfixes[i].ParentType = ParentSectorType;
+ _Hotfixes[i].ChildType = ChildSectorType;
+}
+
+
+
+BOOLEAN
+DEFERRED_ACTIONS_LIST::AddCrosslinkedLbn(
+ LBN ParentLbn,
+ HPFS_PATH* CurrentPath,
+ DEFERRED_SECTOR_TYPE ParentSectorType,
+ ULONG RunIndex
+ )
+/*++
+
+Routine Description:
+
+ This method adds a crosslink to the list of crosslinks to be resolved
+
+Arguments:
+
+ ParentLbn -- supplies the Lbn of the crosslink's parent.
+ CurrentPath -- supplies Full path of the object affected
+ by the crosslink
+ ParentSectorType -- indicates the type of the parent Lbn
+ (FNode or AlSec).
+ RunIndex -- supplies the index into the parent's storage
+ area of the run which is crosslinked.
+
+Return Value:
+
+ TRUE if the crosslink is successfully added to the list.
+
+ Note that, unlike the other deferred actions, this method
+ returns an indication of its success or failure, and there
+ is no QueryUnresolved method for crosslinks.
+
+--*/
+{
+ ULONG i;
+
+ i = 0;
+
+ if( ParentSectorType != DEFER_FNODE &&
+ ParentSectorType != DEFER_ALSEC ) {
+
+ // Parent type is invalid
+ return FALSE;
+ }
+
+ // Find a free slot--a slot is free if the ParentLbn is zero.
+
+ while( i < MaximumDeferredXlinks && _Xlinks[i].ParentLbn != 0 ) {
+
+ i += 1;
+ }
+
+ if( i >= MaximumDeferredXlinks ) {
+
+ // No room in the list.
+ return FALSE;
+ }
+
+ // Copy the path first, since that's the only one that can fail.
+
+ if( (_Xlinks[i].Path = NEW HPFS_PATH) == NULL ||
+ !_Xlinks[i].Path->Initialize() ||
+ !_Xlinks[i].Path->Copy( CurrentPath ) ) {
+
+ return FALSE;
+ }
+
+ _Xlinks[i].ParentLbn = ParentLbn;
+ _Xlinks[i].ParentType = ParentSectorType;
+ _Xlinks[i].RunIndex = RunIndex;
+
+ return TRUE;
+}
+
+
+
+VOID
+DEFERRED_ACTIONS_LIST::AddNameToDelete(
+ HPFS_PATH* PathToDelete,
+ HPFS_NAME* NameToDelete
+ )
+/*++
+
+Routine Description:
+
+ This methods adds a file or directory name to the list of objects to
+ be deleted.
+
+Arguments:
+
+ PathToDelete -- supplies path to object to delete (must be non-NULL)
+ NameToDelete -- supplies name of object to delete (may be NULL)
+
+Return Value:
+
+ None.
+
+Notes:
+
+ If NameToDelete is non-NULL, the target object has name
+ NameToDelete in directory PathToDelete; if NameToDelete
+ is NULL, then PathToDelete is the complete path to the
+ target object.
+
+--*/
+{
+ ULONG i;
+
+
+ // Find a free slot:
+
+ for( i = 0; i < MaximumNamesToDelete; i++ ) {
+
+ if( _PathsToDelete[i] == NULL ) {
+
+ break;
+ }
+ }
+
+
+ if( i >= MaximumNamesToDelete ||
+ (_PathsToDelete[i] = NEW HPFS_PATH) == NULL ||
+ !_PathsToDelete[i]->Initialize() ||
+ !_PathsToDelete[i]->Copy( PathToDelete ) ) {
+
+
+ _DeleteOverflow = TRUE;
+
+ DELETE( _PathsToDelete[i] );
+ _PathsToDelete[i] = NULL;
+
+ return;
+ }
+
+
+ if( NameToDelete == NULL ) {
+
+ _NamesToDelete[i] = NULL;
+
+ } else if ( (_NamesToDelete[i] = NEW HPFS_NAME) == NULL ||
+ !_NamesToDelete[i]->Initialize( NameToDelete ) ) {
+
+ _DeleteOverflow = TRUE;
+
+ DELETE( _PathsToDelete[i] );
+ _PathsToDelete[i] = NULL;
+ DELETE( _NamesToDelete[i] );
+ _NamesToDelete[i] = NULL;
+ }
+}
+
+
+
+VOID
+DEFERRED_ACTIONS_LIST::AddDirectoryToSort(
+ LBN LbnFnode
+ )
+/*++
+
+Routine Description:
+
+ This method adds a directory fnode to the list of directories
+ to be sorted.
+
+Arguments:
+
+ LbnFnode -- supplies the FNode lbn of the directory to be sorted
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ ULONG i = 0;
+
+ while( i < MaximumFnodesToSort && _FnodesToSort[i] != 0 ) {
+
+ i += 1;
+ }
+
+ if( i < MaximumFnodesToSort ) {
+
+ _FnodesToSort[i] = LbnFnode;
+
+ } else {
+
+ _SortOverflow = TRUE;
+ }
+}
+
+
+
+
+VOID
+DEFERRED_ACTIONS_LIST::ResolveDeferredHotfixes(
+ PLOG_IO_DP_DRIVE Drive,
+ HPFS_SA* SuperArea
+ )
+/*++
+
+Routine Description:
+
+ This method traverses the list of unresolved hotfixes and
+ attempts to resolve them.
+
+Arguments:
+
+ Drive -- supplies the drive on which the hotfixes reside.
+ SuperArea -- supplies the Super Area of the volume.
+
+Return Value:
+
+ None. The client may determine whether any unresolved hotfixes
+ remain by calling QueryUnresolvedHotfixes.
+
+--*/
+{
+ ULONG i;
+ PDIRBLK ChildDirblk;
+ FNODE* ChildFnode;
+ PALSEC ChildAlsec;
+
+ for( i = 0; i < MaximumDeferredHotfixes; i++ ) {
+
+ if( _Hotfixes[i].ParentLbn != 0 ) {
+
+ // This is a deferred hotfix
+
+ switch ( _Hotfixes[i].ParentType ) {
+
+ case DEFER_DIRBLK :
+
+ if( (ChildDirblk = NEW DIRBLK) != NULL &&
+ ChildDirblk->Initialize( Drive,
+ SuperArea->GetHotfixList(),
+ _Hotfixes[i].ParentLbn ) &&
+ ChildDirblk->
+ FindAndResolveHotfix( SuperArea,
+ _Hotfixes[i].ChildType ) ) {
+
+ // This hotfix successfully resolved.
+ _Hotfixes[i].ParentLbn = 0;
+ }
+
+ DELETE( ChildDirblk );
+ break;
+
+ case DEFER_FNODE :
+
+ if( (ChildFnode = NEW FNODE) != NULL &&
+ ChildFnode->Initialize( Drive,
+ _Hotfixes[i].ParentLbn ) &&
+ ChildFnode->
+ FindAndResolveHotfix( SuperArea,
+ _Hotfixes[i].ChildType ) ) {
+
+ // This hotfix successfully resolved.
+ _Hotfixes[i].ParentLbn = 0;
+ }
+
+ DELETE( ChildFnode );
+ break;
+
+ case DEFER_ALSEC :
+
+ if( (ChildAlsec = NEW ALSEC) != NULL &&
+ ChildAlsec->Initialize( Drive,
+ _Hotfixes[i].ParentLbn ) &&
+ ChildAlsec->
+ FindAndResolveHotfix( SuperArea,
+ _Hotfixes[i].ChildType ) ) {
+
+ // This hotfix successfully resolved.
+ _Hotfixes[i].ParentLbn = 0;
+ }
+
+ DELETE( ChildAlsec );
+ break;
+
+ default :
+
+ break;
+ }
+ }
+ }
+}
+
+
+
+VOID
+DEFERRED_ACTIONS_LIST::ResolveDeferredCrosslinks(
+ PLOG_IO_DP_DRIVE Drive,
+ HPFS_SA* SuperArea
+ )
+/*++
+
+Routine Description:
+
+ This method traverses the list of deferred crosslinks and
+ attempts to resolve them.
+
+Arguments:
+
+ Drive -- supplies the drive being fixed.
+ SuperArea -- supplies the volume's super area.
+
+Return Value:
+
+ None.
+
+Notes:
+
+ If a crosslink cannot be resolved, for whatever reason, then
+ its associated path goes on the Delete list.
+
+ There is no QueryUnresolvedCrosslinks method; this method either
+ resolves crosslinks or moves them to the Delete pile; it does not
+ leave any unresolved.
+
+--*/
+{
+ ULONG i;
+ FNODE Fnode;
+ ALSEC Alsec;
+
+ for( i = 0; i < MaximumDeferredXlinks; i++ ) {
+
+ if( _Xlinks[i].ParentLbn != 0 ) {
+
+ // This is an unresolved crosslink.
+
+ switch( _Xlinks[i].ParentType ) {
+
+
+ case DEFER_FNODE :
+
+ if( Fnode.Initialize( Drive, _Xlinks[i].ParentLbn ) &&
+ Fnode.ResolveCrosslink( SuperArea,
+ _Xlinks[i].RunIndex ) ) {
+
+ // Successfully resolved the crosslink
+
+ _Xlinks[i].ParentLbn = 0;
+
+ } else {
+
+ // We couldn't resolve the hotfix, either because
+ // Chkdsk ran out of resources or because of
+ // some problem with the FNode. Since we can't
+ // leave the crosslink lying about, delete the file.
+
+ AddNameToDelete( _Xlinks[i].Path, NULL );
+ }
+
+ break;
+
+ case DEFER_ALSEC :
+
+ if( Alsec.Initialize( Drive, _Xlinks[i].ParentLbn ) &&
+ Alsec.ResolveCrosslink( SuperArea,
+ _Xlinks[i].RunIndex ) ) {
+
+ // Successfully resolved the crosslink
+
+ _Xlinks[i].ParentLbn = 0;
+
+ } else {
+
+ // We couldn't resolve the crosslink, either because
+ // Chkdsk ran out of resources or because of
+ // some problem with the Alsec. Since we can't
+ // leave the crosslink lying about, delete the file.
+
+ AddNameToDelete( _Xlinks[i].Path, NULL );
+ }
+
+ break;
+
+ default :
+
+ break;
+ }
+ }
+ }
+}
+
+
+
+VOID
+DEFERRED_ACTIONS_LIST::Sort(
+ PLOG_IO_DP_DRIVE Drive,
+ HPFS_SA* SuperArea,
+ DIRBLK_CACHE* Cache,
+ LBN RootFnodeLbn,
+ HPFS_DIRECTORY_TREE* RootTree
+ )
+/*++
+
+Routine Description:
+
+ This method sorts the directories in the to-be-sorted list.
+
+Arguments:
+
+ Drive -- supplies the drive on which the directories reside.
+ SuperArea -- supplies the volume's superarea.
+ Cache -- supplies the dirblk cache for that drive.
+
+Return Value:
+
+ None. The caller may determine whether any deferred sorts were left
+ unresolved by calling QueryUnresolvedSorts.
+
+Notes:
+
+ If a directory other than the root is sorted, SORT will
+ read its FNode and update its root dirblk lbn. However,
+ if the root directory is sorted, the caller must update
+ the root FNode.
+
+--*/
+{
+ ULONG i;
+ FNODE Fnode;
+ HPFS_DIRECTORY_TREE DirTree;
+
+ if( !Fnode.Initialize( Drive, 0 ) ) {
+
+ return;
+ }
+
+ for( i = 0; i < MaximumFnodesToSort; i++ ) {
+
+ if( _FnodesToSort[i] != 0 ) {
+
+ // We have the FNode lbn of a directory to be sorted.
+ // Read the FNode to make sure it's a directory, then
+ // initialize the directory tree object and tell it
+ // to sort itself.
+
+ if( _FnodesToSort[i] == RootFnodeLbn ) {
+
+ // We have to sort the root directory.
+
+ if( RootTree->Sort() ) {
+
+ // Note that the caller is responsible
+ // for fixing up the root FNode.
+
+ _FnodesToSort[i] = 0;
+ }
+
+ } else {
+
+ Fnode.Relocate( _FnodesToSort[i] );
+
+ if( Fnode.Read() &&
+ Fnode.IsFnode() &&
+ DirTree.Initialize( SuperArea,
+ Cache,
+ Fnode.QueryRootDirblkLbn(),
+ _FnodesToSort[i] ) &&
+ DirTree.Sort( ) ) {
+
+ // The directory is now in proper order; remove
+ // this Fnode lbn from the list. Since the
+ // root dirblk lbn has (presumably) changed,
+ // we need to update the FNode. Then we can
+ // remove this FNode from the to-be-sorted list.
+
+ Fnode.SetRootDirblkLbn( DirTree.QueryRootDirblkLbn() );
+ Fnode.Write();
+
+ _FnodesToSort[i] = 0;
+ }
+ }
+ }
+ }
+}
+
+
+
+VOID
+DEFERRED_ACTIONS_LIST::Delete(
+ PLOG_IO_DP_DRIVE Drive,
+ HPFS_SA* SuperArea,
+ DIRBLK_CACHE* Cache,
+ HPFS_DIRECTORY_TREE* RootTree,
+ LBN RootFnodeLbn
+ )
+/*++
+
+Routine Description:
+
+ This method traverses the list of directory-entries-to-be-deleted
+ and attempts to delete them.
+
+Arguments:
+
+ Drive -- supplies the drive which is being fixed.
+ SuperArea -- supplies the volume superarea.
+ Cache -- supplies the volume dirblk cache.
+ RootTree -- supplies the directory tree for the volume's
+ root directory.
+ RootFnodeLbn -- supplies the LBN of the volume's root FNode.
+
+Return Value
+
+ None. Deferred deletes which are resolved are removed from the list;
+ the client may determine if any deletes were unresolved by calling
+ QueryUnresolvedDeletes.
+
+Notes:
+
+ If a directory which is to be deleted does not exist, then that
+ deferred deletion is considered resolved.
+
+--*/
+{
+ ULONG i;
+ HPFS_NAME* CurrentName;
+ HPFS_NAME* NextName;
+ HPFS_DIRECTORY_TREE CurrentTree;
+ FNODE CurrentFnode;
+ LBN CurrentFnodeLbn, CurrentRootDirblkLbn;
+ BOOLEAN NotFound, DeleteSuccessful;
+
+
+ if( !CurrentFnode.Initialize( Drive, 0 ) ) {
+
+ return;
+ }
+
+
+ for( i = 0; i < MaximumNamesToDelete; i++ ) {
+
+ if( _PathsToDelete[i] == NULL ) {
+
+ // Nothing in this slot.
+
+ continue;
+ }
+
+ NotFound = FALSE;
+
+ NextName = _PathsToDelete[i]->QueryFirstLevel();
+ CurrentName = NextName;
+
+ if( NextName != NULL ) {
+
+ NextName = _PathsToDelete[i]->QueryNextLevel();
+ }
+
+ if( CurrentName == NULL ) {
+
+ if( RootTree->Delete( _NamesToDelete[i] ) ) {
+
+ _PathsToDelete[i] = NULL;
+ }
+
+ } else if( NextName == NULL && _NamesToDelete[i] == NULL ) {
+
+ if( RootTree->Delete( CurrentName ) ) {
+
+ _PathsToDelete[i] = NULL;
+ }
+
+ } else {
+
+ if( !CurrentTree.Initialize( SuperArea,
+ Cache,
+ RootTree->QueryRootDirblkLbn(),
+ RootFnodeLbn ) ) {
+
+ NotFound = TRUE;
+ }
+
+ // If the name to delete is NULL, we stop when NextName
+ // is null, so that we can use the last component of the
+ // path as the name to delete; otherwise, we keep going
+ // until CurrentName is NULL.
+
+ while( CurrentName != NULL &&
+ (_NamesToDelete[i] != NULL || NextName != NULL) &&
+ !NotFound ) {
+
+ CurrentFnodeLbn = CurrentTree.
+ QueryFnodeLbnFromName( CurrentName );
+
+ if( CurrentFnodeLbn == 0 ) {
+
+ NotFound = TRUE;
+ break;
+ }
+
+ CurrentFnode.Relocate( CurrentFnodeLbn );
+
+ if( !CurrentFnode.Read() ||
+ !CurrentFnode.IsFnode() ||
+ (CurrentRootDirblkLbn =
+ CurrentFnode.QueryRootDirblkLbn()) == 0 ||
+ !CurrentTree.Initialize( SuperArea,
+ Cache,
+ CurrentRootDirblkLbn,
+ CurrentFnodeLbn ) ) {
+
+ NotFound = TRUE;
+
+ } else {
+
+ DELETE( CurrentName );
+ CurrentName = NextName;
+
+ if( NextName != NULL ) {
+
+ NextName = _PathsToDelete[i]->QueryNextLevel();
+ }
+ }
+ }
+
+ if( NotFound ) {
+
+ // We couldn't find it, so we don't need to delete it.
+
+ _PathsToDelete[i] = NULL;
+ continue;
+ }
+
+
+
+ if( _NamesToDelete[i] == NULL ) {
+
+ DeleteSuccessful = CurrentTree.Delete( CurrentName );
+
+ } else {
+
+ DeleteSuccessful = CurrentTree.Delete( _NamesToDelete[i] );
+ }
+
+ if( DeleteSuccessful ) {
+
+ // Successfully deleted the entry.
+
+ _PathsToDelete[i] = NULL;
+ }
+
+
+ if( DeleteSuccessful &&
+ CurrentTree.QueryRootDirblkLbn() !=
+ CurrentFnode.QueryRootDirblkLbn() ) {
+
+ // The root dirblk changed--update the FNode.
+
+ CurrentFnode.SetRootDirblkLbn(
+ CurrentTree.QueryRootDirblkLbn() );
+
+ if( CurrentFnode.QueryStartLbn() == 0 ) {
+
+ DebugPrint("DEFERRED_ACTIONS_LIST::Delete: Writing Fnode at sector zero!\n" );
+
+ } else {
+
+ // It's safe to write
+ CurrentFnode.Write();
+ }
+ }
+ }
+ }
+}
+
+
+
+BOOLEAN
+DEFERRED_ACTIONS_LIST::QueryUnresolvedHotfixes(
+ )
+/*++
+
+Routine Description:
+
+ This method determines whether any unresolved hotfixes remain.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if there are outstanding hotfixes unresolved.
+
+--*/
+{
+ ULONG i;
+
+
+ if( _HotfixOverflow ) {
+
+ return TRUE;
+ }
+
+ for( i = 0; i < MaximumDeferredHotfixes; i++ ) {
+
+ if( _Hotfixes[i].ParentLbn != 0 ) {
+
+ // Found an unresolved hotfix.
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+
+BOOLEAN
+DEFERRED_ACTIONS_LIST::QueryUnresolvedSorts(
+ )
+/*++
+
+Routine Description:
+
+ This method determines whether any directories in need of
+ sorting remain unsorted.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if there are directories remaining to be sorted.
+
+--*/
+{
+ ULONG i;
+
+
+ if( _SortOverflow ) {
+
+ return TRUE;
+ }
+
+ for( i = 0; i < MaximumFnodesToSort; i++ ) {
+
+ if( _FnodesToSort[i] != 0 ) {
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+
+BOOLEAN
+DEFERRED_ACTIONS_LIST::QueryUnresolvedDeletes(
+ )
+/*++
+
+Routine Description:
+
+ This method determines whether any files remain on the delete list.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if there are still entries in the delete list.
+
+--*/
+{
+ ULONG i;
+
+
+ if( _DeleteOverflow ) {
+
+ return TRUE;
+ }
+
+ for( i = 0; i < MaximumNamesToDelete; i++ ) {
+
+ if( _PathsToDelete[i] != NULL ) {
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+
+
+VOID
+DEFERRED_ACTIONS_LIST::StatDirectory(
+ IN BOOLEAN Remove
+ )
+/*++
+
+Routine Description:
+
+ This method updates the number of directories, either adding or
+ subtracting one.
+
+Arguments:
+
+ Remove -- supplies a flag which, if TRUE, indicates that the number
+ of directories should be decremented rather than incremented.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if( Remove ) {
+
+ _NumberOfDirectories -= 1;
+
+ } else {
+
+ _NumberOfDirectories += 1;
+ }
+}
+
+
+
+VOID
+DEFERRED_ACTIONS_LIST::StatDirblk(
+ IN BOOLEAN Remove
+ )
+/*++
+
+Routine Description:
+
+ This method updates the number of Dirblks.
+
+Arguments:
+
+ Remove -- supplies a flag which, if TRUE, indicates that the number
+ of dirblks should be decremented rather than incremented.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if( Remove ) {
+
+ _NumberOfDirblks -= 1;
+
+ } else {
+
+ _NumberOfDirblks += 1;
+ }
+}
+
+
+
+VOID
+DEFERRED_ACTIONS_LIST::StatFile(
+ IN ULONG SectorsInFile,
+ IN BOOLEAN Remove
+ )
+/*++
+
+Routine Description:
+
+ This method updates the number of files and the amount of file data.
+
+Arguments:
+
+ SectorsInFile -- supplies the number of sectors involved in
+ this transaction.
+ Remove -- supplies a flag which, if TRUE, indicates that the
+ number of files should be decremented rather than
+ incremented, and that the number of sectors should
+ be subtracted from, rather than added to, the running
+ total.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if( Remove ) {
+
+ _NumberOfFiles -= 1;
+ _TotalFileSectors -= SectorsInFile;
+
+ } else {
+
+ _NumberOfFiles += 1;
+ _TotalFileSectors += SectorsInFile;
+ }
+}
+
+
+
+VOID
+DEFERRED_ACTIONS_LIST::StatEaData(
+ IN ULONG SectorsInAllocation,
+ IN BOOLEAN Remove
+ )
+/*++
+
+Routine Description:
+
+ This method updates the running total of sectors in Extended Attributes.
+
+Arguments:
+
+ SectorsInAllocation -- supplies the number of sectors involved in
+ this transaction.
+ Remove -- supplies a flag which, if TRUE, indicates that the
+ number of sectors should be subtracted from, rather
+ than added to, the running total.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if( Remove ) {
+
+ _TotalEaSectors -= SectorsInAllocation;
+
+ } else {
+
+ _TotalEaSectors += SectorsInAllocation;
+ }
+}
+
+
+
+VOID
+DEFERRED_ACTIONS_LIST::StatReport(
+ IN ULONG TotalSectors,
+ IN ULONG FreeSectors,
+ IN ULONG BytesPerSector,
+ IN ULONG BadSectors,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This method reports the statistics compiled during Chkdsk.
+
+Arguments:
+
+ TotalSectors -- supplies the number of sectors on the volume.
+ FreeSectors -- supplies the number of free sectors on the volume.
+ BytesPerSector -- supplies the volume sector size.
+ Message -- supplies an output port for messages.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG SectorsForSystem, SectorsAccountedFor;
+ ULONG KBTotal, KBFree, KBSystem, KBDirs, KBFiles, KBEas, KBBad;
+ ULONG Scale;
+
+
+ SectorsAccountedFor = BadSectors +
+ _NumberOfDirblks * SectorsPerDirblk +
+ _TotalFileSectors +
+ _TotalEaSectors;
+
+
+ if( Message == NULL ) {
+
+ DebugPrint( "Can't print statistics--message pointer is null.\n" );
+ return;
+ }
+
+ if( SectorsAccountedFor > TotalSectors ) {
+
+ DebugPrint( "ERROR: The whole is greater than the sum of the parts.\n" );
+ return;
+ }
+
+ SectorsForSystem = TotalSectors - (SectorsAccountedFor + FreeSectors);
+
+ if( BytesPerSector > 0x400 ) {
+
+ if( BytesPerSector % 0x400 ) {
+
+ DebugPrint( "Can't print stats--sector size not even 1K multiple\n" );
+ return;
+ }
+
+ Scale = BytesPerSector / 0x400;
+
+ KBTotal = TotalSectors * Scale;
+ KBFree = FreeSectors * Scale;
+ KBSystem = SectorsForSystem * Scale;
+ KBDirs = _NumberOfDirblks * SectorsPerDirblk * Scale;
+ KBFiles = _TotalFileSectors * Scale;
+ KBEas = _TotalEaSectors * Scale;
+ KBBad = BadSectors * Scale;
+
+ } else {
+
+ if( 0x400 % BytesPerSector ) {
+
+ DebugPrint( "Can't print stats--sector size not divisor of 1K\n" );
+ return;
+ }
+
+ Scale = 0x400 / BytesPerSector;
+
+ KBTotal = TotalSectors / Scale;
+ KBFree = FreeSectors / Scale;
+ KBSystem = SectorsForSystem / Scale;
+ KBDirs = _NumberOfDirblks * SectorsPerDirblk / Scale;
+ KBFiles = _TotalFileSectors / Scale;
+ KBEas = _TotalEaSectors / Scale;
+ KBBad = BadSectors / Scale;
+ }
+
+
+ Message->Set( MSG_BLANK_LINE );
+ Message->Display( "" );
+
+ Message->Set( MSG_HPFS_CHKDSK_STATISTICS_TOTAL_SPACE );
+ Message->Display( "%9d", KBTotal );
+
+ Message->Set( MSG_HPFS_CHKDSK_STATISTICS_DIRECTORIES );
+ Message->Display( "%9d%d", KBDirs, _NumberOfDirectories );
+
+ Message->Set( MSG_HPFS_CHKDSK_STATISTICS_FILE_DATA );
+ Message->Display( "%9d%d", KBFiles, _NumberOfFiles );
+
+ Message->Set( MSG_HPFS_CHKDSK_STATISTICS_BAD );
+ Message->Display( "%9d", KBBad );
+
+ Message->Set( MSG_HPFS_CHKDSK_STATISTICS_EAS );
+ Message->Display( "%9d%d", KBEas );
+
+ Message->Set( MSG_HPFS_CHKDSK_STATISTICS_SYSTEM );
+ Message->Display( "%9d", KBSystem );
+
+ Message->Set( MSG_HPFS_CHKDSK_STATISTICS_FREE_SPACE );
+ Message->Display( "%9d", KBFree );
+
+ Message->Set( MSG_BLANK_LINE );
+ Message->Display( "" );
+
+}
+
+
+BOOLEAN
+DEFERRED_ACTIONS_LIST::RecordVisitedSectors(
+ IN ULONG SectorCount,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+ SectorCount -- Supplies the number of sectors to add
+ to the visited sector count.
+ Message -- Supplies an outlet for a Percent Completed
+ message, if appropriate.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ ULONG OldPercentComplete;
+ BOOLEAN result;
+
+ if( !_TargetSectors ) {
+
+ return TRUE;
+ }
+
+ _VisitedSectors += SectorCount;
+
+ OldPercentComplete = _PercentComplete;
+
+ _PercentComplete = (100 * _VisitedSectors)/_TargetSectors;
+
+ if( _PercentComplete > OldPercentComplete && _PercentComplete <= 100 ) {
+
+ Message->Set( MSG_PERCENT_COMPLETE );
+ result = Message->Display( "%d", _PercentComplete );
+ }
+
+ return result;
+}
diff --git a/private/utils/uhpfs/src/dirblk.cxx b/private/utils/uhpfs/src/dirblk.cxx
new file mode 100644
index 000000000..8ba86781c
--- /dev/null
+++ b/private/utils/uhpfs/src/dirblk.cxx
@@ -0,0 +1,1865 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ dirblk.cxx
+
+Abstract:
+
+ This module contains member function definitions for the
+ DIRBLK object, which models a directory block in an HPFS
+ directory B-Tree.
+
+Author:
+
+ Norbert Kusters (norbertk) 27-Aug-1990
+ Bill McJohn (billmc) 01-Dec-1990
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "ifssys.hxx"
+#include "uhpfs.hxx"
+#include "bitmap.hxx"
+#include "cpinfo.hxx"
+#include "defer.hxx"
+#include "dirblk.hxx"
+#include "error.hxx"
+#include "hotfix.hxx"
+#include "hpcensus.hxx"
+#include "hpfsname.hxx"
+#include "hpfssa.hxx"
+#include "fnode.hxx"
+#include "orphan.hxx"
+#include "badblk.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( DIRBLK, HOTFIX_SECRUN, UHPFS_EXPORT );
+
+VOID
+DIRBLK::Construct (
+ )
+
+{
+ _Drive = NULL;
+ _pdb = NULL;
+}
+
+UHPFS_EXPORT
+DIRBLK::~DIRBLK(
+ )
+{
+ Destroy();
+}
+
+
+UHPFS_EXPORT
+BOOLEAN
+DIRBLK::Initialize(
+ IN PLOG_IO_DP_DRIVE Drive,
+ IN PHOTFIXLIST HotfixList,
+ IN LBN Lbn
+ )
+/*++
+
+Routine Description:
+
+ Initialize the DIRBLK object to refer to a particular LBN on
+ a particular drive.
+
+Arguments:
+
+ Drive -- drive on which the dirblk resides
+ HotfixList -- hotfix list for that drive
+ Lbn -- lbn of the dirblk
+
+Return Value:
+
+ TRUE on successful completion
+
+--*/
+{
+ Destroy();
+
+ _Drive = Drive;
+
+ if( !_mem.Initialize() ||
+ !HOTFIX_SECRUN::Initialize( &(_mem), Drive, HotfixList,
+ Lbn, SectorsPerDirblk ) ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ _pdb = (DIRBLKD*)GetBuf();
+
+ if( _pdb == NULL ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ _IsModified = FALSE;
+ return TRUE;
+}
+
+
+VOID
+DIRBLK::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Clean up a DIRBLK to prepare it for destruction or
+ reinitialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ // unreferenced parameters
+ (void) this;
+}
+
+
+BOOLEAN
+DIRBLK::CreateRoot(
+ IN LBN FnodeLbn
+ )
+/*++
+
+Routine Desription:
+
+ Create the root dirblk.
+
+Arguements:
+
+ FnodeLbn -- supplies the LBN of the root FNode.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ DIRENTD* pded;
+ ULONG HpfsTime;
+
+ // Check that construction was successful.
+ if (!_pdb)
+ {
+ perrstk->push(ERR_DB_PARAMETER, QueryClassId());
+ return FALSE;
+ }
+
+ // Set signature.
+ _pdb->sig = DirblkSignature;
+
+ // Set Change bit to indicate that this is the top most directory.
+ _pdb->culChange = 1;
+
+ // Set the lbn of the parent directory (or fnode for top most).
+ _pdb->lbnParent = FnodeLbn;
+
+ // Set the lbn of this dir block.
+ _pdb->lbnThisDir = QueryStartLbn();
+
+ // Point the first directory entry to the end of the header.
+ pded = GetFirstEntry();
+
+ // Do the special ".." entry for the directory.
+ pded->cchThisEntry = (sizeof(DIRENTD) + 2 + 3) & ~3;
+ pded->fFlags = DF_SPEC;
+ pded->fAttr = ATTR_DIRECTORY;
+ pded->cchFSize = 5;
+ pded->lbnFnode = FnodeLbn;
+
+ IFS_SYSTEM::QueryHpfsTime( &HpfsTime );
+
+ pded->timLastMod = pded->timLastAccess =
+ pded->timCreate = HpfsTime;
+
+ pded->ulEALen = 0;
+ pded->fFlex = 0;
+ pded->bCodePage = 0;
+ pded->cchName = 2;
+ pded->bName[0] = 1;
+ pded->bName[1] = 1;
+
+ // Do the end of directory entry.
+ pded = (DIRENTD*) ((BYTE*) pded + pded->cchThisEntry);
+ pded->cchThisEntry = sizeof(DIRENTD);
+ pded->fFlags = DF_END;
+ pded->fAttr = 0;
+ pded->lbnFnode = 0;
+ pded->cchFSize = 0;
+ pded->bCodePage = 0;
+ pded->cchName = 1;
+ pded->bName[0] = 0xff;
+
+ // Compute offset to next free space.
+ pded = (DIRENTD*) ((BYTE*) pded + pded->cchThisEntry);
+ _pdb->offulFirstFree = (BYTE*) pded - (BYTE*) _pdb;
+
+ return TRUE;
+}
+
+
+
+VERIFY_RETURN_CODE
+DIRBLK::VerifyAndFix(
+ IN PHPFS_SA SuperArea,
+ IN PDEFERRED_ACTIONS_LIST DeferredActions,
+ IN PHPFS_PATH CurrentPath,
+ IN OUT PHPFS_NAME PreviousName,
+ IN LBN ExpectedParentLbn,
+ IN LBN ParentFnodeLbn,
+ IN ULONG CurrentDepth,
+ IN OUT PULONG LeafDepth,
+ IN PMESSAGE Message,
+ OUT PBOOLEAN ErrorsDetected,
+ IN BOOLEAN UpdateAllowed,
+ IN BOOLEAN Verbose,
+ IN PHPFS_ORPHANS OrphansList
+ )
+/*++
+
+Routine Description:
+
+ Verify the validity of a Dirblk.
+
+Arguments:
+
+ SuperArea -- supplies the superarea for the volume
+ being verified.
+ DeferredActions -- supplies the deferred actions list for this
+ pass of Chkdsk
+ CurrentPath -- Current Path to this directory (NULL if
+ recovering orphans)
+ ExpectedParentLbn -- Supplies the LBN of this DIRBLK's parent
+ ParentFnodeLbn -- supplies the LBN of the directory's FNode
+ CurrentDepth -- supplies the depth into the tree of this block
+ LeafDepth -- supplies the greatest depth seen so far in the tree;
+ receives the greatest depth in this subtree if
+ that is greater than incoming value.
+ Message -- supplies an outlet for messages
+ *ErrorsDetected -- receives TRUE if an error is detected which does
+ generate a message
+ UpdateAllowed -- supplies a flag indicating whether corrections
+ should be written to disk.
+ Verbose -- supplies a flag indicating whether all files
+ encountered should be displayed
+ OrphansList -- supplies a list of previously-recovered orphans that
+ may be claimed as children. (May be NULL).
+
+
+Return Value:
+
+ usual verification code; in addition, *LeafDepth, *PreviousName,
+ and *ErrorsDetected are updated.
+
+Notes:
+
+ Note that ExpectedParentLbn and ParentFnodeLbn should be identical
+ for a root dirblk (i.e. the topmost dirblk in a directory), but
+ lower dirblks in a directory b-tree will have a dirblk for their
+ parent.
+
+ Note also that (during orphan recovery) ExpectedParentLbn and
+ ParentFnodeLbn are zero if the parent is unknown.
+
+ During orphan recovery, OrphansList may point to a list of
+ discovered orphans which may be consulted to find children.
+
+ We determine which phase this is (directory tree validation or
+ orphan recovery) by CurrentPath--it's NULL if and only if we are
+ recovering orphans.
+
+--*/
+{
+
+ DIRBLK ChildDirblk;
+ FNODE ChildFnode;
+ HPFS_NAME CurrentName;
+
+ ULONG OffsetOfFirstFree;
+ PDIRENTD pde;
+ BOOLEAN IsLeaf;
+ BOOLEAN IsBadlyOrdered = FALSE;
+ LBN ChildLbn;
+ VERIFY_RETURN_CODE erc;
+ ULONG FileSize;
+ ULONG EaSize;
+ ULONG CorrectLength;
+
+
+ // Check that the sectors of this Dirblk are not crosslinked;
+ // read the Dirblk, check the signature, and mark the sectors
+ // as in use.
+
+ if( !SuperArea->GetBitmap()->IsFree( QueryStartLbn(),
+ SectorsPerDirblk,
+ TRUE ) ) {
+
+ // The Dirblk is cross-linked.
+ //
+ DebugPrintf( "Crosslinked Dirblk at lbn %lx\n", QueryStartLbn() );
+ return VERIFY_STRUCTURE_INVALID;
+ }
+
+ if( !Read() ) {
+
+ // The Dirblk is unreadable.
+ SuperArea->GetBitmap()->SetAllocated( QueryStartLbn(),
+ SectorsPerDirblk );
+
+ SuperArea->GetBadBlockList()->
+ AddRun( QueryStartLbn(), SectorsPerDirblk );
+
+ DebugPrintf( "Unreadable Dirblk at lbn %lx\n", QueryStartLbn() );
+ return VERIFY_STRUCTURE_INVALID;
+ }
+
+
+ if( !ChildFnode.Initialize( _Drive, 0 ) ||
+ !ChildDirblk.Initialize( _Drive,
+ SuperArea->GetHotfixList(),
+ 0 ) ) {
+
+ return VERIFY_INSUFFICIENT_RESOURCES;
+ }
+
+
+ if( _pdb->sig != DirblkSignature ) {
+
+ // This is not a Dirblk.
+ return VERIFY_STRUCTURE_INVALID;
+ }
+
+ SuperArea->GetBitmap()->SetAllocated( QueryStartLbn(),
+ SectorsPerDirblk );
+
+ // The lowest bit of culChange is the topmost-dirblk flag.
+ // If we do not know the Parent LBN (ie. if we are recovering
+ // this dirblk as a freestanding orphan) we clear this flag;
+ // it will be set appropriately when this dirblk is claimed
+ // by an FNode. Otherwise, it must be set if this is the
+ // topmost dirblk (current depth is zero), and clear if
+ // this is not a topmost dirblk.
+
+ if( ParentFnodeLbn == 0 &&
+ (_pdb->culChange & 1) ) {
+
+ // We are recovering a freestanding orphan dirblk, and the
+ // topmost-dirblk flag is set; clear it. If this is truly
+ // a topmost dirblk, this flag will be set when the dirblk
+ // is claimed by its parent FNode.
+
+ _pdb->culChange &= ~1;
+ MarkModified();
+
+ } else if( CurrentDepth == 0 &&
+ !(_pdb->culChange & 1) ) {
+
+ // This is a root diblk, but does not have the
+ // topmost-dirblk flag set. Fix in place.
+
+ *ErrorsDetected = TRUE;
+
+ DebugPrintf( "Set topmost-dirblk bit for lbn %lx\n", QueryStartLbn() );
+ _pdb->culChange |= 1;
+ MarkModified();
+
+ } else if( CurrentDepth != 0 &&
+ (_pdb->culChange & 1) ) {
+
+ // This is not a root dirblk, but the topmost-dirblk
+ // flag is set. Fix in place.
+
+ *ErrorsDetected = TRUE;
+
+ DebugPrintf( "Reset topmost-dirblk bit for lbn %lx\n", QueryStartLbn() );
+ _pdb->culChange &= ~1;
+ MarkModified();
+ }
+
+ if( _pdb->lbnThisDir != QueryStartLbn() ) {
+
+ // the self-lbn field is incorrect; fix it.
+
+ *ErrorsDetected = TRUE;
+
+ DebugPrintf( "Fixed lbnThisDir for lbn %lx\n", QueryStartLbn() );
+
+ _pdb->lbnThisDir = QueryStartLbn();
+ MarkModified();
+ }
+
+ if( ExpectedParentLbn != 0 &&
+ _pdb->lbnParent != ExpectedParentLbn ) {
+
+ // the parent-lbn field is incorrect; fix it.
+
+ *ErrorsDetected = TRUE;
+
+ DebugPrintf( "Fixed lbnParent for lbn %lx\n", QueryStartLbn() );
+ _pdb->lbnParent = ExpectedParentLbn;
+ MarkModified();
+ }
+
+ // Determine if this is a leaf block. A leaf block is defined
+ // as a Dirblk whose first Dirent does not have a downpointer.
+ // If any Dirent in a leaf block has a downpointer, then the
+ // directory is badly ordered; similarly, if any entry in a non-leaf
+ // dirblk does not have a downpointer, then the directory tree is
+ // badly ordered. Finally, all leaf blocks must occur at the
+ // same depth, or else the directory is badly ordered.
+
+ pde = GetFirstEntry( );
+
+ IsLeaf = (BOOLEAN)(!(pde->fFlags & DF_BTP));
+
+ if( IsLeaf ) {
+
+ if( *LeafDepth == 0 ) {
+
+ // This is the first leaf block; initialize *LeafDepth.
+ *LeafDepth = CurrentDepth;
+
+ } else if ( *LeafDepth != CurrentDepth ) {
+
+ // Leaves occur at different depths--the directory
+ // is badly ordered.
+
+ IsBadlyOrdered = TRUE;
+ }
+ }
+
+ // Check the individual Directory Entries. As we go, we'll
+ // compute the correct value of the offset of the first free
+ // byte in the Dirblk, so we can check it at the end.
+
+ OffsetOfFirstFree = (PBYTE)(&_pdb->bFirst) - (PBYTE)_pdb;
+
+ while( TRUE ) {
+
+ if( OffsetOfFirstFree + pde->cchThisEntry > DIRBLK_SIZE ||
+ pde->cchThisEntry < MinimumDirentSize ||
+ pde->cchThisEntry > MaximumDirentSize ) {
+
+ // Either the alleged length of this dirent would cause
+ // it to overflow the dirblk, or the length is not in
+ // the permissible range of dirent sizes. In either case,
+ // the rest of the dirblk is trash.
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_TRUNCATED_DIRBLK );
+ Message->Display( "" );
+ }
+
+ DebugPrintf( "Truncated dirblk at lbn %lx\n", QueryStartLbn() );
+ Truncate( pde );
+ MarkModified();
+ break;
+ }
+
+ if( pde->fFlags & DF_BTP ) {
+
+ // This entry has a downpointer
+
+ if( IsLeaf ) {
+
+ // This entry has a downpointer, but this dirblk
+ // is a leaf block. The directory is badly ordered.
+ IsBadlyOrdered = TRUE;
+ }
+
+ ChildLbn = BTP( pde );
+
+ // If the child is hotfixed, add the current dirblk
+ // to the deferred actions hotfix resolution list.
+
+ if( SuperArea->GetHotfixList()->
+ IsInList( ChildLbn, SectorsPerDirblk ) ) {
+
+ DeferredActions->AddHotfixedLbn( QueryStartLbn(),
+ DEFER_DIRBLK,
+ DEFER_DIRBLK );
+ }
+
+ // Initialize the child DIRBLK
+
+ ChildDirblk.Relocate( ChildLbn );
+
+ erc = ChildDirblk.VerifyAndFix( SuperArea,
+ DeferredActions,
+ CurrentPath,
+ PreviousName,
+ QueryStartLbn(),
+ ParentFnodeLbn,
+ CurrentDepth + 1,
+ LeafDepth,
+ Message,
+ ErrorsDetected,
+ UpdateAllowed,
+ Verbose,
+ OrphansList );
+
+ if( erc == VERIFY_STRUCTURE_INVALID ) {
+
+ // If we have a list of orphans, look there
+ // for the child. If we can't find it there,
+ // either, then remove the downpointer.
+
+ if( OrphansList == NULL ||
+ !OrphansList->LookupDirblk( ChildLbn,
+ QueryStartLbn(),
+ ParentFnodeLbn,
+ UpdateAllowed ) ) {
+
+ *ErrorsDetected = TRUE;
+
+ DebugPrintf( "Removing bad downpointer in Dirblk at lbn %lx\n",
+ QueryStartLbn() );
+ memmove( (PBYTE)pde+pde->cchThisEntry -
+ DOWNPOINTER_SIZE,
+ (PBYTE)pde+pde->cchThisEntry,
+ (UINT)( DIRBLK_SIZE -
+ OffsetOfFirstFree -
+ pde->cchThisEntry ) );
+
+ pde->cchThisEntry -= DOWNPOINTER_SIZE;
+ pde->fFlags &= ~DF_BTP;
+
+ MarkModified();
+ IsBadlyOrdered = TRUE;
+ }
+
+ } else if ( erc == VERIFY_STRUCTURE_BADLY_ORDERED ) {
+
+ IsBadlyOrdered = TRUE;
+
+ } else if ( erc != VERIFY_STRUCTURE_OK ) {
+
+ return erc;
+ }
+
+ } else if( !IsLeaf ) {
+
+ // This dirent is a leaf, but this is not a
+ // leaf block--the directory is badly ordered.
+ IsBadlyOrdered = TRUE;
+ }
+
+ // Now check the current Directory Entry.
+ if( pde->fFlags & DF_END ) {
+
+ // The current entry is the end entry--we've
+ // seen all the entries in this block.
+ break;
+ }
+
+ // Check that the name of the current entry is lexically
+ // greater than PreviousName
+
+ if( !CurrentName.Initialize( pde->cchName,
+ pde->bName,
+ pde->bCodePage,
+ SuperArea->GetCasemap() ) ) {
+
+ return VERIFY_INSUFFICIENT_RESOURCES;
+ }
+
+ if( PreviousName->IsNull() &&
+ !(pde->fFlags & DF_SPEC ) ) {
+
+ // This is the first entry in the directory (since
+ // there is no previous name), and it is not the
+ // special '..' entry, so the directory is badly-
+ // ordered.
+
+ IsBadlyOrdered = TRUE;
+ }
+
+ if( CurrentName.CompareName( PreviousName ) !=
+ NAME_IS_GREATER_THAN ) {
+
+ IsBadlyOrdered = TRUE;
+ }
+
+
+ // Check the name of the current entry--if it's invalid,
+ // add it to the delete-me list.
+
+ // Enhancement -- if the codepage is invalid, and
+ // the name is codepage-invariant, substitute codepage zero.
+
+ if( !CurrentName.IsValid( SuperArea->GetCasemap(),
+ pde->bCodePage ) ) {
+
+ // The name is bad, so we'll delete this entry. If
+ // we're validating the tree (i.e. if CurrentPath is
+ // non-NULL) we defer deletion; if we're recovering
+ // orphans, we just rip the entry out.
+
+ if( CurrentPath != NULL ) {
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_DELETE_PATH_AND_FILE );
+ Message->Display( "%s%s",
+ CurrentPath->GetString(),
+ CurrentName.GetString() );
+ }
+
+ DeferredActions->AddNameToDelete( CurrentPath,
+ &CurrentName );
+
+ OffsetOfFirstFree += pde->cchThisEntry;
+ pde = NEXT_ENTRY(pde);
+
+ } else {
+
+ memmove( pde,
+ NEXT_ENTRY(pde),
+ (UINT)( DIRBLK_SIZE -
+ OffsetOfFirstFree -
+ pde->cchThisEntry ) );
+ }
+
+ // Swap CurrentName and PreviousName
+ PreviousName->Swap( &CurrentName );
+
+ continue;
+ }
+
+
+ if( pde->cchName == 2 &&
+ pde->bName[0] == '\001' &&
+ pde->bName[1] == '\001' ) {
+
+ // This is the special entry representing '.' and '..'.
+ // We'll check its flags and attributes. The Special
+ // flag must be set; DF_ACL and DF_XACL may also be set,
+ // but the rest of the flags must be clear; the Directory
+ // attribute must be set, and the Archive attribute may
+ // be set, but the other attributes must be clear.
+
+ if( (pde->fFlags & ~(DF_ACL | DF_XACL)) != DF_SPEC ) {
+
+ *ErrorsDetected = TRUE;
+
+ DebugPrintf( "Fixing flags for .. entry in lbn %lx\n",
+ QueryStartLbn() );
+
+ pde->fFlags |= DF_SPEC;
+ pde->fFlags &= (DF_SPEC | DF_ACL | DF_XACL );
+ MarkModified();
+ }
+
+ if( (pde->fAttr & ~ATTR_ARCHIVE) != ATTR_DIRECTORY ) {
+
+ *ErrorsDetected = TRUE;
+
+ DebugPrintf( "Fixing attributes for .. entry in lbn %lx\n",
+ QueryStartLbn() );
+ pde->fAttr |= ATTR_DIRECTORY;
+ pde->fAttr &= (ATTR_DIRECTORY | ATTR_ARCHIVE );
+ MarkModified();
+ }
+
+ // OS/2 PIA requires that the lbnFnode field of the '..'
+ // entry in the root directory point at the root
+ // directory's FNode. (Don't issue a message--just fix it).
+
+ if( CurrentPath != NULL &&
+ CurrentPath->IsRoot() &&
+ pde->lbnFnode != ParentFnodeLbn ) {
+
+ *ErrorsDetected = TRUE;
+
+ DebugPrintf( "Fixing parent fnode LBN for .. entry in lbn %lx\n",
+ QueryStartLbn() );
+ pde->lbnFnode = ParentFnodeLbn;
+ MarkModified();
+ }
+
+ // NT HPFS requires that the special '..' entry
+ // be exactly the right size. If not, set the
+ // name to something invalid and mark the directory
+ // for resorting.
+ //
+ CorrectLength = (( LeafEndEntrySize + 1 ) + 3 ) & ~3;
+
+ if( pde->fFlags & DF_BTP ) {
+
+ CorrectLength += DOWNPOINTER_SIZE;
+ }
+
+ if( pde->cchThisEntry != CorrectLength ) {
+
+ // This entry is bad. Since it is marked as
+ // DF_SPEC, we can eliminate it by sorting.
+ //
+ IsBadlyOrdered = TRUE;
+ }
+
+ // We don't need to check the rest of the fields
+ // for this special entry--move on to the next.
+
+ OffsetOfFirstFree += pde->cchThisEntry;
+ pde = NEXT_ENTRY(pde);
+
+ // Swap CurrentName and PreviousName
+ PreviousName->Swap( &CurrentName );
+
+ continue;
+ }
+
+ // This is an ordinary directory entry--it refers
+ // either to a file or a subdirectory. Check its flags:
+
+ // Check the new-names bit
+ if( CurrentName.IsNewName( SuperArea->GetCasemap(),
+ pde->bCodePage) ) {
+
+ if( !(pde->fAttr & ATTR_NEWNAME) ) {
+
+ // The new-names bit should be set, but isn't.
+ // Fix it in place.
+
+ *ErrorsDetected = TRUE;
+
+ if( CurrentPath != NULL ) {
+
+ DebugPrintf( "UHPFS: Setting new-names bit for %s%s\n",
+ (PCHAR)CurrentPath->GetString(),
+ (PCHAR)CurrentName.GetString() );
+ }
+
+ pde->fAttr |= ATTR_NEWNAME;
+ MarkModified();
+ }
+
+ } else {
+
+ if( pde->fAttr & ATTR_NEWNAME ) {
+
+ // The new-names bit shouldn't be set, but is.
+ // Fix it in place.
+
+ *ErrorsDetected = TRUE;
+
+ if( CurrentPath != NULL ) {
+
+ DebugPrintf( "UHPFS: Resetting new-names bit for %s%s\n",
+ (PCHAR)CurrentPath->GetString(),
+ (PCHAR)CurrentName.GetString() );
+ }
+
+ pde->fAttr &= ~ATTR_NEWNAME;
+ MarkModified();
+ }
+ }
+
+ // If the user requested verbose operation,
+ // display the name
+
+
+ if( Verbose &&
+ CurrentPath != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_PATH_AND_FILE );
+ Message->Display( "%s%s",
+ CurrentPath->GetString(),
+ CurrentName.GetString() );
+ }
+
+ // Verify the FNode
+
+ ChildLbn = SuperArea->GetHotfixList()->
+ GetLbnTranslation( pde->lbnFnode );
+
+ if( pde->lbnFnode != ChildLbn ) {
+
+ // The Fnode has been hotfixed. Resolve the reference.
+
+ SuperArea->GetHotfixList()->
+ ClearHotfix( pde->lbnFnode, SuperArea );
+
+ pde->lbnFnode = ChildLbn;
+ MarkModified();
+ }
+
+ ChildFnode.Relocate( pde->lbnFnode );
+
+ FileSize = pde->cchFSize;
+ EaSize = 0;
+
+ if( CurrentPath != NULL ) {
+
+ if( !CurrentPath->AddLevel( &CurrentName ) ) {
+
+ return VERIFY_INSUFFICIENT_RESOURCES;
+ }
+ }
+
+ erc = ChildFnode.VerifyAndFix( SuperArea,
+ DeferredActions,
+ CurrentPath,
+ ParentFnodeLbn,
+ pde->fAttr & ATTR_DIRECTORY,
+ &FileSize,
+ &EaSize,
+ Message,
+ ErrorsDetected,
+ UpdateAllowed,
+ Verbose,
+ OrphansList );
+
+ if( CurrentPath != NULL ) {
+
+ CurrentPath->StripLevel();
+ }
+
+ if( erc == VERIFY_STRUCTURE_INVALID ) {
+
+ // The FNode is not recoverable--see if it's in
+ // the list of orphans already recovered. If not,
+ // this entry will be deleted.
+
+ if( OrphansList == NULL ||
+ !OrphansList->LookupFnode( pde->lbnFnode,
+ pde->fAttr & ATTR_DIRECTORY,
+ ParentFnodeLbn,
+ &FileSize,
+ &EaSize,
+ UpdateAllowed ) ) {
+
+ // Delete this entry. If we're still validating
+ // the tree, we defer the deletion in order to
+ // preserve the well-orderedness of the dirblk;
+ // if we're recovering orphans, we just wipe
+ // out the entry.
+
+ if( CurrentPath != NULL ) {
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_DELETE_PATH_AND_FILE );
+ Message->Display( "%s%s",
+ CurrentPath->GetString(),
+ CurrentName.GetString() );
+ }
+
+ DeferredActions->AddNameToDelete( CurrentPath,
+ &CurrentName );
+
+ OffsetOfFirstFree += pde->cchThisEntry;
+ pde = NEXT_ENTRY(pde);
+
+ } else {
+
+ memmove( pde,
+ NEXT_ENTRY(pde),
+ (UINT)( DIRBLK_SIZE -
+ OffsetOfFirstFree -
+ pde->cchThisEntry ) );
+ }
+
+ // Swap CurrentName and PreviousName
+ PreviousName->Swap( &CurrentName );
+
+ continue;
+ }
+ }
+
+ // Check the file size and the EA information:
+
+ if( pde->cchFSize != FileSize ) {
+
+ // The Fnode disagrees with the file size; correct
+ // the directory entry.
+
+ *ErrorsDetected = TRUE;
+
+ DebugPrint( "File size error.\n" );
+
+ pde->cchFSize = FileSize;
+ MarkModified();
+ }
+
+ if( pde->ulEALen != EaSize ) {
+
+ // The Fnode disagrees with the size of EAs;
+ // correct the directory entry.
+
+ *ErrorsDetected = TRUE;
+
+ DebugPrint( "EA size error.\n" );
+
+ pde->ulEALen = EaSize;
+ MarkModified();
+ }
+
+ if( ChildFnode.QueryNumberOfNeedEas() != 0 ) {
+
+ if( !(pde->fFlags & DF_NEEDEAS) ) {
+
+ // This entry has need-EAs--correct the flag.
+
+ *ErrorsDetected = TRUE;
+
+ if( CurrentPath != NULL ) {
+
+ DebugPrint( "Setting need-eas bit for " );
+ DebugPrint( (PCHAR)CurrentPath->GetString() );
+ DebugPrint( (PCHAR)CurrentName.GetString() );
+ DebugPrint( "\n" );
+ }
+
+ pde->fFlags |= DF_NEEDEAS;
+ MarkModified();
+ }
+
+ } else {
+
+ if( pde->fFlags & DF_NEEDEAS ) {
+
+ // This entry does not have need-EAs--correct the flag.
+
+ *ErrorsDetected = TRUE;
+
+ if( CurrentPath != NULL ) {
+
+ DebugPrint( "Resetting need-eas bit for " );
+ DebugPrint( (PCHAR)CurrentPath->GetString() );
+ DebugPrint( (PCHAR)CurrentName.GetString() );
+ DebugPrint( "\n" );
+ }
+
+ pde->fFlags &= ~DF_NEEDEAS;
+ MarkModified();
+ }
+ }
+
+
+ // Swap CurrentName and PreviousName
+ PreviousName->Swap( &CurrentName );
+
+ // Move on to the next entry
+ OffsetOfFirstFree += pde->cchThisEntry;
+
+ pde = NEXT_ENTRY(pde);
+ }
+
+ // pde now points (or, should point) at the 'End' entry
+ VerifyAndFixEndEntry( pde, ErrorsDetected );
+
+ if( ( IsLeaf && (pde->fFlags & DF_BTP)) ||
+ (!IsLeaf && !(pde->fFlags & DF_BTP)) ) {
+
+ IsBadlyOrdered = TRUE;
+ }
+
+ OffsetOfFirstFree += pde->cchThisEntry;
+
+ // Now that we've checked all the directory entries, we can
+ // check the offset of the first free byte.
+
+ if( _pdb->offulFirstFree != OffsetOfFirstFree ) {
+
+ // The offset of the first free byte in the dirblk is
+ // incorrect; fix it.
+
+ *ErrorsDetected = TRUE;
+
+ DebugPrintf( "Fixing offulFirstFree for lbn %lx\n", QueryStartLbn() );
+ _pdb->offulFirstFree = OffsetOfFirstFree;
+ MarkModified();
+ }
+
+
+ // If we've modified the Dirblk and have permission to
+ // update the volume, write the Dirblk.
+
+ if ( IsModified() && UpdateAllowed ) {
+
+ Write();
+ }
+
+ // If the only entry in the dirblk is the 'END' entry,
+ // then the directory is badly ordered.
+
+ pde = GetFirstEntry();
+
+ if( pde->fFlags & DF_END ) {
+
+ IsBadlyOrdered = TRUE;
+ }
+
+ DeferredActions->StatDirblk();
+
+ return( IsBadlyOrdered ? VERIFY_STRUCTURE_BADLY_ORDERED :
+ VERIFY_STRUCTURE_OK );
+}
+
+
+VOID
+DIRBLK::Truncate(
+ IN PDIRENTD pde
+ )
+/*++
+
+Routine Description:
+
+ Truncate the DIRBLK by slamming an 'End' entry in at pde
+
+Arguments:
+
+ pde -- points to a DIRENT that will become the end dirent
+
+--*/
+{
+
+ if( DIRBLK_SIZE - ((PBYTE)pde - (PBYTE)_pdb) < MinimumDirentSize ) {
+
+ // There isn't enough room, so we won't do it.
+ return;
+ }
+
+ memset( (PBYTE)pde, '\0', MinimumDirentSize );
+
+ pde->cchThisEntry = MinimumDirentSize;
+ pde->fFlags = DF_END;
+
+ pde->bCodePage = 0;
+ pde->cchName = 1;
+ pde->bName[0] = 0xff;
+}
+
+
+VOID
+DIRBLK::VerifyAndFixEndEntry(
+ PDIRENTD pde,
+ PBOOLEAN ErrorsDetected
+ )
+/*++
+
+Routine Description:
+
+ verify that the end entry of the dirblk is correct
+
+Arguments:
+
+ pde -- pointer to end entry to check
+
+--*/
+{
+
+ USHORT Length;
+
+ Length = MinimumDirentSize;
+
+ if( pde->fFlags & DF_BTP ) {
+
+ Length += DOWNPOINTER_SIZE;
+ }
+
+ if( pde->cchThisEntry != Length ) {
+
+ *ErrorsDetected = TRUE;
+ pde->cchThisEntry = Length;
+ MarkModified();
+ }
+
+ if( !(pde->fFlags & DF_END) ) {
+
+ *ErrorsDetected = TRUE;
+ pde->fFlags |= DF_END;
+ MarkModified();
+ }
+
+ if( pde->bCodePage != 0 ) {
+
+ *ErrorsDetected = TRUE;
+ pde->bCodePage = 0;
+ MarkModified();
+ }
+
+ if( pde->cchName != 1 ) {
+
+ *ErrorsDetected = TRUE;
+ pde->cchName = 1;
+ MarkModified();
+ }
+
+ if( pde->bName[0] != 0xff ) {
+
+ *ErrorsDetected = TRUE;
+ pde->bName[0] = 0xff;
+ MarkModified();
+ }
+}
+
+
+BOOLEAN
+DIRBLK::FindName(
+ IN HPFS_NAME* Name,
+ OUT PDIRENTD* DirentFound,
+ IN CASEMAP* Casemap
+ )
+/*++
+
+Routine Description:
+
+ Searches the DIRBLK for the first entry with a name that is
+ lexically greater than or equal to the argument Name.
+
+Arguments:
+
+ Name -- Supplies the name for which to search
+
+ DirentFound -- receives the address of the first dirent in the
+ block which has a name lexically greater than or
+ equal to Name. *DirentFound is set to NULL if an
+ error occurs.
+
+ Casemap -- Supplies the volume's case-mapping table
+
+Return Value:
+
+ TRUE if Name was found in the block, FALSE if it was not.
+
+--*/
+{
+ PDIRENTD pde;
+
+ if( Name == NULL ) {
+
+ *DirentFound = NULL;
+ return FALSE;
+ }
+
+ pde = GetFirstEntry();
+
+ while( !(pde->fFlags & DF_END) ) {
+
+ switch( Name->CompareName( pde->cchName,
+ pde->bName,
+ pde->bCodePage,
+ Casemap ) ) {
+
+ case NAME_IS_LESS_THAN :
+
+ *DirentFound = pde;
+ return FALSE;
+
+ case NAME_IS_EQUAL_TO :
+
+ *DirentFound = pde;
+ return TRUE;
+
+ case NAME_IS_GREATER_THAN :
+
+ pde = NEXT_ENTRY( pde );
+ break;
+ }
+ }
+
+ // All the entries in the block are lexically less than
+ // Name. Return the end entry.
+
+ *DirentFound = pde;
+ return FALSE;
+}
+
+
+
+BOOLEAN
+DIRBLK::FindAndResolveHotfix(
+ IN PHPFS_SA SuperArea,
+ IN DEFERRED_SECTOR_TYPE ChildSectorType
+ )
+/*++
+
+Routine Description:
+
+ Find all immediate children of this dirblk that are
+ hotfixed and resolve those references.
+
+Arguments:
+
+ SuperaArea -- supplies superarea for the volume
+ ChildSectorType -- supplies a flag indicating what sort of
+ child is hotfixed
+
+Return Value:
+
+ TRUE on successful completion
+
+Notes:
+
+ This function is invoked by the deferred-actions list, when
+ it tries to clean up the deferred hotfix references. The
+ only sort of child sector type that is deferred for DIRBLKs
+ is child DIRBLKs.
+
+--*/
+{
+ DIRBLK Child;
+ PDIRENTD pde;
+ LBN ChildLbn, NewLbn;
+ ULONG i;
+
+ DebugAssert( ChildSectorType = DEFER_DIRBLK );
+
+ if( !Read() ) {
+
+ return FALSE;
+ }
+
+ // If this is not a DIRBLK, then we just assume everything is OK
+
+ if( _pdb->sig != DirblkSignature ) {
+
+ return TRUE;
+ }
+
+ pde = GetFirstEntry();
+
+ do {
+
+ if( (pde->fFlags & DF_BTP) &&
+ (ChildLbn = BTP(pde) != 0) &&
+ SuperArea->GetHotfixList()->
+ IsInList( ChildLbn, SectorsPerDirblk ) ) {
+
+
+ // The child DIRBLK is hotfixed, so we need to
+ // relocate it.
+
+ if( !Child.Initialize( _Drive,
+ SuperArea->GetHotfixList(),
+ ChildLbn ) ||
+ !Child.Read() ) {
+
+ return FALSE;
+ }
+
+ if( (NewLbn = SuperArea->GetBitmap()->AllocateDirblk() ) == 0 ) {
+
+ // can't allocate a new dirblk.
+
+ return FALSE;
+ }
+
+ Child.Relocate( NewLbn );
+
+ if( !Child.Write() ) {
+
+ // unable to relocate child.
+ return FALSE;
+ }
+
+ Child.FixupChildren();
+
+ BTP(pde) = NewLbn;
+
+ SuperArea->GetBitmap()->SetFree( ChildLbn, SectorsPerDirblk );
+
+ for( i = 0; i < SectorsPerDirblk; i++ ) {
+
+ SuperArea->GetHotfixList()->
+ ClearHotfix( ChildLbn + i, SuperArea );
+ }
+ }
+
+ pde = NEXT_ENTRY(pde);
+
+ } while( !(pde->fFlags & DF_END) );
+
+ Write();
+ return TRUE;
+}
+
+
+
+BOOLEAN
+DIRBLK::InsertDirent(
+ IN DIRENTD* NewDirent,
+ OUT BOOLEAN* ErrorOccurred,
+ IN PCASEMAP Casemap,
+ IN PUCHAR InsertPoint,
+ IN ULONG NewDownPointer
+ )
+/*++
+
+Routine Description:
+
+ Insert a directory entry into the block
+
+Arguments:
+
+ NewDirent -- the directory entry to insert
+
+ ErrorOccurred -- receives TRUE if an error occurs
+
+ InsertPoint -- where in the dirblk to insert it, if known.
+
+ NewDownPointer -- new down pointer for the entry _after_
+ the inserted entry. (This is non-zero
+ if the inserted entry is being promoted from
+ a split child dirblk.)
+
+ Casemap -- Case-mapping table for the volume
+
+Return Value:
+
+ If the entry was successfully inserted, returns TRUE and
+ *ErrorOccurred is undefined (i.e. its value does not matter)
+
+ If the entry does not fit, but no error occurred, returns
+ FALSE and *ErrorOccurred is set to FALSE.
+
+ If an error occurs returns FALSE and *ErrorOccurred is
+ set to TRUE.
+
+--*/
+{
+
+ if( _pdb->offulFirstFree + NewDirent->cchThisEntry > DIRBLK_SIZE ) {
+
+ *ErrorOccurred = FALSE;
+ return FALSE;
+ }
+
+ if( InsertPoint == NULL ) {
+
+ // We have to determine where this entry should be
+ // inserted in the block:
+
+ HPFS_NAME Name;
+ PDIRENTD DirentInsertPoint;
+
+ if( !Name.Initialize( NewDirent->cchName,
+ NewDirent->bName,
+ NewDirent->bCodePage,
+ Casemap ) ) {
+
+ *ErrorOccurred = TRUE;
+ return FALSE;
+ }
+
+ FindName( &Name, &DirentInsertPoint, Casemap );
+
+ InsertPoint = (PUCHAR)DirentInsertPoint;
+ }
+
+ // Before we diddle with the dirblk, set the next entry's
+ // new down-pointer, if necessary:
+
+ if( NewDownPointer != 0 ) {
+
+ BTP( (PDIRENTD)(InsertPoint) ) = NewDownPointer;
+ }
+
+ // Make room for the new entry, and then copy it in.
+
+ memmove( InsertPoint + NewDirent->cchThisEntry,
+ InsertPoint,
+ (UINT)( _pdb->offulFirstFree -
+ (InsertPoint - (PBYTE)_pdb) ) );
+
+ memmove( InsertPoint,
+ NewDirent,
+ NewDirent->cchThisEntry );
+
+ _pdb->offulFirstFree += NewDirent->cchThisEntry;
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+DIRBLK::IsEmptyDirectory(
+ )
+/*++
+
+Routine Description:
+
+ This method determines whether the dirblk represents an empty
+ directory.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the dirblk represents an empty directory; otherwise,
+ false.
+
+Notes:
+
+ This method should only be called on the root dirblk of
+ a directory.
+
+ The only entries allowed in an empty directory are:
+
+ -- the special '..' entry, with no downpointer.
+ -- the END entry, with no downpointer.
+
+--*/
+{
+ PDIRENTD CurrentEntry;
+
+ CurrentEntry = GetFirstEntry();
+
+ // If the first entry is the special entry for '..', and
+ // has no downpointer, ignore it.
+ //
+ if( CurrentEntry->fFlags & DF_SPEC &&
+ !(CurrentEntry->fFlags & DF_BTP) ) {
+
+ CurrentEntry = NEXT_ENTRY( CurrentEntry );
+ }
+
+ // The only remaining entry allowed is an END entry
+ // with no downpointer.
+
+ if( CurrentEntry->fFlags & DF_END &&
+ !(CurrentEntry->fFlags & DF_BTP) ) {
+
+ // This dirblk satisfies the definition of an
+ // empty directory.
+ //
+ return TRUE;
+
+ } else {
+
+ // This dirblk does not satisfy the definition
+ // of an empty directory.
+ //
+ return FALSE;
+ }
+}
+
+
+PDIRENTD
+DIRBLK::FindSplitPoint(
+ )
+/*++
+
+Routine Description:
+
+ Finds a point at which the DIRBLK may be split.
+
+Return Value:
+
+ A pointer into the dirblk's data at the place where it
+ should be split. Returns NULL if some error occurs.
+
+Notes:
+
+ The split point may not be the first entry in the block; nor
+ may it be the end entry.
+
+--*/
+{
+
+ PDIRENTD Current, Previous;
+ ULONG CurrentOffset, Halfway;
+
+
+ Previous = GetFirstEntry();
+ Current = NEXT_ENTRY(Previous);
+
+ CurrentOffset = (PBYTE)Current - (PBYTE)_pdb;
+
+ Halfway = _pdb->offulFirstFree/2;
+
+ while( CurrentOffset < Halfway &&
+ !(Current->fFlags & DF_END) ) {
+
+ CurrentOffset += Current->cchThisEntry;
+ Previous = Current;
+ Current = NEXT_ENTRY(Previous);
+ }
+
+ if( Current->fFlags & DF_END ) {
+
+ // We got to the end entry, but are not allowed to return it.
+ // If the previous entry isn't the first in the block, we can
+ // return it instead. If it is, return error.
+
+ if( Previous != GetFirstEntry() ) {
+
+ return Previous;
+
+ } else {
+
+ return NULL;
+ }
+ }
+
+ return Current;
+}
+
+
+
+PDIRENTD
+DIRBLK::EndEntry(
+ )
+/*++
+
+Routine Description:
+
+ Find the end entry in a Dirblk
+
+Return Value:
+
+ a pointer to the end entry; NULL to indicate error
+
+Notes:
+
+ This doesn't rely on offulFirstFree, but scans through
+ the dirblk looking for an END entry.
+
+
+--*/
+{
+ PDIRENTD CurrentEntry;
+ ULONG CurrentOffset;
+
+ CurrentOffset = DIRBLK_HEADER_SIZE;
+ CurrentEntry = GetFirstEntry();
+
+ while( CurrentOffset < DIRBLK_SIZE &&
+ !(CurrentEntry->fFlags & DF_END) ) {
+
+ if( CurrentEntry->cchThisEntry == 0 ) {
+
+ // This dirblk is screwed up.
+ return NULL;
+ }
+
+ CurrentEntry = NEXT_ENTRY( CurrentEntry );
+ }
+
+ if( CurrentEntry->fFlags & DF_END ) {
+
+ return CurrentEntry;
+
+ } else {
+
+ // Didn't find an END entry
+ return NULL;
+ }
+
+}
+
+
+
+
+PDIRENTD
+DIRBLK::LastNonEndEntry(
+ )
+/*++
+
+Routine Description:
+
+ Find the last entry in the dirblk which is not an end entry.
+
+Return Value:
+
+ The entry which precedes the END entry. If the first entry
+ in the block is an END entry (i.e. the block is empty),
+ return NULL.
+
+Notes:
+
+ The dirblk must be well-formed, but it may be empty.
+
+--*/
+{
+ PDIRENTD CurrentEntry;
+ PDIRENTD PreviousEntry;
+
+ PreviousEntry = NULL;
+ CurrentEntry = GetFirstEntry();
+
+ while( !(CurrentEntry->fFlags & DF_END) ) {
+
+ PreviousEntry = CurrentEntry;
+ CurrentEntry = NEXT_ENTRY( CurrentEntry );
+ }
+
+ return PreviousEntry;
+}
+
+
+
+VOID
+DIRBLK::SetParents(
+ LBN ParentLbn,
+ LBN ParentFnodeLbn
+ )
+/*++
+
+Routine Description:
+
+ Sets the dirblk's parent pointers
+
+Arguments:
+
+ ParentLbn -- LBN of the immediate parent
+ ParentFnodeLbn -- LBN of the directory's FNode
+
+Notes:
+
+ ParentFnodeLbn is not propagated to the dirblk's children.
+
+ ParentFnodeLbn may be zero, in which case it is not used.
+
+--*/
+{
+ DIRBLK ChildDirblk;
+ FNODE ChildFnode;
+
+ if( ParentLbn != 0 ) {
+
+ _pdb->lbnParent = ParentLbn;
+ }
+
+ if( ParentFnodeLbn == 0 ) {
+
+ return;
+ }
+
+ if( ParentLbn == ParentFnodeLbn ) {
+
+ // This is a topmost dirblk.
+
+ _pdb->culChange |= 1;
+
+ } else {
+
+ // This is not a topmost dirblk
+
+ _pdb->culChange &= ~1;
+ }
+}
+
+
+
+
+VOID
+DIRBLK::FixupChildren(
+ PHOTFIXLIST HotfixList
+ )
+/*++
+
+Routine Description:
+
+ Reads a dirblk's child dirblks and sets their parent lbn field
+ to refer to the parent dirblk.
+
+Arguments:
+
+ HotfixList -- optionally supplies the volume hotfix list
+
+
+
+--*/
+{
+
+ DIRBLK Child;
+ PDIRENTD CurrentEntry;
+
+ if( !Child.Initialize( _Drive, HotfixList, 0 ) ) {
+
+ return;
+ }
+
+
+ CurrentEntry = GetFirstEntry();
+
+ while ( TRUE ) {
+
+ if( CurrentEntry->fFlags & DF_BTP ) {
+
+ // This entry has a down pointer--we need to
+ // read the child and fix its parent pointer.
+
+ Child.Relocate( BTP( CurrentEntry ) );
+
+ if( Child.Read() &&
+ Child.IsDirblk() ) {
+
+ // set the child's parent pointer
+ Child.SetParents( QueryStartLbn(), 0 );
+ Child.Write();
+ }
+ }
+
+
+ if( CurrentEntry->fFlags & DF_END ) {
+
+ break;
+ }
+
+
+ CurrentEntry = NEXT_ENTRY( CurrentEntry );
+ }
+}
+
+
+
+BOOLEAN
+DIRBLK::TakeCensusAndClear(
+ IN OUT PHPFS_BITMAP VolumeBitmap,
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap,
+ IN OUT PHPFS_CENSUS Census
+ )
+/*++
+
+Routine Description:
+
+ This method takes the census at this Dirblk.
+
+Arguments:
+
+ VolumeBitmap -- Supplies the volume bitmap.
+ HpfsOnlyBitmap -- Supplies the bitmap for sectors containing
+ file-system structures.
+ Census -- Supplies the census object.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+ If this method fails, the reason for failure may be determined
+ using Census->QueryError.
+
+--*/
+{
+ DIRBLK ChildDirblk;
+ FNODE ChildFnode;
+ PDIRENTD CurrentEntry = NULL;
+ ULONG EntryOffset;
+
+ // Initialize the objects I'll use to process the children:
+ //
+ if( !ChildDirblk.Initialize( _Drive, NULL, 0 ) ||
+ !ChildFnode.Initialize( _Drive, 0 ) ) {
+
+ Census->SetError( HPFS_CENSUS_INSUFFICIENT_MEMORY );
+ return FALSE;
+ }
+
+ // Record this Dirblk in the census object and in the
+ // HPFS-structures bitmap:
+ //
+ Census->AddDirblk();
+ HpfsOnlyBitmap->SetAllocated( QueryStartLbn(), SectorsPerDirblk );
+
+
+ // Traverse the entries in the block:
+
+ do {
+
+ if( CurrentEntry == NULL ) {
+ CurrentEntry = GetFirstEntry();
+ } else {
+ CurrentEntry = NEXT_ENTRY( CurrentEntry );
+ }
+
+ // Did the current-entry pointer fall off the end? First, check
+ // that this entry's cchThisEntry field fits in the dirblk, and
+ // then check that the entire length of the entry (based on that
+ // field) also fits.
+ //
+ EntryOffset = QueryEntryOffset( CurrentEntry );
+
+ if( EntryOffset + sizeof(USHORT) > DIRBLK_SIZE ||
+ EntryOffset + CurrentEntry->cchThisEntry > DIRBLK_SIZE ||
+ CurrentEntry->cchThisEntry == 0 ) {
+
+ // It fell off the end or has zero length--either way,
+ // unacceptable.
+ //
+ Census->SetError( HPFS_CENSUS_CORRUPT_VOLUME );
+ return FALSE;
+ }
+
+ if( CurrentEntry->fFlags & DF_BTP ) {
+
+ // This entry has a down pointer--recurse
+ // into the child dirblk.
+ //
+ ChildDirblk.Relocate( BTP( CurrentEntry ) );
+
+ if( !ChildDirblk.Read() ||
+ !ChildDirblk.IsDirblk() ) {
+
+ Census->SetError( HPFS_CENSUS_CORRUPT_VOLUME );
+ return FALSE;
+ }
+
+ if( !ChildDirblk.TakeCensusAndClear( VolumeBitmap,
+ HpfsOnlyBitmap,
+ Census ) ) {
+ return FALSE;
+ }
+ }
+
+ if( !(CurrentEntry->fFlags & (DF_END | DF_SPEC)) ) {
+
+ // This is an ordinary entry--neither an END entry
+ // nor the special '..' entry. Process the FNode.
+ //
+ ChildFnode.Relocate( CurrentEntry->lbnFnode );
+
+ if( !ChildFnode.Read() ||
+ !ChildFnode.IsFnode() ) {
+
+ Census->SetError( HPFS_CENSUS_CORRUPT_VOLUME );
+ return FALSE;
+ }
+
+ if( !ChildFnode.
+ TakeCensusAndClear( CurrentEntry->fAttr & ATTR_DIRECTORY,
+ VolumeBitmap,
+ HpfsOnlyBitmap,
+ Census ) ) {
+ return FALSE;
+ }
+ }
+
+ } while( !(CurrentEntry->fFlags & DF_END) );
+
+ return TRUE;
+}
diff --git a/private/utils/uhpfs/src/dircache.cxx b/private/utils/uhpfs/src/dircache.cxx
new file mode 100644
index 000000000..3c5db49df
--- /dev/null
+++ b/private/utils/uhpfs/src/dircache.cxx
@@ -0,0 +1,585 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ dircache.cxx
+
+Abstract:
+
+ HPFS DIRBLK cache to support the HPFS Directory Tree object
+
+Author:
+
+ Bill McJohn (billmc) 16-Jan-1989
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "dirblk.hxx"
+#include "dircache.hxx"
+#include "error.hxx"
+
+
+DEFINE_CONSTRUCTOR( DIRBLK_CACHE_ELEMENT, OBJECT );
+
+
+DIRBLK_CACHE_ELEMENT::~DIRBLK_CACHE_ELEMENT(
+ )
+{
+ Destroy();
+}
+
+
+VOID
+DIRBLK_CACHE_ELEMENT::Construct (
+ )
+/*++
+
+Routine Description:
+
+ This method is the helper routine for object construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ _IsUnused = TRUE;
+ _HoldCount = 0;
+}
+
+
+
+VOID
+DIRBLK_CACHE_ELEMENT::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This method cleans up a dirblk-cache element. Note that the dirblk
+ is not written--if it is dirty, any changes are lost.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ _IsUnused = TRUE;
+ _HoldCount = 0;
+}
+
+
+
+
+BOOLEAN
+DIRBLK_CACHE_ELEMENT::Initialize(
+ PLOG_IO_DP_DRIVE Drive,
+ PHOTFIXLIST HotfixList
+ )
+/*++
+
+Routine Description:
+
+ Initialize a dirblk cache element.
+
+Arguments:
+
+ Drive -- supplies drive on which the dirblk resides.
+ HotfixList -- supplies the volume hotfix list.
+
+Return Value:
+
+ TRUE on successful completion
+
+Notes:
+
+ The dirblk owned by the cache element is initialized with an LBN of
+ zero; however, no I/O will be performed on it until its lbn has
+ been set (using Relocate()) to some more useful value.
+
+--*/
+{
+
+ if( !_Dirblk.Initialize( Drive, HotfixList, 0 ) ) {
+
+ _Dirblk.MarkUnmodified();
+ perrstk->push( ERR_NOT_INIT, QueryClassId() );
+ Destroy();
+
+ return FALSE;
+ }
+
+ _IsUnused = TRUE;
+ _HoldCount = 0;
+ return TRUE;
+}
+
+
+
+BOOLEAN
+DIRBLK_CACHE_ELEMENT::Read(
+ LBN DirblkLbn,
+ BOOLEAN OmitRead
+ )
+/*++
+
+Routine Description:
+
+ Read a dirblk into the cache.
+
+Arguments:
+
+ DirblkLbn -- supplies the LBN of the desired dirblk
+ OmitRead -- supplies a flag indicating, if TRUE, that the
+ the dirblk need not be read (i.e. it is being created,
+ so whatever's on disk doesn't matter).
+
+Return Value:
+
+ TRUE on successful completion
+
+Notes:
+
+ There is no corresponding Write function. Writes occur implicitly
+ when a cache element is re-used or deleted.
+
+--*/
+{
+
+ DebugAssert( _HoldCount == 0 );
+
+ if( !_IsUnused && _Dirblk.IsModified() ) {
+
+ _Dirblk.Write();
+ }
+
+ _Dirblk.Relocate( DirblkLbn );
+
+ if( !OmitRead && !_Dirblk.Read() ) {
+
+ _Dirblk.MarkUnmodified();
+ _Dirblk.Relocate( 0 );
+ perrstk->push( ERR_NOT_READ, QueryClassId() );
+ _IsUnused = TRUE;
+ return FALSE;
+ }
+
+ _IsUnused = FALSE;
+ _HoldCount = 0;
+ return TRUE;
+}
+
+
+
+BOOLEAN
+DIRBLK_CACHE_ELEMENT::Flush(
+ )
+/*++
+
+Routine Description:
+
+ Writes the cached dirblk if it is dirty. Then marks the cache
+ element as unused.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if successful
+
+--*/
+{
+
+ if( !_IsUnused && _Dirblk.IsModified() ) {
+
+
+ _Dirblk.Write();
+ }
+
+ _IsUnused = TRUE;
+ return TRUE;
+}
+
+
+
+LBN
+DIRBLK_CACHE_ELEMENT::QueryLbn(
+ )
+/*++
+
+Routine Description:
+
+ This method determines the LBN of the dirblk associated with
+ this cache element.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ return( _IsUnused ? 0 : _Dirblk.QueryStartLbn() );
+}
+
+
+
+
+PDIRBLK
+DIRBLK_CACHE_ELEMENT::GetDirblk(
+ )
+/*++
+
+Routine Description:
+
+ This method returns the dirblk associated with this cache element.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The dirblk associated with this cache element.
+
+--*/
+{
+ return &_Dirblk;
+}
+
+
+
+VOID
+DIRBLK_CACHE_ELEMENT::Hold(
+ )
+/*++
+
+Routine Description:
+
+ This method puts a hold on the cache element, to guarantee that the
+ associated dirblk will be kept in place until the hold is released.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _HoldCount += 1;
+}
+
+
+
+VOID
+DIRBLK_CACHE_ELEMENT::Unhold(
+ )
+/*++
+
+Routine Description:
+
+ This method releases a hold on the cache element.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DebugAssert( _HoldCount != 0 );
+ _HoldCount -= 1;
+}
+
+
+
+BOOLEAN
+DIRBLK_CACHE_ELEMENT::IsFree(
+ )
+/*++
+
+Routine Description:
+
+ Determine whether a cache element is available for use
+
+Return Value:
+
+ TRUE if the element may be used
+
+Notes:
+
+ An element is free if it is not in use, or if its hold count
+ is zero.
+
+--*/
+{
+ return ( _IsUnused || _HoldCount == 0 );
+}
+
+
+
+
+VOID
+DIRBLK_CACHE_ELEMENT::MarkModified(
+ )
+/*++
+
+Routine Description:
+
+ This method marks the dirblk associated with this cache element
+ as having been modified.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _Dirblk.MarkModified();
+}
+
+
+
+
+DEFINE_CONSTRUCTOR( DIRBLK_CACHE, OBJECT );
+
+
+DIRBLK_CACHE::~DIRBLK_CACHE(
+ )
+{
+ Destroy();
+}
+
+
+
+VOID
+DIRBLK_CACHE::Construct(
+ )
+/*++
+
+Routine Description:
+
+ This method is the helper routine for object construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _NextVictim = 0;
+}
+
+
+
+VOID
+DIRBLK_CACHE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Cleans up a dirblk cache object. Note that it does not flush the
+ cache--any cached changes are lost.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _NextVictim = 0;
+}
+
+
+
+BOOLEAN
+DIRBLK_CACHE::Initialize(
+ PLOG_IO_DP_DRIVE Drive,
+ PHOTFIXLIST HotfixList
+ )
+/*++
+
+Routine Description:
+
+ Initialize the directory cache object.
+
+Arguments:
+
+ Drive -- supplies the drive with which the cache is associated
+ HotfixList -- supplies the volume hotfix list
+
+Return Value:
+
+ TRUE on successful completion
+
+--*/
+{
+
+ for ( _NextVictim = 0; _NextVictim < DirblkCacheSize; _NextVictim++ ) {
+
+ if( !_Cache[_NextVictim].Initialize( Drive, HotfixList ) ) {
+
+ perrstk->push( ERR_NOT_INIT, QueryClassId() );
+ Destroy();
+ return FALSE;
+ }
+ }
+
+
+ _NextVictim = 0;
+ return TRUE;
+}
+
+
+
+BOOLEAN
+DIRBLK_CACHE::Flush(
+ )
+/*++
+
+Routine Description:
+
+ Flushes cache, writing all dirty dirblks to disk. The cache is
+ also invalidated.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ TRUE on successful completion
+
+--*/
+{
+
+ ULONG i;
+
+ for( i = 0; i < DirblkCacheSize; i++ ) {
+
+ _Cache[i].Flush();
+ }
+
+ return TRUE;
+}
+
+
+
+PDIRBLK_CACHE_ELEMENT
+DIRBLK_CACHE::GetCachedDirblk(
+ LBN DirblkLbn,
+ BOOLEAN OmitRead
+ )
+/*++
+
+Routine Description:
+
+ This method locates a dirblk in the cache. If the dirblk is not already
+ in the cache, it will find a free cache element and read the dirblk
+ into it.
+
+Arguments:
+
+ DirblkLbn -- supplies the LBN of the desired dirblk.
+ OmitRead -- supplies a flag indicating, if TRUE, that the
+ the dirblk need not be read (i.e. it is being created,
+ so whatever's on disk doesn't matter).
+
+Return Value:
+
+ Pointer to cache element that holds the desired dirblk, or NULL
+ to indicate failure.
+
+--*/
+{
+ ULONG i, StartingPoint;
+
+ // First, spin through the cache looking for the dirblk we want.
+
+ DebugAssert( DirblkLbn != 0 );
+
+ for( i = 0; i < DirblkCacheSize; i++ ) {
+
+ if( _Cache[i].QueryLbn() == DirblkLbn ) {
+
+ return &(_Cache[i]);
+ }
+ }
+
+ // Didn't find it in the cache, have to find a free cache element
+ // and get the dirblk we want into it.
+
+ StartingPoint = _NextVictim;
+
+ do {
+
+ if( _Cache[_NextVictim].IsFree() ) {
+
+ // Found one!
+ i = _NextVictim;
+ _NextVictim = (_NextVictim + 1) % DirblkCacheSize;
+
+ if( _Cache[i].Read( DirblkLbn, OmitRead ) ) {
+
+ return &(_Cache[i]);
+
+ } else {
+
+ return NULL;
+ }
+ }
+
+ _NextVictim = (_NextVictim + 1) % DirblkCacheSize;
+
+ } while( _NextVictim != StartingPoint );
+
+
+ // Couldn't find a free cache element.
+ return NULL;
+}
diff --git a/private/utils/uhpfs/src/dirmap.cxx b/private/utils/uhpfs/src/dirmap.cxx
new file mode 100644
index 000000000..32a65f53d
--- /dev/null
+++ b/private/utils/uhpfs/src/dirmap.cxx
@@ -0,0 +1,662 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ dirmap.cxx
+
+Abstract:
+
+ This module contains member function definitions for HPFS_DIR_BITMAP,
+ which models the dirblk-band bitmap of an HPFS volume.
+
+ Note that this object is normally accessed only through the HPFS_BITMAP
+ object, which coordinates it with the HPFS_MAIN_BITMAP.
+
+Author:
+
+ Bill McJohn (billmc) 16-Jan-1989
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "bitvect.hxx"
+#include "bmind.hxx"
+#include "dirblk.hxx"
+#include "dirmap.hxx"
+#include "error.hxx"
+
+
+DEFINE_CONSTRUCTOR( HPFS_DIR_BITMAP, HOTFIX_SECRUN );
+
+VOID
+HPFS_DIR_BITMAP::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Constructor for the HPFS Directory Bitmap object. Sets the
+ private data to safe values (i.e. NULL or zero)
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ _Drive = NULL;
+ _HotfixList = NULL;
+
+ _NumberOfDirblks = 0;
+ _idb = 0;
+ _FirstDirblkLbn = 0;
+
+ _OrphanScanBlock = NULL;
+ _OrphanIndex = 0;
+}
+
+
+HPFS_DIR_BITMAP::~HPFS_DIR_BITMAP(
+ )
+{
+ Destroy();
+}
+
+
+BOOLEAN
+HPFS_DIR_BITMAP::Initialize(
+ PLOG_IO_DP_DRIVE Drive,
+ PHOTFIXLIST HotfixList,
+ LBN StartLbn,
+ SECTORCOUNT SectorsInBand,
+ LBN FirstDirblkLbn
+ )
+/*++
+
+Routine Description:
+
+ Initializes the HPFS Directory Bitmap object.
+
+Arguments:
+
+ Drive -- supplies the drive on which the bitmap resides.
+ HotfixList -- supplies the volume hotfix list
+ (may be NULL -- see note).
+ StartLbn -- supplies the first lbn of the bitmap.
+ DirblksInBand -- supplies the number of DIRBLKS in the directory band.
+ FirstDirblkLbn -- supplies the LBN of the first Dirblk in the band.
+
+Returns:
+
+ TRUE is successful; FALSE if failure
+
+Notes:
+
+ If a NULL HotfixList is passed in, then I/O will be performed without
+ checking for hotfixes. (This may be suitable for Format?)
+
+--*/
+{
+ ULONG SectorSize;
+ PT* BitmapBuffer;
+
+ if( Drive == NULL ||
+ SectorsInBand == 0 ||
+ (SectorSize = Drive->QuerySectorSize()) == 0 ) {
+
+ return FALSE;
+ }
+
+ Destroy();
+
+ _Drive = Drive;
+ _HotfixList = HotfixList;
+ _NumberOfDirblks = SectorsInBand/SectorsPerDirblk;
+ _FirstDirblkLbn = FirstDirblkLbn;
+ _DirblkMapLbn = StartLbn;
+
+ if( !_Mem.Initialize() ||
+ !HOTFIX_SECRUN::Initialize( &_Mem,
+ Drive,
+ HotfixList,
+ StartLbn,
+ SectorsPerBitmap ) ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ BitmapBuffer = (PT*)GetBuf();
+
+ if( BitmapBuffer == NULL ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ if( ! _Bitmap.Initialize( 8 * DIRMAP_SIZE, RESET, BitmapBuffer )) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ // Mark all the DIRBLKS free, but bits beyond those corresponding
+ // to DIRBLKS in the band are marked as in use.
+ _Bitmap.SetBit(0, _NumberOfDirblks);
+ _Bitmap.ResetBit(_NumberOfDirblks, DIRMAP_SIZE - _NumberOfDirblks);
+
+
+ return TRUE;
+}
+
+
+VOID
+HPFS_DIR_BITMAP::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Cleans up HPFS Directory Bitmap object and restores it to
+ a blank (and harmless) state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ DELETE( _OrphanScanBlock );
+ _OrphanScanBlock = NULL;
+
+ _Drive = NULL;
+ _HotfixList = NULL;
+
+ _NumberOfDirblks = 0;
+ _idb = 0;
+ _FirstDirblkLbn = 0;
+
+ _OrphanIndex = 0;
+}
+
+
+
+BOOLEAN
+HPFS_DIR_BITMAP::Create(
+ )
+/*++
+
+Routine Description:
+
+ This method creates (ie. Formats) an HPFS Directory Bitmap.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE on successful completion
+--*/
+{
+
+ // Mark all the DIRBLKS free, but bits beyond those corresponding
+ // to DIRBLKS in the band are marked as in use.
+ _Bitmap.SetBit(0, _NumberOfDirblks);
+ _Bitmap.ResetBit(_NumberOfDirblks, DIRMAP_SIZE - _NumberOfDirblks);
+
+ return TRUE;
+}
+
+
+
+
+LBN
+HPFS_DIR_BITMAP::GetDirblkLbn(
+ BOOLEAN Backward
+ )
+/*++
+
+Routine Description:
+
+ Find a free DIRBLK and allocate it.
+
+Arguments:
+
+ Backward -- supplies a flag which, if TRUE, indicates this method
+ should start its search at the end of the dirblk band
+ and work its way backwards. (Otherwise, it starts at
+ the beginning and goes forwards).
+
+Return Value:
+
+ lbn of dirblk allocated, or zero for failure.
+
+--*/
+{
+ ULONG i;
+ LBN lbn;
+
+ // Loop until a free dir blk is found or the list is exhausted.
+
+ if( Backward ) {
+
+ // Search backwards from the end of the dirblk band
+
+ i = _NumberOfDirblks;
+
+ while( i-- && !_Bitmap.IsBitSet(i) ) {
+
+ // Null loop
+ }
+
+ // If list was exhausted.
+ if( i > _NumberOfDirblks ||
+ !_Bitmap.IsBitSet(i) ) {
+
+ perrstk->push(ERR_DM_FULL, QueryClassId());
+ return 0;
+ }
+
+ // Found it
+ _idb = i;
+
+ } else {
+
+ // Search forward from current search point
+
+ for (i = 0;
+ i < _NumberOfDirblks && !_Bitmap.IsBitSet((_idb + i)%_NumberOfDirblks);
+ i++)
+ ;
+
+ // If list was exhausted.
+ if (i == _NumberOfDirblks) {
+
+ perrstk->push(ERR_DM_FULL, QueryClassId());
+ return 0;
+ }
+
+ // Compute exact index of free dir block.
+ _idb = (_idb + i)%_NumberOfDirblks;
+ }
+
+ // Set the dir block as used.
+ _Bitmap.ResetBit(_idb);
+
+ // Compute the lbn of the newly allocated dir blk.
+ lbn = _FirstDirblkLbn + _idb*SectorsPerDirblk;
+
+ // Increment the index.
+ _idb++;
+
+ return lbn;
+}
+
+
+BOOLEAN
+HPFS_DIR_BITMAP::SetAllocated(
+ LBN Lbn,
+ SECTORCOUNT BlockCount
+ )
+/*++
+
+Routine Description:
+
+ Marks a run of DIRBLKs as used in the bitmap
+
+Arguments:
+
+ Lbn -- supplies the first lbn of the DIRBLK to mark as used
+ BlockCount -- supplies the number of dirblks to mark as used
+
+Returns:
+
+ TRUE on successful completion
+
+--*/
+{
+
+ ULONG i;
+
+ // Compute offset into bit vector.
+ i = (Lbn - _FirstDirblkLbn)/SectorsPerDirblk;
+
+ // Check that parameter is in range.
+
+ if ( i >= _NumberOfDirblks ) {
+
+ perrstk->push(ERR_DM_PARAMETER, QueryClassId());
+ return FALSE;
+ }
+
+ // Reset bits in bit map.
+
+ _Bitmap.ResetBit(i, BlockCount);
+
+ return TRUE;
+}
+
+
+BOOLEAN
+HPFS_DIR_BITMAP::SetFree(
+ LBN Lbn,
+ SECTORCOUNT BlockCount
+ )
+/*++
+
+Routine Description:
+
+ Marks a run of DIRBLKs as free in the bitmap
+
+Arguments:
+
+ Lbn -- supplies the first lbn of the DIRBLK to free
+ BlockCount -- supplies the number of dirblks to free
+
+Returns:
+
+ TRUE on successful completion
+
+--*/
+{
+
+ ULONG i;
+
+ // Compute offset into bit vector.
+ i = (Lbn - _FirstDirblkLbn)/SectorsPerDirblk;
+
+ // Check parameter is in range.
+
+ if (i >= _NumberOfDirblks) {
+
+ perrstk->push(ERR_DM_PARAMETER, QueryClassId());
+ return FALSE;
+ }
+
+ // Reset bit in bit map.
+ _Bitmap.SetBit(i, BlockCount);
+
+ return TRUE;
+}
+
+
+BOOLEAN
+HPFS_DIR_BITMAP::IsFree(
+ LBN Lbn
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method determines whether a particular Dirblk is marked as
+ free in the bitmap.
+
+Arguments:
+
+ Lbn -- supplies the starting LBN of the dirblk in question.
+
+Return Value:
+
+ TRUE if the given Lbn is in range (i.e. refers to an block in the
+ dirblk band) and is marked as free in the bitmap.
+
+--*/
+{
+
+ ULONG i;
+
+ // Compute offset into bit vector.
+ i = (Lbn - _FirstDirblkLbn)/SectorsPerDirblk;
+
+ // Check that parameter is in range.
+
+ if (i >= _NumberOfDirblks) {
+
+ perrstk->push(ERR_DM_PARAMETER, QueryClassId());
+ return FALSE;
+ }
+
+ // Check bit vector for result.
+ return _Bitmap.IsBitSet(i);
+
+}
+
+
+BOOLEAN
+HPFS_DIR_BITMAP::QueryNextOrphan(
+ OUT PLBN NextOrphan,
+ IN OUT PBOOLEAN AllocationErrors
+ )
+/*++
+
+Routine Description:
+
+ Returns the next potential orphan sector. A sector is a
+ potential orphan if it is marked as in-use in the on-disk
+ bitmap but as free in the in-memory bitmap.
+
+Arguments:
+
+ NextOrphan -- receives the next potential orphan identified
+ AllocationErrors -- receives TRUE if an allocation error (ie. a block
+ marked as free on disk but in use in in-memory bitmap)
+ is found.
+
+Return Value:
+
+ TRUE if successful--
+ *NextOrphan is set to the next potential orphan LBN, or zero
+ if there are no more
+
+ FALSE if error
+
+--*/
+{
+ LBN PotentialOrphan;
+ ULONG OrphanByteOffset, BytesInMap, i;
+ PBYTE ByteInMemory, ByteFromDisk;
+
+ if( _OrphanScanBlock == NULL ) {
+
+ // This is the first call to QueryNextOrphan, so
+ // we have some initialization to do. We need to
+ // set up a HOTFIX_SECRUN to read the on-disk bitmap,
+ // and then feed it to a bitvector object.
+
+ if( !_OrphanScanMem.Initialize() ||
+ (_OrphanScanBlock = NEW HOTFIX_SECRUN) == NULL ||
+ !_OrphanScanBlock->Initialize( &_OrphanScanMem,
+ _Drive,
+ _HotfixList,
+ _DirblkMapLbn,
+ SectorsPerBitmap ) ) {
+
+ return FALSE;
+ }
+
+ if( ! _OrphanBitmap.Initialize( BITMAP_SIZE * 8, RESET,
+ ( PPT )(_OrphanScanBlock->GetBuf( )))) {
+
+ // Couldn't initialize the bitvector
+ return FALSE;
+ }
+
+ if( !_OrphanScanBlock->Read() ) {
+
+ return FALSE;
+ }
+
+ _OrphanIndex = 0;
+ }
+
+ BytesInMap = (_NumberOfDirblks % 8) ? (_NumberOfDirblks / 8 + 1 ) :
+ (_NumberOfDirblks / 8);
+
+ OrphanByteOffset = _OrphanIndex / 8;
+
+ ByteInMemory = (PBYTE)(_Mem.GetBuf()) + OrphanByteOffset;
+ ByteFromDisk = (PBYTE)(_OrphanScanMem.GetBuf()) + OrphanByteOffset;
+
+ while( _OrphanIndex < _NumberOfDirblks &&
+ OrphanByteOffset < BytesInMap ) {
+
+ if( *ByteInMemory != *ByteFromDisk ) {
+
+ // There is a discrepancy between the on-disk map and
+ // the in-memory map.
+
+ // Check for allocation errors, if we haven't already found one:
+
+ if( !*AllocationErrors ) {
+
+ for( i = 0; i < 8; i++ ) {
+
+ PotentialOrphan = OrphanByteOffset * 8 + i;
+
+ if( PotentialOrphan < _NumberOfDirblks &&
+ !_Bitmap.IsBitSet( PotentialOrphan ) &&
+ _OrphanBitmap.IsBitSet( PotentialOrphan ) ) {
+
+ // This bit is in range, and it's in-use in memory
+ // and free on disk--the definition of an allocation
+ // error.
+
+ *AllocationErrors = TRUE;
+ }
+ }
+ }
+
+
+ // Check for orphans. Don't return anything we've already
+ // returned (ie. LBNs less than or equal to _OrphanIndex).
+
+ for( i = 0; i < 8; i++ ) {
+
+ PotentialOrphan = OrphanByteOffset * 8 + i;
+
+ if( PotentialOrphan > _OrphanIndex &&
+ PotentialOrphan < _NumberOfDirblks &&
+ _Bitmap.IsBitSet( PotentialOrphan ) &&
+ !_OrphanBitmap.IsBitSet( PotentialOrphan ) ) {
+
+ // This bit is in range, and it's free in memory
+ // and in-use on disk--it's an orphan.
+
+ _OrphanIndex = PotentialOrphan;
+ *NextOrphan = _FirstDirblkLbn +
+ PotentialOrphan * SectorsPerDirblk;
+ return TRUE;
+ }
+ }
+ }
+
+ OrphanByteOffset += 1;
+ ByteInMemory += 1;
+ ByteFromDisk += 1;
+ }
+
+
+ // No more orphans.
+ _OrphanIndex = _NumberOfDirblks;
+ *NextOrphan = 0;
+ return TRUE;
+}
+
+
+BOOLEAN
+HPFS_DIR_BITMAP::AndWithDisk(
+ )
+/*++
+
+Routine Description:
+
+ This method ANDs the in-memory bitmap with the on-disk bitmap. This
+ operation has the effect of marking as in-use any Dirblk which either
+ bitmap claims is in use.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE on successful completion
+
+--*/
+{
+ HOTFIX_SECRUN Secrun;
+ HMEM Mem;
+ BITVECTOR DiskBits;
+ ULONG i;
+
+ if( !Mem.Initialize() ||
+ !Secrun.Initialize( &Mem,
+ _Drive,
+ _HotfixList,
+ _DirblkMapLbn,
+ SectorsPerBitmap ) ||
+ !Secrun.Read() ||
+ !DiskBits.Initialize( BITMAP_SIZE * 8,
+ RESET,
+ (PPT)(Mem.GetBuf()) ) ) {
+
+ return FALSE;
+ }
+
+
+ for( i = 0; i < _NumberOfDirblks; i++ ) {
+
+ if( !DiskBits.IsBitSet(i) ) {
+
+ SetAllocated(i, 1);
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+ULONG
+HPFS_DIR_BITMAP::QueryFreeDirblks(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method determines the number of free dirblks in the dirblk
+ bitmap.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of free dirblks in this bitmap.
+
+--*/
+{
+ return _Bitmap.QueryCountSet();
+}
diff --git a/private/utils/uhpfs/src/dirtree.cxx b/private/utils/uhpfs/src/dirtree.cxx
new file mode 100644
index 000000000..2124f5f53
--- /dev/null
+++ b/private/utils/uhpfs/src/dirtree.cxx
@@ -0,0 +1,2381 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ dirtree.cxx
+
+Abstract:
+
+ This module contains the member function definitions for the
+ HPFS_DIRECTORY_TREE object, which models a dirblk tree on an
+ HPFS volume.
+
+ This object uses a DIRBLK_CACHE object to manage reading and
+ writing dirblks, which saves it from having to decide the correct
+ time to read and write dirblks.
+
+ The HPFS_DIRECTORY_TREE is able to perform transformations on the
+ directory; however, it does not update the associated FNode. This
+ responsibility remains in the hands of the client.
+
+Author:
+
+ Bill McJohn (billmc) 16-Jan-1989
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "dirblk.hxx"
+#include "bitmap.hxx"
+#include "cpinfo.hxx"
+#include "dircache.hxx"
+#include "error.hxx"
+#include "hpfsname.hxx"
+#include "hpfssa.hxx"
+#include "dirtree.hxx"
+#include "fnode.hxx"
+#include "badblk.hxx"
+#include "hotfix.hxx"
+
+DEFINE_CONSTRUCTOR( HPFS_DIRECTORY_TREE, OBJECT );
+
+
+HPFS_DIRECTORY_TREE::~HPFS_DIRECTORY_TREE(
+ )
+{
+ Destroy();
+}
+
+
+VOID
+HPFS_DIRECTORY_TREE::Construct (
+ )
+
+{
+ _SuperArea = NULL;
+ _Cache = NULL;
+ _RootDirblkLbn = 0;
+ _FnodeLbn = 0;
+}
+
+
+VOID
+HPFS_DIRECTORY_TREE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This method cleans up the object in preparation for destruction
+ or reinitialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _SuperArea = NULL;
+ _Cache = NULL;
+ _RootDirblkLbn = 0;
+ _FnodeLbn = 0;
+}
+
+
+
+BOOLEAN
+HPFS_DIRECTORY_TREE::Initialize(
+ IN PHPFS_SA SuperArea,
+ IN PDIRBLK_CACHE Cache,
+ IN LBN RootDirblkLbn,
+ IN LBN FnodeLbn
+ )
+/*++
+
+Routine Description:
+
+ Initializes the directory tree object
+
+Arguments:
+
+ SuperArea -- supplies the Superarea of the volume on
+ which the directory resides.
+ Cache -- supplies the DIRBLK_CACHE for the drive on which
+ the directory resides. The directory tree will use
+ this cache for all its I/O.
+ RootDirblkLbn -- supplies the LBN of the root DIRBLK of the directory.
+ FnodeLbn -- supplies the LBN of the directory's FNode.
+
+Return Value:
+
+ TRUE on successful completion
+
+--*/
+{
+ Destroy();
+
+ if( Cache == NULL || RootDirblkLbn == 0 || FnodeLbn == 0 ) {
+
+ perrstk->push( ERR_NOT_INIT, QueryClassId() );
+ return FALSE;
+ }
+
+ _SuperArea = SuperArea;
+ _Cache = Cache;
+ _RootDirblkLbn = RootDirblkLbn;
+ _FnodeLbn = FnodeLbn;
+
+ return TRUE;
+}
+
+
+BOOLEAN
+HPFS_DIRECTORY_TREE::InsertIntoDirblk(
+ PDIRENTD NewDirent,
+ PDIRBLK Dirblk,
+ PDIRBLK_CACHE_ELEMENT Header,
+ PBYTE InsertionPoint,
+ LBN NewDownPointer
+ )
+/*++
+
+Routine Description:
+
+ Insert a directory entry at a known place in the tree.
+ If necessary, it will split the dirblk and promote one
+ of its dirents into the parent, or split the root dirblk
+ and make a new root.
+
+Arguments:
+
+ NewDirent -- supplies the new directory entry.
+ Dirblk -- supplies the Dirblk into which the entry
+ will be inserted
+ Cache -- supplies the directory block cache header
+ for the dirblk
+ InsertionPoint -- supplies the point in the dirblk to insert the
+ dirent. (NULL if not known)
+ NewDownPointer -- supplies the downpointer for the entry _after_
+ the one we insert (0 if none)
+
+Return Value:
+
+ TRUE on successful completion
+
+Notes:
+
+ This is a private method, and does no parameter validation
+
+--*/
+{
+ HPFS_NAME NewName;
+ PDIRENTD SplitPoint, DirentToPromote;
+ PDIRBLK NewDirblk, FixupDirblk;
+ PDIRBLK_CACHE_ELEMENT NewHeader, FixupHeader;
+ PBYTE CopyPoint;
+ BOOLEAN Error = FALSE;
+ LBN NewDirblkLbn, OldDownPointer;
+ ULONG SplitOffset, BytesToCopy;
+
+ if( Dirblk->InsertDirent( NewDirent,
+ &Error,
+ _SuperArea->GetCasemap(),
+ InsertionPoint,
+ NewDownPointer ) ) {
+
+ // It fit--we're all done.
+ Dirblk->MarkModified();
+ return TRUE;
+
+ } else if (!Error) {
+
+ // The dirent doesn't fit, so we have to split the
+ // dirblk.
+
+ // Allocate a buffer for the promoted directory entry
+
+ if( (DirentToPromote = (PDIRENTD)MALLOC( MaximumDirentSize )) ==
+ NULL ) {
+
+ perrstk->push( ERR_NOT_INIT, QueryClassId() );
+ return FALSE;
+ }
+
+
+ // Allocate a new DIRBLK and get it into the cache
+ // (without actually reading it).
+
+ if((NewDirblkLbn = _SuperArea->GetBitmap()->AllocateDirblk()) == 0) {
+
+ FREE( DirentToPromote );
+ return FALSE;
+ }
+
+ // Find the split point in TargetDirblk, and split
+ // it by copying the split-point dirent to the promotion
+ // buffer, and all the entries after it (including the
+ // end entry) to the new DIRBLK. We remember the promoted
+ // entry's old B-Tree pointer, if it had one; its new
+ // pointer is the DIRBLK we're splitting. We create
+ // an END entry over the split point (where the promoted
+ // entry used to be); its down pointer is the promoted
+ // entry's old down pointer.
+
+ Header->Hold();
+
+ if( (SplitPoint = Dirblk->FindSplitPoint()) == NULL ||
+ (NewHeader = _Cache->GetCachedDirblk( NewDirblkLbn,
+ TRUE )) == NULL ||
+ (NewDirblk = NewHeader->GetDirblk()) == NULL ) {
+
+ FREE( DirentToPromote );
+ Header->Unhold();
+ return FALSE;
+ }
+
+ if( !NewName.Initialize( NewDirent->cchName,
+ NewDirent->bName,
+ NewDirent->bCodePage,
+ _SuperArea->GetCasemap() ) ) {
+
+ FREE( DirentToPromote );
+ Header->Unhold();
+ return FALSE;
+ }
+
+ NewHeader->Hold();
+
+ SplitOffset = Dirblk->QueryEntryOffset( SplitPoint );
+
+ // Set up the promotion buffer, which will get passed
+ // recursively to InsertIntoDirblk.
+
+ memmove( (PBYTE)DirentToPromote,
+ (PBYTE)SplitPoint,
+ (size_t)SplitPoint->cchThisEntry );
+
+ if( DirentToPromote->fFlags & DF_BTP ) {
+
+ // The promoted entry has a downpointer. Remember
+ // the old value for later, and set the down pointer
+ // to the dirblk we split.
+
+ OldDownPointer = BTP( DirentToPromote );
+ BTP( DirentToPromote ) = Dirblk->QueryStartLbn();
+
+ } else {
+
+ // The promoted entry has no downpointer, so we need to
+ // make it bigger in order to hold the down pointer.
+ OldDownPointer = 0;
+ DirentToPromote->fFlags |= DF_BTP;
+ DirentToPromote->cchThisEntry += DOWNPOINTER_SIZE;
+ BTP( DirentToPromote ) = Dirblk->QueryStartLbn();
+ }
+
+ // Set up the new dirblk--copy all the dirents beyond
+ // the promoted dirent into the new dirblk, and fill in
+ // its header fields.
+
+ CopyPoint = (PBYTE)(NEXT_ENTRY( SplitPoint ));
+ BytesToCopy = Dirblk->_pdb->offulFirstFree -
+ (SplitOffset + SplitPoint->cchThisEntry);
+
+ memmove( &NewDirblk->_pdb->bFirst, CopyPoint, (size_t)BytesToCopy );
+
+ NewDirblk->_pdb->sig = DirblkSignature;
+ NewDirblk->_pdb->offulFirstFree = DIRBLK_HEADER_SIZE + BytesToCopy;
+ NewDirblk->_pdb->culChange = 0;
+ NewDirblk->_pdb->lbnParent = Dirblk->_pdb->lbnParent;
+ NewDirblk->_pdb->lbnThisDir = NewDirblkLbn;
+
+ // Fix up the old dirblk by putting an END entry over the
+ // promoted dirent and updating the offset of the first free
+ // byte.
+
+ memset( (PBYTE)SplitPoint, '\0', LeafEndEntrySize );
+
+ SplitPoint->cchThisEntry = LeafEndEntrySize;
+ SplitPoint->fFlags = DF_END;
+ SplitPoint->cchName = 1;
+ SplitPoint->bCodePage = 0;
+ SplitPoint->bName[0] = 0xff;
+
+ if( OldDownPointer != 0 ) {
+
+ // The promoted entry had a downpointer, which must be
+ // transferred to this new END entry. We have to make
+ // the END entry bigger, to accommodate the downpointer.
+
+ SplitPoint->cchThisEntry += DOWNPOINTER_SIZE;
+ BTP( SplitPoint ) = OldDownPointer;
+ }
+
+ Dirblk->_pdb->offulFirstFree = SplitOffset +
+ SplitPoint->cchThisEntry;
+
+ // Next, we insert the promoted entry into the appropriate
+ // DIRBLK. It will fit (or a very bad internal error has
+ // occurred).
+
+ if( NewName.CompareName( DirentToPromote->cchName,
+ DirentToPromote->bName,
+ DirentToPromote->bCodePage,
+ _SuperArea->GetCasemap() ) ==
+ NAME_IS_LESS_THAN ) {
+
+ // the name of the new dirent is less than the name in
+ // the promoted dirent, so the new entry goes in the
+ // original dirblk
+
+ Dirblk->InsertDirent( NewDirent, &Error, _SuperArea->GetCasemap(),
+ NULL, NewDownPointer );
+
+ } else {
+
+ // the name of the new dirent is equal to or greater
+ // than (and it can't be equal to) the name of the
+ // promoted entry, so the new entry goes in the new dirblk.
+
+ NewDirblk->InsertDirent( NewDirent, &Error, _SuperArea->GetCasemap(),
+ NULL, NewDownPointer );
+ }
+
+
+ if( NewDownPointer != 0 ) {
+
+ // The dirents we moved into the new dirblk have
+ // downpointers, so we need to fix up their children
+ // to point at their new parent. Since we're done
+ // with SplitPoint, we'll use it to traverse the
+ // new dirblk.
+
+ SplitPoint = NewDirblk->GetFirstEntry();
+
+ do {
+
+ FixupHeader = _Cache->GetCachedDirblk( BTP( SplitPoint ) );
+
+ if( FixupHeader != NULL &&
+ (FixupDirblk = FixupHeader->GetDirblk()) != NULL ) {
+
+ FixupDirblk->_pdb->lbnParent = NewDirblkLbn;
+ FixupDirblk->MarkModified();
+ }
+
+ SplitPoint = NEXT_ENTRY( SplitPoint );
+
+ } while ( !(SplitPoint->fFlags & DF_END) );
+ }
+
+ // Finally, we insert the promoted entry into the parent.
+
+ if( Dirblk->_pdb->culChange & 1 ) {
+
+ // We split the root of the directory tree, so we need
+ // to create a new root. The new root will be the parent
+ // of both the split dirblk and the new dirblk, so we
+ // need to hang on to them until the new root is created.
+ // We also need to reset the is-topmost bit in the
+ // split dirblk.
+
+ if( !CreateNewRoot( DirentToPromote, NewDirblkLbn ) ) {
+
+ NewHeader->Unhold();
+ Header->Unhold();
+ return FALSE;
+ }
+
+ NewHeader->GetDirblk()->_pdb->lbnParent = _RootDirblkLbn;
+ Dirblk->_pdb->lbnParent = _RootDirblkLbn;
+ Dirblk->_pdb->culChange &= ~1;
+
+ NewHeader->MarkModified();
+ Header->MarkModified();
+
+ NewHeader->Unhold();
+ Header->Unhold();
+
+ return TRUE;
+
+ } else {
+
+ // OK, we just need to promote DirentToPromote into
+ // the parent, which means we're done with the split
+ // dirblk and the new dirblk.
+
+ NewHeader->MarkModified();
+ Header->MarkModified();
+
+ NewHeader->Unhold();
+ Header->Unhold();
+
+ Header = _Cache->GetCachedDirblk( Dirblk->_pdb->lbnParent );
+
+ if( Header == NULL ) {
+
+ return FALSE;
+ }
+
+ return ( InsertIntoDirblk( DirentToPromote,
+ Header->GetDirblk(),
+ Header,
+ NULL,
+ NewDirblkLbn ) );
+ }
+
+ } else {
+
+ // An error occurred during processing--bail out
+ return FALSE;
+ }
+
+}
+
+
+
+BOOLEAN
+HPFS_DIRECTORY_TREE::CreateNewRoot(
+ PDIRENTD DirentToPromote,
+ LBN EndDownPointer
+ )
+/*++
+
+Routine Description:
+
+ Creates a new root dirblk for the directory tree
+
+Arguments:
+
+ FirstDirent -- supplies the first directory entry to put into
+ the dirblk
+ EndDownPointer -- supplies a B-Tree Downpointer for the new root
+ dirblk's END entry
+
+Notes:
+
+ This method updates the Directory Tree object's private
+ data item _RootDirblkLbn, but it does not update the FNode
+ to point at the new root. The caller (of Insert or Adjust)
+ is responsible for updating the FNode.
+
+--*/
+{
+ PDIRBLK Dirblk;
+ PDIRENTD Dirent;
+ LBN NewRootLbn;
+ PDIRBLK_CACHE_ELEMENT Header;
+
+ NewRootLbn = _SuperArea->GetBitmap()->AllocateDirblk();
+ DebugAssert( NewRootLbn != 0 );
+
+ Header = _Cache->GetCachedDirblk( NewRootLbn, TRUE );
+
+ if( Header == NULL ) {
+
+ return FALSE;
+ }
+
+
+ Dirblk = Header->GetDirblk();
+
+ memset( (PBYTE)Dirblk->_pdb, 0, DIRBLK_SIZE );
+
+ Dirblk->_pdb->sig = DirblkSignature;
+ Dirblk->_pdb->offulFirstFree = DIRBLK_HEADER_SIZE +
+ DirentToPromote->cchThisEntry +
+ LeafEndEntrySize +
+ DOWNPOINTER_SIZE;
+ Dirblk->_pdb->culChange = 1;
+ Dirblk->_pdb->lbnParent = _FnodeLbn;
+ Dirblk->_pdb->lbnThisDir = NewRootLbn;
+
+ Dirent = Dirblk->GetFirstEntry();
+
+ memmove( (PBYTE) Dirent,
+ (PBYTE) DirentToPromote,
+ (size_t)DirentToPromote->cchThisEntry );
+
+ Dirent = NEXT_ENTRY(Dirent);
+
+ Dirent->cchThisEntry = LeafEndEntrySize + DOWNPOINTER_SIZE;
+ Dirent->fFlags = DF_END | DF_BTP;
+ Dirent->cchName = 1;
+ Dirent->bCodePage = 0;
+ Dirent->bName[0] = 0xff;
+ BTP(Dirent) = EndDownPointer;
+
+ Header->MarkModified();
+
+ _RootDirblkLbn = NewRootLbn;
+
+ return TRUE;
+}
+
+
+
+
+BOOLEAN
+HPFS_DIRECTORY_TREE::Insert(
+ IN PDIRENTD NewDirent
+ )
+/*++
+
+Routine Description:
+
+ Inserts a directory entry into the tree. It determines
+ which DIRBLK the entry should go into, and then calls
+ the private method InsertIntoDirblk.
+
+Arguments:
+
+ NewDirent -- supplies the directory entry to insert.
+
+Return Value:
+
+ TRUE on successful completion.
+
+Notes:
+
+ NewDirent must point at a valid dirent; it must be a leaf (i.e.
+ have no B-Tree downpointer).
+
+--*/
+{
+ HPFS_NAME Name;
+ PDIRENTD TargetDirent;
+ PDIRBLK TargetDirblk;
+ PDIRBLK_CACHE_ELEMENT TargetHeader;
+
+
+ if( !Name.Initialize( NewDirent->cchName,
+ NewDirent->bName,
+ NewDirent->bCodePage,
+ _SuperArea->GetCasemap() ) ) {
+
+ return FALSE;
+ }
+
+
+ if( FindName( &Name, &TargetDirent, &TargetDirblk, &TargetHeader ) ) {
+
+ // This name is already in the tree; the dirent
+ // cannot be inserted.
+
+ return FALSE;
+
+ } else if ( TargetDirent != NULL ) {
+
+ // Before we try anything else, make sure that the drive has enough
+ // free space to support splitting dirblks.
+
+ if( !_SuperArea->GetBitmap()->
+ CheckAvailableDirblks( WorstCaseSplit ) ) {
+
+ return FALSE;
+ }
+
+ // The name does not exist in the tree, so TargetDirent points
+ // at the dirent before which it should be inserted.
+
+ return ( InsertIntoDirblk( NewDirent,
+ TargetDirblk,
+ TargetHeader,
+ (PBYTE)TargetDirent ) );
+
+ } else {
+
+ // an error occurred trying to find the name.
+ return FALSE;
+ }
+}
+
+
+BOOLEAN
+HPFS_DIRECTORY_TREE::QueryDirentFromName(
+ IN PHPFS_NAME Name,
+ OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ OUT PBOOLEAN Error
+ )
+/*++
+
+Routine Description:
+
+ This method finds a dirent in the tree based on the supplied name
+ and copies it into the client's buffer.
+
+Arguments:
+
+ Name -- Supplies the name to find.
+ Buffer -- Supplies a pointer to the client's buffer.
+ BufferLength -- Supplies the length in bytes of the client's buffer.
+ Error -- Receives TRUE if the method fails due to error.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ The value of *Error is undefined if the method returns TRUE; if
+ it returns FALSE, then *Error is TRUE if an error occurred. If
+ the method returns FALSE and *Error is FALSE, the requested name
+ is not in the tree.
+
+ If the client's buffer is too small to hold the dirent, this method
+ will fail (and *Error will be set to TRUE).
+
+--*/
+{
+ PDIRBLK_CACHE_ELEMENT TargetHeader;
+ PDIRENTD TargetEntry;
+ PDIRBLK TargetDirblk;
+
+ DebugPtrAssert( Buffer );
+ DebugPtrAssert( Error );
+
+ if( FindName( Name, &TargetEntry, &TargetDirblk, &TargetHeader ) ) {
+
+ // A matching entry was found. If the client's buffer is large
+ // enough, copy the entry into it.
+ //
+ DebugPtrAssert( TargetEntry );
+
+ if( TargetEntry->cchThisEntry > BufferLength ) {
+
+ // The client's buffer is too small.
+ //
+ DebugPrint( "Too small a buffer supplied to QueryDirentFromName.\n" );
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ memcpy( Buffer, TargetEntry, TargetEntry->cchThisEntry );
+ return TRUE;
+
+ } else {
+
+ // The entry was not found. If TargetEntry is NULL, an error
+ // occurred; otherwise, the requested name simply is not in
+ // the tree.
+ //
+ *Error = ( TargetEntry == NULL );
+ return FALSE;
+ }
+}
+
+
+
+LBN
+HPFS_DIRECTORY_TREE::QueryFnodeLbnFromName(
+ IN HPFS_NAME* Name
+ )
+/*++
+
+Routine Description:
+
+ Finds the FNode of a directory entry in the tree based on its name.
+
+Arguments:
+
+ Name -- supplies the name to find
+
+Return Value:
+
+ the sector number of the FNode for the entry with that name; returns
+ zero if the entry was not found.
+
+--*/
+{
+
+ PDIRBLK_CACHE_ELEMENT TargetHeader;
+ PDIRENTD TargetEntry;
+ PDIRBLK TargetDirblk;
+
+ if( !FindName( Name, &TargetEntry, &TargetDirblk, &TargetHeader ) ){
+
+ // It's not in the tree
+ return 0;
+ }
+
+ return( TargetEntry->lbnFnode );
+}
+
+
+
+LBN
+HPFS_DIRECTORY_TREE::QueryRootDirblkLbn(
+ )
+/*++
+
+Routine Description:
+
+ This method returns the LBN of the root dirblk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The LBN of the root dirblk.
+
+Notes:
+
+ This method is useful for updating the FNode--after a client performs
+ an operation which could change the root dirblk lbn, it should check
+ use this method to check that the FNode still refers to the correct
+ dirblk.
+
+--*/
+{
+ return _RootDirblkLbn;
+}
+
+
+
+BOOLEAN
+HPFS_DIRECTORY_TREE::Delete(
+ IN HPFS_NAME* Name
+ )
+/*++
+
+Routine Description:
+
+ Deletes a name from the tree.
+
+Arguments:
+
+ Name -- supplies the name of the entry to delete.
+
+--*/
+{
+ PDIRBLK_CACHE_ELEMENT TargetHeader, LeafHeader;
+ PDIRENTD TargetEntry, NextEntry, LeafEntry, ReplacementEntry;
+ PDIRBLK TargetDirblk, LeafDirblk;
+ LBN LeafLbn;
+
+
+ if( !FindName( Name, &TargetEntry, &TargetDirblk, &TargetHeader ) ) {
+
+ // The name is not in the tree, so there's nothing to delete.
+
+ return TRUE;
+
+ }
+
+ if( !(TargetEntry->fFlags & DF_BTP) ) {
+
+ // This is a leaf entry.
+
+ TargetHeader->MarkModified();
+
+ NextEntry = NEXT_ENTRY(TargetEntry);
+
+ TargetDirblk->_pdb->offulFirstFree -= TargetEntry->cchThisEntry;
+
+ memmove( TargetEntry,
+ NEXT_ENTRY(TargetEntry),
+ (size_t)(DIRBLK_SIZE -
+ TargetDirblk->QueryEntryOffset(NextEntry)) );
+
+ if( TargetDirblk->IsEmpty() ) {
+
+ // We deleted the only non-end entry from this
+ // dirblk, which means we need to readjust the
+ // tree.
+
+ Adjust( TargetHeader, TargetDirblk );
+ }
+
+ } else {
+
+ // This entry is a node, which means we need to replace it
+ // with a leaf entry (which will inherit its downpointer).
+ // We want the first entry in the subtree rooted at the
+ // child of the dirent following the one we will delete.
+
+ if( (ReplacementEntry = (PDIRENTD)MALLOC( MaximumDirentSize )) ==
+ NULL ) {
+
+ perrstk->push( ERR_MEMORY_UNAVAILABLE, QueryClassId() );
+ return FALSE;
+ }
+
+ LeafLbn = BTP( NEXT_ENTRY( TargetEntry ) );
+
+ do {
+
+ if( (LeafHeader = _Cache->GetCachedDirblk( LeafLbn )) == NULL ) {
+
+ return FALSE;
+ }
+
+ LeafEntry = LeafHeader->GetDirblk()->GetFirstEntry();
+
+ if( LeafEntry->fFlags & DF_BTP ) {
+
+ LeafLbn = BTP( LeafEntry );
+
+ } else {
+
+ break;
+ }
+
+ } while ( TRUE );
+
+ // We've located the dirent--copy it into the replacement
+ // buffer, set its down pointer, and delete it from the
+ // leaf block. Then delete the target entry and insert
+ // the replacement entry into its place. Then check the
+ // leaf dirblk to see if it needs to be adjusted. Note
+ // that this requires holding the leaf block while we
+ // insert the replacement entry. Note also that we don't
+ // need to mark the target dirblk as modified, since
+ // InsertIntoDirblk will take care of that.
+
+ LeafHeader->Hold();
+ LeafDirblk = LeafHeader->GetDirblk();
+
+ memmove( ReplacementEntry,
+ LeafEntry,
+ LeafEntry->cchThisEntry );
+
+ LeafDirblk->_pdb->offulFirstFree -= LeafEntry->cchThisEntry;
+
+ memmove( LeafEntry,
+ NEXT_ENTRY( LeafEntry ),
+ (size_t)(DIRBLK_SIZE -
+ LeafDirblk->QueryEntryOffset(NEXT_ENTRY(LeafEntry))) );
+
+ ReplacementEntry->cchThisEntry += DOWNPOINTER_SIZE;
+ ReplacementEntry->fFlags |= DF_BTP;
+ BTP( ReplacementEntry ) = BTP( TargetEntry );
+
+ // The replacement entry is ready--delete the target entry
+ // and insert the replacement entry in its place.
+
+ TargetDirblk->_pdb->offulFirstFree -= TargetEntry->cchThisEntry;
+
+ memmove( TargetEntry,
+ NEXT_ENTRY(TargetEntry),
+ (size_t)(DIRBLK_SIZE - TargetDirblk->
+ QueryEntryOffset(NEXT_ENTRY(TargetEntry))) );
+
+ InsertIntoDirblk( ReplacementEntry,
+ TargetDirblk,
+ TargetHeader,
+ (PBYTE)TargetEntry );
+
+ LeafHeader->MarkModified();
+ LeafHeader->Unhold();
+
+ if( LeafDirblk->IsEmpty() ) {
+
+ Adjust( LeafHeader, LeafHeader->GetDirblk() );
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+HPFS_DIRECTORY_TREE::Sort(
+ )
+/*++
+
+Routine Description:
+
+ This resorts the directory by creating a new tree and inserting
+ entries into it.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE on successful completion.
+
+Notes:
+
+ If any DIRBLK in the tree to be sorted is unreadable, it (and
+ any of its children) will be omitted from the sort.
+
+ We wait until the sort is completed to free up the old dirblks,
+ to avoid any unpleasantness if we encounter an error.
+
+ The caller is responsible for updating the FNode to point at
+ the new root dirblk.
+
+--*/
+{
+ HPFS_DIRECTORY_TREE NewTree;
+ LBN NewRootLbn;
+ PDIRBLK_CACHE_ELEMENT CurrentHeader;
+ PDIRBLK CurrentDirblk;
+ PDIRENTD CopyBuffer;
+
+
+ // We begin by allocating a new DIRBLK to be the root of
+ // the new tree, and creating and initializing a new Directory
+ // Tree object to manage it. Note that we will not accept a
+ // hotfix LBN for the new root, since that would make life much
+ // more complicated than need be.
+
+ while( TRUE ) {
+
+ if( (NewRootLbn = _SuperArea->GetBitmap()->AllocateDirblk()) == 0 ) {
+
+ // We're out of space on the volume.
+
+ return FALSE;
+ }
+
+ if( _SuperArea->GetHotfixList()->IsInList( NewRootLbn,
+ SectorsPerDirblk ) ) {
+
+ // Somebody in this block is bad--wipe out the whole block.
+ // Since we just allocated it, we can put it on the bad block
+ // list without any further ado. And since we're moving it
+ // to the bad block list, we can clear it out of the hotfix
+ // list, too. Two birds with one stone, and all that.
+
+ _SuperArea->GetBadBlockList()->AddRun( NewRootLbn,
+ SectorsPerDirblk );
+
+ _SuperArea->GetHotfixList()->ClearRun( NewRootLbn,
+ SectorsPerDirblk,
+ _SuperArea );
+
+ } else {
+
+ break;
+ }
+ }
+
+
+ if( !NewTree.Initialize( _SuperArea, _Cache, NewRootLbn, _FnodeLbn ) ) {
+
+ _SuperArea->GetBitmap()->SetFree( NewRootLbn, SectorsPerDirblk );
+ return FALSE;
+ }
+
+ // We have allocated a root dirblk, and initialized its tree.
+ // Now we set up a root dirblk, and mark it dirty.
+
+ if( (CurrentHeader = _Cache->GetCachedDirblk( NewRootLbn, TRUE )) ==
+ NULL ) {
+
+ // Our new root dirblk is unreadable--give up.
+ _SuperArea->GetBitmap()->SetFree( NewRootLbn, SectorsPerDirblk );
+ return FALSE;
+ }
+
+ CurrentHeader->MarkModified();
+ CurrentHeader->Hold();
+ CurrentDirblk = CurrentHeader->GetDirblk();
+ CurrentDirblk->CreateRoot( _FnodeLbn );
+ CurrentHeader->Unhold();
+
+ // OK, we're ready to roll. Call the recursive worker.
+
+ if( (CopyBuffer = (PDIRENTD) MALLOC( MaximumDirentSize )) == NULL ||
+ !SortFromDirblk( _RootDirblkLbn, &NewTree, CopyBuffer ) ) {
+
+ // the sort failed.
+ _SuperArea->GetBitmap()->SetFree( NewRootLbn, SectorsPerDirblk );
+ return FALSE;
+ }
+
+ // The sort succeeded. Now we free all the DIRBLKs in the
+ // old tree. Note that this operation is not likely to be
+ // as expensive as it looks, since the DIRBLKS of the current
+ // tree are likely to be in the cache. Then we set
+ // _RootDirblkLbn to refer to the new root, and we're done.
+
+ FreeDirblks( _RootDirblkLbn );
+
+ _RootDirblkLbn = NewTree.QueryRootDirblkLbn();
+
+ return TRUE;
+}
+
+
+
+
+BOOLEAN
+HPFS_DIRECTORY_TREE::CheckOrder(
+ PLOG_IO_DP_DRIVE Drive,
+ PBOOLEAN IsBadlyOrdered
+ )
+/*++
+
+Routine Description:
+
+ Checks that the directory is well-ordered and that every FNode
+ has the correct parent FNode. Recurses into subdirectories.
+
+Arguments:
+
+ Drive -- supplies the drive on which the directory resides
+ (needed to read and write FNodes).
+ IsBadlyOrdered -- receives TRUE if the directory is found to be
+ badly ordered.
+
+Return Value:
+
+ TRUE on successful completion (in which case *IsBadlyOrdered
+ may be used to determine whether the directory should be sorted).
+
+Notes:
+
+ This routine is used to check recovered orphan directories.
+ It assumes that the dirblks themselves are well-formed, but
+ that they may be badly-ordered or that the tree may be unbalanced.
+
+--*/
+{
+ HPFS_NAME PreviousName;
+
+ *IsBadlyOrdered = FALSE;
+
+ return( CheckOrderFromDirblk( Drive,
+ _RootDirblkLbn,
+ &PreviousName,
+ IsBadlyOrdered ) );
+}
+
+
+
+BOOLEAN
+HPFS_DIRECTORY_TREE::UpdateDirent(
+ IN PDIRENTD SourceDirent
+ )
+/*++
+
+Routine Description:
+
+ This method updates a directory entry.
+
+Arguments:
+
+ SourceDirent -- Supplies the new version of the dirent.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+
+Notes:
+
+ The following fields are copied from the source directory
+ entry into the corresponding entry in the tree:
+
+ fAttr
+ timLastMod
+ cchFSize
+ timLastAccess
+ timCreate
+
+ Other fields are left unaffected.
+
+ If there is no matching directory entry in the tree, this
+ method fails.
+
+--*/
+{
+ HPFS_NAME SearchName;
+ PDIRBLK_CACHE_ELEMENT TargetHeader;
+ PDIRENTD TargetEntry;
+ PDIRBLK TargetDirblk;
+
+ // Initialize a search name based on the source dirent.
+ //
+ if( !SearchName.Initialize( SourceDirent->cchName,
+ SourceDirent->bName,
+ SourceDirent->bCodePage,
+ _SuperArea->GetCasemap() ) ) {
+
+ return FALSE;
+ }
+
+ // Find the matching directory entry in the tree:
+ //
+ if( !FindName( &SearchName,
+ &TargetEntry,
+ &TargetDirblk,
+ &TargetHeader ) ) {
+
+ // Since we can't find the entry, we can't update it.
+ //
+ return FALSE;
+ }
+
+ TargetEntry->fAttr = SourceDirent->fAttr;
+ TargetEntry->timLastMod = SourceDirent->timLastMod;
+ TargetEntry->cchFSize = SourceDirent->cchFSize;
+ TargetEntry->timLastAccess = SourceDirent->timLastAccess;
+ TargetEntry->timCreate = SourceDirent->timCreate;
+
+ // Mark the header containing the target entry as dirty.
+ //
+ TargetHeader->MarkModified();
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+HPFS_DIRECTORY_TREE::CheckOrderFromDirblk(
+ PLOG_IO_DP_DRIVE Drive,
+ IN LBN DirblkLbn,
+ IN OUT PHPFS_NAME PreviousName,
+ OUT PBOOLEAN IsBadlyOrdered
+ )
+/*++
+
+Routine Description:
+
+ Checks that the dirblk sub-tree rooted at the specified LBN
+ is well-ordered and that every FNode has the correct parent FNode.
+ Recurses into subdirectories. (Worker routine for CheckOrder.)
+
+Arguments:
+
+ Drive -- supplies the drive on which the directory resides
+ (needed to read and write FNodes)
+ DirblkLbn -- supplies the Lbn of the root of the subtree.
+ PreviousName -- supplies the last name preceding this subtree in the
+ directory (may be uninitialized) and receives the last
+ name in this subtree.
+ IsBadlyOrdered -- receives TRUE if the sub-tree is badly ordered.
+
+Return Value:
+
+ TRUE on successful completion (in which case *IsBadlyOrdered
+ may be used to determine whether the directory should be sorted).
+
+Notes:
+
+ This routine is used to check recovered orphan directories.
+ It assumes that the dirblks themselves are well-formed, but
+ that they may be badly-ordered or that the tree may be unbalanced.
+
+--*/
+{
+ HPFS_DIRECTORY_TREE ChildTree;
+ HPFS_NAME CurrentName;
+ PDIRBLK_CACHE_ELEMENT CurrentHeader;
+ PDIRENTD CurrentEntry;
+ BOOLEAN ChildIsBadlyOrdered;
+ FNODE ChildFnode;
+
+ if( !ChildFnode.Initialize( Drive, 0 ) ) {
+
+ return FALSE;
+ }
+
+
+ // Read the dirblk and check that it is indeed a dirblk.
+
+ if( (CurrentHeader = _Cache->GetCachedDirblk( DirblkLbn )) == NULL ||
+ !CurrentHeader->GetDirblk()->IsDirblk() ) {
+
+ return FALSE;
+ }
+
+ // Hold the dirblk
+
+ CurrentHeader->Hold();
+
+
+ CurrentEntry = CurrentHeader->GetDirblk()->GetFirstEntry();
+
+ while (TRUE) { // break out after end entry is processed
+
+ // Read the FNode and check its lbnContDir field. If
+ // the current entry is a subdirectory, check that it
+ // is well-ordered.
+
+ if( !(CurrentEntry->fFlags & (DF_SPEC | DF_END)) ) {
+
+ ChildFnode.Relocate( CurrentEntry->lbnFnode );
+
+ if( ChildFnode.Read() &&
+ ChildFnode.IsFnode() ) {
+
+ if( ChildFnode.CheckParent( _FnodeLbn ) ) {
+
+ // We updated the parent pointer, so we
+ // need to write the FNode.
+
+ ChildFnode.Write();
+ }
+
+ if( CurrentEntry->fAttr & ATTR_DIRECTORY ) {
+
+ // It's a subdirectory--check order
+ // and sort, if necessary.
+
+ ChildIsBadlyOrdered = FALSE;
+
+ if( !ChildTree.
+ Initialize( _SuperArea,
+ _Cache,
+ ChildFnode.QueryRootDirblkLbn(),
+ CurrentEntry->lbnFnode ) ) {
+
+ CurrentHeader->Unhold();
+ return FALSE;
+ }
+
+ if( ChildTree.CheckOrder( Drive,
+ &ChildIsBadlyOrdered ) &&
+ ChildIsBadlyOrdered ) {
+
+ // The child needs to be sorted
+
+ ChildTree.Sort();
+
+ ChildFnode.SetRootDirblkLbn(
+ ChildTree.QueryRootDirblkLbn() );
+
+ ChildFnode.Write();
+ }
+ }
+ }
+ }
+
+
+ // If it has a down pointer, recurse into that child,
+ // propagating any error detected back to caller.
+
+ if( CurrentEntry->fFlags & DF_BTP ) {
+
+ if( !CheckOrderFromDirblk( Drive,
+ BTP(CurrentEntry),
+ PreviousName,
+ IsBadlyOrdered ) ) {
+
+ CurrentHeader->Unhold();
+ return FALSE;
+ }
+ }
+
+
+ if( CurrentEntry->fFlags & DF_END ) {
+
+ break;
+ }
+
+ // Check that the name of the current entry is lexically
+ // greater than PreviousName.
+
+ if( !CurrentName.Initialize( CurrentEntry->cchName,
+ CurrentEntry->bName,
+ CurrentEntry->bCodePage,
+ _SuperArea->GetCasemap() ) ) {
+
+ CurrentHeader->Unhold();
+ return FALSE;
+ }
+
+ if( PreviousName->IsNull() &&
+ !(CurrentEntry->fFlags & DF_SPEC ) ) {
+
+ // This is the first entry in the directory (since
+ // there is no previous name), and it is not the
+ // special '..' entry, so the directory is badly-
+ // ordered.
+
+ *IsBadlyOrdered = TRUE;
+ }
+
+ if( CurrentName.CompareName( PreviousName ) !=
+ NAME_IS_GREATER_THAN ) {
+
+ *IsBadlyOrdered = TRUE;
+ }
+
+ // Swap CurrentName and PreviousName
+ PreviousName->Swap( &CurrentName );
+
+ CurrentEntry = NEXT_ENTRY(CurrentEntry);
+ }
+
+
+ CurrentHeader->Unhold();
+ return TRUE;
+}
+
+
+
+BOOLEAN
+HPFS_DIRECTORY_TREE::FindName(
+ IN HPFS_NAME* Name,
+ OUT PDIRENTD* DirentFound,
+ OUT PDIRBLK* DirblkFound,
+ OUT PDIRBLK_CACHE_ELEMENT* CacheFound
+ )
+/*++
+
+Routine Description:
+
+ This method finds a name in the tree.
+
+Arguments:
+
+ Name -- supplies the name to be found
+ DirblkFound -- receives a pointer to the entry containing the name
+ DirentFound -- receives a pointer to the dirblk containing the entry
+ CacheFound -- receives a pointer to the cache element containing
+ the dirblk
+Return Value:
+
+ TRUE if an entry with the requested name is found, FALSE if
+ it is not found or if an error occurred.
+
+ If the name was found, *DirentFound points at the entry containing
+ the name, *DirblkFound points at the dirblk containing this entry,
+ and *CacheFound points at the cache element containing that dirblk.
+
+ If the name was not found, but no error occurred, *DirentFound
+ points at the first leaf entry in the tree whose name is lexically
+ greater than Name, *DirblkFound points at the dirblk containing
+ that name, and *CacheFound points at the cache element containing
+ that dirblk. (Note that if the first entry in the tree whose
+ name is lexically greater than Name is a node entry, *DirentFound
+ will point at the END entry of a leaf.)
+
+ Note that these pointers point into the dirblk cache, and that
+ the cache element containing them may not be held.
+
+ If an error occurred, the function returns FALSE and *DirentFound,
+ *DirblkFound, and *CacheFound are set to NULL.
+
+--*/
+{
+
+ PDIRBLK_CACHE_ELEMENT CacheHeader;
+
+ CacheHeader = _Cache->GetCachedDirblk( _RootDirblkLbn );
+
+ if( CacheHeader == NULL ) {
+
+ // Read error.
+
+ *DirblkFound = NULL;
+ *CacheFound = NULL;
+ return FALSE;
+ }
+
+ while( TRUE ) {
+
+ if( CacheHeader->GetDirblk()->
+ FindName( Name,
+ DirentFound,
+ _SuperArea->GetCasemap() ) ) {
+
+ // Found the name!
+ *DirblkFound = CacheHeader->GetDirblk();
+ *CacheFound = CacheHeader;
+ return TRUE;
+
+ } else if ( *DirentFound != NULL ) {
+
+ // The name is not in the current block. If the entry returned
+ // has a B-Tree pointer, then that's the next dirblk to search.
+ // It it doesn't, then the name is not in the tree.
+
+ if( (*DirentFound)->fFlags & DF_BTP ) {
+
+ CacheHeader =
+ _Cache->GetCachedDirblk( BTP( *DirentFound ) );
+
+ if( CacheHeader == NULL ) {
+
+ // Error
+ *DirblkFound = NULL;
+ *CacheFound = NULL;
+ return FALSE;
+ }
+
+ } else {
+
+ // The name is not in the tree.
+ *DirblkFound = CacheHeader->GetDirblk();
+ *CacheFound = CacheHeader;
+ return FALSE;
+ }
+
+ } else {
+
+ // Error
+ *DirblkFound = NULL;
+ *CacheFound = NULL;
+ return FALSE;
+ }
+ }
+}
+
+
+
+BOOLEAN
+HPFS_DIRECTORY_TREE::Merge(
+ PDIRBLK FirstDirblk,
+ PDIRBLK_CACHE_ELEMENT FirstHeader,
+ PDIRBLK SecondDirblk,
+ PDIRBLK_CACHE_ELEMENT SecondHeader,
+ PDIRBLK ParentDirblk,
+ PDIRBLK_CACHE_ELEMENT ParentHeader,
+ PDIRENTD ParentEntry
+ )
+/*++
+
+Routine Description:
+
+ This method merges two dirblks into one.
+
+Arguments:
+
+ FirstDirblk -- supplies the first dirblk to be merged.
+ FirstHeader -- supplies the cache header for FirstDirblk.
+ SecondDirblk -- supplies the second dirblk to be merged.
+ SecondHeader -- supplies the cache header for SecondDirblk.
+ ParentDirblk -- supplies the parent of the two dirblks.
+ ParentHeader -- supplies the cache header for ParentDirblk.
+ ParentEntry -- supplies the parent directory entry of FirstDirblk.
+
+Return Value:
+
+ TRUE on successful completion
+
+Notes:
+
+ The Dirblks in question must be well-formed and well-ordered.
+ The names in the entries in FirstDirblk must be lexically less
+ than the name in ParentEntry, which in turn must be lexically
+ less than the names in the entries in SecondDirblk.
+
+ The dirblks in question must be leaf blocks; non-leaf blocks
+ are never merged.
+
+ The entries from the first block and the parent entry (stripped
+ of its B-Tree downpointer) are moved into the second block, and
+ the first block is freed. (The parent of the second block is not
+ modified.)
+
+--*/
+{
+
+ ULONG BytesInFirstBlock, BytesInSecondBlock;
+ PDIRENTD TargetEntry;
+
+ DebugAssert( BTP(ParentEntry) == FirstDirblk->QueryStartLbn() );
+ DebugAssert( FirstHeader->GetDirblk() == FirstDirblk );
+ DebugAssert( SecondHeader->GetDirblk() == SecondDirblk );
+ DebugAssert( ParentHeader->GetDirblk() == ParentDirblk );
+ DebugAssert( !(FirstDirblk->GetFirstEntry()->fFlags & DF_BTP) );
+
+ // Determine how many bytes to copy from the first block,
+ // and how many in the second block will have to be shifted.
+ // We want to copy all the dirents except the END entry from
+ // the first block; we'll have to shift all the dirents,
+ // including the END entry, in the second block.
+
+ BytesInFirstBlock = FirstDirblk->_pdb->offulFirstFree -
+ DIRBLK_HEADER_SIZE -
+ LeafEndEntrySize;
+
+ BytesInSecondBlock = SecondDirblk->_pdb->offulFirstFree -
+ DIRBLK_HEADER_SIZE;
+
+ DebugAssert( BytesInFirstBlock + BytesInSecondBlock +
+ ParentEntry->cchThisEntry - DOWNPOINTER_SIZE +
+ + DIRBLK_HEADER_SIZE <=
+ DIRBLK_SIZE );
+
+ // Adjust the second block's offset of first free byte to reflect
+ // the entries it is about to receive.
+
+ SecondDirblk->_pdb->offulFirstFree +=
+ BytesInFirstBlock +
+ ParentEntry->cchThisEntry - DOWNPOINTER_SIZE;
+
+ // Shift the entries in the second block to make room for the
+ // entries which will be inserted:
+
+ memmove( (PBYTE)(SecondDirblk->GetFirstEntry()) + BytesInFirstBlock
+ + ParentEntry->cchThisEntry - DOWNPOINTER_SIZE,
+ (PBYTE)(SecondDirblk->GetFirstEntry()),
+ (size_t)BytesInSecondBlock );
+
+ // copy the entries from the first block
+
+ memmove( SecondDirblk->GetFirstEntry(),
+ FirstDirblk->GetFirstEntry(),
+ (size_t)BytesInFirstBlock );
+
+ // copy the parent entry, less the downpointer, and modify the
+ // length of the copied entry to reflect the loss of the down
+ // pointer.
+
+ TargetEntry = (PDIRENTD)((PBYTE)(SecondDirblk->GetFirstEntry()) +
+ BytesInFirstBlock);
+
+ memmove( TargetEntry,
+ ParentEntry,
+ (size_t)(ParentEntry->cchThisEntry - DOWNPOINTER_SIZE) );
+
+ TargetEntry->cchThisEntry -= DOWNPOINTER_SIZE;
+ TargetEntry->fFlags &= ~DF_BTP;
+
+
+ // Remove the parent entry from the parent directory block
+ // by moving everything after it down over it. (Adjust
+ // the offset-of-first-free-byte first, while we still
+ // know how much we're losing.)
+
+ ParentDirblk->_pdb->offulFirstFree -= ParentEntry->cchThisEntry;
+
+ memmove(ParentEntry,
+ NEXT_ENTRY(ParentEntry),
+ (size_t)(DIRBLK_SIZE -
+ ParentDirblk->QueryEntryOffset(NEXT_ENTRY(ParentEntry))) );
+
+
+ // Wipe out the signature of the first block and free it in the bitmap
+
+ FirstDirblk->_pdb->sig = 0;
+ _SuperArea->GetBitmap()->
+ SetFree( FirstDirblk->QueryStartLbn(),SectorsPerDirblk );
+
+ // All three dirblks have been modified
+
+ FirstHeader->MarkModified();
+ SecondHeader->MarkModified();
+ ParentHeader->MarkModified();
+
+ // Since the first dirblk is no longer a dirblk, flush it
+ // out of the cache
+
+ FirstHeader->Flush();
+
+ return TRUE;
+}
+
+BOOLEAN
+HPFS_DIRECTORY_TREE::Balance(
+ PDIRBLK FirstDirblk,
+ PDIRBLK_CACHE_ELEMENT FirstHeader,
+ PDIRBLK SecondDirblk,
+ PDIRBLK_CACHE_ELEMENT SecondHeader,
+ PDIRBLK ParentDirblk,
+ PDIRBLK_CACHE_ELEMENT ParentHeader,
+ PDIRENTD ParentEntry
+ )
+/*++
+
+Routine Description:
+
+ This method redistribute directory entries between two directory
+ blocks. It will ensure that neither Dirblk is left empty.
+
+Arguments:
+
+ FirstDirblk -- supplies the first dirblk to be balanced.
+ FirstHeader -- supplies the cache header for FirstDirblk.
+ SecondDirblk -- supplies the second dirblk to be balanced.
+ SecondHeader -- supplies the cache header for SecondDirblk.
+ ParentDirblk -- supplies the parent of the two dirblks.
+ ParentHeader -- supplies the cache header for ParentDirblk.
+ ParentEntry -- supplies the parent directory entry of FirstDirblk
+
+Return Value:
+
+ TRUE on successful completion
+
+Notes:
+
+ Both FirstDirblk and SecondDirblk must be valid, well-formed
+ leaf blocks; we do not attempt to balance non-leaf blocks.
+
+ Balance is only called if one of the dirblks to be balanced
+ is empty and the other has at least two non-END entries, so
+ we won't expend any effort on checking for certain error
+ conditions.
+
+--*/
+{
+ PDIRENTD EntryToPromote, InsertPoint, PrevEntry, CurrentEntry;
+ ULONG Offset, MidPoint;
+ size_t BytesToMove;
+
+ if( (EntryToPromote = (PDIRENTD)MALLOC( MaximumDirentSize)) == NULL ) {
+
+ return FALSE;
+ }
+
+ if( !FirstDirblk->IsEmpty() &&
+ !SecondDirblk->IsEmpty() ) {
+
+ // Neither block is empty, so we don't really need to
+ // balance these puppies.
+
+ return TRUE;
+ }
+
+ // Determine which direction we should move entries:
+
+ if( FirstDirblk->_pdb->offulFirstFree <
+ SecondDirblk->_pdb->offulFirstFree ) {
+
+ // We're going to move entries from SecondDirblk into
+ // FirstDirblk. The parent entry will be moved into
+ // FirstDirblk, followed by some number of entries from
+ // SecondDirblk (possibly zero); the next entry in
+ // SecondDirblk will be taken to replace ParentEntry in
+ // ParentDirblk. Note that at least one non-end entry
+ // must be left in SecondDirblk.
+
+ // Our first order of business is to select the entry from
+ // SecondDirblk that will replace ParentEntry. If we consider
+ // a set of entries (consisting of all the non-END entries from
+ // FirstBlock, followed by ParentEntry, followed by all the
+ // non-END entries from SecondBlock), we want to find an entry
+ // near the middle of this set. We know that it will be
+ // ParentEntry or an entry from SecondDirblk. As we scan
+ // through SecondDirblk for our victim, we can also compute
+ // the number of bytes we'll have to move from SecondDirblk.
+
+ MidPoint = ( FirstDirblk->_pdb->offulFirstFree +
+ SecondDirblk->_pdb->offulFirstFree +
+ ParentEntry->cchThisEntry ) / 2 -
+ ( DIRBLK_HEADER_SIZE + LeafEndEntrySize );
+
+ Offset = FirstDirblk->_pdb->offulFirstFree -
+ (DIRBLK_HEADER_SIZE + LeafEndEntrySize) +
+ ParentEntry->cchThisEntry;
+
+ PrevEntry = NULL;
+ BytesToMove = 0;
+ CurrentEntry = SecondDirblk->GetFirstEntry();
+
+ while( (Offset < MidPoint) &&
+ !(CurrentEntry->fFlags & DF_END) ) {
+
+ Offset += CurrentEntry->cchThisEntry;
+ BytesToMove += CurrentEntry->cchThisEntry;
+ PrevEntry = CurrentEntry;
+ CurrentEntry = NEXT_ENTRY( CurrentEntry );
+ }
+
+
+ DebugAssert( !(CurrentEntry->fFlags & DF_END) );
+
+ if( NEXT_ENTRY(CurrentEntry)->fFlags & DF_END ) {
+
+ // Oops, this is the last non-END entry--back up one.
+ // Since Balance is only called if the non-empty block
+ // has at least two entries, this is safe.
+
+ DebugAssert( PrevEntry != NULL );
+ CurrentEntry = PrevEntry;
+ BytesToMove -= CurrentEntry->cchThisEntry;
+ }
+
+ // OK, CurrentEntry points at the entry that will replace
+ // ParentEntry in ParentDirblk. All the entries before
+ // CurrentEntry (if there are any) will go to FirstBlock;
+ // CurrentEntry itself will be copied to EntryToPromote,
+ // our promotion buffer, for insertion into ParentDirblk.
+ // (It will, while it's there, also inherit ParentEntry's
+ // old B-Tree down pointer.)
+
+ // Set up EntryToPromote.
+
+ memmove( EntryToPromote,
+ CurrentEntry,
+ CurrentEntry->cchThisEntry );
+
+ EntryToPromote->cchThisEntry += DOWNPOINTER_SIZE;
+ BTP(EntryToPromote) = BTP(ParentEntry);
+ EntryToPromote->fFlags |= DF_BTP;
+
+ // Now, open up space in FirstBlock for the entries it
+ // will receive. This really just shifts the END entry
+ // down, but it's easy to do, so we'll do it.
+
+ InsertPoint = (FirstDirblk->EndEntry());
+
+ FirstDirblk->_pdb->offulFirstFree +=
+ BytesToMove +
+ ParentEntry->cchThisEntry - DOWNPOINTER_SIZE;
+
+ memmove( (PBYTE)InsertPoint + BytesToMove +
+ ParentEntry->cchThisEntry - DOWNPOINTER_SIZE,
+ InsertPoint,
+ InsertPoint->cchThisEntry );
+
+ // Copy in ParentEntry, less its BTree downpointer--adjust
+ // its size once it gets here.
+
+ memmove( InsertPoint,
+ ParentEntry,
+ ParentEntry->cchThisEntry - DOWNPOINTER_SIZE );
+
+ InsertPoint->cchThisEntry -= DOWNPOINTER_SIZE;
+ InsertPoint->fFlags &= ~DF_BTP;
+
+ InsertPoint = NEXT_ENTRY(InsertPoint);
+
+ // Copy the entries (if any) from SecondDirblk
+
+ if( BytesToMove != 0 ) {
+
+ memmove( InsertPoint,
+ SecondDirblk->GetFirstEntry(),
+ BytesToMove );
+ }
+
+ // OK, FirstDirblk is all set. Now we can shift down the entries
+ // that remain in SecondDirblk. (Note that we update offulFirstFree
+ // before we use it to determine how many bytes to move.)
+
+ SecondDirblk->_pdb->offulFirstFree -=
+ BytesToMove + CurrentEntry->cchThisEntry;
+
+ memmove( SecondDirblk->GetFirstEntry(),
+ NEXT_ENTRY(CurrentEntry),
+ (size_t)(SecondDirblk->_pdb->offulFirstFree -
+ DIRBLK_HEADER_SIZE) );
+
+ // That takes care of SecondDirblk.
+
+
+ } else {
+
+ // We're going to move entries from FirstDirblk into
+ // SecondDirblk. We'll choose an entry from FirstDirblk
+ // to replace ParentEntry; the entries in FirstDirblk
+ // after that replacement (if any) will go into
+ // SecondDirblk, followed by ParentEntry.
+
+ // We can also compute, as we go, the number of bytes
+ // to move from FirstDirblk to SecondDirblk. We start
+ // by assuming that we'll move all the non-end entries;
+ // each entry we pass over won't be moved.
+
+ MidPoint = ( FirstDirblk->_pdb->offulFirstFree +
+ SecondDirblk->_pdb->offulFirstFree +
+ ParentEntry->cchThisEntry ) / 2 -
+ ( DIRBLK_HEADER_SIZE + LeafEndEntrySize );
+
+ Offset = 0;
+ BytesToMove = (size_t)FirstDirblk->_pdb->offulFirstFree -
+ DIRBLK_HEADER_SIZE -
+ LeafEndEntrySize;
+
+ PrevEntry = NULL;
+ CurrentEntry = FirstDirblk->GetFirstEntry();
+
+ while( (Offset < MidPoint) &&
+ !(CurrentEntry->fFlags & DF_END) ) {
+
+ Offset += CurrentEntry->cchThisEntry;
+ BytesToMove -= CurrentEntry->cchThisEntry;
+ PrevEntry = CurrentEntry;
+ CurrentEntry = NEXT_ENTRY( CurrentEntry );
+ }
+
+
+ if( CurrentEntry == FirstDirblk->GetFirstEntry() ) {
+
+ // This is not OK, since we have to leave at
+ // least one non-END entry in FirstDirblk.
+ // Since we know there are at least two non-END
+ // entries in the non-empty dirblk, we can
+ // take the next entry instead.
+
+ BytesToMove -= CurrentEntry->cchThisEntry;
+ PrevEntry = CurrentEntry;
+ CurrentEntry = NEXT_ENTRY(CurrentEntry);
+ }
+
+ if( CurrentEntry->fFlags & DF_END ) {
+
+ // We can't take the END entry, so we'll back up
+ // to PrevEntry. This is safe, since we know
+ // there are at least two non-END entries in
+ // this dirblk.
+
+ CurrentEntry = PrevEntry;
+ BytesToMove += CurrentEntry->cchThisEntry;
+ }
+
+ // BytesToMove now equals the bytes in CurrentEntry and
+ // all the non-end entries after it; however, CurrentEntry
+ // isn't going into SecondDirblk, so we subtract it out,
+ // too.
+
+ BytesToMove -= CurrentEntry->cchThisEntry;
+
+ DebugAssert( CurrentEntry != FirstDirblk->GetFirstEntry() );
+
+
+ // OK, CurrentEntry points at the entry that will replace
+ // ParentEntry in ParentDirblk. All the non-END entries after
+ // CurrentEntry (if there are any) will go to SecondBlock;
+ // CurrentEntry itself will be copied to EntryToPromote,
+ // our promotion buffer, for insertion into ParentDirblk.
+ // (It will, while it's there, also inherit ParentEntry's
+ // old B-Tree down pointer.)
+
+ // Set up EntryToPromote.
+
+ memmove( EntryToPromote, CurrentEntry, CurrentEntry->cchThisEntry );
+ EntryToPromote->cchThisEntry += DOWNPOINTER_SIZE;
+ EntryToPromote->fFlags |= DF_BTP;
+ BTP(EntryToPromote) = BTP(ParentEntry);
+
+ // Now open up space in SecondEntry for the entries it
+ // will receive.
+
+ memmove( (PBYTE)(SecondDirblk->GetFirstEntry()) + BytesToMove +
+ ParentEntry->cchThisEntry - DOWNPOINTER_SIZE,
+ SecondDirblk->GetFirstEntry(),
+ (size_t)(SecondDirblk->_pdb->offulFirstFree -
+ DIRBLK_HEADER_SIZE) );
+
+ SecondDirblk->_pdb->offulFirstFree +=
+ BytesToMove + ParentEntry->cchThisEntry - DOWNPOINTER_SIZE;
+
+
+ // If there are any entries in FirstDirblk after CurrentEntry,
+ // copy them into SecondDirblk.
+
+ memmove( SecondDirblk->GetFirstEntry(),
+ NEXT_ENTRY(CurrentEntry),
+ BytesToMove );
+
+ // Now we copy ParentEntry (less its downpointer) into
+ // SecondDirblk after the entries from FirstDirblk, and
+ // strip off its B-Tree pointer after it gets there.
+
+ InsertPoint = (PDIRENTD)((PBYTE)SecondDirblk->GetFirstEntry() +
+ BytesToMove);
+
+ memmove( InsertPoint,
+ ParentEntry,
+ ParentEntry->cchThisEntry - DOWNPOINTER_SIZE );
+
+ InsertPoint->cchThisEntry -= DOWNPOINTER_SIZE;
+ InsertPoint->fFlags &= ~DF_BTP;
+
+ // OK, we're done with SecondDirblk. Now we move the end entry
+ // of FirstDirblk down.
+
+ FirstDirblk->_pdb->offulFirstFree -= BytesToMove +
+ CurrentEntry->cchThisEntry;
+
+ memmove( CurrentEntry,
+ (PBYTE)(NEXT_ENTRY(CurrentEntry)) + BytesToMove,
+ LeafEndEntrySize );
+
+ DebugAssert( CurrentEntry->fFlags & DF_END );
+
+ // That takes care of FirstDirblk, too.
+ }
+
+
+ // OK, we've modified FirstDirblk and SecondDirblk, and
+ // we're ready to insert EntryToPromote into ParentDirblk.
+ // (We don't need to mark ParentDirblk as modified, since
+ // it will get marked by InsertIntoDirblk).
+
+ FirstHeader->MarkModified();
+ SecondHeader->MarkModified();
+
+ // Remove the parent entry from the parent directory block
+ // by moving everything after it down over it. (Adjust
+ // the offset-of-first-free-byte first, while we still
+ // know how much we're losing.)
+
+ ParentDirblk->_pdb->offulFirstFree -= ParentEntry->cchThisEntry;
+
+ memmove(ParentEntry,
+ NEXT_ENTRY(ParentEntry),
+ (size_t)(DIRBLK_SIZE -
+ ParentDirblk->QueryEntryOffset(NEXT_ENTRY(ParentEntry))) );
+
+ return( InsertIntoDirblk( EntryToPromote,
+ ParentDirblk,
+ ParentHeader,
+ (PBYTE)ParentEntry ) );
+}
+
+
+
+BOOLEAN
+HPFS_DIRECTORY_TREE::Adjust(
+ PDIRBLK_CACHE_ELEMENT TargetHeader,
+ PDIRBLK TargetDirblk
+ )
+/*++
+
+Routine Description:
+
+ Juggles dirblks to ensure that none are left empty.
+
+Arguments:
+
+ TargetHeader -- supplies the cache element associated with the
+ Dirblk to be adjusted.
+ TargetDirblk -- supplies the Dirblk to be adjusted.
+
+Return Value:
+
+ TRUE on successful completion
+
+Notes:
+
+ We always adjust a leaf block. The caller is responsible for
+ updating the FNode, if necessary .
+
+--*/
+{
+ PDIRBLK_CACHE_ELEMENT ParentHeader, PrevHeader, NextHeader;
+ PDIRBLK ParentDirblk, PrevDirblk, NextDirblk;
+ PDIRENTD ParentEntry, PrevEntry, NextEntry;
+ LBN TargetLbn;
+
+ DebugAssert( TargetDirblk == TargetHeader->GetDirblk() );
+ DebugAssert( TargetDirblk->GetFirstEntry()->fFlags & DF_END );
+ DebugAssert( !(TargetDirblk->GetFirstEntry()->fFlags & DF_BTP) );
+
+ if( !TargetDirblk->IsEmpty() ) {
+
+ // The dirblk isn't empty--don't mess with it.
+ return TRUE;
+ }
+
+ // If this is the root dirblk, then we just eliminate a level
+ // of the tree. Note that there must always be at least one
+ // entry in the tree (the special entry for . and ..); however,
+ // we'll gracefully handle the case that there are no entries
+ // in the tree by leaving a single, empty dirblk.
+
+ if( TargetDirblk->_pdb->culChange & 1 ) {
+
+ // It's the root.
+
+ if( !( TargetDirblk->GetFirstEntry()->fFlags & DF_BTP ) ) {
+
+ // this tree is messed up--it's completely empty.
+ // let's leave it alone.
+ return TRUE;
+ }
+
+ _RootDirblkLbn = BTP( TargetDirblk->GetFirstEntry() );
+
+ TargetDirblk->_pdb->sig = 0;
+ _SuperArea->GetBitmap()->SetFree( TargetDirblk->QueryStartLbn(),
+ SectorsPerDirblk );
+
+ TargetHeader->MarkModified();
+ TargetHeader->Flush();
+
+ return TRUE;
+ }
+
+ // Get the parent dirblk, and find the entry in that block which is
+ // the parent of TargetDirblk. This will also allow us to find
+ // the entry that precedes that parent (PrevEntry) and the
+ // entry that follows it (NextEntry).
+
+ ParentHeader = _Cache->GetCachedDirblk( TargetDirblk->_pdb->lbnParent );
+
+ if( ParentHeader == NULL ||
+ (ParentDirblk = ParentHeader->GetDirblk()) == NULL ) {
+
+ return FALSE;
+ }
+
+ TargetLbn = TargetDirblk->QueryStartLbn();
+
+ NextEntry = NULL;
+ PrevEntry = NULL;
+ ParentEntry = ParentDirblk->GetFirstEntry();
+
+ while( BTP(ParentEntry) != TargetLbn &&
+ !(ParentEntry->fFlags & DF_END) ) {
+
+ PrevEntry = ParentEntry;
+ ParentEntry = NEXT_ENTRY(ParentEntry);
+ }
+
+ if( BTP(ParentEntry) != TargetLbn ) {
+
+ // ERROR
+ return FALSE;
+ }
+
+ if( !(ParentEntry->fFlags & DF_END) ) {
+
+ NextEntry = NEXT_ENTRY(ParentEntry);
+ }
+
+
+ if( PrevEntry == NULL ) {
+
+ DebugAssert( NextEntry != NULL );
+
+ // We have to either balance or merge with the next leaf
+ // dirblk. We'll balance if we're sure it's big enough,
+ // otherwise we'll merge.
+
+ if( (NextHeader = _Cache->
+ GetCachedDirblk( BTP(NextEntry) )) == NULL ||
+ (NextDirblk = NextHeader->GetDirblk()) == NULL ) {
+
+ return FALSE;
+ }
+
+ if( NextDirblk->_pdb->offulFirstFree +
+ TargetDirblk->_pdb->offulFirstFree > MergeThreshhold ) {
+
+ return( Balance( TargetDirblk, TargetHeader,
+ NextDirblk, NextHeader,
+ ParentDirblk, ParentHeader,
+ ParentEntry) );
+
+ } else {
+
+ return( Merge( TargetDirblk, TargetHeader,
+ NextDirblk, NextHeader,
+ ParentDirblk, ParentHeader,
+ ParentEntry ) );
+ }
+
+ } else if ( NextEntry == NULL ) {
+
+ // We have to either balance or merge with the previous
+ // dirblk. We'll balance if we're sure it's big enough,
+ // otherwise we'll merge.
+
+ if( (PrevHeader = _Cache->
+ GetCachedDirblk( BTP(PrevEntry) )) == NULL ||
+ (PrevDirblk = PrevHeader->GetDirblk()) == NULL ) {
+
+ return FALSE;
+ }
+
+ if( PrevDirblk->_pdb->offulFirstFree +
+ TargetDirblk->_pdb->offulFirstFree > MergeThreshhold ) {
+
+ return( Balance( PrevDirblk, PrevHeader,
+ TargetDirblk, TargetHeader,
+ ParentDirblk, ParentHeader,
+ PrevEntry) );
+
+ } else {
+
+ return( Merge( PrevDirblk, PrevHeader,
+ TargetDirblk, TargetHeader,
+ ParentDirblk, ParentHeader,
+ PrevEntry ) );
+ }
+
+ } else {
+
+ // We have a choice. We'll balance if we can,
+ // otherwise we'll merge.
+
+ if( (NextHeader = _Cache->
+ GetCachedDirblk( BTP(NextEntry) )) == NULL ||
+ (NextDirblk = NextHeader->GetDirblk()) == NULL ||
+ (PrevHeader = _Cache->
+ GetCachedDirblk( BTP(PrevEntry) )) == NULL ||
+ (PrevDirblk = PrevHeader->GetDirblk()) == NULL ) {
+
+ return FALSE;
+ }
+
+ if( NextDirblk->_pdb->offulFirstFree +
+ TargetDirblk->_pdb->offulFirstFree > MergeThreshhold ) {
+
+ // We can balance with the next block
+
+ return( Balance( TargetDirblk, TargetHeader,
+ NextDirblk, NextHeader,
+ ParentDirblk, ParentHeader,
+ ParentEntry) );
+
+ } else if( PrevDirblk->_pdb->offulFirstFree +
+ TargetDirblk->_pdb->offulFirstFree > MergeThreshhold ) {
+
+ // We can balance with the previous block
+
+ return( Balance( PrevDirblk, PrevHeader,
+ TargetDirblk, TargetHeader,
+ ParentDirblk, ParentHeader,
+ PrevEntry) );
+
+ } else {
+
+ // We have to merge.
+
+ return( Merge( TargetDirblk, TargetHeader,
+ NextDirblk, NextHeader,
+ ParentDirblk, ParentHeader,
+ ParentEntry ) );
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+VOID
+HPFS_DIRECTORY_TREE::FreeDirblks(
+ LBN DirblkLbn
+ )
+/*++
+
+Routine Description:
+
+ Frees the specified DIRBLK and all its children. When a dirblk
+ is freed, its signature is wiped out and its sectors are marked
+ as free in the bitmap.
+
+Arguments:
+
+ DirblkLbn -- supplies the LBN of the dirblk who is the root of the
+ subtree being freed.
+
+Return Value:
+
+ None.
+
+Notes:
+
+ This operation is not likely to be as expensive as it looks,
+ since the DIRBLKS of the current tree are likely to be in the
+ cache.
+
+--*/
+{
+ PDIRBLK_CACHE_ELEMENT CurrentHeader;
+ PDIRBLK CurrentDirblk;
+ PDIRENTD CurrentEntry;
+
+ if( (CurrentHeader = _Cache->GetCachedDirblk( DirblkLbn )) != NULL ) {
+
+ CurrentDirblk = CurrentHeader->GetDirblk();
+ CurrentEntry = CurrentDirblk->GetFirstEntry();
+
+ if( CurrentDirblk->_pdb->sig != DirblkSignature ) {
+
+ // It's not a dirblk--don't bother with it.
+ return;
+ }
+
+ CurrentHeader->Hold();
+
+ while( TRUE ) {
+
+ if( CurrentEntry->fFlags & DF_BTP ) {
+
+ FreeDirblks( BTP(CurrentEntry) );
+ }
+
+ if( CurrentEntry->fFlags & DF_END ) {
+
+ break;
+ }
+
+ CurrentEntry = NEXT_ENTRY( CurrentEntry );
+ }
+
+ _SuperArea->GetBitmap()->SetFree( CurrentDirblk->QueryStartLbn(),
+ SectorsPerDirblk );
+ CurrentDirblk->_pdb->sig = 0;
+ CurrentHeader->MarkModified();
+ CurrentHeader->Flush();
+ CurrentHeader->Unhold();
+ }
+}
+
+
+
+BOOLEAN
+HPFS_DIRECTORY_TREE::SortFromDirblk(
+ LBN DirblkLbn,
+ HPFS_DIRECTORY_TREE* NewTree,
+ PDIRENTD Buffer
+ )
+/*++
+
+Routine Description:
+
+ Inserts all dirents with valid names in the dirblk lbn described
+ into the new tree, and then recurses into children.
+
+Arguments:
+
+ DirblkLbn -- supplies the lbn of the root of the subtree
+ from which directory entries will be copied
+ NewTree -- supplies the directory tree into which the entries
+ will be inserted
+ EntryBuffer -- supplies a buffer to use to copy dirents
+
+Return Value:
+
+ TRUE on successful completion
+
+Notes:
+
+ If a source dirblk is unreadable, then entries from that dirblk
+ (and its children) will be omitted.
+
+ Entries with invalid names are not copied--they are silently
+ omitted. (If they are part of the volume's logical directory tree,
+ their deletion was noted as the tree was traversed. If they
+ aren't, nobody will notice that they're gone.)
+
+ To avoid (slightly, but every bit counts) inserting in lexical
+ order, we copy all entries from the current dirblk, and then
+ recurse into all the children in order. Since even worst-case
+ lexical insertion isn't all that bad, we don't try anything
+ fancier.
+
+ Note that the source dirblk is not modified. Thus, if the sort
+ fails at some intermediate point, it can be safely abandoned.
+
+--*/
+{
+ HPFS_NAME CurrentName;
+ PDIRBLK_CACHE_ELEMENT CurrentHeader;
+ PDIRBLK CurrentDirblk;
+ PDIRENTD CurrentEntry;
+
+ if( (CurrentHeader = _Cache->GetCachedDirblk( DirblkLbn )) != NULL ) {
+
+ CurrentDirblk = CurrentHeader->GetDirblk();
+ CurrentEntry = CurrentDirblk->GetFirstEntry();
+
+ if( CurrentDirblk->_pdb->sig != DirblkSignature ) {
+
+ // It's not a dirblk--don't bother with it.
+ return TRUE;
+ }
+
+ CurrentHeader->Hold();
+
+ // Traverse the block, copying the entries into the new tree.
+ // Note that if an entry has a downpointer, it must be copied
+ // into the buffer so that the downpointer may be stripped.
+
+ // Note that we don't copy special entries, end entries, or
+ // entries with invalid names.
+
+ while( !(CurrentEntry->fFlags & DF_END) ) {
+
+ if( !(CurrentEntry->fFlags & DF_SPEC) ) {
+
+ // Note that since all we're going to do to this name
+ // is check it for validity, we don't need to supply
+ // the codepage information on initialization. (Checking
+ // for validity doesn't require converting the name to
+ // upper-case.)
+
+ if( !CurrentName.Initialize( CurrentEntry->cchName,
+ CurrentEntry->bName ) ) {
+
+ return FALSE;
+ }
+
+
+ if( CurrentName.IsValid( _SuperArea->GetCasemap(),
+ CurrentEntry->bCodePage ) ) {
+
+ // The name is valid, so we'll insert this entry
+ // into the new tree.
+
+ if( CurrentEntry->fFlags & DF_BTP ) {
+
+ // The entry has a downpointer, so we need to
+ // copy it to the buffer so we can strip off
+ // the downpointer.
+
+ memmove( Buffer,
+ CurrentEntry,
+ CurrentEntry->cchThisEntry) ;
+
+ Buffer->fFlags &= ~DF_BTP;
+ Buffer->cchThisEntry -= DOWNPOINTER_SIZE;
+
+ if( !NewTree->Insert( Buffer ) ) {
+
+ return FALSE;
+ }
+
+ } else {
+
+ // No modification needed--just copy directly.
+
+ if( !NewTree->Insert( CurrentEntry ) ) {
+
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ CurrentEntry = NEXT_ENTRY( CurrentEntry );
+ }
+
+
+ // Now go back and pick up the children.
+
+ CurrentEntry = CurrentDirblk->GetFirstEntry();
+
+ while( TRUE ) {
+
+ if( CurrentEntry->fFlags & DF_BTP ) {
+
+ SortFromDirblk( BTP(CurrentEntry), NewTree, Buffer );
+ }
+
+ if( CurrentEntry->fFlags & DF_END ) {
+
+ break;
+ }
+
+ CurrentEntry = NEXT_ENTRY( CurrentEntry );
+ }
+
+ CurrentHeader->Unhold();
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/uhpfs/src/entry.cxx b/private/utils/uhpfs/src/entry.cxx
new file mode 100644
index 000000000..92882f076
--- /dev/null
+++ b/private/utils/uhpfs/src/entry.cxx
@@ -0,0 +1,610 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ entry.cxx
+
+Abstract:
+
+ This module contains the main entry points for the HPFS utilities.
+ These are:
+
+ Chkdsk
+ Format
+ Recover
+
+Author:
+
+ Bill McJohn (billmc) 31-05-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "error.hxx"
+#include "fnode.hxx"
+#include "file.hxx"
+#include "filestrm.hxx"
+#include "hpfsvol.hxx"
+#include "path.hxx"
+#include "system.hxx"
+#include "wstring.hxx"
+#include "ifssys.hxx"
+#include "dir.hxx"
+
+extern "C" {
+ #include "nturtl.h"
+}
+
+#include "message.hxx"
+#include "rtmsg.h"
+#include "ifsserv.hxx"
+
+const ULONG ChunkSize = 64;
+
+BOOLEAN
+SafeCopyFile(
+ IN PPATH SrcFilePath,
+ IN PMESSAGE Message,
+ IN OUT PNUMBER_SET BadBlocks,
+ IN PFNODE Fnode
+);
+
+BOOLEAN
+FAR APIENTRY
+Chkdsk(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Fix,
+ IN BOOLEAN Verbose,
+ IN BOOLEAN OnlyIfDirty,
+ IN BOOLEAN Recover,
+ IN PPATH PathToCheck,
+ OUT PULONG ExitStatus
+ )
+/*++
+
+Routine Description:
+
+ Check an HPFS volume.
+
+Arguments:
+
+ DosDrivName supplies the name of the drive to check
+ Message supplies an outlet for messages
+ Fix TRUE if Chkdsk should fix errors
+ Verbose TRUE if Chkdsk should list every file it finds
+ OnlyIfDirty TRUE if the drive should be checked only if
+ it is dirty
+ Recover TRUE if the drive should be checked everywhere
+ for bad sectors
+ PathToCheck Supplies a path to files Chkdsk should check for
+ contiguity (Note that HFPS ignores this parameter.)
+
+Return Value:
+
+ TRUE if successful.
+
+--*/
+{
+ HPFS_VOL HpfsVol;
+ ULONG exit_status;
+
+ if (NULL == ExitStatus) {
+ ExitStatus = &exit_status;
+ }
+
+ if (Recover) {
+ Message->Set(MSG_HPFS_CHKDSK_NO_RECOVER_MODE);
+ Message->Display();
+ return FALSE;
+ }
+
+ if( !HpfsVol.Initialize( NtDriveName, Message )) {
+
+ return FALSE;
+ }
+
+ if (Fix && !HpfsVol.Lock()) {
+
+ // The client wants to fix the drive, but we can't lock it.
+ // Offer to fix it on next reboot.
+ //
+ Message->Set(MSG_CHKDSK_ON_REBOOT_PROMPT);
+ Message->Display("");
+
+ if( Message->IsYesResponse( FALSE ) ) {
+
+ if( HpfsVol.ForceAutochk( Recover, NtDriveName ) ) {
+
+ Message->Set(MSG_CHKDSK_SCHEDULED);
+ Message->Display();
+
+ } else {
+
+ Message->Set(MSG_CHKDSK_CANNOT_SCHEDULE);
+ Message->Display();
+ }
+ }
+
+ return FALSE;
+ }
+
+
+ return( HpfsVol.ChkDsk( Fix ? TotalFix : CheckOnly,
+ Message,
+ Verbose,
+ OnlyIfDirty,
+ Recover, Recover, ExitStatus ) );
+}
+
+
+BOOLEAN
+FAR APIENTRY
+Format(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Quick,
+ IN MEDIA_TYPE MediaType,
+ IN PCWSTRING LabelString,
+ IN ULONG ClusterSize
+ )
+/*++
+
+Routine Description:
+
+ This function formats an HPFS volume.
+
+Arguments:
+
+ NtDriveName -- supplies the NT name of the volume to format.
+ Message -- supplies a channel for output.
+ Quick -- supplies a flag which, if TRUE, indicates that
+ the low-level format should be skipped.
+ MediaType -- supplies the volume media type.
+ LabelString -- supplies the volume label.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ DP_DRIVE DpDrive;
+ HPFS_VOL HpfsVol;
+
+ if (!DpDrive.Initialize( NtDriveName, Message )) {
+
+ return FALSE;
+ }
+
+ if (DpDrive.IsRemovable()) {
+
+ Message->Set(MSG_HPFS_FORMAT_NO_FLOPPIES);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (DpDrive.QuerySectorSize() > 512) {
+
+ Message->Set(MSG_HPFS_FORMAT_BAD_SECTOR_SIZE);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (ClusterSize) {
+ Message->Set(MSG_FMT_VARIABLE_CLUSTERS_NOT_SUPPORTED);
+ Message->Display("%s", "HPFS");
+ return FALSE;
+ }
+
+ if( !HpfsVol.Initialize( NtDriveName, Message, FALSE, !Quick, MediaType ) ) {
+
+ return FALSE;
+ }
+
+ return( HpfsVol.Format( LabelString, Message, ClusterSize ) );
+}
+
+
+BOOLEAN
+FAR APIENTRY
+Recover(
+ IN PPATH RecFilePath,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ Recover a file on a HPFS volume. Method: copy the source file to
+ a temporary file. If a bad sector is encountered in src file,
+ write a sector of nulls in temp file and add the sector number to
+ the bad block list.
+
+Arguments:
+
+ RecFilePath -- supplies the path to the file to recover.
+ Message -- supplies a channel for output.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ HPFS_VOL HpfsVol;
+ NUMBER_SET BadBlocks;
+ PFNODE Fnode = NULL;
+ PWSTRING DosDrive = NULL;
+ PHPFS_SA HpfsSa = NULL;
+ DSTRING NtDrive;
+#if DBG==1
+ BOOLEAN DoCopy = TRUE;
+#endif
+
+
+ DosDrive = RecFilePath->QueryDevice();
+ if( !DosDrive
+ || !IFS_SYSTEM::DosDriveNameToNtDriveName( DosDrive, &NtDrive ) ) {
+
+ // couldn't get drive name
+ DebugPrint( "recover: couldn't get drive name\n" );
+
+ Message->Set( MSG_INVALID_DRIVE );
+ Message->Display("");
+ DELETE( DosDrive );
+ return FALSE;
+ }
+
+ Message->Set( MSG_RECOV_BEGIN );
+ Message->Display( "%W", DosDrive );
+ Message->WaitForUserSignal();
+
+ if( !HpfsVol.Initialize( &NtDrive, Message ) ) {
+ DebugPrint( "recover: couldn't init volume\n" );
+
+ DELETE( DosDrive );
+ return FALSE;
+ }
+
+ if( (HpfsSa = HpfsVol.GetHPFSSuperArea()) == NULL
+ || !BadBlocks.Initialize() ) {
+
+ DebugPrint( "recover: couldn't get SA or init BadBlockList\n" );
+
+ Message->Set( MSG_RECOV_INTERNAL_ERROR );
+ Message->Display("");
+ DELETE( DosDrive );
+ return FALSE;
+ }
+
+
+#if DBG==1
+ if( DoCopy ) {
+#endif
+
+ //
+ // - get FNODE
+ //
+ if( (Fnode = HpfsSa->QueryFnodeFromName( RecFilePath, Message )) == NULL ) {
+
+ // file does not exist?
+
+ DebugPrint( "couldn't find fnode for path - doesn't exist?\n" );
+ DELETE( DosDrive );
+ return FALSE;
+ }
+
+ //
+ // - copies file to temp
+ // - if read fails, record logical
+ //
+ if( !SafeCopyFile( RecFilePath, Message, &BadBlocks, Fnode ) ) {
+
+ // copy failed for some reason
+
+ DebugPrint( "recover: safe copy failed\n" );
+ DELETE( DosDrive );
+ DELETE( Fnode );
+ return FALSE;
+ }
+
+#if DBG==1
+ } else {
+ BadBlocks.Add( 22080 );
+ BadBlocks.Add( 22147 );
+ BadBlocks.Add( 22216 );
+ }
+#endif
+
+ //
+ // - if read errors update BadBlock list
+ //
+ if( BadBlocks.QueryCardinality() > 0 ) {
+ //
+ // - open and lock the disk DASD
+ //
+ if( !HpfsVol.Lock() ) {
+
+ // can't lock disk
+
+ DebugPrint( "can't lock disk\n" );
+
+ Message->Set( MSG_CANT_LOCK_THE_DRIVE );
+ Message->Display("");
+ return FALSE;
+ }
+
+ if( !HpfsSa->AddBadBlocks( &BadBlocks, Message ) ) {
+
+ // error adding bad blocks
+
+ DebugPrint( "recover: error adding bad blocks\n" );
+ DELETE( DosDrive );
+ DELETE( Fnode );
+ return FALSE;
+ } // else {
+ // DebugPrint( "recover: added bad blocks successfully\n" );
+ // }
+ } // else {
+ // DebugPrint( "recover: no bad blocks found\n" );
+ // }
+
+ DELETE( DosDrive );
+ DELETE( Fnode );
+ return TRUE;
+}
+
+
+BOOLEAN
+SafeCopyFile(
+ IN PPATH SrcFilePath,
+ IN PMESSAGE Message,
+ IN OUT PNUMBER_SET BadBlocks,
+ IN PFNODE Fnode
+)
+/*++
+
+Routine Description:
+
+ Copies SrcFile to TmpFile. Any bad sector numbers (logical) are
+ added to the BadBlocks container.
+
+Arguments:
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PFSN_DIRECTORY SrcFSNDirectory = NULL;
+ PFSN_FILE SrcFSNFile = NULL;
+ PFSN_FILE TmpFSNFile = NULL;
+ PFILE_STREAM SrcStream = NULL;
+ PFILE_STREAM TmpStream = NULL;
+ BOOLEAN InChunks = TRUE;
+ PBYTE Buffer = NULL;
+ LBN PhysSec;
+ ULONG BytesRead;
+ ULONG BytesWritten;
+ ULONG BytesInFile;
+ ULONG LogicalSec = 0;
+ PATH PathLocation;
+ DSTRING Prefix;
+ PATH SavePath;
+ PWSTRING Location;
+
+
+ // Check to see if the source is a directory. (HPFS cannot recover
+ // directories.)
+
+ if( (SrcFSNDirectory = SYSTEM::QueryDirectory( SrcFilePath )) != NULL ) {
+
+ // The source path is a directory.
+
+ DELETE( SrcFSNDirectory );
+ Message->Set( MSG_HPFS_RECOVER_DIRECTORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( (Buffer = (PBYTE)MALLOC( cbSector*ChunkSize )) == NULL ) {
+
+ // error: out of memory
+ DebugPrint( "recover: can't allocate buffer for copy\n" );
+ Message->Set( MSG_INSUFFICIENT_MEMORY );
+ Message->Display("");
+ return FALSE;
+ }
+
+ // - get an FSN_FILE from SYSTEM:: for the source file and the destination
+ // file (ie. the temporary file)
+ // - for the tmp file, pass a location and a prefix
+ // - query a stream for each of source and destination
+
+ if( (SrcFSNFile = SYSTEM::QueryFile( SrcFilePath )) == NULL
+ || (Location = SrcFilePath->QueryPrefix()) == NULL
+ || !( PathLocation.Initialize( Location ))
+ || !Prefix.Initialize( "rec" )
+ || (TmpFSNFile = SYSTEM::MakeTemporaryFile( &Prefix, &PathLocation )) == NULL
+ || (SrcStream = SrcFSNFile->QueryStream( READ_ACCESS )) == NULL
+ || (TmpStream = TmpFSNFile->QueryStream( WRITE_ACCESS )) == NULL ) {
+
+ DebugPrint( "recover: error init'ing files for copy\n" );
+ Message->Set( MSG_INSUFFICIENT_MEMORY );
+ Message->Display("");
+ FREE( Buffer );
+ DELETE( Location );
+ DELETE( SrcFSNFile );
+ DELETE( TmpFSNFile );
+ DELETE( SrcStream );
+ DELETE( TmpStream );
+ return FALSE;
+ }
+
+ DELETE( Location );
+
+ if( SrcFSNFile->IsArchived() ) {
+ TmpFSNFile->MakeArchived();
+ }
+
+ if( SrcFSNFile->IsHidden() ) {
+ TmpFSNFile->MakeHidden();
+ }
+
+ if( SrcFSNFile->IsNormal() ) {
+ TmpFSNFile->MakeNormal();
+ }
+
+ if( SrcFSNFile->IsReadOnly() ) {
+ TmpFSNFile->MakeReadOnly();
+ }
+
+ if( SrcFSNFile->IsSystem() ) {
+ TmpFSNFile->MakeSystem();
+ }
+
+ TmpFSNFile->SetTimeInfo( SrcFSNFile->QueryTimeInfo( FSN_TIME_MODIFIED ),
+ FSN_TIME_MODIFIED );
+ TmpFSNFile->SetTimeInfo( SrcFSNFile->QueryTimeInfo( FSN_TIME_CREATED ),
+ FSN_TIME_CREATED );
+ TmpFSNFile->SetTimeInfo( SrcFSNFile->QueryTimeInfo( FSN_TIME_ACCESSED ),
+ FSN_TIME_ACCESSED );
+
+ //
+ // the following loop reads the source file in either:
+ // Chunk-mode - 'ChunkSize' sectors at a time (32K)
+ // or Sector-mode - single sectors
+ //
+ // if we can't read a 'chunk' then try reading the chunk on a
+ // sector by sector basis
+ //
+ // if we can read a 'chunk' then write it out
+ //
+ while( !SrcStream->IsAtEnd() ) {
+ if( !SrcStream->Read( Buffer, (InChunks)
+ ? cbSector*ChunkSize
+ : cbSector, &BytesRead ) ) {
+ //
+ // - read failed
+ // - if reading in chunks then
+ // - start reading in sectors
+ // - set the file pointer back to beginning of chunk
+ // - otherwise it's a bad sector
+ // - record it
+ // - set buffer to nulls
+ // - advance pointer to next sector
+ //
+ if( InChunks ) {
+ InChunks = FALSE;
+ SrcStream->MovePointerPosition( LogicalSec * cbSector,
+ STREAM_BEGINNING );
+ continue;
+ } else {
+ // - convert logical sector to physical
+ PhysSec = Fnode->QueryPhysicalLbn( LogicalSec, &PhysSec );
+ BadBlocks->Add( (int)PhysSec );
+
+ memset( Buffer, 0, cbSector );
+ BytesRead = cbSector;
+ SrcStream->MovePointerPosition( cbSector,
+ STREAM_CURRENT );
+ }
+
+ } // else if( BytesRead < cbSector ) {
+
+ // AtEndOfFile
+
+ // DebugPrint( (InChunks) ? "E" : "e" );
+ //} else {
+ // DebugPrint( (InChunks) ? "R" : "r" );
+ //}
+
+ // - if we encounter a write failure then
+ // - delete the temporary file created
+ // - return error
+
+ if( !TmpStream->Write( Buffer, BytesRead, &BytesWritten ) ) {
+
+ DebugPrint( "recover: write failed - returning false\n" );
+ Message->Set( MSG_RECOV_WRITE_ERROR );
+ Message->Display("");
+
+ if( !SYSTEM::RemoveNode( (PFSNODE*) &SrcFSNFile, TRUE ) ) {
+ DebugPrint( "recover: delete file failed\n" );
+ }
+
+ FREE( Buffer );
+ DELETE( SrcFSNFile );
+ DELETE( TmpFSNFile );
+ DELETE( SrcStream );
+ DELETE( TmpStream );
+ return( FALSE );
+
+ } // else {
+ // DebugPrint( (InChunks) ? "W" : "w" );
+ // }
+
+ //
+ // - bump up the Logical sector counter
+ // - if the counter is on a 'chunk' boundary, then we have finished
+ // reading sector-by-sector so go back to 'chunk-mode'
+ //
+ if( !SrcStream->IsAtEnd() ) {
+ if( InChunks ) {
+ LogicalSec += ChunkSize;
+ } else {
+ LogicalSec++;
+ if( LogicalSec % ChunkSize == 0 ) {
+ InChunks = TRUE;
+ }
+ }
+ }
+
+ }
+ // DebugPrint( "\n" );
+
+ BytesInFile = LogicalSec * cbSector + BytesRead;
+ Message->Set( MSG_RECOV_BYTES_RECOVERED );
+ Message->Display( "%d%d", BytesInFile -
+ BadBlocks->QueryCardinality().GetLowPart() *
+ cbSector,
+ BytesInFile );
+
+ // - close streams before trying to delete and move
+
+ DELETE( SrcStream );
+ DELETE( TmpStream );
+
+ // - get name from SrcFSNFile
+ // - delete SrcFSNFile (actually deletes file)
+ // - rename TmpFSNFile to the the saved name
+
+ SavePath = *SrcFSNFile->GetPath();
+ if( !SYSTEM::RemoveNode( (PFSNODE*)&SrcFSNFile, TRUE ) ) {
+ DebugPrint( "recover: delete file failed\n" );
+ }
+ if( !TmpFSNFile->Rename( &SavePath ) ) {
+ DebugPrint( "recover: move file failed\n" );
+ }
+
+ FREE( Buffer );
+ DELETE( SrcFSNFile );
+ DELETE( TmpFSNFile );
+ return( TRUE );
+}
diff --git a/private/utils/uhpfs/src/fnode.cxx b/private/utils/uhpfs/src/fnode.cxx
new file mode 100644
index 000000000..fbaf099ce
--- /dev/null
+++ b/private/utils/uhpfs/src/fnode.cxx
@@ -0,0 +1,1543 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ fnode.cxx
+
+Abstract:
+
+ This module contains member function definitions for the FNODE
+ object, which models an HPFS file or directory FNode.
+
+Author:
+
+ Bill McJohn (billmc) 01-Dec-1990
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "bitmap.hxx"
+#include "defer.hxx"
+#include "dirblk.hxx"
+#include "error.hxx"
+#include "hotfix.hxx"
+#include "hpcensus.hxx"
+#include "fnode.hxx"
+#include "hpfsacl.hxx"
+#include "hpfseal.hxx"
+#include "hpfsname.hxx"
+#include "hpfssa.hxx"
+#include "orphan.hxx"
+#include "badblk.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( FNODE, SECRUN, UHPFS_EXPORT );
+
+VOID
+FNODE::Construct (
+ )
+
+{
+ p_fn = NULL;
+ _Drive = NULL;
+ _IsModified = FALSE;
+}
+
+
+UHPFS_EXPORT
+FNODE::~FNODE(
+ )
+{
+ Destroy();
+}
+
+
+UHPFS_EXPORT
+BOOLEAN
+FNODE::Initialize(
+ LOG_IO_DP_DRIVE* Drive,
+ LBN Lbn
+ )
+/*++
+
+Routine Description:
+
+ Initialize an FNODE object.
+
+Arguments:
+
+ Drive -- supplies the drive on which the FNODE resides
+ Lbn -- supplies the LBN of the FNODE.
+
+--*/
+{
+ Destroy();
+
+ _Drive = Drive;
+
+ if( !_buf.Initialize() ||
+ !SECRUN::Initialize( &_buf, Drive, Lbn, SectorsPerFnode ) ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ p_fn = (_FNODE*)GetBuf();
+
+ if( p_fn == NULL ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ _IsModified = FALSE;
+
+ return TRUE;
+}
+
+
+
+VOID
+FNODE::Destroy (
+ )
+/*++
+
+Routine Description:
+
+ Clean up an FNODE, to reinitialize or discard it.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ p_fn = NULL;
+ _Drive = NULL;
+
+ _IsModified = FALSE;
+}
+
+
+
+
+BOOLEAN
+FNODE::CreateRoot(
+ IN LBN DirblkLbn
+ )
+/*++
+
+Routine Description:
+
+ Create an fnode for a directory.
+
+Arguments:
+
+ DirblkLbn -- supplies the LBN of the directory's root dirblk
+
+Return Value:
+
+ TRUE upon successful completion.
+--*/
+{
+ // Check state of object.
+ if (!p_fn) {
+ perrstk->push(ERR_FN_PARAMETER, QueryClassId());
+ return FALSE;
+ }
+
+ memset( p_fn, '\0', sizeof( _FNODE ) );
+
+ // Set signature.
+ p_fn->_fni.sig = FnodeSignature;
+
+ // Set histories to 0.
+ p_fn->_fni.ulSRHist = 0;
+ p_fn->_fni.ulFRHist = 0;
+
+ // Make self the containing directory.
+ p_fn->_fni.lbnContDir = QueryStartLbn();
+
+ // Set low bit of flag byte to indicate a directory.
+ p_fn->_fni.bFlag = FNF_DIR;
+
+ // Set offset into the FNODE of the first access control entry.
+ p_fn->_fni.usACLBase = (USHORT)(&p_fn->abFree[0] - (BYTE*) p_fn);
+
+ // Set number of "need" EA's.
+ p_fn->_fni.ulRefCount = 0;
+
+ // Set filestorage information.
+ p_fn->_fni.fn_store.alblk.bFlag = 0;
+ p_fn->_fni.fn_store.alblk.cFree = LeavesPerFnode - 1;
+ p_fn->_fni.fn_store.alblk.cUsed = 1;
+ p_fn->_fni.fn_store.alblk.oFree = sizeof(ALBLK) + sizeof(ALLEAF);
+
+ // Set the location of the file on disk.
+ p_fn->_fni.fn_store.a.alleaf[0].lbnLog = 0;
+ p_fn->_fni.fn_store.a.alleaf[0].csecRun = 0;
+ p_fn->_fni.fn_store.a.alleaf[0].lbnPhys = DirblkLbn;
+
+ p_fn->_fni.fn_store.a.alleaf[1].lbnLog = (LBN) -1;
+ p_fn->_fni.fn_store.a.alleaf[1].csecRun = 0;
+ p_fn->_fni.fn_store.a.alleaf[1].lbnPhys = 0;
+
+ return TRUE;
+}
+
+
+BOOLEAN
+FNODE::CreateFile(
+ IN LBN ParentFnodeLbn
+ )
+/*++
+
+Routine Description:
+
+ Creates an FNode for an empty file.
+
+Arguments:
+
+ ParentFnodeLbn -- LBN of the parent directory's Fnode
+
+Return Value:
+
+ TRUE on successful completion.
+
+--*/
+{
+ DebugPtrAssert( p_fn );
+
+ memset( p_fn, 0, sizeof( _FNODE ) );
+
+ // Set the signature and parent directory:
+ //
+ p_fn->_fni.sig = FnodeSignature;
+ p_fn->_fni.lbnContDir = ParentFnodeLbn;
+
+ // Set offset into the FNODE of the first access control entry.
+ //
+ p_fn->_fni.usACLBase = (USHORT)(&p_fn->abFree[0] - (BYTE*) p_fn);
+
+ // Set up the storage information:
+ //
+ p_fn->_fni.fn_store.alblk.bFlag = 0;
+ p_fn->_fni.fn_store.alblk.cFree = LeavesPerFnode;
+ p_fn->_fni.fn_store.alblk.cUsed = 0;
+ p_fn->_fni.fn_store.alblk.oFree = sizeof(ALBLK);
+
+ return TRUE;
+}
+
+
+BOOLEAN
+FNODE::CreateNode(
+ IN LBN ParentFnodeLbn,
+ IN LBN AlsecLbn,
+ IN ULONG FileSize
+ )
+/*++
+
+Routine Description:
+
+ Creates an FNode that points at an allocation sector
+
+Arguments:
+
+ ParentFnodeLbn -- LBN of the parent directory's Fnode
+ AlsecLbn -- LBN of the allocation sector
+ FileSize -- size of allocation claimed by allocation sector
+
+Return Value:
+
+ TRUE on successful completion.
+
+--*/
+{
+ // Check state of object.
+ if (!p_fn) {
+ perrstk->push(ERR_FN_PARAMETER, QueryClassId());
+ return FALSE;
+ }
+
+ memset( p_fn, '\0', sizeof( _FNODE ) );
+
+ // Set signature.
+ p_fn->_fni.sig = FnodeSignature;
+
+
+ // Make self the containing directory.
+ p_fn->_fni.lbnContDir = ParentFnodeLbn;
+
+ p_fn->_fni.ulVlen = FileSize;
+
+ // Set offset into the FNODE of the first access control entry.
+ p_fn->_fni.usACLBase = (USHORT)(&p_fn->abFree[0] - (BYTE*) p_fn);
+
+ // Set filestorage information.
+ p_fn->_fni.fn_store.alblk.bFlag = ABF_NODE;
+ p_fn->_fni.fn_store.alblk.cFree = NodesPerFnode - 1;
+ p_fn->_fni.fn_store.alblk.cUsed = 1;
+ p_fn->_fni.fn_store.alblk.oFree = sizeof(ALBLK) + sizeof(ALNODE);
+
+ p_fn->_fni.fn_store.a.alnode[0].lbnLog = (LBN) -1;
+ p_fn->_fni.fn_store.a.alnode[0].lbnPhys = AlsecLbn;
+
+ return TRUE;
+}
+
+
+
+VERIFY_RETURN_CODE
+FNODE::VerifyAndFix(
+ IN PHPFS_SA SuperArea,
+ IN PDEFERRED_ACTIONS_LIST DeferredActions,
+ IN PHPFS_PATH CurrentPath,
+ IN LBN ExpectedParentLbn,
+ IN BOOLEAN IsDir,
+ IN OUT PULONG DirentFileSize,
+ OUT PULONG EaSize,
+ IN PMESSAGE Message,
+ IN OUT PBOOLEAN ErrorsDetected,
+ IN BOOLEAN UpdateAllowed,
+ IN BOOLEAN Verbose,
+ IN PHPFS_ORPHANS OrphansList
+ )
+/*++
+
+Description of Routine:
+
+ Verify an FNode and its descendants.
+
+Arguments:
+
+ SuperArea -- supplies the superarea for the volume
+ being verified.
+ DeferredActions -- supplies the deferred actions list for this
+ pass of Chkdsk
+ CurrentPath -- Current Path to this FNode (NULL if
+ recovering orphans)
+ ExpectedParentLbn -- LBN of the DIRBLK which contains the parent DIRENT.
+ (zero if unknown).
+ IsDir -- TRUE if this is the FNode of a subdirectory
+ FALSE if it is a file FNode.
+ DirentFileSize -- supplies the file size in the parent DIRENT;
+ receives corrected value
+ EaSize -- receives the size of EAs for this FNode
+ Message -- supplies an outlet for messages
+ *ErrorsDetected -- receives TRUE if an error is detected which does
+ generate a message
+ UpdateAllowed -- supplies a flag indicating whether corrections
+ should be written to disk.
+ Verbose -- supplies a flag indicating whether all files
+ encountered should be displayed
+ OrphansList -- supplies a list of previously-recovered orphans that
+ may be claimed as children. (May be NULL).
+
+Return Value:
+
+ A verify return code indicating the state of the FNode:
+
+ VERIFY_STRUCTURE_OK -- the FNode is OK. (It may have been fixed.)
+
+ VERIFY_STRUCTURE_INVALID -- the FNode is corrupt, and should
+ be removed.
+
+ VERIFY_INSUFFICIENT_RESOURCES -- the program could not allocate
+ enough memory to check the FNode.
+
+Notes:
+
+ During the orphan recovery phase, CurrentPath is NULL, OrphansList
+ may be non-NULL, and ExpectedParentLbn may be zero.
+
+--*/
+{
+
+ HPFS_EA_LIST EaList;
+ HPFS_ACL AccessControlList;
+ LBN NextSectorNumber;
+ ULONG SectorSize;
+ ULONG AllocatedFileSize;
+ VERIFY_RETURN_CODE erc;
+ DIRBLK ChildDirblk;
+ HPFS_NAME PreviousName;
+ LBN DirblkLbn;
+ ULONG LeafDepth;
+ USHORT MinimumAclBase;
+
+
+ // Check that the sector is not crosslinked, read it and
+ // check its signature, and mark it in the bitmap as allocated
+
+ if( !SuperArea->GetBitmap()->IsFree( QueryStartLbn(), SectorsPerFnode ) ) {
+
+ // The FNode is cross-linked.
+ DebugPrintf( "Crosslinked FNode at lbn %lx\n", QueryStartLbn() );
+ return VERIFY_STRUCTURE_INVALID;
+ }
+
+ if( !Read() ) {
+
+ // The FNode is unreadable.
+
+ DebugPrintf( "Unreadable FNode at lbn %lx\n", QueryStartLbn() ) ;
+ SuperArea->GetBitmap()->SetAllocated( QueryStartLbn(), SectorsPerFnode );
+ SuperArea->GetBadBlockList()->Add( QueryStartLbn() );
+ return VERIFY_STRUCTURE_INVALID;
+ }
+
+ if( p_fn->_fni.sig != FnodeSignature ) {
+
+ // This sector is not an FNode.
+ return VERIFY_STRUCTURE_INVALID;
+ }
+
+ SuperArea->GetBitmap()->SetAllocated( QueryStartLbn(), SectorsPerFnode );
+
+ if( ExpectedParentLbn != 0 &&
+ p_fn->_fni.lbnContDir != ExpectedParentLbn ) {
+
+ // The parent LBN field is incorrect; fix it in place.
+ // Of course, this change will only be written to disk
+ // if we have update authority.
+
+ *ErrorsDetected = TRUE;
+
+ if( CurrentPath != NULL ) {
+
+ DebugPrintf( "%s: changing FNode's lbnContDir to %lx\n",
+ (PCHAR)CurrentPath->GetString(),
+ ExpectedParentLbn );
+ }
+
+ MarkModified();
+ p_fn->_fni.lbnContDir = ExpectedParentLbn;
+ }
+
+ // Verify the storage structure. If this is a subdirectory
+ // Fnode, then the root dirblk must be consistent. If this
+ // is a file Fnode, then the file storage must be consistent.
+
+ if( IsDir ) {
+
+ // We expect this to be the FNode of a subdirectory
+
+ if( !(p_fn->_fni.bFlag & FNF_DIR ) ) {
+
+ // the flag is incorrectly set--fix it.
+
+ *ErrorsDetected = TRUE;
+
+ if( CurrentPath != NULL ) {
+
+ DebugPrintf( "%s: setting FNode's FNF_DIR bit\n",
+ (PCHAR)CurrentPath->GetString() );
+ }
+
+ MarkModified();
+ p_fn->_fni.bFlag |= FNF_DIR;
+ }
+
+ DirblkLbn = p_fn->_fni.fn_store.a.alleaf[0].lbnPhys;
+
+ if( SuperArea->GetHotfixList()->
+ IsInList( DirblkLbn, SectorsPerDirblk ) ) {
+
+ DeferredActions->AddHotfixedLbn( QueryStartLbn(),
+ DEFER_FNODE,
+ DEFER_DIRBLK );
+ }
+
+ if( ChildDirblk.Initialize(_Drive,
+ SuperArea->GetHotfixList(),
+ DirblkLbn) ) {
+
+ LeafDepth = 0;
+
+ erc = ChildDirblk.VerifyAndFix( SuperArea, DeferredActions,
+ CurrentPath, &PreviousName,
+ QueryStartLbn(),
+ QueryStartLbn(),
+ 0, &LeafDepth,
+ Message,
+ ErrorsDetected,
+ UpdateAllowed,
+ Verbose,
+ OrphansList );
+
+ if( erc == VERIFY_STRUCTURE_INVALID ) {
+
+ // The child dirblk didn't pan out. If there is
+ // an orphans list, check for the child there. If
+ // that also fails, then this FNode is invalid.
+
+ if( OrphansList == NULL ||
+ !OrphansList->LookupDirblk( DirblkLbn,
+ QueryStartLbn(),
+ QueryStartLbn(),
+ UpdateAllowed ) ) {
+
+ SuperArea->GetBitmap()->SetFree( QueryStartLbn(),
+ SectorsPerFnode );
+ return VERIFY_STRUCTURE_INVALID;
+ }
+
+ } else if( erc == VERIFY_STRUCTURE_BADLY_ORDERED ) {
+
+ if( Message != NULL &&
+ CurrentPath != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_SORT );
+ Message->Display( "%s", CurrentPath->GetString() );
+ }
+ DeferredActions->AddDirectoryToSort( QueryStartLbn() );
+
+ } else if( erc != VERIFY_STRUCTURE_OK ) {
+
+ // An error occurred--send it back up
+
+ return erc;
+ }
+
+ } else {
+
+ // Couldn't initialize the child dirblk
+
+ return VERIFY_INSUFFICIENT_RESOURCES;
+ }
+
+ } else {
+
+ // We expect this to be the FNode of a file.
+
+ if( p_fn->_fni.bFlag & FNF_DIR ) {
+
+ // the flag is incorrectly set--fix it.
+
+ *ErrorsDetected = TRUE;
+
+ if( CurrentPath != NULL ) {
+
+ DebugPrint( (PCHAR)CurrentPath->GetString() );
+ DebugPrint( ": resetting FNode's FNF_DIR bit\n" );
+ }
+
+ MarkModified();
+ p_fn->_fni.bFlag &= ~FNF_DIR;
+ }
+
+ // Set up the storage object, and then ask it to verify itself.
+
+ if( !_Store.Initialize( _Drive,
+ (PSTORED)&(p_fn->_fni.fn_store ),
+ QueryStartLbn(),
+ TRUE ) ) {
+
+ // Couldn't initialize the storage object.
+
+ return VERIFY_INSUFFICIENT_RESOURCES;
+ }
+
+ NextSectorNumber = 0;
+
+ erc = _Store.VerifyAndFix ( SuperArea,
+ DeferredActions,
+ CurrentPath,
+ &NextSectorNumber,
+ Message,
+ ErrorsDetected,
+ UpdateAllowed,
+ OrphansList );
+
+ if ( erc != VERIFY_STRUCTURE_OK ) {
+
+ SuperArea->GetBitmap()->SetFree( QueryStartLbn(),
+ SectorsPerFnode );
+ return erc;
+ }
+
+ if( _Store.QueryModified() ) {
+
+ MarkModified();
+ }
+
+
+ // Check the file size fields: the three values which we must
+ // reconcile are the allocated length, the verified length
+ // (p_fn->_fni.ulVlen) and the length from the directory
+ // entry (*DirentFileSize). The rules are:
+ //
+ // - the verified length may not be greater than the dirent length
+ // - the allocated length must equal the dirent length, rounded
+ // up to a multiple of sector size.
+
+ SectorSize = _Drive->QuerySectorSize();
+ AllocatedFileSize = NextSectorNumber * SectorSize;
+
+ if( *DirentFileSize > AllocatedFileSize ) {
+
+ // The directory entry's file size is too big--trim it back
+
+ if( CurrentPath != NULL ) {
+
+ DebugPrint( (PCHAR)CurrentPath->GetString() );
+ DebugPrint( ": dirent file size is greater than allocated size.\n" );
+ }
+
+ *ErrorsDetected = TRUE;
+
+ *DirentFileSize = AllocatedFileSize;
+
+ } else if ( *DirentFileSize + SectorSize - 1 <
+ AllocatedFileSize ) {
+
+ // The file has more space allocated to it than the directory
+ // entry knows about. If the Verified length agrees with the
+ // directory entry, we'll truncate the allocation; otherwise,
+ // we'll bump the size in the directory entry.
+
+ if( CurrentPath != NULL ) {
+
+ DebugPrint( (PCHAR)CurrentPath->GetString() );
+ DebugPrint( ": dirent file size is less than allocated size.\n" );
+ }
+
+ *ErrorsDetected = TRUE;
+
+ if( *DirentFileSize == p_fn->_fni.ulVlen ) {
+
+ if( UpdateAllowed ) {
+
+ Truncate( (*DirentFileSize + SectorSize - 1)/
+ SectorSize );
+ }
+
+ } else {
+
+ *DirentFileSize = AllocatedFileSize;
+ }
+ }
+
+ if( p_fn->_fni.ulVlen > *DirentFileSize ) {
+
+ // The verified length cannot be greater than the actual
+ // length; fix in place.
+
+ *ErrorsDetected = TRUE;
+
+ if ( CurrentPath != NULL ) {
+
+ DebugPrintf( "%s: setting FNode verified length to %lx\n",
+ (PCHAR)CurrentPath->GetString(),
+ *DirentFileSize );
+ }
+
+ p_fn->_fni.ulVlen = *DirentFileSize;
+ MarkModified();
+ }
+ }
+
+
+ // Check the Access Control List
+
+ if( !AccessControlList.Initialize( _Drive, p_fn, QueryStartLbn() ) ) {
+
+ // Couldn't initialize the Access Control List
+
+ return VERIFY_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ // Check the ACL. Note that this always succeeds--if
+ // the ACL is not OK, the ACL object wipes it out, leaving
+ // a consistent structure behind one way or the other.
+ // It could give an internal error, but we'll just ignore
+ // that, since we can't do anything about it.
+ //
+ // Note also that the ACL object directly manipulates the
+ // FNode's data.
+
+ AccessControlList.VerifyAndFix( SuperArea,
+ DeferredActions,
+ CurrentPath,
+ Message,
+ ErrorsDetected,
+ UpdateAllowed,
+ OrphansList );
+
+ if( AccessControlList.QueryFnodeModified() ) {
+
+ MarkModified();
+ }
+ }
+
+ // Verify the value of usACLBase--if must be greater
+ // than or equal to the offset of the free space at
+ // the end of the FNODE.
+ //
+ MinimumAclBase = (USHORT)(&p_fn->abFree[0] - (BYTE*) p_fn);
+
+ if( p_fn->_fni.usACLBase < MinimumAclBase ||
+ p_fn->_fni.usACLBase > sizeof( _FNODE ) ) {
+
+ // usACLBase is invalid.
+ //
+ *ErrorsDetected = TRUE;
+
+ if( CurrentPath != NULL ) {
+
+ DebugPrint( (PCHAR)CurrentPath->GetString() );
+ DebugPrint( ": fixing ACL Base" );
+ }
+
+ MarkModified();
+ p_fn->_fni.usACLBase = MinimumAclBase;
+ }
+
+
+
+ // Check the Extended Attributes.
+
+ if( !EaList.Initialize( _Drive, p_fn, QueryStartLbn() ) ) {
+
+ // Couldn't initialize the EA List object
+
+ return VERIFY_INSUFFICIENT_RESOURCES;
+
+ } else {
+
+ // Verify the EA list. Like the ACL, the EA List object
+ // will directly modify the FNode data.
+
+ if( EaList.VerifyAndFix( SuperArea,
+ DeferredActions,
+ CurrentPath,
+ Message,
+ ErrorsDetected,
+ UpdateAllowed,
+ OrphansList ) ==
+ VERIFY_STRUCTURE_OK ) {
+
+ if( EaList.QueryFnodeModified() ) {
+
+ MarkModified();
+ }
+
+ if( p_fn->_fni.ulRefCount != EaList.QueryNumberOfNeedEas() ) {
+
+ *ErrorsDetected = TRUE;
+
+ if( CurrentPath != NULL ) {
+
+ DebugPrintf( "%s: setting FNode count of Need EAs to %lx\n",
+ (PCHAR)CurrentPath->GetString(),
+ EaList.QueryNumberOfNeedEas() );
+ }
+
+ p_fn->_fni.ulRefCount = EaList.QueryNumberOfNeedEas();
+ MarkModified();
+ }
+
+ // return the EA Size to the parent DirEnt.
+ *EaSize = EaList.QuerySizeOfEas();
+ }
+ }
+
+ if( IsModified() && UpdateAllowed ) {
+
+ Write();
+ }
+
+
+ if( IsDir ) {
+
+ DeferredActions->StatDirectory();
+
+ } else {
+
+ // For space taken up by user files, record the sectors
+ // allocated to the file plus one for the FNode.
+
+ DeferredActions->StatFile( AllocatedFileSize/SectorSize + 1 );
+ }
+
+
+ return VERIFY_STRUCTURE_OK;
+}
+
+
+UHPFS_EXPORT
+BOOLEAN
+FNODE::IsFnode(
+ )
+/*++
+
+Routine description:
+
+ Checks the signature of the FNode to make sure that this is
+ indeed an FNode.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the signature is the FNode signature.
+
+--*/
+{
+
+ return( p_fn->_fni.sig == FnodeSignature );
+}
+
+
+
+VOID
+FNODE::MarkModified(
+ )
+/*++
+
+Routine description:
+
+ Mark the FNode as modified, so that when it comes time to flush
+ it we know we'd like to write it.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ _IsModified = TRUE;
+}
+
+BOOLEAN
+FNODE::IsModified(
+ )
+/*++
+
+Routine description:
+
+ Query whether the FNode has been modified since our last I/O
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the FNode has been modified.
+
+--*/
+{
+ return _IsModified;
+}
+
+
+ULONG
+FNODE::QueryNumberOfNeedEas(
+ )
+/*++
+
+Routine description:
+
+ Query the number of need-EAs on the FNode.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of need-EAs we found on this FNode.
+
+Notes:
+
+ This value is meaningless unless the FNode has already passed
+ through a method like VerifyAndFix which traverses the EA list.
+
+--*/
+{
+ return p_fn->_fni.ulRefCount;
+}
+
+
+
+BOOLEAN
+FNODE::FindAndResolveHotfix(
+ IN PHPFS_SA SuperArea,
+ IN DEFERRED_SECTOR_TYPE ChildSectorType
+ )
+/*++
+
+Routine Description:
+
+ Examine this fnode's children of a specific type to find any
+ which are hotfixed, and resolve those references.
+
+Arguments:
+
+ SuperaArea -- supplies superarea for the volume
+ ChildSectorType -- indicates what sort of child is hotfixed
+
+Return Value:
+
+ TRUE on successful completion
+
+Notes:
+
+ The child types are:
+
+ dirblk -- this fnode must be a directory fnode. The only
+ child of interest is the directory's root dirblk.
+
+ store -- examine leaves. (If the fnode has node entries,
+ they would have been resolved on the fly.)
+
+ auxillary data -- EA and ACL data.
+
+--*/
+{
+
+ DIRBLK ChildDirblk;
+ HPFS_EA_LIST EaList;
+ HPFS_ACL AccessControlList;
+ LBN ChildLbn, NewLbn;
+ ULONG i;
+
+ if( !Read() || p_fn->_fni.sig != FnodeSignature ) {
+
+ // couldn't read it, or it's not an FNode
+ return FALSE;
+ }
+
+
+ switch ( ChildSectorType ) {
+
+ case DEFER_DIRBLK :
+
+ if( !(p_fn->_fni.bFlag & FNF_DIR ) ) {
+
+ // This is not a directory FNode--we can't resolve
+ // the hotfix.
+ return FALSE;
+ }
+
+ ChildLbn = p_fn->_fni.fn_store.a.alleaf[0].lbnPhys;
+
+ if( !ChildDirblk.Initialize( _Drive,
+ SuperArea->GetHotfixList(),
+ ChildLbn ) ||
+ !ChildDirblk.Read() ) {
+
+ return FALSE;
+ }
+
+ if( (NewLbn = SuperArea->GetBitmap()->AllocateDirblk() ) == 0 ) {
+
+ // can't allocate a new dirblk.
+ return FALSE;
+ }
+
+ ChildDirblk.Relocate( NewLbn );
+
+ if( !ChildDirblk.Write() ) {
+
+ // unable to relocate child.
+ return FALSE;
+ }
+
+ ChildDirblk.FixupChildren( SuperArea->GetHotfixList() );
+
+ p_fn->_fni.fn_store.a.alleaf[0].lbnPhys = NewLbn;
+
+ SuperArea->GetBitmap()->SetFree( ChildLbn, SectorsPerDirblk );
+
+ for( i = 0; i < SectorsPerDirblk; i++ ) {
+
+ SuperArea->GetHotfixList()->
+ ClearHotfix( ChildLbn + i, SuperArea );
+ }
+
+ Write();
+ return TRUE;
+
+ case DEFER_STORE :
+
+ // Set up the storage object, and let it deal with
+ // the deferred reference.
+
+ if( !_Store.Initialize( _Drive,
+ (PSTORED)&(p_fn->_fni.fn_store ),
+ QueryStartLbn(),
+ TRUE ) ||
+ !_Store.FindAndResolveHotfix( SuperArea, ChildSectorType ) ) {
+
+ return FALSE;
+ }
+
+ Write();
+ return TRUE;
+
+ case DEFER_ACL_DATA :
+
+ if( !AccessControlList.Initialize( _Drive,
+ p_fn,
+ QueryStartLbn() ) ||
+ !AccessControlList.FindAndResolveHotfix( SuperArea ) ) {
+
+ return FALSE;
+ }
+
+ if( AccessControlList.QueryFnodeModified() ) {
+
+ Write();
+ }
+
+ return TRUE;
+
+ case DEFER_EA_DATA :
+
+ if( !EaList.Initialize( _Drive, p_fn, QueryStartLbn() ) ||
+ !EaList.FindAndResolveHotfix( SuperArea ) ) {
+
+ return FALSE;
+ }
+
+ if( EaList.QueryFnodeModified() ) {
+
+ Write();
+ }
+
+ return TRUE;
+
+ default :
+
+ // Don't recognize this child type
+ return FALSE;
+ }
+}
+
+
+
+BOOLEAN
+FNODE::ResolveCrosslink(
+ IN PHPFS_SA SuperArea,
+ IN ULONG RunIndex
+ )
+/*++
+
+Routine Description:
+
+ Attempts to copy a crosslinked run
+
+Arguments:
+
+ SuperArea -- super area for the volume being fixed
+ RunIndex -- index in the storage object of the crosslinked run
+
+Return Value:
+
+ TRUE on successful completion
+
+--*/
+{
+
+ if( !Read() || p_fn->_fni.sig != FnodeSignature ) {
+
+ // couldn't read it, or it's not an FNode--can't resolve.
+ return FALSE;
+ }
+
+
+ // Set up the storage object, and let it deal with
+ // the deferred reference.
+
+ if( !_Store.Initialize( _Drive,
+ (PSTORED)&(p_fn->_fni.fn_store ),
+ QueryStartLbn(),
+ TRUE ) ) {
+
+ return FALSE;
+ }
+
+ if( !_Store.ResolveCrosslink( SuperArea, RunIndex ) ) {
+
+ return FALSE;
+ }
+
+ Write();
+ return TRUE;
+}
+
+
+
+VOID
+FNODE::SetRootDirblkLbn(
+ IN LBN NewRootLbn
+ )
+/*++
+
+Routine Description:
+
+ This function sets the physical lbn of a directory FNode
+ to point at a new root dirblk.
+
+Arguments:
+
+ NewRootLbn -- supplies the first LBN of the new root dirblk.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ p_fn->_fni.fn_store.a.alleaf[0].lbnPhys = NewRootLbn;
+ MarkModified();
+}
+
+
+
+VOID
+FNODE::SetParent(
+ IN LBN ParentLbn
+ )
+/*++
+
+Routine description:
+
+ Sets parent of a recovered orphan
+
+Arguments:
+
+ ParentLbn -- supplies the lbn of the parent directory's fnode
+ (zero if unknown)
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if( ParentLbn != 0 ) {
+ p_fn->_fni.lbnContDir = ParentLbn;
+ }
+}
+
+
+
+BOOLEAN
+FNODE::CheckParent(
+ IN LBN ParentLbn
+ )
+/*++
+
+Routine description:
+
+ Checks parent of a recovered orphan, changing it if necessary.
+
+Arguments:
+
+ ParentLbn -- supplies the lbn of the parent directory's fnode
+ (zero if unknown)
+
+Return Value:
+
+ TRUE if the value changed, FALSE if it did not.
+
+--*/
+{
+ if( ParentLbn != 0 ) {
+
+ if( p_fn->_fni.lbnContDir != ParentLbn ) {
+
+ p_fn->_fni.lbnContDir = ParentLbn;
+ return TRUE;
+ }
+ }
+
+ // Didn't change.
+
+ return FALSE;
+}
+
+
+
+LBN
+FNODE::QueryPhysicalLbn(
+ IN LBN FileBlockNumber,
+ OUT PULONG RunLength
+ )
+/*++
+
+Routine Description:
+
+ Returns the disk lbn of the FileBlockNumber-th block of the file
+ described by the FNode
+
+Arguments:
+
+ FileBlockNumber -- supplies the ordinal within the file or
+ extended attribute of the desired block
+ RunLength -- Receives the remaining number of sectors
+ (including the returned sector) in this
+ contiguous run.
+
+Return Value:
+
+ The disk lbn of the desired block. Zero indicates error.
+
+Notes:
+
+ This method assumes that the allocation sector has been read and
+ is valid.
+
+--*/
+{
+ if( !_Store.Initialize( _Drive,
+ (PSTORED)&(p_fn->_fni.fn_store),
+ QueryStartLbn(),
+ TRUE ) ) {
+
+ return 0;
+
+ } else {
+
+ return (_Store.QueryPhysicalLbn(FileBlockNumber, RunLength));
+ }
+}
+
+
+
+BOOLEAN
+FNODE::Truncate(
+ IN LBN SectorCount
+ )
+/*++
+
+Routine Description:
+
+ Truncates the allocation of a file (or extended attribute)
+
+Arguments:
+
+ SectorCount -- supplies the number of sectors to retain
+
+Return value:
+
+ TRUE on successful completion
+
+--*/
+{
+ if( !_Store.Initialize( _Drive,
+ (PSTORED)&(p_fn->_fni.fn_store ),
+ QueryStartLbn(),
+ TRUE ) ||
+ !_Store.Truncate(SectorCount) ) {
+
+ return FALSE;
+ }
+
+ Write();
+ return TRUE;
+}
+
+
+
+
+UHPFS_EXPORT
+BOOLEAN
+FNODE::QueryExtents(
+ IN ULONG MaximumNumberOfExtents,
+ OUT PVOID ExtentList,
+ OUT PULONG NumberOfExtents
+ )
+/*++
+
+Routine Description:
+
+ This method fetches the list of extents covered by this FNode.
+
+
+Arguments:
+
+ MaximumNumberOfExtents -- Supplies the maximum number of extents
+ that will fit in the client's buffer
+ ExtentList -- Supplies the client's buffer into which
+ extents will be placed.
+ NumberOfExtents -- Receives the number of extents associated
+ with this FNode.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+
+Notes:
+
+ This method assumes that this FNode is a file FNode, and not a
+ directory FNode.
+
+ If ExtentList is NULL and MaximumNumberOfExtents is zero, this
+ method will only return the number of extents associated with
+ the FNode.
+
+--*/
+{
+ // Initialize the count of extents to zero.
+
+ *NumberOfExtents = 0;
+
+ // Set up the storage object and pass the request on down.
+
+ return( _Store.Initialize( _Drive,
+ (PSTORED)&(p_fn->_fni.fn_store ),
+ QueryStartLbn(),
+ TRUE ) &&
+ _Store.QueryExtents( MaximumNumberOfExtents,
+ ExtentList,
+ NumberOfExtents ) );
+
+}
+
+
+BOOLEAN
+FNODE::StoreExtents(
+ IN ULONG NumberOfExtents,
+ IN PALLEAF ExtentList,
+ IN OUT PHPFS_BITMAP VolumeBitmap
+ )
+/*++
+
+Routine Description:
+
+ This method saves an extent list into an FNode.
+
+Arguments:
+
+ NumberOfExtents -- Supplies the number of extents to be saved.
+ ExtentList -- Supplies the extents for the file.
+ VolumeBitmap -- Supplies the volume bitmap.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This method assumes that this FNode is a file FNode, and not a
+ directory FNode.
+
+--*/
+{
+ DebugAssert( NumberOfExtents == 0 || ExtentList != NULL );
+
+ // Set up the storage object and pass the request on down.
+
+ return( _Store.Initialize( _Drive,
+ (PSTORED)&(p_fn->_fni.fn_store ),
+ QueryStartLbn(),
+ TRUE ) &&
+ _Store.StoreExtents( NumberOfExtents,
+ ExtentList,
+ FALSE,
+ VolumeBitmap ) &&
+ Write() );
+
+}
+
+
+
+BOOLEAN
+FNODE::TakeCensusAndClear(
+ IN BOOLEAN IsDir,
+ IN OUT PHPFS_BITMAP VolumeBitmap,
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap,
+ IN OUT PHPFS_CENSUS Census
+ )
+/*++
+
+Routine Description:
+
+ This method takes the census of this FNode and its children (if any).
+
+Arguments:
+
+ IsDir -- Supplies a flag which indicates, if TRUE, that
+ this is an FNode for a directory.
+ VolumeBitmap -- Supplies the volume bitmap.
+ HpfsOnlyBitmap -- Supplies the bitmap for sectors containing
+ file-system structures.
+ Census -- Supplies the census object.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+ If this method fails, the reason for failure may be determined
+ using Census->QueryError.
+
+--*/
+{
+ DIRBLK ChildDirblk;
+ LBN ChildLbn;
+
+ // Record this FNode in the bitmap of HPFS file system structures.
+
+ HpfsOnlyBitmap->SetAllocated( QueryStartLbn(), SectorsPerFnode );
+
+ if( IsDir ) {
+
+ // I have a directory FNode to deal with.
+
+ Census->AddDirectory();
+
+ // Set up the child dirblk and take its census. Note that
+ // the census assumes that the volume contains no hotfixes,
+ // so I pass a NULL pointer for the hotfix list.
+
+ ChildLbn = p_fn->_fni.fn_store.a.alleaf[0].lbnPhys;
+
+ if( !ChildDirblk.Initialize( _Drive,
+ NULL,
+ ChildLbn ) ) {
+
+ Census->SetError( HPFS_CENSUS_INSUFFICIENT_MEMORY );
+ return FALSE;
+ }
+
+
+ if( !ChildDirblk.Read() ||
+ !ChildDirblk.IsDirblk() ) {
+
+ Census->SetError( HPFS_CENSUS_CORRUPT_VOLUME );
+ return FALSE;
+ }
+
+ return( ChildDirblk.TakeCensusAndClear( VolumeBitmap,
+ HpfsOnlyBitmap,
+ Census ) );
+
+ } else {
+
+ // This is a file FNode.
+
+ Census->AddFile();
+
+ // Set up the storage object and pass the request on down.
+
+ if( !_Store.Initialize( _Drive,
+ (PSTORED)&(p_fn->_fni.fn_store ),
+ QueryStartLbn(),
+ TRUE ) ) {
+
+ Census->SetError( HPFS_CENSUS_INSUFFICIENT_MEMORY );
+ return FALSE;
+ }
+
+ if( !_Store.TakeCensusAndClear( VolumeBitmap,
+ HpfsOnlyBitmap,
+ Census ) ) {
+
+ return FALSE;
+ }
+
+
+ // If the storage object changed, write the FNode.
+
+ if( _Store.QueryModified() && !Write() ) {
+
+ Census->SetError( HPFS_CENSUS_CORRUPT_VOLUME );
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+}
+
+
+
+UHPFS_EXPORT
+BOOLEAN
+FNODE::QueryPackedEaList(
+ OUT PVOID OutputBuffer,
+ IN ULONG BufferLength,
+ OUT PULONG PackedLength,
+ OUT PBOOLEAN IsCorrupt,
+ IN PHOTFIXLIST HotfixList
+ )
+/*++
+
+Routine Description:
+
+ This method fetches the list of Extended Attributes associated
+ with this FNode in packed (HPFS) format.
+
+Arguments:
+
+ OutputBuffer -- Receives the list of Extended Attributes
+ BufferLength -- Supplies the length of OutputBuffer
+ PackedLength -- Supplies the length of data put into the buffer
+ UnpackedLength -- Receives the unpacked (NT format) length of
+ this Extended Attributes list
+ IsCorrupt -- Receives TRUE if the list is found to be corrupt.
+ HotfixList -- Supplies the volume hotfix list. May be NULL, in
+ which case hotfixes are ignored.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+ The packed EA list is simply a succession of entries of the form:
+
+ EA-Header
+ EA name (length specified in header)
+ null byte
+ EA value (length specified in header)
+
+ packed together.
+
+--*/
+{
+ HPFS_EA_LIST EaList;
+
+ if( !EaList.Initialize( _Drive, p_fn, QueryStartLbn() ) ) {
+
+ return FALSE;
+ }
+
+ return( EaList.QueryPackedEaList( OutputBuffer,
+ BufferLength,
+ PackedLength,
+ IsCorrupt,
+ HotfixList ) );
+
+}
diff --git a/private/utils/uhpfs/src/hfsecrun.cxx b/private/utils/uhpfs/src/hfsecrun.cxx
new file mode 100644
index 000000000..c2bb1a350
--- /dev/null
+++ b/private/utils/uhpfs/src/hfsecrun.cxx
@@ -0,0 +1,298 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "error.hxx"
+#include "hfsecrun.hxx"
+#include "hotfix.hxx"
+
+
+DEFINE_CONSTRUCTOR( HOTFIX_SECRUN, SECRUN );
+
+VOID
+HOTFIX_SECRUN::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Constructor for HOTFIX_SECRUN.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _hotfix_list = NULL;
+}
+
+
+HOTFIX_SECRUN::~HOTFIX_SECRUN(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for HOTFIX_SECRUN.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+BOOLEAN
+HOTFIX_SECRUN::Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PIO_DP_DRIVE Drive,
+ IN PHOTFIXLIST HotfixList,
+ IN LBN StartSector,
+ IN SECTORCOUNT NumSectors
+ )
+{
+ Destroy();
+
+ if (!SECRUN::Initialize(Mem, Drive, StartSector, NumSectors)) {
+ Destroy();
+ return FALSE;
+ }
+
+ _buf = GetBuf();
+ _hotfix_list = HotfixList;
+ _drive = Drive;
+ _start_sector = StartSector;
+ _num_sectors = NumSectors;
+
+ return TRUE;
+}
+
+
+UHPFS_EXPORT
+VOID
+HOTFIX_SECRUN::Relocate(
+ LBN Newlbn
+ )
+/*++
+
+Routine Description:
+
+ Set the starting sector to a new value.
+
+Arguments:
+
+ Newlbn -- new starting sector number.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _start_sector = Newlbn;
+ SECRUN::Relocate( Newlbn );
+}
+
+
+UHPFS_EXPORT
+BOOLEAN
+HOTFIX_SECRUN::Read(
+ )
+{
+ LBN i, NextSectorToRead, ReplacementLbn;
+
+ if( _hotfix_list == NULL ||
+ !_hotfix_list->IsInList( _start_sector, _num_sectors) ){
+
+ // The sectors in question aren't hotfixed--it's just
+ // an ordinary read.
+
+ return SECRUN::Read();
+ }
+
+ // One of the sectors in the run is hotfixed. Step
+ // through the run looking for hotfixed sectors. When
+ // we find a hotfixed sector, read the sectors between
+ // the last sector read (or the beginning of the run)
+ // and the hotfixed sector, and then read the hotfixed
+ // sector. Note that we may need to read the last section
+ // of the run after we've finished stepping through the run.
+
+ i = _start_sector;
+ NextSectorToRead = _start_sector;
+
+ while ( i < _start_sector + _num_sectors ) {
+
+ if( _hotfix_list->IsInList( i, 1 ) ) {
+
+ if( NextSectorToRead < i ) {
+
+ if( !_drive->Read( NextSectorToRead,
+ i - NextSectorToRead,
+ (BYTE *)_buf +
+ (NextSectorToRead - _start_sector) *
+ _drive->QuerySectorSize() ) ) {
+
+ // Read failed.
+ return FALSE;
+ }
+ }
+
+ ReplacementLbn = _hotfix_list->GetLbnTranslation( i );
+
+ if( !_drive->Read( ReplacementLbn,
+ 1,
+ (BYTE *)_buf +
+ (i - _start_sector) *
+ _drive->QuerySectorSize() ) ) {
+
+ return FALSE;
+ }
+
+ NextSectorToRead = i + 1;
+ }
+
+ i += 1;
+ }
+
+
+ if( NextSectorToRead < i ) {
+
+ if( !_drive->Read( NextSectorToRead,
+ i - NextSectorToRead,
+ (BYTE *)_buf +
+ (NextSectorToRead - _start_sector) *
+ _drive->QuerySectorSize() ) ) {
+
+ // Read failed.
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+HOTFIX_SECRUN::Write(
+ )
+{
+ LBN NextSectorToWrite, i, ReplacementLbn;
+
+ if( _hotfix_list == NULL ||
+ !_hotfix_list->IsInList( _start_sector, _num_sectors) ) {
+
+ // The sectors in question aren't hotfixed--it's just
+ // an ordinary write.
+
+ return SECRUN::Write();
+ }
+
+ // One of the sectors in the run is hotfixed. Step
+ // through the run looking for hotfixed sectors. When
+ // we find a hotfixed sector, write the sectors between
+ // the last sector written (or the beginning of the run)
+ // and the hotfixed sector, and then write the hotfixed
+ // sector from the replacement sector. Note that we may
+ // need to write the last section of the run after we've
+ // finished stepping through the run.
+
+ i = _start_sector;
+ NextSectorToWrite = _start_sector;
+
+ while ( i < _start_sector + _num_sectors ) {
+
+ if( _hotfix_list->IsInList( i, 1 ) ) {
+
+ if( NextSectorToWrite < i ) {
+
+ if( !_drive->Write( NextSectorToWrite,
+ i - NextSectorToWrite,
+ (BYTE *)_buf +
+ (NextSectorToWrite - _start_sector) *
+ _drive->QuerySectorSize() ) ) {
+
+ // Write failed.
+ return FALSE;
+ }
+ }
+
+ ReplacementLbn = _hotfix_list->GetLbnTranslation( i );
+
+ if( !_drive->Write( ReplacementLbn,
+ 1,
+ (BYTE *)_buf +
+ (i - _start_sector) *
+ _drive->QuerySectorSize() ) ) {
+
+ // Write failed.
+ return FALSE;
+ }
+
+ NextSectorToWrite = i + 1;
+ }
+
+ i += 1;
+ }
+
+
+ if( NextSectorToWrite < i ) {
+
+ if( !_drive->Write( NextSectorToWrite,
+ i - NextSectorToWrite,
+ (BYTE *)_buf +
+ (NextSectorToWrite - _start_sector) *
+ _drive->QuerySectorSize() ) ) {
+
+ // Write failed.
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+
+}
+
+
+VOID
+HOTFIX_SECRUN::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a HOTFIX_SECRUN to its initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _hotfix_list = NULL;
+ _drive = NULL;
+ _hotfix_list = NULL;
+ _start_sector = 0;
+ _num_sectors = 0;
+ _buf = NULL;
+}
diff --git a/private/utils/uhpfs/src/hotfix.cxx b/private/utils/uhpfs/src/hotfix.cxx
new file mode 100644
index 000000000..8d76dd969
--- /dev/null
+++ b/private/utils/uhpfs/src/hotfix.cxx
@@ -0,0 +1,827 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "badblk.hxx"
+#include "bitmap.hxx"
+#include "error.hxx"
+#include "hotfix.hxx"
+#include "hpfssa.hxx"
+#include "spareb.hxx"
+
+
+/***************************************************************************\
+
+MEMBER: HOTFIXLIST::HOTFIXLIST
+
+SYNOPSIS: Constructor for HOTFIXLIST.
+
+ALGORITHM:
+
+ARGUMENTS: pliodpdrv The drive for the hot fix list.
+ pspIn Valid spare block for this drive.
+
+RETURNS:
+
+NOTES:
+
+HISTORY:
+ 21-Aug-90 norbertk
+ Create
+
+KEYWORDS:
+
+SEEALSO:
+
+\***************************************************************************/
+
+
+DEFINE_CONSTRUCTOR( HOTFIXLIST, SECRUN );
+
+VOID
+HOTFIXLIST::Construct(
+ )
+
+{
+
+ _Drive = NULL;
+ _SparesBlock = NULL;
+ _HotfixData = NULL;
+
+ _MaximumHotfixes = 0;
+ _NumberOfHotfixes = 0;
+}
+HOTFIXLIST::~HOTFIXLIST(
+ )
+{
+ Destroy();
+}
+
+VOID
+HOTFIXLIST::Destroy(
+ )
+{
+ _Drive = NULL;
+ _SparesBlock = NULL;
+ _HotfixData = NULL;
+
+ _MaximumHotfixes = 0;
+ _NumberOfHotfixes = 0;
+}
+
+
+BOOLEAN
+HOTFIXLIST::Initialize(
+ PLOG_IO_DP_DRIVE Drive,
+ PSPAREB SparesBlock
+ )
+/*++
+
+Routine Description:
+
+ Initializes the Hotfix list object.
+
+Arguments:
+
+ Drive -- drive on which the list resides
+
+ SparesBlock -- Spares Block for that drive
+
+Return Value:
+
+ TRUE on successful completion
+
+--*/
+{
+
+ if( Drive == NULL || SparesBlock == NULL ) {
+
+ perrstk->push(ERR_HF_PARAMETER, QueryClassId());
+ return FALSE;
+ }
+
+ Destroy();
+
+ _Drive = Drive;
+ _SparesBlock = SparesBlock;
+
+ if( !_Mem.Initialize() ||
+ !SECRUN::Initialize( &_Mem,
+ _Drive,
+ _SparesBlock->QueryHotFixLbn(),
+ SECTORS_IN_HOTFIX_BLOCK ) ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ _MaximumHotfixes = _SparesBlock->QueryMaxHotFixes();
+ _NumberOfHotfixes = _SparesBlock->QueryHotFixCount();
+
+ if( _MaximumHotfixes > HOTFIX_MAX_LBN ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ _HotfixData = (HOTFIXD*)GetBuf();
+
+ return TRUE;
+}
+
+
+/***************************************************************************\
+
+MEMBER: HOTFIXLIST::Create
+
+SYNOPSIS:
+
+ALGORITHM:
+
+ARGUMENTS: Bitmap Valid bitmap from which to get free sectors.
+ Lbn The recommended location on disk where the free
+ sectors of the 'new' section should be allocated.
+
+
+RETURNS: TRUE upon successful completion.
+
+NOTES:
+
+HISTORY:
+ 21-Aug-90 norbertk
+ Create
+
+KEYWORDS:
+
+SEEALSO:
+
+\***************************************************************************/
+
+
+BOOLEAN
+HOTFIXLIST::Create(PHPFS_BITMAP Bitmap, LBN Lbn )
+{
+ ULONG ilbn;
+
+ // Check for integrity.
+ if (!_HotfixData || !Bitmap) {
+ perrstk->push(ERR_HF_PARAMETER, QueryClassId());
+ return FALSE;
+ }
+
+ memset( _HotfixData,
+ '\0',
+ (size_t)(SECTORS_IN_HOTFIX_BLOCK * _Drive->QuerySectorSize()) );
+
+ // Fill up the new section while updating the bitmap.
+ for (ilbn = 0; ilbn < _MaximumHotfixes; ilbn++) {
+
+ _HotfixData->lbn[_MaximumHotfixes + ilbn] =
+ Bitmap->NearLBN(Lbn + ilbn, 1);
+
+ if (!_HotfixData->lbn[_MaximumHotfixes + ilbn]) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+/***************************************************************************\
+
+MEMBER: HOTFIXLIST::AddBad
+
+SYNOPSIS:
+
+ALGORITHM:
+
+ARGUMENTS: BadLbn The bad sector that needs to be added to
+ the hot fix list.
+ SparesBlockIn A read/write spare block so that this
+ routine may update the current number of
+ hot fixes used.
+
+RETURNS: A new LBN to replace the bad one or 0 for failure.
+
+NOTES:
+
+HISTORY:
+ 21-Aug-90 norbertk
+ Create
+
+KEYWORDS:
+
+SEEALSO:
+
+\***************************************************************************/
+
+
+LBN HOTFIXLIST::AddBad(LBN BadLbn, PSPAREB SparesBlockIn )
+{
+ // Insure that the spare block parameter is the same as the one
+ // used on construction. Also check that construction was good.
+ if( SparesBlockIn != _SparesBlock ||
+ _HotfixData == NULL ||
+ _MaximumHotfixes == 0 ) {
+
+ perrstk->push(ERR_HF_PARAMETER, QueryClassId());
+ return 0;
+ }
+
+ // Increment hot fix counter in spare block.
+ if (!SparesBlockIn->SetHotFixCount(_NumberOfHotfixes + 1)) {
+
+ perrstk->push(NEW_ALLOC_FAILED, QueryClassId());
+ return 0;
+ }
+
+ // Update bad list.
+ _HotfixData->lbn[_NumberOfHotfixes] = BadLbn;
+
+ // Increment the number of hot fixes and return the new lbn.
+ return _HotfixData->lbn[_MaximumHotfixes + _NumberOfHotfixes++];
+}
+
+BOOLEAN
+HOTFIXLIST::IsInList (
+ IN REGISTER LBN Lbn,
+ IN SECTORCOUNT SectorCount
+) CONST
+
+/*++
+
+Method Description:
+
+ Return TRUE if the passed run is in the hotfix list.
+
+Arguments:
+
+ StartLbn - first LBN to mark in use
+ SectorCount - size of LBN to mark in use
+
+Return Value:
+
+ TRUE - if the passed run is hotfixed
+
+--*/
+{
+ REGISTER LBN CurrentLbn;
+ REGISTER LBN FinalLbn;
+
+ if( SectorCount == 0 ) {
+
+ return FALSE;
+ }
+
+ FinalLbn = (LBN)SectorCount+Lbn-1;
+
+ // loop for every sector in the run
+ for (CurrentLbn = Lbn; CurrentLbn <= FinalLbn; ++CurrentLbn) {
+ // if a translation occurs a Hotfix is present
+ if ( CurrentLbn != GetLbnTranslation(CurrentLbn) ) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+LBN
+HOTFIXLIST::GetLbnTranslation (
+ IN LBN Lbn
+) CONST
+
+/*++
+
+Method Description:
+
+ Return LBN the named LBN is mapped to. Echo the LBN if its not
+ Hotfixed.
+
+Arguments:
+
+ Lbn - LBN to be translated
+
+Return Value:
+
+ LBN - translated LBN or echoed LBN
+
+Notes:
+
+ Sector zero can never be hotfixed.
+
+--*/
+{
+ REGISTER ULONG i; // table index
+
+ if( Lbn == 0 ) {
+
+ return 0;
+ }
+
+ // for every entry in the bad Lbn list
+ for (i = 0; i < _NumberOfHotfixes; ++i) {
+ // if the Lbn is in the bad list
+ if ( QueryBadLbn(i) == Lbn ) {
+ // return mapped Lbn
+ return QueryNewLbn(i);
+ }
+ }
+
+ // no match found, return the passed in Lbn
+ return Lbn;
+}
+
+
+VERIFY_RETURN_CODE
+HOTFIXLIST::VerifyAndFix (
+ PHPFS_SA SuperArea
+)
+/*++
+
+Method Description:
+
+ Verify and the hot fix list by making sure it can be read and
+ written to if the disk up date flag is set. If the I/O fails
+ this method sets the internal status flag for the Hotfix object
+ and returns a failure status to the client.
+
+ WARNING: this methods does a read without looking at any read flags
+ which means any in memory data that is not written to the volume
+ will be destroyed. This is done because VerifyAndFix refers to
+ the on disk data.
+
+ The list of good sectors cannot be fixed unless the bitmap
+ has been verified. As a result this method does not verify
+ the list of good sectors because it may be called before the
+ bitmap is verified.
+
+Arguments:
+
+ LogicalDrive - IO object
+ UpdateVolume - TRUE if volume is to be updated if needed
+
+Return Value:
+
+ VERIFY_STRUCTURE_INVALID if the hotfix list is corrupt;
+ VERIFY_STRUCTURE_OK if it's OK.
+
+--*/
+{
+ ULONG i;
+ LBN Lbn;
+ PHPFS_BITMAP Bitmap;
+
+ // Check that the hotfix block is not crosslinked, and that it
+ // is readable; then mark it as used in the bitmap.
+
+ Bitmap = SuperArea->GetBitmap();
+ Lbn = _SparesBlock->QueryHotFixLbn();
+
+ if( !Bitmap->IsFree( Lbn, SECTORS_IN_HOTFIX_BLOCK) ||
+ !Read() ) {
+
+ return VERIFY_STRUCTURE_INVALID;
+ }
+
+ Bitmap->SetAllocated( Lbn, SECTORS_IN_HOTFIX_BLOCK );
+
+ // Check that all the replacement sectors are in range
+ // and not already used. If one is invalid, it and the
+ // corresponding replaced sector are set to zero.
+
+
+ for( i = 0; i < _MaximumHotfixes; i++ ) {
+
+ if( !Bitmap->IsFree( QueryNewLbn(i), 1 ) ) {
+
+ SetNewLbn(i, 0);
+ SetBadLbn(i, 0);
+ }
+ }
+
+ // Mark the unused replacement sectors as used in the bitmap.
+
+ for( i = _NumberOfHotfixes; i < _MaximumHotfixes; i++ ) {
+
+ Bitmap->SetAllocated( QueryNewLbn(i), 1 );
+ }
+
+ return VERIFY_STRUCTURE_OK;
+}
+
+
+NONVIRTUAL
+BOOLEAN
+HOTFIXLIST::SetNewLbn(
+ ULONG LbnIndex,
+ LBN Lbn
+)
+/*++
+
+Method Description:
+
+ Set a fresh Lbn at the named location. No validation of the Lbn
+ is done by this method.
+
+Arguments:
+
+ LbnIndex - index into the list where lbn resides
+ Lbn - Lbn to set
+
+Return Value:
+
+ BOOLEAN - TRUE if successful
+
+--*/
+{
+ // Private method--no range checking.
+ _HotfixData->lbn[_MaximumHotfixes + LbnIndex] = Lbn;
+ return TRUE;
+}
+
+
+NONVIRTUAL
+BOOLEAN
+HOTFIXLIST::SetBadLbn(
+ ULONG LbnIndex,
+ LBN Lbn
+)
+/*++
+
+Method Description:
+
+ Set a fresh Lbn at the named location. No validation of the Lbn
+ is done by this method.
+
+Arguments:
+
+ LbnIndex - index into the list where lbn resides
+ Lbn - Lbn to set
+
+Return Value:
+
+ BOOLEAN - TRUE if successful
+
+--*/
+{
+ // Private method--no range checking.
+ _HotfixData->lbn[LbnIndex] = Lbn;
+ return TRUE;
+}
+
+VOID
+HOTFIXLIST::Print(
+) const
+{
+ // unreferenced parameters
+ (void)(this);
+
+// REGISTER ULONG i;
+//
+// printf("HotFix List:\n");
+//
+//
+// printf("Echo list of Bad hotfixes:\n");
+// for (i = 0; i < QueryMaxHotFixes(); ++i) {
+// printf("%lx\n", QueryBadLbn(i));
+// }
+// printf("Echo list of Good hotfixes:\n");
+// for (i = 0; i < QueryMaxHotFixes(); ++i) {
+// printf("%lx\n", QueryNewLbn(i));
+// }
+}
+
+
+ULONG
+HOTFIXLIST::FirstHotfixInRun(
+ LBN StartLbn,
+ SECTORCOUNT SectorCount
+ ) CONST
+/*++
+
+Routine Description:
+
+ Determines the offset in the run of the first hotfixed
+ sector in the run.
+
+Arguments:
+
+ StartLbn -- supplies the first LBN of the run
+ SectorCount -- supplies the length of the run
+
+Return Value:
+
+ The offset into the run of the first hotfixed sector in
+ the run. If there are no hotfixed sectors in the run,
+ or if an error occurs, SectorCount is returned.
+--*/
+{
+ REGISTER LBN CurrentLbn;
+ REGISTER LBN FinalLbn;
+
+ FinalLbn = (LBN)SectorCount+StartLbn;
+
+ // loop for every sector in the run
+ for (CurrentLbn = StartLbn; CurrentLbn <= FinalLbn; ++CurrentLbn) {
+
+ // if a translation occurs a Hotfix is present
+ if ( CurrentLbn != GetLbnTranslation(CurrentLbn) ) {
+
+ return CurrentLbn - StartLbn;
+ }
+ }
+
+ return SectorCount;
+}
+
+
+
+VOID
+HOTFIXLIST::MarkAllUsed(
+ IN OUT HPFS_BITMAP* Bitmap
+ )
+/*++
+
+Routine Description:
+
+ Marks all the replaced (bad) and replacement (new) lbns
+ as used in the bitmap.
+
+Arguments:
+
+ Bitmap -- bitmap to mark them in
+
+Notes:
+
+ We don't care if these lbns are already marked as used; we
+ just want to make sure that they don't get allocated.
+
+--*/
+{
+ ULONG i;
+
+ for( i = 0; i < _MaximumHotfixes; i++ ) {
+
+ Bitmap->SetAllocated( QueryNewLbn(i), 1 );
+ Bitmap->SetAllocated( QueryBadLbn(i), 1 );
+ }
+}
+
+
+VOID
+HOTFIXLIST::ClearHotfix(
+ LBN BadLbn,
+ PHPFS_SA SuperArea
+ )
+/*++
+
+Routine Description:
+
+ Clears a single hotfix reference in the hotfix list
+
+Arguments:
+
+ BadLbn -- the bad lbn of the pair that is to be cleared.
+ SuperArea -- volume superarea
+
+Notes:
+
+ We record that a hotfix reference has been resolved by
+ setting the replacement lbn (new lbn) to zero.
+
+ We also mark the sector as used in the bitmap and add it
+ to the bad block list.
+
+--*/
+{
+ ULONG i;
+
+ for( i = 0; i < _NumberOfHotfixes; i++ ) {
+
+ if( QueryBadLbn(i) == BadLbn ) {
+
+ // This is the pair to clear. We swap it
+ // with the last used hotfix pair (at index
+ // _NumberOfHotfixes-1); set the replacement
+ // lbn for that pair to zero (to indicate that
+ // the replacement lbn has been use), and
+ // decrement the number of used hotfixes.
+
+ // Note that we copy the bad lbn up to the last
+ // used pair so that it can be set in the bad block
+ // list when the hotfix list is cleared.
+
+ BadLbn = QueryBadLbn(i);
+
+ SetBadLbn( i, QueryBadLbn( _NumberOfHotfixes - 1 ) );
+ SetNewLbn( i, QueryNewLbn( _NumberOfHotfixes - 1 ) );
+
+ SetNewLbn( _NumberOfHotfixes - 1, 0 );
+ SetBadLbn( _NumberOfHotfixes - 1, BadLbn );
+
+ _NumberOfHotfixes -= 1;
+
+ // Mark the sector as used in the bitmap and add
+ // it to the bad block list, to keep it out of
+ // circulation.
+
+ SuperArea->GetBitmap()->SetAllocated( BadLbn, 1 );
+ SuperArea->GetBadBlockList()->Add( BadLbn );
+ }
+ }
+}
+
+
+VOID
+HOTFIXLIST::ClearRun(
+ IN LBN StartLbn,
+ IN SECTORCOUNT Length,
+ IN OUT PHPFS_SA SuperArea
+ )
+/*++
+
+Routine Description:
+
+ Clear all hotfix references in a run of sectors.
+
+Arguments:
+
+ StartLbn -- first LBN in the run
+ Length -- number of sectors in the run
+ SuperArea -- volume superarea
+
+Notes:
+
+ This method may be called when the client has resolved
+ a set of hotfix references by brute force, by copying
+ an entire run.
+
+--*/
+{
+ LBN CurrentLbn, EndLbn;
+
+
+ EndLbn = StartLbn + Length - 1;
+
+ for( CurrentLbn = StartLbn; CurrentLbn <= EndLbn; CurrentLbn++ ) {
+
+ if( CurrentLbn != GetLbnTranslation( CurrentLbn ) ) {
+
+ ClearHotfix( CurrentLbn, SuperArea );
+ }
+ }
+}
+
+
+VOID
+HOTFIXLIST::ClearList(
+ IN OUT HPFS_BITMAP* Bitmap,
+ IN OUT BADBLOCKLIST* BadBlockList,
+ IN BOOLEAN ClearAll
+ )
+/*++
+
+Routine Description:
+
+ Clear the used hotfixes from the list.
+
+Arguments:
+
+ Bitmap -- supplies the volume bitmap
+
+ ClearAll -- TRUE if all used hotfixes should be cleared;
+ FALSE if only the resolved hotfixes should be cleared.
+
+Notes:
+
+ If ClearAll is TRUE, we set all the bad lbns (replaced lbns)
+ in the list to zero, and allocate a new good lbn (replacement
+ lbn) for any pair with a zero replacement lbn.
+
+ If ClearAll is FALSE, then we only set the bad lbns to zero
+ for those references which have been resolved (i.e. pairs
+ where the replacement lbn is zero).
+
+ Note that all used pairs (pairs with a bad lbn that is non-zero)
+ must appear at the beginning of the list, and _NumberOfHotfixes
+ must be updated to the number of used pairs.
+
+ This method also updates the spares block.
+
+--*/
+{
+ ULONG i;
+ LBN NewLbn;
+ LBN BadLbn;
+
+ if( ClearAll ) {
+
+ // We're going to clear the entire list.
+
+ _NumberOfHotfixes = 0;
+ }
+
+
+ for( i = _NumberOfHotfixes;
+ i < _MaximumHotfixes;
+ i++ ) {
+
+ if( (BadLbn = QueryBadLbn(i)) != 0 ) {
+
+ Bitmap->SetAllocated( BadLbn, 1 );
+ BadBlockList->Add( BadLbn );
+ }
+
+ SetBadLbn( i, 0 );
+
+ if( QueryNewLbn(i) == 0 ) {
+
+ // This replacement sector has been used up,
+ // so we have to allocate a new one.
+
+ if( (NewLbn = Bitmap->NearLBN( 0, 1 )) == 0 ) {
+
+ // We ran out of space. We deal with this
+ // by stealing the replacement lbn from the
+ // last pair and shortening the list by one.
+
+ SetNewLbn( i, QueryNewLbn( _MaximumHotfixes - 1 ) );
+
+ _MaximumHotfixes -= 1;
+
+ } else {
+
+ SetNewLbn( i, NewLbn );
+ }
+ }
+ }
+
+
+ _SparesBlock->SetHotFixCount( _NumberOfHotfixes );
+}
+
+
+NONVIRTUAL
+BOOLEAN
+HOTFIXLIST::TakeCensus(
+ IN PHPFS_BITMAP VolumeBitmap,
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap
+ )
+/*++
+
+Routine Description:
+
+ This method takes the census of the hotfix list. It checks to make
+ sure that the hotfix list sector and the replacement sectors are
+ marked as in-use in the volume bitmap, and it marks them in the
+ hpfs-only bitmap.
+
+Arguments:
+
+ VolumeBitmap -- Supplies the volume bitmap.
+ HpfsOnlyBitmap -- Supplies the bitmap of hpfs-only structures.
+
+Return value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This method reads the hotfix list, so any changes previously
+ made will be lost.
+
+--*/
+{
+ ULONG i;
+
+ // First, check the hotfix list sector itself:
+
+ if( !VolumeBitmap->CheckUsed( QueryStartLbn(), SECTORS_IN_HOTFIX_BLOCK ) ||
+ !Read() ) {
+
+ DebugPrint( "Hotfix list is corrupt." );
+ return FALSE;
+ }
+
+ HpfsOnlyBitmap->SetAllocated( QueryStartLbn(), SECTORS_IN_HOTFIX_BLOCK );
+
+ // Now check all the replacement sectors.
+
+ for( i = 0; i < _MaximumHotfixes; i++ ) {
+
+ if( !VolumeBitmap->CheckUsed( QueryNewLbn(i), 1 ) ) {
+
+ DebugPrint( "Hotfix list is corrupt." );
+ return FALSE;
+ }
+
+ HpfsOnlyBitmap->SetAllocated( QueryNewLbn(i), 1 );
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/uhpfs/src/hpcensus.cxx b/private/utils/uhpfs/src/hpcensus.cxx
new file mode 100644
index 000000000..561ba3105
--- /dev/null
+++ b/private/utils/uhpfs/src/hpcensus.cxx
@@ -0,0 +1,283 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+
+Module Name:
+
+ hpcensus.hxx
+
+
+Abstract:
+
+ This module contains the member function definitions for the HPFS
+ Census object. This object is a receptacle for the information
+ needed by Convert, when the source file system is HPFS.
+
+ Information flows through the census object in both directions. The
+ source file system (HPFS as it exists on the disk) informs the target
+ file system how many files, directories, and dirblks are on disk. The
+ target file system gives the source file system a list of sectors (LBNs)
+ which must be clear of file and EA data in order for conversion to
+ proceed.
+
+
+Author:
+
+ Bill McJohn (billmc) 05-Nov-1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "bitmap.hxx"
+#include "hpcensus.hxx"
+
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( HPFS_CENSUS, OBJECT, UHPFS_EXPORT );
+
+VOID
+HPFS_CENSUS::Construct(
+ )
+/*++
+
+Routine Description:
+
+ This method is the helper function for object construction. It sets
+ the member data to safe values.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _ClearSectors = NULL;
+}
+
+
+UHPFS_EXPORT
+HPFS_CENSUS::~HPFS_CENSUS(
+ )
+/*++
+
+Routine Description:
+
+ Object destructor.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+HPFS_CENSUS::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This method cleans up the object in preparation for destruction or
+ reinitialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if( _ClearSectors != NULL ) {
+
+ FREE( _ClearSectors );
+ }
+}
+
+
+
+UHPFS_EXPORT
+BOOLEAN
+HPFS_CENSUS::Initialize(
+ ULONG MaximumClearSectors
+ )
+/*++
+
+Routine Description:
+
+ This method initializes the HPFS_CENSUS object.
+
+Arguments:
+
+ MaximumClearSectors -- supplies the maximum number of clear sectors
+ that this object must handle.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ Destroy();
+
+ _NumberOfFiles = 0;
+ _NumberOfDirectories = 0;
+ _NumberOfDirblks = 0;
+
+ _NumberOfClearSectors = 0;
+ _MaximumClearSectors = MaximumClearSectors;
+
+ if( (_ClearSectors =
+ (PLBN) MALLOC( MaximumClearSectors * sizeof(LBN) )) == NULL ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ _DataRelocated = FALSE;
+ _Error = HPFS_CENSUS_NO_ERROR;
+
+ return TRUE;
+}
+
+
+UHPFS_EXPORT
+BOOLEAN
+HPFS_CENSUS::AddClearSector(
+ IN LBN Lbn
+ )
+/*++
+
+Routine Description:
+
+ This method adds an LBN to the list of Clear Sectors.
+
+Arguments:
+
+ Lbn -- the LBN to add to the list.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+
+ if( _NumberOfClearSectors < _MaximumClearSectors ) {
+
+ _ClearSectors[_NumberOfClearSectors++] = Lbn;
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+ }
+}
+
+
+BOOLEAN
+HPFS_CENSUS::ConflictWithClearSectors(
+ IN LBN StartLbn,
+ IN ULONG RunLength,
+ OUT PLBN FirstConflictingLbn
+ )
+/*++
+
+Routine Description:
+
+ This method checks to see if the supplied run includes any sectors
+ which appear on the object's list of Clear Sectors.
+
+Arguments:
+
+ StartLbn -- Supplies the first LBN of the run to check.
+ RunLength -- Supplies the length of the run to check.
+ FirstConflictingLbn -- Receives the LBN of the first sector of the
+ run which appears in the list of Clear Sectors.
+
+Return Value:
+
+ TRUE if any sector in the run appears in the list of Clear Sectors;
+ FALSE otherwise.
+
+--*/
+{
+ ULONG i, j;
+
+ for( i = 0; i < RunLength; i++ ) {
+
+ for( j = 0; j < _NumberOfClearSectors; j++ ) {
+
+ if( StartLbn + i == _ClearSectors[j] ) {
+
+ *FirstConflictingLbn = StartLbn + i;
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+
+
+VOID
+HPFS_CENSUS::MarkClearSectors(
+ IN OUT PHPFS_BITMAP VolumeBitmap
+ )
+/*++
+
+Routine Description:
+
+ This method marks all the Clear Sectors as in-use in the supplied
+ bitmap.
+
+Arguments:
+
+ VolumeBitmap -- supplies the volume to mark the ClearSectors in.
+
+Return Value:
+
+ None.
+
+Notes:
+
+ If a Clear Sector is in the dirblk band, it may not be marked
+ as in use; however, since only file and EA data needs to be cleared,
+ this is acceptable.
+
+--*/
+{
+ ULONG j;
+
+ for( j = 0; j < _NumberOfClearSectors; j++ ) {
+
+ VolumeBitmap->SetAllocated( _ClearSectors[j], 1 );
+ }
+}
diff --git a/private/utils/uhpfs/src/hpfsacl.cxx b/private/utils/uhpfs/src/hpfsacl.cxx
new file mode 100644
index 000000000..9376f237d
--- /dev/null
+++ b/private/utils/uhpfs/src/hpfsacl.cxx
@@ -0,0 +1,398 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "alsec.hxx"
+#include "bitmap.hxx"
+#include "error.hxx"
+#include "hotfix.hxx"
+#include "hpfsacl.hxx"
+#include "hpfssa.hxx"
+#include "hpfsname.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+#include "orphan.hxx"
+
+DEFINE_CONSTRUCTOR( HPFS_ACL, OBJECT );
+
+
+HPFS_ACL::~HPFS_ACL(
+ )
+/*++
+--*/
+{
+ _Drive = NULL;
+ _FnodeData = NULL;
+}
+
+BOOLEAN
+HPFS_ACL::Initialize(
+ PLOG_IO_DP_DRIVE Drive,
+ _FNODE* FnodeData,
+ LBN FnodeLbn
+ )
+/*++
+--*/
+{
+ _Drive = Drive;
+ _FnodeData = FnodeData;
+ _FnodeLbn = FnodeLbn;
+
+ _FnodeModified = FALSE;
+
+ return TRUE;
+}
+
+
+VERIFY_RETURN_CODE
+HPFS_ACL::VerifyAndFix(
+ IN HPFS_SA* SuperArea,
+ IN PDEFERRED_ACTIONS_LIST DeferredActions,
+ IN PHPFS_PATH CurrentPath,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN ErrorsDetected,
+ IN BOOLEAN UpdateAllowed,
+ IN OUT PHPFS_ORPHANS OrphansList
+ )
+/*++
+
+Description of Routine:
+
+ This function checks the Access Control List for an FNode.
+ The ACL is an all-or-nothing proposition: if there is any
+ corruption detected in the ACL, the entire list is removed.
+
+Arguments:
+
+ SuperArea -- supplies the volume superarea
+ DeferredActions -- supplies a place to put actions which
+ chkdsk must defer
+ CurrentPath -- supplies the path of the file being checked.
+ May be NULL.
+ Message -- supplies an outlet for messages. May be NULL.
+ ErrorsDetected -- receives an indication whether errors were
+ detected which did not trigger messages
+ UpdateAllowed -- supplies an indication whether changes should
+ be written to disk
+ OrphansList -- supplies a list of orphaned structures which
+ may hold children of this object.
+ May be NULL.
+
+Return Value:
+
+ a verify return code indicating status
+
+--*/
+{
+
+ PALSEC ChildAlsec;
+ LBN NewLbn, NextSectorNumber;
+ ULONG SectorSize, csec;
+ USHORT LengthInFnode;
+ VERIFY_RETURN_CODE erc;
+
+ // Check that the object has been initialized:
+ if ( !_Drive || !_FnodeData ) {
+
+ return VERIFY_INTERNAL_ERROR;
+ }
+
+ LengthInFnode = _FnodeData->_fni.usFNLACL;
+
+ // If there is no Access Control List, we can bail out now.
+ if( LengthInFnode == 0 &&
+ _FnodeData->_fni.lbnACL == (LBN)(0) ) {
+
+ return VERIFY_STRUCTURE_OK;
+ }
+
+ // If there are ACLs both in the FNode and on disk,
+ // remove the entries in the FNode.
+ if( LengthInFnode != 0 &&
+ _FnodeData->_fni.lbnACL != (LBN)(0) ) {
+
+ if( LengthInFnode < sizeof( _FnodeData->abFree ) ) {
+
+ // There may be EAs after the ACL; move them down.
+ memmove( _FnodeData->abFree,
+ _FnodeData->abFree + LengthInFnode,
+ sizeof( _FnodeData->abFree ) - LengthInFnode );
+ }
+
+ *ErrorsDetected = TRUE;
+
+ _FnodeData->_fni.usFNLACL = 0;
+ LengthInFnode = 0;
+ _FnodeModified = TRUE;
+ }
+
+ // All Access Control Entries are ULONG-aligned, so the
+ // length of the list must be a multiple of sizeof(ULONG).
+ // If this is not true, remove the list.
+
+ if( LengthInFnode % sizeof(ULONG) != 0 ||
+ ( _FnodeData->_fni.lbnACL != (LBN)(0L) &&
+ _FnodeData->_fni.cbRunACL % sizeof(ULONG) != 0 ) ) {
+
+ if( Message != NULL && CurrentPath != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_REMOVED_ACL );
+ Message->Display( "%s", CurrentPath->GetString() );
+ }
+
+
+ if( LengthInFnode != 0 &&
+ LengthInFnode <= sizeof( _FnodeData->abFree ) ) {
+
+ // There may be EAs after the ACL; move them down.
+ memmove( _FnodeData->abFree,
+ _FnodeData->abFree + LengthInFnode,
+ sizeof( _FnodeData->abFree ) - LengthInFnode );
+ }
+
+ _FnodeData->_fni.usFNLACL = 0;
+ _FnodeData->_fni.lbnACL = (LBN)(0L);
+ _FnodeData->_fni.cbRunACL = 0;
+
+ _FnodeModified = TRUE;
+
+ return VERIFY_STRUCTURE_OK;
+ }
+
+
+ // If the ACL is in the FNode, we just need to check its length
+ if( LengthInFnode != 0 ) {
+
+ if( LengthInFnode > sizeof(_FnodeData->abFree) ) {
+
+ // The length is too great--cut it down to maximum size.
+
+ *ErrorsDetected = TRUE;
+ _FnodeData->_fni.usFNLACL = sizeof(_FnodeData->abFree);
+ _FnodeModified = TRUE;
+ }
+
+ return VERIFY_STRUCTURE_OK;
+
+ }
+
+ // The ACL is on disk. Compute the number of sectors
+ // required to hold it.
+ SectorSize = _Drive->QuerySectorSize();
+ csec = (_FnodeData->_fni.cbRunACL - 1 + SectorSize) / SectorSize;
+
+ if( _FnodeData->_fni.bDatACL ) {
+
+ // The ACL is in an allocation tree. Check to see if the
+ // ALSEC has been hotfixed (resolving the reference if
+ // necessary), and verify the allocation tree.
+
+ NewLbn = SuperArea->GetHotfixList()->
+ GetLbnTranslation( _FnodeData->_fni.lbnACL );
+
+ if( NewLbn != _FnodeData->_fni.lbnACL ) {
+
+ // The ALSEC lbn has been hotfixed--resolve the reference.
+
+ *ErrorsDetected = TRUE;
+ _FnodeData->_fni.lbnACL = NewLbn;
+ _FnodeModified = TRUE;
+ }
+
+ if( !(ChildAlsec = NEW ALSEC) ||
+ !ChildAlsec->Initialize( _Drive, _FnodeData->_fni.lbnACL ) ) {
+
+ if( ChildAlsec ) {
+
+ DELETE( ChildAlsec );
+ }
+
+ return VERIFY_INSUFFICIENT_RESOURCES;
+ }
+
+ NextSectorNumber = 0;
+
+ erc = ChildAlsec->VerifyAndFix( SuperArea,
+ DeferredActions,
+ NULL,
+ _FnodeLbn,
+ &NextSectorNumber,
+ Message,
+ ErrorsDetected,
+ UpdateAllowed );
+ DELETE( ChildAlsec );
+
+ if( erc != VERIFY_STRUCTURE_OK &&
+ OrphansList != NULL &&
+ OrphansList->LookupAlsec( _FnodeData->_fni.lbnACL,
+ _FnodeLbn,
+ &NextSectorNumber,
+ UpdateAllowed,
+ FALSE ) ) {
+
+ // We found the child allocation sector in the
+ // orphan list, so it's OK.
+
+ erc = VERIFY_STRUCTURE_OK;
+ }
+
+
+ if ( erc != VERIFY_STRUCTURE_OK ||
+ csec > NextSectorNumber ) {
+
+ // Something is wrong--either the allocation tree
+ // could not be verified, or the ACL does not fit
+ // in the space claimed by the allocation tree.
+ // Either way, it's corrupt--remove it.
+
+ if( Message != NULL && CurrentPath != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_REMOVED_ACL );
+ Message->Display( "%s", CurrentPath->GetString() );
+ }
+
+ _FnodeData->_fni.lbnACL = (LBN)(0L);
+ _FnodeData->_fni.cbRunACL = 0;
+ _FnodeModified = TRUE;
+
+ }
+
+ return VERIFY_STRUCTURE_OK;
+
+ } else {
+
+ // The ACL is in a single run on disk
+
+ if( !SuperArea->GetBitmap()->
+ IsFree( _FnodeData->_fni.lbnACL, csec ) ) {
+
+ // The ACL is crosslinked--remove it.
+
+ if( Message != NULL && CurrentPath != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_REMOVED_ACL );
+ Message->Display( "%s", CurrentPath->GetString() );
+ }
+
+ _FnodeData->_fni.lbnACL = (LBN)(0L);
+ _FnodeData->_fni.cbRunACL = 0;
+ _FnodeModified = TRUE;
+ }
+
+ if( SuperArea->GetHotfixList()
+ ->IsInList(_FnodeData->_fni.lbnACL, csec) ) {
+
+ DeferredActions->AddHotfixedLbn(_FnodeLbn,
+ DEFER_FNODE,
+ DEFER_ACL_DATA);
+ }
+
+ SuperArea->GetBitmap()->SetAllocated( _FnodeData->_fni.lbnACL, csec );
+
+ return VERIFY_STRUCTURE_OK;
+ }
+}
+
+
+BOOLEAN
+HPFS_ACL::QueryFnodeModified(
+ )
+{
+ return _FnodeModified;
+}
+
+
+
+BOOLEAN
+HPFS_ACL::FindAndResolveHotfix(
+ PHPFS_SA SuperArea
+ )
+/*++
+
+Routine Description:
+
+ Finds and resolves any hotfix references in the access control list
+
+Arguments:
+
+ SuperArea -- super area for the volume (used to access the
+ hotfix list and bitmap).
+
+Return Value:
+
+ TRUE if, when we're done, the access control list has no
+ hotfixed sectors.
+
+Notes:
+
+ This method is fairly straightforward, since the only case of
+ interest is when the access control list resides outside the
+ FNode in a single run of sectors. (If it resides in an allocation
+ tree, the allocation sector would have been reported as the parent
+ of the hotfixed sector, not the FNode.)
+
+ This method assumes that the access control list is valid (i.e.
+ that it has passed the scrutiny of VerifyAndFix).
+
+--*/
+{
+ LBN StartLbn, NewLbn;
+ ULONG SectorsInList, SectorSize;
+ PHOTFIXLIST HotfixList;
+
+ if( _FnodeData->_fni.lbnACL == 0 ||
+ _FnodeData->_fni.bDatACL != 0 ) {
+
+ // Either there are no ACL entries outside the FNode,
+ // or the ACL resides in an allocation tree. In either
+ // case, there is nothing to resolve.
+
+ return TRUE;
+ }
+
+
+ StartLbn = _FnodeData->_fni.lbnACL;
+
+ SectorSize = _Drive->QuerySectorSize();
+ SectorsInList = (_FnodeData->_fni.cbRunACL - 1 + SectorSize) /
+ SectorSize;
+
+ HotfixList = SuperArea->GetHotfixList();
+
+ while( HotfixList->IsInList( StartLbn, SectorsInList ) ) {
+
+
+ // Copy the run to a new location-- return FALSE if
+ // we can't copy it.
+
+ if( !SuperArea->CopyRun( StartLbn, SectorsInList, &NewLbn ) ) {
+
+ return FALSE;
+ }
+
+
+ // We successfully relocated the ACL; update the FNode
+ // to point at the new location.
+
+ _FnodeData->_fni.lbnACL = NewLbn;
+ _FnodeModified = TRUE;
+
+
+ // Now that we've relocated the run, we free up its
+ // old sectors and clear the hotfix references. (Note
+ // the ClearRun will mark the bad sectors as used and
+ // add them to the badblock list.
+
+ SuperArea->GetBitmap()->SetFree( StartLbn, SectorsInList );
+
+ HotfixList->ClearRun( StartLbn, SectorsInList, SuperArea );
+ }
+
+
+ // The ACL is now free of hotfix references.
+
+ return TRUE;
+}
diff --git a/private/utils/uhpfs/src/hpfschk.cxx b/private/utils/uhpfs/src/hpfschk.cxx
new file mode 100644
index 000000000..74570c217
--- /dev/null
+++ b/private/utils/uhpfs/src/hpfschk.cxx
@@ -0,0 +1,814 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ hpfschk.cxx
+
+Abstract:
+
+ This module contains the definition of HPFS_SA::VerifyAndFix,
+ which implements Chkdsk for HPFS volumes.
+
+Author:
+
+ Bill McJohn (billmc) 01-Dec-1990
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "badblk.hxx"
+#include "bmind.hxx"
+#include "bitmap.hxx"
+#include "cpinfo.hxx"
+#include "defer.hxx"
+#include "dirblk.hxx"
+#include "dircache.hxx"
+#include "dirtree.hxx"
+#include "error.hxx"
+#include "fnode.hxx"
+#include "hotfix.hxx"
+#include "hpfsname.hxx"
+#include "hpfssa.hxx"
+#include "orphan.hxx"
+#include "spareb.hxx"
+#include "superb.hxx"
+#include "message.hxx"
+#include "ifsentry.hxx"
+#include "rtmsg.h"
+
+
+BOOLEAN
+HPFS_SA::VerifyAndFix (
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT BOOLEAN Verbose,
+ IN BOOLEAN OnlyIfDirty,
+ IN BOOLEAN RecoverFree,
+ IN BOOLEAN RecoverAlloc,
+ OUT PULONG ExitStatus,
+ IN PCWSTRING DriveLetter
+ )
+/*++
+
+Method Description:
+
+ This is the high level algorithm used to verify and fix a volume, which
+ is also known as Chkdsk. This method is called by the Volume.Chkdsk
+ method. See the Chdsk design work book for more information.
+
+
+Arguments:
+
+ FixLevel - Supplies the fix up level.
+ Message - Supplies an outlet for messages.
+ Verbose - Supplies verbose action flag
+ OnlyIfDirty - Supplies a flag indicating that the volume should
+ only be checked if the Spares Block Dirty Bit is set.
+ RecoverFree -
+ RecoverAlloc-
+ ExitStatus - Returns an indication of what happened.
+ DriveLetter - For autocheck, tells the drive letter of the volume.
+
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+
+{
+ HPFS_DIRECTORY_TREE RootTree;
+ FNODE RootFnode;
+ HPFS_PATH CurrentPath;
+ HPFS_ORPHANS OrphansList;
+ SECRUN OrphanSecrun;
+ HMEM OrphanMem;
+ PBITMAPINDIRECT BitmapIndirect;
+ DEFERRED_ACTIONS_LIST* DeferredActionsList;
+ DIRBLK_CACHE* DirblkCache;
+ LBN OrphanLbn;
+ BOOLEAN UpdateVolume; // volume is updated with fixes
+ ULONG TrashCan;
+ VERIFY_RETURN_CODE erc;
+ ULONG i;
+ LBN lbn;
+ ULONG LbnsInSuperArea;
+ BOOLEAN ErrorsDetected = FALSE;
+ BOOLEAN OrphansError = FALSE;
+ BOOLEAN AllocationErrors = FALSE;
+ ULONG BadSectors;
+ ULONG exit_status;
+
+ if (NULL == ExitStatus) {
+ ExitStatus = &exit_status;
+ }
+ exit_status = CHKDSK_EXIT_SUCCESS;
+ *ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
+
+ // make sure object was initialized properly
+ if (!_drive) {
+
+ DebugAbort("Object inconsistent");
+ perrstk->push(ERR_CHKDSK_UNEXPECTEDERR, QueryClassId());
+ return FALSE;
+ }
+
+ // Allocate local variables--bug out if they can't be allocated.
+
+ if( (DeferredActionsList = NEW DEFERRED_ACTIONS_LIST) == NULL ||
+ (DirblkCache = NEW DIRBLK_CACHE) == NULL ) {
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_INSUFFICIENT_MEMORY );
+ Message->Display("");
+ }
+
+ perrstk->push(NEW_ALLOC_FAILED, QueryClassId());
+
+ DELETE( DeferredActionsList );
+ DELETE( DirblkCache );
+
+ return FALSE;
+ }
+
+
+ UpdateVolume = ( FixLevel >= TotalFix );
+
+ // If this is non-/f, print a warning message so the user
+ // doesn't get confused.
+ //
+ if (FixLevel == CheckOnly) {
+ Message->Set(MSG_CHK_NTFS_READ_ONLY_MODE);
+ Message->Display();
+ }
+
+
+ // if the super block or spare block are corrupt beyond repair
+ // we can't check the volume.
+
+ if ( !_SuperBlock.Verify( ) || !_SparesBlock.Verify( ) ) {
+
+
+ DebugPrint( "Superblock or Spares block unrecoverably corrupt.\n" );
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_ELEMENTARY_CORRUPTION );
+ Message->Display("");
+ }
+
+ DELETE( DeferredActionsList );
+ DELETE( DirblkCache );
+
+ *ExitStatus = CHKDSK_EXIT_COULD_NOT_FIX;
+
+ return FALSE;
+ }
+
+
+ if( OnlyIfDirty ) {
+
+ if (!_SparesBlock.IsFsDirty() ) {
+
+ // The client requested that the volume only be
+ // checked if it's dirty, and it isn't.
+
+ Message->Set(MSG_CHK_VOLUME_CLEAN);
+ Message->Display();
+
+ *ExitStatus = CHKDSK_EXIT_SUCCESS;
+
+ return TRUE;
+ }
+
+ //
+ // The volume is not clean, so if we're autochecking we want to
+ // make sure that we're printing real messages on the console
+ // instead of just dots.
+ //
+
+#ifdef _AUTOCHECK_
+
+ BOOLEAN bPrev;
+
+ Message->SetLoggingEnabled();
+ bPrev = Message->SetDotsOnly(FALSE);
+
+ if (bPrev) {
+
+ if (NULL != DriveLetter) {
+ Message->Set(MSG_CHK_RUNNING);
+ Message->Display("%W", DriveLetter);
+ }
+
+ Message->Set(MSG_FILE_SYSTEM_TYPE);
+ Message->Display("%s", "HPFS");
+ }
+#endif /* _AUTOCHECK_ */
+ }
+
+
+
+ // Check the version number.
+
+ if( _SuperBlock.QueryVersion() != SUPERB_VERSION ||
+ ( _SuperBlock.QueryFuncVersion() != SUPERB_FVERSION_2 &&
+ _SuperBlock.QueryFuncVersion() != SUPERB_FVERSION_3 ) ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_WRONG_VERSION );
+ Message->Display( "" );
+
+ return FALSE;
+ }
+
+
+ // We initialize the bitmap without a hotfix list; we'll need
+ // to set its hotfix list before we try to read or write it.
+
+ if ( !(_Bitmap = NEW HPFS_BITMAP()) ||
+ !_Bitmap->Initialize( _drive,
+ _SuperBlock.QueryDirblkMapLbn(),
+ _SuperBlock.QueryDirBandSize(),
+ _SuperBlock.QueryDirBandLbn(),
+ NULL ) ) {
+
+ DebugPrint( "Cannot allocate bitmap.\n" );
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_INSUFFICIENT_MEMORY );
+ Message->Display("");
+ }
+
+ perrstk->push(NEW_ALLOC_FAILED, QueryClassId());
+
+ DELETE( _Bitmap );
+ DELETE( DeferredActionsList );
+ DELETE( DirblkCache );
+
+ return FALSE;
+ }
+
+
+ // Note that the bitmap object begins (by default) with every
+ // sector marked free. We need to mark the boot block, the
+ // super and spares blocks, the bitmap-indirect block, and the
+ // SID list as used in the bitmap.
+
+ LbnsInSuperArea = EndOfSuperArea - StartOfSuperArea + 1;
+
+ if ( !_Bitmap->SetAllocated(StartOfSuperArea, LbnsInSuperArea) ||
+ !_Bitmap->SetAllocated(_SuperBlock.QuerySidTableLbn(), 8) ) {
+
+ DebugAbort("Unable to set bits in bitmap");
+
+ perrstk->push(ERR_CHKDSK_UNEXPECTEDERR, QueryClassId());
+
+ DELETE( DeferredActionsList );
+ DELETE( DirblkCache );
+
+ return FALSE;
+ }
+
+ // Mark the spare dirblks as in use in the bitmap.
+
+ i = 0;
+ while( (lbn = _SparesBlock.QuerySpareDirblkLbn(i)) != 0 ) {
+
+ _Bitmap->SetAllocated( lbn, SectorsPerDirblk );
+ i += 1;
+ }
+
+ // Allocate and verify the the ancillary objects. These objects
+ // are used to model the elementary file system structures that
+ // exist outside the super area. We'll need to check them before
+ // we can check the directory tree, since they contain information
+ // about the status of the volume.
+
+ // The process of verifying these structures will also ensure that
+ // they are set up to support verification of the directory tree.
+
+ if ( !(_HotfixList = QueryHotFixList()) ||
+ !(_BadBlockList = QueryBadBlockList()) ||
+ !(_Codepage = QueryCodePage()) ||
+ !(BitmapIndirect = QueryBitMapInd()) ) {
+
+ // The super-areas ancillary objects could not
+ // be allocated.
+
+ DebugPrint( "Unable to create helper objects\n" );
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_INSUFFICIENT_MEMORY );
+ Message->Display("");
+ }
+
+ perrstk->push(ERR_CHKDSK_UNEXPECTEDERR, QueryClassId());
+
+ DELETE( DeferredActionsList );
+ DELETE( DirblkCache );
+
+ return FALSE;
+ }
+
+
+ if( BitmapIndirect->VerifyAndFix(this) == VERIFY_STRUCTURE_INVALID ) {
+
+ DebugPrint( "Bitmap indirect block unrecoverable.\n" );
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_ELEMENTARY_CORRUPTION );
+ Message->Display("");
+ }
+
+ DELETE( DeferredActionsList );
+ DELETE( DirblkCache );
+
+ *ExitStatus = CHKDSK_EXIT_COULD_NOT_FIX;
+
+ return FALSE;
+ }
+
+ // Note that the dirblk band structures (dirblk bitmap and
+ // the band itself) are marked as allocated in the bitmap
+ // when the bitmap is initialized.
+
+ if( _SuperBlock.QueryDirBandSize() % SectorsPerDirblk != 0 ||
+ _SuperBlock.QueryDirBandLbn() % SectorsPerDirblk != 0 ) {
+
+
+ DebugPrint( "Directory Band Bitmap is unrecoverable.\n" );
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_ELEMENTARY_CORRUPTION );
+ Message->Display("");
+ }
+
+ DELETE( DeferredActionsList );
+ DELETE( DirblkCache );
+
+ *ExitStatus = CHKDSK_EXIT_COULD_NOT_FIX;
+
+ return FALSE;
+
+ } else {
+
+ _Bitmap->SetAllocated( _SuperBlock.QueryDirblkMapLbn(),
+ SectorsPerBitmap );
+ }
+
+ if( _HotfixList->VerifyAndFix(this) == VERIFY_STRUCTURE_INVALID ) {
+
+ DebugPrint( "Hotfix List unrecoverable.\n" );
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_ELEMENTARY_CORRUPTION );
+ Message->Display("");
+ }
+
+ DELETE( DeferredActionsList );
+ DELETE( DirblkCache );
+
+ *ExitStatus = CHKDSK_EXIT_COULD_NOT_FIX;
+
+ return FALSE;
+ }
+
+ if( _BadBlockList->VerifyAndFix(this, &BadSectors) ==
+ VERIFY_STRUCTURE_INVALID ) {
+
+ DebugPrint( "Bad block list unrecoverable.\n" );
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_ELEMENTARY_CORRUPTION );
+ Message->Display("");
+ }
+
+ DELETE( DeferredActionsList );
+ DELETE( DirblkCache );
+
+ *ExitStatus = CHKDSK_EXIT_COULD_NOT_FIX;
+
+ return FALSE;
+ }
+
+ if( _Codepage->VerifyAndFix(_drive,
+ _HotfixList,
+ _Bitmap,
+ _SparesBlock.QueryCpInfoLbn(),
+ UpdateVolume,
+ &ErrorsDetected) != VERIFY_STRUCTURE_OK ) {
+
+ DebugPrint( "Codepages unrecoverable.\n" );
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_ELEMENTARY_CORRUPTION );
+ Message->Display("");
+ }
+
+ DELETE( DeferredActionsList );
+ DELETE( DirblkCache );
+
+ *ExitStatus = CHKDSK_EXIT_COULD_NOT_FIX;
+
+ return FALSE;
+ }
+
+ // OK, now that we have the hotfix list, we can give it to the
+ // bitmap object.
+ _Bitmap->SetHotfixList( _HotfixList );
+
+
+ // The elementary disk structures have passed muster, so we
+ // can turn our attention to the directory tree. Initialize
+ // the RootFnode object to hold the volume's Root Fnode, and
+ // tell it to verify itself.
+
+ if( !RootFnode.Initialize(_drive, _SuperBlock.QueryRootFnodeLbn()) ||
+ !DeferredActionsList->Initialize() ||
+ !CurrentPath.Initialize() ) {
+
+ DebugPrint( "Insufficient memory to initialize root fnode object\n" );
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_INSUFFICIENT_MEMORY );
+ Message->Display("");
+ }
+
+ perrstk->push(NEW_ALLOC_FAILED, QueryClassId());
+
+ DELETE( DeferredActionsList );
+ DELETE( DirblkCache );
+
+ return FALSE;
+ }
+
+
+ erc = RootFnode.VerifyAndFix( this,
+ DeferredActionsList,
+ &CurrentPath,
+ _SuperBlock.QueryRootFnodeLbn(),
+ TRUE,
+ &TrashCan,
+ &TrashCan,
+ Message,
+ &ErrorsDetected,
+ UpdateVolume,
+ Verbose
+ );
+
+ switch( erc ) {
+
+ case VERIFY_INSUFFICIENT_RESOURCES :
+
+ DebugPrint( "Insufficient memory to check directory tree.\n" );
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_INSUFFICIENT_MEMORY );
+ Message->Display("");
+ }
+
+ DELETE( DeferredActionsList );
+ DELETE( DirblkCache );
+
+ return FALSE;
+
+
+ case VERIFY_STRUCTURE_INVALID :
+
+ // The Root Fnode is unrecoverably corrupt; we
+ // cannot verify this volume.
+
+ DebugPrint( "Root FNode is corrupt.\n" );
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_ELEMENTARY_CORRUPTION );
+ Message->Display( "" );
+ }
+
+ DELETE( DeferredActionsList );
+ DELETE( DirblkCache );
+
+ *ExitStatus = CHKDSK_EXIT_COULD_NOT_FIX;
+
+ return FALSE;
+
+
+ case VERIFY_INTERNAL_ERROR :
+
+ DebugAbort( "Internal error verifying root FNode.\n" );
+
+ DELETE( DeferredActionsList );
+ DELETE( DirblkCache );
+
+ return FALSE;
+ }
+
+
+ if( Message!= NULL && ErrorsDetected ) {
+
+ if( UpdateVolume ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_ERRORS_FIXED );
+ Message->Display( "" );
+
+ *ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+
+ } else {
+
+ Message->Set( MSG_HPFS_CHKDSK_ERRORS_DETECTED );
+ Message->Display( "" );
+
+ *ExitStatus = CHKDSK_EXIT_ERRS_NOT_FIXED;
+ }
+ }
+
+
+ // Look for orphans, and build them up in OrphansList. First,
+ // set up the orphans list, the secrun we'll use to read
+ // potential orphans, and its mem object. Then query the
+ // bitmap for potential orphans. For each potential orphan
+ // Lbn returned, attempt to recover it. If it is an orphan,
+ // it will add itself to the orphans list.
+
+ if( !OrphansList.Initialize() ||
+ !OrphanMem.Initialize() ||
+ !OrphanSecrun.Initialize( &OrphanMem, _drive, 0, 1 ) ) {
+
+
+ DebugPrint( "Insufficient memory to initialize orphans list.\n" );
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_INSUFFICIENT_MEMORY_ORPHANS );
+ Message->Display("");
+ }
+
+ OrphansError = TRUE;
+
+ } else {
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_SEARCHING_FOR_ORPHANS );
+ Message->Display( "" );
+ }
+
+ while( !OrphansError &&
+ _Bitmap->QueryNextOrphan( BitmapIndirect,
+ &OrphanLbn,
+ &AllocationErrors ) &&
+ OrphanLbn != 0 ) {
+
+ if( !OrphansList.RecoverOrphan( _drive,
+ this,
+ DeferredActionsList,
+ OrphanLbn,
+ &OrphanSecrun,
+ UpdateVolume ) ) {
+
+ OrphansError = TRUE;
+ }
+ }
+
+
+ if( OrphansError &&
+ Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_INSUFFICIENT_MEMORY_ORPHANS );
+ Message->Display( "" );
+ }
+ }
+
+ if( Message != NULL &&
+ OrphansList.QueryOrphansFound() ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_ORPHANS_FOUND );
+ Message->Display( "" );
+ }
+
+ if( Message != NULL &&
+ AllocationErrors ) {
+
+ // We detected allocation errors (sectors marked as free
+ // that should be marked as in use) while looking for orphans;
+ // tell the user about it.
+
+ if( !UpdateVolume ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_ALLOCATION_ERROR_NOT_FIXED );
+
+ } else {
+
+ Message->Set( MSG_HPFS_CHKDSK_ALLOCATION_ERROR_FIXED );
+ }
+
+ Message->Display( "" );
+ }
+
+ // Now that we've finished traversing both the tree and the
+ // orphans, we make sure all replaced and replacement sectors
+ // in the hotfix list are marked as used in the bitmap, to
+ // prevent them from being allocated while we resolve the
+ // deferred actions.
+
+ _HotfixList->MarkAllUsed( _Bitmap );
+
+
+ // If Chkdsk is running in look-only mode, then all the
+ // work is done. If it's supposed to fix the disk, then
+ // it has to resolve the deferred actions and save the
+ // orphans.
+
+ if( UpdateVolume ) {
+
+ // If the orphan-search hit an error, we AND the the bitmap
+ // with the on-disk bitmap, so that orphans will not get
+ // allocated in the next steps. We don't mind if this fails,
+ // but we at least try to preserve the orphans.
+
+ if( OrphansError ) {
+
+ _Bitmap->AndWithDisk( BitmapIndirect );
+ }
+
+ // Resolve the deferred actions. Note that both the directory-
+ // tree validation phase and the orphan recovery phase may
+ // have added actions to the deferred actions list. Resolution
+ // of the deferred actions does not return a success or failure
+ // indicator; instead, after the fact, we ask the deferred
+ // actions list if any deferred actions are still outstanding.
+
+ DeferredActionsList->ResolveDeferredHotfixes( _drive, this );
+
+ DeferredActionsList->ResolveDeferredCrosslinks( _drive, this );
+
+
+ // The Sort and Delete phases and the orphan-saving phase
+ // need the root directory tree.
+
+ if( DirblkCache->Initialize( _drive, _HotfixList ) &&
+ RootTree.Initialize( this,
+ DirblkCache,
+ RootFnode.QueryRootDirblkLbn(),
+ RootFnode.QueryStartLbn() ) ) {
+
+ DeferredActionsList->Sort( _drive,
+ this,
+ DirblkCache,
+ RootFnode.QueryStartLbn(),
+ &RootTree );
+
+ // The sort phase may have changed the root directory's
+ // root dirblk--if so, propagate that change to the
+ // root FNode before the delete phase.
+
+ if( RootFnode.QueryRootDirblkLbn() !=
+ RootTree.QueryRootDirblkLbn() ) {
+
+ RootFnode.SetRootDirblkLbn( RootTree.QueryRootDirblkLbn() );
+ RootFnode.Write();
+ }
+
+ DeferredActionsList->Delete( _drive,
+ this,
+ DirblkCache,
+ &RootTree,
+ RootFnode.QueryStartLbn() );
+
+ if( !OrphansError &&
+ !OrphansList.Save( _drive,
+ this,
+ DirblkCache,
+ &RootTree,
+ RootFnode.QueryStartLbn(),
+ Message ) ) {
+
+ // Note that Save sends its own failure messages.
+ DebugPrint( "Could not save orphans.\n" );
+ }
+
+ DirblkCache->Flush();
+
+ if( RootFnode.QueryRootDirblkLbn() !=
+ RootTree.QueryRootDirblkLbn() ) {
+
+ RootFnode.SetRootDirblkLbn( RootTree.QueryRootDirblkLbn() );
+ RootFnode.Write();
+ }
+
+ } else {
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_INSUFF_MEMORY_TO_FIX );
+ Message->Display( "" );
+
+ *ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
+ }
+ }
+
+
+ // Check to see if there are any unresolved deferred
+ // actions.
+
+ if( Message != NULL ) {
+
+ if( DeferredActionsList->QueryUnresolvedHotfixes() ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_UNRESOLVED_HOTFIXES );
+ Message->Display( "" );
+ }
+
+ if( DeferredActionsList->QueryUnresolvedSorts() ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_UNRESOLVED_SORTS );
+ Message->Display( "" );
+ }
+
+ if( DeferredActionsList->QueryUnresolvedDeletes() ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_UNRESOLVED_DELETES );
+ Message->Display( "" );
+ }
+ }
+
+ _HotfixList->ClearList(
+ _Bitmap,
+ _BadBlockList,
+ !DeferredActionsList->QueryUnresolvedHotfixes() );
+
+ _HotfixList->Write();
+
+ if( !_Bitmap->Write( BitmapIndirect ) ) {
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_CANT_WRITE_BITMAP );
+ Message->Display( "" );
+ }
+
+ } else {
+
+ BitmapIndirect->Write();
+ }
+
+
+ // Set the count of bad sectors in the superblock; BadSectors
+ // is the number of bad sectors in the on disk list, so we
+ // can add it to the number of sectors in the in-memory disk
+ // to get the total.
+
+ BadSectors += _BadBlockList->QueryLength();
+
+ _SuperBlock.SetBadSectors( BadSectors );
+ _SuperBlock.Write( );
+
+ // Set the spares block's flags and checksums,
+ // and write it out.
+
+ _SparesBlock.SetFlags( TRUE );
+ _SparesBlock.ComputeAndSetChecksums( &_SuperBlock );
+
+ _SparesBlock.Write( );
+
+ _BadBlockList->Write( this );
+ }
+
+ DeferredActionsList->StatReport( _drive->QuerySectors().GetLowPart(),
+ _Bitmap->QueryFreeSectors(),
+ _drive->QuerySectorSize(),
+ BadSectors,
+ Message );
+
+ // final fixups
+ DELETE( BitmapIndirect );
+ DELETE( DeferredActionsList );
+ DELETE( DirblkCache );
+
+ *ExitStatus = exit_status;
+
+ return TRUE;
+}
diff --git a/private/utils/uhpfs/src/hpfsea.cxx b/private/utils/uhpfs/src/hpfsea.cxx
new file mode 100644
index 000000000..00c72c877
--- /dev/null
+++ b/private/utils/uhpfs/src/hpfsea.cxx
@@ -0,0 +1,994 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ hpfsea.cxx
+
+Abstract:
+
+ This module contains member function definitions for the HPFS_EA
+ object, which models an HPFS Extended Attribute. This class is
+ essentially a template which can be laid over an arbitrary piece
+ of memory to interpret that memory as an HPFS Extended Attribute.
+
+Author:
+
+ Bill McJohn (billmc) 01-Dec-1990
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "alsec.hxx"
+#include "bitmap.hxx"
+#include "defer.hxx"
+#include "error.hxx"
+#include "hotfix.hxx"
+#include "hpfsea.hxx"
+#include "hpfssa.hxx"
+#include "orphan.hxx"
+
+DEFINE_EXPORTED_CONSTRUCTOR( HPFS_EA, OBJECT, UHPFS_EXPORT );
+
+UHPFS_EXPORT
+HPFS_EA::~HPFS_EA(
+ )
+/*++
+--*/
+{
+ _Drive = NULL;
+ _Data = NULL;
+}
+
+
+UHPFS_EXPORT
+BOOLEAN
+HPFS_EA::Initialize(
+ PLOG_IO_DP_DRIVE Drive,
+ PEA_DATA Data,
+ LBN ParentLbn
+ )
+/*++
+
+Routine Description:
+
+ This method initializes an HPFS_EA object.
+
+Arguments:
+
+ Drive -- Supplies the drive on which the EA resides.
+ Data -- Supplies a pointer to the EA data.
+ ParentLbn -- Supplies the LBN of the parent structure.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ _Drive = Drive;
+ _Data = Data;
+ _ParentLbn = ParentLbn;
+
+ _IsModified = FALSE;
+
+ return TRUE;
+}
+
+
+
+LBN
+HPFS_EA::GetLbnFromEaIndirect(
+ PEA_INDIRECT peaind
+ )
+/*++
+
+Routine Description:
+
+ This method extracts the LBN field from an EA_INDIRECT record.
+ Note that it uses memcpy, since there is no alignment guarantee
+ for the EA_INDIRECT record.
+
+Arguments:
+
+ peaind -- Supplies the EA_INDIRECT record.
+
+Return Value:
+
+ The LBN field of the EA_INDIRECT record.
+
+--*/
+{
+ LBN Lbn;
+
+ memcpy( &Lbn, peaind->lbn, sizeof(LBN) );
+
+ return Lbn;
+}
+
+
+
+ULONG
+HPFS_EA::GetLengthFromEaIndirect(
+ PEA_INDIRECT peaind
+ )
+/*++
+
+Routine Description:
+
+ This method extracts the Length field from an EA_INDIRECT record.
+ Note that it uses memcpy, since there is no alignment guarantee
+ for the EA_INDIRECT record.
+
+Arguments:
+
+ peaind -- Supplies the EA_INDIRECT record.
+
+Return Value:
+
+ The Length field of the EA_INDIRECT record.
+
+--*/
+{
+ ULONG cb;
+
+ memcpy( &cb, peaind->cb, sizeof(ULONG) );
+
+ return cb;
+}
+
+
+
+VOID
+HPFS_EA::SetLbnInEaIndirect(
+ PEA_INDIRECT peaind,
+ LBN Lbn
+ )
+/*++
+
+Routine Description:
+
+ This method sets the LBN field in an EA_INDIRECT record. Note
+ that it uses memcpy, since there is no alignment guarantee
+ for the EA_INDIRECT record.
+
+Arguments:
+
+ peaind -- Supplies the EA_INDIRECT record.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ memcpy( peaind->lbn, &Lbn, sizeof(LBN) );
+}
+
+
+
+VOID
+HPFS_EA::SetLengthInEaIndirect(
+ PEA_INDIRECT peaind,
+ ULONG cb
+ )
+/*++
+
+Routine Description:
+
+ This method sets the Length field in an EA_INDIRECT record. Note
+ that it uses memcpy, since there is no alignment guarantee for the
+ EA_INDIRECT record.
+
+Arguments:
+
+ peaind -- Supplies the EA_INDIRECT record.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ memcpy( peaind->cb, &cb, sizeof(ULONG) );
+}
+
+
+
+VERIFY_RETURN_CODE
+HPFS_EA::VerifyAndFix(
+ IN PHPFS_SA SuperArea,
+ IN PDEFERRED_ACTIONS_LIST DeferredActions,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN ErrorsDetected,
+ IN BOOLEAN UpdateAllowed,
+ IN OUT PHPFS_ORPHANS OrphansList
+ )
+/*++
+
+Routine Description:
+
+ This method verifies the validity (and fixes any errors it detects)
+ of the Extended Attribute.
+
+Arguments:
+
+ SuperArea -- Supplies the super-area for the volume being
+ checked.
+ DeferredActions -- Supplies the deferred-actions list for this pass
+ of CHKDSK
+ Message -- Supplies an outlet for messages
+ ErrorsDetected -- Receives TRUE if this method detects an error
+ which does not trigger a message.
+ UpdateAllowed -- Supplies a flag which indicates, if TRUE,
+ that corrections should be written to disk.
+ OrphansList -- Supplies a list of previously-recovered orphans that
+ may be claimed as children. (May be NULL).
+
+--*/
+{
+
+ PBYTE pb;
+ PEA_INDIRECT peaind;
+ ULONG csec;
+
+ VERIFY_RETURN_CODE erc;
+ ALSEC ChildAlsec;
+ LBN NextSectorNumber;
+ LBN NewLbn;
+ ULONG AllocatedSize;
+ ULONG SectorSize;
+
+ // Look at the character after the name:
+
+ pb = (PBYTE)_Data + EA_HEADER_SIZE + GetNameLength();
+
+ if( *pb != 0 ) {
+
+ // The name is not null-terminated; put a null there.
+
+ *ErrorsDetected = TRUE;
+ DebugPrint( "Extended attribute name is not NULL-terminated.\n" );
+ *pb = 0;
+ MarkModified();
+ }
+
+ // Advance pb to the EA's value field:
+ pb += 1;
+
+ if( GetFlags() & FF_BIGD ) {
+
+ // The EA's value is stored out-of-stream, so we
+ // need to check its allocation.
+
+ peaind = (PEA_INDIRECT)pb;
+
+ SectorSize = _Drive->QuerySectorSize();
+
+ if( GetFlags() & FF_DAT ) {
+
+ // peaind->lbn is an allocation sector, the root
+ // of an allocation tree. Verify that tree.
+
+ // If the child ALSEC lbn is hotfixed, resolve
+ // that reference.
+
+ NewLbn = SuperArea->GetHotfixList()->
+ GetLbnTranslation( GetLbnFromEaIndirect( peaind) );
+
+ if ( GetLbnFromEaIndirect( peaind) != NewLbn ) {
+
+ *ErrorsDetected = TRUE;
+ SetLbnInEaIndirect( peaind, NewLbn );
+ MarkModified();
+ }
+
+ if( !ChildAlsec.Initialize( _Drive,
+ GetLbnFromEaIndirect(peaind) ) ) {
+
+ return VERIFY_INSUFFICIENT_RESOURCES;
+ }
+
+ NextSectorNumber = 0;
+
+ erc = ChildAlsec.VerifyAndFix( SuperArea,
+ DeferredActions,
+ NULL,
+ _ParentLbn,
+ &NextSectorNumber,
+ Message,
+ ErrorsDetected,
+ UpdateAllowed,
+ OrphansList );
+
+
+ if( erc != VERIFY_STRUCTURE_OK ) {
+
+ // Look in the orphan list (if we have one);
+ // if we can't find the child there, either,
+ // then propagate the error up to the parent.
+ // Note that we call LookupAlsec with IsParentFnode
+ // set to FALSE, since we know we're an auxillary
+ // storage structure.
+
+ NextSectorNumber = 0;
+
+ if( OrphansList == NULL ||
+ !OrphansList->LookupAlsec( GetLbnFromEaIndirect(peaind),
+ _ParentLbn,
+ &NextSectorNumber,
+ UpdateAllowed,
+ FALSE ) ) {
+
+ return erc;
+ }
+ }
+
+ // Check that the EA value fits in the space
+ // claimed by the child allocation tree. If it
+ // doesn't truncate the value length.
+
+ AllocatedSize = SectorSize * NextSectorNumber;
+
+ if( GetLengthFromEaIndirect(peaind) > AllocatedSize ) {
+
+ *ErrorsDetected = TRUE;
+ SetLengthInEaIndirect( peaind, AllocatedSize );
+ MarkModified();
+ }
+
+ DeferredActions->StatEaData( NextSectorNumber );
+
+ } else {
+
+ // The Extended Attribute's value is stored in
+ // a single data run.
+
+ csec = (GetLengthFromEaIndirect(peaind) - 1 + SectorSize) /
+ SectorSize;
+
+ if( !SuperArea->GetBitmap()->
+ IsFree( GetLbnFromEaIndirect(peaind), csec ) ) {
+
+ // The EA data run is crosslinked--it's bad.
+
+ return VERIFY_STRUCTURE_INVALID;
+ }
+
+ SuperArea->GetBitmap()->
+ SetAllocated( GetLbnFromEaIndirect(peaind), csec );
+
+ if( SuperArea->GetHotfixList()->
+ IsInList( GetLbnFromEaIndirect(peaind), csec ) ) {
+
+ DeferredActions->AddHotfixedLbn(_ParentLbn,
+ DEFER_FNODE,
+ DEFER_EA_DATA);
+ }
+
+ DeferredActions->StatEaData( csec );
+ }
+ }
+
+ return VERIFY_STRUCTURE_OK;
+}
+
+
+
+BOOLEAN
+HPFS_EA::FindAndResolveHotfix(
+ PHPFS_SA SuperArea
+ )
+/*++
+
+Routine Description:
+
+ Resolves all hotfix references in the Extended Attribute.
+
+Arguments:
+
+ SuperArea -- volume superarea
+
+Return Value:
+
+ TRUE if successful
+
+Notes:
+
+ The only interesting case is if the EA value is stored as
+ a single out-of-stream run. If that run is hotfixed, we
+ copy it to a new location.
+
+--*/
+{
+ PHOTFIXLIST HotfixList;
+ PEA_INDIRECT peaind;
+ LBN StartLbn, NewLbn;
+ ULONG SectorSize, SectorsInList;
+
+
+ if( GetFlags() & (FF_BIGD | ~FF_DAT) ) {
+
+ // The EA's value is stored in a single out-of-stream
+ // run, so we need to see if that run is hotfixed.
+
+ HotfixList = SuperArea->GetHotfixList();
+ SectorSize = _Drive->QuerySectorSize();
+
+ peaind = (PEA_INDIRECT)GetValue();
+ StartLbn = GetLbnFromEaIndirect(peaind);
+ SectorsInList = (GetLengthFromEaIndirect(peaind) - 1 + SectorSize) /
+ SectorSize;
+
+ while( HotfixList->IsInList( StartLbn, SectorsInList ) ) {
+
+ // Copy the run to a new location-- return FALSE if
+ // we can't copy it.
+
+ if( !SuperArea->CopyRun( StartLbn, SectorsInList, &NewLbn ) ) {
+
+ return FALSE;
+ }
+
+ SetLbnInEaIndirect( peaind, NewLbn );
+ _IsModified = TRUE;
+
+ // Now that we've relocated the run, we free up its
+ // old sectors and clear the hotfix references. (Note
+ // the ClearRun will mark the bad sectors as used and
+ // add them to the badblock list.
+
+ SuperArea->GetBitmap()->SetFree( StartLbn, SectorsInList );
+
+ HotfixList->ClearRun( StartLbn, SectorsInList, SuperArea );
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+HPFS_EA::QueryPackedEa(
+ OUT PVOID OutputBuffer,
+ IN ULONG BufferLength,
+ IN OUT PULONG OffsetIntoBuffer,
+ OUT PBOOLEAN IsCorrupt,
+ IN PHOTFIXLIST HotfixList
+ )
+/*++
+
+Routine Description:
+
+ This method copies the Extended Attribute into the client's buffer.
+
+Arguments:
+
+ OutputBuffer -- Supplies the client's buffer.
+ BufferLength -- Supplies the total length of the buffer.
+ OffsetIntoBuffer -- Supplies the point in the buffer to which
+ this EA should be copied.
+ Receives the offset of the point to which
+ the next EA should be copied (ie. is incremented
+ by the size of this EA).
+ IsCorrupt -- Receives TRUE if the EA is found to be corrupt.
+ HotfixList -- Supplies the volume hotfix list. May be NULL,
+ in which case hotfixes are ignored.
+
+Return Value:
+
+ TRUE upon successful completion. If the EA is found to be corrupt,
+ this method sets *IsCorrupt to TRUE and returns FALSE.
+
+Notes:
+
+ This method returns the actual Extended Attribute, so if the value
+ is stored out-of-stream, it must be read off disk.
+
+--*/
+{
+ ALSEC ChildAlsec;
+ HMEM TempBuffer;
+ HOTFIX_SECRUN ValueSecrun;
+ ULONG RunLength, LengthInBytes, SectorSize, BytesRead;
+ BYTE FlagsByte;
+ PEA_DATA TargetEa;
+ PEA_INDIRECT peaind;
+
+
+
+ if( *OffsetIntoBuffer + QuerySize() > BufferLength ) {
+
+ // This extended attribute will not fit into the
+ // client's buffer.
+
+ return FALSE;
+ }
+
+ FlagsByte = GetFlags();
+
+ if( FlagsByte & FF_BIGD ) {
+
+ // The extended attribute's value is stored out-of-stream.
+ // Extract the EA Indirect record from the value stored
+ // in-stream.
+
+ peaind = (PEA_INDIRECT)( GetValue() );
+ LengthInBytes = GetLengthFromEaIndirect( peaind );
+
+ // Copy the EA header and the name. Since we will copy the
+ // actual value into the client's buffer, we have to clear
+ // FF_BIGD (and FF_DAT if it is set) and change the length
+ // field to describe the length of the value, rather than the
+ // length of the EA Indirect record.
+
+ // The amount we copy at this point is the EA header, the
+ // name, and the null byte that follows the name.
+
+ TargetEa = (PEA_DATA)( (PBYTE)OutputBuffer + *OffsetIntoBuffer );
+
+ memcpy( TargetEa,
+ _Data,
+ EA_HEADER_SIZE + GetNameLength() + sizeof(BYTE) );
+
+ // Bump *OffsetIntoBuffer to reflect what we just copied.
+
+ *OffsetIntoBuffer += EA_HEADER_SIZE + GetNameLength() + sizeof(BYTE);
+
+ // Clear the HPFS-internal flags in the client's copy and set
+ // the value-length of the client's copy to the actual length
+ // of the value.
+
+ TargetEa->fEA &= ~( FF_BIGD | FF_DAT );
+ memcpy( TargetEa->cbValue, &LengthInBytes, 2 );
+
+
+ // Now read the value off disk and copy it into the
+ // client's buffer.
+
+ SectorSize = _Drive->QuerySectorSize();
+
+ if( FlagsByte & FF_DAT ) {
+
+ // This extended attribute is fragmented on disk;
+ // its allocation is described by an allocation sector.
+
+ if( !ChildAlsec.Initialize( _Drive,
+ GetLbnFromEaIndirect( peaind ) ) ||
+ !ChildAlsec.Read() ||
+ !ChildAlsec.IsAlsec() ||
+ !ChildAlsec.ReadData( 0,
+ OutputBuffer,
+ LengthInBytes,
+ &BytesRead,
+ HotfixList ) ||
+ BytesRead != LengthInBytes ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+
+ } else {
+
+ // This extended attribute is stored as a single
+ // run on disk; read its data into the client's buffer.
+
+ RunLength = ( LengthInBytes - 1 + SectorSize ) / SectorSize;
+
+ if( !TempBuffer.Initialize() ||
+ !ValueSecrun.Initialize( &TempBuffer,
+ _Drive,
+ HotfixList,
+ GetLbnFromEaIndirect( peaind ),
+ RunLength ) ) {
+
+ return FALSE;
+ }
+
+ if( !ValueSecrun.Read() ) {
+
+ // The EA value is unreadable.
+
+ DebugPrint( "Unreadable EA value.\n" );
+
+ *IsCorrupt = TRUE;
+ return FALSE;
+ }
+
+ memcpy( (PBYTE)OutputBuffer + *OffsetIntoBuffer,
+ ValueSecrun.GetBuf(),
+ LengthInBytes );
+
+ *OffsetIntoBuffer += LengthInBytes;
+
+ return TRUE;
+ }
+
+ } else {
+
+ // The Extended Attribute's value is stored in-stream,
+ // so we can just copy the Extended Attribute into the
+ // client's buffer.
+
+ memcpy( (PBYTE)OutputBuffer + *OffsetIntoBuffer,
+ _Data,
+ QuerySize() );
+
+ *OffsetIntoBuffer += QuerySize();
+
+ return TRUE;
+ }
+}
+
+
+BYTE
+HPFS_EA::GetFlags(
+ )
+/*++
+
+Routine Description:
+
+ This method returns the flags for this Extended Attribute
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The EA flags byte.
+
+--*/
+{
+ return _Data->fEA;
+}
+
+
+
+VOID
+HPFS_EA::SetFlags(
+ BYTE NewFlags
+ )
+{
+ _Data->fEA = NewFlags;
+}
+
+
+
+BYTE
+HPFS_EA::GetNameLength(
+ )
+/*++
+
+Routine Description:
+
+ This method returns the length of the EA's name.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The length of the EA's name.
+
+--*/
+{
+ return _Data->cbName;
+}
+
+
+
+VOID
+HPFS_EA::SetNameLength(
+ BYTE NewNameLength
+ )
+/*++
+
+Routine Description:
+
+ This method sets the length of the Extended Attribute's name.
+
+Arguments:
+
+ NewNameLength -- Supplies the new name length.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _Data->cbName = NewNameLength;
+}
+
+
+
+USHORT
+HPFS_EA::GetValueLength(
+ )
+/*++
+
+Routine Description:
+
+ This method fetches the length of the Extended Attribute's value.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The length of the Extended Attribute's value.
+
+--*/
+{
+ USHORT ReturnValue;
+
+ memcpy( &ReturnValue, _Data->cbValue, sizeof(USHORT) );
+
+ return ReturnValue;
+}
+
+
+
+VOID
+HPFS_EA::SetValueLength(
+ USHORT NewValueLength
+ )
+/*++
+
+Routine Description:
+
+ This method sets the length of the Extended Attribute's value.
+
+Arguments:
+
+ NewValueLength -- Supplies the new value length.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ memcpy( _Data->cbValue, &NewValueLength, sizeof(USHORT) );
+}
+
+
+
+PBYTE
+HPFS_EA::GetName(
+ )
+/*++
+
+Routine Description:
+
+ This method fetches the Extended Attribute's name.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer the the Extended Attribute's name. Note that this pointer
+ becomes invalid if this object is destroyed or reinitialized.
+
+--*/
+{
+ return( (PBYTE)_Data + EA_HEADER_SIZE );
+}
+
+
+
+PBYTE
+HPFS_EA::GetValue(
+ )
+/*++
+
+Routine Description:
+
+ This method fetches the Extended Attribute's value.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the Extended Attribute's value. Note that this pointer
+ will be invalid if this object is destroyed or reinitialized.
+
+ Note also that if the Extended Attribute's actual value is stored
+ out-of-stream (FF_BIGD is set in the flags byte), this will return
+ a pointer to the EA Indirect record (rather than the actual value).
+
+--*/
+{
+ // The value is stored after the name; there is also one
+ // null byte after the name and before the value.
+
+ return( (PBYTE)_Data + EA_HEADER_SIZE + GetNameLength() + 1 );
+}
+
+
+
+VOID
+HPFS_EA::MarkModified(
+ )
+/*++
+
+Routine Description:
+
+ This method marks this object as modified.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _IsModified = TRUE;
+}
+
+
+
+
+BOOLEAN
+HPFS_EA::IsModified(
+ )
+/*++
+
+Routine Description:
+
+ This method determines whether this object has been marked as modified.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if and only if the object has been marked as modified.
+
+--*/
+{
+ return _IsModified;
+}
+
+
+
+UHPFS_EXPORT
+USHORT
+HPFS_EA::QueryLength(
+ )
+/*++
+
+Routine Description:
+
+ Determine the length of an Extended Attribute. Note that this
+ length is only the in-stream portion of the EA; if the value
+ is stored out-of-stream, the size of the EA will be different
+ from the length.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Length of the Extended Attribute in-run.
+
+--*/
+{
+ if( !_Data ) {
+
+ return 0;
+ }
+
+ return ( EA_HEADER_SIZE + GetNameLength() +
+ sizeof(BYTE) + GetValueLength() );
+}
+
+
+
+ULONG
+HPFS_EA::QuerySize(
+ )
+/*++
+
+Routine Description:
+
+ Determine the size of the Extended Attribute
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Size of the Extended Attribute.
+
+Notes:
+
+ This routine assumes that the value field of the EA can be
+ used.
+
+--*/
+{
+ PEA_INDIRECT peaind;
+ ULONG LengthOfHeaderAndName;
+
+
+
+ if( !_Data ) {
+
+ return 0;
+ }
+
+ // The size of an EA is the sum of:
+ // the size of the EA header
+ // the length of the name
+ // the size of the null that terminates the name
+ // the length of the value
+ //
+ // If the value is stored in-stream, then we just take the
+ // cbValue from the EA header; if it's stored out-of-stream,
+ // we use the count of bytes from the indirect record.
+
+ LengthOfHeaderAndName = EA_HEADER_SIZE + GetNameLength() + sizeof(BYTE);
+
+ if( GetFlags() & FF_BIGD ) {
+
+ peaind = (PEA_INDIRECT)( (PBYTE) _Data + LengthOfHeaderAndName );
+ return( LengthOfHeaderAndName + GetLengthFromEaIndirect(peaind) );
+
+ } else {
+
+ return ( LengthOfHeaderAndName + GetValueLength() );
+ }
+}
+
+
+UHPFS_EXPORT
+BOOLEAN
+HPFS_EA::IsNeedEa(
+ )
+/*++
+
+Routine Description:
+
+ This method determines whether this is a NEED-EAS Extended Attribute.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if and only if this is a NEED-EAS Extended Attribute.
+
+--*/
+{
+ if( !_Data ) return FALSE;
+
+ return ( GetFlags() & FF_NEED );
+}
diff --git a/private/utils/uhpfs/src/hpfseal.cxx b/private/utils/uhpfs/src/hpfseal.cxx
new file mode 100644
index 000000000..234a40f54
--- /dev/null
+++ b/private/utils/uhpfs/src/hpfseal.cxx
@@ -0,0 +1,1811 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ hpfseal.cxx
+
+Abstract:
+
+ This module contains the member function definitions for the
+ HPFS_EA_LIST class. This class models an EA list attached to
+ an HPFS FNode.
+
+Author:
+
+ Bill McJohn (billmc) 19-Dec-1990
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "alsec.hxx"
+#include "error.hxx"
+#include "hpfsea.hxx"
+#include "hpfseal.hxx"
+#include "orphan.hxx"
+#include "hpfssa.hxx"
+#include "cmem.hxx"
+#include "hfsecrun.hxx"
+#include "bitmap.hxx"
+#include "hotfix.hxx"
+#include "hpfsname.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+
+
+DEFINE_CONSTRUCTOR( HPFS_EA_LIST, OBJECT );
+
+VOID
+HPFS_EA_LIST::Construct (
+ )
+
+/*++
+--*/
+{
+ _Drive = NULL;
+ _FnodeData = NULL;
+
+}
+
+HPFS_EA_LIST::~HPFS_EA_LIST(
+ )
+/*++
+--*/
+{
+}
+
+BOOLEAN
+HPFS_EA_LIST::Initialize(
+ PLOG_IO_DP_DRIVE Drive,
+ _FNODE* FnodeData,
+ LBN FnodeLbn
+ )
+{
+ _Drive = Drive;
+ _FnodeData = FnodeData;
+ _FnodeLbn = FnodeLbn;
+
+ _NumberOfEas = 0;
+ _NumberOfNeedEas = 0;
+ _SizeOfEas = 0;
+
+ _FnodeModified = FALSE;
+
+ return TRUE;
+}
+
+
+
+VERIFY_RETURN_CODE
+HPFS_EA_LIST::VerifyAndFix(
+ IN HPFS_SA* SuperArea,
+ IN PDEFERRED_ACTIONS_LIST DeferredActions,
+ IN PHPFS_PATH CurrentPath,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN ErrorsDetected,
+ IN BOOLEAN UpdateAllowed,
+ IN OUT PHPFS_ORPHANS OrphansList
+ )
+/*++
+
+Routine Description:
+
+ Walk and FNode's Extended Attribute List, and verify
+ that the list is well-formed and valid.
+
+Arguments:
+
+Return Value:
+
+Notes:
+
+ The FNode's Access Control List must be verified before the
+ EAs can be verified.
+--*/
+{
+ ULONG LengthInFnode;
+ PBYTE CurrentEa;
+ SHORT RemainingSpace;
+ USHORT LengthOfEa;
+ HPFS_EA ChildEa;
+ VERIFY_RETURN_CODE erc;
+
+
+ _NumberOfEas = 0;
+ _NumberOfNeedEas = 0;
+ _SizeOfEas = 0;
+
+ // Check that the object has been initialized:
+ if ( !_Drive || !_FnodeData ) {
+
+ DebugAbort( "Ea List object not initialized.\n" );
+ return VERIFY_INTERNAL_ERROR;
+ }
+
+ // First, check to see if the Fnode has any EAs--if not, we
+ // can bail out early.
+ if( _FnodeData->_fni.usFNLEA == 0 &&
+ _FnodeData->_fni.lbnEA == 0 ) {
+
+ return VERIFY_STRUCTURE_OK;
+ }
+
+
+ // Determine where the EAs are--in the Fnode or out on disk.
+
+ if( _FnodeData->_fni.lbnEA == 0 ) {
+
+ // The EAs are in the FNode.
+
+ RemainingSpace = sizeof(_FnodeData->abFree) -
+ _FnodeData->_fni.usFNLACL;
+
+ LengthInFnode = 0;
+
+ CurrentEa = _FnodeData->abFree + _FnodeData->_fni.usFNLACL;
+
+ while( LengthInFnode < _FnodeData->_fni.usFNLEA ) {
+
+ ChildEa.Initialize( _Drive, (PEA_DATA)CurrentEa, _FnodeLbn );
+
+ if( RemainingSpace < (SHORT)sizeof(EA_DATA) ||
+ (SHORT)ChildEa.QueryLength() > RemainingSpace ) {
+
+ // The EA overflows the available space;
+ // truncate the list here.
+
+ if( Message != NULL &&
+ CurrentPath != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_TRUNCATED_EAS );
+ Message->Display( "%s", CurrentPath->GetString() );
+ }
+
+ break;
+ }
+
+ if( (erc = ChildEa.VerifyAndFix( SuperArea,
+ DeferredActions,
+ Message,
+ ErrorsDetected,
+ UpdateAllowed,
+ OrphansList )) !=
+ VERIFY_STRUCTURE_OK ) {
+
+
+ if( erc == VERIFY_STRUCTURE_INVALID ) {
+
+ if( Message != NULL &&
+ CurrentPath != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_REMOVED_EA );
+ Message->Display( "%s", CurrentPath->GetString() );
+ }
+
+ LengthOfEa = ChildEa.QueryLength();
+
+ if( _FnodeData->_fni.usFNLEA > LengthOfEa ) {
+
+ _FnodeData->_fni.usFNLEA -= LengthOfEa;
+
+ } else {
+
+ _FnodeData->_fni.usFNLEA = 0;
+ }
+
+ RemainingSpace -= LengthOfEa;
+ memmove( CurrentEa, CurrentEa + LengthOfEa,
+ RemainingSpace );
+
+ _FnodeModified = TRUE;
+
+ } else {
+
+ // We ran out of resources, or got
+ // an internal error. Bail out.
+
+ return erc;
+ }
+
+ } else {
+
+ if( ChildEa.IsModified() ) {
+
+ *ErrorsDetected = TRUE;
+
+ _FnodeModified = TRUE;
+ }
+
+ // Move on to the next EA
+
+ _SizeOfEas += ChildEa.QuerySize();
+
+ LengthOfEa = ChildEa.QueryLength();
+
+ LengthInFnode += LengthOfEa;
+ RemainingSpace -= LengthOfEa;
+ CurrentEa += LengthOfEa;
+
+ if ( ChildEa.IsNeedEa() ) {
+
+ _NumberOfNeedEas +=1;
+ }
+
+ _NumberOfEas += 1;
+ }
+ }
+
+ } else {
+
+ // The EAs are outside the FNode. (Note that we take
+ // this path if there are EAs both in and outside the
+ // FNode; in that case, the EAs in the FNode will be
+ // deleted.)
+
+ LengthInFnode = 0;
+
+
+ if( _FnodeData->_fni.bDatEA != 0 ) {
+
+ // EAs are in an allocation tree
+
+ erc = VerifyInTree(SuperArea,
+ DeferredActions,
+ CurrentPath,
+ Message,
+ ErrorsDetected,
+ UpdateAllowed,
+ OrphansList );
+
+ } else {
+
+ // EAs are in a single run on disk. Note that
+ // VerifyOnDiskRun will never return VERIFY_STRUCTURE_INVALID;
+ // it will either fix things up or report a resource problem.
+
+ erc = VerifyOnDiskRun( SuperArea,
+ DeferredActions,
+ CurrentPath,
+ Message,
+ ErrorsDetected,
+ UpdateAllowed,
+ OrphansList );
+ }
+
+
+ if( erc != VERIFY_STRUCTURE_OK ) {
+
+ return erc;
+ }
+ }
+
+ if( _FnodeData->_fni.usFNLEA != LengthInFnode ) {
+
+ *ErrorsDetected = TRUE;
+
+ _FnodeData->_fni.usFNLEA = (USHORT) LengthInFnode;
+ _FnodeModified = TRUE;
+ }
+
+ return VERIFY_STRUCTURE_OK;
+}
+
+
+VERIFY_RETURN_CODE
+HPFS_EA_LIST::VerifyOnDiskRun(
+ IN OUT PHPFS_SA SuperArea,
+ IN OUT PDEFERRED_ACTIONS_LIST DeferredActions,
+ IN PHPFS_PATH CurrentPath,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN ErrorsDetected,
+ IN BOOLEAN UpdateAllowed,
+ IN OUT PHPFS_ORPHANS OrphansList
+ )
+/*++
+
+Routine Description:
+
+ Verify an EA List that exists in a single run outside the FNode.
+
+Arguments:
+
+ SuperArea -- SuperArea of the volume being checked
+
+ DeferredActions -- deferred actions list for the current
+ pass of Chkdsk.
+
+ UpdateAllowed -- TRUE if we may write corrections to disk
+
+ OrphansList -- list of orphans for the current recovery pass
+ (may be NULL)
+
+Return Value:
+
+ VERIFY_STRUCTURE_OK if the EA list is consistent or can be made
+ consistent.
+
+Notes:
+
+ This private method is only called if we determine that the
+ EAs are outside the FNode, in a single run on disk.
+
+--*/
+{
+ HOTFIX_SECRUN Buffer1, Buffer2;
+ HPFS_EA ChildEa;
+ CONT_MEM Mem;
+ HMEM BufferMem;
+ ULONG SectorSize;
+ ULONG LengthOnDisk, RemainingSpace, RemainingInBuffer1, Overlap;
+ ULONG LengthToBump, RunLength, LengthOfEa;
+ LBN NextLbn;
+ PBYTE CurrentEa;
+ VERIFY_RETURN_CODE erc;
+
+
+ // Check for crosslinks and hotfixes. (NextLbn is set to the first
+ // lbn of the list; we'll use it later.)
+
+ SectorSize = _Drive->QuerySectorSize();
+
+ NextLbn = _FnodeData->_fni.lbnEA;
+ RunLength = (_FnodeData->_fni.cbRunEA + SectorSize - 1)/SectorSize;
+
+ if( !SuperArea->GetBitmap()->IsFree( NextLbn, RunLength ) ) {
+
+ if( Message != NULL &&
+ CurrentPath != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_TRUNCATED_EAS );
+ Message->Display( "%s", CurrentPath->GetString() );
+ }
+
+ DebugPrint( "Removing a crosslinked EA list.\n" );
+
+ _FnodeData->_fni.cbRunEA = 0;
+ _FnodeData->_fni.lbnEA = 0;
+ _FnodeModified = TRUE;
+
+ return VERIFY_STRUCTURE_OK;
+ }
+
+
+ SuperArea->GetBitmap()->SetAllocated( NextLbn, RunLength );
+
+ if( SuperArea->GetHotfixList()->
+ IsInList( NextLbn, RunLength ) ) {
+
+ DeferredActions->
+ AddHotfixedLbn( _FnodeLbn,
+ DEFER_FNODE,
+ DEFER_EA_DATA );
+ }
+
+
+ // Set up to verify the list--initialize the two Secruns
+ // with contiguous memory, and set them to hold the first
+ // two sectors of the list. Note that we use BufferMem
+ // (an HMEM) to allocate a suitably-aligned chunk of memory,
+ // and Mem (a CONT_MEM) to dole it out to the two Secruns.
+
+ if( !BufferMem.Initialize() ||
+ !BufferMem.Acquire( 2 * SectorSize,
+ _Drive->QueryAlignmentMask() ) ) {
+
+ return VERIFY_INSUFFICIENT_RESOURCES;
+ }
+
+ if( !Mem.Initialize( BufferMem.GetBuf(), 2 * SectorSize ) ||
+ !Buffer1.Initialize( &Mem,
+ _Drive,
+ SuperArea->GetHotfixList(),
+ 0,
+ 1 ) ||
+ !Buffer2.Initialize( &Mem,
+ _Drive,
+ SuperArea->GetHotfixList(),
+ 0,
+ 1 ) ) {
+
+ DebugPrint( "Can't check EAs.\n" );
+ return VERIFY_INSUFFICIENT_RESOURCES;
+ }
+
+ Buffer1.Relocate( NextLbn++ );
+ Buffer2.Relocate( NextLbn++ );
+
+ if( !Buffer1.Read() ||
+ ( RunLength > 1 && !Buffer2.Read() ) ) {
+
+ if( Message != NULL &&
+ CurrentPath != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_TRUNCATED_EAS );
+ Message->Display( "%s", CurrentPath->GetString() );
+ }
+
+ DebugPrint( "Removing an unreadable EA list\n" );
+ _FnodeData->_fni.cbRunEA = 0;
+ _FnodeData->_fni.lbnEA = 0;
+ _FnodeModified = TRUE;
+
+ return VERIFY_STRUCTURE_OK;
+ }
+
+ // OK, we've read two sectors of the run.
+
+ RunLength = ( RunLength > 1 ) ? RunLength - 2 : 0;
+
+
+ // Initialize the LengthOnDisk accumulator and the counters of
+ // remaining space in the list and in the current buffer.
+
+ LengthOnDisk = 0;
+ RemainingSpace = _FnodeData->_fni.cbRunEA;
+ RemainingInBuffer1 = SectorSize;
+
+ CurrentEa = (PBYTE)(Buffer1.GetBuf());
+
+ while( RemainingSpace > 0 ) {
+
+ ChildEa.Initialize( _Drive, (PEA_DATA)CurrentEa, _FnodeLbn );
+
+ erc = VERIFY_STRUCTURE_INVALID;
+
+ if( RemainingSpace < sizeof(EA_DATA) ||
+ ChildEa.QueryLength() > RemainingSpace ||
+ (erc = ChildEa.VerifyAndFix( SuperArea,
+ DeferredActions,
+ Message,
+ ErrorsDetected,
+ UpdateAllowed,
+ OrphansList )) !=
+ VERIFY_STRUCTURE_OK ) {
+
+ if( erc == VERIFY_STRUCTURE_INVALID ) {
+
+ // The EA list is corrupt, so we'll truncate
+ // it right here.
+
+ if( Message != NULL &&
+ CurrentPath != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_TRUNCATED_EAS );
+ Message->Display( "%s", CurrentPath->GetString() );
+ }
+
+ DeferredActions->
+ StatEaData( (LengthOnDisk + SectorSize - 1)/SectorSize );
+
+ _FnodeData->_fni.cbRunEA = LengthOnDisk;
+ _FnodeModified = TRUE;
+ return VERIFY_STRUCTURE_OK;
+
+ } else {
+
+ // We ran into a resource problem--bail out.
+
+ return erc;
+ }
+ }
+
+
+ // Move on to the next EA
+
+ _SizeOfEas += ChildEa.QuerySize();
+
+ LengthOfEa = ChildEa.QueryLength();
+ LengthToBump = LengthOfEa;
+
+ RemainingSpace -= LengthOfEa;
+ LengthOnDisk += LengthOfEa;
+
+ if ( ChildEa.IsNeedEa() ) {
+
+ _NumberOfNeedEas +=1;
+ }
+
+ _NumberOfEas += 1;
+
+ // Before we move on, write the current sectors if the
+ // EA changed.
+
+ if( ChildEa.IsModified() ) {
+
+ *ErrorsDetected = TRUE;
+
+ if( UpdateAllowed ) {
+
+ Buffer1.Write();
+
+ if( LengthToBump >= RemainingInBuffer1 ) {
+
+ Buffer2.Write();
+ }
+ }
+ }
+
+
+ while( LengthToBump >= SectorSize ) {
+
+ Buffer1.Relocate( Buffer2.QueryStartLbn() );
+ Buffer2.Relocate( NextLbn++ );
+
+ memmove( Buffer1.GetBuf(), Buffer2.GetBuf(), (UINT)SectorSize );
+
+ if( RunLength > 0 ) {
+
+ if( !Buffer2.Read() ) {
+
+ // Oh No! an unreadable sector!
+
+ if( Message != NULL &&
+ CurrentPath != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_TRUNCATED_EAS );
+ Message->Display( "%s", CurrentPath->GetString() );
+ }
+
+ DeferredActions->
+ StatEaData( (LengthOnDisk + SectorSize - 1)/
+ SectorSize );
+
+ _FnodeData->_fni.cbRunEA = LengthOnDisk;
+ _FnodeModified = TRUE;
+ return VERIFY_STRUCTURE_OK;
+ }
+
+ RunLength -= 1;
+ }
+
+ LengthToBump -= SectorSize;
+ }
+
+
+ if( LengthToBump < RemainingInBuffer1 ) {
+
+ CurrentEa += LengthToBump;
+ RemainingInBuffer1 -= LengthToBump;
+
+ } else {
+
+ Buffer1.Relocate( Buffer2.QueryStartLbn() );
+ Buffer2.Relocate( NextLbn++ );
+
+ memmove( Buffer1.GetBuf(), Buffer2.GetBuf(), (UINT)SectorSize );
+
+ if( RunLength > 0 ) {
+
+ if( !Buffer2.Read() ) {
+
+ // Oh No! an unreadable sector!
+
+ if( Message != NULL &&
+ CurrentPath != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_TRUNCATED_EAS );
+ Message->Display( "%s", CurrentPath->GetString() );
+ }
+
+ DeferredActions->
+ StatEaData( (LengthOnDisk + SectorSize - 1)/
+ SectorSize );
+
+ _FnodeData->_fni.cbRunEA = LengthOnDisk;
+ _FnodeModified = TRUE;
+ return VERIFY_STRUCTURE_OK;
+ }
+
+ RunLength -= 1;
+ }
+
+ Overlap = LengthToBump - RemainingInBuffer1;
+ CurrentEa = (PBYTE)Buffer1.GetBuf() + Overlap;
+ RemainingInBuffer1 = SectorSize - Overlap;
+ }
+ }
+
+ if( _FnodeData->_fni.cbRunEA != LengthOnDisk ) {
+
+ *ErrorsDetected = TRUE;
+
+ _FnodeData->_fni.cbRunEA = LengthOnDisk;
+ _FnodeModified = TRUE;
+ }
+
+ DeferredActions-> StatEaData( (LengthOnDisk + SectorSize - 1)/SectorSize );
+
+ return VERIFY_STRUCTURE_OK;
+}
+
+
+VERIFY_RETURN_CODE
+HPFS_EA_LIST::VerifyInTree(
+ IN OUT PHPFS_SA SuperArea,
+ IN OUT PDEFERRED_ACTIONS_LIST DeferredActions,
+ IN PHPFS_PATH CurrentPath,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN ErrorsDetected,
+ IN BOOLEAN UpdateAllowed,
+ IN OUT PHPFS_ORPHANS OrphansList
+ )
+{
+ HOTFIX_SECRUN Buffer1, Buffer2;
+ HPFS_EA ChildEa;
+ ALSEC ChildAlsec;
+ CONT_MEM Mem;
+ HMEM BufferMem;
+ ULONG SectorSize;
+ ULONG LengthOnDisk, RemainingSpace, RemainingInBuffer1, Overlap;
+ ULONG LengthToBump, LengthOfEa, AllocatedSize,
+ RemainingSectors, RunLength;
+ LBN NextFileLbn, NextPhysLbn, NewLbn;
+ PBYTE CurrentEa;
+ VERIFY_RETURN_CODE erc;
+
+
+ SectorSize = _Drive->QuerySectorSize();
+
+ // If the allocation sector is hotfixed, resolve the reference.
+
+ NewLbn = SuperArea->GetHotfixList()->
+ GetLbnTranslation( _FnodeData->_fni.lbnEA );
+
+ if( _FnodeData->_fni.lbnEA != NewLbn ) {
+
+ _FnodeData->_fni.lbnEA = NewLbn;
+ SuperArea->GetHotfixList()->
+ ClearHotfix( _FnodeData->_fni.lbnEA, SuperArea );
+
+ _FnodeModified = TRUE;
+ }
+
+ // Verify the allocation tree, and make sure that the EA list
+ // fits in it.
+
+ if( !ChildAlsec.Initialize( _Drive, _FnodeData->_fni.lbnEA ) ) {
+
+ return VERIFY_INSUFFICIENT_RESOURCES;
+ }
+
+ RemainingSectors = 0;
+
+ erc = ChildAlsec.VerifyAndFix( SuperArea,
+ DeferredActions,
+ NULL,
+ _FnodeLbn,
+ &RemainingSectors,
+ Message,
+ ErrorsDetected,
+ UpdateAllowed,
+ OrphansList,
+ TRUE );
+
+
+ if( erc != VERIFY_STRUCTURE_OK ) {
+
+ // Look in the orphan list (if we have one);
+ // if we can't find the child there, either,
+ // the EA list is totally corrupt--yank it.
+ // Note that we call LookupAlsec with ParentIsFnode
+ // set to FALSE, since we know we're an auxillary
+ // storage structure (and hence not an FNode).
+
+ RemainingSectors = 0;
+
+ if( OrphansList == NULL ||
+ !OrphansList->LookupAlsec( _FnodeData->_fni.lbnEA,
+ _FnodeLbn,
+ &RemainingSectors,
+ UpdateAllowed,
+ FALSE ) ) {
+
+ if( Message != NULL && CurrentPath != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_TRUNCATED_EAS );
+ Message->Display( "%s", CurrentPath->GetString() );
+ }
+
+ _FnodeData->_fni.cbRunEA = 0;
+ _FnodeData->_fni.lbnEA = 0;
+ _FnodeModified = TRUE;
+
+ return VERIFY_STRUCTURE_OK;
+ }
+ }
+
+ // Check that the EA list fits in the space
+ // claimed by the child allocation tree. If it
+ // doesn't, truncate the list.
+
+ AllocatedSize = SectorSize * RemainingSectors;
+
+ if( _FnodeData->_fni.cbRunEA > AllocatedSize ) {
+
+ *ErrorsDetected = TRUE;
+
+ if( CurrentPath != NULL ) {
+
+ DebugPrintf( "Truncating EA list for %s.\n", CurrentPath->GetString() );
+ }
+
+ _FnodeData->_fni.cbRunEA = AllocatedSize;
+ _FnodeModified = TRUE;
+ }
+
+
+ // Set up to verify the list--initialize the two Secruns
+ // with contiguous memory, and set them to hold the first
+ // two sectors of the list. Note that we use BufferMem
+ // (an HMEM) to allocate a suitably-aligned chunk of memory,
+ // and Mem (a CONT_MEM) to dole it out to the two Secruns.
+
+ if( !BufferMem.Initialize() ||
+ !BufferMem.Acquire( 2 * SectorSize,
+ _Drive->QueryAlignmentMask() ) ) {
+
+ return VERIFY_INSUFFICIENT_RESOURCES;
+ }
+
+ if( !Mem.Initialize( BufferMem.GetBuf(), 2 * SectorSize ) ||
+ !Buffer1.Initialize( &Mem,
+ _Drive,
+ SuperArea->GetHotfixList(),
+ 0,
+ 1 ) ||
+ !Buffer2.Initialize( &Mem,
+ _Drive,
+ SuperArea->GetHotfixList(),
+ 0,
+ 1 ) ) {
+
+ return VERIFY_INSUFFICIENT_RESOURCES;
+ }
+
+ NextFileLbn = 0;
+ NextPhysLbn = ChildAlsec.QueryPhysicalLbn( NextFileLbn++, &RunLength );
+
+ Buffer1.Relocate( NextPhysLbn );
+
+ if( NextPhysLbn == 0 ||
+ !Buffer1.Read() ) {
+
+ // The EA list is unreadable, so away it goes
+
+ if( Message != NULL &&
+ CurrentPath != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_TRUNCATED_EAS );
+ Message->Display( "%s", CurrentPath->GetString() );
+ }
+
+ _FnodeData->_fni.cbRunEA = 0;
+ _FnodeData->_fni.lbnEA = 0;
+ _FnodeModified = TRUE;
+
+ return VERIFY_STRUCTURE_OK;
+ }
+
+ RemainingSectors -= 1;
+
+ if( RemainingSectors > 0 ) {
+
+ NextPhysLbn = ChildAlsec.QueryPhysicalLbn( NextFileLbn++,
+ &RunLength );
+ Buffer2.Relocate( NextPhysLbn );
+
+ if( NextPhysLbn == 0 ||
+ !Buffer2.Read() ) {
+
+ // The EA list is unreadable, so away it goes
+
+ if( Message != NULL &&
+ CurrentPath != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_TRUNCATED_EAS );
+ Message->Display( "%s", CurrentPath->GetString() );
+ }
+
+ _FnodeData->_fni.cbRunEA = 0;
+ _FnodeData->_fni.lbnEA = 0;
+ _FnodeModified = TRUE;
+
+ return VERIFY_STRUCTURE_OK;
+ }
+
+ RemainingSectors -= 1;
+ }
+
+
+ // Initialize the LengthOnDisk accumulator and the counters of
+ // remaining space in the list and in the current buffer.
+
+ LengthOnDisk = 0;
+ RemainingSpace = _FnodeData->_fni.cbRunEA;
+ RemainingInBuffer1 = SectorSize;
+
+ CurrentEa = (PBYTE)(Buffer1.GetBuf());
+
+ while( RemainingSpace > 0 ) {
+
+ ChildEa.Initialize( _Drive, (PEA_DATA)CurrentEa, _FnodeLbn );
+
+ erc = VERIFY_STRUCTURE_INVALID;
+
+ if( RemainingSpace < sizeof(EA_DATA) ||
+ ChildEa.QueryLength() > RemainingSpace ||
+ (erc = ChildEa.VerifyAndFix( SuperArea,
+ DeferredActions,
+ Message,
+ ErrorsDetected,
+ UpdateAllowed,
+ OrphansList )) !=
+ VERIFY_STRUCTURE_OK ) {
+
+ if( erc == VERIFY_STRUCTURE_INVALID ) {
+
+ // The EA list is corrupt, so we'll truncate
+ // it right here.
+
+ if( Message != NULL &&
+ CurrentPath != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_TRUNCATED_EAS );
+ Message->Display( "%s", CurrentPath->GetString() );
+ }
+
+ _FnodeData->_fni.cbRunEA = LengthOnDisk;
+ _FnodeModified = TRUE;
+ return VERIFY_STRUCTURE_OK;
+
+ } else {
+
+ // We ran into a resource problem--bail out.
+
+ return erc;
+ }
+ }
+
+ // Move on to the next EA
+
+ _SizeOfEas += ChildEa.QuerySize();
+
+ LengthOfEa = ChildEa.QueryLength();
+ LengthToBump = LengthOfEa;
+
+ RemainingSpace -= LengthOfEa;
+ LengthOnDisk += LengthOfEa;
+
+ if ( ChildEa.IsNeedEa() ) {
+
+ _NumberOfNeedEas +=1;
+ }
+
+ _NumberOfEas += 1;
+
+
+ // Before we move on, write the current sectors if the
+ // EA changed.
+
+ if( UpdateAllowed && ChildEa.IsModified() ) {
+
+ Buffer1.Write();
+
+ if( LengthToBump >= RemainingInBuffer1 ) {
+
+ Buffer2.Write();
+ }
+ }
+
+
+ while( LengthToBump >= SectorSize ) {
+
+ NextPhysLbn = ChildAlsec.QueryPhysicalLbn( NextFileLbn++,
+ &RunLength );
+
+ Buffer1.Relocate( Buffer2.QueryStartLbn() );
+ Buffer2.Relocate( NextPhysLbn );
+
+ memmove( Buffer1.GetBuf(), Buffer2.GetBuf(), (UINT)SectorSize );
+
+ if( RemainingSectors > 0 ) {
+
+ if( NextPhysLbn == 0 ||
+ !Buffer2.Read() ) {
+
+ // Oh No! an unreadable sector!
+
+ if( Message != NULL &&
+ CurrentPath != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_TRUNCATED_EAS );
+ Message->Display( "%s", CurrentPath->GetString() );
+ }
+
+ _FnodeData->_fni.cbRunEA = LengthOnDisk;
+ _FnodeModified = TRUE;
+ return VERIFY_STRUCTURE_OK;
+ }
+
+ RemainingSectors -= 1;
+ }
+
+ LengthToBump -= SectorSize;
+ }
+
+
+ if( LengthToBump < RemainingInBuffer1 ) {
+
+ CurrentEa += LengthToBump;
+ RemainingInBuffer1 -= LengthToBump;
+
+ } else {
+
+ NextPhysLbn = ChildAlsec.QueryPhysicalLbn( NextFileLbn++,
+ &RunLength );
+
+ Buffer1.Relocate( Buffer2.QueryStartLbn() );
+ Buffer2.Relocate( NextPhysLbn );
+
+ memmove( Buffer1.GetBuf(), Buffer2.GetBuf(), (UINT)SectorSize );
+
+ if( RemainingSectors > 0 ) {
+
+ if( NextPhysLbn == 0 ||
+ !Buffer2.Read() ) {
+
+ // Oh No! an unreadable sector!
+
+ if( Message != NULL &&
+ CurrentPath != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_TRUNCATED_EAS );
+ Message->Display( "%s", CurrentPath->GetString() );
+ }
+
+ _FnodeData->_fni.cbRunEA = LengthOnDisk;
+ _FnodeModified = TRUE;
+ return VERIFY_STRUCTURE_OK;
+ }
+
+ RemainingSectors -= 1;
+ }
+
+ Overlap = LengthToBump - RemainingInBuffer1;
+ CurrentEa = (PBYTE)Buffer1.GetBuf() + Overlap;
+ RemainingInBuffer1 = SectorSize - Overlap;
+ }
+ }
+
+ if( _FnodeData->_fni.cbRunEA != LengthOnDisk ) {
+
+ *ErrorsDetected = TRUE;
+
+ _FnodeData->_fni.cbRunEA = LengthOnDisk;
+ _FnodeModified = TRUE;
+ }
+
+ return VERIFY_STRUCTURE_OK;
+}
+
+
+BOOLEAN
+HPFS_EA_LIST::FindAndResolveHotfix(
+ PHPFS_SA SuperArea
+ )
+/*++
+
+Routine Description:
+
+ Resolves all hotfix references in the EA list.
+
+Arguments:
+
+ SuperArea: volume superarea
+
+Return Value:
+
+ TRUE if all hotfixes in the list are successfully resolved.
+
+Notes:
+
+ Assumes that the list is valid (i.e. that it satisfies
+ VerifyAndFix).
+
+--*/
+{
+ HPFS_EA ChildEa;
+ LBN StartLbn, NewLbn;
+ ULONG LengthTraversed, LengthOfEa, SectorsInList, SectorSize;
+ PBYTE CurrentEa;
+ PHOTFIXLIST HotfixList;
+
+ // First, check to see if the Fnode has any EAs--if not,
+ // we can bail out early.
+
+ if( _FnodeData->_fni.usFNLEA == 0 &&
+ (_FnodeData->_fni.lbnEA == 0 || _FnodeData->_fni.cbRunEA == 0) ) {
+
+ return TRUE;
+ }
+
+
+ if( _FnodeData->_fni.lbnEA == 0 ) {
+
+ // The EAs are in the FNode. We just have to crawl
+ // the list, resolving any hotfixes in each EA.
+
+ LengthTraversed = 0;
+
+ CurrentEa = _FnodeData->abFree + _FnodeData->_fni.usFNLACL;
+
+ while( LengthTraversed < _FnodeData->_fni.usFNLEA ) {
+
+ ChildEa.Initialize( _Drive, (PEA_DATA)CurrentEa, _FnodeLbn );
+
+ if( !ChildEa.FindAndResolveHotfix( SuperArea ) ) {
+
+ // Unable to resolve hotfixes in this child--
+ // give up.
+
+ return FALSE;
+ }
+
+ // See if we changed the FNode.
+
+ if( ChildEa.IsModified() ) {
+
+ _FnodeModified = TRUE;
+ }
+
+ // Move on to the next EA
+
+ LengthOfEa = ChildEa.QueryLength();
+ CurrentEa += LengthOfEa;
+ LengthTraversed += LengthOfEa;
+ }
+
+ return TRUE;
+
+ } else {
+
+ // The EA list is outside the FNode.
+
+ if( _FnodeData->_fni.bDatEA != 0 ) {
+
+ // EAs are in an allocation tree. Crawl through that
+ // tree, resolving any hotfixes we find.
+
+ return ( FindAndResolveHotfixInTree( SuperArea ) );
+
+ } else {
+
+ // EAs are in a single run on disk. First, resolve any
+ // hotfixes in that run itself. Then crawl through it,
+ // resolving any hotfixes in the EAs.
+
+ StartLbn = _FnodeData->_fni.lbnEA;
+
+ SectorSize = _Drive->QuerySectorSize();
+ SectorsInList = (_FnodeData->_fni.cbRunEA - 1 + SectorSize) /
+ SectorSize;
+
+ HotfixList = SuperArea->GetHotfixList();
+
+ while( HotfixList->IsInList( StartLbn, SectorsInList ) ) {
+
+ // Copy the run to a new location--if we can't copy
+ // it, then we can't resolve hotfixes in the EA list.
+ // If we can relocate the run, we need to update the
+ // FNode to point at the new location.
+
+ if( !SuperArea->CopyRun( StartLbn,
+ SectorsInList,
+ &NewLbn ) ) {
+
+ return FALSE;
+ }
+
+ _FnodeData->_fni.lbnEA = NewLbn;
+ _FnodeModified = TRUE;
+
+ // Now that we've relocated the run, we free up its
+ // old sectors and clear the hotfix references. (Note
+ // the ClearRun will mark the bad sectors as used and
+ // add them to the badblock list.
+
+ SuperArea->GetBitmap()->SetFree( StartLbn, SectorsInList );
+
+ HotfixList->ClearRun( StartLbn, SectorsInList, SuperArea );
+ }
+
+ return( FindAndResolveHotfixOnDiskRun( SuperArea ) );
+ }
+ }
+}
+
+
+BOOLEAN
+HPFS_EA_LIST::FindAndResolveHotfixOnDiskRun(
+ IN OUT PHPFS_SA SuperArea
+ )
+/*++
+
+Routine Description:
+
+ Find and resolve all hotfixes in an EA List that exists in a
+ single run outside the FNode.
+
+Arguments:
+
+ SuperArea -- SuperArea of the volume being checked
+
+
+Return Value:
+
+ TRUE if successful
+
+Notes:
+
+ This private method is only called if we determine that the
+ EAs are outside the FNode, in a single run on disk. It assumes
+ that the list is valid (i.e. that it meets the requirements
+ enforced by VerifyAndFix).
+
+ This method is only called if we have permission to modify
+ the volume.
+
+--*/
+{
+ HOTFIX_SECRUN Buffer1, Buffer2;
+ HPFS_EA ChildEa;
+ CONT_MEM Mem;
+ HMEM BufferMem;
+ ULONG SectorSize;
+ ULONG RemainingSpace, RemainingInBuffer1, Overlap;
+ ULONG LengthToBump, RunLength, LengthOfEa;
+ LBN NextLbn;
+ PBYTE CurrentEa;
+
+
+ // Set up to crawl the list--initialize the two Secruns
+ // with contiguous memory, and set them to hold the first
+ // two sectors of the list.Note that we use BufferMem
+ // (an HMEM) to allocate a suitably-aligned chunk of memory,
+ // and Mem (a CONT_MEM) to dole it out to the two Secruns.
+
+
+ SectorSize = _Drive->QuerySectorSize();
+
+ NextLbn = _FnodeData->_fni.lbnEA;
+ RunLength = (_FnodeData->_fni.cbRunEA + SectorSize - 1)/SectorSize;
+
+ if( !BufferMem.Initialize() ||
+ !BufferMem.Acquire( 2 * SectorSize,
+ _Drive->QueryAlignmentMask() ) ) {
+
+ return FALSE;
+ }
+
+ if( !Mem.Initialize( BufferMem.GetBuf(), 2 * SectorSize ) ||
+ !Buffer1.Initialize( &Mem,
+ _Drive,
+ SuperArea->GetHotfixList(),
+ 0,
+ 1 ) ||
+ !Buffer2.Initialize( &Mem,
+ _Drive,
+ SuperArea->GetHotfixList(),
+ 0,
+ 1 ) ) {
+
+ return FALSE;
+ }
+
+ Buffer1.Relocate( NextLbn++ );
+ Buffer2.Relocate( NextLbn++ );
+
+ if( !Buffer1.Read() ||
+ ( RunLength > 1 && !Buffer2.Read() ) ) {
+
+ return FALSE;
+ }
+
+
+ // OK, we've read two sectors of the run.
+
+ RunLength = (RunLength > 1) ? RunLength - 2 : 0;
+
+
+ // Initialize the remaining space accumulators.
+
+ RemainingSpace = _FnodeData->_fni.cbRunEA;
+ RemainingInBuffer1 = SectorSize;
+
+ CurrentEa = (PBYTE)(Buffer1.GetBuf());
+
+ while( RemainingSpace > 0 ) {
+
+ if( !ChildEa.Initialize( _Drive,
+ (PEA_DATA)CurrentEa,
+ _FnodeLbn ) ||
+ !ChildEa.FindAndResolveHotfix( SuperArea ) ) {
+
+ return FALSE;
+ }
+
+
+ // Move on to the next EA
+
+ LengthOfEa = ChildEa.QueryLength();
+
+ LengthToBump = LengthOfEa;
+ RemainingSpace -= LengthOfEa;
+
+
+ // Before we move on, write the current sectors if the
+ // EA changed.
+
+ if( ChildEa.IsModified() ) {
+
+ Buffer1.Write();
+
+ if( LengthToBump >= RemainingInBuffer1 ) {
+
+ Buffer2.Write();
+ }
+ }
+
+
+ while( LengthToBump >= SectorSize ) {
+
+ Buffer1.Relocate( Buffer2.QueryStartLbn() );
+ Buffer2.Relocate( NextLbn++ );
+
+ memmove( Buffer1.GetBuf(), Buffer2.GetBuf(), (UINT)SectorSize );
+
+ if( RunLength > 0 ) {
+
+ if( !Buffer2.Read() ) {
+
+ return FALSE;
+ }
+
+ RunLength -= 1;
+ }
+
+ LengthToBump -= SectorSize;
+ }
+
+
+ if( LengthToBump < RemainingInBuffer1 ) {
+
+ CurrentEa += LengthToBump;
+ RemainingInBuffer1 -= LengthToBump;
+
+ } else {
+
+ Buffer1.Relocate( Buffer2.QueryStartLbn() );
+ Buffer2.Relocate( NextLbn++ );
+
+ memmove( Buffer1.GetBuf(), Buffer2.GetBuf(), (UINT)SectorSize );
+
+ if( RunLength > 0 ) {
+
+ if( !Buffer2.Read() ) {
+
+ return FALSE;
+ }
+
+ RunLength -= 1;
+ }
+
+ Overlap = LengthToBump - RemainingInBuffer1;
+ CurrentEa = (PBYTE)Buffer1.GetBuf() + Overlap;
+ RemainingInBuffer1 = SectorSize - Overlap;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+HPFS_EA_LIST::FindAndResolveHotfixInTree(
+ IN OUT PHPFS_SA SuperArea
+ )
+{
+ HOTFIX_SECRUN Buffer1, Buffer2;
+ HPFS_EA ChildEa;
+ ALSEC ChildAlsec;
+ CONT_MEM Mem;
+ HMEM BufferMem;
+ ULONG SectorSize;
+ ULONG LengthOnDisk, RemainingSpace, RemainingInBuffer1, Overlap;
+ ULONG LengthToBump, LengthOfEa, RemainingSectors, RunLength;
+ LBN NextFileLbn, NextPhysLbn;
+ PBYTE CurrentEa;
+
+
+ SectorSize = _Drive->QuerySectorSize();
+
+
+ // Initialize the child allocation sector and the count of remaining
+ // sectors.
+
+ if( !ChildAlsec.Initialize( _Drive, _FnodeData->_fni.lbnEA ) ) {
+
+ return FALSE;
+ }
+
+ RemainingSectors = (_FnodeData->_fni.cbRunEA - 1 + SectorSize) /
+ SectorSize;
+
+
+ // Set up to crawl the list--initialize the two Secruns
+ // with contiguous memory, and set them to hold the first
+ // two sectors of the list. Note that we use BufferMem (an
+ // HMEM) to allocate a suitably-aligned chunk of memory, and
+ // Mem (a CONT_MEM) to dole it out to the two Secruns.
+
+ if( !BufferMem.Initialize() ||
+ !BufferMem.Acquire( 2 * SectorSize,
+ _Drive->QueryAlignmentMask() ) ) {
+
+ return FALSE;
+ }
+
+ if( !Mem.Initialize( BufferMem.GetBuf(), 2 * SectorSize ) ||
+ !Buffer1.Initialize( &Mem,
+ _Drive,
+ SuperArea->GetHotfixList(),
+ 0,
+ 1 ) ||
+ !Buffer2.Initialize( &Mem,
+ _Drive,
+ SuperArea->GetHotfixList(),
+ 0,
+ 1 ) ) {
+
+ return FALSE;
+ }
+
+ NextFileLbn = 0;
+ NextPhysLbn = ChildAlsec.QueryPhysicalLbn( NextFileLbn++, &RunLength );
+
+ Buffer1.Relocate( NextPhysLbn );
+
+ if( NextPhysLbn == 0 ||
+ !Buffer1.Read() ) {
+
+ return FALSE;
+ }
+
+ RemainingSectors -= 1;
+
+ if( RemainingSectors > 0 ) {
+
+ NextPhysLbn = ChildAlsec.QueryPhysicalLbn( NextFileLbn++,
+ &RunLength );
+ Buffer2.Relocate( NextPhysLbn );
+
+ if( NextPhysLbn == 0 ||
+ !Buffer2.Read() ) {
+
+ return FALSE;
+ }
+
+ RemainingSectors -= 1;
+ }
+
+
+ // Initialize the LengthOnDisk accumulator and the counters of
+ // remaining space in the list and in the current buffer.
+
+ LengthOnDisk = 0;
+ RemainingSpace = _FnodeData->_fni.cbRunEA;
+ RemainingInBuffer1 = SectorSize;
+
+ CurrentEa = (PBYTE)(Buffer1.GetBuf());
+
+ while( RemainingSpace > 0 ) {
+
+ if( !ChildEa.Initialize( _Drive,
+ (PEA_DATA)CurrentEa,
+ _FnodeLbn ) ||
+ !ChildEa.FindAndResolveHotfix( SuperArea ) ) {
+
+ return FALSE;
+ }
+
+
+ // Move on to the next EA
+
+ LengthOfEa = ChildEa.QueryLength();
+ LengthToBump = LengthOfEa;
+ RemainingSpace -= LengthOfEa;
+
+ // Before we move on, write the current sectors if the
+ // EA changed.
+
+ if( ChildEa.IsModified() ) {
+
+ Buffer1.Write();
+
+ if( LengthToBump >= RemainingInBuffer1 ) {
+
+ Buffer2.Write();
+ }
+ }
+
+
+ while( LengthToBump >= SectorSize ) {
+
+ NextPhysLbn = ChildAlsec.QueryPhysicalLbn( NextFileLbn++,
+ &RunLength );
+
+ Buffer1.Relocate( Buffer2.QueryStartLbn() );
+ Buffer2.Relocate( NextPhysLbn );
+
+ memmove( Buffer1.GetBuf(), Buffer2.GetBuf(), (UINT)SectorSize );
+
+ if( RemainingSectors > 0 ) {
+
+ if( NextPhysLbn == 0 ||
+ !Buffer2.Read() ) {
+
+ return FALSE;
+ }
+
+ RemainingSectors -= 1;
+ }
+
+ LengthToBump -= SectorSize;
+ }
+
+
+ if( LengthToBump < RemainingInBuffer1 ) {
+
+ CurrentEa += LengthToBump;
+ RemainingInBuffer1 -= LengthToBump;
+
+ } else {
+
+ NextPhysLbn = ChildAlsec.QueryPhysicalLbn( NextFileLbn++,
+ &RunLength );
+
+ Buffer1.Relocate( Buffer2.QueryStartLbn() );
+ Buffer2.Relocate( NextPhysLbn );
+
+ memmove( Buffer1.GetBuf(), Buffer2.GetBuf(), (UINT)SectorSize );
+
+ if( RemainingSectors > 0 ) {
+
+ if( NextPhysLbn == 0 ||
+ !Buffer2.Read() ) {
+
+ return FALSE;
+ }
+
+ RemainingSectors -= 1;
+ }
+
+ Overlap = LengthToBump - RemainingInBuffer1;
+ CurrentEa = (PBYTE)Buffer1.GetBuf() + Overlap;
+ RemainingInBuffer1 = SectorSize - Overlap;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+HPFS_EA_LIST::QueryPackedEaList(
+ OUT PVOID OutputBuffer,
+ IN ULONG BufferLength,
+ OUT PULONG PackedLength,
+ OUT PBOOLEAN IsCorrupt,
+ IN PHOTFIXLIST HotfixList
+ )
+/*++
+
+Routine Description:
+
+ This method fetches the list of Extended Attributes in packed
+ (HPFS) format.
+
+Arguments:
+
+ OutputBuffer -- Receives the list of Extended Attributes
+ BufferLength -- Supplies the length of OutputBuffer
+ PackedLength -- Supplies the length of data put into the buffer
+ UnpackedLength -- Receives the unpacked (NT format) length of
+ this Extended Attributes list
+ IsCorrupt -- Receives TRUE if the list is found to be corrupt.
+ HotfixList -- Supplies the hotfix list for the volume. This
+ parameter may be NULL, in which case hotfixes
+ are ignored.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ HPFS_EA ChildEa;
+ PVOID InternalBuffer;
+ ULONG LengthTraversed, LengthOfEa, LengthOfInternalList;
+ PBYTE CurrentEa;
+
+ // First, check to see if the Fnode has any EAs--if not,
+ // we can bail out early.
+
+ if( _FnodeData->_fni.usFNLEA == 0 &&
+ (_FnodeData->_fni.lbnEA == 0 || _FnodeData->_fni.cbRunEA == 0) ) {
+
+ *PackedLength = 0;
+ return TRUE;
+ }
+
+
+ LengthOfInternalList = ( _FnodeData->_fni.usFNLEA != 0 ) ?
+ _FnodeData->_fni.usFNLEA :
+ _FnodeData->_fni.cbRunEA;
+
+ DebugPrintf( "UHPFS: Query EA List: 0x%x bytes\n", LengthOfInternalList );
+
+ // Allocate a temporary buffer to hold the list.
+
+ if( (InternalBuffer = MALLOC( LengthOfInternalList )) == NULL ) {
+
+ DebugPrintf( "UHPFS: Can't allocate 0x%x bytes for EA List\n", LengthOfInternalList );
+ return FALSE;
+ }
+
+
+ // Read the list into the temporary buffer so we don't have to write
+ // three versions of the list-crawling code.
+
+ if( !ReadList( InternalBuffer,
+ LengthOfInternalList,
+ HotfixList,
+ IsCorrupt ) ) {
+
+ // Couldn't read the list. ReadList will have set *IsCorrupt
+ // if appropriate.
+
+ FREE( InternalBuffer );
+ return FALSE;
+ }
+
+
+ // Now crawl through the list, copying each Extended Attribute.
+
+ LengthTraversed = 0;
+ *PackedLength = 0;
+ CurrentEa = (PBYTE)InternalBuffer;
+
+ while( LengthTraversed < LengthOfInternalList ) {
+
+ ChildEa.Initialize( _Drive, (PEA_DATA)CurrentEa, _FnodeLbn );
+
+ if( !ChildEa.QueryPackedEa( OutputBuffer,
+ BufferLength,
+ PackedLength,
+ IsCorrupt,
+ HotfixList ) ) {
+
+ FREE( InternalBuffer );
+ return FALSE;
+ }
+
+ // Move on to the next EA. The EA's length is it's length
+ // in the stream (excluding any out of stream portion).
+ //
+ LengthOfEa = ChildEa.QueryLength();
+ CurrentEa += LengthOfEa;
+ LengthTraversed += LengthOfEa;
+
+ // Note that QueryPackedEa will update *PackedLength.
+ }
+
+
+ FREE( InternalBuffer );
+ return TRUE;
+}
+
+
+BOOLEAN
+HPFS_EA_LIST::ReadList(
+ IN OUT PVOID TargetBuffer,
+ IN ULONG TargetBufferLength,
+ IN PHOTFIXLIST HotfixList,
+ IN OUT PBOOLEAN IsCorrupt
+ )
+/*++
+
+Routine Description:
+
+ This method reads the Extended Attributes list into memory. Note
+ that only the in-stream attributes are read; thus, this list may
+ contain EA Indirect records.
+
+Arguments:
+
+ TargetBuffer -- Receives the list.
+ TargetBufferLength -- Supplies the length of the client's buffer.
+ HotfixList -- Supplies the hotfix list for the volume.
+ May be NULL, in which case hotfixes are ignored.
+ IsCorrupt -- Receives TRUE if this method fails because the
+ structures describing the list are corrupt.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ ALSEC ChildAlsec;
+ HMEM TempBuffer;
+ HOTFIX_SECRUN TempSecrun;
+ ULONG SectorsInList, SectorSize, BytesRead;
+
+ // First, check to see if the Fnode has any EAs--if not,
+ // we can bail out early.
+
+ if( _FnodeData->_fni.usFNLEA == 0 &&
+ (_FnodeData->_fni.lbnEA == 0 || _FnodeData->_fni.cbRunEA == 0) ) {
+
+ return TRUE;
+ }
+
+
+ if( _FnodeData->_fni.lbnEA == 0 ) {
+
+ // The EAs are in the FNode. Make sure it doesn't overflow
+ // the FNode, and then copy it to the client's buffer.
+
+ if( sizeof(_FnodeData->abFree) <
+ _FnodeData->_fni.usFNLACL + _FnodeData->_fni.usFNLEA ) {
+
+ // The claimed size of the EA list is bigger than the
+ // available space.
+ //
+ DebugPrintf( "UHPFS: EA's in FNode 0x%x are corrupt.\n", _FnodeLbn );
+ *IsCorrupt = TRUE;
+ return FALSE;
+ }
+
+ if( _FnodeData->_fni.usFNLEA <= TargetBufferLength ) {
+
+ memcpy( TargetBuffer,
+ _FnodeData->abFree + _FnodeData->_fni.usFNLACL,
+ _FnodeData->_fni.usFNLEA );
+
+ return TRUE;
+
+ } else {
+
+ // The list won't fit into the supplied buffer.
+
+ DebugPrint( "UHPFS: Client's buffer is too small for EA List." );
+ return FALSE;
+ }
+
+
+ } else {
+
+ // The EA list is outside the FNode.
+
+ if( TargetBufferLength < _FnodeData->_fni.cbRunEA ) {
+
+ // The list will not fit in the supplied buffer.
+ //
+ DebugPrint( "UHPFS: Client's buffer is too small for EA List." );
+ return FALSE;
+ }
+
+ SectorSize = _Drive->QuerySectorSize();
+ SectorsInList = (_FnodeData->_fni.cbRunEA % SectorSize) ?
+ (_FnodeData->_fni.cbRunEA / SectorSize + 1) :
+ (_FnodeData->_fni.cbRunEA / SectorSize);
+
+
+ if( _FnodeData->_fni.bDatEA != 0 ) {
+
+ // The EA list is in an allocation tree.
+
+ if( !ChildAlsec.Initialize( _Drive,
+ _FnodeData->_fni.lbnEA ) ||
+ !ChildAlsec.Read() ||
+ !ChildAlsec.IsAlsec() ||
+ !ChildAlsec.ReadData( 0,
+ TargetBuffer,
+ _FnodeData->_fni.cbRunEA,
+ &BytesRead,
+ HotfixList ) ||
+ BytesRead != _FnodeData->_fni.cbRunEA ) {
+
+ DebugPrint( "UHPFS: Can't read EA's from allocation tree." );
+ return FALSE;
+ }
+
+ return TRUE;
+
+ } else {
+
+ // The EA list is in a single on-disk run.
+
+ if( !TempBuffer.Initialize() ||
+ !TempSecrun.Initialize( &TempBuffer,
+ _Drive,
+ HotfixList,
+ _FnodeData->_fni.lbnEA,
+ SectorsInList ) ) {
+
+ DebugPrint( "UHPFS: Insufficient memory to read EA's." );
+ return FALSE;
+ }
+
+ if( !TempSecrun.Read() ) {
+
+ // The on-disk run is unreadable.
+ //
+ DebugPrintf( "UHPFS: EA's in FNode 0x%x are corrupt.\n", _FnodeLbn );
+ *IsCorrupt = TRUE;
+ return FALSE;
+ }
+
+ memcpy( TargetBuffer,
+ TempSecrun.GetBuf(),
+ _FnodeData->_fni.cbRunEA );
+
+ return TRUE;
+ }
+ }
+}
+
+
+ULONG
+HPFS_EA_LIST::QueryNumberOfEas(
+ )
+{
+ return _NumberOfEas;
+}
+
+
+ULONG
+HPFS_EA_LIST::QueryNumberOfNeedEas(
+ )
+{
+ return _NumberOfNeedEas;
+}
+
+
+ULONG
+HPFS_EA_LIST::QuerySizeOfEas(
+ )
+{
+ return _SizeOfEas;
+}
+
+
+
+BOOLEAN
+HPFS_EA_LIST::QueryFnodeModified(
+ )
+{
+ return _FnodeModified;
+}
diff --git a/private/utils/uhpfs/src/hpfsname.cxx b/private/utils/uhpfs/src/hpfsname.cxx
new file mode 100644
index 000000000..beb0507cb
--- /dev/null
+++ b/private/utils/uhpfs/src/hpfsname.cxx
@@ -0,0 +1,1221 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "cpinfo.hxx"
+#include "error.hxx"
+#include "hpfsname.hxx"
+
+
+// This string is the set of all characters that are NOT allowed in an
+// HPFS OS/2 1.2 filename.
+
+//
+// jaimes 08/19/91
+// Mips compiler thinks that the string below is not terminated
+// For this reason the string is defined in only one line.
+//
+//
+// const char * InvalidChars =
+// "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+// "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+// "\"/\\:<|>";
+//
+
+const char * InvalidChars = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f\"/\\:<|>";
+
+
+// This string is the set of characters added to the valid set
+// of characters for file names by OS/2 1.2; any directory entry
+// whose name includes one of these characters must have the
+// NEW NAMES bit set in its flag.
+
+const char * NewChars = ",[]+=;";
+
+
+
+DEFINE_CONSTRUCTOR( HPFS_NAME, OBJECT );
+
+VOID
+HPFS_NAME::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Constructor for the HPFS_NAME object. Sets private data to
+ reasonable values.
+
+--*/
+{
+ _Buffer = NULL;
+ _BufferSize = 0;
+ _Length = 0;
+}
+
+
+HPFS_NAME::~HPFS_NAME(
+ )
+{
+ Destroy();
+}
+
+
+BOOLEAN
+HPFS_NAME::Initialize(
+ ULONG Length,
+ PUCHAR String,
+ ULONG VolumeCodepageIndex,
+ PCASEMAP Casemap
+ )
+/*++
+
+Routine Description:
+
+ Initializes a name object.
+
+Arguments:
+
+ Length: Number of bytes in the name
+ String: Pointer to raw bytes
+ VolumeCodepageIndex: Index on volume of name's codepage
+ CaseMapTable: Case Map Table for the volume
+
+Returns:
+
+ TRUE if successful; FALSE otherwise.
+
+Notes:
+
+ Unlike most Init routines, this routine does _not_ call Destroy;
+ this allows the object to reuse its buffer if it is large enough.
+ (If the buffer is too small, the object will free it and allocate
+ a new one.)
+
+ The name is saved in upper-cased form.
+
+--*/
+{
+
+ PUCHAR pc = String;
+ ULONG i;
+
+ // Note that the buffer must be big enough for the name plus
+ // a trailing null byte.
+
+ if( _Buffer != NULL && _BufferSize < Length + 1) {
+
+ FREE( _Buffer );
+ _Buffer = NULL;
+ }
+
+ if( _Buffer == NULL ) {
+
+ _BufferSize = Length + 1;
+
+ if( (_Buffer = (PBYTE)MALLOC( (size_t)_BufferSize )) == NULL ) {
+
+ perrstk->push(NEW_ALLOC_FAILED, QueryClassId());
+ _BufferSize = 0;
+ _Length = 0;
+ return FALSE;
+ }
+ }
+
+ _Length = Length;
+
+ if( Casemap->HasDBCS( VolumeCodepageIndex ) ) {
+
+ // This codepage has DBCS characters, so we have
+ // to check for them.
+
+ for( i = 0; i < _Length && *pc; i++, pc++ ) {
+
+ if( Casemap->IsDBCS( VolumeCodepageIndex, *pc ) ) {
+
+ // It's a DBCS lead-byte. Copy the lead byte
+ // and the trailing byte without upcasing.
+
+ _Buffer[i] = *pc;
+
+ i += 1;
+ pc += 1;
+
+ if( i >= _Length || *pc == 0 ) {
+
+ // There's no trailing byte! Break out.
+
+ break;
+ }
+
+ _Buffer[i] = *pc;
+
+ } else {
+
+ // It's not a DBCS lead-byte--upcase it.
+
+ _Buffer[i] = Casemap->UpperCase(*pc, VolumeCodepageIndex);
+ }
+ }
+
+ // Add a trailing null.
+ _Buffer[i] = 0;
+
+ } else {
+
+ // This codepage doesn't have any DBCS characters,
+ // so we can just slam through the string.
+
+ for( i = 0; i < _Length && *pc; i++, pc++ ) {
+
+ _Buffer[i] = Casemap->UpperCase(*pc, VolumeCodepageIndex);
+ }
+
+ // Add a trailing null.
+ _Buffer[i] = 0;
+
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+HPFS_NAME::Initialize(
+ ULONG Length,
+ PUCHAR String
+ )
+/*++
+
+Routine Description:
+
+ Initializes a name object.
+
+Arguments:
+
+ Length: Number of bytes in the name
+ String: Pointer to previously-uppercased string
+
+Returns:
+
+ TRUE if successful; FALSE otherwise.
+
+Notes:
+
+ This method is used to initialize the name with a string that
+ has already been uppercased. Since we don't need to uppercase
+ the string, we don't need the codepage index or case mapping table.
+
+--*/
+{
+
+ // Note that the buffer must be big enough for the name plus
+ // a trailing null byte.
+
+ if( _Buffer != NULL && _BufferSize < Length + 1) {
+
+ FREE( _Buffer );
+ _Buffer = NULL;
+ }
+
+ if( _Buffer == NULL ) {
+
+ _BufferSize = Length + 1;
+
+ if( (_Buffer = (PBYTE)MALLOC( (size_t)_BufferSize )) == NULL ) {
+
+ perrstk->push(NEW_ALLOC_FAILED, QueryClassId());
+ _BufferSize = 0;
+ _Length = 0;
+ return FALSE;
+ }
+ }
+
+ _Length = Length;
+
+ memmove( _Buffer, String, (size_t)_Length );
+
+ _Buffer[_Length] = 0;
+
+ return TRUE;
+}
+
+
+BOOLEAN
+HPFS_NAME::Initialize(
+ HPFS_NAME* OtherName
+ )
+/*++
+
+Routine Description:
+
+ Initializes a name object, copying data from an existing name object
+
+Arguments:
+
+ OtherName -- name to copy
+
+Returns:
+
+ TRUE if successful; FALSE otherwise.
+
+Notes:
+
+ This allows the user to initialize the Name object with an
+ already-uppercased name. Note that OtherName may be NULL.
+
+--*/
+{
+ if( OtherName == NULL ) {
+
+ _Length = 0;
+
+ if( _Buffer != NULL && _BufferSize < 1 ) {
+
+ _BufferSize = 1;
+
+ if( (_Buffer = (PBYTE)MALLOC( (size_t)_BufferSize )) == NULL ) {
+
+ perrstk->push(NEW_ALLOC_FAILED, QueryClassId());
+ _BufferSize = 0;
+ _Length = 0;
+ return FALSE;
+ }
+
+ _Length = 0;
+ _Buffer[0] = '\0';
+ return TRUE;
+ }
+ }
+
+ // OK, we've dealt with the case that OtherName is NULL.
+
+ // Note that the buffer must be big enough for the name plus
+ // a trailing null byte.
+
+ if( _Buffer != NULL && _BufferSize < OtherName->_Length + 1 ) {
+
+ FREE( _Buffer );
+ _Buffer = NULL;
+ }
+
+ if( _Buffer == NULL ) {
+
+ _BufferSize = OtherName->_Length + 1;
+
+ if( (_Buffer = (PBYTE)MALLOC( (size_t)_BufferSize )) == NULL ) {
+
+ perrstk->push(NEW_ALLOC_FAILED, QueryClassId());
+ _BufferSize = 0;
+ _Length = 0;
+ return FALSE;
+ }
+ }
+
+ _Length = OtherName->_Length;
+
+ memmove( _Buffer, OtherName->_Buffer, (size_t)_Length );
+
+ _Buffer[_Length] = 0;
+
+ return TRUE;
+}
+
+
+BOOLEAN
+HPFS_NAME::IsNull(
+ )
+/*++
+
+Routine description:
+
+ Determines whether the name is null
+
+Return Value:
+
+ TRUE if the name is null (i.e. uninitialized).
+
+--*/
+{
+
+ return ( _Length == 0 );
+}
+
+
+BOOLEAN
+HPFS_NAME::Swap(
+ HPFS_NAME* OtherName
+ )
+/*++
+
+Description of Routine:
+
+ Swaps the guts of two HPFS_NAME objects.
+
+Arguments:
+
+ OtherName -- pointer to the HPFS_NAME which will be swapped
+ with the current object.
+
+--*/
+{
+ ULONG temp;
+ PBYTE tp;
+
+ tp = _Buffer;
+ _Buffer = OtherName->_Buffer;
+ OtherName->_Buffer = tp;
+
+ temp = _BufferSize;
+ _BufferSize = OtherName->_BufferSize;
+ OtherName->_BufferSize = temp;
+
+ temp = _Length;
+ _Length = OtherName->_Length;
+ OtherName->_Length = temp;
+
+ return TRUE;
+}
+
+
+BOOLEAN
+HPFS_NAME::IsValid(
+ CASEMAP* Casemap,
+ ULONG CodepageIndex
+ )
+/*++
+
+Description of Routine:
+
+ Checks name for validity.
+
+Returns:
+
+ FALSE if the name is invalid; TRUE otherwise.
+
+Arguments:
+
+ Casemap -- case mapping table for the volume
+ CodepageIndex -- codepage index on volume for which name must be valid
+
+Notes:
+
+ A valid name must meet the following criteria:
+
+ -- it refers to a valid codepage
+
+ -- it does not contain any invalid characters
+ (Note that a DBCS trailing-byte may have any value)
+
+ -- it does not have a trailing '.' or blank
+
+--*/
+{
+ ULONG i;
+ BOOLEAN HasTrailingDot = FALSE;
+
+ if( _Length == 0 || _Buffer == NULL ) {
+
+ return FALSE;
+ }
+
+ // Special case -- the entry for '.' and '..'.
+
+ if( _Length == 2 &&
+ _Buffer[0] == '\001' &&
+ _Buffer[1] == '\001' ) {
+
+ return TRUE;
+ }
+
+
+ // If the codepage index is invalid, then the name is invalid.
+
+ if( !Casemap->IsCodpageIndexValid( CodepageIndex ) ) {
+
+ return FALSE;
+ }
+
+ if( Casemap->HasDBCS( CodepageIndex ) ) {
+
+ // This codepage has DBCS characters
+
+ for( i = 0; i < _Length; i++ ) {
+
+ if( Casemap->IsDBCS( CodepageIndex, _Buffer[i] ) ) {
+
+ // This is a DBCS lead byte. The next byte
+ // can be anything, but it must be there.
+
+ i += 1;
+ if( i >= _Length ) {
+
+ // No trailing byte--not acceptable.
+ return FALSE;
+ }
+
+ HasTrailingDot = FALSE;
+
+ } else {
+
+ if( strchr( InvalidChars, _Buffer[i] ) ) {
+
+ // The name has an invalid character
+ return FALSE;
+ }
+
+ if( _Buffer[i] == '.' || _Buffer[i] == ' ' ) {
+
+ HasTrailingDot = TRUE;
+
+ } else {
+
+ HasTrailingDot = FALSE;
+ }
+ }
+ }
+
+ } else {
+
+ // This name has no DBCS characters, so we can just
+ // check each character to see if it is invalid.
+
+ for( i = 0; i < _Length; i++ ) {
+
+ if( strchr( InvalidChars, _Buffer[i] ) ) {
+
+ // The name has an invalid character
+ return FALSE;
+ }
+
+ if( _Buffer[i] == '.' || _Buffer[i] == ' ' ) {
+
+ HasTrailingDot = TRUE;
+
+ } else {
+
+ HasTrailingDot = FALSE;
+ }
+ }
+ }
+
+ // The name has no invalid characters. If it does not
+ // end with a dot or a blank, then it is valid.
+
+ return (!HasTrailingDot);
+}
+
+
+BOOLEAN
+HPFS_NAME::IsNewName(
+ CASEMAP* Casemap,
+ ULONG CodepageIndex
+ )
+/*++
+
+Description of Routine:
+
+ Checks to see if the name is a 'new-name' (i.e. uses the
+ extended naming conventions introduced in OS/2 1.2. A name
+ is a 'new name' if it meets either of two conditions:
+
+ 1) The name does not fit into the 8.3 format, or
+ 2) The name uses a previously forbidden character
+ (ie. one of comma, semicolon, '[', ']', '+', or '=').
+
+Arguments:
+
+ Casemap -- case mapping table for the volume
+ CodepageIndex -- codepage index on volume for which name must be valid
+
+Returns:
+
+ TRUE if the name is a 'new name'; FALSE if not.
+
+Notes:
+
+ This method assumes that the name is valid. In particular, it
+ assumes that every DBCS lead-byte is followed by a trailing byte.
+
+--*/
+{
+
+ BOOLEAN DotSeen = FALSE;
+ ULONG BytesSinceDot, i;
+ BOOLEAN HasDbcs;
+
+ HasDbcs = Casemap->HasDBCS( CodepageIndex );
+
+
+ // The special '..' entry is not a new-name
+
+ if( (_Length == 2) &&
+ (_Buffer[0] == '\001') &&
+ (_Buffer[1] == '\001') ) {
+
+ return FALSE;
+ }
+
+ if( _Length > 12 ) {
+
+ // This is obviously greater than 8.3
+ return TRUE;
+ }
+
+
+ BytesSinceDot = 0;
+
+ for( i = 0; i < _Length; i++ ) {
+
+ // Increment number of bytes seen since last dot
+ BytesSinceDot += 1;
+
+ if( HasDbcs && Casemap->IsDBCS( CodepageIndex, _Buffer[i] ) ) {
+
+ // This is a non-dot character that occupies two bytes.
+ // Increment the counters an extra time to account for
+ // the trailing byte.
+
+ BytesSinceDot += 1;
+ i += 1;
+
+ // If we've seen more than eight bytes before the first
+ // dot, or more than three after it, then the name is a
+ // new name.
+
+ if( !DotSeen && BytesSinceDot > 8 ) {
+
+ return TRUE;
+ }
+
+ if( DotSeen && BytesSinceDot > 3 ) {
+
+ return TRUE;
+ }
+
+ } else if( _Buffer[i] == '.' ) {
+
+ if (DotSeen) {
+
+ /* This is the second dot--it's a new name. */
+ return TRUE;
+
+ } else {
+
+ /*
+ * Note the fact that we've seen a dot, and
+ * start counting bytes after the dot. If
+ * this is the first character, the name
+ * is a new name (leading dot).
+ */
+ if( BytesSinceDot <= 1 )
+ return TRUE;
+
+ BytesSinceDot = 0;
+ DotSeen = TRUE;
+ }
+
+ } else {
+
+ /*
+ * This is a single-byte character. If it is
+ * in the list of new characters, then the name
+ * is a new name.
+ */
+
+ if ( strchr(NewChars, _Buffer[i] ) ) {
+
+ return TRUE;
+ }
+
+ /*
+ * If we've seen more than eight bytes before the
+ * the first dot, or more than three bytes after
+ * it, then the name is a new name.
+ */
+
+ if( !DotSeen && BytesSinceDot > 8 ) {
+
+ return TRUE;
+ }
+
+ if( DotSeen && BytesSinceDot > 3 ) {
+
+ return TRUE;
+ }
+ }
+ }
+
+ // We made it through, so it's not a new name.
+ return FALSE;
+}
+
+
+NAME_COMPARE_RETURN
+HPFS_NAME::CompareName(
+ HPFS_NAME* OtherName
+ )
+/*++
+
+Routine Description:
+
+ Compare two HPFS Names.
+
+
+Returns:
+
+ NAME_IS_LESS_THAN if this name is less that OtherName;
+ NAME_IS_EQUAL_TWO if the two names are identical; or
+ NAME_IS_GREATER_THAN if this name is greater than OtherName.
+
+Notes:
+
+ Since both names have already been converted to upper-case,
+ this is pretty easy...
+
+--*/
+{
+ int i;
+
+ if( _Buffer == NULL ) {
+
+ return NAME_IS_LESS_THAN;
+ }
+
+ if( OtherName == NULL || OtherName->_Buffer == NULL ) {
+
+ return NAME_IS_GREATER_THAN;
+ }
+
+ i = strcmp( (char *)_Buffer, (char *)OtherName->_Buffer );
+
+ if( i < 0 ) {
+
+ return NAME_IS_LESS_THAN;
+
+ } else if( i == 0 ) {
+
+ return NAME_IS_EQUAL_TO;
+
+ } else {
+
+ return NAME_IS_GREATER_THAN;
+ }
+
+}
+
+
+NAME_COMPARE_RETURN
+HPFS_NAME::CompareName(
+ ULONG Length,
+ PUCHAR String,
+ ULONG VolumeCodepageIndex,
+ CASEMAP* Casemap
+ )
+/*++
+
+Routine Description:
+
+ Compare the current name to a raw name
+
+Arguments:
+
+ Length -- Length of the raw name
+ String -- pointer to raw name
+ VolumeCodepageIndex -- codepage of the raw name
+ Casemap -- pointer to volume case-mapping table
+
+Return Value:
+
+ NAME_EQUAL_TO if the current name is equal to the raw name
+ NAME_IS_LESS_THAN if the current name is less than the raw name
+ NAME_IS_GREATER_THAN if the current name is greater than the raw name.
+
+Notes:
+
+ All name comparisons are performed on upper-case names. The
+ current name has already been upper-cased (in Init), but the
+ raw name has not. Thus, we must upper-case the raw name as
+ we go.
+
+ This method assumes that both names are valid.
+
+--*/
+{
+
+ PBYTE pc2 = String;
+ PBYTE pc1 = _Buffer;
+ ULONG Len = min( Length, _Length );
+ BYTE cTemp;
+
+ if( _Buffer == NULL ) {
+
+ return NAME_IS_LESS_THAN;
+ }
+
+ if( Casemap->HasDBCS( VolumeCodepageIndex ) ) {
+
+ // This codepage has DBCS characters, so we have
+ // to check for them.
+
+ while( Len && *pc1 && *pc2) {
+
+ if( Casemap->IsDBCS( VolumeCodepageIndex, *pc2 ) ) {
+
+ // It's a DBCS lead-byte. Compare the lead byte
+ // and the trailing byte without upcasing.
+
+ if( *pc1 != *pc2 ) {
+
+ if( *pc1 < *pc2 ) {
+
+ return NAME_IS_LESS_THAN;
+
+ } else {
+
+ return NAME_IS_GREATER_THAN;
+ }
+ }
+
+ Len--; pc1++; pc2++;
+
+ if( *pc1 != *pc2 ) {
+
+ if( *pc1 < *pc2 ) {
+
+ return NAME_IS_LESS_THAN;
+
+ } else {
+
+ return NAME_IS_GREATER_THAN;
+ }
+ }
+
+ } else {
+
+ // It's not a DBCS lead-byte--compare.
+
+ cTemp = Casemap->UpperCase(*pc2, VolumeCodepageIndex);
+
+ if( *pc1 != cTemp ) {
+
+ if( *pc1 < cTemp ) {
+
+ return NAME_IS_LESS_THAN;
+
+ } else {
+
+ return NAME_IS_GREATER_THAN;
+ }
+ }
+ }
+
+ Len--; pc1++; pc2++;
+ }
+
+ } else {
+
+ // This codepage doesn't have any DBCS characters,
+ // so we can just slam through the string.
+
+ while( Len && *pc1 && *pc2 ) {
+
+ cTemp = Casemap->UpperCase(*pc2, VolumeCodepageIndex);
+
+ if( *pc1 != cTemp ) {
+
+ if( *pc1 < cTemp ) {
+
+ return NAME_IS_LESS_THAN;
+
+ } else {
+
+ return NAME_IS_GREATER_THAN;
+ }
+ }
+
+ Len--; pc1++; pc2++;
+ }
+ }
+
+ // They are equal for the length of the shorter name
+
+ if( Length == _Length ) {
+
+ return NAME_IS_EQUAL_TO;
+
+ } else if ( _Length < Length ) {
+
+ return NAME_IS_LESS_THAN;
+
+ } else {
+
+ return NAME_IS_GREATER_THAN;
+ }
+
+
+}
+
+
+PCUCHAR
+HPFS_NAME::GetString(
+ ) CONST
+{
+ return( _Buffer );
+}
+
+
+BOOLEAN
+HPFS_NAME::IsCodepageInvariant(
+ ) CONST
+/*++
+
+Routine Description:
+
+ Determines if a name is codepage-invariant.
+
+Return Value:
+
+ TRUE if the name is codepage invariant
+
+Notes:
+
+ A name is considered codepage-invariant if it has no characters
+ greater than 0x80, since all single-byte characters below 0x80
+ are always uppercased the same, no matter what the codepage.
+
+ This routine is used in a last-ditch attempt to keep a name--
+ if a directory entry refers to an invalid codepage, it may be
+ kept if it is codepage-invariant. Note that this routine is
+ not one-hundred percent accurate, since it cannot detect
+ DBCS-characters. However, losing the codepage information
+ is preferable to losing the entire file.
+
+
+--*/
+{
+ ULONG i = _Length;
+
+ while( i-- ) {
+
+ if( _Buffer[i] >= 0x80 ) {
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+VOID
+HPFS_NAME::Destroy(
+ )
+/*++
+
+Description of Routine:
+
+ Clean-up routine for an HPFS_NAME. Releases the object's allocated
+ memory and renders it harmless.
+
+--*/
+{
+ if( _Buffer ) {
+
+ FREE (_Buffer);
+ _Buffer = NULL;
+ }
+
+ _Length = 0;
+ _BufferSize = 0;
+
+}
+
+
+
+
+
+DEFINE_CONSTRUCTOR( HPFS_PATH, OBJECT );
+
+VOID
+HPFS_PATH::Construct (
+ )
+
+/*++
+
+Description of Routine:
+
+ Constructor for the HPFS_PATH object; sets private data to
+ reasonable values.
+
+--*/
+{
+
+ _Buffer = NULL;
+ _CurrentLength = 0;
+ _CurrentLevelIndex = 0;
+}
+
+
+HPFS_PATH::~HPFS_PATH(
+ )
+{
+ Destroy();
+}
+
+
+BOOLEAN
+HPFS_PATH::Initialize(
+ )
+/*++
+
+Description of Routine:
+
+ Initializes an HPFS_PATH object.
+
+--*/
+{
+
+ Destroy();
+
+ if( !_ComponentOffsets.Initialize() ||
+ !(_Buffer = (PBYTE)MALLOC( MaximumPathLength + 1)) ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ memset( _Buffer, 0, MaximumPathLength + 1);
+
+ _CurrentLength = 0;
+ _CurrentLevelIndex = 0;
+
+ return TRUE;
+}
+
+
+BOOLEAN
+HPFS_PATH::AddLevel(
+ HPFS_NAME* Name
+ )
+/*++
+
+Description of Routine:
+
+ Adds the name of a subdirectory to the path
+
+Arguments:
+
+ DirectoryName -- pointer to subdirectory name
+
+--*/
+{
+ ULONG i;
+
+ if( _Buffer == NULL ) {
+
+ return FALSE;
+ }
+
+ if( _CurrentLength + 1 + Name->_Length > MaximumPathLength ) {
+
+ return FALSE;
+ }
+
+ if( !_ComponentOffsets.Push( _CurrentLength ) ) {
+
+ return FALSE;
+ }
+
+ _Buffer[_CurrentLength] = '\\';
+ _CurrentLength += 1;
+
+ for( i = 0; i < Name->_Length; i++ ) {
+
+ _Buffer[_CurrentLength+i] = Name->_Buffer[i];
+ }
+
+ _CurrentLength += Name->_Length;
+ _Buffer[_CurrentLength] = 0;
+
+ return TRUE;
+}
+
+BOOLEAN
+HPFS_PATH::StripLevel(
+ )
+/*++
+
+Description of Routine:
+
+ Strips the most-recently-added level (i.e. the last subdirectory
+ name) from the path.
+
+--*/
+{
+ if( _Buffer == NULL ) {
+
+ return FALSE;
+ }
+
+ if( _ComponentOffsets.QuerySize() == 0 ) {
+
+ _CurrentLength = 0;
+
+ } else {
+
+ DebugAssert( _ComponentOffsets.Look().GetLowPart() < _CurrentLength );
+
+ _CurrentLength = _ComponentOffsets.Look().GetLowPart();
+ _ComponentOffsets.Pop();
+ }
+
+ _Buffer[_CurrentLength] = 0;
+
+ return TRUE;
+}
+
+HPFS_NAME*
+HPFS_PATH::QueryFirstLevel(
+ )
+/*++
+
+Description of Routine:
+
+ Fetches the topmost level (i.e. the first name in the path)
+ from the path. This also initializes internal data used by
+ QueryNextLevel.
+
+Returns:
+
+ pointer to the first name in the path, or NULL if the path
+ is empty.
+--*/
+{
+ _CurrentLevelIndex = 0;
+
+ return QueryNextLevel();
+}
+
+
+HPFS_NAME*
+HPFS_PATH::QueryNextLevel(
+ )
+/*++
+
+Description of Routine:
+
+ Fetches the next level in the path. Note that QueryFirstLevel
+ must be called to start the ball rolling.
+
+--*/
+{
+ ULONG DepthInStack;
+ ULONG StartingOffset;
+ ULONG Length;
+ HPFS_NAME* NewName;
+
+ // _CurrentLevelIndex is the index of the component we want.
+
+ if( _CurrentLevelIndex >= (ULONG)_ComponentOffsets.QuerySize() ) {
+
+ return NULL;
+ }
+
+ DepthInStack = _ComponentOffsets.QuerySize() - _CurrentLevelIndex - 1;
+
+ StartingOffset = _ComponentOffsets.Look( DepthInStack ).GetLowPart() + 1;
+
+ DebugAssert( StartingOffset < _CurrentLength );
+
+ if( DepthInStack == 0 ) {
+
+ Length = _CurrentLength - StartingOffset;
+
+ } else {
+
+ Length = _ComponentOffsets.Look( DepthInStack - 1 ).GetLowPart() -
+ StartingOffset;
+ }
+
+
+ if( Length == 0 ||
+ (NewName = NEW HPFS_NAME) == NULL ||
+ !NewName->Initialize( Length,
+ _Buffer + StartingOffset ) ) {
+
+ DELETE( NewName );
+ NewName = NULL;
+
+ return NULL;
+ }
+
+ _CurrentLevelIndex += 1;
+ return NewName;
+}
+
+
+BOOLEAN
+HPFS_PATH::Copy(
+ HPFS_PATH* OtherPath
+ )
+{
+ ULONG i;
+
+ if( _Buffer == NULL ||
+ OtherPath->_Buffer == NULL ||
+ !_ComponentOffsets.Initialize() ) {
+
+ return FALSE;
+ }
+
+ i = OtherPath->_ComponentOffsets.QuerySize();
+
+ while( i-- ) {
+
+ if( !_ComponentOffsets.Push(
+ OtherPath->_ComponentOffsets.Look(i).GetLowPart() ) ) {
+
+ return FALSE;
+ }
+ }
+
+ _CurrentLength = OtherPath->_CurrentLength;
+ _CurrentLevelIndex = 0;
+
+ memmove( _Buffer, OtherPath->_Buffer, (size_t)_CurrentLength );
+
+ return TRUE;
+}
+
+
+PCUCHAR
+HPFS_PATH::GetString(
+ ) CONST
+{
+ return( _Buffer );
+}
+
+
+VOID
+HPFS_PATH::Destroy(
+ )
+/*++
+
+Description of Routine:
+
+ Clean-up routine for an HPFS_PATH. Releases the object's allocated
+ memory and renders it harmless.
+
+--*/
+{
+
+ if( _Buffer ) {
+
+ FREE( _Buffer );
+ }
+}
diff --git a/private/utils/uhpfs/src/hpfssa.cxx b/private/utils/uhpfs/src/hpfssa.cxx
new file mode 100644
index 000000000..7e7b7af97
--- /dev/null
+++ b/private/utils/uhpfs/src/hpfssa.cxx
@@ -0,0 +1,2201 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ hpfssa.cxx
+
+Abstract:
+
+ This module contains member function definitions for the HPFS_SA
+ class, which models the superarea of an HPFS volume. (Note, however,
+ that HPFS_SA::VerifyAndFix is in hpfschk.cxx.)
+
+Author:
+
+ Bill McJohn (billmc) 01-Dec-1990
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "badblk.hxx"
+#include "bitmap.hxx"
+#include "bmind.hxx"
+#include "dirblk.hxx"
+#include "dirmap.hxx"
+#include "error.hxx"
+#include "fnode.hxx"
+#include "hotfix.hxx"
+#include "hpcensus.hxx"
+#include "hpfssa.hxx"
+#include "sid.hxx"
+#include "rtmsg.h"
+#include "message.hxx"
+#include "boothpfs.h"
+
+#if !defined( _AUTOCHECK_ ) && !defined( _SETUP_LOADER_ )
+
+ #include "array.hxx"
+ #include "arrayit.hxx"
+ #include "dircache.hxx"
+ #include "dirtree.hxx"
+ #include "hpfsname.hxx"
+ #include "path.hxx"
+ #include "wstring.hxx"
+
+#endif // _AUTOCHECK_
+
+#define sigSUPERSEC1 (UCHAR)0x55 // signature first byte
+#define sigSUPERSEC2 (UCHAR)0xAA // signature second byte
+
+DEFINE_CONSTRUCTOR( HPFS_SA, SUPERAREA );
+
+VOID
+HPFS_SA::Construct (
+ )
+/*++
+
+Routine Description:
+
+ This method is the helper function for object construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _Bitmap = NULL;
+ _BadBlockList = NULL;
+ _HotfixList = NULL;
+ _Codepage = NULL;
+}
+
+
+HPFS_SA::~HPFS_SA(
+ )
+/*++
+
+Description of Routine:
+
+ Destructor for HPFS_SA
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+HPFS_SA::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Cleanup for the HPFS Superarea class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DELETE( _Bitmap );
+ DELETE( _BadBlockList );
+ DELETE( _HotfixList );
+ DELETE( _Codepage );
+}
+
+
+BOOLEAN
+HPFS_SA::Initialize(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ Initializes the HPFS Superarea.
+
+Arguments:
+
+ Drive - Supplies the drive for the super area.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ CONT_MEM cmem;
+ PVOID super_block;
+
+ Destroy();
+
+ if (!_Mem.Initialize() ||
+ !SUPERAREA::Initialize(&_Mem, Drive, 18, Message)) {
+ Destroy();
+ Message->Set(MSG_INSUFFICIENT_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ _sector_sig = (UCHAR *)SECRUN::GetBuf() + 510;
+
+ super_block = (PCHAR) _Mem.GetBuf() + 16*Drive->QuerySectorSize();
+
+ if (!cmem.Initialize(super_block, 2*Drive->QuerySectorSize()) ||
+ !_SuperBlock.Initialize(&cmem, Drive) ||
+ !_SparesBlock.Initialize(&cmem, Drive)) {
+ Destroy();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+HPFS_SA::Create(
+ IN PCNUMBER_SET BadSectors,
+ IN OUT PMESSAGE Message,
+ IN PCWSTRING Label,
+ IN ULONG ClusterSize,
+ IN ULONG VirtualSectors
+ )
+/*++
+
+Routine Description:
+
+ Create the super area, i.e. Format the disk.
+
+Arguments:
+
+ BadSectors - Supplies a list of the bad sectors on the volume.
+ Message - Supplies an outlet for messages.
+ Label - Supplies an optional label.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+#if defined( _SETUP_LOADER_ )
+
+ return FALSE;
+
+#else
+
+ BITMAPINDIRECT bmind;
+ FNODE fnode;
+ DIRBLK dirblk;
+ SIDTABLE sid;
+ LBN lbn;
+ LBN lbnBadBlk;
+ LBN lbnBMInd;
+ LBN lbnHotFix;
+ LBN lbnDirBand;
+ LBN lbnRootDir;
+ LBN lbnRootFNode;
+ LBN lbnDirMap;
+ LBN lbnSid;
+ LBN lbnSpareDir;
+ LBN lbnCentreBand;
+ LBN lbnCpData;
+ LBN lbnCpInfo;
+ SECTORCOUNT scBadBlk;
+ SECTORCOUNT scBMInd;
+ SECTORCOUNT scHotFix;
+ SECTORCOUNT scDirBand;
+ SECTORCOUNT scDirblk;
+ SECTORCOUNT scDirMap;
+ SECTORCOUNT scMaxHot;
+ ULONG cMegaBytes;
+ HMEM hmem;
+ SECRUN secrun;
+ SECRUN small_secrun;
+ BIG_INT TotalSpaceKB, FreeSpaceKB;
+ SECTORCOUNT sectors;
+ ULONG sector_size;
+ LBN i, n;
+ HPFS_MAIN_BITMAP used_sectors;
+ PUSHORT p;
+ DSTRING label;
+ ULONG NumberOfBitmaps;
+ BIG_INT start, length;
+ PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK
+ SourceBootSector, TargetBootSector;
+ ULONG BootCodeOffset;
+
+ UNREFERENCED_PARAMETER( VirtualSectors );
+
+ if (_drive->IsFloppy()) {
+ Message->Set(MSG_HPFS_FORMAT_NO_FLOPPIES);
+ Message->Display();
+ return FALSE;
+ }
+
+ sector_size = _drive->QuerySectorSize();
+
+ if (_drive->QuerySectors().GetHighPart() != 0) {
+ DebugAbort("Number of sectors exceeds 32 bits");
+ Message->Set( MSG_DISK_TOO_LARGE_TO_FORMAT );
+ Message->Display();
+ return FALSE;
+ }
+
+ sectors = _drive->QuerySectors().GetLowPart();
+
+ if (sector_size != 512) {
+ Message->Set(MSG_HPFS_FORMAT_BAD_SECTOR_SIZE);
+ Message->Display();
+ return FALSE;
+ }
+
+ memset(_Mem.GetBuf(), 0, (UINT) _Mem.QuerySize());
+
+ // Start by doing a create of the SUPERAREA.
+ if (!SetSystemId()) {
+ Message->Set(MSG_WRITE_PARTITION_TABLE);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!CreateBootSector()) {
+
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if (!used_sectors.Initialize(_drive) ||
+ !used_sectors.Create()) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ n = BadSectors->QueryNumDisjointRanges();
+ for (i = 0; i < n; i++) {
+ BadSectors->QueryDisjointRange(i, &start, &length);
+ if (!used_sectors.SetAllocated(start.GetLowPart(), length.GetLowPart())) {
+
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+ }
+
+ // Verify that sectors 0 to 17 are free.
+ for (lbn = 0; lbn <= 17; lbn++) {
+ if (!used_sectors.IsFree(lbn)) {
+ Message->Set(MSG_CANT_READ_HPFS_ROOT);
+ Message->Display("");
+ return FALSE;
+ }
+ }
+
+ // Mark 0 to 19 as used.
+ if (!used_sectors.SetAllocated(0, EndOfSuperArea + 1)) {
+
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+
+ // ---------------------------------------
+ // Do the simple computation of constants.
+ // ---------------------------------------
+
+ // Compute the number of sectors for the bit map indirect. There is
+ // one bitmap block for each 8*BITMAP_SIZE sectors on the volume, and
+ // the Bitmap Indirect Block has one LBN for each bitmap block. Note
+ // that the size of the Bitmap Indirect Block is rounded up to a multiple
+ // of four sectors.
+
+ NumberOfBitmaps = (sectors + 8*BITMAP_SIZE - 1)/(8*BITMAP_SIZE);
+
+ scBMInd = ( NumberOfBitmaps * sizeof(LBN) + sector_size - 1)/sector_size;
+
+ scBMInd = ( scBMInd + 3 ) & (~3);
+
+
+ // Compute the number of sectors for first bad block. Note that
+ // a bad block has a forward pointer (which is an LBN) and
+ // LBNS_IN_BADBLK bad-sector LBNs.
+
+ scBadBlk = (LBNS_IN_BADBLK+1)*sizeof(LBN)/sector_size;
+
+ // Compute the number of sectors per dir block.
+ scDirblk = DIRBLK_SIZE/sector_size;
+
+ // Compute the number of megabytes of disk space.
+ cMegaBytes = sectors*sector_size/MEGABYTE;
+
+ // If the disk contains more than 10 megabytes.
+ if (cMegaBytes > 10) {
+ // Allocate 5 dir blocks per megabyte.
+ scDirBand = 5*cMegaBytes;
+ } else {
+ // Allocate 50 dir blocks.
+ scDirBand = 50;
+ }
+
+ // If the computed number is greater than allowed maximum.
+ if (scDirBand > MAX_DBS_PER_DIRBAND) {
+ // Set value to the max.
+ scDirBand = MAX_DBS_PER_DIRBAND;
+ }
+
+ // Multiply by number of sectors per dirblk to get total number of sectors.
+ scDirBand *= scDirblk;
+
+ // Compute the number of sectors per dir band bit map.
+ scDirMap = DIRMAP_SIZE/sector_size;
+
+ // Compute the number of sectors for the hot fix list.
+ scHotFix = HOTFIX_MAX_LBN*sizeof(LBN)/sector_size;
+
+ // Compute the number of hotfixes.
+ scMaxHot = sectors/400;
+ if (scMaxHot > 100) {
+ scMaxHot = 100;
+ }
+
+ // Compute the location of the centre band on the disk.
+ lbnCentreBand = (sectors/(8*BITMAP_SIZE)/2)*8*BITMAP_SIZE;
+
+
+
+ // ------------------------
+ // Set up the hpfs bit map.
+ // ------------------------
+
+ // Find room for dir band.
+ if (!(lbnDirBand = used_sectors.NearLBN(lbnCentreBand, scDirBand, SPB))) {
+ Message->Set(MSG_INSUFFICIENT_DISK_SPACE);
+ Message->Display("");
+ return FALSE;
+ }
+
+ // Find room for the dir bit map.
+ if (lbnCentreBand) {
+ if (!(lbnDirMap = used_sectors.NearLBN(
+ lbnCentreBand - scDirMap, scDirMap))) {
+ Message->Set(MSG_INSUFFICIENT_DISK_SPACE);
+ Message->Display("");
+ return FALSE;
+ }
+ } else {
+ if (!(lbnDirMap = used_sectors.MiddleLBN(scDirMap, scDirMap))) {
+ Message->Set(MSG_INSUFFICIENT_DISK_SPACE);
+ Message->Display("");
+ return FALSE;
+ }
+ }
+
+ // Create the bit map.
+ if (!(_Bitmap = NEW HPFS_BITMAP)) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!_Bitmap->Initialize(_drive, lbnDirMap, scDirBand, lbnDirBand)) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ // Allocate sectors 0 to 19 again and mark the bad sectors too.
+ if (!_Bitmap->SetAllocated(0, EndOfSuperArea + 1)) {
+ Message->Set(MSG_INSUFFICIENT_DISK_SPACE);
+ Message->Display("");
+ return FALSE;
+ }
+
+ n = BadSectors->QueryNumDisjointRanges();
+ for (i = 0; i < n; i++) {
+ BadSectors->QueryDisjointRange(i, &start, &length);
+ if (!_Bitmap->SetAllocated(start.GetLowPart(), length.GetLowPart())) {
+
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+ }
+
+ // -------------------------------------
+ // Now there's a good bit map. Go nuts.
+ // -------------------------------------
+
+
+ // -----------------------
+ // Take care of the BMIND.
+ // -----------------------
+
+ if (!(lbnBMInd = _Bitmap->NearLBN(sectors/2, scBMInd, scBMInd))) {
+ Message->Set(MSG_INSUFFICIENT_DISK_SPACE);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!bmind.Initialize(_drive, lbnBMInd) ||
+ !bmind.Create(_drive, _Bitmap)) {
+ Message->Set(MSG_INSUFFICIENT_DISK_SPACE);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!bmind.Write()) {
+
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ // ----------------------------------------------------------
+ // Allocate room for the remaining structures on the bit map.
+ // ----------------------------------------------------------
+
+ // Allocate sectors for the hot fix list.
+ lbnHotFix = _Bitmap->NearLBN(20, scHotFix, scHotFix);
+
+ if (lbnCentreBand) {
+ lbnRootDir = _Bitmap->NearLBN(
+ lbnCentreBand - scDirblk - scDirMap, scDirblk);
+ } else {
+ lbnRootDir = _Bitmap->NearLBN(sectors/2, scDirblk, scDirblk);
+ }
+
+ // Allocate the spot for the root fnode behind the root directory.
+ lbnRootFNode = _Bitmap->NearLBN(lbnRootDir, 1, 1, TRUE);
+
+ // Allocate first bad block.
+ lbnBadBlk = _Bitmap->NearLBN(sectors/2, scBadBlk, scBadBlk);
+
+ // Allocate room for the sid table.
+ lbnSid = _Bitmap->NearLBN(sectors/2, SECTORS_PER_SID, SPB);
+
+ // Allocate room for the CP DATA sector.
+ lbnCpData = _Bitmap->NearLBN(sectors/2, SectorsPerCPDataSector);
+
+ // Allocate room for the CP INFO sector.
+ lbnCpInfo = _Bitmap->NearLBN(sectors/2, SectorsPerCPInfoSector);
+
+ if (!lbnHotFix || !lbnRootDir || !lbnRootFNode || !lbnBadBlk ||
+ !lbnSid || !lbnCpData || !lbnCpInfo) {
+ Message->Set(MSG_INSUFFICIENT_DISK_SPACE);
+ Message->Display("");
+ return FALSE;
+ }
+
+
+ // --------------------------------
+ // Take care of the bad block list.
+ // --------------------------------
+
+ // Create a new bad block.
+ if (!(_BadBlockList = NEW BADBLOCKLIST) ||
+ !_BadBlockList->Initialize(_drive, lbnBadBlk) ||
+ !_BadBlockList->Create(lbnBadBlk) ||
+ !_BadBlockList->Initialize(_drive, lbnBadBlk)) {
+
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+
+ n = BadSectors->QueryNumDisjointRanges();
+ for (i = 0; i < n; i++) {
+ BadSectors->QueryDisjointRange(i, &start, &length);
+ if (!_BadBlockList->AddRun(start.GetLowPart(), length.GetLowPart())) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+ }
+
+
+ // Write the bad block list to disk.
+ if (!_BadBlockList->Write(this)) {
+
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+
+ // ---------------------------------------------
+ // Create the super and spare blocks.
+ // ---------------------------------------------
+
+ // Compute starting lbn of the spare dir blocks.
+ lbnSpareDir = lbnDirBand + scDirBand;
+
+ // Create the super block.
+ if (!_SuperBlock.Create(_drive, _Bitmap, _BadBlockList, lbnRootFNode,
+ lbnBMInd, lbnBadBlk, scDirBand, lbnDirBand, lbnDirMap, lbnSid)) {
+
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ // Set the number of bad sectors in the super block.
+
+ _SuperBlock.SetBadSectors(BadSectors->QueryCardinality().GetLowPart());
+
+ // Create the spare block.
+ if (!_SparesBlock.Create(_drive, _Bitmap, &_SuperBlock, lbnHotFix, scMaxHot,
+ lbnCpInfo, 1, lbnSpareDir, SPARE_DIR_BLKS)) {
+
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+
+ // ------------------
+ // Do the root fnode.
+ // ------------------
+
+ if (!fnode.Initialize(_drive, lbnRootFNode)) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ // Create the root fnode.
+ if (!fnode.CreateRoot(lbnRootDir)) {
+
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ // Write the root fnode to disk.
+ if (!fnode.Write()) {
+
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if (!hmem.Initialize() ||
+ !secrun.Initialize(&hmem, _drive, fnode.QueryStartLbn(), 1) ||
+ !secrun.Read()) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+
+ // --------------------
+ // Do the hot fix list.
+ // --------------------
+
+ if (!(_HotfixList = NEW HOTFIXLIST)) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!_HotfixList->Initialize(_drive, &_SparesBlock)) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!_HotfixList->Create(_Bitmap, lbnHotFix)) {
+ Message->Set(MSG_INSUFFICIENT_DISK_SPACE);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!_HotfixList->Write()) {
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+
+ // ----------------------
+ // Do the root dir block.
+ // ----------------------
+
+ if (!dirblk.Initialize(_drive, _HotfixList, lbnRootDir)) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!dirblk.CreateRoot(lbnRootFNode)) {
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if (!dirblk.Write()) {
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+
+ // -----------------
+ // Do the sid table.
+ // -----------------
+
+ if (!sid.Initialize(_drive, lbnSid)) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!sid.Create()) {
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if (!sid.Write()) {
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+
+ // -----------------------
+ // Do the code page stuff.
+ // -----------------------
+
+ if (!(_Codepage = NEW UHPFS_CODEPAGE)) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!_Codepage->Initialize()) {
+ Message->Set(MSG_FMT_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!_Codepage->Create(_drive, lbnCpInfo, lbnCpData)) {
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+
+ // ----------------------------------
+ // Write the important stuff to disk.
+ // ----------------------------------
+
+
+ // Write the bit map.
+ if (!_Bitmap->Write(&bmind)) {
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ Message->Set(MSG_FORMAT_COMPLETE);
+ Message->Display("");
+
+ if (!label.Initialize( "" )) {
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if (Label) {
+ if (!label.Initialize(Label)) {
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+ } else {
+ Message->Set(MSG_VOLUME_LABEL_PROMPT);
+ Message->Display("");
+ Message->QueryStringInput(&label);
+ }
+
+ while (!label.Strupr() || !SetLabel(&label)) {
+
+ Message->Set(MSG_INVALID_LABEL_CHARACTERS);
+ Message->Display("");
+
+ Message->Set(MSG_VOLUME_LABEL_PROMPT);
+ Message->Display("");
+ Message->QueryStringInput(&label);
+ }
+
+ // Copy the HPFS boot code into the secrun's buffer.
+ // This is complicated by the fact that DOS_SA::Write
+ // packs the data from the unpacked boot sector into
+ // the packed boot sector, so we have to set the
+ // first few fields in the unpacked version.
+ //
+ SourceBootSector = (PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK)HpfsBootCode;
+
+ CopyUchar2(&_sector_zero.BootStrapJumpOffset,
+ SourceBootSector->BootStrapJumpOffset);
+ CopyUchar1(&_sector_zero.IntelNearJumpCommand,
+ SourceBootSector->IntelNearJumpCommand);
+
+ //
+ // Copy the remainder of the boot code directly into
+ // the secrun.
+ //
+ TargetBootSector = (PPACKED_EXTENDED_BIOS_PARAMETER_BLOCK)SECRUN::GetBuf();
+
+ BootCodeOffset = FIELD_OFFSET( PACKED_EXTENDED_BIOS_PARAMETER_BLOCK, StartBootCode );
+
+ memcpy( (PUCHAR)TargetBootSector + BootCodeOffset,
+ (PUCHAR)SourceBootSector + BootCodeOffset,
+ sizeof( HpfsBootCode ) - BootCodeOffset );
+
+
+ // Write the HPFS super area.
+ if (!Write()) {
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+
+ // -----------------------
+ // Generate a nice report.
+ // -----------------------
+ //
+ // Note that we have to do some funny arithmetic to make sure
+ // everything gets promoted to BIG_INTs.
+ //
+ TotalSpaceKB = sectors;
+ TotalSpaceKB = TotalSpaceKB * sector_size;
+ TotalSpaceKB = TotalSpaceKB / 1024;
+
+ FreeSpaceKB = (_Bitmap->GetBitmap())->QueryFreeSectors();
+ FreeSpaceKB = FreeSpaceKB * sector_size;
+ FreeSpaceKB = FreeSpaceKB / 1024;
+
+ Message->Set(MSG_TOTAL_KILOBYTES);
+ Message->Display("%9d", TotalSpaceKB.GetLowPart());
+
+ if (BadSectors->QueryCardinality().GetLowPart()) {
+ Message->Set(MSG_HPFS_CHKDSK_STATISTICS_BAD);
+ Message->Display("%9d",
+ (BadSectors->QueryCardinality()*sector_size/1024).GetLowPart());
+ }
+
+ Message->Set(MSG_AVAILABLE_KILOBYTES);
+ Message->Display("%9d", FreeSpaceKB.GetLowPart());
+
+ if (QueryVolId()) {
+ p = (PUSHORT) &_sector_zero.SerialNumber;
+ Message->Set(MSG_VOLUME_SERIAL_NUMBER);
+ Message->Display("%04X%04X", p[1], p[0]);
+ }
+
+ DELETE( _Bitmap );
+ DELETE( _HotfixList );
+ DELETE( _BadBlockList );
+ DELETE( _Codepage );
+
+ return TRUE;
+
+#endif // _SETUP_LOADER_
+}
+
+
+BOOLEAN
+HPFS_SA::RecoverFile(
+ IN PCWSTRING FullPathFileName,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This method is a stub to satisfy the requirement for a RecoverFile
+ method on classes that derive from DOS_SA. File recovery is carried
+ out in the Recover entry point of UHPFS.DLL.
+
+Arguments:
+
+ FullPathFileName -- supplies the full path of the file to recover.
+ Message -- supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ (void)this;
+ (void)FullPathFileName;
+ (void)Message;
+ return TRUE;
+}
+
+
+#if !defined( _AUTOCHECK_ ) && !defined( _SETUP_LOADER_ )
+
+UHPFS_EXPORT
+PFNODE
+HPFS_SA::QueryFnodeFromName(
+ IN PPATH RecFilePath,
+ IN PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ Gets FNODE for a path.
+
+Arguments:
+
+ RecFilePath -- supplies the path.
+ Message -- supplies an outlet for messages.
+
+Return Value:
+
+ NULL - Failure.
+ non-NULL- pointer to FNODE for the path.
+
+--*/
+{
+ HPFS_DIRECTORY_TREE DirTree;
+ PDIRBLK_CACHE DirBlkCache = NULL;
+ PARRAY_ITERATOR Iterator = NULL;
+
+ LBN CurrFnodeLbn;
+ LBN CurrDirBlkLbn;
+ FNODE CurrFnode;
+ PFNODE RetFnode;
+ PARRAY Components = NULL;
+ PWSTRING CurrentComp;
+ PSTR AnsiStr;
+ HPFS_NAME HpfsName;
+
+ //
+ // - chase down HPFS_DIRECTORY_TREE until we have an LBN for the fnode
+ // - need a DirBlkCache
+ // - get the root dir's FnodeLbn from SuperArea's SuperBlock
+ // - get the root dir's DirBlkLbn from Fnode
+ //
+ if( !(_HotfixList = QueryHotFixList())
+ || !(_BadBlockList = QueryBadBlockList())
+ || !ReadCodepage()
+ || (DirBlkCache = NEW DIRBLK_CACHE) == NULL
+ || !(DirBlkCache->Initialize( _drive, _HotfixList ))
+ || (Components = RecFilePath->QueryComponentArray()) == NULL
+ || (CurrFnodeLbn = _SuperBlock.QueryRootFnodeLbn()) == 0
+ || (Iterator = (PARRAY_ITERATOR)Components->QueryIterator()) == NULL ) {
+
+ // The super-areas ancillary objects could not
+ // be allocated.
+
+ DebugPrint( "recover: Unable to create helper objects in name->fnode\n" );
+
+ Message->Set( MSG_INSUFFICIENT_MEMORY );
+ Message->Display("");
+
+ DELETE( Iterator );
+ DELETE( Components );
+ DELETE( DirBlkCache );
+ return NULL;
+ }
+
+ //
+ // - for each component
+ // - init a DirTree
+ // - get Lbn of Fnode of child from DirTree
+ //
+
+ CurrentComp = (PWSTRING)Iterator->GetNext();
+ DELETE(CurrentComp);
+ while( (CurrentComp = (PWSTRING)Iterator->GetNext()) ) {
+ //
+ // - verify that the wstring is indeed a wstring
+ //
+ CurrFnode.Initialize( _drive, CurrFnodeLbn );
+ CurrFnode.Read();
+
+ DebugAssert( CurrFnode.IsFnode() );
+
+ CurrDirBlkLbn = CurrFnode.QueryRootDirblkLbn();
+ DebugAssert( CurrDirBlkLbn != 0 );
+ DirTree.Initialize( this, DirBlkCache, CurrDirBlkLbn, CurrFnodeLbn );
+
+ CurrentComp->Strupr();
+ if( (AnsiStr = CurrentComp->QuerySTR()) == NULL ) {
+
+ Message->Set( MSG_INSUFFICIENT_MEMORY );
+ Message->Display("");
+ DELETE( Iterator );
+ DELETE( Components );
+ DELETE( DirBlkCache );
+ return( NULL );
+ }
+
+ DebugPrint( "searching for component <" );
+ DebugPrint( AnsiStr );
+ DebugPrint( ">\n" );
+ HpfsName.Initialize( (ULONG)strlen( AnsiStr ), (PUCHAR)AnsiStr );
+ FREE( AnsiStr );
+ CurrFnodeLbn = DirTree.QueryFnodeLbnFromName( &HpfsName );
+ if( CurrFnodeLbn == 0 ) {
+
+ // print message here: file not found
+
+ DebugPrint( "recover: file not found\n" );
+
+ Message->Set( MSG_RECOV_FILE_NOT_FOUND );
+ Message->Display("");
+
+ DELETE( Iterator );
+ DELETE( Components );
+ DELETE( DirBlkCache );
+ return( NULL );
+ }
+
+ DELETE( CurrentComp );
+ }
+
+ // Don't need the array of components or its iterator or the dirblkcache
+
+ DELETE( Components );
+ DELETE( Iterator );
+ DELETE( DirBlkCache );
+
+ //
+ // - init an FNODE with the LBN
+ // - fnode->read() - to make it read itself
+ //
+ if( !(RetFnode = NEW FNODE) ) {
+ Message->Set( MSG_INSUFFICIENT_MEMORY );
+ Message->Display("");
+ DELETE( RetFnode );
+ return( NULL );
+ }
+
+ if( !RetFnode->Initialize( _drive, CurrFnodeLbn )
+ || !RetFnode->Read() ) {
+
+ DebugPrint( "recover: error getting ready to return the fnode (read/mem)\n" );
+
+ Message->Set( MSG_RECOV_READ_ERROR );
+ Message->Display("");
+ DELETE( RetFnode );
+ return( NULL );
+ }
+
+ return( RetFnode );
+}
+
+
+BOOLEAN
+HPFS_SA::AddBadBlocks(
+ IN OUT PNUMBER_SET BadBlocks,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ Adds the bad sectors in the BadBlocks to the volume's BadBlockList.
+
+Arguments:
+
+ BadBlocks -- supplies a collection of LBNs which are to be
+ added to the bad block list.
+ Message -- supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ LBN BadSec;
+ PBITMAPINDIRECT BitmapIndirectBlock = NULL;
+
+ if ( !(_BadBlockList = QueryBadBlockList()) ) {
+
+ // The super-area's ancillary objects could not
+ // be allocated.
+
+ DebugPrint( "recover: Unable to get bad block list\n" );
+
+ Message->Set( MSG_INSUFFICIENT_MEMORY );
+ Message->Display("");
+
+ return FALSE;
+ }
+
+ if( (_Bitmap = NEW HPFS_BITMAP()) == NULL
+ || !_Bitmap->Initialize( _drive,
+ _SuperBlock.QueryDirblkMapLbn(),
+ _SuperBlock.QueryDirBandSize(),
+ _SuperBlock.QueryDirBandLbn() )
+ || (BitmapIndirectBlock = QueryBitMapInd()) == NULL
+ || !BitmapIndirectBlock->Read()
+ || !_Bitmap->Read( BitmapIndirectBlock ) ) {
+
+ DebugPrint( "Cannot alloc/initialize bitmap.\n" );
+
+ Message->Set( MSG_INSUFFICIENT_MEMORY );
+ Message->Display("");
+
+ DELETE( BitmapIndirectBlock );
+ DELETE( _Bitmap );
+ return FALSE;
+ }
+
+ //
+ // - update BadBlockList
+ //
+ while( BadBlocks->QueryCardinality() > 0 ) {
+
+ BadSec = BadBlocks->QueryNumber(0).GetLowPart();
+ BadBlocks->Remove(BadSec);
+
+ //
+ // - add bad sector if not in use. This check is done because it
+ // is possible that another process slipped in and used the sector
+ // between the time the file was deleted and we locked the disk.
+ // (ie. deleting the file and locking the disk was not atomic)
+ // - so if it is not in use then mark it as bad.
+ //
+ if( _Bitmap->IsFree( BadSec, 1 ) ) {
+ _Bitmap->SetAllocated( BadSec );
+ _BadBlockList->Add( BadSec );
+ _SuperBlock.SetBadSectors( _SuperBlock.QueryBadSectors() + 1 );
+ } else {
+ DebugPrint( "recover: Bad sector couldn't be marked bad because already in use\n" );
+ }
+ }
+
+ if( !_BadBlockList->Write(this)
+ || !_Bitmap->Write( BitmapIndirectBlock )
+ || !BitmapIndirectBlock->Write()
+ || !_SuperBlock.Write() ) {
+
+ DebugPrint( "recover: couldn't write the bitmap!!\n" );
+ Message->Set( MSG_RECOV_WRITE_ERROR );
+ Message->Display("");
+
+ DELETE( BitmapIndirectBlock );
+ DELETE( _Bitmap );
+ return( FALSE );
+ }
+
+ DELETE( _Bitmap );
+ DELETE( BitmapIndirectBlock );
+ return( TRUE );
+}
+
+#endif // _AUTOCHECK_ || _SETUP_LOADER_
+
+
+PUHPFS_CODEPAGE
+HPFS_SA::QueryCodePage(
+ )
+/*++
+
+Method Description:
+
+ Return a new code page object.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ PUHPFS_CODEPAGE or NULL
+
+--*/
+{
+ PUHPFS_CODEPAGE CodePage;
+
+ // Check state of object.
+ if (!_drive)
+ {
+ perrstk->push(ERR_HPSA_PARAMETER, QueryClassId());
+ return NULL;
+ }
+
+ if ((CodePage = NEW UHPFS_CODEPAGE) != NULL) {
+ return CodePage;
+ }
+ else {
+ perrstk->push(NEW_ALLOC_FAILED, QueryClassId());
+ return NULL;
+ }
+}
+
+
+
+UHPFS_EXPORT
+BOOLEAN
+HPFS_SA::ReadCodepage(
+ )
+/*++
+
+Routine Description:
+
+ Reads the codepages from disk and set up the codepage member object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion
+
+Notes:
+
+ This function assumes that the codepages on disk are valid. If _Codepage
+ is NULL, this method will set it up.
+
+--*/
+{
+ if( _Codepage == NULL &&
+ (_Codepage = QueryCodePage()) == NULL ) {
+
+ return FALSE;
+ }
+
+ return _Codepage->Read( _drive, _SparesBlock.QueryCpInfoLbn() );
+}
+
+UHPFS_EXPORT
+BOOLEAN
+HPFS_SA::SetupHelpers(
+ )
+/*++
+
+Routine Description:
+
+ This method sets up the cached helpers for the super-area--
+ the Bitmap, the Codepages, and the Hotfix List. All of
+ these are initialized and read into memory from disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ PBITMAPINDIRECT BitmapIndirectBlock;
+
+ // Allocate and read the Bitmap.
+ //
+ if( (_Bitmap = NEW HPFS_BITMAP()) == NULL
+ || !_Bitmap->Initialize( _drive,
+ _SuperBlock.QueryDirblkMapLbn(),
+ _SuperBlock.QueryDirBandSize(),
+ _SuperBlock.QueryDirBandLbn() )
+ || (BitmapIndirectBlock = QueryBitMapInd()) == NULL
+ || !BitmapIndirectBlock->Read()
+ || !_Bitmap->Read( BitmapIndirectBlock ) ) {
+
+ DELETE( BitmapIndirectBlock );
+ DELETE( _Bitmap );
+ return FALSE;
+ }
+
+ DELETE( BitmapIndirectBlock );
+
+ // Read the hotfix list and the codepage information.
+ //
+ if( !(_HotfixList = QueryHotFixList()) ||
+ !_HotfixList->Read() ||
+ !ReadCodepage() ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+HPFS_SA::WriteBitmap(
+ )
+/*++
+
+Routine Description:
+
+ This methods writes the volume bitmap.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ BOOLEAN Result;
+ PBITMAPINDIRECT BitmapIndirectBlock;
+
+ if( (BitmapIndirectBlock = QueryBitMapInd()) == NULL ) {
+
+ return FALSE;
+ }
+
+ Result = BitmapIndirectBlock->Read() &&
+ _Bitmap->Write( BitmapIndirectBlock );
+
+ DELETE( BitmapIndirectBlock );
+
+ return Result;
+}
+
+BOOLEAN
+HPFS_SA::QueryLabel(
+ OUT PWSTRING Label
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine queries the label from the HPFS superarea.
+ If the label is not present then 'Label' will return the
+ null-string. If the label is invalid then FALSE will be
+ returned.
+
+Arguments:
+
+ Label - Returns a volume label.
+
+Return Value:
+
+ FALSE - The label is invalid.
+ TRUE - The label is valid.
+
+--*/
+{
+ ULONG i;
+ BOOLEAN Result;
+
+ // Accept as part of the label any characters up to the first
+ // null or space, or up to the maximum number of characters
+ // in the label (cLABEL, defined in ifsutil\inc\bpb.hxx).
+ //
+ i = 0;
+
+ while( i < cLABEL &&
+ _sector_zero.Label[i] != ' ' &&
+ _sector_zero.Label[i] != 0 ) {
+
+ i++;
+ }
+
+ if( i == 0 ) {
+
+ Result = Label->Initialize( "" );
+
+ } else {
+
+ Result = Label->Initialize( (PCSTR)_sector_zero.Label, i );
+ }
+
+ return Result;
+}
+
+
+
+PBADBLOCKLIST
+HPFS_SA::QueryBadBlockList (
+ )
+/*++
+
+Method Description:
+
+ Return a new in memory bad block list.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ PBADBLOCKLIST or NULL
+
+--*/
+{
+ PBADBLOCKLIST BadBlockList;
+ LBN Lbn;
+
+ // Query the starting lbn of the bad block list from super block.
+ if (!(Lbn = _SuperBlock.QueryBadBlkLbn())) {
+ perrstk->push(ERR_HPSA_NOT_READ, QueryClassId());
+ return NULL;
+ }
+
+ if ( (BadBlockList = NEW BADBLOCKLIST) != NULL &&
+ BadBlockList->Initialize( _drive, Lbn ) ) {
+
+ return BadBlockList;
+ }
+ else {
+
+ DELETE( BadBlockList );
+ perrstk->push(NEW_ALLOC_FAILED, QueryClassId());
+ return NULL;
+ }
+}
+
+
+
+PHOTFIXLIST
+HPFS_SA::QueryHotFixList(
+ ) const
+/*++
+
+Routine Description:
+
+ This method fetches sets up a Hotfix List for the volume.
+ Note that it does not read the hotfix list.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the newly-generated hotfix-list object.
+
+--*/
+{
+ PHOTFIXLIST HotFix;
+
+ // Check state of object.
+ if (!_drive)
+ {
+ perrstk->push(ERR_HPSA_PARAMETER, QueryClassId());
+ return NULL;
+ }
+
+ if( (HotFix = NEW HOTFIXLIST) != NULL &&
+ HotFix->Initialize(_drive, (SPAREB *)&_SparesBlock) ) {
+
+ return HotFix;
+
+ } else {
+
+ perrstk->push(NEW_ALLOC_FAILED, QueryClassId());
+ return NULL;
+ }
+}
+
+
+PBITMAPINDIRECT
+HPFS_SA::QueryBitMapInd(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method sets up a Bitmap Indirect Block object for the volume.
+ Note that it does not read the Bitmap Indirect Block.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the newly-generated bitmap indirect block object
+
+--*/
+{
+ LBN lbn;
+ PBITMAPINDIRECT BitmapIndirect;
+
+ // Check state of object.
+ if (!_drive)
+ {
+ perrstk->push(ERR_HPSA_PARAMETER, QueryClassId());
+ return NULL;
+ }
+
+ // Query the lbn for the bit map indirect from the super block.
+ lbn = _SuperBlock.QueryBitMapIndLbn();
+ if (!lbn) {
+
+ perrstk->push(ERR_HPSA_NOT_READ, QueryClassId());
+ return NULL;
+ }
+
+ if( (BitmapIndirect = NEW BITMAPINDIRECT) != NULL &&
+ BitmapIndirect->Initialize(_drive, lbn) ) {
+
+ return BitmapIndirect;
+
+ } else {
+
+ DELETE( BitmapIndirect );
+ perrstk->push(NEW_ALLOC_FAILED, QueryClassId());
+ return NULL;
+ }
+}
+
+
+/***************************************************************************\
+
+MEMBER: HPFS_SA::QuerySidTable
+
+SYNOPSIS: Construct a sid table object from information in super area.
+
+ALGORITHM:
+
+ARGUMENTS:
+
+RETURNS: A pointer to a valid sid table object or NULL.
+
+NOTES:
+
+HISTORY:
+ 9-Sep-90 norbertk
+ Create
+
+KEYWORDS:
+
+SEEALSO:
+
+\***************************************************************************/
+
+
+PSIDTABLE HPFS_SA::QuerySidTable() const
+{
+ LBN lbn;
+ PSIDTABLE p = NULL;
+
+ // Check state of object.
+ if (!_drive)
+ {
+ perrstk->push(ERR_HPSA_PARAMETER, QueryClassId());
+ DELETE( p );
+ return NULL;
+ }
+
+ // Query the lbn for the sid table from the super block.
+ lbn = _SuperBlock.QuerySidTableLbn();
+ if (!lbn)
+ {
+ perrstk->push(ERR_HPSA_NOT_READ, QueryClassId());
+ DELETE( p );
+ return NULL;
+ }
+
+ if (!(p = NEW SIDTABLE)) {
+ perrstk->push(NEW_ALLOC_FAILED, QueryClassId());
+ DELETE( p );
+ return FALSE;
+ }
+
+ if (!p->Initialize(_drive, lbn)) {
+ DELETE( p );
+ return NULL;
+ }
+
+ return p;
+}
+
+BOOLEAN
+HPFS_SA::SetBpb(
+ )
+/*++
+
+Routine Description:
+
+ This routine sets an HPFS BPB.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+#if defined( _SETUP_LOADER_ )
+
+ return FALSE;
+
+#else
+
+ //
+ // This is the relevant text of DOS_SUPERAREA::SetBpb()
+ //
+
+ DebugAssert(_drive);
+ DebugAssert(_drive->QuerySectors().GetHighPart() == 0);
+ DebugAssert(_drive->QueryHiddenSectors().GetHighPart() == 0);
+
+ _sector_zero.Bpb.BytesPerSector = (USHORT)_drive->QuerySectorSize();
+
+ _sector_zero.Bpb.Media = _drive->QueryMediaByte();
+ _sector_zero.Bpb.SectorsPerTrack = (USHORT)_drive->QuerySectorsPerTrack();
+ _sector_zero.Bpb.Heads = (USHORT)_drive->QueryHeads();
+ _sector_zero.Bpb.HiddenSectors = _drive->QueryHiddenSectors().GetLowPart();
+
+ // HPFS will use 32bit sector count instead of the 16 bit count
+ // in all cases.
+ _sector_zero.Bpb.LargeSectors = _drive->QuerySectors().GetLowPart();
+ _sector_zero.Bpb.Sectors = 0;
+
+ // Set the number of FATs to zero.
+ _sector_zero.Bpb.Fats = 0;
+
+ _sector_zero.Bpb.SectorsPerCluster = 0;
+ _sector_zero.Bpb.ReservedSectors = 1;
+ _sector_zero.Bpb.SectorsPerFat = 0;
+ _sector_zero.Bpb.RootEntries = 512;
+
+ memcpy(_sector_zero.SystemIdText, "HPFS ", cSYSID);
+
+ return TRUE;
+
+#endif // _SETUP_LOADER_
+}
+
+
+SECTORCOUNT
+HPFS_SA::QueryFreeSectors(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This virtual method is not supported for HPFS.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ // unreferenced parameters
+ (void)(this);
+
+ return 0;
+}
+
+
+BOOLEAN
+HPFS_SA::CopyRun(
+ IN LBN StartLbn,
+ IN SECTORCOUNT Length,
+ OUT PLBN NewStartLbn
+ )
+/*++
+
+Routine Description:
+
+ copies a data run on the volume to a newly allocated location
+
+Arguments:
+
+ StartLbn -- supplies first lbn of the run
+ Length -- supplies sectors in the run
+ *NewStartLbn -- receives new location of run
+
+Return Value:
+
+ TRUE if successful.
+
+Notes:
+
+ This method requires that _Bitmap be properly initialized; if
+ _HotfixList is NULL, hotfix references will not be used.
+
+--*/
+{
+ HOTFIX_SECRUN DataRun;
+ HMEM DataBuffer;
+
+
+ // First, we initialize the memory and secrun objects, and
+ // read the run. Then we allocate new space from the bitmap,
+ // relocate the secrun to that new location, and write the data.
+ // If any of these steps fail, we back out and return FALSE.
+
+ if( !DataBuffer.Initialize() ||
+ !DataRun.Initialize( &DataBuffer,
+ _drive,
+ _HotfixList,
+ StartLbn,
+ Length ) ||
+ !DataRun.Read() ) {
+
+ // Couldn't initialize, or the data is unreadable.
+
+ return FALSE;
+ }
+
+ *NewStartLbn = _Bitmap->NearLBN( StartLbn, Length );
+
+ if( *NewStartLbn == 0 ) {
+
+ // Unable to relocate run
+ return FALSE;
+ }
+
+ DataRun.Relocate( *NewStartLbn );
+
+ if( !DataRun.Write() ) {
+
+ // Unable to write to new location.
+
+ _Bitmap->SetFree( *NewStartLbn, Length );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+UHPFS_EXPORT
+BOOLEAN
+HPFS_SA::QueryBadLbns(
+ IN ULONG MaximumBadLbns,
+ OUT PLBN Buffer,
+ OUT PULONG NumberOfBadLbns
+ )
+/*++
+
+Routine Description:
+
+ This method fetches the list of bad sectors for the volume.
+
+Arguments:
+
+ MaximumBadLbns -- supplies the maximum number of LBNs that will
+ fit into the user's buffer.
+ Buffer -- receives the list of bad lbns. May be NULL if
+ MaximumBadLbns is zero.
+ NumberOfBadLbns -- receives the number of bad lbns in the list.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ If the user does not supply a buffer (ie. if MaximumBadLbns is
+ zero and Buffer is NULL), this method will return the number of
+ bad LBNs on disk.
+
+ If the user supplies a buffer which is too small for the list of
+ bad LBNs, this method will fail.
+
+--*/
+{
+
+ // Check to make sure that this is indeed an HPFS volume.
+
+ if( !_SuperBlock.IsValid() ) {
+
+ return FALSE;
+ }
+
+
+ // If the client did not supply a buffer, just return the number
+ // of bad sectors.
+
+ if( Buffer == NULL ) {
+
+ *NumberOfBadLbns = _SuperBlock.QueryBadSectors();
+ return TRUE;
+ }
+
+
+ if( _BadBlockList == NULL &&
+ (_BadBlockList = QueryBadBlockList()) == NULL ) {
+
+ return FALSE;
+ }
+
+ return( _BadBlockList->QueryBadLbns( MaximumBadLbns,
+ Buffer,
+ NumberOfBadLbns ) );
+}
+
+
+UHPFS_EXPORT
+BOOLEAN
+HPFS_SA::TakeCensusAndClear(
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap,
+ IN OUT PHPFS_CENSUS Census
+ )
+/*++
+
+Routine Description:
+
+ This method takes a census of the volume. It also moves file
+ and extended-attribute data which conflict with the Census
+ object's Clear Sectors.
+
+Arguments:
+
+ HpfsOnlyBitmap -- Supplies a bitmap in which disk structures
+ unique to HPFS (ie. everything except file
+ and EA data) is to be marked.
+ Census -- Supplies the recording object for this census.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ FNODE RootFnode;
+ PBITMAPINDIRECT BitmapIndirectBlock = NULL;
+ ULONG LbnsInSuperArea, i, lbn;
+
+ // Mark the superarea sectors in the hpfs-only bitmap.
+ //
+ LbnsInSuperArea = EndOfSuperArea - StartOfSuperArea + 1;
+ HpfsOnlyBitmap->SetAllocated(StartOfSuperArea, LbnsInSuperArea);
+
+ // The census will fail if the volume has hotfixes:
+ //
+ if( _SparesBlock.QueryHotFixCount() != 0 ) {
+
+ Census->SetError( HPFS_CENSUS_HOTFIXES_PRESENT );
+ return FALSE;
+ }
+
+ // Set up the ancillary objects: Bad Block List, Bitmap Indirect
+ // Block, Hotfix List, and Bitmap.
+ //
+ if ( !(_BadBlockList = QueryBadBlockList()) ||
+ !(_HotfixList = QueryHotFixList()) ||
+ !(_Codepage = QueryCodePage() ) ||
+ (_Bitmap = NEW HPFS_BITMAP()) == NULL ||
+ !_Bitmap->Initialize( _drive,
+ _SuperBlock.QueryDirblkMapLbn(),
+ _SuperBlock.QueryDirBandSize(),
+ _SuperBlock.QueryDirBandLbn() ) ||
+ (BitmapIndirectBlock = QueryBitMapInd()) == NULL ) {
+
+ Census->SetError( HPFS_CENSUS_INSUFFICIENT_MEMORY );
+ DELETE( BitmapIndirectBlock );
+ return FALSE;
+ }
+
+
+ // Read the Bitmap Indirect Block and the Bitmap.
+ //
+ if( !BitmapIndirectBlock->Read() ||
+ !_Bitmap->Read( BitmapIndirectBlock ) ) {
+
+ Census->SetError( HPFS_CENSUS_CORRUPT_VOLUME );
+ DELETE( BitmapIndirectBlock );
+ return FALSE;
+ }
+
+ // An HPFS volume may have padding sectors at the end of the
+ // volume--mark these in the hpfs-only bitmap.
+
+ if( _SuperBlock.QuerySectors() < _drive->QuerySectors().GetLowPart() ) {
+
+ HpfsOnlyBitmap->SetAllocated( _SuperBlock.QuerySectors(),
+ _drive->QuerySectors().GetLowPart() -
+ _SuperBlock.QuerySectors() );
+ }
+
+ // Mark the spare dirblks in the hpfs-only bitmap:
+
+ i = 0;
+ while( (lbn = _SparesBlock.QuerySpareDirblkLbn(i)) != 0 ) {
+
+ if( !_Bitmap->CheckUsed( lbn, SectorsPerDirblk ) ) {
+
+ // This spare dirblk is not marked as in use in
+ // the volume bitmap--the volume is corrupt.
+ //
+ Census->SetError( HPFS_CENSUS_CORRUPT_VOLUME );
+ DELETE( BitmapIndirectBlock );
+ return FALSE;
+ }
+
+ HpfsOnlyBitmap->SetAllocated( lbn, SectorsPerDirblk );
+ i += 1;
+ }
+
+
+ // Take the census of the elementary structures:
+ //
+ if( !_BadBlockList->TakeCensus( _Bitmap, HpfsOnlyBitmap ) ||
+ !BitmapIndirectBlock->TakeCensus( _Bitmap, HpfsOnlyBitmap ) ||
+ !_HotfixList->TakeCensus( _Bitmap, HpfsOnlyBitmap ) ||
+ !_Codepage->TakeCensus( _drive,
+ _SparesBlock.QueryCpInfoLbn(),
+ HpfsOnlyBitmap ) ) {
+
+ Census->SetError( HPFS_CENSUS_CORRUPT_VOLUME );
+ DELETE( BitmapIndirectBlock );
+ return FALSE;
+ }
+
+ // Include the dirblk bitmap and the dirblk band in the map of
+ // hpfs-only structures.
+
+ if( _SuperBlock.QueryDirBandSize() % SectorsPerDirblk != 0 ||
+ _SuperBlock.QueryDirBandLbn() % SectorsPerDirblk != 0 ||
+ !_Bitmap->CheckUsed( _SuperBlock.QueryDirblkMapLbn(),
+ SectorsPerBitmap ) ) {
+
+ DebugPrint( "Directory Band Bitmap is corrupt" );
+
+ Census->SetError( HPFS_CENSUS_CORRUPT_VOLUME );
+ DELETE( BitmapIndirectBlock );
+ return FALSE;
+ }
+
+ HpfsOnlyBitmap->SetAllocated( _SuperBlock.QueryDirblkMapLbn(),
+ SectorsPerBitmap );
+
+ HpfsOnlyBitmap->SetAllocated( _SuperBlock.QueryDirBandLbn(),
+ _SuperBlock.QueryDirBandSize() );
+
+
+ // And the sid table:
+
+ if( !_Bitmap->CheckUsed( _SuperBlock.QuerySidTableLbn(), 8 ) ) {
+
+ DebugPrint( "SID table is corrupt" );
+
+ Census->SetError( HPFS_CENSUS_CORRUPT_VOLUME );
+ DELETE( BitmapIndirectBlock );
+ return FALSE;
+ }
+
+ HpfsOnlyBitmap->SetAllocated( _SuperBlock.QuerySidTableLbn(), 8 );
+
+
+
+ // Set up and read the root FNode.
+
+ if( !RootFnode.Initialize( _drive, _SuperBlock.QueryRootFnodeLbn() ) ) {
+
+ Census->SetError( HPFS_CENSUS_INSUFFICIENT_MEMORY );
+ DELETE( BitmapIndirectBlock );
+ return FALSE;
+ }
+
+
+ if( !RootFnode.Read() ||
+ !RootFnode.IsFnode() ) {
+
+ Census->SetError( HPFS_CENSUS_CORRUPT_VOLUME );
+ DELETE( BitmapIndirectBlock );
+ return FALSE;
+ }
+
+
+ // Take the census of the root FNode:
+
+ if( !RootFnode.TakeCensusAndClear( TRUE,
+ _Bitmap,
+ HpfsOnlyBitmap,
+ Census ) ) {
+
+ // The census failed--the error is already set in the
+ // Census object.
+
+ DELETE( BitmapIndirectBlock );
+ return FALSE;
+ }
+
+
+ // If the Census caused data to be relocated, I have to write the
+ // bitmap. If this write fails, then I've put the volume into a
+ // corrupt state (which, however, is easily fixed by Chkdsk).
+
+ if( Census->QueryRelocationPerformed() &&
+ !_Bitmap->Write( BitmapIndirectBlock ) ) {
+
+ Census->SetError( HPFS_CENSUS_CORRUPT_VOLUME );
+ DELETE( BitmapIndirectBlock );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+HPFS_SA::CreateBootSector(
+ )
+/*++
+
+Routine Description:
+
+ This routine updates fields in sector 0 which must be set by both
+ FAT and HPFS formats.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+#if defined( _SETUP_LOADER_ )
+
+ return FALSE;
+
+#else
+
+ SetVolId(ComputeVolId());
+
+ return SetBpb() &&
+ SetBootCode() &&
+ SetPhysicalDriveType(_drive->IsRemovable() ? PHYS_REMOVABLE :
+ PHYS_FIXED) &&
+ SetOemData() &&
+ SetSignature();
+#endif // _SETUP_LOADER_
+}
+
+BOOLEAN
+HPFS_SA::SetLabel(
+ IN PCWSTRING NewLabel
+ )
+/*++
+
+Routine Description:
+
+ This routine set the volume label in the boot sector.
+
+Arguments:
+
+ NewLabel - Supplies a null-terminated volume label.
+
+Return Value:
+
+ FALSE - The string was an invalid label.
+ TRUE - Success.
+
+--*/
+{
+ INT i;
+ STR buf[80];
+
+ if ( (NewLabel->QuerySTR(0, TO_END, buf, 80) == NULL) ||
+ (i = strlen(buf)) > 11) {
+ return FALSE;
+ }
+
+ if (!IsValidString(NewLabel)) {
+ return FALSE;
+ }
+
+ memset(&_sector_zero.Label[i], 0, 11 - i);
+ memcpy(_sector_zero.Label, buf, i);
+ return TRUE;
+}
+
+BOOLEAN
+HPFS_SA::SetBootCode(
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the boot code in the super area.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ _sector_zero.IntelNearJumpCommand = 0xEB;
+ _sector_zero.BootStrapJumpOffset = 0x903C;
+ SetBootSignature();
+ return TRUE;
+}
+
+BOOLEAN
+HPFS_SA::SetPhysicalDriveType(
+ IN PHYSTYPE PhysType
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the physical drive type in the super area.
+
+Arguments:
+
+ PhysType - Supplies the physical drive type.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ _sector_zero.PhysicalDrive = (UCHAR)PhysType;
+ return TRUE;
+}
+
+BOOLEAN
+HPFS_SA::SetSignature(
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the sector zero signature in the super area.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ if (!_sector_sig) {
+ perrstk->push(ERR_NOT_INIT, QueryClassId());
+ return FALSE;
+ }
+
+ *_sector_sig = sigSUPERSEC1;
+ *(_sector_sig + 1) = sigSUPERSEC2;
+
+ return TRUE;
+}
+
+BOOLEAN
+HPFS_SA::IsValidString(
+ IN PCWSTRING String
+ )
+/*++
+
+Routine Description:
+
+ This routine determines whether or not the given null-terminated string
+ has any invalid characters in it.
+
+Arguments:
+
+ String - Supplies the string to validate.
+
+Return Value:
+
+ FALSE - The string contains invalid characters.
+ TRUE - The string is free from invalid characters.
+
+Notes:
+
+ The list of invalid characters is stricter than HPFS requires.
+
+--*/
+{
+ CHNUM i, l;
+
+ l = String->QueryChCount();
+
+ for (i = 0; i < l; i++) {
+ if (String->QueryChAt(i) < 32) {
+ return FALSE;
+ }
+
+ switch (String->QueryChAt(i)) {
+ case '*':
+ case '?':
+ case '/':
+ case '\\':
+ case '|':
+ case ',':
+ case ';':
+ case ':':
+ case '+':
+ case '=':
+ case '<':
+ case '>':
+ case '[':
+ case ']':
+ case '"':
+ case '.':
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/uhpfs/src/hpfsvol.cxx b/private/utils/uhpfs/src/hpfsvol.cxx
new file mode 100644
index 000000000..65fbae39a
--- /dev/null
+++ b/private/utils/uhpfs/src/hpfsvol.cxx
@@ -0,0 +1,252 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "error.hxx"
+#include "hpfsvol.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( HPFS_VOL, VOL_LIODPDRV, UHPFS_EXPORT );
+
+
+VOID
+HPFS_VOL::Construct(
+ )
+/*++
+
+Routine Description:
+
+ Constructor for HPFS_VOL.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ // unreferenced parameters
+ (void)(this);
+}
+
+
+UHPFS_EXPORT
+HPFS_VOL::~HPFS_VOL(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for HPFS_VOL.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+UHPFS_EXPORT
+BOOLEAN
+HPFS_VOL::Initialize(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN ExclusiveWrite,
+ IN BOOLEAN FormatMedia,
+ IN MEDIA_TYPE MediaType
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes a HPFS_VOL object.
+
+Arguments:
+
+ NtDriveName - Supplies the drive path for the volume.
+ Message - Supplies an outlet for messages.
+ ExclusiveWrite - Supplies whether or not the drive should be
+ opened for exclusive write.
+ FormatMedia - Supplies whether or not to format the media.
+ MediaType - Supplies the type of media to format to.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ MESSAGE msg;
+
+ Destroy();
+
+ if (!VOL_LIODPDRV::Initialize(NtDriveName, &_hpfssa, Message,
+ ExclusiveWrite, FormatMedia, MediaType)) {
+ return FALSE;
+ }
+
+ if (!Message) {
+ Message = &msg;
+ }
+
+ if (!_hpfssa.Initialize(this, Message)) {
+ return FALSE;
+ }
+
+ if (!FormatMedia && !_hpfssa.Read()) {
+ Message->Set(MSG_CANT_READ_HPFS_ROOT);
+ Message->Display("");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+ULONG
+HPFS_VOL::QuerySectorSize(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of bytes per sector.
+ In the case where the actual number of bytes per sector is
+ less than 512, this routine will return 512 anyway so
+ that we can fake it on Japanese drives.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of bytes per sector.
+
+--*/
+{
+ return max(512, VOL_LIODPDRV::QuerySectorSize());
+}
+
+
+BIG_INT
+HPFS_VOL::QuerySectors(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number sectors on the disk. This does not
+ include the hidden sectors.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of sectors on the disk.
+
+--*/
+{
+ ULONG cluster_factor;
+
+ cluster_factor = 512/VOL_LIODPDRV::QuerySectorSize();
+
+ if (!cluster_factor) {
+ return VOL_LIODPDRV::QuerySectors();
+ }
+
+ return VOL_LIODPDRV::QuerySectors()/cluster_factor;
+}
+
+
+PVOL_LIODPDRV
+HPFS_VOL::QueryDupVolume(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN ExclusiveWrite,
+ IN BOOLEAN FormatMedia,
+ IN MEDIA_TYPE MediaType
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine allocates an HPFS_VOL and initializes it to 'NtDriveName'.
+
+Arguments:
+
+ NtDriveName - Supplies the drive path for the volume.
+ Message - Supplies an outlet for messages.
+ ExclusiveWrite - Supplies whether or not the drive should be
+ opened for exclusive write.
+ FormatMedia - Supplies whether or not to format the media.
+ MediaType - Supplies the type of media to format to.
+
+Return Value:
+
+ A pointer to a newly allocated HPFS volume.
+
+--*/
+{
+ PHPFS_VOL vol;
+
+ // unreferenced parameters
+ (void)(this);
+
+ if (!(vol = NEW HPFS_VOL)) {
+ Message ? Message->Set(MSG_FMT_NO_MEMORY) : 1;
+ Message ? Message->Display("") : 1;
+ return NULL;
+ }
+
+ if (!vol->Initialize(NtDriveName, Message, ExclusiveWrite,
+ FormatMedia, MediaType)) {
+ DELETE(vol);
+ return NULL;
+ }
+
+ return vol;
+}
+
+
+VOID
+HPFS_VOL::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a HPFS_VOL object to its initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ // unreferenced parameters
+ (void)(this);
+}
diff --git a/private/utils/uhpfs/src/makefile b/private/utils/uhpfs/src/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/uhpfs/src/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/uhpfs/src/makefile.inc b/private/utils/uhpfs/src/makefile.inc
new file mode 100644
index 000000000..b1477410c
--- /dev/null
+++ b/private/utils/uhpfs/src/makefile.inc
@@ -0,0 +1,14 @@
+{}.cxx{obj\i386\}.obj:
+ $(386_COMPILER) -Fo$@ $(MAKEDIR)\$(<F)
+
+{}.cxx{obj\mips\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClMips $< " $(C_COMPILER) "
+ @$(C_COMPILER) -Fo$@ $(MAKEDIR)\$<
+
+{}.cxx{obj\alpha\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClAlpha $< " $(ALPHA_COMPILER) "
+ @$(ALPHA_COMPILER) -Fo$@ $(MAKEDIR)\$<
+
+dummy:
diff --git a/private/utils/uhpfs/src/orphan.cxx b/private/utils/uhpfs/src/orphan.cxx
new file mode 100644
index 000000000..03bfe718a
--- /dev/null
+++ b/private/utils/uhpfs/src/orphan.cxx
@@ -0,0 +1,1492 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "ifssys.hxx"
+#include "uhpfs.hxx"
+#include "alsec.hxx"
+#include "badblk.hxx"
+#include "bitmap.hxx"
+#include "cpinfo.hxx"
+#include "defer.hxx"
+#include "dirblk.hxx"
+#include "dircache.hxx"
+#include "dirtree.hxx"
+#include "error.hxx"
+#include "fnode.hxx"
+#include "hotfix.hxx"
+#include "hpfsname.hxx"
+#include "hpfssa.hxx"
+#include "orphan.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+
+extern "C" {
+ #include <stdio.h>
+}
+
+
+// METHODS ON HPFS_ORPHANS
+
+DEFINE_CONSTRUCTOR( HPFS_ORPHANS, OBJECT );
+
+VOID
+HPFS_ORPHANS::Construct (
+ )
+
+{
+ // unreferenced parameters
+ (void)(this);
+}
+
+HPFS_ORPHANS::~HPFS_ORPHANS(
+ )
+{
+ Destroy();
+}
+
+BOOLEAN
+HPFS_ORPHANS::Initialize(
+ )
+{
+ Destroy();
+
+ if( !_ListHead.Initialize() ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ _ListHead._Next = &_ListHead;
+ _ListHead._Previous = &_ListHead;
+
+ return TRUE;
+}
+
+VOID
+HPFS_ORPHANS::Destroy(
+ )
+{
+ // unreferenced parameters
+ (void)(this);
+}
+
+
+BOOLEAN
+HPFS_ORPHANS::RecoverOrphan(
+ PLOG_IO_DP_DRIVE Drive,
+ HPFS_SA* SuperArea,
+ DEFERRED_ACTIONS_LIST* DeferredActionsList,
+ LBN OrphanLbn,
+ PSECRUN OrphanSecrun,
+ BOOLEAN UpdateAllowed
+ )
+/*++
+
+Routine Description:
+
+ Recover a potential orphan
+
+Arguments:
+
+ Drive Drive on which the orphans reside
+ SuperArea Superarea for the drive
+ DeferredActionsList List of deferred actions for this pass of CHKDSK
+ OrphanLbn Lbn of the potential orphan
+ OrphanSecrun SECRUN object to hold orphan lbn
+ UpdateAllowed TRUE if we have write permission
+
+Return Value:
+
+ TRUE if no error
+
+Notes:
+
+ If the orphan is recovered successfully, it is added to the
+ orphans list, which then has the responsibility for deleting
+ it. If it is not recovered successfully, then this method
+ will delete the unsuccessful orphan object.
+
+--*/
+{
+ HPFS_ORPHAN_DIRBLK* OrphanDirblk;
+ HPFS_ORPHAN_FNODE* OrphanFnode;
+ HPFS_ORPHAN_ALSEC* OrphanAlsec;
+ _FNODE* OrphanData;
+
+ OrphanSecrun->Relocate( OrphanLbn );
+
+ if( OrphanSecrun->Read() ) {
+
+ OrphanData = (_FNODE*)( OrphanSecrun->GetBuf() );
+
+ switch ( OrphanData->_fni.sig ) {
+
+ case FnodeSignature:
+
+ if( (OrphanFnode = NEW HPFS_ORPHAN_FNODE) == NULL ||
+ !OrphanFnode->Initialize( Drive,
+ OrphanLbn,
+ OrphanData->_fni.bFlag &
+ FNF_DIR ) ) {
+
+ DELETE( OrphanFnode );
+ return FALSE;
+ }
+
+ if( OrphanFnode->RecoverOrphan( SuperArea,
+ DeferredActionsList,
+ this,
+ UpdateAllowed ) ) {
+
+ DebugPrintf( "Orphan FNode recovered at lbn %lx\n", OrphanLbn );
+ AddOrphan( OrphanFnode );
+
+ } else {
+
+ DELETE( OrphanFnode );
+ }
+
+ break;
+
+ case DirblkSignature :
+
+ if( (OrphanDirblk = NEW HPFS_ORPHAN_DIRBLK) == NULL ||
+ !OrphanDirblk->Initialize( Drive,
+ SuperArea->GetHotfixList(),
+ OrphanLbn ) ) {
+
+ DELETE( OrphanDirblk );
+ return FALSE;
+ }
+
+ if( OrphanDirblk->RecoverOrphan( SuperArea,
+ DeferredActionsList,
+ this,
+ UpdateAllowed ) ) {
+
+ DebugPrintf( "Orphan Dirblk recovered at lbn %lx\n", OrphanLbn );
+ AddOrphan( OrphanDirblk );
+
+ } else {
+
+ DELETE( OrphanDirblk );
+ }
+
+ break;
+
+ case AlsecSignature :
+
+ // don't recover isolated allocation blocks.
+ //
+ break;
+
+ default :
+
+ // do nothing.
+ break;
+ }
+
+ } else {
+
+ // It's unreadable--add it to the bad block list.
+
+ SuperArea->GetBitmap()->SetAllocated( OrphanLbn );
+ SuperArea->GetBadBlockList()->Add( OrphanLbn );
+ }
+
+ return TRUE;
+}
+
+
+VOID
+HPFS_ORPHANS::AddOrphan(
+ HPFS_ORPHAN* NewOrphan
+ )
+/*++
+
+Routine Description:
+
+ Adds an orphan to the list of orphans available to be claimed.
+
+Arguments:
+
+ NewOrphan -- the orphan to add to the list
+
+--*/
+{
+ NewOrphan->_Next = _ListHead._Next;
+ NewOrphan->_Previous = &_ListHead;
+
+ _ListHead._Next->_Previous = NewOrphan;
+ _ListHead._Next = NewOrphan;
+}
+
+
+HPFS_ORPHAN*
+HPFS_ORPHANS::RemoveNextOrphan(
+ )
+/*++
+
+Routine Description:
+
+ Removes an orphan from the list and returns it to the caller.
+ The order in which orphans are removed from the list is not
+ significant.
+
+Return Value:
+
+ Pointer to an orphan, if one (other than the place-holding list
+ head) is available; otherwise, NULL.
+
+--*/
+{
+ HPFS_ORPHAN* Returnee;
+
+ Returnee = _ListHead._Next;
+
+ if( Returnee == &_ListHead ) {
+
+ return NULL;
+
+ } else {
+
+ Returnee->Detach();
+ return Returnee;
+ }
+}
+
+
+BOOLEAN
+HPFS_ORPHANS::LookupFnode(
+ IN LBN DesiredLbn,
+ IN BOOLEAN fIsDir,
+ IN LBN ParentLbn,
+ IN OUT PULONG DirentFileSize,
+ OUT PULONG EaSize,
+ BOOLEAN UpdateAllowed
+ )
+/*++
+--*/
+{
+ HPFS_ORPHAN* CurrentOrphan;
+
+ CurrentOrphan = _ListHead._Next;
+
+ while( CurrentOrphan != &_ListHead ) {
+
+ if( CurrentOrphan->LookupFnode( DesiredLbn,
+ fIsDir,
+ ParentLbn,
+ DirentFileSize,
+ EaSize,
+ UpdateAllowed ) ) {
+
+ return TRUE;
+ }
+
+ CurrentOrphan = CurrentOrphan->_Next;
+ }
+
+ return FALSE;
+}
+
+
+BOOLEAN
+HPFS_ORPHANS::LookupDirblk(
+ IN LBN DesiredLbn,
+ IN LBN ParentLbn,
+ IN LBN ParentFnodeLbn,
+ BOOLEAN UpdateAllowed
+ )
+/*++
+--*/
+{
+ HPFS_ORPHAN* CurrentOrphan;
+
+ CurrentOrphan = _ListHead._Next;
+
+ while( CurrentOrphan != &_ListHead ) {
+
+ if( CurrentOrphan->LookupDirblk( DesiredLbn,
+ ParentLbn,
+ ParentFnodeLbn,
+ UpdateAllowed ) ) {
+
+ return TRUE;
+ }
+
+ CurrentOrphan = CurrentOrphan->_Next;
+ }
+
+ return FALSE;
+}
+
+
+BOOLEAN
+HPFS_ORPHANS::LookupAlsec(
+ IN LBN DesiredLbn,
+ IN LBN ParentLbn,
+ IN OUT PULONG NextSectorNumber,
+ IN BOOLEAN UpdateAllowed,
+ IN BOOLEAN ParentIsFnode
+ )
+/*++
+
+Routine Description:
+
+ Scans the orphan list for an orphaned Alsec with the specified lbn
+
+Arguments:
+
+ DesiredLbn -- lbn of the Alsec we want
+
+ ParentLbn -- lbn of the parent structure
+
+ NextSectorNumber -- supplies the expected next logical file
+ lbn; is updated on exit.
+
+ UpdateAllowed -- TRUE if we should write changes to disk
+
+Return Value:
+
+ TRUE if the ALSEC is found.
+
+Notes:
+
+ If the Alsec is found, it will be removed from the orphans list,
+ patched up, and written to disk. The parent need concern itself
+ with the child no longer.
+
+--*/
+{
+ HPFS_ORPHAN* CurrentOrphan;
+
+ CurrentOrphan = _ListHead._Next;
+
+ while( CurrentOrphan != &_ListHead ) {
+
+ if( CurrentOrphan->LookupAlsec( DesiredLbn,
+ ParentLbn,
+ NextSectorNumber,
+ UpdateAllowed,
+ ParentIsFnode ) ) {
+
+ return TRUE;
+ }
+
+ CurrentOrphan = CurrentOrphan->_Next;
+ }
+
+ return FALSE;
+}
+
+
+BOOLEAN
+HPFS_ORPHANS::Save(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT HPFS_SA* SuperArea,
+ IN OUT DIRBLK_CACHE* Cache,
+ IN OUT HPFS_DIRECTORY_TREE* RootTree,
+ IN LBN RootFnodeLbn,
+ PMESSAGE Message
+ )
+{
+ DIRBLK FoundRootDirblk;
+ FNODE FoundRootFnode;
+ HPFS_ORPHAN* CurrentOrphan;
+ HPFS_DIRECTORY_TREE FoundTree;
+ BOOLEAN RetVal = TRUE;
+ BOOLEAN IsDir = FALSE;
+ ULONG FileNumber = 0;
+ ULONG DirectoryNumber = 0;
+ ULONG NameLength;
+ ULONG i;
+ PDIRENTD NewEntry;
+ LBN FoundRootFnodeLbn;
+ LBN FoundRootDirblkLbn;
+ BOOLEAN Inserted, IsBadlyOrdered;
+ ULONG HpfsTime;
+
+ if( _ListHead._Next == &_ListHead ) {
+
+ // Nothing to save.
+
+ return TRUE;
+ }
+
+ // Create a dirent buffer.
+
+ if( (NewEntry = (PDIRENTD)MALLOC( MaximumDirentSize )) == NULL ) {
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_ORPHANS_NO_MEM );
+ Message->Display( "" );
+ }
+
+ return FALSE;
+ }
+
+
+ // Create a FOUND directory in the root
+
+ if( (FoundRootDirblkLbn =
+ SuperArea->GetBitmap()->AllocateDirblk()) == 0 ||
+ (FoundRootFnodeLbn =
+ SuperArea->GetBitmap()->NearLBN(FoundRootDirblkLbn, 1)) == 0 ) {
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_ORPHANS_NO_DISK );
+ Message->Display( "" );
+ }
+
+ FREE( NewEntry );
+ return FALSE;
+ }
+
+
+ if( !FoundRootDirblk.Initialize( Drive,
+ SuperArea->GetHotfixList(),
+ FoundRootDirblkLbn ) ||
+ !FoundRootFnode.Initialize( Drive, FoundRootFnodeLbn ) ) {
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_ORPHANS_NO_MEM );
+ Message->Display( "" );
+ }
+
+ FREE (NewEntry);
+ return FALSE;
+ }
+
+ FoundRootDirblk.CreateRoot( FoundRootFnodeLbn );
+
+ FoundRootFnode.CreateRoot( FoundRootDirblkLbn );
+ FoundRootFnode.SetParent( RootFnodeLbn );
+
+ if( !FoundRootDirblk.Write() ||
+ !FoundRootFnode.Write() ){
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_NO_FOUND_DIR );
+ Message->Display( "%s", NewEntry->bName );
+ }
+
+ return FALSE;
+ }
+
+ // OK, we've created and written to disk a root dirblk and FNode
+ // for the Found directory; now let's make a directory entry for
+ // it and insert it into the root directory.
+
+ memset( NewEntry, '\0', MaximumDirentSize );
+
+ NameLength = 9;
+
+ NewEntry->cchThisEntry = (USHORT)(( LeafEndEntrySize +
+ NameLength - 1 + 3) & ~3);
+ NewEntry->fFlags = 0;
+ NewEntry->fAttr = ATTR_DIRECTORY;
+ NewEntry->lbnFnode = FoundRootFnodeLbn;
+ NewEntry->cchFSize = 5;
+
+ IFS_SYSTEM::QueryHpfsTime( &HpfsTime );
+
+ NewEntry->timLastMod = NewEntry->timLastAccess =
+ NewEntry->timCreate = HpfsTime;
+
+ NewEntry->ulEALen = 0;
+ NewEntry->fFlex = 0;
+ NewEntry->bCodePage = 0;
+ NewEntry->cchName = (UCHAR) NameLength;
+
+ Inserted = FALSE;
+ i = 0;
+
+ while( !Inserted && i <= 999 ) {
+
+ sprintf( (PCHAR)(NewEntry->bName), "FOUND.%03d", i );
+ i += 1;
+
+ Inserted = RootTree->Insert( NewEntry );
+ }
+
+ if( !Inserted ) {
+
+ // Couldn't create an entry in the root directory.
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_NO_FOUND_DIR );
+ Message->Display( "%s", NewEntry->bName );
+ }
+
+ FREE( NewEntry );
+ return FALSE;
+ }
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_FOUND_DIR_NAME );
+ Message->Display( "%s", NewEntry->bName );
+ }
+
+
+ // Now that we've created FOUND.xxx, we can set up a directory
+ // tree object for it.
+
+ if( !FoundTree.Initialize( SuperArea,
+ Cache,
+ FoundRootDirblkLbn,
+ FoundRootFnodeLbn ) ) {
+
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_ORPHANS_NO_MEM );
+ Message->Display( "" );
+ }
+
+ FREE( NewEntry );
+ return FALSE;
+ }
+
+ // Go around the list of orphans, adding a directory
+ // entry to FoundTree for each orphan we can save.
+
+ CurrentOrphan = _ListHead._Next;
+
+ while( CurrentOrphan != &_ListHead ) {
+
+ memset( NewEntry, '\0', MaximumDirentSize );
+
+ if( CurrentOrphan->Save( Drive,
+ SuperArea,
+ NewEntry,
+ FoundRootFnodeLbn,
+ &IsDir ) ) {
+
+ // The orphan fills in lbnFnode, cchFSize, and ulEALen;
+ // we fill in the rest.
+
+ NameLength = ( IsDir ? 11 : 12 );
+
+ NewEntry->cchThisEntry = (USHORT)(( LeafEndEntrySize +
+ NameLength - 1 + 3) & ~3);
+ NewEntry->fFlags = 0;
+ NewEntry->fAttr = (BYTE)( IsDir ? ATTR_DIRECTORY : 0 );
+
+ IFS_SYSTEM::QueryHpfsTime( &HpfsTime );
+
+ NewEntry->timLastMod = NewEntry->timLastAccess =
+ NewEntry->timCreate = HpfsTime;
+
+ NewEntry->fFlex = 0;
+ NewEntry->bCodePage = 0;
+ NewEntry->cchName = (UCHAR)NameLength;
+
+ Inserted = FALSE;
+
+ if( IsDir ) {
+
+ while( !Inserted && DirectoryNumber <= 999 ) {
+
+ sprintf( (PCHAR)NewEntry->bName,
+ "DIR%04d.CHK",
+ DirectoryNumber );
+
+ DirectoryNumber += 1;
+
+ Inserted = FoundTree.Insert( NewEntry );
+ }
+
+ if( !Inserted ) {
+
+ RetVal = FALSE;
+ }
+
+ if( Message != NULL && Inserted ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_RECOVERED_DIRECTORY );
+ Message->Display( "%s", NewEntry->bName );
+ }
+
+ } else {
+
+ while( !Inserted && FileNumber <= 999 ) {
+
+ sprintf( (PCHAR)NewEntry->bName,
+ "FILE%04d.CHK",
+ FileNumber );
+
+ FileNumber += 1;
+
+ Inserted = FoundTree.Insert( NewEntry );
+ }
+
+ if( !Inserted ) {
+
+ RetVal = FALSE;
+ }
+
+ if( Message != NULL && Inserted ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_RECOVERED_FILE );
+ Message->Display( "%s", NewEntry->bName );
+ }
+ }
+
+
+ } else {
+
+ RetVal = FALSE;
+ }
+
+ CurrentOrphan = CurrentOrphan->_Next;
+ }
+
+ if( !RetVal && Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_ORPHANS_CANT_SAVE );
+ Message->Display( "" );
+ }
+
+
+ // Now check that the lost-and-found directory is
+ // well-ordered.
+
+ IsBadlyOrdered = FALSE;
+
+ if( FoundTree.CheckOrder( Drive, &IsBadlyOrdered ) ) {
+
+ if( IsBadlyOrdered ) {
+
+ FoundTree.Sort();
+ FoundRootFnode.SetRootDirblkLbn(
+ FoundTree.QueryRootDirblkLbn() );
+
+ FoundRootFnode.Write();
+ }
+
+ } else {
+
+ if( Message != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_ORPHANS_CONSISTENCY );
+ Message->Display( "" );
+ }
+
+ RetVal = FALSE;
+ }
+
+ // Make sure that the FNode for this newly-created directory
+ // still points at the root dirblk.
+
+ if( FoundTree.QueryRootDirblkLbn() !=
+ FoundRootFnode.QueryRootDirblkLbn() ) {
+
+ // We must have split the root while inserting orphans;
+ // update the FNode.
+
+ FoundRootFnode.SetRootDirblkLbn( FoundTree.QueryRootDirblkLbn() );
+ FoundRootFnode.Write();
+ }
+
+
+ return RetVal;
+}
+
+
+BOOLEAN
+HPFS_ORPHANS::QueryOrphansFound(
+ )
+/*++
+
+Routine Description:
+
+ Tell whether there are any orphans in the list
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the list is not empty.
+
+--*/
+{
+ return( _ListHead._Next != &_ListHead );
+}
+
+
+// METHODS ON HPFS_ORPHAN
+
+DEFINE_CONSTRUCTOR( HPFS_ORPHAN, OBJECT );
+
+VOID
+HPFS_ORPHAN::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Construct an HPFS_ORPHAN object. Sets private data
+ to harmless values.
+
+--*/
+{
+ _Next = NULL;
+ _Previous = NULL;
+}
+
+
+HPFS_ORPHAN::~HPFS_ORPHAN()
+{
+ Destroy();
+}
+
+
+BOOLEAN
+HPFS_ORPHAN::Initialize(
+ )
+/*++
+
+Routine Description:
+
+ Initialize an HPFS_ORPHAN object.
+
+Return Value:
+
+ TRUE on successful completion
+
+--*/
+{
+ Destroy();
+ return TRUE;
+}
+
+
+
+VOID
+HPFS_ORPHAN::Destroy()
+/*++
+
+Routine Description:
+
+ Cleans up the object, in preparation for deletion or
+ reinitialization.
+
+--*/
+{
+ _Next = NULL;
+ _Previous = NULL;
+}
+
+
+VOID
+HPFS_ORPHAN::Detach()
+/*++
+
+Routine Description:
+
+ Removes the orphan from the list of orphans.
+
+--*/
+{
+ if( _Next != NULL && _Previous != NULL ) {
+
+ _Next->_Previous = _Previous;
+ _Previous->_Next = _Next;
+ }
+
+ _Next = NULL;
+ _Previous = NULL;
+}
+
+BOOLEAN
+HPFS_ORPHAN::LookupFnode(
+ IN LBN DesiredLbn,
+ IN BOOLEAN fIsDir,
+ IN LBN ParentLbn,
+ IN OUT PULONG DirentFileSize,
+ OUT PULONG EaSize,
+ BOOLEAN UpdateAllowed
+ )
+{
+ // unreferenced parameters
+ (void)(this);
+ (void)(DesiredLbn);
+ (void)(fIsDir);
+ (void)(ParentLbn);
+ (void)(DirentFileSize);
+ (void)(EaSize);
+ (void)(UpdateAllowed);
+
+ return FALSE;
+}
+
+BOOLEAN
+HPFS_ORPHAN::LookupDirblk(
+ IN LBN DesiredLbn,
+ IN LBN ParentLbn,
+ IN LBN ParentFnodeLbn,
+ BOOLEAN UpdateAllowed
+ )
+{
+ // unreferenced parameters
+ (void)(this);
+ (void)(DesiredLbn);
+ (void)(ParentLbn);
+ (void)(ParentFnodeLbn);
+ (void)(UpdateAllowed);
+
+ return FALSE;
+}
+
+BOOLEAN
+HPFS_ORPHAN::LookupAlsec(
+ IN LBN DesiredLbn,
+ IN LBN ParentLbn,
+ IN OUT PULONG NextSectorNumber,
+ IN BOOLEAN UpdateAllowed,
+ IN BOOLEAN ParentIsFnode
+ )
+{
+ // unreferenced parameters
+ (void)(this);
+ (void)(DesiredLbn);
+ (void)(ParentLbn);
+ (void)(NextSectorNumber);
+ (void)(UpdateAllowed);
+ (void)(ParentIsFnode);
+
+ return FALSE;
+}
+
+BOOLEAN
+HPFS_ORPHAN::Save(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT HPFS_SA* SuperArea,
+ IN OUT PDIRENTD NewEntry,
+ IN LBN FoundTreeFnodeLbn,
+ OUT BOOLEAN* IsDir
+ )
+{
+ // unreferenced parameters
+ (void)(this);
+ (void)(Drive);
+ (void)(SuperArea);
+ (void)(NewEntry);
+ (void)(FoundTreeFnodeLbn);
+ (void)(IsDir);
+
+ return TRUE;
+}
+
+
+// METHODS ON HPFS_ORPHAN_LIST_HEAD
+
+DEFINE_CONSTRUCTOR( HPFS_ORPHAN_LIST_HEAD, HPFS_ORPHAN );
+
+VOID
+HPFS_ORPHAN_LIST_HEAD::Construct (
+ )
+{
+ // unreferenced parameters
+ (void)(this);
+}
+
+HPFS_ORPHAN_LIST_HEAD::~HPFS_ORPHAN_LIST_HEAD(
+ )
+{
+ // unreferenced parameters
+ (void)(this);
+}
+
+BOOLEAN
+HPFS_ORPHAN_LIST_HEAD::Initialize(
+ )
+{
+ if( !HPFS_ORPHAN::Initialize() ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+VOID
+HPFS_ORPHAN_LIST_HEAD::Destroy(
+ )
+{
+ // unreferenced parameters
+ (void)(this);
+}
+
+
+// METHODS ON HPFS_ORPHAN_DIRBLK
+
+
+DEFINE_CONSTRUCTOR( HPFS_ORPHAN_DIRBLK, HPFS_ORPHAN );
+
+VOID
+HPFS_ORPHAN_DIRBLK::Construct (
+ )
+
+{
+ // unreferenced parameters
+ (void)(this);
+}
+
+HPFS_ORPHAN_DIRBLK::~HPFS_ORPHAN_DIRBLK()
+{
+ Destroy();
+}
+
+BOOLEAN
+HPFS_ORPHAN_DIRBLK::Initialize(
+ PLOG_IO_DP_DRIVE Drive,
+ IN PHOTFIXLIST HotfixList,
+ LBN lbn
+ )
+/*++
+
+Routine Description:
+
+ Initializes the HPFS_ORPHAN_DIRBLK object.
+
+Arguments:
+
+ Drive -- drive on which the orphan resides
+
+ HotfixList -- hotfix list for that drive (possibly NULL)
+
+ lbn -- first lbn of the dirblk
+
+Return Value:
+
+ TRUE on successful completion
+
+--*/
+{
+ Destroy();
+
+ return( HPFS_ORPHAN::Initialize() &&
+ _Dirblk.Initialize( Drive, HotfixList, lbn ) );
+}
+
+VOID
+HPFS_ORPHAN_DIRBLK::Destroy(
+ )
+{
+ // unreferenced parameters
+ (void)(this);
+}
+
+
+BOOLEAN
+HPFS_ORPHAN_DIRBLK::RecoverOrphan(
+ HPFS_SA* SuperArea,
+ DEFERRED_ACTIONS_LIST* DeferredActionsList,
+ HPFS_ORPHANS* OrphansList,
+ BOOLEAN UpdateAllowed
+ )
+{
+ HPFS_NAME PreviousName;
+ ULONG LeafDepth = 0;
+ BOOLEAN ErrorsDetected = FALSE;
+ VERIFY_RETURN_CODE erc;
+
+ erc = _Dirblk.VerifyAndFix( SuperArea,
+ DeferredActionsList,
+ NULL,
+ &PreviousName,
+ 0,
+ 0,
+ 0,
+ &LeafDepth,
+ NULL,
+ &ErrorsDetected,
+ UpdateAllowed,
+ FALSE,
+ OrphansList );
+
+ if ( erc != VERIFY_STRUCTURE_OK &&
+ erc != VERIFY_STRUCTURE_BADLY_ORDERED ) {
+
+ // Either this dirblk is screwed up, or we ran out of
+ // resources. Either way, we don't want to keep it around.
+
+ return FALSE;
+
+ } else {
+
+ // There's nothing wrong with this orphan except
+ // that it may be out of order.
+
+ return TRUE;
+ }
+}
+
+
+BOOLEAN
+HPFS_ORPHAN_DIRBLK::LookupDirblk(
+ IN LBN DesiredLbn,
+ IN LBN ParentLbn,
+ IN LBN ParentFnodeLbn,
+ BOOLEAN UpdateAllowed
+ )
+{
+ if( _Dirblk.QueryStartLbn() != DesiredLbn ) {
+
+ return FALSE;
+
+ } else {
+
+ // This matches the request, so we delete this orphan from
+ // the list of orphans, update its parent information, and
+ // write it out.
+
+ if( UpdateAllowed ) {
+
+ _Dirblk.SetParents( ParentLbn, ParentFnodeLbn );
+ _Dirblk.Write();
+ }
+
+ Detach();
+ return TRUE;
+ }
+}
+
+
+BOOLEAN
+HPFS_ORPHAN_DIRBLK::Save(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT HPFS_SA* SuperArea,
+ IN OUT PDIRENTD NewEntry,
+ IN LBN FoundTreeFnodeLbn,
+ OUT BOOLEAN* IsDir
+ )
+{
+
+ FNODE Fnode;
+ LBN FnodeLbn;
+
+ // Create an FNode for this baby
+
+ if( (FnodeLbn = SuperArea->GetBitmap()->NearLBN(0, 1)) == 0 ) {
+
+ // Can't allocate Fnode
+
+ return FALSE;
+ }
+
+ if( !Fnode.Initialize( Drive, FnodeLbn ) ||
+ !Fnode.CreateRoot( _Dirblk.QueryStartLbn() ) ) {
+
+ SuperArea->GetBitmap()->SetFree( FnodeLbn, 1 );
+ return FALSE;
+ }
+
+ // Set the dirblk to point at this newly-created Fnode as
+ // its parent. (Note that this will also mark the dirblk
+ // as topmost in its tree.) After that, we're done with
+ // the dirblk, and can write it out.
+
+ _Dirblk.SetParents( FnodeLbn, FnodeLbn );
+ _Dirblk.Write();
+
+ // Update the FNode's lbnContDir field and write it out.
+
+ Fnode.SetParent( FoundTreeFnodeLbn );
+ Fnode.Write();
+
+ // Fill in the fields of the directory entry for
+ // which the orphan is responsible:
+
+ NewEntry->lbnFnode = FnodeLbn;
+ NewEntry->cchFSize = 0;
+ NewEntry->ulEALen = 0;
+
+ *IsDir = TRUE;
+
+ return TRUE;
+}
+
+
+// METHODS ON HPFS_ORPHAN_FNODE
+
+DEFINE_CONSTRUCTOR( HPFS_ORPHAN_FNODE, HPFS_ORPHAN );
+
+VOID
+HPFS_ORPHAN_FNODE::Construct (
+ )
+
+{
+ _Drive = NULL;
+ _IsDir = FALSE;
+ _FileSize = 0;
+ _EaSize = 0;
+}
+
+HPFS_ORPHAN_FNODE::~HPFS_ORPHAN_FNODE(
+ )
+{
+ Destroy();
+}
+
+
+BOOLEAN
+HPFS_ORPHAN_FNODE::Initialize(
+ LOG_IO_DP_DRIVE* Drive,
+ LBN Lbn,
+ BOOLEAN IsDir
+ )
+{
+ Destroy();
+
+ _Drive = Drive;
+ _IsDir = IsDir;
+
+ return( _Fnode.Initialize( Drive, Lbn ) );
+}
+
+
+VOID
+HPFS_ORPHAN_FNODE::Destroy(
+ )
+{
+ _Drive = NULL;
+ _IsDir = FALSE;
+ _FileSize = 0;
+ _EaSize = 0;
+}
+
+
+BOOLEAN
+HPFS_ORPHAN_FNODE::RecoverOrphan(
+ HPFS_SA* SuperArea,
+ DEFERRED_ACTIONS_LIST* DeferredActionsList,
+ HPFS_ORPHANS* OrphansList,
+ BOOLEAN UpdateAllowed
+ )
+{
+ BOOLEAN ErrorsDetected = FALSE;
+ VERIFY_RETURN_CODE erc;
+
+ HPFS_NAME PreviousName;
+
+ erc = _Fnode.VerifyAndFix( SuperArea,
+ DeferredActionsList,
+ NULL,
+ 0,
+ _IsDir,
+ &_FileSize,
+ &_EaSize,
+ NULL,
+ &ErrorsDetected,
+ UpdateAllowed,
+ FALSE,
+ OrphansList );
+
+ if ( erc != VERIFY_STRUCTURE_OK ) {
+
+ // Either this fnode is screwed up, or we ran out of
+ // resources. Either way, we don't want to keep it around.
+
+ return FALSE;
+
+ } else {
+
+ // It's a keeper
+ return TRUE;
+ }
+}
+
+
+BOOLEAN
+HPFS_ORPHAN_FNODE::LookupFnode(
+ IN LBN DesiredLbn,
+ IN BOOLEAN fIsDir,
+ IN LBN ParentLbn,
+ IN OUT PULONG DirentFileSize,
+ OUT PULONG EaSize,
+ BOOLEAN UpdateAllowed
+ )
+{
+ ULONG SectorSize;
+
+ if( _Fnode.QueryStartLbn() != DesiredLbn ||
+ (!fIsDir && _IsDir) ||
+ (fIsDir && !_IsDir) ) {
+
+ return FALSE;
+
+ } else {
+
+ // This matches the request, so we delete this orphan from
+ // the list of orphans, update its parent information, and
+ // write it out.
+
+ if( UpdateAllowed ) {
+
+ _Fnode.SetParent( ParentLbn );
+ _Fnode.Write();
+ }
+
+ Detach();
+
+ // _FileSize is the allocated size of the file
+
+ SectorSize = _Drive->QuerySectorSize();
+
+ if( !_IsDir &&
+ ( *DirentFileSize > _FileSize ||
+ *DirentFileSize + SectorSize - 1 < _FileSize ) ) {
+
+ // The directory entry's file size doesn't agree with
+ // the allocation. Since this is an orphan, we'll recover
+ // all the allocated space into the file.
+
+ *DirentFileSize = _FileSize;
+ }
+
+ *EaSize = _EaSize;
+ return TRUE;
+ }
+}
+
+
+BOOLEAN
+HPFS_ORPHAN_FNODE::Save(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT HPFS_SA* SuperArea,
+ IN OUT PDIRENTD NewEntry,
+ IN LBN FoundTreeFnodeLbn,
+ OUT BOOLEAN* IsDir
+ )
+/*++
+
+Routine Description:
+
+ Save the orphan FNode in the found directory.
+
+Arguments:
+
+ Drive -- Drive on which the FNode resides
+
+ SuperArea -- superarea for the drive
+
+ NewEntry -- points to directory entry orphan should fill in
+
+ FoundTreeFnodeLbn -- LBN of the Found directory's FNode
+
+
+Return Value:
+
+ TRUE on successful completion.
+
+--*/
+{
+
+ // unreferenced parameters
+ (void)(Drive);
+ (void)(SuperArea);
+
+ // FNodes are easy, since we don't have to create any
+ // additional structures. Just fill in the fields
+ // of the directory entry which are the orphan's responsibility.
+
+ NewEntry->lbnFnode = _Fnode.QueryStartLbn();
+ NewEntry->cchFSize = _FileSize;
+ NewEntry->ulEALen = _EaSize;
+
+ // Update the FNode's lbnContDir field and write it out.
+
+ _Fnode.SetParent( FoundTreeFnodeLbn );
+ _Fnode.Write();
+
+ *IsDir = _IsDir;
+
+ return TRUE;
+}
+
+
+// METHODS ON HPFS_ORPHAN_ALSEC
+
+DEFINE_CONSTRUCTOR( HPFS_ORPHAN_ALSEC, HPFS_ORPHAN );
+
+VOID
+HPFS_ORPHAN_ALSEC::Construct (
+ )
+
+{
+ // unreferenced parameters
+ (void)(this);
+}
+
+HPFS_ORPHAN_ALSEC::~HPFS_ORPHAN_ALSEC()
+{
+ Destroy();
+}
+
+
+BOOLEAN
+HPFS_ORPHAN_ALSEC::Initialize(
+ LOG_IO_DP_DRIVE* Drive,
+ LBN Lbn
+ )
+{
+ return ( HPFS_ORPHAN::Initialize() &&
+ _Alsec.Initialize( Drive, Lbn ) );
+}
+
+VOID
+HPFS_ORPHAN_ALSEC::Destroy(
+ )
+{
+ // unreferenced parameters
+ (void)(this);
+}
+
+BOOLEAN
+HPFS_ORPHAN_ALSEC::RecoverOrphan(
+ HPFS_SA* SuperArea,
+ DEFERRED_ACTIONS_LIST* DeferredActionsList,
+ HPFS_ORPHANS* OrphansList,
+ BOOLEAN UpdateAllowed
+ )
+{
+ BOOLEAN ErrorsDetected = FALSE;
+ VERIFY_RETURN_CODE erc;
+
+ _NextSectorNumber = 0;
+
+ erc = _Alsec.VerifyAndFix( SuperArea,
+ DeferredActionsList,
+ NULL,
+ 0,
+ &_NextSectorNumber,
+ NULL,
+ &ErrorsDetected,
+ UpdateAllowed,
+ OrphansList );
+
+ if ( erc != VERIFY_STRUCTURE_OK ) {
+
+ // Either this fnode is screwed up, or we ran out of
+ // resources. Either way, we don't want to keep it around.
+
+ return FALSE;
+
+ } else {
+
+ // It's a keeper
+ return TRUE;
+ }
+}
+
+
+BOOLEAN
+HPFS_ORPHAN_ALSEC::LookupAlsec(
+ IN LBN DesiredLbn,
+ IN LBN ParentLbn,
+ IN OUT PULONG NextSectorNumber,
+ IN BOOLEAN UpdateAllowed,
+ IN BOOLEAN ParentIsFnode
+ )
+{
+ if( _Alsec.QueryStartLbn() != DesiredLbn ) {
+
+ return FALSE;
+
+ } else {
+
+ // This matches the request, so we delete this orphan from
+ // the list of orphans, update its parent information, and
+ // write it out.
+
+ if( UpdateAllowed ) {
+
+ _Alsec.SetParent( ParentLbn, NextSectorNumber, ParentIsFnode );
+ _Alsec.Write();
+ }
+
+ Detach();
+ return TRUE;
+ }
+}
+
+
+BOOLEAN
+HPFS_ORPHAN_ALSEC::Save(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT HPFS_SA* SuperArea,
+ IN OUT PDIRENTD NewEntry,
+ IN LBN FoundTreeFnodeLbn,
+ OUT BOOLEAN* IsDir
+ )
+{
+
+ FNODE Fnode;
+ LBN FnodeLbn;
+ ULONG NextSectorNumber = 0;
+ SECTORCOUNT SectorSize;
+
+
+ SectorSize = Drive->QuerySectorSize();
+
+ // Create an FNode for this baby
+
+ if( (FnodeLbn = SuperArea->GetBitmap()->NearLBN(0, 1)) == 0 ) {
+
+ // Can't allcoate Fnode
+
+ return FALSE;
+ }
+
+
+ // Set the Alsec to point at this newly-created Fnode as
+ // its parent. After that, we're done with the Alsec, and
+ // can write it out. Note that we call SetParent with
+ // ParentIsFnode set to TRUE, since we know that the parent
+ // of this alsec is the FNode we are about to create.
+
+ _Alsec.SetParent( FnodeLbn, &NextSectorNumber, TRUE );
+ _Alsec.Write();
+
+
+ if( !Fnode.Initialize( Drive, FnodeLbn ) ||
+ !Fnode.CreateNode( FoundTreeFnodeLbn,
+ _Alsec.QueryStartLbn(),
+ NextSectorNumber * SectorSize ) ) {
+
+ SuperArea->GetBitmap()->SetFree( FnodeLbn, 1 );
+ return FALSE;
+ }
+
+ // Update the FNode's lbnContDir field and write it out.
+
+ Fnode.SetParent( FoundTreeFnodeLbn );
+ Fnode.Write();
+
+ // Fill in the fields of the directory entry for
+ // which the orphan is responsible:
+
+ NewEntry->lbnFnode = FnodeLbn;
+ NewEntry->cchFSize = _NextSectorNumber * SectorSize;
+ NewEntry->ulEALen = 0;
+
+ *IsDir = FALSE;
+
+ return TRUE;
+}
diff --git a/private/utils/uhpfs/src/pch.cxx b/private/utils/uhpfs/src/pch.cxx
new file mode 100644
index 000000000..3537fa131
--- /dev/null
+++ b/private/utils/uhpfs/src/pch.cxx
@@ -0,0 +1,50 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ pch.cxx
+
+Abstract:
+
+ This module is for the uhpfs precompiled header.
+
+Author:
+
+ Matthew Bradburn (mattbr) 26-Apr-1994
+
+--*/
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "alsec.hxx"
+#include "badblk.hxx"
+#include "bitmap.hxx"
+#include "bmind.hxx"
+#include "cpinfo.hxx"
+#include "defer.hxx"
+#include "dirblk.hxx"
+#include "dircache.hxx"
+#include "dirmap.hxx"
+#include "dirtree.hxx"
+#include "fnode.hxx"
+#include "hfsecrun.hxx"
+#include "hotfix.hxx"
+#include "hpcensus.hxx"
+#include "hpfsacl.hxx"
+#include "hpfsea.hxx"
+#include "hpfseal.hxx"
+#include "hpfsname.hxx"
+#include "hpfssa.hxx"
+#include "hpfsvol.hxx"
+#include "ods.hxx"
+#include "orphan.hxx"
+#include "sid.hxx"
+#include "spareb.hxx"
+#include "store.hxx"
+#include "superb.hxx"
+#include "verify.hxx"
diff --git a/private/utils/uhpfs/src/sid.cxx b/private/utils/uhpfs/src/sid.cxx
new file mode 100644
index 000000000..006d3dbbc
--- /dev/null
+++ b/private/utils/uhpfs/src/sid.cxx
@@ -0,0 +1,142 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "error.hxx"
+#include "sid.hxx"
+
+
+DEFINE_CONSTRUCTOR( SIDTABLE, SECRUN );
+
+VOID
+SIDTABLE::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Constructor for SIDTABLE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _pstd = NULL;
+}
+
+SIDTABLE::~SIDTABLE(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for SIDTABLE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+BOOLEAN
+SIDTABLE::Initialize(
+ IN PLOG_IO_DP_DRIVE Drive,
+ IN LBN Lbn
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes a SIDTABLE.
+
+Arguments:
+
+ Drive - Supplies the drive on which the SIDTABLE should reside.
+ Lbn - Supplies the sector number of the beginning of the table.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ Destroy();
+
+ if (!_hmem.Initialize() ||
+ !SECRUN::Initialize(&_hmem, Drive, Lbn, SECTORS_PER_SID)) {
+ Destroy();
+ return FALSE;
+ }
+
+ _pstd = (SIDTABLED*) GetBuf();
+
+ return TRUE;
+}
+
+
+BOOLEAN
+SIDTABLE::Create(
+ )
+/*++
+
+Routine Description:
+
+ This routine creates a new SIDTABLE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ memset(_hmem.GetBuf(), 0, (UINT) _hmem.QuerySize());
+
+ return TRUE;
+}
+
+
+VOID
+SIDTABLE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a SIDTABLE to its initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _pstd = NULL;
+}
diff --git a/private/utils/uhpfs/src/sources b/private/utils/uhpfs/src/sources
new file mode 100644
index 000000000..687de1482
--- /dev/null
+++ b/private/utils/uhpfs/src/sources
@@ -0,0 +1,98 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in $(BASEDIR)\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=utils
+MINORCOMP=uhpfs
+
+TARGETNAME=uhpfs
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ ..\..\ulib\src\obj\*\ulib.lib \
+ ..\..\ifsutil\src\obj\*\ifsutil.lib
+
+USE_CRTDLL=1
+BLDCRT=1
+
+DLLENTRY=InitializeUhpfs
+
+PRECOMPILED_INCLUDE= pch.cxx
+
+
+SOURCES= \
+ alsec.cxx \
+ badblk.cxx \
+ bitmap.cxx \
+ bmind.cxx \
+ cpinfo.cxx \
+ defer.cxx \
+ dirblk.cxx \
+ dircache.cxx \
+ dirmap.cxx \
+ dirtree.cxx \
+ entry.cxx \
+ fnode.cxx \
+ hfsecrun.cxx \
+ hotfix.cxx \
+ hpcensus.cxx \
+ hpfsacl.cxx \
+ hpfschk.cxx \
+ hpfsea.cxx \
+ hpfseal.cxx \
+ hpfsname.cxx \
+ hpfssa.cxx \
+ hpfsvol.cxx \
+ orphan.cxx \
+ sid.cxx \
+ spareb.cxx \
+ store.cxx \
+ superb.cxx \
+ uhpfs.cxx \
+ uhpfs.rc
+
+INCLUDES=..\inc;..\..\ulib\inc;..\..\ifsutil\inc;$(BASEDIR)\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+CXXFLAGS=+d
+UMLIBS=obj\*\uhpfs.lib
+
+UMTYPE=console
+
+UMTEST=
+UMRES=obj\*\uhpfs.res
+
+DLLDEF=uhpfs.def
diff --git a/private/utils/uhpfs/src/spareb.cxx b/private/utils/uhpfs/src/spareb.cxx
new file mode 100644
index 000000000..00113022a
--- /dev/null
+++ b/private/utils/uhpfs/src/spareb.cxx
@@ -0,0 +1,530 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "bitmap.hxx"
+#include "error.hxx"
+#include "spareb.hxx"
+#include "superb.hxx"
+
+
+DEFINE_CONSTRUCTOR( SPAREB, SECRUN );
+
+VOID
+SPAREB::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Constructor for SPAREB.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _pspd = NULL;
+}
+
+
+SPAREB::~SPAREB(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for SPAREB.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+SPAREB::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a SPAREB to its initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _pspd = NULL;
+}
+
+
+BOOLEAN
+SPAREB::Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes a SPAREB to a valid initial state.
+
+Arguments:
+
+ Mem - Supplies the memory for the super block.
+ Drive - Supplies the drive on which the spare block resides.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ Destroy();
+
+ if (!SECRUN::Initialize(Mem, Drive, lbnSPAREB, csecSPAREB)) {
+ Destroy();
+ return FALSE;
+ }
+
+ _pspd = (_SPAREB*) GetBuf();
+
+ return TRUE;
+}
+
+
+ULONG
+SPAREB::ccs(
+ IN PVOID Buffer,
+ IN ULONG Size
+ )
+/*++
+
+Routine Description:
+
+ This routine computes a 32-bit checksum on 'Buffer'.
+
+Arguments:
+
+ Buffer - Supplies the buffer to check sum.
+ Size - Supplies the number of bytes in the buffer.
+
+Return Value:
+
+ A 32-bit checksum.
+
+--*/
+{
+ // CONST CCS_ROT = 7;
+
+ ULONG i;
+ ULONG accum;
+ PUCHAR pb;
+
+ pb = (PUCHAR) Buffer;
+ accum = 0;
+ for (i = 0; i < Size; i++)
+ {
+ accum += (ULONG)*pb++;
+ accum = (accum << CCS_ROT) + (accum >> (32 - CCS_ROT));
+ }
+
+ return accum;
+}
+
+
+NONVIRTUAL
+BOOLEAN
+SPAREB::Create(
+ IN PCLOG_IO_DP_DRIVE Drive,
+ IN OUT PHPFS_BITMAP BitMap,
+ IN PSUPERB SuperBlock,
+ IN LBN HotFixLbn,
+ IN SECTORCOUNT MaxHotFixes,
+ IN LBN CodePageSectorLbn,
+ IN ULONG NumCodePages,
+ IN LBN StartSparesLbn,
+ IN ULONG NumSpares
+ )
+/*++
+
+Routine Description:
+
+ This routine creates a spare block.
+
+Arguments:
+
+ Drive - Supplies the drive to create the spare block on.
+ BitMap - Supplies the free sectors bitmap for that drive.
+ SuperBlock - Supplies the spare block.
+ HotFixLbn - Supplies the lbn of the hot fix list.
+ MaxHotFixes - Supplies the maximum number of hot fixes.
+ CodePageSectorLbn - Supplies the code page sector lbn.
+ NumCodePages - Supplies the number of code pages.
+ StartSparesLbn - Supplies the lbn where the spare dir blocks will go.
+ NumSpares - Supplies the number of spare dir blocks to allocate.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG i;
+ ULONG cbSectorSize;
+ SECTORCOUNT scDirblk;
+ PVOID psbd;
+
+ // Check for valid construction and soundness of parameters.
+ if (!BitMap ||
+ !_pspd ||
+ !Drive ||
+ !(cbSectorSize = Drive->QuerySectorSize()) ||
+ !SuperBlock ||
+ !(psbd = SuperBlock->GetBuf())) {
+ perrstk->push(ERR_SP_PARAMETER, QueryClassId());
+ return FALSE;
+ }
+
+ // Compute the number of sectors per dir block.
+ scDirblk = DIRBLK_SIZE/cbSectorSize;
+
+ // Zero fill secbuf.
+ memset(GetBuf(), 0, (UINT)cbSectorSize);
+
+ // Set signatures.
+ _pspd->sig1 = SparesBlockSignature1;
+ _pspd->sig2 = SparesBlockSignature2;
+
+ // Set flag to 0.
+ _pspd->bFlag = 0;
+ for (i = 0; i < 3; i++) {
+ _pspd->bAlign[i] = 0;
+ }
+
+ // Set hot fix stuff.
+ _pspd->lbnHotFix = HotFixLbn;
+ _pspd->culHotFixes = 0;
+ _pspd->culMaxHotFixes = MaxHotFixes;
+
+ // Set the number of spare dir blocks to be allocated.
+ _pspd->cdbSpares = _pspd->cdbMaxSpare = NumSpares;
+ if (NumSpares > 101) {
+ perrstk->push(ERR_SP_PARAMETER, QueryClassId());
+ return FALSE;
+ }
+
+ // Set the code page information.
+ _pspd->lbnCPInfo = CodePageSectorLbn;
+ _pspd->culCP = NumCodePages;
+
+ // Allocate the spare dir blocks at the specified location.
+ for (i = 0; i < NumSpares; i++) {
+ // Allocate sectors for dir block.
+ _pspd->albnSpareDirblks[i] = BitMap->NearLBN(
+ StartSparesLbn + i*scDirblk, scDirblk, scDirblk);
+
+ if (!_pspd->albnSpareDirblks[i]) {
+ return FALSE;
+ }
+ }
+
+ // Perform a check sum on the super block.
+ _pspd->chkSuperBlock = ccs(psbd, sizeof(_SUPERB));
+
+ // Perform a check sum on the spare block.
+ _pspd->chkSpareBlock = 0;
+ _pspd->chkSpareBlock = ccs(_pspd, sizeof(_SPAREB));
+
+ return TRUE;
+}
+
+
+BOOLEAN
+SPAREB::Verify(
+ )
+{
+ if( !Read() ||
+ _pspd->sig1 != SparesBlockSignature1 ||
+ _pspd->sig2 != SparesBlockSignature2 ) {
+
+ }
+
+ return TRUE;
+}
+
+
+/***************************************************************************\
+
+MEMBER: IsValid
+
+SYNOPSIS: Determine of the spare block is valid
+
+ALGORITHM: if data is allocated and the signatures are correct
+ return TRUE
+ else
+ return FALSE
+
+ARGUMENTS:
+
+RETURNS:
+
+HISTORY: 26-July-90 marks
+ created
+KEYWORDS:
+
+SEEALSO:
+
+\***************************************************************************/
+BOOLEAN
+SPAREB::IsValid(
+) CONST {
+ DebugAssert(_pspd);
+
+ return _pspd && (_pspd->sig1 == SparesBlockSignature1 &&
+ _pspd->sig2 == SparesBlockSignature2);
+}
+
+/***************************************************************************\
+
+MEMBER: SetFlag
+
+SYNOPSIS: Set the state information bit(s) as specified by parameters
+
+ALGORITHM: if a set requested
+ set requested bit(s)
+ else
+ clear requested bit(s)
+
+ARGUMENTS:
+ BOOL fSet, // TRUE if bit(s) to be turned on
+ SPI spi // bit to set
+
+RETURNS:
+
+NOTES: Any number of bit masks can be OR'ed and then passed
+ to this call for set/clear
+
+HISTORY: 26-July-90 marks
+ created
+KEYWORDS:
+
+SEEALSO:
+
+\***************************************************************************/
+BOOLEAN
+SPAREB::SetFlag(
+ BOOLEAN Flag,
+ SPI Bit
+) {
+ DebugAssert(_pspd);
+ if (_pspd) {
+ if (Flag) {
+ // set the value
+ _pspd->bFlag |= Bit;
+ }
+ else {
+ // else clear the value
+ _pspd->bFlag &= ~Bit;
+ }
+ return TRUE;
+ }
+ else {
+ return FALSE;
+ }
+}
+
+LBN
+SPAREB::QuerySpareDirblkLbn(
+ ULONG i
+ ) const
+{
+ return _pspd->albnSpareDirblks[i];
+}
+
+
+VOID
+SPAREB::ComputeAndSetChecksums(
+ IN PSUPERB SuperBlock
+ )
+/*++
+
+Routine Description:
+
+ Computes the spares block checksums and sets those fields.
+
+Arguments:
+
+ SuperBlock supplies the volume's super block
+
+Notes:
+
+ The super block checksum is simply computed on the super block.
+ The Spares Block checksum is computed on the spares block with
+ the super block checksum field set to its proper value and the
+ spares block checksum field set to zero.
+
+--*/
+{
+ PVOID psbd;
+
+ if( (psbd = SuperBlock->GetBuf()) == NULL ||
+ _pspd == NULL ) {
+
+ DebugAbort( "spareb.cxx: superblock or sparesblock ptr is NULL" );
+ return;
+ }
+
+
+ // Perform a check sum on the super block.
+ _pspd->chkSuperBlock = ccs(psbd, sizeof(_SUPERB));
+
+ // Perform a check sum on the spare block.
+ _pspd->chkSpareBlock = 0;
+ _pspd->chkSpareBlock = ccs(_pspd, sizeof(_SPAREB));
+}
+
+
+VOID
+SPAREB::SetFlags(
+ IN BOOLEAN IsClean
+ )
+/*++
+
+Routine description:
+
+ Sets the spares block flags, depending on the state of the
+ spares block.
+
+Arguments:
+
+ IsClean -- supplies state of volume--TRUE if the volume
+ is consistent.
+
+Notes:
+
+ The only flag which is preserved is SPI_FSVER; the rest are
+ redetermined based on the state of the spares block or the
+ argument IsClean.
+
+--*/
+{
+ BYTE NewFlags;
+
+ NewFlags = _pspd->bFlag & SPI_FSVER;
+
+ if( !IsClean ) {
+
+ NewFlags |= SPI_DIRTY;
+ }
+
+ if( _pspd->cdbSpares != _pspd->cdbMaxSpare ) {
+
+ NewFlags |= SPI_SPARE;
+ }
+
+ if( _pspd->culHotFixes != 0 ) {
+
+ NewFlags |= SPI_HFUSED;
+ }
+
+ // SPI_BADSEC and SPI_BADBM are used internally by HPFS;
+ // they should always be cleared by Chkdsk.
+
+ _pspd->bFlag = NewFlags;
+
+ return;
+}
+
+
+/***************************************************************************\
+
+MEMBER: SPAREB::Print
+
+SYNOPSIS: Print the internal _SPAREB structure.
+
+ALGORITHM:
+
+
+ARGUMENTS: BOOL - If true then print the LBN's for all of the
+ Spare Dirblks.
+
+RETURNS: None
+
+NOTES:
+
+HISTORY: 30-Jul-90 norbertk
+ Created.
+
+KEYWORDS:
+
+SEEALSO:
+
+\***************************************************************************/
+
+VOID
+SPAREB::Print(
+ IN BOOLEAN TotalDump
+ ) CONST
+
+{
+ // unreferenced parameters
+ (void)(this);
+ (void)(TotalDump);
+
+// int i;
+//
+// printf("\n*** _SPAREB BEGIN ***\n");
+//
+// printf("sig1 : %#X\n", _pspd->sig1);
+// printf("sig2 : %#X\n", _pspd->sig2);
+// printf("bFlag : %#X\n", _pspd->bFlag);
+// printf("lbnHotFix : %lu\n", _pspd->lbnHotFix);
+// printf("culHotFixes : %lu\n", _pspd->culHotFixes);
+// printf("culMaxHotFixes : %lu\n", _pspd->culMaxHotFixes);
+// printf("cdbSpares : %lu\n", _pspd->cdbSpares);
+// printf("cdbMaxSpare : %lu\n", _pspd->cdbMaxSpare);
+// printf("lbnCPInfo : %lu\n", _pspd->lbnCPInfo);
+// printf("culCP : %lu\n", _pspd->culCP);
+// printf("chkSuperBlock : %lu\n", _pspd->chkSuperBlock);
+// printf("chkSpareBlock : %lu\n", _pspd->chkSpareBlock);
+//
+// if (TotalDump)
+// {
+// printf("%d Dirblk LBN's to follow:\n", _pspd->cdbSpares);
+// for (i = 0; i < _pspd->cdbSpares; i++)
+// {
+// printf("%lu ", _pspd->albnSpareDirblks[i]);
+// if(!((i + 1)%8))
+// printf("\n");
+// }
+// }
+//
+// printf("\n*** _SPAREB END ***\n");
+}
diff --git a/private/utils/uhpfs/src/store.cxx b/private/utils/uhpfs/src/store.cxx
new file mode 100644
index 000000000..26d9e0d0a
--- /dev/null
+++ b/private/utils/uhpfs/src/store.cxx
@@ -0,0 +1,1714 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ store.cxx
+
+Abstract:
+
+ This module contains member function definitions for the STORE
+ object, which models the allocation block common the HPFS Allocation
+ Sectors and FNodes.
+
+ This object is a template which is laid over memory supplied by
+ the client.
+
+Author:
+
+ Bill McJohn (billmc) 01-Dec-1990
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "alsec.hxx"
+#include "bitmap.hxx"
+#include "error.hxx"
+#include "store.hxx"
+#include "hfsecrun.hxx"
+#include "hotfix.hxx"
+#include "hpcensus.hxx"
+#include "hpfsname.hxx"
+#include "hpfssa.hxx"
+#include "orphan.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+
+
+DEFINE_CONSTRUCTOR( STORE, OBJECT );
+
+VOID
+STORE::Construct (
+ )
+/*++
+
+Routine Description:
+
+ This method is the helper function for object construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _pstd = NULL;
+ _IsModified = FALSE;
+ _IsFnode = FALSE;
+ _CurrentLBN = 0;
+
+}
+
+
+STORE::~STORE(
+ )
+/*++
+
+Routine Description:
+
+ Object destructor.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+}
+
+
+
+BOOLEAN
+STORE::Initialize(
+ IN PLOG_IO_DP_DRIVE Drive,
+ IN PSTORED pstd,
+ IN LBN CurrentLBN,
+ IN BOOLEAN IsFnode
+ )
+/*++
+
+Routine Description:
+
+ This method initializes the STORE object.
+
+
+Arguments:
+
+ Drive -- supplies the drive on which this object resides.
+ pstd -- supplies a pointer to the data for the storage object.
+ CurrentLbn -- supplies the lbn of the sector (FNode or ALSEC) which
+ contains this storage object.
+ IsFnode -- supplies a flag which, if TRUE, indicates that this
+ storage object exists in an FNode.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This class is reinitializable.
+
+--*/
+{
+
+ _Drive = Drive;
+ _pstd = pstd;
+ _CurrentLBN = CurrentLBN;
+ _IsFnode = IsFnode;
+
+ return TRUE;
+}
+
+
+
+VERIFY_RETURN_CODE
+STORE::VerifyAndFix(
+ IN HPFS_SA* SuperArea,
+ IN PDEFERRED_ACTIONS_LIST DeferredActions,
+ IN OUT HPFS_PATH* CurrentPath,
+ IN OUT LBN* NextSectorNumber,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN ErrorsDetected,
+ IN BOOLEAN UpdateAllowed,
+ IN OUT HPFS_ORPHANS* OrphansList,
+ IN BOOLEAN ParentIsFnode
+ )
+/*++
+
+Description of Routine:
+
+ Verify a storage object.
+
+Arguments:
+
+ SuperArea -- Supplies the superarea for the volume being
+ checked.
+ DeferredActions -- Supplies the deferred actions list for this
+ pass of Chkdsk.
+ CurrentPath -- Supplies the path to the file with which this
+ storage object is associated. (May be NULL,
+ which indicates that orphans are being recovered.)
+ NextSectorNumber -- Supplies the the expected next file lbn (ie. the
+ number of sectors in the file before this storage
+ object.
+ Receives the next file logical sector number
+ that is expected to come after this storage object.
+ Message -- Supplies an output port for messages.
+ ErrorsDetected -- Receives TRUE if an error is detected that does
+ not cause a message to be displayed.
+ UpdateAllowed -- Supplies a flag which, if TRUE, indicates that
+ corrections should be written to disk.
+ OrphansList -- Supplies a list of previously-recovered orphans
+ that may be claimed as children. May be NULL.
+ ParentIsFnode -- Supplies a flag which, if TRUE, indicates that
+ the immediate parent of the structure containing
+ this storage object is the file FNode.
+
+Notes:
+
+ During the orphan recovery phase, CurrentPath is NULL and OrphansList
+ may be non-NULL.
+
+ Note that if this routine does not return VERIFY_STRUCTURE_OK,
+ it must restore the original value of *NextSectorNumber.
+
+--*/
+{
+ ALSEC ChildAlsec;
+ PALLEAF pall;
+ PALNODE paln;
+ LBN NewLbn;
+ LBN SavedNextSectorNumber;
+ BYTE i, j, TotalEntries;
+ VERIFY_RETURN_CODE erc;
+
+ SavedNextSectorNumber = *NextSectorNumber;
+
+ // Check and fix the Parent-is-Fnode flag
+
+ if( ParentIsFnode && !(_pstd->alb.bFlag & ABF_FNP) ) {
+
+ // This flag is not set, but it should be.
+
+ if( CurrentPath != NULL ) {
+
+ DebugPrintf( "%s: setting ABF_FNP in lbn %lx\n",
+ (PCHAR)CurrentPath->GetString(),
+ _CurrentLBN );
+ }
+
+ *ErrorsDetected = TRUE;
+ _pstd->alb.bFlag |= ABF_FNP;
+ MarkModified();
+ }
+
+ if( !ParentIsFnode && (_pstd->alb.bFlag & ABF_FNP) ) {
+
+ // This flag is set, but it should not be.
+
+ if( CurrentPath != NULL ) {
+
+ DebugPrintf( "%s: clearing ABF_FNP in lbn %lx\n",
+ (PCHAR)CurrentPath->GetString(),
+ _CurrentLBN );
+ }
+
+ *ErrorsDetected = TRUE;
+ _pstd->alb.bFlag &= ~ABF_FNP;
+ MarkModified();
+ }
+
+
+ if ( _pstd->alb.bFlag & ABF_NODE ) {
+
+ // This structure has children which are allocation
+ // sectors. Create and initialize an ALSEC object
+ // to use while we iterate through the children.
+
+ if( !ChildAlsec.Initialize( _Drive, (LBN)0L ) ) {
+
+ *NextSectorNumber = SavedNextSectorNumber;
+ return VERIFY_INSUFFICIENT_RESOURCES;
+ }
+
+ // Ensure that the number of free and used entries
+ // add up to the correct total, then iterate
+ // down the list of entries.
+
+ if( _IsFnode ) {
+
+ TotalEntries = NodesPerFnode;
+
+ } else {
+
+ TotalEntries = NodesPerAlsec;
+ }
+
+ if( _pstd->alb.cFree > TotalEntries ||
+ _pstd->alb.cFree + _pstd->alb.cUsed != TotalEntries ) {
+
+ *ErrorsDetected = TRUE;
+
+ if( CurrentPath != NULL ) {
+
+ DebugPrintf( "%s: setting cFree in lbn %lx\n",
+ (PCHAR)CurrentPath->GetString(),
+ _CurrentLBN );
+ }
+
+ _pstd->alb.cFree = TotalEntries - _pstd->alb.cUsed;
+ MarkModified();
+ }
+
+
+ if( _pstd->alb.oFree != sizeof( ALBLK ) +
+ _pstd->alb.cUsed * sizeof( ALNODE ) ) {
+
+ *ErrorsDetected = TRUE;
+
+ if( CurrentPath != NULL ) {
+
+ DebugPrintf( "%s: setting oFree in lbn %lx\n",
+ (PCHAR)CurrentPath->GetString(),
+ _CurrentLBN );
+ }
+
+ _pstd->alb.oFree = sizeof( ALBLK ) +
+ _pstd->alb.cUsed * sizeof( ALNODE );
+ MarkModified();
+ }
+
+
+ paln = &( _pstd->a.alnode[0] );
+
+ for( i = 0; i < _pstd->alb.cUsed; i++ ) {
+
+ // If the child sector is hotfixed, update the
+ // allocation node.
+ NewLbn = SuperArea->GetHotfixList()->
+ GetLbnTranslation( paln->lbnPhys );
+
+ if (NewLbn != paln->lbnPhys ) {
+
+ SuperArea->GetHotfixList()->
+ ClearHotfix( paln->lbnPhys, SuperArea );
+
+ paln->lbnPhys = NewLbn;
+ MarkModified();
+ }
+
+ ChildAlsec.Relocate( paln->lbnPhys );
+
+ if( (erc = ChildAlsec.VerifyAndFix( SuperArea,
+ DeferredActions,
+ CurrentPath,
+ _CurrentLBN,
+ NextSectorNumber,
+ Message,
+ ErrorsDetected,
+ UpdateAllowed,
+ OrphansList,
+ _IsFnode ) ) !=
+ VERIFY_STRUCTURE_OK ) {
+
+ // If we have an orphan list to draw on, we'll look
+ // for the child there. Otherwise, just propagate
+ // the error back to the parent.
+
+ if( OrphansList == NULL ||
+ !OrphansList->LookupAlsec( paln->lbnPhys,
+ _CurrentLBN,
+ NextSectorNumber,
+ UpdateAllowed,
+ _IsFnode ) ) {
+
+ *NextSectorNumber = SavedNextSectorNumber;
+ return erc;
+ }
+ }
+
+ if( i == (BYTE)(_pstd->alb.cUsed - 1) ) {
+
+
+ // This is the last entry, so it's lbnLog
+ // field must be 0xffffffff.
+
+ if( paln->lbnLog != 0xffffffff ) {
+
+ // This is not a big deal, so just record that a minor
+ // error has been found and fixed.
+ //
+ DebugPrintf( "UHPFS: lbnLog of last node entry is not 0xffffffff.\n" );
+ *ErrorsDetected = TRUE;
+ paln->lbnLog = 0xffffffff;
+ MarkModified();
+ }
+
+ } else {
+
+ // This is not the last entry, so the
+ // lbnLog field should equal the number
+ // of the next sector in the file, i.e.
+ // *NextSectorNumber.
+
+ if( paln->lbnLog != *NextSectorNumber ) {
+
+ DebugPrintf( "UHPFS: LbnLog in allocation node is incorrect.\n" );
+
+ if( Message != NULL && CurrentPath != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_ALLOCATION_ERROR );
+ Message->Display( "%s", CurrentPath->GetString() );
+ }
+
+ paln->lbnLog = *NextSectorNumber;
+ MarkModified();
+ }
+ }
+
+ paln += 1;
+ }
+
+ return VERIFY_STRUCTURE_OK;
+
+ } else {
+
+ // Entries are leaves. Ensure that the number of free and
+ // used entries add up to the correct total, then iterate
+ // down the entries.
+
+ if( _IsFnode ) {
+
+ TotalEntries = LeavesPerFnode;
+
+ } else {
+
+ TotalEntries = LeavesPerAlsec;
+ }
+
+ if( _pstd->alb.cFree + _pstd->alb.cUsed != TotalEntries ) {
+
+ *ErrorsDetected = TRUE;
+
+ if( CurrentPath != NULL ) {
+
+ DebugPrintf( ": setting cFree in lbn %lx\n",
+ (PCHAR)CurrentPath->GetString(),
+ _CurrentLBN );
+ }
+
+ _pstd->alb.cFree = TotalEntries - _pstd->alb.cUsed;
+ MarkModified();
+ }
+
+
+ if( _pstd->alb.oFree != sizeof( ALBLK ) +
+ _pstd->alb.cUsed * sizeof( ALLEAF ) ) {
+
+ *ErrorsDetected = TRUE;
+
+ if( CurrentPath != NULL ) {
+
+ DebugPrintf( ": setting oFree in lbn %lx\n",
+ (PCHAR)CurrentPath->GetString(),
+ _CurrentLBN );
+ }
+
+ _pstd->alb.oFree = sizeof( ALBLK ) +
+ _pstd->alb.cUsed * sizeof( ALLEAF );
+ MarkModified();
+ }
+
+
+ pall = &( _pstd->a.alleaf[0] );
+
+ for( i = 0; i < _pstd->alb.cUsed; i++ ) {
+
+ // We need to ensure that the runs are valid
+ // and not crosslinked.
+ //
+ if( pall->csecRun == 0 ) {
+
+ // This run is zero length, which is illegal.
+ // The other sectors we just visited are set
+ // back to the free state.
+ //
+ for( j = 0; j < i; j++ ) {
+
+ pall = &( _pstd->a.alleaf[j] );
+ SuperArea->GetBitmap()->SetFree( pall->lbnPhys,
+ pall->csecRun );
+ }
+
+ return VERIFY_STRUCTURE_INVALID;
+ }
+
+ if( !SuperArea->GetBitmap()->IsFree( pall->lbnPhys,
+ pall->csecRun ) ) {
+
+ // The run is crosslinked (or falls off the end of
+ // the disk?). If this is file data (i.e. if
+ // CurrentPath is not NULL), add it to the
+ // crosslink resolution list; otherwise, treat
+ // it as unrecoverably corrupt.
+ if( (pall->lbnPhys + pall->csecRun >
+ _Drive->QuerySectors().GetLowPart()) ||
+ CurrentPath == NULL ||
+ !DeferredActions->
+ AddCrosslinkedLbn( _CurrentLBN,
+ CurrentPath,
+ ( _IsFnode ? DEFER_FNODE :
+ DEFER_ALSEC ),
+ i ) ) {
+
+ // Can't defer--treat as corrupt. No message is
+ // sent here; the parent structure will take care
+ // of that.
+
+ // The other sectors we just visited are set back
+ // the free state.
+
+ for( j = 0; j < i; j++ ) {
+
+ pall = &( _pstd->a.alleaf[j] );
+ SuperArea->GetBitmap()->SetFree( pall->lbnPhys,
+ pall->csecRun );
+ }
+
+ *NextSectorNumber = SavedNextSectorNumber;
+ return VERIFY_STRUCTURE_INVALID;
+ }
+ }
+
+ SuperArea->GetBitmap()->SetAllocated( pall->lbnPhys,
+ pall->csecRun );
+
+ if( SuperArea->GetHotfixList()->IsInList( pall->lbnPhys,
+ pall->csecRun ) ) {
+
+ DeferredActions->AddHotfixedLbn( _CurrentLBN,
+ ( _IsFnode ? DEFER_FNODE :
+ DEFER_ALSEC ),
+ DEFER_STORE );
+ }
+
+ // Check the lbnLog field--it should be equal
+ // to the first logical sector of the run, i.e.
+ // the current value of *NextSectorNumber. Then
+ // increment *NextSectorNumber to reflect this run.
+
+ if( pall->lbnLog != *NextSectorNumber ) {
+
+ DebugPrintf( "UHPFS: lbnLog in allocation leaf is incorrect.\n" );
+
+ if( Message != NULL && CurrentPath != NULL ) {
+
+ Message->Set( MSG_HPFS_CHKDSK_ALLOCATION_ERROR );
+ Message->Display( "%s", CurrentPath->GetString() );
+ }
+
+ pall->lbnLog = *NextSectorNumber;
+ MarkModified();
+ }
+
+ *NextSectorNumber += pall->csecRun;
+
+ // ... and move to the next leaf.
+
+ pall += 1;
+ }
+
+ return VERIFY_STRUCTURE_OK;
+ }
+}
+
+
+
+BOOLEAN
+STORE::ScanStorage(
+ IN OUT PULONG NextSectorNumber,
+ IN BOOLEAN ParentIsFnode
+ )
+/*++
+
+Routine Description:
+
+ This method traverses the storage object and sets the File Logical
+ Block Numbers. It also sets or clears the ABF_FNP flag as appropriate.
+
+Arguments:
+
+ NextSectorNumber -- Supplies the first file Logical Block Number
+ for this storage item;
+ Receives the first file Logical Block Number
+ for the portion of the allocation tree (if any)
+ which follows this storage item.
+ ParentIsFnode -- Supplies a flag indication whether the parent
+ of the structure contaning this storage object
+ is the FNode.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ ALSEC ChildAlsec;
+ PALLEAF pall;
+ PALNODE paln;
+ BYTE i;
+
+ // First, make sure that the ABF_FNP flag is set correctly.
+
+ if( ParentIsFnode ) {
+
+ _pstd->alb.bFlag |= ABF_FNP;
+
+ } else {
+
+ _pstd->alb.bFlag &= ~ABF_FNP;
+ }
+
+ if ( _pstd->alb.bFlag & ABF_NODE ) {
+
+ // This structure has children which are allocation
+ // sectors. Create and initialize an ALSEC object
+ // to use while we iterate through the children.
+
+ if( !ChildAlsec.Initialize( _Drive, (LBN)0L ) ) {
+
+ return FALSE;
+ }
+
+
+ paln = &( _pstd->a.alnode[0] );
+
+ for( i = 0; i < _pstd->alb.cUsed; i++ ) {
+
+ ChildAlsec.Relocate( paln->lbnPhys );
+
+ if( !ChildAlsec.Read() ||
+ !ChildAlsec.ScanStorage(NextSectorNumber, _IsFnode) ||
+ !ChildAlsec.Write() ) {
+
+ return FALSE;
+ }
+
+
+ if( i == (BYTE)(_pstd->alb.cUsed - 1) ) {
+
+ // This is the last entry, so it's lbnLog
+ // field must be 0xffffffff.
+
+ paln->lbnLog = (LBN) -1;
+
+ } else {
+
+ // This is not the last entry, so the
+ // lbnLog field should equal the number
+ // of the next sector in the file, i.e.
+ // *NextSectorNumber.
+
+ paln->lbnLog = *NextSectorNumber;
+ }
+
+ paln += 1;
+ }
+
+ return TRUE;
+
+ } else {
+
+ pall = &( _pstd->a.alleaf[0] );
+
+ for( i = 0; i < _pstd->alb.cUsed; i++ ) {
+
+ // Check the lbnLog field--it should be equal
+ // to the first logical sector of the run, i.e.
+ // the current value of *NextSectorNumber. Then
+ // increment *NextSectorNumber to reflect this run.
+
+ pall->lbnLog = *NextSectorNumber;
+
+ *NextSectorNumber += pall->csecRun;
+
+ // ... and move to the next leaf.
+
+ pall += 1;
+ }
+
+ return TRUE;
+ }
+}
+
+
+
+VOID
+STORE::MarkModified(
+ )
+/*++
+
+Routine Description:
+
+ This method marks the storage object as modified.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _IsModified = TRUE;
+}
+
+
+BOOLEAN
+STORE::QueryModified(
+ )
+/*++
+
+Routine Description:
+
+ This method determines whether the storage object has been
+ marked as modified.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the storage object has been marked as modified.
+
+--*/
+{
+ return _IsModified;
+}
+
+
+
+BOOLEAN
+STORE::FindAndResolveHotfix(
+ PHPFS_SA SuperArea,
+ DEFERRED_SECTOR_TYPE ChildSectorType
+ )
+/*++
+
+Routine Description:
+
+ This method finds and resolves hotfix references in the data runs
+ described by this storage object.
+
+Arguments:
+
+ SuperaArea -- supplies superarea for the volume
+ ChildSectorType -- supplies the type of sector which was hotfixed.
+
+Return Value:
+
+ TRUE on successful completion
+
+Notes:
+
+ This function is invoked by the deferred-actions list, when
+ it tries to clean up the deferred hotfix references. The
+ only sort of child sector type that is deferred for storage
+ objects is DEFER_STORE.
+
+--*/
+{
+ PHOTFIXLIST HotfixList;
+ ULONG i, j, k;
+ ULONG MaximumEntries;
+ PALLEAF Leaves;
+ LBN OldLbn, NewLbn;
+
+ i = 0;
+
+ DebugAssert( ChildSectorType == DEFER_STORE );
+
+ if( _pstd->alb.bFlag & ABF_NODE ) {
+
+ // Entries in nodes are resolved on the fly, since
+ // an allocation sector is only one sector.
+
+ return TRUE;
+ }
+
+ if( _IsFnode ) {
+
+ MaximumEntries = LeavesPerFnode;
+
+ } else {
+
+ MaximumEntries = LeavesPerAlsec;
+ }
+
+ HotfixList = SuperArea->GetHotfixList();
+ Leaves = _pstd->a.alleaf;
+
+ // Check each leaf to see if it is hotfixed. If it is,
+ // deal with it.
+
+ while( i < _pstd->alb.cUsed ) {
+
+ while( HotfixList->IsInList( Leaves[i].lbnPhys,
+ Leaves[i].csecRun ) ) {
+
+ // Find the first hotfixed sector in the run.
+ // If it's the first or last sector in the run,
+ // then this run will be divided into two chunks;
+ // otherwise, into three. If there is room
+ // in the Leaves object, we can move the other
+ // entries down and make one or two new entries,
+ // as needed.
+
+ j = HotfixList->FirstHotfixInRun( Leaves[i].lbnPhys,
+ Leaves[i].csecRun );
+
+ DebugAssert( j < Leaves[i].csecRun );
+
+ if( Leaves[i].csecRun == 1 ) {
+
+ OldLbn = Leaves[i].lbnPhys;
+ NewLbn = HotfixList->GetLbnTranslation( OldLbn );
+
+ Leaves[i].lbnPhys = NewLbn;
+
+ SuperArea->GetBitmap()->SetAllocated( NewLbn, 1 );
+
+ HotfixList->ClearHotfix( OldLbn, SuperArea );
+
+ } else if( j == 0 ) {
+
+ if( _pstd->alb.cUsed < MaximumEntries ) {
+
+ // shift the entries after i down one
+ // to make room. The ith entry will have
+ // a length of on sector, and its lbnPhys
+ // will be the hotfix replacement sector.
+
+ OldLbn = Leaves[i].lbnPhys;
+
+ for( k = _pstd->alb.cUsed-1; k > i; k-- ) {
+
+ Leaves[k+1].lbnLog = Leaves[k].lbnLog;
+ Leaves[k+1].lbnPhys = Leaves[k].lbnPhys;
+ Leaves[k+1].csecRun = Leaves[k].csecRun;
+ }
+
+ Leaves[i+1].lbnLog = Leaves[i].lbnLog + 1;
+ Leaves[i+1].lbnPhys = Leaves[i].lbnPhys + 1;
+ Leaves[i+1].csecRun = Leaves[i].csecRun - 1;
+
+ Leaves[i].csecRun = 1;
+ Leaves[i].lbnPhys =
+ HotfixList->GetLbnTranslation( Leaves[i].lbnPhys );
+
+ _pstd->alb.cFree -= 1;
+ _pstd->alb.cUsed += 1;
+
+ // Clear the hotfix, and make sure that the
+ // replacement sector is marked as used.
+
+ HotfixList->ClearHotfix( OldLbn, SuperArea );
+
+ SuperArea->GetBitmap()->
+ SetAllocated( Leaves[i].lbnPhys, 1 );
+
+ } else {
+
+ // Since there isn't room to split this entry,
+ // we'll copy the entire run. Copy the run,
+ // free the old sectors, clear the hotfixes,
+ // and set lbnPhys to point at the new location.
+
+ OldLbn = Leaves[i].lbnPhys;
+
+ if( !SuperArea->CopyRun( OldLbn,
+ Leaves[i].csecRun,
+ &NewLbn ) ) {
+
+ return FALSE;
+ }
+
+ SuperArea->GetBitmap()->SetFree( OldLbn,
+ Leaves[i].csecRun );
+
+ HotfixList->ClearRun(OldLbn,
+ Leaves[i].csecRun,
+ SuperArea );
+
+ Leaves[i].lbnPhys = NewLbn;
+ }
+
+ } else if( j == Leaves[i].csecRun - 1 ) {
+
+ // The last sector of the run is hotfixed,
+ // so we divide the run into two new runs.
+
+ if( _pstd->alb.cUsed < MaximumEntries ) {
+
+ // shift the entries after i down one
+ // to make room. The new (i+1)th entry
+ // will have a length of one sector, and
+ // its lbnPhys will be the hotfix replacement
+ // sector.
+
+ OldLbn = Leaves[i].lbnPhys + j;
+
+ for( k = _pstd->alb.cUsed-1; k > i; k-- ) {
+
+ Leaves[k+1].lbnLog = Leaves[k].lbnLog;
+ Leaves[k+1].lbnPhys = Leaves[k].lbnPhys;
+ Leaves[k+1].csecRun = Leaves[k].csecRun;
+ }
+
+ Leaves[i+1].lbnPhys =
+ HotfixList->
+ GetLbnTranslation( Leaves[i].lbnPhys + j );
+
+ Leaves[i+1].lbnLog = Leaves[i].lbnLog + j;
+ Leaves[i+1].csecRun = 1;
+
+ Leaves[i].csecRun -= 1;
+
+ _pstd->alb.cFree -= 1;
+ _pstd->alb.cUsed += 1;
+
+ // Clear the hotfix
+ HotfixList->ClearHotfix( OldLbn, SuperArea );
+
+ SuperArea->GetBitmap()->
+ SetAllocated( Leaves[i+1].lbnPhys, 1 );
+
+ } else {
+
+ // Since there isn't room to split this entry,
+ // we'll copy the entire run. Copy the run,
+ // free the old sectors, clear the hotfixes,
+ // and set lbnPhys to point at the new location.
+
+ OldLbn = Leaves[i].lbnPhys;
+
+ if( !SuperArea->CopyRun( OldLbn,
+ Leaves[i].csecRun,
+ &NewLbn ) ) {
+
+ return FALSE;
+ }
+
+ SuperArea->GetBitmap()->SetFree( OldLbn,
+ Leaves[i].csecRun );
+
+ HotfixList->ClearRun(OldLbn,
+ Leaves[i].csecRun,
+ SuperArea );
+
+ Leaves[i].lbnPhys = NewLbn;
+ }
+
+ } else {
+
+ // An interior sector is hotfixed, so the run
+ // gets divided into three parts.
+
+ if( _pstd->alb.cUsed < MaximumEntries - 1 ) {
+
+ // shift the entries after i down two
+ // to make room. The new (i+1)th entry
+ // will have a length of one sector, and
+ // its lbnPhys will be the hotfix replacement
+ // sector.
+
+ OldLbn = Leaves[i].lbnPhys + j;
+
+ for( k = _pstd->alb.cUsed-1; k > i; k-- ) {
+
+ Leaves[k+2].lbnLog = Leaves[k].lbnLog;
+ Leaves[k+2].lbnPhys = Leaves[k].lbnPhys;
+ Leaves[k+2].csecRun = Leaves[k].csecRun;
+ }
+
+ Leaves[i+2].lbnLog = Leaves[i].lbnLog +j + 1;
+ Leaves[i+2].lbnPhys = Leaves[i].lbnPhys + j + 1;
+ Leaves[i+2].csecRun = Leaves[i].csecRun - j - 1;
+
+ Leaves[i+1].lbnPhys =
+ HotfixList->
+ GetLbnTranslation( Leaves[i].lbnPhys + j );
+
+ Leaves[i+1].lbnLog = Leaves[i].lbnLog + j;
+ Leaves[i+1].csecRun = 1;
+
+ Leaves[i].csecRun = j;
+
+ _pstd->alb.cFree -= 2;
+ _pstd->alb.cUsed += 2;
+
+ // Clear the hotfix
+ HotfixList->ClearHotfix( OldLbn, SuperArea );
+
+ SuperArea->GetBitmap()->
+ SetAllocated( Leaves[i+1].lbnPhys, 1 );
+
+ } else {
+
+ // Since there isn't room to split this entry,
+ // we'll copy the entire run. Copy the run,
+ // free the old sectors, clear the hotfixes,
+ // and set lbnPhys to point at the new location.
+
+ OldLbn = Leaves[i].lbnPhys;
+
+ if( !SuperArea->CopyRun( OldLbn,
+ Leaves[i].csecRun,
+ &NewLbn ) ) {
+
+ return FALSE;
+ }
+
+ SuperArea->GetBitmap()->SetFree( OldLbn,
+ Leaves[i].csecRun );
+
+ HotfixList->ClearRun(OldLbn,
+ Leaves[i].csecRun,
+ SuperArea );
+
+ Leaves[i].lbnPhys = NewLbn;
+ }
+ }
+ }
+
+ // Move on to the next leaf
+ i += 1;
+ }
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+STORE::ResolveCrosslink(
+ HPFS_SA* SuperArea,
+ ULONG RunIndex
+ )
+/*++
+
+Routine Description:
+
+ This method resolves a crosslink by allocating a new location for the
+ crosslinked run and copying it there.
+
+Arguments:
+
+ SuperArea -- Supplies the super area for the volume being fixed.
+ RunIndex -- Supplies the index into the storage object of the
+ crosslinked run.
+
+Return Value:
+
+ TRUE on successful completion
+
+--*/
+{
+ HOTFIX_SECRUN DataRun;
+ HMEM DataBuffer;
+ LBN NewLbn;
+ PALLEAF pall;
+
+ if( _pstd->alb.bFlag & ABF_NODE ) {
+
+ // Only file data runs are duplicated. Since this
+ // isn't a leaf, refuse to deal with it.
+
+ return FALSE;
+ }
+
+ if( (_IsFnode && (RunIndex >= LeavesPerFnode)) ||
+ (!_IsFnode && (RunIndex >= LeavesPerAlsec)) ) {
+
+ // The run index is not valid
+ return FALSE;
+ }
+
+ pall = &(_pstd->a.alleaf[RunIndex]);
+
+#if defined( _SETUP_LOADER_ )
+ // In the Setup-Loader environment, we can't resolve
+ // hotfixed runs that are more that 1Meg long.
+ //
+ if( pall->csecRun * _Drive->QuerySectorSize() > 0x100000 ) {
+
+ return FALSE;
+ }
+#endif
+
+ if( !DataBuffer.Initialize() ||
+ !DataRun.Initialize( &DataBuffer,
+ _Drive,
+ SuperArea->GetHotfixList(),
+ pall->lbnPhys,
+ pall->csecRun ) ||
+ !DataRun.Read() ) {
+
+ return FALSE;
+ }
+
+
+ NewLbn = SuperArea->GetBitmap()->NearLBN( pall->lbnPhys, pall->csecRun );
+
+ if( NewLbn == 0 ) {
+
+ // Unable to relocate crosslinked run
+ return FALSE;
+ }
+
+
+ DataRun.Relocate( NewLbn );
+
+ if( !DataRun.Write() ) {
+
+ return FALSE;
+ }
+
+ pall->lbnPhys = NewLbn;
+
+ return TRUE;
+}
+
+
+
+LBN
+STORE::QueryPhysicalLbn(
+ IN LBN FileBlockNumber,
+ OUT PULONG RunLength
+ )
+/*++
+
+Routine Description:
+
+ This method converts a file logical block number into a
+ disk logical block number.
+
+Arguments:
+
+ FileBlockNumber -- Supplies the ordinal within the file or
+ extended attribute of the desired block.
+ RunLength -- Receives the remaining length of the
+ contiguous run.
+
+Return Value:
+
+ The disk lbn of the desired block. Zero indicates error.
+
+Notes:
+
+ This method assumes that the storage object is valid.
+
+--*/
+{
+ ULONG i;
+ PALLEAF pall;
+ ALSEC ChildAlsec;
+
+ if( _pstd->alb.bFlag & ABF_NODE ) {
+
+ i = 0;
+
+ while( i < _pstd->alb.cUsed &&
+ FileBlockNumber < _pstd->a.alnode[i].lbnPhys ) {
+
+ i += 1;
+ }
+
+ if( i >= _pstd->alb.cUsed ) {
+
+ // This storage object is not consistent.
+
+ return 0;
+ }
+
+ if( !ChildAlsec.Initialize( _Drive,
+ (LBN)(_pstd->a.alnode[i].lbnPhys) ) ||
+ !ChildAlsec.Read() ||
+ !ChildAlsec.IsAlsec() ) {
+
+ return 0;
+
+ } else {
+
+ return (ChildAlsec.QueryPhysicalLbn(FileBlockNumber, RunLength));
+ }
+
+ } else {
+
+ i = 0;
+
+ while( i < _pstd->alb.cUsed &&
+ FileBlockNumber >= _pstd->a.alleaf[i].lbnLog ) {
+
+ i += 1;
+ }
+
+ // the i'th entry is the first with an lbnLog which is
+ // greater than FileBlockNumber, so we want to back up one.
+
+ if( i == 0 ) {
+
+ // This is inconsistent--return an error.
+ return 0;
+
+ }
+
+ i -= 1;
+
+ pall = &(_pstd->a.alleaf[i]);
+
+ if( FileBlockNumber < pall->lbnLog + pall->csecRun ) {
+
+ *RunLength = pall->csecRun - (FileBlockNumber - pall->lbnLog);
+
+ return (pall->lbnPhys + (FileBlockNumber - pall->lbnLog));
+
+ } else {
+
+ return 0;
+ }
+ }
+}
+
+
+
+BOOLEAN
+STORE::Truncate(
+ LBN SectorCount
+ )
+/*++
+
+Routine Description:
+
+ This method truncates the allocation of a file (or extended attribute).
+
+Arguments:
+
+ SectorCount -- supplies the number of sectors to retain
+
+Return value:
+
+ TRUE on successful completion
+
+--*/
+{
+ ALSEC ChildAlsec;
+ ULONG i;
+ ULONG UsedEntries;
+ PALLEAF pall;
+ PALNODE paln;
+
+ if( SectorCount == 0 ) {
+
+ // We're truncating all the storage.
+
+ _pstd->alb.bFlag &= ~ABF_NODE;
+ _pstd->alb.cFree = (_IsFnode ? LeavesPerFnode : LeavesPerAlsec);
+ _pstd->alb.cUsed = 0;
+ _pstd->alb.oFree = sizeof( ALBLK );
+
+ return TRUE;
+ }
+
+ if( _pstd->alb.bFlag & ABF_NODE ) {
+
+ i = 0;
+ UsedEntries = _pstd->alb.cUsed;
+ paln = &(_pstd->a.alnode[0]);
+
+ while( i < UsedEntries &&
+ SectorCount > paln->lbnLog ) {
+
+ i += 1;
+ paln += 1;
+ }
+
+ // paln now points at the last node to keep, and i is one
+ // less than the number of nodes to keep.
+
+ i += 1;
+
+ _pstd->alb.cFree += (BYTE)(UsedEntries - i);
+ _pstd->alb.cUsed = (BYTE)i;
+ _pstd->alb.oFree -= (USHORT)(sizeof( ALNODE ) * (UsedEntries - i));
+
+ paln->lbnLog = (LBN)(-1);
+
+ if( !ChildAlsec.Initialize( _Drive,
+ paln->lbnPhys ) ||
+ !ChildAlsec.Read() ||
+ !ChildAlsec.IsAlsec() ) {
+
+ return FALSE;
+
+ } else {
+
+ return (ChildAlsec.Truncate(SectorCount));
+ }
+
+ } else {
+
+ i = 0;
+ pall = &(_pstd->a.alleaf[0]);
+ UsedEntries = _pstd->alb.cUsed;
+
+ while( i < UsedEntries && SectorCount > pall->lbnLog ) {
+
+ i += 1;
+ pall += 1;
+ }
+
+ // pall now points at the leaf after the truncation point,
+ // and i is the number of leaves to keep. Back pall up one
+ // to get to the truncation point.
+
+ pall -= 1;
+
+ // fix up the ALBLK
+
+ _pstd->alb.cFree += (BYTE)(UsedEntries - i);
+ _pstd->alb.cUsed = (BYTE)i;
+ _pstd->alb.oFree -= (USHORT)(sizeof( ALLEAF ) * (UsedEntries - i));
+
+ pall->csecRun = SectorCount - pall->lbnLog;
+
+ return TRUE;
+ }
+}
+
+
+
+BOOLEAN
+STORE::QueryExtents(
+ IN ULONG MaximumNumberOfExtents,
+ IN OUT PVOID ExtentList,
+ IN OUT PULONG NumberOfExtents
+ )
+/*++
+
+Routine Description:
+
+ This method fetches the list of extents covered by this
+ storage object.
+
+
+Arguments:
+
+ MaximumNumberOfExtents -- Supplies the maximum number of extents
+ that will fit in the client's buffer
+ ExtentList -- Supplies the client's buffer into which
+ extents will be placed.
+ NumberOfExtents -- Supplies the number of extents already in
+ the buffer.
+ Receives the number of extents in the buffer.
+
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ The records in the extent buffer are allocation leaves.
+
+ If ExtentList is NULL and MaximumNumberOfExtents is zero, this method
+ will only return the number of extents associated with this storage
+ object.
+
+--*/
+{
+ ULONG i;
+ ALSEC ChildAlsec;
+
+ if( _pstd->alb.bFlag & ABF_NODE ) {
+
+ // The entries in this storage object are allocation nodes.
+
+ // Set up an Allocation Sector to process the children.
+
+ if( !ChildAlsec.Initialize( _Drive, 0 ) ) {
+
+ return FALSE;
+ }
+
+
+ // Process each child allocation sector in turn. Each child
+ // will add entries to ExtentList and update NumberOfExtents.
+
+ for( i = 0; i < _pstd->alb.cUsed; i++ ) {
+
+ ChildAlsec.Relocate( (LBN)(_pstd->a.alnode[i].lbnPhys) );
+
+ if( !ChildAlsec.Read() ||
+ !ChildAlsec.QueryExtents( MaximumNumberOfExtents,
+ ExtentList,
+ NumberOfExtents ) ) {
+
+ return FALSE;
+ }
+ }
+
+ } else {
+
+ // The entries in this storage object are allocation leaves.
+ // Since the records in the extent buffer are allocation leaves,
+ // I can just copy the leaf records directly (if there's room).
+
+ if( MaximumNumberOfExtents == 0 && ExtentList == NULL ) {
+
+ // The client is only interested in the number of extents,
+ // not the actual list of allocation leaves.
+
+ *NumberOfExtents += _pstd->alb.cUsed;
+
+ } else if( *NumberOfExtents + _pstd->alb.cUsed <=
+ MaximumNumberOfExtents ) {
+
+ // The entries fit; copy them in and update the number
+ // of extents. To find the point to which I should copy
+ // these new entries, just skip over the number of entries
+ // already in the buffer.
+
+ memcpy( (PBYTE)ExtentList + *NumberOfExtents * sizeof( ALLEAF ),
+ _pstd->a.alleaf,
+ _pstd->alb.cUsed * sizeof( ALLEAF ) );
+
+ *NumberOfExtents += _pstd->alb.cUsed;
+
+ } else {
+
+ // The client's buffer is not large enough to hold the entries.
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+STORE::StoreExtents(
+ IN ULONG NumberOfExtents,
+ IN PALLEAF ExtentList,
+ IN BOOLEAN ParentIsFnode,
+ IN OUT PHPFS_BITMAP VolumeBitmap
+ )
+/*++
+
+Routine Description:
+
+ This method stores a list of extents into this storage object.
+
+Arguments:
+
+ NumberOfExtents -- Supplies the number of extents to store in
+ this chunk of the allocation tree.
+ ExtentList -- Supplies the extent list.
+ ParentIsFnode -- Supplies a flag which indicates, if TRUE, that
+ the parent of the structure which contains this
+ storage object is the FNode.
+
+Return Value:
+
+ TRUE upon successul completion.
+
+Notes:
+
+ The extent list might not start at VBN 0 (ie. it may be in the
+ middle of the file).
+
+--*/
+{
+ ALSEC ChildAlsec;
+ LBN ChildAlsecLbn;
+ ULONG MaximumLeaves, MaximumNodes, RemainingExtents, ExtentsPerChild,
+ ExtentsForCurrentChild, ChildIndex;
+
+ DebugAssert( NumberOfExtents == 0 || ExtentList != NULL );
+
+ // Determine whether this storage object will be a node or
+ // a leaf:
+ //
+ MaximumLeaves = (_IsFnode ? LeavesPerFnode : LeavesPerAlsec);
+
+ if( NumberOfExtents <= MaximumLeaves ) {
+
+ // All the extents will fit in this storage object. Jam
+ // those puppies in.
+ //
+ _pstd->alb.bFlag = ( ParentIsFnode ? ABF_FNP : 0 );
+ _pstd->alb.cFree = (UCHAR)(MaximumLeaves - NumberOfExtents);
+ _pstd->alb.cUsed = (UCHAR)NumberOfExtents;
+ _pstd->alb.oFree = sizeof( ALBLK ) +
+ NumberOfExtents * sizeof( ALLEAF );
+
+ memcpy( _pstd->a.alleaf,
+ ExtentList,
+ NumberOfExtents * sizeof( ALLEAF ) );
+
+ } else {
+
+ // The extent list will not fit into this storage object,
+ // so it will have to have children. The tricky part is
+ // deciding how to divvy up the extents among the children.
+ // Start out by assuming each subtree will consist of a single
+ // allocation sector. If this isn't sufficient to hold the
+ // number of extents that are to be stored, push another
+ // level--ie. introduce an ALSEC full of nodes between this
+ // object and the leave ALSECs. Keep pushing levels until
+ // we have a subtree big enough to hold the number of extents.
+ //
+ MaximumNodes = ( _IsFnode ? NodesPerFnode : NodesPerAlsec );
+
+ ExtentsPerChild = LeavesPerAlsec;
+
+ while( ExtentsPerChild * MaximumNodes < NumberOfExtents ) {
+
+ ExtentsPerChild *= NodesPerAlsec;
+ }
+
+ // Now spread the extents among the children.
+ //
+ RemainingExtents = NumberOfExtents;
+ ChildIndex = 0;
+
+ while( RemainingExtents != 0 ) {
+
+ DebugAssert( ChildIndex < MaximumNodes );
+
+ ExtentsForCurrentChild = min( ExtentsPerChild, RemainingExtents );
+
+ // Initialize an ALSEC object up front for all the children.
+ //
+ if( !ChildAlsec.Initialize( _Drive, 0 ) ) {
+
+ return FALSE;
+ }
+
+ // Allocate an ALSEC to be the root of the subtree, and
+ // pass the appropriate extents to it.
+ //
+ if( (ChildAlsecLbn =
+ VolumeBitmap->NearLBN( _CurrentLBN, 1 )) == 0 ) {
+
+ return FALSE;
+ }
+
+ ChildAlsec.Relocate( ChildAlsecLbn );
+ ChildAlsec.Create( _CurrentLBN, _IsFnode );
+
+ if( !ChildAlsec.StoreExtents( ExtentsForCurrentChild,
+ ExtentList +
+ ChildIndex * ExtentsPerChild,
+ _IsFnode,
+ VolumeBitmap ) ) {
+
+ return FALSE;
+ }
+
+ // Set up the node for this child:
+ //
+ _pstd->a.alnode[ChildIndex].lbnLog =
+ ExtentList[ChildIndex * ExtentsPerChild +
+ ExtentsForCurrentChild].lbnLog;
+ _pstd->a.alnode[ChildIndex].lbnPhys = ChildAlsecLbn;
+
+ RemainingExtents -= ExtentsForCurrentChild;
+
+ if( RemainingExtents == 0 ) {
+
+ // This is the last node. Set lbnLogical appropriately.
+ //
+ _pstd->a.alnode[ChildIndex].lbnLog = (LBN) -1;
+
+ } else {
+
+ // There are more extents beyond those given to this
+ // child, so lbnLog of this node is the beginning
+ // VBN of the first extent after those allocated to
+ // the current child.
+ //
+ _pstd->a.alnode[ChildIndex].lbnLog =
+ ExtentList[ (ChildIndex+1) * ExtentsPerChild ].lbnLog;
+ }
+
+ ChildIndex += 1;
+ }
+
+ _pstd->alb.bFlag = ( ParentIsFnode ? ABF_FNP : 0 ) | ABF_NODE;
+ _pstd->alb.cFree = (UCHAR)(MaximumNodes - ChildIndex);
+ _pstd->alb.cUsed = (UCHAR)ChildIndex;
+ _pstd->alb.oFree = sizeof( ALBLK ) + ChildIndex * sizeof( ALNODE );
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+STORE::TakeCensusAndClear(
+ IN OUT PHPFS_BITMAP VolumeBitmap,
+ IN OUT PHPFS_MAIN_BITMAP HpfsOnlyBitmap,
+ IN OUT PHPFS_CENSUS Census
+ )
+/*++
+
+Routine Description:
+
+ This method takes the census of the storage object. It also ensures
+ that the allocation associated with this storage object does not
+ conflict with the clear sectors of the census object.
+
+Arguments:
+
+ VolumeBitmap -- Supplies the volume bitmap.
+ HpfsOnlyBitmap -- Supplies the bitmap of HPFS file-system structures.
+ Census -- Supplies the census object.
+
+Return Value:
+
+ TRUE upon succesful completion.
+
+Notes:
+
+ This method will relocate runs if they conflict with the
+ clear sectors.
+
+--*/
+{
+ SECRUN DataRun;
+ HMEM DataBuffer;
+ ALSEC ChildAlsec;
+ LBN NewLbn, ConflictingLbn;
+ ULONG i;
+
+ if( _pstd->alb.bFlag & ABF_NODE ) {
+
+ // The entries in this storage object are allocation nodes.
+
+ // Set up an Allocation Sector to process the children.
+
+ if( !ChildAlsec.Initialize( _Drive, 0 ) ) {
+
+ return FALSE;
+ }
+
+ // Process each child allocation sector in turn.
+
+ for( i = 0; i < _pstd->alb.cUsed; i++ ) {
+
+ ChildAlsec.Relocate( (LBN)(_pstd->a.alnode[i].lbnPhys) );
+
+ if( !ChildAlsec.Read() ||
+ !ChildAlsec.IsAlsec() ) {
+
+ Census->SetError( HPFS_CENSUS_CORRUPT_VOLUME );
+ return FALSE;
+ }
+
+ if( !ChildAlsec.TakeCensusAndClear( VolumeBitmap,
+ HpfsOnlyBitmap,
+ Census ) ) {
+
+ return FALSE;
+ }
+ }
+
+ } else {
+
+ // The entries in this storage object are allocation leaves.
+ // I need to make sure that none of these leaves conflicts
+ // with the Clear Sectors of the census object.
+
+ for( i = 0; i < _pstd->alb.cUsed; i++ ) {
+
+
+ if( Census->ConflictWithClearSectors( _pstd->a.alleaf[i].lbnPhys,
+ _pstd->a.alleaf[i].csecRun,
+ &ConflictingLbn ) ) {
+
+ // This run conflicts. Relocate it.
+
+ if( !DataBuffer.Initialize() ||
+ !DataRun.Initialize( &DataBuffer,
+ _Drive,
+ _pstd->a.alleaf[i].lbnPhys,
+ _pstd->a.alleaf[i].csecRun ) ||
+ !DataRun.Read() ||
+ (NewLbn = VolumeBitmap->
+ NearLBN(_pstd->a.alleaf[i].lbnPhys,
+ _pstd->a.alleaf[i].csecRun )) == 0 ) {
+
+ Census->SetError( HPFS_CENSUS_RELOCATION_FAILED );
+ return FALSE;
+ }
+
+ DataRun.Relocate( NewLbn );
+
+ if( !DataRun.Write() ) {
+
+ Census->SetError( HPFS_CENSUS_RELOCATION_FAILED );
+ return FALSE;
+ }
+
+ // Free the old run, and then mark the census object's
+ // Clear Sectors in the bitmap (again) to make sure they
+ // don't get reallocated to anyone else.
+
+ VolumeBitmap->SetFree( _pstd->a.alleaf[i].lbnPhys,
+ _pstd->a.alleaf[i].csecRun );
+
+ Census->MarkClearSectors( VolumeBitmap );
+
+
+ // Update the allocation leaf and remember that this
+ // storage object has changed.
+
+ _pstd->a.alleaf[i].lbnPhys = NewLbn;
+ MarkModified();
+
+ // Inform the Census object that data has been
+ // relocated.
+
+ Census->SetRelocationPerformed();
+ }
+ }
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/uhpfs/src/superb.cxx b/private/utils/uhpfs/src/superb.cxx
new file mode 100644
index 000000000..463c7bb1f
--- /dev/null
+++ b/private/utils/uhpfs/src/superb.cxx
@@ -0,0 +1,327 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+#include "badblk.hxx"
+#include "bitmap.hxx"
+#include "error.hxx"
+#include "superb.hxx"
+
+
+DEFINE_CONSTRUCTOR( SUPERB, SECRUN );
+
+VOID
+SUPERB::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Constructor for SUPERB.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _psb = NULL;
+}
+
+
+SUPERB::~SUPERB(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for SUPERB.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+SUPERB::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a SUPERB to its initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _psb = NULL;
+}
+
+
+BOOLEAN
+SUPERB::Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes a SUPERB to a valid initial state.
+
+Arguments:
+
+ Mem - Supplies the memory for the super block.
+ Drive - Supplies the drive on which the super block resides.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ Destroy();
+
+ if (!SECRUN::Initialize(Mem, Drive, LBN_SUPERB, SUPERB_SECTORS)) {
+ Destroy();
+ return FALSE;
+ }
+
+ _psb = (_SUPERB*) GetBuf();
+
+ return TRUE;
+}
+
+
+BOOLEAN
+SUPERB::Create(
+ IN PCLOG_IO_DP_DRIVE Drive,
+ IN OUT PHPFS_BITMAP BitMap,
+ IN OUT PBADBLOCKLIST BadBlk,
+ IN LBN RootLbn,
+ IN LBN BmindLbn,
+ IN LBN BadBlkLbn,
+ IN SECTORCOUNT DirBandSc,
+ IN LBN FirstDirblkLbn,
+ IN LBN DirMapLbn,
+ IN LBN SidLbn
+ )
+/*++
+
+Routine Description:
+
+ This routine creates a super area.
+
+Arguments:
+
+ Drive - Supplies the drive on which the super block will be
+ created.
+ BitMap - Supplies the sector bitmap for the drive.
+ BadBlk - Supplies the bad block list.
+ RootLbn - Supplies the LBN of the root fnode.
+ BmindLbn - Supplies the LBN of the bit map indirect.
+ BadBlkLbn - Supplies the LBN of the first bad block.
+ DirBandSc - Supplies the number of sectors in the dir block band.
+ FirstDirblkLbn - Supplies the LBN of the first dir block.
+ DirMapLbn - Supplies the LBN of the dir block bit map.
+ SidLbn - Supplies the LBN of the sid table.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG SectorsOnVolume;
+
+ // Verify that construction was good and paramaters are sound.
+ if (!_psb || !Drive || !BitMap || !BadBlk) {
+ perrstk->push(ERR_SB_PARAMETER, QueryClassId());
+ return FALSE;
+ }
+
+ SectorsOnVolume = Drive->QuerySectors().GetLowPart();
+
+ // Zero fill secbuf.
+ memset(GetBuf(), 0, (UINT) Drive->QuerySectorSize());
+
+ // Set signatures and versions.
+ _psb->_sbi.sig1 = SIGSB1;
+ _psb->_sbi.sig2 = SIGSB2;
+ _psb->_sbi.bVersion = SUPERB_VERSION;
+
+ if( SectorsOnVolume >= BigDiskSectorCutoff ) {
+
+ // This disk is larger than the Big Disk cutoff; set
+ // the functional version to 3 to prevent earlier
+ // versions of HPFS from mucking it up.
+ //
+ _psb->_sbi.bFuncVersion = SUPERB_FVERSION_3;
+ _psb->_sbi.bFlags = SBF_BIGDISK;
+
+ } else {
+
+ // This disk is smaller than the Big Disk cutoff; set
+ // the functional version to 2 so earlier versions of
+ // HPFS can access it.
+ //
+ _psb->_sbi.bFuncVersion = SUPERB_FVERSION_2;
+ _psb->_sbi.bFlags = 0;
+ }
+
+ _psb->_sbi.usDummy = 0;
+
+ // Set the root fnode.
+ _psb->_sbi.lbnRootFNode = RootLbn;
+
+ // Compute the current number of sectors on the volume.
+ // Truncate to a multiple of 4.
+ _psb->_sbi.culSectsOnVol = SectorsOnVolume & ~3;
+ if (!_psb->_sbi.culSectsOnVol) {
+ perrstk->push(ERR_SB_PARAMETER, QueryClassId());
+ return FALSE;
+ }
+
+ // Mark partial block at end of disk as used.
+ if (!BitMap->SetAllocated(_psb->_sbi.culSectsOnVol,
+ Drive->QuerySectors().GetLowPart() -
+ _psb->_sbi.culSectsOnVol)) {
+ return FALSE;
+ }
+
+ // Compute the number of bad blocks on disk.
+
+ _psb->_sbi.culNumBadSects = BadBlk->QueryLength();
+
+ // Set rsp for the bit map indirect.
+ _psb->_sbi.lbnMainrspBitMapIndBlk = BmindLbn;
+ _psb->_sbi.lbnSparerspBitMapIndBlk = 0;
+
+ // Set rsp for bad block list.
+ _psb->_sbi.lbnMainrspBadBlkList = BadBlkLbn;
+ _psb->_sbi.lbnSparerspBadBlkList = 0;
+
+ // Set dates.
+ _psb->_sbi.datLastChkdsk = 0;
+ _psb->_sbi.datLastOptimize = 0;
+
+ // Set dir band and dir band bit map.
+ _psb->_sbi.clbndbnd = DirBandSc;
+ _psb->_sbi.lbndbndStart = FirstDirblkLbn;
+ _psb->_sbi.lbndbndEnd = FirstDirblkLbn + DirBandSc - 1;
+ _psb->_sbi.lbndbndbmStart = DirMapLbn;
+
+ // Set lbn of sid table.
+ _psb->_sbi.lbnSidTab = SidLbn;
+
+ return TRUE;
+}
+
+
+BOOLEAN
+SUPERB::Verify(
+ )
+/*++
+--*/
+{
+ if( !Read() ||
+ _psb->_sbi.sig1 != SIGSB1 ||
+ _psb->_sbi.sig2 != SIGSB2 ) {
+
+ // Not acceptable.
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+VOID
+SUPERB::Dump (
+ IN BOOLEAN TotalDump
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine dumps the super block data structure.
+
+Arguments:
+
+ TotalDump - Supplies whether or not to do a complete dump of all
+ the information.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ // unreferenced parameters
+ (void)(this);
+ (void)(TotalDump);
+
+// ULONG i;
+//
+// printf( "\n*** _SUPERB BEGIN ***\n" );
+//
+// printf( "\tSIG1:\t\t\t\t%#lX\n",_psb->_sbi.sig1 );
+// printf( "\tSIG2:\t\t\t\t%#lX\n",_psb->_sbi.sig2 );
+// printf( "\tVERSION:\t\t\t%u\n",_psb->_sbi.bVersion );
+// printf( "\tFUNC_VERSION:\t\t\t%u\n",_psb->_sbi.bFuncVersion );
+// printf( "\tLBN_ROOT_FNODE:\t\t\t%lx\n",_psb->_sbi.lbnRootFNode );
+// printf( "\tSECTS_ON_VOL:\t\t\t%lx\n",_psb->_sbi.culSectsOnVol );
+// printf( "\tNUM_BAD_SECTS:\t\t\t%lx\n",_psb->_sbi.culNumBadSects );
+// printf( "\tLBN_MAIN_BITMAP_IND_BLK:\t%lx\n", _psb->_sbi.lbnMainrspBitMapIndBlk );
+// printf( "\tLBN_SPARE_BITMAP_IND_BLK:\t%lx\n", _psb->_sbi.lbnSparerspBitMapIndBlk );
+// printf( "\tLBN_MAIN_BAD_BLOCK_LIST:\t%lx\n", _psb->_sbi.lbnMainrspBadBlkList );
+// printf( "\tLBN_SPARE_BAD_BLOCK_LIST:\t%lx\n", _psb->_sbi.lbnSparerspBadBlkList );
+// printf( "\tDATE_LAST_CHKDSK:\t\t%lx\n", _psb->_sbi.datLastChkdsk );
+// printf( "\tDATE_LAST_OPTIMIZE:\t\t%lx\n", _psb->_sbi.datLastOptimize );
+// printf( "\tCOUNT_LBN_DIR_BLK_BAND:\t\t%lx\n", _psb->_sbi.clbndbnd );
+// printf( "\tLBN_START_DIR_BLK_BAND:\t\t%lx\n", _psb->_sbi.lbndbndStart );
+// printf( "\tLBN_END_DIR_BLK_BAND:\t\t%lx\n", _psb->_sbi.lbndbndEnd );
+// printf( "\tLBN_START_DIR_BLK_BAND_BITMAP:\t%lx\n", _psb->_sbi.lbndbndbmStart );
+// printf( "\tVOLUME_NAME:\t\t\t%.*s\n", SUPERB_VOLNAME, _psb->_sbi.achVolName );
+// printf( "\tLBN_SID_TABLE:\t\t\t%lx\n", _psb->_sbi.lbnSidTab );
+//
+// if( TotalDump ) {
+// printf( "\tAB_FILL:\t\t\t" );
+// for( i = 0; i < ( cbSector - sizeof( _SUPERB_INFO )); i++ ) {
+// printf( "%u ", _psb->abFill[ i ] );
+// if( !(( i + 1 ) % 16 )) {
+// printf( "\n\t\t\t\t\t" );
+// }
+// }
+// }
+
+// printf( "\n*** _SUPERB END ***\n" );
+}
diff --git a/private/utils/uhpfs/src/uhpfs.cxx b/private/utils/uhpfs/src/uhpfs.cxx
new file mode 100644
index 000000000..e886e2869
--- /dev/null
+++ b/private/utils/uhpfs/src/uhpfs.cxx
@@ -0,0 +1,202 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ uhpfs.cxx
+
+Abstract:
+
+ This module contains run-time, global support for the
+ HPFS IFS Utilities library (UHPFS). This support includes:
+
+ - creation of CLASS_DESCRIPTORs
+ - Global objects
+
+Author:
+
+ Bill McJohn (billmc) 30-May-1991
+
+Environment:
+
+ User Mode
+
+Notes:
+
+--*/
+
+#include <pch.cxx>
+
+#define _UHPFS_MEMBER_
+
+#include "ulib.hxx"
+#include "uhpfs.hxx"
+
+#include "error.hxx"
+
+#if !defined( _AUTOCHECK_ )
+
+ ERRSTACK* perrstk;
+
+#endif // _AUTOCHECK_
+
+
+#if DBG==1
+ // this global buffer is used to support printf-style debug output
+ // (using sprintf).
+
+ CHAR DebugPrintBuffer[128];
+#endif
+
+
+
+// Local prototypes
+
+STATIC
+BOOLEAN
+DefineClassDescriptors(
+ );
+
+extern "C" BOOLEAN
+InitializeUhpfs (
+ PVOID DllHandle,
+ ULONG Reason,
+ PCONTEXT Context
+ );
+
+BOOLEAN
+InitializeUhpfs (
+ PVOID DllHandle,
+ ULONG Reason,
+ PCONTEXT Context
+ )
+/*++
+
+Routine Description:
+
+ Initialize Uhpfs by constructing and initializing all
+ global objects. These include:
+
+ - all CLASS_DESCRIPTORs (class_cd)
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if all global objects were succesfully constructed
+ and initialized.
+
+--*/
+
+{
+
+ STATIC BOOLEAN fInit = FALSE;
+
+ if ( fInit ) {
+
+ return( TRUE );
+ }
+
+ if ( DefineClassDescriptors() ) {
+
+ fInit = TRUE;
+ return TRUE;
+
+ } else {
+
+ DebugAbort( "Uhpfs initialization failed!!!\n" );
+ return( FALSE );
+ }
+}
+
+
+DECLARE_CLASS( ALSEC );
+DECLARE_CLASS( BADBLOCKLIST );
+DECLARE_CLASS( BITMAPINDIRECT );
+DECLARE_CLASS( CASEMAP );
+DECLARE_CLASS( UHPFS_CODEPAGE );
+DECLARE_CLASS( CPDATA );
+DECLARE_CLASS( CODEPAGE_INFO );
+DECLARE_CLASS( DEFERRED_ACTIONS_LIST );
+DECLARE_CLASS( DIRBLK );
+DECLARE_CLASS( DIRBLK_CACHE );
+DECLARE_CLASS( DIRBLK_CACHE_ELEMENT );
+DECLARE_CLASS( FNODE );
+DECLARE_CLASS( HOTFIXLIST );
+DECLARE_CLASS( HOTFIX_SECRUN );
+DECLARE_CLASS( HPFS_ACL );
+DECLARE_CLASS( HPFS_BITMAP );
+DECLARE_CLASS( HPFS_CENSUS );
+DECLARE_CLASS( HPFS_DIRECTORY_TREE );
+DECLARE_CLASS( HPFS_DIR_BITMAP );
+DECLARE_CLASS( HPFS_EA );
+DECLARE_CLASS( HPFS_EA_LIST );
+DECLARE_CLASS( HPFS_MAIN_BITMAP );
+DECLARE_CLASS( HPFS_NAME );
+DECLARE_CLASS( HPFS_ORPHAN );
+DECLARE_CLASS( HPFS_ORPHANS );
+DECLARE_CLASS( HPFS_ORPHAN_ALSEC );
+DECLARE_CLASS( HPFS_ORPHAN_DIRBLK );
+DECLARE_CLASS( HPFS_ORPHAN_FNODE );
+DECLARE_CLASS( HPFS_ORPHAN_LIST_HEAD );
+DECLARE_CLASS( HPFS_PATH );
+DECLARE_CLASS( HPFS_SA );
+DECLARE_CLASS( HPFS_VOL );
+DECLARE_CLASS( SIDTABLE );
+DECLARE_CLASS( SPAREB );
+DECLARE_CLASS( STORE );
+DECLARE_CLASS( SUPERB );
+
+STATIC
+BOOLEAN
+DefineClassDescriptors(
+ )
+{
+ if( DEFINE_CLASS_DESCRIPTOR( ALSEC ) &&
+ DEFINE_CLASS_DESCRIPTOR( BADBLOCKLIST ) &&
+ DEFINE_CLASS_DESCRIPTOR( BITMAPINDIRECT ) &&
+ DEFINE_CLASS_DESCRIPTOR( CASEMAP ) &&
+ DEFINE_CLASS_DESCRIPTOR( UHPFS_CODEPAGE ) &&
+ DEFINE_CLASS_DESCRIPTOR( CPDATA ) &&
+ DEFINE_CLASS_DESCRIPTOR( CODEPAGE_INFO ) &&
+ DEFINE_CLASS_DESCRIPTOR( DEFERRED_ACTIONS_LIST ) &&
+ DEFINE_CLASS_DESCRIPTOR( DIRBLK ) &&
+ DEFINE_CLASS_DESCRIPTOR( DIRBLK_CACHE ) &&
+ DEFINE_CLASS_DESCRIPTOR( DIRBLK_CACHE_ELEMENT ) &&
+ DEFINE_CLASS_DESCRIPTOR( FNODE ) &&
+ DEFINE_CLASS_DESCRIPTOR( HOTFIXLIST ) &&
+ DEFINE_CLASS_DESCRIPTOR( HOTFIX_SECRUN ) &&
+ DEFINE_CLASS_DESCRIPTOR( HPFS_ACL ) &&
+ DEFINE_CLASS_DESCRIPTOR( HPFS_BITMAP ) &&
+ DEFINE_CLASS_DESCRIPTOR( HPFS_CENSUS ) &&
+ DEFINE_CLASS_DESCRIPTOR( HPFS_DIRECTORY_TREE ) &&
+ DEFINE_CLASS_DESCRIPTOR( HPFS_DIR_BITMAP ) &&
+ DEFINE_CLASS_DESCRIPTOR( HPFS_EA ) &&
+ DEFINE_CLASS_DESCRIPTOR( HPFS_EA_LIST ) &&
+ DEFINE_CLASS_DESCRIPTOR( HPFS_MAIN_BITMAP ) &&
+ DEFINE_CLASS_DESCRIPTOR( HPFS_NAME ) &&
+ DEFINE_CLASS_DESCRIPTOR( HPFS_ORPHAN ) &&
+ DEFINE_CLASS_DESCRIPTOR( HPFS_ORPHANS ) &&
+ DEFINE_CLASS_DESCRIPTOR( HPFS_ORPHAN_ALSEC ) &&
+ DEFINE_CLASS_DESCRIPTOR( HPFS_ORPHAN_DIRBLK ) &&
+ DEFINE_CLASS_DESCRIPTOR( HPFS_ORPHAN_FNODE ) &&
+ DEFINE_CLASS_DESCRIPTOR( HPFS_ORPHAN_LIST_HEAD ) &&
+ DEFINE_CLASS_DESCRIPTOR( HPFS_PATH ) &&
+ DEFINE_CLASS_DESCRIPTOR( HPFS_SA ) &&
+ DEFINE_CLASS_DESCRIPTOR( HPFS_VOL ) &&
+ DEFINE_CLASS_DESCRIPTOR( SIDTABLE ) &&
+ DEFINE_CLASS_DESCRIPTOR( STORE ) &&
+ DEFINE_CLASS_DESCRIPTOR( SPAREB ) &&
+ DEFINE_CLASS_DESCRIPTOR( SUPERB ) ) {
+
+ return TRUE;
+
+ } else {
+
+ DebugPrint( "Could not initialize class descriptors!");
+ return FALSE;
+ }
+}
diff --git a/private/utils/uhpfs/src/uhpfs.def b/private/utils/uhpfs/src/uhpfs.def
new file mode 100644
index 000000000..41bf129fc
--- /dev/null
+++ b/private/utils/uhpfs/src/uhpfs.def
@@ -0,0 +1,10 @@
+LIBRARY UHPFS
+
+DESCRIPTION File System Utilities for HPFS
+
+DATA NONSHARED
+
+EXPORTS
+ Chkdsk
+ Format
+ Recover
diff --git a/private/utils/uhpfs/src/uhpfs.rc b/private/utils/uhpfs/src/uhpfs.rc
new file mode 100644
index 000000000..6a0ed194e
--- /dev/null
+++ b/private/utils/uhpfs/src/uhpfs.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "HPFS Utility DLL"
+#define VER_INTERNALNAME_STR "uhpfs\0"
+#define VER_ORIGINALFILENAME_STR "UHPFS.DLL"
+
+#include "common.ver"
diff --git a/private/utils/ulib/dirs b/private/utils/ulib/dirs
new file mode 100644
index 000000000..c4db5a979
--- /dev/null
+++ b/private/utils/ulib/dirs
@@ -0,0 +1,16 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+!ENDIF
+
+DIRS= src
diff --git a/private/utils/ulib/inc/achkmsg.hxx b/private/utils/ulib/inc/achkmsg.hxx
new file mode 100644
index 000000000..5c7f1f58f
--- /dev/null
+++ b/private/utils/ulib/inc/achkmsg.hxx
@@ -0,0 +1,164 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ achkmsg.hxx
+
+Abstract:
+
+
+Author:
+
+ Norbert P. Kusters (norbertk) 3-Jun-91
+
+--*/
+
+#if !defined( _AUTOCHECK_MESSAGE_DEFN_ )
+
+#define _AUTOCHECK_MESSAGE_DEFN_
+
+#include "message.hxx"
+#include "hmem.hxx"
+
+DECLARE_CLASS( AUTOCHECK_MESSAGE );
+
+class AUTOCHECK_MESSAGE : public MESSAGE {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( AUTOCHECK_MESSAGE );
+
+ VIRTUAL
+ ~AUTOCHECK_MESSAGE(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN BOOLEAN DotsOnly DEFAULT FALSE
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Set(
+ IN MSGID MsgId,
+ IN MESSAGE_TYPE MessageType DEFAULT NORMAL_MESSAGE,
+ IN ULONG MessageVisual DEFAULT NORMAL_VISUAL
+ );
+
+ VIRTUAL
+ BOOLEAN
+ DisplayV(
+ IN PCSTR Format,
+ IN va_list VarPointer
+ );
+
+ VIRTUAL
+ BOOLEAN
+ IsYesResponse(
+ IN BOOLEAN Default DEFAULT TRUE
+ );
+
+ VIRTUAL
+ PMESSAGE
+ Dup(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ IsLoggingEnabled(
+ );
+
+ VIRTUAL
+ VOID
+ SetLoggingEnabled(
+ IN BOOLEAN Enable DEFAULT TRUE
+ );
+
+ VIRTUAL
+ VOID
+ ResetLoggingIterator(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ QueryNextLoggedMessage(
+ OUT PFSTRING MessageText
+ );
+
+ VIRTUAL
+ BOOLEAN
+ SetDotsOnly(
+ IN BOOLEAN DotsState
+ );
+
+ VIRTUAL
+ BOOLEAN
+ WaitForUserSignal(
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ LogMessage(
+ PCWSTRING Message
+ );
+
+ HMEM _log_buffer;
+ ULONG _logged_chars;
+ ULONG _next_message_offset;
+ BOOLEAN _dots_only;
+ BOOLEAN _logging_enabled;
+
+ protected:
+
+ MSGID _msgid;
+
+};
+
+
+INLINE
+BOOLEAN
+AUTOCHECK_MESSAGE::Set(
+ IN MSGID MsgId,
+ IN MESSAGE_TYPE MessageType,
+ IN ULONG MessageVisual
+ )
+/*++
+
+Routine Description:
+
+ This routine sets up the class to display the message with the 'MsgId'
+ resource identifier.
+
+Arguments:
+
+ MsgId - Supplies the resource message id.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ (void) MessageType;
+ (void) MessageVisual;
+ _msgid = MsgId;
+ return TRUE;
+}
+
+#endif // _AUTOCHECK_MESSAGE_DEFN_
diff --git a/private/utils/ulib/inc/arg.hxx b/private/utils/ulib/inc/arg.hxx
new file mode 100644
index 000000000..50babee11
--- /dev/null
+++ b/private/utils/ulib/inc/arg.hxx
@@ -0,0 +1,1668 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ARGUMENT_LEXEMIZER
+
+Abstract:
+
+
+ This module contains the definition for the ARGUMENT_LEXEMIZER
+ class. The argument lexemizer is the engine of command-line
+ argument parsing.
+
+Author:
+
+ steve rowe stever 2/1/91
+
+Environment:
+
+ user
+
+Notes:
+
+ The argument lexemizer divides the command line arguments into
+ a series of lexemes, which are then matched argument patterns.
+
+ The way in which the command line is lexed is determined by
+ a few parameters, which are user-settable:
+
+ * White space
+ * Switch characters
+ * Separators
+ * Start of quote
+ * End of quote
+ * Multiple switches (i.e. what switches can be grouped)
+ * Metacharacters (used to escape the following character)
+ * Case sensitivity for switches
+ * "Glomming" of switches (see note at "GLOMMING").
+ * No space between tokens (specifically for xcopy)
+
+ The class provides defaults for all of the above.
+
+ After the command line has been lexed, the lexemizer is
+ given an ARRAY of argument objects. Each argument provides:
+
+ 1.- A pattern to match
+ 2.- A method for setting the argument value
+
+ The lexemizer will try to match each lexeme agains all the
+ arguments. When a match is found, the corresponding argument
+ value is set, the lexeme is consumed and it proceeds with the
+ next lexeme.
+
+ Schematically:
+
+
+
+
+ < Command Line >
+
+ |
+ | Argument
+ | ARRAY
+ v __________
+ +-----------+ [__________]
+ Settings--->| Lexemizer |<-------> [__________]
+ +-----------+ ^ [__________]
+ |
+ |
+ v
+ ( Matcher )
+
+
+
+
+ The matcher will try to match the lexeme provided by the
+ lexemizer and the pattern provided by the argument. If they
+ match, then the matcher asks the argument to set its value
+ (at this point, the argument might consume more lexemes from
+ the lexemizer). If the argument does not set its value, then
+ we will consider this a "no match", and the lexemizer will
+ try to match the lexeme against the following argument in
+ the ARRAY.
+
+ So, this is how to use this thing:
+
+
+ 1.- Initialize the lexemizer (with an empty ARRAY object):
+
+
+ ARGUMENT_LEXEMIZER ArgLex;
+ ARRAY SomeEmtpyArray;
+
+ SomeEmtryArray->Initialize();
+
+ ArgLex->Initialize(&SomeEmptyArray);
+
+
+
+ 2.- If we don't like some default, we change it:
+
+ ArgLex->PutSwitches("-/");
+ ArgLex->PutMetaCharacters("^");
+
+
+
+ 3.- Prepare the lexemizer for parsing. If we don't provide
+ a command line, it will take it from the environment.
+
+ ArgLex->PrepareToParse();
+
+
+
+ 4.- Define the arguments that our application will accept.
+ Initialize them with the pattern that they will match.
+ Put the argument in an ARRAY object. Note that the order
+ in which the arguments are in the array is important, since
+ that is the order in which they are matched.
+
+
+ ARRAY ArrayOfArg;
+ FLAG_ARGUMENT ArgRecursive; // Recursive flag
+ FLAG_ARGUMENT ArgVerbose; // Verbose flag
+
+ ArrayOfArg->Initialize();
+
+ ArgRecursive->Initialize("/R");
+ ArgVerbose->Initialize("/V");
+
+ ArrayOfArg->Put(&ArgRecursive);
+ ArrayOfArg->Put(&ArgVerbose);
+
+
+ 5.- Now let the lexemizer parse the arguments. If the parsing
+ returns TRUE, then all the command line was parsed correctly,
+ if it returns FALSE, then an error was found (e.g. invalid
+ argument):
+
+ if (!(ArgLex->DoParsing(&ArrayOfArg))) {
+
+ //
+ // Error, display usage
+ //
+ Usage();
+
+ }
+
+
+
+ 6.- Voila! We can now query our arguments for their value:
+
+
+ .
+ .
+ .
+ if (ArgRecursive->QueryFlag()) {
+ .
+ .
+ Do_recursive_stuff();
+ .
+ .
+
+
+
+ Warnings:
+
+ * The strings passed when setting options (such as switch
+ characters) have to remain in scope while the lexemizer is
+ being used, because the lexemizer keeps pointers to them.
+
+ * If after parsing the command line you want to change some
+ setting and parse the line again, you have to call the
+ PrepareToParse method after changing the setting and before
+ calling the DoParsing method. Note that in this case you
+ might want to use "fresh" argument objects, because most
+ arguments can only be set once.
+
+ * The method for querying the value of an argument is
+ argument-specific (no virtual method is provided).
+
+
+ * GLOMMING (mjb): This is something of a kludge I added to
+ allow xcopy to take switch arguments glommed together, as
+ in "/s/f/i/d" while not being confused by date arguments
+ such as "/d:8/24/95". This is handled similarly to the
+ "multiple switches"; only switches that are allowed to be
+ grouped may be glommed.
+
+ * NoSpcBetweenDstAndSwitch: This is a kludge to allow xcopy
+ to accept a destination path and a switch with no space
+ in between. The trick is to avoid being confused by date
+ arguments such as "/d:8/24/95".
+
+Revision History:
+
+
+--*/
+
+
+#include "array.hxx"
+#include "wstring.hxx"
+
+#if !defined( _AUTOCHECK_ )
+#include "timeinfo.hxx"
+#include "path.hxx"
+#endif
+
+
+//
+// Forward references
+//
+
+
+#if !defined (_ARGUMENT_LEXEMIZER_)
+
+#define _ARGUMENT_LEXEMIZER_
+
+DECLARE_CLASS( ARGUMENT_LEXEMIZER );
+DECLARE_CLASS( ARGUMENT );
+
+// Type of a pointer to the match function
+//
+typedef BOOLEAN (*PMATCHFUNCTION)(OUT PARGUMENT, OUT PARGUMENT_LEXEMIZER);
+
+class ARGUMENT_LEXEMIZER : public OBJECT {
+
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( ARGUMENT_LEXEMIZER );
+
+ VIRTUAL
+ ULIB_EXPORT
+ ~ARGUMENT_LEXEMIZER(
+ );
+
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize (
+ IN PARRAY LexemeArray
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ DoParsing (
+ IN PARRAY ArgumentArray
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ PWSTRING
+ GetLexemeAt (
+ IN ULONG Index
+ );
+
+ NONVIRTUAL
+ ULONG
+ IncrementConsumedCount (
+ IN ULONG HowMany DEFAULT 1
+ );
+
+ VOID
+ PutEndQuotes (
+ IN PCWSTRING QuoteChars
+ );
+
+ VOID
+ PutEndQuotes (
+ IN PCSTR QuoteChars
+ );
+
+ NONVIRTUAL
+ VOID
+ PutMetaChars (
+ IN PCSTR MetaChars
+ );
+
+ NONVIRTUAL
+ VOID
+ PutMetaChars (
+ IN PCWSTRING MetaChars
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ VOID
+ PutMultipleSwitch (
+ IN PCSTR MultipleSwitch
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ VOID
+ PutMultipleSwitch (
+ IN PCWSTRING MultipleSwitch
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ VOID
+ PutSeparators (
+ IN PCSTR Separators
+ );
+
+ NONVIRTUAL
+ VOID
+ PutSeparators (
+ IN PCWSTRING Separators
+ );
+
+ VOID
+ PutStartQuotes (
+ IN PCSTR QuoteChars
+ );
+
+ VOID
+ PutStartQuotes (
+ IN PCWSTRING QuoteChars
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ VOID
+ PutSwitches (
+ IN PCSTR Switches
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ VOID
+ PutSwitches (
+ IN PCWSTRING Switches
+ );
+
+ NONVIRTUAL
+ PCWSTRING
+ GetSwitches (
+ );
+
+ NONVIRTUAL
+ CHNUM
+ QueryCharPos (
+ IN ULONG LexemeNumber
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryConsumedCount (
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryLexemeCount (
+ ) CONST;
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ PWSTRING
+ QueryInvalidArgument (
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ PrepareToParse (
+ IN PWSTRING CommandLine DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ VOID
+ SetCaseSensitive (
+ BOOLEAN CaseSensitive
+ );
+
+ NONVIRTUAL
+ PCWSTRING
+ GetCmdLine(
+ ) CONST;
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ VOID
+ SetAllowSwitchGlomming (
+ BOOLEAN AllowGlomming
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ VOID
+ SetNoSpcBetweenDstAndSwitch (
+ BOOLEAN NoSpcBetweenDstAndSwitch
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PutCharPos (
+ IN ULONG Position,
+ IN CHNUM CharPos
+ );
+
+ PARRAY _parray; // Array of lexemes
+ PCHNUM _CharPos; // Character positions
+ ULONG _CharPosSize; // Size of _CharPos array
+ ULONG _ConsumedCount; // Lexemes consumed
+ ULONG _LexemeCount; // Total lexemes
+ DSTRING _WhiteSpace; // White space characters
+ DSTRING _SwitchChars; // Switch characters
+ DSTRING _Separators; // Separator characters
+ DSTRING _StartQuote; // Start of quote characters
+ DSTRING _SeparatorString; // All characters which cause separation
+ DSTRING _EndQuote; // End of quote characters
+ DSTRING _MultipleSwitches; // "Groupable" switches
+ DSTRING _MetaChars; // Meta-characters
+ BOOLEAN _CaseSensitive; // TRUE if case sensitive
+ BOOLEAN _AllowGlomming; // TRUE if switch glomming allowed
+ BOOLEAN _NoSpcBetweenDstAndSwitch; // TRUE if no space is required
+ // between tokens
+
+ WCHAR _Switch; // Switch character
+ DSTRING _CmdLine; // The entire command line
+
+};
+
+
+INLINE
+PCWSTRING
+ARGUMENT_LEXEMIZER::GetSwitches (
+ )
+
+/*++
+
+Routine Description:
+
+ Returns a ptr to a string containing the valid switch chars
+
+Arguments:
+
+ none
+
+Return Value:
+
+ Returns string containing the valid switch chars
+
+--*/
+{
+ return &_SwitchChars;
+}
+
+
+INLINE
+ULONG
+ARGUMENT_LEXEMIZER::IncrementConsumedCount (
+ IN ULONG HowMany
+ )
+/*++
+
+Routine Description:
+
+ Increments count of Lexemes consumed
+
+Arguments:
+
+ HowMany - Supplies by how many to increment.
+
+Return Value:
+
+ New count
+
+--*/
+{
+ return (_ConsumedCount += HowMany);
+}
+
+
+INLINE
+VOID
+ARGUMENT_LEXEMIZER::PutEndQuotes (
+ IN PCSTR QuoteChars
+ )
+/*++
+
+Routine Description:
+
+ Initializes the ending quote chars
+
+Arguments:
+
+ QuoteChars - Supplies pointer to string of close quote chars
+
+Return Value:
+
+ none
+--*/
+{
+ DebugPtrAssert( QuoteChars );
+ _EndQuote.Initialize(QuoteChars);
+}
+
+
+INLINE
+VOID
+ARGUMENT_LEXEMIZER::PutEndQuotes (
+ IN PCWSTRING QuoteChars
+ )
+/*++
+
+Routine Description:
+
+ Initializes the ending quote chars
+
+Arguments:
+
+ QuoteChars - Supplies pointer to string of close quote chars
+
+Return Value:
+
+ none
+--*/
+{
+ DebugPtrAssert( QuoteChars );
+ _EndQuote.Initialize(QuoteChars);
+}
+
+
+INLINE
+VOID
+ARGUMENT_LEXEMIZER::PutStartQuotes (
+ IN PCSTR QuoteChars
+ )
+/*++
+
+Routine Description:
+
+ Initializes the starting quote chars
+
+Arguments:
+
+ QuoteChars - Supplies pointer to string of open quote chars
+
+Return Value:
+
+ none
+--*/
+{
+ DebugPtrAssert( QuoteChars );
+ _StartQuote.Initialize(QuoteChars);
+}
+
+
+INLINE
+VOID
+ARGUMENT_LEXEMIZER::PutStartQuotes (
+ IN PCWSTRING QuoteChars
+ )
+/*++
+
+Routine Description:
+
+ Initializes the starting quote chars
+
+Arguments:
+
+ QuoteChars - Supplies pointer to string of open quote chars
+
+Return Value:
+
+ none
+--*/
+{
+ DebugPtrAssert( QuoteChars );
+ _StartQuote.Initialize(QuoteChars);
+}
+
+
+INLINE
+ULONG
+ARGUMENT_LEXEMIZER::QueryConsumedCount (
+ )
+/*++
+
+Routine Description:
+
+ Returns number of lexemes consumed
+
+Arguments:
+
+ none
+
+Return Value:
+
+ Number of lexemes consumed
+
+--*/
+{
+ return _ConsumedCount;
+}
+
+
+INLINE
+ULONG
+ARGUMENT_LEXEMIZER::QueryLexemeCount (
+ ) CONST
+/*++
+
+Routine Description:
+
+ Returns total number of lexemes
+
+Arguments:
+
+ none
+
+Return Value:
+
+ Total number of lexemes
+
+--*/
+{
+ return _LexemeCount;
+}
+
+INLINE
+PCWSTRING
+ARGUMENT_LEXEMIZER::GetCmdLine(
+ ) CONST
+/*++
+
+Routine Description:
+
+ Returns the original commmand line.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The original command line.
+
+--*/
+{
+ return &_CmdLine;
+}
+
+
+#endif // _ARGUMENT_LEXEMIZER_
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ARGUMENT
+
+Abstract:
+
+ Base class for arguments.
+
+Author:
+
+ steve rowe stever 2/1/91
+
+[Environment:]
+
+ optional-environment-info (e.g. kernel mode only...)
+
+Notes:
+
+
+
+Revision History:
+
+--*/
+
+#if !defined (_ARGUMENT_)
+
+#define _ARGUMENT_
+
+
+class ARGUMENT : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( ARGUMENT );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ IN PSTR Pattern
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ IN PWSTRING Pattern
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ PWSTRING
+ GetLexeme (
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ PWSTRING
+ GetPattern (
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ IsValueSet (
+ );
+
+ VIRTUAL
+ BOOLEAN
+ SetIfMatch (
+ OUT PARGUMENT_LEXEMIZER ArgumentLexemizer,
+ IN BOOLEAN CaseSensitive
+ );
+
+ VIRTUAL
+ BOOLEAN
+ SetValue (
+ IN PWSTRING Arg,
+ IN CHNUM chnIdx,
+ IN CHNUM chnEnd,
+ IN PARGUMENT_LEXEMIZER ArgumentLexemizer
+ );
+
+
+ protected:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ BOOLEAN _fValueSet; // TRUE when value set
+ PWSTRING _Lexeme; // Matched Lexeme
+ DSTRING _Pattern; // Pattern
+
+};
+
+#endif // _ARGUMENT
+
+
+
+
+
+
+
+
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ FLAG_ARGUMENT
+
+Abstract:
+
+ Argument class for flags and switches.
+
+Author:
+
+ steve rowe stever 2/1/91
+
+Revision History:
+
+--*/
+
+#if !defined ( _FLAG_ARGUMENT_ )
+
+#define _FLAG_ARGUMENT_
+
+DECLARE_CLASS( FLAG_ARGUMENT );
+
+class FLAG_ARGUMENT : public ARGUMENT {
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( FLAG_ARGUMENT );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize (
+ IN PSTR Pattern
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize (
+ IN PWSTRING Pattern
+ );
+
+ VIRTUAL
+ BOOLEAN
+ SetValue (
+ IN PWSTRING Arg,
+ IN CHNUM chnIdx,
+ IN CHNUM chnEnd,
+ IN PARGUMENT_LEXEMIZER ArgumentLexemizer
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryFlag (
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ BOOLEAN _flag; // TRUE if flag (switch) set
+
+};
+
+INLINE
+BOOLEAN
+FLAG_ARGUMENT::QueryFlag (
+ )
+/*++
+
+Routine Description:
+
+ Returns TRUE if flag set
+
+Arguments:
+
+ none
+
+Return Value:
+
+ TRUE if flag set. FALSE otherwise
+
+--*/
+{
+ return _flag;
+}
+
+#endif // _FLAG_ARGUMENT_
+
+
+
+
+
+
+
+
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ STRING_ARGUMENT
+
+Abstract:
+
+ Argument class for strings.
+
+Author:
+
+ steve rowe stever 2/1/91
+
+Revision History:
+
+--*/
+
+#if !defined ( _STRING_ARGUMENT_ )
+
+#define _STRING_ARGUMENT_
+
+DECLARE_CLASS( STRING_ARGUMENT );
+
+class STRING_ARGUMENT : public ARGUMENT {
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( STRING_ARGUMENT );
+
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ ~STRING_ARGUMENT(
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize (
+ IN PSTR Pattern
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ IN PWSTRING Pattern
+ );
+
+ NONVIRTUAL
+ PWSTRING
+ GetString (
+ );
+
+ VIRTUAL
+ BOOLEAN
+ SetValue (
+ IN PWSTRING Arg,
+ IN CHNUM chnIdx,
+ IN CHNUM chnEnd,
+ IN PARGUMENT_LEXEMIZER ArgumentLexemizer
+ );
+
+ protected:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+
+ PWSTRING _String; // Pointer to the string
+
+};
+
+INLINE
+PWSTRING
+STRING_ARGUMENT::GetString (
+ )
+/*++
+
+Routine Description:
+
+ Returns pointer to the string
+
+Arguments:
+
+ none
+
+Return Value:
+
+ pointer to the string
+
+--*/
+{
+ DebugAssert( _fValueSet );
+
+ return _String;
+}
+
+#endif // _STRING_ARGUMENT_
+
+
+
+
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ LONG_ARGUMENT
+
+Abstract:
+
+ Argument class for long integers.
+
+Author:
+
+ steve rowe stever 2/1/91
+
+Revision History:
+
+--*/
+
+#if !defined ( _LONG_ARGUMENT_ )
+
+#define _LONG_ARGUMENT_
+
+DECLARE_CLASS( LONG_ARGUMENT );
+
+class LONG_ARGUMENT : public ARGUMENT {
+
+ public:
+
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( LONG_ARGUMENT );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize (
+ IN PSTR Pattern
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ IN PWSTRING Pattern
+ );
+
+ VIRTUAL
+ BOOLEAN
+ SetValue (
+ IN PWSTRING Arg,
+ IN CHNUM chnIdx,
+ IN CHNUM chnEnd,
+ IN PARGUMENT_LEXEMIZER ArgumentLexemizer
+ );
+
+ NONVIRTUAL
+ LONG
+ QueryLong (
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ LONG _value; // Long value
+
+};
+
+INLINE
+LONG
+LONG_ARGUMENT::QueryLong (
+ )
+/*++
+
+Routine Description:
+
+ Returns value of the long argument
+
+Arguments:
+
+ none
+
+Return Value:
+
+ value of the argument
+
+--*/
+{
+ DebugAssert( _fValueSet );
+
+ return _value;
+}
+
+#endif // _LONG_ARGUMENT_
+
+
+
+#if !defined( _AUTOCHECK_ )
+
+
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ PATH_ARGUMENT
+
+Abstract:
+
+ Argument class for paths.
+
+Author:
+
+ steve rowe stever 2/1/91
+
+Revision History:
+
+--*/
+
+#if !defined( _PATH_ARGUMENT_ )
+
+#define _PATH_ARGUMENT_
+
+DECLARE_CLASS( PATH_ARGUMENT );
+
+class PATH_ARGUMENT : public ARGUMENT {
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( PATH_ARGUMENT );
+
+ ULIB_EXPORT
+ NONVIRTUAL
+ ~PATH_ARGUMENT (
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize (
+ IN PSTR Pattern,
+ IN BOOLEAN Canonicalize DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ IN PWSTRING Pattern,
+ IN BOOLEAN Canonicalize DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ PPATH
+ GetPath (
+ );
+
+ VIRTUAL
+ BOOLEAN
+ SetValue (
+ IN PWSTRING Arg,
+ IN CHNUM chnIdx,
+ IN CHNUM chnEnd,
+ IN PARGUMENT_LEXEMIZER ArgumentLexemizer
+ );
+
+ protected:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+
+ PPATH _Path; // Pointer to the path
+ BOOLEAN _Canonicalize; // Canonicalization flag
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Destroy (
+ );
+
+};
+
+INLINE
+PPATH
+PATH_ARGUMENT::GetPath (
+ )
+/*++
+
+Routine Description:
+
+ Returns pointer to the path
+
+Arguments:
+
+ none
+
+Return Value:
+
+ pointer to the path
+
+--*/
+{
+ DebugAssert( _fValueSet );
+
+ return _Path;
+}
+
+#endif // _PATH_ARGUMENT_
+
+
+#endif // _AUTOCHECK_
+
+
+
+#if !defined( _AUTOCHECK_ )
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ MULTIPLE_PATH_ARGUMENT
+
+Abstract:
+
+ Provide for access to command line arguments that are file or path names.
+
+Author:
+
+ steve rowe stever 2/1/91
+
+Environment:
+
+ user
+
+Revision History:
+
+
+--*/
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ MULTIPLE_PATH_ARGUMENT
+
+Abstract:
+
+ Hold multiple file names on command line.
+
+Author:
+
+ steve rowe stever 2/1/91
+
+
+Revision History:
+
+--*/
+
+#if !defined ( _MULTIPLE_PATH_ARGUMENT_ )
+
+#define _MULTIPLE_PATH_ARGUMENT_
+
+DECLARE_CLASS( MULTIPLE_PATH_ARGUMENT );
+
+class MULTIPLE_PATH_ARGUMENT : public PATH_ARGUMENT {
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( MULTIPLE_PATH_ARGUMENT );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ ~MULTIPLE_PATH_ARGUMENT (
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize (
+ IN PSTR Pattern,
+ IN BOOLEAN Canonicalize DEFAULT FALSE,
+ IN BOOLEAN ExpandWildCards DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ IN PWSTRING Pattern,
+ IN BOOLEAN Canonicalize DEFAULT FALSE,
+ IN BOOLEAN ExpandWildCards DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ PCWSTRING
+ GetLexemeThatFailed (
+ );
+
+ NONVIRTUAL
+ PARRAY
+ GetPathArray (
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryPathCount (
+ );
+
+ VIRTUAL
+ BOOLEAN
+ SetValue (
+ IN PWSTRING pwcArg,
+ IN CHNUM chnIdx,
+ IN CHNUM chnEnd,
+ IN PARGUMENT_LEXEMIZER ArgumentLexemizer
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ WildCardExpansionFailed (
+ );
+
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy (
+ );
+
+ PARRAY _PathArray;
+ ULONG _PathCount;
+ BOOLEAN _ExpandWildCards;
+ BOOLEAN _WildCardExpansionFailed;
+ DSTRING _LexemeThatFailed;
+};
+
+
+INLINE
+PCWSTRING
+MULTIPLE_PATH_ARGUMENT::GetLexemeThatFailed (
+ )
+/*++
+
+Routine Description:
+
+ Gets the lexeme that failed in case of a wildcard expansion failure
+
+Arguments:
+
+ none
+
+Return Value:
+
+ Pointer to the lexeme that failed
+
+--*/
+{
+ return _WildCardExpansionFailed ? (PCWSTRING)&_LexemeThatFailed : NULL;
+}
+
+
+INLINE
+PARRAY
+MULTIPLE_PATH_ARGUMENT::GetPathArray (
+ )
+/*++
+
+Routine Description:
+
+ Returns pointer to the path array
+
+Arguments:
+
+ none
+
+Return Value:
+
+ pointer to the path array
+
+--*/
+{
+ return _PathArray;
+}
+
+INLINE
+ULONG
+MULTIPLE_PATH_ARGUMENT::QueryPathCount (
+ )
+/*++
+
+Routine Description:
+
+ Returns number of paths in the array
+
+Arguments:
+
+ none
+
+Return Value:
+
+ Number of paths in the array
+
+--*/
+{
+ return _PathCount;
+}
+
+
+
+INLINE
+BOOLEAN
+MULTIPLE_PATH_ARGUMENT::WildCardExpansionFailed (
+ )
+/*++
+
+Routine Description:
+
+ Tells the caller if wildcard expansion failed
+
+Arguments:
+
+ none
+
+Return Value:
+
+ BOOLEAN - TRUE if wildcard expansion failed
+
+--*/
+{
+ return _WildCardExpansionFailed;
+}
+
+#endif // _MULTIPLE_PATH_ARGUMENT_
+
+
+#endif // _AUTOCHECK_
+
+
+
+#if !defined( _AUTOCHECK_ )
+
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ TIMEINFO_ARGUMENT
+
+Abstract:
+
+ Argument class for time information.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) May-15-1991
+
+Revision History:
+
+--*/
+
+#if !defined ( _TIMEINFO_ARGUMENT_ )
+
+#define _TIMEINFO_ARGUMENT_
+
+DECLARE_CLASS( TIMEINFO_ARGUMENT );
+
+class TIMEINFO_ARGUMENT : public ARGUMENT {
+
+ public:
+
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( TIMEINFO_ARGUMENT );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ ~TIMEINFO_ARGUMENT(
+ );
+
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize (
+ IN PSTR Pattern
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ IN PWSTRING Pattern
+ );
+
+ VIRTUAL
+ BOOLEAN
+ SetValue (
+ IN PWSTRING Arg,
+ IN CHNUM chnIdx,
+ IN CHNUM chnEnd,
+ IN PARGUMENT_LEXEMIZER ArgumentLexemizer
+ );
+
+ NONVIRTUAL
+ PTIMEINFO
+ GetTimeInfo (
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ PTIMEINFO _TimeInfo; // Time info.
+
+};
+
+INLINE
+PTIMEINFO
+TIMEINFO_ARGUMENT::GetTimeInfo (
+ )
+/*++
+
+Routine Description:
+
+ Returns pointer to the time information
+
+Arguments:
+
+ none
+
+Return Value:
+
+ Pointer to time info.
+
+--*/
+{
+ DebugAssert( _fValueSet );
+
+ return _TimeInfo;
+}
+
+#endif // _TIMEINFO_ARGUMENT_
+
+
+
+#endif // _AUTOCHECK_
+
+
+
+
+#if !defined( _AUTOCHECK_ )
+
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ TIMEINFO_ARGUMENT
+
+Abstract:
+
+ Argument class for time information.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) May-15-1991
+
+Revision History:
+
+--*/
+
+#if !defined ( _REST_OF_LINE_ARGUMENT_ )
+
+#define _REST_OF_LINE_ARGUMENT_
+
+DECLARE_CLASS( REST_OF_LINE_ARGUMENT );
+
+class REST_OF_LINE_ARGUMENT : public ARGUMENT {
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( REST_OF_LINE_ARGUMENT );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ SetIfMatch(
+ IN OUT PARGUMENT_LEXEMIZER ArgumentLexemizer,
+ IN BOOLEAN CaseSensitive
+ );
+
+ NONVIRTUAL
+ PCWSTRING
+ GetRestOfLine(
+ ) CONST;
+
+ private:
+
+ DSTRING _RestOfLine;
+
+};
+
+
+INLINE
+PCWSTRING
+REST_OF_LINE_ARGUMENT::GetRestOfLine(
+ ) CONST
+/*++
+
+Routine Description:
+
+ Returns pointer to the macro argument.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ A pointer to the macro argument.
+
+--*/
+{
+ DebugAssert( _fValueSet );
+
+ return &_RestOfLine;
+}
+
+#endif // _REST_OF_LINE_ARGUMENT_
+
+
+
+#endif // _AUTOCHECK_
+
diff --git a/private/utils/ulib/inc/array.hxx b/private/utils/ulib/inc/array.hxx
new file mode 100644
index 000000000..82626b173
--- /dev/null
+++ b/private/utils/ulib/inc/array.hxx
@@ -0,0 +1,390 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ array.hxx
+
+Abstract:
+
+ This module contains the declaration for the ARRAY class.
+
+ ARRAY is a concrete implementation of a dynamic (i.e. growable) array
+ derived from the abstract class SORTABLE_CONTAINER.
+
+ ARRAY's support one 'writer' (i.e. one client poutting OBJECTs into
+ the ARRAY) and multiple readers via an ITERATOR. It is the client's
+ responsibility to synchronize multiple writers.
+
+ The ARRAY does not contain holes, i.e. all elements of the array (up
+ to QueryMemberCount() ) have objects.
+
+
+Author:
+
+ David J. Gilman (davegi) 31-Oct-1990
+
+Environment:
+
+ ULIB, User Mode
+
+Notes:
+
+
+--*/
+
+#if ! defined( _ARRAY_ )
+
+#define _ARRAY_
+
+#include "sortcnt.hxx"
+
+//
+// Forward references
+//
+DECLARE_CLASS( ARRAY );
+DECLARE_CLASS( ARRAY_ITERATOR );
+DECLARE_CLASS( SORTED_LIST );
+
+//
+// Pointer to array of POBJECTs
+//
+typedef POBJECT* PPOBJECT;
+
+//
+// Default values for an ARRAY object.
+//
+// - Capacity is the total number of elements that can be stored in an ARRAY
+// - CapacityIncrement is the number of elemnts that the ARRAY's Capacity
+// will be increased by when it's Capacity is exceeded
+//
+CONST ULONG DefaultCapacity = 50;
+CONST ULONG DefaultCapacityIncrement = 25;
+
+//
+// Invalid index within the array
+//
+CONST ULONG INVALID_INDEX = (ULONG)(-1);
+
+
+class ARRAY : public SORTABLE_CONTAINER {
+
+ friend ARRAY_ITERATOR;
+ friend SORTED_LIST;
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( ARRAY );
+
+ DECLARE_CAST_MEMBER_FUNCTION( ARRAY );
+
+ VIRTUAL
+ ULIB_EXPORT
+ ~ARRAY(
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize (
+ IN ULONG Capacity DEFAULT DefaultCapacity,
+ IN ULONG CapacityIncrement DEFAULT DefaultCapacityIncrement
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ DeleteAllMembers(
+ );
+
+ VIRTUAL
+ POBJECT
+ GetAt(
+ IN ULONG Index
+ ) CONST;
+
+ VIRTUAL
+ ULONG
+ GetMemberIndex(
+ IN POBJECT Object
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ ULIB_EXPORT
+ Put(
+ IN OUT POBJECT Member
+ );
+
+ VIRTUAL
+ BOOLEAN
+ PutAt(
+ IN OUT POBJECT Member,
+ IN ULONG Index
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryCapacity (
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QueryCapacityIncrement (
+ ) CONST;
+
+ VIRTUAL
+ ULIB_EXPORT
+ PITERATOR
+ QueryIterator(
+ ) CONST;
+
+ VIRTUAL
+ ULONG
+ QueryMemberCount(
+ ) CONST;
+
+ VIRTUAL
+ ULIB_EXPORT
+ POBJECT
+ Remove(
+ IN OUT PITERATOR Position
+ );
+
+ VIRTUAL
+ POBJECT
+ RemoveAt(
+ IN ULONG Index
+ );
+
+ NONVIRTUAL
+ ULONG
+ SetCapacity (
+ IN ULONG Capacity
+ );
+
+ NONVIRTUAL
+ VOID
+ SetCapacityIncrement (
+ IN ULONG CapacityIncrement
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Sort(
+ IN BOOLEAN Ascending DEFAULT TRUE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Insert(
+ IN OUT POBJECT Member,
+ IN ULONG Index
+ );
+
+
+ protected:
+
+ STATIC
+ LONG
+ CompareAscDesc(
+ IN POBJECT Object1,
+ IN POBJECT Object2,
+ IN BOOLEAN Ascending DEFAULT TRUE
+ );
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ PPOBJECT
+ GetObjectArray (
+ );
+
+ private:
+
+ NONVIRTUAL
+ ULONG
+ SetArrayCapacity(
+ IN ULONG NumberOfElements
+ );
+
+ STATIC
+ int _CRTAPI1
+ CompareAscending (
+ IN const void * Object1,
+ IN const void * Object2
+ );
+
+ STATIC
+ int _CRTAPI1
+ CompareDescending (
+ IN const void * Object1,
+ IN const void * Object2
+ );
+
+ PPOBJECT _ObjectArray; // Array of pointers to OBJECTs
+ ULONG _PutIndex; // Put Index
+ ULONG _Capacity; // Capacity of the array
+ ULONG _CapacityIncrement; // Increment
+
+#if DBG==1
+ ULONG _IteratorCount; // Count of iterators
+#endif
+
+};
+
+
+INLINE
+ULONG
+ARRAY::QueryCapacity (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the current capacity (maximum number of members) of the ARRAY.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - Current capacity.
+
+
+--*/
+
+{
+ return( _Capacity );
+}
+
+
+
+INLINE
+ULONG
+ARRAY::QueryCapacityIncrement (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the current capacity increment (realloc amount) of the ARRAY.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - Current capacity increment.
+
+--*/
+
+{
+ return( _CapacityIncrement );
+}
+
+
+
+INLINE
+VOID
+ARRAY::SetCapacityIncrement (
+ IN ULONG CapacityIncrement
+ )
+
+/*++
+
+Routine Description:
+
+ Set the capacity incement value.
+
+Arguments:
+
+ CapacityIncrement - Supplies the new value for the capacity increment.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _CapacityIncrement = CapacityIncrement;
+}
+
+
+
+INLINE
+LONG
+ARRAY::CompareAscDesc(
+ IN POBJECT Object1,
+ IN POBJECT Object2,
+ IN BOOLEAN Ascending
+ )
+/*++
+
+Routine Description:
+
+ Compares two object accordint to an Ascending flag
+
+Arguments:
+
+ Object1 - Supplies first object
+ Object2 - Supplies second object
+ Ascending - Supplies ascending flag
+
+Return Value:
+
+ LONG - If Ascending:
+ <0 if Object1 is less that Object2
+ 0 if Object1 is equal to Object2
+ >0 if Object1 is greater than Object2
+
+ If !Ascending:
+ <0 if Object2 is less that Object1
+ 0 if Object2 is equal to Object1
+ >0 if Object2 is greater than Object1
+
+
+--*/
+{
+ return ( Ascending ? CompareAscending( &Object1, &Object2 ) :
+ CompareDescending( &Object1, &Object2) );
+}
+
+
+
+INLINE
+PPOBJECT
+ARRAY::GetObjectArray (
+ )
+/*++
+
+Routine Description:
+
+ Obtains pointer to the array of objects
+
+Arguments:
+
+ None
+
+Return Value:
+
+ PPOBJECT - Pointer to array of objects
+
+--*/
+
+{
+ return _ObjectArray;
+}
+
+#endif // _ARRAY_
+
diff --git a/private/utils/ulib/inc/arrayit.hxx b/private/utils/ulib/inc/arrayit.hxx
new file mode 100644
index 000000000..1d75de789
--- /dev/null
+++ b/private/utils/ulib/inc/arrayit.hxx
@@ -0,0 +1,125 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ arrayit.hxx
+
+Abstract:
+
+ This module contains the declaration for the ARRAY_ITERATOR class.
+ ARRAY_ITERATOR is a concrete implementation derived from the abstarct
+ ITERATOR class. It is used to 'read' (iterate) over an ARRAY object.
+ It has no public constructor and therefore can only be queried from an
+ ARRAY object. It is the client's responsibility to detsroy
+ ARRAY_ITERATORs when they are done. ARRAY_ITERATORs maintain the currency
+ for reading an ARRAY in order.
+
+Author:
+
+ David J. Gilman (davegi) 29-Oct-1990
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if ! defined( _ARRAY_ITERATOR_ )
+
+#define _ARRAY_ITERATOR_
+
+#include "iterator.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( ARRAY );
+DECLARE_CLASS( ARRAY_ITERATOR );
+
+
+class ARRAY_ITERATOR : public ITERATOR {
+
+ friend ARRAY;
+
+ public:
+
+ VIRTUAL
+ ~ARRAY_ITERATOR(
+ );
+
+ VIRTUAL
+ VOID
+ Reset(
+ );
+
+ VIRTUAL
+ POBJECT
+ GetCurrent(
+ );
+
+ VIRTUAL
+ POBJECT
+ GetNext(
+ );
+
+ VIRTUAL
+ POBJECT
+ GetPrevious(
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryCurrentIndex(
+ );
+
+ protected:
+
+ DECLARE_CAST_MEMBER_FUNCTION( ARRAY_ITERATOR );
+ DECLARE_CONSTRUCTOR( ARRAY_ITERATOR );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN OUT PARRAY Array
+ );
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ private:
+
+ PARRAY _Array; // Array
+ ULONG _CurrentIndex; // Current index
+
+};
+
+
+INLINE
+ULONG
+ARRAY_ITERATOR::QueryCurrentIndex(
+ )
+/*++
+
+Routine Description:
+
+ Obtains the current index
+
+Arguments:
+
+ None
+
+Return Value:
+
+ ULONG - The current index
+
+--*/
+
+{
+ return _CurrentIndex;
+}
+#endif // _ARRAY_ITERATOR_
diff --git a/private/utils/ulib/inc/basesys.hxx b/private/utils/ulib/inc/basesys.hxx
new file mode 100644
index 000000000..8d4409016
--- /dev/null
+++ b/private/utils/ulib/inc/basesys.hxx
@@ -0,0 +1,57 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ basesys.hxx
+
+Abstract:
+
+ BASE_SYSTEM is the a base class for SYSTEM. It is created so
+ encapsulate the methods on SYSTEM that are used for AUTOCHK.
+
+Author:
+
+ David J. Gilman (davegi) 13-Jan-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if !defined( _BASE_SYSTEM_DEFN_ )
+
+#define _BASE_SYSTEM_DEFN_
+
+#include "message.hxx"
+
+
+class BASE_SYSTEM {
+
+ public:
+
+ STATIC
+ ULIB_EXPORT
+ BOOLEAN
+ QueryResourceString(
+ OUT PWSTRING ResourceString,
+ IN MSGID MsgId,
+ IN PCSTR Format ...
+ );
+
+ STATIC
+ ULIB_EXPORT
+ BOOLEAN
+ QueryResourceStringV(
+ OUT PWSTRING ResourceString,
+ IN MSGID MsgId,
+ IN PCSTR Format,
+ IN va_list VarPointer
+ );
+
+};
+
+
+#endif // _BASE_SYSTEM_DEFN_
diff --git a/private/utils/ulib/inc/bitvect.hxx b/private/utils/ulib/inc/bitvect.hxx
new file mode 100644
index 000000000..1b851740b
--- /dev/null
+++ b/private/utils/ulib/inc/bitvect.hxx
@@ -0,0 +1,447 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ bitvect.hxx
+
+Abstract:
+
+ This module contains the definition for the BITVECTOR class. BITVECTOR
+ is a concrete class which implements a bit array.
+
+Author:
+
+ David J. Gilman (davegi) 13-Jan-1991
+
+Environment:
+
+ ULIB, User Mode
+
+Notes:
+
+ BITVECTOR is an implementation of a general purpose bit
+ vector. It is based around an abstract type called PT
+ (Primitive Type) to increase it's portability. BITVECTORs
+ can be created of arbitrary size. If required they will
+ allocate memory to maintain the bits or will use a memory
+ buffer supplied by the client. This allows the client to
+ superimpose a bit vector onto a predefined buffer (e.g. onto
+ a SECBUF).
+
+--*/
+#if ! defined ( _BITVECTOR_ )
+
+#define _BITVECTOR_
+
+DECLARE_CLASS( BITVECTOR );
+
+
+// extern ERRSTACK *perrstk; // pointer to error stack
+
+//
+// BITVECTOR allocation increment - Primitive Type
+//
+
+DEFINE_TYPE( ULONG, PT );
+
+//
+// BIT values
+//
+
+enum BIT {
+ SET = 1,
+ RESET = 0
+};
+
+//
+// Invalid bit count
+//
+
+extern CONST PT InvalidBitCount;
+
+class BITVECTOR : public OBJECT {
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( BITVECTOR );
+
+ DECLARE_CAST_MEMBER_FUNCTION( BITVECTOR );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ ~BITVECTOR (
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize (
+ IN PT Size DEFAULT 0,
+ IN BIT InitialValue DEFAULT RESET,
+ IN PPT Memory DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ PCPT
+ GetBuf (
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsBitSet (
+ IN PT Index
+ ) CONST;
+
+ NONVIRTUAL
+ PT
+ QueryCountSet (
+ ) CONST;
+
+ NONVIRTUAL
+ PT
+ QuerySize (
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ ResetAll (
+ );
+
+ NONVIRTUAL
+ VOID
+ ResetBit (
+ IN PT Index
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ VOID
+ ResetBit (
+ IN PT Index,
+ IN PT Count
+ );
+
+ NONVIRTUAL
+ VOID
+ SetAll (
+ );
+
+ NONVIRTUAL
+ VOID
+ SetBit (
+ IN PT Index
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ VOID
+ SetBit (
+ IN PT Index,
+ IN PT Count
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ PT
+ SetSize (
+ IN PT Size,
+ IN BIT InitialValue DEFAULT RESET
+ );
+
+ NONVIRTUAL
+ VOID
+ ToggleBit (
+ IN PT Index,
+ IN PT Count DEFAULT 1
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ PT
+ ComputeCountSet (
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ Destroy (
+ );
+
+ VOID
+ NONVIRTUAL
+ InitAll (
+ IN PT InitialValue
+ );
+
+ // Note that these three member data items cannot
+ // be static because they are used in INLINE functions
+ // that are called from outside the DLL.
+
+ PT _BitsPerPT;
+ PT _IndexShiftCount;
+ PT _BitPositionMask;
+
+ STATIC
+ CONST
+ BYTE _BitsSetLookUp[ 256 ];
+
+ PPT _BitVector;
+ PT _PTCount;
+ BOOLEAN _FreeBitVector;
+
+};
+
+INLINE
+PCPT
+BITVECTOR::GetBuf (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the underlying bit vector.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PCPT - Returns a pointer to the underlying bitvector.
+
+--*/
+
+{
+ return( _BitVector );
+}
+
+INLINE
+PT
+BITVECTOR::QuerySize (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the number of bits in this BITVECTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PT
+
+--*/
+
+{
+ return( _PTCount * _BitsPerPT );
+}
+
+INLINE
+VOID
+BITVECTOR::InitAll (
+ IN PT InitialValue
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize each element in the internal bit vector to the
+ supplied bit pattern.
+
+Arguments:
+
+ InitialValue - Supplies the pattern for each element.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DebugAssert( _BitVector != NULL );
+
+ memset(( PVOID ) _BitVector,
+ ( int ) InitialValue, ( size_t ) ( sizeof( PT ) * _PTCount ));
+}
+
+INLINE
+VOID
+BITVECTOR::SetAll (
+ )
+
+/*++
+
+Routine Description:
+
+ Set (to one) all of the bits in this BITVECTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ InitAll(( PT ) ~0 );
+}
+
+INLINE
+VOID
+BITVECTOR::ResetAll (
+ )
+
+/*++
+
+Routine Description:
+
+ Reset (to zero) all of the bits in this BITVECTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ InitAll(( PT ) 0 );
+}
+
+INLINE
+BOOLEAN
+BITVECTOR::IsBitSet (
+ IN PT Index
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine if the bit at the supplied index is set.
+
+Arguments:
+
+ Index - Supplies the index to the bit of interest.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the bit of interest is set.
+
+--*/
+
+{
+ DebugAssert( _BitVector != NULL );
+ DebugAssert( Index < ( _PTCount * _BitsPerPT ));
+
+ return (_BitVector[Index >> _IndexShiftCount] &
+ (1 << (Index & _BitPositionMask))) ? TRUE : FALSE;
+}
+
+INLINE
+VOID
+BITVECTOR::SetBit (
+ IN PT Index
+ )
+
+/*++
+
+Routine Description:
+
+ Set the bit at the supplied index.
+
+Arguments:
+
+ Index - Supplies the index to the bit of interest.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DebugAssert( _BitVector != NULL );
+ DebugAssert( Index < ( _PTCount * _BitsPerPT ));
+
+ _BitVector[Index >> _IndexShiftCount] |=
+ (1 << (Index & _BitPositionMask));
+}
+
+INLINE
+VOID
+BITVECTOR::ResetBit (
+ IN PT Index
+ )
+
+/*++
+
+Routine Description:
+
+ Reset the bit at the supplied index.
+
+Arguments:
+
+ Index - Supplies the index to the bit of interest.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DebugAssert( _BitVector != NULL );
+ DebugAssert( Index < ( _PTCount * _BitsPerPT ));
+
+ _BitVector[Index >> _IndexShiftCount] &=
+ ~(1 << (Index & _BitPositionMask));
+}
+
+INLINE
+PT
+BITVECTOR::QueryCountSet (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine the number of bits set in this BITVECTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PT - Returns the number of set bits.
+
+--*/
+{
+ return ComputeCountSet();
+}
+
+#endif // _BITVECTOR_
diff --git a/private/utils/ulib/inc/buffer.hxx b/private/utils/ulib/inc/buffer.hxx
new file mode 100644
index 000000000..7541b5d96
--- /dev/null
+++ b/private/utils/ulib/inc/buffer.hxx
@@ -0,0 +1,183 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ buffer.hxx
+
+Abstract:
+
+ This contains all buffer class definition.
+ No reallocing of buffers is done. A buffer must be big enough
+ to hold both buffer for a cat.
+
+Author:
+
+ Steve Rowe 27-Nov-90
+
+Environment:
+
+ ULIB, User Mode
+
+Notes:
+
+
+
+Revision History:
+
+--*/
+
+//
+// This class is no longer supported.
+//
+
+#define _BUFFER_
+
+#if !defined (_BUFFER_)
+
+#define _BUFFER_
+
+#include "error.hxx"
+
+DECLARE_CLASS( BUFFER );
+
+
+class BUFFER : public OBJECT {
+
+ friend WSTRING;
+
+ public:
+
+ VIRTUAL
+ ~BUFFER (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ BuffCat (
+ IN PCBUFFER BufferToCat
+ );
+
+ NONVIRTUAL
+ PCVOID
+ GetBufferPtr (
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ PutBuffer (
+ IN PCBUFFER BufferToCopy
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryBytesInBuffer (
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ SetBuffer (
+ IN PVOID InitialBuffer,
+ IN ULONG SizeOfBuffer
+ );
+
+ protected:
+
+ DECLARE_CONSTRUCTOR( BUFFER );
+
+ NONVIRTUAL
+ BOOLEAN
+ BufferCopyAt (
+ IN PCVOID BufferToCopy,
+ IN ULONG BytesToCopy,
+ IN ULONG StartingByte DEFAULT 0
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DeleteAt (
+ IN ULONG cbToDelete,
+ IN ULONG oStartDelete
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ InsertAt (
+ IN PCVOID BufferToCopy,
+ IN ULONG cbToCopy,
+ IN ULONG oStartCopy
+ );
+
+ NONVIRTUAL
+ PVOID
+ ReAllocate (
+ IN ULONG NewCount
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ PVOID pBuffer; // pointer to the data byffer
+ ULONG cb; // count of bytes used
+ ULONG _BufSize; // count of bytes in buffer
+
+ STATIC
+ ULONG _ThresHold;
+};
+
+INLINE
+PCVOID
+BUFFER::GetBufferPtr (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Fetch pointer to internal buffer
+
+Arguments:
+
+ None
+
+Return Value:
+
+ PCVOID - pointer to internal buffer
+
+--*/
+
+{
+ return ( pBuffer );
+}
+
+INLINE
+ULONG
+BUFFER::QueryBytesInBuffer (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Fetch size in bytes of internal buffer
+
+Arguments:
+
+ None
+
+Return Value:
+
+ ULONG - size of internal buffer in bytes
+
+--*/
+
+{
+ return ( cb );
+}
+
+#endif // _BUFFER_
diff --git a/private/utils/ulib/inc/bufstrm.hxx b/private/utils/ulib/inc/bufstrm.hxx
new file mode 100644
index 000000000..f4e5d644e
--- /dev/null
+++ b/private/utils/ulib/inc/bufstrm.hxx
@@ -0,0 +1,217 @@
+ /*++
+
+ Copyright (c) 1991 Microsoft Corporation
+
+ Module Name:
+
+ bufstrm.hxx
+
+ Abstract:
+
+ This module contains the declaration for the BUFFER_STREAM class.
+ The BUFFER_STREAM is an abstract class derived from STREAM, that
+ provides a buffer for read operations in STREAM.
+ Buffer for read operations is needed in order to read
+ STRINGs from streams.
+
+ Buffer for write operation is not currently implemented. It should
+ be implemented if we notice that write operations are slow.
+
+
+ Author:
+
+ Jaime Sasson (jaimes) 12-Apr-1991
+
+ Environment:
+
+ ULIB, User Mode
+
+
+ --*/
+
+
+ #if !defined( _BUFFER_STREAM_ )
+
+ #define _BUFFER_STREAM_
+
+ #include "stream.hxx"
+ #include "wstring.hxx"
+
+ DECLARE_CLASS( STREAM );
+
+
+ class BUFFER_STREAM : public STREAM {
+
+ public:
+
+ VIRTUAL
+ ~BUFFER_STREAM(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ IsAtEnd(
+ ) CONST;
+
+ VIRTUAL
+ STREAMACCESS
+ QueryAccess(
+ ) CONST PURE;
+
+ VIRTUAL
+ VOID
+ SetStreamTypeANSI(
+ );
+
+ VIRTUAL
+ VOID
+ DetermineStreamType(
+ IN OUT PBYTE *Buffer,
+ IN ULONG BufferSize
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Read(
+ OUT PBYTE Buffer,
+ IN ULONG BytesToRead,
+ OUT PULONG BytesRead
+ );
+
+ VIRTUAL
+ BOOLEAN
+ ReadChar(
+ OUT PWCHAR Char,
+ IN BOOLEAN Unicode DEFAULT FALSE
+ );
+
+ VIRTUAL
+ BOOLEAN
+ ReadMbString(
+ IN PSTR String,
+ IN DWORD BufferSize,
+ INOUT PDWORD StringSize,
+ IN PSTR Delimiters,
+ IN BOOLEAN ExpandTabs DEFAULT FALSE,
+ IN DWORD TabExp DEFAULT 8
+ );
+
+ VIRTUAL
+ BOOLEAN
+ ReadWString(
+ IN PWSTR String,
+ IN DWORD BufferSize,
+ INOUT PDWORD StringSize,
+ IN PWSTR Delimiters,
+ IN BOOLEAN ExpandTabs DEFAULT FALSE,
+ IN DWORD TabExp DEFAULT 8
+ );
+
+ VIRTUAL
+ BOOLEAN
+ ReadString(
+ OUT PWSTRING String,
+ IN PWSTRING Delimiters,
+ IN BOOLEAN Unicode DEFAULT FALSE
+ );
+
+
+ protected:
+
+ DECLARE_CONSTRUCTOR( BUFFER_STREAM );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN ULONG BufferSize
+ );
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ AdvanceBufferPointer(
+ IN ULONG NumberOfBytes
+ );
+
+ VIRTUAL
+ BOOLEAN
+ EndOfFile(
+ ) CONST PURE;
+
+ VIRTUAL
+ BOOLEAN
+ FillBuffer(
+ IN PBYTE Buffer,
+ IN ULONG BufferSize,
+ OUT PULONG BytesRead
+ ) PURE;
+
+ NONVIRTUAL
+ ULONG
+ FlushBuffer(
+ );
+
+ VIRTUAL
+ PCBYTE
+ GetBuffer(
+ PULONG BytesInBuffer
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryBytesInBuffer(
+ ) CONST;
+
+ VIRTUAL
+ HANDLE
+ QueryHandle(
+ ) CONST PURE;
+
+
+
+
+ private:
+
+
+ PBYTE _Buffer;
+ ULONG _BufferSize;
+ PBYTE _CurrentByte;
+ ULONG _BytesInBuffer;
+ INT _BufferStreamType;
+ };
+
+
+
+ INLINE
+ ULONG
+ BUFFER_STREAM::QueryBytesInBuffer(
+ ) CONST
+
+ /*++
+
+ Routine Description:
+
+ Returns the number of bytes in the buffer.
+
+ Arguments:
+
+ None.
+
+ Return Value:
+
+ ULONG - Number of bytes in the buffer.
+
+
+ --*/
+
+
+ {
+ return( _BytesInBuffer );
+ }
+
+
+ #endif // _BUFFER_STREAM_
diff --git a/private/utils/ulib/inc/bytestrm.hxx b/private/utils/ulib/inc/bytestrm.hxx
new file mode 100644
index 000000000..91f117bad
--- /dev/null
+++ b/private/utils/ulib/inc/bytestrm.hxx
@@ -0,0 +1,169 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ bytestream.hxx
+
+Abstract:
+
+
+ This module contains the declarations for the BYTE_STREAM class.
+
+ BYTE_STREAM is a class which contains (not derives) a normal
+ ULIB stream and provided fast ReadByte operations. It is designed
+ for those utilities that have to read files one byte at a time.
+
+
+Author:
+
+ Ramon J. San Andres (ramonsa) 28-Feb-1992
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+
+#if !defined( _BYTE_STREAM_ )
+
+#define _BYTE_STREAM_
+
+#include "stream.hxx"
+
+DECLARE_CLASS( BYTE_STREAM );
+
+
+#define DEFAULT_BUFFER_SIZE 256
+
+class BYTE_STREAM : public OBJECT {
+
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( BYTE_STREAM );
+
+ VOID
+ BYTE_STREAM::Construct (
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ ~BYTE_STREAM (
+ );
+
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize (
+ IN PSTREAM Stream,
+ IN DWORD BufferSize DEFAULT DEFAULT_BUFFER_SIZE
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ IsAtEnd(
+ ) CONST;
+
+
+ NONVIRTUAL
+ BOOLEAN
+ ReadByte(
+ IN PBYTE Byte
+ );
+
+
+
+ private:
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ FillAndReadByte (
+ IN PBYTE Byte
+ );
+
+
+ PSTREAM _Stream;
+ PBYTE _Buffer;
+ PBYTE _NextByte;
+ DWORD _BufferSize;
+ DWORD _BytesInBuffer;
+
+};
+
+
+
+INLINE
+BOOLEAN
+BYTE_STREAM::IsAtEnd(
+ ) CONST
+/*++
+
+Routine Description:
+
+ Determines if we're at the end of the stream
+
+Arguments:
+
+ None
+
+Return Value:
+
+ BOOLEAN - TRUE if at end.
+
+--*/
+{
+ if ( _BytesInBuffer > 0 ) {
+ return FALSE;
+ } else {
+ return _Stream->IsAtEnd();
+ }
+}
+
+
+
+INLINE
+BOOLEAN
+BYTE_STREAM::ReadByte(
+ IN PBYTE Byte
+ )
+/*++
+
+
+Routine Description:
+
+ Reads next byte
+
+Arguments:
+
+ Byte - Supplies pointer to where to put the byte
+
+Return Value:
+
+ BOOLEAN - TRUE if byte read.
+
+--*/
+{
+ if ( _BytesInBuffer > 0 ) {
+
+ *Byte = *_NextByte++;
+ _BytesInBuffer--;
+
+ return TRUE;
+
+ } else {
+
+ return FillAndReadByte( Byte );
+
+ }
+}
+
+
+#endif // _BYTE_STREAM_
diff --git a/private/utils/ulib/inc/clasdesc.hxx b/private/utils/ulib/inc/clasdesc.hxx
new file mode 100644
index 000000000..05e3aabbd
--- /dev/null
+++ b/private/utils/ulib/inc/clasdesc.hxx
@@ -0,0 +1,183 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ clasdesc.hxx
+
+Abstract:
+
+ This module contains the declaration for the CLASS_DESCRIPTOR class.
+ A CLASS_DESCRIPTOR contains informatiom to help identify an object's
+ type at run-time. It is a concrete class which is associated with all
+ other concrete classes (i.e. there is one instance of a CLASS_DESCRIPTOR
+ for every concrete class in Ulib). The most important aspect of a
+ CLASS_DESCRIPTOR is that it supplies a guaranteed unique id for the class
+ that it decsribes.
+
+Author:
+
+ David J. Gilman (davegi) 26-Oct-1990
+
+Environment:
+
+ ULIB, User Mode
+
+Notes:
+
+--*/
+
+#if ! defined( _CLASS_DESCRIPTOR_ )
+
+#define _CLASS_DESCRIPTOR_
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( CLASS_DESCRIPTOR );
+
+
+#if DBG==1
+
+ //
+ // Define a CLASS_DESCRIPTOR in the file ulib.cxx. The name will be
+ // the same as the type name for the associated class.
+ //
+
+ #define DEFINE_CLASS_DESCRIPTOR( c ) \
+ ((( c##_cd = NEW CLASS_DESCRIPTOR ) != NULL ) && \
+ ((( PCLASS_DESCRIPTOR ) c##_cd )->Initialize(( PCCLASS_NAME ) #c )))
+
+ #define CLASS_DESCRIPTOR_INITIALIZE \
+ NONVIRTUAL \
+ ULIB_EXPORT \
+ BOOLEAN \
+ Initialize ( \
+ IN PCCLASS_NAME ClassName \
+ )
+
+ //
+ // For debugging purposes, CLASS_DESCRIPTOR stores the name of the class
+ // that it describes.
+ //
+ // NOTE - DebugGetClassName is declared for both CLASS_DESCRIPTOR and
+ // OBJECT. See the note at the end of this module.
+ //
+
+ //
+ // Maximum length for the name of a class
+ //
+
+ CONST _MaxClassNameLength = 20;
+
+ #define DECLARE_CD_DBG_DATA \
+ CLASS_NAME _ClassName[ _MaxClassNameLength ]
+
+ #define DECLARE_CD_DBG_FUNCTIONS \
+ NONVIRTUAL \
+ PCCLASS_NAME \
+ DebugGetClassName ( \
+ ) CONST
+
+ #define DEFINE_CD_INLINE_DBG_FUNCTIONS \
+ \
+ inline \
+ PCCLASS_NAME \
+ CLASS_DESCRIPTOR::DebugGetClassName ( \
+ ) CONST \
+ { \
+ return(( PCCLASS_NAME ) _ClassName );\
+ }
+
+ #define DbgGetClassName( pobj ) \
+ ( pobj )->DebugGetClassName( )
+#else // DBG == 0
+
+ #define DEFINE_CLASS_DESCRIPTOR( c ) \
+ ((( c##_cd = NEW CLASS_DESCRIPTOR ) != NULL ) && \
+ ((( PCLASS_DESCRIPTOR ) c##_cd )->Initialize( )))
+
+ #define CLASS_DESCRIPTOR_INITIALIZE \
+ NONVIRTUAL \
+ ULIB_EXPORT \
+ BOOLEAN \
+ Initialize ( \
+ )
+
+ #define DECLARE_CD_DBG_DATA \
+ static char d
+
+ #define DECLARE_CD_DBG_FUNCTIONS \
+ void f(void){}
+
+ #define DEFINE_CD_INLINE_DBG_FUNCTIONS \
+ inline void f(void){}
+
+ #define DbgGetClassName( pobj )
+
+#endif // DBG
+
+class CLASS_DESCRIPTOR {
+
+ friend
+ BOOLEAN
+ InitializeUlib(
+ IN HANDLE DllHandle,
+ IN ULONG Reason,
+ IN PVOID Reserved
+ );
+
+ public:
+
+ ULIB_EXPORT
+ CLASS_DESCRIPTOR(
+ );
+
+ CLASS_DESCRIPTOR_INITIALIZE;
+
+ NONVIRTUAL
+ CLASS_ID
+ QueryClassId (
+ ) CONST;
+
+ DECLARE_CD_DBG_FUNCTIONS;
+
+ private:
+
+ DECLARE_CD_DBG_DATA;
+
+ CLASS_ID _ClassID;
+};
+
+
+INLINE
+CLASS_ID
+CLASS_DESCRIPTOR::QueryClassId (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the CLASSID for the object described by this CLASS_DESCRIPTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ CLASSID - The CLASSID as maintained by this CLASS_DESCRIPTOR.
+
+--*/
+
+{
+ return( _ClassID );
+}
+
+
+DEFINE_CD_INLINE_DBG_FUNCTIONS;
+
+#endif // CLASS_DESCRIPTOR
diff --git a/private/utils/ulib/inc/classes.xls b/private/utils/ulib/inc/classes.xls
new file mode 100644
index 000000000..a5be9db61
--- /dev/null
+++ b/private/utils/ulib/inc/classes.xls
Binary files differ
diff --git a/private/utils/ulib/inc/cmem.hxx b/private/utils/ulib/inc/cmem.hxx
new file mode 100644
index 000000000..a57cba24f
--- /dev/null
+++ b/private/utils/ulib/inc/cmem.hxx
@@ -0,0 +1,66 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ cmem.hxx
+
+Abstract:
+
+ The class CONT_MEM is an implementation of the class MEM which uses the
+ memory resources given to it on initialization. Successive calls
+ to Acquire will return successive portions of the memory given
+ to it on initialization.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 26-Nov-90
+
+--*/
+
+#if !defined( _CONT_MEM_DEFN_ )
+
+#define _CONT_MEM_DEFN_
+
+#include "mem.hxx"
+
+DECLARE_CLASS( CONT_MEM );
+
+
+class CONT_MEM : public MEM {
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( CONT_MEM );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize(
+ IN PVOID Buffer,
+ IN ULONG Size
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ PVOID
+ Acquire(
+ IN ULONG Size,
+ IN ULONG AlignmentMask DEFAULT 0
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ PVOID _buf;
+ ULONG _size;
+
+};
+
+#endif // _CONT_MEM_DEFN_
diff --git a/private/utils/ulib/inc/comm.hxx b/private/utils/ulib/inc/comm.hxx
new file mode 100644
index 000000000..89d701b42
--- /dev/null
+++ b/private/utils/ulib/inc/comm.hxx
@@ -0,0 +1,564 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ COMM_DEVICE
+
+Abstract:
+
+ This module contains the definition for the COMM_DEVICE class.
+
+Author:
+
+ Ramon J. San Andres (ramonsa) 08-Jul-91
+
+Environment:
+
+ ULIB, User Mode
+
+Notes:
+
+
+
+--*/
+
+#if !defined (_COMM_DEVICE_)
+
+#define _COMM_DEVICE_
+
+
+DECLARE_CLASS( FSN_FILE );
+DECLARE_CLASS( FILE_STREAM );
+DECLARE_CLASS( COMM_DEVICE );
+
+
+//
+// PARITY
+//
+enum PARITY {
+ COMM_PARITY_NONE = NOPARITY,
+ COMM_PARITY_EVEN = EVENPARITY,
+ COMM_PARITY_ODD = ODDPARITY,
+ COMM_PARITY_MARK = MARKPARITY,
+ COMM_PARITY_SPACE = SPACEPARITY
+};
+
+//
+// STOP BITS
+//
+enum STOPBITS {
+
+ COMM_STOPBITS_1 = ONESTOPBIT,
+ COMM_STOPBITS_15 = ONE5STOPBITS,
+ COMM_STOPBITS_2 = TWOSTOPBITS
+};
+
+//
+// DTR control
+//
+enum DTR_CONTROL {
+ DTR_ENABLE = DTR_CONTROL_ENABLE,
+ DTR_DISABLE = DTR_CONTROL_DISABLE,
+ DTR_HANDSHAKE = DTR_CONTROL_HANDSHAKE
+};
+
+//
+// RTS control
+//
+enum RTS_CONTROL {
+ RTS_ENABLE = RTS_CONTROL_ENABLE,
+ RTS_DISABLE = RTS_CONTROL_DISABLE,
+ RTS_HANDSHAKE = RTS_CONTROL_HANDSHAKE,
+ RTS_TOGGLE = RTS_CONTROL_TOGGLE
+};
+
+
+
+
+class COMM_DEVICE : public OBJECT {
+
+ public:
+
+ DECLARE_CAST_MEMBER_FUNCTION( COMM_DEVICE );
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( COMM_DEVICE );
+
+ VIRTUAL
+ ULIB_EXPORT
+ ~COMM_DEVICE(
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize (
+ IN PCPATH PortName,
+ OUT PBOOLEAN OpenError DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ CommitState (
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryBaudRate (
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QueryDataBits (
+ ) CONST;
+
+ NONVIRTUAL
+ DTR_CONTROL
+ QueryDtrControl (
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryIdsr (
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryOcts (
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryOdsr (
+ ) CONST;
+
+ NONVIRTUAL
+ PARITY
+ QueryParity (
+ ) CONST;
+
+ NONVIRTUAL
+ RTS_CONTROL
+ QueryRtsControl (
+ ) CONST;
+
+ NONVIRTUAL
+ STOPBITS
+ QueryStopBits (
+ ) CONST;
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ QueryTimeOut (
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryXon (
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ ReadState (
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ SetBaudRate (
+ IN ULONG BaudRate
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ SetDataBits (
+ IN ULONG DataBits
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ SetDtrControl (
+ IN DTR_CONTROL DtrControl
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ SetIdsr (
+ IN BOOLEAN Idsr
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ SetOcts (
+ IN BOOLEAN Octs
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ SetOdsr (
+ IN BOOLEAN Odsr
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ SetParity (
+ IN PARITY Parity
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ SetRtsControl (
+ IN RTS_CONTROL RtsControl
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ SetStopBits (
+ IN STOPBITS StopBits
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ SetTimeOut (
+ IN BOOLEAN TimeOut
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ SetXon (
+ IN BOOLEAN Xon
+ );
+
+ protected:
+
+
+ private:
+
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy (
+ );
+
+
+ HANDLE _Handle; // Handle to the port
+ DCB _Dcb; // DCB Structure.
+
+#if DBG==1
+
+ BOOLEAN _Initialized; // Object has been initialized
+
+#endif // DBG
+
+
+};
+
+INLINE
+ULONG
+COMM_DEVICE::QueryBaudRate (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Queries the baud rate
+
+Arguments:
+
+ none
+
+Return Value:
+
+ ULONG - The baud rate.
+
+--*/
+
+{
+
+ DebugAssert( _Initialized );
+
+ return (ULONG)_Dcb.BaudRate;
+
+}
+
+INLINE
+ULONG
+COMM_DEVICE::QueryDataBits (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Queries the number of data bits
+
+Arguments:
+
+ none
+
+Return Value:
+
+ ULONG - The number of data bits
+
+--*/
+
+{
+
+ DebugAssert( _Initialized );
+
+ return (ULONG)_Dcb.ByteSize;
+
+}
+
+INLINE
+DTR_CONTROL
+COMM_DEVICE::QueryDtrControl (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Queries the DTR control
+
+Arguments:
+
+ none
+
+Return Value:
+
+ DTR_CONTROL - The DTR control
+
+--*/
+
+{
+
+ DebugAssert( _Initialized );
+
+ return (DTR_CONTROL)_Dcb.fDtrControl;
+
+}
+
+INLINE
+BOOLEAN
+COMM_DEVICE::QueryIdsr (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Queries whether DSR sensitivity is enabled or disabled
+
+Arguments:
+
+ none
+
+Return Value:
+
+ BOOLEAN - TRUE if DSR sensitivity enabled. FALSE otherwise.
+
+--*/
+
+{
+
+ DebugAssert( _Initialized );
+
+ return ( _Dcb.fDsrSensitivity != 0 );
+
+}
+
+INLINE
+BOOLEAN
+COMM_DEVICE::QueryOcts (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Queries whether hanshaking using the CTS circuit is enabled or not.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ BOOLEAN - TRUE if handshaking enabled. FALSE otherwise.
+
+--*/
+
+{
+
+ DebugAssert( _Initialized );
+
+ return ( _Dcb.fOutxCtsFlow != 0 );
+
+}
+
+INLINE
+BOOLEAN
+COMM_DEVICE::QueryOdsr (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Queries whether handshaking using the DSR circuit is enabled or not
+
+Arguments:
+
+ none
+
+Return Value:
+
+ BOOLEAN - TRUE if handshaking enabled. FALSE otherwise.
+
+--*/
+
+{
+
+ DebugAssert( _Initialized );
+
+ return ( _Dcb.fOutxDsrFlow != 0 );
+
+}
+
+INLINE
+PARITY
+COMM_DEVICE::QueryParity (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Queries the parity
+
+Arguments:
+
+ none
+
+Return Value:
+
+ BYTE - The parity value.
+
+--*/
+
+{
+
+ DebugAssert( _Initialized );
+
+ return (PARITY)_Dcb.Parity;
+
+}
+
+INLINE
+RTS_CONTROL
+COMM_DEVICE::QueryRtsControl (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Queries the RTS control
+
+Arguments:
+
+ none
+
+Return Value:
+
+ RTS_CONTROL - The RTS control
+
+--*/
+
+{
+
+ DebugAssert( _Initialized );
+
+ return (RTS_CONTROL)_Dcb.fRtsControl;
+
+}
+
+INLINE
+STOPBITS
+COMM_DEVICE::QueryStopBits (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Queries the number of stop bits
+
+Arguments:
+
+ none
+
+Return Value:
+
+ BYTE - The number of stop bits
+
+--*/
+
+{
+
+ DebugAssert( _Initialized );
+
+ return (STOPBITS)_Dcb.StopBits;
+}
+
+INLINE
+BOOLEAN
+COMM_DEVICE::QueryXon (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Queries whether XON/XOFF protocol is enabled or not.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ BOOLEAN - TRUE if protocol enabled, FALSE otherwise
+
+--*/
+
+{
+
+ DebugAssert( _Initialized );
+
+ return ( _Dcb.fInX && _Dcb.fOutX );
+}
+
+
+
+
+#endif // _COMM_DEVICE_
diff --git a/private/utils/ulib/inc/contain.hxx b/private/utils/ulib/inc/contain.hxx
new file mode 100644
index 000000000..e588e8df3
--- /dev/null
+++ b/private/utils/ulib/inc/contain.hxx
@@ -0,0 +1,95 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ contain.hxx
+
+Abstract:
+
+ This module contains the definition for the CONTAINER class, the most
+ primitive, abstract class in the container sub-hierarchy. CONTAINERs
+ of all types are repositories for OBJECTs. CONTAINER is the most abstract
+ in that it makes no assumptions about the ordering of it's contents.
+
+Author:
+
+ David J. Gilman (davegi) 26-Oct-1990
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if ! defined( _CONTAINER_ )
+
+#define _CONTAINER_
+
+DECLARE_CLASS( CONTAINER );
+
+
+class CONTAINER : public OBJECT {
+
+ public:
+
+ VIRTUAL
+ ~CONTAINER(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Put(
+ IN OUT POBJECT Member
+ ) PURE;
+
+ VIRTUAL
+ ULONG
+ QueryMemberCount(
+ ) CONST PURE;
+
+ VIRTUAL
+ BOOLEAN
+ DeleteAllMembers(
+ ) PURE;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsEmpty(
+ ) CONST;
+
+ protected:
+
+ DECLARE_CONSTRUCTOR( CONTAINER );
+
+};
+
+
+INLINE
+BOOLEAN
+CONTAINER::IsEmpty(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine if the container is empty.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - TRUE if the container is empty.
+
+--*/
+
+{
+ return QueryMemberCount() == 0;
+}
+
+
+#endif // _CONTAINER_
diff --git a/private/utils/ulib/inc/cstring.h b/private/utils/ulib/inc/cstring.h
new file mode 100644
index 000000000..b401d2fd2
--- /dev/null
+++ b/private/utils/ulib/inc/cstring.h
@@ -0,0 +1,174 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ wstring.h
+
+Abstract:
+
+ This module contains the prototypes for the wide character
+ C-runtime support. Since there is no C-runtime support for
+ wide characters, the functions here are wrappers to the
+ single-byte counterparts
+
+Author:
+
+ Ramon San Andres (Ramonsa) 07-Jun-1991
+
+Revision History:
+
+--*/
+
+typedef char wchar;
+typedef WCHAR wchar_t;
+typedef size_t wsize_t;
+
+long watol( const wchar *);
+wchar * wcschr(const wchar *, int);
+wchar * wcslwr(wchar *);
+wchar * wcsrchr(const wchar *, int);
+wchar * wcsupr(wchar *);
+wsize_t wcscspn(const wchar *, const wchar *);
+wsize_t wcsspn(const wchar *, const wchar *);
+wchar * wcsstr(const wchar *, const wchar *);
+int wctomb( char *s, wchar_t wchar );
+int mbtowc(wchar_t *pwc, const char *s, size_t n);
+wchar_t towupper( wchar_t wc);
+
+INLINE
+long
+watol(
+ const wchar * p
+ )
+{
+ return atol( (char *)p );
+}
+
+
+INLINE
+wchar *
+wcschr (
+ const wchar * p,
+ int c
+ )
+{
+ return (wchar *)strchr( (char *)p, c);
+}
+
+
+INLINE
+wchar *
+wcslwr (
+ wchar * p
+ )
+{
+ return (wchar *)strlwr( (char *)p );
+}
+
+INLINE
+wchar *
+wcsrchr (
+ const wchar * p,
+ int c
+ )
+{
+ return (char *)strrchr( (char *)p, c);
+}
+
+INLINE
+wchar *
+wcsupr (
+ wchar * p
+ )
+{
+ return (char *)strupr( (char *)p );
+}
+
+
+INLINE
+wsize_t
+wcscspn (
+ const wchar *p1,
+ const wchar *p2
+ )
+{
+
+ return (wsize_t)strcspn( (char *)p1, (char *)p2);
+
+}
+
+INLINE
+wsize_t
+wcsspn (
+ const wchar *p1,
+ const wchar *p2
+ )
+{
+
+ return (wsize_t)strspn( (char *)p1, (char *)p2);
+
+}
+
+
+INLINE
+wchar *
+wcsstr (
+ const wchar *p1,
+ const wchar *p2
+ )
+{
+
+ return (wchar *)strstr( (char *)p1, (char *)p2);
+
+}
+
+
+INLINE
+int
+wctomb (
+ char *s,
+ wchar_t wchar
+ )
+{
+
+ if (s) {
+ *s = (char)wchar;
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+INLINE
+int
+mbtowc (
+ wchar_t *pwc,
+ const char *s,
+ size_t n
+ )
+{
+ UNREFERENCED_PARAMETER( n );
+
+ if ( s && *s && (n > 0) ) {
+ *pwc = (wchar_t)(*s);
+ return 1;
+ } else {
+ return 0;
+ }
+
+}
+
+
+INLINE
+wchar_t
+towupper(
+ wchar_t wc
+ )
+{
+
+ return (wchar_t)toupper( (char)wc );
+
+}
diff --git a/private/utils/ulib/inc/dir.hxx b/private/utils/ulib/inc/dir.hxx
new file mode 100644
index 000000000..7c4ab3637
--- /dev/null
+++ b/private/utils/ulib/inc/dir.hxx
@@ -0,0 +1,150 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ dir.hxx
+
+Abstract:
+
+ This module contains the declaration for the FSN_DIRECTORY class.
+ FSN_DIRECTORY is derived from the abstract FSNODE class. It offers an
+ interface which supports the manipulation of DIRECTORIES. It's primary
+ purpose is to support the creation of lists of FSNODE (e.g. FILE and
+ DIRECTORY) objects that meet some criteria (see FSN_FILETER)and to
+ manipulate (e.g. copy, move) FSNODEs which are 'owned' by a FSN_DIRECTORY.
+
+Author:
+
+ David J. Gilman (davegi) 09-Jan-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if ! defined( _FSN_DIRECTORY_ )
+
+#define _FSN_DIRECTORY_
+
+#include "fsnode.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( FSN_DIRECTORY );
+DECLARE_CLASS( FSN_FILE );
+DECLARE_CLASS( FSN_FILTER );
+DECLARE_CLASS( FSNODE );
+DECLARE_CLASS( PATH );
+
+//
+// Type of the callback function for the Traverse method
+//
+typedef BOOLEAN (*CALLBACK_FUNCTION)( IN PVOID Object, IN OUT PFSNODE Node, IN PPATH DestinationPath);
+
+//
+// Type of the confirmation function for Copy method.
+//
+typedef BOOLEAN (*CONFIRM_COPY_FUNCTION)( IN PCFSNODE Source,
+ IN OUT PPATH DestinationPath );
+
+
+class FSN_DIRECTORY : public FSNODE {
+
+ friend class FSN_FILTER;
+ friend class SYSTEM;
+
+ public:
+
+ DECLARE_CAST_MEMBER_FUNCTION( FSN_DIRECTORY );
+
+ /*
+ NONVIRTUAL
+ PFSN_DIRECTORY
+ CreateDirectory (
+ IN PCPATH Path
+ ) CONST;
+ */
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ PFSN_DIRECTORY
+ CreateDirectoryPath (
+ IN PCPATH Path
+ ) CONST;
+
+ NONVIRTUAL
+ PFSN_FILE
+ CreateFile (
+ IN PCPATH Path,
+ IN BOOLEAN OverWrite DEFAULT FALSE
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ Copy (
+ IN PFSN_FILTER FsnFilter,
+ IN PCFSN_DIRECTORY DestinationDir,
+ IN BOOLEAN Recurse DEFAULT FALSE,
+ IN BOOLEAN OverWrite DEFAULT FALSE
+ ) CONST;
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ DeleteDirectory (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DeleteFsNode (
+ IN PCFSN_FILTER FsnFilter,
+ IN BOOLEAN Recurse DEFAULT FALSE
+ ) CONST;
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ IsEmpty (
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ Move (
+ IN PCFSN_FILTER FsnFilter,
+ IN PCSTR DestinationName DEFAULT NULL,
+ IN PCFSN_DIRECTORY DestinationDir DEFAULT NULL,
+ IN BOOLEAN Recurse DEFAULT FALSE,
+ IN BOOLEAN OverWrite DEFAULT FALSE
+ ) CONST;
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ PARRAY
+ QueryFsnodeArray (
+ IN PFSN_FILTER FsnFilter DEFAULT NULL
+ ) CONST;
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Traverse (
+ IN PVOID Object,
+ IN PFSN_FILTER FsnFilter,
+ IN OUT PPATH DestinationPath,
+ IN CALLBACK_FUNCTION CallBackFunction
+ ) CONST;
+
+ protected:
+
+ DECLARE_CONSTRUCTOR( FSN_DIRECTORY );
+
+ private:
+
+};
+
+#endif // _FSN_DIRECTORY_
diff --git a/private/utils/ulib/inc/error.hxx b/private/utils/ulib/inc/error.hxx
new file mode 100644
index 000000000..227eb1134
--- /dev/null
+++ b/private/utils/ulib/inc/error.hxx
@@ -0,0 +1,392 @@
+/*
+ Defining error code:
+*/
+
+
+#define ERROR_USER_DEFINED_BASE 0xFF00
+#define ERR_ERRSTK_STACK_OVERFLOW ERROR_USER_DEFINED_BASE + 1
+#define NEW_ALLOC_FAILED ERROR_USER_DEFINED_BASE + 2
+
+#define ERROR_NLS_STRING_BASE 0xFF10
+#define ERR_NLS_ALLOC_FAILED ERROR_NLS_STRING_BASE + 1
+#define ERR_NLS_INVALID_PSZ ERROR_NLS_STRING_BASE + 2
+#define ERR_NLS_INVALID_STRING ERROR_NLS_STRING_BASE + 3
+#define ERR_NLS_FIXED_SIZE_BUF ERROR_NLS_STRING_BASE + 4
+#define ERR_NLS_NOT_FOUND ERROR_NLS_STRING_BASE + 5
+#define ERR_NLS_BAD_DATE ERROR_NLS_STRING_BASE + 6
+#define ERR_NLS_BAD_TIME ERROR_NLS_STRING_BASE + 7
+#define ERR_BAD_SUBSTRING ERROR_NLS_STRING_BASE + 8
+
+#define ERROR_ARG_BASE 0xFF20
+#define ERR_UNKNOWN_ARG_STRING ERROR_ARG_BASE + 1
+#define ERR_INVALID_COMMAND_LINE ERROR_ARG_BASE + 2
+
+#define ERROR_ARRAYLIST_BASE 0xFF30
+#define ERR_REALLOC_SIZE_FAILED ERROR_ARRAYLIST_BASE + 1
+
+#define ERROR_STR_BUF_BASE 0xFF40
+#define ERR_FILE_TOO_LARGE ERROR_STR_BUF_BASE + 1
+#define ERR_MEMORY_UNAVAILABLE ERROR_STR_BUF_BASE + 2
+#define ERR_FILE_READ_ERROR ERROR_STR_BUF_BASE + 3
+#define ERR_NO_STRINGS_IN_BUFFER ERROR_STR_BUF_BASE + 4
+#define ERR_INVALID_FILE_NAME ERROR_STR_BUF_BASE + 4
+
+
+#define ERROR_MB_STRING_BASE 0xFF50
+#define ERR_COLLATE_FAILURE ERROR_MB_STRING_BASE + 1
+
+#define ERROR_VOLUME_BASE 0xFF60
+#define ERR_CANNOT_OPEN_VOL ERROR_VOLUME_BASE + 1
+#define ERR_CANNOT_GET_VOL ERROR_VOLUME_BASE + 2
+#define ERR_PARITION_TOOBIG ERROR_VOLUME_BASE + 3
+#define ERR_NO_S_SWITCH ERROR_VOLUME_BASE + 4
+#define ERR_INVALID_PARM ERROR_VOLUME_BASE + 5
+#define ERR_VOL_NOTOPEN ERROR_VOLUME_BASE + 6
+#define ERR_VOL_NOHELPERS ERROR_VOLUME_BASE + 7
+#define ERR_VOL_NETDRIVE ERROR_VOLUME_BASE + 8
+#define ERR_VOL_BUSYDRIVE ERROR_VOLUME_BASE + 9
+#define ERR_VOL_INVALIDLABEL ERROR_VOLUME_BASE + 0xA
+
+#define ERROR_FMT_BASE 0xFFFF0070
+#define ERR_FMT_NOTSUPPORTED ERROR_FMT_BASE + 1
+#define ERR_FMT_UNEXPECTEDERR ERROR_FMT_BASE + 2
+#define ERR_FMT_BADPARM ERROR_FMT_BASE + 3
+#define ERR_FMT_INCOMPATPARM ERROR_FMT_BASE + 4
+#define ERR_FMT_INCOMPATDISK ERROR_FMT_BASE + 5
+#define ERR_FMT_ONCEONLY ERROR_FMT_BASE + 6
+#define ERR_FMT_VOLTOOBIG ERROR_FMT_BASE + 7
+#define ERR_FMT_BADVOLID ERROR_FMT_BASE + 8
+#define ERR_FMT_EXECFAIL ERROR_FMT_BASE + 9
+#define ERR_FMT_BADCMMFUNC ERROR_FMT_BASE + 0xA
+#define ERR_FMT_INVALIDMEDIA ERROR_FMT_BASE + 0xB
+#define ERR_FMT_BADOS ERROR_FMT_BASE + 0xC
+#define ERR_FMT_GENERALFAIL ERROR_FMT_BASE + 0xD
+#define ERR_FMT_NOSPARM ERROR_FMT_BASE + 0xE
+#define ERR_FMT_INVALIDNAME ERROR_FMT_BASE + 0xF
+#define ERR_FMT_NOWRITEBOOT ERROR_FMT_BASE + 0x10
+#define ERR_FMT_BADLABEL ERROR_FMT_BASE + 0x11
+#define ERR_FMT_FATERR ERROR_FMT_BASE + 0x12
+#define ERR_FMT_DIRWRITE ERROR_FMT_BASE + 0x13
+#define ERR_FMT_DRIVELETTER ERROR_FMT_BASE + 0x14
+#define ERR_FMT_UNSUPP_PARMS ERROR_FMT_BASE + 0x15
+#define ERR_FMT_STOPIFDISK ERROR_FMT_BASE + 0x16
+#define ERR_FMT_NODRIVESPEC ERROR_FMT_BASE + 0x17
+
+#define ERROR_IOBUF_BASE 0xFF90
+#define ERR_ALLOC_FAILURE ERROR_IOBUF_BASE + 1
+#define ERR_REALLOC_FAILURE ERROR_IOBUF_BASE + 2
+#define ERR_BUFFER_OVERFLOW ERROR_IOBUF_BASE + 3
+#define ERR_BUFFER_NOT_LOCAL ERROR_IOBUF_BASE + 4
+
+#define ERROR_FS_MGR_BASE 0xff95
+#define ERROR_DRV_BASE 0xff96
+#define ERR_DRV_NOT_SET ERROR_DRV_BASE + 1
+#define ERR_DRV_INVALID_ARG ERROR_DRV_BASE + 2
+#define ERROR_FS_REF_BASE 0xff99
+#define ERROR_FS_REF_SETPROPERTY ERROR_FS_REF_BASE + 1
+#define ERROR_FILE_BASE 0xffa0
+#define ERROR_DIRECTORY_BASE 0xffb0
+#define ERROR_MSG_BASE 0xffc0
+
+#define ERROR_MBR_BASE 0xFFd0
+#define ERR_INVALID_PARITION ERROR_MBR_BASE + 1
+#define ERR_INVALID_SYSTEM_ID ERROR_MBR_BASE + 2
+
+#define ERROR_BPB_BASE 0xFFe0
+#define ERR_BPB_NOMEM ERROR_BPB_BASE + 1
+#define ERR_INVALID_DEVICE ERROR_BPB_BASE + 2
+#define ERR_NO_BPB ERROR_BPB_BASE + 3
+#define ERR_NO_MBR ERROR_BPB_BASE + 4
+
+#define ERROR_FAT_BASE 0xFFf0
+#define ERR_BAD_CLUS_NUM ERROR_FAT_BASE + 1
+
+#define ERROR_FATFMT_BASE 0xFFf5
+#define ERR_NOMULTITRACK ERROR_FATFMT_BASE + 1
+#define ERR_BADAREAS ERROR_FATFMT_BASE + 2
+
+#define ERROR_BMIND_BASE 0xFFFF0000
+#define ERR_BMIND_PARAMETER ERROR_BMIND_BASE + 1
+#define ERR_BMIND_INITIALIZATION ERROR_BMIND_BASE + 2
+
+#define ERROR_BITMAP_BASE 0xFFFF0010
+#define ERR_BM_PARAMETER ERROR_BITMAP_BASE + 1
+#define ERR_BM_FULL ERROR_BITMAP_BASE + 2
+
+#define ERROR_BADBLK_BASE 0xFFFF0020
+#define ERR_BB_PARAMETER ERROR_BADBLK_BASE + 1
+
+#define ERROR_HOTFIX_BASE 0xFFFF0030
+#define ERR_HF_PARAMETER ERROR_HOTFIX_BASE + 1
+
+#define ERROR_FNODE_BASE 0xFFFF0040
+#define ERR_FN_PARAMETER ERROR_FNODE_BASE + 1
+
+#define ERROR_SUPER_BASE 0xFFFF0050
+#define ERR_SB_PARAMETER ERROR_SUPER_BASE + 1
+
+#define ERROR_SPARE_BASE 0xFFFF0060
+#define ERR_SP_PARAMETER ERROR_SPARE_BASE + 1
+
+#define ERROR_HPFSVOL_BASE 0xFFFF0070
+#define ERR_HV_PARAMETER ERROR_HPFSVOL_BASE + 1
+#define ERR_HV_BAD_SA ERROR_HPFSVOL_BASE + 2
+
+#define ERROR_DIRMAP_BASE 0xFFFF0080
+#define ERR_DM_PARAMETER ERROR_DIRMAP_BASE + 1
+#define ERR_DM_FULL ERROR_DIRMAP_BASE + 2
+
+#define ERROR_DIRBLK_BASE 0xFFFF0090
+#define ERR_DB_PARAMETER ERROR_DIRBLK_BASE + 1
+
+#define ERROR_HP_SUPER_AREA_BASE 0xFFFF00A0
+#define ERR_HPSA_PARAMETER ERROR_HP_SUPER_AREA_BASE + 1
+#define ERR_HPSA_NOT_READ ERROR_HP_SUPER_AREA_BASE + 2
+#define ERR_HPSA_BAD_SA ERROR_HP_SUPER_AREA_BASE + 3
+
+#define ERROR_CHKDSK_BASE 0xFFFF00B0
+#define ERR_CHKDSK_NOTSUPPORTED ERROR_CHKDSK_BASE + 1
+#define ERR_CHKDSK_UNEXPECTEDERR ERROR_CHKDSK_BASE + 2
+#define ERR_CHKDSK_BADPARM ERROR_CHKDSK_BASE + 3
+#define ERR_CHKDSK_INCOMPATPARM ERROR_CHKDSK_BASE + 4
+#define ERR_CHKDSK_INCOMPATDISK ERROR_CHKDSK_BASE + 5
+#define ERR_CHKDSK_BADVOLID ERROR_CHKDSK_BASE + 6
+#define ERR_CHKDSK_EXECFAIL ERROR_CHKDSK_BASE + 7
+#define ERR_CHKDSK_BADCMMFUNC ERROR_CHKDSK_BASE + 8
+#define ERR_CHKDSK_INVALIDMEDIA ERROR_CHKDSK_BASE + 9
+#define ERR_CHKDSK_BADOS ERROR_CHKDSK_BASE + 0xA
+#define ERR_CHKDSK_GENERALFAIL ERROR_CHKDSK_BASE + 0xB
+#define ERR_CHKDSK_INVALIDNAME ERROR_CHKDSK_BASE + 0xC
+#define ERR_CHKDSK_NOWRITEBOOT ERROR_CHKDSK_BASE + 0xD
+#define ERR_CHKDSK_BADLABEL ERROR_CHKDSK_BASE + 0xE
+#define ERR_CHKDSK_FATERR ERROR_CHKDSK_BASE + 0xF
+#define ERR_CHKDSK_DIRWRITE ERROR_CHKDSK_BASE + 0x10
+#define ERR_CHKDSK_DRIVELETTER ERROR_CHKDSK_BASE + 0x11
+#define ERR_CHKDSK_UNSUPP_PARMS ERROR_CHKDSK_BASE + 0x12
+#define ERR_CHKDSK_NODRIVESPEC ERROR_CHKDSK_BASE + 0x13
+#define ERR_CHKDSK_INVALID_FSTYPE ERROR_CHKDSK_BASE + 0x14
+#define ERR_CHKDSK_NO_FIX_SECTOR0 ERROR_CHKDSK_BASE + 0x15
+
+#define ERR_NOT_INIT 0xFFFF00D0
+#define ERR_NOT_READ 0xFFFF00E0
+
+#define ERROR_MEM_BASE 0xFFFF00F0
+#define ERR_CMEM_NO_MEM ERROR_MEM_BASE + 1
+#define ERR_HMEM_NO_MEM ERROR_MEM_BASE + 2
+
+#define ERRSTK_DEFAULT_SIZE 20
+typedef ULONG ERRCODE; // errco
+
+
+#if !defined( ERRSTACK_DEFN )
+#define ERRSTACK_DEFN
+
+// this has to be defined in the .exe and has to use this name.
+
+class ERRSTACK;
+typedef ERRSTACK* PERRSTACK;
+
+extern ERRSTACK *perrstk;
+
+
+class ERRSTACK {
+
+ public:
+
+ void push (ERRCODE errIn, CLASS_ID idIn)
+ { (void)(errIn); (void)(idIn); (void)(this); };
+
+};
+
+
+#define PUSH_ERR( x ) perrstk->push( x, QueryClassId() );
+
+#endif // !defined ERRSTACK_DEFN
+
+
+
+
+
+
+
+#if 0 // BUGBUG davegi fix
+
+
+/***************************************************************************\
+CLASS: ERROR
+
+PURPOSE: Class to hold an error code.
+
+INTERFACE: ERROR constructs and init error with class id and error code
+ SetErr Sets the error code
+ QueryErr returns current error code
+ SetId Set id used to identify class that had error.
+ QueryClassId returns current class id
+ SetMsg Sets pointer to message object
+ QueryMsg Returns pointer to message object
+ SetIdErrMsg Sets err, id and message at same time
+
+NOTES: Any error that is to be passed up the stack should be put into
+ an error object and put in the ERRSTK object. All references
+ to ERRSTK are through the ulib defined global perrstk. All
+ users of ERRSTK should declare:
+
+ #include "error.hxx";
+ extern ERRSTK * perrstk;
+
+ The ERROR object contains the error code, the class id (see
+ object.hxx) and an optional pointer to a MESSAGE object.
+
+ Error codes are defined with error.hxx. These are the error codes
+ specific to the utility objects. All error codes generated from
+ outside of OS/2 need to be mapped to this set of error codes.
+ Specifically the C runtime error codes will have to be mapped
+ to an error code defined in error.hxx. An error code returned
+ from an OS/2 call is put directly into the ERROR object. An
+ error code from the C runtime has to be mapped to some error
+ code defined in error.hxx.
+
+ The class id is defined in object.hxx. Each class has a unique
+ class id. This can be found be using the QueryClassId method on any
+ object. If the error does not occur within an object then use
+ ID_NOT_AN_OBJECT. This is a generic class id defined for this
+ purpose. If a more specific location is needed and the error
+ is not in an object then define a new class id substracting
+ from ID_BASE as shown in object.hxx with the ID_NOT_AN_OBJECT
+ example.
+
+ The optional pointer to a MESSAGE object can be used latter
+ to process the ERROR and recover context specific information
+ about the ERROR. There will need to be a message id defined
+ for the error.
+
+HISTORY: 4-1-90 stever
+
+KEYWORDS: ERROR CLASS_ID
+
+SEEALSO: ERRSTK
+\***************************************************************************/
+#if !defined (ERROR_DEFN)
+
+#define ERROR_DEFN
+
+class MESSAGE;
+
+class ERROR : public OBJECT { // err
+
+ private:
+
+ ERRCODE err;
+ CLASS_ID id;
+// const MESSAGE * pmsg;
+
+ public:
+ ERROR ();
+// ERROR (ERRCODE errIn, CLASS_ID idIn, const MESSAGE *pmsgIn = (MESSAGE *)NULL);
+ ~ERROR ();
+ ERROR & operator= (ERROR & );
+ BOOL SetErr (ERRCODE errIn) {return(err = errIn);}
+ ERRCODE QueryErr () {return(err);}
+ BOOL SetId (CLASS_ID idIn) {return(id = idIn); }
+ CLASS_ID QueryClassId () {return(id); }
+// ERROR * PutIdErrMsg (CLASS_ID idIn, ERRCODE errIn, const MESSAGE * pmsgIn = (const MESSAGE *)NULL) {id = idIn; pmsg = pmsgIn; err = errIn; return(this); }
+// const MESSAGE * PutMsg (MESSAGE * pmsgIn) { return(pmsg = pmsgIn); }
+// const MESSAGE * GetMsg () { return(pmsg); }
+
+#if defined (DEBUG)
+ BOOL print ();
+#endif
+
+};
+
+#if defined( DEBUG_STOP_PUSHERR )
+
+#define PUSH_ERR( x ) DebugPrintAbort( "PUSH_ERR called" );
+
+#else
+
+#define PUSH_ERR( x ) (void)*perrstk->push( x, QueryClassId() );
+
+#endif // DEBUG
+
+#endif // ERROR_DEFN
+
+/***************************************************************************\
+CLASS: ERRSTACK
+
+PURPOSE: Hold a stack of error objects
+
+INTERFACE: ERRSTACK creates an array of error obj. pointers
+ ~ERRSTACK deletes array of errors. (calls ~ERROR on each)
+ push push an error object onto the stack. There are
+ two signatures one for pointer to error objectg
+ the other for error code, class id and message
+ pop pop the top error object off the stack
+ QueryCount Query number of errors on the stack
+ QueryTop Query Top index to stack.
+ QuerySize Query size in pointer of stack
+ ClearStack Clear all error from stack (deletes error objects)
+
+
+NOTES: Each exe should declare with global scope an object of type
+ ERRSTK. If you include error.hxx a pointer called perrstk will
+ be declared. perrstk = NEW ERRSTK should be done at the start
+ of the program. The default size for the error stack will be
+ ERRSTK_DEFAULT_SIZE. If the error stack cannot be constructed the
+ the program should abort.
+
+ One slot is always reserved in the stack to hold an overflow
+ error. If ERRSTK_DEFAULT_SIZE stack is allocated then the
+ actual size of the stack is ERRSTK_DEFAULT_SIZE + 1. The overflow
+ error will also occur at index 0. Index ERRSTK_DEFAULT_SIZE - 1
+ is the bottom of the stack. Unless an overflow has occured the
+ stack index will not go below 1. Note that QuerySize will
+ return the original size passed in plus 1. QueryCountError will
+ include a stack overflow error.
+
+ The ERROR object passed to the stack is copied before it is
+ pushed. The caller is responsible for deleting the object.
+
+HISTORY: 3-6-90 stever
+
+KEYWORDS: ERRSTK
+
+SEEALSO: ERROR CLASS_ID
+\***************************************************************************/
+
+#if !defined (ERRSTK_DEFN)
+
+#define ERRSTK_DEFN
+
+class ERRSTACK : public OBJECT { // errstk
+
+ public:
+
+ ERRSTACK (ULONG cpoInitIn = ERRSTK_DEFAULT_SIZE, ULONG cpoIncIn = 0);
+ ~ERRSTACK ();
+ ERROR * push (const ERROR * );
+ ERROR * push (ERRCODE errIn, CLASS_ID idIn);
+ ERROR * pop ();
+ ULONG QueryCount () { return(ipoCur); }
+ ULONG QueryTop () { return(ipoCur); }
+ ULONG QuerySize () { return(cpoMax); }
+ ULONG ClearStack ();
+
+#ifdef DEBUG
+ ULONG print ();
+#endif
+
+ private:
+
+ ERROR * AllocError();
+ ULONG ipoCur; // index to top of stack
+ ULONG cpoMax; // index to bottom of stack
+ ULONG cpoInc; // bytes to add for each realloc
+ ULONG cpoInit; // initial alloc. (used by ClearStack
+ ERROR ** papo; // pointer to stack bottom
+
+};
+
+#endif // ERRSTK_DEFN
+
+#endif // BUGBUG davegi
diff --git a/private/utils/ulib/inc/file.hxx b/private/utils/ulib/inc/file.hxx
new file mode 100644
index 000000000..3d1f7ac76
--- /dev/null
+++ b/private/utils/ulib/inc/file.hxx
@@ -0,0 +1,127 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ file.hxx
+
+Abstract:
+
+ This module contains the declaration for the FSN_FILE class. FSN_FILE
+ is derived from the abstract FSNODE class. It offers an interface which
+ supports manipulation of the external (i.e. non data) portion of files.
+
+Author:
+
+ David J. Gilman (davegi) 09-Jan-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if ! defined( _FSN_FILE_ )
+
+#define _FSN_FILE_
+
+#include "fsnode.hxx"
+#include "filestrm.hxx"
+
+//
+// Error Codes from a copy
+//
+typedef enum _COPY_ERROR {
+ COPY_ERROR_ACCESS_DENIED = ERROR_ACCESS_DENIED,
+ COPY_ERROR_SHARE_VIOLATION = ERROR_SHARING_VIOLATION,
+ COPY_ERROR_NO_MEMORY = ERROR_NOT_ENOUGH_MEMORY,
+ COPY_ERROR_DISK_FULL = ERROR_DISK_FULL,
+ COPY_ERROR_INVALID_NAME = ERROR_INVALID_NAME
+} COPY_ERROR, *PCOPY_ERROR;
+
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( FSN_FILE );
+DECLARE_CLASS( FSN_FILTER );
+
+class FSN_FILE : public FSNODE {
+
+ friend FSN_FILTER;
+ friend SYSTEM;
+
+ public:
+
+ DECLARE_CAST_MEMBER_FUNCTION( FSN_FILE );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Copy (
+ IN OUT PPATH NewFile,
+ OUT PCOPY_ERROR ErrorCode DEFAULT NULL,
+ IN BOOLEAN OverwriteReadOnly DEFAULT FALSE,
+ IN BOOLEAN ResetReadOnly DEFAULT FALSE,
+ IN BOOLEAN Restartable DEFAULT FALSE,
+ IN LPPROGRESS_ROUTINE CallBack DEFAULT NULL,
+ IN VOID * Data DEFAULT NULL,
+ IN PBOOL Cancel DEFAULT NULL
+
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ DeleteFromDisk(
+ IN BOOLEAN Force DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ ULONG
+ QuerySize (
+ ) CONST;
+
+ ULIB_EXPORT
+ PFILE_STREAM
+ QueryStream (
+ IN STREAMACCESS Access
+ );
+
+ protected:
+
+ DECLARE_CONSTRUCTOR( FSN_FILE );
+
+ private:
+
+};
+
+
+
+INLINE
+ULONG
+FSN_FILE::QuerySize (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the size of the file in bytes.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - returns the file size
+
+--*/
+
+{
+ return( _FileData.nFileSizeLow );
+}
+
+#endif // _FSN_FILE_
diff --git a/private/utils/ulib/inc/filestrm.hxx b/private/utils/ulib/inc/filestrm.hxx
new file mode 100644
index 000000000..581571670
--- /dev/null
+++ b/private/utils/ulib/inc/filestrm.hxx
@@ -0,0 +1,208 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ filestrm.hxx
+
+Abstract:
+
+ This module contains the declaration for the FILE_STREAM class.
+ The FILE_STREAM is an abstract class derived from BUFFER_STREAM,
+ that models a file as a stream of data.
+ A FILE_STREAM class has the concept of a pointer (file poiter),
+ and it provides some methods that allow operations on this pointer,
+ such as:
+
+ .move file pointer to a particular position;
+ .read/write byte in a particular position;
+ .query the position of the file pointer;
+
+ The only way that a client has to create a FILE_STREAM is through
+ QueryStream() (a method in FSN_FILE).
+ FILE_STREAM can be has a method for initialization with two different
+ signatures. In one case, a PFSN_FILE is passed as parameter. This
+ initialization is used by QueryStream().
+ The other signature allows that a HANDLE is passed as parameter.
+ This initialization is used by GetStandardStream() during the
+ initialization of ulib.
+
+
+
+Author:
+
+ Jaime Sasson (jaimes) 21-Mar-1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+
+#if !defined( _FILE_STREAM_ )
+
+#define _FILE_STREAM_
+
+#include "bufstrm.hxx"
+
+
+enum SEEKORIGIN {
+ STREAM_BEGINNING,
+ STREAM_CURRENT,
+ STREAM_END
+ };
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( FILE_STREAM );
+DECLARE_CLASS( FSN_FILE );
+
+
+class FILE_STREAM : public BUFFER_STREAM {
+
+ friend class FSN_FILE;
+ friend class COMM_DEVICE;
+ friend PSTREAM GetStandardStream( HANDLE, STREAMACCESS );
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CAST_MEMBER_FUNCTION( FILE_STREAM );
+
+ VIRTUAL
+ ~FILE_STREAM(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ MovePointerPosition(
+ IN LONG Position,
+ IN SEEKORIGIN Origin
+ );
+
+ VIRTUAL
+ STREAMACCESS
+ QueryAccess(
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ QueryPointerPosition(
+ OUT PULONG Position
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Read(
+ OUT PBYTE Buffer,
+ IN ULONG NumberOfBytesToRead,
+ OUT PULONG NumberOfBytesRead
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ ReadAt(
+ OUT PBYTE Buffer,
+ IN ULONG BytesToRead,
+ IN LONG Position,
+ IN SEEKORIGIN Origin,
+ OUT PULONG BytesRead
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Write(
+ IN PCBYTE Buffer,
+ IN ULONG BytesToWrite,
+ OUT PULONG BytesWritten
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ WriteAt(
+ OUT PBYTE Buffer,
+ IN ULONG BytesToWrite,
+ IN LONG Position,
+ IN SEEKORIGIN Origin,
+ OUT PULONG BytesWritten
+ );
+
+
+ protected:
+
+ DECLARE_CONSTRUCTOR( FILE_STREAM );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ PCFSN_FILE File,
+ STREAMACCESS Access
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ HANDLE Handle,
+ STREAMACCESS Access
+ );
+
+ VIRTUAL
+ BOOLEAN
+ AdvanceBufferPointer(
+ IN ULONG NumberOfBytes
+ );
+
+ VIRTUAL
+ BOOLEAN
+ EndOfFile(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ FillBuffer(
+ IN PBYTE Buffer,
+ IN ULONG BufferSize,
+ OUT PULONG BytesRead
+ );
+
+ NONVIRTUAL
+ PCBYTE
+ GetBuffer(
+ PULONG BytesInBuffer
+ );
+
+ VIRTUAL
+ HANDLE
+ QueryHandle(
+ ) CONST;
+
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+
+ HANDLE _FileHandle;
+ HANDLE _FileMappingHandle;
+ STREAMACCESS _Access;
+ BOOLEAN _EndOfFile;
+ BOOLEAN _ShouldCloseHandle;
+ PBYTE _FileBaseAddress;
+ ULONG _FileSize;
+ PBYTE _CurrentByte;
+ BOOLEAN _EmptyFile;
+ BOOLEAN _MemoryMappedFile;
+};
+
+
+
+#endif // _FILE_STREAM_
diff --git a/private/utils/ulib/inc/filter.hxx b/private/utils/ulib/inc/filter.hxx
new file mode 100644
index 000000000..9519c475b
--- /dev/null
+++ b/private/utils/ulib/inc/filter.hxx
@@ -0,0 +1,274 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ filter.hxx
+
+Abstract:
+
+ This module contains the declaration for the FSN_FILTER class. FSN_FILTER
+ is a concrete class derived from OBJECT. It is used to maintain the state
+ information needed to determine if a file meets the criteria
+ pre-established in the FSN_FILTER.
+
+Author:
+
+ David J. Gilman (davegi) 04-Jan-1991
+
+Environment:
+
+ ULIB, User Mode
+
+Notes:
+
+ Here is how the filter works:
+
+ 1.- You initialize the filter (no arguments). This sets the filter
+ to its default matching criteria, which is "everything matches".
+
+ 2.- You will usually want to set your desired matching criteria. There
+ are 3 parameters that you can set:
+
+ a.- The file name - here you specify a file name (possibly with
+ wild cards ).
+
+ b.- The time criteria - you have to use the SetTimeInfo() method
+ once for every type of time that you want to filter. For the
+ SetTimeInfo() method you have to specify:
+
+ - The time
+ - The type of time that you want to filter (e.g
+ modification time, creation time etc. ).
+ - The matching criteria, which is a combination of:
+
+ TIME_BEFORE - Match if file time before this time
+ TIME_AT - Match if file time is this time
+ TIME_AFTER - Match if file time after this time
+
+ for example, if you want files that have been modified on or
+ after a particular time, you do:
+
+ SetTimeInfo( Time, FSN_TIME_MODIFIED, (TIME_AT | TIME_AFTER ) );
+
+ c.- The attributes - here you can provide 3 masks, called the
+ "All" mask, the "Any" mask, and the "None" mask. The meaning of
+ these mask is:
+
+ ALL: In order to match, a file must contain all the attributes
+ specified in this mask set.
+
+ ANY: In order to match, a file must contain any of the attributes
+ specified in this mask set.
+
+ NONE: In order to match, a file must contain all the attributes
+ specified in this mask NOT set.
+
+ An attribute may be present in at most ONE of the masks. An
+ attribute may be present in none of the masks
+
+
+
+ Here are some examples of the queries that we might want and what
+ the masks should be set to. The attributes are represented by:
+
+ D (directory) H (hidden) S (system) A (archived)
+ R (read-only)
+
+
+ ALL ANY NONE
+ ----- ----- -----
+
+ All files (not directories) that are ---A- ----- DHS--
+ not hidden or system, and that are
+ archived (this is used by XCopy)
+
+ All directories (used by Tree) D---- ----- -----
+
+
+ All files that are read-only or ----- -H--R D----
+ hidden
+
+
+ All hidden files that are read-only -H--- --S-R D----
+ or system
+
+
+
+
+--*/
+
+#if ! defined( _FSN_FILTER_ )
+
+#define _FSN_FILTER_
+
+#include "fsnode.hxx"
+#include "wstring.hxx"
+#include "timeinfo.hxx"
+
+//
+// Forward reference
+//
+
+DECLARE_CLASS( FSN_FILTER );
+DECLARE_CLASS( FSN_DIRECTORY );
+
+#define TIME_BEFORE 1
+#define TIME_AT 2
+#define TIME_AFTER 4
+
+class FSN_FILTER : public OBJECT {
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( FSN_FILTER );
+
+ DECLARE_CAST_MEMBER_FUNCTION( FSN_FILTER );
+
+ VIRTUAL
+ ULIB_EXPORT
+ ~FSN_FILTER (
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize (
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ DoesNodeMatch (
+ IN PFSNODE Node
+ );
+
+ NONVIRTUAL
+ PWSTRING
+ GetFileName (
+ ) CONST;
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ SetFileName (
+ IN PCSTR FileName
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ SetFileName (
+ IN PCWSTRING FileName
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ SetAttributes (
+ IN FSN_ATTRIBUTE All DEFAULT (FSN_ATTRIBUTE)0,
+ IN FSN_ATTRIBUTE Any DEFAULT (FSN_ATTRIBUTE)0,
+ IN FSN_ATTRIBUTE None DEFAULT (FSN_ATTRIBUTE)0
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ SetTimeInfo (
+ IN PCTIMEINFO TimeInfo,
+ IN FSN_TIME TimeInfoType DEFAULT FSN_TIME_MODIFIED,
+ IN USHORT TimeInfoMatch DEFAULT TIME_AT
+ );
+
+ NONVIRTUAL
+ PFSNODE
+ QueryFilteredFsnode (
+ IN PCFSN_DIRECTORY ParentDirectory,
+ IN PWIN32_FIND_DATA FindData
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FilterAttributes (
+ IN FSN_ATTRIBUTE Attributes
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FilterFileName (
+ IN PCWSTRING FileName
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FilterTimeInfo (
+ IN PFILETIME CreationTime,
+ IN PFILETIME LastAccessTime,
+ IN PFILETIME LastWriteTime
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PatternMatch (
+ IN PCWSTRING FileName,
+ IN CHNUM FileNamePosition,
+ IN PCWSTRING FindName,
+ IN CHNUM FindNamePosition
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ TimeInfoMatch (
+ IN PTIMEINFO TimeInfo,
+ IN PFILETIME FileTime,
+ IN USHORT Criteria
+ );
+
+ FSN_ATTRIBUTE _AttributesAll;
+ FSN_ATTRIBUTE _AttributesAny;
+ FSN_ATTRIBUTE _AttributesNone;
+ BOOLEAN _AttributesSet;
+
+ DSTRING _FileName;
+ BOOLEAN _FileNameSet;
+
+ TIMEINFO _TimeInfo[3];
+ USHORT _TimeInfoMatch[3];
+ BOOLEAN _TimeInfoSet[3];
+};
+
+INLINE
+PWSTRING
+FSN_FILTER::GetFileName (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Gets a pointer to the filter's filename
+
+Arguments:
+
+ none
+
+Return Value:
+
+ Pointer to the filter's filename
+
+--*/
+
+{
+ return &(((PFSN_FILTER) this)->_FileName);
+}
+
+#endif // _FSN_FILTER__
diff --git a/private/utils/ulib/inc/findleak.hxx b/private/utils/ulib/inc/findleak.hxx
new file mode 100644
index 000000000..34ed5010f
--- /dev/null
+++ b/private/utils/ulib/inc/findleak.hxx
@@ -0,0 +1,47 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ findleak.hxx
+
+Abstract:
+
+Author:
+
+ David J. Gilman (davegi) 02-Mar-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if ! defined( _FINDLEAK_ )
+
+#define _FINDLEAK_
+
+DEFINE_CLASS_POINTER_AND_REFERENCE_TYPES( FINDLEAK );
+
+class FINDLEAK : public PROGRAM {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( FINDLEAK );
+
+ VIRTUAL
+ BOOLEAN
+ Initialize (
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+};
+
+#endif // _FINDLEAK_
diff --git a/private/utils/ulib/inc/fsnode.hxx b/private/utils/ulib/inc/fsnode.hxx
new file mode 100644
index 000000000..fcca4f349
--- /dev/null
+++ b/private/utils/ulib/inc/fsnode.hxx
@@ -0,0 +1,1018 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ fsnode.hxx
+
+Abstract:
+
+ This module contains the declaration for the FSNODE class. FSNODE stands
+ for File System NODE and is an abstract class for all user visible
+ objects that exist in a file system (e.g. files, directories).
+
+Author:
+
+ David J. Gilman (davegi) 09-Jan-1991
+
+Environment:
+
+ ULIB, User Mode
+
+Notes:
+
+ Do not confuse this class or it's derived classes with the IFS class
+ sub-hierarchy. FSNODE related classes are user visible classes. They
+ are not intended to be used for low level file system tasks such as
+ format or chkdsk. FSNODE classes are as file system independent as the
+ underlying system allows.
+
+--*/
+
+#if ! defined( _FSNODE_ )
+
+#define _FSNODE_
+
+#include "path.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( ARRAY );
+DECLARE_CLASS( FSN_DIRECTORY );
+DECLARE_CLASS( FSNODE );
+DECLARE_CLASS( TIMEINFO );
+DECLARE_CLASS( WSTRING );
+
+
+//
+// Extend the set of system defined FILE_ATTRIBUTEs to include
+//
+// - all files (no directories)
+// - all file and directories
+//
+
+#define FILE_ATTRIBUTE_FILES ( FILE_ATTRIBUTE_ARCHIVE | \
+ FILE_ATTRIBUTE_HIDDEN | \
+ FILE_ATTRIBUTE_NORMAL | \
+ FILE_ATTRIBUTE_READONLY | \
+ FILE_ATTRIBUTE_COMPRESSED | \
+ FILE_ATTRIBUTE_SYSTEM )
+
+#define FILE_ATTRIBUTE_ALL ( FILE_ATTRIBUTE_FILES | \
+ FILE_ATTRIBUTE_DIRECTORY )
+
+typedef ULONG FSN_ATTRIBUTE;
+
+#define FSN_ATTRIBUTE_ARCHIVE FILE_ATTRIBUTE_ARCHIVE
+#define FSN_ATTRIBUTE_DIRECTORY FILE_ATTRIBUTE_DIRECTORY
+#define FSN_ATTRIBUTE_HIDDEN FILE_ATTRIBUTE_HIDDEN
+#define FSN_ATTRIBUTE_NORMAL FILE_ATTRIBUTE_NORMAL
+#define FSN_ATTRIBUTE_READONLY FILE_ATTRIBUTE_READONLY
+#define FSN_ATTRIBUTE_COMPRESSED FILE_ATTRIBUTE_COMPRESSED
+#define FSN_ATTRIBUTE_SYSTEM FILE_ATTRIBUTE_SYSTEM
+#define FSN_ATTRIBUTE_FILES FILE_ATTRIBUTE_FILES
+#define FSN_ATTRIBUTE_ALL FILE_ATTRIBUTE_ALL
+
+//
+// FSNODE time & date types
+//
+
+enum FSN_TIME {
+ FSN_TIME_MODIFIED = 0,
+ FSN_TIME_CREATED = 1,
+ FSN_TIME_ACCESSED = 2
+};
+
+class FSNODE : public OBJECT {
+
+ friend class FSN_FILTER;
+
+ public:
+
+ VIRTUAL
+ ~FSNODE (
+ );
+
+ NONVIRTUAL
+ PCPATH
+ GetPath (
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsArchived (
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsDirectory (
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsHidden (
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsNormal (
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsReadOnly (
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsSystem (
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ MakeArchived (
+ OUT LPDWORD Win32Error DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ MakeHidden (
+ OUT LPDWORD Win32Error DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ MakeNormal (
+ OUT LPDWORD Win32Error DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ MakeReadOnly (
+ OUT LPDWORD Win32Error DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ MakeSystem (
+ OUT LPDWORD Win32Error DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ PWSTRING
+ QueryBase (
+ ) CONST;
+
+ NONVIRTUAL
+ PWSTRING
+ QueryName (
+ ) CONST;
+
+ VIRTUAL
+ PFSN_DIRECTORY
+ QueryParentDirectory (
+ ) CONST;
+
+ VIRTUAL
+ PTIMEINFO
+ QueryTimeInfo (
+ IN FSN_TIME TimeInfoType DEFAULT FSN_TIME_MODIFIED
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ Rename(
+ IN PCPATH NewName
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ResetArchivedAttribute (
+ OUT LPDWORD Win32Error DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ResetHiddenAttribute (
+ OUT LPDWORD Win32Error DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ResetReadOnlyAttribute (
+ OUT LPDWORD Win32Error DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ResetSystemAttribute (
+ OUT LPDWORD Win32Error DEFAULT NULL
+ );
+
+ VIRTUAL
+ BOOLEAN
+ SetTimeInfo (
+ IN PCTIMEINFO TimeInfo,
+ IN FSN_TIME TimeInfoType DEFAULT FSN_TIME_MODIFIED
+ );
+
+ VIRTUAL
+ BOOLEAN
+ DeleteFromDisk(
+ IN BOOLEAN Force DEFAULT FALSE
+ );
+
+ VIRTUAL
+ BOOLEAN
+ UpdateFsNode(
+ );
+
+ NONVIRTUAL
+ FSN_ATTRIBUTE
+ QueryAttributes(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ SetAttributes (
+ IN FSN_ATTRIBUTE Attributes,
+ OUT LPDWORD Win32Error DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ UseAlternateName(
+ );
+
+ protected:
+
+ DECLARE_CONSTRUCTOR( FSNODE );
+
+ VIRTUAL
+ BOOLEAN
+ Initialize (
+ IN PCWSTR PathName,
+ IN PCFSN_DIRECTORY ParentDirectory,
+ IN PWIN32_FIND_DATA FileData
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Initialize (
+ IN PCWSTRING PathName,
+ IN PWIN32_FIND_DATA FileData
+ );
+
+ NONVIRTUAL
+ PFILETIME
+ GetCreationTime(
+ );
+
+ NONVIRTUAL
+ PFILETIME
+ GetLastAccessTime(
+ );
+
+ NONVIRTUAL
+ PFILETIME
+ GetLastWriteTime(
+ );
+
+ PATH _Path;
+ WIN32_FIND_DATAW _FileData;
+
+ private:
+
+};
+
+INLINE
+PCPATH
+FSNODE::GetPath (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the contained PATH object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PCPATH - returns a constant pointer to the contained PATH object
+
+--*/
+
+{
+ return( &_Path );
+}
+
+INLINE
+PFILETIME
+FSNODE::GetCreationTime(
+ )
+
+
+/*++
+
+Routine Description:
+
+ Returns pointer to creation time.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PFILETIME - pointer to creation time
+
+--*/
+
+{
+ return( &_FileData.ftCreationTime );
+}
+
+INLINE
+PFILETIME
+FSNODE::GetLastAccessTime(
+ )
+
+
+/*++
+
+Routine Description:
+
+ Returns pointer to last access time.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PFILETIME - pointer to last access time
+
+--*/
+
+{
+ return( &_FileData.ftLastAccessTime );
+}
+
+INLINE
+PFILETIME
+FSNODE::GetLastWriteTime(
+ )
+
+
+/*++
+
+Routine Description:
+
+ Returns pointer to last write time.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PFILETIME - pointer to last write time
+
+--*/
+
+{
+ return( &_FileData.ftLastWriteTime );
+}
+
+INLINE
+BOOLEAN
+FSNODE::IsArchived (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine if this FSNODE's archived attribute is set.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if this FSNODE's archived attribute is set.
+
+--*/
+
+{
+ return( ( _FileData.dwFileAttributes & FILE_ATTRIBUTE_ARCHIVE ) != 0 );
+}
+
+INLINE
+BOOLEAN
+FSNODE::IsDirectory (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine if this FSNODE's directory attribute is set.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if this FSNODE's directory attribute is set.
+
+--*/
+
+{
+ return( ( _FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) != 0 );
+}
+
+INLINE
+BOOLEAN
+FSNODE::IsHidden (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine if this FSNODE's hidden attribute is set.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if this FSNODE's hidden attribute is set.
+
+--*/
+
+{
+ return( ( _FileData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ) != 0 );
+}
+
+INLINE
+BOOLEAN
+FSNODE::IsNormal (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine if this FSNODE's normal attribute is set.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if this FSNODE's normal attribute is set.
+
+--*/
+
+{
+ return( ( _FileData.dwFileAttributes & FILE_ATTRIBUTE_NORMAL ) != 0 );
+}
+
+INLINE
+BOOLEAN
+FSNODE::IsReadOnly (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine if this FSNODE's readonly attribute is set.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if this FSNODE's readonly attribute is set.
+
+--*/
+
+{
+ return( ( _FileData.dwFileAttributes & FILE_ATTRIBUTE_READONLY ) != 0 );
+}
+
+INLINE
+BOOLEAN
+FSNODE::IsSystem (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine if this FSNODE's system attribute is set.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if this FSNODE's system attribute is set.
+
+--*/
+
+{
+ return( ( _FileData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM ) != 0 );
+}
+
+INLINE
+BOOLEAN
+FSNODE::MakeArchived (
+ OUT LPDWORD Win32Error
+ )
+
+/*++
+
+Routine Description:
+
+ Make the underlying 'file' archived.
+
+Arguments:
+
+ Win32Error - Optional parameter that will contain a Win32 error code
+ if the method is unable to change attribute.
+
+Return Value:
+
+ BOOLEAN - Returns the result of setting the file's archived attribute.
+
+--*/
+
+{
+ if( SetFileAttributesW(( LPWSTR ) _FileData.cFileName,
+ _FileData.dwFileAttributes | FILE_ATTRIBUTE_ARCHIVE )) {
+
+ _FileData.dwFileAttributes |= FILE_ATTRIBUTE_ARCHIVE;
+ return( TRUE );
+ } else {
+
+ if( Win32Error != NULL ) {
+ *Win32Error = GetLastError();
+ }
+ return( FALSE );
+ }
+}
+
+INLINE
+BOOLEAN
+FSNODE::MakeHidden (
+ OUT LPDWORD Win32Error
+ )
+
+/*++
+
+Routine Description:
+
+ Make the underlying 'file' hidden.
+
+Arguments:
+
+ Win32Error - Optional parameter that will contain a Win32 error code
+ if the method is unable to change attribute.
+
+Return Value:
+
+ BOOLEAN - Returns the result of setting the file's hidden attribute.
+
+--*/
+
+{
+ if( SetFileAttributesW(( LPWSTR ) _FileData.cFileName,
+ _FileData.dwFileAttributes | FILE_ATTRIBUTE_HIDDEN )) {
+
+ _FileData.dwFileAttributes |= FILE_ATTRIBUTE_HIDDEN;
+ return( TRUE );
+ } else {
+
+ if( Win32Error != NULL ) {
+ *Win32Error = GetLastError();
+ }
+ return( FALSE );
+ }
+}
+
+INLINE
+BOOLEAN
+FSNODE::MakeNormal (
+ OUT LPDWORD Win32Error
+ )
+
+/*++
+
+Routine Description:
+
+ Make the underlying 'file' normal.
+
+Arguments:
+
+ Win32Error - Optional parameter that will contain a Win32 error code
+ if the method is unable to change attribute.
+
+Return Value:
+
+ BOOLEAN - Returns the result of resetting all the file's resettable
+ attributes.
+
+Note:
+
+ Making a 'file' normal means resetting all but the
+ FILE_ATTRIBUTE_DIRECTORY attributes.
+
+--*/
+
+{
+ if( SetFileAttributesW(( LPWSTR ) _FileData.cFileName,
+ FILE_ATTRIBUTE_NORMAL )) {
+
+ _FileData.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
+ return( TRUE );
+ } else {
+
+ if( Win32Error != NULL ) {
+ *Win32Error = GetLastError();
+ }
+ return( FALSE );
+ }
+}
+
+INLINE
+BOOLEAN
+FSNODE::MakeReadOnly (
+ OUT LPDWORD Win32Error
+ )
+
+/*++
+
+Routine Description:
+
+ Make the underlying 'file' read-only.
+
+Arguments:
+
+ Win32Error - Optional parameter that will contain a Win32 error code
+ if the method is unable to change attribute.
+
+Return Value:
+
+ BOOLEAN - Returns the result of setting the file's read-only attribute.
+
+--*/
+
+{
+ if( SetFileAttributesW(( LPWSTR ) _FileData.cFileName,
+ _FileData.dwFileAttributes | FILE_ATTRIBUTE_READONLY )) {
+
+ _FileData.dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
+ return( TRUE );
+ } else {
+
+ if( Win32Error != NULL ) {
+ *Win32Error = GetLastError();
+ }
+ return( FALSE );
+ }
+}
+
+INLINE
+BOOLEAN
+FSNODE::MakeSystem (
+ OUT LPDWORD Win32Error
+ )
+
+/*++
+
+Routine Description:
+
+ Make the underlying 'file' a system file.
+
+Arguments:
+
+ Win32Error - Optional parameter that will contain a Win32 error code
+ if the method is unable to change attribute.
+
+Return Value:
+
+ BOOLEAN - Returns the result of setting the file's system attribute.
+
+--*/
+
+{
+ if( SetFileAttributesW(( LPWSTR ) _FileData.cFileName,
+ _FileData.dwFileAttributes | FILE_ATTRIBUTE_SYSTEM )) {
+
+ _FileData.dwFileAttributes |= FILE_ATTRIBUTE_SYSTEM;
+ return( TRUE );
+ } else {
+
+ if( Win32Error != NULL ) {
+ *Win32Error = GetLastError();
+ }
+ return( FALSE );
+ }
+}
+
+INLINE
+PWSTRING
+FSNODE::QueryBase (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the base name maintained by the contained PATH object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PWSTRING - Returns a pointer to the base name.
+
+--*/
+
+{
+ return( ((PFSNODE) this)->_Path.QueryBase( ));
+}
+
+INLINE
+FSN_ATTRIBUTE
+FSNODE::QueryAttributes (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the node's attributes
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FSN_ATTRIBUTE - The attributes
+
+--*/
+
+{
+ return( (FSN_ATTRIBUTE)_FileData.dwFileAttributes );
+}
+
+INLINE
+PWSTRING
+FSNODE::QueryName (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the name maintained by the contained PATH object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PWSTRING - Returns a pointer to the name.
+
+--*/
+
+{
+ return( ((PFSNODE) this)->_Path.QueryName( ));
+}
+
+
+
+INLINE
+BOOLEAN
+FSNODE::ResetArchivedAttribute (
+ OUT LPDWORD Win32Error
+ )
+
+/*++
+
+Routine Description:
+
+ Make the underlying 'file' non archived.
+
+Arguments:
+
+ Win32Error - Optional parameter that will contain a Win32 error code
+ if the method is unable to change attribute.
+
+Return Value:
+
+ BOOLEAN - Returns the result of resetting the file's archived attribute.
+
+--*/
+
+{
+ if( SetFileAttributesW(( LPWSTR ) _FileData.cFileName,
+ _FileData.dwFileAttributes & ~FILE_ATTRIBUTE_ARCHIVE )) {
+
+ _FileData.dwFileAttributes &= ~FILE_ATTRIBUTE_ARCHIVE;
+ return( TRUE );
+ } else {
+
+ if( Win32Error != NULL ) {
+ *Win32Error = GetLastError();
+ }
+ return( FALSE );
+ }
+}
+
+INLINE
+BOOLEAN
+FSNODE::ResetHiddenAttribute (
+ OUT LPDWORD Win32Error
+ )
+
+/*++
+
+Routine Description:
+
+ Make the underlying 'file' non-hidden.
+
+Arguments:
+
+ Win32Error - Optional parameter that will contain a Win32 error code
+ if the method is unable to change attribute.
+
+Return Value:
+
+ BOOLEAN - Returns the result of resetting the file's hidden attribute.
+
+--*/
+
+{
+ if( SetFileAttributesW(( LPWSTR ) _FileData.cFileName,
+ _FileData.dwFileAttributes & ~FILE_ATTRIBUTE_HIDDEN )) {
+
+ _FileData.dwFileAttributes &= ~FILE_ATTRIBUTE_HIDDEN;
+ return( TRUE );
+ } else {
+
+ if( Win32Error != NULL ) {
+ *Win32Error = GetLastError();
+ }
+ return( FALSE );
+ }
+}
+
+
+
+INLINE
+BOOLEAN
+FSNODE::ResetReadOnlyAttribute (
+ OUT LPDWORD Win32Error
+ )
+
+/*++
+
+Routine Description:
+
+ Make the underlying 'file' non-read-only.
+
+Arguments:
+
+ Win32Error - Optional parameter that will contain a Win32 error code
+ if the method is unable to change attribute.
+
+Return Value:
+
+ BOOLEAN - Returns the result of resetting the file's read-only attribute.
+
+--*/
+
+{
+ if( SetFileAttributesW(( LPWSTR ) _FileData.cFileName,
+ _FileData.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY )) {
+
+ _FileData.dwFileAttributes &= ~FILE_ATTRIBUTE_READONLY;
+ return( TRUE );
+ } else {
+
+ if( Win32Error != NULL ) {
+ *Win32Error = GetLastError();
+ }
+ return( FALSE );
+ }
+}
+
+INLINE
+BOOLEAN
+FSNODE::ResetSystemAttribute (
+ OUT LPDWORD Win32Error
+ )
+
+/*++
+
+Routine Description:
+
+ Make the underlying 'file' a non-system file.
+
+Arguments:
+
+ Win32Error - Optional parameter that will contain a Win32 error code
+ if the method is unable to change attribute.
+
+Return Value:
+
+ BOOLEAN - Returns the result of setting the file's system attribute.
+
+--*/
+
+{
+ if( SetFileAttributesW(( LPWSTR ) _FileData.cFileName,
+ _FileData.dwFileAttributes & ~FILE_ATTRIBUTE_SYSTEM )) {
+
+ _FileData.dwFileAttributes &= ~FILE_ATTRIBUTE_SYSTEM;
+ return( TRUE );
+ } else {
+ if( Win32Error != NULL ) {
+ *Win32Error = GetLastError();
+ }
+ return( FALSE );
+ }
+}
+
+
+INLINE
+BOOLEAN
+FSNODE::SetAttributes (
+ IN FSN_ATTRIBUTE Attributes,
+ OUT LPDWORD Win32Error
+ )
+
+/*++
+
+Routine Description:
+
+ Set the attributes of the underlying 'file'.
+ (This method was added to improve performance of attrib.exe).
+
+Arguments:
+
+ Attributes - New attributes for the file.
+
+ Win32Error - Optional parameter that will contain a Win32 error code
+ if the method is unable to change attribute.
+
+Return Value:
+
+ BOOLEAN - Returns the result of setting the file's system attribute.
+
+--*/
+
+{
+ if( SetFileAttributesW(( LPWSTR ) _FileData.cFileName,
+ (_FileData.dwFileAttributes & ~FILE_ATTRIBUTE_FILES) | Attributes )) {
+
+ _FileData.dwFileAttributes &= ~FILE_ATTRIBUTE_FILES;
+ _FileData.dwFileAttributes |= Attributes;
+ return( TRUE );
+ } else {
+ if( Win32Error != NULL ) {
+ *Win32Error = GetLastError();
+ }
+ return( FALSE );
+ }
+}
+
+
+
+
+
+#endif // _FSNODE_
diff --git a/private/utils/ulib/inc/hmem.hxx b/private/utils/ulib/inc/hmem.hxx
new file mode 100644
index 000000000..294bf617d
--- /dev/null
+++ b/private/utils/ulib/inc/hmem.hxx
@@ -0,0 +1,152 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ hmem.hxx
+
+Abstract:
+
+ The class HMEM is an implementation of the class MEM which uses the
+ memory resources of the heap.
+
+ After the first call to Acquire that succeeds, all successive calls
+ will return the same memory that was returned by the first call
+ provided that the size requested is within the bounds of the first call.
+ The common buffer which was created upon the first successful call to
+ Acquire will be available along with its size by calling GetBuf and
+ QuerySize.
+
+ Calling Destroy will put the object back in its initial state thus
+ invalidating any pointers to its memory and enabling future calls
+ to Acquire to succeed regardless of the size specicified.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 26-Nov-90
+
+--*/
+
+#if !defined(HMEM_DEFN)
+
+#define HMEM_DEFN
+
+#include "mem.hxx"
+
+DECLARE_CLASS( HMEM );
+
+
+class HMEM : public MEM {
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( HMEM );
+
+ VIRTUAL
+ ULIB_EXPORT
+ ~HMEM(
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize(
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ PVOID
+ Acquire(
+ IN ULONG Size,
+ IN ULONG AlignmentMask DEFAULT 0
+ );
+
+ NONVIRTUAL
+ PVOID
+ GetBuf(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QuerySize(
+ ) CONST;
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Resize(
+ IN ULONG NewSize,
+ IN ULONG AlignmentMask DEFAULT 0
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ ULONG _size;
+ PVOID _real_buf;
+ PVOID _buf;
+
+};
+
+
+INLINE
+PVOID
+HMEM::GetBuf(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the memory that was previously 'Acquired'.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the beginning of the memory buffer.
+
+--*/
+{
+ return _buf;
+}
+
+
+INLINE
+ULONG
+HMEM::QuerySize(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the size of the memory that was previously
+ 'Acquired'.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The size of the memory returned by 'GetBuf'.
+
+--*/
+{
+ return _size;
+}
+
+
+#endif // HMEM_DEFN
diff --git a/private/utils/ulib/inc/ifsentry.hxx b/private/utils/ulib/inc/ifsentry.hxx
new file mode 100644
index 000000000..14c57acd9
--- /dev/null
+++ b/private/utils/ulib/inc/ifsentry.hxx
@@ -0,0 +1,93 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ifsentry.hxx
+
+Abstract:
+
+ Contains prototypes for entry points to the IFS
+ utility DLLs.
+
+
+Author:
+
+ Bill McJohn (billmc) 04-June-1991
+
+Environment:
+
+ User Mode
+
+--*/
+
+
+#if !defined ( _IFS_ENTRY_ )
+
+#define _IFS_ENTRY_
+
+#if defined( _AUTOCHECK_ ) && !defined( _SETUP_LOADER_ )
+#define FAR
+#define APIENTRY
+#endif // _AUTOCHECK_ || _SETUP_LOADER_
+
+typedef BOOLEAN(FAR APIENTRY * CHKDSK_FN)( PCWSTRING DriveName,
+ PMESSAGE Message,
+ BOOLEAN Fix,
+ BOOLEAN Verbose,
+ BOOLEAN,
+ BOOLEAN Recover,
+ PPATH,
+ BOOLEAN Extend,
+ BOOLEAN ResizeLogFile,
+ ULONG LogFileSize,
+ PULONG ExitStatus);
+
+typedef BOOLEAN(FAR APIENTRY * FORMAT_FN)( PCWSTRING,
+ PMESSAGE,
+ BOOLEAN,
+ MEDIA_TYPE,
+ PCWSTRING,
+ ULONG );
+
+
+typedef BOOLEAN(FAR APIENTRY * RECOVER_FN)( PPATH, PMESSAGE );
+
+typedef BOOLEAN (FAR APIENTRY * EXTEND_FN)(PCWSTRING, PMESSAGE, BOOLEAN Verify);
+
+//
+// Convert status code
+//
+typedef enum _CONVERT_STATUS {
+
+ CONVERT_STATUS_CONVERTED,
+ CONVERT_STATUS_INVALID_FILESYSTEM,
+ CONVERT_STATUS_CONVERSION_NOT_AVAILABLE,
+ CONVERT_STATUS_CANNOT_LOCK_DRIVE,
+ CONVERT_STATUS_ERROR,
+ CONVERT_STATUS_INSUFFICIENT_SPACE
+
+} CONVERT_STATUS, *PCONVERT_STATUS;
+
+
+typedef BOOLEAN(FAR APIENTRY * CONVERT_FN)( PCWSTRING,
+ PCWSTRING,
+ PMESSAGE,
+ BOOLEAN,
+ BOOLEAN,
+ PCONVERT_STATUS );
+
+typedef BOOLEAN (FAR APIENTRY * CHECKSPACE_FN)(
+ PCWSTRING,
+ PCWSTRING,
+ PMESSAGE,
+ BOOLEAN,
+ BOOLEAN,
+ BOOLEAN );
+
+typedef BOOLEAN(FAR APIENTRY * NAMETABLE_FN)( PCWSTRING,
+ PCWSTRING,
+ PMESSAGE );
+
+#endif // _IFS_ENTRY_
diff --git a/private/utils/ulib/inc/ifsserv.hxx b/private/utils/ulib/inc/ifsserv.hxx
new file mode 100644
index 000000000..7ae523505
--- /dev/null
+++ b/private/utils/ulib/inc/ifsserv.hxx
@@ -0,0 +1,109 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ifsentry.hxx
+
+Abstract:
+
+ Contains prototypes for entry points to the IFS
+ utility DLLs.
+
+
+Author:
+
+ Bill McJohn (billmc) 04-June-1991
+
+Environment:
+
+ User Mode
+
+--*/
+
+
+#if !defined ( _IFS_ENTRY_ )
+
+#define _IFS_ENTRY_
+
+#if defined( _AUTOCHECK_ ) && !defined( _SETUP_LOADER_ )
+#define FAR
+#define APIENTRY
+#endif // _AUTOCHECK_ || _SETUP_LOADER_
+
+extern "C"
+BOOLEAN
+FAR APIENTRY
+Chkdsk(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Fix,
+ IN BOOLEAN Verbose,
+ IN BOOLEAN OnlyIfDirty,
+ IN BOOLEAN Recover,
+ IN PPATH PathToCheck,
+ IN BOOLEAN Extend,
+ IN BOOLEAN ResizeLogFile,
+ IN ULONG LogFilesize,
+ OUT PULONG ExitStatus
+ );
+
+extern "C"
+BOOLEAN
+FAR APIENTRY
+Format(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Quick,
+ IN MEDIA_TYPE MediaType,
+ IN PCWSTRING LabelString,
+ IN ULONG ClusterSize
+ );
+
+extern "C"
+BOOLEAN
+FAR APIENTRY
+Recover(
+ IN PPATH RecFilePath,
+ IN OUT PMESSAGE Message
+ );
+
+extern "C"
+BOOLEAN
+FAR APIENTRY
+Extend(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verify
+ );
+
+
+//
+// Convert status code
+//
+typedef enum _CONVERT_STATUS {
+
+ CONVERT_STATUS_CONVERTED,
+ CONVERT_STATUS_INVALID_FILESYSTEM,
+ CONVERT_STATUS_CONVERSION_NOT_AVAILABLE,
+ CONVERT_STATUS_CANNOT_LOCK_DRIVE,
+ CONVERT_STATUS_ERROR,
+ CONVERT_STATUS_INSUFFICIENT_SPACE
+
+} CONVERT_STATUS, *PCONVERT_STATUS;
+
+extern "C"
+BOOLEAN
+FAR APIENTRY
+Convert(
+ IN PCWSTRING NtDriveName,
+ IN PCWSTRING FsName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ IN BOOLEAN Pause,
+ OUT PCONVERT_STATUS Status
+ );
+
+
+#endif // _IFS_ENTRY_
diff --git a/private/utils/ulib/inc/iterator.hxx b/private/utils/ulib/inc/iterator.hxx
new file mode 100644
index 000000000..3ea89ae8a
--- /dev/null
+++ b/private/utils/ulib/inc/iterator.hxx
@@ -0,0 +1,78 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ iterator.hxx
+
+Abstract:
+
+ This module contains the declaration for the abstract ITERATOR class.
+ ITERATORS are used to iterate over a CONTAINER allowing for multiple,
+ simultaneous readers. ITERATORs maintain the currency needed to perform
+ an iteration. This includes the current OBJECT in the CONTAINER and the
+ currency needed to get the next or previous OBJECT. ITERATORs also
+ provide the capability of wrapping when the end or begin of the container
+ is reached.
+
+Author:
+
+ David J. Gilman (davegi) 29-Oct-1990
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if ! defined( _ITERATOR_ )
+
+#define _ITERATOR_
+
+DECLARE_CLASS( ITERATOR );
+
+
+class ITERATOR : public OBJECT {
+
+ public:
+
+ VIRTUAL
+ ~ITERATOR(
+ );
+
+ VIRTUAL
+ POBJECT
+ FindNext(
+ IN PCOBJECT Key
+ );
+
+ VIRTUAL
+ POBJECT
+ GetCurrent(
+ ) PURE;
+
+ VIRTUAL
+ POBJECT
+ GetNext(
+ ) PURE;
+
+ VIRTUAL
+ POBJECT
+ GetPrevious(
+ ) PURE;
+
+ VIRTUAL
+ VOID
+ Reset(
+ ) PURE;
+
+
+ protected:
+
+ DECLARE_CONSTRUCTOR( ITERATOR );
+
+};
+
+
+#endif // _ITERATOR_
diff --git a/private/utils/ulib/inc/keyboard.hxx b/private/utils/ulib/inc/keyboard.hxx
new file mode 100644
index 000000000..f605b3198
--- /dev/null
+++ b/private/utils/ulib/inc/keyboard.hxx
@@ -0,0 +1,201 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ keyboard.hxx
+
+Abstract:
+
+ This module contains the declaration for the KEYBOARD class.
+ The KEYBOARD class is a derived from BUFFER_STREAM that provides
+ methods to access the keyboard as a stream of bytes with read-only
+ access.
+ It also provides some methods that set/reset the keyboard mode.
+
+
+Author:
+
+ Jaime Sasson (jaimes) 21-Mar-1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+
+#if !defined( _KEYBOARD_ )
+
+#define _KEYBOARD_
+
+#include "bufstrm.hxx"
+
+
+
+DECLARE_CLASS( KEYBOARD );
+
+class KEYBOARD : public BUFFER_STREAM {
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( KEYBOARD );
+
+ ULIB_EXPORT
+ DECLARE_CAST_MEMBER_FUNCTION( KEYBOARD );
+
+
+ NONVIRTUAL
+ ~KEYBOARD (
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize(
+ IN BOOLEAN LineMode DEFAULT TRUE,
+ IN BOOLEAN EchoMode DEFAULT TRUE
+ );
+
+ STATIC
+ ULIB_EXPORT
+ BOOLEAN
+ DisableBreakHandling (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DisableEchoMode(
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ DisableLineMode(
+ );
+
+ STATIC
+ ULIB_EXPORT
+ BOOLEAN
+ EnableBreakHandling (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ EnableEchoMode(
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ EnableLineMode(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ EndOfFile(
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ FillBuffer(
+ IN PBYTE Buffer,
+ IN ULONG BufferSize,
+ OUT PULONG BytesRead
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Flush(
+ );
+
+ STATIC
+ ULIB_EXPORT
+ BOOLEAN
+ GotABreak (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsEchoModeEnabled(
+ ) CONST;
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ IsKeyAvailable(
+ OUT PBOOLEAN Available
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsLineModeEnabled(
+ ) CONST;
+
+ VIRTUAL
+ STREAMACCESS
+ QueryAccess(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QueryDelay (
+ ) CONST;
+
+ VIRTUAL
+ HANDLE
+ QueryHandle(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QuerySpeed (
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ SetDelay (
+ IN ULONG Delay
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ SetSpeed (
+ IN ULONG Speed
+ ) CONST;
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ CONST
+ PBOOL
+ GetPFlagBreak (
+ VOID
+ ) CONST;
+
+ private:
+
+ HANDLE _KeyboardHandle;
+ ULONG _PreviousMode;
+ BOOLEAN _FlagCtrlZ;
+ STATIC BOOL _FlagBreak;
+
+ NONVIRTUAL
+ BOOLEAN
+ CheckForAsciiKey(
+ IN PINPUT_RECORD InputRecord,
+ IN ULONG NumberOfInputRecords
+ ) CONST;
+
+ STATIC
+ BOOL
+ BreakHandler (
+ IN ULONG CtrlType
+ );
+
+};
+
+#endif // _KEYBOARD_
diff --git a/private/utils/ulib/inc/list.hxx b/private/utils/ulib/inc/list.hxx
new file mode 100644
index 000000000..da5932343
--- /dev/null
+++ b/private/utils/ulib/inc/list.hxx
@@ -0,0 +1,115 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ list.hxx
+
+Abstract:
+
+ This class is an implementation of the SEQUENTIAL_CONTAINER
+ protocol. The specific implementation is that of a doubly
+ linked list.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 22-Oct-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if !defined( _LIST_DEFN_ )
+
+#define _LIST_DEFN_
+
+#include "seqcnt.hxx"
+#include "membmgr.hxx"
+
+
+struct OBJECT_LIST_NODE {
+ OBJECT_LIST_NODE* next;
+ OBJECT_LIST_NODE* prev;
+ POBJECT data;
+};
+
+DEFINE_POINTER_AND_REFERENCE_TYPES( OBJECT_LIST_NODE );
+
+DECLARE_CLASS( LIST );
+
+class LIST : public SEQUENTIAL_CONTAINER {
+
+ FRIEND class LIST_ITERATOR;
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( LIST );
+
+ VIRTUAL
+ ULIB_EXPORT
+ ~LIST(
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize(
+ );
+
+ VIRTUAL
+ ULONG
+ QueryMemberCount(
+ ) CONST;
+
+ VIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Put(
+ IN OUT POBJECT Member
+ );
+
+ VIRTUAL
+ POBJECT
+ Remove(
+ IN OUT PITERATOR Position
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ PITERATOR
+ QueryIterator(
+ ) CONST;
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Insert(
+ IN OUT POBJECT Member,
+ IN OUT PITERATOR Position
+ );
+
+ private:
+
+ POBJECT_LIST_NODE _head;
+ POBJECT_LIST_NODE _tail;
+ ULONG _count;
+ MEM_BLOCK_MGR _mem_block_mgr;
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+};
+
+
+#endif // _LIST_DEFN_
diff --git a/private/utils/ulib/inc/listit.hxx b/private/utils/ulib/inc/listit.hxx
new file mode 100644
index 000000000..0dfbbac59
--- /dev/null
+++ b/private/utils/ulib/inc/listit.hxx
@@ -0,0 +1,118 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ listit.hxx
+
+Abstract:
+
+ This is an implementation of iterator for LIST.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 24-Oct-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if ! defined( _LIST_ITERATOR_ )
+
+#define _LIST_ITERATOR_
+
+#include "iterator.hxx"
+#include "list.hxx"
+
+DECLARE_CLASS( LIST_ITERATOR );
+
+class LIST_ITERATOR : public ITERATOR {
+
+ FRIEND class LIST;
+
+ public:
+
+ DECLARE_CONSTRUCTOR( LIST_ITERATOR );
+
+ DECLARE_CAST_MEMBER_FUNCTION( LIST_ITERATOR );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PCLIST List
+ );
+
+ VIRTUAL
+ VOID
+ Reset(
+ );
+
+ VIRTUAL
+ POBJECT
+ GetCurrent(
+ );
+
+ VIRTUAL
+ POBJECT
+ GetNext(
+ );
+
+ VIRTUAL
+ POBJECT
+ GetPrevious(
+ );
+
+ private:
+
+ POBJECT_LIST_NODE _current;
+ PCLIST _list;
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+};
+
+
+INLINE
+VOID
+LIST_ITERATOR::Construct(
+ )
+/*++
+
+Routine Description:
+
+ This routine resets LIST_ITERATOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _current = NULL;
+ _list = NULL;
+}
+
+
+INLINE
+BOOLEAN
+LIST_ITERATOR::Initialize(
+ IN PCLIST List
+ )
+{
+ DebugAssert(List);
+ _list = List;
+ return TRUE;
+}
+
+
+#endif // _LIST_ITERATOR_
diff --git a/private/utils/ulib/inc/machine.hxx b/private/utils/ulib/inc/machine.hxx
new file mode 100644
index 000000000..9cfdb6f6b
--- /dev/null
+++ b/private/utils/ulib/inc/machine.hxx
@@ -0,0 +1,77 @@
+
+#if defined(JAPAN) && defined(_X86_)
+#if !defined(_MACHINE_DEFN_)
+
+#define _MACHINE_DEFN_
+
+extern "C" {
+ #include "windows.h"
+ #include "machine.h"
+}
+
+#if defined( _AUTOCHECK_ )
+
+extern "C"
+InitializeMachineId(
+ VOID
+);
+
+extern DWORD _dwMachineId;
+
+#define InitializeMachineData() InitializeMachineId();
+
+#define IsFMR_N() ( ISFUJITSUFMR( _dwMachineId ) )
+
+#define IsPC98_N() ( ISNECPC98( _dwMachineId ) )
+
+#define IsPCAT_N() ( ISMICROSOFT( _dwMachineId ) )
+
+#else
+
+DECLARE_CLASS( MACHINE );
+
+class MACHINE : public OBJECT {
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( MACHINE );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize( VOID );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ IsFMR( VOID );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ IsPC98( VOID );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ IsPCAT( VOID );
+
+ private:
+
+ STATIC DWORD _dwMachineId;
+};
+
+extern ULIB_EXPORT MACHINE MachinePlatform;
+
+#define InitializeMachineData() MachinePlatform.Initialize()
+
+#define IsFMR_N() MachinePlatform.IsFMR()
+
+#define IsPC98_N() MachinePlatform.IsPC98()
+
+#define IsPCAT_N() MachinePlatform.IsPCAT()
+
+#endif // defiend(_AUTOCHECK_)
+#endif // defined(JAPAN) && defiend(_X86_)
+#endif
diff --git a/private/utils/ulib/inc/mbstr.hxx b/private/utils/ulib/inc/mbstr.hxx
new file mode 100644
index 000000000..6b3c5ee14
--- /dev/null
+++ b/private/utils/ulib/inc/mbstr.hxx
@@ -0,0 +1,434 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ mbstr.hxx
+
+Abstract:
+
+ This module contains the definition of the MBSTR class. The MBSTR
+ class is a module that provides static methods for operating on
+ multibyte strings.
+
+
+Author:
+
+ Ramon J. San Andres (ramonsa) 21-Feb-1992
+
+Environment:
+
+ ULIB, User Mode
+
+Notes:
+
+
+
+--*/
+
+#if ! defined( _MBSTR_ )
+
+#define _MBSTR_
+
+
+extern "C" {
+ #include <stdarg.h>
+ #include <string.h>
+ #include <memory.h>
+}
+
+DECLARE_CLASS( MBSTR );
+
+class MBSTR {
+
+ public:
+
+ STATIC
+ PVOID
+ Memcpy (
+ INOUT PVOID Src,
+ INOUT PVOID Dst,
+ IN DWORD Size
+ );
+
+ STATIC
+ PVOID
+ Memset (
+ INOUT PVOID Src,
+ IN BYTE Byte,
+ IN DWORD Size
+ );
+
+
+ STATIC
+ PSTR
+ Strcat (
+ INOUT PSTR String1,
+ IN PSTR String2
+ );
+
+ STATIC
+ PSTR
+ Strchr (
+ IN PSTR String,
+ IN CHAR Char
+ );
+
+
+ STATIC
+ INT
+ Strcmp (
+ IN PSTR String1,
+ IN PSTR String2
+ );
+
+
+#ifdef DBCS
+//fix kksuzuka: #931
+//enabling DBCS with stricmp
+ STATIC
+ ULIB_EXPORT
+ INT
+ Stricmp (
+ IN PSTR p1,
+ IN PSTR p2
+ );
+#else
+ STATIC
+ INT
+ Stricmp (
+ IN PSTR String1,
+ IN PSTR String2
+ );
+#endif
+
+
+ STATIC
+ ULIB_EXPORT
+ INT
+ Strcmps (
+ IN PSTR p1,
+ IN PSTR p2
+ );
+
+ STATIC
+ ULIB_EXPORT
+ INT
+ Strcmpis (
+ IN PSTR p1,
+ IN PSTR p2
+ );
+
+
+ STATIC
+ PSTR
+ Strcpy (
+ INOUT PSTR String1,
+ IN PSTR String2
+ );
+
+
+ STATIC
+ DWORD
+ Strcspn (
+ IN PSTR String1,
+ IN PSTR String2
+ );
+
+ STATIC
+ PSTR
+ Strdup (
+ IN PSTR String
+ );
+
+
+ STATIC
+ DWORD
+ Strlen (
+ IN PSTR String
+ );
+
+
+ STATIC
+ PSTR
+ Strlwr (
+ INOUT PSTR String
+ );
+
+ STATIC
+ PSTR
+ Strncat (
+ INOUT PSTR String1,
+ IN PSTR String2,
+ DWORD Size
+ );
+
+
+ STATIC
+ INT
+ Strncmp (
+ IN PSTR String1,
+ IN PSTR String2,
+ IN DWORD Size
+ );
+
+
+ STATIC
+ DWORD
+ Strspn (
+ IN PSTR String1,
+ IN PSTR String2
+ );
+
+
+#ifdef DBCS
+//fix kksuzuka: #926
+//enabling DBCS with strstr
+ STATIC
+ ULIB_EXPORT
+ PSTR
+ Strstr (
+ IN PSTR String1,
+ IN PSTR String2
+ );
+#else
+ STATIC
+ PSTR
+ Strstr (
+ IN PSTR String1,
+ IN PSTR String2
+ );
+#endif
+
+ STATIC
+ PSTR
+ Strupr (
+ INOUT PSTR String
+ );
+
+
+ STATIC
+ PSTR*
+ MakeLineArray (
+ INOUT PSTR* Buffer,
+ INOUT PDWORD BufferSize,
+ INOUT PDWORD NumberOfLines
+ );
+
+ STATIC
+ DWORD
+ Hash(
+ IN PSTR String,
+ IN DWORD Buckets DEFAULT 211,
+ IN DWORD BytesToSum DEFAULT (DWORD)-1
+ );
+
+
+ private:
+
+#ifdef DBCS
+ STATIC
+ INT
+ CheckSpace(
+ IN PSTR s
+ );
+#endif
+
+ STATIC
+ PSTR
+ SkipWhite(
+ IN PSTR p
+ );
+
+
+};
+
+
+INLINE
+PVOID
+MBSTR::Memcpy (
+ INOUT PVOID Src,
+ INOUT PVOID Dst,
+ IN DWORD Size
+ )
+{
+ return memcpy( Src, Dst, (size_t)Size );
+}
+
+
+INLINE
+PVOID
+MBSTR::Memset (
+ INOUT PVOID Src,
+ IN BYTE Byte,
+ IN DWORD Size
+ )
+{
+ return memset( Src, Byte, (size_t)Size );
+}
+
+
+
+INLINE
+PSTR
+MBSTR::Strcat (
+ INOUT PSTR String1,
+ IN PSTR String2
+ )
+{
+ return strcat( String1, String2 );
+}
+
+INLINE
+PSTR
+MBSTR::Strchr (
+ IN PSTR String,
+ IN CHAR Char
+ )
+{
+ return strchr( String, Char );
+}
+
+
+INLINE
+INT
+MBSTR::Strcmp (
+ IN PSTR String1,
+ IN PSTR String2
+ )
+{
+ return strcmp( String1, String2 );
+}
+
+
+#ifndef DBCS
+//fix kksuzuka: #931
+//enabling DBCS with stricmp
+INLINE
+INT
+MBSTR::Stricmp (
+ IN PSTR String1,
+ IN PSTR String2
+ )
+{
+ return _stricmp( String1, String2 );
+}
+#endif
+
+
+INLINE
+PSTR
+MBSTR::Strcpy (
+ INOUT PSTR String1,
+ IN PSTR String2
+ )
+{
+ return strcpy( String1, String2 );
+}
+
+
+INLINE
+DWORD
+MBSTR::Strcspn (
+ IN PSTR String1,
+ IN PSTR String2
+ )
+{
+ return strcspn( String1, String2 );
+}
+
+
+INLINE
+PSTR
+MBSTR::Strdup (
+ IN PSTR String
+ )
+{
+ return _strdup( String );
+}
+
+
+INLINE
+DWORD
+MBSTR::Strlen (
+ IN PSTR String
+ )
+{
+ return strlen( String );
+}
+
+
+INLINE
+PSTR
+MBSTR::Strlwr (
+ INOUT PSTR String
+ )
+{
+ return _strlwr( String );
+}
+
+
+INLINE
+PSTR
+MBSTR::Strncat (
+ INOUT PSTR String1,
+ IN PSTR String2,
+ DWORD Size
+ )
+{
+ return strncat( String1, String2, (unsigned int)Size );
+}
+
+
+INLINE
+INT
+MBSTR::Strncmp (
+ IN PSTR String1,
+ IN PSTR String2,
+ IN DWORD Size
+ )
+{
+ return strncmp( String1, String2, (size_t)Size );
+}
+
+
+INLINE
+DWORD
+MBSTR::Strspn (
+ IN PSTR String1,
+ IN PSTR String2
+ )
+{
+ return strspn( String1, String2 );
+}
+
+#ifndef DBCS
+//fix kksuzuka: #926
+//enabling DBCS with strstr
+INLINE
+PSTR
+MBSTR::Strstr (
+ IN PSTR String1,
+ IN PSTR String2
+ )
+{
+ return strstr( String1, String2 );
+}
+#endif
+
+
+INLINE
+PSTR
+MBSTR::Strupr (
+ INOUT PSTR String
+ )
+{
+ return _strupr( String );
+}
+
+
+
+
+
+#endif // _MBSTR_
diff --git a/private/utils/ulib/inc/mem.hxx b/private/utils/ulib/inc/mem.hxx
new file mode 100644
index 000000000..f0c316e77
--- /dev/null
+++ b/private/utils/ulib/inc/mem.hxx
@@ -0,0 +1,50 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ mem.hxx
+
+Abstract:
+
+ The class MEM contains one pure virtual function named 'Acquire'.
+ The implementors and users of this class must follow some simple
+ constraints.
+
+ Acquire will return a pointer to Size bytes of memory or NULL.
+
+ A function taking a MEM as an argument should call Acquire at most one
+ time. It should not, for instance, cache a pointer to the MEM for
+ future calls to Acquire.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 26-Nov-90
+
+--*/
+
+#if !defined(MEM_DEFN)
+
+#define MEM_DEFN
+
+DECLARE_CLASS( MEM );
+
+class MEM : public OBJECT {
+
+ public:
+
+ VIRTUAL
+ PVOID
+ Acquire(
+ IN ULONG Size,
+ IN ULONG AlignmentMask DEFAULT 0
+ ) PURE;
+
+ protected:
+
+ DECLARE_CONSTRUCTOR( MEM );
+
+};
+
+#endif // MEM_DEFN
diff --git a/private/utils/ulib/inc/membmgr.hxx b/private/utils/ulib/inc/membmgr.hxx
new file mode 100644
index 000000000..f3332048e
--- /dev/null
+++ b/private/utils/ulib/inc/membmgr.hxx
@@ -0,0 +1,258 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ membmgr.hxx
+
+Abstract:
+
+ This class offers two classes for the management of fixed
+ size blocks of memory. The first class STATIC_MEM_BLOCK_MGR
+ allows the user to allocate and free fixed size memory blocks
+ up to the specified limit that the class was initialized to.
+
+ The second class MEM_BLOCK_MGR offers a scheme for memory block
+ management that will grow as the clients needs increase.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 29-May-92
+
+--*/
+
+#if !defined(_MEM_BLOCK_MGR_DEFN_)
+
+#define _MEM_BLOCK_MGR_DEFN_
+
+
+#include "array.hxx"
+#include "bitvect.hxx"
+
+
+DECLARE_CLASS( STATIC_MEM_BLOCK_MGR );
+
+class STATIC_MEM_BLOCK_MGR : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( STATIC_MEM_BLOCK_MGR );
+
+ VIRTUAL
+ ~STATIC_MEM_BLOCK_MGR(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN ULONG MemBlockSize,
+ IN ULONG NumBlocks DEFAULT 128
+ );
+
+ NONVIRTUAL
+ PVOID
+ Alloc(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Free(
+ OUT PVOID MemBlock
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryBlockSize(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QueryNumBlocks(
+ ) CONST;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ PCHAR _heap;
+ ULONG _num_blocks;
+ ULONG _block_size;
+ ULONG _num_allocated;
+ ULONG _next_alloc;
+ BITVECTOR _bitvector;
+
+};
+
+
+INLINE
+ULONG
+STATIC_MEM_BLOCK_MGR::QueryBlockSize(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine return the number of bytes in a block returned
+ by this object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of bytes per block.
+
+--*/
+{
+ return _block_size;
+}
+
+
+INLINE
+ULONG
+STATIC_MEM_BLOCK_MGR::QueryNumBlocks(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine return the number of blocks contained
+ by this object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of blocks.
+
+--*/
+{
+ return _num_blocks;
+}
+
+
+
+DECLARE_CLASS( MEM_BLOCK_MGR );
+
+class MEM_BLOCK_MGR : public OBJECT {
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( MEM_BLOCK_MGR );
+
+ VIRTUAL
+ ULIB_EXPORT
+ ~MEM_BLOCK_MGR(
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize(
+ IN ULONG MemBlockSize,
+ IN ULONG InitialNumBlocks DEFAULT 128
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ PVOID
+ Alloc(
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Free(
+ OUT PVOID MemBlock
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryBlockSize(
+ ) CONST;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ PSTATIC_MEM_BLOCK_MGR _static_mem_list[32];
+
+};
+
+
+INLINE
+ULONG
+MEM_BLOCK_MGR::QueryBlockSize(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine return the number of bytes in a block returned
+ by this object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of bytes per block.
+
+--*/
+{
+ return _static_mem_list[0] ? _static_mem_list[0]->QueryBlockSize() : 0;
+}
+
+
+INLINE
+PVOID
+operator new(
+ IN size_t Size,
+ IN PVOID Pointer
+ )
+/*++
+
+Routine Description:
+
+ This is an explicit placement version of the 'new' operator
+ which clients of these classes may wish to use in order to
+ call the constructor on their newly allocated objects.
+
+Arguments:
+
+ Size - Supplies the size of the buffer.
+ Pointer - Supplies a pointer to the buffer.
+
+Return Value:
+
+ This function returns the passed in pointer.
+
+--*/
+{
+ return Pointer;
+}
+
+
+#endif // _MEM_BLOCK_MGR_DEFN_
diff --git a/private/utils/ulib/inc/message.hxx b/private/utils/ulib/inc/message.hxx
new file mode 100644
index 000000000..2747fabcc
--- /dev/null
+++ b/private/utils/ulib/inc/message.hxx
@@ -0,0 +1,203 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ message.hxx
+
+Abstract:
+
+ The MESSAGE class provides a dummy implementation of a message displayer
+ class. Message displayers are meant to be used by applications to
+ relay information to the user. Many functions will require a 'MESSAGE'
+ parameter through which to relay their output.
+
+ This particular implementation of this concept will do nothing. It
+ will be used by users who do not wish to have any output from their
+ applications.
+
+ Additionally, this class serves as a base class to real implementations
+ of the virtual methods.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 1-Apr-91
+
+--*/
+
+
+#if !defined(MESSAGE_DEFN)
+
+#define MESSAGE_DEFN
+
+#include "wstring.hxx"
+
+extern "C" {
+ #include <stdarg.h>
+}
+
+enum MESSAGE_TYPE {
+ NORMAL_MESSAGE,
+ ERROR_MESSAGE,
+ PROGRESS_MESSAGE
+};
+
+//
+// Each message also has a visualization: text or GUI. The default is both
+//
+
+#define TEXT_MESSAGE 0x1
+#define GUI_MESSAGE 0x2
+#define NORMAL_VISUAL (TEXT_MESSAGE | GUI_MESSAGE)
+
+
+DECLARE_CLASS( MESSAGE );
+DECLARE_CLASS( HMEM );
+
+
+DEFINE_TYPE(ULONG, MSGID);
+
+
+class MESSAGE : public OBJECT {
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR(MESSAGE);
+
+ VIRTUAL
+ ULIB_EXPORT
+ ~MESSAGE(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Set(
+ IN MSGID MsgId,
+ IN MESSAGE_TYPE MessageType DEFAULT NORMAL_MESSAGE,
+ IN ULONG MessageVisual DEFAULT NORMAL_VISUAL
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Display(
+ IN PCSTR Format ...
+ );
+
+ VIRTUAL
+ BOOLEAN
+ DisplayV(
+ IN PCSTR Format,
+ IN va_list VarPointer
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Display(
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ IsYesResponse(
+ IN BOOLEAN Default DEFAULT TRUE
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ QueryStringInput(
+ OUT PWSTRING String
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ WaitForUserSignal(
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ MSGID
+ SelectResponse(
+ IN ULONG NumberOfSelections ...
+ );
+
+ VIRTUAL
+ PMESSAGE
+ Dup(
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ IsLoggingEnabled(
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ VOID
+ SetLoggingEnabled(
+ IN BOOLEAN Enable DEFAULT TRUE
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ VOID
+ ResetLoggingIterator(
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ QueryNextLoggedMessage(
+ OUT PFSTRING MessageText
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ QueryPackedLog(
+ IN OUT PHMEM Mem,
+ OUT PULONG PackedDataLength
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ SetDotsOnly(
+ IN BOOLEAN DotsState
+ );
+};
+
+
+
+INLINE
+BOOLEAN
+MESSAGE::Display(
+ )
+/*++
+
+Routine Description:
+
+ This routine displays the message with no parameters.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ return Display("");
+}
+
+
+
+#endif // MESSAGE_DEFN
diff --git a/private/utils/ulib/inc/newdelp.hxx b/private/utils/ulib/inc/newdelp.hxx
new file mode 100644
index 000000000..f12823d3c
--- /dev/null
+++ b/private/utils/ulib/inc/newdelp.hxx
@@ -0,0 +1,73 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ newdelp.hxx
+
+Abstract:
+
+ This module contains the private definitions used by Ulib's
+ implementation of the new and delete operators and the CRT's malloc,
+ calloc, realloc and free functions.
+
+Author:
+
+ David J. Gilman (davegi) 07-Dec-1990
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+//
+// MEM_BLOCK header signature type and value.
+//
+
+DEFINE_TYPE( ULONG, MEM_BLOCKSIG );
+CONST MEM_BLOCKSIG Signature = 0xDEADDEAD;
+
+//
+// Maximum length of caller's file name.
+//
+
+CONST ULONG MaxFileLength = 20;
+
+//
+// Maximum size of call stack recorded.
+//
+
+CONST ULONG MaxCallStack = 20;
+
+//
+// MEM_BLOCK is the header attached to all allocated memory blocks.
+// Do not change the order of these fields without fixing the initialization
+// of the dummy MEM_BLOCK in newdel.cxx.
+//
+
+struct _MEM_BLOCK {
+ _MEM_BLOCK* pmemNext;
+ _MEM_BLOCK* pmemPrev;
+ MEM_BLOCKSIG memsig;
+ ULONG line;
+ ULONG size;
+ STR file[ MaxFileLength ];
+ DWORD call[ MaxCallStack ];
+};
+
+DEFINE_TYPE( struct _MEM_BLOCK, MEM_BLOCK );
+
+//
+// Returns the root of the stack frame list.
+//
+
+extern "C" {
+
+ VOID
+ DoStackTrace(
+ DWORD CallStack[]
+ );
+
+};
diff --git a/private/utils/ulib/inc/object.hxx b/private/utils/ulib/inc/object.hxx
new file mode 100644
index 000000000..81a37bbae
--- /dev/null
+++ b/private/utils/ulib/inc/object.hxx
@@ -0,0 +1,343 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Object.hxx
+
+Abstract:
+
+ This module contains the class declaration for the OBJECT class,
+ the root of the Ulib hierarchy. OBJECT is a very important class as
+ it provides default (and sometimes NONVIRTUAL) implementations for
+ helping to identify and classify all other objects at run-time. This
+ capability allows CONTAINERs to manipulate OBJECTs rather than a given
+ derived class of objects. OBJECTs supply the most primitive support for
+ polymorphism within the library. Along with CLASS_DESCRIPTORs they supply
+ the ability to safely determine (Cast) if an OBJECT is of a given class
+ at run-time.
+
+Author:
+
+ David J. Gilman (davegi) 22-Oct-1990
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if ! defined( _OBJECT_HXX_ )
+
+#define _OBJECT_HXX_
+
+#include "clasdesc.hxx"
+
+DECLARE_CLASS( OBJECT );
+
+#if DBG == 1
+
+ extern "C" {
+
+ #include <stdio.h>
+ };
+
+ #define DECLARE_OBJECT_DBG_FUNCTIONS \
+ \
+ VIRTUAL \
+ ULIB_EXPORT \
+ VOID \
+ DebugDump ( \
+ IN BOOLEAN Deep DEFAULT FALSE \
+ ) CONST; \
+ \
+ NONVIRTUAL \
+ PCCLASS_NAME \
+ DebugGetClassName ( \
+ ) CONST;
+
+ #define DEFINE_OBJECT_DBG_FUNCTIONS \
+ \
+ ULIB_EXPORT \
+ VOID \
+ OBJECT::DebugDump ( \
+ IN BOOLEAN Deep \
+ ) CONST \
+ { \
+ (void)(Deep); \
+ DebugPtrAssert( _ClassDescriptor ); \
+ } \
+ \
+ PCCLASS_NAME \
+ OBJECT::DebugGetClassName ( \
+ ) CONST \
+ { \
+ DebugPtrAssert( _ClassDescriptor ); \
+ return( _ClassDescriptor->DebugGetClassName( ));\
+ }
+
+
+ //
+ // Debug functions should never be invoked directly. Instead use the
+ // following Dbg macros. Inline functions are not used so that no space
+ // is used in the object when debugging is disabled.
+ //
+
+ #define DbgDump( pobj ) \
+ ( pobj )->DebugDump( FALSE );
+
+ #define DbgDumpAll( pobj ) \
+ ( pobj )->DebugDump( TRUE );
+
+ #define DbgDumpDeep( pobj, flag ) \
+ ( pobj )->DebugDump( flag );
+
+#else // DBG==0
+
+ #define DECLARE_OBJECT_DBG_FUNCTIONS
+
+ #define DEFINE_OBJECT_DBG_FUNCTIONS
+
+ #define DbgDump( pobj )
+
+ #define DbgDumpAll( pobj )
+
+ #define DbgDumpDeep( pobj, flag )
+
+#endif // DBG
+
+class OBJECT {
+
+ public:
+
+ VIRTUAL
+ ULIB_EXPORT
+ ~OBJECT(
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ LONG
+ Compare(
+ IN PCOBJECT Object
+ ) CONST;
+
+ NONVIRTUAL
+ PCCLASS_DESCRIPTOR
+ GetClassDescriptor(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsSameClass(
+ IN PCOBJECT Object
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsSameObject(
+ IN PCOBJECT Object
+ ) CONST;
+
+ NONVIRTUAL
+ CLASS_ID
+ QueryClassId(
+ ) CONST;
+
+ DECLARE_OBJECT_DBG_FUNCTIONS
+
+ protected:
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ OBJECT(
+ );
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ SetClassDescriptor(
+ IN PCCLASS_DESCRIPTOR ClassDescriptor
+ );
+
+ private:
+
+ PCCLASS_DESCRIPTOR _ClassDescriptor;
+
+};
+
+
+INLINE
+VOID
+OBJECT::Construct(
+ )
+{
+}
+
+
+INLINE
+CLASS_ID
+OBJECT::QueryClassId (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the CLASSID for this object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ CLASSID - The CLASSID as maintained by the object's CLASS_DESCRIPTOR.
+
+Notes:
+
+ This function used to be at the end of clasdesac.hxx with th following
+ note:
+
+ This member functions is for OBJECT, not for CLASS_DESCRIPTOR. It is
+ defined here because it requires CLASS_DESCRIPTOR to be defined in
+ order to make it inline.
+
+--*/
+
+{
+ DebugPtrAssert( _ClassDescriptor );
+
+ return _ClassDescriptor->QueryClassId();
+}
+
+
+INLINE
+VOID
+OBJECT::SetClassDescriptor (
+ IN PCCLASS_DESCRIPTOR ClassDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ Set the CLASS_DESCRIPTOR for a derived class.
+
+Arguments:
+
+ ClassDescriptor - Supplies a pointer to the derived class'
+ CLASS_DECRIPTOR.
+
+Return Value:
+
+ None.
+
+Notes:
+
+ This function should only be called by the DEFINE_CONSTRUCTOR macro.
+
+--*/
+
+{
+ DebugPtrAssert( ClassDescriptor );
+ _ClassDescriptor = ClassDescriptor;
+}
+
+
+
+INLINE
+PCCLASS_DESCRIPTOR
+OBJECT::GetClassDescriptor (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Gain access to the object's CLASS_DESCRIPTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PCCLASS_DESCRIPTOR - A pointer to the CLASS_DESCRIPTOR asscoicated with
+ this object.
+
+--*/
+
+{
+ DebugPtrAssert( _ClassDescriptor );
+
+ return( _ClassDescriptor );
+}
+
+
+INLINE
+BOOLEAN
+OBJECT::IsSameClass (
+ IN PCOBJECT Object
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine if this object and the supplied object are of the same class
+ by checking their CLASS_IDs for equality.
+
+Arguments:
+
+ Object - Supplies the object to compare class types against.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if this object and the supplied object are of
+ the same class.
+
+--*/
+
+{
+ DebugPtrAssert( Object );
+
+ return (BOOLEAN) (QueryClassId() == Object->QueryClassId());
+}
+
+
+INLINE
+BOOLEAN
+OBJECT::IsSameObject (
+ IN PCOBJECT Object
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determine if this object and the supplied object are the same by checking
+ their CLASS_IDs and then their memory location.
+
+Arguments:
+
+ Object - Supplies the object to compare for equivalence.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if this object and the supplied object are
+ equivalent.
+
+--*/
+
+{
+ return (BOOLEAN) (this == Object);
+}
+
+
+#endif // OBJECT
diff --git a/private/utils/ulib/inc/path.hxx b/private/utils/ulib/inc/path.hxx
new file mode 100644
index 000000000..f950da038
--- /dev/null
+++ b/private/utils/ulib/inc/path.hxx
@@ -0,0 +1,508 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ path.hxx
+
+Abstract:
+
+ The PATH class provides an interface to the complete
+ Win32 name space. Complete means that it will correctly
+ handle long, drive or UNC based, blank embedded, mixed case
+ names. It should eliminate the need for everyone to code
+ statements such as "is the second char a ':'" or "search for
+ the first '\' from the end of the name". That is, access to and
+ manipulation of path and file names should be performed soley
+ through the PATH member functions. This will eliminate
+ the recoding of standard name manipulation code and ensure
+ complete support of Win32 functionality, such as codepage and
+ DBCS support.
+
+Author:
+
+ Steve Rowe 13-Dec-90
+
+Environment:
+
+ ULIB, user
+
+Notes:
+
+
+ To clarify terminology used here, the following describes a
+ canonicalized path (in butchered BNF/reg exp):
+
+ {Canon} ::= {Prefix}"\"{Name}
+ {Prefix} ::= {Device}{Dirs}
+ {Dirs} ::= {"\"{Component}}*
+ {Device} ::= {Drive}|{Machine}
+ {Drive} ::= {Letter}":"
+ {Machine} ::= "\\"{Char}+
+ {Letter} ::= valid drive letter [a-zA-Z]
+ {Char} ::= valid filename/directory char [~:\]
+ {Component} ::= {Char}+
+ {Name} ::= {Base - excluding "."} | { {Base}"."{Ext} }
+ {Base} ::= {Char}+
+ {Ext} ::= {Char - excluding "."}+
+
+ Legend:
+ -------
+ {x}* - 0 or more x
+ {x}+ - 1 or more x
+ "x" - just x (not the quotes)
+ {x}|{y} - x or y (not both or none)
+
+
+ Examples:
+ ---------
+ # Canon
+ --- -----
+ (1) x:\abc\def.ghi\jkl.mnop
+ (2) \\x\abc\def.ghi\jkl.mnop
+ (3) c:\config.sys
+
+ (1) (2) (3)
+
+ Prefix x:\abc\def.ghi \\x\abc\def.ghi c:
+ Device x: \\x c:
+ Dirs \abc \abc\def.ghi
+ Name jkl.mnop jkl.mnop config.sys
+ Base jkl jkl config
+ Ext mnop mnop sys
+
+ Component numbers are 0-based.
+
+
+--*/
+
+#if !defined( _PATH_)
+
+#define _PATH_
+
+#include "wstring.hxx"
+#include "array.hxx"
+
+//
+// Forward references & declarations
+//
+
+DECLARE_CLASS( PATH );
+
+
+
+//
+// PATHSTATE maintains the number of characters within each component that
+// makes up a PATH
+//
+struct _PATHSTATE {
+
+ //
+ // Prefix
+ //
+ CHNUM PrefixLen;
+ CHNUM DeviceLen;
+ CHNUM DirsLen;
+ CHNUM SeparatorLen;
+
+ //
+ // Name
+ //
+ CHNUM NameLen;
+ CHNUM BaseLen;
+ CHNUM ExtLen;
+
+};
+
+DEFINE_TYPE( struct _PATHSTATE, PATHSTATE );
+
+class PATH : public OBJECT {
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( PATH );
+
+ DECLARE_CAST_MEMBER_FUNCTION( PATH );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize (
+ IN PCWSTR InitialPath,
+ IN BOOLEAN Canonicalize DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize (
+ IN PCWSTRING InitialPath,
+ IN BOOLEAN Canonicalize DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize (
+ IN PCPATH InitialPath,
+ IN BOOLEAN Canonicalize DEFAULT FALSE
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ ~PATH (
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ AppendBase (
+ IN PCWSTRING Base,
+ IN BOOLEAN Absolute DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ EndsWithDelimiter (
+ ) CONST;
+
+ NONVIRTUAL
+ PCWSTRING
+ GetPathString (
+ ) CONST;
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ HasWildCard (
+ ) CONST;
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ IsDrive (
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsRoot (
+ ) CONST;
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ ModifyName (
+ IN PCWSTRING Pattern
+ );
+
+ NONVIRTUAL
+ PWSTRING
+ QueryBase (
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ PARRAY
+ QueryComponentArray (
+ OUT PARRAY Array DEFAULT NULL
+ ) CONST;
+
+ NONVIRTUAL
+ PWSTRING
+ QueryDevice (
+ );
+
+ NONVIRTUAL
+ PWSTRING
+ QueryDirs (
+ );
+
+ NONVIRTUAL
+ PWSTRING
+ QueryDirsAndName (
+ );
+
+ NONVIRTUAL
+ PWSTRING
+ QueryExt (
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ PPATH
+ QueryFullPath (
+ ) CONST;
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ PWSTRING
+ QueryFullPathString (
+ ) CONST;
+
+ NONVIRTUAL
+ PWSTRING
+ QueryName (
+ ) CONST;
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ PPATH
+ QueryPath (
+ ) CONST;
+
+ NONVIRTUAL
+ PWSTRING
+ QueryPrefix (
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ PWSTRING
+ QueryRoot (
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ PPATH
+ QueryWCExpansion(
+ IN PPATH BasePath
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetBase (
+ IN PCWSTRING NewBase
+ );
+
+ ULIB_EXPORT
+ BOOLEAN
+ SetDevice (
+ IN PCWSTRING NewDevice
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetExt (
+ IN PCWSTRING NewExt
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ SetName (
+ IN PCWSTRING NewName
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetPrefix (
+ IN PCWSTRING NewPrefix
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ TruncateBase (
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ VOID
+ TruncateNameAtColon (
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ExpandWildCards(
+ IN OUT PWSTRING pStr1,
+ IN OUT PWSTRING pStr2
+ );
+
+ BOOLEAN
+ Initialize (
+ );
+
+ NONVIRTUAL
+ CHNUM
+ QueryBaseStart (
+ ) CONST;
+
+ CHNUM
+ QueryDeviceLen(
+ IN PWSTRING pString
+ ) CONST;
+
+ NONVIRTUAL
+ CHNUM
+ QueryDeviceStart (
+ ) CONST;
+
+ NONVIRTUAL
+ CHNUM
+ QueryExtStart (
+ ) CONST;
+
+ NONVIRTUAL
+ CHNUM
+ QueryNameStart (
+ ) CONST;
+
+ NONVIRTUAL
+ CHNUM
+ QueryPrefixStart (
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetPathState (
+ );
+
+
+
+#if DBG==1
+
+ ULONG _Signature;
+ BOOLEAN _Initialized;
+
+#endif
+ //
+ // path data
+ //
+ WCHAR _PathBuffer[MAX_PATH];
+ FSTRING _PathString;
+ PATHSTATE _PathState;
+
+};
+
+INLINE
+CHNUM
+PATH::QueryPrefixStart (
+ ) CONST
+
+{
+ return( 0 );
+}
+
+INLINE
+CHNUM
+PATH::QueryNameStart (
+ ) CONST
+
+{
+ //
+ // Increment past the '\'
+ //
+ return( QueryPrefixStart() + _PathState.PrefixLen + _PathState.SeparatorLen );
+}
+
+INLINE
+CHNUM
+PATH::QueryBaseStart (
+ ) CONST
+
+{
+ return( QueryNameStart() );
+}
+
+INLINE
+CHNUM
+PATH::QueryDeviceStart (
+ ) CONST
+
+{
+ return( 0 );
+}
+
+INLINE
+CHNUM
+PATH::QueryExtStart (
+ ) CONST
+{
+ return( QueryNameStart() + _PathState.BaseLen + 1 );
+}
+
+INLINE
+PCWSTRING
+PATH::GetPathString (
+ ) CONST
+
+{
+ return( &_PathString );
+}
+
+INLINE
+PWSTRING
+PATH::QueryBase (
+ )
+
+{
+ return( _PathState.BaseLen ? _PathString.QueryString( QueryBaseStart(), _PathState.BaseLen ) : NULL );
+}
+
+INLINE
+PWSTRING
+PATH::QueryDirs (
+ )
+
+{
+ return( _PathState.DirsLen ? _PathString.QueryString( QueryDeviceStart() + _PathState.DeviceLen, _PathState.DirsLen ) : NULL );
+}
+
+INLINE
+PWSTRING
+PATH::QueryDirsAndName (
+ )
+
+{
+ return( ( _PathState.DirsLen || _PathState.NameLen ) ? _PathString.QueryString( QueryDeviceStart() + _PathState.DeviceLen ) : NULL );
+}
+
+INLINE
+PWSTRING
+PATH::QueryDevice (
+ )
+
+{
+ return( _PathState.DeviceLen ? _PathString.QueryString( QueryDeviceStart(), _PathState.DeviceLen ) : NULL );
+}
+
+INLINE
+PWSTRING
+PATH::QueryExt (
+ )
+
+{
+ return( _PathState.ExtLen ? _PathString.QueryString( QueryExtStart(), _PathState.ExtLen ) : NULL );
+}
+
+INLINE
+PWSTRING
+PATH::QueryName (
+ ) CONST
+
+{
+ return( _PathState.NameLen ? _PathString.QueryString( QueryNameStart(), _PathState.NameLen ) : NULL );
+}
+
+INLINE
+PWSTRING
+PATH::QueryPrefix (
+ )
+
+{
+ return( _PathState.PrefixLen ? _PathString.QueryString( QueryPrefixStart(), _PathState.PrefixLen ) : NULL );
+}
+
+
+
+#endif // _PATH_
diff --git a/private/utils/ulib/inc/pipe.hxx b/private/utils/ulib/inc/pipe.hxx
new file mode 100644
index 000000000..aef3c917d
--- /dev/null
+++ b/private/utils/ulib/inc/pipe.hxx
@@ -0,0 +1,121 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ pipe.hxx
+
+Abstract:
+
+ This module defines the PIPE object.
+
+Author:
+
+ Barry J. Gilhuly (W-Barry) June 27, 1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if ! defined( _PIPE_ )
+
+#define _PIPE_
+
+
+DECLARE_CLASS( PIPE_STREAM );
+DECLARE_CLASS( PIPE );
+DECLARE_CLASS( WSTRING );
+
+class PIPE : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( PIPE );
+
+ DECLARE_CAST_MEMBER_FUNCTION( PIPE );
+
+ BOOLEAN
+ Initialize(
+ IN LPSECURITY_ATTRIBUTES PipeAttributes DEFAULT NULL,
+ IN ULONG PipeSize DEFAULT 0,
+ IN PWSTRING PipeName DEFAULT NULL
+ );
+
+ PPIPE_STREAM
+ QueryReadStream(
+ );
+
+ PPIPE_STREAM
+ QueryWriteStream(
+ );
+
+ private:
+
+ PPIPE_STREAM
+ QueryPipeStream(
+ IN HANDLE hStream,
+ IN STREAMACCESS Access
+ );
+
+ VOID
+ Destroy(
+ );
+
+ BOOLEAN _fInitialized;
+ HANDLE _hReadPipe;
+ HANDLE _hWritePipe;
+
+};
+
+INLINE
+PPIPE_STREAM
+PIPE::QueryReadStream(
+ )
+/*++
+
+Routine Description:
+
+ Create a stream with read access to the PIPE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the created stream if success. Otherwise, it returns
+ NULL.
+
+--*/
+{
+ return( QueryPipeStream( _hReadPipe, READ_ACCESS ) );
+}
+
+INLINE
+PPIPE_STREAM
+PIPE::QueryWriteStream(
+ )
+/*++
+
+Routine Description:
+
+ Create a stream with write access to the PIPE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the created stream if success. Otherwise, it returns
+ NULL.
+
+--*/
+{
+ return( QueryPipeStream( _hWritePipe, WRITE_ACCESS ) );
+}
+
+#endif // _PIPE_
diff --git a/private/utils/ulib/inc/pipestrm.hxx b/private/utils/ulib/inc/pipestrm.hxx
new file mode 100644
index 000000000..28faf4ff5
--- /dev/null
+++ b/private/utils/ulib/inc/pipestrm.hxx
@@ -0,0 +1,112 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ pipestr.hxx
+
+Abstract:
+
+ This module contains the declaration for the PIPE_STREAM class.
+ The PIPE_STREAM is a class derived from BUFFER_STREAM that provides
+ methods to read and write data to an anonymous pipe.
+ A PIPE_STREAM will have one of the following access: READ or WRITE.
+
+
+Author:
+
+ Jaime Sasson (jaimes) 18-Apr-1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+
+#if !defined( PIPE_STREAM_ )
+
+#define PIPE_STREAM_
+
+#include "bufstrm.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( PIPE_STREAM );
+DECLARE_CLASS( WSTRING );
+
+
+class PIPE_STREAM : public BUFFER_STREAM {
+
+ public:
+
+ friend class PIPE;
+ friend PSTREAM GetStandardStream( HANDLE, STREAMACCESS );
+
+ DECLARE_CAST_MEMBER_FUNCTION( PIPE_STREAM );
+
+ VIRTUAL
+ ~PIPE_STREAM(
+ );
+
+ VIRTUAL
+ STREAMACCESS
+ QueryAccess(
+ ) CONST;
+
+
+ protected:
+
+
+ DECLARE_CONSTRUCTOR( PIPE_STREAM );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN HANDLE Handle,
+ IN STREAMACCESS Access
+ );
+
+ VIRTUAL
+ BOOLEAN
+ EndOfFile(
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ FillBuffer(
+ IN PBYTE Buffer,
+ IN ULONG BufferSize,
+ OUT PULONG BytesRead
+ );
+
+ VIRTUAL
+ HANDLE
+ QueryHandle(
+ ) CONST;
+
+#ifdef DBCS // v-junm - 10/15/93
+
+ VIRTUAL
+ BOOLEAN
+ CheckIfLeadByte(
+ IN PUCHAR text,
+ IN ULONG offset
+ );
+
+#endif
+
+
+ private:
+
+ HANDLE _PipeHandle;
+ STREAMACCESS _Access;
+ BOOLEAN _EndOfFile;
+};
+
+
+#endif // _PIPE_STREAM_
diff --git a/private/utils/ulib/inc/program.hxx b/private/utils/ulib/inc/program.hxx
new file mode 100644
index 000000000..7e675b6aa
--- /dev/null
+++ b/private/utils/ulib/inc/program.hxx
@@ -0,0 +1,146 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ program.hxx
+
+Abstract:
+
+Author:
+
+ David J. Gilman (davegi) 02-Mar-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if ! defined( _PROGRAM_ )
+
+#define _PROGRAM_
+
+#include "rtmsg.h"
+#include "smsg.hxx"
+
+DECLARE_CLASS( PATH );
+DECLARE_CLASS( PROGRAM );
+
+class PROGRAM : public OBJECT {
+
+ public:
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize (
+ IN MSGID UsageMsg DEFAULT MSG_UTILS_HELP,
+ IN MSGID FatalMsg DEFAULT MSG_UTILS_ERROR_FATAL,
+ IN ULONG FatalLevel DEFAULT 1
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ ~PROGRAM (
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ DisplayMessage (
+ IN MSGID Message,
+ IN MESSAGE_TYPE Type DEFAULT NORMAL_MESSAGE
+ ) CONST;
+
+ VIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ DisplayMessage (
+ IN MSGID Message,
+ IN MESSAGE_TYPE Type,
+ IN PSTR Format,
+ IN ...
+ ) CONST;
+
+ VIRTUAL
+ ULIB_EXPORT
+ VOID
+ ExitProgram (
+ ULONG Level
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ VOID
+ Fatal (
+ ) CONST;
+
+ VIRTUAL
+ ULIB_EXPORT
+ VOID
+ Fatal (
+ IN ULONG ErrorLevel,
+ IN MSGID Message,
+ IN PSTR Format,
+ IN ...
+ ) CONST;
+
+ VIRTUAL
+ ULIB_EXPORT
+ PSTREAM
+ GetStandardInput (
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ PSTREAM
+ GetStandardOutput (
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ PSTREAM
+ GetStandardError (
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ VOID
+ Usage (
+ ) CONST;
+
+ STATIC
+ PPATH
+ QueryImagePath (
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ VOID
+ ValidateVersion (
+ IN MSGID InvalidVersionMsg DEFAULT MSG_UTILS_ERROR_INVALID_VERSION,
+ IN ULONG ErrorLevel DEFAULT 1
+ ) CONST;
+
+ protected:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( PROGRAM );
+
+ STREAM_MESSAGE _Message; // Message stream
+ PSTREAM _Standard_Input; // Standard input
+ PSTREAM _Standard_Output; // Standard output
+ PSTREAM _Standard_Error; // Standard error
+
+ private:
+
+ MSGID _UsageMsg; // Usage message id.
+ MSGID _FatalMsg; // Fatal message id.
+ ULONG _FatalLevel; // Fatal error level
+
+};
+
+
+#endif // _PROGRAM_
diff --git a/private/utils/ulib/inc/prtstrm.hxx b/private/utils/ulib/inc/prtstrm.hxx
new file mode 100644
index 000000000..0fa283218
--- /dev/null
+++ b/private/utils/ulib/inc/prtstrm.hxx
@@ -0,0 +1,143 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ prtstrm.hxx
+
+Abstract:
+
+ This module contains the declaration for the PRINT_STREAM class.
+ The PRINT_STREAM is a class derived from STREAM that provides
+ methods to write data to a print device.
+ A PRINT_STREAM has always WRITE_ACCESS.
+
+
+Author:
+
+ Jaime Sasson (jaimes) 18-Apr-1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+
+#if !defined( _PRINT_STREAM_ )
+
+#define _PRINT_STREAM_
+
+#include "stream.hxx"
+
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( PRINT_STREAM );
+DECLARE_CLASS( WSTRING );
+DECLARE_CLASS( PATH );
+
+
+class PRINT_STREAM : public STREAM {
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( PRINT_STREAM );
+
+ DECLARE_CAST_MEMBER_FUNCTION( PRINT_STREAM );
+
+ VIRTUAL
+ ULIB_EXPORT
+ ~PRINT_STREAM(
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize(
+ IN PCPATH DeviceName
+ );
+
+ VIRTUAL
+ BOOLEAN
+ IsAtEnd(
+ ) CONST;
+
+ VIRTUAL
+ STREAMACCESS
+ QueryAccess(
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ Read(
+ OUT PBYTE Buffer,
+ IN ULONG BytesToRead,
+ OUT PULONG BytesRead
+ );
+
+ VIRTUAL
+ BOOLEAN
+ ReadChar(
+ OUT PWCHAR Char,
+ IN BOOLEAN Unicode DEFAULT FALSE
+ );
+
+ VIRTUAL
+ BOOLEAN
+ ReadMbString(
+ IN PSTR String,
+ IN DWORD BufferSize,
+ INOUT PDWORD StringSize,
+ IN PSTR Delimiters,
+ IN BOOLEAN ExpandTabs DEFAULT FALSE,
+ IN DWORD TabExp DEFAULT 8
+ );
+
+ VIRTUAL
+ BOOLEAN
+ ReadWString(
+ IN PWSTR String,
+ IN DWORD BufferSize,
+ INOUT PDWORD StringSize,
+ IN PWSTR Delimiters,
+ IN BOOLEAN ExpandTabs DEFAULT FALSE,
+ IN DWORD TabExp DEFAULT 8
+ );
+
+ VIRTUAL
+ BOOLEAN
+ ReadString(
+ OUT PWSTRING String,
+ IN PWSTRING Delimiters,
+ IN BOOLEAN Unicode DEFAULT FALSE
+ );
+
+
+
+ protected:
+
+ VIRTUAL
+ HANDLE
+ QueryHandle(
+ ) CONST;
+
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ HANDLE _Handle;
+};
+
+
+
+#endif // _PRINT_STREAM_
diff --git a/private/utils/ulib/inc/screen.hxx b/private/utils/ulib/inc/screen.hxx
new file mode 100644
index 000000000..6c3c5ceb6
--- /dev/null
+++ b/private/utils/ulib/inc/screen.hxx
@@ -0,0 +1,484 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ screen.hxx
+
+Abstract:
+
+ This module contains the declaration for the SCREEN class.
+ The SCREEN class provides methods that models the stream
+ of bytes, with write access.
+ Read operations from a SCREEN are not allowed.
+ End of stream in a SCREEN object means that the cursor is
+ in the last column of the last row.
+
+
+Author:
+
+ Jaime Sasson (jaimes) 21-Mar-1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+
+#if !defined( _SCREEN_ )
+
+#define _SCREEN_
+
+#include "stream.hxx"
+
+
+enum SCROLL_DIRECTION {
+ SCROLL_UP,
+ SCROLL_DOWN,
+ SCROLL_LEFT,
+ SCROLL_RIGHT
+ };
+
+DECLARE_CLASS( SCREEN );
+
+
+class SCREEN : public STREAM {
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( SCREEN );
+
+ ULIB_EXPORT
+ DECLARE_CAST_MEMBER_FUNCTION( SCREEN );
+
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ ~SCREEN (
+ );
+
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize(
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN BOOLEAN CurrentActiveScreen,
+ IN USHORT NumberOfRows,
+ IN USHORT NumberOfColumns,
+ IN USHORT TextAttribute,
+ IN BOOLEAN ExpandAsciiControlSequence DEFAULT TRUE,
+ IN BOOLEAN WrapAtEndOfLine DEFAULT TRUE
+ );
+
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ ChangeScreenSize(
+ IN USHORT NumberOfRows,
+ IN USHORT NumberOfColumns,
+ OUT PBOOLEAN IsFullScreen DEFAULT NULL
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ ChangeTextAttribute(
+ IN USHORT Attribute
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ DisableAsciiControlSequence(
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ DisableWrapMode(
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ EnableAsciiControlSequence(
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ EnableWrapMode(
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ EraseLine(
+ IN USHORT LineNumber
+ );
+
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ EraseScreen(
+ );
+
+
+#ifdef DBCS
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ EraseScreenAndResetAttribute(
+ );
+#endif
+
+
+ NONVIRTUAL
+ BOOLEAN
+ EraseToEndOfLine(
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ FillRectangularRegionAttribute(
+ IN USHORT TopLeftRow,
+ IN USHORT TopLeftColumn,
+ IN USHORT BottomRightRow,
+ IN USHORT BottomRightColumn,
+ IN USHORT Attribute
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ FillRegionAttribute(
+ IN USHORT StartRow,
+ IN USHORT StartColumn,
+ IN USHORT EndRow,
+ IN USHORT EndColumn,
+ IN USHORT Attribute
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ FillRectangularRegionCharacter(
+ IN USHORT TopLeftRow,
+ IN USHORT TopLeftColumn,
+ IN USHORT BottomRightRow,
+ IN USHORT BottomRightColumn,
+ IN CHAR Character
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ FillRegionCharacter(
+ IN USHORT StartRow,
+ IN USHORT StartColumn,
+ IN USHORT EndRow,
+ IN USHORT EndColumn,
+ IN CHAR Character
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ IsAsciiControlSequenceEnabled(
+ ) CONST;
+
+
+ VIRTUAL
+ BOOLEAN
+ IsAtEnd(
+ ) CONST;
+
+
+ NONVIRTUAL
+ BOOLEAN
+ IsWrapModeEnabled(
+ ) CONST;
+
+
+ NONVIRTUAL
+ BOOLEAN
+ MoveCursorDown(
+ IN USHORT Rows
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ MoveCursorLeft(
+ IN USHORT Columns
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ MoveCursorRight(
+ IN USHORT Columns
+ );
+
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ MoveCursorTo(
+ IN USHORT Row,
+ IN USHORT Column
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ MoveCursorUp(
+ IN USHORT Rows
+ );
+
+
+ VIRTUAL
+ STREAMACCESS
+ QueryAccess(
+ ) CONST;
+
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ DWORD
+ QueryCodePage (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryCursorPosition(
+ OUT PUSHORT Row,
+ OUT PUSHORT Column
+ );
+
+
+ VIRTUAL
+ HANDLE
+ QueryHandle(
+ ) CONST;
+
+
+ NONVIRTUAL
+ DWORD
+ QueryOutputCodePage (
+ );
+
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ VOID
+ QueryScreenSize(
+ OUT PUSHORT NumberOfRows,
+ OUT PUSHORT NumberOfColumns,
+ OUT PUSHORT WindowRows DEFAULT NULL,
+ OUT PUSHORT WindowColumns DEFAULT NULL
+ ) CONST;
+
+
+ VIRTUAL
+ BOOLEAN
+ Read(
+ OUT PBYTE Buffer,
+ IN ULONG BytesToRead,
+ OUT PULONG BytesRead
+ );
+
+
+ VIRTUAL
+ BOOLEAN
+ ReadChar(
+ OUT PWCHAR Char,
+ IN BOOLEAN Unicode DEFAULT FALSE
+ );
+
+
+ VIRTUAL
+ BOOLEAN
+ ReadMbString(
+ IN PSTR String,
+ IN DWORD BufferSize,
+ INOUT PDWORD StringSize,
+ IN PSTR Delimiters,
+ IN BOOLEAN ExpandTabs DEFAULT FALSE,
+ IN DWORD TabExp DEFAULT 8
+ );
+
+ VIRTUAL
+ BOOLEAN
+ ReadWString(
+ IN PWSTR String,
+ IN DWORD BufferSize,
+ INOUT PDWORD StringSize,
+ IN PWSTR Delimiters,
+ IN BOOLEAN ExpandTabs DEFAULT FALSE,
+ IN DWORD TabExp DEFAULT 8
+ );
+
+ VIRTUAL
+ BOOLEAN
+ ReadString(
+ OUT PWSTRING String,
+ IN PWSTRING Delimiter,
+ IN BOOLEAN Unicode DEFAULT FALSE
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ ScrollScreen(
+ USHORT Amount,
+ SCROLL_DIRECTION Direction
+ );
+
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ SetCodePage(
+ IN DWORD CodePage
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetCursorOff(
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ SetCursorOn(
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ SetCursorSize(
+ IN ULONG Size
+ );
+
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ SetOutputCodePage(
+ IN DWORD CodePage
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetScreenActive(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ WriteString(
+ IN PCWSTRING String,
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END,
+ IN CHNUM Granularity DEFAULT 0
+ );
+
+ VIRTUAL
+ BOOLEAN
+ WriteChar(
+ IN WCHAR Char
+ );
+
+ private:
+
+ HANDLE _ScreenHandle;
+// USHORT _Rows;
+// USHORT _Columns;
+ USHORT _TextAttribute;
+ ULONG _ScreenMode;
+
+
+};
+
+
+INLINE
+BOOLEAN
+SCREEN::IsAsciiControlSequenceEnabled(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determines if expansion of ASCII control sequences are currently
+ allowed.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if ASCII control sequences are allowed.
+
+
+--*/
+
+
+{
+ if( ( _ScreenMode & ENABLE_PROCESSED_OUTPUT ) ) {
+ return( TRUE );
+ } else {
+ return( FALSE );
+ }
+}
+
+
+
+INLINE
+BOOLEAN
+SCREEN::IsWrapModeEnabled(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determines if twrap is allowed in the screen.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the screen is in the wrap mode.
+
+
+--*/
+
+
+{
+ if( ( _ScreenMode & ENABLE_WRAP_AT_EOL_OUTPUT ) ) {
+ return( TRUE );
+ } else {
+ return( FALSE );
+ }
+}
+
+
+
+#endif // _SCREEN_
diff --git a/private/utils/ulib/inc/seqcnt.hxx b/private/utils/ulib/inc/seqcnt.hxx
new file mode 100644
index 000000000..352a86286
--- /dev/null
+++ b/private/utils/ulib/inc/seqcnt.hxx
@@ -0,0 +1,83 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ seqcnt.hxx
+
+Abstract:
+
+ This module contains the declaration for the SEQUENTIAL_CONTAINER class.
+ SEQUENTIAL_CONTAINER is a fairly primitive class which augments the
+ CONTAINER class by adding the capability that the objects stored in the
+ container have some sort of sequenced relationship. This means that
+ OBJECTs can be queried from SEQUENTIAL_CONTAINERs by the use of an
+ ITERATOR and that the concepts first, last, next and previous have
+ meaning.
+
+Author:
+
+ David J. Gilman (davegi) 29-Oct-1990
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if ! defined( _SEQUENTIAL_CONTAINER_ )
+
+#define _SEQUENTIAL_CONTAINER_
+
+#include "contain.hxx"
+
+DECLARE_CLASS( SEQUENTIAL_CONTAINER );
+DECLARE_CLASS( ITERATOR );
+
+class SEQUENTIAL_CONTAINER : public CONTAINER {
+
+ FRIEND class ITERATOR;
+
+ public:
+
+ VIRTUAL
+ ~SEQUENTIAL_CONTAINER(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Put(
+ IN OUT POBJECT Member
+ ) PURE;
+
+ VIRTUAL
+ ULONG
+ QueryMemberCount(
+ ) CONST PURE;
+
+ VIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ DeleteAllMembers(
+ );
+
+ VIRTUAL
+ PITERATOR
+ QueryIterator(
+ ) CONST PURE;
+
+ VIRTUAL
+ POBJECT
+ Remove(
+ IN OUT PITERATOR Position
+ ) PURE;
+
+ protected:
+
+ DECLARE_CONSTRUCTOR( SEQUENTIAL_CONTAINER );
+
+};
+
+
+#endif // _SEQUENTIAL_CONTAINER_
diff --git a/private/utils/ulib/inc/smsg.hxx b/private/utils/ulib/inc/smsg.hxx
new file mode 100644
index 000000000..13581bbb4
--- /dev/null
+++ b/private/utils/ulib/inc/smsg.hxx
@@ -0,0 +1,173 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ smsg.hxx
+
+Abstract:
+
+ The STREAM_MESSAGE class offers a STREAM implementation of the
+ MESSAGE class. The messages are output to the STREAM to which
+ the object is initialized to.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 1-Apr-91
+
+--*/
+
+
+#if !defined(STREAM_MESSAGE_DEFN)
+
+#define STREAM_MESSAGE_DEFN
+
+#include "message.hxx"
+
+DECLARE_CLASS( STREAM_MESSAGE );
+DECLARE_CLASS( STREAM );
+
+class STREAM_MESSAGE : public MESSAGE {
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( STREAM_MESSAGE );
+
+ VIRTUAL
+ ULIB_EXPORT
+ ~STREAM_MESSAGE(
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize(
+ IN OUT PSTREAM OutputStream,
+ IN OUT PSTREAM InputStream,
+ IN OUT PSTREAM ErrorStream DEFAULT NULL
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Set(
+ IN MSGID MsgId,
+ IN MESSAGE_TYPE MessageType DEFAULT NORMAL_MESSAGE,
+ IN ULONG MessageVisual DEFAULT NORMAL_VISUAL
+ );
+
+ VIRTUAL
+ BOOLEAN
+ DisplayV(
+ IN PCSTR Format,
+ IN va_list VarPointer
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ IsYesResponse(
+ IN BOOLEAN Default DEFAULT TRUE
+ );
+
+ VIRTUAL
+ BOOLEAN
+ QueryStringInput(
+ OUT PWSTRING String
+ );
+
+ VIRTUAL
+ BOOLEAN
+ WaitForUserSignal(
+ );
+
+ VIRTUAL
+ MSGID
+ SelectResponse(
+ IN ULONG NumberOfSelections ...
+ );
+
+ NONVIRTUAL
+ VOID
+ SetInputCaseSensitivity(
+ IN BOOLEAN CaseSensitive
+ );
+
+ VIRTUAL
+ PMESSAGE
+ Dup(
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ReadLine(
+ OUT PWSTRING String
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Flush(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DisplayString(
+ );
+
+ MSGID _msgid;
+ MESSAGE_TYPE _msgtype;
+ ULONG _msgvisual;
+ PSTREAM _out_stream;
+ PSTREAM _in_stream;
+ PSTREAM _err_stream;
+ BOOLEAN _case_sensitive;
+ BOOLEAN _copy_input;
+ DSTRING _display_string;
+
+};
+
+
+typedef STREAM_MESSAGE* PSTREAM_MESSAGE;
+
+
+INLINE
+VOID
+STREAM_MESSAGE::SetInputCaseSensitivity(
+ IN BOOLEAN CaseSensitive
+ )
+/*++
+
+Routine Description:
+
+ This routine sets whether or not to be case sensitive on input.
+ The class defaults this value to FALSE when it is initialized.
+
+Arguments:
+
+ CaseSensitive - Supplies whether or not to be case sensitive on input.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _case_sensitive = CaseSensitive;
+}
+
+
+#endif // STREAM_MESSAGE_DEFN
diff --git a/private/utils/ulib/inc/sortcnt.hxx b/private/utils/ulib/inc/sortcnt.hxx
new file mode 100644
index 000000000..a4870e5a5
--- /dev/null
+++ b/private/utils/ulib/inc/sortcnt.hxx
@@ -0,0 +1,79 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ sortcnt.hxx
+
+Abstract:
+
+ This module contains the declaration for the SORTABLE_CONTAINER class.
+ SORTABLE_CONTAINER is an abstract classe that is derived from the abstract
+ class SEQUENTIAL_CONTAINER. It not only assumes a sequence but also
+ assumes that the sequence can be changed by sorting it's contents. That
+ is the contents have a relative order independent from how they were
+ placed in the container.
+
+Author:
+
+ David J. Gilman (davegi) 29-Oct-1990
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if ! defined( _SORTABLE_CONTAINER_ )
+
+#define _SORTABLE_CONTAINER_
+
+#include "seqcnt.hxx"
+
+DECLARE_CLASS( SORTABLE_CONTAINER );
+
+class SORTABLE_CONTAINER : public SEQUENTIAL_CONTAINER {
+
+ public:
+
+ VIRTUAL
+ ~SORTABLE_CONTAINER(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Put(
+ IN OUT POBJECT Member
+ ) PURE;
+
+ VIRTUAL
+ ULONG
+ QueryMemberCount(
+ ) CONST PURE;
+
+ VIRTUAL
+ PITERATOR
+ QueryIterator(
+ ) CONST PURE;
+
+ VIRTUAL
+ POBJECT
+ Remove(
+ IN OUT PITERATOR Position
+ ) PURE;
+
+ VIRTUAL
+ BOOLEAN
+ Sort(
+ IN BOOLEAN Ascending DEFAULT TRUE
+ ) PURE;
+
+ protected:
+
+ DECLARE_CONSTRUCTOR( SORTABLE_CONTAINER );
+
+};
+
+
+#endif // _SORTABLE_CONTAINER_
diff --git a/private/utils/ulib/inc/sortlist.hxx b/private/utils/ulib/inc/sortlist.hxx
new file mode 100644
index 000000000..a2ae1ecb0
--- /dev/null
+++ b/private/utils/ulib/inc/sortlist.hxx
@@ -0,0 +1,153 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ sortlist.hxx
+
+Abstract:
+
+ This module contains the declaration for the SORTED_LIST class.
+
+ SORTED_LIST is a concrete implementation of a SORTABLE_CONTAINER.
+ The elements in a SORTED_LIST are maintained in sorted order.
+
+Author:
+
+ Ramon J. San Andres (ramonsa) 29-Oct-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if ! defined( _SORTED_LIST_ )
+
+#define _SORTED_LIST_
+
+#include "sortcnt.hxx"
+#include "array.hxx"
+
+DECLARE_CLASS( SORTED_LIST );
+
+class SORTED_LIST : public SORTABLE_CONTAINER {
+
+ friend class SORTED_LIST_ITERATOR;
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( SORTED_LIST );
+
+ DECLARE_CAST_MEMBER_FUNCTION( SORTED_LIST );
+
+ VIRTUAL
+ ULIB_EXPORT
+ ~SORTED_LIST (
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize (
+ IN BOOLEAN Ascending DEFAULT TRUE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsAscending (
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ DeleteAllMembers(
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Put (
+ IN OUT POBJECT Member
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ PITERATOR
+ QueryIterator (
+ ) CONST;
+
+ VIRTUAL
+ ULIB_EXPORT
+ ULONG
+ QueryMemberCount (
+ ) CONST;
+
+ VIRTUAL
+ POBJECT
+ Remove (
+ IN OUT PITERATOR Position
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Sort(
+ IN BOOLEAN Ascending DEFAULT TRUE
+ );
+
+ protected:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ VIRTUAL
+ ULONG
+ Search(
+ IN PCOBJECT Key,
+ IN ULONG FirstIndex,
+ IN ULONG LastIndex
+ );
+
+
+ private:
+
+ ARRAY _Array; // Array
+ BOOLEAN _Ascending; // Ascending flag
+#if DBG==1
+ ULONG _IteratorCount; // Iterator Count
+#endif
+
+};
+
+
+INLINE
+BOOLEAN
+SORTED_LIST::IsAscending (
+ )
+/*++
+
+Routine Description:
+
+ Determines if the list is sorted in ascending order
+
+Arguments:
+
+ None
+
+Return Value:
+
+ BOOLEAN - TRUE if list is sorted in ascending order, FALSE otherwise
+
+--*/
+
+{
+ return _Ascending;
+}
+
+
+
+#endif // _SORTED_LIST_
diff --git a/private/utils/ulib/inc/sortlit.hxx b/private/utils/ulib/inc/sortlit.hxx
new file mode 100644
index 000000000..81acfbfae
--- /dev/null
+++ b/private/utils/ulib/inc/sortlit.hxx
@@ -0,0 +1,98 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ sortlit.hxx
+
+Abstract:
+
+ This module contains the declaration for the SORTED_LIST_ITERATOR class.
+ SORTED_LIST_ITERATOR is a concrete implementation of the ITERATOR class.
+
+Author:
+
+ Ramon J. San Andres (ramonsa) 29-Oct-1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#if ! defined( _SORTED_LIST_ITERATOR_ )
+
+#define _SORTED_LIST_ITERATOR_
+
+#include "iterator.hxx"
+
+//
+// Forward references
+//
+DECLARE_CLASS( SORTED_LIST );
+DECLARE_CLASS( SORTED_LIST_ITERATOR );
+
+
+class SORTED_LIST_ITERATOR : public ITERATOR {
+
+ friend SORTED_LIST;
+
+ public:
+
+ VIRTUAL
+ ~SORTED_LIST_ITERATOR(
+ );
+
+ VIRTUAL
+ POBJECT
+ FindNext(
+ IN PCOBJECT Key
+ );
+
+ VIRTUAL
+ POBJECT
+ GetCurrent(
+ );
+
+ VIRTUAL
+ POBJECT
+ GetNext(
+ );
+
+ VIRTUAL
+ POBJECT
+ GetPrevious(
+ );
+
+ VIRTUAL
+ VOID
+ Reset(
+ );
+
+ protected:
+
+ DECLARE_CAST_MEMBER_FUNCTION( SORTED_LIST_ITERATOR );
+ DECLARE_CONSTRUCTOR( SORTED_LIST_ITERATOR );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN OUT PSORTED_LIST List
+ );
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ private:
+
+ PSORTED_LIST _List; // Sorted List
+ ULONG _CurrentIndex; // Current index
+
+};
+
+
+#endif // _SORTED_LIST_ITERATOR_
diff --git a/private/utils/ulib/inc/spackmsg.hxx b/private/utils/ulib/inc/spackmsg.hxx
new file mode 100644
index 000000000..30888480f
--- /dev/null
+++ b/private/utils/ulib/inc/spackmsg.hxx
@@ -0,0 +1,64 @@
+/*++
+
+Copyright (c) 1991-1994 Microsoft Corporation
+
+Module Name:
+
+ spackmsg.hxx
+
+Abstract:
+
+ Header file for the SP_AUTOCHECK_MESSAGE subclass.
+
+Author:
+
+ Lonny McMichael (lonnym) 09-Jun-94
+
+--*/
+
+#if !defined( _SP_AUTOCHECK_MESSAGE_DEFN_ )
+
+#define _SP_AUTOCHECK_MESSAGE_DEFN_
+
+#include "achkmsg.hxx"
+
+DECLARE_CLASS( SP_AUTOCHECK_MESSAGE );
+
+class SP_AUTOCHECK_MESSAGE : public AUTOCHECK_MESSAGE {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( SP_AUTOCHECK_MESSAGE );
+
+ VIRTUAL
+ ~SP_AUTOCHECK_MESSAGE(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ DisplayV(
+ IN PCSTR Format,
+ IN va_list VarPointer
+ );
+
+ VIRTUAL
+ BOOLEAN
+ IsYesResponse(
+ IN BOOLEAN Default DEFAULT TRUE
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+};
+
+
+#endif // _SP_AUTOCHECK_MESSAGE_DEFN_
diff --git a/private/utils/ulib/inc/stack.hxx b/private/utils/ulib/inc/stack.hxx
new file mode 100644
index 000000000..c5a2f4964
--- /dev/null
+++ b/private/utils/ulib/inc/stack.hxx
@@ -0,0 +1,233 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ stack.hxx
+
+Abstract:
+
+ This module contains the declaration for the concrete STACK class.
+ STACK is derived from the ORDERED_CONTAINER class. It implements a
+ standard FIFO stack data structure with the addition that it has a last
+ position which can be queried. STACKs are dynamic in that they will
+ grow rather than overflow.
+
+Author:
+
+ David J. Gilman (davegi) 11-Dec-1990
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if ! defined( _STACK_ )
+
+#define _STACK_
+
+#include "seqcnt.hxx"
+
+//
+// Forward references
+//
+
+DECLARE_CLASS( ARRAY );
+DECLARE_CLASS( ITERATOR );
+DECLARE_CLASS( STACK );
+
+
+//
+// Default values for an ARRAY object.
+//
+
+CONST ULONG DefaultCapacity = 50;
+CONST ULONG DefaultCapacityIncrement = 25;
+
+class STACK : public SEQUENTIAL_CONTAINER {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( STACK );
+
+ DECLARE_CAST_MEMBER_FUNCTION( STACK );
+
+ NONVIRTUAL
+ VOID
+ Clear (
+ );
+
+ VIRTUAL
+ PCOBJECT
+ GetFirst (
+ ) CONST PURE;
+
+ VIRTUAL
+ PCOBJECT
+ GetLast (
+ ) CONST PURE;
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ IN ULONG Capacity DEFAULT DefaultCapacity,
+ IN ULONG CapacityIncrement DEFAULT DefaultCapacityIncrement
+ );
+
+ NONVIRTUAL
+ PCOBJECT
+ Pop (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Push (
+ IN PCOBJECT Object
+ );
+
+ VIRTUAL
+ PCOBJECT
+ Put (
+ IN PCOBJECT Member
+ ) PURE;
+
+ VIRTUAL
+ PITERATOR
+ QueryIterator (
+ ) CONST PURE;
+
+ VIRTUAL
+ PCOBJECT
+ Remove (
+ IN PCOBJECT Member
+ ) PURE;
+
+ NONVIRTUAL
+ PCOBJECT
+ Top (
+ ) CONST;
+
+ private:
+
+ PARRAY _Stack;
+ ULONG _Top;
+};
+
+INLINE
+PCOBJECT
+STACK::GetFirst (
+ ) CONST
+
+{
+ return( Top( ));
+}
+
+INLINE
+PCOBJECT
+STACK::GetLast (
+ ) CONST
+
+{
+ DebugPtrAssert( _Stack );
+ if( _Stack != NULL ) {
+ return( _Stack->GetLast( ));
+ } else {
+ return( NULL );
+ }
+}
+
+INLINE
+VOID
+STACK::Clear (
+ )
+
+{
+ _Top = 0;
+}
+
+INLINE
+PCOBJECT
+STACK::Pop (
+ )
+
+{
+ DebugPtrAssert( _Stack );
+ if( ( _Stack != NULL ) && ( _Top != 0 )) {
+ return( _Stack->GetAt( _Top-- ));
+ } else {
+ return( NULL );
+ }
+}
+
+INLINE
+BOOLEAN
+STACK::Push (
+ IN PCOBJECT Object
+ )
+
+{
+ DebugPtrAssert( _Stack );
+ if( _Stack != NULL ) {
+ return( _Stack->PutAt( ++_Top ));
+ } else {
+ return( NULL );
+ }
+}
+
+INLINE
+PCOBJECT
+STACK::Put (
+ IN PCOBJECT Member
+ )
+
+{
+ DebugPtrAssert( Member );
+ return( Push( Member ));
+}
+
+INLINE
+PITERATOR
+STACK::QueryIterator (
+ ) CONST
+
+{
+ DebugPtrAssert( _Stack );
+ if( _Stack != NULL ) {
+ return( _Stack->QueryIterator( ));
+ } else {
+ return( NULL );
+ }
+}
+
+INLINE
+PCOBJECT
+STACK::Remove (
+ IN PCOBJECT Member
+ ) PURE
+
+{
+ DebugPtrAssert( Member ).IsEqual( Top( ));
+ if( ( Member != NULL ) && Member.IsEqual( Top( )) ) {
+ return( Pop( ));
+ } else {
+ retrun( NULL );
+ }
+}
+
+INLINE
+PCOBJECT
+STACK::Top (
+ ) CONST
+
+{
+ DebugPtrAssert( _Stack );
+ if( ( _Stack != NULL ) && ( _Top != 0 )) {
+ return( _Stack->GetAt( _Top ));
+ } else {
+ return( NULL );
+ }
+}
+
+#endif // _STACK_
diff --git a/private/utils/ulib/inc/stream.hxx b/private/utils/ulib/inc/stream.hxx
new file mode 100644
index 000000000..7f8326c08
--- /dev/null
+++ b/private/utils/ulib/inc/stream.hxx
@@ -0,0 +1,244 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ stream.hxx
+
+Abstract:
+
+ This module contains the declarations for the STREAM class.
+ STREAM is an abstract class used to model "devices" that
+ allow read or write operations, as a stream of data.
+ ("Device" here means anything that can supply or accept data
+ through read and write operations. Examples of "devices" are
+ keyboard, screen, file, pipes, etc.)
+ A STREAM object can have one of the following access: READ,
+ WRITE and READ_AND_WRITE.
+
+ The STREAM class provides methods to read data from the stream,
+ write data to the stream, check the stream access, and check if
+ the end of the stream has occurred.
+ (The occurrence of the end of stream means that all data in
+ a stream with READ or READ_AND_WRITE access was consumed, and no
+ more data can be obtained from the stream.)
+
+
+Author:
+
+ Jaime Sasson (jaimes) 21-Mar-1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+
+#if !defined( _STREAM_ )
+
+#define _STREAM_
+
+#include "wstring.hxx"
+#include "system.hxx"
+
+DECLARE_CLASS( STREAM );
+
+
+enum STREAMACCESS {
+ READ_ACCESS,
+ WRITE_ACCESS,
+ READ_AND_WRITE_ACCESS
+ };
+
+
+class STREAM : public OBJECT {
+
+
+ public:
+
+ friend BOOLEAN SYSTEM::PutStandardStream( DWORD, PSTREAM );
+
+ VIRTUAL
+ ~STREAM(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ IsAtEnd(
+ ) CONST PURE;
+
+ VIRTUAL
+ STREAMACCESS
+ QueryAccess(
+ ) CONST PURE;
+
+ VIRTUAL
+ BOOLEAN
+ Read(
+ OUT PBYTE Buffer,
+ IN ULONG BytesToRead,
+ OUT PULONG BytesRead
+ ) PURE;
+
+ NONVIRTUAL
+ BOOLEAN
+ ReadByte(
+ OUT PBYTE Data
+ );
+
+ VIRTUAL
+ BOOLEAN
+ ReadChar(
+ OUT PWCHAR Char,
+ IN BOOLEAN Unicode DEFAULT FALSE
+ ) PURE;
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ ReadLine(
+ OUT PWSTRING String,
+ IN BOOLEAN Unicode DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ ReadMbLine(
+ IN PSTR String,
+ IN DWORD BufferSize,
+ INOUT PDWORD StringSize,
+ IN BOOLEAN ExpandTabs DEFAULT FALSE,
+ IN DWORD TabExp DEFAULT 8
+ );
+
+ VIRTUAL
+ BOOLEAN
+ ReadMbString(
+ IN PSTR String,
+ IN DWORD BufferSize,
+ INOUT PDWORD StringSize,
+ IN PSTR Delimiters,
+ IN BOOLEAN ExpandTabs DEFAULT FALSE,
+ IN DWORD TabExp DEFAULT 8
+ ) PURE;
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ ReadWLine(
+ IN PWSTR String,
+ IN DWORD BufferSize,
+ INOUT PDWORD StringSize,
+ IN BOOLEAN ExpandTabs DEFAULT FALSE,
+ IN DWORD TabExp DEFAULT 8
+ );
+
+ VIRTUAL
+ BOOLEAN
+ ReadWString(
+ IN PWSTR String,
+ IN DWORD BufferSize,
+ INOUT PDWORD StringSize,
+ IN PWSTR Delimiters,
+ IN BOOLEAN ExpandTabs DEFAULT FALSE,
+ IN DWORD TabExp DEFAULT 8
+ ) PURE;
+
+ VIRTUAL
+ BOOLEAN
+ ReadString(
+ OUT PWSTRING String,
+ IN PWSTRING Delimiters,
+ IN BOOLEAN Unicode DEFAULT FALSE
+ ) PURE;
+
+ VIRTUAL
+ BOOLEAN
+ Write(
+ IN PCBYTE Buffer,
+ IN ULONG BytesToWrite,
+ OUT PULONG BytesWritten
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ WriteByte(
+ IN BYTE Data
+ );
+
+ VIRTUAL
+ BOOLEAN
+ WriteChar(
+ IN WCHAR Char
+ );
+
+ VIRTUAL
+ BOOLEAN
+ WriteString(
+ IN PCWSTRING String,
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END,
+ IN CHNUM Granularity DEFAULT 0
+ );
+
+ protected:
+
+
+ DECLARE_CONSTRUCTOR( STREAM );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ );
+
+ VIRTUAL
+ HANDLE
+ QueryHandle(
+ ) CONST PURE;
+
+
+ private:
+
+
+ DSTRING _Delimiter;
+ PSTR _MbDelimiter;
+ PWSTR _WDelimiter;
+};
+
+
+INLINE
+BOOLEAN
+STREAM::Initialize(
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes an object of type STREAM.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns TRUE if the initialization succeeded, or FALSE otherwise.
+
+
+--*/
+
+
+{
+ _MbDelimiter = "\n";
+ _WDelimiter = L"\n";
+ return( _Delimiter.Initialize( "\n" ) );
+}
+
+
+#endif // _STREAM_
diff --git a/private/utils/ulib/inc/string.hxx b/private/utils/ulib/inc/string.hxx
new file mode 100644
index 000000000..28d479ee2
--- /dev/null
+++ b/private/utils/ulib/inc/string.hxx
@@ -0,0 +1,464 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ GENERIC_STRING
+
+Abstract:
+
+ This module contains the definition for the GENERIC_STRING class.
+
+Author:
+
+ Ramon J. San Andres (ramonsa) 03-May-91
+
+Environment:
+
+ ULIB, User Mode
+
+Notes:
+
+ A GENERIC_STRING is the base class for all string classes. This
+ base class provides a basic wide-character interface.
+
+ A string is a finite, ordered sequence of wide characters. Note
+ that a GENERIC_STRING is NOT necessarily null-terminated.
+
+ Individual characters within a string are indexed by a number of
+ type CHNUM (CHaracter NUMber). This index is zero-based.
+
+ There are three special symbols that are widely used in the ULIB
+ strings world:
+
+ INVALID_CHAR This symbol represents an invalid wide character.
+
+ INVALID_CHNUM This symbol represents an invalid CHNUM index within
+ a GENERIC_STRING.
+
+ TO_END This symbol means "up to the end of the string", and
+ is used a lot as a default value in those methods
+ that accept a length argument.
+
+
+--*/
+
+
+//
+// This class is no longer supported.
+//
+
+#include "wstring.hxx"
+
+#define _GENERIC_STRING_
+
+#if !defined (_GENERIC_STRING_)
+
+#define _GENERIC_STRING_
+
+//
+// Comparison flags
+//
+#define COMPARE_IGNORECASE ( 1 )
+#define COMPARE_IGNOREDIACRITIC ( 2 )
+#define COMPARE_IGNORESYMBOLS ( 4 )
+
+
+//
+// The type of the index used to access individual characters within
+// a generic string.
+//
+DEFINE_TYPE( ULONG, CHNUM );
+
+//
+// Magic constants
+//
+#define INVALID_CHAR ((WCHAR)(-1))
+#define INVALID_CHNUM ((CHNUM)(-1))
+#define TO_END INVALID_CHNUM
+
+
+DECLARE_CLASS( GENERIC_STRING );
+
+
+class GENERIC_STRING : public OBJECT {
+
+ public:
+
+ DECLARE_CAST_MEMBER_FUNCTION( GENERIC_STRING );
+
+ VIRTUAL
+ ~GENERIC_STRING(
+ );
+
+ VIRTUAL
+ PBYTE
+ GetInternalBuffer (
+ IN CHNUM Position DEFAULT 0
+ ) CONST PURE;
+
+ VIRTUAL
+ BOOLEAN
+ IsChAt (
+ IN WCHAR Char,
+ IN CHNUM Position DEFAULT 0
+ ) CONST PURE;
+
+ VIRTUAL
+ BOOLEAN
+ MakeNumber (
+ OUT PLONG Number,
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END
+ ) CONST PURE;
+
+ VIRTUAL
+ ULONG
+ QueryByteCount (
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END
+ ) CONST PURE;
+
+ VIRTUAL
+ WCHAR
+ QueryChAt(
+ IN CHNUM Position DEFAULT 0
+ ) CONST PURE;
+
+ VIRTUAL
+ CHNUM
+ QueryChCount (
+ ) CONST PURE;
+
+ VIRTUAL
+ PGENERIC_STRING
+ QueryGenericString (
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END
+ ) CONST PURE;
+
+ VIRTUAL
+ PSTR
+ QuerySTR(
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END,
+ IN OUT PSTR Buffer DEFAULT NULL,
+ IN ULONG BufferSize DEFAULT 0
+ ) CONST PURE;
+
+ VIRTUAL
+ PWSTR
+ QueryWSTR (
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END,
+ IN OUT PWSTR Buffer DEFAULT NULL,
+ IN ULONG BufferSize DEFAULT 0,
+ IN BOOLEAN ForceNull DEFAULT TRUE
+ ) CONST PURE;
+
+ VIRTUAL
+ BOOLEAN
+ Replace (
+ IN PCGENERIC_STRING String2,
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END,
+ IN CHNUM Position2 DEFAULT 0,
+ IN CHNUM Length2 DEFAULT TO_END
+ ) PURE;
+
+ VIRTUAL
+ BOOLEAN
+ SetChAt (
+ IN WCHAR Char,
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END
+ ) PURE;
+
+ VIRTUAL
+ CHNUM
+ Strchr (
+ IN WCHAR Char,
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END
+ ) CONST PURE;
+
+ VIRTUAL
+ LONG
+ Strcmp (
+ IN PCGENERIC_STRING GenericString
+ ) CONST PURE;
+
+ VIRTUAL
+ CHNUM
+ Strcspn (
+ IN PCGENERIC_STRING GenericString,
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END
+ ) CONST PURE;
+
+ VIRTUAL
+ LONG
+ Stricmp (
+ IN PCGENERIC_STRING GenericString
+ ) CONST PURE;
+
+ VIRTUAL
+ LONG
+ StringCompare (
+ IN CHNUM Position1,
+ IN CHNUM Length1 ,
+ IN PCGENERIC_STRING GenericString2,
+ IN CHNUM Position2,
+ IN CHNUM Length2,
+ IN USHORT CompareFlags DEFAULT COMPARE_IGNORECASE
+ ) CONST PURE;
+
+ VIRTUAL
+ CHNUM
+ StrLen (
+ ) CONST PURE;
+
+ VIRTUAL
+ CHNUM
+ Strrchr (
+ IN WCHAR Char,
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END
+ ) CONST PURE;
+
+ VIRTUAL
+ CHNUM
+ Strspn (
+ IN PCGENERIC_STRING GenericString,
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END
+ ) CONST PURE;
+
+ VIRTUAL
+ CHNUM
+ Strstr (
+ IN PCGENERIC_STRING GenericString,
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END
+ ) CONST PURE;
+
+ NONVIRTUAL
+ BOOLEAN
+ operator == (
+ IN RCGENERIC_STRING String
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ operator != (
+ IN RCGENERIC_STRING String
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ operator < (
+ IN RCGENERIC_STRING String
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ operator > (
+ IN RCGENERIC_STRING String
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ operator <= (
+ IN RCGENERIC_STRING String
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ operator >= (
+ IN RCGENERIC_STRING String
+ ) CONST;
+
+ protected:
+
+ DECLARE_CONSTRUCTOR( GENERIC_STRING );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ );
+
+ private:
+
+ VOID
+ Construct (
+ );
+
+
+};
+
+INLINE
+BOOLEAN
+GENERIC_STRING::operator == (
+ IN RCGENERIC_STRING String
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Compares this string with another.
+
+Arguments:
+
+ String - Supplies a reference to the string to compare.
+
+Return Value:
+
+ TRUE - if String is equal to this string
+ FALSE - if not.
+
+--*/
+
+{
+ return (StringCompare( 0, QueryChCount(), (PCGENERIC_STRING)&String, 0, String.QueryChCount(), COMPARE_IGNORECASE ) == 0);
+}
+
+INLINE
+BOOLEAN
+GENERIC_STRING::operator != (
+ IN RCGENERIC_STRING String
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Compares this string with another.
+
+Arguments:
+
+ String - Supplies a reference to the string to compare.
+
+Return Value:
+
+ TRUE - if String is equal to this string
+ FALSE - if not.
+
+--*/
+
+{
+ return (StringCompare( 0, QueryChCount(), (PCGENERIC_STRING)&String, 0, String.QueryChCount(), COMPARE_IGNORECASE ) != 0);
+}
+
+INLINE
+BOOLEAN
+GENERIC_STRING::operator < (
+ IN RCGENERIC_STRING String
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Compares this string with another.
+
+Arguments:
+
+ String - Supplies a reference to the string to compare.
+
+Return Value:
+
+ TRUE - if String is less then this string
+ FALSE - if not.
+
+--*/
+
+{
+ return (StringCompare( 0, QueryChCount(), (PCGENERIC_STRING)&String, 0, String.QueryChCount(), COMPARE_IGNORECASE ) < 0);
+}
+
+INLINE
+BOOLEAN
+GENERIC_STRING::operator > (
+ IN RCGENERIC_STRING String
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Compares this string with another.
+
+Arguments:
+
+ String - Supplies a reference to the string to compare.
+
+Return Value:
+
+ TRUE - if String is greater then this string
+ FALSE - if not.
+
+--*/
+
+
+{
+ return (StringCompare( 0, QueryChCount(), (PCGENERIC_STRING)&String, 0, String.QueryChCount(), COMPARE_IGNORECASE ) > 0);
+}
+
+INLINE
+BOOLEAN
+GENERIC_STRING::operator <= (
+ IN RCGENERIC_STRING String
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Compares this string with another.
+
+Arguments:
+
+ String - Supplies a reference to the string to compare.
+
+Return Value:
+
+ TRUE - if String is less then or equal this string
+ FALSE - if not.
+
+--*/
+
+{
+ return (StringCompare( 0, QueryChCount(), (PCGENERIC_STRING)&String, 0, String.QueryChCount(), COMPARE_IGNORECASE ) <= 0);
+}
+
+INLINE
+NONVIRTUAL
+BOOLEAN
+GENERIC_STRING::operator >= (
+ IN RCGENERIC_STRING String
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Compares this string with another.
+
+Arguments:
+
+ String - Supplies a reference to the string to compare.
+
+Return Value:
+
+ TRUE - if String is greater then or equal this string
+ FALSE - if not.
+
+--*/
+
+{
+ return (StringCompare( 0, QueryChCount(), (PCGENERIC_STRING)&String, 0, String.QueryChCount(), COMPARE_IGNORECASE ) >= 0);
+}
+
+#endif // _GENERIC_STRING_
diff --git a/private/utils/ulib/inc/stringar.hxx b/private/utils/ulib/inc/stringar.hxx
new file mode 100644
index 000000000..dfae463e5
--- /dev/null
+++ b/private/utils/ulib/inc/stringar.hxx
@@ -0,0 +1,83 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ stringar.hxx
+
+Abstract:
+
+ This module contains the definitions for the STRING_ARRAY class.
+ STRING_ARRAY is used only to store strings, and it provides a
+ method to sort the strings in ascending or descending order.
+ The sort methods uses the qsort() function of the C run time
+ library.
+
+Author:
+
+ Jaime F. Sasson (jaimes) 01-May-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if ! defined( _STRING_ARRAY_ )
+
+#define _STRING_ARRAY_
+
+
+
+//
+// Default values for an STRING_ARRAY object.
+//
+// - Capacity is the total number of elemnts that can be stored in an STRING_ARRAY
+// - CapacityIncrement is the number of elemnts that the STRING_ARRAY's Capacity
+// will be increased by when it's Capacity is exceeded
+//
+
+CONST CHNUM DefaultPosition = 0;
+// CONST ULONG DefaultCapacity = 50;
+// CONST ULONG DefaultCapacityIncrement = 25;
+
+class STRING_ARRAY : public ARRAY {
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( STRING_ARRAY );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize (
+ IN CHNUM Position DEFAULT DefaultPosition,
+ IN ULONG Capacity DEFAULT DefaultCapacity,
+ IN ULONG CapacityIncrement DEFAULT DefaultCapacityIncrement
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Sort(
+ IN BOOLEAN Ascending
+ );
+
+ private:
+
+ static
+ NONVIRTUAL
+ int _CRTAPI1
+ StringCompare(
+ IN const void * String1,
+ IN const void * String2
+ );
+
+ static CHNUM _Position;
+ static BOOLEAN _Ascending;
+};
+
+#endif // _STRING_ARRAY_
+
diff --git a/private/utils/ulib/inc/substrng.hxx b/private/utils/ulib/inc/substrng.hxx
new file mode 100644
index 000000000..c7faa0542
--- /dev/null
+++ b/private/utils/ulib/inc/substrng.hxx
@@ -0,0 +1,632 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ SUB_STRING
+
+Abstract:
+
+ This module contains the definition of the SUB_STRING class.
+
+Author:
+
+ Steve Rowe (stever)
+
+Environment:
+
+ ULIB, User Mode
+
+Notes:
+
+ A substring is a subsequence of characters taken from a "base"
+ string. Substrings are useful in those cases in which we want
+ to operate on "chunks" of a given string (e.g. parsing), without
+ having to create separate strings for each one.
+
+ One must be careful when using substrings, though. Since
+ substrings depend on a base string, the base string must exist
+ during the life span of all its substrings. In other words,
+ the base string must not be deleted before having deleted all
+ the substrings obtained from it.
+
+ Note that GENERIC_STRINGs have no substring support. It is up to
+ the derived string classes to provide it.
+
+ Since substrings are just "windows" into a base string, any
+ modification of a substring will be reflected in the base
+ string (hence in all other substrings). This is why we have
+ two classes of substrings:
+
+ SUB_STRING allows only read operations. Note however that
+ one can modify the base string directly.
+
+ DYNAMIC_SUB_STRING is derived from the above, and it allows
+ write operations. Needless to say, you should
+ not use this class unless you're sure of what
+ you are doing.
+
+ Substring objects cannot be created and initialized directly by the
+ user, they must be obtained thru a base string class with substring
+ support.
+
+ Substrings pertaining to the same base string are chained together
+ in a doubly-linked queue. Since substrings have no knowledge of the
+ internals of their base string, the chain has a dummy element as its
+ head. In order to provide substring support, the base string must
+ follow these steps:
+
+
+ 1.- Before spawning any substring, the substring chain head must
+ be created and initialized using the InitializeChainHead() method.
+ Note that this substring is a dummy one, beknown only to the base
+ string.
+
+ 2.- Whenever spawning a new substring, it must be linked to the chain
+ using the InitializeChainNode() method. Any substring already in
+ the chain may be use as argument, but the obvious choice is the
+ chain head.
+
+ 3.- Each time that the size of the string changes, the Update() of the
+ chain head must be invoked.
+
+ 4.- Before destroying a base string, you have to make sure that all its
+ substrings have gone away. This means that the chain head must be
+ the only element of the chain. Use the HasLinks() method to
+ verify this.
+
+ 5.- Don't forget to destroy the chain head before destorying the base
+ string.
+
+
+--*/
+
+//
+// This class is no longer supported
+//
+
+#include "wstring.hxx"
+
+#define _SUB_STRING_
+
+#if !defined (_SUB_STRING_)
+
+#define _SUB_STRING_
+
+#include "string.hxx"
+
+DECLARE_CLASS( SUB_STRING );
+
+class SUB_STRING : public GENERIC_STRING {
+
+ friend SUB_STRING;
+
+ public:
+
+ DECLARE_CONSTRUCTOR( SUB_STRING );
+ DECLARE_CAST_MEMBER_FUNCTION( SUB_STRING );
+
+ VIRTUAL
+ ~SUB_STRING (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ HasLinks (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ InitializeChainHead (
+ IN PGENERIC_STRING BaseString
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ InitializeChainNode (
+ IN OUT PSUB_STRING SubString,
+ IN CHNUM Position,
+ IN CHNUM Length
+ );
+
+ VIRTUAL
+ PBYTE
+ GetInternalBuffer (
+ IN CHNUM Position DEFAULT 0
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ IsChAt (
+ IN WCHAR Char,
+ IN CHNUM Position DEFAULT 0
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ MakeNumber (
+ OUT PLONG Number,
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END
+ ) CONST;
+
+ VIRTUAL
+ ULONG
+ QueryByteCount (
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END
+ ) CONST;
+
+ VIRTUAL
+ WCHAR
+ QueryChAt(
+ IN CHNUM Position DEFAULT 0
+ ) CONST;
+
+ VIRTUAL
+ CHNUM
+ QueryChCount (
+ ) CONST;
+
+ VIRTUAL
+ PGENERIC_STRING
+ QueryGenericString (
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END
+ ) CONST;
+
+ VIRTUAL
+ PSTR
+ QuerySTR(
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END,
+ IN OUT PSTR Buffer DEFAULT NULL,
+ IN ULONG BufferSize DEFAULT 0
+ ) CONST;
+
+ VIRTUAL
+ PSUB_STRING
+ QuerySubString (
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END,
+ OUT PSUB_STRING SubString DEFAULT NULL
+ );
+
+ VIRTUAL
+ PWSTR
+ QueryWSTR (
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END,
+ IN OUT PWSTR Buffer DEFAULT NULL,
+ IN ULONG BufferSize DEFAULT 0,
+ IN BOOLEAN ForceNull DEFAULT TRUE
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ Replace (
+ IN PCGENERIC_STRING String2,
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END,
+ IN CHNUM Position2 DEFAULT 0,
+ IN CHNUM Length2 DEFAULT TO_END
+ );
+
+ VIRTUAL
+ BOOLEAN
+ SetChAt (
+ IN WCHAR Char,
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END
+ );
+
+ VIRTUAL
+ CHNUM
+ Strchr (
+ IN WCHAR Char,
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END
+ ) CONST;
+
+ VIRTUAL
+ LONG
+ Strcmp (
+ IN PCGENERIC_STRING GenericString
+ ) CONST;
+
+ VIRTUAL
+ CHNUM
+ Strcspn (
+ IN PCGENERIC_STRING GenericString,
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END
+ ) CONST;
+
+ VIRTUAL
+ LONG
+ Stricmp (
+ IN PCGENERIC_STRING GenericString
+ ) CONST;
+
+ VIRTUAL
+ LONG
+ StringCompare (
+ IN CHNUM Position1,
+ IN CHNUM Length1,
+ IN PCGENERIC_STRING GenericString2,
+ IN CHNUM Position2,
+ IN CHNUM Length2,
+ IN USHORT CompareFlags DEFAULT COMPARE_IGNORECASE
+ ) CONST;
+
+
+ VIRTUAL
+ CHNUM
+ StrLen (
+ ) CONST;
+
+ VIRTUAL
+ CHNUM
+ Strrchr (
+ IN WCHAR Char,
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END
+ ) CONST;
+
+ VIRTUAL
+ CHNUM
+ Strspn (
+ IN PCGENERIC_STRING GenericString,
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END
+ ) CONST;
+
+ VIRTUAL
+ CHNUM
+ Strstr (
+ IN PCGENERIC_STRING GenericString,
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ Update (
+ IN CHNUM Length
+ );
+
+ protected:
+
+ NONVIRTUAL
+ PGENERIC_STRING
+ GetBaseString (
+ );
+
+ NONVIRTUAL
+ PSUB_STRING
+ GetNextInChain (
+ );
+
+ NONVIRTUAL
+ PSUB_STRING
+ GetPreviousInChain (
+ );
+
+ NONVIRTUAL
+ VOID
+ GetValidLength(
+ IN CHNUM Position,
+ IN OUT PCHNUM Length
+ ) CONST;
+
+ NONVIRTUAL
+ CHNUM
+ QueryStartingPosition (
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetChCount(
+ IN CHNUM NewCount
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy (
+ );
+
+ PGENERIC_STRING _BaseString; // base string to take substring
+ CHNUM _StartingPosition; // starting index within base
+ CHNUM _CountOfChars; // # of chars in substring
+
+ PSUB_STRING _Previous; // Previous in chain
+ PSUB_STRING _Next; // Next in chain
+
+#if DBG==1
+ ULONG _Signature;
+ BOOLEAN _Initialized;
+#endif
+
+};
+
+INLINE
+PGENERIC_STRING
+SUB_STRING::GetBaseString (
+ )
+
+/*++
+
+Routine Description:
+
+ Gets a pointer to the base string
+
+Arguments:
+
+ none
+
+Return Value:
+
+ Pointer to the base string
+
+--*/
+
+{
+ DebugAssert( _Initialized );
+ return _BaseString;
+}
+
+INLINE
+PSUB_STRING
+SUB_STRING::GetNextInChain (
+ )
+
+/*++
+
+Routine Description:
+
+ Gets a pointer to next substring in the chain
+
+Arguments:
+
+ none
+
+Return Value:
+
+ Pointer to substring
+
+--*/
+
+{
+ DebugAssert( _Initialized );
+ return _Next;
+}
+
+INLINE
+PSUB_STRING
+SUB_STRING::GetPreviousInChain (
+ )
+
+/*++
+
+Routine Description:
+
+ Gets a pointer to previous substring in the chain
+
+Arguments:
+
+ none
+
+Return Value:
+
+ Pointer to the previous substring
+
+--*/
+
+{
+ DebugAssert( _Initialized );
+ return _Previous;
+}
+
+INLINE
+VOID
+SUB_STRING::GetValidLength (
+ IN CHNUM Position,
+ IN OUT PCHNUM Length
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ If the length passed has the magic value TO_END, then it is
+ updated to be the from the passed position up to the end of the
+ substring.
+
+Arguments:
+
+ Position - Supplies a starting position within the substring
+ Length - Supplies a length
+
+Return Value:
+
+ none
+
+--*/
+
+{
+
+ DebugAssert(_Initialized );
+
+ DebugAssert( Position <= _CountOfChars );
+
+ if ( *Length == TO_END ) {
+ *Length = _CountOfChars - Position;
+ }
+
+ DebugAssert( Position + *Length <= _CountOfChars );
+}
+
+INLINE
+BOOLEAN
+SUB_STRING::HasLinks (
+ )
+
+/*++
+
+Routine Description:
+
+ Determines if the substring has forward and backward links
+
+Arguments:
+
+ none
+
+Return Value:
+
+ TRUE if the stubstring has forward or backward links
+ FALSE otherwise
+
+--*/
+
+{
+ DebugAssert( _Initialized );
+ return ( (GetNextInChain() != NULL ) || (GetPreviousInChain() != NULL ) );
+
+}
+
+INLINE
+CHNUM
+SUB_STRING::QueryStartingPosition (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the starting character position within the base string.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The starting character position within the base string.
+
+--*/
+
+{
+ DebugAssert( _Initialized );
+ return _StartingPosition;
+}
+
+INLINE
+VOID
+SUB_STRING::SetChCount (
+ IN CHNUM NewCount
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the number of characters in the substring
+
+Arguments:
+
+ NewCount - Supplies the new count of characters
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ DebugAssert( _Initialized );
+ _CountOfChars = NewCount;
+}
+
+
+
+#endif // _SUB_STRING_
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ DYNAMIC_SUB_STRING
+
+Abstract:
+
+ This module contains the definition of the DYNAMIC_SUB_STRING class.
+
+Author:
+
+ steve rowe stever 2/1/91
+
+Notes:
+
+ DYNAMIC_SUB_STRINGs can modify the base string (see notes for
+ SUB_STRING class).
+
+
+Revision History:
+
+--*/
+
+#define _DYNAMIC_SUB_STRING_
+
+#if !defined (_DYNAMIC_SUB_STRING_)
+
+#define _DYNAMIC_SUB_STRING_
+
+DECLARE_CLASS( DYNAMIC_SUB_STRING );
+
+class DYNAMIC_SUB_STRING : public SUB_STRING {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( DYNAMIC_SUB_STRING );
+ DECLARE_CAST_MEMBER_FUNCTION( DYNAMIC_SUB_STRING );
+
+ NONVIRTUAL
+ BOOLEAN
+ Copy (
+ IN PCGENERIC_STRING GenericString
+ );
+
+ VIRTUAL
+ BOOLEAN
+ SetChAt (
+ IN WCHAR Char,
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END
+ );
+
+ NONVIRTUAL
+ CHNUM
+ Truncate (
+ IN CHNUM Position DEFAULT 0
+ );
+
+ private:
+
+ VOID
+ Construct (
+ );
+
+};
+
+
+#endif // _DYNAMIC_SUB_STRING_
diff --git a/private/utils/ulib/inc/system.hxx b/private/utils/ulib/inc/system.hxx
new file mode 100644
index 000000000..a204e07a1
--- /dev/null
+++ b/private/utils/ulib/inc/system.hxx
@@ -0,0 +1,253 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ system.hxx
+
+Abstract:
+
+ This module contains the definition for the SYSTEM class. The SYSTEM
+ class is an abstract class which offers an interface for communicating
+ with the underlying operating system.
+
+Author:
+
+ David J. Gilman (davegi) 13-Jan-1991
+
+Environment:
+
+ ULIB, User Mode
+
+Notes:
+
+
+
+--*/
+
+#if ! defined( _SYSTEM_ )
+
+#define _SYSTEM_
+
+DECLARE_CLASS( FSN_DIRECTORY );
+DECLARE_CLASS( FSN_FILE );
+DECLARE_CLASS( FSNODE );
+DECLARE_CLASS( WSTRING );
+DECLARE_CLASS( STREAM );
+DECLARE_CLASS( TIMEINFO );
+
+#include "message.hxx"
+#include "path.hxx"
+#include "basesys.hxx"
+
+extern "C" {
+ #include <stdarg.h>
+}
+
+
+
+enum DRIVE_TYPE {
+ UnknownDrive,
+ RemovableDrive,
+ FixedDrive,
+ RemoteDrive,
+ CdRomDrive,
+ RamDiskDrive
+};
+
+enum FILE_TYPE {
+ UnknownFile,
+ DiskFile,
+ CharFile,
+ PipeFile
+};
+
+struct _VOL_SERIAL_NUMBER {
+ ULONG HighOrder32Bits;
+ ULONG LowOrder32Bits;
+};
+
+DEFINE_TYPE( struct _VOL_SERIAL_NUMBER, VOL_SERIAL_NUMBER );
+
+class SYSTEM : public BASE_SYSTEM {
+
+ friend
+ BOOLEAN
+ InitializeUlib(
+ IN HANDLE DllHandle,
+ IN ULONG Reason,
+ IN PVOID Reserved
+ );
+
+ public:
+
+ STATIC
+ ULIB_EXPORT
+ PFSN_DIRECTORY
+ MakeDirectory (
+ IN PCPATH Path,
+ IN PCPATH TemplatePath OPTIONAL
+ );
+
+ STATIC
+ ULIB_EXPORT
+ PFSN_FILE
+ MakeFile (
+ IN PCPATH Path
+ );
+
+ STATIC
+ ULIB_EXPORT
+ PFSN_FILE
+ MakeTemporaryFile (
+ IN PCWSTRING PrefixString,
+ IN PCPATH Path DEFAULT NULL
+ );
+
+ STATIC
+ ULIB_EXPORT
+ BOOLEAN
+ RemoveNode (
+ IN PFSNODE *PointerToNode,
+ IN BOOLEAN Force DEFAULT FALSE
+ );
+
+ STATIC
+ ULIB_EXPORT
+ BOOLEAN
+ IsCorrectVersion (
+ );
+
+ STATIC
+ PPATH
+ QueryCurrentPath (
+ );
+
+ STATIC
+ ULIB_EXPORT
+ PFSN_DIRECTORY
+ QueryDirectory (
+ IN PCPATH Path,
+ IN BOOLEAN GetWhatYouCan DEFAULT FALSE
+ );
+
+ STATIC
+ ULIB_EXPORT
+ PWSTRING
+ QueryEnvironmentVariable (
+ IN PCWSTRING Variable
+ );
+
+
+ STATIC
+ ULIB_EXPORT
+ PPATH
+ QuerySystemDirectory (
+ );
+
+ STATIC
+ ULIB_EXPORT
+ PPATH
+ SearchPath(
+ PWSTRING pFileName,
+ PWSTRING pSearchPath DEFAULT NULL
+ );
+
+ STATIC
+ ULIB_EXPORT
+ PFSN_FILE
+ QueryFile (
+ IN PCPATH Path
+ );
+
+ STATIC
+ ULIB_EXPORT
+ BOOLEAN
+ QueryCurrentDosDriveName(
+ OUT PWSTRING DosDriveName
+ );
+
+ STATIC
+ ULIB_EXPORT
+ DRIVE_TYPE
+ QueryDriveType(
+ IN PCWSTRING DosDriveName
+ );
+
+ STATIC
+ ULIB_EXPORT
+ FILE_TYPE
+ QueryFileType(
+ IN PCWSTRING DosFileName
+ );
+
+ STATIC
+ ULIB_EXPORT
+ PWSTRING
+ QueryVolumeLabel(
+ IN PPATH Path,
+ OUT PVOL_SERIAL_NUMBER SerialNumber
+ );
+
+ STATIC
+ ULIB_EXPORT
+ FARPROC
+ QueryLibraryEntryPoint(
+ IN PCWSTRING LibraryName,
+ IN PCWSTRING EntryPointName,
+ OUT PHANDLE LibraryHandle
+ );
+
+ STATIC
+ ULIB_EXPORT
+ VOID
+ FreeLibraryHandle(
+ IN HANDLE LibraryHandle
+ );
+
+ STATIC
+ BOOLEAN
+ PutStandardStream(
+ IN DWORD StdHandle,
+ IN PSTREAM pStream
+ );
+
+ STATIC
+ ULIB_EXPORT
+ BOOLEAN
+ QueryLocalTimeFromUTime(
+ IN PCTIMEINFO UTimeInfo,
+ OUT PTIMEINFO LocalTimeInfo
+ );
+
+ STATIC
+ BOOLEAN
+ QueryUTimeFromLocalTime(
+ IN PCTIMEINFO LocalTimeInfo,
+ OUT PTIMEINFO UTimeInfo
+ );
+
+ STATIC
+ ULIB_EXPORT
+ BOOLEAN
+ QueryWindowsErrorMessage(
+ IN ULONG WindowsErrorCode,
+ OUT PWSTRING ErrorMessage
+ );
+
+};
+
+
+INLINE
+PPATH
+SYSTEM::QueryCurrentPath (
+ )
+
+{
+ DebugAssert( FALSE );
+ return( NEW PATH );
+}
+
+
+#endif // SYSTEM_DEFN
diff --git a/private/utils/ulib/inc/timeinfo.hxx b/private/utils/ulib/inc/timeinfo.hxx
new file mode 100644
index 000000000..e9bf783b2
--- /dev/null
+++ b/private/utils/ulib/inc/timeinfo.hxx
@@ -0,0 +1,631 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ time.hxx
+
+Abstract:
+
+ This module contains the declaration for the TIMEINFO class.
+ The data members of the TIMEINFO class contain the date and
+ time information represented as a FILETIME structure and a
+ SYSTEMTIME structure. These two representations of date and
+ time are always initialized independently of the way that the
+ TIMEINFO class is initialized (as a FILETIME or a SYSTEMTIME).
+
+Author:
+
+ Jaime Sasson (jaimes) 13-Mar-1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+
+#if !defined( _TIMEINFO_ )
+
+#define _TIMEINFO_
+
+#include "wstring.hxx"
+
+
+DECLARE_CLASS( TIMEINFO );
+
+
+class TIMEINFO : public OBJECT {
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( TIMEINFO );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ );
+
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize(
+ IN PFILETIME FileTime
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PSYSTEMTIME SystemTime
+ );
+
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ VOID
+ Initialize(
+ IN PCTIMEINFO TimeInfo
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN USHORT Year,
+ IN USHORT Month,
+ IN USHORT Day,
+ IN USHORT Hour,
+ IN USHORT Minute,
+ IN USHORT Second,
+ IN USHORT Milliseconds
+ );
+
+
+ NONVIRTUAL
+ SHORT
+ CompareTimeInfo(
+ IN PFILETIME FileTime
+ ) CONST;
+
+
+ NONVIRTUAL
+ SHORT
+ CompareTimeInfo(
+ IN PSYSTEMTIME SystemTime
+ ) CONST;
+
+
+ NONVIRTUAL
+ PFILETIME
+ GetFileTime(
+ ) CONST;
+
+
+ NONVIRTUAL
+ PSYSTEMTIME
+ GetSysTime(
+ ) CONST;
+
+
+ NONVIRTUAL
+ BOOLEAN
+ IsLeapYear(
+ USHORT Year DEFAULT 0
+ ) CONST;
+
+
+ NONVIRTUAL
+ USHORT
+ QueryYear(
+ ) CONST;
+
+
+ NONVIRTUAL
+ USHORT
+ QueryMonth(
+ ) CONST;
+
+
+ NONVIRTUAL
+ USHORT
+ QueryDay(
+ ) CONST;
+
+
+ NONVIRTUAL
+ USHORT
+ QueryDayOfWeek(
+ ) CONST;
+
+
+ NONVIRTUAL
+ USHORT
+ QueryHour(
+ ) CONST;
+
+
+ NONVIRTUAL
+ USHORT
+ QueryMinute(
+ ) CONST;
+
+
+ NONVIRTUAL
+ USHORT
+ QuerySecond(
+ ) CONST;
+
+
+ NONVIRTUAL
+ USHORT
+ QueryMilliseconds(
+ ) CONST;
+
+
+ NONVIRTUAL
+ USHORT
+ QueryDayOffset(
+ ) CONST;
+
+
+ NONVIRTUAL
+ USHORT
+ QueryDaysInMonth(
+ ) CONST;
+
+
+ NONVIRTUAL
+ USHORT
+ QueryDaysInYear(
+ ) CONST;
+
+
+ NONVIRTUAL
+ BOOLEAN
+ SetDate(
+ USHORT Year,
+ USHORT Month,
+ USHORT Day
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ SetDate(
+ PCWSTRING Date
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetDateAndTime (
+ PCWSTRING DateAndTime
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetTime(
+ USHORT Hour DEFAULT 0,
+ USHORT Minute DEFAULT 0,
+ USHORT Second DEFAULT 0,
+ USHORT Millisecond DEFAULT 0
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ SetTime(
+ PCWSTRING Time
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ QueryTime(
+ OUT PWSTRING FormattedTimeString
+ ) CONST;
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ QueryDate(
+ OUT PWSTRING FormattedDateString
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ operator== (
+ IN TIMEINFO TimeInfo
+ ) CONST;
+
+
+ NONVIRTUAL
+ BOOLEAN
+ operator!= (
+ IN TIMEINFO TimeInfo
+ ) CONST;
+
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ operator< (
+ IN TIMEINFO TimeInfo
+ ) CONST;
+
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ operator> (
+ IN TIMEINFO TimeInfo
+ ) CONST;
+
+
+ NONVIRTUAL
+ BOOLEAN
+ operator<= (
+ IN TIMEINFO TimeInfo
+ ) CONST;
+
+
+ NONVIRTUAL
+ BOOLEAN
+ operator>= (
+ IN TIMEINFO TimeInfo
+ ) CONST;
+
+
+ private:
+
+ VOID
+ Construct (
+ );
+
+ FILETIME _FileTime;
+ SYSTEMTIME _SystemTime;
+
+};
+
+
+
+INLINE
+BOOLEAN
+TIMEINFO::IsLeapYear(
+ USHORT Year
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ This member function finds out if the year received as parameter
+ is a leap year.
+
+Arguments:
+
+ Year - Year to be verified. If the year specified is zero, then
+ the year stored in this class is verified.
+
+Return Value:
+
+ BOOLEAN - Indicates if it is a leap year (TRUE) or not (FALSE).
+
+
+--*/
+
+{
+ Year = ( Year == 0 )? (USHORT)_SystemTime.wYear : Year;
+ if( ( ( Year % 400 ) == 0 ) ||
+ ( ( Year % 100 ) != 0 ) && ( ( Year % 4 ) == 0 ) ) {
+ return( TRUE );
+ }
+ else {
+ return( FALSE );
+ }
+}
+
+
+
+INLINE
+USHORT
+TIMEINFO::QueryYear(
+ ) CONST
+
+
+/*++
+
+Routine Description:
+
+ Returns the year stored in the data member of this class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ USHORT - Number representing the year.
+
+
+--*/
+
+{
+ return( _SystemTime.wYear );
+}
+
+
+
+
+INLINE
+USHORT
+TIMEINFO::QueryMonth(
+ ) CONST
+
+
+/*++
+
+Routine Description:
+
+ Returns the month stored in the data member of this class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ USHORT - Number representing the month.
+
+
+--*/
+
+{
+ return( _SystemTime.wMonth );
+}
+
+
+
+
+INLINE
+USHORT
+TIMEINFO::QueryDay(
+ ) CONST
+
+
+/*++
+
+Routine Description:
+
+ Returns the day stored in the data member of this class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ USHORT - Number representing the day.
+
+
+--*/
+
+{
+ return( _SystemTime.wDay );
+}
+
+
+
+
+INLINE
+USHORT
+TIMEINFO::QueryDayOfWeek(
+ ) CONST
+
+
+/*++
+
+Routine Description:
+
+ Returns the day of the week stored in the data member of this class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ USHORT - Number representing the day of the week.
+
+
+--*/
+
+{
+ return( _SystemTime.wDayOfWeek );
+}
+
+
+
+
+INLINE
+USHORT
+TIMEINFO::QueryHour(
+ ) CONST
+
+
+/*++
+
+Routine Description:
+
+ Returns the hour stored in the data member of this class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ USHORT - Number representing the hour.
+
+
+--*/
+
+{
+ return( _SystemTime.wHour );
+}
+
+
+
+
+INLINE
+USHORT
+TIMEINFO::QueryMinute(
+ ) CONST
+
+
+/*++
+
+Routine Description:
+
+ Returns the minutes stored in the data member of this class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ USHORT - Number representing the minutes.
+
+
+--*/
+
+{
+ return( _SystemTime.wMinute );
+}
+
+
+
+
+INLINE
+USHORT
+TIMEINFO::QuerySecond(
+ ) CONST
+
+
+/*++
+
+Routine Description:
+
+ Returns the seconds stored in the data member of this class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ USHORT - Number representing the secondss.
+
+
+--*/
+
+{
+ return( _SystemTime.wSecond );
+}
+
+
+
+
+INLINE
+USHORT
+TIMEINFO::QueryMilliseconds(
+ ) CONST
+
+
+/*++
+
+Routine Description:
+
+ Returns the number of milliseconds stored in the data member of
+ this class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ USHORT - Number representing the millisecondss.
+
+
+--*/
+
+{
+ return( _SystemTime.wMilliseconds );
+}
+
+
+
+INLINE
+PFILETIME
+TIMEINFO::GetFileTime(
+ ) CONST
+
+
+/*++
+
+Routine Description:
+
+ Returns a pointer to the data member that contains the file time.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PFILETIME - Pointer to FileTime.
+
+--*/
+
+{
+ return( ( PFILETIME )&_FileTime );
+}
+
+
+
+INLINE
+PSYSTEMTIME
+TIMEINFO::GetSysTime(
+ ) CONST
+
+
+/*++
+
+Routine Description:
+
+ Returns a pointer to the data member that contains the system time.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PSYSTEMTIME - Pointer to SystemTime.
+
+--*/
+
+{
+ return( ( PSYSTEMTIME )&_SystemTime );
+}
+
+
+
+#endif // _TIMEINFO_
diff --git a/private/utils/ulib/inc/ulib.hxx b/private/utils/ulib/inc/ulib.hxx
new file mode 100644
index 000000000..97ce0ceae
--- /dev/null
+++ b/private/utils/ulib/inc/ulib.hxx
@@ -0,0 +1,152 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Ulib.hxx
+
+Abstract:
+
+
+Author:
+
+ David J. Gilman (davegi) 22-Oct-1990
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if !defined ( _ULIB_DEFINED_ )
+
+#define _ULIB_DEFINED_
+
+//
+// Autocheck implies no windows header files so this helps make up the
+// difference. Autocheck also has a special Debug switch, since
+// it allows printing to the debugger but does not execute any other
+// debug-only code.
+//
+
+#if defined( _AUTOCHECK_ )
+
+#define _NTAPI_ULIB_
+
+#if DBG
+#define _AUTOCHECK_DBG_
+#endif
+
+#undef DBG
+
+#define DBG 0
+
+#else
+
+ #ifndef _NTAPI_ULIB_
+ #define _NTAPI_ULIB_
+ #endif
+
+#endif // _AUTOCHECK_
+
+
+extern "C" {
+
+ #if defined( _NTAPI_ULIB_ )
+
+ #include <nt.h>
+ #include <ntrtl.h>
+ #include <nturtl.h>
+ #include <ntdddisk.h>
+
+ #endif // _NTAPI_ULIB_
+
+ #if !defined( _AUTOCHECK_ )
+
+ #include <windows.h>
+
+ #endif // _AUTOCHECK_
+}
+
+
+//
+// Function prototypes for Ulib non member functions (see ulib.cxx)
+//
+
+extern "C"
+BOOLEAN
+InitializeUlib(
+ IN HANDLE DllHandle,
+ IN ULONG Reason,
+ IN PVOID Reserved
+ );
+
+
+//
+// Intrinsic functions
+//
+#if DBG==0
+
+ #pragma intrinsic( memset, memcpy, memcmp )
+
+#endif
+
+//
+// Here's the scoop...ntdef.h defined NULL to be ( PVOID ) 0.
+// Cfront barfs on this if you try and assign NULL to any other pointer type.
+// This leaves two options (a) cast all NULL assignments or (b) define NULL
+// to be zero which is what C++ expects.
+//
+
+#if defined( NULL )
+
+ #undef NULL
+
+#endif
+#define NULL ( 0 )
+
+//
+// Make sure const is not defined.
+//
+#if defined( const )
+ #undef const
+#endif
+
+#include "ulibdef.hxx"
+#include "object.hxx"
+#include "clasdesc.hxx"
+
+//
+// External definitions for global objects (see ulib.cxx)
+//
+
+DECLARE_CLASS( PATH );
+
+#if !defined( _AUTOCHECK_ )
+
+ DECLARE_CLASS( STREAM );
+
+ //
+ // Standard streams
+ //
+ extern PSTREAM Standard_Input_Stream;
+ extern PSTREAM Standard_Output_Stream;
+ extern PSTREAM Standard_Error_Stream;
+
+#endif // _AUTOCHECK
+
+#if !defined( _AUTOCHECK_ )
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ HANDLE
+ FindFirstFile (
+ IN PCPATH Path,
+ OUT PWIN32_FIND_DATA FileFindData
+ );
+
+#endif // _AUTOCHECK
+
+
+#endif // _ULIB_DEFINED_
diff --git a/private/utils/ulib/inc/ulibcl.hxx b/private/utils/ulib/inc/ulibcl.hxx
new file mode 100644
index 000000000..ca882184e
--- /dev/null
+++ b/private/utils/ulib/inc/ulibcl.hxx
@@ -0,0 +1,40 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ulibcl.hxx
+
+Abstract:
+
+ This module contains declarations that the clients of
+ ULIB.DLL require.
+
+Author:
+
+ Bill McJohn (billmc) 17-May-1991
+
+Environment:
+
+ ULIB Clients, User Mode
+
+--*/
+
+#if ! defined( _ULIBCLIENTDEFN_ )
+
+#define _ULIBCLIENTDEFN_
+
+ULIB_EXPORT
+PSTREAM
+Get_Standard_Input_Stream();
+
+ULIB_EXPORT
+PSTREAM
+Get_Standard_Output_Stream();
+
+ULIB_EXPORT
+PSTREAM
+Get_Standard_Error_Stream();
+
+#endif
diff --git a/private/utils/ulib/inc/ulibdef.hxx b/private/utils/ulib/inc/ulibdef.hxx
new file mode 100644
index 000000000..84c104e8d
--- /dev/null
+++ b/private/utils/ulib/inc/ulibdef.hxx
@@ -0,0 +1,460 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ulibdef.hxx
+
+Abstract:
+
+ This module contains primitive support for the ULIB class hierarchy
+ and it's clients. This support includes:
+
+ - type definitions
+ - manifest constants
+ - debugging support
+ - memory leakage support
+ - external references
+
+Author:
+
+ David J. Gilman (davegi) 19-Oct-1990
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if ! defined( _ULIBDEF_ )
+
+#define _ULIBDEF_
+
+extern "C" {
+ #include <stdlib.h>
+};
+
+// The ULIB_EXPORT macro marks functions that are to be
+// exported. The source files for ULIB.DLL will have _ULIB_MEMBER_
+// defined; clients will not.
+//
+#if defined ( _AUTOCHECK_ )
+#define ULIB_EXPORT
+#elif defined ( _ULIB_MEMBER_ )
+#define ULIB_EXPORT __declspec(dllexport)
+#else
+#define ULIB_EXPORT __declspec(dllimport)
+#endif
+
+
+
+#pragma warning(disable:4091) // Symbol not defined
+
+//
+// Macros for defining types:
+//
+// - pointers (Ptype)
+// - pointers to constants (PCtype)
+// - references (Rtype)
+// - references to constants (RCtype)
+//
+
+#define DEFINE_POINTER_TYPES( type ) \
+ typedef type* P##type; \
+ typedef const type* PC##type
+
+#define DEFINE_REFERENCE_TYPES( type ) \
+ typedef type& R##type; \
+ typedef const type& RC##type
+
+#define DEFINE_POINTER_AND_REFERENCE_TYPES( type ) \
+ DEFINE_POINTER_TYPES( type ); \
+ DEFINE_REFERENCE_TYPES( type )
+
+#define DEFINE_TYPE( basetype, newtype ) \
+ typedef basetype newtype; \
+ DEFINE_POINTER_AND_REFERENCE_TYPES( newtype )
+
+#define DECLARE_CLASS( c ) \
+ class c; \
+ DEFINE_POINTER_AND_REFERENCE_TYPES( c );\
+ extern PCCLASS_DESCRIPTOR c##_cd
+
+//
+// Primitive types.
+//
+
+DEFINE_TYPE( unsigned char, UCHAR );
+DEFINE_TYPE( unsigned short,USHORT );
+DEFINE_TYPE( unsigned long, ULONG );
+
+DEFINE_TYPE( char, CCHAR );
+DEFINE_TYPE( short, CSHORT );
+DEFINE_TYPE( ULONG, CLONG );
+
+DEFINE_TYPE( short, SSHORT );
+DEFINE_TYPE( long, SLONG );
+
+DEFINE_TYPE( UCHAR, BYTE );
+DEFINE_TYPE( char, STR );
+DEFINE_TYPE( UCHAR, BOOLEAN );
+DEFINE_TYPE( int, INT );
+DEFINE_TYPE( unsigned int, UINT );
+
+DEFINE_TYPE(USHORT, WCHAR );
+
+typedef WCHAR *LPWCH; // pwc
+typedef WCHAR *LPWSTR; // pwsz, 0x0000 terminated UNICODE strings only
+
+DEFINE_POINTER_AND_REFERENCE_TYPES( WCHAR );
+
+DEFINE_TYPE( WCHAR, WSTR );
+//DEFINE_TYPE( struct tagLC_ID, LC_ID );
+
+//
+// Augmented (beyond standard headers) VOID pointer types
+//
+
+DEFINE_POINTER_TYPES( VOID );
+
+//
+// Ulib specific, primitive types
+//
+
+DEFINE_TYPE( STR, CLASS_NAME );
+DEFINE_TYPE( ULONG, CLASS_ID );
+
+
+//
+// Member and non-member function/data modifiers
+//
+
+#define CONST const
+#define NONVIRTUAL
+#define PURE = 0
+#define STATIC static
+#define VIRTUAL virtual
+#define INLINE inline
+// #define INLINE // hack to build for mips
+#define FRIEND friend
+
+//
+// Argument modifiers
+//
+
+#define DEFAULT =
+#define IN
+#define OPTIONAL
+#define OUT
+#define INOUT
+
+#if !defined(max)
+ #define max(a,b) (((a) > (b)) ? (a) : (b) )
+#endif
+
+#if !defined(min)
+ #define min(a,b) (((a) < (b)) ? (a) : (b) )
+#endif
+
+#if DBG==1
+
+ #define REGISTER
+
+#else
+
+ #define REGISTER register
+
+#endif // DBG
+
+//
+// External constants
+//
+
+extern CONST CLASS_ID NIL_CLASS_ID;
+
+//
+// GetFileName returns the file name portion of the supplied path name.
+//
+
+extern "C" {
+ #include <string.h>
+};
+
+inline
+PCCHAR
+GetFileName (
+ IN PCCHAR PathName
+ )
+
+{
+ PCCHAR pch;
+
+ return((( pch = strrchr( PathName, '\\' )) != NULL ) ?
+ pch + 1 : PathName );
+}
+
+//
+// Cast (beProtocol) support
+//
+// If the ID of the passed object is equal to the ID in this class'
+// CLASS_DESCRIPTOR, then the object is of this type and the Cast succeeds
+// (i.e. returns Object) otherwise the Cast fails (i.e. returns NULL)
+//
+
+
+#define DECLARE_CAST_MEMBER_FUNCTION( type ) \
+ STATIC \
+ P##type \
+ Cast ( \
+ PCOBJECT Object \
+ )
+
+
+#define DEFINE_CAST_MEMBER_FUNCTION( type ) \
+ P##type \
+ type::Cast ( \
+ PCOBJECT Object \
+ ) \
+ { \
+ if( Object && ( Object->QueryClassId( ) == \
+ type##_cd->QueryClassId( ))) { \
+ return(( P##type ) Object ); \
+ } else { \
+ return NULL; \
+ } \
+ }
+
+#define DEFINE_EXPORTED_CAST_MEMBER_FUNCTION( type, export ) \
+ P##type \
+ export \
+ type::Cast ( \
+ PCOBJECT Object \
+ ) \
+ { \
+ if( Object && ( Object->QueryClassId( ) == \
+ type##_cd->QueryClassId( ))) { \
+ return(( P##type ) Object ); \
+ } else { \
+ return NULL; \
+ } \
+ }
+
+//
+// Constructor support
+//
+
+//
+// All classes have CLASS_DESCRIPTORS which are static and named
+// after the class appended with the suffix _cd. They are passed stored in
+// OBJECT and are set by the SetClassDescriptor function. The Construct
+// For debugging purposes the class' name is stored in the CLASS_DESCRIPTOR.
+// The Construct member function gas a no-op implementation in OBJECT and
+// could be overloaded as a private member in any derived class.
+//
+
+#define DECLARE_CONSTRUCTOR( c ) \
+ NONVIRTUAL \
+ c ( \
+ )
+
+#define DEFINE_CONSTRUCTOR( d, b ) \
+ PCCLASS_DESCRIPTOR d##_cd; \
+ d::d ( \
+ ) : b( ) \
+ { \
+ SetClassDescriptor( ##d##_cd ); \
+ Construct( ); \
+ }
+
+#define DEFINE_EXPORTED_CONSTRUCTOR( d, b, e ) \
+ PCCLASS_DESCRIPTOR d##_cd; \
+ e d::d ( \
+ ) : b( ) \
+ { \
+ SetClassDescriptor( ##d##_cd ); \
+ Construct( ); \
+ }
+
+
+
+//
+// Debug support.
+//
+// Use the Debug macros to invoke the following debugging functions.
+//
+// DebugAbort( str ) - Print a message and abort.
+// DebugAssert( exp ) - Assert that an expression is TRUE. Abort if FALSE.
+// DebugChkHeap( ) - Validate the heap. Abort if invalid.
+// DebugPrint( str ) - Print a string including location (file/line)
+// DebugPrintf( fmt, ... ) - Printf.
+//
+#if DBG==1
+
+#include <assert.h>
+
+#define DebugAbort( str ) \
+ DebugPrint( str ); \
+ ExitProcess( 99 )
+
+#define DebugAssert( exp ) \
+ assert( exp )
+
+#define DebugCheckHeap( )
+
+#define DebugPrint( str ) \
+ DebugPrintf( "%s in file: %s on line: %d.\n", \
+ str, \
+ __FILE__, \
+ __LINE__ )
+
+
+ULIB_EXPORT
+VOID
+DebugPrintf(
+ IN PCSTR Format,
+ IN ...
+ );
+
+#define DebugPtrAssert( ptr ) \
+ DebugAssert( ptr != NULL )
+
+//
+// UlibGlobalFlag is used to selectively enable debugging options at
+// run-time.
+//
+
+extern ULONG UlibGlobalFlag;
+
+#elif defined( _AUTOCHECK_DBG_ )
+
+// Autocheck uses the system's DbgPrint function.
+//
+#define DebugPrintf DbgPrint
+#define DebugPrint DbgPrint
+
+#define DebugAbort( str )
+
+#define DebugAssert( exp )
+
+#define DebugCheckHeap( )
+
+#define DebugPtrAssert( ptr )
+
+
+#else // DBG == 0 and _AUTOCHECK_DBG_ not defined.
+
+#define DebugAbort( str )
+
+#define DebugAssert( exp )
+
+#define DebugCheckHeap( )
+
+#define DebugPrint( str )
+
+#define DebugPtrAssert( ptr )
+
+inline
+VOID
+DebugPrintf(
+ IN PCSTR Format,
+ IN ...
+ )
+{
+}
+
+#endif // DBG
+
+//
+// DELETE macro that NULLifizes the pointer to the deleted object.
+//
+
+// Undo any previous definitions of DELETE.
+#undef DELETE
+
+// #define DELETE(x) FREE(x), x = NULL;
+
+#define DELETE( x ) \
+ delete x, x = NULL
+
+#define NEW new
+
+#define DumpStats
+
+#if defined( _AUTOCHECK_ )
+
+ #define MALLOC(bytes) (RtlAllocateHeap(RtlProcessHeap(), 0, bytes))
+
+ INLINE
+ PVOID
+ NtlibZeroAlloc(
+ ULONG Size
+ )
+ {
+ PVOID Result;
+
+ Result = MALLOC( Size );
+
+ if( Result != NULL ) {
+
+ memset( Result, 0, Size );
+ }
+
+ return Result;
+ }
+
+
+ #define CALLOC(nitems, size) (NtlibZeroAlloc(nitems*size))
+
+ ULIB_EXPORT PVOID UlibRealloc(PVOID, ULONG);
+
+ #define REALLOC(p,s) UlibRealloc(p,s)
+
+ #define FREE(x) ((x) ? (RtlFreeHeap(RtlProcessHeap(), 0, x), (x) = NULL) : 0)
+
+#else // _AUTOCHECK_ not defined
+
+ #if defined( _NTAPI_ULIB_ )
+
+ #define MALLOC(bytes) (RtlAllocateHeap(RtlProcessHeap(), 0, bytes))
+
+ #define CALLOC(nitems, size) \
+ (RtlAllocateHeap(RtlProcessHeap(), 0, nitems*size))
+
+ ULIB_EXPORT PVOID UlibRealloc(PVOID, ULONG);
+
+ #define REALLOC(p,s) UlibRealloc(p,s)
+
+ #define FREE(x) ((x) ? (RtlFreeHeap(RtlProcessHeap(), 0, x), (x) = NULL) : 0)
+
+ #else
+
+ #define MALLOC(bytes) ((PVOID) LocalAlloc(0, bytes))
+
+ #define CALLOC(nitems, size) ((PVOID) LocalAlloc(LMEM_ZEROINIT, nitems*size))
+
+ ULIB_EXPORT PVOID UlibRealloc(PVOID, ULONG);
+
+ #define REALLOC(x, size) ((PVOID) LocalReAlloc(x, size, LMEM_MOVEABLE))
+
+ #define FREE(x) ((x) ? (LocalFree(x), (x) = NULL) : 0)
+
+ #endif
+
+#endif // _AUTOCHECK
+
+#if !defined(_SETUP_LOADER_) && !defined(_AUTOCHECK_)
+
+__inline void * __cdecl operator new(size_t x)
+{
+ return(MALLOC(x));
+}
+
+__inline void __cdecl operator delete(void * x)
+{
+ FREE(x);
+}
+
+#endif
+
+#endif // _ULIBDEF_
diff --git a/private/utils/ulib/inc/winnls.old b/private/utils/ulib/inc/winnls.old
new file mode 100644
index 000000000..9ca9f7ddd
--- /dev/null
+++ b/private/utils/ulib/inc/winnls.old
@@ -0,0 +1,292 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ winnls.h
+
+Abstract:
+
+ This module defines the 32-Bit Windows NLS APIs.
+
+Author:
+
+ David J. Gilman (davegi) 22-Mar-1991
+
+Revision History:
+
+--*/
+
+#ifndef _WINNLS_
+#define _WINNLS_
+
+//
+// NLSAPI and wide character related types.
+//
+
+typedef char CHAR;
+typedef PDWORD LPWCHAR;
+typedef LPSTR LPCHAR;
+typedef DWORD HLCID;
+typedef DWORD HLOCALE;
+
+
+//
+// Length of locale strings.
+//
+
+#define MAX_LANG_LEN ( 128 )
+#define MAX_CTRY_LEN ( 128 )
+#define MAX_CP_LEN ( 128 )
+
+//
+// String based locale representation.
+//
+
+typedef struct tagLC_STRINGS {
+ CHAR szLanguage[MAX_LANG_LEN]; // language name
+ CHAR szCountry[MAX_CTRY_LEN]; // country name
+ CHAR szCodePage[MAX_CP_LEN]; // codepage name
+} LC_STRINGS, *LPLC_STRINGS, *PLC_STRINGS;
+
+//
+// Code based local representation.
+//
+
+typedef struct tagLC_ID {
+ WORD wLanguage; // language id
+ WORD wCountry; // country id
+ WORD wCodePage; // codepage id
+} LC_ID, *LPLC_ID, *PLC_ID;
+
+//
+// Locale information enumeration type.
+//
+
+#define LI_CPDATA ( 0 )
+#define LI_CTRYDATA ( 1 )
+#define LI_LANGDATA ( 2 )
+
+//
+// Locale information type.
+//
+
+#define LI_CPDATA ( 0 )
+#define LI_CTRYDATA ( 1 )
+#define LI_LANGDATA ( 2 )
+#define LI_LCMONETARY ( 3 )
+#define LI_LCNUMERIC ( 4 )
+#define LI_DATETIMEFMT ( 5 )
+#define LI_DATETIMESTR ( 6 )
+
+//
+// LC_ID and LC_STRINGS indicator.
+//
+
+#define QF_LCID ( 0 )
+#define QF_STRINGS ( 1 )
+
+//
+// Requested character type information.
+//
+#define CT_CTYPE1 ( 1 )
+#define CT_CTYPE2 ( 2 )
+
+//
+// Character type 1 (CT_CTYPE1) information
+//
+
+#define C1_ALPHA ( 0x100 )
+#define C1_CONTROLCHAR ( 0x020 )
+#define C1_DIACRITIC ( 0x200 )
+#define C1_DIGIT ( 0x004 )
+#define C1_LOWERCASE ( 0x002 )
+#define C1_PUNCTUATION ( 0x010 )
+#define C1_WHITESPACE ( 0x008 )
+#define C1_SYMBOL ( 0x400 )
+#define C1_UPPERCASE ( 0x001 )
+
+//
+// Extended character type 1 (CT_CTYPE1) information
+//
+
+#define C1_ALPHNUMERIC ( C1_ALPHA | C1_DIGIT )
+#define C1_GRAPHIC ( C1_PUNCTUATION | C1_ALPHNUMERIC )
+
+//
+// Character type 2 (CT_CTYPE2) information
+//
+
+#define C2_STRONGLEFTTORIGHT ( 0 )
+#define C2_STRONGRIGHTTOLEFT ( 1 )
+#define C2_WEAKLEFTTORIGHT ( 2 )
+#define C2_WEAKRIGHTTOLEFT ( 3 )
+#define C2_NEUTRAL ( 4 )
+#define C2_NUMERICCONTEXT ( 5 )
+#define C2_OPENPUNCTUATION ( 6 )
+#define C2_CLOSEPUNCTUATION ( 7 )
+
+//
+// Extended character type 2 (CT_CTYPE2) information
+//
+
+#define C2_UPSTREAM ( C2_CLOSEPUNCTUATION + 1 )
+#define C2_DOWNSTREAM ( C2_CLOSEPUNCTUATION + 2 )
+#define C2_IDEOGRAPHIC ( C2_CLOSEPUNCTUATION + 3 )
+#define C2_NONBREAKING ( C2_CLOSEPUNCTUATION + 4 )
+
+//
+// Comparison flags
+//
+
+#define CF_IGNORECASE ( 1 )
+#define CF_IGNOREDIACRITIC ( 2 )
+#define CF_IGNORESYMBOLS ( 4 )
+
+//
+// Map types and flags.
+//
+
+#define MAP_COLLATE ( 0 )
+#define MAP_CTYPE1 ( 1 )
+#define MAP_CTYPE2 ( 2 )
+#define MAP_UPPERCASE ( 3 )
+#define MAP_LOWERCASE ( 4 )
+#define MAP_UCTOMB ( 5 )
+#define MAP_MBTOUC ( 6 )
+#define MAP_SORTKEY ( 7 )
+
+//
+// Character traits.
+//
+
+#define STR_IGNORECASE ( 0 )
+#define STR_IGNOREDIACRITIC ( 1 )
+#define STR_IGNORESYMBOLS ( 2 )
+
+//
+// Low level NLSAPI routines.
+//
+
+HLCID
+BeginEnumLocale(
+ DWORD dwEnumType,
+ LPLC_ID lpLCID
+ );
+
+BOOL
+GetNextLocale(
+ HLCID hEnumHandle,
+ LPLC_ID lpLCID
+ );
+
+BOOL
+EndEnumLocale(
+ HLCID hEnumHandle
+ );
+
+DWORD
+GetLocaleInfo(
+ LPLC_ID lpLocale,
+ DWORD dwLCType,
+ LPVOID pvLCData,
+ DWORD cbBuf
+ );
+
+BOOL
+GetQualifiedLocale(
+ WORD wType,
+ LPVOID lpInput,
+ LPLC_ID lpOutID,
+ LPLC_STRINGS lpOutStr
+ );
+
+//
+// High level NLSAPI routines.
+//
+
+BOOL
+GetCharType(
+ HLOCALE hLocale,
+ WORD wInfoType,
+ WCHAR wcChar,
+ LPWORD lpCharType
+ );
+
+BOOL
+CloseLocale(
+ HLOCALE hLocale
+ );
+
+int
+CompareString(
+ HLOCALE hLocale,
+ DWORD dwCmpFlags,
+ LPWSTR lpwstrString1,
+ int nCount1,
+ LPWSTR lpwstrString2,
+ int nCount2
+ );
+
+int
+QueryMap(
+ HLOCALE hLocale,
+ WORD wMapType,
+ WORD wMapFlags,
+ WCHAR wcBeginMap,
+ WCHAR wcEndMap,
+ LPVOID pvOutMap,
+ DWORD dwOutSize
+ );
+
+int
+MapString(
+ HLOCALE hLocale,
+ DWORD dwMapFlags,
+ LPWSTR lpWCSrcStr,
+ int nWCSrc,
+ LPWSTR lpWCDestStr,
+ int nWCDest
+ );
+
+HLOCALE
+OpenLocale(
+ LPLC_ID lpLCID
+ );
+
+//
+// MBCS Support NLSAPI Routines
+//
+
+int
+WideCharToMultiByte(
+ WORD wCodePage,
+ LPWSTR lpWideCharStr,
+ int nWideChar,
+ LPSTR lpMultiByteStr,
+ int nChar,
+ LPCHAR lpDefaultChar
+ );
+
+int
+MultiByteToWideChar(
+ WORD wCodePage,
+ LPSTR lpMultiByteStr,
+ int nChar,
+ LPWSTR lpWideCharStr,
+ int nWideChar
+ );
+
+int
+MultiByteToMultiByte(
+ WORD wTranslations,
+ WORD wSrcCodePage,
+ LPSTR lpSrcString,
+ int nSrcChar,
+ WORD wDestCodePage,
+ LPSTR wDestString,
+ int nDestChar
+ );
+
+#endif // _WINNLS_
diff --git a/private/utils/ulib/inc/wstring.hxx b/private/utils/ulib/inc/wstring.hxx
new file mode 100644
index 000000000..d62283413
--- /dev/null
+++ b/private/utils/ulib/inc/wstring.hxx
@@ -0,0 +1,1250 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ wstring.hxx
+
+Abstract:
+
+ This module defines the new WSTRING hierarchy:
+
+ WSTRING
+ FSTRING
+ DSTRING
+
+ WSTRING provides all of the desired methods on a string.
+ FSTRING provides an implementation of a WSTRING with fixed
+ size, user provided buffer.
+ DSTRING provides an implementation of a WSTRING with a
+ dynamic heap based buffer.
+
+
+ WSTRING is an abstract classes who's methods depend on the
+ implementation of two pure virtual methods: 'Resize' and 'NewBuf'.
+ A derived class must make use of the protected 'PutString' methods
+ in order to supply WSTRING with its string buffer. Use of
+ 'PutString' is constrained as follows:
+
+ 1. Supplying just a PWSTR to 'PutString' implies that
+ the PWSTR is null-terminated.
+ 2. Supplying a PWSTR and length to 'PutString' implies that
+ the PWSTR points to a buffer of characters that is at
+ least one longer than the given length.
+
+
+ All implementations of 'Resize' and 'NewBuf' must:
+
+ 1. Allocate an extra character for the NULL.
+ 2. NULL-terminate the buffer allocated.
+ 3. Always succeed if size <= current buffer size.
+ 4. Always work as soon as the derived class is initialized (i.e.
+ WSTRING::Initialize method need not be called.).
+ 5. Supply the buffer to WSTRING via 'PutString'.
+
+ Additionally 'Resize' must:
+
+ 1. Preserve the contents of the current buffer.
+
+ All of the comparison operators supplied by WSTRING are
+ case insensitive.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 6-Aug-92
+
+--*/
+
+#if !defined(_WSTRING_DEFN_)
+
+#define _WSTRING_DEFN_
+
+
+//
+// The type of the index used to access individual characters within
+// a generic string.
+//
+DEFINE_TYPE( ULONG, CHNUM );
+
+
+//
+// Magic constants
+//
+#define INVALID_CHAR ((WCHAR)(-1))
+#define INVALID_CHNUM ((CHNUM)(-1))
+#define TO_END INVALID_CHNUM
+
+
+DECLARE_CLASS( WSTRING );
+
+class WSTRING : public OBJECT {
+
+ public:
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize(
+ IN PCWSTRING InitialString,
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize(
+ IN PCWSTR InitialString,
+ IN CHNUM StringLength DEFAULT TO_END
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize(
+ IN PCSTR InitialString,
+ IN CHNUM StringLength DEFAULT TO_END
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Initialize(
+ IN LONG Number
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ PWSTRING
+ QueryString(
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END
+ ) CONST;
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ QueryNumber(
+ OUT PLONG Number,
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END
+ ) CONST;
+
+ NONVIRTUAL
+ CHNUM
+ QueryChCount(
+ ) CONST;
+
+
+#ifdef DBCS
+ NONVIRTUAL
+ ULIB_EXPORT
+ CHNUM
+ QueryByteCount(
+ ) CONST;
+#endif
+
+ NONVIRTUAL
+ CHNUM
+ SyncLength(
+ );
+
+ NONVIRTUAL
+ WCHAR
+ QueryChAt(
+ IN CHNUM Position
+ ) CONST;
+
+ NONVIRTUAL
+ WCHAR
+ SetChAt(
+ IN WCHAR Char,
+ IN CHNUM Position
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ VOID
+ DeleteChAt(
+ IN CHNUM Position,
+ IN CHNUM Length DEFAULT 1
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ InsertString(
+ IN CHNUM AtPosition,
+ IN PCWSTRING String,
+ IN CHNUM FromPosition DEFAULT 0,
+ IN CHNUM FromLength DEFAULT TO_END
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Replace(
+ IN CHNUM AtPosition,
+ IN CHNUM AtLength,
+ IN PCWSTRING String,
+ IN CHNUM FromPosition DEFAULT 0,
+ IN CHNUM FromLength DEFAULT TO_END
+ );
+
+ NONVIRTUAL
+ PCWSTR
+ GetWSTR(
+ ) CONST;
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ PWSTR
+ QueryWSTR(
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END,
+ OUT PWSTR Buffer DEFAULT NULL,
+ IN CHNUM BufferLength DEFAULT 0,
+ IN BOOLEAN ForceNull DEFAULT TRUE
+ ) CONST;
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ PSTR
+ QuerySTR(
+ IN CHNUM Position DEFAULT 0,
+ IN CHNUM Length DEFAULT TO_END,
+ OUT PSTR Buffer DEFAULT NULL,
+ IN CHNUM BufferLength DEFAULT 0,
+ IN BOOLEAN ForceNull DEFAULT TRUE
+ ) CONST;
+
+ NONVIRTUAL
+ LONG
+ Strcmp(
+ IN PCWSTRING String
+ ) CONST;
+
+ STATIC
+ INT
+ Strcmp(
+ IN PWSTR String1,
+ IN PWSTR String2
+ ) ;
+
+ STATIC
+ INT
+ Stricmp(
+ IN PWSTR String1,
+ IN PWSTR String2
+ ) ;
+
+ NONVIRTUAL
+ LONG
+ Strcmp(
+ IN PCWSTRING String,
+ IN CHNUM LeftPosition
+ ) CONST;
+
+ NONVIRTUAL
+ LONG
+ Strcmp(
+ IN PCWSTRING String,
+ IN CHNUM LeftPosition,
+ IN CHNUM LeftLength,
+ IN CHNUM RightPosition DEFAULT 0,
+ IN CHNUM RightLength DEFAULT TO_END
+ ) CONST;
+
+ NONVIRTUAL
+ LONG
+ Stricmp(
+ IN PCWSTRING String
+ ) CONST;
+
+ NONVIRTUAL
+ LONG
+ Stricmp(
+ IN PCWSTRING String,
+ IN CHNUM LeftPosition
+ ) CONST;
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ LONG
+ Stricmp(
+ IN PCWSTRING String,
+ IN CHNUM LeftPosition,
+ IN CHNUM LeftLength,
+ IN CHNUM RightPosition DEFAULT 0,
+ IN CHNUM RightLength DEFAULT TO_END
+ ) CONST;
+
+ ULIB_EXPORT
+ STATIC
+ INT
+ Strcmps(
+ IN PWSTR p1,
+ IN PWSTR p2
+ );
+
+ ULIB_EXPORT
+ STATIC
+ INT
+ Strcmpis(
+ IN PWSTR p1,
+ IN PWSTR p2
+ );
+
+ STATIC
+ PWSTR
+ SkipWhite(
+ IN PWSTR p
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Strcat(
+ IN PCWSTRING String
+ );
+
+ NONVIRTUAL
+ PWSTRING
+ Strupr(
+ );
+
+ NONVIRTUAL
+ PWSTRING
+ Strupr(
+ IN CHNUM StartPosition,
+ IN CHNUM Length DEFAULT TO_END
+ );
+
+ NONVIRTUAL
+ PWSTRING
+ Strlwr(
+ );
+
+ NONVIRTUAL
+ ULIB_EXPORT
+ PWSTRING
+ Strlwr(
+ IN CHNUM StartPosition,
+ IN CHNUM Length DEFAULT TO_END
+ );
+
+ NONVIRTUAL
+ CHNUM
+ Strchr(
+ IN WCHAR Char,
+ IN CHNUM StartPosition DEFAULT 0
+ ) CONST;
+
+ NONVIRTUAL
+ CHNUM
+ Strrchr(
+ IN WCHAR Char,
+ IN CHNUM StartPosition DEFAULT 0
+ ) CONST;
+
+ NONVIRTUAL
+ CHNUM
+ Strstr(
+ IN PCWSTRING String
+ ) CONST;
+
+ NONVIRTUAL
+ CHNUM
+ Strspn(
+ IN PCWSTRING String,
+ IN CHNUM StartPosition DEFAULT 0
+ ) CONST;
+
+ NONVIRTUAL
+ CHNUM
+ Strcspn(
+ IN PCWSTRING String,
+ IN CHNUM StartPosition DEFAULT 0
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ operator==(
+ IN RCWSTRING String
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ operator!=(
+ IN RCWSTRING String
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ operator<(
+ IN RCWSTRING String
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ operator>(
+ IN RCWSTRING String
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ operator<=(
+ IN RCWSTRING String
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ operator>=(
+ IN RCWSTRING String
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ Resize(
+ IN CHNUM NewStringLength
+ ) PURE;
+
+ VIRTUAL
+ BOOLEAN
+ NewBuf(
+ IN CHNUM NewStringLength
+ ) PURE;
+
+ NONVIRTUAL
+ CHNUM
+ Truncate(
+ IN CHNUM Position DEFAULT 0
+ );
+
+ STATIC
+ ULIB_EXPORT
+ VOID
+ SetAnsiConversions(
+ );
+
+ STATIC
+ ULIB_EXPORT
+ VOID
+ SetOemConversions(
+ );
+
+ STATIC
+ ULIB_EXPORT
+ VOID
+ SetConsoleConversions(
+ );
+
+#if defined DBCS
+ STATIC
+ ULIB_EXPORT
+ VOID
+ ResetConversions(
+ );
+#endif // DBCS
+
+ protected:
+
+ DECLARE_CONSTRUCTOR( WSTRING );
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ PutString(
+ IN OUT PWSTR String
+ );
+
+ NONVIRTUAL
+ VOID
+ PutString(
+ IN OUT PWSTR String,
+ IN CHNUM Length
+ );
+
+ private:
+
+ STATIC BOOLEAN _UseAnsiConversions;
+ STATIC BOOLEAN _UseConsoleConversions;
+#if defined DBCS
+ STATIC BOOLEAN _UseAnsiConversionsPrev;
+ STATIC BOOLEAN _UseConsoleConversionsPrev;
+#endif // DBCS
+
+#if defined DBCS
+ STATIC
+ INT
+ CheckSpace(
+ IN PWSTR p
+ );
+#endif // DBCS
+
+ STATIC
+ BOOLEAN
+ ConvertOemToUnicodeN(
+ PWSTR UnicodeString,
+ ULONG MaxBytesInUnicodeString,
+ PULONG BytesInUnicodeString,
+ PCHAR OemString,
+ ULONG BytesInOemString
+ );
+
+ STATIC
+ BOOLEAN
+ ConvertUnicodeToOemN(
+ PCHAR OemString,
+ ULONG MaxBytesInOemString,
+ PULONG BytesInOemString,
+ PWSTR UnicodeString,
+ ULONG BytesInUnicodeString
+ );
+
+ PWSTR _s; // Beginning of string.
+ CHNUM _l; // Strlen of string.
+
+};
+
+
+INLINE
+VOID
+WSTRING::PutString(
+ IN OUT PWSTR String
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes this string with the given null
+ terminated buffer.
+
+Arguments:
+
+ String - Supplies the buffer to initialize the string with.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _s = String;
+ _l = wcslen(_s);
+}
+
+
+INLINE
+VOID
+WSTRING::PutString(
+ IN OUT PWSTR String,
+ IN CHNUM Length
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes this string with the given buffer
+ and string length.
+
+Arguments:
+
+ String - Supplies the buffer to initialize the string with.
+ Length - Supplies the length of the string.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _s = String;
+ _l = Length;
+ _s[_l] = 0;
+}
+
+
+INLINE
+BOOLEAN
+WSTRING::Initialize(
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes this string to an empty null-terminated
+ string.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ return Resize(0);
+}
+
+
+INLINE
+CHNUM
+WSTRING::QueryChCount(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the number of characters in the string.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of characters in this string.
+
+--*/
+{
+ return _l;
+}
+
+
+INLINE
+CHNUM
+WSTRING::SyncLength(
+ )
+/*++
+
+Routine Description:
+
+ This routine recalculates the correct length of the string.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The recomputed length of the string.
+
+--*/
+{
+ return _l = wcslen(_s);
+}
+
+
+INLINE
+WCHAR
+WSTRING::QueryChAt(
+ IN CHNUM Position
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the character at the given position.
+ The position is a zero-based index into the string.
+ The position must be in the range of the string.
+
+Arguments:
+
+ Position - Supplies an index into the string.
+
+Return Value:
+
+ The character at the given position.
+
+--*/
+{
+ return (Position < _l) ? _s[Position] : INVALID_CHAR;
+}
+
+
+INLINE
+WCHAR
+WSTRING::SetChAt(
+ IN WCHAR Char,
+ IN CHNUM Position
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the given character at the given position in
+ the string.
+
+Arguments:
+
+ Char - Supplies the character to set into the string.
+ Position - Supplies the position at which to set the character.
+
+Return Value:
+
+ The character that was set.
+
+--*/
+{
+ DebugAssert(Position < _l);
+ return _s[Position] = Char;
+}
+
+
+INLINE
+PCWSTR
+WSTRING::GetWSTR(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns this string internal buffer.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the strings buffer.
+
+--*/
+{
+ return _s;
+}
+
+
+INLINE
+LONG
+WSTRING::Strcmp(
+ IN PCWSTRING String
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine compares two strings.
+
+Arguments:
+
+ String - Supplies the string to compare to.
+
+Return Value:
+
+ < 0 - This string is less than the given string.
+ 0 - This string is equal to the given string.
+ > 0 - This string is greater than the given string.
+
+--*/
+{
+ return wcscoll(_s, String->_s);
+}
+
+
+INLINE
+INT
+WSTRING::Strcmp(
+ IN PWSTR String1,
+ IN PWSTR String2
+ )
+{
+ return wcscoll( String1, String2 );
+}
+
+INLINE
+INT
+WSTRING::Stricmp(
+ IN PWSTR String1,
+ IN PWSTR String2
+ )
+{
+ return _wcsicoll( String1, String2 );
+}
+
+INLINE
+LONG
+WSTRING::Strcmp(
+ IN PCWSTRING String,
+ IN CHNUM LeftPosition
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine compares two strings. It starts comparing the
+ current string at the given position.
+
+Arguments:
+
+ String - Supplies the string to compare to.
+ LeftPosition - Supplies the starting position to start comparison
+ on the current string.
+
+Return Value:
+
+ < 0 - This string is less than the given string.
+ 0 - This string is equal to the given string.
+ > 0 - This string is greater than the given string.
+
+--*/
+{
+ return wcscoll(_s + LeftPosition, String->_s);
+}
+
+
+INLINE
+LONG
+WSTRING::Stricmp(
+ IN PCWSTRING String
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine compares two strings insensitive of case.
+
+Arguments:
+
+ String - Supplies the string to compare to.
+
+Return Value:
+
+ < 0 - This string is less than the given string.
+ 0 - This string is equal to the given string.
+ > 0 - This string is greater than the given string.
+
+--*/
+{
+ return _wcsicoll(_s, String->_s);
+}
+
+
+INLINE
+LONG
+WSTRING::Stricmp(
+ IN PCWSTRING String,
+ IN CHNUM LeftPosition
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine compares two strings insensitive of case.
+
+Arguments:
+
+ String - Supplies the string to compare to.
+ LeftPosition - Supplies the position in this string to start
+ comparison.
+
+Return Value:
+
+ < 0 - This string is less than the given string.
+ 0 - This string is equal to the given string.
+ > 0 - This string is greater than the given string.
+
+--*/
+{
+ return _wcsicoll(_s + LeftPosition, String->_s);
+}
+
+
+INLINE
+PWSTRING
+WSTRING::Strupr(
+ )
+/*++
+
+Routine Description:
+
+ This routine uppercases this string.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _wcsupr(_s);
+ return this;
+}
+
+
+INLINE
+PWSTRING
+WSTRING::Strlwr(
+ )
+/*++
+
+Routine Description:
+
+ This routine lowercases this string.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _wcslwr(_s);
+ return this;
+}
+
+
+INLINE
+CHNUM
+WSTRING::Strchr(
+ IN WCHAR Char,
+ IN CHNUM StartPosition
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the position of the first occurance of
+ the given character.
+
+Arguments:
+
+ Char - Supplies the character to find.
+
+Return Value:
+
+ The position of the given character or INVALID_CHNUM.
+
+--*/
+{
+ PWSTR p;
+
+ DebugAssert(StartPosition <= _l);
+ p = wcschr(_s + StartPosition, Char);
+ return p ? (p - _s) : INVALID_CHNUM;
+}
+
+
+INLINE
+CHNUM
+WSTRING::Strrchr(
+ IN WCHAR Char,
+ IN CHNUM StartPosition
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the position of the last occurance of
+ the given character.
+
+Arguments:
+
+ Char - Supplies the character to find.
+
+Return Value:
+
+ The position of the given character or INVALID_CHNUM.
+
+--*/
+{
+ PWSTR p;
+
+ p = wcsrchr(_s + StartPosition, Char);
+ return p ? (p - _s) : INVALID_CHNUM;
+}
+
+
+INLINE
+CHNUM
+WSTRING::Strstr(
+ IN PCWSTRING String
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine finds the given string withing this string.
+
+Arguments:
+
+ String - Supplies the string to find.
+
+Return Value:
+
+ The position of the given string in this string or INVALID_CHNUM.
+
+--*/
+{
+ PWSTR p;
+
+ p = wcsstr(_s, String->_s);
+ return p ? (p - _s) : INVALID_CHNUM;
+}
+
+
+INLINE
+CHNUM
+WSTRING::Strspn(
+ IN PCWSTRING String,
+ IN CHNUM StartPosition
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the position of the first character in this
+ string that does not belong to the set of characters in the given
+ string.
+
+Arguments:
+
+ String - Supplies the list of characters to search for.
+
+Return Value:
+
+ The position of the first character found that does not belong
+ to the given string.
+
+--*/
+{
+ CHNUM r;
+
+ DebugAssert(StartPosition <= _l);
+ r = wcsspn(_s + StartPosition, String->_s) + StartPosition;
+ return r < _l ? r : INVALID_CHNUM;
+}
+
+
+INLINE
+CHNUM
+WSTRING::Strcspn(
+ IN PCWSTRING String,
+ IN CHNUM StartPosition
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the position of the first character in this
+ string that belongs to the set of characters in the given
+ string.
+
+Arguments:
+
+ String - Supplies the list of characters to search for.
+
+Return Value:
+
+ Returns the position of the first character in this string
+ belonging to the given string or INVALID_CHNUM.
+
+--*/
+{
+ CHNUM r;
+
+ DebugAssert(StartPosition <= _l);
+ r = wcscspn(_s + StartPosition, String->_s) + StartPosition;
+ return r < _l ? r : INVALID_CHNUM;
+}
+
+
+INLINE
+BOOLEAN
+WSTRING::operator==(
+ IN RCWSTRING String
+ ) CONST
+{
+ return Stricmp(&String) == 0;
+}
+
+
+INLINE
+BOOLEAN
+WSTRING::operator!=(
+ IN RCWSTRING String
+ ) CONST
+{
+ return Stricmp(&String) != 0;
+}
+
+
+INLINE
+BOOLEAN
+WSTRING::operator<(
+ IN RCWSTRING String
+ ) CONST
+{
+ return Stricmp(&String) < 0;
+}
+
+
+INLINE
+BOOLEAN
+WSTRING::operator>(
+ IN RCWSTRING String
+ ) CONST
+{
+ return Stricmp(&String) > 0;
+}
+
+
+INLINE
+BOOLEAN
+WSTRING::operator<=(
+ IN RCWSTRING String
+ ) CONST
+{
+ return Stricmp(&String) <= 0;
+}
+
+
+INLINE
+BOOLEAN
+WSTRING::operator>=(
+ IN RCWSTRING String
+ ) CONST
+{
+ return Stricmp(&String) >= 0;
+}
+
+
+INLINE
+CHNUM
+WSTRING::Truncate(
+ IN CHNUM Position
+ )
+{
+ DebugAssert(Position <= _l);
+ Resize(Position);
+ return _l;
+}
+
+
+DECLARE_CLASS( FSTRING );
+
+class FSTRING : public WSTRING {
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( FSTRING );
+
+ NONVIRTUAL
+ PWSTRING
+ Initialize(
+ IN OUT PWSTR InitialString,
+ IN CHNUM BufferLength DEFAULT TO_END
+ );
+
+ VIRTUAL
+ ULIB_EXPORT
+ BOOLEAN
+ Resize(
+ IN CHNUM NewStringLength
+ );
+
+ VIRTUAL
+ BOOLEAN
+ NewBuf(
+ IN CHNUM NewStringLength
+ );
+
+ private:
+
+ CHNUM _buffer_length;
+
+};
+
+
+INLINE
+PWSTRING
+FSTRING::Initialize(
+ IN OUT PWSTR InitialString,
+ IN CHNUM BufferLength
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes this class with a null-terminated
+ unicode string. This routine does not make a copy of the string
+ but uses it as is.
+
+Arguments:
+
+ NullTerminatedString - Supplies a null-terminated unicode string.
+ BufferLength - Supplies the buffer length.
+
+Return Value:
+
+ A pointer to this class.
+
+--*/
+{
+ PutString(InitialString);
+ _buffer_length = ((BufferLength == TO_END) ?
+ (QueryChCount() + 1) : BufferLength);
+ return this;
+}
+
+
+DECLARE_CLASS( DSTRING );
+
+class DSTRING : public WSTRING {
+
+ public:
+
+ ULIB_EXPORT
+ DECLARE_CONSTRUCTOR( DSTRING );
+
+ VIRTUAL
+ ULIB_EXPORT
+ ~DSTRING(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Resize(
+ IN CHNUM NewStringLength
+ );
+
+ VIRTUAL
+ BOOLEAN
+ NewBuf(
+ IN CHNUM NewStringLength
+ );
+
+ private:
+
+ VOID
+ Construct(
+ );
+
+ PWSTR _buf; // String buffer.
+ CHNUM _length; // Number of characters in buffer.
+
+};
+
+
+#endif // _WSTRING_DEFN_
diff --git a/private/utils/ulib/memtrace/makefile b/private/utils/ulib/memtrace/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/ulib/memtrace/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/ulib/memtrace/memtrace.c b/private/utils/ulib/memtrace/memtrace.c
new file mode 100644
index 000000000..3563c7752
--- /dev/null
+++ b/private/utils/ulib/memtrace/memtrace.c
@@ -0,0 +1,225 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ memtrace.c
+
+Abstract:
+
+ This function contains an extension to NTSD that allows tracing of
+ memory usage when ULIB objects are compiled with the MEMLEAK flag
+ defined.
+
+Author:
+
+ Barry Gilhuly (W-Barry) 25-July-91
+
+Revision History:
+
+--*/
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <windows.h>
+#include <ntsdexts.h>
+
+#include <string.h>
+
+#include "memtrace.h"
+
+
+VOID
+DumpToFile( char *OutString, ... )
+{
+ DWORD bytes;
+
+ bytes = strlen( OutString );
+ WriteFile( hFile, OutString, bytes, &bytes, NULL );
+ return;
+}
+
+VOID
+MemTrace(
+ HANDLE hCurrentProcess,
+ HANDLE hCurrentThread,
+ DWORD dwCurrentPc,
+ PNTSD_EXTENSION_APIS lpExtensionApis,
+ LPSTR lpArgumentString
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called as an NTSD extension to format and dump
+ the current contents of the Mem list.
+
+Arguments:
+
+ hCurrentProcess - Supplies a handle to the current process (at the
+ time the extension was called).
+
+ hCurrentThread - Supplies a handle to the current thread (at the
+ time the extension was called).
+
+ CurrentPc - Supplies the current pc at the time the extension is
+ called.
+
+ lpExtensionApis - Supplies the address of the functions callable
+ by this extension.
+
+ lpArgumentString - Supplies the asciiz string that describes the
+ critical section to be dumped (e.g. ntdll!FastPebLock,
+ csrsrv!CsrProcessStructureLock...).
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DWORD AddrMem;
+
+ BOOL b;
+ DWORD i;
+
+ PMEM_BLOCK MemListNext;
+ MEM_BLOCK MemObject;
+ CHAR Symbol[64];
+ CHAR Buffer[ 128 ];
+ DWORD Displacement;
+
+ PNTSD_OUTPUT_ROUTINE lpOutputRoutine;
+ PNTSD_OUTPUT_ROUTINE lpAlternateOutputRoutine;
+
+ PNTSD_GET_EXPRESSION lpGetExpressionRoutine;
+ PNTSD_GET_SYMBOL lpGetSymbolRoutine;
+
+ UNREFERENCED_PARAMETER(hCurrentThread);
+ UNREFERENCED_PARAMETER(dwCurrentPc);
+ UNREFERENCED_PARAMETER(lpArgumentString);
+
+ lpOutputRoutine = lpExtensionApis->lpOutputRoutine;
+ lpGetExpressionRoutine = lpExtensionApis->lpGetExpressionRoutine;
+ lpGetSymbolRoutine = lpExtensionApis->lpGetSymbolRoutine;
+
+ //
+ // Attempt to use the input string as a file name...
+ //
+ if( ( hFile = CreateFile( lpArgumentString,
+ GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ 0
+ ) ) == (HANDLE)-1 ) {
+ //
+ // Unable to open the file - send all output to the screen.
+ //
+ lpAlternateOutputRoutine = lpExtensionApis->lpOutputRoutine;
+
+ } else {
+
+ lpAlternateOutputRoutine = DumpToFile;
+
+ }
+
+
+
+ //
+ // Get the address of the head of the memleak list...
+ //
+ AddrMem = (lpGetExpressionRoutine)("Ulib!pmemHead");
+ if ( !AddrMem ) {
+ (lpOutputRoutine)( "Unable to find the head of the Mem List!\n" );
+ if( hFile != (HANDLE)-1 ) {
+ CloseHandle( hFile );
+ }
+ return;
+ }
+ if( !ReadProcessMemory(
+ hCurrentProcess,
+ (LPVOID)AddrMem,
+ &MemListNext,
+ sizeof( PMEM_BLOCK ),
+ NULL
+ ) ) {
+ if( hFile != (HANDLE)-1 ) {
+ CloseHandle( hFile );
+ }
+ return;
+ }
+
+ //
+ // Traverse the list of Mem blocks stopping when the head hits the
+ // tail...At this point, the head of the list should be indicated
+ // by MemListHead and the tail by MemListTail. Since the first element
+ // in the list is a dummy entry, it can be skipped...
+ //
+ do {
+
+ if( !ReadProcessMemory(
+ hCurrentProcess,
+ (LPVOID)MemListNext,
+ &MemObject,
+ sizeof( MEM_BLOCK ),
+ NULL
+ ) ) {
+ return;
+ }
+
+ if( MemObject.memsig != Signature ) {
+
+ //
+ // This is an unrecognized memory block - die...
+ //
+ (lpOutputRoutine)( "Invalid block found!\n" );
+ return;
+ }
+
+ //
+ // Display the stored info - First the File, Line and Size of the
+ // memory block allocated. Then the stack trace...
+ //
+ sprintf( Buffer, "File: %s, Line: %ld, Size: %ld\n", MemObject.file,
+ MemObject.line, MemObject.size
+ );
+ ( lpAlternateOutputRoutine )( Buffer );
+
+ //
+ // This should dump the stack trace which was stored...
+ //
+ for( i = 0; ( i < MaxCallStack ) && ( MemObject.call[ i ] != 0 ); i++ ) {
+
+ (lpGetSymbolRoutine)( ( LPVOID )( MemObject.call[ i ] ),
+ Symbol,
+ &Displacement
+ );
+ sprintf( Buffer, "\t%s\n", Symbol );
+ ( lpAlternateOutputRoutine )( Buffer );
+
+ }
+ ( lpAlternateOutputRoutine )( "\n" );
+
+
+ } while( ( MemListNext = MemObject.pmemNext ) != NULL );
+
+
+
+ (lpOutputRoutine)( "\n...End of List...\n" );
+
+ if( hFile != (HANDLE)-1 ) {
+
+ ( lpAlternateOutputRoutine )( "\n...End of List...\n" );
+ CloseHandle( hFile );
+
+ }
+
+ return;
+}
diff --git a/private/utils/ulib/memtrace/memtrace.def b/private/utils/ulib/memtrace/memtrace.def
new file mode 100644
index 000000000..f5e529ac9
--- /dev/null
+++ b/private/utils/ulib/memtrace/memtrace.def
@@ -0,0 +1,6 @@
+NAME MEMTRACE
+
+DESCRIPTION 'Bonus NTSD Extensions'
+
+EXPORTS
+ MemTrace
diff --git a/private/utils/ulib/memtrace/memtrace.h b/private/utils/ulib/memtrace/memtrace.h
new file mode 100644
index 000000000..7d1138678
--- /dev/null
+++ b/private/utils/ulib/memtrace/memtrace.h
@@ -0,0 +1,65 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ memtrace.h
+
+Abstract:
+
+ This function contains an extension to NTSD that allows tracing of
+ memory usage when ULIB objects are compiled with the MEMLEAK flag
+ defined.
+
+Author:
+
+ Barry Gilhuly (W-Barry) 25-July-91
+
+Revision History:
+
+--*/
+
+//
+// The following was ripped off from ULIBDEF.HXX and NEWDELP.HXX
+//
+#define CONST const
+typedef ULONG MEM_BLOCKSIG;
+
+//
+// MEM_BLOCK header signature type and value.
+//
+CONST MEM_BLOCKSIG Signature = 0xDEADDEAD;
+
+//
+// Maximum length of caller's file name.
+//
+
+#define MaxFileLength 20
+
+//
+// Maximum size of call stack recorded.
+//
+
+#define MaxCallStack 20
+
+//
+// MEM_BLOCK is the header attached to all allocated memory blocks.
+// Do not change the order of these fields without fixing the initialization
+// of the dummy MEM_BLOCK in newdel.cxx.
+//
+
+typedef struct _MEM_BLOCK {
+ struct _MEM_BLOCK* pmemNext;
+ struct _MEM_BLOCK* pmemPrev;
+ MEM_BLOCKSIG memsig;
+ ULONG line;
+ ULONG size;
+ char file[ MaxFileLength ];
+ DWORD call[ MaxCallStack ];
+} MEM_BLOCK, *PMEM_BLOCK;
+
+//
+// File handle for data destination...
+//
+HANDLE hFile;
diff --git a/private/utils/ulib/memtrace/sources b/private/utils/ulib/memtrace/sources
new file mode 100644
index 000000000..e23cd09d8
--- /dev/null
+++ b/private/utils/ulib/memtrace/sources
@@ -0,0 +1,37 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Mark Lucovsky (markl) 18-Sep-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntsd
+MINORCOMP=memtrace
+
+TARGETNAME=memtrace
+TARGETPATH=$(BASEDIR)\public\sdk\lib
+TARGETTYPE=DYNLINK
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\kernel32.lib
+
+INCLUDES=
+
+SOURCES= memtrace.c
+
+UMTYPE=console
diff --git a/private/utils/ulib/src/achkmsg.cxx b/private/utils/ulib/src/achkmsg.cxx
new file mode 100644
index 000000000..c20c2811e
--- /dev/null
+++ b/private/utils/ulib/src/achkmsg.cxx
@@ -0,0 +1,550 @@
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "achkmsg.hxx"
+#include "basesys.hxx"
+#include "rtmsg.h"
+
+extern "C" {
+#include <ntddkbd.h>
+}
+
+BOOLEAN
+IsSuppressedMessage(
+ MSGID MessageId
+ )
+/*++
+
+Routine Description:
+
+ This function determines whether the specified message ID
+ should be suppressed, i.e. not recorded in the message log.
+
+Arguments:
+
+ MessageId -- Supplies the Message ID in question.
+
+Return Value:
+
+ TRUE if this message ID is in the set which is not recorded
+ in the message log.
+
+--*/
+{
+ BOOLEAN result;
+
+ switch( MessageId ) {
+
+ case MSG_HIDDEN_STATUS :
+ case MSG_PERCENT_COMPLETE :
+ case MSG_CHK_NTFS_CHECKING_FILES :
+ case MSG_CHK_NTFS_CHECKING_INDICES :
+ case MSG_CHK_NTFS_INDEX_VERIFICATION_COMPLETED :
+ case MSG_CHK_NTFS_FILE_VERIFICATION_COMPLETED :
+ case MSG_CHK_NTFS_CHECKING_SECURITY :
+ case MSG_CHK_NTFS_SECURITY_VERIFICATION_COMPLETED :
+ case MSG_CHK_VOLUME_CLEAN :
+ case MSG_CHK_CHECKING_FILES :
+ case MSG_CHK_DONE_CHECKING :
+
+ result = TRUE;
+ break;
+
+ default:
+ result = FALSE;
+ break;
+ }
+
+ return result;
+}
+
+DEFINE_CONSTRUCTOR(AUTOCHECK_MESSAGE, MESSAGE);
+
+
+AUTOCHECK_MESSAGE::~AUTOCHECK_MESSAGE(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for AUTOCHECK_MESSAGE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+AUTOCHECK_MESSAGE::Construct(
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the object to a default initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _msgid = 0;
+ _logged_chars = 0;
+ _next_message_offset = 0;
+ _logging_enabled = FALSE;
+}
+
+
+VOID
+AUTOCHECK_MESSAGE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the object to a default initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _msgid = 0;
+ _logged_chars = 0;
+ _next_message_offset = 0;
+ _logging_enabled = FALSE;
+}
+
+
+BOOLEAN
+AUTOCHECK_MESSAGE::Initialize(
+ IN BOOLEAN DotsOnly
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the class to a valid initial state.
+
+Arguments:
+
+ DotsOnly - Autochk should produce only dots instead of messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ Destroy();
+
+ _dots_only = DotsOnly;
+
+ return( _log_buffer.Initialize() );
+}
+
+
+BOOLEAN
+AUTOCHECK_MESSAGE::DisplayV(
+ IN PCSTR Format,
+ IN va_list VarPointer
+ )
+/*++
+
+Routine Description:
+
+ This routine displays the message with the specified parameters.
+
+ The format string supports all printf options.
+
+Arguments:
+
+ Format - Supplies a printf style format string.
+ VarPointer - Supplies a varargs pointer to the arguments.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ CHAR buffer[256];
+ DSTRING display_string;
+ UNICODE_STRING unicode_string;
+ PWSTR dis_str;
+ UNICODE_STRING uDot;
+
+ RtlInitUnicodeString(&uDot, L".");
+
+ if (!BASE_SYSTEM::QueryResourceStringV(&display_string, _msgid, Format,
+ VarPointer)) {
+ return FALSE;
+ }
+
+ if (!(dis_str = display_string.QueryWSTR())) {
+ return FALSE;
+ }
+
+ unicode_string.Length = (USHORT)display_string.QueryChCount()*sizeof(WCHAR);
+ unicode_string.MaximumLength = unicode_string.Length;
+ unicode_string.Buffer = dis_str;
+
+ if (!_dots_only && MSG_HIDDEN_STATUS != _msgid) {
+ NtDisplayString(&unicode_string);
+ }
+
+ if (IsLoggingEnabled() && !IsSuppressedMessage(_msgid)) {
+ LogMessage(&display_string);
+ }
+
+ // If we're printing dots only, we print a dot for each interesting
+ // message. The interesting messages are those that aren't suppressed
+ // except VOLUME_CLEAN and FILE_SYSTEM_TYPE, which we want to print a
+ // dot for regardless.
+
+ if (_dots_only && (!IsSuppressedMessage(_msgid) ||
+ MSG_CHK_VOLUME_CLEAN == _msgid || MSG_FILE_SYSTEM_TYPE == _msgid)) {
+
+ NtDisplayString(&uDot);
+ }
+
+ // Send the output to the debug port, too.
+ //
+ if (MSG_HIDDEN_STATUS != _msgid &&
+ display_string.QuerySTR( 0, TO_END, buffer, 256, TRUE ) ) {
+
+ DebugPrint( buffer );
+ }
+
+ DELETE(dis_str);
+
+ return TRUE;
+}
+
+
+BOOLEAN
+AUTOCHECK_MESSAGE::IsYesResponse(
+ IN BOOLEAN Default
+ )
+/*++
+
+Routine Description:
+
+ This routine queries a response of yes or no.
+
+Arguments:
+
+ Default - Supplies a default in the event that a query is not possible.
+
+Return Value:
+
+ FALSE - The answer is no.
+ TRUE - The answer is yes.
+
+--*/
+{
+ PWSTR dis_str;
+ UNICODE_STRING unicode_string;
+ DSTRING string;
+
+ if (!BASE_SYSTEM::QueryResourceString(&string, Default ? MSG_YES : MSG_NO, "")) {
+ return Default;
+ }
+
+ if (!(dis_str = string.QueryWSTR())) {
+ return Default;
+ }
+
+ unicode_string.Length = (USHORT)string.QueryChCount()*sizeof(WCHAR);
+ unicode_string.MaximumLength = unicode_string.Length;
+ unicode_string.Buffer = dis_str;
+
+ NtDisplayString(&unicode_string);
+
+ if (!IsSuppressedMessage(_msgid)) {
+ LogMessage(&string);
+ }
+
+ DELETE(dis_str);
+
+ return Default;
+}
+
+
+PMESSAGE
+AUTOCHECK_MESSAGE::Dup(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a new MESSAGE of the same type.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to a new MESSAGE object.
+
+--*/
+{
+ PAUTOCHECK_MESSAGE p;
+
+ if (!(p = NEW AUTOCHECK_MESSAGE)) {
+ return NULL;
+ }
+
+ if (!p->Initialize()) {
+ DELETE(p);
+ return NULL;
+ }
+
+ return p;
+}
+
+BOOLEAN
+AUTOCHECK_MESSAGE::IsLoggingEnabled(
+ )
+{
+ return _logging_enabled;
+}
+
+
+VOID
+AUTOCHECK_MESSAGE::ResetLoggingIterator(
+ )
+{
+ _next_message_offset = 0;
+}
+
+
+BOOLEAN
+AUTOCHECK_MESSAGE::QueryNextLoggedMessage(
+ OUT PFSTRING MessageText
+ )
+{
+ PWCHAR Buffer = (PWCHAR)_log_buffer.GetBuf();
+ BOOLEAN Result;
+
+ if( _next_message_offset >= _logged_chars ) {
+
+ // No more logged messages.
+ //
+ return FALSE;
+ }
+
+ Result = (MessageText->Initialize( Buffer + _next_message_offset ) != NULL) ?
+ TRUE : FALSE;
+
+ // Push _next_message_offset to the next message. Note
+ // that _next_message_offset is also incremented if this
+ // loop terminates because a zero was found, so that it
+ // will be one character past the next NULL character.
+ //
+ while( _next_message_offset < _logged_chars &&
+ Buffer[_next_message_offset++] );
+
+ return Result;
+}
+
+
+BOOLEAN
+AUTOCHECK_MESSAGE::LogMessage(
+ PCWSTRING Message
+ )
+{
+ ULONG NewBufferSize;
+ PWCHAR Buffer;
+
+ // The buffer must be large enough to accept this message plus
+ // a trailing null. To cut down the number of memory allocation
+ // calls, grow the buffer by 1K chunks.
+ //
+ NewBufferSize = (_logged_chars + Message->QueryChCount() + 1) * sizeof(WCHAR);
+
+ // Don't allow the buffer to grow more than 0.5MB
+ // otherwise we may use up all the pages.
+
+ if (NewBufferSize > 512000)
+ return FALSE;
+
+ if( _log_buffer.QuerySize() < NewBufferSize &&
+ !_log_buffer.Resize( (NewBufferSize + 1023)/1024 * 1024, 0x1 ) ) {
+ return FALSE;
+ }
+
+ Buffer = (PWCHAR)_log_buffer.GetBuf();
+
+ // QueryWSTR will append a trailing NULL.
+ //
+ Message->QueryWSTR( 0, TO_END,
+ Buffer + _logged_chars,
+ _log_buffer.QuerySize()/sizeof(WCHAR) - _logged_chars );
+
+ _logged_chars += Message->QueryChCount() + 1;
+
+ return TRUE;
+}
+
+BOOLEAN
+AUTOCHECK_MESSAGE::SetDotsOnly(
+ IN BOOLEAN DotsOnlyState
+ )
+/*++
+
+Routine Description:
+
+ This routine modifies the output mode, changing whether full
+ output is printed, or just dots.
+
+Arguments:
+
+ DotsOnlyState - TRUE if only dots should be printed.
+
+Return Value:
+
+ The previous state.
+
+--*/
+{
+ BOOLEAN b;
+
+ b = _dots_only;
+
+ _dots_only = DotsOnlyState;
+
+ if (b && !_dots_only) {
+ //
+ // Going from dots-only to full output, want to reset to the
+ // beginning of the next output line.
+ //
+
+ Set(MSG_BLANK_LINE);
+ Display();
+ }
+ return b;
+}
+
+
+VOID
+AUTOCHECK_MESSAGE::SetLoggingEnabled(
+ IN BOOLEAN Enable
+ )
+/*++
+
+Routine Description:
+
+ This routine allows a *_SA::VerifyAndFix routine to note that
+ there were interesting messages for a volume check. Before
+ autochk exits it will call the corresponding IsLoggingEnabled()
+ method to determine whether to save log information.
+
+Arguments:
+
+ Enable - TRUE if logging should be enabled.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _logging_enabled = Enable;
+}
+
+BOOLEAN
+AUTOCHECK_MESSAGE::WaitForUserSignal(
+ )
+/*++
+
+Routine Description:
+
+ Open the keyboard directly and wait to read something.
+
+Arguments:
+
+ None:
+
+Return Value:
+
+ TRUE - Something was successfully read.
+ FALSE - An error occured while attempting to open or read.
+
+--*/
+{
+ UNICODE_STRING u;
+ NTSTATUS Status;
+ IO_STATUS_BLOCK Iosb;
+ OBJECT_ATTRIBUTES ObjAttr;
+ HANDLE h;
+ UCHAR buf[120];
+
+ //
+ // The device we want to open is "\Device\KeyboardClass0"
+ //
+
+ RtlInitUnicodeString(&u, DD_KEYBOARD_DEVICE_NAME_U L"0");
+
+ InitializeObjectAttributes(&ObjAttr,
+ &u,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtCreateFile(&h,
+ SYNCHRONIZE | GENERIC_READ,
+ &ObjAttr,
+ &Iosb,
+ NULL, /* AllocationSize */
+ 0, /* FileAttributes */
+ FILE_SHARE_READ|FILE_SHARE_WRITE, /* ShareAccess */
+ FILE_OPEN, /* CreateDisposition */
+ FILE_SYNCHRONOUS_IO_ALERT, /* CreateOptions */
+ NULL, /* EaBuffer */
+ 0); /* EaLength */
+
+
+ if (!NT_SUCCESS(Status)) {
+
+ DebugPrintf("ULIB: WaitForUserSignal: create status %x\n", Status);
+ return FALSE;
+ }
+
+ Status = NtReadFile(h, NULL, NULL, NULL,
+ &Iosb, (PVOID)&buf, sizeof(buf),
+ NULL, NULL);
+
+ if (!NT_SUCCESS(Status)) {
+
+ DebugPrint("ULIB WaitForUserSignal: read status %x\n", Status);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
diff --git a/private/utils/ulib/src/arg.cxx b/private/utils/ulib/src/arg.cxx
new file mode 100644
index 000000000..5f93094ad
--- /dev/null
+++ b/private/utils/ulib/src/arg.cxx
@@ -0,0 +1,2707 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ argument classes
+
+Abstract:
+
+ These classes implement the command line parsing for all utilities.
+
+Author:
+
+ steve rowe stever 2/45/91
+
+Revision History:
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+extern "C" {
+ #include <ctype.h>
+};
+
+#include "ulib.hxx"
+#include "arg.hxx"
+#include "array.hxx"
+#include "arrayit.hxx"
+#include "wstring.hxx"
+
+#if !defined( _AUTOCHECK_ )
+
+#include "path.hxx"
+#include "dir.hxx"
+#include "filter.hxx"
+#include "system.hxx"
+
+#endif
+
+//
+// Prototypes for the matching functions
+//
+STATIC
+BOOLEAN
+Match(
+ OUT PARGUMENT Argument,
+ OUT PARGUMENT_LEXEMIZER ArgumentLexemizer,
+ IN BOOLEAN CaseSensitive
+ );
+
+STATIC
+BOOLEAN
+TailMatch(
+ IN PWSTRING Pattern,
+ IN PWSTRING String,
+ IN CHNUM chn,
+ OUT PCHNUM chnEnd,
+ IN BOOLEAN CaseSensitive
+ );
+
+
+
+//
+// Increment size of the _CharPos array
+//
+#define CHARPOS_INCREMENT 64
+
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( ARGUMENT_LEXEMIZER, OBJECT, ULIB_EXPORT );
+
+VOID
+ARGUMENT_LEXEMIZER::Construct (
+ )
+{
+ _CharPos = NULL;
+}
+
+
+ULIB_EXPORT
+ARGUMENT_LEXEMIZER::~ARGUMENT_LEXEMIZER (
+ )
+{
+ if ( _CharPos ) {
+ FREE( _CharPos );
+ }
+}
+
+
+
+ULIB_EXPORT
+BOOLEAN
+ARGUMENT_LEXEMIZER::Initialize (
+ IN PARRAY LexemeArray
+ )
+/*++
+
+Routine Description:
+
+ Initialization for ARGUMENT_LEXEMIZER. ARGUMENT_LEXEMIZER holds the
+ container for lexed parameters from the command line.
+
+Arguments:
+
+ LexemeArray - Supplies pointer to a general array container.
+
+Return Value:
+
+ TRUE - If initialization succeeds
+ FALSE - If failed to construct the different character sets used
+ to lex out the argument strings.
+
+--*/
+{
+
+ DebugPtrAssert( LexemeArray );
+
+ //
+ // Initialize our counts and pointer to the array of lexemes
+ //
+ _ConsumedCount = 0;
+ _LexemeCount = 0;
+ _parray = LexemeArray;
+ _CharPosSize = CHARPOS_INCREMENT;
+
+ if ( !(_CharPos = (PCHNUM)MALLOC( (unsigned int)(_CharPosSize * sizeof(CHNUM)) ))) {
+ return FALSE;
+ }
+
+
+
+ //
+ // Setup the character sets used in lexing.
+ //
+ // Switch defines the general character used to a switch. This
+ // is needed to seperate /a/b into /a /b
+ //
+ // White space is all characters that are not of interest
+ //
+ // MultipleSwitches are specific switch values that can be grouped
+ // together under 1 switch. Appear as /a/b or /ab
+ //
+ // EscapeChars are chars that negate any special meaning of a char.
+ //
+ // StartQuote and EndQuote define the opening and closing of quoted strings
+ //
+ if ((_SwitchChars.Initialize( (PWSTR) L"/" )) &&
+ (_WhiteSpace.Initialize( (PWSTR) L" \t")) &&
+ (_MultipleSwitches.Initialize()) &&
+ (_StartQuote.Initialize()) &&
+ (_EndQuote.Initialize()) &&
+ (_MetaChars.Initialize())) {
+
+ //
+ // Separator is a combo of other characters that can terminate
+ // a token.
+ //
+ _Separators.Initialize();
+ _SeparatorString.Initialize( &_Separators );
+ _SeparatorString.Strcat(&_WhiteSpace);
+ _SeparatorString.Strcat(&_SwitchChars);
+ _SeparatorString.Strcat(&_StartQuote);
+
+ _CaseSensitive = TRUE;
+ _AllowGlomming = FALSE;
+ _NoSpcBetweenDstAndSwitch = FALSE;
+
+ return TRUE;
+ }
+
+ //
+ // Something went wrong
+ //
+ return FALSE;
+}
+
+VOID
+ARGUMENT_LEXEMIZER::PutMetaChars (
+ IN PCSTR MetaChars
+ )
+/*++
+
+Routine Description:
+
+ Initializes Meta-characters
+
+Arguments:
+
+ MetaChars - Supplies pointer to string of metacharacters
+
+Return Value:
+
+ none
+--*/
+{
+ DebugPtrAssert( MetaChars );
+ _MetaChars.Initialize(MetaChars);
+}
+
+VOID
+ARGUMENT_LEXEMIZER::PutMetaChars (
+ IN PCWSTRING MetaChars
+ )
+/*++
+
+Routine Description:
+
+ Initializes Meta-characters
+
+Arguments:
+
+ MetaChars - Supplies pointer to string of metacharacters
+
+Return Value:
+
+ none
+--*/
+{
+ DebugPtrAssert( MetaChars );
+ _MetaChars.Initialize(MetaChars);
+}
+
+ULIB_EXPORT
+VOID
+ARGUMENT_LEXEMIZER::PutMultipleSwitch (
+ IN PCSTR MultipleSwitches
+ )
+/*++
+
+Routine Description:
+
+ initializes Multiple-switches
+
+Arguments:
+
+ MultipleSwitches - Supplies pointer to string of multiple switches
+
+Return Value:
+
+ none
+--*/
+{
+ DebugPtrAssert( MultipleSwitches );
+ _MultipleSwitches.Initialize(MultipleSwitches);
+}
+
+ULIB_EXPORT
+VOID
+ARGUMENT_LEXEMIZER::PutMultipleSwitch (
+ IN PCWSTRING MultipleSwitches
+ )
+/*++
+
+Routine Description:
+
+ initializes Multiple-switches
+
+Arguments:
+
+ MultipleSwitches - Supplies pointer to string of multiple switches
+
+Return Value:
+
+ none
+--*/
+{
+ DebugPtrAssert( MultipleSwitches );
+ _MultipleSwitches.Initialize(MultipleSwitches);
+}
+
+ULIB_EXPORT
+VOID
+ARGUMENT_LEXEMIZER::PutSeparators (
+ IN PCSTR Separators
+ )
+/*++
+
+Routine Description:
+
+ Initializes Separators
+
+Arguments:
+
+ pSeparators - Supplies pointer to string of separators
+
+Return Value:
+
+ none
+--*/
+{
+ DebugPtrAssert( Separators );
+ _Separators.Initialize(Separators);
+ _SeparatorString.Initialize( &_Separators );
+ //_SeparatorString += _WhiteSpace;
+ //_SeparatorString += _SwitchChars;
+}
+
+VOID
+ARGUMENT_LEXEMIZER::PutSeparators (
+ IN PCWSTRING Separators
+ )
+/*++
+
+Routine Description:
+
+ Initializes Separators
+
+Arguments:
+
+ Separators - Supplies pointer to string of separators
+
+Return Value:
+
+ none
+--*/
+{
+ DebugPtrAssert( Separators );
+ _Separators.Initialize(Separators);
+ _SeparatorString.Initialize( &_Separators );
+ _SeparatorString.Strcat(&_WhiteSpace);
+ _SeparatorString.Strcat(&_SwitchChars);
+}
+
+ULIB_EXPORT
+VOID
+ARGUMENT_LEXEMIZER::PutSwitches (
+ IN PCSTR Switches
+ )
+/*++
+
+Routine Description:
+
+ Initializes Switches
+
+Arguments:
+
+ Switches - Supplies pointer to string of switches
+
+Return Value:
+
+ none
+--*/
+{
+ DebugPtrAssert( Switches );
+ _SwitchChars.Initialize(Switches);
+ _SeparatorString.Initialize( &_Separators );
+ _SeparatorString.Strcat(&_WhiteSpace);
+ _SeparatorString.Strcat(&_SwitchChars);
+}
+
+ULIB_EXPORT
+VOID
+ARGUMENT_LEXEMIZER::PutSwitches (
+ IN PCWSTRING Switches
+ )
+/*++
+
+Routine Description:
+
+ Initializes Switches
+
+Arguments:
+
+ Switches - Supplies pointer to string of switches
+
+Return Value:
+
+ none
+--*/
+{
+ DebugPtrAssert( Switches );
+ _SwitchChars.Initialize(Switches);
+ _SeparatorString.Initialize( &_Separators );
+ _SeparatorString.Strcat(&_WhiteSpace);
+ _SeparatorString.Strcat(&_SwitchChars);
+}
+
+ULIB_EXPORT
+PWSTRING
+ARGUMENT_LEXEMIZER::QueryInvalidArgument (
+ )
+/*++
+
+Routine Description:
+
+ Returns the lexeme tha could not be matched against any argument
+
+Arguments:
+
+ none
+
+Return Value:
+
+ pointer to string initialized with the offending lexeme
+
+--*/
+{
+ PWSTRING String;
+
+ if ( _ConsumedCount == _LexemeCount) {
+ //
+ // There was no error
+ //
+ return NULL;
+ }
+
+ if ( ((String = NEW DSTRING) == NULL) ||
+ !String->Initialize( GetLexemeAt( _ConsumedCount )) ) {
+ DebugAssert( FALSE );
+
+ DELETE( String );
+ return NULL;
+ }
+
+ return String;
+
+}
+
+BOOLEAN
+ARGUMENT_LEXEMIZER::PutCharPos (
+ IN ULONG Index,
+ IN CHNUM CharPos
+ )
+/*++
+
+Routine Description:
+
+ Puts a character position into the character position array
+
+Arguments:
+
+ Index - Supplies the Index within the CharPos array
+
+ CharPos - Supplies the character
+
+Return Value:
+
+ TRUE - If done, FALSE otherwise
+
+--*/
+
+{
+ PCHNUM pTmp;
+ ULONG NewSize = _CharPosSize;
+
+ if ( Index >= _CharPosSize ) {
+
+ NewSize += CHARPOS_INCREMENT;
+
+ if ( !(pTmp = (PCHNUM)REALLOC( _CharPos, (unsigned int)(NewSize * sizeof(CHNUM)) ))) {
+ return FALSE;
+ }
+
+ _CharPos = pTmp;
+ _CharPosSize = NewSize;
+ }
+
+ _CharPos[ Index ] = CharPos;
+
+ return TRUE;
+}
+
+
+
+ULIB_EXPORT
+BOOLEAN
+ARGUMENT_LEXEMIZER::PrepareToParse (
+ IN PWSTRING CommandLine
+ )
+/*++
+
+Routine Description:
+
+ Lexes command line into strings and puts in array container held
+ with object.
+
+Arguments:
+
+ CommandLine - Supplies command line
+
+Return Value:
+
+ TRUE - If Command line lex'd correctly
+ FALSE - If error in lexing. FALSE will be returned if there are
+ quote characters defined and the user types a command line with
+ an open quote without a corresponding close quote.
+
+--*/
+
+{
+ PWSTRING pEndSet; // End Set for token
+ PWSTRING pCur; // Current token
+ PWSTRING pTmp; // Temporary string
+ CHNUM chnStart; // Start of token
+ CHNUM chnEnd; // End of token
+ CHNUM SwitchAt; // Switch character position
+ CHNUM SwitchSpan; // Switches expand up to this position
+ CHNUM QuoteOffset; // Offset of beg. quote char in _StartQuote
+ WCHAR EndQuoteChar; // end of quote char
+ CHNUM NextMeta;
+ CHNUM NextSeparator;
+
+
+ if ( CommandLine == NULL ) {
+
+#if defined( _AUTOCHECK_ )
+
+ return FALSE;
+#else
+ if (!_CmdLine.Initialize( GetCommandLine() )) {
+ DebugAssert( FALSE );
+ return FALSE;
+ }
+#endif
+
+ } else {
+
+ if (!_CmdLine.Initialize( CommandLine )) {
+ DebugAssert( FALSE );
+ return FALSE;
+ }
+ }
+
+ chnStart = 0;
+
+ //
+ // Set _Switch to any permissible switch character
+ //
+ DebugAssert( _SwitchChars.QueryChCount() > 0 );
+ _Switch = _SwitchChars.QueryChAt( 0 );
+
+ //
+ // If we are case-insensitive, then we expand our multiple switches
+ // to include lower and upper case.
+ //
+ if (!_CaseSensitive && _MultipleSwitches.QueryChCount() > 0) {
+
+ pTmp = NEW DSTRING;
+
+ _MultipleSwitches.Strupr();
+
+ pTmp->Initialize(&_MultipleSwitches);
+ pTmp->DeleteChAt(0);
+ pTmp->Strlwr();
+ _MultipleSwitches.Strcat(pTmp);
+
+ DELETE( pTmp );
+ }
+
+ //
+ // Loop till Command line is exhausted of tokens.
+ //
+ while ( TRUE ) {
+
+ //
+ // move to first character not part of white space. This will
+ // always be the case for the start char. position since lexing
+ // will always be interested in anything that is not white space.
+ //
+ chnStart = _CmdLine.Strspn( &_WhiteSpace, chnStart );
+
+ //
+ // Check of any tokens left to lex. Note that we have to
+ // recheck the actual char. count each time through since
+ // we may have deleted meta characters
+ //
+ if (chnStart == INVALID_CHNUM) {
+
+ //
+ // Have exhausted the command line of tokens. Get out of here
+ //
+ break;
+ }
+
+ //
+ // if escape character, skip it and try again
+ //
+ if (_MetaChars.Strchr( _CmdLine.QueryChAt( chnStart)) != INVALID_CHNUM) {
+
+ chnStart++;
+ continue;
+ }
+
+ //
+ // we've skipped over the leading whitespace so we're at the
+ // beginning of the token.
+ //
+ chnEnd = chnStart;
+
+ if ( chnEnd < _CmdLine.QueryChCount() ) {
+
+ pEndSet = &_SeparatorString;
+
+ while ( chnEnd < _CmdLine.QueryChCount() ) {
+
+ // if the current character is a separator and not
+ // the first character in the token, we're done.
+ // It can also be that there is no space between switches
+ if( chnEnd != chnStart &&
+ ((_SeparatorString.Strchr(_CmdLine.QueryChAt(chnEnd)) != INVALID_CHNUM) ||
+ (_NoSpcBetweenDstAndSwitch &&
+ (_SwitchChars.Strchr(_CmdLine.QueryChAt(chnEnd)) != INVALID_CHNUM) &&
+ ((chnEnd+1) < _CmdLine.QueryChCount()) &&
+ !isdigit(_CmdLine.QueryChAt(chnEnd+1))))) {
+
+ // If this token so far is two consecutive separators,
+ // keep going. Otherwise, it's the end of the token.
+ //
+ if( chnStart + 1 == chnEnd &&
+ (_SwitchChars.Strchr( _CmdLine.QueryChAt( chnStart ) ) != INVALID_CHNUM ) &&
+ (_SwitchChars.Strchr( _CmdLine.QueryChAt( chnEnd ) ) != INVALID_CHNUM ) ) {
+
+ chnEnd++;
+ continue;
+ }
+
+ break;
+ }
+
+ // if the current character is a meta character, delete
+ // the meta character and accept the following character
+ // without reservation.
+ //
+ if( _MetaChars.Strchr( _CmdLine.QueryChAt(chnEnd) ) != INVALID_CHNUM ) {
+
+ _CmdLine.DeleteChAt(chnEnd);
+
+ if( chnEnd < _CmdLine.QueryChCount() ) {
+ chnEnd++;
+ }
+ continue;
+ }
+
+ // if the current character is a start-quote, accept everything
+ // until an end-quote is found (or we run out of string).
+ //
+ if( (QuoteOffset = _StartQuote.Strchr( _CmdLine.QueryChAt(chnEnd) )) != INVALID_CHNUM ) {
+
+ //
+ // Set the end of quote char to the corresponding char in
+ // the _EndQuote string. (ie. if the opening quote char
+ // is the first char in _StartQuote then use the first
+ // char in _EndQuote)
+ //
+ EndQuoteChar = _EndQuote.QueryChAt(QuoteOffset);
+ chnEnd++;
+
+ while( TRUE ) {
+ //
+ // locate potential end of token by looking for the
+ // EndQuoteChar.
+ //
+ // check if next char is the EndQuoteChar--if it is,
+ // then the user is 'quoting' the endquotechar, so
+ // remove the 'quoting' char. Otherwise, this is
+ // the end of the quoted string.
+ //
+ if( (chnEnd = _CmdLine.Strchr(EndQuoteChar, chnEnd ))
+ != INVALID_CHNUM ) {
+
+ //
+ // bump up chnEnd to check the character
+ // after the quote char. If it's another
+ // quote char then, delete the first quote.
+ // Otherwise, we're at the end of the quoted
+ // string.
+ //
+ if( _CmdLine.QueryChAt(++chnEnd) == EndQuoteChar ) {
+
+ _CmdLine.DeleteChAt(chnEnd - 1);
+ continue;
+
+ } else {
+
+ break;
+ }
+
+ } else {
+
+ //
+ // we reached the end of the string w/o finding the
+ // endQuoteChar (chnEnd == INVALID_CHNUM)
+ //
+ // return FALSE because an open quote is being
+ // considered a lex error because this is easier and
+ // does what is required. If someone wants to
+ // handle quote characters they could change this
+ // by setting chnEnd to the last char of the first
+ // token, ignoring the quote. eg: if cmd line was
+ // cmd "arg1 arg2 arg3
+ //
+ // chnEnd could be set to the position of '1'.
+ //
+ return FALSE;
+
+ }
+ }
+
+ // Keep accepting characters.
+ //
+ continue;
+ }
+
+ // It's not a separator, a meta-character, or a start quote;
+ // accept it.
+ //
+ chnEnd++;
+ }
+ }
+
+
+ //
+ // we have a valid token to put in string array.
+ //
+ if ((pCur = _CmdLine.QueryString(chnStart, chnEnd - chnStart)) == NULL) {
+
+ //
+ // Could not create a new substring. Error out.
+ //
+ return FALSE;
+ }
+
+ SwitchSpan = pCur->Strspn( &_MultipleSwitches, 1 );
+
+ //
+ // Ramonsa - We must not replace the original switch character used,
+ // because if we do then we won't be able to retrieve it.
+ //
+ //if ((SwitchAt = _SwitchChars.Strchr( pCur->QueryChAt(0))) != INVALID_CHNUM ) {
+ //
+ // //
+ // // The first character is a switch
+ // //
+ // pCur->SetChAt( _Switch, 0);
+ //
+ //
+ //}
+ SwitchAt = _SwitchChars.Strchr( pCur->QueryChAt(0) );
+
+ //
+ // Check for multiple switch arguments by seeing if any of the
+ // characters in the token are not in the multiple switch set.
+ // Also, if the token is only one character then it can't be
+ // multiple switches.
+ if (( SwitchAt == INVALID_CHNUM ) ||
+ ( SwitchSpan != INVALID_CHNUM ) ||
+ pCur->QueryChCount() == 1) {
+
+ //
+ // Non-multiple characters were found, throw the entire
+ // thing into the string array container
+ //
+
+ if (!_parray->Put( pCur ) ||
+ !PutCharPos( _LexemeCount, chnStart )
+ ) {
+
+ //
+ // Error out we could not insert the value
+ //
+ return FALSE;
+
+ } else {
+
+ //
+ // Setup to fetch next token and go to outer loop
+ //
+ _LexemeCount++;
+ chnStart = chnEnd;
+ continue;
+ }
+
+ } else {
+
+ //
+ // All characters in the string are multiple switches.
+ //
+ for ( CHNUM chn = 1; chn < pCur->QueryChCount(); chn++ ) {
+
+ //
+ // If glomming is allowed then we want to handle pCur when
+ // it looks like "/s/f/i/d" by splitting up each argument.
+ // We skip over the slashes and treat this string the same
+ // as "/sfid". (See arg.hxx at "GLOMMING".)
+ //
+
+ if (_AllowGlomming && chn >= 2 &&
+ pCur->QueryChAt(chn) == pCur->QueryChAt(0)) {
+ continue;
+ }
+
+ //
+ // Pull out a switch and put in new switch string.
+ //
+ pTmp = NEW DSTRING();
+
+ pTmp->Initialize((PWSTR) L" ");
+
+ pTmp->SetChAt( pCur->QueryChAt(0), 0 );
+ pTmp->SetChAt( pCur->QueryChAt(chn), 1 );
+
+ if (!_parray->Put( pTmp ) ||
+ !PutCharPos( _LexemeCount, chnStart )
+ ) {
+
+ //
+ // ERROR out we could not put the token
+ //
+ DELETE( pTmp );
+ return FALSE;
+
+ } else {
+
+ _LexemeCount++;
+ }
+ }
+
+ //
+ // pCur not needed anymore
+ //
+ DELETE( pCur );
+
+ //
+ // Setup to fetch next token and go to outer loop
+ //
+ chnStart = chnEnd;
+ continue;
+ }
+ }
+
+ return TRUE;
+}
+
+ULIB_EXPORT
+BOOLEAN
+ARGUMENT_LEXEMIZER::DoParsing (
+ IN PARRAY ArgumentArray
+ )
+/*++
+
+Routine Description:
+
+ Parses the arguments passed.
+
+Arguments:
+
+ ArgumentArray - Supplies pointer to array of arguments to set
+
+
+Return Value:
+
+ TRUE if all argument strings matched
+ FALSE otherwise.
+
+
+--*/
+{
+
+ PARRAY_ITERATOR Iterator;
+ PARGUMENT arg;
+ BOOLEAN DoAgain = TRUE;
+
+ DebugPtrAssert( ArgumentArray );
+
+ while (DoAgain) {
+
+ DoAgain = FALSE;
+
+ Iterator = (PARRAY_ITERATOR)ArgumentArray->QueryIterator();
+
+ DebugAssert( Iterator );
+
+ if ( Iterator ) {
+
+ arg = (PARGUMENT)Iterator->GetNext();
+
+ while( arg ) {
+
+ //
+ // Check that the argument hasn't already found its
+ // match.
+ //
+ if (!arg->IsValueSet()) {
+
+ //
+ // If the first character of the pattern is a switch,
+ // we change the switch character.
+ //
+ if (( _SwitchChars.Strchr(arg->GetPattern()->QueryChAt(0))) != INVALID_CHNUM) {
+
+ arg->GetPattern()->SetChAt( _Switch, 0);
+
+ }
+
+ //
+ // Try to match it
+ //
+ if (arg->SetIfMatch( this, _CaseSensitive )) {
+
+ //
+ // Found a match, start over with first argument
+ // if there are more lexemes to match.
+ //
+ DoAgain = (BOOLEAN)( _ConsumedCount != _LexemeCount );
+
+ break;
+ }
+ }
+
+ arg = (PARGUMENT)Iterator->GetNext();
+ }
+
+ DELETE( Iterator );
+ }
+ }
+
+ return ( _ConsumedCount == _LexemeCount );
+}
+
+ULIB_EXPORT
+PWSTRING
+ARGUMENT_LEXEMIZER::GetLexemeAt (
+ IN ULONG Index
+ )
+/*++
+
+Routine Description:
+
+ Gets the Lexeme at the specified index
+
+Arguments:
+
+ Index - Supplies the index of the lexeme desired
+
+Return Value:
+
+ Pointer to the lexeme
+
+--*/
+{
+ return (PWSTRING)_parray->GetAt(Index);
+}
+
+
+CHNUM
+ARGUMENT_LEXEMIZER::QueryCharPos (
+ IN ULONG LexemeNumber
+ )
+/*++
+
+Routine Description:
+
+ Queries the character position of a particular lexeme
+
+Arguments:
+
+ LexemeNumber - Supplies the lexeme number
+
+Return Value:
+
+ Returns the character position of the lexeme
+
+--*/
+{
+ DebugAssert( LexemeNumber < _LexemeCount );
+ DebugAssert( LexemeNumber < _CharPosSize );
+
+ return _CharPos[ LexemeNumber ];
+}
+
+
+ULIB_EXPORT
+VOID
+ARGUMENT_LEXEMIZER::SetCaseSensitive (
+ IN BOOLEAN CaseSensitive
+ )
+/*++
+
+Routine Description:
+
+ Sets case sensitivity ON/OFF
+
+Arguments:
+
+ CaseSensitive - Supplies case sensitivity flag
+
+Return Value:
+
+ none
+
+--*/
+{
+ _CaseSensitive = CaseSensitive;
+}
+
+
+ULIB_EXPORT
+VOID
+ARGUMENT_LEXEMIZER::SetAllowSwitchGlomming (
+ IN BOOLEAN AllowGlomming
+ )
+/*++
+
+Routine Description:
+
+ Sets whether swith glomming (as in "/s/f/i/d") is allowed
+ or not. See note in <arg.hxx> at "GLOMMING".
+
+Arguments:
+
+ AllowGlomming - Supplies glomming allowed flag.
+
+Return Value:
+
+ none
+
+--*/
+{
+ _AllowGlomming = AllowGlomming;
+}
+
+
+ULIB_EXPORT
+VOID
+ARGUMENT_LEXEMIZER::SetNoSpcBetweenDstAndSwitch (
+ IN BOOLEAN NoSpcBetweenDstAndSwitch
+ )
+/*++
+
+Routine Description:
+
+ Sets whether a separator is required between
+ tokens. This is specifically for xcopy that
+ a space should not be required to separate the
+ destination and the specified options.
+
+Arguments:
+
+ NoSpcBetweenDstAndSwitch - Supplies the flag
+
+Return Value:
+
+ none
+
+--*/
+{
+ _NoSpcBetweenDstAndSwitch = NoSpcBetweenDstAndSwitch;
+}
+
+
+DEFINE_CONSTRUCTOR( ARGUMENT, OBJECT );
+
+VOID
+ARGUMENT::Construct (
+ )
+{
+ UNREFERENCED_PARAMETER( (void)this);
+ _Lexeme = NULL;
+}
+
+BOOLEAN
+ARGUMENT::Initialize (
+ IN PSTR Pattern
+ )
+/*++
+
+Routine Description:
+
+ Create an ARGUMENT object and setup for parsing
+
+Arguments:
+
+ Pattern - Supplies string used in matching argument with command line
+ parameter
+
+Return Value:
+
+ TRUE - If arg. initialized.
+ FALSE - If failed to initialize.
+
+--*/
+{
+
+ //
+ // Make sure that we have an associated pattern
+ //
+ DebugAssert(Pattern);
+
+ //
+ // Initially we don't have a value
+ //
+ _fValueSet = FALSE;
+
+ //
+ // Initialize the pattern
+ //
+ return _Pattern.Initialize(Pattern);
+}
+
+BOOLEAN
+ARGUMENT::Initialize (
+ IN PWSTRING Pattern
+ )
+/*++
+
+Routine Description:
+
+ Create an ARGUMENT object and setup for parsing
+
+Arguments:
+
+ Pattern - Supplies string used in matching argument with command line
+ parameter
+
+Return Value:
+
+ TRUE - If arg. initialized.
+ FALSE - If failed to initialize.
+
+--*/
+{
+
+ //
+ // Make sure that we have an associated pattern
+ //
+ DebugAssert(Pattern);
+
+ //
+ // Initially we don't have a value
+ //
+ _fValueSet = FALSE;
+
+ //
+ // Initialize the pattern
+ //
+ return _Pattern.Initialize(Pattern);
+}
+
+ULIB_EXPORT
+PWSTRING
+ARGUMENT::GetLexeme (
+ )
+/*++
+
+Routine Description:
+
+ Gets the lexeme matched by this Argument.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ Pointer to Lexeme
+
+--*/
+{
+ //DebugAssert( _fValueSet );
+
+ return _Lexeme;
+}
+
+ULIB_EXPORT
+PWSTRING
+ARGUMENT::GetPattern (
+ )
+/*++
+
+Routine Description:
+
+ Gets the pattern associated with this Argument.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ Pointer to pattern
+
+--*/
+{
+ return &_Pattern;
+}
+
+BOOLEAN
+ARGUMENT ::SetIfMatch(
+ OUT PARGUMENT_LEXEMIZER ArgumentLexemizer,
+ IN BOOLEAN CaseSensitive
+ )
+/*++
+
+Routine Description:
+
+ Determines if the current argument string is recognized by
+ this ARGUMENT object, and setst the value if there is a match.
+
+Arguments:
+
+ ArgumentLexemizer - Supplies container holding command line
+ lex'd into strings
+ CaseSensitive - Supplies case sensitivity flag
+
+Return Value:
+
+ TRUE - argument recognized and value set.
+ FALSE - argument not recognized and/or value not set.
+
+--*/
+{
+ //
+ // Match will try to match the current argument pattern (Pattern)
+ // with one of the string from the lexemizer. If a match occurs
+ // then it will callback through the this pointer passed to
+ // the SetValue routine for this argument object.
+ //
+ return Match( this, ArgumentLexemizer, CaseSensitive );
+};
+
+ULIB_EXPORT
+BOOLEAN
+ARGUMENT::IsValueSet (
+ )
+/*++
+
+Routine Description:
+
+ Checks if the argument has been found and set.
+
+ This method is used to determine if the ARGUMENT object has had
+ its value set without having to know what type of ARGUMENT object
+ it is. This is used mainly in ARGUMENT_LIST to avoid repeated calling
+ IsArgument once the argument has been recognized and the value
+ set.
+
+Arguments:
+
+Return Value:
+
+ TRUE - if value has already been set.
+ FALSE - if the value has not been set and it is ok to call IsArgument
+
+--*/
+{
+ return _fValueSet;
+};
+
+BOOLEAN
+ARGUMENT::SetValue(
+ IN PWSTRING Arg,
+ IN CHNUM chnIdx,
+ IN CHNUM chnEnd,
+ IN PARGUMENT_LEXEMIZER ArgumentLexemizer
+ )
+/*++
+
+Routine Description:
+
+ Default method for setting the value of an argument. Sets
+ fValueSet to false.
+
+Arguments:
+
+ Arg - Supplies current argument string
+ chnIdx - Supplies index within Arg
+ ArgumentLexemizer - Supplies list of lexed strings
+
+Return Value:
+
+ FALSE
+
+--*/
+{
+
+ UNREFERENCED_PARAMETER( this );
+ UNREFERENCED_PARAMETER( (void)Arg );
+ UNREFERENCED_PARAMETER( (void)chnIdx );
+ UNREFERENCED_PARAMETER( (void)ArgumentLexemizer );
+ UNREFERENCED_PARAMETER( (void)chnEnd );
+
+
+ return _fValueSet = FALSE ;
+}
+
+
+
+
+
+
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( FLAG_ARGUMENT, ARGUMENT, ULIB_EXPORT);
+
+VOID
+FLAG_ARGUMENT::Construct (
+ )
+{
+ UNREFERENCED_PARAMETER( this );
+}
+
+ULIB_EXPORT
+BOOLEAN
+FLAG_ARGUMENT::Initialize (
+ IN PSTR Pattern
+ )
+/*++
+
+Routine Description:
+
+ Create a FLAG_ARGUMENT object and setup for parsing
+
+Arguments:
+
+ Pattern - Supplies string used in matching argument with command line
+ parameter
+
+Return Value:
+
+ TRUE - If arg. initialized.
+ FALSE - If failed to initialize.
+
+--*/
+{
+
+ //
+ // Set our initial value
+ //
+ _flag = FALSE;
+
+ //
+ // Initialize the pattern
+ //
+ return ARGUMENT::Initialize(Pattern);
+
+}
+
+ULIB_EXPORT
+BOOLEAN
+FLAG_ARGUMENT::Initialize (
+ IN PWSTRING Pattern
+ )
+/*++
+
+Routine Description:
+
+ Create a FLAG_ARGUMENT object and setup for parsing
+
+Arguments:
+
+ Pattern - Supplies string used in matching argument with command line
+ parameter
+
+Return Value:
+
+ TRUE - If arg. initialized.
+ FALSE - If failed to initialize.
+
+--*/
+{
+
+ //
+ // Set our initial value
+ //
+ _flag = FALSE;
+
+ //
+ // Initialize the pattern
+ //
+ return ARGUMENT::Initialize(Pattern);
+
+}
+
+BOOLEAN
+FLAG_ARGUMENT::SetValue(
+ IN PWSTRING Arg,
+ IN CHNUM chnIdx,
+ IN CHNUM chnEnd,
+ IN PARGUMENT_LEXEMIZER ArgumentLexemizer
+ )
+/*++
+
+Routine Description:
+
+ Sets the flag to TRUE
+
+Arguments:
+
+ Arg - Supplies current argument string
+ chnIdx - Supplies index within Arg
+ ArgumentLexemizer - Supplies list of lexed strings
+
+Return Value:
+
+ FALSE
+
+--*/
+{
+
+ UNREFERENCED_PARAMETER( this );
+ UNREFERENCED_PARAMETER( (void)Arg );
+ UNREFERENCED_PARAMETER( (void)chnIdx );
+ UNREFERENCED_PARAMETER( (void)ArgumentLexemizer );
+
+ _Lexeme = Arg;
+ return _flag = _fValueSet = TRUE;
+
+}
+
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( STRING_ARGUMENT, ARGUMENT, ULIB_EXPORT);
+
+VOID
+STRING_ARGUMENT::Construct (
+ )
+{
+ _String = NULL;
+}
+
+ULIB_EXPORT
+STRING_ARGUMENT::~STRING_ARGUMENT (
+ )
+/*++
+
+Routine Description:
+
+ Destructor for String Arguments
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+{
+ DELETE( _String );
+}
+
+ULIB_EXPORT
+BOOLEAN
+STRING_ARGUMENT::Initialize (
+ IN PSTR Pattern
+ )
+/*++
+
+Routine Description:
+
+ Create a FLAG_ARGUMENT object and setup for parsing
+
+Arguments:
+
+ Pattern - Supplies string used in matching argument with command line
+ parameter
+
+Return Value:
+
+ TRUE - If arg. initialized.
+ FALSE - If failed to initialize.
+
+--*/
+{
+ //
+ // Set our initial value
+ //
+ _String = NULL;
+
+ //
+ // Initialize the pattern
+ //
+ return ARGUMENT::Initialize(Pattern);
+
+}
+
+BOOLEAN
+STRING_ARGUMENT::Initialize (
+ IN PWSTRING Pattern
+ )
+/*++
+
+Routine Description:
+
+ Create a FLAG_ARGUMENT object and setup for parsing
+
+Arguments:
+
+ Pattern - Supplies string used in matching argument with command line
+ parameter
+
+Return Value:
+
+ TRUE - If arg. initialized.
+ FALSE - If failed to initialize.
+
+--*/
+{
+ //
+ // Set our initial value
+ //
+ _String = NULL;
+
+ //
+ // Initialize the pattern
+ //
+ return ARGUMENT::Initialize(Pattern);
+
+}
+
+BOOLEAN
+STRING_ARGUMENT::SetValue(
+ IN PWSTRING Arg,
+ IN CHNUM chnIdx,
+ IN CHNUM chnEnd,
+ IN PARGUMENT_LEXEMIZER ArgumentLexemizer
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the value of a STRING_ARGUMENT argument
+
+Arguments:
+
+ Arg - Supplies current argument string
+ chnIdx - Supplies index within Arg
+ ArgumentLexemizer - Supplies list of lexed strings
+
+Return Value:
+
+ TRUE if value set
+ FALSE otherwise
+
+--*/
+{
+
+ DebugPtrAssert( Arg );
+
+ _fValueSet = FALSE;
+
+ DebugAssert( Arg->QueryChCount() >= chnEnd );
+
+ if ((_String=Arg->QueryString(chnIdx, chnEnd - chnIdx )) != NULL) {
+ ArgumentLexemizer->IncrementConsumedCount( );
+
+ _Lexeme = Arg;
+ _fValueSet = TRUE;
+ }
+
+ return _fValueSet;
+}
+
+
+
+
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( LONG_ARGUMENT, ARGUMENT, ULIB_EXPORT);
+
+VOID
+LONG_ARGUMENT::Construct (
+ )
+{
+ UNREFERENCED_PARAMETER( this );
+}
+
+ULIB_EXPORT
+BOOLEAN
+LONG_ARGUMENT::Initialize (
+ IN PSTR Pattern
+ )
+/*++
+
+Routine Description:
+
+ Create a FLAG_ARGUMENT object and setup for parsing
+
+Arguments:
+
+ Pattern - Supplies string used in matching argument with command line
+ parameter
+
+Return Value:
+
+ TRUE - If arg. initialized.
+ FALSE - If failed to initialize.
+
+--*/
+{
+
+ //
+ // Set our initial value
+ //
+ _value = 0;
+
+ //
+ // Initialize the pattern
+ //
+ return ARGUMENT::Initialize(Pattern);
+
+}
+
+BOOLEAN
+LONG_ARGUMENT::Initialize (
+ IN PWSTRING Pattern
+ )
+/*++
+
+Routine Description:
+
+ Create a FLAG_ARGUMENT object and setup for parsing
+
+Arguments:
+
+ Pattern - Supplies string used in matching argument with command line
+ parameter
+
+Return Value:
+
+ TRUE - If arg. initialized.
+ FALSE - If failed to initialize.
+
+--*/
+{
+
+ //
+ // Set our initial value
+ //
+ _value = 0;
+
+ //
+ // Initialize the pattern
+ //
+ return ARGUMENT::Initialize(Pattern);
+
+}
+
+BOOLEAN
+LONG_ARGUMENT::SetValue (
+ IN PWSTRING Arg,
+ IN CHNUM chnIdx,
+ IN CHNUM chnEnd,
+ IN PARGUMENT_LEXEMIZER ArgumentLexemizer
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the value of a LONG_ARGUMENT argument
+
+Arguments:
+
+ Arg - Supplies current argument string
+ chnIdx - Supplies index within Arg
+ ArgStrings - Supplies list of lexed strings
+
+Return Value:
+
+ TRUE if value set
+ FALSE otherwise
+
+--*/
+{
+ DebugPtrAssert( Arg );
+
+ DebugAssert( Arg->QueryChCount() >= chnEnd );
+
+ if ( Arg->QueryNumber( &_value, chnIdx, chnEnd - chnIdx )) {
+ ArgumentLexemizer->IncrementConsumedCount();
+
+ _Lexeme = Arg;
+ return _fValueSet = TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
+#if !defined( _AUTOCHECK_ )
+
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( TIMEINFO_ARGUMENT, ARGUMENT, ULIB_EXPORT);
+
+VOID
+TIMEINFO_ARGUMENT::Construct (
+ )
+{
+ UNREFERENCED_PARAMETER( this );
+}
+
+ULIB_EXPORT
+TIMEINFO_ARGUMENT::~TIMEINFO_ARGUMENT (
+ )
+/*++
+
+Routine Description:
+
+ Destructor for Timeinfo Arguments
+
+Arguments:
+
+
+Return Value:
+
+ none
+
+--*/
+{
+ DELETE( _TimeInfo );
+}
+
+ULIB_EXPORT
+BOOLEAN
+TIMEINFO_ARGUMENT::Initialize (
+ IN PSTR Pattern
+ )
+/*++
+
+Routine Description:
+
+ Create a TIMEINFO_ARGUMENT object and setup for parsing
+
+Arguments:
+
+ Pattern - Supplies string used in matching argument with command line
+ parameter
+
+Return Value:
+
+ TRUE - If arg. initialized.
+ FALSE - If failed to initialize.
+
+--*/
+{
+
+ _TimeInfo = NULL;
+
+ return ARGUMENT::Initialize(Pattern);
+
+}
+
+BOOLEAN
+TIMEINFO_ARGUMENT::Initialize (
+ IN PWSTRING Pattern
+ )
+/*++
+
+Routine Description:
+
+ Create a TIMEINFO_ARGUMENT object and setup for parsing
+
+Arguments:
+
+ Pattern - Supplies string used in matching argument with command line
+ parameter
+
+Return Value:
+
+ TRUE - If arg. initialized.
+ FALSE - If failed to initialize.
+
+--*/
+{
+
+ _TimeInfo = NULL;
+
+ return ARGUMENT::Initialize(Pattern);
+
+}
+
+BOOLEAN
+TIMEINFO_ARGUMENT::SetValue (
+ IN PWSTRING Arg,
+ IN CHNUM chnIdx,
+ IN CHNUM chnEnd,
+ IN PARGUMENT_LEXEMIZER ArgumentLexemizer
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the value of a TIMEINFO_ARGUMENT argument
+
+Arguments:
+
+ Arg - Supplies current argument string
+ chnIdx - Supplies index within Arg
+ ArgStrings - Supplies list of lexed strings
+
+Return Value:
+
+ TRUE if value set
+ FALSE otherwise
+
+--*/
+{
+
+ DSTRING String;
+
+ DebugPtrAssert( Arg );
+
+ if ( ( Arg) &&
+ String.Initialize( Arg, chnIdx, chnEnd - chnIdx ) &&
+ ((_TimeInfo = NEW TIMEINFO) != NULL) &&
+ _TimeInfo->Initialize() &&
+ _TimeInfo->SetDateAndTime( &String ) ) {
+
+ ArgumentLexemizer->IncrementConsumedCount();
+
+ _Lexeme = Arg;
+ return _fValueSet = TRUE;
+ }
+
+ return FALSE;
+}
+
+#endif // _AUTOCHECK_
+
+
+#if !defined( _AUTOCHECK_ )
+
+DEFINE_EXPORTED_CONSTRUCTOR( PATH_ARGUMENT, ARGUMENT, ULIB_EXPORT);
+
+VOID
+PATH_ARGUMENT::Construct (
+ )
+{
+ _Path = NULL;
+}
+
+ULIB_EXPORT
+PATH_ARGUMENT::~PATH_ARGUMENT(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for Path Arguments
+
+Arguments:
+
+ none
+
+Return Value:
+
+ none
+
+--*/
+{
+ Destroy();
+}
+
+VOID
+PATH_ARGUMENT::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Destroys a path argument
+
+Arguments:
+
+ none
+
+Return Value:
+
+ none
+
+--*/
+{
+ DELETE( _Path );
+}
+
+ULIB_EXPORT
+BOOLEAN
+PATH_ARGUMENT::Initialize (
+ IN PSTR Pattern,
+ IN BOOLEAN Canonicalize
+ )
+/*++
+
+Routine Description:
+
+ Create a PATH_ARGUMENT object and setup for parsing
+
+Arguments:
+
+ Pattern - Supplies string used in matching argument with
+ command line parameter
+ Canonicalize - Supplies the canonicalization flag
+
+Return Value:
+
+ TRUE - If arg. initialized.
+ FALSE - If failed to initialize.
+
+--*/
+{
+
+ //
+ // Destroy the path, in case we are re-initializing
+ //
+ Destroy();
+
+ _Canonicalize = Canonicalize;
+
+ //
+ // Initialize the pattern
+ //
+ return ARGUMENT::Initialize(Pattern);
+
+}
+
+BOOLEAN
+PATH_ARGUMENT::Initialize (
+ IN PWSTRING Pattern,
+ IN BOOLEAN Canonicalize
+ )
+/*++
+
+Routine Description:
+
+ Create a PATH_ARGUMENT object and setup for parsing
+
+Arguments:
+
+ Pattern - Supplies string used in matching argument with
+ command line parameter
+ Canonicalize - Supplies the canonicalization flag
+
+Return Value:
+
+ TRUE - If arg. initialized.
+ FALSE - If failed to initialize.
+
+--*/
+{
+
+ //
+ // Destroy the path, in case we are re-initializing
+ //
+ Destroy();
+
+ _Canonicalize = Canonicalize;
+
+ //
+ // Initialize the pattern
+ //
+ return ARGUMENT::Initialize(Pattern);
+
+}
+
+BOOLEAN
+PATH_ARGUMENT::SetValue(
+ IN PWSTRING Arg,
+ IN CHNUM chnIdx,
+ IN CHNUM chnEnd,
+ IN PARGUMENT_LEXEMIZER ArgumentLexemizer
+ )
+/*++
+
+Routine Description:
+
+ Sets the value of a PATH_ARGUMENT argument
+
+Arguments:
+
+ Arg - Supplies current argument string
+ chnIdx - Supplies index within Arg
+ ArgumentLexemizer - Supplies list of lexed strings
+
+Return Value:
+
+ TRUE if value set
+ FALSE otherwise
+
+--*/
+{
+
+ PWSTRING pT;
+
+ DebugPtrAssert( Arg );
+
+
+ _fValueSet = FALSE;
+
+ DebugAssert( Arg->QueryChCount() >= chnEnd );
+
+ pT = Arg->QueryString(chnIdx, chnEnd - chnIdx);
+
+ if (NULL != pT) {
+
+ //
+ // Remove double quotes from the path string. We assume
+ // that there will never be a valid double-quote in an
+ // actual path.
+ //
+
+ for (ULONG i = 0; i < pT->QueryChCount(); ++i) {
+ if ('\"' == pT->QueryChAt(i)) {
+ pT->DeleteChAt(i);
+ i--;
+ continue;
+ }
+ }
+
+ if( (_Path = NEW PATH) != NULL) {
+ if ( _Path->Initialize( pT, _Canonicalize )) {
+
+ //
+ // check the first char to see if it's a switch char
+ // (it can't be if it's a path)
+ //
+ if( (ArgumentLexemizer->GetSwitches()->Strchr(pT->QueryChAt(0))
+ == INVALID_CHNUM) ) {
+ ArgumentLexemizer->IncrementConsumedCount();
+
+ _Lexeme = Arg;
+ _fValueSet = TRUE;
+ }
+
+ } else {
+
+ DebugAssert( FALSE );
+ DELETE( _Path );
+ }
+ }
+
+ DELETE( pT );
+
+ }
+
+ return _fValueSet;
+}
+
+
+#endif // _AUTOCHECK_
+
+
+
+#if !defined( _AUTOCHECK_ )
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( MULTIPLE_PATH_ARGUMENT, PATH_ARGUMENT, ULIB_EXPORT);
+
+VOID
+MULTIPLE_PATH_ARGUMENT::Construct (
+ )
+{
+ _PathArray = NULL;
+}
+
+ULIB_EXPORT
+MULTIPLE_PATH_ARGUMENT::~MULTIPLE_PATH_ARGUMENT(
+ )
+
+/*++
+
+Routine Description:
+
+ Destructor for Path Arguments
+
+Arguments:
+
+ none
+
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ Destroy();
+}
+
+VOID
+MULTIPLE_PATH_ARGUMENT::Destroy(
+ )
+
+/*++
+
+Routine Description:
+
+ Destroys a multiple-path argument
+
+Arguments:
+
+ none
+
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ DELETE( _PathArray );
+}
+
+ULIB_EXPORT
+BOOLEAN
+MULTIPLE_PATH_ARGUMENT::Initialize (
+ IN PSTR Pattern,
+ IN BOOLEAN Canonicalize,
+ IN BOOLEAN ExpandWildCards
+ )
+/*++
+
+Routine Description:
+
+ Initializes a MULTIPLE_PATH_ARGUMENT
+
+Arguments:
+
+ Pattern - Supplies the argument pattern
+ Canonicalize - Supplies canonicalization flag
+ ExpandWildCards - Supplies wildcard expansion flag
+
+Return Value:
+
+ TRUE if correctly initialized
+ FALSE otherwise
+
+--*/
+
+{
+
+ //
+ // Destroy, in case we are re-initializing
+ //
+ Destroy();
+
+ //
+ // Initialize the argument
+ //
+ if (PATH_ARGUMENT::Initialize( Pattern, Canonicalize ) ) {
+
+ //
+ // Argument correctly initialized, create our array object
+ //
+ if ((_PathArray = NEW ARRAY) != NULL) {
+
+ //
+ // Ok, so initialize it
+ //
+ if (_PathArray->Initialize() ) {
+
+ //
+ // Everything's cool
+ //
+ _PathCount = 0;
+ _ExpandWildCards = ExpandWildCards;
+ _WildCardExpansionFailed = FALSE;
+ return TRUE ;
+ }
+
+ DELETE( _PathArray );
+ }
+ }
+
+ return FALSE;
+}
+
+BOOLEAN
+MULTIPLE_PATH_ARGUMENT::Initialize (
+ IN PWSTRING Pattern,
+ IN BOOLEAN Canonicalize,
+ IN BOOLEAN ExpandWildCards
+ )
+/*++
+
+Routine Description:
+
+ Initializes a MULTIPLE_PATH_ARGUMENT
+
+Arguments:
+
+ Pattern - Supplies the argument pattern
+ Canonicalize - Supplies canonicalization flag
+ ExpandWildCards - Supplies wildcard expansion flag
+
+Return Value:
+
+ TRUE if correctly initialized
+ FALSE otherwise
+
+--*/
+
+{
+ //
+ // Destroy, in case we are re-initializing
+ //
+ Destroy();
+
+ //
+ // Initialize the argument
+ //
+ if (PATH_ARGUMENT::Initialize( Pattern, Canonicalize ) ) {
+
+ //
+ // Argument correctly initialized, create our array object
+ //
+ if ((_PathArray = NEW ARRAY) != NULL) {
+
+ //
+ // Ok, so initialize it
+ //
+ if (_PathArray->Initialize() ) {
+
+ //
+ // Everything's cool
+ //
+ _PathCount = 0;
+ _ExpandWildCards = ExpandWildCards;
+ _WildCardExpansionFailed = FALSE;
+ return TRUE ;
+ }
+
+ DELETE( _PathArray );
+ }
+ }
+
+ return FALSE;
+}
+
+BOOLEAN
+MULTIPLE_PATH_ARGUMENT::SetValue (
+ IN PWSTRING pwcArg,
+ IN CHNUM chnIdx,
+ IN CHNUM chnEnd,
+ IN PARGUMENT_LEXEMIZER ArgumentLexemizer
+ )
+/*++
+
+Routine Description:
+
+ Sets the value of a MULTIPLE_PATH_ARGUMENT argument
+
+Arguments:
+
+ pwcArg - Supplies current argument string
+ chnIdx - Supplies index within pwcArg
+ ArgumentLexemizer - Supplies list of lexed strings
+
+Return Value:
+
+ TRUE if value set
+ FALSE otherwise
+
+--*/
+{
+
+ PPATH FullPath = NULL;
+ PWSTRING TmpName = NULL;
+ PFSN_DIRECTORY Directory = NULL;
+ PARRAY NodeArray = NULL;
+ PARRAY_ITERATOR Iterator = NULL;
+ PFSNODE Node;
+ PPATH Path;
+ CHNUM BaseLength;
+ DSTRING Name;
+ FSN_FILTER Filter;
+ CHNUM PrefixLength;
+ BOOLEAN Ok = FALSE;
+
+ DebugPtrAssert( _PathArray );
+
+ //
+ // Try to set the path value
+ //
+ if (PATH_ARGUMENT::SetValue(pwcArg, chnIdx, chnEnd, ArgumentLexemizer)) {
+
+ //
+ // If we have to expand wildcards, we get an array of paths and put
+ // the elements in our array, otherwise we just put the path that we
+ // have.
+ //
+ if ( _ExpandWildCards && PATH_ARGUMENT::_Path->HasWildCard() ) {
+
+ //
+ // Expand the path that we have, remember its name portion
+ // and truncate it so that we are left with a directory
+ // path. Then get a directory object from the path and a filter
+ // for the wildcard.
+ //
+ // Then do the wildcard expansion.
+ //
+ if ( ( FullPath = PATH_ARGUMENT::_Path->QueryFullPath() ) &&
+ ( TmpName = FullPath->QueryName() ) &&
+ Name.Initialize( TmpName ) &&
+ FullPath->TruncateBase() &&
+ (Directory = SYSTEM::QueryDirectory( FullPath )) &&
+ Filter.Initialize() &&
+ Filter.SetFileName( &Name ) &&
+ ( NodeArray = Directory->QueryFsnodeArray( &Filter )) &&
+ ( Iterator = (PARRAY_ITERATOR)NodeArray->QueryIterator() )
+ ) {
+
+ Ok = TRUE;
+
+
+ //
+ // If no files matched the wildcard, we remember the pattern
+ // and set the failure flag.
+ //
+ if ( !_WildCardExpansionFailed &&
+ (NodeArray->QueryMemberCount() == 0 ) ) {
+
+ _WildCardExpansionFailed = TRUE;
+ _LexemeThatFailed.Initialize( pwcArg );
+
+ } else {
+
+ //
+ // Now that we have done the wildcard expansion, extract
+ // all the paths and put them in our array
+ //
+ while ( Node = (PFSNODE)Iterator->GetNext() ) {
+
+ Path = NULL;
+
+ DELETE( TmpName );
+
+ if ( (Path = NEW PATH) &&
+ Path->Initialize( PATH_ARGUMENT::_Path ) &&
+ Path->TruncateBase() &&
+ (TmpName = ((PPATH) Node->GetPath())->QueryName()) &&
+ Path->AppendBase( TmpName ) &&
+ _PathArray->Put( Path )
+ ) {
+
+ DELETE( TmpName );
+
+ _PathCount++;
+
+ } else {
+
+ DELETE( Path );
+ Ok = FALSE;
+ break;
+
+ }
+ }
+ }
+
+ DELETE( TmpName );
+ DELETE( FullPath );
+ DELETE( Directory );
+ DELETE( Iterator );
+ if ( NodeArray ) {
+ NodeArray->DeleteAllMembers();
+ }
+ DELETE( NodeArray );
+ DELETE( FullPath );
+ }
+
+
+ } else {
+
+ if (_PathArray->Put(PATH_ARGUMENT::_Path)) {
+
+ _PathCount++;
+
+ Ok = TRUE;
+
+ }
+ }
+
+ //
+ // We reset the _fValueSet flag, because we can
+ // always take another path.
+ //
+ ARGUMENT::_fValueSet = FALSE;
+ }
+
+ return Ok;
+}
+
+
+#endif // _AUTOCHECK_
+
+
+
+//
+// Macro for handling case-sensitivity
+//
+#define CASESENS(c) ( CaseSensitive ? (c) : towupper((c)) )
+
+STATIC
+BOOLEAN
+Match(
+ OUT PARGUMENT Argument,
+ OUT PARGUMENT_LEXEMIZER ArgumentLexemizer,
+ IN BOOLEAN CaseSensitive
+ )
+/*++
+
+Routine Description:
+
+ Tries to match a pattern, and if there is a match it
+ sets the value of the corresponding argument.
+
+Arguments:
+
+ Argument - Supplies pointer to argument
+ ArgumentLexemizer - Supplies pointer to lexed string list
+ CaseSensitive - Supplies case sensitivity flag
+
+Return Value:
+
+ TRUE - argument recognized and value set.
+ FALSE - argument not recognized and/or value not set.
+
+--*/
+{
+
+ BOOLEAN fFound;
+ CHNUM chnCurrent = 0;
+ CHNUM chnEnd = 0;
+ PWSTRING Lexeme;
+ PWSTRING Pattern;
+ CHNUM chn;
+
+
+ if (!(Lexeme = ArgumentLexemizer->GetLexemeAt( ArgumentLexemizer->QueryConsumedCount()))) {
+ return FALSE;
+ }
+
+ Pattern = Argument->GetPattern();
+
+ fFound = FALSE;
+
+ //
+ // If first character in the pattern is a switch, see if the
+ // first character in the Lexeme is also a switch.
+ //
+ if ( Pattern->QueryChCount() > 0 &&
+ Lexeme->QueryChCount() > 0 &&
+ ArgumentLexemizer->GetSwitches()->Strchr( Pattern->QueryChAt(0)) != INVALID_CHNUM ) {
+
+ if ( ArgumentLexemizer->GetSwitches()->Strchr( Lexeme->QueryChAt(0)) != INVALID_CHNUM ) {
+ //
+ // Switch, advance pointer
+ //
+ chn = 1;
+
+ } else {
+ //
+ // No switch, no match
+ //
+ return FALSE;
+ }
+
+ } else {
+ //
+ // This is not a switch pattern, match from the beginning
+ //
+ chn = 0;
+ }
+
+ for ( ; ; chn++ ) {
+
+ switch( Pattern->QueryChAt( chn ) ) {
+
+ case (WCHAR)'#':
+
+ //
+ // Optional space between flag and argument
+ //
+ if ( Lexeme->QueryChAt( chn ) == INVALID_CHAR ) {
+
+ //
+ // At the end of the Argument string. Must get the next.
+ //
+ ArgumentLexemizer->IncrementConsumedCount();
+ Lexeme = ArgumentLexemizer->GetLexemeAt( ArgumentLexemizer->QueryConsumedCount() );
+
+ if (!Lexeme) {
+ goto FAIL;
+ }
+
+ chn = 0;
+
+ }
+
+ chnCurrent = chn;
+ chnEnd = Lexeme->QueryChCount();
+ fFound = TRUE;
+ break;
+
+
+ case (WCHAR)'*':
+
+ //
+ // No space allowed between flag and argument
+ //
+ if ( !(Lexeme->QueryChAt( chn )) ||
+ !(TailMatch( Pattern, Lexeme, chn, &chnEnd, CaseSensitive ))) {
+
+ goto FAIL;
+ }
+
+ chnCurrent = chn;
+ fFound = TRUE;
+ break;
+
+
+ case INVALID_CHAR:
+
+ //
+ // Space required beteen flag and argument
+ //
+ if( Lexeme->QueryChAt( chn ) != INVALID_CHAR) {
+ goto FAIL;
+
+ }
+
+ Lexeme = ArgumentLexemizer->GetLexemeAt( ArgumentLexemizer->QueryConsumedCount() );
+ ArgumentLexemizer->IncrementConsumedCount();
+ fFound = TRUE;
+ chnEnd++;
+ break;
+
+
+
+ default:
+
+ if ( CASESENS(Lexeme->QueryChAt( chn )) != CASESENS(Pattern->QueryChAt( chn )) ) {
+ goto FAIL;
+ }
+ chnEnd++;
+ }
+
+ if (fFound) {
+ break;
+ }
+
+ }
+
+ //
+ // The patterns matched, see if the argument is recognized.
+ //
+ if (Argument->SetValue( Lexeme, chnCurrent, chnEnd, ArgumentLexemizer ) == FALSE ) {
+ goto FAIL;
+ }
+
+ //DELETE( Lexeme );
+
+ return TRUE;
+
+FAIL:
+ //DELETE( Lexeme );
+ return FALSE;
+}
+
+
+STATIC
+BOOLEAN
+TailMatch(
+ IN PWSTRING Pattern,
+ IN PWSTRING String,
+ IN CHNUM chn,
+ OUT PCHNUM chnEnd,
+ IN BOOLEAN CaseSensitive
+ )
+/*++
+
+Routine Description:
+
+ Performs tailmatching of a pattern and a string
+
+Arguments:
+
+ Pattern - Supplies pointer to pattern
+ String - Supplies pointer to string
+ chn - Supplies index of current char
+ chnEnd - Supplies pointer to index of first character to
+ match in tail;
+ CaseSensitive - Supplies case sensitivity flag
+
+Return Value:
+
+ TRUE if match
+ FALSE otherwise
+
+--*/
+{
+ CHNUM PatternIndex;
+ CHNUM StringIndex;
+
+ PatternIndex = Pattern->QueryChCount() - 1;
+ StringIndex = String->QueryChCount() - 1;
+
+
+ if (chn == PatternIndex) {
+
+ //
+ // wild card is the last thing in the format, it matches.
+ //
+ *chnEnd = StringIndex + 1 ;
+ return TRUE;
+ }
+
+ //
+ // Check characters walking towards front
+ //
+ while( CASESENS(Pattern->QueryChAt(PatternIndex)) == CASESENS(String->QueryChAt(StringIndex)) ) {
+
+ if ( chn == PatternIndex ) {
+ break;
+ }
+
+ PatternIndex--;
+ StringIndex--;
+
+ }
+
+ //
+ // If we're back at the beginning of the Pattern and the string is
+ // either at the beginning or somewhere inside then we have a match.
+ //
+ *chnEnd = StringIndex + 1;
+
+ return( (PatternIndex == chn ) && ( StringIndex != INVALID_CHNUM ) );
+}
+
+
+#if !defined( _AUTOCHECK_ )
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( REST_OF_LINE_ARGUMENT, ARGUMENT, ULIB_EXPORT );
+
+ULIB_EXPORT
+BOOLEAN
+REST_OF_LINE_ARGUMENT::Initialize(
+ )
+{
+ return ARGUMENT::Initialize("*");
+}
+
+BOOLEAN
+REST_OF_LINE_ARGUMENT::SetIfMatch(
+ IN OUT PARGUMENT_LEXEMIZER ArgumentLexemizer,
+ IN BOOLEAN CaseSensitive
+ )
+/*++
+
+Routine Description:
+
+ This routine computes whether or not the current state of the argument lexemizer
+ lends itself to a MACRO argument as described by DOS 5's DOSKEY function. If the
+ current state of the argument lexemizer is indeed in such a state then this routine
+ will grab all of the remaining tokens on the line and copy the contents of the
+ command line from the current token to the end of the line in this class's argument.
+
+Arguments:
+
+ ArgumentLexemizer - Supplies the argument lexemizer.
+ CaseSensitive - Supplies whether or not to distinguish letters based solely on case.
+
+Return Value:
+
+ FALSE - argument not recognized and/or value not set.
+ TRUE - argument recognized and value set.
+
+--*/
+{
+ CHNUM char_pos;
+ ULONG consumed_count;
+
+ consumed_count = ArgumentLexemizer->QueryConsumedCount();
+ char_pos = ArgumentLexemizer->QueryCharPos(consumed_count);
+
+ if (!_RestOfLine.Initialize(ArgumentLexemizer->GetCmdLine(), char_pos)) {
+ _fValueSet = FALSE;
+ return FALSE;
+ }
+
+
+ // Consume all of the remaining tokens.
+
+ ArgumentLexemizer->IncrementConsumedCount(
+ ArgumentLexemizer->QueryLexemeCount() - consumed_count);
+
+ _fValueSet = TRUE;
+
+ return TRUE;
+}
+
+
+#endif // _AUTOCHECK_
+
diff --git a/private/utils/ulib/src/array.cxx b/private/utils/ulib/src/array.cxx
new file mode 100644
index 000000000..ffec5c745
--- /dev/null
+++ b/private/utils/ulib/src/array.cxx
@@ -0,0 +1,760 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ array.cxx
+
+Abstract:
+
+ This module contains the definition for the ARRAY class. ARRAY is a
+ concrete implementation of a SORTABLE_CONTAINER. It extends the interface
+ to allow for easy access uswing a simple ULONG as an index. It is
+ dynamically growable and supports bases other than zero.
+
+Author:
+
+ David J. Gilman (davegi) 02-Nov-1990
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "array.hxx"
+#include "arrayit.hxx"
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( ARRAY, SORTABLE_CONTAINER, ULIB_EXPORT );
+
+DEFINE_CAST_MEMBER_FUNCTION( ARRAY );
+
+VOID
+ARRAY::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Construct an ARRAY by setting the initial value of of the OBJECT array
+ pointer to NULL.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _ObjectArray = NULL;
+}
+
+
+
+
+
+ULIB_EXPORT
+ARRAY::~ARRAY (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy an ARRAY by freeing it's internal storage. Note that this
+ deletes the array, not the objects themselves.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if ( _ObjectArray ) {
+ FREE( _ObjectArray );
+ }
+}
+
+
+
+ULIB_EXPORT
+BOOLEAN
+ARRAY::Initialize (
+ IN ULONG Capacity,
+ IN ULONG CapacityIncrement
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize an ARRAY object by setting it's internal state to supplied
+ or default values. In addition allocate an initial chunk of memory for
+ the actual storage of POBJECTs.
+
+Arguments:
+
+ Capacity - Supplies the total number of OBJECTs the ARRAY
+ can contain
+ CapacityIncrement - Supplies the number of OBJECTs to make room for
+ when growing the ARRAY
+
+Return Value:
+
+ BOOLEAN - TRUE if the ARRAY is successfully initialized.
+
+--*/
+
+{
+ DebugAssert( Capacity != 0 );
+
+ //
+ // If re-initializing, se reuse the current array
+ //
+ if ( _ObjectArray ) {
+ _Capacity = SetArrayCapacity( Capacity );
+ } else {
+ _ObjectArray = (PPOBJECT)CALLOC( (UINT)Capacity,
+ sizeof( POBJECT ) );
+ _Capacity = Capacity;
+ }
+
+ _CapacityIncrement = CapacityIncrement;
+ _PutIndex = 0;
+
+#if DBG==1
+ _IteratorCount = 0;
+#endif
+
+ if ( _ObjectArray ) {
+ DebugCheckHeap();
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+ULIB_EXPORT
+BOOLEAN
+ARRAY::DeleteAllMembers (
+ )
+
+/*++
+
+Routine Description:
+
+ Deletes all the members of the array
+
+Arguments:
+
+ None
+
+Return Value:
+
+ BOOLEAN - TRUE if all members deleted
+
+--*/
+
+{
+ PPOBJECT PObject;
+
+ if ( _PutIndex > 0 ) {
+
+#if 0 // Bogus assert due to compiler error. Put it back in when compiler fixed
+#if DBG==1
+ DebugAssert( _IteratorCount == 0 );
+#endif
+#endif
+
+ PObject = &_ObjectArray[ _PutIndex - 1 ];
+
+ while ( PObject >= _ObjectArray ) {
+ DELETE( *PObject );
+ PObject--;
+ }
+
+ _PutIndex = 0;
+ }
+
+ return TRUE;
+}
+
+
+
+
+POBJECT
+ARRAY::GetAt (
+ IN ULONG Index
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Retrieves the OBJECT at the specified Index.
+
+Arguments:
+
+ Index - Supplies the index of the OBJECT in question.
+
+Return Value:
+
+ POBJECT - A constant pointer to the requested OBJECT.
+
+--*/
+
+{
+ DebugPtrAssert( _ObjectArray );
+
+ if ( (_PutIndex > 0) && (Index < _PutIndex) ) {
+ return _ObjectArray[ Index ];
+ } else {
+ return NULL;
+ }
+}
+
+
+
+ULONG
+ARRAY::GetMemberIndex (
+ IN POBJECT Object
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the position (index) of an object in the array.
+
+Arguments:
+
+ POBJECT - Pointer to the OBJECT in question.
+
+Return Value:
+
+ ULONG - The position of the OBJECT in the array. If the OBJECT is not
+ in the array, returns INVALID_INDEX.
+
+--*/
+
+{
+ ULONG Index;
+
+ DebugPtrAssert( _ObjectArray );
+ DebugPtrAssert( Object );
+
+ if( Object == NULL ) {
+ return( INVALID_INDEX );
+ }
+
+ Index = 0;
+ while( ( Index < QueryMemberCount() ) &&
+ ( _ObjectArray[ Index ] != Object ) ) {
+ Index++;
+ }
+ return( ( Index < QueryMemberCount() )? Index : INVALID_INDEX );
+}
+
+
+
+ULIB_EXPORT
+BOOLEAN
+ARRAY::Put (
+ IN OUT POBJECT Member
+ )
+
+/*++
+
+Routine Description:
+
+ Puts an OBJECT at the next available location in the array.
+
+Arguments:
+
+ Member - Supplies the OBJECT to place in the array
+
+Return Value:
+
+ BOOLEAN - TRUE if member put, FALSE otherwise
+
+--*/
+
+{
+ DebugPtrAssert( Member );
+ DebugPtrAssert( _PutIndex <= _Capacity );
+
+ //
+ // Grow the array if necessary
+ //
+ if ( _PutIndex >= _Capacity ) {
+ if ( _PutIndex >= SetArrayCapacity( _Capacity + _CapacityIncrement ) ) {
+ //
+ // Could not grow the array
+ //
+
+ return FALSE;
+ }
+ }
+
+ _ObjectArray[ _PutIndex++ ] = Member;
+
+ return TRUE;
+
+}
+
+
+
+BOOLEAN
+ARRAY::PutAt (
+ IN OUT POBJECT Member,
+ IN ULONG Index
+ )
+
+/*++
+
+Routine Description:
+
+ Puts an OBJECT at a particular location in the ARRAY.
+ The new object has to replace an existing object, i.e. the
+ index has to be smaller than the member count.
+
+Arguments:
+
+ Member - Supplies the OBJECT to place in the ARRAY
+ Index - Supplies the index where the member is to be put
+
+Return Value:
+
+ BOOLEAN - TRUE if member put, FALSE otherwise
+
+
+--*/
+
+{
+ DebugPtrAssert( Member );
+ DebugPtrAssert( Index < _PutIndex );
+
+ if ( Index < _PutIndex ) {
+ _ObjectArray[ Index ] = Member;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+ULIB_EXPORT
+PITERATOR
+ARRAY::QueryIterator (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Create an ARRAY_ITERATOR object for this ARRAY.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PITERATOR - Pointer to an ITERATOR object.
+
+--*/
+
+{
+ PARRAY_ITERATOR Iterator;
+
+ //
+ // Create new iterator
+ //
+ if ( Iterator = NEW ARRAY_ITERATOR ) {
+
+ //
+ // Initialize the iterator
+ //
+ if ( !Iterator->Initialize( (PARRAY)this ) ) {
+ DELETE( Iterator );
+ }
+ }
+
+ return Iterator;
+}
+
+
+
+ULONG
+ARRAY::QueryMemberCount (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Obtains the number of elements in the array
+
+Arguments:
+
+ None
+
+Return Value:
+
+ ULONG - The number of members in the array
+
+
+--*/
+
+{
+ return _PutIndex;
+}
+
+
+ULIB_EXPORT
+POBJECT
+ARRAY::Remove (
+ IN OUT PITERATOR Position
+ )
+
+/*++
+
+Routine Description:
+
+ Removes a member from the array
+
+Arguments:
+
+ Position - Supplies an iterator whose currency is to be removed
+
+Return Value:
+
+ POBJECT - The object removed
+
+
+--*/
+
+{
+ PARRAY_ITERATOR Iterator;
+
+ DebugPtrAssert( Position );
+ DebugPtrAssert( ARRAY_ITERATOR::Cast( Position ));
+
+ Iterator = (PARRAY_ITERATOR)Position;
+
+ return RemoveAt( Iterator->QueryCurrentIndex() );
+}
+
+
+POBJECT
+ARRAY::RemoveAt (
+ IN ULONG Index
+ )
+
+/*++
+
+Routine Description:
+
+ Removes a member from the array
+
+Arguments:
+
+ Index - Supplies the index of the member to be removed
+
+Return Value:
+
+ POBJECT - The object removed
+
+
+--*/
+
+{
+ POBJECT Object = NULL;
+
+ if ( Index < _PutIndex ) {
+
+ // DebugAssert( _IteratorCount <= 1 );
+
+ //
+ // Get the object
+ //
+ Object = (POBJECT)_ObjectArray[ Index ];
+
+ //
+ // Shift the rest of the array
+ //
+ memmove ( &_ObjectArray[ Index ],
+ &_ObjectArray[ Index + 1 ],
+ (UINT)(_PutIndex - Index - 1) * sizeof( POBJECT ) );
+
+ //
+ // Update the _PutIndex
+ //
+ _PutIndex--;
+
+ }
+
+ return Object;
+}
+
+
+
+ULONG
+ARRAY::SetCapacity (
+ IN ULONG Capacity
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the capacity of the array. Will not shrink the array if the
+ capacity indicated is less than the number of members in the array.
+
+Arguments:
+
+ Capacity - New capacity of the array
+
+Return Value:
+
+ ULONG - The new capacity of the array
+
+
+--*/
+
+{
+ if ( Capacity >= _PutIndex ) {
+
+ SetArrayCapacity( Capacity );
+
+ }
+
+ return _Capacity;
+}
+
+
+BOOLEAN
+ARRAY::Sort (
+ IN BOOLEAN Ascending
+ )
+
+/*++
+
+Routine Description:
+
+ Sorts the array
+
+Arguments:
+
+ Ascending - Supplies ascending flag
+
+Return Value:
+
+ BOOLEAN - TRUE if array sorted, FALSE otherwise
+
+
+--*/
+
+{
+ int (_CRTAPI1 *CompareFunction)(const void *, const void*);
+
+ CompareFunction = Ascending ?
+ &ARRAY::CompareAscending :
+ &ARRAY::CompareDescending;
+
+ qsort( _ObjectArray,
+ (size_t)_PutIndex,
+ sizeof(POBJECT),
+ CompareFunction );
+
+ return TRUE;
+}
+
+
+BOOLEAN
+ARRAY::Insert(
+ IN OUT POBJECT Member,
+ IN ULONG Index
+ )
+/*++
+
+Routine Description:
+
+ Inserts an element in the array at the specified position, shifting
+ elements to the right if necessary.
+
+Arguments:
+
+ Member - Supplies pointer to object to be inserted in the array
+
+ Index - Supplies the index where the element is to be put
+
+Return Value:
+
+ BOOLEAN - TRUE if new element inserted, FALSE otherwise
+
+
+--*/
+
+{
+ DebugPtrAssert( Member );
+ DebugPtrAssert( Index <= _PutIndex );
+
+ //
+ // Make sure that there will be enough space in the array for the
+ // new element
+ //
+ if ( _PutIndex >= _Capacity ) {
+
+ if ( _PutIndex >= SetArrayCapacity( _Capacity + _CapacityIncrement ) ) {
+ //
+ // Could not grow the array
+ //
+ return FALSE;
+ }
+ }
+
+ //
+ // If required, shift the array to the right to make space for the
+ // new element.
+ //
+ if ( Index < _PutIndex ) {
+
+ memmove ( &_ObjectArray[ Index + 1 ],
+ &_ObjectArray[ Index ],
+ (UINT)( _PutIndex - Index ) * sizeof( POBJECT ) );
+ }
+
+ //
+ // Insert the element
+ //
+ _ObjectArray[ Index ] = Member;
+
+ //
+ // Increment the number of elements in the array
+ //
+ _PutIndex++;
+
+ return TRUE;
+}
+
+
+
+ULONG
+ARRAY::SetArrayCapacity (
+ IN ULONG NumberOfElements
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the capacity of the array. Allways reallocs the array.
+
+Arguments:
+
+ NewSize - New capacity of the array
+
+Return Value:
+
+ ULONG - The new capacity of the array
+
+
+--*/
+
+{
+ PPOBJECT Tmp;
+
+ Tmp = (PPOBJECT)REALLOC( _ObjectArray,
+ (UINT)NumberOfElements * sizeof(POBJECT) );
+
+ if ( Tmp ) {
+ _ObjectArray = Tmp;
+ _Capacity = NumberOfElements;
+ }
+
+ return _Capacity;
+}
+
+
+int _CRTAPI1
+ARRAY::CompareAscending (
+ IN const void * Object1,
+ IN const void * Object2
+ )
+
+/*++
+
+Routine Description:
+
+ Compares two objects.
+
+Arguments:
+
+ Object1 - Supplies pointer to first object
+ Object2 - Supplies pointer to second object
+
+Return Value:
+
+ Returns:
+
+ <0 if Object1 is less that Object2
+ 0 if Object1 is equal to Object2
+ >0 if Object1 is greater than Object2
+
+
+--*/
+
+{
+ return (*(POBJECT *)Object1)->Compare( *(POBJECT *)Object2 );
+}
+
+
+
+int _CRTAPI1
+ARRAY::CompareDescending (
+ IN const void * Object1,
+ IN const void * Object2
+ )
+
+/*++
+
+Routine Description:
+
+ Compares two objects
+
+Arguments:
+
+ Object1 - Supplies pointer to first object
+ Object2 - Supplies pointer to second object
+
+Return Value:
+
+ Returns:
+
+ <0 if Object2 is less that Object1
+ 0 if Object2 is equal to Object1
+ >0 if Object2 is greater than Object1
+
+--*/
+
+{
+ return (*(POBJECT *)Object2)->Compare( *(POBJECT *)Object1 );
+}
diff --git a/private/utils/ulib/src/arrayit.cxx b/private/utils/ulib/src/arrayit.cxx
new file mode 100644
index 000000000..dc51c73c9
--- /dev/null
+++ b/private/utils/ulib/src/arrayit.cxx
@@ -0,0 +1,261 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ arrayit.cxx
+
+Abstract:
+
+ This file contains the definitions for the ARRAY_ITERATOR class.
+ ARRAY_ITERATOR is a concrete implementation of the abstract ITERATOR
+ class.
+
+Author:
+
+ David J. Gilman (davegi) 03-Dec-1990
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "array.hxx"
+#include "arrayit.hxx"
+
+
+DEFINE_CAST_MEMBER_FUNCTION( ARRAY_ITERATOR );
+
+DEFINE_CONSTRUCTOR( ARRAY_ITERATOR, ITERATOR );
+
+
+VOID
+ARRAY_ITERATOR::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Construct an ARRAY_ITERATOR by setting it's current index to 0 and it's
+ associated ARRAY to NULL.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _Array = NULL;
+}
+
+
+
+ARRAY_ITERATOR::~ARRAY_ITERATOR (
+ )
+/*++
+
+Routine Description:
+
+ Destructor for the ARRAY_ITERATOR class
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+#if DBG==1
+ if ( _Array ) {
+ _Array->_IteratorCount--;
+ }
+#endif
+}
+
+
+
+
+VOID
+ARRAY_ITERATOR::Reset(
+ )
+
+/*++
+
+Routine Description:
+
+ Resets the iterator
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ _CurrentIndex = INVALID_INDEX;
+}
+
+
+
+POBJECT
+ARRAY_ITERATOR::GetCurrent(
+ )
+/*++
+
+Routine Description:
+
+ Gets current member
+
+Arguments:
+
+ None
+
+Return Value:
+
+ POBJECT - Pointer to current member in the array
+
+--*/
+
+{
+ if ( _CurrentIndex == INVALID_INDEX ) {
+ return NULL;
+ } else {
+ return _Array->GetAt( _CurrentIndex );
+ }
+}
+
+
+
+
+POBJECT
+ARRAY_ITERATOR::GetNext(
+ )
+/*++
+
+Routine Description:
+
+ Gets next member in the array
+
+Arguments:
+
+ None
+
+Return Value:
+
+ POBJECT - Pointer to next member in the array
+
+--*/
+
+{
+ //
+ // Wrap if necessary. Note that this assumes that INVALID_INDEX + 1 == 0
+ //
+ _CurrentIndex++;
+
+ if ( _CurrentIndex >= _Array->QueryMemberCount() ) {
+ _CurrentIndex = INVALID_INDEX;
+ }
+
+ //
+ // Get next
+ //
+ return _Array->GetAt( _CurrentIndex );
+}
+
+
+POBJECT
+ARRAY_ITERATOR::GetPrevious(
+ )
+/*++
+
+Routine Description:
+
+ Gets previous member in the array
+
+Arguments:
+
+ None
+
+Return Value:
+
+ POBJECT - Pointer to previous member in the array
+
+--*/
+
+{
+ //
+ // Wrap if necessary. Note that this assumes that 0 - 1 == INVALID_INDEX
+ //
+
+ if ( _CurrentIndex == INVALID_INDEX ) {
+ _CurrentIndex = _Array->QueryMemberCount() - 1;
+ } else {
+ _CurrentIndex--;
+ }
+
+ //
+ // Get next
+ //
+ return _Array->GetAt( _CurrentIndex );
+}
+
+
+
+
+BOOLEAN
+ARRAY_ITERATOR::Initialize (
+ IN PARRAY Array
+ )
+
+/*++
+
+Routine Description:
+
+ Associate an ARRAY with this ARRAY_ITERATOR and reset the current index
+
+Arguments:
+
+ Array - Supplies pointer to the array object
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the initialization was succesful.
+
+--*/
+
+{
+ DebugPtrAssert( Array );
+
+#if DBG==1
+ if ( _Array ) {
+ _Array->_IteratorCount--;
+ }
+ Array->_IteratorCount++;
+#endif
+ _Array = Array;
+ _CurrentIndex = INVALID_INDEX;
+
+
+ return TRUE;
+}
diff --git a/private/utils/ulib/src/basesys.cxx b/private/utils/ulib/src/basesys.cxx
new file mode 100644
index 000000000..e78b2b71f
--- /dev/null
+++ b/private/utils/ulib/src/basesys.cxx
@@ -0,0 +1,249 @@
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+#include "ulib.hxx"
+#include "basesys.hxx"
+
+extern "C" {
+ #include <stdio.h>
+#if defined( _AUTOCHECK_ )
+
+//
+// This stuff is lifted from winuser.h, because with _AUTOCHECK_ we
+// shouldn't include windows header files.
+//
+
+#define MAKEINTRESOURCEW(i) (LPWSTR)((ULONG)((USHORT)(i)))
+#define MAKEINTRESOURCE MAKEINTRESOURCEW
+#define RT_MESSAGETABLE MAKEINTRESOURCE(11)
+
+#endif // _AUTOCHECK_
+
+};
+
+ULIB_EXPORT
+BOOLEAN
+BASE_SYSTEM::QueryResourceString(
+ OUT PWSTRING ResourceString,
+ IN MSGID MsgId,
+ IN PCSTR Format ...
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the resource string identified by the resource
+ identifier 'MsgId'. In addition to the 'printf' format strings
+ supported, 'QueryResourceString' supports :
+
+ 1. '%W' - Expects a pointer to a WSTRING.
+
+Arguments:
+
+ ResourceString - Returns the resource string.
+ MsgId - Supplies the message id of the resource string.
+ Format - Supplies a 'printf' style format descriptor for the
+ arguments to the resource string.
+ ... - Supplies the arguments to the resource string.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ va_list ap;
+ BOOLEAN r;
+
+ va_start(ap, Format);
+ r = QueryResourceStringV(ResourceString, MsgId, Format, ap);
+ va_end(ap);
+
+ return r;
+}
+
+STATIC WSTR display_buffer[4096];
+
+
+ULIB_EXPORT
+BOOLEAN
+BASE_SYSTEM::QueryResourceStringV(
+ OUT PWSTRING ResourceString,
+ IN MSGID MsgId,
+ IN PCSTR Format,
+ IN va_list VarPointer
+ )
+/*++
+
+Routine Description:
+
+ This is a 'varargs' implementation of 'QueryResourceString'.
+
+Arguments:
+
+ ResourceString - Returns the resource string.
+ MsgId - Supplies the message id of the resource string.
+ Format - Supplies a 'printf' style format descriptor for the
+ arguments to the resource string.
+ VarPointer - Supplies a varargs pointer to the arguments of the
+ resource string.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ STATIC HANDLE lib_handle = 0;
+ PWSTR args[10];
+ WSTR fmt[20];
+ INT i, j;
+ PWSTR p;
+ PWSTRING gstring;
+ DSTRING UnicodeFormat;
+
+#if !defined( _AUTOCHECK_ )
+ if (!lib_handle) {
+ lib_handle = GetModuleHandle((LPWSTR)L"ulib.dll");
+ DebugAssert(lib_handle);
+ if (!lib_handle) {
+ return FALSE;
+ }
+ }
+
+#else
+ NTSTATUS Status;
+ PMESSAGE_RESOURCE_ENTRY MessageEntry;
+ PWSTR MessageFormat;
+ ULONG Result;
+ ANSI_STRING AnsiString;
+ UNICODE_STRING UnicodeString;
+
+ if (!lib_handle) {
+ lib_handle = (PVOID)NtCurrentPeb()->ImageBaseAddress;
+ DebugAssert(lib_handle);
+ if (!lib_handle) {
+ return FALSE;
+ }
+ }
+#endif
+
+ for (i = 0; i < 10; i++) {
+ args[i] = NULL;
+ }
+
+ if (!UnicodeFormat.Initialize(Format)) {
+ return FALSE;
+ }
+
+ i = 0;
+ for (p = (PWSTR) UnicodeFormat.GetWSTR(); *p; p++) {
+ if (*p == '%') {
+ if (*(p + 1) == 'W') {
+ p++;
+ gstring = va_arg(VarPointer, PWSTRING);
+ gstring->QueryWSTR(0, TO_END, display_buffer, 4096);
+ } else {
+ j = 0;
+ fmt[j++] = *p++;
+ while (*p && *p != '%') {
+ if ((*p == 's' || *p == 'c') && *(p - 1) != 'w') {
+ fmt[j++] = 'h';
+ }
+ fmt[j++] = *p++;
+ }
+ p--;
+ fmt[j] = 0;
+ swprintf(display_buffer, fmt, va_arg(VarPointer, PVOID));
+ }
+ args[i] = (PWSTR)MALLOC(wcslen(display_buffer) * sizeof(WCHAR) +
+ sizeof(WCHAR));
+ if (NULL == args[i]) {
+ return FALSE;
+ }
+ wcscpy( args[i++], display_buffer);
+ }
+ }
+
+#if !defined( _AUTOCHECK_ )
+ FormatMessage(FORMAT_MESSAGE_FROM_HMODULE |
+ FORMAT_MESSAGE_ARGUMENT_ARRAY,
+ (LPVOID)lib_handle,
+ (ULONG)MsgId,
+ 0L,
+ display_buffer,
+ 4096,
+ (va_list *)args);
+
+ for (i = 0; i < 10; i++) {
+ FREE(args[i]);
+ }
+
+ return ResourceString->Initialize(display_buffer);
+
+#else
+ Status = RtlFindMessage( lib_handle,
+ (ULONG)RT_MESSAGETABLE,
+
+#if defined JAPAN // v-junm - 08/03/93
+// The default TEB's value for NT-J is set to 0x411(JP) in the hives. Since
+// we do not want Japanese messages to come out in the boot screen, we have to
+// force autochk.exe to pick up the English text rather than the Japanese.
+//
+// NOTE: This has to be done because the current version of autochk.exe has
+// bilingual messages. It's more efficient to make a US version rather
+// than a bilingual version to save space.
+ 0x409,
+#else
+ 0,
+#endif
+ (ULONG)MsgId,
+ &MessageEntry
+ );
+
+ if (!NT_SUCCESS( Status )) {
+ return FALSE;
+ }
+
+ if (!(MessageEntry->Flags & MESSAGE_RESOURCE_UNICODE)) {
+ RtlInitAnsiString( &AnsiString, (PCSZ)&MessageEntry->Text[ 0 ] );
+ Status = RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, TRUE );
+ if (!NT_SUCCESS( Status )) {
+ return FALSE;
+ }
+
+ MessageFormat = UnicodeString.Buffer;
+ } else {
+ MessageFormat = (PWSTR)MessageEntry->Text;
+ UnicodeString.Buffer = NULL;
+ }
+
+ Status = RtlFormatMessage( MessageFormat,
+ 0,
+ FALSE,
+ FALSE,
+ TRUE,
+ (va_list *)args,
+ (PWSTR)display_buffer,
+ sizeof( display_buffer ),
+ &Result
+ );
+
+ if (UnicodeString.Buffer != NULL) {
+ RtlFreeUnicodeString( &UnicodeString );
+ }
+
+ for (i = 0; i < 10; i++) {
+ FREE(args[i]);
+ }
+
+ if (!NT_SUCCESS( Status )) {
+ return FALSE;
+ }
+
+ return ResourceString->Initialize(display_buffer);
+
+#endif // _AUTOCHECK_
+}
diff --git a/private/utils/ulib/src/bitvect.cxx b/private/utils/ulib/src/bitvect.cxx
new file mode 100644
index 000000000..acda50365
--- /dev/null
+++ b/private/utils/ulib/src/bitvect.cxx
@@ -0,0 +1,595 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ bitvect.cxx
+
+Abstract:
+
+ This module contains the definition for thje BITVECTOR class.
+
+Author:
+
+ David J. Gilman (davegi) 01-Feb-1991
+ Barry Gilhuly (w-barry)
+ Norbert P. Kusters (norbertk)
+
+Environment:
+
+ ULIB, User Mode
+
+[Notes:]
+
+ optional-notes
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "bitvect.hxx"
+#include <limits.h>
+
+//
+// Invalid bit count
+//
+
+CONST PT InvalidBitCount = (PT)(-1);
+
+//
+// Static member data.
+//
+
+//
+// Bits per byte value table e.g. 27->4 bits
+//
+// Algorithm:
+//
+// _BitsSetLookUp[0] = 0;
+//
+// For the ranges [1,1],[2,3],[4,7],[8,15],...,[128,255].
+//
+// for (n = (( PT ) 1 ); n <= 8; n++) {
+//
+//
+// Compute range for loop.
+//
+// r = (( PT ) 1 ) << (n - (( PT ) 1 ));
+//
+//
+// [r, 2*r - 1 ] = [0, r - 1] + 1;
+//
+// for (i = 0; i < r; i++) {
+// _BitsSetLookUp[i + r] = _BitsSetLookUp[i] + (( PT ) 1 );
+// }
+// }
+// }
+//
+
+CONST BYTE BITVECTOR::_BitsSetLookUp[ 256 ] = {
+
+ 0, 1, 1, 2, 1, 2, 2, 3,
+ 1, 2, 2, 3, 2, 3, 3, 4,
+ 1, 2, 2, 3, 2, 3, 3, 4,
+ 2, 3, 3, 4, 3, 4, 4, 5,
+ 1, 2, 2, 3, 2, 3, 3, 4,
+ 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5,
+ 3, 4, 4, 5, 4, 5, 5, 6,
+ 1, 2, 2, 3, 2, 3, 3, 4,
+ 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5,
+ 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5,
+ 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6,
+ 4, 5, 5, 6, 5, 6, 6, 7,
+ 1, 2, 2, 3, 2, 3, 3, 4,
+ 2, 3, 3, 4, 3, 4, 4, 5,
+ 2, 3, 3, 4, 3, 4, 4, 5,
+ 3, 4, 4, 5, 4, 5, 5, 6,
+ 2, 3, 3, 4, 3, 4, 4, 5,
+ 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6,
+ 4, 5, 5, 6, 5, 6, 6, 7,
+ 2, 3, 3, 4, 3, 4, 4, 5,
+ 3, 4, 4, 5, 4, 5, 5, 6,
+ 3, 4, 4, 5, 4, 5, 5, 6,
+ 4, 5, 5, 6, 5, 6, 6, 7,
+ 3, 4, 4, 5, 4, 5, 5, 6,
+ 4, 5, 5, 6, 5, 6, 6, 7,
+ 4, 5, 5, 6, 5, 6, 6, 7,
+ 5, 6, 6, 7, 6, 7, 7, 8
+};
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( BITVECTOR, OBJECT, ULIB_EXPORT );
+
+DEFINE_CAST_MEMBER_FUNCTION( BITVECTOR );
+
+VOID
+BITVECTOR::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Construct a BITVECTOR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ REGISTER PT pt;
+
+ //
+ // Find the number of bits per PTs
+ //
+
+ _BitsPerPT = sizeof( PT ) * CHAR_BIT;
+
+ //
+ // Set the smallest number of PTs needed
+ //
+
+ _PTCount = (( PT ) 1 );
+
+ //
+ // Create the mask used to separate the array index from the bit index
+ //
+
+ _BitPositionMask = _BitsPerPT - (( PT ) 1 );
+
+ //
+ // Count the number of bits required to make the shift count for
+ // accessing the Primitive Type.
+ //
+
+ for( _IndexShiftCount = 0, pt = _BitPositionMask; pt;
+ pt >>= (( PT ) 1 ), _IndexShiftCount++ );
+
+ //
+ // Initialize BITVECTOR state.
+ //
+
+ _BitVector = NULL;
+ _PTCount = 0;
+ _FreeBitVector = FALSE;
+}
+
+ULIB_EXPORT
+BOOLEAN
+BITVECTOR::Initialize (
+ IN PT Size,
+ IN BIT InitialValue,
+ IN PPT Memory
+ )
+
+/*++
+
+Routine Description:
+
+ Construct a BITVECTOR with at least the size specified and
+ initialize all bits to SET or RESET.
+
+Arguments:
+
+ Size - Supplies the number of bits in the vector
+ InitialValue - Supplies the initial value for the bits
+ Memory - Supplies a memory buffer to use for the vector
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the BITVECTOR was succesfully initialized.
+
+Notes:
+
+ Minimum and default BITVECTOR size is the number of bits in
+ one PT. Default initializer is RESET. The size of a BITVECTOR
+ is rounded up to the nearest whole multiple of (_BitsPerPT * CHAR_BIT).
+
+ If the client supplies the buffer it is the client's responsibility
+ to ensure that Size and the size of the buffer are in sync.
+ Also SetSize will not change the size of a client supplied
+ buffer.
+
+--*/
+
+{
+ //
+ // Destroy the internals of a previous BITVECTOR.
+ //
+
+ Destroy( );
+
+ //
+ // Find the number of PTs that will be required for this BITVECTOR
+ // (handles smallest size case (Size = 0) ).
+ //
+
+ _PTCount = Size ? (( Size + _BitsPerPT - (( PT ) 1 )) / _BitsPerPT ) : (( PT ) 1 );
+
+ //
+ // If Memory was supplied use that for the vector else allocate
+ // the vector.
+ //
+
+ if( Memory ) {
+
+ _BitVector = Memory;
+
+ } else {
+ _FreeBitVector = TRUE;
+ if( !( _BitVector = ( PT* ) MALLOC(( size_t ) ( _PTCount * sizeof( PT ))))) {
+
+ return FALSE;
+ }
+ }
+
+ //
+ // Set the bitvector to the supplied value ( SET | RESET )
+ //
+
+ ( InitialValue == SET ) ? SetAll( ) : ResetAll( );
+
+ return TRUE;
+}
+
+ULIB_EXPORT
+BITVECTOR::~BITVECTOR (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy a BITVECTOR by calling it's Destroy function.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ Destroy( );
+}
+
+VOID
+BITVECTOR::Destroy (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy a BITVECTOR by possibly freeing it's internal storage.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if( _FreeBitVector ) {
+
+ DebugAssert( _BitVector != NULL );
+ FREE( _BitVector );
+ }
+}
+
+ULIB_EXPORT
+PT
+BITVECTOR::SetSize (
+ IN PT Size,
+ IN BIT InitialValue
+ )
+
+/*++
+
+Routine Description:
+
+ Set the number of bits in the vector
+
+Arguments:
+
+ Size - Supplies the number of bits to set the vector size to
+ InitialValue- Supplies the initial value for the bits
+
+Return Value:
+
+ PT - Returns the new size of this BITVECTOR in bits.
+
+Notes:
+
+ SetSize will merrily truncate the vector with no warning.
+
+ Minimum and default BITVECTOR size is the number of bits in
+ one PT. Default initializer is RESET. The size of a BITVECTOR
+ is rounded up to the nearest whole multiple of (_BitsPerPT * CHAR_BIT).
+
+ If the client supplied the buffer refuse to change it's size
+
+--*/
+
+{
+ REGISTER PT PTCountNew;
+ PT cbitsNew;
+ PT cbitsOld;
+
+ //
+ // Check that the bitvector was created...
+ //
+
+ DebugPtrAssert( _BitVector );
+ if( _BitVector == NULL ) {
+ return( 0 );
+ }
+
+ //
+ // If the client supplied the buffer, refuse to change it's size.
+ //
+
+ if( ! _FreeBitVector ) {
+ return( _PTCount * _BitsPerPT );
+ }
+
+
+ //
+ // Compute the number of PTs and bits required for the new size
+ //
+
+ PTCountNew = Size ? (( Size + _BitsPerPT - (( PT ) 1 ) ) / _BitsPerPT ) : (( PT ) 1 );
+ cbitsNew = PTCountNew * _BitsPerPT;
+
+ if( PTCountNew != _PTCount ) {
+
+ //
+ // The new size requires a different number of PTs then the old
+ //
+
+ if( !( _BitVector = ( PT* ) REALLOC(( VOID* ) _BitVector,
+ ( size_t ) ( PTCountNew * sizeof( PT ))))) {
+
+ return( 0 );
+ }
+ }
+
+ //
+ // If the new size contains more bits, initialize them to the supplied
+ // value
+ //
+
+ cbitsOld = _PTCount * _BitsPerPT;
+ _PTCount = PTCountNew;
+
+ if( cbitsNew > cbitsOld ) {
+ if( InitialValue == SET ) {
+ SetBit( cbitsOld, cbitsNew - cbitsOld );
+ } else {
+ ResetBit( cbitsOld, cbitsNew - cbitsOld );
+ }
+ }
+
+ return( _PTCount * _BitsPerPT );
+}
+
+ULIB_EXPORT
+VOID
+BITVECTOR::SetBit (
+ IN PT Index,
+ IN PT Count
+ )
+
+/*++
+
+Routine Description:
+
+ SET the supplied range of bits
+
+Arguments:
+
+ Index - Supplies the index at which to start setting bits.
+ Count - Supplies the number of bits to set.
+
+Return Value:
+
+ None.
+
+Notes:
+
+ It may be faster to compute masks for setting sub-ranges.
+
+--*/
+
+{
+ REGISTER PT ptCurBit;
+
+ DebugAssert( _BitVector != NULL );
+ DebugAssert(( Index + Count ) <= ( _PTCount * _BitsPerPT ));
+
+ // Set count to be the max instead.
+ Count += Index;
+
+ for (ptCurBit = Index; (ptCurBit < Count) &&
+ (ptCurBit & _BitPositionMask); ptCurBit++) {
+ _BitVector[ptCurBit >> _IndexShiftCount] |=
+ (1 << (ptCurBit & _BitPositionMask));
+ }
+
+ for (; ptCurBit + 8*sizeof(PT) <= Count; ptCurBit += 8*sizeof(PT)) {
+ _BitVector[ptCurBit >> _IndexShiftCount] = 0xffffffff;
+ }
+
+ for (; ptCurBit < Count; ptCurBit++) {
+ _BitVector[ptCurBit >> _IndexShiftCount] |=
+ (1 << (ptCurBit & _BitPositionMask));
+ }
+}
+
+ULIB_EXPORT
+VOID
+BITVECTOR::ResetBit (
+ IN PT Index,
+ IN PT Count
+ )
+
+/*++
+
+Routine Description:
+
+ RESET the supplied range of bits
+
+Arguments:
+
+ Index - Supplies the index at which to start resetting bits.
+ Count - Supplies the number of bits to reset.
+
+Return Value:
+
+ None.
+
+Notes:
+
+ It may be faster to compute masks for resetting sub-ranges.
+
+--*/
+
+{
+ REGISTER PT ptCurBit;
+
+ DebugAssert( _BitVector != NULL );
+ DebugAssert(( Index + Count ) <= ( _PTCount * _BitsPerPT ));
+
+ // Set count to be the max instead.
+ Count += Index;
+
+ for (ptCurBit = Index; (ptCurBit < Count) &&
+ (ptCurBit & _BitPositionMask); ptCurBit++) {
+ _BitVector[ptCurBit >> _IndexShiftCount] &=
+ ~(1 << (ptCurBit & _BitPositionMask));
+ }
+
+ for (; ptCurBit + 8*sizeof(PT) <= Count; ptCurBit += 8*sizeof(PT)) {
+ _BitVector[ptCurBit >> _IndexShiftCount] = 0;
+ }
+
+ for (; ptCurBit < Count; ptCurBit++) {
+ _BitVector[ptCurBit >> _IndexShiftCount] &=
+ ~(1 << (ptCurBit & _BitPositionMask));
+ }
+}
+
+VOID
+BITVECTOR::ToggleBit (
+ IN PT Index,
+ IN PT Count
+ )
+
+/*++
+
+Routine Description:
+
+ Toggle the supplied range of bits.
+
+Arguments:
+
+ Index - Supplies the index at which to start toggling bits.
+ Count - Supplies the number of bits to toggle.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ REGISTER PT ptCurBit;
+
+ DebugAssert( _BitVector != NULL );
+ DebugAssert( Index + Count <= _PTCount * _BitsPerPT);
+
+ while( Count-- ) {
+ ptCurBit = Index + Count;
+ if( IsBitSet( ptCurBit )) {
+ ResetBit( ptCurBit );
+ } else {
+ SetBit( ptCurBit );
+ }
+ }
+}
+
+ULIB_EXPORT
+PT
+BITVECTOR::ComputeCountSet(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Compute the number of bits that are set in the bitvector using a table
+ look up.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PT - Returns the number of set bits.
+
+--*/
+
+{
+ REGISTER PCBYTE pbBV;
+ REGISTER PT i;
+ REGISTER PT BitsSet;
+
+ //
+ // Cast the bitvector into a string of bytes.
+ //
+
+ pbBV = ( PCBYTE ) _BitVector;
+
+ //
+ // Initialize the count to zero.
+ //
+
+ BitsSet = 0;
+
+ //
+ // For all of the bytes in the bitvector.
+ //
+
+ for (i = 0; i < _PTCount * sizeof( PT ); i++) {
+
+ //
+ // Add the number of bits set in this byte to the total.
+ //
+
+ BitsSet += _BitsSetLookUp[pbBV[ i ]];
+ }
+
+ return( BitsSet );
+}
diff --git a/private/utils/ulib/src/buffer.cxx b/private/utils/ulib/src/buffer.cxx
new file mode 100644
index 000000000..51ecf5d9a
--- /dev/null
+++ b/private/utils/ulib/src/buffer.cxx
@@ -0,0 +1,457 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ buffer.cxx
+
+Abstract:
+
+ This contains all buffer class definition.
+ Buffers do not have implicit terminations. Sizes on construction
+ should include any termination bytes.
+
+Author:
+
+ steve rowe stever 27-Nov-90
+
+Environment:
+
+ ULIB, User Mode
+
+Notes:
+
+
+
+Revision History:
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "buffer.hxx"
+
+#if defined( __BCPLUSPLUS__ )
+
+ #include <mem.h>
+#else
+
+ extern "C" {
+ #include <memory.h>
+ };
+
+#endif // __BCPLUSPLUS__
+
+//
+// _ThresHold is the constant used by ReAllocate to determine when
+// to actually call realloc to shrink the buffer.
+//
+
+ULONG BUFFER::_ThresHold = 129;
+
+DEFINE_CONSTRUCTOR( BUFFER, OBJECT );
+
+VOID
+BUFFER::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Construct a BUFFER by initializing it's internal state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ cb = 0;
+ _BufSize = 0;
+ pBuffer = NULL;
+}
+
+BUFFER::~BUFFER (
+ )
+
+/*++
+
+Routine Description:
+
+ Destructor for general buffer class
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if( pBuffer ) {
+ FREE(pBuffer);
+ }
+}
+
+BOOLEAN
+BUFFER::BuffCat (
+ IN PCBUFFER Buffer2
+ )
+
+/*++
+
+Routine Description:
+
+ Concatenates a buffer with this buffer.
+
+Arguments:
+
+ Buffer2 - Buffer to add to current buffer.
+
+Return Value:
+
+ TRUE - success
+ FALSE - failed to reallocate memory.
+
+--*/
+
+{
+ REGISTER ULONG cbT;
+ PCHAR pTmp;
+
+ // Note W-Barry 11-JUN-91 Needed to add a variable to hold the
+ // current value of cb since the reallocate routine has been changed
+ // to update 'cb' when called...
+ //
+ ULONG CurrentCount;
+
+ cbT = cb + Buffer2->QueryBytesInBuffer();
+ CurrentCount = cb;
+ if ((pTmp = (char *)ReAllocate( cbT )) != NULL) {
+ memcpy( pTmp + CurrentCount, Buffer2->GetBufferPtr(), (size_t)(cbT - CurrentCount) );
+ pBuffer = pTmp;
+ cb = cbT;
+ return( TRUE );
+ }
+ return( FALSE );
+}
+
+BOOLEAN
+BUFFER::BufferCopyAt (
+ IN PCVOID BufferToCopy,
+ IN ULONG cbToCopy,
+ IN ULONG oStart
+ )
+
+/*++
+
+Routine Description:
+
+ Copies a number of bytes from a buffer to a particular location.
+ Note that the total buffer size my increase, it will not decrease.
+ This way replaces can be done. StartingByte can be past end of
+ current buffer. What would lie between end of buffer and
+ startingbyte would be undefined.
+
+ WARNING: BufferToCopy cannot point into this buffer.
+
+Arguments:
+
+ BufferToCopy - Supplies the buffer to copy
+ SizeOfBuffer - Supplies the number of bytes to copy
+
+Return Value:
+
+ ULONG - number of bytes copied.
+ 0 - if error. check error stack.
+
+--*/
+
+{
+
+
+ ULONG cbT;
+ PCHAR pBufferNew;
+
+ //
+ // Enforce warning
+ //
+
+/*** Note davegi What does warning mean?
+
+ DebugAssert(((( PCHAR ) pBuffer + cb ) <= BufferToCopy ) &&
+ ( BufferToCopy < (PCHAR ) pBuffer ));
+
+***/
+ /*
+ Copies to yourself are rare and will fall through the code so
+ no special action is taken.
+
+ Copes of a null will fall through since realloc will free the
+ buffer for a size of 0.
+
+ If the new buffer will fit in the old the size is not reduced to
+ the end of the new buffer. This is to support sub-string replacement.
+ The caller then must be aware of how the copy effects buffer size.
+ */
+
+ cbT = oStart + cbToCopy;
+ pBufferNew = (PCHAR) pBuffer;
+ // will it fit in current buffer
+ if (cb < cbT) {
+ if ((pBufferNew = (char *)ReAllocate( cbT )) != NULL) {
+ cb = cbT;
+ } else {
+ return( FALSE );
+ }
+ }
+
+ memcpy (pBufferNew + oStart, BufferToCopy, (size_t)cbToCopy);
+ pBuffer = pBufferNew;
+ return( TRUE );
+}
+
+BOOLEAN
+BUFFER::DeleteAt(
+ IN ULONG cbToDelete,
+ IN ULONG oStartDelete
+ )
+
+/*++
+
+Routine Description:
+
+ Deletes the specificied section of the current buffer
+
+Arguments:
+
+ cbToDelete - Supplies the number of bytes to delete
+ oStartDelete - Supplies the offset for the delete
+
+Return Value:
+
+ TRUE - insert success
+ FALSE - This can happen when cbToDelete is larger then
+ the size of the buffer, oStartDelete is past the
+ end of the buffer.
+--*/
+
+
+{
+ if (oStartDelete < cb) {
+ if (cbToDelete <= cb) {
+ cb = cb - cbToDelete;
+ pBuffer = ( PCCHAR )ReAllocate( cb );
+ DebugPtrAssert( pBuffer );
+ memmove(( PCCHAR )pBuffer + oStartDelete ,
+ ( PCCHAR )pBuffer + (oStartDelete + cbToDelete),
+ (size_t)(cb - oStartDelete) );
+ return( TRUE );
+ }
+ }
+ return( FALSE );
+}
+
+BOOLEAN
+BUFFER::InsertAt (
+ IN PCVOID BufferToCopy,
+ IN ULONG cbToCopy,
+ IN ULONG oStartCopy
+ )
+
+/*++
+
+Routine Description:
+
+ Inserts the specificied buffer of bytes at the specified
+ location.
+
+Arguments:
+
+ BufferToCopy - Supplies the buffer to insert
+ cbToCopy - Supplies the number of bytes to insert
+ oStartCopy - Supplies the offset for the insertion
+
+Return Value:
+
+ TRUE - insert success
+ FALSE - This can happen for memory allocation failure
+ or oStartCopy is past end of buffer.
+--*/
+
+{
+ ULONG cbT;
+
+ // Note W-Barry 11-JUN-91 Necessary to add since cb is currently
+ // being updated by ReAllocate().
+ size_t CountToMove;
+ PCHAR pTmp;
+
+ CountToMove = (size_t)( cb - oStartCopy );
+ if (oStartCopy < cb ) {
+ cbT = cb + cbToCopy;
+ if ((pTmp = (char *)ReAllocate( cbT )) != NULL) {
+ memmove( pTmp + (oStartCopy + cbToCopy),
+ pTmp + oStartCopy,
+ CountToMove );
+ memcpy( pTmp + oStartCopy, BufferToCopy, (size_t)cbToCopy );
+ pBuffer = pTmp;
+ cb = cbT;
+ return( TRUE );
+ }
+ }
+ return( FALSE );
+}
+
+BOOLEAN
+BUFFER::PutBuffer (
+ IN PCBUFFER BufferToCopy
+ )
+
+/*++
+
+Routine Description:
+
+ Constructor for Buffer object. The buffer held in BufferToCopy
+ is not moved but copied to this object. If failed to init orginal
+ buffer state retained.
+
+Arguments:
+
+ BufferToCopy - pointer to BUFFER object to copy
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if supplied buffer was succesfully copied
+
+--*/
+
+{
+
+ ULONG cbNew;
+ PVOID pBufferNew;
+
+ cbNew = BufferToCopy->QueryBytesInBuffer ();
+
+ if (( pBufferNew = MALLOC( (size_t)cbNew )) != NULL) {
+ if( SetBuffer( pBufferNew, cbNew) ) {
+ // Note the buffer is not shortened on this?
+ pBuffer = BufferToCopy->GetBufferPtr();
+ BufferCopyAt( pBuffer, cbNew );
+ return( TRUE );
+ }
+ }
+
+ return( FALSE );
+}
+
+BOOLEAN
+BUFFER::SetBuffer (
+ IN PVOID InitialBuffer,
+ IN ULONG SizeOfBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ Constructor for Buffer object. The buffer passed in should not be
+ freed by the caller. BUFFER will free in upon deletion.
+
+Arguments:
+
+ InitialBuffer - pointer to buffer
+ SizeOfBuffer - size of buffer in bytes.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if (cb) {
+ FREE (pBuffer);
+ }
+
+ pBuffer = InitialBuffer;
+ cb = SizeOfBuffer;
+ _BufSize = SizeOfBuffer;
+
+ return( TRUE );
+}
+
+PVOID
+BUFFER::ReAllocate (
+ IN ULONG NewCount
+ )
+
+/*++
+
+Routine Description:
+
+ Reallocates the private data member pBuffer if required. ReAllocate
+ supports the concept that BUFFER's internal buffer can be larger
+ than the number of bytes actually in use.
+
+
+Arguments:
+
+ NewCount - Supplies the new size of pBuffer in bytes.
+
+
+Return Value:
+
+ PVOID - Returns a pointer to the 'newly allocated' pBuffer.
+
+--*/
+
+{
+ REGISTER PVOID pv;
+
+ //
+ // If the new buffer size is greater than what we currently have
+ // in reserve, or it is smaller than the threshold, realloc the
+ // buffer.
+ //
+
+ if( ( NewCount > _BufSize ) ||
+ ( ( _BufSize - NewCount ) >= _ThresHold )
+ ) {
+
+ //
+ // If the realloc of the buffer succeeds, record it's actual size.
+ //
+
+ if(( pv = REALLOC( pBuffer, (size_t)NewCount )) != NULL ) {
+
+ pBuffer = pv;
+ _BufSize = cb = NewCount;
+
+ }
+ } else {
+
+ //
+ // Enough storage is available in reserve, just return the
+ // existing pointer.
+ //
+
+ _BufSize = cb = NewCount;
+ pv = pBuffer;
+ }
+
+ return( pv );
+}
diff --git a/private/utils/ulib/src/bufstrm.cxx b/private/utils/ulib/src/bufstrm.cxx
new file mode 100644
index 000000000..5bd7eafab
--- /dev/null
+++ b/private/utils/ulib/src/bufstrm.cxx
@@ -0,0 +1,1041 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ bufstrm.cxx
+
+Abstract:
+
+ This module contains the definitions of the member functions
+ of BUFFER_STREAM class.
+
+Author:
+
+ Jaime Sasson (jaimes) 14-Apr-1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "bufstrm.hxx"
+#include "mbstr.hxx"
+#include "system.hxx"
+#include "wstring.hxx"
+
+extern "C" {
+ #include <ctype.h>
+}
+
+DEFINE_CONSTRUCTOR ( BUFFER_STREAM, STREAM );
+
+
+
+BUFFER_STREAM::~BUFFER_STREAM (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy a BUFFER_STREAM.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ FREE( _Buffer );
+}
+
+
+
+VOID
+BUFFER_STREAM::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Constructs a BUFFER_STREAM object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ _Buffer = NULL;
+ _BufferSize = 0;
+ _CurrentByte = NULL;
+ _BytesInBuffer = 0;
+ _BufferStreamType = -1;
+}
+
+
+BOOLEAN
+BUFFER_STREAM::Initialize (
+ ULONG BufferSize
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize an object of type BUFFER_STREAM.
+ A BUFFER_STREAM object cannot be reinitialized.
+
+Arguments:
+
+ BufferSize - Size of the buffer to be allocated.
+ The size of the buffer can be zero, but in this case no
+ memory will be allocated. This initialization should be used
+ only by FILE_STREAM when it is mapping a file in memory. In
+ this case, all methods that read from the buffer or test
+ the end of the file will be overloaded by methods defined
+ in FILE_STREAM.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the initialization succeed.
+
+--*/
+
+{
+ BOOLEAN Result;
+
+ Result = FALSE;
+ if( BufferSize != 0 ) {
+ //
+ // The +2 is needed becase the buffer needs to be
+ // double NUL terminated
+ //
+ _Buffer = ( PBYTE ) MALLOC( ( size_t )( BufferSize + 2 ) );
+ if( _Buffer != NULL ) {
+ *( _Buffer + BufferSize ) = 0;
+ *( _Buffer + BufferSize + 1 ) = 0;
+ _BufferSize = BufferSize;
+ _CurrentByte = NULL;
+ _BytesInBuffer = 0;
+ Result = TRUE;
+ }
+ } else {
+ _Buffer = NULL;
+ _BufferSize = 0;
+ _CurrentByte = NULL;
+ _BytesInBuffer = 0;
+ Result = TRUE;
+ }
+ return( ( STREAM::Initialize() ) && Result );
+}
+
+
+
+ULONG
+BUFFER_STREAM::FlushBuffer (
+ )
+
+/*++
+
+Routine Description:
+
+ Empty the buffer. The contents of the buffer is lost, and the
+ buffer is reinitialized.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - Returns the number of bytes lost in the buffer.
+
+--*/
+
+{
+ ULONG BytesLost;
+
+ BytesLost = _BytesInBuffer;
+ _CurrentByte = NULL;
+ _BytesInBuffer = 0;
+ return( BytesLost );
+}
+
+
+
+BOOLEAN
+BUFFER_STREAM::IsAtEnd(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Informs the caller if all bytes were read (the buffer is empty and
+ end of file has occurred.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - TRUE indicates that there is no more byte to read.
+
+
+--*/
+
+{
+ return( ( _BytesInBuffer == 0 ) && EndOfFile() );
+}
+
+VOID
+BUFFER_STREAM::SetStreamTypeANSI()
+{
+ _BufferStreamType = 0;
+}
+
+VOID
+BUFFER_STREAM::DetermineStreamType(
+ IN OUT PBYTE *Buffer,
+ IN ULONG BufferSize
+ )
+/*++
+Routine Description:
+ Sets _BufferStreamType for memory mapped files, called from
+ file_stream.
+
+Arguments:
+ Pointer to data & byte count.
+
+Return Value:
+ True always.
+--*/
+{
+ if (_BufferStreamType < 0) {
+ if (IsTextUnicode((LPTSTR)*Buffer, (INT)BufferSize, NULL)) {
+ _BufferStreamType = 1;
+ if (*((LPWCH)*Buffer) == (WCHAR)0xfeff)
+ *Buffer+= 2 ; // eat the Byte Order Mark
+ }
+ else
+ _BufferStreamType = 0;
+ }
+}
+
+
+BOOLEAN
+BUFFER_STREAM::Read(
+ OUT PBYTE Buffer,
+ IN ULONG BytesToRead,
+ OUT PULONG BytesRead
+ )
+
+/*++
+
+Routine Description:
+
+ Reads data from the buffer.
+
+Arguments:
+
+ Buffer - Points to the buffer where the data will be put.
+
+ BytesToRead - Indicates total number of bytes to read.
+
+ BytesRead - Points to the variable that will contain the number of
+ bytes read.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the read operation succeeded. If there was no
+ data to be read, the return value will be TRUE (to indicate
+ success), but BytesRead will be zero.
+
+
+--*/
+
+{
+ ULONG BytesReadSoFar;
+
+ DebugPtrAssert( Buffer );
+
+ if( BytesToRead <= _BytesInBuffer ) {
+ //
+ // If the buffer contains more bytes than requested, then
+ // just transfer bytes from one buffer to the other
+ //
+ memmove( Buffer, _CurrentByte, ( size_t )BytesToRead );
+ _BytesInBuffer -= BytesToRead;
+ if( _BytesInBuffer != 0 ) {
+ _CurrentByte += BytesToRead;
+ } else {
+ _CurrentByte = NULL;
+ }
+ *BytesRead = BytesToRead;
+ return( TRUE );
+ }
+
+ //
+ // Buffer contains less bytes than the total number requested.
+ // Transfer all bytes in the buffer to the caller's buffer
+ //
+ memmove( Buffer, _CurrentByte, ( size_t )_BytesInBuffer );
+ BytesReadSoFar = _BytesInBuffer;
+ _CurrentByte = _Buffer;
+ BytesToRead -= _BytesInBuffer;
+ _BytesInBuffer = 0;
+ //
+ // Refill the buffer and transfer bytes to the caller's buffer
+ // until all bytes are read or end of file occurs.
+ //
+ while( ( BytesToRead > 0 ) && !EndOfFile() ) {
+ if( !FillBuffer( _Buffer, _BufferSize, &_BytesInBuffer ) ) {
+ _BytesInBuffer = 0;
+ return( FALSE );
+ }
+ if( BytesToRead >= _BytesInBuffer ) {
+ memmove( Buffer, _Buffer, ( size_t )_BytesInBuffer );
+ Buffer += _BytesInBuffer;
+ BytesReadSoFar += _BytesInBuffer;
+ BytesToRead -= _BytesInBuffer;
+ _BytesInBuffer = 0;
+ } else {
+ memmove( Buffer, _Buffer, ( size_t )BytesToRead );
+ BytesReadSoFar += BytesToRead;
+ _CurrentByte += BytesToRead;
+ _BytesInBuffer -= BytesToRead;
+ BytesToRead = 0;
+ }
+ }
+ *BytesRead = BytesReadSoFar;
+ return( TRUE );
+}
+
+
+BOOLEAN
+BUFFER_STREAM::AdvanceBufferPointer(
+ IN ULONG Offset
+ )
+
+/*++
+
+Routine Description:
+
+ Adds an offset to the pointer to the current byte.
+ (It has the effect of removing the first 'offset' bytes from the
+ buffer.)
+
+Arguments:
+
+ Offset - Number of bytes to remove from the buffer.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the pointer was advanced, or FALSE if the
+ offset was greater than the number of bytes in the buffer.
+
+
+--*/
+
+{
+ BOOLEAN Result;
+
+ if( Offset <= _BytesInBuffer ) {
+ _BytesInBuffer -= Offset;
+ _CurrentByte = ( _BytesInBuffer == 0 ) ? NULL : _CurrentByte + Offset;
+ Result = TRUE;
+ } else {
+ Result = FALSE;
+ }
+ return( Result );
+}
+
+
+
+PCBYTE
+BUFFER_STREAM::GetBuffer(
+ PULONG BytesInBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ Returns to the caller the pointer to the buffer. If the buffer
+ is empty, then it fills the buffer.
+
+Arguments:
+
+ BytesInBuffer - Points to the variable that will contain the number
+ of bytes added to the buffer.
+
+
+Return Value:
+
+ PCBYTE - Pointer to the buffer.
+
+--*/
+
+{
+ if( _BytesInBuffer == 0 ) {
+ if( !EndOfFile() ) {
+ FillBuffer( _Buffer, _BufferSize, &_BytesInBuffer );
+ _CurrentByte = _Buffer;
+ } else {
+ _CurrentByte = NULL;
+ }
+ }
+
+ if (_BufferStreamType < 0) {
+ if (IsTextUnicode((LPTSTR)_CurrentByte, (INT)_BufferSize, NULL) &&
+ (_BufferSize > 1) ) {
+
+ _BufferStreamType = 1;
+ if (*((LPWCH)_CurrentByte)==0xfeff) {
+ _CurrentByte+=2; // eat the Byte Order Mark
+ }
+ } else {
+ _BufferStreamType = 0;
+ }
+ }
+ *BytesInBuffer = _BytesInBuffer;
+ return( _CurrentByte );
+}
+
+
+BOOLEAN
+BUFFER_STREAM::ReadChar(
+ OUT PWCHAR Char,
+ IN BOOLEAN Unicode
+ )
+
+/*++
+
+Routine Description:
+
+ Reads a character off the stream
+
+Arguments:
+
+ Char - Supplies pointer to wide character.
+
+Return Value:
+
+ TRUE if a character was read,
+ FALSE otherwise
+
+Notes:
+
+ We always read the character from the stream as a multibyte character
+ and do the multibyte to wide character conversion.
+
+--*/
+
+{
+
+ PBYTE Buffer;
+ ULONG BytesInBuffer;
+ USHORT BytesInChar;
+
+ if (!Char || ((Buffer = (PBYTE)GetBuffer( &BytesInBuffer)) == NULL )) {
+ return FALSE;
+ }
+ //
+ // Buffer may be a pointer to a file mapped in memory. For this
+ // reason we have to be aware of exception while accessing it.
+ //
+ DebugAssert( _BufferStreamType >= 0 );
+ if (_BufferStreamType == 0 && !Unicode) {
+ __try {
+ if( !( *Buffer ) ) {
+ //
+ // The first character in the buffer is a NULL. Return ZERO
+ // as the character read.
+ //
+ BytesInChar = 1;
+ Char = 0;
+ } else {
+ BytesInChar = (USHORT)mbtowc( (wchar_t *)Char, (char *)Buffer, (size_t)BytesInBuffer );
+ }
+ }
+ __except( GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR ) {
+ return( FALSE );
+ }
+ } else {
+ __try {
+ if( !( *((wchar_t *)Buffer) ) ) {
+ //
+ // The first character in the buffer is a NULL. Return ZERO
+ // as the character read.
+ //
+ BytesInChar = 2;
+ Char = 0;
+ } else {
+ BytesInChar = 2;
+ Char = (wchar_t *)Buffer;
+ }
+ }
+ __except( GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR ) {
+ return( FALSE );
+ }
+ }
+
+ if ( BytesInChar == 0 ) {
+ return FALSE;
+ }
+
+ AdvanceBufferPointer( BytesInChar );
+
+ return TRUE;
+
+}
+
+//disable C4509 warning about nonstandard ext: SEH + destructor
+#pragma warning(disable:4509)
+
+
+BOOLEAN
+BUFFER_STREAM::ReadString(
+ OUT PWSTRING String,
+ IN PWSTRING Delimiters,
+ IN BOOLEAN Unicode
+ )
+
+/*++
+
+Routine Description:
+
+ Reads a string off the stream
+
+Arguments:
+
+ String - Supplies pointer to string. The string must have been
+ previously initialized.
+ Delimiter - Supplies the set of characters that constitute a
+ string delimiter.
+
+Return Value:
+
+ TRUE if a string was read,
+ FALSE otherwise
+
+--*/
+
+{
+ PCVOID pBuffer;
+ ULONG BytesInBuffer;
+ ULONG BytesConsumed;
+ BOOLEAN EndOfString;
+ PSTR delim;
+ PWSTR delim_U;
+ BOOLEAN r;
+ FSTRING fstring;
+ CHNUM old_string_length;
+
+ DebugPtrAssert( String );
+
+ String->Truncate();
+
+ EndOfString = FALSE;
+
+ //
+ // Since the buffer might not contain the entire string, we keep
+ // converting the buffer and concatenating to the string, until
+ // we reach a delimiter (or there is no more input).
+ //
+ while ( !EndOfString ) {
+
+ //
+ // Get pointer into buffer
+ //
+ pBuffer = (PCVOID)GetBuffer( &BytesInBuffer );
+ if ( BytesInBuffer == 0 ) {
+ //
+ // No more input
+ //
+ break;
+ }
+
+ //
+ // Concatenate the buffer obtained to the one we have
+ //
+ //
+ // pBuffer may be a pointer to a file mapped in memory. For this
+ // reason we have to be aware of exception while accessing it.
+ //
+ DebugAssert( _BufferStreamType >= 0 );
+ if ( _BufferStreamType == 0 && !Unicode) {
+ __try {
+ if (delim = Delimiters->QuerySTR()) {
+ //
+ // If pBuffer points to a file mapped in memory, and the
+ // end of the file is in a page boundary, and the last
+ // byte in the file is neither NUL nor one of the delimiters,
+ // we get an access violation.
+ // For this reason we call strcspn inside a try-except, and
+ // if an access violation occurs we consume all bytes in
+ // the buffer.
+ // The access violation will not occur if the end of the file
+ // is not in a page boundary. In this case, it is guaranteed that
+ // the remaining bytes on the last page will be 0s.
+ //
+ // The access violation will not occur if pBuffer points to the
+ // buffer defined in this class. In this case, it is guaranteed
+ // that the byte immediately after the end of the buffer is NUL
+ // (see the initialization of this object).
+ //
+
+ __try {
+ BytesConsumed = strcspn((PCSTR) pBuffer, delim);
+ }
+ __except( GetExceptionCode() == STATUS_ACCESS_VIOLATION ) {
+ BytesConsumed = BytesInBuffer;
+ }
+ DELETE(delim);
+ old_string_length = String->QueryChCount();
+ if (r = String->Resize(old_string_length + BytesConsumed)) {
+ fstring.Initialize((PWSTR) String->GetWSTR() +
+ old_string_length, BytesConsumed + 1);
+ r = fstring.WSTRING::Initialize((PCSTR) pBuffer,
+ BytesConsumed);
+ String->SyncLength();
+ }
+ } else {
+ r = FALSE;
+ }
+ }
+ __except( GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR ) {
+ return( FALSE );
+ }
+
+ EndOfString = (BytesConsumed < BytesInBuffer);
+
+ } else {
+ __try {
+ if (delim_U = Delimiters->QueryWSTR()) {
+ __try {
+ BytesConsumed = wcscspn((wchar_t *) pBuffer, delim_U)*sizeof(WCHAR);
+ }
+ __except( GetExceptionCode() == STATUS_ACCESS_VIOLATION ) {
+ BytesConsumed = BytesInBuffer;
+ }
+ if((BytesInBuffer & 0xfffe) != BytesInBuffer){
+ BytesInBuffer++;
+ }
+
+ DELETE(delim_U);
+ old_string_length = String->QueryChCount();
+ if (r = String->Resize(old_string_length + BytesConsumed/sizeof(WCHAR))) {
+ fstring.Initialize((PWSTR)String->GetWSTR() +
+ old_string_length, BytesConsumed/sizeof(WCHAR) + 1);
+ r = fstring.WSTRING::Initialize((PCWSTR) pBuffer,
+ BytesConsumed/sizeof(WCHAR));
+ String->SyncLength();
+ }
+ } else {
+ r = FALSE;
+ }
+ }
+ __except( GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR ) {
+ return( FALSE );
+ }
+ EndOfString = (BytesConsumed < BytesInBuffer);
+ }
+
+ //EndOfString = (BytesConsumed < BytesInBuffer);
+
+ DebugAssert( (BytesConsumed > 0) || EndOfString );
+
+ //
+ // Advance the buffer pointer the ammount consumed
+ //
+ if (r) {
+ if (!AdvanceBufferPointer( BytesConsumed )) {
+ break;
+ }
+ }
+ }
+
+ return TRUE;
+
+}
+
+
+
+
+BOOLEAN
+BUFFER_STREAM::ReadMbString(
+ IN PSTR String,
+ IN DWORD BufferSize,
+ INOUT PDWORD StringSize,
+ IN PSTR Delimiters,
+ IN BOOLEAN ExpandTabs,
+ IN DWORD TabExp
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+
+Return Value:
+
+--*/
+
+{
+
+ DWORD StrSize;
+ BOOLEAN EndOfString;
+ PCVOID pBuffer;
+ ULONG BytesInBuffer;
+ ULONG BytesConsumed;
+ BYTE Byte;
+ DWORD NumBytes;
+ DWORD ChunkSize;
+ DWORD Spaces;
+ PBYTE pBuf;
+
+ DebugPtrAssert( String );
+ DebugPtrAssert( BufferSize );
+ DebugPtrAssert( Delimiters );
+
+ *String = '\0';
+ StrSize = 0;
+ EndOfString = FALSE;
+
+ //
+ // Since the buffer might not contain the entire string, we keep
+ // converting the buffer and concatenating to the string, until
+ // we reach a delimiter (or there is no more input).
+ //
+ while ( !EndOfString ) {
+
+ //
+ // Get pointer into buffer
+ //
+ pBuffer = (PCVOID)GetBuffer( &BytesInBuffer );
+
+ if ( BytesInBuffer == 0 ) {
+ //
+ // No more input
+ //
+ break;
+ }
+
+ //
+ // Concatenate the buffer obtained to the one we have
+ //
+ //
+ // pBuffer may be a pointer to a file mapped in memory. For this
+ // reason we have to be aware of exception while accessing it.
+ //
+ __try {
+ //
+ // If pBuffer points to a file mapped in memory, and the
+ // end of the file is in a page boundary, and the last
+ // byte in the file is neither NUL nor one of the delimiters,
+ // we get an access violation.
+ // For this reason we call strcspn inside a try-except, and
+ // if an access violation occurs we consume all bytes in
+ // the buffer.
+ // The access violation will not occur if the end of the file
+ // is not in a page boundary. In this case, it is guaranteed that
+ // the remaining bytes on the last page will be 0s.
+ //
+ // The access violation will not occur if pBuffer points to the
+ // buffer defined in this class. In this case, it is guaranteed
+ // that the byte immediately after the end of the buffer is NUL
+ // (see the initialization of this object).
+ //
+ __try {
+ BytesConsumed = MBSTR::Strcspn( (PSTR)pBuffer, Delimiters );
+ }
+ __except( GetExceptionCode() == STATUS_ACCESS_VIOLATION ) {
+ BytesConsumed = BytesInBuffer;
+ }
+
+ if ( BytesConsumed < BytesInBuffer ) {
+ EndOfString = TRUE;
+ }
+
+ if ( ExpandTabs ) {
+
+ //
+ // Expand tabs
+ //
+ ChunkSize = BytesConsumed;
+ NumBytes = BufferSize - StrSize - 1;
+
+ pBuf = (PBYTE)pBuffer;
+
+ while ( ChunkSize-- && NumBytes ) {
+
+ Byte = *pBuf++;
+
+ if ( Byte != '\t' ) {
+
+ String[StrSize++] = Byte;
+ NumBytes--;
+
+ } else {
+
+ Spaces = min (TabExp - (StrSize % TabExp), NumBytes);
+ MBSTR::Memset( &String[StrSize], ' ', Spaces );
+ StrSize += Spaces;
+ NumBytes -= Spaces;
+ }
+ }
+ ChunkSize++;
+
+ if ( ChunkSize > 0 ) {
+ EndOfString = TRUE;
+ BytesConsumed -= ChunkSize;
+ }
+
+ } else {
+
+ //
+ // Just copy string
+ //
+ if ( BytesConsumed >= (BufferSize-StrSize) ) {
+ BytesConsumed = BufferSize - StrSize - 1;
+ EndOfString = TRUE;
+ }
+
+ MBSTR::Memcpy( &String[StrSize], (PVOID) pBuffer, BytesConsumed );
+ StrSize += BytesConsumed;
+ }
+
+ }
+ __except( GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR ) {
+ return( FALSE );
+ }
+
+ DebugAssert( (BytesConsumed > 0) || EndOfString );
+
+ //
+ // Advance the buffer pointer the ammount consumed
+ //
+ if( BytesConsumed < BytesInBuffer ) {
+ //
+ // Get rid of the delimiter
+ // This is to improve the performance of FC, who calls
+ // STREAM::ReadMbLine several times
+ //
+ BytesConsumed++;
+ }
+ AdvanceBufferPointer( BytesConsumed );
+
+ }
+
+ String[StrSize] = '\0';
+
+ *StringSize = StrSize;
+
+ return TRUE;
+}
+
+
+BOOLEAN
+BUFFER_STREAM::ReadWString(
+ IN PWSTR String,
+ IN DWORD BufferSize, // char count
+ INOUT PDWORD StringSize, // char count
+ IN PWSTR Delimiters,
+ IN BOOLEAN ExpandTabs,
+ IN DWORD TabExp
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+
+Return Value:
+
+--*/
+
+{
+
+ DWORD StrSize;
+ BOOLEAN EndOfString;
+ PCVOID pBuffer;
+ ULONG BytesInBuffer;
+ ULONG BytesConsumed;
+ WCHAR Byte;
+ DWORD NumBytes;
+ DWORD ChunkSize;
+ DWORD Spaces;
+ PWCHAR pBuf;
+
+ DebugPtrAssert( String );
+ DebugPtrAssert( BufferSize );
+ DebugPtrAssert( Delimiters );
+
+ *String = L'\0';
+ StrSize = 0;
+ EndOfString = FALSE;
+
+ //
+ // Since the buffer might not contain the entire string, we keep
+ // converting the buffer and concatenating to the string, until
+ // we reach a delimiter (or there is no more input).
+ //
+ while ( !EndOfString ) {
+
+ //
+ // Get pointer into buffer
+ //
+ pBuffer = (PCVOID)GetBuffer( &BytesInBuffer );
+
+ if ( BytesInBuffer == 0 ) {
+ //
+ // No more input
+ //
+ break;
+ }
+
+ //
+ // Concatenate the buffer obtained to the one we have
+ //
+ //
+ // pBuffer may be a pointer to a file mapped in memory. For this
+ // reason we have to be aware of exception while accessing it.
+ //
+ __try {
+ //
+ // If pBuffer points to a file mapped in memory, and the
+ // end of the file is in a page boundary, and the last
+ // byte in the file is neither NUL nor one of the delimiters,
+ // we get an access violation.
+ // For this reason we call strcspn inside a try-except, and
+ // if an access violation occurs we consume all bytes in
+ // the buffer.
+ // The access violation will not occur if the end of the file
+ // is not in a page boundary. In this case, it is guaranteed that
+ // the remaining bytes on the last page will be 0s.
+ //
+ // The access violation will not occur if pBuffer points to the
+ // buffer defined in this class. In this case, it is guaranteed
+ // that the byte immediately after the end of the buffer is NUL
+ // (see the initialization of this object).
+ //
+ __try {
+ BytesConsumed = wcscspn( (unsigned short *)pBuffer, Delimiters )*sizeof(WCHAR);
+ }
+ __except( GetExceptionCode() == STATUS_ACCESS_VIOLATION ) {
+ BytesConsumed = BytesInBuffer&0xFFFE;
+ }
+
+ if ( BytesConsumed < BytesInBuffer ) {
+ EndOfString = TRUE;
+ }
+
+ if ( ExpandTabs ) {
+
+ //
+ // Expand tabs
+ //
+ ChunkSize = BytesConsumed/sizeof(WCHAR);
+ NumBytes = BufferSize - StrSize - 1;
+
+ pBuf = (PWCHAR)pBuffer;
+
+ while ( (ChunkSize--) && NumBytes ) {
+
+ Byte = *pBuf++;
+
+ if ( Byte != L'\t' ) {
+
+ String[StrSize++] = Byte;
+ NumBytes--;
+
+ } else {
+
+ Spaces = min (TabExp - (StrSize % TabExp), NumBytes);
+ // wcsnset( (wchar_t *)&String[StrSize], L' ', Spaces );
+ for (DWORD ii=0;ii<Spaces;ii++) {
+ String[StrSize+ii] = L' ';
+ }
+ StrSize += Spaces;
+ NumBytes -= Spaces;
+ }
+ }
+ ChunkSize++;
+
+ if ( ChunkSize > 0 ) {
+ EndOfString = TRUE;
+ BytesConsumed = BytesConsumed - sizeof(WCHAR)*ChunkSize;
+ }
+
+ } else {
+
+ //
+ // Just copy string
+ //
+ if ( BytesConsumed >= (BufferSize-StrSize)*sizeof(WCHAR) ) {
+ BytesConsumed = (BufferSize - StrSize - 1)*sizeof(WCHAR);
+ EndOfString = TRUE;
+ }
+
+ MBSTR::Memcpy( &String[StrSize], (PVOID) pBuffer, BytesConsumed );
+ StrSize += BytesConsumed/sizeof(WCHAR);
+ }
+
+ }
+ __except( GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR ) {
+ return( FALSE );
+ }
+
+ DebugAssert( (BytesConsumed > 0) || EndOfString );
+
+ //
+ // Advance the buffer pointer the ammount consumed
+ //
+ if( BytesConsumed < BytesInBuffer ) {
+ //
+ // Get rid of the delimiter
+ // This is to improve the performance of FC, who calls
+ // STREAM::ReadWLine several times
+ //
+ BytesConsumed+=2;
+ }
+ AdvanceBufferPointer( BytesConsumed );
+
+ }
+
+ String[StrSize] = 0;
+
+ *StringSize = StrSize;
+
+ return TRUE;
+}
+
diff --git a/private/utils/ulib/src/bytestrm.cxx b/private/utils/ulib/src/bytestrm.cxx
new file mode 100644
index 000000000..3986f8031
--- /dev/null
+++ b/private/utils/ulib/src/bytestrm.cxx
@@ -0,0 +1,189 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ bytestrm.cxx
+
+Abstract:
+
+ This module contains the definitions of the member functions
+ of BYTE_STREAM class.
+
+Author:
+
+ Ramon J. San Andres (ramonsa) 28-Feb-1992
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "stream.hxx"
+#include "bytestrm.hxx"
+
+DEFINE_EXPORTED_CONSTRUCTOR( BYTE_STREAM, OBJECT, ULIB_EXPORT );
+
+VOID
+BYTE_STREAM::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Constructs a BYTE_STREAM object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ _Stream = NULL;
+ _Buffer = NULL;
+ _NextByte = NULL;
+ _BufferSize = 0;
+ _BytesInBuffer = 0;
+}
+
+
+
+ULIB_EXPORT
+BYTE_STREAM::~BYTE_STREAM (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy a BYTE_STREAM.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ FREE( _Buffer );
+}
+
+
+
+
+
+
+ULIB_EXPORT
+BOOLEAN
+BYTE_STREAM::Initialize (
+ IN PSTREAM Stream,
+ IN DWORD BufferSize
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes a BYTE_STREAM
+
+Arguments:
+
+ Stream - Supplies the stream to be used
+ BufferSize - Supplies the size of the buffer to use
+
+Return Value:
+
+ BOOLEAN - TRUE if successful.
+
+--*/
+
+{
+ STREAMACCESS Access;
+
+ DebugPtrAssert( Stream );
+ DebugAssert( BufferSize > 0 );
+
+ FREE( _Buffer );
+
+ Access = Stream->QueryAccess();
+
+ if ( (Access == READ_ACCESS) || (Access == READ_AND_WRITE_ACCESS)) {
+
+ if ( _Buffer = (PBYTE)MALLOC( BufferSize ) ) {
+
+ _Stream = Stream;
+ _NextByte = _Buffer;
+ _BufferSize = BufferSize;
+ _BytesInBuffer = 0;
+
+ return TRUE;
+
+ }
+ }
+
+ return FALSE;
+}
+
+
+
+ULIB_EXPORT
+BOOLEAN
+BYTE_STREAM::FillAndReadByte(
+ IN PBYTE Byte
+ )
+/*++
+
+
+Routine Description:
+
+ Fills the buffer and reads next byte
+
+Arguments:
+
+ Byte - Supplies pointer to where to put the byte
+
+Return Value:
+
+ BOOLEAN - TRUE if byte read.
+
+--*/
+
+{
+ ULONG BytesRead;
+
+ DebugAssert( _BytesInBuffer == 0 );
+
+ if ( _Stream->Read( _Buffer, _BufferSize, &BytesRead ) &&
+ (BytesRead > 0) ) {
+
+ _NextByte = _Buffer;
+ _BytesInBuffer = (DWORD)BytesRead;
+
+ *Byte = *_NextByte++;
+ _BytesInBuffer--;
+
+ return TRUE;
+
+ }
+
+ return FALSE;
+}
diff --git a/private/utils/ulib/src/clasdesc.cxx b/private/utils/ulib/src/clasdesc.cxx
new file mode 100644
index 000000000..983c91acf
--- /dev/null
+++ b/private/utils/ulib/src/clasdesc.cxx
@@ -0,0 +1,124 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ clasdesc.cxx
+
+Abstract:
+
+ This module contains the definition for the CLASS_DESCRIPTOR class.
+ CLASS_DESCRIPTOR classes are special concrete classes derived from
+ OBJECT. They are special in that a single staic object of this class
+ exists for every other concrete class in the Ulib hierarchy.
+ CLASS_DESCRIPTORs allocate and maintain information that can be used
+ at run-time to determine the actual type of an object.
+
+Author:
+
+ David J. Gilman (davegi) 30-Oct-1990
+
+Environment:
+
+ ULIB, User Mode
+
+Notes:
+
+ The definitions for all concrete class' CLASS_DESCRIPTORs can be found
+ in the file ulib.cxx.
+
+ See the Cast member function in ulibdef.hxx to see how dynamic casting
+ and CLASS_DESCRIPTORs work.
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+
+
+ULIB_EXPORT
+CLASS_DESCRIPTOR::CLASS_DESCRIPTOR (
+ )
+{
+}
+
+#if DBG==1
+
+//
+// For debugging purposes CLASS_DESCRIPTORs maintain the name of the class
+// that they describe.
+//
+
+#include <string.h>
+
+ULIB_EXPORT
+BOOLEAN
+CLASS_DESCRIPTOR::Initialize (
+ IN PCCLASS_NAME ClassName
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize a CLASS_DESCRIPTOR object by initializing the classname
+ and class ids.
+
+Arguments:
+
+ ClassName - Supplies the name of the class being described.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DebugPtrAssert( ClassName );
+ strncpy(( PCCHAR ) _ClassName,
+ ( PCCCHAR ) ClassName,
+ ( INT ) _MaxClassNameLength );
+
+ //
+ // Note that this guarantees that the CLASS_ID is unique for all classes
+ // at the expense of not being able to recognize a class based on it's
+ // CLASS_ID. The benefit is that IDs are guaranteed to be unique and
+ // do not have to be cleared or registered.
+ //
+
+ _ClassID = ( ULONG ) &_ClassID;
+ return( TRUE );
+}
+
+#else // DBG==0
+
+ULIB_EXPORT
+BOOLEAN
+CLASS_DESCRIPTOR::Initialize (
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize a CLASS_DESCRIPTOR object by initializing the class id.
+
+Arguments:
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _ClassID = ( ULONG ) &_ClassID;
+ return( TRUE );
+}
+
+#endif // DBG
diff --git a/private/utils/ulib/src/cmem.cxx b/private/utils/ulib/src/cmem.cxx
new file mode 100644
index 000000000..bf13aefc7
--- /dev/null
+++ b/private/utils/ulib/src/cmem.cxx
@@ -0,0 +1,107 @@
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+#include "ulib.hxx"
+#include "cmem.hxx"
+#include "error.hxx"
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( CONT_MEM, MEM, ULIB_EXPORT );
+
+VOID
+CONT_MEM::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Constructor for CONT_MEM.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _buf = NULL;
+ _size = 0;
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+CONT_MEM::Initialize(
+ IN PVOID Buffer,
+ IN ULONG Size
+ )
+/*++
+
+Routine Description:
+
+ This routine supplies the object with a store of memory from which to
+ work with.
+
+Arguments:
+
+ Buffer - Supplies a pointer to memory.
+ Size - Supplies the number of bytes of memory addressable through
+ the pointer.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _buf = Buffer;
+ _size = Size;
+
+ return TRUE;
+}
+
+
+ULIB_EXPORT
+PVOID
+CONT_MEM::Acquire(
+ IN ULONG Size,
+ IN ULONG AlignmentMask
+ )
+/*++
+
+Routine Description:
+
+ This routine takes size bytes of memory from the current memory
+ pool and returns it to the user. If size bytes of memory are not
+ available then this routine return NULL. After a call to this routine
+ the local pool of memory is decreased by Size bytes. Successive requests
+ will be granted as long as there is sufficient memory to grant them.
+
+ This method will fail if the memory is not at the alignment requested.
+
+Arguments:
+
+ Size - Supplies the number of bytes of memory requested.
+ Alignment - Supplies the necessary alignment for the memory.
+
+Return Value:
+
+ A pointer to size bytes of memory or NULL.
+
+--*/
+{
+ PVOID rv;
+
+ if (Size > _size ||
+ ((ULONG) _buf)&AlignmentMask) {
+ return NULL;
+ }
+
+ _size -= Size;
+ rv = _buf;
+ _buf = (PCHAR) _buf + Size;
+ return rv;
+}
diff --git a/private/utils/ulib/src/comm.cxx b/private/utils/ulib/src/comm.cxx
new file mode 100644
index 000000000..f951d6754
--- /dev/null
+++ b/private/utils/ulib/src/comm.cxx
@@ -0,0 +1,700 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ COMM_DEVICE
+
+Abstract:
+
+ This module contains the implementation for the COMM_DEVICE class.
+
+Author:
+
+ Ramon J. San Andres (ramonsa) 08-Jul-1991
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "comm.hxx"
+#include "file.hxx"
+
+
+//
+// Default timeout is one minute
+//
+#define DEFAULT_TIMEOUT 60000
+
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( COMM_DEVICE, OBJECT, ULIB_EXPORT );
+
+DEFINE_CAST_MEMBER_FUNCTION( COMM_DEVICE );
+
+ULIB_EXPORT
+COMM_DEVICE::~COMM_DEVICE(
+ )
+{
+ Destroy();
+}
+
+VOID
+COMM_DEVICE::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Constructs a COMM_DEVICE object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ _Handle = NULL;
+
+#if DBG==1
+
+ _Initialized = FALSE;
+
+#endif
+
+}
+
+ULIB_EXPORT
+BOOLEAN
+COMM_DEVICE::Initialize (
+ IN PCPATH PortName,
+ OUT PBOOLEAN OpenError
+ )
+
+/*++
+
+Routine Description:
+
+ Phase 2 of construction for a COMM_DEVICE.
+
+Arguments:
+
+ Port - Supplies pointer to the FSN_FILE object of the port.
+ OpenError - Supplies pointer to flag which if TRUE means that
+ the port could not be openend.
+
+Return Value:
+
+ BOOLEAN - TRUE if the serial port was successfully initialized,
+ FALSE otherwise.
+
+--*/
+
+{
+ DSTRING QualifiedName;
+ BOOLEAN InitOk;
+
+ DebugPtrAssert( PortName );
+
+ Destroy();
+
+ if( !QualifiedName.Initialize( L"\\\\.\\" ) ||
+ !QualifiedName.Strcat( PortName->GetPathString() ) ) {
+
+ if( OpenError ) {
+ *OpenError = FALSE;
+ }
+ return FALSE;
+ }
+
+ //
+ // Open the Port and get a handle to it.
+ //
+ _Handle = CreateFile( QualifiedName.GetWSTR(),
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL );
+
+
+ if ( _Handle != INVALID_HANDLE_VALUE ) {
+
+ if ( OpenError ) {
+ *OpenError = FALSE;
+ }
+
+ //
+ // Get the current port state
+ //
+ InitOk = GetCommState( _Handle, &_Dcb );
+
+#if DBG==1
+ GetLastError();
+#endif
+
+#if DBG==1
+
+ _Initialized = InitOk;
+
+#endif
+
+ } else if ( OpenError ) {
+ *OpenError = TRUE;
+ }
+
+ return InitOk;
+}
+
+VOID
+COMM_DEVICE::Destroy (
+ )
+
+/*++
+
+Routine Description:
+
+ Brings the object to a point at which it can be initialized.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ none
+
+--*/
+
+{
+
+ if ( _Handle != INVALID_HANDLE_VALUE ) {
+
+ CloseHandle( _Handle );
+
+ _Handle = INVALID_HANDLE_VALUE;
+
+ }
+
+#if DBG==1
+
+ _Initialized = FALSE;
+
+#endif
+
+}
+
+ULIB_EXPORT
+BOOLEAN
+COMM_DEVICE::CommitState (
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the port state.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ BOOLEAN - TRUE if state set
+ FALSE otherwise.
+
+--*/
+
+{
+
+ DebugAssert( _Initialized );
+
+ return SetCommState( _Handle, &_Dcb );
+
+}
+
+ULIB_EXPORT
+BOOLEAN
+COMM_DEVICE::QueryTimeOut (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Queries whether infinite timeouts are enabled or not.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ BOOLEAN - TRUE if infinite timeouts are enabled
+ FALSE otherwise.
+
+--*/
+
+{
+ COMMTIMEOUTS TimeOut;
+
+ DebugAssert( _Initialized );
+
+ GetCommTimeouts( _Handle, &TimeOut );
+
+ return ( (TimeOut.ReadTotalTimeoutConstant == 0) &&
+ (TimeOut.WriteTotalTimeoutConstant == 0) );
+
+}
+
+BOOLEAN
+COMM_DEVICE::ReadState (
+ )
+
+/*++
+
+Routine Description:
+
+ Gets the current port state.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ BOOLEAN - TRUE if state read
+ FALSE otherwise.
+
+--*/
+
+{
+
+ DebugAssert( _Initialized );
+
+ return GetCommState( _Handle, &_Dcb );
+
+}
+
+ULIB_EXPORT
+BOOLEAN
+COMM_DEVICE::SetBaudRate (
+ IN ULONG BaudRate
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the baud rate. Note that all changes take effect only after the
+ CommitState() method is called.
+
+Arguments:
+
+ BaudRate - Supplies the baud rate
+
+Return Value:
+
+ BOOLEAN - TRUE if valid baud rate
+ FALSE otherwise
+
+--*/
+
+{
+
+ DebugAssert( _Initialized );
+
+ _Dcb.BaudRate = BaudRate;
+
+ return TRUE;
+
+}
+
+ULIB_EXPORT
+BOOLEAN
+COMM_DEVICE::SetDataBits (
+ IN ULONG DataBits
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the number of data bits. Note that all changes take effect only
+ after the CommitState() method is called.
+
+Arguments:
+
+ DataBits - Supplies the number of data bits
+
+Return Value:
+
+ BOOLEAN - TRUE if valid number of data bits
+ FALSE otherwise
+
+--*/
+
+{
+
+ DebugAssert( _Initialized );
+
+ _Dcb.ByteSize = (BYTE)DataBits;
+
+ return TRUE;
+
+}
+
+ULIB_EXPORT
+BOOLEAN
+COMM_DEVICE::SetDtrControl (
+ IN DTR_CONTROL DtrControl
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the DTR control. Note that all changes take effect only
+ after the CommitState() method is called.
+
+Arguments:
+
+ DtrControl - Supplies the DTR control value
+
+Return Value:
+
+ BOOLEAN - TRUE if valid DTR control
+ FALSE otherwise
+
+--*/
+
+{
+
+ DebugAssert( _Initialized );
+
+ if ( (DtrControl == DTR_ENABLE) ||
+ (DtrControl == DTR_DISABLE) ||
+ (DtrControl == DTR_HANDSHAKE) ) {
+
+ _Dcb.fDtrControl = (DWORD)DtrControl;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+ULIB_EXPORT
+BOOLEAN
+COMM_DEVICE::SetIdsr (
+ IN BOOLEAN Idsr
+ )
+
+/*++
+
+Routine Description:
+
+ Enables/disables DSR sensitivity
+
+Arguments:
+
+ Odsr - Supplies a flag which if TRUE, enables DSR sensitivity
+ if FALSE, it disables it.
+
+Return Value:
+
+ BOOLEAN - TRUE if DSR sensitivity enabled/disabled, FALSE otherwise.
+
+--*/
+
+{
+ DebugAssert( _Initialized );
+
+ if ( Idsr ) {
+ _Dcb.fDsrSensitivity = TRUE;
+ } else {
+ _Dcb.fDsrSensitivity = FALSE;
+ }
+
+ return TRUE;
+}
+
+ULIB_EXPORT
+BOOLEAN
+COMM_DEVICE::SetOcts (
+ IN BOOLEAN Octs
+ )
+
+/*++
+
+Routine Description:
+
+ Sets/resets CTS handshaking
+
+Arguments:
+
+ Octs - Supplies a flag which if TRUE, enables CTS handshaking,
+ if FALSE, it disables it.
+
+Return Value:
+
+ BOOLEAN - TRUE if handshaking enabled/disabled, FALSE otherwise.
+
+--*/
+
+{
+ DebugAssert( _Initialized );
+
+ if ( Octs ) {
+ _Dcb.fOutxCtsFlow = TRUE;
+ } else {
+ _Dcb.fOutxCtsFlow = FALSE;
+ }
+
+ return TRUE;
+}
+
+ULIB_EXPORT
+BOOLEAN
+COMM_DEVICE::SetOdsr (
+ IN BOOLEAN Odsr
+ )
+
+/*++
+
+Routine Description:
+
+ Sets/resets DSR handshaking
+
+Arguments:
+
+ Odsr - Supplies a flag which if TRUE, enables DSR handshaking,
+ if FALSE, it disables it.
+
+Return Value:
+
+ BOOLEAN - TRUE if handshaking enabled/disabled, FALSE otherwise.
+
+--*/
+
+{
+ DebugAssert( _Initialized );
+
+ if ( Odsr ) {
+ _Dcb.fOutxDsrFlow = TRUE;
+ } else {
+ _Dcb.fOutxDsrFlow = FALSE;
+ }
+
+ return TRUE;
+}
+
+ULIB_EXPORT
+BOOLEAN
+COMM_DEVICE::SetParity (
+ IN PARITY Parity
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the parity. Note that all changes take effect only after the
+ CommitState() method is called.
+
+Arguments:
+
+ Parity - Supplies the parity value
+
+Return Value:
+
+ BOOLEAN - TRUE if valid parity
+ FALSE otherwise
+
+--*/
+
+{
+
+
+ DebugAssert( _Initialized );
+
+ DebugAssert( (Parity == COMM_PARITY_NONE) || (Parity == COMM_PARITY_ODD) ||
+ (Parity == COMM_PARITY_EVEN) || (Parity == COMM_PARITY_MARK) ||
+ (Parity == COMM_PARITY_SPACE));
+
+ _Dcb.Parity = (BYTE)Parity;
+
+ return TRUE;
+
+}
+
+ULIB_EXPORT
+BOOLEAN
+COMM_DEVICE::SetRtsControl (
+ IN RTS_CONTROL RtsControl
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the RTS control. Note that all changes take effect only
+ after the CommitState() method is called.
+
+Arguments:
+
+ RtsControl - Supplies the RTS control value
+
+Return Value:
+
+ BOOLEAN - TRUE if valid RTS control
+ FALSE otherwise
+
+--*/
+
+{
+
+ DebugAssert( _Initialized );
+
+ if ( (RtsControl == RTS_ENABLE) ||
+ (RtsControl == RTS_DISABLE) ||
+ (RtsControl == RTS_HANDSHAKE) ||
+ (RtsControl == RTS_TOGGLE )
+ ) {
+
+ _Dcb.fRtsControl = (DWORD)RtsControl;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+ULIB_EXPORT
+BOOLEAN
+COMM_DEVICE::SetStopBits (
+ IN STOPBITS StopBits
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the number of stop bits. Note that all changes take effect
+ only after the CommitState() method is called.
+
+Arguments:
+
+ StopBits - Supplies the number of stop bits
+
+Return Value:
+
+ BOOLEAN - TRUE if valid number of stop bits
+ FALSE otherwise
+
+--*/
+
+{
+
+ DebugAssert( _Initialized );
+
+ DebugAssert( (StopBits == COMM_STOPBITS_1) || (StopBits == COMM_STOPBITS_15) ||
+ (StopBits == COMM_STOPBITS_2) );
+
+ _Dcb.StopBits = (BYTE)StopBits;
+
+ return TRUE;
+
+}
+
+ULIB_EXPORT
+BOOLEAN
+COMM_DEVICE::SetTimeOut (
+ IN BOOLEAN TimeOut
+ )
+
+/*++
+
+Routine Description:
+
+ Sets/resets infinite timeouts.
+
+Arguments:
+
+ TimeOut - Supplies a flag which if TRUE means that infinite timeout
+ is to be set. if FALSE, a 1-minute timeout is set for
+ both reading and writting.
+
+Return Value:
+
+ BOOLEAN = TRUE if timeout set, FALSE otherwise
+
+--*/
+
+{
+ COMMTIMEOUTS Time;
+
+ DebugAssert( _Initialized );
+
+ GetCommTimeouts( _Handle, &Time );
+
+ if ( TimeOut ) {
+ Time.ReadTotalTimeoutConstant = 0;
+ Time.WriteTotalTimeoutConstant = 0;
+ } else {
+ Time.ReadTotalTimeoutConstant = DEFAULT_TIMEOUT;
+ Time.WriteTotalTimeoutConstant = DEFAULT_TIMEOUT;
+ }
+
+ return SetCommTimeouts( _Handle, &Time );
+
+}
+
+ULIB_EXPORT
+BOOLEAN
+COMM_DEVICE::SetXon (
+ IN BOOLEAN Xon
+ )
+
+/*++
+
+Routine Description:
+
+ Sets/resets XON/XOFF data-flow protocol.
+
+Arguments:
+
+ Xon - Supplies flag which if TRUE, enables XON/XOFF protocol,
+ if FALSE, disables it.
+
+Return Value:
+
+ BOOLEAN = TRUE if protocol set/reset, FALSE otherwise
+
+--*/
+
+{
+ DebugAssert( _Initialized );
+
+ if ( Xon ) {
+ _Dcb.fInX = TRUE;
+ _Dcb.fOutX = TRUE;
+ } else {
+ _Dcb.fInX = FALSE;
+ _Dcb.fOutX = FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/ulib/src/contain.cxx b/private/utils/ulib/src/contain.cxx
new file mode 100644
index 000000000..4ca6b8e8f
--- /dev/null
+++ b/private/utils/ulib/src/contain.cxx
@@ -0,0 +1,38 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ contain.cxx
+
+Abstract:
+
+ This module contains the definition for the CONTAINER class, the most
+ primitive, abstract class in the container sub-hierarchy. Given it's
+ abstract, prmitive nature there is minimal implementation at this point
+ in the hierarchy.
+
+Author:
+
+ David J. Gilman (davegi) 02-Nov-1990
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "contain.hxx"
+
+
+DEFINE_CONSTRUCTOR( CONTAINER, OBJECT );
+
+CONTAINER::~CONTAINER(
+ )
+{
+}
diff --git a/private/utils/ulib/src/dir.cxx b/private/utils/ulib/src/dir.cxx
new file mode 100644
index 000000000..308848b9a
--- /dev/null
+++ b/private/utils/ulib/src/dir.cxx
@@ -0,0 +1,939 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ dir.cxx
+
+Abstract:
+
+ This module contains the defintion for the FSN_DIRECTORY class.
+
+Author:
+
+ David J. Gilman (davegi) 09-Jan-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "array.hxx"
+#include "arrayit.hxx"
+#include "dir.hxx"
+#include "filter.hxx"
+#include "wstring.hxx"
+#include "path.hxx"
+#include "system.hxx"
+
+BOOLEAN
+IsDot (
+ IN WCHAR *p
+ );
+
+INLINE
+BOOLEAN
+IsDot (
+ IN WCHAR *p
+ )
+/*++
+
+Routine Description:
+
+ Determines if a name is a '.' or '..' entry in a directory.
+
+ It is only intended to be used when processing a WIN32_FIND_DATA
+ structure.
+
+Arguments:
+
+ p - Supplies pointer to char array
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the name is a '.' or '..' entry.
+
+--*/
+{
+
+
+ return ( (p[0] == '.' && p[1] == '\0') ||
+ (p[0] == '.' && p[1] == '.' && p[2] == '\0' ) );
+}
+
+
+
+
+DEFINE_CONSTRUCTOR( FSN_DIRECTORY, FSNODE );
+
+DEFINE_CAST_MEMBER_FUNCTION( FSN_DIRECTORY );
+
+BOOLEAN
+FSN_DIRECTORY::Copy (
+ IN PFSN_FILTER FsnFilter,
+ IN PCFSN_DIRECTORY DestinationDir,
+ IN BOOLEAN Recurse,
+ IN BOOLEAN OverWrite
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Copies a set of FSNODEs to a destination directory.
+
+Arguments:
+
+ FsnFilter - Supplies a pointer top a constant FSN_FILTER, which
+ describes the set of FSNODEs to be copied.
+
+ DestinationDir - Supplies a pointer to a constant FSN_DIRECTORY which is
+ the destination of the copy.
+
+ Recurse - Supplies a flag which if TRUE causes Copy to perform
+ a recursive copy if it encounters a FSN_DIRECTORY.
+
+ OverWrite - Supplies a flag which if TRUE, allows Copy to over
+ write an existing destination file.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the entire Copy operation was succesful.
+
+--*/
+
+
+{
+
+ ULONG Files = 0;
+ DWORD ErrorStatus = 0;
+ PARRAY SrcFiles;
+ PARRAY_ITERATOR Iterator;
+ PPATH SourcePath = NULL;
+ LPWSTR SourcePathString = NULL;
+ ULONG SourceBufferSize = 0;
+ PPATH DestinationPath = NULL;
+ LPWSTR DestinationPathString = NULL;
+ ULONG DestinationBufferSize = 0;
+ ULONG BufferSize;
+ PFSNODE FsNode;
+ PWSTRING Name;
+ BOOLEAN ReturnValue = TRUE;
+ PFSN_DIRECTORY SourceDirectory = NULL;
+ PFSN_DIRECTORY DestinationDirectory = NULL;
+
+ DebugPtrAssert( FsnFilter );
+ DebugPtrAssert( DestinationDir );
+ if ( //
+ // Verify arguments
+ //
+ ( FsnFilter != NULL ) &&
+ ( DestinationDir != NULL ) &&
+ //
+ // Get array of nodes for files in the directory
+ //
+ (( SrcFiles = QueryFsnodeArray( FsnFilter )) != NULL ) &&
+ //
+ // Get an iterator for processing the nodes
+ //
+ (( Iterator = ( PARRAY_ITERATOR ) SrcFiles->QueryIterator( )) != NULL ) &&
+ //
+ // Get paths
+ //
+ ((SourcePath = NEW PATH) != NULL) &&
+ ((DestinationPath = DestinationDir->GetPath( )->QueryFullPath( )) != NULL) ) {
+
+ //
+ // For each FSNODE in the ARRAY either:
+ //
+ // - set up and call Copy on the sub directory (based on Recurse)
+ // - or copy the file
+ //
+ while (( FsNode = (PFSNODE)Iterator->GetNext( )) != NULL ) {
+
+ //
+ // Append the name portion of the source to the
+ // destination path.
+ //
+ if ( ((Name = FsNode->QueryName()) == NULL) ||
+ !DestinationPath->AppendBase( Name ) ) {
+ break;
+ }
+
+
+ //
+ // Get paths and strings
+ //
+ SourcePath->Initialize( FsNode->GetPath() );
+
+ BufferSize = (SourcePath->GetPathString()->QueryChCount() + 1) * 2;
+ if ( BufferSize > SourceBufferSize ) {
+ if (SourceBufferSize == 0) {
+ SourcePathString = (LPWSTR)MALLOC((size_t)BufferSize);
+ } else {
+ SourcePathString = (LPWSTR)REALLOC( SourcePathString, (size_t)BufferSize);
+ }
+ SourceBufferSize = BufferSize;
+ }
+
+ BufferSize = (DestinationPath->GetPathString()->QueryChCount() + 1) * 2;
+ if ( BufferSize > DestinationBufferSize ) {
+ if (DestinationBufferSize == 0) {
+ DestinationPathString = (LPWSTR)MALLOC((size_t)BufferSize);
+ } else {
+ DestinationPathString = (LPWSTR)REALLOC( DestinationPathString, (size_t)BufferSize);
+ }
+ DestinationBufferSize = BufferSize;
+ }
+
+ if ( (SourcePathString == NULL) || (DestinationPathString == NULL)) {
+ break;
+ }
+
+ SourcePath->GetPathString()->QueryWSTR(0, TO_END, SourcePathString, SourceBufferSize);
+ DestinationPath->GetPathString()->QueryWSTR(0, TO_END, DestinationPathString, DestinationBufferSize );
+
+
+ if ( FsNode->IsDirectory() ) {
+
+ //
+ // Copy directory
+ //
+
+ CreateDirectoryEx( SourcePathString, DestinationPathString, NULL );
+
+ if ( Recurse ) {
+
+ if ( ((SourceDirectory = SYSTEM::QueryDirectory( SourcePath )) != NULL) &&
+ ((DestinationDirectory = SYSTEM::QueryDirectory( DestinationPath )) != NULL)) {
+
+ if ( SourceDirectory->Copy( FsnFilter,
+ DestinationDirectory,
+ Recurse,
+ OverWrite )) {
+
+ DELETE( SourceDirectory );
+ DELETE( DestinationDirectory );
+
+ SourceDirectory = NULL;
+ DestinationDirectory = NULL;
+
+ } else {
+
+ break;
+
+ }
+
+ } else {
+
+ break;
+
+ }
+
+ }
+
+ } else {
+
+ //
+ // Copy file
+ //
+ if (!CopyFile( SourcePathString, DestinationPathString, !OverWrite)) {
+
+ ReturnValue = FALSE;
+ break;
+ }
+
+ }
+
+ DELETE( Name );
+
+ DestinationPath->TruncateBase();
+
+ }
+
+
+ if (SourcePathString != NULL) {
+ FREE( SourcePathString );
+ }
+
+ if (DestinationPathString != NULL) {
+ FREE( DestinationPathString );
+ }
+
+ if (SourceDirectory != NULL ) {
+ DELETE( SourceDirectory );
+ }
+
+ if (DestinationDirectory != NULL) {
+ DELETE( DestinationDirectory );
+ }
+
+ DELETE( DestinationPath );
+ DELETE( SourcePath );
+ DELETE( Iterator );
+ DELETE( SrcFiles );
+
+ }
+
+ return ReturnValue;
+
+}
+
+ULIB_EXPORT
+PFSN_DIRECTORY
+FSN_DIRECTORY::CreateDirectoryPath (
+ IN PCPATH Path
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Creates all the directories along a path and returns the directory
+ of the deepest one.
+
+Arguments:
+
+ Path - Supplies pointer to the path
+
+Return Value:
+
+ PFSN_DIRECTORY - Returns pointer to the directory object of the
+ deepest directory created.
+
+--*/
+
+{
+
+ PARRAY DesiredComponentArray;
+ PARRAY ExistingComponentArray;
+ PITERATOR IteratorDesired;
+ PITERATOR IteratorExisting;
+ PPATH PathToCreate;
+ PWSTRING DesiredComponent;
+ PWSTRING ExistingComponent;
+ BOOLEAN OkSoFar = TRUE;
+ PFSN_DIRECTORY Directory = NULL;
+ LPWSTR Buffer = NULL;
+ ULONG BufferSize = 0;
+ ULONG Size;
+
+
+ DebugPtrAssert( Path );
+
+ //
+ // Split both paths in their component parts
+ //
+ DesiredComponentArray = Path->QueryComponentArray();
+ ExistingComponentArray = GetPath()->QueryComponentArray();
+
+ DebugPtrAssert( DesiredComponentArray );
+ DebugPtrAssert( ExistingComponentArray );
+
+ if ( DesiredComponentArray && ExistingComponentArray ) {
+
+ IteratorDesired = DesiredComponentArray->QueryIterator();
+ IteratorExisting = ExistingComponentArray->QueryIterator();
+
+ DebugPtrAssert( IteratorDesired );
+ DebugPtrAssert( IteratorExisting );
+
+ if ( IteratorDesired && IteratorExisting ) {
+
+ //
+ // Make sure that the existing components are a subset of the
+ // desired components.
+ //
+ while (TRUE) {
+
+ if (!(ExistingComponent = (PWSTRING)(IteratorExisting->GetNext()))) {
+ break;
+ }
+
+ DesiredComponent = (PWSTRING)(IteratorDesired->GetNext());
+
+ DebugPtrAssert( DesiredComponent );
+
+ if ( !DesiredComponent || ( *DesiredComponent != *ExistingComponent )) {
+
+ DebugAssert( FALSE );
+ OkSoFar = FALSE;
+ break;
+
+ }
+ }
+
+ if ( OkSoFar ) {
+
+ //
+ // Now we can start creating directories
+ //
+ // PathToCreate = GetPath()->QueryFullPath();
+ PathToCreate = GetPath()->QueryPath();
+
+ while ( DesiredComponent = (PWSTRING)(IteratorDesired->GetNext()) ) {
+
+ //
+ // One directory to create
+ //
+ PathToCreate->AppendBase( DesiredComponent, TRUE );
+
+ Size = (PathToCreate->GetPathString()->QueryChCount() + 1) * 2;
+ if ( Size > BufferSize ) {
+ if ( Buffer ) {
+ Buffer = (LPWSTR)REALLOC( Buffer, (unsigned int)Size );
+ } else {
+ Buffer = (LPWSTR)MALLOC( (unsigned int)Size );
+ }
+ DebugPtrAssert( Buffer );
+ BufferSize = Size;
+ }
+ PathToCreate->GetPathString()->QueryWSTR( 0, TO_END, (LPWSTR)Buffer, BufferSize );
+
+ OkSoFar = CreateDirectory( (LPWSTR)Buffer, NULL );
+
+ // DebugAssert( OkSoFar );
+
+ }
+
+ if ( OkSoFar ) {
+
+ //
+ // Create directory object
+ //
+ Directory = SYSTEM::QueryDirectory( Path );
+ DebugPtrAssert( Directory );
+ }
+
+ DELETE( PathToCreate );
+ }
+ }
+
+ DELETE( IteratorDesired );
+ DELETE( IteratorExisting );
+
+ }
+
+ DesiredComponentArray->DeleteAllMembers();
+ ExistingComponentArray->DeleteAllMembers();
+
+ DELETE( DesiredComponentArray );
+ DELETE( ExistingComponentArray );
+
+ return Directory;
+
+}
+
+ULIB_EXPORT
+BOOLEAN
+FSN_DIRECTORY::DeleteDirectory (
+ )
+
+/*++
+
+Routine Description:
+
+ Deltes this directory and everything underneath it.
+
+ Note that after this, the directory object must be deleted!
+
+Arguments:
+
+ none
+
+Return Value:
+
+ BOOLEAN - Return TRUE if everything was deleted
+
+--*/
+
+{
+
+ FSN_FILTER Filter;
+ PARRAY Array;
+ ULONG Size;
+ LPWSTR Buffer = NULL;
+ ULONG BufferSize = 0;
+ BOOLEAN Ok = TRUE;
+ PITERATOR Iterator;
+ PFSNODE FsNode;
+
+ Filter.Initialize();
+ Filter.SetFileName( "*.*" );
+
+ Array = QueryFsnodeArray( &Filter );
+
+ if ( Array ) {
+
+ Iterator = ( PARRAY_ITERATOR ) Array->QueryIterator( );
+ DebugPtrAssert( Iterator );
+
+ //
+ // Delete everything underneath us.
+ //
+ while ( Ok && (( FsNode = (PFSNODE)Iterator->GetNext( )) != NULL )) {
+
+ if ( FsNode->IsDirectory() ) {
+
+ //
+ // Directory, just recurse.
+ //
+ Ok = ((PFSN_DIRECTORY)FsNode)->DeleteDirectory();
+
+ } else {
+
+ //
+ // File, delete it.
+ //
+ Size = (FsNode->GetPath()->GetPathString()->QueryChCount() + 1) * 2;
+ if (Size > BufferSize) {
+ if (Buffer == NULL) {
+ Buffer = (LPWSTR)MALLOC((unsigned int)Size );
+ } else {
+ Buffer = (LPWSTR)REALLOC(Buffer, (unsigned int)Size );
+ }
+ DebugPtrAssert(Buffer);
+ BufferSize = Size;
+ }
+
+ FsNode->GetPath()->GetPathString()->QueryWSTR( 0, TO_END, Buffer, BufferSize );
+
+ Ok = DeleteFile( (LPWSTR)Buffer );
+
+ }
+ }
+
+ DELETE( Array );
+
+ }
+
+ if ( Ok ) {
+ //
+ // Commit suicide
+ //
+ Size = (GetPath()->GetPathString()->QueryChCount() + 1) * 2;
+ if (Size > BufferSize) {
+ if (Buffer == NULL) {
+ Buffer = (LPWSTR)MALLOC( (unsigned int)Size );
+ } else {
+ Buffer = (LPWSTR)REALLOC(Buffer, (unsigned int)Size );
+ }
+ DebugPtrAssert(Buffer);
+ BufferSize = Size;
+ }
+
+ GetPath()->GetPathString()->QueryWSTR( 0, TO_END, Buffer, BufferSize );
+
+ Ok = RemoveDirectory( (LPWSTR)Buffer );
+
+ FREE( Buffer );
+
+ }
+
+ return Ok;
+
+}
+
+ULIB_EXPORT
+BOOLEAN
+FSN_DIRECTORY::IsEmpty (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determines if a directory is empty (A directory is empty if has
+ no entries other than "." and ".."
+
+Arguments:
+
+ none
+
+Return Value:
+
+ BOOLEAN - TRUE if directory is empty
+ FALSE otherwise
+
+--*/
+
+{
+
+
+ PATH Path;
+ FSTRING Base;
+ WIN32_FIND_DATA FindData;
+ HANDLE Handle;
+ BOOLEAN IsEmpty;
+ PFSN_DIRECTORY SubDirectory;
+ PATH SubPath;
+ DSTRING SubBase;
+ BOOLEAN SubEmpty;
+
+
+ IsEmpty = FALSE;
+
+ if ( Path.Initialize( GetPath() ) &&
+ Base.Initialize((PWSTR) L"*.*") &&
+ Path.AppendBase( &Base ) ) {
+
+ //
+ // Get the first entry
+ //
+ Handle = FindFirstFile( &Path, &FindData );
+
+ if ( Handle == INVALID_HANDLE_VALUE ) {
+
+ //
+ // If we fail we assume that the directory
+ // is empty.
+ //
+ IsEmpty = TRUE;
+
+ } else {
+
+ if ( IsDot(FindData.cFileName) ) {
+
+ while ( TRUE ) {
+
+ if ( !FindNextFile( Handle, &FindData ) ) {
+ IsEmpty = TRUE;
+ break;
+ }
+
+ if ( !IsDot( FindData.cFileName ) ) {
+
+ // If this file is a sub-directory check to
+ // see whether or not it is empty. If it is
+ // empty then we still do not know whether or
+ // not this directory is empty.
+
+ if (FindData.dwFileAttributes &
+ FILE_ATTRIBUTE_DIRECTORY) {
+
+ if (!SubPath.Initialize(GetPath()) ||
+ !SubBase.Initialize(FindData.cFileName) ||
+ !SubPath.AppendBase(&SubBase) ||
+ !(SubDirectory =
+ SYSTEM::QueryDirectory(&SubPath))) {
+
+ break;
+ }
+
+ SubEmpty = SubDirectory->IsEmpty();
+ DELETE(SubDirectory);
+
+ if (!SubEmpty) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+ }
+ }
+
+ FindClose( Handle );
+ }
+ } else {
+
+ DebugAssert( FALSE );
+
+ }
+
+ return IsEmpty;
+
+}
+
+
+ULIB_EXPORT
+PARRAY
+FSN_DIRECTORY::QueryFsnodeArray (
+ IN PFSN_FILTER FsnFilter
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Construct and fill an ARRAY object with FSNODE object that meet the
+ criteria maintained by the supplied FSN_FILTER.
+
+Arguments:
+
+ FsnFilter - Supplies a constant pointer to an FS_FILTER which will be
+ used to determine if a found 'file' should be constructed and
+ included in the ARRAY.
+
+Return Value:
+
+ PARRAY - Returns a pointer to an ARRAY of FSNODEs. If no 'file' meets
+ the FSN_FILTER criteria returns a pointer to an empy array.
+ Returns NULL if the array couldn't be constructed or initialized.
+
+--*/
+
+{
+ REGISTER PARRAY parr;
+ REGISTER PFSNODE pfsn;
+ WIN32_FIND_DATA ffd;
+ PATH Path;
+ HANDLE hndl;
+ PFSN_FILTER Filter;
+ BOOLEAN DeleteFilter;
+
+
+ //
+ // If a filter was not provided, we use a default match-all
+ // filter.
+ //
+ if ( FsnFilter ) {
+
+ Filter = FsnFilter;
+ DeleteFilter = FALSE;
+
+ } else {
+
+ Filter = NEW FSN_FILTER;
+ DebugPtrAssert( Filter );
+ if (!Filter) {
+ return NULL;
+ }
+ Filter->Initialize();
+ DeleteFilter = TRUE;
+ }
+
+ //
+ // Initialize the ARRAY pointer
+ //
+
+ parr = NULL;
+
+ //
+ // Append the filter name to this DIRECTORY's name
+ //
+
+ Path.Initialize( (PCPATH)&_Path, TRUE);
+ Path.AppendBase( Filter->GetFileName() );
+
+ //
+ // If there are found files and the ARRAY is succesfully
+ // constructed and initialized...
+ //
+
+ if((( parr = NEW ARRAY ) != NULL ) &&
+ ( parr->Initialize( ))) {
+
+ if( ( hndl = FindFirstFile( &Path, &ffd )) != INVALID_HANDLE_VALUE ) {
+ //
+ // if there is at least one file that meetes the filter
+ // criteria, put the fsnodes in the array. Otherwise, leave
+ // the array empty
+ //
+ do {
+
+ //
+ // If the found 'file' meets the filter criteria, put the
+ // returned FSNODE in the ARRAY
+ //
+
+ if(( pfsn = Filter->QueryFilteredFsnode( this, &ffd )) != NULL ) {
+
+ //
+ // If the FSNODE can not be put in the ARRAY
+ // delete it and exit the loop.
+ //
+
+ if( ! ( parr->Put( pfsn ))) {
+ DELETE( pfsn );
+ break;
+ }
+ }
+
+ //
+ // Loop while there are still more files to find.
+ //
+
+ } while( FindNextFile( hndl, &ffd ));
+
+ //
+ // Close the search.
+ //
+
+ FindClose( hndl );
+
+ }
+ //
+ // There is no file that meets the filter criteria.
+ // Return pointer to an empty array
+ //
+
+ } else {
+
+ //
+ // There were no found files or the construction or
+ // initialization of the ARRAY failed, delete the ARRAY in case
+ // it was constructed and setup to return a NULL pointer i.e. no ARRAY
+ //
+
+ if( parr != NULL ) {
+ DELETE( parr );
+ }
+ parr = NULL;
+ }
+
+ //
+ // Return the pointer to the ARRAY (which may be NULL)
+ //
+
+ if ( DeleteFilter ) {
+ DELETE( Filter );
+ }
+
+ return( parr );
+}
+
+
+
+ULIB_EXPORT
+BOOLEAN
+FSN_DIRECTORY::Traverse (
+ IN PVOID Object,
+ IN PFSN_FILTER FsnFilter,
+ IN OUT PPATH DestinationPath,
+ IN CALLBACK_FUNCTION CallBackFunction
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Traverses a directory, calling the callback function for each node
+ (directory of file) visited. The traversal may be finished
+ prematurely when the callback function returnes FALSE.
+
+ The destination path is modified to reflect the directory structure
+ being traversed.
+
+Arguments:
+
+ Object - Supplies pointer to the object
+
+ FsnFilter - Supplies a pointer to the filter that determines the
+ nodes to be visited.
+
+ DestinationPath - Supplies pointer to path to be used with the callback
+ function.
+
+ CallBackFunction- Supplies pointer to the function to be called back
+ with the node to be visited.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the entire traversal was successful.
+
+--*/
+
+
+{
+
+ PARRAY SrcFiles;
+ PARRAY_ITERATOR Iterator;
+ PFSNODE FsNode;
+ PPATH SubDirectoryPath = NULL;
+ PFSN_DIRECTORY SubDirectory = NULL;
+ BOOLEAN StatusOk = TRUE;
+ PWSTRING Name;
+
+
+ DebugPtrAssert( FsnFilter );
+ DebugPtrAssert( CallBackFunction );
+
+ //
+ // Get array of nodes for files in the directory
+ //
+ SrcFiles = QueryFsnodeArray( FsnFilter );
+ DebugPtrAssert( SrcFiles );
+
+ //
+ // Get an iterator for processing the nodes
+ //
+ Iterator = ( PARRAY_ITERATOR ) SrcFiles->QueryIterator( );
+ DebugPtrAssert( Iterator );
+
+ //
+ // Get path
+ //
+ SubDirectoryPath = NEW PATH;
+ DebugPtrAssert( SubDirectoryPath );
+
+
+ //
+ // Visit all the nodes in the array. We recurse if the node is
+ // a directory.
+ //
+ while ( StatusOk && (( FsNode = (PFSNODE)Iterator->GetNext( )) != NULL )) {
+
+
+ if ( DestinationPath ) {
+
+ //
+ // Append the name portion of the node to the destination path.
+ //
+ Name = FsNode->QueryName();
+ DebugPtrAssert( Name );
+
+ StatusOk = DestinationPath->AppendBase( Name );
+ DebugAssert( StatusOk );
+
+ DELETE( Name );
+ }
+
+ //
+ // Visit the node
+ //
+ if ( StatusOk = CallBackFunction( Object, FsNode, DestinationPath )) {
+
+ if ( FsNode->IsDirectory() ) {
+
+ //
+ // Recurse
+ //
+ SubDirectoryPath->Initialize( FsNode->GetPath() );
+
+ SubDirectory = SYSTEM::QueryDirectory( SubDirectoryPath );
+
+ DebugPtrAssert( SubDirectory );
+
+ StatusOk = SubDirectory->Traverse( Object,
+ FsnFilter,
+ DestinationPath,
+ CallBackFunction );
+ DELETE( SubDirectory );
+
+ }
+
+ }
+
+ if ( DestinationPath ) {
+
+ //
+ // Restore the destination path
+ //
+ DestinationPath->TruncateBase();
+ }
+ }
+
+ DELETE( SrcFiles );
+ DELETE( Iterator );
+ DELETE( SubDirectoryPath );
+
+ return StatusOk;
+}
diff --git a/private/utils/ulib/src/error.cxx b/private/utils/ulib/src/error.cxx
new file mode 100644
index 000000000..65e3c3e11
--- /dev/null
+++ b/private/utils/ulib/src/error.cxx
@@ -0,0 +1,510 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+
+DEFINE_CONSTRUCTOR( ERRSTACK, OBJECT );
+
+
+
+
+
+
+
+
+#if 0 // Note davegi Fix....
+
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "bitvect.hxx"
+// #include "string.hxx"
+// #include "path.hxx"
+// #include "message.hxx"
+
+
+/**************************************************************************\
+
+MEMBER: ERROR
+
+SYNOPSIS: constructor for ERROR object using no parameters
+
+ALGORITHM:
+
+ARGUMENTS:
+
+RETURNS: pointer to ERROR objects
+
+NOTES: Constructs an empty error object with no initialized error code
+ or Class Id.
+
+HISTORY: 3-7-90
+
+KEYWORDS: ERROR
+
+SEEALSO:
+\**************************************************************************/
+
+ERROR::ERROR (
+ ) : OBJECT(ID_ERROR) {
+
+ err = 0;
+ id = 0;
+}
+
+
+
+/**************************************************************************\
+
+MEMBER: ERROR
+
+SYNOPSIS: constructor for ERROR object
+
+ALGORITHM:
+
+ARGUMENTS: errIn - error code
+ idIn - class id
+ pmsgIn - pointer to message (optional)
+
+RETURNS: pointer to ERROR objects
+
+NOTES: Class id is usually the class id where the error occured. In cases
+ where there is no class id then a special class id below ID_BASE
+ should be defined. There is currently a generic id called
+ ID_NOT_AN_OBJECT that can be used if no more information is needed.
+
+HISTORY: 3-6-90
+
+KEYWORDS: ERROR
+
+SEEALSO:
+\**************************************************************************/
+
+/******************************
+ERROR::ERROR (
+ ERRCODE errIn,
+ CLASS_ID idIn,
+ const MESSAGE * pmsgIn
+ ) : OBJECT(ID_ERROR) {
+
+ err = errIn;
+ id = idIn;
+ pmsg = NULL;
+ if (pmsgIn) {
+ pmsg = NEW MESSAGE(*pmsgIn);
+ }
+
+}
+*****************************/
+
+/**************************************************************************\
+
+MEMBER: ~ERROR
+
+SYNOPSIS: destructor for the error
+
+ALGORITHM: delete the message pointed to in ERROR
+
+ARGUMENTS:
+
+RETURNS:
+
+NOTES:
+
+HISTORY: 3-6-90
+
+KEYWORDS: ERRROR ERRSTK
+
+SEEALSO:
+\**************************************************************************/
+ERROR::~ERROR (
+ ) {
+
+// if (pmsg) {
+// delete pmsg;
+// }
+}
+
+
+/**************************************************************************\
+
+MEMBER: operator=
+
+SYNOPSIS: assignment operator for assigning one error to another.
+
+ALGORITHM:
+
+ARGUMENTS: error - reference to error to assign from.
+
+RETURNS: reference to ERROR object assigned to.
+
+NOTES: This is used in ERRSTK to copy the ERROR object locally.
+
+HISTORY: 3-7-90
+
+KEYWORDS: ERROR
+
+SEEALSO:
+\**************************************************************************/
+
+ERROR &
+ERROR::operator= (
+ ERROR & error
+ ) {
+
+ err = error.QueryErr();
+ id = error.QueryClassId();
+// pmsg = NEW MESSAGE(*error.GetMsg());
+ return(*this);
+
+}
+
+/**************************************************************************\
+
+MEMBER: ERRSTK
+
+SYNOPSIS: constructor for error stack.
+
+ALGORITHM:
+
+ARGUMENTS: cpoIn - size of stack to alloc. (# of entries)
+
+RETURNS:
+
+NOTES: The actual amount alloc'd is cpoIn + 1. One slot is reserved
+ for a stack overflow error. A QueryCount should be done to
+ determine if stack could be allocated.
+
+ Pointers to ERROR objects are put in this stack. The scope
+ of these pointers is assumed to be global.
+
+HISTORY: 3-6-90
+
+KEYWORDS: ERRSTK
+
+SEEALSO: ERROR
+\**************************************************************************/
+
+ERRSTACK::ERRSTACK (
+ ULONG cpoInitIn,
+ ULONG cpoIncIn
+ ) : OBJECT (ID_ERRSTACK) {
+
+ ipoCur = cpoMax = 0;
+ cpoInit = cpoInitIn;
+ if (cpoIncIn) {
+ cpoInc = cpoIncIn;
+ } else {
+ cpoInc = cpoInitIn;
+ }
+ // save 1 slot for stack overflow
+ if (papo = (ERROR **)malloc((size_t)(++cpoInit) * (sizeof (ERROR *)))) {
+ cpoMax = cpoInit;
+ }
+
+}
+
+/**************************************************************************\
+
+MEMBER: ~ERRSTK
+
+SYNOPSIS: destructor for the error stack
+
+ALGORITHM: delete each error in the stack then free space used for stack
+
+ARGUMENTS:
+
+RETURNS:
+
+NOTES:
+
+HISTORY: 3-6-90
+
+KEYWORDS: ERRSTK
+
+SEEALSO: ERROR
+\**************************************************************************/
+
+ERRSTACK::~ERRSTACK (
+ ) {
+
+ for (ULONG i = ipoCur; i > 0; i--) {
+ delete papo[i];
+ }
+ if (papo) {
+ free((void *)papo);
+ }
+}
+
+/**************************************************************************\
+
+MEMBER: ClearStack
+
+SYNOPSIS: deletes error in stack but does not free stack.
+
+ALGORITHM:
+
+ARGUMENTS:
+
+RETURNS: number of free entries in stack.
+
+NOTES:
+
+HISTORY: 5-6-90
+
+KEYWORDS: ERRSTK ClearStack
+
+SEEALSO: ERROR
+\**************************************************************************/
+ULONG
+ERRSTACK::ClearStack (
+ ) {
+
+ for (ULONG i = ipoCur; i > 0; i--) {
+ /* delete papo[i]; */
+ papo[i] = (ERROR *)NULL;
+ }
+ papo = (ERROR **)realloc(papo, (size_t)cpoInit * (sizeof (ERROR *))); // can't fail. realloc down
+
+ ipoCur = 0;
+ cpoMax = cpoInit;
+ return(cpoMax);
+}
+
+/**************************************************************************\
+
+MEMBER: AllocError
+
+SYNOPSIS: Alocates an ERROR object and pushes it on the stack.
+
+ALGORITHM:
+
+ARGUMENTS:
+
+RETURNS: pointer to ERROR object on the top of the stack if a
+ push occurred. If the ERROR object could not be alloc'd
+ then NULL is returned.
+
+NOTES: This is used internally by push with error code argument.
+ It creates an uninitiallized ERROR object and pushes it on the
+ stack. If there is no room it grows the stack. If it can't
+ grow the stack it pushes a stack overflow error on the stack.
+ Space is always available for the stack overflow error.
+
+HISTORY: 3-14-90
+
+KEYWORDS: ERRSTK AllocError
+
+SEEALSO: ERROR
+\**************************************************************************/
+ERROR *
+ERRSTACK::AllocError(
+ ) {
+
+ ERROR ** papoT;
+
+ // Note: optimize by precompute cpoMax - 1
+ if (ipoCur == (cpoMax - 1)) { // stack full
+ return((ERROR *)NULL);
+ }
+
+ if ((papo[++ipoCur] = NEW ERROR ()) == NULL) {
+ ipoCur--; // don't leave a null pointer to stack
+ return((ERROR *)NULL); // can't push create an error on stack
+ }
+
+ if (ipoCur == (cpoMax - 1)) {
+ if ((papoT = (ERROR **)realloc(papo, (size_t)((sizeof (ERROR *)) * (cpoMax = (cpoMax + cpoInc))))) == NULL) {
+// (papo[ipoCur])->PutIdErrMsg(this->QueryClassId(), ERR_ERRSTK_STACK_OVERFLOW);
+ } else {
+ papo = papoT;
+ }
+ }
+
+ return(papo[ipoCur]);
+
+}
+
+/**************************************************************************\
+
+MEMBER: push
+
+SYNOPSIS: pushes a pointer to an ERROR object onto the stack
+
+ALGORITHM:
+
+ARGUMENTS: perr - pointer to ERROR object
+
+RETURNS: pointer to ERROR object pushed. This is not be the same
+ as the perr argument. perr is copied to the stack.
+
+NOTES: The ERROR objected is copied so it's scope should
+ match that of the ERRSTK.
+
+HISTORY: 3-6-90
+
+KEYWORDS: push ERRSTK
+
+SEEALSO: ERROR
+\**************************************************************************/
+
+ERROR *
+ERRSTACK::push (
+ const ERROR *perr
+ ) {
+
+ if (AllocError()) {
+ return(&(*(papo[ipoCur]) = *( ERROR *)perr));
+ } else {
+ return((ERROR *)NULL);
+ }
+}
+
+/**************************************************************************\
+
+MEMBER: push
+
+SYNOPSIS: The form of push takes direct error arguments, creates an ERROR
+ object and pushes it on the stack.
+
+ALGORITHM:
+
+ARGUMENTS: errcoIn - error code
+ idIn - class id
+ pmsgIn - pointer to message object. (optional)
+
+RETURNS: pointer to ERROR object pushed. This is not be the same
+ as the perr argument. perr is copied to the stack.
+
+NOTES: The ERROR objected is copied so it's scope should
+ match that of the ERRSTK.
+
+HISTORY: 3-6-90
+
+KEYWORDS: push ERRSTK
+
+SEEALSO: ERROR
+\**************************************************************************/
+ERROR *
+ERRSTACK::push (
+ ERRCODE errcoIn,
+ CLASS_ID idIn
+ ) {
+
+ ERROR *perrT;
+
+ if ((perrT = AllocError()) != NULL) {
+ if (perrT->QueryErr() != ERR_ERRSTK_STACK_OVERFLOW) {
+// return(perrT->PutIdErrMsg(idIn, errcoInIn));
+ }
+ }
+ return(perrT);
+}
+
+/**************************************************************************\
+
+MEMBER: pop
+
+SYNOPSIS: pop's a pointer to an ERROR object of the stack
+
+ALGORITHM:
+
+ARGUMENTS:
+
+RETURNS: pointer to a ERROR object. If the stack is empty NULL is returned.
+
+NOTES:
+
+HISTORY: 3-6-90
+
+KEYWORDS: pop ERRSTK
+
+SEEALSO: ERROR
+\**************************************************************************/
+
+ERROR *
+ERRSTACK::pop(
+ ) {
+
+ if (!ipoCur) { // stack empty
+ return((ERROR *)NULL);
+ }
+ return(papo[ipoCur--]);
+
+}
+
+#ifdef DEBUG
+
+/**************************************************************************\
+
+MEMBER: print
+
+SYNOPSIS: prints each error on the stack to standard out
+
+ALGORITHM:
+
+ARGUMENTS:
+
+RETURNS: # of errors printed.
+
+NOTES:
+
+HISTORY: 3-6-90
+
+KEYWORDS: print ERRSTK
+
+SEEALSO: ERROR
+\**************************************************************************/
+
+ULONG
+ERRSTACK::print(
+ ) {
+
+ printf("Error Stack: entries = %ld, Top of Stack = %ld, Size of Stack = %ld\n", QueryCount(), QueryTop(), QuerySize());
+ if (!ipoCur) {
+ printf("\tError: stack empty\n");
+ return(0);
+ }
+
+ for (ULONG i = ipoCur; i > 0 ; i--) { // 0 not used.
+ printf("\t");
+ (papo[i])->print();
+ }
+ return(QueryCount());
+}
+
+/**************************************************************************\
+
+MEMBER: print
+
+SYNOPSIS: print a error to standard out
+
+ALGORITHM:
+
+ARGUMENTS:
+
+RETURNS:
+
+NOTES:
+
+HISTORY:
+
+KEYWORDS:
+
+SEEALSO:
+\**************************************************************************/
+
+BOOL
+ERROR::print(
+ ) {
+
+ printf("Error: id:%x, error:%X\n", id, err);
+ return(TRUE);
+}
+
+#endif
+
+#endif // 0 Note davegi Fix....
diff --git a/private/utils/ulib/src/file.cxx b/private/utils/ulib/src/file.cxx
new file mode 100644
index 000000000..eeb5e460a
--- /dev/null
+++ b/private/utils/ulib/src/file.cxx
@@ -0,0 +1,251 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ file.cxx
+
+Abstract:
+
+ This module contains the definition for the FSN_FILE class.
+
+Author:
+
+ David J. Gilman (davegi) 09-Jan-1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "system.hxx"
+#include "file.hxx"
+#include "timeinfo.hxx"
+
+DEFINE_CONSTRUCTOR( FSN_FILE, FSNODE );
+
+DEFINE_CAST_MEMBER_FUNCTION( FSN_FILE );
+
+
+
+ULIB_EXPORT
+BOOLEAN
+FSN_FILE::Copy (
+ IN OUT PPATH NewFile,
+ OUT PCOPY_ERROR CopyError,
+ IN BOOLEAN OverwriteReadOnly,
+ IN BOOLEAN ResetReadOnly,
+ IN BOOLEAN Restartable,
+ IN LPPROGRESS_ROUTINE CallBack,
+ IN VOID * Data,
+ IN PBOOL Cancel
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Copies this file to another path. If appropriate the NewFile
+ will be altered to its "short" (FAT) form before the copy.
+
+Arguments:
+
+ NewFile - Supplies path of new file. All the subdirectories must
+ exist.
+
+ CopyError - Supplies pointer to variable that receives the
+ error code.
+
+ OverwriteReadOnly - Supplies flag which if TRUE means that read-only files
+ should be overwritten.
+
+ ResetReadOnly - Supplies flag which if TRUE causes the readonly flag
+ in the target to be reset.
+
+ Restartable - Copy is restartable.
+
+ Callback - Pointer to callback routine passed to CopyFileEx.
+
+ Data - Pointer to opaque data passed to CopyFileEx.
+
+ Cancel - Pointer to cancel flag passed to CopyFileEx.
+
+Return Value:
+
+ BOOLEAN - TRUE if the file was successfully copied,
+ FALSE otherwise.
+
+--*/
+
+{
+
+ PCWSTR Source;
+ PCWSTR Destination;
+ BOOLEAN CopiedOk = FALSE;
+ FSN_FILE File;
+ DWORD Attr;
+ WIN32_FIND_DATA FindData;
+ FSTRING AlternateFileName;
+
+
+ Source = GetPath()->GetPathString()->GetWSTR();
+ DebugPtrAssert( Source );
+
+ if ( Source ) {
+
+ Destination = NewFile->GetPathString()->GetWSTR();
+ DebugPtrAssert( Destination );
+
+ if ( Destination ) {
+
+ CopiedOk = TRUE;
+
+ //
+ // If we must overwrite read-only files, we must
+ // get the file attributes and change to writeable.
+ //
+ // What we should do here is do
+ // a SYSTEM::QueryFile of the destination file and
+ // use the FILE methods for resetting the read-only
+ // attribute. However this is faster!
+ //
+ if ( OverwriteReadOnly ) {
+
+ Attr = GetFileAttributes( (LPWSTR) Destination );
+
+ if (Attr != -1 &&
+ (Attr & (FILE_ATTRIBUTE_READONLY |
+ FILE_ATTRIBUTE_HIDDEN |
+ FILE_ATTRIBUTE_SYSTEM))) {
+
+ Attr &= ~( FILE_ATTRIBUTE_READONLY |
+ FILE_ATTRIBUTE_HIDDEN |
+ FILE_ATTRIBUTE_SYSTEM );
+
+ if ( !SetFileAttributes( (LPWSTR) Destination, Attr ) ) {
+ CopiedOk = FALSE;
+ }
+ }
+ }
+
+ //
+ // Copy the file
+ //
+ if ( CopiedOk ) {
+ CopiedOk = CopyFileEx( (LPWSTR) Source,
+ (LPWSTR) Destination,
+ CallBack,
+ Data,
+ (LPBOOL) Cancel,
+ Restartable ? COPY_FILE_RESTARTABLE : 0);
+ }
+
+ if ( CopiedOk && ResetReadOnly ) {
+
+ FindData = _FileData;
+ NewFile->GetPathString()->QueryWSTR( 0,
+ TO_END,
+ FindData.cFileName,
+ MAX_PATH );
+ FindData.cAlternateFileName[ 0 ] = ( WCHAR )'\0';
+
+
+ if( File.Initialize( NewFile->GetPathString(),
+ &FindData ) ) {
+
+ File.ResetReadOnlyAttribute();
+
+ } else {
+
+ //
+ // The file is no longer there, we fail the copy
+ //
+ CopiedOk = FALSE;
+ *CopyError = (COPY_ERROR) ERROR_FILE_NOT_FOUND;
+ }
+
+
+
+ } else if ( !CopiedOk && CopyError ) {
+
+ *CopyError = (COPY_ERROR)GetLastError();
+
+ }
+ }
+ }
+
+ return CopiedOk;
+
+}
+
+
+
+BOOLEAN
+FSN_FILE::DeleteFromDisk(
+ IN BOOLEAN Force
+ )
+{
+ PCWSTR FileName;
+
+ UNREFERENCED_PARAMETER( Force );
+
+ if ( FileName = _Path.QueryFullPathString()->GetWSTR() ) {
+
+ if ( FileName[0] != (WCHAR)'\0' ) {
+ return DeleteFile( (LPWSTR) FileName );
+ }
+ }
+
+ return FALSE;
+}
+
+
+
+
+ULIB_EXPORT
+PFILE_STREAM
+FSN_FILE::QueryStream (
+ STREAMACCESS Access
+ )
+
+/*++
+
+Routine Description:
+
+ Creates a FILE_STREAM object associated with the file described
+ by FSN_FILE, and returns the pointer to the FILE_STREAM.
+
+
+Arguments:
+
+ Access - Desired access to the stream
+
+Return Value:
+
+ PFILE_STREAM - Returns a pointer to a FILE_STREAM, or NULL
+ if the FILE_STREAM couldn't be created.
+
+--*/
+
+{
+ PFILE_STREAM FileStream;
+
+ if( IsReadOnly() && ( Access != READ_ACCESS ) ) {
+ return( NULL );
+ }
+ FileStream = NEW( FILE_STREAM );
+ DebugPtrAssert( FileStream );
+ if( !FileStream->Initialize( this, Access ) ) {
+ DELETE( FileStream );
+ return( NULL );
+ }
+ return( FileStream );
+}
diff --git a/private/utils/ulib/src/filestrm.cxx b/private/utils/ulib/src/filestrm.cxx
new file mode 100644
index 000000000..6516b9186
--- /dev/null
+++ b/private/utils/ulib/src/filestrm.cxx
@@ -0,0 +1,937 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ filestrm.cxx
+
+Abstract:
+
+ This module contains the definitions of the member functions
+ of FILE_STREAM class.
+
+Author:
+
+ Jaime Sasson (jaimes) 24-Mar-1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include <pch.cxx>
+
+#define BUFFER_SIZE 256
+#define BIG_BUFFER_SIZE (64 * 1024)
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "file.hxx"
+#include "wstring.hxx"
+#include "stream.hxx"
+#include "bufstrm.hxx"
+#include "filestrm.hxx"
+
+
+DEFINE_CONSTRUCTOR ( FILE_STREAM, BUFFER_STREAM );
+
+DEFINE_EXPORTED_CAST_MEMBER_FUNCTION( FILE_STREAM , ULIB_EXPORT );
+
+
+FILE_STREAM::~FILE_STREAM (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy a FILE_STREAM.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if( ( _MemoryMappedFile ) && !_EmptyFile ) {
+ if( _FileBaseAddress != 0 ) {
+ UnmapViewOfFile( _FileBaseAddress );
+ }
+ if( _FileMappingHandle != NULL ) {
+ CloseHandle( _FileMappingHandle );
+ _FileMappingHandle = NULL;
+ }
+ }
+ if( _ShouldCloseHandle ) {
+ if( _FileHandle != NULL ) {
+ CloseHandle( _FileHandle );
+ _FileHandle = NULL;
+ }
+ }
+}
+
+
+
+VOID
+FILE_STREAM::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Constructs a FILE_STREAM object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ _FileHandle = NULL;
+ _FileMappingHandle = NULL;
+ _EndOfFile = FALSE;
+ _ShouldCloseHandle = FALSE;
+ _FileBaseAddress = 0;
+ _MemoryMappedFile = FALSE;
+ _EmptyFile = FALSE;
+}
+
+
+
+
+
+
+
+BOOLEAN
+FILE_STREAM::Initialize(
+ IN PCFSN_FILE File,
+ IN STREAMACCESS Access
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes an object of type FILE_STREAM.
+
+Arguments:
+
+ PCFSN_FILE - Pointer to a FSN_FILE object (will provide the filename).
+
+ STREAMACCESS - Access allowed in the stream.
+
+
+Return Value:
+
+ None.
+
+
+--*/
+
+
+{
+ ULONG DesiredAccess;
+ ULONG CreationDisposition;
+ ULONG ShareMode;
+ PCPATH Path;
+ PCWSTRING String;
+// PCWC_STRING String;
+ PCWSTR FileName;
+ BOOLEAN MappingFailed = FALSE;
+
+ DebugPtrAssert( File );
+
+ _Access = Access;
+ _EndOfFile = FALSE;
+ _ShouldCloseHandle = TRUE;
+ _EmptyFile = FALSE;
+ if (_Access == READ_ACCESS) {
+ _MemoryMappedFile = TRUE;
+ } else {
+ _MemoryMappedFile = FALSE;
+ }
+
+ Path = File->GetPath();
+ String = Path->GetPathString();
+ FileName = String->GetWSTR();
+
+ if( Access == READ_ACCESS ) {
+ DesiredAccess = GENERIC_READ;
+ CreationDisposition = OPEN_EXISTING;
+ ShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE;
+ } else if( Access == WRITE_ACCESS ) {
+ DesiredAccess = GENERIC_WRITE;
+ CreationDisposition = OPEN_ALWAYS;
+ ShareMode = FILE_SHARE_READ;
+ } else {
+ DesiredAccess = GENERIC_READ | GENERIC_WRITE;
+ CreationDisposition = OPEN_EXISTING;
+ ShareMode = FILE_SHARE_READ;
+ }
+
+ _FileHandle = CreateFile( (LPWSTR) FileName,
+ DesiredAccess,
+ ShareMode,
+ NULL, // Security attributes
+ CreationDisposition,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL );
+ if( _FileHandle == INVALID_HANDLE_VALUE ) {
+ return( FALSE );
+ }
+
+ //
+ // If stream is to be created with READ_ACCESS, then map file
+ // in memory
+ //
+
+ if( _MemoryMappedFile ) {
+ if( ( _FileSize = File->QuerySize() ) == 0 ) {
+ //
+ // Empty file that is also read-only, cannot be mapped in
+ // memory, but we pretend we do it
+ //
+ _FileBaseAddress = NULL;
+ _EmptyFile = TRUE;
+ _EndOfFile = TRUE;
+ } else {
+ _FileMappingHandle = CreateFileMapping( _FileHandle,
+ NULL,
+ PAGE_READONLY,
+ 0,
+ 0,NULL );
+ if( _FileMappingHandle == NULL ) {
+ CloseHandle( _FileHandle );
+ _FileHandle = NULL;
+ DebugPrintf( "GetLastError() = %x \n", GetLastError() );
+ DebugAbort( "CreateFileMapping() failed" );
+ return( FALSE );
+ }
+ _FileBaseAddress = ( PBYTE )MapViewOfFile( _FileMappingHandle,
+ FILE_MAP_READ,
+ 0,
+ 0,
+ 0 );
+
+ if( _FileBaseAddress == NULL ) {
+ DebugPrintf("map view of file failed with %d\n", GetLastError());
+ CloseHandle( _FileMappingHandle );
+ _FileMappingHandle = NULL;
+ _MemoryMappedFile = FALSE;
+ MappingFailed = TRUE;
+ }
+ }
+
+ if (_MemoryMappedFile) {
+ _CurrentByte = _FileBaseAddress;
+ //
+ // If the file is maped in memory then we don't need
+ // a buffer. For this reason BUFFER_STREAM is initialized
+ // with zero
+ //
+ return( BUFFER_STREAM::Initialize( 0 ) );
+ }
+ }
+
+ if (!_MemoryMappedFile) {
+
+ //
+ // If the stream is to be created with WRITE or READ_AND_WRITE
+ // access, then allocate a buffer. If we attempted to map
+ // the file and failed, it must be very large--use a big
+ // buffer.
+ //
+ return( BUFFER_STREAM::Initialize( MappingFailed ?
+ BIG_BUFFER_SIZE :
+ BUFFER_SIZE ) );
+ }
+
+ return FALSE; // Keep compiler happy.
+}
+
+
+
+
+BOOLEAN
+FILE_STREAM::Initialize(
+ IN HANDLE FileHandle,
+ IN STREAMACCESS Access
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes an object of type FILE_STREAM.
+
+Arguments:
+
+ FileHandle - File handle.
+
+ Access - Access allowed in the stream.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the initialization succeeded.
+
+
+--*/
+
+
+{
+ BOOLEAN MappingFailed = FALSE;
+
+ _Access = Access;
+ _EndOfFile = FALSE;
+ _ShouldCloseHandle = FALSE;
+ _FileHandle = FileHandle;
+
+ if (_Access == READ_ACCESS) {
+ _MemoryMappedFile = TRUE;
+ } else {
+ _MemoryMappedFile = FALSE;
+ }
+
+ //
+ // If stream is to be creadted with READ access, then map file in
+ // memory
+ //
+ if( _MemoryMappedFile ) {
+ _FileSize = SetFilePointer( _FileHandle, 0, NULL, FILE_END );
+ if( _FileSize == -1 ) {
+ return( FALSE );
+ }
+ if( _FileSize == 0 ) {
+ //
+ // Empty file that is also read only cannot be mapped in
+ // memory, but we pretend we do it.
+ //
+ _FileBaseAddress = NULL;
+ _EmptyFile = TRUE;
+ _EndOfFile = TRUE;
+ } else {
+ _FileMappingHandle = CreateFileMapping( _FileHandle,
+ NULL,
+ PAGE_READONLY,
+ 0,
+ 0,NULL );
+ if( _FileMappingHandle == NULL ) {
+ return( FALSE );
+ }
+ _FileBaseAddress = ( PBYTE )MapViewOfFile( _FileMappingHandle,
+ FILE_MAP_READ,
+ 0,
+ 0,
+ 0 );
+
+ if( _FileBaseAddress == NULL ) {
+ CloseHandle( _FileMappingHandle );
+ _FileMappingHandle = NULL;
+ MappingFailed = TRUE;
+ _MemoryMappedFile = FALSE;
+ }
+ }
+
+ if (_MemoryMappedFile) {
+ _CurrentByte = _FileBaseAddress;
+ return( BUFFER_STREAM::Initialize( 0 ) );
+ }
+ }
+ //
+ // If stream is to be created with WRITE and READ_AND_WRITE access,
+ // then allocate a buffer. Or the file was so big that it couldn't
+ // be mapped into memory. If the mapping failed, use a big buffer.
+
+ return( BUFFER_STREAM::Initialize( MappingFailed ?
+ BIG_BUFFER_SIZE :
+ BUFFER_SIZE ) );
+}
+
+
+
+BOOLEAN
+FILE_STREAM::AdvanceBufferPointer(
+ IN ULONG Offset
+ )
+
+/*++
+
+Routine Description:
+
+ Advance the buffer pointer by an offset. (Removes bytes from
+ the buffer)
+
+Arguments:
+
+ Offset - Number of bytes to remove from the buffer.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the pointer was advanced, or FALSE if the
+ offset was greater than the number of bytes in the buffer.
+
+
+--*/
+
+{
+ if( _MemoryMappedFile ) {
+ return( MovePointerPosition( (LONG)Offset, STREAM_CURRENT ));
+ } else {
+ return( BUFFER_STREAM::AdvanceBufferPointer( Offset ) );
+ }
+}
+
+
+
+BOOLEAN
+FILE_STREAM::FillBuffer(
+ IN PBYTE Buffer,
+ IN ULONG BufferSize,
+ OUT PULONG BytesRead
+ )
+
+/*++
+
+Routine Description:
+
+ Fills a buffer with bytes read from a file.
+ This function will fill the buffer only if the stream has
+ READ_AND_WRITE access.
+ It won't do anything if the stream has READ access. (In this case
+ the file was mapped in memory and the buffer was not defined).
+
+
+Arguments:
+
+ Buffer - Buffer where the bytes are to be stored.
+
+ BufferSize - Size of the buffer.
+
+ BytesRead - Pointer to the variable that will contain the number of bytes
+ put in the buffer.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the buffer was filled. FALSE otherwise.
+
+
+--*/
+
+{
+ BOOLEAN Result;
+
+ DebugPtrAssert( Buffer );
+ DebugPtrAssert( BytesRead );
+
+ Result = FALSE;
+ if( _Access != WRITE_ACCESS ) {
+ Result = ReadFile( _FileHandle,
+ Buffer,
+ BufferSize,
+ BytesRead,
+ NULL );
+ if( Result && ( *BytesRead == 0 ) ) {
+ _EndOfFile = TRUE;
+ }
+ }
+ return( Result );
+}
+
+
+
+PCBYTE
+FILE_STREAM::GetBuffer(
+ PULONG BytesInBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ Returns the pointer to the buffer, and the number of bytes in
+ the buffer.
+
+Arguments:
+
+ BytesInBuffer - Points to the variable that will contain the number
+ of bytes in the buffer being returned.
+
+
+Return Value:
+
+ PCBYTE - Pointer to the buffer.
+
+--*/
+
+
+{
+ if( _MemoryMappedFile ) {
+ *BytesInBuffer = _FileSize - ( _CurrentByte - _FileBaseAddress );
+ BUFFER_STREAM::DetermineStreamType(&_CurrentByte,*BytesInBuffer);
+ return( _CurrentByte );
+ } else {
+ return( BUFFER_STREAM::GetBuffer( BytesInBuffer ));
+ }
+}
+
+
+BOOLEAN
+FILE_STREAM::MovePointerPosition(
+ IN LONG Position,
+ IN SEEKORIGIN Origin
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the file pointer to a particular position.
+
+Arguments:
+
+ Position - Indicates the displacement in relation to the Origin
+ where the file pointer is to be moved.
+
+ Origin - Defines the origin of the stream.
+
+
+Return Value:
+
+ BOOLEAN - Indicates if the seek operation succeeded.
+
+
+--*/
+
+
+{
+ ULONG NewPosition;
+ ULONG MoveMethod;
+ PBYTE Pointer;
+
+ if( _MemoryMappedFile ) {
+ //
+ // The file IS mapped on memory
+ //
+ if( Origin == STREAM_BEGINNING ) {
+ Pointer = _FileBaseAddress;
+ } else if( Origin == STREAM_CURRENT ) {
+ Pointer = _CurrentByte;
+ } else {
+ Pointer = _FileBaseAddress + _FileSize - 1;
+ }
+ Pointer += Position;
+ if( ( Pointer < _FileBaseAddress ) ||
+ ( Pointer > _FileBaseAddress + _FileSize ) ) {
+ _CurrentByte = Pointer;
+ _EndOfFile = ( BOOLEAN )( Pointer >= _FileBaseAddress + _FileSize );
+ return( FALSE );
+ }
+ _CurrentByte = Pointer;
+ _EndOfFile = ( BOOLEAN )( Pointer == _FileBaseAddress + _FileSize );
+
+ } else {
+ //
+ // The file IS NOT mapped in memory, so access to the file
+ // must be through APIs.
+ //
+ if( Origin == STREAM_BEGINNING ) {
+ MoveMethod = FILE_BEGIN;
+ } else if( Origin == STREAM_CURRENT ) {
+ MoveMethod = FILE_CURRENT;
+ } else {
+ MoveMethod = FILE_END;
+ }
+ NewPosition = SetFilePointer( _FileHandle,
+ Position,
+ 0,
+ MoveMethod );
+ if( NewPosition == ( ULONG )-1 ) {
+ return( FALSE );
+ }
+ //
+ // Since the file is buffered, we have to flush the buffer.
+ // The return value of FlushBuffer can be ignored because
+ // the file pointer was already moved to the right position.
+ //
+ BUFFER_STREAM::FlushBuffer();
+ _EndOfFile = FALSE;
+ }
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+FILE_STREAM::QueryPointerPosition(
+ OUT PULONG Position
+ )
+
+/*++
+
+Routine Description:
+
+ Returns the position of the file pointer in relation to the beginning of
+ the stream.
+
+Arguments:
+
+ Position - Address of the variable that will contain the position of the
+ file pointer.
+
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+
+{
+ ULONG BytesInBuffer;
+
+ if( _MemoryMappedFile ) {
+ *Position = ( _CurrentByte - _FileBaseAddress );
+ } else {
+ *Position = SetFilePointer( _FileHandle,
+ 0,
+ 0,
+ FILE_CURRENT );
+ if( *Position == ( ULONG )-1 ) {
+ return( FALSE );
+ }
+ //
+ // Needs to subtract the number of bytes in the buffer
+ // to obtain the position where the client thinks that
+ // the pointer is.
+ //
+ BUFFER_STREAM::GetBuffer( &BytesInBuffer );
+ *Position -= BytesInBuffer;
+ }
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+FILE_STREAM::Read(
+ OUT PBYTE Buffer,
+ IN ULONG BytesToRead,
+ OUT PULONG BytesRead
+ )
+
+/*++
+
+Routine Description:
+
+ Reads data from the file.
+
+Arguments:
+
+ Buffer - Points to the buffer where the data will be put.
+
+ BytesToRead - Indicates total number of bytes to read from the stream.
+
+ BytesRead - Points to the variable that will contain the number of
+ bytes read.
+
+Return Value:
+
+ BOOLEAN - Indicates if the read operation succeeded. If there was no
+ data to be read (end of stream), the return value will be
+ TRUE (to indicate success), but NumberOfBytesRead will be
+ zero.
+
+
+--*/
+
+{
+ if( _MemoryMappedFile ) {
+ if( ( _CurrentByte + BytesToRead ) > _FileBaseAddress + _FileSize ) {
+ BytesToRead = _FileBaseAddress + _FileSize - _CurrentByte;
+ }
+ __try {
+ memcpy( Buffer, _CurrentByte, ( size_t )BytesToRead );
+ }
+ __except( GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR ) {
+ return( FALSE );
+ }
+ *BytesRead = BytesToRead;
+ _CurrentByte += BytesToRead;
+ if( _CurrentByte >= _FileBaseAddress + _FileSize ) {
+ _EndOfFile = TRUE;
+ }
+ return( TRUE );
+ } else {
+ return( BUFFER_STREAM::Read( Buffer, BytesToRead, BytesRead ) );
+ }
+}
+
+
+
+ULIB_EXPORT
+BOOLEAN
+FILE_STREAM::ReadAt(
+ OUT PBYTE Buffer,
+ IN ULONG BytesToRead,
+ IN LONG Position,
+ IN SEEKORIGIN Origin,
+ OUT PULONG BytesRead
+ )
+
+/*++
+
+Routine Description:
+
+ Reads data from the file stream at a specified position.
+
+Arguments:
+
+ Buffer - Points to the buffer where the data will be put.
+
+ BytesToRead - Indicates total number of bytes to read from the stream.
+
+ Position - Position in the stream where data is to be read from,
+ relative to the origin of the stream.
+
+ Origin - Indicates what position in the stream should be used
+ as origin.
+
+ BytesRead - Points to the variable that will contain the number of
+ bytes read.
+
+
+Return Value:
+
+ BOOLEAN - Indicates if the read operation succeeded. If there was no
+ data to be read (end of stream), the return value will be
+ TRUE (to indicate success), but BytesRead will be zero.
+
+
+--*/
+
+{
+ BOOLEAN Result;
+ ULONG SavedPosition;
+
+ DebugPtrAssert( Buffer );
+ DebugPtrAssert( BytesRead );
+
+ Result = FALSE;
+ if( QueryPointerPosition( &SavedPosition ) &&
+ MovePointerPosition( Position, Origin ) &&
+ Read( Buffer, BytesToRead, BytesRead ) ) {
+ Result = MovePointerPosition( SavedPosition, STREAM_BEGINNING );
+ }
+ return( Result );
+}
+
+
+
+BOOLEAN
+FILE_STREAM::Write(
+ IN PCBYTE Buffer,
+ IN ULONG BytesToWrite,
+ OUT PULONG BytesWritten
+ )
+
+/*++
+
+Routine Description:
+
+ Writes data a file stream with WRITE_ACCESS or READ_AND_WRITE_ACCESS.
+
+Arguments:
+
+ Buffer - Points to the buffer that contains the data to be written.
+
+ BytesToWrite - Indicates total number of bytes to write to the stream.
+
+ BytesWritten - Points to the variable that will contain the number of
+ bytes written.
+
+Return Value:
+
+ BOOLEAN - Indicates if the write operation succeeded.
+
+
+--*/
+
+{
+ LONG Offset;
+
+ DebugPtrAssert( Buffer );
+ DebugPtrAssert( BytesWritten );
+
+ //
+ // If the stream have READ_AND_WRITE_ACCESS, we have to flush the
+ // buffer before we write to the file, and move the file pointer
+ // to the right place.
+ //
+ if( _Access == READ_AND_WRITE_ACCESS ) {
+ Offset = FlushBuffer();
+ if( !MovePointerPosition( -Offset, STREAM_CURRENT ) ) {
+ return( FALSE );
+ }
+ }
+ return( STREAM::Write( Buffer, BytesToWrite, BytesWritten ) );
+}
+
+
+
+BOOLEAN
+FILE_STREAM::WriteAt(
+ IN PBYTE Buffer,
+ IN ULONG BytesToWrite,
+ IN LONG Position,
+ IN SEEKORIGIN Origin,
+ OUT PULONG BytesWritten
+ )
+
+/*++
+
+Routine Description:
+
+ Writes data to the stream at a specified position.
+
+Arguments:
+
+ Buffer - Points to the buffer that contains the data to be written.
+
+ BytesToWrite - Indicates total number of bytes to write to the stream.
+
+ Position - Position in the stream where data is to be written to,
+ relative to the origin of the stream.
+
+ Origin - Indicates what position in the stream should be used
+ as origin.
+
+ BytesWritten - Points to the variable that will contain the number of
+ bytes written.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE to indicate that the operation succeeded.
+ Returns FALSE otherwise.
+
+
+--*/
+
+{
+ BOOLEAN Result;
+ ULONG SavedPosition;
+
+ DebugPtrAssert( Buffer );
+ DebugPtrAssert( BytesWritten );
+
+ Result = FALSE;
+ if( QueryPointerPosition( &SavedPosition ) &&
+ MovePointerPosition( Position, Origin ) &&
+ Write( Buffer, BytesToWrite, BytesWritten ) ) {
+ Result = MovePointerPosition( SavedPosition, STREAM_BEGINNING );
+ }
+ return( Result );
+}
+
+
+BOOLEAN
+FILE_STREAM::EndOfFile(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Informs the caller if end of file has occurred. End of file happens
+ when all bytes from the file were read, and there is no more bytes
+ to read (the API returns zero bytes read).
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A boolean value that indicates if end of file was detected.
+
+
+--*/
+
+
+{
+ return( _EndOfFile );
+}
+
+
+
+STREAMACCESS
+FILE_STREAM::QueryAccess(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the type of access of the file stream
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The stream access.
+
+
+--*/
+
+
+{
+ return( _Access );
+}
+
+
+
+HANDLE
+FILE_STREAM::QueryHandle(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the file handle
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The file handle.
+
+
+--*/
+
+
+{
+ return( _FileHandle );
+}
diff --git a/private/utils/ulib/src/filter.cxx b/private/utils/ulib/src/filter.cxx
new file mode 100644
index 000000000..60d141596
--- /dev/null
+++ b/private/utils/ulib/src/filter.cxx
@@ -0,0 +1,719 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ filter.cxx
+
+Abstract:
+
+ This module contains the definition for the FSN_FILTER class.
+ FSN_FILTER essentially maintains the state information needed to
+ establish the criteria by which other 'file' or FSNODE objects are
+ compared against.
+
+Author:
+
+ David J. Gilman (davegi) 09-Jan-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "dir.hxx"
+#include "file.hxx"
+#include "filter.hxx"
+#include "wstring.hxx"
+
+extern "C" {
+ #include <string.h>
+ #include <ctype.h>
+}
+
+
+
+
+//
+// Pattern that matches all files
+//
+#define MATCH_ALL_FILES "*.*"
+
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( FSN_FILTER, OBJECT, ULIB_EXPORT );
+
+DEFINE_CAST_MEMBER_FUNCTION( FSN_FILTER );
+
+
+
+
+ULIB_EXPORT
+FSN_FILTER::~FSN_FILTER (
+ )
+/*++
+
+Routine Description:
+
+ Destructs an FSN_FILTER objtect
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+}
+
+
+
+VOID
+FSN_FILTER::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Construct a FSN_FILTER by setting it's internal data to a known state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _AttributesSet = FALSE;
+ _FileNameSet = FALSE;
+
+ //
+ // Note that even though _FileNameSet is false, we initialize
+ // the _FileName criteria with a match-all pattern. having the
+ // _FileNameSet flag set to FALSE saves us time because we don't
+ // have to do pattern-matching, since we know that everything will
+ // match anyway.
+ //
+ _FileName.Initialize( MATCH_ALL_FILES );
+ _TimeInfoSet[FSN_TIME_MODIFIED] = FALSE;
+ _TimeInfoSet[FSN_TIME_CREATED] = FALSE;
+ _TimeInfoSet[FSN_TIME_ACCESSED] = FALSE;
+
+}
+
+ULIB_EXPORT
+BOOLEAN
+FSN_FILTER::Initialize (
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes the FSN_FILTER
+
+Arguments:
+
+ none
+
+Return Value:
+
+ TRUE if the filter was succesfully initialized.
+
+--*/
+
+{
+
+ return _TimeInfo[FSN_TIME_MODIFIED].Initialize() &&
+ _TimeInfo[FSN_TIME_CREATED].Initialize() &&
+ _TimeInfo[FSN_TIME_ACCESSED].Initialize();
+
+}
+
+ULIB_EXPORT
+BOOLEAN
+FSN_FILTER::DoesNodeMatch (
+ IN PFSNODE FsNode
+ )
+/*++
+
+Routine Description:
+
+ Determine if the supplied node matches the criteria established
+ in this FSN_FILTER.
+
+Arguments:
+
+ Node - Node to match
+
+Return Value:
+
+ TRUE if match, FALSE otherwise
+
+--*/
+
+{
+ FSTRING FileName;
+
+ if (!FsNode) {
+ return FALSE;
+ }
+
+ if (FilterFileName(FileName.Initialize(FsNode->_FileData.cFileName)) ||
+ (FsNode->_FileData.cAlternateFileName[0] &&
+ FilterFileName(FileName.Initialize(FsNode->_FileData.cAlternateFileName)))) {
+
+ if (FilterAttributes(FsNode->QueryAttributes()) &&
+ FilterTimeInfo( FsNode->GetCreationTime(),
+ FsNode->GetLastAccessTime(),
+ FsNode->GetLastWriteTime())) {
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+BOOLEAN
+FSN_FILTER::FilterAttributes (
+ IN FSN_ATTRIBUTE Attributes
+ )
+
+/*++
+
+Routine Description:
+
+ Determines if the supplied data matches the attribute criteria.
+
+Arguments:
+
+ FindData - Supplies the system data which represents a found file.
+
+Return Value:
+
+ TRUE if data matches attribute criteria.
+ FALSE otherwise
+
+--*/
+
+{
+ if ( _AttributesSet ) {
+ return ( ((Attributes & _AttributesAll) == _AttributesAll) &&
+ ((_AttributesAny == 0) || (Attributes & _AttributesAny)) &&
+ !(Attributes & _AttributesNone) );
+ }
+
+ return TRUE;
+
+}
+
+BOOLEAN
+FSN_FILTER::FilterFileName (
+ IN PCWSTRING FileName
+ )
+
+/*++
+
+Routine Description:
+
+ Determines if the supplied data matches the path criteria. We never
+ return "." or ".." entries.
+
+Arguments:
+
+ FindData - Supplies the system data which represents a found file.
+
+Return Value:
+
+ TRUE if data matches the path criteria.
+ FALSE otherwise
+
+--*/
+
+{
+ CHNUM ChCount;
+ WCHAR c;
+
+ ChCount = FileName->QueryChCount();
+
+ //
+ // We never return the "." or ".." entries
+ //
+ if ( ( FileName->QueryChAt(0) == (WCHAR)'.') &&
+ ( (ChCount == 1) ||
+ ((FileName->QueryChAt(1) == (WCHAR)'.') && (ChCount == 2))) ) {
+
+ return FALSE;
+ }
+
+
+ if ( _FileNameSet ) {
+ //
+ // We only match the base portion of the name
+ //
+ ChCount = FileName->QueryChCount()-1;
+ while (ChCount < ~0 ) {
+ c = FileName->QueryChAt( ChCount );
+
+ if ( c == (WCHAR)':' || c == (WCHAR)'\\' ) {
+ break;
+ }
+ ChCount--;
+ }
+ ChCount++;
+
+ return PatternMatch( &_FileName, 0, FileName, ChCount );
+ }
+
+ return TRUE;
+
+}
+
+BOOLEAN
+FSN_FILTER::FilterTimeInfo (
+ IN PFILETIME CreationTime,
+ IN PFILETIME LastAccessTime,
+ IN PFILETIME LastWriteTime
+ )
+
+/*++
+
+Routine Description:
+
+ Determines if the supplied data matches the TimeInfo criteria.
+
+Arguments:
+
+ FindData - Supplies the system data which represents a found file.
+
+Return Value:
+
+ TRUE if data matches TimeInfo criteria.
+ FALSE otherwise
+
+--*/
+
+{
+
+ BOOLEAN Match = TRUE;
+
+ if ( _TimeInfoSet[FSN_TIME_MODIFIED] ) {
+ Match = TimeInfoMatch( &_TimeInfo[FSN_TIME_MODIFIED],
+ LastWriteTime,
+ _TimeInfoMatch[FSN_TIME_MODIFIED] );
+ }
+
+ if ( Match && _TimeInfoSet[FSN_TIME_CREATED] ) {
+ Match = TimeInfoMatch( &_TimeInfo[FSN_TIME_CREATED],
+ CreationTime,
+ _TimeInfoMatch[FSN_TIME_CREATED] );
+ }
+
+ if ( Match && _TimeInfoSet[FSN_TIME_ACCESSED] ) {
+ Match = TimeInfoMatch( &_TimeInfo[FSN_TIME_ACCESSED],
+ LastAccessTime,
+ _TimeInfoMatch[FSN_TIME_ACCESSED] );
+ }
+
+ return Match;
+
+}
+
+BOOLEAN
+IsThereADot(
+ IN PCWSTRING String
+ )
+{
+ PATH path;
+ PWSTRING p;
+ BOOLEAN r;
+
+ if (!path.Initialize(String) ||
+ !(p = path.QueryName())) {
+
+ return FALSE;
+ }
+
+ r = (p->Strchr('.') != INVALID_CHNUM);
+
+ DELETE(p);
+
+ return r;
+}
+
+
+BOOLEAN
+FSN_FILTER::PatternMatch (
+ IN PCWSTRING Pattern,
+ IN CHNUM PatternPosition,
+ IN PCWSTRING FileName,
+ IN CHNUM FileNamePosition
+ )
+
+/*++
+
+Routine Description:
+
+ Determines if a file name matches a pattern.
+
+Arguments:
+
+ Pattern - Supplies the pattern to compare against.
+ PatternPosition - Supplies first position within pattern.
+ FileName - Supplies the name to match. Cannot contain
+ wildcards.
+ FileNamePosition - Supplies first position within FileName.
+
+
+Return Value:
+
+ TRUE if name matches
+
+--*/
+
+{
+ if ( PatternPosition == Pattern->QueryChCount() ) {
+
+ return (FileNamePosition == FileName->QueryChCount());
+
+ }
+
+ switch( Pattern->QueryChAt( PatternPosition )) {
+
+ case (WCHAR)'?':
+ if ((FileNamePosition == FileName->QueryChCount()) ||
+ (FileName->QueryChAt( FileNamePosition ) == (WCHAR)'.' )) {
+ return PatternMatch( Pattern, PatternPosition + 1,
+ FileName, FileNamePosition );
+ } else {
+ return PatternMatch( Pattern, PatternPosition + 1,
+ FileName, FileNamePosition + 1 );
+ }
+
+ case (WCHAR) '*':
+ do {
+ if (PatternMatch( Pattern, PatternPosition+1,
+ FileName, FileNamePosition )) {
+ return TRUE;
+ }
+ FileNamePosition++;
+ } while (FileNamePosition <= FileName->QueryChCount());
+
+ return FALSE;
+
+ case (WCHAR)'.':
+ if (FileNamePosition == FileName->QueryChCount() &&
+ !IsThereADot(FileName) &&
+ Pattern->Strchr('.') == PatternPosition) {
+
+ return PatternMatch( Pattern, PatternPosition+1,
+ FileName, FileNamePosition );
+ }
+
+ default:
+ return ( (WCHAR)CharUpper((LPTSTR)Pattern->QueryChAt( PatternPosition )) ==
+ (WCHAR)CharUpper((LPTSTR)FileName->QueryChAt( FileNamePosition ))) &&
+ PatternMatch( Pattern, PatternPosition + 1,
+ FileName, FileNamePosition + 1 );
+
+ }
+}
+
+PFSNODE
+FSN_FILTER::QueryFilteredFsnode (
+ IN PCFSN_DIRECTORY ParentDirectory,
+ IN PWIN32_FIND_DATA FindData
+ )
+
+/*++
+
+Routine Description:
+
+ Determine if the supplied system data matches the criteria established
+ in this FSN_FILTER. If it is create the appropriate FSNODE (i.e. FSN_FILE
+ or FSN_DIRECTORY) and return it to the caller.
+
+Arguments:
+
+ ParentDirectory - Supplies pointer to the parent directory object
+ FindData - Supplies the system data which represents a found file.
+
+Return Value:
+
+ Pointer to an FSNODE if the criteria was met. NULL otherwise.
+
+--*/
+
+{
+ PFSNODE FsNode = NULL;
+ FSTRING FileName;
+
+
+ if ( (FindData != NULL) &&
+ ((FileName.Initialize( FindData->cFileName ) &&
+ FilterFileName( &FileName )) ||
+ (FindData->cAlternateFileName[0] &&
+ FileName.Initialize( FindData->cAlternateFileName ) &&
+ FilterFileName( &FileName ))) &&
+ FilterAttributes( (FSN_ATTRIBUTE)FindData->dwFileAttributes ) &&
+ FilterTimeInfo( &FindData->ftCreationTime,
+ &FindData->ftLastAccessTime,
+ &FindData->ftLastWriteTime )
+ ) {
+
+ //
+ // The data matches the filter criteria.
+ //
+ if ( FindData->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
+
+ //
+ // We have to create a directory object
+ //
+ FsNode = NEW FSN_DIRECTORY;
+
+ } else {
+
+ //
+ // We have to create a file object
+ //
+ FsNode = NEW FSN_FILE;
+ }
+
+ if ( FsNode ) {
+
+ if ( !(FsNode->Initialize( (LPWSTR)FindData->cFileName, ParentDirectory, FindData )) ) {
+
+ DELETE( FsNode );
+
+ }
+ }
+ }
+
+ return FsNode;
+}
+
+ULIB_EXPORT
+BOOLEAN
+FSN_FILTER::SetAttributes (
+ IN FSN_ATTRIBUTE All,
+ IN FSN_ATTRIBUTE Any,
+ IN FSN_ATTRIBUTE None
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the attributes criteria
+
+Arguments:
+
+ All - Supplies the mask for the ALL attributes
+ Any - Supplies the mask for the ANY attributes
+ None - Supplies the mask for the NONE attributes
+
+Return Value:
+
+ TRUE if the Attributes criteria was set.
+
+--*/
+
+{
+
+ //
+ // Verify that no attribute is set in more than one mask
+ //
+ if ((All | Any | None) != ( All ^ Any ^ None )) {
+ return FALSE;
+ }
+
+ _AttributesAll = All;
+ _AttributesAny = Any;
+ _AttributesNone = None;
+
+ return (_AttributesSet = TRUE);
+
+}
+
+ULIB_EXPORT
+BOOLEAN
+FSN_FILTER::SetFileName (
+ IN PCSTR FileName
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the FileName criteria
+
+Arguments:
+
+ FileName - Supplies the filename to match against
+
+Return Value:
+
+ TRUE if the filename criteria was set.
+
+--*/
+
+{
+
+ if ( _FileName.Initialize( FileName ) ) {
+
+ return ( _FileNameSet = TRUE );
+
+ }
+
+ return FALSE;
+
+}
+
+ULIB_EXPORT
+BOOLEAN
+FSN_FILTER::SetFileName (
+ IN PCWSTRING FileName
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the FileName criteria
+
+Arguments:
+
+ FileName - Supplies the filename to match against
+
+Return Value:
+
+ TRUE if the filename criteria was set.
+
+--*/
+
+{
+
+ if ( _FileName.Initialize( FileName ) ) {
+
+ return ( _FileNameSet = TRUE );
+
+ }
+
+ return FALSE;
+
+}
+
+ULIB_EXPORT
+BOOLEAN
+FSN_FILTER::SetTimeInfo (
+ IN PCTIMEINFO TimeInfo,
+ IN FSN_TIME TimeInfoType,
+ IN USHORT TimeInfoMatch
+ )
+
+/*++
+
+Routine Description:
+
+ Sets a TimeInfo criteria
+
+Arguments:
+
+ TimeInfo - Supplies the timeinfo
+ TimeinfoType - Supplies the type of timeinfo to set
+ TimeInfoMatch - Supplies the match criteria
+
+Return Value:
+
+ TRUE if the timeinfo criteria was set.
+
+--*/
+
+{
+
+ //
+ // Verify the parameters
+ //
+ if ((TimeInfoType < FSN_TIME_MODIFIED) ||
+ (TimeInfoType > FSN_TIME_ACCESSED) ||
+ (TimeInfoMatch == 0) ||
+ (TimeInfoMatch & ~(TIME_BEFORE | TIME_AT | TIME_AFTER)) ||
+ ((TimeInfoMatch & TIME_BEFORE) && (TimeInfoMatch & TIME_AFTER))
+ ) {
+
+ return FALSE;
+ }
+
+ _TimeInfo[TimeInfoType].Initialize( (TIMEINFO *)TimeInfo );
+
+ _TimeInfoMatch[TimeInfoType] = TimeInfoMatch;
+
+ return (_TimeInfoSet[TimeInfoType] = TRUE);
+
+}
+
+BOOLEAN
+FSN_FILTER::TimeInfoMatch (
+ IN PTIMEINFO TimeInfo,
+ IN PFILETIME FileTime,
+ IN USHORT Criteria
+ )
+
+/*++
+
+Routine Description:
+
+ Determines if the supplied file time matches the criteria for a certain
+ time
+
+Arguments:
+
+ TimeInfo - Supplies pointer to Timeinfo object to match against
+ FileTime - Supplies the file time to match
+ Criteria - Supplies the match criteria
+
+Return Value:
+
+ TRUE if criteria met
+ FALSE otherwise
+
+--*/
+
+{
+
+ USHORT Compare;
+
+ UNREFERENCED_PARAMETER( (void)this );
+
+ //
+ // Compare and set in range 0 - 2
+ //
+ Compare = (USHORT)(TimeInfo->CompareTimeInfo( FileTime ) + 1);
+
+ //
+ // Our crietria is a bit mask, so we transform the result of the
+ // comparison to something that we can compare our mask against.
+ //
+ // i.e. {0,1,2} to {1,2,4}
+ //
+ Compare = (USHORT)((Compare * 2) + ( (Compare == 0) ? 1 : 0));
+
+ return BOOLEAN( (USHORT)Compare & ~Criteria );
+
+}
diff --git a/private/utils/ulib/src/fsnode.cxx b/private/utils/ulib/src/fsnode.cxx
new file mode 100644
index 000000000..e5b2b5993
--- /dev/null
+++ b/private/utils/ulib/src/fsnode.cxx
@@ -0,0 +1,459 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ fsnode.cxx
+
+Abstract:
+
+ This module contains the definition for the FSNODE class, the most
+ primitive, abstract class in the file system sub-hierarchy. Given it's
+ abstract, prmitive nature it contains very minimal implementation. It's
+ primary intent is to support a polymorphic base class for file system
+ objects.
+
+Author:
+
+ David J. Gilman (davegi) 02-Jan-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "array.hxx"
+#include "dir.hxx"
+#include "fsnode.hxx"
+#include "wstring.hxx"
+#include "path.hxx"
+#include "timeinfo.hxx"
+#include "system.hxx"
+
+DEFINE_CONSTRUCTOR( FSNODE, OBJECT );
+
+FSNODE::~FSNODE (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy an FSNODE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+}
+
+BOOLEAN
+FSNODE::Initialize (
+ IN PCWSTR PathName,
+ IN PCFSN_DIRECTORY ParentDirectory,
+ IN PWIN32_FIND_DATA FileData
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize an FSNODE by constructing and initializing it's contained
+ PATH object.
+
+Arguments:
+
+ PathName - Supplies a name used to initialize the contained PATH
+
+ FileData - Points to the structure that contains all file information.
+
+Return Value:
+
+ BOOLEAN - TRUE if the contained PATH was succesfully constructed and
+ initialized.
+
+--*/
+
+{
+
+ FSTRING wcs;
+
+ DebugPtrAssert( PathName );
+ DebugPtrAssert( ParentDirectory );
+ if( ( PathName != NULL ) &&
+ ( ParentDirectory != NULL ) &&
+ _Path.Initialize((( PFSN_DIRECTORY )
+ ParentDirectory )->GetPath( ), FALSE) &&
+ wcs.Initialize( (PWSTR) PathName ) &&
+ _Path.AppendBase( &wcs ) ) {
+ memcpy( &_FileData, FileData, sizeof( WIN32_FIND_DATA ) );
+ _Path.GetPathString( )->QueryWSTR( 0, TO_END,
+ ( LPWSTR )_FileData.cFileName,
+ sizeof( _FileData.cFileName));
+ return( TRUE );
+
+ } else {
+
+ DebugAbort( "Could not construct/initialize PATH" );
+ return( FALSE );
+
+ }
+}
+
+BOOLEAN
+FSNODE::Initialize (
+ IN PCWSTRING PathName,
+ IN PWIN32_FIND_DATA FileData
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize an FSNODE by constructing and initializing it's contained
+ PATH object.
+
+Arguments:
+
+ PathName - Supplies a name used to initialize the contained PATH
+
+ FileData - Points to the structure that contains all file information.
+
+Return Value:
+
+ BOOLEAN - TRUE if the contained PATH was succesfully constructed and
+ initialized.
+
+--*/
+
+{
+
+ DebugPtrAssert( PathName );
+ if( ( PathName != NULL ) &&
+ _Path.Initialize( PathName, FALSE ) ) {
+ memcpy( &_FileData, FileData, sizeof( WIN32_FIND_DATA ) );
+ PathName->QueryWSTR( 0, TO_END,
+ ( LPWSTR )_FileData.cFileName,
+ sizeof( _FileData.cFileName ));
+ return( TRUE );
+
+ } else {
+
+ DebugAbort( "Could not construct/initialize PATH" );
+ return( FALSE );
+
+ }
+}
+
+PFSN_DIRECTORY
+FSNODE::QueryParentDirectory (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Construct and return the FSN_DIRECTORY object which represents this
+ FSNODE's parent.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PFSN_DIRECTORY - Returns a pointer the the parent FSN_DIRECTORY.
+
+--*/
+
+{
+ REGISTER PFSN_DIRECTORY pfsnDir;
+ PATH path;
+
+ if( path.Initialize( ((PFSNODE) this)->_Path.QueryPrefix( )) &&
+ (( pfsnDir = SYSTEM::QueryDirectory( &path )) != NULL )) {
+
+ return( pfsnDir );
+ } else {
+
+ DebugAbort( "Can't construct parent directory" );
+ return( NULL );
+ }
+}
+
+PTIMEINFO
+FSNODE::QueryTimeInfo (
+ IN FSN_TIME FsnTime
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Query the time imformation pertaining to this FSNODE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PTIMEINFO - Returns a pointer to the TIMEINFO object.
+
+--*/
+
+{
+ PTIMEINFO TimeInfo;
+ PFILETIME DesiredFileTime;
+
+ TimeInfo = NULL;
+
+ TimeInfo = NEW( TIMEINFO );
+ DebugPtrAssert( TimeInfo );
+
+ switch( FsnTime ) {
+
+ case FSN_TIME_MODIFIED:
+ DesiredFileTime = &( ((PFSNODE) this)->_FileData.ftLastWriteTime );
+ break;
+
+ case FSN_TIME_CREATED:
+ DesiredFileTime = &( ((PFSNODE) this)->_FileData.ftCreationTime );
+ break;
+
+ case FSN_TIME_ACCESSED:
+ DesiredFileTime = &( ((PFSNODE) this)->_FileData.ftLastAccessTime );
+ break;
+
+ default:
+ DebugAbort( "Invalid value of FsnTime \n" );
+ return( NULL );
+ }
+
+ if( !TimeInfo->Initialize( DesiredFileTime ) ) {
+ DebugAbort( "TimeInfo->Initialize() failed \n" );
+ return( NULL );
+ }
+ return( TimeInfo );
+}
+
+BOOLEAN
+FSNODE::SetTimeInfo (
+ IN PCTIMEINFO TimeInfo,
+ IN FSN_TIME TimeInfoType
+ )
+
+/*++
+
+Routine Description:
+
+ Change the time information of an FSNODE.
+
+Arguments:
+
+ TimeInfo - Pointer to a TIMEINFO object that contains the new time.
+
+ TimeInfoType - Indicates the time to be modified (creation time,
+ last access time, or last modified time )
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds. FALSE otherwise.
+
+
+--*/
+
+{
+ PFILETIME DesiredFileTime;
+ HANDLE FileHandle;
+ BOOLEAN TimeSet;
+
+ DebugPtrAssert( TimeInfo );
+
+ switch( TimeInfoType ) {
+
+ case FSN_TIME_MODIFIED:
+ DesiredFileTime = &( _FileData.ftLastWriteTime );
+ break;
+
+ case FSN_TIME_CREATED:
+ DesiredFileTime = &( _FileData.ftCreationTime );
+ break;
+
+ case FSN_TIME_ACCESSED:
+ DesiredFileTime = &( _FileData.ftLastAccessTime );
+ break;
+
+ default:
+ DebugAbort( "Invalid value of FsnTime \n" );
+ return( NULL );
+ }
+
+ *DesiredFileTime = *( TimeInfo->GetFileTime() );
+ if( DesiredFileTime == NULL ) {
+ return( FALSE );
+ }
+
+ FileHandle = CreateFile( &_FileData.cFileName[0],
+ GENERIC_WRITE,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL );
+ if( FileHandle == INVALID_HANDLE_VALUE ) {
+ return( FALSE );
+ }
+
+ TimeSet = SetFileTime( FileHandle,
+ &( _FileData.ftCreationTime ),
+ &( _FileData.ftLastAccessTime ),
+ &( _FileData.ftLastWriteTime ) );
+
+ CloseHandle( FileHandle );
+ return( TimeSet );
+}
+
+
+
+BOOLEAN
+FSNODE::Rename(
+ IN PCPATH NewName
+ )
+/*++
+
+Routine Description:
+
+ Renames a file and updates its FSNODE
+
+Arguments:
+
+ NewName - New name for the file.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds. FALSE otherwise.
+
+--*/
+
+{
+
+ PCWSTRING NewNameWstring;
+ PCWSTR NewNameString;
+
+
+ DebugPtrAssert( NewName );
+ NewNameWstring = NewName->GetPathString();
+ if( NewNameWstring == NULL ) {
+ return( FALSE );
+ }
+ NewNameString = NewNameWstring->GetWSTR();
+ if( NewNameString == NULL ) {
+ return( FALSE );
+ }
+ if( !MoveFile( _FileData.cFileName,
+ (LPWSTR) NewNameString ) ) {
+ return( FALSE );
+ }
+ memmove( _FileData.cFileName,
+ NewNameString,
+ (NewNameWstring->QueryChCount() + 1) * sizeof( WCHAR ) );
+ if( !_Path.Initialize( NewName ) ) {
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+BOOLEAN
+FSNODE::DeleteFromDisk(
+ IN BOOLEAN Force
+ )
+{
+ UNREFERENCED_PARAMETER( Force );
+ return( FALSE );
+}
+
+
+
+BOOLEAN
+FSNODE::UpdateFsNode (
+ )
+
+/*++
+
+Routine Description:
+
+ Update the file attributes in this FSNODE object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the attributes were updated.
+
+--*/
+
+{
+ HANDLE Handle;
+ WIN32_FIND_DATA Data;
+
+ if( ( Handle = FindFirstFile( &_Path, &Data ) ) == INVALID_HANDLE_VALUE ) {
+ DebugPrint( "FindFirstFile() failed \n" );
+ return( FALSE );
+ }
+ _FileData = Data;
+ FindClose( Handle );
+ return( TRUE );
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+FSNODE::UseAlternateName(
+ )
+/*++
+
+Routine Description:
+
+ This routine set the last component of the path for this object to
+ the alternate name if it is available.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ FSTRING f;
+
+ // If there is no alternate then we are already DOS compatible.
+
+ if (!_FileData.cAlternateFileName[0]) {
+ return TRUE;
+ }
+
+ return _Path.SetName(f.Initialize(_FileData.cAlternateFileName));
+}
diff --git a/private/utils/ulib/src/hmem.cxx b/private/utils/ulib/src/hmem.cxx
new file mode 100644
index 000000000..e5ce2394f
--- /dev/null
+++ b/private/utils/ulib/src/hmem.cxx
@@ -0,0 +1,247 @@
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+#include "ulib.hxx"
+#include "error.hxx"
+#include "hmem.hxx"
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( HMEM, MEM, ULIB_EXPORT );
+
+VOID
+HMEM::Construct (
+ )
+/*++
+
+Routine Description:
+
+ The is the contructor of HMEM. It initializes the private data
+ to reasonable default values.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _size = 0;
+ _real_buf = NULL;
+ _buf = NULL;
+}
+
+
+ULIB_EXPORT
+HMEM::~HMEM(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for HMEM. Frees up any memory used.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+HMEM::Initialize(
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes HMEM to an initial state. All pointers or
+ information previously aquired from this object will become invalid.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ Destroy();
+
+ return TRUE;
+}
+
+
+ULIB_EXPORT
+PVOID
+HMEM::Acquire(
+ IN ULONG Size,
+ IN ULONG AlignmentMask
+ )
+/*++
+
+Routine Description:
+
+ This routine acquires the memory resources of this object for
+ the client to use. 'Size' bytes of data are guaranteed by
+ this routine or this routine will return NULL. After one call
+ of 'Acquire' has succeeded, all subsequent calls will return the
+ same memory, provided that the Size requested is within bounds
+ specified in the first successful call. The first successful call
+ will dictate the size and location of the memory which will be
+ available by calls to 'QuerySize' and 'GetBuf' respectively.
+
+ A call to Initialize will invalidate all memory previously granted
+ by this object and enable the next call to Acquire to specify
+ any size.
+
+Arguments:
+
+ Size - The number of bytes of memory expected.
+ AlignmentMask - Supplies the alignment required on the memory.
+
+Return Value:
+
+ A valid pointer to 'Size' bytes of memory or NULL.
+
+--*/
+{
+ if (_buf) {
+ if (Size <= _size && !(((ULONG) _buf)&AlignmentMask)) {
+ return _buf;
+ } else {
+ return NULL;
+ }
+ }
+
+ _size = Size;
+
+ if (!(_real_buf = MALLOC((UINT) (_size + AlignmentMask)))) {
+ return NULL;
+ }
+
+ _buf = (PVOID) ((ULONG) ((PCHAR) _real_buf + AlignmentMask) &
+ (~AlignmentMask));
+
+ return _buf;
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+HMEM::Resize(
+ IN ULONG NewSize,
+ IN ULONG AlignmentMask
+ )
+/*++
+
+Routine Description:
+
+ This method reallocates the object's buffer to a larger
+ chunk of memory.
+
+Arguments:
+
+ NewSize -- supplies the new size of the buffer.
+ AlignmentMask -- supplies the alignment requirements on the memory.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This method allocates a new buffer, copies the appropriate
+ amount of data to it, and then frees the old buffer. Clients
+ who use Resize must avoid caching pointers to the memory, but
+ must use GetBuf to find out where the memory is.
+
+ If NewSize is smaller than the current buffer size, we keep
+ the current buffer.
+
+ If this method fails, the object is left unchanged.
+
+--*/
+{
+ PVOID NewBuffer;
+ PVOID NewRealBuffer;
+
+ // First, check to see if our current buffer is big enough
+ // and has the correct alignment
+ // to satisfy the client.
+
+ if( _buf &&
+ NewSize <= _size &&
+ !(((ULONG) _buf)&AlignmentMask)) {
+
+ return TRUE;
+ }
+
+ // We need to allocate a new chunk of memory.
+
+ if( (NewRealBuffer = MALLOC((UINT) (NewSize + AlignmentMask))) == NULL ) {
+
+ return FALSE;
+ }
+
+ NewBuffer = (PVOID) ((ULONG) ((PCHAR) NewRealBuffer + AlignmentMask) &
+ (~AlignmentMask));
+
+ // Copy data from the old buffer to the new. Since we know
+ // that NewSize is greater than _size, we copy _size bytes.
+
+ memset( NewBuffer, 0, (UINT) NewSize );
+ memcpy( NewBuffer, _buf, (UINT) min(_size, NewSize) );
+
+ // Free the old buffer and set the object's private variables.
+
+ FREE( _real_buf );
+ _real_buf = NewRealBuffer;
+ _buf = NewBuffer;
+ _size = NewSize;
+
+ return TRUE;
+}
+
+
+VOID
+HMEM::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine frees the memory of a previous call to Acquire thus
+ invalidating all pointers to that memory and enabling future
+ Acquires to succeed.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _size = 0;
+ if (_real_buf) {
+ FREE(_real_buf);
+ _real_buf = NULL;
+ }
+ _buf = NULL;
+}
diff --git a/private/utils/ulib/src/i386/dosttr.c b/private/utils/ulib/src/i386/dosttr.c
new file mode 100644
index 000000000..e6fc847c6
--- /dev/null
+++ b/private/utils/ulib/src/i386/dosttr.c
@@ -0,0 +1,76 @@
+#include <windows.h>
+
+#define MaxCallStack 20
+
+VOID
+DoStackTrace( DWORD callstack[] )
+
+/*++
+
+Routine Description:
+
+ Backtrace a stack recording all the return addresses in the supplied
+ structure. The mips version of this code does nothing.
+
+Arguments:
+
+ DWORD Callstack[] - The array in which the addresses are stored.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+#pragma message( "Including the stack trace!" )
+
+ int i;
+ DWORD bytes;
+ HANDLE hProcess;
+ DWORD dwEbp;
+
+ hProcess = GetCurrentProcess();
+
+ //
+ // Get the current contents of the control registers...
+ //
+ _asm {
+
+ mov dwEbp, ebp
+
+ }
+
+ //
+ // Ignore the entry on the stack for this procedure...
+ //
+ if( !ReadProcessMemory( hProcess,
+ (LPVOID)dwEbp,
+ (LPVOID)&dwEbp,
+ sizeof( DWORD ),
+ NULL ) ) {
+ return;
+ }
+
+ for( i = 0; ( i < MaxCallStack ) && dwEbp; i++ ) {
+
+ if( !ReadProcessMemory( hProcess,
+ (LPVOID)( (PDWORD)dwEbp + 1 ),
+ (LPVOID)( &callstack[ i ] ),
+ sizeof( DWORD ),
+ NULL ) ) {
+ break;
+ }
+ if( !ReadProcessMemory( hProcess,
+ (LPVOID)dwEbp,
+ (LPVOID)&dwEbp,
+ sizeof( DWORD ),
+ NULL ) ) {
+ break;
+ }
+
+ }
+
+ return;
+}
diff --git a/private/utils/ulib/src/iterator.cxx b/private/utils/ulib/src/iterator.cxx
new file mode 100644
index 000000000..5c344449a
--- /dev/null
+++ b/private/utils/ulib/src/iterator.cxx
@@ -0,0 +1,63 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ iterator.cxx
+
+Abstract:
+
+ This contains the definitions for the non-inline member functions
+ for the abstract ITERATOR class. The only interesting aspect of this
+ implementation is that the destructor decrements the iterator count in
+ it's associated CONTAINER. This count, increment by the CONTAINER when
+ the ITERATOR is constructed, allows the associated CONTAINER to watch
+ for outstanding ITERATORs when it is destroyed - a situation which is
+ dangerous and surely a bug.
+
+Author:
+
+ David J. Gilman (davegi) 03-Dec-1990
+
+Environment:
+
+ ULIB, User Mode
+
+[Notes:]
+
+ optional-notes
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "iterator.hxx"
+
+
+DEFINE_CONSTRUCTOR( ITERATOR, OBJECT );
+
+ITERATOR::~ITERATOR(
+ )
+{
+}
+
+
+POBJECT
+ITERATOR::FindNext(
+ IN PCOBJECT Key
+ )
+{
+ POBJECT p;
+
+ for (p = GetNext(); p; p = GetNext()) {
+ if (!Key->Compare(p)) {
+ break;
+ }
+ }
+
+ return p;
+}
diff --git a/private/utils/ulib/src/keyboard.cxx b/private/utils/ulib/src/keyboard.cxx
new file mode 100644
index 000000000..fca87c2e9
--- /dev/null
+++ b/private/utils/ulib/src/keyboard.cxx
@@ -0,0 +1,920 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ keyboard.cxx
+
+Abstract:
+
+ This module contains the definitions of the member functions
+ of KEYBOARD class.
+
+Author:
+
+ Jaime Sasson (jaimes) 24-Mar-1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "stream.hxx"
+#include "bufstrm.hxx"
+#include "keyboard.hxx"
+
+
+BOOL KEYBOARD::_FlagBreak;
+
+
+#define CTRL_Z 0x1a
+
+DEFINE_EXPORTED_CONSTRUCTOR ( KEYBOARD, BUFFER_STREAM, ULIB_EXPORT );
+
+
+DEFINE_EXPORTED_CAST_MEMBER_FUNCTION( KEYBOARD, ULIB_EXPORT );
+
+
+KEYBOARD::~KEYBOARD (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy a KEYBOARD (close a keyboard handle).
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ SetConsoleMode( _KeyboardHandle, _PreviousMode );
+ CloseHandle( _KeyboardHandle );
+}
+
+
+
+ULIB_EXPORT
+BOOLEAN
+KEYBOARD::Initialize(
+ BOOLEAN LineMode,
+ BOOLEAN EchoMode
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes a KEYBOARD class.
+
+Arguments:
+
+ LineMode - Indicates if the keyboard is to be set in line mode.
+
+ EchoMode - Indicates if the keyboard is to be set in the echo mode
+ (characters are echoed to the current active screen)
+
+Return Value:
+
+ BOOLEAN - Indicates if the initialization succeeded.
+
+--*/
+
+{
+ ULONG KeyboardMode;
+
+ _KeyboardHandle = CreateFile( (LPWSTR)L"CONIN$",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL );
+ if( _KeyboardHandle ==INVALID_HANDLE_VALUE ) {
+ return( FALSE );
+ }
+ if( !GetConsoleMode( _KeyboardHandle, &_PreviousMode ) ) {
+ return( FALSE );
+ }
+ KeyboardMode = _PreviousMode;
+ if( LineMode ) {
+ KeyboardMode |= ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
+ } else {
+ KeyboardMode &= ~(ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
+ }
+ if( EchoMode ) {
+ KeyboardMode |= ENABLE_ECHO_INPUT;
+ } else {
+ KeyboardMode &= ~ENABLE_ECHO_INPUT;
+ }
+ if( !SetConsoleMode( _KeyboardHandle, KeyboardMode ) ) {
+ return( FALSE );
+ }
+ _FlagCtrlZ = FALSE;
+ return( BUFFER_STREAM::Initialize( 256 ) );
+}
+
+
+BOOL
+KEYBOARD::BreakHandler (
+ IN ULONG CtrlType
+ )
+
+/*++
+
+Routine Description:
+
+ Handles Break events. Sets up the static data so that it can be
+ queried later on.
+
+Arguments:
+
+ CtrlType - Supplies the type of Ctrl
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER( CtrlType );
+
+ _FlagBreak = TRUE;
+ return TRUE;
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+KEYBOARD::GotABreak (
+ )
+
+/*++
+
+Routine Description:
+
+ Determines if a Break event (e.g Ctrl-C) was caught and handled.
+
+ The static data that contains the Break information is set to a
+ "FALSE" state. Note that this means that if there is no Break
+ between two consecutive calls to this method, then the second
+ one will always return FALSE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - TRUE if a Break event happened, FALSE otherwise.
+
+--*/
+
+{
+ BOOLEAN GotBreak = _FlagBreak;
+
+ _FlagBreak = FALSE;
+
+ return GotBreak;
+
+}
+
+ULIB_EXPORT
+BOOLEAN
+KEYBOARD::EnableBreakHandling(
+ )
+
+/*++
+
+Routine Description:
+
+ Enables Break events handling (E.g. Ctrl-C).
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+--*/
+
+{
+ _FlagBreak = FALSE;
+
+ return SetConsoleCtrlHandler( KEYBOARD::BreakHandler, TRUE );
+
+}
+
+ULIB_EXPORT
+BOOLEAN
+KEYBOARD::EnableLineMode(
+ )
+
+/*++
+
+Routine Description:
+
+ Set the keyboard in line mode.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+--*/
+
+{
+ ULONG Mode;
+
+ if( !GetConsoleMode( _KeyboardHandle, &Mode ) ) {
+ return( FALSE );
+ }
+
+ Mode |= ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT;
+ return( SetConsoleMode( _KeyboardHandle, Mode ) );
+}
+
+
+
+ULIB_EXPORT
+BOOLEAN
+KEYBOARD::DisableBreakHandling(
+ )
+
+/*++
+
+Routine Description:
+
+ Disables Break event handling (E.g. Ctrl-C).
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+--*/
+
+{
+ _FlagBreak = FALSE;
+
+ return SetConsoleCtrlHandler( KEYBOARD::BreakHandler, FALSE );
+
+}
+
+ULIB_EXPORT
+BOOLEAN
+KEYBOARD::DisableLineMode(
+ )
+
+/*++
+
+Routine Description:
+
+ Set the keyboard in character mode.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+--*/
+
+{
+ ULONG Mode;
+
+ // unreferenced parameters
+ (void)(this);
+
+ if( !GetConsoleMode( _KeyboardHandle, &Mode ) ) {
+ return( FALSE );
+ }
+ Mode &= ~(ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT | ENABLE_ECHO_INPUT);
+ return( SetConsoleMode( _KeyboardHandle, Mode ) );
+}
+
+
+
+
+BOOLEAN
+KEYBOARD::IsLineModeEnabled(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Finds out if the keyboard is in line mode.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the keyboard is in line mode
+
+--*/
+
+{
+ ULONG Mode;
+
+ // unreferenced parameters
+ (void)(this);
+
+ GetConsoleMode( _KeyboardHandle, &Mode );
+ return( ( Mode & ENABLE_LINE_INPUT ) != 0 );
+}
+
+
+
+BOOLEAN
+KEYBOARD::EnableEchoMode(
+ )
+
+/*++
+
+Routine Description:
+
+ Set the keyboard in echo mode.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+--*/
+
+{
+ ULONG Mode;
+
+ if( !GetConsoleMode( _KeyboardHandle, &Mode ) ) {
+ return( FALSE );
+ }
+ Mode |= ENABLE_ECHO_INPUT;
+ return( SetConsoleMode( _KeyboardHandle, Mode ) );
+}
+
+
+
+BOOLEAN
+KEYBOARD::DisableEchoMode(
+ )
+
+/*++
+
+Routine Description:
+
+ Does not echo characters read from keyboard.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+--*/
+
+{
+ ULONG Mode;
+
+ if( !GetConsoleMode( _KeyboardHandle, &Mode ) ) {
+ return( FALSE );
+ }
+ Mode &= ~ENABLE_ECHO_INPUT;
+ return( SetConsoleMode( _KeyboardHandle, Mode ) );
+}
+
+
+
+BOOLEAN
+KEYBOARD::IsEchoModeEnabled(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Finds out if characters read from keyboard echoed to the screen.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the keyboard is in echo mode
+
+--*/
+
+{
+ ULONG Mode;
+
+ GetConsoleMode( _KeyboardHandle, &Mode );
+ return( ( Mode | ENABLE_ECHO_INPUT ) != 0 );
+}
+
+
+
+BOOLEAN
+KEYBOARD::CheckForAsciiKey(
+ IN PINPUT_RECORD InputRecord,
+ IN ULONG NumberOfInputRecords
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Examines an array of input records in order to find out if at least
+ one ascii key was pressed.
+
+Arguments:
+
+ InputRecord - Pointer to an array of INPUT_RECORDS.
+
+ NumberOfInputRecords - Number of elements in the array
+
+
+Return Value:
+
+ BOOLEAN - Indicates if the input buffer contains at least one
+ ASCII key.
+
+
+--*/
+
+{
+ BOOLEAN Result;
+
+ // unreferenced parameters
+ (void)(this);
+
+ Result = FALSE;
+ while( !Result && NumberOfInputRecords ) {
+ if( ( InputRecord->EventType == KEY_EVENT ) &&
+ ( InputRecord->Event ).KeyEvent.bKeyDown &&
+
+#if defined DBCS
+// MSKK KazuM Sep,24,1993
+ ( ( InputRecord->Event ).KeyEvent.uChar.UnicodeChar > 0 ) &&
+ ( ( InputRecord->Event >.KeyEvent.uChar.UnicodeChar <= 0x7e ) ) {
+#else
+ ( ( InputRecord->Event ).KeyEvent.uChar.AsciiChar > 0 ) &&
+ ( ( InputRecord->Event ).KeyEvent.uChar.AsciiChar <= 0x7e ) ) {
+#endif
+
+ Result = TRUE;
+ } else {
+ NumberOfInputRecords--;
+ InputRecord++;
+ }
+ }
+ return( Result );
+}
+
+
+
+ULIB_EXPORT
+BOOLEAN
+KEYBOARD::IsKeyAvailable(
+ OUT PBOOLEAN Available
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determines if there is at least one key to be read.
+
+Arguments:
+
+ Available - Pointer to the variable that will contain the result of
+ the query (if there is a key in the keyboard buffer).
+
+Return Value:
+
+ BOOLEAN - A boolean value that indicates if the operation succeeded
+ If this value is FALSE, the contets of 'Available' has no
+ meaning (the calls to the APIs failed).
+
+
+--*/
+
+
+{
+ BOOLEAN Result;
+ ULONG NumberOfInputEvents;
+ PINPUT_RECORD Event;
+ ULONG NumberOfEventsRead;
+
+ //
+ // Keys read, but not yet consumed, are kept are in a buffer.
+ // So, we have to check first if there is at least one key
+ // in this buffer.
+ //
+ if( BUFFER_STREAM::QueryBytesInBuffer() != 0 ) {
+ *Available = TRUE;
+ return( TRUE );
+ }
+ //
+ // If there was no key previously read, we have to check the
+ // keyboard buffer for key events.
+ //
+ Result = FALSE;
+ if ( GetNumberOfConsoleInputEvents( _KeyboardHandle,
+ &NumberOfInputEvents ) ) {
+
+ if( NumberOfInputEvents == 0 ) {
+ *Available = FALSE;
+ Result = TRUE;
+ } else {
+ Event = ( PINPUT_RECORD ) MALLOC( ( size_t )( sizeof( INPUT_RECORD ) * NumberOfInputEvents ) );
+ if( PeekConsoleInput( _KeyboardHandle,
+ Event,
+ NumberOfInputEvents,
+ &NumberOfEventsRead ) &&
+ NumberOfEventsRead != 0 ) {
+
+ *Available = CheckForAsciiKey( Event, NumberOfInputEvents );
+ Result = TRUE;
+ }
+ FREE( Event );
+ }
+
+ }
+ return( Result );
+}
+
+
+
+
+BOOLEAN
+KEYBOARD::FillBuffer(
+ OUT PBYTE Buffer,
+ IN ULONG BufferSize,
+ OUT PULONG BytesRead
+ )
+
+/*++
+
+Routine Description:
+
+ Fills a buffer with data read from the keyboard.
+
+Arguments:
+
+ Buffer - Points to the buffer where the data will be put.
+
+ BufferSize - Indicates total number of bytes to read from the stream.
+
+ BytesRead - Points to the variable that will contain the number of
+ bytes read.
+
+Return Value:
+
+ BOOLEAN - Indicates if the read operation succeeded.
+
+
+--*/
+
+
+{
+ BOOLEAN Result;
+ ULONG Count;
+
+
+ Result = ReadFile( _KeyboardHandle,
+ Buffer,
+ BufferSize,
+ BytesRead,
+ NULL );
+ if( !Result ) {
+ return( Result );
+ }
+ if (*BytesRead == 0) {
+ _FlagCtrlZ = TRUE;
+ } else if ( IsLineModeEnabled() ) {
+ Count = *BytesRead;
+ while( Count > 0 ) {
+ if( *Buffer != CTRL_Z ) {
+ Count--;
+ Buffer++;
+ } else {
+ *Buffer = 0;
+ *BytesRead -= Count;
+ _FlagCtrlZ = TRUE;
+ Count = 0; // To get out of while() loop
+ }
+ }
+ }
+ BUFFER_STREAM::SetStreamTypeANSI();
+ return( Result );
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+KEYBOARD::Flush(
+ )
+
+/*++
+
+Routine Description:
+
+ Discards all keys in the buffer in BUFFER_STREAM, and flushes the
+ console input buffer.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+
+{
+ BUFFER_STREAM::FlushBuffer();
+ return( FlushConsoleInputBuffer( _KeyboardHandle ) );
+}
+
+
+
+BOOLEAN
+KEYBOARD::EndOfFile(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Indicates if end-of-file has occurred when the keyboard was read.
+ End-of-file for a keyboard means that the keyboard was in line
+ mode and a Ctrl-Z was read from the keyboard.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - returns TRUE if the keyboard is in the line mode and a
+ CTRL-Z was read. Returns FALSE otherwise.
+
+--*/
+
+{
+ BOOLEAN CtrlZ;
+ BOOLEAN MoreKeys;
+ PBOOLEAN Pointer;
+
+ CtrlZ = _FlagCtrlZ;
+ if( CtrlZ ) {
+ if( IsKeyAvailable( &MoreKeys ) ) {
+ //
+ // Enables client to read again from the keyboard
+ //
+ // This method is CONST and shouldn't modify
+ // _FlagCtrlZ, but here is the place to do it.
+ // I cannot define the method as non-const because it was
+ // defined as CONST in the base class
+ //
+ Pointer = &(((PKEYBOARD) this)->_FlagCtrlZ);
+ *Pointer = !MoreKeys;
+ }
+ }
+ return( CtrlZ );
+}
+
+STREAMACCESS
+KEYBOARD::QueryAccess(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Informs the caller about the access to the keyboard.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ STREAMACCESS - Returns READ_ACCESS always.
+
+--*/
+
+{
+ // unreferenced parameters
+ (void)(this);
+
+ return( READ_ACCESS );
+}
+
+
+
+
+ULONG
+KEYBOARD::QueryDelay(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Obtains the delay value of the keyboard.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - The delay value.
+
+--*/
+
+{
+ INT Delay;
+
+ SystemParametersInfo( SPI_GETKEYBOARDDELAY, 0, &Delay, 0 );
+
+ return Delay;
+}
+
+HANDLE
+KEYBOARD::QueryHandle(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns to the caller the keyboard handle.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ HANDLE - Returns the keyboard handle.
+
+--*/
+
+{
+ return( _KeyboardHandle );
+}
+
+
+ULONG
+KEYBOARD::QuerySpeed(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Obtains the speed rate of the keyboard.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - The speed value.
+
+--*/
+
+{
+ WORD Speed;
+
+ SystemParametersInfo( SPI_GETKEYBOARDSPEED, 0, &Speed, 0 );
+
+ return Speed;
+
+}
+
+
+BOOLEAN
+KEYBOARD::SetDelay(
+ IN ULONG Delay
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Sets the delay value of the keyboard.
+
+Arguments:
+
+ Delay - Supplies the delay value
+
+Return Value:
+
+ BOOLEAN - TRUE if delay set, FALSE otherwise
+
+--*/
+
+{
+
+ // return SystemParametersInfo( SPI_SETKEYBOARDDELAY, (UINT)Delay, NULL, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE );
+ return TRUE;
+
+}
+
+
+BOOLEAN
+KEYBOARD::SetSpeed (
+ IN ULONG Speed
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Sets the speed rate of the keyboard.
+
+Arguments:
+
+ Speed - Supplies the speed value
+
+Return Value:
+
+ BOOLEAN - TRUE if speed set, FALSE otherwise
+
+--*/
+
+{
+
+ // return SystemParametersInfo( SPI_SETKEYBOARDSPEED, (UINT)Speed, NULL, SPIF_UPDATEINIFILE | SPIF_SENDWININICHANGE );
+ return TRUE;
+
+}
+
+ULIB_EXPORT
+CONST
+PBOOL
+KEYBOARD::GetPFlagBreak (
+ VOID
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns pointer to _FlagBreak. Used by xcopy to pass pointer to _FlagBreak
+ as the lpCancel flag to CopyFileEx. When the user hits a Ctrl-C, this flag
+ becomes TRUE and CopyFileEx will stop copying the current file.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ Pointer to _Flagbreak
+--*/
+
+{
+ return (&_FlagBreak);
+}
diff --git a/private/utils/ulib/src/list.cxx b/private/utils/ulib/src/list.cxx
new file mode 100644
index 000000000..85f6afc2c
--- /dev/null
+++ b/private/utils/ulib/src/list.cxx
@@ -0,0 +1,336 @@
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+#include "ulib.hxx"
+#include "list.hxx"
+#include "listit.hxx"
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( LIST, SEQUENTIAL_CONTAINER, ULIB_EXPORT );
+
+VOID
+LIST::Construct(
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the object to a default state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _head = NULL;
+ _tail = NULL;
+ _count = 0;
+}
+
+
+VOID
+LIST::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the object to a default state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _head = NULL;
+ _tail = NULL;
+ _count = 0;
+}
+
+
+ULIB_EXPORT
+LIST::~LIST(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for LIST.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+LIST::Initialize(
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the object to a valid initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ Destroy();
+
+ if (!_mem_block_mgr.Initialize(sizeof(OBJECT_LIST_NODE))) {
+ Destroy();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+ULONG
+LIST::QueryMemberCount(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of members in the list.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of members in the list.
+
+--*/
+{
+ return _count;
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+LIST::Put(
+ IN POBJECT Member
+ )
+/*++
+
+Routine Description:
+
+ This routine adds a new member to the end of the list.
+
+Arguments:
+
+ Member - Supplies the element to add to the list.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ if (!_tail) {
+
+ if (!(_head = _tail = (POBJECT_LIST_NODE) _mem_block_mgr.Alloc())) {
+ return FALSE;
+ }
+
+ _head->next = _head->prev = NULL;
+ _head->data = Member;
+
+ _count++;
+ return TRUE;
+ }
+
+ if (!(_tail->next = (POBJECT_LIST_NODE) _mem_block_mgr.Alloc())) {
+ return FALSE;
+ }
+
+ _tail->next->prev = _tail;
+ _tail = _tail->next;
+
+ _tail->next = NULL;
+ _tail->data = Member;
+
+ _count++;
+ return TRUE;
+}
+
+
+POBJECT
+LIST::Remove(
+ IN OUT PITERATOR Position
+ )
+/*++
+
+Routine Description:
+
+ This routine removes the element at the specified position from the
+ list. The iterator is left pointing at the following element in
+ the list.
+
+Arguments:
+
+ Position - Supplies a pointer to the element to remove.
+
+Return Value:
+
+ A pointer to the element removed.
+
+--*/
+{
+ POBJECT_LIST_NODE p;
+ PLIST_ITERATOR piter;
+ POBJECT pobj;
+
+ DebugAssert(LIST_ITERATOR::Cast(Position));
+
+ if (!(piter = (PLIST_ITERATOR) Position) || !(p = piter->_current)) {
+ return NULL;
+ }
+
+ if (p->next) {
+ p->next->prev = p->prev;
+ }
+
+ if (p->prev) {
+ p->prev->next = p->next;
+ }
+
+ if (_head == p) {
+ _head = p->next;
+ }
+
+ if (_tail == p) {
+ _tail = p->prev;
+ }
+
+ piter->_current = p->next;
+
+ pobj = p->data;
+
+ _mem_block_mgr.Free(p);
+
+ _count--;
+
+ return pobj;
+}
+
+
+ULIB_EXPORT
+PITERATOR
+LIST::QueryIterator(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns an iterator for this list.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A valid iterator.
+
+--*/
+{
+ PLIST_ITERATOR p;
+
+ if (!(p = NEW LIST_ITERATOR)) {
+ return NULL;
+ }
+
+ p->Initialize(this);
+
+ return p;
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+LIST::Insert(
+ IN OUT POBJECT Member,
+ IN OUT PITERATOR Position
+ )
+/*++
+
+Routine Description:
+
+ This routine inserts a new element before the specified position.
+ The 'Position' continues to point to the same element.
+
+Arguments:
+
+ Member - Supplies the element to insert.
+ Position - Supplies the point at which to insert this member.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ POBJECT_LIST_NODE p, current;
+
+ DebugAssert(LIST_ITERATOR::Cast(Position));
+
+ current = ((PLIST_ITERATOR) Position)->_current;
+
+ if (!current) {
+ return Put(Member);
+ }
+
+ if (!(p = (POBJECT_LIST_NODE) _mem_block_mgr.Alloc())) {
+ return FALSE;
+ }
+
+ _count++;
+ p->data = Member;
+
+ if (current == _head) {
+ _head = p;
+ }
+
+ p->next = current;
+ p->prev = current->prev;
+ current->prev = p;
+
+ if (p->prev) {
+ p->prev->next = p;
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/ulib/src/listit.cxx b/private/utils/ulib/src/listit.cxx
new file mode 100644
index 000000000..f10f1832e
--- /dev/null
+++ b/private/utils/ulib/src/listit.cxx
@@ -0,0 +1,45 @@
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+#include "ulib.hxx"
+#include "listit.hxx"
+
+
+DEFINE_CONSTRUCTOR( LIST_ITERATOR, ITERATOR );
+
+
+DEFINE_CAST_MEMBER_FUNCTION( LIST_ITERATOR );
+
+
+VOID
+LIST_ITERATOR::Reset(
+ )
+{
+ _current = NULL;
+}
+
+
+POBJECT
+LIST_ITERATOR::GetCurrent(
+ )
+{
+ return _current ? _current->data : NULL;
+}
+
+
+POBJECT
+LIST_ITERATOR::GetNext(
+ )
+{
+ _current = _current ? _current->next : _list->_head;
+ return _current ? _current->data : NULL;
+}
+
+
+POBJECT
+LIST_ITERATOR::GetPrevious(
+ )
+{
+ _current = _current ? _current->prev : _list->_tail;
+ return _current ? _current->data : NULL;
+}
diff --git a/private/utils/ulib/src/machine.cxx b/private/utils/ulib/src/machine.cxx
new file mode 100644
index 000000000..ad548e2dd
--- /dev/null
+++ b/private/utils/ulib/src/machine.cxx
@@ -0,0 +1,312 @@
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+
+#if defined(_AUTOCHECK_)
+extern "C" {
+ #include "nt.h"
+ #include "ntrtl.h"
+ #include "nturtl.h"
+}
+#endif // defined(_AUTOCHECK_)
+
+#include "ulib.hxx"
+#include "machine.hxx"
+
+extern "C" {
+ #include "windows.h"
+}
+
+BOOLEAN bInitialized = FALSE;
+
+#if defined(JAPAN) && defined(_X86_)
+
+extern "C" {
+#include "..\..\..\machine\machinep.h"
+}
+
+#if defined( _AUTOCHECK_ )
+
+DWORD _dwMachineId = MACHINEID_MICROSOFT;
+
+//
+// Local Support routine
+//
+
+#define KEY_WORK_AREA ((sizeof(KEY_VALUE_FULL_INFORMATION) + \
+ sizeof(ULONG)) + 64)
+
+
+InitializeMachineId(
+ VOID
+)
+/*++
+
+Routine Description:
+
+ Given a unicode value name this routine will go into the registry
+ location for the machine identifier information and get the
+ value.
+
+Return Value:
+
+--*/
+
+{
+ HANDLE Handle;
+ NTSTATUS Status;
+ ULONG RequestLength;
+ ULONG ResultLength;
+ UCHAR Buffer[KEY_WORK_AREA];
+ UNICODE_STRING ValueName;
+ UNICODE_STRING KeyName;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
+
+ if( bInitialized ) {
+ return TRUE;
+ } else {
+ bInitialized = TRUE;
+ }
+
+ //
+ // Read the registry to determine of machine type.
+ //
+
+ ValueName.Buffer = REGISTRY_MACHINE_IDENTIFIER;
+ ValueName.Length = sizeof(REGISTRY_MACHINE_IDENTIFIER) - sizeof(WCHAR);
+ ValueName.MaximumLength = sizeof(REGISTRY_MACHINE_IDENTIFIER);
+
+ KeyName.Buffer = REGISTRY_HARDWARE_DESCRIPTION;
+ KeyName.Length = sizeof(REGISTRY_HARDWARE_DESCRIPTION) - sizeof(WCHAR);
+ KeyName.MaximumLength = sizeof(REGISTRY_HARDWARE_DESCRIPTION);
+
+ InitializeObjectAttributes(&ObjectAttributes,
+ &KeyName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ Status = NtOpenKey(&Handle,
+ KEY_READ,
+ &ObjectAttributes);
+
+ if (!NT_SUCCESS(Status)) {
+
+ return FALSE;
+ }
+
+ RequestLength = KEY_WORK_AREA;
+
+ KeyValueInformation = (PKEY_VALUE_FULL_INFORMATION)Buffer;
+
+ Status = NtQueryValueKey(Handle,
+ &ValueName,
+ KeyValueFullInformation,
+ KeyValueInformation,
+ RequestLength,
+ &ResultLength);
+
+ ASSERT( Status != STATUS_BUFFER_OVERFLOW );
+
+ if (Status == STATUS_BUFFER_OVERFLOW) {
+
+ return FALSE;
+
+ }
+
+ NtClose(Handle);
+
+ if (NT_SUCCESS(Status)) {
+
+ if (KeyValueInformation->DataLength != 0) {
+
+ PWCHAR DataPtr;
+ UNICODE_STRING DetectedString, TargetString1, TargetString2;
+
+ //
+ // Return contents to the caller.
+ //
+
+ DataPtr = (PWCHAR)
+ ((PUCHAR)KeyValueInformation + KeyValueInformation->DataOffset);
+
+ //
+ // Initialize strings.
+ //
+
+ RtlInitUnicodeString( &DetectedString, DataPtr );
+ RtlInitUnicodeString( &TargetString1, FUJITSU_FMR_NAME_W );
+ RtlInitUnicodeString( &TargetString2, NEC_PC98_NAME_W );
+
+ //
+ // Check the hardware platform
+ //
+
+ if (RtlPrefixUnicodeString( &TargetString1 , &DetectedString , TRUE)) {
+
+ //
+ // Fujitsu FMR Series.
+ //
+
+ _dwMachineId = MACHINEID_FUJITSU_FMR;
+
+ } else if (RtlPrefixUnicodeString( &TargetString2 , &DetectedString , TRUE)) {
+
+ //
+ // NEC PC-9800 Seriss
+ //
+
+ _dwMachineId = MACHINEID_NEC_PC98;
+
+ } else {
+
+ //
+ // Standard PC/AT comapatibles
+ //
+
+ _dwMachineId = MACHINEID_MS_PCAT;
+
+ }
+
+ return TRUE;
+
+ } else {
+
+ //
+ // Treat as if no value was found
+ //
+
+ return FALSE;
+
+ }
+ }
+
+ return FALSE;
+}
+
+#else // _AUTOCHECK_
+
+DEFINE_EXPORTED_CONSTRUCTOR( MACHINE, OBJECT, ULIB_EXPORT );
+
+DWORD MACHINE::_dwMachineId = MACHINEID_MICROSOFT;
+
+ULIB_EXPORT MACHINE MachinePlatform;
+
+NONVIRTUAL
+ULIB_EXPORT
+BOOLEAN
+MACHINE::Initialize(
+ VOID
+ )
+{
+ HKEY hkeyMap;
+ int ret;
+ DWORD cb;
+ WCHAR szBuff[80];
+ UNICODE_STRING DetectedString,
+ TargetString1,
+ TargetString2;
+
+ if( bInitialized ) {
+ return TRUE;
+ } else {
+ bInitialized = TRUE;
+ }
+
+ if ( RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+ REGISTRY_HARDWARE_SYSTEM,
+ 0,
+ KEY_READ,
+ &hkeyMap) != ERROR_SUCCESS ) {
+ return( FALSE );
+ }
+
+ //
+ // Reg functions deal with bytes, not chars
+ //
+
+ cb = sizeof(szBuff);
+
+ ret = RegQueryValueExW(hkeyMap,
+ REGISTRY_MACHINE_IDENTIFIER,
+ NULL, NULL, (LPBYTE)szBuff, &cb);
+
+ RegCloseKey(hkeyMap);
+
+ if (ret != ERROR_SUCCESS) return( FALSE );
+
+ //
+ // Initialize strings.
+ //
+
+ RtlInitUnicodeString( &DetectedString, szBuff );
+ RtlInitUnicodeString( &TargetString1, FUJITSU_FMR_NAME_W );
+ RtlInitUnicodeString( &TargetString2, NEC_PC98_NAME_W );
+
+ //
+ // Check the hardware platform
+ //
+
+ if (RtlPrefixUnicodeString( &TargetString1 , &DetectedString , TRUE)) {
+
+ //
+ // Fujitsu FMR Series.
+ //
+
+ _dwMachineId = MACHINEID_FUJITSU_FMR;
+
+ } else if (RtlPrefixUnicodeString( &TargetString2 , &DetectedString , TRUE)) {
+
+ //
+ // NEC PC-9800 Seriss
+ //
+
+ _dwMachineId = MACHINEID_NEC_PC98;
+
+ } else {
+
+ //
+ // Standard PC/AT comapatibles
+ //
+
+ _dwMachineId = MACHINEID_MS_PCAT;
+
+ }
+
+ return( TRUE );
+}
+
+NONVIRTUAL
+ULIB_EXPORT
+BOOLEAN
+MACHINE::IsFMR(
+ VOID
+)
+{
+ return( ISFUJITSUFMR( _dwMachineId ) );
+}
+
+NONVIRTUAL
+ULIB_EXPORT
+BOOLEAN
+MACHINE::IsPC98(
+ VOID
+)
+{
+ return( ISNECPC98( _dwMachineId ) );
+}
+
+NONVIRTUAL
+ULIB_EXPORT
+BOOLEAN
+MACHINE::IsPCAT(
+ VOID
+)
+{
+ return( ISMICROSOFT( _dwMachineId ) );
+}
+
+#endif // defined( _AUTOCHECK_ )
+#endif // defined(JAPAN) && defined(_X86_)
diff --git a/private/utils/ulib/src/makefile b/private/utils/ulib/src/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/ulib/src/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/ulib/src/makefile.inc b/private/utils/ulib/src/makefile.inc
new file mode 100644
index 000000000..6cf902f60
--- /dev/null
+++ b/private/utils/ulib/src/makefile.inc
@@ -0,0 +1,4 @@
+..\inc\rtmsg.h msg00001.bin rtmsg.rc: rtmsg.mc ulib.rc
+ mc -v -h ..\inc\ rtmsg.mc
+ copy rtmsg.rc + ulib.rc rtmsg.rc
+
diff --git a/private/utils/ulib/src/mbstr.cxx b/private/utils/ulib/src/mbstr.cxx
new file mode 100644
index 000000000..421d98301
--- /dev/null
+++ b/private/utils/ulib/src/mbstr.cxx
@@ -0,0 +1,597 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ mbstr.cxx
+
+Abstract:
+
+ This module contains the implementation of the MBSTR class. The MBSTR
+ class is a module that provides static methods for operating on
+ multibyte strings.
+
+
+Author:
+
+ Ramon J. San Andres (ramonsa) 21-Feb-1992
+
+Environment:
+
+ ULIB, User Mode
+
+Notes:
+
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "mbstr.hxx"
+
+extern "C" {
+ #include <string.h>
+ #include <ctype.h>
+}
+
+#ifdef DBCS
+#define DB_SP_HI 0x81
+#define DB_SP_LO 0x40
+#endif
+
+PSTR*
+MBSTR::MakeLineArray (
+ INOUT PSTR* Buffer,
+ INOUT PDWORD BufferSize,
+ INOUT PDWORD NumberOfLines
+ )
+/*++
+
+Routine Description:
+
+ Constructs an array of strings into a buffer, one string per line.
+ Adds nulls in the buffer.
+
+Arguments:
+
+ Buffer - Supplies the buffer.
+ Receives pointer remaining buffer
+
+ BufferSize - Supplies the size of the buffer.
+ Receives the size of the remaining buffer
+
+ NumberOfLines - Supplies number of lines wanted.
+ Receives number of lines obtained. If BufferSize is
+ 0 on output, the last line is partial (i.e. equal
+ to Buffer).
+
+Return Value:
+
+ Pointer to array of string pointers.
+
+
+--*/
+{
+
+#if 0
+ PSTR *Array = NULL;
+ DWORD NextElement;
+ DWORD ArraySize;
+ DWORD ArrayLeft;
+ DWORD Lines = 0;
+ DWORD LinesLeft;
+ DWORD Size, Size1;
+ PSTR Buf, Buf1;
+ PSTR p;
+ DWORD Idx;
+
+ if ( Buffer && BufferSize && NumberOfLines ) {
+
+ Buf = *Buffer;
+ Size = *BufferSize;
+ Linesleft = *NumberOfLines;
+
+ if ( Buf && (Array = (PSTR *)MALLOC( CHUNK_SIZE * sizeof( PSTR *)) ) ) {
+
+ ArrayLeft = CHUNK_SIZE;
+ ArraySize = CHUNK_SIZE;
+
+ //
+ // Linearize the buffer and get pointers to all the lines
+ //
+ while ( Size && LinesLeft ) {
+
+ //
+ // If Array is full, reallocate it.
+ //
+ if ( ArrayLeft == 0 ) {
+
+ if ( !(Array = (PSTR *)REALLOC( Array, (ArraySize+CHUNK_SIZE) * sizeof( PSTR * ) ) )) {
+
+ Buf = *Buffer;
+ Size = *BufferSize;
+ Lines = 0;
+ break;
+ }
+
+ ArraySize += CHUNK_SIZE;
+ ArrayLeft += CHUNK_SIZE;
+
+ }
+
+
+ //
+ // Get one line and add it to the array
+ //
+ Buf1 = Buf;
+ Size1 = Size;
+
+ while ( TRUE ) {
+
+ //
+ // Look for end of line
+ //
+ Idx = Strcspn( Buf1, "\r\n" );
+
+
+ //
+ // If end of line not found, we add the last chunk to the list and
+ // increment the line count, but to not update the size.
+ //
+ if ( Idx > Size1 ) {
+ //
+ // End of line not found, we add the last chunk
+ // to the list and stop looking for strings, but
+ // we do not update the size.
+ //
+ LinesLeft = 0;
+ Size1 = Size;
+ Buf1 = Buf;
+ break;
+
+ } else {
+ //
+ // If this is really the end of a line we stop.
+ //
+ Buf1 += Idx;
+ Size1 -= Idx;
+
+ //
+ // If '\r', see if this is really the end of a line.
+ //
+ if ( *Buf1 == '\r' ) {
+
+ if ( Size1 == 0 ) {
+
+ //
+ // Cannot determine if end of line because
+ // ran out of buffer
+ //
+ LinesLeft = 0;
+ Size1 = Size;
+ Buf1 = Buf;
+ break;
+
+ } else if ( *(Buf+1) == '\n' ) {
+
+ //
+ // End of line is \r\n
+ //
+ *Buf1++ = '\0';
+ *Buf1++ = '\0';
+ Size1--;
+ break;
+
+ } else {
+
+ //
+ // Not end of line
+ //
+ Buf1++;
+ Size1--;
+
+ }
+
+ } else {
+
+ //
+ // End of line is \n
+ //
+ Buf1++;
+ Size1--;
+ break;
+ }
+
+ }
+ }
+
+ //
+ // Add line to array
+ //
+ Array[Lines++] = Buf;
+
+ Buf = Buf1;
+ Size = Size1;
+
+ }
+ }
+
+ *Buffer = Buf;
+ *BufferSize = Size;
+ *NumberOfLines = Lines;
+ }
+
+ return Array;
+#endif
+
+ UNREFERENCED_PARAMETER( Buffer );
+ UNREFERENCED_PARAMETER( BufferSize );
+ UNREFERENCED_PARAMETER( NumberOfLines );
+
+ return NULL;
+}
+
+
+
+DWORD
+MBSTR::Hash(
+ IN PSTR String,
+ IN DWORD Buckets,
+ IN DWORD BytesToSum
+ )
+{
+
+ DWORD HashValue = 0;
+ DWORD Bytes;
+
+ if ( !String ) {
+
+ HashValue = (DWORD)-1;
+
+ } else {
+
+ if ( (Bytes = (DWORD)Strlen( String )) > BytesToSum ) {
+ Bytes = BytesToSum;
+ }
+
+ while ( Bytes > 0 ) {
+ HashValue += *(String + --Bytes);
+ }
+
+ HashValue = HashValue % Buckets;
+ }
+
+ return HashValue;
+}
+
+
+
+PSTR
+MBSTR::SkipWhite(
+ IN PSTR p
+ )
+{
+
+#ifdef DBCS
+
+ while (*p) {
+
+ if (*p == DB_SP_HI && *(p+1) == DB_SP_LO) {
+ *p++ = ' ';
+ *p++ = ' ';
+ } else if (!IsDBCSLeadByte(*p) && issspace(*p)) {
+ p++;
+ } else {
+ break;
+ }
+ }
+
+#else
+ while (isspace(*p)) {
+ p++;
+ }
+#endif
+
+ return p;
+
+}
+
+
+
+/**************************************************************************/
+/* Compare two strings, ignoring white space, case is significant, return */
+/* 0 if identical, <>0 otherwise. Leading and trailing white space is */
+/* ignored, internal white space is treated as single characters. */
+/**************************************************************************/
+ULIB_EXPORT
+INT
+MBSTR::Strcmps (
+ IN PSTR p1,
+ IN PSTR p2
+ )
+{
+ char *q;
+
+ p1 = MBSTR::SkipWhite(p1); /* skip any leading white space */
+ p2 = MBSTR::SkipWhite(p2);
+
+ while (TRUE)
+ {
+ if (*p1 == *p2)
+ {
+ if (*p1++ == 0) /* quit if at the end */
+ return (0);
+ else
+ p2++;
+
+#ifdef DBCS
+ if (CheckSpace(p1))
+#else
+ if (isspace(*p1)) /* compress multiple spaces */
+#endif
+ {
+ q = MBSTR::SkipWhite(p1);
+ p1 = (*q == 0) ? q : q - 1;
+ }
+
+#ifdef DBCS
+ if (CheckSpace(p2))
+#else
+ if (isspace(*p2))
+#endif
+ {
+ q = MBSTR::SkipWhite(p2);
+ p2 = (*q == 0) ? q : q - 1;
+ }
+ }
+ else
+ return *p1-*p2;
+ }
+}
+
+
+
+
+
+/**************************************************************************/
+/* Compare two strings, ignoring white space, case is not significant, */
+/* return 0 if identical, <>0 otherwise. Leading and trailing white */
+/* space is ignored, internal white space is treated as single characters.*/
+/**************************************************************************/
+ULIB_EXPORT
+INT
+MBSTR::Strcmpis (
+ IN PSTR p1,
+ IN PSTR p2
+ )
+{
+#ifndef DBCS
+ char *q;
+
+ p1 = MBSTR::SkipWhite(p1); /* skip any leading white space */
+ p2 = MBSTR::SkipWhite(p2);
+
+ while (TRUE)
+ {
+ if (toupper(*p1) == toupper(*p2))
+ {
+ if (*p1++ == 0) /* quit if at the end */
+ return (0);
+ else
+ p2++;
+
+ if (isspace(*p1)) /* compress multiple spaces */
+ {
+ q = SkipWhite(p1);
+ p1 = (*q == 0) ? q : q - 1;
+ }
+
+ if (isspace(*p2))
+ {
+ q = MBSTR::SkipWhite(p2);
+ p2 = (*q == 0) ? q : q - 1;
+ }
+ }
+ else
+ return *p1-*p2;
+ }
+#else // DBCS
+// MSKK KazuM Jan.28.1993
+// Unicode DBCS support
+ PSTR q;
+
+ p1 = MBSTR::SkipWhite(p1); /* skip any leading white space */
+ p2 = MBSTR::SkipWhite(p2);
+
+ while (TRUE)
+ {
+ if (toupper(*p1) == toupper(*p2))
+ {
+ if (*p1++ == 0) /* quit if at the end */
+ return (0);
+ else
+ p2++;
+
+ if (CheckSpace(p1))
+ {
+ q = SkipWhite(p1);
+ p1 = (*q == 0) ? q : q - 1;
+ }
+
+ if (CheckSpace(p2))
+ {
+ q = MBSTR::SkipWhite(p2);
+ p2 = (*q == 0) ? q : q - 1;
+ }
+ }
+ else
+ return *p1-*p2;
+ }
+#endif // DBCS
+}
+
+
+
+#ifdef DBCS
+
+/**************************************************************************/
+/* Routine: CheckSpace */
+/* Arguments: an arbitrary string */
+/* Function: Determine whether there is a space in the string. */
+/* Side effects: none */
+/**************************************************************************/
+INT
+MBSTR::CheckSpace(
+ IN PSTR s
+ )
+{
+ if (isspace(*s) || (*s == DB_SP_HI && *(s+1) == DB_SP_LO))
+ return (TRUE);
+ else
+ return (FALSE);
+}
+
+#endif
+
+
+
+
+
+#if 0
+/**************************************************************************/
+/* strcmpi will compare two string lexically and return one of */
+/* the following: */
+/* - 0 if the strings are equal */
+/* - 1 if first > the second */
+/* - (-1) if first < the second */
+/* */
+/* This was written to replace the run time library version of */
+/* strcmpi which does not correctly compare the european character set. */
+/* This version relies on a version of toupper which uses IToupper. */
+/**************************************************************************/
+
+int FC::_strcmpi(unsigned char *str1, unsigned char *str2)
+{
+ unsigned char c1, c2;
+
+#ifdef DBCS
+ while (TRUE)
+ {
+ c1 = *str1++;
+ c2 = *str2++;
+ if (c1 == '\0' || c2 == '\0')
+ break;
+ if (IsDBCSLeadBYTE(c1) && IsDBCSLeadBYTE(c2))
+ {
+ if (c1 == c2)
+ {
+ c1 = *str1++;
+ c2 = *str2++;
+ if (c1 != c2)
+ break;
+ }
+ else
+ break;
+ }
+ else if (IsDBCSLeadBYTE(c1) || IsDBCSLeadBYTE(c2))
+ return (IsDBCSLeadBYTE(c1) ? 1 : -1);
+ else
+ if ((c1 = toupper(c1)) != (c2 = toupper(c2)))
+ break;
+ }
+ return (c1 == c2 ? 0 : (c1 > c2 ? 1 : -1));
+#else
+ while ((c1 = toupper(*str1++)) == (c2 = toupper(*str2++)))
+ {
+ if (c1 == '\0')
+ return (0);
+ }
+
+ if (c1 > c2)
+ return (1);
+ else
+ return (-1);
+#endif // DBCS
+}
+#endif // if 0
+
+#ifdef DBCS
+//fix kksuzuka: #930
+//Enabling strcmpi disregarding the case of DBCS letters.
+
+ULIB_EXPORT
+INT
+MBSTR::Stricmp (
+ IN PSTR p1,
+ IN PSTR p2
+ )
+{
+ char c1,c2;
+
+ while (TRUE)
+ {
+ c1 = *p1++;
+ c2 = *p2++;
+
+ if (c1=='\0' || c2 == '\0')
+ break;
+
+ if (IsDBCSLeadByte(c1) && IsDBCSLeadByte(c2) && c1 == c2)
+ {
+ if (c1==c2)
+ {
+ c1 = *p1++;
+ c2 = *p2++;
+ if (c1 != c2)
+ break;
+ }
+ else
+ break;
+ }
+
+ else if (IsDBCSLeadByte(c1) || IsDBCSLeadByte(c2))
+ return (IsDBCSLeadByte(c1) ? 1: -1);
+
+ else
+ if ((c1 = toupper(c1)) != (c2 = toupper(c2)))
+ break;
+
+ }
+ return (c1 == c2 ? 0 : (c1 >c2 ? 1: -1));
+}
+
+//fix kksuzuka: #926
+//Enabling strstr disregarding the case of DBCS letters.
+ULIB_EXPORT
+PSTR
+MBSTR::Strstr (
+ IN PSTR p1,
+ IN PSTR p2
+ )
+{
+ DWORD dLen;
+ PSTR pEnd;
+
+ dLen = Strlen(p2);
+ pEnd = p1+ Strlen(p1);
+
+ while ((p1+dLen)<=pEnd) {
+ if ( !memcmp(p1,p2,dLen) ) {
+ return(p1);
+ }
+ if ( IsDBCSLeadByte(*p1) ) {
+ p1 += 2;
+ } else {
+ p1++;
+ }
+ }
+
+ return( NULL );
+}
+
+#endif
diff --git a/private/utils/ulib/src/mem.cxx b/private/utils/ulib/src/mem.cxx
new file mode 100644
index 000000000..89df14071
--- /dev/null
+++ b/private/utils/ulib/src/mem.cxx
@@ -0,0 +1,8 @@
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+#include "ulib.hxx"
+#include "mem.hxx"
+
+
+DEFINE_CONSTRUCTOR( MEM, OBJECT );
diff --git a/private/utils/ulib/src/membmgr.cxx b/private/utils/ulib/src/membmgr.cxx
new file mode 100644
index 000000000..3f0bd4494
--- /dev/null
+++ b/private/utils/ulib/src/membmgr.cxx
@@ -0,0 +1,415 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ membmgr.cxx
+
+Author:
+
+ Norbert P. Kusters (norbertk) 29-May-92
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "membmgr.hxx"
+#include "iterator.hxx"
+
+
+DEFINE_CONSTRUCTOR( STATIC_MEM_BLOCK_MGR, OBJECT );
+
+
+STATIC_MEM_BLOCK_MGR::~STATIC_MEM_BLOCK_MGR(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for STATIC_MEM_BLOCK_MGR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+STATIC_MEM_BLOCK_MGR::Construct(
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the object to a default initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _heap = NULL;
+ _num_blocks = 0;
+ _block_size = 0;
+ _num_allocated = 0;
+ _next_alloc = 0;
+}
+
+
+VOID
+STATIC_MEM_BLOCK_MGR::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the object to a default initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ FREE(_heap);
+ _num_blocks = 0;
+ _block_size = 0;
+ _num_allocated = 0;
+ _next_alloc = 0;
+}
+
+
+BOOLEAN
+STATIC_MEM_BLOCK_MGR::Initialize(
+ IN ULONG MemBlockSize,
+ IN ULONG NumBlocks
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes this object to a usable initial state.
+
+Arguments:
+
+ MemBlockSize - Supplies the number of bytes per mem block.
+ NumBlocks - Supplies the number of mem blocks to be
+ contained by this object.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ Destroy();
+
+ DebugAssert(MemBlockSize);
+
+ if (!(_heap = (PCHAR) MALLOC(NumBlocks*MemBlockSize)) ||
+ !_bitvector.Initialize(NumBlocks)) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ _num_blocks = NumBlocks;
+ _block_size = MemBlockSize;
+
+ return TRUE;
+}
+
+
+PVOID
+STATIC_MEM_BLOCK_MGR::Alloc(
+ )
+/*++
+
+Routine Description:
+
+ This routine allocates a single memory block and returns its
+ pointer.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to a mem block.
+
+--*/
+{
+ if (_num_allocated == _num_blocks) {
+ return NULL;
+ }
+
+ for (;;) {
+
+ if (!_bitvector.IsBitSet(_next_alloc)) {
+
+ _bitvector.SetBit(_next_alloc);
+ _num_allocated++;
+ return &_heap[_next_alloc*_block_size];
+ }
+
+ _next_alloc = (_next_alloc + 1) % _num_blocks;
+ }
+}
+
+
+BOOLEAN
+STATIC_MEM_BLOCK_MGR::Free(
+ OUT PVOID MemBlock
+ )
+/*++
+
+Routine Description:
+
+ This routine frees the given mem block for use by other clients.
+
+Arguments:
+
+ MemBlock - Supplies a pointer to the mem block to free.
+
+Return Value:
+
+ FALSE - The mem block was not freed.
+ TRUE - Success.
+
+--*/
+{
+ ULONG i;
+
+ if (!MemBlock) {
+ return TRUE;
+ }
+
+ i = ((PCHAR) MemBlock - _heap)/_block_size;
+ if (i >= _num_blocks) {
+ return FALSE;
+ }
+
+ DebugAssert(((PCHAR) MemBlock - _heap)%_block_size == 0);
+
+ _bitvector.ResetBit(i);
+ _num_allocated--;
+ _next_alloc = i;
+ return TRUE;
+}
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( MEM_BLOCK_MGR, OBJECT, ULIB_EXPORT );
+
+
+VOID
+MEM_BLOCK_MGR::Construct(
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the object to a default initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ memset(_static_mem_list, 0, 32*sizeof(PVOID));
+}
+
+
+VOID
+MEM_BLOCK_MGR::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the object to a default initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG i;
+
+ for (i = 0; _static_mem_list[i]; i++) {
+ DELETE(_static_mem_list[i]);
+ }
+}
+
+
+ULIB_EXPORT
+MEM_BLOCK_MGR::~MEM_BLOCK_MGR(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for MEM_BLOCK_MGR.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+MEM_BLOCK_MGR::Initialize(
+ IN ULONG MemBlockSize,
+ IN ULONG InitialNumBlocks
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the class to a valid initial state.
+
+Arguments:
+
+ MemBlockSize - Specifies the size of the memory blocks to
+ be allocated from this object.
+ InitialNumBlocks - Specifies the initial number of blocks
+ to be allocated by this object.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ Destroy();
+
+ if (!(_static_mem_list[0] = NEW STATIC_MEM_BLOCK_MGR) ||
+ !_static_mem_list[0]->Initialize(MemBlockSize, InitialNumBlocks)) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+ULIB_EXPORT
+PVOID
+MEM_BLOCK_MGR::Alloc(
+ )
+/*++
+
+Routine Description:
+
+ This routine allocates a mem blocks and returns its pointer.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to a mem block.
+
+--*/
+{
+ ULONG i;
+ PVOID r;
+
+ for (i = 0; _static_mem_list[i]; i++) {
+ if (r = _static_mem_list[i]->Alloc()) {
+ return r;
+ }
+ }
+
+ // At this point all of the current buffers are full so
+ // start another one.
+
+ if (!(_static_mem_list[i] = NEW STATIC_MEM_BLOCK_MGR) ||
+ !_static_mem_list[i]->Initialize(
+ _static_mem_list[i - 1]->QueryBlockSize(),
+ 2*_static_mem_list[i - 1]->QueryNumBlocks())) {
+
+ DELETE(_static_mem_list[i]);
+ return NULL;
+ }
+
+ return _static_mem_list[i]->Alloc();
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+MEM_BLOCK_MGR::Free(
+ IN OUT PVOID MemPtr
+ )
+/*++
+
+Routine Description:
+
+ This routine frees the given memory block.
+
+Arguments:
+
+ MemPtr - Supplies a pointer to the buffer to free.
+
+Return Value:
+
+ This function returns TRUE if the memory was successfully
+ freed.
+
+--*/
+{
+ ULONG i;
+
+ for (i = 0; _static_mem_list[i]; i++) {
+ if (_static_mem_list[i]->Free(MemPtr)) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
diff --git a/private/utils/ulib/src/message.cxx b/private/utils/ulib/src/message.cxx
new file mode 100644
index 000000000..141b501c8
--- /dev/null
+++ b/private/utils/ulib/src/message.cxx
@@ -0,0 +1,400 @@
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+#include "ulib.hxx"
+#include "message.hxx"
+#include "hmem.hxx"
+
+
+DEFINE_EXPORTED_CONSTRUCTOR(MESSAGE, OBJECT, ULIB_EXPORT);
+
+
+ULIB_EXPORT
+MESSAGE::~MESSAGE(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for MESSAGE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+}
+
+BOOLEAN
+MESSAGE::Set(
+ IN MSGID MsgId,
+ IN MESSAGE_TYPE MessageType,
+ IN ULONG MessageVisual
+ )
+/*++
+
+Routine Description:
+
+ This routine sets up the MESSAGE class to display the message with the
+ 'MsgId' resource identifier.
+
+Arguments:
+
+ MsgId - Supplies the resource id of the message.
+ MessageType - Suppies the type of the message to be displayed.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ // unreferenced parameters
+ (void)(this);
+ (void)(MsgId);
+ (void)(MessageType);
+ (void)(MessageVisual);
+
+ return TRUE;
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+MESSAGE::Display(
+ IN PCSTR Format ...
+ )
+/*++
+
+Routine Description:
+
+ This routine displays the message with the specified parameters.
+
+Arguments:
+
+ Format ... - Supplies a printf style list of arguments.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ va_list ap;
+ BOOLEAN r;
+
+ // unreferenced parameters
+ (void)(this);
+
+ va_start(ap, Format);
+ r = DisplayV(Format, ap);
+ va_end(ap);
+
+ return r;
+}
+
+
+BOOLEAN
+MESSAGE::DisplayV(
+ IN PCSTR Format,
+ IN va_list VarPointer
+ )
+/*++
+
+Routine Description:
+
+ This routine displays the message with the specified parameters.
+
+Arguments:
+
+ Format - Supplies a printf style list of arguments.
+ VarPointer - Supplies a varargs pointer to the arguments.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ // unreferenced parameters
+ (void)(this);
+ (void)(Format);
+ (void)(VarPointer);
+
+ return TRUE;
+}
+
+
+PMESSAGE
+MESSAGE::Dup(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a new MESSAGE of the same type.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to a new MESSAGE object.
+
+--*/
+{
+ // unreferenced parameters
+ (void)(this);
+
+ return NEW MESSAGE;
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+MESSAGE::IsYesResponse(
+ IN BOOLEAN Default
+ )
+/*++
+
+Routine Description:
+
+ This routine queries to see if the response to a message is either
+ yes or no.
+
+Arguments:
+
+ Default - Supplies a default answer to the question.
+
+Return Value:
+
+ FALSE - A "no" response.
+ TRUE - A "yes" response.
+
+--*/
+{
+ // unreferenced parameters
+ (void)(this);
+
+ return Default;
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+MESSAGE::QueryStringInput(
+ OUT PWSTRING String
+ )
+/*++
+
+Routine Description:
+
+ This routine queries a string from the user.
+
+Arguments:
+
+ String - Supplies a buffer to return the string into.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ // unreferenced parameters
+ (void)(this);
+
+ return String->Initialize("");
+}
+
+
+
+ULIB_EXPORT
+MSGID
+MESSAGE::SelectResponse(
+ IN ULONG NumberOfSelections ...
+ )
+/*++
+
+Routine Descriptions:
+
+ This routine queries a response from the user. It returns the
+ message id of the response inputted.
+
+Arguments:
+
+ NumberOfSelections - Supplies the number of possible message
+ responses.
+
+ ... - Supplies 'NumberOfSelections' message identifiers.
+
+Return Value:
+
+ The first message id on the list.
+
+--*/
+{
+ va_list ap;
+ MSGID msg;
+
+ // unreferenced parameters
+ (void)(this);
+
+ va_start(ap, NumberOfSelections);
+ msg = va_arg(ap, MSGID);
+ va_end(ap);
+ return msg;
+}
+
+
+
+ULIB_EXPORT
+BOOLEAN
+MESSAGE::WaitForUserSignal(
+ )
+/*++
+
+Routine Description:
+
+ This routine waits for a signal from the user.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ // unreferenced parameters
+ (void)(this);
+
+ return TRUE;
+}
+
+ULIB_EXPORT
+BOOLEAN
+MESSAGE::SetDotsOnly(
+ IN BOOLEAN DotsState
+ )
+{
+ // unreferenced parameters
+ (void)this;
+ (void)DotsState;
+
+ return FALSE;
+}
+
+ULIB_EXPORT
+BOOLEAN
+MESSAGE::IsLoggingEnabled(
+ )
+{
+ return FALSE;
+}
+
+ULIB_EXPORT
+VOID
+MESSAGE::SetLoggingEnabled(
+ IN BOOLEAN Enable
+ )
+{
+ (void)this;
+ (void)Enable;
+}
+
+
+ULIB_EXPORT
+VOID
+MESSAGE::ResetLoggingIterator(
+ )
+{
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+MESSAGE::QueryNextLoggedMessage(
+ OUT PFSTRING MessageText
+ )
+{
+ return FALSE;
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+MESSAGE::QueryPackedLog(
+ IN OUT PHMEM Mem,
+ OUT PULONG PackedDataLength
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+ Mem -- Supplies a container for the packed log.
+ PackedDataLength -- Receives the number of bytes written to Mem.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ FSTRING CurrentString;
+ PWCHAR Buffer;
+ ULONG NewBufferSize, CurrentOffset;
+
+ if( !IsLoggingEnabled() ) {
+
+ // BUGBUG billmc -- this should really return FALSE!
+ //
+ FSTRING Hello;
+
+ Hello.Initialize( L"Hello World!\n" );
+
+ *PackedDataLength = Hello.QueryChCount() * sizeof(WCHAR);
+
+ return( Mem->Resize( Hello.QueryChCount() * sizeof(WCHAR) ) &&
+ Hello.QueryWSTR( 0, TO_END,
+ (PWCHAR)Mem->GetBuf(), Mem->QuerySize() ) );
+ }
+
+ ResetLoggingIterator();
+ CurrentOffset = 0;
+
+ while( QueryNextLoggedMessage( &CurrentString ) ) {
+
+ NewBufferSize = (CurrentOffset + CurrentString.QueryChCount()) * sizeof(WCHAR);
+ if( NewBufferSize > Mem->QuerySize() &&
+ !Mem->Resize( (NewBufferSize + 1023)/1024 * 1024, 0x1 ) ) {
+
+ return FALSE;
+ }
+
+ Buffer = (PWCHAR)Mem->GetBuf();
+ memcpy( Buffer + CurrentOffset,
+ CurrentString.GetWSTR(),
+ CurrentString.QueryChCount() * sizeof(WCHAR) );
+
+ CurrentOffset += CurrentString.QueryChCount();
+ }
+
+ *PackedDataLength = CurrentOffset * sizeof(WCHAR);
+ return TRUE;
+}
diff --git a/private/utils/ulib/src/newdel.cxx b/private/utils/ulib/src/newdel.cxx
new file mode 100644
index 000000000..1cf15b52d
--- /dev/null
+++ b/private/utils/ulib/src/newdel.cxx
@@ -0,0 +1,260 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ newdel.cxx
+
+Abstract:
+
+ This module implements the C++ new and delete operators for
+ the Setup-Loader environment. In other environments, the utilities
+ use the standard C++ new and delete.
+
+Author:
+
+ David J. Gilman (davegi) 07-Dec-1990
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+
+
+
+extern "C"
+int _cdecl
+_purecall( );
+
+int _cdecl
+_purecall( )
+{
+
+ DebugAbort( "Pure virtual function called.\n" );
+
+ return 0;
+}
+
+
+
+
+
+#if defined( _SETUP_LOADER_ ) || defined( _AUTOCHECK_ )
+
+// When the utilities are running the Setup Loader
+// or Autocheck environments, they can't use the C-Run-
+// Time new and delete; instead, these functions are
+// provided.
+//
+PVOID _cdecl
+operator new (
+ IN size_t bytes
+ )
+/*++
+
+Routine Description:
+
+ This routine allocates 'bytes' bytes of memory.
+
+Arguments:
+
+ bytes - Supplies the number of bytes requested.
+
+Return Value:
+
+ A pointer to 'bytes' bytes or NULL.
+
+--*/
+{
+ #if defined( _AUTOCHECK_ )
+
+ return RtlAllocateHeap(RtlProcessHeap(), 0, bytes);
+
+ #elif defined( _SETUP_LOADER_ )
+
+ return SpMalloc( bytes );
+
+ #else // _AUTOCHECK_ and _SETUP_LOADER_ not defined
+
+ return (PVOID) LocalAlloc(0, bytes);
+
+ #endif // _AUTOCHECK_
+}
+
+
+VOID _cdecl
+operator delete (
+ IN PVOID pointer
+ )
+/*++
+
+Routine Description:
+
+ This routine frees the memory pointed to by 'pointer'.
+
+Arguments:
+
+ pointer - Supplies a pointer to the memoery to be freed.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if (pointer) {
+
+ #if defined( _AUTOCHECK_ )
+
+ RtlFreeHeap(RtlProcessHeap(), 0, pointer);
+
+ #elif defined( _SETUP_LOADER_ )
+
+ SpFree( pointer );
+
+ #else // _AUTOCHECK_ and _SETUP_LOADER_ not defined
+
+ LocalFree( pointer );
+
+ #endif // _AUTOCHECK_
+
+ }
+}
+
+
+typedef void (*PF)(PVOID);
+typedef void (*PFI)(PVOID, int);
+PVOID
+__vec_new(
+ IN OUT PVOID op,
+ IN int number,
+ IN int size,
+ IN PVOID f)
+/*
+ allocate a vector of "number" elements of size "size"
+ and initialize each by a call of "f"
+*/
+{
+ if (op == 0) {
+
+ #if defined( _AUTOCHECK_ )
+
+ op = RtlAllocateHeap(RtlProcessHeap(), 0, number*size);
+
+ #elif defined( _SETUP_LOADER_ )
+
+ op = SpMalloc( number*size );
+
+ #else // _AUTOCHECK_ and _SETUP_LOADER_ not defined
+
+ op = (PVOID) LocalAlloc(0, number*size);
+
+ #endif // _AUTOCHECK_
+
+ }
+
+ if (op && f) {
+
+ register char* p = (char*) op;
+ register char* lim = p + number*size;
+ register PF fp = PF(f);
+ while (p < lim) {
+ (*fp) (PVOID(p));
+ p += size;
+ }
+ }
+
+ return op;
+}
+
+
+void
+__vec_delete(
+ PVOID op,
+ int n,
+ int sz,
+ PVOID f,
+ int del,
+ int x)
+
+/*
+ destroy a vector of "n" elements of size "sz"
+*/
+{
+ // unreferenced parameters
+ // I wonder what it does--billmc
+ (void)(x);
+
+ if (op) {
+ if (f) {
+ register char* cp = (char*) op;
+ register char* p = cp;
+ register PFI fp = PFI(f);
+ p += n*sz;
+ while (p > cp) {
+ p -= sz;
+ (*fp)(PVOID(p), 2); // destroy VBC, don't delete
+ }
+ }
+ if (del) {
+
+ #if defined( _AUTOCHECK_ )
+
+ RtlFreeHeap(RtlProcessHeap(), 0, op);
+
+ #elif defined( _SETUP_LOADER_ )
+
+ SpFree( op );
+
+ #else // _AUTOCHECK_ not defined
+
+ LocalFree(op);
+
+ #endif // _AUTOCHECK_
+
+ }
+ }
+}
+
+#endif // _SETUP_LOADER_
+
+ULIB_EXPORT
+PVOID
+UlibRealloc(
+ PVOID x,
+ ULONG size
+ )
+{
+#if defined( _SETUP_LOADER_ )
+
+ return SpRealloc(x, size);
+
+#else // _SETUP_LOADER_
+
+ PVOID p;
+ ULONG l;
+
+
+ if (size <= (l = RtlSizeHeap(RtlProcessHeap(), 0, x))) {
+ return x;
+ }
+
+ if (!(p = MALLOC(size))) {
+ return NULL;
+ }
+
+ memcpy(p, x, (UINT) l);
+
+ FREE(x);
+
+ return p;
+
+#endif // _SETUP_LOADER_
+}
diff --git a/private/utils/ulib/src/object.cxx b/private/utils/ulib/src/object.cxx
new file mode 100644
index 000000000..c89eb4a70
--- /dev/null
+++ b/private/utils/ulib/src/object.cxx
@@ -0,0 +1,94 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ object.cxx
+
+Abstract:
+
+ This module contains the definitions for the non-inline member functions
+ for the class OBJECT, the root of the Ulib hierarchy. OBJECT's
+ constructor merely initializes it's internal CLASS_DESCRIPTOR to point
+ to the static descriptor for the class at the beginning of this
+ construction chain.
+
+Author:
+
+ David J. Gilman (davegi) 30-Oct-1990
+
+Environment:
+
+ ULIB, User Mode
+
+[Notes:]
+
+ optional-notes
+
+--*/
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+
+ULIB_EXPORT
+OBJECT::OBJECT(
+ )
+{
+}
+
+ULIB_EXPORT
+OBJECT::~OBJECT(
+ )
+{
+}
+
+
+ULIB_EXPORT
+LONG
+OBJECT::Compare (
+ IN PCOBJECT Object
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Compare two objects based on their CLASS_ID's
+
+Arguments:
+
+ Object - Supplies the object to compare with.
+
+Return Value:
+
+ LONG < 0 - supplied OBJECT has a higher CLASS_ID
+ == 0 - supplied object has same CLASS_ID
+ > 0 - supplied OBJECT has a lower CLASS_ID
+
+Notes:
+
+ It is expected that derived classes will overload this method and supply
+ an implementation that is more meaningful (i.e. class specific). This
+ implementation is ofeered as a default but is fairly meaningless as
+ CLASS_IDs are allocated randomly (but uniquely) at run-time by
+ CLASS_DESCRIPTORs. Therefore comparing two CLASS_IDs is not very
+ interesting (e.g. it will help if an ORDERED_CONTAINER of homogenous
+ objects is sorted).
+
+--*/
+
+{
+ LONG r;
+
+ DebugPtrAssert( Object );
+
+ r = QueryClassId() - Object->QueryClassId();
+
+ return r ? r : (this - Object);
+}
+
+
+DEFINE_OBJECT_DBG_FUNCTIONS;
diff --git a/private/utils/ulib/src/path.cxx b/private/utils/ulib/src/path.cxx
new file mode 100644
index 000000000..c502c6828
--- /dev/null
+++ b/private/utils/ulib/src/path.cxx
@@ -0,0 +1,1449 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ path.cxx
+
+Abstract:
+
+ This contains the implementation for all methods handling file
+ path names. These are needed for use with an file i/o or the
+ FILE and DIR objects.
+
+Author:
+
+ bruce wilson w-wilson 21-Mar-90
+ steve rowe stever 27-Dec-90
+
+Environment:
+
+ ULIB, user mode
+
+Revision History:
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+extern "C" {
+ #include <string.h>
+}
+#include "ulib.hxx"
+#include "wstring.hxx"
+#include "path.hxx"
+#include "system.hxx"
+
+#if DBG==1
+ #define PATH_SIGNATURE 0xADDBEEAD
+#endif
+
+
+typedef enum _SPECIAL_DEVICES {
+ LPT,
+ COM,
+ CON,
+ PRN,
+ AUX,
+ LAST_SPECIAL_DEVICE
+} SPECIAL_DEVICES;
+
+
+//
+// Static member data.
+//
+PWSTRING _SlashString;
+BOOLEAN _fInit = FALSE;
+PWSTRING _SpecialDevices[ LAST_SPECIAL_DEVICE ];
+
+#define DELIMITER_STRING "\\"
+#define DELIMITER_CHAR ((WCHAR)'\\')
+
+
+
+BOOLEAN
+PATH::Initialize (
+ )
+
+/*++
+
+Routine Description:
+
+ Perform global initialization of the PATH class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if global initialization was succesful
+
+Notes:
+
+ Global initialization should be interpreted as class (rather than object)
+ initialization. This routine should be called by ALL other
+ PATH::Initialize member functions.
+
+ Current this routine:
+
+ - constructs and initializes _SlashString, a WSTRING that
+ contains a '\'
+
+--*/
+
+{
+ // unreferenced parameters
+ (void)(this);
+
+ if (!_fInit) {
+
+ if ( (( _SlashString = NEW DSTRING) != NULL) &&
+ ((_SpecialDevices[LPT] = NEW DSTRING) != NULL) &&
+ ((_SpecialDevices[COM] = NEW DSTRING) != NULL) &&
+ ((_SpecialDevices[CON] = NEW DSTRING) != NULL) &&
+ ((_SpecialDevices[PRN] = NEW DSTRING) != NULL) &&
+ ((_SpecialDevices[AUX] = NEW DSTRING) != NULL) &&
+ _SlashString->Initialize( DELIMITER_STRING ) &&
+ _SpecialDevices[LPT]->Initialize( "LPT" ) &&
+ _SpecialDevices[COM]->Initialize( "COM" ) &&
+ _SpecialDevices[CON]->Initialize( "CON" ) &&
+ _SpecialDevices[PRN]->Initialize( "PRN" ) &&
+ _SpecialDevices[AUX]->Initialize( "AUX" )
+ ) {
+
+ return _fInit = TRUE;
+
+ }
+ }
+
+ return FALSE;
+}
+
+ULIB_EXPORT
+BOOLEAN
+PATH::EndsWithDelimiter (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns TRUE if the path ends with slash
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the path ends with a slash
+
+--*/
+{
+
+ return ( _PathString.QueryChAt( _PathString.QueryChCount() - 1 ) == DELIMITER_CHAR );
+
+}
+
+ULIB_EXPORT
+PARRAY
+PATH::QueryComponentArray (
+ OUT PARRAY Array
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Obtain an array of strings containing all the components in the path.
+ Each string will have an element in the path delimited by '\\'
+
+Arguments:
+
+ Array - Supplies an optional pointer to the array to fill.
+
+Return Value:
+
+ Pointer to the array
+
+--*/
+
+{
+
+ CHNUM Index;
+ CHNUM DelimiterPosition;
+ CHNUM StringSize;
+ PWSTRING Component;
+
+ if (!Array) {
+ Array = NEW ARRAY;
+ }
+
+ DebugPtrAssert( Array );
+ DebugAssert( _Initialized == TRUE );
+
+ Array->Initialize();
+
+ Index = 0;
+ StringSize = _PathString.QueryChCount();
+
+ while ( ( Index < StringSize) &&
+ ( _PathString.QueryChAt( Index ) == DELIMITER_CHAR ) ) {
+ Index++;
+ }
+
+ while ( Index < StringSize ) {
+
+ DelimiterPosition = _PathString.Strchr( DELIMITER_CHAR, Index );
+
+ Component = _PathString.QueryString( Index,
+ (DelimiterPosition == INVALID_CHNUM) ? TO_END : DelimiterPosition - Index );
+
+ DebugPtrAssert( Component );
+
+ if ( !Component ) {
+ break;
+ }
+
+ Array->Put( Component );
+
+ if ( DelimiterPosition == INVALID_CHNUM ) {
+ Index = StringSize;
+ } else {
+ Index = DelimiterPosition + 1;
+ }
+ }
+
+ return Array;
+}
+
+CHNUM
+PATH::QueryDeviceLen(
+ IN PWSTRING pString
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Find length in character of drive section
+
+Arguments:
+
+ pString - Supplies the string to determine drive size.
+
+Return Value:
+
+ CHNUM - Number of characters making up drive section. If no
+ drive section then the length is 0.
+
+--*/
+{
+ CHNUM Position = 0;
+ CHNUM Position1;
+ SPECIAL_DEVICES Index;
+ ULONG tmp;
+ INT Pos;
+ LONG Number;
+
+
+ UNREFERENCED_PARAMETER( (void)this );
+
+ DebugPtrAssert( pString );
+
+ if ( pString->QueryChCount() > 0) {
+
+ //
+ // Check for special device
+ //
+ Pos = (INT)pString->QueryChCount() - 1;
+
+ while ( (Pos >= 0) && (pString->QueryChAt( (CHNUM)Pos ) != DELIMITER_CHAR) ) {
+ Pos --;
+ }
+
+ Pos++;
+
+ for (Index = LPT; Index < LAST_SPECIAL_DEVICE;
+ (tmp = (ULONG) Index, tmp++, Index = (SPECIAL_DEVICES) tmp) ) {
+
+ if ( !pString->Stricmp( _SpecialDevices[Index],
+ (CHNUM)Pos ) ) {
+
+ Position = (CHNUM)Pos + _SpecialDevices[Index]->QueryChCount();
+
+ //
+ // LPT && COM must be followed by a number;
+ //
+ if ( (Index == LPT) || (Index == COM) ) {
+ if ( Position >= pString->QueryChCount()) {
+ continue;
+ }
+ while ( (Position < pString->QueryChCount()) &&
+ pString->QueryNumber( &Number, Position, 1 ) ) {
+
+ Position++;
+ }
+ }
+
+ if (Position >= pString->QueryChCount()) {
+ return Position;
+ } else if (pString->QueryChAt( Position ) == (WCHAR)':') {
+ return Position+1;
+ }
+ }
+ }
+ //
+ // Look for ':'
+ //
+ if ((Position = pString->Strchr((WCHAR)':')) != INVALID_CHNUM) {
+ return Position + 1;
+ }
+
+ //
+ // check for leading "\\"
+ //
+ if ( pString->QueryChCount() > 1 &&
+ pString->QueryChAt(0) == DELIMITER_CHAR &&
+ pString->QueryChAt(1) == DELIMITER_CHAR) {
+
+ //
+ // the device is a machine name - find the second backslash
+ // (start search after first double backsl). Note that this
+ // means that the device names if formed by the machine name
+ // and the sharepoint.
+ //
+ if ( ((Position = pString->Strchr( DELIMITER_CHAR, 2 )) != INVALID_CHNUM )) {
+
+ Position1 = pString->Strchr( DELIMITER_CHAR, Position+1 );
+ if ( Position1 == INVALID_CHNUM ) {
+ return pString->QueryChCount();
+ }
+ return Position1;
+
+ }
+
+ //
+ // No backslash found, this is an invalid device
+ //
+ DebugAbort( "Invalid Device name" );
+
+ }
+
+
+ }
+
+ return 0;
+}
+
+VOID
+PATH::SetPathState(
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the state information for the Path
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ CHNUM chnLastSlash;
+ CHNUM chnLastDot;
+ CHNUM chnAcum;
+ CHNUM FirstSeparator;
+
+ //
+ // Find the number of characters in the device name
+ //
+ chnAcum = _PathState.DeviceLen = QueryDeviceLen( &_PathString );
+
+ //
+ // Find the number of characters in the dirs portion of the path
+ // by searching for the last '\'
+ //
+ if ( _PathString.QueryChAt( chnAcum ) == DELIMITER_CHAR ) {
+ //
+ // Skip over the slash after the device name
+ //
+ FirstSeparator = 1;
+ chnAcum++;
+
+ } else {
+
+ FirstSeparator = 0;
+ }
+
+ if ( chnAcum < _PathString.QueryChCount() ) {
+
+ if (( chnLastSlash = _PathString.Strrchr( DELIMITER_CHAR, chnAcum )) != INVALID_CHNUM ) {
+
+ //
+ // The dirs length is that character position less the length
+ // of the device
+ //
+ _PathState.DirsLen = chnLastSlash - _PathState.DeviceLen;
+ _PathState.SeparatorLen = 1;
+
+ chnAcum += _PathState.DirsLen;
+ if ( FirstSeparator == 0 ) {
+ chnAcum++;
+ }
+ } else {
+ //
+ // There is no dirs portion of this path, but there is a name.
+ //
+ _PathState.DirsLen = FirstSeparator;
+ _PathState.SeparatorLen = 0;
+
+ }
+ } else {
+
+ //
+ // There is no name portion in this path, and the dirs portion
+ // might be empty (or consist solely of the delimiter ).
+ //
+ _PathState.DirsLen = FirstSeparator;
+ _PathState.SeparatorLen = 0;
+ }
+
+ if ( chnAcum < _PathString.QueryChCount() ) {
+
+ //
+ // Find the number of characters in the name portion of the path
+ // by searching for the last '.'
+ //
+ if (( chnLastDot = _PathString.Strrchr( ( WCHAR )'.',
+ chnAcum )) != INVALID_CHNUM ) {
+
+ _PathState.BaseLen = chnLastDot - chnAcum;
+
+ chnAcum += _PathState.BaseLen + 1;
+
+ _PathState.ExtLen = _PathString.QueryChCount() - chnAcum;
+
+ _PathState.NameLen = _PathState.BaseLen + _PathState.ExtLen + 1;
+
+
+ } else {
+
+ //
+ // There is no last '.' so the name length is the length of the
+ // component from the last '\' to the end of the path (adjusted
+ // for zero base) and there is no extension.
+ //
+
+ _PathState.NameLen = _PathString.QueryChCount() - chnAcum;
+ _PathState.BaseLen = _PathState.NameLen;
+ _PathState.ExtLen = 0;
+
+ }
+ } else {
+
+ //
+ // There is no name part
+ //
+ _PathState.NameLen = 0;
+ _PathState.BaseLen = 0;
+ _PathState.ExtLen = 0;
+
+ }
+
+
+ //
+ // The prefix length is the sum of the device and dirs
+ //
+ _PathState.PrefixLen = _PathState.DeviceLen + _PathState.DirsLen;
+
+ //
+ // If The device refers to a drive, uppercase it. (Done for
+ // compatibility with some DOS apps ).
+ //
+ if ( _PathState.DeviceLen == 2 ) {
+ _PathString.Strupr( 0, 1 );
+ }
+
+}
+
+DEFINE_EXPORTED_CONSTRUCTOR( PATH, OBJECT, ULIB_EXPORT );
+
+DEFINE_CAST_MEMBER_FUNCTION( PATH );
+
+VOID
+PATH::Construct (
+ )
+
+{
+ _PathState.BaseLen = 0;
+ _PathState.DeviceLen= 0;
+ _PathState.DirsLen = 0;
+ _PathState.ExtLen = 0;
+ _PathState.NameLen = 0;
+ _PathState.PrefixLen= 0;
+
+ _PathBuffer[0] = 0;
+ _PathString.Initialize(_PathBuffer, MAX_PATH);
+
+#if DBG==1
+ _Signature = PATH_SIGNATURE;
+#endif
+
+}
+
+ULIB_EXPORT
+BOOLEAN
+PATH::Initialize(
+ IN PCWSTR InitialPath,
+ IN BOOLEAN Canonicalize
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize a PATH object with the supplied string. No validation
+ on the given path is performed unless 'Canonicalize' is set to TRUE.
+
+Arguments:
+
+ InitialPath - Supplies a zero terminated string
+ Canonicalize- Supplies a flag, which if TRUE indicates that the PATH
+ should be canoicalized at initialization time (i.e. now)
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the PATH was succesfully initialized.
+
+--*/
+
+{
+ PWSTR filepart;
+ DWORD CharsInPath;
+
+
+ DebugPtrAssert( InitialPath );
+
+ //
+ // Perform global (class) initialization
+ //
+ if ( !_fInit ) {
+ if (!Initialize()) {
+ DebugAbort( "Class initialization failed" );
+ return FALSE;
+ }
+ }
+
+ // Avoid copies during Strcat by making this a reasonable size.
+ if (!_PathString.NewBuf(MAX_PATH - 1)) {
+ return FALSE;
+ }
+
+ if ( Canonicalize ) {
+
+ if (!_PathString.NewBuf(MAX_PATH - 1) ||
+ !(CharsInPath = GetFullPathName((LPWSTR) InitialPath,
+ MAX_PATH,
+ (LPWSTR) _PathString.GetWSTR(),
+ &filepart)) ||
+ CharsInPath > MAX_PATH) {
+
+ return FALSE;
+ }
+
+ _PathString.SyncLength();
+
+ SetPathState( );
+#if DBG==1
+ _Initialized = TRUE;
+#endif
+ return TRUE;
+
+ } else if( ((PWSTRING) &_PathString)->Initialize( InitialPath )) {
+
+ SetPathState( );
+#if DBG==1
+ _Initialized = TRUE;
+#endif
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+ULIB_EXPORT
+BOOLEAN
+PATH::Initialize(
+ IN PCWSTRING InitialPath,
+ IN BOOLEAN Canonicalize
+
+ )
+{
+ DebugPtrAssert( InitialPath );
+
+ return Initialize( InitialPath->GetWSTR(), Canonicalize );
+}
+
+ULIB_EXPORT
+BOOLEAN
+PATH::Initialize (
+ IN PCPATH InitialPath,
+ IN BOOLEAN Canonicalize
+ )
+
+{
+ DebugPtrAssert( InitialPath );
+
+ return Initialize( InitialPath->GetPathString()->GetWSTR(), Canonicalize );
+}
+
+ULIB_EXPORT
+PATH::~PATH (
+ )
+
+{
+}
+
+ULIB_EXPORT
+BOOLEAN
+PATH::AppendBase (
+ IN PCWSTRING Base,
+ IN BOOLEAN Absolute
+ )
+
+/*++
+
+Routine Description:
+
+ Append the supplied name to the end of this PATH.
+
+Arguments:
+
+ Base - Supplies the string to be appended.
+ Absolute - Supplies a flag which if TRUE means that the path must
+ be absolute.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the '\' and the supplied string was succesfully
+ appended.
+
+--*/
+
+{
+ BOOLEAN AppendedSlash = FALSE;
+
+ DebugPtrAssert( Base );
+ DebugAssert( _Initialized );
+
+ //
+ // If the path does not consist of only a drive letter followed by a
+ // colon, we might need to add a '\'
+ //
+ if ( _PathString.QueryChCount() > 0 ) {
+ if ( !(( _PathState.DeviceLen == _PathString.QueryChCount()) &&
+ ( _PathString.QueryChAt( _PathState.DeviceLen - 1) == (WCHAR)':')) ||
+ Absolute ) {
+
+
+ if ( _PathString.QueryChAt( _PathString.QueryChCount() - 1 ) != (WCHAR)'\\' ) {
+
+ if ( !_PathString.Strcat( _SlashString )) {
+ return FALSE;
+ }
+
+ AppendedSlash = TRUE;
+ }
+ }
+ }
+
+ //
+ // Append the base
+ //
+ if ( _PathString.Strcat( Base )) {
+ SetPathState();
+ return TRUE;
+ }
+
+ //
+ // Could not append base, remove the slash if we appended it
+ //
+ if ( AppendedSlash ) {
+ TruncateBase();
+ }
+
+ return FALSE;
+}
+
+ULIB_EXPORT
+BOOLEAN
+PATH::HasWildCard (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determines if the name portion of the path contains wild cards
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the name portion of the path has wild cards
+ FALSE otherwise
+
+--*/
+
+{
+
+ FSTRING WildCards;
+
+ DebugAssert( _Initialized );
+
+ if ( _PathString.QueryChCount() > 0 ) {
+
+ WildCards.Initialize( (PWSTR) L"*?" );
+
+ if (_PathString.Strcspn( &WildCards, _PathState.PrefixLen ) != INVALID_CHNUM ) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+
+}
+
+ULIB_EXPORT
+BOOLEAN
+PATH::IsDrive(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns TRUE if the path refers to a device name
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - TRUE if the path is a device name.
+ FALSE otherwise.
+
+--*/
+
+{
+ DebugAssert( _Initialized );
+
+ return ( _PathState.DeviceLen > 0 ) &&
+ ( (_PathString.QueryChCount() == _PathState.DeviceLen) );
+
+}
+
+BOOLEAN
+PATH::IsRoot(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns TRUE if the path refers to a root directory
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - TRUE if the path is a root directory.
+ FALSE otherwise.
+
+--*/
+
+{
+ DebugAssert( _Initialized );
+
+ return( ( (_PathString.QueryChCount() == 1 ) &&
+ (_PathString.QueryChAt( 0 ) == DELIMITER_CHAR ) ) ||
+ ( ( _PathState.DeviceLen > 0 ) &&
+ ( _PathString.QueryChCount() == _PathState.DeviceLen + 1 ) &&
+ ( _PathString.QueryChAt( _PathState.DeviceLen ) == DELIMITER_CHAR ) )
+ );
+}
+
+ULIB_EXPORT
+PPATH
+PATH::QueryFullPath(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PPATH
+
+--*/
+
+{
+
+
+ REGISTER PPATH pFullPath;
+ REGISTER PWSTRING pFullPathString;
+
+ DebugAssert( _Initialized );
+
+ //
+ // If the full path name string for this PATH can not be queried
+ // or a new PATH, representing the full path, can not be constructed
+ // return NULL.
+ //
+
+ if ((( pFullPathString = QueryFullPathString( )) == NULL ) ||
+ (( pFullPath = NEW PATH ) == NULL )) {
+
+ return NULL;
+ }
+
+ //
+ // If the new, full path, can not be initialized, delete it.
+ //
+
+ if( ! ( pFullPath->Initialize( pFullPathString ))) {
+
+ DELETE( pFullPath );
+ }
+
+ //
+ // Delete the full path string and return a pointer to the new, full path
+ // (note that the pointer may be NULL).
+ //
+
+ DELETE( pFullPathString );
+
+ return pFullPath ;
+}
+
+ULIB_EXPORT
+PWSTRING
+PATH::QueryFullPathString (
+ ) CONST
+{
+
+ LPWSTR pszName;
+
+ PWSTRING pwcFullPathString;
+ WSTR szBufferSrc[ MAX_PATH ];
+ WSTR szBufferTrg[ MAX_PATH ];
+
+ DebugAssert( _Initialized );
+
+ if( (pwcFullPathString = NEW DSTRING ()) != NULL ) {
+
+ if ( _PathString.QueryWSTR( 0, TO_END, szBufferSrc, MAX_PATH ) ) {
+
+ if (GetFullPathName( szBufferSrc,MAX_PATH,szBufferTrg,&pszName)) {
+
+ if (pwcFullPathString->Initialize(szBufferTrg)) {
+
+ return pwcFullPathString;
+
+ }
+ }
+ }
+ }
+
+ DELETE( pwcFullPathString );
+
+ return NULL;
+
+}
+
+ULIB_EXPORT
+BOOLEAN
+PATH::SetDevice (
+ IN PCWSTRING NewDevice
+ )
+{
+ DebugAssert( _Initialized );
+ DebugPtrAssert( NewDevice );
+
+ if (_PathState.DeviceLen) {
+ if (!_PathString.Replace(QueryDeviceStart(), _PathState.DeviceLen,
+ NewDevice)) {
+
+ return FALSE;
+ }
+ } else {
+ if (!_PathString.Strcat(NewDevice)) {
+ return FALSE;
+ }
+ }
+
+ SetPathState();
+
+ return TRUE;
+}
+
+BOOLEAN
+PATH::SetPrefix (
+ IN PCWSTRING NewPrefix
+ )
+{
+ DebugAssert( _Initialized );
+ DebugPtrAssert( NewPrefix );
+
+ if (_PathState.PrefixLen) {
+
+ if (!_PathString.Replace(QueryPrefixStart(), _PathState.PrefixLen,
+ NewPrefix)) {
+
+ return FALSE;
+ }
+
+ } else {
+
+ if (!_PathString.Strcat(NewPrefix)) {
+ return FALSE;
+ }
+ }
+
+ SetPathState();
+
+ return TRUE;
+}
+
+ULIB_EXPORT
+BOOLEAN
+PATH::SetName (
+ IN PCWSTRING NewName
+ )
+{
+ DebugAssert( _Initialized );
+ DebugPtrAssert( NewName );
+
+ if (_PathState.NameLen) {
+
+ if (!_PathString.Replace(QueryNameStart(), _PathState.NameLen,
+ NewName)) {
+
+ return FALSE;
+ }
+
+ } else {
+
+ if (!_PathString.Strcat(NewName)) {
+ return FALSE;
+ }
+ }
+
+ SetPathState();
+
+ return TRUE;
+}
+
+BOOLEAN
+PATH::SetBase (
+ IN PCWSTRING NewBase
+ )
+{
+ DebugAssert( _Initialized );
+ DebugPtrAssert( NewBase );
+
+ if (_PathState.BaseLen) {
+
+ if (!_PathString.Replace(QueryBaseStart(), _PathState.BaseLen,
+ NewBase)) {
+
+ return FALSE;
+ }
+
+ } else {
+
+ if (!_PathString.Strcat(NewBase)) {
+ return FALSE;
+ }
+ }
+
+ SetPathState();
+
+ return TRUE;
+}
+
+BOOLEAN
+PATH::SetExt (
+ IN PCWSTRING NewExt
+ )
+{
+ DebugAssert( _Initialized );
+ DebugPtrAssert( NewExt );
+
+ if (_PathState.ExtLen) {
+
+ if (!_PathString.Replace(QueryExtStart(), _PathState.ExtLen,
+ NewExt)) {
+
+ return FALSE;
+ }
+
+ } else {
+
+ if (!_PathString.Strcat(NewExt)) {
+ return FALSE;
+ }
+ }
+
+ SetPathState();
+
+ return TRUE;
+}
+
+ULIB_EXPORT
+BOOLEAN
+PATH::TruncateBase (
+ )
+
+/*++
+
+Routine Description:
+
+ This routine truncates the path after the prefix portion.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the base existed and was succesfully removed.
+
+--*/
+
+{
+ DebugAssert( _Initialized );
+
+ // If this is the root then the prefix len will include the \.
+ // If not, then it won't. Either way. Truncate this string to
+ // the prefix length.
+
+ _PathString.Truncate( _PathState.PrefixLen );
+
+ SetPathState();
+
+ return TRUE;
+}
+
+
+
+ULIB_EXPORT
+PPATH
+PATH::QueryPath(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PPATH
+
+--*/
+
+{
+
+
+ REGISTER PPATH pPath;
+
+ DebugAssert( _Initialized );
+
+ if (( pPath = NEW PATH ) == NULL ) {
+ return NULL;
+ }
+
+ //
+ // If the new path can not be initialized, delete it.
+ //
+ if( ! ( pPath->Initialize( GetPathString()->GetWSTR(), FALSE ))) {
+
+ DELETE( pPath );
+ }
+
+ return pPath ;
+}
+
+ULIB_EXPORT
+PPATH
+PATH::QueryWCExpansion(
+ IN PPATH BasePath
+ )
+/*++
+
+Routine Description:
+
+ Expands any wildcards in path to match the equivalent characters in
+ the base path.
+
+Arguments:
+
+ PCPATH BasePath - The base path from which the equivalent characters are
+ retrieved.
+
+Return Value:
+
+ Pointer to the generated path.
+
+
+--*/
+{
+ PPATH pGeneratedPath;
+ PWSTRING pBasePathStr;
+ PWSTRING pGeneratedPathStr;
+ PWSTRING pTmp;
+ FSTRING fstring;
+ DSTRING new_string;
+
+ //
+ // Initialize the path to be generated with the current path (this)
+ //
+ pGeneratedPath = NEW PATH;
+ if( pGeneratedPath == NULL ) {
+ DebugAbort( "Failed to create a new path.\n" );
+ return( NULL );
+ }
+
+ // Does the Base have '*' while the ext is not there? If so then
+ // make the extension '*'.
+
+ if (_PathState.ExtLen == 0 &&
+ _PathString.Strchr('*', _PathState.PrefixLen) != INVALID_CHNUM &&
+ _PathString.QueryChAt(_PathString.QueryChCount() - 1) != '.') {
+
+ if (!new_string.Initialize(GetPathString()) ||
+ !new_string.Strcat(fstring.Initialize((PWSTR) L".*")) ||
+ !pGeneratedPath->Initialize(&new_string)) {
+
+ return NULL;
+ }
+ } else {
+ if (!pGeneratedPath->Initialize(GetPathString())) {
+ return NULL;
+ }
+ }
+
+ if( ( pTmp = pGeneratedPath->QueryBase() ) != NULL ) {
+ pGeneratedPathStr = pTmp->QueryString();
+ DebugPtrAssert( pGeneratedPathStr );
+ DELETE( pTmp );
+
+ //
+ // If the base path doesn't have a findable base, return an error...
+ // (filenames must have a base - in Dos anyways...)
+ //
+ if( ( pTmp = BasePath->QueryBase() ) == NULL ) {
+ DELETE( pGeneratedPathStr );
+ DELETE( pGeneratedPath );
+ return( NULL );
+ }
+ pBasePathStr = pTmp->QueryString();
+ DebugPtrAssert( pBasePathStr );
+ DELETE( pTmp );
+
+ if( !ExpandWildCards( pBasePathStr, pGeneratedPathStr ) ) {
+ DELETE( pBasePathStr );
+ DELETE( pGeneratedPathStr );
+ DELETE( pGeneratedPath );
+ return( NULL );
+ }
+ pGeneratedPath->SetBase( pGeneratedPathStr );
+ DELETE( pBasePathStr );
+ DELETE( pGeneratedPathStr );
+ }
+
+ if( ( pTmp = pGeneratedPath->QueryExt() ) != NULL ) {
+ pGeneratedPathStr = pTmp->QueryString();
+ DebugPtrAssert( pGeneratedPathStr );
+
+ DELETE( pTmp );
+
+ //
+ // If no extension is found, create an empty string to pass to
+ // the wildcard expansion routine - this is to allow 'tmp.*' to
+ // match 'tmp.'...
+ //
+ if( ( pTmp = BasePath->QueryExt() ) == NULL ) {
+ pBasePathStr = NEW DSTRING;
+ pBasePathStr->Initialize();
+ } else {
+ pBasePathStr = pTmp->QueryString();
+ DebugPtrAssert( pBasePathStr );
+ DELETE( pTmp );
+ }
+
+ if( !ExpandWildCards( pBasePathStr, pGeneratedPathStr ) ) {
+ DELETE( pBasePathStr );
+ DELETE( pGeneratedPathStr );
+ DELETE( pGeneratedPath );
+ return( NULL );
+ }
+ pGeneratedPath->SetExt( pGeneratedPathStr );
+ DELETE( pBasePathStr );
+ DELETE( pGeneratedPathStr );
+ }
+ return( pGeneratedPath );
+}
+
+BOOLEAN
+PATH::ExpandWildCards(
+ IN OUT PWSTRING pStr1,
+ IN OUT PWSTRING pStr2
+ )
+/*++
+
+Routine Description:
+
+ Expands any wildcards in string 2 to match the equivalent characters in
+ string 1. Used by QueryWildCardExpansion().
+
+Arguments:
+
+ Str1 - A pointer to the 'base' string
+ Str2 - A pointer to the string to be expanded
+
+Return Value:
+
+ TRUE if expansion was successful.
+
+--*/
+{
+ CHNUM idx;
+
+
+ UNREFERENCED_PARAMETER( (void)this);
+
+ // Deal with the * wild card first...
+ //
+ // Note: This method will ignore, even remove, any characters after the
+ // '*' in string 2. This is to comform with the behavior of Dos...
+ //
+ if( ( idx = pStr2->Strchr( '*' ) ) != INVALID_CHNUM ) {
+ if( idx > pStr1->QueryChCount() ) {
+ return( FALSE );
+ }
+ if( idx == pStr1->QueryChCount() ) {
+ pStr2->Truncate( idx );
+ } else {
+ pStr2->Replace( idx, TO_END, pStr1, idx, TO_END );
+ }
+ }
+
+ // Now convert any '?' in the base
+ while( ( idx = pStr2->Strchr( '?' ) ) != INVALID_CHNUM ) {
+ // Make sure that the wild card is within the limits of the
+ // base string...
+ if( idx >= pStr1->QueryChCount() ) {
+ return( FALSE );
+ }
+ pStr2->SetChAt( pStr1->QueryChAt( idx ), idx );
+ }
+ return( TRUE );
+}
+
+ULIB_EXPORT
+BOOLEAN
+PATH::ModifyName (
+ IN PCWSTRING Pattern
+ )
+
+/*++
+
+Routine Description:
+
+ Modifies the file name of the path according to a pattern. The pattern
+ may contain wildcards.
+
+Arguments:
+
+ Pattern - Supplies pointer to string with the pattern
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ PATH PatternPath;
+ PPATH TargetPath;
+ PWSTRING NewName;
+
+
+ // If the pattern is trivial then just bail out since there's
+ // nothing to change.
+
+ if (Pattern->QueryChCount() == 1 &&
+ Pattern->QueryChAt(0) == '*') {
+
+ return TRUE;
+ }
+
+ if (Pattern->QueryChCount() == 3 &&
+ Pattern->QueryChAt(0) == '*' &&
+ Pattern->QueryChAt(1) == '.' &&
+ Pattern->QueryChAt(2) == '*') {
+
+ return TRUE;
+ }
+
+ if (!PatternPath.Initialize(Pattern)) {
+ return FALSE;
+ }
+
+ TargetPath = PatternPath.QueryWCExpansion(this);
+ if (!TargetPath) {
+ return FALSE;
+ }
+
+ NewName = TargetPath->QueryName();
+
+ DELETE(TargetPath);
+
+ if (!NewName) {
+ return FALSE;
+ }
+
+ TruncateBase();
+ AppendBase( NewName );
+
+ DELETE( NewName );
+
+ return TRUE;
+}
+
+ULIB_EXPORT
+VOID
+PATH::TruncateNameAtColon (
+ )
+
+/*++
+
+Routine Description:
+
+ This is an awful hack to keep XCopy compatibility.
+
+ If the last segment of the path contains a colon, we truncate the
+ path at that point.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ none
+
+--*/
+
+{
+
+ CHNUM IndexColon;
+ CHNUM IndexDelimiter;
+
+
+ IndexColon = _PathString.Strrchr( (WCHAR)':', 0 );
+
+ if ( IndexColon != INVALID_CHNUM ) {
+
+ IndexDelimiter = _PathString.Strrchr( DELIMITER_CHAR, 0 );
+
+ if ( ( IndexDelimiter == INVALID_CHNUM ) ||
+ ( IndexColon > IndexDelimiter ) ) {
+
+ if (IndexColon > 1) {
+
+ //
+ // Truncate the path
+ //
+ _PathString.Truncate( IndexColon );
+ SetPathState();
+ }
+ }
+ }
+}
+
+
+
+
+ULIB_EXPORT
+PWSTRING
+PATH::QueryRoot (
+ )
+
+/*++
+
+Routine Description:
+
+ Returns a string that contains the canonicalized name of the root
+ directory (device name followed by "\").
+
+ QueryRoot returns NULL if there is no device component part of
+ this path. In other words it may be necessary to canonicalize
+ the path before having access to the Root.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ Pointer to a WSTRING that contains the root directory in its
+ canonicalized form.
+
+--*/
+
+{
+ PWSTRING Root;
+
+ if( _PathState.DeviceLen == 0 ) {
+ return( NULL );
+ }
+ Root = NEW( DSTRING );
+ DebugPtrAssert( Root );
+
+ if( !Root->Initialize( &_PathString, 0, _PathState.DeviceLen ) ) {
+ DELETE( Root );
+ return( NULL );
+ }
+
+ Root->Strcat( _SlashString );
+ return( Root );
+}
diff --git a/private/utils/ulib/src/pch.cxx b/private/utils/ulib/src/pch.cxx
new file mode 100644
index 000000000..056a4201d
--- /dev/null
+++ b/private/utils/ulib/src/pch.cxx
@@ -0,0 +1,75 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ pch.cxx
+
+Abstract:
+
+ This module implements pre-compiled headers for ulib.
+
+Author:
+
+ Matthew Bradburn (mattbr) 26-Apr-1994
+
+--*/
+
+#define _ULIB_MEMBER_
+
+//
+// Include all ulib headers, except a couple of troublemakers.
+//
+
+#include "ulib.hxx"
+#include "smsg.hxx"
+#include "array.hxx"
+#include "basesys.hxx"
+#include "bitvect.hxx"
+#include "buffer.hxx"
+#include "bufstrm.hxx"
+#include "bytestrm.hxx"
+#include "contain.hxx"
+#include "wstring.hxx"
+#include "system.hxx"
+#include "achkmsg.hxx"
+#include "arg.hxx"
+#include "arrayit.hxx"
+#include "comm.hxx"
+#include "dir.hxx"
+#include "error.hxx"
+#include "file.hxx"
+#include "filestrm.hxx"
+#include "filter.hxx"
+#include "fsnode.hxx"
+#include "ifsentry.hxx"
+#include "ifsserv.hxx"
+#include "iterator.hxx"
+#include "keyboard.hxx"
+#include "list.hxx"
+#include "listit.hxx"
+#include "mbstr.hxx"
+#include "membmgr.hxx"
+#include "message.hxx"
+#include "newdelp.hxx"
+#include "path.hxx"
+#include "pipe.hxx"
+#include "pipestrm.hxx"
+#include "program.hxx"
+#include "prtstrm.hxx"
+#include "rtmsg.h"
+#include "screen.hxx"
+#include "seqcnt.hxx"
+#include "sortcnt.hxx"
+#include "sortlist.hxx"
+#include "sortlit.hxx"
+#include "stream.hxx"
+#include "string.hxx"
+#include "stringar.hxx"
+#include "substrng.hxx"
+#include "ulibcl.hxx"
+#include "timeinfo.hxx"
+#include "object.hxx"
+#include "clasdesc.hxx"
+
diff --git a/private/utils/ulib/src/pipe.cxx b/private/utils/ulib/src/pipe.cxx
new file mode 100644
index 000000000..b5e06ca3c
--- /dev/null
+++ b/private/utils/ulib/src/pipe.cxx
@@ -0,0 +1,165 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ pipe.cxx
+
+Abstract:
+
+ This module contains the implementation of the PIPE class.
+
+Author:
+
+ Barry J. Gilhuly (W-Barry) June 27, 1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "pipestrm.hxx"
+#include "pipe.hxx"
+#include "wstring.hxx"
+
+
+DEFINE_CONSTRUCTOR( PIPE, OBJECT );
+
+DEFINE_CAST_MEMBER_FUNCTION( PIPE );
+
+
+VOID
+PIPE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Close the handles which were opened by the initialize method.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if( !_fInitialized ) {
+ return;
+ }
+
+ //
+ // Close the pipe...
+ //
+ CloseHandle( _hReadPipe );
+ CloseHandle( _hWritePipe );
+ _fInitialized = FALSE;
+
+ return;
+}
+
+BOOLEAN
+PIPE::Initialize(
+ IN LPSECURITY_ATTRIBUTES PipeAttributes,
+ IN ULONG PipeSize,
+ IN PWSTRING PipeName
+ )
+/*++
+
+Routine Description:
+
+ Create a PIPE by making a call to the system API. If the PIPE object
+ has been previously initialized, destroy it first.
+
+Arguments:
+
+ PipeAttributes - A pointer to a structure which defines the attributes
+ of the pipe to be created.
+
+ PipeSize - A suggested buffer size for the pipe.
+
+ PipeName - The name of the pipe. Currently, this option is
+ unimplemented, it should ALWAYS be NULL.
+
+Return Value:
+
+ TRUE if the PIPE was created successfully.
+
+--*/
+{
+ BOOLEAN PipeStatus = FALSE;
+
+ Destroy();
+
+ if( PipeName == NULL ) {
+ //
+ // Create an anonomous pipe...
+ //
+ if( !( PipeStatus = CreatePipe( &_hReadPipe,
+ &_hWritePipe,
+ PipeAttributes,
+ PipeSize ) ) ) {
+ DebugPrint( "Unable to create the pipe - returning failure!\n" );
+ _fInitialized = FALSE;
+ } else {
+ _fInitialized = TRUE;
+ }
+ } else {
+ DebugPrint( "Named Pipes are not currently implemented!\n" );
+ }
+ return( PipeStatus );
+}
+
+PPIPE_STREAM
+PIPE::QueryPipeStream(
+ IN HANDLE hPipe,
+ IN STREAMACCESS Access
+ )
+/*++
+
+Routine Description:
+
+ Create and initialize a stream to the PIPE object.
+
+Arguments:
+
+ hPipe - A handle to use in the initialization of the stream.
+
+ Access - The desired access on this stream.
+
+Return Value:
+
+ Returns a pointer to the created PIPE STREAM if successful. Otherwise,
+ it returns NULL.
+
+--*/
+{
+ PPIPE_STREAM NewStream;
+
+ if( !_fInitialized ) {
+ DebugPrint( "Pipe object is uninitialized!\n" );
+ NewStream = NULL;
+ } else {
+ if( ( NewStream = NEW PIPE_STREAM ) == NULL ) {
+ DebugPrint( "Unable to create a new copy of the Read Stream!\n" );
+ } else {
+ if( !NewStream->Initialize( hPipe, Access ) ) {
+ DebugPrint( "Unable to initialize the new stream!\n" );
+ DELETE( NewStream );
+ NewStream = NULL;
+ }
+ }
+ }
+ return( NewStream );
+}
diff --git a/private/utils/ulib/src/pipestrm.cxx b/private/utils/ulib/src/pipestrm.cxx
new file mode 100644
index 000000000..a989bd926
--- /dev/null
+++ b/private/utils/ulib/src/pipestrm.cxx
@@ -0,0 +1,356 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ pipestrm.cxx
+
+Abstract:
+
+ This module contains the definitions of the member functions
+ of PIPE_STREAM class.
+
+Author:
+
+ Jaime Sasson (jaimes) 24-Mar-1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "stream.hxx"
+#include "bufstrm.hxx"
+#include "pipestrm.hxx"
+
+#define BUFFER_SIZE 4*1024
+
+
+DEFINE_CONSTRUCTOR ( PIPE_STREAM, BUFFER_STREAM );
+
+
+DEFINE_CAST_MEMBER_FUNCTION( PIPE_STREAM );
+
+
+PIPE_STREAM::~PIPE_STREAM (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy a PIPE_STREAM.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+}
+
+
+BOOLEAN
+PIPE_STREAM::Initialize(
+ IN HANDLE Handle,
+ IN STREAMACCESS Access
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes a PIPE_STREAM object.
+
+Arguments:
+
+ Handle - Handle to the anonymous pipe.
+
+ Access - Access allowed to the stream.
+
+
+Return Value:
+
+ BOOLEAN - Indicates if the initialization succeeded.
+
+
+--*/
+
+
+{
+ if( ( Access == READ_ACCESS ) || ( Access == WRITE_ACCESS ) ) {
+ _PipeHandle = Handle;
+ _Access = Access;
+ _EndOfFile = FALSE;
+ return( BUFFER_STREAM::Initialize( BUFFER_SIZE ) );
+ } else {
+ return( FALSE );
+ }
+}
+
+
+BOOLEAN
+PIPE_STREAM::EndOfFile(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Informs the caller if end of file has occurred. End of file happens
+ when all bytes were read from the pipe (in the case of anonymous
+ pipe, "end of file" happens when ReadFile returns STATUS_END_OF_FILE).
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A boolean value that indicates if end of file was detected.
+
+
+--*/
+
+
+{
+ return( _EndOfFile );
+}
+
+#ifdef DBCS // v-junm - 10/15/93
+
+BOOLEAN
+PIPE_STREAM::CheckIfLeadByte(
+ IN PUCHAR text,
+ IN ULONG offset
+ )
+
+/*++
+
+Routine Description:
+
+ Checks to see if the character at an given offset in a MBCS string is a
+ leadbyte of a DBCS character.
+
+Arguments:
+
+ text - MBCS string.
+
+Return Value:
+
+ TRUE - if char is leadbyte.
+ FALSE - otherwise.
+
+--*/
+
+{
+ ULONG i = offset;
+
+ for ( ; i; i-- )
+ if ( !IsDBCSLeadByte ( text[i] ) )
+ break;
+
+ return( ( offset - i ) % 2 );
+}
+
+#endif
+
+
+
+BOOLEAN
+PIPE_STREAM::FillBuffer(
+ IN PBYTE Buffer,
+ IN ULONG BufferSize,
+ OUT PULONG BytesRead
+ )
+
+/*++
+
+Routine Description:
+
+ Fills a buffer with bytes read from the pipe, if the pipe has
+ READ_ACCESS.
+ Returns FALSE if the pipe has WRITE_ACCESS.
+
+Arguments:
+
+ Buffer - Buffer where the bytes are to be stored.
+
+ BufferSize - Size of the buffer.
+
+ BytesRead - Pointer to the variable that will contain the number of bytes
+ put in the buffer.
+
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+{
+ BOOLEAN Result;
+ PBYTE p;
+
+#ifdef DBCS // v-junm - 10/15/93
+
+ //
+ // This define keeps the remaining leadbyte that was read from the
+ // pipe stream and concatanates it to the next set of strings read.
+ // The remaining byte means that if there is a leadbyte at the end
+ // of a string without a cooresponding tail byte.
+ //
+ // NOTE: The following code assumes that the pipe stream is always
+ // constant and is continuously reading from the same pipe for the
+ // same caller.
+ //
+
+ static BYTE LeadByte = 0;
+
+
+ //
+ // If there was a leadbyte, put it in buffer and decrement buffer size.
+ //
+
+ if ( LeadByte != 0 ) {
+ *Buffer++ = LeadByte;
+ BufferSize--;
+ }
+
+#endif
+
+ Result = FALSE;
+ if( _Access == READ_ACCESS ) {
+ Result = ReadFile( _PipeHandle,
+ Buffer,
+ BufferSize,
+ BytesRead,
+ NULL );
+
+#ifdef DBCS // v-junm - 10/15/93
+
+ //
+ // If there was a leadbyte placed earlier,
+ // re-adjust buffer and buffercount.
+ //
+
+ if ( LeadByte != 0 ) {
+ *BytesRead = *BytesRead + 1;
+ Buffer--;
+ }
+
+ //
+ // If bytes were read, check if string ends with a leadbyte.
+ // If so, save it for next time.
+ //
+
+ if ( (*BytesRead != 0) && CheckIfLeadByte( Buffer, *BytesRead-1 ) ) {
+
+ //
+ // Check if buffer contains only the leadbyte that was placed
+ // from the previous call to this function.
+ //
+
+ if ( (LeadByte != 0) && (*BytesRead == 1) )
+ LeadByte = 0;
+ else {
+
+ //
+ // Leadbyte is at end of string. save it for next time
+ // and adjust buffer size so a null will be replaced
+ // for the leadbyte.
+ //
+
+ LeadByte = *(Buffer + *BytesRead - 1);
+ *BytesRead = *BytesRead - 1;
+ }
+
+ }
+ else
+ LeadByte = 0;
+
+#endif
+
+ //
+ // no bytes read means end of file (according to markl)
+ //
+ if( *BytesRead == 0 ) {
+ _EndOfFile = TRUE;
+ } else {
+ p = (PBYTE)Buffer + *BytesRead;
+ *p++ = '\0';
+ *p = '\0';
+ }
+ }
+ return( Result );
+}
+
+
+
+STREAMACCESS
+PIPE_STREAM::QueryAccess(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the type of access of the pipe stream
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The stream access.
+
+
+--*/
+
+
+{
+ return( _Access );
+}
+
+
+
+HANDLE
+PIPE_STREAM::QueryHandle(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the file handle
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The file handle.
+
+
+--*/
+
+
+{
+ return( _PipeHandle );
+}
+
diff --git a/private/utils/ulib/src/prnthack.cxx b/private/utils/ulib/src/prnthack.cxx
new file mode 100644
index 000000000..d7fdb5dab
--- /dev/null
+++ b/private/utils/ulib/src/prnthack.cxx
@@ -0,0 +1,16 @@
+// Because the name of the function to be used is
+// DbgPrint, we can't include "ulib.hxx"
+
+void
+DbgPrint (
+ char* String
+ );
+
+
+void
+AutoCheckDisplayString (
+ char* String
+ )
+{
+ DbgPrint(String);
+}
diff --git a/private/utils/ulib/src/program.cxx b/private/utils/ulib/src/program.cxx
new file mode 100644
index 000000000..7d00baef3
--- /dev/null
+++ b/private/utils/ulib/src/program.cxx
@@ -0,0 +1,453 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ program.cxx
+
+Abstract:
+
+Author:
+
+ David J. Gilman (davegi) 02-Mar-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "path.hxx"
+#include "program.hxx"
+#include "system.hxx"
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( PROGRAM, OBJECT, ULIB_EXPORT );
+
+ULIB_EXPORT
+PROGRAM::~PROGRAM (
+ )
+{
+
+}
+
+ULIB_EXPORT
+BOOLEAN
+PROGRAM::Initialize (
+ IN MSGID UsageMsg,
+ IN MSGID FatalMsg,
+ IN ULONG FatalLevel
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes a PROGRAM object.
+
+Arguments:
+
+ UsageMsg - Supplies usage (help) message id.
+ FatalMsg - Supplies default fatal message id.
+ FatalLevel - Supplies default fatal exit level.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if object initialized,
+ FALSE otherwise.
+
+
+--*/
+
+{
+
+ //
+ // Get standard streams.
+ //
+ _Standard_Input = Standard_Input_Stream;
+ _Standard_Output = Standard_Output_Stream;
+ _Standard_Error = Standard_Error_Stream;
+
+ //
+ // Initialize the message object
+ //
+ if ( _Standard_Output &&
+ _Standard_Input &&
+ _Message.Initialize( _Standard_Output, _Standard_Input, _Standard_Error ) ) {
+
+ //
+ // Initialize message ids and error levels
+
+ _UsageMsg = UsageMsg;
+ _FatalMsg = FatalMsg;
+ _FatalLevel = FatalLevel;
+
+ return TRUE;
+
+ }
+
+ _Standard_Input = NULL;
+ _Standard_Output = NULL;
+ _Standard_Error = NULL;
+ return FALSE;
+}
+
+ULIB_EXPORT
+BOOLEAN
+PROGRAM::DisplayMessage (
+ IN MSGID Message,
+ IN MESSAGE_TYPE Type
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Displays a message
+
+Arguments:
+
+ Message - Supplies the message id of the message to display
+ Type - Supplies the type of message
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if message displayed,
+ FALSE otherwise.
+
+
+--*/
+
+{
+ return DisplayMessage( Message, Type, NULL );
+}
+
+ULIB_EXPORT
+BOOLEAN
+PROGRAM::DisplayMessage (
+ IN MSGID Message,
+ IN MESSAGE_TYPE Type,
+ IN PSTR Format,
+ IN ...
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Displays a message with arguments
+
+
+Arguments:
+
+ Message - Supplies the message id of the message to display
+ Type - Supplies the message type
+ Format - Supplies a format string
+ ... - Supplies list of arguments
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if message displayed,
+ FALSE otherwise.
+
+--*/
+
+{
+
+ va_list Arguments;
+ BOOLEAN Status;
+
+ if ( ((PPROGRAM) this)->_Message.Set( Message, Type ) ) {
+
+ if ( !Format ) {
+
+ return ((PPROGRAM) this)->_Message.Display( "" );
+
+ } else {
+
+ va_start( Arguments, Format );
+ Status = ((PPROGRAM) this)->_Message.DisplayV( Format, Arguments );
+ va_end( Arguments );
+ return Status;
+ }
+ }
+
+ return FALSE;
+
+}
+
+ULIB_EXPORT
+VOID
+PROGRAM::ExitProgram (
+ ULONG Level
+ )
+{
+ ExitProcess( Level );
+}
+
+ULIB_EXPORT
+PSTREAM
+PROGRAM::GetStandardInput (
+ )
+
+/*++
+
+Routine Description
+
+ Obtains the standard input stream
+
+Arguments:
+
+ None
+
+Return Value:
+
+ PSTREAM - Returns the standard input stream
+
+--*/
+
+{
+
+ return _Standard_Input;
+
+}
+
+ULIB_EXPORT
+PSTREAM
+PROGRAM::GetStandardOutput (
+ )
+
+/*++
+
+Routine Description
+
+ Obtains the standard output stream
+
+Arguments:
+
+ None
+
+Return Value:
+
+ PSTREAM - Returns the standard output stream
+
+--*/
+
+{
+
+ return _Standard_Output;
+
+}
+
+
+ULIB_EXPORT
+PSTREAM
+PROGRAM::GetStandardError (
+ )
+
+/*++
+
+Routine Description
+
+ Obtains the standard error stream
+
+Arguments:
+
+ None
+
+Return Value:
+
+ PSTREAM - Returns the standard error stream
+
+--*/
+
+{
+
+ return _Standard_Error;
+
+}
+
+
+ULIB_EXPORT
+VOID
+PROGRAM::Fatal (
+ ) CONST
+
+/*++
+
+Routine Description
+
+ Displays the default fatal message and exits with the default
+ fatal error level.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ Fatal( _FatalLevel, _FatalMsg, NULL );
+
+}
+
+ULIB_EXPORT
+VOID
+PROGRAM::Fatal (
+ IN ULONG ErrorLevel,
+ IN MSGID Message,
+ IN PSTR Format,
+ IN ...
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Displays a message (with arguments) and exits with the specified
+ error level.
+
+Arguments:
+
+ ErrorLevel - Supplies the error level to exit with.
+ Message - Supplies the id of the message to display
+ Format - Supplies the format string
+ ... - Supply pointers to the arguments
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ va_list Arguments;
+
+ if ( ((PPROGRAM) this)->_Message.Set( Message, ERROR_MESSAGE ) ) {
+
+ if ( !Format ) {
+
+ ((PPROGRAM) this)->_Message.Display( "" );
+
+ } else {
+
+ va_start( Arguments, Format );
+ ((PPROGRAM) this)->_Message.DisplayV( Format, Arguments );
+
+ }
+ }
+
+ ExitProcess( ErrorLevel );
+}
+
+ULIB_EXPORT
+VOID
+PROGRAM::Usage (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Displays the usage (help) message and exits with an error level of
+ zero.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ((PPROGRAM) this)->_Message.Set( _UsageMsg, NORMAL_MESSAGE );
+ ((PPROGRAM) this)->_Message.Display();
+
+ ExitProcess( 0 );
+}
+
+PPATH
+PROGRAM::QueryImagePath (
+ )
+
+/*++
+
+Routine Description:
+
+ Queries the path to the program image (executable file)
+
+Arguments:
+
+ None
+
+Return Value:
+
+ PPATH - Returns a canonicalized path to the program image.
+
+--*/
+
+{
+ WSTR PathName[ MAX_PATH ];
+ PPATH Path;
+
+ if (( GetModuleFileName( NULL, PathName, MAX_PATH ) != 0 ) &&
+ (( Path = NEW PATH ) != NULL ) &&
+ Path->Initialize( PathName, TRUE )) {
+
+ return Path;
+
+ }
+
+ return NULL;
+}
+
+
+ULIB_EXPORT
+VOID
+PROGRAM::ValidateVersion (
+ IN MSGID InvalidVersionMsg,
+ IN ULONG ErrorLevel
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Validates the version, and if the version is invalid, exits the
+ program.
+
+Arguments:
+
+ InvalidVersionMsg - Supplies id of message to display if the
+ version number is incorrect.
+
+ ErrorLevel - Supplies the error level with which to exit
+ if the version number is incorrect.
+
+Return Value:
+
+ None (Only returns if is correct version).
+
+
+--*/
+
+{
+ if ( !SYSTEM::IsCorrectVersion() ) {
+
+ Fatal( ErrorLevel, InvalidVersionMsg, "" );
+ }
+}
diff --git a/private/utils/ulib/src/prtstrm.cxx b/private/utils/ulib/src/prtstrm.cxx
new file mode 100644
index 000000000..fa53906da
--- /dev/null
+++ b/private/utils/ulib/src/prtstrm.cxx
@@ -0,0 +1,392 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ prtstrm.cxx
+
+Abstract:
+
+ This module contains the definitions of the member functions
+ of PRINT_STREAM class.
+
+Author:
+
+ Jaime Sasson (jaimes) 12-Jun-1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "wstring.hxx"
+#include "path.hxx"
+#include "stream.hxx"
+#include "prtstrm.hxx"
+
+
+DEFINE_EXPORTED_CONSTRUCTOR ( PRINT_STREAM, STREAM, ULIB_EXPORT );
+
+DEFINE_CAST_MEMBER_FUNCTION( PRINT_STREAM );
+
+
+VOID
+PRINT_STREAM::Construct(
+ )
+{
+ _Handle = INVALID_HANDLE_VALUE;
+}
+
+
+ULIB_EXPORT
+PRINT_STREAM::~PRINT_STREAM (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy a PRINT_STREAM.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if (INVALID_HANDLE_VALUE != _Handle) {
+
+ CloseHandle( _Handle );
+ }
+}
+
+
+
+ULIB_EXPORT
+BOOLEAN
+PRINT_STREAM::Initialize(
+ IN PCPATH DeviceName
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes an object of type PRINT_STREAM.
+
+Arguments:
+
+ DevicName - A path to the device associated with the printer.
+
+
+Return Value:
+
+ BOOLEAN - TRUE if the initialization succeeded. FALSE otherwise.
+
+
+--*/
+
+
+{
+ ULONG FileType;
+ PCWSTRING String;
+
+ String = DeviceName->GetPathString();
+
+
+ _Handle = CreateFile( String->GetWSTR(),
+ GENERIC_WRITE,
+ FILE_SHARE_READ,
+ NULL, // Security attributes
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL );
+ if( _Handle == INVALID_HANDLE_VALUE ) {
+ return( FALSE );
+ }
+ return( STREAM::Initialize() );
+}
+
+
+BOOLEAN
+PRINT_STREAM::IsAtEnd(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Informs the caller if end of file has occurred. The concept of
+ end of file for a PRINT_STREAM does not have any meaning, so this
+ method will always return FALSE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns FALSE.
+
+
+--*/
+
+
+{
+ (void)(this);
+ return( FALSE );
+}
+
+
+STREAMACCESS
+PRINT_STREAM::QueryAccess(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the type of access of the print stream
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns always WRITE_ACCESS.
+
+
+--*/
+
+
+{
+ (void)(this);
+ return( WRITE_ACCESS );
+}
+
+
+
+HANDLE
+PRINT_STREAM::QueryHandle(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the handle to the stream.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns a handle.
+
+
+--*/
+
+
+{
+ return( _Handle );
+}
+
+
+BOOLEAN
+PRINT_STREAM::Read(
+ OUT PBYTE Buffer,
+ IN ULONG BytesToRead,
+ OUT PULONG BytesRead
+ )
+
+/*++
+
+Routine Description:
+
+ Reads bytes from the print stream.
+
+Arguments:
+
+ PBYTE - Points that will receive the bytes read.
+
+ ULONG - Number of bytes to read (buffer size)
+
+ PULONG - Points to the variable that will contain the total
+ number of bytes read.
+
+Return Value:
+
+ Returns always FALSE since no data can be read from a print stream.
+
+
+--*/
+
+
+{
+ // unreferenced parameters
+ (void)(this);
+ (void)(Buffer);
+ (void)(BytesToRead);
+ (void)(BytesRead);
+
+ return( FALSE );
+}
+
+
+
+BOOLEAN
+PRINT_STREAM::ReadChar(
+ OUT PWCHAR Char,
+ IN BOOLEAN Unicode
+ )
+
+/*++
+
+Routine Description:
+
+ Reads a character from the print stream.
+
+Arguments:
+
+ Char - Supplies poinbter to wide character
+
+Return Value:
+
+ Returns always FALSE since no data can be read from a print stream.
+
+
+--*/
+
+
+{
+ // unreferenced parameters
+ (void)(this);
+ (void)(Char);
+ (void)(Unicode);
+
+ return( FALSE );
+}
+
+
+
+BOOLEAN
+PRINT_STREAM::ReadString(
+ OUT PWSTRING String,
+ IN PWSTRING Delimiter,
+ IN BOOLEAN Unicode
+ )
+
+/*++
+
+Routine Description:
+
+ Reads a STRING from the print stream.
+
+Arguments:
+
+ Pointer to the variable that will contain the pointer to the STRING
+ object.
+
+Return Value:
+
+ Returns always FALSE since no data can be read from a print stream.
+
+
+--*/
+
+
+{
+ // unreferenced parameters
+ (void)(this);
+ (void)(String);
+ (void)(Delimiter);
+ (void)(Unicode);
+
+ return( FALSE );
+}
+
+
+
+BOOLEAN
+PRINT_STREAM::ReadMbString(
+ IN PSTR String,
+ IN DWORD BufferSize,
+ INOUT PDWORD StringSize,
+ IN PSTR Delimiters,
+ IN BOOLEAN ExpandTabs,
+ IN DWORD TabExp
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+
+{
+ // unreferenced parameters
+ (void)(this);
+ (void)(String);
+ (void)(BufferSize);
+ (void)(StringSize);
+ (void)(Delimiters);
+ (void)(ExpandTabs);
+ (void)(TabExp);
+
+ return( FALSE );
+}
+
+
+BOOLEAN
+PRINT_STREAM::ReadWString(
+ IN PWSTR String,
+ IN DWORD BufferSize,
+ INOUT PDWORD StringSize,
+ IN PWSTR Delimiters,
+ IN BOOLEAN ExpandTabs,
+ IN DWORD TabExp
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+
+{
+ // unreferenced parameters
+ (void)(this);
+ (void)(String);
+ (void)(BufferSize);
+ (void)(StringSize);
+ (void)(Delimiters);
+ (void)(ExpandTabs);
+ (void)(TabExp);
+
+ return( FALSE );
+}
diff --git a/private/utils/ulib/src/rtmsg.dbl b/private/utils/ulib/src/rtmsg.dbl
new file mode 100644
index 000000000..3d8cd0be3
--- /dev/null
+++ b/private/utils/ulib/src/rtmsg.dbl
@@ -0,0 +1,387 @@
+MessageId=30100 SymbolicName=MSG_CONV_USAGE
+Language=English
+Converts FAT or HPFS volumes to NTFS.
+
+CONVERT drive: /FS:NTFS [/V]
+CONVERT /UNCOMPRESS[:sss] drive: /FS:NTFS [/V] [/C]
+
+ drive Specifies the drive to convert to NTFS. Note that
+ you cannot convert the current drive.
+ /FS:NTFS Specifies to convert the volume to NTFS.
+ /UNCOMPRESS Causes files to be extracted from a DoubleSpace volume.
+ sss Specifies the sequence number of a compressed volume file.
+ /C The resulting filesystem is compressed.
+.
+
+
+MessageId=30115 SymbolicName=MSG_CONV_SLASH_C_INVALID
+Language=English
+The /C option is only valid with the /UNCOMPRESS option.
+.
+
+;//----------------------
+;//
+;// Dblspace-specific Convert messages (cudbfs)
+;//
+;//----------------------
+
+MessageId=30190 SymbolicName=MSG_DBLCONV_CANT_CREATE
+Language=English
+Cannot create the file %1
+.
+
+MessageId=30191 SymbolicName=MSG_DBLCONV_CVF_CORRUPT
+Language=English
+The Compressed Volume File is corrupt -- run SCANDISK
+.
+
+MessageId=30192 SymbolicName=MSG_DBLCONV_CREATE_FILE
+Language=English
+Creating %1
+.
+
+MessageId=30193 SymbolicName=MSG_DBLCONV_FILE_CONFLICT
+Language=English
+A file in the Compressed Volume File would conflict with %1
+.
+
+MessageId=30194 SymbolicName=MSG_DBLCONV_NOT_ENOUGH_SPACE
+Language=English
+Not enough free space on host; need %1 clusters, have %2
+.
+
+MessageId=30195 SymbolicName=MSG_DBLCONV_AGAIN
+Language=English
+After the machine is rebooted, run CONVERT /UNCOMPRESS again.
+.
+
+MessageId=30196 SymbolicName=MSG_DBLCONV_SPACE_EXHAUSTED
+Language=English
+All disk space on the host volume has been exhausted. Please delete
+files from the host volume and run CONVERT /UNCOMPRESS again.
+.
+
+
+;//-----------------------
+;//
+;// DOUBLE SPACE messages
+;//
+;//-----------------------
+
+MessageId=30600 SymbolicName=MSG_DBLSPACE_USAGE
+Language=English
+Creates or configures DoubleSpace compressed drives.
+
+DBLSPACE /AUTOMOUNT=0|1
+DBLSPACE /LIST
+DBLSPACE /MOUNT[=sss] [drive:] [/NEWDRIVE=drive2:]
+DBLSPACE /UNCOMPRESS[=sss] drive: [/V]
+DBLSPACE /UNMOUNT [drive:]
+
+.
+
+MessageId=30601 SymbolicName=MSG_DBLSPACE_CREATE_DISK_ERROR
+Language=English
+A disk error occurred; the Double Space volume cannot
+be created. Run CHKDSK /R on the host volume to map out
+bad sectors.
+.
+
+MessageId=30602 SymbolicName=MSG_DBLSPACE_NO_CVF_NAME
+Language=English
+No name is available for the Double Space volume; the
+volume could not be created.
+.
+
+MessageId=30603 SymbolicName=MSG_DBLSPACE_CVF_NAME_EXISTS
+Language=English
+A file already exists with the specified Compressed Volume File
+extension; the specified file cannot be created. Use FORMAT to
+reformat existing Double Space volumes.
+.
+
+MessageId=30604 SymbolicName=MSG_DBLSPACE_HOST_NOT_FAT
+Language=English
+The specified host volume is not FAT; Double Space volumes
+can only be created on FAT host volumes.
+.
+
+MessageId=30605 SymbolicName=MSG_DBLSPACE_NO_SPACE_ON_HOST
+Language=English
+There is not enough free space on the host drive.
+.
+
+MessageId=30606 SymbolicName=MSG_DBLSPACE_CVF_CREATE_ERROR
+Language=English
+The Double Space volume could not be created.
+.
+
+MessageId=30607 SymbolicName=MSG_DBLSPACE_PARSE_NO_DRIVE
+Language=English
+No drive specified.
+.
+
+MessageId=30608 SymbolicName=MSG_DBLSPACE_INVALID_PARAMETERS
+Language=English
+Invalid parameters.
+.
+
+MessageId=30609 SymbolicName=MSG_DBLSPACE_INVALID_DRIVE
+Language=English
+Invalid drive.
+.
+
+MessageId=30610 SymbolicName=MSG_DBLSPACE_UNSUPPORTED_OPERATION
+Language=English
+This operation is not supported on Windows NT.
+.
+
+MessageId=30611 SymbolicName=MSG_DBLSPACE_VOLUME_CREATED
+Language=English
+%1\%2 created.
+.
+
+MessageId=30612 SymbolicName=MSG_DBLSPACE_VOLUME_NOT_CREATED
+Language=English
+The compressed volume was not created.
+.
+
+MessageId=30613 SymbolicName=MSG_DBLSPACE_INVALID_PARAMETER
+Language=English
+Invalid parameter - %1
+.
+
+MessageId=30614 SymbolicName=MSG_DBLSPACE_INSUFFICIENT_SPACE_TO_CREATE
+Language=English
+There is not enough free space on drive %1 to create the
+specified Double Space volume.
+.
+
+MessageId=30615 SymbolicName=MSG_CANT_READ_FAT_EXTENS
+Language=English
+Error reading FAT extensions.
+.
+
+MessageId=30616 SymbolicName=MSG_CANT_WRITE_FAT_EXTENS
+Language=English
+Error writing FAT extensions.
+.
+
+MessageId=30617 SymbolicName=MSG_DBLSPACE_CANT_MOUNT
+Language=English
+Can't mount %1
+.
+
+MessageId=30618 SymbolicName=MSG_DBLSPACE_MOUNTED
+Language=English
+%1 mounted as drive %2
+.
+
+MessageId=30619 SymbolicName=MSG_DBLSPACE_DRIVE_LETTER_IN_USE
+Language=English
+Drive %1 is already in use.
+.
+
+MessageId=30620 SymbolicName=MSG_DBLSPACE_CANT_ASSIGN_DRIVE_LETTER
+Language=English
+Cannot assign drive letter %1 to volume.
+.
+
+MessageId=30621 SymbolicName=MSG_DBLSPACE_UNMOUNTED
+Language=English
+Drive %1 unmounted.
+.
+
+MessageId=30622 SymbolicName=MSG_DBLSPACE_NO_DRIVE_LETTER
+Language=English
+No drive letter is available to mount the volume.
+.
+
+MessageId=30623 SymbolicName=MSG_DBLSPACE_CANT_GET_CVF_NAME
+Language=English
+Cannot determine the name of the Compressed Volume File.
+.
+
+MessageId=30624 SymbolicName=MSG_DBLSPACE_REQUIRED_PARAMETER
+Language=English
+Required parameter missing.
+.
+
+MessageId=30625 SymbolicName=MSG_DBLSPACE_NOT_COMPRESSED
+Language=English
+Drive %1 is not a compressed drive.
+.
+
+MessageId=30626 SymbolicName=MSG_DBLSPACE_NOT_COMPRESSED_NO_NAME
+Language=English
+The specified drive is not compressed.
+.
+
+MessageId=30627 SymbolicName=MSG_DBLSPACE_FMT_NOT_COMPRESSED
+Language=English
+Drive %1 is not a compressed drive. To format it, use the FORMAT command.
+.
+
+MessageId=30628 SymbolicName=MSG_DBLSPACE_CHK_NOT_COMPRESSED
+Language=English
+Drive %1 is not a compressed drive. To check it, use the CHKDSK command.
+.
+
+MessageId=30629 SymbolicName=MSG_DBLSPACE_CONFIRM_DELETE
+Language=English.
+Deleting drive %1 will permanently erase it and all the files
+it contains. Are you sure you want to delete drive %1 (Y/N)? %0
+.
+
+MessageId=30630 SymbolicName=MSG_DBLSPACE_DELETING
+Language=English
+DoubleSpace is deleting drive %1.
+.
+
+MessageId=30631 SymbolicName=MSG_DBLSPACE_DELETED
+Language=English
+DoubleSpace has deleted drive %1.
+.
+
+
+MessageId=30632 SymbolicName=MSG_DBLSPACE_DISMOUNTED
+Language=English
+Drive %1 has been dismounted.
+.
+
+MessageId=30634 SymbolicName=MSG_DBLSPACE_DISMOUNTED_NO_NAME
+Language=English
+The volume has been dismounted.
+.
+
+MessageId=30635 SymbolicName=MSG_DBLSPACE_CANT_DELETE_CVF
+Language=English
+Unable to delete Compressed Volume File.
+.
+
+MessageId=30636 SymbolicName=MSG_DBLSPACE_LIST_HEADER
+Language=English
+Drive Type MB Free MB Size CVF Filename
+----- -------------------------- ---------- ---------- ---------------
+.
+
+MessageId=30637 SymbolicName=MSG_DBLSPACE_LIST_REMOVABLE
+Language=English
+ %1 Removable-media drive %0
+.
+
+MessageId=30638 SymbolicName=MSG_DBLSPACE_LIST_FLOPPY
+Language=English
+ %1 Floppy disk %0
+.
+
+MessageId=30639 SymbolicName=MSG_DBLSPACE_LIST_FIXED
+Language=English
+ %1 Local hard drive %0
+.
+
+MessageId=30640 SymbolicName=MSG_DBLSPACE_LIST_COMPRESSED_REMOVABLE
+Language=English
+ %1 Compressed removable disk %0
+.
+
+MessageId=30641 SymbolicName=MSG_DBLSPACE_LIST_COMPRESSED_FLOPPY
+Language=English
+ %1 Compressed floppy disk %0
+.
+
+MessageId=30642 SymbolicName=MSG_DBLSPACE_LIST_COMPRESSED_FIXED
+Language=English
+ %1 Compressed hard drive %0
+.
+
+MessageId=30643 SymbolicName=MSG_DBLSPACE_LIST_NOT_PRESENT_REMOVABLE
+Language=English
+No disk in drive.
+.
+
+MessageId=30644 SymbolicName=MSG_DBLSPACE_LIST_NOT_PRESENT_FIXED
+Language=English
+Information not available.
+.
+
+MessageId=30645 SymbolicName=MSG_DBLSPACE_LIST_DETAIL
+Language=English
+ %1.%2 %3.%4 %5
+.
+
+MessageId=30646 SymbolicName=MSG_DBLSPACE_CANT_REMOVE_DRIVE_LETTER
+Language=English
+Cannot remove definition of drive letter %1.
+.
+
+MessageId=30647 SymbolicName=MSG_DBLSPACE_AUTOMOUNT_STATE_ON
+Language=English
+Automounting is enabled for removable drives.
+.
+
+MessageId=30648 SymbolicName=MSG_DBLSPACE_AUTOMOUNT_STATE_OFF
+Language=English
+Automounting is not enabled for removable drives.
+.
+
+MessageId=30649 SymbolicName=MSG_DBLSPACE_AUTOMOUNT_ENABLED
+Language=English
+Automounting has been enabled for removable drives.
+.
+
+MessageId=30650 SymbolicName=MSG_DBLSPACE_AUTOMOUNT_DISABLED
+Language=English
+Automounting has been disabled for removable drives.
+.
+
+MessageId=30651 SymbolicName=MSG_DBLSPACE_AUTOMOUNT_ENABLE_FAILED
+Language=English
+DBLSPACE could not enable automounting.
+.
+
+MessageId=30652 SymbolicName=MSG_DBLSPACE_AUTOMOUNT_DISABLE_FAILED
+Language=English
+DBLSPACE could not disable automounting.
+.
+
+MessageId=30653 SymbolicName=MSG_DBLSPACE_REBOOT
+Language=English
+For this change to take effect, you must restart your computer.
+.
+
+MessageId=30515 SymbolicName=MSG_DBLSPACE_SECTOR_DUP_ALLOC
+Language=English
+Sector allocated by multiple clusters.
+.
+
+MessageId=30516 SymbolicName=MSG_DBLSPACE_FAT_EXTENS_MISMATCH
+Language=English
+FAT extensions don't match FAT, cluster %1.
+.
+
+MessageId=30517 SymbolicName=MSG_DBLSPACE_FAT_EXTENS_INVALID
+Language=English
+FAT extensions invalid, cluster %1.
+.
+
+MessageId=30518 SymbolicName=MSG_DBLSPACE_SECTOR_RANGE
+Language=English
+FAT extensions contain invalid sector number.
+.
+
+MessageId=30519 SymbolicName=MSG_DBLSPACE_UNCOMPRESSING
+Language=English
+Uncompressing files
+.
+
+MessageId=30520 SymbolicName=MSG_DBLSPACE_NO_SUCH_FILE
+Language=English
+The file %1 does not exist.
+.
+
+MessageId=30521 SymbolicName=MSG_DBLSPACE_CANT_UNMOUNT_CURRENT_DRIVE
+Language=English
+DBLSPACE cannot unmount the current drive.
+.
+
diff --git a/private/utils/ulib/src/rtmsg.mc b/private/utils/ulib/src/rtmsg.mc
new file mode 100644
index 000000000..8720bb674
--- /dev/null
+++ b/private/utils/ulib/src/rtmsg.mc
@@ -0,0 +1,4851 @@
+;/*++ BUILD Version: 0001 // Increment this if a change has global effects
+;
+;Copyright (c) 1990 Microsoft Corporation
+;
+;Module Name:
+;
+; rtmsg.h
+;
+;Abstract:
+;
+; This file contains the message definitions for the Win32 utilities
+; library.
+;
+;Author:
+;
+; Norbert P. Kusters (norbertk) 2-Apr-1991
+;
+;Revision History:
+;
+;--*/
+
+;//----------------------
+;//
+;// DOS 5 chkdsk message.
+;//
+;//----------------------
+
+MessageId=1000 SymbolicName=MSG_CONVERT_LOST_CHAINS
+Language=English
+Convert lost chains to files (Y/N)? %0
+.
+
+MessageId=1001 SymbolicName=MSG_CHK_ERROR_IN_DIR
+Language=English
+Unrecoverable error in directory %1
+.
+
+MessageId=1002 SymbolicName=MSG_CHK_CONVERT_DIR_TO_FILE
+Language=English
+Convert directory to file (Y/N)? %0
+.
+
+MessageId=1003 SymbolicName=MSG_TOTAL_DISK_SPACE
+Language=English
+
+%1 bytes total disk space.
+.
+
+MessageId=1004 SymbolicName=MSG_BAD_SECTORS
+Language=English
+%1 bytes in bad sectors.
+.
+
+MessageId=1005 SymbolicName=MSG_HIDDEN_FILES
+Language=English
+%1 bytes in %2 hidden files.
+.
+
+MessageId=1006 SymbolicName=MSG_DIRECTORIES
+Language=English
+%1 bytes in %2 directories.
+.
+
+MessageId=1007 SymbolicName=MSG_USER_FILES
+Language=English
+%1 bytes in %2 user files.
+.
+
+MessageId=1008 SymbolicName=MSG_RECOVERED_FILES
+Language=English
+%1 bytes in %2 recovered files.
+.
+
+MessageId=1009 SymbolicName=MSG_WOULD_BE_RECOVERED_FILES
+Language=English
+%1 bytes would be in %2 recovered files.
+.
+
+MessageId=1010 SymbolicName=MSG_AVAILABLE_DISK_SPACE
+Language=English
+%1 bytes available on disk.
+.
+
+MessageId=1011 SymbolicName=MSG_TOTAL_MEMORY
+Language=English
+%1 total bytes memory.
+.
+
+MessageId=1012 SymbolicName=MSG_AVAILABLE_MEMORY
+Language=English
+%1 bytes free.
+.
+
+MessageId=1013 SymbolicName=MSG_CHK_CANT_NETWORK
+Language=English
+Cannot CHKDSK a network drive.
+.
+
+MessageId=1014 SymbolicName=MSG_1014
+Language=English
+Cannot CHKDSK a SUBSTed or ASSIGNed drive.
+.
+
+MessageId=1015 SymbolicName=MSG_PROBABLE_NON_DOS_DISK
+Language=English
+Probable non-Windows NT disk
+Continue (Y/N)? %0
+.
+
+MessageId=1016 SymbolicName=MSG_DISK_ERROR_READING_FAT
+Language=English
+Disk error reading FAT %1
+.
+
+MessageId=1017 SymbolicName=MSG_DIRECTORY
+Language=English
+Directory %1.
+.
+
+MessageId=1018 SymbolicName=MSG_CONTIGUITY_REPORT
+Language=English
+%1 Contains %2 non-contiguous blocks.
+.
+
+MessageId=1019 SymbolicName=MSG_ALL_FILES_CONTIGUOUS
+Language=English
+All specified file(s) are contiguous.
+.
+
+MessageId=1020 SymbolicName=MSG_CORRECTIONS_WILL_NOT_BE_WRITTEN
+Language=English
+Errors found, F parameter not specified.
+Corrections will not be written to disk.
+.
+
+MessageId=1021 SymbolicName=MSG_BAD_FAT_DRIVE
+Language=English
+ File allocation table (FAT) is bad on drive %1.
+.
+
+MessageId=1022 SymbolicName=MSG_BAD_FIRST_UNIT
+Language=English
+%1 First allocation unit is invalid, entry truncated.
+.
+
+MessageId=1023 SymbolicName=MSG_CHK_DONE_CHECKING
+Language=English
+File and directory verification completed.
+.
+
+MessageId=1024 SymbolicName=MSG_DISK_TOO_LARGE_TO_CONVERT
+Language=English
+The volume is too large to convert.
+.
+
+MessageId=1025 SymbolicName=MSG_CONV_NTFS_CHKDSK
+Language=English
+The volume is dirty -- run chkdsk.
+.
+
+MessageId=1028 SymbolicName=MSG_1028
+Language=English
+ Allocation error, size adjusted.
+.
+
+MessageId=1029 SymbolicName=MSG_1029
+Language=English
+ Cannot recover .. entry, processing continued.
+.
+
+MessageId=1030 SymbolicName=MSG_1030
+Language=English
+ Directory is totally empty, no . or ..
+.
+
+MessageId=1031 SymbolicName=MSG_1031
+Language=English
+ Directory is joined.
+.
+
+MessageId=1032 SymbolicName=MSG_1032
+Language=English
+ Cannot recover .. entry.
+.
+
+MessageId=1033 SymbolicName=MSG_BAD_LINK
+Language=English
+%1 Entry has a bad link.
+.
+
+MessageId=1034 SymbolicName=MSG_BAD_ATTRIBUTE
+Language=English
+ Entry has a bad attribute.
+.
+
+MessageId=1035 SymbolicName=MSG_BAD_FILE_SIZE
+Language=English
+%1 Entry has a bad size.
+.
+
+MessageId=1036 SymbolicName=MSG_CROSS_LINK
+Language=English
+%1 Is cross linked on allocation unit %2
+.
+
+MessageId=1037 SymbolicName=MSG_1037
+Language=English
+ Cannot CHDIR to %1,
+tree past this point not processed.
+.
+
+MessageId=1038 SymbolicName=MSG_1038
+Language=English
+ tree past this point not processed.
+.
+
+MessageId=1039 SymbolicName=MSG_BYTES_FREED
+Language=English
+%1 bytes disk space freed.
+.
+
+MessageId=1040 SymbolicName=MSG_BYTES_WOULD_BE_FREED
+Language=English
+%1 bytes disk space would be freed.
+.
+
+MessageId=1041 SymbolicName=MSG_VOLUME_LABEL_AND_DATE
+Language=English
+Volume %1 created %2 %3
+.
+
+MessageId=1042 SymbolicName=MSG_TOTAL_ALLOCATION_UNITS
+Language=English
+%1 total allocation units on disk.
+.
+
+MessageId=1043 SymbolicName=MSG_BYTES_PER_ALLOCATION_UNIT
+Language=English
+%1 bytes in each allocation unit.
+.
+
+MessageId=1044 SymbolicName=MSG_1044
+Language=English
+CHKDSK not available on drive %1.
+.
+
+MessageId=1045 SymbolicName=MSG_1045
+Language=English
+Invalid parameter.
+.
+
+MessageId=1046 SymbolicName=MSG_PATH_NOT_FOUND
+Language=English
+Path not found.
+.
+
+MessageId=1047 SymbolicName=MSG_FILE_NOT_FOUND
+Language=English
+%1 : File not found.
+.
+
+MessageId=1048 SymbolicName=MSG_LOST_CHAINS
+Language=English
+ %1 lost allocation units found in %2 chains.
+.
+
+MessageId=1049 SymbolicName=MSG_BLANK_LINE
+Language=English
+
+.
+
+MessageId=1050 SymbolicName=MSG_1050
+Language=English
+ Cannot CHDIR to root
+.
+
+MessageId=1051 SymbolicName=MSG_BAD_FAT_WRITE
+Language=English
+ Disk error writing FAT
+.
+
+MessageId=1052 SymbolicName=MSG_ONE_STRING
+Language=English
+%1.
+.
+
+MessageId=1054 SymbolicName=MSG_ONE_STRING_NEWLINE
+Language=English
+%1
+.
+
+MessageId=1055 SymbolicName=MSG_NO_ROOM_IN_ROOT
+Language=English
+ Insufficient room in root directory
+ Move files from root directory and repeat CHKDSK.
+.
+
+MessageId=1056 SymbolicName=MSG_1056
+Language=English
+%1 %2 %3.
+.
+
+MessageId=1057 SymbolicName=MSG_1057
+Language=English
+%1 %2, %3.
+.
+
+MessageId=1058 SymbolicName=MSG_1058
+Language=English
+%1%2%3%4%5.
+.
+
+MessageId=1059 SymbolicName=MSG_1059
+Language=English
+%1%2%3%4.
+.
+
+MessageId=1060 SymbolicName=MSG_UNITS_ON_DISK
+Language=English
+%1 available allocation units on disk.
+.
+
+MessageId=1061 SymbolicName=MSG_1061
+Language=English
+CHKDSK /F cannot be done in a Windows/DosShell Command Prompt
+.
+
+MessageId=1062 SymbolicName=MSG_CHK_NO_MEMORY
+Language=English
+ - Insufficient Memory.
+.
+
+MessageId=1063 SymbolicName=MSG_HIDDEN_STATUS
+Language=English
+This never gets printed.
+.
+
+
+MessageId=1064 SymbolicName=MSG_CHK_USAGE_HEADER
+Language=English
+Checks a disk and displays a status report.
+
+.
+
+MessageId=1065 SymbolicName=MSG_CHK_COMMAND_LINE
+Language=English
+CHKDSK [drive:][[path]filename] [/F] [/V] [/R] [/L[:size]]
+
+.
+
+MessageId=1066 SymbolicName=MSG_CHK_DRIVE
+Language=English
+ [drive:] Specifies the drive to check.
+.
+
+MessageId=1067 SymbolicName=MSG_CHK_USG_FILENAME
+Language=English
+ filename Specifies the file(s) to check for fragmentation (FAT only).
+.
+
+MessageId=1068 SymbolicName=MSG_CHK_F_SWITCH
+Language=English
+ /F Fixes errors on the disk.
+.
+
+MessageId=1069 SymbolicName=MSG_CHK_V_SWITCH
+Language=English
+ /V Displays the full path and name of every file on the disk.
+ /R Locates bad sectors and recovers readable information.
+ /L:size NTFS only: changes the log file size to the specified number
+ of kilobytes. If size is not specified, displays current size.
+.
+
+MessageId=1070 SymbolicName=MSG_WITHOUT_PARAMETERS
+Language=English
+Type CHKDSK without parameters to check the current disk.
+.
+
+
+MessageId=1071 SymbolicName=MSG_CHK_CANT_CDROM
+Language=English
+CHKDSK does not run on CD-ROM drives.
+.
+
+MessageId=1072 SymbolicName=MSG_CHK_RUNNING
+Language=English
+Checking file system on %1
+.
+
+MessageId=1073 SymbolicName=MSG_CHK_VOLUME_CLEAN
+Language=English
+The volume is clean.
+.
+
+MessageId=1074 SymbolicName=MSG_CHK_TRAILING_DIRENTS
+Language=English
+Removing trailing directory entries from %1
+.
+
+MessageId=1075 SymbolicName=MSG_CHK_BAD_CLUSTERS_IN_FILE_SUCCESS
+Language=English
+CHKDSK replaced bad clusters in file %1.
+.
+
+MessageId=1076 SymbolicName=MSG_CHK_BAD_CLUSTERS_IN_FILE_FAILURE
+Language=English
+Insufficient disk space to replace bad clusters
+detected in file %1.
+.
+
+MessageId=1077 SymbolicName=MSG_CHK_RECOVERING_FREE_SPACE
+Language=English
+CHKDSK is verifying free space...
+.
+
+MessageId=1078 SymbolicName=MSG_CHK_DONE_RECOVERING_FREE_SPACE
+Language=English
+Free space verification completed.
+.
+
+MessageId=1079 SymbolicName=MSG_CHK_CHECKING_FILES
+Language=English
+CHKDSK is verifying files and directories...
+.
+
+;//-----------------------
+;//
+;// Windows NT Chkdsk messages.
+;//
+;//-----------------------
+
+
+MessageId=1080 SymbolicName=MSG_CHK_ON_REBOOT
+Language=English
+Do you want AUTOCHK to be run the next time that
+the system restarts? [Y] %0
+.
+
+MessageId=1081 SymbolicName=MSG_CHK_VOLUME_SET_DIRTY
+Language=English
+AUTOCHK will run the next time that the system restarts.
+.
+
+MessageId=1082 SymbolicName=MSG_CHK_BOOT_PARTITION_REBOOT
+Language=English
+
+CHKDSK has finished checking your boot partition.
+Please wait while the system restarts.
+.
+
+MessageId=1083 SymbolicName=MSG_CHK_BAD_LONG_NAME
+Language=English
+Removing invalid long directory entry from %1
+.
+
+MessageId=1084 SymbolicName=MSG_CHK_CHECKING_VOLUME
+Language=English
+Checking %1
+.
+
+MessageId=1085 SymbolicName=MSG_CHK_BAD_LONG_NAME_IS
+Language=English
+Removing orphan long directory entry: %1
+.
+
+MessageId=1086 SymbolicName=MSG_CHK_WONT_ZERO_LOGFILE
+Language=English
+The logfile size must be greater than zero.
+.
+
+MessageId=1087 SymbolicName=MSG_CHK_LOGFILE_NOT_NTFS
+Language=English
+CHKDSK cannot set the logfile size on non-NTFS volumes.
+.
+
+MessageId=1088 SymbolicName=MSG_CHK_LOGFILE_SIZE
+Language=English
+The current logfile size is %1 kilobytes.
+The default logfile size for this volume is %2 kilobytes.
+.
+
+MessageId=1089 SymbolicName=MSG_CHK_BAD_LOGFILE_SIZE
+Language=English
+The size specified for the logfile is too small.
+.
+
+MessageId=1090 SymbolicName=MSG_CHK_BAD_DRIVE_PATH_FILENAME
+Language=English
+Invalid drive, path, or filename
+.
+
+;//-----------------------
+;//
+;// DOS 5 Format messages.
+;//
+;//-----------------------
+
+
+MessageId=2000 SymbolicName=MSG_PERCENT_COMPLETE
+Language=English
+%1 percent completed. %r%0
+.
+
+MessageId=2001 SymbolicName=MSG_FORMAT_COMPLETE
+Language=English
+Format complete. %b
+.
+
+MessageId=2002 SymbolicName=MSG_INSERT_DISK
+Language=English
+Insert new disk for drive %1:
+.
+
+MessageId=2003 SymbolicName=MSG_REINSERT_DISKETTE
+Language=English
+Reinsert disk for drive %1:
+.
+
+MessageId=2006 SymbolicName=MSG_BAD_IOCTL
+Language=English
+Error in IOCTL call.
+.
+
+MessageId=2007 SymbolicName=MSG_CANT_DASD
+Language=English
+Cannot open volume for direct access.
+.
+
+MessageId=2008 SymbolicName=MSG_CANT_WRITE_FAT
+Language=English
+Error writing File Allocation Table (FAT).
+.
+
+MessageId=2009 SymbolicName=MSG_CANT_WRITE_ROOT_DIR
+Language=English
+Error writing directory.
+.
+
+MessageId=2012 SymbolicName=MSG_FORMAT_NO_NETWORK
+Language=English
+Cannot format a network drive.
+.
+
+MessageId=2013 SymbolicName=MSG_UNSUPPORTED_PARAMETER
+Language=English
+Parameters not supported.
+.
+
+MessageId=2016 SymbolicName=MSG_UNUSABLE_DISK
+Language=English
+Invalid media or Track 0 bad - disk unusable.
+.
+
+MessageId=2018 SymbolicName=MSG_BAD_DIR_READ
+Language=English
+Error reading directory.
+.
+
+MessageId=2019 SymbolicName=MSG_PRESS_ENTER_WHEN_READY
+Language=English
+and press ENTER when ready... %0
+.
+
+MessageId=2021 SymbolicName=MSG_ENTER_CURRENT_LABEL
+Language=English
+Enter current volume label for drive %1: %0
+.
+
+MessageId=2022 SymbolicName=MSG_INCOMPATIBLE_PARAMETERS_FOR_FIXED
+Language=English
+Parameters incompatible with fixed disk.
+.
+
+MessageId=2023 SymbolicName=MSG_READ_PARTITION_TABLE
+Language=English
+Error reading partition table.
+.
+
+MessageId=2028 SymbolicName=MSG_NOT_SUPPORTED_BY_DRIVE
+Language=English
+Parameters not supported by drive.
+.
+
+MessageId=2029 SymbolicName=MSG_2029
+Language=English
+
+.
+
+MessageId=2030 SymbolicName=MSG_2030
+Language=English
+
+
+.
+
+MessageId=2031 SymbolicName=MSG_INSERT_DOS_DISK
+Language=English
+Insert Windows NT disk in drive %1:
+.
+
+MessageId=2032 SymbolicName=MSG_WARNING_FORMAT
+Language=English
+
+WARNING, ALL DATA ON NON-REMOVABLE DISK
+DRIVE %1: WILL BE LOST!
+Proceed with Format (Y/N)? %0
+.
+
+MessageId=2033 SymbolicName=MSG_FORMAT_ANOTHER
+Language=English
+
+Format another (Y/N)? %0
+.
+
+MessageId=2035 SymbolicName=MSG_WRITE_PARTITION_TABLE
+Language=English
+Error writing partition table.
+.
+
+MessageId=2036 SymbolicName=MSG_INCOMPATIBLE_PARAMETERS
+Language=English
+Parameters not compatible.
+.
+
+MessageId=2037 SymbolicName=MSG_AVAILABLE_ALLOCATION_UNITS
+Language=English
+%1 allocation units available on disk.
+.
+
+MessageId=2038 SymbolicName=MSG_ALLOCATION_UNIT_SIZE
+Language=English
+
+%1 bytes in each allocation unit.
+.
+
+MessageId=2040 SymbolicName=MSG_PARAMETER_TWICE
+Language=English
+Same parameter entered twice.
+.
+
+MessageId=2041 SymbolicName=MSG_NEED_BOTH_T_AND_N
+Language=English
+Must enter both /t and /n parameters.
+.
+
+MessageId=2042 SymbolicName=MSG_2042
+Language=English
+Trying to recover allocation unit %1. %0
+.
+
+MessageId=2047 SymbolicName=MSG_NO_LABEL_WITH_8
+Language=English
+Volume label is not supported with /8 parameter.
+.
+
+MessageId=2049 SymbolicName=MSG_FMT_NO_MEMORY
+Language=English
+Insufficient memory.
+.
+
+MessageId=2050 SymbolicName=MSG_QUICKFMT_ANOTHER
+Language=English
+
+QuickFormat another (Y/N)? %0
+.
+
+MessageId=2052 SymbolicName=MSG_CANT_QUICKFMT
+Language=English
+Invalid existing format.
+This disk cannot be QuickFormatted.
+Proceed with unconditional format (Y/N)? %0
+.
+
+MessageId=2053 SymbolicName=MSG_FORMATTING_KB
+Language=English
+Formatting %1K
+.
+
+MessageId=2054 SymbolicName=MSG_FORMATTING_MB
+Language=English
+Formatting %1M
+.
+
+MessageId=2055 SymbolicName=MSG_FORMATTING_DOT_MB
+Language=English
+Formatting %1.%2M
+.
+
+MessageId=2057 SymbolicName=MSG_VERIFYING_KB
+Language=English
+Verifying %1K
+.
+
+MessageId=2058 SymbolicName=MSG_VERIFYING_MB
+Language=English
+Verifying %1M
+.
+
+MessageId=2059 SymbolicName=MSG_VERIFYING_DOT_MB
+Language=English
+Verifying %1.%2M
+.
+
+MessageId=2060 SymbolicName=MSG_2060
+Language=English
+Saving UNFORMAT information.
+.
+
+MessageId=2061 SymbolicName=MSG_2061
+Language=English
+Checking existing disk format.
+.
+
+MessageId=2062 SymbolicName=MSG_QUICKFORMATTING_KB
+Language=English
+QuickFormatting %1K
+.
+
+MessageId=2063 SymbolicName=MSG_QUICKFORMATTING_MB
+Language=English
+QuickFormatting %1M
+.
+
+MessageId=2064 SymbolicName=MSG_QUICKFORMATTING_DOT_MB
+Language=English
+QuickFormatting %1.%2M
+.
+
+MessageId=2065 SymbolicName=MSG_FORMAT_INFO
+Language=English
+Formats a disk for use with Windows NT.
+
+.
+
+MessageId=2066 SymbolicName=MSG_FORMAT_COMMAND_LINE_1
+Language=English
+FORMAT drive: [/FS:file-system] [/V:label] [/Q] [/A:size] [/C]
+FORMAT drive: [/V:label] [/Q] [/F:size]
+.
+
+MessageId=2067 SymbolicName=MSG_FORMAT_COMMAND_LINE_2
+Language=English
+FORMAT drive: [/V:label] [/Q] [/T:tracks /N:sectors]
+.
+
+MessageId=2068 SymbolicName=MSG_FORMAT_COMMAND_LINE_3
+Language=English
+FORMAT drive: [/V:label] [/Q] [/1] [/4]
+.
+
+MessageId=2069 SymbolicName=MSG_FORMAT_COMMAND_LINE_4
+Language=English
+FORMAT drive: [/Q] [/1] [/4] [/8]
+
+ /FS:file-system Specifies the type of the file system (FAT or NTFS).
+.
+
+MessageId=2070 SymbolicName=MSG_FORMAT_SLASH_V
+Language=English
+ /V:label Specifies the volume label.
+.
+
+MessageId=2071 SymbolicName=MSG_FORMAT_SLASH_Q
+Language=English
+ /Q Performs a quick format.
+.
+
+MessageId=2072 SymbolicName=MSG_FORMAT_SLASH_C
+Language=English
+ /C Files created on the new volume will be compressed by
+ default.
+.
+
+MessageId=2073 SymbolicName=MSG_FORMAT_SLASH_F
+Language=English
+ /A:size Overrides the default allocation unit size. Default settings
+ are strongly recommended for general use.
+ NTFS supports 512, 1024, 2048, 4096, 8192, 16K, 32K, 64K.
+ FAT supports 8192, 16K, 32K, 64K, 128K, 256K.
+ NTFS compression is not supported for allocation unit sizes
+ above 4096.
+ /F:size Specifies the size of the floppy disk to format (160,
+.
+
+MessageId=2074 SymbolicName=MSG_FORMAT_SUPPORTED_SIZES
+Language=English
+ 180, 320, 360, 720, 1.2, 1.44, 2.88, or 20.8).
+.
+
+MessageId=2075 SymbolicName=MSG_WRONG_CURRENT_LABEL
+Language=English
+An incorrect volume label was entered for this drive.
+.
+
+MessageId=2077 SymbolicName=MSG_FORMAT_SLASH_T
+Language=English
+ /T:tracks Specifies the number of tracks per disk side.
+.
+
+MessageId=2078 SymbolicName=MSG_FORMAT_SLASH_N
+Language=English
+ /N:sectors Specifies the number of sectors per track.
+.
+
+MessageId=2079 SymbolicName=MSG_FORMAT_SLASH_1
+Language=English
+ /1 Formats a single side of a floppy disk.
+.
+
+MessageId=2080 SymbolicName=MSG_FORMAT_SLASH_4
+Language=English
+ /4 Formats a 5.25-inch 360K floppy disk in a
+ high-density drive.
+.
+
+MessageId=2081 SymbolicName=MSG_FORMAT_SLASH_8
+Language=English
+ /8 Formats eight sectors per track.
+.
+
+MessageId=2083 SymbolicName=MSG_FORMAT_NO_CDROM
+Language=English
+Cannot format a CD-ROM drive.
+.
+
+MessageId=2084 SymbolicName=MSG_FORMAT_NO_RAMDISK
+Language=English
+Cannot format a RAM DISK drive.
+.
+
+MessageId=2086 SymbolicName=MSG_FORMAT_PLEASE_USE_FS_SWITCH
+Language=English
+Please use the /FS switch to specify the file system
+you wish to use on this volume.
+.
+
+MessageId=2087 SymbolicName=MSG_NTFS_FORMAT_FAILED
+Language=English
+Format failed.
+.
+
+MessageId=2088 SymbolicName=MSG_FMT_WRITE_PROTECTED_MEDIA
+Language=English
+Cannot format. This media is write protected.
+.
+
+MessageId=2089 SymbolicName=MSG_FMT_INSTALL_FILE_SYSTEM
+Language=English
+
+WARNING! The %1 file system is not enabled.
+Would you like to enable it (Y/N)? %0
+.
+
+MessageId=2090 SymbolicName=MSG_FMT_FILE_SYSTEM_INSTALLED
+Language=English
+
+The file system will be enabled when you restart the system.
+.
+
+MessageId=2091 SymbolicName=MSG_FMT_CANT_INSTALL_FILE_SYSTEM
+Language=English
+
+FORMAT is unable to enable the file system.
+.
+
+MessageId=2092 SymbolicName=MSG_FMT_VOLUME_TOO_SMALL
+Language=English
+The volume is too small for the specified file system.
+.
+
+MessageId=2093 SymbolicName=MSG_FMT_CREATING_FILE_SYSTEM
+Language=English
+Creating file system structures.
+.
+
+MessageId=2094 SymbolicName=MSG_FMT_VARIABLE_CLUSTERS_NOT_SUPPORTED
+Language=English
+%1 FORMAT does not support user selected allocation unit sizes.
+.
+
+MessageId=2096 SymbolicName=MSG_DEVICE_BUSY
+Language=English
+The device is busy.
+.
+
+MessageId=2097 SymbolicName=MSG_FMT_DMF_NOT_SUPPORTED_ON_288_DRIVES
+Language=English
+The specified format cannot be mastered on 2.88MB drives.
+.
+
+MessageId=2098 SymbolicName=MSG_HPFS_NO_FORMAT
+Language=English
+FORMAT does not support the HPFS file system type.
+.
+
+MessageId=2099 SymbolicName=MSG_FMT_ALLOCATION_SIZE_CHANGED
+Language=English
+Allocation unit size changed to %1 bytes.
+.
+
+MessageId=2203 SymbolicName=MSG_CONV_PAUSE_BEFORE_REBOOT
+Language=English
+
+Preinstallation completed successfully. Press any key to
+shut down/reboot.
+.
+
+MessageId=2204 SymbolicName=MSG_CONV_WILL_REBOOT
+Language=English
+
+Convert will take some time to process the files on the volume.
+When this phase of conversion is complete, the system will be
+rebooted.
+
+.
+
+;//----------------------
+;//
+;// Common ulib messages.
+;//
+;//----------------------
+
+MessageId=3000 SymbolicName=MSG_CANT_LOCK_THE_DRIVE
+Language=English
+Cannot lock the drive. The volume is still in use.
+.
+
+MessageId=3002 SymbolicName=MSG_CANT_READ_BOOT_SECTOR
+Language=English
+Cannot read boot sector.
+.
+
+MessageId=3003 SymbolicName=MSG_VOLUME_SERIAL_NUMBER
+Language=English
+Volume Serial Number is %1-%2
+.
+
+MessageId=3004 SymbolicName=MSG_VOLUME_LABEL_PROMPT
+Language=English
+Volume label (11 characters, ENTER for none)? %0
+.
+
+MessageId=3005 SymbolicName=MSG_INVALID_LABEL_CHARACTERS
+Language=English
+Invalid characters in volume label
+.
+
+MessageId=3006 SymbolicName=MSG_CANT_READ_ANY_FAT
+Language=English
+There are no readable file allocation tables (FAT).
+.
+
+MessageId=3007 SymbolicName=MSG_SOME_FATS_UNREADABLE
+Language=English
+Some file allocation tables (FAT) are unreadable.
+.
+
+MessageId=3008 SymbolicName=MSG_CANT_WRITE_BOOT_SECTOR
+Language=English
+Cannot write boot sector.
+.
+
+MessageId=3009 SymbolicName=MSG_SOME_FATS_UNWRITABLE
+Language=English
+Some file allocation tables (FAT) are unwritable.
+.
+
+MessageId=3010 SymbolicName=MSG_INSUFFICIENT_DISK_SPACE
+Language=English
+Insufficient disk space.
+.
+
+MessageId=3011 SymbolicName=MSG_TOTAL_KILOBYTES
+Language=English
+%1 kilobytes total disk space.
+.
+
+MessageId=3012 SymbolicName=MSG_AVAILABLE_KILOBYTES
+Language=English
+%1 kilobytes are available.
+.
+
+MessageId=3013 SymbolicName=MSG_NOT_FAT
+Language=English
+Disk not formatted or not FAT.
+.
+
+MessageId=3014 SymbolicName=MSG_REQUIRED_PARAMETER
+Language=English
+Required parameter missing -
+.
+
+MessageId=3015 SymbolicName=MSG_FILE_SYSTEM_TYPE
+Language=English
+The type of the file system is %1.
+.
+
+MessageId=3016 SymbolicName=MSG_NEW_FILE_SYSTEM_TYPE
+Language=English
+The new file system is %1.
+.
+
+MessageId=3017 SymbolicName=MSG_FMT_AN_ERROR_OCCURRED
+Language=English
+An error occurred while running Format.
+.
+
+MessageId=3018 SymbolicName=MSG_FS_NOT_SUPPORTED
+Language=English
+%1 is not available for %2 drives.
+.
+
+MessageId=3019 SymbolicName=MSG_FS_NOT_DETERMINED
+Language=English
+Cannot determine file system of drive %1.
+.
+
+MessageId=3020 SymbolicName=MSG_CANT_DISMOUNT
+Language=English
+Cannot dismount the drive.
+.
+
+MessageId=3021 SymbolicName=MSG_NOT_FULL_PATH_NAME
+Language=English
+%1 is not a complete name.
+.
+
+MessageId=3022 SymbolicName=MSG_YES
+Language=English
+Yes
+.
+
+MessageId=3023 SymbolicName=MSG_NO
+Language=English
+No
+.
+
+MessageId=3024 SymbolicName=MSG_DISK_NOT_FORMATTED
+Language=English
+Disk is not formatted.
+.
+
+MessageId=3025 SymbolicName=MSG_NONEXISTENT_DRIVE
+Language=English
+Specified drive does not exist.
+.
+
+MessageId=3026 SymbolicName=MSG_INVALID_PARAMETER
+Language=English
+Invalid parameter - %1
+.
+
+MessageId=3027 SymbolicName=MSG_INSUFFICIENT_MEMORY
+Language=English
+Out of memory.
+.
+
+MessageId=3028 SymbolicName=MSG_ACCESS_DENIED
+Language=English
+Access denied - %1
+.
+
+MessageId=3029 SymbolicName=MSG_DASD_ACCESS_DENIED
+Language=English
+Access denied.
+.
+
+MessageId=3030 SymbolicName=MSG_CANT_LOCK_CURRENT_DRIVE
+Language=English
+Cannot lock current drive.
+.
+
+MessageId=3031 SymbolicName=MSG_INVALID_LABEL
+Language=English
+Invalid volume label
+.
+
+MessageId=3032 SymbolicName=MSG_DISK_TOO_LARGE_TO_FORMAT
+Language=English
+The disk is too large to format for the specified file system.
+.
+
+MessageId=3033 SymbolicName=MSG_VOLUME_LABEL_NO_MAX
+Language=English
+Volume label (ENTER for none)? %0
+.
+
+MessageId=3034 SymbolicName=MSG_CHKDSK_ON_REBOOT_PROMPT
+Language=English
+Chkdsk cannot run because the volume is in use by another
+process. Would you like to schedule this volume to be
+checked the next time the system restarts? (Y/N) %0
+.
+
+MessageId=3035 SymbolicName=MSG_CHKDSK_CANNOT_SCHEDULE
+Language=English
+
+Chkdsk could not schedule this volume to be checked
+the next time the system boots.
+.
+
+MessageId=3036 SymbolicName=MSG_CHKDSK_SCHEDULED
+Language=English
+
+This volume will be checked the next time the system restarts.
+.
+
+MessageId=3037 SymbolicName=MSG_COMPRESSION_NOT_AVAILABLE
+Language=English
+Compression is not available for %1.
+.
+
+MessageId=3038 SymbolicName=MSG_CANNOT_ENABLE_COMPRESSION
+Language=English
+Cannot enable compression for the volume.
+.
+
+MessageId=3039 SymbolicName=MSG_CANNOT_COMPRESS_HUGE_CLUSTERS
+Language=English
+Compression is not supported on volumes with clusters larger than
+4096 bytes.
+.
+
+MessageId=3040 SymbolicName=MSG_CANT_UNLOCK_THE_DRIVE
+Language=English
+Cannot unlock the drive.
+.
+
+MessageId=4004 SymbolicName=MSG_HPFS_CHKDSK_ERRORS_DETECTED
+Language=English
+CHKDSK detected minor inconsistencies on the drive.
+.
+
+MessageId=4005 SymbolicName=MSG_HPFS_CHKDSK_ERRORS_FIXED
+Language=English
+CHKDSK detected and fixed minor inconsistencies on the drive.
+.
+
+;//---------------------
+;//
+;// FAT ChkDsk Messages.
+;//
+;//---------------------
+
+MessageId=5000 SymbolicName=MSG_CHK_ERRORS_IN_FAT
+Language=English
+Errors in file allocation table (FAT) corrected.
+.
+
+MessageId=5001 SymbolicName=MSG_CHK_EAFILE_HAS_HANDLE
+Language=English
+Extended attribute file has handle. Handle removed.
+.
+
+MessageId=5002 SymbolicName=MSG_CHK_EMPTY_EA_FILE
+Language=English
+Extended attribute file contains no extended attributes. File deleted.
+.
+
+MessageId=5003 SymbolicName=MSG_CHK_ERASING_INVALID_LABEL
+Language=English
+Erasing invalid label.
+.
+
+MessageId=5004 SymbolicName=MSG_CHK_EA_SIZE
+Language=English
+%1 bytes in extended attributes.
+.
+
+MessageId=5005 SymbolicName=MSG_CHK_CANT_CHECK_EA_LOG
+Language=English
+Unreadable extended attribute header.
+Cannot check extended attribute log.
+.
+
+MessageId=5006 SymbolicName=MSG_CHK_BAD_LOG
+Language=English
+Extended attribute log is unintelligible.
+Ignore log and Continue? (Y/N) %0
+.
+
+MessageId=5007 SymbolicName=MSG_CHK_UNUSED_EA_PORTION
+Language=English
+Unused, unreadable, or unwritable portion of extended attribute file removed.
+.
+
+MessageId=5008 SymbolicName=MSG_CHK_EASET_SIZE
+Language=English
+Total size entry for extended attribute set at cluster %1 corrected.
+.
+
+MessageId=5009 SymbolicName=MSG_CHK_EASET_NEED_COUNT
+Language=English
+Need count entry for extended attribute set at cluster %1 corrected.
+.
+
+MessageId=5010 SymbolicName=MSG_CHK_UNORDERED_EA_SETS
+Language=English
+Extended attribute file is unsorted.
+Sorting extended attribute file.
+.
+
+MessageId=5011 SymbolicName=MSG_CHK_NEED_MORE_HEADER_SPACE
+Language=English
+Insufficient space in extended attribute file for its header.
+Attempting to allocate more disk space.
+.
+
+MessageId=5012 SymbolicName=MSG_CHK_INSUFFICIENT_DISK_SPACE
+Language=English
+Insufficient disk space to correct disk error.
+Please free up some disk space and run CHKDSK again.
+.
+
+MessageId=5013 SymbolicName=MSG_CHK_RELOCATED_EA_HEADER
+Language=English
+Bad clusters in extended attribute file header relocated.
+.
+
+MessageId=5014 SymbolicName=MSG_CHK_ERROR_IN_EA_HEADER
+Language=English
+Errors in extended attribute file header corrected.
+.
+
+MessageId=5015 SymbolicName=MSG_CHK_MORE_THAN_ONE_DOT
+Language=English
+More than one dot entry in directory %1. Entry removed.
+.
+
+MessageId=5016 SymbolicName=MSG_CHK_DOT_IN_ROOT
+Language=English
+Dot entry found in root directory. Entry removed.
+.
+
+MessageId=5017 SymbolicName=MSG_CHK_DOTDOT_IN_ROOT
+Language=English
+Dot-dot entry found in root directory. Entry removed.
+.
+
+MessageId=5018 SymbolicName=MSG_CHK_ERR_IN_DOT
+Language=English
+Dot entry in directory %1 has incorrect link. Link corrected.
+.
+
+MessageId=5019 SymbolicName=MSG_CHK_ERR_IN_DOTDOT
+Language=English
+Dot-dot entry in directory %1 has incorrect link. Link corrected.
+.
+
+MessageId=5020 SymbolicName=MSG_CHK_REPEATED_ENTRY
+Language=English
+More than one %1 entry in directory %2. Entry removed.
+.
+
+MessageId=5021 SymbolicName=MSG_CHK_CYCLE_IN_TREE
+Language=English
+Directory %1 causes cycle in directory tree.
+Directory entry removed.
+.
+
+MessageId=5022 SymbolicName=MSG_CHK_BAD_CLUSTERS_IN_DIR
+Language=English
+Directory %1 has bad clusters.
+Bad clusters removed from directory.
+.
+
+MessageId=5023 SymbolicName=MSG_CHK_BAD_DIR
+Language=English
+Directory %1 is entirely unreadable.
+Directory entry removed.
+.
+
+MessageId=5024 SymbolicName=MSG_CHK_FILENAME
+Language=English
+%1
+.
+
+MessageId=5025 SymbolicName=MSG_CHK_DIR_TRUNC
+Language=English
+Directory truncated.
+.
+
+MessageId=5026 SymbolicName=MSG_CHK_CROSS_LINK_COPY
+Language=English
+Cross link resolved by copying.
+.
+
+MessageId=5027 SymbolicName=MSG_CHK_CROSS_LINK_TRUNC
+Language=English
+Insufficient disk space to copy cross-linked portion.
+File being truncated.
+.
+
+MessageId=5028 SymbolicName=MSG_CHK_INVALID_NAME
+Language=English
+%1 Invalid name. Directory entry removed.
+.
+
+MessageId=5029 SymbolicName=MSG_CHK_INVALID_TIME_STAMP
+Language=English
+%1 Invalid time stamp.
+.
+
+MessageId=5030 SymbolicName=MSG_CHK_DIR_HAS_FILESIZE
+Language=English
+%1 Directory has non-zero file size.
+.
+
+MessageId=5031 SymbolicName=MSG_CHK_UNRECOG_EA_HANDLE
+Language=English
+%1 Unrecognized extended attribute handle.
+.
+
+MessageId=5032 SymbolicName=MSG_CHK_SHARED_EA
+Language=English
+%1 Has handle extended attribute set belonging to another file.
+ Handle removed.
+.
+
+MessageId=5033 SymbolicName=MSG_CHK_UNUSED_EA_SET
+Language=English
+Unused extended attribute set with handle %1 deleted from
+extended attribute file.
+.
+
+MessageId=5034 SymbolicName=MSG_CHK_NEW_OWNER_NAME
+Language=English
+Extended attribute set with handle %1 owner changed
+from %2 to %3.
+.
+
+MessageId=5035 SymbolicName=MSG_CHK_BAD_LINKS_IN_ORPHANS
+Language=English
+Bad links in lost-chain at cluster %1 corrected.
+.
+
+MessageId=5036 SymbolicName=MSG_CHK_CROSS_LINKED_ORPHAN
+Language=English
+Lost-chain cross-linked at cluster %1. Orphan truncated.
+.
+
+MessageId=5037 SymbolicName=MSG_ORPHAN_DISK_SPACE
+Language=English
+Insufficient disk space to recover lost data.
+.
+
+MessageId=5038 SymbolicName=MSG_TOO_MANY_ORPHANS
+Language=English
+Insufficient disk space to recover lost data.
+.
+
+MessageId=5039 SymbolicName=MSG_CHK_ERROR_IN_LOG
+Language=English
+Error in extended attribute log.
+.
+
+MessageId=5040 SymbolicName=MSG_CHK_ERRORS_IN_DIR_CORR
+Language=English
+%1 Errors in directory corrected.
+.
+
+
+;//--------------------
+;//
+;// Messages for label.
+;//
+;//--------------------
+
+
+MessageId=6000 SymbolicName=MSG_LBL_INFO
+Language=English
+Creates, changes, or deletes the volume label of a disk.
+
+.
+
+MessageId=6001 SymbolicName=MSG_LBL_USAGE
+Language=English
+LABEL [drive:][label]
+
+.
+
+MessageId=6002 SymbolicName=MSG_LBL_NO_LABEL
+Language=English
+Volume in drive %1 has no label
+.
+
+MessageId=6003 SymbolicName=MSG_LBL_THE_LABEL
+Language=English
+Volume in drive %1 is %2
+.
+
+MessageId=6005 SymbolicName=MSG_LBL_DELETE_LABEL
+Language=English
+
+Delete current volume label (Y/N)? %0
+.
+
+MessageId=6006 SymbolicName=MSG_LBL_NOT_SUPPORTED
+Language=English
+The network request is not supported.
+.
+
+
+;//---------------------
+;//
+;// Messages for attrib.
+;//
+;//---------------------
+
+
+MessageId=7000 SymbolicName=MSG_ATTRIB_ARCHIVE
+Language=English
+A
+.
+
+MessageId=7001 SymbolicName=MSG_ATTRIB_HIDDEN
+Language=English
+H
+.
+
+MessageId=7002 SymbolicName=MSG_ATTRIB_READ_ONLY
+Language=English
+R
+.
+
+MessageId=7003 SymbolicName=MSG_ATTRIB_SYSTEM
+Language=English
+R
+.
+
+MessageId=7004 SymbolicName=MSG_ATTRIB_FILE_NOT_FOUND
+Language=English
+File not found - %1
+.
+
+MessageId=7005 SymbolicName=MSG_ATTRIB_PATH_NOT_FOUND
+Language=English
+Path not found - %1
+.
+
+MessageId=7006 SymbolicName=MSG_ATTRIB_PARAMETER_NOT_CORRECT
+Language=English
+Parameter format not correct -
+.
+
+MessageId=7007 SymbolicName=MSG_ATTRIB_NOT_RESETTING_SYS_FILE
+Language=English
+Not resetting system file - %1
+.
+
+MessageId=7008 SymbolicName=MSG_ATTRIB_NOT_RESETTING_HIDDEN_FILE
+Language=English
+Not resetting hidden file - %1
+.
+
+MessageId=7009 SymbolicName=MSG_ATTRIB_DISPLAY_ATTRIBUTE
+Language=English
+%1 %2%3%4 %5
+.
+
+MessageId=7010 SymbolicName=MSG_ATTRIB_HELP_MESSAGE
+Language=English
+Displays or changes file attributes.
+
+ATTRIB [+R | -R] [+A | -A ] [+S | -S] [+H | -H] [[drive:] [path] filename] [/S]
+
+ + Sets an attribute.
+ - Clears an attribute.
+ R Read-only file attribute.
+ A Archive file attribute.
+ S System file attribute.
+ H Hidden file attribute.
+ /S Processes matching files in the current directory
+ and all subdirectories.
+
+.
+
+MessageId=7012 SymbolicName=MSG_ATTRIB_INVALID_SWITCH
+Language=English
+Invalid switch - %1
+.
+
+MessageId=7013 SymbolicName=MSG_ATTRIB_ACCESS_DENIED
+Language=English
+Access denied - %1
+.
+
+MessageId=7014 SymbolicName=MSG_ATTRIB_UNABLE_TO_CHANGE_ATTRIBUTE
+Language=English
+Unable to change attribute - %1
+.
+
+;//--------------------
+;//
+;// Messages for sort
+;//
+;//--------------------
+
+
+MessageId=8000 SymbolicName=MSG_SORT_VALUE_NOT_IN_RANGE
+Language=English
+SORT: Parameter value not in allowed range
+.
+
+MessageId=8001 SymbolicName=MSG_SORT_INVALID_SWITCH
+Language=English
+SORT: Invalid switch
+.
+
+MessageId=8002 SymbolicName=MSG_SORT_TOO_MANY_PARAMETERS
+Language=English
+SORT: Too many parameters
+.
+
+MessageId=8003 SymbolicName=MSG_SORT_HELP_MESSAGE
+Language=English
+Sorts input and writes results to the screen, a file, or another device.
+
+SORT [/R] [/+n] < [drive1:][path1]filename1 [> [drive2:][path2]filename2]
+[command |] SORT [/R] [/+n] [> [drive2:][path2]filename2]
+
+ /R Reverses the sort order; that is, sorts Z to A,
+ then 9 to 0.
+ /+n Sorts the file according to characters in
+ column n.
+ [drive1:][path1]filename1 Specifies a file to be sorted.
+ [drive2:][path2]filename2 Specifies a file where the sorted input is to be
+ stored.
+ command Specifies a command whose output is to be sorted.
+
+
+.
+
+;//-------------------
+;//
+;// Diskcopy messages.
+;//
+;//-------------------
+
+
+MessageId=9000 SymbolicName=MSG_9000
+Language=English
+
+.
+
+MessageId=9001 SymbolicName=MSG_9001
+Language=English
+Do not specify filename(s)
+Command Format: DISKCOPY [drive1: [drive2:]] [/1] [/V]
+.
+
+MessageId=9002 SymbolicName=MSG_DCOPY_INVALID_DRIVE
+Language=English
+
+Invalid drive specification
+Specified drive does not exist
+or is non-removable
+.
+
+MessageId=9003 SymbolicName=MSG_9003
+Language=English
+
+Cannot DISKCOPY to or from
+a network drive
+.
+
+MessageId=9004 SymbolicName=MSG_DCOPY_FORMATTING_WHILE_COPYING
+Language=English
+
+Formatting while copying
+.
+
+MessageId=9005 SymbolicName=MSG_DCOPY_INSERT_SOURCE
+Language=English
+
+Insert SOURCE disk in drive %1
+.
+
+MessageId=9006 SymbolicName=MSG_DCOPY_INSERT_TARGET
+Language=English
+
+Insert TARGET disk in drive %1
+.
+
+MessageId=9007 SymbolicName=MSG_9007
+Language=English
+Make sure a disk is inserted into
+the drive and the door is closed
+.
+
+MessageId=9008 SymbolicName=MSG_9008
+Language=English
+
+Target disk may be unusable
+.
+
+MessageId=9009 SymbolicName=MSG_DCOPY_BAD_TARGET
+Language=English
+
+Target disk unusable
+.
+
+MessageId=9010 SymbolicName=MSG_DCOPY_ANOTHER
+Language=English
+
+Copy another disk (Y/N)? %0
+.
+
+MessageId=9011 SymbolicName=MSG_DCOPY_COPYING
+Language=English
+
+Copying %1 tracks
+%2 sectors per track, %3 side(s)
+.
+
+MessageId=9012 SymbolicName=MSG_DCOPY_NON_COMPAT_DISKS
+Language=English
+
+Drive types or disk types
+not compatible
+.
+
+MessageId=9013 SymbolicName=MSG_DCOPY_READ_ERROR
+Language=English
+
+Unrecoverable read error on drive %1
+side %2, track %3
+.
+
+MessageId=9014 SymbolicName=MSG_DCOPY_WRITE_ERROR
+Language=English
+
+Unrecoverable write error on drive %1
+side %2, track %3
+.
+
+MessageId=9015 SymbolicName=MSG_DCOPY_ENDED
+Language=English
+
+Copy process ended
+.
+
+MessageId=9016 SymbolicName=MSG_DCOPY_BAD_SOURCE
+Language=English
+
+SOURCE disk bad or incompatible.
+.
+
+MessageId=9017 SymbolicName=MSG_DCOPY_BAD_DEST
+Language=English
+
+TARGET disk bad or incompatible.
+.
+
+MessageId=9020 SymbolicName=MSG_DCOPY_INFO
+Language=English
+Copies the contents of one floppy disk to another.
+
+.
+
+MessageId=9021 SymbolicName=MSG_DCOPY_USAGE
+Language=English
+DISKCOPY [drive1: [drive2:]] [/V]
+
+.
+
+MessageId=9023 SymbolicName=MSG_DCOPY_SLASH_V
+Language=English
+ /V Verifies that the information is copied correctly.
+
+.
+
+MessageId=9024 SymbolicName=MSG_DCOPY_INFO_2
+Language=English
+The two floppy disks must be the same type.
+You may specify the same drive for drive1 and drive2.
+.
+
+MessageId=9025 SymbolicName=MSG_DCOPY_INSERT_SOURCE_AND_TARGET
+Language=English
+
+Insert SOURCE disk in drive %1
+
+Insert TARGET disk in drive %2
+.
+
+MessageId=9026 SymbolicName=MSG_DCOPY_UNRECOGNIZED_FORMAT
+Language=English
+Unrecognized format.
+.
+
+MessageId=9027 SymbolicName=MSG_DCOPY_NOT_ADMINISTRATOR
+Language=English
+You need to be an administrator to copy this disk.
+.
+
+MessageId=9028 SymbolicName=MSG_DCOPY_DISK_TOO_LARGE
+Language=English
+Cannot copy disk larger than %1 Megabytes.
+.
+
+;// this message will never appear as text message.
+;// this is a placeholder for the GUI version of the message.
+MessageId=9029 SymbolicName=MSG_DCOPY_UNRECOGNIZED_MEDIA
+Language=English
+Unrecognized media. Please insert the correct media into drive %1.
+.
+
+;// this message will never appear as text message.
+;// this is a placeholder for the GUI version of the message.
+MessageId=9030 SymbolicName=MSG_DCOPY_NO_MEDIA_IN_DEVICE
+Language=English
+There is no disk in the drive. Please insert a disk into drive %1.
+.
+
+;// this message will never appear as text message.
+;// this is a placeholder for the GUI version of the message.
+MessageId=9031 SymbolicName=MSG_DCOPY_MEDIA_WRITE_PROTECTED
+Language=English
+The disk in drive %1 is write protected. Please use a writable disk.
+.
+
+;//-------------------
+;//
+;// Diskcomp messages.
+;//
+;//-------------------
+
+MessageId=10000 SymbolicName=MSG_10000
+Language=English
+Do not specify filename(s)
+Command format: DISKCOMP [drive1: [drive2:]] [/1] [/8]
+.
+
+MessageId=10001 SymbolicName=MSG_10001
+Language=English
+
+Invalid drive specification
+Specified drive does not exist
+or is non-removable.
+.
+
+MessageId=10003 SymbolicName=MSG_DCOMP_INSERT_FIRST
+Language=English
+
+Insert FIRST disk in drive %1
+.
+
+MessageId=10004 SymbolicName=MSG_DCOMP_INSERT_SECOND
+Language=English
+
+Insert SECOND disk in drive %1
+.
+
+MessageId=10005 SymbolicName=MSG_DCOMP_FIRST_DISK_BAD
+Language=English
+
+FIRST disk bad or incompatible
+.
+
+MessageId=10006 SymbolicName=MSG_DCOMP_SECOND_DISK_BAD
+Language=English
+
+SECOND disk bad or incompatible
+.
+
+MessageId=10007 SymbolicName=MSG_DCOMP_ANOTHER
+Language=English
+
+Compare another disk (Y/N) ? %0
+.
+
+MessageId=10008 SymbolicName=MSG_DCOMP_COMPARING
+Language=English
+
+Comparing %1 tracks
+%2 sectors per track, %3 side(s)
+.
+
+MessageId=10009 SymbolicName=MSG_DCOMP_NOT_COMPATIBLE
+Language=English
+
+Drive types or disk types not compatible
+.
+
+MessageId=10010 SymbolicName=MSG_10010
+Language=English
+
+Unrecoverable read error on drive %1
+side %2, track %3
+.
+
+MessageId=10011 SymbolicName=MSG_DCOMP_COMPARE_ERROR
+Language=English
+
+Compare error on
+side %1, track %2
+.
+
+MessageId=10012 SymbolicName=MSG_10012
+Language=English
+Make sure a disk is inserted into
+the drive and the door is closed.
+.
+
+MessageId=10013 SymbolicName=MSG_DCOMP_ENDED
+Language=English
+
+Compare process ended.
+.
+
+MessageId=10014 SymbolicName=MSG_DCOMP_OK
+Language=English
+
+Compare OK
+.
+
+MessageId=10015 SymbolicName=MSG_10015
+Language=English
+
+.
+
+MessageId=10016 SymbolicName=MSG_DCOMP_INFO
+Language=English
+Compares the contents of two floppy disks.
+
+.
+
+MessageId=10017 SymbolicName=MSG_DCOMP_USAGE
+Language=English
+DISKCOMP [drive1: [drive2:]]
+
+.
+
+
+
+;//--------------------
+;//
+;// Messages for tree
+;//
+;//--------------------
+
+
+MessageId=11000 SymbolicName=MSG_TREE_INVALID_SWITCH
+Language=English
+Invalid switch - /%1
+.
+
+MessageId=11001 SymbolicName=MSG_TREE_INVALID_PATH
+Language=English
+Invalid path - %1
+.
+
+MessageId=11002 SymbolicName=MSG_TREE_NO_SUBDIRECTORIES
+Language=English
+No subdirectories exist %1
+.
+
+MessageId=11003 SymbolicName=MSG_TREE_DIR_LISTING_NO_VOLUME_NAME
+Language=English
+Directory PATH listing
+.
+
+MessageId=11004 SymbolicName=MSG_TREE_DIR_LISTING_WITH_VOLUME_NAME
+Language=English
+Directory PATH listing for volume %1
+.
+
+MessageId=11005 SymbolicName=MSG_TREE_32_BIT_SERIAL_NUMBER
+Language=English
+Volume serial number is %1-%2
+.
+
+MessageId=11006 SymbolicName=MSG_TREE_64_BIT_SERIAL_NUMBER
+Language=English
+Volume serial number is %1 %2:%3
+.
+
+MessageId=11007 SymbolicName=MSG_TREE_HELP_MESSAGE
+Language=English
+Graphically displays the directory structure of a drive or path.
+
+TREE [drive:][path] [/F] [/A]
+
+ /F Display the names of the files in each directory.
+ /A Use ASCII instead of extended characters.
+
+.
+
+MessageId=11008 SymbolicName=MSG_TREE_SINGLE_BOTTOM_LEFT_CORNER
+Language=English
+€
+.
+
+MessageId=11009 SymbolicName=MSG_TREE_SINGLE_BOTTOM_HORIZONTAL
+Language=English
+.
+
+MessageId=11010 SymbolicName=MSG_TREE_SINGLE_LEFT_T
+Language=English
+„
+.
+
+MessageId=11011 SymbolicName=MSG_TREE_PARAMETER_NOT_CORRECT
+Language=English
+Parameter format not correct - %1
+.
+
+MessageId=11012 SymbolicName=MSG_TREE_TOO_MANY_PARAMETERS
+Language=English
+Too many parameters - %1
+.
+
+MessageId=11013 SymbolicName=MSG_TREE_INVALID_DRIVE
+Language=English
+Invalid drive specification
+.
+
+;//-------------------
+;//
+;// Find messages.
+;//
+;//-------------------
+
+MessageId=12000 SymbolicName=MSG_FIND
+Language=English
+FIND: %0
+.
+
+MessageId=12001 SymbolicName=MSG_FIND_INCORRECT_VERSION
+Language=English
+FIND: Incorrect Windows NT version
+.
+
+MessageId=12002 SymbolicName=MSG_FIND_INVALID_SWITCH
+Language=English
+FIND: Invalid switch
+.
+
+MessageId=12003 SymbolicName=MSG_FIND_INVALID_FORMAT
+Language=English
+FIND: Parameter format not correct
+.
+
+MessageId=12004 SymbolicName=MSG_FIND_USAGE
+Language=English
+Searches for a text string in a file or files.
+
+FIND [/V] [/C] [/N] [/I] "string" [[drive:][path]filename[ ...]]
+
+ /V Displays all lines NOT containing the specified string.
+ /C Displays only the count of lines containing the string.
+ /N Displays line numbers with the displayed lines.
+ /I Ignores the case of characters when searching for the string.
+ "string" Specifies the text string to find.
+ [drive:][path]filename
+ Specifies a file or files to search.
+
+If a path is not specified, FIND searches the text typed at the prompt
+or piped from another command.
+.
+
+MessageId=12005 SymbolicName=MSG_FIND_MISSING_PARM
+Language=English
+FIND: Required parameter missing
+.
+
+MessageId=12006 SymbolicName=MSG_FIND_FILE_NOT_FOUND
+Language=English
+File not found - %1
+.
+
+MessageId=12007 SymbolicName=MSG_FIND_COUNT
+Language=English
+%1
+.
+
+MessageId=12008 SymbolicName=MSG_FIND_COUNT_BANNER
+Language=English
+
+---------- %1: %2
+.
+
+MessageId=12009 SymbolicName=MSG_FIND_BANNER
+Language=English
+
+---------- %1
+.
+
+MessageId=12010 SymbolicName=MSG_FIND_LINEONLY
+Language=English
+%1
+.
+
+MessageId=12011 SymbolicName=MSG_FIND_LINE_AND_NUMBER
+Language=English
+[%1]%2
+.
+
+
+;//-----------------
+;//
+;// FC Messages
+;//
+;//-----------------
+
+MessageId=13000 SymbolicName=MSG_FC_HELP_MESSAGE
+Language=English
+Compares two files or sets of files and displays the differences between
+them
+
+
+FC [/A] [/C] [/L] [/LBn] [/N] [/T] [/U] [/W] [/nnnn] [drive1:][path1]filename1
+ [drive2:][path2]filename2
+FC /B [drive1:][path1]filename1 [drive2:][path2]filename2
+
+ /A Displays only first and last lines for each set of differences.
+ /B Performs a binary comparison.
+ /C Disregards the case of letters.
+ /L Compares files as ASCII text.
+ /LBn Sets the maximum consecutive mismatches to the specified number of
+ lines.
+ /N Displays the line numbers on an ASCII comparison.
+ /T Does not expand tabs to spaces.
+ /U Compare files as UNICODE text files.
+ /W Compresses white space (tabs and spaces) for comparison.
+ /nnnn Specifies the number of consecutive lines that must match after a
+ mismatch.
+
+.
+MessageId=13001 SymbolicName=MSG_FC_INCOMPATIBLE_SWITCHES
+Language=English
+FC: Incompatible Switches
+
+.
+MessageId=13002 SymbolicName=MSG_FC_INVALID_SWITCH
+Language=English
+FC: Invalid Switch
+
+.
+MessageId=13003 SymbolicName=MSG_FC_INSUFFICIENT_FILES
+Language=English
+FC: Insufficient number of file specifications
+
+.
+MessageId=13004 SymbolicName=MSG_13004
+Language=English
+Comparing files %1 and %2
+.
+MessageId=13005 SymbolicName=MSG_FC_UNABLE_TO_OPEN
+Language=English
+FC: cannot open %1 - No such file or directory
+
+.
+MessageId=13006 SymbolicName=MSG_FC_CANT_EXPAND_TO_MATCH
+Language=English
+%1 %2
+Could not expand second filename so as to match first
+
+.
+MessageId=13007 SymbolicName=MSG_FC_NO_DIFFERENCES
+Language=English
+FC: no differences encountered
+
+.
+MessageId=13008 SymbolicName=MSG_FC_COMPARING_FILES
+Language=English
+Comparing files %1 and %2
+.
+MessageId=13009 SymbolicName=MSG_FC_FILES_NOT_FOUND
+Language=English
+File(s) not found : %1
+
+.
+MessageId=13010 SymbolicName=MSG_FC_DATA
+Language=English
+%1
+.
+MessageId=13011 SymbolicName=MSG_FC_NUMBERED_DATA
+Language=English
+%1: %2
+.
+MessageId=13012 SymbolicName=MSG_FC_OUTPUT_FILENAME
+Language=English
+***** %1
+.
+MessageId=13013 SymbolicName=MSG_FC_DUMP_END
+Language=English
+*****
+
+.
+MessageId=13014 SymbolicName=MSG_FC_FILES_DIFFERENT_LENGTH
+Language=English
+FC: %1 longer than %2
+
+
+.
+MessageId=13015 SymbolicName=MSG_FC_RESYNC_FAILED
+Language=English
+Resync Failed. Files are too different
+.
+MessageId=13016 SymbolicName=MSG_FC_CANT_CREATE_STREAM
+Language=English
+FC: Unable to open %1. File unavailable for read access
+
+.
+MessageId=13017 SymbolicName=MSG_FC_INCORRECT_VERSION
+Language=English
+FC: Incorrect Windows NT Version
+
+.
+MessageId=13018 SymbolicName=MSG_FC_ABBREVIATE_SYMBOL
+Language=English
+...
+.
+
+MessageId=13019 SymbolicName=MSG_FC_ABBREVIATE_SYMBOL_SHIFTED
+Language=English
+ ...
+.
+
+MessageId=13020 SymbolicName=MSG_FC_HEX_OUT
+Language=English
+%1: %2 %3
+.
+
+MessageId=13021 SymbolicName=MSG_FC_OUT_OF_MEMORY
+Language=English
+FC: Out of memory
+.
+
+
+
+;//-----------------
+;//
+;// Comp Messages
+;//
+;//-----------------
+
+MessageId=14000 SymbolicName=MSG_COMP_HELP_MESSAGE
+Language=English
+Compares the contents of two files or sets of files.
+
+COMP [data1] [data2] [/D] [/A] [/L] [/N=number] [/C]
+
+ data1 Specifies location and name(s) of first file(s) to compare.
+ data2 Specifies location and name(s) of second files to compare.
+ /D Displays differences in decimal format. This is the default
+ setting.
+ /A Displays differences in ASCII characters.
+ /L Displays line numbers for differences.
+ /N=number Compares only the first specified number of lines in each file.
+ /C Disregards case of ASCII letters when comparing files.
+
+To compare sets of files, use wildcards in data1 and data2 parameters.
+.
+MessageId=14001 SymbolicName=MSG_COMP_FILES_OK
+Language=English
+Files compare OK
+
+.
+MessageId=14002 SymbolicName=MSG_COMP_NO_MEMORY
+Language=English
+No memory available.
+
+.
+MessageId=14003 SymbolicName=MSG_COMP_UNABLE_TO_OPEN
+Language=English
+Can't find/open file: %1
+
+.
+MessageId=14004 SymbolicName=MSG_COMP_UNABLE_TO_READ
+Language=English
+Can't read file: %1
+
+.
+MessageId=14005 SymbolicName=MSG_COMP_BAD_COMMAND_LINE
+Language=English
+Bad command line syntax
+
+.
+MessageId=14006 SymbolicName=MSG_COMP_BAD_NUMERIC_ARG
+Language=English
+Bad numeric argument :
+%1
+
+.
+MessageId=14007 SymbolicName=MSG_COMP_COMPARE_ERROR
+Language=English
+Compare error at %1 %2
+file1 = %3
+file2 = %4
+.
+MessageId=14008 SymbolicName=MSG_COMP_QUERY_FILE1
+Language=English
+Name of first file to compare: %0
+.
+MessageId=14009 SymbolicName=MSG_COMP_QUERY_FILE2
+Language=English
+Name of second file to compare: %0
+.
+MessageId=14010 SymbolicName=MSG_COMP_OPTION
+Language=English
+Option : %0
+.
+MessageId=14011 SymbolicName=MSG_COMP_COMPARE_FILES
+Language=English
+Comparing %1 and %2...
+.
+MessageId=14012 SymbolicName=MSG_COMP_DIFFERENT_SIZES
+Language=English
+Files are different sizes.
+
+.
+MessageId=14013 SymbolicName=MSG_COMP_NUMERIC_FORMAT
+Language=English
+Format for /n switch is /n=XXXX
+.
+MessageId=14014 SymbolicName=MSG_COMP_MORE
+Language=English
+Compare more files (Y/N) ? %0
+.
+MessageId=14015 SymbolicName=MSG_COMP_UNABLE_TO_EXPAND
+Language=English
+%1 %2
+Could not expand second filename so as to match first
+
+.
+MessageId=14016 SymbolicName=MSG_COMP_TOO_MANY_ERRORS
+Language=English
+10 Mismatches - ending compare
+
+.
+MessageId=14017 SymbolicName=MSG_COMP_INCORRECT_VERSION
+Language=English
+Incorrect Windows NT version
+
+.
+MessageId=14018 SymbolicName=MSG_COMP_UNEXPECTED_END
+Language=English
+Unexpected end of file
+
+.
+MessageId=14019 SymbolicName=MSG_COMP_INVALID_SWITCH
+Language=English
+Invalid switch - %1
+
+.
+MessageId=14020 SymbolicName=MSG_COMP_FILE1_TOO_SHORT
+Language=English
+
+File1 only has %1 lines
+
+.
+MessageId=14021 SymbolicName=MSG_COMP_FILE2_TOO_SHORT
+Language=English
+
+File2 only has %1 lines
+
+.
+MessageId=14022 SymbolicName=MSG_COMP_WILDCARD_STRING
+Language=English
+*.*%0
+.
+
+
+;//---------------------------
+;//
+;// FAT/HPFS Recover messages.
+;//
+;//---------------------------
+
+
+MessageId=15000 SymbolicName=MSG_RECOV_FILE_NOT_FOUND
+Language=English
+
+File not found
+.
+
+MessageId=15001 SymbolicName=MSG_15001
+Language=English
+
+Cannot RECOVER an ASSIGNed or SUBSTed drive
+.
+
+MessageId=15002 SymbolicName=MSG_INVALID_DRIVE
+Language=English
+
+Invalid drive or file name
+.
+
+MessageId=15004 SymbolicName=MSG_RECOV_CANT_NETWORK
+Language=English
+
+Cannot RECOVER a network drive
+.
+
+MessageId=15005 SymbolicName=MSG_15005
+Language=English
+
+%1 file(s) recovered.
+.
+
+MessageId=15006 SymbolicName=MSG_RECOV_BYTES_RECOVERED
+Language=English
+
+%1 of %2 bytes recovered.
+.
+
+MessageId=15007 SymbolicName=MSG_RECOV_BEGIN
+Language=English
+
+Press ENTER to begin recovery of the file on drive %1
+
+.
+
+MessageId=15008 SymbolicName=MSG_RECOV_CANT_READ_FAT
+Language=English
+
+Cannot read the file allocation table (FAT).
+.
+
+MessageId=15009 SymbolicName=MSG_RECOV_CANT_WRITE_FAT
+Language=English
+
+Cannot write the file allocation table (FAT).
+.
+
+MessageId=15010 SymbolicName=MSG_15010
+Language=English
+
+.
+
+MessageId=15011 SymbolicName=MSG_RECOV_INFO
+Language=English
+Recovers readable information from a bad or defective disk.
+
+.
+
+MessageId=15012 SymbolicName=MSG_RECOV_USAGE
+Language=English
+RECOVER [drive:][path]filename
+.
+
+MessageId=15013 SymbolicName=MSG_15013
+Language=English
+RECOVER drive:
+
+.
+
+MessageId=15014 SymbolicName=MSG_RECOV_INFO2
+Language=English
+Consult the online Command Reference in Windows NT Help
+before using the RECOVER command.
+.
+
+MessageId=15017 SymbolicName=MSG_RECOV_WRITE_ERROR
+Language=English
+Write error.
+.
+
+MessageId=15018 SymbolicName=MSG_RECOV_INTERNAL_ERROR
+Language=English
+Internal consistency error.
+.
+
+MessageId=15019 SymbolicName=MSG_RECOV_READ_ERROR
+Language=English
+Read error.
+.
+
+MessageId=15020 SymbolicName=MSG_RECOV_NOT_SUPPORTED
+Language=English
+RECOVER on an entire volume is no longer supported.
+To get equivalent functionality use CHKDSK.
+.
+
+
+;//----------------------------------
+;//
+;// NTFS-specific recover messages
+;//
+;//----------------------------------
+
+MessageId=15401 SymbolicName=MSG_NTFS_RECOV_SYSTEM_FILE
+Language=English
+NTFS RECOVER cannot be used to recover system files; use CHKDSK instead.
+.
+
+MessageId=15402 SymbolicName=MSG_NTFS_RECOV_FAILED
+Language=English
+NTFS RECOVER failed.
+.
+
+MessageId=15043 SymbolicName=MSG_NTFS_RECOV_CORRUPT_VOLUME
+Language=English
+NTFS RECOVER has detected that the volume is corrupt. Run CHKDSK /f
+to fix it.
+.
+
+MessageId=15044 SymbolicName=MSG_NTFS_RECOV_CANT_WRITE_ELEMENTARY
+Language=English
+NTFS Recover could not write elementary disk structures. The volume
+may be corrupt; run CHKDSK /f to fix it.
+.
+
+MessageId=15045 SymbolicName=MSG_NTFS_RECOV_WRONG_VERSION
+Language=English
+Files on this volume cannot be recovered with this version of UNTFS.DLL.
+.
+
+
+
+
+;//--------------------
+;//
+;// Messages for Print
+;//
+;//--------------------
+
+
+MessageId=16000 SymbolicName=MSG_PRINT_INVALID_SWITCH
+Language=English
+Invalid switch - %1
+.
+
+MessageId=16001 SymbolicName=MSG_PRINT_NOT_IMPLEMENTED
+Language=English
+Switch %1 is not implemented
+.
+
+MessageId=16002 SymbolicName=MSG_PRINT_NO_FILE
+Language=English
+No file to print
+.
+
+MessageId=16003 SymbolicName=MSG_PRINT_UNABLE_INIT_DEVICE
+Language=English
+Unable to initialize device %1
+.
+
+MessageId=16004 SymbolicName=MSG_PRINT_FILE_NOT_FOUND
+Language=English
+Can't find file %1
+.
+
+MessageId=16005 SymbolicName=MSG_PRINT_PRINTING
+Language=English
+%1 is currently being printed
+.
+
+MessageId=16006 SymbolicName=MSG_PRINT_HELP_MESSAGE
+Language=English
+Prints a text file.
+
+PRINT [/D:device] [[drive:][path]filename[...]]
+
+ /D:device Specifies a print device.
+
+.
+
+
+
+;//---------------
+;//
+;// Help Messages
+;//
+;//---------------
+
+MessageId=17000 SymbolicName=MSG_HELP_HELP_MESSAGE
+Language=English
+Provides help information for Windows NT commands.
+
+HELP [command]
+
+ command - displays help information on that command.
+
+.
+MessageId=17001 SymbolicName=MSG_HELP_HELP_FILE_NOT_FOUND
+Language=English
+Help file could not be found.
+
+.
+MessageId=17002 SymbolicName=MSG_HELP_HELP_FILE_ERROR
+Language=English
+Error reading help file.
+
+.
+MessageId=17003 SymbolicName=MSG_HELP_GENERAL_HELP
+Language=English
+
+
+For more information on a specific command, type HELP command-name.
+.
+MessageId=17004 SymbolicName=MSG_HELP_HELP_UNAVAILABLE
+Language=English
+This command is not supported by the help utility. Try "%1 /?".
+.
+MessageId=17005 SymbolicName=MSG_HELP_HELP_COMMENT
+Language=English
+@ %0
+.
+MessageId=17006 SymbolicName=MSG_HELP_EXECUTE_WITH_CMD
+Language=English
+cmd /c %1 /? %0
+.
+MessageId=17007 SymbolicName=MSG_HELP_EXECUTE_WITHOUT_CMD
+Language=English
+%1 /? %0
+.
+MessageId=17008 SymbolicName=MSG_HELP_HELP_FILE_NAME
+Language=English
+DosHelp.hlp%0
+.
+MessageId=17009 SymbolicName=MSG_HELP_HELP_FILE_DATA
+Language=English
+%1
+.
+MessageId=17010 SymbolicName=MSG_HELP_INCORRECT_VERSION
+Language=English
+Incorrect Windows NT version
+
+.
+MessageId=17011 SymbolicName=MSG_HELP_MORE
+Language=English
+--- MORE ---%0
+.
+
+
+
+;//---------------
+;//
+;// MORE messages.
+;//
+;//---------------
+
+
+MessageId=20001 SymbolicName=MORE_ENVIRONMENT_VARIABLE_NAME
+Language=English
+MORE%0
+.
+
+MessageId=20002 SymbolicName=MORE_PATTERN_SWITCH_EXTENDED
+Language=English
+/E%0
+.
+
+MessageId=20003 SymbolicName=MORE_PATTERN_SWITCH_CLEARSCREEN
+Language=English
+/C%0
+.
+
+MessageId=20004 SymbolicName=MORE_PATTERN_SWITCH_EXPANDFORMFEED
+Language=English
+/P%0
+.
+
+MessageId=20005 SymbolicName=MORE_PATTERN_SWITCH_SQUEEZEBLANKS
+Language=English
+/S%0
+.
+
+MessageId=20006 SymbolicName=MORE_PATTERN_SWITCH_HELP1
+Language=English
+/?%0
+.
+
+MessageId=20007 SymbolicName=MORE_PATTERN_SWITCH_HELP2
+Language=English
+/H%0
+.
+
+MessageId=20008 SymbolicName=MORE_PATTENR_ARG_STARTATLINE
+Language=English
++*%0
+.
+
+MessageId=20010 SymbolicName=MORE_LEXEMIZER_MULTIPLESWITCH
+Language=English
+/ECPSH?%0
+.
+
+MessageId=20011 SymbolicName=MORE_LEXEMIZER_SWITCHES
+Language=English
+/-%0
+.
+
+MessageId=20020 SymbolicName=MORE_PROMPT
+Language=English
+-- More %1%2%3 -- %4%0
+.
+
+MessageId=20021 SymbolicName=MORE_PERCENT
+Language=English
+(%1%%)%0
+.
+
+MessageId=20022 SymbolicName=MORE_LINE
+Language=English
+[Line: %1]%0
+.
+
+MessageId=20023 SymbolicName=MORE_HELP
+Language=English
+[Options: psfq=<space><ret>]%0
+.
+
+MessageId=20024 SymbolicName=MORE_LINEPROMPT
+Language=English
+Lines: %0
+.
+
+MessageId=20030 SymbolicName=MORE_OPTION_DISPLAYLINES
+Language=English
+P%0
+.
+
+MessageId=20031 SymbolicName=MORE_OPTION_SKIPLINES
+Language=English
+S%0
+.
+
+MessageId=20032 SymbolicName=MORE_OPTION_SHOWLINENUMBER
+Language=English
+=%0
+.
+
+MessageId=20033 SymbolicName=MORE_OPTION_QUIT
+Language=English
+Q%0
+.
+
+MessageId=20034 SymbolicName=MORE_OPTION_HELP1
+Language=English
+?%0
+.
+
+MessageId=20035 SymbolicName=MORE_OPTION_HELP2
+Language=English
+H%0
+.
+
+MessageId=20036 SymbolicName=MORE_OPTION_NEXTFILE
+Language=English
+F%0
+.
+
+MessageId=20040 SymbolicName=MORE_MESSAGE_USAGE
+Language=English
+Displays output one screen at a time.
+
+MORE [/E [/C] [/P] [/S] [/Tn] [+n]] < [drive:][path]filename
+command-name | MORE [/E [/C] [/P] [/S] [/Tn] [+n]]
+MORE /E [/C] [/P] [/S] [/Tn] [+n] [files]
+
+ [drive:][path]filename Specifies a file to display one
+ screen at a time.
+
+ command-name Specifies a command whose output
+ will be displayed.
+
+ /E Enable extended features
+ /C Clear screen before displaying page
+ /P Expand FormFeed characters
+ /S Squeeze multiple blank lines into a single line
+ /Tn Expand tabs to n spaces (default 8)
+
+ Switches can be present in the MORE environment
+ variable.
+
+ +n Start displaying the first file at line n
+
+ files List of files to be displayed. Files in the list
+ are separated by blanks.
+
+ If extended features are enabled, the following commands
+ are accepted at the -- More -- prompt:
+
+ P n Display next n lines
+ S n Skip next n lines
+ F Display next file
+ Q Quit
+ = Show line number
+ ? Show help line
+ <space> Display next page
+ <ret> Display next line
+.
+
+MessageId=20050 SymbolicName=MORE_ERROR_GENERAL
+Language=English
+Internal error.
+.
+
+MessageId=20051 SymbolicName=MORE_ERROR_TOO_MANY_ARGUMENTS
+Language=English
+Too many arguments in command line.
+.
+
+MessageId=20052 SymbolicName=MORE_ERROR_NO_MEMORY
+Language=English
+Not enough memory.
+.
+
+MessageId=20053 SymbolicName=MORE_ERROR_CANNOT_ACCESS
+Language=English
+Cannot access file %1
+.
+
+
+
+;//------------------
+;//
+;// REPLACE messages.
+;//
+;//------------------
+
+
+MessageId=21001 SymbolicName=REPLACE_PATTERN_SWITCH_ADD
+Language=English
+/A%0
+.
+
+MessageId=21002 SymbolicName=REPLACE_PATTERN_SWITCH_PROMPT
+Language=English
+/P%0
+.
+
+MessageId=21003 SymbolicName=REPLACE_PATTERN_SWITCH_READONLY
+Language=English
+/R%0
+.
+
+MessageId=21004 SymbolicName=REPLACE_PATTERN_SWITCH_SUBDIR
+Language=English
+/S%0
+.
+
+MessageId=21005 SymbolicName=REPLACE_PATTERN_SWITCH_COMPARETIME
+Language=English
+/U%0
+.
+
+MessageId=21006 SymbolicName=REPLACE_PATTERN_SWITCH_WAIT
+Language=English
+/W%0
+.
+
+MessageId=21007 SymbolicName=REPLACE_PATTERN_SWITCH_HELP
+Language=English
+/?%0
+.
+
+MessageId=21010 SymbolicName=REPLACE_LEXEMIZER_SWITCHES
+Language=English
+/-%0
+.
+
+MessageId=21011 SymbolicName=REPLACE_LEXEMIZER_MULTIPLESWITCH
+Language=English
+/APRSUW?%0
+.
+
+MessageId=21020 SymbolicName=REPLACE_MESSAGE_REPLACING
+Language=English
+Replacing %1
+.
+
+MessageId=21021 SymbolicName=REPLACE_MESSAGE_ADDING
+Language=English
+Adding %1
+.
+
+MessageId=21022 SymbolicName=REPLACE_MESSAGE_FILES_REPLACED
+Language=English
+%1 file(s) replaced
+.
+
+MessageId=21023 SymbolicName=REPLACE_MESSAGE_FILES_ADDED
+Language=English
+%1 file(s) added
+.
+
+MessageId=21024 SymbolicName=REPLACE_MESSAGE_NO_FILES_REPLACED
+Language=English
+No files replaced
+.
+
+MessageId=21025 SymbolicName=REPLACE_MESSAGE_NO_FILES_ADDED
+Language=English
+No files added
+.
+
+MessageId=21026 SymbolicName=REPLACE_MESSAGE_PRESS_ANY_KEY
+Language=English
+Press any key to continue . . .
+.
+
+MessageId=21027 SymbolicName=REPLACE_MESSAGE_REPLACE_YES_NO
+Language=English
+Replace %1? (Y/N) %0
+.
+
+MessageId=21028 SymbolicName=REPLACE_MESSAGE_ADD_YES_NO
+Language=English
+Add %1? (Y/N) %0
+.
+
+MessageId=21029 SymbolicName=REPLACE_MESSAGE_USAGE
+Language=English
+Replaces files.
+
+REPLACE [drive1:][path1]filename [drive2:][path2] [/A] [/P] [/R] [/W]
+REPLACE [drive1:][path1]filename [drive2:][path2] [/P] [/R] [/S] [/W] [/U]
+
+ [drive1:][path1]filename Specifies the source file or files.
+ [drive2:][path2] Specifies the directory where files are to be
+ replaced.
+ /A Adds new files to destination directory. Cannot
+ use with /S or /U switches.
+ /P Prompts for confirmation before replacing a file or
+ adding a source file.
+ /R Replaces read-only files as well as unprotected
+ files.
+ /S Replaces files in all subdirectories of the
+ destination directory. Cannot use with the /A
+ switch.
+ /W Waits for you to insert a disk before beginning.
+ /U Replaces (updates) only files that are older than
+ source files. Cannot use with the /A switch.
+.
+
+MessageId=21050 SymbolicName=REPLACE_ERROR_INCORRECT_OS_VERSION
+Language=English
+Incorrect Windows NT version
+.
+
+MessageId=21051 SymbolicName=REPLACE_ERROR_SOURCE_PATH_REQUIRED
+Language=English
+Source path required
+.
+
+MessageId=21052 SymbolicName=REPLACE_ERROR_SELF_REPLACE
+Language=English
+File cannot be copied onto itself
+.
+
+MessageId=21053 SymbolicName=REPLACE_ERROR_NO_DISK_SPACE
+Language=English
+Insufficient disk space
+.
+
+MessageId=21054 SymbolicName=REPLACE_ERROR_NO_FILES_FOUND
+Language=English
+No files found - %1
+.
+
+MessageId=21055 SymbolicName=REPLACE_ERROR_EXTENDED
+Language=English
+Extended Error %1
+.
+
+MessageId=21056 SymbolicName=REPLACE_ERROR_PARSE
+Language=English
+Parse Error %1
+.
+
+MessageId=21057 SymbolicName=REPLACE_ERROR_NO_MEMORY
+Language=English
+Out of memory
+.
+
+MessageId=21058 SymbolicName=REPLACE_ERROR_INVALID_SWITCH
+Language=English
+Invalid switch - %1
+.
+
+MessageId=21059 SymbolicName=REPLACE_ERROR_INVALID_PARAMETER_COMBINATION
+Language=English
+Invalid parameter combination
+.
+
+MessageId=21060 SymbolicName=REPLACE_ERROR_PATH_NOT_FOUND
+Language=English
+Path not found - %1
+.
+
+MessageId=21061 SymbolicName=REPLACE_ERROR_ACCESS_DENIED
+Language=English
+Access denied - %1
+.
+
+
+
+;//----------------
+;//
+;// XCOPY messages.
+;//
+;//----------------
+
+
+MessageId=22001 SymbolicName=XCOPY_PATTERN_SWITCH_ARCHIVE
+Language=English
+/A%0
+.
+
+MessageId=22002 SymbolicName=XCOPY_PATTERN_SWITCH_DATE
+Language=English
+/D:*%0
+.
+
+MessageId=22003 SymbolicName=XCOPY_PATTERN_SWITCH_EMPTY
+Language=English
+/E%0
+.
+
+MessageId=22004 SymbolicName=XCOPY_PATTERN_SWITCH_MODIFY
+Language=English
+/M%0
+.
+
+MessageId=22005 SymbolicName=XCOPY_PATTERN_SWITCH_PROMPT
+Language=English
+/P%0
+.
+
+MessageId=22006 SymbolicName=XCOPY_PATTERN_SWITCH_SUBDIR
+Language=English
+/S%0
+.
+
+MessageId=22007 SymbolicName=XCOPY_PATTERN_SWITCH_VERIFY
+Language=English
+/V%0
+.
+
+MessageId=22008 SymbolicName=XCOPY_PATTERN_SWITCH_WAIT
+Language=English
+/W%0
+.
+
+MessageId=22009 SymbolicName=XCOPY_PATTERN_SWITCH_HELP
+Language=English
+/?%0
+.
+
+MessageId=22020 SymbolicName=XCOPY_LEXEMIZER_SWITCHES
+Language=English
+/-%0
+.
+
+MessageId=22021 SymbolicName=XCOPY_LEXEMIZER_MULTIPLESWITCH
+Language=English
+/AEMPSVW?%0
+.
+
+MessageId=22031 SymbolicName=XCOPY_ERROR_NO_MEMORY
+Language=English
+Insufficient memory
+.
+
+MessageId=22032 SymbolicName=XCOPY_ERROR_INVALID_PARAMETER
+Language=English
+Invalid parameter - %1
+.
+
+MessageId=22034 SymbolicName=XCOPY_ERROR_INVALID_PATH
+Language=English
+Invalid path
+.
+
+MessageId=22035 SymbolicName=XCOPY_ERROR_CYCLE
+Language=English
+Cannot perform a cyclic copy
+.
+
+MessageId=22036 SymbolicName=XCOPY_ERROR_INVALID_DATE
+Language=English
+Invalid date
+.
+
+MessageId=22037 SymbolicName=XCOPY_ERROR_CREATE_DIRECTORY
+Language=English
+Unable to create directory
+.
+
+MessageId=22038 SymbolicName=XCOPY_ERROR_INVALID_DRIVE
+Language=English
+Invalid drive specification
+.
+
+MessageId=22039 SymbolicName=XCOPY_ERROR_RESERVED_DEVICE
+Language=English
+Cannot XCOPY from a reserved device
+.
+
+MessageId=22040 SymbolicName=XCOPY_ERROR_ACCESS_DENIED
+Language=English
+Access denied
+.
+
+MessageId=22041 SymbolicName=XCOPY_ERROR_TOO_MANY_OPEN_FILES
+Language=English
+Too many open files
+.
+
+MessageId=22042 SymbolicName=XCOPY_ERROR_GENERAL
+Language=English
+General failure
+.
+
+MessageId=22043 SymbolicName=XCOPY_ERROR_SHARING_VIOLATION
+Language=English
+Sharing violation
+.
+
+MessageId=22044 SymbolicName=XCOPY_ERROR_LOCK_VIOLATION
+Language=English
+Lock violation
+.
+
+MessageId=22045 SymbolicName=XCOPY_ERROR_PATH_NOT_FOUND
+Language=English
+Path not found
+.
+
+MessageId=22046 SymbolicName=XCOPY_ERROR_DISK_FULL
+Language=English
+Insufficient disk space
+.
+
+MessageId=22047 SymbolicName=XCOPY_ERROR_SELF_COPY
+Language=English
+File cannot be copied onto itself
+.
+
+MessageId=22048 SymbolicName=XCOPY_ERROR_INVALID_NUMBER_PARAMETERS
+Language=English
+Invalid number of parameters
+.
+
+MessageId=22049 SymbolicName=XCOPY_ERROR_CREATE_DIRECTORY1
+Language=English
+Unable to create directory - %1
+.
+
+MessageId=22050 SymbolicName=XCOPY_ERROR_FILE_NOT_FOUND
+Language=English
+File not found - %1
+.
+
+MessageId=22051 SymbolicName=XCOPY_ERROR_CANNOT_MAKE
+Language=English
+File creation error - %1
+.
+
+MessageId=22052 SymbolicName=XCOPY_ERROR_INVALID_SWITCH
+Language=English
+Invalid switch
+.
+
+MessageId=22053 SymbolicName=XCOPY_ERROR_INVALID_PATH_PARTIAL_COPY
+Language=English
+Invalid Path, not all directories/files copied
+.
+
+MessageId=22054 SymbolicName=XCOPY_ERROR_EXTENDED
+Language=English
+Extended Error %1
+.
+
+MessageId=22055 SymbolicName=XCOPY_ERROR_PARSE
+Language=English
+Parse Error
+.
+
+MessageId=22056 SymbolicName=XCOPY_ERROR_WRITE_PROTECT
+Language=English
+Write protect error accessing drive.
+.
+
+MessageId=22057 SymbolicName=XCOPY_ERROR_INVALID_SWITCH_SWITCH
+Language=English
+Invalid switch - %1
+.
+
+MessageId=22060 SymbolicName=XCOPY_MESSAGE_USAGE
+Language=English
+Copies files and directory trees.
+
+XCOPY source [destination] [/A | /M] [/D[:date]] [/P] [/S [/E]] [/V] [/W]
+ [/C] [/I] [/Q] [/F] [/L] [/H] [/R] [/T] [/U]
+ [/K] [/N] [/Z]
+
+ source Specifies the file(s) to copy.
+ destination Specifies the location and/or name of new files.
+ /A Copies files with the archive attribute set,
+ doesn't change the attribute.
+ /M Copies files with the archive attribute set,
+ turns off the archive attribute.
+ /D:m-d-y Copies files changed on or after the specified date.
+ If no date is given, copies only those files whose
+ source time is newer than the destination time.
+ /P Prompts you before creating each destination file.
+ /S Copies directories and subdirectories except empty ones.
+ /E Copies directories and subdirectories, including empty ones.
+ Same as /S /E. May be used to modify /T.
+ /V Verifies each new file.
+ /W Prompts you to press a key before copying.
+ /C Continues copying even if errors occur.
+ /I If destination does not exist and copying more than one file,
+ assumes that destination must be a directory.
+ /Q Does not display file names while copying.
+ /F Displays full source and destination file names while copying.
+ /L Displays files that would be copied.
+ /H Copies hidden and system files also.
+ /R Overwrites read-only files.
+ /T Creates directory structure, but does not copy files. Does not
+ include empty directories or subdirectories. /T /E includes
+ empty directories and subdirectories.
+ /U Copies only files that already exist in destination.
+ /K Copies attributes. Normal Xcopy will reset read-only attributes.
+ /N Copies using the generated short names.
+ /Z Copies networked files in restartable mode.
+.
+
+MessageId=22061 SymbolicName=XCOPY_MESSAGE_WAIT
+Language=English
+Press any key when ready to begin copying file(s)%0
+.
+
+MessageId=22062 SymbolicName=XCOPY_MESSAGE_CONFIRM
+Language=English
+%1 (Y/N)? %0
+.
+
+MessageId=22063 SymbolicName=XCOPY_MESSAGE_FILE_OR_DIRECTORY
+Language=English
+Does %1 specify a file name
+or directory name on the target
+(F = file, D = directory)? %0
+.
+
+MessageId=22064 SymbolicName=XCOPY_MESSAGE_FILES_COPIED
+Language=English
+%1 File(s) copied
+.
+
+MessageId=22065 SymbolicName=XCOPY_MESSAGE_FILENAME
+Language=English
+%1
+.
+
+MessageId=22066 SymbolicName=XCOPY_MESSAGE_VERBOSE_COPY
+Language=English
+%1 -> %2
+.
+
+MessageId=22067 SymbolicName=XCOPY_MESSAGE_CHANGE_DISK
+Language=English
+
+Insufficient disk space on current disk.
+Insert another disk and type <Return> to continue... %0
+.
+
+MessageId=22070 SymbolicName=XCOPY_RESPONSE_FILE
+Language=English
+F%0
+.
+
+MessageId=22071 SymbolicName=XCOPY_RESPONSE_DIRECTORY
+Language=English
+D%0
+.
+
+MessageId=22072 SymbolicName=XCOPY_RESPONSE_YES
+Language=English
+Y%0
+.
+
+MessageId=22073 SymbolicName=XCOPY_RESPONSE_NO
+Language=English
+N%0
+.
+
+MessageId=22074 SymbolicName=XCOPY_MESSAGE_FILES
+Language=English
+%1 File(s)
+.
+
+MessageId=22075 SymbolicName=XCOPY_ERROR_VERIFY_FAILED
+Language=English
+File verification failed.
+.
+
+;//---------------
+;//
+;// MODE messages.
+;//
+;//---------------
+
+
+MessageId=23050 SymbolicName=MODE_MESSAGE_REROUTED
+Language=English
+LPT%1: rerouted to COM%2:
+.
+
+MessageId=23051 SymbolicName=MODE_MESSAGE_ACTIVE_CODEPAGE
+Language=English
+Active code page for device %1 is %2
+.
+
+MessageId=23052 SymbolicName=MODE_MESSAGE_HELP
+Language=English
+Configures system devices.
+
+Serial port: MODE COMm[:] [BAUD=b] [PARITY=p] [DATA=d] [STOP=s]
+ [to=on|off] [xon=on|off] [odsr=on|off]
+ [octs=on|off] [dtr=on|off|hs]
+ [rts=on|off|hs|tg] [idsr=on|off]
+
+Device Status: MODE [device] [/STATUS]
+
+Redirect printing: MODE LPTn[:]=COMm[:]
+
+Select code page: MODE CON[:] CP SELECT=yyy
+
+Code page status: MODE CON[:] CP [/STATUS]
+
+Display mode: MODE CON[:] [COLS=c] [LINES=n]
+
+Typematic rate: MODE CON[:] [RATE=r DELAY=d]
+.
+
+MessageId=23053 SymbolicName=MODE_MESSAGE_STATUS
+Language=English
+Status for device *:%0
+.
+
+MessageId=23055 SymbolicName=MODE_MESSAGE_STATUS_BAUD
+Language=English
+ Baud: %1
+.
+
+MessageId=23056 SymbolicName=MODE_MESSAGE_STATUS_PARITY
+Language=English
+ Parity: %1
+.
+
+MessageId=23057 SymbolicName=MODE_MESSAGE_STATUS_DATA
+Language=English
+ Data Bits: %1
+.
+
+MessageId=23058 SymbolicName=MODE_MESSAGE_STATUS_STOP
+Language=English
+ Stop Bits: %1
+.
+
+MessageId=23059 SymbolicName=MODE_MESSAGE_STATUS_TIMEOUT
+Language=English
+ Timeout: %1
+.
+
+MessageId=23060 SymbolicName=MODE_MESSAGE_STATUS_XON
+Language=English
+ XON/XOFF: %1
+.
+
+MessageId=23061 SymbolicName=MODE_MESSAGE_STATUS_OCTS
+Language=English
+ CTS handshaking: %1
+.
+
+MessageId=23062 SymbolicName=MODE_MESSAGE_STATUS_ODSR
+Language=English
+ DSR handshaking: %1
+.
+
+MessageId=23063 SymbolicName=MODE_MESSAGE_STATUS_IDSR
+Language=English
+ DSR sensitivity: %1
+.
+
+MessageId=23064 SymbolicName=MODE_MESSAGE_STATUS_DTR
+Language=English
+ DTR circuit: %1
+.
+
+MessageId=23065 SymbolicName=MODE_MESSAGE_STATUS_RTS
+Language=English
+ RTS circuit: %1
+.
+
+MessageId=23070 SymbolicName=MODE_MESSAGE_STATUS_LINES
+Language=English
+ Lines: %1
+.
+
+MessageId=23071 SymbolicName=MODE_MESSAGE_STATUS_COLS
+Language=English
+ Columns: %1
+.
+MessageId=23072 SymbolicName=MODE_MESSAGE_STATUS_CODEPAGE
+Language=English
+ Code page: %1
+.
+
+MessageId=23073 SymbolicName=MODE_MESSAGE_STATUS_REROUTED
+Language=English
+ Printer output is being rerouted to serial port %1
+.
+
+MessageId=23074 SymbolicName=MODE_MESSAGE_STATUS_NOT_REROUTED
+Language=English
+ Printer output is not being rerouted.
+.
+
+MessageId=23075 SymbolicName=MODE_MESSAGE_STATUS_RATE
+Language=English
+ Keyboard rate: %1
+.
+
+MessageId=23076 SymbolicName=MODE_MESSAGE_STATUS_DELAY
+Language=English
+ Keyboard delay: %1
+.
+
+MessageId=23079 SymbolicName=MODE_MESSAGE_LPT_USE_CONTROL_PANEL
+Language=English
+To change printer settings use the Printers option in Control Panel
+.
+
+MessageId=23080 SymbolicName=MODE_ERROR_INCORRECT_OS_VERSION
+Language=English
+Incorrect operating system version
+.
+
+MessageId=23081 SymbolicName=MODE_ERROR_INVALID_DEVICE_NAME
+Language=English
+Illegal device name - %1
+.
+
+MessageId=23082 SymbolicName=MODE_ERROR_INVALID_BAUD_RATE
+Language=English
+Invalid baud rate specified
+.
+
+MessageId=23083 SymbolicName=MODE_ERROR_NOT_REROUTED
+Language=English
+%1: not rerouted
+.
+
+MessageId=23084 SymbolicName=MODE_ERROR_INVALID_PARAMETER
+Language=English
+Invalid parameter - %1
+.
+
+MessageId=23085 SymbolicName=MODE_ERROR_INVALID_NUMBER_OF_PARAMETERS
+Language=English
+Invalid number of parameters
+.
+
+MessageId=23086 SymbolicName=MODE_ERROR_CANNOT_ACCESS_DEVICE
+Language=English
+Failure to access device: %1
+.
+
+MessageId=23087 SymbolicName=MODE_ERROR_CODEPAGE_OPERATION_NOT_SUPPORTED
+Language=English
+Code page operation not supported on this device
+.
+
+MessageId=23088 SymbolicName=MODE_ERROR_CODEPAGE_NOT_SUPPORTED
+Language=English
+Current keyboard does not support this code page
+.
+
+MessageId=23089 SymbolicName=MODE_ERROR_NO_MEMORY
+Language=English
+Out of memory
+.
+
+MessageId=23090 SymbolicName=MODE_ERROR_PARSE
+Language=English
+Parse Error
+.
+
+MessageId=23091 SymbolicName=MODE_ERROR_EXTENDED
+Language=English
+Extended error %1
+.
+
+MessageId=23092 SymbolicName=MODE_ERROR_SERIAL_OPTIONS_NOT_SUPPORTED
+Language=English
+The specified options are not supported by this serial device
+.
+
+MessageId=23093 SymbolicName=MODE_ERROR_INVALID_SCREEN_SIZE
+Language=English
+The screen cannot be set to the number of lines and columns specified.
+.
+
+MessageId=23094 SymbolicName=MODE_ERROR_LPT_CANNOT_SET
+Language=English
+The device cannot be set to the specified number of lines and/or columns.
+.
+
+MessageId=23095 SymbolicName=MODE_ERROR_LPT_CANNOT_ENDREROUTE
+Language=English
+Cannot stop printer rerouting at this time.
+.
+
+MessageId=23096 SymbolicName=MODE_ERROR_LPT_CANNOT_REROUTE
+Language=English
+Cannot reroute printer output to serial device %1.
+.
+
+MessageId=23097 SymbolicName=MODE_ERROR_INVALID_RATE
+Language=English
+Invalid keyboard rate
+.
+
+MessageId=23098 SymbolicName=MODE_ERROR_INVALID_DELAY
+Language=English
+Invalid keyboard delay
+.
+
+MessageId=23099 SymbolicName=MODE_ERROR_FULL_SCREEN
+Language=English
+The number of lines and columns cannot be changed in a full screen.
+.
+
+MessageId=23100 SymbolicName=MODE_ERROR_INVALID_CODEPAGE
+Language=English
+The code page specified is not valid.
+.
+
+MessageId=23101 SymbolicName=MODE_ERROR_NOT_SUPPORTED
+Language=English
+The specified option is not supported.
+.
+
+MessageId=23110 SymbolicName=MODE_MESSAGE_USED_DEFAULT_PARITY
+Language=English
+Default to even parity.
+.
+
+MessageId=23111 SymbolicName=MODE_MESSAGE_USED_DEFAULT_DATA
+Language=English
+Default to %1 data bits.
+.
+
+MessageId=23112 SymbolicName=MODE_MESSAGE_USED_DEFAULT_STOP
+Language=English
+Default to %1 stop bits.
+.
+
+MessageId=23113 SymbolicName=MODE_MESSAGE_COM_NO_CHANGE
+Language=English
+No serial port setting changed.
+.
+
+MessageId=23114 SymbolicName=MODE_MESSAGE_NOT_NEEDED
+Language=English
+This operation is not necessary under Windows NT.
+.
+
+MessageId=23115 SymbolicName=MODE_ERROR_DEVICE_UNAVAILABLE
+Language=English
+Device %1 is not currently available.
+.
+
+
+
+
+
+
+
+
+
+
+
+;//---------------
+;//
+;// NTFS messages.
+;//
+;//---------------
+
+MessageId=24000 SymbolicName=MSG_NTFS_UNREADABLE_BOOT_SECTOR
+Language=English
+The first NTFS boot sector is unreadable.
+Reading second NTFS boot sector instead.
+.
+
+MessageId=24001 SymbolicName=MSG_NTFS_ALL_BOOT_SECTORS_UNREADABLE
+Language=English
+All NTFS boot sectors are unreadable. Cannot continue.
+.
+
+MessageId=24002 SymbolicName=MSG_NTFS_SECOND_BOOT_SECTOR_UNWRITEABLE
+Language=English
+The second NTFS boot sector is unwriteable.
+.
+
+MessageId=24003 SymbolicName=MSG_NTFS_FIRST_BOOT_SECTOR_UNWRITEABLE
+Language=English
+The first NTFS boot sector is unwriteable.
+.
+
+MessageId=24004 SymbolicName=MSG_NTFS_ALL_BOOT_SECTORS_UNWRITEABLE
+Language=English
+All NTFS boot sectors are unwriteable. Cannot continue.
+.
+
+MessageId=24005 SymbolicName=MSG_NTFS_FORMAT_NO_FLOPPIES
+Language=English
+The NTFS file system does not function on floppy disks.
+.
+
+
+;//----------------------
+;//
+;// NTFS CHKDSK messages.
+;//
+;//----------------------
+
+MessageId=26000 SymbolicName=MSG_CHK_NTFS_BAD_FRS
+Language=English
+Deleting corrupt file record segment %1.
+.
+
+MessageId=26001 SymbolicName=MSG_CHK_NTFS_BAD_ATTR
+Language=English
+Deleting corrupt attribute record (%1, %2)
+from file record segment %3.
+.
+
+MessageId=26002 SymbolicName=MSG_CHK_NTFS_FRS_TRUNC_RECORDS
+Language=English
+Truncating badly linked attribute records
+from file record segment %1.
+.
+
+MessageId=26003 SymbolicName=MSG_CHK_NTFS_UNSORTED_FRS
+Language=English
+Sorting attribute records for file record segment %1.
+.
+
+MessageId=26004 SymbolicName=MSG_CHK_NTFS_DUPLICATE_ATTRIBUTES
+Language=English
+Deleting duplicate attribute records (%1, %2)
+from file record segment %3.
+.
+
+MessageId=26005 SymbolicName=MSG_CHK_NTFS_BAD_ATTR_LIST
+Language=English
+Deleted corrupt attribute list for file %1.
+.
+
+MessageId=26006 SymbolicName=MSG_CHK_NTFS_CANT_READ_ATTR_LIST
+Language=English
+Deleted unreadable attribute list for file %1.
+.
+
+MessageId=26007 SymbolicName=MSG_CHK_NTFS_BAD_ATTR_LIST_ENTRY
+Language=English
+Deleted corrupt attribute list entry
+with type code %1 in file %2.
+.
+
+MessageId=26008 SymbolicName=MSG_CHK_NTFS_ATTR_LIST_TRUNC
+Language=English
+Truncating corrupt attribute list for file %1.
+.
+
+MessageId=26009 SymbolicName=MSG_CHK_NTFS_UNSORTED_ATTR_LIST
+Language=English
+Sorting attribute list for file %1.
+.
+
+MessageId=26010 SymbolicName=MSG_CHK_NTFS_UNREADABLE_MFT
+Language=English
+Unreadable master file table. CHKDSK aborted.
+.
+
+MessageId=26011 SymbolicName=MSG_CHK_NTFS_BAD_MFT
+Language=English
+Corrupt master file table. CHKDSK aborted.
+.
+
+MessageId=26012 SymbolicName=MSG_CHK_NTFS_BAD_ATTR_DEF_TABLE
+Language=English
+Corrupt Attribute Definition Table.
+CHKDSK is assuming the default.
+.
+
+MessageId=26013 SymbolicName=MSG_NTFS_CHK_NOT_NTFS
+Language=English
+This is not an NTFS volume.
+.
+
+MessageId=26014 SymbolicName=MSG_CHK_NTFS_UNREADABLE_FRS
+Language=English
+File record segment %1 is unreadable.
+.
+
+MessageId=26015 SymbolicName=MSG_CHK_NTFS_ORPHAN_FRS
+Language=English
+Deleting orphan file record segment %1.
+.
+
+MessageId=26016 SymbolicName=MSG_CHK_NTFS_CANT_HOTFIX_SYSTEM_FILES
+Language=English
+Insufficient disk space to hotfix unreadable system file %1.
+CHKDSK Aborted.
+.
+
+MessageId=26017 SymbolicName=MSG_CHK_NTFS_CANT_HOTFIX
+Language=English
+Insufficient disk space to hotfix unreadable user file %1.
+.
+
+MessageId=26018 SymbolicName=MSG_CHK_NTFS_BAD_FIRST_FREE
+Language=English
+First free byte offset corrected in file record segment %1.
+.
+
+MessageId=26019 SymbolicName=MSG_CHK_NTFS_CORRECTING_MFT_MIRROR
+Language=English
+Correcting errors in the Master File Table (MFT) mirror.
+.
+
+MessageId=26020 SymbolicName=MSG_CHK_NTFS_CANT_FIX_MFT_MIRROR
+Language=English
+Insufficient disk space to repair master file table (MFT) mirror.
+CHKDSK aborted.
+.
+
+MessageId=26021 SymbolicName=MSG_CHK_NTFS_CANT_ADD_BAD_CLUSTERS
+Language=English
+Insufficient disk space to record bad clusters.
+.
+
+MessageId=26022 SymbolicName=MSG_CHK_NTFS_CORRECTING_MFT_DATA
+Language=English
+Correcting errors in the master file table's (MFT) DATA attribute.
+.
+
+MessageId=26023 SymbolicName=MSG_CHK_NTFS_CANT_FIX_MFT
+Language=English
+Insufficient disk space to fix master file table (MFT). CHKDSK aborted.
+.
+
+MessageId=26024 SymbolicName=MSG_CHK_NTFS_CORRECTING_MFT_BITMAP
+Language=English
+Correcting errors in the master file table's (MFT) BITMAP attribute.
+.
+
+MessageId=26025 SymbolicName=MSG_CHK_NTFS_CANT_FIX_VOLUME_BITMAP
+Language=English
+Insufficient disk space to fix volume bitmap. CHKDSK aborted.
+.
+
+MessageId=26026 SymbolicName=MSG_CHK_NTFS_CORRECTING_VOLUME_BITMAP
+Language=English
+Correcting errors in the Volume Bitmap.
+.
+
+MessageId=26027 SymbolicName=MSG_CHK_NTFS_CORRECTING_ATTR_DEF
+Language=English
+Correcting errors in the Attribute Definition Table.
+.
+
+MessageId=26028 SymbolicName=MSG_CHK_NTFS_CANT_FIX_ATTR_DEF
+Language=English
+Insufficient disk space to fix the attribute definition table.
+CHKDSK aborted.
+.
+
+MessageId=26029 SymbolicName=MSG_CHK_NTFS_CORRECTING_BAD_FILE
+Language=English
+Correcting errors in the Bad Clusters File.
+.
+
+MessageId=26030 SymbolicName=MSG_CHK_NTFS_CANT_FIX_BAD_FILE
+Language=English
+Insufficient disk space to fix the bad clusters file.
+CHKDSK aborted.
+.
+
+MessageId=26031 SymbolicName=MSG_CHK_NTFS_CORRECTING_BOOT_FILE
+Language=English
+Correcting errors in the Boot File.
+.
+
+MessageId=26032 SymbolicName=MSG_CHK_NTFS_CANT_FIX_BOOT_FILE
+Language=English
+Insufficient disk space to fix the boot file.
+CHKDSK aborted.
+.
+
+MessageId=26033 SymbolicName=MSG_CHK_NTFS_ADDING_BAD_CLUSTERS
+Language=English
+Adding %1 bad clusters to the Bad Clusters File.
+.
+
+MessageId=26034 SymbolicName=MSG_CHK_NTFS_TOTAL_DISK_SPACE
+Language=English
+
+%1 kilobytes total disk space.
+.
+
+MessageId=26035 SymbolicName=MSG_CHK_NTFS_USER_FILES
+Language=English
+%1 kilobytes in %2 user files.
+.
+
+MessageId=26036 SymbolicName=MSG_CHK_NTFS_INDICES_REPORT
+Language=English
+%1 kilobytes in %2 indexes.
+.
+
+MessageId=26037 SymbolicName=MSG_CHK_NTFS_BAD_SECTORS_REPORT
+Language=English
+%1 kilobytes in bad sectors.
+.
+
+MessageId=26038 SymbolicName=MSG_CHK_NTFS_SYSTEM_SPACE
+Language=English
+%1 kilobytes in use by the system.
+.
+
+MessageId=26039 SymbolicName=MSG_CHK_NTFS_AVAILABLE_SPACE
+Language=English
+%1 kilobytes available on disk.
+
+.
+
+MessageId=26040 SymbolicName=MSG_CHK_NTFS_ERROR_IN_INDEX
+Language=English
+Correcting error in index %2 for file %1.
+.
+
+MessageId=26041 SymbolicName=MSG_CHK_NTFS_CANT_FIX_INDEX
+Language=English
+Insufficient disk space to correct errors
+in index %2 of file %1.
+.
+
+MessageId=26042 SymbolicName=MSG_CHK_NTFS_BAD_INDEX
+Language=English
+Removing corrupt index %2 in file %1.
+.
+
+MessageId=26043 SymbolicName=MSG_CHK_NTFS_DELETING_DIRECTORY_ENTRIES
+Language=English
+Deleting directory entries in %1
+.
+
+MessageId=26044 SymbolicName=MSG_CHK_NTFS_CANT_DELETE_ALL_DIRECTORY_ENTRIES
+Language=English
+CHKDSK cannot delete all corrupt directory entries.
+.
+
+MessageId=26045 SymbolicName=MSG_CHK_NTFS_RECOVERING_ORPHANS
+Language=English
+CHKDSK is recovering lost files.
+.
+
+MessageId=26046 SymbolicName=MSG_CHK_NTFS_CANT_CREATE_ORPHANS
+Language=English
+Insufficient disk space for CHKDSK to recover lost files.
+.
+
+MessageId=26047 SymbolicName=MSG_CHK_NTFS_CORRECTING_ERROR_IN_DIRECTORY
+Language=English
+Correcting error in directory %1
+.
+
+MessageId=26048 SymbolicName=MSG_CHK_NTFS_BADLY_ORDERED_INDEX
+Language=English
+Sorting index %2 in file %1.
+.
+
+MessageId=26049 SymbolicName=MSG_CHK_NTFS_CORRECTING_EA
+Language=English
+Correcting extended attribute information in file %1.
+.
+
+MessageId=26050 SymbolicName=MSG_CHK_NTFS_DELETING_CORRUPT_EA_SET
+Language=English
+Deleting corrupt extended attribute set in file %1.
+.
+
+MessageId=26051 SymbolicName=MSG_CHK_NTFS_INACCURATE_DUPLICATED_INFORMATION
+Language=English
+Incorrect duplicate information in file %1.
+.
+
+MessageId=26052 SymbolicName=MSG_CHK_NTFS_CREATING_ROOT_DIRECTORY
+Language=English
+CHKDSK is creating new root directory.
+.
+
+MessageId=26053 SymbolicName=MSG_CHK_NTFS_CANT_CREATE_ROOT_DIRECTORY
+Language=English
+Insufficient disk space to create new root directory.
+.
+
+MessageId=26054 SymbolicName=MSG_CHK_NTFS_RECOVERING_ORPHAN
+Language=English
+Recovering orphaned file %1 into directory file %2.
+.
+
+MessageId=26055 SymbolicName=MSG_CHK_NTFS_CANT_RECOVER_ORPHAN
+Language=English
+Insufficient disk space to recover lost data.
+.
+
+MessageId=26056 SymbolicName=MSG_CHK_NTFS_TOO_MANY_ORPHANS
+Language=English
+Too much lost data to recover it all.
+.
+
+MessageId=26057 SymbolicName=MSG_CHK_NTFS_USING_MFT_MIRROR
+Language=English
+Fixing critical master file table (MFT) files with MFT mirror.
+.
+
+MessageId=26058 SymbolicName=MSG_CHK_NTFS_MINOR_CHANGES_TO_FRS
+Language=English
+Correcting a minor error in file %1.
+.
+
+MessageId=26059 SymbolicName=MSG_CHK_NTFS_BAD_UPCASE_TABLE
+Language=English
+Corrupt uppercase Table.
+Using current system uppercase Table.
+.
+
+MessageId=26060 SymbolicName=MSG_CHK_NTFS_CANT_GET_UPCASE_TABLE
+Language=English
+Cannot retrieve current system uppercase table.
+CHKDSK aborted.
+.
+
+MessageId=26061 SymbolicName=MSG_CHK_NTFS_MINOR_MFT_BITMAP_ERROR
+Language=English
+CHKDSK discovered free space marked as allocated in the
+master file table (MFT) bitmap.
+.
+
+MessageId=26062 SymbolicName=MSG_CHK_NTFS_MINOR_VOLUME_BITMAP_ERROR
+Language=English
+CHKDSK discovered free space marked as allocated in the volume bitmap.
+.
+
+MessageId=26063 SymbolicName=MSG_CHK_NTFS_CORRECTING_UPCASE_FILE
+Language=English
+Correcting errors in the uppercase file.
+.
+
+MessageId=26064 SymbolicName=MSG_CHK_NTFS_CANT_FIX_UPCASE_FILE
+Language=English
+Insufficient disk space to fix the uppercase file.
+CHKDSK aborted.
+.
+
+MessageId=26065 SymbolicName=MSG_CHK_NTFS_DELETING_INDEX_ENTRY
+Language=English
+Deleting index entry %3 in index %2 of file %1.
+.
+
+MessageId=26066 SymbolicName=MSG_CHK_NTFS_SLASH_V_NOT_SUPPORTED
+Language=English
+Verbose output not supported by NTFS CHKDSK.
+.
+
+MessageId=26067 SymbolicName=MSG_CHK_NTFS_READ_ONLY_MODE
+Language=English
+Warning! F parameter not specified
+Running CHKDSK in read-only mode.
+.
+
+MessageId=26068 SymbolicName=MSG_CHK_NTFS_ERRORS_FOUND
+Language=English
+
+Errors found. CHKDSK cannot continue in read-only mode.
+.
+
+MessageId=26069 SymbolicName=MSG_CHK_NTFS_CYCLES_IN_DIR_TREE
+Language=English
+Correcting cycles in directory tree.
+.
+
+MessageId=26070 SymbolicName=MSG_CHK_NTFS_MINOR_FILE_NAME_ERRORS
+Language=English
+Correcting minor file name errors in file %1.
+.
+
+MessageId=26071 SymbolicName=MSG_CHK_NTFS_MISSING_DATA_ATTRIBUTE
+Language=English
+Inserting data attribute into file %1.
+.
+
+MessageId=26072 SymbolicName=MSG_CHK_NTFS_CANT_PUT_DATA_ATTRIBUTE
+Language=English
+Insufficient disk space to insert missing data attribute.
+.
+
+MessageId=26073 SymbolicName=MSG_CHK_NTFS_CORRECTING_LOG_FILE
+Language=English
+Correcting errors in the Log File.
+.
+
+MessageId=26074 SymbolicName=MSG_CHK_NTFS_CANT_FIX_LOG_FILE
+Language=English
+Insufficient disk space to fix the log file.
+CHKDSK aborted.
+.
+
+MessageId=26075 SymbolicName=MSG_CHK_NTFS_CHECKING_FILES
+Language=English
+
+CHKDSK is verifying files...
+.
+
+MessageId=26076 SymbolicName=MSG_CHK_NTFS_CHECKING_INDICES
+Language=English
+CHKDSK is verifying indexes...
+.
+
+MessageId=26077 SymbolicName=MSG_CHK_NTFS_INDEX_VERIFICATION_COMPLETED
+Language=English
+Index verification completed.
+.
+
+MessageId=26078 SymbolicName=MSG_CHK_NTFS_FILE_VERIFICATION_COMPLETED
+Language=English
+File verification completed.
+.
+
+MessageId=26079 SymbolicName=MSG_CHK_NTFS_CHECKING_SECURITY
+Language=English
+CHKDSK is verifying security descriptors...
+.
+
+MessageId=26080 SymbolicName=MSG_CHK_NTFS_SECURITY_VERIFICATION_COMPLETED
+Language=English
+Security descriptor verification completed.
+.
+
+MessageId=26081 SymbolicName=MSG_CHK_NTFS_INVALID_SECURITY_DESCRIPTOR
+Language=English
+Replacing missing or invalid security descriptor for file %1.
+.
+
+MessageId=26082 SymbolicName=MSG_CHK_NTFS_CANT_FIX_SECURITY
+Language=English
+Insufficient disk space for security descriptor for file %1.
+.
+
+MessageId=26083 SymbolicName=MSG_CHK_NTFS_WRONG_VERSION
+Language=English
+This volume cannot be checked with this version of UNTFS.DLL.
+.
+
+MessageId=26084 SymbolicName=MSG_CHK_NTFS_DELETING_GENERIC_INDEX_ENTRY
+Language=English
+Deleting an index entry from index %2 of file %1.
+.
+
+MessageId=26085 SymbolicName=MSG_CHK_NTFS_CORRECTING_CROSS_LINK
+Language=English
+Correcting cross-link for file %1.
+.
+
+MessageId=26086 SymbolicName=MSG_CHK_NTFS_VERIFYING_FILE_DATA
+Language=English
+CHKDSK is verifying file data...
+.
+
+MessageId=26087 SymbolicName=MSG_CHK_NTFS_VERIFYING_FILE_DATA_COMPLETED
+Language=English
+File data verification completed.
+.
+
+MessageId=26088 SymbolicName=MSG_CHK_NTFS_TOO_MANY_FILE_NAMES
+Language=English
+Index entries referencing file %1 will not be validated
+because this file contains too many file names.
+.
+
+MessageId=26089 SymbolicName=MSG_CHK_NTFS_RESETTING_LSNS
+Language=English
+CHKDSK is resetting recovery information...
+.
+
+MessageId=26090 SymbolicName=MSG_CHK_NTFS_RESETTING_LOG_FILE
+Language=English
+CHKDSK is resetting the log file.
+.
+
+MessageId=26091 SymbolicName=MSG_CHK_NTFS_RESIZING_LOG_FILE
+Language=English
+CHKDSK is adjusting the size of the log file.
+.
+
+MessageId=26092 SymbolicName=MSG_CHK_NTFS_RESIZING_LOG_FILE_FAILED
+Language=English
+CHKDSK was unable to adjust the size of the log file.
+.
+
+MessageId=26093 SymbolicName=MSG_CHK_NTFS_ADJUSTING_INSTANCE_TAGS
+Language=English
+Adjusting instance tags to prevent rollover on file %1.
+.
+
+MessageId=26094 SymbolicName=MSG_CHK_NTFS_FIX_ATTR
+Language=English
+Fixing corrupt attribute record (%1, %2)
+in file record segment %3.
+.
+
+MessageId=26095 SymbolicName=MSG_CHK_NTFS_LOGFILE_SPACE
+Language=English
+%1 kilobytes occupied by the logfile.
+.
+
+MessageId=26096 SymbolicName=MSG_CHK_READABLE_FRS_UNWRITEABLE
+Language=English
+Readable file record segment %1 is not writeable.
+.
+
+MessageId=26097 SymbolicName=MSG_CHK_NTFS_DEFAULT_QUOTA_ENTRY_MISSING
+Language=English
+Inserting default quota record into index %2 in file %1.
+.
+
+MessageId=26098 SymbolicName=MSG_CHK_NTFS_CREATING_DEFAULT_SECURITY_DESCRIPTOR
+Language=English
+Creating a default security descriptor.
+.
+
+MessageId=26099 SymbolicName=MSG_CHK_NTFS_CANNOT_SET_QUOTA_FLAG_OUT_OF_DATE
+Language=English
+Unable to set the quota out of date flag.
+.
+
+MessageId=26100 SymbolicName=MSG_CHK_NTFS_REPAIRING_INDEX_ENTRY
+Language=English
+Repairing an index entry in index %2 of file %1.
+.
+
+MessageId=26101 SymbolicName=MSG_CHK_NTFS_INSERTING_INDEX_ENTRY
+Language=English
+Inserting an index entry into index %2 of file %1.
+.
+
+MessageId=26102 SymbolicName=MSG_CHK_NTFS_CANT_FIX_SECURITY_DATA_STREAM
+Language=English
+Insufficient disk space to fix the security descriptors data stream.
+.
+
+MessageId=26103 SymbolicName=MSG_CHK_NTFS_CANT_FIX_ATTRIBUTE
+Language=English
+Unable to write to attribute %1 of file %2.
+.
+
+MessageId=26104 SymbolicName=MSG_CHK_NTFS_CANT_READ_SECURITY_DATA_STREAM
+Language=English
+Unable to read the security descriptors data stream.
+.
+
+MessageId=26105 SymbolicName=MSG_CHK_NTFS_FIXING_SECURITY_DATA_STREAM_MIRROR
+Language=English
+Fixing mirror copy of the security descriptors data stream.
+.
+
+MessageId=26106 SymbolicName=MSG_CHK_NTFS_FIXING_COLLATION_RULE
+Language=English
+Fixing collation rule value for index %1 of file %2.
+.
+
+MessageId=26107 SymbolicName=MSG_CHK_NTFS_CREATE_INDEX
+Language=English
+Creating index %1 for file %2.
+.
+
+MessageId=26108 SymbolicName=MSG_CHK_NTFS_REPAIRING_SECURITY_FRS
+Language=English
+Repairing the security file record segment.
+.
+
+MessageId=26109 SymbolicName=MSG_CHK_NTFS_REPAIRING_UNREADABLE_SECURITY_DATA_STREAM
+Language=English
+Repairing the unreadable security descriptors data stream.
+.
+
+MessageId=26110 SymbolicName=MSG_CHK_NTFS_CANT_FIX_OBJID
+Language=English
+Insufficient disk space to fix the object id file.
+.
+
+MessageId=26111 SymbolicName=MSG_CHK_NTFS_CANT_FIX_QUOTA
+Language=English
+Insufficient disk space to fix the quota file.
+.
+
+MessageId=26112 SymbolicName=MSG_CHK_NTFS_CREATE_OBJID
+Language=English
+Creating object id file.
+.
+
+MessageId=26113 SymbolicName=MSG_CHK_NTFS_CREATE_QUOTA
+Language=English
+Creating quota file.
+.
+
+MessageId=26114 SymbolicName=MSG_CHK_NTFS_FIX_FLAGS
+Language=English
+Fixing flags for file record segment %1.
+.
+
+MessageId=26115 SymbolicName=MSG_CHK_NTFS_CANT_FIX_SYSTEM_FILE
+Language=English
+Unable to correct an error in system file %1.
+.
+
+MessageId=26116 SymbolicName=MSG_CHK_NTFS_CANT_CREATE_INDEX
+Language=English
+Unable to create index %1 for file %2.
+.
+
+MessageId=26117 SymbolicName=MSG_CHK_NTFS_INVALID_SECURITY_ID
+Language=English
+Replacing invalid security id with default security id for file %1.
+.
+
+MessageId=26118 SymbolicName=MSG_CHK_NTFS_MULTIPLE_QUOTA_FILE
+Language=English
+Multiple quota file found. Ignoring extra quota files.
+.
+
+MessageId=26119 SymbolicName=MSG_CHK_NTFS_MULTIPLE_OBJECTID_FILE
+Language=English
+Multiple Object ID file found. Ignoring extra object id files.
+.
+
+MessageId=26120 SymbolicName=MSG_CHK_NTFS_TOO_BIG_LOGFILE_SIZE
+Language=English
+The size specified for the logfile is too big.
+.
+
+;//---------------
+;//
+;// Common messages.
+;//
+;//---------------
+
+MessageId=30000 SymbolicName=MSG_UTILS_HELP
+Language=English
+There is no help for this utility.
+.
+
+MessageId=30001 SymbolicName=MSG_UTILS_ERROR_FATAL
+Language=English
+Critical error encountered.
+.
+
+MessageId=30002 SymbolicName=MSG_UTILS_ERROR_INVALID_VERSION
+Language=English
+Incorrect Windows NT version
+.
+
+;//----------------------
+;//
+;// Convert messages.
+;//
+;//----------------------
+
+MessageId=30100 SymbolicName=MSG_CONV_USAGE
+Language=English
+Converts FAT volumes to NTFS.
+
+CONVERT drive: /FS:NTFS [/V]
+
+ drive Specifies the drive to convert to NTFS. Note that
+ you cannot convert the current drive.
+ /FS:NTFS Specifies to convert the volume to NTFS.
+ /V Specifies that Convert should be run in verbose mode.
+.
+
+MessageId=30101 SymbolicName=MSG_CONV_INVALID_PARAMETER
+Language=English
+Invalid Parameter - %1
+.
+
+MessageId=30102 SymbolicName=MSG_CONV_NO_FILESYSTEM_SPECIFIED
+Language=English
+Must specify a file system
+.
+
+MessageId=30103 SymbolicName=MSG_CONV_INVALID_DRIVE
+Language=English
+Invalid drive - %1
+.
+
+MessageId=30104 SymbolicName=MSG_CONV_CANT_NETWORK
+Language=English
+Cannot CONVERT a network drive.
+.
+
+MessageId=30105 SymbolicName=MSG_CONV_INVALID_FILESYSTEM
+Language=English
+%1 is not a valid file system
+.
+
+MessageId=30106 SymbolicName=MSG_CONV_CONVERSION_NOT_AVAILABLE
+Language=English
+Cannot convert %1 volumes to %2.
+.
+
+MessageId=30107 SymbolicName=MSG_CONV_WILL_CONVERT_ON_REBOOT
+Language=English
+The conversion will take place automatically the next time the
+system restarts.
+.
+
+MessageId=30108 SymbolicName=MSG_CONV_CANNOT_FIND_SYSTEM_DIR
+Language=English
+Cannot determine location of system directory.
+.
+
+MessageId=30109 SymbolicName=MSG_CONV_CANNOT_FIND_FILE
+Language=English
+Could not find file %1
+Make sure that the required file exists and try again.
+.
+
+MessageId=30110 SymbolicName=MSG_CONV_CANNOT_SCHEDULE
+Language=English
+Could not schedule an automatic conversion of the drive.
+.
+
+MessageId=30111 SymbolicName=MSG_CONV_ALREADY_SCHEDULED
+Language=English
+The %1 drive is already scheduled for an automatic
+conversion.
+.
+
+MessageId=30112 SymbolicName=MSG_CONV_CONVERTING
+Language=English
+Converting drive %1 to %2
+.
+
+MessageId=30113 SymbolicName=MSG_CONV_ALREADY_CONVERTED
+Language=English
+Drive %1 is already %2.
+.
+
+MessageId=30114 SymbolicName=MSG_CONV_CANNOT_AUTOCHK
+Language=English
+Could not check volume %1 for errors.
+The conversion to %2 did not take place.
+.
+
+MessageId=30115 SymbolicName=MSG_CONV_SLASH_C_INVALID
+Language=English
+The /C option is only valid with the /UNCOMPRESS option.
+.
+
+MessageId=30120 SymbolicName=MSG_CONV_CHECKING_SPACE
+Language=English
+Determining disk space required for filesystem conversion
+.
+
+MessageId=30121 SymbolicName=MSG_CONV_KBYTES_TOTAL
+Language=English
+Total disk space: %1 kilobytes.
+.
+
+MessageId=30122 SymbolicName=MSG_CONV_KBYTES_FREE
+Language=English
+Free space on volume: %1 kilobytes.
+.
+
+MessageId=30123 SymbolicName=MSG_CONV_KBYTES_NEEDED
+Language=English
+Space required for conversion: %1 kilobytes.
+.
+
+MessageId=30124 SymbolicName=MSG_CONV_CONVERTING_FS
+Language=English
+Converting file system
+.
+
+MessageId=30125 SymbolicName=MSG_CONV_PERCENT_COMPLETE
+Language=English
+%1 percent completed. %r%0
+.
+
+MessageId=30126 SymbolicName=MSG_CONV_CONVERSION_COMPLETE
+Language=English
+Conversion complete
+.
+
+MessageId=30127 SymbolicName=MSG_CONV_CONVERSION_FAILED
+Language=English
+The conversion failed.
+%1 was not converted to %2
+.
+
+MessageId=30150 SymbolicName=MSG_CONV_CANNOT_READ
+Language=English
+Error during disk read
+.
+
+MessageId=30151 SymbolicName=MSG_CONV_CANNOT_WRITE
+Language=English
+Error during disk write
+.
+
+MessageId=30152 SymbolicName=MSG_CONV_NO_MEMORY
+Language=English
+Insufficient Memory
+.
+
+MessageId=30153 SymbolicName=MSG_CONV_NO_DISK_SPACE
+Language=English
+Insufficient disk space for conversion
+.
+
+MessageId=30154 SymbolicName=MSG_CONV_CANNOT_RELOCATE
+Language=English
+Cannot relocate existing file system structures
+.
+
+MessageId=30155 SymbolicName=MSG_CONV_CANNOT_CREATE_ELEMENTARY
+Language=English
+Cannot create the elementary file system structures.
+.
+
+MessageId=30156 SymbolicName=MSG_CONV_ERROR_READING_DIRECTORY
+Language=English
+Error reading directory %1
+.
+
+MessageId=30157 SymbolicName=MSG_CONV_CANNOT_CONVERT_DIRECTORY
+Language=English
+Error converting directory %1
+.
+
+MessageId=30158 SymbolicName=MSG_CONV_CANNOT_CONVERT_FILE
+Language=English
+Error converting file %1
+.
+
+MessageId=30159 SymbolicName=MSG_CONV_CANNOT_CONVERT_DATA
+Language=English
+Error converting file data
+.
+
+MessageId=30160 SymbolicName=MSG_CONV_CANNOT_CONVERT_EA
+Language=English
+Cannot convert an extended attribute
+.
+
+MessageId=30161 SymbolicName=MSG_CONV_NO_EA_FILE
+Language=English
+A file contains extended attributes,
+but the extended attribute file was not found.
+.
+
+MessageId=30162 SymbolicName=MSG_CONV_CANNOT_MAKE_INDEX
+Language=English
+Cannot locate or create an NTFS index.
+.
+
+MessageId=30163 SymbolicName=MSG_CONV_CANNOT_CONVERT_VOLUME
+Language=English
+This volume cannot be converted to %1.
+Possible causes are:
+ 1.- Bad sectors in required areas of the volume.
+ 2.- %2 structures in areas required by %1.
+.
+
+MessageId=30164 SymbolicName=MSG_CONVERT_ON_REBOOT_PROMPT
+Language=English
+Convert cannot gain exclusive access to the %1 drive,
+so it cannot convert it now. Would you like to
+schedule it to be converted the next time the
+system restarts (Y/N)? %0
+.
+
+MessageId=30165 SymbolicName=MSG_CONVERT_FILE_SYSTEM_NOT_ENABLED
+Language=English
+The %1 file system is not enabled. The volume
+will not be converted.
+.
+
+MessageId=30166 SymbolicName=MSG_CONVERT_UNSUPPORTED_SECTOR_SIZE
+Language=English
+Unsupported sector size. Cannot convert volume to %1.
+.
+
+MessageId=30167 SymbolicName=MSG_CONVERT_REBOOT
+Language=English
+
+The file system has been converted.
+Please wait while the system restarts.
+.
+
+MessageId=30168 SymbolicName=MSG_CONV_ARC_SYSTEM_PARTITION
+Language=English
+The specified drive is the system partition on an ARC-compliant
+system; its file system cannot be converted
+.
+
+MessageId=30169 SymbolicName=MSG_CONV_GEOMETRY_MISMATCH
+Language=English
+The disk geometry recorded in the volume's Bios Parameter
+Block differs from the geometry reported by the driver.
+This volume cannot be converted to %1.
+.
+
+MessageId=30170 SymbolicName=MSG_CONV_NAME_TABLE_NOT_SUPPORTED
+Language=English
+Name table translation is not available for conversion to %1.
+.
+
+MessageId=30185 SymbolicName=MSG_CONV_VOLUME_TOO_FRAGMENTED
+Language=English
+The volume is too fragmented to be converted to NTFS.
+.
+
+;//----------------------
+;//
+;// Dblspace-specific Convert messages (cudbfs)
+;//
+;//----------------------
+
+MessageId=30190 SymbolicName=MSG_DBLCONV_CANT_CREATE
+Language=English
+Cannot create the file %1
+.
+
+MessageId=30191 SymbolicName=MSG_DBLCONV_CVF_CORRUPT
+Language=English
+The Compressed Volume File is corrupt -- run SCANDISK
+.
+
+MessageId=30192 SymbolicName=MSG_DBLCONV_CREATE_FILE
+Language=English
+Creating %1
+.
+
+MessageId=30193 SymbolicName=MSG_DBLCONV_FILE_CONFLICT
+Language=English
+A file in the Compressed Volume File would conflict with %1
+.
+
+MessageId=30194 SymbolicName=MSG_DBLCONV_NOT_ENOUGH_SPACE
+Language=English
+Not enough free space on host; need %1 clusters, have %2
+.
+
+MessageId=30195 SymbolicName=MSG_DBLCONV_AGAIN
+Language=English
+After the machine is rebooted, run CONVERT /UNCOMPRESS again.
+.
+
+MessageId=30196 SymbolicName=MSG_DBLCONV_SPACE_EXHAUSTED
+Language=English
+All disk space on the host volume has been exhausted. Please delete
+files from the host volume and run CONVERT /UNCOMPRESS again.
+.
+
+
+;//----------------------
+;//
+;// DC messages.
+;//
+;//----------------------
+
+MessageId=30200 SymbolicName=MSG_DISKCOPY_USAGE
+Language=English
+Usage: DC Src Dst [/v] [/h]
+.
+
+MessageId=30201 SymbolicName=MSG_DISKCOPY_NO_MEMORY
+Language=English
+Out of memory
+.
+
+MessageId=30202 SymbolicName=MSG_DISKCOPY_INVALID_PARAMETER
+Language=English
+Invalid parameter - %1
+.
+
+
+
+
+;//----------------------
+;//
+;// KEYB messages.
+;//
+;//----------------------
+
+MessageId=30300 SymbolicName=MSG_KEYB_EXTENDED_ERROR
+Language=English
+Extended Error %1
+.
+
+MessageId=30301 SymbolicName=MSG_KEYB_TOO_MANY_PARAMETERS
+Language=English
+Too many parameters
+.
+
+MessageId=30302 SymbolicName=MSG_KEYB_MISSING_PARAMETER
+Language=English
+Required parameter missing
+.
+
+MessageId=30303 SymbolicName=MSG_KEYB_INVALID_SWITCH
+Language=English
+Invalid switch
+.
+
+MessageId=30305 SymbolicName=MSG_KEYB_VALUE_OUT_OF_RANGE
+Language=English
+Parameter value not in allowed range
+.
+
+MessageId=30307 SymbolicName=MSG_KEYB_INVALID_PARAMETER
+Language=English
+Invalid parameter
+.
+
+MessageId=30308 SymbolicName=MSG_KEYB_PARSE_ERROR
+Language=English
+Parse Error %1
+.
+
+MessageId=30309 SymbolicName=MSG_KEYB_INCORRECT_VERSION
+Language=English
+Incorrect Windows NT version
+.
+
+MessageId=30310 SymbolicName=MSG_KEYB_KEYBOARD_CODE
+Language=English
+Current keyboard code: %1
+.
+
+MessageId=30311 SymbolicName=MSG_KEYB_KEYBOARD_LAYOUT
+Language=English
+There is no two-letter keyboard code for the current
+keyboard layout.
+
+Current keyboard Layout: Language %1 Sublanguage %2
+.
+
+MessageId=30312 SymbolicName=MSG_KEYB_KEYBOARD_ID
+Language=English
+Current keyboard ID: %1
+.
+
+MessageId=30313 SymbolicName=MSG_KEYB_CODE_PAGE
+Language=English
+code page: %1
+.
+
+MessageId=30314 SymbolicName=MSG_KEYB_CON_CODE_PAGE
+Language=English
+Current CON code page: %1
+.
+
+MessageId=30315 SymbolicName=MSG_KEYB_INVALID_CODE
+Language=English
+Invalid keyboard code specified
+.
+
+MessageId=30316 SymbolicName=MSG_KEYB_INVALID_ID
+Language=English
+Invalid keyboard ID specified
+.
+
+MessageId=30317 SymbolicName=MSG_KEYB_INVALID_CODE_PAGE
+Language=English
+Invalid code page specified
+.
+MessageId=30318 SymbolicName=MSG_KEYB_BAD_REGISTRY
+Language=English
+Keyboard Layout information missing from Registry
+.
+
+MessageId=30327 SymbolicName=MSG_KEYB_USAGE
+Language=English
+Configures a keyboard for a specific language.
+
+KEYB [xx[,[yyy][,[drive:][path]filename]]] [/E] [/ID:nnn]
+
+ xx Specifies a two-letter keyboard code.
+ yyy Specifies a console code page.
+ [drive:][path]filename Ignored
+ /E Ignored
+ /ID:nnn Ignored
+
+.
+
+
+;//----------------------
+;//
+;// CHCP messages.
+;//
+;//----------------------
+
+MessageId=30350 SymbolicName=MSG_CHCP_INVALID_PARAMETER
+Language=English
+Parameter format not correct - %1
+.
+
+MessageId=30354 SymbolicName=MSG_CHCP_ACTIVE_CODEPAGE
+Language=English
+Active code page: %1
+.
+
+MessageId=30355 SymbolicName=MSG_CHCP_INVALID_CODEPAGE
+Language=English
+Invalid code page
+.
+
+MessageId=30356 SymbolicName=MSG_CHCP_USAGE
+Language=English
+Displays or sets the active code page number.
+
+CHCP [nnn]
+
+ nnn Specifies a code page number.
+
+Type CHCP without a parameter to display the active code page number.
+.
+
+MessageId=30357 SymbolicName=MSG_CHCP_INTERNAL_ERROR
+Language=English
+Internal error.
+.
+
+;//----------------
+;//
+;// DOSKEY messages
+;//
+;//----------------
+
+
+MessageId=30503 SymbolicName=MSG_DOSKEY_INVALID_MACRO_DEFINITION
+Language=English
+Invalid macro definition.
+.
+
+MessageId=30504 SymbolicName=MSG_DOSKEY_HELP
+Language=English
+Edits command lines, recalls Windows NT commands, and creates macros.
+
+DOSKEY [/REINSTALL] [/LISTSIZE=size] [/MACROS[:ALL | :exename]]
+ [/HISTORY] [/INSERT | /OVERSTRIKE] [/EXENAME=exename] [/MACROFILE=filename]
+ [macroname=[text]]
+
+ /REINSTALL Installs a new copy of Doskey.
+ /LISTSIZE=size Sets size of command history buffer.
+ /MACROS Displays all Doskey macros.
+ /MACROS:ALL Displays all Doskey macros for all executables which have
+ Doskey macros.
+ /MACROS:exename Displays all Doskey macros for the given executable.
+ /HISTORY Displays all commands stored in memory.
+ /INSERT Specifies that new text you type is inserted in old text.
+ /OVERSTRIKE Specifies that new text overwrites old text.
+ /EXENAME=exename Specifies the executable.
+ /MACROFILE=filename Specifies a file of macros to install.
+ macroname Specifies a name for a macro you create.
+ text Specifies commands you want to record.
+
+UP and DOWN ARROWS recall commands; ESC clears command line; F7 displays
+command history; ALT+F7 clears command history; F8 searches command
+history; F9 selects a command by number; ALT+F10 clears macro definitions.
+
+The following are some special codes in Doskey macro definitions:
+$T Command separator. Allows multiple commands in a macro.
+$1-$9 Batch parameters. Equivalent to %%1-%%9 in batch programs.
+$* Symbol replaced by everything following macro name on command line.
+.
+
+MessageId=30505 SymbolicName=MSG_DOSKEY_CANT_DO_BUFSIZE
+Language=English
+To specify the size of the command history buffer under Window NT,
+use the /listsize switch which sets the number of commands to remember.
+.
+
+MessageId=30506 SymbolicName=MSG_DOSKEY_CANT_SIZE_LIST
+Language=English
+Insufficient memory to grow DOSKEY list.
+.
+
+
+;//----------------
+;//
+;// SUBST messages
+;//
+;//----------------
+
+
+MessageId=30507 SymbolicName=MSG_SUBST_INFO
+Language=English
+Associates a path with a drive letter.
+
+.
+
+MessageId=30508 SymbolicName=MSG_SUBST_ALREADY_SUBSTED
+Language=English
+Drive already SUBSTed
+.
+
+MessageId=30509 SymbolicName=MSG_SUBST_USAGE
+Language=English
+SUBST [drive1: [drive2:]path]
+SUBST drive1: /D
+
+ drive1: Specifies a virtual drive to which you want to assign a path.
+ [drive2:]path Specifies a physical drive and path you want to assign to
+ a virtual drive.
+ /D Deletes a substituted (virtual) drive.
+
+Type SUBST with no parameters to display a list of current virtual drives.
+.
+
+MessageId=30510 SymbolicName=MSG_SUBST_SUBSTED_DRIVE
+Language=English
+%1: => %2
+.
+
+MessageId=30511 SymbolicName=MSG_SUBST_INVALID_PARAMETER
+Language=English
+Invalid parameter - %1
+.
+
+MessageId=30512 SymbolicName=MSG_SUBST_TOO_MANY_PARAMETERS
+Language=English
+Incorrect number of parameters - %1
+.
+
+MessageId=30513 SymbolicName=MSG_SUBST_PATH_NOT_FOUND
+Language=English
+Path not found - %1
+.
+
+MessageId=30514 SymbolicName=MSG_SUBST_ACCESS_DENIED
+Language=English
+Access denied - %1
+.
+
+
+;//----------------
+;//
+;// CHKNTFS messages
+;//
+;//----------------
+
+MessageId=30520 SymbolicName=MSG_CHKNTFS_INVALID_FORMAT
+Language=English
+CHKNTFS: Incorrect command-line format.
+.
+
+MessageId=30521 SymbolicName=MSG_CHKNTFS_INVALID_SWITCH
+Language=English
+Invalid parameter - %1
+.
+
+MessageId=30522 SymbolicName=MSG_CHKNTFS_NO_WILDCARDS
+Language=English
+CHKNTFS: drive specifiers may not contain wildcards.
+.
+
+MessageId=30523 SymbolicName=MSG_CHKNTFS_USAGE
+Language=English
+CHKNTFS drive: [...]
+CHKNTFS /D
+CHKNTFS /X drive: [...]
+CHKNTFS /C drive: [...]
+
+ drive: Specifies a drive letter.
+ /D Restores the machine to the default behavior; all drives are
+ checked at boot time and chkdsk is run on those that are dirty.
+ This undoes the effect of the /X option.
+ /X Excludes a drive from the default boot-time check. Excluded
+ drives are not accumulated between command invocations.
+ /C Schedules chkdsk to be run at the next reboot.
+
+If no switches are specified, CHKNTFS will display the status of the
+dirty bit for each drive.
+.
+
+MessageId=30524 SymbolicName=MSG_CHKNTFS_ARGS_CONFLICT
+Language=English
+Specify only one of /D, /X, and /C.
+.
+
+MessageId=30525 SymbolicName=MSG_CHKNTFS_REQUIRES_DRIVE
+Language=English
+You must specify at least one drive name.
+.
+
+MessageId=30526 SymbolicName=MSG_CHKNTFS_BAD_ARG
+Language=English
+%1 is not a drive letter.
+.
+
+MessageId=30527 SymbolicName=MSG_CHKNTFS_CANNOT_CHECK
+Language=English
+Cannot query state of drive %1
+.
+
+MessageId=30528 SymbolicName=MSG_CHKNTFS_DIRTY
+Language=English
+%1 is dirty. You may use the /C option to schedule chkdsk for
+ this drive.
+.
+
+MessageId=30529 SymbolicName=MSG_CHKNTFS_CLEAN
+Language=English
+%1 is not dirty.
+.
+
+MessageId=30530 SymbolicName=MSG_CHKNTFS_NONEXISTENT_DRIVE
+Language=English
+Drive %1 does not exist.
+.
+
+MessageId=30531 SymbolicName=MSG_CHKNTFS_NO_NETWORK
+Language=English
+CHKNTFS cannot be used for the network drive %1.
+.
+
+MessageId=30532 SymbolicName=MSG_CHKNTFS_NO_CDROM
+Language=English
+CHKNTFS cannot be used for the cdrom drive %1.
+.
+
+MessageId=30533 SymbolicName=MSG_CHKNTFS_NO_RAMDISK
+Language=English
+CHKNTFS cannot be used for the ram disk %1.
+.
diff --git a/private/utils/ulib/src/screen.cxx b/private/utils/ulib/src/screen.cxx
new file mode 100644
index 000000000..24ee4c384
--- /dev/null
+++ b/private/utils/ulib/src/screen.cxx
@@ -0,0 +1,1998 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ screen.cxx
+
+Abstract:
+
+ This module contains the definitions of the member functions
+ of SCREEN class.
+
+Author:
+
+ Jaime Sasson (jaimes) 24-Mar-1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "stream.hxx"
+#include "screen.hxx"
+
+
+DEFINE_EXPORTED_CONSTRUCTOR ( SCREEN, STREAM, ULIB_EXPORT );
+
+DEFINE_EXPORTED_CAST_MEMBER_FUNCTION( SCREEN, ULIB_EXPORT );
+
+
+ULIB_EXPORT
+SCREEN::~SCREEN (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy a SCREEN (closes the screen handle).
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CloseHandle( _ScreenHandle );
+}
+
+
+
+BOOLEAN
+SCREEN::Initialize(
+ IN BOOLEAN CurrentActiveScreen,
+ IN USHORT NumberOfRows,
+ IN USHORT NumberOfColumns,
+ IN USHORT TextAttribute,
+ IN BOOLEAN ExpandAsciiControlSequence,
+ IN BOOLEAN WrapAtEndOfLine
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes an object of type SCREEN.
+
+Arguments:
+
+ CurrentActiveScreen - Indicates if the client wants to use the screen
+ currently displayed (TRUE), or if a new screen
+ buffer is to be created (FALSE).
+
+ NumberOfRows - Number of rows in the screen.
+
+ NumberOfColumns - Number of columns in the screen.
+
+ TextAttribute - Indicates the default text attribute.
+
+ ExpandAsciiControlSequence - Indicates if expansion of ASCII control
+ sequences is allowed.
+
+ WrapAtEndOfLine - Indicates if wrap at the end of a line is allowed.
+
+Return Value:
+
+ BOOLEAN - Indicates if the initialization succeeded.
+
+
+--*/
+
+
+{
+
+
+ if( CurrentActiveScreen ) {
+ _ScreenHandle = CreateFile( (LPWSTR)L"CONOUT$",
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL );
+ } else {
+ _ScreenHandle = CreateConsoleScreenBuffer(GENERIC_WRITE | GENERIC_READ,
+ 0,
+ NULL,
+ CONSOLE_TEXTMODE_BUFFER,
+ NULL );
+ }
+
+
+ if( _ScreenHandle == INVALID_HANDLE_VALUE ) {
+ return( FALSE );
+ }
+
+ if( !GetConsoleMode( _ScreenHandle, (LPDWORD)&_ScreenMode ) ) {
+ return( FALSE );
+ }
+ if( ExpandAsciiControlSequence ) {
+ _ScreenMode |= ENABLE_PROCESSED_OUTPUT;
+ } else {
+ _ScreenMode &= ~ENABLE_PROCESSED_OUTPUT;
+ }
+ if( WrapAtEndOfLine ) {
+ _ScreenMode |= ENABLE_WRAP_AT_EOL_OUTPUT;
+ } else {
+ _ScreenMode &= ~ENABLE_WRAP_AT_EOL_OUTPUT;
+ }
+ if( !ChangeScreenSize( NumberOfRows, NumberOfColumns ) ) {
+ return( FALSE );
+ }
+ if( !ChangeTextAttribute( TextAttribute ) ) {
+ return( FALSE );
+ }
+ if( !SetConsoleMode( _ScreenHandle, _ScreenMode ) ) {
+ return( FALSE );
+ }
+ return( STREAM::Initialize() );
+}
+
+
+
+ULIB_EXPORT
+BOOLEAN
+SCREEN::Initialize(
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes an object of type SCREEN with default values.
+ This object will access the screen currently active, and all
+ values such as number of rows, columns, attributes, and mode
+ will be the ones defined in the currently active screen.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the initialization succeeded.
+
+
+--*/
+
+
+{
+ CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo;
+
+ _ScreenHandle = CreateFile( (LPWSTR)L"CONOUT$",
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL );
+ if( _ScreenHandle == (HANDLE)-1 ) {
+ return( FALSE );
+ }
+
+ if( !GetConsoleScreenBufferInfo( _ScreenHandle, &ScreenBufferInfo ) ) {
+ return( FALSE );
+ }
+ if( !GetConsoleMode( _ScreenHandle, (LPDWORD)&_ScreenMode ) ) {
+ return( FALSE );
+ }
+ _TextAttribute = ScreenBufferInfo.wAttributes;
+ return( STREAM::Initialize() );
+}
+
+
+
+
+ULIB_EXPORT
+BOOLEAN
+SCREEN::ChangeScreenSize(
+ IN USHORT NumberOfRows,
+ IN USHORT NumberOfColumns,
+ OUT PBOOLEAN IsFullScreen
+ )
+
+/*++
+
+Routine Description:
+
+ Changes the screen buffer size to the specified number of rows and
+ columns. And sets the window size accordingly.
+
+Arguments:
+
+ NumberOfRows - Number of rows in the screen.
+
+ NumberOfColumns - Number of columns in the screen.
+
+ IsFullScreen - TRUE if in full screen mode.
+
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+{
+ CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo;
+ SMALL_RECT ScreenRect;
+ COORD ScreenSize;
+ COORD LargestScreenSize;
+ USHORT MaxRows;
+ USHORT MaxCols;
+ BOOLEAN WindowSet = FALSE;
+
+ //
+ // Clear the screen
+ //
+ MoveCursorTo(0, 0);
+ EraseScreen();
+
+ if ( IsFullScreen ) {
+ *IsFullScreen = FALSE;
+ }
+
+ //
+ // We obtain the current screen information.
+ //
+ if ( GetConsoleScreenBufferInfo( _ScreenHandle, &ScreenBufferInfo ) ) {
+
+ //
+ // Set the Window Size. The new size is the minimum of the
+ // buffer size or the screen size.
+ //
+ LargestScreenSize = GetLargestConsoleWindowSize( _ScreenHandle );
+
+ if ( (LargestScreenSize.X == 0) && (LargestScreenSize.Y == 0) ) {
+
+ if ( IsFullScreen && (GetLastError() == ERROR_FULLSCREEN_MODE) ) {
+ *IsFullScreen = TRUE;
+ }
+ return FALSE;
+ }
+
+ //
+ // If the desired window size is smaller than the current window
+ // size, we have to resize the current window first. (The buffer
+ // size cannot be smaller than the window size)
+ //
+ if ( ( NumberOfRows < (USHORT)
+ (ScreenBufferInfo.srWindow.Bottom -
+ ScreenBufferInfo.srWindow.Top + 1) ) ||
+ ( NumberOfColumns < (USHORT)
+ (ScreenBufferInfo.srWindow.Right -
+ ScreenBufferInfo.srWindow.Left + 1) ) ) {
+
+
+ //
+ // Set the window to a size that will fit in the current
+ // screen buffer and that is no bigger than the size to
+ // which we want to grow the screen buffer or the largest window
+ // size.
+ //
+ MaxRows = (USHORT)min( (int)NumberOfRows, (int)(ScreenBufferInfo.dwSize.Y) );
+ MaxRows = (USHORT)min( (int)MaxRows, (int)LargestScreenSize.Y );
+ MaxCols = (USHORT)min( (int)NumberOfColumns, (int)(ScreenBufferInfo.dwSize.X) );
+ MaxCols = (USHORT)min( (int)MaxCols, (int)LargestScreenSize.X );
+
+ ScreenRect.Top = 0;
+ ScreenRect.Left = 0;
+ ScreenRect.Right = MaxCols - (SHORT)1;
+ ScreenRect.Bottom = MaxRows - (SHORT)1;
+
+ WindowSet = (BOOLEAN)SetConsoleWindowInfo( _ScreenHandle, TRUE, &ScreenRect );
+
+ if ( !WindowSet ) {
+
+ DebugPrintf( "MODE: SetConsoleWindowInfo failed. Error %d\n", GetLastError() );
+ if ( IsFullScreen && (GetLastError() == ERROR_FULLSCREEN_MODE) ) {
+ *IsFullScreen = TRUE;
+ }
+ return FALSE;
+ }
+ }
+
+ //
+ // Set the screen buffer size to the desired size.
+ //
+ ScreenSize.X = NumberOfColumns;
+ ScreenSize.Y = NumberOfRows;
+
+ if ( !SetConsoleScreenBufferSize( _ScreenHandle, ScreenSize ) ) {
+
+ DebugPrintf( "MODE: SetConsoleScreenBufferSize failed (Y:%d X:%d ) Error: %d\n",
+ ScreenSize.Y, ScreenSize.X, GetLastError() );
+
+ if ( IsFullScreen && (GetLastError() == ERROR_FULLSCREEN_MODE) ) {
+ *IsFullScreen = TRUE;
+ }
+
+ //
+ // Return the window to its original size. We ignore the return
+ // code because there is nothing we can do about it.
+ //
+ if ( !SetConsoleWindowInfo( _ScreenHandle, TRUE, &(ScreenBufferInfo.srWindow) )) {
+ DebugPrintf( "MODE: SetConsoleWindowInfo (2) failed. Error %d\n", GetLastError() );
+
+ }
+
+ return FALSE;
+ }
+
+ MaxRows = (USHORT)min( (int)NumberOfRows, (int)(LargestScreenSize.Y) );
+ MaxCols = (USHORT)min( (int)NumberOfColumns, (int)(LargestScreenSize.X) );
+
+ ScreenRect.Top = 0;
+ ScreenRect.Left = 0;
+ ScreenRect.Right = MaxCols - (SHORT)1;
+ ScreenRect.Bottom = MaxRows - (SHORT)1;
+
+ WindowSet = (BOOLEAN)SetConsoleWindowInfo( _ScreenHandle, TRUE, &ScreenRect );
+
+ if ( !WindowSet ) {
+ //
+ // We could not resize the window. We will leave the
+ // resized screen buffer.
+ //
+ DebugPrintf( "MODE: SetConsoleWindowInfo (3) failed. Error %d\n", GetLastError() );
+ return FALSE;
+ }
+
+ return TRUE;
+
+ } else {
+
+ DebugPrintf( "ULIB: Cannot get console screen buffer info, Error = %X\n", GetLastError() );
+ }
+
+ return FALSE;
+}
+
+
+
+
+BOOLEAN
+SCREEN::ChangeTextAttribute(
+ IN USHORT Attribute
+ )
+
+/*++
+
+Routine Description:
+
+ Set the attribute to be used when text is written using WriteFile()
+ (ie, when the stream API is used ).
+
+Arguments:
+
+ Attribute - Attribute to be used
+
+Return Value:
+
+ BOOLEAN - Indicates if the initialization succeeded.
+
+
+--*/
+
+{
+ _TextAttribute = Attribute;
+ return( SetConsoleTextAttribute( _ScreenHandle, Attribute ) );
+}
+
+
+
+BOOLEAN
+SCREEN::EnableAsciiControlSequence(
+ )
+
+/*++
+
+Routine Description:
+
+ Set the screen in the line mode (allows expansion of control ASCII
+ sequences);
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+
+{
+ if( _ScreenMode & ENABLE_PROCESSED_OUTPUT ) {
+ return( TRUE );
+ }
+ _ScreenMode |= ENABLE_PROCESSED_OUTPUT;
+ return( SetConsoleMode( _ScreenHandle, _ScreenMode ) );
+}
+
+
+
+BOOLEAN
+SCREEN::DisableAsciiControlSequence(
+ )
+
+/*++
+
+Routine Description:
+
+ Set the screen in the character mode (does not expansion of control
+ ASCII sequences);
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+
+{
+ if( !( _ScreenMode & ENABLE_PROCESSED_OUTPUT ) ) {
+ return( TRUE );
+ }
+ _ScreenMode &= ~(ENABLE_PROCESSED_OUTPUT);
+ return( SetConsoleMode( _ScreenHandle, _ScreenMode ) );
+}
+
+
+
+BOOLEAN
+SCREEN::EnableWrapMode(
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the screen in the wrap mode (characters are written in the next
+ line when cursor reaches the end of a line).
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+
+{
+ if( _ScreenMode & ENABLE_WRAP_AT_EOL_OUTPUT ) {
+ return( TRUE );
+ }
+ _ScreenMode |= ENABLE_WRAP_AT_EOL_OUTPUT;
+ return( SetConsoleMode( _ScreenHandle, _ScreenMode ) );
+}
+
+
+
+BOOLEAN
+SCREEN::DisableWrapMode(
+ )
+
+/*++
+
+Routine Description:
+
+ Disables the wrap mode (cursor does not move to the beginning of
+ the next line when it reaches the eand of a line).
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+
+{
+ if( !( _ScreenMode & ENABLE_WRAP_AT_EOL_OUTPUT ) ) {
+ return( TRUE );
+ }
+ _ScreenMode &= ~ENABLE_WRAP_AT_EOL_OUTPUT;
+ return( SetConsoleMode( _ScreenHandle, _ScreenMode ) );
+}
+
+
+
+BOOLEAN
+SCREEN::IsAtEnd(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Determines if the cursor is at the end of the screen.
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+ BOOLEAN - Indicates if the cursor is at the end of the screen.
+
+
+--*/
+
+
+{
+ CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo;
+
+ GetConsoleScreenBufferInfo( _ScreenHandle, &ScreenBufferInfo );
+ return( ( ScreenBufferInfo.dwCursorPosition.X ==
+ ScreenBufferInfo.dwSize.X ) &&
+ ( ScreenBufferInfo.dwCursorPosition.Y ==
+ ScreenBufferInfo.dwSize.Y ) );
+}
+
+
+
+BOOLEAN
+SCREEN::SetScreenActive(
+ )
+
+/*++
+
+Routine Description:
+
+ Makes the screen buffer defined in this class active.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+
+{
+ return( SetConsoleActiveScreenBuffer( _ScreenHandle ) );
+}
+
+
+
+
+ULIB_EXPORT
+BOOLEAN
+SCREEN::MoveCursorTo(
+ IN USHORT Row,
+ IN USHORT Column
+ )
+
+/*++
+
+Routine Description:
+
+ Moves the cursor to a particular position in the screen
+
+Arguments:
+
+ USHORT - Row where the cursor is to be moved to.
+
+ USHORT - Column where the cursor is to be moved to.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+
+{
+ COORD CursorPosition;
+
+ CursorPosition.Y = Row;
+ CursorPosition.X = Column;
+ return( SetConsoleCursorPosition( _ScreenHandle, CursorPosition ) );
+}
+
+
+
+BOOLEAN
+SCREEN::MoveCursorDown(
+ IN USHORT Rows
+ )
+
+/*++
+
+Routine Description:
+
+ Moves the cursor down by a number of lines, keeping it in the same
+ column.
+
+Arguments:
+
+ Rows - Number of lines to move the cursor.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+
+{
+ CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo;
+
+ if( !GetConsoleScreenBufferInfo( _ScreenHandle, &ScreenBufferInfo ) ) {
+ return( FALSE );
+ }
+ return( MoveCursorTo( ScreenBufferInfo.dwCursorPosition.Y + Rows,
+ ScreenBufferInfo.dwCursorPosition.X ) );
+}
+
+
+
+BOOLEAN
+SCREEN::MoveCursorUp(
+ IN USHORT Rows
+ )
+
+/*++
+
+Routine Description:
+
+ Moves the cursor up by a number of lines, keeping it in the same
+ column.
+
+Arguments:
+
+ Rows - Number of lines to move the cursor.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+
+{
+ CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo;
+
+ if( !GetConsoleScreenBufferInfo( _ScreenHandle, &ScreenBufferInfo ) ) {
+ return( FALSE );
+ }
+ return( MoveCursorTo( ScreenBufferInfo.dwCursorPosition.Y - Rows,
+ ScreenBufferInfo.dwCursorPosition.X ) );
+}
+
+
+
+BOOLEAN
+SCREEN::MoveCursorRight(
+ IN USHORT Columns
+ )
+
+/*++
+
+Routine Description:
+
+ Moves the cursor right by a number of columns, keeping it in the same
+ line.
+
+Arguments:
+
+ Columns - Number of columns to move the cursor.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+
+{
+ CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo;
+
+ if( !GetConsoleScreenBufferInfo( _ScreenHandle, &ScreenBufferInfo ) ) {
+ return( FALSE );
+ }
+ return( MoveCursorTo( ScreenBufferInfo.dwCursorPosition.Y,
+ ScreenBufferInfo.dwCursorPosition.X + Columns ) );
+}
+
+
+
+BOOLEAN
+SCREEN::MoveCursorLeft(
+ IN USHORT Columns
+ )
+
+/*++
+
+Routine Description:
+
+ Moves the cursor left by a number of columns, keeping it in the same
+ line.
+
+Arguments:
+
+ Columns - Number of columns to move the cursor.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+
+{
+ CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo;
+
+ if( !GetConsoleScreenBufferInfo( _ScreenHandle, &ScreenBufferInfo ) ) {
+ return( FALSE );
+ }
+ return( MoveCursorTo( ScreenBufferInfo.dwCursorPosition.Y,
+ ScreenBufferInfo.dwCursorPosition.X - Columns ) );
+}
+
+
+
+
+ULIB_EXPORT
+DWORD
+SCREEN::QueryCodePage(
+ )
+
+/*++
+
+Routine Description:
+
+ Obtains the current console code page.
+
+Arguments:
+
+ None
+
+
+Return Value:
+
+ The current console code page.
+
+
+--*/
+
+
+{
+ return GetConsoleCP( );
+}
+
+
+DWORD
+SCREEN::QueryOutputCodePage(
+ )
+
+/*++
+
+Routine Description:
+
+ Obtains the current console code page.
+
+Arguments:
+
+ None
+
+
+Return Value:
+
+ The current console code page.
+
+
+--*/
+
+
+{
+ return GetConsoleOutputCP( );
+}
+
+
+BOOLEAN
+SCREEN::QueryCursorPosition(
+ OUT PUSHORT Row,
+ OUT PUSHORT Column
+ )
+
+/*++
+
+Routine Description:
+
+ Returns to the caller the current position of the cursor.
+
+Arguments:
+
+ Row - Address of the variable that will contain the row.
+
+ Column - Address of the variable that will contain the column.
+
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+
+{
+ CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo;
+
+ if( !GetConsoleScreenBufferInfo( _ScreenHandle, &ScreenBufferInfo ) ) {
+ return( FALSE );
+ }
+
+ *Row = ScreenBufferInfo.dwCursorPosition.Y;
+ *Column = ScreenBufferInfo.dwCursorPosition.X;
+ return( TRUE );
+}
+
+
+
+ULIB_EXPORT
+BOOLEAN
+SCREEN::SetCodePage(
+ IN DWORD CodePage
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the console codepage.
+
+Arguments:
+
+
+ CodePage - New codepage
+
+
+Return Value:
+
+ BOOLEAN - TRUE if codepage set, FALSE otherwise (most probably the
+ codepage is invalid).
+
+
+--*/
+
+
+{
+ return SetConsoleCP( CodePage );
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+SCREEN::SetOutputCodePage(
+ IN DWORD CodePage
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the console output codepage.
+
+Arguments:
+
+
+ CodePage - New codepage
+
+
+Return Value:
+
+ BOOLEAN - TRUE if codepage set, FALSE otherwise (most probably the
+ codepage is invalid).
+
+
+--*/
+
+
+{
+ return SetConsoleOutputCP( CodePage );
+}
+
+
+BOOLEAN
+SCREEN::SetCursorSize(
+ IN ULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the size of the cursor.
+
+Arguments:
+
+ Size - A number in the range 1-100 that indicates the percentage of
+ character cell to be filled.
+
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+
+{
+ CONSOLE_CURSOR_INFO CursorInfo;
+
+ if( !GetConsoleCursorInfo( _ScreenHandle, &CursorInfo ) ) {
+ return( FALSE );
+ }
+ CursorInfo.dwSize = Size;
+ return( SetConsoleCursorInfo( _ScreenHandle, &CursorInfo ) );
+}
+
+
+
+BOOLEAN
+SCREEN::SetCursorOff(
+ )
+
+/*++
+
+Routine Description:
+
+ Turns off the cursor.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+
+{
+ CONSOLE_CURSOR_INFO CursorInfo;
+
+ if( !GetConsoleCursorInfo( _ScreenHandle, &CursorInfo ) ) {
+ return( FALSE );
+ }
+ CursorInfo.bVisible = FALSE;
+ return( SetConsoleCursorInfo( _ScreenHandle, &CursorInfo ) );
+}
+
+
+
+BOOLEAN
+SCREEN::SetCursorOn(
+ )
+
+/*++
+
+Routine Description:
+
+ Turns on the cursor.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+
+{
+ CONSOLE_CURSOR_INFO CursorInfo;
+
+ if( !GetConsoleCursorInfo( _ScreenHandle, &CursorInfo ) ) {
+ return( FALSE );
+ }
+ CursorInfo.bVisible = TRUE;
+ return( SetConsoleCursorInfo( _ScreenHandle, &CursorInfo ) );
+}
+
+
+
+BOOLEAN
+SCREEN::FillRegionCharacter(
+ IN USHORT StartRow,
+ IN USHORT StartColumn,
+ IN USHORT EndRow,
+ IN USHORT EndColumn,
+ IN CHAR Character
+ )
+
+/*++
+
+Routine Description:
+
+ Fills a region in the screen with a particular character. Attributes
+ in this region are not changed.
+
+Arguments:
+
+ StartRow - Row where the region starts.
+
+ StartColumn - Column where the region starts.
+
+ EndRow - Row where the region ends.
+
+ EndColumn - Column where the region ends.
+
+ Character - Character to fill the region.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+
+{
+ COORD Origin;
+ ULONG Length;
+ CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo;
+ ULONG Columns;
+ ULONG NumberOfCharsWritten;
+
+
+ GetConsoleScreenBufferInfo( _ScreenHandle, &ScreenBufferInfo );
+ Columns = ScreenBufferInfo.dwSize.X;
+
+ if( EndRow == StartRow ) {
+ Length = EndColumn - StartColumn + 1;
+ } else {
+ Length = Columns - StartColumn +
+ Columns*( EndRow - StartRow - 1 ) +
+ EndColumn + 1;
+ }
+ Origin.Y = StartRow;
+ Origin.X = StartColumn;
+ if( !FillConsoleOutputCharacter( _ScreenHandle,
+ Character,
+ Length,
+ Origin,
+ &NumberOfCharsWritten ) ||
+ NumberOfCharsWritten != Length) {
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+SCREEN::FillRectangularRegionCharacter(
+ IN USHORT TopLeftRow,
+ IN USHORT TopLeftColumn,
+ IN USHORT BottomRightRow,
+ IN USHORT BottomRightColumn,
+ IN CHAR Character
+ )
+
+/*++
+
+Routine Description:
+
+ Fills a rectangular region in the screen with a particular character.
+ Attributes in this region are not changed.
+
+Arguments:
+
+ TopLeftRow - Row where the region starts.
+
+ TopLeftColumn - Column where the region starts.
+
+ BottomRightRow - Row where the region ends.
+
+ BottomeRightColumn - Column where the region ends.
+
+ Character - Character to fill the region.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+
+{
+ COORD Origin;
+ ULONG Length;
+ ULONG NumberOfRows;
+ ULONG NumberOfCharsWritten;
+
+ NumberOfRows = BottomRightRow - TopLeftRow + 1;
+ Length = BottomRightColumn - TopLeftColumn + 1;
+ Origin.X = TopLeftColumn;
+ Origin.Y = TopLeftRow;
+ while( NumberOfRows-- ) {
+ if( !FillConsoleOutputCharacter( _ScreenHandle,
+ Character,
+ Length,
+ Origin,
+ &NumberOfCharsWritten ) ||
+ NumberOfCharsWritten != Length ) {
+ return( FALSE );
+ }
+ Origin.Y++;
+ }
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+SCREEN::FillRegionAttribute(
+ IN USHORT StartRow,
+ IN USHORT StartColumn,
+ IN USHORT EndRow,
+ IN USHORT EndColumn,
+ IN USHORT Attribute
+ )
+
+/*++
+
+Routine Description:
+
+ Fills a region in the screen with a particular attribute. Characters
+ in this region are not changed.
+
+Arguments:
+
+ StartRow - Row where the region starts.
+
+ StartColumn - Column where the region starts.
+
+ EndRow - Row where the region ends.
+
+ EndColumn - Column where the region ends.
+
+ Attribute - Attribute to fill the region.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+
+{
+ COORD Origin;
+ ULONG Length;
+ CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo;
+ ULONG Columns;
+ ULONG NumberOfAttrsWritten;
+
+
+ GetConsoleScreenBufferInfo( _ScreenHandle, &ScreenBufferInfo );
+ Columns = ScreenBufferInfo.dwSize.X;
+
+ if( EndRow == StartRow ) {
+ Length = EndColumn - StartColumn + 1;
+ } else {
+ Length = Columns - StartColumn +
+ Columns*( EndRow - StartRow - 1 ) +
+ EndColumn + 1;
+ }
+ Origin.Y = StartRow;
+ Origin.X = StartColumn;
+ if( !FillConsoleOutputAttribute( _ScreenHandle,
+ Attribute,
+ Length,
+ Origin,
+ &NumberOfAttrsWritten ) ||
+ NumberOfAttrsWritten != Length ) {
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+SCREEN::FillRectangularRegionAttribute(
+ IN USHORT TopLeftRow,
+ IN USHORT TopLeftColumn,
+ IN USHORT BottomRightRow,
+ IN USHORT BottomRightColumn,
+ IN USHORT Attribute
+ )
+
+/*++
+
+Routine Description:
+
+ Fills a rectangular region in the screen with a particular attribute.
+ Characters in this region are not changed.
+
+Arguments:
+
+ TopLeftRow - Row where the region starts.
+
+ TopLeftColumn - Column where the region starts.
+
+ BottomRighhtRow - Row where the region ends.
+
+ BottomRightColumn - Column where the region ends.
+
+ Attribute - Attribute used to fill the region.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+
+{
+ COORD Origin;
+ ULONG Length;
+ ULONG NumberOfRows;
+ ULONG NumberOfAttrsWritten;
+
+ NumberOfRows = BottomRightRow - TopLeftRow + 1;
+ Length = BottomRightColumn - TopLeftColumn + 1;
+ Origin.X = TopLeftColumn;
+ Origin.Y = TopLeftRow;
+ while( NumberOfRows-- ) {
+ if( !FillConsoleOutputAttribute( _ScreenHandle,
+ Attribute,
+ Length,
+ Origin,
+ &NumberOfAttrsWritten ) ||
+ NumberOfAttrsWritten != Length ) {
+ return( FALSE );
+ }
+ Origin.Y++;
+ }
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+SCREEN::EraseLine(
+ IN USHORT LineNumber
+ )
+
+/*++
+
+Routine Description:
+
+ Erases a line in the screen.
+
+Arguments:
+
+ LineNumber - Line number.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+
+{
+ CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo;
+
+ if( !GetConsoleScreenBufferInfo( _ScreenHandle, &ScreenBufferInfo ) ) {
+ return( FALSE );
+ }
+ return( FillRegionCharacter( LineNumber,
+ 0,
+ LineNumber,
+ ScreenBufferInfo.dwSize.X - 1,
+ 0x20 ) );
+}
+
+
+
+BOOLEAN
+SCREEN::EraseToEndOfLine(
+ )
+
+/*++
+
+Routine Description:
+
+ Erases the current line from the cursor position to the end of line.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+
+{
+ CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo;
+
+ if( !GetConsoleScreenBufferInfo( _ScreenHandle, &ScreenBufferInfo ) ) {
+ return( FALSE );
+ }
+ return( FillRegionCharacter( ScreenBufferInfo.dwCursorPosition.Y,
+ ScreenBufferInfo.dwCursorPosition.X,
+ ScreenBufferInfo.dwCursorPosition.Y,
+ ScreenBufferInfo.dwSize.X - 1,
+ 0x20 ) );
+}
+
+
+
+ULIB_EXPORT
+BOOLEAN
+SCREEN::EraseScreen(
+ )
+
+/*++
+
+Routine Description:
+
+ Erases all characters in the screen. Attributes are not changed.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+
+{
+ CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo;
+
+ GetConsoleScreenBufferInfo( _ScreenHandle, &ScreenBufferInfo );
+ return( FillRegionCharacter( 0,
+ 0,
+ ScreenBufferInfo.dwSize.Y - 1,
+ ScreenBufferInfo.dwSize.X - 1,
+ 0x20 ) );
+}
+
+
+
+ULIB_EXPORT
+VOID
+SCREEN::QueryScreenSize(
+ OUT PUSHORT NumberOfRows,
+ OUT PUSHORT NumberOfColumns,
+ OUT PUSHORT WindowRows,
+ OUT PUSHORT WindowColumns
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns to the caller the screen size, and optionally the window
+ size.
+
+Arguments:
+
+ NumberOfRows - Points to the variable that will contain the
+ number of rows
+
+ NumberOfColumns - Points to the variable that will contain the
+ number of columns
+
+ WindowRows - Points to the variable that will contain the number
+ of rows in the window
+
+ WindowColumns - Points to the variable that will contain the number
+ of columns in the window
+
+Return Value:
+
+ None.
+
+
+--*/
+
+
+{
+ CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo;
+
+ GetConsoleScreenBufferInfo( _ScreenHandle, &ScreenBufferInfo );
+
+ //
+ // Get screen buffer size
+ //
+ *NumberOfRows = ScreenBufferInfo.dwSize.Y;
+ *NumberOfColumns = ScreenBufferInfo.dwSize.X;
+
+ //
+ // Get window size
+ //
+ if ( WindowRows && WindowColumns ) {
+ *WindowColumns = ScreenBufferInfo.srWindow.Right - ScreenBufferInfo.srWindow.Left + 1;
+ *WindowRows = ScreenBufferInfo.srWindow.Bottom - ScreenBufferInfo.srWindow.Top + 1;
+ }
+}
+
+
+
+
+BOOLEAN
+SCREEN::ScrollScreen(
+ IN USHORT Amount,
+ IN SCROLL_DIRECTION Direction
+ )
+
+/*++
+
+Routine Description:
+
+ Scrolls the screen.
+
+Arguments:
+
+ Amount - Number of rows or columns to scroll.
+
+ Direction - Indicates if up, down, left or right.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the screen was scrolled. FALSE otherwise.
+
+
+--*/
+
+
+{
+ UNREFERENCED_PARAMETER( Amount );
+ UNREFERENCED_PARAMETER( Direction );
+
+/*
+ CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo;
+ CONSOLE_SCROLL_INFO ConsoleScrollInfo;
+
+ if( !GetConsoleScreenBufferInfo( _ScreenHandle, &ScreenBufferInfo ) ) {
+ return( FALSE );
+ }
+ switch( Direction ) {
+
+ case SCROLL_UP:
+
+ ConsoleScrollInfo.ScrollRectangle.Left = 0;
+ ConsoleScrollInfo.ScrollRectangle.Top = Amount;
+ ConsoleScrollInfo.ScrollRectangle.Right =
+ ( SHORT )( ScreenBufferInfo.dwSize.X - 1 );
+ ConsoleScrollInfo.ScrollRectangle.Bottom =
+ ( SHORT )( ScreenBufferInfo.dwSize.Y - 1 );
+ ConsoleScrollInfo.dwDestinationOrigin.X = 0;
+ ConsoleScrollInfo.dwDestinationOrigin.Y = 0;
+ break;
+
+
+ case SCROLL_DOWN:
+
+ ConsoleScrollInfo.ScrollRectangle.Left = 0;
+ ConsoleScrollInfo.ScrollRectangle.Top = 0;
+ ConsoleScrollInfo.ScrollRectangle.Right =
+ ( SHORT )( ScreenBufferInfo.dwSize.X - 1 );
+ ConsoleScrollInfo.ScrollRectangle.Bottom =
+ ( SHORT )( ScreenBufferInfo.dwSize.Y - Amount - 1 );
+ ConsoleScrollInfo.dwDestinationOrigin.X = 0;
+ ConsoleScrollInfo.dwDestinationOrigin.Y = Amount;
+ break;
+
+
+ case SCROLL_LEFT:
+
+ ConsoleScrollInfo.ScrollRectangle.Left = Amount;
+ ConsoleScrollInfo.ScrollRectangle.Top = 0;
+ ConsoleScrollInfo.ScrollRectangle.Right =
+ ( SHORT )( ScreenBufferInfo.dwSize.X - 1 );
+ ConsoleScrollInfo.ScrollRectangle.Bottom =
+ ( SHORT )( ScreenBufferInfo.dwSize.Y - 1 );
+ ConsoleScrollInfo.dwDestinationOrigin.X = 0;
+ ConsoleScrollInfo.dwDestinationOrigin.Y = 0;
+ break;
+
+
+ case SCROLL_RIGHT:
+
+ ConsoleScrollInfo.ScrollRectangle.Left = 0;
+ ConsoleScrollInfo.ScrollRectangle.Top = 0;
+ ConsoleScrollInfo.ScrollRectangle.Right =
+ ( SHORT )( ScreenBufferInfo.dwSize.X - Amount - 1 );
+ ConsoleScrollInfo.ScrollRectangle.Bottom =
+ ( SHORT )( ScreenBufferInfo.dwSize.Y - 1 );
+ ConsoleScrollInfo.dwDestinationOrigin.X = Amount;
+ ConsoleScrollInfo.dwDestinationOrigin.Y = 0;
+ break;
+
+ }
+
+ ConsoleScrollInfo.Fill.Char.AsciiChar = 0x20;
+ ConsoleScrollInfo.Fill.Attributes = ScreenBufferInfo.wAttributes;
+ return( ScrollConsoleScreenBuffer( _ScreenHandle,
+ &ConsoleScrollInfo ) );
+*/
+//
+// jaimes - 07/08/91
+// ScrollConsoleScreenBuffer has chaged
+//
+return TRUE;
+}
+
+
+
+BOOLEAN
+SCREEN::Read(
+ OUT PBYTE Buffer,
+ IN ULONG BytesToRead,
+ OUT PULONG BytesRead
+ )
+
+/*++
+
+Routine Description:
+
+ Reads bytes from the screen stream.
+
+Arguments:
+
+ Buffer - Points that will receive the bytes read.
+
+ BytesToRead - Number of bytes to read (buffer size)
+
+ BytesRead - Points to the variable that will contain the total
+ number of bytes read.
+
+Return Value:
+
+ Returns always FALSE since no data can be read from a screen stream.
+
+
+--*/
+
+
+{
+ // unreferenced parameters
+ (void)(this);
+ (void)(Buffer);
+ (void)(BytesToRead);
+ (void)(BytesRead);
+
+ return( FALSE );
+}
+
+
+
+BOOLEAN
+SCREEN::ReadChar(
+ OUT PWCHAR Char,
+ IN BOOLEAN Unicode
+ )
+
+/*++
+
+Routine Description:
+
+ Reads a character from the screen stream.
+
+Arguments:
+
+ Char - Supplies poinbter to wide character
+
+Return Value:
+
+ Returns always FALSE since no data can be read from a screen stream.
+
+
+--*/
+
+
+{
+ // unreferenced parameters
+ (void)(this);
+ (void)(Char);
+ (void)(Unicode);
+
+ return( FALSE );
+}
+
+
+
+BOOLEAN
+SCREEN::ReadMbString(
+ IN PSTR String,
+ IN DWORD BufferSize,
+ INOUT PDWORD StringSize,
+ IN PSTR Delimiters,
+ IN BOOLEAN ExpandTabs,
+ IN DWORD TabExp
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+
+--*/
+
+
+{
+ // unreferenced parameters
+ (void)(this);
+ (void)(String);
+ (void)(BufferSize);
+ (void)(StringSize);
+ (void)(Delimiters);
+ (void)(ExpandTabs);
+ (void)(TabExp);
+
+ return( FALSE );
+}
+
+
+
+BOOLEAN
+SCREEN::ReadWString(
+ IN PWSTR String,
+ IN DWORD BufferSize,
+ INOUT PDWORD StringSize,
+ IN PWSTR Delimiters,
+ IN BOOLEAN ExpandTabs,
+ IN DWORD TabExp
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+
+--*/
+
+
+{
+ // unreferenced parameters
+ (void)(this);
+ (void)(String);
+ (void)(BufferSize);
+ (void)(StringSize);
+ (void)(Delimiters);
+ (void)(ExpandTabs);
+ (void)(TabExp);
+
+ return( FALSE );
+}
+
+
+
+BOOLEAN
+SCREEN::ReadString(
+ OUT PWSTRING String,
+ IN PWSTRING Delimiter,
+ IN BOOLEAN Unicode
+ )
+
+/*++
+
+Routine Description:
+
+ Reads a STRING from the screen stream.
+
+Arguments:
+
+ String - Pointer to a WSTRING object that will contain the string read.
+
+ Delimiter - Pointer to a WSTRING object that contains the delimiters
+ of a string
+
+Return Value:
+
+ Returns always FALSE since no data can be read from a screen stream.
+
+
+--*/
+
+
+{
+ // unreferenced parameters
+ (void)(this);
+ (void)(String);
+ (void)(Delimiter);
+ (void)(Unicode);
+
+ return( FALSE );
+}
+
+
+
+STREAMACCESS
+SCREEN::QueryAccess(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the access to the screen stream.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns always WRITE_ACCESS.
+
+
+--*/
+
+
+{
+ (void)(this);
+ return( WRITE_ACCESS );
+}
+
+
+
+HANDLE
+SCREEN::QueryHandle(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the handle to the screen.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns a handle.
+
+
+--*/
+
+
+{
+ return( _ScreenHandle );
+}
+
+
+#if 0
+// TMPTMP just for debug.
+
+#include <stdio.h>
+#endif
+
+
+
+
+BOOLEAN
+SCREEN::WriteString(
+ IN PCWSTRING String,
+ IN CHNUM Position,
+ IN CHNUM Length,
+ IN CHNUM Granularity
+ )
+
+/*++
+
+Routine Description:
+
+ Writes a string to the screen.
+
+Arguments:
+
+ String - Pointer to a STRING object.
+ Position - Starting character within the string
+ Length - Number of characters to write
+ Granularity - The maximum number of bytes to write at one time.
+ A value of 0 indicates to write it all at once.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the write operation succeeded.
+
+
+--*/
+
+
+{
+ ULONG i, n, written, to_write;
+ PCWSTR p;
+ BOOLEAN r;
+ HANDLE h;
+
+ DebugAssert(Position <= String->QueryChCount());
+
+ n = min(String->QueryChCount() - Position, Length);
+ p = String->GetWSTR() + Position;
+ h = QueryHandle();
+
+ if (!Granularity) {
+ Granularity = n;
+ }
+
+ r = TRUE;
+ for (i = 0; r && i < n; i += Granularity) {
+
+ to_write = min(Granularity, n - i);
+
+ r = WriteConsole(h, p + i, to_write,
+ &written, NULL) &&
+ to_write == written;
+ }
+
+ return r;
+}
+
+
+BOOLEAN
+SCREEN::WriteChar(
+ IN WCHAR Char
+ )
+/*++
+
+Routine Description:
+
+ This routine writes a character to the output. This routine
+ uses WriteConsoleW to avoid having to make the translation
+ from wide to narrow characters.
+
+Arguments:
+
+ Char - Supplies the character to write.
+
+Return Value:
+
+ TRUE - Success.
+ FALSE - Failure.
+
+--*/
+{
+ ULONG written;
+
+ if (!WriteConsole(QueryHandle(), &Char, 1, &written, NULL) ||
+ written != 1) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#ifdef DBCS
+
+BOOLEAN
+SCREEN::EraseScreenAndResetAttribute(
+ )
+
+/*++
+
+Routine Description:
+
+ Erases all characters in the screen. Attributes are also reset.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the operation succeeded.
+
+
+--*/
+
+{
+ CONSOLE_SCREEN_BUFFER_INFO ScreenBufferInfo;
+
+ GetConsoleScreenBufferInfo( _ScreenHandle, &ScreenBufferInfo );
+
+ return (
+ FillRegionCharacter(
+ 0,
+ 0,
+ ScreenBufferInfo.dwSize.Y - 1,
+ ScreenBufferInfo.dwSize.X - 1,
+ 0x20
+ )
+ &&
+ FillRegionAttribute(
+ 0,
+ 0,
+ ScreenBufferInfo.dwSize.Y - 1,
+ ScreenBufferInfo.dwSize.X - 1,
+ ScreenBufferInfo.wAttributes
+ )
+ );
+}
+
+#endif // DBCS
diff --git a/private/utils/ulib/src/seqcnt.cxx b/private/utils/ulib/src/seqcnt.cxx
new file mode 100644
index 000000000..b3202cf4f
--- /dev/null
+++ b/private/utils/ulib/src/seqcnt.cxx
@@ -0,0 +1,82 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ seqcnt.cxx
+
+Abstract:
+
+ This module contains the definition for the SEQUENTIAL_CONTAINER class.
+ There exists no implementation, merely a constructor that acts as a link
+ between derived classes as SEQUENTIAL_CONTAINERs base class CONTAINER.
+
+Author:
+
+ David J. Gilman (davegi) 02-Nov-1990
+
+Environment:
+
+ ULIB, User Mode
+
+[Notes:]
+
+ optional-notes
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "iterator.hxx"
+#include "seqcnt.hxx"
+
+
+DEFINE_CONSTRUCTOR( SEQUENTIAL_CONTAINER, CONTAINER );
+
+SEQUENTIAL_CONTAINER::~SEQUENTIAL_CONTAINER(
+ )
+{
+}
+
+ULIB_EXPORT
+BOOLEAN
+SEQUENTIAL_CONTAINER::DeleteAllMembers(
+ )
+/*++
+
+Routine Description:
+
+ This routine not only removes all members from the container
+ class, but also deletes all the objects themselves.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PITERATOR iter;
+ POBJECT pobj;
+
+ if (!(iter = QueryIterator())) {
+ return FALSE;
+ }
+
+ iter->GetNext();
+ while (iter->GetCurrent()) {
+ pobj = Remove(iter);
+ DELETE(pobj);
+ }
+ DELETE(iter);
+
+ return TRUE;
+}
diff --git a/private/utils/ulib/src/smsg.cxx b/private/utils/ulib/src/smsg.cxx
new file mode 100644
index 000000000..3bdefd06d
--- /dev/null
+++ b/private/utils/ulib/src/smsg.cxx
@@ -0,0 +1,607 @@
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "smsg.hxx"
+#include "array.hxx"
+#include "arg.hxx"
+#include "iterator.hxx"
+#include "system.hxx"
+#include "stream.hxx"
+#include "keyboard.hxx"
+#include "rtmsg.h"
+#include "screen.hxx"
+
+
+DEFINE_EXPORTED_CONSTRUCTOR(STREAM_MESSAGE, MESSAGE, ULIB_EXPORT)
+
+
+VOID
+STREAM_MESSAGE::Construct(
+ )
+/*++
+
+Routine Description:
+
+ Constructor for STREAM_MESSAGE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _msgid = 0;
+ _msgtype = NORMAL_MESSAGE;
+ _out_stream = NULL;
+ _in_stream = NULL;
+ _err_stream = NULL;
+ _case_sensitive = FALSE;
+ _copy_input = FALSE;
+}
+
+
+ULIB_EXPORT
+STREAM_MESSAGE::~STREAM_MESSAGE(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for STREAM_MESSAGE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+STREAM_MESSAGE::Initialize(
+ IN OUT PSTREAM OutputStream,
+ IN OUT PSTREAM InputStream,
+ IN OUT PSTREAM ErrorStream
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the STREAM_MESSAGE object to the specified stream.
+
+Arguments:
+
+ OutputStream - Supplies the output stream for the object.
+ InputStream - Supplies the input stream for the object.
+ ErrorStream - Supplies the error stream for the object.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ Destroy();
+
+ DebugAssert(OutputStream);
+ DebugAssert(InputStream);
+
+ _out_stream = OutputStream;
+ _in_stream = InputStream;
+ _err_stream = ErrorStream;
+ _copy_input = SCREEN::Cast(OutputStream) ? FALSE : TRUE;
+
+
+#if defined JAPAN // v-junm - 08/11/93
+// Set TEB's LanguageId to either Japanese or US depending on the code page.
+// If the code page is non-JP, then the message to display is assumed to be US.
+
+ if ( GetConsoleOutputCP() == 932 )
+ SetThreadLocale(
+ MAKELCID(
+ MAKELANGID( LANG_JAPANESE, SUBLANG_ENGLISH_US ),
+ SORT_DEFAULT
+ )
+ );
+ else
+ SetThreadLocale(
+ MAKELCID(
+ MAKELANGID( LANG_ENGLISH, SUBLANG_ENGLISH_US ),
+ SORT_DEFAULT
+ )
+ );
+
+#endif // JAPAN
+ return TRUE;
+}
+
+ULIB_EXPORT
+BOOLEAN
+STREAM_MESSAGE::Set(
+ IN MSGID MsgId,
+ IN MESSAGE_TYPE MessageType,
+ IN ULONG MessageVisual
+ )
+/*++
+
+Routine Description:
+
+ This routine sets up the class to display the message with the
+ 'MsgId' resource identifier.
+
+Arguments:
+
+ MsgId - Supplies the resource id of the message.
+ MessageType - Supplies the type of the message.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ _msgid = MsgId;
+ _msgtype = MessageType;
+ _msgvisual = MessageVisual;
+ return TRUE;
+}
+
+
+BOOLEAN
+STREAM_MESSAGE::DisplayV(
+ IN PCSTR Format,
+ IN va_list VarPointer
+ )
+/*++
+
+Routine Description:
+
+ This routine displays the message with the specified parameters.
+
+ The format string supports all printf options.
+
+Arguments:
+
+ Format - Supplies a printf style list format string.
+ VarPointer - Supplies a varargs pointer to the arguments.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ if (! (_msgvisual & TEXT_MESSAGE) )
+ {
+ return TRUE;
+ }
+
+ if (!SYSTEM::QueryResourceStringV(&_display_string, _msgid, Format,
+ VarPointer)) {
+ return FALSE;
+ }
+
+ return DisplayString();
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+STREAM_MESSAGE::IsYesResponse(
+ IN BOOLEAN Default
+ )
+/*++
+
+Routine Description:
+
+ This routine queries either a "yes" or "no" from the input stream.
+
+Arguments:
+
+ Default - Supplies the default answer if neither "yes" nor "no" is the
+ recognized input.
+
+Return Value:
+
+ FALSE - A "no" response.
+ TRUE - A "yes" response.
+
+--*/
+{
+ DSTRING input;
+ DSTRING yes_message;
+ DSTRING no_message;
+ WCHAR w;
+
+ Flush();
+
+ if (!SYSTEM::QueryResourceString(&yes_message, MSG_YES, "")) {
+ return Default;
+ }
+
+ if (!SYSTEM::QueryResourceString(&no_message, MSG_NO, "")) {
+ return Default;
+ }
+
+ for (;;) {
+ if (!ReadLine(&input)) {
+ return Default;
+ }
+
+ if (!input.Strupr()) {
+ return Default;
+ }
+
+ w = input.QueryChAt(0);
+
+ if (w == no_message.QueryChAt(0)) {
+ return FALSE;
+ }
+
+ if (w == yes_message.QueryChAt(0)) {
+ return TRUE;
+ }
+
+ DisplayString();
+ }
+}
+
+
+BOOLEAN
+STREAM_MESSAGE::QueryStringInput(
+ OUT PWSTRING String
+ )
+/*++
+
+Routine Description:
+
+ This routine queries a string from the user.
+
+Arguments:
+
+ String - Supplies a buffer to return the string into.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ return ReadLine(String);
+}
+
+
+BOOLEAN
+STREAM_MESSAGE::WaitForUserSignal(
+ )
+/*++
+
+Routine Description:
+
+ This routine waits for a signal from the user.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ DSTRING string;
+
+ return (BOOLEAN) (Flush() && ReadLine(&string));
+}
+
+
+MSGID
+STREAM_MESSAGE::SelectResponse(
+ IN ULONG NumberOfSelections ...
+ )
+/*++
+
+Routine Description:
+
+ This routine queries input from the user in order to determine which
+ message was entered. It then returns the message id of the message
+ entered.
+
+Arguments:
+
+ NumberOfSelections - Supplies the number of message ids.
+ ... - Supplies the message ids.
+
+Return Value:
+
+ The message id of the message entered, or the first message id.
+
+--*/
+{
+ va_list ap;
+ ARRAY lex_array;
+ ARRAY arg_array;
+ PFLAG_ARGUMENT flag_arg;
+ ARGUMENT_LEXEMIZER arg;
+ DSTRING input_string;
+ MSGID first;
+ PITERATOR arg_it;
+ ULONG i;
+ DSTRING match_string;
+ DSTRING del;
+
+ va_start(ap, NumberOfSelections);
+ first = va_arg(ap, MSGID);
+ va_end(ap);
+
+ if (!lex_array.Initialize() || !arg_array.Initialize()) {
+ return first;
+ }
+
+ if (!arg.Initialize(&lex_array)) {
+ return first;
+ }
+
+ arg.SetCaseSensitive(_case_sensitive);
+
+ va_start(ap, NumberOfSelections);
+ for (i = 0; i < NumberOfSelections; i++) {
+ SYSTEM::QueryResourceString(&match_string, va_arg(ap, MSGID), "");
+
+ if (!(flag_arg = NEW FLAG_ARGUMENT) ||
+ !flag_arg->Initialize(&match_string) ||
+ !arg_array.Put(flag_arg)) {
+ va_end(ap);
+ return first;
+ }
+ }
+ va_end(ap);
+
+ Flush();
+
+ if (!ReadLine(&input_string)) {
+ return first;
+ }
+
+ if (!arg.PrepareToParse(&input_string)) {
+ return first;
+ }
+
+ if (!arg.DoParsing(&arg_array)) {
+ return first;
+ }
+
+ arg_it = arg_array.QueryIterator();
+ va_start(ap, NumberOfSelections);
+ for (i = 0; i < NumberOfSelections; i++) {
+ flag_arg = (PFLAG_ARGUMENT) arg_it->GetNext();
+ if (flag_arg->QueryFlag()) {
+ first = va_arg(ap, MSGID);
+ } else {
+ va_arg(ap, MSGID) ? 1 : 0;
+ }
+ DELETE(flag_arg);
+ }
+ va_end(ap);
+
+ DELETE(arg_it);
+
+ return first;
+}
+
+
+PMESSAGE
+STREAM_MESSAGE::Dup(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a new MESSAGE of the same type.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to a new MSG object.
+
+--*/
+{
+ PSTREAM_MESSAGE p;
+
+ if (!(p = NEW STREAM_MESSAGE)) {
+ return NULL;
+ }
+
+ if (!p->Initialize(_out_stream, _in_stream)) {
+ DELETE(p);
+ return NULL;
+ }
+
+ return p;
+}
+
+
+VOID
+STREAM_MESSAGE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns an STREAM_MESSAGE object to its initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _msgid = 0;
+ _msgtype = NORMAL_MESSAGE;
+ _out_stream = NULL;
+ _in_stream = NULL;
+ _err_stream = NULL;
+ _case_sensitive = FALSE;
+ _copy_input = FALSE;
+}
+
+
+BOOLEAN
+STREAM_MESSAGE::ReadLine(
+ OUT PWSTRING String
+ )
+/*++
+
+Routine Description:
+
+ This routine reads a line from the input stream.
+
+Arguments:
+
+ String - Returns the read in string.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ DSTRING del;
+ WCHAR w;
+
+ if (!del.Initialize("\r\n")) {
+ return FALSE;
+ }
+
+ if (_in_stream->IsAtEnd()) {
+ return FALSE;
+ }
+
+ String->Initialize( "" );
+
+ if (!_in_stream->ReadString(String, &del)) {
+ return FALSE;
+ }
+
+ // Line feed is the last character on the line.
+
+ for (;;) {
+ if (_in_stream->IsAtEnd()) {
+ return TRUE;
+ }
+
+ if (!_in_stream->ReadChar(&w)) {
+ return FALSE;
+ }
+
+ if (w == '\n') {
+ break;
+ }
+ }
+
+ if (_copy_input) {
+ _out_stream->WriteString(String, 0, String->QueryChCount());
+ _out_stream->WriteString(&del, 0, del.QueryChCount());
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+STREAM_MESSAGE::Flush(
+ )
+/*++
+
+Routine Description:
+
+ This routine flushes the input stream of all previously typed input.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PKEYBOARD key;
+
+ if (key = KEYBOARD::Cast(_in_stream)) {
+ return key->Flush();
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+STREAM_MESSAGE::DisplayString(
+ )
+/*++
+
+Routine Description:
+
+ This routine prints this objects current string to the
+ appropriate output.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PSTREAM stream;
+
+ if (! (_msgvisual & TEXT_MESSAGE) )
+ {
+ return TRUE;
+ }
+
+ if (_msgtype == ERROR_MESSAGE && _err_stream) {
+ stream = _err_stream;
+ } else {
+ stream = _out_stream;
+ }
+
+ if (!stream->WriteString(&_display_string, 0, TO_END, 40)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/ulib/src/sortcnt.cxx b/private/utils/ulib/src/sortcnt.cxx
new file mode 100644
index 000000000..9d0386b0a
--- /dev/null
+++ b/private/utils/ulib/src/sortcnt.cxx
@@ -0,0 +1,37 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ sortcnt.cxx
+
+Abstract:
+
+ This module contains the definition for the SORTABLE_CONTAINER class.
+
+Author:
+
+ David J. Gilman (davegi) 02-Nov-1990
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "iterator.hxx"
+#include "sortcnt.hxx"
+
+
+DEFINE_CONSTRUCTOR( SORTABLE_CONTAINER, SEQUENTIAL_CONTAINER );
+
+SORTABLE_CONTAINER::~SORTABLE_CONTAINER(
+ )
+{
+}
diff --git a/private/utils/ulib/src/sortlist.cxx b/private/utils/ulib/src/sortlist.cxx
new file mode 100644
index 000000000..c79824d42
--- /dev/null
+++ b/private/utils/ulib/src/sortlist.cxx
@@ -0,0 +1,373 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ sortlist.cxx
+
+Abstract:
+
+ This module contains the definition for the SORTED_LIST class.
+ SORTED_LIST is a concrete implementation of a SORTABLE_CONTAINER, where
+ all the elements are maintained in sorted order.
+
+Author:
+
+ Ramon J. San Andres (ramonsa) 29-Oct-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "sortlist.hxx"
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( SORTED_LIST, SORTABLE_CONTAINER, ULIB_EXPORT );
+
+DEFINE_CAST_MEMBER_FUNCTION( SORTED_LIST );
+
+VOID
+SORTED_LIST::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Constructor for SORTED_LIST
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+}
+
+
+
+
+
+ULIB_EXPORT
+SORTED_LIST::~SORTED_LIST (
+ )
+
+/*++
+
+Routine Description:
+
+ Destructor for SORTED_LIST
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+}
+
+
+
+ULIB_EXPORT
+BOOLEAN
+SORTED_LIST::Initialize (
+ IN BOOLEAN Ascending
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes a SORTED_LIST object.
+
+Arguments:
+
+ Ascending - Supplies ascending flag
+
+Return Value:
+
+ BOOLEAN - TRUE if the SORTED_LIST is successfully initialized.
+
+--*/
+
+{
+ _Ascending = Ascending;
+
+#if DBG==1
+ _IteratorCount = 0;
+#endif
+
+ return _Array.Initialize();
+}
+
+
+
+
+ULIB_EXPORT
+BOOLEAN
+SORTED_LIST::DeleteAllMembers (
+ )
+
+/*++
+
+Routine Description:
+
+ Deletes all the members of the sorted list
+
+Arguments:
+
+ None
+
+Return Value:
+
+ BOOLEAN - TRUE if all members deleted
+
+--*/
+
+{
+ return _Array.DeleteAllMembers();
+}
+
+
+
+
+
+ULIB_EXPORT
+BOOLEAN
+SORTED_LIST::Put (
+ IN OUT POBJECT Member
+ )
+
+/*++
+
+Routine Description:
+
+ Puts an OBJECT in the sorted list, maintaining the list sorted
+
+Arguments:
+
+ Member - Supplies the OBJECT to place in the array
+
+Return Value:
+
+ BOOLEAN - TRUE if member put, FALSE otherwise
+
+--*/
+
+{
+ if ( _Array.QueryMemberCount() > 0 ) {
+ return _Array.Insert( Member, Search( Member, 0, _Array.QueryMemberCount()-1 ) );
+ } else {
+ return _Array.Insert( Member, 0 );
+ }
+}
+
+
+
+
+ULIB_EXPORT
+PITERATOR
+SORTED_LIST::QueryIterator (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Creates an iterator object for this sorted-list.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ PITERATOR - Pointer to an ITERATOR object.
+
+--*/
+
+{
+
+
+
+ return (PITERATOR)_Array.QueryIterator();
+}
+
+
+
+ULIB_EXPORT
+ULONG
+SORTED_LIST::QueryMemberCount (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Obtains the number of elements in the list
+
+Arguments:
+
+ None
+
+Return Value:
+
+ ULONG - The number of members in the list
+
+
+--*/
+
+{
+ return _Array.QueryMemberCount();
+}
+
+
+POBJECT
+SORTED_LIST::Remove (
+ IN OUT PITERATOR Position
+ )
+
+/*++
+
+Routine Description:
+
+ Removes a member from the list
+
+Arguments:
+
+ Position - Supplies an iterator whose currency is to be removed
+
+Return Value:
+
+ POBJECT - The object removed
+
+
+--*/
+
+{
+ return _Array.Remove( Position );
+}
+
+
+
+
+BOOLEAN
+SORTED_LIST::Sort (
+ IN BOOLEAN Ascending
+ )
+
+/*++
+
+Routine Description:
+
+ Sorts the array
+
+Arguments:
+
+ Ascending - Supplies ascending flag
+
+Return Value:
+
+ BOOLEAN - TRUE if array sorted, FALSE otherwise
+
+
+--*/
+
+{
+ if ( ( Ascending == _Ascending ) ||
+ _Array.Sort( Ascending ) ) {
+
+ _Ascending = Ascending;
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+ }
+}
+
+
+
+
+ULONG
+SORTED_LIST::Search(
+ IN PCOBJECT Key,
+ IN ULONG FirstIndex,
+ IN ULONG LastIndex
+ )
+
+/*++
+
+Routine Description:
+
+ Searches an element that matches the supplied key.
+ If no such element is found, this method returns
+ the element one past the largest element less
+ than the given element.
+
+Arguments:
+
+ Key - Supplies the key
+ FirstIndex - Supplies lowerbound for the search
+ LastIndex - Supplies upperbound for the search
+
+Return Value:
+
+ ULONG - Index of the element that matched the key, or
+ LastIndex+1 if no match
+
+--*/
+
+{
+ LONG First, Middle, Last;
+ LONG Match;
+
+ DebugPtrAssert( Key );
+ DebugPtrAssert( FirstIndex < _Array.QueryMemberCount() );
+ DebugPtrAssert( (LastIndex == INVALID_INDEX) ||
+ (LastIndex < _Array.QueryMemberCount()) );
+ DebugPtrAssert( FirstIndex <= LastIndex );
+
+ if (LastIndex == INVALID_INDEX) {
+ return 0;
+ }
+
+ First = FirstIndex;
+ Last = LastIndex;
+ while (First <= Last) {
+ Middle = (First + Last)/2;
+ Match = _Array.CompareAscDesc((POBJECT) Key,
+ _Array.GetAt(Middle),
+ _Ascending);
+
+ if (!Match) {
+ break;
+ }
+
+ if (Match < 0) {
+ Last = Middle - 1;
+ } else {
+ First = ++Middle;
+ }
+ }
+
+ return Middle;
+}
diff --git a/private/utils/ulib/src/sortlit.cxx b/private/utils/ulib/src/sortlit.cxx
new file mode 100644
index 000000000..d9d9dc9cc
--- /dev/null
+++ b/private/utils/ulib/src/sortlit.cxx
@@ -0,0 +1,316 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ sortlit.cxx
+
+Abstract:
+
+ This file contains the definitions for the SORTED_LIST_ITERATOR class.
+ SORTED_LIST_ITERATOR is a concrete implementation of the abstract ITERATOR
+ class.
+
+Author:
+
+ Ramon J. San Andres ( ramonsa) 29-Oct-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "sortlist.hxx"
+#include "sortlit.hxx"
+
+
+DEFINE_CAST_MEMBER_FUNCTION( SORTED_LIST_ITERATOR );
+
+DEFINE_CONSTRUCTOR( SORTED_LIST_ITERATOR, ITERATOR );
+
+
+VOID
+SORTED_LIST_ITERATOR::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Construct a SORTED_LIST_ITERATOR
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _List = NULL;
+}
+
+
+
+SORTED_LIST_ITERATOR::~SORTED_LIST_ITERATOR (
+ )
+/*++
+
+Routine Description:
+
+ Destructor for the SORTED_LIST_ITERATOR class
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+#if DBG==1
+ if ( _List ) {
+ _List->_IteratorCount--;
+ }
+#endif
+}
+
+
+POBJECT
+SORTED_LIST_ITERATOR::FindNext(
+ IN PCOBJECT Key
+ )
+/*++
+
+Routine Description:
+
+ Finds the next object in the list that matches the given key
+
+Arguments:
+
+ Key - Supplies the key
+
+Return Value:
+
+ POBJECT - Pointer to next member of the list that matches the key
+
+--*/
+
+{
+
+ ULONG Index;
+
+ //
+ // Wrap if necessary
+ //
+ if ( _CurrentIndex == INVALID_INDEX ) {
+ _CurrentIndex = 0;
+ }
+
+ //
+ // If we are not at the end of the list, look for the next object
+ // that matches the key.
+ //
+ if ( _CurrentIndex < _List->QueryMemberCount()-1 ) {
+
+ Index = _List->Search( Key, _CurrentIndex+1, _List->QueryMemberCount()-1 );
+
+ //
+ // If an object was found, set our currency and return the object
+ //
+ if ( Index < _List->QueryMemberCount() &&
+ !Key->Compare(_List->_Array.GetAt( Index ))) {
+
+ _CurrentIndex = Index;
+ return _List->_Array.GetAt( Index );
+ }
+ }
+
+ //
+ // No match, return NULL
+ //
+ _CurrentIndex = INVALID_INDEX;
+ return NULL;
+}
+
+
+POBJECT
+SORTED_LIST_ITERATOR::GetCurrent(
+ )
+/*++
+
+Routine Description:
+
+ Gets current member
+
+Arguments:
+
+ None
+
+Return Value:
+
+ POBJECT - Pointer to current member in the array
+
+--*/
+
+{
+ if ( _CurrentIndex == INVALID_INDEX ) {
+ return NULL;
+ } else {
+ return _List->_Array.GetAt( _CurrentIndex );
+ }
+}
+
+
+
+
+POBJECT
+SORTED_LIST_ITERATOR::GetNext(
+ )
+/*++
+
+Routine Description:
+
+ Gets next member in the array
+
+Arguments:
+
+ None
+
+Return Value:
+
+ POBJECT - Pointer to next member in the array
+
+--*/
+
+{
+ //
+ // Wrap if necessary. Note that this assumes that INVALID_INDEX + 1 == 0
+ //
+ _CurrentIndex++;
+
+ if ( _CurrentIndex >= _List->_Array.QueryMemberCount() ) {
+ _CurrentIndex = INVALID_INDEX;
+ }
+
+ //
+ // Get next
+ //
+ return _List->_Array.GetAt( _CurrentIndex );
+}
+
+
+POBJECT
+SORTED_LIST_ITERATOR::GetPrevious(
+ )
+/*++
+
+Routine Description:
+
+ Gets previous member in the array
+
+Arguments:
+
+ None
+
+Return Value:
+
+ POBJECT - Pointer to previous member in the array
+
+--*/
+
+{
+ //
+ // Wrap if necessary. Note that this assumes that 0 - 1 == INVALID_INDEX
+ //
+ _CurrentIndex--;
+
+ if ( _CurrentIndex == INVALID_INDEX ) {
+ _CurrentIndex = _List->_Array.QueryMemberCount() - 1;
+ }
+
+ //
+ // Get next
+ //
+ return _List->_Array.GetAt( _CurrentIndex );
+}
+
+
+
+VOID
+SORTED_LIST_ITERATOR::Reset(
+ )
+
+/*++
+
+Routine Description:
+
+ Resets the iterator
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ _CurrentIndex = INVALID_INDEX;
+}
+
+
+
+
+BOOLEAN
+SORTED_LIST_ITERATOR::Initialize (
+ IN PSORTED_LIST List
+ )
+
+/*++
+
+Routine Description:
+
+ Associate a SORTED_LIST with this SORTED_LIST_ITERATOR and
+ reset the current index
+
+Arguments:
+
+ List - Supplies pointer to the sorted list object
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the initialization was succesful.
+
+--*/
+
+{
+ DebugPtrAssert( List );
+
+#if DBG==1
+ if ( _List ) {
+ _List->_IteratorCount--;
+ }
+ List->_IteratorCount++;
+#endif
+ _List = List;
+ _CurrentIndex = INVALID_INDEX;
+
+
+ return TRUE;
+}
diff --git a/private/utils/ulib/src/sources b/private/utils/ulib/src/sources
new file mode 100644
index 000000000..d3054eaea
--- /dev/null
+++ b/private/utils/ulib/src/sources
@@ -0,0 +1,139 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=utils
+MINORCOMP=ulib
+
+TARGETNAME=ulib
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib
+DLLENTRY=InitializeUlib
+
+USE_CRTDLL=1
+BLDCRT=1
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=rtmsg.rc \
+ arg.cxx \
+ array.cxx \
+ arrayit.cxx \
+ basesys.cxx \
+ bitvect.cxx \
+ bytestrm.cxx \
+ bufstrm.cxx \
+ clasdesc.cxx \
+ cmem.cxx \
+ comm.cxx \
+ contain.cxx \
+ dir.cxx \
+ file.cxx \
+ filestrm.cxx \
+ filter.cxx \
+ fsnode.cxx \
+ hmem.cxx \
+ iterator.cxx \
+ keyboard.cxx \
+ list.cxx \
+ listit.cxx \
+ machine.cxx \
+ mbstr.cxx \
+ mem.cxx \
+ membmgr.cxx \
+ message.cxx \
+ newdel.cxx \
+ object.cxx \
+ path.cxx \
+ pipe.cxx \
+ pipestrm.cxx \
+ program.cxx \
+ prtstrm.cxx \
+ screen.cxx \
+ seqcnt.cxx \
+ smsg.cxx \
+ sortcnt.cxx \
+ sortlist.cxx \
+ sortlit.cxx \
+ stream.cxx \
+ stringar.cxx \
+ system.cxx \
+ timeinfo.cxx \
+ ulib.cxx \
+ wstring.cxx
+
+i386_SOURCES=i386\dosttr.c
+
+INCLUDES=..\inc
+
+PRECOMPILED_INCLUDE= pch.cxx
+
+#
+# Debug support.
+#
+# We have 4 levels:
+#
+# 1.- FREE: Non-debug
+# 2.- NTDBG: Debug, no memleak
+# 3.- MEMLEAK: 2 + memleak
+# 4.- STACK_TRACE 3 + stack trace
+#
+#
+# By default, whenever the NTDEBUG symbol is defined, you get level
+# 3. In order to get level 2 you have to define the symbol NOMEMLEAK.
+# In order to get level 4, you have to the file the symbol STACK_TRACE
+#
+# In summary here is how to get each one:
+#
+# 1.- Undefine NTDEBUG
+# 2.- define NTDEBUG, define NOMEMLEAK
+# 3.- define NTDEBUG, undefine NOMEMLEAK
+# 4.- define NTDEBUG, undefine NOMEMLEAK, define STACK_TRACE
+#
+NO_NOTHIN=-DNO_COMMDLGH -DNO_LZEXPANDH -DNO_MMSYSTEMH -DNO_NB30H
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1 $(NO_NOTHIN)
+!ELSE # NOMEMLEAK
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1 $(NO_NOTHIN)
+!ELSE # STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1 $(NO_NOTHIN)
+!ENDIF # STACK_TRACE
+!ENDIF # NOMEMLEAK
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1 $(NO_NOTHIN)
+!ENDIF # NTDEBUG
+
+CXXFLAGS=+d
+UMLIBS=obj\*\ulib.lib
+
+UMTYPE=console
+
+UMTEST=
+
+NTTARGETFILE0=..\inc\rtmsg.h
+DLLDEF=
diff --git a/private/utils/ulib/src/spackmsg.cxx b/private/utils/ulib/src/spackmsg.cxx
new file mode 100644
index 000000000..6ee09ebdb
--- /dev/null
+++ b/private/utils/ulib/src/spackmsg.cxx
@@ -0,0 +1,182 @@
+/*++
+
+Copyright (c) 1991-1994 Microsoft Corporation
+
+Module Name:
+
+ spackmsg.cxx
+
+Abstract:
+
+ Contains the implementation of the SP_AUTOCHECK_MESSAGE subclass.
+
+Author:
+
+ Lonny McMichael (lonnym) 09-Jun-94
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "spackmsg.hxx"
+
+
+DEFINE_CONSTRUCTOR(SP_AUTOCHECK_MESSAGE, AUTOCHECK_MESSAGE);
+
+SP_AUTOCHECK_MESSAGE::~SP_AUTOCHECK_MESSAGE(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for SP_AUTOCHECK_MESSAGE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+SP_AUTOCHECK_MESSAGE::Construct(
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the object to a default initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // nothing to do
+ //
+}
+
+
+VOID
+SP_AUTOCHECK_MESSAGE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the object to a default initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // nothing to do
+ //
+}
+
+
+BOOLEAN
+SP_AUTOCHECK_MESSAGE::DisplayV(
+ IN PCSTR Format,
+ IN va_list VarPointer
+ )
+/*++
+
+Routine Description:
+
+ This routine outputs the message to the debugger (if checked build).
+
+ The format string supports all printf options.
+
+Arguments:
+
+ Format - Supplies a printf style format string.
+ VarPointer - Supplies a varargs pointer to the arguments.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ CHAR buffer[256];
+ DSTRING display_string;
+
+ if (!BASE_SYSTEM::QueryResourceStringV(&display_string, _msgid, Format,
+ VarPointer)) {
+ return FALSE;
+ }
+
+ //
+ // Send the output to the debug port.
+ //
+ if( display_string.QuerySTR( 0, TO_END, buffer, 256, TRUE ) ) {
+ DebugPrint(buffer);
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+
+BOOLEAN
+SP_AUTOCHECK_MESSAGE::IsYesResponse(
+ IN BOOLEAN Default
+ )
+/*++
+
+Routine Description:
+
+ This routine queries a response of yes or no.
+
+Arguments:
+
+ Default - Supplies a default in the event that a query is not possible.
+
+Return Value:
+
+ FALSE - The answer is no.
+ TRUE - The answer is yes.
+
+--*/
+{
+ CHAR buffer[256];
+ DSTRING string;
+
+ if (!BASE_SYSTEM::QueryResourceString(&string, Default ? MSG_YES : MSG_NO, "")) {
+ return Default;
+ }
+
+ //
+ // Send the output to the debug port.
+ //
+ if( string.QuerySTR( 0, TO_END, buffer, 256, TRUE ) ) {
+ DebugPrint(buffer);
+ }
+
+ return Default;
+}
+
diff --git a/private/utils/ulib/src/stream.cxx b/private/utils/ulib/src/stream.cxx
new file mode 100644
index 000000000..d6cdc811c
--- /dev/null
+++ b/private/utils/ulib/src/stream.cxx
@@ -0,0 +1,512 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ stream.cxx
+
+Abstract:
+
+ This module contains the definitions of the member functions
+ of STREAM class.
+
+Author:
+
+ Jaime Sasson (jaimes) 24-Mar-1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "mbstr.hxx"
+#include "wstring.hxx"
+#include "stream.hxx"
+#include "system.hxx"
+
+extern "C" {
+ #include <ctype.h>
+}
+
+DEFINE_CONSTRUCTOR ( STREAM, OBJECT );
+
+
+STREAM::~STREAM (
+ )
+
+/*++
+
+Routine Description:
+
+ Destroy a STREAM.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+}
+
+
+
+BOOLEAN
+STREAM::ReadByte(
+ OUT PBYTE Data
+ )
+
+/*++
+
+Routine Description:
+
+ Reads one byte from the stream.
+
+Arguments:
+
+ Data - Address of the variable that will contain the byte read.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the read operation succeeded.
+
+
+--*/
+
+
+{
+ ULONG BytesRead;
+
+ DebugPtrAssert( Data );
+ if( Read( Data, sizeof( BYTE ), &BytesRead ) &&
+ ( BytesRead == sizeof( BYTE ) ) ) {
+ return( TRUE );
+ } else {
+ return( FALSE );
+ }
+}
+
+
+
+ULIB_EXPORT
+BOOLEAN
+STREAM::ReadLine(
+ OUT PWSTRING String,
+ IN BOOLEAN Unicode
+ )
+
+/*++
+
+Routine Description:
+
+ Reads a line from the stream.
+ A line is sequence of WCHARs, terminated by '\n' or '\r\n'.
+ The delimiters are not returned in the string, but are removed
+ from the stream.
+
+Arguments:
+
+ String - Pointer to an initialized string object. This object
+ will contain the string read from the stream, without the
+ delimiters.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeded, and String points to
+ a valid WSTRING.
+ Returns FALSE otherwise.
+
+
+--*/
+
+
+{
+ WCHAR Wchar;
+ CHNUM StringSize;
+
+ DebugPtrAssert( String );
+ //
+ // Read a string from the stream
+ //
+ if( !ReadString( String, &_Delimiter , Unicode) ) {
+ DebugAbort( "ReadString() failed \n" );
+ return( FALSE );
+ }
+ //
+ // If a string was successfully read, then we have to remove the
+ // delimiter from the stream
+ //
+ if( !IsAtEnd() ) {
+ //
+ // Read the delimiter
+ //
+ if( !ReadChar( &Wchar , Unicode) ) {
+ DebugAbort( "ReadChar() failed \n" );
+ return( FALSE );
+ }
+ }
+ // Also, we have to check if last character in the string is \r.
+ // If it is, then we remove it.
+ //
+ StringSize = String->QueryChCount();
+ StringSize--;
+ if( String->QueryChAt( StringSize ) == ( WCHAR )'\r' ) {
+ String->Truncate( StringSize );
+ }
+
+
+/*
+ if( !IsAtEnd() ) {
+ //
+ // Read the first delimiter
+ //
+ if( !ReadChar( &Wchar, Unicode ) ) {
+ DebugAbort( "ReadChar() failed \n" );
+ return( FALSE );
+ }
+ if( Wchar == ( WCHAR )'\r' ) {
+ //
+ // If the delimiter read was '\r' then there is a second
+ // delimiter ('\n') and we have to remove it from the stream
+ //
+ if( !IsAtEnd() ) {
+ if( !ReadChar( &Wchar, Unicode ) ) {
+ DebugAbort( "ReadChar() failed \n" );
+ return( FALSE );
+ }
+ }
+ }
+ }
+*/
+ return( TRUE );
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+STREAM::ReadMbLine(
+ IN PSTR String,
+ IN DWORD BufferSize,
+ INOUT PDWORD StringSize,
+ IN BOOLEAN ExpandTabs,
+ IN DWORD TabExp
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+
+{
+
+ BYTE Char;
+
+
+ DebugPtrAssert( String );
+ DebugPtrAssert( BufferSize );
+ DebugPtrAssert( StringSize );
+
+ //
+ // Read a string from the stream
+ // Note that ReadMbString will remove the delimiter from the stream,
+ // in order to improve performance of FC and Find
+ //
+ if( !ReadMbString( String, BufferSize, StringSize, _MbDelimiter, ExpandTabs, TabExp ) ) {
+ DebugAbort( "ReadMbString() failed \n" );
+ return( FALSE );
+ }
+
+
+ // Also, we have to check if last character in the string is \r.
+ // If it is, then we remove it.
+ //
+ if ( (*StringSize > 0 ) && (String[*StringSize-1] == '\r') ) {
+ (*StringSize)--;
+ String[*StringSize] = '\0';
+ }
+
+ return( TRUE );
+}
+
+
+
+ULIB_EXPORT
+BOOLEAN
+STREAM::ReadWLine(
+ IN PWSTR String,
+ IN DWORD BufferSize,
+ INOUT PDWORD StringSize,
+ IN BOOLEAN ExpandTabs,
+ IN DWORD TabExp
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+
+{
+
+ WCHAR Char;
+
+
+ DebugPtrAssert( String );
+ DebugPtrAssert( BufferSize );
+ DebugPtrAssert( StringSize );
+
+ //
+ // Read a string from the stream
+ // Note that ReadWString will remove the delimiter from the stream,
+ // in order to improve performance of FC and Find
+ //
+ if( !ReadWString( String, BufferSize, StringSize, _WDelimiter, ExpandTabs, TabExp ) ) {
+ DebugAbort( "ReadWString() failed \n" );
+ return( FALSE );
+ }
+
+
+ // Also, we have to check if last character in the string is \r.
+ // If it is, then we remove it.
+ //
+ if ( (*StringSize > 0 ) && (String[*StringSize-1] == L'\r') ) {
+ (*StringSize)--;
+ String[*StringSize] = 0;
+ }
+
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+STREAM::Write(
+ IN PCBYTE Buffer,
+ IN ULONG BytesToWrite,
+ OUT PULONG BytesWritten
+ )
+
+/*++
+
+Routine Description:
+
+ Writes data to the stream.
+
+Arguments:
+
+ Buffer - Points to the buffer that contains the data to be written.
+
+ BytesToWrite - Indicates total number of bytes to write.
+
+ BytesWritten - Points to the variable that will contain the number of
+ bytes actually written.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the write operation succeeded.
+
+
+--*/
+
+
+{
+ DebugPtrAssert( Buffer );
+ DebugPtrAssert( BytesWritten );
+
+ if( QueryAccess() != READ_ACCESS ) {
+ return( WriteFile( QueryHandle(),
+ (LPVOID)Buffer,
+ BytesToWrite,
+ BytesWritten,
+ NULL
+ ) );
+ } else {
+ return( FALSE );
+ }
+}
+
+
+
+ULIB_EXPORT
+BOOLEAN
+STREAM::WriteByte(
+ IN BYTE Data
+ )
+
+/*++
+
+Routine Description:
+
+ Writes one byte to the stream.
+
+Arguments:
+
+ Data - Byte to be written.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the write operation succeeded.
+
+
+--*/
+
+
+{
+ ULONG BytesWritten = 0;
+
+ if( Write( &Data, sizeof( BYTE ), &BytesWritten ) &&
+ ( BytesWritten == sizeof( BYTE ) ) ) {
+ return( TRUE );
+ } else {
+ return( FALSE );
+ }
+}
+
+
+BOOLEAN
+STREAM::WriteChar(
+ IN WCHAR Char
+ )
+
+/*++
+
+Routine Description:
+
+ Writes one character to the stream, Doing wide character - to -
+ multibyte conversion before writting
+
+Arguments:
+
+ Char - Supplies character to be converted and written
+
+Return Value:
+
+ TRUE if character converted and written. FALSE otherwise
+
+
+--*/
+
+
+{
+
+ BYTE Buffer[ 2 ]; // FIX, FIX - can this be anything but 2?
+ USHORT BytesToWrite;
+ ULONG BytesWritten;
+ BOOLEAN Result = FALSE;
+
+ BytesToWrite = (USHORT)wctomb( (char *)Buffer, (wchar_t)Char );
+
+ if ( BytesToWrite > 0 ) {
+
+ Result = Write( Buffer, BytesToWrite, &BytesWritten );
+
+ if ( BytesWritten != BytesToWrite) {
+ Result =FALSE;
+ }
+ }
+
+ return Result;
+}
+
+
+
+BOOLEAN
+STREAM::WriteString(
+ IN PCWSTRING String,
+ IN CHNUM Position,
+ IN CHNUM Length,
+ IN CHNUM Granularity
+ )
+
+/*++
+
+Routine Description:
+
+ Writes a string to the stream.
+
+Arguments:
+
+ String - Pointer to a STRING object.
+ Position - Starting character within the string
+ Length - Number of characters to write
+ Granularity - The maximum number of bytes to write at one time.
+ A value of 0 indicates to write it all at once.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the write operation succeeded.
+
+
+--*/
+
+
+{
+ ULONG BytesWritten = 0;
+ BOOLEAN Result = TRUE;
+ ULONG Size, i, to_write;
+ PBYTE Buffer;
+
+ DebugPtrAssert( String );
+#if defined(DBCS)
+ //
+ // let convert unicode string to oem string with current console codepage.
+ //
+ String->SetConsoleConversions();
+#endif // defined(DBCS)
+ Buffer = (PBYTE)String->QuerySTR( Position, Length );
+
+ Size = strlen((char *)Buffer);
+
+ if (!Granularity) {
+ Granularity = Size;
+ }
+
+ Result = TRUE;
+ for (i = 0; Result && i < Size; i += Granularity) {
+
+ to_write = min(Granularity, Size - i);
+
+ Result = Write( Buffer + i, to_write, &BytesWritten ) &&
+ to_write == BytesWritten;
+ }
+
+#if defined(DBCS)
+ //
+ // Reset/Back to conversion mode.
+ //
+ String->ResetConversions();
+#endif // defined(DBCS)
+
+ FREE( Buffer );
+ return( Result );
+}
diff --git a/private/utils/ulib/src/string.cxx b/private/utils/ulib/src/string.cxx
new file mode 100644
index 000000000..87070a83d
--- /dev/null
+++ b/private/utils/ulib/src/string.cxx
@@ -0,0 +1,84 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ GENERIC_STRING
+
+Abstract:
+
+ This module contains the implementation for the GENERIC_STRING class.
+
+Author:
+
+ Ramon J. San Andres (ramonsa) 07-May-1991
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "string.hxx"
+
+
+DEFINE_CONSTRUCTOR( GENERIC_STRING, OBJECT );
+
+DEFINE_CAST_MEMBER_FUNCTION( GENERIC_STRING );
+
+GENERIC_STRING::~GENERIC_STRING(
+ )
+{
+}
+
+VOID
+GENERIC_STRING::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Constructs a GENERIC_STRING object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+}
+
+BOOLEAN
+GENERIC_STRING::Initialize (
+ )
+
+/*++
+
+Routine Description:
+
+ Phase 2 of construction for a GENERIC_STRING.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ TRUE if the string was successfully initialized,
+ FALSE otherwise.
+
+--*/
+
+{
+ return TRUE;
+}
diff --git a/private/utils/ulib/src/stringar.cxx b/private/utils/ulib/src/stringar.cxx
new file mode 100644
index 000000000..bea260c91
--- /dev/null
+++ b/private/utils/ulib/src/stringar.cxx
@@ -0,0 +1,210 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ stringar.cxx
+
+Abstract:
+
+ This module contains the implementation of the STRING_ARRAY class.
+ STRING_ARRAY is used only to store strings, and it provides a
+ method to sort the strings in ascending or descending order.
+ The sort methods uses the qsort() function of the C run time
+ library.
+
+Author:
+
+ Jaime F. Sasson (jaimes) 01-May-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "array.hxx"
+#include "wstring.hxx"
+#include "stringar.hxx"
+
+#if defined( __BCPLUSPLUS__ )
+
+ #include <search.h>
+
+#else
+
+ extern "C" {
+ #include <search.h>
+ };
+
+#endif // __BCPLUSPLUS__
+
+CHNUM STRING_ARRAY::_Position;
+BOOLEAN STRING_ARRAY::_Ascending;
+
+DEFINE_EXPORTED_CONSTRUCTOR( STRING_ARRAY, ARRAY, ULIB_EXPORT );
+
+
+ULIB_EXPORT
+BOOLEAN
+STRING_ARRAY::Initialize (
+ IN CHNUM Position,
+ IN ULONG Capacity,
+ IN ULONG CapacityIncrement
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize a STRING_ARRAY object by setting it's internal state to s
+ upplied or default values.
+
+Arguments:
+
+ Position - Supplies the position in each string to be used as
+ strating position when sorting the array.
+ Capacity - Supplies the total number of WSTRINGs the
+ STRING_ARRAY can contain.
+ CapacityIncrement - Supplies the number of OBJECTs to make room for
+ when growing the STRING_ARRAY
+
+
+Return Value:
+
+ BOOLEAN - TRUE if the ARRAY is successfully initialized.
+
+--*/
+
+{
+ _Position = Position;
+ return( ARRAY::Initialize( Capacity, CapacityIncrement ) );
+}
+
+
+
+ULIB_EXPORT
+BOOLEAN
+STRING_ARRAY::Sort (
+ BOOLEAN Ascending
+ )
+
+/*++
+
+Routine Description:
+
+ Sorts the array in ascending or descending order, depending
+ on the parameter passed.
+
+Arguments:
+
+ Ascending - Specifies if the sort is to be performed in ascending (TRUE)
+ or descending (FALSE) order.
+
+Return Value:
+
+ BOOLEAN -
+
+--*/
+
+{
+ _Ascending = Ascending;
+
+ qsort( GetObjectArray(),
+ ( size_t )QueryMemberCount(),
+ sizeof( PWSTRING ),
+ &STRING_ARRAY::StringCompare );
+
+ return( TRUE );
+}
+
+
+
+int _CRTAPI1
+STRING_ARRAY::
+StringCompare (
+ IN const void * String1,
+ IN const void * String2
+ )
+
+/*++
+
+Routine Description:
+
+ This function is used by qsort(), and it compares *String1
+ and *String2. The string used as key depends on the value
+ of _Ascending.
+ If _Ascending == TRUE, then it uses *String1 as a key.
+ If _Ascending == FALSE, then it uses *String2 as a key.
+
+Arguments:
+
+ *String1 - Pointer to a string object.
+
+ *String2 - Pointer to a string object.
+
+Return Value:
+
+ Returns:
+
+ if _Ascending == TRUE, then it returns
+ -1 if **String1 is less that **String2
+ 0 if **String1 is equal to **String2
+ 1 if **String1 is greater than **String2
+
+ if _Ascending == FALSE, then it returns
+ -1 if **String2 is less that **String1
+ 0 if **String2 is equal to **String1
+ 1 if **String2 is greater than **String1
+
+--*/
+
+{
+ PCWSTRING St1;
+ PCWSTRING St2;
+ CHNUM Position1;
+ CHNUM Length1;
+ CHNUM Position2;
+ CHNUM Length2;
+// char name[256];
+// LONG result;
+
+ if( _Ascending ) {
+ St1 = *(PCWSTRING *)String1;
+ St2 = *(PCWSTRING *)String2;
+ } else {
+ St1 = *(PCWSTRING *)String2;
+ St2 = *(PCWSTRING *)String1;
+ }
+ Length1 = St1->QueryChCount();
+ Position1 = ( Length1 >= _Position ) ? _Position : Length1;
+ Length1 -= Position1;
+ Length2 = St2->QueryChCount();
+ Position2 = ( Length2 >= _Position ) ? _Position : Length2;
+ Length2 -= Position2;
+/*
+ St1->QueryApiString(name, 256);
+ printf( "Length1 = %d, Position1 = %d, %s \n", Length1, Position1, name );
+ St2->QueryApiString(name, 256);
+ printf( "Length2 = %d, Position2 = %d, %s \n", Length2, Position2, name );
+ result = St1->StringCompare( Position1,
+ Length1,
+ St2,
+ Position2,
+ Length2,
+ CF_IGNORECASE );
+ printf( "Result = %d \n", result );
+ return( result );
+*/
+ return( St1->Stricmp( St2,
+ Position1,
+ Length1,
+ Position2,
+ Length2 ) );
+}
diff --git a/private/utils/ulib/src/substrng.cxx b/private/utils/ulib/src/substrng.cxx
new file mode 100644
index 000000000..982719630
--- /dev/null
+++ b/private/utils/ulib/src/substrng.cxx
@@ -0,0 +1,1197 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ SUB_STRING
+
+Abstract:
+
+ Implementation of the SUB_STRING class.
+
+Author:
+
+ Stve Rowe (stever)
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "substrng.hxx"
+
+
+#if DBG==1
+ #define SUBSTRING_SIGNATURE 0xADDCACA1
+#endif
+
+
+
+
+DEFINE_CONSTRUCTOR( SUB_STRING, GENERIC_STRING );
+
+DEFINE_CAST_MEMBER_FUNCTION( SUB_STRING );
+
+VOID
+SUB_STRING::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Construct a SUBS_TRING by initializing it's internal state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ _BaseString = NULL;
+
+#if DBG==1
+ _Signature = SUBSTRING_SIGNATURE;
+ _Initialized = FALSE;
+#endif
+}
+
+SUB_STRING::~SUB_STRING ()
+
+{
+ Destroy();
+}
+
+VOID
+SUB_STRING::Destroy (
+ )
+
+/*++
+
+Routine Description:
+
+ Detaches this substring from the chain (if it belongs to one).
+
+Arguments:
+
+ none
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ if ( _BaseString != NULL ) {
+ //
+ // We extract ourselves from the substring chain
+ //
+ if (_Previous) {
+
+ //
+ // Update the previous in the chain
+ //
+ DebugAssert( _Previous->_Signature == SUBSTRING_SIGNATURE );
+ _Previous->_Next = _Next;
+
+ }
+
+ if ( _Next ) {
+
+ //
+ // Update the next in the chain
+ //
+ DebugAssert( _Next->_Signature == SUBSTRING_SIGNATURE );
+ _Next->_Previous = _Previous;
+
+ }
+
+ }
+
+ //
+ // Forget everything about our previous life
+ //
+ _BaseString = NULL;
+ _CountOfChars = 0;
+ _StartingPosition = 0;
+ _Next = _Previous = NULL;
+
+#if DBG==1
+ _Initialized = FALSE;
+#endif
+
+}
+
+BOOLEAN
+SUB_STRING::InitializeChainHead (
+ IN PGENERIC_STRING BaseString
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes the substring with a base string. This should be called
+ only for the head of the substring chain.
+
+Arguments:
+
+ BaseString - Supplies pointer to base string
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+ DebugPtrAssert( BaseString );
+
+ DebugAssert( _BaseString == NULL );
+
+ Destroy();
+
+ GENERIC_STRING::Initialize();
+
+ _BaseString = BaseString;
+
+#if DBG==1
+ _Initialized = TRUE;
+#endif
+
+ return TRUE;
+
+}
+
+BOOLEAN
+SUB_STRING::InitializeChainNode (
+ IN OUT PSUB_STRING SubString,
+ IN CHNUM Position,
+ IN CHNUM Length
+ )
+
+/*++
+
+Routine Description:
+
+ Links this substring to a substring chain.
+
+ This method should ONLY be used by a string class, who knows about string
+ chains.
+
+Arguments:
+
+ SubString - Supplies pointer to a substring in the chain.
+ Position - Supplies the starting position value for this substring.
+ Note that this is relative to the BASE string.
+ Length - Supplies Number of Characters in substring.
+
+Return Value:
+
+ TRUE
+
+--*/
+
+{
+
+ //
+ // It is a bug to call this method on a substring that already belongs
+ // to a chain.
+ //
+ DebugAssert( SubString && (SubString->_Signature == SUBSTRING_SIGNATURE) );
+ DebugAssert( _BaseString == NULL );
+
+ Destroy();
+
+ GENERIC_STRING::Initialize();
+
+ //
+ // Initialize our pointers and counters
+ //
+ _StartingPosition = Position;
+ _CountOfChars = Length;
+
+ //
+ // Add ourselves to the substring chain
+ //
+ _BaseString = SubString->_BaseString;
+ _Next = SubString->_Next;
+ _Previous = SubString;
+
+ SubString->_Next = this;
+
+ if (_Next) {
+ DebugAssert( _Next->_Signature == SUBSTRING_SIGNATURE );
+ _Next->_Previous = this;
+ }
+
+#if DBG==1
+ _Initialized = TRUE;
+#endif
+
+ return TRUE;
+
+}
+
+PBYTE
+SUB_STRING::GetInternalBuffer (
+ IN CHNUM Position
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Gets pointer to buffer containing the string.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ Pointer to the buffer
+
+--*/
+{
+
+ DebugAssert( Position < _CountOfChars );
+
+ return _BaseString->GetInternalBuffer( _StartingPosition + Position );
+
+}
+
+BOOLEAN
+SUB_STRING::IsChAt (
+ IN WCHAR Ch,
+ IN CHNUM Position
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Finds out if a certain character is at the specified position.
+
+Arguments:
+
+ Ch - Supplies the character to llok for
+ Position - Supplies the position to look at
+
+Return Value:
+
+ TRUE if the character is at the specified position
+
+--*/
+
+{
+ DebugAssert( _StartingPosition + Position < _CountOfChars );
+
+ return ( QueryChAt( Position ) == Ch );
+
+}
+
+BOOLEAN
+SUB_STRING::MakeNumber (
+ OUT PLONG Number,
+ IN CHNUM Position,
+ IN CHNUM Length
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Converts the string to a number.
+
+Arguments:
+
+ Number - Pointer to returned number
+ Position - Supplies the starting position
+ Length - Supplies the length
+
+
+Return Value:
+
+ TRUE if made a valid number
+ FALSE otherwise
+
+--*/
+
+{
+ GetValidLength( Position, &Length );
+
+ return _BaseString->MakeNumber( Number, _StartingPosition + Position, Length );
+}
+
+ULONG
+SUB_STRING::QueryByteCount (
+ IN CHNUM Position,
+ IN CHNUM Length
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Gets the number of bytes in the buffer containing this substring
+
+Arguments:
+
+ Position - Supplies the starting position
+ Length - Supplies the length
+
+
+Return Value:
+
+ Number of bytes in buffer.
+
+--*/
+
+{
+
+ GetValidLength( Position, &Length );
+
+ return _BaseString->QueryByteCount( _StartingPosition + Position, Length );
+}
+
+CHNUM
+SUB_STRING::QueryChCount (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the number of characters in this substring.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of characters in this substring.
+
+--*/
+
+{
+ DebugAssert( _Initialized );
+ return _CountOfChars;
+}
+
+WCHAR
+SUB_STRING::QueryChAt(
+ IN CHNUM Position
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ returns the character at the supplied position.
+
+Arguments:
+
+ Position - Supplies the character position.
+
+Return Value:
+
+ Returns the character at the supplied position.
+
+--*/
+
+{
+ DebugAssert( Position < _CountOfChars );
+
+ if ( Position < _CountOfChars ) {
+ return _BaseString->QueryChAt( _StartingPosition + Position );
+ } else {
+ return INVALID_CHAR;
+ }
+}
+
+
+PGENERIC_STRING
+SUB_STRING::QueryGenericString(
+ IN CHNUM Position,
+ IN CHNUM Length
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Obtains a string off this substring
+
+Arguments:
+
+ Position - Supplies the character position.
+ Length - Supplies the length of the substring
+
+Return Value:
+
+ Pointer to the string
+
+--*/
+
+{
+ GetValidLength( Position, &Length );
+
+ return _BaseString->QueryGenericString( _StartingPosition + Position, Length );
+
+}
+
+PSTR
+SUB_STRING::QuerySTR(
+ IN CHNUM Position,
+ IN CHNUM Length,
+ IN OUT PSTR Buffer,
+ IN ULONG BufferSize
+ ) CONST
+
+
+
+/*++
+
+Routine Description:
+
+ Obtains a null-terminated multibyte string ( PSTR )
+
+Arguments:
+
+ Position - Supplies starting position
+ Length - Supplies length (in characters) of substring desired
+ Buffer - Supplies optional pointer to buffer
+ BufferSize - Supplies length of the buffer (in bytes)
+
+Return Value:
+
+ Pointer to PSTR
+
+
+--*/
+
+{
+
+ GetValidLength( Position, &Length );
+
+ return _BaseString->QuerySTR( _StartingPosition + Position,
+ Length,
+ Buffer,
+ BufferSize );
+
+
+}
+
+PSUB_STRING
+SUB_STRING::QuerySubString(
+ IN CHNUM Position,
+ IN CHNUM Length,
+ OUT PSUB_STRING SubString
+ )
+
+/*++
+
+Routine Description:
+
+ Obtains a substring of this string
+
+Arguments:
+
+ Position - Supplies the character position.
+ Length - Supplies the length of the substring
+ SubString - Supplies optional pointer to SUB_STRING object
+
+Return Value:
+
+ Pointer to the substring
+
+--*/
+
+{
+ GetValidLength( Position, &Length );
+
+ if (SubString == NULL) {
+ SubString = NEW SUB_STRING;
+ }
+
+ if (SubString) {
+
+ SubString->InitializeChainNode( this, _StartingPosition + Position, Length );
+
+ }
+
+ return SubString;
+
+}
+
+PWSTR
+SUB_STRING::QueryWSTR (
+ IN CHNUM Position,
+ IN CHNUM Length,
+ IN OUT PWSTR Buffer,
+ IN ULONG BufferSize,
+ IN BOOLEAN ForceNull
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Obtains a null-terminated wide character string ( PWSTR )
+
+Arguments:
+
+ Position - Supplies starting position
+ Length - Supplies length (in characters) of substring desired
+ Buffer - Supplies optional pointer to buffer
+ BufferSize - Supplies length of the buffer (in bytes)
+ ForceNull - Supplies a flag which indicates, if TRUE, that the
+ returned string must be null-terminated. If this
+ flag is not FALSE, QueryWSTR will return as much
+ of the string as fits in the buffer; if it is TRUE,
+ QueryWSTR will return as much as fits in the buffer
+ minus one character for the terminating NULL.
+
+
+Return Value:
+
+ Pointer to PWSTR
+
+
+--*/
+
+{
+ GetValidLength( Position, &Length );
+
+ return _BaseString->QueryWSTR( _StartingPosition + Position,
+ Length,
+ Buffer,
+ BufferSize,
+ ForceNull );
+
+}
+
+CHNUM
+SUB_STRING::Strchr (
+ IN WCHAR Char,
+ IN CHNUM Position,
+ IN CHNUM Length
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Searches for first occurence of a character in the string
+
+Arguments:
+
+ Char - Supplies character to match
+ Position - Supplies index of first character where search
+ will start.
+ Length - Supplies length of the subsequence in which to
+ search.
+
+Return Value:
+
+
+ Index within the string where the character was found.
+
+--*/
+
+{
+ CHNUM Pos;
+
+ GetValidLength( Position, &Length );
+
+ Pos = _BaseString->Strchr( Char,
+ _StartingPosition + Position,
+ Length );
+
+ return (Pos == INVALID_CHNUM) ? INVALID_CHNUM : Pos - _StartingPosition;
+
+}
+
+LONG
+SUB_STRING::Strcmp (
+ IN PCGENERIC_STRING GenericString
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Does a case sensitive string compare.
+
+Arguments:
+
+ GenericString - Supplies a pointer to string to compare against
+
+Return Value:
+
+ == 0 - strings are equal
+ <0 - this string is less then StringToCompare
+ >0 - this string is greater then StringToCompare
+
+--*/
+
+{
+ return _BaseString->StringCompare( _StartingPosition,
+ _CountOfChars,
+ GenericString,
+ 0,
+ GenericString->QueryChCount() );
+}
+
+CHNUM
+SUB_STRING::Strcspn (
+ IN PCGENERIC_STRING GenericString,
+ IN CHNUM Position,
+ IN CHNUM Length
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns index of the first character that belongs to the set of
+ characters provided in the generic string.
+
+Arguments:
+
+ GenericString - Supplies the string to match from
+ Position - Supplies position where match should start
+ Length - Supplies the length of the subsequence in which to
+ search.
+
+
+Return Value:
+
+ Index of the character that matched.
+
+--*/
+
+{
+ CHNUM Pos;
+
+ GetValidLength( Position, &Length );
+
+ Pos = _BaseString->Strcspn( GenericString,
+ _StartingPosition + Position,
+ Length );
+
+ return (Pos == INVALID_CHNUM) ? INVALID_CHNUM : Pos - _StartingPosition;
+
+}
+
+LONG
+SUB_STRING::Stricmp (
+ IN PCGENERIC_STRING GenericString
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Does a case insensitive string compare.
+
+Arguments:
+
+ String - Supplies a pointer to string to compare against
+
+Return Value:
+
+ == 0 - strings are equal
+ <0 - this string is less then StringToCompare
+ >0 - this string is greater then StringToCompare
+
+--*/
+
+{
+ return _BaseString->StringCompare( _StartingPosition,
+ _CountOfChars,
+ GenericString,
+ 0,
+ GenericString->QueryChCount(),
+ COMPARE_IGNORECASE );
+}
+
+LONG
+SUB_STRING::StringCompare (
+ IN CHNUM Position1,
+ IN CHNUM Length1,
+ IN PCGENERIC_STRING GenericString2,
+ IN CHNUM Position2,
+ IN CHNUM Length2,
+ IN USHORT CompareFlags
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Compares this string with another one
+
+Arguments:
+
+ Position1 - Supplies Index within this string
+ Length1 - Supplies Length within this string
+ GenericString2 - Supplies other string
+ Position2 - Supplies index within other string
+ Length2 - Supplies length of other string
+ CompareFlags - Supplies compare flags
+
+Return Value:
+
+ < 0 if this string lexically less than other
+ 0 if both strings the same
+ > 0 if other string lexically more than this one
+
+--*/
+{
+ GetValidLength( Position1, &Length1 );
+
+ return _BaseString->StringCompare( _StartingPosition + Position1,
+ Length1,
+ GenericString2,
+ Position2,
+ Length2,
+ CompareFlags );
+}
+
+CHNUM
+SUB_STRING::Strrchr (
+ IN WCHAR Char,
+ IN CHNUM Position,
+ IN CHNUM Length
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Finds last occurrence of the character to match in the string.
+
+Arguments:
+
+ Char - Supplies the character to match
+ Position - Supplies the starting position
+ Length - Supplies length of subsequence in which to search.
+
+Return Value:
+
+ Index of last occurence of the character
+
+--*/
+
+{
+ CHNUM Pos;
+
+ GetValidLength( Position, &Length );
+
+ Pos = _BaseString->Strrchr( Char,
+ _StartingPosition + Position,
+ Length );
+
+ return (Pos == INVALID_CHNUM) ? INVALID_CHNUM : Pos - _StartingPosition;
+}
+
+CHNUM
+SUB_STRING::StrLen (
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the number of characters in this substring.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of characters in this substring.
+
+--*/
+
+{
+ return _CountOfChars;
+}
+
+CHNUM
+SUB_STRING::Strspn (
+ IN PCGENERIC_STRING GenericString,
+ IN CHNUM Position,
+ IN CHNUM Length
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns index of the first character in the string that
+ does not belong to the set of characters in the string to match.
+
+Arguments:
+
+ String - Supplies pointer to string to match from
+ Position - Supplies initial position to start search
+ Length - Supplies length.
+
+Return Value:
+
+ Index of the first character that does not belong to the set
+ of characters in the string passed.
+
+--*/
+
+{
+ CHNUM Pos;
+
+ GetValidLength( Position, &Length );
+
+ Pos = _BaseString->Strspn( GenericString,
+ _StartingPosition + Position,
+ Length );
+
+ return (Pos == INVALID_CHNUM) ? INVALID_CHNUM : Pos - _StartingPosition;
+}
+
+CHNUM
+SUB_STRING::Strstr (
+ IN PCGENERIC_STRING GenericString,
+ IN CHNUM Position,
+ IN CHNUM Length
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Returns the index of the first occurrence of a string within us.
+
+Arguments:
+
+ GenericString - Supplies pointer to string to match from
+ Position - Supplies initial position to start search
+ Length - Supplies the length of the subsequence in which to
+ search.
+
+Return Value:
+
+ Index of first occurence of the string
+
+--*/
+
+{
+
+ CHNUM Pos;
+
+ GetValidLength( Position, &Length );
+
+ Pos = _BaseString->Strstr( GenericString,
+ _StartingPosition + Position,
+ Length );
+
+ return (Pos == INVALID_CHNUM) ? INVALID_CHNUM : Pos - _StartingPosition;
+}
+
+
+BOOLEAN
+SUB_STRING::Replace (
+ IN PCGENERIC_STRING String2,
+ IN CHNUM Position,
+ IN CHNUM Length,
+ IN CHNUM Position2,
+ IN CHNUM Length2
+ )
+
+/*++
+
+Routine Description:
+
+ Illegal method in SUB_STRING
+
+Arguments:
+
+ String2 - Supplies pointer to other string
+ Position - Suplies the starting position to start copy
+ Lengh - Supplies the length of the portion to replace
+ Position2 - Supplies position in other string
+ Length2 - Supplies length to copy
+
+Return Value:
+
+ FALSE
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER( String2 );
+ UNREFERENCED_PARAMETER( Position );
+ UNREFERENCED_PARAMETER( Length );
+ UNREFERENCED_PARAMETER( Position2 );
+ UNREFERENCED_PARAMETER( Length2 );
+
+ DebugAssert( FALSE );
+ return FALSE;
+}
+
+BOOLEAN
+SUB_STRING::SetChAt(
+ IN WCHAR Char,
+ IN CHNUM Position,
+ IN CHNUM Length
+ )
+
+/*++
+
+Routine Description:
+
+ Illegal method in SUB_STRING
+
+Arguments:
+
+ Char - Supplies the character to set.
+ Position - Supplies the character position to set.
+ Length - Supplies the number of characters to set.
+
+Return Value:
+
+ FALSE
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER( Char );
+ UNREFERENCED_PARAMETER( Position );
+ UNREFERENCED_PARAMETER( Length );
+
+ DebugAssert( FALSE );
+ return FALSE;
+
+}
+
+BOOLEAN
+SUB_STRING::Update (
+ IN CHNUM Length
+ )
+
+/*++
+
+Routine Description:
+
+ Updates a substring. When the length of the base string changes, the
+ new length has to be propagated along the substring chain, so that
+ substrings are maintained up-to-date. Each substring is responsible
+ for propagating the new length to its successors in the chain.
+
+
+Arguments:
+
+ Length - Supplies the new length of the base string
+
+
+Return Value:
+
+ TRUE if updated, FALSE otherwise.
+
+--*/
+
+{
+
+ //
+ // Set the new starting position
+ //
+ _StartingPosition = min ( _StartingPosition, Length - 1);
+
+ //
+ // Set the new length
+ //
+ if ( _StartingPosition + _CountOfChars > Length ) {
+
+ _CountOfChars = Length - _StartingPosition;
+ }
+
+ //
+ // Propagate along the chain
+ //
+ if ( _Next ) {
+
+ DebugAssert( _Next->_Signature == SUBSTRING_SIGNATURE );
+ return _Next->Update( Length );
+ }
+
+ return TRUE;
+
+}
+
+
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ DYNAMIC_SUB_STRING
+
+Abstract:
+
+ Implementation of the DYNAMIC_SUB_STRING class.
+
+Author:
+
+ Stve Rowe (stever)
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+DEFINE_CONSTRUCTOR( DYNAMIC_SUB_STRING, SUB_STRING);
+
+VOID
+DYNAMIC_SUB_STRING::Construct (
+ )
+
+{
+ UNREFERENCED_PARAMETER( (void)this );
+}
+
+BOOLEAN
+DYNAMIC_SUB_STRING::Copy (
+ IN PCGENERIC_STRING GenericString
+ )
+/*++
+
+Routine Description:
+
+ Copies one substring to another. The size of the substring changes
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if copied, false otherwise
+
+--*/
+
+{
+
+ DebugPtrAssert( GenericString );
+
+ if ( GetBaseString()->Replace( GenericString,
+ QueryStartingPosition(),
+ QueryChCount(),
+ 0,
+ GenericString->QueryChCount() )) {
+ //
+ // Update the length
+ //
+ SetChCount( GenericString->QueryChCount());
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOLEAN
+DYNAMIC_SUB_STRING::SetChAt(
+ IN WCHAR Char,
+ IN CHNUM Position,
+ IN CHNUM Length
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the specified number of characters, starting at a certain
+ position, with the supplied character.
+
+Arguments:
+
+ Char - Supplies the character to set.
+ Position - Supplies the character position to set.
+ Length - Supplies the number of characters to set.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the characters were succesfully set.
+
+--*/
+
+{
+
+ GetValidLength( Position, &Length );
+
+ return GetBaseString()->SetChAt( Char,
+ QueryStartingPosition() + Position,
+ Length );
+
+}
+
+CHNUM
+DYNAMIC_SUB_STRING::Truncate(
+ IN CHNUM Position
+ )
+
+/*++
+
+Routine Description:
+
+ Truncates the substring at the specified position. The corresponding
+ part of the base string is chopped out.
+
+Arguments:
+
+ Position - Supplies the character position where truncation is to
+ occur.
+
+Return Value:
+
+ CHNUM - Returns new size of the substring
+
+--*/
+
+{
+
+
+ DebugAssert( Position < QueryStartingPosition() + QueryChCount() );
+
+ if ( GetBaseString()->Replace( NULL,
+ QueryStartingPosition() + Position,
+ QueryChCount() - Position,
+ 0,
+ 0 )) {
+ //
+ // Update the length
+ //
+ SetChCount( Position );
+
+ }
+
+ return QueryChCount();
+
+}
diff --git a/private/utils/ulib/src/system.cxx b/private/utils/ulib/src/system.cxx
new file mode 100644
index 000000000..df7d7ec2f
--- /dev/null
+++ b/private/utils/ulib/src/system.cxx
@@ -0,0 +1,1339 @@
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+#include "ulib.hxx"
+#include "system.hxx"
+
+extern "C" {
+ #include <stdio.h>
+ #include <string.h>
+}
+
+#include "dir.hxx"
+#include "file.hxx"
+#include "path.hxx"
+#include "wstring.hxx"
+#include "timeinfo.hxx"
+
+
+
+ULIB_EXPORT
+BOOLEAN
+SYSTEM::IsCorrectVersion (
+ )
+
+/*++
+
+Routine Description:
+
+ Verify that the version of the operating system is correct.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ BOOLEAN - TRUE is the version is correct
+ - FALSE if wrong version
+
+--*/
+
+{
+ // It makes more sense to just allow this binary to run.
+ // Future version of Windows NT will have to be backward
+ // compatible.
+ return TRUE;
+ // return (GetVersion()&0x0000FFFF) == 0x0A03; // Windows 3.10
+}
+
+
+
+ULIB_EXPORT
+PFSN_DIRECTORY
+SYSTEM::MakeDirectory (
+ IN PCPATH Path,
+ IN PCPATH TemplatePath
+ )
+
+/*++
+
+Routine Description:
+
+ Creates a Directory and returs the corresponging FSN_Directory object.
+
+Arguments:
+
+ Path - Supplies the Path of thedirectory to be created.
+ TemplatePath - Supplies the template directory from which to
+ copy alternate data streams.
+
+Return Value:
+
+ PFSN_DIRECTORY - A pointer to the object of the directory created.
+
+--*/
+
+{
+ PCWSTR PathString, TemplateString;
+ BOOL r;
+
+ DebugAssert(Path);
+
+ PathString = Path->GetPathString()->GetWSTR();
+ DebugAssert(PathString);
+ if (TemplatePath) {
+ TemplateString = TemplatePath->GetPathString()->GetWSTR();
+ } else {
+ TemplateString = NULL;
+ }
+
+ if (TemplateString) {
+ r = CreateDirectoryEx((PWSTR) TemplateString, (PWSTR) PathString, NULL);
+ } else {
+ r = CreateDirectory((PWSTR) PathString, NULL);
+ }
+
+ if (!r) {
+ return NULL;
+ }
+
+ return QueryDirectory( Path );
+}
+
+ULIB_EXPORT
+PFSN_FILE
+SYSTEM::MakeFile (
+ IN PCPATH Path
+ )
+
+/*++
+
+Routine Description:
+
+ Creates a File and returs the corresponging FSN_FILE object.
+
+ If the file already exists, its contents are destroyed.
+
+ Note that all the subdirectories along the path must exist (this
+ method does not create directories).
+
+Arguments:
+
+ Path - Supplies the Path of the file to be created.
+
+Return Value:
+
+ PFSN_FILE - A pointer to the FSN_FILE object of the file created.
+
+--*/
+
+{
+
+ HANDLE Handle;
+ PCWSTR PathString;
+ PFSN_FILE File = NULL;
+
+ DebugPtrAssert( Path );
+
+ PathString = Path->GetPathString()->GetWSTR();
+
+ DebugPtrAssert( PathString );
+
+ if ( PathString ) {
+
+ Handle = CreateFile( (LPWSTR) PathString,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ 0 );
+
+
+ DebugAssert( Handle != INVALID_HANDLE_VALUE );
+
+ if ( Handle != INVALID_HANDLE_VALUE ) {
+
+ //
+ // Now that we know that the file exists, we use the
+ // QueryFile method to obtain the FSN_FILE object.
+ //
+ CloseHandle( Handle );
+
+ File = QueryFile( Path );
+
+ }
+ }
+
+ return File;
+
+}
+
+ULIB_EXPORT
+PFSN_FILE
+SYSTEM::MakeTemporaryFile (
+ IN PCWSTRING PrefixString,
+ IN PCPATH Path
+ )
+
+/*++
+
+Routine Description:
+
+ Creates a file with a unique name using the provided path and
+ prefix string. If the path is NULL, then the defult path for
+ temporary files is used.
+
+Arguments:
+
+ PrefixString - Supplies the file prefix used for creating the
+ file name.
+
+ Path - Supplies the Path of the directory to contain the
+ temporary file.
+
+
+Return Value:
+
+ PFSN_FILE - A pointer to the FSN_FILE object of the file created.
+
+--*/
+
+{
+ DWORD BufferSize;
+ LPWSTR TempPath;
+ PCWSTR TempPrefix;
+
+ WCHAR FileName[ MAX_PATH ];
+
+ PFSN_FILE File = NULL;
+ PATH FilePath;
+
+
+ DebugPtrAssert( PrefixString );
+
+ TempPrefix = PrefixString->GetWSTR();
+
+ DebugPtrAssert( TempPrefix );
+
+ if ( TempPrefix ) {
+
+ //
+ // Get the STR representation of the directory for temporary files
+ //
+ if ( !Path ) {
+
+ //
+ // Path not supplied, we will use the default
+ //
+ BufferSize = GetTempPath( 0, NULL );
+ TempPath = (LPWSTR)MALLOC( (unsigned int)BufferSize * 2 );
+
+ if (!GetTempPath( BufferSize, TempPath )) {
+ FREE( TempPath );
+ TempPath = NULL;
+ }
+
+ } else {
+
+ //
+ // We will use the supplied path (and it better exist)
+ //
+ TempPath = Path->GetPathString()->QueryWSTR();
+
+ }
+
+ DebugPtrAssert( TempPath );
+
+ if ( TempPath ) {
+
+ //
+ // Now get the file name of the Temporary File.
+ //
+ if (!GetTempFileName( TempPath, (LPWSTR) TempPrefix, 0, FileName )) {
+ FREE( TempPath );
+ return NULL;
+ }
+
+ //
+ // Now create the file
+ //
+ FilePath.Initialize( FileName );
+
+ File = MakeFile( &FilePath );
+
+ FREE( TempPath );
+
+
+ }
+ }
+
+ return File;
+
+}
+
+ULIB_EXPORT
+BOOLEAN
+SYSTEM::RemoveNode (
+ IN OUT PFSNODE *PointerToNode,
+ IN BOOLEAN Force
+ )
+
+/*++
+
+Routine Description:
+
+ DDeletes nodes and directories.
+
+ Read-only files are deleted only if the supplied "Force" flag
+ is true.
+
+Arguments:
+
+ Node - Supplies a pointer to a pointer to the node
+
+ Force - Supplies a flag which if TRUE means that the file
+ should be deleted even if it is read-only.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the file was deleted successfully.
+
+--*/
+
+{
+
+ PFSN_FILE File;
+ PFSN_DIRECTORY Dir;
+ BOOLEAN ReadOnly;
+ PCWSTR FileName;
+ BOOLEAN Deleted = FALSE;
+
+ DebugPtrAssert( PointerToNode );
+ DebugPtrAssert( *PointerToNode );
+
+
+ File = FSN_FILE::Cast( *PointerToNode );
+
+ if ( File ) {
+
+ //
+ // The node is a file
+ //
+
+ //
+ // We delete the file if it is not read-only or if the Force flag
+ // is set.
+ //
+ if ( Force || !(ReadOnly = File->IsReadOnly()) ) {
+
+ //
+ // If readonly, we reset the read only attribute.
+ //
+ if ( ReadOnly ) {
+
+ File->ResetReadOnlyAttribute();
+
+ }
+
+ //
+ // Now we delete the file
+ //
+ FileName = File->GetPath()->GetPathString()->GetWSTR();
+
+ DebugPtrAssert( FileName );
+
+ if ( FileName ) {
+
+ Deleted = DeleteFile( (LPWSTR) FileName );
+
+ if ( Deleted ) {
+
+ //
+ // The file has been deleted, now we have to get rid of
+ // the file object, which is no longer valid.
+ //
+ DELETE( File );
+ *PointerToNode = NULL;
+
+ }
+ }
+
+ }
+
+ } else {
+
+ Dir = FSN_DIRECTORY::Cast( *PointerToNode );
+
+ if ( Dir ) {
+
+ //
+ // We remove the directory if it is not read-only or if the Force flag
+ // is set.
+ //
+ if ( Force || !(ReadOnly = Dir->IsReadOnly()) ) {
+
+ //
+ // If readonly, we reset the read only attribute.
+ //
+ if ( ReadOnly ) {
+
+ Dir->ResetReadOnlyAttribute();
+
+ }
+
+ //
+ // Now we remove the directory
+ //
+ FileName = Dir->GetPath()->GetPathString()->GetWSTR();
+
+ DebugPtrAssert( FileName );
+
+ if ( FileName ) {
+
+ Deleted = RemoveDirectory( (LPWSTR) FileName );
+
+ if ( Deleted ) {
+
+ //
+ // The directory has been removed, now we have
+ // to get rid of
+ // the directory object, which is no longer valid.
+ //
+ DELETE( Dir );
+ *PointerToNode = NULL;
+
+ }
+ }
+
+ }
+
+ } else {
+
+ DebugAssert( FALSE );
+
+ }
+
+ }
+ return Deleted;
+
+}
+
+ULIB_EXPORT
+PFSN_DIRECTORY
+SYSTEM::QueryDirectory (
+ IN PCPATH Path,
+ IN BOOLEAN GetWhatYouCan
+ )
+
+/*++
+
+Routine Description:
+
+ Construct, initialize and return a FSN_DIRECTORY object.
+
+Arguments:
+
+ Path - Supplies a PATH object to construct as a FSN_DIRECTORY.
+ **** IMPORTANT ****
+ If Path represents a drive (ie, C: ) the it must be terminated
+ by '\'. Otherwise the return value (PFSN_DIRECTORY will
+ contain information about the current directory, and not
+ the root directory.
+
+ GetWhatYouCan - Supplies a flag which if TRUE causes QueryDirectory to
+ backtrack along the path until it finds something
+ that it can open.
+
+Return Value:
+
+ PFSN_DIRECTORY - Returns a pointer to a FSN_DIRECTORY, NULL if the
+ supplied path name does not point to an existing directory.
+
+--*/
+
+{
+ WIN32_FIND_DATA FindData;
+ HANDLE Handle;
+ PPATH TempPath;
+ PFSN_DIRECTORY Directory;
+ PATH Parent;
+ PCWSTRING TempString;
+ PWSTRING DeviceString;
+ BOOLEAN IsRoot;
+ FSTRING TmpString;
+ PCWSTR RootString = NULL;
+ PATH FullPath;
+
+ DebugPtrAssert( Path );
+
+ //
+ // Initialize the FSN_DIRECTORY and PATH pointers
+ //
+ Directory = NULL;
+ TempPath = NULL;
+
+ if ( !Path->HasWildCard() ) {
+
+ //
+ // If the supplied path exists and it references an existing entry
+ // in the file system and it's a directory
+ //
+
+ TempPath = Path->QueryPath();
+ DebugPtrAssert( TempPath );
+ FullPath.Initialize( TempPath, TRUE );
+
+
+ if ( TempPath != NULL ) {
+
+ DeviceString = FullPath.QueryDevice();
+
+ if ( DeviceString ) {
+ IsRoot = (FullPath.IsRoot() || !FullPath.GetPathString()->Stricmp( DeviceString ) );
+ DELETE( DeviceString );
+ } else {
+ IsRoot = TempPath->IsRoot();
+ }
+
+ if( !IsRoot ) {
+ //
+ // If path does not represent the root directory, then let it
+ // call FindFirstFile()
+ //
+ if( ( Handle = FindFirstFile( TempPath, &FindData )) != INVALID_HANDLE_VALUE ) {
+
+ //
+ // Terminate the search
+ //
+ FindClose( Handle );
+
+ if( FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
+
+ if ( !((( Directory = NEW FSN_DIRECTORY ) != NULL ) &&
+ Directory->Initialize( TempPath->GetPathString( ), &FindData ))) {
+
+ DELETE( Directory );
+ }
+ }
+ }
+ } else {
+
+ //
+ // So we have a root directory. We have to determine if it
+ // is a valid drive. We used to call FindFirstFile on it,
+ // but it so happens that FindFirstFile may fail if the
+ // volume in question is empty (we don't even get the
+ // "." or ".." entries!)
+ //
+ if ( TmpString.Initialize( (PWSTR) L"." ) &&
+ TempPath->AppendBase( &TmpString ) &&
+ (RootString = TempPath->GetPathString()->GetWSTR()) &&
+ (GetFileAttributes( (LPWSTR) RootString ) != -1) ) {
+ //
+ // Path represents the root directory. We don't use the information
+ // obtained by FindFirstFile because that refers to the first entry
+ // in the root directory, not the root directory itself.
+ // This is not a bug in the API, but the way it is specified.
+ //
+ // The concept of WIN32_FIND_DATA does not apply to the root directory.
+ // For this reason I will do the initialization of FindData.
+ // Everything in FindData will be initialized, but the FILETIMEs will
+ // be initialized with zero.
+ //
+ // It is important that Path is contains a '\' at the end
+ // if it represents a drive.
+
+ TempPath->TruncateBase();
+
+ FindData.dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
+ FindData.ftCreationTime.dwLowDateTime = 0;
+ FindData.ftCreationTime.dwHighDateTime = 0;
+ FindData.ftLastAccessTime.dwLowDateTime = 0;
+ FindData.ftLastAccessTime.dwHighDateTime = 0;
+ FindData.ftLastWriteTime.dwLowDateTime = 0;
+ FindData.ftLastWriteTime.dwHighDateTime = 0;
+ FindData.nFileSizeHigh = 0;
+ FindData.nFileSizeLow = 0;
+
+ TempString = TempPath->GetPathString();
+ DebugPtrAssert( TempString );
+ TempString->QueryWSTR( 0, TO_END, (LPWSTR)FindData.cFileName, MAX_PATH );
+ if ( !((( Directory = NEW FSN_DIRECTORY ) != NULL ) &&
+ Directory->Initialize( TempPath->GetPathString( ), &FindData ))) {
+
+ DELETE( Directory );
+ }
+ }
+ }
+ }
+
+ DELETE( TempPath );
+ }
+
+ if (!Directory && GetWhatYouCan && !Path->IsDrive() && !Path->IsRoot()) {
+ //
+ // The path is not that of an existing directory.
+ // take off the base and try again.
+ //
+ Parent.Initialize( Path );
+ Parent.TruncateBase();
+
+ Directory = QueryDirectory( &Parent, GetWhatYouCan );
+ }
+
+ return Directory;
+}
+
+
+
+ULIB_EXPORT
+PPATH
+SYSTEM::QuerySystemDirectory (
+ )
+
+/*++
+
+Routine Description:
+
+ Returns the directory where the system files are located.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ PPATH - Path of the system directory.
+
+--*/
+
+{
+ WCHAR Buffer[MAX_PATH];
+ DSTRING PathName;
+ PPATH Path = NULL;
+ DWORD Cb;
+
+ Cb = GetSystemDirectory( Buffer, MAX_PATH );
+
+ if ( (Cb != 0) || (Cb < MAX_PATH) ) {
+
+ if ( !PathName.Initialize( (PWSTR)Buffer) ||
+ !(Path = NEW PATH) ||
+ !Path->Initialize( &PathName )
+ ) {
+
+ DELETE( Path );
+
+ }
+ }
+
+ return Path;
+}
+
+
+
+const MaxEnvVarLen = 256;
+
+ULIB_EXPORT
+PWSTRING
+SYSTEM::QueryEnvironmentVariable (
+ IN PCWSTRING Variable
+ )
+
+/*++
+
+Routine Description:
+
+ Obtains the value of an environment variable
+
+Arguments:
+
+ Variable - Supplies the variable to look for
+
+Return Value:
+
+ Value of the environment variable, NULL if not defined
+
+--*/
+
+{
+
+ PCWSTR Buffer;
+ WCHAR Value[MaxEnvVarLen];
+ PWSTRING pString;
+ ULONG ValueLength;
+
+ if (!Variable) {
+ return NULL;
+ }
+
+ //
+ // Get the ApiString of the variable to look for
+ //
+ Buffer = Variable->GetWSTR();
+
+ //
+ // Look for the variable
+ //
+ ValueLength = GetEnvironmentVariable( (LPWSTR) Buffer, Value, MaxEnvVarLen );
+
+ if ( ValueLength == 0 ) {
+
+ //
+ // The environment variable is not defined
+ //
+ return NULL;
+ }
+
+ //
+ // Got the value, form a string with it and return it
+ //
+ if ( (pString = NEW DSTRING) != NULL ) {
+
+ if (pString->Initialize( Value )) {
+
+ return pString;
+
+ }
+
+ DELETE( pString );
+ }
+
+ return NULL;
+
+}
+
+ULIB_EXPORT
+PPATH
+SYSTEM::SearchPath(
+ PWSTRING pFileName,
+ PWSTRING pSearchPath
+ )
+/*++
+
+Routine Description:
+
+ Search a given path for a file name. If the input path is NULL, the
+ routine searches the default path.
+
+Arguments:
+
+ pSearchPath - Supplies a set of semicolon terminated paths.
+ pFileName - The name of the file to search for.
+
+Return Value:
+
+ A pointer to a path containing the first occurance of pFileName. If the
+ name isn't found, the path is NULL.
+
+--*/
+{
+ CHNUM cb;
+ WSTR ReturnPath[ MAX_PATH + 1 ];
+ PPATH pFullPath;
+ LPWSTR pFilePart;
+ PCWSTR pPath;
+ PCWSTR pName;
+
+ if( pSearchPath != NULL ) {
+ // Extract the path from pSearchPath for the API call...
+ pPath = pSearchPath->GetWSTR();
+ } else {
+ pPath = NULL;
+ }
+ if( pFileName == NULL ) {
+ DebugPrint( "The input filename is NULL - Can't find it...\n" );
+ return( NULL );
+ }
+ // Extract the filename from the pFileName string...
+ pName = pFileName->GetWSTR();
+
+ //
+ // Call the API ...
+ //
+ cb = ::SearchPath( (LPWSTR) pPath,
+ (LPWSTR) pName,
+ NULL, // The extension must be specified as part of the file name...
+ MAX_PATH,
+ ReturnPath,
+ &pFilePart
+ );
+
+
+ if( !cb ) {
+ DebugPrint( "File name not found...\n" );
+ return( NULL );
+ }
+
+ //
+ // Create a new path and Initialize it with the buffer resulting
+ //
+ if( ( pFullPath = NEW PATH ) == NULL ) {
+ DebugPrint( "Unable to allocate the path to return the data...\n" );
+ return( NULL );
+ }
+
+ if( !pFullPath->Initialize( ReturnPath, FALSE ) ) {
+ DebugPrint( "Unable to initialize the new path!\n" );
+ return( NULL );
+ }
+
+ //
+ // The path should now be constucted...
+ //
+ return( pFullPath );
+}
+
+ULIB_EXPORT
+PFSN_FILE
+SYSTEM::QueryFile (
+ IN PCPATH Path
+ )
+
+/*++
+
+Routine Description:
+
+ Construct, initialize and return a FSN_FILE object.
+
+Arguments:
+
+ Path - Supplies a PATH object to construct as a FSN_FILE.
+
+Return Value:
+
+ A pointer to a FSN_FILE.
+
+--*/
+
+{
+
+ PFSN_FILE File = NULL;
+ PPATH FullPath = NULL;
+ HANDLE Handle;
+ WIN32_FIND_DATA FindData;
+
+ DebugPtrAssert( Path );
+
+ if ( Path &&
+ !Path->HasWildCard() &&
+ ((FullPath = Path->QueryFullPath()) != NULL ) &&
+ ((Handle = FindFirstFile( FullPath, &FindData )) != INVALID_HANDLE_VALUE) ) {
+
+ FindClose( Handle );
+
+ if( !(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) {
+
+ if ((File = NEW FSN_FILE) != NULL) {
+ if ( !(File->Initialize(FullPath->GetPathString(), &FindData)) ) {
+ DELETE( File );
+ File = NULL;
+ }
+ }
+ }
+ }
+
+ DELETE( FullPath );
+
+ return File;
+}
+
+
+BOOLEAN
+SYSTEM::PutStandardStream(
+ IN DWORD StdHandle,
+ IN PSTREAM pStream
+ )
+/*++
+
+Routine Description:
+
+ Redirect a standard stream.
+
+Arguments:
+
+ StdHandle - An identifier for the Standard Handle to modify.
+ pStream - The standard stream is redirected to this stream.
+
+Return Value:
+
+ TRUE if successful.
+
+--*/
+{
+ //
+ // First, set the system standard handle to the stream
+ //
+ if( !SetStdHandle( StdHandle, pStream->QueryHandle() ) ) {
+ DebugPrint( "Unable to redirect the system handle - nothing changed!\n" );
+ return( FALSE );
+ }
+
+
+ //
+ // Get a pointer to the stream to change...
+ //
+ switch( StdHandle ) {
+ case STD_INPUT_HANDLE:
+ Standard_Input_Stream = pStream;
+ break;
+ case STD_OUTPUT_HANDLE:
+ Standard_Output_Stream = pStream;
+ break;
+ case STD_ERROR_HANDLE:
+ Standard_Error_Stream = pStream;
+ break;
+ default:
+ DebugPrint( "Unrecognized Standard Handle Type - Returning Error!\n" );
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+SYSTEM::QueryCurrentDosDriveName(
+ OUT PWSTRING DosDriveName
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the name of the current drive.
+
+Arguments:
+
+ DosDriveName - Returns the name of the current drive.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PATH path;
+ PWSTRING p;
+
+ if (!path.Initialize( (LPWSTR)L"foo", TRUE)) {
+ return FALSE;
+ }
+
+ if (!(p = path.QueryDevice())) {
+ return FALSE;
+ }
+
+ if (!DosDriveName->Initialize(p)) {
+ return FALSE;
+ }
+
+ DELETE(p);
+
+ return TRUE;
+}
+
+
+ULIB_EXPORT
+DRIVE_TYPE
+SYSTEM::QueryDriveType(
+ IN PCWSTRING DosDriveName
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the type of drive pointed to by 'DosDriveName'.
+
+Arguments:
+
+ DosDriveName - Supplies the dos name of the drive.
+
+Return Value:
+
+ The type of drive that is pointed to by 'DosDriveName'.
+
+--*/
+{
+ DSTRING wstring;
+ DSTRING slash;
+ PCWSTR p;
+ DRIVE_TYPE r;
+
+ if (!wstring.Initialize(DosDriveName)) {
+ return UnknownDrive;
+ }
+
+ if (!slash.Initialize("\\")) {
+ return UnknownDrive;
+ }
+
+ wstring.Strcat(&slash);
+
+ if (!(p = wstring.GetWSTR())) {
+ return UnknownDrive;
+ }
+
+ switch (GetDriveType((LPWSTR) p)) {
+ case DRIVE_REMOVABLE:
+ r = RemovableDrive;
+ break;
+
+ case DRIVE_FIXED:
+ r = FixedDrive;
+ break;
+
+ case DRIVE_REMOTE:
+ r = RemoteDrive;
+ break;
+
+ case DRIVE_CDROM:
+ r = CdRomDrive;
+ break;
+
+ case DRIVE_RAMDISK:
+ r = RamDiskDrive;
+ break;
+
+ default:
+ r = UnknownDrive;
+ break;
+
+ }
+
+ return r;
+}
+
+ULIB_EXPORT
+FILE_TYPE
+SYSTEM::QueryFileType(
+ IN PCWSTRING DosFileName
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the type of filee pointed to by 'DosFileName'.
+
+Arguments:
+
+ DosFileName - Supplies the dos name of the file.
+
+Return Value:
+
+ The type of file that is pointed to by 'DosFileName'.
+
+--*/
+{
+ DSTRING wstring;
+ PCWSTR p;
+ FILE_TYPE r;
+ HANDLE Handle;
+
+ if (!wstring.Initialize(DosFileName)) {
+ return UnknownFile;
+ }
+
+ if (!(p = wstring.GetWSTR())) {
+ return UnknownFile;
+ }
+
+ Handle = CreateFile( (LPWSTR) p,
+ GENERIC_READ,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ NULL );
+
+ if ( Handle != INVALID_HANDLE_VALUE ) {
+
+ switch ( GetFileType( Handle ) ) {
+
+ case FILE_TYPE_DISK:
+ r = DiskFile;
+ break;
+
+ case FILE_TYPE_CHAR:
+ r = CharFile;
+ break;
+
+ case FILE_TYPE_PIPE:
+ r = PipeFile;
+ break;
+
+ default:
+ r = UnknownFile;
+ break;
+
+ }
+
+ CloseHandle( Handle );
+
+ } else {
+
+ r = UnknownFile;
+ }
+
+ return r;
+}
+
+
+
+ULIB_EXPORT
+PWSTRING
+SYSTEM::QueryVolumeLabel(
+ IN PPATH Path,
+ OUT PVOL_SERIAL_NUMBER VolSerialNumber
+ )
+/*++
+
+Routine Description:
+
+ Returns the name and serial number of a volume.
+
+Arguments:
+
+ Path - Path in the file system whose volume information is to be
+ retrieved.
+
+ VolSerialNumber - Pointer to a structure that will contain the
+ serial number
+
+Return Value:
+
+ PWSTRING - Pointer to a WSTRING that will contain the volume name, or
+ NULL if an error occurs.
+
+
+--*/
+{
+ PWSTRING VolumeName;
+ PWSTRING RootString;
+ PCWSTR RootName;
+ WCHAR VolumeNameBuffer[ MAX_PATH ];
+ ULONG SerialNumber[2];
+
+ DebugPtrAssert( Path );
+ DebugPtrAssert( VolSerialNumber );
+ RootString = Path->QueryRoot();
+ DebugPtrAssert( RootString );
+ RootName = RootString->GetWSTR();
+ if( !GetVolumeInformation( (LPWSTR) RootName,
+ (LPWSTR)VolumeNameBuffer,
+ MAX_PATH,
+ ( PDWORD )SerialNumber,
+ NULL,
+ NULL,
+ NULL,
+ 0 ) ) {
+ DELETE( RootString );
+ return( NULL );
+ }
+ VolSerialNumber->LowOrder32Bits = SerialNumber[ 0 ];
+ VolSerialNumber->HighOrder32Bits = SerialNumber[ 1 ];
+ VolumeName=NEW( DSTRING );
+ DebugPtrAssert( VolumeName );
+ VolumeName->Initialize( VolumeNameBuffer );
+ DELETE( RootString );
+ return( VolumeName );
+}
+
+
+
+const MaximumLibraryNameLength = 256;
+const MaximumEntryPointNameLength = 128;
+
+ULIB_EXPORT
+FARPROC
+SYSTEM::QueryLibraryEntryPoint(
+ IN PCWSTRING LibraryName,
+ IN PCWSTRING EntryPointName,
+ OUT PHANDLE LibraryHandle
+ )
+/*++
+
+Routine Description:
+
+ Loads a dynamically-linked library and returns an
+ entry point into it.
+
+Arguments:
+
+ LibraryName -- name of the library to load
+
+ EntryPointName -- name of the entry point to get
+
+ LibraryHandle -- receives handle of loaded library
+
+Return Value:
+
+ Pointer to the requested function; NULL to indicate failure.
+
+--*/
+{
+ WCHAR AnsiLibraryName[MaximumLibraryNameLength+1];
+ CHAR AnsiEntryPointName[MaximumEntryPointNameLength+1];
+ FARPROC EntryPoint;
+
+
+ LibraryName->QueryWSTR( 0, TO_END, AnsiLibraryName, MaximumLibraryNameLength + 1);
+
+ EntryPointName->QuerySTR( 0, TO_END, AnsiEntryPointName,
+ MaximumEntryPointNameLength + 1 );
+
+ if( (*LibraryHandle = (HANDLE)LoadLibrary( AnsiLibraryName )) != NULL &&
+ (EntryPoint = GetProcAddress( (HINSTANCE)*LibraryHandle,
+ (LPSTR)AnsiEntryPointName )) != NULL ) {
+
+ return EntryPoint;
+
+ } else {
+
+ if( *LibraryHandle != NULL ) {
+
+ FreeLibrary( (HMODULE)*LibraryHandle );
+ *LibraryHandle = NULL;
+ }
+
+ return NULL;
+ }
+}
+
+
+ULIB_EXPORT
+VOID
+SYSTEM::FreeLibraryHandle(
+ HANDLE LibraryHandle
+ )
+/*++
+
+Routine Description:
+
+ Frees a library handle gotten by QueryLibraryEntryPoint
+
+Arguments:
+
+ LibraryHandle -- handle to free
+
+Return Value:
+
+ None.
+
+--*/
+{
+ FreeLibrary( (HMODULE)LibraryHandle );
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+SYSTEM::QueryLocalTimeFromUTime(
+ IN PCTIMEINFO UTimeInfo,
+ OUT PTIMEINFO LocalTimeInfo
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the local time from the given
+ universal time.
+
+Arguments:
+
+ UTimeInfo - Supplies the universal time to convert.
+ LocalTimeInfo - Returns the corresponding local time.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ FILETIME filetime;
+
+ DebugAssert(UTimeInfo->GetFileTime());
+
+ if (!FileTimeToLocalFileTime(UTimeInfo->GetFileTime(), &filetime)) {
+ return FALSE;
+ }
+
+ return LocalTimeInfo->Initialize(&filetime);
+}
+
+
+BOOLEAN
+SYSTEM::QueryUTimeFromLocalTime(
+ IN PCTIMEINFO LocalTimeInfo,
+ OUT PTIMEINFO UTimeInfo
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the universal time from the given
+ local time.
+
+Arguments:
+
+ LocalTimeInfo - Supplies the local time to convert.
+ UTimeInfo - Returns the corresponding universal time.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ FILETIME filetime;
+
+ DebugAssert(LocalTimeInfo->GetFileTime());
+
+ if (!LocalFileTimeToFileTime(LocalTimeInfo->GetFileTime(), &filetime)) {
+ return FALSE;
+ }
+
+ return UTimeInfo->Initialize(&filetime);
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+SYSTEM::QueryWindowsErrorMessage(
+ IN ULONG WindowsErrorCode,
+ OUT PWSTRING ErrorMessage
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the text corresponding to the given
+ windows error message.
+
+Arguments:
+
+ WindowsErrorCode - Supplies the windows error code.
+ ErrorMessage - Returns the error message for this error code.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ WCHAR buffer[MAX_PATH];
+
+ if (!FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL,
+ WindowsErrorCode, 0, buffer, MAX_PATH, NULL)) {
+
+ return FALSE;
+ }
+
+ return ErrorMessage->Initialize(buffer);
+}
diff --git a/private/utils/ulib/src/timeinfo.cxx b/private/utils/ulib/src/timeinfo.cxx
new file mode 100644
index 000000000..7c89b6674
--- /dev/null
+++ b/private/utils/ulib/src/timeinfo.cxx
@@ -0,0 +1,1213 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ time.cxx
+
+Abstract:
+
+ This module contains the definitions of the member functions
+ of TIMEINFO class.
+
+Author:
+
+ Jaime Sasson (jaimes) 13-Mar-1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "wstring.hxx"
+#include "timeinfo.hxx"
+
+extern "C" {
+ #include <stdio.h>
+}
+
+
+//
+// The following two tables map a month index to the number of days preceding
+// the month in the year. Both tables are zero based. For example, 1 (Feb)
+// has 31 days preceding it. To help calculate the maximum number of days
+// in a month each table has 13 entries, so the number of days in a month
+// of index i is the table entry of i+1 minus the table entry of i.
+//
+
+USHORT LeapYearDaysPrecedingMonth[13] = {
+ 0, // January
+ 31, // February
+ 31+29, // March
+ 31+29+31, // April
+ 31+29+31+30, // May
+ 31+29+31+30+31, // June
+ 31+29+31+30+31+30, // July
+ 31+29+31+30+31+30+31, // August
+ 31+29+31+30+31+30+31+31, // September
+ 31+29+31+30+31+30+31+31+30, // October
+ 31+29+31+30+31+30+31+31+30+31, // November
+ 31+29+31+30+31+30+31+31+30+31+30, // December
+ 31+29+31+30+31+30+31+31+30+31+30+31};
+
+USHORT NormalYearDaysPrecedingMonth[13] = {
+ 0, // January
+ 31, // February
+ 31+28, // March
+ 31+28+31, // April
+ 31+28+31+30, // May
+ 31+28+31+30+31, // June
+ 31+28+31+30+31+30, // July
+ 31+28+31+30+31+30+31, // August
+ 31+28+31+30+31+30+31+31, // September
+ 31+28+31+30+31+30+31+31+30, // October
+ 31+28+31+30+31+30+31+31+30+31, // November
+ 31+28+31+30+31+30+31+31+30+31+30, // December
+ 31+28+31+30+31+30+31+31+30+31+30+31};
+
+
+
+//
+// The tables below contain the number of days in each month of
+// a year (leap and normal year)
+//
+
+USHORT LeapYearDaysInMonth[12] = {
+ 31, // January
+ 29, // February
+ 31, // March
+ 30, // April
+ 31, // May
+ 30, // June
+ 31, // July
+ 31, // August
+ 30, // September
+ 31, // October
+ 30, // November
+ 31 // December
+ };
+
+USHORT NormalYearDaysInMonth[12] = {
+ 31, // January
+ 28, // February
+ 31, // March
+ 30, // April
+ 31, // May
+ 30, // June
+ 31, // July
+ 31, // August
+ 30, // September
+ 31, // October
+ 30, // November
+ 31 // December
+ };
+
+
+
+
+DEFINE_EXPORTED_CONSTRUCTOR ( TIMEINFO, OBJECT, ULIB_EXPORT );
+
+VOID
+TIMEINFO::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Contructs a TIMEINFO.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ // unreferenced parameters
+ (void)(this);
+}
+
+
+
+
+BOOLEAN
+TIMEINFO::Initialize(
+ )
+
+/*++
+
+Routine Description:
+
+ This function initializes the data members of TIMEINFO class with
+ the current date and time.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Indicates if the data members were correctly initialized.
+
+
+--*/
+
+
+{
+ SYSTEMTIME st;
+
+ GetSystemTime( &st );
+ return( this->Initialize( &st ) );
+}
+
+
+
+
+ULIB_EXPORT
+BOOLEAN
+TIMEINFO::Initialize(
+ IN PFILETIME FileTime
+ )
+
+/*++
+
+Routine Description:
+
+ This function initializes the data members of TIMEINFO class with
+ the date and time stored in the structured pointed by FileTime.
+
+Arguments:
+
+ FileTime - Pointer to a FILETIME structure that contains the
+ date and time to be used in the initialization of the
+ date members.
+
+Return Value:
+
+ BOOLEAN - Indicates if the data members were correctly initialized.
+
+
+--*/
+
+
+{
+ _FileTime = *FileTime;
+ return( FileTimeToSystemTime( &_FileTime, &_SystemTime ) );
+}
+
+
+BOOLEAN
+TIMEINFO::Initialize(
+ IN PSYSTEMTIME SystemTime
+ )
+
+/*++
+
+Routine Description:
+
+ This function initializes the data members of TIMEINFO class with
+ the date and time stored in the structured pointed by SystemTime.
+
+Arguments:
+
+ SystemTime - Pointer to a SYSTEMTIME structure that contains the
+ date and time to be used in the initialization of the
+ data members.
+
+Return Value:
+
+ BOOLEAN - Indicates if the data members were correctly initialized.
+
+
+--*/
+
+
+{
+ BOOLEAN Result;
+
+ _SystemTime = *SystemTime;
+ Result = (BOOLEAN)SystemTimeToFileTime( &_SystemTime, &_FileTime );
+//
+// The call below is necessary in order to make sure that
+// SystemTime.wDayOfWeek is correctly initialized
+//
+ Result &= FileTimeToSystemTime( &_FileTime, &_SystemTime );
+ return( Result );
+}
+
+
+ULIB_EXPORT
+VOID
+TIMEINFO::Initialize(
+ IN PCTIMEINFO TimeInfo
+ )
+
+/*++
+
+Routine Description:
+
+ This function initializes the data members of TIMEINFO class with
+ the date and time stored in the class pointed by pTimeInfo.
+
+Arguments:
+
+ TimeInfo - Pointer to a TIMEINFO class that contains the
+ date and time to be used in the initialization of the
+ data members in this class.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+
+{
+ _FileTime = TimeInfo->_FileTime;
+ _SystemTime = TimeInfo->_SystemTime;
+}
+
+
+
+BOOLEAN
+TIMEINFO::Initialize(
+ IN USHORT Year,
+ IN USHORT Month,
+ IN USHORT Day,
+ IN USHORT Hour,
+ IN USHORT Minute,
+ IN USHORT Second,
+ IN USHORT Milliseconds
+ )
+
+/*++
+
+Routine Description:
+
+ This function initializes the data members of TIMEINFO class with
+ the date and time information received as parameter.
+
+Arguments:
+
+ Year - A number indicating the year
+ Month - A number indicating the month
+ Day - A number indicating the day
+ Hour - Number of hours
+ Minute - Number of minutes
+ Second - Number of seconds
+ Milliseconds - Number of milliseconds
+
+Return Value:
+
+ BOOLEAN - Indicates if the data members were correctly initialized.
+
+
+--*/
+
+
+{
+ SYSTEMTIME st;
+ st.wYear = Year;
+ st.wMonth = Month;
+ st.wDay = Day;
+ st.wHour = Hour;
+ st.wMinute = Minute;
+ st.wSecond = Second;
+ st.wMilliseconds = Milliseconds;
+
+ return( this->Initialize( &st ) );
+}
+
+
+SHORT
+TIMEINFO::CompareTimeInfo(
+ IN PFILETIME FileTime
+ ) CONST
+
+
+/*++
+
+Routine Description:
+
+ This function compares the date and time information stored in
+ this class, with one pointed by FileTime.
+
+Arguments:
+
+ FileTime - Pointer to a FILETIME structure that contains the
+ date and time to be used in the comparison.
+
+Return Value:
+
+ -1: - Indicates that the time information in this class is less
+ than the time information pointed by FileTime.
+
+ 0: - Indicates that the time information in this class is equal
+ to the time information pointed by FileTime.
+
+ 1: - Indicates that the time information in this class is greater
+ than the time information pointed by FileTime.
+
+
+--*/
+
+{
+ FILETIME ft1;
+
+ ft1 = _FileTime;
+ return( (SHORT)CompareFileTime( &ft1, FileTime ) ) ;
+}
+
+
+
+SHORT
+TIMEINFO::CompareTimeInfo(
+ IN PSYSTEMTIME SystemTime
+ ) CONST
+
+
+/*++
+
+Routine Description:
+
+ This function compares the date and time information stored in
+ this class, with the one pointed by SysteTime.
+
+Arguments:
+
+ SystemTime - Pointer to a FILETIME structure that contains the
+ date and time to be used in the comparison.
+
+Return Value:
+
+ -1: - Indicates that the time information in this class is less
+ than the time information pointed by SystemTime.
+
+ 0: - Indicates that the time information in this class is equal
+ to the time information pointed by SystemTime.
+
+ 1: - Indicates that the time information in this class is greater
+ than the time information pointed by SystemTime.
+
+
+--*/
+
+{
+ FILETIME ft1;
+ FILETIME ft2;
+
+ ft1 = _FileTime;
+ SystemTimeToFileTime( SystemTime, &ft2 );
+ return( (SHORT)CompareFileTime( &ft1, &ft2 ) );
+}
+
+
+
+USHORT
+TIMEINFO::QueryDayOffset(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ This function determines the offset in year of the day stored in
+ this class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ USHORT - Offset in year of the current day.
+
+
+--*/
+
+{
+ USHORT Offset;
+
+ if( IsLeapYear( (USHORT)_SystemTime.wYear ) ) {
+ Offset = LeapYearDaysPrecedingMonth[ _SystemTime.wMonth ];
+ }
+ else {
+ Offset = NormalYearDaysPrecedingMonth[ _SystemTime.wMonth ];
+ }
+ Offset += _SystemTime.wDay;
+ return( Offset );
+}
+
+
+
+USHORT
+TIMEINFO::QueryDaysInMonth(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ This function determines the number of days in the month of the
+ date stored in this class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ USHORT - Number of days in the month.
+
+
+--*/
+
+{
+ USHORT NumberOfDays;
+
+ if( IsLeapYear( (USHORT)_SystemTime.wYear ) ) {
+ NumberOfDays = LeapYearDaysInMonth[ _SystemTime.wMonth ];
+ }
+ else {
+ NumberOfDays = NormalYearDaysInMonth[ _SystemTime.wMonth ];
+ }
+ return( NumberOfDays );
+}
+
+
+
+USHORT
+TIMEINFO::QueryDaysInYear(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ This function determines the total number of days in the year
+ stored in this class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ USHORT - Number of days in the year.
+
+
+--*/
+
+{
+ if( IsLeapYear( (USHORT)_SystemTime.wYear ) ) {
+ return( LeapYearDaysPrecedingMonth[ 12 ] );
+ }
+ else {
+ return( NormalYearDaysPrecedingMonth[ 12 ] );
+ }
+}
+
+
+
+BOOLEAN
+TIMEINFO::SetDate(
+ USHORT Year,
+ USHORT Month,
+ USHORT Day
+ )
+
+/*++
+
+Routine Description:
+
+ This function sets the date of the TIMEINFO object (the time
+ remains unchanged).
+
+Arguments:
+
+ Year - A number that indicates the year.
+ Month - A number that indicates the month.
+ Day - A number that indicates the day.
+
+Return Value:
+
+ BOOLEAN - A boolean value indicating if the date was set correctly.
+
+
+--*/
+
+{
+ SYSTEMTIME TempSystemTime;
+
+ TempSystemTime = _SystemTime;
+ TempSystemTime.wYear = Year;
+ TempSystemTime.wMonth = Month;
+ TempSystemTime.wDay = Day;
+ return( this->Initialize( &TempSystemTime ) );
+}
+
+
+
+BOOLEAN
+TIMEINFO::SetDate(
+ PCWSTRING Date
+ )
+
+/*++
+
+Routine Description:
+
+ This function sets the date of a TIMEINFO object (the time remains
+ unchanged).
+
+Arguments:
+
+ Date - A string that contains the date.
+
+Return Value:
+
+ BOOLEAN - A boolean value indicating if the date was set correctly.
+
+Notes:
+
+ BUGBUG - jaimes - 05/10/91
+
+ THE CURRENT IMPLEMENTATION IS JUST A TEMPORARY ONE, UNTIL WE HAVE
+ THE WINNLS APIs READY.
+ THE IMPLEMENTATION BELOW ASSUMES THAT THE DATE REPRESENTED IN THE
+ STRING HAS THE FORM: m-d-y or m/d/y, where:
+
+ m: represents the month (1 or 2 characters);
+ d: represents the day (1 or 2 characters);
+ y: represents the year (any number of characters)
+
+
+--*/
+
+{
+ SYSTEMTIME TempSystemTime;
+ CHNUM FirstDelimiter;
+ CHNUM SecondDelimiter;
+ FSTRING Delimiters;
+ USHORT Day;
+ USHORT Month;
+ USHORT Year;
+ BOOLEAN IsNumber;
+ LONG Number;
+
+
+ //
+ // Check if the string is a valid one ( must contain two separators )
+ //
+ if( !Delimiters.Initialize( (PWSTR) L"/-" ) ) {
+ return( FALSE );
+ }
+ if( ( FirstDelimiter = Date->Strcspn( &Delimiters ) ) == INVALID_CHNUM ) {
+ return( FALSE );
+ }
+ if( ( SecondDelimiter = Date->Strcspn( &Delimiters,
+ FirstDelimiter + 1 ) ) == INVALID_CHNUM ) {
+ return( FALSE );
+ }
+ if( Date->Strcspn( &Delimiters, SecondDelimiter + 1 ) != INVALID_CHNUM ) {
+ return( FALSE );
+ }
+ //
+ // At this point we know that the string has two delimiters and
+ // three numeric fields.
+ // We now have to extract the numbers that represent the date,
+ // and validate these numbers.
+ //
+
+ if (!(IsNumber = Date->QueryNumber(&Number, 0, FirstDelimiter ))) {
+ return FALSE;
+ }
+ Month = (USHORT)Number;
+
+ if (!(IsNumber = Date->QueryNumber(&Number, FirstDelimiter+1, SecondDelimiter-FirstDelimiter-1))) {
+ return FALSE;
+ }
+ Day = (USHORT)Number;
+
+ if (!(IsNumber = Date->QueryNumber(&Number, SecondDelimiter+1))) {
+ return FALSE;
+ }
+ Year = (USHORT)Number;
+
+ if( ( Month == 0 ) || ( Month > 12 ) ) {
+ return( FALSE );
+ }
+ //
+ // Years in the range 00 - 79 are transformed to 2000-2079
+ // Years in the range 80 - 99 are transformed to 1980-1999
+ if( ( Year >= 80 ) && ( Year < 100 ) ) {
+ Year += 1900;
+ } else {
+ if( Year <= 79 ) {
+ Year += 2000;
+ }
+
+ }
+ if( ( Day > 31 ) ||
+ ( ( Day == 31 ) && ( ( Month % 2 ) == 0 ) && ( Month != 8 ) ) ||
+ ( ( Day == 29 ) && (Month == 2) && IsLeapYear( Year ) ) ) {
+ return( FALSE );
+ }
+
+ TempSystemTime = _SystemTime;
+ TempSystemTime.wYear = ( USHORT )Year;
+ TempSystemTime.wMonth = ( USHORT )Month;
+ TempSystemTime.wDay = ( USHORT )Day;
+ return( this->Initialize( &TempSystemTime ) );
+}
+
+
+BOOLEAN
+TIMEINFO::SetDateAndTime (
+ IN PCWSTRING DateAndTime
+ )
+
+/*++
+
+Routine Description:
+
+ This function sets the date or time of a TIMEINFO object.
+
+Arguments:
+
+ DateAndTime - A string that contains the date or time.
+
+Return Value:
+
+ BOOLEAN - A boolean value indicating if the date or time was set
+ correctly.
+
+Notes:
+
+ BUGBUG - ramonsa - 05/10/91
+
+ THIS IMPLEMENTATION SETS ONLY THE DATE OR THE TIME, BUT NOT BOTH.
+ IT RELIES ON HACKS UNTIL THE WINNLS SUPPORT IS AVAILABLE FOR
+ TRANSFORMING STRINGS INTO DATES AND TIMES.
+
+--*/
+
+{
+ if( DateAndTime->Strchr( (WCHAR)':' ) == INVALID_CHNUM ) {
+ //
+ // We assume that we have a date
+ //
+ if( !SetDate( DateAndTime ) ) {
+ return( FALSE );
+ }
+ //
+ // Sets the time to the earliest time in the day
+ //
+ return( SetTime( 0, 0, 0, 0 ) );
+ } else {
+ //
+ // We assume that we have a time
+ //
+ return SetTime( DateAndTime );
+ }
+}
+
+
+BOOLEAN
+TIMEINFO::SetTime(
+ USHORT Hour,
+ USHORT Minute,
+ USHORT Second,
+ USHORT Milliseconds
+ )
+
+/*++
+
+Routine Description:
+
+ This function sets the time of of a TIMEINFO object (the date
+ remains unchanged).
+
+Arguments:
+
+ Hour - Number of hours.
+ Minute - Number of minutes.
+ Second - Number of seconds.
+ Milliseconds - Number of milliseconds
+
+Return Value:
+
+ BOOLEAN - A boolean value indicating if the time was set correctly.
+
+
+--*/
+
+{
+ SYSTEMTIME TempSystemTime;
+
+ TempSystemTime = _SystemTime;
+ TempSystemTime.wHour = Hour;
+ TempSystemTime.wMinute = Minute;
+ TempSystemTime.wSecond = Second;
+ TempSystemTime.wMilliseconds = Milliseconds;
+ return( this->Initialize( &TempSystemTime ) );
+}
+
+
+
+BOOLEAN
+TIMEINFO::SetTime(
+ PCWSTRING Time
+ )
+
+/*++
+
+Routine Description:
+
+ This function sets the time of a TIMEINFO object (the date remains
+ unchanged).
+
+Arguments:
+
+ Date - A string that contains the time. This string must have
+ one of the following formats:
+
+ h:m
+ h:m:s
+
+ Where:
+
+ h: represents the hour (1 or 2 digits)
+ m: represents the minutes (1 or 2 digits)
+ s: represents the seconds (1 or 2 digits)
+
+
+Return Value:
+
+ BOOLEAN - A boolean value indicating if the time was set correctly.
+
+Notes:
+
+ BUGBUG - jaimes - 05/10/91
+
+ THE CURRENT IMPLEMENTATION IS JUST A TEMPORARY ONE, UNTIL WE HAVE
+ THE WINNLS APIs READY.
+
+
+--*/
+
+{
+ CHNUM FirstDelimiter;
+ CHNUM SecondDelimiter;
+ USHORT Hour;
+ USHORT Minute;
+ USHORT Second;
+ BOOLEAN IsNumber;
+ LONG Number;
+ FSTRING Delimiters;
+ SYSTEMTIME TempSystemTime;
+
+ //
+ // Check if the string is a valid one
+ //
+ FirstDelimiter = INVALID_CHNUM;
+ SecondDelimiter = INVALID_CHNUM;
+
+ if( !Delimiters.Initialize( (LPWSTR) L":" ) ) {
+ return( FALSE );
+ }
+ if( ( FirstDelimiter = Time->Strcspn( &Delimiters ) ) == INVALID_CHNUM ) {
+ return( FALSE );
+ }
+ SecondDelimiter = Time->Strcspn( &Delimiters, FirstDelimiter + 1 );
+
+ //
+ // At this point we know that the string has one or two delimiters, and
+ // two or three numeric fields.
+ // We now have to extract the numbers that represent the time,
+ // and validate these numbers.
+ //
+
+ if (!(IsNumber = Time->QueryNumber(&Number, 0, FirstDelimiter ))) {
+ return FALSE;
+ }
+ Hour = (USHORT)Number;
+
+ if( SecondDelimiter == INVALID_CHNUM ) {
+ if (!(IsNumber = Time->QueryNumber(&Number, FirstDelimiter+1))) {
+ return FALSE;
+ }
+ Minute = (USHORT)Number;
+ Second = 0;
+ } else {
+ if (!(IsNumber = Time->QueryNumber(&Number, FirstDelimiter+1, SecondDelimiter-FirstDelimiter-1))) {
+ return FALSE;
+ }
+ Minute = (USHORT)Number;
+
+ if (!(IsNumber = Time->QueryNumber(&Number, SecondDelimiter+1))) {
+ return FALSE;
+ }
+ Second = (USHORT)Number;
+ }
+
+ //
+ // Check if the time is valid
+ //
+ if( ( Hour >= 24 ) || ( Minute >= 60 ) || ( Second >= 60 ) ) {
+ return( FALSE );
+ }
+
+ TempSystemTime = _SystemTime;
+ TempSystemTime.wHour = ( USHORT )Hour;
+ TempSystemTime.wMinute = ( USHORT )Minute;
+ TempSystemTime.wSecond = ( USHORT )Second;
+ TempSystemTime.wMilliseconds = 0;
+ return( this->Initialize( &TempSystemTime ) );
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+TIMEINFO::QueryTime(
+ OUT PWSTRING FormattedTimeString
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the correct time string for this TIMEINFO.
+
+Arguments:
+
+ FormattedTimeString - Returns a formatted time string.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ WSTR buf[50];
+
+ return( GetTimeFormatW( GetSystemDefaultLCID(),
+ TIME_NOSECONDS,
+ &_SystemTime,
+ NULL,
+ buf,
+ 50 ) &&
+ FormattedTimeString->Initialize(buf) );
+
+}
+
+
+NONVIRTUAL
+ULIB_EXPORT
+BOOLEAN
+TIMEINFO::QueryDate(
+ OUT PWSTRING FormattedDateString
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the correct date string for this TIMEINFO.
+
+Arguments:
+
+ FormattedTimeString - Returns a formatted date string.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ WSTR buf[50];
+
+ return( GetDateFormatW( GetSystemDefaultLCID(),
+ DATE_SHORTDATE,
+ &_SystemTime,
+ NULL,
+ buf,
+ 50 ) != 0 &&
+ FormattedDateString->Initialize(buf) );
+}
+
+
+BOOLEAN
+TIMEINFO::operator== (
+ IN TIMEINFO TimeInfo
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ This function determines if the time information contained in this
+ class is equal to the time information received as parameter.
+
+Arguments:
+
+ TimeInfo - An object of type TIMEINFO that contains the time
+ information to be compared.
+
+Return Value:
+
+ BOOLEAN - A boolean value indicating if the time information in this
+ object is equal to the information in the object received
+ as parameter.
+
+
+--*/
+
+
+{
+ FILETIME ft;
+
+ ft = _FileTime;
+ switch( CompareFileTime( &ft, TimeInfo.GetFileTime() ) ) {
+ case 0:
+ return( TRUE );
+
+ default:
+ return( FALSE );
+ }
+}
+
+
+
+BOOLEAN
+TIMEINFO::operator!= (
+ IN TIMEINFO TimeInfo
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ This function determines if the time information contained in this
+ class is different than the time information received as parameter.
+
+Arguments:
+
+ TimeInfo - An object of type TIMEINFO that contains the time
+ information to be compared.
+
+Return Value:
+
+ BOOLEAN - A boolean value indicating if the time information in this
+ object is different than the information in the object received
+ as parameter.
+
+
+--*/
+
+
+{
+ FILETIME ft;
+
+ ft = _FileTime;
+ switch( CompareFileTime( &ft, TimeInfo.GetFileTime() ) ) {
+
+ case 0:
+ return( FALSE );
+
+ default:
+ return( TRUE );
+ }
+}
+
+
+
+ULIB_EXPORT
+BOOLEAN
+TIMEINFO::operator< (
+ IN TIMEINFO TimeInfo
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ This function determines if the time information contained in this
+ class is smaller than the time information received as parameter.
+
+Arguments:
+
+ TimeInfo - An object of type TIMEINFO that contains the time
+ information to be compared.
+
+Return Value:
+
+ BOOLEAN - A boolean value indicating if the time information in this
+ object is smaller than the information in the object received
+ as parameter.
+
+
+--*/
+
+
+{
+ FILETIME ft;
+
+ ft = _FileTime;
+ switch( CompareFileTime( &ft, TimeInfo.GetFileTime() ) ) {
+
+ case -1:
+ return( TRUE );
+
+ default:
+ return( FALSE );
+ }
+}
+
+
+
+ULIB_EXPORT
+BOOLEAN
+TIMEINFO::operator> (
+ IN TIMEINFO TimeInfo
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ This function determines if the time information contained in this
+ class is greter than the time information received as parameter.
+
+Arguments:
+
+ TimeInfo - An object of type TIMEINFO that contains the time
+ information to be compared.
+
+Return Value:
+
+ BOOLEAN - A boolean value indicating if the time information in this
+ object is greater than the information in the object received
+ as parameter.
+
+
+--*/
+
+
+{
+ FILETIME ft;
+
+ ft = _FileTime;
+ switch( CompareFileTime( &ft, TimeInfo.GetFileTime() ) ) {
+
+ case 1:
+ return( TRUE );
+
+ default:
+ return( FALSE );
+ }
+}
+
+
+
+BOOLEAN
+TIMEINFO::operator<= (
+ IN TIMEINFO TimeInfo
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ This function determines if the time information contained in this
+ class is less or equal than the time information received as parameter.
+
+Arguments:
+
+ TimeInfo - An object of type TIMEINFO that contains the time
+ information to be compared.
+
+Return Value:
+
+ BOOLEAN - A boolean value indicating if the time information in this
+ object is less or equal than the information in the object
+ received as parameter.
+
+
+--*/
+
+
+{
+ FILETIME ft;
+
+ ft = _FileTime;
+ switch( CompareFileTime( &ft, TimeInfo.GetFileTime() ) ) {
+
+ case -1:
+ case 0:
+ return( TRUE );
+
+ default:
+ return( FALSE );
+ }
+}
+
+
+
+BOOLEAN
+TIMEINFO::operator>= (
+ IN TIMEINFO TimeInfo
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ This function determines if the time information contained in this
+ class is greater or equal than the time information received as
+ parameter.
+
+Arguments:
+
+ TimeInfo - An object of type TIMEINFO that contains the time
+ information to be compared.
+
+Return Value:
+
+ BOOLEAN - A boolean value indicating if the time information in this
+ object is greater or equal than the information in the object
+ received as parameter.
+
+
+--*/
+
+
+{
+ FILETIME ft;
+
+ ft = _FileTime;
+ switch( CompareFileTime( &ft, TimeInfo.GetFileTime() ) ) {
+
+ case 0:
+ case 1:
+ return( TRUE );
+
+ default:
+ return( FALSE );
+ }
+}
diff --git a/private/utils/ulib/src/ulib.cxx b/private/utils/ulib/src/ulib.cxx
new file mode 100644
index 000000000..10c785150
--- /dev/null
+++ b/private/utils/ulib/src/ulib.cxx
@@ -0,0 +1,681 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ulib.cxx
+
+Abstract:
+
+ This module contains run-time, global support for the ULIB class library.
+ This support includes:
+
+ - creation of CLASS_DESCRIPTORs
+ - Global objects
+ - Ulib to Win32 API mapping functions
+
+Author:
+
+ David J. Gilman (davegi) 05-Dec-1990
+
+Environment:
+
+ ULIB, User Mode
+
+Notes:
+
+--*/
+
+#include <pch.cxx>
+
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+
+#if !defined( _AUTOCHECK_ ) && !defined( _SETUP_LOADER_ )
+
+#include "system.hxx"
+#include "array.hxx"
+#include "arrayit.hxx"
+#include "bitvect.hxx"
+#include "dir.hxx"
+#include "file.hxx"
+#include "filestrm.hxx"
+#include "filter.hxx"
+#include "keyboard.hxx"
+#include "message.hxx"
+#include "wstring.hxx"
+#include "path.hxx"
+#include "pipestrm.hxx"
+#include "prtstrm.hxx"
+#include "screen.hxx"
+#include "stream.hxx"
+#include "timeinfo.hxx"
+
+extern "C" {
+#include <locale.h>
+}
+
+#endif // _AUTOCHECK_ || _SETUP_LOADER_
+
+
+//
+// Constants
+//
+
+CONST CLASS_ID NIL_CLASS_ID = 0;
+
+#if !defined( _AUTOCHECK_ ) && !defined( _SETUP_LOADER_ )
+
+#if DBG==1
+
+//
+// UlibGlobalFlag is used to selectively enable debugging options at
+// run-time.
+//
+
+ULONG UlibGlobalFlag = 0x00000000;
+
+ULIB_EXPORT
+VOID
+DebugPrintf(
+ IN PCSTR Format,
+ IN ...
+ )
+
+/*++
+
+Routine Description:
+
+ Printf to the debug console.
+
+Arguments:
+
+ Format - Supplies a printf style format string.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ STR Buffer[ 512 ];
+ va_list args;
+
+ va_start( args, Format );
+ vsprintf( Buffer, Format, args );
+ va_end( args );
+ OutputDebugStringA( Buffer );
+}
+
+#endif // DBG
+//
+// GLobal object pointers.
+//
+
+// Clients of the DLL cannot access the DLL's
+// global data yet, so I have the delightful hacks to get at it.
+
+ULIB_EXPORT
+PSTREAM
+Get_Standard_Input_Stream(
+ )
+{
+ return Standard_Input_Stream;
+}
+
+ULIB_EXPORT
+PSTREAM
+Get_Standard_Output_Stream(
+ )
+{
+ return Standard_Output_Stream;
+}
+
+ULIB_EXPORT
+PSTREAM
+Get_Standard_Error_Stream(
+ )
+{
+ return Standard_Error_Stream;
+}
+
+PSTREAM Standard_Input_Stream;
+PSTREAM Standard_Output_Stream;
+PSTREAM Standard_Error_Stream;
+
+#endif // _AUTOCHECK_ || _SETUP_LOADER_
+
+// Note: Who put this here? Currently it is being defined
+// by applications. Something has to be done about this.
+ERRSTACK* perrstk;
+
+
+//
+// Declare class descriptors for all classes.
+//
+
+DECLARE_CLASS( CLASS_DESCRIPTOR );
+
+DECLARE_CLASS( ARGUMENT );
+DECLARE_CLASS( ARGUMENT_LEXEMIZER );
+DECLARE_CLASS( ARRAY );
+DECLARE_CLASS( ARRAY_ITERATOR );
+DECLARE_CLASS( BITVECTOR );
+DECLARE_CLASS( BUFFER_STREAM );
+DECLARE_CLASS( BYTE_STREAM );
+DECLARE_CLASS( COMM_DEVICE );
+DECLARE_CLASS( CONT_MEM );
+DECLARE_CLASS( CONTAINER );
+DECLARE_CLASS( DSTRING );
+DECLARE_CLASS( FILE_STREAM );
+DECLARE_CLASS( FLAG_ARGUMENT );
+DECLARE_CLASS( FSNODE );
+DECLARE_CLASS( FSN_DIRECTORY );
+DECLARE_CLASS( FSN_FILE );
+DECLARE_CLASS( FSN_FILTER );
+DECLARE_CLASS( FSTRING );
+DECLARE_CLASS( HMEM );
+DECLARE_CLASS( ITERATOR );
+DECLARE_CLASS( KEYBOARD );
+DECLARE_CLASS( LIST );
+DECLARE_CLASS( LIST_ITERATOR );
+DECLARE_CLASS( LONG_ARGUMENT );
+DECLARE_CLASS( MEM );
+DECLARE_CLASS( MESSAGE );
+DECLARE_CLASS( MULTIPLE_PATH_ARGUMENT );
+DECLARE_CLASS( OBJECT );
+DECLARE_CLASS( PATH );
+DECLARE_CLASS( PATH_ARGUMENT );
+DECLARE_CLASS( PIPE );
+DECLARE_CLASS( PIPE_STREAM );
+DECLARE_CLASS( PROGRAM );
+DECLARE_CLASS( PRINT_STREAM );
+DECLARE_CLASS( REST_OF_LINE_ARGUMENT );
+DECLARE_CLASS( SCREEN );
+DECLARE_CLASS( SEQUENTIAL_CONTAINER );
+DECLARE_CLASS( SORTABLE_CONTAINER );
+DECLARE_CLASS( SORTED_LIST );
+DECLARE_CLASS( SORTED_LIST_ITERATOR );
+DECLARE_CLASS( STREAM_MESSAGE );
+DECLARE_CLASS( STACK );
+DECLARE_CLASS( STREAM );
+DECLARE_CLASS( WSTRING );
+DECLARE_CLASS( STRING_ARGUMENT );
+DECLARE_CLASS( STRING_ARRAY );
+DECLARE_CLASS( TIMEINFO );
+DECLARE_CLASS( TIMEINFO_ARGUMENT );
+DECLARE_CLASS( STATIC_MEM_BLOCK_MGR );
+DECLARE_CLASS( MEM_BLOCK_MGR );
+
+
+#if defined( _AUTOCHECK_ )
+
+ DECLARE_CLASS( AUTOCHECK_MESSAGE );
+
+#endif // _AUTOCHECK_
+
+
+
+
+
+//
+// Local prototypes
+//
+STATIC
+BOOLEAN
+DefineClassDescriptors (
+ );
+
+#if !defined( _AUTOCHECK_ ) && !defined( _SETUP_LOADER_ )
+
+BOOLEAN
+CreateStandardStreams (
+ );
+
+PSTREAM
+GetStandardStream (
+ IN HANDLE Handle,
+ IN STREAMACCESS Access
+ );
+
+#endif // _AUTOCHECK_ || _SETUP_LOADER_
+
+
+BOOLEAN
+InitializeUlib (
+ IN HANDLE DllHandle,
+ IN ULONG Reason,
+ IN PVOID Reserved
+ )
+
+/*++
+
+Routine Description:
+
+ Initilize Ulib by constructing and initializing all global objects. These
+ include:
+
+ - all CLASS_DESCRIPTORs (class_cd)
+ - SYSTEM (System)
+ - Standard streams
+
+Arguments:
+
+ DllHandle - Not used.
+ Reason - Supplies the reason why the entry point was called.
+ Reserved - Not used.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if all global objects were succesfully constructed
+ and initialized.
+
+--*/
+
+{
+
+ STATIC BOOLEAN fInit = FALSE;
+
+ UNREFERENCED_PARAMETER( DllHandle );
+ UNREFERENCED_PARAMETER( Reason );
+ UNREFERENCED_PARAMETER( Reserved );
+
+
+ if ( fInit ) {
+ return( TRUE );
+ }
+
+ fInit = TRUE;
+
+#if defined( _AUTOCHECK_ ) || defined( _SETUP_LOADER_ )
+
+ if( !DefineClassDescriptors() ) {
+ return( FALSE );
+ }
+
+#else // _AUTOCHECK_ and _SETUP_LOADER_ not defined
+ //
+ // Initialization of ULIB can no longer depend on
+ // the initialization of the standard streams since they don't seem
+ // to exist for Windows programs (no console...)
+ //
+
+ if( !DefineClassDescriptors() ) {
+ DebugAbort( "Ulib initialization failed!!!\n" );
+ return( FALSE );
+ }
+
+ CreateStandardStreams();
+
+ setlocale(LC_ALL, "");
+
+#endif // _AUTOCHECK || _SETUP_LOADER_
+
+ return( TRUE );
+
+}
+
+STATIC
+BOOLEAN
+DefineClassDescriptors (
+ )
+
+/*++
+
+Routine Description:
+
+ Defines all the class descriptors used by ULIB
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if all class descriptors were succesfully
+ constructed and initialized.
+
+--*/
+
+{
+
+ // This is broken up into many ifs because of compiler limitations.
+
+ BOOLEAN Success = TRUE;
+
+ if (Success &&
+ DEFINE_CLASS_DESCRIPTOR( ARGUMENT ) &&
+ DEFINE_CLASS_DESCRIPTOR( ARGUMENT_LEXEMIZER ) &&
+ DEFINE_CLASS_DESCRIPTOR( ARRAY ) &&
+ DEFINE_CLASS_DESCRIPTOR( ARRAY_ITERATOR ) &&
+ DEFINE_CLASS_DESCRIPTOR( BITVECTOR ) &&
+ DEFINE_CLASS_DESCRIPTOR( BYTE_STREAM ) &&
+ DEFINE_CLASS_DESCRIPTOR( COMM_DEVICE ) &&
+ DEFINE_CLASS_DESCRIPTOR( CONTAINER ) &&
+ DEFINE_CLASS_DESCRIPTOR( DSTRING ) &&
+ DEFINE_CLASS_DESCRIPTOR( FLAG_ARGUMENT ) &&
+ DEFINE_CLASS_DESCRIPTOR( FSNODE ) &&
+ DEFINE_CLASS_DESCRIPTOR( FSN_DIRECTORY ) &&
+ DEFINE_CLASS_DESCRIPTOR( FSN_FILE ) &&
+ DEFINE_CLASS_DESCRIPTOR( FSN_FILTER ) &&
+ DEFINE_CLASS_DESCRIPTOR( ITERATOR ) &&
+ DEFINE_CLASS_DESCRIPTOR( LIST ) &&
+ DEFINE_CLASS_DESCRIPTOR( LIST_ITERATOR ) &&
+ DEFINE_CLASS_DESCRIPTOR( LONG_ARGUMENT ) &&
+ DEFINE_CLASS_DESCRIPTOR( MULTIPLE_PATH_ARGUMENT ) &&
+ DEFINE_CLASS_DESCRIPTOR( PATH ) &&
+ DEFINE_CLASS_DESCRIPTOR( PATH_ARGUMENT ) &&
+ DEFINE_CLASS_DESCRIPTOR( PROGRAM ) &&
+ DEFINE_CLASS_DESCRIPTOR( SEQUENTIAL_CONTAINER ) &&
+ DEFINE_CLASS_DESCRIPTOR( SORTABLE_CONTAINER ) &&
+ DEFINE_CLASS_DESCRIPTOR( SORTED_LIST ) &&
+ DEFINE_CLASS_DESCRIPTOR( SORTED_LIST_ITERATOR ) &&
+ DEFINE_CLASS_DESCRIPTOR( WSTRING ) &&
+ DEFINE_CLASS_DESCRIPTOR( STRING_ARGUMENT ) &&
+ DEFINE_CLASS_DESCRIPTOR( STRING_ARRAY ) &&
+ DEFINE_CLASS_DESCRIPTOR( TIMEINFO ) &&
+ DEFINE_CLASS_DESCRIPTOR( TIMEINFO_ARGUMENT ) &&
+ DEFINE_CLASS_DESCRIPTOR( MESSAGE ) &&
+ TRUE ) {
+ } else {
+ Success = FALSE;
+ }
+
+ if (Success &&
+ DEFINE_CLASS_DESCRIPTOR( BUFFER_STREAM ) &&
+ DEFINE_CLASS_DESCRIPTOR( CONT_MEM ) &&
+ TRUE ) {
+ } else {
+ Success = FALSE;
+ }
+
+ if (Success &&
+ DEFINE_CLASS_DESCRIPTOR( FILE_STREAM ) &&
+ DEFINE_CLASS_DESCRIPTOR( FSTRING ) &&
+ DEFINE_CLASS_DESCRIPTOR( HMEM ) &&
+ DEFINE_CLASS_DESCRIPTOR( STATIC_MEM_BLOCK_MGR ) &&
+ DEFINE_CLASS_DESCRIPTOR( MEM_BLOCK_MGR ) &&
+ TRUE ) {
+ } else {
+ Success = FALSE;
+ }
+
+ if (Success &&
+ DEFINE_CLASS_DESCRIPTOR( KEYBOARD ) &&
+ DEFINE_CLASS_DESCRIPTOR( MEM ) &&
+ DEFINE_CLASS_DESCRIPTOR( PATH_ARGUMENT ) &&
+ DEFINE_CLASS_DESCRIPTOR( PIPE ) &&
+ DEFINE_CLASS_DESCRIPTOR( PIPE_STREAM ) &&
+ DEFINE_CLASS_DESCRIPTOR( PRINT_STREAM ) &&
+
+
+ DEFINE_CLASS_DESCRIPTOR( REST_OF_LINE_ARGUMENT ) &&
+ DEFINE_CLASS_DESCRIPTOR( SCREEN ) &&
+ DEFINE_CLASS_DESCRIPTOR( STREAM ) &&
+ DEFINE_CLASS_DESCRIPTOR( STREAM_MESSAGE ) &&
+
+#if defined( _AUTOCHECK_ )
+
+ DEFINE_CLASS_DESCRIPTOR( AUTOCHECK_MESSAGE ) &&
+
+#endif // _AUTOCHECK_
+
+ TRUE ) {
+ } else {
+ Success = FALSE;
+ }
+
+
+ if (Success &&
+ TRUE ) {
+ } else {
+ Success = FALSE;
+ }
+
+ if (!Success) {
+ DebugPrint( "Could not initialize class descriptors!");
+ }
+ return Success;
+
+}
+
+
+#if !defined( _AUTOCHECK_ ) && !defined( _SETUP_LOADER_ )
+
+BOOLEAN
+CreateStandardStreams (
+ )
+
+/*++
+
+Routine Description:
+
+ Creates the standard streams
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the streams were successfully created,
+ FALSE otherwise
+
+--*/
+
+{
+
+ Standard_Input_Stream = GetStandardStream( GetStdHandle( STD_INPUT_HANDLE),
+ READ_ACCESS );
+
+ Standard_Output_Stream = GetStandardStream( GetStdHandle( STD_OUTPUT_HANDLE),
+ WRITE_ACCESS );
+
+ Standard_Error_Stream = GetStandardStream( GetStdHandle( STD_ERROR_HANDLE),
+ WRITE_ACCESS );
+
+
+ return ( (Standard_Input_Stream != NULL) &&
+ (Standard_Output_Stream != NULL) &&
+ (Standard_Error_Stream != NULL) );
+}
+
+PSTREAM
+GetStandardStream (
+ IN HANDLE Handle,
+ IN STREAMACCESS Access
+ )
+
+/*++
+
+Routine Description:
+
+ Creates a standard stream out of a standard handle
+
+Arguments:
+
+ Handle - Supplies the standard handle
+ Access - Supplies the access.
+
+Return Value:
+
+ Pointer to the stream object created.
+
+--*/
+
+
+{
+ PSTREAM Stream = NULL;
+ PFILE_STREAM FileStream;
+ PPIPE_STREAM PipeStream;
+ PKEYBOARD Keyboard;
+ PSCREEN Screen;
+
+
+ switch ( GetFileType( Handle ) ) {
+
+ case (DWORD)FILE_TYPE_DISK:
+
+ if ((FileStream = NEW FILE_STREAM) != NULL ) {
+ if ( !FileStream->Initialize( Handle, Access ) ) {
+ DELETE( FileStream );
+ }
+ Stream = (PSTREAM)FileStream;
+ }
+ break;
+
+
+ case (DWORD)FILE_TYPE_CHAR:
+
+ //
+ // BUGBUG RamonSA this type refers to all character devices, not
+ // just the console. I will add some hacks to see if
+ // the handle refers to the console or not. This
+ // information should be given in a clean way by the
+ // API (talk with MarkL)
+ //
+ switch ( Access ) {
+
+ case READ_ACCESS:
+
+ //
+ // BUGBUG Jaimes See if this is a console handle
+ //
+ {
+ DWORD Mode;
+ if (!GetConsoleMode( Handle, &Mode )) {
+ //
+ // This is not a console, but some other character
+ // device. Create a pipe stream for it.
+ //
+ if ((PipeStream = NEW PIPE_STREAM) != NULL ) {
+ if ( !PipeStream->Initialize( Handle, Access ) ) {
+ DELETE( PipeStream );
+ }
+ Stream = (PSTREAM)PipeStream;
+ }
+ break;
+ }
+ }
+ if ((Keyboard = NEW KEYBOARD) != NULL ) {
+ if ( !Keyboard->Initialize() ) {
+ DELETE( Keyboard );
+ }
+ Stream = (PSTREAM)Keyboard;
+ }
+ break;
+
+ case WRITE_ACCESS:
+
+ //
+ // BUGBUG Ramonsa See if this is a console handle
+ //
+ {
+ DWORD Mode;
+ if (!GetConsoleMode( Handle, &Mode )) {
+ //
+ // This is not a console, but some other character
+ // device. Create a file stream for it.
+ //
+ if ((FileStream = NEW FILE_STREAM) != NULL ) {
+ if ( !FileStream->Initialize( Handle, Access ) ) {
+ DELETE( FileStream );
+ }
+ Stream = (PSTREAM)FileStream;
+ }
+ break;
+ }
+ }
+
+ if ((Screen = NEW SCREEN) != NULL ) {
+ if ( !Screen->Initialize() ) {
+ DELETE( Screen );
+ }
+ Stream = (PSTREAM)Screen;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ break;
+
+ case (DWORD)FILE_TYPE_PIPE:
+
+ if ((PipeStream = NEW PIPE_STREAM) != NULL ) {
+ if ( !PipeStream->Initialize( Handle, Access ) ) {
+ DELETE( PipeStream );
+ }
+ Stream = (PSTREAM)PipeStream;
+ }
+ break;
+
+ case (DWORD)FILE_TYPE_UNKNOWN:
+ // Probably a windows app. Don't print anything to debug.
+ break;
+
+ default:
+ DebugPrintf( "ERROR: FileType for standard stream %lx is invalid (%lx)\n", Handle, GetFileType(Handle) );
+ break;
+
+ }
+
+ return Stream;
+
+}
+
+NONVIRTUAL
+ULIB_EXPORT
+HANDLE
+FindFirstFile (
+ IN PCPATH Path,
+ OUT PWIN32_FIND_DATA FileFindData
+ )
+
+/*++
+
+Routine Description:
+
+ Perform a FindFirst file given a PATH rather tha a PSTR.
+
+Arguments:
+
+ Path - Supplies a pointer to the PATH to search.
+ FileFindData - Supplies a pointer where the results of the find is
+ returned.
+
+Return Value:
+
+ HANDLE - Returns the results of the call to the Win32 FindFirstFile API.
+
+--*/
+
+{
+ PWSTR p;
+
+ //
+ // If the supplied pointers are non-NULL and an OEM representation
+ // (i.e. API ready) of the PATH is available, return the
+ // HANDLE returned by the Win32 FindFirstFile API
+ //
+
+ DebugPtrAssert( Path );
+ DebugPtrAssert( FileFindData );
+ if (!Path || !FileFindData) {
+ return INVALID_HANDLE_VALUE;
+ }
+
+ p = (PWSTR) Path->GetPathString()->GetWSTR();
+ if (!p) {
+ return INVALID_HANDLE_VALUE;
+ }
+
+ return FindFirstFile(p, FileFindData);
+}
+
+#endif // _AUTOCHECK_ || _SETUP_LOADER_
diff --git a/private/utils/ulib/src/ulib.rc b/private/utils/ulib/src/ulib.rc
new file mode 100644
index 000000000..85a680014
--- /dev/null
+++ b/private/utils/ulib/src/ulib.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "File Utilities Support DLL"
+#define VER_INTERNALNAME_STR "ulib.dll"
+#define VER_ORIGINALFILENAME_STR "ulib.dll"
+
+#include "common.ver"
diff --git a/private/utils/ulib/src/usa-ms.msg b/private/utils/ulib/src/usa-ms.msg
new file mode 100644
index 000000000..055d66676
--- /dev/null
+++ b/private/utils/ulib/src/usa-ms.msg
@@ -0,0 +1,1588 @@
+0408
+COMMON 00000006 0038
+0001 U 0000 "Incorrect DOS version",CR,LF
+0002 U 0000 "%1 already installed",CR,LF
+0003 U 0000 "%1 bytes available on disk",CR,LF
+0004 U 0000 "%1 bytes free",CR,LF
+0005 U 0000 "%1 bytes in bad sectors",CR,LF
+0006 U 0000 "%1 bytes total disk space",CR,LF
+0007 U 0000 "%1 bytes total memory",CR,LF
+0008 U 0000 "%1 bytes used by system",CR,LF
+0009 U 0000 "%1 installed",CR,LF
+0010 U 0000 "%1 not installed",CR,LF
+0011 U 0000 "%1 not installed",CR,LF
+0012 U 0000 "Cannot %1 a network drive",CR,LF
+0013 U 0000 "",
+0014 U 0000 "Cannot %1 a SUBSTed or ASSIGNed drive",CR,LF
+0015 U 0000 "Cannot execute %1",CR,LF
+0016 U 0000 "Expanded Memory not available",CR,LF
+0017 U 0000 "File allocation table bad, drive %1",CR,LF
+0018 U 0000 "File cannot be copied onto itself",CR,LF
+0019 U 0000 "Insert target disk in drive %1",CR,LF
+0020 U 0000 "Insufficient disk space",CR,LF
+0021 U 0000 "Invalid characters in volume label",CR,LF
+0022 U 0000 "Invalid code page",CR,LF
+0023 U 0000 "Invalid date",CR,LF
+0024 U 0000 "Invalid time",CR,LF
+0025 U 0000 "Invalid path",CR,LF
+0026 U 0000 "No source drive specified",CR,LF
+0027 U 0000 "No target drive specified",CR,LF
+0028 U 0000 "Press any key to continue . . .",CR,LF
+0029 U 0000 "Source path required",CR,LF
+0030 U 0000 "System transferred",CR,LF
+0031 U 0000 "",
+0032 U 0000 "Unable to create directory",CR,LF
+0033 U 0000 "Volume in drive %1 has no label",CR,LF
+0034 U 0000 "Volume in drive %1 is %2",CR,LF
+0035 U 0001 "Volume label (11 characters, ENTER for none)? "
+0036 U 0000 "Volume Serial Number is %1-%2",CR,LF
+0037 U 0000 "Incorrect file type",CR,LF
+0038 U 0001 CR,LF
+EXTEND 00000689 0090
+0001 U 0003 "Invalid function"
+0002 U 0000 "File not found"
+0003 U 0000 "Path not found"
+0004 U 0000 "Too many open files"
+0005 U 0000 "Access denied "
+0006 U 0000 "Invalid handle"
+0007 U 0000 "Memory control blocks destroyed"
+0008 U 0000 "Insufficient memory"
+0009 U 0000 "Invalid memory block address"
+0010 U 0000 "Invalid Environment"
+0011 U 0000 "Invalid format"
+0012 U 0000 "Invalid function parameter"
+0013 U 0000 "Invalid data"
+0014 U 0000 "",
+0015 U 0000 "Invalid drive specification"
+0016 U 0000 "Attempt to remove current directory"
+0017 U 0000 "Not same device"
+0018 U 0000 "No more files"
+0019 U 0000 "Write protect error"
+0020 U 0000 "Invalid unit"
+0021 U 0000 "Not ready"
+0022 U 0000 "Invalid device request"
+0023 U 0000 "Data error"
+0024 U 0000 "Invalid device request parameters"
+0025 U 0000 "Seek error"
+0026 U 0000 "Invalid media type"
+0027 U 0000 "Sector not found"
+0028 U 0000 "Printer out of paper error"
+0029 U 0000 "Write fault error"
+0030 U 0000 "Read fault error"
+0031 U 0000 "General failure"
+0032 U 0000 "Sharing violation"
+0033 U 0000 "Lock violation"
+0034 U 0000 "Invalid disk change"
+0035 U 0000 "FCB unavailable"
+0036 U 0000 "System resource exhausted"
+0037 U 0000 "Code page mismatch"
+0038 U 0000 "Out of input"
+0039 U 0000 "Insufficient disk space"
+0040 U 0000 "",
+0041 U 0000 "",
+0042 U 0000 "",
+0043 U 0000 "",
+0044 U 0000 "",
+0045 U 0000 "",
+0046 U 0000 "",
+0047 U 0000 "",
+0048 U 0000 "",
+0049 U 0000 "",
+0050 U 0000 "NET809: Network request not supported"
+0051 U 0000 "NET801: Remote computer not listening"
+0052 U 0000 "NET802: Duplicate name on network"
+0053 U 0000 "NET803: Network path not found"
+0054 U 0000 "NET804: Network busy"
+0055 U 0000 "NET805: Network device no longer exists"
+0056 U 0000 "NET806: NETBIOS command limit exceeded"
+0057 U 0000 "NET807: System error; NETBIOS error"
+0058 U 0000 "NET808: Incorrect response from network"
+0059 U 0000 "NET810: Unexpected network error"
+0060 U 0000 "NET811: Incompatible remote adapter"
+0061 U 0000 "NET812: Print queue full"
+0062 U 0000 "NET813: Not enough space for print file"
+0063 U 0000 "NET814: Print file was cancelled"
+0064 U 0000 "NET815: Network name was deleted"
+0065 U 0000 "Access denied"
+0066 U 0000 "NET817: Network device type incorrect"
+0067 U 0000 "NET818: Network name not found"
+0068 U 0000 "NET819: Network name limit exceeded"
+0069 U 0000 "NET820: NETBIOS session limit exceeded"
+0070 U 0000 "NET821: Sharing temporarily paused"
+0071 U 0000 "NET823: Network request not accepted"
+0072 U 0000 "NET822: Print or disk redirection is paused"
+0073 U 0000 "NET476: Netbeui not loaded"
+0074 U 0000 "NET477: Unexpected adapter close"
+0075 U 0000 "",
+0076 U 0000 "",
+0077 U 0004 "",
+0078 U 0004 "",
+0079 U 0004 "",
+0080 U 0004 "File exists"
+0081 U 0004 "",
+0082 U 0004 "Cannot make directory entry"
+0083 U 0004 "Fail on INT 24"
+0084 U 0004 "Too many redirections"
+0085 U 0004 "Duplicate redirection"
+0086 U 0004 "Invalid password"
+0087 U 0004 "Invalid parameter"
+0088 U 0004 "Network data fault"
+0089 U 0004 "Function not supported by network"
+0090 U 0002 "Required system component not installed"
+PARSE 0000131d 0011
+0001 U 0000 "Too many parameters"
+0002 U 0000 "Required parameter missing"
+0003 U 0000 "Invalid switch"
+0004 U 0000 "Invalid keyword"
+0005 U 0000 "",
+0006 U 0000 "Parameter value not in allowed range"
+0007 U 0000 "Parameter value not allowed"
+0008 U 0000 "Parameter value not allowed"
+0009 U 0000 "Parameter format not correct"
+0010 U 0000 "Invalid parameter"
+0011 U 0000 "Invalid parameter combination"
+COMMAND 000014d4 0147
+1002 U 0000 "Duplicate file name or file not found",CR,LF
+1003 U 0000 "Invalid path or file name",CR,LF
+1007 U 0000 "Out of environment space",CR,LF
+1008 U 0000 "File creation error",CR,LF
+1009 U 0000 "Batch file missing",CR,LF
+1010 U 0000 CR,LF,"Insert disk with batch file",CR,LF
+1011 U 0000 "Bad command or file name",CR,LF
+1016 U 0000 "Content of destination lost before copy",CR,LF
+1017 U 0000 "Invalid filename or file not found",CR,LF
+1018 U 0000 "%1 file(s) copied",CR,LF
+1019 U 0000 "%1 file(s) "
+1022 U 0000 "Code page %1 not prepared for system",CR,LF
+1023 U 0000 "Code page %1 not prepared for all devices",CR,LF
+1024 U 0000 "Active code page: %1",CR,LF
+1025 U 0000 "NLSFUNC not installed",CR,LF
+1027 U 0000 "Current drive is no longer valid"
+1029 U 0000 "Label not found",CR,LF
+1030 U 0000 "Syntax error",CR,LF
+1032 U 0000 "Current date is %1 %2",CR,LF
+1033 U 0000 "SunMonTueWedThuFriSat"
+1034 U 0000 "Enter new date (%1): "
+1036 U 0000 "Current time is %1",CR,LF
+1037 U 0000 "Enter new time: "
+1038 U 0000 ", Delete (Y/N)?"
+1039 U 0000 "All files in directory will be deleted!",CR,LF,"Are you sure (Y/N)?"
+1040 U 0000 "MS-DOS Version %1.%2"
+1044 U 0000 "Invalid directory",CR,LF
+1046 U 0000 "Invalid path, not directory,",CR,LF,"or directory not empty",CR,LF
+1047 U 0000 "Must specify ON or OFF",CR,LF
+1048 U 0000 "Directory of %1",CR,LF
+1049 U 0000 "No Path",CR,LF
+1050 U 0000 "Invalid drive in search path",CR,LF
+1051 U 0000 "Invalid device",CR,LF
+1052 U 0000 "FOR cannot be nested",CR,LF
+1053 U 0000 "Intermediate file error during pipe",CR,LF
+1054 U 0000 "Cannot do binary reads from a device",CR,LF
+1055 U 0000 "BREAK is %1",CR,LF
+1056 U 0000 "VERIFY is %1",CR,LF
+1057 U 0000 "ECHO is %1",CR,LF
+1059 U 0000 "off",0
+1060 U 0000 "on",0
+1061 U 0000 "Error writing to device",CR,LF
+1063 U 0000 "%1"
+1064 U 0000 "%1"
+1065 U 0000 "%1"
+1066 U 0000 "%1"
+1067 U 0000 9
+1068 U 0000 " <DIR> "
+1069 U 0000 8," ",8
+1070 U 0000 CR,LF
+1071 U 0000 "%1"
+1072 U 0000 "mm-dd-yy"
+1073 U 0000 "dd-mm-yy"
+1074 U 0000 "yy-mm-dd"
+1075 U 0000 "%1 %2"
+1076 U 0000 "%1"
+1077 U 0000 " %1 %2"
+1078 U 0000 "Directory already exists",CR,LF
+1079 U 0000 "%1 bytes",CR,LF
+1080 U 0000 "Total files listed:",CR,LF
+1081 U 0000 "(Error occurred in environment variable)",CR,LF
+1084 U 0000 "(continuing %1)"
+1090 U 0000 "Revision %1",CR,LF
+1091 U 0000 "DOS is in ROM"
+1092 U 0000 "DOS is in HMA"
+1093 U 0000 "DOS is in low memory"
+1094 U 0000 "Cannot Loadhigh batch file",CR,LF
+1095 U 0000 "LoadHigh: Invalid filename",CR,LF
+1096 U 0000 "Cannot open specified country information file",CR,LF
+1300 U 0000 "Sets or clears extended CTRL+C checking.",CR,LF,CR,LF
+ "BREAK [ON | OFF]",CR,LF,CR,LF
+ "Type BREAK without a parameter to display the current BREAK setting.",CR,LF
+1320 U 0000 "Displays or sets the active code page number.",CR,LF,CR,LF
+ "CHCP [nnn]",CR,LF,CR,LF
+1321 U 0000 " nnn Specifies a code page number.",CR,LF,CR,LF
+ "Type CHCP without a parameter to display the active code page number.",CR,LF
+1340 U 0000 "Displays the name of or changes the current directory.",CR,LF,CR,LF
+ "CHDIR [drive:][path]",CR,LF
+ "CHDIR[..]",CR,LF
+1341 U 0000 "CD [drive:][path]",CR,LF
+ "CD[..]",CR,LF,CR,LF
+ " .. Specifies that you want to change to the parent directory.",CR,LF,CR,LF
+1342 U 0000 "Type CD drive: to display the current directory in the specified drive.",CR,LF
+ "Type CD without parameters to display the current drive and directory.",CR,LF
+1360 U 0000 "Clears the screen.",CR,LF,CR,LF
+ "CLS",CR,LF
+1400 U 0000 "Copies one or more files to another location.",CR,LF,CR,LF
+ "COPY [/A | /B] source [/A | /B] [+ source [/A | /B] [+ ...]] [destination",CR,LF
+ " [/A | /B]] [/V]",CR,LF,CR,LF
+1401 U 0000 " source Specifies the file or files to be copied.",CR,LF
+ " /A Indicates an ASCII text file.",CR,LF
+1402 U 0000 " /B Indicates a binary file.",CR,LF
+ " destination Specifies the directory and/or filename for the new file(s).",CR,LF
+1403 U 0000 " /V Verifies that new files are written correctly.",CR,LF,CR,LF
+1404 U 0000 "To append files, specify a single file for destination, but multiple files",CR,LF
+ "for source (using wildcards or file1+file2+file3 format).",CR,LF
+1420 U 0000 "Changes the terminal device used to control your system.",CR,LF,CR,LF
+ "CTTY device",CR,LF,CR,LF
+ " device The terminal device you want to use, such as COM1.",CR,LF
+1440 U 0000 "Displays or sets the date.",CR,LF,CR,LF
+ "DATE [date]",CR,LF,CR,LF
+1441 U 0000 "Type DATE without parameters to display the current date setting and",CR,LF
+ "a prompt for a new one. Press ENTER to keep the same date.",CR,LF
+1460 U 0000 "Deletes one or more files.",CR,LF,CR,LF
+ "DEL [drive:][path]filename [/P]",CR,LF
+ "ERASE [drive:][path]filename [/P]",CR,LF,CR,LF
+1461 U 0000 " [drive:][path]filename Specifies the file(s) to delete. Specify multiple",CR,LF
+ " files by using wildcards.",CR,LF
+1462 U 0000 " /P Prompts for confirmation before deleting each file.",CR,LF
+1480 U 0000 "Displays a list of files and subdirectories in a directory.",CR,LF,CR,LF
+ "DIR [drive:][path][filename] [/P] [/W] [/A[[:]attributes]]",CR,LF
+ " [/O[[:]sortorder]] [/S] [/B] [/L]",CR,LF,CR,LF
+1481 U 0000 " [drive:][path][filename]",CR,LF
+ " Specifies drive, directory, and/or files to list.",CR,LF
+1482 U 0000 " /P Pauses after each screenful of information.",CR,LF
+ " /W Uses wide list format.",CR,LF
+1483 U 0000 " /A Displays files with specified attributes.",CR,LF
+ " attributes D Directories R Read-only files",CR,LF
+1484 U 0000 " H Hidden files A Files ready for archiving",CR,LF
+ " S System files - Prefix meaning ""not""",CR,LF
+ " /O List by files in sorted order.",CR,LF
+1485 U 0000 " sortorder N By name (alphabetic) S By size (smallest first)",CR,LF
+ " E By extension (alphabetic) D By date & time (earliest first)",CR,LF
+1486 U 0000 " G Group directories first - Prefix to reverse order",CR,LF
+ " /S Displays files in specified directory and all subdirectories.",CR,LF
+1487 U 0000 " /B Uses bare format (no heading information or summary).",CR,LF
+ " /L Uses lowercase.",CR,LF,CR,LF
+1488 U 0000 "Switches may be preset in the DIRCMD environment variable. Override",CR,LF
+ "preset switches by prefixing any switch with - (hyphen)--for example, /-W.",CR,LF
+1500 U 0000 "Quits the COMMAND.COM program (command interpreter).",CR,LF,CR,LF
+ "EXIT",CR,LF
+1520 U 0000 "Creates a directory.",CR,LF,CR,LF
+ "MKDIR [drive:]path",CR,LF
+ "MD [drive:]path",CR,LF
+1540 U 0000 "Displays or sets a search path for executable files.",CR,LF,CR,LF
+ "PATH [[drive:]path[;...]]",CR,LF
+ "PATH ;",CR,LF,CR,LF
+1541 U 0000 "Type PATH ; to clear all search-path settings and direct MS-DOS to search",CR,LF
+ "only in the current directory.",CR,LF
+1542 U 0000 "Type PATH without parameters to display the current path.",CR,LF
+1560 U 0000 "Changes the MS-DOS command prompt.",CR,LF,CR,LF
+ "PROMPT [text]",CR,LF,CR,LF
+1561 U 0000 " text Specifies a new command prompt.",CR,LF,CR,LF
+ "Prompt can be made up of normal characters and the following special codes:",CR,LF,CR,LF
+1562 U 0000 " $Q = (equal sign)",CR,LF
+ " $$ $ (dollar sign)",CR,LF
+1563 U 0000 " $T Current time",CR,LF
+ " $D Current date",CR,LF
+1564 U 0000 " $P Current drive and path",CR,LF
+ " $V MS-DOS version number",CR,LF
+1565 U 0000 " $N Current drive",CR,LF
+ " $G > (greater-than sign)",CR,LF
+1566 U 0000 " $L < (less-than sign)",CR,LF
+ " $B | (pipe)",CR,LF
+1567 U 0000 " $H Backspace (erases previous character)",CR,LF
+ " $E Escape code (ASCII code 27)",CR,LF
+ " $_ Carriage return and linefeed",CR,LF,CR,LF
+1568 U 0000 "Type PROMPT without parameters to reset the prompt to the default setting.",CR,LF
+1580 U 0000 "Removes (deletes) a directory.",CR,LF,CR,LF
+ "RMDIR [drive:]path",CR,LF
+ "RD [drive:]path",CR,LF
+1600 U 0000 "Renames a file or files.",CR,LF,CR,LF
+1601 U 0000 "RENAME [drive:][path]filename1 filename2",CR,LF
+ "REN [drive:][path]filename1 filename2",CR,LF,CR,LF
+1602 U 0000 "Note that you cannot specify a new drive or path for your destination file.",CR,LF
+1620 U 0000 "Displays, sets, or removes MS-DOS environment variables.",CR,LF,CR,LF
+ "SET [variable=[string]]",CR,LF,CR,LF
+1621 U 0000 " variable Specifies the environment-variable name.",CR,LF
+ " string Specifies a series of characters to assign to the variable.",CR,LF,CR,LF
+1622 U 0000 "Type SET without parameters to display the current environment variables.",CR,LF
+1640 U 0000 "Displays or sets the system time.",CR,LF,CR,LF
+ "TIME [time]",CR,LF,CR,LF
+1641 U 0000 "Type TIME with no parameters to display the current time setting and a prompt",CR,LF
+ "for a new one. Press ENTER to keep the same time.",CR,LF
+1660 U 0000 "Displays the contents of a text file.",CR,LF,CR,LF
+ "TYPE [drive:][path]filename",CR,LF
+1680 U 0000 "Displays the MS-DOS version.",CR,LF,CR,LF
+ "VER",CR,LF
+1700 U 0000 "Tells MS-DOS whether to verify that your files are written correctly to a",CR,LF
+ "disk.",CR,LF,CR,LF
+ "VERIFY [ON | OFF]",CR,LF,CR,LF
+ "Type VERIFY without a parameter to display the current VERIFY setting.",CR,LF
+1720 U 0000 "Displays the disk volume label and serial number, if they exist.",CR,LF,CR,LF
+ "VOL [drive:]",CR,LF
+1740 U 0000 "Calls one batch program from another.",CR,LF,CR,LF
+ "CALL [drive:][path]filename [batch-parameters]",CR,LF,CR,LF
+1741 U 0000 " batch-parameters Specifies any command-line information required by the",CR,LF
+ " batch program.",CR,LF
+1760 U 0000 "Records comments (remarks) in a batch file or CONFIG.SYS.",CR,LF,CR,LF
+ "REM [comment]",CR,LF
+1780 U 0000 "Suspends processing of a batch program and displays the message ""Press any",CR,LF
+ "key to continue....""",CR,LF,CR,LF
+ "PAUSE",CR,LF
+1800 U 0000 "Displays messages, or turns command-echoing on or off.",CR,LF,CR,LF
+ " ECHO [ON | OFF]",CR,LF
+1801 U 0000 " ECHO [message]",CR,LF,CR,LF
+ "Type ECHO without parameters to display the current echo setting.",CR,LF
+1820 U 0000 "Directs MS-DOS to a labelled line in a batch program.",CR,LF,CR,LF
+ "GOTO label",CR,LF,CR,LF
+1821 U 0000 " label Specifies a text string used in the batch program as a label.",CR,LF,CR,LF
+ "You type a label on a line by itself, beginning with a colon.",CR,LF
+1840 U 0000 "Changes the position of replaceable parameters in a batch file.",CR,LF,CR,LF
+ "SHIFT",CR,LF
+1860 U 0000 "Performs conditional processing in batch programs.",CR,LF,CR,LF
+ "IF [NOT] ERRORLEVEL number command",CR,LF
+1861 U 0000 "IF [NOT] string1==string2 command",CR,LF
+ "IF [NOT] EXIST filename command",CR,LF,CR,LF
+1862 U 0000 " NOT Specifies that MS-DOS should carry out the command only",CR,LF
+ " if the condition is false.",CR,LF
+1863 U 0000 " ERRORLEVEL number Specifies a true condition if the last program run returned",CR,LF
+ " an exit code equal to or greater than the number specified.",CR,LF
+1864 U 0000 " command Specifies the command to carry out if the condition is",CR,LF
+ " met.",CR,LF
+1865 U 0000 " string1==string2 Specifies a true condition if the specified text strings",CR,LF
+ " match.",CR,LF
+1866 U 0000 " EXIST filename Specifies a true condition if the specified filename",CR,LF
+ " exists.",CR,LF
+1880 U 0000 "Runs a specified command for each file in a set of files.",CR,LF,CR,LF
+ "FOR %variable IN (set) DO command [command-parameters]",CR,LF,CR,LF
+1881 U 0000 " %variable Specifies a replaceable parameter.",CR,LF
+ " (set) Specifies a set of one or more files. Wildcards may be used.",CR,LF
+1882 U 0000 " command Specifies the command to carry out for each file.",CR,LF
+ " command-parameters",CR,LF
+1883 U 0000 " Specifies parameters or switches for the specified command.",CR,LF,CR,LF
+ "To use the FOR command in a batch program, specify %%variable instead of",CR,LF
+ "%variable.",CR,LF
+1900 U 0000 "Reserved command name",CR,LF
+1920 U 0000 "Loads a program into the upper memory area.",CR,LF,CR,LF
+1921 U 0000 "LOADHIGH [drive:][path]filename [parameters]",CR,LF
+ "LH [drive:][path]filename [parameters]",CR,LF,CR,LF
+1922 U 0000 " parameters Specifies any command-line information required by the",CR,LF
+ " program you want to load.",CR,LF
+ANSI 000046c0 0001
+0010 U 0000 "Invalid parameter - %1",CR,LF
+APPEND 00004704 0026
+0001 U 0000 "Incorrect APPEND version",CR,LF
+0002 U 0000 "Invalid path",CR,LF
+0003 U 0000 "Invalid parameter",CR,LF
+0004 U 0000 "Invalid combination of parameters",CR,LF
+0005 U 0000 "No Append",CR,LF
+0006 U 0000 "APPEND / ASSIGN Conflict",CR,LF
+0007 U 0000 "APPEND / TopView Conflict",CR,LF
+0008 U 0000 "Incorrect DOS version",CR,LF
+0009 U 0000 "APPEND already installed",CR,LF
+0300 U 0000 "Allows programs to open data files in specified directories as if they were in",CR,LF
+0301 U 0000 "the current directory.",CR,LF,CR,LF
+0302 U 0000 "APPEND [[drive:]path[;...]] [/X[:ON | :OFF]] [/PATH:ON | /PATH:OFF] [/E]",CR,LF
+0303 U 0000 "APPEND ;",CR,LF,CR,LF
+0304 U 0000 " [drive:]path Specifies a drive and directory to append.",CR,LF
+0305 U 0000 " /X:ON Applies appended directories to file searches and",CR,LF
+0306 U 0000 " application execution.",CR,LF
+0307 U 0000 " /X:OFF Applies appended directories only to requests to open files.",CR,LF
+0308 U 0000 " /X:OFF is the default setting.",CR,LF
+0309 U 0000 " /PATH:ON Applies appended directories to file requests that already",CR,LF
+0310 U 0000 " specify a path. /PATH:ON is the default setting.",CR,LF
+0311 U 0000 " /PATH:OFF Turns off the effect of /PATH:ON.",CR,LF
+0312 U 0000 " /E Stores a copy of the appended directory list in an environment",CR,LF
+0313 U 0000 " variable named APPEND. /E may be used only the first time",CR,LF
+0314 U 0000 " you use APPEND after starting your system.",CR,LF,CR,LF
+0315 U 0000 "Type APPEND ; to clear the appended directory list.",CR,LF
+0316 U 0000 "Type APPEND without parameters to display the appended directory list.",CR,LF
+ASSIGN 00004df2 0007
+0002 U 0000 "Original %1: set to %2:",cr,lf
+0300 U 0000 "Redirects requests for disk operations on one drive to a different drive.",CR,LF,CR,LF
+0301 U 0000 "ASSIGN [x[:]=y[:][...]]",CR,LF
+ "ASSIGN /STATUS",CR,LF,CR,LF
+0302 U 0000 " x Specifies the drive letter to reassign.",CR,LF
+0303 U 0000 " y Specifies the drive that x: will be assigned to.",CR,LF
+0304 U 0000 " /STATUS Displays current drive assignments.",CR,LF,CR,LF
+0305 U 0000 "Type ASSIGN without parameters to reset all drive letters to original",CR,LF
+ "assignments.",CR,LF
+ATTRIB 0000503d 0027
+0004 U 0000 "Invalid number of parameters",CR,LF
+0005 U 0000 "Invalid path or file not found",CR,LF
+0006 U 0000 "Syntax error",CR,LF
+0008 U 0000 " %1"
+0009 U 0000 "%1 %2",CR,LF
+0010 U 0000 "%1",CR,LF,"%2",CR,LF
+0011 U 0000 "%1, Code page mismatch",CR,LF,"Are you sure (Y/N)?"
+0012 U 0000 "%1",CR,LF
+0014 U 0000 CR,LF
+0015 U 0000 "Invalid file type value",CR,LF
+0199 U 0000 "Extended attribute error",CR,LF
+0201 U 0000 "Extended attribute name not found",CR,LF
+0204 U 0000 "Extended attribute name cannot be set",CR,LF
+0205 U 0000 "Extended attribute name known to this file system but not supported",CR,LF
+0206 U 0000 "Extended attribute type mismatch",CR,LF
+0208 U 0000 "Extended attribute value not supported",CR,LF
+0216 U 0000 "Not resetting system file %1",CR,LF
+0217 U 0000 "Not resetting hidden file %1",CR,LF
+0300 U 0000 "Displays or changes file attributes.",CR,LF,CR,LF
+0301 U 0000 "ATTRIB [+R | -R] [+A | -A] [+S | -S] [+H | -H] [[drive:][path]filename] [/S]",CR,LF,CR,LF
+0302 U 0000 " + Sets an attribute.",CR,LF
+0303 U 0000 " - Clears an attribute.",CR,LF
+0304 U 0000 " R Read-only file attribute.",CR,LF
+0305 U 0000 " A Archive file attribute.",CR,LF
+0306 U 0000 " S System file attribute.",CR,LF
+0307 U 0000 " H Hidden file attribute.",CR,LF
+0308 U 0000 " /S Processes files in all directories in the specified path.",CR,LF
+BACKUP 000055c2 0040
+0002 U 0000 CR,LF,"Insufficient memory",CR,LF
+0006 U 0000 CR,LF,"Invalid drive specification",CR,LF
+0014 U 0000 CR,LF,"Source and target drives are the same",CR,LF
+0015 U 0001 CR,LF,"Error executing FORMAT",CR,LF
+0016 U 0001 CR,LF,"Cannot find FORMAT.COM",CR,LF
+0017 U 0000 CR,LF,"Error opening logfile",CR,LF
+0018 U 0000 CR,LF,"Logging to file %1",CR,LF
+0019 U 0000 CR,LF,"Last backup diskette not inserted",CR,LF
+0020 U 0000 CR,LF,"WARNING! Files in the target drive",CR,LF
+ "%1:\ root directory will be erased",CR,LF
+0021 U 0000 CR,LF,"WARNING! Files in the target drive",CR,LF
+ "%1:\BACKUP directory will be erased",CR,LF
+0022 U 0000 CR,LF,"*** Backing up files to drive %1: ***",CR,LF
+0023 U 0000 "Diskette Number: %1",CR,LF
+0024 U 0000 CR,LF,"WARNING! No files were found to back up",CR,LF
+0025 U 0000 CR,LF,"Insert backup source diskette in drive %1:",CR,LF
+0026 U 0000 CR,LF,"Insert backup diskette %1 in drive %2:",CR,LF
+0027 U 0000 CR,LF,"*** Not able to backup file ***",CR,LF
+0028 U 0000 CR,LF,"Insert last backup diskette in drive %1:",CR,LF
+0029 U 0000 CR,LF,"Target cannot be used for backup",CR,LF
+0030 U 0000 CR,LF,"*** Last file not backed up ***",CR,LF
+0031 U 0000 CR,LF,"Fixed backup device %1: is full",CR,LF
+0032 U 0000 CR,LF,"Disk full error writing to BACKUP Log File",CR,LF
+0034 U 0000 CR,LF
+0035 U 0001 CR,LF,"Cannot FORMAT nonremovable drive %1:",CR,LF
+0040 U 0000 CR, LF, "Because your source drive is either ASSIGNed, JOINed, or SUBSTed", CR, LF, "it is actually the same as the target drive", CR, LF
+0041 U 0000 CR, LF, "Because your target drive is either ASSIGNed, JOINed, or SUBSTed", CR, LF, "it is actually the same as the source drive", CR, LF
+0042 U 0000 "Your target diskette is unformatted and "
+0043 U 0000 "No FORMAT program was found.",CR,LF
+ "Do you have another diskette with FORMAT on it (Y/N)? "
+0044 U 0000 CR,LF,"Insert the diskette with FORMAT in drive A:",CR,LF
+0045 U 0000 CR,LF,"Do you want to continue by inserting a new disk (Y/N)? "
+0300 U 0000 "Backs up one or more files from one disk to another.",CR,LF,CR,LF
+0301 U 0000 "BACKUP source destination-drive: [/S] [/M] [/A] [/F[:size]]",CR,LF
+ " [/D:date[/T:time]] [/L[:[drive:][path]logfile]]",CR,LF,CR,LF
+0302 U 0000 " source Specifies the file(s), drive, or directory to back up.",CR,LF
+0303 U 0000 " destination-drive: Specifies the drive to save backup copies onto.",CR,LF
+0304 U 0000 " /S Backs up contents of subdirectories.",CR,LF
+0305 U 0000 " /M Backs up only files that have changed since the last",CR,LF
+ " backup.",CR,LF
+0306 U 0000 " /A Adds backup files to an existing backup disk.",CR,LF
+0307 U 0000 " /F:[size] Specifies the size of the disk to be formatted.",CR,LF
+0308 U 0000 " /D:date Backs up only files changed on or after the specified",CR,LF
+ " date.",CR,LF
+0309 U 0000 " /T:time Backs up only files changed at or after the specified",CR,LF
+ " time.",CR,LF
+0310 U 0000 " /L[:[drive:][path]logfile]",CR,LF
+ " Creates a log file and entry to record the backup",CR,LF
+ " operation.",CR,LF
+BASIC 0000629a 0001
+0001 U 0001 "Cannot exec BASICA.COM"
+BOOT 000062d8 0001
+0001 U 0000 13,10,"Non-System disk or disk error",13,10
+ "Replace and press any key when ready",13,10,0
+CHKDSK 0000635a 0071
+0003 U 0000 "Convert lost chains to files (Y/N)?"
+0004 U 0000 "Unrecoverable error in directory"
+0005 U 0000 "Convert directory to file (Y/N)?"
+0007 U 0000 "%1 bytes total disk space"
+0008 U 0000 "%1 bytes in bad sectors"
+0009 U 0000 "%1 bytes in %2 hidden files"
+0010 U 0000 "%1 bytes in %2 directories"
+0011 U 0000 "%1 bytes in %2 user files"
+0012 U 0000 "%1 bytes in %2 recovered files"
+0013 U 0000 "%1 bytes would be in %2 recovered files"
+0014 U 0000 "%1 bytes available on disk"
+0015 U 0000 "%1 total bytes memory"
+0016 U 0000 "%1 bytes free"
+0017 U 0000 "Cannot CHKDSK a network drive"
+0018 U 0000 "Cannot CHKDSK a SUBSTed or ASSIGNed drive"
+0019 U 0000 "Probable non-DOS disk",CR,LF,"Continue (Y/N)?"
+0020 U 0000 "Disk error reading FAT %1",CR,LF
+0021 U 0000 "Directory %1"
+0022 U 0000 "%1 Contains %2 non-contiguous blocks"
+0023 U 0000 "All specified file(s) are contiguous"
+0024 U 0000 "Errors found, F parameter not specified",CR,LF,"Corrections will not be written to disk"
+0025 U 0000 " Processing cannot continue %1%2"
+0026 U 0000 " File allocation table bad, drive %1"
+0029 U 0000 " CHDIR .. failed, trying alternate method"
+0030 U 0001 " Has invalid allocation unit, file truncated"
+0031 U 0000 " Invalid sub-directory entry"
+0032 U 0000 " Does not exist"
+0033 U 0001 " First allocation unit is invalid, entry truncated"
+0034 U 0000 " Allocation error, size adjusted"
+0035 U 0000 " Cannot recover .. entry, processing continued"
+0036 U 0000 " Directory is totally empty, no . or .."
+0037 U 0000 " Directory is joined"
+0038 U 0000 " Cannot recover .. entry"
+0039 U 0000 " Entry has a bad link"
+0040 U 0000 " Entry has a bad attribute"
+0041 U 0000 " Entry has a bad size"
+0042 U 0001 " Is cross linked on allocation unit %1"
+0043 U 0000 " Cannot CHDIR to %1,",CR,LF,"tree past this point not processed"
+0044 U 0000 " tree past this point not processed"
+0045 U 0000 "%1 bytes disk space freed"
+0046 U 0000 "%1 bytes disk space would be freed"
+0047 U 0000 "Volume %1 created %2 %3",CR,LF
+0048 U 0000 "%1 total allocation units on disk"
+0049 U 0000 "%1 bytes in each allocation unit"
+0050 U 0000 "CHKDSK not available on drive %1"
+0053 U 0000 "Invalid parameter"
+0055 U 0000 "Path not found"
+0056 U 0000 "File not found"
+0058 U 0001 " %1 lost allocation units found in %2 chains."
+0059 U 0000 CR,LF
+0060 U 0000 " Cannot CHDIR to root",CR,LF
+0061 U 0000 " Disk error writing FAT %1"
+0062 U 0000 "%1" ;C05
+0063 U 0000 "Invalid current directory",0
+0064 U 0000 "%1",CR,LF
+0065 U 0000 " Insufficient room in root directory",CR,LF," Move files from root directory and repeat CHKDSK"
+0066 U 0000 "%1 %2 %3"
+0067 U 0000 "%1 %2, %3"
+0068 U 0000 "%1%2%3%4%5"
+0069 U 0000 "%1%2%3%4"
+0070 U 0000 "%1 available allocation units on disk"
+0075 U 0000 "CHKDSK /F cannot be done in a Windows/DosShell Command Prompt",CR,LF
+0076 U 0000 " - Insufficient Memory",0
+0077 U 0000 " - File allocation table bad",0
+0300 U 0000 "Checks a disk and displays a status report.",CR,LF,CR,LF
+0301 U 0000 "CHKDSK [drive:][[path]filename] [/F] [/V]",CR,LF,CR,LF
+0302 U 0000 " [drive:][path] Specifies the drive and directory to check.",CR,LF
+0303 U 0000 " filename Specifies the file(s) to check for fragmentation.",CR,LF
+0304 U 0000 " /F Fixes errors on the disk.",CR,LF
+0305 U 0000 " /V Displays the full path and name of every file on the disk.",CR,LF,CR,LF
+0306 U 0000 "Type CHKDSK without parameters to check the current disk.",CR,LF
+DEBUG 000071a0 0068
+0004 U 0000 "Allocation failed or specified buffer too small",CR,LF
+0006 U 0000 "Bad device name"
+0007 U 0000 "Cannot open list device PRN",CR,LF
+ "Enter name of list device? "
+0008 U 0000 CR,LF
+0009 U 0000 CR,LF,"Program terminated normally",CR,LF
+0010 U 0001 "Invalid drive specification",CR,LF
+0012 U 0001 "File creation error",CR,LF
+0013 U 0001 "Insufficient space on disk",CR,LF
+0014 U 0001 "Disk error reading drive %1",CR,LF
+0015 U 0001 "Disk error writing drive %1",CR,LF
+0016 U 0001 "Write protect error reading drive %1",CR,LF
+0017 U 0001 "Write protect error writing drive %1",CR,LF
+0019 U 0000 "%1^ Error"
+0020 U 0001 "Error in EXE or HEX file",CR,LF
+0021 U 0001 "EXE and HEX files cannot be written",CR,LF
+0022 U 0000 "EXEC failure"
+0023 U 0001 "(W)rite error, no destination defined",CR,LF
+0024 U 0001 "Access denied",CR,LF
+0025 U 0000 "Parity error or nonexistent memory error detected"
+0026 U 0000 "-"
+0027 U 0000 "%1 -"
+0032 U 0000 "%1%2"
+0033 U 0000 "%1:%2 %3"
+0034 U 0000 "%1 %2"
+0035 U 0000 "%1 %2",CR,LF,":"
+0036 U 0000 "%1=%2 "
+0037 U 0000 "%1 Error"
+0038 U 0000 "Writing %2%1 bytes" ;C02
+0039 U 0000 "%1:%2="
+0040 U 0000 "%1"
+0041 U 0000 "%1"
+0042 U 0000 "%1:%2 %3 %4 %5:%6"
+0044 U 0000 32,8
+0046 U 0000 "%1"
+0047 U 0000 "%1"
+0050 U 0000 "%1 of a total %2 EMS pages have been allocated",cr,lf
+0051 U 0000 "%1 of a total %2 EMS handles have been allocated",cr,lf
+0055 U 0000 "Handle created = %1 ",cr,lf
+0056 U 0000 "Logical page %1 mapped to physical page %2 ",cr,lf
+0057 U 0001 "EMS hardware/software failure",cr,lf
+0058 U 0000 "Handle not found",cr,lf
+0059 U 0000 "Invalid function code",cr,lf
+0060 U 0000 "No free handles",cr,lf
+0061 U 0000 "Save/Restore error",cr,lf
+0062 U 0000 "Total pages exceeded",cr,lf
+0063 U 0000 "Free pages exceeded",cr,lf
+0064 U 0000 "Parameter error",cr,lf
+0065 U 0000 "Logical Page out of range",cr,lf
+0066 U 0000 "Physical Page out of range",cr,lf
+0067 U 0000 "Save area already in use",cr,lf
+0068 U 0000 "Save area not in use",cr,lf
+0070 U 0001 "General EMS error",cr,lf
+0071 U 0000 "Missing or invalid EMS parameter",cr,lf
+0072 U 0000 "Handle %1 has %2 pages allocated",cr,lf
+0075 U 0000 "Physical page %1 = Frame segment %2",cr,lf
+0076 U 0003 "Handle %1 deallocated",cr,lf
+0078 U 0000 "EMS not installed",cr,lf
+0090 U 0000 "Runs Debug, a program testing and editing tool.",cr,lf,cr,lf
+0091 U 0000 "DEBUG [[drive:][path]filename [testfile-parameters]]",cr,lf,cr,lf
+0092 U 0000 " [drive:][path]filename Specifies the file you want to test.", cr,lf
+0093 U 0000 " testfile-parameters Specifies command-line information required by",cr,lf
+ " the file you want to test.",cr,lf,cr,lf
+0094 U 0000 "After Debug starts, type ? to display a list of debugging commands.",cr,lf
+0100 U 0000 "assemble A [address]",CR,LF
+ "compare C range address",CR,LF
+ "dump D [range]",CR,LF
+ "enter E address [list]",CR,LF
+0101 U 0000 "fill F range list",CR,LF
+ "go G [=address] [addresses]",CR,LF
+ "hex H value1 value2",CR,LF
+ "input I port",CR,LF
+0102 U 0000 "load L [address] [drive] [firstsector] [number]",CR,LF
+ "move M range address",CR,LF
+ "name N [pathname] [arglist]",CR,LF
+ "output O port byte",CR,LF
+0103 U 0000 "proceed P [=address] [number]",CR,LF
+ "quit Q",CR,LF
+ "register R [register]",CR,LF
+ "search S range list",CR,LF
+0104 U 0000 "trace T [=address] [value]",CR,LF
+ "unassemble U [range]",CR,LF
+ "write W [address] [drive] [firstsector] [number]",CR,LF
+0105 U 0000 "allocate expanded memory XA [#pages]",CR,LF
+ "deallocate expanded memory XD [handle]",CR,LF
+ "map expanded memory pages XM [Lpage] [Ppage] [handle]",CR,LF
+ "display expanded memory status XS",CR,LF
+DISKCOMP 0000810a 0020
+0004 U 0000 "Do not specify filename(s)",CR,LF
+ "Command format: DISKCOMP [drive1: [drive2:]] [/1] [/8]",LF,CR
+0005 U 0000 CR,LF,"Invalid drive specification",CR,LF
+ "Specified drive does not exist",CR,LF
+ "or is non-removable",CR,LF
+0006 U 0000 CR,LF,"Cannot DISKCOMP to or from",CR,LF
+ "a network drive",CR,LF
+0007 U 0000 CR,LF,"Insert FIRST diskette in drive %1:",CR,LF
+0008 U 0000 CR,LF,"Insert SECOND diskette in drive %1:",CR,LF
+0009 U 0000 CR,LF,"FIRST diskette bad or incompatible",CR,LF
+0010 U 0000 CR,LF,"SECOND diskette bad or incompatible",CR,LF
+0014 U 0000 CR,LF,"Compare another diskette (Y/N) ?"
+0015 U 0000 CR,LF,"Comparing %1 tracks",CR,LF
+ "%2 sectors per track, %3 side(s)",CR,LF
+0016 U 0000 CR,LF,"Drive types or diskette types",CR,LF
+ "not compatible",CR,LF
+0017 U 0000 CR,LF,"Unrecoverable read error on drive %2",CR,LF
+ "side %3, track %4",CR,LF
+0018 U 0000 CR,LF,"Compare error on",CR,LF,"side %3, track %4",CR,LF
+0019 U 0000 "Make sure a diskette is inserted into",CR,LF
+ "the drive and the door is closed",CR,LF
+0020 U 0000 CR,LF,"Compare process ended",CR,LF
+0021 U 0000 CR,LF,"Compare OK",CR,LF
+0022 U 0000 CR,LF
+0300 U 0000 "Compares the contents of two floppy disks.",CR,LF,CR,LF
+0301 U 0000 "DISKCOMP [drive1: [drive2:]] [/1] [/8]",CR,LF,CR,LF
+0302 U 0000 " /1 Compares the first side of the disks.",CR,LF
+0303 U 0000 " /8 Compares only the first eight sectors of each track.",CR,LF
+DISKCOPY 000086ca 0025
+0002 U 0000 CR,LF
+0004 U 0000 "Do not specify filename(s)",CR,LF
+ "Command Format: DISKCOPY [drive1: [drive2:]] [/1] [/V]",CR,LF
+0005 U 0000 CR,LF,"Invalid drive specification",CR,LF
+ "Specified drive does not exist",CR,LF
+ "or is non-removable",CR,LF
+0006 U 0000 CR,LF,"Cannot DISKCOPY to or from",CR,LF
+ "a network drive",CR,LF
+0007 U 0000 CR,LF,"Formatting while copying",CR,LF
+0008 U 0000 CR,LF,"Insert SOURCE diskette in drive %1:",CR,LF
+0009 U 0000 CR,LF,"Insert TARGET diskette in drive %1:",CR,LF
+0010 U 0000 "Make sure a diskette is inserted into",CR,LF
+ "the drive and the door is closed",CR,LF
+0011 U 0000 CR,LF,"Target diskette may be unusable",CR,LF
+0012 U 0000 CR,LF,"Target diskette unusable",CR,LF
+0016 U 0000 CR,LF,"Copy another diskette (Y/N)? "
+0017 U 0000 CR,LF,"Copying %1 tracks",CR,LF
+ "%2 sectors per track, %3 side(s)",CR,LF
+0018 U 0000 CR,LF,"Drive types or diskette types",CR,LF
+ "not compatible",CR,LF
+0019 U 0000 CR,LF,"Unrecoverable read error on drive %1",CR,LF
+ "Side %2, track %3",CR,LF
+0020 U 0000 CR,LF,"Unrecoverable write error on drive %1",CR,LF
+ "Side %2, track %3",CR,LF
+0021 U 0000 CR,LF,"Copy process ended",CR,LF
+0022 U 0000 CR,LF,"SOURCE diskette bad or incompatible"
+0023 U 0000 CR,LF,"TARGET diskette bad or incompatible"
+0030 U 0000 CR,LF,"TARGET media has lower capacity than SOURCE",CR,LF
+ "Continue anyway (Y/N)?"
+0031 U 0000 CR,LF,"Press CTRL+C to abort,",CR,LF
+ "or correct this problem and press any other key to continue . . .",CR,LF
+0300 U 0000 "Copies the contents of one floppy disk to another.",CR,LF,CR,LF
+0301 U 0000 "DISKCOPY [drive1: [drive2:]] [/1] [/V]",CR,LF,CR,LF
+0302 U 0000 " /1 Copies only the first side of the disk.",CR,LF
+0303 U 0000 " /V Verifies that the information is copied correctly.",CR,LF,CR,LF
+0304 U 0000 "The two floppy disks must be the same type.",CR,LF
+ "You may specify the same drive for drive1 and drive2.",CR,LF
+DISPLAY 00008e7b 0003
+0002 U 0000 "%1 code page driver cannot be initialized",CR,LF,BELL
+0008 U 0000 "Too many code pages specified",CR,LF,BELL
+0012 U 0000 "Invalid syntax on DISPLAY.SYS code page driver",CR,LF,BELL
+DOSKEY 00008f58 0010
+0001 U 0000 7,"An incompatible DOSKey is already installed.$"
+0002 U 0000 7,"Cannot change BUFSIZE.$"
+0003 U 0000 "DOSKey installed.$"
+0004 U 0000 "Invalid macro definition.$"
+0005 U 0000 "Edits command lines, recalls MS-DOS commands, and creates macros.",CR,LF,CR,LF
+ "DOSKEY [/REINSTALL] [/BUFSIZE=size] [/MACROS] [/HISTORY]",CR,LF
+ " [/INSERT | /OVERSTRIKE] [macroname=[text]]",CR,LF,CR,LF
+ " /REINSTALL Installs a new copy of Doskey.",CR,LF
+ " /BUFSIZE=size Sets size of command history buffer.",CR,LF
+ " /MACROS Displays all Doskey macros.",CR,LF
+ " /HISTORY Displays all commands stored in memory.",CR,LF
+ " /INSERT Specifies that new text you type is inserted in old text.",CR,LF
+ " /OVERSTRIKE Specifies that new text overwrites old text.",CR,LF
+ " macroname Specifies a name for a macro you create.",CR,LF
+ " text Specifies commands you want to record.",CR,LF,CR,LF
+ "UP and DOWN ARROWS recall commands; ESC clears command line; F7 displays",CR,LF
+ "command history; ALT+F7 clears command history; F8 searches command",CR,LF
+ "history; F9 selects a command by number; ALT+F10 clears macro definitions.",CR,LF,CR,LF
+ "The following are some special codes in Doskey macro definitions:",CR,LF
+ "$T Command separator. Allows multiple commands in a macro.",CR,LF
+ "$1-$9 Batch parameters. Equivalent to %1-%9 in batch programs.",CR,LF
+ "$* Symbol replaced by everything following macro name on command line.",CR,LF,0
+0006 U 0000 7,"Insufficent memory to store macro. Use the DOSKEY command with the /BUFSIZE",CR,LF
+ "switch to increase available memory.$",0
+0007 U 0000 7,"Incorrect DOS version$"
+0008 U 0000 CR,LF,'$'
+0020 U 0000 CR,LF,"-- More --",0
+0021 U 0000 "Line number: ",0
+DRIVER 00009659 0002
+0002 U 0000 "No drive specified",CR,LF
+0003 U 0000 "Loaded External Disk Driver for Drive %1",CR,LF
+EDLIN 000096d7 0035
+0006 U 0000 "*"
+0007 U 0000 "Invalid drive or file name",CR,LF
+0008 U 0000 "File name must be specified",CR,LF
+0010 U 0000 "File is READ-ONLY",CR,LF
+0011 U 0000 "File Creation Error",CR,LF
+0012 U 0000 "Too many files open",CR,LF
+0013 U 0000 "Read error in:",CR,LF,"%1",CR,LF
+0014 U 0000 "Cannot edit .BAK file--rename file",CR,LF
+0015 U 0000 "No room in directory for file",CR,LF
+0016 U 0000 "Disk full. Edits lost.",CR,LF
+0017 U 0000 "File not found",CR,LF
+0018 U 0000 "Entry error",CR,LF
+0019 U 0000 "New file",CR,LF
+0020 U 0000 "Not found",CR,LF
+0021 U 0000 "O.K.? "
+0022 U 0000 "Line too long",CR,LF
+0023 U 0000 "End of input file",CR,LF
+0024 U 0000 "Abort edit (Y/N)? "
+0025 U 0000 "Must specify destination line number",CR,LF
+0026 U 0000 "Not enough room to merge the entire file",CR,LF
+0027 U 0000 CR,LF
+0028 U 0000 LF
+0029 U 0000 "Continue (Y/N)?"
+0030 U 0000 "Unable to print message",CR,LF
+0031 U 0000 "%1"
+0032 U 0000 "%1:%2"
+0033 U 0000 "Cannot merge - code page mismatch",CR,LF
+0300 U 0000 "Starts Edlin, a line-oriented text editor.",CR,LF,CR,LF
+ "EDLIN [drive:][path]filename [/B]",CR,LF,CR,LF
+ " /B Ignores end-of-file (CTRL+Z) characters.",CR,LF
+0301 U 0000 "Edit line line#",CR,LF
+ "Append [#lines]A",CR,LF
+0302 U 0000 "Copy [startline],[endline],toline[,times]C",CR,LF
+ "Delete [startline][,endline]D",CR,LF
+0303 U 0000 "End (save file) E",CR,LF
+ "Insert [line]I",CR,LF
+0304 U 0000 "List [startline][,endline]L",CR,LF
+ "Move [startline],[endline],tolineM",CR,LF
+0305 U 0000 "Page [startline][,endline]P",CR,LF
+ "Quit (throw away changes) Q",CR,LF
+0306 U 0000 "Replace [startline][,endline][?]R[oldtext][CTRL+Znewtext]",CR,LF
+ "Search [startline][,endline][?]Stext",CR,LF
+0307 U 0000 "Transfer [toline]T[drive:][path]filename",CR,LF
+ "Write [#lines]W",CR,LF
+EXE2BIN 00009f1b 0012
+0002 U 0000 "Insufficient memory",CR,LF
+0003 U 0000 "Cannot find messages",CR,LF
+0004 U 0000 "Access denied",CR,LF
+0005 U 0000 "File cannot be converted",CR,LF
+0006 U 0000 "File not found",CR,LF
+0007 U 0000 "File creation error",CR,LF
+0008 U 0000 "Fix-ups needed - base segment (hex):"
+0012 U 0000 "File name must be specified",CR,LF
+0300 U 0000 "Converts .EXE (executable) files to binary format.",CR,LF,CR,LF
+0301 U 0000 "EXE2BIN [drive1:][path1]input-file [[drive2:][path2]output-file]",CR,LF,CR,LF
+0302 U 0000 " input-file Specifies the .EXE file to be converted.",CR,LF
+0303 U 0000 " output-file Specifies the binary file to be created.",CR,LF
+FASTOPEN 0000a1cd 0021
+0004 U 0000 CR,LF,"FASTOPEN installed",CR,LF
+0005 U 0000 CR,LF,"FASTOPEN already installed",CR,LF
+0006 U 0000 CR,LF,"Incorrect parameter",CR,LF
+0007 U 0000 CR,LF,"Too many drive entries",CR,LF
+0008 U 0000 CR,LF,"Same drive specified more than once",CR,LF
+0009 U 0000 CR,LF,"Invalid parameter",CR,LF
+0010 U 0000 CR,LF,"Invalid switch type",CR,LF
+0012 U 0001 CR,LF,"Invalid number of file/directory entries",CR,LF
+0013 U 0000 CR,LF,"Cannot setup expanded memory",CR,LF
+0014 U 0000 CR,LF,"Expanded memory not available",CR,LF
+0015 U 0000 CR,LF,"Invalid drive specification %1",CR,LF
+0016 U 0002 CR,LF,"FASTOPEN EMS entry count exceeded. Use fewer entries",CR,LF
+0017 U 0000 CR,LF,"Cannot use FASTOPEN for drive %1",CR,LF
+0019 U 0000 CR,LF,"Too many file/directory entries",CR,LF
+0020 U 0000 CR,LF,"FASTOPEN cannot be installed under DosShell",CR,LF
+0300 U 0000 "Decreases the amount of time needed to open frequently used files",CR,LF
+0301 U 0000 "and directories.",CR,LF,CR,LF
+0302 U 0000 "FASTOPEN drive:[[=]n] [drive:[[=]n][ ...]] [/X]",CR,LF,CR,LF
+0303 U 0000 " drive: Specifies the hard disk drive you want Fastopen to work with.",CR,LF
+0304 U 0000 " n Specifies the maximum number of file locations Fastopen retains",CR,LF
+ " in its filename cache.",CR,LF
+0305 U 0000 " /X Creates the filename cache in expanded memory.",CR,LF
+FDISK 0000a746 0140
+0004 U 0000 "Cannot FDISK with network loaded",CR,LF
+0005 U 0000 "No fixed disks present",CR,LF
+0006 U 0000 "Error reading fixed disk",CR,LF
+0007 U 0000 "Error writing fixed disk",CR,LF
+0009 U 0003 "Y",0
+0010 U 0003 "N",0
+0011 U 0000 "The master boot code has NOT been updated.",CR,LF
+0300 U 0000 "Configures a hard disk for use with MS-DOS.",CR,LF,CR,LF
+0301 U 0000 "FDISK",CR,LF
+1001 U 0000 " MS-DOS Version 5.00"
+1002 U 0000 " Fixed Disk Setup Program"
+1003 U 0000 " (C)Copyright Microsoft Corp. 1983 - 1991"
+1004 U 0000 " FDISK Options"
+1005 U 0000 "1. <R>Create DOS partition or Logical DOS Drive"
+1006 U 0000 "2. <R>Set active partition"
+1007 U 0000 "3. <R>Delete partition or Logical DOS Drive"
+1008 U 0000 "4. <R>Display partition information"
+1009 U 0000 "Press <H>Esc<R> to exit FDISK"
+1010 U 0000 "Choose one of the following:"
+1011 U 0000 "5. <R>Change current fixed disk drive"
+1012 U 0000 "Current fixed disk drive: <H><I>"
+1013 U 0000 "WARNING! <R>No partitions are set active - disk 1 is not startable unless"
+1014 U 0000 "a partition is set active"
+1015 U 0000 "Enter choice: <H>[<S> ]"
+1016 U 0000 " Create DOS Partition or Logical DOS Drive"
+1017 U 0000 "1. <R>Create Primary DOS Partition"
+1018 U 0000 "2. <R>Create Extended DOS Partition"
+1019 U 0000 "3. <R>Create Logical DOS Drive(s) in the Extended DOS Partition"
+1020 U 0000 "Press <H>Esc<R> to return to FDISK Options"
+1021 U 0000 " Create Primary DOS Partition"
+1022 U 0000 "Do you wish to use the maximum available size for a Primary DOS Partition"
+1023 U 0000 "and make the partition active (<Y>/<N>).....................? <H>[<S> ]"
+1024 U 0000 "(<Y>/<N>)...................................................? <H>[<S> ]"
+1025 U 0000 "Partition Status Type Volume Label Mbytes System Usage" ;C25
+1026 U 0000 "Total disk space is <HIIIIR> Mbytes (1 Mbyte = 1048576 bytes)"
+1027 U 0000 "Maximum space available for partition is <HIIIIR> Mbytes (<HIIIIR>)"
+1028 U 0000 "Enter partition size in Mbytes or percent of disk space (%) to"
+1029 U 0000 "create a Primary DOS Partition.................................: <H>[<IIISI>]"
+1030 U 0000 " Create Extended DOS Partition"
+1031 U 0000 "create an Extended DOS Partition..............................: <H>[<IIISI>]"
+1032 U 0000 "Press <H>Esc<R> to continue<S>"
+1033 U 0000 " Create Logical DOS Drive(s) in the Extended DOS Partition"
+1034 U 0000 "Drv Volume Label Mbytes System Usage"
+1035 U 0000 "Total Extended DOS Partition size is <HIIIIR> Mbytes (1 MByte = 1048576 bytes)"
+1036 U 0000 "Maximum space available for logical drive is <HIIIIR> Mbytes <H>(<IIII>)"
+1037 U 0000 "Enter logical drive size in Mbytes or percent of disk space (%)...<H>[<IIISI>]"
+1038 U 0000 " Set Active Partition"
+1039 U 0000 "Enter the number of the partition you want to make active...........: <H>[<S> ]"
+1040 U 0000 " Delete DOS Partition or Logical DOS Drive"
+1041 U 0000 "1. <R>Delete Primary DOS Partition"
+1042 U 0000 "2. <R>Delete Extended DOS Partition"
+1043 U 0000 "3. <R>Delete Logical DOS Drive(s) in the Extended DOS Partition"
+1044 U 0000 " Delete Primary DOS Partition"
+1045 U 0000 "WARNING! <OR>Data in the deleted Primary DOS Partition will be lost."
+1046 U 0000 "Do you wish to continue (<Y>/<N>).................? <H>[<S> ]"
+1047 U 0000 " Delete Extended DOS Partition"
+1048 U 0000 "WARNING! <OR>Data in the deleted Extended DOS Partition will be lost."
+1049 U 0000 "Do you wish to continue (<Y>/<N>).................? <H>[<S> ]"
+1050 U 0000 " Delete Logical DOS Drive(s) in the Extended DOS Partition"
+1051 U 0000 "WARNING! <OR>Data in a deleted Logical DOS Drive will be lost."
+1052 U 0000 "What drive do you want to delete...............................? <H>[<S> ]"
+1053 U 0000 "Are you sure (<Y>/<N>)..............................? <H>[<S> ]"
+1054 U 0000 "Enter Volume Label..............................? <H>[<S> ]"
+1055 U 0000 " Display Partition Information"
+1056 U 0000 "The Extended DOS Partition contains Logical DOS Drives."
+1057 U 0000 "Do you want to display the logical drive information (<Y>/<N>)......?<H>[<S> ]"
+1058 U 0000 " Display Logical DOS Drive Information"
+1059 U 0000 "System will now restart"
+1060 U 0001 "Insert DOS system diskette in drive A:"
+1061 U 0000 "Press any key when ready . . .<S>"
+1062 U 0000 "Primary DOS Partition deleted"
+1063 U 0000 "Extended DOS Partition deleted"
+1064 U 0000 "Drive deleted"
+1065 U 0000 "Partition <I> made active"
+1066 U 0000 "Primary DOS Partition created"
+1067 U 0000 "Extended DOS Partition created"
+1068 U 0000 "Logical DOS Drive created, drive letters changed or added<W>"
+1069 U 0000 "No partitions defined"
+1070 U 0000 "No logical drives defined"
+1071 U 0000 "Drive letters have been changed or deleted<W>"
+1072 U 0000 "Drive redirected"
+1073 U 0000 "Primary DOS Partition created, drive letters changed or added"
+1074 U 0000 "No fixed disks present."
+1075 U 0000 "Error reading fixed disk."
+1076 U 0000 "Error writing fixed disk."
+1077 U 0000 "Incorrect DOS version."
+1078 U 0000 "Cannot FDISK with network loaded."
+1079 U 0000 "No Primary DOS Partition to delete."
+1080 U 0000 "No Extended DOS Partition to delete."
+1081 U 0000 "Primary DOS Partition already exists."
+1082 U 0000 "Extended DOS Partition already exists."
+1083 U 0000 "No space to create a DOS partition."
+1084 U 0000 "Requested logical drive size exceeds the maximum available space.<W>"
+1085 U 0000 "Requested partition size exceeds the maximum available space.<W>"
+1086 U 0000 "No partitions to delete."
+1087 U 0000 "The only startable partition on Drive 1 is already set active.<W>"
+1088 U 0000 "No partitions to make active."
+1089 U 0000 "Partition selected (<I>) is not startable, active partition not changed.<W>"
+1090 U 0000 "Cannot create Extended DOS Partition without"
+1091 U 0000 "Primary DOS Partition on disk 1.<W>"
+1092 U 0000 "All available space in the Extended DOS Partition"
+1093 U 0000 "is assigned to logical drives.<W>"
+1094 U 0000 "Cannot delete Extended DOS Partition while logical drives exist.<W>"
+1095 U 0000 "All logical drives deleted in the Extended DOS Partition.<W>"
+1096 U 0000 " is not a choice. Please enter <III>.<W>"
+1097 U 0000 "WARNING! The partition set active is not startable.<W>"
+1098 U 0000 " Only non-startable partitions exist."
+1099 U 0000 "Only partitions on Drive 1 can be made active.<W>"
+1100 U 0000 "Maximum number of Logical DOS Drives installed.<W>"
+1101 U 0000 "Cannot create a zero size partition."
+1102 U 0000 "Drive <II> already deleted."
+1103 U 0000 "Unable to access Drive <I>.<OW>"
+1104 U 0000 "Invalid entry, please enter <III>.<W>"
+1105 U 0000 "Cannot delete Primary DOS Partition on drive 1 "
+1106 U 0000 "when an Extended DOS Partition exists.<W>"
+1107 U 0000 "Invalid entry.<W>"
+1108 U 0000 "Volume label does not match.<W>"
+1109 U 0000 "Cannot create Logical DOS Drive without"
+1110 U 0000 "an Extended DOS Partition on the current drive.<W>"
+1111 U 0000 "No Logical DOS Drive(s) to delete."
+1112 U 0000 "Message string error <I>. See header of FDISKC.MSG for error definition"
+1113 U 0000 "Internal error"
+1114 U 0001 "Invalid partition table",0
+1115 U 0001 "Error loading operating system",0
+1116 U 0001 "Missing operating system",0
+1117 U 0000 " Change Current Fixed Disk Drive"
+1118 U 0000 " Disk Drv Mbytes Free Usage"
+1119 U 0000 "(1 MByte = 1048576 bytes)"
+1120 U 0000 "Enter Fixed Disk Drive Number (1-<I>).......................<H>[<SI>]"
+1121 U 0000 "* Remote * ",0
+1122 U 0000 " Fixed Disk Drive Status"
+1123 U 0000 "What primary partition do you want to delete..? <H>[<S> ]<R>" ;C01
+1124 U 0000 "Partition selected is not a Primary DOS Partition" ;C01
+1125 U 0000 "4. <R>Delete Non-DOS Partition" ;C14
+1126 U 0000 " Delete Non-DOS Partition" ;C14
+1127 U 0000 "WARNING! <OR>Data in the deleted Non-DOS Partition will be lost." ;C14
+1128 U 0000 "What Non-DOS partition do you want to delete..? <H>[<S> ]<R>" ;C14
+1129 U 0000 "Non-DOS Partition deleted" ;C14
+1130 U 0000 "No Non-DOS Partition to delete." ;C14
+1131 U 0000 "Partition selected is not a Non-DOS Partition" ;C14
+FIND 0000c938 0012
+0004 U 0000 "FIND: "
+0300 U 0000 "Searches for a text string in a file or files.",CR,LF,CR,LF
+0301 U 0000 "FIND [/V] [/C] [/N] [/I] ""string"" [[drive:][path]filename[ ...]]",CR,LF,CR,LF
+0302 U 0000 " /V Displays all lines NOT containing the specified string.",CR,LF
+0303 U 0000 " /C Displays only the count of lines containing the string.",CR,LF
+0304 U 0000 " /N Displays line numbers with the displayed lines.",CR,LF
+0305 U 0000 " /I Ignores the case of characters when searching for the string.",CR,LF
+0306 U 0000 " ""string"" Specifies the text string to find.",CR,LF
+0307 U 0000 " [drive:][path]filename",CR,LF
+0308 U 0000 " Specifies a file or files to search.",CR,LF,CR,LF
+0309 U 0000 "If a pathname is not specified, FIND searches the text typed at the prompt",CR,LF
+0310 U 0000 "or piped from another command.",CR,LF
+FORMAT 0000ccc4 0082
+0002 U 0000 CR,"%1 percent completed. ",CR ; max 39 chars (not counting CR,LF)
+0004 U 0003 CR,"Format complete. ",CR,LF ; padded with blanks to 1 more than length of 0002 (%1 takes 3 characters)
+0007 U 0000 "Insert new diskette for drive %1:",CR,LF
+0009 U 0000 "Reinsert diskette for drive %1:",CR,LF
+0011 U 0000 CR,"Format not supported on drive %1:", CR,LF
+0012 U 0000 CR,"Invalid device parameters from device driver.",CR,LF
+0013 U 0000 CR,"Error in IOCTL call. ",CR,LF
+0014 U 0000 CR,"Not a block device. ",CR,LF
+0015 U 0000 CR,"Error writing FAT. ",CR,LF
+0016 U 0000 CR,"Error writing directory.",CR,LF
+0017 U 0000 CR,"Cannot format an ASSIGNed or SUBSTed drive. ",CR,LF
+0018 U 0000 CR,"Cannot find System Files.",CR,LF
+0019 U 0000 CR,"Cannot format a network drive.",CR,LF
+0021 U 0000 CR,"Parameters not supported.",CR,LF
+0022 U 0003 CR,"Format terminated. ",CR,LF
+0023 U 0000 CR,"Disk unsuitable for system disk.",CR,LF
+0024 U 0000 CR,"Invalid media or Track 0 bad - disk unusable.",CR,LF
+0025 U 0000 CR,"Unable to write BOOT. ",CR,LF
+0026 U 0000 CR,"Error reading directory.",CR,LF
+0028 U 0000 CR,"and press ENTER when ready..."
+0029 U 0000 CR,"Invalid Volume ID. ",CR,LF
+0031 U 0000 CR,"Enter current volume label for drive %1: "
+0032 U 0000 CR,"Parameters not compatible",CR,LF,"with fixed disk.",CR,LF
+0035 U 0000 CR,"Error reading partition table.",CR,LF
+0037 U 0000 CR,"Format broken.",CR,LF
+0038 U 0000 CR,"Format not available on drive %1:",CR,LF
+0039 U 0000 CR,"Non-System disk or disk error.",CR,LF
+0040 U 0000 CR,"Bad Partition Table. ",CR,LF
+0041 U 0000 CR,"Parameters not supported by drive.",CR,LF
+0042 U 0000 CR,LF
+0043 U 0000 CR,LF,LF
+0044 U 0000 CR,"Insert DOS disk in drive %1:",CR,LF
+0045 U 0000 CR,LF,"WARNING, ALL DATA ON NON-REMOVABLE DISK",CR,LF
+ "DRIVE %1: WILL BE LOST!",CR,LF
+ "Proceed with Format (Y/N)?"
+0046 U 0000 CR,"Format another (Y/N)?"
+0047 U 0000 CR,"Error reading partition table.",CR,LF
+0048 U 0000 CR,"Error writing partition table.",CR,LF
+0049 U 0000 CR,"Parameters not compatible.", CR,LF
+0050 U 0000 "%1 allocation units available on disk.",CR,LF
+0051 U 0000 "%1 bytes in each allocation unit.",CR,LF
+0052 U 0000 CR, "Error writing partition table.",CR,LF
+0053 U 0000 CR,"Same parameter entered twice.",CR,LF
+0054 U 0000 CR,"Must enter both /T and /N parameters.",CR,LF
+0055 U 0000 CR,"Trying to recover allocation unit %1. ",CR
+0056 U 0000 CR,"There is not enough room to create a restore file.",CR,LF
+ "You will not be able to use the unformat utility.",CR,LF
+ "Proceed with Format (Y/N)?"
+0057 U 0000 CR,"There is not enough disk space for system files. ",CR,LF
+0058 U 0000 CR,"Disk was formatted under a different version of DOS.",CR,LF
+ "This disk cannot be unformatted.",CR,LF
+ "Proceed with Format (Y/N)?"
+0059 U 0000 CR,"There was an error creating the format recovery file.",CR,LF
+ "This disk cannot be unformatted.",CR,LF
+ "Proceed with Format (Y/N)?"
+0060 U 0000 CR,"Volume label is not supported with /8 parameter.",CR,LF
+0070 U 0000 CR,"Insufficient memory to load system files.",CR,LF
+0071 U 0000 CR,"Insufficient memory.",CR,LF
+0075 U 0000 CR,"QuickFormat another (Y/N)?"
+0076 U 0000 CR,"Existing format differs from that specified.",CR,LF
+ "This disk cannot be unformatted.",CR,LF
+ "Proceed with Format (Y/N)?"
+0077 U 0000 CR,"Invalid existing format.",CR,LF
+ "This disk cannot be QuickFormatted.",CR,LF
+ "Proceed with Unconditional Format (Y/N)?"
+0078 U 0000 CR,"Formatting %1K",CR,LF
+0079 U 0000 CR,"Formatting %1M",CR,LF
+0080 U 0000 CR,"Formatting %1.%2M",CR,LF
+0081 U 0000 CR,"WARNING: This disk cannot be unformatted if system files are transferred.",CR,LF
+ "Proceed with system transfer anyway (Y/N)?"
+0082 U 0000 CR,"Verifying %1K",CR,LF
+0083 U 0000 CR,"Verifying %1M",CR,LF
+0084 U 0000 CR,"Verifying %1.%2M",CR,LF
+0085 U 0000 CR,"Saving UNFORMAT information.",CR,LF
+0086 U 0000 CR,"Checking existing disk format.",CR,LF
+0087 U 0000 CR,"QuickFormatting %1K",CR,LF
+0088 U 0000 CR,"QuickFormatting %1M",CR,LF
+0089 U 0000 CR,"QuickFormatting %1.%2M",CR,LF
+0300 U 0000 "Formats a disk for use with MS-DOS.",CR,LF,CR,LF
+0301 U 0000 "FORMAT drive: [/V[:label]] [/Q] [/U] [/F:size] [/B | /S]",CR,LF
+0302 U 0000 "FORMAT drive: [/V[:label]] [/Q] [/U] [/T:tracks /N:sectors] [/B | /S]",CR,LF
+0303 U 0000 "FORMAT drive: [/V[:label]] [/Q] [/U] [/1] [/4] [/B | /S]",CR,LF
+0304 U 0000 "FORMAT drive: [/Q] [/U] [/1] [/4] [/8] [/B | /S]",CR,LF,CR,LF
+0305 U 0000 " /V[:label] Specifies the volume label.",CR,LF
+0306 U 0000 " /Q Performs a quick format.",CR,LF
+0307 U 0000 " /U Performs an unconditional format.",CR,LF
+0308 U 0000 " /F:size Specifies the size of the floppy disk to format (such ",CR,LF
+0309 U 0000 " as 160, 180, 320, 360, 720, 1.2, 1.44, 2.88).",CR,LF
+0310 U 0000 " /B Allocates space on the formatted disk for system files.",CR,LF
+0311 U 0000 " /S Copies system files to the formatted disk.",CR,LF
+0312 U 0000 " /T:tracks Specifies the number of tracks per disk side.",CR,LF
+0313 U 0000 " /N:sectors Specifies the number of sectors per track.",CR,LF
+0314 U 0000 " /1 Formats a single side of a floppy disk.",CR,LF
+0315 U 0000 " /4 Formats a 5.25-inch 360K floppy disk in a high-density drive.",CR,LF
+0316 U 0000 " /8 Formats eight sectors per track.",CR,LF
+GRAFTABL 0000e2d0 0008
+0002 U 0000 "Active Code Page: %1",CR,LF
+0003 U 0000 "Previous Code Page: %1",CR,LF
+0004 U 0000 "None",NULL
+0005 U 0000 "Non-standard",NULL
+0300 U 0000 "Enables MS-DOS to display an extended character set in graphics mode.",CR,LF,CR,LF
+0301 U 0000 "GRAFTABL [xxx]",CR,LF
+ "GRAFTABL /STATUS",CR,LF,CR,LF
+0302 U 0000 " xxx Specifies a code page number.",CR,LF
+0303 U 0000 " /STATUS Displays the current code page selected for use with GRAFTABL.",CR,LF
+GRAPHICS 0000e4bb 0020
+0005 U 0000 "Invalid parameter: %1",CR,LF
+0007 U 0000 "Duplicate parameters not allowed",CR,LF
+0009 U 0000 "Cannot find GRAPHICS profile",CR,LF
+0010 U 0000 "Required profile statement missing before line %1",CR,LF
+0011 U 0000 "Invalid profile statement on line %1",CR,LF
+0012 U 0000 "Profile statement out of sequence on line %1",CR,LF
+0013 U 0000 "Error reading GRAPHICS profile",CR,LF
+0014 U 0000 "Syntax errors in GRAPHICS profile",CR,LF
+0015 U 0000 "Printbox ID not in GRAPHICS profile",CR,LF
+0016 U 0000 "Printer type not in GRAPHICS profile",CR,LF
+0017 U 0000 "/B invalid with a black and white printer",CR,LF
+0018 U 0000 "Unable to reload with profile supplied",CR,LF
+0300 U 0000 "Loads a program that can print graphics.",CR,LF,CR,LF
+0301 U 0000 "GRAPHICS [type] [[drive:][path]filename] [/R] [/B] [/LCD]",CR,LF
+ " [/PRINTBOX:STD | /PRINTBOX:LCD]",CR,LF,CR,LF
+0302 U 0000 " type Specifies a printer type (see User's Guide and Reference).",CR,LF
+0303 U 0000 " [drive:][path]filename",CR,LF
+ " Specifies the file containing information on supported printers.",CR,LF
+0304 U 0000 " /R Prints white on black as seen on the screen.",CR,LF
+0305 U 0000 " /B Prints the background in color for COLOR4 and COLOR8 printers.",CR,LF
+0306 U 0000 " /LCD Prints using LCD aspect ratio.",CR,LF
+0307 U 0000 " /PRINTBOX:STD | /PRINTBOX:LCD",CR,LF
+ " Specifies the print-box size, either STD or LCD.",CR,LF
+JOIN 0000eaa5 0009
+0002 U 0001 "Directory not empty",CR,LF
+0300 U 0000 "Joins a disk drive to a directory on another drive.",CR,LF,CR,LF
+0301 U 0000 "JOIN [drive1: [drive2:]path]",CR,LF
+0302 U 0000 "JOIN drive1: /D",CR,LF,CR,LF
+0303 U 0000 " drive1: Specifies a disk drive that will appear as a directory on",CR,LF
+ " drive2.",CR,LF
+0304 U 0000 " drive2: Specifies a drive to which you want to join drive1.",CR,LF
+0305 U 0000 " path Specifies the directory to which you want to join drive1. It",CR,LF
+ " must be empty and cannot be the root directory.",CR,LF
+0306 U 0000 " /D Cancels any previous JOIN commands for the specified drive.",CR,LF,CR,LF
+0307 U 0000 "Type JOIN without parameters to list currently joined drives.",CR,LF
+KEYB 0000edd8 0023
+0002 U 0000 "Current keyboard code: %1"
+0003 U 0000 "Current keyboard ID: %1"
+0004 U 0000 " code page: %1",CR,LF
+0005 U 0000 "Current CON code page: %1",CR,LF
+0006 U 0000 "Invalid keyboard code specified",CR,LF
+0007 U 0000 "Invalid keyboard ID specified",CR,LF
+0008 U 0000 "Invalid code page specified",CR,LF
+0009 U 0000 "Bad or missing Keyboard Definition File",CR,LF
+0010 U 0000 "KEYB has not been installed",CR,LF
+0011 U 0000 "Active code page not available from CON device",CR,LF
+0012 U 0000 "Code page specified has not been prepared",CR,LF
+0013 U 0000 "One or more CON code pages invalid for given keyboard code",CR,LF
+0014 U 0000 "Code page requested (%1) is not valid for given keyboard code",CR,LF
+0015 U 0000 "Code page specified is inconsistent with the selected code page",CR,LF
+0016 U 0001 "Keyboard ID specified is inconsistent with the selected keyboard layout",CR,LF
+0017 U 0000 "Unable to create KEYB table in resident memory",CR,LF
+0300 U 0000 "Configures a keyboard for a specific language.",CR,LF,CR,LF
+0301 U 0000 "KEYB [xx[,[yyy][,[drive:][path]filename]]] [/E] [/ID:nnn]",CR,LF,CR,LF
+0302 U 0000 " xx Specifies a two-letter keyboard code.",CR,LF
+0303 U 0000 " yyy ÿ Specifies the code page for the character set.",CR,LF
+0304 U 0000 " [drive:][path]filename Specifies the keyboard definition file.",CR,LF
+0305 U 0000 " /E Specifies that an enhanced keyboard is installed.",CR,LF
+0306 U 0000 " /ID:nnn Specifies the keyboard in use.",CR,LF
+MEM 0000f40f 0066
+0010 U 0000 CR,LF
+0011 U 0000 " Address Name Size Type ",CR,LF
+0012 U 0000 " ------- -------- ------ ------",CR,LF
+0013 U 0000 " Handle EMS Name Size ",CR,LF
+0014 U 0000 " ------- -------- ------ ",CR,LF
+0015 U 0000 " %1 %2 %3 %4",CR,LF
+0016 U 0000 " %1 %2 %3 ",CR,LF
+0017 U 0000 " %1 %2 ",CR,LF
+0018 U 0000 "%1 bytes total conventional memory",CR,LF
+0019 U 0000 "%1 bytes available to MS-DOS",CR,LF
+0020 U 0000 "%1 largest executable program size",CR,LF
+0021 U 0000 "%1 bytes total EMS memory",CR,LF
+0022 U 0000 "%1 bytes free EMS memory",CR,LF
+0023 U 0000 "%1 bytes total contiguous extended memory",CR,LF
+0024 U 0000 "Interrupt Vector",0
+0025 U 0000 "ROM Communication Area",0
+0026 U 0000 "DOS Communication Area",0
+0027 U 0000 "IO",0
+0028 U 0000 "MSDOS",0
+0029 U 0000 "System Data",0
+0030 U 0000 "System Program",0
+0031 U 0000 "System Device Driver",0
+0032 U 0000 "Installed Device Driver",0
+0033 U 0000 "%1:",0
+0034 U 0000 "%1: - %2:",0
+0035 U 0000 "BUFFERS=",0
+0036 U 0000 "FILES=",0
+0037 U 0000 "FCBS=",0
+0038 U 0000 "STACKS=",0
+0039 U 0000 "DEVICE=",0
+0040 U 0000 "IFS=",0
+0041 U 0000 "LASTDRIVE=",0
+0042 U 0000 "----------",0
+0043 U 0000 " ",0
+0044 U 0000 " %1 %2 %3",CR,LF
+0045 U 0001 "INSTALL=",0
+0046 U 0001 "%1 bytes available contiguous extended memory",CR,LF
+0047 U 0000 "System Stacks",0
+0048 U 0000 "-- Free --",0
+0049 U 0000 "Program",0
+0050 U 0000 "Environment",0
+0051 U 0000 "Data",0
+0052 N 0000 "%1 bytes available XMS memory",CR,LF
+0053 N 0000 " 64Kb High Memory Area available",CR,LF
+0054 N 0000 " High Memory Area in use",CR,LF
+0055 N 0000 " MS-DOS resident in High Memory Area",CR,LF
+0056 U 0000 "IBMBIO",0 ;*EGH
+0057 U 0000 "IBMDOS",0 ;*EGH
+0058 N 0000 " MS-DOS resident in ROM using High Memory Area",CR,LF
+0059 U 0000 "Conventional Memory :",CR,LF
+0060 U 0000 "Upper Memory :",CR,LF
+0061 U 0000 "Total FREE : %1 %2 ",CR,LF
+0062 U 0000 "FREE",0
+0063 U 0000 " Name Size in Decimal Size in Hex",CR,LF
+0064 U 0000 "------------- --------------------- -------------",CR,LF
+0065 U 0000 "Total bytes available to programs (Conventional+Upper) : %1 %2",CR,LF
+0066 U 0000 "Largest executable program size : %1 %2",CR,LF
+0067 U 0000 "Largest available upper memory block : %1 %2",CR,LF
+0068 U 0000 "Too much of memory fragmentation; MEM /C cannot be done",CR,LF
+0069 U 0000 "SYSTEM",0
+0070 U 0000 "Total bytes available to programs : %1 %2",CR,LF
+0300 U 0000 "Displays the amount of used and free memory in your system.",CR,LF,CR,LF
+0301 U 0000 "MEM [/PROGRAM | /DEBUG | /CLASSIFY]",CR,LF,CR,LF
+0302 U 0000 " /PROGRAM or /P Displays status of programs currently loaded in memory.",CR,LF
+0303 U 0000 " /DEBUG or /D Displays status of programs, internal drivers, and other",CR,LF
+ " information.",CR,LF
+0304 U 0000 " /CLASSIFY or /C Classifies programs by memory usage. Lists the size of",CR,LF
+ " programs, provides a summary of memory in use, and lists",CR,LF
+ " largest memory block available.",CR,LF
+MODE 000101cb 0079
+0003 U 0000 CR,LF,"Must specify COM1, COM2, COM3 or COM4",CR,LF
+0004 U 0000 CR,LF,"Resident portion of MODE loaded",CR,LF
+0005 U 0000 CR,LF,"Illegal device name",CR,LF
+0006 U 0000 CR,LF,"Printer error",CR,LF
+0007 U 0000 CR,LF,"LPT%1: set for 80",CR,LF
+0008 U 0000 CR,LF,"LPT%1: set for 132",CR,LF
+0009 U 0000 CR,LF,"Printer lines per inch set",CR,LF
+0010 U 0000 CR,LF,"Invalid baud rate specified",CR,LF
+0011 U 0000 CR,LF,"COM%1: %2,%3,%4,%5,%6",CR,LF
+0012 U 0000 "0123456789"
+0013 U 0001 CR,LF,"Do you see the %1? (Y/N) "
+0015 U 0000 "LPT%1: rerouted to COM%2:",CR,LF
+0016 U 0000 "LPT%1: not rerouted",CR,LF
+0017 U 0000 CR,LF,"%1 retry on parallel printer time-out",CR,LF
+0018 U 0000 CR,LF," Unable to shift screen %1",CR,LF
+0020 U 0000 CR,LF,"Invalid number of parameters",CR,LF
+0021 U 0000 CR,LF,"NET 042: Unable to do requested command",CR,LF
+0022 U 0001 CR,LF,"Infinite retry not supported on network printer",CR,LF
+0023 U 0001 CR,LF,"Failure to access code page font file",cr,lf
+0024 U 0000 CR,LF,"Failure to access device: %1",CR,LF
+0025 U 0001 CR,LF,"Device or code page missing from font file",CR,LF
+0026 U 0000 CR,LF,"Font file contents invalid",CR,LF
+0027 U 0001 CR,LF,"Previously prepared code page replaced",CR,LF
+0028 U 0001 CR,LF,"Active code page for device %1 is %2",CR,LF
+0029 U 0000 CR,LF,"Device %1 not prepared",CR,LF
+0030 U 0001 "%1 code pages:",CR,LF
+0031 U 0001 " code page %1",CR,LF
+0032 U 0001 CR,LF,"MODE %1 code page function completed",CR,LF
+0033 U 0002 CR,LF,"Current code page settings:",CR,LF
+0034 U 0002 " %1 - %2 code page",CR,LF
+0035 U 0002 " code page not prepared",CR,LF
+0036 U 0002 CR,LF,"Code page operation not supported on this device",CR,LF
+0037 U 0002 CR,LF,"No code page has been selected",CR,LF
+0038 U 0002 "Device error during %1",CR,LF
+0039 U 0002 "Code page not prepared",CR,LF
+0040 U 0002 CR,LF,"Current keyboard does not support this code page",CR,LF
+0041 U 0002 CR,LF,"Error during read of font file",CR,LF
+0042 U 0002 CR,LF,"Unable to perform refresh operation",CR,LF
+0043 U 0002 CR,LF
+0044 U 0002 CR,LF,"Status for device %1:",CR,LF
+0045 U 0002 "------------------"
+0046 U 0002 "----",CR,LF
+0047 U 0002 "-----",CR,LF
+0048 U 0002 "Lines=%1",CR,LF
+0049 U 0002 "Columns=%1",CR,LF
+0050 U 0002 CR,LF,"Rate and delay must be specified together",CR,LF
+0051 U 0002 "Rate=%1",CR,LF
+0052 U 0002 "Delay=%1",CR,LF
+0053 U 0002 CR,LF,"Function not supported on this computer - %1",CR,LF
+0054 U 0002 CR,LF,"Required font not loaded",CR,LF
+0055 U 0002 CR,LF,"ANSI.SYS must be installed to perform requested function",CR,LF
+0056 U 0002 CR,LF,"Baud rate required",CR,LF
+0057 U 0002 "Retry=%1",CR,LF
+0059 U 0002 "rightmost 9",0
+0060 U 0002 "leftmost 0",0
+0061 U 0002 "No",0
+0062 U 0002 "Infinite",0
+0063 U 0002 "left",0
+0064 U 0002 "right",0
+0065 U 0002 "Hardware",0
+0066 U 0002 "Prepared",0
+0067 U 0002 "status",0
+0068 U 0002 "prepare",0
+0069 U 0002 "select",0
+0070 U 0002 "refresh",0
+0071 U 0002 "write of font file to device",0
+0072 U 0002 "selected",0
+0073 U 0002 "system",0
+0300 U 0000 "Configures system devices.",CR,LF,CR,LF
+0301 U 0000 "Printer port: MODE LPTn[:] [COLS=c] [LINES=l] [RETRY=r]",CR,LF
+0302 U 0000 "Serial port: MODE COMm[:] [BAUD=b] [PARITY=p] [DATA=d] [STOP=s] [RETRY=r]",CR,LF
+0303 U 0000 "Device Status: MODE [device] [/STATUS]",CR,LF
+0304 U 0000 "Redirect printing: MODE LPTn[:]=COMm[:]",CR,LF
+0305 U 0000 "Prepare code page: MODE device CP PREPARE=((yyy[...]) [drive:][path]filename)",CR,LF
+0306 U 0000 "Select code page: MODE device CP SELECT=yyy",CR,LF
+0307 U 0000 "Refresh code page: MODE device CP REFRESH",CR,LF
+0308 U 0000 "Code page status: MODE device CP [/STATUS]",CR,LF
+0309 U 0000 "Display mode: MODE [display-adapter][,n]",CR,LF
+ " MODE CON[:] [COLS=c] [LINES=n]",CR,LF
+0310 U 0000 "Typematic rate: MODE CON[:] [RATE=r DELAY=d]",CR,LF
+MORE 00011148 0007
+0002 U 0000 "-- More --"
+0003 U 0000 "Too many arguments in command line",CR,LF
+0300 U 0000 "Displays output one screen at a time.",CR,LF,CR,LF
+0301 U 0000 "MORE < [drive:][path]filename",CR,LF
+0302 U 0000 "command-name | MORE",CR,LF,CR,LF
+0303 U 0000 " [drive:][path]filename Specifies a file to display one screen at a time.",CR,LF
+0304 U 0000 " command-name Specifies a command whose output will be displayed.",CR,LF
+MSBIO 00011319 0023
+0003 U 0000 13,10,"Unrecognized command in CONFIG.SYS"
+0004 U 0000 13,10,"$"
+0005 U 0000 13,10,"Sector size too large in file $"
+0006 U 0000 13,10,"Bad or missing $"
+0007 U 0000 "Command Interpreter",0
+0008 U 0000 13,10,"Invalid country code or code page",13,10,"$"
+0009 U 0000 13,10,"Error in COUNTRY command",13,10,"$"
+0010 U 0000 13,10, "Insufficient memory for COUNTRY.SYS file",13,10,"$"
+0011 U 0000 13,10,"Configuration too large for memory",13,10,"$"
+0012 U 0000 13,10,"Too many block devices",13,10,"$"
+0013 U 0000 13,10,"Invalid STACK parameters",13,10,"$"
+0014 U 0000 13,10,"Incorrect order in CONFIG.SYS line ","$"
+0015 U 0000 "Error in CONFIG.SYS line ","$"
+0016 U 0000 13,10,"Memory allocation error ","$"
+0017 U 0001 0DH,0AH,7,0DH,0AH, "Internal stack overflow",0DH,0AH
+ "System halted",0DH,0AH,"$"
+0018 U 0000 "HMA not available : Loading DOS low",13,10,"$"
+0019 U 0000 13,10,"failed to boot - missing local driver $"
+0020 U 0000 13,10,"Insert diskette for drive "
+0021 U 0000 "A: and press any key when ready",13,10,10,0
+0022 U 0000 13,10,"Bad command or parameters - $"
+0023 U 0000 "Fatal Error:Cannot allocate Memory for DOS", 13, 10, "$"
+0024 U 0000 "WARNING! Logical drives past Z: exist and will be ignored",13,10,"$"
+0025 U 0000 "This version of DOS will boot only on IBM machines",13,10,0
+MSDOS 00011869 0007
+0001 U 0001 13,10,"Divide overflow",13,10
+0002 U 0002 "y"
+0003 U 0002 "n"
+0004 U 0003 13,10,"A20 Hardware Error",13,10,"$"
+0005 U 0000 "Y"
+0006 U 0000 "N"
+0007 U 0000 "You must have the file WINA20.386 in the root of your boot drive",13,10
+ "to run Windows in Enhanced Mode",13,10
+NLSFUNC 000119a2 0003
+0300 U 0000 "Loads country-specific information.",CR,LF,CR,LF
+0301 U 0000 "NLSFUNC [[drive:][path]filename]",CR,LF,CR,LF
+0302 U 0000 " [drive:][path]filename Specifies the file containing country-specific",CR,LF
+ " information.",CR,LF
+PRINT 00011ac6 0034
+0002 U 0000 CR,LF
+0006 U 0000 " error reading file",CR,LF,"$"
+0007 U 0000 "File not found",CR,LF,"$"
+0008 U 0000 CR,LF,LF,"File $"
+0009 U 0000 " canceled by operator$"
+0010 U 0000 CR,LF,LF,"All files canceled by operator$"
+0011 U 0000 "File allocation table bad drive "
+0012 U 0000 "A.",CR,LF,"$"
+0013 U 0000 "List output is not assigned to a device",CR,LF
+0014 U 0000 "Resident part of PRINT installed",CR,LF
+0015 U 0000 "Cannot use PRINT - Use NET PRINT",CR,LF
+0017 U 0000 "PRINT queue is full",CR,LF
+0018 U 0000 "PRINT queue is empty",CR,LF
+0019 U 0000 "Access denied",CR,LF
+0020 U 0000 "Invalid drive specification",CR,LF
+0021 U 0000 "Errors on list device indicate that it",CR,LF
+ "may be off-line. Please check it.",CR,LF
+0022 U 0000 CR,LF,LF," %1 is currently being printed",CR,LF
+0023 U 0000 " %1 is in queue",CR,LF
+0025 U 0001 "Pathname too long",CR,LF
+0026 U 0001 "File not in PRINT queue",CR,LF
+0027 U 0000 "Name of list device [PRN]: "
+0300 U 0000 "Prints a text file while you are using other MS-DOS commands.",CR,LF,CR,LF
+0301 U 0000 "PRINT [/D:device] [/B:size] [/U:ticks1] [/M:ticks2] [/S:ticks3]",CR,LF
+0302 U 0000 " [/Q:qsize] [/T] [[drive:][path]filename[ ...]] [/C] [/P]",CR,LF,CR,LF
+0303 U 0000 " /D:device Specifies a print device.",CR,LF
+0304 U 0000 " /B:size Sets the internal buffer size, in bytes.",CR,LF
+0305 U 0000 " /U:ticks1 Waits the specified maximum number of clock ticks for the printer",CR,LF
+ " to be available.",CR,LF
+0306 U 0000 " /M:ticks2 Specifies the maximum number of clock ticks it takes to print a",CR,LF
+ " character.",CR,LF
+0307 U 0000 " /S:ticks3 Allocates the scheduler the specified number of clock ticks for",CR,LF
+ " background printing.",CR,LF
+0308 U 0000 " /Q:qsize Specifies the maximum number of files allowed in the print queue.",CR,LF
+0309 U 0000 " /T Removes all files from the print queue.",CR,LF
+0310 U 0000 " /C Cancels printing of the preceding filename and subsequent",CR,LF
+ " filenames.",CR,LF
+0311 U 0000 " /P Adds the preceding filename and subsequent filenames to the print",CR,LF
+ " queue.",CR,LF,CR,LF
+0312 U 0000 "Type PRINT without parameters to display the contents of the print queue.",CR,LF
+PRINTER 000123f8 0002
+0002 U 0000 "%1 code page driver cannot be initialized",CR,LF,BELL
+0012 U 0000 "Invalid syntax on PRINTER.SYS code page driver",CR,LF,BELL
+RECOVER 0001249d 0017
+0002 U 0000 CR,LF,"File not found",CR,LF
+0003 U 0000 CR,LF,"Cannot RECOVER an ASSIGNed or SUBSTed drive",CR,LF
+0004 U 0000 CR,LF,"Invalid drive or file name",CR,LF
+0005 U 0000 CR,LF,"WARNING - directory full",CR,LF
+0006 U 0000 CR,LF,"Cannot RECOVER a network drive", CR,LF
+0008 U 0000 CR,LF,"%1 file(s) recovered",CR,LF
+0009 U 0000 CR,LF,"%1 of %2 bytes recovered",CR,LF
+0010 U 0000 CR,LF,"Press any key to begin recovery of the",CR,LF,"file(s) on drive %1",CR,LF,CR,LF
+0011 U 0000 CR,LF,"Cannot read file allocation table",CR,LF
+0012 U 0000 CR,LF,"Cannot write file allocation table",CR,LF
+0013 U 0000 CR,LF
+0300 U 0000 "Recovers readable information from a bad or defective disk.",CR,LF,CR,LF
+0301 U 0000 "RECOVER [drive:][path]filename",CR,LF
+0302 U 0000 "RECOVER drive:",CR,LF,CR,LF
+0303 U 0000 "Consult your User's Guide and Reference before using the RECOVER command.",CR,LF
+0400 U 0000 "The current directory structure will be destroyed.",CR,LF
+ "All files will be placed in the root directory.",CR,LF
+ "Are you sure (Y/N)? "
+0401 U 0000 "The entire drive will be reconstructed,",CR,LF
+ "directory structures will be destroyed.", CR, LF
+ "Are you sure (Y/N)? "
+REPLACE 0001295a 0019
+0003 U 0000 CR,LF,"No files replaced",CR,LF
+0004 U 0000 CR,LF,"No files added",CR,LF
+0013 U 0000 CR,LF,"Replacing %1",CR,LF
+0014 U 0000 CR,LF,"Adding %1",CR,LF
+0015 U 0000 CR,LF,"%1 file(s) replaced",CR,LF
+0016 U 0000 CR,LF,"%1 file(s) added",CR,LF
+0017 U 0000 CR,LF,"No files found - %1",CR,LF
+0022 U 0000 CR,LF,"Replace %1? (Y/N)"
+0023 U 0000 CR,LF,"Add %1? (Y/N)"
+0300 U 0000 "Replaces files.",CR,LF,CR,LF
+0301 U 0000 "REPLACE [drive1:][path1]filename [drive2:][path2] [/A] [/P] [/R] [/W]",CR,LF
+ "REPLACE [drive1:][path1]filename [drive2:][path2] [/P] [/R] [/S] [/W] [/U]",CR,LF,CR,LF
+0302 U 0000 " [drive1:][path1]filename Specifies the source file or files.",CR,LF
+0303 U 0000 " [drive2:][path2] Specifies the directory where files are to be",CR,LF
+ " replaced.",CR,LF
+0304 U 0000 " /A Adds new files to destination directory. Cannot",CR,LF
+ " use with /S or /U switches.",CR,LF
+0305 U 0000 " /P Prompts for confirmation before replacing a file or",CR,LF
+ " adding a source file.",CR,LF
+0306 U 0000 " /R Replaces read-only files as well as unprotected",CR,LF
+ " files.",CR,LF
+0307 U 0000 " /S Replaces files in all subdirectories of the",CR,LF
+ " destination directory. Cannot use with the /A",CR,LF
+ " switch.",CR,LF
+0308 U 0000 " /W Waits for you to insert a disk before beginning.",CR,LF
+0309 U 0000 " /U Replaces (updates) only files that are older than",CR,LF
+ " source files. Cannot use with the /A switch.",CR,LF
+RESTORE 00013069 0035
+0002 U 0000 CR,LF,"Source and target drives are the same",CR,LF
+0003 U 0000 CR,LF,"Invalid number of parameters",CR,LF
+0006 U 0000 CR,LF,"Invalid drive specification",CR,LF
+0007 U 0000 CR,LF,"WARNING! No files were found to restore",CR,LF
+0008 U 0000 CR,LF,"Insert backup diskette %1 in drive %2:",CR,LF
+0009 U 0000 CR,LF,"Insert restore target in drive %1:",CR,LF
+0011 U 0000 CR,LF,"WARNING! Diskette is out of sequence",CR,LF
+ "Replace diskette or continue if OK",CR,LF
+0012 U 0000 CR,LF,"The last file was not restored",CR,LF
+0013 U 0000 CR,LF,"*** Files were backed up %1 ***",CR,LF
+0014 U 0000 CR,LF,"Source does not contain backup files",CR,LF
+0015 U 0000 CR,LF,"Insufficient memory",CR,LF
+0016 U 0000 CR,LF,"WARNING! File %1",CR,LF
+ "is a read-only file",CR,LF
+ "Replace the file (Y/N)?"
+0017 U 0000 CR,LF,"Restore file sequence error",CR,LF
+0018 U 0000 CR,LF,"File creation error",CR,LF
+0019 U 0000 CR,LF,"Insufficient disk space",CR,LF
+0020 U 0000 CR,LF,"*** Not able to restore file ***",CR,LF
+0021 U 0000 CR,LF,"*** Restoring files from drive %1: ***",CR,LF
+0022 U 0000 CR,LF,"WARNING! File %1",CR,LF
+ "was changed after it was backed up",CR,LF
+ "Replace the file (Y/N)?",CR,LF
+0023 U 0000 "Diskette: %1",CR,LF
+0032 U 0000 CR,LF,"*** Listing files on drive %1: ***",CR,LF
+0300 U 0000 "Restores files that were backed up by using the BACKUP command.",CR,LF,CR,LF
+0301 U 0000 "RESTORE drive1: drive2:[path[filename]] [/S] [/P] [/B:date] [/A:date] [/E:time]",CR,LF
+0302 U 0000 " [/L:time] [/M] [/N] [/D]",CR,LF,CR,LF
+0303 U 0000 " drive1: Specifies the drive on which the backup files are stored.",CR,LF
+0304 U 0000 " drive2:[path[filename]]",CR,LF
+ " Specifies the file(s) to restore.",CR,LF
+0305 U 0000 " /S Restores files in all subdirectories in the path.",CR,LF
+0306 U 0000 " /P Prompts before restoring read-only files or files changed since",CR,LF
+0307 U 0000 " the last backup (if appropriate attributes are set).",CR,LF
+0308 U 0000 " /B Restores only files last changed on or before the specified date.",CR,LF
+0309 U 0000 " /A Restores only files changed on or after the specified date.",CR,LF
+ " /E Restores only files last changed at or earlier than the specified",CR,LF
+0310 U 0000 " time.",CR,LF
+0311 U 0000 " /L Restores only files changed at or later than the specified time.",CR,LF
+0312 U 0000 " /M Restores only files changed since the last backup.",CR,LF
+0313 U 0000 " /N Restores only files that no longer exist on the destination disk.",CR,LF
+0314 U 0000 " /D Displays files on the backup disk that match specifications.",CR,LF
+SHARE 00013b08 0005
+0003 U 0000 "SHARE cannot be installed under DOSSHELL.",CR,LF
+0300 U 0000 "Installs file-sharing and locking capabilities on your hard disk.",CR,LF,CR,LF
+0301 U 0000 "SHARE [/F:space] [/L:locks]",CR,LF,CR,LF
+0302 U 0000 " /F:space Allocates file space (in bytes) for file-sharing information.",CR,LF
+0303 U 0000 " /L:locks Sets the number of files that can be locked at one time.",CR,LF
+SORT 00013cae 0009
+0005 U 0000 "SORT: "
+0300 U 0000 "Sorts input and writes results to the screen, a file, or another device.",CR,LF,CR,LF
+0301 U 0000 "SORT [/R] [/+n] < [drive1:][path1]filename1 [> [drive2:][path2]filename2]",CR,LF
+0302 U 0000 "[command |] SORT [/R] [/+n] [> [drive2:][path2]filename2]",CR,LF,CR,LF
+0303 U 0000 " /R Reverses the sort order; that is, sorts Z to A,",CR,LF
+ " then 9 to 0.",CR,LF
+0304 U 0000 " /+n Sorts the file according to characters in",CR,LF
+ " column n.",CR,LF
+0305 U 0000 " [drive1:][path1]filename1 Specifies a file to be sorted.",CR,LF
+0306 U 0000 " [drive2:][path2]filename2 Specifies a file where the sorted input is to be ",CR,LF
+ " stored.",CR,LF
+0307 U 0000 " command Specifies a command whose output is to be sorted.",CR,LF
+SUBST 0001405f 0009
+0002 U 0001 "Incorrect number of parameters",CR,LF
+0005 U 0000 "Drive already SUBSTed",CR,LF
+0300 U 0000 "Associates a path with a drive letter.",CR,LF,CR,LF
+0301 U 0000 "SUBST [drive1: [drive2:]path]",CR,LF
+0302 U 0000 "SUBST drive1: /D",CR,LF,CR,LF
+0303 U 0000 " drive1: Specifies a virtual drive to which you want to assign a path.",CR,LF
+0304 U 0000 " [drive:2]path Specifies a physical drive and path you want to assign to",CR,LF
+ " a virtual drive.",CR,LF
+0305 U 0000 " /D Deletes a substituted (virtual) drive.",CR,LF,CR,LF
+0306 U 0000 "Type SUBST with no parameters to display a list of current virtual drives.",CR,LF
+SYS 0001431a 0015
+0004 U 0000 "Invalid drive specification",CR,LF
+0007 U 0000 "No room for system on destination disk",CR,LF
+0008 U 0001 "Invalid path or System files not found",CR,LF
+0010 U 0000 "No system on default drive",CR,LF
+0011 U 0000 "Cannot specify default drive",CR,LF
+0012 U 0000 "Write failure, diskette unusable",CR,LF
+0014 U 0000 "Insert system disk in drive %1",CR,LF
+0016 U 0000 "Not able to SYS to %1 file system",CR,LF
+0019 U 0000 "Source path and target drive cannot be the same",CR,LF ;C04
+0025 U 0000 CR,LF,"Could not copy COMMAND.COM onto target disk",CR,LF
+0026 U 0000 "Insufficient memory",CR,LF
+0300 U 0000 "Copies MS-DOS system files and command interpreter to a disk you specify.",CR,LF,CR,LF
+0301 U 0000 "SYS [drive1:][path] drive2:",CR,LF,CR,LF
+0302 U 0000 " [drive1:][path] Specifies the location of the system files.",CR,LF
+0303 U 0000 " drive2: Specifies the drive the files are to be copied to.",CR,LF
+TREE 000146e8 0008
+0002 U 0000 "Directory PATH listing for Volume %1",CR,LF
+0003 U 0000 "Directory PATH listing",CR,LF
+0004 U 0000 "No sub-directories exist",CR,LF,LF
+0007 U 0000 "ÀÄó"
+0300 U 0000 "Graphically displays the directory structure of a drive or path.",CR,LF,CR,LF
+0301 U 0000 "TREE [drive:][path] [/F] [/A]",CR,LF,CR,LF
+0302 U 0000 " /F Displays the names of the files in each directory.",CR,LF
+0303 U 0000 " /A Uses ASCII instead of extended characters.",CR,LF
+XCOPY 000148d6 0033
+0004 U 0000 "Does %1 specify a file name",CR,LF
+ "or directory name on the target",CR,LF
+ "(F = file, D = directory)?"
+0005 U 0000 "Press any key to begin copying file(s)"
+0006 U 0000 "Path too long",CR,LF
+0008 U 0000 "Cannot perform a cyclic copy",CR,LF
+0012 U 0000 "Cannot XCOPY from a reserved device",CR,LF
+0021 U 0000 "Invalid number of parameters",CR,LF
+0022 U 0000 "Cannot XCOPY to a reserved device",CR,LF
+0024 U 0000 "File creation error",CR,LF
+0025 U 0000 "Reading source file(s)...",CR,LF
+0026 U 0000 CR,LF
+0027 U 0000 "%1 File(s) copied",CR,LF
+0028 U 0000 "%1 File not found",CR,LF
+0029 U 0000 "F D "
+0030 U 0000 "%1%2",CR,LF
+0031 U 0000 "%1\%2",CR,LF
+0032 U 0000 "%1",CR,LF
+0033 U 0000 "%1%2 (Y/N)?"
+0034 U 0000 "%1\%2 (Y/N)?"
+0036 U 0000 "Invalid Path, not all directories/files copied",CR,LF ;C02
+0300 U 0000 "Copies files (except hidden and system files) and directory trees.",CR,LF,CR,LF
+0301 U 0000 "XCOPY source [destination] [/A | /M] [/D:date] [/P] [/S [/E]] [/V] [/W]",CR,LF,CR,LF
+0302 U 0000 " source Specifies the file(s) to copy.",CR,LF
+0303 U 0000 " destination Specifies the location and/or name of new files.",CR,LF
+0304 U 0000 " /A Copies files with the archive attribute set,",CR,LF
+0305 U 0000 " doesn't change the attribute.",CR,LF
+0306 U 0000 " /M Copies files with the archive attribute set,",CR,LF
+0307 U 0000 " turns off the archive attribute.",CR,LF
+0308 U 0000 " /D:date Copies files changed on or after the specified date.",CR,LF
+0309 U 0000 " /P Prompts you before creating each destination file.",CR,LF
+0310 U 0000 " /S Copies directories and subdirectories except empty ones.",CR,LF
+0311 U 0000 " /E Copies any subdirectories, even if empty.",CR,LF
+0312 U 0000 " /V Verifies each new file.",CR,LF
+0313 U 0000 " /W Prompts you to press a key before copying.",CR,LF
diff --git a/private/utils/ulib/src/winnls.old b/private/utils/ulib/src/winnls.old
new file mode 100644
index 000000000..f34273d1d
--- /dev/null
+++ b/private/utils/ulib/src/winnls.old
@@ -0,0 +1,183 @@
+#include "ulib.hxx"
+
+
+extern "C" {
+
+ #include "string.h"
+
+}
+
+
+BOOL
+GetQualifiedLocale(
+ WORD wType,
+ LPVOID lpInput,
+ LPLC_ID lpOutID,
+ LPLC_STRINGS lpOutStr
+ )
+
+{
+
+ char Unknown[] = "UNKNOWN";
+
+ // unreferenced parameters
+ (void)(wType);
+ (void)(lpInput);
+ (void)(lpOutID);
+ (void)(lpOutStr);
+
+ if ( lpOutID ) {
+
+ PLC_ID Locale = lpOutID;
+
+ Locale->wLanguage = 0;
+ Locale->wCountry = 0;
+ Locale->wCodePage = 0;
+ }
+
+ if ( lpOutStr ) {
+
+ strcpy( lpOutStr->szLanguage, Unknown );
+ strcpy( lpOutStr->szCountry, Unknown );
+ strcpy( lpOutStr->szCodePage, Unknown );
+ }
+
+ return( TRUE );
+}
+
+HLOCALE
+OpenLocale(
+ LPLC_ID lpLCID
+ )
+
+{
+ // unreferenced parameters
+ (void)(lpLCID);
+
+ return( 1 );
+}
+
+int
+CompareString(
+ HLOCALE hLocale,
+ DWORD dwCmpFlags,
+ LPWSTR lpwstrString1,
+ int nCount1,
+ LPWSTR lpwstrString2,
+ int nCount2
+ )
+
+{
+
+ register int result;
+
+ // unreferenced parameters
+ (void)(hLocale);
+
+
+ DbgPtrAssert( lpwstrString1 );
+ DbgPtrAssert( lpwstrString2 );
+
+ if( nCount1 == -1 ) {
+ nCount1 = strlen(( PCCCHAR ) lpwstrString1 );
+ }
+
+ if( nCount2 == -1 ) {
+ nCount2 = strlen(( PCCCHAR ) lpwstrString2 );
+ }
+
+ if( dwCmpFlags & CF_IGNORECASE ) {
+ result = strnicmp(( PCCCHAR ) lpwstrString1,
+ ( PCCCHAR ) lpwstrString2, min( nCount1, nCount2 ));
+ } else {
+ result = strncmp(( PCCCHAR ) lpwstrString1,
+ ( PCCCHAR ) lpwstrString2, min( nCount1, nCount2 ));
+ }
+
+ if( result < 0 ) {
+ result = 1;
+ } else if( result == 0 ) {
+ result = 2;
+ } else {
+ result = 3;
+ }
+
+ if(( result != 2 ) || ( nCount1 == nCount2 )) {
+ return( result );
+ } else {
+ return nCount1 < nCount2 ? 1 : 3;
+ }
+}
+
+int
+WideCharToMultiByte (
+ WORD wCodePage,
+ LPWSTR lpWideCharStr,
+ int nWideChar,
+ LPSTR lpMultiByteStr,
+ int nChar,
+ LPCHAR lpDefaultChar
+ )
+{
+ int i;
+ PCHAR pWccString = (PCHAR)lpWideCharStr;
+
+ // unreferenced parameters
+ (void)(wCodePage);
+ (void)(lpDefaultChar);
+
+ if (!lpWideCharStr) {
+ return 0;
+ }
+
+ if (nWideChar == -1) {
+ nWideChar = strlen((PCCCHAR)pWccString)+1;
+ }
+
+ if (nChar == 0) {
+ return nWideChar;
+ }
+
+ for (i = 0; (i < nChar) && (nWideChar--); i++) {
+ lpMultiByteStr[i] = pWccString[i];
+ }
+
+ return i;
+
+}
+
+
+int
+MultiByteToWideChar(
+ WORD wCodePage,
+ LPSTR lpMultiByteStr,
+ int nChar,
+ LPWSTR lpWideCharStr,
+ int nWideChar
+ )
+
+{
+ int i = 0;
+ PCHAR pWccString = (PCHAR)lpWideCharStr;
+
+ // unreferenced parameters
+ (void)(wCodePage);
+
+ if (!lpMultiByteStr) {
+ return 0;
+ }
+
+ if( nChar == -1 ) {
+ nChar = strlen(( PCCCHAR ) lpMultiByteStr )+1;
+ }
+
+ if (nWideChar == 0) {
+ return nChar;
+ }
+
+ for ( i = 0; (i < nWideChar) && (nChar--) ; i++ ) {
+ pWccString[ i ] = ( CHAR ) lpMultiByteStr[i];
+ }
+
+ return i;
+}
diff --git a/private/utils/ulib/src/wstring.cxx b/private/utils/ulib/src/wstring.cxx
new file mode 100644
index 000000000..dd3b3e0c8
--- /dev/null
+++ b/private/utils/ulib/src/wstring.cxx
@@ -0,0 +1,1606 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ wstring.cxx
+
+Author:
+
+ Norbert P. Kusters (norbertk) 6-Aug-92
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _ULIB_MEMBER_
+
+#include "ulib.hxx"
+#include "wstring.hxx"
+
+#include <stdio.h>
+#include <wchar.h>
+
+BOOLEAN WSTRING::_UseAnsiConversions = FALSE;
+BOOLEAN WSTRING::_UseConsoleConversions = FALSE;
+#if defined DBCS
+BOOLEAN WSTRING::_UseAnsiConversionsPrev = FALSE;
+BOOLEAN WSTRING::_UseConsoleConversionsPrev = FALSE;
+#endif // DBCS
+
+// Helper functions for OEM/Unicode conversion. Note that these
+// are abstracted to private functions to make it easier to set
+// them up for various environments.
+//
+#if defined( _AUTOCHECK_ )
+
+INLINE
+BOOLEAN
+WSTRING::ConvertOemToUnicodeN(
+ PWSTR UnicodeString,
+ ULONG MaxBytesInUnicodeString,
+ PULONG BytesInUnicodeString,
+ PCHAR OemString,
+ ULONG BytesInOemString
+ )
+{
+ return _UseAnsiConversions ?
+ NT_SUCCESS(RtlMultiByteToUnicodeN( UnicodeString,
+ MaxBytesInUnicodeString,
+ BytesInUnicodeString,
+ OemString,
+ BytesInOemString )) :
+ NT_SUCCESS(RtlOemToUnicodeN( UnicodeString,
+ MaxBytesInUnicodeString,
+ BytesInUnicodeString,
+ OemString,
+ BytesInOemString ));
+}
+
+INLINE
+BOOLEAN
+WSTRING::ConvertUnicodeToOemN(
+ PCHAR OemString,
+ ULONG MaxBytesInOemString,
+ PULONG BytesInOemString,
+ PWSTR UnicodeString,
+ ULONG BytesInUnicodeString
+ )
+{
+ return _UseAnsiConversions ?
+ NT_SUCCESS(RtlUnicodeToMultiByteN( OemString,
+ MaxBytesInOemString,
+ BytesInOemString,
+ UnicodeString,
+ BytesInUnicodeString )) :
+ NT_SUCCESS(RtlUnicodeToOemN( OemString,
+ MaxBytesInOemString,
+ BytesInOemString,
+ UnicodeString,
+ BytesInUnicodeString ));
+}
+
+#else // _AUTOCHECK_ not defined
+
+INLINE
+BOOLEAN
+ConvertToUnicodeWithConsoleCP(
+ PWSTR UnicodeString,
+ ULONG MaxBytesInUnicodeString,
+ PULONG BytesInUnicodeString,
+ PCHAR OemString,
+ ULONG BytesInOemString
+ )
+{
+ int result;
+
+ *BytesInUnicodeString =
+ MultiByteToWideChar( GetConsoleCP(),
+ MB_PRECOMPOSED,
+ OemString,
+ BytesInOemString,
+ UnicodeString,
+ MaxBytesInUnicodeString/sizeof(WCHAR) ) *
+ sizeof(WCHAR);
+
+ return( *BytesInUnicodeString != 0 );
+}
+
+#if defined DBCS // ConvertToOemWithConsoleCP()
+INLINE
+BOOLEAN
+ConvertToOemWithConsoleCP(
+ PCHAR OemString,
+ ULONG MaxBytesInOemString,
+ PULONG BytesInOemString,
+ PWSTR UnicodeString,
+ ULONG BytesInUnicodeString
+ )
+{
+ int result;
+
+ *BytesInOemString =
+ WideCharToMultiByte( GetConsoleCP(),
+ 0,
+ UnicodeString,
+ BytesInUnicodeString/sizeof(WCHAR),
+ OemString,
+ MaxBytesInOemString,
+ NULL,
+ NULL );
+
+ return( *BytesInOemString != 0 );
+}
+#endif // DBCS
+
+INLINE
+BOOLEAN
+WSTRING::ConvertOemToUnicodeN(
+ PWSTR UnicodeString,
+ ULONG MaxBytesInUnicodeString,
+ PULONG BytesInUnicodeString,
+ PCHAR OemString,
+ ULONG BytesInOemString
+ )
+{
+ return
+ _UseConsoleConversions ?
+ ConvertToUnicodeWithConsoleCP( UnicodeString,
+ MaxBytesInUnicodeString,
+ BytesInUnicodeString,
+ OemString,
+ BytesInOemString ) :
+ _UseAnsiConversions ?
+ NT_SUCCESS(RtlMultiByteToUnicodeN( UnicodeString,
+ MaxBytesInUnicodeString,
+ BytesInUnicodeString,
+ OemString,
+ BytesInOemString )) :
+ NT_SUCCESS(RtlOemToUnicodeN( UnicodeString,
+ MaxBytesInUnicodeString,
+ BytesInUnicodeString,
+ OemString,
+ BytesInOemString ));
+}
+
+INLINE
+BOOLEAN
+WSTRING::ConvertUnicodeToOemN(
+ PCHAR OemString,
+ ULONG MaxBytesInOemString,
+ PULONG BytesInOemString,
+ PWSTR UnicodeString,
+ ULONG BytesInUnicodeString
+ )
+{
+#if defined DBCS // WSTRING::ConvertUnicodeToOemN()
+ return
+ _UseConsoleConversions ?
+ ConvertToOemWithConsoleCP( OemString,
+ MaxBytesInOemString,
+ BytesInOemString,
+ UnicodeString,
+ BytesInUnicodeString ) :
+ _UseAnsiConversions ?
+#else
+ return _UseAnsiConversions ?
+#endif // DBCS
+ NT_SUCCESS(RtlUnicodeToMultiByteN( OemString,
+ MaxBytesInOemString,
+ BytesInOemString,
+ UnicodeString,
+ BytesInUnicodeString )) :
+ NT_SUCCESS(RtlUnicodeToOemN( OemString,
+ MaxBytesInOemString,
+ BytesInOemString,
+ UnicodeString,
+ BytesInUnicodeString ));
+}
+
+
+#endif // not autochk
+
+// Implement wcscoll and wcsicoll for AUTOCHECK,
+// since they're not in LIBCNT.LIB
+
+#if defined( _AUTOCHECK_ )
+
+int _CRTAPI1 wcscoll(const wchar_t * left, const wchar_t * right)
+{
+ return wcscmp(left, right);
+}
+
+int _CRTAPI1 _wcsicoll(const wchar_t * left, const wchar_t * right)
+{
+ return _wcsicmp(left, right);
+}
+
+#endif // _AUTOCHECK_
+
+INLINE
+VOID
+WSTRING::Construct(
+ )
+{
+ _s = NULL;
+ _l = 0;
+}
+
+
+DEFINE_CONSTRUCTOR( WSTRING, OBJECT );
+
+
+ULIB_EXPORT
+BOOLEAN
+WSTRING::Initialize(
+ IN PCWSTRING InitialString,
+ IN CHNUM Position,
+ IN CHNUM Length
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the current string by copying the contents
+ of the given string.
+
+Arguments:
+
+ InitialString - Supplies the initial string.
+ Position - Supplies the position in the given string to start at.
+ Length - Supplies the length of the string.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ DebugAssert(Position <= InitialString->_l);
+
+ Length = min(Length, InitialString->_l - Position);
+
+ if (!NewBuf(Length)) {
+ return FALSE;
+ }
+
+ memcpy(_s, InitialString->_s + Position, (UINT) Length*sizeof(WCHAR));
+
+ return TRUE;
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+WSTRING::Initialize(
+ IN PCWSTR InitialString,
+ IN CHNUM StringLength
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the current string by copying the contents
+ of the given string.
+
+Arguments:
+
+ InitialString - Supplies the initial string.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ if (StringLength == TO_END) {
+ StringLength = wcslen(InitialString);
+ }
+
+ if (!NewBuf(StringLength)) {
+ return FALSE;
+ }
+
+ memcpy(_s, InitialString, (UINT) StringLength*sizeof(WCHAR));
+
+ return TRUE;
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+WSTRING::Initialize(
+ IN PCSTR InitialString,
+ IN CHNUM StringLength
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the current string by copying the contents
+ of the given string.
+
+Arguments:
+
+ InitialString - Supplies the initial string.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ CHNUM length;
+ BOOLEAN status;
+
+ if (StringLength == TO_END) {
+ StringLength = strlen(InitialString);
+ }
+
+ if (!StringLength) {
+ return Resize(0);
+ }
+
+
+ // We want to avoid making two calls to RtlOemToUnicodeN so
+ // try to guess an adequate size for the buffer.
+
+ if (!NewBuf(StringLength)) {
+ return FALSE;
+ }
+
+ status = ConvertOemToUnicodeN(_s, _l*sizeof(WCHAR),
+ &length, (PSTR) InitialString,
+ StringLength);
+ length /= sizeof(WCHAR);
+
+ if (status) {
+ return Resize(length);
+ }
+
+
+ // We didn't manage to make in one try so ask exactly how much
+ // we need and then make the call.
+
+ status = ConvertOemToUnicodeN(NULL, 0, &length, (PSTR) InitialString,
+ StringLength);
+ length /= sizeof(WCHAR);
+
+ if (!status || !NewBuf(length)) {
+ return FALSE;
+ }
+
+ status = ConvertOemToUnicodeN(_s, _l*sizeof(WCHAR),
+ &length, (PSTR) InitialString, StringLength);
+
+ if (!status) {
+ return FALSE;
+ }
+
+ DebugAssert(length == _l*sizeof(WCHAR));
+
+ return TRUE;
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+WSTRING::Initialize(
+ IN LONG Number
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the current string by copying the contents
+ of the given string.
+
+Arguments:
+
+ Number - Supplies the number to initialize the string to.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ CHAR tmp[64];
+
+ sprintf(tmp, "%d", Number);
+ return Initialize(tmp);
+}
+
+
+NONVIRTUAL
+ULIB_EXPORT
+PWSTRING
+WSTRING::QueryString(
+ IN CHNUM Position,
+ IN CHNUM Length
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns a copy of this string from the specified
+ coordinates.
+
+Arguments:
+
+ Position - Supplies the initialize position of the string.
+ Length - Supplies the length of the string.
+
+Return Value:
+
+ A pointer to a string or NULL.
+
+--*/
+{
+ PWSTRING p;
+
+ if (!(p = NEW DSTRING) ||
+ !p->Initialize(this, Position, Length)) {
+
+ DELETE(p);
+ }
+
+ return p;
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+WSTRING::QueryNumber(
+ OUT PLONG Number,
+ IN CHNUM Position,
+ IN CHNUM Length
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine queries a number from the string.
+
+Arguments:
+
+ Number - Returns the number parsed out of the string.
+ Position - Supplies the position of the number.
+ Length - Supplies the length of the number.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ FSTRING String;
+ PSTR p;
+ CHNUM spn;
+
+ if (Position >= _l) {
+ return FALSE;
+ }
+
+ Length = min(Length, _l - Position);
+
+ //
+ // Note that 123+123 will be a number!
+ //
+ String.Initialize((PWSTR) L"1234567890+-");
+
+ spn = Strspn(&String, Position);
+
+ if ((spn == INVALID_CHNUM || spn >= Position + Length) &&
+ (p = QuerySTR(Position, Length))) {
+
+ *Number = atol(p);
+
+ DELETE(p);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+ULIB_EXPORT
+VOID
+WSTRING::DeleteChAt(
+ IN CHNUM Position,
+ IN CHNUM Length
+ )
+/*++
+
+Routine Description:
+
+ This routine removes the character at the given position.
+
+Arguments:
+
+ Position - Supplies the position of the character to remove.
+ Length - Supplies the number of characters to remove.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ DebugAssert(Position <= _l);
+
+ Length = min(Length, _l - Position);
+
+ memmove(_s + Position, _s + Position + Length,
+ (UINT) (_l - Position - Length)*sizeof(WCHAR));
+
+ Resize(_l - Length);
+}
+
+
+NONVIRTUAL
+ULIB_EXPORT
+BOOLEAN
+WSTRING::InsertString(
+ IN CHNUM AtPosition,
+ IN PCWSTRING String,
+ IN CHNUM FromPosition,
+ IN CHNUM FromLength
+ )
+/*++
+
+Routine Description:
+
+ This routine inserts the given string at the given position in
+ this string.
+
+Arguments:
+
+ AtPosition - Supplies the position at which to insert the string.
+ String - Supplies the string to insert.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ CHNUM old_length;
+
+ DebugAssert(AtPosition <= _l);
+ DebugAssert(FromPosition <= String->_l);
+
+ FromLength = min(FromLength, String->_l - FromPosition);
+
+ old_length = _l;
+ if (!Resize(_l + FromLength)) {
+ return FALSE;
+ }
+
+ memmove(_s + AtPosition + FromLength, _s + AtPosition,
+ (UINT) (old_length - AtPosition)*sizeof(WCHAR));
+
+ memcpy(_s + AtPosition, String->_s + FromPosition,
+ (UINT) FromLength*sizeof(WCHAR));
+
+ return TRUE;
+}
+
+
+NONVIRTUAL
+ULIB_EXPORT
+BOOLEAN
+WSTRING::Replace(
+ IN CHNUM AtPosition,
+ IN CHNUM AtLength,
+ IN PCWSTRING String,
+ IN CHNUM FromPosition,
+ IN CHNUM FromLength
+ )
+/*++
+
+Routine Description:
+
+ This routine replaces the contents of this string from
+ 'Position' to 'Length' with the contents of 'String2'
+ from 'Position2' to 'Length2'.
+
+Arguments:
+
+ AtPosition - Supplies the position to replace at.
+ AtLength - Supplies the length to replace at.
+ String - Supplies the string to replace with.
+ FromPosition - Supplies the position to replace from in String2.
+ FromLength - Supplies the position to replace from in String2.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ CHNUM old_length;
+
+ DebugAssert(AtPosition <= _l);
+ DebugAssert(FromPosition <= String->_l);
+
+ AtLength = min(AtLength, _l - AtPosition);
+ FromLength = min(FromLength, String->_l - FromPosition);
+
+ // Make sure up front that we have the room but don't disturb
+ // the string.
+
+ if (FromLength > AtLength) {
+ old_length = _l;
+ if (!Resize(_l + FromLength - AtLength)) {
+ return FALSE;
+ }
+ Resize(old_length);
+ }
+
+ DeleteChAt(AtPosition, AtLength);
+ if (!InsertString(AtPosition, String, FromPosition, FromLength)) {
+ DebugAbort("This absolutely can never happen\n");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+ULIB_EXPORT
+PWSTR
+WSTRING::QueryWSTR(
+ IN CHNUM Position,
+ IN CHNUM Length,
+ OUT PWSTR Buffer,
+ IN CHNUM BufferLength,
+ IN BOOLEAN ForceNull
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine makes a copy of this string into the provided
+ buffer. If this string is not provided then a buffer is
+ allocated on the heap.
+
+Arguments:
+
+ Position - Supplies the position within this string.
+ Length - Supplies the length of this string to take.
+ Buffer - Supplies the buffer to copy to.
+ BufferLength - Supplies the number of characters in the buffer.
+ ForceNull - Specifies whether or not to force the final character
+ of the buffer to be NULL in the case when there
+ isn't enough room for the whole string including
+ the NULL.
+
+Return Value:
+
+ A pointer to a NULL terminated string.
+
+--*/
+{
+ DebugAssert(Position <= _l);
+
+ Length = min(Length, _l - Position);
+
+ if (!Buffer) {
+ BufferLength = Length + 1;
+ if (!(Buffer = (PWCHAR) MALLOC(BufferLength*sizeof(WCHAR)))) {
+ return NULL;
+ }
+ }
+
+ if (BufferLength > Length) {
+ memcpy(Buffer, _s + Position, (UINT) Length*sizeof(WCHAR));
+ Buffer[Length] = 0;
+ } else {
+ memcpy(Buffer, _s + Position, (UINT) BufferLength*sizeof(WCHAR));
+ if (ForceNull) {
+ Buffer[BufferLength - 1] = 0;
+ }
+ }
+
+ return Buffer;
+}
+
+
+ULIB_EXPORT
+PSTR
+WSTRING::QuerySTR(
+ IN CHNUM Position,
+ IN CHNUM Length,
+ OUT PSTR Buffer,
+ IN CHNUM BufferLength,
+ IN BOOLEAN ForceNull
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes a multi-byte version of the current
+ unicode string. If the buffer is not supplied then it
+ will be allocated by this routine.
+
+Arguments:
+
+ Position - Supplies the position within this string.
+ Length - Supplies the length of this string to take.
+ Buffer - Supplies the buffer to convert into.
+ BufferLength - Supplies the number of characters in this buffer.
+ ForceNull - Specifies whether or not to force a NULL even
+ when the buffer is too small for the string.
+
+Return Value:
+
+ A pointer to a NULL terminated multi byte string.
+
+--*/
+{
+ ULONG ansi_length;
+
+ DebugAssert(Position <= _l);
+
+ Length = min(Length, _l - Position);
+
+
+ // First special case the empty result.
+
+ if (!Length) {
+
+ if (!Buffer) {
+ if (!(Buffer = (PSTR) MALLOC(1))) {
+ return NULL;
+ }
+ } else if (!BufferLength) {
+ return NULL;
+ }
+
+ Buffer[0] = 0;
+ return Buffer;
+ }
+
+
+ // Next case is that the buffer is not provided and thus
+ // we have to figure out what size it should be.
+
+ if (!Buffer) {
+
+ // We want to avoid too many calls to RtlUnicodeToOemN
+ // so we'll estimate a correct size for the buffer and
+ // hope that that works.
+
+ BufferLength = 2*Length + 1;
+ if (!(Buffer = (PSTR) MALLOC(BufferLength))) {
+ return NULL;
+ }
+
+ if (ConvertUnicodeToOemN(Buffer, BufferLength - 1,
+ &ansi_length, _s + Position,
+ Length*sizeof(WCHAR))) {
+ Buffer[ansi_length] = 0;
+ return Buffer;
+ }
+
+
+ // We failed to estimate the necessary size of the buffer.
+ // So ask the correct size and try again.
+
+ FREE(Buffer);
+
+ if (!ConvertUnicodeToOemN(NULL, 0, &ansi_length,
+ _s + Position, Length*sizeof(WCHAR))) {
+ return NULL;
+ }
+
+ BufferLength = ansi_length + 1;
+ if (!(Buffer = (PSTR) MALLOC(BufferLength))) {
+ return NULL;
+ }
+ }
+
+ if (!ConvertUnicodeToOemN(Buffer, BufferLength, &ansi_length,
+ _s + Position, Length*sizeof(WCHAR))) {
+ return NULL;
+ }
+
+ if (BufferLength > ansi_length) {
+ Buffer[ansi_length] = 0;
+ } else {
+ if (ForceNull) {
+ Buffer[BufferLength - 1] = 0;
+ }
+ }
+
+ return Buffer;
+}
+
+
+ULIB_EXPORT
+BOOLEAN
+WSTRING::Strcat(
+ IN PCWSTRING String
+ )
+/*++
+
+Routine Description:
+
+ This routine concatenates the given string onto this one.
+
+Arguments:
+
+ String - Supplies the string to concatenate to this one.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ CHNUM old_length;
+
+ old_length = _l;
+ if (!Resize(_l + String->_l)) {
+ return FALSE;
+ }
+
+ memcpy(_s + old_length, String->_s, (UINT) String->_l*sizeof(WCHAR));
+
+ return TRUE;
+}
+
+
+NONVIRTUAL
+PWSTRING
+WSTRING::Strupr(
+ IN CHNUM StartPosition,
+ IN CHNUM Length
+ )
+/*++
+
+Routine Description:
+
+ This routine upcases a portion of this string.
+
+Arguments:
+
+ StartPosition - Supplies the start position of the substring to upcase.
+ Length - Supplies the length of the substring to upscase.
+
+Return Value:
+
+ A pointer to this string.
+
+--*/
+{
+ WCHAR c;
+
+ DebugAssert(StartPosition <= _l);
+
+ Length = min(Length, _l - StartPosition);
+
+ c = _s[StartPosition + Length];
+ _s[StartPosition + Length] = 0;
+
+ _wcsupr(_s + StartPosition);
+
+ _s[StartPosition + Length] = c;
+
+ return this;
+}
+
+
+NONVIRTUAL
+ULIB_EXPORT
+PWSTRING
+WSTRING::Strlwr(
+ IN CHNUM StartPosition,
+ IN CHNUM Length
+ )
+/*++
+
+Routine Description:
+
+ This routine lowercases a portion of this string.
+
+Arguments:
+
+ StartPosition - Supplies the start position of the substring to lowercase.
+ Length - Supplies the length of the substring to lowercase.
+
+Return Value:
+
+ A pointer to this string.
+
+--*/
+{
+ WCHAR c;
+
+ DebugAssert(StartPosition <= _l);
+
+ Length = min(Length, _l - StartPosition);
+
+ c = _s[StartPosition + Length];
+ _s[StartPosition + Length] = 0;
+
+ _wcslwr(_s + StartPosition);
+
+ _s[StartPosition + Length] = c;
+
+ return this;
+}
+
+
+NONVIRTUAL
+LONG
+WSTRING::Strcmp(
+ IN PCWSTRING String,
+ IN CHNUM LeftPosition,
+ IN CHNUM LeftLength,
+ IN CHNUM RightPosition,
+ IN CHNUM RightLength
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine compares two substrings.
+
+Arguments:
+
+ String - Supplies the string to compare this one to.
+ LeftPosition - Supplies the postion for the left substring.
+ LeftLength - Supplies the length of the left substring.
+ LeftPosition - Supplies the postion for the left substring.
+ LeftLength - Supplies the length of the left substring.
+
+Return Value:
+
+ <0 - Left substring is less than right substring.
+ 0 - Left and Right substrings are equal
+ >0 - Left substring is greater than right substring.
+
+--*/
+{
+ WCHAR c, d;
+ LONG r;
+
+ DebugAssert(LeftPosition <= _l);
+ DebugAssert(RightPosition <= String->_l);
+
+ LeftLength = min(LeftLength, _l - LeftPosition);
+ RightLength = min(RightLength, String->_l - RightPosition);
+
+ c = _s[LeftPosition + LeftLength];
+ d = String->_s[RightPosition + RightLength];
+ _s[LeftPosition + LeftLength] = 0;
+ String->_s[RightPosition + RightLength] = 0;
+
+ r = wcscoll(_s + LeftPosition, String->_s + RightPosition);
+
+ _s[LeftPosition + LeftLength] = c;
+ String->_s[RightPosition + RightLength] = d;
+
+ return r;
+}
+
+
+NONVIRTUAL
+ULIB_EXPORT
+LONG
+WSTRING::Stricmp(
+ IN PCWSTRING String,
+ IN CHNUM LeftPosition,
+ IN CHNUM LeftLength,
+ IN CHNUM RightPosition,
+ IN CHNUM RightLength
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine compares two substrings insensitive of case.
+
+Arguments:
+
+ String - Supplies the string to compare this one to.
+ LeftPosition - Supplies the postion for the left substring.
+ LeftLength - Supplies the length of the left substring.
+ LeftPosition - Supplies the postion for the left substring.
+ LeftLength - Supplies the length of the left substring.
+
+Return Value:
+
+ <0 - Left substring is less than right substring.
+ 0 - Left and Right substrings are equal
+ >0 - Left substring is greater than right substring.
+
+--*/
+{
+ WCHAR c, d;
+ LONG r;
+
+ DebugAssert(LeftPosition <= _l);
+ DebugAssert(RightPosition <= String->_l);
+
+ LeftLength = min(LeftLength, _l - LeftPosition);
+ RightLength = min(RightLength, String->_l - RightPosition);
+
+ c = _s[LeftPosition + LeftLength];
+ d = String->_s[RightPosition + RightLength];
+ _s[LeftPosition + LeftLength] = 0;
+ String->_s[RightPosition + RightLength] = 0;
+
+#if !defined _AUTOCHECK_
+
+ // This works around a bug in the libc version of wcsicoll, where
+ // it doesn't specify STRINGSORT to CompareString(). To reproduce the
+ // bug, try sorting 1 and -1. (-1 should sort before 1.) -mjb.
+ //
+
+ r = CompareString(GetUserDefaultLCID(),
+ NORM_IGNORECASE | SORT_STRINGSORT,
+ _s + LeftPosition,
+ -1,
+ String->_s + RightPosition,
+ -1
+ );
+
+
+ if (r >= 1) {
+
+ //
+ // return codes 1, 2, and 3 map to -1, 0, and 1.
+ //
+
+ _s[LeftPosition + LeftLength] = c;
+ String->_s[RightPosition + RightLength] = d;
+ return r - 2;
+ }
+
+ // If 'r' is 0, this indicates failure and we'll fall through and
+ // call wcsicoll.
+ //
+
+#endif // _AUTOCHECK_
+
+ r = _wcsicoll(_s + LeftPosition, String->_s + RightPosition);
+
+ _s[LeftPosition + LeftLength] = c;
+ String->_s[RightPosition + RightLength] = d;
+
+ return r;
+}
+
+
+PWSTR
+WSTRING::SkipWhite(
+ IN PWSTR p
+ )
+{
+#ifdef DBCS
+
+ while (*p) {
+
+ if (iswspace(*p))
+ p++;
+ else if ( *p == 0x3000 )
+ {
+ *p++ = TEXT(' ');
+ }
+ else
+ break;
+ }
+
+#else
+ while (iswspace(*p)) {
+ p++;
+ }
+#endif
+
+ return p;
+
+}
+
+
+/**************************************************************************/
+/* Compare two strings, ignoring white space, case is significant, return */
+/* 0 if identical, <>0 otherwise. Leading and trailing white space is */
+/* ignored, internal white space is treated as single characters. */
+/**************************************************************************/
+ULIB_EXPORT
+INT
+WSTRING::Strcmps (
+ IN PWSTR p1,
+ IN PWSTR p2
+ )
+{
+ WCHAR *q;
+
+ p1 = WSTRING::SkipWhite(p1); /* skip any leading white space */
+ p2 = WSTRING::SkipWhite(p2);
+
+ while (TRUE)
+ {
+ if (*p1 == *p2)
+ {
+ if (*p1++ == 0) /* quit if at the end */
+ return (0);
+ else
+ p2++;
+
+#ifdef DBCS
+ if (CheckSpace(p1))
+#else
+ if (iswspace(*p1)) /* compress multiple spaces */
+#endif
+ {
+ q = WSTRING::SkipWhite(p1);
+ p1 = (*q == 0) ? q : q - 1;
+ }
+
+#ifdef DBCS
+ if (CheckSpace(p2))
+#else
+ if (iswspace(*p2))
+#endif
+ {
+ q = WSTRING::SkipWhite(p2);
+ p2 = (*q == 0) ? q : q - 1;
+ }
+ }
+ else
+ return *p1-*p2;
+ }
+}
+
+
+
+
+
+/**************************************************************************/
+/* Compare two strings, ignoring white space, case is not significant, */
+/* return 0 if identical, <>0 otherwise. Leading and trailing white */
+/* space is ignored, internal white space is treated as single characters.*/
+/**************************************************************************/
+ULIB_EXPORT
+INT
+WSTRING::Strcmpis (
+ IN PWSTR p1,
+ IN PWSTR p2
+ )
+{
+ WCHAR *q;
+#ifdef DBCS
+ WCHAR c1,c2;
+#endif
+
+ p1 = WSTRING::SkipWhite(p1); /* skip any leading white space */
+ p2 = WSTRING::SkipWhite(p2);
+
+ while (TRUE)
+ {
+ if (towupper(*p1) == towupper(*p2))
+ {
+ if (*p1++ == 0) /* quit if at the end */
+ return (0);
+ else
+ p2++;
+#ifdef DBCS
+ if (CheckSpace(p1))
+#else
+ if (iswspace(*p1)) /* compress multiple spaces */
+#endif
+ {
+ q = SkipWhite(p1);
+ p1 = (*q == 0) ? q : q - 1;
+ }
+#ifdef DBCS
+ if (CheckSpace(p2))
+#else
+ if (iswspace(*p2))
+#endif
+ {
+ q = WSTRING::SkipWhite(p2);
+ p2 = (*q == 0) ? q : q - 1;
+ }
+ }
+ else
+ return *p1-*p2;
+ }
+}
+
+#ifdef DBCS
+
+/**************************************************************************/
+/* Routine: CheckSpace */
+/* Arguments: an arbitrary string */
+/* Function: Determine whether there is a space in the string. */
+/* Side effects: none */
+/**************************************************************************/
+INT
+WSTRING::CheckSpace(
+ IN PWSTR s
+ )
+{
+ if (iswspace(*s) || *s == 0x3000 )
+ return (TRUE);
+ else
+ return (FALSE);
+}
+
+#endif
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( FSTRING, WSTRING, ULIB_EXPORT );
+
+
+ULIB_EXPORT
+BOOLEAN
+FSTRING::Resize(
+ IN CHNUM NewStringLength
+ )
+/*++
+
+Routine Description:
+
+ This routine implements the WSTRING Resize routine by using
+ the buffer supplied at initialization time.
+
+Arguments:
+
+ NewStringLength - Supplies the new length of the string.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ return NewBuf(NewStringLength);
+}
+
+
+BOOLEAN
+FSTRING::NewBuf(
+ IN CHNUM NewStringLength
+ )
+/*++
+
+Routine Description:
+
+ This routine implements the WSTRING NewBuf routine by using
+ the buffer supplied at initialization time.
+
+Arguments:
+
+ NewStringLength - Supplies the new length of the string.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ if (NewStringLength >= _buffer_length) {
+ return FALSE;
+ }
+
+ PutString((PWSTR) GetWSTR(), NewStringLength);
+
+ return TRUE;
+}
+
+
+INLINE
+VOID
+DSTRING::Construct(
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the string to a valid initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _buf = NULL;
+ _length = 0;
+}
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( DSTRING, WSTRING, ULIB_EXPORT );
+
+
+ULIB_EXPORT
+DSTRING::~DSTRING(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for DSTRING.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ FREE(_buf);
+}
+
+
+BOOLEAN
+DSTRING::Resize(
+ IN CHNUM NewStringLength
+ )
+/*++
+
+Routine Description:
+
+ This routine resizes this string to the specified new size.
+
+Arguments:
+
+ NewStringLength - Supplies the new length of the string.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PWSTR new_buf;
+
+ if (NewStringLength >= _length) {
+
+ if (_buf) {
+ if (!(new_buf = (PWSTR)
+ REALLOC(_buf, (NewStringLength + 1)*sizeof(WCHAR)))) {
+
+ return FALSE;
+ }
+ } else {
+ if (!(new_buf = (PWSTR)
+ MALLOC((NewStringLength + 1)*sizeof(WCHAR)))) {
+
+ return FALSE;
+ }
+ }
+
+ _buf = new_buf;
+ _length = NewStringLength + 1;
+ }
+
+ PutString(_buf, NewStringLength);
+
+ return TRUE;
+}
+
+
+BOOLEAN
+DSTRING::NewBuf(
+ IN CHNUM NewStringLength
+ )
+/*++
+
+Routine Description:
+
+ This routine resizes this string to the specified new size.
+
+Arguments:
+
+ NewStringLength - Supplies the new length of the string.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PWSTR new_buf;
+
+ if (NewStringLength >= _length) {
+
+ if (!(new_buf = (PWSTR)
+ MALLOC((NewStringLength + 1)*sizeof(WCHAR)))) {
+
+ return FALSE;
+ }
+
+ _buf = new_buf;
+ _length = NewStringLength + 1;
+ }
+
+ PutString(_buf, NewStringLength);
+
+ return TRUE;
+}
+
+#if defined DBCS
+ULIB_EXPORT
+VOID
+WSTRING::ResetConversions(
+ )
+{
+ _UseAnsiConversions = _UseAnsiConversionsPrev;
+ _UseConsoleConversions = _UseConsoleConversionsPrev;
+}
+#endif // DBCS
+
+ULIB_EXPORT
+VOID
+WSTRING::SetAnsiConversions(
+ )
+/*++
+
+Routine Description:
+
+ This routine declares that all conversions from multi byte
+ to unicode will take place using the ANSI code page. Note
+ that this is a STATIC method. Therefore this switch affects
+ *all* WSTRINGs.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+#if defined DBCS
+ _UseAnsiConversionsPrev = _UseAnsiConversions;
+ _UseConsoleConversionsPrev = _UseConsoleConversions;
+#endif // DBCS
+
+ _UseAnsiConversions = TRUE;
+ _UseConsoleConversions = FALSE;
+}
+
+
+ULIB_EXPORT
+VOID
+WSTRING::SetOemConversions(
+ )
+/*++
+
+Routine Description:
+
+ This routine declares that all conversions from multi byte
+ to unicode will take place using the OEM code page. Note
+ that this is a STATIC method. Therefore this switch affects
+ *all* WSTRINGs.
+
+ This is the default if neither this nor the above function is
+ called.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+#if defined DBCS
+ _UseAnsiConversionsPrev = _UseAnsiConversions;
+ _UseConsoleConversionsPrev = _UseConsoleConversions;
+#endif // DBCS
+
+ _UseAnsiConversions = FALSE;
+ _UseConsoleConversions = FALSE;
+}
+
+ULIB_EXPORT
+VOID
+WSTRING::SetConsoleConversions(
+ )
+/*++
+
+Routine Description:
+
+ This routine declares that all conversions from multi byte
+ to unicode will take place using the current console code page.
+ Note that this is a STATIC method. Therefore this switch
+ affects *all* WSTRINGs.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+#if defined DBCS
+ _UseAnsiConversionsPrev = _UseAnsiConversions;
+ _UseConsoleConversionsPrev = _UseConsoleConversions;
+#endif // DBCS
+ _UseAnsiConversions = FALSE;
+ _UseConsoleConversions = TRUE;
+}
+
+#if defined DBCS
+CHNUM
+WSTRING::QueryByteCount(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the number of ANSI bytes the UNICODE string
+ consists of.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Number of ANSI bytes the UNICODE string is made from, or INVALID_CHNUM
+ on error.
+
+--*/
+
+{
+ ULONG ansi_length;
+ ULONG BufferLen = _l * sizeof(WCHAR) + 1;
+ PSTR Buffer;
+ BOOLEAN success;
+
+ if ( !_l ) {
+ return( (CHNUM)0 );
+ }
+
+ if (NULL == (Buffer = (PSTR)MALLOC( BufferLen ))) {
+ return( INVALID_CHNUM );
+ }
+
+ success = ConvertUnicodeToOemN( Buffer, BufferLen - 1, &ansi_length,
+ _s, BufferLen - 1 );
+
+ FREE( Buffer );
+
+ if (!success) {
+ return INVALID_CHNUM;
+ }
+ return ansi_length;
+}
+#endif // DBCS
diff --git a/private/utils/untfs/dirs b/private/utils/untfs/dirs
new file mode 100644
index 000000000..c4db5a979
--- /dev/null
+++ b/private/utils/untfs/dirs
@@ -0,0 +1,16 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+!ENDIF
+
+DIRS= src
diff --git a/private/utils/untfs/inc/attrcol.hxx b/private/utils/untfs/inc/attrcol.hxx
new file mode 100644
index 000000000..1d646b1eb
--- /dev/null
+++ b/private/utils/untfs/inc/attrcol.hxx
@@ -0,0 +1,248 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ attrcol.hxx
+
+Abstract:
+
+ This module contains the declarations for the
+ NTFS_ATTRIBUTE_COLUMNS class, which models
+ the attribute columns of an attribute definition table
+ file for an NTFS volume.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 19-Aug-91
+
+--*/
+
+#if !defined( NTFS_ATRIBUTE_COLUMNS_DEFN )
+
+#define NTFS_ATRIBUTE_COLUMNS_DEFN
+
+DECLARE_CLASS( NTFS_ATTRIBUTE_COLUMNS );
+DECLARE_CLASS( NTFS_ATTRIBUTE );
+
+#include "bigint.hxx"
+#include "wstring.hxx"
+
+class NTFS_ATTRIBUTE_COLUMNS : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( NTFS_ATTRIBUTE_COLUMNS );
+
+ VIRTUAL
+ ~NTFS_ATTRIBUTE_COLUMNS(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN ULONG NumberOfColumns,
+ IN PATTRIBUTE_DEFINITION_COLUMNS Columns DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Read(
+ IN OUT PNTFS_ATTRIBUTE AttributeDefinitionTableData
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryIndex(
+ IN ATTRIBUTE_TYPE_CODE AttributeCode,
+ OUT PULONG Index
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QueryFlags(
+ IN ULONG Index
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryAttributeName(
+ IN ULONG Index,
+ OUT PWSTRING AttributeName
+ ) CONST;
+
+ NONVIRTUAL
+ BIG_INT
+ QueryMinimumLength(
+ IN ULONG Index
+ ) CONST;
+
+ NONVIRTUAL
+ BIG_INT
+ QueryMaximumLength(
+ IN ULONG Index
+ ) CONST;
+
+ NONVIRTUAL
+ PCATTRIBUTE_DEFINITION_COLUMNS
+ GetColumns(
+ OUT PULONG NumColumns
+ ) CONST;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ PATTRIBUTE_DEFINITION_COLUMNS _columns;
+ ULONG _num_columns;
+
+};
+
+
+INLINE
+ULONG
+NTFS_ATTRIBUTE_COLUMNS::QueryFlags(
+ IN ULONG Index
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the flags for the attribute type
+ with the supplied index.
+
+Arguments:
+
+ Index - Supplies the index of the desired attribute type code.
+
+Return Value:
+
+ The flags for the attribute type currently in focus.
+
+--*/
+{
+ return _columns[Index].Flags;
+}
+
+
+INLINE
+BOOLEAN
+NTFS_ATTRIBUTE_COLUMNS::QueryAttributeName(
+ IN ULONG Index,
+ OUT PWSTRING AttributeName
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the attribute name for the attribute type
+ with the supplied index.
+
+Arguments:
+
+ Index - Supplies the index of the desired attribute type code.
+ AttributeName - Returns the attribute name.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ return AttributeName->Initialize(_columns[Index].AttributeName);
+}
+
+
+INLINE
+BIG_INT
+NTFS_ATTRIBUTE_COLUMNS::QueryMinimumLength(
+ IN ULONG Index
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the minimum length for the attribute type
+ with the supplied index.
+
+Arguments:
+
+ Index - Supplies the index of the desired attribute type code.
+
+Return Value:
+
+ The minimum length for the attribute type currently in focus.
+
+--*/
+{
+ PLARGE_INTEGER p;
+ p = (PLARGE_INTEGER)&_columns[Index].MinimumLength;
+ return *p;
+}
+
+
+INLINE
+BIG_INT
+NTFS_ATTRIBUTE_COLUMNS::QueryMaximumLength(
+ IN ULONG Index
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the maximum length for the attribute type
+ with the supplied index.
+
+Arguments:
+
+ Index - Supplies the index of the desired attribute type code.
+
+Return Value:
+
+ The maximum length for the attribute type currently in focus.
+
+--*/
+{
+ PLARGE_INTEGER p;
+ p = (PLARGE_INTEGER)&_columns[Index].MaximumLength;
+ return *p;
+}
+
+
+INLINE
+PCATTRIBUTE_DEFINITION_COLUMNS
+NTFS_ATTRIBUTE_COLUMNS::GetColumns(
+ OUT PULONG NumColumns
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the raw columns data.
+
+Arguments:
+
+ NumColumns - Returns the number of columns.
+
+Return Value:
+
+ The attribute columns data.
+
+--*/
+{
+ *NumColumns = _num_columns;
+ return _columns;
+}
+
+
+#endif // NTFS_ATRIBUTE_COLUMNS_DEFN
diff --git a/private/utils/untfs/inc/attrdef.hxx b/private/utils/untfs/inc/attrdef.hxx
new file mode 100644
index 000000000..ef75d6ab3
--- /dev/null
+++ b/private/utils/untfs/inc/attrdef.hxx
@@ -0,0 +1,97 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ attrdef.hxx
+
+Abstract:
+
+ This module contains the declarations for the
+ NTFS_ATTRIBUTE_DEFINITION_TABLE class, which models
+ the attribute definition table file for an NTFS volume.
+
+Author:
+
+ Bill McJohn (billmc) 17-June-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+#if !defined( NTFS_ATTRIBUTE_DEFINITION_TABLE_DEFN )
+
+#define NTFS_ATTRIBUTE_DEFINITION_TABLE_DEFN
+
+#include "frs.hxx"
+
+DECLARE_CLASS( NTFS_ATTRIBUTE_DEFINITION_TABLE );
+DECLARE_CLASS( NTFS_ATTRIBUTE_COLUMNS );
+
+
+
+CONST NumberOfNtfsAttributeDefinitions = $EA_DATA + 1;
+
+extern ATTRIBUTE_DEFINITION_COLUMNS NtfsAttributeDefinitions[
+ NumberOfNtfsAttributeDefinitions];
+
+
+class NTFS_ATTRIBUTE_DEFINITION_TABLE : public NTFS_FILE_RECORD_SEGMENT {
+
+ public:
+
+ UNTFS_EXPORT
+ DECLARE_CONSTRUCTOR( NTFS_ATTRIBUTE_DEFINITION_TABLE );
+
+ VIRTUAL
+ UNTFS_EXPORT
+ ~NTFS_ATTRIBUTE_DEFINITION_TABLE(
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Initialize(
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Create(
+ IN PCSTANDARD_INFORMATION StandardInformation,
+ IN OUT PNTFS_BITMAP Bitmap
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ VerifyAndFix(
+ IN OUT PNTFS_ATTRIBUTE_COLUMNS AttributeDefTable,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNUMBER_SET UnreadableClusters,
+ IN OUT PNTFS_INDEX_TREE RootIndex,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ );
+
+ STATIC
+ ULONG
+ QueryDefaultSize(
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+};
+
+#endif
diff --git a/private/utils/untfs/inc/attrib.hxx b/private/utils/untfs/inc/attrib.hxx
new file mode 100644
index 000000000..eb71b7a86
--- /dev/null
+++ b/private/utils/untfs/inc/attrib.hxx
@@ -0,0 +1,1004 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ attrib.hxx
+
+Abstract:
+
+ This module contains the declarations for NTFS_ATTRIBUTE,
+ which models an NTFS attribute instance.
+
+ An attribute instance models the user's view of an attribute,
+ as a [type, name, value] triple. (The name is optional.) It
+ does not correspond to any specific disk structure.
+
+ An attribute instance may exist in:
+
+ 1) a single resident attribute record,
+
+ 2) a single non-resident attribute record, or
+
+ 3) multiple, non-overlapping non-resident attribute records.
+
+ Case (3) is rare, so we don't need to optimize for it, but we
+ do need to handle it.
+
+
+ The client may initialize an Attribute object by supplying the
+ value directly [resident]; by supplying a description of the
+ value's location on disk [non-resident]; or by supplying an
+ attribute record or list of attribute records for the attribute.
+
+
+ On disk, an attribute may be resident (with the data contained
+ in the attribute record) or it may be nonresident (with the
+ data residing on disk, outside the File Record Segment). This
+ is reflected in the attribute object by having the value stored
+ directly (in space allocated by the attribute object and copied
+ at initialization) or stored on disk (with the attribute object
+ keeping an Extent List which describes this disk storage). I
+ chose not to reflect this difference with different classes for
+ three reasons: first, an attribute may wish to transform itself
+ from one form to another; second, this would introduce many
+ virtual methods; and third, I want to have special attribute
+ classes derive from the attribute class, and dividing attributes
+ into resident and nonresident would force me to use multiple
+ inheritance.
+
+ Generally, the difference between resident and nonresident
+ attributes is not visible to clients of this class. The
+ most important exception is GetResidentValue; this method
+ is provided for performance reasons--Read will supply the
+ same effect, but requires copying the data.
+
+Author:
+
+ Bill McJohn (billmc) 19-June-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if !defined( _NTFS_ATTRIBUTE_DEFN_ )
+
+#define _NTFS_ATTRIBUTE_DEFN_
+
+#include "extents.hxx"
+#include "wstring.hxx"
+#include "drive.hxx"
+
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( NTFS_FILE_RECORD_SEGMENT );
+DECLARE_CLASS( NTFS_EXTENT_LIST );
+DECLARE_CLASS( NTFS_ATTRIBUTE_RECORD );
+DECLARE_CLASS( NTFS_ATTRIBUTE_RECORD_LIST );
+DECLARE_CLASS( NTFS_BITMAP );
+DECLARE_CLASS( NTFS_ATTRIBUTE );
+DECLARE_CLASS( NTFS_BAD_CLUSTER_FILE );
+DECLARE_CLASS( NUMBER_SET );
+DECLARE_CLASS( NTFS_ATTRIBUTE );
+
+class NTFS_ATTRIBUTE : public OBJECT {
+
+ public:
+
+ UNTFS_EXPORT
+ DECLARE_CONSTRUCTOR( NTFS_ATTRIBUTE );
+
+ VIRTUAL
+ UNTFS_EXPORT
+ ~NTFS_ATTRIBUTE (
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Initialize (
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN ULONG ClusterFactor,
+ IN PCVOID Value,
+ IN ULONG ValueLength,
+ IN ATTRIBUTE_TYPE_CODE TypeCode,
+ IN PCWSTRING Name DEFAULT NULL,
+ IN USHORT Flags DEFAULT 0
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Initialize (
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN ULONG ClusterFactor,
+ IN PCNTFS_EXTENT_LIST Extents,
+ IN BIG_INT ValueLength,
+ IN BIG_INT ValidLength,
+ IN ATTRIBUTE_TYPE_CODE TypeCode,
+ IN PCWSTRING Name DEFAULT NULL,
+ IN USHORT Flags DEFAULT 0
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN ULONG ClusterFactor,
+ IN PCNTFS_ATTRIBUTE_RECORD AttributeRecord
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AddAttributeRecord (
+ IN PCNTFS_ATTRIBUTE_RECORD AttributeRecord
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ VerifyAndFix(
+ IN BIG_INT VolumeSectors
+ );
+
+ NONVIRTUAL
+ ATTRIBUTE_TYPE_CODE
+ QueryTypeCode (
+ ) CONST;
+
+ NONVIRTUAL
+ PCWSTRING
+ GetName (
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ QueryValueLength (
+ OUT PBIG_INT ValueLength,
+ OUT PBIG_INT AllocatedLength DEFAULT NULL,
+ OUT PBIG_INT ValidLength DEFAULT NULL
+ ) CONST;
+
+ NONVIRTUAL
+ BIG_INT
+ QueryValueLength(
+ ) CONST;
+
+ NONVIRTUAL
+ BIG_INT
+ QueryValidDataLength(
+ ) CONST;
+
+ NONVIRTUAL
+ BIG_INT
+ QueryAllocatedLength(
+ ) CONST;
+
+ NONVIRTUAL
+ BIG_INT
+ QueryClustersAllocated(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsResident (
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsIndexed (
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetIsIndexed(
+ IN BOOLEAN State DEFAULT TRUE
+ );
+
+ NONVIRTUAL
+ PCVOID
+ GetResidentValue (
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryLcnFromVcn (
+ IN VCN Vcn,
+ OUT PLCN Lcn,
+ OUT PBIG_INT RunLength DEFAULT NULL
+ ) CONST;
+
+ VIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ InsertIntoFile (
+ IN OUT PNTFS_FILE_RECORD_SEGMENT BaseFileRecordSegment,
+ IN OUT PNTFS_BITMAP Bitmap OPTIONAL
+ );
+
+ VIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ MakeNonresident (
+ IN OUT PNTFS_BITMAP Bitmap
+ );
+
+ VIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Resize (
+ IN BIG_INT NewSize,
+ IN OUT PNTFS_BITMAP Bitmap OPTIONAL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AddExtent (
+ IN VCN Vcn,
+ IN LCN Lcn,
+ IN BIG_INT RunLength
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Read (
+ OUT PVOID Data,
+ IN BIG_INT ByteOffset,
+ IN ULONG BytesToRead,
+ OUT PULONG BytesRead
+ );
+
+ NONVIRTUAL
+ VOID
+ PrimeCache (
+ IN BIG_INT ByteOffset,
+ IN ULONG BytesToRead
+ );
+
+ VIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Write (
+ IN PCVOID Data,
+ IN BIG_INT ByteOffset,
+ IN ULONG BytesToWrite,
+ OUT PULONG BytesWritten,
+ IN OUT PNTFS_BITMAP Bitmap OPTIONAL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Fill (
+ IN BIG_INT Offset,
+ IN CHAR FillCharacter
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Fill (
+ IN BIG_INT Offset,
+ IN CHAR FillCharacter,
+ IN ULONG NumberOfBytes
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsStorageModified (
+ ) CONST;
+
+ NONVIRTUAL
+ PLOG_IO_DP_DRIVE
+ GetDrive(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ RecoverAttribute(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNUMBER_SET BadClusters,
+ OUT PBIG_INT BytesRecovered DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ USHORT
+ QueryFlags(
+ ) CONST;
+
+ NONVIRTUAL
+ UCHAR
+ QueryResidentFlags(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ MarkAsAllocated(
+ IN OUT PNTFS_BITMAP VolumeBitmap
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QueryCompressionUnit(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsCompressed(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ Hotfix(
+ IN VCN Vcn,
+ IN BIG_INT RunLength,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNUMBER_SET BadClusters,
+ IN BOOLEAN Contiguous DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ReplaceVcns(
+ IN VCN StartingVcn,
+ IN LCN NewLcn,
+ IN BIG_INT NumberOfClusters
+ );
+
+ NONVIRTUAL
+ PCNTFS_EXTENT_LIST
+ GetExtentList(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsAllocationZeroed(
+ OUT PBOOLEAN Error DEFAULT NULL
+ );
+
+ FRIEND
+ BOOLEAN
+ operator==(
+ IN RCNTFS_ATTRIBUTE Left,
+ IN RCNTFS_ATTRIBUTE Right
+ );
+
+ protected:
+
+ NONVIRTUAL
+ VOID
+ SetStorageModified (
+ );
+
+ NONVIRTUAL
+ VOID
+ ResetStorageModified (
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryClusterFactor(
+ ) CONST;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ InsertMftDataIntoFile (
+ IN OUT PNTFS_FILE_RECORD_SEGMENT BaseFileRecordSegment,
+ IN OUT PNTFS_BITMAP Bitmap OPTIONAL,
+ IN BOOLEAN BeConservative
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ReadCompressed (
+ OUT PVOID Data,
+ IN BIG_INT ByteOffset,
+ IN ULONG BytesToRead,
+ OUT PULONG BytesRead
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ WriteCompressed (
+ IN PCVOID Data,
+ IN BIG_INT ByteOffset,
+ IN ULONG BytesToWrite,
+ OUT PULONG BytesWritten,
+ IN OUT PNTFS_BITMAP Bitmap OPTIONAL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ RecoverCompressedAttribute(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNUMBER_SET BadClusters,
+ OUT PBIG_INT BytesRecovered DEFAULT NULL
+ );
+
+
+ PLOG_IO_DP_DRIVE _Drive;
+ ULONG _ClusterFactor;
+
+ ATTRIBUTE_TYPE_CODE _Type;
+ DSTRING _Name;
+ USHORT _Flags;
+ UCHAR _FormCode;
+ UCHAR _CompressionUnit;
+
+ BIG_INT _ValueLength;
+ BIG_INT _ValidDataLength;
+
+ PVOID _ResidentData;
+ PNTFS_EXTENT_LIST _ExtentList;
+
+ UCHAR _ResidentFlags;
+
+ BOOLEAN _StorageModified;
+
+};
+
+
+
+INLINE
+BOOLEAN
+NTFS_ATTRIBUTE::IsResident(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns whether the attribute value is resident.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the value is resident; FALSE if it is non-resident.
+
+--*/
+{
+ return( _ResidentData != NULL );
+}
+
+
+INLINE
+BIG_INT
+NTFS_ATTRIBUTE::QueryValueLength(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the length of the attribute value in bytes.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The length of the attribute value in bytes.
+
+--*/
+{
+ return _ValueLength;
+}
+
+
+INLINE
+BIG_INT
+NTFS_ATTRIBUTE::QueryValidDataLength(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the valid data length.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The valid data length.
+
+--*/
+{
+ return _ValidDataLength;
+}
+
+
+
+INLINE
+BIG_INT
+NTFS_ATTRIBUTE::QueryAllocatedLength(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine return the number of bytes allocated for this attribute
+ on disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The amount of disk space allocated for this attribute.
+
+--*/
+{
+ BIG_INT Result;
+
+ if( IsResident() ) {
+
+ Result = QuadAlign( _ValueLength.GetLowPart() );
+
+ } else {
+
+ Result = (_ExtentList->QueryNextVcn()*_ClusterFactor*
+ _Drive->QuerySectorSize());
+ }
+
+ return Result;
+}
+
+
+
+INLINE
+ATTRIBUTE_TYPE_CODE
+NTFS_ATTRIBUTE::QueryTypeCode(
+ ) CONST
+/*++
+
+Routine Description:
+
+ Returns the attribute's type code.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The attribute's type code.
+
+--*/
+{
+ return _Type;
+}
+
+
+INLINE
+PCWSTRING
+NTFS_ATTRIBUTE::GetName(
+ ) CONST
+/*++
+
+Routine Description:
+
+ Returns the attribute's name. (Note that this returns a pointer
+ to the attribute's private copy of its name.)
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the attribute's name, if it has one; NULL if it
+ has none.
+
+--*/
+{
+ return &_Name;
+}
+
+
+
+INLINE
+VOID
+NTFS_ATTRIBUTE::QueryValueLength(
+ OUT PBIG_INT ValueLength,
+ OUT PBIG_INT AllocatedLength,
+ OUT PBIG_INT ValidLength
+ ) CONST
+/*++
+
+Routine Description:
+
+ Returns the attribute's value lengths (actual, allocated
+ and valid length).
+
+Arguments:
+
+ ValueLength -- receives the attribute value's length
+ AllocatedLength -- receives the attribute value's allocated length
+ (ignored if NULL)
+ ValidLength -- receives the attribute value's valid length
+ (ignored if NULL );
+
+Return Value:
+
+ None.
+
+--*/
+{
+ *ValueLength = _ValueLength;
+
+ if( AllocatedLength != NULL ) {
+
+ *AllocatedLength = QueryAllocatedLength();
+ }
+
+ if( ValidLength != NULL ) {
+
+ *ValidLength = _ValidDataLength;
+ }
+}
+
+
+INLINE
+BOOLEAN
+NTFS_ATTRIBUTE::IsIndexed(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns whether the attribute is indexed.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the attribute is indexed; FALSE if not.
+
+--*/
+{
+ return( (_ResidentData == NULL) ?
+ FALSE :
+ _ResidentFlags & RESIDENT_FORM_INDEXED );
+}
+
+
+INLINE
+VOID
+NTFS_ATTRIBUTE::SetIsIndexed(
+ IN BOOLEAN State
+ )
+/*++
+
+Routine Description:
+
+ This method marks the attribute as indexed. It has no effect if
+ the attribute is nonresident.
+
+Arguments:
+
+ State -- supplies a value indicating whether the attribute
+ is indexed (TRUE) or not indexed (FALSE).
+Return Value:
+
+ None.
+
+--*/
+{
+ if( _ResidentData != NULL ) {
+
+ if( State ) {
+
+ _ResidentFlags |= RESIDENT_FORM_INDEXED;
+
+ } else {
+
+ _ResidentFlags &= ~RESIDENT_FORM_INDEXED;
+
+ }
+ }
+}
+
+
+INLINE
+PCVOID
+NTFS_ATTRIBUTE::GetResidentValue(
+ ) CONST
+/*++
+
+Routine Description:
+
+ Returns a pointer to the attribute's value.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ If the attribute value is resident, returns a pointer to the
+ value. If it is nonresident, returns NULL.
+
+Notes:
+
+ This method is provided for clients who know that the value is
+ resident and who want to inspect it without copying it; if the
+ client doesn't know whether the value is resident, Read is
+ a better way to get it.
+
+--*/
+{
+ return _ResidentData;
+}
+
+
+INLINE
+BOOLEAN
+NTFS_ATTRIBUTE::QueryLcnFromVcn (
+ IN VCN Vcn,
+ OUT PLCN Lcn,
+ OUT PBIG_INT RunLength
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method converts a VCN within the attribute into an LCN.
+ (Note that it only applies to nonresident attributes.)
+
+Arguments:
+
+ Vcn -- Supplies the VCN to be converted.
+ Lcn -- Receives the corresponding LCN.
+ RunLength -- Receives the remaining length in the current run
+ starting at this LCN.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ if( _ExtentList == NULL ) {
+
+ return FALSE;
+
+ } else {
+
+ return _ExtentList->QueryLcnFromVcn( Vcn, Lcn, RunLength );
+ }
+}
+
+
+INLINE
+BOOLEAN
+NTFS_ATTRIBUTE::IsStorageModified(
+ ) CONST
+/*++
+
+Routine Description:
+
+ Query whether the attribute's storage (i.e. anything that
+ would go into an attribute record) has changed
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns TRUE if the attribute's storage has been modified since
+ the last time we got it from or put it into a File Record Segment.
+
+--*/
+{
+ return _StorageModified;
+}
+
+
+INLINE
+VOID
+NTFS_ATTRIBUTE::SetStorageModified (
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the 'IsStorageModified' flag.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _StorageModified = TRUE;
+}
+
+
+INLINE
+VOID
+NTFS_ATTRIBUTE::ResetStorageModified (
+ )
+/*++
+
+Routine Description:
+
+ This routine resets the 'IsStorageModified' flag.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _StorageModified = FALSE;
+}
+
+
+INLINE
+PLOG_IO_DP_DRIVE
+NTFS_ATTRIBUTE::GetDrive(
+ )
+/*++
+
+Routine Description:
+
+ This method returns the drive on which the Attribute resides.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The drive on which the Attribute resides.
+
+--*/
+{
+ return _Drive;
+}
+
+
+INLINE
+USHORT
+NTFS_ATTRIBUTE::QueryFlags(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns this attribute's flags.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ This attribute's flags.
+
+--*/
+{
+ return _Flags;
+}
+
+
+INLINE
+UCHAR
+NTFS_ATTRIBUTE::QueryResidentFlags(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns this attribute's resident flags.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ This attribute's resident flags.
+
+--*/
+{
+ return _ResidentFlags;
+}
+
+INLINE
+ULONG
+NTFS_ATTRIBUTE::QueryCompressionUnit(
+ ) CONST
+{
+ return _CompressionUnit;
+}
+
+
+INLINE
+BOOLEAN
+NTFS_ATTRIBUTE::IsCompressed(
+ ) CONST
+{
+ return ((_Flags & ATTRIBUTE_FLAG_COMPRESSION_MASK) != 0);
+}
+
+
+INLINE
+ULONG
+NTFS_ATTRIBUTE::QueryClusterFactor(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the cluster factor.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The cluster factor.
+
+--*/
+{
+ return _ClusterFactor;
+}
+
+
+INLINE
+PCNTFS_EXTENT_LIST
+NTFS_ATTRIBUTE::GetExtentList(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to this object's extent list.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the extent list.
+
+--*/
+{
+ return _ExtentList;
+}
+
+
+
+
+#endif
diff --git a/private/utils/untfs/inc/attrlist.hxx b/private/utils/untfs/inc/attrlist.hxx
new file mode 100644
index 000000000..f1f773d4e
--- /dev/null
+++ b/private/utils/untfs/inc/attrlist.hxx
@@ -0,0 +1,296 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ attrlist.hxx
+
+Abstract:
+
+ This module contains the declarations for NTFS_ATTRIBUTE_LIST,
+ which models an ATTRIBUTE_LIST Attribute in an NTFS File Record
+ Segment.
+
+ If a file has any external attributes (i.e. if it has more than
+ one File Record Segment), then it will have an ATTRIBUTE_LIST
+ attribute. This attribute's value consists of a series of
+ Attribute List Entries, which describe the attribute records
+ in the file's File Record Segments. There is an entry for each
+ attribute record attached to the file, including the attribute
+ records in the base File Record Segment, and in particular
+ including the attribute records which describe the ATTRIBUTE_LIST
+ attribute itself.
+
+ An entry in the Attribute List gives the type code and name (if any)
+ of the attribute, along with the LowestVcn of the attribute record
+ (zero if the attribute record is Resident) and a segment reference
+ (which combines an MFT VCN with a sequence number) showing where
+ the attribute record may be found.
+
+ The entries in the Attribute List are sorted first by attribute
+ type code and then by name. Note that two attributes can have the
+ same type code and name only if they can be distinguished by
+ value.
+
+Author:
+
+ Bill McJohn (billmc) 12-Aug-1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#if !defined( NTFS_ATTRIBUTE_LIST_DEFN )
+
+#define NTFS_ATTRIBUTE_LIST_DEFN
+
+#include "attrib.hxx"
+#include "hmem.hxx"
+#include "volume.hxx"
+
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( WSTRING );
+DECLARE_CLASS( NTFS_ATTRIBUTE_RECORD );
+DECLARE_CLASS( NTFS_ATTRIBUTE_RECORD_LIST );
+DECLARE_CLASS( NTFS_BITMAP );
+DECLARE_CLASS( NTFS_UPCASE_TABLE );
+DECLARE_CLASS( NTFS_ATTRIBUTE_LIST );
+
+// This macro produces a pointer to the wide-character name of an attribute
+// list entry from a pointer to an attribute list entry.
+
+#define NameFromEntry( x ) ((PWSTR)((PBYTE)(x)+(x)->AttributeNameOffset))
+
+// This macro produces a pointer to the attribute list entry
+// following x
+
+#define NextEntry( x ) \
+ ((PATTRIBUTE_LIST_ENTRY)((PBYTE)(x) + (x)->RecordLength))
+
+class NTFS_ATTRIBUTE_LIST : public NTFS_ATTRIBUTE {
+
+ public:
+
+ UNTFS_EXPORT
+ DECLARE_CONSTRUCTOR( NTFS_ATTRIBUTE_LIST );
+
+ VIRTUAL
+ UNTFS_EXPORT
+ ~NTFS_ATTRIBUTE_LIST(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN ULONG ClusterFactor,
+ IN PNTFS_UPCASE_TABLE UpcaseTable
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN ULONG ClusterFactor,
+ IN PCNTFS_ATTRIBUTE_RECORD AttributeRecord,
+ IN PNTFS_UPCASE_TABLE UpcaseTable
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ VerifyAndFix(
+ IN FIX_LEVEL FixLevel,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PMESSAGE Message,
+ IN VCN FileNumber,
+ OUT PBOOLEAN Tube,
+ IN OUT PBOOLEAN DiskErrorsFound DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AddEntry(
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN VCN LowestVcn,
+ IN PCMFT_SEGMENT_REFERENCE SegmentReference,
+ IN USHORT InstanceTag,
+ IN PCWSTRING Name DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DeleteEntry(
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN VCN LowestVcn,
+ IN PCWSTRING Name DEFAULT NULL,
+ IN PCMFT_SEGMENT_REFERENCE SegmentReference DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DeleteEntry(
+ IN ULONG EntryIndex
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DeleteEntries(
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCWSTRING Name DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsInList(
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCWSTRING Name DEFAULT NULL
+ ) CONST;
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ QueryEntry(
+ IN ULONG EntryIndex,
+ OUT PATTRIBUTE_TYPE_CODE Type,
+ OUT PVCN LowestVcn,
+ OUT PMFT_SEGMENT_REFERENCE SegmentReference,
+ OUT PUSHORT InstanceTag,
+ OUT PWSTRING Name
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryEntry(
+ IN MFT_SEGMENT_REFERENCE SegmentReference,
+ IN USHORT InstanceTag,
+ OUT PATTRIBUTE_TYPE_CODE Type,
+ OUT PVCN LowestVcn,
+ OUT PWSTRING Name
+ ) CONST;
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ PCATTRIBUTE_LIST_ENTRY
+ GetNextAttributeListEntry(
+ IN PCATTRIBUTE_LIST_ENTRY CurrentEntry
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryExternalReference(
+ IN ATTRIBUTE_TYPE_CODE Type,
+ OUT PMFT_SEGMENT_REFERENCE SegmentReference,
+ OUT PULONG EntryIndex,
+ IN PCWSTRING Name DEFAULT NULL,
+ IN PVCN DesiredVcn DEFAULT NULL,
+ OUT PVCN StartingVcn DEFAULT NULL
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryNextAttribute(
+ IN OUT PATTRIBUTE_TYPE_CODE TypeCode,
+ IN OUT PWSTRING Name
+ ) CONST;
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ ReadList(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ WriteList(
+ PNTFS_BITMAP VolumeBitmap
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryAttributeRecord(
+ OUT PVOID AttributeRecordData,
+ IN ULONG MaximumLength,
+ OUT PNTFS_ATTRIBUTE_RECORD AttributeRecord
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ ModifyInstanceTag(
+ IN PCNTFS_ATTRIBUTE_RECORD AttributeRecord,
+ IN MFT_SEGMENT_REFERENCE SegmentReference,
+ IN USHORT NewInstanceTag
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ PATTRIBUTE_LIST_ENTRY
+ FindEntry(
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCWSTRING Name,
+ IN VCN LowestVcn,
+ OUT PULONG EntryOffset DEFAULT NULL,
+ OUT PULONG EntryIndex DEFAULT NULL
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ Sort(
+ OUT PBOOLEAN Changes
+ );
+
+ HMEM _Mem;
+ ULONG _LengthOfList;
+ PNTFS_UPCASE_TABLE _UpcaseTable;
+
+};
+
+
+
+INLINE
+BOOLEAN
+NTFS_ATTRIBUTE_LIST::WriteList(
+ IN OUT PNTFS_BITMAP VolumeBitmap
+ )
+/*++
+
+Routine Description:
+
+ This method writes the list to disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ ULONG BytesWritten;
+
+ return( Resize( _LengthOfList, VolumeBitmap ) &&
+ Write( _Mem.GetBuf(),
+ 0,
+ _LengthOfList,
+ &BytesWritten,
+ VolumeBitmap ) &&
+ BytesWritten == _LengthOfList );
+}
+
+#endif
diff --git a/private/utils/untfs/inc/attrrec.hxx b/private/utils/untfs/inc/attrrec.hxx
new file mode 100644
index 000000000..bbdcd2c18
--- /dev/null
+++ b/private/utils/untfs/inc/attrrec.hxx
@@ -0,0 +1,743 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ attrrec.hxx
+
+Abstract:
+
+ This module contains the declarations for NTFS_ATTRIBUTE_RECORD,
+ which models NTFS attribute records.
+
+ An Attribute Record may be a template laid over a chunk of
+ memory; in that case, it does not own the memory. It may
+ also be told, upon initialization, to allocate its own memory
+ and copy the supplied data. In that case, it is also responsible
+ for freeing that memory.
+
+ Attribute Records are passed between Attributes and File
+ Record Segments. A File Record Segment can initialize
+ an Attribute with a list of Attribute Records; when an
+ Attribute is Set into a File Record Segment, it packages
+ itself up into Attribute Records and inserts them into
+ the File Record Segment.
+
+ File Record Segments also use Attribute Records to scan
+ through their list of attribute records, and to shuffle
+ them around.
+
+Author:
+
+ Bill McJohn (billmc) 14-June-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if !defined( _NTFS_ATTRIBUTE_RECORD_DEFN_ )
+
+#define _NTFS_ATTRIBUTE_RECORD_DEFN_
+
+DECLARE_CLASS( WSTRING );
+DECLARE_CLASS( NTFS_EXTENT_LIST );
+DECLARE_CLASS( NTFS_ATTRIBUTE_RECORD );
+DECLARE_CLASS( NTFS_ATTRIBUTE_COLUMNS );
+DECLARE_CLASS( NTFS_UPCASE_TABLE );
+
+// This function is used to compare attribute records, in order
+// to determine their ordering in the base FRS. Its definition
+// appears in attrrec.cxx.
+//
+LONG
+CompareAttributeRecords(
+ IN PCNTFS_ATTRIBUTE_RECORD Left,
+ IN PCNTFS_ATTRIBUTE_RECORD Right,
+ IN PCNTFS_UPCASE_TABLE UpcaseTable
+ );
+
+class NTFS_ATTRIBUTE_RECORD : public OBJECT {
+
+ public:
+
+ UNTFS_EXPORT
+ DECLARE_CONSTRUCTOR( NTFS_ATTRIBUTE_RECORD );
+
+ VIRTUAL
+ UNTFS_EXPORT
+ ~NTFS_ATTRIBUTE_RECORD(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN OUT PVOID Data,
+ IN ULONG MaximumLength,
+ IN BOOLEAN MakeCopy DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Initialize(
+ IN OUT PVOID Data
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CreateResidentRecord(
+ IN PCVOID Value,
+ IN ULONG ValueLength,
+ IN ATTRIBUTE_TYPE_CODE TypeCode,
+ IN PCWSTRING Name DEFAULT NULL,
+ IN USHORT Flags DEFAULT 0,
+ IN UCHAR ResidentFlags DEFAULT 0
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CreateNonresidentRecord(
+ IN PCNTFS_EXTENT_LIST Extents,
+ IN BIG_INT AllocatedLength,
+ IN BIG_INT ActualLength,
+ IN BIG_INT ValidDataLength,
+ IN ATTRIBUTE_TYPE_CODE TypeCode,
+ IN PCWSTRING Name DEFAULT NULL,
+ IN USHORT Flags DEFAULT 0,
+ IN USHORT CompressionUnit DEFAULT 0
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Verify(
+ IN PCNTFS_ATTRIBUTE_COLUMNS AttributeDefTable OPTIONAL,
+ IN BOOLEAN BeLenient
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ UseClusters(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ OUT PBIG_INT ClusterCount
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ UseClusters(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ OUT PBIG_INT ClusterCount,
+ IN ULONG AllowCrossLinkStart,
+ IN ULONG AllowCrossLinkLength,
+ OUT PBOOLEAN DidCrossLinkOccur
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ UnUseClusters(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN ULONG LeaveInUseStart,
+ IN ULONG LeaveInUseLength
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QueryRecordLength(
+ ) CONST;
+
+ NONVIRTUAL
+ ATTRIBUTE_TYPE_CODE
+ QueryTypeCode(
+ ) CONST;
+
+ NONVIRTUAL
+ USHORT
+ QueryFlags(
+ ) CONST;
+
+ NONVIRTUAL
+ UCHAR
+ QueryResidentFlags(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QueryCompressionUnit(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsResident(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsIndexed(
+ ) CONST;
+
+ NONVIRTUAL
+ VCN
+ QueryLowestVcn(
+ ) CONST;
+
+ NONVIRTUAL
+ PWSTR
+ GetName(
+ ) CONST;
+
+ NONVIRTUAL
+ VCN
+ QueryNextVcn(
+ ) CONST;
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ QueryName(
+ OUT PWSTRING Name
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QueryNameLength(
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ QueryValueLength(
+ OUT PBIG_INT ValueLength,
+ OUT PBIG_INT AllocatedLength DEFAULT NULL,
+ OUT PBIG_INT ValidLength DEFAULT NULL,
+ OUT PBIG_INT TotalAllocated DEFAULT NULL
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetTotalAllocated(
+ IN BIG_INT TotalAllocated
+ );
+
+ NONVIRTUAL
+ USHORT
+ QueryInstanceTag(
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetInstanceTag(
+ USHORT NewTag
+ );
+
+ NONVIRTUAL
+ PCVOID
+ GetData(
+ ) CONST;
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ QueryExtentList(
+ OUT PNTFS_EXTENT_LIST ExtentList
+ ) CONST;
+
+ NONVIRTUAL
+ PCVOID
+ GetResidentValue(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QueryResidentValueLength(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsMatch(
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCWSTRING Name DEFAULT NULL,
+ IN PCVOID Value DEFAULT NULL,
+ IN ULONG ValueLength DEFAULT 0
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ DisableUnUse(
+ IN BOOLEAN NewState DEFAULT TRUE
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ PATTRIBUTE_RECORD_HEADER _Data;
+ ULONG _MaximumLength;
+ BOOLEAN _IsOwnBuffer;
+
+ //
+ // DisableUnUse will turn the UnUseClusters operation into a
+ // no-op.
+ //
+
+ BOOLEAN _DisableUnUse;
+
+};
+
+
+INLINE
+ULONG
+NTFS_ATTRIBUTE_RECORD::QueryRecordLength(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the length of the attribute record. (Note
+ that this is the length of the record itself, not the length
+ of the buffer allotted to it).
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The length of the attribute record.
+
+--*/
+{
+ return _Data->RecordLength;
+}
+
+
+INLINE
+ATTRIBUTE_TYPE_CODE
+NTFS_ATTRIBUTE_RECORD::QueryTypeCode(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the attribute type code.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The attribute type code for this attribute record.
+
+--*/
+{
+ return _Data->TypeCode;
+}
+
+
+INLINE
+USHORT
+NTFS_ATTRIBUTE_RECORD::QueryFlags(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the attribute's flags.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The flags from the attribute record.
+
+--*/
+{
+ DebugPtrAssert( _Data );
+
+ return( _Data->Flags );
+}
+
+
+
+INLINE
+ULONG
+NTFS_ATTRIBUTE_RECORD::QueryCompressionUnit(
+ ) CONST
+{
+ return( (_Data->FormCode == NONRESIDENT_FORM) ?
+ _Data->Form.Nonresident.CompressionUnit :
+ 0 );
+}
+
+
+INLINE
+UCHAR
+NTFS_ATTRIBUTE_RECORD::QueryResidentFlags(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the attribute's resident-form flags.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The resident-form flags from the attribute record. If
+ if the attribute is nonresident, this method returns zero.
+
+--*/
+{
+ DebugPtrAssert( _Data );
+
+ return( (_Data->FormCode == NONRESIDENT_FORM) ?
+ 0 :
+ _Data->Form.Resident.ResidentFlags );
+}
+
+
+
+INLINE
+BOOLEAN
+NTFS_ATTRIBUTE_RECORD::IsResident(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns whether the attribute is resident.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the attribute is resident.
+
+--*/
+{
+ return (_Data->FormCode == RESIDENT_FORM);
+}
+
+
+INLINE
+BOOLEAN
+NTFS_ATTRIBUTE_RECORD::IsIndexed(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns whether the attribute is indexed.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the attribute is indexed.
+
+--*/
+{
+ return IsResident() &&
+ (_Data->Form.Resident.ResidentFlags & RESIDENT_FORM_INDEXED);
+}
+
+
+INLINE
+VCN
+NTFS_ATTRIBUTE_RECORD::QueryLowestVcn(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the lowest VCN covered by this attribute
+ record. If this attribute record is resident, the the lowest
+ VCN is zero; if it is nonresident, the lowest VCN is given by
+ the
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The lowest VCN covered by this attribute record.
+
+--*/
+{
+ if( IsResident() ) {
+
+ return 0;
+
+ } else {
+
+ return _Data->Form.Nonresident.LowestVcn;
+ }
+}
+
+
+INLINE
+VCN
+NTFS_ATTRIBUTE_RECORD::QueryNextVcn(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the highest VCN covered by this attribute
+ record. If this attribute record is resident, then the highest
+ VCN is zero; if it is nonresident, the highest VCN is given by
+ the
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The highest VCN covered by this attribute record.
+
+--*/
+{
+ if( IsResident() ) {
+
+ return 1;
+
+ } else {
+
+ return _Data->Form.Nonresident.HighestVcn + 1;
+ }
+}
+
+
+INLINE
+ULONG
+NTFS_ATTRIBUTE_RECORD::QueryNameLength(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the length of the name, in characters.
+ Zero indicates that the attribute record has no name.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Length of the name, in characters.
+
+--*/
+{
+ return _Data->NameLength;
+}
+
+
+
+INLINE
+USHORT
+NTFS_ATTRIBUTE_RECORD::QueryInstanceTag(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method queries the attribute record's unique-within-this-file
+ attribute instance tag.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The attribute record's instance tag.
+
+--*/
+{
+ return _Data->Instance;
+}
+
+
+INLINE
+VOID
+NTFS_ATTRIBUTE_RECORD::SetInstanceTag(
+ USHORT NewTag
+ )
+/*++
+
+Routine Description:
+
+ This method sets the attribute record's unique-within-this-file
+ attribute instance tag.
+
+Arguments:
+
+ NewTag -- Supplies the new value for the instance tag.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _Data->Instance = NewTag;
+
+}
+
+
+INLINE
+PWSTR
+NTFS_ATTRIBUTE_RECORD::GetName(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns a pointer to the wide-character attribute
+ name.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the wide-character name in this attribute record;
+ NULL if there is no name.
+
+Notes:
+
+ This method is provided to permit optimization of the common
+ attribute look-op operation in File Record Segments.
+
+--*/
+{
+
+ if( QueryNameLength() == 0 ) {
+
+ return NULL;
+
+ } else {
+
+ return( (PWSTR)( (PBYTE)_Data + _Data->NameOffset ) );
+ }
+}
+
+
+
+INLINE
+PCVOID
+NTFS_ATTRIBUTE_RECORD::GetData(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns a pointer to the attribute record's data.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the attribute record's data.
+
+--*/
+{
+ return _Data;
+}
+
+
+INLINE
+PCVOID
+NTFS_ATTRIBUTE_RECORD::GetResidentValue(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns a pointer to the attribute record's
+ resident value. If the attribute record is non-resident,
+ it returns NULL.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The attribute record's resident value; NULL if the attribute
+ record is non-resident.
+
+--*/
+{
+ if( _Data->FormCode == NONRESIDENT_FORM ) {
+
+ return NULL;
+
+ } else {
+
+ return ((PBYTE)_Data + _Data->Form.Resident.ValueOffset);
+ }
+}
+
+
+INLINE
+ULONG
+NTFS_ATTRIBUTE_RECORD::QueryResidentValueLength(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the attribute record's resident value
+ length (zero if the attribute is nonresident).
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Who Cares.
+
+--*/
+{
+ return( (_Data->FormCode == NONRESIDENT_FORM) ?
+ 0 :
+ _Data->Form.Resident.ValueLength );
+}
+
+INLINE
+VOID
+NTFS_ATTRIBUTE_RECORD::DisableUnUse(
+ IN BOOLEAN NewState
+ )
+{
+ _DisableUnUse = NewState;
+}
+
+
+#endif
diff --git a/private/utils/untfs/inc/badfile.hxx b/private/utils/untfs/inc/badfile.hxx
new file mode 100644
index 000000000..a299f64bc
--- /dev/null
+++ b/private/utils/untfs/inc/badfile.hxx
@@ -0,0 +1,128 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ badfile.hxx
+
+Abstract:
+
+ This module contains the declarations for the NTFS_BAD_CLUSTER_FILE
+ class, which models the bad cluster file for an NTFS volume.
+
+ The DATA attribute of the bad cluster file is a non-resident
+ attribute to which bad clusters are allocated. It is stored
+ as a sparse file with LCN = VCN.
+
+Author:
+
+ Bill McJohn (billmc) 18-June-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+#if !defined( NTFS_BAD_CLUSTER_FILE_DEFN )
+
+#define NTFS_BAD_CLUSTER_FILE_DEFN
+
+#include "frs.hxx"
+
+DECLARE_CLASS( IO_DP_DRIVE );
+DECLARE_CLASS( NTFS_ATTRIBUTE);
+DECLARE_CLASS( NTFS_MASTER_FILE_TABLE );
+DECLARE_CLASS( NTFS_BITMAP );
+DECLARE_CLASS( NUMBER_SET );
+
+class NTFS_BAD_CLUSTER_FILE : public NTFS_FILE_RECORD_SEGMENT {
+
+ public:
+
+ UNTFS_EXPORT
+ DECLARE_CONSTRUCTOR( NTFS_BAD_CLUSTER_FILE );
+
+ UNTFS_EXPORT
+ VIRTUAL
+ ~NTFS_BAD_CLUSTER_FILE(
+ );
+
+ UNTFS_EXPORT
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Create(
+ IN PCSTANDARD_INFORMATION StandardInformation,
+ IN OUT PNTFS_BITMAP Bitmap,
+ IN PCNUMBER_SET BadClusters
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ VerifyAndFix(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNTFS_INDEX_TREE RootIndex,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Add(
+ IN LCN Lcn
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Add(
+ IN PCNUMBER_SET ClustersToAdd
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AddRun(
+ IN LCN Lcn,
+ IN BIG_INT RunLength
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsInList(
+ IN LCN Lcn
+ );
+
+ NONVIRTUAL
+ BIG_INT
+ QueryNumBad(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Flush(
+ IN OUT PNTFS_BITMAP Bitmap,
+ IN OUT PNTFS_INDEX_TREE ParentIndex DEFAULT NULL
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ PNTFS_ATTRIBUTE _DataAttribute;
+};
+
+
+#endif
diff --git a/private/utils/untfs/inc/bitfrs.hxx b/private/utils/untfs/inc/bitfrs.hxx
new file mode 100644
index 000000000..c20830414
--- /dev/null
+++ b/private/utils/untfs/inc/bitfrs.hxx
@@ -0,0 +1,69 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ bitfrs.hxx
+
+Abstract:
+
+ This module contains the declarations for the NTFS_BITMAP_FILE
+ class, which models the bitmap file for an NTFS volume.
+
+Author:
+
+ Bill McJohn (billmc) 18-June-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+#if !defined( NTFS_BITMAP_FILE_DEFN )
+
+#define NTFS_BITMAP_FILE_DEFN
+
+#include "frs.hxx"
+
+class NTFS_BITMAP_FILE : public NTFS_FILE_RECORD_SEGMENT {
+
+ public:
+
+ UNTFS_EXPORT
+ DECLARE_CONSTRUCTOR( NTFS_BITMAP_FILE );
+
+ VIRTUAL
+ UNTFS_EXPORT
+ ~NTFS_BITMAP_FILE(
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Initialize(
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Create(
+ IN PCSTANDARD_INFORMATION StandardInformation,
+ IN OUT PNTFS_BITMAP VolumeBitmap
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+};
+
+#endif
diff --git a/private/utils/untfs/inc/bootfile.hxx b/private/utils/untfs/inc/bootfile.hxx
new file mode 100644
index 000000000..40023006e
--- /dev/null
+++ b/private/utils/untfs/inc/bootfile.hxx
@@ -0,0 +1,82 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ bootfile.hxx
+
+Abstract:
+
+ This module contains the declarations for the NTFS_BOOT_FILE
+ class, which models the boot file for an NTFS volume.
+
+Author:
+
+ Bill McJohn (billmc) 18-June-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+#if !defined( NTFS_BOOT_FILE_DEFN )
+
+#define NTFS_BOOT_FILE_DEFN
+
+#include "frs.hxx"
+
+class NTFS_BOOT_FILE : public NTFS_FILE_RECORD_SEGMENT {
+
+ public:
+
+ UNTFS_EXPORT
+ DECLARE_CONSTRUCTOR( NTFS_BOOT_FILE );
+
+ UNTFS_EXPORT
+ VIRTUAL
+ ~NTFS_BOOT_FILE(
+ );
+
+ UNTFS_EXPORT
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Create(
+ IN PCSTANDARD_INFORMATION StandardInformation
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ VerifyAndFix(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNTFS_INDEX_TREE RootIndex,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ );
+
+ private:
+
+ NONVIRTUAL
+ BOOLEAN
+ CreateDataAttribute(
+ );
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+};
+
+#endif
diff --git a/private/utils/untfs/inc/clusrun.hxx b/private/utils/untfs/inc/clusrun.hxx
new file mode 100644
index 000000000..574780289
--- /dev/null
+++ b/private/utils/untfs/inc/clusrun.hxx
@@ -0,0 +1,340 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ clusrun.hxx
+
+Abstract:
+
+ This class models a run of clusters on an NTFS volume. Its
+ principle purpose is to mediate between the cluster-oriented
+ NTFS volume and the sector-oriented drive object.
+
+Author:
+
+ Bill McJohn (billmc) 17-June-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if !defined( NTFS_CLUSTER_RUN_DEFN )
+
+#define NTFS_CLUSTER_RUN_DEFN
+
+#include "secrun.hxx"
+
+
+class NTFS_CLUSTER_RUN : public SECRUN {
+
+ public:
+
+ UNTFS_EXPORT
+ DECLARE_CONSTRUCTOR( NTFS_CLUSTER_RUN );
+
+ UNTFS_EXPORT
+ VIRTUAL
+ ~NTFS_CLUSTER_RUN(
+ );
+
+ UNTFS_EXPORT
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PMEM Mem,
+ IN PLOG_IO_DP_DRIVE Drive,
+ IN LCN Lcn,
+ IN ULONG ClusterFactor,
+ IN ULONG NumberOfClusters
+ );
+
+ UNTFS_EXPORT
+ NONVIRTUAL
+ VOID
+ Relocate(
+ IN LCN NewLcn
+ );
+
+ NONVIRTUAL
+ LCN
+ QueryStartLcn(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QueryClusterFactor(
+ ) CONST;
+
+ NONVIRTUAL
+ PLOG_IO_DP_DRIVE
+ GetDrive(
+ );
+
+ NONVIRTUAL
+ VOID
+ MarkModified(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsModified(
+ ) CONST;
+
+ VIRTUAL
+ BOOLEAN
+ Write(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Write(
+ IN BOOLEAN OnlyIfModified
+ );
+
+ protected:
+
+ NONVIRTUAL
+ USHORT
+ QueryClusterSize(
+ ) CONST;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy (
+ );
+
+
+ LCN _StartLcn;
+ ULONG _ClusterFactor;
+ PLOG_IO_DP_DRIVE _Drive;
+ BOOLEAN _IsModified;
+
+};
+
+
+INLINE
+LCN
+NTFS_CLUSTER_RUN::QueryStartLcn (
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method gives the client the first LCN of the cluster run.
+
+Arguments:
+
+ StartLcn -- receives the first LCN of the cluster run.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ return _StartLcn;
+}
+
+
+INLINE
+ULONG
+NTFS_CLUSTER_RUN::QueryClusterFactor(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the number of sectors per cluster in
+ this cluster run.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The cluster run's cluster factor.
+
+++*/
+{
+ return _ClusterFactor;
+}
+
+
+INLINE
+PLOG_IO_DP_DRIVE
+NTFS_CLUSTER_RUN::GetDrive(
+ )
+/*++
+
+Routine Description:
+
+ This method returns the drive on which the Cluster Run resides.
+ This functionality enables clients of Cluster Run to initialize
+ other Cluster Runs on the same drive.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The drive on which the Cluster Run resides.
+
+--*/
+{
+ return _Drive;
+}
+
+
+INLINE
+VOID
+NTFS_CLUSTER_RUN::MarkModified(
+ )
+/*++
+
+Routine Description:
+
+ Mark the Cluster Run as modified.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _IsModified = TRUE;
+}
+
+
+INLINE
+BOOLEAN
+NTFS_CLUSTER_RUN::IsModified(
+ ) CONST
+/*++
+
+Routine Description:
+
+ Query whether the Cluster Run has been marked as modified.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the Cluster Run has been marked as modified.
+
+--*/
+{
+ return( _IsModified );
+}
+
+
+INLINE
+BOOLEAN
+NTFS_CLUSTER_RUN::Write(
+ )
+/*++
+
+Routine Description:
+
+ This method writes the Cluster Run.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This method is provided to keep the Write method on SECRUN visible.
+
+--*/
+{
+ return SECRUN::Write();
+}
+
+
+INLINE
+BOOLEAN
+NTFS_CLUSTER_RUN::Write(
+ IN BOOLEAN OnlyIfModified
+ )
+/*++
+
+Routine Description:
+
+ This method writes the Cluster Run; it also allows the client
+ to specify that it should only be written if it has been modified.
+
+Arguments:
+
+ OnlyIfModified -- supplies a flag indicating whether the write
+ is conditional; if this is TRUE, then the
+ Cluster Run is written only if it has been
+ marked as modified.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ The Cluster Run does not mark itself dirty; if clients want
+ to take advantage of the ability to write only if modified,
+ they have to be sure to call MarkModified appropriately.
+
+--*/
+{
+ _IsModified = (BOOLEAN)
+ !((OnlyIfModified && !_IsModified) || SECRUN::Write());
+
+ return !_IsModified;
+}
+
+
+INLINE
+USHORT
+NTFS_CLUSTER_RUN::QueryClusterSize(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the number of bytes per cluster.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Number of bytes per cluster (zero indicates error).
+
+--*/
+{
+ DebugPtrAssert( _Drive );
+
+ return( (USHORT)_ClusterFactor * (USHORT)_Drive->QuerySectorSize() );
+}
+
+#endif
diff --git a/private/utils/untfs/inc/extents.hxx b/private/utils/untfs/inc/extents.hxx
new file mode 100644
index 000000000..6e6f3e788
--- /dev/null
+++ b/private/utils/untfs/inc/extents.hxx
@@ -0,0 +1,361 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ extents.hxx
+
+Abstract:
+
+ This module contains the declarations for NTFS_EXTENT_LIST, which
+ models a set of NTFS extents.
+
+ An extent is a contiguous run of clusters; a non-resident
+ attribute's value is made up of a list of extents. The
+ NTFS_EXTENT_LIST object can be used to describe the disk space
+ allocated to a non-resident attribute.
+
+ This class also encapsulates the knowledge of mapping pairs
+ and their compression, i.e. of the representation of extent
+ lists in attribute records.
+
+Author:
+
+ Bill McJohn (billmc) 17-June-91
+ Matthew Bradburn (mattbr) 19-August-95
+ Changed to use NTFS MCB package.
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#if !defined( _NTFS_EXTENT_LIST_DEFN_ )
+
+#define _NTFS_EXTENT_LIST_DEFN_
+
+DECLARE_CLASS( NTFS_BITMAP );
+DECLARE_CLASS( NTFS_EXTENT_LIST );
+DECLARE_CLASS( NTFS_EXTENT );
+
+typedef struct _MAPPING_PAIR {
+
+ VCN NextVcn;
+ LCN CurrentLcn;
+};
+
+DEFINE_TYPE( _MAPPING_PAIR, MAPPING_PAIR );
+
+
+class NTFS_EXTENT : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( NTFS_EXTENT );
+
+ VCN Vcn;
+ LCN Lcn;
+ BIG_INT RunLength;
+
+};
+
+
+class NTFS_EXTENT_LIST : public OBJECT {
+
+ public:
+
+ UNTFS_EXPORT
+ DECLARE_CONSTRUCTOR( NTFS_EXTENT_LIST );
+
+ VIRTUAL
+ UNTFS_EXPORT
+ ~NTFS_EXTENT_LIST(
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Initialize(
+ IN VCN LowestVcn,
+ IN VCN NextVcn
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN VCN StartingVcn,
+ IN PCVOID CompressedMappingPairs,
+ IN ULONG MappingPairsMaximumLength,
+ OUT PBOOLEAN BadMappingPairs DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PCNTFS_EXTENT_LIST ExtentsToCopy
+ );
+
+ FRIEND
+ BOOLEAN
+ NTFS_EXTENT_LIST::Initialize(
+ IN PCNTFS_EXTENT_LIST ExtentsToCopy
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsEmpty(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsSparse(
+ ) CONST;
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ ULONG
+ QueryNumberOfExtents(
+ ) CONST;
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ AddExtent(
+ IN VCN Vcn,
+ IN LCN Lcn,
+ IN BIG_INT RunLength
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AddExtents(
+ IN VCN StartingVcn,
+ IN PCVOID CompressedMappingPairs,
+ IN ULONG MappingPairsMaximumLength,
+ OUT PBOOLEAN BadMappingPairs DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ VOID
+ DeleteExtent(
+ IN ULONG ExtentNumber
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Resize(
+ IN BIG_INT NewSize,
+ IN OUT PNTFS_BITMAP Bitmap
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ QueryExtent(
+ IN ULONG ExtentNumber,
+ OUT PVCN Vcn,
+ OUT PLCN Lcn,
+ OUT PBIG_INT RunLength
+ ) CONST;
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ QueryLcnFromVcn(
+ IN VCN Vcn,
+ OUT PLCN Lcn,
+ OUT PBIG_INT RunLength DEFAULT NULL
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryCompressedMappingPairs(
+ OUT PVCN LowestVcn,
+ OUT PVCN NextVcn,
+ OUT PULONG MappingPairsLength,
+ IN ULONG BufferSize,
+ IN OUT PVOID Buffer,
+ OUT PBOOLEAN HasHoleInFront DEFAULT NULL
+ ) CONST;
+
+ NONVIRTUAL
+ VCN
+ QueryLowestVcn(
+ ) CONST;
+
+ NONVIRTUAL
+ VCN
+ QueryNextVcn(
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetLowestVcn(
+ IN BIG_INT LowestVcn
+ );
+
+ NONVIRTUAL
+ VOID
+ SetNextVcn(
+ IN BIG_INT NextVcn
+ );
+
+ NONVIRTUAL
+ BIG_INT
+ QueryClustersAllocated(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ DeleteRange(
+ IN VCN Vcn,
+ IN BIG_INT RunLength
+ );
+
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ LCN
+ QueryLastLcn(
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ Truncate(
+ IN BIG_INT NewNumberOfClusters,
+ IN OUT PNTFS_BITMAP Bitmap
+ );
+
+ NONVIRTUAL
+ VOID
+ Coalesce(
+ );
+
+ STATIC
+ BOOLEAN
+ QueryMappingPairsLength(
+ IN PCVOID CompressedPairs,
+ IN ULONG MaximumLength,
+ OUT PULONG Length,
+ OUT PULONG NumberOfPairs
+ );
+
+ STATIC
+ BOOLEAN
+ ExpandMappingPairs(
+ IN PCVOID CompressedPairs,
+ IN VCN StartingVcn,
+ IN ULONG MaximumCompressedLength,
+ IN ULONG MaximumNumberOfPairs,
+ IN OUT PMAPPING_PAIR MappingPairs,
+ OUT PULONG NumberOfPairs
+ );
+
+ STATIC
+ BOOLEAN
+ CompressMappingPairs(
+ IN PCMAPPING_PAIR MappingPairs,
+ IN ULONG NumberOfPairs,
+ IN VCN StartingVcn,
+ IN OUT PVOID CompressedPairs,
+ IN ULONG MaximumCompressedLength,
+ OUT PULONG CompressedLength
+ );
+
+ struct _LARGE_MCB* _Mcb;
+ BOOLEAN _McbInitialized;
+ VCN _LowestVcn;
+ VCN _NextVcn;
+};
+
+
+INLINE
+BOOLEAN
+NTFS_EXTENT_LIST::IsEmpty(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method determines whether the extent list is empty.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if there are no extents in the list.
+
+--*/
+{
+ return ( _LowestVcn == _NextVcn );
+}
+
+
+INLINE
+VCN
+NTFS_EXTENT_LIST::QueryLowestVcn(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the lowest VCN covered by this extent
+ list. Note that for a sparse file, this is not necessarily
+ the same as the VCN of the first extent in the list.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The lowest VCN mapped by this extent list.
+
+--*/
+{
+ return _LowestVcn;
+}
+
+
+INLINE
+LCN
+NTFS_EXTENT_LIST::QueryNextVcn(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the highest VCN covered by this extent
+ list. Note that for a sparse file, this is not necessarily
+ the same as the last VCN of the last extent in the list.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The highest VCN mapped by this extent list.
+
+--*/
+{
+ return _NextVcn;
+}
+
+#endif // _NTFS_EXTENT_LIST_DEFN_
diff --git a/private/utils/untfs/inc/frs.hxx b/private/utils/untfs/inc/frs.hxx
new file mode 100644
index 000000000..b99aedddd
--- /dev/null
+++ b/private/utils/untfs/inc/frs.hxx
@@ -0,0 +1,715 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ frs.hxx
+
+Abstract:
+
+ This module contains the declarations for the
+ NTFS_FILE_RECORD_SEGMENT class. This class models File
+ Record Segments in the NTFS Master File Table; it is the
+ object through which a file's attributes may be accessed.
+
+Author:
+
+ Bill McJohn (billmc) 13-June-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if !defined( _NTFS_FILE_RECORD_SEGMENT_DEFN_ )
+
+#define _NTFS_FILE_RECORD_SEGMENT_DEFN_
+
+#include "frsstruc.hxx"
+#include "cannedsd.hxx"
+#include "clusrun.hxx"
+#include "array.hxx"
+#include "hmem.hxx"
+#include "list.hxx"
+#include "iterator.hxx"
+
+// Possible return codes for SortIndex:
+//
+// NTFS_SORT_INDEX_NOT_FOUND -- this FRS does not contain an
+// index with the specified name.
+// NTFS_SORT_INDEX_WELL_ORDERED -- the index was not sorted because
+// it was found to be well-ordered.
+// NTFS_SORT_INDEX_BADLY_ORDERED -- The index was found to be badly
+// ordered, and it was not sorted.
+// NTFS_SORT_INDEX_SORTED -- The index was sorted and new
+// attributes were inserted into
+// the FRS.
+// NTFS_SORT_INSERT_FAILED -- An insertion of an index entry
+// into the new tree failed.
+// (Probable cause: out of space.)
+// NTFS_SORT_ERROR -- Sort failed because of an error.
+//
+//
+typedef enum NTFS_SORT_CODE {
+
+ NTFS_SORT_INDEX_NOT_FOUND,
+ NTFS_SORT_INDEX_WELL_ORDERED,
+ NTFS_SORT_INDEX_BADLY_ORDERED,
+ NTFS_SORT_INDEX_SORTED,
+ NTFS_SORT_INSERT_FAILED,
+ NTFS_SORT_ERROR
+};
+
+// Possible return codes for VerifyAndFixQuotaDefaultId:
+//
+// NTFS_QUOTA_INDEX_NOT_FOUND -- this FRS does not contain an
+// index with the specified name.
+// NTFS_QUOTA_DEFAULT_ENTRY_MISSING-- the default entry was not found
+// in the index
+// NTFS_QUOTA_INDEX_FOUND -- Found the default Id entry in the
+// index tree.
+// NTFS_QUOTA_INDEX_INSERTED -- Inserted the default Id entry into
+// the index tree.
+// NTFS_QUOTA_INSERT_FAILED -- An insertion of the default Id
+// entry into the index tree failed.
+// (Probable cause: out of space.)
+// NTFS_QUOTA_ERROR -- error occurred. (Possibly out
+// of memory or out of space.)
+//
+typedef enum NTFS_QUOTA_CODE {
+
+ NTFS_QUOTA_INDEX_NOT_FOUND,
+ NTFS_QUOTA_INDEX_FOUND,
+ NTFS_QUOTA_DEFAULT_ENTRY_MISSING,
+ NTFS_QUOTA_INDEX_INSERTED,
+ NTFS_QUOTA_INSERT_FAILED,
+ NTFS_QUOTA_ERROR
+};
+
+// Possible return codes for FindSecurityIndexEntryAndValidate:
+//
+// NTFS_SECURITY_INDEX_ENTRY_MISSING -- the specified index entry key
+// cannot be found in the index
+// NTFS_SECURITY_INDEX_FOUND -- the found entry contains
+// correct data
+// NTFS_SECURITY_INDEX_FIXED -- the found entry contains invalid
+// data but is now corrected
+// NTFS_SECURITY_INDEX_DATA_ERROR -- The index was found but the data
+// data in it is incorrect.
+// NTFS_SECURITY_INDEX_INSERTED -- An index was successfully inserted
+// into the specified index.
+// NTFS_SECURITY_INSERT_FAILED -- An insertion of an index entry
+// into the index tree failed.
+// (Probable cause: out of space.)
+// NTFS_SECURITY_ERROR -- failed because of an error.
+// (Probably out of memory or out
+// of space.)
+//
+typedef enum NTFS_SECURITY_CODE {
+ NTFS_SECURITY_INDEX_ENTRY_MISSING,
+ NTFS_SECURITY_INDEX_FOUND,
+ NTFS_SECURITY_INDEX_FIXED,
+ NTFS_SECURITY_INDEX_DATA_ERROR,
+ NTFS_SECURITY_INDEX_INSERTED,
+ NTFS_SECURITY_INSERT_FAILED,
+ NTFS_SECURITY_ERROR
+};
+
+// Forward references
+
+DECLARE_CLASS( IO_DP_DRIVE );
+DECLARE_CLASS( NTFS_MASTER_FILE_TABLE );
+DECLARE_CLASS( NTFS_MFT_FILE );
+DECLARE_CLASS( NTFS_ATTRIBUTE );
+DECLARE_CLASS( WSTRING );
+DECLARE_CLASS( NTFS_ATTRIBUTE_RECORD );
+DECLARE_CLASS( NTFS_ATTRIBUTE_RECORD_LIST );
+DECLARE_CLASS( NTFS_FILE_RECORD_SEGMENT );
+DECLARE_CLASS( NTFS_ATTRIBUTE_LIST );
+DECLARE_CLASS( NTFS_BITMAP );
+DECLARE_CLASS( NTFS_BAD_CLUSTER_FILE );
+
+
+class NTFS_FILE_RECORD_SEGMENT : public NTFS_FRS_STRUCTURE {
+
+ public:
+
+ UNTFS_EXPORT
+ DECLARE_CONSTRUCTOR( NTFS_FILE_RECORD_SEGMENT );
+
+ VIRTUAL
+ UNTFS_EXPORT
+ ~NTFS_FILE_RECORD_SEGMENT (
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Initialize (
+ IN VCN FileNumber,
+ IN OUT PNTFS_MFT_FILE MftFile
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Initialize (
+ IN VCN FileNumber,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Create (
+ IN PCSTANDARD_INFORMATION StandardInformation,
+ IN USHORT Flags DEFAULT 0
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Create (
+ IN PCMFT_SEGMENT_REFERENCE BaseSegment,
+ IN USHORT Flags DEFAULT 0
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CreateSystemFile(
+ IN UCHAR major DEFAULT 0,
+ IN UCHAR minor DEFAULT 0
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CreateExtendSystemFile(
+ IN PCWSTRING file_name_text,
+ IN USHORT Flags
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ VerifyAndFixFileNames(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN DiskErrorsFound DEFAULT NULL,
+ IN BOOLEAN FixDupInfo DEFAULT TRUE
+ );
+
+ VIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Write(
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Flush(
+ IN OUT PNTFS_BITMAP VolumeBitmap OPTIONAL,
+ IN OUT PNTFS_INDEX_TREE ParentIndex DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AddDataAttribute(
+ IN ULONG InitialSize,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN BOOLEAN Fill DEFAULT FALSE,
+ IN CHAR FillCharacter DEFAULT 0
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ AddFileNameAttribute(
+ IN PFILE_NAME FileNameAttributeValue
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AddAttribute(
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCWSTRING Name OPTIONAL,
+ IN PCVOID Value OPTIONAL,
+ IN ULONG Length,
+ IN OUT PNTFS_BITMAP Bitmap OPTIONAL,
+ IN BOOLEAN IsIndexed DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ AddSecurityDescriptor(
+ IN CANNED_SECURITY_TYPE SecurityType,
+ IN OUT PNTFS_BITMAP Bitmap
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ AddSecurityDescriptorData(
+ IN PNTFS_ATTRIBUTE attribute,
+ IN OUT PVOID buffer,
+ OUT PSECURITY_ENTRY *SecurityEntry,
+ IN ULONG SecurityId,
+ IN CANNED_SECURITY_TYPE SecurityType,
+ IN OUT PNTFS_BITMAP Bitmap,
+ IN BOOLEAN FixLevel
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AddEmptyAttribute(
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCWSTRING Name DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ IsAttributePresent (
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCWSTRING Name DEFAULT NULL,
+ IN BOOLEAN IgnoreExternal DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryAttributeRecord (
+ OUT PNTFS_ATTRIBUTE_RECORD AttributeRecord,
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCWSTRING Name DEFAULT NULL
+ ) CONST;
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ QueryAttribute (
+ OUT PNTFS_ATTRIBUTE Attribute,
+ OUT PBOOLEAN Error,
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCWSTRING Name DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ QueryFileSizes (
+ OUT PBIG_INT AllocatedLength,
+ OUT PBIG_INT FileSize,
+ OUT PBOOLEAN Error
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryResidentAttribute (
+ OUT PNTFS_ATTRIBUTE Attribute,
+ OUT PBOOLEAN Error,
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCVOID Value,
+ IN ULONG ValueLength,
+ IN COLLATION_RULE CollationRule DEFAULT COLLATION_BINARY
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ QueryAttributeByOrdinal (
+ OUT PNTFS_ATTRIBUTE Attribute,
+ OUT PBOOLEAN Error,
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN ULONG Ordinal
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryAttributeByTag (
+ OUT PNTFS_ATTRIBUTE Attribute,
+ OUT PBOOLEAN Error,
+ IN ULONG Tag
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PurgeAttribute (
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCWSTRING Name DEFAULT NULL,
+ IN BOOLEAN IgnoreExternal DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DeleteResidentAttribute(
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCWSTRING Name OPTIONAL,
+ IN PCVOID Value,
+ IN ULONG ValueLength,
+ OUT PBOOLEAN Deleted,
+ IN BOOLEAN IgnoreExternal DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DeleteResidentAttributeLocal(
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCWSTRING Name OPTIONAL,
+ IN PCVOID Value,
+ IN ULONG ValueLength,
+ OUT PBOOLEAN Deleted,
+ OUT PBOOLEAN IsIndexed,
+ OUT PUSHORT InstanceTag
+ );
+
+ VIRTUAL
+ BOOLEAN
+ InsertAttributeRecord (
+ IN OUT PNTFS_ATTRIBUTE_RECORD NewRecord,
+ IN BOOLEAN ForceExternal DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ USHORT
+ QueryNextInstance(
+ );
+
+ NONVIRTUAL
+ VOID
+ IncrementNextInstance(
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryFreeSpace(
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryMaximumAttributeRecordSize (
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryNextAttribute(
+ IN OUT PATTRIBUTE_TYPE_CODE TypeCode,
+ IN OUT PWSTRING Name
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ RecoverFile(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNUMBER_SET BadClusterList,
+ OUT PULONG BadClusters,
+ OUT PBIG_INT BytesRecovered,
+ OUT PBIG_INT TotalBytes
+ );
+
+ NONVIRTUAL
+ NTFS_SORT_CODE
+ SortIndex(
+ IN PCWSTRING IndexName,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN BOOLEAN DuplicatesAllowed,
+ IN BOOLEAN CheckOnly DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ NTFS_QUOTA_CODE
+ VerifyAndFixQuotaDefaultId(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN BOOLEAN CheckOnly
+ );
+
+ NONVIRTUAL
+ NTFS_SECURITY_CODE
+ FindSecurityIndexEntryAndValidate(
+ IN OUT PNTFS_INDEX_TREE OldTree,
+ IN PVOID Key,
+ IN USHORT KeyLength,
+ IN PSECURITY_DESCRIPTOR_HEADER SecurityDescriptorHeader,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN BOOLEAN CheckOnly
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryDuplicatedInformation(
+ OUT PDUPLICATED_INFORMATION DuplicatedInformation
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ UpdateFileNames(
+ IN PDUPLICATED_INFORMATION DuplicatedInformation,
+ IN OUT PNTFS_INDEX_TREE Index OPTIONAL,
+ IN BOOLEAN IgnoreExternal
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Backtrack(
+ OUT PWSTRING Path
+ );
+
+ NONVIRTUAL
+ VOID
+ SetLsn(
+ IN BIG_INT NewLsn
+ );
+
+ protected:
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN LCN StartOfMft,
+ IN PNTFS_MASTER_FILE_TABLE Mft
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Create (
+ IN USHORT Flags DEFAULT 0
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetupAttributeList(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CreateAttributeList(
+ OUT PNTFS_ATTRIBUTE_LIST AttributeList
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SaveAttributeList(
+ PNTFS_BITMAP VolumeBitmap
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ InsertExternalAttributeRecord(
+ IN PNTFS_ATTRIBUTE_RECORD NewRecord
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ BacktrackWorker(
+ IN OUT PWSTRING Path
+ );
+
+ NONVIRTUAL
+ PNTFS_FILE_RECORD_SEGMENT
+ SetupChild(
+ IN VCN FileNumber
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AddChild(
+ PNTFS_FILE_RECORD_SEGMENT ChildFrs
+ );
+
+ NONVIRTUAL
+ PNTFS_FILE_RECORD_SEGMENT
+ GetChild(
+ VCN FileNumber
+ );
+
+ NONVIRTUAL
+ VOID
+ DeleteChild(
+ VCN FileNumber
+ );
+
+ HMEM _Mem;
+ LIST _Children;
+ PITERATOR _ChildIterator;
+ PNTFS_MASTER_FILE_TABLE _Mft;
+ PNTFS_ATTRIBUTE_LIST _AttributeList;
+
+};
+
+
+INLINE
+USHORT
+NTFS_FILE_RECORD_SEGMENT::QueryNextInstance(
+ )
+/*++
+
+Routine Description:
+
+ This method fetches the current value of the FRS'
+ NextAttributeInstance field.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The current value of the FRS' NextAttributeInstance field.
+
+--*/
+{
+ return _FrsData->NextAttributeInstance;
+}
+
+
+INLINE
+VOID
+NTFS_FILE_RECORD_SEGMENT::IncrementNextInstance(
+ )
+/*++
+
+Routine Description:
+
+ This method increments the NextAttributeInstance field of
+ the File Record Segment.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _FrsData->NextAttributeInstance++;
+}
+
+
+
+INLINE
+ULONG
+NTFS_FILE_RECORD_SEGMENT::QueryFreeSpace(
+ )
+/*++
+
+Routine Description:
+
+ This method returns the amount of free space following the
+ last Attribute Record in the File Record Segment.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The amount of free space.
+
+Notes:
+
+ This method assumes that the FRS is consistent.
+
+--*/
+{
+ return _FrsData->BytesAvailable - _FrsData->FirstFreeByte;
+}
+
+
+INLINE
+ULONG
+NTFS_FILE_RECORD_SEGMENT::QueryMaximumAttributeRecordSize (
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the size of the largest attribute record
+ the File Record Segment will accept. Note that this is the
+ largest record it will ever accept, not what it can currently
+ accept.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The size of the largest attribute record a File Record Segment
+ of this size can accept.
+
+--*/
+{
+ ULONG temp;
+
+ //
+ // Take a precaution to make sure this routine never returns a
+ // "negative" number.
+ //
+
+ temp = _FrsData->FirstAttributeOffset + QuadAlign(sizeof(ATTRIBUTE_TYPE_CODE));
+
+ if (temp > QuerySize()) {
+
+ return QuerySize();
+
+ }
+
+ return QuerySize() - temp;
+}
+
+
+INLINE
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::AddEmptyAttribute(
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCWSTRING Name
+ )
+/*++
+
+Routine Description:
+
+ This method adds an empty, non-indexed, resident attribute of
+ the specified type to the FRS.
+
+Arguments:
+
+ Type -- Supplies the attribute's type code.
+ Name -- Supplies the attribute's name. May be NULL, in which
+ case the attribute has no name.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ NTFS_ATTRIBUTE Attribute;
+
+ return( Attribute.Initialize( GetDrive(),
+ QueryClusterFactor(),
+ NULL,
+ 0,
+ Type,
+ Name,
+ 0 ) &&
+ Attribute.InsertIntoFile( this, NULL ) );
+
+}
+
+#endif
diff --git a/private/utils/untfs/inc/frsstruc.hxx b/private/utils/untfs/inc/frsstruc.hxx
new file mode 100644
index 000000000..376a3c66c
--- /dev/null
+++ b/private/utils/untfs/inc/frsstruc.hxx
@@ -0,0 +1,912 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ frsstruc.hxx
+
+Abstract:
+
+ This class models a file record segment structure.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 17-Sep-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if !defined( _NTFS_FRS_STRUCTURE_DEFN_ )
+
+#define _NTFS_FRS_STRUCTURE_DEFN_
+
+#include "volume.hxx"
+#include "ntfssa.hxx"
+
+DECLARE_CLASS( NTFS_FRS_STRUCTURE );
+DECLARE_CLASS( MEM );
+DECLARE_CLASS( NTFS_ATTRIBUTE );
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( NTFS_CLUSTER_RUN );
+DECLARE_CLASS( WSTRING );
+DECLARE_CLASS( MESSAGE );
+DECLARE_CLASS( NTFS_ATTRIBUTE_COLUMNS );
+DECLARE_CLASS( NTFS_ATTRIBUTE_LIST );
+DECLARE_CLASS( NTFS_BITMAP );
+DECLARE_CLASS( NTFS_UPCASE_TABLE );
+
+class NTFS_FRS_STRUCTURE : public OBJECT {
+
+ public:
+
+ UNTFS_EXPORT
+ DECLARE_CONSTRUCTOR( NTFS_FRS_STRUCTURE );
+
+ VIRTUAL
+ UNTFS_EXPORT
+ ~NTFS_FRS_STRUCTURE(
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PNTFS_ATTRIBUTE MftData,
+ IN VCN FileNumber,
+ IN ULONG ClusterFactor,
+ IN BIG_INT VolumeSectors,
+ IN ULONG FrsSize,
+ IN PNTFS_UPCASE_TABLE UpcaseTable OPTIONAL
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN LCN StartOfMft,
+ IN ULONG ClusterFactor,
+ IN BIG_INT VolumeSectors,
+ IN ULONG FrsSize,
+ IN PNTFS_UPCASE_TABLE UpcaseTable DEFAULT NULL,
+ IN ULONG Offset DEFAULT 0
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ VerifyAndFix(
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN PCNTFS_ATTRIBUTE_COLUMNS AttributeDefTable OPTIONAL,
+ IN OUT PBOOLEAN DiskErrorsFound DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ LoneFrsAllocationCheck(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNTFS_CHKDSK_REPORT ChkdskReport,
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN DiskErrorsFound DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CheckInstanceTags(
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ OUT PBOOLEAN Changes,
+ IN OUT PNTFS_ATTRIBUTE_LIST AttributeList DEFAULT NULL
+ );
+
+ VIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Read(
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Write(
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ PVOID
+ GetNextAttributeRecord(
+ IN PCVOID AttributeRecord,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ OUT PBOOLEAN ErrorsFound DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ VOID
+ DeleteAttributeRecord(
+ IN OUT PVOID AttributeRecord
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ InsertAttributeRecord(
+ IN OUT PVOID Position,
+ IN PCVOID AttributeRecord
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ QueryAttributeList(
+ OUT PNTFS_ATTRIBUTE_LIST AttributeList
+ );
+
+ NONVIRTUAL
+ PVOID
+ GetAttribute(
+ IN ULONG TypeCode
+ );
+
+ NONVIRTUAL
+ PVOID
+ GetAttributeList(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ UpdateAttributeList(
+ IN PCNTFS_ATTRIBUTE_LIST AttributeList,
+ IN BOOLEAN WriteList
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ SafeQueryAttribute(
+ IN ATTRIBUTE_TYPE_CODE TypeCode,
+ IN OUT PNTFS_ATTRIBUTE MftData,
+ OUT PNTFS_ATTRIBUTE Attribute
+ );
+
+ NONVIRTUAL
+ MFT_SEGMENT_REFERENCE
+ QuerySegmentReference(
+ ) CONST;
+
+ NONVIRTUAL
+ FILE_REFERENCE
+ QueryBaseFileRecordSegment(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsBase(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsInUse(
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ ClearInUse(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsSystemFile(
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetSystemFile(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsViewIndexPresent(
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetViewIndexPresent(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsIndexPresent(
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetIndexPresent(
+ );
+
+ NONVIRTUAL
+ VOID
+ ClearIndexPresent(
+ );
+
+ NONVIRTUAL
+ VCN
+ QueryFileNumber(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QueryClusterFactor(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QuerySize(
+ ) CONST;
+
+ NONVIRTUAL
+ PLOG_IO_DP_DRIVE
+ GetDrive(
+ );
+
+ NONVIRTUAL
+ USHORT
+ QueryReferenceCount(
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetReferenceCount(
+ IN USHORT ReferenceCount
+ );
+
+ NONVIRTUAL
+ BIG_INT
+ QueryVolumeSectors(
+ ) CONST;
+
+ NONVIRTUAL
+ PNTFS_UPCASE_TABLE
+ GetUpcaseTable(
+ );
+
+ NONVIRTUAL
+ VOID
+ SetUpcaseTable(
+ IN PNTFS_UPCASE_TABLE UpcaseTable
+ );
+
+ NONVIRTUAL
+ LSN
+ QueryLsn(
+ ) CONST;
+
+ protected:
+
+ NONVIRTUAL
+ ULONG
+ QueryAvailableSpace(
+ );
+
+ PFILE_RECORD_SEGMENT_HEADER _FrsData;
+
+ private:
+
+ NONVIRTUAL
+ BOOLEAN
+ Sort(
+ OUT PBOOLEAN Changes,
+ OUT PBOOLEAN Duplicates
+ );
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ PSECRUN _secrun;
+ PNTFS_ATTRIBUTE _mftdata;
+
+ PNTFS_UPCASE_TABLE _upcase_table;
+
+ VCN _file_number;
+ ULONG _cluster_factor;
+ ULONG _size;
+ PLOG_IO_DP_DRIVE _drive;
+ BIG_INT _volume_sectors;
+
+};
+
+
+INLINE
+MFT_SEGMENT_REFERENCE
+NTFS_FRS_STRUCTURE::QuerySegmentReference(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the segment reference value for this FRS.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The segment reference value for this FRS.
+
+--*/
+{
+ MFT_SEGMENT_REFERENCE SegmentReference;
+
+ DebugAssert( _FrsData );
+
+ SegmentReference.LowPart = _file_number.GetLowPart();
+ SegmentReference.HighPart = (USHORT) _file_number.GetHighPart();
+ SegmentReference.SequenceNumber = _FrsData->SequenceNumber;
+
+ return SegmentReference;
+}
+
+
+INLINE
+FILE_REFERENCE
+NTFS_FRS_STRUCTURE::QueryBaseFileRecordSegment(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This field contains a pointer to the base file record segment for
+ this file record segment.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A FILE_REFERENCE to the base file record segment for this file
+ record segment.
+
+--*/
+{
+ DebugAssert( _FrsData );
+
+ return _FrsData->BaseFileRecordSegment;
+}
+
+
+INLINE
+BOOLEAN
+NTFS_FRS_STRUCTURE::IsBase(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method determines whether this File Record Segment is the
+ Base File Record Segment for its file.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if this is a Base File Record Segment; FALSE otherwise.
+
+--*/
+{
+ return( _FrsData->BaseFileRecordSegment.LowPart == 0 &&
+ _FrsData->BaseFileRecordSegment.HighPart == 0 &&
+ _FrsData->BaseFileRecordSegment.SequenceNumber == 0 );
+}
+
+
+INLINE
+BOOLEAN
+NTFS_FRS_STRUCTURE::IsInUse(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes whether or not this file record segment is in
+ use.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - This file record segment is not in use.
+ TRUE - This file record segment is in use.
+
+--*/
+{
+ DebugAssert( _FrsData );
+
+ return (_FrsData->Flags & FILE_RECORD_SEGMENT_IN_USE) ? TRUE : FALSE;
+}
+
+
+INLINE
+VOID
+NTFS_FRS_STRUCTURE::ClearInUse(
+ )
+/*++
+
+Routine Description:
+
+ This routine clears the in use bit on this file record segment.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DebugAssert( _FrsData );
+
+ _FrsData->Flags &= ~FILE_RECORD_SEGMENT_IN_USE;
+}
+
+
+INLINE
+BOOLEAN
+NTFS_FRS_STRUCTURE::IsSystemFile(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes whether or not this file record segment is a
+ system file.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - This file record segment is not a system file.
+ TRUE - This file record segment is a system file.
+
+--*/
+{
+ DebugAssert( _FrsData );
+
+ return (_FrsData->Flags & FILE_SYSTEM_FILE) ? TRUE : FALSE;
+}
+
+
+INLINE
+VOID
+NTFS_FRS_STRUCTURE::SetSystemFile(
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the system file bit on this file record segment.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DebugAssert( _FrsData );
+
+ _FrsData->Flags |= FILE_SYSTEM_FILE;
+}
+
+
+INLINE
+BOOLEAN
+NTFS_FRS_STRUCTURE::IsViewIndexPresent(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes whether or not the indices of file record segment
+ can be viewed.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - The indices of this file record segment cannot be viewed.
+ TRUE - The indices of this file record segment can be viewed.
+
+--*/
+{
+ DebugAssert( _FrsData );
+
+ return (_FrsData->Flags & FILE_VIEW_INDEX_PRESENT) ? TRUE : FALSE;
+}
+
+INLINE
+VOID
+NTFS_FRS_STRUCTURE::SetViewIndexPresent(
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the view index present bit on this file record segment.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DebugAssert( _FrsData );
+
+ _FrsData->Flags |= FILE_VIEW_INDEX_PRESENT;
+}
+
+
+INLINE
+BOOLEAN
+NTFS_FRS_STRUCTURE::IsIndexPresent(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes whether or not this file record segment's
+ FILE_NAME_INDEX_PRESENT flag is set.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - This file record segment's FILE_NAME_INDEX_PRESENT is NOT set.
+ TRUE - This file record segment's FILE_NAME_INDEX_PRESENT is set.
+
+--*/
+{
+ DebugAssert( _FrsData );
+
+ return (_FrsData->Flags & FILE_FILE_NAME_INDEX_PRESENT) ? TRUE : FALSE;
+}
+
+
+INLINE
+VOID
+NTFS_FRS_STRUCTURE::ClearIndexPresent(
+ )
+/*++
+
+Routine Description:
+
+ This routine clears the index present bit on this file record segment.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DebugAssert( _FrsData );
+
+ _FrsData->Flags &= ~FILE_FILE_NAME_INDEX_PRESENT;
+}
+
+
+INLINE
+VOID
+NTFS_FRS_STRUCTURE::SetIndexPresent(
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the index present bit on this file record segment.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DebugAssert( _FrsData );
+
+ _FrsData->Flags |= FILE_FILE_NAME_INDEX_PRESENT;
+}
+
+
+INLINE
+ULONG
+NTFS_FRS_STRUCTURE::QuerySize(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of bytes in this file
+ record segment.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of bytes in this file record segment.
+
+--*/
+{
+ return _size;
+}
+
+
+INLINE
+VCN
+NTFS_FRS_STRUCTURE::QueryFileNumber(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the File Number of the File Record Segment.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ the File Number (i.e. ordinal number within the MFT) of this
+ File Record Segment.
+
+--*/
+{
+ return _file_number;
+}
+
+
+INLINE
+ULONG
+NTFS_FRS_STRUCTURE::QueryClusterFactor(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the cluster factor.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The cluster factor with which this File Record Segment was initialized.
+
+--*/
+{
+ return _cluster_factor;
+}
+
+INLINE
+PLOG_IO_DP_DRIVE
+NTFS_FRS_STRUCTURE::GetDrive(
+ )
+/*++
+
+Routine Description:
+
+ This method returns the drive on which the File Record Segment
+ resides. This functionality enables clients to initialize
+ other File Record Segments on the same drive.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The drive on which the File Record Segment resides.
+
+--*/
+{
+ return _drive;
+}
+
+
+INLINE
+USHORT
+NTFS_FRS_STRUCTURE::QueryReferenceCount(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the value of the reference count field
+ in this frs.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The value of the reference count field in this frs.
+
+--*/
+{
+ return _FrsData->ReferenceCount;
+}
+
+
+INLINE
+VOID
+NTFS_FRS_STRUCTURE::SetReferenceCount(
+ IN USHORT ReferenceCount
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the value of the reference count field
+ in this frs.
+
+Arguments:
+
+ ReferenceCount - Supplies the new reference count.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _FrsData->ReferenceCount = ReferenceCount;
+}
+
+
+INLINE
+BIG_INT
+NTFS_FRS_STRUCTURE::QueryVolumeSectors(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the number of sectors on the volume as recorded in
+ the boot sector.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of volume sectors.
+
+--*/
+{
+ return _volume_sectors;
+}
+
+
+INLINE
+PNTFS_UPCASE_TABLE
+NTFS_FRS_STRUCTURE::GetUpcaseTable(
+ )
+/*++
+
+Routine Description:
+
+ This method fetches the upcase table for the volume on which
+ this FRS resides.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The volume upcase table.
+
+--*/
+{
+ return _upcase_table;
+}
+
+INLINE
+VOID
+NTFS_FRS_STRUCTURE::SetUpcaseTable(
+ IN PNTFS_UPCASE_TABLE UpcaseTable
+ )
+/*++
+
+Routine Description:
+
+ This method sets the upcase table for the volume on which
+ this FRS resides.
+
+Arguments:
+
+ UpcaseTable -- Supplies the volume upcase table.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _upcase_table = UpcaseTable;
+}
+
+
+INLINE
+LSN
+NTFS_FRS_STRUCTURE::QueryLsn(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the logical sequence number for this file
+ record segment.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The logical sequence number for this file record segment.
+
+--*/
+{
+ DebugAssert( _FrsData );
+
+ return _FrsData->Lsn;
+}
+
+
+#endif // _NTFS_FRS_STRUCTURE_DEFN_
diff --git a/private/utils/untfs/inc/fsrtlp.h b/private/utils/untfs/inc/fsrtlp.h
new file mode 100644
index 000000000..db08b28f1
--- /dev/null
+++ b/private/utils/untfs/inc/fsrtlp.h
@@ -0,0 +1,273 @@
+/*++
+
+Copyright (c) 1995 Microsoft Corporation
+
+Module Name:
+
+ fsrtlp.h
+
+Abstract:
+
+ This header file is included by largemcb.h, and is used to stub out the
+ kernel-only subroutine calls, as well as declare types and functions
+ provided by the MCB package.
+
+Author:
+
+ Matthew Bradburn (mattbr) 19-August-95
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+#define NTKERNELAPI
+
+typedef ULONG ERESOURCE, *PERESOURCE;
+typedef ULONG FAST_MUTEX, *PFAST_MUTEX;
+typedef ULONG KEVENT, *PKEVENT;
+typedef ULONG KMUTEX, *PKMUTEX;
+
+typedef enum _POOL_TYPE {
+ NonPagedPool,
+ PagedPool,
+ NonPagedPoolMustSucceed,
+ DontUseThisType,
+ NonPagedPoolCacheAligned,
+ PagedPoolCacheAligned,
+ NonPagedPoolCacheAlignedMustS,
+ MaxPoolType
+} POOL_TYPE;
+
+typedef ULONG VBN, *PVBN;
+typedef ULONG LBN, *PLBN;
+
+#define PAGED_CODE() /* nothing */
+#define DebugTrace(a, b, c, d) /* nothing */
+#define ExInitializeFastMutex(a) /* nothing */
+#define ExAcquireFastMutex(a) /* nothing */
+#define ExReleaseFastMutex(a) /* nothing */
+#define ExAcquireSpinLock(a, b) /* nothing */
+#define ExReleaseSpinLock(a, b) /* nothing */
+
+#define ExIsFullZone(a) FALSE
+#define ExAllocateFromZone(a) ((PVOID)1)
+#define ExIsObjectInFirstZoneSegment(a, b) TRUE
+#define ExFreeToZone(a, p) /* nothing */
+
+#define try_return(S) { S; goto try_exit; }
+
+extern
+PVOID
+MemAlloc(
+ IN ULONG Size
+ );
+
+extern
+PVOID
+MemAllocOrRaise(
+ IN ULONG Size
+ );
+
+extern
+VOID
+MemFree(
+ IN PVOID Addr
+ );
+
+#define ExAllocatePool(type, size) MemAlloc(size)
+#define FsRtlAllocatePool(type, size) MemAllocOrRaise(size)
+#define ExFreePool(p) MemFree(p)
+
+//
+// Large Integer Mapped Control Blocks routines, implemented in LargeMcb.c
+//
+// An LARGE_MCB is an opaque structure but we need to declare the size of
+// it here so that users can allocate space for one. Consequently the
+// size computation here must be updated by hand if the MCB changes.
+//
+// Current the structure consists of the following.
+// PVOID
+// ULONG
+// ULONG
+// POOL_TYPE (enumerated type)
+// PVOID
+//
+// We will round the structure up to a quad-word boundary.
+//
+
+typedef struct _LARGE_MCB {
+ ULONG Opaque[ 6 ];
+} LARGE_MCB;
+typedef LARGE_MCB *PLARGE_MCB;
+
+NTKERNELAPI
+VOID
+FsRtlInitializeLargeMcb (
+ IN PLARGE_MCB Mcb,
+ IN POOL_TYPE PoolType
+ );
+
+NTKERNELAPI
+VOID
+FsRtlUninitializeLargeMcb (
+ IN PLARGE_MCB Mcb
+ );
+
+NTKERNELAPI
+VOID
+FsRtlTruncateLargeMcb (
+ IN PLARGE_MCB Mcb,
+ IN LONGLONG Vbn
+ );
+
+NTKERNELAPI
+BOOLEAN
+FsRtlAddLargeMcbEntry (
+ IN PLARGE_MCB Mcb,
+ IN LONGLONG Vbn,
+ IN LONGLONG Lbn,
+ IN LONGLONG SectorCount
+ );
+
+NTKERNELAPI
+VOID
+FsRtlRemoveLargeMcbEntry (
+ IN PLARGE_MCB Mcb,
+ IN LONGLONG Vbn,
+ IN LONGLONG SectorCount
+ );
+
+NTKERNELAPI
+BOOLEAN
+FsRtlLookupLargeMcbEntry (
+ IN PLARGE_MCB Mcb,
+ IN LONGLONG Vbn,
+ OUT PLONGLONG Lbn OPTIONAL,
+ OUT PLONGLONG SectorCountFromLbn OPTIONAL,
+ OUT PLONGLONG StartingLbn OPTIONAL,
+ OUT PLONGLONG SectorCountFromStartingLbn OPTIONAL,
+ OUT PULONG Index OPTIONAL
+ );
+
+NTKERNELAPI
+BOOLEAN
+FsRtlLookupLastLargeMcbEntry (
+ IN PLARGE_MCB Mcb,
+ OUT PLONGLONG Vbn,
+ OUT PLONGLONG Lbn
+ );
+
+NTKERNELAPI
+ULONG
+FsRtlNumberOfRunsInLargeMcb (
+ IN PLARGE_MCB Mcb
+ );
+
+NTKERNELAPI
+BOOLEAN
+FsRtlGetNextLargeMcbEntry (
+ IN PLARGE_MCB Mcb,
+ IN ULONG RunIndex,
+ OUT PLONGLONG Vbn,
+ OUT PLONGLONG Lbn,
+ OUT PLONGLONG SectorCount
+ );
+
+NTKERNELAPI
+BOOLEAN
+FsRtlSplitLargeMcb (
+ IN PLARGE_MCB Mcb,
+ IN LONGLONG Vbn,
+ IN LONGLONG Amount
+ );
+
+
+//
+// Mapped Control Blocks routines, implemented in Mcb.c
+//
+// An MCB is an opaque structure but we need to declare the size of
+// it here so that users can allocate space for one. Consequently the
+// size computation here must be updated by hand if the MCB changes.
+//
+
+typedef struct _MCB {
+ ULONG Opaque[ 4 + (sizeof(PKMUTEX)+3)/4 ];
+} MCB;
+typedef MCB *PMCB;
+
+NTKERNELAPI
+VOID
+FsRtlInitializeMcb (
+ IN PMCB Mcb,
+ IN POOL_TYPE PoolType
+ );
+
+NTKERNELAPI
+VOID
+FsRtlUninitializeMcb (
+ IN PMCB Mcb
+ );
+
+NTKERNELAPI
+VOID
+FsRtlTruncateMcb (
+ IN PMCB Mcb,
+ IN VBN Vbn
+ );
+
+NTKERNELAPI
+BOOLEAN
+FsRtlAddMcbEntry (
+ IN PMCB Mcb,
+ IN VBN Vbn,
+ IN LBN Lbn,
+ IN ULONG SectorCount
+ );
+
+NTKERNELAPI
+VOID
+FsRtlRemoveMcbEntry (
+ IN PMCB Mcb,
+ IN VBN Vbn,
+ IN ULONG SectorCount
+ );
+
+NTKERNELAPI
+BOOLEAN
+FsRtlLookupMcbEntry (
+ IN PMCB Mcb,
+ IN VBN Vbn,
+ OUT PLBN Lbn,
+ OUT PULONG SectorCount OPTIONAL,
+ OUT PULONG Index
+ );
+
+NTKERNELAPI
+BOOLEAN
+FsRtlLookupLastMcbEntry (
+ IN PMCB Mcb,
+ OUT PVBN Vbn,
+ OUT PLBN Lbn
+ );
+
+NTKERNELAPI
+ULONG
+FsRtlNumberOfRunsInMcb (
+ IN PMCB Mcb
+ );
+
+NTKERNELAPI
+BOOLEAN
+FsRtlGetNextMcbEntry (
+ IN PMCB Mcb,
+ IN ULONG RunIndex,
+ OUT PVBN Vbn,
+ OUT PLBN Lbn,
+ OUT PULONG SectorCount
+ );
diff --git a/private/utils/untfs/inc/hackwc.hxx b/private/utils/untfs/inc/hackwc.hxx
new file mode 100644
index 000000000..593ad250b
--- /dev/null
+++ b/private/utils/untfs/inc/hackwc.hxx
@@ -0,0 +1,34 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ hackwc.hxx
+
+Abstract:
+
+ This module contains the prototype for a hack that allows me
+ to compare attribute names correctly.
+
+ The comparison of attribute names is binary (word by word);
+ I can't use WSTRING because it's comparisons are all based
+ on the locale, while this comparison is locale-independent.
+
+Author:
+
+ Bill McJohn (billmc) 14-Aug-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+INT
+CountedWCMemCmp(
+ IN PCWSTR String1,
+ IN ULONG Length1,
+ IN PCWSTR String2,
+ IN ULONG Length2
+ );
diff --git a/private/utils/untfs/inc/indxbuff.hxx b/private/utils/untfs/inc/indxbuff.hxx
new file mode 100644
index 000000000..5a01a02de
--- /dev/null
+++ b/private/utils/untfs/inc/indxbuff.hxx
@@ -0,0 +1,378 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ indxbuff.hxx
+
+Abstract:
+
+ this module contains the declarations for the NTFS_INDEX_BUFFER
+ class, which models index buffers in NTFS index trees.
+
+Author:
+
+ Bill McJohn (billmc) 02-Sept-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if !defined( _NTFS_INDEX_BUFFER_DEFN_ )
+
+#define _NTFS_INDEX_BUFFER_DEFN_
+
+#include "hmem.hxx"
+#include "indxtree.hxx"
+
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( NTFS_ATTRIBUTE );
+DECLARE_CLASS( NTFS_INDEX_TREE );
+DECLARE_CLASS( NTFS_UPCASE_TABLE );
+
+class NTFS_INDEX_BUFFER : public OBJECT {
+
+ FRIEND
+ BOOLEAN
+ NTFS_INDEX_TREE::InsertIntoBuffer(
+ PNTFS_INDEX_BUFFER TargetBuffer,
+ PINTSTACK ParentTrail,
+ PCINDEX_ENTRY NewEntry,
+ PINDEX_ENTRY InsertionPoint
+ );
+
+ FRIEND
+ BOOLEAN
+ NTFS_INDEX_TREE::InsertIntoRoot(
+ PCINDEX_ENTRY NewEntry,
+ PINDEX_ENTRY InsertionPoint
+ );
+
+ FRIEND
+ BOOLEAN
+ NTFS_INDEX_TREE::GetNextParent(
+ );
+
+ public:
+
+ DECLARE_CONSTRUCTOR( NTFS_INDEX_BUFFER );
+
+ VIRTUAL
+ ~NTFS_INDEX_BUFFER(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PCLOG_IO_DP_DRIVE Drive,
+ IN VCN ThisBufferVcn,
+ IN ULONG ClusterSize,
+ IN ULONG ClustersPerBuffer,
+ IN ULONG BufferSize,
+ IN ULONG CollationRule,
+ IN PNTFS_UPCASE_TABLE UpcaseTable
+ );
+
+ NONVIRTUAL
+ VOID
+ Create(
+ IN BOOLEAN IsLeaf,
+ IN VCN EndEntryDownpointer
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Read(
+ IN OUT PNTFS_ATTRIBUTE AllocationAttribute
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Write(
+ IN OUT PNTFS_ATTRIBUTE AllocationAttribute
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FindEntry(
+ IN PCINDEX_ENTRY SearchEntry,
+ IN OUT PULONG Ordinal,
+ OUT PINDEX_ENTRY* EntryFound
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ InsertEntry(
+ IN PCINDEX_ENTRY NewEntry,
+ IN PINDEX_ENTRY InsertPoint DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ VOID
+ RemoveEntry(
+ IN PINDEX_ENTRY EntryToRemove
+ );
+
+ NONVIRTUAL
+ PINDEX_ENTRY
+ GetFirstEntry(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsLeaf(
+ ) CONST;
+
+ NONVIRTUAL
+ VCN
+ QueryVcn(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QuerySize(
+ ) CONST;
+
+ NONVIRTUAL
+ PINDEX_ALLOCATION_BUFFER
+ GetData(
+ );
+
+ NONVIRTUAL
+ PINDEX_ENTRY
+ FindSplitPoint(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsEmpty(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetLsn(
+ IN BIG_INT NewLsn
+ );
+
+ NONVIRTUAL
+ LSN
+ QueryLsn(
+ ) CONST;
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ VOID
+ InsertClump(
+ IN ULONG LengthOfClump,
+ IN PCVOID Clump
+ );
+
+ NONVIRTUAL
+ VOID
+ RemoveClump(
+ IN ULONG LengthOfClump
+ );
+
+
+
+ VCN _ThisBufferVcn;
+ ULONG _ClusterSize;
+ ULONG _ClustersPerBuffer;
+ ULONG _BufferSize;
+ COLLATION_RULE _CollationRule;
+ PNTFS_UPCASE_TABLE _UpcaseTable;
+
+ HMEM _Mem;
+ PINDEX_ALLOCATION_BUFFER _Data;
+};
+
+
+INLINE
+PINDEX_ENTRY
+NTFS_INDEX_BUFFER::GetFirstEntry(
+ )
+/*++
+
+Routine Description:
+
+ This method returns a pointer to the first entry in the index buffer.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the first index entry in the buffer.
+
+--*/
+{
+ return( (PINDEX_ENTRY)( (PBYTE)&(_Data->IndexHeader) +
+ _Data->IndexHeader.FirstIndexEntry ) );
+}
+
+
+
+INLINE
+BOOLEAN
+NTFS_INDEX_BUFFER::IsLeaf(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method determines whether this index buffer is a leaf.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if this buffer is a leaf; FALSE otherwise.
+
+--*/
+{
+ return( !(_Data->IndexHeader.Flags & INDEX_NODE) );
+}
+
+
+INLINE
+VCN
+NTFS_INDEX_BUFFER::QueryVcn(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the VCN within the index allocation attribute
+ of this index buffer.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The VCN within the index allocation attribute of this index buffer.
+
+--*/
+{
+ return _ThisBufferVcn;
+}
+
+
+INLINE
+ULONG
+NTFS_INDEX_BUFFER::QuerySize(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the size of this buffer. Note that it includes
+ any free space in the buffer, and that all buffers in a given tree
+ will have the same size.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The size of the buffer.
+--*/
+{
+ return _BufferSize;
+}
+
+
+INLINE
+PINDEX_ALLOCATION_BUFFER
+NTFS_INDEX_BUFFER::GetData(
+ )
+/*++
+
+Routine Description:
+
+ This method returns the index buffer's data buffer. It's a back
+ door that allows the index tree to read and write the index buffer.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The index buffer's data buffer.
+
+--*/
+{
+ return _Data;
+}
+
+
+INLINE
+BOOLEAN
+NTFS_INDEX_BUFFER::SetLsn(
+ IN BIG_INT NewLsn
+ )
+/*++
+
+Routine Description:
+
+ This method sets the Log Sequence Number in the index buffer.
+
+Arguments:
+
+ NewLsn -- Supplies the new LSN
+
+Return Value:
+
+ Always returns TRUE.
+
+--*/
+{
+ _Data->Lsn = NewLsn.GetLargeInteger();
+ return TRUE;
+}
+
+
+INLINE
+LSN
+NTFS_INDEX_BUFFER::QueryLsn(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method sets the Log Sequence Number in the index buffer.
+
+Arguments:
+
+ NewLsn -- Supplies the new LSN
+
+Return Value:
+
+ Always returns TRUE.
+
+--*/
+{
+ return _Data->Lsn;
+}
+
+#endif
diff --git a/private/utils/untfs/inc/indxroot.hxx b/private/utils/untfs/inc/indxroot.hxx
new file mode 100644
index 000000000..9c977f7c5
--- /dev/null
+++ b/private/utils/untfs/inc/indxroot.hxx
@@ -0,0 +1,366 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ indxroot.hxx
+
+Abstract:
+
+ this module contains the declarations for the NTFS_INDEX_ROOT
+ class, which models the root of an NTFS index
+
+Author:
+
+ Bill McJohn (billmc) 06-Sept-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if !defined( _NTFS_INDEX_ROOT_DEFN_ )
+
+#define _NTFS_INDEX_ROOT_DEFN_
+
+DECLARE_CLASS( NTFS_ATTRIBUTE );
+DECLARE_CLASS( NTFS_UPCASE_TABLE );
+
+// If the index buffer size is smaller than the cluster size, we'll
+// divide the index buffers into 512-byte blocks, and the ClustersPer-
+// IndexBuffer item will actually be blocks per index buffer.
+//
+
+const ULONG NTFS_INDEX_BLOCK_SIZE = 512;
+
+class NTFS_INDEX_ROOT : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( NTFS_INDEX_ROOT );
+
+ VIRTUAL
+ ~NTFS_INDEX_ROOT(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PNTFS_ATTRIBUTE RootAttribute,
+ IN PNTFS_UPCASE_TABLE UpcaseTable,
+ IN ULONG MaximumSize
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN ATTRIBUTE_TYPE_CODE IndexedAttributeType,
+ IN COLLATION_RULE CollationRule,
+ IN PNTFS_UPCASE_TABLE UpcaseTable,
+ IN ULONG ClustersPerBuffer,
+ IN ULONG BytesPerBuffer,
+ IN ULONG MaximumRootSize
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FindEntry(
+ IN PCINDEX_ENTRY SearchEntry,
+ IN OUT PULONG Ordinal,
+ OUT PINDEX_ENTRY* EntryFound
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ InsertEntry(
+ IN PCINDEX_ENTRY NewEntry,
+ IN PINDEX_ENTRY InsertPoint DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ VOID
+ RemoveEntry(
+ PINDEX_ENTRY EntryToRemove
+ );
+
+ NONVIRTUAL
+ PINDEX_ENTRY
+ GetFirstEntry(
+ );
+
+ NONVIRTUAL
+ VOID
+ Recreate(
+ IN BOOLEAN IsLeaf,
+ IN VCN EndEntryDownpointer
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Write(
+ PNTFS_ATTRIBUTE RootAttribute
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryClustersPerBuffer(
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryBufferSize(
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryIndexedAttributeType(
+ );
+
+ NONVIRTUAL
+ COLLATION_RULE
+ QueryCollationRule(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsLeaf(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsModified(
+ );
+
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ VOID
+ MarkModified(
+ );
+
+
+ ULONG _MaximumSize;
+ ULONG _DataLength;
+ PINDEX_ROOT _Data;
+ PNTFS_UPCASE_TABLE _UpcaseTable;
+
+ BOOLEAN _IsModified;
+
+};
+
+
+INLINE
+PINDEX_ENTRY
+NTFS_INDEX_ROOT::GetFirstEntry(
+ )
+/*++
+
+Routine Description:
+
+ This method returns a pointer to the first entry in the index root.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the first index entry in the root.
+
+--*/
+{
+ return( (PINDEX_ENTRY)( (PBYTE)&(_Data->IndexHeader) +
+ _Data->IndexHeader.FirstIndexEntry ) );
+}
+
+
+INLINE
+ULONG
+NTFS_INDEX_ROOT::QueryClustersPerBuffer(
+ )
+/*++
+
+Routine Description:
+
+ This method returns the number of clusters in each Index Allocation
+ Buffer in this index.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Clusters per Buffer.
+
+--*/
+{
+ return _Data->ClustersPerIndexBuffer;
+}
+
+
+INLINE
+ULONG
+NTFS_INDEX_ROOT::QueryBufferSize(
+ )
+/*++
+
+Routine Description:
+
+ This method returns the number of bytes in each Index Allocation
+ Buffer in this index.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Bytes per Buffer.
+
+--*/
+{
+ return _Data->BytesPerIndexBuffer;
+}
+
+
+
+INLINE
+ULONG
+NTFS_INDEX_ROOT::QueryIndexedAttributeType(
+ )
+/*++
+
+Routine Description:
+
+ This method returns the Attribute Type Code of the attribute
+ which is indexed by this index.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The attribute type code of the attributes in this index.
+
+--*/
+{
+ return _Data->IndexedAttributeType;
+}
+
+
+
+INLINE
+COLLATION_RULE
+NTFS_INDEX_ROOT::QueryCollationRule(
+ )
+/*++
+
+Routine Description:
+
+ This method marks the index root as modified.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ return _Data->CollationRule;
+}
+
+
+INLINE
+BOOLEAN
+NTFS_INDEX_ROOT::IsLeaf(
+ )
+/*++
+
+Routine Description:
+
+ This method determines whether the Index Root is a leaf (ie. that
+ the entries in the root do not have downpointers) or a node
+ (ie. the entries have downpointers).
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the root is a leaf; FALSE if it is a node.
+
+--*/
+{
+ return( !(_Data->IndexHeader.Flags & INDEX_NODE) );
+}
+
+
+INLINE
+BOOLEAN
+NTFS_INDEX_ROOT::IsModified(
+ )
+/*++
+
+Routine Description:
+
+ This method indicates whether the index root has been modified
+ since the last time it was read from or written to an $INDEX_ROOT
+ attribute.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the index root has been modified; FALSE otherwise.
+
+--*/
+{
+ return _IsModified;
+}
+
+
+INLINE
+VOID
+NTFS_INDEX_ROOT::MarkModified(
+ )
+/*++
+
+Routine Description:
+
+ This method marks the index root as modified.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _IsModified = TRUE;
+}
+
+#endif
diff --git a/private/utils/untfs/inc/indxtree.hxx b/private/utils/untfs/inc/indxtree.hxx
new file mode 100644
index 000000000..19ee5b275
--- /dev/null
+++ b/private/utils/untfs/inc/indxtree.hxx
@@ -0,0 +1,686 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ indxtree.hxx
+
+Abstract:
+
+ this module contains the declarations for the NTFS_INDEX_TREE
+ class, which models index trees on an NTFS volume.
+
+ An NTFS Index Tree consists of an index root and a set of
+ index buffers. The index root is stored as the value of
+ an INDEX_ROOT attribute; the index buffers are part of the
+ value of an INDEX_ALLOCATION attribute.
+
+Author:
+
+ Bill McJohn (billmc) 30-Aug-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if !defined( _NTFS_INDEX_TREE_DEFN_ )
+
+#define _NTFS_INDEX_TREE_DEFN_
+
+#include "hmem.hxx"
+#include "intstack.hxx"
+
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( WSTRING );
+DECLARE_CLASS( NTFS_ATTRIBUTE );
+DECLARE_CLASS( NTFS_BITMAP );
+DECLARE_CLASS( NTFS_INDEX_ROOT );
+DECLARE_CLASS( NTFS_INDEX_BUFFER );
+DECLARE_CLASS( NTFS_FILE_RECORD_SEGMENT );
+DECLARE_CLASS( NTFS_UPCASE_TABLE );
+
+// This constant is given to FindEntry to indicate it should skip
+// all matching entries.
+//
+CONST ULONG INDEX_SKIP = (ULONG)(-1);
+
+typedef enum INDEX_ITERATOR_STATE {
+
+ INDEX_ITERATOR_RESET,
+ INDEX_ITERATOR_CURRENT,
+ INDEX_ITERATOR_INVALID,
+ INDEX_ITERATOR_DELETED,
+ INDEX_ITERATOR_CORRUPT
+};
+
+
+LONG
+NtfsCollate(
+ IN PCVOID Value1,
+ IN ULONG Length1,
+ IN PCVOID Value2,
+ IN ULONG Length2,
+ IN COLLATION_RULE CollationRule,
+ IN PNTFS_UPCASE_TABLE UpcaseTable OPTIONAL
+ );
+
+LONG
+CompareNtfsIndexEntries(
+ IN PCINDEX_ENTRY Entry1,
+ IN PCINDEX_ENTRY Entry2,
+ IN COLLATION_RULE CollationRule,
+ IN PNTFS_UPCASE_TABLE UpcaseTable OPTIONAL
+ );
+
+
+class NTFS_INDEX_TREE : public OBJECT {
+
+ public:
+
+ UNTFS_EXPORT
+ DECLARE_CONSTRUCTOR( NTFS_INDEX_TREE );
+
+ VIRTUAL
+ UNTFS_EXPORT
+ ~NTFS_INDEX_TREE(
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Initialize(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN ULONG ClusterFactor,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN PNTFS_UPCASE_TABLE UpcaseTable,
+ IN ULONG MaximumRootSize,
+ IN PNTFS_FILE_RECORD_SEGMENT SourceFrs,
+ IN PCWSTRING IndexName DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Initialize(
+ IN ATTRIBUTE_TYPE_CODE IndexedAttributeType,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN ULONG ClusterFactor,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN PNTFS_UPCASE_TABLE UpcaseTable,
+ IN COLLATION_RULE CollationRule,
+ IN ULONG IndexBufferSize,
+ IN ULONG MaximumRootSize,
+ IN PCWSTRING IndexName DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ QueryFileReference(
+ IN ULONG KeyLength,
+ IN PVOID Key,
+ IN ULONG Ordinal,
+ OUT PMFT_SEGMENT_REFERENCE SegmentReference,
+ OUT PBOOLEAN Error
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ QueryEntry(
+ IN ULONG KeyLength,
+ IN PVOID Key,
+ IN ULONG Ordinal,
+ OUT PINDEX_ENTRY* FoundEntry,
+ OUT PNTFS_INDEX_BUFFER* ContainingBuffer,
+ OUT PBOOLEAN Error
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ InsertEntry(
+ IN ULONG KeyLength,
+ IN PVOID KeyValue,
+ IN MFT_SEGMENT_REFERENCE FileReference,
+ IN BOOLEAN NoDuplicates DEFAULT TRUE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ InsertEntry(
+ IN PCINDEX_ENTRY NewEntry,
+ IN BOOLEAN NoDuplicates DEFAULT TRUE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DeleteEntry(
+ IN ULONG KeyLength,
+ IN PVOID Key,
+ IN ULONG Ordinal
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Save(
+ IN OUT PNTFS_FILE_RECORD_SEGMENT TargetFrs
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsBadlyOrdered(
+ OUT PBOOLEAN Error,
+ IN BOOLEAN DuplicatesAllowed
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Sort(
+ IN OUT PNTFS_FILE_RECORD_SEGMENT TargetFrs
+ );
+
+ NONVIRTUAL
+ ATTRIBUTE_TYPE_CODE
+ QueryTypeCode(
+ ) CONST;
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ VOID
+ ResetIterator(
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ PCINDEX_ENTRY
+ GetNext(
+ OUT PULONG Depth,
+ OUT PBOOLEAN Error,
+ IN BOOLEAN FilterEndEntries DEFAULT TRUE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DeleteCurrentEntry(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ WriteCurrentEntry(
+ );
+
+ NONVIRTUAL
+ COLLATION_RULE
+ QueryCollationRule(
+ );
+
+ NONVIRTUAL
+ ATTRIBUTE_TYPE_CODE
+ QueryIndexedAttributeType(
+ );
+
+ NONVIRTUAL
+ UCHAR
+ QueryClustersPerBuffer(
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryBufferSize(
+ );
+
+ NONVIRTUAL
+ VOID
+ FreeAllocation(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ UpdateFileName(
+ IN PCFILE_NAME Name,
+ IN FILE_REFERENCE ContainingFile
+ );
+
+ NONVIRTUAL
+ PCWSTRING
+ GetName(
+ ) CONST;
+
+ STATIC
+ BOOLEAN
+ IsIndexEntryCorrupt(
+ IN PCINDEX_ENTRY IndexEntry,
+ IN ULONG MaximumLength
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ResetLsns(
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FindHighestLsn(
+ IN OUT PMESSAGE Message,
+ OUT PLSN HighestLsn
+ ) CONST;
+
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FindEntry(
+ IN ULONG KeyLength,
+ IN PVOID KeyValue,
+ IN ULONG Ordinal,
+ OUT PINDEX_ENTRY* FoundEntry,
+ OUT PNTFS_INDEX_BUFFER* ContainingBuffer,
+ OUT PINTSTACK ParentTrail
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ RemoveEntry(
+ IN PINDEX_ENTRY EntryToRemove,
+ IN PNTFS_INDEX_BUFFER ContainingBuffer,
+ IN PINTSTACK ParentTrail
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryReplacementEntry(
+ IN PINDEX_ENTRY Successor,
+ OUT PINDEX_ENTRY ReplacementEntry,
+ OUT PBOOLEAN Error,
+ OUT PBOOLEAN EmptyLeaf,
+ OUT PVCN EmptyLeafVcn
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FixupEmptyLeaf(
+ IN VCN EmptyLeafVcn
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FindBuffer(
+ IN VCN BufferVcn,
+ IN PNTFS_INDEX_BUFFER ParentBuffer,
+ OUT PNTFS_INDEX_BUFFER FoundBuffer,
+ IN OUT PINTSTACK ParentTrail,
+ OUT PBOOLEAN Error
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ InsertIntoRoot(
+ IN PCINDEX_ENTRY NewEntry,
+ IN PINDEX_ENTRY InsertionPoint DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ InsertIntoBuffer(
+ IN OUT PNTFS_INDEX_BUFFER TargetBuffer,
+ IN OUT PINTSTACK ParentTrail,
+ IN PCINDEX_ENTRY NewEntry,
+ IN PINDEX_ENTRY InsertionPoint DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ WriteIndexBuffer(
+ IN VCN BufferVcn,
+ OUT PVOID Data
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AllocateIndexBuffer(
+ OUT PVCN NewBufferVcn
+ );
+
+ NONVIRTUAL
+ VOID
+ FreeIndexBuffer(
+ IN VCN BufferVcn
+ );
+
+ NONVIRTUAL
+ VOID
+ FreeChildren(
+ IN PINDEX_ENTRY IndexEntry
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryMaximumEntrySize(
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ CreateAllocationAttribute(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ InvalidateIterator(
+ );
+
+ NONVIRTUAL
+ PCINDEX_ENTRY
+ GetNextUnfiltered(
+ OUT PULONG Depth,
+ OUT PBOOLEAN Error
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ GetNextLeafEntry(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ GetNextParent(
+ );
+
+ NONVIRTUAL
+ VOID
+ UpdateOrdinal(
+ );
+
+ NONVIRTUAL
+ VOID
+ SaveCurrentKey(
+ );
+
+ ULONG
+ QueryCurrentEntryDepth(
+ );
+
+
+ PLOG_IO_DP_DRIVE _Drive;
+ ULONG _ClusterFactor;
+ ULONG _ClustersPerBuffer;
+ ULONG _BufferSize;
+ PNTFS_BITMAP _VolumeBitmap;
+ PNTFS_ATTRIBUTE _AllocationAttribute;
+ PNTFS_INDEX_ROOT _IndexRoot;
+ PNTFS_BITMAP _IndexAllocationBitmap;
+
+ PWSTRING _Name;
+ ATTRIBUTE_TYPE_CODE _IndexedAttributeType;
+ COLLATION_RULE _CollationRule;
+
+ PNTFS_UPCASE_TABLE _UpcaseTable;
+
+
+ // Iterator state information:
+ //
+ // Each index tree has a single iterator associated with it.
+ // This iterator oscillates among the following states:
+ //
+ // INDEX_ITERATOR_RESET -- the iterator is at the beginning
+ // of the index, and the next call
+ // to GetNext will return the first
+ // entry in the index.
+ // INDEX_ITERATOR_CURRENT -- _CurrentEntry points at the current
+ // entry. _IsCurrentEntryInRoot is
+ // TRUE if that entry is in the index
+ // root, otherwise _CurrentEntryBuffer
+ // points to the buffer that contains
+ // the entry, and _CurrentEntryTrail
+ // contains the parent trail of that
+ // buffer. In either case,
+ // _CurrentKeyOrdinal gives the
+ // ordinal of the current entry
+ // (ie. it is the nth entry for
+ // the current key).
+ // INDEX_ITERATOR_INVALID -- _CurrentEntry has been invalidated,
+ // and the tree must relocate the
+ // current entry. _CurrentKey,
+ // _CurrentKeyLength, and
+ // _CurrentKeyOrdinal give the entry
+ // information to locate the current
+ // entry.
+ // INDEX_ITERATOR_DELETED -- Differs from INDEX_ITERATOR_INVALID
+ // only in that _CurrentKey,
+ // _CurrentKeyLength, and
+ // _CurrentKeyOrdinal describe the
+ // next entry, rather than the current.
+ // INDEX_ITERATOR_CORRUPT -- The iterator (or the tree itself)
+ // has become corrupt; any attempt to
+ // use it will return error.
+ //
+ // Since the iterator is very closely coupled to the index
+ // tree, it is built into this class, rather than being maintained
+ // as a separate object.
+
+ INDEX_ITERATOR_STATE _IteratorState;
+
+ BOOLEAN _IsCurrentEntryInRoot;
+ PINDEX_ENTRY _CurrentEntry;
+ PNTFS_INDEX_BUFFER _CurrentBuffer;
+ INTSTACK _CurrentEntryTrail;
+
+ ULONG _CurrentKeyOrdinal;
+ PVOID _CurrentKey;
+ ULONG _CurrentKeyLength;
+ ULONG _CurrentKeyMaxLength;
+
+};
+
+
+INLINE
+ATTRIBUTE_TYPE_CODE
+NTFS_INDEX_TREE::QueryTypeCode(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the attribute type code over which this index
+ acts.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The attribute type code for this index.
+--*/
+{
+ return _IndexedAttributeType;
+}
+
+
+
+INLINE
+NONVIRTUAL
+COLLATION_RULE
+NTFS_INDEX_TREE::QueryCollationRule(
+ )
+/*++
+
+Routine Description:
+
+ This method returns the collation rule by which this
+ index tree is ordered.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The index tree's collation rule.
+
+--*/
+{
+ return _CollationRule;
+}
+
+
+INLINE
+NONVIRTUAL
+ATTRIBUTE_TYPE_CODE
+NTFS_INDEX_TREE::QueryIndexedAttributeType(
+ )
+/*++
+
+Routine Description:
+
+ This method returns the type code of the attribute which is
+ indexed by this index tree.
+
+Arguments:
+
+ None.
+
+Return Value:
+--*/
+{
+ return _IndexedAttributeType;
+}
+
+
+INLINE
+NONVIRTUAL
+UCHAR
+NTFS_INDEX_TREE::QueryClustersPerBuffer(
+ )
+/*++
+
+Routine Description:
+
+ This method returns the number of clusters in each allocation
+ buffer in this index tree.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of clusters per allocation buffer in this tree.
+
+--*/
+{
+ return (UCHAR)_ClustersPerBuffer;
+}
+
+INLINE
+NONVIRTUAL
+ULONG
+NTFS_INDEX_TREE::QueryBufferSize(
+ )
+/*++
+
+Routine Description:
+
+ This method returns the size of each allocation
+ buffer in this index tree.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of bytes per allocation buffer in this tree.
+
+--*/
+{
+ return _BufferSize;
+}
+
+
+
+INLINE
+ULONG
+NTFS_INDEX_TREE::QueryCurrentEntryDepth(
+ )
+/*++
+
+Routine Description:
+
+ This method returns the depth in the tree of _CurrentEntry.
+ (Root is zero.)
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Depth.
+
+Notes:
+
+ This method should only be called if _IteratorState
+ is INDEX_ITERATOR_CURRENT.
+
+--*/
+{
+ ULONG Result;
+
+ if( _IteratorState == INDEX_ITERATOR_CURRENT ) {
+
+ Result = _IsCurrentEntryInRoot ?
+ 0 :
+ ( _CurrentEntryTrail.QuerySize() + 1 );
+
+ } else {
+
+ DebugAbort( "Tried to determine depth of invalid iterator.\n" );
+ Result = 0;
+ }
+
+ return Result;
+}
+
+
+INLINE
+PCWSTRING
+NTFS_INDEX_TREE::GetName(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the name of the index.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The name of the index.
+
+--*/
+{
+ return _Name;
+}
+
+
+#endif
diff --git a/private/utils/untfs/inc/logfile.hxx b/private/utils/untfs/inc/logfile.hxx
new file mode 100644
index 000000000..9db326a7c
--- /dev/null
+++ b/private/utils/untfs/inc/logfile.hxx
@@ -0,0 +1,160 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ logfile.hxx
+
+Abstract:
+
+ This module contains the declarations for the NTFS_LOG_FILE
+ class, which models the log file for an NTFS volume.
+
+ The utilities do not pretend to understand the contents of the
+ log file. They only create it and set its signature.
+
+Author:
+
+ Bill McJohn (billmc) 05-May-1992
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+#if !defined( NTFS_LOG_FILE_DEFN )
+
+#define NTFS_LOG_FILE_DEFN
+
+#include "frs.hxx"
+#include "drive.hxx"
+
+typedef enum LOG_FILE_SIGNATURE_CODE {
+
+ LogFileSignatureCreated,
+ LogFileSignatureChecked
+};
+
+// Note that LogFileFillCharacter matches LOG_FILE_SIGNATURE_CREATED;
+// this relationship must be maintained.
+
+#define LogFileFillCharacter (CHAR)0xFF
+
+CONST ULONG LogFileSignatureLength = 4;
+#define LOG_FILE_SIGNATURE_CREATED "\xFF\xFF\xFF\xFF"
+#define LOG_FILE_SIGNATURE_CHECKED "CHKD"
+
+class NTFS_LOG_FILE : public NTFS_FILE_RECORD_SEGMENT {
+
+ public:
+
+ UNTFS_EXPORT
+ DECLARE_CONSTRUCTOR( NTFS_LOG_FILE );
+
+ VIRTUAL
+ UNTFS_EXPORT
+ ~NTFS_LOG_FILE(
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Initialize(
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Create(
+ IN PCSTANDARD_INFORMATION StandardInformation,
+ IN ULONG InitialSize OPTIONAL,
+ IN OUT PNTFS_BITMAP VolumeBitmap
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ CreateDataAttribute(
+ IN ULONG InitialSize OPTIONAL,
+ IN OUT PNTFS_BITMAP VolumeBitmap
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ MarkVolumeChecked(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ MarkVolumeChecked(
+ BOOLEAN WriteSecondPage,
+ LSN GreatestLsn
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Reset(
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Resize(
+ IN BIG_INT NewSize,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN BOOLEAN GetWhatYouCan,
+ OUT PBOOLEAN Changed,
+ OUT PBOOLEAN LogFileGrew,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ VerifyAndFix(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNTFS_INDEX_TREE RootIndex,
+ IN OUT PNTFS_CHKDSK_REPORT ChkdskReport,
+ IN FIX_LEVEL FixLevel,
+ IN BOOLEAN Resize,
+ IN ULONG LogFileSize,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ EnsureCleanShutdown(
+ );
+
+ STATIC
+ ULONG
+ QueryDefaultSize(
+ IN PCDP_DRIVE Drive,
+ IN BIG_INT VolumeSectors
+ );
+
+ STATIC
+ ULONG
+ QueryMinimumSize(
+ IN PCDP_DRIVE Drive,
+ IN BIG_INT VolumeSectors
+ );
+
+ STATIC
+ ULONG
+ QueryMaximumSize(
+ IN PCDP_DRIVE Drive,
+ IN BIG_INT VolumeSectors
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+
+};
+
+#endif
diff --git a/private/utils/untfs/inc/mft.hxx b/private/utils/untfs/inc/mft.hxx
new file mode 100644
index 000000000..4e9b67a1c
--- /dev/null
+++ b/private/utils/untfs/inc/mft.hxx
@@ -0,0 +1,487 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ mft.hxx
+
+Abstract:
+
+ This module contains the declarations for the NTFS_MASTER_FILE_TABLE
+ class. The MFT is the root of the file system
+
+Author:
+
+ Bill McJohn (billmc) 13-June-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if !defined( _NTFS_MASTER_FILE_TABLE_DEFN_ )
+
+#define _NTFS_MASTER_FILE_TABLE_DEFN_
+
+#include "ntfsbit.hxx"
+
+DECLARE_CLASS( NTFS_ATTRIBUTE );
+DECLARE_CLASS( NTFS_UPCASE_TABLE );
+
+class NTFS_MASTER_FILE_TABLE : public OBJECT {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( NTFS_MASTER_FILE_TABLE );
+
+ VIRTUAL
+ ~NTFS_MASTER_FILE_TABLE(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN OUT PNTFS_ATTRIBUTE DataAttribute,
+ IN OUT PNTFS_BITMAP MftBitmap,
+ IN OUT PNTFS_BITMAP VolumeBitmap OPTIONAL,
+ IN PNTFS_UPCASE_TABLE UpcaseTable OPTIONAL,
+ IN ULONG ClusterFactor,
+ IN ULONG FrsSize,
+ IN ULONG SectorSize,
+ IN BIG_INT VolumeSectors,
+ IN BOOLEAN ReadOnly DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ AllocateFileRecordSegment(
+ OUT PVCN FileNumber,
+ IN BOOLEAN IsMft
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FreeFileRecordSegment(
+ IN VCN SegmentToFree
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Extend(
+ IN ULONG NumberOfSegmentsToAdd
+ );
+
+ NONVIRTUAL
+ PNTFS_ATTRIBUTE
+ GetDataAttribute(
+ );
+
+ NONVIRTUAL
+ PNTFS_BITMAP
+ GetMftBitmap(
+ );
+
+ NONVIRTUAL
+ PNTFS_BITMAP
+ GetVolumeBitmap(
+ );
+
+ NONVIRTUAL
+ VOID
+ EnableMethods(
+ );
+
+ NONVIRTUAL
+ VOID
+ DisableMethods(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AreMethodsEnabled(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QueryClusterFactor(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QueryFrsSize(
+ ) CONST;
+
+ NONVIRTUAL
+ BIG_INT
+ QueryVolumeSectors(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ QuerySectorSize(
+ ) CONST;
+
+ NONVIRTUAL
+ PNTFS_UPCASE_TABLE
+ GetUpcaseTable(
+ );
+
+ NONVIRTUAL
+ VOID
+ SetUpcaseTable(
+ IN PNTFS_UPCASE_TABLE UpcaseTable
+ );
+
+ NONVIRTUAL
+ BIG_INT
+ QueryFrsCount(
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ PNTFS_ATTRIBUTE _DataAttribute;
+ PNTFS_BITMAP _MftBitmap;
+ PNTFS_BITMAP _VolumeBitmap;
+ PNTFS_UPCASE_TABLE _UpcaseTable;
+ ULONG _ClusterFactor;
+ ULONG _BytesPerFrs;
+ BOOLEAN _MethodsEnabled;
+ BOOLEAN _ReadOnly;
+ BIG_INT _VolumeSectors;
+ ULONG _SectorSize;
+
+};
+
+
+INLINE
+BOOLEAN
+NTFS_MASTER_FILE_TABLE::FreeFileRecordSegment(
+ IN VCN SegmentToFree
+ )
+/*++
+
+Routine Description:
+
+ Free a File Record Segment in the Master File Table.
+
+Arguments:
+
+ SegmentToFree -- supplies the virtual cluster number withing
+ the Master File Table of the segment to be
+ freed.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ DebugAssert(_MftBitmap);
+
+ return _MethodsEnabled ?
+ (_MftBitmap->SetFree(SegmentToFree, 1), TRUE) : FALSE;
+}
+
+
+INLINE
+PNTFS_ATTRIBUTE
+NTFS_MASTER_FILE_TABLE::GetDataAttribute(
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the MFT's $DATA attribute.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The data attribute for this class.
+
+--*/
+{
+ return _MethodsEnabled ? _DataAttribute : NULL;
+}
+
+
+INLINE
+PNTFS_BITMAP
+NTFS_MASTER_FILE_TABLE::GetMftBitmap(
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the MFT's $BITMAP attribute.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The mft bitmap.
+
+--*/
+{
+ return _MethodsEnabled ? _MftBitmap : NULL;
+}
+
+
+INLINE
+PNTFS_BITMAP
+NTFS_MASTER_FILE_TABLE::GetVolumeBitmap(
+ )
+/*++
+
+Routine Description:
+
+ This routine return the volume bitmap
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The volume bitmap.
+
+--*/
+{
+ return _MethodsEnabled ? _VolumeBitmap : NULL;
+}
+
+
+INLINE
+VOID
+NTFS_MASTER_FILE_TABLE::EnableMethods(
+ )
+/*++
+
+Routine Description:
+
+ This method enables the methods provided by this class.
+
+ This method and its complement allow the user of this class to declare
+ when the passed in data attribute and mft bitmap are good enough to
+ use.
+
+ After the class is initialized, all of the methods are enabled.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _MethodsEnabled = TRUE;
+}
+
+
+INLINE
+VOID
+NTFS_MASTER_FILE_TABLE::DisableMethods(
+ )
+/*++
+
+Routine Description:
+
+ This method disables the methods provided by this class.
+
+ This method and its complement allow the user of this class to declare
+ when the passed in data attribute and mft bitmap are good enough to
+ use.
+
+ After the class is initialized, all of the methods are enabled.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _MethodsEnabled = FALSE;
+}
+
+
+INLINE
+BOOLEAN
+NTFS_MASTER_FILE_TABLE::AreMethodsEnabled(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method computes whether or not the methods are enabled.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - The methods are not enabled.
+ TRUE - The methods are enabled.
+
+--*/
+{
+ return _MethodsEnabled;
+}
+
+
+INLINE
+ULONG
+NTFS_MASTER_FILE_TABLE::QueryClusterFactor(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of sectors per cluster.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of sectors per cluster.
+
+--*/
+{
+ return _ClusterFactor;
+}
+
+
+INLINE
+BIG_INT
+NTFS_MASTER_FILE_TABLE::QueryVolumeSectors(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the number of sectors on the volume as recorded in
+ the boot sector.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of volume sectors.
+
+--*/
+{
+ return _VolumeSectors;
+}
+
+
+INLINE
+ULONG
+NTFS_MASTER_FILE_TABLE::QueryFrsSize(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of clusters per FRS.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of clusters per FRS.
+
+--*/
+{
+ return _BytesPerFrs;
+}
+
+
+INLINE
+PNTFS_UPCASE_TABLE
+NTFS_MASTER_FILE_TABLE::GetUpcaseTable(
+ )
+/*++
+
+Routine Description:
+
+ This method fetches the upcase table for the volume.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The volume upcase table.
+
+--*/
+{
+ return _UpcaseTable;
+}
+
+
+INLINE
+VOID
+NTFS_MASTER_FILE_TABLE::SetUpcaseTable(
+ IN PNTFS_UPCASE_TABLE UpcaseTable
+ )
+/*++
+
+Routine Description:
+
+ This method sets the upcase table for the volume.
+
+Arguments:
+
+ UpcaseTable -- Supplies the volume upcase table.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _UpcaseTable = UpcaseTable;
+}
+
+INLINE
+ULONG
+NTFS_MASTER_FILE_TABLE::QuerySectorSize(
+ ) CONST
+{
+ return _SectorSize;
+}
+
+
+#endif
diff --git a/private/utils/untfs/inc/mftfile.hxx b/private/utils/untfs/inc/mftfile.hxx
new file mode 100644
index 000000000..c2fd8bf1d
--- /dev/null
+++ b/private/utils/untfs/inc/mftfile.hxx
@@ -0,0 +1,265 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ mftfile.hxx
+
+Abstract:
+
+ This module contains the declarations for the NTFS_MFT_FILE
+ class. The MFT is the root of the file system
+
+Author:
+
+ Bill McJohn (billmc) 13-June-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if !defined( _NTFS_MFT_FILE_DEFN_ )
+
+#define _NTFS_MFT_FILE_DEFN_
+
+#include "hmem.hxx"
+
+#include "bitfrs.hxx"
+#include "clusrun.hxx"
+#include "frs.hxx"
+#include "attrib.hxx"
+#include "ntfsbit.hxx"
+#include "mft.hxx"
+#include "mftref.hxx"
+
+DECLARE_CLASS( NTFS_MFT_FILE );
+
+
+class NTFS_MFT_FILE : public NTFS_FILE_RECORD_SEGMENT {
+
+ public:
+
+ UNTFS_EXPORT
+ DECLARE_CONSTRUCTOR( NTFS_MFT_FILE );
+
+ VIRTUAL
+ UNTFS_EXPORT
+ ~NTFS_MFT_FILE(
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Initialize(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN LCN Lcn,
+ IN ULONG ClusterFactor,
+ IN ULONG FrsSize,
+ IN BIG_INT VolumeSectors,
+ IN OUT PNTFS_BITMAP VolumeBitmap OPTIONAL,
+ IN PNTFS_UPCASE_TABLE UpcaseTable OPTIONAL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Create(
+ IN ULONG InitialSize,
+ IN PCSTANDARD_INFORMATION StandardInformation,
+ IN OUT PNTFS_BITMAP VolumeBitmap
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Read(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AllocateFileRecordSegment(
+ OUT PVCN FileNumber,
+ IN BOOLEAN IsMft
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FreeFileRecordSegment(
+ IN VCN SegmentToFree
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Extend(
+ IN ULONG NumberOfSegmentsToAdd
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Flush(
+ );
+
+ NONVIRTUAL
+ PNTFS_MASTER_FILE_TABLE
+ GetMasterFileTable(
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetUpMft(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CheckMirrorSize(
+ IN OUT PNTFS_ATTRIBUTE MirrorDataAttribute,
+ IN BOOLEAN Fix,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ OUT PLCN FirstLcn
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ WriteMirror(
+ IN OUT PNTFS_ATTRIBUTE MirrorDataAttribute
+ );
+
+
+
+ LCN _FirstLcn;
+ NTFS_ATTRIBUTE _DataAttribute;
+ NTFS_BITMAP _MftBitmap;
+ NTFS_MASTER_FILE_TABLE _Mft;
+ PNTFS_BITMAP _VolumeBitmap;
+
+ HMEM _MirrorMem;
+ NTFS_CLUSTER_RUN _MirrorClusterRun;
+
+};
+
+
+INLINE
+BOOLEAN
+NTFS_MFT_FILE::AllocateFileRecordSegment(
+ OUT PVCN FileNumber,
+ IN BOOLEAN IsMft
+
+ )
+/*++
+
+Routine Description:
+
+ Allocate a File Record Segment from the Master File Table.
+
+Arguments:
+
+ FileNumber -- receives the file number of the allocated segment.
+ IsMft -- supplies a flag which indicates, if TRUE, that
+ the allocation is being made on behalf of the
+ MFT itself.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ return _Mft.AllocateFileRecordSegment(FileNumber, IsMft);
+}
+
+
+INLINE
+BOOLEAN
+NTFS_MFT_FILE::FreeFileRecordSegment(
+ IN VCN SegmentToFree
+ )
+/*++
+
+Routine Description:
+
+ Free a File Record Segment in the Master File Table.
+
+Arguments:
+
+ SegmentToFree -- supplies the virtual cluster number withing
+ the Master File Table of the segment to be
+ freed.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ return _Mft.FreeFileRecordSegment(SegmentToFree);
+}
+
+
+INLINE
+BOOLEAN
+NTFS_MFT_FILE::Extend(
+ IN ULONG NumberOfSegmentsToAdd
+ )
+/*++
+
+Routine Description:
+
+ This method grows the Master File Table. It increases the
+ size of the Data attribute (to hold more File Record Segments)
+ and increases the size of the MFT Bitmap to match.
+
+Arguments:
+
+ NumberOfSegmentsToAdd -- supplies the number of new File Record
+ Segments to add to the Master File Table.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ return _Mft.Extend(NumberOfSegmentsToAdd);
+}
+
+
+INLINE
+PNTFS_MASTER_FILE_TABLE
+NTFS_MFT_FILE::GetMasterFileTable(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to master file table.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the master file table.
+
+--*/
+{
+ return _Mft.AreMethodsEnabled() ? &_Mft : NULL;
+}
+
+
+#endif
diff --git a/private/utils/untfs/inc/mftref.hxx b/private/utils/untfs/inc/mftref.hxx
new file mode 100644
index 000000000..75901858e
--- /dev/null
+++ b/private/utils/untfs/inc/mftref.hxx
@@ -0,0 +1,90 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ mftref.hxx
+
+Abstract:
+
+ This module contains the declarations for the
+ NTFS_REFLECTED_MASTER_FILE_TABLE class. This
+ class models the backup copy of the Master File
+ Table.
+
+Author:
+
+ Bill McJohn (billmc) 13-June-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if !defined( _NTFS_REFLECTED_MASTER_FILE_TABLE_DEFN_ )
+
+#define _NTFS_REFLECTED_MASTER_FILE_TABLE_DEFN_
+
+#include "frs.hxx"
+
+DECLARE_CLASS( NTFS_MASTER_FILE_TABLE );
+
+class NTFS_REFLECTED_MASTER_FILE_TABLE : public NTFS_FILE_RECORD_SEGMENT {
+
+ public:
+
+ UNTFS_EXPORT
+ DECLARE_CONSTRUCTOR( NTFS_REFLECTED_MASTER_FILE_TABLE );
+
+ VIRTUAL
+ UNTFS_EXPORT
+ ~NTFS_REFLECTED_MASTER_FILE_TABLE(
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Initialize(
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Create(
+ IN PCSTANDARD_INFORMATION StandardInformation,
+ IN OUT PNTFS_BITMAP VolumeBitmap
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ VerifyAndFix(
+ IN PNTFS_ATTRIBUTE MftData,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNUMBER_SET BadClusters,
+ IN OUT PNTFS_INDEX_TREE RootIndex,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ LCN
+ QueryFirstLcn(
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+};
+
+#endif
diff --git a/private/utils/untfs/inc/ntfsbit.hxx b/private/utils/untfs/inc/ntfsbit.hxx
new file mode 100644
index 000000000..adabb3e9f
--- /dev/null
+++ b/private/utils/untfs/inc/ntfsbit.hxx
@@ -0,0 +1,549 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ntfsbit.hxx
+
+Abstract:
+
+ This module contains the declarations for NTFS_BITMAP,
+ which models the bitmaps on an NTFS volume. There are three
+ kinds of bitmaps on an NTFS volume:
+
+ (1) The Volume Bitmap, which is stored as the nameless $DATA
+ attribute of the bitmap file. This bitmap has one bit for
+ each cluster on the disk, and is of fixed size. It is unique.
+
+ (2) The MFT Bitmap, which is stored as the value of the nameless
+ $BITMAP attribute of the Master File Table File. It has one
+ bit per File Record Segment in the Master File Table, and grows
+ with the Master File Table. It is unique.
+
+ (3) Index Allocation bitmaps. An index allocation bitmap is stored
+ as the value of a $BITMAP attribute in a File Record Segment
+ that has an $INDEX_ALLOCATION attribute. The name of the $BITMAP
+ attribute agrees with the associated $INDEX_ALLOCATION attribute.
+ This bitmap has one bit for each index allocation buffer in the
+ associated $INDEX_ALLOCATION attribute, and grows with that
+ attribute.
+
+ In every case, a set bit indicates that the associated allocation
+ unit (cluster, File Record Segment, or Index Allocation Buffer) is
+ allocated; a reset bit indicates that it is free.
+
+ The size of a bitmap (in bytes) is always quad-word aligned; bytes
+ are added at the end of the bitmap to pad it to the correct size.
+ If the bitmap is of fixed size, then all bits in the padding are
+ set (allocated); if it is growable, the bits of the padding are
+ reset (free).
+
+
+Author:
+
+ Bill McJohn (billmc) 17-June-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if !defined( _NTFS_BITMAP_DEFN_ )
+
+#define _NTFS_BITMAP_DEFN_
+
+#include "bitvect.hxx"
+#include "attrib.hxx"
+
+DECLARE_CLASS( NTFS_ATTRIBUTE );
+DECLARE_CLASS( NTFS_BITMAP );
+DECLARE_CLASS( NTFS_MASTER_FILE_TABLE );
+
+class NTFS_BITMAP : public OBJECT {
+
+ public:
+
+ UNTFS_EXPORT
+ DECLARE_CONSTRUCTOR( NTFS_BITMAP );
+
+ VIRTUAL
+ UNTFS_EXPORT
+ ~NTFS_BITMAP(
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Initialize(
+ IN BIG_INT NumberOfClusters,
+ IN BOOLEAN IsGrowable,
+ IN PLOG_IO_DP_DRIVE Drive DEFAULT NULL,
+ IN ULONG ClusterFactor DEFAULT 0
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Create(
+ );
+
+ NONVIRTUAL
+ BIG_INT
+ QuerySize(
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetFree(
+ IN LCN Lcn,
+ IN BIG_INT NumberOfClusters
+ );
+
+ NONVIRTUAL
+ VOID
+ SetAllocated(
+ IN LCN Lcn,
+ IN BIG_INT NumberOfClusters
+ );
+
+ NONVIRTUAL
+ BIG_INT
+ QueryFreeClusters(
+ ) CONST;
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ IsFree(
+ IN LCN Lcn,
+ IN BIG_INT RunLength
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ IsInRange(
+ IN LCN Lcn,
+ IN BIG_INT RunLength
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ AllocateClusters(
+ IN LCN NearHere OPTIONAL,
+ IN BIG_INT NumberOfClusters,
+ OUT PLCN FirstAllocatedLcn,
+ IN ULONG AlignmentFactor DEFAULT 1
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Read(
+ IN OUT PNTFS_ATTRIBUTE BitmapAttribute
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Write(
+ IN OUT PNTFS_ATTRIBUTE BitmapAttribute,
+ IN OUT PNTFS_BITMAP VolumeBitmap OPTIONAL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CheckAttributeSize(
+ IN OUT PNTFS_ATTRIBUTE BitmapAttribute,
+ IN OUT PNTFS_BITMAP VolumeBitmap
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Resize(
+ IN BIG_INT NumberOfClusters
+ );
+
+ NONVIRTUAL
+ PCVOID
+ GetBitmapData(
+ OUT PULONG SizeInBytes
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetMftPointer(
+ IN PNTFS_MASTER_FILE_TABLE Mft
+ );
+
+ NONVIRTUAL
+ VOID
+ SetGrowable(
+ IN BOOLEAN Growable
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ BIG_INT _NumberOfClusters;
+ BOOLEAN _IsGrowable;
+
+ ULONG _BitmapSize;
+ PVOID _BitmapData;
+ BIG_INT _NextAlloc;
+ BITVECTOR _Bitmap;
+
+ //
+ // This is to support testing newly-allocated clusters in the
+ // volume bitmap to ensure they can support IO.
+ //
+
+ PLOG_IO_DP_DRIVE _Drive;
+ ULONG _ClusterFactor;
+ PNTFS_MASTER_FILE_TABLE _Mft;
+};
+
+
+INLINE
+BIG_INT
+NTFS_BITMAP::QuerySize(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the number of clusters covered by this bitmap.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of clusters covered by this bitmap.
+
+--*/
+{
+ return _NumberOfClusters;
+}
+
+
+
+INLINE
+VOID
+NTFS_BITMAP::SetFree(
+ IN LCN Lcn,
+ IN BIG_INT RunLength
+ )
+/*++
+
+Routine Description:
+
+ This method marks a run of clusters as free in the bitmap.
+
+Arguments:
+
+ Lcn -- supplies the LCN of the first cluster in the run
+ RunLength -- supplies the length of the run
+
+Return Value:
+
+ None.
+
+Notes:
+
+ This method performs range checking.
+
+--*/
+{
+ // Since the high part of _NumberOfClusters is zero, if
+ // Lcn and RunLength pass the range-checking, their high
+ // parts must also be zero.
+
+ if( !(Lcn < 0) &&
+ !(RunLength < 0 ) &&
+ !(Lcn + RunLength > _NumberOfClusters) ) {
+
+ _Bitmap.ResetBit( Lcn.GetLowPart(), RunLength.GetLowPart() ) ;
+ }
+}
+
+
+
+INLINE
+VOID
+NTFS_BITMAP::SetAllocated(
+ IN LCN Lcn,
+ IN BIG_INT RunLength
+ )
+/*++
+
+Routine Description:
+
+ This method marks a run of clusters as used in the bitmap.
+
+Arguments:
+
+ Lcn -- supplies the LCN of the first cluster in the run
+ RunLength -- supplies the length of the run
+
+Return Value:
+
+ None.
+
+Notes:
+
+ This method performs range checking.
+
+--*/
+{
+ // Since the high part of _NumberOfClusters is zero, if
+ // Lcn and RunLength pass the range-checking, their high
+ // parts must also be zero.
+
+ if( !(Lcn < 0) &&
+ !(Lcn + RunLength > _NumberOfClusters) ) {
+
+ _Bitmap.SetBit( Lcn.GetLowPart(), RunLength.GetLowPart() );
+ }
+}
+
+
+INLINE
+BIG_INT
+NTFS_BITMAP::QueryFreeClusters(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the number of free clusters in the bitmap.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of free clusters in the bitmap.
+
+--*/
+{
+ BIG_INT result;
+
+ if( _IsGrowable ) {
+
+ // The bits in the padding are marked as free (ie. are
+ // not set). Thus, we can just count the number of set
+ // bits and subtract that from the number of clusters.
+ //
+ result = _NumberOfClusters - ((PNTFS_BITMAP) this)->_Bitmap.QueryCountSet();
+
+ } else {
+
+ // The bits in the padding are marked as in-use (ie.
+ // are set), so we need to compensate for them when
+ // we count the number of bits that are set.
+ //
+ result = _BitmapSize*8 - ((PNTFS_BITMAP) this)->_Bitmap.QueryCountSet();
+ }
+
+ return result;
+}
+
+
+INLINE
+BOOLEAN
+NTFS_BITMAP::Create(
+ )
+/*++
+
+Routine Description:
+
+ This method sets up an NTFS_BITMAP object in memory. Note that
+ it does not write the bitmap to disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ The newly-created bitmap begins with all clusters marked as FREE.
+
+--*/
+{
+ SetFree( 0, _NumberOfClusters );
+ return TRUE;
+}
+
+
+INLINE
+BOOLEAN
+NTFS_BITMAP::IsInRange(
+ IN LCN Lcn,
+ IN BIG_INT RunLength
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes whether or not the given range of clusters is
+ in the range allowed by this bitmap.
+
+Arguments:
+
+ Lcn - Supplies the first cluster in the range.
+ RunLength - Supplies the number of clusters in the range.
+
+Return Value:
+
+ FALSE - The specified range of clusters is not within the range of
+ the bitmap.
+ TRUE - The specified range of clusters is within the range of
+ the bitmap.
+
+--*/
+{
+ return (BOOLEAN) ((Lcn >= 0) &&
+ (RunLength >= 0 ) &&
+ (Lcn + RunLength <= _NumberOfClusters));
+}
+
+
+
+INLINE
+BOOLEAN
+NTFS_BITMAP::Read(
+ PNTFS_ATTRIBUTE BitmapAttribute
+ )
+/*++
+
+Routine Description:
+
+ This method reads the bitmap.
+
+Arguments:
+
+ BitmapAttribute -- supplies the attribute which describes the
+ bitmap's location on disk.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ ULONG BytesRead;
+
+ DebugPtrAssert( _BitmapData );
+
+ return( BitmapAttribute->Read( _BitmapData,
+ 0,
+ _BitmapSize,
+ &BytesRead ) &&
+
+ BytesRead == _BitmapSize );
+}
+
+
+
+INLINE
+BOOLEAN
+NTFS_BITMAP::CheckAttributeSize(
+ IN OUT PNTFS_ATTRIBUTE BitmapAttribute,
+ IN OUT PNTFS_BITMAP VolumeBitmap
+ )
+/*++
+
+Routine Description:
+
+ This method ensures that the allocated size of the attribute is
+ big enough to hold the bitmap.
+
+Arguments:
+
+ BitmapAttribute -- Supplies the attribute which describes the
+ bitmap's location on disk.
+ VolumeBitmap -- Supplies the volume bitmap.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ DebugAssert( BitmapAttribute != NULL );
+
+ return( BitmapAttribute->QueryValueLength() == _BitmapSize ||
+ BitmapAttribute->Resize( _BitmapSize, VolumeBitmap ) );
+}
+
+
+
+INLINE
+PCVOID
+NTFS_BITMAP::GetBitmapData(
+ OUT PULONG SizeInBytes
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the in memory bitmap contained by
+ this class. It also return the size in bytes of the bitmap.
+
+Arguments:
+
+ SizeInBytes - Returns the size of the bitmap.
+
+Return Value:
+
+ The bitmap contained by this class.
+
+--*/
+{
+ *SizeInBytes = _BitmapSize;
+ return _BitmapData;
+}
+
+INLINE
+VOID
+NTFS_BITMAP::SetMftPointer(
+ IN PNTFS_MASTER_FILE_TABLE Mft
+ )
+/*++
+
+Routine Description:
+
+ This routine set the _Mft member in the NTFS_BITMAP so that
+ subsequent calls to AllocateClusters will be able to add any
+ bad clusters found to the bad cluster file.
+
+Arguments:
+
+ Mft - pointer to the volume's mft.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _Mft = Mft;
+}
+
+
+#endif // _NTFS_BITMAP_DEFN_
diff --git a/private/utils/untfs/inc/ntfssa.hxx b/private/utils/untfs/inc/ntfssa.hxx
new file mode 100644
index 000000000..65e24f53b
--- /dev/null
+++ b/private/utils/untfs/inc/ntfssa.hxx
@@ -0,0 +1,1010 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ntfssa.hxx
+
+Abstract:
+
+ This class supplies the NTFS-only SUPERAREA methods.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 29-Jul-91
+
+--*/
+
+#if !defined(_NTFS_SUPERAREA_DEFN_)
+
+#define _NTFS_SUPERAREA_DEFN_
+
+
+#include "supera.hxx"
+#include "hmem.hxx"
+#include "untfs.hxx"
+#include "message.hxx"
+#include "ntfsbit.hxx"
+#include "numset.hxx"
+
+struct NTFS_CHKDSK_REPORT {
+
+ BIG_INT NumUserFiles;
+ BIG_INT BytesUserData;
+ BIG_INT NumIndices;
+ BIG_INT BytesInIndices;
+ BIG_INT BytesLogFile;
+};
+
+DEFINE_POINTER_TYPES( NTFS_CHKDSK_REPORT );
+
+struct NTFS_CHKDSK_INFO {
+
+ UCHAR major;
+ UCHAR minor;
+ VCN QuotaFileNumber;
+ VCN ObjectIdFileNumber;
+ ULONG NumFiles;
+ PUSHORT NumFileNames; // array of length 'NumFiles'
+ PSHORT ReferenceCount; // array of length 'NumFiles'
+ NTFS_BITMAP FilesWithIndices;
+ ULONG CountFilesWithIndices;
+ NUMBER_SET FilesWithEas;
+ NUMBER_SET ChildFrs;
+ NUMBER_SET BadFiles;
+ NUMBER_SET FilesWhoNeedData;
+ BOOLEAN CrossLinkYet; // Is the following field valid.
+ ULONG CrossLinkedFile; // File cross-linked with following.
+ ULONG CrossLinkedAttribute;
+ DSTRING CrossLinkedName;
+ ULONG CrossLinkStart; // Start of cross-linked portion.
+ ULONG CrossLinkLength; // Length of cross-link.
+ NUMBER_SET FilesWithNoReferences;
+ NUMBER_SET FilesWithTooManyFileNames;
+ NUMBER_SET FilesWithObjectId;
+ ULONG ExitStatus; // To be returned to chkdsk.exe
+};
+
+DEFINE_POINTER_TYPES( NTFS_CHKDSK_INFO );
+
+//
+// NTFS_CENSUS_INFO -- this is used by convert to determine how
+// much space will be needed to convert an NTFS volume.
+//
+
+struct NTFS_CENSUS_INFO {
+ ULONG NumFiles; // Total number of files on volume.
+ ULONG BytesLgResidentFiles; // Bytes in "large" resident files.
+ ULONG BytesIndices; // Bytes in indices.
+ ULONG BytesExternalExtentLists;
+ ULONG BytesFileNames; // Total bytes in file name attributes.
+};
+
+DEFINE_POINTER_TYPES( NTFS_CENSUS_INFO );
+
+
+DECLARE_CLASS( LOG_IO_DP_DRIVE );
+DECLARE_CLASS( WSTRING );
+DECLARE_CLASS( NTFS_MASTER_FILE_TABLE );
+DECLARE_CLASS( NTFS_BITMAP );
+DECLARE_CLASS( NTFS_FILE_RECORD_SEGMENT );
+DECLARE_CLASS( NTFS_ATTRIBUTE );
+DECLARE_CLASS( NTFS_ATTRIBUTE_COLUMNS );
+DECLARE_CLASS( NTFS_FRS_STRUCTURE );
+DECLARE_CLASS( NTFS_ATTRIBUTE_LIST );
+DECLARE_CLASS( CONTAINER );
+DECLARE_CLASS( SEQUENTIAL_CONTAINER );
+DECLARE_CLASS( LIST );
+DECLARE_CLASS( NTFS_EXTENT_LIST );
+DECLARE_CLASS( NUMBER_SET );
+DECLARE_CLASS( NTFS_INDEX_TREE );
+DECLARE_CLASS( NTFS_UPCASE_TABLE );
+DECLARE_CLASS( DIGRAPH );
+DECLARE_CLASS( NTFS_LOG_FILE );
+DECLARE_CLASS( NTFS_MFT_FILE );
+
+
+// This global variable used by CHKDSK to compute the largest
+// LSN on the volume.
+
+extern LSN LargestLsnEncountered;
+
+CONST ULONG LsnResetThreshholdHighPart = 0x10000;
+
+class NTFS_SA : public SUPERAREA {
+
+ public:
+
+ UNTFS_EXPORT
+ DECLARE_CONSTRUCTOR(NTFS_SA);
+
+ VIRTUAL
+ UNTFS_EXPORT
+ ~NTFS_SA(
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Initialize(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT PMESSAGE Message
+ );
+
+ VIRTUAL
+ PVOID
+ GetBuf(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Create(
+ IN PCNUMBER_SET BadSectors,
+ IN OUT PMESSAGE Message,
+ IN PCWSTRING Label DEFAULT NULL,
+ IN ULONG ClusterSize DEFAULT 0,
+ IN ULONG VirtualSectors DEFAULT 0
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Create(
+ IN PCNUMBER_SET BadSectors,
+ IN ULONG ClusterFactor,
+ IN ULONG FrsSize,
+ IN ULONG ClustersPerIndexBuffer,
+ IN ULONG InitialLogFileSize,
+ IN OUT PMESSAGE Message,
+ IN PCWSTRING Label DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ CreateElementaryStructures(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN ULONG ClusterFactor,
+ IN ULONG FrsSize,
+ IN ULONG IndexBufferSize,
+ IN ULONG InitialLogFileSize,
+ IN PCNUMBER_SET BadSectors,
+ IN OUT PMESSAGE Message,
+ IN PBIOS_PARAMETER_BLOCK OldBpb OPTIONAL,
+ IN PCWSTRING Label DEFAULT NULL
+ );
+
+ STATIC
+ UNTFS_EXPORT
+ ULONG
+ QuerySectorsInElementaryStructures(
+ IN PCDP_DRIVE Drive,
+ IN ULONG ClusterFactor DEFAULT 0,
+ IN ULONG FrsSize DEFAULT 0,
+ IN ULONG ClustersPerIndexBuffer DEFAULT 0,
+ IN ULONG InitialLogFileSize DEFAULT 0
+ );
+
+ STATIC
+ ULONG
+ QueryDefaultClusterFactor(
+ IN PCDP_DRIVE Drive
+ );
+
+ STATIC
+ UNTFS_EXPORT
+ ULONG
+ QueryDefaultFrsSize(
+ IN PCDP_DRIVE Drive,
+ IN ULONG ClusterFactor
+ );
+
+ STATIC
+ UNTFS_EXPORT
+ ULONG
+ QueryDefaultClustersPerIndexBuffer(
+ IN PCDP_DRIVE Drive,
+ IN ULONG ClusterFactor
+ );
+
+ VIRTUAL
+ BOOLEAN
+ VerifyAndFix(
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose DEFAULT FALSE,
+ IN BOOLEAN OnlyIfDirty DEFAULT FALSE,
+ IN BOOLEAN RecoverFree DEFAULT FALSE,
+ IN BOOLEAN RecoverAlloc DEFAULT FALSE,
+ IN BOOLEAN ResizeLogFile DEFAULT FALSE,
+ IN ULONG DesiredLogFileSize DEFAULT 0,
+ OUT PULONG ExitStatus DEFAULT NULL,
+ IN PCWSTRING DriveLetter DEFAULT NULL
+ );
+
+ VIRTUAL
+ BOOLEAN
+ RecoverFile(
+ IN PCWSTRING FullPathFileName,
+ IN OUT PMESSAGE Message
+ );
+
+ UNTFS_EXPORT
+ BOOLEAN
+ Read(
+ );
+
+ UNTFS_EXPORT
+ BOOLEAN
+ Read(
+ IN OUT PMESSAGE Message
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Write(
+ );
+
+ VIRTUAL
+ BOOLEAN
+ Write(
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BIG_INT
+ QueryVolumeSectors(
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetVolumeSectors(
+ BIG_INT NewVolumeSectors
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ UCHAR
+ QueryClusterFactor(
+ ) CONST;
+
+ NONVIRTUAL
+ LCN
+ QueryMftStartingLcn(
+ ) CONST;
+
+ NONVIRTUAL
+ LCN
+ QueryMft2StartingLcn(
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ SetMftStartingLcn(
+ IN LCN Lcn
+ );
+
+ NONVIRTUAL
+ VOID
+ SetMft2StartingLcn(
+ IN LCN Lcn
+ );
+
+ UNTFS_EXPORT
+ NONVIRTUAL
+ BOOLEAN
+ SetVolumeDirty(
+ IN USHORT FlagsToSet,
+ OUT PBOOLEAN CorruptVolume DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ ULONG
+ QueryFrsSize(
+ ) CONST;
+
+ NONVIRTUAL
+ PARTITION_SYSTEM_ID
+ QuerySystemId(
+ ) CONST;
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ WriteRemainingBootCode(
+ );
+
+ UNTFS_EXPORT
+ NONVIRTUAL
+ USHORT
+ QueryVolumeFlags(
+ OUT PBOOLEAN CorruptVolume DEFAULT NULL,
+ OUT PUCHAR MajorVersion DEFAULT NULL,
+ OUT PUCHAR MinorVersion DEFAULT NULL
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ SetVolumeClean(
+ IN USHORT FlagsToClear,
+ IN OUT PNTFS_LOG_FILE LogFile OPTIONAL,
+ IN BOOLEAN WriteSecondLogFilePage OPTIONAL,
+ IN LSN LargestVolumeLsn OPTIONAL,
+ OUT PBOOLEAN CorruptVolume DEFAULT NULL
+ );
+
+ STATIC
+ BOOLEAN
+ PostReadMultiSectorFixup(
+ IN OUT PVOID MultiSectorBuffer,
+ IN ULONG BufferSize
+ );
+
+ STATIC
+ VOID
+ PreWriteMultiSectorFixup(
+ IN OUT PVOID MultiSectorBuffer,
+ IN ULONG BufferSize
+ );
+
+ STATIC
+ UNTFS_EXPORT
+ BOOLEAN
+ IsDosName(
+ IN PCFILE_NAME FileName
+ );
+
+ STATIC
+ BOOLEAN
+ IsValidLabel(
+ IN PCWSTRING Label
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ QueryFrsFromPath(
+ IN PCWSTRING FullPathFileName,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ OUT PNTFS_FILE_RECORD_SEGMENT TargetFrs,
+ OUT PBOOLEAN InternalError
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ TakeCensus(
+ IN PNTFS_MASTER_FILE_TABLE Mft,
+ IN ULONG ResidentSizeThreshhold,
+ OUT PNTFS_CENSUS_INFO Census
+ );
+
+ STATIC
+ VOID
+ SetVersionNumber(
+ IN UCHAR Major,
+ IN UCHAR Minor
+ );
+
+ STATIC
+ VOID
+ QueryVersionNumber(
+ OUT PUCHAR Major,
+ OUT PUCHAR Minor
+ );
+
+ STATIC
+ BOOLEAN
+ DumpMessagesToFile(
+ IN PCWSTRING FileName,
+ IN OUT PNTFS_MFT_FILE MftFile,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ResizeCleanLogFile(
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN AlwaysResize,
+ IN ULONG DesiredSize
+ );
+
+ private:
+
+ NONVIRTUAL
+ BOOLEAN
+ FetchMftDataAttribute(
+ IN OUT PMESSAGE Message,
+ OUT PNTFS_ATTRIBUTE MftData
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ValidateCriticalFrs(
+ IN OUT PNTFS_ATTRIBUTE MftData,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryDefaultAttributeDefinitionTable(
+ OUT PNTFS_ATTRIBUTE_COLUMNS AttributeDefinitionTable,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FetchAttributeDefinitionTable(
+ IN OUT PNTFS_ATTRIBUTE MftData,
+ IN OUT PMESSAGE Message,
+ OUT PNTFS_ATTRIBUTE_COLUMNS AttributeDefinitionTable
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FetchUpcaseTable(
+ IN OUT PNTFS_ATTRIBUTE MftData,
+ IN OUT PMESSAGE Message,
+ OUT PNTFS_UPCASE_TABLE UpcaseTable
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ VerifyAndFixMultiFrsFile(
+ IN OUT PNTFS_FRS_STRUCTURE BaseFrs,
+ IN OUT PNTFS_ATTRIBUTE_LIST AttributeList,
+ IN PNTFS_ATTRIBUTE MftData,
+ IN PCNTFS_ATTRIBUTE_COLUMNS AttributeDefTable,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNTFS_BITMAP MftBitmap,
+ IN OUT PNTFS_CHKDSK_REPORT ChkdskReport,
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN DiskErrorsFound
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryListOfFrs(
+ IN PCNTFS_FRS_STRUCTURE BaseFrs,
+ IN PCNTFS_ATTRIBUTE_LIST AttributeList,
+ IN OUT PNTFS_ATTRIBUTE MftData,
+ OUT PNUMBER_SET ChildFileNumbers,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ VerifyAndFixChildFrs(
+ IN PCNUMBER_SET ChildFileNumbers,
+ IN PNTFS_ATTRIBUTE MftData,
+ IN PCNTFS_ATTRIBUTE_COLUMNS AttributeDefTable,
+ IN PNTFS_UPCASE_TABLE UpcaseTable,
+ OUT PHMEM* ChildFrsHmemList,
+ IN OUT PCONTAINER ChildFrsList,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN DiskErrorsFound
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ EnsureWellDefinedAttrList(
+ IN PNTFS_FRS_STRUCTURE BaseFrs,
+ IN OUT PNTFS_ATTRIBUTE_LIST AttributeList,
+ IN PCSEQUENTIAL_CONTAINER ChildFrsList,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNTFS_CHKDSK_REPORT ChkdskReport,
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN DiskErrorsFound
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ VerifyAndFixAttribute(
+ IN PCLIST Attribute,
+ IN OUT PNTFS_ATTRIBUTE_LIST AttributeList,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN PCNTFS_FRS_STRUCTURE BaseFrs,
+ OUT PBOOLEAN ErrorsFound,
+ IN OUT PNTFS_CHKDSK_REPORT ChkdskReport,
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ EnsureSurjectiveAttrList(
+ IN OUT PNTFS_FRS_STRUCTURE BaseFrs,
+ IN PCNTFS_ATTRIBUTE_LIST AttributeList,
+ IN OUT PSEQUENTIAL_CONTAINER ChildFrsList,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN DiskErrorsFound
+ );
+
+ STATIC
+ BOOLEAN
+ AreBitmapsEqual(
+ IN OUT PNTFS_ATTRIBUTE BitmapAttribute,
+ IN PCNTFS_BITMAP Bitmap,
+ IN BIG_INT MinimumBitmapSize OPTIONAL,
+ IN OUT PMESSAGE Message,
+ OUT PBOOLEAN CompleteFailure,
+ OUT PBOOLEAN SecondIsSubset DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ValidateIndices(
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ OUT PDIGRAPH DirectoryDigraph,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN PCNTFS_ATTRIBUTE_COLUMNS AttributeDefTable,
+ IN OUT PNTFS_CHKDSK_REPORT ChkdskReport,
+ IN OUT PNUMBER_SET BadClusters,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN DiskErrorsFound
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ VerifyAndFixIndex(
+ IN PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PNTFS_ATTRIBUTE RootIndex,
+ IN OUT PNTFS_ATTRIBUTE IndexAllocation OPTIONAL,
+ OUT PNTFS_BITMAP AllocationBitmap OPTIONAL,
+ IN VCN FileNumber,
+ IN PCWSTRING AttributeName,
+ IN OUT PNUMBER_SET BadClusters,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN PCNTFS_ATTRIBUTE_COLUMNS AttributeDefTable,
+ OUT PBOOLEAN Tube,
+ IN FIX_LEVEL Fixlevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN DiskErrorsFound
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ TraverseIndexTree(
+ IN OUT PINDEX_HEADER IndexHeader,
+ IN ULONG IndexLength,
+ IN OUT PNTFS_ATTRIBUTE IndexAllocation OPTIONAL,
+ IN OUT PNTFS_BITMAP AllocationBitmap OPTIONAL,
+ IN ULONG BytesPerBlock,
+ OUT PBOOLEAN Tube,
+ OUT PBOOLEAN Changes,
+ IN VCN FileNumber,
+ IN PCWSTRING AttributeName,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN DiskErrorsFound
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ValidateEntriesInIndex(
+ IN OUT PNTFS_INDEX_TREE Index,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT IndexFrs,
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PDIGRAPH DirectoryDigraph,
+ OUT PBOOLEAN Changes,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN DiskErrorsFound
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ValidateEntriesInObjIdIndex(
+ IN OUT PNTFS_INDEX_TREE Index,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT IndexFrs,
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ OUT PBOOLEAN Changes,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN DiskErrorsFound
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ RecoverOrphans(
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PDIGRAPH DirectoryDigraph,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ProperOrphanRecovery(
+ IN OUT PNUMBER_SET Orphans,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN OUT PDIGRAPH DirectoryDigraph,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ OldOrphanRecovery(
+ IN OUT PNUMBER_SET Orphans,
+ IN PCNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT RootFrs,
+ IN OUT PNTFS_INDEX_TREE RootIndex,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ HotfixMftData(
+ IN OUT PNTFS_ATTRIBUTE MftData,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN PCNUMBER_SET UnreadableFrs,
+ OUT PNUMBER_SET BadClusters,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SynchronizeMft(
+ IN OUT PNTFS_INDEX_TREE RootIndex,
+ IN PNTFS_MASTER_FILE_TABLE InternalMft,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CheckAllForData(
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ValidateSecurityDescriptors(
+ IN PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PNTFS_CHKDSK_REPORT ChkdskReport,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN OUT PNUMBER_SET BadClusters,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CheckExtendSystemFiles(
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PNTFS_CHKDSK_REPORT ChkdskReport,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ ResetLsns(
+ IN OUT PMESSAGE Message,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN BOOLEAN SkipRootIndex
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ FindHighestLsn(
+ IN OUT PMESSAGE Message,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ OUT PLSN HighestLsn
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ LogFileMayNeedResize(
+ ) CONST;
+
+
+ HMEM _hmem; // memory for SECRUN
+ PPACKED_BOOT_SECTOR _boot_sector; // packed boot sector
+ BIOS_PARAMETER_BLOCK _bpb; // unpacked BPB
+ BIG_INT _boot2; // alternate boot sector
+ BIG_INT _boot3; // second alternate boot sector
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ // This version number is used to determine what format
+ // is used for the compressed mapping pairs of sparse
+ // files. Ideally, this information should be tracked
+ // on a per-volume basis; however, that would require
+ // extensive changes to the UNTFS class interfaces.
+ //
+ STATIC UCHAR _MajorVersion, _MinorVersion;
+};
+
+
+INLINE
+PVOID
+NTFS_SA::GetBuf(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the write buffer for the NTFS
+ SUPERAREA. This routine also packs the bios parameter block.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the write buffer.
+
+--*/
+{
+ PackBios(&_bpb, &(_boot_sector->PackedBpb));
+ return SECRUN::GetBuf();
+}
+
+INLINE
+BOOLEAN
+NTFS_SA::Write(
+ )
+/*++
+
+Routine Description:
+
+ This routine simply calls the other write with the default message
+ object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ MESSAGE msg;
+
+ return Write(&msg);
+}
+
+
+INLINE
+BIG_INT
+NTFS_SA::QueryVolumeSectors(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the number of sectors on the volume as recorded in
+ the boot sector.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of volume sectors.
+
+--*/
+{
+ return _boot_sector->NumberSectors;
+}
+
+
+INLINE
+VOID
+NTFS_SA::SetVolumeSectors(
+ BIG_INT NewNumberOfSectors
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the number of sectors on the volume
+ in the boot sector.
+
+Arguments:
+
+ NewVolumeSectors -- Supplies the new value of the number
+ of sectors on the volume.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _boot_sector->NumberSectors.LowPart = NewNumberOfSectors.GetLowPart();
+ _boot_sector->NumberSectors.HighPart = NewNumberOfSectors.GetHighPart();
+}
+
+INLINE
+LCN
+NTFS_SA::QueryMftStartingLcn(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the starting logical cluster number
+ for the Master File Table.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The starting LCN for the MFT.
+
+--*/
+{
+ return _boot_sector->MftStartLcn;
+}
+
+
+INLINE
+LCN
+NTFS_SA::QueryMft2StartingLcn(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the starting logical cluster number
+ for the mirror of the Master File Table.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The starting LCN for the mirror of the MFT.
+
+--*/
+{
+ return _boot_sector->Mft2StartLcn;
+}
+
+
+INLINE
+ULONG
+NTFS_SA::QueryFrsSize(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of clusters per file record segment.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of clusters per file record segment.
+
+--*/
+{
+ if (_boot_sector->ClustersPerFileRecordSegment < 0) {
+
+ LONG temp = LONG(_boot_sector->ClustersPerFileRecordSegment);
+
+ return 1 << -temp;
+ }
+
+ return _boot_sector->ClustersPerFileRecordSegment *
+ _bpb.SectorsPerCluster * _drive->QuerySectorSize();
+}
+
+INLINE
+PARTITION_SYSTEM_ID
+NTFS_SA::QuerySystemId(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the system ID for the volume.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The system ID for the volume.
+
+--*/
+{
+ // unreferenced parameters
+ (void)(this);
+
+ return SYSID_IFS;
+}
+
+INLINE
+VOID
+NTFS_SA::SetMftStartingLcn(
+ IN LCN Lcn
+ )
+/*++
+836a861,879
+Routine Description:
+
+ This routine sets the starting logical cluster number
+ for the Master File Table.
+
+Arguments:
+
+ Lcn - The starting lcn.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _boot_sector->MftStartLcn = Lcn;
+}
+
+
+INLINE
+VOID
+NTFS_SA::SetMft2StartingLcn(
+ IN LCN Lcn
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the starting logical cluster number
+ for the mirror of the Master File Table.
+
+Arguments:
+
+ Lcn - the starting lcn.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _boot_sector->Mft2StartLcn = Lcn;
+}
+
+#endif // _NTFS_SUPERAREA_DEFN_
diff --git a/private/utils/untfs/inc/ntfsvol.hxx b/private/utils/untfs/inc/ntfsvol.hxx
new file mode 100644
index 000000000..a59486497
--- /dev/null
+++ b/private/utils/untfs/inc/ntfsvol.hxx
@@ -0,0 +1,113 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ntfsvol.hxx
+
+Abstract:
+
+ This class implements NTFS only VOLUME items.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 29-Jul-91
+
+--*/
+
+#if !defined(_NTFSVOL_)
+
+#define _NTFSVOL_
+
+#include "volume.hxx"
+#include "ntfssa.hxx"
+
+DECLARE_CLASS( NTFS_SA );
+DECLARE_CLASS( NTFS_VOL );
+DECLARE_CLASS( MESSAGE );
+
+class NTFS_VOL : public VOL_LIODPDRV {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( NTFS_VOL );
+
+ VIRTUAL
+ ~NTFS_VOL(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN BOOLEAN ExclusiveWrite DEFAULT FALSE,
+ IN BOOLEAN FormatMedia DEFAULT FALSE,
+ IN MEDIA_TYPE MediaType DEFAULT Unknown
+ );
+
+ NONVIRTUAL
+ PVOL_LIODPDRV
+ QueryDupVolume(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message DEFAULT NULL,
+ IN BOOLEAN ExclusiveWrite DEFAULT FALSE,
+ IN BOOLEAN FormatMedia DEFAULT FALSE,
+ IN MEDIA_TYPE MediaType DEFAULT Unknown
+ ) CONST;
+
+ NONVIRTUAL
+ PNTFS_SA
+ GetNtfsSuperArea(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Extend(
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verify,
+ IN BIG_INT nsecOldSize
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NTFS_SA _ntfssa;
+
+};
+
+INLINE
+PNTFS_SA
+NTFS_VOL::GetNtfsSuperArea(
+ )
+/*++
+
+Routine Description:
+
+ This method returns a pointer to the NTFS Super Area
+ associated with this volume.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the NTFS Super Area.
+
+--*/
+{
+ return &_ntfssa;
+}
+
+#endif // _NTFSVOL_
diff --git a/private/utils/untfs/inc/sdchk.hxx b/private/utils/untfs/inc/sdchk.hxx
new file mode 100644
index 000000000..68f3431bb
--- /dev/null
+++ b/private/utils/untfs/inc/sdchk.hxx
@@ -0,0 +1,52 @@
+/*++
+
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ sdchk.h
+
+Abstract:
+
+ This module contains basic declarations and definitions for
+ the security descriptor checking routines.
+
+Author:
+
+ Daniel Chan [DanielCh] 30-Sept-1996
+
+Revision History:
+
+
+IMPORTANT NOTE:
+
+--*/
+
+#if !defined( _SECURITY_CHK_DEFN_ )
+
+#define _SECURITY_CHK__DEFN_
+
+#include "untfs.hxx"
+
+//
+// Function prototype to compute the hash value
+//
+
+ULONG
+ComputeSecurityDescriptorHash(
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ IN ULONG Length
+);
+
+//
+// Function prototype to mark the end of a security descriptors block
+//
+
+VOID
+MarkEndOfSecurityDescriptorsBlock(
+ IN OUT PSECURITY_ENTRY Security_entry,
+ IN ULONG LengthOfBlock
+);
+
+#endif // _SECURITY_CHK_DEFN_
diff --git a/private/utils/untfs/inc/untfs.hxx b/private/utils/untfs/inc/untfs.hxx
new file mode 100644
index 000000000..07b77d41d
--- /dev/null
+++ b/private/utils/untfs/inc/untfs.hxx
@@ -0,0 +1,1552 @@
+/*++
+
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ untfs.h
+
+Abstract:
+
+ This module contains basic declarations and definitions for
+ the NTFS utilities. Note that more extensive description
+ of the file system structures may be found in ntos\inc\ntfs.h.
+
+Author:
+
+ Bill McJohn [BillMc] 23-July-1991
+
+Revision History:
+
+
+IMPORTANT NOTE:
+
+ The NTFS on-disk structure must guarantee natural alignment of all
+ arithmetic quantities on disk up to and including quad-word (64-bit)
+ numbers. Therefore, all attribute records are quad-word aligned, etc.
+
+--*/
+
+#if !defined( _UNTFS_DEFN_ )
+
+#define _UNTFS_DEFN_
+
+#define FRIEND friend
+#define MIN( a, b ) ( ((a) < (b)) ? (a) : (b) )
+
+
+// Set up the UNTFS_EXPORT macro for exporting from UNTFS (if the
+// source file is a member of UNTFS) or importing from UNTFS (if
+// the source file is a client of UNTFS).
+//
+#if defined ( _AUTOCHECK_ )
+#define UNTFS_EXPORT
+#elif defined ( _UNTFS_MEMBER_ )
+#define UNTFS_EXPORT __declspec(dllexport)
+#else
+#define UNTFS_EXPORT __declspec(dllimport)
+#endif
+
+
+
+#include "bigint.hxx"
+#include "bpb.hxx"
+
+#pragma pack(4)
+
+DEFINE_TYPE( BIG_INT, LCN );
+DEFINE_TYPE( BIG_INT, VCN );
+
+DEFINE_TYPE( LARGE_INTEGER, LSN );
+
+// Macros:
+
+#define QuadAlign( n ) \
+ (((n) + 7) & ~7 )
+
+#define DwordAlign( n ) \
+ (((n) + 3) & ~3 )
+
+#define IsQuadAligned( n ) \
+ (((n) & 7) == 0)
+
+#define IsDwordAligned( n ) \
+ (((n) & 3) == 0)
+
+
+// Miscellaneous constants:
+
+// This value represents the number of clusters from the Master
+// File Table which are copied to the Master File Table Reflection.
+
+#define REFLECTED_MFT_SEGMENTS (4)
+#define BYTES_IN_BOOT_AREA (0x2000)
+
+// This value is used in a mapping-pair to indicate that the run
+// described by the mapping pair doesn't really exist. This allows
+// NTFS to support sparse files. Note that the actual values
+// are LARGE_INTEGERS; the BIG_INT class manages the conversion.
+
+#define LCN_NOT_PRESENT -1
+#define INVALID_VCN -1
+
+// This definition is for VCNs that appear in Unions, since an object
+// with a constructor (like a BIG_INT) can't appear in a union.
+
+DEFINE_TYPE( LARGE_INTEGER, VCN2 );
+
+//
+// Temporary definitions ****
+//
+
+typedef ULONG COLLATION_RULE;
+typedef ULONG DISPLAY_RULE;
+
+// This defines the number of bytes to read at one time
+// when processing the MFT.
+
+#define MFT_PRIME_SIZE (32*1024)
+
+// The compression chunk size is constant for now, at 4KB.
+//
+
+#define NTFS_CHUNK_SIZE (0x1000)
+
+//
+// This number is actually the log of the number of clusters per compression
+// unit to be stored in a nonresident attribute record header.
+//
+
+#define NTFS_CLUSTERS_PER_COMPRESSION (4)
+
+//
+// Collation Rules
+//
+
+//
+// For binary collation, values are collated by a binary compare of their
+// bytes, with the first byte being most significant.
+//
+
+#define COLLATION_BINARY (0)
+
+//
+// For collation of Ntfs file names, file names are collated as Unicode
+// strings. See below.
+//
+
+#define COLLATION_FILE_NAME (1)
+
+//
+// For collation of Unicode strings, the strings are collated by their
+// binary Unicode value, with the exception that for characters which may
+// be upcased, the lower case value for that character collates immediately
+// after the upcased value.
+//
+
+#define COLLATION_UNICODE_STRING (2)
+
+#define COLLATION_ULONG (16)
+#define COLLATION_SID (17)
+#define COLLATION_SECURITY_HASH (18)
+#define COLLATION_ULONGS (19)
+
+//
+// Total number of collation rules
+//
+
+#define COLLATION_NUMBER_RULES (7)
+
+
+// An MFT_SEGMENT_REFERENCE identifies a cluster in the Master
+// File Table by its file number (VCN in Master File Table) and
+// sequence number. If the sequence number is zero, sequence
+// number checking is not performed.
+
+typedef struct _MFT_SEGMENT_REFERENCE {
+
+ ULONG LowPart;
+ USHORT HighPart;
+ USHORT SequenceNumber;
+
+} MFT_SEGMENT_REFERENCE, *PMFT_SEGMENT_REFERENCE;
+
+DEFINE_TYPE( struct _MFT_SEGMENT_REFERENCE, MFT_SEGMENT_REFERENCE );
+
+DEFINE_TYPE( MFT_SEGMENT_REFERENCE, FILE_REFERENCE );
+
+INLINE
+BOOLEAN
+operator == (
+ IN RCMFT_SEGMENT_REFERENCE Left,
+ IN RCMFT_SEGMENT_REFERENCE Right
+ )
+/*++
+
+Routine Description:
+
+ This function tests two segment references for equality.
+
+Arguments:
+
+ Left -- supplies the left-hand operand
+ Right -- supplies the right-hand operand
+
+Return Value:
+
+ TRUE if they are equal; FALSE if not.
+
+--*/
+{
+ return( Left.HighPart == Right.HighPart &&
+ Left.LowPart == Right.LowPart &&
+ Left.SequenceNumber == Right.SequenceNumber );
+}
+
+
+
+// System file numbers:
+//
+// The first sixteen entries in the Master File Table are reserved for
+// system use. The following reserved slots have been defined:
+
+#define MASTER_FILE_TABLE_NUMBER (0)
+#define MASTER_FILE_TABLE2_NUMBER (1)
+#define LOG_FILE_NUMBER (2)
+#define VOLUME_DASD_NUMBER (3)
+#define ATTRIBUTE_DEF_TABLE_NUMBER (4)
+#define ROOT_FILE_NAME_INDEX_NUMBER (5)
+#define BIT_MAP_FILE_NUMBER (6)
+#define BOOT_FILE_NUMBER (7)
+#define BAD_CLUSTER_FILE_NUMBER (8)
+#define QUOTA_TABLE_NUMBER (9) // for version < 2.0
+#define SECURITY_TABLE_NUMBER (9) // for version >= 2.0
+#define UPCASE_TABLE_NUMBER (10)
+#define EXTEND_TABLE_NUMBER (11) // for version >= 2.0
+
+#define MFT_OVERFLOW_FRS_NUMBER (15)
+
+#define FIRST_USER_FILE_NUMBER (16)
+
+DEFINE_TYPE( ULONG, ATTRIBUTE_TYPE_CODE );
+
+//
+// System-defined Attribute Type Codes. For the System-defined attributes,
+// the Unicode Name is exactly equal to the name of the following symbols.
+// For this reason, all of the system-defined attribute names start with "$",
+// to always distinguish them when attribute names are listed, and to reserve
+// a namespace for attributes defined in the future. I.e., a User-Defined
+// attribute name will never collide with a current or future system-defined
+// attribute name if it does not start with "$". User attribute numbers
+// should not start until $FIRST_USER_DEFINED_ATTRIBUTE, too allow the
+// potential for upgrading existing volumes with new user-defined attributes
+// in future versions of NTFS. The tagged attribute list is terminated with
+// a lone-standing $END - the rest of the attribute record does not exist.
+//
+
+#define $UNUSED (0x0)
+
+#define $STANDARD_INFORMATION (0x10)
+#define $ATTRIBUTE_LIST (0x20)
+#define $FILE_NAME (0x30)
+#define $VOLUME_VERSION (0x40)
+#define $OBJECT_ID (0x40)
+#define $SECURITY_DESCRIPTOR (0x50)
+#define $VOLUME_NAME (0x60)
+#define $VOLUME_INFORMATION (0x70)
+#define $DATA (0x80)
+#define $INDEX_ROOT (0x90)
+#define $INDEX_ALLOCATION (0xA0)
+#define $BITMAP (0xB0)
+#define $SYMBOLIC_LINK (0xC0)
+#define $EA_INFORMATION (0xD0)
+#define $EA_DATA (0xE0)
+#define $FIRST_USER_DEFINED_ATTRIBUTE (0x100)
+#define $END (0xFFFFFFFF)
+
+
+//
+// The boot sector is duplicated on the partition. The first copy is on
+// the first physical sector (LBN == 0) of the partition, and the second
+// copy is at <number sectors on partition> / 2. If the first copy can
+// not be read when trying to mount the disk, the second copy may be read
+// and has the identical contents. Format must figure out which cluster
+// the second boot record belongs in, and it must zero all of the other
+// sectors that happen to be in the same cluster. The boot file minimally
+// contains with two clusters, which are the two clusters which contain the
+// copies of the boot record. If format knows that some system likes to
+// put code somewhere, then it should also align this requirement to
+// even clusters, and add that to the boot file as well.
+//
+
+
+//
+// Define the boot sector. Note that MFT2 is exactly three file record
+// segments long, and it mirrors the first three file record segments from
+// the MFT, which are MFT, MFT2 and the Log File.
+//
+// The Oem field contains the ASCII characters "NTFS ".
+//
+// The Checksum field is a simple additive checksum of all of the ULONGs
+// which precede the Checksum ULONG. The rest of the sector is not included
+// in this Checksum.
+//
+
+typedef struct _PACKED_BOOT_SECTOR {
+ UCHAR Jump[3]; // offset = 0x000
+ UCHAR Oem[8]; // offset = 0x003
+ PACKED_BIOS_PARAMETER_BLOCK PackedBpb; // offset = 0x00B
+ UCHAR PhysicalDrive; // offset = 0x024
+ UCHAR ReservedForBootCode; // offset = 0x025
+ UCHAR Unused[2]; // offset = 0x026
+ LARGE_INTEGER NumberSectors; // offset = 0x028
+ LCN MftStartLcn; // offset = 0x030
+ LCN Mft2StartLcn; // offset = 0x038
+ CHAR ClustersPerFileRecordSegment; // offset = 0x040
+ UCHAR Unused1[3]; // offset = 0x041
+ CHAR DefaultClustersPerIndexAllocationBuffer; // offset = 0x044
+ UCHAR Unused2[3]; // offset = 0x047
+ LARGE_INTEGER SerialNumber; // offset = 0x048
+ ULONG Checksum; // offset = 0x050
+ UCHAR BootStrap[0x200-0x054]; // offset = 0x054
+} PACKED_BOOT_SECTOR; // sizeof = 0x200
+typedef PACKED_BOOT_SECTOR *PPACKED_BOOT_SECTOR;
+
+//
+// If the ClustersPerFileRecordSegment entry is zero, we use the
+// following as the size of our frs's regardless of the cluster
+// size.
+//
+
+#define SMALL_FRS_SIZE (1024)
+
+//
+// If the DefaultClustersPerIndexAllocationBuffer entry is zero,
+// we use the following as the size of our buffers regardless of
+// the cluster size.
+//
+
+#define SMALL_INDEX_BUFFER_SIZE (4096)
+
+
+
+// Update sequence array structures--see ntos\inc\cache.h for
+// description.
+
+#define SEQUENCE_NUMBER_STRIDE (512)
+
+DEFINE_TYPE( USHORT, UPDATE_SEQUENCE_NUMBER );
+
+typedef struct _UNTFS_MULTI_SECTOR_HEADER {
+
+ UCHAR Signature[4];
+ USHORT UpdateSequenceArrayOffset; // byte offset
+ USHORT UpdateSequenceArraySize; // number of Update Sequence Numbers
+
+};
+
+DEFINE_TYPE( _UNTFS_MULTI_SECTOR_HEADER, UNTFS_MULTI_SECTOR_HEADER );
+
+typedef UPDATE_SEQUENCE_NUMBER UPDATE_SEQUENCE_ARRAY[1];
+typedef UPDATE_SEQUENCE_ARRAY *PUPDATE_SEQUENCE_ARRAY;
+
+
+//
+// File Record Segment. This is the header that begins every File Record
+// Segment in the Master File Table.
+//
+
+typedef struct _FILE_RECORD_SEGMENT_HEADER {
+
+ UNTFS_MULTI_SECTOR_HEADER MultiSectorHeader;
+ LSN Lsn;
+ USHORT SequenceNumber;
+ USHORT ReferenceCount;
+ USHORT FirstAttributeOffset;
+ USHORT Flags; // FILE_xxx flags
+ ULONG FirstFreeByte; // byte-offset
+ ULONG BytesAvailable; // Size of FRS
+ FILE_REFERENCE BaseFileRecordSegment;
+ USHORT NextAttributeInstance; // Attribute instance tag for next insert.
+ UPDATE_SEQUENCE_ARRAY UpdateArrayForCreateOnly;
+
+};
+
+//
+// If the above NextAttributeInstance field exceeds the following
+// value, chkdsk will take steps to prevent it from rolling over.
+//
+
+#define ATTRIBUTE_INSTANCE_TAG_THRESHOLD 0xf000
+
+
+DEFINE_TYPE( _FILE_RECORD_SEGMENT_HEADER, FILE_RECORD_SEGMENT_HEADER );
+
+//
+// FILE_xxx flags.
+//
+
+#define FILE_RECORD_SEGMENT_IN_USE (0x0001)
+#define FILE_FILE_NAME_INDEX_PRESENT (0x0002)
+#define FILE_SYSTEM_FILE (0x0004)
+#define FILE_VIEW_INDEX_PRESENT (0x0008)
+
+//
+// Define a macro to determine the maximum space available for a
+// single attribute. For example, this is required when a
+// nonresident attribute has to split into multiple file records -
+// we need to know how much we can squeeze into a single file
+// record. If this macro has any inaccurracy, it must be in the
+// direction of returning a slightly smaller number than actually
+// required.
+//
+// ULONG
+// NtfsMaximumAttributeSize (
+// IN ULONG FileRecordSegmentSize
+// );
+//
+
+#define NtfsMaximumAttributeSize(FRSS) ( \
+ (FRSS) - QuadAlign(sizeof(FILE_RECORD_SEGMENT_HEADER)) - \
+ QuadAlign((((FRSS) / SEQUENCE_NUMBER_STRIDE) * sizeof(UPDATE_SEQUENCE_NUMBER))) - \
+ QuadAlign(sizeof(ATTRIBUTE_TYPE_CODE)) \
+)
+
+
+
+//
+// Attribute Record. Logically an attribute has a type, an optional name,
+// and a value, however the storage details make it a little more complicated.
+// For starters, an attribute's value may either be resident in the file
+// record segment itself, on nonresident in a separate data stream. If it
+// is nonresident, it may actually exist multiple times in multiple file
+// record segments to describe different ranges of VCNs.
+//
+// Attribute Records are always aligned on a quad word (64-bit) boundary.
+//
+// Note that SIZE_OF_RESIDENT_HEADER and SIZE_OF_NONRESIDENT_HEADER
+// must correspond to the ATTRIBUTE_RECORD_HEADER structure.
+
+#define SIZE_OF_RESIDENT_HEADER 24
+#define SIZE_OF_NONRESIDENT_HEADER 64
+
+typedef struct _ATTRIBUTE_RECORD_HEADER {
+
+ ATTRIBUTE_TYPE_CODE TypeCode;
+ ULONG RecordLength;
+ UCHAR FormCode;
+ UCHAR NameLength; // length in characters
+ USHORT NameOffset; // byte offset from start of record
+ USHORT Flags; // ATTRIBUTE_xxx flags.
+ USHORT Instance; // FRS-unique attribute instance tag
+
+ union {
+
+ //
+ // Resident Form. Attribute resides in file record segment.
+ //
+
+ struct {
+
+ ULONG ValueLength; // in bytes
+ USHORT ValueOffset; // byte offset from start of record
+ UCHAR ResidentFlags; // RESIDENT_FORM_xxx Flags.
+ UCHAR Reserved;
+
+ } Resident;
+
+ //
+ // Nonresident Form. Attribute resides in separate stream.
+ //
+
+ struct {
+
+ VCN2 LowestVcn;
+ VCN2 HighestVcn;
+ USHORT MappingPairsOffset; // byte offset from start of record
+ UCHAR CompressionUnit;
+ UCHAR Reserved[5];
+ LARGE_INTEGER AllocatedLength;
+ LARGE_INTEGER FileSize;
+ LARGE_INTEGER ValidDataLength;
+ LARGE_INTEGER TotalAllocated;
+
+ //
+ // Mapping Pairs Array follows, starting at the offset given
+ // above. See the extended comment in ntfs.h.
+ //
+
+ } Nonresident;
+
+ } Form;
+
+};
+
+DEFINE_TYPE( _ATTRIBUTE_RECORD_HEADER, ATTRIBUTE_RECORD_HEADER );
+
+
+//
+// Attribute Form Codes
+//
+
+#define RESIDENT_FORM (0x00)
+#define NONRESIDENT_FORM (0x01)
+
+//
+// Define Attribute Flags
+//
+
+#define ATTRIBUTE_FLAG_COMPRESSION_MASK (0x00FF)
+
+//
+// RESIDENT_FORM_xxx flags
+//
+
+//
+// This attribute is indexed.
+//
+
+#define RESIDENT_FORM_INDEXED (0x01)
+
+//
+// The maximum attribute name length is 255 (in chars)
+//
+
+#define NTFS_MAX_ATTR_NAME_LEN (255)
+
+
+//
+// Macros for manipulating mapping pair count byte.
+//
+
+INLINE
+UCHAR
+ComputeMappingPairCountByte(
+ IN UCHAR VcnLength,
+ IN UCHAR LcnLength
+ )
+{
+ return VcnLength + 16*LcnLength;
+}
+
+INLINE
+UCHAR
+VcnBytesFromCountByte(
+ IN UCHAR CountByte
+ )
+{
+ return CountByte%16;
+}
+
+INLINE
+UCHAR
+LcnBytesFromCountByte(
+ IN UCHAR CountByte
+ )
+{
+ return CountByte/16;
+}
+
+
+//
+// Standard Information Attribute. This attribute is present in every
+// base file record, and must be resident.
+//
+
+typedef struct _STANDARD_INFORMATION {
+
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastModificationTime; // refers to $DATA attribute
+ LARGE_INTEGER LastChangeTime; // any attribute
+ LARGE_INTEGER LastAccessTime;
+ ULONG FileAttributes;
+ ULONG MaximumVersions;
+ ULONG VersionNumber;
+ ULONG Reserved;
+
+};
+
+DEFINE_TYPE( _STANDARD_INFORMATION, STANDARD_INFORMATION );
+
+typedef struct _STANDARD_INFORMATION2 {
+
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastModificationTime; // refers to $DATA attribute
+ LARGE_INTEGER LastChangeTime; // any attribute
+ LARGE_INTEGER LastAccessTime;
+ ULONG FileAttributes;
+ ULONG MaximumVersions;
+ ULONG VersionNumber;
+ ULONG ClassId;
+ ULONG OwnerId;
+ ULONG SecurityId;
+ LARGE_INTEGER QuotaCharged;
+ LARGE_INTEGER Usn;
+
+};
+
+DEFINE_TYPE( _STANDARD_INFORMATION2, STANDARD_INFORMATION2 );
+
+#define SIZEOF_NEW_STANDARD_INFORMATION (0x48)
+
+//
+// Define the file attributes, starting with the Fat attributes.
+//
+
+#define FAT_DIRENT_ATTR_READ_ONLY (0x01)
+#define FAT_DIRENT_ATTR_HIDDEN (0x02)
+#define FAT_DIRENT_ATTR_SYSTEM (0x04)
+#define FAT_DIRENT_ATTR_VOLUME_ID (0x08)
+#define FAT_DIRENT_ATTR_ARCHIVE (0x20)
+#define FAT_DIRENT_ATTR_DEVICE (0x40)
+
+#define DUP_FILE_NAME_INDEX_PRESENT (0x10000000)
+#define DUP_VIEW_INDEX_PRESENT (0x20000000)
+
+//
+// Attribute List. Because there is not a special header that goes
+// before the list of attribute list entries we do not need to declare
+// an attribute list header
+//
+
+//
+// The Attributes List attribute is an ordered-list of quad-word
+// aligned ATTRIBUTE_LIST_ENTRY records. It is ordered first by
+// Attribute Type Code, and then by Attribute Name (if present). No two
+// attributes may exist with the same type code, name and LowestVcn. This
+// also means that at most one occurrence of a given Attribute Type Code
+// without a name may exist.
+//
+// To binary search this attribute, it is first necessary to make a quick
+// pass through it and form a list of pointers, since the optional name
+// makes it variable-length.
+//
+
+typedef struct _ATTRIBUTE_LIST_ENTRY {
+
+ ATTRIBUTE_TYPE_CODE AttributeTypeCode;
+ USHORT RecordLength; // length in bytes
+ UCHAR AttributeNameLength; // length in characters
+ UCHAR AttributeNameOffset; // offset from beginning of struct
+ VCN LowestVcn;
+ MFT_SEGMENT_REFERENCE SegmentReference;
+ USHORT Instance; // FRS-unique instance tag
+ WCHAR AttributeName[1];
+
+};
+
+DEFINE_TYPE( _ATTRIBUTE_LIST_ENTRY, ATTRIBUTE_LIST_ENTRY );
+
+BOOLEAN
+operator <= (
+ IN RCATTRIBUTE_LIST_ENTRY Left,
+ IN RCATTRIBUTE_LIST_ENTRY Right
+ );
+
+
+typedef struct _DUPLICATED_INFORMATION {
+
+ BIG_INT CreationTime; // File creation
+ BIG_INT LastModificationTime; // Last change of $DATA attribute
+ BIG_INT LastChangeTime; // Last change of any attribute
+ BIG_INT LastAccessTime; // see ntfs.h for notes
+ BIG_INT AllocatedLength; // File allocated size
+ BIG_INT FileSize; // File actual size
+ ULONG FileAttributes;
+ USHORT PackedEaSize;
+ USHORT Reserved;
+
+};
+
+DEFINE_TYPE( _DUPLICATED_INFORMATION, DUPLICATED_INFORMATION );
+
+//
+// This bit is duplicated from the file record, to indicate that
+// this file has a file name index present (is a "directory").
+//
+
+#define DUP_FILE_NAME_INDEX_PRESENT (0x10000000)
+
+//
+// File Name attribute. A file has one File Name attribute for every
+// directory it is entered into (hard links).
+//
+
+typedef struct _FILE_NAME {
+
+ FILE_REFERENCE ParentDirectory;
+ DUPLICATED_INFORMATION Info;
+ UCHAR FileNameLength; // length in characters
+ UCHAR Flags; // FILE_NAME_xxx flags
+ WCHAR FileName[1]; // First character of file name
+
+};
+
+DEFINE_TYPE( _FILE_NAME, FILE_NAME );
+
+// NtfsFileNameGetLength evaluates to the length of a FILE_NAME attribute
+// value, which is the FILE_NAME structure plus the length of the name.
+// Note that this is the actual length, not the quad-aligned length.
+
+#define NtfsFileNameGetLength(p) ( FIELD_OFFSET( FILE_NAME, FileName ) \
+ + ((p)->FileNameLength * sizeof( WCHAR )) )
+
+// NtfsFileNameGetName gets the pointer to the name in a FILE_NAME
+// structure, which in turn is the value of an NTFS $FILE_NAME attribute.
+
+#define NtfsFileNameGetName(p) ( &((p)->FileName[0]) )
+
+
+//
+// File Name flags
+//
+
+#define FILE_NAME_NTFS (0x01)
+#define FILE_NAME_DOS (0x02)
+
+//
+// The maximum file name length is 255 (in chars)
+//
+
+#define NTFS_MAX_FILE_NAME_LENGTH (255)
+
+
+//
+// The maximum number of links on a file is 1024
+//
+
+#define NTFS_MAX_LINK_COUNT (1024)
+
+
+// This is the name of all attributes associated with an index
+// over $FILE_NAME:
+
+#define FileNameIndexNameData "$I30"
+
+//
+// Object ID attribute.
+//
+
+typedef struct _OBJECT_ID {
+ char x[16];
+};
+
+DEFINE_TYPE( _OBJECT_ID, OBJECT_ID );
+
+typedef struct _OBJID_INDEX_ENTRY_VALUE {
+ OBJECT_ID key;
+ MFT_SEGMENT_REFERENCE SegmentReference;
+ char extraInfo[16];
+};
+
+DEFINE_TYPE( _OBJID_INDEX_ENTRY_VALUE, OBJID_INDEX_ENTRY_VALUE );
+
+//
+// Object Id File Name to appear in the \$Extend directory
+//
+
+#define ObjectIdFileName "$ObjId"
+#define LObjectIdFileName L"$ObjId"
+
+#define ObjectIdIndexNameData "$O"
+
+
+//
+// Volume Version attribute.
+//
+
+typedef struct _VOLUME_VERSION {
+
+ ULONG CurrentVersion;
+ ULONG MaximumVersions;
+
+};
+
+DEFINE_TYPE( _VOLUME_VERSION, VOLUME_VERSION );
+
+
+//
+// Security Descriptor attribute. This is just a normal attribute stream
+// containing a security descriptor as defined by NT security and is
+// really treated pretty opaque by NTFS.
+//
+#define SecurityIdIndexNameData "$SII"
+#define SecurityDescriptorHashIndexNameData "$SDH"
+#define SecurityDescriptorStreamNameData "$SDS"
+
+// Security Descriptor Stream data is organized into chunks of 256K bytes
+// and it contains a mirror copy of each security descriptor. When writing
+// to a security descriptor at location X, another copy will be written at
+// location (X+256K). When writing a security descriptor that will
+// cross the 256K boundary, the pointer will be advanced by 256K to skip
+// over the mirror portion.
+
+#define SecurityDescriptorsBlockSize (0x40000) // 256K
+#define SecurityDescriptorMaxSize (0x20000) // 128K
+
+
+// Volume Name attribute. This attribute is just a normal attribute stream
+// containing the unicode characters that make up the volume label. It
+// is an attribute of the Volume Dasd File.
+//
+
+
+//
+// Volume Information attribute. This attribute is only intended to be
+// used on the Volume DASD file.
+//
+
+typedef struct _VOLUME_INFORMATION {
+
+ LARGE_INTEGER Reserved;
+
+ //
+ // Major and minor version number of NTFS on this volume, starting
+ // with 1.0. The major and minor version numbers are set from the
+ // major and minor version of the Format and NTFS implementation for
+ // which they are initialized. The policy for incementing major and
+ // minor versions will always be decided on a case by case basis, however,
+ // the following two paragraphs attempt to suggest an approximate strategy.
+ //
+ // The major version number is incremented if/when a volume format
+ // change is made which requires major structure changes (hopefully
+ // never?). If an implementation of NTFS sees a volume with a higher
+ // major version number, it should refuse to mount the volume. If a
+ // newer implementation of NTFS sees an older major version number,
+ // it knows the volume cannot be accessed without performing a one-time
+ // conversion.
+ //
+ // The minor version number is incremented if/when minor enhancements
+ // are made to a major version, which potentially support enhanced
+ // functionality through additional file or attribute record fields,
+ // or new system-defined files or attributes. If an older implementation
+ // of NTFS sees a newer minor version number on a volume, it may issue
+ // some kind of warning, but it will proceed to access the volume - with
+ // presumably some degradation in functionality compared to the version
+ // of NTFS which initialized the volume. If a newer implementation of
+ // NTFS sees a volume with an older minor version number, it may issue
+ // a warning and proceed. In this case, it may choose to increment the
+ // minor version number on the volume and begin full or incremental
+ // upgrade of the volume on an as-needed basis. It may also leave the
+ // minor version number unchanged, until some sort of explicit directive
+ // from the user specifies that the minor version should be updated.
+ //
+
+ UCHAR MajorVersion;
+ UCHAR MinorVersion;
+
+ //
+ // VOLUME_xxx flags.
+ //
+
+ USHORT VolumeFlags;
+
+} VOLUME_INFORMATION;
+typedef VOLUME_INFORMATION *PVOLUME_INFORMATION;
+
+// Current version number:
+//
+#define NTFS_CURRENT_MAJOR_VERSION 1
+#define NTFS_CURRENT_MINOR_VERSION 1
+
+//
+// Volume is dirty
+//
+
+#define VOLUME_DIRTY (0x0001)
+#define VOLUME_RESIZE_LOG_FILE (0x0002)
+
+
+//
+// Common Index Header for Index Root and Index Allocation Buffers.
+// This structure is used to locate the Index Entries and describe the free
+// space in either of the two structures above.
+//
+
+typedef struct _INDEX_HEADER {
+
+ //
+ // Offset from the start of this structure to the first Index Entry.
+ //
+
+ ULONG FirstIndexEntry;
+
+ //
+ // Offset from the start of this structure to the first (quad-word aligned)
+ // free byte.
+ //
+
+ ULONG FirstFreeByte;
+
+ //
+ // Total number of bytes available, from the start of this structure.
+ // In the Index Root, this number must always be equal to FirstFreeByte,
+ // as the total attribute record will be grown and shrunk as required.
+ //
+
+ ULONG BytesAvailable;
+
+ //
+ // INDEX_xxx flags.
+ //
+
+ UCHAR Flags;
+
+ //
+ // Reserved to round up to quad word boundary.
+ //
+
+ UCHAR Reserved[3];
+
+} INDEX_HEADER;
+typedef INDEX_HEADER *PINDEX_HEADER;
+
+//
+// INDEX_xxx flags
+//
+
+//
+// This Index or Index Allocation buffer is an intermediate node, as opposed to
+// a leaf in the Btree. All Index Entries will have a Vcn down pointer.
+//
+
+#define INDEX_NODE (0x01)
+
+
+//
+// Index Root attribute. The index attribute consists of an index
+// header record followed by one or more index entries.
+//
+
+typedef struct _INDEX_ROOT {
+
+ ATTRIBUTE_TYPE_CODE IndexedAttributeType;
+ COLLATION_RULE CollationRule;
+ ULONG BytesPerIndexBuffer;
+ UCHAR ClustersPerIndexBuffer;
+ UCHAR Reserved[3];
+
+ //
+ // Index Header to describe the Index Entries which follow
+ //
+
+ INDEX_HEADER IndexHeader;
+
+} INDEX_ROOT;
+typedef INDEX_ROOT *PINDEX_ROOT;
+
+//
+// Index Allocation record is used for non-root clusters of the b-tree
+// Each non root cluster is contained in the data part of the index
+// allocation attribute. Each cluster starts with an index allocation list
+// header and is followed by one or more index entries.
+//
+
+typedef struct _INDEX_ALLOCATION_BUFFER {
+
+ //
+ // Multi-Sector Header as defined by the Cache Manager. This structure
+ // will always contain the signature "INDX" and a description of the
+ // location and size of the Update Sequence Array.
+ //
+
+ UNTFS_MULTI_SECTOR_HEADER MultiSectorHeader;
+
+ //
+ // Log File Sequence Number of last logged update to this Index Allocation
+ // Buffer.
+ //
+
+ LSN Lsn;
+
+ VCN ThisVcn;
+
+
+ //
+ // Index Header to describe the Index Entries which follow
+ //
+
+ INDEX_HEADER IndexHeader;
+
+ //
+ // Update Sequence Array to protect multi-sector transfers of the
+ // Index Allocation Bucket.
+ //
+
+ UPDATE_SEQUENCE_ARRAY UpdateSequenceArray;
+
+} INDEX_ALLOCATION_BUFFER;
+typedef INDEX_ALLOCATION_BUFFER *PINDEX_ALLOCATION_BUFFER;
+
+
+//
+// Index Entry. This structure is common to both the resident index list
+// attribute and the Index Allocation records
+//
+
+typedef struct _INDEX_ENTRY {
+
+ //
+ // Define a union to distinguish directory indices from view indices
+ //
+
+ union {
+
+ //
+ // Reference to file containing the attribute with this
+ // attribute value.
+ //
+
+ FILE_REFERENCE FileReference; // offset = 0x000
+
+ //
+ // For views, describe the Data Offset and Length in bytes
+ //
+
+ struct {
+
+ USHORT DataOffset; // offset = 0x000
+ USHORT DataLength; // offset = 0x001
+ ULONG ReservedForZero; // offset = 0x002
+ };
+ };
+
+ //
+ // Length of this index entry, in bytes.
+ //
+
+ USHORT Length;
+
+ //
+ // Length of attribute value, in bytes. The attribute value immediately
+ // follows this record.
+ //
+
+ USHORT AttributeLength;
+
+ //
+ // INDEX_ENTRY_xxx Flags.
+ //
+
+ USHORT Flags;
+
+ //
+ // Reserved to round to quad-word boundary.
+ //
+
+ USHORT Reserved;
+
+ //
+ // If this Index Entry is an intermediate node in the tree, as determined
+ // by the INDEX_xxx flags, then a VCN is stored at the end of this
+ // entry at Length - sizeof(VCN).
+ //
+
+};
+
+DEFINE_TYPE( _INDEX_ENTRY, INDEX_ENTRY );
+
+
+#define GetDownpointer( x ) \
+ (*((PVCN)((PBYTE)(x) + (x)->Length - sizeof(VCN))))
+
+#define GetIndexEntryValue( x ) \
+ ((PBYTE)(x)+sizeof(INDEX_ENTRY))
+
+#define GetNextEntry( x ) \
+ ((PINDEX_ENTRY)( (PBYTE)(x)+(x)->Length ))
+
+CONST UCHAR NtfsIndexLeafEndEntrySize = QuadAlign( sizeof(INDEX_ENTRY) );
+
+//
+// INDEX_ENTRY_xxx flags
+//
+
+//
+// This entry is currently in the intermediate node form, i.e., it has a
+// Vcn at the end.
+//
+
+#define INDEX_ENTRY_NODE (0x0001)
+
+//
+// This entry is the special END record for the Index or Index Allocation buffer.
+//
+
+#define INDEX_ENTRY_END (0x0002)
+
+
+//
+// Define the struture of the quota data in the quota index. The key for
+// the quota index is the 32 bit owner id.
+//
+
+typedef struct _QUOTA_USER_DATA {
+ ULONG QuotaVersion;
+ ULONG QuotaFlags;
+ ULONGLONG QuotaThreshold;
+ ULONGLONG QuotaLimit;
+ ULONGLONG QuotaUsed;
+ ULONGLONG QuotaChangeTime;
+ ULONGLONG QuotaExceededTime;
+ SID QuotaSid;
+} QUOTA_USER_DATA, *PQUOTA_USER_DATA;
+
+//
+// Define the size of the quota user data structure without the quota SID.
+//
+
+#define SIZEOF_QUOTA_USER_DATA FIELD_OFFSET(QUOTA_USER_DATA, QuotaSid)
+
+//
+// Define the current version of the quote user data.
+//
+
+#define QUOTA_USER_VERSION 1
+
+//
+// Define the quota flags.
+//
+
+#define QUOTA_FLAG_DEFAULT_LIMITS (0x00000001)
+#define QUOTA_FLAG_LIMIT_REACHED (0x00000002)
+#define QUOTA_FLAG_ID_DELETED (0x00000004)
+#define QUOTA_FLAG_USER_MASK (0x00000007)
+
+//
+// The following flags are only stored in the quota defaults index entry.
+//
+
+#define QUOTA_FLAG_TRACKING_ENABLED (0x00000010)
+#define QUOTA_FLAG_ENFORCEMENT_ENABLED (0x00000020)
+#define QUOTA_FLAG_TRACKING_REQUESTED (0x00000040)
+#define QUOTA_FLAG_LOG_THRESHOLD (0x00000080)
+#define QUOTA_FLAG_LOG_LIMIT (0x00000100)
+#define QUOTA_FLAG_OUT_OF_DATE (0x00000200)
+#define QUOTA_FLAG_CORRUPT (0x00000400)
+#define QUOTA_FLAG_PENDING_DELETES (0x00000800)
+
+//
+// Define the quota charge for resident streams.
+//
+
+#define QUOTA_RESIDENT_STREAM (1024)
+
+//
+// Define special quota owner ids.
+//
+
+#define QUOTA_INVALID_ID 0x00000000
+#define QUOTA_DEFAULTS_ID 0x00000001
+#define QUOTA_FISRT_USER_ID 0x00000100
+
+//
+// Quota File Name to appear in the \$Extend directory
+//
+
+#define QuotaFileName "$Quota"
+#define LQuotaFileName L"$Quota"
+
+//
+// Quota Index Names
+//
+
+#define Sid2UseridQuotaNameData "$O"
+#define Userid2SidQuotaNameData "$Q"
+
+//
+//
+//
+#define MAXULONGLONG (0xffffffffffffffff)
+
+
+//
+// Key structure for Security Hash index
+//
+
+typedef struct _SECURITY_HASH_KEY
+{
+ ULONG Hash; // Hash value for descriptor
+ ULONG SecurityId; // Security Id (guaranteed unique)
+} SECURITY_HASH_KEY, *PSECURITY_HASH_KEY;
+
+//
+// Key structure for Security Id index is simply the SECURITY_ID itself
+//
+
+//
+// Header for security descriptors in the security descriptor stream. This
+// is the data format for all indexes and is part of SharedSecurity
+//
+
+typedef struct _SECURITY_DESCRIPTOR_HEADER
+{
+ SECURITY_HASH_KEY HashKey; // Hash value for the descriptor
+ ULONGLONG Offset; // offset to beginning of header
+ ULONG Length; // Length in bytes
+} SECURITY_DESCRIPTOR_HEADER, *PSECURITY_DESCRIPTOR_HEADER;
+
+typedef struct _SECURITY_ENTRY {
+ SECURITY_DESCRIPTOR_HEADER security_descriptor_header;
+ SECURITY_DESCRIPTOR security;
+} SECURITY_ENTRY, *PSECURITY_ENTRY;
+
+#define GETSECURITYDESCRIPTORLENGTH(HEADER) \
+ ((HEADER)->Length - sizeof( SECURITY_DESCRIPTOR_HEADER ))
+
+#define SetSecurityDescriptorLength(HEADER,LENGTH) \
+ ((HEADER)->Length = (LENGTH) + sizeof( SECURITY_DESCRIPTOR_HEADER ))
+
+//
+// Define standard values for well-known security IDs
+//
+
+#define SECURITY_ID_INVALID (0x00000000)
+#define SECURITY_ID_FIRST (0x00000100)
+
+
+//
+// MFT Bitmap attribute
+//
+// The MFT Bitmap is simply a normal attribute stream in which there is
+// one bit to represent the allocation state of each File Record Segment
+// in the MFT. Bit clear means free, and bit set means allocated.
+//
+// Whenever the MFT Data attribute is extended, the MFT Bitmap attribute
+// must also be extended. If the bitmap is still in a file record segment
+// for the MFT, then it must be extended and the new bits cleared. When
+// the MFT Bitmap is in the Nonresident form, then the allocation should
+// always be sufficient to store enough bits to describe the MFT, however
+// ValidDataLength insures that newly allocated space to the MFT Bitmap
+// has an initial value of all 0's. This means that if the MFT Bitmap is
+// extended, the newly represented file record segments are automatically in
+// the free state.
+//
+// No structure definition is required; the positional offset of the file
+// record segment is exactly equal to the bit offset of its corresponding
+// bit in the Bitmap.
+//
+
+//
+// The utilities attempt to allocate a more disk space than necessary for
+// the initial MFT Bitmap to allow for future growth.
+//
+
+#define MFT_BITMAP_INITIAL_SIZE 0x2000 /* bytes of bitmap */
+
+
+//
+// Symbolic Link attribute ****TBS
+//
+
+typedef struct _SYMBOLIC_LINK {
+
+ LARGE_INTEGER Tbs;
+
+} SYMBOLIC_LINK;
+typedef SYMBOLIC_LINK *PSYMBOLIC_LINK;
+
+
+//
+// Ea Information attribute
+//
+
+typedef struct _EA_INFORMATION {
+
+ USHORT PackedEaSize; // Size of buffer to hold in unpacked form
+ USHORT NeedEaCount; // Count of EA's with NEED_EA bit set
+ ULONG UnpackedEaSize; // Size of buffer to hold in packed form
+
+} EA_INFORMATION;
+
+
+typedef EA_INFORMATION *PEA_INFORMATION;
+
+struct PACKED_EA {
+ UCHAR Flag;
+ UCHAR NameSize;
+ UCHAR ValueSize[2]; // Was USHORT.
+ CHAR Name[1];
+};
+
+DEFINE_POINTER_TYPES( PACKED_EA );
+
+#define EA_FLAG_NEED 0x80
+
+//
+// SLEAZY_LARGE_INTEGER is used because x86 C8 won't allow us to
+// do static init on a union (like LARGE_INTEGER) and we can't use
+// BIG_INT for cases where we need to static-init an array with a non-
+// default constructor. The bit pattern must be the same as
+// LARGE_INTEGER.
+//
+typedef struct _SLEAZY_LARGE_INTEGER {
+ ULONG LowPart;
+ LONG HighPart;
+} SLEAZY_LARGE_INTEGER, *PSLEAZY_LARGE_INTEGER;
+
+
+//
+// Attribute Definition Table
+//
+// The following struct defines the columns of this table. Initially they
+// will be stored as simple records, and ordered by Attribute Type Code.
+//
+
+typedef struct _ATTRIBUTE_DEFINITION_COLUMNS {
+
+ //
+ // Unicode attribute name.
+ //
+
+ WCHAR AttributeName[64];
+
+ //
+ // Attribute Type Code.
+ //
+
+ ATTRIBUTE_TYPE_CODE AttributeTypeCode;
+
+ //
+ // Default Display Rule for this attribute
+ //
+
+ DISPLAY_RULE DisplayRule;
+
+ //
+ // Default Collation rule
+ //
+
+ COLLATION_RULE CollationRule;
+
+ //
+ // ATTRIBUTE_DEF_xxx flags
+ //
+
+ ULONG Flags;
+
+ //
+ // Minimum Length for attribute, if present.
+ //
+
+ SLEAZY_LARGE_INTEGER MinimumLength;
+
+ //
+ // Maximum Length for attribute.
+ //
+
+ SLEAZY_LARGE_INTEGER MaximumLength;
+
+} ATTRIBUTE_DEFINITION_COLUMNS;
+
+DEFINE_POINTER_TYPES( ATTRIBUTE_DEFINITION_COLUMNS );
+
+//
+// ATTRIBUTE_DEF_xxx flags
+//
+
+//
+// This flag is set if the attribute may be indexed.
+//
+
+#define ATTRIBUTE_DEF_INDEXABLE (0x00000002)
+
+//
+// This flag is set if the attribute may occur more than once, such as is
+// allowed for the File Name attribute.
+//
+
+#define ATTRIBUTE_DEF_DUPLICATES_ALLOWED (0x00000004)
+
+//
+// This flag is set if the value of the attribute may not be entirely
+// null, i.e., all binary 0's.
+//
+
+#define ATTRIBUTE_DEF_MAY_NOT_BE_NULL (0x00000008)
+
+//
+// This attribute must be indexed, and no two attributes may exist with
+// the same value in the same file record segment.
+//
+
+#define ATTRIBUTE_DEF_MUST_BE_INDEXED (0x00000010)
+
+//
+// This attribute must be named, and no two attributes may exist with
+// the same name in the same file record segment.
+//
+
+#define ATTRIBUTE_DEF_MUST_BE_NAMED (0x00000020)
+
+//
+// This attribute must be in the Resident Form.
+//
+
+#define ATTRIBUTE_DEF_MUST_BE_RESIDENT (0x00000040)
+
+//
+// Modifications to this attribute should be logged even if the
+// attribute is nonresident.
+//
+
+#define ATTRIBUTE_DEF_LOG_NONRESIDENT (0X00000080)
+
+//
+// The remaining stuff in this file describes some of the lfs data
+// structures; some of these are used by chkdsk, and some are used
+// only by diskedit.
+//
+
+typedef struct _MULTI_SECTOR_HEADER {
+
+ //
+ // Space for a four-character signature
+ //
+
+ UCHAR Signature[4];
+
+ //
+ // Offset to Update Sequence Array, from start of structure. The Update
+ // Sequence Array must end before the last USHORT in the first "sector"
+ // of size SEQUENCE_NUMBER_STRIDE. (I.e., with the current constants,
+ // the sum of the next two fields must be <= 510.)
+ //
+
+ USHORT UpdateSequenceArrayOffset;
+
+ //
+ // Size of Update Sequence Array (from above formula)
+ //
+
+ USHORT UpdateSequenceArraySize;
+
+} MULTI_SECTOR_HEADER, *PMULTI_SECTOR_HEADER;
+
+
+typedef struct _LFS_RESTART_PAGE_HEADER {
+
+ //
+ // Cache multisector protection header.
+ //
+
+ MULTI_SECTOR_HEADER MultiSectorHeader;
+
+ //
+ // This is the last Lsn found by checkdisk for this volume.
+ //
+
+ LSN ChkDskLsn;
+
+ //
+ //
+
+ ULONG SystemPageSize;
+ ULONG LogPageSize;
+
+ //
+ // Lfs restart area offset. This is the offset from the start of this
+ // structure to the Lfs restart area.
+ //
+
+ USHORT RestartOffset;
+
+ USHORT MinorVersion;
+ USHORT MajorVersion;
+
+ //
+ // Update Sequence Array. Used to protect the page blcok.
+ //
+
+ UPDATE_SEQUENCE_ARRAY UpdateSequenceArray;
+
+} LFS_RESTART_PAGE_HEADER, *PLFS_RESTART_PAGE_HEADER;
+
+//
+// Log Client Record. A log client record exists for each client user of
+// the log file. One of these is in each Lfs restart area.
+//
+
+#define LFS_NO_CLIENT 0xffff
+#define LFS_CLIENT_NAME_MAX 64
+
+typedef struct _LFS_CLIENT_RECORD {
+
+ //
+ // Oldest Lsn. This is the oldest Lsn that this client requires to
+ // be in the log file.
+ //
+
+ LSN OldestLsn;
+
+ //
+ // Client Restart Lsn. This is the Lsn of the latest client restart
+ // area written to the disk. A reserved Lsn will indicate that no
+ // restart area exists for this client.
+ //
+
+ LSN ClientRestartLsn;
+
+ //
+ //
+ // Previous/Next client area. These are the indexes into an array of
+ // Log Client Records for the previous and next client records.
+ //
+
+ USHORT PrevClient;
+ USHORT NextClient;
+
+ //
+ // Sequence Number. Incremented whenever this record is reused. This
+ // will happen whenever a client opens (reopens) the log file and has
+ // no current restart area.
+
+ USHORT SeqNumber;
+
+ //
+ // Alignment field.
+ //
+
+ USHORT AlignWord;
+
+ //
+ // Align the entire record.
+ //
+
+ ULONG AlignDWord;
+
+ //
+ // The following fields are used to describe the client name. A client
+ // name consists of at most 32 Unicode character (64 bytes). The Log
+ // file service will treat client names as case sensitive.
+ //
+
+ ULONG ClientNameLength;
+
+ WCHAR ClientName[LFS_CLIENT_NAME_MAX];
+
+} LFS_CLIENT_RECORD, *PLFS_CLIENT_RECORD;
+
+typedef struct _LFS_RESTART_AREA {
+
+ LSN CurrentLsn;
+ USHORT LogClients;
+ USHORT ClientFreeList;
+ USHORT ClientInUseList;
+
+ USHORT Flags;
+ ULONG SeqNumberBits;
+ USHORT RestartAreaLength;
+ USHORT ClientArrayOffset;
+ LONGLONG FileSize;
+ ULONG LastLsnDataLength;
+ USHORT RecordHeaderLength;
+ USHORT LogPageDataOffset;
+ LFS_CLIENT_RECORD LogClientArray[1];
+
+} LFS_RESTART_AREA, *PLFS_RESTART_AREA;
+
+#pragma pack()
+
+#endif // _UNTFS_DEFN_
diff --git a/private/utils/untfs/inc/upcase.hxx b/private/utils/untfs/inc/upcase.hxx
new file mode 100644
index 000000000..142e1f24a
--- /dev/null
+++ b/private/utils/untfs/inc/upcase.hxx
@@ -0,0 +1,275 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ upcase.hxx
+
+Abstract:
+
+ This module contains the declarations for the NTFS_UPCASE_TABLE
+ class. This class models the upcase table stored on an NTFS volume,
+ which is used to upcase attribute names and file names resident
+ on that volume.
+
+Author:
+
+ Bill McJohn (billmc) 04-March-92
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#if !defined( _NTFS_UPCASE_TABLE_DEFN_ )
+
+#define _NTFS_UPCASE_TABLE_DEFN_
+
+DECLARE_CLASS( NTFS_ATTRIBUTE );
+DECLARE_CLASS( NTFS_BITMAP );
+DECLARE_CLASS( NTFS_UPCASE_TABLE );
+
+#include "attrib.hxx"
+
+// This function is used to compare two NTFS names. Its definition
+// appears in upcase.cxx.
+//
+LONG
+UNTFS_EXPORT
+NtfsUpcaseCompare(
+ IN PCWSTR LeftName,
+ IN ULONG LeftNameLength,
+ IN PCWSTR RightName,
+ IN ULONG RightNameLength,
+ IN PCNTFS_UPCASE_TABLE UpcaseTable,
+ IN BOOLEAN CaseSensitive
+ );
+
+class NTFS_UPCASE_TABLE : public OBJECT {
+
+ public:
+
+ UNTFS_EXPORT
+ DECLARE_CONSTRUCTOR( NTFS_UPCASE_TABLE );
+
+ VIRTUAL
+ UNTFS_EXPORT
+ ~NTFS_UPCASE_TABLE(
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Initialize(
+ IN PNTFS_ATTRIBUTE Attribute
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PWCHAR Data,
+ IN ULONG Length
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Verify(
+ ) CONST;
+
+ NONVIRTUAL
+ WCHAR
+ UpperCase(
+ IN WCHAR Character
+ ) CONST;
+
+ NONVIRTUAL
+ BOOLEAN
+ Write(
+ IN OUT PNTFS_ATTRIBUTE Attribute,
+ IN OUT PNTFS_BITMAP VolumeBitmap OPTIONAL
+ );
+
+ NONVIRTUAL
+ PCWCHAR
+ GetUpcaseArray(
+ OUT PULONG Length
+ ) CONST;
+
+ STATIC
+ ULONG
+ QueryDefaultLength(
+ );
+
+ STATIC
+ ULONG
+ QueryDefaultSize(
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ PWCHAR _Data;
+ ULONG _Length;
+};
+
+
+INLINE
+WCHAR
+NTFS_UPCASE_TABLE::UpperCase(
+ IN WCHAR Character
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the upper-case value of the supplied
+ character.
+
+Arguments:
+
+ Character -- Supplies the character to upcase.
+
+Notes:
+
+ If Character is not in the table (ie. is greater or equal
+ to _Length), it upcases to itself.
+
+--*/
+{
+ return( (Character < _Length) ? _Data[Character] : Character );
+}
+
+
+INLINE
+BOOLEAN
+NTFS_UPCASE_TABLE::Write(
+ IN OUT PNTFS_ATTRIBUTE Attribute,
+ IN OUT PNTFS_BITMAP VolumeBitmap
+ )
+/*++
+
+Routine Description:
+
+ This method writes the upcase table through the supplied
+ attribute.
+
+Arguments:
+
+ Attribute -- Supplies the attribute which has the upcase
+ table as its value.
+ VolumeBitmap -- Supplies the volume bitmap. This parameter
+ may be omitted if the attribute is already
+ the correct size.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ ULONG BytesInTable, BytesWritten;
+
+ BytesInTable = _Length * sizeof( WCHAR );
+
+ return( Attribute->Resize( _Length, VolumeBitmap ) &&
+ Attribute->Write( _Data,
+ 0,
+ BytesInTable,
+ &BytesWritten,
+ VolumeBitmap ) &&
+ BytesWritten == BytesInTable );
+
+}
+
+
+INLINE
+PCWCHAR
+NTFS_UPCASE_TABLE::GetUpcaseArray(
+ OUT PULONG Length
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the in-memory upcase array.
+
+Arguments:
+
+ Length - Returns the number of characters in the array.
+
+Return Value:
+
+ The in-memory upcase array.
+
+--*/
+{
+ *Length = _Length;
+ return _Data;
+}
+
+
+INLINE
+ULONG
+NTFS_UPCASE_TABLE::QueryDefaultLength(
+ )
+/*++
+
+Routine Description:
+
+ This method returns the length (in characters) of the
+ default upcase table.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The length (in characters) of the default upcase table.
+
+--*/
+{
+ return 0x10000;
+}
+
+
+INLINE
+ULONG
+NTFS_UPCASE_TABLE::QueryDefaultSize(
+ )
+/*++
+
+Routine Description:
+
+ This method returns the size of the default upcase table.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The size of the default upcase table.
+
+--*/
+{
+ return( QueryDefaultLength() * sizeof( WCHAR ) );
+}
+
+#endif
diff --git a/private/utils/untfs/inc/upfile.hxx b/private/utils/untfs/inc/upfile.hxx
new file mode 100644
index 000000000..fef7e91f3
--- /dev/null
+++ b/private/utils/untfs/inc/upfile.hxx
@@ -0,0 +1,86 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ upfile.hxx
+
+Abstract:
+
+ This module contains the declarations for the NTFS_UPCASE_FILE
+ class, which models the upcase-table file for an NTFS volume.
+ This class' main purpose in life is to encapsulate the creation
+ of this file.
+
+Author:
+
+ Bill McJohn (billmc) 04-March-1992
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+#if !defined( NTFS_UPCASE_FILE_DEFN )
+
+#define NTFS_UPCASE_FILE_DEFN
+
+#include "frs.hxx"
+
+DECLARE_CLASS( NTFS_BITMAP );
+DECLARE_CLASS( NTFS_UPCASE_TABLE );
+
+class NTFS_UPCASE_FILE : public NTFS_FILE_RECORD_SEGMENT {
+
+ public:
+
+ UNTFS_EXPORT
+ DECLARE_CONSTRUCTOR( NTFS_UPCASE_FILE );
+
+ VIRTUAL
+ UNTFS_EXPORT
+ ~NTFS_UPCASE_FILE(
+ );
+
+ NONVIRTUAL
+ UNTFS_EXPORT
+ BOOLEAN
+ Initialize(
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Create(
+ IN PCSTANDARD_INFORMATION StandardInformation,
+ IN PNTFS_UPCASE_TABLE UpcaseTable,
+ IN OUT PNTFS_BITMAP VolumeBitmap
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ VerifyAndFix(
+ IN OUT PNTFS_UPCASE_TABLE UpcaseTable,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNUMBER_SET BadClusters,
+ IN OUT PNTFS_INDEX_TREE RootIndex,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ );
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+};
+
+#endif
diff --git a/private/utils/untfs/src/attrcol.cxx b/private/utils/untfs/src/attrcol.cxx
new file mode 100644
index 000000000..e82753d7f
--- /dev/null
+++ b/private/utils/untfs/src/attrcol.cxx
@@ -0,0 +1,201 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "untfs.hxx"
+#include "attrcol.hxx"
+
+#include "attrib.hxx"
+
+
+DEFINE_CONSTRUCTOR( NTFS_ATTRIBUTE_COLUMNS, OBJECT );
+
+NTFS_ATTRIBUTE_COLUMNS::~NTFS_ATTRIBUTE_COLUMNS(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for NTFS_ATTRIBUTE_COLUMNS.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+NTFS_ATTRIBUTE_COLUMNS::Construct(
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the class to an initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _columns = NULL;
+ _num_columns = 0;
+}
+
+
+VOID
+NTFS_ATTRIBUTE_COLUMNS::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the class to an initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DELETE(_columns);
+ _num_columns = 0;
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE_COLUMNS::Initialize(
+ IN ULONG NumberOfColumns,
+ IN PATTRIBUTE_DEFINITION_COLUMNS Columns
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the class to a valid initial state.
+
+Arguments:
+
+ NumberOfColumns - Supplies the number of columns.
+ Columns - Supplies 'NumberOfColumns' columns to
+ initialize to. This parameter is optional.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ Destroy();
+
+ _num_columns = NumberOfColumns;
+
+ // NOTE: use old new for vectors.
+ if (!(_columns = NEW ATTRIBUTE_DEFINITION_COLUMNS[_num_columns])) {
+ Destroy();
+ return FALSE;
+ }
+
+ if (Columns) {
+ memcpy(_columns, Columns,
+ (UINT) (NumberOfColumns*sizeof(ATTRIBUTE_DEFINITION_COLUMNS)));
+ }
+
+ return TRUE;
+}
+
+
+NONVIRTUAL
+BOOLEAN
+NTFS_ATTRIBUTE_COLUMNS::Read(
+ IN OUT PNTFS_ATTRIBUTE AttributeDefinitionTableData
+ )
+/*++
+
+Routine Description:
+
+ This routine reads in the attribute definition columns from disk.
+
+Arguments:
+
+ AttributeDefinitionTableData - Supplies the data attribute of the
+ attribute definition table.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG bytes_to_read;
+ ULONG bytes_read;
+
+ bytes_to_read = _num_columns*sizeof(ATTRIBUTE_DEFINITION_COLUMNS);
+
+ return AttributeDefinitionTableData->Read(_columns,
+ 0,
+ bytes_to_read,
+ &bytes_read) &&
+ (bytes_read == bytes_to_read);
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE_COLUMNS::QueryIndex(
+ IN ATTRIBUTE_TYPE_CODE AttributeCode,
+ OUT PULONG Index
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the location of the column for
+ 'AttributeCode' and sets the internal pointer to that
+ column. This makes it so that subsequent 'Query' operations
+ are for the attribute type of 'AttributeCode'.
+
+Arguments:
+
+ AttributeCode - Supplies the attribute type code to search for.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG i;
+
+ DebugAssert(Index);
+
+ for (i = 0; i < _num_columns; i++) {
+ if (_columns[i].AttributeTypeCode == AttributeCode) {
+ *Index = i;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
diff --git a/private/utils/untfs/src/attrdef.cxx b/private/utils/untfs/src/attrdef.cxx
new file mode 100644
index 000000000..188950db9
--- /dev/null
+++ b/private/utils/untfs/src/attrdef.cxx
@@ -0,0 +1,484 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ attrdef.hxx
+
+Abstract:
+
+ This module contains the member function definitions for
+ the NTFS_ATTRIBUTE_DEFINITION_TABLE class, which models
+ the attribute definition table file for an NTFS volume.
+
+Author:
+
+ Bill McJohn (billmc) 17-June-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "untfs.hxx"
+
+#include "drive.hxx"
+#include "attrib.hxx"
+#include "ntfsbit.hxx"
+#include "attrdef.hxx"
+#include "ifssys.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+#include "attrcol.hxx"
+
+// This is the initial table:
+
+ATTRIBUTE_DEFINITION_COLUMNS
+ NtfsAttributeDefinitions[NumberOfNtfsAttributeDefinitions] =
+
+{
+ {{'$','S','T','A','N','D','A','R','D','_','I','N','F','O','R','M','A','T','I','O','N'},
+ $STANDARD_INFORMATION, // Attribute code
+ 0, // Display rule
+ 0, // Collation rule
+ ATTRIBUTE_DEF_MUST_BE_RESIDENT, // Flags
+ {sizeof(STANDARD_INFORMATION), 0}, // Minimum length
+ {sizeof(STANDARD_INFORMATION), 0}}, // Maximum length
+
+ {{'$','A','T','T','R','I','B','U','T','E','_','L','I','S','T'},
+ $ATTRIBUTE_LIST, // Attribute code
+ 0, // Display rule
+ 0, // Collation rule
+ ATTRIBUTE_DEF_LOG_NONRESIDENT, // Flags
+ {0,0}, // Minimum length
+ {MAXULONG,MAXULONG}}, // Maximum length
+
+ {{'$','F','I','L','E','_','N','A','M','E'},
+ $FILE_NAME, // Attribute code
+ 0, // Display rule
+ 0, // Collation rule
+ ATTRIBUTE_DEF_MUST_BE_RESIDENT | ATTRIBUTE_DEF_INDEXABLE, // Flags
+ {sizeof(FILE_NAME), 0}, // Minimum length
+ {sizeof(FILE_NAME) + (255 * sizeof(WCHAR)), 0}}, // Maximum length
+
+ {{'$','V','O','L','U','M','E','_','V','E','R','S','I','O','N'},
+ $VOLUME_VERSION, // Attribute code
+ 0, // Display rule
+ 0, // Collation rule
+ ATTRIBUTE_DEF_MUST_BE_RESIDENT, // Flags
+ {sizeof(VOLUME_VERSION), 0}, // Minimum length
+ {sizeof(VOLUME_VERSION), 0}}, // Maximum length
+
+ {{'$','S','E','C','U','R','I','T','Y','_','D','E','S','C','R','I','P','T','O','R'},
+ $SECURITY_DESCRIPTOR, // Attribute code
+ 0, // Display rule
+ 0, // Collation rule
+ ATTRIBUTE_DEF_LOG_NONRESIDENT, // Flags
+ {0,0}, // Minimum length
+ {MAXULONG,MAXULONG}}, // Maximum length
+
+ {{'$','V','O','L','U','M','E','_','N','A','M','E'},
+ $VOLUME_NAME, // Attribute code
+ 0, // Display rule
+ 0, // Collation rule
+ ATTRIBUTE_DEF_MUST_BE_RESIDENT, // Flags
+ {2,0}, // Minimum length
+ {256,0}}, // Maximum length
+
+ {{'$','V','O','L','U','M','E','_','I','N','F','O','R','M','A','T','I','O','N'},
+ $VOLUME_INFORMATION, // Attribute code
+ 0, // Display rule
+ 0, // Collation rule
+ ATTRIBUTE_DEF_MUST_BE_RESIDENT, // Flags
+ {sizeof(VOLUME_INFORMATION),0}, // Minimum length
+ {sizeof(VOLUME_INFORMATION),0}}, // Maximum length
+
+ {{'$','D','A','T','A'},
+ $DATA, // Attribute code
+ 0, // Display rule
+ 0, // Collation rule
+ 0, // Flags
+ {0,0}, // Minimum length
+ {MAXULONG,MAXULONG}}, // Maximum length
+
+ {{'$','I','N','D','E','X','_','R','O','O','T'},
+ $INDEX_ROOT, // Attribute code
+ 0, // Display rule
+ 0, // Collation rule
+ ATTRIBUTE_DEF_MUST_BE_RESIDENT, // Flags
+ {0,0}, // Minimum length
+ {MAXULONG,MAXULONG}}, // Maximum length
+
+ {{'$','I','N','D','E','X','_','A','L','L','O','C','A','T','I','O','N'},
+ $INDEX_ALLOCATION, // Attribute code
+ 0, // Display rule
+ 0, // Collation rule
+ ATTRIBUTE_DEF_LOG_NONRESIDENT, // Flags
+ {0,0}, // Minimum length
+ {MAXULONG,MAXULONG}}, // Maximum length
+
+ {{'$','B','I','T','M','A','P'},
+ $BITMAP, // Attribute code
+ 0, // Display rule
+ 0, // Collation rule
+ ATTRIBUTE_DEF_LOG_NONRESIDENT, // Flags
+ {0,0}, // Minimum length
+ {MAXULONG,MAXULONG}}, // Maximum length
+
+ {{'$','S','Y','M','B','O','L','I','C','_','L','I','N','K'},
+ $SYMBOLIC_LINK, // Attribute code
+ 0, // Display rule
+ 0, // Collation rule
+ ATTRIBUTE_DEF_LOG_NONRESIDENT, // Flags
+ {0,0}, // Minimum length
+ {MAXULONG,MAXULONG}}, // Maximum length
+
+ {{'$','E','A','_','I','N','F','O','R','M','A','T','I','O','N'},
+ $EA_INFORMATION, // Attribute code
+ 0, // Display rule
+ 0, // Collation rule
+ ATTRIBUTE_DEF_MUST_BE_RESIDENT, // Flags
+ {sizeof(EA_INFORMATION), 0}, // Minimum length
+ {sizeof(EA_INFORMATION), 0}}, // Maximum length
+
+ {{'$','E','A',},
+ $EA_DATA, // Attribute code
+ 0, // Display rule
+ 0, // Collation rule
+ 0, // Flags
+ {0,0}, // Minimum length
+ {0x10000,0}} // Maximum length
+};
+
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( NTFS_ATTRIBUTE_DEFINITION_TABLE,
+ NTFS_FILE_RECORD_SEGMENT, UNTFS_EXPORT );
+
+UNTFS_EXPORT
+NTFS_ATTRIBUTE_DEFINITION_TABLE::~NTFS_ATTRIBUTE_DEFINITION_TABLE(
+ )
+{
+ Destroy();
+}
+
+
+VOID
+NTFS_ATTRIBUTE_DEFINITION_TABLE::Construct(
+ )
+/*++
+
+Routine Description:
+
+ Worker function for the construtor.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ (void) this;
+}
+
+
+VOID
+NTFS_ATTRIBUTE_DEFINITION_TABLE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Worker function for destruction/reinitialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ (void) this;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_ATTRIBUTE_DEFINITION_TABLE::Initialize(
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft
+ )
+/*++
+
+Routine Description:
+
+ This method initializes an Attribute Definition Table object.
+ The only special knowledge that it adds to the File Record Segment
+ initialization is the location within the Master File Table of the
+ Attribute Definition Table.
+
+Arguments:
+
+ Drive -- Supplies the drive on which the segment resides.
+ Mft -- Supplies the volume MasterFile Table.
+ ClusterFactor -- Supplies the volume Cluster Factor.
+
+Return Value:
+
+ TRUE upon successful completion
+
+Notes:
+
+ This class is reinitializable.
+
+
+--*/
+{
+ Destroy();
+
+ return( NTFS_FILE_RECORD_SEGMENT::Initialize( ATTRIBUTE_DEF_TABLE_NUMBER,
+ Mft ) );
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE_DEFINITION_TABLE::Create(
+ IN PCSTANDARD_INFORMATION StandardInformation,
+ IN OUT PNTFS_BITMAP VolumeBitmap
+ )
+/*++
+
+Routine Description:
+
+ This method formats a Attribute Definition Table File Record
+ Segment in memory (without writing it to disk).
+
+Arguments:
+
+ StandardInformation -- supplies the standard information for the
+ file record segment.
+ VolumeBitmap -- supplies the bitmap for the volume on
+ which this object resides.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ NTFS_ATTRIBUTE DataAttribute;
+ NTFS_EXTENT_LIST Extents;
+ LCN FirstLcn;
+ ULONG Size;
+ ULONG NumberOfClusters;
+ ULONG BytesWritten;
+ ULONG ClusterSize;
+
+ // Set this object up as a File Record Segment.
+
+ if( !NTFS_FILE_RECORD_SEGMENT::Create( StandardInformation ) ) {
+
+ return FALSE;
+ }
+
+ // The Attribute Definition Table has a data attribute whose value
+ // consists of the attribute definition table. The initial table,
+ // with the system-defined attributes, is copied into this attribute.
+
+ Size = QueryDefaultSize();
+
+ ClusterSize = GetDrive()->QuerySectorSize() * QueryClusterFactor();
+
+ NumberOfClusters = Size/ClusterSize;
+
+ if( Size % ClusterSize ) {
+
+ NumberOfClusters += 1;
+ }
+
+ if( !Extents.Initialize( 0, 0 ) ||
+ !Extents.Resize( NumberOfClusters, VolumeBitmap ) ||
+ !DataAttribute.Initialize( GetDrive(),
+ QueryClusterFactor(),
+ &Extents,
+ Size,
+ Size,
+ $DATA ) ||
+ !DataAttribute.Write( (PVOID)NtfsAttributeDefinitions,
+ 0,
+ Size,
+ &BytesWritten,
+ VolumeBitmap ) ||
+ BytesWritten != Size ||
+ !DataAttribute.InsertIntoFile( this, VolumeBitmap ) ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+NTFS_ATTRIBUTE_DEFINITION_TABLE::VerifyAndFix(
+ IN OUT PNTFS_ATTRIBUTE_COLUMNS AttributeDefTable,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNUMBER_SET BadClusters,
+ IN OUT PNTFS_INDEX_TREE RootIndex,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine compares the given attribute definition table with
+ the one contained in this file's DATA attribute and ensures
+ that both are the same. The in-memory version will override the
+ on-disk version.
+
+Arguments:
+
+ AttributeDefTable - Supplies the in-memory version of the table.
+ VolumeBitmap - Supplies the volume bitmap.
+ BadClusters - Supplies the list of bad clusters.
+ RootIndex - Supplies the root index.
+ FixLevel - Supplies the fix up level.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_ATTRIBUTE data_attribute;
+ BOOLEAN errors;
+ ULONG num_columns;
+ ULONG value_length;
+ PCATTRIBUTE_DEFINITION_COLUMNS mem_columns;
+ PATTRIBUTE_DEFINITION_COLUMNS disk_columns;
+ ULONG num_bytes;
+ NTFS_EXTENT_LIST extent_list;
+ BOOLEAN ErrorInAttribute;
+
+ errors = FALSE;
+
+ mem_columns = AttributeDefTable->GetColumns(&num_columns);
+ value_length = num_columns*sizeof(ATTRIBUTE_DEFINITION_COLUMNS);
+
+ if (!(disk_columns = new ATTRIBUTE_DEFINITION_COLUMNS[num_columns])) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!QueryAttribute(&data_attribute, &ErrorInAttribute, $DATA)) {
+
+ if (!extent_list.Initialize(0, 0) ) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!data_attribute.Initialize(GetDrive(),
+ QueryClusterFactor(),
+ &extent_list,
+ 0,
+ 0,
+ $DATA)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+
+ }
+ }
+
+ if (value_length != data_attribute.QueryValueLength() ||
+ !data_attribute.Read(disk_columns, 0, value_length, &num_bytes) ||
+ num_bytes != value_length ||
+ memcmp(mem_columns, disk_columns, value_length)) {
+
+ if (!errors) {
+ Message->Set(MSG_CHK_NTFS_CORRECTING_ATTR_DEF);
+ Message->Display();
+ errors = TRUE;
+ }
+
+ if (FixLevel != CheckOnly) {
+ if (!data_attribute.MakeNonresident(VolumeBitmap) ||
+ !data_attribute.Resize(value_length, VolumeBitmap) ||
+ !data_attribute.Write(mem_columns, 0, value_length, &num_bytes,
+ VolumeBitmap) ||
+ value_length != num_bytes) {
+
+ if (!data_attribute.RecoverAttribute(VolumeBitmap, BadClusters) ||
+ !data_attribute.Write(mem_columns, 0, value_length,
+ &num_bytes, VolumeBitmap) ||
+ value_length != num_bytes) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_ATTR_DEF);
+ Message->Display();
+ return FALSE;
+ }
+ }
+ }
+
+ if (!data_attribute.InsertIntoFile(this, VolumeBitmap)) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_ATTR_DEF);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ if (FixLevel != CheckOnly && !Flush(VolumeBitmap, RootIndex)) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_ATTR_DEF);
+ Message->Display();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+ULONG
+NTFS_ATTRIBUTE_DEFINITION_TABLE::QueryDefaultSize(
+ )
+/*++
+
+Routine Description:
+
+ This method returns the size of the default upcase table.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The size of the default upcase table;
+
+--*/
+{
+ return( sizeof( NtfsAttributeDefinitions ) );
+}
diff --git a/private/utils/untfs/src/attrib.cxx b/private/utils/untfs/src/attrib.cxx
new file mode 100644
index 000000000..9c872eb38
--- /dev/null
+++ b/private/utils/untfs/src/attrib.cxx
@@ -0,0 +1,3533 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ attrib.cxx
+
+Abstract:
+
+ This module contains member function definitions for NTFS_ATTRIBUTE,
+ which models an NTFS attribute instance.
+
+Author:
+
+ Bill McJohn (billmc) 21-June-91
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "untfs.hxx"
+
+#include "cmem.hxx"
+#include "drive.hxx"
+#include "mft.hxx"
+#include "attrrec.hxx"
+#include "attrib.hxx"
+#include "frs.hxx"
+#include "ntfsbit.hxx"
+#include "badfile.hxx"
+#include "numset.hxx"
+
+// This constant specifies the maximum number of clusters Read and
+// Write will try to transfer at once. Note that it is chosen to
+// ensure that MaximumClustersToTransfer * ClusterSize will fito
+// in a ULONG.
+
+CONST MaximumClustersToTransfer = 32;
+
+DEFINE_EXPORTED_CONSTRUCTOR( NTFS_ATTRIBUTE, OBJECT, UNTFS_EXPORT );
+
+
+UNTFS_EXPORT
+NTFS_ATTRIBUTE::~NTFS_ATTRIBUTE(
+ )
+{
+ Destroy();
+}
+
+
+VOID
+NTFS_ATTRIBUTE::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Worker method for object construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _Type = 0;
+ _Flags = 0;
+ _CompressionUnit = 0;
+ _ValueLength = 0;
+ _ValidDataLength = 0;
+
+ _ResidentData = NULL;
+ _ExtentList = NULL;
+
+ _StorageModified = FALSE;
+}
+
+
+VOID
+NTFS_ATTRIBUTE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Worker method for object destruction or reinitialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _Type = 0;
+
+ _Flags = 0;
+ _CompressionUnit = 0;
+ _ValueLength = 0;
+ _ValidDataLength = 0;
+
+ if( _ResidentData != NULL ) {
+
+ FREE( _ResidentData );
+ _ResidentData = NULL;
+ }
+
+ if( _ExtentList != NULL ) {
+
+ DELETE( _ExtentList );
+ _ExtentList = NULL;
+ }
+
+ _StorageModified = FALSE;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_ATTRIBUTE::Initialize (
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN ULONG ClusterFactor,
+ IN PCVOID Value,
+ IN ULONG ValueLength,
+ IN ATTRIBUTE_TYPE_CODE TypeCode,
+ IN PCWSTRING Name,
+ IN USHORT Flags
+ )
+/*++
+
+Routine Description:
+
+ This method initializes a resident attribute based on its value.
+
+Arguments:
+
+
+ Drive -- supplies the drive on which the attribute resides
+ ClusterFactor -- supplies the cluster factor for that drive
+ Value -- supplies the attribute's value.
+ ValueLength -- supplies the length of the attribute's value.
+ TypeCode -- supplies the attribute's type code.
+ Name -- supplies the attribute's name. NULL indicates
+ that the attribute has no name.
+ Flags -- supplies the attribute's flags.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ If ValueLength is zero, then this is an empty attribute (and Value
+ may be NULL).
+
+--*/
+{
+ Destroy();
+
+ _Drive = Drive;
+ _ClusterFactor = ClusterFactor;
+ _CompressionUnit = 0;
+
+ if( (_ResidentData = MALLOC( (UINT) ValueLength )) == NULL ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ if (Name) {
+ if (!_Name.Initialize(Name)) {
+ Destroy();
+ return FALSE;
+ }
+ } else {
+ if (!_Name.Initialize("")) {
+ Destroy();
+ return FALSE;
+ }
+ }
+
+
+ // Copy the value into our buffer:
+
+ memcpy( _ResidentData, Value, (UINT) ValueLength );
+
+ _ValueLength = ValueLength;
+ _ValidDataLength = ValueLength;
+
+ _Type = TypeCode;
+ _Flags = Flags;
+ _ResidentFlags = 0;
+ _FormCode = RESIDENT_FORM;
+
+ _StorageModified = TRUE;
+
+ return TRUE;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_ATTRIBUTE::Initialize (
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN ULONG ClusterFactor,
+ IN PCNTFS_EXTENT_LIST Extents,
+ IN BIG_INT ValueLength,
+ IN BIG_INT ValidLength,
+ IN ATTRIBUTE_TYPE_CODE TypeCode,
+ IN PCWSTRING Name,
+ IN USHORT Flags
+ )
+/*++
+
+Routine Description:
+
+ This method initializes a non-resident attribute based on an
+ extent list.
+
+Arguments:
+
+ Drive -- supplies the drive on which the attribute resides
+ ClusterFactor -- supplies the cluster factor for that drive
+ Extents -- supplies the extent list describing the attribute
+ value's disk storage.
+ ValueLength -- supplies the actual length of the attribute's value.
+ ValidLength -- supplies the valid length of the attribute's value.
+ TypeCode -- supplies the attribute's type code.
+ Name -- supplies the attribute's name. NULL indicates
+ that the attribute has no name.
+ Flags -- supplies the attribute's flags.
+
+Return Code:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ Destroy();
+
+ if (Extents->QueryLowestVcn() != 0) {
+ Destroy();
+ return FALSE;
+ }
+
+ _Drive = Drive;
+ _ClusterFactor = ClusterFactor;
+ _CompressionUnit = 0;
+
+ if( (_ExtentList = NEW NTFS_EXTENT_LIST) == NULL ||
+ !_ExtentList->Initialize( Extents ) ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ if (Name) {
+ if (!_Name.Initialize(Name)) {
+ Destroy();
+ return FALSE;
+ }
+ } else {
+ if (!_Name.Initialize("")) {
+ Destroy();
+ return FALSE;
+ }
+ }
+
+ _ResidentData = NULL;
+ _ResidentFlags = 0;
+
+ _ValueLength = ValueLength;
+ _ValidDataLength = ValidLength;
+
+ if (_ValidDataLength > _ValueLength ||
+ _ValueLength > QueryAllocatedLength()) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ _Type = TypeCode;
+ _Flags = Flags;
+ _FormCode = NONRESIDENT_FORM;
+ _StorageModified = TRUE;
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE::Initialize (
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN ULONG ClusterFactor,
+ IN PCNTFS_ATTRIBUTE_RECORD AttributeRecord
+ )
+/*++
+
+Routine Description:
+
+ This method initializes an attribute based on an attribute record.
+
+Arguments:
+
+ Drive -- supplies the drive on which the attribute resides
+ ClusterFactor -- supplies the cluster factor for that drive
+ AttributeRecord -- supplies the attribute record.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ BIG_INT AllocatedLength;
+
+ Destroy();
+
+ if (AttributeRecord->QueryLowestVcn() != 0) {
+ Destroy();
+ return FALSE;
+ }
+
+ _Drive = Drive;
+ _ClusterFactor = ClusterFactor;
+
+ _Type = AttributeRecord->QueryTypeCode();
+ _Flags = AttributeRecord->QueryFlags();
+ _CompressionUnit = (UCHAR)AttributeRecord->QueryCompressionUnit();
+ _StorageModified = FALSE;
+
+ if (!AttributeRecord->QueryName(&_Name)) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ if( AttributeRecord->IsResident() ) {
+
+ _ValueLength = AttributeRecord->QueryResidentValueLength();
+
+ if( (_ResidentData = MALLOC( (UINT) AttributeRecord->
+ QueryResidentValueLength() )) ==
+ NULL ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ // Copy the value into our buffer:
+
+ memcpy( _ResidentData,
+ AttributeRecord->GetResidentValue(),
+ (UINT) AttributeRecord->QueryResidentValueLength() );
+
+ _ValidDataLength = _ValueLength;
+
+ _FormCode = RESIDENT_FORM;
+ _ResidentFlags = AttributeRecord->QueryResidentFlags();
+
+ } else {
+
+ if (!(_ExtentList = NEW NTFS_EXTENT_LIST) ||
+ !AttributeRecord->QueryExtentList(_ExtentList)) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ AttributeRecord->QueryValueLength( &_ValueLength,
+ &AllocatedLength,
+ &_ValidDataLength );
+
+ _FormCode = NONRESIDENT_FORM;
+ _ResidentFlags = 0;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE::AddAttributeRecord (
+ IN PCNTFS_ATTRIBUTE_RECORD AttributeRecord
+ )
+/*++
+
+Routine Description:
+
+ This method adds an attribute record to the attribute.
+
+ This method is intended to be used in inializing the
+ attribute with multiple attribute records.
+
+Arguments:
+
+ AttributeRecord -- supplies the attribute record.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ DSTRING record_name;
+ NTFS_EXTENT_LIST extent_list;
+ NTFS_EXTENT_LIST backup_extent_list;
+ ULONG i, n;
+ VCN vcn;
+ LCN lcn;
+ BIG_INT run_length;
+
+ if (IsResident() || AttributeRecord->IsResident()) {
+
+ // Can't have multiple resident attribute records.
+ return FALSE;
+ }
+
+ DebugAssert(_ExtentList);
+
+ if (_Type != AttributeRecord->QueryTypeCode()) {
+
+ // Attribute record must have the same type code.
+ return FALSE;
+ }
+
+ // The filesystem only cares about and maintains the Flags member
+ // in the first attribute record of a multi-frs attribute. So
+ // I removed the check below, which used to insure that each set
+ // of flags was identical. -mjb.
+
+ if (!AttributeRecord->QueryName(&record_name) ||
+ record_name.Strcmp(&_Name) ||
+ /* _Flags != AttributeRecord->QueryFlags() || */
+ !AttributeRecord->QueryExtentList(&extent_list) ||
+ !backup_extent_list.Initialize(_ExtentList)) {
+
+
+ return FALSE;
+ }
+
+ n = extent_list.QueryNumberOfExtents();
+
+ for (i = 0; i < n; i++) {
+
+ // Query i'th extent from attribute record.
+ if (!extent_list.QueryExtent(i, &vcn, &lcn, &run_length) ||
+ !_ExtentList->AddExtent(vcn, lcn, run_length)) {
+
+ // Restore the extent list.
+ _ExtentList->Initialize(&backup_extent_list);
+
+ return FALSE;
+ }
+ }
+
+ // If the LowestVcn of this record is less than the LowestVcn
+ // of the extent list, update the extent list. If the NextVcn
+ // of this record is greater than the NextVcn of the extent list,
+ // update the extent list. This will cover the cases where the
+ // the attribute is sparse and the new record begins or ends with
+ // a gap
+ //
+ if( AttributeRecord->QueryLowestVcn() < _ExtentList->QueryLowestVcn() ) {
+
+ _ExtentList->SetLowestVcn( AttributeRecord->QueryLowestVcn() );
+ }
+
+ if( AttributeRecord->QueryNextVcn() > _ExtentList->QueryNextVcn() ) {
+
+ _ExtentList->SetNextVcn( AttributeRecord->QueryNextVcn() );
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE::VerifyAndFix(
+ IN BIG_INT VolumeSectors
+ )
+/*++
+
+Routine Description:
+
+ This routine ensures that the allocation of the given
+ attribute is non-self overlapping and that the allocation
+ does not use the clusters reserved for the boot file.
+
+ It also tweeks the allocation sizes if necessary.
+
+Arguments:
+
+ VolumeSectors - Supplies the number of sectors on the volume.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG i;
+ LCN j;
+ LCN lcn;
+ VCN vcn;
+ BIG_INT run_length;
+ NTFS_BITMAP allocated_clusters;
+ NTFS_EXTENT_LIST new_extent_list;
+ BOOLEAN cross_link;
+ BIG_INT num_clusters;
+
+ cross_link = FALSE;
+
+ if (_ExtentList) {
+
+ // Now analyse the mapping pairs for cross-links.
+ // Truncate the attribute at the first offending
+ // cluster.
+
+ num_clusters = VolumeSectors/QueryClusterFactor();
+
+ if (!allocated_clusters.Initialize(num_clusters, FALSE, _Drive,
+ _ClusterFactor) ||
+ !new_extent_list.Initialize(0, 0)) {
+
+ return FALSE;
+ }
+
+ // Mark as allocate sector zero since this always belongs
+ // to the boot file. Don't bother marking n/2 as allocated
+ // because we deal with copying that cross-links there.
+
+ allocated_clusters.SetAllocated(0, 1);
+
+ for (i = 0; _ExtentList->QueryExtent(i, &vcn, &lcn, &run_length); i++) {
+
+ if (LCN_NOT_PRESENT == lcn) {
+ continue;
+ }
+
+ if (!allocated_clusters.IsFree(lcn, run_length)) {
+
+ for (j = 0; j < run_length; j += 1) {
+ if (!allocated_clusters.IsFree(lcn + j, 1)) {
+ break;
+ }
+ }
+
+ if (j > 0 && !new_extent_list.AddExtent(vcn, lcn, j)) {
+ return FALSE;
+ }
+
+ cross_link = TRUE;
+ break;
+ }
+
+ allocated_clusters.SetAllocated(lcn, run_length);
+
+ if (!new_extent_list.AddExtent(vcn, lcn, run_length)) {
+ return FALSE;
+ }
+ }
+ }
+
+ if (cross_link) {
+ if (!_ExtentList->Initialize(&new_extent_list)) {
+ return FALSE;
+ }
+ _StorageModified = TRUE;
+ }
+
+ if (_ValueLength > QueryAllocatedLength()) {
+ _ValueLength = QueryAllocatedLength();
+ _StorageModified = TRUE;
+ }
+
+ if (_ValidDataLength > _ValueLength) {
+ _ValidDataLength = _ValueLength;
+ _StorageModified = TRUE;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+PartitionExtentList(
+ IN PCNTFS_EXTENT_LIST SourceList,
+ IN ULONG MaxSize,
+ OUT PNTFS_EXTENT_LIST ResultList,
+ OUT PNTFS_EXTENT_LIST RemainderList
+ )
+/*++
+
+Routine Description:
+
+ This routine partitions 'SourceList' into 'ResultList' and
+ 'RemainderList'.
+
+ 'ResultList' contains as many extents from 'SourceList' as can be
+ compressed into 'MaxSize' bytes.
+
+ 'RemainderList' contains all of the extents of 'SourceList' which are
+ not in 'ResultList'.
+
+Arguments:
+
+ SourceList - Supplies the list of extents to partition.
+ MaxSize - Supplies the maximum number of bytes for
+ the compressed mapping pairs of the first
+ part of the partition.
+ ResultList - Returns the first part of the partition.
+ RemainderList - Returns the second part of the partition.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ CONST MaxBytesPerMappingPair = sizeof(LCN) + sizeof(VCN) + 1;
+
+ VCN lowest;
+ VCN next;
+ ULONG mapping_length;
+ PUCHAR mapping_space;
+ ULONG buffer_size;
+ ULONG count;
+ ULONG ptr;
+ VCN vcn;
+ LCN lcn;
+ BIG_INT run_length;
+ ULONG i;
+ VCN part_next;
+ ULONG num_extents;
+ UCHAR v, l;
+ BIG_INT tmp;
+ BIG_INT sum;
+ BOOLEAN ends_with_gap = FALSE;
+ BOOLEAN HasHoleInFront;
+
+
+ // Handle an empty list gracefully
+
+ if( SourceList->IsEmpty() ) {
+
+ if( !ResultList->Initialize( SourceList ) ||
+ !RemainderList->Initialize( 0, 0 ) ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+
+ // compute an upper bound for the space required by the compressed
+ // extents of the source extent list.
+
+ buffer_size = MaxBytesPerMappingPair*
+ (2*SourceList->QueryNumberOfExtents() + 1) + 1;
+
+ if ( (mapping_space = (PUCHAR) MALLOC( (UINT) buffer_size )) == NULL ) {
+
+ return FALSE;
+ }
+
+
+ // Get the compressed mapping pairs for the source list.
+
+ // The HasHoleInFront flag allows us to take into account of the
+ // (0, ffffffff. ????) entry at the very beginning of an extented
+ // list. As this entry won't make it into the compression pairs.
+ // The code below that counts the compression pairs and retrieves
+ // vcn/lcn/runlength tuple needs to take into account of this entry.
+
+
+ if (!SourceList->QueryCompressedMappingPairs(&lowest,
+ &next,
+ &mapping_length,
+ buffer_size,
+ mapping_space,
+ &HasHoleInFront)) {
+ FREE(mapping_space);
+ return FALSE;
+ }
+
+ // Let count denote the number of extents in the first partition
+
+ count = 0;
+ ptr = 0;
+ sum = 0;
+ while (mapping_space[ptr] != 0) {
+
+ v = VcnBytesFromCountByte(mapping_space[ptr]);
+ l = LcnBytesFromCountByte(mapping_space[ptr]);
+
+ // Only consider this mapping pair if it will fit along with
+ // the next description byte.
+
+ if (ptr + v + l + 2 > MaxSize) {
+ break;
+ }
+
+ tmp.Set(l, &mapping_space[ptr + v + 1]);
+ sum += tmp;
+
+ // If the number of LCN bytes is 0 or the lcn is -1,
+ // then it's a place holder, not a real extent.
+
+ if (l != 0 && sum != -1) {
+ count++;
+ ends_with_gap = FALSE;
+ } else {
+ ends_with_gap = TRUE;
+ }
+
+ ptr += v + l + 1;
+ }
+
+ // Compute the next VCN of the first partition, which is also the
+ // starting VCN of the remainder.
+ //
+ if (mapping_space[ptr] == 0) {
+
+ // We processed and accepted for the first partition the entire
+ // source list; this means that the result list is the same as
+ // the sources, and the remainder is empty.
+ //
+ part_next = next;
+
+ } else {
+
+ if( ends_with_gap ) {
+
+ // The result partition ends with a gap, which implies that
+ // the remainder starts with a non-gap extent (or else we
+ // would have accepted the entire list). Thus, the starting
+ // VCN of the remainder is the starting VCN of its first
+ // extent.
+ //
+ if (!SourceList->QueryExtent(count + (HasHoleInFront ? 1 : 0),
+ &vcn, &lcn, &run_length)) {
+ return FALSE;
+ }
+ part_next = vcn;
+
+ } else {
+
+ // The result partition ends with a real extent, so the
+ // starting VCN of the remainder is the next VCN after
+ // that extent. Note that the remainder may start with
+ // a gap.
+ //
+ if (!SourceList->QueryExtent(count - (HasHoleInFront ? 0 : 1),
+ &vcn, &lcn, &run_length)) {
+ return FALSE;
+ }
+ part_next = vcn + run_length;
+ }
+ }
+
+ FREE(mapping_space);
+
+
+ // Now that we know how to split it up, create the two partitions.
+
+ if (!ResultList->Initialize(lowest, part_next) ||
+ !RemainderList->Initialize(part_next, next)) {
+
+ return FALSE;
+ }
+
+ num_extents = SourceList->QueryNumberOfExtents();
+
+ for (i = 0; i < num_extents; i++) {
+
+ if (!SourceList->QueryExtent(i, &vcn, &lcn, &run_length)) {
+ return FALSE;
+ }
+ if (LCN_NOT_PRESENT == lcn) {
+ count++;
+ continue;
+ }
+
+ if (i < count) {
+
+ if (!ResultList->AddExtent(vcn, lcn, run_length)) {
+ return FALSE;
+ }
+
+ } else {
+
+ if (!RemainderList->AddExtent(vcn, lcn, run_length)) {
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_ATTRIBUTE::InsertIntoFile (
+ IN OUT PNTFS_FILE_RECORD_SEGMENT BaseFileRecordSegment,
+ IN OUT PNTFS_BITMAP Bitmap
+ )
+/*++
+
+
+Routine Description:
+
+ This method inserts the attribute into a File Record Segment.
+ The attribute packages itself up into Attribute Records and
+ jams them into the File Record Segment.
+
+Arguments:
+
+ FileRecordSegment -- Supplies the File Record Segment into
+ which the attribute will jam itself.
+ Bitmap -- Supplies the volume bitmap.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ If the volume bitmap is supplied, the attribute may make itself
+ nonresident, or the File Record Segment may make one or more of
+ its attribute records nonresident or external.
+
+--*/
+{
+ NTFS_ATTRIBUTE_RECORD AttributeRecord;
+ PVOID AttributeRecordData;
+ BOOLEAN Result;
+ ULONG MaxSize;
+ ULONG MaxExtentsSize, CurrentMaxExtentsSize;
+ NTFS_EXTENT_LIST source;
+ NTFS_EXTENT_LIST result;
+ NTFS_EXTENT_LIST remainder;
+ BOOLEAN FirstChunkInserted = FALSE;
+ BOOLEAN Completed = FALSE;
+
+
+ // First purge the attribute out of the file, unless it's indexed.
+
+ if (!IsIndexed()) {
+
+ if (!BaseFileRecordSegment->PurgeAttribute(_Type, &_Name)) {
+ return FALSE;
+ }
+ }
+
+ // If this is the MFT Data attribute, use the private worker method:
+ //
+ if( BaseFileRecordSegment->QueryFileNumber() == MASTER_FILE_TABLE_NUMBER &&
+ QueryTypeCode() == $DATA &&
+ _Name.QueryChCount() == 0 ) {
+
+ // First, try to save the MFT data attribute conservatively,
+ // leaving space for future hotfixing. If that fails (typically
+ // because of bootstrapping problems), fill it to the gills.
+ //
+ if( InsertMftDataIntoFile( BaseFileRecordSegment, Bitmap, TRUE ) ) {
+
+ ResetStorageModified();
+ return TRUE;
+
+ } else {
+
+ Result = BaseFileRecordSegment->PurgeAttribute(_Type, &_Name) &&
+ InsertMftDataIntoFile( BaseFileRecordSegment, Bitmap, FALSE );
+ ResetStorageModified();
+ return Result;
+ }
+ }
+
+
+ // Allocate a buffer to hold attribute records.
+
+ MaxSize = BaseFileRecordSegment->QueryMaximumAttributeRecordSize();
+
+ if( (AttributeRecordData = MALLOC( (UINT) MaxSize )) == NULL ) {
+
+ return FALSE;
+ }
+
+
+ // Handle the resident attribute case:
+
+ if ( _ResidentData != NULL ) {
+
+ if( !AttributeRecord.Initialize( AttributeRecordData, MaxSize ) ) {
+
+ FREE( AttributeRecordData );
+ return FALSE;
+ }
+
+ // The attribute value is resident. Package up a resident
+ // attribute record.
+
+ Result = AttributeRecord.
+ CreateResidentRecord( _ResidentData,
+ _ValueLength.GetLowPart(),
+ _Type,
+ &_Name,
+ _Flags,
+ _ResidentFlags );
+
+ //
+ // Check to see if there is enough space to Create a resident record
+ //
+
+ if (Result) {
+ Result = BaseFileRecordSegment->
+ InsertAttributeRecord( &AttributeRecord );
+
+ FREE( AttributeRecordData );
+ return Result;
+ } else {
+ // Not enough space to do so, make attribute record non-resident
+ if (IsIndexed() || !Bitmap || !MakeNonresident(Bitmap)) {
+ FREE( AttributeRecordData );
+ return FALSE;
+ }
+ }
+ }
+
+
+ // Compute the maximum number of bytes in an extent list.
+ //
+ MaxExtentsSize = MaxSize - SIZE_OF_NONRESIDENT_HEADER;
+ MaxExtentsSize -= QuadAlign(_Name.QueryChCount());
+ Result = source.Initialize(_ExtentList);
+
+ while (Result && !Completed) {
+
+ // Initialize attribute record.
+
+ Result = AttributeRecord.Initialize( AttributeRecordData, MaxSize );
+
+
+ // Partition extent list into two pieces, the first of which
+ // can be made into an attribute record.
+
+ Result = Result &&
+ PartitionExtentList(&source,
+ MaxExtentsSize,
+ &result,
+ &remainder);
+
+
+ // Create the attribute record.
+
+ Result = Result &&
+ AttributeRecord.
+ CreateNonresidentRecord( &result,
+ QueryAllocatedLength(),
+ _ValueLength,
+ _ValidDataLength,
+ _Type,
+ &_Name,
+ _Flags,
+ _CompressionUnit );
+
+
+ // If we were able to package it up, then give the attribute
+ // record to the File Record Segment.
+
+ Result = Result &&
+ BaseFileRecordSegment->
+ InsertAttributeRecord( &AttributeRecord );
+
+
+ // If all of the extents fit in the last record then we are done.
+
+ if (remainder.IsEmpty()) {
+
+ Completed = TRUE;
+
+ } else {
+
+ Result = Result &&
+ source.Initialize(&remainder);
+ }
+ }
+
+
+ ResetStorageModified();
+ FREE( AttributeRecordData );
+ return Result;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_ATTRIBUTE::MakeNonresident (
+ IN OUT PNTFS_BITMAP Bitmap
+ )
+/*++
+
+Routine Description:
+
+ This method makes the attribute value nonresident.
+
+Arguments:
+
+ Bitmap -- supplies the volume bitmap.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ If the attribute is already nonresident, this method succeeds.
+
+--*/
+{
+ NTFS_CLUSTER_RUN ClusterRun;
+ HMEM IntermediateBuffer;
+ LCN Lcn;
+ ULONG DataLength, ClusterSize, ClustersRequired, ClustersAllocated, MaxRunLength;
+ ULONG RunLength;
+
+ if (!IsResident()) {
+
+ // The attribute is already nonresident, which makes
+ // this task pretty easy.
+
+ return TRUE;
+ }
+
+
+ // Since the attribute is resident, its length will fit in a ULONG.
+ //
+ DebugAssert(_ValueLength.GetHighPart() == 0);
+
+ DataLength = _ValueLength.GetLowPart();
+
+ if (DataLength == 0) {
+
+ // This attribute has no data, so we just set up an empty
+ // extent list.
+
+ if ((_ExtentList = NEW NTFS_EXTENT_LIST) == NULL ||
+ !_ExtentList->Initialize( 0, 0 )) {
+
+ return FALSE;
+ }
+
+ FREE(_ResidentData);
+ _ResidentData = NULL;
+
+ _FormCode = NONRESIDENT_FORM;
+ SetStorageModified();
+ return TRUE;
+ }
+
+ // This attribute has data, so we need to allocate disk space
+ // for it, copy it into that disk space, and set up an extent
+ // list that describes that disk space. Determine how many
+ // clusters we need to hold the resident value.
+
+ if ((_ExtentList = NEW NTFS_EXTENT_LIST ) == NULL ||
+ !_ExtentList->Initialize( 0, 0 )) {
+
+ if( _ExtentList != NULL ) {
+
+ DELETE( _ExtentList );
+ _ExtentList = NULL;
+
+ return FALSE;
+ }
+ }
+
+ ClusterSize = _Drive->QuerySectorSize() * _ClusterFactor;
+
+ ClustersRequired = DataLength / ClusterSize;
+ if (DataLength % ClusterSize) {
+
+ ClustersRequired += 1;
+ }
+
+ ClustersAllocated = 0;
+ MaxRunLength = ClustersRequired;
+
+ while (ClustersAllocated < ClustersRequired) {
+
+ //
+ // Never try to allocate more clusters than we need to finish the
+ // allocation.
+ //
+
+ RunLength = min(MaxRunLength, ClustersRequired - ClustersAllocated);
+
+ if (!Bitmap->AllocateClusters( 0, RunLength, &Lcn )) {
+
+ if (RunLength == 1) {
+
+ // Out of disk space.
+ return FALSE;
+ }
+
+ MaxRunLength /= 2;
+ continue;
+ }
+
+ _ExtentList->AddExtent( ClustersAllocated /* vcn */,
+ Lcn,
+ RunLength );
+
+ //
+ // Copy data from the resident attribute value into this chunk of
+ // the nonresident attribute allocation.
+ //
+
+ if (!IntermediateBuffer.Initialize() ||
+ !ClusterRun.Initialize( &IntermediateBuffer, _Drive, Lcn, _ClusterFactor,
+ RunLength )) {
+
+ Bitmap->SetFree( Lcn, RunLength );
+ return FALSE;
+ }
+
+ memset( ClusterRun.GetBuf(), '\0', ClusterSize * RunLength );
+ memcpy( ClusterRun.GetBuf(),
+ PUCHAR(_ResidentData) + ClustersAllocated * ClusterSize,
+ min(ClusterSize * RunLength,
+ DataLength - ClustersAllocated * ClusterSize) );
+
+ if (!ClusterRun.Write()) {
+
+ Bitmap->SetFree( Lcn, RunLength );
+ return FALSE;
+ }
+
+ ClustersAllocated += RunLength;
+ }
+
+ //
+ // We've succeeded in making the attribute value nonresident.
+ // Clean up the resident data and change the state variables.
+ //
+
+ FREE( _ResidentData );
+ _ResidentData = NULL;
+
+ _FormCode = NONRESIDENT_FORM;
+
+ SetStorageModified();
+
+ return TRUE;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_ATTRIBUTE::Resize (
+ IN BIG_INT NewSize,
+ IN OUT PNTFS_BITMAP Bitmap
+ )
+/*++
+
+Routine Description:
+
+ This method changes the file size of an attribute. It will also modify
+ the allocated size appropriately, either extending or truncating it.
+
+Arguments:
+
+ NewSize -- supplies the attribute value's new allocated size.
+ Bitmap -- supplies the volume bitmap. May be NULL.
+
+Return Value:
+
+ None.
+
+Notes:
+
+ If the attribute value is resident and the client attempts to
+ allocate to a new size which is greater than the maximum ULONG,
+ this method will fail. The client must call MakeNonresident first.
+
+ Note that a nonresident attribute cannot be extended without
+ the bitmap; if a nonresident attribute is truncated without
+ a bitmap then the free space is not updated in the bitmap.
+
+--*/
+{
+ BIG_INT NewNumberOfClusters, NewAllocatedSize;
+ PVOID NewData;
+ ULONG ClusterSize;
+
+ if (_ValueLength == NewSize &&
+ QueryAllocatedLength() == NewSize) {
+
+ return TRUE;
+ }
+
+ if( _ResidentData != NULL ) {
+
+ // The attribute value is resident. We just allocate a
+ // new chunk of memory, zero it out, copy in the old value
+ // (or as much of it as fits), and adjust the length fields.
+
+ // Note that we do not allow the client to resize a resident
+ // attribute to a size greater than the maximum ULONG.
+
+ if( NewSize.GetHighPart() == 0 &&
+ (NewData = MALLOC( NewSize.GetLowPart() )) != NULL ) {
+
+ memset( NewData, '\0', NewSize.GetLowPart() );
+ memcpy( NewData,
+ _ResidentData,
+ MIN(_ValueLength.GetLowPart(), NewSize.GetLowPart()) );
+
+ _ValueLength = NewSize;
+ _ValidDataLength = NewSize;
+
+ FREE( _ResidentData );
+ _ResidentData = NewData;
+
+ SetStorageModified();
+
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+ }
+
+ } else {
+
+ // The attribute value is nonresident. First, we round the
+ // allocation size up to a multiple of the volume cluster size.
+ // Since ClusterSize is always a power of two, the use of
+ // the low part of NewSize in this modulo operation is safe.
+
+ ClusterSize = _ClusterFactor * _Drive->QuerySectorSize();
+
+ NewAllocatedSize = NewSize;
+
+ if( NewAllocatedSize % ClusterSize != 0 ) {
+
+ NewAllocatedSize += (ClusterSize - NewAllocatedSize % ClusterSize);
+ }
+
+ NewNumberOfClusters = NewAllocatedSize / ClusterSize;
+
+ DebugAssert( _ExtentList != NULL );
+
+ if( _ExtentList->Resize( NewNumberOfClusters, Bitmap ) ) {
+
+ _ValueLength = NewSize;
+
+ if( _ValidDataLength > _ValueLength ) {
+
+ _ValidDataLength = _ValueLength;
+ }
+
+ SetStorageModified();
+
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+ }
+ }
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE::AddExtent(
+ IN VCN Vcn,
+ IN LCN Lcn,
+ IN BIG_INT RunLength
+ )
+/*++
+
+Routine Description:
+
+ This method adds an extent to the Attribute's allocation. (Note
+ that if the attribute is resident, this method will fail.)
+
+Arguments:
+
+ Vcn -- supplies the starting VCN of the run.
+ Lcn -- supplies the starting LCN of the run.
+ RunLength -- supplies the number of clusters in the run.
+
+Return Value:
+
+ TRUE upon successful completion.
+--*/
+{
+ if( _ExtentList == NULL ) {
+
+ return FALSE;
+
+ } else {
+
+ if ( _ExtentList->AddExtent( Vcn, Lcn, RunLength ) ) {
+
+ SetStorageModified();
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+ }
+ }
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_ATTRIBUTE::Read (
+ OUT PVOID Data,
+ IN BIG_INT ByteOffset,
+ IN ULONG BytesToRead,
+ OUT PULONG BytesRead
+ )
+/*++
+
+Routine Description:
+
+ This method reads data from the attribute's value.
+
+Arguments:
+
+ Data -- supplies the user's buffer, into which data
+ will be read.
+ ByteOffset -- supplies the byte offset into the attribute value
+ at which the read should commence.
+ BytesToRead -- supplies the number of bytes to read.
+ BytesRead -- receives the number of bytes actually read.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ Read will only read up to the attribute's actual length.
+
+ Note that Read ignores the attribute's valid data length.
+
+ Note that if Read fails, the contents of the user's buffer is
+ undefined.
+
+ This method is able to handle sparse attributes.
+
+--*/
+{
+ NTFS_CLUSTER_RUN ClusterRun;
+ HMEM IntermediateBuffer;
+ BIG_INT TempBigInt;
+ BIG_INT RunLength;
+ VCN CurrentVcn;
+ LCN CurrentLcn;
+ PBYTE CurrentData;
+ ULONG BytesToCopy;
+ ULONG OffsetIntoCluster;
+ ULONG ClusterSize;
+ ULONG CurrentRunLength;
+ ULONG RemainingRequest, BytesToZero;
+
+ // First, perform some range-checking. We can only read to
+ // the end of the actual size of the attribute value.
+
+ if( _ValueLength <= ByteOffset ) {
+
+ BytesToRead = 0;
+
+ } else if ( _ValueLength < ByteOffset + BytesToRead ) {
+
+ // Since this difference is less than BytesToRead, this
+ // assignment is safe:
+
+ TempBigInt = _ValueLength - ByteOffset;
+ BytesToRead = TempBigInt.GetLowPart();
+ }
+
+
+ if( _ResidentData != NULL ) {
+
+ // Since the attribute value is resident, we can
+ // just copy it. We've verified above that the request
+ // fits in the allocated space, so there's nothing more
+ // to do except the copy itself.
+
+ memcpy( Data,
+ (PCHAR) _ResidentData + ByteOffset.GetLowPart(),
+ (UINT) BytesToRead );
+
+ } else if ( _ExtentList != NULL ) {
+
+ RemainingRequest = BytesToRead;
+
+ // Now check the valid length. If the entire read is beyond
+ // the end valid data, just zero it out; otherwise, zero out
+ // the portion beyond the end of valid data.
+ //
+ if( _ValidDataLength <= ByteOffset ) {
+
+ // The entire read is beyond the end of valid data.
+ //
+ memset( Data, 0, BytesToRead );
+ *BytesRead = BytesToRead;
+ return TRUE;
+
+ } else if( _ValidDataLength < ByteOffset + BytesToRead ) {
+
+ // Only read the portion up to the end of valid data;
+ // zero the rest out.
+ //
+ TempBigInt = _ValidDataLength - ByteOffset;
+ RemainingRequest = TempBigInt.GetLowPart();
+
+ BytesToZero = BytesToRead - RemainingRequest;
+
+ memset( (PBYTE) Data + RemainingRequest, 0, BytesToZero );
+ }
+
+ // The attribute value is nonresident, so we'll have to go
+ // find it on disk. First, we'll read any leading partial
+ // cluster through an intermediate buffer. Then we'll read
+ // as many whole clusters as there are in the request directly
+ // into the user's buffer. Finally, we'll read any trailing
+ // partial cluster through the intermediate buffer.
+
+ if( RemainingRequest > 0 ) {
+
+ ClusterSize = _ClusterFactor * _Drive->QuerySectorSize();
+ CurrentData = (PBYTE) Data;
+
+ OffsetIntoCluster = (ByteOffset % ClusterSize).GetLowPart();
+
+ if( OffsetIntoCluster != 0 ) {
+
+ // We have a partial leading cluster, so we'll read
+ // it through the intermediate buffer.
+
+ BytesToCopy = MIN( BytesToRead,
+ ClusterSize - OffsetIntoCluster );
+
+ CurrentVcn = ByteOffset / ClusterSize;
+
+ if( !_ExtentList->QueryLcnFromVcn( CurrentVcn,
+ &CurrentLcn,
+ &RunLength ) ) {
+
+
+ return FALSE;
+ }
+
+ if( CurrentLcn == LCN_NOT_PRESENT ) {
+
+ // This part of the request hits a hole in a
+ // sparse file, so we just fill the corresponding
+ // part of the request with zeroes.
+
+ memset( CurrentData, 0, BytesToCopy );
+
+ } else {
+
+ // Read the cluster containing this part of the
+ // request and copy the partial leading cluster
+ // into the client's buffer.
+
+ if( !IntermediateBuffer.Initialize() ||
+ !ClusterRun.Initialize( &IntermediateBuffer,
+ _Drive,
+ CurrentLcn,
+ _ClusterFactor,
+ 1 ) ||
+ !ClusterRun.Read() ) {
+
+ DebugPrint( "Cannot read leading clusters.\n" );
+
+ return FALSE;
+ }
+
+ memcpy( CurrentData,
+ (PBYTE)ClusterRun.GetBuf() + OffsetIntoCluster,
+ (UINT) BytesToCopy );
+ }
+
+ RemainingRequest -= BytesToCopy;
+ CurrentData += BytesToCopy;
+ ByteOffset += BytesToCopy;
+ }
+
+ // Now transfer any complete clusters. Because the
+ // client's buffer may not be suitably aligned, we
+ // have to cycle these through an intermediate buffer.
+
+ while( RemainingRequest >= ClusterSize ) {
+
+ CurrentVcn = ByteOffset / ClusterSize;
+
+ if( !_ExtentList->QueryLcnFromVcn( CurrentVcn,
+ &CurrentLcn,
+ &RunLength ) ) {
+
+ return FALSE;
+ }
+
+ if( RunLength.GetHighPart() != 0 ||
+ RunLength.GetLowPart() >
+ MaximumClustersToTransfer ) {
+
+ CurrentRunLength = MaximumClustersToTransfer;
+
+ } else {
+
+ CurrentRunLength = RunLength.GetLowPart();
+ }
+
+ if( CurrentRunLength * ClusterSize >
+ RemainingRequest ) {
+
+ CurrentRunLength = RemainingRequest/ClusterSize;
+ }
+
+ BytesToCopy = CurrentRunLength * ClusterSize;
+
+ if( CurrentLcn == LCN_NOT_PRESENT ) {
+
+ // This part of the read request falls into a hole
+ // in a sparse attribute, so we can just fill the
+ // client's buffer with zeroes.
+
+ memset( CurrentData, 0, BytesToCopy );
+
+ } else {
+
+ // Read the data into the temporary buffer (used
+ // to avoid alignment problems) and then copy it
+ // into the client's buffer.
+
+ if( !IntermediateBuffer.Initialize( ) ||
+ !ClusterRun.Initialize( &IntermediateBuffer,
+ _Drive,
+ CurrentLcn,
+ _ClusterFactor,
+ CurrentRunLength ) ||
+ !ClusterRun.Read() ) {
+
+ DebugPrint( "Cannot read complete clusters.\n" );
+ return FALSE;
+ }
+
+ memcpy( CurrentData,
+ IntermediateBuffer.GetBuf(),
+ BytesToCopy );
+ }
+
+ RemainingRequest -= BytesToCopy;
+ CurrentData += BytesToCopy;
+ ByteOffset += BytesToCopy;
+ }
+
+ if( RemainingRequest > 0 ) {
+
+ // OK, we have a partial trailing cluster. Read
+ // it through the intermediate buffer.
+
+ BytesToCopy = RemainingRequest;
+
+ CurrentVcn = ByteOffset / ClusterSize;
+
+ if( !_ExtentList->QueryLcnFromVcn( CurrentVcn,
+ &CurrentLcn,
+ &RunLength ) ) {
+
+ return FALSE;
+ }
+
+ if( CurrentLcn == LCN_NOT_PRESENT ) {
+
+ // This part of the read request falls into a hole
+ // in a sparse attribute, so we can just fill the
+ // appropriate part of the client's buffer with
+ // zeroes.
+
+ memset( CurrentData, 0, BytesToCopy );
+
+ } else {
+
+ // Read this part of the request into an intermediate
+ // buffer (to avoid alignment problems) and then
+ // copy the data into the client's buffer.
+
+ if( !IntermediateBuffer.Initialize() ||
+ !ClusterRun.Initialize( &IntermediateBuffer,
+ _Drive,
+ CurrentLcn,
+ _ClusterFactor,
+ 1 ) ||
+ !ClusterRun.Read() ) {
+ DebugPrint( "Cannot read partial clusters.\n" );
+
+ return FALSE;
+ }
+
+
+ // We've read the cluster in question; copy the partial
+ // trailing cluster of our request.
+
+ memcpy( CurrentData,
+ ClusterRun.GetBuf(),
+ (UINT) BytesToCopy );
+ }
+ }
+ }
+
+ } else {
+
+ DebugAbort( "This attribute is neither resident nor nonresident.\n" );
+ return FALSE;
+ }
+
+ *BytesRead = BytesToRead;
+ return TRUE;
+}
+
+
+VOID
+NTFS_ATTRIBUTE::PrimeCache (
+ IN BIG_INT ByteOffset,
+ IN ULONG BytesToRead
+ )
+/*++
+
+Routine Description:
+
+ This routine reads the given range from the attribute. If the drive
+ hierarchy is cached then this will have the effect of priming the
+ cache so that fewer reads are necessary.
+
+Arguments:
+
+ ByteOffset - Supplies where to start the read.
+ BytesToRead - Supplies the number of bytes to read.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ HMEM hmem;
+ PVOID buf;
+ ULONG bytes_read;
+
+ if (hmem.Initialize() &&
+ (buf = hmem.Acquire(BytesToRead))) {
+
+ Read(buf, ByteOffset, BytesToRead, &bytes_read);
+ }
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_ATTRIBUTE::Write (
+ IN PCVOID Data,
+ IN BIG_INT ByteOffset,
+ IN ULONG BytesToWrite,
+ OUT PULONG BytesWritten,
+ IN OUT PNTFS_BITMAP Bitmap
+ )
+
+/*++
+
+Routine Description:
+
+ This method writes data to the attribute's value.
+
+Arguments:
+
+ Data -- supplies the user's buffer containing data
+ to be written
+ ByteOffset -- supplies the byte offset within the attribute's
+ value at shich the write should commence.
+ BytesToWrite -- supplies the number of bytes to write.
+ BytesWritten -- receives the number of bytes written.
+ Bitmap -- supplies the volume bitmap. This may be NULL.
+
+Notes:
+
+ If the user supplies a bitmap, Write will attempt to extend the
+ attribute's allocation (if necessary) in order to complete the
+ write. If the user does not supply a bitmap, Write will fail if
+ the write extends past the attribute value's allocated length.
+ (It may or may not write some of the data.)
+
+ Note that this method does not check the attribute's valid data
+ length, but it does reset the valid data length if it writes
+ past the valid data length. Therefore, clients must use some
+ caution to avoid introducing stretches of uninitialized data
+ in the attribute (which would be a security leak).
+
+ Note that if Write fails, the contents of the attribute on
+ disk is undefined.
+
+ Note also that Write is not supported for sparse files.
+
+--*/
+{
+ NTFS_CLUSTER_RUN ClusterRun;
+ HMEM IntermediateBuffer;
+ BIG_INT TempBigInt;
+ BIG_INT RunLength;
+ BIG_INT OldValidDataLength;
+ VCN CurrentVcn, RecentLcn;
+ LCN CurrentLcn;
+ PBYTE CurrentData;
+ ULONG BytesToCopy, OffsetIntoCluster, CurrentRunLength;
+ ULONG ClusterSize;
+ ULONG RemainingRequest;
+ ULONG BytesToZero;
+
+ // First, make sure that the space allocated to the attribute
+ // value is sufficient.
+
+ if( QueryAllocatedLength() < ByteOffset + BytesToWrite &&
+ !Resize( ByteOffset + BytesToWrite, Bitmap ) ) {
+
+ // This attribute does not have enough space allocated
+ // to it to satisfy the write request, and we could not
+ // extend the allocation, so the write fails.
+
+ return FALSE;
+ }
+
+ // Now check the valid data length. If the write begins
+ // past the end of valid data, we have to fill the intervening
+ // gap with zeroes. Note that before we call Fill, we
+ // must set the Valid Data Length appropriately, since Fill
+ // just recurses back into Write.
+ //
+ if( _ValidDataLength < ByteOffset ) {
+
+ TempBigInt = ByteOffset - _ValidDataLength;
+
+ if( TempBigInt.GetHighPart() != 0 ) {
+
+ DebugPrint( "UNTFS: Writing discontiguous huge attribute.\n" );
+ return FALSE;
+ }
+
+ BytesToZero = TempBigInt.GetLowPart();
+
+ OldValidDataLength = _ValidDataLength;
+ _ValidDataLength = ByteOffset;
+
+ if( !Fill( OldValidDataLength, 0, BytesToZero ) ) {
+
+ // Couldn't zero-fill the gap; restore Valid Data
+ // Length and return failure.
+ //
+ _ValidDataLength = OldValidDataLength;
+ return FALSE;
+ }
+ }
+
+
+ if( _ResidentData != NULL ) {
+
+ // Since the attribute value is resident, we can
+ // just copy it.
+ //
+ DebugAssert( ByteOffset.GetHighPart() == 0 );
+
+ memcpy( (PBYTE)_ResidentData + ByteOffset.GetLowPart(),
+ Data,
+ (UINT) BytesToWrite );
+
+ SetStorageModified();
+ ByteOffset += BytesToWrite;
+
+ } else if ( _ExtentList != NULL ) {
+
+ // Now we can actually start writing stuff! First, we'll write
+ // any partial leading cluster through an intermediate buffer.
+ // Next, we write entire clusters directly from the user's buffer.
+ // Finally, we write any partial trailing cluster.
+
+ ClusterSize = _ClusterFactor * _Drive->QuerySectorSize();
+
+ RemainingRequest = BytesToWrite;
+
+ // RecentLcn is used in case we need to grab extents on the
+ // fly--if we have to allocate space to fill in holes in a
+ // sparse attribute, using RecentLcn will increase the probability
+ // that the space we grab is close to the rest of the attribute.
+
+ RecentLcn = 0;
+
+ if( RemainingRequest > 0 ) {
+
+ CurrentData = (PBYTE) Data;
+
+ OffsetIntoCluster = (ByteOffset % ClusterSize).GetLowPart();
+
+ if( OffsetIntoCluster != 0 ) {
+
+ // We have a partial leading cluster, so we'll write
+ // it through the intermediate buffer. Note that we
+ // must read the cluster in, copy the part we intend
+ // to write, and then write it back out.
+
+ BytesToCopy = MIN( BytesToWrite,
+ ClusterSize - OffsetIntoCluster );
+
+ CurrentVcn = ByteOffset / ClusterSize;
+
+ if( !_ExtentList->QueryLcnFromVcn( CurrentVcn,
+ &CurrentLcn,
+ &RunLength ) ) {
+
+ return FALSE;
+ }
+
+ if( CurrentLcn == LCN_NOT_PRESENT ) {
+
+ // This portion of the request falls into a
+ // hole in a sparse attribute, so we have
+ // to allocate disk space for it and add
+ // this new extent to the extent list. If
+ // we can't, the request fails.
+
+ if( Bitmap == NULL ||
+ !Bitmap->AllocateClusters( RecentLcn,
+ 1,
+ &CurrentLcn) ||
+ !_ExtentList->AddExtent( CurrentVcn,
+ CurrentLcn,
+ 1 ) ) {
+
+ return FALSE;
+ }
+ }
+
+ RecentLcn = CurrentLcn;
+
+ if( !IntermediateBuffer.Initialize() ||
+ !ClusterRun.Initialize( &IntermediateBuffer,
+ _Drive,
+ CurrentLcn,
+ _ClusterFactor,
+ 1 ) ||
+ !ClusterRun.Read() ) {
+
+ DebugPrint( "Could not read partial leading sector\n" );
+ return FALSE;
+ }
+
+ // We've read the cluster in question; copy the partial
+ // leading cluster of our write request and write it
+ // back out.
+
+ memcpy( (PBYTE)ClusterRun.GetBuf() + OffsetIntoCluster,
+ CurrentData,
+ (UINT) BytesToCopy );
+
+ if( !ClusterRun.Write() ) {
+
+ DebugPrint( "Could not write partial leading sector.\n" );
+ return FALSE;
+ }
+
+ RemainingRequest -= BytesToCopy;
+ CurrentData += BytesToCopy;
+ ByteOffset += BytesToCopy;
+
+ }
+
+ // Now transfer any complete clusters. Because the
+ // client's buffer may not be suitably aligned, we
+ // have to cycle these through an intermediate buffer.
+
+ while( RemainingRequest >= ClusterSize ) {
+
+ CurrentVcn = ByteOffset / ClusterSize;
+
+ if( !_ExtentList->QueryLcnFromVcn( CurrentVcn,
+ &CurrentLcn,
+ &RunLength ) ) {
+
+ DebugPrint( "Could not determine LCN.\n" );
+ return FALSE;
+ }
+
+ if( RunLength.GetHighPart() != 0 ||
+ RunLength.GetLowPart() >
+ MaximumClustersToTransfer ) {
+
+ CurrentRunLength = MaximumClustersToTransfer;
+
+ } else {
+
+ CurrentRunLength = RunLength.GetLowPart();
+ }
+
+ if( CurrentRunLength * ClusterSize >
+ RemainingRequest ) {
+
+ CurrentRunLength = RemainingRequest/ClusterSize;
+ }
+
+ BytesToCopy = CurrentRunLength * ClusterSize;
+
+ if( CurrentLcn == LCN_NOT_PRESENT ) {
+
+ // This portion of the request falls into a
+ // hole in a sparse attribute, so we have
+ // to allocate disk space for it and add
+ // this new extent to the extent list. If
+ // we can't, the request fails.
+
+ if( Bitmap == NULL ||
+ !Bitmap->AllocateClusters( RecentLcn,
+ CurrentRunLength,
+ &CurrentLcn) ||
+ !_ExtentList->AddExtent( CurrentVcn,
+ CurrentLcn,
+ 1 ) ) {
+
+ return FALSE;
+ }
+ }
+
+ RecentLcn = CurrentLcn;
+
+ if( !IntermediateBuffer.Initialize() ||
+ !ClusterRun.Initialize( &IntermediateBuffer,
+ _Drive,
+ CurrentLcn,
+ _ClusterFactor,
+ CurrentRunLength ) ) {
+
+
+ DebugPrint( "Could not get memory to write user data.\n" );
+ return FALSE;
+ }
+
+ memcpy( IntermediateBuffer.GetBuf(),
+ CurrentData,
+ BytesToCopy );
+
+ if( !ClusterRun.Write() ) {
+
+ DebugPrint( "Could not write complete clusters.\n" );
+ return FALSE;
+ }
+
+ RemainingRequest -= BytesToCopy;
+ CurrentData += BytesToCopy;
+ ByteOffset += BytesToCopy;
+ }
+
+ if( RemainingRequest > 0 ) {
+
+ // OK, we have a partial trailing cluster. Write
+ // it through the intermediate buffer. Again,
+ // we have to read the cluster, copy the data,
+ // and write the cluster back out.
+
+ BytesToCopy = RemainingRequest;
+
+ CurrentVcn = ByteOffset / ClusterSize;
+
+ if( !_ExtentList->QueryLcnFromVcn( CurrentVcn,
+ &CurrentLcn,
+ &RunLength ) ) {
+
+ return FALSE;
+ }
+
+ if( CurrentLcn == LCN_NOT_PRESENT ) {
+
+ // This portion of the request falls into a
+ // hole in a sparse attribute, so we have
+ // to allocate disk space for it and add
+ // this new extent to the extent list. If
+ // we can't, the request fails.
+
+ if( Bitmap == NULL ||
+ !Bitmap->AllocateClusters( RecentLcn,
+ 1,
+ &CurrentLcn) ||
+ !_ExtentList->AddExtent( CurrentVcn,
+ CurrentLcn,
+ 1 ) ) {
+
+ return FALSE;
+ }
+ }
+
+ RecentLcn = CurrentLcn;
+
+ if( !IntermediateBuffer.Initialize() ||
+ !ClusterRun.Initialize( &IntermediateBuffer,
+ _Drive,
+ CurrentLcn,
+ _ClusterFactor,
+ 1 ) ||
+ !ClusterRun.Read() ) {
+
+ DebugPrint( "Failure getting LCN or intermediat buffer.\n" );
+ return FALSE;
+ }
+
+ // We've read the cluster in question; copy the partial
+ // leading cluster of our write request and write it
+ // back out.
+
+ memcpy( ClusterRun.GetBuf(),
+ CurrentData,
+ (UINT) BytesToCopy );
+
+ if( !ClusterRun.Write() ) {
+
+ DebugPrint( "Could not write trailing partial cluster.\n" );
+ DebugPrintf("Status: %x\n", _Drive->QueryLastNtStatus());
+ DebugPrintf("LCN: %x\n", CurrentLcn.GetLowPart());
+ return FALSE;
+ }
+
+ // Update ByteOffset, since it may be used to check
+ // _ValidDataLength below.
+
+ ByteOffset += RemainingRequest;
+ }
+ }
+
+ } else {
+
+ DebugAbort( "This attribute is neither resident nor nonresident.\n" );
+ return FALSE;
+ }
+
+ if( _ValidDataLength < ByteOffset ) {
+
+ _ValidDataLength = ByteOffset;
+ SetStorageModified();
+ }
+
+ if( _ValueLength < ByteOffset ) {
+
+ _ValueLength = ByteOffset;
+ SetStorageModified();
+ }
+
+ *BytesWritten = BytesToWrite;
+ return TRUE;
+}
+
+BOOLEAN
+NTFS_ATTRIBUTE::Fill (
+ IN BIG_INT Offset,
+ IN CHAR FillCharacter
+ )
+/*++
+
+Routine Description:
+
+ This method fills the attribute with the specified character
+ from the given offset until the end of the attribute.
+
+Arguments:
+
+ Offset -- Starting offset to begin the fill.
+ FillCharacter -- Supplies the character that will be written
+ to every byte of the attribute value.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This method will fail if it is used on an attribute which has a size
+ greater than MAXULONG.
+
+--*/
+{
+ BIG_INT TempBigInt;
+
+ if( Offset >= QueryValueLength() ) {
+
+ // Nothing to do.
+ //
+ return TRUE;
+ }
+
+ // Fill to the end of the attribute--compute the number of
+ // bytes in the attribute starting at Offset. Make sure
+ // that the amount to fill fits in a ULONG.
+ //
+ TempBigInt = QueryValueLength() - Offset;
+
+ if( TempBigInt.GetHighPart() != 0 ) {
+
+ DebugPrint( "UNTFS: Trying to fill a very large attribute.\n" );
+ return FALSE;
+ }
+
+ return( Fill( Offset, FillCharacter, TempBigInt.GetLowPart() ) );
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE::Fill (
+ IN BIG_INT Offset,
+ IN CHAR FillCharacter,
+ IN ULONG NumberOfBytes
+ )
+/*++
+
+Routine Description:
+
+ This method fills the attribute with the specified character
+ from the given offset for the specified number of bytes.
+
+Arguments:
+
+ Offset -- Starting offset to begin the fill.
+ FillCharacter -- Supplies the character that will be written
+ to every byte of the attribute value.
+ NumberOfBytes -- Number of bytes to fill.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This method will fail if it is used on an attribute which has a size
+ greater than MAXULONG.
+
+--*/
+{
+ PVOID FillBuffer;
+ ULONG BytesRemaining, FillBufferSize, BytesToWrite, BytesWritten;
+ BOOLEAN Result;
+
+ CONST ULONG MaximumBufferSize = 0x10000;
+
+ if( Offset > QueryValueLength() ) {
+
+ DebugPrint( "UNTFS: Filling an attribute starting past end.\n" );
+ return TRUE;
+ }
+
+ // Get a buffer to fill with the fill character. Start out by
+ // requesting the full amount; if we can't get it, keep asking
+ // for smaller amounts.
+ //
+ BytesRemaining = NumberOfBytes;
+ FillBufferSize = min( BytesRemaining, MaximumBufferSize );
+
+ while( FillBufferSize > 0 &&
+ (FillBuffer = MALLOC( FillBufferSize )) == NULL ) {
+
+ FillBufferSize /= 2;
+ }
+
+ // If we couldn't get a buffer, fail.
+ //
+ if( FillBufferSize == 0 || FillBuffer == NULL ) {
+
+ return FALSE;
+ }
+
+ // Fill the buffer with the fill character.
+ //
+ memset( FillBuffer,
+ FillCharacter,
+ FillBufferSize );
+
+ // Chug through the attribute, writing each chunk until we hit
+ // a failure or reach the end.
+ //
+ Result = TRUE;
+
+ while( BytesRemaining > 0 && Result ) {
+
+ // Write the lesser of our buffer size or the remainder
+ // of the attribute. Note that we pass NULL for the
+ // bitmap parameter to Write, since this write should
+ // not affect the allocated length of the buffer.
+ //
+ BytesToWrite = min( BytesRemaining, FillBufferSize );
+
+ if( !Write( FillBuffer,
+ Offset,
+ BytesToWrite,
+ &BytesWritten,
+ NULL ) ||
+ BytesWritten != BytesToWrite ) {
+
+ DebugPrint( "Write failed in NTFS_ATTRIBUTE::Fill.\n" );
+ Result = FALSE;
+ }
+
+ Offset += BytesToWrite;
+ BytesRemaining -= BytesToWrite;
+ }
+
+ FREE( FillBuffer );
+ return Result;
+}
+
+
+
+BOOLEAN
+NTFS_ATTRIBUTE::RecoverAttribute(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNUMBER_SET BadClusters,
+ OUT PBIG_INT BytesRecovered
+ )
+/*++
+
+Routine Description:
+
+ This method recovers an attribute. Recovery consists of reading each
+ cluster in the attribute value, and replacing it with a cluster full
+ of zeroes if it is unreadable.
+
+Arguments:
+
+ VolumeBitmap -- supplies the volume bitmap.
+ BadClusters -- receives the bad clusters identified by this method.
+ BytesRecovered -- receives the number of bytes recovered (not
+ mapped out). This parameter may be NULL, in
+ which case this information is not returned.
+ Note that if the method returns FALSE, this
+ parameter's contents will be undefined.
+
+Notes:
+
+ This method should not be called for any system-defined attribute
+ other than $DATA.
+
+ Recover for resident attributes is trivial.
+
+--*/
+{
+ HMEM MultiClusterMem, SingleClusterMem;
+ NTFS_CLUSTER_RUN MultiClusterRun, SingleClusterRun;
+ VCN StartingVcn, ClustersAttempted, BadVcn;
+ LCN StartingLcn;
+ BIG_INT RunLength, dVcn;
+ ULONG CurrentRunLength;
+ ULONG ExtentNumber, i, j;
+ BOOLEAN FoundBad;
+ LCN NewLcn;
+ BIG_INT OldOffset;
+ ULONG ClusterSize;
+ ULONG MaxClusters, Take;
+
+ // Compressed attributes receive special handling.
+ //
+ if (IsCompressed() && !IsResident()) {
+
+ return RecoverCompressedAttribute( VolumeBitmap, BadClusters,
+ BytesRecovered );
+ }
+
+ if( _ExtentList == NULL ) {
+
+ // The attribute is resident--Recover is a no-op.
+ //
+ if( BytesRecovered != NULL ) {
+
+ *BytesRecovered = QueryValueLength();
+ }
+
+ return TRUE;
+ }
+
+ ClusterSize = QueryClusterFactor() * GetDrive()->QuerySectorSize();
+ MaxClusters = 0x10000/ClusterSize;
+
+ if( !MultiClusterMem.Initialize() ||
+ !MultiClusterRun.Initialize( &MultiClusterMem,
+ GetDrive(),
+ 0,
+ QueryClusterFactor(),
+ MaxClusters ) ||
+ !SingleClusterMem.Initialize() ||
+ !SingleClusterRun.Initialize( &SingleClusterMem,
+ GetDrive(),
+ 0,
+ QueryClusterFactor(),
+ 1 ) ) {
+ // insufficient memory.
+
+ return FALSE;
+ }
+
+
+ // Initialize the counters.
+ //
+ ExtentNumber = 0;
+ ClustersAttempted = 0;
+
+ if( BytesRecovered != NULL ) {
+
+ *BytesRecovered = 0;
+ }
+
+ while( _ExtentList->QueryExtent( ExtentNumber,
+ &StartingVcn,
+ &StartingLcn,
+ &RunLength ) ) {
+
+ if( RunLength.GetHighPart() != 0 ) {
+
+ DebugPrint( "NTFS_ATTRIBUTE::Recover--RunLength > Max ULONG )\n" );
+ return FALSE;
+ }
+
+ // Read the extent in chunks until we get a bad sector
+ // (read failure) or run out.
+ //
+ CurrentRunLength = RunLength.GetLowPart();
+
+ FoundBad = FALSE;
+
+
+ Take = MaxClusters;
+ for( i = 0; i < CurrentRunLength && !FoundBad; i += Take ) {
+
+ Take = min(MaxClusters, CurrentRunLength - i);
+
+ MultiClusterRun.Initialize( &MultiClusterMem,
+ GetDrive(),
+ StartingLcn + i,
+ QueryClusterFactor(),
+ Take );
+
+ if( MultiClusterRun.Read() ) {
+
+ // This whole run of clusters is good. If this
+ // range of VCNs has not already been attempted,
+ // update the count of bytes recovered.
+ //
+ if( BytesRecovered &&
+ StartingVcn + i + Take > ClustersAttempted ) {
+
+ dVcn = StartingVcn + i + Take - ClustersAttempted;
+ OldOffset = ClustersAttempted * ClusterSize;
+
+ ClustersAttempted += dVcn;
+
+ if( OldOffset + dVcn * ClusterSize < QueryValueLength() ) {
+
+ *BytesRecovered += dVcn * ClusterSize;
+
+ } else if( OldOffset < QueryValueLength() ) {
+
+ *BytesRecovered += QueryValueLength() - OldOffset;
+ }
+ }
+
+ } else {
+
+ // Check each of the clusters individually.
+ //
+ for( j = 0; j < Take && !FoundBad; j++ ) {
+
+ SingleClusterRun.Relocate( StartingLcn + i + j );
+
+ if( SingleClusterRun.Read() ) {
+
+ // This cluster is good. Update the total
+ // of bytes recovered.
+ //
+ if( BytesRecovered &&
+ StartingVcn + i + j + 1 > ClustersAttempted ) {
+
+ OldOffset = ClustersAttempted * ClusterSize;
+ ClustersAttempted += 1;
+
+ if( OldOffset+ClusterSize < QueryValueLength() ) {
+
+ *BytesRecovered += ClusterSize;
+
+ } else if( OldOffset < QueryValueLength() ) {
+
+ *BytesRecovered += QueryValueLength() -
+ OldOffset;
+ }
+ }
+
+ } else {
+
+ // Found a bad cluster. Allocate a replacement
+ // for it, fill the replacement with zeroes, and
+ // splinter the extent. Note that we don't check
+ // the return value of the write; instead, on the
+ // next iteration, we'll check this VCN again.
+ //
+ FoundBad = TRUE;
+ BadVcn = StartingVcn + i + j;
+
+ if( BytesRecovered &&
+ ClustersAttempted < BadVcn + 1 ) {
+
+ ClustersAttempted = BadVcn + 1;
+ }
+
+ if( !VolumeBitmap->AllocateClusters( StartingLcn,
+ 1,
+ &NewLcn) ) {
+
+ return FALSE;
+ }
+
+ SingleClusterRun.Relocate( NewLcn );
+
+ memset( SingleClusterMem.GetBuf(),
+ '\0',
+ GetDrive()->QuerySectorSize() *
+ QueryClusterFactor() );
+
+ SingleClusterRun.Write();
+
+ _ExtentList->DeleteExtent( ExtentNumber );
+
+ if( ( i + j > 0 &&
+ !AddExtent( StartingVcn,
+ StartingLcn,
+ i + j ) ) ||
+ !AddExtent( BadVcn, NewLcn, 1 ) ||
+ ( i + j + 1 < CurrentRunLength &&
+ !AddExtent( StartingVcn + i + j + 1,
+ StartingLcn + i + j + 1,
+ CurrentRunLength - (i + j + 1) ) ) ) {
+
+ DebugPrint( "RECOVER: couldn't splinter extent." );
+ return FALSE;
+ }
+
+ // Add the bad cluster to the list of identified
+ // bad clusters, and remember that the attribute's
+ // storage has been modified.
+ //
+ if( !BadClusters->Add( StartingLcn + i + j ) ) {
+
+ return FALSE;
+ }
+
+ SetStorageModified();
+ }
+ }
+ }
+ }
+
+ // If we processed this entire extent without finding any bad
+ // sectors, update the count of bytes recovered and go on to
+ // the next one. Otherwise, try this one again.
+ //
+ if( !FoundBad ) {
+
+ ExtentNumber += 1;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE::MarkAsAllocated(
+ IN OUT PNTFS_BITMAP VolumeBitmap
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine allocated the space taken by this attribute in the
+ given Volume Bitmap. If any of the space taken by this attribute is
+ beyond the range of the given bitmap then this routine will fail
+ without allocating any new space in the bitmap.
+
+ This routine allocates the space in the bitmap regardless of whether
+ or not this space is already allocated in the bitmap.
+
+Arguments:
+
+ VolumeBitmap - Supplies the bitmap which to mark the allocation.
+
+Return Value:
+
+ FALSE - The space requested is beyond the natural range of the
+ given bitmap.
+ TRUE - Success.
+
+--*/
+{
+ ULONG num_extents;
+ ULONG i;
+ VCN next_vcn;
+ LCN current_lcn;
+ BIG_INT run_length;
+
+
+ DebugAssert(VolumeBitmap);
+
+
+ // If the attribute is resident then we have already succeeded.
+
+ if (!_ExtentList) {
+ return TRUE;
+ }
+
+
+ num_extents = _ExtentList->QueryNumberOfExtents();
+
+ for (i = 0; i < num_extents; i++) {
+
+ if (!_ExtentList->QueryExtent(i, &next_vcn, &current_lcn,
+ &run_length)) {
+
+ DebugAbort("Could not query extent");
+ return FALSE;
+ }
+ if (LCN_NOT_PRESENT == current_lcn) {
+ continue;
+ }
+
+ if (!VolumeBitmap->IsInRange(current_lcn, run_length)) {
+ return FALSE;
+ }
+ }
+
+ for (i = 0; i < num_extents; i++) {
+
+ if (!_ExtentList->QueryExtent(i, &next_vcn, &current_lcn,
+ &run_length)) {
+
+ DebugAbort("Could not query extent");
+ return FALSE;
+ }
+ if (LCN_NOT_PRESENT == current_lcn) {
+ return FALSE;
+ }
+
+ VolumeBitmap->SetAllocated(current_lcn, run_length);
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+AccountForBadClusters(
+ IN LCN Lcn,
+ IN BIG_INT RunLength,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN ULONG ClusterFactor,
+ OUT PBOOLEAN SomeWereBad,
+ IN OUT PNUMBER_SET BadClusters
+ )
+/*++
+
+Routine Description:
+
+ This routine read through the given run of clusters. The clusters
+ that are bad are added to the list of BadClusters and marked
+ as allocated in the volume bitmap. The clusters which are good are
+ marked free in the volume bitmap.
+
+Arguments:
+
+ Lcn - Supplies the first logical cluster number.
+ RunLength - Supplies the length of the run.
+ VolumeBitmap - Supplies the volume bitmap.
+ Drive - Supplies the drive.
+ ClusterFactor - Supplies the cluster factor.
+ SomeWereBad - Returns whether or not any clusters were bad.
+ BadClusters - Supplies the list of bad volume clusters.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ HMEM hmem;
+ NTFS_CLUSTER_RUN clusrun;
+ BIG_INT i;
+ LCN sup;
+
+ if (!hmem.Initialize()) {
+ return FALSE;
+ }
+
+ *SomeWereBad = FALSE;
+
+ sup = Lcn + RunLength;
+ for (i = Lcn; i < sup; i += 1) {
+
+ if (!clusrun.Initialize(&hmem, Drive, i, ClusterFactor, 1)) {
+ return FALSE;
+ }
+
+ if (clusrun.Read()) {
+
+ VolumeBitmap->SetFree(i, 1);
+
+ } else {
+
+ VolumeBitmap->SetAllocated(i, 1);
+
+ *SomeWereBad = TRUE;
+
+ if (!BadClusters->Add(i)) {
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE::Hotfix(
+ IN VCN Vcn,
+ IN BIG_INT RunLength,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNUMBER_SET BadClusters,
+ IN BOOLEAN Contiguous
+ )
+/*++
+
+Routine Description:
+
+ This routine replaces the cluster run specified by 'Vcn' and
+ 'RunLength' with new readable clusters allocated from
+ 'VolumeBitmap'.
+
+ If 'Contiguous' is TRUE then the readable clusters will be allocated
+ from the bitmap in one contiguous run.
+
+ If 'BadClusters' is specified then the logical cluster numbers
+ of all of the bad clusters detected by this routine will be added
+ to this list. This does not include the run to hotfix.
+
+Arguments:
+
+ Vcn - Supplies the first vcn of the run to hotfix.
+ RunLength - Supplies the number of clusters to hotfix.
+ VolumeBitmap - Supplies a valid volume bitmap from which to
+ allocate new clusters.
+ BadClusters - Supplies a list to which to add the bad clusters
+ of the volume.
+ Contiguous - Supplies whether or not the new clusters must be
+ contiguous.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ BIG_INT alloc_size;
+ BIG_INT total_so_far;
+ LCN first_lcn;
+ BOOLEAN some_were_bad;
+ NTFS_EXTENT_LIST new_stuff;
+ NTFS_EXTENT_LIST backup_copy;
+ VCN i;
+ VCN vcn;
+ LCN lcn;
+ BIG_INT run_length;
+ ULONG j;
+
+
+ DebugAssert(RunLength != 0);
+
+ if (!_ExtentList) {
+ return FALSE;
+ }
+
+ if (!new_stuff.Initialize(0, 0) ||
+ !backup_copy.Initialize(_ExtentList)) {
+
+ return FALSE;
+ }
+
+ // Allocate the space necessary on the bitmap making sure that
+ // the sectors are good.
+
+ alloc_size = RunLength;
+ total_so_far = 0;
+
+ while (total_so_far < RunLength) {
+
+ if (VolumeBitmap->AllocateClusters(0, alloc_size, &first_lcn)) {
+
+ if (!AccountForBadClusters(first_lcn, alloc_size,
+ VolumeBitmap, GetDrive(),
+ QueryClusterFactor(),
+ &some_were_bad,
+ BadClusters)) {
+
+ return FALSE;
+ }
+
+ if (some_were_bad) {
+ continue;
+ }
+
+ VolumeBitmap->SetAllocated(first_lcn, alloc_size);
+
+ if (!new_stuff.AddExtent(Vcn + total_so_far,
+ first_lcn,
+ alloc_size)) {
+
+ return FALSE;
+ }
+
+ total_so_far += alloc_size;
+
+ alloc_size = min(alloc_size, RunLength - total_so_far);
+
+ } else {
+
+ if (Contiguous || alloc_size == 1) {
+ return FALSE;
+ }
+
+ alloc_size = alloc_size/2;
+ }
+ }
+
+
+ // Delete the given range of VCN's from the extent list.
+
+ if (!_ExtentList->DeleteRange(Vcn, RunLength)) {
+ return FALSE;
+ }
+
+
+ // Now insert the extents into the extent list.
+
+ for (j = 0; j < new_stuff.QueryNumberOfExtents(); j++) {
+
+ if (!new_stuff.QueryExtent(j, &vcn, &lcn, &run_length) ||
+ !_ExtentList->AddExtent(vcn, lcn, run_length)) {
+
+ _ExtentList->Initialize(&backup_copy);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE::ReplaceVcns(
+ IN VCN StartingVcn,
+ IN LCN NewLcn,
+ IN BIG_INT NumberOfClusters
+ )
+/*++
+
+Routine Description:
+
+ This routine replaces the VCNs specified by 'StartingVcn' and
+ 'NumberOfClusters' with the contiguous run that starts at
+ 'NewLcn'.
+
+Arguments:
+
+ StartingVcn - Supplies the starting vcn to replace.
+ NewLcn - Supplies a run of 'NumberOfClusters' clusters.
+ NumberOfClusters - Supplies the number of clusters to replace.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ if (!_ExtentList->DeleteRange(StartingVcn, NumberOfClusters)) {
+ return FALSE;
+ }
+
+ if (!_ExtentList->AddExtent(StartingVcn, NewLcn, NumberOfClusters)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+operator==(
+ IN RCNTFS_ATTRIBUTE Left,
+ IN RCNTFS_ATTRIBUTE Right
+ )
+/*++
+
+Routine Description:
+
+ This routine computes whether or not the two given attributes are
+ equal.
+
+Arguments:
+
+ Left - Supplies the left argument.
+ Right - Supplies the right argument.
+
+Return Value:
+
+ FALSE - The given attributes are not equal.
+ TRUE - The given attributes are equal.
+
+--*/
+{
+ VCN left_vcn, right_vcn;
+ LCN left_lcn, right_lcn;
+ BIG_INT left_length, right_length;
+ ULONG num_extents;
+ PNTFS_EXTENT_LIST left_list;
+ PNTFS_EXTENT_LIST right_list;
+ ULONG i;
+
+ if (Left._ClusterFactor != Right._ClusterFactor ||
+ Left._Type != Right._Type ||
+ Left._Name.Strcmp(&Right._Name) ||
+ Left._Flags != Right._Flags ||
+ Left._FormCode != Right._FormCode ||
+ Left._ValueLength != Right._ValueLength ||
+ Left._ValidDataLength != Right._ValidDataLength ||
+ Left._ResidentFlags != Right._ResidentFlags) {
+
+ return FALSE;
+ }
+
+ if (Left._ResidentData) {
+
+ if (!Right._ResidentData) {
+ return FALSE;
+ }
+
+ return !memcmp(Left._ResidentData,
+ Right._ResidentData,
+ (UINT) Left._ValueLength.GetLowPart());
+ }
+
+ DebugAssert(Left._ExtentList);
+ DebugAssert(Right._ExtentList);
+
+ left_list = Left._ExtentList;
+ right_list = Right._ExtentList;
+
+ if (left_list->QueryNumberOfExtents() !=
+ right_list->QueryNumberOfExtents() ||
+ left_list->QueryLowestVcn() != right_list->QueryLowestVcn() ||
+ left_list->QueryNextVcn() != right_list->QueryNextVcn()) {
+
+ return FALSE;
+ }
+
+ num_extents = left_list->QueryNumberOfExtents();
+
+ for (i = 0; i < num_extents; i += 1) {
+
+ if (!left_list->QueryExtent(i, &left_vcn, &left_lcn, &left_length) ||
+ !right_list->QueryExtent(i, &right_vcn, &right_lcn, &right_length) ||
+ left_vcn != right_vcn ||
+ left_lcn != right_lcn ||
+ left_length != right_length) {
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BIG_INT
+NTFS_ATTRIBUTE::QueryClustersAllocated(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of clusters allocated for this
+ attribute.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of clusters allocated by this attribute.
+
+--*/
+{
+ BIG_INT r;
+
+ if (_ExtentList) {
+ r = _ExtentList->QueryClustersAllocated();
+ } else {
+ r = 0;
+ }
+
+ return r;
+}
+
+
+
+BOOLEAN
+NTFS_ATTRIBUTE::InsertMftDataIntoFile (
+ IN OUT PNTFS_FILE_RECORD_SEGMENT BaseFileRecordSegment,
+ IN OUT PNTFS_BITMAP Bitmap OPTIONAL,
+ IN BOOLEAN BeConservative
+ )
+/*++
+
+Routine Description:
+
+ This method inserts the MFT Data attribute into a File Record
+ Segment (presumably FRS 0). It is a private worker method for
+ InsertIntoFile.
+
+Arguments:
+
+ FileRecordSegment -- Supplies the File Record Segment into
+ which the attribute will jam itself.
+ Bitmap -- Supplies the volume bitmap.
+ BeConservative -- Supplies a flag which indicates, if TRUE,
+ that the attribute should try to leave free
+ space in the File Record Segments (to leave
+ room for changes due to hotfixing). If this
+ flag is FALSE, the attribute will make each
+ attribute record as large as it can.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ NTFS_ATTRIBUTE_RECORD AttributeRecord;
+ PVOID AttributeRecordData;
+ BOOLEAN Result;
+ ULONG MaxSize;
+ ULONG MaxExtentsSize, CurrentMaxExtentsSize;
+ NTFS_EXTENT_LIST source;
+ NTFS_EXTENT_LIST result;
+ NTFS_EXTENT_LIST remainder;
+ BOOLEAN FirstChunkInserted = FALSE;
+ BOOLEAN Completed = FALSE;
+
+ // The MFT data attribute must be resident.
+ //
+ if( _ResidentData != NULL ) {
+
+ return FALSE;
+ }
+
+ // Allocate a buffer to hold attribute records. If we're being
+ // conservative, reduce the size of the maximum record by 1/8.
+ //
+ MaxSize = BaseFileRecordSegment->QueryMaximumAttributeRecordSize();
+
+ if( BeConservative ) {
+
+ // Reduce the maximum record size by 1/8 of the FRS size,
+ // to allow for hotfixing and other changes.
+ //
+ MaxSize -= BaseFileRecordSegment->QuerySize()/8;
+ }
+
+ if( (AttributeRecordData = MALLOC( (UINT) MaxSize )) == NULL ) {
+
+ return FALSE;
+ }
+
+
+ // Compute the maximum number of bytes in an extent list.
+ //
+ MaxExtentsSize = MaxSize - SIZE_OF_NONRESIDENT_HEADER;
+ MaxExtentsSize -= QuadAlign(_Name.QueryChCount());
+
+ // The first chunk of the MFT's DATA attribute gets
+ // special treatment, since it has to fit into the
+ // Base FRS. If our first attempt doesn't fit, we
+ // keep whittling it down until it does or until we
+ // run out of possibilities.
+ //
+ CurrentMaxExtentsSize = MaxExtentsSize;
+
+ Result = AttributeRecord.Initialize( AttributeRecordData, MaxSize );
+
+ while( Result && !FirstChunkInserted ) {
+
+ // Partition the extent list.
+ //
+ if( PartitionExtentList( _ExtentList,
+ CurrentMaxExtentsSize,
+ &result,
+ &remainder ) ) {
+
+ if( !AttributeRecord.
+ CreateNonresidentRecord( &result,
+ QueryAllocatedLength(),
+ _ValueLength,
+ _ValidDataLength,
+ _Type,
+ &_Name,
+ _Flags,
+ _CompressionUnit ) ||
+ !BaseFileRecordSegment->
+ InsertAttributeRecord( &AttributeRecord ) ) {
+
+ // This partition didn't work. Try a smaller one.
+ //
+ CurrentMaxExtentsSize /= 2;
+
+ if( CurrentMaxExtentsSize == 0 ) {
+
+ Result = FALSE;
+ }
+
+ } else {
+
+ // Successfully inserted first chunk. Set up
+ // source to continue inserting the remaining
+ // chunks.
+ //
+ FirstChunkInserted = TRUE;
+
+ if (remainder.IsEmpty()) {
+
+ Completed = TRUE;
+
+ } else {
+
+ Result = source.Initialize(&remainder);
+ }
+ }
+
+ } else {
+
+ Result = FALSE;
+ }
+ }
+
+
+
+ while (Result && !Completed) {
+
+ // Initialize attribute record.
+
+ Result = AttributeRecord.Initialize( AttributeRecordData, MaxSize );
+
+
+ // Partition extent list into two pieces, the first of which
+ // can be made into an attribute record.
+
+ Result = Result &&
+ PartitionExtentList(&source,
+ MaxExtentsSize,
+ &result,
+ &remainder);
+
+
+ // Create the attribute record.
+
+ Result = Result &&
+ AttributeRecord.
+ CreateNonresidentRecord( &result,
+ QueryAllocatedLength(),
+ _ValueLength,
+ _ValidDataLength,
+ _Type,
+ &_Name,
+ _Flags,
+ _CompressionUnit );
+
+
+ // If we were able to package it up, then give the attribute
+ // record to the File Record Segment.
+
+ Result = Result &&
+ BaseFileRecordSegment->
+ InsertAttributeRecord( &AttributeRecord );
+
+
+ // If all of the extents fit in the last record then we are done.
+
+ if (remainder.IsEmpty()) {
+
+ Completed = TRUE;
+
+ } else {
+
+ Result = Result &&
+ source.Initialize(&remainder);
+ }
+ }
+
+
+ ResetStorageModified();
+ FREE( AttributeRecordData );
+ return Result;
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE::RecoverCompressedAttribute(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNUMBER_SET BadClusters,
+ OUT PBIG_INT BytesRecovered
+ )
+/*++
+
+Routine Description:
+
+ This method is a private helper function for RecoverAttribute;
+ it is invoked if the attribute is compressed. Recovery consists
+ of reading each cluster in the attribute value, and replacing it
+ with a cluster full of zeroes if it is unreadable.
+
+Arguments:
+
+ VolumeBitmap -- supplies the volume bitmap.
+ BadClusters -- receives the bad clusters identified by this method.
+ BytesRecovered -- receives the number of bytes recovered (not
+ mapped out). This parameter may be NULL, in
+ which case this information is not returned.
+ Note that if the method returns FALSE, this
+ parameter's contents will be undefined.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ HMEM ClusterMem, OneClusterMem;
+ NTFS_CLUSTER_RUN ClusterRun, OneCluster;
+ VCN CurrentVcn, Vcn;
+ LCN Lcn;
+ BIG_INT RunLength;
+ ULONG i, j, BytesPerCluster, ClustersPerCompressionUnit, ClustersRemaining,
+ CompressedClusters, ThisRun, UncompressedSize, Holes;
+ BOOLEAN DiscardThisUnit;
+ PUCHAR CompressedBuffer, UncompressedBuffer;
+ NTSTATUS Status;
+
+
+ if (IsResident() || !IsCompressed()) {
+
+ DebugPrintf( "UNTFS: RecoverCompressedAttribute called for non-compressed attribute.\n" );
+ return FALSE;
+ }
+
+ if( !OneClusterMem.Initialize() ||
+ !OneCluster.Initialize( &OneClusterMem,
+ GetDrive(),
+ 0,
+ QueryClusterFactor(),
+ 1 ) ) {
+
+ return FALSE;
+ }
+
+ if( BytesRecovered ) {
+
+ *BytesRecovered = 0;
+ }
+
+ ClustersPerCompressionUnit = 1 << QueryCompressionUnit();
+ BytesPerCluster = QueryClusterFactor() * GetDrive()->QuerySectorSize();
+
+ CompressedBuffer = (PUCHAR)MALLOC( ClustersPerCompressionUnit * BytesPerCluster );
+ UncompressedBuffer = (PUCHAR)MALLOC( ClustersPerCompressionUnit * BytesPerCluster );
+
+ if( CompressedBuffer == NULL || UncompressedBuffer == NULL ) {
+
+ CompressedBuffer ? FREE( CompressedBuffer ) : 0;
+ UncompressedBuffer ? FREE( UncompressedBuffer ) : 0;
+ return FALSE;
+ }
+
+ ClustersRemaining = QueryAllocatedLength().GetLowPart()/BytesPerCluster;
+ CurrentVcn = 0;
+
+ while( ClustersRemaining ) {
+
+ DiscardThisUnit = FALSE;
+
+ if( ClustersRemaining < ClustersPerCompressionUnit ) {
+
+ ClustersPerCompressionUnit = ClustersRemaining;
+ }
+
+ CompressedClusters = 0;
+ Holes = 0;
+
+ while( CompressedClusters < ClustersPerCompressionUnit ) {
+
+ if( !QueryLcnFromVcn( CurrentVcn + CompressedClusters + Holes,
+ &Lcn,
+ &RunLength ) ) {
+
+ // No more clusters in this compression unit.
+ // Check to make sure that the gap covers at
+ // least the rest of the compression unit.
+ //
+
+ if( CompressedClusters + Holes < ClustersPerCompressionUnit ) {
+
+ DebugPrintf( "UNTFS: malformed compression unit at VCN 0x%x\n",
+ CurrentVcn.GetLowPart() );
+ DiscardThisUnit = TRUE;
+ }
+ break;
+ }
+
+ if( Lcn == LCN_NOT_PRESENT ) {
+
+ Holes += RunLength.GetLowPart();
+ continue;
+ }
+
+ if( CompressedClusters + RunLength.GetLowPart() >
+ ClustersPerCompressionUnit ) {
+
+ ThisRun = ClustersPerCompressionUnit - CompressedClusters;
+
+ } else {
+
+ ThisRun = RunLength.GetLowPart();
+ }
+
+ if( !ClusterMem.Initialize() ||
+ !ClusterRun.Initialize( &ClusterMem,
+ GetDrive(),
+ Lcn,
+ QueryClusterFactor(),
+ ThisRun ) ) {
+
+ FREE( CompressedBuffer );
+ FREE( UncompressedBuffer );
+ return FALSE;
+ }
+
+ if( !ClusterRun.Read() ) {
+
+ // There's a bad sector in here. Read the clusters
+ // one at a time to see which ones are bad.
+ //
+ for( i = 0; i < ThisRun; i++ ) {
+
+ OneCluster.Relocate( Lcn + i );
+
+ if( !OneCluster.Read() ) {
+
+ // This one's bad--add it to the bad block list.
+ //
+ BadClusters->Add( Lcn + i );
+ }
+ }
+
+ DebugPrintf( "UNTFS: unreadable compression unit at VCN 0x%x\n", CurrentVcn.GetLowPart() + CompressedClusters );
+ DiscardThisUnit = TRUE;
+
+ } else {
+
+ // Copy this run into the compressed buffer.
+ //
+ memcpy( CompressedBuffer + CompressedClusters * BytesPerCluster,
+ ClusterRun.GetBuf(),
+ ThisRun * BytesPerCluster );
+
+ }
+
+ CompressedClusters += ThisRun;
+ }
+
+ if( !DiscardThisUnit &&
+ CurrentVcn * BytesPerCluster < QueryValidDataLength() &&
+ CompressedClusters != 0 &&
+ CompressedClusters != ClustersPerCompressionUnit ) {
+
+ // The clusters can all be read--see if they can be
+ // decompressed.
+ //
+ Status = RtlDecompressBuffer( COMPRESSION_FORMAT_LZNT1,
+ UncompressedBuffer,
+ ClustersPerCompressionUnit * BytesPerCluster,
+ CompressedBuffer,
+ CompressedClusters * BytesPerCluster,
+ &UncompressedSize );
+
+ // If the RTL compression routines are not implemented,
+ // assume that the compressed data is just fine.
+ //
+ if( Status != STATUS_NOT_IMPLEMENTED &&
+ Status != STATUS_NOT_SUPPORTED &&
+ !NT_SUCCESS( Status ) ) {
+
+ // Can't decompress it.
+ //
+ DebugPrintf( "UNTFS: RtlDecompressBuffer failed--status 0x%x\n", Status );
+ DiscardThisUnit = TRUE;
+ }
+ }
+
+ if( DiscardThisUnit ) {
+
+ // Replace this compression unit with a gap.
+ // Walk through all the extents, clipping any
+ // extent that intersects the discarded unit.
+ //
+ SetStorageModified();
+
+ i = 0;
+
+ while( _ExtentList->QueryExtent( i,
+ &Vcn,
+ &Lcn,
+ &RunLength ) ) {
+
+ if( Lcn == LCN_NOT_PRESENT ) {
+
+ i++;
+ continue;
+ }
+
+ if( Vcn >= CurrentVcn + ClustersPerCompressionUnit ) {
+
+ // We're done.
+ //
+ break;
+ }
+
+ if( Vcn + RunLength <= CurrentVcn ) {
+
+ // This run does not overlap the discarded
+ // segment. Try the next one.
+ //
+ i++;
+ continue;
+ }
+
+ _ExtentList->DeleteExtent( i );
+
+ if( Vcn < CurrentVcn &&
+ !_ExtentList->AddExtent( Vcn,
+ Lcn,
+ CurrentVcn - Vcn ) ) {
+
+ FREE( CompressedBuffer );
+ FREE( UncompressedBuffer );
+ return FALSE;
+ }
+
+ if( Vcn + RunLength > CurrentVcn + ClustersPerCompressionUnit &&
+ !_ExtentList->AddExtent( CurrentVcn + ClustersPerCompressionUnit,
+ Lcn + (CurrentVcn - Vcn ) +
+ ClustersPerCompressionUnit,
+ RunLength - (CurrentVcn - Vcn ) -
+ ClustersPerCompressionUnit ) ) {
+
+ FREE( CompressedBuffer );
+ FREE( UncompressedBuffer );
+ return FALSE;
+ }
+
+ // Free stuff in the bitmap.
+ //
+ for( j = 0; j < ClustersPerCompressionUnit; j++ ) {
+
+ if( !BadClusters->DoesIntersectSet( CurrentVcn + j, 1 ) ) {
+
+ // this cluster was not added to the bad clusters,
+ // it has become free.
+ //
+ VolumeBitmap->SetFree( CurrentVcn + j, 1 );
+ }
+ }
+
+ // Don't advance to the next extent, since we may have
+ // deleted this entire extent.
+ }
+
+ } else {
+
+ if( BytesRecovered &&
+ CurrentVcn * BytesPerCluster < QueryValueLength() ) {
+
+ if( CurrentVcn * BytesPerCluster +
+ ClustersPerCompressionUnit * BytesPerCluster >
+ QueryValueLength() ) {
+
+ *BytesRecovered += QueryValueLength() - CurrentVcn * BytesPerCluster;
+
+ } else {
+
+ *BytesRecovered += ClustersPerCompressionUnit * BytesPerCluster;
+ }
+ }
+ }
+
+ ClustersRemaining -= ClustersPerCompressionUnit;
+ CurrentVcn += ClustersPerCompressionUnit;
+ }
+
+ FREE( CompressedBuffer );
+ FREE( UncompressedBuffer );
+ return TRUE;
+}
+
+BOOLEAN
+NTFS_ATTRIBUTE::IsAllocationZeroed(
+ OUT PBOOLEAN Error
+ )
+/*++
+
+Routine Description:
+
+ This routine reads the attribute value and checks whether all the
+ bytes in the allocation are zeros.
+
+Arguments:
+
+ Error - if this routine returns false, check error to see if it
+ encountered an error trying to read the attribute.
+
+Return Value:
+
+ TRUE if all zeroes, FALSE otherwise.
+
+--*/
+{
+ CONST MaxNumBytesToCheck = 65536;
+ ULONG num_bytes, chomp_length, bytes_read, disk_bytes;
+ ULONG bytes_left;
+ PUCHAR buf;
+ PBYTE p1, p2;
+ ULONG i, j;
+ BOOLEAN error;
+
+ DebugAssert(QueryValueLength().GetHighPart() == 0);
+
+ if (NULL != Error) {
+ *Error = FALSE;
+ } else {
+ Error = &error;
+ }
+
+ disk_bytes = QueryValueLength().GetLowPart();
+
+ if (NULL == (buf = NEW UCHAR[min(MaxNumBytesToCheck, disk_bytes)])) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ for (i = 0; i < disk_bytes; i += MaxNumBytesToCheck) {
+
+ chomp_length = min(MaxNumBytesToCheck, disk_bytes - i);
+
+ if (!Read(buf, i, chomp_length, &bytes_read) ||
+ bytes_read != chomp_length) {
+
+ *Error = TRUE;
+ DELETE(buf);
+ return FALSE;
+ }
+
+ for (j = 0; j < chomp_length; j++) {
+
+ if (buf[j] != 0) {
+ DELETE(buf);
+ return FALSE;
+ }
+ }
+ }
+
+ DELETE(buf);
+ return TRUE;
+}
diff --git a/private/utils/untfs/src/attrlist.cxx b/private/utils/untfs/src/attrlist.cxx
new file mode 100644
index 000000000..741ff18ff
--- /dev/null
+++ b/private/utils/untfs/src/attrlist.cxx
@@ -0,0 +1,1952 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ attrlist.cxx
+
+Abstract:
+
+ This module contains the member function definitions for
+ NTFS_ATTRIBUTE_LIST, which models an ATTRIBUTE_LIST Attribute
+ in an NTFS File Record Segment.
+
+ If a file has any external attributes (i.e. if it has more than
+ one File Record Segment), then it will have an ATTRIBUTE_LIST
+ attribute. This attribute's value consists of a series of
+ Attribute List Entries, which describe the attribute records
+ in the file's File Record Segments. There is an entry for each
+ attribute record attached to the file, including the attribute
+ records in the base File Record Segment, and in particular
+ including the attribute records which describe the ATTRIBUTE_LIST
+ attribute itself.
+
+ An entry in the Attribute List gives the type code and name (if any)
+ of the attribute, along with the LowestVcn of the attribute record
+ (zero if the attribute record is Resident) and a segment reference
+ (which combines an MFT VCN with a sequence number) showing where
+ the attribute record may be found.
+
+ The entries in the Attribute List are sorted first by attribute
+ type code and then by name. Note that two attributes can have the
+ same type code and name only if they can be distinguished by
+ value.
+
+Author:
+
+ Bill McJohn (billmc) 12-Aug-1991
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "untfs.hxx"
+
+#include "wstring.hxx"
+#include "hackwc.hxx"
+
+#include "attrlist.hxx"
+#include "attrrec.hxx"
+#include "upcase.hxx"
+
+#include "message.hxx"
+#include "rtmsg.h"
+
+
+ULONG
+CompareAttributeListEntries(
+ IN PCATTRIBUTE_LIST_ENTRY Left,
+ IN PCATTRIBUTE_LIST_ENTRY Right,
+ IN PCNTFS_UPCASE_TABLE UpcaseTable
+ )
+/*++
+
+Routine Description:
+
+ This function compares two attribute list entries.
+
+Arguments:
+
+ Left -- Supplies the left hand of the comparison
+ Right -- Supplies the right hand of the comparison
+ UpcaseTable -- Supplies the volume upcase table.
+
+Return Value:
+
+ <0 if Left is less than Right
+ 0 if Left equals Right
+ >0 if Left is greater than Right.
+
+Notes:
+
+ Attribute List Entries are ordered first by type code, then
+ by name, and finally by lowest VCN. An attribute list entry
+ with no name is less than any entry of the same type code with
+ a name.
+
+ Name comparision is first done case-insensitive; if the names
+ are equal by that metric, a case-sensitive comparision is made.
+
+ The UpcaseTable parameter may be omitted if either or both names
+ are zero-length, or if they are identical (including case).
+ Otherwise, it must be supplied.
+
+--*/
+{
+ LONG Result;
+
+ // First, compare the type codes:
+ //
+ Result = Left->AttributeTypeCode - Right->AttributeTypeCode;
+
+ if( Result != 0 ) {
+
+ return Result;
+ }
+
+ // The entries have the same type code, so we compare the
+ // names. Pass in TRUE for the IsAttribute parameter, to
+ // indicate that we are comparing attribute names.
+ //
+ Result = NtfsUpcaseCompare( NameFromEntry( Left ),
+ Left->AttributeNameLength,
+ NameFromEntry( Right ),
+ Right->AttributeNameLength,
+ UpcaseTable,
+ TRUE );
+
+ if( Result != 0 ) {
+
+ return Result;
+ }
+
+ // These two entries have the same type code and name;
+ // compare the lowest VCN.
+ //
+ if( Left->LowestVcn < Right->LowestVcn ) {
+
+ Result = -1;
+
+ } else if( Left->LowestVcn < Right->LowestVcn ) {
+
+ Result = 1;
+
+ } else {
+
+ Result = 0;
+ }
+
+ return Result;
+}
+
+
+DEFINE_CONSTRUCTOR( NTFS_ATTRIBUTE_LIST, NTFS_ATTRIBUTE );
+
+
+NTFS_ATTRIBUTE_LIST::~NTFS_ATTRIBUTE_LIST(
+ )
+{
+ Destroy();
+}
+
+VOID
+NTFS_ATTRIBUTE_LIST::Construct(
+ )
+/*++
+
+Routine Description:
+
+ Worker function for object construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _LengthOfList = 0;
+ _UpcaseTable = NULL;
+}
+
+VOID
+NTFS_ATTRIBUTE_LIST::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Worker function for object destruction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _LengthOfList = 0;
+ _UpcaseTable = NULL;
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE_LIST::Initialize(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN ULONG ClusterFactor,
+ IN PNTFS_UPCASE_TABLE UpcaseTable
+ )
+/*++
+
+Routine Description:
+
+ This method initializes an empty attribute list.
+
+Arguments:
+
+ Drive -- supplies the drive on which the attribute list resides
+ ClusterFactor -- supplies the cluster factor for that drive
+ UpcaseTable -- supplies the volume upcase table.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ UpcaseTable may be NULL if the client will never compare
+ named attribute records.
+
+--*/
+{
+ Destroy();
+
+ if( !_Mem.Initialize() ||
+ !NTFS_ATTRIBUTE::Initialize( Drive,
+ ClusterFactor,
+ NULL,
+ 0,
+ $ATTRIBUTE_LIST ) ) {
+
+ return FALSE;
+ }
+
+ _UpcaseTable = UpcaseTable;
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE_LIST::Initialize(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN ULONG ClusterFactor,
+ IN PCNTFS_ATTRIBUTE_RECORD AttributeRecord,
+ IN PNTFS_UPCASE_TABLE UpcaseTable
+ )
+/*++
+
+Routine Description:
+
+ This method initializes an attribute list based on an
+ attribute record.
+
+Arguments:
+
+ Drive -- supplies the drive on which the attribute list resides
+ ClusterFactor -- supplies the cluster factor for that drive
+ AttributeRecord -- supplies the attribute record describing the
+ attribute list.
+ UpcaseTable -- supplies the volume upcase table.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This method does not read the attribute list.
+
+ UpcaseTable may be NULL if the client will never compare
+ named attribute records.
+
+--*/
+{
+ Destroy();
+
+ if( !_Mem.Initialize() ||
+ !NTFS_ATTRIBUTE::Initialize( Drive,
+ ClusterFactor,
+ AttributeRecord ) ) {
+
+ return FALSE;
+ }
+
+ _UpcaseTable = UpcaseTable;
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE_LIST::VerifyAndFix(
+ IN FIX_LEVEL FixLevel,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PMESSAGE Message,
+ IN VCN FileNumber,
+ OUT PBOOLEAN Tube,
+ IN OUT PBOOLEAN DiskErrorsFound
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies and fixes this attribute list under
+ the assumption that this class was initialized with an
+ attribute record that was itself VerifiedAndFixed.
+
+ In other words, this routine will check the issues specific
+ to the $ATTRIBUTE_LIST attribute.
+
+Arguments:
+
+ FixLevel - Supplies the fix up level.
+ VolumeBitmap - Supplies the volume bitmap.
+ Message - Supplies an outlet for messages.
+ FileNumber - Supplies the file number for the file that owns
+ this attribute list.
+ Tube - Returns whether or not the attribute list is beyond
+ repair.
+ DiskErrorsFound - Supplies whether or not disk errors have been found.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ BIG_INT file_size;
+ BIG_INT alloc_size;
+ BIG_INT valid_size;
+ PATTRIBUTE_LIST_ENTRY p;
+ ULONG length;
+ BOOLEAN need_write;
+ BOOLEAN changes;
+
+ DebugAssert(VolumeBitmap);
+ DebugAssert(Message);
+ DebugAssert(Tube);
+
+ *Tube = FALSE;
+
+ // If the attribute is non-resident then make sure that the
+ // lowest vcn is 0 and the the three size parameters make sense.
+
+ if (!GetResidentValue()) {
+
+ QueryValueLength(&file_size, &alloc_size, &valid_size);
+
+ if (GetExtentList()->QueryLowestVcn() != 0 ||
+ alloc_size != QueryClusterFactor()*
+ GetDrive()->QuerySectorSize()*
+ GetExtentList()->QueryNextVcn()) {
+
+ Message->Set(MSG_CHK_NTFS_BAD_ATTR_LIST);
+ Message->Display("%d", FileNumber.GetLowPart());
+
+ *Tube = TRUE;
+ return TRUE;
+ }
+ }
+
+
+ // Read the attribute. If it is not readable then it must be tubed.
+
+ if (!ReadList()) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_READ_ATTR_LIST);
+ Message->Display("%d", FileNumber.GetLowPart());
+
+ *Tube = TRUE;
+ return TRUE;
+ }
+
+
+ // Go through the attribute list entries and make sure that
+ // they're all ok. If any of them are not good then delete
+ // them.
+
+ need_write = FALSE;
+
+ p = (PATTRIBUTE_LIST_ENTRY) _Mem.GetBuf();
+ length = 0;
+ while (length + sizeof(ATTRIBUTE_TYPE_CODE) + sizeof(USHORT) <
+ _LengthOfList) {
+
+ // Make sure that the record fits inside the attribute list.
+
+ if (length + p->RecordLength > _LengthOfList) {
+ break;
+ }
+
+ // If the record length is zero then break out of this loop.
+
+ if (!p->RecordLength) {
+ break;
+ }
+
+ // Make sure the name fits inside the attribute list entry.
+
+ if (p->AttributeNameLength != 0 &&
+ ( p->AttributeNameLength + p->AttributeNameOffset >
+ p->RecordLength ||
+ p->AttributeNameOffset <
+ FIELD_OFFSET(ATTRIBUTE_LIST_ENTRY, AttributeName) )) {
+
+ need_write = TRUE;
+
+ Message->Set(MSG_CHK_NTFS_BAD_ATTR_LIST_ENTRY);
+ Message->Display("%d%d", p->AttributeTypeCode,
+ FileNumber.GetLowPart());
+
+ _LengthOfList -= p->RecordLength;
+
+ memmove(p,
+ (PCHAR) p + p->RecordLength,
+ (UINT) (_LengthOfList - length));
+
+ p = (PATTRIBUTE_LIST_ENTRY) _Mem.GetBuf();
+ length = 0;
+ continue;
+ }
+
+ length += p->RecordLength;
+ p = NextEntry(p);
+ }
+
+
+ if (length != _LengthOfList) {
+
+ need_write = TRUE;
+
+ Message->Set(MSG_CHK_NTFS_ATTR_LIST_TRUNC);
+ Message->Display("%d", FileNumber.GetLowPart());
+ _LengthOfList = length;
+ }
+
+
+ // Now that the attribute list is valid, it must next be sorted.
+
+ if (!Sort(&changes)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (changes) {
+ Message->Set(MSG_CHK_NTFS_UNSORTED_ATTR_LIST);
+ Message->Display("%d", FileNumber.GetLowPart());
+ need_write = TRUE;
+ }
+
+ if (need_write) {
+
+ if (DiskErrorsFound) {
+ *DiskErrorsFound = TRUE;
+ }
+
+ if (FixLevel != CheckOnly && !WriteList(VolumeBitmap)) {
+
+ DebugAbort("Cant write readable attribute list");
+ *Tube = TRUE;
+ return TRUE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+NTFS_ATTRIBUTE_LIST::AddEntry(
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN VCN LowestVcn,
+ IN PCMFT_SEGMENT_REFERENCE SegmentReference,
+ IN USHORT InstanceTag,
+ IN PCWSTRING Name
+ )
+/*++
+
+Routine Description:
+
+ This adds an Attribute List Entry to the list.
+
+Arguments:
+
+ Type -- supplies the attribute type code of the
+ attribute record corresponding to this entry
+ LowestVcn -- supplies the record's LowestVcn
+ SegmentReference -- supplies the location of the record
+ InstanceTag -- supplies the record's attribute instance tag.
+ Name -- supplies the name associated with the
+ record (NULL if it has no name).
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ ULONG LengthOfNewEntry;
+ ULONG NewLengthOfList;
+ PATTRIBUTE_LIST_ENTRY CurrentEntry;
+ ULONG EntryOffset, NameLength;
+
+
+ // Compute the size of the new entry and the new length of the
+ // list with this entry added.
+ //
+ NameLength = ( Name == NULL ) ? 0 : (Name->QueryChCount());
+
+ LengthOfNewEntry = QuadAlign( sizeof(ATTRIBUTE_LIST_ENTRY) +
+ NameLength * sizeof(WCHAR) );
+
+ NewLengthOfList = _LengthOfList + LengthOfNewEntry;
+
+ // If our existing buffer isn't big enough, stretch it to
+ // hold the new entry.
+
+ if( !_Mem.Resize( NewLengthOfList ) ) {
+
+ return FALSE;
+ }
+
+ // Scan forward to the point at which the new entry should
+ // be inserted.
+
+ CurrentEntry = FindEntry( Type, Name, LowestVcn, &EntryOffset );
+
+ // Insert a new entry at CurrentEntry.
+
+ memmove( (PBYTE)CurrentEntry + LengthOfNewEntry,
+ (PVOID)CurrentEntry,
+ _LengthOfList - EntryOffset );
+
+ memset( (PVOID)CurrentEntry, '\0', LengthOfNewEntry );
+
+ _LengthOfList = NewLengthOfList;
+
+ // Fill in the new entry
+
+ CurrentEntry->AttributeTypeCode = Type;
+ CurrentEntry->RecordLength = (USHORT)LengthOfNewEntry;
+ CurrentEntry->AttributeNameLength = (UCHAR)NameLength;
+ CurrentEntry->LowestVcn = LowestVcn;
+ CurrentEntry->SegmentReference = *SegmentReference;
+ CurrentEntry->Instance = InstanceTag;
+ CurrentEntry->AttributeNameOffset = FIELD_OFFSET( ATTRIBUTE_LIST_ENTRY,
+ AttributeName );
+
+ if( Name != NULL ) {
+
+ Name->QueryWSTR( 0,
+ TO_END,
+ NameFromEntry( CurrentEntry ),
+ Name->QueryChCount(),
+ FALSE );
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE_LIST::DeleteEntry(
+ IN ULONG EntryIndex
+ )
+/*++
+
+Routine Description:
+
+ This method deletes the nth entry from the list.
+
+Arguments:
+
+ EntryIndex -- supplies the index of the entry to be deleted
+
+Return Value:
+
+ TRUE upon successful completion. Note that if there are
+ not enough entries, this method returns TRUE.
+
+--*/
+{
+ PATTRIBUTE_LIST_ENTRY CurrentEntry;
+ ULONG CurrentOffset;
+ ULONG BytesToRemove;
+ ULONG i;
+
+
+ // Scan forward to the requested entry
+
+ CurrentOffset = 0;
+ CurrentEntry = (PATTRIBUTE_LIST_ENTRY)(_Mem.GetBuf());
+
+ if( _LengthOfList == 0 ) {
+
+ // The list is empty.
+
+ return TRUE;
+ }
+
+
+ for( i = 0; i < EntryIndex; i++ ) {
+
+ CurrentOffset += CurrentEntry->RecordLength;
+
+ if( CurrentOffset >= _LengthOfList ) {
+
+ // We ran out of entries.
+
+ return TRUE;
+ }
+
+ CurrentEntry = NextEntry( CurrentEntry );
+ }
+
+
+
+ // Delete the entry.
+
+ BytesToRemove = CurrentEntry->RecordLength;
+
+ DebugAssert( CurrentOffset + BytesToRemove <= _LengthOfList );
+
+ memmove( CurrentEntry,
+ (PBYTE)CurrentEntry + BytesToRemove,
+ _LengthOfList - (CurrentOffset + BytesToRemove) );
+
+ _LengthOfList -= BytesToRemove;
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE_LIST::DeleteEntry(
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN VCN LowestVcn,
+ IN PCWSTRING Name,
+ IN PCMFT_SEGMENT_REFERENCE SegmentReference
+ )
+/*++
+
+Routine Description:
+
+ This method deletes from the list the first entry which matches
+ its parameters. This method is used when deleting a non-unique
+ (resident) attribute. It may also be used to delete the entry
+ for a known attribute record (for instance, when we move shuffle
+ records between File Record Segments).
+
+Arguments:
+
+ Type -- Supplies the attribute type code of the
+ entry to be deleted.
+ Name -- Supplies the name of the entry to be deleted;
+ may be NULL, in which case it is ignored.
+ LowestVCN -- Supplies the LowestVcn of the entry to delete.
+ SegmentReference -- Supplies the segment reference field of the
+ entry to be deleted; may be NULL, in which
+ case it is ignored.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ PATTRIBUTE_LIST_ENTRY CurrentEntry;
+ ULONG EntryOffset;
+ ULONG BytesToRemove;
+ PWSTR NameBuffer = NULL;
+ ULONG NameLength;
+
+ // This is slightly ugly but necessary. NTFS attribute names
+ // are collated straight, so we can't use the WSTRING name
+ // comparison, which relies on the current locale.
+
+ if( Name != NULL ) {
+
+ NameLength = Name->QueryChCount();
+ NameBuffer = Name->QueryWSTR();
+
+ if( NameBuffer == NULL ) {
+
+ return FALSE;
+ }
+ }
+
+
+ // Scan forward to the first entry that matches the input
+
+ CurrentEntry = FindEntry( Type, Name, LowestVcn, &EntryOffset );
+
+ if( SegmentReference != NULL ) {
+
+ // The caller specified a segment reference, so we have to
+ // scan through the matching entries until we find that segment
+ // reference or we run out of matching entries.
+
+ while( EntryOffset < _LengthOfList &&
+ CurrentEntry->AttributeTypeCode == Type &&
+ ( Name == NULL ||
+ (NameLength == CurrentEntry->AttributeNameLength &&
+ memcmp( NameBuffer,
+ NameFromEntry(CurrentEntry),
+ NameLength * sizeof(WCHAR) ) == 0) ) &&
+ CurrentEntry->LowestVcn == LowestVcn &&
+ memcmp( SegmentReference,
+ &CurrentEntry->SegmentReference,
+ sizeof(MFT_SEGMENT_REFERENCE) ) != 0 ) {
+
+ EntryOffset += CurrentEntry->RecordLength;
+ CurrentEntry = NextEntry(CurrentEntry);
+ }
+ }
+
+ // If we've gone off the end of the list, or if the type, name,
+ // and LowestVcn don't match, then we don't have any matching
+ // records.
+
+ if( EntryOffset >= _LengthOfList ||
+ CurrentEntry->AttributeTypeCode != Type ||
+ ( Name != NULL &&
+ ( NameLength != CurrentEntry->AttributeNameLength ||
+ memcmp( NameBuffer,
+ NameFromEntry(CurrentEntry),
+ NameLength * sizeof(WCHAR) ) != 0 ) ) ||
+ CurrentEntry->LowestVcn != LowestVcn ) {
+
+ // There are no matching entries, so there's nothing to
+ // delete.
+
+ if( NameBuffer != NULL ) {
+
+ FREE( NameBuffer );
+ }
+
+ return TRUE;
+ }
+
+
+ // Delete the entry.
+
+ BytesToRemove = CurrentEntry->RecordLength;
+
+ DebugAssert( EntryOffset + BytesToRemove <= _LengthOfList );
+
+ memmove( CurrentEntry,
+ (PBYTE)CurrentEntry + BytesToRemove,
+ _LengthOfList - (EntryOffset + BytesToRemove) );
+
+ _LengthOfList -= BytesToRemove;
+
+ if( NameBuffer != NULL ) {
+
+ FREE( NameBuffer );
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE_LIST::DeleteEntries(
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCWSTRING Name
+ )
+/*++
+
+Routine Description:
+
+ This method deletes all entries in the list which match the input.
+ This is used when deleting a unique attribute, since all attribute
+ records for that attribute type-code and name will be removed.
+
+Arguments:
+
+ Type -- Supplies the attribute type code of the
+ entry to be deleted.
+ Name -- Supplies the name of the entry to be deleted;
+ may be NULL, in which case it is ignored.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ PATTRIBUTE_LIST_ENTRY CurrentEntry;
+ ULONG EntryOffset;
+ ULONG BytesToRemove;
+ ULONG NameLength;
+ PWSTR NameBuffer = NULL;
+
+ // This is slightly ugly but necessary. NTFS attribute names
+ // are collated straight, so we can't use the WSTRING name
+ // comparison, which relies on the current locale.
+
+ if( Name != NULL ) {
+
+ NameLength = Name->QueryChCount();
+ NameBuffer = Name->QueryWSTR();
+
+ if( NameBuffer == NULL ) {
+
+ return FALSE;
+ }
+ }
+
+
+ // find the first matching entry.
+
+ CurrentEntry = FindEntry( Type, Name, 0, &EntryOffset );
+
+ while( EntryOffset < _LengthOfList &&
+ CurrentEntry->AttributeTypeCode == Type &&
+ ( Name == NULL ||
+ ( NameLength == CurrentEntry->AttributeNameLength &&
+ memcmp( NameBuffer,
+ NameFromEntry( CurrentEntry ),
+ NameLength * sizeof(WCHAR) ) == 0 ) ) ) {
+
+ // This entry matches, so we delete it. Note that instead of
+ // incrementing CurrentEntry and EntryOffset, we draw the
+ // succeeding entries down to the current point.
+
+ BytesToRemove = CurrentEntry->RecordLength;
+
+ DebugAssert( EntryOffset + BytesToRemove <= _LengthOfList );
+
+ memmove( CurrentEntry,
+ (PBYTE)CurrentEntry + BytesToRemove,
+ _LengthOfList - (EntryOffset + BytesToRemove) );
+
+ _LengthOfList -= BytesToRemove;
+ }
+
+ if( NameBuffer != NULL ) {
+
+ FREE( NameBuffer );
+ }
+
+ return TRUE;
+}
+
+
+NONVIRTUAL
+BOOLEAN
+NTFS_ATTRIBUTE_LIST::IsInList(
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCWSTRING Name
+ ) CONST
+/*++
+
+Routine Description:
+
+Arguments:
+
+ Type -- supplies the type code of the attribute in question.
+ Name -- supplies the name of the attribute in question.
+ (may be NULL, in which case the attribute has no name.)
+Return Value:
+
+ TRUE if there is an entry in the attribute list with this
+ type code and (if specified) name.
+
+--*/
+{
+ PATTRIBUTE_LIST_ENTRY CurrentEntry;
+ ULONG EntryOffset, CurrentEntryIndex;
+ ULONG NameLength;
+ PCWSTR NameBuffer = NULL;
+
+ // This is slightly ugly but necessary. NTFS attribute names
+ // are collated straight, so we can't use the WSTRING name
+ // comparison, which relies on the current locale.
+
+ if( Name != NULL ) {
+
+ NameLength = Name->QueryChCount();
+ NameBuffer = Name->GetWSTR();
+
+ } else {
+
+ NameLength = 0;
+ }
+
+
+ // Find the first entry which matches this type code & name.
+
+ CurrentEntry = FindEntry( Type, Name, 0,
+ &EntryOffset, &CurrentEntryIndex );
+
+ if( EntryOffset >= _LengthOfList ||
+ CurrentEntry->AttributeTypeCode != Type ||
+ NameLength != CurrentEntry->AttributeNameLength ||
+ NtfsUpcaseCompare( NameBuffer,
+ NameLength,
+ NameFromEntry( CurrentEntry ),
+ NameLength,
+ _UpcaseTable,
+ TRUE) != 0 ) {
+
+ // We've gone too far. There are no matching entries.
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE_LIST::QueryEntry(
+ IN ULONG EntryIndex,
+ OUT PATTRIBUTE_TYPE_CODE Type,
+ OUT PVCN LowestVcn,
+ OUT PMFT_SEGMENT_REFERENCE SegmentReference,
+ OUT PUSHORT InstanceTag,
+ OUT PWSTRING Name
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method fetches the nth entry in the list.
+
+Arguments:
+
+ EntryIndex -- supplies the index into the list of the
+ entry to fetch
+ Type -- receives the entry's attribute type code
+ LowestVcn -- receives the entry's LowestVcn
+ SegmentReference -- receives the entry's SegmentReference
+ InstanceTag -- receives the entry's attribute instance tag.
+ Name -- receives the entry's Name (if any)
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ ULONG i;
+ PATTRIBUTE_LIST_ENTRY CurrentEntry;
+ ULONG CurrentOffset;
+
+ CurrentOffset = 0;
+ CurrentEntry = (PATTRIBUTE_LIST_ENTRY)(((PNTFS_ATTRIBUTE_LIST) this)->_Mem.GetBuf());
+
+ if( _LengthOfList == 0 ) {
+
+ // The list is empty.
+
+ return FALSE;
+ }
+
+
+ for( i = 0; i < EntryIndex; i++ ) {
+
+ CurrentOffset += CurrentEntry->RecordLength;
+
+ if( CurrentOffset >= _LengthOfList ) {
+
+ // We ran out of entries.
+
+ return FALSE;
+ }
+
+ CurrentEntry = NextEntry( CurrentEntry );
+ }
+
+ *Type = CurrentEntry->AttributeTypeCode;
+ *LowestVcn = CurrentEntry->LowestVcn;
+ *SegmentReference = CurrentEntry->SegmentReference;
+ *InstanceTag = CurrentEntry->Instance;
+
+ if( !Name->Initialize( NameFromEntry( CurrentEntry ),
+ CurrentEntry->AttributeNameLength ) ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE_LIST::QueryEntry(
+ IN MFT_SEGMENT_REFERENCE SegmentReference,
+ IN USHORT InstanceTag,
+ OUT PATTRIBUTE_TYPE_CODE Type,
+ OUT PVCN LowestVcn,
+ OUT PWSTRING Name
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the type, lowestvcn, and name of the attribute
+ list entry with the given segment reference and instance tag.
+
+Arguments:
+
+ SegmentReference - Supplies the entry's segment reference.
+ InstanceTag - Supplies the entry's instance tag.
+ Type - Returns the entry's type code.
+ LowestVcn - Returns the entry's lowest vcn.
+ Name - Returns the entry's name.
+
+Return Value:
+
+ FALSE - An entry with the given segment reference and instance was
+ not found.
+ TRUE - Success.
+
+--*/
+{
+ ULONG i;
+ PATTRIBUTE_LIST_ENTRY CurrentEntry;
+ ULONG CurrentOffset;
+
+ CurrentOffset = 0;
+ CurrentEntry = (PATTRIBUTE_LIST_ENTRY)(_Mem.GetBuf());
+
+ if( _LengthOfList == 0 ) {
+
+ // The list is empty.
+
+ return FALSE;
+ }
+
+
+ for( i = 0; ; i++ ) {
+
+ if (CurrentEntry->Instance == InstanceTag &&
+ CurrentEntry->SegmentReference == SegmentReference) {
+
+ break;
+ }
+
+ CurrentOffset += CurrentEntry->RecordLength;
+
+ if( CurrentOffset >= _LengthOfList ) {
+
+ // We ran out of entries.
+
+ return FALSE;
+ }
+
+ CurrentEntry = NextEntry( CurrentEntry );
+ }
+
+ *Type = CurrentEntry->AttributeTypeCode;
+ *LowestVcn = CurrentEntry->LowestVcn;
+
+ if( !Name->Initialize( NameFromEntry( CurrentEntry ),
+ CurrentEntry->AttributeNameLength ) ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+UNTFS_EXPORT
+PCATTRIBUTE_LIST_ENTRY
+NTFS_ATTRIBUTE_LIST::GetNextAttributeListEntry(
+ IN PCATTRIBUTE_LIST_ENTRY CurrentEntry
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine fetches the next attribute list entry structure.
+
+Arguments:
+
+ CurrentEntry - Supplies the current attribute list entry.
+ Supplying NULL as the current entry specifies that
+ you want the first entry in the list.
+
+Return Value:
+
+ The next attribute list entry or NULL if the current entry
+ is at the end of the list.
+
+--*/
+{
+ ULONG CurrentOffset;
+
+ if (!_LengthOfList) {
+ return NULL;
+ }
+
+ if (!CurrentEntry) {
+ return (PCATTRIBUTE_LIST_ENTRY) _Mem.GetBuf();
+ }
+
+ CurrentOffset = (PCHAR) CurrentEntry - (PCHAR) _Mem.GetBuf();
+
+ if (CurrentOffset + CurrentEntry->RecordLength >= _LengthOfList) {
+ return NULL;
+ }
+
+ return (PCATTRIBUTE_LIST_ENTRY) ((PCHAR) CurrentEntry + CurrentEntry->RecordLength);
+}
+
+
+
+BOOLEAN
+NTFS_ATTRIBUTE_LIST::QueryExternalReference(
+ IN ATTRIBUTE_TYPE_CODE Type,
+ OUT PMFT_SEGMENT_REFERENCE SegmentReference,
+ OUT PULONG EntryIndex,
+ IN PCWSTRING Name,
+ IN PVCN DesiredVcn,
+ OUT PVCN StartingVcn
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method fetches an entry from the list based on a type code,
+ name (optional), and VCN.
+
+Arguments:
+
+ Type -- supplies the attribute type code to search for.
+ SegmentReference -- receives the entry's SegmentReference
+ EntryIndex -- receives the entry's index into the list
+ Name -- supplies the entry's name. If this pointer
+ is NULL, attribute names are ignored.
+ DesiredVcn -- supplies a pointer to the VCN we're interested
+ in. (Note that this pointer may be NULL if
+ the caller just wants the first entry for this
+ type & name.)
+ StartingVcn -- receives the LowestVcn of the entry found;
+ if this pointer is NULL, that information is
+ not returned.
+
+
+Return Value:
+
+ TRUE if a matching entry is found.
+
+Notes:
+
+ A client who wishes to find all the entries for a particular
+ attribute can take advantage of the fact that the list is sorted
+ by type code and name. Thus, the client finds the first matching
+ entry (using QueryExternalReference), and then queries successive
+ entries by index until one doesn't match.
+
+--*/
+{
+ PATTRIBUTE_LIST_ENTRY CurrentEntry, PreviousEntry;
+ ULONG EntryOffset, CurrentEntryIndex;
+ ULONG NameLength;
+ PWSTR NameBuffer = NULL;
+
+ // This is slightly ugly but necessary. NTFS attribute names
+ // are collated straight, so we can't use the WSTRING name
+ // comparison, which relies on the current locale.
+
+ if( Name != NULL ) {
+
+ NameLength = Name->QueryChCount();
+ NameBuffer = Name->QueryWSTR();
+
+ if( NameBuffer == NULL ) {
+
+ return FALSE;
+ }
+ }
+
+
+ // The search algorithm for this method is slightly different than
+ // the other methods for this class. Instead of the first matching
+ // entry, we want the last matching entry which has a LowestVcn field
+ // less than or equal to *DesiredVcn. (If DesiredVcn is NULL, we can
+ // just return the first entry we find.)
+
+ CurrentEntry = FindEntry( Type, Name, 0,
+ &EntryOffset, &CurrentEntryIndex );
+
+ if( EntryOffset >= _LengthOfList ||
+ CurrentEntry->AttributeTypeCode != Type ||
+ ( Name != NULL &&
+ ( NameLength != CurrentEntry->AttributeNameLength ||
+ memcmp( NameBuffer,
+ NameFromEntry( CurrentEntry ),
+ NameLength * sizeof(WCHAR) ) != 0 ) ) ||
+ ( DesiredVcn != NULL &&
+ CurrentEntry->LowestVcn > *DesiredVcn ) ) {
+
+ // We've gone too far. There are no matching entries.
+
+ if( NameBuffer != NULL ) {
+
+ FREE( NameBuffer );
+ }
+
+ return FALSE;
+ }
+
+ if( DesiredVcn != NULL ) {
+
+ // The caller specified a particular VCN, so we have to find the
+ // entry that contains it. We do this by scanning forward until
+ // we find an entry that is beyond what we want, and then backing
+ // up one. Since we passed the test above, we know that the
+ // loop below will execute at least once, so PreviousEntry is
+ // sure to get set.
+
+ while( EntryOffset < _LengthOfList &&
+ CurrentEntry->AttributeTypeCode == Type &&
+ ( Name == NULL ||
+ ( NameLength == CurrentEntry->AttributeNameLength &&
+ memcmp( NameBuffer,
+ NameFromEntry( CurrentEntry ),
+ NameLength * sizeof(WCHAR) ) == 0 ) ) &&
+ CurrentEntry->LowestVcn <= *DesiredVcn ) {
+
+ PreviousEntry = CurrentEntry;
+ CurrentEntryIndex += 1;
+ EntryOffset += CurrentEntry->RecordLength;
+ CurrentEntry = NextEntry( CurrentEntry );
+ }
+
+ // Now back up one, to the entry we really want:
+
+ CurrentEntry = PreviousEntry;
+ CurrentEntryIndex -= 1;
+ }
+
+ // Fill in the output parameters.
+
+ memcpy( SegmentReference,
+ &CurrentEntry->SegmentReference,
+ sizeof( MFT_SEGMENT_REFERENCE ) );
+
+ *EntryIndex = CurrentEntryIndex;
+
+ if( StartingVcn != NULL ) {
+
+ *StartingVcn = CurrentEntry->LowestVcn;
+ }
+
+ if( NameBuffer != NULL ) {
+
+ FREE( NameBuffer );
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE_LIST::QueryNextAttribute(
+ IN OUT PATTRIBUTE_TYPE_CODE TypeCode,
+ IN OUT PWSTRING Name
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method determines the type code and name of the first
+ attribute list which is strictly greater than the supplied
+ type and name.
+
+Arguments:
+
+ TypeCode -- supplies the current attribute type code. Receives
+ the type code of the next attribute. A returned type
+ code of $END indicates that there are no more attributes.
+ Name -- supplies the current name. Receives the name of the
+ next attribute.
+
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This method is useful for iterating through the non-indexed
+ attributes of a file, since there can only be one non-indexed
+ attribute with a given type code and name in the file. However,
+ it offers no way of dealing with indexed attributes, which may
+ be distinguished only by value.
+
+--*/
+{
+ PATTRIBUTE_LIST_ENTRY CurrentEntry;
+ ULONG CurrentEntryOffset, CurrentEntryIndex;
+
+ // Use FindEntry to get to the entry we want. Note that we use
+ // a LowestVcn of -1, to skip over all matching entries.
+
+ if( (CurrentEntry = FindEntry( *TypeCode,
+ Name,
+ -1,
+ &CurrentEntryOffset,
+ &CurrentEntryIndex )) == NULL ) {
+
+ // An error occurred searching the list.
+ return FALSE;
+ }
+
+ if( CurrentEntryOffset >= _LengthOfList ) {
+
+ // This is the end of the list; there are no more entries.
+
+ *TypeCode = $END;
+
+ return Name->Initialize("");
+ }
+
+ // OK, we have the entry we want. Copy its type and name (if any).
+
+ *TypeCode = CurrentEntry->AttributeTypeCode;
+
+ if( !Name->Initialize( NameFromEntry(CurrentEntry),
+ CurrentEntry->AttributeNameLength ) ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+NTFS_ATTRIBUTE_LIST::ReadList(
+ )
+/*++
+
+Routine Description:
+
+ This method reads the list into the object's private buffer.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ BIG_INT ValueLength;
+ ULONG BytesRead;
+
+ // Determine the length of the list.
+
+ QueryValueLength( &ValueLength );
+
+ DebugAssert( ValueLength.GetHighPart() == 0 );
+
+ _LengthOfList = ValueLength.GetLowPart();
+
+ // Initialize our MEM object and use it to get the correct
+ // amount of memory.
+
+ if( !_Mem.Initialize() ||
+ !_Mem.Acquire( (LONG)_LengthOfList ) ) {
+
+ return FALSE;
+ }
+
+ // Read the attribute's value into our buffer.
+
+ return( Read( _Mem.GetBuf(), 0, _LengthOfList, &BytesRead) &&
+ BytesRead == _LengthOfList );
+}
+
+
+
+PATTRIBUTE_LIST_ENTRY
+NTFS_ATTRIBUTE_LIST::FindEntry(
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCWSTRING Name,
+ IN VCN LowestVcn,
+ OUT PULONG EntryOffset,
+ OUT PULONG EntryIndex
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method finds the first entry in the list which matches
+ its input or, if there is no match, the first entry that
+ would come after it (i.e. the place it would be if it were there).
+
+Arguments:
+
+ Type -- supplies the attribute type code to find
+ Name -- supplies the name to find (may be NULL, in which case it
+ is ignored)
+ LowestVcn -- supplies the VCN to find. A value of -1 indicates
+ we should skip all entries for this type and name.
+ EntryOffset -- receives the offset into the list of the
+ returned pointer. (May be NULL, in which case
+ this value is not returned.)
+ EntryIndex -- receives the index into the list of the returned
+ entry. (May be NULL, in which case this value
+ is not returned.
+
+
+Return Value:
+
+ A pointer to the first entry in the list which matches the input.
+ If there is no match, this method returns the next entry (i.e. the
+ point at which a matching entry should be inserted).
+
+ NULL is returned to indicate end of entry.
+
+--*/
+{
+ PATTRIBUTE_LIST_ENTRY CurrentEntry;
+ ULONG CurrentOffset, CurrentIndex;
+ ULONG NameLength;
+ PWSTR NameBuffer = NULL;
+
+ // This is slightly ugly but necessary. NTFS attribute names
+ // are collated straight, so we can't use the WSTRING name
+ // comparison, which relies on the current locale.
+
+ if( Name != NULL ) {
+
+ NameLength = Name->QueryChCount();
+ NameBuffer = Name->QueryWSTR();
+
+ if( NameBuffer == NULL ) {
+
+ return NULL;
+ }
+ }
+
+ // Start at the beginning of the list.
+
+ CurrentEntry = (PATTRIBUTE_LIST_ENTRY)(((PNTFS_ATTRIBUTE_LIST) this)->_Mem.GetBuf());
+ CurrentOffset = 0;
+ CurrentIndex = 0;
+
+ // Scan forward to the first entry which has a type code
+ // greater than or equal to the type code we want.
+
+ while( CurrentOffset < _LengthOfList &&
+ Type > CurrentEntry->AttributeTypeCode ) {
+
+ CurrentIndex += 1;
+ CurrentOffset += CurrentEntry->RecordLength;
+ CurrentEntry = NextEntry( CurrentEntry );
+ }
+
+
+ // CurrentEntry now points at the first entry with an attribute
+ // type code greater than or equal to the one we're seeking.
+ // Within the group of entries with the same type code, the
+ // entries are sorted first by name and then by LowestVcn.
+
+ if( Name != NULL ) {
+
+ // The caller specified a name name, so we need to scan
+ // through the entries with this attribute type code for
+ // the first entry with a name greater than or equal to
+ // that name.
+
+ while( CurrentOffset < _LengthOfList &&
+ Type == CurrentEntry->AttributeTypeCode &&
+ NtfsUpcaseCompare( NameBuffer,
+ NameLength,
+ NameFromEntry( CurrentEntry ),
+ CurrentEntry->AttributeNameLength,
+ _UpcaseTable,
+ TRUE ) > 0 ) {
+
+ CurrentIndex += 1;
+ CurrentOffset += CurrentEntry->RecordLength;
+ CurrentEntry = NextEntry( CurrentEntry );
+ }
+
+ // Now scan forward by LowestVcn through the attributes with
+ // this type code and name. Note that a search value of -1
+ // for LowestVcn indicates we should skip all matching entries.
+
+ while( CurrentOffset < _LengthOfList &&
+ Type == CurrentEntry->AttributeTypeCode &&
+ ( NameLength == CurrentEntry->AttributeNameLength &&
+ memcmp( NameBuffer,
+ NameFromEntry( CurrentEntry ),
+ NameLength * sizeof(WCHAR) ) == 0 ) &&
+ ( (LowestVcn == -1) ||
+ (LowestVcn > CurrentEntry->LowestVcn) ) ) {
+
+ CurrentIndex += 1;
+ CurrentOffset += CurrentEntry->RecordLength;
+ CurrentEntry = NextEntry( CurrentEntry );
+ }
+
+ } else {
+
+ // The caller did not specify a name, so we only examine
+ // entries without names. These come before entries with
+ // that same attribute type code that have names. Scan
+ // forward by LowestVcn through the entries that have this
+ // attribute type code and no name. Note that a search value
+ // of -1 for LowestVcn indicates that we should skip all matching
+ // entries.
+
+ while( CurrentOffset < _LengthOfList &&
+ Type == CurrentEntry->AttributeTypeCode &&
+ CurrentEntry->AttributeNameLength == 0 &&
+ ( (LowestVcn == -1) ||
+ (LowestVcn > CurrentEntry->LowestVcn) ) ) {
+
+ CurrentIndex += 1;
+ CurrentOffset += CurrentEntry->RecordLength;
+ CurrentEntry = NextEntry( CurrentEntry );
+ }
+ }
+
+ if( EntryOffset != NULL ) {
+
+ *EntryOffset = CurrentOffset;
+ }
+
+ if( EntryIndex != NULL ) {
+
+ *EntryIndex = CurrentIndex;
+ }
+
+ if( NameBuffer != NULL ) {
+
+ FREE( NameBuffer );
+ }
+
+ return CurrentEntry;
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE_LIST::QueryAttributeRecord(
+ OUT PVOID AttributeRecordData,
+ IN ULONG MaximumLength,
+ OUT PNTFS_ATTRIBUTE_RECORD AttributeRecord
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes an attribute record which corresponds to
+ this attribute.
+
+Arguments:
+
+ AttributeRecordData - Supplies a buffer for the attribute record.
+ MaximumLength - Supplies the length of the buffer in bytes.
+ AttributeRecord - Returns the attribute record for this attribute.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ BIG_INT value_length;
+ BIG_INT alloc_length;
+ BIG_INT valid_length;
+
+ DebugAssert(AttributeRecordData);
+ DebugAssert(MaximumLength);
+ DebugAssert(AttributeRecord);
+
+ if (!AttributeRecord->Initialize(AttributeRecordData, MaximumLength)) {
+ DebugAbort("Could not initialize attribute record.");
+ return FALSE;
+ }
+
+ QueryValueLength(&value_length, &alloc_length, &valid_length);
+
+ if (GetResidentValue()) {
+
+ DebugAssert(value_length.GetHighPart() == 0);
+
+ if (!AttributeRecord->CreateResidentRecord(GetResidentValue(),
+ value_length.GetLowPart(),
+ QueryTypeCode(),
+ NULL,
+ QueryFlags(),
+ QueryResidentFlags())) {
+
+ return FALSE;
+ }
+
+ } else {
+
+ if (!AttributeRecord->CreateNonresidentRecord(
+ GetExtentList(),
+ alloc_length,
+ value_length,
+ valid_length,
+ QueryTypeCode(),
+ NULL,
+ QueryFlags(),
+ (USHORT)QueryCompressionUnit())) {
+
+ return FALSE;
+ }
+
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+SwapAttributeListEntries(
+ IN OUT PVOID FirstAttributeListEntry
+ )
+/*++
+
+Routine Description:
+
+ This routine swaps 'FirstAttributeListEntry' with the next attribute
+ list entry in the attribute list. This method will fail if there is not
+ enough memory available for a swap buffer.
+
+Arguments:
+
+ FirstAttributeListEntry - Supplies the first of two attribute list
+ entries to be swapped.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ CONST StaticBufSize = 128;
+
+ STATIC CHAR static_buf[StaticBufSize];
+
+ PATTRIBUTE_LIST_ENTRY p1, p2;
+ PCHAR q1, q2;
+ PVOID buf;
+ UINT first_entry_length;
+ BOOLEAN alloc_buf;
+
+ p1 = (PATTRIBUTE_LIST_ENTRY) FirstAttributeListEntry;
+ q1 = (PCHAR) p1;
+
+ first_entry_length = p1->RecordLength;
+
+ if (first_entry_length > StaticBufSize) {
+ if (!(buf = MALLOC(first_entry_length))) {
+ return FALSE;
+ }
+ alloc_buf = TRUE;
+ } else {
+ buf = static_buf;
+ alloc_buf = FALSE;
+ }
+
+ // Tuck away the first record.
+
+ memcpy(buf, p1, first_entry_length);
+
+
+ q2 = q1 + p1->RecordLength;
+ p2 = (PATTRIBUTE_LIST_ENTRY) q2;
+
+
+ // Overwrite first attribute record with second attribute record.
+
+ memmove(p1, p2, (UINT) p2->RecordLength);
+
+
+ // Copy over the first attribute record after the second.
+
+ memcpy(q1 + p1->RecordLength, buf, first_entry_length);
+
+ if (alloc_buf) {
+ FREE(buf);
+ }
+
+ return TRUE;
+}
+
+
+INT
+CompareInstances(
+ IN PCATTRIBUTE_LIST_ENTRY Left,
+ IN PCATTRIBUTE_LIST_ENTRY Right
+ )
+/*++
+
+Routine Description:
+
+ This routine compares the left and right instance and segment
+ reference values for these two attribute list entries.
+
+Arguments:
+
+ Left - Supplies the left side of the comparison.
+ Right - Supplies the right side of the comparison.
+
+Return Value:
+
+ < 0 - Left < Right
+ 0 - Left == Right
+ > 0 - Left > Right
+
+--*/
+{
+ BIG_INT l, r;
+
+ // First compare the segment references as BIG_INTs.
+
+ l = *((PBIG_INT) &Left->SegmentReference);
+ r = *((PBIG_INT) &Right->SegmentReference);
+
+ if (l < r) {
+ return -1;
+ }
+
+ if (l > r) {
+ return 1;
+ }
+
+ if (Left->Instance < Right->Instance) {
+ return -1;
+ }
+
+ if (Left->Instance > Right->Instance) {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE_LIST::Sort(
+ OUT PBOOLEAN Changes
+ )
+/*++
+
+Routine Description:
+
+ This routine sorts an attribute list by type, name, and lowest vcn.
+ It reports through Message if any attribute list entries are out
+ of order.
+
+Arguments:
+
+ Changes - Returns whether or not a change was made.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ BOOLEAN stable;
+ PATTRIBUTE_LIST_ENTRY prev, curr;
+ PCHAR start;
+ ULONG i;
+ INT r;
+
+ DebugAssert(Changes);
+
+ *Changes = FALSE;
+
+ start = (PCHAR) _Mem.GetBuf();
+
+ stable = FALSE;
+
+ while (!stable) {
+
+ stable = TRUE;
+
+ prev = (PATTRIBUTE_LIST_ENTRY) _Mem.GetBuf();
+ DebugAssert(prev);
+
+ for (i = 0; ; i++) {
+
+ curr = NextEntry(prev);
+
+ if ((ULONG)((PCHAR) curr - start) >= _LengthOfList) {
+ break;
+ }
+
+ r = CompareAttributeListEntries( prev,
+ curr,
+ _UpcaseTable );
+
+ if( r > 0 ) {
+
+ // prev is greater than curr--these two
+ // entries are out of order. Swap them.
+
+ if (!SwapAttributeListEntries(prev)) {
+ return FALSE;
+ }
+
+ *Changes = TRUE;
+ stable = FALSE;
+ break;
+
+ } else if( r == 0 ) {
+
+ // These two entries have the same type code, name,
+ // and lowest vcn. We must now insure that they
+ // have different instance numbers.
+
+ r = CompareInstances(prev, curr);
+
+ if (r == 0) {
+
+ // Duplicates. Remove them both.
+
+ if (!DeleteEntry(i + 1) ||
+ !DeleteEntry(i)) {
+
+ DebugAbort("Could not delete entry");
+ return FALSE;
+ }
+
+ *Changes = TRUE;
+ stable = FALSE;
+ break;
+ }
+
+ if (r > 0) {
+
+ // Out of order. Swap.
+
+ if (!SwapAttributeListEntries(prev)) {
+ return FALSE;
+ }
+
+ // We don't set the 'Changes' flag here because
+ // attribute list entries don't have to be ordered by
+ // instance.
+
+ stable = FALSE;
+ curr = NextEntry(prev);
+ }
+ }
+
+ prev = curr;
+ }
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+NTFS_ATTRIBUTE_LIST::ModifyInstanceTag(
+ IN PCNTFS_ATTRIBUTE_RECORD AttributeRecord,
+ IN MFT_SEGMENT_REFERENCE SegmentReference,
+ IN USHORT NewInstanceTag
+ )
+/*++
+
+Routine Description:
+
+ Find an entry in the attribute list and change it's instance
+ tag to the given value.
+
+
+Arguments:
+
+ AttributeRecord -
+ SegmentReference - These two objects describe the interesting
+ attribute list entry -- it's the entry for this
+ attribute record in this segment.
+
+ NewInstanceTag - The desired instance tag value.
+
+Return Value:
+
+ FALSE - Failure (the entry could not be located)
+ TRUE - Success.
+
+--*/
+{
+ ULONG i;
+ PATTRIBUTE_LIST_ENTRY CurrentEntry;
+ ULONG CurrentOffset;
+ USHORT InstanceTag;
+
+ InstanceTag = AttributeRecord->QueryInstanceTag();
+
+ CurrentOffset = 0;
+ CurrentEntry = (PATTRIBUTE_LIST_ENTRY)(_Mem.GetBuf());
+
+ if( _LengthOfList == 0 ) {
+ // The list is empty.
+ return FALSE;
+ }
+
+ for (i = 0; ; i++) {
+
+ if (CurrentEntry->Instance == InstanceTag &&
+ CurrentEntry->SegmentReference == SegmentReference) {
+ break;
+ }
+
+ CurrentOffset += CurrentEntry->RecordLength;
+
+ if( CurrentOffset >= _LengthOfList ) {
+ // We ran out of entries.
+ return FALSE;
+ }
+
+ CurrentEntry = NextEntry(CurrentEntry);
+ }
+
+ CurrentEntry->Instance = NewInstanceTag;
+
+ SetStorageModified();
+
+ return TRUE;
+}
diff --git a/private/utils/untfs/src/attrrec.cxx b/private/utils/untfs/src/attrrec.cxx
new file mode 100644
index 000000000..b32ef7384
--- /dev/null
+++ b/private/utils/untfs/src/attrrec.cxx
@@ -0,0 +1,1465 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ attrrec.hxx
+
+Abstract:
+
+ This module contains the member function definitions for
+ NTFS_ATTRIBUTE_RECORD, which models NTFS attribute records.
+
+ An Attribute Record may be a template laid over a chunk of
+ memory; in that case, it does not own the memory. It may
+ also be told, upon initialization, to allocate its own memory
+ and copy the supplied data. In that case, it is also responsible
+ for freeing that memory.
+
+ Attribute Records are passed between Attributes and File
+ Record Segments. A File Record Segment can initialize
+ an Attribute with a list of Attribute Records; when an
+ Attribute is Set into a File Record Segment, it packages
+ itself up into Attribute Records and inserts them into
+ the File Record Segment.
+
+ File Record Segments also use Attribute Records to scan
+ through their list of attribute records, and to shuffle
+ them around.
+
+Author:
+
+ Bill McJohn (billmc) 14-June-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "untfs.hxx"
+
+#include "wstring.hxx"
+#include "extents.hxx"
+#include "attrrec.hxx"
+#include "attrcol.hxx"
+#include "ntfsbit.hxx"
+#include "extents.hxx"
+
+#include "upcase.hxx"
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( NTFS_ATTRIBUTE_RECORD, OBJECT, UNTFS_EXPORT );
+
+UNTFS_EXPORT
+NTFS_ATTRIBUTE_RECORD::~NTFS_ATTRIBUTE_RECORD(
+ )
+{
+ Destroy();
+}
+
+VOID
+NTFS_ATTRIBUTE_RECORD::Construct(
+ )
+/*++
+
+Routine Description:
+
+ This method is the private worker function for object construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _Data = NULL;
+ _MaximumLength = 0;
+ _IsOwnBuffer = FALSE;
+ _DisableUnUse = FALSE;
+}
+
+VOID
+NTFS_ATTRIBUTE_RECORD::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This method is the private worker function for object destruction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if( _IsOwnBuffer && _Data != NULL ) {
+
+ FREE( _Data );
+ }
+
+ _Data = NULL;
+ _MaximumLength = 0;
+ _IsOwnBuffer = FALSE;
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE_RECORD::Initialize(
+ IN OUT PVOID Data,
+ IN ULONG MaximumLength,
+ IN BOOLEAN MakeCopy
+ )
+/*++
+
+Routine Description:
+
+ This method initializes an NTFS_ATTRIBUTE_RECORD object,
+ handing it a buffer with attribute record data. The caller
+ may also ask the object to make a private copy of the data.
+
+Arguments:
+
+ Data -- supplies a buffer containing the attribute
+ record data the object will own.
+ MaximumLength -- supplies the size of the buffer.
+ MakeCopy -- supplies a flag indicating whether the object
+ should copy the data to a private buffer.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ If MakeCopy is TRUE, then the object must allocate its own
+ buffer and copy the attribute record data to it, in which
+ case the object is also responsible for freeing that private
+ buffer. It that flag is FALSE, then the object will cache a
+ pointer to the buffer supplied by the client; the client is
+ responsible for making sure that buffer remains valid for
+ the lifetime of the NTFS_ATTRIBUTE_RECORD object.
+
+ This object is reinitializable.
+
+--*/
+{
+ Destroy();
+
+ if( !MakeCopy ) {
+
+ _Data = (PATTRIBUTE_RECORD_HEADER) Data;
+ _MaximumLength = MaximumLength;
+ _IsOwnBuffer = FALSE;
+
+ return TRUE;
+
+ } else {
+
+ if( (_Data = (PATTRIBUTE_RECORD_HEADER)
+ MALLOC( (UINT) MaximumLength )) == NULL ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ _MaximumLength = MaximumLength;
+ _IsOwnBuffer = TRUE;
+ memcpy(_Data, Data, (UINT) MaximumLength);
+
+ return TRUE;
+ }
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_ATTRIBUTE_RECORD::Initialize(
+ IN OUT PVOID Data
+ )
+/*++
+
+Routine Description:
+
+ This version of Initialize takes it's maximum size from the
+ attribute record.
+
+Arguments:
+
+ Data - supplies a buffer containing the attribute
+ record data.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ Destroy();
+
+ _Data = (PATTRIBUTE_RECORD_HEADER) Data;
+ _MaximumLength = _Data->RecordLength;
+ _IsOwnBuffer = FALSE;
+
+ return TRUE;
+}
+
+BOOLEAN
+NTFS_ATTRIBUTE_RECORD::CreateResidentRecord(
+ IN PCVOID Value,
+ IN ULONG ValueLength,
+ IN ATTRIBUTE_TYPE_CODE TypeCode,
+ IN PCWSTRING Name,
+ IN USHORT Flags,
+ IN UCHAR ResidentFlags
+ )
+/*++
+
+Routine Description:
+
+ This method formats the object's buffer with a resident
+ attribute record.
+
+Arguments:
+
+ Value -- supplies the attribute value
+ ValueLength -- supplies the length of the value
+ TypeCode -- supplies the attribute type code
+ Name -- supplies the name of the attribute
+ (may be NULL)
+ Flags -- supplies the attribute's flags.
+ ResidentFlags -- supplies the attribute's resident flags
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ // Clear the memory first.
+ memset(_Data, 0, (UINT) _MaximumLength);
+
+ // We will arrange the attribute in the following order:
+ // Attribute Record Header
+ // Name (if any)
+ // Value
+
+ if( _MaximumLength < SIZE_OF_RESIDENT_HEADER ) {
+
+ DebugAbort( "Create: buffer is too small.\n" );
+ return FALSE;
+ }
+
+ _Data->TypeCode = TypeCode;
+ _Data->FormCode = RESIDENT_FORM;
+ _Data->Flags = Flags;
+
+ if( Name != NULL ) {
+
+ _Data->NameLength = (UCHAR) Name->QueryChCount();
+ _Data->NameOffset = DwordAlign(SIZE_OF_RESIDENT_HEADER);
+
+ _Data->Form.Resident.ValueOffset =
+ QuadAlign( _Data->NameOffset +
+ _Data->NameLength * sizeof( WCHAR ) );
+
+ } else {
+
+ _Data->NameLength = 0;
+ _Data->NameOffset = 0;
+
+ _Data->Form.Resident.ValueOffset =
+ QuadAlign(SIZE_OF_RESIDENT_HEADER);
+ }
+
+ _Data->Form.Resident.ValueLength = ValueLength;
+ _Data->Form.Resident.ResidentFlags = ResidentFlags;
+
+ _Data->RecordLength =
+ QuadAlign(_Data->Form.Resident.ValueOffset + ValueLength );
+
+ if( _Data->RecordLength > _MaximumLength ) {
+
+ return FALSE;
+ }
+
+ // Now that we're sure there's room, copy the name (if any)
+ // and the value into their respective places.
+
+ if( Name != NULL ) {
+
+ Name->QueryWSTR( 0,
+ _Data->NameLength,
+ (PWSTR)((PBYTE)_Data + _Data->NameOffset),
+ _Data->NameLength,
+ FALSE );
+ }
+
+ memcpy( (PBYTE)_Data + _Data->Form.Resident.ValueOffset,
+ Value,
+ (UINT) ValueLength );
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE_RECORD::CreateNonresidentRecord(
+ IN PCNTFS_EXTENT_LIST Extents,
+ IN BIG_INT AllocatedLength,
+ IN BIG_INT ActualLength,
+ IN BIG_INT ValidLength,
+ IN ATTRIBUTE_TYPE_CODE TypeCode,
+ IN PCWSTRING Name,
+ IN USHORT Flags,
+ IN USHORT CompressionUnit
+ )
+/*++
+
+Routine Description:
+
+ This method formats the attribute record to hold a nonresident
+ attribute.
+
+Arguments:
+
+ Extents -- supplies an extent list describing the
+ attribute value's disk storage.
+ AllocatedLength -- supplies the allocated length of the value
+ ActualLength -- supplies the actual length of the value
+ ValidLength -- supplies the valid length of the value
+ TypeCode -- supplies the attribute type code
+ Name -- supplies the name of the attribute
+ (may be NULL)
+ Flags -- supplies the attribute's flags.
+ CompressionUnit -- supplies the log in base 2 of the number of
+ clusters per compression unit.
+
+--*/
+{
+ ULONG MappingPairsLength;
+ VCN NextVcn, HighestVcn;
+
+ // Clear the memory first.
+ memset(_Data, 0, (UINT) _MaximumLength);
+
+ // We will arrange the attribute in the following order:
+ // Attribute Record Header
+ // Name (if any)
+ // Compressed Mapping Pairs
+
+ if( _MaximumLength < SIZE_OF_NONRESIDENT_HEADER ) {
+
+ DebugAbort( "Create: buffer is too small.\n" );
+ return FALSE;
+ }
+
+ _Data->TypeCode = TypeCode;
+ _Data->FormCode = NONRESIDENT_FORM;
+ _Data->Flags = Flags;
+
+ if( Name != NULL ) {
+
+ _Data->NameLength = (UCHAR) Name->QueryChCount();
+ _Data->NameOffset = DwordAlign(SIZE_OF_NONRESIDENT_HEADER);
+
+ _Data->Form.Nonresident.MappingPairsOffset =
+ (USHORT)DwordAlign( _Data->NameOffset +
+ _Data->NameLength * sizeof( WCHAR ) );
+
+ } else {
+
+ _Data->NameLength = 0;
+ _Data->NameOffset = 0;
+
+ _Data->Form.Nonresident.MappingPairsOffset =
+ (USHORT)DwordAlign(SIZE_OF_NONRESIDENT_HEADER);
+ }
+
+ _Data->Form.Nonresident.CompressionUnit = (UCHAR)CompressionUnit;
+
+ _Data->Form.Nonresident.AllocatedLength =
+ AllocatedLength.GetLargeInteger();
+
+ _Data->Form.Nonresident.FileSize = ActualLength.GetLargeInteger();
+ _Data->Form.Nonresident.ValidDataLength = ValidLength.GetLargeInteger();
+
+
+ // Copy the name
+
+ if( Name != NULL ) {
+
+ if( (ULONG)(_Data->NameOffset + _Data->NameLength) > _MaximumLength ) {
+
+ // There isn't enough room for the name.
+
+ return FALSE;
+ }
+
+ Name->QueryWSTR( 0,
+ _Data->NameLength,
+ (PWSTR)((PBYTE)_Data + _Data->NameOffset),
+ _Data->NameLength,
+ FALSE );
+ }
+
+
+ if( !Extents->QueryCompressedMappingPairs(
+ (PVCN)&(_Data->Form.Nonresident.LowestVcn),
+ &NextVcn,
+ &MappingPairsLength,
+ _MaximumLength -
+ _Data->Form.Nonresident.MappingPairsOffset,
+ (PVOID)((PBYTE)_Data +
+ _Data->Form.Nonresident.MappingPairsOffset) ) ) {
+
+ // Unable to get the compressed mapping pairs.
+
+ DebugPrint( "Could not get compressed mapping pairs.\n" );
+ return FALSE;
+ }
+
+ HighestVcn = NextVcn - 1;
+ memcpy( &_Data->Form.Nonresident.HighestVcn, &HighestVcn, sizeof(VCN) );
+
+ _Data->RecordLength =
+ QuadAlign(_Data->Form.Nonresident.MappingPairsOffset +
+ MappingPairsLength );
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE_RECORD::Verify(
+ IN PCNTFS_ATTRIBUTE_COLUMNS AttributeDefTable,
+ IN BOOLEAN BeLenient
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine verifies an attribute record for consistency against
+ itself and against the attribute definition table. This routine
+ will return FALSE if the attribute record contains any
+ inconsistencies.
+
+Arguments:
+
+ AttributeDefTable - Supplies the attribute definition table.
+
+Return Value:
+
+ FALSE - The attribute record is inconsistent.
+ TRUE - The attribute record is ok.
+
+--*/
+{
+ NTFS_EXTENT_LIST extent_list;
+ BOOLEAN bad_mapping_pairs;
+ ULONG index;
+ ULONG column_flags;
+ BIG_INT length;
+ PFILE_NAME file_name;
+ ULONG value_length;
+ UCHAR i;
+ PWCHAR p;
+
+ DebugAssert(_Data);
+
+ // Make sure that we can access at least the form code.
+
+ if (FIELD_OFFSET(ATTRIBUTE_RECORD_HEADER, Instance) > _Data->RecordLength) {
+ DebugPrintf("Attribute form code out-of-bounds.\n");
+ return FALSE;
+ }
+
+ // Make sure that the form code is either resident or non-resident.
+
+ if (_Data->FormCode != RESIDENT_FORM &&
+ _Data->FormCode != NONRESIDENT_FORM) {
+
+ DebugPrintf("Attribute %d has non-existent form code.\n", _Data->TypeCode);
+ return FALSE;
+ }
+
+
+ // Make sure that the record is at least as big as the header
+ // for the record
+
+ if (_Data->FormCode == RESIDENT_FORM &&
+ _Data->RecordLength < SIZE_OF_RESIDENT_HEADER) {
+
+ DebugPrintf("Attribute record res header out-of-bounds.\n");
+ return FALSE;
+ }
+
+ if (_Data->FormCode == NONRESIDENT_FORM &&
+ _Data->RecordLength < SIZE_OF_NONRESIDENT_HEADER) {
+ DebugPrintf("Attribute record nonres header out-of-bounds.\n");
+
+ return FALSE;
+ }
+
+
+ switch (_Data->TypeCode) {
+
+ case $STANDARD_INFORMATION:
+
+ if (!IsResident() ||
+ (_Data->Form.Resident.ValueLength !=
+ sizeof(STANDARD_INFORMATION) &&
+ _Data->Form.Resident.ValueLength !=
+ SIZEOF_NEW_STANDARD_INFORMATION)
+ ) {
+
+ // This attribute must be resident and at least
+ // as big as the above structure.
+
+ DebugPrintf("The standard information is too small\n");
+ return FALSE;
+ }
+
+ // Fall through for next check.
+
+ case $ATTRIBUTE_LIST:
+ case $VOLUME_VERSION:
+ case $SECURITY_DESCRIPTOR:
+ case $VOLUME_NAME:
+ case $VOLUME_INFORMATION:
+ case $SYMBOLIC_LINK:
+ case $EA_INFORMATION:
+ case $EA_DATA:
+
+ if (_Data->NameLength) {
+
+ // These attribute may not have names.
+ DebugPrintf("Attribute %d should not have a name.\n", _Data->TypeCode);
+ return FALSE;
+ }
+
+ break;
+
+ case $INDEX_ALLOCATION:
+
+ // $INDEX_ALLOCATION's can't be resident.
+
+ if (IsResident()) {
+ DebugPrintf("Attribute %d has resident index allocation\n", _Data->TypeCode);
+ return FALSE;
+ }
+ break;
+
+ default:
+ break;
+
+ }
+
+
+ // Make sure the name offset if well-aligned and in bounds.
+ // Also make sure that the name does not have any unicode NULLs
+ // in them.
+
+ if (_Data->NameLength) {
+
+ if (_Data->NameOffset%sizeof(WCHAR) ||
+ ULONG(_Data->NameOffset + _Data->NameLength) > _Data->RecordLength) {
+
+ DebugPrintf("Corrupt name for attribute %d.\n", _Data->TypeCode);
+ return FALSE;
+ }
+
+ p = (PWCHAR) ((PCHAR) _Data + _Data->NameOffset);
+ for (i = 0; i < _Data->NameLength; i++) {
+ if (!p[i]) {
+ DebugPrintf("Unicode NULL in attribute name for attribute %d.\n",
+ _Data->TypeCode);
+ return FALSE;
+ }
+ }
+ }
+
+
+ // Make sure that things mesh with the attribute definition table.
+
+ if (AttributeDefTable) {
+
+
+ if (!AttributeDefTable->QueryIndex(_Data->TypeCode, &index)) {
+
+ // The attribute type code doesn't exist in the attribute
+ // definition table.
+
+ DebugPrintf("Attribute %d does not exist in the definition table.\n", _Data->TypeCode);
+ return FALSE;
+ }
+
+ column_flags = AttributeDefTable->QueryFlags(index);
+
+ if (IsResident() &&
+ (_Data->Form.Resident.ResidentFlags & RESIDENT_FORM_INDEXED) &&
+ !(column_flags & ATTRIBUTE_DEF_INDEXABLE)) {
+
+ // Non-indexable indexed attribute.
+
+ DebugPrintf("Attribute %d is NOT indexable.\n", _Data->TypeCode);
+ return FALSE;
+ }
+
+ if ((column_flags & ATTRIBUTE_DEF_MUST_BE_INDEXED) &&
+ !(IsResident() &&
+ (_Data->Form.Resident.ResidentFlags & RESIDENT_FORM_INDEXED))) {
+
+ // Attribute must be indexed but isn't.
+
+ DebugPrintf("Attribute %d is MUST be indexed.\n", _Data->TypeCode);
+ return FALSE;
+ }
+
+ if ((column_flags & ATTRIBUTE_DEF_INDEXABLE) && _Data->NameLength) {
+
+ // Indexable attributes cannot have names.
+
+ DebugPrintf("Attribute %d cannot have a name.\n", _Data->TypeCode);
+ return FALSE;
+ }
+
+ if ((column_flags & ATTRIBUTE_DEF_MUST_BE_NAMED) &&
+ !_Data->NameLength) {
+
+ // Attribute must be named but isn't.
+
+ DebugPrintf("Attribute %d MUST have a name.\n", _Data->TypeCode);
+ return FALSE;
+ }
+
+ if ((column_flags & ATTRIBUTE_DEF_MUST_BE_RESIDENT) &&
+ !IsResident()) {
+
+ // Attribute must be resident but isn't.
+
+ DebugPrintf("Attribute %d MUST be resident.\n", _Data->TypeCode);
+ return FALSE;
+ }
+
+ if (IsResident()) {
+ length = _Data->Form.Resident.ValueLength;
+ } else if (_Data->Form.Nonresident.LowestVcn == 0) {
+ length = _Data->Form.Nonresident.FileSize;
+ } else {
+ length = 0;
+ }
+
+ if (length != 0) {
+
+ if (length < AttributeDefTable->QueryMinimumLength(index)) {
+
+ // Length is less than the minimum.
+
+ DebugPrintf("Attribute %d has length less than the minimum.\n", _Data->TypeCode);
+ return FALSE;
+ }
+
+ // Note that a value of -1 in the Length field of the
+ // Attribute Definition Table entry indicates that the
+ // attribute can be as large as it pleases.
+ //
+ // Note the length of the $STANDARD_INFORMATION attribute
+ // is checked above.
+ //
+
+ if (AttributeDefTable->QueryMaximumLength(index) != -1 &&
+ length > AttributeDefTable->QueryMaximumLength(index) &&
+ _Data->TypeCode != $VOLUME_VERSION &&
+ _Data->TypeCode != $STANDARD_INFORMATION ) {
+
+ // Length is greater than the maximum.
+
+ DebugPrintf("Attribute %d has length greater than the maximum.\n", _Data->TypeCode);
+ return FALSE;
+ }
+ }
+ }
+
+
+ if (IsResident()) {
+
+ // Make sure that the value is in bounds and
+ // make sure that name comes before value.
+
+ if (_Data->Form.Resident.ValueLength) {
+
+ if (_Data->Form.Resident.ValueOffset +
+ _Data->Form.Resident.ValueLength >
+ _Data->RecordLength) {
+
+ DebugPrintf("Attribute %d has corrupt resident value.\n", _Data->TypeCode);
+ return FALSE;
+ }
+
+ if (_Data->NameLength &&
+ _Data->NameOffset +
+ _Data->NameLength >
+ _Data->Form.Resident.ValueOffset) {
+
+ DebugPrintf("Attribute %d colliding name and resident value.\n", _Data->TypeCode);
+ return FALSE;
+ }
+ }
+
+ // Make sure that if the attribute is indexed then it
+ // has no name.
+
+ if ((_Data->Form.Resident.ResidentFlags & RESIDENT_FORM_INDEXED) &&
+ _Data->NameLength) {
+
+ DebugPrintf("Attribute %d is indexed AND has a name.\n", _Data->TypeCode);
+ return FALSE;
+ }
+
+
+ } else {
+
+ // Make sure that the mapping pairs are in bounds.
+
+ if (_Data->Form.Nonresident.MappingPairsOffset >=
+ _Data->RecordLength) {
+
+ DebugPrintf("Attribute %d has mapping pairs that are out of bounds.\n", _Data->TypeCode);
+ return FALSE;
+ }
+
+ if ((QueryFlags() & ATTRIBUTE_FLAG_COMPRESSION_MASK) != 0) {
+
+ if (_Data->Form.Nonresident.LowestVcn == 0 &&
+ _Data->Form.Nonresident.MappingPairsOffset <
+ 4 * sizeof(BIG_INT)) {
+
+ DebugPrintf("Attribute %d MappingPairsOffset too small (%d).\n",
+ _Data->TypeCode,
+ _Data->Form.Nonresident.MappingPairsOffset);
+
+ return FALSE;
+ }
+ } else {
+ if (_Data->Form.Nonresident.LowestVcn == 0 &&
+ _Data->Form.Nonresident.MappingPairsOffset <
+ 3 * sizeof(BIG_INT)) {
+ DebugPrintf("Attribute %d has MappingPairsOffset too small (%d).\n",
+ _Data->TypeCode,
+ _Data->Form.Nonresident.MappingPairsOffset);
+ }
+ }
+
+ // Make sure that the name comes before the mapping pairs.
+
+ if (_Data->NameLength &&
+ _Data->NameOffset +
+ _Data->NameLength >
+ _Data->Form.Nonresident.MappingPairsOffset) {
+
+ DebugPrintf("Attribute %d has its name colliding with the mapping pairs.\n", _Data->TypeCode);
+ return FALSE;
+ }
+
+
+ // Validate the mapping pairs.
+
+ if (!extent_list.Initialize(_Data->Form.Nonresident.LowestVcn,
+ (PCHAR) _Data +
+ _Data->Form.Nonresident.MappingPairsOffset,
+ _Data->RecordLength -
+ _Data->Form.Nonresident.MappingPairsOffset,
+ &bad_mapping_pairs)) {
+
+ DebugPrintf("Attribute %d has bad mapping pairs.\n", _Data->TypeCode);
+ return FALSE;
+ }
+
+ if (extent_list.QueryNextVcn() !=
+ _Data->Form.Nonresident.HighestVcn + 1 && !BeLenient) {
+
+ DebugPrintf("Attribute %d has an invalid highest vcn.\n", _Data->TypeCode);
+ return FALSE;
+ }
+
+
+ // If the lowest vcn is 0 then make sure that the three sizes
+ // make sense.
+
+ if (_Data->Form.Nonresident.LowestVcn == 0 && !BeLenient) {
+
+ if (_Data->Form.Nonresident.ValidDataLength >
+ _Data->Form.Nonresident.FileSize ||
+ _Data->Form.Nonresident.FileSize >
+ _Data->Form.Nonresident.AllocatedLength) {
+
+ DebugPrintf("Attribute %d has inconsistent sizes.\n", _Data->TypeCode);
+ return FALSE;
+ }
+
+ if ((QueryFlags() & ATTRIBUTE_FLAG_COMPRESSION_MASK) != 0 &&
+ _Data->Form.Nonresident.TotalAllocated >
+ _Data->Form.Nonresident.AllocatedLength) {
+
+ DebugPrintf("Attribute %d has inconsistent TotalAllocated.\n",
+ _Data->TypeCode);
+#if 0
+//
+// This would cause the attribute record to be deleted, which is considered
+// to be too harsh a penalty for this minor error.
+//
+ return FALSE;
+#endif
+ }
+
+ if ((QueryFlags() & ATTRIBUTE_FLAG_COMPRESSION_MASK) != 0 &&
+ (_Data->Form.Nonresident.AllocatedLength %
+ (1 << QueryCompressionUnit())) != 0) {
+
+ DebugPrintf("Attribute %d has TotalAllocated not multiple of "
+ "compression unit\n", _Data->TypeCode);
+
+ return FALSE;
+ }
+ }
+
+ }
+
+
+ // $FILE_NAME attribute must follow additional special structure.
+
+ if (_Data->TypeCode == $FILE_NAME) {
+
+ if (!IsIndexed()) {
+ DebugPrintf("File name attribute is not indexed.\n");
+ return FALSE;
+ }
+
+ file_name = (PFILE_NAME) ((PCHAR) _Data +
+ _Data->Form.Resident.ValueOffset);
+
+ value_length = _Data->Form.Resident.ValueLength;
+
+ if (value_length < sizeof(FILE_NAME)) {
+ DebugPrintf("Corrupt file name attribute.\n");
+ return FALSE;
+ }
+
+ if (NtfsFileNameGetLength(file_name) > value_length) {
+ DebugPrintf("Corrupt file name attribute.\n");
+ return FALSE;
+ }
+
+
+ // Make sure that the file name has no NULL
+ // characters in it. If it does then the attribute
+ // is "corrupt".
+
+ for (i = 0; i < file_name->FileNameLength; i++) {
+ if (!file_name->FileName[i]) {
+ DebugPrintf("Attribute %d has filename w/ null characters\n", _Data->TypeCode);
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE_RECORD::UseClusters(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ OUT PBIG_INT ClusterCount
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine allocates the disk space claimed by this attribute
+ record in the bitmap provided. A check is made to verify that
+ the requested disk space is free before the allocation takes
+ place. If the requested space is not available in the bitmap
+ then this routine will return FALSE.
+
+Arguments:
+
+ VolumeBitmap - Supplies the bitmap.
+ ClusterCount - Receives the number of clusters allocated
+ to this record. Not set if method fails.
+
+Return Value:
+
+ FALSE - The request bitmap space was not available.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_EXTENT_LIST extent_list;
+ ULONG num_extents;
+ ULONG i, j;
+ VCN next_vcn;
+ LCN current_lcn;
+ BIG_INT run_length;
+
+ DebugAssert(VolumeBitmap);
+
+ if (IsResident()) {
+ *ClusterCount = 0;
+ return TRUE;
+ }
+
+ if (!QueryExtentList(&extent_list)) {
+ return FALSE;
+ }
+
+ num_extents = extent_list.QueryNumberOfExtents();
+
+ for (i = 0; i < num_extents; i++) {
+
+ if (!extent_list.QueryExtent(i, &next_vcn, &current_lcn,
+ &run_length)) {
+
+ DebugAbort("Could not query extent");
+ return FALSE;
+ }
+
+ if (current_lcn == LCN_NOT_PRESENT) {
+ continue;
+ }
+
+
+ // Make sure that the run is free before allocating.
+ // If it is not, this indicates a cross-link.
+
+ if (!VolumeBitmap->IsFree(current_lcn, run_length)) {
+
+ DebugPrintf("cross-linked run starts at 0x%X for 0x%X\n",
+ current_lcn.GetLowPart(), run_length.GetLowPart());
+
+ // Free everything so far allocated by this routine.
+
+ for (j = 0; j < i; j++) {
+
+ if (!extent_list.QueryExtent(j, &next_vcn, &current_lcn,
+ &run_length)) {
+
+ DebugAbort("Could not query extent");
+ return FALSE;
+ }
+ if (current_lcn == LCN_NOT_PRESENT) {
+ continue;
+ }
+
+ VolumeBitmap->SetFree(current_lcn, run_length);
+ }
+
+ return FALSE;
+ }
+
+ VolumeBitmap->SetAllocated(current_lcn, run_length);
+ }
+
+ *ClusterCount = extent_list.QueryClustersAllocated();
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE_RECORD::UseClusters(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ OUT PBIG_INT ClusterCount,
+ IN ULONG AllowCrossLinkStart,
+ IN ULONG AllowCrossLinkLength,
+ OUT PBOOLEAN DidCrossLinkOccur
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine allocates the disk space claimed by this attribute
+ record in the bitmap provided. A check is made to verify that
+ the requested disk space is free before the allocation takes
+ place. If the requested space is not available in the bitmap
+ then this routine will return FALSE.
+
+ This methode assumes that the range specified by the Allow
+ parameters are marked as allocated in the given bitmap.
+
+Arguments:
+
+ VolumeBitmap - Supplies the bitmap.
+ ClusterCount - Receives the number of clusters allocated
+ to this record. Not set if method fails.
+ AllowCrossLinkStart - Supplies the start of a range where
+ cross-links are allowed.
+ AllowCrossLinkLength - Supplies the length of the range where
+ cross-links are allowed.
+ DidCrossLinkOccur - Returns whether or not an allowable
+ cross-link occurred.
+
+Return Value:
+
+ FALSE - The request bitmap space was not available.
+ TRUE - Success.
+
+--*/
+{
+ BOOLEAN r;
+
+ DebugAssert(DidCrossLinkOccur);
+
+ *DidCrossLinkOccur = FALSE;
+
+ if (UseClusters(VolumeBitmap,ClusterCount)) {
+ return TRUE;
+ }
+
+ *DidCrossLinkOccur = TRUE;
+
+ VolumeBitmap->SetFree(AllowCrossLinkStart, AllowCrossLinkLength);
+
+ r = UseClusters(VolumeBitmap,ClusterCount);
+
+ VolumeBitmap->SetAllocated(AllowCrossLinkStart, AllowCrossLinkLength);
+
+ return r;
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE_RECORD::UnUseClusters(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN ULONG LeaveInUseStart,
+ IN ULONG LeaveInUseLength
+ ) CONST
+/*++
+
+Routine Description:
+
+ This operation reverses a successful 'UseClusters' operation.
+
+ This method assumes that the LeaveInUse range is already in
+ use by the bitmap.
+
+Arguments:
+
+ VolumeBitmap - Supplies the bitmap.
+ LeaveInUseStart - Supplies the start of the range that this routine
+ should leave in use.
+ LeaveInUseLength - Supplies the length of the range that this
+ routine should leave in use.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_EXTENT_LIST extent_list;
+ ULONG num_extents;
+ ULONG i;
+ VCN next_vcn;
+ LCN current_lcn;
+ BIG_INT run_length;
+
+ DebugAssert(VolumeBitmap);
+
+ if (IsResident() || _DisableUnUse) {
+ return TRUE;
+ }
+
+ if (!QueryExtentList(&extent_list)) {
+ return FALSE;
+ }
+
+ num_extents = extent_list.QueryNumberOfExtents();
+
+ for (i = 0; i < num_extents; i++) {
+
+ if (!extent_list.QueryExtent(i, &next_vcn, &current_lcn,
+ &run_length)) {
+
+ DebugAbort("Could not query extent");
+ return FALSE;
+ }
+ if (LCN_NOT_PRESENT == current_lcn) {
+ continue;
+ }
+
+ VolumeBitmap->SetFree(current_lcn, run_length);
+ }
+
+ VolumeBitmap->SetAllocated(LeaveInUseStart, LeaveInUseLength);
+
+ return TRUE;
+}
+
+
+
+NONVIRTUAL
+UNTFS_EXPORT
+BOOLEAN
+NTFS_ATTRIBUTE_RECORD::QueryName(
+ OUT PWSTRING Name
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the name of the attribute.
+
+Arguments:
+
+ Name - Returns the name of the attribute.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ if (FIELD_OFFSET(ATTRIBUTE_RECORD_HEADER, Flags) >= _MaximumLength ||
+ ULONG(_Data->NameOffset + _Data->NameLength) > _MaximumLength ||
+ _Data->NameLength == 0) {
+
+ return Name->Initialize( "" );
+
+ } else {
+
+ return Name->Initialize((PWSTR)((PBYTE)_Data + _Data->NameOffset),
+ _Data->NameLength);
+
+ }
+}
+
+
+VOID
+NTFS_ATTRIBUTE_RECORD::QueryValueLength(
+ OUT PBIG_INT ValueLength,
+ OUT PBIG_INT AllocatedLength,
+ OUT PBIG_INT ValidLength,
+ OUT PBIG_INT TotalAllocated
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the actual, allocated, valid, and
+ total allocated lengths
+ of the attribute value associated with this record.
+
+ If the attribute is resident, these values are all
+ the length of the resident value, except total allocated,
+ which is meaningless.
+
+ If the attribute is nonresident, these four values are only
+ meaningful if the LowestVcn of this attribute record is 0.
+ Additionally, TotalAllocated is only valid for compressed
+ attributes.
+
+Arguments:
+
+ ValueLength -- receives the actual length of the value.
+ AllocatedLength -- receives the allocated size of the value.
+ (may be NULL if the caller doesn't care)
+ ValidLength -- receives the valid length of the value.
+ (may be NULL if the caller doesn't care)
+ TotalAllocated -- receives the total allocated length of the
+ value (may be NULL).
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DebugPtrAssert( _Data );
+
+ if( _Data->FormCode == RESIDENT_FORM ) {
+
+ *ValueLength = _Data->Form.Resident.ValueLength;
+
+ if( AllocatedLength != NULL ) {
+
+ *AllocatedLength = _Data->Form.Resident.ValueLength;
+ }
+
+ if( ValidLength != NULL ) {
+
+ *ValidLength = _Data->Form.Resident.ValueLength;
+ }
+
+ if (TotalAllocated != NULL ) {
+
+ // no such value for resident attributes
+
+ *TotalAllocated = 0;
+ }
+
+ } else {
+
+ DebugAssert( _Data->FormCode == NONRESIDENT_FORM );
+
+ *ValueLength = _Data->Form.Nonresident.FileSize;
+
+ if( AllocatedLength != NULL ) {
+
+ *AllocatedLength = _Data->Form.Nonresident.AllocatedLength;
+ }
+
+ if( ValidLength != NULL ) {
+
+ *ValidLength = _Data->Form.Nonresident.ValidDataLength;
+ }
+
+ if (TotalAllocated != NULL) {
+ if ((_Data->Flags & ATTRIBUTE_FLAG_COMPRESSION_MASK) != 0) {
+ *TotalAllocated = _Data->Form.Nonresident.TotalAllocated;
+ } else {
+ *TotalAllocated = 0;
+ }
+ }
+
+ }
+}
+
+VOID
+NTFS_ATTRIBUTE_RECORD::SetTotalAllocated(
+ IN BIG_INT TotalAllocated
+ )
+/*++
+
+Routine Description:
+
+ Set the "TotalAllocated" field in the attribute record. If the
+ attribute record doesn't have a total allocated field because
+ the attribute isn't compressed or because it's resident, this
+ method has no effect.
+
+Arguments:
+
+ TotalAllocated - the new value.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DebugPtrAssert( _Data );
+
+ if( _Data->FormCode == RESIDENT_FORM ) {
+
+ // no such value for resident attributes; ignore
+
+ return;
+
+ }
+
+ DebugAssert( _Data->FormCode == NONRESIDENT_FORM );
+
+ if ((_Data->Flags & ATTRIBUTE_FLAG_COMPRESSION_MASK) != 0) {
+ _Data->Form.Nonresident.TotalAllocated =
+ TotalAllocated.GetLargeInteger();
+ }
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_ATTRIBUTE_RECORD::QueryExtentList(
+ OUT PNTFS_EXTENT_LIST ExtentList
+ ) CONST
+/*++
+
+Routine Description:
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the extent list. A return value of NULL indicates
+ that the attribute is resident or that an error occurred processing
+ the compressed mapping pairs. (Clients should use IsResident to
+ determine whether the attribute value is resident.)
+
+--*/
+{
+ DebugPtrAssert( _Data );
+
+ if( _Data->FormCode == NONRESIDENT_FORM &&
+ ExtentList->Initialize( _Data->Form.Nonresident.LowestVcn,
+ (PVOID)((PBYTE)_Data +
+ _Data->Form.Nonresident.MappingPairsOffset),
+ _MaximumLength -
+ _Data->Form.Nonresident.
+ MappingPairsOffset ) ) {
+
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+ }
+}
+
+
+BOOLEAN
+NTFS_ATTRIBUTE_RECORD::IsMatch(
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCWSTRING Name,
+ IN PCVOID Value,
+ IN ULONG ValueLength
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method determines whether the attribute record matches the
+ parameters given.
+
+Arguments:
+
+ Type -- Supplies the type code of the attribute. This
+ is the primary key, and must always be present.
+ Name -- Supplies a name to match. A name of NULL is the
+ same as specifying the null string.
+ Value -- Supplies the value to match. If this argument is
+ null, any value matches. Only resident
+ attributes can be checked for value matches.
+ ValueLength -- Supplies the length of the value (if any).
+
+Notes:
+
+ Value matching is not supported for nonresident attribute values;
+ if a Value parameter is supplied, then no non-resident attribute
+ records will match.
+
+--*/
+{
+ DSTRING RecordName;
+
+ DebugPtrAssert( _Data );
+
+ if( Type != _Data->TypeCode ) {
+
+ return FALSE;
+ }
+
+ if( Name != NULL ) {
+
+ if( !RecordName.Initialize((PWSTR)((PBYTE)_Data + _Data->NameOffset),
+ _Data->NameLength ) ) {
+
+ return FALSE;
+ }
+
+ if( Name->Strcmp( &RecordName ) != 0 ) {
+
+ return FALSE;
+ }
+ } else if (_Data->NameLength) {
+ return FALSE;
+ }
+
+ if( Value != NULL &&
+ ( _Data->FormCode != RESIDENT_FORM ||
+ ValueLength != _Data->Form.Resident.ValueLength ||
+ memcmp( Value,
+ (PBYTE)_Data + _Data->Form.Resident.ValueOffset,
+ (UINT) ValueLength ) ) ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+LONG
+CompareAttributeRecords(
+ IN PCNTFS_ATTRIBUTE_RECORD Left,
+ IN PCNTFS_ATTRIBUTE_RECORD Right,
+ IN PCNTFS_UPCASE_TABLE UpcaseTable
+ )
+/*++
+
+Routine Description:
+
+ This method compares two attribute records to determine their
+ correct ordering in the File Record Segment.
+
+Arguments:
+
+ Left -- Supplies the left-hand operand of the comparison.
+ Right -- Supplies the right-hand operand of the comparison.
+ UpcaseTable -- Supplies the upcase table for the volume.
+ If this parameter is NULL, name comparison
+ cannot be performed.
+
+Return Value:
+
+ <0 if Left is less than Right
+ 0 if Left equals Right
+ >0 if Left is greater than Right.
+
+Notes:
+
+ Attribute records are ordered first by type code and then
+ by name. An attribute record without a name is less than
+ any attribute record of the same type with a name.
+
+ Name comparision is first done case-insensitive; if the names
+ are equal by that metric, a case-sensitive comparision is made.
+
+ The UpcaseTable parameter may be omitted if either or both names
+ are zero-length, or if they are identical (including case).
+ Otherwise, it must be supplied.
+
+--*/
+{
+ ULONG Result;
+
+ // First, compare the type codes:
+ //
+ Result = Left->QueryTypeCode() - Right->QueryTypeCode();
+
+ if( Result != 0 ) {
+
+ return Result;
+ }
+
+ // They have the same type code, so we have to compare the names.
+ // Pass in TRUE for the IsAttribute parameter, to indicate that
+ // we are comparing attribute names.
+ //
+ return( NtfsUpcaseCompare( Left->GetName(),
+ Left->QueryNameLength(),
+ Right->GetName(),
+ Right->QueryNameLength(),
+ UpcaseTable,
+ TRUE ) );
+}
diff --git a/private/utils/untfs/src/badfile.cxx b/private/utils/untfs/src/badfile.cxx
new file mode 100644
index 000000000..c4aeafdad
--- /dev/null
+++ b/private/utils/untfs/src/badfile.cxx
@@ -0,0 +1,596 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ badfile.hxx
+
+Abstract:
+
+ This module contains the declarations for the NTFS_BAD_CLUSTER_FILE
+ class, which models the bad cluster file for an NTFS volume.
+
+ The DATA attribute of the bad cluster file is a non-resident
+ attribute to which bad clusters are allocated. It is stored
+ as a sparse file with LCN = VCN.
+
+Author:
+
+ Bill McJohn (billmc) 18-June-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "untfs.hxx"
+
+#include "drive.hxx"
+#include "numset.hxx"
+
+#include "ntfsbit.hxx"
+#include "mft.hxx"
+#include "attrrec.hxx"
+#include "attrib.hxx"
+
+#include "badfile.hxx"
+#include "ifssys.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+
+#define BadfileDataNameData "$Bad"
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( NTFS_BAD_CLUSTER_FILE, NTFS_FILE_RECORD_SEGMENT, UNTFS_EXPORT );
+
+UNTFS_EXPORT
+NTFS_BAD_CLUSTER_FILE::~NTFS_BAD_CLUSTER_FILE(
+ )
+{
+ Destroy();
+}
+
+VOID
+NTFS_BAD_CLUSTER_FILE::Construct(
+ )
+/*++
+
+Routine Description:
+
+ Worker method for NTFS_BAD_CLUSTER_FILE construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _DataAttribute = NULL;
+}
+
+VOID
+NTFS_BAD_CLUSTER_FILE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Worker method for NTFS_BAD_CLUSTER_FILE destruction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DELETE( _DataAttribute );
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_BAD_CLUSTER_FILE::Initialize(
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft
+ )
+/*++
+
+Routine Description:
+
+ This method initializes an NTFS_BAD_CLUSTER_FILE object.
+
+Arguments:
+
+ Mft -- Supplies the volume MasterFile Table.
+
+--*/
+{
+ Destroy();
+
+ return( NTFS_FILE_RECORD_SEGMENT::
+ Initialize( BAD_CLUSTER_FILE_NUMBER,
+ Mft ) );
+}
+
+
+BOOLEAN
+NTFS_BAD_CLUSTER_FILE::Create(
+ IN PCSTANDARD_INFORMATION StandardInformation,
+ IN OUT PNTFS_BITMAP Bitmap,
+ IN PCNUMBER_SET BadClusters
+ )
+/*++
+
+Routine Description:
+
+ This method sets up the volume's Bad Cluster List. It also accepts
+ a set of clusters to add to the list, and marks those clusters
+ as used in the volume bitmap.
+
+Arguments:
+
+ Bitmap -- supplies the volume bitmap.
+ BadClusters -- supplies the set of bad clusters.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ NTFS_EXTENT_LIST Extents;
+ DSTRING DataAttributeName;
+ LCN Lcn;
+ BIG_INT Size, ClustersOnVolume, RunLength;
+ ULONG i;
+
+ // If we have an old data attribute lying around,
+ // throw it out.
+ //
+ DELETE( _DataAttribute );
+
+
+ // First, we have to set up the File Record Segment structure.
+
+ if( !NTFS_FILE_RECORD_SEGMENT::Create( StandardInformation) ) {
+
+ return FALSE;
+ }
+
+ ClustersOnVolume = QueryVolumeSectors()/QueryClusterFactor();
+
+
+ // Now we put together an extent list with all the bad clusters.
+ //
+ if( !Extents.Initialize( 0, ClustersOnVolume ) ) {
+
+ return FALSE;
+ }
+
+ for( i = 0; i < BadClusters->QueryNumDisjointRanges(); i++ ) {
+
+ BadClusters->QueryDisjointRange(i, &Lcn, &RunLength);
+
+ Bitmap->SetAllocated( Lcn, RunLength);
+
+ if( !Extents.AddExtent( Lcn, Lcn, RunLength ) ) {
+
+ return FALSE;
+ }
+ }
+
+ // Finally, create a data attribute and initialize it with
+ // the extent list. Then insert it into this File Record
+ // Segment (but keep it around in case we want to add to it).
+ // This data attribute has a value length equal to the size
+ // of the disk, but a valid length of zero.
+ //
+ // Note that the size of the attribute only includes clusters
+ // on the volume; it excludes any partial cluster at the end
+ // of the volume.
+ //
+ Size = ClustersOnVolume * QueryClusterFactor() *
+ GetDrive()->QuerySectorSize();
+
+ if( (_DataAttribute = NEW NTFS_ATTRIBUTE) == NULL ||
+ !DataAttributeName.Initialize( BadfileDataNameData ) ||
+ !_DataAttribute->Initialize( GetDrive(),
+ QueryClusterFactor(),
+ &Extents,
+ Size,
+ 0,
+ $DATA,
+ &DataAttributeName ) ||
+ !_DataAttribute->InsertIntoFile( this, NULL ) ) {
+
+ DELETE( _DataAttribute );
+ return FALSE;
+ }
+
+
+ // Add an unnamed, empty $DATA attribute.
+
+ if (!AddAttribute($DATA, NULL, NULL, 0, NULL)) {
+
+ DELETE( _DataAttribute );
+ return FALSE;
+ }
+
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+NTFS_BAD_CLUSTER_FILE::Add(
+ IN LCN Lcn
+ )
+/*++
+
+Routine Description:
+
+ This method adds a cluster to the Bad Cluster List. Note that it
+ does not mark it as used in the volume bitmap.
+
+Arguments:
+
+ Lcn -- supplies the LCN of the bad cluster
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ return( AddRun( Lcn, 1 ) );
+}
+
+
+
+BOOLEAN
+NTFS_BAD_CLUSTER_FILE::Add(
+ IN PCNUMBER_SET ClustersToAdd
+ )
+/*++
+
+Routine Description:
+
+ This method adds a set of clusters to the Bad Cluster List. Note
+ that it does not mark them as used in the volume bitmap.
+
+Arguments:
+
+ BadClusters -- Supplies the clusters to be added to the
+ bad cluster file.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ BIG_INT NumberOfClustersToAdd;
+ LCN CurrentLcn;
+ ULONG i;
+
+ NumberOfClustersToAdd = ClustersToAdd->QueryCardinality();
+
+ for( i = 0; i < NumberOfClustersToAdd; i++ ) {
+
+ CurrentLcn = ClustersToAdd->QueryNumber(i);
+
+ if( !IsInList( CurrentLcn ) &&
+ !Add( CurrentLcn ) ) {
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+NTFS_BAD_CLUSTER_FILE::AddRun(
+ IN LCN Lcn,
+ IN BIG_INT RunLength
+ )
+/*++
+
+Routine Description:
+
+ This method adds a run of clusters to the Bad Cluster List. Note
+ that it does not mark these clusters as used in the volume bitmap.
+
+Arguments:
+
+ Lcn -- supplies the LCN of the first cluster in the run.
+ RunLength -- supplies the number of clusters in the run.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ If LCN is in the range of the volume but the run extends past
+ the end of the volume, then the run is truncated.
+
+ If LCN or the RunLength is negative, the run is ignored. (The
+ method succeeds without doing anything in this case.)
+
+--*/
+{
+ DSTRING DataAttributeName;
+ BIG_INT num_clusters;
+ BOOLEAN Error;
+
+ num_clusters = QueryVolumeSectors()/QueryClusterFactor();
+
+ if( Lcn < 0 ||
+ Lcn >= num_clusters ||
+ RunLength < 0 ) {
+
+ return TRUE;
+ }
+
+ if (Lcn + RunLength > num_clusters) {
+
+ RunLength = num_clusters - Lcn;
+ }
+
+ if( _DataAttribute == NULL &&
+ ( !DataAttributeName.Initialize( BadfileDataNameData ) ||
+ (_DataAttribute = NEW NTFS_ATTRIBUTE) == NULL ||
+ !QueryAttribute( _DataAttribute,
+ &Error,
+ $DATA,
+ &DataAttributeName ) ) ) {
+
+ DELETE( _DataAttribute );
+ return FALSE;
+ }
+
+ return( _DataAttribute->AddExtent( Lcn, Lcn, RunLength ) );
+}
+
+
+BOOLEAN
+NTFS_BAD_CLUSTER_FILE::IsInList(
+ IN LCN Lcn
+ )
+/*++
+
+Routine Description:
+
+ This method determines whether a particular LCN is in the bad
+ cluster list.
+
+Arguments:
+
+ Lcn -- supplies the LCN in question.
+
+Return Value:
+
+ TRUE if the specified LCN is in the list of bad clusters.
+
+Notes:
+
+ This method cannot be CONST because it may need to fetch the
+ data attribute.
+
+--*/
+{
+ DSTRING DataAttributeName;
+ LCN QueriedLcn;
+ BOOLEAN Error;
+
+ if( _DataAttribute == NULL &&
+ (!DataAttributeName.Initialize( BadfileDataNameData ) ||
+ (_DataAttribute = NEW NTFS_ATTRIBUTE) == NULL ||
+ !QueryAttribute( _DataAttribute,
+ &Error,
+ $DATA,
+ &DataAttributeName ) ) ) {
+
+ DELETE( _DataAttribute );
+ return FALSE;
+ }
+
+ if( !_DataAttribute->QueryLcnFromVcn( Lcn, &QueriedLcn ) ||
+ QueriedLcn == LCN_NOT_PRESENT ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+NTFS_BAD_CLUSTER_FILE::Flush(
+ IN OUT PNTFS_BITMAP Bitmap,
+ IN OUT PNTFS_INDEX_TREE ParentIndex
+ )
+/*++
+
+Routine Description:
+
+ Write the modified bad cluster list to disk.
+
+Arguments:
+
+ Bitmap -- supplies the volume bitmap. (May be NULL).
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ if( _DataAttribute != NULL &&
+ _DataAttribute->IsStorageModified() &&
+ !_DataAttribute->InsertIntoFile( this, Bitmap ) ) {
+
+ return FALSE;
+ }
+
+ return( NTFS_FILE_RECORD_SEGMENT::Flush( Bitmap, ParentIndex ) );
+}
+
+BOOLEAN
+NTFS_BAD_CLUSTER_FILE::VerifyAndFix(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNTFS_INDEX_TREE RootIndex,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine ensures that this bad cluster file is prepared
+ to receive new bad clusters.
+
+Arguments:
+
+ VolumeBitmap - Supplies the volume bitmap.
+ RootIndex - Supplies the root index.
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ DSTRING DataAttributeName;
+ NTFS_EXTENT_LIST extent_list;
+ BOOLEAN errors;
+ BOOLEAN ErrorInAttribute;
+
+ errors = FALSE;
+
+
+ if (!_DataAttribute) {
+
+ if (!(_DataAttribute = NEW NTFS_ATTRIBUTE) ||
+ !DataAttributeName.Initialize(BadfileDataNameData)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!QueryAttribute(_DataAttribute,
+ &ErrorInAttribute,
+ $DATA,
+ &DataAttributeName)) {
+
+ if (!errors) {
+ errors = TRUE;
+ Message->Set(MSG_CHK_NTFS_CORRECTING_BAD_FILE);
+ Message->Display();
+ }
+
+ if (!extent_list.Initialize(0, QueryVolumeSectors()/
+ QueryClusterFactor())) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!_DataAttribute->Initialize(GetDrive(),
+ QueryClusterFactor(),
+ &extent_list,
+ 0,
+ 0,
+ $DATA,
+ &DataAttributeName ) ) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!_DataAttribute->InsertIntoFile(this, VolumeBitmap)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+ }
+
+
+ if (_DataAttribute->IsStorageModified() &&
+ !_DataAttribute->InsertIntoFile(this, VolumeBitmap) ||
+ (FixLevel != CheckOnly && !Flush(VolumeBitmap, RootIndex))) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_BAD_FILE);
+ Message->Display();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BIG_INT
+NTFS_BAD_CLUSTER_FILE::QueryNumBad(
+ )
+/*++
+
+Routine Description:
+
+ This routine return the number of bad clusters in the bad cluster
+ file.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of bad clusters in the bad cluster file.
+
+--*/
+{
+ DSTRING DataAttributeName;
+ BOOLEAN Error;
+
+ if( _DataAttribute == NULL &&
+ ( !DataAttributeName.Initialize( BadfileDataNameData ) ||
+ (_DataAttribute = NEW NTFS_ATTRIBUTE) == NULL ||
+ !QueryAttribute( _DataAttribute,
+ &Error,
+ $DATA,
+ &DataAttributeName ) ) ) {
+
+ DELETE( _DataAttribute );
+ return 0;
+ }
+
+ return _DataAttribute->QueryClustersAllocated();
+}
diff --git a/private/utils/untfs/src/bitfrs.cxx b/private/utils/untfs/src/bitfrs.cxx
new file mode 100644
index 000000000..cea211a44
--- /dev/null
+++ b/private/utils/untfs/src/bitfrs.cxx
@@ -0,0 +1,219 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ bitfrs.cxx
+
+Abstract:
+
+ This module contains the member function definitions for
+ the NTFS_BITMAP_FILE class.
+
+Author:
+
+ Bill McJohn (billmc) 18-June-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "untfs.hxx"
+
+#include "ntfsbit.hxx"
+#include "drive.hxx"
+#include "attrib.hxx"
+#include "bitfrs.hxx"
+
+DEFINE_EXPORTED_CONSTRUCTOR( NTFS_BITMAP_FILE, NTFS_FILE_RECORD_SEGMENT, UNTFS_EXPORT );
+
+UNTFS_EXPORT
+NTFS_BITMAP_FILE::~NTFS_BITMAP_FILE(
+ )
+{
+ Destroy();
+}
+
+
+VOID
+NTFS_BITMAP_FILE::Construct(
+ )
+/*++
+
+Routine Description:
+
+ Worker function for the construtor.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+}
+
+
+VOID
+NTFS_BITMAP_FILE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Clean up an NTFS_BITMAP_FILE object in preparation for
+ destruction or reinitialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_BITMAP_FILE::Initialize(
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft
+ )
+/*++
+
+Routine Description:
+
+ This method initializes a Bitmap File object.
+ The only special knowledge that it adds to the File Record Segment
+ initialization is the location within the Master File Table of the
+ Bitmap File.
+
+Arguments:
+
+ Mft -- Supplies the volume MasterFile Table.
+
+Return Value:
+
+ TRUE upon successful completion
+
+Notes:
+
+ This class is reinitializable.
+
+
+--*/
+{
+ Destroy();
+
+ return( NTFS_FILE_RECORD_SEGMENT::Initialize( BIT_MAP_FILE_NUMBER,
+ Mft ) );
+}
+
+
+BOOLEAN
+NTFS_BITMAP_FILE::Create(
+ IN PCSTANDARD_INFORMATION StandardInformation,
+ IN OUT PNTFS_BITMAP VolumeBitmap
+ )
+/*++
+
+Routine Description:
+
+ This method formats a Bitmap-File File Record
+ Segment in memory (without writing it to disk).
+
+ It creates a DATA attribute to hold the volume bitmap, and
+ allocates space on disk for the bitmap. Note that it does
+ not write the bitmap.
+
+Arguments:
+
+ StandardInformation -- supplies the standard information for the
+ file record segment.
+
+ VolumeBitmap -- supplies the volume bitmap
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ NTFS_ATTRIBUTE DataAttribute;
+ NTFS_EXTENT_LIST Extents;
+ LCN BitmapLcn;
+ BIG_INT NumberOfClusters;
+ ULONG Size;
+ ULONG ClusterSize;
+ ULONG ClustersToHoldBitmap;
+
+
+ // Set this object up as a File Record Segment.
+
+ if( !NTFS_FILE_RECORD_SEGMENT::Create( StandardInformation ) ) {
+
+ return FALSE;
+ }
+
+
+ // Determine the number of clusters necessary to hold the bitmap.
+
+ NumberOfClusters = VolumeBitmap->QuerySize();
+
+ if( NumberOfClusters.GetHighPart() != 0 ) {
+
+ DebugAbort( "Bitmap is too big.\n" );
+ return FALSE;
+ }
+
+ Size = NumberOfClusters.GetLowPart()/8;
+
+ ClusterSize = GetDrive()->QuerySectorSize() * QueryClusterFactor();
+
+ if( NumberOfClusters.GetLowPart() % (ULONG)8 ) {
+
+ Size += 1;
+ }
+
+ Size = QuadAlign(Size);
+
+ ClustersToHoldBitmap = Size/ClusterSize;
+ if( Size % ClusterSize ) {
+
+ ClustersToHoldBitmap++;
+ }
+
+ // Create a zero-length non-resident attribute, and
+ // then resize it to the correct size to hold the bitmap.
+ //
+ if( !Extents.Initialize( 0, 0 ) ||
+ !Extents.Resize( ClustersToHoldBitmap, VolumeBitmap ) ||
+ !DataAttribute.Initialize( GetDrive(),
+ QueryClusterFactor(),
+ &Extents,
+ Size,
+ Size,
+ $DATA ) ||
+ !DataAttribute.InsertIntoFile( this, VolumeBitmap ) ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/untfs/src/bootfile.cxx b/private/utils/untfs/src/bootfile.cxx
new file mode 100644
index 000000000..3709fb55a
--- /dev/null
+++ b/private/utils/untfs/src/bootfile.cxx
@@ -0,0 +1,352 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ bootfile.cxx
+
+Abstract:
+
+ This module contains the member function definitions for
+ the NTFS_BOOT_FILE class.
+
+Author:
+
+ Bill McJohn (billmc) 18-June-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "untfs.hxx"
+
+#include "drive.hxx"
+#include "attrib.hxx"
+#include "bootfile.hxx"
+#include "ifssys.hxx"
+#include "ntfsbit.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+
+DEFINE_EXPORTED_CONSTRUCTOR( NTFS_BOOT_FILE,
+ NTFS_FILE_RECORD_SEGMENT, UNTFS_EXPORT );
+
+UNTFS_EXPORT
+NTFS_BOOT_FILE::~NTFS_BOOT_FILE(
+ )
+{
+ Destroy();
+}
+
+
+VOID
+NTFS_BOOT_FILE::Construct(
+ )
+/*++
+
+Routine Description:
+
+ Worker function for the construtor.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+}
+
+
+VOID
+NTFS_BOOT_FILE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Clean up an NTFS_MASTER_FILE_TABLE object in preparation for
+ destruction or reinitialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_BOOT_FILE::Initialize(
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft
+ )
+/*++
+
+Routine Description:
+
+ This method initializes a Master File Table Reflection object.
+ The only special knowledge that it adds to the File Record Segment
+ initialization is the location within the Master File Table of the
+ Boot File.
+
+Arguments:
+
+ Mft -- Supplies the volume MasterFile Table.
+
+Return Value:
+
+ TRUE upon successful completion
+
+Notes:
+
+ This class is reinitializable.
+
+
+--*/
+{
+ Destroy();
+
+ return( NTFS_FILE_RECORD_SEGMENT::Initialize( BOOT_FILE_NUMBER,
+ Mft ) );
+}
+
+
+BOOLEAN
+NTFS_BOOT_FILE::CreateDataAttribute(
+ )
+/*++
+
+Routine Description:
+
+ This routine creates the data attribute for the boot file.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_ATTRIBUTE DataAttribute;
+ NTFS_EXTENT_LIST Extents;
+ ULONG Size, ClusterSize, ClustersInBootArea;
+ ULONG NumBootClusters;
+
+ ClusterSize = QueryClusterFactor() * GetDrive()->QuerySectorSize();
+
+ ClustersInBootArea = (BYTES_IN_BOOT_AREA % ClusterSize) ?
+ BYTES_IN_BOOT_AREA / ClusterSize + 1 :
+ BYTES_IN_BOOT_AREA / ClusterSize;
+
+ NumBootClusters = max(1, BYTES_PER_BOOT_SECTOR/ClusterSize);
+
+ Size = ClustersInBootArea * ClusterSize;
+
+ if( !Extents.Initialize( 0, 0 ) ) {
+
+ return FALSE;
+ }
+
+ if( !Extents.AddExtent( 0,
+ 0,
+ ClustersInBootArea ) ) {
+ return FALSE;
+ }
+
+ if( !DataAttribute.Initialize( GetDrive(),
+ QueryClusterFactor(),
+ &Extents,
+ Size,
+ Size,
+ $DATA ) ) {
+
+ return FALSE;
+ }
+
+ if( !DataAttribute.InsertIntoFile( this, NULL ) ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+NTFS_BOOT_FILE::Create(
+ IN PCSTANDARD_INFORMATION StandardInformation
+ )
+/*++
+
+Routine Description:
+
+ This method formats a Boot-File File Record
+ Segment in memory (without writing it to disk).
+
+Arguments:
+
+ StandardInformation -- supplies the standard information for the
+ file record segment.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ // Set this object up as a File Record Segment.
+
+ if( !NTFS_FILE_RECORD_SEGMENT::Create( StandardInformation ) ) {
+
+ return FALSE;
+ }
+
+ if (!CreateDataAttribute()) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+NONVIRTUAL
+BOOLEAN
+NTFS_BOOT_FILE::VerifyAndFix(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNTFS_INDEX_TREE RootIndex,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine ensures that the boot file's $DATA attribute is present
+ and encompases the two boot sectors.
+
+Arguments:
+
+ VolumeBitmap - Supplies the volume bitmap.
+ RootIndex - Supplies the root index.
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_ATTRIBUTE data_attribute;
+ LCN lcn, mid_lcn;
+ BIG_INT run_length;
+ BOOLEAN ErrorInAttribute;
+ BOOLEAN replace_data;
+ BOOLEAN found_zero;
+ BOOLEAN found_mid;
+ VCN i;
+ NTFS_EXTENT_LIST extents;
+ ULONG size;
+ ULONG num_boot_clusters;
+
+ //
+ // We used to do a replica boot sector in the middle of the volume.
+ // Now we want it at the end, so chkdsk has to deal with both cases.
+ // The rule is that the boot file should have a data attribute. If
+ // that data attribute has two extents, the second one should describe
+ // a replica at n/2. If there's a single extent, the replica is
+ // assumed to occupy the last sector of the partition.
+ //
+
+ // Insure that the $DATA attribute is present and that it
+ // allocates cluster 0 and the cluster in the middle of the disk.
+
+ num_boot_clusters = max(1,
+ BYTES_PER_BOOT_SECTOR/(GetDrive()->QuerySectorSize()*
+ QueryClusterFactor()));
+ mid_lcn = QueryVolumeSectors()/2/QueryClusterFactor();
+
+ replace_data = FALSE;
+ if (QueryAttribute(&data_attribute, &ErrorInAttribute, $DATA)) {
+
+ found_zero = FALSE;
+ found_mid = FALSE;
+ for (i = 0; data_attribute.QueryLcnFromVcn(i, &lcn, &run_length); i += 1) {
+ if (lcn == 0) {
+ found_zero = (run_length >= num_boot_clusters);
+ }
+ if (lcn == mid_lcn) {
+ found_mid = (run_length >= num_boot_clusters);
+ }
+ }
+
+ if (!found_zero) {
+ replace_data = TRUE;
+ data_attribute.Resize(0, VolumeBitmap);
+ }
+
+ } else {
+ replace_data = TRUE;
+ }
+
+ // If it's not good then replace it with one that takes
+ // up only the boot sector and the middle sector.
+
+
+ //
+ // When creating a new boot sector we just do sector 0.
+ //
+
+ if (replace_data) {
+ Message->Set(MSG_CHK_NTFS_CORRECTING_BOOT_FILE);
+ Message->Display();
+
+ size = GetDrive()->QuerySectorSize()*QueryClusterFactor();
+
+ if (!extents.Initialize(0,0) ||
+ !extents.AddExtent(0, 0, num_boot_clusters) ||
+ !data_attribute.Initialize(GetDrive(),
+ QueryClusterFactor(),
+ &extents,
+ size,
+ size,
+ $DATA) ||
+ !data_attribute.InsertIntoFile(this, VolumeBitmap) ||
+ (FixLevel != CheckOnly && !Flush(VolumeBitmap, RootIndex))) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_BOOT_FILE);
+ Message->Display();
+ return FALSE;
+ }
+
+ VolumeBitmap->SetAllocated(0, num_boot_clusters);
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/untfs/src/clusrun.cxx b/private/utils/untfs/src/clusrun.cxx
new file mode 100644
index 000000000..2618f7443
--- /dev/null
+++ b/private/utils/untfs/src/clusrun.cxx
@@ -0,0 +1,174 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ clusrun.cxx
+
+Abstract:
+
+ This class models a run of clusters on an NTFS volume. Its
+ principle purpose is to mediate between the cluster-oriented
+ NTFS volume and the sector-oriented drive object.
+
+Author:
+
+ Bill McJohn (billmc) 11-July-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "untfs.hxx"
+#include "clusrun.hxx"
+
+DEFINE_EXPORTED_CONSTRUCTOR( NTFS_CLUSTER_RUN, SECRUN, UNTFS_EXPORT );
+
+UNTFS_EXPORT
+NTFS_CLUSTER_RUN::~NTFS_CLUSTER_RUN(
+ )
+{
+ Destroy();
+}
+
+
+VOID
+NTFS_CLUSTER_RUN::Construct(
+ )
+/*++
+
+Routine Description:
+
+ Worker function for construction of the NTFS_CLUSTER_RUN object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _StartLcn = 0;
+ _ClusterFactor = 0;
+ _Drive = NULL;
+ _IsModified = FALSE;
+}
+
+VOID
+NTFS_CLUSTER_RUN::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Worker function for destruction of the NTFS_CLUSTER_RUN object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _StartLcn = 0;
+ _ClusterFactor = 0;
+ _Drive = NULL;
+ _IsModified = FALSE;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_CLUSTER_RUN::Initialize (
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN LCN Lcn,
+ IN ULONG ClusterFactor,
+ IN ULONG RunLength
+ )
+/*++
+
+Routine Description:
+
+ Initialize an NTFS_CLUSTER_RUN object.
+
+Arguments:
+
+ Mem -- supplies the memory object for this cluster run.
+ Drive -- supplies the drive on which this cluster run resides.
+ Lcn -- supplies the staring Lcn of the cluster run.
+ Cluster Factor -- supplies the cluster factor for the drive.
+ RunLength -- supplies the length of the run in clusters.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This class is reinitializable.
+
+--*/
+{
+ DebugPtrAssert( Mem );
+ DebugPtrAssert( Drive );
+
+ Destroy();
+
+ if( !SECRUN::Initialize( Mem, Drive,
+ Lcn * ClusterFactor,
+ RunLength * ClusterFactor ) ) {
+
+ return FALSE;
+ }
+
+ _StartLcn = Lcn;
+ _Drive = Drive;
+ _ClusterFactor = ClusterFactor;
+
+ return TRUE;
+}
+
+
+UNTFS_EXPORT
+VOID
+NTFS_CLUSTER_RUN::Relocate (
+ IN LCN NewLcn
+ )
+/*++
+
+Routine Description:
+
+ Move the cluster run to point at a different section of
+ the volume.
+
+Arguments:
+
+ NewLcn -- supplies the first Lcn of the new location.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _StartLcn = NewLcn;
+
+ SECRUN::Relocate( NewLcn * _ClusterFactor );
+}
diff --git a/private/utils/untfs/src/entry.cxx b/private/utils/untfs/src/entry.cxx
new file mode 100644
index 000000000..760bf326d
--- /dev/null
+++ b/private/utils/untfs/src/entry.cxx
@@ -0,0 +1,400 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ entry.cxx
+
+Abstract:
+
+ This module contains the entry points for UNTFS.DLL. These
+ include:
+
+ Chkdsk
+ Format
+ Recover
+ Extend
+
+Author:
+
+ Bill McJohn (billmc) 31-05-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "untfs.hxx"
+#include "ntfsvol.hxx"
+#include "path.hxx"
+#include "ifssys.hxx"
+#include "rcache.hxx"
+#include "ifsserv.hxx"
+
+extern "C" {
+ #include "nturtl.h"
+}
+
+#include "message.hxx"
+#include "rtmsg.h"
+
+
+BOOLEAN
+FAR APIENTRY
+Chkdsk(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Fix,
+ IN BOOLEAN Verbose,
+ IN BOOLEAN OnlyIfDirty,
+ IN BOOLEAN Recover,
+ IN PPATH PathToCheck,
+ IN BOOLEAN Extend,
+ IN BOOLEAN ResizeLogFile,
+ IN ULONG DesiredLogFileSize,
+ OUT PULONG ExitStatus
+ )
+/*++
+
+Routine Description:
+
+ Check an NTFS volume.
+
+Arguments:
+
+ NtDrivName supplies the name of the drive to check
+ Message supplies an outlet for messages
+ Fix TRUE if Chkdsk should fix errors
+ Verbose TRUE if Chkdsk should list every file it finds
+ OnlyIfDirty TRUE if the drive should be checked only if
+ it is dirty
+ Recover TRUE if the drive is to be completely checked
+ for bad sectors.
+ PathToCheck supplies a path to files Chkdsk should check
+ for contiguity
+ Extend TRUE if Chkdsk should extend the volume
+ ResizeLogfile TRUE if Chkdsk should resize the logfile.
+ DesiredLogfileSize if ResizeLogfile is true, supplies the desired logfile
+ size, or 0 if we're to resize the logfile to the
+ default size.
+ ExitStatus Returns information about whether the chkdsk failed
+
+
+Return Value:
+
+ TRUE if successful.
+
+--*/
+{
+ if (Extend) {
+
+ LOG_IO_DP_DRIVE Drive;
+ SECRUN Secrun;
+ HMEM Mem;
+
+ PPACKED_BOOT_SECTOR BootSector;
+
+ if( !Drive.Initialize( NtDriveName, Message ) ||
+ !Drive.Lock() ||
+ !Mem.Initialize() ||
+ !Secrun.Initialize( &Mem, &Drive, 0, 1 ) ||
+ !Secrun.Read() ) {
+
+ return FALSE;
+ }
+
+ BootSector = (PPACKED_BOOT_SECTOR)Secrun.GetBuf();
+
+ BootSector->NumberSectors.LowPart = Drive.QuerySectors().GetLowPart();
+ BootSector->NumberSectors.HighPart = Drive.QuerySectors().GetHighPart();
+
+ if (!Secrun.Write()) {
+ *ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
+ return FALSE;
+ }
+ }
+
+ NTFS_VOL NtfsVol;
+ BOOLEAN RecoverFree, RecoverAlloc;
+ BOOLEAN r;
+
+ RecoverFree = RecoverAlloc = Recover;
+
+ if (Extend) {
+
+ // If we're to extend the volume, we also want to verify the
+ // new free space we're adding.
+ //
+
+ RecoverFree = TRUE;
+ }
+
+ if (!NtfsVol.Initialize(NtDriveName, Message)) {
+ *ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
+ return FALSE;
+ }
+
+ if ((Fix || (ResizeLogFile && DesiredLogFileSize != 0)) &&
+ !NtfsVol.Lock()) {
+
+ // The client wants to modify the drive, but we can't lock it.
+ // Offer to do it on next reboot.
+ //
+ Message->Set(MSG_CHKDSK_ON_REBOOT_PROMPT);
+ Message->Display("");
+
+ if (Message->IsYesResponse( FALSE )) {
+
+ if (NtfsVol.ForceAutochk( Recover,
+ ResizeLogFile,
+ DesiredLogFileSize,
+ NtDriveName )) {
+
+ Message->Set(MSG_CHKDSK_SCHEDULED);
+ Message->Display();
+
+ } else {
+
+ Message->Set(MSG_CHKDSK_CANNOT_SCHEDULE);
+ Message->Display();
+ }
+ }
+
+ *ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
+ return FALSE;
+ }
+
+ if (!Fix && ResizeLogFile) {
+
+ if (!NtfsVol.GetNtfsSuperArea()->ResizeCleanLogFile( Message,
+ TRUE, /* ExplicitResize */
+ DesiredLogFileSize )) {
+ Message->Set(MSG_CHK_NTFS_RESIZING_LOG_FILE_FAILED);
+ Message->Display();
+ return FALSE;
+ }
+ return TRUE;
+ }
+
+ return NtfsVol.ChkDsk( Fix ? TotalFix : CheckOnly,
+ Message,
+ Verbose,
+ OnlyIfDirty,
+ RecoverFree, RecoverAlloc,
+ ResizeLogFile, DesiredLogFileSize,
+ ExitStatus );
+
+ return r;
+}
+
+
+BOOLEAN
+FAR APIENTRY
+Format(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Quick,
+ IN MEDIA_TYPE MediaType,
+ IN PCWSTRING LabelString,
+ IN ULONG ClusterSize
+ )
+/*++
+
+Routine Description:
+
+ Format an NTFS volume.
+
+Arguments:
+
+ NtDriveName -- supplies the name (in NT API form) of the volume
+ Message -- supplies an outlet for messages
+ Quick -- supplies a flag to indicate whether to do Quick Format
+ MediaType -- supplies the volume's Media Type
+ LabelString -- supplies the volume's label
+ ClusterSize -- supplies the cluster size for the volume.
+
+--*/
+{
+ DP_DRIVE DpDrive;
+ NTFS_VOL NtfsVol;
+ ULONG SectorsNeeded;
+
+ if (!DpDrive.Initialize( NtDriveName, Message )) {
+
+ return FALSE;
+ }
+
+ if (DpDrive.IsFloppy()) {
+
+ Message->Set(MSG_NTFS_FORMAT_NO_FLOPPIES);
+ Message->Display();
+ return FALSE;
+ }
+
+ SectorsNeeded = NTFS_SA::QuerySectorsInElementaryStructures( &DpDrive );
+
+ if( SectorsNeeded > DpDrive.QuerySectors() ) {
+
+ Message->Set( MSG_FMT_VOLUME_TOO_SMALL );
+ Message->Display();
+ return FALSE;
+ }
+
+ if( !NtfsVol.Initialize( NtDriveName,
+ Message,
+ FALSE,
+ !Quick,
+ MediaType ) ) {
+
+ return FALSE;
+ }
+
+ return( NtfsVol.Format( LabelString, Message, ClusterSize ) );
+}
+
+
+BOOLEAN
+FAR APIENTRY
+Recover(
+ IN PPATH RecFilePath,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ Recover a file on an NTFS disk.
+
+Arguments:
+
+ RecFilePath -- supplies the path to the file to recover
+ Message -- supplies a channel for messages
+
+Return Value:
+
+ TRUE if successful.
+
+--*/
+{
+ NTFS_VOL NtfsVol;
+ PWSTRING FullPath;
+ PWSTRING DosDriveName;
+ DSTRING NtDriveName;
+ BOOLEAN Result;
+
+ FullPath = RecFilePath->QueryDirsAndName();
+ DosDriveName = RecFilePath->QueryDevice();
+
+ if ( DosDriveName == NULL ||
+ !IFS_SYSTEM::DosDriveNameToNtDriveName(DosDriveName,
+ &NtDriveName) ||
+ FullPath == NULL ) {
+
+ DELETE(DosDriveName);
+ DELETE(FullPath);
+ return FALSE;
+ }
+
+ Message->Set(MSG_RECOV_BEGIN);
+ Message->Display("%W", DosDriveName);
+ Message->WaitForUserSignal();
+
+ Result = ( NtfsVol.Initialize( &NtDriveName, Message ) &&
+ NtfsVol.Recover( FullPath, Message ) );
+
+ DELETE(DosDriveName);
+ DELETE(FullPath);
+ return Result;
+}
+
+BOOLEAN
+FAR APIENTRY
+Extend(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verify
+ )
+/*++
+
+Routine Description:
+
+ Extend an NTFS volume without going through the whole chkdsk
+ process.
+
+Arguments:
+
+ NtDrivName Supplies the name of the drive to extend.
+ Message Supplies an outlet for messages.
+ Verify TRUE if we should verify the new space.
+
+Return Value:
+
+ TRUE if successful.
+
+--*/
+{
+ BIG_INT nsecOldSize; // previous size in sectors
+
+ //
+ // First save the old volume size from the boot sector, then query
+ // the new size from the device driver and write a new boot sector
+ // contining that size. When the Drive object is destroyed, the
+ // dasd handle will be closed.
+ //
+
+ {
+ LOG_IO_DP_DRIVE Drive;
+ SECRUN Secrun;
+ HMEM Mem;
+
+ PPACKED_BOOT_SECTOR BootSector;
+
+
+ if( !Drive.Initialize( NtDriveName, Message ) ||
+ !Drive.Lock() ||
+ !Mem.Initialize() ||
+ !Secrun.Initialize( &Mem, &Drive, 0, 1 ) ||
+ !Secrun.Read() ) {
+
+ return FALSE;
+ }
+
+ BootSector = (PPACKED_BOOT_SECTOR)Secrun.GetBuf();
+
+ nsecOldSize = BootSector->NumberSectors;
+
+ // Leave one sector at the end of the volume for the replica boot
+ // sector.
+ //
+
+ BootSector->NumberSectors.LowPart = (Drive.QuerySectors() - 1).GetLowPart();
+ BootSector->NumberSectors.HighPart = (Drive.QuerySectors() - 1).GetHighPart();
+
+ if (!Secrun.Write()) {
+ return FALSE;
+ }
+ }
+
+ //
+ // When the ntfs volume object is initialized, it will get the new
+ // size from the boot sector. When it opens a handle on the volume,
+ // the filesystem will re-mount and pick up the new size, as well.
+ //
+
+ NTFS_VOL ntfs_vol;
+
+ if (!ntfs_vol.Initialize(NtDriveName, Message) || !ntfs_vol.Lock()) {
+ return FALSE;
+ }
+
+ return ntfs_vol.Extend(Message, Verify, nsecOldSize);
+}
diff --git a/private/utils/untfs/src/extents.cxx b/private/utils/untfs/src/extents.cxx
new file mode 100644
index 000000000..15158f191
--- /dev/null
+++ b/private/utils/untfs/src/extents.cxx
@@ -0,0 +1,1789 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ extents.cxx
+
+Abstract:
+
+ This module contains the definitions for NTFS_EXTENT_LIST, which
+ models a set of NTFS extents.
+
+ An extent is a contiguous run of clusters; a non-resident
+ attribute's value is made up of a list of extents. The
+ NTFS_EXTENT_LIST object can be used to describe the disk space
+ allocated to a non-resident attribute.
+
+ This class also encapsulates the knowledge of mapping pairs
+ and their compression, i.e. of the representation of extent
+ lists in attribute records.
+
+ The extent list is kept sorted by VCN. Since extent lists are
+ typically quite short, linear search is used.
+
+Author:
+
+ Bill McJohn (billmc) 17-June-91
+ Matthew Bradburn (mattbr) 19-August-95
+ Changed to use NTFS MCB package for improved performance.
+
+Environment:
+
+ ULIB, User Mode
+
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "untfs.hxx"
+#include "ntfsbit.hxx"
+#include "intstack.hxx"
+#include "iterator.hxx"
+
+#include "extents.hxx"
+#include "ntfssa.hxx"
+
+extern "C" {
+#include "fsrtlp.h"
+}
+
+DEFINE_EXPORTED_CONSTRUCTOR( NTFS_EXTENT_LIST, OBJECT, UNTFS_EXPORT );
+DEFINE_CONSTRUCTOR( NTFS_EXTENT, OBJECT );
+
+//
+// These routines are to support the NTFS MCB package.
+//
+
+extern "C"
+PVOID
+MemAlloc(
+ IN ULONG Size
+ );
+
+PVOID
+MemAlloc(
+ IN ULONG Size
+ )
+{
+ return NEW BYTE[Size];
+}
+
+extern "C"
+PVOID
+MemAllocOrRaise(
+ IN ULONG Size
+ );
+
+PVOID
+MemAllocOrRaise(
+ IN ULONG Size
+ )
+{
+ PVOID p;
+
+ p = MemAlloc(Size);
+
+ if (NULL == p) {
+ RtlRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
+ }
+ return p;
+}
+
+extern "C"
+VOID
+MemFree(
+ IN PVOID Addr
+ );
+
+VOID
+MemFree(
+ IN PVOID Addr
+ )
+{
+ delete[] Addr;
+}
+
+
+UNTFS_EXPORT
+NTFS_EXTENT_LIST::~NTFS_EXTENT_LIST(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for NTFS_EXTENT_LIST class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+VOID
+NTFS_EXTENT_LIST::Construct(
+ )
+/*++
+
+Routine Description:
+
+ Worker method for NTFS_EXTENT_LIST construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _LowestVcn = 0;
+ _NextVcn = 0;
+ _McbInitialized = FALSE;
+ _Mcb = NULL;
+}
+
+VOID
+NTFS_EXTENT_LIST::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Worker method for NTFS_EXTENT_LIST destruction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _LowestVcn = 0;
+ _NextVcn = 0;
+
+ if (_McbInitialized) {
+
+ FsRtlUninitializeLargeMcb(_Mcb);
+ _McbInitialized = FALSE;
+ }
+
+ DELETE(_Mcb);
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_EXTENT_LIST::Initialize(
+ IN VCN LowestVcn,
+ IN VCN NextVcn
+ )
+/*++
+
+Routine Description:
+
+ Initializes an empty extent list.
+
+Arguments:
+
+ LowestVcn -- supplies the lowest VCN mapped by this extent list
+ NextVcn -- supplies the next VCN following this extent list
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ Highest and Lowest VCN are typically zero; they are provided
+ to permit creation of sparse files.
+
+ This class is reinitializable.
+
+--*/
+{
+ Destroy();
+
+ _LowestVcn = LowestVcn;
+ _NextVcn = (NextVcn < LowestVcn) ? LowestVcn : NextVcn;
+
+ if (NULL == (_Mcb = NEW LARGE_MCB)) {
+ Destroy();
+ return FALSE;
+ }
+
+ __try {
+
+ FsRtlInitializeLargeMcb(_Mcb, (POOL_TYPE)0);
+
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ _McbInitialized = TRUE;
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_EXTENT_LIST::Initialize(
+ IN VCN StartingVcn,
+ IN PCVOID CompressedMappingPairs,
+ IN ULONG MappingPairsMaximumLength,
+ OUT PBOOLEAN BadMappingPairs
+ )
+/*++
+
+Routine Description:
+
+ Initialize an extent list based on a set of compressed mapping
+ pairs (presumably taken from an attribute record).
+
+Arguments:
+
+ StartingVcn -- Supplies the starting VCN of the
+ mapping pairs list
+ CompressedMappingPairs -- Supplies a pointer to the compressed
+ list of mapping pairs
+ MappingPairsMaximumLength -- Supplies the length (in bytes) of
+ the buffer in which the mapping
+ pairs list resides
+ BadMappingPairs -- If non-NULL, receives TRUE if this
+ method failed because the mapping
+ pairs list could not be expanded.
+ If this method returns TRUE, then
+ *BadMappingPairs should be ignored.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This method does not assume that the mapping pairs list can be
+ correctly expanded. It does assume that the MappingPairsMaximumLength
+ is correct, i.e. that it can reference that many bytes of memory
+ starting at CompressedMappingPairs.
+
+ Clients who trust the mapping pairs list which they pass in may omit
+ the BadMappingPairs parameter; those (like Chkdsk) who do not trust
+ the list can use BadMappingPairs to determine whether Initialize failed
+ because of a bad mapping pairs list.
+
+--*/
+{
+ DebugPtrAssert( CompressedMappingPairs );
+
+ return( Initialize( StartingVcn, StartingVcn ) &&
+ AddExtents( StartingVcn,
+ CompressedMappingPairs,
+ MappingPairsMaximumLength,
+ BadMappingPairs ) );
+}
+
+
+
+BOOLEAN
+NTFS_EXTENT_LIST::Initialize(
+ IN PCNTFS_EXTENT_LIST ExtentsToCopy
+ )
+/*++
+
+Routine Description:
+
+ Initializes an extent list based on another extent list.
+
+Arguments:
+
+ ExtentsToCopy - Supplies the other list of extents.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This class is reinitializable.
+
+--*/
+{
+ PNTFS_EXTENT src_extent, dst_extent;
+ VCN Vcn;
+ LCN Lcn;
+ BIG_INT RunLength;
+
+ Destroy();
+
+ if (!Initialize(ExtentsToCopy->_LowestVcn,
+ ExtentsToCopy->_NextVcn)) {
+
+ Destroy();
+ return FALSE;
+ }
+
+
+ for (ULONG i = 0; i < ExtentsToCopy->QueryNumberOfExtents(); ++i) {
+ if (!ExtentsToCopy->QueryExtent(i, &Vcn, &Lcn, &RunLength)) {
+ Destroy();
+ return FALSE;
+ }
+ if (LCN_NOT_PRESENT == Lcn) {
+ continue;
+ }
+
+ if (!AddExtent(Vcn, Lcn, RunLength)) {
+ Destroy();
+ return FALSE;
+ }
+ }
+
+ SetLowestVcn(ExtentsToCopy->_LowestVcn);
+ SetNextVcn(ExtentsToCopy->_NextVcn);
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+NTFS_EXTENT_LIST::IsSparse(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method determines whether the extent list has holes
+ (ie. if there are not-present-on-disk runs in the attribute).
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the extent list is sparse.
+
+--*/
+{
+ PNTFS_EXTENT current_extent, previous_extent;
+ VCN TempVcn;
+ BIG_INT previous_vcn, previous_lcn, previous_runlength;
+ BIG_INT current_vcn, current_lcn, current_runlength;
+ ULONG i = 0;
+
+ if (!QueryExtent(i, &previous_vcn, &previous_lcn, &previous_runlength)) {
+
+ if (_LowestVcn != _NextVcn) {
+
+ // This extent list is one big hole.
+
+ return TRUE;
+
+ } else {
+
+ // This extent list is empty.
+
+ return FALSE;
+ }
+ }
+
+ if (previous_vcn != _LowestVcn) {
+
+ // This extent list starts with a hole.
+
+ return TRUE;
+ }
+
+ // Check the rest of the extents, to see if there's a hole
+ // before any of them:
+
+ while (QueryExtent(++i, &current_vcn, &current_lcn, &current_runlength)) {
+
+ if (LCN_NOT_PRESENT == current_lcn) {
+ continue;
+ }
+
+ if (previous_vcn + previous_runlength != current_vcn) {
+ return TRUE;
+ }
+
+ previous_vcn = current_vcn;
+ previous_lcn = current_lcn;
+ previous_runlength = current_runlength;
+ }
+
+ // Check to see if there's a hole after the last extent:
+
+ if (previous_vcn + previous_runlength != _NextVcn) {
+ return TRUE;
+ }
+
+ // Didn't find any holes.
+
+ return FALSE;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_EXTENT_LIST::AddExtent(
+ IN VCN Vcn,
+ IN LCN Lcn,
+ IN BIG_INT RunLength
+ )
+/*++
+
+Routine Description:
+
+ This method adds an extent, specified by its Virtual Cluster Number,
+ Logical Cluster Number, and Run Length, to the extent list.
+
+ NTFS_EXTENT_LIST may, at its discretion, merge contiguous extents,
+ but it does not guarrantee this behavior.
+
+Arguments:
+
+ Vcn -- Supplies the starting VCN of the extent.
+ Lcn -- Supplies the starting LCN of the extent.
+ RunLength -- Supplies the number of clusters in the extent.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ PNTFS_EXTENT current_extent, new_extent, previous_extent;
+ VCN TempVcn;
+ BOOLEAN appending;
+ BOOLEAN b;
+
+ if (RunLength <= 0) {
+
+ // zero-length runs are not valid. Neither are negative ones.
+
+ return FALSE;
+ }
+ if (LCN_NOT_PRESENT == Lcn) {
+
+ // We ignore attempts to explicitly add holes.
+
+ return TRUE;
+ }
+
+ __try {
+
+ b = FsRtlAddLargeMcbEntry(_Mcb,
+ Vcn.GetLargeInteger().QuadPart,
+ Lcn.GetLargeInteger().QuadPart,
+ RunLength.GetLargeInteger().QuadPart);
+
+ } __except (EXCEPTION_EXECUTE_HANDLER) {
+
+ return FALSE;
+ }
+
+ if (!b) {
+ return FALSE;
+ }
+
+ if (_LowestVcn == _NextVcn) {
+ _LowestVcn = Vcn;
+ _NextVcn = Vcn + RunLength;
+ }
+
+
+ // If this extent changes the lowest and highest VCNs mapped
+ // by this extent list, update those values.
+
+ if (Vcn < _LowestVcn) {
+
+ _LowestVcn = Vcn;
+ }
+
+ TempVcn = Vcn + RunLength;
+
+ if (TempVcn > _NextVcn) {
+
+ _NextVcn = TempVcn;
+ }
+
+ return TRUE;
+}
+
+
+
+VOID
+NTFS_EXTENT_LIST::Coalesce(
+ )
+/*++
+
+Routine Description:
+
+ This routine coalesces adjacent extents in the extent list.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ // The MCB package does this for us.
+
+ return;
+}
+
+
+BOOLEAN
+NTFS_EXTENT_LIST::AddExtents(
+ IN VCN StartingVcn,
+ IN PCVOID CompressedMappingPairs,
+ IN ULONG MappingPairsMaximumLength,
+ OUT PBOOLEAN BadMappingPairs
+ )
+/*++
+
+Routine Description:
+
+ This method adds a set of extents defined by a compressed mapping
+ pairs list (presumably taken from an Attribute Record).
+
+Arguments:
+
+ StartingVcn -- supplies the starting VCN of the mapping pairs list
+ CompressedMappingPairs -- supplies a pointer to the compressed
+ list of mapping pairs
+ MappingPairsMaximumLengt -- supplies the length (in bytes) of the buffer
+ in which the mapping pairs list resides
+ BadMappingPairs -- if non-NULL, receives TRUE if an error occurrs
+ while processing the mapping pairs list.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ BadMappingPairs will be set to TRUE if the compressed mapping
+ pairs list cannot be expanded or if any extent derived from
+ this list overlaps with another extent in the list. In either
+ of these cases, AddExtents will return FALSE.
+
+ If this method encounters an error after processing part of
+ the list, it will leave the extent list in an undefined (but
+ valid, as an object) state.
+
+ Clients who trust their mapping pairs list may omit the
+ BadMappingPairs parameter.
+
+--*/
+{
+ VCN CurrentVcn;
+ ULONG LengthOfCompressedPairs;
+ ULONG NumberOfPairs;
+ PMAPPING_PAIR MappingPairs;
+ ULONG i;
+
+ // Assume innocent until found guilty
+ //
+ if( BadMappingPairs != NULL ) {
+
+ *BadMappingPairs = FALSE;
+ }
+
+ // Determine how many mapping pairs we actually have, so
+ // we can allocate the correct size of an expanded mapping
+ // pairs buffer.
+
+ if( !QueryMappingPairsLength( CompressedMappingPairs,
+ MappingPairsMaximumLength,
+ &LengthOfCompressedPairs,
+ &NumberOfPairs ) ) {
+
+ if( BadMappingPairs != NULL ) {
+
+ *BadMappingPairs = TRUE;
+ }
+
+ DebugPrint( "Can't determine length of mapping pairs.\n" );
+ return FALSE;
+ }
+
+ // Allocate a buffer to hold the expanded mapping pairs.
+
+ MappingPairs = (PMAPPING_PAIR)MALLOC( sizeof(MAPPING_PAIR) *
+ (UINT) NumberOfPairs );
+
+ if( MappingPairs == NULL ) {
+
+ return FALSE;
+ }
+
+
+ if( !ExpandMappingPairs( CompressedMappingPairs,
+ StartingVcn,
+ MappingPairsMaximumLength,
+ NumberOfPairs,
+ MappingPairs,
+ &NumberOfPairs ) ) {
+
+ DebugPrint( "Cannot expand mapping pairs.\n" );
+
+ if( BadMappingPairs != NULL ) {
+
+ *BadMappingPairs = TRUE;
+ }
+
+ FREE( MappingPairs );
+ return FALSE;
+ }
+
+
+ // Convert the mapping pairs into extents.
+
+ CurrentVcn = StartingVcn;
+
+ for( i = 0; i < NumberOfPairs; i++ ) {
+
+ if( MappingPairs[i].CurrentLcn != LCN_NOT_PRESENT ) {
+
+ if( !AddExtent( CurrentVcn,
+ MappingPairs[i].CurrentLcn,
+ MappingPairs[i].NextVcn - CurrentVcn ) ) {
+
+ FREE( MappingPairs );
+ return FALSE;
+ }
+ }
+
+ CurrentVcn = MappingPairs[i].NextVcn;
+ }
+
+ // Set _LowestVcn to the client-supplied value, if necessary.
+ // (This is required for mapping pair lists that begin with
+ // a hole.)
+ //
+ if( StartingVcn < _LowestVcn ) {
+
+ _LowestVcn = StartingVcn;
+ }
+
+
+ // Update _NextVcn if neccessary.
+ //
+ if( CurrentVcn > _NextVcn ) {
+
+ _NextVcn = CurrentVcn;
+ }
+
+ FREE( MappingPairs );
+ return TRUE;
+}
+
+
+
+VOID
+NTFS_EXTENT_LIST::DeleteExtent(
+ IN ULONG ExtentNumber
+ )
+/*++
+
+Routine Description:
+
+ This method removes an extent from the list.
+
+Arguments:
+
+ ExtentNumber -- supplies the (zero-based) extent number to remove
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG i;
+ VCN Vcn;
+ LCN Lcn;
+ BIG_INT RunLength;
+
+ //
+ // Find the VCN for the extent number.
+ //
+
+ if (!QueryExtent(ExtentNumber, &Vcn, &Lcn, &RunLength)) {
+ DebugAbort("Shouldn't get here.");
+ return;
+ }
+
+ FsRtlRemoveLargeMcbEntry(_Mcb,
+ Vcn.GetLargeInteger().QuadPart,
+ RunLength.GetLargeInteger().QuadPart);
+
+ return;
+}
+
+
+
+BOOLEAN
+NTFS_EXTENT_LIST::Resize(
+ IN BIG_INT NewNumberOfClusters,
+ IN OUT PNTFS_BITMAP Bitmap
+ )
+/*++
+
+Routine Description:
+
+ This method either extends or truncates the disk allocation
+ covered by this extent list.
+
+Arguments:
+
+ NewNumberOfClusters -- supplies the number of clusters in
+ in the new allocation.
+
+ Bitmap -- supplies the volume bitmap.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This method is only meaningful is the extent list covers an entire
+ attribute instance. In particular, if the extent list's LowestVcn
+ is not zero, this method does nothing (and returns FALSE).
+
+ If this method fails, it leaves the extent list in its original
+ state.
+
+--*/
+{
+ BIG_INT OldNumberOfClusters;
+ BIG_INT ClustersToAdd;
+ LCN NewLcn, NearLcn;
+ ULONG ThisLump;
+
+ if( _LowestVcn != 0 ) {
+
+ // This extent list does not cover the entire attribute
+ // instance, so it cannot be resized.
+
+ return FALSE;
+ }
+
+ // Determine the number of clusters in the current size.
+
+ OldNumberOfClusters = _NextVcn;
+
+
+ if( OldNumberOfClusters == NewNumberOfClusters ) {
+
+ // The extent list is already the size we want.
+
+ return TRUE;
+
+ } else if( NewNumberOfClusters < OldNumberOfClusters ) {
+
+ // We're shrinking the extent list. Note that Truncate
+ // always succeeds, and does not have a return value.
+
+ Truncate( NewNumberOfClusters, Bitmap );
+ return TRUE;
+
+ } else {
+
+ // We are extending the allocation.
+
+ ClustersToAdd = NewNumberOfClusters - OldNumberOfClusters;
+
+ if( ClustersToAdd.GetHighPart() != 0 ) {
+
+ DebugPrint( "Trying to allocate more than 4G clusters.\n" );
+ return FALSE;
+ }
+
+ ThisLump = ClustersToAdd.GetLowPart();
+ NearLcn = QueryLastLcn();
+
+ while( ClustersToAdd != 0 ) {
+
+ if (ClustersToAdd.GetLowPart() < ThisLump) {
+
+ ThisLump = ClustersToAdd.GetLowPart();
+ }
+
+ if( !Bitmap->AllocateClusters( NearLcn,
+ ThisLump,
+ &NewLcn ) ) {
+
+ // We can't allocate a chunk this size; cut it
+ // in half and try again.
+ //
+ ThisLump /= 2;
+
+ if( ThisLump == 0 ) {
+
+ // We're out of disk space. Restore the extent
+ // list to its original state and exit with an
+ // error.
+
+ Truncate( OldNumberOfClusters, Bitmap );
+ return FALSE;
+ }
+
+ } else {
+
+ // We allocated a chunk. Add it on to the end.
+
+ if( !AddExtent( _NextVcn, NewLcn, ThisLump ) ) {
+
+ // We hit an internal error trying to add
+ // this extent. Restore the extent list to
+ // its original state and return failure.
+
+ Truncate( OldNumberOfClusters, Bitmap );
+ return FALSE;
+ }
+
+ ClustersToAdd -= ThisLump;
+
+ // If there's more to get, we won't be able to get
+ // it contiguous; instead, set NearLcn to 0 to take
+ // advantage of the roving pointer.
+ //
+ NearLcn = 0;
+ }
+ }
+
+ return TRUE;
+ }
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_EXTENT_LIST::QueryExtent(
+ IN ULONG ExtentNumber,
+ OUT PVCN Vcn,
+ OUT PLCN Lcn,
+ OUT PBIG_INT RunLength
+ ) CONST
+/*++
+
+Routine Description:
+
+ This methods gives the client information on an extent in
+ the list.
+
+Arguments:
+
+ ExtentNumber -- supplies the number of the extent to return (zero-based).
+ Vcn -- receives the starting VCN of the extent.
+ Lcn -- receives the starting LCN of the extent.
+ RunLength -- receives the number of clusters in the extent.
+
+Return Value:
+
+ TRUE if ExtentNumber is less than the number of extents in the list;
+ FALSE if it is out of range.
+
+--*/
+{
+ PNTFS_EXTENT extent;
+ ULONG i;
+ BOOLEAN b;
+ LONGLONG Vbn, Lbn, SectorCount;
+ LARGE_INTEGER li;
+
+ b = FsRtlGetNextLargeMcbEntry((PLARGE_MCB)_Mcb,
+ ExtentNumber, &Vbn, &Lbn, &SectorCount);
+ if (!b) {
+ return FALSE;
+ }
+
+ li.QuadPart = Vbn;
+ *Vcn = li;
+
+ li.QuadPart = Lbn;
+ *Lcn = li;
+
+ li.QuadPart = SectorCount;
+ *RunLength = li;
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_EXTENT_LIST::QueryLcnFromVcn(
+ IN VCN Vcn,
+ OUT PLCN Lcn,
+ OUT PBIG_INT RunLength
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method converts a VCN within the allocation described by
+ this extent list into an LCN.
+
+Arguments:
+
+ Vcn -- supplies the VCN to be converted.
+ Lcn -- receives the LCN that corresponds to the supplied Vcn.
+ RunLength -- if non-NULL, receives the remaining length in the
+ extent from the supplied Vcn.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+ If the specified VCN is outside the range [_LowestVcn, _NextVcn),
+ this method returns FALSE.
+
+ If the extent list is sparse and the requested VCN is in the range
+ of this extent list but falls in a hole, this method will return TRUE;
+ *Lcn is set to LCN_NOT_PRESENT, and *RunLength is set to the remaining
+ run length to the next actual extent.
+
+--*/
+{
+ PNTFS_EXTENT extent;
+ BOOLEAN b;
+ LONGLONG Lbn, SectorCount;
+ LARGE_INTEGER li;
+ VCN vcn;
+ LCN lcn;
+ BIG_INT runlength;
+
+ if (Vcn < _LowestVcn || Vcn >= _NextVcn) {
+
+ return FALSE;
+ }
+
+ b = FsRtlLookupLargeMcbEntry(
+ (PLARGE_MCB)_Mcb,
+ Vcn.GetLargeInteger().QuadPart,
+ &Lbn,
+ &SectorCount, /* SectorCountFromLbn */
+ NULL, /* StartingLbn */
+ NULL, /* SectorCountFromStartingLbn */
+ NULL /* Index */
+ );
+ if (!b) {
+
+ // This VCN fell into a hole. See if it comes after the last
+ // real extent in the list, otherwise maybe it comes before the
+ // first.
+ //
+
+ *Lcn = LCN_NOT_PRESENT;
+
+ if (0 == QueryNumberOfExtents()) {
+ if (NULL != RunLength) {
+ *RunLength = _NextVcn - Vcn;
+ }
+ return TRUE;
+ }
+
+ if (!QueryExtent(QueryNumberOfExtents() - 1, &vcn, &lcn, &runlength)) {
+ return FALSE;
+ }
+
+ if (Vcn > vcn) {
+ if (NULL != RunLength) {
+ *RunLength = _NextVcn - Vcn;
+ }
+ return TRUE;
+ }
+
+ if (!QueryExtent(0, &vcn, &lcn, &runlength)) {
+ return FALSE;
+ }
+
+ if (Vcn < vcn) {
+ if (NULL != RunLength) {
+ *RunLength = Vcn - _LowestVcn;
+ }
+ return TRUE;
+ }
+
+ return FALSE;
+ }
+
+ if (NULL != RunLength) {
+ li.QuadPart = SectorCount;
+ *RunLength = li;
+ }
+
+ if (-1 == Lbn) {
+ *Lcn = LCN_NOT_PRESENT;
+ return TRUE;
+ }
+
+ li.QuadPart = Lbn;
+ *Lcn = li;
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+NTFS_EXTENT_LIST::QueryCompressedMappingPairs(
+ OUT PVCN LowestVcn,
+ OUT PVCN NextVcn,
+ OUT PULONG Length,
+ IN ULONG BufferSize,
+ IN OUT PVOID Buffer,
+ OUT PBOOLEAN HasHoleInFront
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method produces a set of compressed mapping pairs
+ corresponding to this extent list.
+
+Arguments:
+
+ LowestVcn -- receives the lowest VCN covered by this extent list.
+ NextVcn -- receives the VCN following this extent list.
+ Length -- receives the length of the compressed mapping pairs list.
+ BufferSize -- supplies the size of the mapping pairs buffer provided
+ by the caller
+ Buffer -- supplies the buffer into which the compressed mapping
+ pairs list is written.
+ HasHoleInFront
+ -- receives TRUE if we skipped a hole at the very beginning
+ of the extent list during compression; otherwise FALSE.
+ This is useful for code that counts the compression
+ pairs and calls QueryExtent with the count.
+
+Return Value:
+
+ A pointer to the compressed mapping pairs list. Note that the client
+ must free this memory (using FREE). NULL indicates an error.
+
+--*/
+{
+ ULONG MaximumMappingPairs;
+ PMAPPING_PAIR MappingPairs;
+ PMAPPING_PAIR CurrentMappingPair;
+ ULONG NumberOfPairs;
+ VCN TheNextVcn;
+ BOOLEAN Result;
+
+ if (HasHoleInFront)
+ *HasHoleInFront = FALSE;
+
+ // First, let's handle the degenerate case--if the list
+ // has no extents, it's compresses to a single zero byte.
+ //
+ if (IsEmpty()) {
+
+ if (BufferSize == 0) {
+
+ return FALSE;
+
+ } else {
+
+ *LowestVcn = 0;
+ *NextVcn = 0;
+ *Length = 1;
+
+ *(PBYTE)Buffer = 0;
+
+ return TRUE;
+ }
+ }
+
+ // Massage the extent list into a mapping pairs list and compress it.
+ // In the worst case, no two extents are VCN-contiguous, and
+ // so the number of mapping pairs would be one more than twice
+ // the number of extents (gap extent gap extent gap ... extent gap).
+
+ MaximumMappingPairs = 2 * QueryNumberOfExtents() + 1;
+
+ MappingPairs = (PMAPPING_PAIR)MALLOC( (UINT) (sizeof(MAPPING_PAIR) *
+ MaximumMappingPairs) );
+
+ if( MappingPairs == NULL ) {
+
+ return FALSE;
+ }
+
+ TheNextVcn = _LowestVcn;
+ NumberOfPairs = 0;
+
+ CurrentMappingPair = MappingPairs;
+
+ for (ULONG i = 0; i < QueryNumberOfExtents(); ++i) {
+
+ VCN Vcn;
+ LCN Lcn;
+ BIG_INT RunLength;
+
+ DebugAssert(NumberOfPairs < MaximumMappingPairs);
+
+ if (!QueryExtent(i, &Vcn, &Lcn, &RunLength)) {
+ DebugAbort("This shouldn't happen\n");
+ return FALSE;
+ }
+ if (LCN_NOT_PRESENT == Lcn) {
+ if ((i == 0) && HasHoleInFront)
+ *HasHoleInFront = TRUE;
+ continue;
+ }
+
+ if (Vcn != TheNextVcn) {
+
+ // This extent is preceded by a gap, so we create
+ // a mapping pair with the LCN equal to LCN_NOT_PRESENT.
+
+ CurrentMappingPair->NextVcn = Vcn;
+ CurrentMappingPair->CurrentLcn = LCN_NOT_PRESENT;
+
+ CurrentMappingPair++;
+ NumberOfPairs++;
+ }
+
+ // Create a mapping pair for the extent represented by
+ // the current node. At the same time, compute NextVcn
+ // so we can check to see if there's a gap before the
+ // next extent.
+
+ TheNextVcn = Vcn + RunLength;
+
+ CurrentMappingPair->NextVcn = TheNextVcn;
+ CurrentMappingPair->CurrentLcn = Lcn;
+
+ CurrentMappingPair++;
+ NumberOfPairs++;
+ }
+
+ DebugAssert(NumberOfPairs < MaximumMappingPairs);
+
+ if (TheNextVcn != _NextVcn) {
+
+ // The last extent is followed by a gap. Add a mapping pair
+ // (with CurrentLcn of LCN_NOT_PRESENT) to cover that gap.
+
+ CurrentMappingPair->NextVcn = _NextVcn;
+ CurrentMappingPair->CurrentLcn = LCN_NOT_PRESENT;
+
+ NumberOfPairs++;
+ CurrentMappingPair++;
+ }
+
+ // We now have a properly set-up array of mapping pairs. Compress
+ // it into the user's buffer.
+
+ Result = CompressMappingPairs( MappingPairs,
+ NumberOfPairs,
+ _LowestVcn,
+ Buffer,
+ BufferSize,
+ Length );
+
+ FREE( MappingPairs );
+
+ *LowestVcn = _LowestVcn;
+ *NextVcn = _NextVcn;
+
+ return Result;
+}
+
+VOID
+NTFS_EXTENT_LIST::Truncate(
+ IN BIG_INT NewNumberOfClusters,
+ IN OUT PNTFS_BITMAP Bitmap
+ )
+/*++
+
+Routine Description:
+
+ This method truncates the extent list.
+
+Arguments:
+
+ NewNumberOfClusters -- supplies the number of clusters to keep.
+ Bitmap -- supplies the volume bitmap (optional).
+
+Return Value:
+
+ None.
+
+Notes:
+
+ If the number of clusters covered by this extent list is already
+ less than or equal to NewNumberOfClusters, then this method does
+ nothing.
+
+--*/
+{
+ PNTFS_EXTENT extent;
+ BIG_INT new_run_length;
+
+ DebugAssert(_LowestVcn == 0);
+
+ if (NewNumberOfClusters >= _NextVcn) {
+
+ return;
+ }
+
+ for (ULONG i = 0; i < QueryNumberOfExtents(); ++i) {
+
+ VCN Vcn;
+ LCN Lcn;
+ BIG_INT RunLength;
+
+ if (!QueryExtent(i, &Vcn, &Lcn, &RunLength)) {
+ DebugAbort("This shouldn't happen\n");
+ return;
+ }
+ if (LCN_NOT_PRESENT == Lcn) {
+ continue;
+ }
+
+ if (Vcn >= NewNumberOfClusters) {
+
+ if (NULL != Bitmap) {
+ Bitmap->SetFree(Lcn, RunLength);
+ }
+ } else if (Vcn + RunLength > NewNumberOfClusters) {
+
+ new_run_length = NewNumberOfClusters - Vcn;
+
+ if (NULL != Bitmap) {
+ Bitmap->SetFree(Lcn + new_run_length,
+ RunLength - new_run_length);
+ }
+ }
+ }
+
+ _NextVcn = NewNumberOfClusters;
+ FsRtlTruncateLargeMcb(_Mcb, _NextVcn.GetLargeInteger().QuadPart);
+}
+
+
+
+BOOLEAN
+NTFS_EXTENT_LIST::QueryMappingPairsLength(
+ IN PCVOID CompressedPairs,
+ IN ULONG MaximumLength,
+ OUT PULONG Length,
+ OUT PULONG NumberOfPairs
+ )
+/*++
+
+Routine Description:
+
+ This function determines the length of a compressed
+ mapping pairs list.
+
+Arguments:
+
+ CompressedPairs -- supplies the pointer to the compressed list
+ MaximumLength -- supplies the size of the buffer containing the
+ compressed list.
+ Length -- receives the length of the compressed list
+ NumberOfPairs -- receieves the number of pairs in the list
+
+Return Value:
+
+ TRUE upon successful completion. FALSE indicates that the list
+ overflows the supplied buffer.
+
+--*/
+{
+ PBYTE CurrentCountByte;
+ ULONG CurrentLength;
+
+ CurrentCountByte = (PBYTE)CompressedPairs;
+
+ *NumberOfPairs = 0;
+ *Length = 0;
+
+ while( *Length <= MaximumLength &&
+ *CurrentCountByte != 0 ) {
+
+ // The length for this pair is the number of LCN bytes, plus
+ // the number of VCN bytes, plus one for the count byte.
+
+ CurrentLength = LcnBytesFromCountByte( *CurrentCountByte ) +
+ VcnBytesFromCountByte( *CurrentCountByte ) +
+ 1;
+
+ (*NumberOfPairs)++;
+ *Length += CurrentLength;
+
+ CurrentCountByte += CurrentLength;
+ }
+
+ (*Length)++; // For the final 0 byte.
+
+ return( *Length <= MaximumLength );
+}
+
+
+BOOLEAN
+NTFS_EXTENT_LIST::ExpandMappingPairs(
+ IN PCVOID CompressedPairs,
+ IN VCN StartingVcn,
+ IN ULONG BufferSize,
+ IN ULONG MaximumNumberOfPairs,
+ IN OUT PMAPPING_PAIR MappingPairs,
+ OUT PULONG NumberOfPairs
+ )
+/*++
+
+Routine Description:
+
+ This function expands a compressed list of mapping pairs into
+ a client-supplied buffer.
+
+Arguments:
+
+ CompressedPairs -- supplies the compressed mapping pairs
+ StartingVcn -- supplies the lowest VCN mapped by these
+ mapping pairs
+ BufferSize -- supplies the maximum size of the buffer from
+ which the compressed pairs are expanded
+ MaximumNumberOfPairs -- supplies the maximum number of expanded
+ mapping pairs the output buffer can accept
+ MappingPairs -- receives the expanded pairs
+ NumberOfPairs -- receives the number of pairs
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ PBYTE CurrentData;
+ VCN CurrentVcn;
+ LCN CurrentLcn;
+ UCHAR v, l;
+ ULONG CurrentLength;
+ VCN DeltaVcn;
+ LCN DeltaLcn;
+ ULONG PairIndex;
+
+
+ CurrentData = (PBYTE)CompressedPairs;
+ CurrentVcn = StartingVcn;
+ CurrentLcn = 0;
+ CurrentLength = 0;
+ PairIndex = 0;
+
+ while( CurrentLength < BufferSize &&
+ *CurrentData != 0 &&
+ PairIndex < MaximumNumberOfPairs
+ ) {
+
+ // Get the count byte. Note that whenever we advance the
+ // current data pointer, we first increment the length count,
+ // to make sure our access is valid.
+
+ CurrentLength ++;
+
+ if( CurrentLength > BufferSize ) {
+
+ return FALSE;
+ }
+
+ v = VcnBytesFromCountByte( *CurrentData );
+ l = LcnBytesFromCountByte( *CurrentData );
+
+ CurrentData ++;
+
+
+ // Unpack DeltaVcn and compute the current VCN:
+
+ CurrentLength += v;
+
+ if( v > 8 || CurrentLength > BufferSize ) {
+
+ return FALSE;
+ }
+
+ DeltaVcn.Set( v, CurrentData );
+ CurrentData += v;
+
+ CurrentVcn += DeltaVcn;
+ MappingPairs[PairIndex].NextVcn = CurrentVcn;
+
+ // Unpack DeltaLcn and compute the current LCN:
+ //
+ CurrentLength += l;
+
+ if( l > 8 || CurrentLength > BufferSize ) {
+
+ return FALSE;
+ }
+
+ if( l == 0 ) {
+
+ // a delta-LCN count value of 0 indicates a
+ // non-present run.
+ //
+ MappingPairs[PairIndex].CurrentLcn = LCN_NOT_PRESENT;
+
+ } else {
+
+ DeltaLcn.Set( l, CurrentData );
+ CurrentLcn += DeltaLcn;
+ MappingPairs[PairIndex].CurrentLcn = CurrentLcn;
+ }
+
+ CurrentData += l;
+ PairIndex ++;
+ }
+
+ *NumberOfPairs = PairIndex;
+
+ return( CurrentLength <= BufferSize &&
+ *CurrentData == 0 &&
+ PairIndex <= MaximumNumberOfPairs );
+}
+
+
+BOOLEAN
+NTFS_EXTENT_LIST::CompressMappingPairs(
+ IN PCMAPPING_PAIR MappingPairs,
+ IN ULONG NumberOfPairs,
+ IN VCN StartingVcn,
+ IN OUT PVOID CompressedPairs,
+ IN ULONG MaximumCompressedLength,
+ OUT PULONG CompressedLength
+ )
+/*++
+
+Notes:
+
+ The returned length includes the terminating NULL count byte.
+
+--*/
+{
+ PBYTE CurrentData;
+ VCN CurrentVcn;
+ LCN CurrentLcn;
+ ULONG CurrentLength;
+ VCN DeltaVcn;
+ LCN DeltaLcn;
+ ULONG i;
+ UCHAR ComDeltaVcn[sizeof(VCN)];
+ UCHAR ComDeltaLcn[sizeof(LCN)];
+ UCHAR VcnLength;
+ UCHAR LcnLength;
+ UCHAR Major, Minor;
+ BOOLEAN NewSparseFormat;
+
+ // Determine whether to use the old or new format for
+ // representing sparse files.
+ //
+ NTFS_SA::QueryVersionNumber( &Major, &Minor );
+ NewSparseFormat = (Major > 1) || (Major == 1 && Minor > 1);
+
+ // A mapping pair is (NextVcn, CurrentLcn); however, the compressed
+ // form is a list of deltas.
+
+ CurrentData = (PBYTE)CompressedPairs;
+ CurrentVcn = StartingVcn;
+ CurrentLcn = 0;
+ CurrentLength = 0;
+
+ for( i = 0; i < NumberOfPairs; i++ ) {
+
+ DeltaVcn = MappingPairs[i].NextVcn - CurrentVcn;
+ DeltaLcn = MappingPairs[i].CurrentLcn - CurrentLcn;
+
+ DeltaVcn.QueryCompressedInteger(&VcnLength, ComDeltaVcn);
+
+ if( NewSparseFormat && MappingPairs[i].CurrentLcn == LCN_NOT_PRESENT ) {
+
+ LcnLength = 0;
+ DeltaLcn = 0;
+
+ } else {
+
+ DeltaLcn.QueryCompressedInteger(&LcnLength, ComDeltaLcn);
+ }
+
+ // Fill in the count byte and step over it.
+
+ CurrentLength ++;
+
+ if( CurrentLength > MaximumCompressedLength ) {
+
+ return FALSE;
+ }
+
+ *CurrentData = ComputeMappingPairCountByte( VcnLength, LcnLength );
+ CurrentData ++;
+
+
+ // Copy DeltaVcn and advance the pointer
+
+ CurrentLength += VcnLength;
+
+ if( CurrentLength > MaximumCompressedLength ) {
+
+ return FALSE;
+ }
+
+ memcpy( CurrentData, ComDeltaVcn, VcnLength );
+ CurrentData += VcnLength;
+
+
+ // Copy DeltaLcn and advance the pointer
+
+ CurrentLength += LcnLength;
+
+ if( CurrentLength > MaximumCompressedLength ) {
+
+ return FALSE;
+ }
+
+ memcpy( CurrentData, ComDeltaLcn, LcnLength );
+ CurrentData += LcnLength;
+
+ CurrentVcn += DeltaVcn;
+ CurrentLcn += DeltaLcn;
+ }
+
+ // Terminate the compressed list with a zero count byte
+
+ CurrentLength ++;
+
+ if( CurrentLength > MaximumCompressedLength ) {
+
+ return FALSE;
+ }
+
+ *CurrentData = 0;
+ CurrentData ++;
+
+ *CompressedLength = CurrentLength;
+ return TRUE;
+}
+
+
+LCN
+NTFS_EXTENT_LIST::QueryLastLcn(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the last LCN associated with this allocation.
+ If it cannot determine that LCN, it returns an LCN of zero.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The LCN of the last cluster in the extent list (or zero, if
+ the list is empty or we can't determine the last cluster).
+
+--*/
+{
+ LCN TempLcn;
+
+ if( QueryLcnFromVcn( _NextVcn - 1, &TempLcn ) &&
+ TempLcn != LCN_NOT_PRESENT ) {
+
+ return TempLcn;
+
+ } else {
+
+ return( 0 );
+ }
+}
+
+
+
+BOOLEAN
+NTFS_EXTENT_LIST::DeleteRange(
+ IN VCN Vcn,
+ IN BIG_INT RunLength
+ )
+/*++
+
+Routine Description:
+
+ This routine will remove any vcn's in the range specified from
+ the extent list. If this does not exist or exists only partially
+ then those parts that exist will be removed.
+
+Arguments:
+
+ Vcn - Supplies the first Vcn of the range.
+ RunLength - Supplies the length of the range.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PNTFS_EXTENT extent;
+ PNTFS_EXTENT new_extent;
+ BIG_INT delta;
+ NTFS_EXTENT_LIST backup_list;
+
+ FsRtlRemoveLargeMcbEntry(_Mcb,
+ Vcn.GetLargeInteger().QuadPart,
+ RunLength.GetLargeInteger().QuadPart
+ );
+
+ return TRUE;
+}
+
+
+
+BIG_INT
+NTFS_EXTENT_LIST::QueryClustersAllocated(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine computes the number of clusters allocated for this
+ attribute.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of clusters allocated by this attribute.
+
+--*/
+{
+ ULONG i;
+ VCN vcn;
+ LCN lcn;
+ BIG_INT run_length;
+ BIG_INT r;
+
+ r = 0;
+ for (i = 0; QueryExtent(i, &vcn, &lcn, &run_length); i++) {
+
+ if (LCN_NOT_PRESENT == lcn) {
+ continue;
+ }
+ r += run_length;
+ }
+
+ return r;
+}
+
+
+VOID
+NTFS_EXTENT_LIST::SetLowestVcn(
+ IN BIG_INT LowestVcn
+ )
+/*++
+
+Routine Description:
+
+ This method sets the lowest VCN covered by this extent
+ list. Note that for a sparse file, this is not necessarily
+ the same as the VCN of the first extent in the list.
+
+Arguments:
+
+ The lowest VCN mapped by this extent list. Note that this must
+ be less than or equal to the starting VCN of the first entry
+ in the list.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _LowestVcn = LowestVcn;
+}
+
+VOID
+NTFS_EXTENT_LIST::SetNextVcn(
+ IN BIG_INT NextVcn
+ )
+/*++
+
+Routine Description:
+
+ This method sets the highest VCN covered by this extent
+ list. Note that for a sparse file, this is not necessarily
+ the same as the last VCN of the last extent in the list.
+
+Arguments:
+
+ The highest VCN mapped by this extent list.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _NextVcn = NextVcn;
+}
+
+UNTFS_EXPORT
+ULONG
+NTFS_EXTENT_LIST::QueryNumberOfExtents(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This methods tells the client how many extents are in the
+ extent list.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of extents in the list.
+
+--*/
+{
+ return FsRtlNumberOfRunsInLargeMcb((PLARGE_MCB)_Mcb);
+}
diff --git a/private/utils/untfs/src/format.cxx b/private/utils/untfs/src/format.cxx
new file mode 100644
index 000000000..298f7ce31
--- /dev/null
+++ b/private/utils/untfs/src/format.cxx
@@ -0,0 +1,1402 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ format.cxx
+
+Abstract:
+
+ This module contains the definition of NTFS_SA::Create,
+ which performs FORMAT for an NTFS volume.
+
+Author:
+
+ Bill McJohn (billmc) 15-Aug-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "untfs.hxx"
+#include "..\..\ufat\inc\fatsa.hxx" // for PHYS_REMOVABLE and PHYS_FIXED ;
+
+#include "string.hxx"
+#include "wstring.hxx"
+#include "numset.hxx"
+#include "numset.hxx"
+
+#include "ifssys.hxx"
+
+#include "ntfssa.hxx"
+#include "attrib.hxx"
+#include "frs.hxx"
+#include "mftfile.hxx"
+#include "mftref.hxx"
+#include "ntfsbit.hxx"
+#include "attrdef.hxx"
+#include "badfile.hxx"
+#include "bootfile.hxx"
+#include "bitfrs.hxx"
+#include "indxtree.hxx"
+#include "upcase.hxx"
+#include "upfile.hxx"
+#include "logfile.hxx"
+
+#include "rtmsg.h"
+#include "message.hxx"
+
+extern "C" {
+
+#include "bootntfs.h"
+}
+
+
+WCHAR FileNameMft[] = {'$', 'M', 'F', 'T', 0};
+WCHAR FileNameMftRef[] = {'$', 'M', 'F', 'T', 'M', 'i', 'r', 'r', 0 };
+WCHAR FileNameLogFile[] = {'$', 'L', 'o', 'g', 'F', 'i', 'l', 'e', 0 };
+WCHAR FileNameDasd[] = {'$', 'V', 'o', 'l', 'u', 'm', 'e', 0 };
+WCHAR FileNameAttrDef[] = {'$', 'A', 't', 't', 'r', 'D', 'e', 'f', 0 };
+WCHAR FileNameRootIndex[] = {'.', 0 };
+WCHAR FileNameBitmap[] = {'$', 'B', 'i', 't', 'm', 'a', 'p', 0 };
+WCHAR FileNameBootFile[] = {'$', 'B', 'o', 'o', 't', 0 };
+WCHAR FileNameBadFile[] = {'$', 'B', 'a', 'd', 'C', 'l', 'u', 's', 0 };
+WCHAR FileNameQuota[] = {'$', 'Q', 'u', 'o', 't', 'a', 0 };
+
+WCHAR FileNameUpcase[] = { '$', 'U', 'p', 'C', 'a', 's', 'e', 0 };
+
+
+// Buffer for FILE_NAME structure
+
+CONST FileNameBufferSize = 256;
+CHAR FileNameBuffer[ FileNameBufferSize ];
+CONST PFILE_NAME FileName = (PFILE_NAME)(FileNameBuffer);
+
+
+UNTFS_EXPORT
+ULONG
+NTFS_SA::QuerySectorsInElementaryStructures(
+ IN PCDP_DRIVE Drive,
+ IN ULONG ClusterFactor,
+ IN ULONG FrsSize,
+ IN ULONG ClustersPerIndexBuffer,
+ IN ULONG LogFileSize
+ )
+/*++
+
+Routine Description:
+
+ This method computes the number of sectors required for
+ the elementary structures of an NTFS volume.
+
+Arguments:
+
+ Drive -- Supplies the drive under consideration.
+ ClusterFactor -- Supplies the number of sectors per
+ cluster. May be zero, in which case
+ a default value is supplied.
+ FrsSize -- Supplies the number of bytes per
+ NTFS File Record Segment. May be zero,
+ in which case a default value is supplied.
+ ClustersPerIndexBuffer -- Supplies the number of clusters per NTFS
+ index allocation buffer. May be zero,
+ in which case a default value is supplied.
+ LogFileSize -- Supplies the size of the log file. May
+ be zero, in which case a default value
+ is supplied.
+
+Return Value:
+
+ Returns the number of sectors required by an NTFS volume on
+ this drive with the specified parameters. Returns zero if
+ it is unable to compute this figure.
+
+--*/
+{
+ ULONG SectorsOnVolume, SectorsRequired, SectorSize;
+ ULONG ClusterSize;
+
+ if( Drive->QuerySectors().GetHighPart() != 0 ) {
+
+ return 0;
+ }
+
+ SectorsOnVolume = Drive->QuerySectors().GetLowPart() - 1;
+
+ SectorSize = Drive->QuerySectorSize();
+
+ if( SectorSize == 0 ) {
+
+ return 0;
+ }
+
+ // compute defaults.
+ //
+ if( ClusterFactor == 0 ) {
+
+ ClusterFactor = NTFS_SA::QueryDefaultClusterFactor( Drive );
+ }
+
+ if( FrsSize == 0 ) {
+ FrsSize = SMALL_FRS_SIZE;
+ }
+
+ //
+ // We'll be in trouble if the frs size is less than the sector
+ // size, because we do all our io in units of sectors.
+ //
+
+ if (FrsSize < Drive->QuerySectorSize()) {
+ FrsSize = Drive->QuerySectorSize();
+ }
+
+ if( ClustersPerIndexBuffer == 0 ) {
+
+ ClustersPerIndexBuffer = QueryDefaultClustersPerIndexBuffer( Drive, ClusterFactor);
+ }
+
+ if( LogFileSize == 0 ) {
+
+ LogFileSize = NTFS_LOG_FILE::QueryDefaultSize( Drive, Drive->QuerySectors()-1 );
+ }
+
+ ClusterSize = ClusterFactor * SectorSize;
+
+ // Now add up the various elementary structures:
+ //
+ // MFT
+ //
+
+ SectorsRequired = ((FIRST_USER_FILE_NUMBER * FrsSize + (ClusterSize - 1))
+ / ClusterSize) * ClusterFactor;
+
+ // MFT Mirror
+ //
+
+ SectorsRequired += ((REFLECTED_MFT_SEGMENTS * FrsSize + (ClusterSize - 1))
+ / ClusterSize) * ClusterFactor;
+
+ // Log file
+ //
+
+ SectorsRequired += LogFileSize/SectorSize + 1;
+
+ // Attribute Definition Table
+ //
+ SectorsRequired += NTFS_ATTRIBUTE_DEFINITION_TABLE::QueryDefaultSize()/SectorSize + 1;
+
+ // Bitmap
+ //
+ SectorsRequired += ((SectorsOnVolume / ClusterFactor ) / 8)/SectorSize + 1;
+
+ // Boot file
+ //
+ SectorsRequired += BYTES_IN_BOOT_AREA/SectorSize;
+
+ // Upcase Table
+ //
+ SectorsRequired += NTFS_UPCASE_TABLE::QueryDefaultSize()/SectorSize;
+
+ // The Volume DASD file, the Bad Cluster file, and the Quota
+ // Table don't take up any extra space.
+
+ return SectorsRequired;
+}
+
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_SA::WriteRemainingBootCode(
+ )
+/*++
+
+Routine Description:
+
+ This method writes the remainder of the boot code, ie. the
+ portion that is not stored in the first sector (which is
+ written when the superarea itself is written).
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ HMEM BootCodeMem;
+ SECRUN BootCodeSecrun;
+ ULONG SectorsInBootArea, SectorSize;
+
+ SectorSize = _drive->QuerySectorSize();
+
+ SectorsInBootArea = ( BYTES_IN_BOOT_AREA % SectorSize ) ?
+ ( BYTES_IN_BOOT_AREA / SectorSize + 1 ) :
+ ( BYTES_IN_BOOT_AREA / SectorSize );
+
+ if( !BootCodeMem.Initialize() ||
+ !BootCodeSecrun.Initialize( &BootCodeMem,
+ _drive,
+ 1,
+ SectorsInBootArea - 1 ) ) {
+
+ return FALSE;
+ }
+
+ memcpy( BootCodeSecrun.GetBuf(),
+ (PUCHAR)NtfsBootCode + SectorSize,
+ sizeof( NtfsBootCode ) - SectorSize );
+
+ if( !BootCodeSecrun.Write( ) ) {
+
+ return FALSE;
+ }
+
+ SetSystemId();
+
+ return TRUE;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_SA::CreateElementaryStructures(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN ULONG ClusterFactor,
+ IN ULONG FrsSize,
+ IN ULONG IndexBufferSize,
+ IN ULONG InitialLogFileSize,
+ IN PCNUMBER_SET BadSectors,
+ IN OUT PMESSAGE Message,
+ IN PBIOS_PARAMETER_BLOCK OldBpb,
+ IN PCWSTRING Label
+ )
+/*++
+
+Routine Description:
+
+ This method creates the system-defined files on the volume. Note
+ that it does not write the superarea (ie. the boot sectors).
+
+Arguments:
+
+ VolumeBitmap -- Supplies the bitmap for the volume.
+ ClusterFactor -- Supplies the number of sectors per cluster.
+ FrsSize -- Supplies the size of each FRS (in bytes).
+ IndexBufferSize -- Supplies the volume default index allocation
+ buffer size.
+ InitialLogFileSize -- Supplies the initial size of the log file.
+ If zero is given for this parameter, this
+ method will choose a default size based on
+ the size of the volume.
+ BadSectors -- Supplies a list of the bad sectors on the disk.
+ Message -- Supplies an outlet for messages.
+ OldBpb -- Supplies a pointer to the volume's existing
+ Bios Parameter Block. If this parameter
+ is present, then the disk geometry information
+ (Sectors per Track, Heads, and HiddenSectors)
+ are copied from it; otherwise, they are
+ queried from the drive.
+ Label -- Supplies an optional volume label (may be NULL)
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ The supplied Bitmap is updated and written to disk.
+
+ We want the volume layout to be something like this:
+
+ 0 $Boot
+ $Mft Bitmap (at least 8k)
+ $Mft
+
+ n/2 $MftMirr
+ $LogFile
+ $AttrDef
+ $Bitmap
+ $UpCase
+ root index allocation
+
+--*/
+{
+ NUMBER_SET BadClusters;
+ NTFS_MFT_FILE MftFile;
+ NTFS_REFLECTED_MASTER_FILE_TABLE MftReflection;
+ NTFS_ATTRIBUTE_DEFINITION_TABLE AttributeDefinitionTable;
+ NTFS_BAD_CLUSTER_FILE BadClusterFile;
+ NTFS_BITMAP_FILE BitmapFile;
+ NTFS_BOOT_FILE BootFile;
+ NTFS_LOG_FILE LogFile;
+ NTFS_FILE_RECORD_SEGMENT RootIndexFile;
+ NTFS_FILE_RECORD_SEGMENT QuotaFile;
+ NTFS_FILE_RECORD_SEGMENT VolumeDasdFile;
+ NTFS_FILE_RECORD_SEGMENT GenericFrs;
+ NTFS_INDEX_TREE RootIndex;
+ NTFS_ATTRIBUTE BitmapAttribute;
+ NTFS_ATTRIBUTE VolumeInformationAttribute;
+ DSTRING RootIndexName;
+ NTFS_UPCASE_FILE UpcaseFile;
+ NTFS_UPCASE_TABLE UpcaseTable;
+
+ MFT_SEGMENT_REFERENCE RootFileIndexSegment;
+ STANDARD_INFORMATION StandardInformation;
+ VOLUME_INFORMATION VolumeInformation;
+ LARGE_INTEGER SystemTime;
+ LCN MftLcn, Lcn;
+ ULONG NumberOfSectors, i, nFirstUserFrs,
+ ClusterSize, ClustersInBootArea, MftSize;
+ PWSTR LabelString;
+ ULONG NumBootClusters;
+
+ CONST PVOID FileNameValue = NtfsFileNameGetName( FileName );
+
+ // Determine the size of the volume:
+ //
+ if (_drive->QuerySectors().GetHighPart() != 0) {
+
+ DebugAbort("Number of sectors exceeds 32 bits");
+ return FALSE;
+ }
+
+ NumberOfSectors = _drive->QuerySectors().GetLowPart() - 1;
+
+ //
+ // The replica boot sector will be just past the end of the volume.
+ //
+
+ if (_boot2 != 0 && _boot2 != NumberOfSectors) {
+
+ DebugPrintf("NTFS_SA::CreateElentary - found _boot2 incorrect.\n");
+ }
+
+ _boot2 = NumberOfSectors;
+
+ // Set up the Standard Information structure that will
+ // be used by all the special files. The creation and modification
+ // times are now, and all files created by format are hidden.
+
+ memset( (PVOID)&StandardInformation,
+ 0,
+ sizeof(STANDARD_INFORMATION) );
+
+ IFS_SYSTEM::QueryNtfsTime( &SystemTime );
+
+ StandardInformation.CreationTime =
+ StandardInformation.LastModificationTime =
+ StandardInformation.LastChangeTime =
+ StandardInformation.LastAccessTime = SystemTime;
+
+ StandardInformation.FileAttributes = FILE_ATTRIBUTE_HIDDEN |
+ FILE_ATTRIBUTE_SYSTEM;
+
+ // Get the default system upcase table
+ //
+ if( !UpcaseTable.Initialize() ) {
+
+ DebugAbort( "Can't initialize upcase table.\n" );
+ return FALSE;
+ }
+
+ // Calculate the cluster size. Currently cluster sizes greater
+ // than 64k are not supported, so make sure we don't create volumes
+ // with larger clusters.
+ //
+
+ ClusterSize = ClusterFactor * _drive->QuerySectorSize();
+
+ if (ClusterSize > 64 * 1024) {
+
+ ClusterSize = 64 * 1024;
+ ClusterFactor = ClusterSize / _drive->QuerySectorSize();
+ }
+
+ // Clear the boot block and the backup boot cluster in the
+ // bitmap. Note that these will get set immediately after
+ // the bad sectors are marked as in use--this allows me to
+ // detect if these sectors are on the bad sector list.
+ //
+
+ ClustersInBootArea = (BYTES_IN_BOOT_AREA % ClusterSize) ?
+ BYTES_IN_BOOT_AREA / ClusterSize + 1 :
+ BYTES_IN_BOOT_AREA / ClusterSize;
+
+ NumBootClusters = max(1, BYTES_PER_BOOT_SECTOR/ClusterSize);
+
+ VolumeBitmap->SetFree( 0, ClustersInBootArea );
+
+ // Convert the Bad Sectors to Bad Clusters, and mark those
+ // clusters as in-use in the bitmap. Note that we have to
+ // check for duplicates, or else the Bad Cluster File will
+ // choke on the list.
+
+ if( !BadClusters.Initialize() ) {
+
+ Message->Set( MSG_FMT_NO_MEMORY );
+ Message->Display( "" );
+
+ DebugPrint( "Can't initialize bad clusters numset.\n" );
+ return FALSE;
+ }
+
+ for( i = 0; i < BadSectors->QueryCardinality(); i++ ) {
+
+ Lcn = BadSectors->QueryNumber(i)/ClusterFactor;
+
+ BadClusters.Add( Lcn );
+ VolumeBitmap->SetAllocated( Lcn, 1 );
+ }
+
+
+ // The first BYTES_IN_BOOT_AREA bytes on the volume and
+ // the cluster which contains the middle sector of the volume
+ // are reserved for the Boot file. If these sectors are not
+ // free, it means that we have bad sectors in one of these
+ // reserved spots. We won't allow such a volume to be formatted
+ // to NTFS.
+
+ if( !VolumeBitmap->IsFree( 0, ClustersInBootArea )) {
+
+ DebugPrint( "Boot sector is in bad cluster list.\n" );
+ return FALSE;
+ }
+
+ VolumeBitmap->SetAllocated( 0, ClustersInBootArea );
+
+ // Allocate space for the MFT itself. We want the mft bitmap to
+ // be immediately after the primary boot cluster, with the Mft following,
+ // so we leave space for the mft bitmap.
+ //
+
+ MftSize = (FIRST_USER_FILE_NUMBER * FrsSize + (ClusterSize - 1))/ClusterSize;
+
+ MftLcn = ClustersInBootArea +
+ (MFT_BITMAP_INITIAL_SIZE + (ClusterSize - 1))/ClusterSize;
+
+ if( !VolumeBitmap->AllocateClusters( MftLcn, MftSize, &MftLcn ) ) {
+
+ DebugPrint( "Can't allocate space for the MFT.\n" );
+ return FALSE;
+ }
+
+ // Another bit of housecleaning: I need the file segment reference
+ // of the root file name index so I can add file-name attributes
+ // to the system files. The initial sequence number of the Root
+ // File Index FRS is the same as its file number.
+ //
+
+ RootFileIndexSegment.LowPart = ROOT_FILE_NAME_INDEX_NUMBER;
+ RootFileIndexSegment.HighPart = 0;
+ RootFileIndexSegment.SequenceNumber = ROOT_FILE_NAME_INDEX_NUMBER;
+
+ if( !RootIndexName.Initialize( FileNameIndexNameData ) ||
+ !RootIndex.Initialize( $FILE_NAME,
+ _drive,
+ ClusterFactor,
+ VolumeBitmap,
+ &UpcaseTable,
+ COLLATION_FILE_NAME,
+ IndexBufferSize,
+ FrsSize / 2,
+ &RootIndexName ) ) {
+
+ DebugPrint( "Cannot initialize Index Tree for root file name index.\n" );
+ return FALSE;
+ }
+
+ // These "Hidden Status" messages are a hack to allow WinDisk to
+ // cancel a quick format, which ordinarily doesn't send any status
+ // messages, but which might take a while and for which there is a
+ // cancel button. When using format.com, no message will be displayed
+ // for this.
+
+ Message->Set(MSG_HIDDEN_STATUS, NORMAL_MESSAGE, 0);
+ if (!Message->Display()) {
+ return FALSE;
+ }
+
+ // Initialize and create the MFT. Note that this will not
+ // actually write the MFT to disk.
+
+ // Set up the FILE_NAME attribute.
+
+ memset( FileName,
+ 0,
+ FileNameBufferSize );
+
+ FileName->ParentDirectory = RootFileIndexSegment;
+ FileName->FileNameLength = wcslen( FileNameMft );
+ FileName->Flags = FILE_NAME_NTFS | FILE_NAME_DOS;
+
+ memset( FileNameValue,
+ 0,
+ FileNameBufferSize - sizeof( FILE_NAME ) );
+
+ memcpy( FileNameValue,
+ FileNameMft,
+ FileName->FileNameLength * sizeof( WCHAR ) );
+
+ if( !MftFile.Initialize( _drive,
+ MftLcn,
+ ClusterFactor,
+ FrsSize,
+ _drive->QuerySectors() - 1,
+ VolumeBitmap,
+ &UpcaseTable ) ||
+ !MftFile.Create( FIRST_USER_FILE_NUMBER,
+ &StandardInformation,
+ VolumeBitmap ) ||
+ !MftFile.AddFileNameAttribute( FileName ) ||
+ !MftFile.AddSecurityDescriptor( ReadCannedSd, VolumeBitmap ) ||
+ !RootIndex.InsertEntry( NtfsFileNameGetLength( FileName ),
+ FileName,
+ MftFile.QuerySegmentReference() ) ) {
+
+ DebugPrint( "Can't create MFT.\n" );
+ return FALSE;
+ }
+
+ // Initialize, create, and write the reflection of the Master
+ // File Table. Note that this allocates space for the MFT
+ // Reflection's data attribute, but does not write the data
+ // attribute.
+
+ // Set up the FILE_NAME attribute.
+
+ FileName->ParentDirectory = RootFileIndexSegment;
+ FileName->FileNameLength = wcslen( FileNameMftRef );
+ FileName->Flags = FILE_NAME_NTFS | FILE_NAME_DOS;
+
+ memset( FileNameValue,
+ 0,
+ FileNameBufferSize - sizeof( FILE_NAME ) );
+
+ memcpy( FileNameValue,
+ FileNameMftRef,
+ FileName->FileNameLength * sizeof( WCHAR ) );
+
+ if( !MftReflection.Initialize( MftFile.GetMasterFileTable() ) ||
+ !MftReflection.Create( &StandardInformation,
+ VolumeBitmap ) ||
+ !MftReflection.AddFileNameAttribute( FileName ) ||
+ !MftReflection.AddSecurityDescriptor( ReadCannedSd,
+ VolumeBitmap ) ||
+ !RootIndex.InsertEntry( NtfsFileNameGetLength( FileName ),
+ FileName,
+ MftReflection.QuerySegmentReference() ) ||
+ !MftReflection.Flush(VolumeBitmap, &RootIndex) ) {
+
+ DebugPrint( "Can't create MFT Reflection.\n" );
+ return FALSE;
+ }
+
+ Message->Set(MSG_HIDDEN_STATUS, NORMAL_MESSAGE, 0);
+ if (!Message->Display()) {
+ return FALSE;
+ }
+
+ // Initialize, create, and write the log file.
+
+ // Set up the FILE_NAME attribute.
+
+ FileName->ParentDirectory = RootFileIndexSegment;
+ FileName->FileNameLength = wcslen( FileNameLogFile );
+ FileName->Flags = FILE_NAME_NTFS | FILE_NAME_DOS;
+
+ memset( FileNameValue,
+ 0,
+ FileNameBufferSize - sizeof( FILE_NAME ) );
+
+ memcpy( FileNameValue,
+ FileNameLogFile,
+ FileName->FileNameLength * sizeof( WCHAR ) );
+
+ if( !LogFile.Initialize( MftFile.GetMasterFileTable() ) ||
+ !LogFile.Create( &StandardInformation,
+ InitialLogFileSize,
+ VolumeBitmap ) ||
+ !LogFile.AddFileNameAttribute( FileName ) ||
+ !LogFile.AddSecurityDescriptor( ReadCannedSd, VolumeBitmap ) ||
+ !RootIndex.InsertEntry( NtfsFileNameGetLength( FileName ),
+ FileName,
+ LogFile.QuerySegmentReference() ) ||
+ !LogFile.Flush(VolumeBitmap, &RootIndex) ) {
+
+ DebugPrint( "Can't create Log File.\n" );
+ return FALSE;
+ }
+
+ Message->Set(MSG_HIDDEN_STATUS, NORMAL_MESSAGE, 0);
+ if (!Message->Display()) {
+ return FALSE;
+ }
+
+ // Initialize, create, and write an empty file for the Volume DASD info.
+
+ // Set up the FILE_NAME attribute.
+
+ FileName->ParentDirectory = RootFileIndexSegment;
+ FileName->FileNameLength = wcslen( FileNameDasd );
+ FileName->Flags = FILE_NAME_NTFS | FILE_NAME_DOS;
+
+ memset( FileNameValue,
+ 0,
+ FileNameBufferSize - sizeof( FILE_NAME ) );
+
+ memcpy( FileNameValue,
+ FileNameDasd,
+ FileName->FileNameLength * sizeof( WCHAR ) );
+
+ // Set up the volume information attribute.
+ //
+ memset(&VolumeInformation, 0, sizeof(VOLUME_INFORMATION));
+
+ VolumeInformation.MajorVersion = NTFS_CURRENT_MAJOR_VERSION;
+ VolumeInformation.MinorVersion = NTFS_CURRENT_MINOR_VERSION;
+ VolumeInformation.VolumeFlags = 0;
+
+ if (!VolumeInformationAttribute.Initialize(_drive, ClusterFactor,
+ &VolumeInformation, sizeof(VOLUME_INFORMATION),
+ $VOLUME_INFORMATION)) {
+
+ DebugPrint( "Can't create volume information attribute.\n" );
+ return FALSE;
+ }
+
+ if (Label) {
+ LabelString = Label->QueryWSTR();
+ } else {
+ LabelString = NULL;
+ }
+
+ if( !VolumeDasdFile.Initialize( VOLUME_DASD_NUMBER,
+ MftFile.GetMasterFileTable() ) ||
+ !VolumeDasdFile.Create( &StandardInformation ) ||
+ !VolumeDasdFile.AddFileNameAttribute( FileName ) ||
+ !VolumeDasdFile.AddSecurityDescriptor( WriteCannedSd, VolumeBitmap ) ||
+ !VolumeDasdFile.AddEmptyAttribute( $DATA ) ||
+ !(LabelString == NULL ||
+ VolumeDasdFile.AddAttribute( $VOLUME_NAME, NULL, LabelString,
+ Label->QueryChCount()*sizeof(WCHAR),
+ VolumeBitmap )) ||
+ !VolumeInformationAttribute.InsertIntoFile( &VolumeDasdFile,
+ NULL ) ||
+ !RootIndex.InsertEntry( NtfsFileNameGetLength( FileName ),
+ FileName,
+ VolumeDasdFile.QuerySegmentReference() ) ||
+ !VolumeDasdFile.Flush(VolumeBitmap, &RootIndex) ) {
+
+ DebugPrint( "Can't create Volume DASD file.\n" );
+ return FALSE;
+ }
+
+ DELETE(LabelString);
+
+ Message->Set(MSG_HIDDEN_STATUS, NORMAL_MESSAGE, 0);
+ if (!Message->Display()) {
+ return FALSE;
+ }
+
+ // Initialize, create, and write the Attribute Definition Table
+ // File Record Segment. This will also allocate and write the
+ // Attribute Definition Table's DATA attribute, which is the
+ // actual attribute definition table.
+
+ // Set up the FILE_NAME attribute.
+
+ FileName->ParentDirectory = RootFileIndexSegment;
+ FileName->FileNameLength = wcslen( FileNameAttrDef );
+ FileName->Flags = FILE_NAME_NTFS | FILE_NAME_DOS;
+
+ memset( FileNameValue,
+ 0,
+ FileNameBufferSize - sizeof( FILE_NAME ) );
+
+ memcpy( FileNameValue,
+ FileNameAttrDef,
+ FileName->FileNameLength * sizeof( WCHAR ) );
+
+ if( !AttributeDefinitionTable.Initialize( MftFile.GetMasterFileTable() ) ||
+ !AttributeDefinitionTable.Create( &StandardInformation,
+ VolumeBitmap ) ||
+ !AttributeDefinitionTable.AddFileNameAttribute( FileName ) ||
+ !AttributeDefinitionTable.AddSecurityDescriptor( ReadCannedSd,
+ VolumeBitmap ) ||
+ !RootIndex.InsertEntry( NtfsFileNameGetLength( FileName ),
+ FileName,
+ AttributeDefinitionTable.
+ QuerySegmentReference() ) ||
+ !AttributeDefinitionTable.Flush(VolumeBitmap, &RootIndex) ) {
+
+ DebugPrint( "Can't create Attribute Definition Table.\n" );
+ return FALSE;
+ }
+
+ Message->Set(MSG_HIDDEN_STATUS, NORMAL_MESSAGE, 0);
+ if (!Message->Display()) {
+ return FALSE;
+ }
+
+ // Initialize, create, and write the FRS for the root file name
+ // index.
+
+ // Set up the FILE_NAME attribute.
+
+ FileName->ParentDirectory = RootFileIndexSegment;
+ FileName->FileNameLength = wcslen( FileNameRootIndex );
+ FileName->Flags = FILE_NAME_NTFS | FILE_NAME_DOS;
+
+ memset( FileNameValue,
+ 0,
+ FileNameBufferSize - sizeof( FILE_NAME ) );
+
+ memcpy( FileNameValue,
+ FileNameRootIndex,
+ FileName->FileNameLength * sizeof( WCHAR ) );
+
+ if( !RootIndexFile.Initialize( ROOT_FILE_NAME_INDEX_NUMBER,
+ MftFile.GetMasterFileTable() ) ||
+ !RootIndexFile.Create( &StandardInformation,
+ FILE_FILE_NAME_INDEX_PRESENT ) ||
+ !RootIndexFile.AddFileNameAttribute( FileName ) ||
+ !RootIndexFile.AddSecurityDescriptor( NoAclCannedSd,
+ VolumeBitmap ) ||
+ !RootIndex.InsertEntry( NtfsFileNameGetLength( FileName ),
+ FileName,
+ RootIndexFile.QuerySegmentReference() ) ||
+ !RootIndexFile.Flush(VolumeBitmap, &RootIndex) ) {
+
+ DebugPrint( "Can't create Root Index FRS.\n" );
+ return FALSE;
+ }
+
+ Message->Set(MSG_HIDDEN_STATUS, NORMAL_MESSAGE, 0);
+ if (!Message->Display()) {
+ return FALSE;
+ }
+
+ // Initialize, create, and write the bitmap File Record Segment.
+ // Note that this does not write the bitmap, just its File Record
+ // Segment. Note also that the disk space for the bitmap is
+ // allocated at this time.
+
+ // Set up the FILE_NAME attribute.
+
+ FileName->ParentDirectory = RootFileIndexSegment;
+ FileName->FileNameLength = wcslen( FileNameBitmap );
+ FileName->Flags = FILE_NAME_NTFS | FILE_NAME_DOS;
+
+ memset( FileNameValue,
+ 0,
+ FileNameBufferSize - sizeof( FILE_NAME ) );
+
+ memcpy( FileNameValue,
+ FileNameBitmap,
+ FileName->FileNameLength * sizeof( WCHAR ) );
+
+ if( !BitmapFile.Initialize( MftFile.GetMasterFileTable() ) ||
+ !BitmapFile.Create( &StandardInformation, VolumeBitmap ) ||
+ !BitmapFile.AddFileNameAttribute( FileName ) ||
+ !BitmapFile.AddSecurityDescriptor( ReadCannedSd, VolumeBitmap ) ||
+ !RootIndex.InsertEntry( NtfsFileNameGetLength( FileName ),
+ FileName,
+ BitmapFile.QuerySegmentReference() ) ||
+ !BitmapFile.Flush(VolumeBitmap, &RootIndex) ) {
+
+ DebugPrint( "Can't create Bitmap File.\n" );
+ return FALSE;
+ }
+
+ Message->Set(MSG_HIDDEN_STATUS, NORMAL_MESSAGE, 0);
+ if (!Message->Display()) {
+ return FALSE;
+ }
+
+ // Initialize, create, and write the Boot-File File Record Segment.
+
+ // Set up the FILE_NAME attribute.
+
+ FileName->ParentDirectory = RootFileIndexSegment;
+ FileName->FileNameLength = wcslen( FileNameBootFile );
+ FileName->Flags = FILE_NAME_NTFS | FILE_NAME_DOS;
+
+ memset( FileNameValue,
+ 0,
+ FileNameBufferSize - sizeof( FILE_NAME ) );
+
+ memcpy( FileNameValue,
+ FileNameBootFile,
+ FileName->FileNameLength * sizeof( WCHAR ) );
+
+ if( !BootFile.Initialize( MftFile.GetMasterFileTable() ) ||
+ !BootFile.Create( &StandardInformation ) ||
+ !BootFile.AddFileNameAttribute( FileName ) ||
+ !BootFile.AddSecurityDescriptor( ReadCannedSd, VolumeBitmap ) ||
+ !RootIndex.InsertEntry( NtfsFileNameGetLength( FileName ),
+ FileName,
+ BootFile.QuerySegmentReference() ) ||
+ !BootFile.Flush(VolumeBitmap, &RootIndex) ) {
+
+ DebugPrint( "Can't create boot file.\n" );
+ return FALSE;
+ }
+
+ Message->Set(MSG_HIDDEN_STATUS, NORMAL_MESSAGE, 0);
+ if (!Message->Display()) {
+ return FALSE;
+ }
+
+ // Initialize, create, and write the Bad Cluster File.
+ //
+ // Set up the FILE_NAME attribute.
+ //
+ FileName->ParentDirectory = RootFileIndexSegment;
+ FileName->FileNameLength = wcslen( FileNameBadFile );
+ FileName->Flags = FILE_NAME_NTFS | FILE_NAME_DOS;
+
+ memset( FileNameValue,
+ 0,
+ FileNameBufferSize - sizeof( FILE_NAME ) );
+
+ memcpy( FileNameValue,
+ FileNameBadFile,
+ FileName->FileNameLength * sizeof( WCHAR ) );
+
+ if( !BadClusterFile.Initialize( MftFile.GetMasterFileTable() ) ||
+ !BadClusterFile.Create( &StandardInformation,
+ VolumeBitmap,
+ &BadClusters ) ||
+ !BadClusterFile.AddFileNameAttribute( FileName ) ||
+ !BadClusterFile.AddSecurityDescriptor( ReadCannedSd, VolumeBitmap ) ||
+ !RootIndex.InsertEntry( NtfsFileNameGetLength( FileName ),
+ FileName,
+ BadClusterFile.QuerySegmentReference() ) ||
+ !BadClusterFile.Flush(VolumeBitmap, &RootIndex) ) {
+
+ DebugPrint( "Can't create Bad Cluster File.\n" );
+ return FALSE;
+ }
+
+ Message->Set(MSG_HIDDEN_STATUS, NORMAL_MESSAGE, 0);
+ if (!Message->Display()) {
+ return FALSE;
+ }
+
+ // Initialize, create, and write the Quota Table.
+
+ // Set up the FILE_NAME attribute.
+
+ FileName->ParentDirectory = RootFileIndexSegment;
+ FileName->FileNameLength = wcslen( FileNameQuota );
+ FileName->Flags = FILE_NAME_NTFS | FILE_NAME_DOS;
+
+ memset( FileNameValue,
+ 0,
+ FileNameBufferSize - sizeof( FILE_NAME ) );
+
+ memcpy( FileNameValue,
+ FileNameQuota,
+ FileName->FileNameLength * sizeof( WCHAR ) );
+
+ if( !QuotaFile.Initialize( QUOTA_TABLE_NUMBER,
+ MftFile.GetMasterFileTable() ) ||
+ !QuotaFile.Create( &StandardInformation ) ||
+ !QuotaFile.AddEmptyAttribute( $DATA ) ||
+ !QuotaFile.AddFileNameAttribute( FileName ) ||
+ !QuotaFile.AddSecurityDescriptor( WriteCannedSd, VolumeBitmap ) ||
+ !RootIndex.InsertEntry( NtfsFileNameGetLength( FileName ),
+ FileName,
+ QuotaFile.QuerySegmentReference() ) ||
+ !QuotaFile.Flush(VolumeBitmap, &RootIndex) ) {
+
+ DebugPrint( "Can't create Quota Table File Record Segment.\n" );
+ return FALSE;
+ }
+
+ Message->Set(MSG_HIDDEN_STATUS, NORMAL_MESSAGE, 0);
+ if (!Message->Display()) {
+ return FALSE;
+ }
+
+ // Create the Upcase Table file.
+ //
+ // Set up the FILE_NAME attribute.
+ //
+ FileName->ParentDirectory = RootFileIndexSegment;
+ FileName->FileNameLength = wcslen( FileNameUpcase );
+ FileName->Flags = FILE_NAME_NTFS | FILE_NAME_DOS;
+
+ memset( FileNameValue,
+ 0,
+ FileNameBufferSize - sizeof( FILE_NAME ) );
+
+ memcpy( FileNameValue,
+ FileNameUpcase,
+ FileName->FileNameLength * sizeof( WCHAR ) );
+
+ if( !UpcaseFile.Initialize( MftFile.GetMasterFileTable() ) ||
+ !UpcaseFile.Create( &StandardInformation,
+ &UpcaseTable,
+ VolumeBitmap ) ||
+ !UpcaseFile.AddFileNameAttribute( FileName ) ||
+ !UpcaseFile.AddSecurityDescriptor( ReadCannedSd, VolumeBitmap ) ||
+ !RootIndex.InsertEntry( NtfsFileNameGetLength( FileName ),
+ FileName,
+ UpcaseFile.QuerySegmentReference() ) ||
+ !UpcaseFile.Flush( VolumeBitmap, &RootIndex ) ) {
+
+ DebugPrint( "Can't create Upcase Table File Record Segment.\n" );
+ return FALSE;
+ }
+
+
+
+ // The reserved FRS's between the Upcase Table and the first user
+ // file must be valid and in-use.
+
+ if (ClusterSize > (FrsSize*FIRST_USER_FILE_NUMBER))
+ nFirstUserFrs = (ClusterSize + FrsSize - 1) / FrsSize;
+ else
+ nFirstUserFrs = FIRST_USER_FILE_NUMBER;
+
+ for( i = UPCASE_TABLE_NUMBER + 1; i < nFirstUserFrs; i++ ) {
+
+ if( !GenericFrs.Initialize( i,
+ MftFile.GetMasterFileTable() ) ||
+ !GenericFrs.Create( &StandardInformation ) ||
+ !GenericFrs.AddEmptyAttribute( $DATA ) ||
+ !GenericFrs.AddSecurityDescriptor( WriteCannedSd,
+ VolumeBitmap ) ||
+ ((i >= FIRST_USER_FILE_NUMBER) && (GenericFrs.ClearInUse(), FALSE)) ||
+ !GenericFrs.Flush( VolumeBitmap ) ) {
+
+ DebugPrintf( "Can't create a generic FRS.\n" );
+ return FALSE;
+ }
+ }
+
+
+ // Construct the root file name index.
+
+
+ if( !RootIndex.Save( &RootIndexFile ) ||
+ !RootIndexFile.Flush(VolumeBitmap) ) {
+
+ DebugPrint( "Can't save root index.\n" );
+ return FALSE;
+ }
+
+
+ // Flush the MFT. Note that flushing the MFT writes the volume
+ // bitmap and the MFT Mirror.
+
+ if( !MftFile.Flush() ) {
+
+ DebugPrint( "Can't flush MFT.\n" );
+ return FALSE;
+ }
+
+ Message->Set(MSG_HIDDEN_STATUS, NORMAL_MESSAGE, 0);
+ if (!Message->Display()) {
+ return FALSE;
+ }
+
+ memset( _boot_sector->Unused1, 0, sizeof(_boot_sector->Unused1) );
+ memset( _boot_sector->Unused2, 0, sizeof(_boot_sector->Unused2) );
+
+ // Fill in sector zero. First, copy the boot code in. Then
+ // set the fields of interest.
+ //
+ memcpy( _boot_sector, NtfsBootCode, _drive->QuerySectorSize() );
+
+ memcpy( _boot_sector->Oem, "NTFS ", 8 );
+
+ _bpb.BytesPerSector = (USHORT)_drive->QuerySectorSize();
+ _bpb.SectorsPerCluster = (UCHAR)ClusterFactor;
+ _bpb.ReservedSectors = 0;
+ _bpb.Fats = 0;
+ _bpb.RootEntries = 0;
+ _bpb.Sectors = 0;
+ _bpb.Media = _drive->QueryMediaByte();
+ _bpb.SectorsPerFat = 0;
+
+ if( OldBpb == NULL ) {
+
+ // Use geometry supplied by the driver.
+ //
+ _bpb.SectorsPerTrack = (USHORT) _drive->QuerySectorsPerTrack();
+ _bpb.Heads = (USHORT) _drive->QueryHeads();
+ _bpb.HiddenSectors = _drive->QueryHiddenSectors().GetLowPart();
+
+ } else {
+
+ // Use geometry recorded in the existing Bios
+ // Parameter Block.
+ //
+ _bpb.SectorsPerTrack = OldBpb->SectorsPerTrack;
+ _bpb.Heads = OldBpb->Heads;
+ _bpb.HiddenSectors = OldBpb->HiddenSectors;
+ }
+
+ _bpb.LargeSectors = 0;
+
+ // Unused[0] is used by the boot code to indicate Drive Number.
+ //
+ memset( _boot_sector->Unused, '\0', 4 );
+
+ memset( _boot_sector->Unused1, '\0', sizeof(_boot_sector->Unused1) );
+ memset( _boot_sector->Unused2, '\0', sizeof(_boot_sector->Unused2) );
+
+ _boot_sector->Unused[0] = _drive->IsRemovable() ? PHYS_REMOVABLE :
+ PHYS_FIXED ;
+ _boot_sector->NumberSectors.LowPart =
+ _drive->QuerySectors().GetLowPart() - 1;
+ _boot_sector->NumberSectors.HighPart =
+ _drive->QuerySectors().GetHighPart();
+
+ _boot_sector->MftStartLcn = MftLcn;
+ _boot_sector->Mft2StartLcn = MftReflection.QueryFirstLcn();
+
+ // If the frs size is less than the cluster size, we write 0 in the
+ // ClustersPerFileRecordSegment. In that case the actual frs size
+ // should be SMALL_FRS_SIZE.
+ //
+
+ // If the frs size is greater than or equal to the cluster size, we
+ // write cluster size divided by frs size into the ClustersPerFrs field.
+ // Otherwise, we will want the frs size to be 1024 bytes, and we will
+ // set the ClustersPerFileRecordSegment to the negation of the log (base 2)
+ // of 1024.
+ //
+
+ ULONG cluster_size = ClusterFactor * _drive->QuerySectorSize();
+
+ if (FrsSize < cluster_size) {
+
+ ULONG temp;
+ LONG j;
+
+ for (j = 0, temp = FrsSize; temp > 1; temp >>= 1) {
+ j++;
+ }
+
+ _boot_sector->ClustersPerFileRecordSegment = CHAR(-j);
+
+ } else {
+
+ _boot_sector->ClustersPerFileRecordSegment = CHAR(FrsSize / cluster_size);
+ }
+
+ // The treatment of DefaultClustersPerIndexBuffer is similar to that of
+ // ClustersPerFRS, except we use SMALL_INDEX_BUFFER_SIZE if the clusters
+ // are larger than a cluster.
+ //
+
+ if (IndexBufferSize < cluster_size) {
+
+ ULONG temp;
+ LONG j;
+
+ for (j = 0, temp = SMALL_INDEX_BUFFER_SIZE; temp > 1; temp >>= 1) {
+ j++;
+ }
+
+ _boot_sector->DefaultClustersPerIndexAllocationBuffer = CHAR(-j);
+
+ } else {
+
+ _boot_sector->DefaultClustersPerIndexAllocationBuffer =
+ CHAR(IndexBufferSize / cluster_size);
+ }
+
+ _boot_sector->SerialNumber.LowPart = SUPERAREA::ComputeVolId();
+ _boot_sector->SerialNumber.HighPart =
+ SUPERAREA::ComputeVolId(_boot_sector->SerialNumber.LowPart);
+
+ _boot_sector->Checksum = 0;
+
+ // The elementary disk structures have been created.
+
+ return TRUE;
+}
+
+BOOLEAN
+NTFS_SA::Create(
+ IN PCNUMBER_SET BadSectors,
+ IN OUT PMESSAGE Message,
+ IN PCWSTRING Label,
+ IN ULONG ClusterSize,
+ IN ULONG VirtualSectors
+ )
+/*++
+
+Routine Description:
+
+ This routine creates a new NTFS volume on disk based on defaults.
+
+Arguments:
+
+ BadSectors - Supplies a list of the bad sectors on the disk.
+ Message - Supplies an outlet for messages.
+ Label - Supplies an optional volume label (may be NULL).
+ ClusterSize - Supplies the desired size of a cluster in bytes.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG ClusterFactor, ClustersPerIndexBuffer;
+
+ UNREFERENCED_PARAMETER( VirtualSectors );
+
+ if (ClusterSize) {
+ ClusterFactor = max(1, ClusterSize/_drive->QuerySectorSize());
+ } else {
+ ClusterFactor = QueryDefaultClusterFactor( _drive );
+ }
+
+ if (ClusterSize != 0 &&
+ ClusterFactor * _drive->QuerySectorSize() != ClusterSize) {
+
+ Message->Set(MSG_FMT_ALLOCATION_SIZE_CHANGED);
+ Message->Display("%d", ClusterFactor * _drive->QuerySectorSize());
+ }
+
+ return( Create( BadSectors,
+ ClusterFactor,
+ SMALL_FRS_SIZE,
+ SMALL_INDEX_BUFFER_SIZE,
+ 0,
+ Message,
+ Label ) );
+}
+
+BOOLEAN
+NTFS_SA::Create(
+ IN PCNUMBER_SET BadSectors,
+ IN ULONG ClusterFactor,
+ IN ULONG FrsSize,
+ IN ULONG IndexBufferSize,
+ IN ULONG InitialLogFileSize,
+ IN OUT PMESSAGE Message,
+ IN PCWSTRING Label
+ )
+/*++
+
+Routine Description:
+
+ This routine creates a new NTFS volume on disk.
+
+Arguments:
+
+ BadSectors -- Supplies a list of the bad sectors
+ on the disk.
+ ClusterFactor -- Supplies the volume cluster factor
+ FrsSize -- Supplies the size of each FRS
+ IndexBufferSize -- Supplies the default size of
+ an index allocation block.
+ InitialLogFileSize -- Supplies the log file size. May be zero,
+ in which case a default value is used.
+ Message -- Supplies an outlet for messages.
+ Label -- Supplies an optional volume label
+ (may be NULL).
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_BITMAP VolumeBitmap;
+ DSTRING InternalLabel;
+ SECRUN BootCodeSecrun;
+ HMEM BootCodeMem;
+
+ BIG_INT KBytesInVolume;
+ ULONG NumberOfSectors, NumberOfClusters, SectorSize,
+ ClusterSize, SectorsInBootArea;
+
+#if 0
+ // For testing, add a bad cluster.
+ //
+ ((PNUMBER_SET) BadSectors)->Add( _drive->QuerySectors() - 16 );
+#endif
+
+
+ // Determine the number of sectors and clusters on the drive.
+
+ if (_drive->QuerySectors().GetHighPart() != 0) {
+
+ DebugAbort("Number of sectors exceeds 32 bits");
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+
+ NumberOfSectors = _drive->QuerySectors().GetLowPart() - 1;
+ NumberOfClusters = NumberOfSectors/ClusterFactor;
+
+ // We're currently not prepared to deal with disks where the frs
+ // size is smaller than the sector size, so bump the frs size
+ // up if that is the case. Same deal with the default index buffer
+ // size.
+ //
+
+ if (FrsSize < _drive->QuerySectorSize()) {
+
+ FrsSize = _drive->QuerySectorSize();
+ }
+ if (IndexBufferSize < _drive->QuerySectorSize()) {
+
+ IndexBufferSize = _drive->QuerySectorSize();
+ }
+
+ // The replica boot sector will be at the very end of the volume.
+
+ _boot2 = NumberOfSectors;
+
+ // Generate a bitmap to cover the number of clusters on the drive.
+
+ if (!VolumeBitmap.Initialize(NumberOfClusters, FALSE, NULL, 0)) {
+
+ DebugPrint( "Cannot initialize bitmap.\n" );
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ // If the user did not specify a label, prompt for it:
+ //
+ if (Label) {
+ if (!InternalLabel.Initialize(Label)) {
+ return FALSE;
+ }
+ } else {
+ Message->Set(MSG_VOLUME_LABEL_NO_MAX);
+ Message->Display("");
+ Message->QueryStringInput(&InternalLabel);
+ }
+
+ while( !IsValidLabel(&InternalLabel)) {
+
+ Message->Set(MSG_INVALID_LABEL_CHARACTERS);
+ Message->Display("");
+
+ Message->Set(MSG_VOLUME_LABEL_NO_MAX);
+ Message->Display("");
+ Message->QueryStringInput(&InternalLabel);
+ }
+
+ Message->Set( MSG_FMT_CREATING_FILE_SYSTEM );
+ Message->Display( "" );
+
+ // Create the elementary file system structures. Pass in
+ // zero for the initial log file size to indicate that
+ // CreateElementaryStructures should choose the size of
+ // the log file, and NULL for the OldBpb to indicate that
+ // it should use the geometry information from the drive.
+ //
+ if( !CreateElementaryStructures( &VolumeBitmap,
+ ClusterFactor,
+ FrsSize,
+ IndexBufferSize,
+ InitialLogFileSize,
+ BadSectors,
+ Message,
+ NULL,
+ &InternalLabel ) ) {
+
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+
+ if( !Write( Message ) ) {
+
+ DebugPrint( "UNTFS: Unable to write superarea.\n" );
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ // Write the rest of the boot code:
+ //
+ SectorSize = _drive->QuerySectorSize();
+
+ SectorsInBootArea = ( BYTES_IN_BOOT_AREA % SectorSize ) ?
+ BYTES_IN_BOOT_AREA / SectorSize + 1 :
+ BYTES_IN_BOOT_AREA / SectorSize;
+
+ if( !BootCodeMem.Initialize() ||
+ !BootCodeSecrun.Initialize( &BootCodeMem,
+ _drive,
+ 1,
+ SectorsInBootArea - 1 ) ) {
+
+ DebugPrint( "UNTFS: Unable to write boot code.\n" );
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ memcpy( BootCodeSecrun.GetBuf(),
+ (PUCHAR)NtfsBootCode + _drive->QuerySectorSize(),
+ sizeof( NtfsBootCode ) - _drive->QuerySectorSize() );
+
+ if( !BootCodeSecrun.Write( ) ) {
+
+ DebugPrint( "UNTFS: Unable to write boot code.\n" );
+ Message->Set( MSG_NTFS_FORMAT_FAILED );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+
+ if (!SetSystemId()) {
+ Message->Set(MSG_WRITE_PARTITION_TABLE);
+ Message->Display("");
+ return FALSE;
+ }
+
+ Message->Set(MSG_FORMAT_COMPLETE);
+ Message->Display("");
+
+ // -----------------------
+ // Generate a nice report.
+ // -----------------------
+ //
+ ClusterSize = ClusterFactor * _drive->QuerySectorSize();
+
+ KBytesInVolume = NumberOfClusters;
+ KBytesInVolume = KBytesInVolume * ClusterSize / 1024;
+
+ Message->Set(MSG_TOTAL_KILOBYTES);
+ Message->Display("%9d", KBytesInVolume.GetLowPart() );
+
+ Message->Set(MSG_AVAILABLE_KILOBYTES);
+ Message->Display("%9d",
+ ((ClusterSize * VolumeBitmap.QueryFreeClusters())/1024).GetLowPart() );
+
+ return TRUE;
+}
diff --git a/private/utils/untfs/src/frs.cxx b/private/utils/untfs/src/frs.cxx
new file mode 100644
index 000000000..c340bf749
--- /dev/null
+++ b/private/utils/untfs/src/frs.cxx
@@ -0,0 +1,5708 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ frs.cxx
+
+Abstract:
+
+ This module contains the member function definitions for the
+ NTFS_FILE_RECORD_SEGMENT class. This class models File
+ Record Segments in the NTFS Master File Table; it is the
+ object through which a file's attributes may be accessed.
+
+
+
+Author:
+
+ Bill McJohn (billmc) 21-June-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "untfs.hxx"
+#include "list.hxx"
+#include "numset.hxx"
+#include "ifssys.hxx"
+#include "cannedsd.hxx"
+#include "drive.hxx"
+#include "mft.hxx"
+#include "mftfile.hxx"
+#include "attrrec.hxx"
+#include "attrib.hxx"
+#include "attrlist.hxx"
+#include "frs.hxx"
+#include "badfile.hxx"
+#include "ntfsbit.hxx"
+#include "indxtree.hxx"
+#include "rtmsg.h"
+
+#include "hackwc.hxx"
+#include "sdchk.hxx"
+
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( NTFS_FILE_RECORD_SEGMENT, NTFS_FRS_STRUCTURE, UNTFS_EXPORT );
+
+
+UNTFS_EXPORT
+NTFS_FILE_RECORD_SEGMENT::~NTFS_FILE_RECORD_SEGMENT (
+ )
+{
+ Destroy();
+}
+
+VOID
+NTFS_FILE_RECORD_SEGMENT::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Worker method for NTFS_FILE_RECORD_SEGMENT construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _Mft = NULL;
+ _AttributeList = NULL;
+ _ChildIterator = NULL;
+}
+
+
+VOID
+NTFS_FILE_RECORD_SEGMENT::Destroy (
+ )
+/*++
+
+Routine Description:
+
+ Worker method for NTFS_FILE_RECORD_SEGMENT destruction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _Mft = NULL;
+
+ // If the child iterator is not NULL, then the list of children
+ // has been initialized.
+
+ if( _ChildIterator != NULL ) {
+
+ DELETE( _ChildIterator );
+ _Children.DeleteAllMembers();
+ }
+
+ DELETE(_AttributeList);
+ _AttributeList = NULL;
+}
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::Initialize(
+ IN VCN FileNumber,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft
+ )
+/*++
+
+Routine Description:
+
+ Initialize a File Record Segment object. Note that this will not
+ cause the FRS to be read.
+
+Arguments:
+
+ FileNumber -- Supplies the FRS's cluster number within the MFT.
+ Mft -- Supplies the volume MasterFile Table.
+
+Return Value:
+
+ TRUE upon successful completion
+
+Notes:
+
+ This class is reinitializable.
+
+--*/
+{
+ Destroy();
+
+ DebugAssert(Mft);
+
+ _Mft = Mft;
+
+ if( !Mft->GetDataAttribute() ||
+ !_Mem.Initialize() ||
+ !_Children.Initialize() ||
+ (_ChildIterator = _Children.QueryIterator()) == NULL ||
+ !NTFS_FRS_STRUCTURE::Initialize(&_Mem,
+ Mft->GetDataAttribute(),
+ FileNumber,
+ Mft->QueryClusterFactor(),
+ Mft->QueryVolumeSectors(),
+ Mft->QueryFrsSize(),
+ Mft->GetUpcaseTable() ) ) {
+ Destroy();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::Initialize(
+ IN VCN FileNumber,
+ IN OUT PNTFS_MFT_FILE MftFile
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes this class to a valid initial state.
+
+Arguments:
+
+ FileNumber - Supplies the file number for this FRS.
+ MftFile - Supplies the MFT file.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+Notes:
+
+ The upcase-table may be NULL; in this case, attributes with
+ names cannot be manipulated until the upcase table is set.
+
+--*/
+{
+ return Initialize(FileNumber,
+ MftFile->GetMasterFileTable());
+}
+
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::Initialize(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN LCN StartOfMft,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft
+ )
+/*++
+
+Routine Description:
+
+ Initialize a File Record Segment object. Note that this will not
+ cause the FRS to be read.
+
+Arguments:
+
+ Drive - Supplies the drive object.
+ StartOfMft - Supplies the starting cluster for the MFT.
+ Mft - Supplies the master file table.
+
+Return Value:
+
+ TRUE upon successful completion
+
+Notes:
+
+ This class is reinitializable.
+
+--*/
+{
+ Destroy();
+
+ DebugAssert(Mft);
+
+ _Mft = Mft;
+ _AttributeList = NULL;
+
+ return _Children.Initialize() &&
+ (_ChildIterator = _Children.QueryIterator()) != NULL &&
+ _Mem.Initialize() &&
+ NTFS_FRS_STRUCTURE::Initialize(&_Mem,
+ Drive,
+ StartOfMft,
+ Mft->QueryClusterFactor(),
+ Mft->QueryVolumeSectors(),
+ Mft->QueryFrsSize(),
+ Mft->GetUpcaseTable());
+}
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::Create (
+ IN USHORT Flags
+ )
+/*++
+
+Routine Description:
+
+ Create (i.e. Format) a file record segment. This is a private
+ worker method which is called by the other Create methods. It
+ creates a File Record Segment which has no attribute records.
+
+Arguments:
+
+ Flags -- Supplies the FILE_xxx flags which should be set in this
+ File Record Set. (Note that FILE_RECORD_SEGMENT_IN_USE
+ will also be set, whether or not is is specified.)
+
+Return value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ PATTRIBUTE_TYPE_CODE FirstAttribute;
+
+ DebugPtrAssert( _FrsData );
+
+ memset( _FrsData, 0, (UINT) QuerySize() );
+
+ _FrsData->Lsn.LowPart = 0;
+ _FrsData->Lsn.HighPart = 0;
+
+ _FrsData->SequenceNumber = (USHORT) max(QueryFileNumber().GetLowPart(),1);
+ _FrsData->ReferenceCount = 0;
+ _FrsData->Flags = FILE_RECORD_SEGMENT_IN_USE | Flags;
+ _FrsData->BytesAvailable = QuerySize();
+ _FrsData->NextAttributeInstance = 0;
+
+ memset( &_FrsData->BaseFileRecordSegment,
+ 0,
+ sizeof(MFT_SEGMENT_REFERENCE) );
+
+
+ // Write the 'FILE' signature in the MultiSectorHeader.
+
+ memcpy( _FrsData->MultiSectorHeader.Signature,
+ "FILE",
+ 4 );
+
+
+ // Compute the number of Update Sequence Numbers in the
+ // update array. This number is (see ntos\inc\cache.h):
+ //
+ // n/SEQUENCE_NUMBER_STRIDE + 1
+ //
+ // where n is the number of bytes in the protected structure
+ // (in this case, a cluster).
+
+ _FrsData->MultiSectorHeader.UpdateSequenceArraySize =
+ (USHORT)(QuerySize()/SEQUENCE_NUMBER_STRIDE + 1);
+
+ // The update sequence array starts at the field
+ // UpdateArrayForCreateOnly. (In other words, create locates
+ // it using this field, all other methods locate it using
+ // the offset that Create computes.)
+ //
+ _FrsData->MultiSectorHeader.UpdateSequenceArrayOffset =
+ FIELD_OFFSET( FILE_RECORD_SEGMENT_HEADER,
+ UpdateArrayForCreateOnly );
+
+ _FrsData->FirstAttributeOffset =
+ QuadAlign( _FrsData->MultiSectorHeader.UpdateSequenceArrayOffset +
+ _FrsData->MultiSectorHeader.UpdateSequenceArraySize *
+ sizeof( UPDATE_SEQUENCE_NUMBER ) );
+
+ // Make sure that the offset of the first attribute is in range:
+ //
+ if( _FrsData->FirstAttributeOffset + sizeof(ULONG) > QuerySize() ) {
+
+ return FALSE;
+ }
+
+ // Put an END attribute at the first-attribute offset. (Note
+ // that this attribute doesn't have an attribute header, it just
+ // consists of an Attribute Type Code of $END.)
+ //
+ FirstAttribute = (PATTRIBUTE_TYPE_CODE)
+ ((PBYTE)_FrsData +
+ _FrsData->FirstAttributeOffset);
+
+ *FirstAttribute = $END;
+
+ // The first free byte comes after the END attribute, which
+ // consists of a single ATTRIBUTE_TYPE_CODE.
+ //
+ _FrsData->FirstFreeByte = _FrsData->FirstAttributeOffset +
+ QuadAlign( sizeof( ATTRIBUTE_TYPE_CODE ) );
+
+ return TRUE;
+}
+
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::Create (
+ IN PCSTANDARD_INFORMATION StandardInformation,
+ IN USHORT Flags
+ )
+/*++
+
+Routine Description:
+
+ Create (i.e. Format) a base file record segment. The base
+ file record segment is the primary FRS for a file; it contains
+ any resident attributes (and hence any indexed attributes) of the
+ file and the External Attributes List, if any.
+
+ Note that Create will not cause the FRS to be written, only to
+ be formatted in memory.
+
+Arguments:
+
+ StandardInformation -- supplies the standard information for the
+ file record segment.
+ Flags -- Supplies the FILE_xxx flags which should
+ be set in this File Record Set. (Note
+ that FILE_RECORD_SEGMENT_IN_USE will also
+ be set, whether or not is is specified.)
+
+
+Return value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ NTFS_ATTRIBUTE StandardInfoAttribute;
+
+ DebugPtrAssert( _FrsData );
+
+ if( Create( Flags ) &&
+ StandardInfoAttribute.Initialize( GetDrive(),
+ QueryClusterFactor(),
+ StandardInformation,
+ sizeof( STANDARD_INFORMATION ),
+ $STANDARD_INFORMATION ) &&
+ StandardInfoAttribute.InsertIntoFile( this, NULL ) ) {
+
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+ }
+}
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::Create (
+ IN PCMFT_SEGMENT_REFERENCE BaseSegment,
+ IN USHORT Flags
+ )
+/*++
+
+Routine Description:
+
+ Create (i.e. Format) a secondary file record segment. A secondary
+ file record segment contains external attributes; it is referenced
+ in the file's External Attributes List, which is in the file's
+ base file record segment.
+
+Arguments:
+
+ BaseSegment -- supplies a reference to the base file
+ record segment for this file.
+ Flags -- Supplies the FILE_xxx flags which should
+ be set in this File Record Set. (Note
+ that FILE_RECORD_SEGMENT_IN_USE will also
+ be set, whether or not is is specified.)
+
+Return value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ DebugPtrAssert( _FrsData );
+
+ if( Create( Flags ) ) {
+
+ memcpy( &_FrsData->BaseFileRecordSegment,
+ BaseSegment,
+ sizeof(MFT_SEGMENT_REFERENCE) );
+
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+ }
+}
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::CreateSystemFile(
+ IN UCHAR major,
+ IN UCHAR minor
+ )
+/*++
+
+Routine Description:
+
+ This method creates a new base frs with a STANDARD_INFORMATION and
+ a FILE_NAME attribute. The standard info attribute will be
+ set to the current time.
+
+ This function looks up the correct file name base on this FRS's
+ file number.
+
+ This function will not succeed unless this FRS is a system file.
+
+ This function does not update the root index or write to the frs.
+
+Arguments:
+
+ major - the major revision number for the volume
+ minor - the minor revsion number for the volume
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ STANDARD_INFORMATION standard_info;
+ PFILE_NAME file_name;
+ UCHAR name_length;
+ ULONG buffer_length;
+ NTFS_FILE_RECORD_SEGMENT root_dir;
+ DSTRING file_name_text;
+ BOOLEAN r;
+ NTFS_INDEX_TREE root_index;
+ DSTRING index_name;
+ BOOLEAN no_file_name;
+ MFT_SEGMENT_REFERENCE root_ref;
+ BOOLEAN this_is_root;
+
+
+ // Figure out the correct file name for this.
+
+ no_file_name = FALSE;
+ r = TRUE;
+ this_is_root = FALSE;
+
+ if (QueryFileNumber() == MASTER_FILE_TABLE_NUMBER ) {
+ r = file_name_text.Initialize("$MFT");
+
+ } else if (QueryFileNumber() == MASTER_FILE_TABLE2_NUMBER ) {
+ r = file_name_text.Initialize("$MFTMirr");
+
+ } else if (QueryFileNumber() == LOG_FILE_NUMBER ) {
+ r = file_name_text.Initialize("$LogFile");
+
+ } else if (QueryFileNumber() == VOLUME_DASD_NUMBER ) {
+ r = file_name_text.Initialize("$Volume");
+
+ } else if (QueryFileNumber() == ATTRIBUTE_DEF_TABLE_NUMBER ) {
+ r = file_name_text.Initialize("$AttrDef");
+
+ } else if (QueryFileNumber() == ROOT_FILE_NAME_INDEX_NUMBER ) {
+ r = file_name_text.Initialize(".");
+ this_is_root = TRUE;
+
+ } else if (QueryFileNumber() == BIT_MAP_FILE_NUMBER ) {
+ r = file_name_text.Initialize("$BitMap");
+
+ } else if (QueryFileNumber() == BOOT_FILE_NUMBER ) {
+ r = file_name_text.Initialize("$Boot");
+
+ } else if (QueryFileNumber() == BAD_CLUSTER_FILE_NUMBER ) {
+ r = file_name_text.Initialize("$BadClus");
+
+ } else if (QueryFileNumber() == SECURITY_TABLE_NUMBER && major >= 2) {
+ r = file_name_text.Initialize("$Secure");
+
+ } else if (QueryFileNumber() == QUOTA_TABLE_NUMBER && major <= 1) {
+ r = file_name_text.Initialize("$Quota");
+
+ } else if (QueryFileNumber() == UPCASE_TABLE_NUMBER ) {
+ r = file_name_text.Initialize("$UpCase");
+
+ } else if (QueryFileNumber() == EXTEND_TABLE_NUMBER && major >= 2) {
+ r = file_name_text.Initialize("$Extend");
+
+ } else {
+ no_file_name = TRUE;
+ }
+
+ if (!r) {
+ return FALSE;
+ }
+
+ // Create a standard info structure.
+
+ memset(&standard_info, 0, sizeof(STANDARD_INFORMATION));
+
+ IFS_SYSTEM::QueryNtfsTime(&standard_info.CreationTime);
+
+ standard_info.LastModificationTime =
+ standard_info.LastChangeTime =
+ standard_info.LastAccessTime = standard_info.CreationTime;
+
+ standard_info.FileAttributes = FAT_DIRENT_ATTR_HIDDEN |
+ FAT_DIRENT_ATTR_SYSTEM;
+
+ if (!Create(&standard_info)) {
+ return FALSE;
+ }
+
+ if (!no_file_name) {
+
+ // Figure out the segment reference for the root index.
+
+ if (this_is_root) {
+ root_ref = QuerySegmentReference();
+ } else {
+
+ if (!root_dir.Initialize(ROOT_FILE_NAME_INDEX_NUMBER,
+ _Mft) ||
+ !root_dir.Read()) {
+
+ return FALSE;
+ }
+
+ root_ref = root_dir.QuerySegmentReference();
+ }
+
+
+ // Allocate a buffer of sufficient length for the FILE_NAME struct.
+
+ name_length = (UCHAR) file_name_text.QueryChCount();
+
+ buffer_length = FIELD_OFFSET(FILE_NAME, FileName) +
+ name_length*sizeof(WCHAR);
+
+ if (!(file_name = (PFILE_NAME) MALLOC(buffer_length))) {
+ return FALSE;
+ }
+ memset(file_name, 0, buffer_length);
+
+
+ // Initialize the FILE_NAME structure and add it to this FRS.
+
+ file_name->ParentDirectory = root_ref;
+ file_name->FileNameLength = name_length;
+ file_name->Flags = FILE_NAME_NTFS | FILE_NAME_DOS;
+ file_name_text.QueryWSTR(0,
+ TO_END,
+ file_name->FileName,
+ name_length,
+ FALSE);
+
+ if (!AddFileNameAttribute(file_name)) {
+
+ FREE(file_name);
+ return FALSE;
+ }
+
+ // Set the ref count back to zero because this guy doesn't yet
+ // exist in the root directory.
+
+ SetReferenceCount(0);
+
+ FREE(file_name);
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::CreateExtendSystemFile(
+ PCWSTRING file_name_text,
+ IN USHORT Flags
+ )
+/*++
+
+Routine Description:
+
+ This method creates a new base frs with a STANDARD_INFORMATION and
+ a FILE_NAME attribute. The standard info attribute will be
+ set to the current time. The parent of this frs is \$Extend.
+
+ This function does not update the root index or write to the frs.
+
+Arguments:
+
+ file_name_text
+ -- Supplies the file name.
+ Flags -- Supplies the FILE_xxx flags which should be set in this
+ File Record Set. (Note that FILE_RECORD_SEGMENT_IN_USE
+ will also be set, whether or not is is specified.)
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ STANDARD_INFORMATION standard_info;
+ PFILE_NAME file_name;
+ UCHAR name_length;
+ ULONG buffer_length;
+ NTFS_FILE_RECORD_SEGMENT root_dir;
+ NTFS_INDEX_TREE root_index;
+ DSTRING index_name;
+ BOOLEAN no_file_name;
+ MFT_SEGMENT_REFERENCE root_ref;
+
+ // Check file name
+
+ no_file_name = (!file_name_text || file_name_text->QueryChCount() == 0);
+
+ // Create a standard info structure.
+
+ memset(&standard_info, 0, sizeof(STANDARD_INFORMATION));
+
+ IFS_SYSTEM::QueryNtfsTime(&standard_info.CreationTime);
+
+ standard_info.LastModificationTime =
+ standard_info.LastChangeTime =
+ standard_info.LastAccessTime = standard_info.CreationTime;
+
+ standard_info.FileAttributes = FAT_DIRENT_ATTR_HIDDEN |
+ FAT_DIRENT_ATTR_SYSTEM |
+ FAT_DIRENT_ATTR_ARCHIVE |
+ DUP_VIEW_INDEX_PRESENT;
+
+ if (!Create(&standard_info, Flags)) {
+ return FALSE;
+ }
+
+ if (!no_file_name) {
+
+ // Figure out the segment reference for the root index.
+
+ if (!root_dir.Initialize(EXTEND_TABLE_NUMBER, _Mft) ||
+ !root_dir.Read()) {
+
+ return FALSE;
+ }
+
+ root_ref = root_dir.QuerySegmentReference();
+
+ // Allocate a buffer of sufficient length for the FILE_NAME struct.
+
+ name_length = (UCHAR) file_name_text->QueryChCount();
+
+ buffer_length = FIELD_OFFSET(FILE_NAME, FileName) +
+ name_length*sizeof(WCHAR);
+
+ if (!(file_name = (PFILE_NAME) MALLOC(buffer_length))) {
+ return FALSE;
+ }
+ memset(file_name, 0, buffer_length);
+
+
+ // Initialize the FILE_NAME structure and add it to this FRS.
+
+ file_name->ParentDirectory = root_ref;
+ file_name->FileNameLength = name_length;
+ file_name->Flags = FILE_NAME_NTFS | FILE_NAME_DOS;
+ file_name_text->QueryWSTR(0,
+ TO_END,
+ file_name->FileName,
+ name_length,
+ FALSE);
+
+ if (!AddFileNameAttribute(file_name)) {
+
+ FREE(file_name);
+ return FALSE;
+ }
+
+ // Set the ref count back to zero because this guy doesn't yet
+ // exist in the root directory.
+
+ SetReferenceCount(0);
+
+ FREE(file_name);
+ }
+
+ return TRUE;
+}
+
+
+NONVIRTUAL
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::VerifyAndFixFileNames(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN DiskErrorsFound,
+ IN BOOLEAN FixDupInfo
+ )
+/*++
+
+Routine Description:
+
+ This routine ensures that the duplicate information in the
+ file name attributes is correct. It otherwise corrects
+ these entries and outputs a message.
+
+ This method will also make sure that for every NTFS
+ file name there is a corresponding FAT file name with
+ the same parent pointer and that for every FAT file
+ name there is a corresponding NTFS file name with the
+ same parent pointer.
+
+Arguments:
+
+ CurrentDirectory - Supplies the directory to which this
+ file belongs.
+ VolumeBitmap - Supplies the volume bitmap.
+ FixLevel - Supplies the fix up level.
+ Message - Supplies an outlet for messages.
+ DiskErrorsFound - Supplies whether or not disk errors have been
+ found.
+ DontFixDupInfo - Supplies whether or not to fix incorrect
+ duplicated information.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_ATTRIBUTE attribute;
+ ULONG i;
+ BOOLEAN error;
+ DUPLICATED_INFORMATION actual_info;
+ PSTANDARD_INFORMATION pstandard;
+ EA_INFORMATION ea_info;
+ PFILE_NAME pfile_name;
+ ULONG num_bytes;
+ BOOLEAN index_present;
+ DSTRING index_name;
+ MFT_SEGMENT_REFERENCE parent_for_dos_name;
+ BOOLEAN ntfs_name_encountered;
+ BOOLEAN dos_name_encountered;
+ BOOLEAN flags_mod;
+ BOOLEAN success;
+ HMEM hmem;
+ ULONG value_length, cluster_size;
+ PINDEX_ROOT index_root;
+
+
+ // First check the validity of the FILE_FILE_NAME_INDEX_PRESENT bit.
+
+ if (!index_name.Initialize(FileNameIndexNameData)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ error = FALSE;
+ index_present = QueryAttribute(&attribute, &error, $INDEX_ROOT,
+ &index_name);
+
+
+ // Make sure that if the $INDEX_ROOT is present then
+ // that it is also valid enough so that it won't be tubed.
+
+ if (index_present) {
+
+ value_length = attribute.QueryValueLength().GetLowPart();
+
+ if (error || !hmem.Acquire(value_length)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!attribute.Read(hmem.GetBuf(), 0, value_length, &num_bytes) ||
+ num_bytes != value_length ||
+ value_length < sizeof(INDEX_ROOT) ||
+ !(index_root = (PINDEX_ROOT) hmem.GetBuf()) ||
+ index_root->IndexHeader.FirstIndexEntry < sizeof(INDEX_HEADER)) {
+
+ index_present = FALSE;
+ }
+
+ // If our cluster size is greater than the index buffer size,
+ // the ClustersPerIndexBuffer in the index root should reflect
+ // a 512-byte block size.
+ //
+
+ if (index_present) {
+
+ ULONG cluster_size = QueryClusterFactor() * GetDrive()->QuerySectorSize();
+
+ if (index_root->BytesPerIndexBuffer < cluster_size &&
+ ULONG(index_root->ClustersPerIndexBuffer * NTFS_INDEX_BLOCK_SIZE) !=
+ index_root->BytesPerIndexBuffer) {
+
+ DebugPrintf("VerifyAndFixFileNames: %x %x %x\n",
+ index_root->BytesPerIndexBuffer, index_root->ClustersPerIndexBuffer,
+ cluster_size);
+
+ index_present = FALSE;
+ }
+ }
+ }
+
+
+ if ((IsIndexPresent() && !index_present) ||
+ (!IsIndexPresent() && index_present)) {
+
+ index_present ? SetIndexPresent() : ClearIndexPresent();
+
+ Message->Set(MSG_CHK_NTFS_MINOR_CHANGES_TO_FRS);
+ Message->Display("%d", QueryFileNumber().GetLowPart());
+
+ if (DiskErrorsFound) {
+ *DiskErrorsFound = TRUE;
+ }
+
+ if (FixLevel != CheckOnly && !Flush(VolumeBitmap)) {
+ DebugAbort("Can't write it out");
+ return FALSE;
+ }
+ }
+
+
+ if (FixDupInfo) {
+
+ // First build up a correct 'duplicated_information' structure.
+
+ memset(&actual_info, 0, sizeof(DUPLICATED_INFORMATION));
+
+ if (!QueryAttribute(&attribute, &error, $STANDARD_INFORMATION) ||
+ !(pstandard = (PSTANDARD_INFORMATION) attribute.GetResidentValue())) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ actual_info.CreationTime = pstandard->CreationTime;
+ actual_info.LastModificationTime = pstandard->LastModificationTime;
+ actual_info.LastChangeTime = pstandard->LastChangeTime;
+ actual_info.LastAccessTime = pstandard->LastAccessTime;
+ actual_info.FileAttributes = pstandard->FileAttributes;
+
+ if (index_present) {
+ actual_info.FileAttributes |= DUP_FILE_NAME_INDEX_PRESENT;
+ }
+
+ error = FALSE;
+ if (QueryAttribute(&attribute, &error, $EA_INFORMATION) &&
+ attribute.Read(&ea_info, 0, sizeof(EA_INFORMATION), &num_bytes) &&
+ num_bytes == sizeof(EA_INFORMATION)) {
+
+ actual_info.PackedEaSize = ea_info.PackedEaSize;
+ } else if (error) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (QueryAttribute(&attribute, &error, $DATA)) {
+
+ // Note that for a nonresident $DATA attribute, the
+ // allocated length in the duplicated information is
+ // the amount of disk space actually taken up by the
+ // unnamed data attribute, rather than its allocated
+ // size.
+ //
+ cluster_size = QueryClusterFactor() * GetDrive()->QuerySectorSize();
+ actual_info.AllocatedLength =
+ attribute.IsResident() ?
+ attribute.QueryAllocatedLength():
+ attribute.QueryClustersAllocated()*cluster_size;
+ actual_info.FileSize = attribute.QueryValueLength();
+ } else if (error) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+
+
+ // Now go through the file name attributes and make sure that
+ // they have the correct duplicated information. Also insure
+ // consistency of DOS and NTFS bits set.
+
+ dos_name_encountered = FALSE;
+ ntfs_name_encountered = FALSE;
+ flags_mod = FALSE;
+
+ for (i = 0; QueryAttributeByOrdinal(&attribute,
+ &error,
+ $FILE_NAME,
+ i);) {
+
+ pfile_name = (PFILE_NAME) attribute.GetResidentValue();
+
+ if (!pfile_name) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+
+ if (FixDupInfo) {
+
+ // Validate the duplicate information.
+
+ if (memcmp(&pfile_name->Info, &actual_info,
+ sizeof(DUPLICATED_INFORMATION))) {
+
+// No need to be verbal about this fix, since the duplicate information
+// in the file name attribute is not maintained by the file system.
+
+#if 0
+ Message->Set(MSG_CHK_NTFS_INACCURATE_DUPLICATED_INFORMATION);
+ Message->Display("%d", QueryFileNumber().GetLowPart());
+#endif
+
+ if (!UpdateFileNames(&actual_info, NULL, FALSE)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (DiskErrorsFound) {
+ *DiskErrorsFound = TRUE;
+ }
+
+ if (FixLevel != CheckOnly && !Flush(VolumeBitmap)) {
+ DebugAbort("Can't flush out changes");
+ return FALSE;
+ }
+
+ i = 0;
+ continue;
+ }
+ }
+
+
+ // Make sure there's only one NTFS name and that it's in the
+ // same directory as the corresponding DOS name.
+
+ if (pfile_name->Flags & FILE_NAME_NTFS) {
+
+ if (ntfs_name_encountered) {
+ flags_mod = TRUE;
+ } else {
+ ntfs_name_encountered = TRUE;
+ if (dos_name_encountered) {
+ if (!(parent_for_dos_name == pfile_name->ParentDirectory)) {
+ flags_mod = TRUE;
+ }
+ } else {
+ parent_for_dos_name = pfile_name->ParentDirectory;
+ }
+ }
+ }
+
+
+ // Make sure there's only one DOS name and that it's in the
+ // same directory as the corresponding NTFS name.
+
+ if (pfile_name->Flags & FILE_NAME_DOS) {
+
+ if (dos_name_encountered || !NTFS_SA::IsDosName(pfile_name)) {
+ flags_mod = TRUE;
+ } else {
+ dos_name_encountered = TRUE;
+ if (ntfs_name_encountered) {
+ if (!(parent_for_dos_name == pfile_name->ParentDirectory)) {
+ flags_mod = TRUE;
+ }
+ } else {
+ parent_for_dos_name = pfile_name->ParentDirectory;
+ }
+ }
+ }
+
+ i++;
+ }
+
+
+ // Make sure DOS name iff NTFS name.
+
+ if (dos_name_encountered && !ntfs_name_encountered ||
+ !dos_name_encountered && ntfs_name_encountered) {
+
+ flags_mod = TRUE;
+ }
+
+
+ if (flags_mod) {
+
+ // There were some flags errors so clear all the flags.
+
+ for (i = 0; QueryAttributeByOrdinal(&attribute,
+ &error,
+ $FILE_NAME,
+ i);) {
+
+ pfile_name = (PFILE_NAME) attribute.GetResidentValue();
+
+ if (pfile_name->Flags & FILE_NAME_DOS ||
+ pfile_name->Flags & FILE_NAME_NTFS) {
+
+ DeleteResidentAttribute($FILE_NAME, NULL, pfile_name,
+ attribute.QueryValueLength().GetLowPart(), &success);
+
+ // Clear the flags.
+
+ pfile_name->Flags &= ~(FILE_NAME_DOS | FILE_NAME_NTFS);
+
+ if (!attribute.InsertIntoFile(this, VolumeBitmap)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ i = 0;
+ continue;
+ }
+
+ i++;
+ }
+ }
+
+
+ // Commit any flag changes to disk.
+
+ if (flags_mod) {
+
+ Message->Set(MSG_CHK_NTFS_MINOR_FILE_NAME_ERRORS);
+ Message->Display("%d", QueryFileNumber().GetLowPart());
+
+ if (FixLevel != CheckOnly && !Flush(VolumeBitmap)) {
+ DebugAbort("Can't flush out changes");
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::AddDataAttribute(
+ IN ULONG InitialSize,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN BOOLEAN Fill,
+ IN CHAR FillCharacter
+ )
+/*++
+
+Routine Description:
+
+ This method adds a nonresident data attribute to the File Record Segment.
+
+Arguments:
+
+ InitialSize -- Supplies the number of bytes to allocate for
+ the data attribute.
+ VolumeBitmap -- Supplies the volume bitmap.
+ Fill -- Supplies a flag which, if TRUE, indicates that
+ the value of the attribute should be set to
+ the supplied fill character.
+ FillCharacter -- Supplies a fill character.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ NTFS_ATTRIBUTE DataAttribute;
+ NTFS_EXTENT_LIST Extents;
+
+ // Initialize the data attribute [type is $DATA, no name] with an
+ // empty extent list, and then resize it to the desired size.
+
+ if( !Extents.Initialize( 0, 0 ) ||
+ !DataAttribute.Initialize( GetDrive(),
+ QueryClusterFactor(),
+ &Extents,
+ 0,
+ 0,
+ $DATA,
+ NULL ) ||
+ !DataAttribute.Resize( InitialSize, VolumeBitmap ) ) {
+
+ return FALSE;
+ }
+
+ if( Fill &&
+ !DataAttribute.Fill( 0, FillCharacter ) ) {
+
+ return FALSE;
+ }
+
+ // Insert the data attribute into this File Record Segment. If that
+ // operation fails, we need to free up the space allocated by
+ // resizing the attribute back to zero.
+
+ if( !DataAttribute.InsertIntoFile( this, VolumeBitmap ) ) {
+
+ DataAttribute.Resize( 0, VolumeBitmap );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::AddFileNameAttribute(
+ IN PFILE_NAME FileName
+ )
+/*++
+
+Routine Description:
+
+ This method adds a File Name attribute to the File Record Segment.
+ Note that it assumes that the File Name is indexed.
+
+Arguments:
+
+ FileName -- Supplies the value of the File Name attribute, which
+ is a FILE_NAME structure.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ NTFS_ATTRIBUTE FileNameAttribute;
+
+ // Initialize a file-name attribute and insert it into this FRS.
+
+ if( FileNameAttribute.Initialize( GetDrive(),
+ QueryClusterFactor(),
+ FileName,
+ NtfsFileNameGetLength( FileName ),
+ $FILE_NAME ) ) {
+
+ FileNameAttribute.SetIsIndexed();
+
+ return( FileNameAttribute.InsertIntoFile( this, NULL ) );
+
+ } else {
+
+ return FALSE;
+ }
+}
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::AddAttribute(
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCWSTRING Name,
+ IN PCVOID Value,
+ IN ULONG Length,
+ IN OUT PNTFS_BITMAP Bitmap,
+ IN BOOLEAN IsIndexed
+ )
+/*++
+
+Routine Description:
+
+ This method adds an attribute of the specified type to the file.
+
+Arguments:
+
+ Type -- Supplies the type of the attribute.
+ Name -- Supplies the name of the attribute--may be NULL,
+ which is interpreted as no name.
+ Value -- Supplies a pointer to the attribute's value. May
+ be NULL if the attribute value length is zero.
+ Length -- Supplies the length of the attribute value.
+ Bitmap -- Supplies the volume bitmap. May be NULL,
+ in which case the attribute cannot be made
+ nonresident.
+ IsIndexed -- Supplies a flag which indicates whether the
+ attribute is indexed.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ NTFS_ATTRIBUTE Attribute;
+
+ // Initialize a resident attribute with the desired
+ // characteristics. If it is to be indexed, mark
+ // it as such.
+ //
+ if( !Attribute.Initialize( GetDrive(),
+ QueryClusterFactor(),
+ Value,
+ Length,
+ Type,
+ Name ) ) {
+
+ return FALSE;
+ }
+
+ if( IsIndexed ) {
+
+ Attribute.SetIsIndexed();
+ }
+
+ // Insert the attribute into the file. If it cannot be inserted
+ // as a resident attribute, make it non-resident and try again.
+ //
+ if( Attribute.InsertIntoFile( this, NULL ) ) {
+
+ // Success!
+ //
+ return TRUE;
+ }
+
+ // Couldn't insert it as a resident attribute; if it isn't
+ // indexed, make it nonresident and try again. Note that
+ // we can't make it nonresident if the client did not provide
+ // a bitmap, and that indexed attributes cannot be made
+ // nonresident.
+ //
+ if( !IsIndexed &&
+ Bitmap != NULL &&
+ Attribute.MakeNonresident( Bitmap ) &&
+ Attribute.InsertIntoFile( this, Bitmap ) ) {
+
+ // Second time lucky.
+ //
+ return TRUE;
+ }
+
+ // Can't insert this attribute into this FRS. If the attribute
+ // is nonresident, truncate it to zero length to free up the
+ // space allocated to it.
+ //
+ if( !Attribute.IsResident() ) {
+
+ DebugPtrAssert( Bitmap );
+ Attribute.Resize( 0, Bitmap );
+ }
+
+ // return failure.
+ //
+ return FALSE;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::AddSecurityDescriptor(
+ IN CANNED_SECURITY_TYPE SecurityType,
+ IN OUT PNTFS_BITMAP Bitmap
+ )
+/*++
+
+Routine Description:
+
+ This method adds a security descriptor, chosen from the
+ canned security descriptors, to the file.
+
+Arguments:
+
+ SecurityType -- Identifies the sort of security descriptor
+ to add.
+ Bitmap -- Supplies the volume bitmap.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ PCANNED_SECURITY CannedSecurity;
+ PVOID SecurityDescriptor;
+ ULONG SdLength;
+
+#if defined( _SETUP_LOADER_ )
+
+ // Security descriptors are not supported under the
+ // setup loader.
+ //
+ return TRUE;
+
+#else
+
+ if( (CannedSecurity = IFS_SYSTEM::GetCannedSecurity()) == NULL ||
+ (SecurityDescriptor =
+ CannedSecurity->GetCannedSecurityDescriptor( SecurityType,
+ &SdLength ))
+ == NULL ) {
+
+ DebugPrint( "UNTFS: Canned security is not available.\n" );
+ return TRUE;
+ }
+
+ return( AddAttribute( $SECURITY_DESCRIPTOR,
+ NULL,
+ SecurityDescriptor,
+ SdLength,
+ Bitmap ) );
+
+#endif // _SETUP_LOADER_
+
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::AddSecurityDescriptorData(
+ IN PNTFS_ATTRIBUTE Attribute,
+ IN OUT PVOID Buffer,
+ OUT PSECURITY_ENTRY *SecurityEntry,
+ IN ULONG SecurityId,
+ IN CANNED_SECURITY_TYPE SecurityType,
+ IN OUT PNTFS_BITMAP Bitmap,
+ IN BOOLEAN FixLevel
+ )
+/*++
+
+Routine Description:
+
+ This method adds a default security descriptor entry to the
+ end of the security descriptor data stream. This routine assumes
+ that the security descriptor data stream has been checked out
+ or corrected.
+
+ A flush of the frs is required to commit changes onto disk.
+
+Arguments:
+
+ Attribute -- supplies the attribute.
+ Buffer -- work buffer of SecurityDescriptorsBlockSize.
+ SecurityEntry -- returns a pointer into the working buffer where the
+ security entry lies.
+ SecurityId -- supplies the security id.
+ SecurityType -- Identifies the sort of security descriptor to add.
+ Bitmap -- Supplies the volume bitmap.
+ FixLevel -- Supplies a flag which, if equals to CheckOnly, indicates
+ that this method should not actually modify the
+ security descriptor data stream on disk.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ PCANNED_SECURITY cannedSecurity;
+ PVOID securityDescriptor;
+ ULONG sdLength;
+ ULONG num_bytes = 0;
+ ULONG bytesWritten;
+ ULONG length, length1, length2, offset, pad1_size;
+
+ SECURITY_DESCRIPTOR_HEADER sdh;
+
+#if defined( _SETUP_LOADER_ )
+
+ // Security descriptors are not supported under the
+ // setup loader.
+ //
+ return TRUE;
+
+#else
+
+ if( (cannedSecurity = IFS_SYSTEM::GetCannedSecurity()) == NULL ||
+ (securityDescriptor =
+ cannedSecurity->GetCannedSecurityDescriptor( SecurityType,
+ &sdLength ))
+ == NULL ) {
+
+ DebugPrint( "UNTFS: Canned security is not available.\n" );
+ return FALSE;
+ }
+
+ length = Attribute->QueryValueLength().GetLowPart();
+ if (length < SecurityDescriptorsBlockSize) {
+
+ // this should not occur if the data stream has been checked
+
+ if (FixLevel != CheckOnly) // if stream has been corrected
+ return FALSE; // then we got bad news
+
+ // If in read-only mode, then fake the length and continue
+
+ length = SecurityDescriptorsBlockSize;
+ }
+
+ length -= SecurityDescriptorsBlockSize;
+ offset = length & ~(SecurityDescriptorsBlockSize-1);
+
+ length1 = length & (SecurityDescriptorsBlockSize-1);
+ pad1_size = ((length1 + 0xf) & ~0xf) - length1;
+
+ length2 = sizeof(SECURITY_DESCRIPTOR_HEADER)+sdLength;
+
+ sdh.Length = length2;
+ sdh.HashKey.SecurityId = SecurityId;
+ sdh.HashKey.Hash = ComputeSecurityDescriptorHash(securityDescriptor,
+ sdLength);
+
+ if (length1 + pad1_size + length2 <= SecurityDescriptorsBlockSize) {
+ // everything fits into the current block
+ memset(Buffer, 0, pad1_size);
+ sdh.Offset = length + pad1_size;
+ *SecurityEntry = (PSECURITY_ENTRY)((PCHAR)Buffer+pad1_size);
+ memcpy((PVOID)*SecurityEntry,
+ &sdh,
+ sizeof(SECURITY_DESCRIPTOR_HEADER));
+ memcpy(&((*SecurityEntry)->security),
+ securityDescriptor,
+ sdLength);
+ offset += length1;
+ length = pad1_size + length2;
+ } else if (length1 + pad1_size +
+ sizeof(SECURITY_DESCRIPTOR_HEADER) <=
+ SecurityDescriptorsBlockSize) {
+ // add End of Block marker then
+ // goto next block and add the security descriptor
+ memset(Buffer, 0, pad1_size);
+ MarkEndOfSecurityDescriptorsBlock(
+ (PSECURITY_ENTRY)((PCHAR)Buffer+pad1_size),
+ SecurityDescriptorsBlockSize - length1 - pad1_size);
+ length = SecurityDescriptorsBlockSize - length1;
+ if (FixLevel != CheckOnly &&
+ (!Attribute->Write(Buffer,
+ length1,
+ length,
+ &bytesWritten,
+ Bitmap) ||
+ bytesWritten != length)) {
+ return FALSE;
+ }
+ offset += (SecurityDescriptorsBlockSize<<1);
+ sdh.Offset = offset;
+ *SecurityEntry = (PSECURITY_ENTRY)Buffer;
+ memcpy(*SecurityEntry, &sdh, sizeof(SECURITY_DESCRIPTOR_HEADER));
+ memcpy(&((*SecurityEntry)->security),
+ securityDescriptor,
+ sdLength);
+ length = length2;
+ } else if ((length1 == SecurityDescriptorsBlockSize) ||
+ (length1 + pad1_size == SecurityDescriptorsBlockSize)) {
+ // goto next block and add the security descriptor
+ offset += (SecurityDescriptorsBlockSize<<1);
+ sdh.Offset = offset;
+ *SecurityEntry = (PSECURITY_ENTRY)Buffer;
+ memcpy(*SecurityEntry, &sdh, sizeof(SECURITY_DESCRIPTOR_HEADER));
+ memcpy(&((*SecurityEntry)->security),
+ securityDescriptor,
+ sdLength);
+ length = length2;
+ } else {
+ // move the last security descriptor to the beginning
+ // of next block then append the new security descriptor
+ *SecurityEntry = NULL;
+ DebugAssert(FALSE);
+ return FALSE;
+ }
+
+ if (FixLevel != CheckOnly &&
+ (!Attribute->Write(Buffer,
+ offset,
+ length,
+ &bytesWritten,
+ Bitmap) ||
+ bytesWritten != length ||
+ !Attribute->Write(Buffer,
+ offset + SecurityDescriptorsBlockSize,
+ length,
+ &bytesWritten,
+ Bitmap) ||
+ bytesWritten != length)) {
+ return FALSE;
+ }
+ if (FixLevel != CheckOnly && Attribute->IsStorageModified() &&
+ !Attribute->InsertIntoFile(this, Bitmap)) {
+ return FALSE;
+ }
+
+ return TRUE;
+
+#endif // _SETUP_LOADER_
+
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::IsAttributePresent (
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCWSTRING Name,
+ IN BOOLEAN IgnoreExternal
+ )
+/*++
+
+Routine Description:
+
+ This function determines whether a specified attribute is present
+ in the attributes associated with the File Record Segment.
+
+Arguments:
+
+ Type -- supplies the type code of the attribute in question.
+ Name -- supplies the name of the attribute in question.
+ (may be NULL, in which case the attribute has no name.)
+ IgnoreExternal -- supplies a flag indicating that the FRS should
+ not look for external attributes.
+
+Return Value:
+
+ TRUE if the File Record Segment has an attribute which matches
+ the type (and name, if given).
+
+Notes:
+
+ This method assumes that the file record segment is consistent,
+ and that it has been read.
+
+ Note that we can determine what attribute records are present,
+ and whether they are unique, without reading the child FRS's,
+ since the information we need is in the Attribute List.
+
+ The NoExternal flag is provided mainly to allow us to check for
+ the presence of the ATTRIBUTES_LIST attribute without falling
+ into infinite recursion.
+
+--*/
+{
+ ULONG CurrentRecordOffset;
+ NTFS_ATTRIBUTE_RECORD CurrentRecord;
+ NTFS_ATTRIBUTE AttributeList;
+ BOOLEAN Found = FALSE;
+
+ DebugPtrAssert( _FrsData );
+
+ if( !IgnoreExternal &&
+ Type != $ATTRIBUTE_LIST &&
+ (_AttributeList != NULL ||
+ IsAttributePresent( $ATTRIBUTE_LIST, NULL, TRUE )) ) {
+
+ // This File Record Segment has an ATTRIBUTE_LIST attribute,
+ // and the caller wants to include external attributes, so
+ // we can traverse that list.
+
+ if( !SetupAttributeList() ) {
+
+ return FALSE;
+ }
+
+ return( _AttributeList->IsInList( Type, Name ) );
+
+ } else {
+
+ // Either the caller has asked us to ignore external
+ // attributes or there is no ATTRIBUTE_LIST attribute,
+ // or we're looking for the attribute list itself,
+ // so we'll go through the list of attribute records
+ // in this File Record Segment.
+
+ CurrentRecordOffset = _FrsData->FirstAttributeOffset;
+
+ while( CurrentRecordOffset < QuerySize() &&
+ CurrentRecord.
+ Initialize( (PBYTE)_FrsData + CurrentRecordOffset,
+ QuerySize() - CurrentRecordOffset ) &&
+ CurrentRecord.QueryTypeCode() != $END ) {
+
+ if( CurrentRecord.IsMatch( Type, Name ) ) {
+
+ Found = TRUE;
+ break;
+ }
+
+ // If this record has a zero length, then this FRS
+ // is corrupt. Otherwise, just go on to the next
+ // attribute record.
+ //
+ if( CurrentRecord.QueryRecordLength() == 0 ) {
+ Found = FALSE;
+ break;
+ }
+
+ CurrentRecordOffset += CurrentRecord.QueryRecordLength();
+ }
+ }
+
+ return Found;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::QueryAttribute (
+ OUT PNTFS_ATTRIBUTE Attribute,
+ OUT PBOOLEAN Error,
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCWSTRING Name
+ )
+/*++
+
+Routine Description:
+
+ This function fetches an attribute associated with the
+ File Record Segment.
+
+ This method cannot be used to fetch the ATTRIBUTE_LIST attribute.
+
+Arguments:
+
+ Attribute -- Receives (ie. is initialized to) the attribute. Note
+ that this parameter may be uninitialized on entry, and
+ may be left uninitialized if this method fails.
+ Error -- Receives TRUE if the method fails because of an error.
+ Type -- Supplies the type of the desired attribute
+ Name -- Supplies the name of the desired attribute (NULL if
+ the attribute has no name).
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ If the method returns TRUE, *Error should be ignored. If it
+ returns FALSE, *Error will be set to TRUE if the failure resulted
+ from an error (out of memory, corrupt structure); otherwise, the
+ caller may assume that the attribute is not present.
+
+ This method will check both internal and external attributes,
+ reading child File Record Segments as necessary to access their
+ attribute records.
+
+--*/
+{
+ MFT_SEGMENT_REFERENCE SegmentReference;
+ NTFS_ATTRIBUTE_RECORD Record;
+ PNTFS_FILE_RECORD_SEGMENT ChildFrs = NULL;
+ VCN TargetFileNumber;
+ ULONG Index;
+ ATTRIBUTE_TYPE_CODE FetchType;
+ VCN LowestVcn;
+ DSTRING FetchName;
+ USHORT Instance;
+
+ DebugPtrAssert( Attribute );
+ DebugPtrAssert( Error );
+
+ DebugPtrAssert( _FrsData );
+
+ // Assume innocent until proven guilty:
+
+ *Error = FALSE;
+
+ // This method cannot be used to fetch the ATTRIBUTE_LIST
+ // attribute.
+
+ if( Type == $ATTRIBUTE_LIST ) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ if( !IsAttributePresent( Type, Name, FALSE ) ) {
+
+ // there is no matching attribute.
+
+ return FALSE;
+ }
+
+ // Now that we've determined that the attribute is present,
+ // this method can only fail because of an error.
+
+ *Error = TRUE;
+
+
+ if( !SetupAttributeList() ) {
+
+ return FALSE;
+ }
+
+
+ // Get the TargetFileNumber.
+
+ if ( _AttributeList ) {
+
+ if (!_AttributeList->QueryExternalReference( Type,
+ &SegmentReference,
+ &Index,
+ Name )) {
+
+ return FALSE;
+ }
+
+ // We've found the first entry in the Attribute List
+ // for this attribute. We'll use that entry to
+ // initialize the attribute object. But first,
+ // we have to find it...
+
+ TargetFileNumber.Set( SegmentReference.LowPart,
+ (LONG) SegmentReference.HighPart );
+
+ } else {
+
+ TargetFileNumber = QueryFileNumber();
+ }
+
+
+ // Get the first attribute record.
+
+ if ( TargetFileNumber == QueryFileNumber() ) {
+
+ if (!QueryAttributeRecord(&Record, Type, Name)) {
+
+ return FALSE;
+ }
+
+ } else {
+
+ // The record we want is in a child record segment.
+ // Fetch the child. (Note that SetupChild will construct
+ // an FRS for the child and read it, if it's not already
+ // in the list of children.)
+
+ if( (ChildFrs = SetupChild( TargetFileNumber )) == NULL ) {
+
+ return FALSE;
+ }
+
+ if (!ChildFrs->QueryAttributeRecord(&Record, Type, Name)) {
+
+ return FALSE;
+ }
+ }
+
+
+ // Initialize the Attribute with the first attribute record.
+
+ if ( !Attribute->Initialize( GetDrive(),
+ QueryClusterFactor(),
+ &Record ) ) {
+
+ return FALSE;
+ }
+
+ if( Attribute->IsResident() ) {
+
+ // A resident attribute can only have one attribute record;
+ // since we've found it, we can return now.
+ //
+ *Error = FALSE;
+ return TRUE;
+ }
+
+ // Add any other attribute records to the attribute.
+
+ for (Index++;
+ _AttributeList &&
+ _AttributeList->QueryEntry(Index,
+ &FetchType,
+ &LowestVcn,
+ &SegmentReference,
+ &Instance,
+ &FetchName) &&
+ FetchType == Type &&
+ ((!Name && !FetchName.QueryChCount()) ||
+ (Name && !Name->Strcmp(&FetchName)));
+ Index++) {
+
+ TargetFileNumber.Set( SegmentReference.LowPart,
+ (LONG) SegmentReference.HighPart );
+
+
+ // Get attribute record from file record segment.
+
+ if ( TargetFileNumber == QueryFileNumber() ) {
+
+ if (!QueryAttributeRecord(&Record, Type, Name)) {
+
+ return FALSE;
+ }
+
+ } else {
+
+ // The record we want is in a child record segment.
+ // Fetch the child. (Note that SetupChild will construct
+ // an FRS for the child and read it, if it's not already
+ // in the list of children.)
+ //
+ if( (ChildFrs = SetupChild( TargetFileNumber )) == NULL ) {
+
+ return FALSE;
+
+ }
+
+ if (!ChildFrs->QueryAttributeRecord(&Record, Type, Name)) {
+
+ return FALSE;
+ }
+ }
+
+
+ // Add attribute record to attribute.
+
+ if (!Attribute->AddAttributeRecord(&Record)) {
+
+ DebugAbort("Couldn't do an Add attribute record.");
+ return FALSE;
+ }
+
+ }
+
+ *Error = FALSE;
+ return TRUE;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::QueryFileSizes (
+ OUT PBIG_INT AllocatedLength,
+ OUT PBIG_INT FileSize,
+ OUT PBOOLEAN Error
+ )
+/*++
+
+Routine Description:
+
+ This function fetches the allocated length and file size of a
+ file associated with a base File Record Segment.
+
+Arguments:
+
+ AllocatedLength -- receives the allocated length of the file.
+ FileSize -- receives the valid length of the file.
+ Error -- receives TRUE if the method fails because of an error.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ If the method returns TRUE, *Error should be ignored. If it
+ returns FALSE, *Error will be set to TRUE if the failure resulted
+ from an error (out of memory, corrupt structure); otherwise, the
+ caller may assume that the attribute is not present.
+
+ This method will check both internal and external attributes,
+ reading child File Record Segments as necessary to access their
+ attribute records.
+
+ Please note that the file size and allocated length of the file
+ is entire in the base frs or the first child frs. There is no
+ need to read in all the child frs in order to compute the desired
+ values.
+
+--*/
+{
+ NTFS_ATTRIBUTE Attribute;
+ ULONG ClusterSize;
+ BIG_INT TotalAllocated;
+ MFT_SEGMENT_REFERENCE SegmentReference;
+ NTFS_ATTRIBUTE_RECORD Record;
+ PNTFS_FILE_RECORD_SEGMENT ChildFrs = NULL;
+ VCN TargetFileNumber;
+ ULONG Index;
+ ATTRIBUTE_TYPE_CODE FetchType;
+ VCN LowestVcn;
+ DSTRING FetchName;
+ USHORT Instance;
+
+ DebugPtrAssert( Error );
+
+ DebugPtrAssert( _FrsData );
+
+ // Assume innocent until proven guilty:
+
+ *Error = FALSE;
+
+ // This method cannot be used to fetch the ATTRIBUTE_LIST
+ // attribute.
+
+ if( !IsAttributePresent( $DATA, NULL, FALSE ) ) {
+
+ // there is no matching attribute.
+
+ return FALSE;
+ }
+
+ // Now that we've determined that the attribute is present,
+ // this method can only fail because of an error.
+
+ *Error = TRUE;
+
+
+ if( !SetupAttributeList() ) {
+
+ return FALSE;
+ }
+
+
+ // Get the TargetFileNumber.
+
+ if ( _AttributeList ) {
+
+ if (!_AttributeList->QueryExternalReference( $DATA,
+ &SegmentReference,
+ &Index,
+ NULL )) {
+
+ return FALSE;
+ }
+
+ // We've found the first entry in the Attribute List
+ // for this attribute. We'll use that entry to
+ // initialize the attribute object. But first,
+ // we have to find it...
+
+ TargetFileNumber.Set( SegmentReference.LowPart,
+ (LONG) SegmentReference.HighPart );
+
+ } else {
+
+ TargetFileNumber = QueryFileNumber();
+ }
+
+
+ // Get the first attribute record.
+
+ if ( TargetFileNumber == QueryFileNumber() ) {
+
+ if (!QueryAttributeRecord(&Record, $DATA, NULL)) {
+
+ return FALSE;
+ }
+
+ } else {
+
+ // The record we want is in a child record segment.
+ // Fetch the child. (Note that SetupChild will construct
+ // an FRS for the child and read it, if it's not already
+ // in the list of children.)
+
+ if( (ChildFrs = SetupChild( TargetFileNumber )) == NULL ) {
+
+ return FALSE;
+ }
+
+ if (!ChildFrs->QueryAttributeRecord(&Record, $DATA, NULL)) {
+
+ return FALSE;
+ }
+ }
+
+ Record.QueryValueLength(FileSize,
+ AllocatedLength,
+ NULL,
+ &TotalAllocated);
+
+ // for uncompressed file, the total allocated length does
+ // not exist
+
+ if (Record.IsResident()) {
+
+ *AllocatedLength = QuadAlign(AllocatedLength->GetLowPart());
+
+ } else if(Record.QueryFlags() & ATTRIBUTE_FLAG_COMPRESSION_MASK) {
+
+ // for compressed file, the allocated length is the
+ // total allocated length
+ *AllocatedLength = TotalAllocated;
+
+ }
+
+ *Error = FALSE;
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::QueryResidentAttribute (
+ OUT PNTFS_ATTRIBUTE Attribute,
+ OUT PBOOLEAN Error,
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCVOID Value,
+ IN ULONG ValueLength,
+ IN COLLATION_RULE CollationRule
+ )
+/*++
+
+Routine Description:
+
+ This method fetches a resident attribute associated with
+ the File Record Segment based on attribute type code and
+ attribute value.
+
+ Note that it does not distinguish between attributes which
+ have the same type code but different names; its primary use
+ it to fetch indexable attributes, which are by convention
+ do not have names.
+
+Arguments:
+
+ Attribute -- Receives (ie. is initialized to) the attribute.
+ Note that this parameter may be uninitialized on
+ entry, and may be left uninitialized if this
+ method fails.
+ Error -- Receives TRUE if the method fails because of
+ an error (corrupt FRS or out of memory).
+ Type -- Supplies the type of the desired attribute
+ Value -- Supplies a pointer to the value to match.
+ ValueLength -- Supplies the length of the value to be matched.
+ CollationRule -- Supplies the collation rule to use for comparison.
+ The first attribute found whose value matches
+ the supplied value according to this collation
+ rule will be returned.
+
+Return Value:
+
+ TRUE if a matching attribute is found.
+
+Notes:
+
+ If this method succeeds, *Error should be ignored.
+
+ If this method fails because of error, *Error will be set to
+ TRUE. If this method returns FALSE and *Error is FALSE, the
+ client may assume that this File Record Segment has no
+ matching attributes.
+
+--*/
+{
+ ULONG AttributeValueLength, i;
+ BOOLEAN Found;
+
+ // This method cannot be used to fetch the ATTRIBUTE_LIST
+ // attribute.
+
+ if( Type == $ATTRIBUTE_LIST ) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ // If the attribute list is present, force it into memory.
+
+ if( !SetupAttributeList() ) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ // Iterate through all the attributes with this type code
+ // until we run out or find a match. Start by resetting *Error
+ // to FALSE--if QueryAttributeByOrdinal encounters an error,
+ // it will set *Error for us.
+
+ *Error = FALSE;
+ Found = FALSE;
+ i = 0;
+
+ while( !Found &&
+ QueryAttributeByOrdinal( Attribute, Error, Type, i ) ) {
+
+ DebugAssert( !Attribute->IsResident() ||
+ Attribute->GetResidentValue() != NULL );
+
+ // If the attribute is resident and the value is the right
+ // length, compare its value with the search value.
+ //
+ AttributeValueLength = Attribute->QueryValueLength().GetLowPart();
+
+ if( Attribute->IsResident() &&
+ AttributeValueLength == ValueLength &&
+ NtfsCollate( Attribute->GetResidentValue(),
+ AttributeValueLength,
+ Value,
+ ValueLength,
+ CollationRule,
+ GetUpcaseTable() ) == 0 ) {
+
+ if( CollationRule == COLLATION_FILE_NAME ) {
+
+ // NOTE: for FILE_NAME comparison, we also have to
+ // check that the parent pointer in the attribute
+ // we found is the same as the search value, to ensure
+ // that we are returning the name associated with the
+ // appropriate index.
+ //
+ if( ((PFILE_NAME)
+ (Attribute->GetResidentValue()))->ParentDirectory ==
+ ((PFILE_NAME)Value)->ParentDirectory ) {
+
+ Found = TRUE;
+ }
+
+ } else {
+
+ // This attribute is a match. Return it to the client.
+ //
+ Found = TRUE;
+ }
+ }
+
+ i++;
+ }
+
+ return Found;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::QueryAttributeByOrdinal (
+ OUT PNTFS_ATTRIBUTE Attribute,
+ OUT PBOOLEAN Error,
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN ULONG Ordinal
+ )
+/*++
+
+Routine Description:
+
+ This method returns the n-th attribute of the specified
+ type. Note that it ignores attribute names (but, of course,
+ the client can query the name of the returned attribute from
+ that attribute).
+
+Arguments:
+
+ Attribute -- Receives (ie. is initialized to) the attribute. Note
+ that this parameter may be uninitialized on entry, and
+ may be left uninitialized if this method fails.
+ Error -- Receives TRUE if the method fails because of an error.
+ Type -- Supplies the type of the desired attribute
+ Ordinal -- Supplies the (zero-based) ordinal number of the
+ attribute to return.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+ If this method succeeds, the client should ignore *Error.
+
+ If this method fails because of error, *Error will be set; if
+ this method returns FALSE and *Error is FALSE, the client may
+ assume that there is no such matching attribute.
+
+--*/
+{
+ NTFS_ATTRIBUTE_RECORD CurrentRecord;
+ MFT_SEGMENT_REFERENCE SegmentReference, NextSegmentReference;
+ DSTRING Name;
+ VCN LowestVcn;
+ VCN TargetFileNumber;
+ ATTRIBUTE_TYPE_CODE CurrentType;
+
+ PVOID CurrentRecordData;
+ PNTFS_FILE_RECORD_SEGMENT TargetFrs = NULL;
+
+ ULONG RecordIndex;
+ USHORT InstanceTag, NextInstanceTag;
+
+
+ DebugPtrAssert( Attribute );
+ DebugPtrAssert( Error );
+
+ // If the attribute list is present, force it into memory.
+ //
+ if( !SetupAttributeList() ) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+
+ if( _AttributeList != NULL ) {
+
+ // Spin through the attribute list until we find the nth
+ // entry with the requested type and a LowestVcn of zero.
+ //
+ RecordIndex = 0;
+
+ while( TRUE ) {
+
+ if( !_AttributeList->QueryEntry( RecordIndex,
+ &CurrentType,
+ &LowestVcn,
+ &SegmentReference,
+ &InstanceTag,
+ &Name ) ) {
+
+ // Out of entries in the attribute list, so there
+ // is no matching attribute type.
+
+ *Error = FALSE;
+ return FALSE;
+ }
+
+ if( CurrentType == Type && LowestVcn == 0 ) {
+
+ // This entry has the desired type code; check
+ // to see if we want to skip it or grab it.
+ //
+ if( Ordinal == 0 ) {
+
+ // Found the entry we want.
+ //
+ break;
+
+ } else {
+
+ // Skip this one.
+ //
+ Ordinal--;
+ }
+ }
+
+ // Move on to the next entry.
+ //
+ RecordIndex ++;
+ }
+
+ // Now we have an entry for the attribute we want. If there's
+ // only one entry for this attribute, we can initialize an
+ // attribute with that record and return; if there are multiple
+ //
+ // If the next entry does not have a LowestVcn of zero, it
+ // is another entry for this attribute. Note that we need
+ // SegmentReference and Instance tag for later use.
+ //
+ RecordIndex++;
+
+ if( _AttributeList->QueryEntry( RecordIndex,
+ &CurrentType,
+ &LowestVcn,
+ &NextSegmentReference,
+ &NextInstanceTag,
+ &Name ) &&
+ CurrentType == Type &&
+ LowestVcn != 0 ) {
+
+ // This is a multi-record attribute, which means it is
+ // uniquely identified by Type and Name.
+ //
+ return( QueryAttribute( Attribute,
+ Error,
+ Type,
+ &Name ) );
+
+ } else {
+
+ // There are no more entries for this attribute,
+ // so we can initialize an the attribute with
+ // this record. We'll let QueryAttributeByTag
+ // do the work for us.
+ //
+ TargetFileNumber.Set( SegmentReference.LowPart,
+ (LONG) SegmentReference.HighPart );
+
+ if( TargetFileNumber == QueryFileNumber() ) {
+
+ // The record is in this FRS.
+ //
+ TargetFrs = this;
+
+ } else {
+
+ // The record we want is in a child FRS; get that
+ // child and squeeze the attribute out of it.
+ //
+ if( (TargetFrs = SetupChild( TargetFileNumber)) == NULL ) {
+
+ // Something is wrong--we can't get the child.
+ //
+ *Error = TRUE;
+ return FALSE;
+ }
+ }
+
+
+ if( !TargetFrs->QueryAttributeByTag( Attribute,
+ Error,
+ InstanceTag ) ) {
+
+ // We know the attribute is there, but we can't
+ // get it.
+ //
+ *Error = TRUE;
+ return FALSE;
+
+ } else {
+
+ return TRUE;
+ }
+ }
+
+ } else {
+
+ // This File Record Segment does not have an attribute list,
+ // so we only have to grope through this FRS.
+
+ // First, skip over attribute records with a type-code
+ // less than the one we're looking for:
+
+ CurrentRecordData = NULL;
+ *Error = FALSE;
+
+ do {
+
+ if( (CurrentRecordData =
+ GetNextAttributeRecord( CurrentRecordData,
+ NULL,
+ Error )) == NULL ||
+ *Error ) {
+
+ // No more, or an error was found.
+ return FALSE;
+ }
+
+ if( !CurrentRecord.Initialize( CurrentRecordData ) ) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ } while( CurrentRecord.QueryTypeCode() != $END &&
+ CurrentRecord.QueryTypeCode() < Type );
+
+ if( CurrentRecord.QueryTypeCode() == $END ||
+ CurrentRecord.QueryTypeCode() > Type ) {
+
+ // There are no attributes of the specified type in
+ // this FRS. Note that *Error has already been set
+ // to FALSE.
+
+ return FALSE;
+ }
+
+ // Now step through the attributes of this type code to
+ // find the one we want.
+
+ while( Ordinal != 0 ) {
+
+ // In determining the ordinal of an attribute, we only
+ // count attribute records which are resident or have
+ // a LowestVcn of zero.
+
+ if( CurrentRecord.IsResident() ||
+ CurrentRecord.QueryLowestVcn() == 0 ) {
+
+ Ordinal--;
+ }
+
+ if( (CurrentRecordData =
+ GetNextAttributeRecord( CurrentRecordData,
+ NULL,
+ Error )) == NULL ||
+ *Error ) {
+
+ // No more, or an error was found.
+ return FALSE;
+ }
+
+ if( !CurrentRecord.Initialize( CurrentRecordData ) ) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ if( CurrentRecord.QueryTypeCode() == $END ||
+ CurrentRecord.QueryTypeCode() > Type ) {
+
+ // Ran out of matching records.
+
+ return FALSE;
+ }
+ }
+
+ // We've found our baby. Initialize the attribute and return.
+
+ if( CurrentRecord.IsResident() ) {
+
+ // Since this attribute record is resident, it is
+ // the only attribute record for this attribute, and
+ // so it suffices to initialize the attribute with
+ // this record.
+
+ if( Attribute->Initialize( GetDrive(),
+ QueryClusterFactor(),
+ &CurrentRecord ) ) {
+
+ // Everything is just fine.
+
+ return TRUE;
+
+ } else {
+
+ // Foiled at the last minute by some dastardly error.
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ } else {
+
+ // Since there may be other attribute records associated
+ // with this attribute, we have to invoke QueryAttribute
+ // to do our work for us. Get the name from the attribute
+ // record, and then query this FRS for the attribute with
+ // the requested type and that name.
+
+ if( !CurrentRecord.QueryName( &Name ) ) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ return( QueryAttribute( Attribute,
+ Error,
+ Type,
+ &Name ) );
+ }
+
+ }
+}
+
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::QueryAttributeByTag (
+ OUT PNTFS_ATTRIBUTE Attribute,
+ OUT PBOOLEAN Error,
+ IN ULONG Tag
+ )
+/*++
+
+Routine Description:
+
+ This method initializes an attribute based on the single attribute
+ record with the specified instance tag. Note that it only examines
+ records in this File Record Segment; it does not look at child FRS's.
+
+Arguments:
+
+ Attribute -- Receives (ie. is initialized to) the attribute
+ in question. Note that this parameter may be
+ uninitialized on entry, and may be left in that
+ state if this method fails.
+ Error -- Receives TRUE if the method fails because of
+ an error.
+ Tag -- Supplies the attribute record instance tag of
+ the desired record.
+
+--*/
+{
+ NTFS_ATTRIBUTE_RECORD CurrentRecord;
+ PVOID CurrentRecordData = NULL;
+ BOOLEAN Found = FALSE;
+
+
+ while( !Found ) {
+
+ CurrentRecordData = GetNextAttributeRecord( CurrentRecordData );
+
+ if( CurrentRecordData == NULL ) {
+
+ // No more records.
+ //
+ *Error = FALSE;
+ return FALSE;
+ }
+
+ if( !CurrentRecord.Initialize( CurrentRecordData ) ) {
+
+ // Error initializing object.
+ //
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ if( CurrentRecord.QueryInstanceTag() == Tag ) {
+
+ Found = TRUE;
+ }
+ }
+
+ if( !Attribute->Initialize( GetDrive(),
+ QueryClusterFactor(),
+ &CurrentRecord ) ) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::PurgeAttribute (
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCWSTRING Name,
+ IN BOOLEAN IgnoreExternal
+ )
+/*++
+
+Routine Description:
+
+ This method removes all attribute records for the given attribute
+ type and name from the File Record Segment and its children.
+
+Arguments:
+
+ Type -- supplies the type of the attribute to purge
+ Name -- supplies the name of the attribute to purge (NULL if
+ the attribute has no name).
+ IgnoreExternal -- supplies a flag that, if TRUE, indicates we
+ should ignore the attribute list and only delete
+ matching records found in this File Record Segment
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ NTFS_ATTRIBUTE_RECORD CurrentRecord;
+ MFT_SEGMENT_REFERENCE SegmentReference;
+ PNTFS_FILE_RECORD_SEGMENT ChildFrs;
+ VCN TargetFileNumber;
+ ULONG EntryIndex;
+ ULONG CurrentRecordOffset;
+ ULONG NextRecordOffset;
+
+ if( !IgnoreExternal &&
+ Type != $ATTRIBUTE_LIST &&
+ (_AttributeList != NULL ||
+ IsAttributePresent($ATTRIBUTE_LIST, NULL, TRUE) ) ) {
+
+ // This File Record Segment has an attribute list, so
+ // we should consult it.
+
+ if( !SetupAttributeList() ) {
+
+ return FALSE;
+ }
+
+
+ while( _AttributeList->QueryExternalReference( Type,
+ &SegmentReference,
+ &EntryIndex,
+ Name ) ) {
+
+ TargetFileNumber.Set( SegmentReference.LowPart,
+ (LONG) SegmentReference.HighPart );
+
+ if( TargetFileNumber == QueryFileNumber() ) {
+
+ // The record we want to delete is in this File
+ // Record Segment. The easiest way to get at it
+ // is to recurse back into this function with
+ // IgnoreExternal equal to TRUE (which prevents
+ // further recursion).
+
+ PurgeAttribute( Type, Name, TRUE );
+
+ } else {
+
+ // The record we want to delete is in a child record
+ // segment. Note that SetupChild will construct and
+ // read a new FRS if the child isn't already in the list.
+
+ if( (ChildFrs = SetupChild( TargetFileNumber )) == NULL ) {
+
+ return FALSE;
+ }
+
+ // Now we've got the child; purge any matching attributes
+ // from it. (It's OK if we purge more than one; we'll
+ // catch up on later iterations.)
+
+ if( !ChildFrs->PurgeAttribute( Type, Name ) ) {
+
+ return FALSE;
+ }
+ }
+
+ _AttributeList->DeleteEntry( EntryIndex );
+ }
+
+ } else {
+
+ // Either there is no Attribute List, or we're deleting
+ // the Attribute List itself, or we've been instructed to
+ // ignore it, so we can just go through this File Record
+ // Segment and blow away any matching records we find.
+
+ CurrentRecordOffset = _FrsData->FirstAttributeOffset;
+
+ while( CurrentRecordOffset < QuerySize() &&
+ CurrentRecord.
+ Initialize( (PBYTE)_FrsData + CurrentRecordOffset,
+ QuerySize() - CurrentRecordOffset ) &&
+ CurrentRecord.QueryTypeCode() != $END ) {
+
+ if( CurrentRecord.QueryRecordLength() == 0 ) {
+
+ return FALSE;
+ }
+
+ if( CurrentRecord.IsMatch( Type, Name ) ) {
+
+ // This record matches, so away it goes!
+
+ NextRecordOffset =CurrentRecordOffset +
+ CurrentRecord.QueryRecordLength();
+
+ DebugAssert( NextRecordOffset < QuerySize() );
+
+ _FrsData->FirstFreeByte -= CurrentRecord.QueryRecordLength();
+
+ memmove( (PBYTE)_FrsData + CurrentRecordOffset,
+ (PBYTE)_FrsData + NextRecordOffset,
+ (UINT) (QuerySize() - NextRecordOffset) );
+
+
+
+ // Note that, since we've brought the next record to
+ // CurrentRecordOffset, there's no need to adjust
+ // CurrentRecordOffset.
+
+ } else {
+
+ // This record doesn't match, so we won't purge it.
+
+ CurrentRecordOffset += CurrentRecord.QueryRecordLength();
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::DeleteResidentAttribute(
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCWSTRING Name,
+ IN PCVOID Value,
+ IN ULONG ValueLength,
+ OUT PBOOLEAN Deleted,
+ IN BOOLEAN IgnoreExternal
+ )
+/*++
+
+Routine Description:
+
+ This method will delete any attribute record associated with the
+ File Record Segment which represents a resident attribute of the
+ specified type and name with a value equal to the supplied value.
+
+Arguments:
+
+ Type -- Supplies the attribute type code.
+ Name -- Supplies the attribute name. May be NULL, which
+ indicates that the attribute has no name.
+ Value -- Supplies the value of the attribute to delete.
+ ValueLength -- Supplies the length of the value.
+ IgnoreExternal -- Supplies a flag which indicates, if TRUE,
+ that this method should only examine records
+ in this FRS (ie. it should ignore external
+ attributes).
+ Deleted -- Receives TRUE if the method found and deleted
+ a matching record.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ DSTRING CurrentName;
+ NTFS_ATTRIBUTE_RECORD CurrentRecord;
+ MFT_SEGMENT_REFERENCE SegmentReference, FoundSegmentReference;
+
+ PNTFS_FILE_RECORD_SEGMENT ChildFrs;
+
+ ATTRIBUTE_TYPE_CODE CurrentType;
+ VCN LowestVcn, TargetFileNumber;
+ ULONG RecordIndex;
+ USHORT Instance, FoundInstance;
+ BOOLEAN IsIndexed;
+
+ DebugPtrAssert( Value );
+ DebugPtrAssert( Deleted );
+
+ *Deleted = FALSE;
+
+ if( !SetupAttributeList() ) {
+
+ return FALSE;
+ }
+
+ if( !IgnoreExternal &&
+ _AttributeList != NULL ) {
+
+ // First, traverse the list to force all the children into
+ // memory.
+ //
+ for( RecordIndex = 0;
+ _AttributeList->QueryEntry( RecordIndex,
+ &CurrentType,
+ &LowestVcn,
+ &SegmentReference,
+ &Instance,
+ &CurrentName );
+ RecordIndex++ ) {
+
+ TargetFileNumber.Set( SegmentReference.LowPart,
+ (LONG) SegmentReference.HighPart );
+
+ if( TargetFileNumber != QueryFileNumber() &&
+ SetupChild( TargetFileNumber ) == NULL ) {
+
+ return FALSE;
+ }
+ }
+
+ // Now traverse the list of children, trying to delete
+ // the record in question.
+ //
+ _ChildIterator->Reset();
+
+ while( (ChildFrs = (PNTFS_FILE_RECORD_SEGMENT)
+ _ChildIterator->GetNext()) != NULL ) {
+
+ if( !ChildFrs->DeleteResidentAttributeLocal( Type,
+ Name,
+ Value,
+ ValueLength,
+ Deleted,
+ &IsIndexed,
+ &Instance ) ) {
+
+ return FALSE;
+ }
+
+ if( *Deleted ) {
+
+ // We found our victim. Remember the segment reference
+ // and instance tag, so we can delete the attribute list
+ // entry.
+ //
+ FoundSegmentReference = ChildFrs->QuerySegmentReference();
+ FoundInstance = Instance;
+
+ break;
+ }
+ }
+
+ if( !*Deleted ) {
+
+ // We didn't find the target attribute record in any
+ // of the children; see if it's in this FRS itself.
+ //
+ if( !DeleteResidentAttributeLocal( Type,
+ Name,
+ Value,
+ ValueLength,
+ Deleted,
+ &IsIndexed,
+ &Instance ) ) {
+
+ return FALSE;
+ }
+
+ if( *Deleted ) {
+
+ // Found it in this FRS.
+ //
+ FoundSegmentReference = QuerySegmentReference();
+ FoundInstance = Instance;
+ }
+ }
+
+ if( *Deleted ) {
+
+ // We found and deleted a matching attribute record.
+ // Find the corresponding entry in the attribute list
+ // and delete it. Note that the Segment Reference and
+ // Instance Tag are sufficient to identify that entry.
+ //
+ for( RecordIndex = 0;
+ _AttributeList->QueryEntry( RecordIndex,
+ &CurrentType,
+ &LowestVcn,
+ &SegmentReference,
+ &Instance,
+ &CurrentName );
+ RecordIndex++ ) {
+
+ if( SegmentReference == FoundSegmentReference &&
+ Instance == FoundInstance ) {
+
+ _AttributeList->DeleteEntry( RecordIndex );
+ break;
+ }
+ }
+ }
+
+ } else {
+
+ // This FRS does not have an attribute list (or the client
+ // wants to ignore it), so we just have to examine the records
+ // in this FRS.
+ //
+ if( !DeleteResidentAttributeLocal( Type,
+ Name,
+ Value,
+ ValueLength,
+ Deleted,
+ &IsIndexed,
+ &Instance ) ) {
+
+ return FALSE;
+ }
+
+ }
+
+ // If we successfully deleted an indexed attribute record
+ // from a Base File Record Segment, we need to adjust the
+ // reference count.
+ //
+ if( *Deleted && IsBase() && IsIndexed ) {
+ SetReferenceCount(QueryReferenceCount() - 1);
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::DeleteResidentAttributeLocal(
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCWSTRING Name OPTIONAL,
+ IN PCVOID Value,
+ IN ULONG ValueLength,
+ OUT PBOOLEAN Deleted,
+ OUT PBOOLEAN IsIndexed,
+ OUT PUSHORT InstanceTag
+ )
+/*++
+
+Routine Description:
+
+ This method deletes a resident attribute from the FRS. Note
+ that it will not affect external attributes.
+
+Arguments:
+
+ Type -- Supplies the attribute type code.
+ Name -- Supplies the attribute name. May be NULL, which
+ indicates that the attribute has no name.
+ Value -- Supplies the value of the attribute to delete.
+ ValueLength -- Supplies the length of the value.
+ Deleted -- Receives TRUE if the method found and deleted
+ a matching record.
+ IsIndexed -- Receives TRUE if the deleted record was indexed.
+ If no matching record was found, *Deleted is
+ FALSE and *IsIndexed is undefined.
+ InstanceTag -- Receives the instance tag of the deleted record;
+ if no matching record was found, *Deleted is
+ FALSE and *InstanceTag is undefined.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+
+--*/
+{
+ NTFS_ATTRIBUTE_RECORD CurrentRecord;
+ PVOID CurrentRecordData;
+ PCWSTR NameBuffer = NULL;
+ ULONG NameLength; // Length of Name in characters
+
+ DebugPtrAssert( Value );
+ DebugPtrAssert( Deleted );
+
+ *Deleted = FALSE;
+
+ // Get the search name into a WSTR buffer, for
+ // easier comparison:
+ //
+ if( Name == NULL ) {
+
+ NameLength = 0;
+
+ } else {
+
+ NameLength = Name->QueryChCount();
+ NameBuffer = Name->GetWSTR();
+ }
+
+ // Go through the attribute records in this FRS until
+ // we find one that matches. If we find one, it is
+ // unique (unless the FRS is corrupt), so we delete
+ // it and return.
+
+ CurrentRecordData = NULL;
+
+ while( (CurrentRecordData =
+ GetNextAttributeRecord( CurrentRecordData )) != NULL ) {
+
+ if( !CurrentRecord.Initialize( CurrentRecordData ) ) {
+
+ return FALSE;
+ }
+
+ // This record matches if the type codes are the same,
+ // the record is resident, the names are the same length
+ // and compare exactly, and the values are the same length
+ // and compare exactly.
+ //
+ if( CurrentRecord.QueryTypeCode() == Type &&
+ CurrentRecord.IsResident() &&
+ CurrentRecord.QueryNameLength() == NameLength &&
+ memcmp( NameBuffer,
+ CurrentRecord.GetName(),
+ NameLength * sizeof(WCHAR) ) == 0 &&
+ CurrentRecord.QueryResidentValueLength() == ValueLength &&
+ memcmp( CurrentRecord.GetResidentValue(),
+ Value,
+ ValueLength ) == 0 ) {
+
+ // This is the record we want to delete.
+ //
+ *IsIndexed = CurrentRecord.IsIndexed();
+ *InstanceTag = CurrentRecord.QueryInstanceTag();
+
+ DeleteAttributeRecord( CurrentRecordData );
+ *Deleted = TRUE;
+
+ return TRUE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::SetupAttributeList(
+ )
+/*++
+
+Routine Description:
+
+ This method makes sure that the attribute list, if present,
+ has been properly set up. If the attribute list is present
+ but cannot be initialized, this method returns FALSE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ if ( _AttributeList == NULL &&
+ IsAttributePresent( $ATTRIBUTE_LIST, NULL, TRUE ) ) {
+
+ if (!(_AttributeList = NEW NTFS_ATTRIBUTE_LIST) ||
+ !QueryAttributeList(_AttributeList) ||
+ !_AttributeList->ReadList()) {
+
+ // This File Record Segment has an Attribute List, and I
+ // can't get it. Return failure.
+
+ DELETE(_AttributeList);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::CreateAttributeList(
+ OUT PNTFS_ATTRIBUTE_LIST AttributeList
+ )
+/*++
+
+Routine Description:
+
+ This method generates an Attribute List Attribute for this
+ File Record Segment.
+
+Arguments:
+
+ AttributeList - Returns a newly-create Attribute List.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+Notes:
+
+ It is an error to create an Attribute List Attribute for a
+ File Record Segment that already has one.
+
+--*/
+{
+ NTFS_ATTRIBUTE_RECORD CurrentRecord;
+ MFT_SEGMENT_REFERENCE SegmentReference;
+ ULONG CurrentRecordOffset;
+ DSTRING CurrentName;
+
+ // Construct an attribute list object:
+
+ if( !AttributeList->Initialize( GetDrive(),
+ QueryClusterFactor(),
+ GetUpcaseTable() ) ) {
+
+ return FALSE;
+ }
+
+ // Walk through the record entries in this File Record Segment,
+ // adding an entry to the Attribute List for each record we find.
+ // Note that we can use the same Segment Reference for every entry,
+ // since they are all in this File Record Segment.
+
+ SegmentReference = QuerySegmentReference();
+
+ CurrentRecordOffset = _FrsData->FirstAttributeOffset;
+
+ while( CurrentRecordOffset < QuerySize() &&
+ CurrentRecord.
+ Initialize( (PBYTE)_FrsData + CurrentRecordOffset,
+ QuerySize() - CurrentRecordOffset ) &&
+ CurrentRecord.QueryTypeCode() != $END ) {
+
+ if( CurrentRecord.QueryRecordLength() == 0 ) {
+
+ // Corrupt FRS.
+ //
+ return FALSE;
+ }
+
+ if (!CurrentRecord.QueryName(&CurrentName) ||
+ !AttributeList->AddEntry( CurrentRecord.QueryTypeCode(),
+ CurrentRecord.QueryLowestVcn(),
+ &SegmentReference,
+ CurrentRecord.QueryInstanceTag(),
+ &CurrentName ) ) {
+
+ return FALSE;
+ }
+
+ CurrentRecordOffset += CurrentRecord.QueryRecordLength();
+ }
+
+ return TRUE;
+}
+
+
+PVOID
+GetBiggestLocalAttributeRecord(
+ IN PNTFS_FRS_STRUCTURE Frs
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the biggest attribute record in this
+ file record segment.
+
+Arguments:
+
+ Frs - Supplies a Frs.
+
+Return Value:
+
+ A pointer to the biggest attribute record or NULL.
+
+--*/
+{
+ PATTRIBUTE_RECORD_HEADER pattr, biggest;
+
+ biggest = NULL;
+ while (biggest = (PATTRIBUTE_RECORD_HEADER)
+ Frs->GetNextAttributeRecord(biggest)) {
+
+ if (biggest->TypeCode != $STANDARD_INFORMATION) {
+ break;
+ }
+ }
+
+ if (!biggest) {
+ return NULL;
+ }
+
+ pattr = biggest;
+ while (pattr = (PATTRIBUTE_RECORD_HEADER)
+ Frs->GetNextAttributeRecord(pattr)) {
+
+ if (pattr->TypeCode != $STANDARD_INFORMATION &&
+ pattr->RecordLength > biggest->RecordLength) {
+ biggest = pattr;
+ }
+ }
+
+ return biggest;
+}
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::SaveAttributeList(
+ PNTFS_BITMAP VolumeBitmap
+ )
+/*++
+
+Routine Description:
+
+ This method instructs the File Record Segment to save its
+ attribute record list.
+
+Arguments:
+
+ VolumeBitmap -- supplies the volume bitmap.
+
+Notes:
+
+ If _AttributesList is NULL, then the File Record Segment has not
+ modified its attribute list (if it has one) and therefore does
+ not need to save it.
+
+ If this method fails, it will leave the File Record Segment in
+ a consistent state (it will leave the old attribute list, if any,
+ in place).
+
+--*/
+{
+ NTFS_ATTRIBUTE_RECORD OldAttributeListRecord;
+ NTFS_ATTRIBUTE_RECORD TemporaryRecord;
+ BOOLEAN InsertSucceeded, OldPresent;
+ PATTRIBUTE_RECORD_HEADER Biggest;
+ ATTRIBUTE_TYPE_CODE type;
+ VCN lowest_vcn;
+ MFT_SEGMENT_REFERENCE seg_ref;
+ USHORT instance;
+ DSTRING name, tmp_name;
+ ULONG i;
+ BOOLEAN found_entry;
+
+
+ if( _AttributeList == NULL ) {
+
+ return TRUE;
+ }
+
+ // Note that there is no attribute list entry for the
+ // attribute list's own attribute record.
+ //
+ // Write the attribute list.
+ //
+ if( !_AttributeList->WriteList( VolumeBitmap ) ) {
+
+ return FALSE;
+ }
+
+ // We'll hedge our bets by squirreling away a copy of the old
+ // attribute list's attribute record, if it exists. Note that
+ // this is a two-step process; first, we query the attribute
+ // list's record from the File Record Segment; however, since
+ // this record's data is actually owned by the File Record Segment,
+ // we need to copy it into a record that has its own data.
+
+ if( IsAttributePresent( $ATTRIBUTE_LIST, NULL, TRUE ) ) {
+
+ OldPresent = TRUE;
+
+ if( !QueryAttributeRecord(&TemporaryRecord, $ATTRIBUTE_LIST) ||
+ !OldAttributeListRecord.
+ Initialize( (PVOID) TemporaryRecord.GetData(),
+ TemporaryRecord.QueryRecordLength(),
+ TRUE ) ) {
+
+ // This File Record Segment has an attribute list record,
+ // but we weren't able to copy it to a safe place. Stop
+ // right here, instead of going forward into a mess from
+ // which we can't recover.
+
+ return FALSE;
+ }
+
+ } else {
+
+ OldPresent = FALSE;
+ }
+
+
+ // Now that we have our own copy of the old record (if it existed),
+ // we can safely delete it from the File Record Segment. We could
+ // rely on _AttributeList->InsertIntoFile to do that for us, but
+ // that would complicate our error handling further down.
+
+ if( !PurgeAttribute( $ATTRIBUTE_LIST ) ) {
+
+ return FALSE;
+ }
+
+
+ // Now we try every trick we've got to insert the new attribute
+ // list into the File Record Segment.
+
+ InsertSucceeded = FALSE;
+
+ while( !InsertSucceeded ) {
+
+ InsertSucceeded = _AttributeList->InsertIntoFile( this,
+ VolumeBitmap );
+
+ if( !InsertSucceeded ) {
+
+ // We weren't able to insert the attribute. Try different
+ // strategems to jam it in. First, if the attribute list
+ // is resident, we can make it non-resident.
+
+ if( _AttributeList->IsResident() ) {
+
+ if( !_AttributeList->MakeNonresident( VolumeBitmap ) ) {
+
+ // We failed trying to make the attribute list
+ // nonresident. Give up.
+
+ break;
+ }
+
+ } else {
+
+ // It's nonresident, so we have to move to our next
+ // contingency plan: start moving records out of the
+ // base File Record Segment and into children.
+
+ // Find the biggest attribute record in the base
+ // and then eliminate it from the attribute list
+ // and the base file record segment but save it.
+
+ Biggest = (PATTRIBUTE_RECORD_HEADER)
+ GetBiggestLocalAttributeRecord(this);
+ if (!Biggest ||
+ !TemporaryRecord.Initialize(Biggest,
+ Biggest->RecordLength,
+ TRUE)) {
+
+ // Serious problems.
+ break;
+ }
+
+ found_entry = FALSE;
+ for (i = 0;
+ _AttributeList->QueryEntry(i, &type, &lowest_vcn,
+ &seg_ref, &instance, &name);
+ i++) {
+
+ if (type == TemporaryRecord.QueryTypeCode() &&
+ lowest_vcn == TemporaryRecord.QueryLowestVcn() &&
+ seg_ref == QuerySegmentReference() &&
+ instance == TemporaryRecord.QueryInstanceTag() &&
+ TemporaryRecord.QueryName(&tmp_name) &&
+ !tmp_name.Strcmp(&name)) {
+
+ _AttributeList->DeleteEntry(i);
+ found_entry = TRUE;
+ break;
+ }
+ }
+
+ if (found_entry) {
+ DeleteAttributeRecord(Biggest);
+ } else {
+ DebugAbort("Could not find attribute list entry for big");
+ break;
+ }
+
+ // Now just pull an insert external on this record to
+ // finish the task.
+
+ if (!InsertExternalAttributeRecord(&TemporaryRecord) ||
+ !_AttributeList->WriteList(VolumeBitmap)) {
+
+ // Out of memory or out of disk space.
+ break;
+ }
+ }
+ }
+ }
+
+
+ if( !InsertSucceeded && OldPresent ) {
+
+ // Since we were unable to insert the new attribute
+ // record, we reinsert the old one. Note that we can
+ // be sure that there's room for it, since we haven't
+ // added anything to the File Record Segment since we
+ // deleted this record.
+
+ InsertAttributeRecord( &OldAttributeListRecord );
+ }
+
+ // For good or ill, we're done.
+
+ return( InsertSucceeded );
+}
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::QueryAttributeRecord (
+ OUT PNTFS_ATTRIBUTE_RECORD AttributeRecord,
+ IN ATTRIBUTE_TYPE_CODE Type,
+ IN PCWSTRING Name
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method finds an attribute record in the FRS. Note that it only
+ searches this FRS, it will not look for external attribute records.
+
+Arguments:
+
+ AttributeRecord -- returns the Attribute Record object.
+ Type -- supplies the type of the desired attribute record
+ Name -- supplies the name of the desired attribute (NULL if
+ the attribute has no name).
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG CurrentRecordOffset;
+ BOOLEAN Found = FALSE;
+
+ DebugPtrAssert( _FrsData );
+ DebugPtrAssert( AttributeRecord );
+
+ // Spin through the records in this File Record Segment
+ // looking for a match. If we find one, set the Found
+ // flag and break out.
+
+ CurrentRecordOffset = _FrsData->FirstAttributeOffset;
+
+ while( CurrentRecordOffset < QuerySize() &&
+ AttributeRecord->
+ Initialize( (PBYTE)_FrsData + CurrentRecordOffset,
+ QuerySize() - CurrentRecordOffset ) &&
+ AttributeRecord->QueryTypeCode() != $END ) {
+
+ if( AttributeRecord->IsMatch( Type, Name ) ) {
+
+ Found = TRUE;
+ break;
+ }
+
+ // Go on to the next record
+
+ CurrentRecordOffset += AttributeRecord->QueryRecordLength();
+ }
+
+ // If Found is TRUE, then CurrentRecord is the attribute
+ // record we want, so we'll return it to the caller.
+
+ return Found;
+}
+
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::InsertAttributeRecord (
+ IN PNTFS_ATTRIBUTE_RECORD NewRecord,
+ IN BOOLEAN ForceExternal
+ )
+/*++
+
+Routine Description:
+
+ This method inserts an attribute record into the File Record
+ Segment.
+
+ If the File Record Segment has room, it will just insert the
+ record. If not, it may make the attribute external, or it
+ may make room for the record by making other attributes nonresident
+ or external.
+
+ The Attribute List attribute and the Standard Information attribute
+ cannot be made external.
+
+ This method is virtual because classes which derive from
+ File Record Segment may have preferences about how they manage
+ their attribute records.
+
+Arguments:
+
+ AttributeRecord -- supplies the attribute record to insert
+
+ ForceExternal -- supplies a flag telling whether to force
+ this record into a child File Record Segment;
+ if this flag is TRUE, we force this record
+ to be external.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This method may also update the Instance tag in the attribute record.
+
+--*/
+{
+ NTFS_ATTRIBUTE_RECORD CurrentRecord;
+ MFT_SEGMENT_REFERENCE SegmentReference, CheckSegment;
+ DSTRING NewName, CheckName;
+ NTFS_ATTRIBUTE_RECORD TempRecord;
+ PATTRIBUTE_RECORD_HEADER EvicteeData, TempRecordData;
+ DSTRING NewRecordName;
+ VCN CheckVcn;
+ ULONG CurrentRecordOffset;
+ ULONG FreeSpace, Index;
+ ATTRIBUTE_TYPE_CODE CheckType;
+ BOOLEAN Result, MatchPresent;
+ USHORT CheckInstance;
+
+ // The reservation for the attribute list is enought for
+ // a nonresident attribute with no name and two worst-case
+ // extents. Since this reservation is only required for
+ // FRS 0, this should be plenty.
+ //
+ CONST AttributeListReservation = SIZE_OF_NONRESIDENT_HEADER +
+ 3 * ( 1 + 2 * sizeof(VCN) );
+
+
+ DebugPtrAssert( _FrsData );
+ DebugPtrAssert( NewRecord );
+
+ // The utilities will never insert any non-$DATA records into
+ // the reserved MFT-overflow FRS when it is being used as
+ // a child of the MFT.
+ //
+ if( !IsBase() &&
+ QueryFileNumber() == MFT_OVERFLOW_FRS_NUMBER &&
+ NewRecord->QueryTypeCode() != $DATA ) {
+
+ return FALSE;
+ }
+
+ // If this File Record Segment has an attribute list, we have
+ // to make sure that we've read it.
+
+ if( !SetupAttributeList() ) {
+
+ return FALSE;
+ }
+
+ // Determine whether an attribute record of the same type and
+ // name is already present in this precise FRS (ie. in this
+ // FRS and not one of its children). If this is the case,
+ // then if this
+ //
+ if( !NewRecord->QueryName( &NewRecordName ) ) {
+
+ DebugPrint( "UNTFS: Can't get name from attribute record.\n" );
+ return FALSE;
+ }
+
+ MatchPresent = IsAttributePresent( NewRecord->QueryTypeCode(),
+ &NewRecordName,
+ TRUE );
+
+ // Determine how much space is available in the File Record Segment.
+ // If there's enough, find the correct insertion point for this
+ // attribute record and put it there.
+ //
+ FreeSpace = QueryFreeSpace();
+
+ if( QueryFileNumber() == MASTER_FILE_TABLE_NUMBER &&
+ IsBase() &&
+ NewRecord->QueryTypeCode() != $ATTRIBUTE_LIST ) {
+
+ // Reserve space for the Attribute List.
+ //
+ if ( FreeSpace < AttributeListReservation ) {
+
+ FreeSpace = 0;
+
+ } else{
+
+ FreeSpace -= AttributeListReservation;
+ }
+ }
+
+ // The new record can go in this FRS if the client has not
+ // requested that it be made external, if there's sufficient
+ // room for it, and if there is no collision with other records
+ // for this attribute.
+ //
+ if( !ForceExternal &&
+ NewRecord->QueryRecordLength() <= FreeSpace &&
+ ( NewRecord->IsResident() || !MatchPresent ) ) {
+
+ // There's enough free space for the new record, so it'll
+ // go in this FRS. Attach the current Next Instance tag
+ // to this attribute record and increment the tag.
+ //
+ NewRecord->SetInstanceTag( QueryNextInstance() );
+ IncrementNextInstance();
+
+ // Scan through the list of records to find the point
+ // at which we should insert it.
+ //
+ CurrentRecordOffset = _FrsData->FirstAttributeOffset;
+
+ while( CurrentRecordOffset < QuerySize() &&
+ CurrentRecord.
+ Initialize( (PBYTE)_FrsData + CurrentRecordOffset,
+ QuerySize() - CurrentRecordOffset ) &&
+ CurrentRecord.QueryTypeCode() != $END &&
+ CompareAttributeRecords( &CurrentRecord,
+ NewRecord,
+ GetUpcaseTable() ) <= 0 ) {
+
+ if( CurrentRecord.QueryRecordLength() == 0 ) {
+
+ // Corrupt FRS.
+ //
+ return FALSE;
+ }
+
+ // Go on to the next record
+
+ CurrentRecordOffset += CurrentRecord.QueryRecordLength();
+ }
+
+ // We want to insert the new record at CurrentRecordOffset;
+ // make room for it there and copy it in.
+
+ memmove( (PBYTE)_FrsData + CurrentRecordOffset +
+ NewRecord->QueryRecordLength(),
+ (PBYTE)_FrsData + CurrentRecordOffset,
+ _FrsData->FirstFreeByte - CurrentRecordOffset);
+
+ _FrsData->FirstFreeByte += NewRecord->QueryRecordLength();
+
+ memcpy( (PBYTE)_FrsData + CurrentRecordOffset,
+ NewRecord->GetData(),
+ (UINT) NewRecord->QueryRecordLength() );
+
+ // if this File Record Segment has an attribute list, then
+ // we add an entry to it for the attribute record we just added.
+ // Note that we can safely assume that an attribute list is
+ // present if and only if _AttributeList is non-NULL because
+ // we made sure we had read it at the beginning of this method.
+
+ if( _AttributeList != NULL &&
+ NewRecord->QueryTypeCode() != $ATTRIBUTE_LIST ) {
+
+ SegmentReference = QuerySegmentReference();
+
+ if (!NewRecord->QueryName(&NewName) ||
+ !_AttributeList->AddEntry(NewRecord->QueryTypeCode(),
+ NewRecord->QueryLowestVcn(),
+ &SegmentReference,
+ NewRecord->QueryInstanceTag(),
+ &NewName)) {
+
+ // So near and yet so far. We have to back all the
+ // way out because we couldn't add an entry for this
+ // record to the attribute list.
+
+ memmove( (PBYTE)_FrsData + CurrentRecordOffset,
+ (PBYTE)_FrsData + CurrentRecordOffset +
+ NewRecord->QueryRecordLength(),
+ _FrsData->FirstFreeByte -
+ (CurrentRecordOffset +
+ NewRecord->QueryRecordLength()) );
+
+ _FrsData->FirstFreeByte -= NewRecord->QueryRecordLength();
+
+ return FALSE;
+ }
+ }
+
+ Result = TRUE;
+
+ } else if( QueryFileNumber() == MASTER_FILE_TABLE_NUMBER &&
+ NewRecord->QueryTypeCode() == $DATA &&
+ NewRecord->QueryLowestVcn() == 0 ) {
+
+ // The first chunk of the MFT's $DATA attribute must
+ // be in the base File Record Segment. Evict as many
+ // other records as possible.
+ //
+ if( (TempRecordData = (PATTRIBUTE_RECORD_HEADER)
+ MALLOC( QuerySize() )) == NULL ) {
+
+ DebugPrint( "UNTFS: Can't allocate memory for temporary attribute record.\n" );
+ return FALSE;
+ }
+
+ EvicteeData = (PATTRIBUTE_RECORD_HEADER)GetNextAttributeRecord( NULL );
+
+ while( EvicteeData != NULL &&
+ EvicteeData->TypeCode != $END ) {
+
+ // If this is not an attribute record we can evict,
+ // then skip over it; otherwise, move it to a child
+ // FRS. Note that we don't check for the first chunk
+ // of the $DATA attribute becuase, after all, that's
+ // what we're inserting.
+ //
+ if( EvicteeData->TypeCode == $STANDARD_INFORMATION ||
+ EvicteeData->TypeCode == $ATTRIBUTE_LIST ) {
+
+ EvicteeData = (PATTRIBUTE_RECORD_HEADER)
+ GetNextAttributeRecord( EvicteeData );
+
+ } else {
+
+ // Copy this record to the temporary buffer and
+ // delete it from the FRS.
+ //
+ memcpy( TempRecordData,
+ EvicteeData,
+ EvicteeData->RecordLength );
+
+ if( !TempRecord.Initialize( TempRecordData ) ) {
+
+ FREE( TempRecordData );
+ return FALSE;
+ }
+
+ DeleteAttributeRecord( EvicteeData );
+
+ // Delete the attribute list entry that corresponds
+ // to this attribute record.
+ //
+ if( _AttributeList != NULL ) {
+
+ Index = 0;
+ while( _AttributeList->QueryEntry( Index,
+ &CheckType,
+ &CheckVcn,
+ &CheckSegment,
+ &CheckInstance,
+ &CheckName ) ) {
+
+ // It's enough to establish a match if the
+ // segment reference and instance tag match,
+ // but we'll throw in a check for the type
+ // code just to be safe.
+ //
+ if( CheckType == TempRecord.QueryTypeCode() &&
+ CheckInstance == TempRecord.QueryInstanceTag() &&
+ CheckSegment == QuerySegmentReference() ) {
+
+ _AttributeList->DeleteEntry( Index );
+ break;
+ }
+
+ Index += 1;
+ }
+ }
+
+ // Insert this record into a child FRS.
+ //
+ if( !InsertExternalAttributeRecord( &TempRecord ) ) {
+
+ FREE( TempRecordData );
+ return FALSE;
+ }
+
+ // No need to advance EvicteeData, since
+ // DeleteAttributeRecord will bring the next
+ // one down to us.
+ }
+
+ }
+
+ FREE( TempRecordData );
+
+ // OK, we've made as much free space as possible. Recompute
+ // the free space; if it's enough, insert the record recursively.
+ // Since we only recurse if there's enough free space, and
+ // we only fall into this branch if there isn't enough space,
+ // we won't get infinite recursion.
+ //
+ FreeSpace = QueryFreeSpace();
+
+ if( FreeSpace < AttributeListReservation ) {
+
+ FreeSpace = 0;
+
+ } else {
+
+ FreeSpace -= AttributeListReservation;
+ }
+
+ if( FreeSpace > NewRecord->QueryRecordLength() ) {
+
+ // It'll fit--go ahead and insert it.
+ //
+ return( InsertAttributeRecord( NewRecord, FALSE ) );
+
+ } else {
+
+ return FALSE;
+
+ }
+
+ } else {
+
+ // This attribute will be external. Call the private worker
+ // method.
+
+ Result = InsertExternalAttributeRecord( NewRecord );
+ }
+
+ // If this is a base file record segment and we've successfully
+ // inserted an indexed attribute, increment the reference count.
+
+ if( Result &&
+ IsBase() &&
+ NewRecord->IsResident() &&
+ (NewRecord->QueryResidentFlags() & RESIDENT_FORM_INDEXED ) ) {
+
+ _FrsData->ReferenceCount += 1;
+ }
+
+ return Result;
+}
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::InsertExternalAttributeRecord(
+ IN PNTFS_ATTRIBUTE_RECORD NewRecord
+ )
+/*++
+
+Routine Description:
+
+ This method adds an external attribute record to the File Record
+ Segment. It is a private worker for InsertAttributeRecord. (It
+ can also be used to move attribute records out of the base segment).
+
+ Note that it is nonvirtual--once the File Record Segment has decided
+ to make the attribute record external, it's done the same way for
+ all types of File Record Segments.
+
+Arguments:
+
+ AttributeRecord -- supplies the attribute record to insert
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ The Attribute List and Standard Information attributes cannot
+ be made external; this method enforces that restriction.
+
+
+--*/
+{
+ PNTFS_FILE_RECORD_SEGMENT ChildFrs;
+ MFT_SEGMENT_REFERENCE SegmentReference;
+ VCN ChildFileNumber;
+ ULONG i;
+ ATTRIBUTE_TYPE_CODE TypeCode;
+ VCN LowestVcn;
+ DSTRING Name;
+ USHORT Instance;
+ BOOLEAN IsMft, IsMftData;
+
+ ULONG cluster_size = QueryClusterFactor() * GetDrive()->QuerySectorSize();
+
+
+ IsMft = ( QueryFileNumber() == MASTER_FILE_TABLE_NUMBER );
+ IsMftData = IsMft && ( NewRecord->QueryTypeCode() == $DATA );
+
+ // the standard information and attribute list attributes cannot
+ // be made external.
+
+ if( NewRecord->QueryTypeCode() == $STANDARD_INFORMATION ||
+ NewRecord->QueryTypeCode() == $ATTRIBUTE_LIST ) {
+
+ return FALSE;
+ }
+
+ // The Log File cannot have any external attributes.
+ //
+ if( !IsBase() &&
+ QueryFileNumber() == LOG_FILE_NUMBER ) {
+
+ return FALSE;
+ }
+
+ // Note that only Base File Record Segments can have attribute lists.
+
+ if( !IsBase() || !SetupAttributeList() ) {
+
+ return FALSE;
+ }
+
+ // OK, at this point, _AttributeList is NULL if and only if
+ // the File Record Segment has no attribute list. If the File
+ // Record Segment has no attribute list, we need to create one.
+
+ if (_AttributeList == NULL) {
+
+ if (!(_AttributeList = NEW NTFS_ATTRIBUTE_LIST) ||
+ !CreateAttributeList(_AttributeList)) {
+
+ // We can't create an attribute list for this File Record
+ // Segment.
+
+ DELETE(_AttributeList);
+ return FALSE;
+ }
+ }
+
+ // Since this is a somewhat rare case, we can indulge ourselves
+ // a bit. Go through the Attribute List and force all the
+ // children of this File Record Segment into memory.
+
+ for( i = 0;
+ _AttributeList->QueryEntry( i,
+ &TypeCode,
+ &LowestVcn,
+ &SegmentReference,
+ &Instance,
+ &Name );
+ i++ ) {
+
+ ChildFileNumber.Set( SegmentReference.LowPart,
+ (LONG) SegmentReference.HighPart );
+
+ if( ChildFileNumber != QueryFileNumber() &&
+ SetupChild( ChildFileNumber ) == NULL ) {
+
+ // Error.
+ return FALSE;
+ }
+ }
+
+
+ // Now go down the list of children and see if any of them
+ // will accept this record. Note that if this is the MFT
+ // $DATA attribute, we must check each child before we try
+ // to use it to make sure we don't break the bootstrap.
+ // we much check each child
+ //
+ _ChildIterator->Reset();
+
+ while( (ChildFrs =
+ (PNTFS_FILE_RECORD_SEGMENT)_ChildIterator->GetNext()) != NULL ) {
+
+ // The MFT requires special handling. Records for the data
+ // attribute must be inserted into child FRS' in a way that
+ // preserves the MFT's bootstrapping, ie. the starting VCN of
+ // the record must be greater than the VCN (file number times
+ // clusters per FRS) of the child. In addition, $DATA records
+ // cannot share a child FRS with any other attribute records.
+ //
+ if( IsMft ) {
+
+ if (IsMftData &&
+ ( ChildFrs->GetNextAttributeRecord( NULL ) != NULL ||
+ NewRecord->QueryLowestVcn() * cluster_size <=
+ ChildFrs->QueryFileNumber() * QuerySize())) {
+
+ // Either this child FRS is not empty, or
+ // inserting this record into it will break
+ // the MFT's bootstrapping. Either way,
+ // it can't accept this record.
+ //
+ continue;
+ }
+
+ if( ChildFrs->IsAttributePresent( $DATA ) ) {
+
+ // This child FRS already has a $DATA attribute
+ // record, so it can't accept any other records.
+ //
+ continue;
+ }
+ }
+
+ // This child FRS is eligible to hold this attribute record.
+ //
+ if( ChildFrs->InsertAttributeRecord( NewRecord ) ) {
+
+ // Success! Add an appropriate entry to the
+ // attribute list.
+ //
+ SegmentReference = ChildFrs->QuerySegmentReference();
+
+ if( !NewRecord->QueryName( &Name ) ||
+ !_AttributeList->AddEntry( NewRecord->QueryTypeCode(),
+ NewRecord->QueryLowestVcn(),
+ &SegmentReference,
+ NewRecord->QueryInstanceTag(),
+ &Name ) ) {
+
+ DebugPrintf( "UNTFS: Can't add entry to attribute list." );
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+ }
+
+ // We have to allocate a new child File Record Segment. If
+ // This is the MFT File, see if we can grab the reserved FRS.
+ //
+ if( IsMftData &&
+ GetChild( MFT_OVERFLOW_FRS_NUMBER ) == NULL ) {
+
+ // This FRS is the MFT, and it hasn't already grabbed
+ // the reserved FRS--grab it now.
+ //
+ ChildFileNumber = MFT_OVERFLOW_FRS_NUMBER;
+
+ } else if( !_Mft->AllocateFileRecordSegment( &ChildFileNumber, IsMftData ) ) {
+
+ // Can't get a new child File Record Segment.
+
+ return FALSE;
+ }
+
+ // Set up the Segment Reference to refer to the Base File
+ // Record Segment, ie. this File Record Segment.
+ //
+ SegmentReference = QuerySegmentReference();
+
+ // Construct the new child File Record Segment and insert
+ // the attribute record into it. Again, make sure we don't
+ // violate the MFT bootstrapping requirements. (Note that
+ // we don't have to check the sharing rule for the MFT data
+ // attribute because this is a new FRS--it can't contain
+ // any conflicting records.
+ //
+ if( (ChildFrs = NEW NTFS_FILE_RECORD_SEGMENT) == NULL ||
+ !ChildFrs->Initialize( ChildFileNumber, _Mft ) ||
+ !ChildFrs->Create( &SegmentReference ) ||
+ ( IsMftData &&
+ NewRecord->QueryLowestVcn() * cluster_size <=
+ ChildFrs->QueryFileNumber() * QuerySize() ) ||
+ !ChildFrs->InsertAttributeRecord( NewRecord ) ||
+ !AddChild( ChildFrs ) ) {
+
+ // That didn't do us any good at all. Clean up the child
+ // and return our failure.
+
+ DELETE( ChildFrs );
+ _Mft->FreeFileRecordSegment( ChildFileNumber );
+
+ return FALSE;
+ }
+
+ // Note that the Child File Record Segment has passed into the
+ // keeping of the children list, so we don't delete it.
+ //
+ // Add an entry to the attribute list for the new record.
+ //
+ SegmentReference = ChildFrs->QuerySegmentReference();
+
+ if( !NewRecord->QueryName( &Name ) ||
+ !_AttributeList->AddEntry( NewRecord->QueryTypeCode(),
+ NewRecord->QueryLowestVcn(),
+ &SegmentReference,
+ NewRecord->QueryInstanceTag(),
+ &Name ) ) {
+
+ DebugPrintf( "UNTFS: Can't add entry to attribute list." );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::Write(
+ )
+/*++
+
+Routine Description:
+
+ This method writes the File Record Segment. It does not affect the
+ attribute list or the child record segments.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ return( NTFS_FRS_STRUCTURE::Write() );
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::Flush(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNTFS_INDEX_TREE ParentIndex
+ )
+/*++
+
+Routine Description:
+
+ This method is used to commit a file to disk. It saves the attribute
+ list, writes any child record segments that have been brought into
+ memory, and writes the File Record Segment itself.
+
+Arguments:
+
+ VolumeBitmap -- Supplies the volume bitmap. This parameter may
+ be NULL, in which case non-resident attributes
+ cannot be resized.
+ ParentIndex -- Supplies the directory which indexes this FRS
+ over $FILE_NAME. May be NULL.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ DUPLICATED_INFORMATION DuplicatedInformation;
+ PNTFS_FILE_RECORD_SEGMENT CurrentChild;
+
+ // If this is a child FRS, just write it.
+ //
+ if( !IsBase() ) {
+
+ return( Write() );
+ }
+
+ // This FRS is a Base File Record Segment--it may have
+ // an attribute list and children, and we have to update
+ // the file-name information in the parent index.
+ //
+ if( _AttributeList != NULL &&
+ !SaveAttributeList( VolumeBitmap ) ) {
+
+ return FALSE;
+ }
+
+ // Update the file name attributes:
+
+ if( !QueryDuplicatedInformation( &DuplicatedInformation ) ||
+ !UpdateFileNames( &DuplicatedInformation, ParentIndex, FALSE ) ) {
+
+ DebugAbort( "Can't update file names in Flush.\n" );
+ return FALSE;
+ }
+
+ // Flush all the children. If a child is empty, mark it as
+ // unused.
+ //
+ _ChildIterator->Reset();
+
+ while( (CurrentChild = (PNTFS_FILE_RECORD_SEGMENT)
+ _ChildIterator->GetNext()) != NULL ) {
+
+ if( !CurrentChild->GetNextAttributeRecord( NULL ) ) {
+
+ // This child has no attribute records--we don't
+ // need it anymore.
+ //
+ CurrentChild->ClearInUse();
+ CurrentChild->Write();
+ _Mft->FreeFileRecordSegment( CurrentChild->QueryFileNumber() );
+
+ } else if( !CurrentChild->Flush( VolumeBitmap ) ) {
+
+ return FALSE;
+ }
+ }
+
+ return( Write() );
+}
+
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::QueryNextAttribute(
+ IN PATTRIBUTE_TYPE_CODE TypeCode,
+ IN PWSTRING Name
+ )
+/*++
+
+Routine Description:
+
+ This method finds the first (attribute type, name) pair in this
+ file which is greater than (TypeCode, Name). Note that it will
+ not return the ATTRIBUTE_LIST, if one is present.
+
+Arguments:
+
+ TypeCode -- supplies the current attribute type code. Receives
+ the type code of the next attribute. A returned type
+ code of $END indicates that there are no more attributes.
+ Name -- supplies the current name. Receives the name of the
+ next attribute.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This method is useful for iterating through the non-indexed
+ attributes of a file, since there can only be one non-indexed
+ attribute with a given type code and name in the file. However,
+ it offers no way of dealing with indexed attributes, which may
+ be distinguished only by value.
+
+--*/
+{
+ NTFS_ATTRIBUTE_RECORD CurrentRecord;
+ ULONG CurrentRecordOffset;
+ PWSTR NameBuffer = NULL;
+ ULONG NameLength;
+
+ DebugAssert( Name );
+
+
+ if( !SetupAttributeList() ) {
+
+ return FALSE;
+ }
+
+ if( _AttributeList != NULL ) {
+
+ return( _AttributeList->QueryNextAttribute( TypeCode, Name ) );
+ }
+
+ // This is slightly ugly but necessary. NTFS attribute names
+ // are collated straight, so we can't use the WSTRING name
+ // comparison, which relies on the current locale.
+
+ NameLength = Name->QueryChCount();
+ NameBuffer = Name->QueryWSTR();
+
+ if( NameBuffer == NULL ) {
+
+ return FALSE;
+ }
+
+
+ // Start at the first attribute record, and iterate forward from
+ // there.
+
+ CurrentRecordOffset = _FrsData->FirstAttributeOffset;
+
+ while( CurrentRecordOffset < QuerySize() ) {
+
+ if( !CurrentRecord.Initialize( (PBYTE)_FrsData + CurrentRecordOffset,
+ QuerySize() - CurrentRecordOffset ) ) {
+
+ if( NameBuffer != NULL ) {
+
+ FREE( NameBuffer );
+ }
+
+ return FALSE;
+ }
+
+
+ if( CurrentRecord.QueryTypeCode() == $END ||
+ CurrentRecord.QueryTypeCode() > *TypeCode ) {
+
+ // Either we're at the end of the list, or we've found
+ // an attribute with a type code greater than *TypeCode--
+ // either way, we've succeeded.
+
+ break;
+ }
+
+ if( CurrentRecord.QueryTypeCode() == *TypeCode ) {
+
+ // This record has the same type code as current
+ // type, so we have to compare names.
+
+ if( CurrentRecord.QueryNameLength() > 0 &&
+ CountedWCMemCmp( NameBuffer,
+ NameLength,
+ CurrentRecord.GetName(),
+ CurrentRecord.QueryNameLength() ) > 0 ) {
+
+ // This record has a name which is greater than
+ // Name, so we're done.
+
+ break;
+ }
+ }
+
+ // Go on to the next record
+ //
+ if( CurrentRecord.QueryRecordLength() == 0 ) {
+
+ // Corrupt FRS.
+ //
+ if( NameBuffer != NULL ) {
+
+ FREE( NameBuffer );
+ }
+ return FALSE;
+ }
+
+ CurrentRecordOffset += CurrentRecord.QueryRecordLength();
+ }
+
+ // Check for overflow.
+
+ if( CurrentRecordOffset >= QuerySize() ) {
+
+ if( NameBuffer != NULL ) {
+
+ FREE( NameBuffer );
+ }
+ return FALSE;
+ }
+
+ // Copy the output parameters.
+
+ *TypeCode = CurrentRecord.QueryTypeCode();
+
+ if( *TypeCode != $END ) {
+
+ if (!CurrentRecord.QueryName(Name)) {
+ if( NameBuffer != NULL ) {
+
+ FREE( NameBuffer );
+ }
+ return FALSE;
+ }
+
+ } else {
+
+ if (!Name->Initialize("")) {
+ if( NameBuffer != NULL ) {
+
+ FREE( NameBuffer );
+ }
+ return FALSE;
+ }
+ }
+
+ if( NameBuffer != NULL ) {
+
+ FREE( NameBuffer );
+ }
+ return TRUE;
+}
+
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::RecoverFile(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNUMBER_SET BadClusterList,
+ OUT PULONG BadClusters,
+ OUT PBIG_INT BytesRecovered,
+ OUT PBIG_INT TotalBytes
+ )
+/*++
+
+Routine Description:
+
+ This method performs recovery on a file record segment.
+
+Arguments:
+
+ VolumeBitmap -- supplies the volume bitmap.
+ BadClusterFile -- supplies the volume's bad-cluster file
+ BadClusters -- receives the number of bad clusters found in
+ attributes associated with this object.
+ BytesRecovered -- bytes recovered in all attributes subject to
+ recovery.
+ TotalBytes -- total bytes in attributes subject to recovery.
+
+Notes:
+
+ $DATA is the only system-defined attribute which is recovered.
+ problems with other system-defined attributes must be handled by
+ CHKDSK.
+
+--*/
+{
+ NTFS_ATTRIBUTE CurrentAttribute;
+ NUMBER_SET BadClusterNumSet;
+
+ ATTRIBUTE_TYPE_CODE CurrentAttributeTypeCode;
+ DSTRING CurrentAttributeName;
+ BIG_INT CurrentBytesRecovered;
+
+ BOOLEAN Error, Modified;
+
+ DebugAssert(IsInUse());
+ DebugAssert(IsBase());
+
+
+ Modified = FALSE;
+
+ if( !BadClusterNumSet.Initialize() ) {
+
+ return FALSE;
+ }
+
+
+ // Force the attribute list, if we have one, into memory.
+
+ if( !SetupAttributeList() ) {
+
+ return FALSE;
+ }
+
+
+ if (!CurrentAttributeName.Initialize("")) {
+ return FALSE;
+ }
+
+
+ CurrentAttributeTypeCode = $STANDARD_INFORMATION;
+
+ *BytesRecovered = 0;
+ *TotalBytes = 0;
+
+ while( TRUE ) {
+
+ // Determine the type code and name of the next attribute
+ // to recover.
+
+ if( !QueryNextAttribute( &CurrentAttributeTypeCode,
+ &CurrentAttributeName ) ) {
+
+ return FALSE;
+ }
+
+
+ // Are we done yet?
+
+ if( CurrentAttributeTypeCode == $END ) {
+
+ break;
+ }
+
+ // System defined attributes other than $DATA are not
+ // recovered.
+
+ if( CurrentAttributeTypeCode < $FIRST_USER_DEFINED_ATTRIBUTE &&
+ CurrentAttributeTypeCode != $DATA ) {
+
+ continue;
+ }
+
+
+ // Recover the attribute we decided to recover.
+
+ if( !QueryAttribute( &CurrentAttribute,
+ &Error,
+ CurrentAttributeTypeCode,
+ &CurrentAttributeName ) ||
+ !CurrentAttribute.RecoverAttribute( VolumeBitmap,
+ &BadClusterNumSet,
+ &CurrentBytesRecovered )) {
+
+ return FALSE;
+ }
+
+ *BytesRecovered += CurrentBytesRecovered;
+ *TotalBytes += CurrentAttribute.QueryValueLength();
+
+ // If the attribute's storage has been modified, I have
+ // to save the attribute.
+
+ if( CurrentAttribute.IsStorageModified() ) {
+
+ Modified = TRUE;
+ if( !CurrentAttribute.InsertIntoFile( this, VolumeBitmap ) ) {
+
+ return FALSE;
+ }
+ }
+ }
+
+ DebugAssert(BadClusterNumSet.QueryCardinality().GetHighPart() == 0);
+
+ *BadClusters = BadClusterNumSet.QueryCardinality().GetLowPart();
+
+ if( *BadClusters != 0 ) {
+
+ BadClusterList->Add( &BadClusterNumSet );
+
+ }
+
+ // If any of the attributes have been modified, flush the FRS.
+ //
+ if( Modified && !Flush( VolumeBitmap ) ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+NTFS_SORT_CODE
+NTFS_FILE_RECORD_SEGMENT::SortIndex(
+ IN PCWSTRING IndexName,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN BOOLEAN DuplicatesAllowed,
+ IN BOOLEAN CheckOnly
+ )
+/*++
+
+Routine Description:
+
+ This method sorts an index tree associated with the File
+ Record Segment.
+
+Arguments:
+
+ IndexName -- Supplies the name of the index.
+ VolumeBitmap -- Supplies the bitmap for this volume.
+ CheckOnly -- Supplies a flag which, if true, indicates that
+ this method should only determine whether the
+ index is badly ordered, it should not actually
+ sort it.
+ DuplicatesAllowed -- Supplies a flag that indicates whether this
+ index tolerates duplicate entries.
+
+Return Value:
+
+ A code indicating the result of the sort:
+
+ Possible return codes for SortIndex:
+
+ NTFS_SORT_INDEX_NOT_FOUND -- this FRS does not contain an
+ index with the specified name.
+ NTFS_SORT_INDEX_WELL_ORDERED -- the index was not sorted because
+ it was found to be well-ordered.
+ NTFS_SORT_INDEX_BADLY_ORDERED -- The index was found to be badly
+ ordered, and it was not sorted.
+ NTFS_SORT_INDEX_SORTED -- The index was sorted and new
+ attributes were inserted into
+ the FRS.
+ NTFS_INSERT_FAILED -- An insertion of an index entry
+ into the new tree failed.
+ (Probable cause: out of space.)
+ NTFS_SORT_ERROR -- Sort failed because of an error.
+
+
+--*/
+{
+ NTFS_INDEX_TREE OldTree, NewTree;
+
+ PCINDEX_ENTRY CurrentEntry;
+ PINDEX_ENTRY NewEntry;
+
+ ULONG Depth;
+ BOOLEAN Error;
+ MFT_SEGMENT_REFERENCE SegmentReference;
+
+ DebugPtrAssert( VolumeBitmap );
+
+ // Get the existing index out of the FRS.
+
+ if( !OldTree.Initialize( GetDrive(),
+ QueryClusterFactor(),
+ VolumeBitmap,
+ GetUpcaseTable(),
+ QuerySize()/2,
+ this,
+ IndexName ) ) {
+
+ return NTFS_SORT_INDEX_NOT_FOUND;
+ }
+
+ // Determine whether the index needs to be sorted:
+
+ if( !OldTree.IsBadlyOrdered( &Error, DuplicatesAllowed ) ) {
+
+ if( Error ) {
+
+ // We could not determine whether the index was
+ // badly ordered.
+
+ return NTFS_SORT_ERROR;
+
+ } else {
+
+ // The index is well-ordered, so there's nothing to do.
+ //
+ return NTFS_SORT_INDEX_WELL_ORDERED;
+ }
+ }
+
+ if( CheckOnly ) {
+
+ // The client doesn't want us to actually sort the index,
+ // just to determine whether it's badly ordered.
+
+ return NTFS_SORT_INDEX_BADLY_ORDERED;
+ }
+
+ // The index is badly ordered, and the client wants us to
+ // sort it. Initialize a new index tree:
+ //
+ if( !NewTree.Initialize( OldTree.QueryIndexedAttributeType(),
+ GetDrive(),
+ QueryClusterFactor(),
+ VolumeBitmap,
+ GetUpcaseTable(),
+ OldTree.QueryCollationRule(),
+ OldTree.QueryBufferSize(),
+ QuerySize()/2,
+ IndexName ) ) {
+
+ // Couldn't initialize a new index.
+ //
+ return NTFS_SORT_ERROR;
+ }
+
+ // Iterate through the entries in the old tree, copying them
+ // (by value) into the new tree.
+ //
+ OldTree.ResetIterator();
+
+ while( (CurrentEntry = OldTree.GetNext( &Depth, &Error )) != NULL ) {
+
+ if( !DuplicatesAllowed &&
+ NewTree.QueryFileReference( CurrentEntry->AttributeLength,
+ GetIndexEntryValue( CurrentEntry ),
+ 0,
+ &SegmentReference,
+ &Error ) ) {
+
+ // This index does not tolerate duplicate entries; since
+ // an entry with the very same name as this one has already
+ // been added to the tree, we're skipping this one.
+ //
+ continue;
+ }
+
+ ASSERT(CurrentEntry->Length >=
+ (sizeof(INDEX_ENTRY)+CurrentEntry->AttributeLength));
+
+ if (!(NewEntry = (PINDEX_ENTRY)MALLOC(CurrentEntry->Length))) {
+ NewTree.FreeAllocation();
+ return NTFS_SORT_ERROR;
+ }
+
+ memcpy(NewEntry, CurrentEntry, CurrentEntry->Length);
+ NewEntry->Flags = 0;
+
+ if( !NewTree.InsertEntry( NewEntry )) {
+
+ NewTree.FreeAllocation();
+ DELETE(NewEntry);
+ return NTFS_SORT_INSERT_FAILED;
+ }
+ DELETE(NewEntry);
+ }
+
+ if( Error ) {
+
+ // An error occurred while traversing the old tree.
+
+ NewTree.FreeAllocation();
+ return NTFS_SORT_ERROR;
+ }
+
+ // We've constructed the new index--save it into this FRS to
+ // replace the old one.
+ //
+ if( !NewTree.Save( this ) ) {
+
+ NewTree.FreeAllocation();
+ return NTFS_SORT_ERROR;
+ }
+
+ // Clean up the old tree.
+
+ OldTree.FreeAllocation();
+
+ return NTFS_SORT_INDEX_SORTED;
+}
+
+NTFS_QUOTA_CODE
+NTFS_FILE_RECORD_SEGMENT::VerifyAndFixQuotaDefaultId(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN BOOLEAN CheckOnly
+ )
+/*++
+
+Routine Description:
+
+ This method verifies that the default quota ID exists inside the
+ Userid2SidQuotaNameData Index.
+
+Arguments:
+
+ VolumeBitmap -- Supplies the bitmap for this volume.
+ CheckOnly -- Supplies a flag which, if true, indicates that
+ this method should only determine whether the
+ index is badly ordered, it should not actually
+ sort it.
+
+Return Value:
+
+ A code indicating the result of the sort:
+
+ Possible return codes for SortIndex:
+
+ NTFS_QUOTA_INDEX_NOT_FOUND -- this FRS does not contain an
+ index with the specified name.
+ NTFS_QUOTA_DEFAULT_ENTRY_MISSING-- the default entry was not found
+ in the index
+ NTFS_QUOTA_INDEX_FOUND -- Found the default Id entry in the
+ index tree.
+ NTFS_QUOTA_INDEX_INSERTED -- Inserted the default Id entry into
+ the index tree.
+ NTFS_QUOTA_INSERT_FAILED -- An insertion of the default Id
+ entry into the index tree failed.
+ (Probable cause: out of space.)
+ NTFS_QUOTA_ERROR -- error occurred. (Possibly out
+ of memory or out of space.)
+
+
+--*/
+{
+ NTFS_INDEX_TREE OldTree;
+ PINDEX_ENTRY FoundEntry, NewEntry;
+ PNTFS_INDEX_BUFFER ContainingBuffer;
+ PQUOTA_USER_DATA QuotaUserData;
+ BOOLEAN Error;
+ DSTRING IndexName;
+ ULONG Key;
+ USHORT length;
+
+ DebugPtrAssert( VolumeBitmap );
+
+ // Get the existing index out of the FRS.
+
+ if (!IndexName.Initialize(Userid2SidQuotaNameData) ||
+ !OldTree.Initialize( GetDrive(),
+ QueryClusterFactor(),
+ VolumeBitmap,
+ GetUpcaseTable(),
+ QuerySize()/2,
+ this,
+ &IndexName ) ) {
+ return NTFS_QUOTA_INDEX_NOT_FOUND; // index not found
+ }
+
+ // Search the index for the QUOTA_DEFAULTS_ID record
+
+ Key = QUOTA_DEFAULTS_ID;
+
+ if (!OldTree.QueryEntry(sizeof(ULONG),
+ &Key,
+ 0,
+ &FoundEntry,
+ &ContainingBuffer,
+ &Error
+ )) {
+
+ // The default entry not found, let inserts a new one in
+
+ if (CheckOnly)
+ return NTFS_QUOTA_DEFAULT_ENTRY_MISSING;
+
+ length = QuadAlign(sizeof(INDEX_ENTRY) +
+ sizeof(ULONG) +
+ SIZEOF_QUOTA_USER_DATA);
+ if (!(NewEntry = (PINDEX_ENTRY)MALLOC(length)))
+ return NTFS_QUOTA_ERROR;
+
+ memset(NewEntry, 0, length);
+
+ NewEntry->DataOffset = sizeof(INDEX_ENTRY)+sizeof(ULONG);
+ NewEntry->DataLength = SIZEOF_QUOTA_USER_DATA;
+ NewEntry->Length = length;
+ NewEntry->AttributeLength = sizeof(ULONG);
+ NewEntry->Flags = 0;
+
+ *((ULONG*)GetIndexEntryValue(NewEntry)) = QUOTA_DEFAULTS_ID;
+
+ QuotaUserData = (PQUOTA_USER_DATA)((char*)GetIndexEntryValue(NewEntry) + sizeof(ULONG));
+ memset(QuotaUserData, 0, SIZEOF_QUOTA_USER_DATA);
+
+ QuotaUserData->QuotaVersion = QUOTA_USER_VERSION;
+ QuotaUserData->QuotaFlags = QUOTA_FLAG_DEFAULT_LIMITS |
+ QUOTA_FLAG_OUT_OF_DATE;
+
+ QuotaUserData->QuotaThreshold = MAXULONGLONG;
+ QuotaUserData->QuotaLimit = MAXULONGLONG;
+ NtQuerySystemTime((PLARGE_INTEGER)&(QuotaUserData->QuotaChangeTime));
+
+ if ( !OldTree.InsertEntry( NewEntry )) {
+ DELETE( NewEntry );
+ return NTFS_QUOTA_INSERT_FAILED;
+ }
+ //
+ // replace the old one.
+ //
+ if( !OldTree.Save( this ) ) {
+
+ return NTFS_QUOTA_ERROR;
+ }
+
+ return NTFS_QUOTA_INDEX_INSERTED;
+
+ } else {
+
+ if (ContainingBuffer)
+ DELETE(ContainingBuffer);
+
+ return NTFS_QUOTA_INDEX_FOUND;
+ }
+}
+
+
+NTFS_SECURITY_CODE
+NTFS_FILE_RECORD_SEGMENT::FindSecurityIndexEntryAndValidate(
+ IN OUT PNTFS_INDEX_TREE OldTree,
+ IN PVOID Key,
+ IN USHORT KeyLength,
+ IN PSECURITY_DESCRIPTOR_HEADER SecurityDescriptorHeader,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN BOOLEAN CheckOnly
+ )
+/*++
+
+Routine Description:
+
+ This method verifies that the given key exists in the specified
+ index and that the given security descriptor header matches
+ the data in the index entry. If the given key does not exists
+ in the index, one will be inserted into it.
+
+Arguments:
+
+ Key -- supplies the search key value
+ KeyLength -- supplies the length of the search key value
+ SecurityDescriptorHeader
+ -- supplies the data portion of the index entry
+ VolumeBitmap -- Supplies the bitmap for this volume.
+ CheckOnly -- Supplies a flag which, if true, indicates that
+ this method should only determine whether the
+ index is badly ordered, it should not actually
+ sort it.
+
+Return Value:
+
+ A code indicating the result of the sort:
+
+ Possible return codes for SortIndex:
+
+ NTFS_SECURITY_INDEX_ENTRY_MISSING -- the specified index entry key
+ cannot be found in the index
+ NTFS_SECURITY_INDEX_FOUND -- the found entry contains
+ correct data
+ NTFS_SECURITY_INDEX_FIXED -- the found entry contains invalid
+ data but is now corrected
+ NTFS_SECURITY_INDEX_DATA_ERROR -- The index was found but the data
+ data in it is incorrect.
+ NTFS_SECURITY_INDEX_INSERTED -- An index was successfully inserted
+ into the specified index.
+ NTFS_SECURITY_INSERT_FAILED -- An insertion of an index entry
+ into the index tree failed.
+ (Probable cause: out of space.)
+ NTFS_SECURITY_ERROR -- failed because of an error.
+ (Probably out of memory or out
+ of space.)
+
+
+--*/
+{
+ PINDEX_ENTRY foundEntry, newEntry;
+ PNTFS_INDEX_BUFFER containingBuffer;
+ BOOLEAN error;
+ USHORT length;
+
+ DebugPtrAssert( VolumeBitmap );
+
+ // Search the index for the given Key
+
+ if (!OldTree->QueryEntry(KeyLength,
+ Key,
+ 0,
+ &foundEntry,
+ &containingBuffer,
+ &error
+ )) {
+
+ // The entry not found, let inserts a new one in
+
+ if (CheckOnly)
+ return NTFS_SECURITY_INDEX_ENTRY_MISSING;
+
+ length = QuadAlign(sizeof(INDEX_ENTRY) +
+ KeyLength +
+ sizeof(SECURITY_DESCRIPTOR_HEADER));
+
+ if (!(newEntry = (PINDEX_ENTRY)MALLOC(length)))
+ return NTFS_SECURITY_ERROR;
+
+ memset((PVOID)newEntry, 0, length);
+
+ newEntry->DataOffset = sizeof(INDEX_ENTRY)+KeyLength;
+ newEntry->DataLength = sizeof(SECURITY_DESCRIPTOR_HEADER);
+ newEntry->Length = length;
+ newEntry->AttributeLength = KeyLength;
+ newEntry->Flags = 0;
+
+ memcpy(GetIndexEntryValue(newEntry), Key, KeyLength);
+ memcpy((PCHAR)GetIndexEntryValue(newEntry) + KeyLength,
+ (PCHAR)SecurityDescriptorHeader,
+ sizeof(SECURITY_DESCRIPTOR_HEADER));
+
+ if ( !OldTree->InsertEntry( newEntry )) {
+ DELETE( newEntry );
+ return NTFS_SECURITY_INSERT_FAILED;
+ }
+ //
+ // replace the old one.
+ //
+ if( !OldTree->Save( this ) ) {
+
+ return NTFS_SECURITY_ERROR;
+ }
+
+ return NTFS_SECURITY_INDEX_INSERTED;
+
+ } else {
+
+ if (memcmp((PCHAR)GetIndexEntryValue(foundEntry)+KeyLength,
+ SecurityDescriptorHeader,
+ sizeof(SECURITY_DESCRIPTOR_HEADER))) {
+
+ if (CheckOnly)
+ return NTFS_SECURITY_INDEX_DATA_ERROR;
+
+ memcpy((PCHAR)GetIndexEntryValue(foundEntry)+KeyLength,
+ SecurityDescriptorHeader,
+ sizeof(SECURITY_DESCRIPTOR_HEADER));
+
+ if (!OldTree->DeleteEntry(KeyLength, Key, 0)) {
+ return NTFS_SECURITY_ERROR;
+ }
+
+ length = QuadAlign(sizeof(INDEX_ENTRY) +
+ KeyLength +
+ sizeof(SECURITY_DESCRIPTOR_HEADER));
+
+ if (!(newEntry = (PINDEX_ENTRY)MALLOC(length)))
+ return NTFS_SECURITY_ERROR;
+
+ memset((PVOID)newEntry, 0, length);
+
+ newEntry->DataOffset = sizeof(INDEX_ENTRY)+KeyLength;
+ newEntry->DataLength = sizeof(SECURITY_DESCRIPTOR_HEADER);
+ newEntry->Length = length;
+ newEntry->AttributeLength = KeyLength;
+ newEntry->Flags = 0;
+
+ memcpy(GetIndexEntryValue(newEntry), Key, KeyLength);
+ memcpy((PCHAR)GetIndexEntryValue(newEntry) + KeyLength,
+ SecurityDescriptorHeader,
+ sizeof(SECURITY_DESCRIPTOR_HEADER));
+
+ if ( !OldTree->InsertEntry( newEntry )) {
+ DELETE( newEntry );
+ return NTFS_SECURITY_INSERT_FAILED;
+ }
+
+ if (!OldTree->Save(this)) {
+ return NTFS_SECURITY_ERROR;
+ }
+
+ return NTFS_SECURITY_INDEX_FIXED;
+ }
+
+ if (containingBuffer)
+ DELETE(containingBuffer);
+
+ return NTFS_SECURITY_INDEX_FOUND;
+ }
+}
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::QueryDuplicatedInformation(
+ OUT PDUPLICATED_INFORMATION DuplicatedInformation
+ )
+/*++
+
+Routine Description:
+
+ This method queries the FRS for the information which is
+ duplicated in File Name attributes.
+
+Arguments:
+
+ DuplicatedInformation -- Receives the duplicated information.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+
+--*/
+{
+ NTFS_ATTRIBUTE Attribute;
+
+ STANDARD_INFORMATION StandardInformation;
+ EA_INFORMATION EaInformation;
+
+ ULONG BytesRead, ClusterSize;
+ BOOLEAN Error;
+
+ // Start with a clean slate:
+ //
+ memset( DuplicatedInformation, 0, sizeof( DUPLICATED_INFORMATION ) );
+
+ // Most of the duplicated information comes from the
+ // Standard Information attribute.
+ //
+ if( !QueryAttribute( &Attribute,
+ &Error,
+ $STANDARD_INFORMATION ) ||
+ !Attribute.Read( &StandardInformation,
+ 0,
+ sizeof( STANDARD_INFORMATION ),
+ &BytesRead ) ||
+ BytesRead != sizeof( STANDARD_INFORMATION ) ) {
+
+ DebugPrintf( "Can't fetch standard information.\n" );
+ return FALSE;
+ }
+
+ DuplicatedInformation->CreationTime =
+ StandardInformation.CreationTime;
+ DuplicatedInformation->LastModificationTime =
+ StandardInformation.LastModificationTime;
+ DuplicatedInformation->LastChangeTime =
+ StandardInformation.LastChangeTime;
+ DuplicatedInformation->LastAccessTime =
+ StandardInformation.LastAccessTime;
+
+ DuplicatedInformation->FileAttributes = StandardInformation.FileAttributes;
+
+ if( _FrsData->Flags & FILE_FILE_NAME_INDEX_PRESENT ) {
+
+ DuplicatedInformation->FileAttributes |= DUP_FILE_NAME_INDEX_PRESENT;
+ }
+
+ // We also need one field from the EA_INFORMATION attribute:
+ //
+ if( !QueryAttribute( &Attribute, &Error, $EA_INFORMATION )) {
+
+ if( Error ) {
+
+ // The Ea Information attribute is present, but we
+ // couldn't get it. Bail out.
+ //
+ DebugAbort( "Error fetching Ea Information attribute.\n" );
+ return FALSE;
+
+ } else {
+
+ // The Ea Information attribute is not present, which
+ // means this file has no EAs.
+
+ DuplicatedInformation->PackedEaSize = 0;
+ }
+
+ } else if( !Attribute.Read( &EaInformation,
+ 0,
+ sizeof( EA_INFORMATION ),
+ &BytesRead ) ||
+ BytesRead != sizeof( EA_INFORMATION ) ) {
+
+ // Couldn't read the Ea Information data.
+ //
+ DebugAbort( "Can't read EA Information.\n" );
+ return FALSE;
+
+ } else {
+
+ // We've got the Ea Information.
+ //
+ DuplicatedInformation->PackedEaSize = EaInformation.PackedEaSize;
+ }
+
+
+ // Now we grope the size of the unnamed $DATA attribute and we
+ // are done.
+ //
+
+ if( !QueryFileSizes( &(DuplicatedInformation->AllocatedLength),
+ &(DuplicatedInformation->FileSize),
+ &Error ) ) {
+
+ if( Error ) {
+
+ // The Data attribute is present, but we couldn't get it.
+ //
+ DebugAbort( "Error fetching $DATA attribute.\n" );
+ return FALSE;
+
+ } else {
+
+ // This file has no unnamed $DATA attribute.
+ //
+ DuplicatedInformation->AllocatedLength = 0;
+ DuplicatedInformation->FileSize = 0;
+ }
+
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::UpdateFileNames(
+ IN PDUPLICATED_INFORMATION DuplicatedInformation,
+ IN OUT PNTFS_INDEX_TREE Index,
+ IN BOOLEAN IgnoreExternal
+ )
+/*++
+
+Routine Description:
+
+ This method propagates
+
+Arguments:
+
+ DuplicatedInformation -- Supplies the duplicated information which
+ is to be propagated into the File Names.
+ Index -- Supplies the index for the directory which
+ contains this FRS. It may be NULL, in which
+ case changes are not propagated to the index.
+ IgnoreExternal -- Supplies a flag which, if TRUE, indicates
+ that this method should only update file
+ names in this FRS, and not in its children.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This method only propagates changes to the supplied index; thus,
+ if a file is indexed by more than one directory, changes can
+ only be propagated to one directory. However, all entries for
+ this file in the supplied index will be updated.
+
+--*/
+{
+ NTFS_ATTRIBUTE_RECORD CurrentRecord;
+ DSTRING Name;
+ MFT_SEGMENT_REFERENCE SegmentReference;
+
+ PNTFS_FILE_RECORD_SEGMENT ChildFrs;
+ LCN TargetFileNumber;
+ VCN LowestVcn;
+ ATTRIBUTE_TYPE_CODE CurrentType;
+ PFILE_NAME CurrentName;
+ PVOID CurrentRecordData;
+ ULONG ValueLength, RecordNumber;
+ USHORT Tag;
+
+ // Make sure that the supplied index, if any, is constructed
+ // over the FILE_NAME attribute:
+
+ if( Index != NULL &&
+ Index->QueryIndexedAttributeType() != $FILE_NAME ) {
+
+ DebugAbort( "Updating file names in an index that's not over $FILE_NAME.\n" );
+ return FALSE;
+ }
+
+ // Force the attribute list, if we have one, into memory.
+ //
+ if( !SetupAttributeList() ) {
+
+ return FALSE;
+ }
+
+ if( !IgnoreExternal &&
+ _AttributeList != NULL ) {
+
+ for( RecordNumber = 0;
+ _AttributeList->QueryEntry( RecordNumber,
+ &CurrentType,
+ &LowestVcn,
+ &SegmentReference,
+ &Tag,
+ &Name );
+ RecordNumber++ ) {
+
+ if( CurrentType == $FILE_NAME ) {
+
+ // The current entry represents a record for a
+ // File Name attribute, which we may wish to
+ // update. Figure out what FRS it's in:
+
+ TargetFileNumber.Set( SegmentReference.LowPart,
+ (LONG) SegmentReference.HighPart );
+
+ if( TargetFileNumber == QueryFileNumber() ) {
+
+ // This file name is in the base FRS, ie. in
+ // this FRS. Call this method recursively,
+ // with IgnoreExternal TRUE to limit the
+ // recursion.
+
+ if( !UpdateFileNames( DuplicatedInformation,
+ Index,
+ TRUE ) ) {
+ return FALSE;
+ }
+
+ } else {
+
+ // This attribute is in a child FRS. Get the
+ // child and update any file names in it. Note
+ // Note that we can ignore external names in
+ // the child, since child FRS's cannot have
+ // children. (Note also that this will preemptively
+ // update any other names in that child, which is
+ // fine.
+ //
+ if( (ChildFrs = SetupChild( TargetFileNumber )) == NULL ||
+ !ChildFrs->UpdateFileNames( DuplicatedInformation,
+ Index,
+ TRUE ) ) {
+
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ } else {
+
+ // Crawl through the records in this FRS looking for File Names.
+ //
+ CurrentRecordData = NULL;
+
+ while( (CurrentRecordData =
+ GetNextAttributeRecord( CurrentRecordData )) != NULL ) {
+
+ // Note that GetNextAttributeRecord always returns a
+ // structurally-sound attribute record, which we can
+ // pass directly to this flavor of Initialize, which
+ // in turn will always succeed. It is also important
+ // that this flavor of initialize will cause the
+ // attribute record to use directly the data in the
+ // File Record Segment, so we can twiddle it there.
+ //
+ if( !CurrentRecord.Initialize( CurrentRecordData ) ) {
+
+ DebugAbort( "Can't initialize attribute record.\n" );
+ return FALSE;
+ }
+
+ if( CurrentRecord.QueryTypeCode() == $FILE_NAME ) {
+
+ // It's a file name.
+
+ CurrentName = (PFILE_NAME)
+ (CurrentRecord.GetResidentValue() );
+
+ ValueLength = CurrentRecord.QueryResidentValueLength();
+
+ // Perform sanity checks--the attribute must be resident,
+ // big enough to be a File Name, and big enough to hold
+ // the name it claims to be.
+ //
+ if( CurrentName == NULL ||
+ ValueLength < sizeof( FILE_NAME ) ||
+ ValueLength < (ULONG)FIELD_OFFSET( FILE_NAME, FileName ) +
+ CurrentName->FileNameLength ) {
+
+ DebugAbort( "Corrupt file name.\n" );
+ return FALSE;
+ }
+
+ // OK, it's a valid file name. Update the duplicated
+ // information and propagate duplicated information and
+ // file name bits back to the index entry.
+ //
+ memcpy( &(CurrentName->Info),
+ DuplicatedInformation,
+ sizeof( DUPLICATED_INFORMATION ) );
+
+ // Update the corresponding entry in the index.
+ //
+
+ SegmentReference = ( IsBase() ) ?
+ QuerySegmentReference() :
+ QueryBaseFileRecordSegment();
+
+
+ if( Index != NULL &&
+ !Index->UpdateFileName( CurrentName,
+ SegmentReference ) ) {
+
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+VOID
+NTFS_FILE_RECORD_SEGMENT::SetLsn(
+ IN BIG_INT NewLsn
+ )
+/*++
+
+Routine Description:
+
+ This method sets the Lsn for the File Record Segment
+ and any of its children which are in memory.
+
+Arguments:
+
+ NewLsn -- Supplies the new LSN for this File Record
+ Segment and any available children.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PNTFS_FILE_RECORD_SEGMENT CurrentChild;
+
+ _FrsData->Lsn = NewLsn.GetLargeInteger();
+
+ _ChildIterator->Reset();
+
+ while( (CurrentChild = (PNTFS_FILE_RECORD_SEGMENT)
+ _ChildIterator->GetNext()) != NULL ) {
+
+ CurrentChild->SetLsn( NewLsn );
+ }
+}
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::Backtrack(
+ OUT PWSTRING Path
+ )
+/*++
+
+Routine Description:
+
+ This function finds a path from the root to this FRS. Note
+ that it does not detect cycles, and may enter into an infinite
+ loop if there is a cycle in the logical directory structure.
+
+ Note that the client must read this FRS before calling Backtrack.
+
+Arguments:
+
+ Path -- Receives the path.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ // First, check to see if this is the Root
+ //
+ if( QueryFileNumber() == ROOT_FILE_NAME_INDEX_NUMBER ) {
+
+ return( Path->Initialize( "\\" ) );
+ }
+
+ // Initialize the path to the empty string and then pass it
+ // to the worker routine.
+ //
+ return( Path->Initialize( "" ) &&
+ BacktrackWorker( Path ) );
+}
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::BacktrackWorker(
+ IN OUT PWSTRING Path
+ )
+/*++
+
+Routine Description:
+
+ This member function is a private worker routine for Backtrack;
+ it performs the actual work of constructing the path from the
+ root to this FRS.
+
+Arguments:
+
+ Path -- Receives the path to this FRS.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ NTFS_ATTRIBUTE FileNameAttribute;
+ NTFS_FILE_RECORD_SEGMENT ParentFrs;
+ VCN ParentFileNumber;
+ PCFILE_NAME FileName;
+ DSTRING FileNameString, Backslash;
+ BOOLEAN Error;
+
+ // Short circuit if this is the root--it doesn't add
+ // anything to the path.
+ //
+ if( QueryFileNumber() == ROOT_FILE_NAME_INDEX_NUMBER ) {
+
+ return TRUE;
+ }
+
+ // Extract a name from the FRS. Any name will do.
+ //
+ if( !QueryAttribute( &FileNameAttribute, &Error, $FILE_NAME ) ||
+ !FileNameAttribute.IsResident() ) {
+
+ return FALSE;
+ }
+
+ FileName = (PCFILE_NAME)FileNameAttribute.GetResidentValue();
+
+ ParentFileNumber.Set( FileName->ParentDirectory.LowPart,
+ (LONG)FileName->ParentDirectory.HighPart );
+
+ // If the parent FRS is not the root, initialize and read it,
+ // and then recurse into it.
+ //
+ if( ParentFileNumber != ROOT_FILE_NAME_INDEX_NUMBER &&
+ (!ParentFrs.Initialize( ParentFileNumber, _Mft ) ||
+ !ParentFrs.Read() ||
+ !ParentFrs.Backtrack( Path ) ) ) {
+
+ return FALSE;
+ }
+
+ // Now add this FRS's name to the path.
+ //
+ if( !Backslash.Initialize( "\\" ) ||
+ !FileNameString.Initialize( NtfsFileNameGetName( FileName ),
+ FileName->FileNameLength ) ||
+ !Path->Strcat( &Backslash ) ||
+ !Path->Strcat( &FileNameString ) ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_FILE_RECORD_SEGMENT::AddChild(
+ PNTFS_FILE_RECORD_SEGMENT ChildFrs
+ )
+/*++
+
+Routine Description:
+
+ This method adds a child File Record Segment to the list of
+ children. Management of that File Record Segment then passes
+ to the list.
+
+Arguments:
+
+ ChildFrs -- supplies a pointer to the child File Record Segment.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ _ChildIterator->Reset();
+
+ return( _Children.Insert( ChildFrs, _ChildIterator ) );
+}
+
+
+
+PNTFS_FILE_RECORD_SEGMENT
+NTFS_FILE_RECORD_SEGMENT::GetChild(
+ VCN FileNumber
+ )
+/*++
+
+Routine Description:
+
+ This method finds a File Record Segment in the list of children
+ based on its File Number.
+
+Arguments:
+
+ FileNumber -- supplies the file number of the desired child.
+
+Return Value:
+
+ A pointer to the desired File Record Segment. Note that this
+ object belongs to the child list, and should not be deleted by
+ the client.
+
+ NULL if the desired child could not be found in the list.
+
+--*/
+{
+ PNTFS_FILE_RECORD_SEGMENT CurrentChild;
+
+ // Spin through the list of children until we run out or find
+ // one with the appropriate VCN.
+
+ _ChildIterator->Reset();
+
+ while( (CurrentChild =
+ (PNTFS_FILE_RECORD_SEGMENT)_ChildIterator->GetNext()) != NULL &&
+ CurrentChild->QueryFileNumber() != FileNumber );
+
+ // If there is a matching child in the list, CurrentChild now points
+ // at it; otherwise, CurrentChild is NULL.
+
+ return CurrentChild;
+}
+
+
+PNTFS_FILE_RECORD_SEGMENT
+NTFS_FILE_RECORD_SEGMENT::SetupChild(
+ IN VCN FileNumber
+ )
+/*++
+
+Routine Description:
+
+ This method sets up a child FRS. If the desired child is already
+ in the list, it is returned; otherwise, it is allocated and read
+ and added to the list, and the returned.
+
+Arguments:
+
+ FileNumber -- Supplies the file number of the desired child.
+
+Return Value:
+
+ A pointer to the child FRS, or NULL to indicate error.
+
+--*/
+{
+ PNTFS_FILE_RECORD_SEGMENT ChildFrs;
+ PNTFS_MFT_FILE MftFile;
+
+ if( (ChildFrs = GetChild( FileNumber )) != NULL ) {
+
+ // The child is already in the list.
+ //
+ return ChildFrs;
+ }
+
+ // Allocate a new FRS object, initialize it to be the
+ // child we want, read it in, and add it to the list.
+ //
+ if( (ChildFrs = NEW NTFS_FILE_RECORD_SEGMENT) == NULL ) {
+
+ return NULL;
+ }
+
+ if( _Mft != NULL ) {
+
+ // This is an ordinary, run-of-the-mill File Record
+ // Segment, so just initialize the child with the
+ // same MFT as this object was initialized with.
+ //
+ if( !ChildFrs->Initialize( FileNumber, _Mft ) ||
+ !ChildFrs->Read() ||
+ !AddChild( ChildFrs ) ) {
+
+ DELETE( ChildFrs );
+ return NULL;
+ }
+
+ } else {
+
+ // This File Record Segment is really the
+ // MFT file itself, so we have to do some
+ // arcane gesticulation. Since we know this
+ // is really an NTFS_MFT_FILE object, we'll
+ // dynamically cast it to that class, and
+ // then pass it in as the NTFS_MFT_FILE to
+ // initialize the child.
+ //
+ if( QueryClassId() != NTFS_MFT_FILE_cd->QueryClassId() ) {
+
+ DELETE( ChildFrs );
+ return FALSE;
+ }
+
+ MftFile = (PNTFS_MFT_FILE)( this );
+
+ if( !ChildFrs->Initialize( FileNumber, MftFile ) ||
+ !ChildFrs->Read() ||
+ !AddChild( ChildFrs ) ) {
+
+ DELETE( ChildFrs );
+ return FALSE;
+ }
+ }
+
+ return ChildFrs;
+}
+
+
+VOID
+NTFS_FILE_RECORD_SEGMENT::DeleteChild(
+ VCN FileNumber
+ )
+/*++
+
+Routine Description:
+
+ This method removes a File Record Segment from the list of
+ children based on its File Number.
+
+Arguments:
+
+ FileNumber -- supplies the file number of the child to delete.
+
+Return Value:
+
+ None.
+
+Notes:
+
+ Since the list manages the File Record Segments which it has been
+ given, it deletes the File Record Segment in question.
+
+ This method assumes that only one matching child exists (since the
+ same File Record Segment should not appear twice in the list).
+
+--*/
+{
+ PNTFS_FILE_RECORD_SEGMENT CurrentChild, ChildToDelete;
+
+ // Spin through the list of children until we run out or find
+ // one with the appropriate VCN.
+
+ _ChildIterator->Reset();
+
+ while( (CurrentChild =
+ (PNTFS_FILE_RECORD_SEGMENT)_ChildIterator->GetNext()) != NULL &&
+ CurrentChild->QueryFileNumber() != FileNumber );
+
+ // If there is a matching child in the list, the iterator's current
+ // state points at it and CurrentChild is non-NULL.
+
+ if( CurrentChild != NULL ) {
+
+ // A matching child was found; remove it from the list
+ // and delete it.
+
+ ChildToDelete = (PNTFS_FILE_RECORD_SEGMENT)
+ _Children.Remove( _ChildIterator );
+
+ DebugAssert( ChildToDelete == CurrentChild );
+
+ DELETE( ChildToDelete );
+ }
+}
diff --git a/private/utils/untfs/src/frsstruc.cxx b/private/utils/untfs/src/frsstruc.cxx
new file mode 100644
index 000000000..e9e9150cb
--- /dev/null
+++ b/private/utils/untfs/src/frsstruc.cxx
@@ -0,0 +1,1870 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "untfs.hxx"
+#include "frsstruc.hxx"
+#include "mem.hxx"
+#include "attrib.hxx"
+#include "drive.hxx"
+#include "clusrun.hxx"
+#include "wstring.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+#include "attrrec.hxx"
+#include "attrlist.hxx"
+#include "ntfsbit.hxx"
+#include "bigint.hxx"
+#include "numset.hxx"
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( NTFS_FRS_STRUCTURE, OBJECT, UNTFS_EXPORT );
+
+
+UNTFS_EXPORT
+NTFS_FRS_STRUCTURE::~NTFS_FRS_STRUCTURE(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for NTFS_FRS_STRUCTURE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+NTFS_FRS_STRUCTURE::Construct(
+ )
+/*++
+
+Routine Description:
+
+ This routine initialize this class to a default state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _FrsData = NULL;
+ _secrun = NULL;
+ _mftdata = NULL;
+ _file_number = 0;
+ _cluster_factor = 0;
+ _size = 0;
+ _drive = NULL;
+ _volume_sectors = 0;
+ _upcase_table = NULL;
+}
+
+
+
+VOID
+NTFS_FRS_STRUCTURE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns this class to a default state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _FrsData = NULL;
+ DELETE(_secrun);
+ _mftdata = NULL;
+ _file_number = 0;
+ _cluster_factor = 0;
+ _size = 0;
+ _drive = NULL;
+ _volume_sectors = 0;
+ _upcase_table = NULL;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_FRS_STRUCTURE::Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PNTFS_ATTRIBUTE MftData,
+ IN VCN FileNumber,
+ IN ULONG ClusterFactor,
+ IN BIG_INT VolumeSectors,
+ IN ULONG FrsSize,
+ IN PNTFS_UPCASE_TABLE UpcaseTable
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes a NTFS_FRS_STRUCTURE to a valid
+ initial state.
+
+Arguments:
+
+ Mem - Supplies memory for the FRS.
+ MftData - Supplies the $DATA attribute of the MFT.
+ FileNumber - Supplies the file number for this FRS.
+ ClusterFactor - Supplies the number of sectors per cluster.
+ VolumeSectors - Supplies the number of volume sectors.
+ FrsSize - Supplies the size of each frs, in bytes.
+ UpcaseTable - Supplies the volume upcase table.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+Notes:
+
+ The client may supply NULL for the upcase table, but then
+ it cannot manipulate named attributes until the ucpase
+ table is set.
+
+--*/
+{
+ Destroy();
+
+ DebugAssert(Mem);
+ DebugAssert(MftData);
+ DebugAssert(ClusterFactor);
+
+ _mftdata = MftData;
+ _file_number = FileNumber;
+ _cluster_factor = ClusterFactor;
+ _drive = MftData->GetDrive();
+ _size = FrsSize;
+ _volume_sectors = VolumeSectors;
+ _upcase_table = UpcaseTable;
+
+ DebugAssert(_drive);
+ DebugAssert(_drive->QuerySectorSize());
+
+ _FrsData = (PFILE_RECORD_SEGMENT_HEADER)
+ Mem->Acquire(QuerySize(), _drive->QueryAlignmentMask());
+
+ if (!_FrsData) {
+ Destroy();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_FRS_STRUCTURE::Initialize(
+ IN OUT PMEM Mem,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN LCN StartOfFrs,
+ IN ULONG ClusterFactor,
+ IN BIG_INT VolumeSectors,
+ IN ULONG FrsSize,
+ IN PNTFS_UPCASE_TABLE UpcaseTable,
+ IN ULONG Offset
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes an NTFS_FRS_STRUCTURE to point at one
+ of the low frs's.
+
+Arguments:
+
+ Mem - Supplies memory for the FRS.
+ Drive - Supplies the drive.
+ StartOfFrs - Supplies the starting LCN for the frs.
+ ClusterFactor - Supplies the number of sectors per cluster.
+ UpcaseTable - Supplies the volume upcase table.
+ FrsSize - Supplies the size of frs 0 in bytes.
+ Offset - Supplies the offset in the cluster for the frs.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+Notes:
+
+ The client may supply NULL for the upcase table; in that case,
+ the FRS cannot manipulate named attributes until the upcase
+ table is set.
+
+--*/
+{
+ Destroy();
+
+ DebugAssert(Mem);
+ DebugAssert(Drive);
+
+ _file_number = 0;
+ _cluster_factor = ClusterFactor;
+ _drive = Drive;
+ _size = FrsSize;
+ _volume_sectors = VolumeSectors;
+ _upcase_table = UpcaseTable;
+
+ //
+ // Our SECRUN will need to hold the one or more sectors occupied
+ // by this frs.
+ //
+
+#define BYTES_TO_SECTORS(bytes, sector_size) \
+ (((bytes) + ((sector_size) - 1))/(sector_size))
+
+ ULONG sectors_per_frs = BYTES_TO_SECTORS(FrsSize,
+ Drive->QuerySectorSize());
+
+ if (!(_secrun = NEW SECRUN) ||
+ !_secrun->Initialize(Mem,
+ Drive,
+ StartOfFrs * QueryClusterFactor() +
+ Offset/Drive->QuerySectorSize(),
+ sectors_per_frs)) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ _FrsData = (PFILE_RECORD_SEGMENT_HEADER)_secrun->GetBuf();
+
+ DebugAssert(_FrsData);
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_FRS_STRUCTURE::VerifyAndFix(
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN PCNTFS_ATTRIBUTE_COLUMNS AttributeDefTable,
+ IN OUT PBOOLEAN DiskErrorsFound
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies, and if necessary, fixes an NTFS_FRS_STRUCTURE.
+
+ This routine will clear the IN_USE bit on this FRS if the FRS is
+ completely hosed.
+
+Arguments:
+
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages.
+ AttributeDefTable - Supplies an attribute definition table.
+ DiskErrorsFound - Supplies whether or not disk errors have
+ been found.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PATTRIBUTE_RECORD_HEADER pattr;
+ NTFS_ATTRIBUTE_RECORD attr;
+ DSTRING string;
+ BOOLEAN changes, duplicates;
+ BOOLEAN need_write;
+ DSTRING null_string;
+ BOOLEAN errors_found;
+ NUMBER_SET instance_numbers;
+ BOOLEAN standard_info_found;
+ PSTANDARD_INFORMATION pstandard;
+
+ if (!null_string.Initialize("\"\"") ||
+ !instance_numbers.Initialize()) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ need_write = FALSE;
+
+ // First make sure that the update sequence array precedes the
+ // attribute records and that the two don't overlap.
+
+ if (_FrsData->MultiSectorHeader.Signature[0] != 'F' ||
+ _FrsData->MultiSectorHeader.Signature[1] != 'I' ||
+ _FrsData->MultiSectorHeader.Signature[2] != 'L' ||
+ _FrsData->MultiSectorHeader.Signature[3] != 'E' ||
+
+ _FrsData->MultiSectorHeader.UpdateSequenceArrayOffset <
+ FIELD_OFFSET(FILE_RECORD_SEGMENT_HEADER, UpdateArrayForCreateOnly) ||
+
+ _FrsData->MultiSectorHeader.UpdateSequenceArrayOffset +
+ _FrsData->MultiSectorHeader.UpdateSequenceArraySize *
+ sizeof(UPDATE_SEQUENCE_NUMBER) > _FrsData->FirstAttributeOffset ||
+
+ _FrsData->FirstAttributeOffset + sizeof(ATTRIBUTE_TYPE_CODE) >
+ QuerySize() ||
+
+ _FrsData->MultiSectorHeader.UpdateSequenceArrayOffset %
+ sizeof(UPDATE_SEQUENCE_NUMBER) ||
+
+ !IsQuadAligned(_FrsData->FirstAttributeOffset) ||
+
+ _FrsData->MultiSectorHeader.UpdateSequenceArraySize !=
+ QuerySize()/SEQUENCE_NUMBER_STRIDE + 1 ||
+
+ QuerySize() % SEQUENCE_NUMBER_STRIDE != 0 ||
+
+ _FrsData->BytesAvailable != QuerySize()) {
+
+ Message->Set(MSG_CHK_NTFS_BAD_FRS);
+ Message->Display("%d", QueryFileNumber().GetLowPart());
+ ClearInUse();
+
+ if (DiskErrorsFound) {
+ *DiskErrorsFound = TRUE;
+ }
+
+ if (FixLevel != CheckOnly && !Write()) {
+
+ DebugAbort("Could not write a readable sector");
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+
+ // If this is the MFT then make sure that the Sequence Number
+ // is not zero.
+
+ if (_FrsData->SequenceNumber == 0 && QueryFileNumber() == 0) {
+
+ Message->Set(MSG_CHK_NTFS_MINOR_CHANGES_TO_FRS);
+ Message->Display("%d", QueryFileNumber().GetLowPart());
+
+ _FrsData->SequenceNumber = 1;
+ need_write = TRUE;
+ }
+
+
+ // Validate the stucture of the list of attribute records,
+ // make sure that there are no special attributes with names,
+ // and make sure that all of the attribute records are well
+ // composed.
+
+ pattr = NULL;
+ while (pattr = (PATTRIBUTE_RECORD_HEADER)
+ GetNextAttributeRecord(pattr, Message, &errors_found)) {
+
+ need_write = need_write || errors_found;
+
+ // Make sure that the attribute record is in good shape.
+ // Don't account for it's disk space yet.
+ // Make sure that the attribute instance number is not duplicated.
+
+ if (!attr.Initialize(pattr)) {
+ DebugAbort("Could not initialize attribute record.");
+ return FALSE;
+ }
+
+ if (!attr.Verify(AttributeDefTable, FALSE) ||
+ instance_numbers.DoesIntersectSet((ULONG) pattr->Instance, 1) ||
+ pattr->Instance >= _FrsData->NextAttributeInstance) {
+
+ if (!attr.QueryName(&string)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ Message->Set(MSG_CHK_NTFS_BAD_ATTR);
+ Message->Display("%d%W%d", pattr->TypeCode,
+ string.QueryChCount() ? &string : &null_string,
+ QueryFileNumber().GetLowPart());
+
+ DeleteAttributeRecord(pattr);
+
+ if (!instance_numbers.Initialize()) {
+ DebugAbort("Can't initialize trivial number set");
+ return FALSE;
+ }
+
+ need_write = TRUE;
+ pattr = NULL;
+ continue;
+ }
+
+ if (!instance_numbers.Add((ULONG) pattr->Instance)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ need_write = need_write || errors_found;
+
+
+ // Sort the base FRS attribute records by type, and name.
+ // This method will also eliminate duplicates.
+
+ if (!Sort(&changes, &duplicates)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (duplicates || (changes && IsBase())) {
+ Message->Set(MSG_CHK_NTFS_UNSORTED_FRS);
+ Message->Display("%d", QueryFileNumber().GetLowPart());
+ need_write = TRUE;
+ }
+
+
+ // Detect whether or not there is a $STANDARD_INFORMATION.
+
+ standard_info_found = FALSE;
+ pattr = NULL;
+ while (pattr = (PATTRIBUTE_RECORD_HEADER) GetNextAttributeRecord(pattr)) {
+ if (pattr->TypeCode == $STANDARD_INFORMATION) {
+
+ standard_info_found = TRUE;
+
+ // Make sure that if this is a system file than the
+ // system and hidden bits are set in the $STANDARD_INFORMATION.
+
+ if (QueryFileNumber() < FIRST_USER_FILE_NUMBER) {
+ pstandard = (PSTANDARD_INFORMATION)
+ ((PCHAR) pattr + pattr->Form.Resident.ValueOffset);
+
+ if (!(pstandard->FileAttributes&FAT_DIRENT_ATTR_HIDDEN) ||
+ !(pstandard->FileAttributes&FAT_DIRENT_ATTR_SYSTEM)) {
+
+ pstandard->FileAttributes |= FAT_DIRENT_ATTR_HIDDEN;
+ pstandard->FileAttributes |= FAT_DIRENT_ATTR_SYSTEM;
+
+ Message->Set(MSG_CHK_NTFS_MINOR_CHANGES_TO_FRS);
+ Message->Display("%d", QueryFileNumber().GetLowPart());
+ need_write = TRUE;
+ }
+ }
+ break;
+ }
+ }
+
+ if (IsBase() && !standard_info_found) {
+
+ Message->Set(MSG_CHK_NTFS_BAD_FRS);
+ Message->Display("%d", QueryFileNumber().GetLowPart());
+ ClearInUse();
+ need_write = TRUE;
+ }
+
+
+ // Write out changes if necessary.
+
+ if (need_write) {
+
+ if (DiskErrorsFound) {
+ *DiskErrorsFound = TRUE;
+ }
+
+ if (FixLevel != CheckOnly && !Write()) {
+
+ DebugAbort("Could not write a readable sector");
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_FRS_STRUCTURE::LoneFrsAllocationCheck(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNTFS_CHKDSK_REPORT ChkdskReport,
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN DiskErrorsFound
+ )
+/*++
+
+Routine Description:
+
+ This routine checks the allocation of the attribute records in
+ the given FRS under the presumption that there is no attribute
+ list for this FRS and that this FRS is a base FRS.
+
+Arguments:
+
+ VolumeBitmap - Supplies a volume bitmap on which to mark off
+ the non-resident attribute records'
+ allocations.
+ ChkdskReport - Supplies the current chkdsk report to be updated
+ with the statistics from this file.
+ ChkdskInfo - Supplies the chkdsk information.
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages.
+ DiskErrorsFound - Supplies whether or not disk errors have
+ been found.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PVOID pattr, next_attribute;
+ NTFS_ATTRIBUTE_RECORD attribute_record;
+ DSTRING string;
+ DSTRING null_string;
+ BIG_INT file_length;
+ BIG_INT alloc_length;
+ BIG_INT total_allocated;
+ BIG_INT compute_alloc_length;
+ BIG_INT compute_total_allocated;
+ BIG_INT cluster_count;
+ BOOLEAN changes;
+ BIG_INT total_user_bytes;
+ ATTRIBUTE_TYPE_CODE type_code;
+ BOOLEAN user_file;
+ BOOLEAN got_allow_cross_link;
+
+ DebugAssert(VolumeBitmap);
+ DebugAssert(Message);
+
+ user_file = FALSE;
+ changes = FALSE;
+ pattr = NULL;
+ total_user_bytes = 0;
+ pattr = GetNextAttributeRecord(NULL);
+
+ while (pattr) {
+
+ if (!attribute_record.Initialize(pattr)) {
+
+ DebugAbort("Can't initialize attribute record");
+ return FALSE;
+ }
+
+ if (attribute_record.IsResident()) {
+
+ compute_alloc_length = 0;
+ cluster_count = 0;
+
+ } else {
+
+ compute_alloc_length = (attribute_record.QueryNextVcn() -
+ attribute_record.QueryLowestVcn())*
+ QueryClusterFactor()*
+ _drive->QuerySectorSize();
+
+ attribute_record.QueryValueLength(&file_length, &alloc_length,
+ NULL, &total_allocated);
+
+ if (attribute_record.QueryLowestVcn() != 0 ||
+ compute_alloc_length != alloc_length ||
+ !attribute_record.UseClusters(VolumeBitmap,
+ &cluster_count,
+ ChkdskInfo->CrossLinkStart,
+ ChkdskInfo->CrossLinkYet ? 0 :
+ ChkdskInfo->CrossLinkLength,
+ &got_allow_cross_link)) {
+
+ DebugPrintf("Attribute %d has either a cross-link or a bad allocation length\n",
+ attribute_record.QueryTypeCode());
+
+ // The lowest vcn must be zero and
+ // the allocated length must match the length allocated and
+ // the allocated space must be available in the volume
+ // bitmap.
+ // So tube this attribute record.
+
+ if (!null_string.Initialize("\"\"") ||
+ !attribute_record.QueryName(&string)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ Message->Set(MSG_CHK_NTFS_BAD_ATTR);
+ Message->Display("%d%W%d", attribute_record.QueryTypeCode(),
+ string.QueryChCount() ? &string : &null_string,
+ QueryFileNumber().GetLowPart());
+
+ next_attribute = GetNextAttributeRecord(pattr);
+
+ DeleteAttributeRecord(pattr);
+ changes = TRUE;
+
+ // Do not increment pattr--DeleteAttributeRecord
+ // will bring the next attribute record down to us.
+ //
+ if( !next_attribute ) {
+
+ // The deleted attribute record was the
+ // last in this FRS.
+ //
+ break;
+ }
+
+ continue;
+ }
+
+//+++
+//ZZZ
+ if ((attribute_record.QueryFlags() &
+ ATTRIBUTE_FLAG_COMPRESSION_MASK) != 0) {
+
+ NTFS_EXTENT_LIST extent_list;
+
+ if (!attribute_record.QueryExtentList(&extent_list)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ compute_total_allocated = extent_list.QueryClustersAllocated() *
+ QueryClusterFactor() * _drive->QuerySectorSize();
+
+ if (compute_total_allocated != total_allocated) {
+
+ DebugPrintf("Attribute %d has bad total allocated\n",
+ attribute_record.QueryTypeCode());
+
+ Message->Set(MSG_CHK_NTFS_FIX_ATTR);
+ Message->Display("%d%W%d", attribute_record.QueryTypeCode(),
+ string.QueryChCount() ? &string : &null_string,
+ QueryFileNumber().GetLowPart());
+
+ attribute_record.SetTotalAllocated(compute_total_allocated);
+
+ changes = TRUE;
+ }
+ }
+//---
+
+ if (got_allow_cross_link) {
+ ChkdskInfo->CrossLinkYet = TRUE;
+ ChkdskInfo->CrossLinkedFile = QueryFileNumber().GetLowPart();
+ ChkdskInfo->CrossLinkedAttribute =
+ attribute_record.QueryTypeCode();
+ if (!attribute_record.QueryName(&ChkdskInfo->CrossLinkedName)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+ }
+
+ type_code = attribute_record.QueryTypeCode();
+
+ if (type_code == $DATA ||
+ type_code == $EA_DATA ||
+ type_code >= $FIRST_USER_DEFINED_ATTRIBUTE) {
+
+ user_file = TRUE;
+ total_user_bytes += cluster_count *
+ QueryClusterFactor()*
+ _drive->QuerySectorSize();
+ }
+
+ pattr = GetNextAttributeRecord(pattr);
+ }
+
+ if (changes && DiskErrorsFound) {
+ *DiskErrorsFound = TRUE;
+ }
+
+ if (changes && FixLevel != CheckOnly && !Write()) {
+ DebugAbort("readable FRS is unwriteable");
+ return FALSE;
+ }
+
+ if (QueryFileNumber() >= FIRST_USER_FILE_NUMBER && user_file) {
+ ChkdskReport->NumUserFiles += 1;
+ ChkdskReport->BytesUserData += total_user_bytes;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+NTFS_FRS_STRUCTURE::CheckInstanceTags(
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ OUT PBOOLEAN Changes,
+ IN OUT PNTFS_ATTRIBUTE_LIST AttributeList
+ )
+/*++
+
+Routine Description:
+
+ This routine attempts to prevent the instance tags on the
+ FRS_STRUCTURE from rolling over... if we see that the next
+ instance tag field is above a reasonable value, we renumber
+ the instance tags in the attribute records and reset the
+ next instance tag field to the lowest acceptable value.
+
+Arguments:
+
+ AttributeList - NULL if we're checking a lone frs, otherwise
+ changes to instance tags require us to update
+ this attribute list as well.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PVOID pattr;
+ NTFS_ATTRIBUTE_RECORD attr_rec;
+ BOOLEAN errors;
+ USHORT instance_tag;
+ DSTRING Name;
+
+ if (_FrsData->NextAttributeInstance <= ATTRIBUTE_INSTANCE_TAG_THRESHOLD) {
+ *Changes = FALSE;
+ return TRUE;
+ }
+
+ Message->Set(MSG_CHK_NTFS_ADJUSTING_INSTANCE_TAGS);
+ Message->Display("%d", _file_number.GetLowPart());
+
+ *Changes = TRUE;
+
+ instance_tag = 0;
+ pattr = NULL;
+ while (NULL != (pattr = (PNTFS_ATTRIBUTE_RECORD)GetNextAttributeRecord(
+ pattr ))) {
+
+ if (!attr_rec.Initialize(pattr)) {
+ return FALSE;
+ }
+
+ if (NULL != AttributeList &&
+ $ATTRIBUTE_LIST != attr_rec.QueryTypeCode()) {
+
+ if (!AttributeList->ModifyInstanceTag(&attr_rec,
+ QuerySegmentReference(),
+ instance_tag)) {
+ DebugAbort("UNTFS: Could not find attribute in attr list.");
+ return FALSE;
+ }
+ }
+
+ attr_rec.SetInstanceTag(instance_tag);
+
+ instance_tag++;
+ }
+
+ _FrsData->NextAttributeInstance = instance_tag;
+
+ if (FixLevel != CheckOnly && !Write()) {
+ DebugAbort("UNTFS: Once readable frs struct is unwriteable");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_FRS_STRUCTURE::Read(
+ )
+/*++
+
+Routine Description:
+
+ This routine reads the FRS in from disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG bytes;
+ BOOLEAN r;
+
+ DebugAssert(_mftdata || _secrun);
+
+ if (_mftdata) {
+
+ r = _mftdata->Read(_FrsData,
+ _file_number*QuerySize(),
+ QuerySize(),
+ &bytes) &&
+ bytes == QuerySize();
+
+ } else {
+ r = _secrun->Read();
+ }
+
+ return r && NTFS_SA::PostReadMultiSectorFixup(_FrsData, QuerySize());
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_FRS_STRUCTURE::Write(
+ )
+/*++
+
+Routine Description:
+
+ This routine writes the FRS to disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG bytes;
+ BOOLEAN r;
+
+ DebugAssert(_mftdata || _secrun);
+
+ NTFS_SA::PreWriteMultiSectorFixup(_FrsData, QuerySize());
+
+ if (_mftdata) {
+
+ r = _mftdata->Write(_FrsData,
+ _file_number*QuerySize(),
+ QuerySize(),
+ &bytes,
+ NULL) &&
+ bytes == QuerySize();
+
+ } else {
+ r = _secrun->Write();
+ }
+
+ NTFS_SA::PostReadMultiSectorFixup(_FrsData, QuerySize());
+
+ return r;
+}
+
+
+UNTFS_EXPORT
+PVOID
+NTFS_FRS_STRUCTURE::GetNextAttributeRecord(
+ IN PCVOID AttributeRecord,
+ IN OUT PMESSAGE Message,
+ OUT PBOOLEAN ErrorsFound
+ )
+/*++
+
+Routine Description:
+
+ This routine gets the next attribute record in the file record
+ segment assuming that 'AttributeRecord' points to a valid
+ attribute record. If NULL is given as the first argument then
+ the first attribute record is returned.
+
+Arguments:
+
+ AttributeRecord - Supplies a pointer to the current attribute record.
+ Message - Supplies an outlet for error processing.
+ ErrorsFound - Supplies whether or not errors were found and
+ corrected in the FRS.
+
+Return Value:
+
+ A pointer to the next attribute record or NULL if there are no more.
+
+--*/
+{
+ PATTRIBUTE_RECORD_HEADER p;
+ PCHAR q;
+ PCHAR next_frs;
+ ULONG bytes_free;
+
+ DebugAssert(_FrsData);
+
+ if (ErrorsFound) {
+ *ErrorsFound = FALSE;
+ }
+
+ next_frs = (PCHAR) _FrsData + QuerySize();
+
+ if (!AttributeRecord) {
+
+ // Make sure the FirstAttributeOffset field will give us a properly
+ // aligned pointer. If not, bail.
+ //
+
+ if (_FrsData->FirstAttributeOffset % 4 != 0) {
+
+ return NULL;
+ }
+
+ AttributeRecord = (PCHAR) _FrsData + _FrsData->FirstAttributeOffset;
+
+ p = (PATTRIBUTE_RECORD_HEADER) AttributeRecord;
+ q = (PCHAR) AttributeRecord;
+
+ if (q + QuadAlign(sizeof(ATTRIBUTE_TYPE_CODE)) > next_frs) {
+
+ // There is no way to correct this error.
+ // The FRS is totally hosed, this will also be detected
+ // by VerifyAndFix. I can't really say *ErrorsFound = TRUE
+ // because the error was not corrected. I also cannot
+ // update the firstfreebyte and bytesfree fields.
+
+ return NULL;
+ }
+
+ if (p->TypeCode != $END) {
+
+ if (q + sizeof(ATTRIBUTE_TYPE_CODE) + sizeof(ULONG) > next_frs ||
+ !p->RecordLength ||
+ !IsQuadAligned(p->RecordLength) ||
+ q + p->RecordLength + sizeof(ATTRIBUTE_TYPE_CODE) > next_frs) {
+
+ p->TypeCode = $END;
+
+ bytes_free = (next_frs - q) -
+ QuadAlign(sizeof(ATTRIBUTE_TYPE_CODE));
+
+ _FrsData->FirstFreeByte = QuerySize() - bytes_free;
+
+ if (ErrorsFound) {
+ *ErrorsFound = TRUE;
+ }
+
+ if (Message) {
+ Message->Set(MSG_CHK_NTFS_FRS_TRUNC_RECORDS);
+ Message->Display("%d", QueryFileNumber().GetLowPart());
+ }
+
+ return NULL;
+ }
+ }
+
+ } else {
+
+ // Assume that the attribute record passed in is good.
+
+ p = (PATTRIBUTE_RECORD_HEADER) AttributeRecord;
+ q = (PCHAR) AttributeRecord;
+
+ q += p->RecordLength;
+ p = (PATTRIBUTE_RECORD_HEADER) q;
+ }
+
+
+ if (p->TypeCode == $END) {
+
+ // Update the bytes free and first free fields.
+
+ bytes_free = (next_frs - q) - QuadAlign(sizeof(ATTRIBUTE_TYPE_CODE));
+
+ if (_FrsData->FirstFreeByte + bytes_free != QuerySize()) {
+
+ _FrsData->FirstFreeByte = QuerySize() - bytes_free;
+
+ if (ErrorsFound) {
+ *ErrorsFound = TRUE;
+ }
+
+ if (Message) {
+ Message->Set(MSG_CHK_NTFS_BAD_FIRST_FREE);
+ Message->Display("%d", QueryFileNumber().GetLowPart());
+ }
+ }
+
+ return NULL;
+ }
+
+
+ // Make sure the attribute record is good.
+
+ if (q + sizeof(ATTRIBUTE_TYPE_CODE) + sizeof(ULONG) > next_frs ||
+ !p->RecordLength ||
+ !IsQuadAligned(p->RecordLength) ||
+ q + p->RecordLength + QuadAlign(sizeof(ATTRIBUTE_TYPE_CODE)) > next_frs) {
+
+ p->TypeCode = $END;
+
+ bytes_free = (next_frs - q) - QuadAlign(sizeof(ATTRIBUTE_TYPE_CODE));
+
+ _FrsData->FirstFreeByte = QuerySize() - bytes_free;
+
+ if (ErrorsFound) {
+ *ErrorsFound = TRUE;
+ }
+
+ if (Message) {
+ Message->Set(MSG_CHK_NTFS_FRS_TRUNC_RECORDS);
+ Message->Display("%d", QueryFileNumber().GetLowPart());
+ }
+
+ return NULL;
+ }
+
+ return p;
+}
+
+
+VOID
+NTFS_FRS_STRUCTURE::DeleteAttributeRecord(
+ IN OUT PVOID AttributeRecord
+ )
+/*++
+
+Routine Description:
+
+ This routine removes the pointed to attribute record from the
+ file record segment. The pointer passed in will point to
+ the next attribute record
+
+Arguments:
+
+ AttributeRecord - Supplies a valid pointer to an attribute record.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PATTRIBUTE_RECORD_HEADER p;
+ PCHAR end;
+ PCHAR frs_end;
+
+ DebugAssert(AttributeRecord);
+
+ p = (PATTRIBUTE_RECORD_HEADER) AttributeRecord;
+
+ DebugAssert(p->TypeCode != $END);
+
+ end = ((PCHAR) p) + p->RecordLength;
+ frs_end = ((PCHAR) _FrsData) + QuerySize();
+
+ DebugAssert(end < frs_end);
+
+ memmove(p, end, frs_end - end);
+
+ // This loop is here to straighten out the attribute records.
+ p = NULL;
+ while (p = (PATTRIBUTE_RECORD_HEADER) GetNextAttributeRecord(p)) {
+ }
+}
+
+
+BOOLEAN
+NTFS_FRS_STRUCTURE::InsertAttributeRecord(
+ IN OUT PVOID Position,
+ IN PCVOID AttributeRecord
+ )
+/*++
+
+Routine Description:
+
+ This routine inserts the attribute record pointed to by
+ 'AttributeRecord' before the attribute record pointed to
+ by Position. When this routine is done, 'Position' will
+ point to the copy of the attribute record just inserted
+ inside this file record segment.
+
+Arguments:
+
+ Position - Supplies a pointer to the attribute record that
+ will follow the attribute record to insert.
+ AttributeRecord - Supplies the attribute record to insert.
+
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PATTRIBUTE_RECORD_HEADER pos, attr;
+ PCHAR dest, frs_end;
+
+ DebugAssert(Position);
+ DebugAssert(AttributeRecord);
+
+ pos = (PATTRIBUTE_RECORD_HEADER) Position;
+ attr = (PATTRIBUTE_RECORD_HEADER) AttributeRecord;
+
+ if (attr->RecordLength > QueryAvailableSpace()) {
+ return FALSE;
+ }
+
+ dest = (PCHAR) pos + attr->RecordLength;
+ frs_end = (PCHAR) _FrsData + QuerySize();
+
+ memmove(dest, pos, frs_end - dest);
+
+ memcpy(pos, attr, (UINT) attr->RecordLength);
+
+ // This loop is here to straighten out the attribute records.
+ pos = NULL;
+ while (pos = (PATTRIBUTE_RECORD_HEADER) GetNextAttributeRecord(pos)) {
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_FRS_STRUCTURE::QueryAttributeList(
+ OUT PNTFS_ATTRIBUTE_LIST AttributeList
+ )
+/*++
+
+Routine Description:
+
+ This method fetches the Attribute List Attribute from this
+ File Record Segment.
+
+Arguments:
+
+ AttributeList - Returns A pointer to the Attribute List Attribute.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PATTRIBUTE_RECORD_HEADER prec;
+ NTFS_ATTRIBUTE_RECORD record;
+
+ return (prec = (PATTRIBUTE_RECORD_HEADER) GetAttributeList()) &&
+ record.Initialize(prec) &&
+ AttributeList->Initialize(GetDrive(), QueryClusterFactor(),
+ &record,
+ GetUpcaseTable());
+}
+
+
+NONVIRTUAL
+PVOID
+NTFS_FRS_STRUCTURE::GetAttribute(
+ IN ULONG TypeCode
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the unnamed attribute with the
+ given type code or NULL if this attribute does not exist.
+
+Arguments:
+
+ TypeCode - Supplies the type code of the attribute to search for.
+
+Return Value:
+
+ A pointer to an attribute or NULL if there none was found.
+
+--*/
+{
+ PATTRIBUTE_RECORD_HEADER prec;
+
+ prec = NULL;
+ while (prec = (PATTRIBUTE_RECORD_HEADER) GetNextAttributeRecord(prec)) {
+
+ if (prec->TypeCode == TypeCode &&
+ prec->NameLength == 0) {
+ break;
+ }
+ }
+
+ return prec;
+}
+
+
+NONVIRTUAL
+PVOID
+NTFS_FRS_STRUCTURE::GetAttributeList(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the attribute list or NULL if
+ there is no attribute list.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the attribute list or NULL if there is no attribute list.
+
+--*/
+{
+ return GetAttribute($ATTRIBUTE_LIST);
+}
+
+
+BOOLEAN
+NTFS_FRS_STRUCTURE::UpdateAttributeList(
+ IN PCNTFS_ATTRIBUTE_LIST AttributeList,
+ IN BOOLEAN WriteFrs
+ )
+/*++
+
+Routine Description:
+
+ This routine updates the local $ATTRIBUTE_LIST with the
+ attribute list provided. 'AttributeList' must be smaller
+ than or equal (and of the form) to the the local
+ $ATTRIBUTE_LIST in order for this method to be guaranteed
+ to succeed.
+
+Arguments:
+
+ AttributeList - Supplies a valid attribute list.
+ WriteFrs - State whether or not to write the FRS when done.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_ATTRIBUTE_RECORD attribute;
+ PATTRIBUTE_RECORD_HEADER old_attr, new_attr;
+
+ DebugAssert(AttributeList);
+
+
+ // Don't do anything if the attribute list hasn't changed.
+
+ if (!AttributeList->IsStorageModified()) {
+ return TRUE;
+ }
+
+
+ // Allocate some storage for the new attribute record.
+
+ if (!(new_attr = (PATTRIBUTE_RECORD_HEADER) MALLOC((UINT) QuerySize()))) {
+ return FALSE;
+ }
+
+
+ // Get the new attribute record.
+
+ if (!AttributeList->QueryAttributeRecord(new_attr,
+ QuerySize(),
+ &attribute)) {
+
+ FREE(new_attr);
+ return FALSE;
+ }
+
+
+ // Locate the old attribute record.
+
+ old_attr = (PATTRIBUTE_RECORD_HEADER) GetAttributeList();
+
+ if (!old_attr) {
+ FREE(new_attr);
+ return FALSE;
+ }
+
+
+ // Make sure that there is enough room for new attribute record.
+
+ if (QueryAvailableSpace() + old_attr->RecordLength <
+ new_attr->RecordLength) {
+
+ FREE(new_attr);
+ return FALSE;
+ }
+
+
+ // Use the same old instance field that exists on the current
+ // attribute list for the new attribute list.
+
+ new_attr->Instance = old_attr->Instance;
+
+
+ // Delete the old attribute record.
+
+ DeleteAttributeRecord(old_attr);
+
+
+ // Insert the new attribute record.
+
+ if (!InsertAttributeRecord(old_attr, new_attr)) {
+ DebugAbort("Could not insert attribute list");
+ FREE(new_attr);
+ return FALSE;
+ }
+
+
+ // If required, write the changes to disk.
+
+ if (WriteFrs && !Write()) {
+
+ DebugAbort("Readable FRS is unwritable");
+ return FALSE;
+ }
+
+
+ FREE(new_attr);
+
+ return TRUE;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_FRS_STRUCTURE::SafeQueryAttribute(
+ IN ATTRIBUTE_TYPE_CODE TypeCode,
+ IN OUT PNTFS_ATTRIBUTE MftData,
+ OUT PNTFS_ATTRIBUTE Attribute
+ )
+/*++
+
+Routine Description:
+
+ This routine does a 'safe' query attribute operation. This
+ primarily needed by 'chkdsk' at times when it absolutely needs
+ to retrieve a certain attribute but it cannot depend on the disk
+ structures being good.
+
+ This routine queries unnamed attributes only.
+
+Arguments:
+
+ TypeCode - Supplies the type code of the attribute to retrieve.
+ MftData - Supplies the MFT $DATA attribute.
+ Attribute - Returns the attribute.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PVOID record;
+ NTFS_ATTRIBUTE_RECORD attr_record;
+ NTFS_FRS_STRUCTURE frs;
+ HMEM hmem;
+ VCN next_lowest_vcn;
+ NTFS_ATTRIBUTE_LIST attrlist;
+ ATTRIBUTE_TYPE_CODE type_code;
+ MFT_SEGMENT_REFERENCE seg_ref;
+ VCN lowest_vcn;
+ DSTRING name;
+ DSTRING record_name;
+ VCN file_number;
+ PNTFS_FRS_STRUCTURE pfrs;
+ BOOLEAN rvalue;
+ ULONG i;
+ USHORT instance;
+
+
+ // First validate the attribute records linking in this FRS;
+
+ record = NULL;
+ while (record = GetNextAttributeRecord(record)) {
+ }
+
+
+ if (!QueryAttributeList(&attrlist)) {
+
+ // There's no attribute list so just go through it and pluck
+ // out the record.
+
+ record = NULL;
+ while (record = GetNextAttributeRecord(record)) {
+
+ if (!attr_record.Initialize(record)) {
+ DebugAbort("Counldn't initialize attribute record");
+ return FALSE;
+ }
+
+ if (attr_record.QueryTypeCode() == TypeCode &&
+ attr_record.QueryLowestVcn() == 0 &&
+ attr_record.Verify(NULL, TRUE) &&
+ attr_record.QueryName(&name) &&
+ !name.QueryChCount()) {
+
+ break;
+ }
+ }
+
+ if (!record) {
+ return FALSE;
+ }
+
+ return Attribute->Initialize(GetDrive(), QueryClusterFactor(),
+ &attr_record) &&
+ Attribute->VerifyAndFix(QueryVolumeSectors());
+ }
+
+
+ // Crap out if the attribute list is unreadable.
+
+ if (!attrlist.ReadList()) {
+ return FALSE;
+ }
+
+
+ // Since, there's an attribute list, perform the analysis based
+ // on it.
+
+ // The first attribute record to pick up will have lowest_vcn of 0.
+ next_lowest_vcn = 0;
+
+ rvalue = FALSE;
+
+ for (i = 0; attrlist.QueryEntry(i, &type_code, &lowest_vcn,
+ &seg_ref, &instance, &name); ) {
+
+ if (type_code != TypeCode ||
+ lowest_vcn != next_lowest_vcn ||
+ name.QueryChCount()) {
+ i++;
+ continue;
+ }
+
+ file_number.Set(seg_ref.LowPart, (LONG) seg_ref.HighPart);
+
+ pfrs = NULL;
+
+ if (file_number == QueryFileNumber()) {
+
+ if (!(seg_ref == QuerySegmentReference())) {
+ i++;
+ continue;
+ }
+
+ pfrs = this;
+
+ } else {
+
+ // If we're boot strapping the MFT then make sure that
+ // the first one is in the base FRS.
+
+ if (lowest_vcn == 0 && MftData == Attribute) {
+ return FALSE;
+ }
+
+ if (!hmem.Initialize() ||
+ !frs.Initialize(&hmem, MftData, file_number,
+ QueryClusterFactor(), QueryVolumeSectors(),
+ QuerySize(), GetUpcaseTable()) ||
+ !frs.Read() ||
+ !(frs.QuerySegmentReference() == seg_ref) ||
+ !(frs.QueryBaseFileRecordSegment() == QuerySegmentReference())) {
+
+ i++;
+ continue;
+ }
+
+ pfrs = &frs;
+ }
+
+ DebugAssert(pfrs);
+
+ record = NULL;
+ while (record = pfrs->GetNextAttributeRecord(record)) {
+
+ if (!attr_record.Initialize(record)) {
+ DebugAbort("Could not initialize attribute record");
+ return FALSE;
+ }
+
+
+ if (attr_record.QueryTypeCode() == type_code &&
+ attr_record.QueryLowestVcn() == lowest_vcn &&
+ attr_record.Verify(NULL, TRUE) &&
+ attr_record.QueryName(&record_name) &&
+ !record_name.QueryChCount()) {
+
+ break;
+ }
+ }
+
+ if (!record) {
+ i++;
+ continue;
+ }
+
+ if (lowest_vcn == 0) {
+
+ rvalue = Attribute->Initialize(GetDrive(),
+ QueryClusterFactor(),
+ &attr_record);
+
+ if (!rvalue) {
+ i++;
+ continue;
+ }
+
+ } else {
+
+ if (!Attribute->AddAttributeRecord(&attr_record)) {
+ i++;
+ continue;
+ }
+ }
+
+ next_lowest_vcn = attr_record.QueryNextVcn();
+ i = 0;
+ }
+
+ return rvalue ? Attribute->VerifyAndFix(QueryVolumeSectors()) : FALSE;
+}
+
+
+ULONG
+NTFS_FRS_STRUCTURE::QueryAvailableSpace(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the number of bytes available for
+ attribute records.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of bytes currently available for attribute records.
+
+--*/
+{
+ PVOID p;
+
+ // Spin through in order to guarantee a valid field.
+
+ p = NULL;
+ while (p = GetNextAttributeRecord(p)) {
+ }
+
+ return QuerySize() - _FrsData->FirstFreeByte;
+}
+
+
+BOOLEAN
+SwapAttributeRecords(
+ IN OUT PVOID FirstAttributeRecord
+ )
+/*++
+
+Routine Description:
+
+ This routine swaps 'FirstAttributeRecord' with the next attribute
+ record in the list. This method will fail if there is not
+ enough memory available for a swap buffer.
+
+Arguments:
+
+ FirstAttributeRecord - Supplies the first of two attribute records
+ to be swapped.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PATTRIBUTE_RECORD_HEADER p1, p2;
+ PCHAR q1, q2;
+ PVOID buf;
+ UINT first_record_length;
+
+ p1 = (PATTRIBUTE_RECORD_HEADER) FirstAttributeRecord;
+ q1 = (PCHAR) p1;
+
+ DebugAssert(p1->TypeCode != $END);
+
+ first_record_length = (UINT) p1->RecordLength;
+
+ if (!(buf = MALLOC(first_record_length))) {
+ return FALSE;
+ }
+
+ // Tuck away the first record.
+
+ memcpy(buf, p1, first_record_length);
+
+
+ q2 = q1 + p1->RecordLength;
+ p2 = (PATTRIBUTE_RECORD_HEADER) q2;
+
+ DebugAssert(p2->TypeCode != $END);
+
+
+ // Overwrite first attribute record with second attribute record.
+
+ memmove(p1, p2, (UINT) p2->RecordLength);
+
+
+ // Copy over the first attribute record after the second.
+
+ memcpy(q1 + p1->RecordLength, buf, first_record_length);
+
+ FREE(buf);
+
+ return TRUE;
+}
+
+
+INT
+CompareResidentAttributeValues(
+ IN PCNTFS_ATTRIBUTE_RECORD Left,
+ IN PCNTFS_ATTRIBUTE_RECORD Right
+ )
+/*++
+
+Routine Description:
+
+ This routine compares the attribute values of two resident attributes
+ and returns -1 is Left < Right, 0 if Left == Right, or 1 if Left > Right.
+
+Arguments:
+
+ Left - Supplies the left hand side of the comparison.
+ Right - Supplies the right hand side of the comparison.
+
+Return Value:
+
+ < 0 - Left < Right
+ 0 - Left == Right
+ > 0 - Left > Right
+
+--*/
+{
+ BIG_INT left_length, right_length;
+ INT r;
+
+ Left->QueryValueLength(&left_length);
+ Right->QueryValueLength(&right_length);
+
+ r = memcmp(Left->GetResidentValue(), Right->GetResidentValue(),
+ min(left_length.GetLowPart(), right_length.GetLowPart()));
+
+ if (r != 0) {
+ return r;
+ }
+
+ if (left_length == right_length) {
+ r = 0;
+ } else if (left_length < right_length) {
+ r = -1;
+ } else {
+ r = 1;
+ }
+
+ return r;
+}
+
+
+BOOLEAN
+NTFS_FRS_STRUCTURE::Sort(
+ OUT PBOOLEAN Changes,
+ OUT PBOOLEAN Duplicates
+ )
+/*++
+
+Routine Description:
+
+ This routine bubble sorts the attributes by type, name, and (if
+ the attribute is indexed) value.
+
+Arguments:
+
+ Changes - Returns whether or not there were any changes made.
+ Duplicates - Returns whether or not there were any duplicates
+ eliminated.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PVOID prev;
+ PVOID p;
+ NTFS_ATTRIBUTE_RECORD attr1;
+ NTFS_ATTRIBUTE_RECORD attr2;
+ PNTFS_ATTRIBUTE_RECORD prev_attr;
+ PNTFS_ATTRIBUTE_RECORD attr;
+ PNTFS_ATTRIBUTE_RECORD tmp_attr;
+ BOOLEAN stable;
+ INT r;
+ LONG CompareResult;
+
+ DebugAssert(Changes);
+
+ *Changes = FALSE;
+ *Duplicates = FALSE;
+
+ prev_attr = &attr1;
+ attr = &attr2;
+
+ stable = FALSE;
+
+ while (!stable) {
+
+ stable = TRUE;
+
+ if (!(prev = GetNextAttributeRecord(NULL))) {
+ return TRUE;
+ }
+
+ if (!prev_attr->Initialize(prev)) {
+ DebugAbort("Could not initialize attribute record.");
+ return FALSE;
+ }
+
+ while (p = GetNextAttributeRecord(prev)) {
+
+ if (!attr->Initialize(p)) {
+ DebugAbort("Could not initialize attribute record.");
+ return FALSE;
+ }
+
+ CompareResult = CompareAttributeRecords( prev_attr,
+ attr,
+ GetUpcaseTable() );
+
+ if ( CompareResult > 0 ) {
+
+ // Out of order. Swap.
+
+ if (!SwapAttributeRecords(prev)) {
+ return FALSE;
+ }
+
+ *Changes = TRUE;
+ stable = FALSE;
+ break;
+ }
+
+ if ( CompareResult == 0 ) {
+
+ // These two attribute records have the same type
+ // code and name. They better both be indexed and
+ // have differing values.
+
+ if (!attr->IsIndexed() ||
+ !prev_attr->IsIndexed()) {
+
+ // They're not both indexed so delete them.
+
+ DeleteAttributeRecord(p);
+ DeleteAttributeRecord(prev);
+
+ *Duplicates = TRUE;
+ *Changes = TRUE;
+ stable = FALSE;
+ break;
+ }
+
+ // They're both indexed so do a comparison.
+
+ r = CompareResidentAttributeValues(prev_attr, attr);
+
+ if (r == 0) {
+
+ // The attribute records are equal so
+ // delete them both.
+
+ DeleteAttributeRecord(p);
+ DeleteAttributeRecord(prev);
+
+ *Duplicates = TRUE;
+ *Changes = TRUE;
+ stable = FALSE;
+ break;
+ }
+
+ if (r > 0) {
+
+ // Out of order. Swap.
+
+ if (!SwapAttributeRecords(prev)) {
+ return FALSE;
+ }
+
+ // We don't set the 'Changes' flag here because
+ // indexed attributes don't have to be ordered by
+ // value.
+
+ stable = FALSE;
+ break;
+ }
+ }
+
+ tmp_attr = prev_attr;
+ prev_attr = attr;
+ attr = tmp_attr;
+
+ prev = p;
+ }
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/untfs/src/hackwc.cxx b/private/utils/untfs/src/hackwc.cxx
new file mode 100644
index 000000000..b25ed9030
--- /dev/null
+++ b/private/utils/untfs/src/hackwc.cxx
@@ -0,0 +1,82 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ hackwc.cxx
+
+Abstract:
+
+ This module contains the definition for a hack that allows me
+ to compare attribute names correctly.
+
+ The comparison of attribute names is binary (word by word);
+ I can't use WSTRING because it's comparisons are all based
+ on the locale, while this comparison is locale-independent.
+
+Author:
+
+ Bill McJohn (billmc) 14-Aug-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "untfs.hxx"
+
+#include "hackwc.hxx"
+
+INT
+CountedWCMemCmp(
+ IN PCWSTR String1,
+ IN ULONG Length1,
+ IN PCWSTR String2,
+ IN ULONG Length2
+ )
+/*++
+
+Routine Description:
+
+ This function compares two counted wide-character buffers.
+ It compares word-by-word, rather than byte by byte.
+
+Arguments:
+
+ String1 -- supplies the first wide-character buffer
+ Length1 -- supplies the number of wide characters in String1
+ String2 -- supplies the second wide-character buffer
+ Length2 -- supplies the number of wide characters in String2
+
+Return Value:
+
+ a negative value if String1 is less than String2
+ zero if String1 equals String2
+ a positive value if String1 is greater than String2
+
+--*/
+{
+ ULONG i;
+ LONG res;
+
+ i = ( Length1 < Length2 ) ? Length1 : Length2;
+
+ while( i-- ) {
+
+ if( (res = *String1++ - *String2++) != 0 ) {
+
+ return res;
+ }
+ }
+
+ return Length1 - Length2;
+}
diff --git a/private/utils/untfs/src/indxbuff.cxx b/private/utils/untfs/src/indxbuff.cxx
new file mode 100644
index 000000000..975dce67f
--- /dev/null
+++ b/private/utils/untfs/src/indxbuff.cxx
@@ -0,0 +1,841 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ indxbuff.hxx
+
+Abstract:
+
+ This module contains the member function definitions for
+ NTFS_INDEX_BUFFER, which models index buffers in an Index
+ Allocation attribute.
+
+ These buffers are the component blocks of a b-tree, which
+ is rooted in the matching Index Root attribute.
+
+Author:
+
+ Bill McJohn (billmc) 04-Sept-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "untfs.hxx"
+#include "ntfssa.hxx"
+
+#include "drive.hxx"
+
+#include "attrib.hxx"
+#include "indxbuff.hxx"
+
+DEFINE_CONSTRUCTOR( NTFS_INDEX_BUFFER, OBJECT );
+
+NTFS_INDEX_BUFFER::~NTFS_INDEX_BUFFER(
+ )
+{
+ Destroy();
+}
+
+
+VOID
+NTFS_INDEX_BUFFER::Construct(
+ )
+/*++
+
+Routine Description:
+
+ This method is the worker function for object construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _ClustersPerBuffer = 0;
+ _BufferSize = 0;
+ _ClusterSize = 0;
+ _ThisBufferVcn = 0;
+ _CollationRule = COLLATION_NUMBER_RULES;
+ _UpcaseTable = NULL;
+}
+
+
+VOID
+NTFS_INDEX_BUFFER::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This method cleans up the object in preparation for destruction
+ or reinitialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _ClustersPerBuffer = 0;
+ _ThisBufferVcn = 0;
+ _ClusterSize = 0;
+ _BufferSize = 0;
+ _CollationRule = COLLATION_NUMBER_RULES;
+ _UpcaseTable = NULL;
+}
+
+
+BOOLEAN
+NTFS_INDEX_BUFFER::Initialize(
+ IN PCLOG_IO_DP_DRIVE Drive,
+ IN VCN ThisBufferVcn,
+ IN ULONG ClusterSize,
+ IN ULONG ClustersPerBuffer,
+ IN ULONG BufferSize,
+ IN COLLATION_RULE CollationRule,
+ IN PNTFS_UPCASE_TABLE UpcaseTable
+ )
+/*++
+
+Routine Description:
+
+ This method initializes an NTFS_INDEX_BUFFER. Note that this class
+ is reinitializable.
+
+Arguments:
+
+ Drive -- supplies the drive on which the index resides.
+ ThisBufferVcn -- supplies the this buffer's VCN within the
+ index allocation attribute for the containing
+ index.
+ ClusterSize -- supplies the size of a cluster on this volume.
+ ClustersPerBuffer -- supplies the number of clusters per index
+ allocation buffer in this index b-tree.
+ BufferSize -- size of the buffer in bytes.
+ CollationRule -- supplies the collation rule for this index.
+ UpcaseTable -- supplies the volume upcase table.
+
+Either the ClustersPerBuffer or the BufferSize may be zero, but not
+both. If BufferSize is zero, then we're doing an old-style buffer where
+each buffer is at least one cluster. If ClustersPerBuffer is zero, then
+we're doing a new-style buffer where the buffer size may be a fraction of
+the cluster size.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ DebugPtrAssert( Drive );
+ DebugAssert( ClusterSize != 0 );
+ DebugAssert( BufferSize != 0 || ClustersPerBuffer != 0 );
+
+ Destroy();
+
+ _ClusterSize = ClusterSize;
+ _ClustersPerBuffer = ClustersPerBuffer;
+ _BufferSize = BufferSize;
+ _ThisBufferVcn = ThisBufferVcn;
+ _CollationRule = CollationRule;
+ _UpcaseTable = UpcaseTable;
+
+ if( !_Mem.Initialize() ||
+ (_Data = (PINDEX_ALLOCATION_BUFFER)
+ _Mem.Acquire( BufferSize,
+ Drive->QueryAlignmentMask() )) == NULL ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+VOID
+NTFS_INDEX_BUFFER::Create(
+ IN BOOLEAN IsLeaf,
+ IN VCN EndEntryDownpointer
+ )
+/*++
+
+Arguments:
+
+ IsLeaf -- supplies a flag indicating whether this is a
+ leaf block (TRUE) or a node block (FALSE).
+ EndEntryDownpointer -- supplies the B-Tree downpointer for the end
+ entry. (This parameter is ignored if IsLeaf
+ is TRUE.)
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PINDEX_ENTRY EndEntry;
+
+ DebugPtrAssert( _Data );
+
+ // The layout of an index buffer is:
+ // Index Allocation Buffer Header
+ // Update Sequence Array
+ // First Entry.
+
+ memset( _Data, 0, QuerySize() );
+
+ // Write the 'FILE' signature in the MultiSectorHeader.
+
+ memcpy( _Data->MultiSectorHeader.Signature,
+ "INDX",
+ 4 );
+
+ // Compute the number of Update Sequence Numbers in the
+ // update array. This number is (see ntos\inc\cache.h):
+ //
+ // n/SEQUENCE_NUMBER_STRIDE + 1
+ //
+ // where n is the number of bytes in the protected structure
+ // (in this case, an index allocation buffer ).
+
+ _Data->MultiSectorHeader.UpdateSequenceArraySize =
+ (USHORT)(QuerySize()/SEQUENCE_NUMBER_STRIDE + 1);
+
+ _Data->MultiSectorHeader.UpdateSequenceArrayOffset =
+ (PBYTE)&(_Data->UpdateSequenceArray) - (PBYTE)_Data;
+
+ _Data->Lsn.LowPart = 0;
+ _Data->Lsn.HighPart = 0;
+
+ _Data->ThisVcn = _ThisBufferVcn;
+ _Data->IndexHeader.Flags = IsLeaf ? 0 : INDEX_NODE;
+
+
+ _Data->IndexHeader.FirstIndexEntry =
+ QuadAlign( _Data->MultiSectorHeader.UpdateSequenceArrayOffset +
+ _Data->MultiSectorHeader.UpdateSequenceArraySize *
+ sizeof(UPDATE_SEQUENCE_NUMBER));
+
+ // the first entry is the end entry. The only fields in it that
+ // matter are the length, the flags, and the downpointer (if any).
+
+ EndEntry = (PINDEX_ENTRY)((PBYTE)&(_Data->IndexHeader) +
+ _Data->IndexHeader.FirstIndexEntry);
+
+
+ EndEntry->Length = NtfsIndexLeafEndEntrySize;
+ EndEntry->AttributeLength = 0;
+ EndEntry->Flags = INDEX_ENTRY_END;
+
+ if( !IsLeaf ) {
+
+ EndEntry->Flags |= INDEX_ENTRY_NODE;
+ EndEntry->Length += sizeof(VCN);
+ GetDownpointer(EndEntry) = EndEntryDownpointer;
+ }
+
+
+ _Data->IndexHeader.FirstFreeByte =
+ _Data->IndexHeader.FirstIndexEntry + EndEntry->Length;
+
+ _Data->IndexHeader.BytesAvailable =
+ QuerySize() - ( (PBYTE)&(_Data->IndexHeader) - (PBYTE)_Data );
+
+}
+
+
+
+BOOLEAN
+NTFS_INDEX_BUFFER::Read(
+ IN OUT PNTFS_ATTRIBUTE AllocationAttribute
+ )
+/*++
+
+Routine Description:
+
+ This method reads the index allocation buffer.
+
+Arguments:
+
+ AllocationAttribute -- supplies the Index Allocation Attribute
+ that describes the allocation for this
+ b-tree.
+
+Return Value:
+
+ TRUE upon successful completion
+
+--*/
+{
+ ULONG BytesRead;
+ BOOLEAN Result;
+ PINDEX_ENTRY CurrentEntry;
+ ULONG RemainingSpace, FirstEntryOffset;
+ BIG_INT AttributeOffset;
+
+ DebugPtrAssert( AllocationAttribute );
+
+ if (_BufferSize < _ClusterSize) {
+ AttributeOffset = NTFS_INDEX_BLOCK_SIZE * QueryVcn();
+ } else {
+ AttributeOffset = _ClusterSize * QueryVcn();
+ }
+
+ Result = AllocationAttribute->Read( _Data,
+ AttributeOffset,
+ QuerySize(),
+ &BytesRead ) &&
+ BytesRead == QuerySize() &&
+ NTFS_SA::PostReadMultiSectorFixup( _Data, BytesRead );
+
+ // if the read succeeded, sanity-check the buffer.
+ //
+ if( Result ) {
+
+ CurrentEntry = GetFirstEntry();
+ FirstEntryOffset = (PBYTE)CurrentEntry - (PBYTE)_Data;
+
+ if( FirstEntryOffset > QuerySize() ) {
+
+ // The first entry pointer is completely wrong.
+ //
+ Result = FALSE;
+
+ } else {
+
+ RemainingSpace = QuerySize() - FirstEntryOffset;
+
+ while( TRUE ) {
+
+ if( NTFS_INDEX_TREE::IsIndexEntryCorrupt( CurrentEntry,
+ RemainingSpace ) ) {
+
+ Result = FALSE;
+ break;
+ }
+
+ if( CurrentEntry->Flags & INDEX_ENTRY_END ) {
+
+ break;
+ }
+
+ RemainingSpace -= CurrentEntry->Length;
+ CurrentEntry = GetNextEntry( CurrentEntry );
+ }
+ }
+ }
+
+ return Result;
+}
+
+
+BOOLEAN
+NTFS_INDEX_BUFFER::Write(
+ IN OUT PNTFS_ATTRIBUTE AllocationAttribute
+ )
+/*++
+
+Routine Description:
+
+ This method writes the index allocation buffer.
+
+Arguments:
+
+ AllocationAttribute -- supplies the Index Allocation Attribute
+ that describes the allocation for this
+ b-tree.
+
+Return Value:
+
+ TRUE upon successful completion
+
+--*/
+{
+ ULONG BytesWritten;
+ BIG_INT Offset;
+ BOOLEAN r;
+
+ DebugPtrAssert( AllocationAttribute );
+
+ NTFS_SA::PreWriteMultiSectorFixup( _Data, QuerySize() );
+
+ if (_ClusterSize <= QuerySize()) {
+ Offset = _ClusterSize * QueryVcn();
+ } else {
+ Offset = NTFS_INDEX_BLOCK_SIZE * QueryVcn();
+ }
+
+ r = AllocationAttribute->Write( _Data,
+ Offset,
+ QuerySize(),
+ &BytesWritten, NULL ) &&
+ BytesWritten == QuerySize();
+
+ NTFS_SA::PostReadMultiSectorFixup( _Data, QuerySize() );
+
+ return r;
+}
+
+
+
+BOOLEAN
+NTFS_INDEX_BUFFER::FindEntry(
+ IN PCINDEX_ENTRY SearchEntry,
+ IN OUT PULONG Ordinal,
+ OUT PINDEX_ENTRY* EntryFound
+ )
+/*++
+
+Routine Description:
+
+ This method locates an entry in the index buffer. Note that it
+ does not recurse into the buffer's children (if any). If no matching
+ entry is found, it returns the first entry which is greater than
+ the desired entry; if the search key is greater than all the entries
+ in the buffer, it returns the END entry.
+
+Arguments:
+
+ SearchEntry -- Supplies an entry with the search key and length.
+ (Note that this entry has a meaningless file reference).
+ Ordinal -- supplies an ordinal showing which matching entry
+ to return; see note below.
+ EntryFound -- receives a pointer to the located entry. Receives
+ NULL if an error has occurred.
+
+Return Value:
+
+ TRUE if a matching entry is found. If an error occurs, *EntryFound
+ is set to NULL. If no error occurs, and no matching entry is found,
+ *EntryFound is set to the next entry (i.e. the point at which the
+ search key would be inserted into this buffer).
+
+Notes:
+
+ This method assumes that the index buffer is consistent.
+
+ The ordinal argument indicates how many matching entries should be
+ passed over before one is returned. When an entry is found which
+ matches the search key, if *Ordinal is zero, that entry is returned;
+ otherwise, *Ordinal is decremented, and the FindEntry goes on to
+ the next entry.
+
+ If *Ordinal is INDEX_SKIP, then all matching entries are skipped.
+
+--*/
+{
+ PINDEX_ENTRY CurrentEntry;
+ BOOLEAN Found;
+ int CompareResult;
+
+ CurrentEntry = GetFirstEntry();
+ Found = FALSE;
+
+ while( !(CurrentEntry->Flags & INDEX_ENTRY_END) ) {
+
+ CompareResult = CompareNtfsIndexEntries( SearchEntry,
+ CurrentEntry,
+ _CollationRule,
+ _UpcaseTable );
+
+ if( CompareResult < 0 ) {
+
+ // The search value is less than the current entry's
+ // value, so we've overshot where our search key would
+ // be. Stop (and return the current entry).
+
+ break;
+
+ } else if( CompareResult == 0 ) {
+
+ // The current entry matches the search entry. Check
+ // the ordinal argument to see if we should return this
+ // entry or skip it.
+
+ if( *Ordinal == 0 ) {
+
+ Found = TRUE;
+ break;
+
+ } else if( *Ordinal != INDEX_SKIP ) {
+
+ *Ordinal -= 1;
+ }
+ }
+
+ // Haven't found our entry, so we'll just go on to the next.
+
+ CurrentEntry = GetNextEntry( CurrentEntry );
+ }
+
+ *EntryFound = CurrentEntry;
+ return( Found );
+}
+
+
+BOOLEAN
+NTFS_INDEX_BUFFER::InsertEntry(
+ IN PCINDEX_ENTRY NewEntry,
+ IN PINDEX_ENTRY InsertPoint
+ )
+/*++
+
+Routine Description:
+
+ This method inserts an index entry into the buffer.
+
+Arguments:
+
+ NewEntry -- Supplies the entry to insert.
+ InsertPoint -- supplies the point in the buffer at which this entry
+ should be inserted, if known. This parameter may be
+ NULL, in which case the buffer determines where to
+ insert the new entry.
+
+Return Value:
+
+ TRUE upon successful completion. A return value of FALSE indicates
+ that the entry will not fit in the buffer.
+
+Notes:
+
+ This method assumes that the buffer is consistent.
+
+ InsertPoint should be a pointer previously returned from FindEntry;
+ otherwise, this method will go badly astray.
+
+--*/
+{
+ ULONG Ordinal, BytesToCopy;
+
+ // First, check to see if there's enough room:
+
+ if( _Data->IndexHeader.FirstFreeByte + NewEntry->Length >
+ _Data->IndexHeader.BytesAvailable ) {
+
+ return FALSE;
+ }
+
+ // We know there's enough space, so we know we'll succeed.
+
+ if( InsertPoint == NULL ) {
+
+ // The client has not supplied the insert point, so we get to
+ // figure it out for ourselves. Fortunately, we can get FindEntry
+ // to do our work for us.
+
+ // Note that we don't care what InsertEntry returns--we know it
+ // won't hit an error, and we don't care whether there are any
+ // matching entries in the buffer. (If we get a matching buffer,
+ // we insert the new one before it, which is just fine.)
+
+ Ordinal = 0;
+
+ FindEntry( NewEntry,
+ &Ordinal,
+ &InsertPoint );
+
+ DebugPtrAssert( InsertPoint );
+ }
+
+ // Now we just make room for the entry and jam it in.
+
+ BytesToCopy = _Data->IndexHeader.FirstFreeByte -
+ ((PBYTE)InsertPoint - (PBYTE)&(_Data->IndexHeader));
+
+ memmove( (PBYTE)InsertPoint + NewEntry->Length,
+ InsertPoint,
+ BytesToCopy );
+
+ _Data->IndexHeader.FirstFreeByte += NewEntry->Length;
+
+ memcpy( InsertPoint, NewEntry, NewEntry->Length );
+
+ return TRUE;
+}
+
+
+VOID
+NTFS_INDEX_BUFFER::RemoveEntry(
+ IN PINDEX_ENTRY EntryToRemove
+ )
+/*++
+
+Routine Description:
+
+ This method removes an entry from the index buffer, closing up
+ the buffer over it.
+
+Arguments:
+
+ EntryToRemove -- supplies a pointer to the entry to remove.
+
+Return Value:
+
+ None. This method always succeeds.
+
+Notes:
+
+ This method assumes that the index buffer is consistent.
+
+ EntryToRemove must be a pointer that was returned by a previous
+ call (with no intervening inserts or deletes) to FindEntry or
+ GetFirstEntry.
+
+--*/
+{
+ PBYTE NextEntry;
+ ULONG BytesToCopy;
+
+ NextEntry = (PBYTE)EntryToRemove + EntryToRemove->Length;
+
+ BytesToCopy = _Data->IndexHeader.FirstFreeByte -
+ (NextEntry - (PBYTE)&(_Data->IndexHeader));
+
+ _Data->IndexHeader.FirstFreeByte -= EntryToRemove->Length;
+
+ memmove( EntryToRemove,
+ NextEntry,
+ BytesToCopy );
+
+}
+
+
+
+PINDEX_ENTRY
+NTFS_INDEX_BUFFER::FindSplitPoint(
+ )
+/*++
+
+Routine Description:
+
+ This method finds a point at which the index allocation buffer
+ would like to be split.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A pointer to the entry which will be promoted in the split.
+
+ Note that we can return any non-end entry, but we cannot return
+ the end entry.
+
+--*/
+{
+ PINDEX_ENTRY CurrentEntry, PreviousEntry, NextEntry;
+ ULONG CurrentOffset;
+
+
+ CurrentOffset = _Data->IndexHeader.FirstIndexEntry;
+ CurrentEntry = GetFirstEntry();
+
+ DebugAssert( !(CurrentEntry->Flags & INDEX_ENTRY_END) );
+
+ while( !(CurrentEntry->Flags & INDEX_ENTRY_END) &&
+ CurrentOffset < _Data->IndexHeader.FirstFreeByte/2 ) {
+
+ PreviousEntry = CurrentEntry;
+ CurrentOffset += CurrentEntry->Length;
+ CurrentEntry = GetNextEntry( CurrentEntry );
+ }
+
+ // We need to make sure we don't pick the last entry in the buffer
+ // to split before; the entry just after the split point gets promoted
+ // to the parent buffer, which would leave us with an empty buffer.
+ //
+
+ if( CurrentEntry->Flags & INDEX_ENTRY_END ) {
+
+ // Oops! Back up one. [XXX.mjb: really need to back up *two*
+ // in this case, because the last entry is just a marker to hold
+ // the flag, it's not a true entry.]
+ //
+
+ CurrentEntry = PreviousEntry;
+
+ } else {
+
+ NextEntry = GetNextEntry( CurrentEntry );
+
+ if( NextEntry->Flags & INDEX_ENTRY_END ) {
+
+ CurrentEntry = PreviousEntry;
+ }
+ }
+
+ return CurrentEntry;
+}
+
+
+VOID
+NTFS_INDEX_BUFFER::InsertClump(
+ IN ULONG LengthOfClump,
+ IN PCVOID Clump
+ )
+/*++
+
+Routine Description:
+
+ This method inserts a clump of entries at the beginning of
+ the buffer. It is used to insert entries into a newly-created
+ buffer.
+
+Arguments:
+
+ LengthOfClump -- supplies the number of bytes to insert
+ Clump -- supplies the source from which the data
+ is to be copied.
+
+Return Value:
+
+ None.
+
+Notes:
+
+ This private method should be used with care; the client must
+ ensure that the entries being inserted are valid, and that they
+ will not cause the buffer to overflow.
+
+--*/
+{
+ ULONG BytesToMove;
+ PBYTE InsertPoint;
+
+ DebugAssert( _Data->IndexHeader.FirstFreeByte + LengthOfClump <=
+ _Data->IndexHeader.BytesAvailable );
+
+ // We'll insert the new entries in front of the first entry in
+ // the buffer, which means we have to shift all the existing
+ // entries up to make room.
+
+ InsertPoint = (PBYTE)GetFirstEntry();
+
+ BytesToMove = _Data->IndexHeader.FirstFreeByte -
+ _Data->IndexHeader.FirstIndexEntry;
+
+ memmove( InsertPoint + LengthOfClump,
+ InsertPoint,
+ BytesToMove );
+
+ // Copy the new entries into the space we just created:
+
+ memcpy( InsertPoint,
+ Clump,
+ LengthOfClump );
+
+ // Adjust the offset of the First Free Byte to reflect
+ // what we just did:
+
+ _Data->IndexHeader.FirstFreeByte += LengthOfClump;
+
+}
+
+
+VOID
+NTFS_INDEX_BUFFER::RemoveClump(
+ IN ULONG LengthOfClump
+ )
+/*++
+
+Routine Description:
+
+ This method removes a clump of entries from the beginning of
+ the index buffer. It's particularly useful when splitting
+ a buffer.
+
+Arguments:
+
+ LengthOfClump -- supplies the number of bytes to remove from
+ the index buffer.
+
+Return Value:
+
+ None.
+
+Notes:
+
+ This private method should be used with care; the client must
+ ensure that the number of bytes to be removed covers a valid
+ clump of entries, and does not include (or extend past) the
+ END entry.
+
+--*/
+{
+ ULONG BytesToMove;
+ PBYTE FirstEntry;
+
+ DebugAssert( LengthOfClump + _Data->IndexHeader.FirstIndexEntry
+ < _Data->IndexHeader.FirstFreeByte );
+
+ // Compute the number of bytes in entries after the clump:
+
+ BytesToMove = _Data->IndexHeader.FirstFreeByte -
+ (LengthOfClump + _Data->IndexHeader.FirstIndexEntry);
+
+ // Shift those entries down to the beginning of the index
+ // entries in this index buffer.
+
+ FirstEntry = (PBYTE)GetFirstEntry();
+
+ memmove( FirstEntry,
+ FirstEntry + LengthOfClump,
+ BytesToMove );
+
+ // Adjust the offset of the First Free Byte to reflect
+ // what we just did:
+
+ _Data->IndexHeader.FirstFreeByte -= LengthOfClump;
+}
+
+
+
+BOOLEAN
+NTFS_INDEX_BUFFER::IsEmpty(
+ )
+/*++
+
+Routine Description:
+
+ This method determines whether the buffer is empty.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the first entry is an END entry.
+
+--*/
+{
+ PINDEX_ENTRY FirstEntry;
+
+ FirstEntry = GetFirstEntry();
+
+ return( FirstEntry->Flags & INDEX_ENTRY_END );
+}
diff --git a/private/utils/untfs/src/indxchk.cxx b/private/utils/untfs/src/indxchk.cxx
new file mode 100644
index 000000000..f7c7f2082
--- /dev/null
+++ b/private/utils/untfs/src/indxchk.cxx
@@ -0,0 +1,3741 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+
+extern "C" {
+ #include <stdio.h>
+#if defined(TIMING_ANALYSIS)
+ #include <time.h>
+#endif
+}
+
+#include "ntfssa.hxx"
+
+#include "message.hxx"
+#include "rtmsg.h"
+#include "ntfsbit.hxx"
+#include "attrib.hxx"
+#include "attrdef.hxx"
+#include "mft.hxx"
+#include "numset.hxx"
+#include "indxtree.hxx"
+#include "attrcol.hxx"
+#include "ifssys.hxx"
+#include "digraph.hxx"
+#include "ifsentry.hxx"
+
+
+// This global flag is used to signal that incorrect duplicated
+// information was found in some of the file name indices on the
+// disk.
+
+STATIC BOOLEAN FileSystemConsistencyErrorsFound = FALSE;
+
+#define SET_TRUE(x) ((x)=TRUE)
+
+BOOLEAN
+ExtractExtendInfo(
+ IN OUT PNTFS_INDEX_TREE Index,
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PMESSAGE Message
+);
+
+BOOLEAN
+NTFS_SA::ValidateIndices(
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ OUT PDIGRAPH DirectoryDigraph,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN PCNTFS_ATTRIBUTE_COLUMNS AttributeDefTable,
+ IN OUT PNTFS_CHKDSK_REPORT ChkdskReport,
+ IN OUT PNUMBER_SET BadClusters,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN DiskErrorsFound
+ )
+/*++
+
+Routine Description:
+
+ This routine validates the EAs and indices on the volume. A complete
+ list of all files which may (or may not) contain EAs or indices is
+ supplied. This, along with a valid Mft makes this validation possible.
+
+Arguments:
+
+ ChkdskInfo - Supplies the current chkdsk information.
+ DirectoryDigraph - Returns a digraph of the directory structure.
+ Mft - Supplies a valid MFT.
+ AttributeDefTable - Supplies the attribute definition table.
+ ChkdskReport - Supplies the current chkdsk report to be updated
+ by this routine.
+ BadClusters - Supplies the bad cluster list.
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages.
+ DiskErrorsFound - Supplies whether or not disk errors have been
+ found.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_FILE_RECORD_SEGMENT frs;
+ ULONG i, j;
+ ULONG num_dirs, num_dirs_checked;
+ NTFS_ATTRIBUTE bitmap_attrib;
+ NTFS_ATTRIBUTE root_attrib;
+ NTFS_ATTRIBUTE alloc_attrib;
+ NTFS_BITMAP alloc_bitmap;
+ PINDEX_ROOT index_root;
+ ATTRIBUTE_TYPE_CODE indexed_attribute_type;
+ BOOLEAN alloc_present;
+ BOOLEAN need_write;
+ BOOLEAN complete_failure;
+ PVOID bitmap_value;
+ ULONG bitmap_length;
+ ULONG attr_def_index;
+ BOOLEAN tube;
+ BOOLEAN ErrorInAttribute;
+ NTFS_INDEX_TREE index;
+ BOOLEAN changes;
+ ULONG percent_done, new_percent;
+ BOOLEAN error_in_index;
+ BOOLEAN duplicates_allowed;
+
+ DebugAssert(ChkdskInfo);
+ DebugAssert(Mft);
+ DebugAssert(ChkdskReport);
+ DebugAssert(Message);
+
+ if (!DirectoryDigraph->Initialize(ChkdskInfo->NumFiles)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ Message->Set(MSG_CHK_NTFS_CHECKING_INDICES, PROGRESS_MESSAGE);
+ Message->Display();
+ percent_done = 0;
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", percent_done)) {
+ return FALSE;
+ }
+
+ num_dirs = max(1, ChkdskInfo->CountFilesWithIndices);
+ num_dirs_checked = 0;
+
+#if defined(TIMING_ANALYSIS)
+ char buf[100];
+
+ printf("Before stage 2: %s\n", _strtime(buf));
+#endif
+
+ for (i = 0; i < ChkdskInfo->NumFiles; i++) {
+
+ new_percent = max(num_dirs_checked*100 / num_dirs, 0);
+
+ if (new_percent != percent_done) {
+ percent_done = new_percent;
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", percent_done)) {
+ return FALSE;
+ }
+ }
+
+ if (ChkdskInfo->FilesWithIndices.IsFree(i, 1)) {
+ continue;
+ }
+
+ num_dirs_checked += 1;
+
+ if (!frs.Initialize(i, Mft)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!frs.Read()) {
+ DebugAbort("Previously readable FRS is no longer readable");
+ continue;
+ }
+
+ // The following loop deletes all $INDEX_ALLOCATION attributes that
+ // don't have a corresponding $INDEX_ROOT attribute.
+
+ need_write = FALSE;
+
+ for (j = 0; frs.QueryAttributeByOrdinal(&alloc_attrib,
+ &ErrorInAttribute,
+ $INDEX_ALLOCATION,
+ j); j++) {
+
+ // Make sure that there's an index root of the same name
+ // here. Otherwise tube this attribute.
+
+ if (frs.IsAttributePresent($INDEX_ROOT, alloc_attrib.GetName())) {
+ continue;
+ }
+
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+
+ Message->Set(MSG_CHK_NTFS_ERROR_IN_INDEX);
+ Message->Display("%d%W",
+ frs.QueryFileNumber().GetLowPart(),
+ alloc_attrib.GetName());
+ DebugPrintf("UNTFS: Index allocation without index root.\n");
+
+ need_write = TRUE;
+
+ if (!alloc_attrib.Resize(0, Mft->GetVolumeBitmap()) ||
+ !frs.PurgeAttribute(alloc_attrib.QueryTypeCode(),
+ alloc_attrib.GetName())) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+
+ // Because we deleted a $INDEX_ALLOCATION we need to
+ // adjust j.
+
+ j--;
+
+
+ // If there's a $BITMAP then tube that also.
+
+ if (!frs.QueryAttribute(&bitmap_attrib,
+ &ErrorInAttribute,
+ $BITMAP,
+ alloc_attrib.GetName())) {
+
+ if (ErrorInAttribute) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ continue;
+ }
+
+ if (!bitmap_attrib.Resize(0, Mft->GetVolumeBitmap()) ||
+ !frs.PurgeAttribute(bitmap_attrib.QueryTypeCode(),
+ bitmap_attrib.GetName())) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ if (ErrorInAttribute) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+
+ // This loop goes through all of the $INDEX_ROOT attributes in
+ // this FRS.
+
+ for (j = 0; frs.QueryAttributeByOrdinal(&root_attrib,
+ &ErrorInAttribute,
+ $INDEX_ROOT,
+ j); j++) {
+
+ // First find out if we have an INDEX_ALLOCATION here.
+
+ alloc_present = frs.QueryAttribute(&alloc_attrib,
+ &ErrorInAttribute,
+ $INDEX_ALLOCATION,
+ root_attrib.GetName());
+
+ if (!alloc_present && ErrorInAttribute) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ error_in_index = FALSE;
+
+ if (!VerifyAndFixIndex(ChkdskInfo,
+ &root_attrib,
+ alloc_present ? &alloc_attrib : NULL,
+ alloc_present ? &alloc_bitmap : NULL,
+ frs.QueryFileNumber(),
+ root_attrib.GetName(),
+ BadClusters,
+ Mft->GetVolumeBitmap(),
+ AttributeDefTable,
+ &tube,
+ FixLevel, Message,
+ &error_in_index)) {
+
+ return FALSE;
+ }
+
+ *DiskErrorsFound = *DiskErrorsFound || error_in_index;
+
+ if (tube) {
+
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+
+ need_write = TRUE;
+
+ Message->Set(MSG_CHK_NTFS_BAD_INDEX);
+ Message->Display("%d%W",
+ frs.QueryFileNumber().GetLowPart(),
+ root_attrib.GetName());
+
+ if (!root_attrib.Resize(0, Mft->GetVolumeBitmap()) ||
+ !frs.PurgeAttribute(root_attrib.QueryTypeCode(),
+ root_attrib.GetName())) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ // Adjust j because an $INDEX_ROOT has just been removed.
+
+ j--;
+
+ if (alloc_present) {
+
+ if (!alloc_attrib.Resize(0, Mft->GetVolumeBitmap()) ||
+ !frs.PurgeAttribute(alloc_attrib.QueryTypeCode(),
+ alloc_attrib.GetName())) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (frs.QueryAttribute(&bitmap_attrib,
+ &ErrorInAttribute,
+ $BITMAP,
+ root_attrib.GetName())) {
+
+ if (!bitmap_attrib.Resize(0, Mft->GetVolumeBitmap()) ||
+ !frs.PurgeAttribute(bitmap_attrib.QueryTypeCode(),
+ bitmap_attrib.GetName())) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ } else if (ErrorInAttribute) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ continue;
+ }
+
+ if (root_attrib.IsStorageModified()) {
+
+ need_write = TRUE;
+
+ if (!root_attrib.InsertIntoFile(&frs,
+ Mft->GetVolumeBitmap())) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_INDEX);
+ Message->Display("%d%W",
+ frs.QueryFileNumber().GetLowPart(),
+ root_attrib.GetName());
+ }
+ }
+
+ if (alloc_present && alloc_attrib.IsStorageModified()) {
+
+ need_write = TRUE;
+
+ if (!alloc_attrib.InsertIntoFile(&frs,
+ Mft->GetVolumeBitmap())) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_INDEX);
+ Message->Display("%d%W",
+ frs.QueryFileNumber().GetLowPart(),
+ root_attrib.GetName());
+ }
+ }
+
+ if (alloc_present) {
+
+ BOOLEAN bitmap_present;
+ BOOLEAN bitmaps_equal;
+ BOOLEAN error;
+
+ // Make sure the bitmap is present and good.
+
+ complete_failure = FALSE;
+
+ bitmap_present = frs.QueryAttribute(&bitmap_attrib,
+ &ErrorInAttribute,
+ $BITMAP,
+ root_attrib.GetName());
+
+ if (bitmap_present) {
+ bitmaps_equal = AreBitmapsEqual(&bitmap_attrib,
+ &alloc_bitmap,
+ alloc_bitmap.QuerySize(),
+ Message,
+ &complete_failure);
+
+ //
+ // Make an exception here for cases where our internal bitmap
+ // is size zero but there is a positively-sized bitmap attribute,
+ // as long as the bitmap attribute's contents are zeroed. The
+ // filesystem can leave the disk in this state after all the files
+ // are deleted from a large directory.
+ //
+
+ if (!bitmaps_equal && alloc_bitmap.QuerySize() == 0 &&
+ bitmap_attrib.QueryValueLength() > 0 &&
+ bitmap_attrib.IsAllocationZeroed()) {
+
+ bitmaps_equal = TRUE;
+ }
+ }
+
+
+ if (!bitmap_present || !bitmaps_equal) {
+
+ need_write = TRUE;
+
+ Message->Set(MSG_CHK_NTFS_ERROR_IN_INDEX);
+ Message->Display("%d%W",
+ frs.QueryFileNumber().GetLowPart(),
+ root_attrib.GetName());
+ DebugPrintf("UNTFS: Incorrect index bitmap.\n");
+
+ if (complete_failure ||
+ !(bitmap_value = (PVOID)
+ alloc_bitmap.GetBitmapData(&bitmap_length)) ||
+ !bitmap_attrib.Initialize(_drive,
+ QueryClusterFactor(),
+ bitmap_value,
+ bitmap_length,
+ $BITMAP,
+ root_attrib.GetName())) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!bitmap_attrib.InsertIntoFile(&frs,
+ Mft->GetVolumeBitmap())) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_INDEX);
+ Message->Display("%d%W",
+ frs.QueryFileNumber().GetLowPart(),
+ root_attrib.GetName());
+ }
+ }
+ } else {
+
+ // Since there's no allocation, make sure that there's
+ // no bitmap, either.
+ //
+
+ if (frs.QueryAttribute(&bitmap_attrib,
+ &ErrorInAttribute,
+ $BITMAP,
+ root_attrib.GetName())) {
+
+ need_write = TRUE;
+
+ Message->Set(MSG_CHK_NTFS_ERROR_IN_INDEX);
+ Message->Display("%d%W",
+ frs.QueryFileNumber().GetLowPart(),
+ root_attrib.GetName());
+
+ DebugPrintf("UNTFS: no index allocation; removing bitmap.\n");
+
+ if (!bitmap_attrib.Resize(0, Mft->GetVolumeBitmap()) ||
+ !frs.PurgeAttribute(bitmap_attrib.QueryTypeCode(),
+ bitmap_attrib.GetName())) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ } else if (ErrorInAttribute) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ }
+
+ // Don't go on to sort this sucker if you're in read/only
+ // and it's corrupt.
+
+ if ((error_in_index || need_write) && FixLevel == CheckOnly) {
+ continue;
+ }
+
+
+ // Now make sure that this sucker is ordered. The
+ // Attribute Definition Table indicates whether indices
+ // over this attribute can have duplicate entries.
+ // Since this index has already passed through VerifyAndFixIndex,
+ // the following operations are safe.
+ //
+ // Determine the indexed attribute type:
+ //
+
+ if ((frs.QueryFileNumber() != SECURITY_TABLE_NUMBER &&
+ frs.QueryFileNumber() != ChkdskInfo->QuotaFileNumber &&
+ frs.QueryFileNumber() != ChkdskInfo->ObjectIdFileNumber) ||
+ ChkdskInfo->major <= 1) {
+
+ index_root = (PINDEX_ROOT)root_attrib.GetResidentValue();
+ indexed_attribute_type = index_root->IndexedAttributeType;
+
+ AttributeDefTable->QueryIndex( indexed_attribute_type,
+ &attr_def_index );
+
+ duplicates_allowed =
+ 0 != (AttributeDefTable->QueryFlags(attr_def_index) &
+ ATTRIBUTE_DEF_DUPLICATES_ALLOWED);
+
+ } else
+ duplicates_allowed = FALSE;
+
+#if defined(TIMING_ANALYSIS)
+ printf("Before stage 2 sorting: %s\n", _strtime(buf));
+#endif
+
+#if !defined(TIMING_ANALYSIS)
+ switch (frs.SortIndex(root_attrib.GetName(),
+ Mft->GetVolumeBitmap(),
+ duplicates_allowed,
+ FixLevel == CheckOnly)) {
+#else
+ switch (NTFS_SORT_INDEX_WELL_ORDERED) {
+#endif
+ case NTFS_SORT_INDEX_WELL_ORDERED:
+ break;
+
+ case NTFS_SORT_INDEX_SORTED:
+ case NTFS_SORT_INDEX_BADLY_ORDERED:
+ *DiskErrorsFound = TRUE;
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ Message->Set(MSG_CHK_NTFS_BADLY_ORDERED_INDEX);
+ Message->Display("%d%W",
+ frs.QueryFileNumber().GetLowPart(),
+ root_attrib.GetName());
+ need_write = TRUE;
+ break;
+
+ case NTFS_SORT_INDEX_NOT_FOUND:
+ DebugPrint("Index not found");
+
+ // Fall through.
+
+ case NTFS_SORT_ERROR:
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+
+ case NTFS_SORT_INSERT_FAILED:
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_COULD_NOT_FIX;
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_INDEX);
+ Message->Display("%d%W",
+ frs.QueryFileNumber().GetLowPart(),
+ root_attrib.GetName());
+ break;
+ }
+
+
+#if defined(TIMING_ANALYSIS)
+ printf("After stage 2 sorting: %s\n", _strtime(buf));
+#endif
+
+ // Update the chkdsk report.
+
+ ChkdskReport->NumIndices += 1;
+
+ if (alloc_present) {
+ ChkdskReport->BytesInIndices +=
+ alloc_attrib.QueryAllocatedLength();
+ }
+
+ if (frs.QueryFileNumber() == SECURITY_TABLE_NUMBER &&
+ ChkdskInfo->major >= 2) {
+ ChkdskInfo->FilesWhoNeedData.Remove(SECURITY_TABLE_NUMBER);
+ } else if (frs.QueryFileNumber() == ChkdskInfo->QuotaFileNumber) {
+
+ DSTRING IndexName;
+
+ ChkdskInfo->FilesWhoNeedData.Remove(ChkdskInfo->QuotaFileNumber);
+ if (!IndexName.Initialize(Userid2SidQuotaNameData)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (root_attrib.GetName()->Strcmp(&IndexName) == 0) {
+ switch (frs.VerifyAndFixQuotaDefaultId(Mft->GetVolumeBitmap(),
+ FixLevel == CheckOnly)) {
+ case NTFS_QUOTA_INDEX_FOUND:
+ break;
+
+ case NTFS_QUOTA_INDEX_INSERTED:
+ case NTFS_QUOTA_DEFAULT_ENTRY_MISSING:
+ *DiskErrorsFound = TRUE;
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ Message->Set(MSG_CHK_NTFS_DEFAULT_QUOTA_ENTRY_MISSING);
+ Message->Display("%d%W",
+ frs.QueryFileNumber().GetLowPart(),
+ root_attrib.GetName());
+ need_write = TRUE;
+ break;
+
+ case NTFS_QUOTA_INDEX_NOT_FOUND:
+ // possibly quota disabled
+ break;
+
+ case NTFS_QUOTA_ERROR:
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+
+ case NTFS_QUOTA_INSERT_FAILED:
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_COULD_NOT_FIX;
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_INDEX);
+ Message->Display("%d%W",
+ frs.QueryFileNumber().GetLowPart(),
+ root_attrib.GetName());
+ break;
+ }
+ }
+
+ } else if (frs.QueryFileNumber() == ChkdskInfo->ObjectIdFileNumber) {
+
+
+ // Now go through all of the index entries and make sure
+ // that they point somewhere decent.
+
+ ChkdskInfo->FilesWhoNeedData.Remove(ChkdskInfo->ObjectIdFileNumber);
+
+ if (!index.Initialize(_drive, QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ Mft->GetUpcaseTable(),
+ frs.QuerySize()/2,
+ &frs,
+ root_attrib.GetName())) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!ValidateEntriesInObjIdIndex(&index, &frs, ChkdskInfo,
+ &changes, Mft, FixLevel,
+ Message, DiskErrorsFound)) {
+ return FALSE;
+ }
+
+ if (changes) {
+ need_write = TRUE;
+ }
+
+ } else {
+
+ // Now go through all of the index entries and make sure
+ // that they point somewhere decent.
+
+ if (!index.Initialize(_drive, QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ Mft->GetUpcaseTable(),
+ frs.QuerySize()/2,
+ &frs,
+ root_attrib.GetName())) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+#if defined(TIMING_ANALYSIS)
+ printf("Before stage 2 ValidateEntries: %s\n", _strtime(buf));
+#endif
+
+ if (!ValidateEntriesInIndex(&index, &frs, ChkdskInfo,
+ DirectoryDigraph, &changes,
+ Mft, FixLevel, Message,
+ DiskErrorsFound)) {
+ return FALSE;
+ }
+
+#if defined(TIMING_ANALYSIS)
+ printf("After stage 2 ValidateEntries: %s\n", _strtime(buf));
+#endif
+
+ if (changes) {
+ if (FixLevel != CheckOnly && !index.Save(&frs)) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_INDEX);
+ Message->Display("%d%W",
+ frs.QueryFileNumber().GetLowPart(),
+ index.GetName());
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_COULD_NOT_FIX;
+ }
+ need_write = TRUE;
+ }
+
+ if (i == EXTEND_TABLE_NUMBER && ChkdskInfo->major >= 2) {
+ if (!ExtractExtendInfo(&index, ChkdskInfo, Message))
+ return FALSE;
+ }
+ }
+ }
+
+ if (ErrorInAttribute) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (need_write) {
+ *DiskErrorsFound = TRUE;
+ }
+
+ if (need_write &&
+ FixLevel != CheckOnly &&
+ !frs.Flush(Mft->GetVolumeBitmap())) {
+
+ DebugAbort("Can't write readable FRS");
+ return FALSE;
+ }
+ }
+
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", 100)) {
+ return FALSE;
+ }
+ Message->Set(MSG_CHK_NTFS_INDEX_VERIFICATION_COMPLETED, PROGRESS_MESSAGE);
+ Message->Display();
+
+#if defined(TIMING_ANALYSIS)
+ printf("After stage 2: %s\n", _strtime(buf));
+#endif
+
+ // Now make sure all of the reference counts are good.
+
+ for (i = 0; i < ChkdskInfo->NumFiles; i++) {
+
+ if (!ChkdskInfo->ReferenceCount[i]) {
+ continue;
+ }
+
+ FileSystemConsistencyErrorsFound = TRUE;
+
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+
+// Take out this message because it can be printed a billion times.
+#if 0
+ Message->Set(MSG_CHK_NTFS_MINOR_CHANGES_TO_FRS);
+ Message->Display("%d", i);
+#endif
+
+ if (!frs.Initialize(i, Mft)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!frs.Read()) {
+ continue;
+ }
+
+ // If the reference count is being adjusted to zero then
+ // it should be added to the list of files with no reference.
+ // Otherwise if the reference is being adjusted to something
+ // non-zero it must be taken out of the list.
+
+ if (frs.QueryReferenceCount() == ChkdskInfo->ReferenceCount[i]) {
+ if (!ChkdskInfo->FilesWithNoReferences.Add(i)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ } else {
+ if (!ChkdskInfo->FilesWithNoReferences.Remove(i)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ frs.SetReferenceCount(frs.QueryReferenceCount() -
+ ChkdskInfo->ReferenceCount[i]);
+
+ if (FixLevel != CheckOnly && !frs.Write()) {
+ DebugAbort("can't write readable frs");
+ return FALSE;
+ }
+ }
+
+
+ if (FileSystemConsistencyErrorsFound) {
+ Message->Set((FixLevel == CheckOnly) ?
+ MSG_HPFS_CHKDSK_ERRORS_DETECTED :
+ MSG_HPFS_CHKDSK_ERRORS_FIXED);
+ Message->Display();
+
+ if (CHKDSK_EXIT_SUCCESS == ChkdskInfo->ExitStatus) {
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_MINOR_ERRS;
+ }
+ }
+
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_SA::VerifyAndFixIndex(
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PNTFS_ATTRIBUTE RootIndex,
+ IN OUT PNTFS_ATTRIBUTE IndexAllocation OPTIONAL,
+ OUT PNTFS_BITMAP AllocationBitmap OPTIONAL,
+ IN VCN FileNumber,
+ IN PCWSTRING AttributeName,
+ IN OUT PNUMBER_SET BadClusters,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN PCNTFS_ATTRIBUTE_COLUMNS AttributeDefTable,
+ OUT PBOOLEAN Tube,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN DiskErrorsFound
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies and fixes an index over an attribute.
+
+ As it does this, it builds up an allocation bitmap which it
+ returns in
+
+Arguments:
+
+ RootIndex - Supplies the root index attribute.
+ IndexAllocation - Supplies the index allocation attribute.
+ AllocationBitmap - Returns the allocation bitmap.
+ BadClusters - Supplies the bad clusters list.
+ VolumeBitmap - Supplies the volume bitmap.
+ AttributeDefTable - Supplies the attribute definition table.
+ Tube - Returns whether or not the index must be tubed.
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages.
+ DiskErrorsFound - Supplies whether or not disk errors have been
+ found.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG root_length;
+ ULONG num_bytes;
+ PINDEX_ROOT index_root;
+ ULONG attr_def_index;
+ ULONG flags;
+ ULONG bytes_per_buffer;
+ PINDEX_HEADER index_header;
+ ULONG index_block_length;
+ BOOLEAN changes;
+ BOOLEAN need_write = FALSE;
+ DSTRING index_name;
+
+ *Tube = FALSE;
+
+ root_length = RootIndex->QueryValueLength().GetLowPart();
+
+ if (root_length < sizeof(INDEX_ROOT)) {
+ *Tube = TRUE;
+ return TRUE;
+ }
+
+ if (!(index_root = (PINDEX_ROOT) MALLOC(root_length))) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!RootIndex->Read(index_root, 0, root_length, &num_bytes) ||
+ num_bytes != root_length) {
+
+ DebugAbort("Unreadable resident attribute");
+ FREE(index_root);
+ return FALSE;
+ }
+
+
+ if (index_root->IndexedAttributeType == $FILE_NAME) {
+
+ // This index should be tubed if it indexes $FILE_NAME
+ // but the index name is not $I30.
+
+ if (!index_name.Initialize(FileNameIndexNameData)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (RootIndex->GetName()->Strcmp(&index_name)) {
+
+ DebugPrintf("UNTFS: index over file name is not $I30.\n");
+ FREE(index_root);
+ *Tube = TRUE;
+ return TRUE;
+ }
+
+ if (index_root->CollationRule != COLLATION_FILE_NAME) {
+ index_root->CollationRule = COLLATION_FILE_NAME;
+ Message->Set(MSG_CHK_NTFS_FIXING_COLLATION_RULE);
+ Message->Display("%W%d", &index_name, FileNumber.GetLowPart());
+ need_write = TRUE;
+ }
+
+ } else if (FileNumber == ChkdskInfo->ObjectIdFileNumber) {
+
+ // This index should be tubed if it an object id
+ // index but the index name is not ObjectIdIndexNameData
+
+ if (!index_name.Initialize(ObjectIdIndexNameData)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (RootIndex->GetName()->Strcmp(&index_name)) {
+
+ DebugPrintf("UNTFS: index over object id is not %s.\n",
+ ObjectIdIndexNameData);
+ FREE(index_root);
+ *Tube = TRUE;
+ return TRUE;
+ }
+
+ if (index_root->CollationRule != COLLATION_ULONGS) {
+ index_root->CollationRule = COLLATION_ULONGS;
+ Message->Set(MSG_CHK_NTFS_FIXING_COLLATION_RULE);
+ Message->Display("%W%d", &index_name, FileNumber.GetLowPart());
+ need_write = TRUE;
+ }
+
+ } else if (FileNumber == ChkdskInfo->QuotaFileNumber) {
+
+ // This index should be tubed if it an quota index
+ // but the index name is not Sid2UseridQuotaNameData
+ // or Userid2SidQuotaNameData
+
+ // Furthermore, if the index name is Sid2UseridQuotaNameData,
+ // the collation rule value should be COLLATION_SID. If
+ // the index name is Userid2SidQuotaNameData, the collation
+ // rule value should be COLLATION_ULONG.
+
+ if (!index_name.Initialize(Sid2UseridQuotaNameData)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (RootIndex->GetName()->Strcmp(&index_name) == 0) {
+ if (index_root->CollationRule != COLLATION_SID) {
+ index_root->CollationRule = COLLATION_SID;
+ Message->Set(MSG_CHK_NTFS_FIXING_COLLATION_RULE);
+ Message->Display("%W%d", &index_name, FileNumber.GetLowPart());
+ need_write = TRUE;
+ }
+ } else {
+ if (!index_name.Initialize(Userid2SidQuotaNameData)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (RootIndex->GetName()->Strcmp(&index_name) == 0) {
+ if (index_root->CollationRule != COLLATION_ULONG) {
+ index_root->CollationRule = COLLATION_ULONG;
+ Message->Set(MSG_CHK_NTFS_FIXING_COLLATION_RULE);
+ Message->Display("%W%d", &index_name, FileNumber.GetLowPart());
+ need_write = TRUE;
+ }
+ } else {
+ DebugPrintf("UNTFS: index over quota is not %s or %s.\n",
+ Sid2UseridQuotaNameData,
+ Userid2SidQuotaNameData);
+ FREE(index_root);
+ *Tube = TRUE;
+ return TRUE;
+ }
+ }
+
+ } else if (FileNumber == SECURITY_TABLE_NUMBER) {
+
+ // This index should be tubed if it an security index
+ // but the index name is not SecurityIdIndexNameData
+ // or SecurityDescriptorHashIndexNameData.
+
+ // Furthermore, if the index name is SecurityIdIndexNameData,
+ // the collation rule value should be COLLATION_ULONG. If
+ // the index name is SecurityDescriptorHashIndexNameData,
+ // the collation rule value should be COLLATION_SECURITY_HASH.
+
+ if (!index_name.Initialize(SecurityIdIndexNameData)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (RootIndex->GetName()->Strcmp(&index_name) == 0) {
+ if (index_root->CollationRule != COLLATION_ULONG) {
+ index_root->CollationRule = COLLATION_ULONG;
+ Message->Set(MSG_CHK_NTFS_FIXING_COLLATION_RULE);
+ Message->Display("%W%d", &index_name, FileNumber.GetLowPart());
+ need_write = TRUE;
+ }
+ } else {
+ if (!index_name.Initialize(SecurityDescriptorHashIndexNameData)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (RootIndex->GetName()->Strcmp(&index_name) == 0) {
+ if (index_root->CollationRule != COLLATION_SECURITY_HASH) {
+ index_root->CollationRule = COLLATION_SECURITY_HASH;
+ Message->Set(MSG_CHK_NTFS_FIXING_COLLATION_RULE);
+ Message->Display("%W%d", &index_name, FileNumber.GetLowPart());
+ need_write = TRUE;
+ }
+ } else {
+ DebugPrintf("UNTFS: index over security is not %s or %s.\n",
+ SecurityIdIndexNameData,
+ SecurityDescriptorHashIndexNameData);
+ FREE(index_root);
+ *Tube = TRUE;
+ return TRUE;
+ }
+ }
+
+ }
+
+ //
+ // BUGBUG: Skip the cairo file for now.
+ //
+
+ if (FileNumber != ChkdskInfo->QuotaFileNumber &&
+ FileNumber != ChkdskInfo->ObjectIdFileNumber &&
+ FileNumber != SECURITY_TABLE_NUMBER) {
+
+ // Make sure that the attribute that we're indexing over is
+ // an indexable attribute.
+
+ if (!AttributeDefTable->QueryIndex(
+ index_root->IndexedAttributeType,
+ &attr_def_index)) {
+
+ *Tube = TRUE;
+ FREE(index_root);
+ return TRUE;
+ }
+
+ flags = AttributeDefTable->QueryFlags(attr_def_index);
+
+ if (!(flags & ATTRIBUTE_DEF_MUST_BE_INDEXED) &&
+ !(flags & ATTRIBUTE_DEF_INDEXABLE)) {
+
+ *Tube = TRUE;
+ FREE(index_root);
+ return TRUE;
+ }
+
+ }
+
+ bytes_per_buffer = index_root->BytesPerIndexBuffer;
+
+ // Check out the index allocation. Recover it. Make sure
+ // that the size is a multiple of bytesperindexbuffer.
+ //
+
+ if (IndexAllocation) {
+
+ if (IndexAllocation->QueryValueLength() % bytes_per_buffer != 0 ||
+ IndexAllocation->QueryAllocatedLength() % bytes_per_buffer != 0) {
+
+ Message->Set(MSG_CHK_NTFS_ERROR_IN_INDEX);
+ Message->Display("%d%W",
+ FileNumber.GetLowPart(), AttributeName);
+ DebugPrintf("UNTFS: Index allocation has incorrect length.\n");
+
+ if (!IndexAllocation->Resize(
+ (IndexAllocation->QueryValueLength()/bytes_per_buffer)*
+ bytes_per_buffer,
+ VolumeBitmap)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(index_root);
+ return FALSE;
+ }
+ }
+
+ // Try to recover as much as possible.
+
+ IndexAllocation->RecoverAttribute(VolumeBitmap, BadClusters);
+
+ if (!AllocationBitmap->Initialize(
+ IndexAllocation->QueryValueLength()/bytes_per_buffer,
+ TRUE)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(index_root);
+ return FALSE;
+ }
+ }
+
+ index_header = &(index_root->IndexHeader);
+ index_block_length = ((PCHAR) index_root + root_length) -
+ ((PCHAR) index_header);
+
+ if (!TraverseIndexTree(index_header, index_block_length,
+ IndexAllocation, AllocationBitmap,
+ bytes_per_buffer, Tube, &changes,
+ FileNumber, AttributeName,
+ FixLevel, Message, DiskErrorsFound)) {
+ FREE(index_root);
+ return FALSE;
+ }
+
+ if (*Tube) {
+ FREE(index_root);
+ return TRUE;
+ }
+
+ if (changes || need_write) {
+
+ Message->Set(MSG_CHK_NTFS_ERROR_IN_INDEX);
+ Message->Display("%d%W",
+ FileNumber.GetLowPart(),
+ AttributeName);
+
+ if (!RootIndex->Write(index_root, 0, root_length, &num_bytes, NULL) ||
+ num_bytes != root_length) {
+
+ DebugAbort("Unwriteable resident attribute");
+ FREE(index_root);
+ return FALSE;
+ }
+ }
+
+
+ if (index_header->FirstFreeByte != index_header->BytesAvailable) {
+
+ DebugPrintf("UNTFS: Index root has FirstFreeByte != BytesAvailable\n");
+
+ index_header->BytesAvailable = index_header->FirstFreeByte;
+
+ if (!RootIndex->Resize(index_header->BytesAvailable +
+ sizeof(INDEX_ROOT) - sizeof(INDEX_HEADER),
+ VolumeBitmap) ) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(index_root);
+ return FALSE;
+ }
+ }
+
+
+ FREE(index_root);
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_SA::TraverseIndexTree(
+ IN OUT PINDEX_HEADER IndexHeader,
+ IN ULONG IndexLength,
+ IN OUT PNTFS_ATTRIBUTE IndexAllocation OPTIONAL,
+ IN OUT PNTFS_BITMAP AllocationBitmap OPTIONAL,
+ IN ULONG BytesPerBlock,
+ OUT PBOOLEAN Tube,
+ OUT PBOOLEAN Changes,
+ IN VCN FileNumber,
+ IN PCWSTRING AttributeName,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN DiskErrorsFound
+ )
+/*++
+
+Routine Description:
+
+ This routine traverses an index tree and verifies the entries while
+ traversing.
+
+Arguments:
+
+ IndexHeader - Supplies a pointer to the beginning of this index
+ block.
+ IndexLength - Supplies the length of this index block.
+ IndexAllocation - Supplies the index allocation attribute.
+ AllocationBitmap - Supplies the current in memory bitmap of used
+ index blocks.
+ BytesPerBuffer - Supplies the size of an index block within the
+ index allocation attribute.
+ Tube - Returns whether or not the whole index block
+ is invalid.
+ Changes - Returns whether or not changes were made to
+ the index block.
+ FirstFreeByte - Returns the first free byte in the index block.
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages.
+ DiskErrorsFound - Supplies whether or not disk errors have been found.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PINDEX_ENTRY p, pnext;
+ PCHAR pend;
+ ULONG first_free_byte;
+ VCN down_pointer;
+ ULONG clusters_per_block, cluster_size;
+ PINDEX_ALLOCATION_BUFFER down_block;
+ PINDEX_HEADER down_header;
+ BOOLEAN tube, changes;
+ ULONG num_bytes;
+
+ *Tube = FALSE;
+ *Changes = FALSE;
+
+ cluster_size = QueryClusterFactor() * _drive->QuerySectorSize();
+ clusters_per_block = (BytesPerBlock < cluster_size ?
+ BytesPerBlock / NTFS_INDEX_BLOCK_SIZE :
+ BytesPerBlock / cluster_size);
+
+ // pend points past the end of the block.
+
+ pend = (PCHAR) IndexHeader + IndexLength;
+
+
+ // First make sure that the first entry is valid.
+
+ if (sizeof(INDEX_HEADER) > IndexLength ||
+ IndexHeader->FirstIndexEntry < sizeof(INDEX_HEADER)) {
+
+ *Tube = TRUE;
+ return TRUE;
+ }
+
+ p = (PINDEX_ENTRY) ((PCHAR) IndexHeader + IndexHeader->FirstIndexEntry);
+
+ if (pend < (PCHAR) p ||
+ NTFS_INDEX_TREE::IsIndexEntryCorrupt(p, pend - (PCHAR) p)) {
+
+ *Tube = TRUE;
+ return TRUE;
+ }
+
+
+ // Now make sure that the bytes available count is correct.
+
+ if (IndexHeader->BytesAvailable != IndexLength) {
+
+ *Changes = TRUE;
+ IndexHeader->BytesAvailable = IndexLength;
+ DebugPrintf("UNTFS: Incorrect bytes available.\n");
+ }
+
+
+ // Validate all of the entries in the tree.
+
+ for (;;) {
+
+ // If this has a VCN down pointer then recurse down the tree.
+
+ if (p->Flags & INDEX_ENTRY_NODE) {
+
+ // Make sure that the index header is marked as a node.
+ if (!(IndexHeader->Flags&INDEX_NODE)) {
+ *Changes = TRUE;
+ IndexHeader->Flags |= INDEX_NODE;
+ }
+
+ down_pointer = GetDownpointer(p)/clusters_per_block;
+
+ if (!(down_block = (PINDEX_ALLOCATION_BUFFER)
+ MALLOC(BytesPerBlock))) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (GetDownpointer(p) % clusters_per_block == 0 &&
+ AllocationBitmap &&
+ AllocationBitmap->IsFree(down_pointer, 1) &&
+ IndexAllocation &&
+ IndexAllocation->Read(down_block,
+ down_pointer*BytesPerBlock,
+ BytesPerBlock,
+ &num_bytes) &&
+ num_bytes == BytesPerBlock &&
+ NTFS_SA::PostReadMultiSectorFixup(down_block, num_bytes) &&
+
+ down_block->MultiSectorHeader.Signature[0] == 'I' &&
+ down_block->MultiSectorHeader.Signature[1] == 'N' &&
+ down_block->MultiSectorHeader.Signature[2] == 'D' &&
+ down_block->MultiSectorHeader.Signature[3] == 'X' &&
+
+ down_block->MultiSectorHeader.UpdateSequenceArrayOffset >=
+ FIELD_OFFSET(INDEX_ALLOCATION_BUFFER, UpdateSequenceArray) &&
+
+ down_block->ThisVcn == GetDownpointer(p) &&
+
+ down_block->MultiSectorHeader.UpdateSequenceArrayOffset +
+ down_block->MultiSectorHeader.UpdateSequenceArraySize*
+ sizeof(UPDATE_SEQUENCE_NUMBER) <=
+ down_block->IndexHeader.FirstIndexEntry +
+ FIELD_OFFSET(INDEX_ALLOCATION_BUFFER, IndexHeader) &&
+
+ IsQuadAligned(down_block->IndexHeader.FirstIndexEntry) &&
+
+ num_bytes%SEQUENCE_NUMBER_STRIDE == 0 &&
+
+ down_block->MultiSectorHeader.UpdateSequenceArrayOffset%
+ sizeof(UPDATE_SEQUENCE_NUMBER) == 0 &&
+
+ down_block->MultiSectorHeader.UpdateSequenceArraySize ==
+ num_bytes/SEQUENCE_NUMBER_STRIDE + 1) {
+
+
+ // Compare this block's LSN against the largest so far.
+
+ if (down_block->Lsn > LargestLsnEncountered) {
+ LargestLsnEncountered = down_block->Lsn;
+ }
+
+
+ AllocationBitmap->SetAllocated(down_pointer, 1);
+
+ down_header = &(down_block->IndexHeader);
+
+
+ if (!TraverseIndexTree(down_header,
+ BytesPerBlock -
+ ((PCHAR) down_header -
+ (PCHAR) down_block),
+ IndexAllocation, AllocationBitmap,
+ BytesPerBlock, &tube, &changes,
+ FileNumber, AttributeName,
+ FixLevel, Message,
+ DiskErrorsFound)) {
+
+ FREE(down_block);
+ return FALSE;
+ }
+
+ if (tube || changes) {
+
+ Message->Set(MSG_CHK_NTFS_ERROR_IN_INDEX);
+ Message->Display("%d%W",
+ FileNumber.GetLowPart(),
+ AttributeName);
+
+ if (tube) {
+ *Changes = TRUE;
+ AllocationBitmap->SetFree(down_pointer, 1);
+ GetDownpointer(p) = INVALID_VCN;
+ DebugPrintf("UNTFS: 1 Index down pointer being set to invalid.\n");
+ }
+
+ NTFS_SA::PreWriteMultiSectorFixup(down_block,
+ BytesPerBlock);
+
+ *DiskErrorsFound = TRUE;
+
+ if (FixLevel != CheckOnly &&
+ !IndexAllocation->Write(down_block,
+ down_pointer*BytesPerBlock,
+ BytesPerBlock,
+ &num_bytes,
+ NULL)) {
+
+ DebugAbort("Can't write what was read");
+ FREE(down_block);
+ return FALSE;
+ }
+
+ NTFS_SA::PostReadMultiSectorFixup(down_block,
+ BytesPerBlock);
+ }
+
+ } else {
+ *Changes = TRUE;
+ GetDownpointer(p) = INVALID_VCN;
+ DebugPrintf("UNTFS: 2 Index down pointer being set to invalid.\n");
+ }
+
+ FREE(down_block);
+ } else {
+
+ // Make sure that the index header has this marked as a leaf. If the block
+ // is not consistent then the Sort routine for indices will detect that they're
+ // unsorted.
+
+ if (IndexHeader->Flags&INDEX_NODE) {
+ *Changes = TRUE;
+ IndexHeader->Flags &= ~INDEX_NODE;
+ }
+ }
+
+ if (p->Flags & INDEX_ENTRY_END) {
+ break;
+ }
+
+ // Make sure the next entry is not corrupt. If it is then
+ // truncate this one. If we truncate a node, we have to
+ // keep its downpointer.
+
+ pnext = (PINDEX_ENTRY) ((PCHAR) p + p->Length);
+
+ if (pend < (PCHAR) pnext ||
+ NTFS_INDEX_TREE::IsIndexEntryCorrupt(pnext, pend - (PCHAR) pnext)) {
+
+ *Changes = TRUE;
+ DebugPrintf("UNTFS: Index entry is corrupt.\n");
+ if( p->Flags & INDEX_ENTRY_NODE ) {
+ down_pointer = GetDownpointer(p);
+ }
+ p->Length = NtfsIndexLeafEndEntrySize +
+ ((p->Flags & INDEX_ENTRY_NODE) ? sizeof(VCN) : 0);
+ p->AttributeLength = 0;
+ p->Flags |= INDEX_ENTRY_END;
+ if( p->Flags & INDEX_ENTRY_NODE ) {
+ GetDownpointer(p) = down_pointer;
+ }
+ break;
+ }
+
+ p = pnext;
+ }
+
+
+ // Verify the first free byte.
+
+ first_free_byte = ((PCHAR) p - (PCHAR) IndexHeader) + p->Length;
+
+ if (IndexHeader->FirstFreeByte != first_free_byte) {
+
+ DebugPrintf("UNTFS: Index entry has invalid first free byte.\n");
+ *Changes = TRUE;
+ IndexHeader->FirstFreeByte = first_free_byte;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+QueryFileNameFromIndex(
+ IN PCFILE_NAME IndexValue,
+ IN ULONG ValueLength,
+ OUT PWSTRING FileName
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a file name string for a given file name
+ structure.
+
+Arguments:
+
+ IndexValue - Supplies the file name structure.
+ ValueLength - Supplies the number of bytes in the file name structure.
+ FileName - Returns the file name string.
+
+Return Value:
+
+ FALSE - There is a corruption in the file name structure.
+ TRUE - Success.
+
+--*/
+{
+ WSTR string[256];
+ UCHAR i, len;
+
+ if (sizeof(FILE_NAME) > ValueLength) {
+ return FALSE;
+ }
+
+ len = IndexValue->FileNameLength;
+
+ if (NtfsFileNameGetLength(IndexValue) > ValueLength) {
+ return FALSE;
+ }
+
+ for (i = 0; i < len; i++) {
+ string[i] = IndexValue->FileName[i];
+ }
+ string[i] = 0;
+
+ return FileName->Initialize(string);
+}
+
+
+BOOLEAN
+NTFS_SA::ValidateEntriesInIndex(
+ IN OUT PNTFS_INDEX_TREE Index,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT IndexFrs,
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PDIGRAPH DirectoryDigraph,
+ OUT PBOOLEAN Changes,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN DiskErrorsFound
+ )
+/*++
+
+Routine Description:
+
+ This routine goes through all of the entries in the given index
+ and makes sure that they point to an appropriate attribute. This
+ verification will not be made if the index has index name "$I30".
+
+ In either case the 'ChkdskInfo's ReferenceCount fields will be
+ updated.
+
+Arguments:
+
+ Index - Supplies the index.
+ IndexFrs - Supplies the index frs.
+ ChkdskInfo - Supplies the current chkdsk information.
+ DirectoryDigraph - Supplies the current directory digraph.
+ Changes - Returns whether or not changes were made.
+ Mft - Supplies the master file table.
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages.
+ DiskErrorsFound - Supplies whether or not disk errors have
+ been found.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PNTFS_FILE_RECORD_SEGMENT pfrs;
+ NTFS_FILE_RECORD_SEGMENT frs;
+ PCINDEX_ENTRY index_entry;
+ ULONG depth;
+ BOOLEAN error;
+ BOOLEAN file_name_index;
+ DSTRING file_name_index_name;
+ VCN file_number;
+ NTFS_ATTRIBUTE attribute;
+ BOOLEAN need_delete;
+ DSTRING entry_name;
+ PFILE_NAME file_name, frs_file_name;
+ DUPLICATED_INFORMATION actual_dupinfo;
+ BOOLEAN dupinfo_match;
+ PDUPLICATED_INFORMATION p,q;
+ NUMBER_SET files_in_this_index;
+ BIG_INT start, length, prime_start, prime_length, prime_offset;
+ ULONG max_frs_in_prime;
+ ULONG frs_size;
+ BOOLEAN file_has_too_many_file_names;
+
+ *Changes = FALSE;
+
+ if (!file_name_index_name.Initialize(FileNameIndexNameData)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ file_name_index = !Index->GetName()->Strcmp(&file_name_index_name) &&
+ Index->QueryTypeCode() == $FILE_NAME;
+
+ // Construct a list of all of the files pointed to by this index.
+
+ if (!files_in_this_index.Initialize()) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ Index->ResetIterator();
+
+#if defined(TIMING_ANALYSIS)
+ char buf[100];
+
+ printf("Before reading entries loop 1: %s\n", _strtime(buf));
+#endif
+
+ if (index_entry = Index->GetNext(&depth, &error)) {
+
+ file_number.Set(index_entry->FileReference.LowPart,
+ (LONG) index_entry->FileReference.HighPart);
+
+ if (!files_in_this_index.AddStart(file_number)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ while (index_entry = Index->GetNext(&depth, &error)) {
+
+ file_number.Set(index_entry->FileReference.LowPart,
+ (LONG) index_entry->FileReference.HighPart);
+
+ if (!files_in_this_index.AddNext(file_number)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+#if defined(TIMING_ANALYSIS)
+ printf("Before processing loop 2: %s\n", _strtime(buf));
+#endif
+
+ frs_size = IndexFrs->QuerySize();
+ max_frs_in_prime = 16*1024/frs_size;
+
+ Index->ResetIterator();
+ while (index_entry = Index->GetNext(&depth, &error)) {
+
+ file_number.Set(index_entry->FileReference.LowPart,
+ (LONG) index_entry->FileReference.HighPart);
+
+ need_delete = FALSE;
+ file_has_too_many_file_names = ChkdskInfo->
+ FilesWithTooManyFileNames.DoesIntersectSet(file_number, 1);
+
+ file_name = (PFILE_NAME) GetIndexEntryValue(index_entry);
+
+ if (file_name_index &&
+ !QueryFileNameFromIndex(file_name,
+ index_entry->AttributeLength,
+ &entry_name)) {
+ need_delete = TRUE;
+ }
+
+ if (!need_delete) {
+ if (IndexFrs->QueryFileNumber() == file_number) {
+ pfrs = IndexFrs;
+ } else {
+ if (!frs.Initialize(file_number, Mft)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (files_in_this_index.QueryContainingRange(file_number,
+ &start, &length)) {
+
+ prime_offset = (file_number - start)/max_frs_in_prime*
+ max_frs_in_prime;
+ prime_start = prime_offset + start;
+ prime_length = length - prime_offset;
+ if (prime_length > max_frs_in_prime) {
+ prime_length = max_frs_in_prime;
+ }
+
+ if (!files_in_this_index.Remove(prime_start, prime_length)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (prime_length > 1) {
+ Mft->GetDataAttribute()->PrimeCache(prime_start*frs_size,
+ prime_length.GetLowPart()*frs_size);
+ }
+ }
+
+ if (!frs.Read() || !frs.IsInUse()) {
+ need_delete = TRUE;
+ }
+
+ pfrs = &frs;
+ }
+ }
+
+
+ if (!need_delete && !pfrs->IsBase()) {
+
+ need_delete = TRUE;
+ }
+
+ if (!need_delete &&
+ !(pfrs->QuerySegmentReference() == index_entry->FileReference)) {
+
+ need_delete = TRUE;
+ }
+
+ if (!need_delete &&
+ file_name_index &&
+ !file_has_too_many_file_names &&
+ !pfrs->VerifyAndFixFileNames(Mft->GetVolumeBitmap(),
+ FixLevel, Message,
+ DiskErrorsFound, FALSE)) {
+
+ return FALSE;
+ }
+
+
+ // After verifying the file names we know that this FRS is
+ // not a candidate for a missing data attribute if is has
+ // its index bit set.
+
+ if (!need_delete && pfrs->IsIndexPresent()) {
+ if (!ChkdskInfo->FilesWhoNeedData.Remove(file_number)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+
+ if (!need_delete &&
+ !file_has_too_many_file_names &&
+ !pfrs->QueryResidentAttribute(&attribute, &error,
+ Index->QueryTypeCode(),
+ file_name,
+ index_entry->AttributeLength,
+ Index->QueryCollationRule())) {
+
+ need_delete = TRUE;
+ }
+
+ if (!need_delete &&
+ file_name_index &&
+ !file_has_too_many_file_names &&
+ !(file_name->ParentDirectory ==
+ IndexFrs->QuerySegmentReference())) {
+
+ need_delete = TRUE;
+ }
+
+ // Make sure that the duplicated information in the index
+ // entry is correct, also check the back pointers, and
+ // the flags.
+
+ if (!need_delete && file_name_index && !file_has_too_many_file_names) {
+
+ if (!pfrs->QueryDuplicatedInformation(&actual_dupinfo)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ frs_file_name = (PFILE_NAME) attribute.GetResidentValue();
+ DebugAssert(frs_file_name);
+
+
+ p = &file_name->Info;
+ q = &actual_dupinfo;
+ dupinfo_match = TRUE;
+
+ if (memcmp(p, q, sizeof(DUPLICATED_INFORMATION)) ||
+ frs_file_name->Flags != file_name->Flags) {
+
+ if (file_number >= FIRST_USER_FILE_NUMBER) {
+
+ if (p->CreationTime != q->CreationTime) {
+ dupinfo_match = FALSE;
+ DebugPrintf("UNTFS: Incorrect creation time for file 0x%X, indx = 0x%X, frs = 0x%X\n", file_number.GetLowPart(),
+ p->CreationTime.GetLowPart(), q->CreationTime.GetLowPart());
+ }
+
+ if (p->LastModificationTime != q->LastModificationTime) {
+ dupinfo_match = FALSE;
+ DebugPrintf("UNTFS: Incorrect last mod time for file 0x%X, indx = 0x%X, frs = 0x%X\n", file_number.GetLowPart(),
+ p->LastModificationTime.GetLowPart(), q->LastModificationTime.GetLowPart());
+ }
+
+ if (p->LastChangeTime != q->LastChangeTime) {
+ dupinfo_match = FALSE;
+ DebugPrintf("UNTFS: Incorrect last change time for file 0x%X, indx = 0x%X, frs = 0x%X\n", file_number.GetLowPart(),
+ p->LastChangeTime.GetLowPart(), q->LastChangeTime.GetLowPart());
+ }
+
+ if (p->AllocatedLength != q->AllocatedLength) {
+ dupinfo_match = FALSE;
+ DebugPrintf("UNTFS: Incorrect allocation length for file 0x%X, indx = 0x%X, frs = 0x%X\n", file_number.GetLowPart(),
+ p->AllocatedLength.GetLowPart(), q->AllocatedLength.GetLowPart());
+ }
+
+ if (p->FileSize != q->FileSize) {
+ dupinfo_match = FALSE;
+ DebugPrintf("UNTFS: Incorrect file size for file 0x%X, indx = 0x%X, frs = 0x%X\n", file_number.GetLowPart(),
+ p->FileSize.GetLowPart(), q->FileSize.GetLowPart());
+ }
+
+ if (p->FileAttributes != q->FileAttributes) {
+ dupinfo_match = FALSE;
+ DebugPrintf("UNTFS: Incorrect file attributes for file 0x%X, indx = 0x%X, frs = 0x%X\n", file_number.GetLowPart(),
+ p->FileAttributes, q->FileAttributes);
+ }
+
+ if (p->PackedEaSize != q->PackedEaSize) {
+ dupinfo_match = FALSE;
+ DebugPrintf("UNTFS: Incorrect packed ea size for file 0x%X, indx = 0x%X, frs = 0x%X\n", file_number.GetLowPart(),
+ p->PackedEaSize, q->PackedEaSize);
+ }
+
+ if (file_name->Flags != frs_file_name->Flags) {
+ dupinfo_match = FALSE;
+ DebugPrintf("UNTFS: Incorrect file name flags for file 0x%X, indx = 0x%X, frs = 0x%X\n", file_number.GetLowPart(),
+ file_name->Flags, frs_file_name->Flags);
+ }
+ } else {
+ dupinfo_match = FALSE;
+ }
+ }
+
+
+ if (!dupinfo_match) {
+
+ // Don't report duplicated information on system files.
+
+ if (file_number >= FIRST_USER_FILE_NUMBER) {
+ FileSystemConsistencyErrorsFound = TRUE;
+ if (CHKDSK_EXIT_SUCCESS == ChkdskInfo->ExitStatus) {
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_MINOR_ERRS;
+ }
+ }
+
+
+// Take out this message because it's annoying.
+#if 0
+ Message->Set(MSG_CHK_NTFS_INACCURATE_DUPLICATED_INFORMATION);
+ Message->Display("%d", file_number.GetLowPart());
+#endif
+
+ if (FixLevel != CheckOnly) {
+ *Changes = TRUE;
+ }
+
+ memcpy(&file_name->Info, &actual_dupinfo,
+ sizeof(DUPLICATED_INFORMATION));
+ file_name->Flags = frs_file_name->Flags;
+
+ if (FixLevel != CheckOnly && !Index->WriteCurrentEntry()) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ if (!(frs_file_name->ParentDirectory ==
+ file_name->ParentDirectory)) {
+
+ need_delete = TRUE;
+ }
+ }
+
+
+ if (need_delete) {
+
+ *Changes = TRUE;
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+
+ if (file_name_index) {
+ Message->Set(MSG_CHK_NTFS_DELETING_INDEX_ENTRY);
+ Message->Display("%d%W%W",
+ IndexFrs->QueryFileNumber().GetLowPart(),
+ Index->GetName(),
+ &entry_name);
+ } else {
+ Message->Set(MSG_CHK_NTFS_DELETING_GENERIC_INDEX_ENTRY);
+ Message->Display("%d%W",
+ IndexFrs->QueryFileNumber().GetLowPart(),
+ Index->GetName());
+ }
+
+ *DiskErrorsFound = TRUE;
+
+ if (FixLevel != CheckOnly &&
+ !Index->DeleteCurrentEntry()) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ } else if (file_number < ChkdskInfo->NumFiles) {
+ ChkdskInfo->ReferenceCount[file_number.GetLowPart()]--;
+ if (file_name_index) {
+ ChkdskInfo->NumFileNames[file_number.GetLowPart()]--;
+
+ if (!DirectoryDigraph->AddEdge(IndexFrs->QueryFileNumber().
+ GetLowPart(),
+ file_number.GetLowPart())) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+NTFS_SA::ValidateEntriesInObjIdIndex(
+ IN OUT PNTFS_INDEX_TREE Index,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT IndexFrs,
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ OUT PBOOLEAN Changes,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN DiskErrorsFound
+ )
+/*++
+
+Routine Description:
+
+ This routine goes through all of the entries in the given object id
+ index and makes sure that they point to an appropriate file with
+ the same object id.
+
+Arguments:
+
+ Index - Supplies the index.
+ IndexFrs - Supplies the index frs.
+ ChkdskInfo - Supplies the current chkdsk information.
+ Changes - Returns whether or not changes were made.
+ Mft - Supplies the master file table.
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages.
+ DiskErrorsFound - Supplies whether or not disk errors have
+ been found.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PNTFS_FILE_RECORD_SEGMENT pfrs;
+ NTFS_FILE_RECORD_SEGMENT frs;
+ PCINDEX_ENTRY index_entry;
+ POBJID_INDEX_ENTRY_VALUE objid_index_entry;
+ ULONG depth;
+ BOOLEAN error;
+ VCN file_number;
+ NTFS_ATTRIBUTE attribute;
+ BOOLEAN need_delete;
+ DSTRING IndexName;
+ NTFS_INDEX_TREE IndexTree;
+ BIG_INT i;
+ PINDEX_ENTRY NewEntry;
+ NUMBER_SET DuplicateTest;
+ BOOLEAN AlreadyExists;
+ BOOLEAN need_save;
+ OBJECT_ID ObjId;
+ ULONG BytesRead;
+ BOOLEAN chkdskErrCouldNotFix = FALSE;
+
+ //
+ // First make sure each entry in the index reference an unique frs
+ //
+
+ if (!DuplicateTest.Initialize()) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ *Changes = FALSE;
+ need_save = FALSE;
+ Index->ResetIterator();
+ while (index_entry = Index->GetNext(&depth, &error)) {
+ objid_index_entry = (POBJID_INDEX_ENTRY_VALUE) GetIndexEntryValue(index_entry);
+
+ file_number.Set(objid_index_entry->SegmentReference.LowPart,
+ (LONG) objid_index_entry->SegmentReference.HighPart);
+
+ if (DuplicateTest.CheckAndAdd(file_number, &AlreadyExists)) {
+ if (AlreadyExists) {
+
+ // another entry with same file number
+ // so we remove this colliding entry
+
+ *DiskErrorsFound = TRUE;
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+
+ Message->Set(MSG_CHK_NTFS_DELETING_GENERIC_INDEX_ENTRY);
+ Message->Display("%d%W",
+ IndexFrs->QueryFileNumber().GetLowPart(),
+ Index->GetName());
+
+ if (FixLevel != CheckOnly && SET_TRUE(*Changes) &&
+ !Index->DeleteCurrentEntry()) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ need_save = TRUE;
+ }
+ } else {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ if (need_save && FixLevel != CheckOnly && !Index->Save(IndexFrs)) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_INDEX);
+ Message->Display("%d%W",
+ IndexFrs->QueryFileNumber().GetLowPart(),
+ Index->GetName());
+ chkdskErrCouldNotFix = TRUE;
+ }
+
+ DuplicateTest.RemoveAll();
+
+ //
+ // now make sure index entries point to an existing frs
+ //
+
+ need_save = FALSE;
+ Index->ResetIterator();
+ while (index_entry = Index->GetNext(&depth, &error)) {
+
+ objid_index_entry = (POBJID_INDEX_ENTRY_VALUE) GetIndexEntryValue(index_entry);
+
+ file_number.Set(objid_index_entry->SegmentReference.LowPart,
+ (LONG) objid_index_entry->SegmentReference.HighPart);
+
+ need_delete = FALSE;
+
+ if (ChkdskInfo->FilesWithObjectId.DoesIntersectSet(file_number, 1)) {
+
+ // there is a corresponding file with an object id entry
+ // check to make sure that the two object id's are equal
+
+ ChkdskInfo->FilesWithObjectId.Remove(file_number, 1);
+
+ if (IndexFrs->QueryFileNumber() == file_number) {
+ pfrs = IndexFrs;
+ } else {
+ if (!frs.Initialize(file_number, Mft)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!frs.Read() || !frs.IsInUse()) {
+
+ // something is not right
+ // the frs was readable & in use otherwise we wouldn't be here
+
+ *DiskErrorsFound = TRUE;
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+
+ Message->Set(MSG_CHK_NTFS_DELETING_GENERIC_INDEX_ENTRY);
+ Message->Display("%d%W",
+ IndexFrs->QueryFileNumber().GetLowPart(),
+ Index->GetName());
+
+ if (FixLevel != CheckOnly && SET_TRUE(*Changes) &&
+ !Index->DeleteCurrentEntry()) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ need_save = TRUE;
+ continue;
+ }
+ pfrs = &frs;
+ }
+
+ if (!pfrs->QueryAttribute(&attribute, &error, $OBJECT_ID) ||
+ !attribute.Read(&ObjId, 0, sizeof(ObjId), &BytesRead) ||
+ BytesRead != sizeof(ObjId)) {
+ // previously exists attribute does not exists anymore
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (memcmp(&(objid_index_entry->key),
+ &ObjId, sizeof(OBJECT_ID)) != 0) {
+
+ // Assume the object id stored with the index is incorrect.
+ // We cannot just overwrite the incorrect values and write
+ // out the entry as that may change the ordering of the index.
+ // So, we delete the entry and insert it back later on
+
+ if (!ChkdskInfo->FilesWithObjectId.Add(file_number)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ *DiskErrorsFound = TRUE;
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+
+ Message->Set(MSG_CHK_NTFS_DELETING_GENERIC_INDEX_ENTRY);
+ Message->Display("%d%W",
+ IndexFrs->QueryFileNumber().GetLowPart(),
+ Index->GetName());
+
+ if (FixLevel != CheckOnly && SET_TRUE(*Changes) &&
+ !Index->DeleteCurrentEntry()) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ need_save = TRUE;
+ continue;
+ }
+
+ if (!(objid_index_entry->SegmentReference ==
+ pfrs->QuerySegmentReference())) {
+ // should correct index entry
+
+ objid_index_entry->SegmentReference = pfrs->QuerySegmentReference();
+
+ *DiskErrorsFound = TRUE;
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+
+ Message->Set(MSG_CHK_NTFS_REPAIRING_INDEX_ENTRY);
+ Message->Display("%d%W",
+ IndexFrs->QueryFileNumber().GetLowPart(),
+ Index->GetName());
+
+ if (FixLevel != CheckOnly && SET_TRUE(*Changes) &&
+ !Index->WriteCurrentEntry()) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ need_save = TRUE;
+ }
+ } else {
+ // the particular file does not have an object id entry
+ // this index entry should be deleted
+
+ *DiskErrorsFound = TRUE;
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+
+ Message->Set(MSG_CHK_NTFS_DELETING_GENERIC_INDEX_ENTRY);
+ Message->Display("%d%W",
+ IndexFrs->QueryFileNumber().GetLowPart(),
+ Index->GetName());
+
+ if (FixLevel != CheckOnly && SET_TRUE(*Changes) &&
+ !Index->DeleteCurrentEntry()) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ need_save = TRUE;
+ }
+ }
+
+ if (need_save && FixLevel != CheckOnly && !Index->Save(IndexFrs)) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_INDEX);
+ Message->Display("%d%W",
+ pfrs->QueryFileNumber().GetLowPart(),
+ Index->GetName());
+ chkdskErrCouldNotFix = TRUE;
+ }
+
+ // Now loop thru the remainder of files with object id and insert
+ // them into the object id index
+
+ if (!IndexName.Initialize(ObjectIdIndexNameData) ||
+ !IndexTree.Initialize( IndexFrs->GetDrive(),
+ QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ IndexFrs->GetUpcaseTable(),
+ IndexFrs->QuerySize()/2,
+ IndexFrs,
+ &IndexName ) ) {
+ return FALSE;
+ }
+ if (!(NewEntry = (PINDEX_ENTRY)MALLOC(sizeof(INDEX_ENTRY) +
+ sizeof(OBJID_INDEX_ENTRY_VALUE)))) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ IndexTree.FreeAllocation();
+ return FALSE;
+ }
+
+ need_save = FALSE;
+ i = 0;
+ while (i < ChkdskInfo->FilesWithObjectId.QueryCardinality()) {
+ file_number = ChkdskInfo->FilesWithObjectId.QueryNumber(i);
+ ChkdskInfo->FilesWithObjectId.Remove(file_number);
+ if (!frs.Initialize(file_number, Mft) ||
+ !frs.Read() ||
+ !frs.QueryAttribute(&attribute, &error, $OBJECT_ID) ||
+ !attribute.Read(&ObjId, 0, sizeof(ObjId), &BytesRead) ||
+ BytesRead != sizeof(ObjId)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ IndexTree.FreeAllocation();
+ FREE(NewEntry);
+ return FALSE;
+ }
+
+ memset((PVOID)NewEntry, 0, sizeof(INDEX_ENTRY) +
+ sizeof(OBJID_INDEX_ENTRY_VALUE));
+ NewEntry->DataOffset = sizeof(INDEX_ENTRY)+sizeof(OBJECT_ID);
+ NewEntry->DataLength = sizeof(OBJID_INDEX_ENTRY_VALUE)-sizeof(OBJECT_ID);
+ NewEntry->ReservedForZero = 0;
+ NewEntry->Length = sizeof(INDEX_ENTRY)+sizeof(OBJID_INDEX_ENTRY_VALUE);
+ NewEntry->AttributeLength = sizeof(OBJECT_ID);
+ NewEntry->Flags = 0;
+
+ objid_index_entry = ((POBJID_INDEX_ENTRY_VALUE)GetIndexEntryValue(NewEntry));
+ memcpy(&(objid_index_entry->key), &ObjId, sizeof(OBJECT_ID));
+ objid_index_entry->SegmentReference = frs.QuerySegmentReference();
+ memset(objid_index_entry->extraInfo, 0, sizeof(objid_index_entry->extraInfo));
+
+ *DiskErrorsFound = TRUE;
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+
+ Message->Set(MSG_CHK_NTFS_INSERTING_INDEX_ENTRY);
+ Message->Display("%d%W",
+ IndexFrs->QueryFileNumber().GetLowPart(),
+ Index->GetName());
+
+ if (FixLevel != CheckOnly && SET_TRUE(*Changes) &&
+ !IndexTree.InsertEntry( NewEntry )) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ IndexTree.FreeAllocation();
+ FREE(NewEntry);
+ return FALSE;
+ }
+ need_save = TRUE;
+ }
+
+ if (FixLevel == CheckOnly) {
+ IndexTree.FreeAllocation();
+ FREE(NewEntry);
+ if (chkdskErrCouldNotFix)
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_COULD_NOT_FIX;
+ return TRUE;
+ }
+
+ if (need_save && !IndexTree.Save(IndexFrs)) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_INDEX);
+ Message->Display("%d%W",
+ IndexFrs->QueryFileNumber().GetLowPart(),
+ Index->GetName());
+ chkdskErrCouldNotFix = TRUE;
+ }
+
+ IndexTree.FreeAllocation();
+ FREE(NewEntry);
+
+ if (chkdskErrCouldNotFix)
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_COULD_NOT_FIX;
+ return TRUE;
+}
+
+BOOLEAN
+RemoveBadLink(
+ IN ULONG ParentFileNumber,
+ IN ULONG ChildFileNumber,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine removes all file name links between the given
+ parent in child. Neither the directory entries nor the
+ file names are preserved.
+
+Arguments:
+
+ ParentFileNumber - Supplies the parent file number.
+ ChildFileNumber - Supplies the child file number.
+ Mft - Supplies the master file table.
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_FILE_RECORD_SEGMENT parent_frs;
+ NTFS_INDEX_TREE index;
+ NTFS_FILE_RECORD_SEGMENT child_frs;
+ PNTFS_FILE_RECORD_SEGMENT pchild_frs;
+ DSTRING index_name;
+ BOOLEAN error;
+ NTFS_ATTRIBUTE attribute;
+ ULONG i;
+ PFILE_NAME file_name;
+ ULONG attr_len;
+ BOOLEAN success;
+
+ if (ParentFileNumber == ROOT_FILE_NAME_INDEX_NUMBER &&
+ ChildFileNumber == ROOT_FILE_NAME_INDEX_NUMBER) {
+
+ return TRUE;
+ }
+
+ if (!parent_frs.Initialize(ParentFileNumber, Mft) ||
+ !parent_frs.Read() ||
+ !index_name.Initialize(FileNameIndexNameData) ||
+ !index.Initialize(parent_frs.GetDrive(),
+ parent_frs.QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ Mft->GetUpcaseTable(),
+ parent_frs.QuerySize()/2,
+ &parent_frs,
+ &index_name)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (ParentFileNumber == ChildFileNumber) {
+ pchild_frs = &parent_frs;
+ } else {
+
+ pchild_frs = &child_frs;
+
+ if (!pchild_frs->Initialize(ChildFileNumber, Mft) ||
+ !pchild_frs->Read()) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ for (i = 0; pchild_frs->QueryAttributeByOrdinal(&attribute, &error,
+ $FILE_NAME, i); i++) {
+
+ file_name = (PFILE_NAME) attribute.GetResidentValue();
+ attr_len = attribute.QueryValueLength().GetLowPart();
+
+ if (file_name->ParentDirectory.LowPart == ParentFileNumber) {
+
+ if (!pchild_frs->DeleteResidentAttribute($FILE_NAME, NULL,
+ file_name, attr_len, &success) ||
+ !success ||
+ !index.DeleteEntry(attr_len, file_name, 0)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+ }
+
+ if (error || FixLevel != CheckOnly) {
+ if (error ||
+ !index.Save(&parent_frs) ||
+ !parent_frs.Flush(Mft->GetVolumeBitmap()) ||
+ !pchild_frs->Flush(Mft->GetVolumeBitmap())) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_SA::RecoverOrphans(
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PDIGRAPH DirectoryDigraph,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine recovers orphans into a subdirectory of the root
+ subdirectory. It also validates the existence of the file
+ systems root directory which it expects to be supplied in the
+ list of 'OrphanedDirectories'.
+
+Arguments:
+
+ ChkdskInfo - Supplies the current chkdsk information.
+ DirectoryDigraph - Supplies the directory digraph.
+ Mft - Supplies the master file table.
+ FixLevel - Supplies the fix up level.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ LIST bad_links;
+ PITERATOR bad_links_iter;
+ PDIGRAPH_EDGE p;
+ NUMBER_SET parents_of_root;
+ ULONG i, n;
+ NTFS_FILE_RECORD_SEGMENT root_frs;
+ NTFS_INDEX_TREE root_index;
+ DSTRING index_name;
+ NUMBER_SET orphans;
+ PNUMBER_SET no_ref;
+ ULONG cluster_size;
+
+ cluster_size = QueryClusterFactor() * _drive->QuerySectorSize();
+
+ // First make sure that the root directory is intact.
+
+ if (!index_name.Initialize(FileNameIndexNameData) ||
+ !root_frs.Initialize(ROOT_FILE_NAME_INDEX_NUMBER, Mft) ||
+ !root_frs.Read()) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!root_frs.IsIndexPresent() ||
+ !root_index.Initialize(_drive, QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ Mft->GetUpcaseTable(),
+ root_frs.QuerySize()/2,
+ &root_frs,
+ &index_name)) {
+
+ Message->Set(MSG_CHK_NTFS_CREATING_ROOT_DIRECTORY);
+ Message->Display();
+
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+
+ if (!root_index.Initialize($FILE_NAME,
+ _drive, QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ Mft->GetUpcaseTable(),
+ COLLATION_FILE_NAME,
+ SMALL_INDEX_BUFFER_SIZE,
+ root_frs.QuerySize()/2,
+ &index_name)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (FixLevel != CheckOnly &&
+ (!root_index.Save(&root_frs) ||
+ !root_frs.Flush(Mft->GetVolumeBitmap()))) {
+
+ DebugAbort("can't write");
+ return FALSE;
+ }
+ }
+
+
+ // Compute the list of orphans. This is to include files with
+ // no references whatsoever.
+
+ if (!orphans.Initialize()) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ for (i = 0; i < ChkdskInfo->NumFiles; i++) {
+ if (ChkdskInfo->NumFileNames[i] && !orphans.Add(i)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ no_ref = &(ChkdskInfo->FilesWithNoReferences);
+ if (!no_ref->Remove(0, FIRST_USER_FILE_NUMBER) ||
+ !orphans.Add(no_ref)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (orphans.QueryCardinality() != 0) {
+
+ Message->Set(MSG_CHK_NTFS_RECOVERING_ORPHANS);
+ Message->Display();
+
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+
+ // Connect all possible orphans the easy way. Adjust the
+ // directory digraph accordingly.
+
+ if (!ProperOrphanRecovery(&orphans, Mft, DirectoryDigraph,
+ FixLevel, Message)) {
+ return FALSE;
+ }
+ }
+
+
+ // Construct a list with all of the links that introduce cycles
+ // or point to the root.
+
+ if (!bad_links.Initialize() ||
+ !DirectoryDigraph->EliminateCycles(&bad_links) ||
+ !(bad_links_iter = bad_links.QueryIterator()) ||
+ !DirectoryDigraph->QueryParents(ROOT_FILE_NAME_INDEX_NUMBER,
+ &parents_of_root)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ n = parents_of_root.QueryCardinality().GetLowPart();
+ for (i = 0; i < n; i++) {
+
+ if (!(p = NEW DIGRAPH_EDGE)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ p->Parent = parents_of_root.QueryNumber(i).GetLowPart();
+ p->Child = ROOT_FILE_NAME_INDEX_NUMBER;
+
+ if (!bad_links.Put(p)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ bad_links_iter->Reset();
+ while (p = (PDIGRAPH_EDGE) bad_links_iter->GetNext()) {
+
+ // Ignore links from the root to itself.
+
+ if (p->Parent == ROOT_FILE_NAME_INDEX_NUMBER &&
+ p->Child == ROOT_FILE_NAME_INDEX_NUMBER) {
+
+ continue;
+ }
+
+ Message->Set(MSG_CHK_NTFS_CYCLES_IN_DIR_TREE);
+ Message->Display();
+
+ if (FixLevel == CheckOnly) {
+ return TRUE;
+ }
+
+ if (!RemoveBadLink(p->Parent, p->Child, Mft, FixLevel, Message)) {
+ return FALSE;
+ }
+ }
+
+ DELETE(bad_links_iter);
+ bad_links.DeleteAllMembers();
+
+
+ // Recover the remaining orphans.
+
+ if (!root_frs.Initialize(ROOT_FILE_NAME_INDEX_NUMBER, Mft) ||
+ !root_frs.Read() ||
+ !root_index.Initialize(_drive, QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ Mft->GetUpcaseTable(),
+ root_frs.QuerySize()/2,
+ &root_frs,
+ &index_name)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (orphans.QueryCardinality() != 0 &&
+ !OldOrphanRecovery(&orphans, ChkdskInfo, &root_frs, &root_index,
+ Mft, FixLevel, Message)) {
+
+ return FALSE;
+ }
+
+ if (FixLevel != CheckOnly) {
+
+ if (!root_index.Save(&root_frs) ||
+ !root_frs.Flush(Mft->GetVolumeBitmap())) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_CREATE_ORPHANS);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+ConnectFile(
+ IN OUT PNTFS_FILE_RECORD_SEGMENT OrphanFile,
+ IN OUT PDIGRAPH DirectoryDigraph,
+ OUT PBOOLEAN Connected,
+ IN BOOLEAN RemoveCrookedLinks,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine connects all possible file names contained in
+ the orphan to their parents. If any or all end up being
+ connected before of after this call then *Connected will be
+ set to TRUE. If RemoveCrookedLinks is TRUE then this routine
+ will delete any file names that cannot be connected to their
+ parents.
+
+Arguments:
+
+ OrphanFile - Supplies the file to connect.
+ DirectoryDigraph - Supplies the directory digraph for future
+ enhancements.
+ Connected - Returns whether or not the file could be
+ connected to at least one directory.
+ RemoveCrookedLinks - Supplies whether or not to remove file names
+ which cannot be connected to their parents.
+ Mft - Supplies the master file table.
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ DSTRING index_name;
+ NTFS_FILE_RECORD_SEGMENT parent_file;
+ PNTFS_FILE_RECORD_SEGMENT pparent_file;
+ NTFS_INDEX_TREE parent_index;
+ ULONG i;
+ MFT_SEGMENT_REFERENCE parent_seg_ref;
+ VCN parent_file_number;
+ DSTRING file_name_string;
+ NTFS_ATTRIBUTE file_name_attribute;
+ NTFS_ATTRIBUTE attribute;
+ BOOLEAN error;
+ PFILE_NAME file_name;
+ MFT_SEGMENT_REFERENCE seg_ref;
+ BOOLEAN success;
+
+ if (!index_name.Initialize(FileNameIndexNameData)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ // Iterate through all of the file name entries here.
+
+ *Connected = FALSE;
+ for (i = 0; OrphanFile->QueryAttributeByOrdinal(
+ &file_name_attribute, &error,
+ $FILE_NAME, i); i++) {
+
+ file_name = (PFILE_NAME) file_name_attribute.GetResidentValue();
+ DebugAssert(file_name);
+
+
+ // Figure out who the claimed parent of the orphan is.
+
+ parent_seg_ref = file_name->ParentDirectory;
+
+ if (!file_name_string.Initialize(
+ file_name->FileName,
+ (ULONG) file_name->FileNameLength)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ parent_file_number.Set(parent_seg_ref.LowPart,
+ (LONG) parent_seg_ref.HighPart);
+
+ if (parent_file_number == OrphanFile->QueryFileNumber()) {
+ pparent_file = OrphanFile;
+ } else {
+ pparent_file = &parent_file;
+
+ if (!pparent_file->Initialize(parent_file_number, Mft)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+
+ // Determine whether or not the so-called parent is a real index.
+
+ if ((pparent_file != OrphanFile && !pparent_file->Read()) ||
+ !pparent_file->IsInUse() ||
+ !(pparent_file->QuerySegmentReference() == parent_seg_ref) ||
+ !pparent_file->QueryAttribute(&attribute, &error, $FILE_NAME) ||
+ !parent_index.Initialize(OrphanFile->GetDrive(),
+ OrphanFile->QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ pparent_file->GetUpcaseTable(),
+ pparent_file->QuerySize()/2,
+ pparent_file,
+ &index_name) ||
+ parent_index.QueryTypeCode() != $FILE_NAME) {
+
+ if (RemoveCrookedLinks) {
+ OrphanFile->DeleteResidentAttribute($FILE_NAME, NULL,
+ file_name,
+ file_name_attribute.QueryValueLength().GetLowPart(),
+ &success);
+
+ OrphanFile->SetReferenceCount(
+ OrphanFile->QueryReferenceCount() + 1);
+
+ i--;
+ }
+
+ continue;
+ }
+
+
+ // First make sure that the entry isn't already in there.
+
+ if (parent_index.QueryFileReference(
+ file_name_attribute.QueryValueLength().GetLowPart(),
+ file_name, 0, &seg_ref, &error)) {
+
+ // If the entry is there and points to this orphan
+ // then the file is already connected. Otherwise,
+ // this file cannot be connected to the parent index
+ // through this file name. This file_name is then "crooked".
+
+ if (seg_ref == OrphanFile->QuerySegmentReference()) {
+ *Connected = TRUE;
+ } else if (RemoveCrookedLinks) {
+
+ OrphanFile->DeleteResidentAttribute($FILE_NAME, NULL,
+ file_name,
+ file_name_attribute.QueryValueLength().GetLowPart(),
+ &success);
+
+ // Readjust the reference count post delete because
+ // the file-name we deleted does not appear in any index.
+
+ OrphanFile->SetReferenceCount(
+ OrphanFile->QueryReferenceCount() + 1);
+
+ if (!OrphanFile->VerifyAndFixFileNames(Mft->GetVolumeBitmap(),
+ FixLevel, Message) ||
+ !OrphanFile->Flush(Mft->GetVolumeBitmap(),
+ &parent_index)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ i--;
+ }
+
+ continue;
+ }
+
+
+ // Now there is a parent directory so add this file name
+ // into the index.
+
+ Message->Set(MSG_CHK_NTFS_RECOVERING_ORPHAN);
+ Message->Display("%W%d", &file_name_string,
+ pparent_file->QueryFileNumber().GetLowPart());
+
+ if (FixLevel != CheckOnly) {
+
+ if (!parent_index.InsertEntry(
+ file_name_attribute.QueryValueLength().GetLowPart(),
+ file_name,
+ OrphanFile->QuerySegmentReference()) ||
+ !OrphanFile->Flush(Mft->GetVolumeBitmap(),
+ &parent_index) ||
+ !parent_index.Save(pparent_file) ||
+ !pparent_file->Flush(Mft->GetVolumeBitmap())) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_RECOVER_ORPHAN);
+ Message->Display();
+ }
+ }
+
+ DirectoryDigraph->AddEdge(pparent_file->QueryFileNumber().GetLowPart(),
+ OrphanFile->QueryFileNumber().GetLowPart());
+
+ OrphanFile->SetReferenceCount(
+ OrphanFile->QueryReferenceCount() + 1);
+
+ *Connected = TRUE;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_SA::ProperOrphanRecovery(
+ IN OUT PNUMBER_SET Orphans,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN OUT PDIGRAPH DirectoryDigraph,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine attempts to recover the given orphans where they
+ belong. All properly recovered orphans will be deleted from the
+ orphans list.
+
+Arguments:
+
+ Orphans - Supplies the list of orphans.
+ Mft - Supplies the master file table.
+ DirectoryDigraph - Supplies the directory digraph for future
+ enhancement.
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_FILE_RECORD_SEGMENT orphan_file;
+ BIG_INT i;
+ BOOLEAN connected;
+
+ i = 0;
+ while (i < Orphans->QueryCardinality()) {
+
+ // First read in the orphaned file.
+
+ if (!orphan_file.Initialize(Orphans->QueryNumber(i), Mft) ||
+ !orphan_file.Read()) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!orphan_file.VerifyAndFixFileNames(
+ Mft->GetVolumeBitmap(), FixLevel, Message)) {
+
+ return FALSE;
+ }
+
+ if (!ConnectFile(&orphan_file, DirectoryDigraph,
+ &connected, FALSE,
+ Mft, FixLevel, Message)) {
+
+ return FALSE;
+ }
+
+ if (connected) {
+ if (!Orphans->Remove(Orphans->QueryNumber(i))) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ // Go through the list of file names and delete those that
+ // don't point anywhere. Only do this one if in /F
+ // mode. Otherwise we see each orphan being recovered
+ // twice.
+
+ if (FixLevel != CheckOnly) {
+ if (!ConnectFile(&orphan_file, DirectoryDigraph,
+ &connected, TRUE,
+ Mft, FixLevel, Message)) {
+
+ return FALSE;
+ }
+ }
+
+ } else {
+ i += 1;
+ }
+
+ if (FixLevel != CheckOnly &&
+ !orphan_file.Flush(Mft->GetVolumeBitmap())) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_RECOVER_ORPHAN);
+ Message->Display();
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+RecordParentPointers(
+ IN PCNUMBER_SET Orphans,
+ IN PCNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ OUT PDIGRAPH BackPointers
+ )
+/*++
+
+Routine Description:
+
+ This routine records the parent pointer information in the given
+ digraph with (parent, source) edges.
+
+Arguments:
+
+ Orphans - Supplies the list of orphans.
+ ChkdskInfo - Supplies the chkdsk information.
+ Mft - Supplies the MFT.
+ BackPointers - Returns the parent pointer relationships.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_FILE_RECORD_SEGMENT frs;
+ NTFS_ATTRIBUTE attribute;
+ BOOLEAN error;
+ ULONG i;
+ PFILE_NAME file_name;
+ ULONG parent_dir;
+ ULONG file_number;
+
+ if (!BackPointers->Initialize(ChkdskInfo->NumFiles)) {
+ return FALSE;
+ }
+
+ for (i = 0; i < Orphans->QueryCardinality(); i++) {
+
+ file_number = Orphans->QueryNumber(i).GetLowPart();
+
+ if (!frs.Initialize(file_number, Mft) ||
+ !frs.Read()) {
+ return FALSE;
+ }
+
+ // Only consider one file name per file for this
+ // analysis. This is because we don't ever want
+ // to have file in multiple found directories.
+
+ if (frs.QueryAttribute(&attribute, &error, $FILE_NAME)) {
+
+ file_name = (PFILE_NAME) attribute.GetResidentValue();
+
+ parent_dir = file_name->ParentDirectory.LowPart;
+
+ if (parent_dir < ChkdskInfo->NumFiles &&
+ file_name->ParentDirectory.HighPart == 0 &&
+ !BackPointers->AddEdge(parent_dir, file_number)) {
+ return FALSE;
+ }
+
+ } else if (error) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+CreateNtfsDirectory(
+ IN OUT PNTFS_INDEX_TREE CurrentIndex,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT CurrentDirFile,
+ IN PCWSTRING FileName,
+ OUT PNTFS_INDEX_TREE SubDirIndex,
+ OUT PNTFS_FILE_RECORD_SEGMENT SubDirFile,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ OUT PBOOLEAN OutOfDisk
+ )
+/*++
+
+Routine Description:
+
+ This routine creates a new subdirectory for a directory.
+
+Arguments:
+
+ CurrentIndex - Supplies the index in which to insert the
+ new subdirectory entry.
+ CurrentDirFile - Supplies the FRS for the above index.
+ FileName - Supplies the name of the new directory.
+ SubDirIndex - Returns the index of the new subdirectory.
+ SubDirFile - Returns the FRS of the new subdirectory.
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages.
+ OutOfDisk - Returns whether this routine ran out of disk
+ space or not.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ VCN dir_file_number;
+ STANDARD_INFORMATION standard_info;
+ FILE_NAME file_name[2];
+ ULONG file_name_size;
+ DSTRING index_name;
+ ULONG cluster_size;
+
+ *OutOfDisk = FALSE;
+
+ // Create a new file for this directory.
+
+ if (!Mft->AllocateFileRecordSegment(&dir_file_number, FALSE)) {
+ Message->Set(MSG_CHK_NTFS_CANT_CREATE_ORPHANS);
+ Message->Display();
+ *OutOfDisk = TRUE;
+ return TRUE;
+ }
+
+ if (!SubDirFile->Initialize(dir_file_number, Mft)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ file_name->ParentDirectory = CurrentDirFile->QuerySegmentReference();
+ file_name->FileNameLength = (UCHAR)FileName->QueryChCount();
+ file_name->Flags = FILE_NAME_NTFS | FILE_NAME_DOS;
+ FileName->QueryWSTR(0, TO_END, file_name->FileName,
+ sizeof(FILE_NAME)/sizeof(WCHAR));
+ file_name_size = FIELD_OFFSET(FILE_NAME, FileName) +
+ FileName->QueryChCount()*sizeof(WCHAR);
+
+ memset(&standard_info, 0, sizeof(STANDARD_INFORMATION));
+
+ IFS_SYSTEM::QueryNtfsTime(&standard_info.CreationTime);
+
+ standard_info.LastModificationTime =
+ standard_info.LastChangeTime =
+ standard_info.LastAccessTime = standard_info.CreationTime;
+
+ if (!SubDirFile->Create(&standard_info) ||
+ !SubDirFile->AddFileNameAttribute(file_name)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ cluster_size = Mft->QueryClusterFactor() * Mft->QuerySectorSize();
+
+ if (!index_name.Initialize(FileNameIndexNameData) ||
+ !SubDirIndex->Initialize($FILE_NAME,
+ SubDirFile->GetDrive(),
+ SubDirFile->QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ Mft->GetUpcaseTable(),
+ COLLATION_FILE_NAME,
+ CurrentIndex->QueryBufferSize(),
+ SubDirFile->QuerySize()/2,
+ &index_name)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+
+ // Insert the found file into the root index.
+
+ if (FixLevel != CheckOnly &&
+ !CurrentIndex->InsertEntry(file_name_size, file_name,
+ SubDirFile->QuerySegmentReference())) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_CREATE_ORPHANS);
+ Message->Display();
+
+ Mft->GetMftBitmap()->SetFree(dir_file_number, 1);
+ *OutOfDisk = TRUE;
+ return TRUE;
+ }
+
+ SubDirFile->SetIndexPresent();
+
+ return TRUE;
+}
+
+
+BOOLEAN
+BuildOrphanSubDir(
+ IN ULONG DirNumber,
+ IN ULONG OldParentDir,
+ IN OUT PNUMBER_SET OrphansInDir,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN OUT PNTFS_INDEX_TREE FoundIndex,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT FoundFrs,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ OUT PBOOLEAN OutOfDisk
+ )
+/*++
+
+Routine Description:
+
+ This routine build orphan directory 'dir<DirNumber>.chk' to
+ contain the entries listed in 'OrphansInDir' and then puts
+ that directory in given found directory.
+
+Arguments:
+
+ DirNumber - Supplies the number of the directory to add.
+ OldParentDir - Supplies the old directory file number.
+ OrphansInDir - Supplies the file numbers of the orphans to
+ add to the new directory. Returns those
+ orphans that were not recovered.
+ Mft - Supplies the MFT.
+ FoundIndex - Supplies the index of the found.XXX directory.
+ FoundFrs - Supplies the frs of found.XXX
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages.
+ OutOfDisk - Indicates out of disk space.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_FILE_RECORD_SEGMENT dir_file;
+ NTFS_INDEX_TREE dir_index;
+ DSTRING dir_name;
+ ULONG i, j, current_orphan;
+ NTFS_FILE_RECORD_SEGMENT orphan_file;
+ CHAR buf[20];
+ NTFS_ATTRIBUTE attribute;
+ BOOLEAN error;
+ PFILE_NAME file_name;
+ BOOLEAN success, connect;
+ ULONG file_name_len;
+
+
+ // First put together 'dir0000.chk' and add the entry to
+ // found.000.
+
+ sprintf(buf, "dir%04d.chk", DirNumber);
+ if (!dir_name.Initialize(buf)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!CreateNtfsDirectory(FoundIndex, FoundFrs, &dir_name, &dir_index,
+ &dir_file, Mft, FixLevel, Message, OutOfDisk)) {
+
+ return FALSE;
+ }
+
+ if (*OutOfDisk == TRUE) {
+ return TRUE;
+ }
+
+ i = 0;
+ while (i < OrphansInDir->QueryCardinality().GetLowPart()) {
+
+ current_orphan = OrphansInDir->QueryNumber(i).GetLowPart();
+
+ if (!orphan_file.Initialize(current_orphan, Mft) ||
+ !orphan_file.Read()) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ // Go through all of the file names and tube those
+ // that are not pointing to the old parent dir. Otherwise
+ // tweek the entry to point back to the new directory.
+
+ connect = FALSE;
+ j = 0;
+ while (orphan_file.QueryAttributeByOrdinal(&attribute, &error,
+ $FILE_NAME, j)) {
+
+ file_name = (PFILE_NAME) attribute.GetResidentValue();
+ file_name_len = attribute.QueryValueLength().GetLowPart();
+
+ if (file_name->ParentDirectory.LowPart == OldParentDir &&
+ file_name->ParentDirectory.HighPart == 0) {
+
+ if (!orphan_file.DeleteResidentAttribute(
+ $FILE_NAME, NULL, file_name, file_name_len, &success) ||
+ !success) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ orphan_file.SetReferenceCount(
+ orphan_file.QueryReferenceCount() + 1);
+
+ file_name->ParentDirectory = dir_file.QuerySegmentReference();
+
+ if (!attribute.InsertIntoFile(&orphan_file,
+ Mft->GetVolumeBitmap())) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ j = 0; // reset ordinal as the insertion may have changed
+ // the ordering of the $FILE_NAME attributes
+
+ if (FixLevel != CheckOnly) {
+ if (dir_index.InsertEntry(file_name_len, file_name,
+ orphan_file.QuerySegmentReference())) {
+
+ connect = TRUE;
+
+ } else {
+
+ // this one didn't connect, so destroy the
+ // file_name attribute. Note that we have
+ // already adjusted the reference count so
+ // (unlike the parallel case in proper orphan
+ // recovery) we don't need to tweek it here.
+
+ orphan_file.DeleteResidentAttribute(
+ $FILE_NAME, NULL, file_name, file_name_len,
+ &success);
+ }
+
+ } else {
+ connect = TRUE; // don't panic read-only chkdsk
+ }
+ continue;
+ } else if (!(file_name->ParentDirectory ==
+ dir_file.QuerySegmentReference())) {
+ if (!orphan_file.DeleteResidentAttribute(
+ $FILE_NAME, NULL, file_name, file_name_len, &success) ||
+ !success) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ orphan_file.SetReferenceCount(
+ orphan_file.QueryReferenceCount() + 1);
+
+ j = 0;
+ continue;
+ }
+ j++;
+ }
+
+ if (error) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!orphan_file.VerifyAndFixFileNames(Mft->GetVolumeBitmap(),
+ FixLevel, Message)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (FixLevel != CheckOnly &&
+ !orphan_file.Flush(Mft->GetVolumeBitmap(), &dir_index)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ // If this one was connected then take it out of the list
+ // of files that we're orphaned. Otherwise just increment
+ // the counter.
+
+ if (connect) {
+ if (!OrphansInDir->Remove(current_orphan)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ } else {
+ i++;
+ }
+ }
+
+ if (FixLevel != CheckOnly) {
+
+ if (!dir_index.Save(&dir_file) ||
+ !dir_file.Flush(Mft->GetVolumeBitmap(), FoundIndex)) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_CREATE_ORPHANS);
+ Message->Display();
+
+ *OutOfDisk = TRUE;
+
+ return TRUE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_SA::OldOrphanRecovery(
+ IN OUT PNUMBER_SET Orphans,
+ IN PCNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT RootFrs,
+ IN OUT PNTFS_INDEX_TREE RootIndex,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine recovers all of the orphans in the given list
+ into a found.xxx directory.
+
+Arguments:
+
+ Orphans - Supplies the list of orphans.
+ ChkdskInfo - Supplies the current chkdsk information.
+ RootFrs - Supplies the root FRS.
+ RootIndex - Supplies the root index.
+ Mft - Supplies the master file table.
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ FILE_NAME found_name[2];
+ ULONG found_name_size;
+ MFT_SEGMENT_REFERENCE ref;
+ BOOLEAN error;
+ NTFS_FILE_RECORD_SEGMENT found_directory;
+ ULONG i;
+ NTFS_INDEX_TREE found_index;
+ NTFS_FILE_RECORD_SEGMENT orphan_file;
+ DSTRING index_name;
+ FILE_NAME orphan_file_name[2];
+ ULONG next_dir_num;
+ ULONG next_file_num;
+ VCN file_number;
+ DIGRAPH back_pointers;
+ NUMBER_SET dir_candidates;
+ NUMBER_SET orphans_in_dir;
+ ULONG dir_num;
+ DSTRING lost_and_found;
+ BOOLEAN out_of_disk;
+ CHAR buf[20];
+
+
+ // Create the FOUND.XXX directory.
+
+ for (i = 0; i < 1000; i++) {
+ found_name->Flags = FILE_NAME_DOS | FILE_NAME_NTFS;
+ found_name->ParentDirectory = RootFrs->QuerySegmentReference();
+ found_name->FileName[0] = 'f';
+ found_name->FileName[1] = 'o';
+ found_name->FileName[2] = 'u';
+ found_name->FileName[3] = 'n';
+ found_name->FileName[4] = 'd';
+ found_name->FileName[5] = '.';
+ found_name->FileName[6] = USHORT(i/100 + '0');
+ found_name->FileName[7] = USHORT((i/10)%10 + '0');
+ found_name->FileName[8] = USHORT(i%10 + '0');
+ found_name->FileNameLength = 9;
+
+ found_name_size = NtfsFileNameGetLength(found_name);
+
+ if (!RootIndex->QueryFileReference(found_name_size, found_name, 0,
+ &ref, &error) && !error) {
+ break;
+ }
+ }
+
+ if (i == 1000) {
+ Message->Set(MSG_CHK_NTFS_CANT_CREATE_ORPHANS);
+ Message->Display();
+ return TRUE;
+ }
+
+ sprintf(buf, "found.%03d", i);
+ if (!lost_and_found.Initialize(buf)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!CreateNtfsDirectory(RootIndex, RootFrs, &lost_and_found,
+ &found_index, &found_directory, Mft, FixLevel,
+ Message, &out_of_disk)) {
+ return FALSE;
+ }
+
+ if (out_of_disk) {
+ return TRUE;
+ }
+
+ // Record the parent pointer relationship of the orphans in a
+ // digraph and then extract those parents who have more than
+ // one child.
+
+ if (!RecordParentPointers(Orphans, ChkdskInfo, Mft, &back_pointers) ||
+ !back_pointers.QueryParentsWithChildren(&dir_candidates, 2)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ // Remove the root directory from consideration. Since the
+ // root directory exists any legitimate orphans should have
+ // been properly recovered. If a bunch point to the root
+ // but couldn't be put into the root the just put them in
+ // found.XXX, not a subdir thereof.
+
+ dir_candidates.Remove(ROOT_FILE_NAME_INDEX_NUMBER);
+
+
+ // Using the information just attained, put together some nice
+ // found subdirectories for orphans with common parents.
+
+ for (i = 0; i < dir_candidates.QueryCardinality(); i++) {
+
+ dir_num = dir_candidates.QueryNumber(i).GetLowPart();
+
+ if (!back_pointers.QueryChildren(dir_num, &orphans_in_dir) ||
+ !Orphans->Remove(&orphans_in_dir)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!BuildOrphanSubDir(i, dir_num, &orphans_in_dir, Mft,
+ &found_index, &found_directory,
+ FixLevel, Message, &out_of_disk)) {
+ return FALSE;
+ }
+
+ // Add back those orphans that were not recovered.
+
+ if (!Orphans->Add(&orphans_in_dir)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (out_of_disk) {
+ return TRUE;
+ }
+ }
+
+
+ // Now go through all of the orphans that remain.
+
+ for (next_dir_num = i, next_file_num = 0;
+ Orphans->QueryCardinality() != 0 &&
+ next_dir_num < 10000 && next_file_num < 10000;
+ Orphans->Remove(file_number)) {
+
+ file_number = Orphans->QueryNumber(0);
+
+ if (!orphan_file.Initialize(file_number, Mft)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!orphan_file.Read()) {
+ continue;
+ }
+
+ if (!orphan_file.VerifyAndFixFileNames(Mft->GetVolumeBitmap(),
+ FixLevel, Message)) {
+
+ return FALSE;
+ }
+
+ // Delete all file name attributes on this file and set
+ // the current reference count to 0.
+
+ while (orphan_file.IsAttributePresent($FILE_NAME)) {
+ if (!orphan_file.PurgeAttribute($FILE_NAME)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ orphan_file.SetReferenceCount(0);
+
+ if (orphan_file.QueryFileNumber() >= FIRST_USER_FILE_NUMBER) {
+
+ // Put a new file name attribute on the orphan in
+ // order to link it to the found directory.
+
+ orphan_file_name->ParentDirectory =
+ found_directory.QuerySegmentReference();
+ orphan_file_name->Flags = FILE_NAME_DOS | FILE_NAME_NTFS;
+
+ if (orphan_file.IsIndexPresent()) {
+ orphan_file_name->FileName[0] = 'd';
+ orphan_file_name->FileName[1] = 'i';
+ orphan_file_name->FileName[2] = 'r';
+ orphan_file_name->FileName[3] = USHORT(next_dir_num/1000 + '0');
+ orphan_file_name->FileName[4] = USHORT((next_dir_num/100)%10 + '0');
+ orphan_file_name->FileName[5] = USHORT((next_dir_num/10)%10 + '0');
+ orphan_file_name->FileName[6] = USHORT(next_dir_num%10 + '0');
+ orphan_file_name->FileName[7] = '.';
+ orphan_file_name->FileName[8] = 'c';
+ orphan_file_name->FileName[9] = 'h';
+ orphan_file_name->FileName[10] = 'k';
+ orphan_file_name->FileNameLength = 11;
+ next_dir_num++;
+ } else {
+ orphan_file_name->FileName[0] = 'f';
+ orphan_file_name->FileName[1] = 'i';
+ orphan_file_name->FileName[2] = 'l';
+ orphan_file_name->FileName[3] = 'e';
+ orphan_file_name->FileName[4] = USHORT(next_file_num/1000 + '0');
+ orphan_file_name->FileName[5] = USHORT((next_file_num/100)%10 + '0');
+ orphan_file_name->FileName[6] = USHORT((next_file_num/10)%10 + '0');
+ orphan_file_name->FileName[7] = USHORT(next_file_num%10 + '0');
+ orphan_file_name->FileName[8] = '.';
+ orphan_file_name->FileName[9] = 'c';
+ orphan_file_name->FileName[10] = 'h';
+ orphan_file_name->FileName[11] = 'k';
+ orphan_file_name->FileNameLength = 12;
+ next_file_num++;
+ }
+
+ if (!orphan_file.AddFileNameAttribute(orphan_file_name)) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_CREATE_ORPHANS);
+ Message->Display();
+ return TRUE;
+ }
+
+ if (FixLevel != CheckOnly &&
+ !found_index.InsertEntry(
+ NtfsFileNameGetLength(orphan_file_name),
+ orphan_file_name,
+ orphan_file.QuerySegmentReference())) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_CREATE_ORPHANS);
+ Message->Display();
+ return TRUE;
+ }
+ }
+
+ // Write out the newly found orphan.
+
+ if (FixLevel != CheckOnly &&
+ !orphan_file.Flush(Mft->GetVolumeBitmap(), &found_index)) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_CREATE_ORPHANS);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+
+ if (next_dir_num == 10000 || next_file_num == 10000) {
+ Message->Set(MSG_CHK_NTFS_TOO_MANY_ORPHANS);
+ Message->Display();
+ }
+
+
+ // Flush out the found.
+
+ if (FixLevel != CheckOnly) {
+
+ if (!found_index.Save(&found_directory) ||
+ !found_directory.Flush(Mft->GetVolumeBitmap(), RootIndex)) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_CREATE_ORPHANS);
+ Message->Display();
+
+ return TRUE;
+ }
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+ExtractExtendInfo(
+ IN OUT PNTFS_INDEX_TREE Index,
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine extracts the frs numbers for each of the corresponding
+ files in the \$Extend directory. It ignores file name that it does
+ not recognize.
+
+Arguments:
+
+ Index - Supplies the index to the $Extend directory.
+ ChkdskInfo - Supplies the current chkdsk information.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ DSTRING entry_name;
+ PFILE_NAME file_name;
+ DSTRING extend_filename;
+ FSTRING expected_extend_filename;
+ VCN file_number;
+ PCINDEX_ENTRY index_entry;
+ ULONG depth;
+ BOOLEAN error;
+
+ Index->ResetIterator();
+ while (index_entry = Index->GetNext(&depth, &error)) {
+ file_name = (PFILE_NAME) GetIndexEntryValue(index_entry);
+ expected_extend_filename.Initialize(LQuotaFileName);
+ if (!extend_filename.Initialize(NtfsFileNameGetName(file_name),
+ file_name->FileNameLength)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ if (extend_filename.Strcmp(&expected_extend_filename) == 0) {
+ if (ChkdskInfo->QuotaFileNumber.GetLowPart() ||
+ ChkdskInfo->QuotaFileNumber.GetHighPart()) {
+ Message->Set(MSG_CHK_NTFS_MULTIPLE_QUOTA_FILE);
+ Message->Display();
+ } else {
+ file_number.Set(index_entry->FileReference.LowPart,
+ (LONG) index_entry->FileReference.HighPart);
+ ChkdskInfo->QuotaFileNumber = file_number;
+ }
+ continue;
+ }
+ expected_extend_filename.Initialize(LObjectIdFileName);
+ if (!extend_filename.Initialize(NtfsFileNameGetName(file_name),
+ file_name->FileNameLength)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ if (extend_filename.Strcmp(&expected_extend_filename) == 0) {
+ if (ChkdskInfo->ObjectIdFileNumber.GetLowPart() ||
+ ChkdskInfo->ObjectIdFileNumber.GetHighPart()) {
+ Message->Set(MSG_CHK_NTFS_MULTIPLE_OBJECTID_FILE);
+ Message->Display();
+ } else {
+ file_number.Set(index_entry->FileReference.LowPart,
+ (LONG) index_entry->FileReference.HighPart);
+ ChkdskInfo->ObjectIdFileNumber = file_number;
+ }
+ continue;
+ }
+ }
+ return TRUE;
+}
+
diff --git a/private/utils/untfs/src/indxroot.cxx b/private/utils/untfs/src/indxroot.cxx
new file mode 100644
index 000000000..d1d0ed1e7
--- /dev/null
+++ b/private/utils/untfs/src/indxroot.cxx
@@ -0,0 +1,639 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ indxroot.hxx
+
+Abstract:
+
+ this module contains the member funciton definitions for the
+ NTFS_INDEX_ROOT class, which models the root of an NTFS index
+
+Author:
+
+ Bill McJohn (billmc) 06-Sept-1991
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "untfs.hxx"
+
+#include "drive.hxx"
+
+#include "attrib.hxx"
+#include "frs.hxx"
+#include "indxroot.hxx"
+#include "indxtree.hxx"
+
+DEFINE_CONSTRUCTOR( NTFS_INDEX_ROOT, OBJECT );
+
+NTFS_INDEX_ROOT::~NTFS_INDEX_ROOT(
+ )
+{
+ Destroy();
+}
+
+
+VOID
+NTFS_INDEX_ROOT::Construct(
+ )
+/*++
+
+Routine Description:
+
+ Worker function for object construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _MaximumSize = 0;
+ _DataLength = 0;
+ _Data = NULL;
+ _IsModified = FALSE;
+ _UpcaseTable = NULL;
+
+}
+
+VOID
+NTFS_INDEX_ROOT::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This method cleans up an NTFS_INDEX_ROOT object in preparation
+ for destruction or reinitialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _MaximumSize = 0;
+ _DataLength = 0;
+ FREE( _Data );
+ _IsModified = FALSE;
+ _UpcaseTable = NULL;
+
+}
+
+
+BOOLEAN
+NTFS_INDEX_ROOT::Initialize(
+ IN PNTFS_ATTRIBUTE RootAttribute,
+ IN PNTFS_UPCASE_TABLE UpcaseTable,
+ IN ULONG MaximumSize
+ )
+/*++
+
+Routine Description:
+
+ This method initializes the index root based on an $INDEX_ROOT
+ attribute. It is used to initialize an index root object for
+ an extant index.
+
+Arguments:
+
+ RootAttribute -- supplies the $INDEX_ROOT attribute for
+ this index.
+ UpcaseTable -- supplies the volume upcase table.
+ MaximumSize -- supplies the maximum size of this index root
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ If the existing attribute's value length is greater than the
+ supplied maximum size, the maximum size will be adjusted.
+
+--*/
+{
+ BIG_INT ValueLength;
+ ULONG BytesRead;
+
+ DebugPtrAssert( RootAttribute );
+
+ Destroy();
+
+ RootAttribute->QueryValueLength( &ValueLength );
+
+ // Check that the attribute is the correct type and that
+ // it is a reasonable size.
+
+ if( RootAttribute->QueryTypeCode() != $INDEX_ROOT ||
+ ValueLength.GetHighPart() != 0 ) {
+
+ return FALSE;
+ }
+
+ // If the existing attribute is already bigger than the specified
+ // maximum size, then increase the maximum size, since it is only
+ // provided to give an upper bound on the size of the attribute.
+
+ if( ValueLength.GetLowPart() > MaximumSize ) {
+
+ MaximumSize = ValueLength.GetLowPart();
+ }
+
+ _DataLength = ValueLength.GetLowPart();
+ _MaximumSize = MaximumSize;
+ _IsModified = FALSE;
+
+ if( (_Data = (PINDEX_ROOT)MALLOC( _MaximumSize )) == NULL ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ if( !RootAttribute->Read( _Data,
+ 0,
+ _DataLength,
+ &BytesRead ) ||
+ BytesRead != _DataLength ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ _UpcaseTable = UpcaseTable;
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_INDEX_ROOT::Initialize(
+ IN ATTRIBUTE_TYPE_CODE IndexedAttributeType,
+ IN COLLATION_RULE CollationRule,
+ IN PNTFS_UPCASE_TABLE UpcaseTable,
+ IN ULONG ClustersPerBuffer,
+ IN ULONG BytesPerBuffer,
+ IN ULONG MaximumRootSize
+ )
+/*++
+
+Routine Description:
+
+ This method initializes the index root based on the fundamental
+ information of the index. It is used to initialize an index root
+ for a new index.
+
+Arguments:
+
+ IndexedAttributeType -- supplies the type code of the attribute
+ which is indexed by this index.
+ CollationRule -- supplies the collation rule for this index.
+ UpcaseTable -- supplies the volume upcase table.
+ BytesPerBuffer -- supplies the number of bytes per Index
+ Allocation Buffer in this index.
+ MaximumRootSize -- supplies the maximum size of this index root.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This method marks the index root as modified, since it is being
+ created ex nihilo instead of being read from an attribute.
+
+ It creates an empty leaf index root (ie. with only an END entry).
+
+--*/
+{
+ PINDEX_ENTRY EndEntry;
+
+ DebugAssert( sizeof( INDEX_ROOT ) % 8 == 0 );
+ DebugAssert( sizeof( INDEX_HEADER ) % 8 == 0 );
+
+ Destroy();
+
+ _UpcaseTable = UpcaseTable;
+ _MaximumSize = MaximumRootSize;
+ _IsModified = TRUE;
+
+ _DataLength = sizeof( INDEX_ROOT ) + NtfsIndexLeafEndEntrySize;
+
+ // check to make sure that an empty index root will fit in the
+ // maximum size given. Note that we also reserve space for a
+ // VCN downpointer, in case this index root gets converted into
+ // a node by Recreate.
+
+ if( _DataLength + sizeof(VCN) > _MaximumSize ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ if( (_Data = (PINDEX_ROOT)MALLOC( _MaximumSize )) == NULL ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ memset( _Data, 0, _MaximumSize );
+
+ _Data->IndexedAttributeType = IndexedAttributeType;
+ _Data->CollationRule = CollationRule;
+ _Data->BytesPerIndexBuffer = BytesPerBuffer;
+ _Data->ClustersPerIndexBuffer = (UCHAR)ClustersPerBuffer;
+ _Data->IndexHeader.FirstIndexEntry = sizeof( INDEX_HEADER );
+ _Data->IndexHeader.FirstFreeByte = sizeof( INDEX_HEADER ) +
+ NtfsIndexLeafEndEntrySize;
+ _Data->IndexHeader.BytesAvailable = _Data->IndexHeader.FirstFreeByte;
+ _Data->IndexHeader.Flags = 0;
+
+ // Fill in the end entry. Its only meaningful fields are Length
+ // and Flags.
+
+ EndEntry = GetFirstEntry();
+
+ EndEntry->Length = NtfsIndexLeafEndEntrySize;
+ EndEntry->AttributeLength = 0;
+ EndEntry->Flags = INDEX_ENTRY_END;
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_INDEX_ROOT::FindEntry(
+ IN PCINDEX_ENTRY SearchEntry,
+ IN OUT PULONG Ordinal,
+ OUT PINDEX_ENTRY* EntryFound
+ )
+/*++
+
+Routine Description:
+
+ This method locates an entry in the index root. Note that it does
+ not search the index allocation b-tree (if any).
+
+
+Arguments:
+
+ SearchEntry -- Supplies a search entry, which gives the attribute
+ value to find.
+ Ordinal -- supplies an ordinal showing which matching entry
+ to return; see note below. A value of INDEX_SKIP
+ indicates that all matching entries should be skipped.
+ EntryFound -- receives a pointer to the located entry. Receives
+ NULL if an error has occurred.
+
+Return Value:
+
+ TRUE if a matching entry is found.
+
+ If an error occurs, *EntryFound is set to NULL.
+
+ If no error occurs, and no matching entry is found, *EntryFound
+ is set to the next entry (i.e. the point at which the search key
+ would be inserted into this index root) and the method returns
+ FALSE.
+
+Notes:
+
+ This method assumes that the index root is consistent.
+
+ The ordinal argument indicates how many matching entries should be
+ passed over before one is returned. When an entry is found which
+ matches the search key, if *Ordinal is zero, that entry is returned;
+ otherwise, *Ordinal is decremented, and the FindEntry goes on to
+ the next entry.
+
+ If *Ordinal is INDEX_SKIP, all matching entries are skipped.
+
+--*/
+{
+ PINDEX_ENTRY CurrentEntry;
+ BOOLEAN Found;
+ int CompareResult;
+
+ CurrentEntry = GetFirstEntry();
+ Found = FALSE;
+
+ while( !(CurrentEntry->Flags & INDEX_ENTRY_END) ) {
+
+ CompareResult = CompareNtfsIndexEntries( SearchEntry,
+ CurrentEntry,
+ _Data->CollationRule,
+ _UpcaseTable);
+
+ if( CompareResult < 0 ) {
+
+ // The search value is less than the current entry's
+ // value, so we've overshot where our search key would
+ // be. Stop (and return the current entry).
+
+ break;
+
+ } else if( CompareResult == 0 ) {
+
+ // The current entry matches the search entry. Check
+ // the ordinal argument to see if we should return this
+ // entry or skip it.
+
+ if( *Ordinal == 0 ) {
+
+ Found = TRUE;
+ break;
+
+ } else if( *Ordinal != INDEX_SKIP ) {
+
+ *Ordinal -= 1;
+ }
+ }
+
+ // Haven't found our entry, so we'll just go on to the next.
+
+ CurrentEntry = GetNextEntry( CurrentEntry );
+ }
+
+ *EntryFound = CurrentEntry;
+ return( Found );
+}
+
+
+BOOLEAN
+NTFS_INDEX_ROOT::InsertEntry(
+ IN PCINDEX_ENTRY NewEntry,
+ IN PINDEX_ENTRY InsertPoint
+ )
+/*++
+
+Routine Description:
+
+ This inserts an index entry into the index root. It will
+ expand the index root (if possible), but it will not split it.
+
+Arguments:
+
+ NewEntry -- supplies the new entry to be inserted.
+ InsertPoint -- supplies the point at which the new entry should be
+ inserted--it may be NULL, in which case the index
+ root should decide for itself.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ A return value of FALSE indicates that there is not enough room
+ for the entry in this index root.
+
+ If an insertion point is specified, it must be a pointer returned
+ by a previous call to FindEntry or GetFirstEntry (with no intervening
+ inserts or deletes).
+
+ This method assumes that the index root and the new entry are
+ consistent, which includes that the entry has a downpointer if
+ and only if the index root is a node.
+
+--*/
+{
+ ULONG Ordinal, BytesToMove;
+
+
+ // Check to see if there's room.
+
+ if( _DataLength + NewEntry->Length > _MaximumSize ) {
+
+ return FALSE;
+ }
+
+ // There's enough room, so we're bound to succeed.
+
+ if( InsertPoint == NULL ) {
+
+ // The client has not supplied the insert point, so we get to
+ // figure it out for ourselves. Fortunately, we can get FindEntry
+ // to do our work for us.
+
+ // Note that we don't care what InsertEntry returns--we know it
+ // won't hit an error, and we don't care whether there are any
+ // matching entries in the buffer. (If we get a matching buffer,
+ // we insert the new one before it, which is just fine.)
+
+ Ordinal = 0;
+
+ FindEntry( NewEntry,
+ &Ordinal,
+ &InsertPoint );
+
+ DebugPtrAssert( InsertPoint );
+ }
+
+
+ // Make room for the new entry...
+
+ BytesToMove = _Data->IndexHeader.FirstFreeByte -
+ ((PBYTE)InsertPoint - (PBYTE)&(_Data->IndexHeader));
+
+ memmove( (PBYTE)InsertPoint + NewEntry->Length,
+ InsertPoint,
+ BytesToMove );
+
+ _Data->IndexHeader.FirstFreeByte += NewEntry->Length;
+ _Data->IndexHeader.BytesAvailable = _Data->IndexHeader.FirstFreeByte;
+
+ memcpy( InsertPoint, NewEntry, NewEntry->Length );
+
+ _DataLength += NewEntry->Length;
+
+ return TRUE;
+}
+
+
+VOID
+NTFS_INDEX_ROOT::RemoveEntry(
+ PINDEX_ENTRY EntryToRemove
+ )
+/*++
+
+Routine Description:
+
+ This method removes an entry from the index root. Note that it will
+ not find a replacement entry for nodes, or perform any other b-tree
+ maintenance; it just expunges the entry from the root.
+
+Arguments:
+
+ EntryToRemove -- supplies the index entry to be removed. This
+ must be an entry returned by a previous call
+ to FindEntry or GetFirstEntry.
+
+Return Value:
+
+ None.
+
+Notes:
+
+ This method assumes that the index root is consistent.
+--*/
+{
+ PBYTE NextEntry;
+ ULONG BytesToMove;
+
+
+ DebugAssert( (PBYTE)EntryToRemove <
+ (PBYTE)&(_Data->IndexHeader) +
+ _Data->IndexHeader.FirstFreeByte );
+
+ DebugAssert( (PBYTE)EntryToRemove >=
+ (PBYTE)&(_Data->IndexHeader) +
+ _Data->IndexHeader.FirstIndexEntry );
+
+ NextEntry = (PBYTE)GetNextEntry( EntryToRemove );
+
+ BytesToMove = _Data->IndexHeader.FirstFreeByte -
+ ( NextEntry - (PBYTE)&(_Data->IndexHeader) );
+
+ _Data->IndexHeader.FirstFreeByte -= EntryToRemove->Length;
+ _Data->IndexHeader.BytesAvailable = _Data->IndexHeader.FirstFreeByte;
+
+ _DataLength -= EntryToRemove->Length;
+
+ memmove( EntryToRemove,
+ NextEntry,
+ BytesToMove );
+
+}
+
+
+
+VOID
+NTFS_INDEX_ROOT::Recreate(
+ IN BOOLEAN IsLeaf,
+ IN VCN EndEntryDownpointer
+ )
+/*++
+
+Routine Description:
+
+ This method recreates the Index Root with only an end entry.
+
+Arguments:
+
+ IsLeaf -- supplies an indicator whether this index root
+ is a leaf (TRUE) or a node (FALSE).
+ EndEntryDownpointer -- supplies the VCN DownPointer for the End
+ Entry. (If IsLeaf is TRUE, this parameter
+ is ignored.)
+
+Return Value:
+
+ None.
+
+Notes:
+
+ The basic information of the index root is not changed; just the
+ index entries and flags.
+
+--*/
+{
+ PINDEX_ENTRY EndEntry;
+ ULONG EndEntrySize;
+
+ _IsModified = TRUE;
+ _DataLength = sizeof( INDEX_ROOT ) + NtfsIndexLeafEndEntrySize;
+
+ EndEntrySize = NtfsIndexLeafEndEntrySize;
+
+ if( !IsLeaf ) {
+
+ _Data->IndexHeader.Flags = INDEX_NODE;
+ _DataLength += sizeof(VCN);
+ EndEntrySize += sizeof( VCN );
+
+ } else {
+
+ _Data->IndexHeader.Flags = 0;
+ }
+
+ DebugAssert( _MaximumSize >= _DataLength );
+
+ _Data->IndexHeader.FirstFreeByte = sizeof( INDEX_HEADER ) +
+ EndEntrySize;
+
+ _Data->IndexHeader.BytesAvailable = _Data->IndexHeader.FirstFreeByte;
+
+ // Fill in the end entry. Its only meaningful fields are Length,
+ // Flags, and downpointer (if any).
+
+ EndEntry = GetFirstEntry();
+
+ EndEntry->Length = (USHORT)EndEntrySize;
+ EndEntry->AttributeLength = 0;
+ EndEntry->Flags = INDEX_ENTRY_END;
+
+ if( !IsLeaf ) {
+
+ EndEntry->Flags |= INDEX_ENTRY_NODE;
+ GetDownpointer( EndEntry ) = EndEntryDownpointer;
+ }
+}
+
+
+BOOLEAN
+NTFS_INDEX_ROOT::Write(
+ PNTFS_ATTRIBUTE RootAttribute
+ )
+/*++
+
+Routine Description:
+
+ This method writes the index root to the supplied attribute.
+
+Arguments:
+
+ RootAttribute -- supplies the INDEX_ROOT attribute.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ ULONG BytesWritten;
+
+ // Resize the attribute to the correct size, and then write
+ // the root's data to it. Since this attribute is always
+ // resident, pass in NULL for the bitmap.
+ //
+
+ return( RootAttribute->IsResident() &&
+ RootAttribute->Resize( _DataLength, NULL ) &&
+ RootAttribute->Write( _Data,
+ 0,
+ _DataLength,
+ &BytesWritten,
+ NULL ) &&
+ BytesWritten == _DataLength );
+}
diff --git a/private/utils/untfs/src/indxtree.cxx b/private/utils/untfs/src/indxtree.cxx
new file mode 100644
index 000000000..ed72b5e57
--- /dev/null
+++ b/private/utils/untfs/src/indxtree.cxx
@@ -0,0 +1,4016 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ indxtree.cxx
+
+Abstract:
+
+ This module contains the member function definitions for the
+ NTFS_INDEX_TREE class, which models index trees on an NTFS
+ volume.
+
+ An NTFS Index Tree consists of an index root and a set of
+ index buffers. The index root is stored as the value of
+ an INDEX_ROOT attribute; the index buffers are part of the
+ value of an INDEX_ALLOCATION attribute.
+
+Author:
+
+ Bill McJohn (billmc) 19-June-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "untfs.hxx"
+
+#include "drive.hxx"
+
+#include "attrib.hxx"
+#include "frs.hxx"
+#include "indxtree.hxx"
+#include "indxbuff.hxx"
+#include "indxroot.hxx"
+#include "ntfsbit.hxx"
+#include "upcase.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+
+LONG
+CompareNtfsFileNames(
+ IN PCFILE_NAME Name1,
+ IN PCFILE_NAME Name2,
+ IN PNTFS_UPCASE_TABLE UpcaseTable
+ )
+/*++
+
+Routine Description:
+
+ This method compares two FILE_NAME structures according to the
+ COLLATION_FILE_NAME collation rule.
+
+Arguments:
+
+ Name1 -- Supplies the first name to compare.
+ Name2 -- Supplies the second name to compare.
+ UpcaseTable -- Supplies the volume upcase table.
+
+Returns:
+
+ <0 if Name1 is less than Name2
+ =0 if Name1 is equal to Name2
+ >0 if Name1 is greater than Name2.
+
+--*/
+{
+ LONG Result;
+ BOOLEAN CaseInsensitive;
+
+ // If either name has neither the FILE_NAME_NTFS nor the
+ // FILE_NAME_DOS flag set, the comparison is case sensitive.
+ //
+ CaseInsensitive = (Name1->Flags & (FILE_NAME_DOS | FILE_NAME_NTFS)) &&
+ (Name2->Flags & (FILE_NAME_DOS | FILE_NAME_NTFS));
+
+ Result = NtfsUpcaseCompare( NtfsFileNameGetName( Name1 ),
+ Name1->FileNameLength,
+ NtfsFileNameGetName( Name2 ),
+ Name2->FileNameLength,
+ UpcaseTable,
+ !CaseInsensitive );
+
+ return Result;
+}
+
+LONG
+NtfsCollate(
+ IN PCVOID Value1,
+ IN ULONG Length1,
+ IN PCVOID Value2,
+ IN ULONG Length2,
+ IN COLLATION_RULE CollationRule,
+ IN PNTFS_UPCASE_TABLE UpcaseTable
+ )
+/*++
+
+Routine Description:
+
+ This function compares two values according to an NTFS
+ collation rule.
+
+Arguments:
+
+ Value1 -- Supplies the first value.
+ Length1 -- Supplies the length of the first value.
+ Value2 -- Supplies the second value.
+ Length2 -- Supplies the length of the second value.
+ CollationRule -- Supplies the rule used for collation.
+ UpcaseTable -- Supplies the volume upcase table. (May be NULL
+ if the collatio rule is not COLLATION_FILE_NAME).
+
+Return Value:
+
+ <0 if Entry1 is less than Entry2 by CollationRule
+ 0 if Entry1 is equal to Entry2 by CollationRule
+ >0 if Entry1 is greater than Entry2 by CollationRule
+
+Notes:
+
+ The upcase table is only required for comparing file names.
+
+ If two values are compared according to an unsupported collation
+ rule, they are always treated as equal.
+
+--*/
+{
+ LONG result;
+
+ switch( CollationRule ) {
+
+ case COLLATION_BINARY :
+
+ // Binary collation of the values.
+ //
+ result = memcmp( Value1,
+ Value2,
+ MIN( Length1, Length2 ) );
+
+ if( result != 0 ) {
+
+ return result;
+
+ } else {
+
+ return( Length1 - Length2 );
+ }
+
+ case COLLATION_FILE_NAME :
+
+ return CompareNtfsFileNames( (PFILE_NAME)Value1,
+ (PFILE_NAME)Value2,
+ UpcaseTable );
+
+
+ case COLLATION_UNICODE_STRING :
+
+ // unsupported collation rule.
+ //
+ return 0;
+
+ case COLLATION_ULONG:
+
+ // Unsigned long collation
+
+ DebugAssert(Length1 == sizeof(ULONG));
+ DebugAssert(Length1 == sizeof(ULONG));
+
+ if (*(ULONG*)Value1 < *(ULONG *)Value2)
+ return -1;
+ else if (*(ULONG*)Value1 > *(ULONG *)Value2)
+ return 1;
+ else
+ return 0;
+
+ case COLLATION_SID:
+
+ // SecurityId collation
+
+ result = memcmp(&Length1, &Length2, sizeof(Length1));
+ if (result != 0)
+ return result;
+
+ result = memcmp( Value1, Value2, Length1 );
+ return result;
+
+ case COLLATION_SECURITY_HASH: {
+
+ // Security Hash (Hash key and SecurityId) Collation
+
+ PSECURITY_HASH_KEY HashKey1 = (PSECURITY_HASH_KEY)Value1;
+ PSECURITY_HASH_KEY HashKey2 = (PSECURITY_HASH_KEY)Value2;
+
+ DebugAssert(Length1 == sizeof(SECURITY_HASH_KEY));
+ DebugAssert(Length2 == sizeof(SECURITY_HASH_KEY));
+
+ if (HashKey1->Hash < HashKey2->Hash)
+ return -1;
+ else if (HashKey1->Hash > HashKey2->Hash)
+ return 1;
+ else if (HashKey1->SecurityId < HashKey2->SecurityId)
+ return -1;
+ else if (HashKey1->SecurityId > HashKey2->SecurityId)
+ return 1;
+ else
+ return 0;
+ }
+
+ case COLLATION_ULONGS: {
+ PULONG pu1, pu2;
+ ULONG count;
+
+ result = 0;
+
+ DebugAssert( (Length1 & 3) == 0 );
+ DebugAssert( (Length2 & 3) == 0 );
+
+ count = Length1;
+ if (count != Length2) {
+ result = -1;
+ if (count > Length2) {
+ count = Length2;
+ result = 1;
+ }
+ }
+
+ pu1 = (PULONG)Value1;
+ pu2 = (PULONG)Value2;
+
+ while (count > 0) {
+ if (*pu1 > *pu2) {
+ return 1;
+ } else if (*(pu1++) < *(pu2++)) {
+ return -1;
+ }
+ count -= 4;
+ }
+ return result;
+ }
+
+ default:
+
+ DebugAbort( "Unsupported collation rule.\n" );
+ return 0;
+ }
+}
+
+
+
+
+LONG
+CompareNtfsIndexEntries(
+ IN PCINDEX_ENTRY Entry1,
+ IN PCINDEX_ENTRY Entry2,
+ IN COLLATION_RULE CollationRule,
+ IN PNTFS_UPCASE_TABLE UpcaseTable
+ )
+/*++
+
+Routine Description:
+
+ This global function is used to compare index entries.
+
+Arguments:
+
+ Entry1 -- Supplies the first entry to compare.
+ Entry2 -- Supplies the second entry to compare.
+ CollationRule -- Supplies the rule used for collation.
+ UpcaseTable -- Supplies the volume upcase table.
+
+Return Value:
+
+ <0 if Entry1 is less than Entry2 by CollationRule
+ 0 if Entry1 is equal to Entry2 by CollationRule
+ >0 if Entry1 is greater than Entry2 by CollationRule
+
+Notes:
+
+ The upcase table is only required for comparing file names.
+
+--*/
+{
+ return NtfsCollate( GetIndexEntryValue( Entry1 ),
+ Entry1->AttributeLength,
+ GetIndexEntryValue( Entry2 ),
+ Entry2->AttributeLength,
+ CollationRule,
+ UpcaseTable );
+}
+
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( NTFS_INDEX_TREE, OBJECT, UNTFS_EXPORT );
+
+UNTFS_EXPORT
+NTFS_INDEX_TREE::~NTFS_INDEX_TREE(
+ )
+{
+ Destroy();
+}
+
+VOID
+NTFS_INDEX_TREE::Construct(
+ )
+/*++
+
+Routine Description:
+
+ Worker function for object construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _Drive = NULL;
+ _ClusterFactor = 0;
+ _ClustersPerBuffer = 0;
+ _BufferSize = 0;
+ _VolumeBitmap = NULL;
+ _UpcaseTable = NULL;
+ _AllocationAttribute = NULL;
+ _IndexAllocationBitmap = NULL;
+ _IndexRoot = NULL;
+ _Name = NULL;
+
+ _IteratorState = INDEX_ITERATOR_RESET;
+ _CurrentEntry = NULL;
+ _CurrentBuffer = NULL;
+ _CurrentKey = NULL;
+ _CurrentKeyLength = 0;
+}
+
+VOID
+NTFS_INDEX_TREE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This method cleans up an NTFS_INDEX_TREE object in preparation
+ for destruction or reinitialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _Drive = NULL;
+ _ClustersPerBuffer = 0;
+ _BufferSize = 0;
+ _VolumeBitmap = NULL;
+ _UpcaseTable = NULL;
+
+ DELETE( _AllocationAttribute );
+ DELETE( _IndexAllocationBitmap );
+ DELETE( _IndexRoot );
+ DELETE( _Name );
+
+ _IteratorState = INDEX_ITERATOR_RESET;
+
+ _CurrentEntry = NULL;
+ DELETE( _CurrentBuffer );
+ FREE( _CurrentKey );
+
+ _CurrentKeyLength = 0;
+}
+
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_INDEX_TREE::Initialize(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN ULONG ClusterFactor,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN PNTFS_UPCASE_TABLE UpcaseTable,
+ IN ULONG MaximumRootSize,
+ IN PNTFS_FILE_RECORD_SEGMENT SourceFrs,
+ IN PCWSTRING IndexName
+ )
+/*++
+
+Routine Description:
+
+ This method initializes an NTFS_INDEX_TREE based on
+ attributes queried from a File Record Segment.
+
+Arguments:
+
+ Drive -- supplies the drive on which the
+ index resides.
+ ClusterFactor -- supplies the cluster factor for the drive.
+ VolumeBitmap -- supplies the volume bitmap.
+ MaximumRootSize -- supplies the maximum length of the index root
+ SourceFrs -- supplies the File Record Segment that contains
+ this index.
+ UpcaseTable -- supplies the volume upcase table.
+ IndexName -- supplies the name for this index. (May be NULL,
+ in which case the index has no name.)
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ SourceFrs must have an $INDEX_ROOT attribute, or this method will
+ fail.
+
+ The index tree does not remember what File Record Segment it came
+ from; it only uses the FRS as a place to get the index root and
+ index allocation attributes.
+
+ The volume upcase table is only required if the indexed attribute
+ type code is $FILE_NAME.
+
+--*/
+{
+ NTFS_ATTRIBUTE RootAttribute;
+ NTFS_ATTRIBUTE BitmapAttribute;
+
+ BIG_INT ValueLength;
+ ULONG NumberOfBuffers;
+ BOOLEAN Error;
+
+ Destroy();
+
+ DebugAssert(0 != ClusterFactor);
+
+ if( !SourceFrs->QueryAttribute( &RootAttribute,
+ &Error,
+ $INDEX_ROOT,
+ IndexName ) ||
+ (_IndexRoot = NEW NTFS_INDEX_ROOT) == NULL ||
+ !_IndexRoot->Initialize( &RootAttribute,
+ UpcaseTable,
+ MaximumRootSize ) ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ _Drive = Drive;
+ _ClusterFactor = ClusterFactor;
+ _ClustersPerBuffer = _IndexRoot->QueryClustersPerBuffer();
+ _BufferSize = _IndexRoot->QueryBufferSize();
+ _VolumeBitmap = VolumeBitmap;
+ _UpcaseTable = UpcaseTable;
+
+ DebugAssert(0 != _BufferSize);
+
+ if( RootAttribute.GetName() != NULL &&
+ ( (_Name = NEW DSTRING) == NULL ||
+ !_Name->Initialize( RootAttribute.GetName() ) ) ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ _IndexedAttributeType = _IndexRoot->QueryIndexedAttributeType();
+ _CollationRule = _IndexRoot->QueryCollationRule();
+
+ if( SourceFrs->IsAttributePresent( $INDEX_ALLOCATION, IndexName ) ) {
+
+ if( (_AllocationAttribute = NEW NTFS_ATTRIBUTE) == NULL ||
+ !SourceFrs->QueryAttribute( _AllocationAttribute,
+ &Error,
+ $INDEX_ALLOCATION,
+ IndexName ) ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ // Set (ie. initialize and read) the bitmap associated with
+ // the index allocation attribute. Note that the bitmap
+ // attribute's value may be larger than necessary to cover
+ // the allocation attribute because the bitmap attribute's
+ // value always grows in increments of eight bytes. However,
+ // at this point, we don't care, since we only worry about
+ // that when we grow the bitmap.
+
+ _AllocationAttribute->QueryValueLength( &ValueLength );
+
+ DebugAssert( ValueLength % _BufferSize == 0 );
+
+ NumberOfBuffers = ValueLength.GetLowPart()/_BufferSize;
+
+
+ if( (_IndexAllocationBitmap = NEW NTFS_BITMAP) == NULL ||
+ !_IndexAllocationBitmap->Initialize( NumberOfBuffers, TRUE ) ||
+ !SourceFrs->QueryAttribute( &BitmapAttribute,
+ &Error,
+ $BITMAP,
+ IndexName ) ||
+ !_IndexAllocationBitmap->Read( &BitmapAttribute ) ) {
+
+ Destroy();
+ return FALSE;
+ }
+ }
+
+ // Set up the buffer to support iteration. This buffer must be
+ // big enough to hold the largest key value. The size of an
+ // index allocation buffer will suffice.
+
+ _IteratorState = INDEX_ITERATOR_RESET;
+ _CurrentKeyMaxLength = _BufferSize;
+
+ if( (_CurrentKey = MALLOC( _CurrentKeyMaxLength )) == NULL ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ _CurrentKeyLength = 0;
+
+ if( !_CurrentEntryTrail.Initialize() ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_INDEX_TREE::Initialize(
+ IN ATTRIBUTE_TYPE_CODE IndexedAttributeType,
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN ULONG ClusterFactor,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN PNTFS_UPCASE_TABLE UpcaseTable,
+ IN COLLATION_RULE CollationRule,
+ IN ULONG BufferSize,
+ IN ULONG MaximumRootSize,
+ IN PCWSTRING IndexName
+ )
+/*++
+
+Routine Description:
+
+ This method initializes an NTFS_INDEX_TREE based on its basic
+ information. It is used when creating an index.
+
+Arguments:
+
+ Drive -- supplies the drive on which the
+ index resides.
+ VolumeBitmap -- supplies the volume bitmap
+ UpcaseTable -- supplies the volume upcase table.
+ IndexedAttributeType -- supplies the attribute type code of the
+ attribute which is used as the key for
+ this index.
+ CollationRule -- supplies the collation rule for this index.
+ BufferSize -- supplies the size of each Index Buffer in this index.
+ MaximumRootSize -- supplies the maximum length of the index root
+ IndexName -- supplies the name of this index. (May be
+ NULL, in which case the index has no name.)
+
+Return Value:
+
+ TRUE upon successful completion.
+
+ The volume upcase table is only required if the indexed attribute
+ type code is $FILE_NAME.
+
+--*/
+{
+ ULONG ClusterSize;
+
+ Destroy();
+
+ DebugAssert(0 != ClusterFactor);
+ DebugPtrAssert(Drive);
+
+ _Drive = Drive;
+ _BufferSize = BufferSize;
+ _VolumeBitmap = VolumeBitmap;
+ _UpcaseTable = UpcaseTable;
+ _ClusterFactor = ClusterFactor;
+
+ ClusterSize = Drive->QuerySectorSize()*ClusterFactor;
+
+ DebugAssert(ClusterSize <= 64 * 1024);
+
+ _ClustersPerBuffer = BufferSize / ((BufferSize < ClusterSize) ?
+ NTFS_INDEX_BLOCK_SIZE : ClusterSize);
+
+ if( IndexName != NULL &&
+ ( (_Name = NEW DSTRING) == NULL ||
+ !_Name->Initialize( IndexName ) ) ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ _IndexedAttributeType = IndexedAttributeType;
+ _CollationRule = CollationRule;
+
+ _AllocationAttribute = NULL;
+ _IndexAllocationBitmap = NULL;
+
+ if( (_IndexRoot = NEW NTFS_INDEX_ROOT) == NULL ||
+ !_IndexRoot->Initialize( IndexedAttributeType,
+ CollationRule,
+ UpcaseTable,
+ _ClustersPerBuffer,
+ BufferSize,
+ MaximumRootSize ) ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+
+ // Set up the buffer to support iteration. This buffer must be
+ // big enough to hold the largest key value. The size of an
+ // index allocation buffer will suffice.
+
+ _IteratorState = INDEX_ITERATOR_RESET;
+ _CurrentKeyMaxLength = BufferSize;
+
+ if( (_CurrentKey = MALLOC( _CurrentKeyMaxLength )) == NULL ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ _CurrentKeyLength = 0;
+
+ if( !_CurrentEntryTrail.Initialize() ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_INDEX_TREE::QueryFileReference(
+ IN ULONG KeyLength,
+ IN PVOID Key,
+ IN ULONG Ordinal,
+ OUT PMFT_SEGMENT_REFERENCE SegmentReference,
+ OUT PBOOLEAN Error
+ )
+/*++
+
+Routine Description:
+
+ This method determines the file which contains the specified
+ value of the indexed attribute.
+
+Arguments:
+
+ KeyLength -- supplies the length of the search key value.
+ Key -- supplies the search key value.
+ Ordinal -- supplies a zero-based ordinal indicating
+ which matching entry to return (zero indicates
+ return the first matching entry).
+ SegmentReference -- receives a segment reference to the Base File
+ Record Segment of the file which contains the
+ supplied value of the indexed attribute.
+ Error -- receives an indication of whether an
+ error (e.g. out of memory) occurred.
+
+Return Value:
+
+ TRUE upon successful completion. In this case, the state of
+ *Error is undefined.
+
+ If the method fails because of a resource problem, it returns FALSE
+ and sets *Error to TRUE. If it fails because the index
+ is invalid or because the search value is not in the index, then
+ it returns FALSE and sets *Error to TRUE. In either case,
+ the contents of SegmentReference are undefined.
+
+--*/
+{
+ INTSTACK ParentTrail;
+ PNTFS_INDEX_BUFFER ContainingBuffer;
+ PINDEX_ENTRY FoundEntry;
+ BOOLEAN Result;
+
+ if( FindEntry( KeyLength,
+ Key,
+ Ordinal,
+ &FoundEntry,
+ &ContainingBuffer,
+ &ParentTrail ) ) {
+
+ memcpy( SegmentReference,
+ &FoundEntry->FileReference,
+ sizeof( MFT_SEGMENT_REFERENCE ) );
+
+ *Error = FALSE;
+ Result = TRUE;
+
+ } else {
+
+ *Error = (FoundEntry == NULL);
+ Result = FALSE;
+ }
+
+ if( ContainingBuffer != NULL ) {
+
+ DELETE( ContainingBuffer );
+ }
+
+ return Result;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_INDEX_TREE::QueryEntry(
+ IN ULONG KeyLength,
+ IN PVOID Key,
+ IN ULONG Ordinal,
+ OUT PINDEX_ENTRY* FoundEntry,
+ OUT PNTFS_INDEX_BUFFER* ContainingBuffer,
+ OUT PBOOLEAN Error
+ )
+/*++
+
+Routine Description:
+
+ This method returns the index entry that matches the given key.
+
+Arguments:
+
+ KeyLength -- supplies the length of the search key value.
+ Key -- supplies the search key value.
+ Ordinal -- supplies a zero-based ordinal indicating
+ which matching entry to return (zero indicates
+ return the first matching entry).
+ FoundEntry -- Receives a pointer to the located entry
+ (NULL indicates error).
+ Error -- receives an indication of whether an
+ error (e.g. out of memory) occurred.
+
+Return Value:
+
+ TRUE upon successful completion. In this case, the state of
+ *Error is undefined.
+
+ If the method fails because of a resource problem, it returns FALSE
+ and sets *Error to TRUE. If it fails because the index
+ is invalid or because the search value is not in the index, then
+ it returns FALSE and sets *Error to TRUE. In either case,
+ the contents of SegmentReference are undefined.
+
+--*/
+{
+ INTSTACK ParentTrail;
+ BOOLEAN Result;
+
+ if( FindEntry( KeyLength,
+ Key,
+ Ordinal,
+ FoundEntry,
+ ContainingBuffer,
+ &ParentTrail ) ) {
+
+ *Error = FALSE;
+ Result = TRUE;
+
+ } else {
+
+ *Error = (FoundEntry == NULL);
+ Result = FALSE;
+ }
+
+ return Result;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_INDEX_TREE::InsertEntry(
+ IN ULONG KeyLength,
+ IN PVOID KeyValue,
+ IN MFT_SEGMENT_REFERENCE FileReference,
+ IN BOOLEAN NoDuplicates
+ )
+/*++
+
+Routine Description:
+
+ This method inserts a new entry into the index given its
+ value and segment reference.
+
+Arguments:
+
+ KeyLength -- supplies the length of the key, in bytes.
+ KeyValue -- supplies the key value.
+ SegmentReference -- supplies the segment reference to the file
+ which contains the indexed attribute with
+ this key value.
+ NoDuplicates -- Supplies a flag which, if TRUE, indicates
+ that InsertEntry should fail if a matching
+ entry is already present in the index.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ PINDEX_ENTRY NewEntry;
+ USHORT EntryLength;
+ BOOLEAN Result;
+
+ // Compute the length of the new entry:
+
+ EntryLength = QuadAlign( sizeof(INDEX_ENTRY) + KeyLength );
+
+ if( (NewEntry = (PINDEX_ENTRY)MALLOC( EntryLength )) == NULL ) {
+
+ return FALSE;
+ }
+
+ memset( NewEntry, 0, EntryLength );
+
+ NewEntry->FileReference = FileReference;
+ NewEntry->Length = EntryLength;
+ NewEntry->AttributeLength = (USHORT) KeyLength;
+ NewEntry->Flags = 0;
+
+ memcpy( (PBYTE)NewEntry + sizeof( INDEX_HEADER ),
+ KeyValue,
+ KeyLength );
+
+ Result = InsertEntry( NewEntry, NoDuplicates );
+
+ FREE( NewEntry );
+
+ return Result;
+}
+
+
+BOOLEAN
+NTFS_INDEX_TREE::InsertEntry(
+ IN PCINDEX_ENTRY NewEntry,
+ IN BOOLEAN NoDuplicates
+ )
+/*++
+
+Routine Description:
+
+ This method adds an entry to the index.
+
+Arguments:
+
+ NewEntry -- supplies the new entry to add to the index.
+ NoDuplicates -- Supplies a flag which, if TRUE, indicates
+ that InsertEntry should fail if a matching
+ entry is already present in the index.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ INTSTACK ParentTrail;
+
+ PNTFS_INDEX_BUFFER ContainingBuffer;
+ PINDEX_ENTRY FoundEntry;
+ ULONG Ordinal;
+ BOOLEAN Found;
+ BOOLEAN Result;
+
+ // First, find the spot in the tree where we want to insert the
+ // new entry.
+ //
+ // If the client does not allow duplicates, search for the first
+ // matching entry--if we find a match, refuse the insert; if we
+ // don't, FindEntry will find the insertion point for us.
+ //
+ // If the client does allow duplicates, call FindEntry with
+ // a value INDEX_SKIP, which indicates all matching entries
+ // should be skipped. Thus, the new entry will be inserted
+ // after all matching entries.
+ //
+ Ordinal = NoDuplicates ? 0 : (INDEX_SKIP);
+
+ Found = FindEntry( NewEntry->AttributeLength,
+ GetIndexEntryValue( NewEntry ),
+ Ordinal,
+ &FoundEntry,
+ &ContainingBuffer,
+ &ParentTrail );
+
+ if( Found && NoDuplicates ) {
+
+ // A matching entry already exists, and the client wants
+ // to fail in that case. So fail.
+ //
+ return FALSE;
+ }
+
+ DebugAssert( !Found );
+
+ // Since no matching entry was found, FindEntry will
+ // return a leaf entry as its insertion point. This
+ // makes this code a lot easier, since we only need
+ // to handle inserting a new leaf.
+ //
+ if( FoundEntry == NULL ) {
+
+ // An error occurred trying to insert the entry.
+
+ return FALSE;
+ }
+
+ if( ContainingBuffer == NULL ) {
+
+ // The root is also a leaf (see comment above), so we'll
+ // insert the new entry into it.
+
+ return( InsertIntoRoot( NewEntry, FoundEntry ) );
+
+ } else {
+
+ // We've found a leaf buffer, so we'll insert the new
+ // entry into it.
+
+ Result = InsertIntoBuffer( ContainingBuffer,
+ &ParentTrail,
+ NewEntry,
+ FoundEntry );
+
+ DELETE( ContainingBuffer );
+ return Result;
+ }
+}
+
+
+
+BOOLEAN
+NTFS_INDEX_TREE::DeleteEntry(
+ IN ULONG KeyLength,
+ IN PVOID Key,
+ IN ULONG Ordinal
+ )
+/*++
+
+Routine Description:
+
+ This method deletes an entry from the index.
+
+Arguments:
+
+ KeyLength -- supplies the length of the search key value.
+ Key -- supplies the search key value.
+ Ordinal -- supplies a zero-based ordinal indicating
+ which matching entry to delete (zero indicates
+ return the first matching entry).
+
+Return Value:
+
+ TRUE upon successful completion.
+
+ If no matching entry is found, this method returns TRUE (without
+ changing the index in any way). However, if an error occurs while
+ searching for matching entries, then the method returns FALSE.
+
+--*/
+{
+ PNTFS_INDEX_BUFFER ContainingBuffer;
+ PINDEX_ENTRY FoundEntry;
+ BOOLEAN Result;
+ INTSTACK ParentTrail;
+
+ // Locate the entry to remove.
+
+ if( !FindEntry( KeyLength,
+ Key,
+ Ordinal,
+ &FoundEntry,
+ &ContainingBuffer,
+ &ParentTrail ) ) {
+
+ // There is no matching entry in the tree, so we don't have
+ // to bother. If no error occurred, return TRUE; otherwise,
+ // return FALSE.
+
+ DELETE( ContainingBuffer );
+ return( FoundEntry != NULL );
+ }
+
+ // Call the common delete helper--this will remove the target
+ // entry and, if necessary, find a replacement for it.
+
+ Result = RemoveEntry( FoundEntry,
+ ContainingBuffer,
+ &ParentTrail );
+
+ DELETE( ContainingBuffer );
+ return Result;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_INDEX_TREE::Save(
+ IN OUT PNTFS_FILE_RECORD_SEGMENT TargetFrs
+ )
+/*++
+
+Routine Description:
+
+ This method saves the index. The root is saved as an INDEX_ROOT
+ attribute in the target File Record Segment; the index allocation
+ (if any) is saved as an INDEX_ALLOCATION attribute.
+
+Arguments:
+
+ TargetFrs -- supplies the File Record Segment in which to save
+ the index.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ NTFS_ATTRIBUTE RootAttribute;
+ NTFS_ATTRIBUTE BitmapAttribute;
+
+ BOOLEAN Error;
+
+ DebugAssert( ( _IndexAllocationBitmap == NULL &&
+ _AllocationAttribute == NULL ) ||
+ ( _IndexAllocationBitmap != NULL &&
+ _AllocationAttribute != NULL ) );
+
+
+
+ // Fetch or create attributes for the Index Root and (if necessary)
+ // the allocation bitmap. If either is to be newly created, make
+ // it resident with zero length (since writing it it resize it
+ // appropriately).
+
+ if( !TargetFrs->QueryAttribute( &RootAttribute,
+ &Error,
+ $INDEX_ROOT,
+ _Name ) &&
+ ( Error ||
+ !RootAttribute.Initialize( _Drive,
+ _ClusterFactor,
+ NULL,
+ 0,
+ $INDEX_ROOT,
+ _Name ) ) ) {
+
+ return FALSE;
+ }
+
+ if( _IndexAllocationBitmap != NULL &&
+ !TargetFrs->QueryAttribute( &BitmapAttribute,
+ &Error,
+ $BITMAP,
+ _Name ) &&
+ ( Error ||
+ !BitmapAttribute.Initialize( _Drive,
+ _ClusterFactor,
+ NULL,
+ 0,
+ $BITMAP,
+ _Name ))) {
+
+ return FALSE;
+ }
+
+ // If this tree does not have an allocation attribute, purge
+ // any existing stale allocation & bitmap attributes.
+ //
+ if( _AllocationAttribute == NULL &&
+ (!TargetFrs->PurgeAttribute( $INDEX_ALLOCATION, _Name ) ||
+ !TargetFrs->PurgeAttribute( $BITMAP, _Name )) ) {
+
+ return FALSE;
+ }
+
+
+ // Now save the attributes that describe this tree.
+ //
+ if( !_IndexRoot->Write( &RootAttribute ) ||
+ !RootAttribute.InsertIntoFile( TargetFrs, _VolumeBitmap ) ) {
+
+ return FALSE;
+ }
+
+
+ if( _AllocationAttribute == NULL ) {
+ return TRUE;
+ }
+
+ if( !_IndexAllocationBitmap->Write( &BitmapAttribute, _VolumeBitmap )) {
+ DebugPrint("UNTFS: Could not write index allocation bitmap\n");
+ return FALSE;
+ }
+
+ if( !BitmapAttribute.InsertIntoFile( TargetFrs, _VolumeBitmap )) {
+
+ DebugPrint("UNTFS: Could not insert bitmap attribute\n");
+
+ // Try a second time after making sure the attribute is non-resident.
+ //
+
+ if( !BitmapAttribute.MakeNonresident( _VolumeBitmap ) ||
+ !BitmapAttribute.InsertIntoFile( TargetFrs, _VolumeBitmap )) {
+
+ DebugPrint("UNTFS: Still could not insert bitmap attr.\n");
+ return FALSE;
+ }
+ }
+
+ if( !_AllocationAttribute->InsertIntoFile( TargetFrs, _VolumeBitmap )) {
+
+ DebugPrintf("UNTFS: Could not insert allocation attribute\n");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_INDEX_TREE::IsBadlyOrdered(
+ OUT PBOOLEAN Error,
+ IN BOOLEAN DuplicatesAllowed
+ )
+/*++
+
+Routine Description:
+
+ This method traverses the index tree to determine whether it
+ is badly-ordered. A tree is well-ordered if it entries are
+ in correct lexical order, all leaves appear at the same depth,
+ and the tree has no empty leaf index allocation buffers.
+
+Arguments:
+
+ Error -- Receives TRUE if this method fails because of
+ an error.
+ DuplicatesAllowed -- Supplies a flag which indicates, if TRUE,
+ that this index may have duplicate entries.
+ Otherwise, if duplicate entries exist, the
+ tree is badly ordered.
+
+Return Value:
+
+ TRUE if the tree is found to be badly ordered. (In this case,
+ *Error should be ignored.)
+
+ If this method returns FALSE and *Error is FALSE, then the tree
+ is well-ordered. If *Error is TRUE, this method was unable to
+ determine whether the tree is well-ordered.
+
+--*/
+{
+ BOOLEAN LeafFound, Result, FirstEntry, PreviousWasNode;
+ ULONG LeafDepth, CurrentDepth;
+ PINDEX_ENTRY PreviousEntry;
+ PCINDEX_ENTRY CurrentEntry;
+
+ DebugAssert( Error );
+
+ // Allocate a buffer to hold the previous entry:
+
+ if( (PreviousEntry =
+ (PINDEX_ENTRY)MALLOC( QueryMaximumEntrySize() )) == NULL ) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ ResetIterator();
+
+ FirstEntry = TRUE;
+ PreviousWasNode = FALSE;
+ LeafFound = FALSE;
+ Result = FALSE;
+ *Error = FALSE;
+
+ while( (CurrentEntry = GetNext( &CurrentDepth, Error, FALSE )) != NULL &&
+ !*Error &&
+ !Result ) {
+
+ // Compare the current entry to the previous entry. If duplicates
+ // are not allowed, the currrent entry must be strictly greater
+ // than the previous; otherwise, it must be greater than or equal
+ // to the previous.
+ //
+ if( !(CurrentEntry->Flags & INDEX_ENTRY_END) ) {
+
+ if( FirstEntry ) {
+
+ // This entry is the first in the index; don't compare
+ // it to the previous entry.
+ //
+ FirstEntry = FALSE;
+
+ } else if ( (!DuplicatesAllowed &&
+ CompareNtfsIndexEntries( CurrentEntry,
+ PreviousEntry,
+ _CollationRule,
+ _UpcaseTable ) <= 0 ) ||
+ (DuplicatesAllowed &&
+ CompareNtfsIndexEntries( CurrentEntry,
+ PreviousEntry,
+ _CollationRule,
+ _UpcaseTable ) < 0 ) ) {
+
+ // The tree is badly ordered.
+ //
+ Result = TRUE;
+ break;
+ }
+
+ } else if( !(CurrentEntry->Flags & INDEX_ENTRY_NODE) ) {
+
+ // This is an end leaf entry. If it's the first
+ // entry in the tree and not in the root, then
+ // it's in an empty index allocation buffer, which
+ // means the tree is badly ordered. Similarly, if
+ // the previous entry was a node, then this entry is
+ // in an empty index allocation block, which means
+ // the tree is badly ordered.
+ //
+ if( FirstEntry && CurrentDepth != 0 ) {
+
+ Result = TRUE;
+ break;
+ }
+
+ if( PreviousWasNode ) {
+
+ Result = TRUE;
+ break;
+ }
+ }
+
+ if( !(CurrentEntry->Flags & INDEX_ENTRY_NODE) ) {
+
+ // This is a leaf. See if it's at the same depth as
+ // the other leaves we've seen so far.
+ //
+ if( !LeafFound ) {
+
+ // This is the first leaf. Record its depth.
+ //
+ LeafFound = TRUE;
+ LeafDepth = CurrentDepth;
+
+ } else {
+
+ if( CurrentDepth != LeafDepth ) {
+
+ // The leaves are not all at the same depth,
+ // which means this tree is badly ordered.
+ //
+ Result = TRUE;
+ break;
+ }
+ }
+
+ PreviousWasNode = FALSE;
+
+ } else if( GetDownpointer(CurrentEntry) == INVALID_VCN ) {
+
+ // This entry has an invalid downpointer, so the
+ // index is badly ordered.
+ //
+ Result = TRUE;
+ break;
+
+ } else {
+
+ // Remember that we just saw a node entry.
+ //
+ PreviousWasNode = TRUE;
+ }
+
+ // If the current entry isn't an END entry, copy it
+ // into the previous entry buffer:
+ //
+ if( !(CurrentEntry->Flags & INDEX_ENTRY_END) ) {
+
+ if( CurrentEntry->Length > QueryMaximumEntrySize() ) {
+
+ // This entry is impossibly large, which means that the
+ // index is corrupt.
+ //
+ *Error = TRUE;
+ Result = FALSE;
+
+ } else {
+
+ memcpy( (PVOID) PreviousEntry,
+ (PVOID) CurrentEntry,
+ CurrentEntry->Length );
+ }
+ }
+ }
+
+ FREE( PreviousEntry );
+ return Result;
+}
+
+
+
+VOID
+NTFS_INDEX_TREE::FreeAllocation(
+ )
+/*++
+
+Routine Description:
+
+ This method frees the disk space associated with this index's
+ Allocation Attribute.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+ This method may leave the tree in a corrupt state, since it
+ truncates the allocation attribute to zero without cleaning
+ up downpointers in the root. Use with care.
+
+--*/
+{
+ if( _AllocationAttribute != NULL ) {
+
+ _AllocationAttribute->Resize( 0, _VolumeBitmap );
+ }
+}
+
+
+BOOLEAN
+NTFS_INDEX_TREE::UpdateFileName(
+ IN PCFILE_NAME Name,
+ IN FILE_REFERENCE FileReference
+ )
+/*++
+
+Routine Description:
+
+ This method updates the duplicated information in a file name
+ index entry.
+
+Arguments:
+
+ Name -- Supplies the file name structure with the new
+ duplicated information.
+ FileReference -- Supplies the file reference for the file to
+ which this name belongs. (Note that this is
+ the base FRS for that file, not necessarily the
+ exact FRS that contains the name.)
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This operation is meaningless on an index that is not constructed
+ over the $FILE_NAME attribute.
+
+--*/
+{
+ INTSTACK ParentTrail;
+ PINDEX_ENTRY FoundEntry;
+ PNTFS_INDEX_BUFFER ContainingBuffer;
+ PFILE_NAME TargetName;
+ BOOLEAN Result;
+
+ DebugPtrAssert( Name );
+
+ if( QueryIndexedAttributeType() != $FILE_NAME ||
+ QueryCollationRule() != COLLATION_FILE_NAME ) {
+
+ DebugAbort( "Updating file name in an index that isn't over $FILE_NAME.\n" );
+ return FALSE;
+ }
+
+ // OK, find the entry that corresponds to the input. Note that the
+ // collation rule for File Names ignores everything but the actual
+ // file name portion of the key value.
+
+ if( !FindEntry( NtfsFileNameGetLength( Name ),
+ (PVOID)Name,
+ 0,
+ &FoundEntry,
+ &ContainingBuffer,
+ &ParentTrail ) ) {
+
+ // If FoundEntry is NULL, FindEntry failed because of an error;
+ // otherwise, there is no matching entry in the index, which
+ // means there's nothing to update.
+ //
+
+ DebugPrint( "UpdateFileName--index entry not found.\n" );
+ Result = ( FoundEntry != NULL );
+
+ } else {
+
+ // We've found an entry. As an extra sanity check, make sure
+ // that the file reference for the found entry is the same as
+ // the input file reference.
+
+ if( memcmp( &(FoundEntry->FileReference),
+ &(FileReference),
+ sizeof( FILE_REFERENCE ) ) != 0 ) {
+
+ DebugPrint( "File references don't match in UpdateFileName.\n" );
+ Result = TRUE;
+
+ } else {
+
+ // Copy the duplicated information and update the file-name bits.
+ //
+ TargetName = (PFILE_NAME)(GetIndexEntryValue(FoundEntry));
+ TargetName->Info = Name->Info;
+ TargetName->Flags = Name->Flags;
+
+ if( ContainingBuffer != NULL ) {
+
+ // This entry is in a buffer, so we have to write the
+ // buffer while we've still got it.
+ //
+ Result = ContainingBuffer->Write( _AllocationAttribute );
+
+ } else {
+
+ // This entry is in the root, so we're done.
+ //
+ Result = TRUE;
+ }
+ }
+ }
+
+ DELETE( ContainingBuffer );
+ return Result;
+}
+
+
+BOOLEAN
+NTFS_INDEX_TREE::IsIndexEntryCorrupt(
+ IN PCINDEX_ENTRY IndexEntry,
+ IN ULONG MaximumLength
+ )
+{
+ ULONG len;
+
+ if (sizeof(INDEX_ENTRY) > MaximumLength ||
+ IndexEntry->Length != QuadAlign(IndexEntry->Length) ||
+ IndexEntry->Length > MaximumLength) {
+
+ return TRUE;
+ }
+
+ len = ((IndexEntry->Flags & INDEX_ENTRY_NODE) ? sizeof(VCN) : 0) +
+ ((IndexEntry->Flags & INDEX_ENTRY_END) ? 0 :
+ QuadAlign(IndexEntry->AttributeLength)) +
+ sizeof(INDEX_ENTRY);
+
+ return len > IndexEntry->Length;
+}
+
+
+BOOLEAN
+NTFS_INDEX_TREE::ResetLsns(
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This method sets the LSN for each in-use index allocation
+ block in the index tree to zero.
+
+Arguments:
+
+ Message -- Supplies an outlet for messages.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ NTFS_INDEX_BUFFER CurrentBuffer;
+ ULONG i, num_buffers, cluster_size;
+
+ cluster_size = _ClusterFactor * _Drive->QuerySectorSize();
+
+ if( _AllocationAttribute == NULL ) {
+
+ // This tree has no index allocation buffers--there's
+ // nothing to do.
+ //
+ return TRUE;
+ }
+
+ num_buffers = (_AllocationAttribute->QueryValueLength()/_BufferSize).GetLowPart();
+
+ for( i = 0; i < num_buffers; i++ ) {
+
+ VCN current_vcn;
+
+ // Skip unused buffers.
+ //
+ if( _IndexAllocationBitmap->IsFree( i, 1 ) ) {
+
+ continue;
+ }
+
+ // If we have a positive number for _ClustersPerBuffer, we want to
+ // use that to compute the VCN (this is a backward compatibility mode).
+ // More recently formatted filesystems will have 0 for _ClustersPerBuffer
+ // and the VCN will be the block number (512-byte blocks), regardless of
+ // how many clusters are in each buffer.
+ //
+
+ if (0 == _ClustersPerBuffer) {
+ current_vcn = i * (_BufferSize / 512);
+ } else {
+ current_vcn = i * _ClustersPerBuffer;
+ }
+
+ // Initialize the buffer, read it, set its LSN, and write it.
+ //
+ if( !CurrentBuffer.Initialize( _Drive,
+ current_vcn,
+ cluster_size,
+ _ClustersPerBuffer,
+ _BufferSize,
+ _CollationRule,
+ _UpcaseTable ) ||
+ !CurrentBuffer.Read( _AllocationAttribute ) ||
+ !CurrentBuffer.SetLsn( 0 ) ||
+ !CurrentBuffer.Write( _AllocationAttribute ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_INDEX_TREE::FindHighestLsn(
+ IN OUT PMESSAGE Message,
+ OUT PLSN HighestLsn
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method finds the highest LSN for any index block
+ associated with this index.
+
+Arguments:
+
+ Message -- Supplies an outlet for messages.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ NTFS_INDEX_BUFFER CurrentBuffer;
+ BIG_INT BigZero;
+ ULONG i, cluster_size, num_buffers;
+
+ cluster_size = _ClusterFactor * _Drive->QuerySectorSize();
+
+ BigZero = 0;
+ *HighestLsn = BigZero.GetLargeInteger();
+
+ if( _AllocationAttribute == NULL ) {
+
+ // This tree has no index allocation buffers--there's
+ // nothing to do.
+ //
+ return TRUE;
+ }
+
+ num_buffers = (_AllocationAttribute->QueryValueLength()/_BufferSize).GetLowPart();
+
+ for( i = 0; i < num_buffers; i++ ) {
+
+ VCN current_vcn;
+
+ // Skip unused buffers.
+ //
+ if( _IndexAllocationBitmap->IsFree( i, 1 ) ) {
+
+ continue;
+ }
+
+ if (0 == _ClustersPerBuffer) {
+ current_vcn = i * (_BufferSize / 512);
+ } else {
+ current_vcn = i * _ClustersPerBuffer;
+ }
+
+ // Initialize and read the buffer
+ //
+ if( !CurrentBuffer.Initialize( _Drive,
+ current_vcn,
+ cluster_size,
+ _ClustersPerBuffer,
+ _BufferSize,
+ _CollationRule,
+ _UpcaseTable ) ||
+ !CurrentBuffer.Read( _AllocationAttribute ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( CurrentBuffer.QueryLsn() > *HighestLsn ) {
+
+ *HighestLsn = CurrentBuffer.QueryLsn();
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+NTFS_INDEX_TREE::FindEntry(
+ IN ULONG KeyLength,
+ IN PVOID KeyValue,
+ IN ULONG Ordinal,
+ OUT PINDEX_ENTRY* FoundEntry,
+ OUT PNTFS_INDEX_BUFFER* ContainingBuffer,
+ OUT PINTSTACK ParentTrail
+ )
+/*++
+
+Routine Description:
+
+ This method locates an entry (based on its key value) in
+ the index tree. If no matching entry is found, it locates
+ the first leaf entry which is greater than the search value
+ (i.e. the point at which the search value would be inserted
+ into the tree).
+
+Arguments:
+
+ KeyLength -- supplies the length, in bytes, of the
+ search value
+ KeyValue -- supplies the search value
+ Ordinal -- supplies the (zero-based) ordinal of the
+ matching entry to return. (zero returns
+ the first matching value).
+
+ Note that a value of INDEX_SKIP skips
+ all matching entries.
+
+ FoundEntry -- Receives a pointer to the located entry
+ (NULL indicates error).
+ ContainingBuffer -- Receives a pointer to the index buffer
+ containing the returned entry (NULL if the
+ entry is in the root).
+ ParentTrail -- Receives the parent trail of ContainingBuffer
+ (ie. the VCNs of that buffer's ancestors).
+ If the entry is in the root, this object
+ may be left uninitialized.
+
+Return Value:
+
+ TRUE If a matching entry is found.
+
+ FALSE if no matching entry was found. If no error occurred, then
+ *FoundEntry will point at the place in the tree where the search
+ value would be inserted.
+
+ If the method fails due to error, it returns FALSE and sets
+ *FoundEntry to NULL.
+
+ Note that if FindEntry does not find a matching entry, it will
+ always return a leaf entry.
+
+--*/
+{
+ PINDEX_ENTRY SearchEntry;
+ VCN CurrentBufferVcn;
+ PNTFS_INDEX_BUFFER CurrentBuffer;
+ BOOLEAN Finished = FALSE;
+ BOOLEAN Result = FALSE;
+ USHORT SearchEntryLength;
+
+ // Rig up an index-entry to pass to the index root and buffers:
+
+ SearchEntryLength = QuadAlign( sizeof( INDEX_ENTRY ) + KeyLength );
+
+ if( (SearchEntry = (PINDEX_ENTRY)MALLOC( SearchEntryLength )) == NULL ) {
+
+ // Return the error.
+
+ *FoundEntry = NULL;
+ Result = FALSE;
+ }
+
+ SearchEntry->Length = SearchEntryLength;
+ SearchEntry->AttributeLength = (USHORT)KeyLength;
+
+ memcpy( GetIndexEntryValue( SearchEntry ),
+ KeyValue,
+ KeyLength );
+
+
+ // See if the entry we want is in the index root:
+
+ if( _IndexRoot->FindEntry( SearchEntry,
+ &Ordinal,
+ FoundEntry ) ) {
+
+ // The desired entry is in the root. *FoundEntry has been set
+ // by the Index Root; fill in the other return parameters
+
+ *ContainingBuffer = NULL;
+ Result = TRUE;
+
+ } else if ( *FoundEntry == NULL ) {
+
+ // An error occurred trying to find the entry.
+
+ *ContainingBuffer = NULL;
+ Result = FALSE;
+
+ } else if( !((*FoundEntry)->Flags & INDEX_ENTRY_NODE) ||
+ GetDownpointer( *FoundEntry ) == INVALID_VCN ) {
+
+ // The entry we want isn't in the root, and the root is a leaf,
+ // so it's not in the tree. Return the entry we did find, and
+ // return 'not found' to the client.
+
+ *ContainingBuffer = NULL;
+ Result = FALSE;
+
+ } else {
+
+ // We didn't find the entry we want in the index root, and
+ // the root is not a leaf, so we'll start looking through the
+ // index allocation buffers.
+
+ // First, we have to allocate an index allocation buffer
+ // for our search. If all goes well, we'll return this
+ // buffer to the client. Initialize the parent trail, but
+ // leave it empty (indicating that we're at the root).
+
+ if( !ParentTrail->Initialize() ||
+ (CurrentBuffer = NEW NTFS_INDEX_BUFFER) == NULL ) {
+
+ *FoundEntry = NULL;
+ }
+
+ if (_AllocationAttribute == NULL) {
+
+ *FoundEntry = NULL;
+ }
+
+ while( *FoundEntry != NULL && !Finished ) {
+
+ DebugAssert( ((*FoundEntry)->Flags & INDEX_ENTRY_NODE) &&
+ GetDownpointer( *FoundEntry ) != INVALID_VCN );
+
+ CurrentBufferVcn = GetDownpointer( *FoundEntry );
+
+ if( !CurrentBuffer->Initialize( _Drive,
+ CurrentBufferVcn,
+ _ClusterFactor * _Drive->QuerySectorSize(),
+ _ClustersPerBuffer,
+ _BufferSize,
+ _CollationRule,
+ _UpcaseTable ) ||
+ !CurrentBuffer->Read( _AllocationAttribute ) ) {
+
+ *FoundEntry = NULL;
+
+ } else if( CurrentBuffer->FindEntry( SearchEntry,
+ &Ordinal,
+ FoundEntry ) ) {
+
+ // We found the entry we want.
+
+ Finished = TRUE;
+ Result = TRUE;
+
+ } else if ( *FoundEntry != NULL &&
+ (!((*FoundEntry)->Flags & INDEX_ENTRY_NODE) ||
+ GetDownpointer( *FoundEntry ) == INVALID_VCN) ) {
+
+ // This buffer is a leaf, so the entry we want isn't
+ // to be found. Instead, we'll return this entry, along
+ // with a result of FALSE to indicate 'not found'.
+
+ Finished = TRUE;
+ Result = FALSE;
+
+ } else {
+
+ // We have to recurse down another level in the tree.
+ // Add the current buffer's VCN to the parent trail.
+
+ if( !ParentTrail->Push( CurrentBufferVcn ) ) {
+
+ // Error. Drop out of the loop and into the error
+ // handling.
+
+ *FoundEntry = NULL;
+ }
+ }
+ }
+
+ if( *FoundEntry == NULL ) {
+
+ // We're returning an error, so we have to clean up.
+
+ DELETE( CurrentBuffer );
+ CurrentBuffer = NULL;
+ *ContainingBuffer = NULL;
+ Result = FALSE;
+
+ } else {
+
+ // We're returning an entry--either the one the client
+ // wants or the next leaf. Either way, it's contained
+ // in the current buffer, so we need to return that, too.
+
+ *ContainingBuffer = CurrentBuffer;
+ }
+ }
+
+ FREE( SearchEntry );
+
+ return Result;
+}
+
+BOOLEAN
+NTFS_INDEX_TREE::RemoveEntry(
+ IN PINDEX_ENTRY EntryToRemove,
+ IN PNTFS_INDEX_BUFFER ContainingBuffer,
+ IN PINTSTACK ParentTrail
+ )
+/*++
+
+Routine Description:
+
+ This method removes an entry from the tree.
+
+Arguments:
+
+ EntryToRemove -- Supplies a pointer to the entry to be removed.
+ ContainingBuffer -- Supplies the buffer which contains this entry.
+ NULL if the entry is in the root.
+ ParentTrail -- Supplies the trail of ancestors of
+ ContainingBuffer, back to the root.
+ If ContainingBuffer is NULL, this object
+ may be uninitialized.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ If the removed entry does not have a downpointer, it is sufficient
+ to simply rip it out. If it does, we have to find a replacement
+ for it.
+
+--*/
+{
+ NTFS_INDEX_BUFFER CurrentBuffer;
+ PINDEX_ENTRY ReplacementEntry, Successor;
+ BOOLEAN Result, Error;
+
+
+ BOOLEAN EmptyLeaf = FALSE;
+ VCN EmptyLeafVcn;
+
+ DebugAssert( !(EntryToRemove->Flags & INDEX_ENTRY_END ) );
+
+ if( ContainingBuffer == NULL ) {
+
+ // The entry we wish to delete is in the root.
+
+ if( !(EntryToRemove->Flags & INDEX_ENTRY_NODE) ||
+ GetDownpointer( EntryToRemove ) == INVALID_VCN ) {
+
+ // It's a leaf entry, so we can just yank it.
+ //
+ _IndexRoot->RemoveEntry( EntryToRemove );
+ Result = TRUE;
+
+ } else {
+
+ // Since the entry we want to remove has a downpointer,
+ // we have to find a replacement for it.
+ //
+ // Allocate a buffer for the replacement entry.
+ //
+ if( (ReplacementEntry = (PINDEX_ENTRY)
+ MALLOC( QueryMaximumEntrySize() ))
+ == NULL ) {
+
+ return FALSE;
+ }
+
+ Successor = GetNextEntry( EntryToRemove );
+
+ if( QueryReplacementEntry( Successor,
+ ReplacementEntry,
+ &Error,
+ &EmptyLeaf,
+ &EmptyLeafVcn ) ) {
+
+ // We've got a replacement. It inherits the deleted
+ // entry's downpointer. Then we remove the deleted entry
+ // and insert the replacement.
+
+ // Note that QueryReplacementEntry always returns a
+ // node entry (ie. INDEX_ENTRY_NODE is set in the flags
+ // and the size includes the Downpointer VCN.)
+
+ GetDownpointer( ReplacementEntry ) =
+ GetDownpointer( EntryToRemove );
+
+ _IndexRoot->RemoveEntry( EntryToRemove );
+
+ Result = InsertIntoRoot( ReplacementEntry,
+ EntryToRemove );
+
+ } else if ( !Error ) {
+
+ // There is no replacement for the current entry.
+ // This means that the subtree rooted at its successor
+ // is empty, and can be deleted, which in turn means
+ // that the successor can just inherit the deleted
+ // entry's downpointer.
+
+ FreeChildren( Successor );
+
+ GetDownpointer( Successor ) = GetDownpointer( EntryToRemove );
+
+ _IndexRoot->RemoveEntry( EntryToRemove );
+
+ Result = TRUE;
+
+ } else {
+
+ // an error has occurred.
+ //
+ Result = FALSE;
+ }
+
+ FREE( ReplacementEntry );
+ }
+
+ } else if( !(EntryToRemove->Flags & INDEX_ENTRY_NODE) ||
+ GetDownpointer( EntryToRemove ) == INVALID_VCN ) {
+
+ // The entry we wish to delete is a leaf, so we
+ // can just yank it.
+ //
+ ContainingBuffer->RemoveEntry( EntryToRemove );
+ Result = ContainingBuffer->Write( _AllocationAttribute );
+
+ // Check to see if removing that entry made the leaf
+ // empty.
+ //
+ if( ContainingBuffer->IsLeaf() && ContainingBuffer->IsEmpty() ) {
+
+ EmptyLeaf = TRUE;
+ EmptyLeafVcn = ContainingBuffer->QueryVcn();
+ }
+
+ } else {
+
+ // The entry we wish to delete is in a node buffer, so we
+ // have to find a replacement for it.
+ //
+ // Allocate a buffer for the replacement entry.
+
+ if( (ReplacementEntry = (PINDEX_ENTRY)
+ MALLOC( QueryMaximumEntrySize() ))
+ == NULL ) {
+
+ return FALSE;
+ }
+
+ Successor = GetNextEntry( EntryToRemove );
+
+ if( QueryReplacementEntry( Successor,
+ ReplacementEntry,
+ &Error,
+ &EmptyLeaf,
+ &EmptyLeafVcn ) ) {
+
+ // We've got a replacement. It inherits the deleted
+ // entry's downpointer. Then we remove the deleted entry
+ // and insert the replacement.
+
+ // Note that QueryReplacementEntry always returns a
+ // node entry (ie. INDEX_ENTRY_NODE is set in the flags
+ // and the size includes the Downpointer VCN.
+
+ GetDownpointer( ReplacementEntry ) =
+ GetDownpointer( EntryToRemove );
+
+ ContainingBuffer->RemoveEntry( EntryToRemove );
+
+ // Note that InsertIntoBuffer will write ContainingBuffer.
+ //
+ Result = InsertIntoBuffer( ContainingBuffer,
+ ParentTrail,
+ ReplacementEntry,
+ EntryToRemove );
+
+ } else if ( !Error ) {
+
+ // There is no replacement for the current entry.
+ // This means that the subtree rooted at its successor
+ // is empty, and can be deleted, which in turn means
+ // that the successor can just inherit the deleted
+ // entry's downpointer.
+
+ FreeChildren( Successor );
+
+ GetDownpointer( Successor ) = GetDownpointer( EntryToRemove );
+
+ ContainingBuffer->RemoveEntry( EntryToRemove );
+
+ ContainingBuffer->Write( _AllocationAttribute );
+
+ Result = TRUE;
+
+ } else {
+
+ // an error has occurred.
+
+ Result = FALSE;
+ }
+
+ FREE( ReplacementEntry );
+ }
+
+ // If we have successfully deleted an entry, we must check
+ // to see if we've created an empty leaf allocation buffer.
+ // Note that this will collapse the tree, if appropriate.
+ //
+ if( EmptyLeaf ) {
+
+ FixupEmptyLeaf( EmptyLeafVcn );
+ }
+
+ return Result;
+}
+
+
+
+BOOLEAN
+NTFS_INDEX_TREE::QueryReplacementEntry(
+ IN PINDEX_ENTRY Successor,
+ OUT PINDEX_ENTRY ReplacementEntry,
+ OUT PBOOLEAN Error,
+ OUT PBOOLEAN EmptyLeaf,
+ OUT PVCN EmptyLeafVcn
+ )
+/*++
+
+Routine Description:
+
+ This private method finds a replacement entry for a deleted
+ entry, removes it from its current location in the tree, and
+ copies it into the supplied replacement entry buffer.
+
+Arguments:
+
+ Successor -- supplies the entry following the entry to be
+ replaced.
+ ReplacementEntry -- receives the replacement entry.
+ Error -- receives TRUE if an error occurs.
+ EmptyLeaf -- receives TRUE if this method creates an
+ empty leaf allocation block. Undefined if
+ the method returns FALSE.
+ EmptyLeafVcn -- receives the VCN of the empty leaf if
+ *EmptyLeaf is set to TRUE. Undefined if
+ the method returns FALSE.
+
+Return Value:
+
+ TRUE if a replacement entry was found without error. FALSE if no
+ replacement was found or if an error occurred. (If an error is
+ encountered, *Error is set to TRUE.)
+
+Notes:
+
+ The replacement entry is the first entry in the subtree rooted at
+ Successor. It is copied into the replacement buffer and then
+ removed from its current location.
+
+ This method assumes that Successor is an entry in a node block
+ (which may be the index root), and that the tree is valid and
+ consistent.
+
+ If a replacement entry is returned, it will be a node entry (i.e.
+ its length will be adjusted, if necessary, to include a downpointer).
+
+ The ReplacementEntry buffer must be big enough to hold any index
+ entry from this tree.
+
+--*/
+{
+ PNTFS_INDEX_BUFFER CurrentBuffer;
+ PNTFS_INDEX_BUFFER CandidateBuffer;
+ VCN CurrentVcn;
+ PINDEX_ENTRY CurrentEntry;
+ PINDEX_ENTRY CandidateEntry;
+ BOOLEAN LeafFound = FALSE;
+
+ CandidateBuffer = NULL;
+ CandidateEntry = NULL;
+ *Error = FALSE;
+
+ CurrentVcn = GetDownpointer( Successor );
+
+ while( !*Error && !LeafFound ) {
+
+ if( (CurrentBuffer = NEW NTFS_INDEX_BUFFER) == NULL ||
+ !CurrentBuffer->Initialize( _Drive,
+ CurrentVcn,
+ _ClusterFactor * _Drive->QuerySectorSize(),
+ _ClustersPerBuffer,
+ _BufferSize,
+ _CollationRule,
+ _UpcaseTable ) ||
+ !CurrentBuffer->Read( _AllocationAttribute ) ) {
+
+ // An error has occurred.
+
+ DELETE( CandidateBuffer );
+ DELETE( CurrentBuffer );
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ CurrentEntry = CurrentBuffer->GetFirstEntry();
+
+ if( !(CurrentEntry->Flags & INDEX_ENTRY_NODE) ||
+ GetDownpointer( CurrentEntry ) == INVALID_VCN ) {
+
+ // This buffer is a leaf, so we will terminate the
+ // search on this iteration.
+
+ LeafFound = TRUE;
+
+ } else {
+
+ // This buffer is a node, so we're interested in
+ // the child of its first entry. We need to grab
+ // this information before we throw the current
+ // buffer out.
+
+ CurrentVcn = GetDownpointer( CurrentEntry );
+ }
+
+ if( !(CurrentEntry->Flags & INDEX_ENTRY_END ) ) {
+
+ // This buffer is non-empty, so its first entry
+ // could be used as the replacement entry.
+
+ DELETE( CandidateBuffer );
+ CandidateBuffer = CurrentBuffer;
+ CurrentBuffer = NULL;
+
+ } else {
+
+ // This buffer is empty, so all we want from it is
+ // the downpointer (if any) from its first entry,
+ // and that we've already got.
+
+ DELETE( CurrentBuffer );
+ }
+ }
+
+ DebugAssert( CurrentBuffer == NULL );
+
+ if( CandidateBuffer == NULL ) {
+
+ *Error = FALSE;
+ return FALSE;
+
+ } else {
+
+ CandidateEntry = CandidateBuffer->GetFirstEntry();
+
+ DebugAssert( !(CandidateEntry->Flags & INDEX_ENTRY_END) );
+
+ // Copy the candidate entry into the replacement entry
+ // buffer.
+
+ memcpy( ReplacementEntry,
+ CandidateEntry,
+ CandidateEntry->Length );
+
+ if( !(CandidateEntry->Flags & INDEX_ENTRY_NODE ) ||
+ GetDownpointer( CandidateEntry ) == INVALID_VCN ) {
+
+ // The replacement entry we found doesn't have a downpointer;
+ // increase its size to hold one.
+
+ ReplacementEntry->Length += sizeof( VCN );
+ ReplacementEntry->Flags |= INDEX_ENTRY_NODE;
+
+ } else {
+
+ // The replacement entry we found was a node entry, which
+ // means that all its child buffers are empty. Return them
+ // to the free pool.
+
+ FreeChildren( CandidateEntry );
+ }
+
+ // Expunge the replacement entry from its former location,
+ // and then write that buffer.
+ //
+ CandidateBuffer->RemoveEntry( CandidateEntry );
+ CandidateBuffer->Write( _AllocationAttribute );
+
+ // Check to see if this action created an empty leaf.
+ //
+ if( CandidateBuffer->IsLeaf() && CandidateBuffer->IsEmpty() ) {
+
+ *EmptyLeaf = TRUE;
+ *EmptyLeafVcn = CandidateBuffer->QueryVcn();
+
+ } else {
+
+ *EmptyLeaf = FALSE;
+ }
+
+ // All's well that ends well.
+
+ return TRUE;
+ }
+}
+
+
+BOOLEAN
+NTFS_INDEX_TREE::FixupEmptyLeaf(
+ IN VCN EmptyLeafVcn
+ )
+/*++
+
+Routine Description:
+
+ This method tidies up the tree if an empty leaf allocation
+ buffer has been created.
+
+Arguments:
+
+ EmptyLeafVcn -- supplies the VCN of the empty leaf.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ INTSTACK ParentTrail;
+ NTFS_INDEX_BUFFER CurrentBuffer;
+ VCN CurrentVcn, ChildVcn;
+ BIG_INT AllocationValueLength;
+ BOOLEAN Error, Result, IsRoot;
+ PINDEX_ENTRY CurrentEntry, PreviousEntry, MovedEntry;
+ ULONG i, NumberOfBuffers;
+
+ // Find the buffer in question, and construct its parent trail.
+ // If the buffer isn't in the tree, don't worry about it.
+ //
+ if( !ParentTrail.Initialize() ) {
+
+ return FALSE;
+ }
+
+ if( !FindBuffer( EmptyLeafVcn,
+ NULL,
+ &CurrentBuffer,
+ &ParentTrail,
+ &Error ) ) {
+
+ return !Error;
+ }
+
+ DebugAssert( CurrentBuffer.QueryVcn() == EmptyLeafVcn );
+
+ if( !CurrentBuffer.IsEmpty() || !CurrentBuffer.IsLeaf() ) {
+
+ // This buffer is not an empty leaf, so there's nothing
+ // to do.
+ //
+ return TRUE;
+ }
+
+ // Crawl up the parent trail until we find a non-empty node.
+ //
+ ChildVcn = EmptyLeafVcn;
+
+ while( ParentTrail.QuerySize() != 0 && CurrentBuffer.IsEmpty() ) {
+
+ ChildVcn = CurrentBuffer.QueryVcn();
+ CurrentVcn = ParentTrail.Look();
+ ParentTrail.Pop();
+
+ if( !CurrentBuffer.Initialize( _Drive,
+ CurrentVcn,
+ _ClusterFactor * _Drive->QuerySectorSize(),
+ _ClustersPerBuffer,
+ _BufferSize,
+ _CollationRule,
+ _UpcaseTable ) ||
+ !CurrentBuffer.Read( _AllocationAttribute ) ) {
+
+ return FALSE;
+ }
+ }
+
+ IsRoot = CurrentBuffer.IsEmpty();
+
+ CurrentEntry = IsRoot ? _IndexRoot->GetFirstEntry() :
+ CurrentBuffer.GetFirstEntry();
+ PreviousEntry = NULL;
+
+ if( IsRoot && (CurrentEntry->Flags & INDEX_ENTRY_END) ) {
+
+ // This tree needs to be collapsed down to an
+ // empty root. Recreate the index root as an
+ // empty leaf and free all the bits in the index
+ // allocation bitmap.
+ //
+ _IndexRoot->Recreate( TRUE, 0 );
+
+ _AllocationAttribute->QueryValueLength( &AllocationValueLength );
+
+ NumberOfBuffers = AllocationValueLength.GetLowPart()/_BufferSize;
+
+ for( i = 0; i < NumberOfBuffers; i++ ) {
+
+ if (0 == _ClustersPerBuffer) {
+ FreeIndexBuffer( i * (_BufferSize / 512) );
+ } else {
+ FreeIndexBuffer( i * _ClustersPerBuffer );
+ }
+ }
+
+ return TRUE;
+ }
+
+ while( !(CurrentEntry->Flags & INDEX_ENTRY_END) &&
+ ( !(CurrentEntry->Flags & INDEX_ENTRY_NODE) ||
+ GetDownpointer( CurrentEntry ) != ChildVcn ) ) {
+
+ PreviousEntry = CurrentEntry;
+ CurrentEntry = GetNextEntry( CurrentEntry );
+ }
+
+ if( GetDownpointer( CurrentEntry ) != ChildVcn ) {
+
+ // Didn't find the parent entry, although this
+ // buffer is in the parent trail. Something is
+ // corrupt.
+ //
+ return FALSE;
+ }
+
+ if( CurrentEntry->Flags & INDEX_ENTRY_END ) {
+
+ // Since we can't remove the end entry, we'll remove
+ // its predecessor instead. This means we have to
+ // transfer the predecessor's downpointer to the end
+ // entry. (Note that this index block is not empty,
+ // so the predecessor must exist.)
+ //
+ if( PreviousEntry == NULL ) {
+
+ return FALSE;
+ }
+
+ if( PreviousEntry->Flags & INDEX_ENTRY_NODE ) {
+
+ GetDownpointer( CurrentEntry ) = GetDownpointer( PreviousEntry );
+
+ } else {
+
+ GetDownpointer( CurrentEntry ) = INVALID_VCN;
+ }
+
+ CurrentEntry = PreviousEntry;
+ }
+
+ // Copy the current entry into a temporary buffer
+ // (stripping off its down-pointer, if any) and
+ // delete it from the current buffer or root, as
+ // appropriate.
+ //
+ MovedEntry = (PINDEX_ENTRY)MALLOC( CurrentEntry->Length );
+
+ if( MovedEntry == NULL ) {
+
+ return FALSE;
+ }
+
+ memcpy( MovedEntry,
+ CurrentEntry,
+ CurrentEntry->Length );
+
+ if( MovedEntry->Flags & INDEX_ENTRY_NODE ) {
+
+ MovedEntry->Flags &= ~INDEX_ENTRY_NODE;
+ MovedEntry->Length -= sizeof( VCN );
+ }
+
+ if( IsRoot ) {
+
+ _IndexRoot->RemoveEntry( CurrentEntry );
+
+ } else {
+
+ CurrentBuffer.RemoveEntry( CurrentEntry );
+ CurrentBuffer.Write( _AllocationAttribute );
+ }
+
+ // Re-insert the entry into the tree.
+ //
+ Result = InsertEntry( MovedEntry, FALSE );
+
+ FREE( MovedEntry );
+
+ return Result;
+}
+
+
+BOOLEAN
+NTFS_INDEX_TREE::FindBuffer(
+ IN VCN BufferVcn,
+ IN PNTFS_INDEX_BUFFER ParentBuffer,
+ OUT PNTFS_INDEX_BUFFER FoundBuffer,
+ IN OUT PINTSTACK ParentTrail,
+ OUT PBOOLEAN Error
+ )
+/*++
+
+Routine Description:
+
+ This method locates a buffer in the tree.
+
+Arguments:
+
+ BufferVcn -- supplies the VCN of the desired buffer.
+ ParentBuffer -- supplies the buffer at which to begin the search.
+ If this parameter is NULL, the search starts
+ at the root.
+ FoundBuffer -- receives the buffer.
+ ParentTrail -- supplies the parent trail to ParentBuffer
+ (not including ParentBuffer itself). Receives
+ the trail to the found buffer. If the buffer
+ is not found, this object is restored to its
+ original state.
+ Error -- receives TRUE if the method fails because
+ of an error. Undefined if the method succeeds.
+
+Return Value:
+
+ TRUE upon successful completion. FoundBuffer is initialized to
+ the desired buffer and read, and ParentTrail contains the trail
+ to this buffer.
+
+--*/
+{
+ NTFS_INDEX_BUFFER ChildBuffer;
+ PINDEX_ENTRY CurrentEntry;
+ BOOLEAN IsRoot;
+
+ IsRoot = ( ParentBuffer == NULL );
+
+ // Spin through the entries in this block to see if one of
+ // them is the parent of the buffer we want.
+ //
+ CurrentEntry = IsRoot ? _IndexRoot->GetFirstEntry() :
+ ParentBuffer->GetFirstEntry();
+
+ while( ( !(CurrentEntry->Flags & INDEX_ENTRY_NODE) ||
+ GetDownpointer( CurrentEntry ) != BufferVcn ) &&
+ !(CurrentEntry->Flags & INDEX_ENTRY_END) ) {
+
+ CurrentEntry = GetNextEntry( CurrentEntry );
+ }
+
+ if( (CurrentEntry->Flags & INDEX_ENTRY_NODE) &&
+ GetDownpointer( CurrentEntry ) == BufferVcn ) {
+
+ // We've found the one we want. Add the current buffer (if any)
+ // to the parent trail, initialize and read the child buffer,
+ // and return.
+ //
+ if( !IsRoot && !ParentTrail->Push( ParentBuffer->QueryVcn() ) ) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ if( !FoundBuffer->Initialize( _Drive,
+ GetDownpointer( CurrentEntry ),
+ _ClusterFactor * _Drive->QuerySectorSize(),
+ _ClustersPerBuffer,
+ _BufferSize,
+ _CollationRule,
+ _UpcaseTable ) ||
+ !FoundBuffer->Read( _AllocationAttribute ) ) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ DebugAssert( BufferVcn == FoundBuffer->QueryVcn() );
+ return TRUE;
+ }
+
+ // This block is not the immediate parent of our desired
+ // buffer. Recurse into its children.
+ //
+ if( !IsRoot && !ParentTrail->Push( ParentBuffer->QueryVcn() ) ) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ CurrentEntry = IsRoot ? _IndexRoot->GetFirstEntry() :
+ ParentBuffer->GetFirstEntry();
+
+ while( TRUE ) {
+
+ if( CurrentEntry->Flags & INDEX_ENTRY_NODE ) {
+
+ // Initialize and read the child buffer and
+ // recurse into it.
+ //
+ if( !ChildBuffer.Initialize(_Drive,
+ GetDownpointer( CurrentEntry ),
+ _ClusterFactor * _Drive->QuerySectorSize(),
+ _ClustersPerBuffer,
+ _BufferSize,
+ _CollationRule,
+ _UpcaseTable ) ||
+ !ChildBuffer.Read( _AllocationAttribute ) ) {
+
+ *Error = TRUE;
+ return FALSE;
+ }
+
+ if( FindBuffer( BufferVcn,
+ &ChildBuffer,
+ FoundBuffer,
+ ParentTrail,
+ Error ) ) {
+
+ // Found it in this subtree.
+ //
+ return TRUE;
+
+ } else if ( *Error ) {
+
+ return FALSE;
+ }
+ }
+
+ if( CurrentEntry->Flags & INDEX_ENTRY_END ) {
+
+ break;
+ }
+
+ CurrentEntry = GetNextEntry( CurrentEntry );
+ }
+
+ // This block is not an ancestor of the desired buffer.
+ // Remove it from the parent trail (if it's a buffer ) and
+ // report its failure.
+ //
+ if( !IsRoot ) {
+
+ DebugAssert( ParentBuffer->QueryVcn() == ParentTrail->Look() );
+ ParentTrail->Pop();
+ }
+
+ return FALSE;
+}
+
+
+BOOLEAN
+NTFS_INDEX_TREE::InsertIntoRoot(
+ PCINDEX_ENTRY NewEntry,
+ PINDEX_ENTRY InsertionPoint
+ )
+/*++
+
+Routine Description:
+
+ This method attempts to insert an entry into the Index Root
+ attribute. If necessary, it will twiddle the index b-tree.
+
+Arguments:
+
+ NewEntry -- supplies the new index entry
+ InsertionPoint -- supplies a pointer to the point in the root
+ where the entry should be inserted, if known.
+ This must be a pointer that was returned by a
+ call to _IndexRoot->FindEntry (with no intervening
+ inserts or deletes). This parameter may be NULL.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ NTFS_INDEX_BUFFER NewBuffer;
+ INTSTACK ParentTrail;
+ VCN NewBufferVcn;
+ ULONG BytesToMove;
+ PINDEX_ENTRY CurrentEntry;
+
+ // Try the easy case--NTFS_INDEX_ROOT::InsertEntry will succeed
+ // if there's room in the root for the new entry.
+
+ if( _IndexRoot->InsertEntry( NewEntry, InsertionPoint ) ) {
+
+ return TRUE;
+ }
+
+ // We didn't get away with the easy case. Instead, we have to
+ // push the entries that are currently in the index root down
+ // into an index allocation buffer. Here's the plan:
+ //
+ // If we don't have an allocation attribute, create one.
+ // Allocate a new index buffer.
+ // Create it as an empty buffer. If the root is currently
+ // a leaf, this new buffer becomes a leaf; if not, not.
+ // Move all the index entries that are in the root to the
+ // new buffer
+ // Recreate the root as an empty node, and set the downpointer
+ // of its END entry to point at the new buffer.
+
+ if( _AllocationAttribute == NULL &&
+ !CreateAllocationAttribute() ) {
+
+ // Can't create an allocation attribute.
+ return FALSE;
+ }
+
+
+ // Allocate and initialize the new buffer. Postpone creating it
+ // until we know what to give it as an end-entry downpointer
+
+ if( !AllocateIndexBuffer( &NewBufferVcn ) ) {
+
+ return FALSE;
+ }
+
+ if( !NewBuffer.Initialize( _Drive,
+ NewBufferVcn,
+ _ClusterFactor * _Drive->QuerySectorSize(),
+ _ClustersPerBuffer,
+ _BufferSize,
+ _CollationRule,
+ _UpcaseTable ) ) {
+
+ FreeIndexBuffer( NewBufferVcn );
+ }
+
+
+ // Now copy all the non-end entries from the index root to
+ // the new buffer.
+
+ BytesToMove = 0;
+
+ CurrentEntry = _IndexRoot->GetFirstEntry();
+
+ while( !(CurrentEntry->Flags & INDEX_ENTRY_END) ) {
+
+ BytesToMove += CurrentEntry->Length;
+ CurrentEntry = GetNextEntry( CurrentEntry );
+ }
+
+ // OK, now we can create the new buffer and copy the entries into
+ // it.
+
+ if( CurrentEntry->Flags & INDEX_ENTRY_NODE &&
+ GetDownpointer( CurrentEntry ) != INVALID_VCN ) {
+
+ // Give the new buffer's end entry the downpointer from the
+ // root's end entry.
+
+ NewBuffer.Create( FALSE, GetDownpointer( CurrentEntry ) );
+
+ } else {
+
+ // The new buffer is a leaf.
+
+ NewBuffer.Create( TRUE, 0 );
+ }
+
+ NewBuffer.InsertClump( BytesToMove,
+ _IndexRoot->GetFirstEntry() );
+
+ NewBuffer.Write( _AllocationAttribute );
+
+
+ // Recreate the index root as an empty node. This will wipe out the
+ // old end entry, which is OK. (If it had a downpointer, we passed
+ // that value to the new buffer's end entry; if not, then it didn't
+ // have any interesting information.)
+
+ _IndexRoot->Recreate( FALSE, NewBufferVcn );
+
+ // Set up an empty stack for the parent trail (since the new
+ // buffer's parent is the root) and insert the new entry into
+ // the new leaf buffer.
+
+ return( ParentTrail.Initialize() &&
+ InsertIntoBuffer( &NewBuffer, &ParentTrail, NewEntry ) );
+}
+
+
+BOOLEAN
+NTFS_INDEX_TREE::InsertIntoBuffer(
+ IN OUT PNTFS_INDEX_BUFFER TargetBuffer,
+ IN OUT PINTSTACK ParentTrail,
+ IN PCINDEX_ENTRY NewEntry,
+ IN PINDEX_ENTRY InsertionPoint
+ )
+/*++
+
+Routine Description:
+
+ This method attempts to insert an entry into an Index
+ Allocation Buffer. If necessary, it will split the buffer.
+
+Arguments:
+
+ TargetBuffer -- supplies the buffer that will receive the
+ new entry.
+ ParentTrail -- supplies the parent trail (ie. stack of VCNs
+ of all buffers between here and root) of the
+ target buffer. If this stack is empty, then
+ the parent of the buffer is the root.
+ NewEntry -- supplies the new index entry
+ InsertionPoint -- supplies a pointer to the point in the root
+ where the entry should be inserted, if known.
+ This must be a pointer that was returned by a
+ call to TargetBuffer->FindEntry (with no
+ intervening inserts or deletes). This parameter
+ may be NULL.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This method may consume ParentTrail. The client should not rely
+ on the state of ParentTrail after this method returns.
+
+--*/
+{
+ PINDEX_ENTRY PromotionBuffer;
+ PINDEX_ENTRY SplitPoint;
+ NTFS_INDEX_BUFFER NewBuffer, ParentBuffer;
+ VCN NewBufferVcn, ParentVcn;
+ ULONG BytesToCopy, BytesToRemove;
+ BOOLEAN Result;
+ int CompareResult;
+
+ // Try the easy way first--NTFS_INDEX_BUFFER will succeed if
+ // there's enough room in the buffer to accept this entry.
+
+ if( TargetBuffer->InsertEntry( NewEntry, InsertionPoint ) ) {
+
+ return( TargetBuffer->Write( _AllocationAttribute ) );
+ }
+
+ // We didn't get away with the easy case; instead, we have to
+ // split this index buffer.
+
+ // Allocate a new index allocation buffer.
+
+ if( !AllocateIndexBuffer( &NewBufferVcn ) ) {
+
+ return FALSE;
+ }
+
+ if( !NewBuffer.Initialize( _Drive,
+ NewBufferVcn,
+ _ClusterFactor * _Drive->QuerySectorSize(),
+ _ClustersPerBuffer,
+ _BufferSize,
+ _CollationRule,
+ _UpcaseTable ) ) {
+
+ FreeIndexBuffer( NewBufferVcn );
+ return FALSE;
+ }
+
+ // Find the split point in the buffer we want to split. This
+ // entry will be promoted into the parent; the entries after it
+ // stay in this buffer, while the entries before it go into the
+ // new buffer. The new buffer will become the child of the promoted
+ // entry.
+
+ SplitPoint = TargetBuffer->FindSplitPoint();
+
+ PromotionBuffer = (PINDEX_ENTRY)MALLOC( TargetBuffer->QuerySize() );
+
+ if( PromotionBuffer == NULL ) {
+
+ FreeIndexBuffer( NewBufferVcn );
+ return FALSE;
+ }
+
+ memcpy( PromotionBuffer,
+ SplitPoint,
+ SplitPoint->Length );
+
+ if( TargetBuffer->IsLeaf() ) {
+
+ PromotionBuffer->Flags |= INDEX_ENTRY_NODE;
+ PromotionBuffer->Length += sizeof(VCN);
+ NewBuffer.Create( TRUE, 0 );
+
+ } else {
+
+ NewBuffer.Create( FALSE, GetDownpointer(PromotionBuffer) );
+ }
+
+ GetDownpointer( PromotionBuffer ) = NewBufferVcn;
+
+
+ // OK, copy all the entries before the split point into the
+ // new buffer.
+
+ BytesToCopy = (PBYTE)SplitPoint - (PBYTE)(TargetBuffer->GetFirstEntry());
+
+ NewBuffer.InsertClump( BytesToCopy, TargetBuffer->GetFirstEntry() );
+
+
+ // Now shift the remaining entries down, and adjust the target
+ // buffer's FirstFreeByte field by the number of bytes we moved
+ // to the new buffer.
+
+ BytesToRemove = BytesToCopy + SplitPoint->Length;
+
+ TargetBuffer->RemoveClump( BytesToRemove );
+
+
+ // Now we decide which buffer gets the new entry, and insert it.
+ // If it's less than the promoted entry, it goes in the new buffer;
+ // otherwise, it goes in the original buffer.
+
+ CompareResult = CompareNtfsIndexEntries( NewEntry,
+ PromotionBuffer,
+ _CollationRule,
+ _UpcaseTable );
+
+ if( CompareResult < 0 ) {
+
+ NewBuffer.InsertEntry( NewEntry );
+
+ } else {
+
+ TargetBuffer->InsertEntry( NewEntry );
+ }
+
+ TargetBuffer->Write( _AllocationAttribute );
+ NewBuffer.Write( _AllocationAttribute );
+
+ // OK, we've finished splitting everybody, so we are ready to
+ // insert the promoted entry into the parent.
+
+ if( ParentTrail->QuerySize() == 0 ) {
+
+ // The parent of the target buffer is the root.
+
+ Result = InsertIntoRoot( PromotionBuffer );
+
+ } else {
+
+ // The target buffer's parent is another buffer, and its
+ // VCN is on top of the ParentTrail stack. Get that VCN,
+ // and then pop the stack so we can pass it to the parent
+ // buffer. (Popping it makes it the parent trail of the
+ // parent buffer.)
+
+ ParentVcn = ParentTrail->Look();
+ ParentTrail->Pop();
+
+ Result = ( ParentBuffer.Initialize( _Drive,
+ ParentVcn,
+ _ClusterFactor * _Drive->QuerySectorSize(),
+ _ClustersPerBuffer,
+ _BufferSize,
+ _CollationRule,
+ _UpcaseTable ) &&
+ ParentBuffer.Read( _AllocationAttribute ) &&
+ InsertIntoBuffer( &ParentBuffer,
+ ParentTrail,
+ PromotionBuffer ) );
+ }
+
+ FREE( PromotionBuffer );
+ return Result;
+}
+
+
+
+
+BOOLEAN
+NTFS_INDEX_TREE::AllocateIndexBuffer(
+ OUT PVCN NewBufferVcn
+ )
+/*++
+
+Routine Description:
+
+ This method allocates an index allocation buffer from the index
+ allocation attribute. It first checks the bitmap, to see if any
+ are free; if there are none free in the bitmap, it adds a new
+ index buffer to the end of the allocation attribute.
+
+Arguments:
+
+ NewBuffer -- receives the VCN of the new buffer.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ BIG_INT ValueLength;
+ VCN NewBufferNumber;
+ ULONG NumberOfBuffers;
+
+
+ DebugPtrAssert( _AllocationAttribute != NULL &&
+ _IndexAllocationBitmap != NULL );
+
+ _AllocationAttribute->QueryValueLength( &ValueLength );
+
+ DebugAssert( ValueLength % _BufferSize == 0 );
+
+ NumberOfBuffers = ValueLength.GetLowPart()/_BufferSize;
+
+ // First, check the bitmap. Allocate as close to the beginning
+ // as possible (hence use 0 for the NearHere parameter).
+
+ if( _IndexAllocationBitmap->AllocateClusters( 0,
+ 1,
+ &NewBufferNumber ) ) {
+
+ // Found a free one in the bitmap--return it.
+
+ DebugPrint( "Buffer allocated from index allocation bitmap.\n" );
+
+ if (0 == _ClustersPerBuffer) {
+ *NewBufferVcn = NewBufferNumber * (_BufferSize / 512) ;
+ } else {
+ *NewBufferVcn = NewBufferNumber * _ClustersPerBuffer;
+ }
+ return TRUE;
+ }
+
+
+ // There are no free buffers in the index allocation attribute,
+ // so I have to add one.
+
+ NewBufferNumber = NumberOfBuffers;
+ NumberOfBuffers += 1;
+
+ // Grow the allocation attribute by one buffer:
+
+ if( !_AllocationAttribute->Resize( ValueLength + _BufferSize, _VolumeBitmap ) ) {
+
+ return FALSE;
+ }
+
+
+ // Grow the index allocation bitmap (if necessary) to cover the
+ // current size of the index allocation attributes.
+
+ if( !_IndexAllocationBitmap->Resize( NumberOfBuffers ) ) {
+
+ // Couldn't resize the bitmap--truncate the allocation attribute
+ // back to its original size and return failure.
+
+ _AllocationAttribute->Resize( ValueLength, _VolumeBitmap );
+ return FALSE;
+ }
+
+ // Mark the new buffer as allocated and return it.
+
+ _IndexAllocationBitmap->SetAllocated( NewBufferNumber, 1 );
+
+ if (0 == _ClustersPerBuffer) {
+
+ // The buffers are indexed by their block offset, where each block
+ // in the allocation is 512 bytes.
+ //
+
+ *NewBufferVcn = NewBufferNumber * (_BufferSize / NTFS_INDEX_BLOCK_SIZE);
+
+ } else {
+ *NewBufferVcn = NewBufferNumber * _ClustersPerBuffer;
+ }
+
+ return TRUE;
+}
+
+
+
+VOID
+NTFS_INDEX_TREE::FreeIndexBuffer(
+ IN VCN BufferVcn
+ )
+/*++
+
+Routine Description:
+
+ This method adds a buffer, identified by VCN, to the free
+ buffer list.
+
+Arguments:
+
+ BufferVcn -- supplies the VCN of the buffer to free.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if (0 == _ClustersPerBuffer) {
+ _IndexAllocationBitmap->SetFree( BufferVcn, _BufferSize/512 );
+ } else {
+ _IndexAllocationBitmap->SetFree( BufferVcn/_ClustersPerBuffer, 1 );
+ }
+}
+
+
+
+VOID
+NTFS_INDEX_TREE::FreeChildren(
+ IN PINDEX_ENTRY IndexEntry
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+ IndexEntry -- supplies the entry whose children are to be marked as
+ free.
+
+Return Value:
+
+ None.
+
+Notes:
+
+ This method assumes that the tree is consistent.
+
+ IndexEntry must be a node entry.
+
+--*/
+{
+ VCN CurrentVcn;
+ NTFS_INDEX_BUFFER ChildBuffer;
+ PINDEX_ENTRY CurrentEntry;
+
+
+ CurrentVcn = GetDownpointer( IndexEntry );
+
+ if( !ChildBuffer.Initialize( _Drive,
+ CurrentVcn,
+ _ClusterFactor * _Drive->QuerySectorSize(),
+ _ClustersPerBuffer,
+ _BufferSize,
+ _CollationRule,
+ _UpcaseTable ) ||
+ !ChildBuffer.Read( _AllocationAttribute ) ) {
+
+ return;
+ }
+
+ // First, recurse into the children, if any.
+
+ if( !ChildBuffer.IsLeaf() ) {
+
+ CurrentEntry = ChildBuffer.GetFirstEntry();
+
+ while( TRUE ) {
+
+ FreeChildren( CurrentEntry );
+
+ if( CurrentEntry->Flags & INDEX_ENTRY_END ) {
+
+ break;
+ }
+
+ CurrentEntry = GetNextEntry( CurrentEntry );
+ }
+ }
+
+ // We've gotten rid of the children; add this buffer to the
+ // free list.
+
+ FreeIndexBuffer( CurrentVcn );
+
+ return;
+}
+
+
+
+ULONG
+NTFS_INDEX_TREE::QueryMaximumEntrySize(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method returns the maximum size buffer needed to hold an
+ index entry from this index.
+
+Arguments
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+ The maximum entry size must be less than the buffer size for
+ the allocation buffers in the tree (since an entry must fit
+ into a buffer), so we'll return the index allocation buffer size.
+
+--*/
+{
+ return( _BufferSize );
+}
+
+
+
+BOOLEAN
+NTFS_INDEX_TREE::CreateAllocationAttribute(
+ )
+/*++
+
+Routine Description:
+
+ This method creates an allocation attribute. This attribute is
+ an empty, nonresident attribute. This method also creates an
+ index allocation bitmap associated with this index allocation
+ attribute.
+
+Arguments:
+
+ None.
+
+Return value:
+
+ TRUE upon successful completion. Note that if this method succeeds,
+ the private member data _AllocationAttribute is set to point at the
+ newly-created attribute and _IndexAllocationBitmap is set to point
+ at the newly-created bitmap.
+
+--*/
+{
+ PNTFS_ATTRIBUTE NewAttribute;
+ PNTFS_BITMAP NewBitmap;
+ NTFS_EXTENT_LIST Extents;
+
+ DebugAssert(0 != _ClusterFactor);
+
+
+ // Create an empty extent list.
+
+ if( !Extents.Initialize( (ULONG)0, (ULONG)0 ) ) {
+
+ return FALSE;
+ }
+
+
+ // Construct an index allocation attribute and initialize
+ // it with this extent list.
+
+ if( (NewAttribute = NEW NTFS_ATTRIBUTE) == NULL ||
+ !NewAttribute->Initialize( _Drive,
+ _ClusterFactor,
+ &Extents,
+ 0,
+ 0,
+ $INDEX_ALLOCATION,
+ _Name ) ) {
+
+ DebugPrint( "CreateAllocationAttribute--Cannot create index allocation attribute.\n" );
+
+ DELETE( NewAttribute );
+ return FALSE;
+ }
+
+ // Create a new bitmap. Initialize it to cover zero allocation units,
+ // and indicate that it is growable.
+
+ if( (NewBitmap = NEW NTFS_BITMAP) == NULL ||
+ !NewBitmap->Initialize( 0, TRUE ) ) {
+
+ DebugPrint( "CreateAllocationAttribute--Cannot create index allocation bitmap.\n" );
+
+ DELETE( NewAttribute );
+ DELETE( NewBitmap );
+ return FALSE;
+ }
+
+ _AllocationAttribute = NewAttribute;
+ _IndexAllocationBitmap = NewBitmap;
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+NTFS_INDEX_TREE::InvalidateIterator(
+ )
+/*++
+
+Routine Description:
+
+ This method sets the tree's associated iterator into the invalid
+ state. This means that instead of caching a pointer to the current
+ entry and the buffer that contains it, the iterator caches the
+ information necessary to locate the current entry.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ // If the iterator is already reset, invalid, deleted, or corrupt,
+ // then this method is a no-op. In particular, the state of the
+ // iterator is unchanged.
+
+ if( _IteratorState == INDEX_ITERATOR_RESET ||
+ _IteratorState == INDEX_ITERATOR_INVALID ||
+ _IteratorState == INDEX_ITERATOR_DELETED ||
+ _IteratorState == INDEX_ITERATOR_CORRUPT ) {
+
+ return TRUE;
+ }
+
+ DebugAssert( _IteratorState == INDEX_ITERATOR_CURRENT );
+
+ // Clean up the current entry and current buffer pointers.
+ //
+ _CurrentEntry = NULL;
+ DELETE( _CurrentBuffer );
+
+ _IteratorState = INDEX_ITERATOR_INVALID;
+
+ return TRUE;
+}
+
+
+UNTFS_EXPORT
+VOID
+NTFS_INDEX_TREE::ResetIterator(
+ )
+/*++
+
+Routine Description:
+
+ This method sets the iterator into the RESET state, so that the
+ next call to GetNext will return the first entry in the index.
+
+Arguments:
+
+ None.
+
+Return value:
+
+ None.
+
+--*/
+{
+ // Clean up the current buffer and current entry pointers and
+ // set the state appropriately.
+
+ _CurrentEntry = NULL;
+ DELETE( _CurrentBuffer );
+
+ _IteratorState = INDEX_ITERATOR_RESET;
+
+}
+
+
+BOOLEAN
+NTFS_INDEX_TREE::GetNextLeafEntry(
+ )
+/*++
+
+Routine Description:
+
+ This method is a helper function for GetNext. It advances
+ _CurrentEntry to the next leaf entry, adjusting the other
+ private data as appropriate.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This method should only be called if _CurrentEntry points at
+ a valid node entry.
+
+--*/
+{
+ DebugPtrAssert( _CurrentEntry );
+ DebugAssert( _CurrentEntry->Flags & INDEX_ENTRY_NODE );
+ DebugAssert( _IsCurrentEntryInRoot || _CurrentBuffer != NULL );
+
+
+ while( _CurrentEntry->Flags & INDEX_ENTRY_NODE &&
+ GetDownpointer( _CurrentEntry ) != INVALID_VCN ) {
+
+ DebugPtrAssert( _AllocationAttribute );
+
+ if( _CurrentBuffer == NULL &&
+ (_CurrentBuffer = NEW NTFS_INDEX_BUFFER) == NULL ) {
+
+ DebugAbort( "Can't construct index allocation buffer object.\n" );
+ _CurrentEntry = NULL;
+ _IteratorState = INDEX_ITERATOR_CORRUPT;
+ return FALSE;
+ }
+
+ // If the current entry is in a buffer, record that buffer in
+ // the trail before recursing into the child.
+
+ if( !_IsCurrentEntryInRoot &&
+ !_CurrentEntryTrail.Push( _CurrentBuffer->QueryVcn() ) ) {
+
+ DebugAbort( "Parent Trail stack failure.\n" );
+ _CurrentEntry = NULL;
+ _IteratorState = INDEX_ITERATOR_CORRUPT;
+ return FALSE;
+ }
+
+ // Initialize and read the child and take its first entry
+ // for the current entry.
+
+ if( !_CurrentBuffer->Initialize( _Drive,
+ GetDownpointer( _CurrentEntry ),
+ _ClusterFactor * _Drive->QuerySectorSize(),
+ _ClustersPerBuffer,
+ _BufferSize,
+ _CollationRule,
+ _UpcaseTable )) {
+
+ DebugPrint("Can't init alloc buffer\n");
+ _CurrentEntry = NULL;
+ _IteratorState = INDEX_ITERATOR_CORRUPT;
+ return FALSE;
+ }
+
+ if (!_CurrentBuffer->Read( _AllocationAttribute ) ) {
+
+ DebugPrint( "Can't read allocation buffer.\n" );
+ _CurrentEntry = NULL;
+ _IteratorState = INDEX_ITERATOR_CORRUPT;
+ return FALSE;
+ }
+
+ _IsCurrentEntryInRoot = FALSE;
+ _CurrentEntry = _CurrentBuffer->GetFirstEntry();
+ }
+
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_INDEX_TREE::GetNextParent(
+ )
+/*++
+
+Routine Description:
+
+ This method is a helper function for GetNextUnfiltered. It
+ backtracks up the current entry's parent trail one level.
+
+Arguments
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion. Private data for the iterator
+ are adjusted appropriately.
+
+Notes:
+
+ This method should only be called if _CurrentEntry is valid.
+
+--*/
+{
+ VCN CurrentVcn, ChildVcn;
+
+ DebugPtrAssert( _CurrentEntry );
+ DebugAssert( _IsCurrentEntryInRoot || _CurrentBuffer != NULL );
+
+ if( !_IsCurrentEntryInRoot ) {
+
+ DebugPtrAssert( _CurrentBuffer );
+ DebugPtrAssert( _AllocationAttribute );
+
+ ChildVcn = _CurrentBuffer->QueryVcn();
+
+ if( _CurrentEntryTrail.QuerySize() == 0 ) {
+
+ // The parent of the current buffer is the root.
+
+ _CurrentEntry = _IndexRoot->GetFirstEntry();
+ _IsCurrentEntryInRoot = TRUE;
+
+ } else {
+
+ // Get the VCN of the current buffer's parent from the
+ // trail, and then pop the trail to reflect the fact
+ // that we're going up a level in the tree.
+
+ CurrentVcn = _CurrentEntryTrail.Look();
+ _CurrentEntryTrail.Pop();
+
+ if( !_CurrentBuffer->Initialize( _Drive,
+ CurrentVcn,
+ _ClusterFactor * _Drive->QuerySectorSize(),
+ _ClustersPerBuffer,
+ _BufferSize,
+ _CollationRule,
+ _UpcaseTable ) ||
+ !_CurrentBuffer->Read( _AllocationAttribute ) ) {
+
+ DebugAbort( "Can't find read/initialize buffer.\n" );
+ _CurrentEntry = NULL;
+ _IteratorState = INDEX_ITERATOR_CORRUPT;
+ return FALSE;
+ }
+
+ _CurrentEntry = _CurrentBuffer->GetFirstEntry();
+ _IsCurrentEntryInRoot = FALSE;
+ }
+
+ // Spin through the entries in this block (whether the root
+ // or a buffer) until we find the entry which is the parent
+ // of our child, or run out of entries, or both.
+
+ while( !(_CurrentEntry->Flags & INDEX_ENTRY_END) &&
+ ( !(_CurrentEntry->Flags & INDEX_ENTRY_NODE) ||
+ !(GetDownpointer( _CurrentEntry ) == ChildVcn) ) ) {
+
+ _CurrentEntry = GetNextEntry( _CurrentEntry );
+ }
+
+ if( !(_CurrentEntry->Flags & INDEX_ENTRY_NODE) ||
+ !(GetDownpointer( _CurrentEntry ) == ChildVcn) ) {
+
+ // Didn't find the parent.
+ DebugAbort( "Can't find read/initialize buffer.\n" );
+ _CurrentEntry = NULL;
+ _IteratorState = INDEX_ITERATOR_CORRUPT;
+ return FALSE;
+ }
+
+ } else {
+
+ // Trying to get the parent when we're already in teh
+ // root isn't very meaningful.
+ //
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+UNTFS_EXPORT
+PCINDEX_ENTRY
+NTFS_INDEX_TREE::GetNext(
+ OUT PULONG Depth,
+ OUT PBOOLEAN Error,
+ IN BOOLEAN FilterEndEntries
+ )
+/*++
+
+Routine Description:
+
+ This method bumps the iterator forward and gets the next entry.
+
+Arguments:
+
+ Depth -- Receives the depth in the tree of the
+ returned entry; 0 indicates the root.
+ Error -- Receives TRUE if this method fails because
+ of error.
+ FilterEndEntries -- Supplies a flag which indicates whether
+ entries with the INDEX_ENTRY_END flag
+ should be filtered. If this parameter is
+ TRUE, this method will not return such
+ entries to the client.
+
+Return Value:
+
+ Returns a pointer to the next entry, or NULL if there are no more
+ or an error occurs.
+
+ If this method returns a non-NULL pointer, the value of *Error should
+ be ignored.
+
+--*/
+{
+ PCINDEX_ENTRY Result;
+
+ Result = GetNextUnfiltered( Depth, Error );
+
+ if( FilterEndEntries ) {
+
+ // The client doesn't want to see END entries; keep
+ // trying until we find a non-end entry or run out.
+ //
+ while( Result != NULL && Result->Flags & INDEX_ENTRY_END ) {
+
+ Result = GetNextUnfiltered( Depth, Error );
+ }
+ }
+
+ return Result;
+
+}
+
+
+PCINDEX_ENTRY
+NTFS_INDEX_TREE::GetNextUnfiltered(
+ OUT PULONG Depth,
+ OUT PBOOLEAN Error
+ )
+/*++
+
+Routine Description:
+
+ This method bumps the iterator forward and gets the next entry.
+
+Arguments:
+
+ Depth -- Receives the depth in the tree of the returned entry;
+ 0 indicates the root.
+ Error -- Receives TRUE if this method fails because of error.
+
+Return Value:
+
+ Returns a pointer to the next entry, or NULL if there are no more
+ or an error occurs.
+
+ If this method returns a non-NULL pointer, the value of *Error should
+ be ignored.
+
+--*/
+{
+ DebugPtrAssert( Error );
+
+ switch( _IteratorState ) {
+
+ case INDEX_ITERATOR_CORRUPT :
+
+ DebugPrint( "Index iterator is corrupt." );
+ *Error = TRUE;
+ return NULL;
+
+ case INDEX_ITERATOR_RESET :
+
+
+ // We want to get the first entry in the tree. The easiest way
+ // to do this is to start at the first entry in the root, drop
+ // down to the the next leaf, and then bounce back up until
+ // we find a non-end entry (which might be the leaf itself).
+ // Since we're starting a search, reinitialize the parent
+ // trail, too.
+ //
+ if( !_CurrentEntryTrail.Initialize() ) {
+
+ DebugPrint( "UNTFS: Can't initialize intstack.\n" );
+ *Error = TRUE;
+ return NULL;
+ }
+
+ _CurrentEntry = _IndexRoot->GetFirstEntry();
+ _IsCurrentEntryInRoot = TRUE;
+
+ // If the current entry isn't a leaf, drop down 'til we
+ // find a leaf entry.
+
+ if( (_CurrentEntry->Flags & INDEX_ENTRY_NODE) &&
+ GetDownpointer( _CurrentEntry ) != INVALID_VCN &&
+ !GetNextLeafEntry() ) {
+
+ // GetNextLeafEntry cleans up the private data appropriately.
+ *Error = TRUE;
+ return NULL;
+ }
+
+ // We've got the first entry in the index--return it.
+ // (Note that it may be an END entry).
+ //
+ _IteratorState = INDEX_ITERATOR_CURRENT;
+ UpdateOrdinal();
+ SaveCurrentKey();
+ *Depth = QueryCurrentEntryDepth();
+ *Error = FALSE;
+ return _CurrentEntry;
+
+
+ case INDEX_ITERATOR_INVALID :
+
+ // We have the information necessary to find the current
+ // entry, rather than the current entry itself. Incrementing
+ // _CurrentKeyOrdinal will give us the information needed
+ // to find the next entry, and then we fall through into
+ // the INDEX_ITERATOR_DELETED case.
+
+ if( _CurrentEntry->Flags & INDEX_ENTRY_END ) {
+
+ *Error = TRUE;
+ return NULL;
+ }
+
+ _CurrentKeyOrdinal++;
+
+ // Fall through to INDEX_ITERATOR_DELETED:
+
+ case INDEX_ITERATOR_DELETED :
+
+ // We have the information necessary to find the next entry,
+ // so let's find it!
+ //
+ if( _CurrentKeyLength == 0 ) {
+
+ *Error = TRUE;
+ return NULL;
+ }
+
+ if( FindEntry( _CurrentKeyLength,
+ _CurrentKey,
+ _CurrentKeyOrdinal,
+ &_CurrentEntry,
+ &_CurrentBuffer,
+ &_CurrentEntryTrail ) ||
+ _CurrentEntry != NULL ) {
+
+ // We got an entry--return it. Note that it
+ // may be an END entry.
+ //
+ _IsCurrentEntryInRoot = (_CurrentBuffer == NULL);
+ _IteratorState = INDEX_ITERATOR_CURRENT;
+ UpdateOrdinal();
+ SaveCurrentKey();
+ *Depth = QueryCurrentEntryDepth();
+ *Error = FALSE;
+ return _CurrentEntry;
+
+ } else {
+
+ // An error occurred--this iterator is hosed.
+
+ _IteratorState = INDEX_ITERATOR_CORRUPT;
+ DELETE( _CurrentBuffer );
+ *Error = TRUE;
+ return NULL;
+ }
+
+ case INDEX_ITERATOR_CURRENT :
+
+ // _CurrentEntry is valid.
+ //
+ if( !(_CurrentEntry->Flags & INDEX_ENTRY_END) ) {
+
+ // There are more entries in this block. Move on
+ // to the next one: if it's a node, get its first
+ // descendant; otherwise, we'll take that entry
+ // itself.
+ //
+ _CurrentEntry = GetNextEntry( _CurrentEntry );
+
+ if( _CurrentEntry->Flags & INDEX_ENTRY_NODE &&
+ GetDownpointer( _CurrentEntry ) != INVALID_VCN ) {
+
+ // This entry is a node; we want to return
+ // all its descendants before returning it.
+ //
+ if( !GetNextLeafEntry() ) {
+
+ // GetNextLeafEntry cleans up the
+ // private data as needed.
+ //
+ *Error = TRUE;
+ return NULL;
+ }
+ }
+
+ UpdateOrdinal();
+ SaveCurrentKey();
+ *Depth = QueryCurrentEntryDepth();
+ *Error = FALSE;
+ return _CurrentEntry;
+
+ } else if( !_IsCurrentEntryInRoot ) {
+
+ // There are no more entries in this block,
+ // so we should return the parent of this block.
+ // Note that GetNextParent sets up the information
+ // about depth.
+ //
+ if( !GetNextParent() ) {
+
+ // GetNextParent cleans up the private data
+ // if it fails.
+ //
+ *Error = TRUE;
+ return NULL;
+ }
+
+ UpdateOrdinal();
+ SaveCurrentKey();
+ *Depth = QueryCurrentEntryDepth();
+ *Error = FALSE;
+ return _CurrentEntry;
+
+ } else {
+
+ // There are no more entries in this block, and
+ // it's the root (so it doesn't have a parent).
+ // We're done!
+ //
+ *Error = FALSE;
+ return NULL;
+ }
+ }
+
+ return NULL; // Keep the compiler happy.
+}
+
+
+
+BOOLEAN
+NTFS_INDEX_TREE::DeleteCurrentEntry(
+ )
+/*++
+
+Routine Description:
+
+ This method deletes the entry which is the iterator's current entry.
+ It also adjusts the iterator so that the next call to GetNext will
+ return the entry after the one that got deleted.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ BOOLEAN Result;
+
+ DebugAssert( _IteratorState == INDEX_ITERATOR_CURRENT );
+ DebugPtrAssert( _CurrentEntry );
+ DebugAssert( _IsCurrentEntryInRoot || _CurrentBuffer != NULL );
+
+ if( _IteratorState != INDEX_ITERATOR_CURRENT ||
+ _CurrentEntry->Flags & INDEX_ENTRY_END ) {
+
+ return FALSE;
+ }
+
+ // The information we need to find the current entry again (which
+ // is also the information we need to find the next entry after
+ // we delete this entry) has been safely squirreled away by
+ // GetNext.
+ //
+ // RemoveEntry requires the ContainingBuffer parameter to be
+ // NULL if the target entry is in the root.
+
+ if( _IsCurrentEntryInRoot ) {
+
+ DELETE( _CurrentBuffer );
+ }
+
+ Result = RemoveEntry( _CurrentEntry,
+ _CurrentBuffer,
+ &_CurrentEntryTrail );
+
+ // Note that RemoveEntry renders the current entry location
+ // invalid.
+
+ _CurrentEntry = NULL;
+ DELETE( _CurrentBuffer );
+
+ _IteratorState = INDEX_ITERATOR_DELETED;
+
+ return Result;
+}
+
+
+BOOLEAN
+NTFS_INDEX_TREE::WriteCurrentEntry(
+ )
+/*++
+
+Routine Description:
+
+ This method commits the current entry (and the index block containing
+ it). Note that it is provided for use at the client's risk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ DebugAssert( _IteratorState == INDEX_ITERATOR_CURRENT );
+ DebugPtrAssert( _CurrentEntry );
+ DebugAssert( _IsCurrentEntryInRoot || _CurrentBuffer != NULL );
+
+ if( _IteratorState != INDEX_ITERATOR_CURRENT ) {
+
+ return FALSE;
+ }
+
+ // If the current entry is in the root, then there's no work
+ // to be done; any changes to the current entry will be written
+ // to disk when the index tree is saved.
+ //
+ if( !_IsCurrentEntryInRoot ) {
+
+ return( _CurrentBuffer->Write( _AllocationAttribute ) );
+ }
+
+ return TRUE; // If the current entry is in the root then write
+ // is a no-op.
+}
+
+
+VOID
+NTFS_INDEX_TREE::UpdateOrdinal(
+ )
+/*++
+
+Routine Description:
+
+ This method is called when a the iterator advances _CurrentEntry
+ to the next entry, in order to determine the correct value of
+ _CurrentKeyOrdinal. If the key value of the new _CurrentEntry
+ is the same as the saved value, then _CurrentKeyOrdinal is
+ incremented; otherwise, it is set to zero.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DebugAssert( _IteratorState == INDEX_ITERATOR_CURRENT );
+ DebugAssert( _CurrentEntry->AttributeLength <= _CurrentKeyMaxLength );
+ DebugPtrAssert( _CurrentKey );
+ DebugPtrAssert( _CurrentEntry );
+
+ if( !(_CurrentEntry->Flags & INDEX_ENTRY_END) &&
+ _CurrentKeyLength == _CurrentEntry->AttributeLength &&
+ memcmp( _CurrentKey,
+ GetIndexEntryValue( _CurrentEntry ),
+ _CurrentEntry->AttributeLength ) == 0 ) {
+
+ _CurrentKeyOrdinal += 1;
+
+ } else {
+
+ _CurrentKeyOrdinal = 0;
+ }
+}
+
+
+VOID
+NTFS_INDEX_TREE::SaveCurrentKey(
+ )
+/*++
+
+Routine Description:
+
+ This method squirrels away the information we need to find
+ the current key.
+
+Arguments:
+
+ None.
+
+Return value:
+
+ None.
+--*/
+{
+ DebugAssert( _IteratorState == INDEX_ITERATOR_CURRENT );
+ DebugAssert( _CurrentEntry->AttributeLength <= _CurrentKeyMaxLength );
+ DebugPtrAssert( _CurrentKey );
+ DebugPtrAssert( _CurrentEntry );
+
+ if( _CurrentEntry->Flags & INDEX_ENTRY_END ) {
+
+ _CurrentKeyLength = 0;
+
+ } else {
+
+ memcpy( _CurrentKey,
+ GetIndexEntryValue( _CurrentEntry ),
+ _CurrentEntry->AttributeLength );
+
+ _CurrentKeyLength = _CurrentEntry->AttributeLength;
+ }
+}
diff --git a/private/utils/untfs/src/largemcb.c b/private/utils/untfs/src/largemcb.c
new file mode 100644
index 000000000..fd022df44
--- /dev/null
+++ b/private/utils/untfs/src/largemcb.c
@@ -0,0 +1,2982 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ LargeMcb.c
+
+Abstract:
+
+ The MCB routines provide support for maintaining an in-memory copy of
+ the retrieval mapping information for a file. The general idea is to
+ have the file system lookup the retrieval mapping for a VBN once from
+ the disk, add the mapping to the MCB structure, and then utilize the
+ MCB to retrieve the mapping for subsequent accesses to the file. A
+ variable of type MCB is used to store the mapping information.
+
+ The routines provided here allow the user to incrementally store some
+ or all of the retrieval mapping for a file and to do so in any order.
+ That is, the mapping can be inserted to the MCB structure all at once
+ starting from the beginning and working to the end of the file, or it
+ can be randomly scattered throughout the file.
+
+ The package identifies each contiguous run of sectors mapping VBNs
+ and LBNs indenpendent of the order they are added to the MCB
+ structure. For example a user can define a mapping between VBN
+ sector 0 and LBN sector 107, and between VBN sector 2 and LBN sector
+ 109. The mapping now contains two runs each one sector in length.
+ Now if the user adds an additional mapping between VBN sector 1 and
+ LBN sector 106 the MCB structure will contain only one run 3 sectors
+ in length.
+
+ Concurrent access to the MCB structure is control by this package.
+
+ The following routines are provided by this package:
+
+ o FsRtlInitializeMcb - Initialize a new MCB structure. There
+ should be one MCB for every opened file. Each MCB structure
+ must be initialized before it can be used by the system.
+
+ o FsRtlUninitializeMcb - Uninitialize an MCB structure. This call
+ is used to cleanup any anciallary structures allocated and
+ maintained by the MCB. After being uninitialized the MCB must
+ again be initialized before it can be used by the system.
+
+ o FsRtlAddMcbEntry - This routine adds a new range of mappings
+ between LBNs and VBNs to the MCB structure.
+
+ o FsRtlRemoveMcbEntry - This routines removes an existing range of
+ mappings between LBNs and VBNs from the MCB structure.
+
+ o FsRtlLookupMcbEntry - This routine returns the LBN mapped to by
+ a VBN, and indicates, in sectors, the length of the run.
+
+ o FsRtlLookupLastMcbEntry - This routine returns the mapping for
+ the largest VBN stored in the structure.
+
+ o FsRtlNumberOfRunsInMcb - This routine tells the caller total
+ number of discontiguous sectors runs stored in the MCB
+ structure.
+
+ o FsRtlGetNextMcbEntry - This routine returns the the caller the
+ starting VBN and LBN of a given run stored in the MCB structure.
+
+Author:
+
+ Gary Kimura [GaryKi] 5-Feb-1990
+
+Revision History:
+
+--*/
+
+#include "FsRtlP.h"
+
+//
+// Trace level for the module
+//
+
+#define Dbg (0x80000000)
+
+
+//
+// Retrieval mapping data structures. The following two structure together
+// are used to map a Vbn to an Lbn. It is layed out as follows:
+//
+//
+// MCB:
+// +----------------+----------------+
+// | PairCount |MaximumPairCount|
+// +----------------+----------------+
+// | Mapping | PoolType |
+// +----------------+----------------+
+//
+//
+// MAPPING:
+// +----------------+----------------+
+// | Lbn | NextVbn | : 0
+// +----------------+----------------+
+// | |
+// / /
+// / /
+// | |
+// +----------------+----------------+
+// | Lbn | NextVbn | : PairCount
+// +----------------+----------------+
+// | |
+// / /
+// / /
+// | |
+// +----------------+----------------+
+// | Lbn | NextVbn |
+// +----------------+----------------+
+//
+// : MaximumPairCount
+//
+// The pairs from 0 to PairCount - 1 are valid. Given an index between
+// 0 and PairCount - 1 (inclusive) it represents the following Vbn
+// to Lbn mapping information
+//
+//
+// { if Index == 0 then 0
+// StartingVbn {
+// { if Index <> 0 then NextVbn[i-1]
+//
+//
+// EndingVbn = NextVbn[i] - 1
+//
+//
+// StartingLbn = Lbn[i]
+//
+//
+// To compute the mapping of a Vbn to an Lbn the following algorithm
+// is used
+//
+// 1. search through the pairs until we find the slot "i" that contains
+// the Vbn we after. Report an error if none if found.
+//
+// 2. Lbn = StartingLbn + (Vbn - StartingVbn);
+//
+// A hole in the allocation (i.e., a sparse allocation) is represented by
+// an Lbn value of -1 (note that is is different than Mcb.c).
+//
+
+#define UNUSED_LBN (-1)
+
+typedef struct _MAPPING {
+ VBN NextVbn;
+ LBN Lbn;
+} MAPPING;
+typedef MAPPING *PMAPPING;
+
+typedef struct _NONOPAQUE_MCB {
+ PFAST_MUTEX FastMutex;
+ ULONG MaximumPairCount;
+ ULONG PairCount;
+ POOL_TYPE PoolType;
+ PMAPPING Mapping;
+} NONOPAQUE_MCB;
+typedef NONOPAQUE_MCB *PNONOPAQUE_MCB;
+
+//
+// A macro to return the size, in bytes, of a retrieval mapping structure
+//
+
+#define SizeOfMapping(MCB) ((sizeof(MAPPING) * (MCB)->MaximumPairCount))
+
+//
+// The parts of a run can be computed as follows:
+//
+//
+// StartingVbn(MCB,I) Mapping[I].NextVbn
+// | |
+// V V
+//
+// Run-(I-1)---+ +---------Run-(I)-----------+ +---Run-(I+1)
+//
+// A A
+// | |
+// Mapping[I].Lbn EndingLbn(MCB,I)
+//
+
+#define PreviousEndingVbn(MCB,I) ( \
+ (VBN)((I) == 0 ? 0xffffffff : EndingVbn(MCB,(I)-1)) \
+)
+
+#define StartingVbn(MCB,I) ( \
+ (VBN)((I) == 0 ? 0 : (((MCB)->Mapping))[(I)-1].NextVbn) \
+)
+
+#define EndingVbn(MCB,I) ( \
+ (VBN)((((MCB)->Mapping)[(I)].NextVbn) - 1) \
+)
+
+#define NextStartingVbn(MCB,I) ( \
+ (VBN)((I) >= (MCB)->PairCount ? 0 : StartingVbn(MCB,(I)+1)) \
+)
+
+
+
+
+#define PreviousEndingLbn(MCB,I) ( \
+ (LBN)((I) == 0 ? UNUSED_LBN : EndingLbn(MCB,(I)-1)) \
+)
+
+#define StartingLbn(MCB,I) ( \
+ (LBN)(((MCB)->Mapping)[(I)].Lbn) \
+)
+
+#define EndingLbn(MCB,I) ( \
+ (LBN)(StartingLbn(MCB,I) == UNUSED_LBN ? \
+ UNUSED_LBN : \
+ ((MCB)->Mapping[(I)].Lbn + \
+ (MCB)->Mapping[(I)].NextVbn - StartingVbn(MCB,I) - 1) \
+ ) \
+)
+
+#define NextStartingLbn(MCB,I) ( \
+ (LBN)((I) >= (MCB)->PairCount - 1 ? UNUSED_LBN : StartingLbn(MCB,(I)+1)) \
+)
+
+#if 0
+LBN
+NextStartingLbn(
+ PNONOPAQUE_MCB Mcb,
+ ULONG I
+ )
+{
+ if ( I >= Mcb->PairCount - 1 ) {
+ return (LBN)UNUSED_LBN;
+ }
+ else {
+ return StartingLbn(Mcb,I+1);
+ }
+}
+#endif
+
+#define SectorsWithinRun(MCB,I) ( \
+ (ULONG)(EndingVbn(MCB,I) - StartingVbn(MCB,I) + 1) \
+)
+
+VOID
+FsRtlRemoveMcbEntryPrivate (
+ IN PNONOPAQUE_MCB OpaqueMcb,
+ IN ULONG Vbn,
+ IN ULONG SectorCount
+ );
+
+//
+// A private routine to search a mapping structure for a Vbn
+//
+
+BOOLEAN
+FsRtlFindLargeIndex (
+ IN PNONOPAQUE_MCB Mcb,
+ IN VBN Vbn,
+ OUT PULONG Index
+ );
+
+VOID
+FsRtlAddLargeEntry (
+ IN PNONOPAQUE_MCB Mcb,
+ IN ULONG WhereToAddIndex,
+ IN ULONG AmountToAdd
+ );
+
+VOID
+FsRtlRemoveLargeEntry (
+ IN PNONOPAQUE_MCB Mcb,
+ IN ULONG WhereToRemoveIndex,
+ IN ULONG AmountToRemove
+ );
+
+//
+// Some private routines to handle common allocations.
+//
+
+PVOID
+FsRtlAllocateFirstMapping (
+ );
+
+VOID
+FsRtlFreeFirstMapping (
+ IN PVOID Mapping
+ );
+
+PFAST_MUTEX
+FsRtlAllocateFastMutex (
+ );
+
+VOID
+FsRtlFreeFastMutex (
+ IN PFAST_MUTEX FastMutex
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE, FsRtlInitializeMcb)
+#pragma alloc_text(PAGE, FsRtlUninitializeMcb)
+#endif
+
+
+//
+// Define a small cache of free mapping pairs structures and also the
+// initial size of the mapping pair
+//
+
+#define INITIAL_MAXIMUM_PAIR_COUNT (15)
+
+//
+// Some globals used with the first mapping allocation
+//
+
+#define FREE_FIRST_MAPPING_ARRAY_SIZE (16)
+
+PVOID FsRtlFreeFirstMappingArray[FREE_FIRST_MAPPING_ARRAY_SIZE];
+
+UCHAR FsRtlFreeFirstMappingSize = 0;
+
+ULONG FsRtlNetFirstMapping = 0;
+
+//
+// Some globals used with the FastMutex allocation
+//
+
+#define FREE_FAST_MUTEX_ARRAY_SIZE (16)
+
+PFAST_MUTEX FsRtlFreeFastMutexArray[FREE_FAST_MUTEX_ARRAY_SIZE];
+
+UCHAR FsRtlFreeFastMutexSize = 0;
+
+ULONG FsRtlNetFastMutex = 0;
+
+
+//
+// The following few routines define the small mcb package which is
+// implemented behind everyones back as large mcbs. The only funny
+// thing we really need to do here is to make sure that unused Lbns
+// get returned as 0 and not -1. This is the result of an historical
+// difference between the original Mcb and LargeMcb packages.
+//
+
+VOID
+FsRtlInitializeMcb (
+ IN PMCB Mcb,
+ IN POOL_TYPE PoolType
+ )
+{
+ PAGED_CODE();
+
+ FsRtlInitializeLargeMcb( (PLARGE_MCB)Mcb,
+ PoolType );
+
+ return;
+}
+
+VOID
+FsRtlUninitializeMcb (
+ IN PMCB Mcb
+ )
+
+{
+ PAGED_CODE();
+
+ FsRtlUninitializeLargeMcb( (PLARGE_MCB)Mcb );
+
+ return;
+}
+
+VOID
+FsRtlTruncateMcb (
+ IN PMCB Mcb,
+ IN VBN Vbn
+ )
+{
+ PAGED_CODE();
+
+ FsRtlTruncateLargeMcb( (PLARGE_MCB)Mcb,
+ (LONGLONG)(Vbn) );
+
+ return;
+}
+
+BOOLEAN
+FsRtlAddMcbEntry (
+ IN PMCB Mcb,
+ IN VBN Vbn,
+ IN LBN Lbn,
+ IN ULONG SectorCount
+ )
+
+{
+ PAGED_CODE();
+
+ return FsRtlAddLargeMcbEntry( (PLARGE_MCB)Mcb,
+ (LONGLONG)(Vbn),
+ (LONGLONG)(Lbn),
+ (LONGLONG)(SectorCount) );
+}
+
+VOID
+FsRtlRemoveMcbEntry (
+ IN PMCB OpaqueMcb,
+ IN VBN Vbn,
+ IN ULONG SectorCount
+ )
+
+{
+ PNONOPAQUE_MCB Mcb = (PNONOPAQUE_MCB)OpaqueMcb;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "FsRtlRemoveMcbEntry, Mcb = %08lx\n", Mcb );
+ DebugTrace( 0, Dbg, " Vbn = %08lx\n", Vbn );
+ DebugTrace( 0, Dbg, " SectorCount = %08lx\n", SectorCount );
+
+ ExAcquireFastMutex( Mcb->FastMutex );
+
+ try {
+
+ FsRtlRemoveMcbEntryPrivate( Mcb,
+ Vbn,
+ SectorCount );
+
+ } finally {
+
+ ExReleaseFastMutex( Mcb->FastMutex );
+
+ DebugTrace(-1, Dbg, "FsRtlRemoveMcbEntry -> VOID\n", 0 );
+ }
+
+ return;
+}
+
+BOOLEAN
+FsRtlLookupMcbEntry (
+ IN PMCB Mcb,
+ IN VBN Vbn,
+ OUT PLBN Lbn,
+ OUT PULONG SectorCount OPTIONAL,
+ OUT PULONG Index OPTIONAL
+ )
+
+{
+ BOOLEAN Results;
+ LONGLONG LiLbn;
+ LONGLONG LiSectorCount;
+
+ Results = FsRtlLookupLargeMcbEntry( (PLARGE_MCB)Mcb,
+ (LONGLONG)(Vbn),
+ &LiLbn,
+ ARGUMENT_PRESENT(SectorCount) ? &LiSectorCount : NULL,
+ NULL,
+ NULL,
+ Index );
+
+ *Lbn = (((ULONG)LiLbn) == -1 ? 0 : ((ULONG)LiLbn));
+
+ if (ARGUMENT_PRESENT(SectorCount)) { *SectorCount = ((ULONG)LiSectorCount); }
+
+ return Results;
+}
+
+BOOLEAN
+FsRtlLookupLastMcbEntry (
+ IN PMCB Mcb,
+ OUT PVBN Vbn,
+ OUT PLBN Lbn
+ )
+
+{
+ BOOLEAN Results;
+ LONGLONG LiVbn;
+ LONGLONG LiLbn;
+
+ PAGED_CODE();
+
+ Results = FsRtlLookupLastLargeMcbEntry( (PLARGE_MCB)Mcb,
+ &LiVbn,
+ &LiLbn );
+
+ *Vbn = ((ULONG)LiVbn);
+ *Lbn = (((ULONG)LiLbn) == -1 ? 0 : ((ULONG)LiLbn));
+
+ return Results;
+}
+
+ULONG
+FsRtlNumberOfRunsInMcb (
+ IN PMCB Mcb
+ )
+
+{
+ PAGED_CODE();
+
+ return FsRtlNumberOfRunsInLargeMcb( (PLARGE_MCB)Mcb );
+}
+
+BOOLEAN
+FsRtlGetNextMcbEntry (
+ IN PMCB Mcb,
+ IN ULONG RunIndex,
+ OUT PVBN Vbn,
+ OUT PLBN Lbn,
+ OUT PULONG SectorCount
+ )
+
+{
+ BOOLEAN Results;
+ LONGLONG LiVbn;
+ LONGLONG LiLbn;
+ LONGLONG LiSectorCount;
+
+ PAGED_CODE();
+
+ Results = FsRtlGetNextLargeMcbEntry( (PLARGE_MCB)Mcb,
+ RunIndex,
+ &LiVbn,
+ &LiLbn,
+ &LiSectorCount );
+
+ *Vbn = ((ULONG)LiVbn);
+ *Lbn = (((ULONG)LiLbn) == -1 ? 0 : ((ULONG)LiLbn));
+ *SectorCount = ((ULONG)LiSectorCount);
+
+ return Results;
+}
+
+
+VOID
+FsRtlInitializeLargeMcb (
+ IN PLARGE_MCB OpaqueMcb,
+ IN POOL_TYPE PoolType
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes a new Mcb structure. The caller must
+ supply the memory for the Mcb structure. This call must precede all
+ other calls that set/query the Mcb structure.
+
+ If pool is not available this routine will raise a status value
+ indicating insufficient resources.
+
+Arguments:
+
+ OpaqueMcb - Supplies a pointer to the Mcb structure to initialize.
+
+ PoolType - Supplies the pool type to use when allocating additional
+ internal Mcb memory.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNONOPAQUE_MCB Mcb = (PNONOPAQUE_MCB)OpaqueMcb;
+
+ DebugTrace(+1, Dbg, "FsRtlInitializeLargeMcb, Mcb = %08lx\n", Mcb );
+
+ //
+ // Preset the following fields to null so we know to deallocate them
+ // during an abnormal termination
+ //
+
+ Mcb->FastMutex = NULL;
+ Mcb->Mapping = NULL;
+
+ try {
+
+ //
+ // Initialize the fields in the Mcb
+ //
+
+ Mcb->FastMutex = FsRtlAllocateFastMutex();
+
+ ExInitializeFastMutex( Mcb->FastMutex );
+
+ Mcb->PairCount = 0;
+ Mcb->PoolType = PoolType;
+
+ //
+ // Allocate a new buffer an initial size is one that will hold
+ // 16 runs
+ //
+
+ if (PoolType == PagedPool) {
+
+ Mcb->Mapping = FsRtlAllocateFirstMapping();
+
+ } else {
+
+ Mcb->Mapping = FsRtlAllocatePool( Mcb->PoolType, sizeof(MAPPING) * INITIAL_MAXIMUM_PAIR_COUNT );
+ }
+
+ //**** RtlZeroMemory( Mcb->Mapping, sizeof(MAPPING) * INITIAL_MAXIMUM_PAIR_COUNT );
+
+ Mcb->MaximumPairCount = INITIAL_MAXIMUM_PAIR_COUNT;
+
+ } finally {
+
+ //
+ // If this is an abnormal termination then we need to deallocate
+ // the FastMutex and/or mapping.
+ //
+
+ if (AbnormalTermination()) {
+
+ if (Mcb->FastMutex != NULL) { FsRtlFreeFastMutex( Mcb->FastMutex ); }
+ }
+
+ DebugTrace(-1, Dbg, "FsRtlInitializeLargeMcb -> VOID\n", 0 );
+ }
+
+ //
+ // And return to our caller
+ //
+
+ return;
+}
+
+
+VOID
+FsRtlUninitializeLargeMcb (
+ IN PLARGE_MCB OpaqueMcb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine uninitializes an Mcb structure. After calling this routine
+ the input Mcb structure must be re-initialized before being used again.
+
+Arguments:
+
+ OpaqueMcb - Supplies a pointer to the Mcb structure to uninitialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNONOPAQUE_MCB Mcb = (PNONOPAQUE_MCB)OpaqueMcb;
+
+ DebugTrace(+1, Dbg, "FsRtlUninitializeLargeMcb, Mcb = %08lx\n", Mcb );
+
+ //
+ // Protect against some user calling us to uninitialize an mcb twice
+ //
+
+ if (Mcb->FastMutex == NULL) {
+
+ ASSERTMSG("Being called to uninitialize an Mcb that is already Uninitialized ", FALSE);
+
+ return;
+ }
+
+ //
+ // Deallocate the FastMutex and mapping buffer
+ //
+
+ FsRtlFreeFastMutex( Mcb->FastMutex );
+
+ Mcb->FastMutex = NULL;
+
+ if ((Mcb->PoolType == PagedPool) && (Mcb->MaximumPairCount == INITIAL_MAXIMUM_PAIR_COUNT)) {
+
+ FsRtlFreeFirstMapping( Mcb->Mapping );
+
+ } else {
+
+ ExFreePool( Mcb->Mapping );
+ }
+
+ //
+ // Now zero our all of the fields in the Mcb
+ //
+
+ //**** Mcb->MaximumPairCount = 0;
+ //**** Mcb->PairCount = 0;
+ //**** Mcb->Mapping = NULL;
+
+ //
+ // And return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "FsRtlUninitializeLargeMcb -> VOID\n", 0 );
+
+ return;
+}
+
+
+VOID
+FsRtlTruncateLargeMcb (
+ IN PLARGE_MCB OpaqueMcb,
+ IN LONGLONG LargeVbn
+ )
+
+/*++
+
+Routine Description:
+
+ This routine truncates an Mcb structure to the specified Vbn.
+ After calling this routine the Mcb will only contain mappings
+ up to and not including the input vbn.
+
+Arguments:
+
+ OpaqueMcb - Supplies a pointer to the Mcb structure to truncate.
+
+ LargeVbn - Specifies the last Vbn at which is no longer to be
+ mapped.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNONOPAQUE_MCB Mcb = (PNONOPAQUE_MCB)OpaqueMcb;
+
+ VBN Vbn = ((ULONG)LargeVbn);
+
+ ASSERTMSG("LargeInteger not supported yet ", ((((PLARGE_INTEGER)&LargeVbn)->HighPart == 0) ||
+ ((((PLARGE_INTEGER)&LargeVbn)->HighPart == 0x7FFFFFFF) &&
+ (((ULONG)LargeVbn) == 0xFFFFFFFF))));
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "FsRtlTruncateLargeMcb, Mcb = %08lx\n", Mcb );
+
+ ExAcquireFastMutex( Mcb->FastMutex );
+
+ try {
+
+ //
+ // Do a quick test to see if we are truncating the entire Mcb.
+ //
+
+ if (Vbn == 0) {
+
+ Mcb->PairCount = 0;
+
+ } else if (Mcb->PairCount > 0) {
+
+ //
+ // Now if the pair count is greater than zero then we will
+ // call the remove mcb entry routine to actually do the truncation
+ // for us.
+ //
+
+ FsRtlRemoveMcbEntryPrivate( Mcb, Vbn, 0xffffffff - Vbn );
+ }
+
+ //
+ // Now see if we can shrink the allocation for the mapping pairs.
+ // We'll shrink the mapping pair buffer if the new pair count will
+ // fit within a quarter of the current maximum pair count and the
+ // current maximum is greater than the initial pair count.
+ //
+
+ if ((Mcb->PairCount < (Mcb->MaximumPairCount / 4)) &&
+ (Mcb->MaximumPairCount > INITIAL_MAXIMUM_PAIR_COUNT)) {
+
+ ULONG NewMax;
+ PMAPPING Mapping;
+
+ //
+ // We need to allocate a new mapping so compute a new maximum pair
+ // count. We'll allocate double the current pair count, but never
+ // less than the initial pair count.
+ //
+
+ NewMax = Mcb->PairCount * 2;
+ if (NewMax < INITIAL_MAXIMUM_PAIR_COUNT) { NewMax = INITIAL_MAXIMUM_PAIR_COUNT; }
+
+ Mapping = ExAllocatePool( Mcb->PoolType, sizeof(MAPPING) * NewMax );
+
+ //
+ // Now check if we really got a new buffer
+ //
+
+ if (Mapping != NULL) {
+
+ //
+ // Now copy over the old mapping to the new buffer
+ //
+
+ RtlCopyMemory( Mapping, Mcb->Mapping, sizeof(MAPPING) * Mcb->PairCount );
+
+ //
+ // Deallocate the old buffer
+ //
+
+ ExFreePool( Mcb->Mapping );
+
+ //
+ // And set up the new buffer in the Mcb
+ //
+
+ Mcb->Mapping = Mapping;
+ Mcb->MaximumPairCount = NewMax;
+ }
+ }
+
+ } finally {
+
+ ExReleaseFastMutex( Mcb->FastMutex );
+ }
+
+ //
+ // And return to our caller
+ //
+
+ DebugTrace(-1, Dbg, "FsRtlTruncateLargeMcb -> VOID\n", 0 );
+
+ return;
+}
+
+
+BOOLEAN
+FsRtlAddLargeMcbEntry (
+ IN PLARGE_MCB OpaqueMcb,
+ IN LONGLONG LargeVbn,
+ IN LONGLONG LargeLbn,
+ IN LONGLONG LargeSectorCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to add a new mapping of VBNs to LBNs to an existing
+ Mcb. The information added will map
+
+ Vbn to Lbn,
+
+ Vbn+1 to Lbn+1,...
+
+ Vbn+(SectorCount-1) to Lbn+(SectorCount-1).
+
+ The mapping for the VBNs must not already exist in the Mcb. If the
+ mapping continues a previous run, then this routine will actually coalesce
+ them into 1 run.
+
+ If pool is not available to store the information this routine will raise a
+ status value indicating insufficient resources.
+
+ An input Lbn value of zero is illegal (i.e., the Mcb structure will never
+ map a Vbn to a zero Lbn value).
+
+Arguments:
+
+ OpaqueMcb - Supplies the Mcb in which to add the new mapping.
+
+ Vbn - Supplies the starting Vbn of the new mapping run to add to the Mcb.
+
+ Lbn - Supplies the starting Lbn of the new mapping run to add to the Mcb.
+
+ SectorCount - Supplies the size of the new mapping run (in sectors).
+
+Return Value:
+
+ BOOLEAN - TRUE if the mapping was added successfully (i.e., the new
+ Vbns did not collide with existing Vbns), and FALSE otherwise. If
+ FALSE is returned then the Mcb is not changed.
+
+--*/
+
+{
+ PNONOPAQUE_MCB Mcb = (PNONOPAQUE_MCB)OpaqueMcb;
+
+ VBN Vbn = ((ULONG)LargeVbn);
+ LBN Lbn = ((ULONG)LargeLbn);
+ ULONG SectorCount = ((ULONG)LargeSectorCount);
+
+ ULONG Index;
+
+ VBN LastVbn;
+
+ BOOLEAN Result;
+
+ ASSERTMSG("LargeInteger not supported yet ", ((PLARGE_INTEGER)&LargeVbn)->HighPart == 0);
+ ASSERTMSG("LargeInteger not supported yet ", ((PLARGE_INTEGER)&LargeLbn)->HighPart == 0);
+ ASSERTMSG("LargeInteger not supported yet ", ((PLARGE_INTEGER)&LargeSectorCount)->HighPart == 0);
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "FsRtlAddLargeMcbEntry, Mcb = %08lx\n", Mcb );
+ DebugTrace( 0, Dbg, " Vbn = %08lx\n", Vbn );
+ DebugTrace( 0, Dbg, " Lbn = %08lx\n", Lbn );
+ DebugTrace( 0, Dbg, " SectorCount = %08lx\n", SectorCount );
+
+ ExAcquireFastMutex( Mcb->FastMutex );
+
+ try {
+
+ if (FsRtlFindLargeIndex(Mcb, Vbn, &Index)) {
+
+ ULONG EndVbn = Vbn + SectorCount - 1;
+ ULONG EndIndex;
+
+ //
+ // First check the case where we are adding to an existing mcb run
+ // and if so then we will modify the insertion to complete the run
+ //
+ // --ExistingRun--| ==becomes==> --ExistingRun--|
+ // |--NewRun--| |---|
+ //
+ // --ExistingRun----| ==becomes==> a noop
+ // |--NewRun--|
+ //
+
+ if (StartingLbn(Mcb, Index) != UNUSED_LBN) {
+
+ //
+ // Assert that the Lbn's line up between the new and existing run
+ //
+
+ ASSERT(Lbn == (StartingLbn(Mcb, Index) + (Vbn - StartingVbn(Mcb, Index))));
+
+ //
+ // Check if the new run is contained in the existing run
+ //
+
+ if (EndVbn <= EndingVbn(Mcb, Index)) {
+
+ //
+ // Do nothing because the run is contained within the existing run
+ //
+
+ try_return(Result = TRUE);
+ }
+
+ //
+ // Otherwise we will simply trim off the request for the new run
+ // to not overlap with the existing run
+ //
+
+ Vbn = NextStartingVbn(Mcb, Index);
+ Lbn = EndingLbn(Mcb, Index) + 1;
+
+ ASSERT(EndVbn >= Vbn);
+
+ SectorCount = EndVbn - Vbn + 1;
+
+ //
+ // At this point the new run start in a hole, now check that if
+ // crosses into a non hole and if so then adjust new run to fit
+ // in the hole
+ //
+ //
+ // |--ExistingRun-- ==becomes==> |--ExistingRun--
+ // |--NewRun--| |--New|
+ //
+
+ } else if (FsRtlFindLargeIndex(Mcb, EndVbn, &EndIndex) && (Index == (EndIndex-1))) {
+
+ //
+ // Assert that the Lbn's line up in the overlap
+ //
+
+ ASSERT( StartingLbn(Mcb, EndIndex) == Lbn + (StartingVbn(Mcb, EndIndex) - Vbn) );
+
+ //
+ // Truncate the sector count to go up to but not include
+ // the existing run
+ //
+
+ SectorCount = StartingVbn(Mcb, EndIndex) - Vbn;
+ }
+ }
+
+ //
+ // Find the index for the starting Vbn of our new run, if there isn't
+ // a hole found then index will be set to paircount.
+ //
+
+ if (((Index = Mcb->PairCount) == 0) ||
+ (PreviousEndingVbn(Mcb,Index)+1 <= Vbn) ||
+ !FsRtlFindLargeIndex(Mcb, Vbn, &Index)) {
+
+ //
+ // We didn't find a mapping, therefore this new mapping must
+ // go on at the end of the current mapping.
+ //
+ // See if we can just grow the last mapping in the current mcb.
+ // We can grow the last entry if (1) the Vbns follow on, and (2)
+ // the Lbns follow on. We can only grow the last mapping if the
+ // index is not 0.
+ //
+
+ if ((Index != 0) &&
+ (PreviousEndingVbn(Mcb,Index) + 1 == Vbn) &&
+ (PreviousEndingLbn(Mcb,Index) + 1 == Lbn)) {
+
+ //
+ // --LastRun--|---NewRun--|
+ //
+
+ //
+ // Extend the last run in the mcb
+ //
+
+ DebugTrace( 0, Dbg, "Continuing last run\n", 0);
+
+ (Mcb->Mapping)[Mcb->PairCount-1].NextVbn += SectorCount;
+
+ try_return (Result = TRUE);
+ }
+
+ //
+ // We couldn't grow the last mapping, now check to see if
+ // this is a continuation of the last Vbn (i.e., there isn't
+ // going to be a hole in the mapping). Or if this is the first
+ // run in the mapping
+ //
+
+ if ((Vbn == 0) ||
+ (PreviousEndingVbn(Mcb,Index) + 1 == Vbn)) {
+
+ //
+ // --LastRun--||---NewRun--|
+ //
+ // 0:|--NewRun--|
+ //
+
+ //
+ // We only need to add one more run to the mcb, so make sure
+ // there is enough room for one.
+ //
+
+ DebugTrace( 0, Dbg, "Adding new contiguous last run\n", 0);
+
+ FsRtlAddLargeEntry( Mcb, Index, 1 );
+
+ //
+ // Add the new mapping
+ //
+
+ (Mcb->Mapping)[Index].Lbn = Lbn;
+ (Mcb->Mapping)[Index].NextVbn = Vbn + SectorCount;
+
+ try_return (Result = TRUE);
+ }
+
+ //
+ // If we reach this point then there is going to be a hole in the
+ // mapping. and the mapping gets appended to the end of the current
+ // allocation. So need to make room for two more runs in the mcb.
+ //
+
+ //
+ // --LastRun--| hole |---NewRun--|
+ //
+ // 0: hole |--NewRun--|
+ //
+
+ DebugTrace( 0, Dbg, "Adding new noncontiguous last run\n", 0);
+
+ FsRtlAddLargeEntry( Mcb, Index, 2 );
+
+ //
+ // Add the hole
+ //
+
+ (Mcb->Mapping)[Index].Lbn = (LBN)UNUSED_LBN;
+ (Mcb->Mapping)[Index].NextVbn = Vbn;
+
+ //
+ // Add the new mapping
+ //
+
+ (Mcb->Mapping)[Index+1].Lbn = Lbn;
+ (Mcb->Mapping)[Index+1].NextVbn = Vbn + SectorCount;
+
+ try_return (Result = TRUE);
+ }
+
+ //
+ // We found an index for the Vbn therefore we must be trying
+ // to fill up a hole in the mcb. So first we need to check to make
+ // sure there really is a hole to be filled
+ //
+
+ LastVbn = Vbn + SectorCount - 1;
+
+ if ((StartingLbn(Mcb,Index) == UNUSED_LBN) &&
+ (StartingVbn(Mcb,Index) <= Vbn) && (LastVbn <= EndingVbn(Mcb,Index))) {
+
+ //
+ // The mapping fits in this hole, but now here are the following
+ // cases we must consider for the new mapping
+ //
+
+ if ((StartingVbn(Mcb,Index) < Vbn) && (LastVbn < EndingVbn(Mcb,Index))) {
+
+ // Leaves a hole are both ends
+ //
+ // --PreviousRun--| hole |--NewRun--| hole |--FollowingRun--
+ //
+ // 0: hole |--NewRun--| hole |--FollowingRun--
+ //
+
+ DebugTrace( 0, Dbg, "Hole at both ends\n", 0);
+
+ //
+ // Make room for two more entries. The NextVbn field of the
+ // one we're shifting remains valid.
+ //
+
+ FsRtlAddLargeEntry( Mcb, Index, 2 );
+
+ //
+ // Add the first hole
+ //
+
+ (Mcb->Mapping)[Index].Lbn = (LBN)UNUSED_LBN;
+ (Mcb->Mapping)[Index].NextVbn = Vbn;
+
+ //
+ // Add the new mapping
+ //
+
+ (Mcb->Mapping)[Index+1].Lbn = Lbn;
+ (Mcb->Mapping)[Index+1].NextVbn = Vbn + SectorCount;
+
+ //
+ // The second hole is already set up by the add entry call, because
+ // that call just shift over the original hole to that slot
+ //
+
+ try_return (Result = TRUE);
+ }
+
+ if ((StartingVbn(Mcb,Index) == Vbn) && (LastVbn < EndingVbn(Mcb,Index))) {
+
+ if (PreviousEndingLbn(Mcb,Index) + 1 == Lbn) {
+
+ //
+ // Leaves a hole at the rear, and continues the earlier run
+ //
+ // --PreviousRun--|--NewRun--| hole |--FollowingRun--
+ //
+
+ DebugTrace( 0, Dbg, "Hole at rear and continue\n", 0);
+
+ //
+ // We just need to extend the previous run
+ //
+
+ (Mcb->Mapping)[Index-1].NextVbn += SectorCount;
+
+ try_return (Result = TRUE);
+
+ } else {
+
+ //
+ // Leaves a hole at the rear, and does not continue the
+ // earlier run. As occurs if index is zero.
+ //
+ // --PreviousRun--||--NewRun--| hole |--FollowingRun--
+ //
+ // 0:|--NewRun--| hole |--FollowingRun--
+ //
+
+ DebugTrace( 0, Dbg, "Hole at rear and not continue\n", 0);
+
+ //
+ // Make room for one more entry. The NextVbn field of the
+ // one we're shifting remains valid.
+ //
+
+ FsRtlAddLargeEntry( Mcb, Index, 1 );
+
+ //
+ // Add the new mapping
+ //
+
+ (Mcb->Mapping)[Index].Lbn = Lbn;
+ (Mcb->Mapping)[Index].NextVbn = Vbn + SectorCount;
+
+ //
+ // The hole is already set up by the add entry call, because
+ // that call just shift over the original hole to that slot
+ //
+
+ try_return (Result = TRUE);
+ }
+ }
+
+ if ((StartingVbn(Mcb,Index) < Vbn) && (LastVbn == EndingVbn(Mcb,Index))) {
+
+ if (NextStartingLbn(Mcb,Index) == Lbn + SectorCount) {
+
+ //
+ // Leaves a hole at the front, and continues the following run
+ //
+ // --PreviousRun--| hole |--NewRun--|--FollowingRun--
+ //
+ // 0: hole |--NewRun--|--FollowingRun--
+ //
+
+ DebugTrace( 0, Dbg, "Hole at front and continue\n", 0);
+
+ //
+ // We just need to extend the following run
+ //
+
+ (Mcb->Mapping)[Index].NextVbn = Vbn;
+ (Mcb->Mapping)[Index+1].Lbn = Lbn;
+
+ try_return (Result = TRUE);
+
+ } else {
+
+ //
+ // Leaves a hole at the front, and does not continue the following
+ // run
+ //
+ // --PreviousRun--| hole |--NewRun--||--FollowingRun--
+ //
+ // 0: hole |--NewRun--||--FollowingRun--
+ //
+
+ DebugTrace( 0, Dbg, "Hole at front and not continue\n", 0);
+
+ //
+ // Make room for one more entry. The NextVbn field of the
+ // one we're shifting remains valid.
+ //
+
+ FsRtlAddLargeEntry( Mcb, Index, 1 );
+
+ //
+ // Add the hole
+ //
+
+ (Mcb->Mapping)[Index].Lbn = (LBN)UNUSED_LBN;
+ (Mcb->Mapping)[Index].NextVbn = Vbn;
+
+ //
+ // Add the new mapping
+ //
+
+ (Mcb->Mapping)[Index+1].Lbn = Lbn;
+
+ try_return (Result = TRUE);
+ }
+
+ }
+
+ if ((PreviousEndingLbn(Mcb,Index) + 1 == Lbn) &&
+ (NextStartingLbn(Mcb,Index) == Lbn + SectorCount)) {
+
+ //
+ // Leaves no holes, and continues both runs
+ //
+ // --PreviousRun--|--NewRun--|--FollowingRun--
+ //
+
+ DebugTrace( 0, Dbg, "No holes, and continues both runs\n", 0);
+
+ //
+ // We need to collapse the current index and the following index
+ // but first we copy the NextVbn of the follwing run into
+ // the NextVbn field of the previous run to so it all becomes
+ // one run
+ //
+
+ (Mcb->Mapping)[Index-1].NextVbn = (Mcb->Mapping)[Index+1].NextVbn;
+
+ FsRtlRemoveLargeEntry( Mcb, Index, 2 );
+
+ try_return (Result = TRUE);
+ }
+
+ if (NextStartingLbn(Mcb,Index) == Lbn + SectorCount) {
+
+ //
+ // Leaves no holes, and continues only following run
+ //
+ // --PreviousRun--||--NewRun--|--FollowingRun--
+ //
+ // 0:|--NewRun--|--FollowingRun--
+ //
+
+ DebugTrace( 0, Dbg, "No holes, and continues following\n", 0);
+
+ //
+ // This index is going away so we need to stretch the
+ // following run to meet up with the previous run
+ //
+
+ (Mcb->Mapping)[Index+1].Lbn = Lbn;
+
+ FsRtlRemoveLargeEntry( Mcb, Index, 1 );
+
+ try_return (Result = TRUE);
+ }
+
+ if (PreviousEndingLbn(Mcb,Index) + 1 == Lbn) {
+
+ //
+ // Leaves no holes, and continues only earlier run
+ //
+ // --PreviousRun--|--NewRun--||--FollowingRun--
+ //
+
+ DebugTrace( 0, Dbg, "No holes, and continues earlier\n", 0);
+
+ //
+ // This index is going away so we need to stretch the
+ // previous run to meet up with the following run
+ //
+
+ (Mcb->Mapping)[Index-1].NextVbn = (Mcb->Mapping)[Index].NextVbn;
+
+ FsRtlRemoveLargeEntry( Mcb, Index, 1 );
+
+ try_return (Result = TRUE);
+ }
+
+ //
+ // Leaves no holes, and continues neither run
+ //
+ // --PreviousRun--||--NewRun--||--FollowingRun--
+ //
+ // 0:|--NewRun--||--FollowingRun--
+ //
+
+ DebugTrace( 0, Dbg, "No holes, and continues none\n", 0);
+
+ (Mcb->Mapping)[Index].Lbn = Lbn;
+
+ try_return (Result = TRUE);
+ }
+
+ //
+ // We tried to overwrite an existing mapping so we'll have to
+ // tell our caller that it's not possible
+ //
+
+ Result = FALSE;
+
+ try_exit: NOTHING;
+ } finally {
+
+ ExReleaseFastMutex( Mcb->FastMutex );
+
+ DebugTrace(-1, Dbg, "FsRtlAddLargeMcbEntry -> %08lx\n", Result );
+ }
+
+ return Result;
+}
+
+
+VOID
+FsRtlRemoveLargeMcbEntry (
+ IN PLARGE_MCB OpaqueMcb,
+ IN LONGLONG LargeVbn,
+ IN LONGLONG LargeSectorCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes a mapping of VBNs to LBNs from an Mcb. The mappings
+ removed are for
+
+ Vbn,
+
+ Vbn+1, to
+
+ Vbn+(SectorCount-1).
+
+ The operation works even if the mapping for a Vbn in the specified range
+ does not already exist in the Mcb. If the specified range of Vbn includes
+ the last mapped Vbn in the Mcb then the Mcb mapping shrinks accordingly.
+
+ If pool is not available to store the information this routine will raise
+ a status value indicating insufficient resources.
+
+Arguments:
+
+ OpaqueMcb - Supplies the Mcb from which to remove the mapping.
+
+ Vbn - Supplies the starting Vbn of the mappings to remove.
+
+ SectorCount - Supplies the size of the mappings to remove (in sectors).
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PNONOPAQUE_MCB Mcb = (PNONOPAQUE_MCB)OpaqueMcb;
+
+ VBN Vbn = ((ULONG)LargeVbn);
+ ULONG SectorCount = ((ULONG)LargeSectorCount);
+
+ PAGED_CODE();
+
+ ASSERTMSG("LargeInteger not supported yet ", ((PLARGE_INTEGER)&LargeVbn)->HighPart == 0);
+
+ DebugTrace(+1, Dbg, "FsRtlRemoveLargeMcbEntry, Mcb = %08lx\n", Mcb );
+ DebugTrace( 0, Dbg, " Vbn = %08lx\n", Vbn );
+ DebugTrace( 0, Dbg, " SectorCount = %08lx\n", SectorCount );
+
+ ExAcquireFastMutex( Mcb->FastMutex );
+
+ try {
+
+ FsRtlRemoveMcbEntryPrivate( Mcb, Vbn, SectorCount );
+
+ } finally {
+
+ ExReleaseFastMutex( Mcb->FastMutex );
+
+ DebugTrace(-1, Dbg, "FsRtlRemoveLargeMcbEntry -> VOID\n", 0 );
+ }
+
+ return;
+}
+
+
+BOOLEAN
+FsRtlLookupLargeMcbEntry (
+ IN PLARGE_MCB OpaqueMcb,
+ IN LONGLONG LargeVbn,
+ OUT PLONGLONG LargeLbn OPTIONAL,
+ OUT PLONGLONG LargeSectorCount OPTIONAL,
+ OUT PLONGLONG LargeStartingLbn OPTIONAL,
+ OUT PLONGLONG LargeCountFromStartingLbn OPTIONAL,
+ OUT PULONG Index OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine retrieves the mapping of a Vbn to an Lbn from an Mcb.
+ It indicates if the mapping exists and the size of the run.
+
+Arguments:
+
+ OpaqueMcb - Supplies the Mcb being examined.
+
+ Vbn - Supplies the Vbn to lookup.
+
+ Lbn - Receives the Lbn corresponding to the Vbn. A value of -1 is
+ returned if the Vbn does not have a corresponding Lbn.
+
+ SectorCount - Receives the number of sectors that map from the Vbn to
+ contiguous Lbn values beginning with the input Vbn.
+
+ Index - Receives the index of the run found.
+
+Return Value:
+
+ BOOLEAN - TRUE if the Vbn is within the range of VBNs mapped by the
+ MCB (even if it corresponds to a hole in the mapping), and FALSE
+ if the Vbn is beyond the range of the MCB's mapping.
+
+ For example, if an MCB has a mapping for VBNs 5 and 7 but not for
+ 6, then a lookup on Vbn 5 or 7 will yield a non zero Lbn and a sector
+ count of 1. A lookup for Vbn 6 will return TRUE with an Lbn value of
+ 0, and lookup for Vbn 8 or above will return FALSE.
+
+--*/
+
+{
+ PNONOPAQUE_MCB Mcb = (PNONOPAQUE_MCB)OpaqueMcb;
+
+ BOOLEAN Result;
+
+ ULONG LocalIndex;
+
+ ASSERTMSG("LargeInteger not supported yet ", ((((PLARGE_INTEGER)&LargeVbn)->HighPart == 0) ||
+ ((((PLARGE_INTEGER)&LargeVbn)->HighPart == 0x7FFFFFFF) &&
+ (((ULONG)LargeVbn) == 0xFFFFFFFF))));
+
+ DebugTrace(+1, Dbg, "FsRtlLookupLargeMcbEntry, Mcb = %08lx\n", Mcb );
+ DebugTrace( 0, Dbg, " LargeVbn.LowPart = %08lx\n", LargeVbn.LowPart );
+
+ ExAcquireFastMutex( Mcb->FastMutex );
+
+ try {
+
+ if (!FsRtlFindLargeIndex(Mcb, ((ULONG)LargeVbn), &LocalIndex)) {
+
+ try_return (Result = FALSE);
+ }
+
+ //
+ // Compute the lbn for corresponding to the vbn, the value is the
+ // starting lbn of the run plus the number of sectors offset into the
+ // run. But if it's a hole then the sector Lbn is zero.
+ //
+
+ if (ARGUMENT_PRESENT(LargeLbn)) {
+
+ if (StartingLbn(Mcb,LocalIndex) == UNUSED_LBN) {
+
+ *((PULONG)LargeLbn) = (LBN)UNUSED_LBN;
+
+ } else {
+
+ *((PULONG)LargeLbn) = StartingLbn(Mcb,LocalIndex) + (((ULONG)LargeVbn) - StartingVbn(Mcb,LocalIndex));
+ }
+ }
+
+ //
+ // If there sector count argument is present then we'll return the number
+ // of sectors remaing in the run.
+ //
+
+ if (ARGUMENT_PRESENT(LargeSectorCount)) {
+
+ *((PULONG)LargeSectorCount) = EndingVbn(Mcb,LocalIndex) - ((ULONG)LargeVbn) + 1;
+ }
+
+ //
+ // Compute the starting lbn for corresponding to the start of the run, the value is the
+ // starting lbn of the run. But if it's a hole then the sector Lbn is zero.
+ //
+
+ if (ARGUMENT_PRESENT(LargeStartingLbn)) {
+
+ if (StartingLbn(Mcb,LocalIndex) == UNUSED_LBN) {
+
+ *((PULONG)LargeStartingLbn) = (LBN)UNUSED_LBN;
+
+ } else {
+
+ *((PULONG)LargeStartingLbn) = StartingLbn(Mcb,LocalIndex);
+ }
+ }
+
+ //
+ // If there sector count argument is present then we'll return the number
+ // of sectors in the run.
+ //
+
+ if (ARGUMENT_PRESENT(LargeCountFromStartingLbn)) {
+
+ *((PULONG)LargeCountFromStartingLbn) = EndingVbn(Mcb,LocalIndex) - StartingVbn(Mcb,LocalIndex) + 1;
+ }
+
+ //
+ // If the caller want to know the Index number, fill it in.
+ //
+
+ if (ARGUMENT_PRESENT(Index)) {
+
+ *Index = LocalIndex;
+ }
+
+ Result = TRUE;
+
+ try_exit: NOTHING;
+ } finally {
+
+ ExReleaseFastMutex( Mcb->FastMutex );
+
+ DebugTrace(-1, Dbg, "FsRtlLookupLargeMcbEntry -> %08lx\n", Result );
+ }
+
+ if (ARGUMENT_PRESENT(LargeLbn)) {
+ ((PLARGE_INTEGER)LargeLbn)->HighPart = (*((PULONG)LargeLbn) == UNUSED_LBN ? UNUSED_LBN : 0);
+ }
+
+ if (ARGUMENT_PRESENT(LargeSectorCount)) {
+ ((PLARGE_INTEGER)LargeSectorCount)->HighPart = 0;
+ }
+
+ if (ARGUMENT_PRESENT(LargeStartingLbn)) {
+ ((PLARGE_INTEGER)LargeStartingLbn)->HighPart = (*((PULONG)LargeStartingLbn) == UNUSED_LBN ? UNUSED_LBN : 0);
+ }
+
+ if (ARGUMENT_PRESENT(LargeCountFromStartingLbn)) {
+ ((PLARGE_INTEGER)LargeCountFromStartingLbn)->HighPart = 0;
+ }
+
+ return Result;
+}
+
+
+BOOLEAN
+FsRtlLookupLastLargeMcbEntry (
+ IN PLARGE_MCB OpaqueMcb,
+ OUT PLONGLONG LargeVbn,
+ OUT PLONGLONG LargeLbn
+ )
+
+/*++
+
+Routine Description:
+
+ This routine retrieves the last Vbn to Lbn mapping stored in the Mcb.
+ It returns the mapping for the last sector or the last run in the
+ Mcb. The results of this function is useful when extending an existing
+ file and needing to a hint on where to try and allocate sectors on the
+ disk.
+
+Arguments:
+
+ OpaqueMcb - Supplies the Mcb being examined.
+
+ Vbn - Receives the last Vbn value mapped.
+
+ Lbn - Receives the Lbn corresponding to the Vbn.
+
+Return Value:
+
+ BOOLEAN - TRUE if there is a mapping within the Mcb and FALSE otherwise
+ (i.e., the Mcb does not contain any mapping).
+
+--*/
+
+{
+ PNONOPAQUE_MCB Mcb = (PNONOPAQUE_MCB)OpaqueMcb;
+
+ BOOLEAN Result;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "FsRtlLookupLastLargeMcbEntry, Mcb = %08lx\n", Mcb );
+
+ ExAcquireFastMutex( Mcb->FastMutex );
+
+ try {
+
+ //
+ // Check to make sure there is at least one run in the mcb
+ //
+
+ if (Mcb->PairCount <= 0) {
+
+ try_return (Result = FALSE);
+ }
+
+ //
+ // Return the last mapping of the last run
+ //
+
+ *((PULONG)LargeLbn) = EndingLbn(Mcb,Mcb->PairCount-1);
+ *((PULONG)LargeVbn) = EndingVbn(Mcb,Mcb->PairCount-1);
+
+ Result = TRUE;
+
+ try_exit: NOTHING;
+ } finally {
+
+ ExReleaseFastMutex( Mcb->FastMutex );
+
+ DebugTrace(-1, Dbg, "FsRtlLookupLastLargeMcbEntry -> %08lx\n", Result );
+ }
+
+ ((PLARGE_INTEGER)LargeVbn)->HighPart = (*((PULONG)LargeVbn) == UNUSED_LBN ? UNUSED_LBN : 0);
+ ((PLARGE_INTEGER)LargeLbn)->HighPart = (*((PULONG)LargeLbn) == UNUSED_LBN ? UNUSED_LBN : 0);
+
+ return Result;
+}
+
+
+ULONG
+FsRtlNumberOfRunsInLargeMcb (
+ IN PLARGE_MCB OpaqueMcb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns to the its caller the number of distinct runs
+ mapped by an Mcb. Holes (i.e., Vbns that map to Lbn=UNUSED_LBN) are counted
+ as runs. For example, an Mcb containing a mapping for only Vbns 0 and 3
+ will have 3 runs, one for the first mapped sector, a second for the
+ hole covering Vbns 1 and 2, and a third for Vbn 3.
+
+Arguments:
+
+ OpaqueMcb - Supplies the Mcb being examined.
+
+Return Value:
+
+ ULONG - Returns the number of distinct runs mapped by the input Mcb.
+
+--*/
+
+{
+ PNONOPAQUE_MCB Mcb = (PNONOPAQUE_MCB)OpaqueMcb;
+
+ ULONG Count;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "FsRtlNumberOfRunsInLargeMcb, Mcb = %08lx\n", Mcb );
+
+ ExAcquireFastMutex( Mcb->FastMutex );
+
+ Count = Mcb->PairCount;
+
+ ExReleaseFastMutex( Mcb->FastMutex );
+
+ DebugTrace(-1, Dbg, "FsRtlNumberOfRunsInLargeMcb -> %08lx\n", Count );
+
+ return Count;
+}
+
+
+BOOLEAN
+FsRtlGetNextLargeMcbEntry (
+ IN PLARGE_MCB OpaqueMcb,
+ IN ULONG RunIndex,
+ OUT PLONGLONG LargeVbn,
+ OUT PLONGLONG LargeLbn,
+ OUT PLONGLONG LargeSectorCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns to its caller the Vbn, Lbn, and SectorCount for
+ distinct runs mapped by an Mcb. Holes are counted as runs. For example,
+ to construct to print out all of the runs in a a file is:
+
+//. . for (i = 0; FsRtlGetNextLargeMcbEntry(Mcb,i,&Vbn,&Lbn,&Count); i++) {
+//
+//. . // print out vbn, lbn, and count
+//
+//. . }
+
+Arguments:
+
+ OpaqueMcb - Supplies the Mcb being examined.
+
+ RunIndex - Supplies the index of the run (zero based) to return to the
+ caller.
+
+ Vbn - Receives the starting Vbn of the returned run, or zero if the
+ run does not exist.
+
+ Lbn - Recieves the starting Lbn of the returned run, or zero if the
+ run does not exist.
+
+ SectorCount - Receives the number of sectors within the returned run,
+ or zero if the run does not exist.
+
+Return Value:
+
+ BOOLEAN - TRUE if the specified run (i.e., RunIndex) exists in the Mcb,
+ and FALSE otherwise. If FALSE is returned then the Vbn, Lbn, and
+ SectorCount parameters receive zero.
+
+--*/
+
+{
+ PNONOPAQUE_MCB Mcb = (PNONOPAQUE_MCB)OpaqueMcb;
+
+ BOOLEAN Result;
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "FsRtlGetNextLargeMcbEntry, Mcb = %08lx\n", Mcb );
+ DebugTrace( 0, Dbg, " RunIndex = %08lx\n", RunIndex );
+
+ ExAcquireFastMutex( Mcb->FastMutex );
+
+ try {
+
+ //
+ // Make sure the run index is within range
+ //
+
+ if (RunIndex >= Mcb->PairCount) {
+
+ try_return (Result = FALSE);
+ }
+
+ //
+ // Set the return variables
+ //
+
+ *((PULONG)LargeVbn) = StartingVbn(Mcb,RunIndex);
+ *((PULONG)LargeLbn) = StartingLbn(Mcb,RunIndex);
+ *((PULONG)LargeSectorCount) = SectorsWithinRun(Mcb,RunIndex);
+
+ Result = TRUE;
+
+ try_exit: NOTHING;
+ } finally {
+
+ ExReleaseFastMutex( Mcb->FastMutex );
+
+ DebugTrace(-1, Dbg, "FsRtlGetNextLargeMcbEntry -> %08lx\n", Result );
+ }
+
+ ((PLARGE_INTEGER)LargeVbn)->HighPart = (*((PULONG)LargeVbn) == UNUSED_LBN ? UNUSED_LBN : 0);
+ ((PLARGE_INTEGER)LargeLbn)->HighPart = (*((PULONG)LargeLbn) == UNUSED_LBN ? UNUSED_LBN : 0);
+ ((PLARGE_INTEGER)LargeSectorCount)->HighPart = 0;
+
+ return Result;
+}
+
+
+BOOLEAN
+FsRtlSplitLargeMcb (
+ IN PLARGE_MCB OpaqueMcb,
+ IN LONGLONG LargeVbn,
+ IN LONGLONG LargeAmount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is used to create a hole within an MCB, by shifting the
+ mapping of Vbns. All mappings above the input vbn are shifted by the
+ amount specified and while keeping their current lbn value. Pictorially
+ we have as input the following MCB
+
+ VBN : LargeVbn-1 LargeVbn N
+ +-----------------+------------------+
+ LBN : X Y
+
+ And after the split we have
+
+ VBN : LargeVbn-1 LargeVbn+Amount N+Amount
+ +-----------------+.............+---------------------------+
+ LBN : X UnusedLbn Y
+
+ When doing the split we have a few cases to consider. They are:
+
+ 1. The input Vbn is beyond the last run. In this case this operation
+ is a noop.
+
+ 2. The input Vbn is within or adjacent to a existing run of unused Lbns.
+ In this case we simply need to extend the size of the existing hole
+ and shift succeeding runs.
+
+ 3. The input Vbn is between two existing runs, including the an input vbn
+ value of zero. In this case we need to add a new entry for the hole
+ and shift succeeding runs.
+
+ 4. The input Vbn is within an existing run. In this case we need to add
+ two new entries to contain the split run and the hole.
+
+ If pool is not available to store the information this routine will raise a
+ status value indicating insufficient resources.
+
+Arguments:
+
+ OpaqueMcb - Supplies the Mcb in which to add the new mapping.
+
+ Vbn - Supplies the starting Vbn that is to be shifted.
+
+ Amount - Supplies the amount to shift by.
+
+Return Value:
+
+ BOOLEAN - TRUE if the mapping was successfully shifted, and FALSE otherwise.
+ If FALSE is returned then the Mcb is not changed.
+
+--*/
+
+{
+ PNONOPAQUE_MCB Mcb = (PNONOPAQUE_MCB)OpaqueMcb;
+
+ VBN Vbn = ((ULONG)LargeVbn);
+ ULONG Amount = ((ULONG)LargeAmount);
+
+ ULONG Index;
+
+ BOOLEAN Result;
+
+ ULONG i;
+
+ ASSERTMSG("LargeInteger not supported yet ", ((PLARGE_INTEGER)&LargeVbn)->HighPart == 0);
+ ASSERTMSG("LargeInteger not supported yet ", ((PLARGE_INTEGER)&LargeAmount)->HighPart == 0);
+
+ PAGED_CODE();
+
+ DebugTrace(+1, Dbg, "FsRtlSplitLargeMcb, Mcb = %08lx\n", Mcb );
+ DebugTrace( 0, Dbg, " Vbn = %08lx\n", Vbn );
+ DebugTrace( 0, Dbg, " Amount = %08lx\n", Amount );
+
+ ExAcquireFastMutex( Mcb->FastMutex );
+
+ try {
+
+ //
+ // First lookup the index for the entry that we are going to split.
+ // If we can't find the entry then there is nothing to split. This
+ // takes care of the case where the input vbn is beyond the last run
+ // in the mcb
+ //
+
+ if (!FsRtlFindLargeIndex( Mcb, Vbn, &Index)) {
+
+ try_return(Result = FALSE);
+ }
+
+ //
+ // Now check if the input Vbn is within a hole
+ //
+
+ if (StartingLbn(Mcb,Index) == UNUSED_LBN) {
+
+ //
+ // Before: --PreviousRun--||--IndexHole--||--FollowingRun--
+ // After: --PreviousRun--||----IndexHole----||--FollowingRun--
+ //
+ // In this case the vbn is somewhere within the hole and we
+ // simply need to added the amount of each existing run
+ // beyond the hole.
+ //
+
+ //
+ // In this case there is really nothing to do here because the
+ // ending code will already shift the runs by proper amount
+ // starting at index
+ //
+
+ NOTHING;
+
+ //
+ // Now check if the input vbn is between a hole and an existing run.
+ //
+
+ } else if ((StartingVbn(Mcb,Index) == Vbn) && (Index != 0) && (PreviousEndingLbn(Mcb,Index) == UNUSED_LBN)) {
+
+ //
+ // Before: --Hole--||--IndexRun--
+ // After: --Hole------||--IndexRun--
+ //
+ // In this case the vbn points to the start of the existing
+ // run and we need to do the split between the hole and the
+ // existing run by simply adding the amount to each existing
+ // run beyond the hole.
+ //
+
+ //
+ // In this case we need to decement the index by 1 and then
+ // fall to the bottom code which will do the shifting for us
+ //
+
+ Index -= 1;
+
+ //
+ // Now check if the input vbn is between two existing runs
+ //
+
+ } else if (StartingVbn(Mcb,Index) == Vbn) {
+
+ //
+ // Before: --PreviousRun--||--IndexRun--
+ // After: --PreviousRun--||--NewHole--||--IndexRun--
+ //
+ // Before: 0:|--IndexRun--
+ // After: 0:|--NewHole--||--IndexRun--
+ //
+ // In this case the vbn points to the start of an existing
+ // run and the preceeding is either a real run or the start
+ // of mapping pairs We simply add a new entry for the hole
+ // and shift succeeding runs.
+ //
+
+ FsRtlAddLargeEntry( Mcb, Index, 1 );
+
+ (Mcb->Mapping)[Index].Lbn = (LBN)UNUSED_LBN;
+ (Mcb->Mapping)[Index].NextVbn = Vbn + Amount;
+
+ Index += 1;
+
+ //
+ // Otherwise the input vbn is inside an existing run
+ //
+
+ } else {
+
+ //
+ // Before: --IndexRun--
+ // After: --SplitRun--||--NewHole--||--SplitRun--
+ //
+ // In this case the vbn points within an existing run
+ // we need to add two new extries for hole and split
+ // run and shift succeeding runs
+ //
+
+ FsRtlAddLargeEntry( Mcb, Index, 2 );
+
+ (Mcb->Mapping)[Index].Lbn = (Mcb->Mapping)[Index+2].Lbn;
+ (Mcb->Mapping)[Index].NextVbn = Vbn;
+
+ (Mcb->Mapping)[Index+1].Lbn = (LBN)UNUSED_LBN;
+ (Mcb->Mapping)[Index+1].NextVbn = Vbn + Amount;
+
+ (Mcb->Mapping)[Index+2].Lbn = (Mcb->Mapping)[Index+2].Lbn +
+ StartingVbn(Mcb, Index+1) -
+ StartingVbn(Mcb, Index);
+
+ Index += 2;
+
+ }
+
+ //
+ // At this point we have completed most of the work we now need to
+ // shift existing runs from the index to the end of the mappings
+ // by the specified amount
+ //
+
+ for (i = Index; i < Mcb->PairCount; i += 1) {
+
+ (Mcb->Mapping)[i].NextVbn += Amount;
+ }
+
+ Result = TRUE;
+
+ try_exit: NOTHING;
+ } finally {
+
+ ExReleaseFastMutex( Mcb->FastMutex );
+
+ DebugTrace(-1, Dbg, "FsRtlSplitLargeMcb -> %08lx\n", Result );
+ }
+
+ return Result;
+}
+
+
+//
+// Private support routine
+//
+
+VOID
+FsRtlRemoveMcbEntryPrivate (
+ IN PNONOPAQUE_MCB Mcb,
+ IN ULONG Vbn,
+ IN ULONG SectorCount
+ )
+
+/*++
+
+Routine Description:
+
+ This is the work routine for remove large mcb entry. It does the work
+ without taking out the mcb FastMutex.
+
+Arguments:
+
+ Mcb - Supplies the Mcb from which to remove the mapping.
+
+ Vbn - Supplies the starting Vbn of the mappings to remove.
+
+ SectorCount - Supplies the size of the mappings to remove (in sectors).
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Index;
+
+ PAGED_CODE();
+
+ //
+ // Do a quick test to see if we are wiping out the entire MCB.
+ //
+
+ if ((Vbn == 0) && (Mcb->PairCount > 0) && (SectorCount >= Mcb->Mapping[Mcb->PairCount-1].NextVbn)) {
+
+ Mcb->PairCount = 0;
+
+ return;
+ }
+
+ //
+ // While there is some more mapping to remove we'll continue
+ // with our main loop
+ //
+
+ while (SectorCount > 0) {
+
+ //
+ // Locate the mapping for the vbn
+ //
+
+ if (!FsRtlFindLargeIndex(Mcb, Vbn, &Index)) {
+
+ DebugTrace( 0, Dbg, "FsRtlRemoveLargeMcbEntry, Cannot remove an unmapped Vbn = %08lx\n", Vbn );
+
+ return;
+ }
+
+ //
+ // Now that we some something to remove the following cases must
+ // be considered
+ //
+
+ if ((StartingVbn(Mcb,Index) == Vbn) &&
+ (EndingVbn(Mcb,Index) < Vbn + SectorCount)) {
+
+ ULONG i;
+
+ //
+ // Removes the entire run
+ //
+
+ //
+ // Update the amount to remove
+ //
+
+ i = SectorsWithinRun(Mcb,Index);
+ Vbn += i;
+ SectorCount -= i;
+
+ //
+ // If already a hole then leave it alone
+ //
+
+ if (StartingLbn(Mcb,Index) == UNUSED_LBN) {
+
+ NOTHING;
+
+ //
+ // Test for last run
+ //
+
+ } else if (Index == Mcb->PairCount - 1) {
+
+ if ((PreviousEndingLbn(Mcb,Index) != UNUSED_LBN) ||
+ (Index == 0)) {
+
+ //
+ // Previous is not hole, index is last run
+ //
+ // --Previous--| Hole
+ //
+ // 0: Hole
+ //
+
+ DebugTrace( 0, Dbg, "Entire run, Previous not hole, index is last run\n", 0);
+
+ //
+ // Just remove this entry
+ //
+
+ FsRtlRemoveLargeEntry( Mcb, Index, 1);
+
+ } else {
+
+ //
+ // Previous is hole, index is last run
+ //
+ // --Hole--| Hole
+ //
+
+ DebugTrace( 0, Dbg, "Entire run, Previous hole, index is last run\n", 0);
+
+ //
+ // Just remove this entry, and preceding entry
+ //
+
+ FsRtlRemoveLargeEntry( Mcb, Index-1, 2);
+ }
+
+ } else if (((PreviousEndingLbn(Mcb,Index) != UNUSED_LBN) || (Index == 0)) &&
+ (NextStartingLbn(Mcb,Index) != UNUSED_LBN)) {
+
+ //
+ // Previous and following are not holes
+ //
+ // --Previous--| Hole |--Following--
+ //
+ // 0: Hole |--Following--
+ //
+
+ DebugTrace( 0, Dbg, "Entire run, Previous & Following not holes\n", 0);
+
+ //
+ // Make this index a hole
+ //
+
+ (Mcb->Mapping)[Index].Lbn = (LBN)UNUSED_LBN;
+
+ } else if (((PreviousEndingLbn(Mcb,Index) != UNUSED_LBN) || (Index == 0)) &&
+ (NextStartingLbn(Mcb,Index) == UNUSED_LBN)) {
+
+ //
+ // Following is hole
+ //
+ // --Previous--| Hole |--Hole--
+ //
+ // 0: Hole |--Hole--
+ //
+
+ DebugTrace( 0, Dbg, "Entire run, Following is hole\n", 0);
+
+ //
+ // Simply remove this entry
+ //
+
+ FsRtlRemoveLargeEntry( Mcb, Index, 1 );
+
+ } else if ((PreviousEndingLbn(Mcb,Index) == UNUSED_LBN) &&
+ (NextStartingLbn(Mcb,Index) != UNUSED_LBN)) {
+
+ //
+ // Previous is hole
+ //
+ // --Hole--| Hole |--Following--
+ //
+
+ DebugTrace( 0, Dbg, "Entire run, Previous is hole\n", 0);
+
+ //
+ // Mark current entry a hole
+ //
+
+ (Mcb->Mapping)[Index].Lbn = (LBN)UNUSED_LBN;
+
+ //
+ // Remove previous entry
+ //
+
+ FsRtlRemoveLargeEntry( Mcb, Index - 1, 1 );
+
+ } else {
+
+ //
+ // Previous and following are holes
+ //
+ // --Hole--| Hole |--Hole--
+ //
+
+ DebugTrace( 0, Dbg, "Entire run, Previous & following are holes\n", 0);
+
+ //
+ // Remove previous and this entry
+ //
+
+ FsRtlRemoveLargeEntry( Mcb, Index - 1, 2 );
+ }
+
+ } else if (StartingVbn(Mcb,Index) == Vbn) {
+
+ //
+ // Removes first part of run
+ //
+
+ //
+ // If already a hole then leave it alone
+ //
+
+ if (StartingLbn(Mcb,Index) == UNUSED_LBN) {
+
+ NOTHING;
+
+ } else if ((PreviousEndingLbn(Mcb,Index) != UNUSED_LBN) || (Index == 0)) {
+
+ //
+ // Previous is not hole
+ //
+ // --Previous--| Hole |--Index--||--Following--
+ //
+ // 0: Hole |--Index--||--Following--
+ //
+
+ DebugTrace( 0, Dbg, "1st part, Previous is not hole\n", 0);
+
+ //
+ // Make room for one more entry. The NextVbn field of the
+ // one we're shifting remains valid.
+ //
+
+ FsRtlAddLargeEntry( Mcb, Index, 1 );
+
+ //
+ // Set the hole
+ //
+
+ (Mcb->Mapping)[Index].Lbn = (LBN)UNUSED_LBN;
+ (Mcb->Mapping)[Index].NextVbn = Vbn + SectorCount;
+
+ //
+ // Set the new Lbn for the remaining run
+ //
+
+ (Mcb->Mapping)[Index+1].Lbn += SectorCount;
+
+ } else {
+
+ //
+ // Previous is hole
+ //
+ // --Hole--| Hole |--Index--||--Following--
+ //
+
+ DebugTrace( 0, Dbg, "1st part, Previous is hole\n", 0);
+
+ //
+ // Expand the preceding hole
+ //
+
+ (Mcb->Mapping)[Index-1].NextVbn += SectorCount;
+
+ //
+ // Set the new Lbn for the remaining run
+ //
+
+ (Mcb->Mapping)[Index].Lbn += SectorCount;
+ }
+
+ //
+ // Update the amount to remove
+ //
+
+ Vbn += SectorCount;
+ SectorCount = 0;
+
+ } else if (EndingVbn(Mcb,Index) < Vbn + SectorCount) {
+
+ ULONG AmountToRemove;
+
+ AmountToRemove = EndingVbn(Mcb,Index) - Vbn + 1;
+
+ //
+ // Removes last part of run
+ //
+
+ //
+ // If already a hole then leave it alone
+ //
+
+ if (StartingLbn(Mcb,Index) == UNUSED_LBN) {
+
+ NOTHING;
+
+ } else if (Index == Mcb->PairCount - 1) {
+
+ //
+ // Index is last run
+ //
+ // --Previous--||--Index--| Hole
+ //
+ // 0:|--Index--| Hole
+ //
+
+ DebugTrace( 0, Dbg, "last part, Index is last run\n", 0);
+
+ //
+ // Shrink back the size of the current index
+ //
+
+ (Mcb->Mapping)[Index].NextVbn -= AmountToRemove;
+
+ } else if (NextStartingLbn(Mcb,Index) == UNUSED_LBN) {
+
+ //
+ // Following is hole
+ //
+ // --Previous--||--Index--| Hole |--Hole--
+ //
+ // 0:|--Index--| Hole |--Hole--
+ //
+
+ DebugTrace( 0, Dbg, "last part, Following is hole\n", 0);
+
+ //
+ // Shrink back the size of the current index
+ //
+
+ (Mcb->Mapping)[Index].NextVbn -= AmountToRemove;
+
+ } else {
+
+ //
+ // Following is not hole
+ //
+ // --Previous--||--Index--| Hole |--Following--
+ //
+ //
+ // 0:|--Index--| Hole |--Following--
+ //
+
+ DebugTrace( 0, Dbg, "last part, Following is not hole\n", 0);
+
+ //
+ // Make room for one more entry. The NextVbn field of the
+ // one we're shifting remains valid.
+ //
+
+ FsRtlAddLargeEntry( Mcb, Index+1, 1 );
+
+ //
+ // Set the new hole
+ //
+
+ (Mcb->Mapping)[Index+1].Lbn = (LBN)UNUSED_LBN;
+ (Mcb->Mapping)[Index+1].NextVbn = (Mcb->Mapping)[Index].NextVbn;
+
+ //
+ // Shrink back the size of the current index
+ //
+
+ (Mcb->Mapping)[Index].NextVbn -= AmountToRemove;
+ }
+
+ //
+ // Update amount to remove
+ //
+
+ Vbn += AmountToRemove;
+ SectorCount -= AmountToRemove;
+
+ } else {
+
+ //
+ // If already a hole then leave it alone
+ //
+
+ if (StartingLbn(Mcb,Index) == UNUSED_LBN) {
+
+ NOTHING;
+
+ } else {
+
+ //
+ // Remove middle of run
+ //
+ // --Previous--||--Index--| Hole |--Index--||--Following--
+ //
+ // 0:|--Index--| Hole |--Index--||--Following--
+ //
+
+ DebugTrace( 0, Dbg, "Middle of run\n", 0);
+
+ //
+ // Make room for two more entries. The NextVbn field of the
+ // one we're shifting remains valid.
+ //
+
+ FsRtlAddLargeEntry( Mcb, Index, 2 );
+
+ //
+ // Set up the first remaining run
+ //
+
+ (Mcb->Mapping)[Index].Lbn = (Mcb->Mapping)[Index+2].Lbn;
+ (Mcb->Mapping)[Index].NextVbn = Vbn;
+
+ //
+ // Set up the hole
+ //
+
+ (Mcb->Mapping)[Index+1].Lbn = (LBN)UNUSED_LBN;
+ (Mcb->Mapping)[Index+1].NextVbn = Vbn + SectorCount;
+
+ //
+ // Set up the second remaining run
+ //
+
+ (Mcb->Mapping)[Index+2].Lbn += SectorsWithinRun(Mcb,Index) +
+ SectorsWithinRun(Mcb,Index+1);
+ }
+
+ //
+ // Update amount to remove
+ //
+
+ Vbn += SectorCount;
+ SectorCount = 0;
+ }
+ }
+
+ return;
+}
+
+
+//
+// Private routine
+//
+
+BOOLEAN
+FsRtlFindLargeIndex (
+ IN PNONOPAQUE_MCB Mcb,
+ IN VBN Vbn,
+ OUT PULONG Index
+ )
+
+/*++
+
+Routine Description:
+
+ This is a private routine that locates a mapping for a Vbn
+ in a given mapping array
+
+Arguments:
+
+ Mcb - Supplies the mapping array to examine
+
+ Vbn - Supplies the Vbn to look up
+
+ Index - Receives the index within the mapping array of the mapping
+ containing the Vbn. If none if found then the index is set to
+ PairCount.
+
+Return Value:
+
+ BOOLEAN - TRUE if Vbn is found and FALSE otherwise
+
+--*/
+
+{
+ LONG MinIndex;
+ LONG MaxIndex;
+ LONG MidIndex;
+
+ //
+ // We'll just do a binary search for the mapping entry. Min and max
+ // are our search boundaries
+ //
+
+ MinIndex = 0;
+ MaxIndex = Mcb->PairCount - 1;
+
+ while (MinIndex <= MaxIndex) {
+
+ //
+ // Compute the middle index to look at
+ //
+
+ MidIndex = ((MaxIndex + MinIndex) / 2);
+
+ //
+ // check if the Vbn is less than the mapping at the mid index
+ //
+
+ if (Vbn < StartingVbn(Mcb, MidIndex)) {
+
+ //
+ // Vbn is less than the middle index so we need to drop
+ // the max down
+ //
+
+ MaxIndex = MidIndex - 1;
+
+ //
+ // check if the Vbn is greater than the mapping at the mid index
+ //
+
+ } else if (Vbn > EndingVbn(Mcb, MidIndex)) {
+
+ //
+ // Vbn is greater than the middle index so we need to bring
+ // up the min
+ //
+
+ MinIndex = MidIndex + 1;
+
+ //
+ // Otherwise we've found the index containing the Vbn so set the
+ // index and return TRUE.
+ //
+
+ } else {
+
+ *Index = MidIndex;
+
+ return TRUE;
+ }
+ }
+
+ //
+ // A match wasn't found so set index to PairCount and return FALSE
+ //
+
+ *Index = Mcb->PairCount;
+
+ return FALSE;
+}
+
+
+//
+// Private Routine
+//
+
+VOID
+FsRtlAddLargeEntry (
+ IN PNONOPAQUE_MCB Mcb,
+ IN ULONG WhereToAddIndex,
+ IN ULONG AmountToAdd
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes a current Mcb and detemines if there is enough
+ room to add the new mapping entries. If there is not enough room
+ it reallocates a new mcb buffer and copies over the current mapping.
+ If also will spread out the current mappings to leave the specified
+ index slots in the mapping unfilled. For example, if WhereToAddIndex
+ is equal to the current pair count then we don't need to make a hole
+ in the mapping, but if the index is less than the current pair count
+ then we'll need to slide some of the mappings down to make room
+ at the specified index.
+
+Arguments:
+
+ Mcb - Supplies the mcb being checked and modified
+
+ WhereToAddIndex - Supplies the index of where the additional entries
+ need to be made
+
+ AmountToAdd - Supplies the number of additional entries needed in the
+ mcb
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PAGED_CODE();
+
+ //
+ // Check to see if the current buffer is large enough to hold
+ // the additional entries
+ //
+
+ if (Mcb->PairCount + AmountToAdd > Mcb->MaximumPairCount) {
+
+ ULONG NewMax;
+ PMAPPING Mapping;
+
+ //
+ // We need to allocate a new mapping so compute a new maximum pair
+ // count. We'll only be asked to grow by at most 2 at a time, so
+ // doubling will definitely make us large enough for the new amount.
+ // But we won't double without bounds we'll stop doubling if the
+ // pair count gets too high.
+ //
+
+ if (Mcb->MaximumPairCount < 2048) {
+
+ NewMax = Mcb->MaximumPairCount * 2;
+
+ } else {
+
+ NewMax = Mcb->MaximumPairCount + 2048;
+ }
+
+ Mapping = FsRtlAllocatePool( Mcb->PoolType, sizeof(MAPPING)*NewMax );
+
+ //**** RtlZeroMemory( Mapping, sizeof(MAPPING) * NewMax );
+
+ //
+ // Now copy over the old mapping to the new buffer
+ //
+
+ RtlCopyMemory( Mapping, Mcb->Mapping, sizeof(MAPPING) * Mcb->PairCount );
+
+ //
+ // Deallocate the old buffer
+ //
+
+ if ((Mcb->PoolType == PagedPool) && (Mcb->MaximumPairCount == INITIAL_MAXIMUM_PAIR_COUNT)) {
+
+ { PVOID t = Mcb->Mapping; FsRtlFreeFirstMapping( t ); }
+
+ } else {
+
+ ExFreePool( Mcb->Mapping );
+ }
+
+ //
+ // And set up the new buffer in the Mcb
+ //
+
+ Mcb->Mapping = Mapping;
+ Mcb->MaximumPairCount = NewMax;
+ }
+
+ //
+ // Now see if we need to shift some entries over according to the
+ // WhereToAddIndex value
+ //
+
+ if (WhereToAddIndex < Mcb->PairCount) {
+
+ RtlMoveMemory( &((Mcb->Mapping)[WhereToAddIndex + AmountToAdd]),
+ &((Mcb->Mapping)[WhereToAddIndex]),
+ (Mcb->PairCount - WhereToAddIndex) * sizeof(MAPPING) );
+ }
+
+ //
+ // Now zero out the new additions
+ //
+
+ //**** RtlZeroMemory( &((Mcb->Mapping)[WhereToAddIndex]), sizeof(MAPPING) * AmountToAdd );
+
+ //
+ // Now increment the PairCount
+ //
+
+ Mcb->PairCount += AmountToAdd;
+
+ //
+ // And return to our caller
+ //
+
+ return;
+}
+
+
+//
+// Private Routine
+//
+
+VOID
+FsRtlRemoveLargeEntry (
+ IN PNONOPAQUE_MCB Mcb,
+ IN ULONG WhereToRemoveIndex,
+ IN ULONG AmountToRemove
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes a current Mcb and removes one or more entries.
+
+Arguments:
+
+ Mcb - Supplies the mcb being checked and modified
+
+ WhereToRemoveIndex - Supplies the index of the entries to remove
+
+ AmountToRemove - Supplies the number of entries to remove
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PAGED_CODE();
+
+ //
+ // Check to see if we need to shift everything down because the
+ // entries to remove do not include the last entry in the mcb
+ //
+
+ if (WhereToRemoveIndex + AmountToRemove < Mcb->PairCount) {
+
+ RtlMoveMemory( &((Mcb->Mapping)[WhereToRemoveIndex]),
+ &((Mcb->Mapping)[WhereToRemoveIndex + AmountToRemove]),
+ (Mcb->PairCount - (WhereToRemoveIndex + AmountToRemove))
+ * sizeof(MAPPING) );
+ }
+
+ //
+ // Now zero out the entries beyond the part we just shifted down
+ //
+
+ //**** RtlZeroMemory( &((Mcb->Mapping)[Mcb->PairCount - AmountToRemove]), AmountToRemove * sizeof(MAPPING) );
+
+ //
+ // Now decrement the PairCount
+ //
+
+ Mcb->PairCount -= AmountToRemove;
+
+ //
+ // And return to our caller
+ //
+
+ return;
+}
+
+
+//
+// Private Routine
+//
+
+PVOID
+FsRtlAllocateFirstMapping(
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will if possible allocate the first mapping from either
+ a zone, a recent deallocated mapping, or pool.
+
+Arguments:
+
+Return Value:
+
+ The mapping.
+
+--*/
+
+{
+ KIRQL _SavedIrql;
+ PVOID Mapping;
+
+ ExAcquireSpinLock( &FsRtlStrucSupSpinLock, &_SavedIrql );
+
+ FsRtlNetFirstMapping += 1;
+
+ if (FsRtlFreeFirstMappingSize > 0) {
+ Mapping = FsRtlFreeFirstMappingArray[--FsRtlFreeFirstMappingSize];
+ ExReleaseSpinLock( &FsRtlStrucSupSpinLock, _SavedIrql );
+ } else {
+ ExReleaseSpinLock( &FsRtlStrucSupSpinLock, _SavedIrql );
+ Mapping = FsRtlAllocatePool( PagedPool, sizeof(MAPPING) * INITIAL_MAXIMUM_PAIR_COUNT );
+ }
+
+ return Mapping;
+}
+
+
+//
+// Private Routine
+//
+
+VOID
+FsRtlFreeFirstMapping(
+ IN PVOID Mapping
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will if possible allocate the first mapping from either
+ a zone, a recent deallocated mapping, or pool.
+
+Arguments:
+
+ Mapping - The mapping to either free to zone, put on the recent
+ deallocated list or free to pool.
+
+Return Value:
+
+ The mapping.
+
+--*/
+
+{
+ KIRQL _SavedIrql;
+
+ ExAcquireSpinLock( &FsRtlStrucSupSpinLock, &_SavedIrql );
+
+ FsRtlNetFirstMapping -= 1;
+
+ if (FsRtlFreeFirstMappingSize < FREE_FIRST_MAPPING_ARRAY_SIZE) {
+ FsRtlFreeFirstMappingArray[FsRtlFreeFirstMappingSize++] = Mapping;
+ ExReleaseSpinLock( &FsRtlStrucSupSpinLock, _SavedIrql );
+ } else {
+ ExReleaseSpinLock( &FsRtlStrucSupSpinLock, _SavedIrql );
+ ExFreePool( Mapping );
+ }
+}
+
+
+//
+// Private Routine
+//
+
+PFAST_MUTEX
+FsRtlAllocateFastMutex(
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will if possible allocate the FastMutex from either
+ a zone, a recent deallocated FastMutex, or pool.
+
+Arguments:
+
+Return Value:
+
+ The FastMutex.
+
+--*/
+
+{
+ KIRQL _SavedIrql;
+ PFAST_MUTEX FastMutex;
+
+ ExAcquireSpinLock( &FsRtlStrucSupSpinLock, &_SavedIrql );
+
+ FsRtlNetFastMutex += 1;
+
+ if (!ExIsFullZone(&FsRtlFastMutexZone)) {
+ FastMutex = ExAllocateFromZone(&FsRtlFastMutexZone);
+ ExReleaseSpinLock( &FsRtlStrucSupSpinLock, _SavedIrql );
+
+ } else if (FsRtlFreeFastMutexSize > 0) {
+ FastMutex = FsRtlFreeFastMutexArray[--FsRtlFreeFastMutexSize];
+ ExReleaseSpinLock( &FsRtlStrucSupSpinLock, _SavedIrql );
+
+ } else {
+ ExReleaseSpinLock( &FsRtlStrucSupSpinLock, _SavedIrql );
+ FastMutex = FsRtlAllocatePool( NonPagedPool, sizeof(FAST_MUTEX) );
+ }
+
+ return FastMutex;
+}
+
+
+//
+// Private Routine
+//
+
+VOID
+FsRtlFreeFastMutex (
+ IN PFAST_MUTEX FastMutex
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will if possible allocate the FastMutex from either
+ a zone, a recent deallocated FastMutexs, or pool.
+
+Arguments:
+
+ Mapping - The FastMutex to either free to zone, put on the recent
+ deallocated list or free to pool.
+
+Return Value:
+
+ The mapping.
+
+--*/
+
+{
+ KIRQL _SavedIrql;
+
+ ExAcquireSpinLock( &FsRtlStrucSupSpinLock, &_SavedIrql );
+
+ FsRtlNetFastMutex -= 1;
+
+ if (ExIsObjectInFirstZoneSegment(&FsRtlFastMutexZone, FastMutex)) {
+ ExFreeToZone(&FsRtlFastMutexZone, FastMutex);
+ ExReleaseSpinLock( &FsRtlStrucSupSpinLock, _SavedIrql );
+
+ } else if (FsRtlFreeFastMutexSize < FREE_FAST_MUTEX_ARRAY_SIZE) {
+ FsRtlFreeFastMutexArray[FsRtlFreeFastMutexSize++] = FastMutex;
+ ExReleaseSpinLock( &FsRtlStrucSupSpinLock, _SavedIrql );
+
+ } else {
+ ExReleaseSpinLock( &FsRtlStrucSupSpinLock, _SavedIrql );
+ ExFreePool( FastMutex );
+ }
+}
+
+
diff --git a/private/utils/untfs/src/logfile.cxx b/private/utils/untfs/src/logfile.cxx
new file mode 100644
index 000000000..02b009632
--- /dev/null
+++ b/private/utils/untfs/src/logfile.cxx
@@ -0,0 +1,859 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ logfile.cxx
+
+Abstract:
+
+ This module contains the member function definitions for
+ the NTFS_LOG_FILE class.
+
+Author:
+
+ Bill McJohn (billmc) 05-May-1992
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "untfs.hxx"
+
+#include "ifssys.hxx"
+#include "drive.hxx"
+#include "attrib.hxx"
+#include "logfile.hxx"
+
+#include "message.hxx"
+#include "rtmsg.h"
+
+DEFINE_EXPORTED_CONSTRUCTOR( NTFS_LOG_FILE, NTFS_FILE_RECORD_SEGMENT, UNTFS_EXPORT );
+
+//
+// These constants are used to determine the default log file size.
+//
+
+#define DefaultLogFileProportion 100 /* 1% of volume size */
+#define MaximumLogFileSize MAXULONG /* ~ 4 GB */
+#define MaximumInitialLogFileSize 0x400000 /* 4 MB */
+#define MinimumLogFileSize 0x200000 /* 2 MB */
+#define LogFileAlignmentMask 0x3FFF
+
+VOID
+NTFS_LOG_FILE::Construct(
+ )
+/*++
+
+Routine Description:
+
+ Worker function for the constructor.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+}
+
+UNTFS_EXPORT
+NTFS_LOG_FILE::~NTFS_LOG_FILE(
+ )
+{
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_LOG_FILE::Initialize(
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft
+ )
+/*++
+
+Routine Description:
+
+ This method initializes the log file object.
+
+Arguments:
+
+ Mft -- Supplies the volume MasterFileTable.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ return( NTFS_FILE_RECORD_SEGMENT::Initialize( LOG_FILE_NUMBER,
+ Mft ) );
+
+}
+
+
+
+BOOLEAN
+NTFS_LOG_FILE::Create(
+ IN PCSTANDARD_INFORMATION StandardInformation,
+ IN ULONG InitialSize,
+ IN OUT PNTFS_BITMAP VolumeBitmap
+ )
+/*++
+
+Routine Description:
+
+ This method creates the Log File. It allocates space for
+ the $DATA attribute, fills it with LogFileFillCharacter
+ (defined in logfile.hxx).
+
+ Note that filling the log file with LogFileFillCharacter
+ also sets the signature to LOG_FILE_SIGNATURE_CREATED.
+
+Arguments:
+
+ StandardInformation -- Supplies the standard file information.
+ InitialSize -- Supplies the initial size of the $DATA
+ attribute. If the client passes in
+ zero, this routine will choose a default
+ size.
+ VolumeBitmap -- Supplies the volume bitmap.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ // If the client passed in zero for initial size, calculate
+ // the default initial size.
+ //
+ if( InitialSize == 0 ) {
+
+ InitialSize = QueryDefaultSize( GetDrive(), QueryVolumeSectors() );
+ }
+
+ // Create the FRS and add the data attribute.
+ //
+ if( !NTFS_FILE_RECORD_SEGMENT::Create( StandardInformation ) ||
+ !CreateDataAttribute( InitialSize, VolumeBitmap ) ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_LOG_FILE::CreateDataAttribute(
+ IN ULONG InitialSize OPTIONAL,
+ IN OUT PNTFS_BITMAP VolumeBitmap
+ )
+/*++
+
+Routine Description:
+
+ This methods creates the log file's $DATA attribute.
+
+Arguments:
+
+ InitialSize -- Supplies the initial size of the $DATA
+ attribute. If the client passes in
+ zero, this routine will choose a default
+ size.
+ VolumeBitmap -- Supplies the volume bitmap.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ ULONG ClusterSize, ClustersInData;
+
+ // If the client passed in zero for initial size, calculate
+ // the default initial size.
+ //
+ if( InitialSize == 0 ) {
+
+ InitialSize = QueryDefaultSize( GetDrive(), QueryVolumeSectors() );
+ }
+
+ // Make sure that the file size is a multiple of cluster size:
+ //
+ ClusterSize = QueryClusterFactor() * GetDrive()->QuerySectorSize();
+
+ if( InitialSize % ClusterSize ) {
+
+ ClustersInData = InitialSize / ClusterSize + 1;
+ InitialSize = ClustersInData * ClusterSize;
+ }
+
+ // Add the data attribute.
+ //
+ return( AddDataAttribute( InitialSize,
+ VolumeBitmap,
+ TRUE,
+ LogFileFillCharacter ) );
+}
+
+
+BOOLEAN
+NTFS_LOG_FILE::MarkVolumeChecked(
+ )
+/*++
+
+Routine Description:
+
+ This method sets the signature in the log file to indicate
+ that the volume has been checked. This signature supports
+ version 1.0 logfiles--ie. does not write the signature at
+ the beginning of the second page, and does not record the
+ greatest LSN.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ LSN NullLsn;
+
+ NullLsn.LowPart = 0;
+ NullLsn.HighPart = 0;
+
+ return( MarkVolumeChecked( FALSE, NullLsn ) );
+}
+
+
+
+BOOLEAN
+NTFS_LOG_FILE::MarkVolumeChecked(
+ BOOLEAN WriteSecondPage,
+ LSN GreatestLsn
+ )
+/*++
+
+Routine Description:
+
+ This method sets the signature in the log file to indicate
+ that the volume has been checked.
+
+Arguments:
+
+ WriteSecondPage -- Supplies a flag which, if TRUE, indicates
+ that the checked signature should also be
+ written at the beginning of the second page
+ of the file, and the greatest LSN on the
+ volume should be recorded.
+
+ GreatestLsn -- Supplies the greatest LSN encountered on
+ the volume. Ignored if WriteSecondPage is
+ FALSE.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ NTFS_ATTRIBUTE DataAttribute;
+ UCHAR Signature[LogFileSignatureLength];
+ LSN SignatureAndLsn[2];
+ ULONG BytesTransferred;
+ BOOLEAN Error;
+ ULONG i, PageSize;
+
+ // Fetch the data attribute:
+ //
+ if( !QueryAttribute( &DataAttribute, &Error, $DATA ) ) {
+
+ return FALSE;
+ }
+
+ // If the data attribute is resident, the volume is corrupt:
+ //
+ if( DataAttribute.IsResident() ) {
+
+ DbgPrint( "UNTFS: Log File $DATA attribute is resident.\n" );
+ return FALSE;
+ }
+
+ // Read the old signature--it's at offset zero in the $DATA
+ // attribute, with a length of LogFileSignatureLength bytes.
+ //
+ if( !DataAttribute.Read( Signature,
+ 0,
+ LogFileSignatureLength,
+ &BytesTransferred ) ||
+ BytesTransferred != LogFileSignatureLength ) {
+
+ DbgPrint( "UNTFS: Can't read log file signature.\n" );
+ return FALSE;
+ }
+
+ // If the signature is LOG_FILE_SIGNATURE_CREATED,
+ // do nothing.
+ //
+ if( memcmp( LOG_FILE_SIGNATURE_CREATED,
+ Signature,
+ LogFileSignatureLength ) == 0 ) {
+
+ return TRUE;
+ }
+
+ if( !WriteSecondPage ) {
+
+ // The client just wants the first signature.
+ //
+ memcpy( Signature,
+ LOG_FILE_SIGNATURE_CHECKED,
+ LogFileSignatureLength );
+
+ if( !DataAttribute.Write( Signature,
+ 0,
+ LogFileSignatureLength,
+ &BytesTransferred,
+ NULL ) ||
+ BytesTransferred != LogFileSignatureLength ) {
+
+ return FALSE;
+ }
+
+ } else {
+
+ // The client wants us to write the signature and LSN at
+ // the beginning of the first two pages.
+ //
+ PageSize = IFS_SYSTEM::QueryPageSize();
+
+ if( PageSize == 0 ||
+ DataAttribute.QueryValidDataLength() <
+ PageSize + sizeof( SignatureAndLsn ) ) {
+
+ return FALSE;
+ }
+
+ memset( SignatureAndLsn, 0, sizeof(SignatureAndLsn) );
+
+ memcpy( SignatureAndLsn,
+ LOG_FILE_SIGNATURE_CHECKED,
+ LogFileSignatureLength );
+
+ SignatureAndLsn[1] = GreatestLsn;
+
+ for( i = 0; i < 2; i++ ) {
+
+ if( !DataAttribute.Write( SignatureAndLsn,
+ PageSize * i,
+ sizeof( SignatureAndLsn ),
+ &BytesTransferred,
+ NULL ) ||
+ BytesTransferred != sizeof( SignatureAndLsn ) ) {
+
+ return FALSE;
+ }
+ }
+ }
+
+ // Since we didn't modify the storage of the attribute, we don't
+ // need to save it.
+ //
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_LOG_FILE::Reset(
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This method resets the Log File by filling it with
+ the LogFileFillCharacter (0xFF).
+
+Arguments:
+
+ Message -- Supplies an outlet for messages.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+ Note that, since the Log File's $DATA attribute is always
+ non-resident and is never sparse, resetting the log file
+ does not change the data attribute's Attribute Record or
+ the Log File's File Record Segment
+
+--*/
+{
+ NTFS_ATTRIBUTE DataAttribute;
+ BOOLEAN Error;
+
+ Message->Set( MSG_CHK_NTFS_RESETTING_LOG_FILE );
+ Message->Display( "" );
+
+ if( !QueryAttribute( &DataAttribute, &Error, $DATA ) ||
+ !DataAttribute.Fill( 0, LogFileFillCharacter ) ) {
+
+ Message->Set( MSG_CHK_NO_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+NTFS_LOG_FILE::Resize(
+ IN BIG_INT NewSize,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN BOOLEAN GetWhatYouCan,
+ OUT PBOOLEAN Changed,
+ OUT PBOOLEAN LogFileGrew,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This method resizes an existing log file. It does not change
+ the value of the remaining contents.
+
+Arguments:
+
+ NewSize -- Supplies the new size of the log file's data
+ attribute, in bytes. Zero means resize to the
+ default size.
+ VolumeBitmap -- Supplies the bitmap for the volume on which
+ the log file resides.
+ GetWhatYouCan -- Supplies a flag that indicates the method
+ should allocate as much of the requested
+ space as possible; if this value is FALSE,
+ this method will fail if it cannot make the
+ log file the requested size.
+ Changed -- Receives TRUE if the log file's size was changed
+ by this operation.
+ LogFileGrew -- Receives TRUE if the log file was made larger
+ by this operation.
+ Message -- Supplies an outlet for messages.
+
+--*/
+{
+ NTFS_ATTRIBUTE DataAttribute;
+ BIG_INT OldSize;
+ BOOLEAN Error;
+
+ if (NewSize == 0) {
+
+ NewSize = QueryDefaultSize( GetDrive(), QueryVolumeSectors() );
+ }
+
+ if (!QueryAttribute( &DataAttribute, &Error, $DATA )) {
+
+ return FALSE;
+ }
+
+ if (NewSize == DataAttribute.QueryValueLength()) {
+
+ *Changed = FALSE;
+ return TRUE;
+ }
+
+ Message->Set( MSG_CHK_NTFS_RESIZING_LOG_FILE );
+ Message->Display( "" );
+
+ OldSize = DataAttribute.QueryValueLength();
+
+ *LogFileGrew = (NewSize > OldSize);
+
+ if( !DataAttribute.Resize( NewSize, VolumeBitmap ) ||
+ !DataAttribute.Fill( OldSize, LogFileFillCharacter ) ||
+ !DataAttribute.InsertIntoFile( this, VolumeBitmap ) ) {
+
+ *Changed = FALSE;
+ return FALSE;
+ }
+
+ *Changed = TRUE;
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_LOG_FILE::VerifyAndFix(
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNTFS_INDEX_TREE RootIndex,
+ IN OUT PNTFS_CHKDSK_REPORT ChkdskReport,
+ IN FIX_LEVEL FixLevel,
+ IN BOOLEAN Resize,
+ IN ULONG LogFileSize,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine ensures the validity of the log file; it should have
+ a valid file name and standard information, and its size should be
+ within reasonable limits.
+
+Arguments:
+
+ VolumeBitmap - Supplies the volume bitmap.
+ RootIndex - Supplies the root index.
+ FixLevel - Supplies the fix up level.
+ Resize - Supplies a flag indicating whether the log file
+ should be resized.
+ LogFileSize - If Resize is set, then LogFileSize supplies the
+ new size of the logfile. If zero, the logfile will be
+ resized to the default size.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_ATTRIBUTE data_attribute;
+ BIG_INT old_size;
+ BOOLEAN error, has_external;
+ ULONG default_size, max_size;
+
+
+ // The logfile should not have an attribute list, and the data
+ // attribute should be non-resident and of a reasonable size.
+ //
+
+ error = FALSE;
+ has_external = FALSE;
+
+ if (QueryAttribute(&data_attribute, &error, $DATA) &&
+ !data_attribute.IsResident()) {
+
+ // If the log file has an attribute list, resize the
+ // data attribute to zero and recreate, it to force
+ // it to be non-external.
+ //
+
+ if (IsAttributePresent($ATTRIBUTE_LIST, NULL, TRUE)) {
+
+ has_external = TRUE;
+ Resize = TRUE;
+
+ if (FixLevel != CheckOnly &&
+ !data_attribute.Resize(0, VolumeBitmap)) {
+
+ // The log file is corrupt, and we can't fix it.
+ //
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_LOG_FILE);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ default_size = QueryDefaultSize(GetDrive(), QueryVolumeSectors());
+ max_size = QueryMaximumSize(GetDrive(), QueryVolumeSectors());
+
+ if (!Resize)
+ LogFileSize = 0;
+
+ if (Resize ||
+ data_attribute.QueryValueLength() < MinimumLogFileSize ||
+ data_attribute.QueryValueLength() > max_size) {
+
+ // The data attribute's size is out-of-bounds. Resize it to
+ // the default size.
+ //
+
+ Message->Set(MSG_CHK_NTFS_RESIZING_LOG_FILE);
+ Message->Display();
+
+ if (FixLevel != CheckOnly) {
+
+ old_size = data_attribute.QueryValueLength();
+
+ if (!data_attribute.Resize(LogFileSize == 0 ? default_size : LogFileSize,
+ VolumeBitmap) ||
+ !data_attribute.Fill(old_size, LogFileFillCharacter) ||
+ !data_attribute.InsertIntoFile(this, VolumeBitmap) ||
+ !Flush(VolumeBitmap, RootIndex)) {
+
+ if (has_external) {
+
+ // The log file is corrupt, and we can't fix it.
+ //
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_LOG_FILE);
+ Message->Display();
+ return FALSE;
+
+ } else {
+
+ // Print a warning message, but still return success.
+ //
+
+ Message->Set(MSG_CHK_NTFS_RESIZING_LOG_FILE_FAILED);
+ Message->Display();
+ }
+ }
+ }
+ }
+
+ ChkdskReport->BytesLogFile = data_attribute.QueryValueLength();
+ return TRUE;
+ }
+
+ Message->Set(MSG_CHK_NTFS_CORRECTING_LOG_FILE);
+ Message->Display();
+
+ if (error) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+
+ // Recreate the $DATA attribute.
+ //
+
+ if (FixLevel != CheckOnly) {
+
+ if (!CreateDataAttribute(0, VolumeBitmap) ||
+ !Flush(VolumeBitmap, RootIndex)) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_LOG_FILE);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ if (QueryAttribute(&data_attribute, &error, $DATA)) {
+
+ ChkdskReport->BytesLogFile = data_attribute.QueryValueLength();
+ } else {
+
+ ChkdskReport->BytesLogFile = 0;
+ }
+
+ return TRUE;
+}
+
+ULONG
+NTFS_LOG_FILE::QueryDefaultSize(
+ IN PCDP_DRIVE Drive,
+ IN BIG_INT VolumeSectors
+ )
+/*++
+
+Routine Description:
+
+ This method returns the appropriate default log file size
+ for the specified drive.
+
+Arguments:
+
+ Drive - Supplies the drive under consideration.
+ VolumeSectors - Supplies the number of volume sectors.
+
+Return Value:
+
+ The appropriate default log file size for the drive.
+
+--*/
+{
+ ULONG InitialSize;
+
+ if (VolumeSectors.GetHighPart() != 0) {
+
+ InitialSize = MaximumInitialLogFileSize;
+
+ } else {
+
+ InitialSize = (VolumeSectors*
+ Drive->QuerySectorSize()/
+ DefaultLogFileProportion).GetLowPart();
+
+ if (InitialSize < MinimumLogFileSize) {
+
+ InitialSize = MinimumLogFileSize;
+
+ } else if (InitialSize > MaximumInitialLogFileSize) {
+
+ InitialSize = MaximumInitialLogFileSize;
+ }
+
+ InitialSize = (InitialSize + LogFileAlignmentMask) & (~LogFileAlignmentMask);
+ }
+
+ return InitialSize;
+}
+
+ULONG
+NTFS_LOG_FILE::QueryMinimumSize(
+ IN PCDP_DRIVE Drive,
+ IN BIG_INT VolumeSectors
+ )
+/*++
+
+Routine Description:
+
+ This method returns the minimum log file size
+ for the specified drive.
+
+Arguments:
+
+ Drive - Supplies the drive under consideration.
+ VolumeSectors - Supplies the number of volume sectors.
+
+Return Value:
+
+ The minimum log file size for the drive.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(Drive);
+ UNREFERENCED_PARAMETER(VolumeSectors);
+
+ return MinimumLogFileSize;
+}
+
+ULONG
+NTFS_LOG_FILE::QueryMaximumSize(
+ IN PCDP_DRIVE Drive,
+ IN BIG_INT VolumeSectors
+ )
+/*++
+
+Routine Description:
+
+ This method returns the maximum log file size
+ for the specified drive.
+
+Arguments:
+
+ Drive - Supplies the drive under consideration.
+ VolumeSectors - Supplies the number of volume sectors.
+
+Return Value:
+
+ The maximum log file size for the drive.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(Drive);
+ UNREFERENCED_PARAMETER(VolumeSectors);
+
+ return MaximumLogFileSize;
+}
+
+
+BOOLEAN
+NTFS_LOG_FILE::EnsureCleanShutdown(
+ )
+/*++
+
+Routine Description:
+
+ This method looks at the logfile to verify that the volume
+ was shut down cleanly. If we can't read the logfile well
+ enough to say for sure, we assume that it was not shut down
+ cleanly.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE - The volume was shut down cleanly.
+ FALSE - The volume was not shut down cleanly.
+
+--*/
+{
+ NTFS_ATTRIBUTE attrib;
+ BOOLEAN error;
+ ULONG nbyte;
+ PLFS_RESTART_PAGE_HEADER header;
+ PLFS_RESTART_AREA restarea;
+ PBYTE buf;
+ BOOLEAN r = TRUE;
+
+ // Read the logfile contents to make sure the volume was shut
+ // down cleanly. If it wasn't generate an error message for
+ // the user and bail. Also generate an error if the logfile's
+ // data isn't big enough to contain an indication of whether it
+ // was cleanly shut down or not.
+ //
+
+ if (!QueryAttribute(&attrib, &error, $DATA)) {
+
+ DebugPrintf("Could not query logfile data\n");
+ return FALSE;
+ }
+
+ if (attrib.QueryValueLength() < IFS_SYSTEM::QueryPageSize()) {
+
+ DebugPrintf("LogFile too small to hold restart area\n");
+ return FALSE;
+ }
+
+ if (NULL == (buf = NEW BYTE[IFS_SYSTEM::QueryPageSize()])) {
+
+ return FALSE;
+ }
+
+ if (!attrib.Read(buf, 0, IFS_SYSTEM::QueryPageSize(), &nbyte) ||
+ nbyte != IFS_SYSTEM::QueryPageSize()) {
+
+ delete[] buf;
+ return FALSE;
+ }
+
+ header = PLFS_RESTART_PAGE_HEADER(buf);
+
+ if (0xffff == header->RestartOffset) {
+
+ // This volume is probably newly formatted.
+ //
+
+ delete[] buf;
+ return TRUE;
+ }
+
+ restarea = PLFS_RESTART_AREA(buf + header->RestartOffset);
+
+ if (restarea->ClientInUseList != 0xffff) {
+ r = FALSE;
+ }
+
+ delete[] buf;
+
+ return r;
+}
diff --git a/private/utils/untfs/src/makefile b/private/utils/untfs/src/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/untfs/src/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/untfs/src/makefile.inc b/private/utils/untfs/src/makefile.inc
new file mode 100644
index 000000000..b1477410c
--- /dev/null
+++ b/private/utils/untfs/src/makefile.inc
@@ -0,0 +1,14 @@
+{}.cxx{obj\i386\}.obj:
+ $(386_COMPILER) -Fo$@ $(MAKEDIR)\$(<F)
+
+{}.cxx{obj\mips\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClMips $< " $(C_COMPILER) "
+ @$(C_COMPILER) -Fo$@ $(MAKEDIR)\$<
+
+{}.cxx{obj\alpha\}.obj:
+ @-erase $@ >nul 2>&1
+ @echo ClAlpha $< " $(ALPHA_COMPILER) "
+ @$(ALPHA_COMPILER) -Fo$@ $(MAKEDIR)\$<
+
+dummy:
diff --git a/private/utils/untfs/src/mft.cxx b/private/utils/untfs/src/mft.cxx
new file mode 100644
index 000000000..3a782a281
--- /dev/null
+++ b/private/utils/untfs/src/mft.cxx
@@ -0,0 +1,408 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "untfs.hxx"
+
+
+#include "mft.hxx"
+
+#include "attrib.hxx"
+#include "drive.hxx"
+#include "frsstruc.hxx"
+#include "hmem.hxx"
+#include "numset.hxx"
+
+
+
+
+DEFINE_CONSTRUCTOR( NTFS_MASTER_FILE_TABLE, OBJECT );
+
+NTFS_MASTER_FILE_TABLE::~NTFS_MASTER_FILE_TABLE(
+ )
+{
+ Destroy();
+}
+
+
+VOID
+NTFS_MASTER_FILE_TABLE::Construct(
+ )
+/*++
+
+Routine Description:
+
+ Worker function for the construtor.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _DataAttribute = NULL;
+ _MftBitmap = NULL;
+ _VolumeBitmap = NULL;
+ _BytesPerFrs = 0;
+ _ClusterFactor = 0;
+ _VolumeSectors = 0;
+ _MethodsEnabled = FALSE;
+ _ReadOnly = FALSE;
+}
+
+
+VOID
+NTFS_MASTER_FILE_TABLE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Clean up an NTFS_MASTER_FILE_TABLE object in preparation for
+ destruction or reinitialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _DataAttribute = NULL;
+ _MftBitmap = NULL;
+ _VolumeBitmap = NULL;
+ _BytesPerFrs = 0;
+ _ClusterFactor = 0;
+ _VolumeSectors = 0;
+ _MethodsEnabled = FALSE;
+ _ReadOnly = FALSE;
+}
+
+
+BOOLEAN
+NTFS_MASTER_FILE_TABLE::Initialize(
+ IN OUT PNTFS_ATTRIBUTE DataAttribute,
+ IN OUT PNTFS_BITMAP MftBitmap,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNTFS_UPCASE_TABLE UpcaseTable,
+ IN ULONG ClusterFactor,
+ IN ULONG FrsSize,
+ IN ULONG SectorSize,
+ IN BIG_INT VolumeSectors,
+ IN BOOLEAN ReadOnly
+ )
+/*++
+
+Routine Description:
+
+ Initialize an NTFS_MASTER_FILE_TABLE object.
+
+Arguments:
+
+ DataAttribute - Supplies the DATA attribute for the MFT.
+ MftBitmap - Supplies the MFT Bitmap for the MFT.
+ VolumeBitmap - Suppleis the volume bitmap.
+ UpcaseTable - Supplies the volume bitmap.
+ ClusterFactor - Supplies the number of sectors per cluster.
+ FrsSize - Supplies the number of bytes per FRS.
+ SectorSize - Supplies the number of bytes per sector.
+ VolumeSectors - Supplies the number of volume sectors.
+ ReadOnly - Supplies whether or not this class is read only.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ Unless the Upcase table is supplied, FRS's initialized with this
+ MFT will not be able to manipulate named attributes until the
+ upcase table is set.
+
+--*/
+{
+ Destroy();
+
+ DebugAssert(DataAttribute);
+ DebugAssert(MftBitmap);
+ DebugAssert(ClusterFactor);
+ DebugAssert(FrsSize);
+ DebugAssert(SectorSize);
+
+ _DataAttribute = DataAttribute;
+ _MftBitmap = MftBitmap;
+ _VolumeBitmap = VolumeBitmap;
+ _UpcaseTable = UpcaseTable;
+ _ClusterFactor = ClusterFactor;
+ _BytesPerFrs = FrsSize;
+ _VolumeSectors = VolumeSectors;
+ _MethodsEnabled = TRUE;
+ _ReadOnly = ReadOnly;
+ _SectorSize = SectorSize;
+
+ return TRUE;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_MASTER_FILE_TABLE::AllocateFileRecordSegment(
+ OUT PVCN FileNumber,
+ IN BOOLEAN IsMft
+ )
+/*++
+
+Routine Description:
+
+ Allocate a File Record Segment from the Master File Table. If the
+ allocation is being done for a user file, we make sure that the frs
+ doesn't come from the first cluster of the mft's allocation.
+
+Arguments:
+
+ FileNumber -- Returns the file number of the allocated segment.
+ IsMft -- supplies a flag which indicates, if TRUE, that
+ the allocation is being made on behalf of the
+ MFT itself.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ Any bad clusters discovered by this routine are added to the volume
+ bitmap but not added to the bad clusters file.
+
+--*/
+{
+ VCN vcn, reserved_vcn;
+ BIG_INT run_length;
+ HMEM hmem;
+ NTFS_FRS_STRUCTURE frs;
+ NUMBER_SET bad_cluster_list;
+ BOOLEAN reserve_allocated;
+ ULONG cluster_size;
+
+ //
+ // This should really be a VCN instead of a LARGE_INTEGER, but the
+ // VCN causes the compiler to insert a reference to atexit(), which
+ // we want to avoid. -mjb.
+ //
+
+ STATIC LARGE_INTEGER LastAllocatedVcn;
+
+ DebugAssert(_MftBitmap);
+
+ if (!_MethodsEnabled) {
+ return FALSE;
+ }
+
+ cluster_size = QueryClusterFactor() * _SectorSize;
+
+ if (LastAllocatedVcn * QueryFrsSize() < cluster_size) {
+
+ LastAllocatedVcn.QuadPart = cluster_size / QueryFrsSize();
+ }
+
+ if( IsMft ) {
+
+ // If the MFT has asked for a sector to be allocated,
+ // we can't grow the MFT (since we're in the process
+ // of saving it). However, the reservation scheme
+ // means that if we have allocated any FRS's to
+ // clients other than the MFT itself, there will be
+ // a free one in the bitmap, so we can just return
+ // it.
+ //
+ return _MftBitmap->AllocateClusters(1, 1, FileNumber, 1);
+ }
+
+
+ // Grab a reserved VCN for the MFT.
+ //
+ reserve_allocated = _MftBitmap->AllocateClusters(1, 1, &reserved_vcn, 1);
+
+
+ if (reserve_allocated &&
+ _MftBitmap->AllocateClusters(LastAllocatedVcn, 1, FileNumber, 1)) {
+
+ LastAllocatedVcn = FileNumber->GetLargeInteger();
+ _MftBitmap->SetFree( reserved_vcn, 1 );
+ return TRUE;
+ }
+
+ // Grow the data attribute (and the MFT Bitmap) to
+ // include another File Record Segment.
+ //
+ if( !Extend(8) ) {
+
+ return FALSE;
+ }
+
+ // If we didn't get a reserved vcn before, get it now.
+ //
+ if( !reserve_allocated &&
+ !_MftBitmap->AllocateClusters(1, 1, &reserved_vcn, 1) ) {
+
+ return FALSE;
+ }
+
+ // And now allocate the FRS we will return to the client.
+ //
+ if (!_MftBitmap->AllocateClusters(LastAllocatedVcn, 1, FileNumber, 1)) {
+
+ return FALSE;
+ }
+
+
+ // Now read in the new FRS to make sure that it is good.
+ // Since we won't be manipulating any named attributes, we can
+ // pass in NULL for the upcase table.
+
+ if (hmem.Initialize() &&
+ bad_cluster_list.Initialize() &&
+ frs.Initialize(&hmem, _DataAttribute, *FileNumber,
+ QueryClusterFactor(),
+ QueryVolumeSectors(),
+ QueryFrsSize(),
+ NULL)) {
+
+ if (!frs.Read()) {
+
+ vcn = (*FileNumber*QueryFrsSize() + (cluster_size - 1))/cluster_size;
+
+ run_length = (QueryFrsSize() + (cluster_size - 1))/cluster_size;
+
+ if (!_VolumeBitmap ||
+ !_DataAttribute->Hotfix(vcn, run_length, _VolumeBitmap,
+ &bad_cluster_list)) {
+
+ return FALSE;
+ }
+ }
+ }
+
+ // Free the reserved FRS and return success.
+ //
+ _MftBitmap->SetFree( reserved_vcn, 1 );
+ LastAllocatedVcn = FileNumber->GetLargeInteger();
+ return TRUE;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_MASTER_FILE_TABLE::Extend(
+ IN ULONG NumberOfSegmentsToAdd
+ )
+/*++
+
+Routine Description:
+
+ This method grows the Master File Table. It increases the
+ size of the Data attribute (to hold more File Record Segments)
+ and increases the size of the MFT Bitmap to match.
+
+Arguments:
+
+ NumberOfSegmentsToAdd -- supplies the number of new File Record
+ Segments to add to the Master File Table.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ BIG_INT OldAllocatedLength, NumberOfSegments;
+ ULONG BytesToAdd;
+
+ DebugAssert(_MftBitmap);
+ DebugAssert(_DataAttribute);
+
+ if (!_MethodsEnabled || !_VolumeBitmap) {
+ return FALSE;
+ }
+
+ // Find out how big it already is, and how much bigger
+ // it needs to be.
+
+ OldAllocatedLength = _DataAttribute->QueryAllocatedLength();
+
+ BytesToAdd = NumberOfSegmentsToAdd * _BytesPerFrs;
+
+ // Resize the attribute. Note that if Resize fails, it
+ // leaves the attribute unaltered.
+ //
+ if (!_DataAttribute->Resize( OldAllocatedLength + BytesToAdd,
+ _VolumeBitmap )) {
+
+ return FALSE;
+ }
+
+ // If the MFT is not operating in read-only mode, fill the
+ // new space with zeroes.
+ //
+ if (!_ReadOnly && !_DataAttribute->Fill( OldAllocatedLength, 0 ) ) {
+
+ _DataAttribute->Resize( OldAllocatedLength, _VolumeBitmap );
+ return FALSE;
+ }
+
+ DebugAssert( _DataAttribute->QueryAllocatedLength() ==
+ OldAllocatedLength + BytesToAdd );
+
+ // Grow the MFT Bitmap to cover the new size of the Data Attribute.
+ // Note that NTFS_BITMAP::Resize will set the new bits free, which
+ // is what I want.
+
+ NumberOfSegments = _DataAttribute->QueryAllocatedLength() / _BytesPerFrs;
+
+ if( !_MftBitmap->Resize( NumberOfSegments ) ) {
+
+ // I couldn't expand the MFT Bitmap to cover the new space,
+ // so I'll have to truncate the data attribute back down.
+
+ _DataAttribute->Resize( OldAllocatedLength, _VolumeBitmap );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BIG_INT
+NTFS_MASTER_FILE_TABLE::QueryFrsCount(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the number of frs's in the MFT.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of frs's.
+
+--*/
+{
+ BIG_INT num_frs;
+
+ num_frs = _DataAttribute->QueryValueLength() / _BytesPerFrs;
+
+ return num_frs;
+}
diff --git a/private/utils/untfs/src/mftfile.cxx b/private/utils/untfs/src/mftfile.cxx
new file mode 100644
index 000000000..1717686f6
--- /dev/null
+++ b/private/utils/untfs/src/mftfile.cxx
@@ -0,0 +1,743 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ mftfile.hxx
+
+Abstract:
+
+ This module contains the member function definitions for the
+ NTFS_MFT_FILE class.
+
+Author:
+
+ Bill McJohn (billmc) 22-June-91
+
+Environment:
+
+ ULIB, User Mode
+
+Notes:
+
+ The MFT and the Volume Bitmap:
+
+ The Master File Table needs the bitmap to extend itself. The
+ volume bitmap can be passed in upon initialization, or it can
+ be supplied (using SetVolumeBitmap) at any time. However,
+ until it is supplied, the Master File Table is unable to grow
+ itself.
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "untfs.hxx"
+
+#include "drive.hxx"
+#include "attrib.hxx"
+#include "ntfsbit.hxx"
+#include "mftfile.hxx"
+#include "clusrun.hxx"
+#include "cmem.hxx"
+#include "indxtree.hxx"
+
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( NTFS_MFT_FILE, NTFS_FILE_RECORD_SEGMENT, UNTFS_EXPORT );
+
+UNTFS_EXPORT
+NTFS_MFT_FILE::~NTFS_MFT_FILE(
+ )
+{
+ Destroy();
+}
+
+
+VOID
+NTFS_MFT_FILE::Construct(
+ )
+/*++
+
+Routine Description:
+
+ Worker function for the construtor.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _FirstLcn = 0;
+ _VolumeBitmap = NULL;
+}
+
+
+VOID
+NTFS_MFT_FILE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Clean up an NTFS_MFT_FILE object in preparation for
+ destruction or reinitialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _FirstLcn = 0;
+ _VolumeBitmap = NULL;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_MFT_FILE::Initialize(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN LCN Lcn,
+ IN ULONG ClusterFactor,
+ IN ULONG FrsSize,
+ IN BIG_INT VolumeSectors,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN PNTFS_UPCASE_TABLE UpcaseTable
+ )
+/*++
+
+Routine Description:
+
+ Initialize an NTFS_MFT_FILE object.
+
+Arguments:
+
+ Drive -- supplies the Drive on which the file table resides
+ Lcn -- supplies the logical cluster number of the master
+ file table entry which describes the master file
+ table itself.
+ ClusterFactor -- supplies the number of sectors per cluster.
+ FrsSize -- supplies the number of bytes per File Record
+ Segment in this MFT.
+ VolumeSectors -- supplies the number of volume sectors.
+ VolumeBitmap -- supplies the bitmap for the volume. This parameter
+ may be NULL.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ ULONG MirroredClusters;
+ ULONG ClusterSize;
+
+ Destroy();
+
+ DebugPtrAssert( Drive );
+
+ _FirstLcn = Lcn;
+ _VolumeBitmap = VolumeBitmap;
+
+ ClusterSize = Drive->QuerySectorSize() * ClusterFactor;
+
+ MirroredClusters = (REFLECTED_MFT_SEGMENTS * FrsSize + (ClusterSize - 1))
+ / ClusterSize;
+
+ if( !_MirrorMem.Initialize() ||
+ !_MirrorClusterRun.Initialize( &_MirrorMem,
+ Drive,
+ 0,
+ ClusterFactor,
+ MirroredClusters ) ) {
+
+ DebugPrint( "Can't initialize MFT helper cluster run.\n" );
+ Destroy();
+ return FALSE;
+ }
+
+ if (!_Mft.Initialize(&_DataAttribute, &_MftBitmap, VolumeBitmap,
+ UpcaseTable, ClusterFactor, FrsSize,
+ Drive->QuerySectorSize(), VolumeSectors)) {
+
+ return FALSE;
+ }
+
+ _Mft.DisableMethods();
+
+
+ if (!NTFS_FILE_RECORD_SEGMENT::Initialize(Drive,
+ Lcn,
+ &_Mft) ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_MFT_FILE::Create(
+ IN ULONG InitialSize,
+ IN PCSTANDARD_INFORMATION StandardInformation,
+ IN OUT PNTFS_BITMAP VolumeBitmap
+ )
+/*++
+
+Routine Description:
+
+ Create a new Master File Table for the volume.
+
+Arguments:
+
+ InitialSize -- supplies the number of clusters to allocate
+ to the MFT we create.
+ StandardInformation -- supplies a standard information structure for
+ the MFT's File Record Segment.
+ VolumeBitmap -- supplies the bitmap for the volume.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ The caller must first allocate a run of InitialSize clusters
+ from the bitmap, and initialize the NTFS_MFT_FILE object
+ with the starting cluster of that run.
+
+--*/
+{
+ NTFS_EXTENT_LIST Extents;
+ NTFS_ATTRIBUTE MftBitmapAttribute;
+ LCN FirstLcnInMftBitmap;
+ ULONG ClustersInMftBitmap;
+ ULONG MftBitmapSize;
+ ULONG ClusterSize;
+ ULONG MftClusters;
+
+ _Mft.DisableMethods();
+
+ if( InitialSize < FIRST_USER_FILE_NUMBER ) {
+
+ DebugPrint( "MFT Initial Size is too small.\n" );
+ return FALSE;
+ }
+
+
+ // Set this object up as a File Record Segment:
+
+ if( !NTFS_FILE_RECORD_SEGMENT::Create( StandardInformation ) ) {
+
+ return FALSE;
+ }
+
+
+ // OK, set up the data attribute with the disk space supplied
+ // by the caller.
+
+ ClusterSize = GetDrive()->QuerySectorSize() * QueryClusterFactor();
+
+ MftClusters = (InitialSize * QuerySize() + (ClusterSize - 1)) / ClusterSize;
+
+ if( !Extents.Initialize( 0, 0 ) ||
+ !Extents.AddExtent( 0,
+ _FirstLcn,
+ MftClusters ) ||
+ !_DataAttribute.Initialize( GetDrive(),
+ QueryClusterFactor(),
+ &Extents,
+ InitialSize * QuerySize(),
+ InitialSize * QuerySize(),
+ $DATA ) ||
+ !_DataAttribute.InsertIntoFile( this,
+ VolumeBitmap ) ) {
+
+ return FALSE;
+ }
+
+ // Create an MFT Bitmap attribute. Allocate a run on disk to
+ // hold its initial size, and use that to set up a non-resident
+ // attribute to hold it. The initial size is at least 8k (to
+ // allow some space for future growth.)
+ //
+
+ MftBitmapSize = (InitialSize + 7)/ 8;
+
+ ClustersInMftBitmap = max((MftBitmapSize + (ClusterSize - 1))/ClusterSize,
+ /* MFT_BITMAP_INITIAL_SIZE/ClusterSize */, 0);
+
+ if( !VolumeBitmap->AllocateClusters( 1,
+ ClustersInMftBitmap,
+ &FirstLcnInMftBitmap,
+ 1 ) ||
+ !Extents.Initialize( 0, 0 ) ||
+ !Extents.AddExtent( 0,
+ FirstLcnInMftBitmap,
+ ClustersInMftBitmap ) ||
+ !MftBitmapAttribute.Initialize( GetDrive(),
+ QueryClusterFactor(),
+ &Extents,
+ MftBitmapSize,
+ /* value length */
+ /* ClustersInMftBitmap * ClusterSize, */
+ MftBitmapSize, /* valid length */
+ $BITMAP ) ||
+ !MftBitmapAttribute.InsertIntoFile( this,
+ VolumeBitmap ) ) {
+
+ return FALSE;
+ }
+
+ // Create the MFT Bitmap. Note that it is growable.
+
+ if( !_MftBitmap.Initialize( InitialSize, TRUE ) ) {
+
+ return FALSE;
+ }
+
+ // Mark the system files as in use. Note that we've already
+ // checked that InitialSize is at least FIRST_USER_FILE_NUMBER.
+
+ _MftBitmap.SetAllocated( 0, FIRST_USER_FILE_NUMBER );
+
+ _Mft.EnableMethods();
+
+ return TRUE;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_MFT_FILE::Read(
+ )
+/*++
+
+Routine Description:
+
+ This routine reads this FRS for the MFT and then proceeds
+ to read the MFT bitmap. If all goes well, the internal
+ data attribute and MFT bitmap will be initialized.
+
+ This method will return TRUE if and only if the base FRS for
+ this MFT is correctly read in. The MFT allocation methods will
+ be enabled by this method if and only if MFT bitmap and the
+ MFT data attribute are properly read in and initialized.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_ATTRIBUTE MftBitmapAttribute;
+ BIG_INT DataAttributeWrittenLength;
+ BIG_INT DataAttributeAllocatedLength;
+ BIG_INT NumberOfAllocatedFileRecordSegments,
+ NumberOfWrittenFileRecordSegments;
+ ULONG RequiredBitsInBitmap, PreferredBitsInBitmap;
+ BOOLEAN Error;
+
+ _Mft.DisableMethods();
+
+ if (!NTFS_FILE_RECORD_SEGMENT::Read()) {
+ return FALSE;
+ }
+
+ _Mft.EnableMethods();
+
+ // Make sure that we have the Data Attribute to play with.
+
+ if (!QueryAttribute(&_DataAttribute, &Error, $DATA)) {
+
+ _Mft.DisableMethods();
+ return TRUE;
+ }
+
+
+ // The length of the bitmap depends on the allocated length of
+ // the data attribute.
+
+ _DataAttribute.QueryValueLength( &DataAttributeWrittenLength,
+ &DataAttributeAllocatedLength );
+
+ // A quick sanity check:
+ //
+ if( DataAttributeWrittenLength > DataAttributeAllocatedLength ) {
+
+ DebugAbort( "UNTFS: MFT Data attribute is corrupt.\n" );
+ _Mft.DisableMethods();
+ return TRUE;
+ }
+
+ NumberOfWrittenFileRecordSegments = DataAttributeWrittenLength / QuerySize();
+ NumberOfAllocatedFileRecordSegments = DataAttributeAllocatedLength / QuerySize();
+
+ DebugAssert( NumberOfWrittenFileRecordSegments.GetHighPart() == 0 );
+ DebugAssert( NumberOfAllocatedFileRecordSegments.GetHighPart() == 0 );
+
+ RequiredBitsInBitmap = NumberOfWrittenFileRecordSegments.GetLowPart();
+ PreferredBitsInBitmap = NumberOfAllocatedFileRecordSegments.GetLowPart();
+
+ // Create a bitmap, and get the MFT bitmap attribute through
+ // which we read it, and read the bitmap.
+
+ if( !_MftBitmap.Initialize( RequiredBitsInBitmap, TRUE ) ||
+ !QueryAttribute( &MftBitmapAttribute, &Error, $BITMAP ) ||
+ !_MftBitmap.Read( &MftBitmapAttribute ) ||
+ !_MftBitmap.Resize( PreferredBitsInBitmap ) ) {
+
+ DebugAbort( "Cannot read MFT Bitmap.\n" );
+ _Mft.DisableMethods();
+ return TRUE;
+ }
+
+ return TRUE;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_MFT_FILE::Flush(
+ )
+/*++
+
+Routine Description:
+
+ This method flushes the MFT--re-inserts the DATA attribute (if
+ necessary); writes the MFT bitmap, and writes the MFT's own
+ File Record Segment.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This method will also write the volume bitmap and the mft mirror.
+ It will resize the $DATA attributes on the bitmap and mirror files
+ and write those FRS's, if necessary.
+
+--*/
+{
+ NTFS_BITMAP_FILE BitmapFile;
+ NTFS_REFLECTED_MASTER_FILE_TABLE MirrorFile;
+ NTFS_INDEX_TREE RootIndex;
+ NTFS_FILE_RECORD_SEGMENT RootIndexFrs;
+ DSTRING FileNameIndexName;
+
+ NTFS_ATTRIBUTE MftBitmapAttribute,
+ MirrorDataAttribute,
+ VolumeBitmapAttribute;
+
+ LCN FirstMirrorLcn;
+ BIG_INT OldValidLength;
+ BOOLEAN Error;
+
+ if( !_Mft.AreMethodsEnabled() ) {
+
+ DebugAbort( "Tried to flush the MFT before enabling it.\n" );
+ return FALSE;
+ }
+
+
+ // Ensure that the bitmap file and mirror file's $DATA attributes
+ // are the correct sizes. This will later allow us to write these
+ // two constructs without affecting their respective FRS's.
+
+ if( !BitmapFile.Initialize( &_Mft ) ||
+ !BitmapFile.Read() ||
+ !BitmapFile.QueryAttribute( &VolumeBitmapAttribute,
+ &Error,
+ $DATA ) ||
+ !_VolumeBitmap->CheckAttributeSize( &VolumeBitmapAttribute,
+ _VolumeBitmap ) ||
+ !MirrorFile.Initialize( &_Mft ) ||
+ !MirrorFile.Read() ||
+ !MirrorFile.QueryAttribute( &MirrorDataAttribute,
+ &Error,
+ $DATA ) ||
+ !CheckMirrorSize( &MirrorDataAttribute,
+ TRUE,
+ _VolumeBitmap,
+ &FirstMirrorLcn ) ) {
+
+ DebugPrint( "Cannot check size of bitmap & mirror attributes.\n" );
+ return FALSE;
+ }
+
+
+ if( VolumeBitmapAttribute.IsStorageModified() &&
+ ( !VolumeBitmapAttribute.InsertIntoFile( &BitmapFile,
+ _VolumeBitmap ) ||
+ !BitmapFile.Flush( _VolumeBitmap ) ) ) {
+
+ DebugPrint( "Cannot save volume bitmap attribute.\n" );
+ return FALSE;
+ }
+
+ if( MirrorDataAttribute.IsStorageModified() &&
+ ( !MirrorDataAttribute.InsertIntoFile( &MirrorFile, _VolumeBitmap ) ||
+ !MirrorFile.Flush( _VolumeBitmap ) ) ) {
+
+ DebugPrint( "Cannot save MFT mirror data attribute.\n" );
+ return FALSE;
+ }
+
+ // Fetch the root index from its FRS.
+ //
+ if( !RootIndexFrs.Initialize( ROOT_FILE_NAME_INDEX_NUMBER, this ) ||
+ !RootIndexFrs.Read() ||
+ !FileNameIndexName.Initialize( FileNameIndexNameData ) ||
+ !RootIndex.Initialize( GetDrive(),
+ QueryClusterFactor(),
+ _VolumeBitmap,
+ GetUpcaseTable(),
+ QuerySize()/2,
+ &RootIndexFrs,
+ &FileNameIndexName ) ) {
+
+ return FALSE;
+ }
+
+ // Fetch the MFT Bitmap attribute.
+ //
+ if( !QueryAttribute( &MftBitmapAttribute, &Error, $BITMAP ) ) {
+
+ DebugPrintf( "UNTFS: Cannot fetch MFT bitmap attribute.\n" );
+ return FALSE;
+ }
+
+ // Write the bitmap once to make it the right size. If
+ // it grows while we're saving the MFT, we'll have to
+ // write it again.
+ //
+ if( !_MftBitmap.Write( &MftBitmapAttribute, _VolumeBitmap ) ) {
+
+ DebugPrintf( "UNTFS: Cannot write the MFT bitmap.\n" );
+ return FALSE;
+ }
+
+ do {
+
+ // Note that inserting an attribute into a file resets the
+ // attribute's StorageModified flag.
+ //
+ if( MftBitmapAttribute.IsStorageModified() &&
+ !MftBitmapAttribute.InsertIntoFile( this, NULL ) ) {
+
+ DebugPrint( "UNTFS: Cannot save MFT bitmap attribute.\n" );
+ return FALSE;
+ }
+
+ // Remember the bitmap size (which is equal to the number
+ // of FRS's in the MFT).
+ //
+ OldValidLength = _DataAttribute.QueryValidDataLength();
+
+ // Save the data attribute.
+ //
+ if( _DataAttribute.IsStorageModified() &&
+ !_DataAttribute.InsertIntoFile(this, NULL) ) {
+
+ DebugAbort( "UNTFS: Cannot save MFT's data attribute.\n" );
+ return FALSE;
+ }
+
+ // Flush this FRS.
+ //
+ if( !NTFS_FILE_RECORD_SEGMENT::Flush( _VolumeBitmap, &RootIndex) ) {
+
+ return FALSE;
+ }
+
+ // Write the bitmap again, in case it changed.
+ //
+ if( !_MftBitmap.Write( &MftBitmapAttribute, _VolumeBitmap ) ) {
+
+ DebugPrintf( "UNTFS: Cannot write the MFT bitmap.\n" );
+ return FALSE;
+ }
+
+ // If the MFT's Valid Data Length changed while we were
+ // saving the data attribute and bitmap, we have to go
+ // through this loop again.
+
+ } while( OldValidLength != _DataAttribute.QueryValidDataLength() );
+
+ // Save the root index:
+ //
+ if( !RootIndex.Save( &RootIndexFrs ) ||
+ !RootIndexFrs.Flush( _VolumeBitmap ) ) {
+
+ return FALSE;
+ }
+
+ if( !_VolumeBitmap->Write( &VolumeBitmapAttribute, NULL ) ||
+ !WriteMirror( &MirrorDataAttribute ) ){
+
+ DebugPrint( "Failed write of MFT Mirror or volume bitmap.\n" );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_MFT_FILE::CheckMirrorSize(
+ IN OUT PNTFS_ATTRIBUTE MirrorDataAttribute,
+ IN BOOLEAN Fix,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ OUT PLCN FirstLcn
+ )
+/*++
+
+Routine Description:
+
+ This method checks that the MFT Mirror $DATA attribute is the
+ correct size and contiguous. It can also be used to check these
+ restrictions.
+
+Arguments:
+
+ MirrorDataAttribut -- Supplies the MFT Mirror's $DATA attribute.
+ Fix -- Supplies a flag which indicates that the
+ attribute should be reallocated if it is
+ the wrong size or not contiguous.
+ VolumeBitmap -- Supplies the volume bitmap (only required
+ if Fix is TRUE).
+ FirstLcn -- Receives the starting LCN of the mirror.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ BIG_INT RunLength;
+ LCN NewStartingLcn;
+ ULONG MirroredClusters;
+ ULONG ClusterSize;
+
+ ClusterSize = QueryClusterFactor() * _Mft.QuerySectorSize();
+
+ MirroredClusters = (REFLECTED_MFT_SEGMENTS * QuerySize() + (ClusterSize - 1))
+ / ClusterSize;
+
+ if( MirrorDataAttribute->QueryLcnFromVcn( 0, FirstLcn, &RunLength ) &&
+ *FirstLcn != 0 &&
+ *FirstLcn != LCN_NOT_PRESENT &&
+ RunLength >= MirroredClusters ) {
+
+ // Everything is perfect.
+
+ return TRUE;
+ }
+
+ // Something is not perfect.
+
+ if( Fix &&
+ VolumeBitmap->AllocateClusters( QueryVolumeSectors()/
+ QueryClusterFactor()/
+ 2,
+ MirroredClusters,
+ &NewStartingLcn ) &&
+ MirrorDataAttribute->Resize( 0, VolumeBitmap ) &&
+ MirrorDataAttribute->AddExtent( 0,
+ NewStartingLcn,
+ MirroredClusters ) ) {
+
+ // It was broken, but now it's perfect.
+
+ *FirstLcn = NewStartingLcn;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+BOOLEAN
+NTFS_MFT_FILE::WriteMirror(
+ IN OUT PNTFS_ATTRIBUTE MirrorDataAttribute
+ )
+/*++
+
+Routine Description:
+
+ This method writes the MFT Mirror. Note that it will fail if
+ the mirror's $DATA attribute is not the correct size or is
+ not contiguous.
+
+Arguments:
+
+ MirrorDataAttribute -- Supplies the MFT Mirror's $DATA attribute.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ This method copies whatever is _on disk_ in the MFT's data attribute
+ to the mirror's data attribute. Therefore, it should only be called
+ after the MFT itself has been written.
+
+--*/
+{
+ LCN FirstMirrorLcn;
+
+ if( !CheckMirrorSize( MirrorDataAttribute,
+ FALSE,
+ NULL,
+ &FirstMirrorLcn ) ) {
+
+ return FALSE;
+ }
+
+ _MirrorClusterRun.Relocate( _FirstLcn );
+
+ if( !_MirrorClusterRun.Read() ) {
+
+ return FALSE;
+ }
+
+ _MirrorClusterRun.Relocate( FirstMirrorLcn );
+
+ if( !_MirrorClusterRun.Write() ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/untfs/src/mftref.cxx b/private/utils/untfs/src/mftref.cxx
new file mode 100644
index 000000000..c8db78671
--- /dev/null
+++ b/private/utils/untfs/src/mftref.cxx
@@ -0,0 +1,392 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ mftref.cxx
+
+Abstract:
+
+ This module contains the member function definitions for
+ the NTFS_REFLECTED_MASTER_FILE_TABLE class. This class
+ models the backup copy of the Master File Table.
+
+Author:
+
+ Bill McJohn (billmc) 13-June-91
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "untfs.hxx"
+
+#include "drive.hxx"
+#include "attrib.hxx"
+#include "ntfsbit.hxx"
+#include "mftref.hxx"
+#include "ifssys.hxx"
+#include "numset.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+
+DEFINE_EXPORTED_CONSTRUCTOR( NTFS_REFLECTED_MASTER_FILE_TABLE,
+ NTFS_FILE_RECORD_SEGMENT, UNTFS_EXPORT );
+
+UNTFS_EXPORT
+NTFS_REFLECTED_MASTER_FILE_TABLE::~NTFS_REFLECTED_MASTER_FILE_TABLE(
+ )
+{
+ Destroy();
+}
+
+
+VOID
+NTFS_REFLECTED_MASTER_FILE_TABLE::Construct(
+ )
+/*++
+
+Routine Description:
+
+ Worker function for the construtor.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+}
+
+
+VOID
+NTFS_REFLECTED_MASTER_FILE_TABLE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Clean up an NTFS_MASTER_FILE_TABLE object in preparation for
+ destruction or reinitialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+}
+
+
+BOOLEAN
+NTFS_REFLECTED_MASTER_FILE_TABLE::Initialize(
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft
+ )
+/*++
+
+Routine Description:
+
+ This method initializes a Master File Table Reflection object.
+ The only special knowledge that it adds to the File Record Segment
+ initialization is the location within the Master File Table of the
+ Master File Table Reflection.
+
+Arguments:
+
+ Mft -- Supplies the volume MasterFile Table.
+
+Return Value:
+
+ TRUE upon successful completion
+
+Notes:
+
+ This class is reinitializable.
+
+
+--*/
+{
+ return( NTFS_FILE_RECORD_SEGMENT::Initialize( MASTER_FILE_TABLE2_NUMBER,
+ Mft ) );
+}
+
+
+BOOLEAN
+NTFS_REFLECTED_MASTER_FILE_TABLE::Create(
+ IN PCSTANDARD_INFORMATION StandardInformation,
+ IN OUT PNTFS_BITMAP VolumeBitmap
+ )
+/*++
+
+Routine Description:
+
+ This method formats a Master File Table Reflection File Record
+ Segment in memory (without writing it to disk).
+
+Arguments:
+
+ StandardInformation -- supplies the standard information for the
+ file record segment.
+ VolumeBitmap -- supplies the bitmap for the volume on
+ which this object resides.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ NTFS_ATTRIBUTE DataAttribute;
+ NTFS_EXTENT_LIST Extents;
+ LCN FirstLcn;
+ BIG_INT Size;
+ ULONG ReflectedMftClusters;
+ ULONG cluster_size;
+
+ // Set this object up as a File Record Segment.
+
+ if( !NTFS_FILE_RECORD_SEGMENT::Create( StandardInformation ) ) {
+
+ return FALSE;
+ }
+
+ // The Master File Table Reflection has a data attribute whose value
+ // consists of REFLECTED_MFT_SEGMENTS file record segments. Create
+ // merely allocates space for these clusters, it does not write them.
+
+ cluster_size = QueryClusterFactor() * GetDrive()->QuerySectorSize();
+
+ ReflectedMftClusters = (REFLECTED_MFT_SEGMENTS * QuerySize() + (cluster_size-1))
+ / cluster_size;
+
+ Size = ReflectedMftClusters * cluster_size;
+
+ if( !VolumeBitmap->AllocateClusters( (QueryVolumeSectors()/2)/
+ QueryClusterFactor(),
+ ReflectedMftClusters,
+ &FirstLcn ) ||
+ !Extents.Initialize( 0, 0 ) ||
+ !Extents.AddExtent( 0,
+ FirstLcn,
+ ReflectedMftClusters ) ||
+ !DataAttribute.Initialize( GetDrive(),
+ QueryClusterFactor(),
+ &Extents,
+ Size,
+ Size,
+ $DATA ) ||
+ !DataAttribute.InsertIntoFile( this, VolumeBitmap ) ) {
+
+ return FALSE;
+ }
+
+
+ return TRUE;
+}
+
+
+NONVIRTUAL
+BOOLEAN
+NTFS_REFLECTED_MASTER_FILE_TABLE::VerifyAndFix(
+ IN PNTFS_ATTRIBUTE MftData,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNUMBER_SET BadClusters,
+ IN OUT PNTFS_INDEX_TREE RootIndex,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine ensures that this FRS's $DATA attribute is the
+ appropriate length (from 1 to 3 clusters). It also compares
+ the data in these clusters with the first clusters of the
+ $MftData attribute and prints a message if they are different.
+
+ This routine does not actually write out the contents of these
+ clusters because this is done by MFT_FILE::Flush()
+
+Arguments:
+
+ MftData - Supplies the MFT $DATA attribute.
+ FixLevel - Supplies the CHKDSK fix level.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ HMEM mft_hmem, ref_hmem;
+ SECRUN mft_secrun, ref_secrun;
+ LCN mft_lcn, ref_lcn;
+ BIG_INT run_length;
+ ULONG num_clusters;
+ ULONG num_sectors;
+ BOOLEAN need_write;
+ NTFS_ATTRIBUTE data_attribute;
+ NTFS_EXTENT_LIST extents;
+ BOOLEAN error;
+
+
+ // First read in the original stuff.
+
+ num_sectors = (REFLECTED_MFT_SEGMENTS*QuerySize())/GetDrive()->QuerySectorSize();
+
+ if (!MftData->QueryLcnFromVcn(0, &mft_lcn) ||
+ !mft_hmem.Initialize() ||
+ !mft_secrun.Initialize(&mft_hmem, GetDrive(),
+ mft_lcn*QueryClusterFactor(),
+ num_sectors) ||
+ !mft_secrun.Read()) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ need_write = FALSE;
+
+
+ // Query the $DATA attribute from this FRS.
+
+ if (!QueryAttribute(&data_attribute, &error, $DATA) ||
+ data_attribute.IsResident()) {
+
+ if (error) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!need_write) {
+ Message->Set(MSG_CHK_NTFS_CORRECTING_MFT_MIRROR);
+ Message->Display();
+ }
+
+ need_write = TRUE;
+
+ if (!extents.Initialize(0, 0) ||
+ !data_attribute.Initialize(GetDrive(), QueryClusterFactor(),
+ &extents, 0, 0, $DATA)) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_MFT_MIRROR);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+
+ // Make sure that the $DATA attribute is the right size.
+
+ if (!data_attribute.QueryLcnFromVcn(0, &ref_lcn, &run_length) ||
+ ref_lcn == LCN_NOT_PRESENT ||
+ run_length*QueryClusterFactor() < num_sectors ||
+ !ref_hmem.Initialize() ||
+ !ref_secrun.Initialize(&ref_hmem, GetDrive(),
+ ref_lcn*QueryClusterFactor(),
+ num_sectors) ||
+ !ref_secrun.Read()) {
+
+ if (!need_write) {
+ Message->Set(MSG_CHK_NTFS_CORRECTING_MFT_MIRROR);
+ Message->Display();
+ }
+
+ need_write = TRUE;
+
+ if (data_attribute.QueryLcnFromVcn(0, &ref_lcn, &run_length) &&
+ ref_lcn != LCN_NOT_PRESENT &&
+ !BadClusters->Add(ref_lcn, run_length)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ num_clusters = (num_sectors+QueryClusterFactor()-1)/QueryClusterFactor();
+
+ if (!data_attribute.Hotfix(0, num_clusters, VolumeBitmap,
+ BadClusters, TRUE)) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_MFT_MIRROR);
+ Message->Display();
+ return FALSE;
+ }
+
+ } else if (memcmp(mft_hmem.GetBuf(), ref_hmem.GetBuf(),
+ REFLECTED_MFT_SEGMENTS*QuerySize())) {
+
+ if (!need_write) {
+ Message->Set(MSG_CHK_NTFS_CORRECTING_MFT_MIRROR);
+ Message->Display();
+ }
+
+ need_write = TRUE;
+ }
+
+ if ((data_attribute.IsStorageModified() &&
+ !data_attribute.InsertIntoFile(this, VolumeBitmap)) ||
+ (need_write && FixLevel != CheckOnly &&
+ !Flush(VolumeBitmap, RootIndex))) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_MFT_MIRROR);
+ Message->Display();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+LCN
+NTFS_REFLECTED_MASTER_FILE_TABLE::QueryFirstLcn(
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The LCN of the first cluster of the Master File Table
+ Reflection's $DATA attribute.
+
+--*/
+{
+ NTFS_ATTRIBUTE DataAttribute;
+ LCN Result = 0;
+ BOOLEAN Error;
+
+ if( !QueryAttribute( &DataAttribute, &Error, $DATA ) ||
+ !DataAttribute.QueryLcnFromVcn( 0, &Result ) ) {
+
+ Result = 0;
+ }
+
+ return Result;
+}
diff --git a/private/utils/untfs/src/ntfsbit.cxx b/private/utils/untfs/src/ntfsbit.cxx
new file mode 100644
index 000000000..e3683c464
--- /dev/null
+++ b/private/utils/untfs/src/ntfsbit.cxx
@@ -0,0 +1,688 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ntfsbit.cxx
+
+Abstract:
+
+ This module contains the declarations for NTFS_BITMAP,
+ which models the bitmap of an NTFS volume, and MFT_BITMAP,
+ which models the bitmap for the Master File Table.
+
+Author:
+
+ Bill McJohn (billmc) 17-June-91
+
+Environment:
+
+ ULIB, User Mode
+
+Notes:
+
+ This implementation only supports bitmaps which have a number
+ of sectors which will fit in a ULONG. The interface supports
+ the 64-bit number of clusters, but Initialize will refuse to
+ accept a number-of-clusters value which has a non-zero high part.
+
+ If we rewrite BITVECTOR to accept 64-bit cluster numbers (or
+ write a new one) this class could easily be fixed to support
+ larger volumes.
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "untfs.hxx"
+
+#include "ntfsbit.hxx"
+#include "attrib.hxx"
+
+DEFINE_EXPORTED_CONSTRUCTOR( NTFS_BITMAP, OBJECT, UNTFS_EXPORT );
+
+UNTFS_EXPORT
+NTFS_BITMAP::~NTFS_BITMAP(
+ )
+{
+ Destroy();
+}
+
+VOID
+NTFS_BITMAP::Construct(
+ )
+/*++
+
+Routine Description:
+
+ Worker method for object construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _NumberOfClusters = 0;
+ _BitmapSize = 0;
+ _BitmapData = NULL;
+ _NextAlloc = 0;
+ _Mft = NULL;
+ _ClusterFactor = 0;
+ _Drive = NULL;
+}
+
+VOID
+NTFS_BITMAP::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Worker method to prepare an object for destruction
+ or reinitialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _NumberOfClusters = 0;
+ _BitmapSize = 0;
+ FREE( _BitmapData );
+ _NextAlloc = 0;
+ _Mft = NULL;
+}
+
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_BITMAP::Initialize(
+ IN BIG_INT NumberOfClusters,
+ IN BOOLEAN IsGrowable,
+ IN PLOG_IO_DP_DRIVE Drive,
+ IN ULONG ClusterFactor
+ )
+/*++
+
+Routine Description:
+
+ This method initializes an NTFS_BITMAP object.
+
+Arguments:
+
+ NumberOfClusters -- Supplies the number of allocation units
+ which the bitmap covers.
+ IsGrowable -- Supplies a flag indicating whether the
+ bitmap may grow (TRUE) or is of fixed size
+ (FALSE).
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ The bitmap is initialized with all clusters within the range of
+ NumberOfClusters marked as FREE.
+
+--*/
+{
+ ULONG LowNumberOfClusters;
+
+ Destroy();
+
+ if( NumberOfClusters.GetHighPart() != 0 ) {
+
+ DebugPrint( "bitmap.cxx: cannot manage a volume of this size.\n" );
+ return FALSE;
+ }
+
+ LowNumberOfClusters = NumberOfClusters.GetLowPart();
+
+ _NumberOfClusters = NumberOfClusters;
+ _IsGrowable = IsGrowable;
+
+ _Drive = Drive;
+ _ClusterFactor = ClusterFactor;
+
+
+ // Determine the size in bytes of the bitmap. Note that this size
+ // is quad-aligned.
+
+ _BitmapSize = ( LowNumberOfClusters % 8 ) ?
+ ( LowNumberOfClusters/8 + 1 ) :
+ ( LowNumberOfClusters/8 );
+
+ _BitmapSize = QuadAlign( max(_BitmapSize, 1) );
+
+
+ // Allocate space for the bitvector and initialize it.
+
+ if( (_BitmapData = MALLOC( _BitmapSize )) == NULL ||
+ !_Bitmap.Initialize( _BitmapSize * 8,
+ RESET,
+ (PPT)_BitmapData ) ) {
+
+ // Note that Destroy will clean up _BitmapData
+
+ Destroy();
+ return FALSE;
+ }
+
+ // If the bitmap is growable, then any padding bits are reset (free);
+ // if it is fixed size, they are set (allocated).
+
+ if( _IsGrowable ) {
+
+ _Bitmap.ResetBit( _NumberOfClusters.GetLowPart(),
+ _BitmapSize * 8 - _NumberOfClusters.GetLowPart() );
+
+ } else {
+
+ _Bitmap.SetBit( _NumberOfClusters.GetLowPart(),
+ _BitmapSize * 8 - _NumberOfClusters.GetLowPart() );
+ }
+
+ // The bitmap is intialized with all clusters marked free.
+ //
+ SetFree( 0, _NumberOfClusters );
+
+ return TRUE;
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_BITMAP::Write(
+ IN OUT PNTFS_ATTRIBUTE BitmapAttribute,
+ IN OUT PNTFS_BITMAP VolumeBitmap
+ )
+/*++
+
+Routine Description:
+
+ This method writes the bitmap.
+
+Arguments:
+
+ BitmapAttribute -- supplies the attribute which describes the
+ bitmap's location on disk.
+ VolumeBitmap -- supplies the volume's bitmap for possible
+ allocation during write.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ The attribute will, if necessary, allocate space from the
+ bitmap to write it.
+
+--*/
+{
+ ULONG BytesWritten;
+
+ DebugPtrAssert( _BitmapData );
+
+
+
+ return( CheckAttributeSize( BitmapAttribute, VolumeBitmap ) &&
+ BitmapAttribute->Write( _BitmapData,
+ 0,
+ _BitmapSize,
+ &BytesWritten,
+ VolumeBitmap ) &&
+ BytesWritten == _BitmapSize );
+}
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_BITMAP::IsFree(
+ IN LCN Lcn,
+ IN BIG_INT RunLength
+ ) CONST
+/*++
+
+Routine Description:
+
+ This method determines whether the specified cluster run is
+ marked as free in the bitmap.
+
+Arguments:
+
+ Lcn -- supplies the LCN of the first cluster in the run
+ RunLength -- supplies the length of the run
+
+Return Value:
+
+ TRUE if all clusters in the run are free in the bitmap.
+
+Notes:
+
+ This method checks to make sure that the LCNs in question are in
+ range, i.e. less than the number of clusters in the bitmap.
+
+--*/
+{
+ ULONG i, CurrentLcn;
+
+
+ if( Lcn < 0 ||
+ Lcn + RunLength > _NumberOfClusters ) {
+
+ return FALSE;
+ }
+
+ // Note that, since _NumberOfClusters is not greater than the
+ // maximum ULONG, the high parts of Lcn and RunLength are
+ // sure to be zero.
+
+ for( i = 0, CurrentLcn = Lcn.GetLowPart();
+ i < RunLength.GetLowPart();
+ i++, CurrentLcn++ ) {
+
+ if( _Bitmap.IsBitSet( CurrentLcn ) ) {
+
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+NTFS_BITMAP::AllocateClusters(
+ IN LCN NearHere,
+ IN BIG_INT RunLength,
+ OUT PLCN FirstAllocatedLcn,
+ IN ULONG AlignmentFactor
+ )
+/*++
+
+Routine Description:
+
+ This method finds a free run of sectors and marks it as allocated.
+
+ If the bitmap being allocated from is the volume bitmap, this method
+ will have a valid _Drive member. In this case, it will attempt to
+ verify that only usable clusters are allocated. If _Mft is also
+ set, any bad clusters found will be added to the bad cluster file.
+
+Arguments:
+
+ NearHere -- supplies the LCN near which the caller would
+ like the space allocated.
+ RunLength -- supplies the number of clusters to be allocated
+ FirstAllocatedLcn -- receives the first LCN of the allocated run
+ AlignmentFactor -- supplies the alignment requirement for the
+ allocated run--it must start on a multiple
+ of AlignmentFactor.
+
+Return Value:
+
+ TRUE upon successful completion; FirstAllocatedLcn receives the
+ LCN of the first cluster in the run.
+
+--*/
+{
+ ULONG current_lcn;
+ LCN first_allocated_lcn;
+ ULONG count;
+ BOOLEAN verify_each;
+
+ NTFS_BAD_CLUSTER_FILE badclus;
+
+ if (NearHere == 0) {
+ NearHere = _NextAlloc;
+ }
+
+ if (NearHere + RunLength > _NumberOfClusters) {
+ NearHere = _NumberOfClusters/2;
+ }
+
+ if( RunLength.GetHighPart() != 0 ) {
+
+ DebugAbort( "UNTFS: Trying to allocate too many sectors.\n" );
+ return FALSE;
+ }
+
+ //
+ // First we'll allocate a run and verify the whole thing at once.
+ // If that fails we'll go through the bitmap again, verifying each
+ // cluster.
+ //
+
+ verify_each = FALSE;
+
+again:
+
+ // Search forwards for a big enough block.
+
+ count = RunLength.GetLowPart();
+ for (current_lcn = NearHere.GetLowPart();
+ count > 0 && current_lcn < _NumberOfClusters;
+ current_lcn += 1) {
+
+ if (IsFree(current_lcn, 1)) {
+
+ if (count == RunLength.GetLowPart() && current_lcn%AlignmentFactor != 0) {
+ continue;
+ }
+
+ if (verify_each && NULL != _Drive) {
+
+ // Insure that this cluster is functional and can accept IO.
+
+ if (!_Drive->Verify(current_lcn * _ClusterFactor,
+ _ClusterFactor)) {
+
+ // This cluster is bad. Set the bit in the bitmap so we
+ // won't waste time trying to allocate it again and start
+ // over.
+
+ SetAllocated(current_lcn, 1);
+ count = RunLength.GetLowPart();
+
+ // If the bad cluster file is available, add this lcn
+ // to it.
+
+ if (NULL != _Mft && badclus.Initialize(_Mft)) {
+ badclus.Add(current_lcn);
+ badclus.Flush(this);
+ }
+
+ continue;
+ }
+ }
+
+ count -= 1;
+
+ } else {
+ count = RunLength.GetLowPart();
+ }
+ }
+
+ //
+ // If the forward search succeeded then allocate and return the
+ // result.
+ //
+
+ if (count == 0) {
+
+ first_allocated_lcn = current_lcn - RunLength;
+
+ if (NULL != _Drive && !_Drive->Verify(first_allocated_lcn * _ClusterFactor,
+ RunLength * _ClusterFactor)) {
+
+ //
+ // Want to go through each cluster in the run we found and
+ // figure out which ones are bad.
+ //
+
+ verify_each = TRUE;
+ NearHere = first_allocated_lcn;
+ goto again;
+ }
+
+ *FirstAllocatedLcn = first_allocated_lcn;
+ SetAllocated(first_allocated_lcn, RunLength);
+ _NextAlloc = first_allocated_lcn + RunLength;
+ return TRUE;
+ }
+
+ //
+ // We couldn't find any space by searching forwards, so let's
+ // search backwards.
+ //
+
+ verify_each = FALSE;
+
+again_backward:
+
+ count = RunLength.GetLowPart();
+ for (current_lcn = NearHere.GetLowPart() + RunLength.GetLowPart() - 1;
+ count > 0 && current_lcn > 0; current_lcn -= 1) {
+
+ if (IsFree(current_lcn, 1)) {
+
+ if (count == RunLength.GetLowPart() &&
+ (current_lcn - RunLength.GetLowPart() + 1)%AlignmentFactor != 0) {
+
+ continue;
+ }
+
+ if (verify_each && NULL != _Drive) {
+
+ // Insure that this cluster is functional and can accept IO.
+
+ if (!_Drive->Verify(current_lcn * _ClusterFactor,
+ _ClusterFactor)) {
+
+ // This cluster is bad. Set the bit in the bitmap so we
+ // won't waste time trying to allocate it again and start
+ // over.
+
+ SetAllocated(current_lcn, 1);
+ count = RunLength.GetLowPart();
+
+ // If the bad cluster file is available, add this lcn
+ // to it.
+
+ if (NULL != _Mft && badclus.Initialize(_Mft)) {
+ badclus.Add(current_lcn);
+ badclus.Flush(this);
+ }
+
+ continue;
+ }
+ }
+
+ count -= 1;
+ } else {
+
+ count = RunLength.GetLowPart();
+ }
+ }
+
+ if (count != 0) {
+ return FALSE;
+ }
+
+ first_allocated_lcn = current_lcn + 1;
+
+ if (NULL != _Drive && !_Drive->Verify(first_allocated_lcn * _ClusterFactor,
+ RunLength * _ClusterFactor)) {
+
+ //
+ // Want to go through each cluster in the run we found and
+ // figure out which ones are bad.
+ //
+
+ verify_each = TRUE;
+ NearHere = first_allocated_lcn + RunLength + 1;
+ goto again_backward;
+ }
+
+ //
+ // Since we had to search backwards, we don't want to start
+ // our next search from here (and waste time searching forwards).
+ // Instead, set the roving pointer to zero.
+ //
+
+ *FirstAllocatedLcn = first_allocated_lcn;
+ SetAllocated(first_allocated_lcn, RunLength);
+ _NextAlloc = 0;
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_BITMAP::Resize(
+ IN BIG_INT NewNumberOfClusters
+ )
+/*++
+
+Routine Description:
+
+ This method changes the number of allocation units that the bitmap
+ covers. It may either grow or shrink the bitmap.
+
+Arguments:
+
+ NewNumberOfClusters -- supplies the new number of allocation units
+ covered by this bitmap.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+Notes:
+
+ The size (in bytes) of the bitmap is always kept quad-aligned, and
+ any padding bits are reset.
+
+--*/
+{
+ PVOID NewBitmapData;
+ ULONG NewSize;
+ LCN OldNumberOfClusters;
+
+
+ DebugAssert( _IsGrowable );
+
+
+ // Make sure that the number of clusters fits into a ULONG,
+ // so we can continue to use BITVECTOR.
+
+ if( NewNumberOfClusters.GetHighPart() != 0 ) {
+
+ DebugPrint( "bitmap.cxx: cannot manage a volume of this size.\n" );
+ return FALSE;
+ }
+
+ // Compute the new size of the bitmap, in bytes. Note that this
+ // size is always quad-aligned (ie. a multiple of 8).
+
+ NewSize = ( NewNumberOfClusters.GetLowPart() % 8 ) ?
+ ( NewNumberOfClusters.GetLowPart()/8 + 1) :
+ ( NewNumberOfClusters.GetLowPart()/8 );
+
+ NewSize = QuadAlign( NewSize );
+
+ if( NewSize == _BitmapSize ) {
+
+ // The bitmap is already the right size, so it's just a matter
+ // of diddling the private data. Since padding in a growable
+ // bitmap is always reset (free), the new space is by default
+ // free.
+
+ _NumberOfClusters = NewNumberOfClusters;
+ return TRUE;
+ }
+
+ // The bitmap has changed size, so we need to allocate new memory
+ // for it and copy it.
+
+ if( (NewBitmapData = MALLOC( NewSize )) == NULL ) {
+
+ return FALSE;
+ }
+
+ // Note that, if we supply the memory, BITVECTOR::Initialize
+ // cannot fail, so we don't check its return value.
+
+ _Bitmap.Initialize( NewSize * 8,
+ RESET,
+ (PPT)NewBitmapData );
+
+ if( NewNumberOfClusters < _NumberOfClusters ) {
+
+ // Copy the part of the old bitmap that we wish to
+ // preserve into the new bitmap.
+
+ memcpy( NewBitmapData,
+ _BitmapData,
+ NewSize );
+
+ } else {
+
+ // Copy the old bitmap into the new bitmap, and then
+ // mark all the newly claimed space as unused.
+
+ memcpy( NewBitmapData,
+ _BitmapData,
+ _BitmapSize );
+
+ SetFree( _NumberOfClusters,
+ NewNumberOfClusters - _NumberOfClusters );
+ }
+
+ FREE( _BitmapData );
+ _BitmapData = NewBitmapData;
+
+ _BitmapSize = NewSize;
+ _NumberOfClusters = NewNumberOfClusters;
+
+ // Make sure the padding bits are reset.
+
+ _Bitmap.ResetBit( _NumberOfClusters.GetLowPart(),
+ _BitmapSize * 8 - _NumberOfClusters.GetLowPart() );
+
+ return TRUE;
+}
+
+
+VOID
+NTFS_BITMAP::SetGrowable(
+ IN BOOLEAN Growable
+ )
+/*++
+
+Routine Description:
+
+ This method changes whether the bitmap is growable or not. This
+ primarily effects the padding bits, if any, at the end of the bitmap.
+ They are clear for growable bitmaps and set for non-growable ones.
+
+Arguments:
+
+ Growable -- Whether the bitmap should be growable.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ if (Growable) {
+
+ _Bitmap.ResetBit( _NumberOfClusters.GetLowPart(),
+ _BitmapSize * 8 - _NumberOfClusters.GetLowPart() );
+ } else {
+
+ _Bitmap.SetBit( _NumberOfClusters.GetLowPart(),
+ _BitmapSize * 8 - _NumberOfClusters.GetLowPart() );
+
+ }
+}
diff --git a/private/utils/untfs/src/ntfschk.cxx b/private/utils/untfs/src/ntfschk.cxx
new file mode 100644
index 000000000..cdd9dd9b3
--- /dev/null
+++ b/private/utils/untfs/src/ntfschk.cxx
@@ -0,0 +1,6408 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ntfschk.cxx
+
+Abstract:
+
+ This module implements NTFS CHKDSK.
+
+Author:
+
+ Norbert P. Kusters (norbertk) 29-Jul-91
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "ntfssa.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+#include "ntfsbit.hxx"
+#include "attrcol.hxx"
+#include "frsstruc.hxx"
+#include "attrib.hxx"
+#include "attrrec.hxx"
+#include "attrlist.hxx"
+#include "list.hxx"
+#include "iterator.hxx"
+#include "attrdef.hxx"
+#include "extents.hxx"
+#include "mft.hxx"
+#include "mftref.hxx"
+#include "bootfile.hxx"
+#include "badfile.hxx"
+#include "mftfile.hxx"
+#include "numset.hxx"
+#include "ifssys.hxx"
+#include "indxtree.hxx"
+#include "upcase.hxx"
+#include "upfile.hxx"
+#include "frs.hxx"
+#include "digraph.hxx"
+#include "logfile.hxx"
+#include "rcache.hxx"
+#include "ifsentry.hxx"
+
+// This global variable used by CHKDSK to compute the largest
+// LSN on the volume.
+
+LSN LargestLsnEncountered;
+
+BOOLEAN
+EnsureValidFileAttributes(
+ IN OUT PNTFS_FILE_RECORD_SEGMENT Frs,
+ IN OUT PNTFS_INDEX_TREE ParentIndex,
+ OUT PBOOLEAN SaveIndex,
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+);
+
+BOOLEAN
+UpdateChkdskInfo(
+ IN OUT PNTFS_FRS_STRUCTURE Frs,
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the necessary changes to the chkdsk information
+ for this FRS.
+
+Arguments:
+
+ Frs - Supplies the base FRS.
+ ChkdskInfo - Supplies the current chkdsk information.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG file_number;
+ BOOLEAN is_multi;
+ NTFS_ATTRIBUTE_LIST attr_list;
+ PATTRIBUTE_RECORD_HEADER precord;
+ ULONG i;
+ ATTRIBUTE_TYPE_CODE type_code;
+ VCN vcn;
+ MFT_SEGMENT_REFERENCE seg_ref;
+ USHORT tag;
+ DSTRING name;
+ ULONG name_length;
+ BOOLEAN data_present;
+
+ file_number = Frs->QueryFileNumber().GetLowPart();
+
+ ChkdskInfo->ReferenceCount[file_number] =
+ (SHORT) Frs->QueryReferenceCount();
+
+ if (Frs->QueryReferenceCount() == 0) {
+
+ if (!ChkdskInfo->FilesWithNoReferences.Add(file_number)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ data_present = FALSE;
+ is_multi = Frs->QueryAttributeList(&attr_list) && attr_list.ReadList();
+ precord = NULL;
+ for (i = 0; ; i++) {
+
+ if (is_multi) {
+ if (!attr_list.QueryEntry(i, &type_code, &vcn, &seg_ref, &tag,
+ &name)) {
+ break;
+ }
+ name_length = name.QueryChCount();
+ } else {
+ if (!(precord = (PATTRIBUTE_RECORD_HEADER)
+ Frs->GetNextAttributeRecord(precord))) {
+ break;
+ }
+ type_code = precord->TypeCode;
+ name_length = precord->NameLength;
+ }
+
+ switch (type_code) {
+
+ case $FILE_NAME:
+ ChkdskInfo->NumFileNames[file_number]++;
+ break;
+
+ case $INDEX_ROOT:
+ case $INDEX_ALLOCATION:
+ ChkdskInfo->FilesWithIndices.SetAllocated(file_number, 1);
+ ChkdskInfo->CountFilesWithIndices += 1;
+ break;
+
+ case $OBJECT_ID:
+ if (ChkdskInfo->major >= 2 &&
+ !ChkdskInfo->FilesWithObjectId.Add(file_number)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ break;
+
+ case $EA_INFORMATION:
+ case $EA_DATA:
+ if (!ChkdskInfo->FilesWithEas.Add(file_number)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ break;
+
+ case $DATA:
+ if (!name_length) {
+ data_present = TRUE;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (!data_present) {
+
+ if (!ChkdskInfo->FilesWhoNeedData.Add(file_number)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+EnsureValidRootFileName(
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PNTFS_FILE_RECORD_SEGMENT Frs,
+ IN FILE_REFERENCE RootFileReference,
+ OUT PBOOLEAN Changes
+ )
+/*++
+
+Routine Description:
+
+ This method ensures that all file_names for the given file
+ point back to the given root-file-reference.
+
+Arguments:
+
+ ChkdskInfo - Supplies the current chkdsk info.
+ Frs - Supplies the Frs to verify.
+ RootFileReference - Supplies the file reference for the root directory.
+ Changes - Returns whether or not there were changes to
+ the file record.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG i;
+ BOOLEAN error;
+ NTFS_ATTRIBUTE attribute;
+ PFILE_NAME p;
+ CHAR buffer[sizeof(FILE_NAME) + 20*sizeof(WCHAR)];
+ PFILE_NAME new_file_name = (PFILE_NAME) buffer;
+ DSTRING file_name_text;
+ BOOLEAN success;
+ ULONG file_number;
+
+ DebugAssert(Changes);
+ *Changes = FALSE;
+
+ file_number = Frs->QueryFileNumber().GetLowPart();
+ for (i = 0; Frs->QueryAttributeByOrdinal(&attribute, &error,
+ $FILE_NAME, i); i++) {
+
+ p = (PFILE_NAME) attribute.GetResidentValue();
+ DebugAssert(p);
+
+ // Remove any file-name that doesn't point back to the root.
+
+ if (!(p->ParentDirectory == RootFileReference)) {
+ *Changes = TRUE;
+ Frs->DeleteResidentAttribute($FILE_NAME, NULL, p,
+ attribute.QueryValueLength().GetLowPart(), &success);
+ if (ChkdskInfo)
+ ChkdskInfo->NumFileNames[file_number]--;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+EnsureSystemFilesInUse(
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine goes through all of the system files and ensures that
+ they are all in use. Any that are not in use are created the way
+ format would do it. Besides that this method makes sure that none
+ of the system files have file-names that point back to any directory
+ besides the root (file 5). Any offending file-names are tubed.
+
+Arguments:
+
+ ChkdskInfo - Supplies the current chkdsk info.
+ Mft - Supplies the MFT.
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG i;
+ NTFS_FILE_RECORD_SEGMENT frs;
+ FILE_REFERENCE root_file_reference;
+ BOOLEAN changes;
+
+ // First to the root index file since the others need to point back
+ // to it.
+
+ if (!frs.Initialize(ROOT_FILE_NAME_INDEX_NUMBER, Mft)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!frs.Read()) {
+ DebugAbort("Can't read a hotfixed system FRS");
+ return FALSE;
+ }
+
+ if (!frs.IsInUse()) {
+
+ ChkdskInfo->NumFileNames[ROOT_FILE_NAME_INDEX_NUMBER] = 1;
+
+ if (!frs.CreateSystemFile()) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (FixLevel != CheckOnly && !frs.Flush(NULL)) {
+ DebugAbort("can't write system file");
+ return FALSE;
+ }
+ }
+
+ root_file_reference = frs.QuerySegmentReference();
+
+ for (i = 0; i < FIRST_USER_FILE_NUMBER; i++) {
+
+ if (!frs.Initialize(i, Mft)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!frs.Read()) {
+ DebugAbort("Can't read a hotfixed system FRS");
+ return FALSE;
+ }
+
+ if (i != SECURITY_TABLE_NUMBER || ChkdskInfo->major < 2) {
+ if (!frs.IsInUse()) {
+
+ ChkdskInfo->NumFileNames[i] = 1;
+
+ if (!frs.CreateSystemFile(ChkdskInfo->major,
+ ChkdskInfo->minor)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (FixLevel != CheckOnly && !frs.Flush(NULL)) {
+ DebugAbort("can't write system file");
+ return FALSE;
+ }
+
+ // Mark this file for consideration when handing out free
+ // data attributes.
+
+ if (!ChkdskInfo->FilesWhoNeedData.Add(frs.QueryFileNumber())) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+ } else {
+ if (!frs.IsInUse()) {
+
+ ChkdskInfo->NumFileNames[i] = 1;
+
+ if (!frs.CreateSystemFile(ChkdskInfo->major,
+ ChkdskInfo->minor)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ frs.SetViewIndexPresent();
+
+ if (FixLevel != CheckOnly && !frs.Flush(NULL)) {
+ DebugAbort("can't write system file");
+ return FALSE;
+ }
+ } else if (!frs.IsViewIndexPresent()) {
+ frs.SetViewIndexPresent();
+
+ Message->Set(MSG_CHK_NTFS_FIX_FLAGS);
+ Message->Display("%d", SECURITY_TABLE_NUMBER);
+
+ if (FixLevel != CheckOnly && !frs.Flush(NULL)) {
+ DebugAbort("can't write system file");
+ return FALSE;
+ }
+ }
+ }
+
+
+ // Make sure that this file has no $FILE_NAME attribute
+ // who's parent is not the root directory.
+
+ if (!EnsureValidRootFileName(ChkdskInfo, &frs,
+ root_file_reference, &changes)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ ChkdskInfo->ReferenceCount[i] = frs.QueryReferenceCount();
+
+ if (changes) {
+
+ // Message->Set(MSG_CHK_NTFS_MISSING_SYSTEM_FILE_NAME);
+ // Message->Display("%d", frs.QueryFileNumber().GetLowPart());
+
+ if (FixLevel != CheckOnly && !frs.Flush(Mft->GetVolumeBitmap())) {
+ DebugAbort("can't write system file");
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_SA::CheckExtendSystemFiles(
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PNTFS_CHKDSK_REPORT ChkdskReport,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine goes through all of the files in \$Extend and make
+ sure they all exist, and are in use. Besides that this method
+ makes sure that none of the system files have file-names that
+ point back to any directory besides the \$Extend (file 0xB).
+ It also makes sure there the proper indices appear in each
+ of the files.
+
+Arguments:
+
+ ChkdskInfo - Supplies the current chkdsk info.
+ ChkdskReport - Supplies the current chkdsk report.
+ Mft - Supplies the MFT.
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG i;
+ NTFS_FILE_RECORD_SEGMENT frs;
+ NTFS_FILE_RECORD_SEGMENT parent_frs;
+ FILE_REFERENCE parent_file_reference;
+ BOOLEAN changes;
+ DSTRING index_name;
+ NTFS_INDEX_TREE parent_index;
+ NTFS_INDEX_TREE index;
+ BIG_INT file_number;
+ FILE_NAME file_name[2];
+ BOOLEAN parent_index_need_save;
+ BOOLEAN index_need_save;
+ BOOLEAN error;
+ PINDEX_ENTRY found_entry;
+ PNTFS_INDEX_BUFFER ContainingBuffer;
+ ULONG file_name_size;
+ NTFS_ATTRIBUTE attrib;
+ BOOLEAN diskErrorsFound;
+ BOOLEAN alloc_present;
+
+ //
+ // read in the $Extend FRS as parent
+ //
+
+ if (!parent_frs.Initialize(EXTEND_TABLE_NUMBER, Mft)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!parent_frs.Read()) {
+ DebugAbort("Can't read a hotfixed system FRS");
+ return FALSE;
+ }
+
+ parent_file_reference = parent_frs.QuerySegmentReference();
+
+ //
+ // Make sure the parent has an $I30 index
+ //
+
+ if (!index_name.Initialize(FileNameIndexNameData)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ parent_index_need_save = FALSE;
+ if (!parent_frs.IsIndexPresent() ||
+ !parent_index.Initialize(_drive,
+ QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ Mft->GetUpcaseTable(),
+ parent_frs.QuerySize()/2,
+ &parent_frs,
+ &index_name)) {
+
+ Message->Set(MSG_CHK_NTFS_CREATE_INDEX);
+ Message->Display("%W%d", &index_name, EXTEND_TABLE_NUMBER);
+
+ if (!parent_index.Initialize($FILE_NAME,
+ _drive,
+ QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ Mft->GetUpcaseTable(),
+ COLLATION_FILE_NAME,
+ SMALL_INDEX_BUFFER_SIZE,
+ parent_frs.QuerySize()/2,
+ &index_name)) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_SYSTEM_FILE);
+ Message->Display("%d", EXTEND_TABLE_NUMBER);
+ return FALSE;
+ }
+ parent_frs.SetIndexPresent();
+ parent_index_need_save = TRUE;
+ ChkdskReport->NumIndices += 1;
+ }
+
+ //
+ // now check the object id file
+ //
+
+ if (!index_name.Initialize(ObjectIdFileName)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!ChkdskInfo->ObjectIdFileNumber.GetLowPart() &&
+ !ChkdskInfo->ObjectIdFileNumber.GetHighPart()) {
+
+ Message->Set(MSG_CHK_NTFS_CREATE_OBJID);
+ Message->Display();
+
+ if (!Mft->AllocateFileRecordSegment(&file_number, FALSE)) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_OBJID);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!frs.Initialize(file_number, Mft)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!frs.CreateExtendSystemFile(&index_name,
+ FILE_SYSTEM_FILE | FILE_VIEW_INDEX_PRESENT)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ frs.SetReferenceCount(1);
+
+ if (FixLevel != CheckOnly && !frs.Flush(NULL)) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_OBJID);
+ Message->Display();
+ return FALSE;
+ }
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ ChkdskInfo->ObjectIdFileNumber = file_number;
+ } else {
+
+ file_number = ChkdskInfo->ObjectIdFileNumber;
+
+ if (!frs.Initialize(file_number, Mft)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!frs.Read()) {
+ Message->Set(MSG_CHK_NTFS_UNREADABLE_FRS);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!frs.IsSystemFile() || !frs.IsViewIndexPresent()) {
+ frs.SetSystemFile();
+ frs.SetViewIndexPresent();
+
+ Message->Set(MSG_CHK_NTFS_FIX_FLAGS);
+ Message->Display("%d", file_number.GetLowPart());
+
+ if (FixLevel != CheckOnly && !frs.Flush(NULL)) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_OBJID);
+ Message->Display();
+ return FALSE;
+ }
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ }
+
+ if (!EnsureValidFileAttributes(&frs,
+ &parent_index,
+ &parent_index_need_save,
+ ChkdskInfo,
+ Mft,
+ FixLevel,
+ Message))
+ return FALSE;
+ }
+
+ // Make sure that this file has no $FILE_NAME attribute
+ // who's parent is not the root directory.
+
+ if (!EnsureValidRootFileName(NULL,
+ &frs,
+ parent_file_reference,
+ &changes)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (changes) {
+
+ if (FixLevel != CheckOnly && !frs.Flush(Mft->GetVolumeBitmap())) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_OBJID);
+ Message->Display();
+ return FALSE;
+ }
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ }
+
+ // now make sure the $ObjId file name appears
+ // in the index entry of its parent
+
+ if (!frs.QueryAttribute(&attrib, &error, $FILE_NAME)) {
+ DebugPrint("Unable to locate $FILE_NAME attribute in the object id FRS\n");
+ return FALSE;
+ }
+
+ DebugAssert(attrib.QueryValueLength().GetHighPart() == 0);
+
+ file_name_size = attrib.QueryValueLength().GetLowPart();
+
+ DebugAssert(file_name_size <= sizeof(FILE_NAME)*2);
+
+ memcpy(file_name, attrib.GetResidentValue(), file_name_size);
+
+ if (!parent_index.QueryEntry(file_name_size,
+ &file_name,
+ 0,
+ &found_entry,
+ &ContainingBuffer,
+ &error)) {
+
+ Message->Set(MSG_CHK_NTFS_INSERTING_INDEX_ENTRY);
+ Message->Display("%d%W", EXTEND_TABLE_NUMBER,
+ parent_index.GetName());
+
+ if (!parent_index.InsertEntry(file_name_size,
+ &file_name,
+ frs.QuerySegmentReference())) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_INDEX);
+ Message->Display("%d%W", EXTEND_TABLE_NUMBER, parent_index.GetName());
+ return FALSE;
+ }
+ parent_index_need_save = TRUE;
+ }
+
+ //
+ // now check the index of $ObjectId
+ //
+
+ if (!index_name.Initialize(ObjectIdIndexNameData)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!index.Initialize(_drive,
+ QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ Mft->GetUpcaseTable(),
+ frs.QuerySize()/2,
+ &frs,
+ &index_name)) {
+
+ Message->Set(MSG_CHK_NTFS_CREATE_INDEX);
+ Message->Display("%W%d", &index_name, frs.QueryFileNumber());
+
+ if (!index.Initialize(0,
+ _drive,
+ QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ Mft->GetUpcaseTable(),
+ COLLATION_ULONGS,
+ SMALL_INDEX_BUFFER_SIZE,
+ frs.QuerySize()/2,
+ &index_name)) {
+ Message->Set(MSG_CHK_NTFS_CANT_CREATE_INDEX);
+ Message->Display("%W%d", &index_name,
+ frs.QueryFileNumber().GetLowPart());
+ return FALSE;
+ }
+ if (FixLevel != CheckOnly &&
+ !index.Save(&frs)) {
+ Message->Set(MSG_CHK_NTFS_CANT_CREATE_INDEX);
+ Message->Display("%W%d", &index_name,
+ frs.QueryFileNumber().GetLowPart());
+ return FALSE;
+ }
+ if (!ValidateEntriesInObjIdIndex(&index,
+ &frs,
+ ChkdskInfo,
+ &changes,
+ Mft,
+ FixLevel,
+ Message,
+ &diskErrorsFound)) {
+ return FALSE;
+ }
+ if (FixLevel != CheckOnly &&
+ !frs.Flush(Mft->GetVolumeBitmap())) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_OBJID);
+ Message->Display();
+ return FALSE;
+ }
+ ChkdskReport->NumIndices += 1;
+ alloc_present = frs.QueryAttribute(&attrib,
+ &error,
+ $INDEX_ALLOCATION,
+ &index_name);
+
+ if (!alloc_present && error) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ if (alloc_present) {
+ ChkdskReport->BytesInIndices += attrib.QueryAllocatedLength();
+ }
+ }
+
+ //
+ // now check the quota file
+ //
+
+ if (!index_name.Initialize(QuotaFileName)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!ChkdskInfo->QuotaFileNumber.GetLowPart() &&
+ !ChkdskInfo->QuotaFileNumber.GetHighPart()) {
+
+ Message->Set(MSG_CHK_NTFS_CREATE_QUOTA);
+ Message->Display();
+
+ if (!Mft->AllocateFileRecordSegment(&file_number, FALSE)) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_QUOTA);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!frs.Initialize(file_number, Mft)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!frs.CreateExtendSystemFile(&index_name,
+ FILE_SYSTEM_FILE | FILE_VIEW_INDEX_PRESENT)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ frs.SetReferenceCount(1);
+
+ if (FixLevel != CheckOnly && !frs.Flush(NULL)) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_QUOTA);
+ Message->Display();
+ return FALSE;
+ }
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ ChkdskInfo->QuotaFileNumber = file_number;
+ } else {
+
+ file_number = ChkdskInfo->QuotaFileNumber;
+
+ if (!frs.Initialize(file_number, Mft)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!frs.Read()) {
+ Message->Set(MSG_CHK_NTFS_UNREADABLE_FRS);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!frs.IsSystemFile() || !frs.IsViewIndexPresent()) {
+ frs.SetSystemFile();
+ frs.SetViewIndexPresent();
+
+ Message->Set(MSG_CHK_NTFS_FIX_FLAGS);
+ Message->Display("%d", file_number.GetLowPart());
+
+ if (FixLevel != CheckOnly && !frs.Flush(NULL)) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_QUOTA);
+ Message->Display();
+ return FALSE;
+ }
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ }
+
+ if (!EnsureValidFileAttributes(&frs,
+ &parent_index,
+ &parent_index_need_save,
+ ChkdskInfo,
+ Mft,
+ FixLevel,
+ Message))
+ return FALSE;
+ }
+
+ // Make sure that this file has no $FILE_NAME attribute
+ // who's parent is not the root directory.
+
+ if (!EnsureValidRootFileName(NULL,
+ &frs,
+ parent_file_reference,
+ &changes)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (changes) {
+
+ if (FixLevel != CheckOnly && !frs.Flush(Mft->GetVolumeBitmap())) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_QUOTA);
+ Message->Display();
+ return FALSE;
+ }
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ }
+
+ // now make sure the $Quota file name appears
+ // in the index entry of its parent
+
+ if (!frs.QueryAttribute(&attrib, &error, $FILE_NAME)) {
+ DebugPrint("Unable to locate $FILE_NAME attribute in the quota FRS\n");
+ return FALSE;
+ }
+
+ DebugAssert(attrib.QueryValueLength().GetHighPart() == 0);
+
+ file_name_size = attrib.QueryValueLength().GetLowPart();
+
+ DebugAssert(file_name_size <= sizeof(FILE_NAME)*2);
+
+ memcpy(file_name, attrib.GetResidentValue(), file_name_size);
+
+ if (!parent_index.QueryEntry(file_name_size,
+ &file_name,
+ 0,
+ &found_entry,
+ &ContainingBuffer,
+ &error)) {
+
+ Message->Set(MSG_CHK_NTFS_INSERTING_INDEX_ENTRY);
+ Message->Display("%d%W", EXTEND_TABLE_NUMBER,
+ parent_index.GetName());
+
+ if (!parent_index.InsertEntry(file_name_size,
+ &file_name,
+ frs.QuerySegmentReference())) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_INDEX);
+ Message->Display("%d%W", EXTEND_TABLE_NUMBER, parent_index.GetName());
+ return FALSE;
+ }
+ parent_index_need_save = TRUE;
+ }
+
+ //
+ // now check the indices of $Quota
+ //
+
+ //
+ // Check the Sid to Userid index first for $Quota
+ //
+
+ if (!index_name.Initialize(Sid2UseridQuotaNameData)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!index.Initialize(_drive,
+ QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ Mft->GetUpcaseTable(),
+ frs.QuerySize()/2,
+ &frs,
+ &index_name)) {
+
+ Message->Set(MSG_CHK_NTFS_CREATE_INDEX);
+ Message->Display("%W%d", &index_name,
+ frs.QueryFileNumber().GetLowPart());
+
+ if (!index.Initialize(0,
+ _drive,
+ QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ Mft->GetUpcaseTable(),
+ COLLATION_SID,
+ SMALL_INDEX_BUFFER_SIZE,
+ frs.QuerySize()/2,
+ &index_name)) {
+ Message->Set(MSG_CHK_NTFS_CANT_CREATE_INDEX);
+ Message->Display("%W%d", &index_name,
+ frs.QueryFileNumber().GetLowPart());
+ return FALSE;
+ }
+ if (FixLevel != CheckOnly &&
+ !index.Save(&frs)) {
+ Message->Set(MSG_CHK_NTFS_CANT_CREATE_INDEX);
+ Message->Display("%W%d", &index_name,
+ frs.QueryFileNumber().GetLowPart());
+ return FALSE;
+ }
+ if (FixLevel != CheckOnly &&
+ !frs.Flush(Mft->GetVolumeBitmap())) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_QUOTA);
+ Message->Display();
+ return FALSE;
+ }
+ ChkdskReport->NumIndices += 1;
+ }
+
+ //
+ // now check the Userid to Sid index for $Quota
+ //
+
+ if (!index_name.Initialize(Userid2SidQuotaNameData)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!index.Initialize(_drive,
+ QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ Mft->GetUpcaseTable(),
+ frs.QuerySize()/2,
+ &frs,
+ &index_name)) {
+
+ Message->Set(MSG_CHK_NTFS_CREATE_INDEX);
+ Message->Display("%W%d", &index_name,
+ frs.QueryFileNumber().GetLowPart());
+
+ if (!index.Initialize(0,
+ _drive,
+ QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ Mft->GetUpcaseTable(),
+ COLLATION_ULONG,
+ SMALL_INDEX_BUFFER_SIZE,
+ frs.QuerySize()/2,
+ &index_name)) {
+ Message->Set(MSG_CHK_NTFS_CANT_CREATE_INDEX);
+ Message->Display("%W%d", &index_name,
+ frs.QueryFileNumber().GetLowPart());
+ return FALSE;
+ }
+ if (FixLevel != CheckOnly &&
+ !index.Save(&frs)) {
+ Message->Set(MSG_CHK_NTFS_CANT_CREATE_INDEX);
+ Message->Display("%W%d", &index_name,
+ frs.QueryFileNumber().GetLowPart());
+ return FALSE;
+ }
+ switch (frs.VerifyAndFixQuotaDefaultId(Mft->GetVolumeBitmap(),
+ FixLevel == CheckOnly)) {
+ case NTFS_QUOTA_INDEX_FOUND:
+ DebugAssert(FALSE);
+ break;
+
+ case NTFS_QUOTA_INDEX_INSERTED:
+ case NTFS_QUOTA_DEFAULT_ENTRY_MISSING:
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ Message->Set(MSG_CHK_NTFS_DEFAULT_QUOTA_ENTRY_MISSING);
+ Message->Display("%d%W",
+ frs.QueryFileNumber().GetLowPart(),
+ &index_name);
+ break;
+
+ case NTFS_QUOTA_INDEX_NOT_FOUND:
+ if (FixLevel != CheckOnly) {
+ DebugAssert(FALSE);
+ return FALSE;
+ }
+ break;
+
+ case NTFS_QUOTA_ERROR:
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+
+ case NTFS_QUOTA_INSERT_FAILED:
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_COULD_NOT_FIX;
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_INDEX);
+ Message->Display("%d%W",
+ frs.QueryFileNumber().GetLowPart(),
+ index_name);
+ return FALSE;
+ }
+
+ if (FixLevel != CheckOnly &&
+ !frs.Flush(Mft->GetVolumeBitmap())) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_QUOTA);
+ Message->Display();
+ return FALSE;
+ }
+ ChkdskReport->NumIndices += 1;
+ alloc_present = frs.QueryAttribute(&attrib,
+ &error,
+ $INDEX_ALLOCATION,
+ &index_name);
+
+ if (!alloc_present && error) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ if (alloc_present) {
+ ChkdskReport->BytesInIndices += attrib.QueryAllocatedLength();
+ }
+ }
+
+ if (parent_index_need_save) {
+ if (FixLevel != CheckOnly &&
+ (!parent_index.Save(&parent_frs) ||
+ !parent_frs.Flush(Mft->GetVolumeBitmap()))) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_SYSTEM_FILE);
+ Message->Display();
+ return FALSE;
+ }
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+MarkQuotaOutOfDate(
+ IN PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN PNTFS_MASTER_FILE_TABLE Mft,
+ IN BOOLEAN FixLevel,
+ IN OUT PMESSAGE Message
+)
+{
+ NTFS_FILE_RECORD_SEGMENT frs;
+ DSTRING index_name;
+ PCINDEX_ENTRY index_entry;
+ PQUOTA_USER_DATA QuotaUserData;
+ NTFS_INDEX_TREE index;
+ ULONG depth;
+ BOOLEAN error;
+ NTFS_ATTRIBUTE attrib;
+
+ if (ChkdskInfo->QuotaFileNumber.GetLowPart() == 0 &&
+ ChkdskInfo->QuotaFileNumber.GetHighPart() == 0) {
+ DebugPrint("Quota file number not found. Please rebuild.\n");
+ return TRUE;
+ }
+
+ if (!frs.Initialize(ChkdskInfo->QuotaFileNumber, Mft)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ if (!frs.Read()) {
+ DebugAbort("Previously readable FRS is no longer readable");
+ return FALSE;
+ }
+ if (!index_name.Initialize(Userid2SidQuotaNameData)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ // Check to see if the index exists
+
+ if (!frs.QueryAttribute(&attrib,
+ &error,
+ $INDEX_ROOT,
+ &index_name))
+ return TRUE; // does nothing as the index does not exist
+
+ if (!index.Initialize(frs.GetDrive(),
+ frs.QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ Mft->GetUpcaseTable(),
+ frs.QuerySize()/2,
+ &frs,
+ &index_name)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ // Get the first entry - that's the default entry
+
+ index.ResetIterator();
+ if (!(index_entry = index.GetNext(&depth, &error))) {
+ DebugPrintf("Default Quota Index does not exist");
+ return FALSE;
+ }
+
+ if (*((ULONG*)GetIndexEntryValue(index_entry)) != QUOTA_DEFAULTS_ID) {
+ DebugPrintf("Default Quota Index not at the beginning of index");
+ return FALSE;
+ }
+ QuotaUserData = (PQUOTA_USER_DATA)((char*)GetIndexEntryValue(index_entry) + sizeof(ULONG));
+ QuotaUserData->QuotaFlags |= QUOTA_FLAG_OUT_OF_DATE;
+ if (FixLevel != CheckOnly &&
+ (!index.WriteCurrentEntry() ||
+ !index.Save(&frs) ||
+ !frs.Flush(Mft->GetVolumeBitmap()))) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ return TRUE;
+}
+
+BOOLEAN
+ValidateEa(
+ IN PNTFS_FILE_RECORD_SEGMENT Frs,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine checks out the given file for any EA related attributes.
+ It then makes sure that these are correct. It will make minor
+ corrections to the EA_INFORMATION attribute but beyond that it
+ will tube the EA attributes if anything is bad.
+
+Arguments:
+
+ Frs - Supplies the file with the alleged EAs.
+ VolumeBitmap - Supplies the volume bitmap.
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ // Greater than theoretical upper bound for $EA_DATA attribute.
+ CONST MaxEaDataSize = 256*1024;
+
+ NTFS_ATTRIBUTE ea_info;
+ NTFS_ATTRIBUTE ea_data;
+ HMEM data_hmem;
+ ULONG data_length;
+ BOOLEAN error;
+ BOOLEAN tube;
+ EA_INFORMATION disk_info;
+ EA_INFORMATION real_info;
+ PPACKED_EA pea;
+ PULONG plength;
+ ULONG packed_total, packed_length;
+ ULONG need_ea_count;
+ ULONG unpacked_total, unpacked_length;
+ PCHAR pend;
+ ULONG num_bytes;
+ BOOLEAN data_present, info_present;
+
+ tube = FALSE;
+
+ data_present = Frs->QueryAttribute(&ea_data, &error, $EA_DATA);
+ if (!data_present && error) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ info_present = Frs->QueryAttribute(&ea_info, &error, $EA_INFORMATION);
+ if (!info_present && error) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!info_present && !data_present) {
+
+ // There are no EAs here.
+ return TRUE;
+ }
+
+
+ if (!info_present || !data_present) {
+
+ tube = TRUE;
+
+ DebugPrintf("UNTFS: EA_INFO XOR EA_DATA in file 0x%X\n",
+ Frs->QueryFileNumber().GetLowPart());
+ }
+
+ if (!tube) {
+
+ data_length = ea_data.QueryValueLength().GetLowPart();
+
+ if (ea_info.QueryValueLength() < sizeof(EA_INFORMATION) ||
+ ea_info.QueryValueLength().GetHighPart() != 0 ||
+ ea_data.QueryValueLength().GetHighPart() != 0 ||
+ data_length > MaxEaDataSize) {
+
+ tube = TRUE;
+
+ DebugPrintf("UNTFS: Bad EA info value length in file 0x%X\n",
+ Frs->QueryFileNumber().GetLowPart());
+ }
+ }
+
+ if (!tube) {
+
+ if (!data_hmem.Initialize() ||
+ !data_hmem.Acquire(data_length)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!ea_info.Read(&disk_info,
+ 0, sizeof(EA_INFORMATION), &num_bytes) ||
+ num_bytes != sizeof(EA_INFORMATION) ||
+ !ea_data.Read(data_hmem.GetBuf(),
+ 0, data_length, &num_bytes) ||
+ num_bytes != data_length) {
+
+ tube = TRUE;
+
+ DebugPrintf("UNTFS: EA too small in file 0x%X\n",
+ Frs->QueryFileNumber().GetLowPart());
+ }
+ }
+
+ if (!tube) {
+
+ plength = (PULONG) data_hmem.GetBuf();
+
+ pend = (PCHAR) data_hmem.GetBuf() + data_length;
+
+ packed_total = 0;
+ need_ea_count = 0;
+ unpacked_total = 0;
+
+ while ((PCHAR) plength < pend) {
+
+ if ((PCHAR) plength + sizeof(ULONG) + sizeof(PACKED_EA) > pend) {
+
+ tube = TRUE;
+ DebugPrintf("UNTFS: Corrupt EA set. File 0x%X\n",
+ Frs->QueryFileNumber().GetLowPart());
+ break;
+ }
+
+ pea = (PPACKED_EA) ((PCHAR) plength + sizeof(ULONG));
+
+ packed_length = sizeof(PACKED_EA) + pea->NameSize +
+ pea->ValueSize[0] + (pea->ValueSize[1]<<8);
+
+ unpacked_length = sizeof(ULONG) + DwordAlign(packed_length);
+
+ packed_total += packed_length;
+ unpacked_total += unpacked_length;
+ if (pea->Flag & EA_FLAG_NEED) {
+ need_ea_count++;
+ }
+
+ if (unpacked_total > data_length ||
+ pea->Name[pea->NameSize] != 0) {
+
+ tube = TRUE;
+ DebugPrintf("UNTFS: EA name in set is missing NULL. File 0x%X\n",
+ Frs->QueryFileNumber().GetLowPart());
+ break;
+ }
+
+ if (*plength != unpacked_length) {
+
+ tube = TRUE;
+ DebugPrintf("UNTFS: Bad unpacked length field in EA set. File 0x%X\n",
+ Frs->QueryFileNumber().GetLowPart());
+ break;
+ }
+
+ plength = (PULONG) ((PCHAR) plength + unpacked_length);
+ }
+
+ if ((packed_total>>(8*sizeof(USHORT))) != 0) {
+
+ tube = TRUE;
+ DebugPrintf("UNTFS: . File 0x%X\n",
+ Frs->QueryFileNumber().GetLowPart());
+ }
+ }
+
+ if (!tube) {
+
+ real_info.PackedEaSize = (USHORT)packed_total;
+ real_info.NeedEaCount = (USHORT)need_ea_count;
+ real_info.UnpackedEaSize = unpacked_total;
+
+ if (memcmp(&real_info, &disk_info, sizeof(EA_INFORMATION))) {
+
+ Message->Set(MSG_CHK_NTFS_CORRECTING_EA);
+ Message->Display("%d", Frs->QueryFileNumber().GetLowPart());
+ DebugPrintf("UNTFS: Incorrect EA information. File 0x%x\n",
+ Frs->QueryFileNumber().GetLowPart());
+
+ if (FixLevel != CheckOnly) {
+
+ if (!ea_info.Write(&real_info, 0, sizeof(EA_INFORMATION),
+ &num_bytes, NULL) ||
+ num_bytes != sizeof(EA_INFORMATION) ||
+ !ea_info.InsertIntoFile(Frs, VolumeBitmap)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+ }
+ }
+
+
+ if (tube) {
+
+ Message->Set(MSG_CHK_NTFS_DELETING_CORRUPT_EA_SET);
+ Message->Display("%d", Frs->QueryFileNumber().GetLowPart());
+
+ if (data_present) {
+ ea_data.Resize(0, VolumeBitmap);
+ Frs->PurgeAttribute($EA_DATA);
+ }
+ if (info_present) {
+ ea_info.Resize(0, VolumeBitmap);
+ Frs->PurgeAttribute($EA_INFORMATION);
+ }
+ }
+
+ if (FixLevel != CheckOnly && !Frs->Flush(VolumeBitmap)) {
+
+ DebugAbort("Can't write it.");
+ return FALSE;
+ }
+
+
+ return TRUE;
+}
+
+
+BOOLEAN
+ValidateEas(
+ IN PCNUMBER_SET FilesWithEas,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine validates all of the EAs on the volume.
+
+Arguments:
+
+ FilesWithEas - Supplies a list of all the files with EAs.
+ Mft - Supplies the MFT.
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_FILE_RECORD_SEGMENT frs;
+ BIG_INT i, l;
+
+ l = FilesWithEas->QueryCardinality();
+ for (i = 0; i < l; i += 1) {
+
+ if (!frs.Initialize(FilesWithEas->QueryNumber(i), Mft)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!frs.Read()) {
+ DebugAbort("Previously readable now unreadable");
+ continue;
+ }
+
+ if (!ValidateEa(&frs, Mft->GetVolumeBitmap(), FixLevel, Message)) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+NTFS_SA::CheckAllForData(
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine makes sure that all of the files in the list
+ of files that don't have unnamed data attributes either
+ get them or aren't supposed to have them anyway.
+
+Arguments:
+
+ ChkdskInfo - Supplies the current chkdsk information.
+ Mft - Supplies the MFT.
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_FILE_RECORD_SEGMENT frs;
+ ULONG i, n;
+ ULONG file_number;
+ NTFS_ATTRIBUTE data_attribute;
+
+
+ // Compute the number of files to examine.
+
+ n = ChkdskInfo->FilesWhoNeedData.QueryCardinality().GetLowPart();
+
+ if (!n) {
+ return TRUE;
+ }
+
+
+ // Create an empty unnamed data attribute.
+
+ if (!data_attribute.Initialize(_drive,
+ QueryClusterFactor(),
+ NULL,
+ 0,
+ $DATA)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+
+ // Ensure that every file in the list either has a $DATA attribute
+ // or is an directory.
+
+ for (i = 0; i < n; i++) {
+
+ file_number = ChkdskInfo->FilesWhoNeedData.QueryNumber(i).GetLowPart();
+
+ if (!frs.Initialize(file_number, Mft) ||
+ !frs.Read()) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (frs.IsIndexPresent() || frs.IsAttributePresent($DATA)) {
+ continue;
+ }
+
+ Message->Set(MSG_CHK_NTFS_MISSING_DATA_ATTRIBUTE);
+ Message->Display("%d", file_number);
+
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+
+ if (!data_attribute.InsertIntoFile(&frs, Mft->GetVolumeBitmap())) {
+ Message->Set(MSG_CHK_NTFS_CANT_PUT_DATA_ATTRIBUTE);
+ Message->Display();
+ }
+
+ if (FixLevel != CheckOnly && !frs.Flush(Mft->GetVolumeBitmap())) {
+ Message->Set(MSG_CHK_NTFS_CANT_PUT_DATA_ATTRIBUTE);
+ Message->Display();
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+ResolveCrossLink(
+ IN PCNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN OUT PNUMBER_SET BadClusters,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine resolved the cross-link specified in the
+ 'ChkdskInfo', if any. The cross-link is resolved by
+ copying if possible.
+
+Arguments:
+
+ ChkdskInfo - Supplies the cross-link information.
+ Mft - Supplies the master file table.
+ FixLevel - Supplies the fix-up level.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_FILE_RECORD_SEGMENT frs;
+ NTFS_ATTRIBUTE attr;
+ PNTFS_ATTRIBUTE pattribute;
+ BOOLEAN error;
+ VCN vcn;
+ LCN lcn;
+ BIG_INT run_length;
+ VCN hotfix_vcn;
+ LCN hotfix_lcn, hotfix_last;
+ BIG_INT hotfix_length;
+ PVOID hotfix_buffer;
+ ULONG cluster_size;
+ ULONG bytes_read, hotfix_bytes;
+
+ if (!ChkdskInfo->CrossLinkYet) {
+ return TRUE;
+ }
+
+ Message->Set(MSG_CHK_NTFS_CORRECTING_CROSS_LINK);
+ Message->Display("%d", ChkdskInfo->CrossLinkedFile);
+
+ if (!frs.Initialize(ChkdskInfo->CrossLinkedFile, Mft) ||
+ !frs.Read()) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (ChkdskInfo->CrossLinkedFile == 0 &&
+ ChkdskInfo->CrossLinkedAttribute == $DATA &&
+ ChkdskInfo->CrossLinkedName.QueryChCount() == 0) {
+
+ pattribute = Mft->GetDataAttribute();
+
+ } else {
+
+ if (!frs.QueryAttribute(&attr, &error,
+ ChkdskInfo->CrossLinkedAttribute,
+ &ChkdskInfo->CrossLinkedName)) {
+
+ if (error) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ // If the attribute is no longer there, that's ok, because
+ // it may have been corrupt.
+
+ return TRUE;
+ }
+
+ pattribute = &attr;
+ }
+
+
+ // Figure out which VCN's map to the given CrossLinked LCN's
+ // and hotfix those VCN's using the hotfix routine.
+
+ for (vcn = 0;
+ pattribute->QueryLcnFromVcn(vcn, &lcn, &run_length);
+ vcn += run_length) {
+
+ if (lcn == LCN_NOT_PRESENT) {
+ continue;
+ }
+
+ if (lcn < ChkdskInfo->CrossLinkStart) {
+ hotfix_lcn = ChkdskInfo->CrossLinkStart;
+ } else {
+ hotfix_lcn = lcn;
+ }
+ if (lcn + run_length > ChkdskInfo->CrossLinkStart +
+ ChkdskInfo->CrossLinkLength) {
+ hotfix_last = ChkdskInfo->CrossLinkStart +
+ ChkdskInfo->CrossLinkLength;
+ } else {
+ hotfix_last = lcn + run_length;
+ }
+
+ if (hotfix_last <= hotfix_lcn) {
+ continue;
+ }
+
+ hotfix_length = hotfix_last - hotfix_lcn;
+ hotfix_vcn = vcn + (hotfix_lcn - lcn);
+ cluster_size = Mft->QueryClusterFactor()*
+ Mft->GetDataAttribute()->GetDrive()->QuerySectorSize();
+ hotfix_bytes = hotfix_length.GetLowPart()*cluster_size;
+
+ // Before hotfixing the cross-linked data, read in the
+ // data into a buffer.
+
+ if (!(hotfix_buffer = MALLOC(hotfix_bytes))) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ memset(hotfix_buffer, 0, hotfix_bytes);
+ pattribute->Read(hotfix_buffer,
+ hotfix_vcn*cluster_size,
+ hotfix_bytes,
+ &bytes_read);
+
+ if (!pattribute->Hotfix(hotfix_vcn, hotfix_length,
+ Mft->GetVolumeBitmap(),
+ BadClusters)) {
+
+ // Purge the attribute since there isn't enough disk
+ // space to save it.
+
+ if (!frs.PurgeAttribute(ChkdskInfo->CrossLinkedAttribute,
+ &ChkdskInfo->CrossLinkedName)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(hotfix_buffer);
+ return FALSE;
+ }
+
+ if (FixLevel != CheckOnly &&
+ !frs.Flush(Mft->GetVolumeBitmap())) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(hotfix_buffer);
+ return FALSE;
+ }
+
+ FREE(hotfix_buffer);
+ return TRUE;
+ }
+
+ if (FixLevel != CheckOnly) {
+ if (!pattribute->Write(hotfix_buffer,
+ hotfix_vcn*cluster_size,
+ hotfix_bytes,
+ &bytes_read,
+ NULL) ||
+ bytes_read != hotfix_bytes ||
+ !pattribute->InsertIntoFile(&frs, Mft->GetVolumeBitmap()) ||
+ !frs.Flush(Mft->GetVolumeBitmap())) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(hotfix_buffer);
+ return FALSE;
+ }
+ }
+
+ FREE(hotfix_buffer);
+ }
+
+ return TRUE;
+}
+
+#if defined( _SETUP_LOADER_ )
+
+BOOLEAN
+RecoverAllUserFiles(
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN OUT PNUMBER_SET BadClusters,
+ IN OUT PMESSAGE Message
+ )
+{
+ return TRUE;
+}
+
+BOOLEAN
+RecoverFreeSpace(
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN OUT PNUMBER_SET BadClusters,
+ IN OUT PMESSAGE Message
+ )
+{
+ return TRUE;
+}
+
+#else // _SETUP_LOADER_ not defined
+
+BOOLEAN
+RecoverAllUserFiles(
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN OUT PNUMBER_SET BadClusters,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine traverses all of the files in the MFT and
+ verifies its attributes for bad clusters.
+
+Arguments:
+
+ Mft - Supplies the master file table.
+ BadClusters - Supplies the current list of bad clusters.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG i, n, percent_done;
+ NTFS_FILE_RECORD_SEGMENT frs;
+ ULONG num_bad;
+ BIG_INT bytes_recovered, total_bytes;
+
+
+ Message->Set(MSG_CHK_NTFS_VERIFYING_FILE_DATA, PROGRESS_MESSAGE);
+ Message->Display();
+
+ n = Mft->GetDataAttribute()->QueryValueLength().GetLowPart() / Mft->QueryFrsSize();
+
+ n -= FIRST_USER_FILE_NUMBER;
+
+ percent_done = 0;
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", percent_done)) {
+ return FALSE;
+ }
+
+ for (i = 0; i < n; i++) {
+
+ if (Mft->GetMftBitmap()->IsFree(i + FIRST_USER_FILE_NUMBER, 1)) {
+ continue;
+ }
+
+ if (!frs.Initialize(i + FIRST_USER_FILE_NUMBER, Mft) ||
+ !frs.Read()) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!frs.IsBase()) {
+ continue;
+ }
+
+ if (frs.RecoverFile(Mft->GetVolumeBitmap(), BadClusters,
+ &num_bad, &bytes_recovered, &total_bytes)) {
+
+ if (bytes_recovered < total_bytes) {
+ Message->Set(MSG_CHK_BAD_CLUSTERS_IN_FILE_SUCCESS);
+ Message->Display("%d", frs.QueryFileNumber().GetLowPart());
+ }
+ } else {
+ Message->Set(MSG_CHK_BAD_CLUSTERS_IN_FILE_FAILURE);
+ Message->Display("%d", frs.QueryFileNumber().GetLowPart());
+ }
+
+ if (i*100/n > percent_done) {
+ percent_done = i*100/n;
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", percent_done)) {
+ return FALSE;
+ }
+ }
+ }
+
+ percent_done = 100;
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", percent_done)) {
+ return FALSE;
+ }
+
+ Message->Set(MSG_CHK_NTFS_VERIFYING_FILE_DATA_COMPLETED, PROGRESS_MESSAGE);
+ Message->Display();
+
+ return TRUE;
+}
+
+
+BOOLEAN
+RecoverFreeSpace(
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN OUT PNUMBER_SET BadClusters,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies all of the unused clusters on the disk.
+ It adds any that are bad to the given bad cluster list.
+
+Arguments:
+
+ Mft - Supplies the master file table.
+ BadClusters - Supplies the current list of bad clusters.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PLOG_IO_DP_DRIVE drive;
+ PNTFS_BITMAP bitmap;
+ BIG_INT i, len, max_len;
+ ULONG percent_done;
+ BIG_INT checked, total_to_check;
+ NUMBER_SET bad_sectors;
+ ULONG cluster_factor;
+ BIG_INT start, run_length, next;
+ ULONG j;
+
+ Message->Set(MSG_CHK_RECOVERING_FREE_SPACE, PROGRESS_MESSAGE);
+ Message->Display();
+
+ drive = Mft->GetDataAttribute()->GetDrive();
+ bitmap = Mft->GetVolumeBitmap();
+ cluster_factor = Mft->QueryClusterFactor();
+ max_len = bitmap->QuerySize()/20 + 1;
+ total_to_check = bitmap->QueryFreeClusters();
+ checked = 0;
+
+ percent_done = 0;
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", percent_done)) {
+ return FALSE;
+ }
+
+ for (i = 0; i < bitmap->QuerySize(); i += 1) {
+
+ for (len = 0; i + len < bitmap->QuerySize() &&
+ bitmap->IsFree(i + len, 1) &&
+ len < max_len; len += 1) {
+ }
+
+ if (len > 0) {
+
+ if (!bad_sectors.Initialize() ||
+ !drive->Verify(i*cluster_factor,
+ len*cluster_factor,
+ &bad_sectors)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ for (j = 0; j < bad_sectors.QueryNumDisjointRanges(); j++) {
+
+ bad_sectors.QueryDisjointRange(j, &start, &run_length);
+ next = start + run_length;
+
+ // Adjust start and next to be on cluster boundaries.
+ start = start/cluster_factor;
+ next = (next - 1)/cluster_factor + 1;
+
+ // Add the bad clusters to the bad cluster list.
+ if (!BadClusters->Add(start, next - start)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ // Mark the bad clusters as allocated in the bitmap.
+ bitmap->SetAllocated(start, next - start);
+ }
+
+ checked += len;
+ i += len - 1;
+
+ if (100*checked/total_to_check > percent_done) {
+ percent_done = (100*checked/total_to_check).GetLowPart();
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", percent_done)) {
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ percent_done = 100;
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", percent_done)) {
+ return FALSE;
+ }
+
+ Message->Set(MSG_CHK_DONE_RECOVERING_FREE_SPACE, PROGRESS_MESSAGE);
+ Message->Display();
+
+ return TRUE;
+}
+
+#endif // _SETUP_LOADER_
+
+
+BOOLEAN
+NTFS_SA::DumpMessagesToFile(
+ IN PCWSTRING FileName,
+ IN OUT PNTFS_MFT_FILE MftFile,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This function dumps the logged messages remembered by the
+ message object into a file in the root directory.
+
+Arguments:
+
+ FileName -- Supplies the (unqualified) name of the file.
+ MftFile -- Supplies an initialized, active Mft File object
+ for the volume.
+ RootIndex -- Supplies the root index for the volume
+ RootIndexFile -- Supplies the FRS for the root index file.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ BYTE FileNameBuffer[NTFS_MAX_FILE_NAME_LENGTH * sizeof(WCHAR) + sizeof(FILE_NAME)];
+ HMEM LoggedMessageMem;
+ ULONG MessageDataLength;
+ NTFS_FILE_RECORD_SEGMENT TargetFrs;
+ NTFS_INDEX_TREE RootIndex;
+ NTFS_FILE_RECORD_SEGMENT RootIndexFrs;
+ NTFS_ATTRIBUTE DataAttribute;
+ STANDARD_INFORMATION StandardInformation;
+ MFT_SEGMENT_REFERENCE FileReference;
+ PNTFS_MASTER_FILE_TABLE Mft = MftFile->GetMasterFileTable();
+ PFILE_NAME SearchName = (PFILE_NAME)FileNameBuffer;
+ VCN FileNumber;
+ DSTRING FileNameIndexName;
+ ULONG BytesWritten;
+ BOOLEAN InternalError;
+
+ if( Mft == NULL ) {
+
+ return FALSE;
+ }
+
+ // Fetch the messages.
+ //
+ if( !LoggedMessageMem.Initialize() ||
+ !Message->QueryPackedLog( &LoggedMessageMem, &MessageDataLength ) ) {
+
+ DebugPrintf( "UNTFS: can't collect logged messages.\n" );
+ return FALSE;
+ }
+
+ // Fetch the volume's root index:
+ //
+ if( !RootIndexFrs.Initialize( ROOT_FILE_NAME_INDEX_NUMBER, MftFile ) ||
+ !RootIndexFrs.Read() ||
+ !FileNameIndexName.Initialize( FileNameIndexNameData ) ||
+ !RootIndex.Initialize( MftFile->GetDrive(),
+ MftFile->QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ MftFile->GetUpcaseTable(),
+ MftFile->QuerySize()/2,
+ &RootIndexFrs,
+ &FileNameIndexName ) ) {
+
+ return FALSE;
+ }
+
+ memset( FileNameBuffer, 0, sizeof(FileNameBuffer) );
+
+ SearchName->ParentDirectory = RootIndexFrs.QuerySegmentReference();
+ SearchName->FileNameLength = (UCHAR)FileName->QueryChCount();
+ SearchName->Flags = FILE_NAME_NTFS | FILE_NAME_DOS;
+
+ if( !FileName->QueryWSTR( 0, TO_END,
+ NtfsFileNameGetName( SearchName ),
+ NTFS_MAX_FILE_NAME_LENGTH ) ) {
+
+ DebugPrintf( "UNTFS: log file name is too long.\n" );
+ return FALSE;
+ }
+
+ DebugPrintf( "UNTFS: Searching for BOOTEX.LOG\n" );
+
+ if( RootIndex.QueryFileReference( NtfsFileNameGetLength( SearchName ),
+ SearchName,
+ 0,
+ &FileReference,
+ &InternalError ) ) {
+
+ DebugPrintf( "UNTFS: BOOTEX.LOG found.\n" );
+
+ FileNumber.Set( FileReference.LowPart, (LONG) FileReference.HighPart );
+
+ if( !TargetFrs.Initialize( FileNumber, Mft ) ||
+ !TargetFrs.Read() ||
+ !(FileReference == TargetFrs.QuerySegmentReference()) ||
+ !TargetFrs.QueryAttribute( &DataAttribute,
+ &InternalError,
+ $DATA ) ) {
+
+ // Either we were unable to initialize and read this FRS,
+ // or its segment reference didn't match (ie. the sequence
+ // number is wrong) or it didn't have a $DATA attribute
+ // (i.e. it's a directory or corrupt).
+
+ return FALSE;
+ }
+
+ } else if( InternalError ) {
+
+ DebugPrintf( "UNTFS: Error searching for BOOTEX.LOG.\n" );
+ return FALSE;
+
+ } else {
+
+ // This file does not exist--create it.
+ //
+ DebugPrintf( "UNTFS: BOOTEX.LOG not found.\n" );
+
+ memset( &StandardInformation, 0, sizeof(StandardInformation) );
+
+ if( !Mft->AllocateFileRecordSegment( &FileNumber, FALSE ) ||
+ !TargetFrs.Initialize( FileNumber, Mft ) ||
+ !TargetFrs.Create( &StandardInformation ) ||
+ !TargetFrs.AddFileNameAttribute( SearchName ) ||
+ !TargetFrs.AddSecurityDescriptor( NoAclCannedSd,
+ Mft->GetVolumeBitmap() ) ||
+ !RootIndex.InsertEntry( NtfsFileNameGetLength( SearchName ),
+ SearchName,
+ TargetFrs.QuerySegmentReference() ) ) {
+
+ DebugPrintf( "UNTFS: Can't create BOOTEX.LOG\n" );
+ return FALSE;
+ }
+
+ if( !DataAttribute.Initialize( MftFile->GetDrive(),
+ MftFile->QueryClusterFactor(),
+ NULL,
+ 0,
+ $DATA ) ) {
+
+ return FALSE;
+ }
+ }
+
+ if( !DataAttribute.Write( LoggedMessageMem.GetBuf(),
+ DataAttribute.QueryValueLength(),
+ MessageDataLength,
+ &BytesWritten,
+ Mft->GetVolumeBitmap() ) ) {
+
+ DebugPrintf( "UNTFS: Can't write logged message.\n" );
+ return FALSE;
+ }
+
+ if( !DataAttribute.InsertIntoFile( &TargetFrs, Mft->GetVolumeBitmap() ) ) {
+
+ // Insert failed--if it's resident, make it non-resident and
+ // try again.
+ //
+ if( !DataAttribute.IsResident() ||
+ !DataAttribute.MakeNonresident( Mft->GetVolumeBitmap() ) ||
+ !DataAttribute.InsertIntoFile( &TargetFrs,
+ Mft->GetVolumeBitmap() ) ) {
+
+ DebugPrintf( "UNTFS: Can't save BOOTEX.LOG's data attribute.\n" );
+ return FALSE;
+ }
+ }
+
+ if( !TargetFrs.Flush( Mft->GetVolumeBitmap(), &RootIndex ) ) {
+
+ DebugPrintf( "UNTFS: Can't flush BOOTEX.LOG.\n" );
+ return FALSE;
+ }
+
+ if( !RootIndex.Save( &RootIndexFrs ) ||
+ !RootIndexFrs.Flush( NULL ) ) {
+
+ DebugPrintf( "UNTFS: Can't flush root index after logging messages.\n" );
+ return FALSE;
+ }
+
+ MftFile->Flush();
+ return TRUE;
+}
+
+
+
+
+BOOLEAN
+NTFS_SA::VerifyAndFix(
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verbose,
+ IN BOOLEAN OnlyIfDirty,
+ IN BOOLEAN RecoverFree,
+ IN BOOLEAN RecoverAlloc,
+ IN BOOLEAN ResizeLogFile,
+ IN ULONG DesiredLogFileSize,
+ OUT PULONG ExitStatus,
+ IN PCWSTRING DriveLetter
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies and, if necessary, fixes an NTFS volume.
+
+Arguments:
+
+ FixLevel - Supplies the level of fixes that may be performed on
+ the disk.
+ Message - Supplies an outlet for messages.
+ Verbose - Supplies whether or not to be verbose.
+ OnlyIfDirty - Supplies whether or not to fix the volume if it is
+ not dirty.
+ RecoverFree - Tells whether to verify the unallocated clusters.
+ RecoverAlloc - Tells whether to verify the allocated clusters.
+ ResizeLogFile - Tells whether to resize the logfile.
+ DesiredLogFileSize - Supplies the desired logfile size in bytes, or 0 if
+ the logfile is to be resized to the default size.
+ ExitStatus - Returns an indication of how the checking went
+ DriveLetter - For autocheck, the letter for the volume we're checking
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_BITMAP mft_bitmap;
+ NTFS_BITMAP volume_bitmap;
+ NTFS_UPCASE_TABLE upcase_table;
+ NTFS_ATTRIBUTE mft_data;
+ BIG_INT num_frs, num_mft_bits;
+ BIG_INT volume_clusters;
+ NTFS_ATTRIBUTE_COLUMNS attribute_def_table;
+ NTFS_FRS_STRUCTURE frsstruc;
+ NTFS_FILE_RECORD_SEGMENT frs;
+ HMEM hmem;
+ VCN i;
+ NTFS_ATTRIBUTE_LIST attr_list;
+ BOOLEAN tube;
+ NUMBER_SET bad_clusters;
+ NTFS_MASTER_FILE_TABLE internal_mft;
+ NTFS_MFT_FILE mft_file;
+ NTFS_REFLECTED_MASTER_FILE_TABLE mft_ref;
+ NTFS_ATTRIBUTE_DEFINITION_TABLE attr_def_file;
+ NTFS_BOOT_FILE boot_file;
+ NTFS_UPCASE_FILE upcase_file;
+ NTFS_LOG_FILE log_file;
+ NTFS_BAD_CLUSTER_FILE bad_clus_file;
+ NTFS_FILE_RECORD_SEGMENT root_file;
+ NTFS_INDEX_TREE root_index;
+ VCN child_file_number;
+ NTFS_CHKDSK_REPORT chkdsk_report;
+ NTFS_CHKDSK_INFO chkdsk_info;
+ BIG_INT disk_size;
+ BIG_INT system_size;
+ BIG_INT free_clusters;
+ BIG_INT cluster_count;
+ ULONG cluster_size;
+ BIG_INT num_bad_clusters;
+ DIGRAPH directory_digraph;
+ BOOLEAN corrupt_volume;
+ USHORT volume_flags;
+ BOOLEAN volume_is_dirty;
+ BOOLEAN resize_log_file;
+ MFT_SEGMENT_REFERENCE seg_ref;
+ ULONG entry_index;
+ BOOLEAN disk_errors_found = FALSE;
+ DSTRING index_name;
+ ULONG percent_done;
+ UCHAR major, minor;
+ ULONG num_boot_clusters;
+ NTFS_ATTRIBUTE_RECORD attr_rec;
+ BIG_INT LsnResetThreshhold;
+ ULONG frs_size;
+ ULONG num_frs_per_prime;
+ ULONG prime_size;
+ PREAD_CACHE read_cache;
+ BOOLEAN changes = FALSE;
+ BOOLEAN RefrainFromResizing = FALSE;
+ BOOLEAN bitmap_growable;
+
+ if (SetupSpecial == FixLevel) {
+
+ //
+ // The "SetupSpecial" fixlevel is used only when the volume
+ // is ntfs and the /s flag is passed to autochk. It means that
+ // we should not bother to resize the logfile, since setup
+ // doesn't want to reboot the system for that.
+ //
+
+ RefrainFromResizing = TRUE;
+ FixLevel = TotalFix;
+ }
+
+ //
+ // When TRUE is returned, CHKDSK_EXIT_SUCCESS will be the
+ // default. When FALSE is returned, the default will be
+ // CHKDSK_EXIT_COULD_NOT_CHK.
+ //
+
+ if (NULL == ExitStatus) {
+ ExitStatus = &chkdsk_info.ExitStatus;
+ }
+ *ExitStatus = CHKDSK_EXIT_COULD_NOT_CHK;
+ chkdsk_info.ExitStatus = CHKDSK_EXIT_SUCCESS;
+
+ // Try to enable caching, if there's not enough resources then
+ // just run without a cache. Make the cache 64K.
+
+ if ((read_cache = NEW READ_CACHE) &&
+ read_cache->Initialize(_drive, (64*1024)/_drive->QuerySectorSize())) {
+
+ _drive->SetCache(read_cache);
+
+ } else {
+ DELETE(read_cache);
+ }
+
+ if (Verbose) {
+ Message->Set(MSG_CHK_NTFS_SLASH_V_NOT_SUPPORTED);
+ Message->Display();
+ return FALSE;
+ }
+
+ volume_flags = QueryVolumeFlags(&corrupt_volume, &major, &minor);
+ volume_is_dirty = (volume_flags & VOLUME_DIRTY) ? TRUE : FALSE;
+ if (!ResizeLogFile)
+ DesiredLogFileSize = 0;
+ resize_log_file = (volume_flags & VOLUME_RESIZE_LOG_FILE) || ResizeLogFile;
+
+ if (corrupt_volume) {
+ Message->Set(MSG_NTFS_CHK_NOT_NTFS);
+ Message->Display();
+ return FALSE;
+ }
+
+ if ((major != 1 || (minor != 0 && minor != 1 && minor != 2)) &&
+ (major != 2 || (minor != 0))) {
+ Message->Set(MSG_CHK_NTFS_WRONG_VERSION);
+ Message->Display();
+ return FALSE;
+ }
+
+ SetVersionNumber( major, minor );
+
+ if (OnlyIfDirty && !volume_is_dirty) {
+
+ Message->Set(MSG_CHK_VOLUME_CLEAN);
+ Message->Display();
+
+ // If the volume version number is 1.2 or greater, check
+ // the log file size.
+ //
+ if (!RefrainFromResizing &&
+ FixLevel != CheckOnly &&
+ (major > 1 || (major == 1 && minor >= 2))) {
+
+ if (!ResizeCleanLogFile( Message, ResizeLogFile, DesiredLogFileSize )) {
+
+ Message->Set(MSG_CHK_NTFS_RESIZING_LOG_FILE_FAILED);
+ Message->Display();
+ }
+ }
+ *ExitStatus = CHKDSK_EXIT_SUCCESS;
+
+ return TRUE;
+ }
+
+ if (FixLevel == CheckOnly) {
+ Message->Set(MSG_CHK_NTFS_READ_ONLY_MODE, NORMAL_MESSAGE, TEXT_MESSAGE);
+ Message->Display();
+ } else {
+
+ //
+ // The volume is not clean, so if we're autochecking we want to
+ // make sure that we're printing real messages on the console
+ // instead of just dots.
+ //
+
+#if defined( _AUTOCHECK_ )
+
+ BOOLEAN bPrev;
+
+ Message->SetLoggingEnabled();
+
+ bPrev = Message->SetDotsOnly(FALSE);
+
+ if (bPrev || RecoverFree || RecoverAlloc) {
+
+ if (NULL != DriveLetter) {
+
+ Message->Set(MSG_CHK_RUNNING);
+ Message->Display("%W", DriveLetter);
+ }
+
+ Message->Set(MSG_FILE_SYSTEM_TYPE);
+ Message->Display("%s", "NTFS");
+ }
+
+#endif /* _AUTOCHECK_ */
+
+ }
+
+
+ memset(&chkdsk_report, 0, sizeof(NTFS_CHKDSK_REPORT));
+
+
+ // Set the 'LargestLsnEncountered' variable to the smallest
+ // possible LSN value.
+
+ LargestLsnEncountered.LowPart = 0;
+ LargestLsnEncountered.HighPart = MINLONG;
+
+
+ // Fetch the MFT's $DATA attribute.
+
+ if (!FetchMftDataAttribute(Message, &mft_data)) {
+ return FALSE;
+ }
+
+ // Now make sure that the first four FRS of the MFT are readable,
+ // contiguous, and not too corrupt.
+
+ if (!ValidateCriticalFrs(&mft_data, Message)) {
+ return FALSE;
+ }
+
+
+ // Compute the number of file record segments and the number of volume
+ // clusters on disk.
+
+ mft_data.QueryValueLength(&num_frs, &num_mft_bits);
+
+ num_frs = num_frs / QueryFrsSize();
+
+ num_mft_bits = num_mft_bits / QueryFrsSize();
+
+ if (num_frs.GetHighPart() != 0) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ volume_clusters = QueryVolumeSectors()/((ULONG) QueryClusterFactor());
+
+ // Initialize the internal MFT bitmap, volume bitmap, and unreadable
+ // file record segments.
+ //
+
+ num_boot_clusters = max(1, BYTES_PER_BOOT_SECTOR/
+ (_drive->QuerySectorSize()*
+ QueryClusterFactor()));
+
+ DebugAssert(num_frs.GetHighPart() == 0);
+ chkdsk_info.major = major;
+ chkdsk_info.minor = minor;
+ chkdsk_info.QuotaFileNumber = 0;
+ chkdsk_info.ObjectIdFileNumber = 0;
+ chkdsk_info.NumFiles = num_frs.GetLowPart();
+ chkdsk_info.CrossLinkYet = FALSE;
+ chkdsk_info.CrossLinkStart = (volume_clusters/2).GetLowPart();
+ chkdsk_info.CrossLinkLength = num_boot_clusters;
+ chkdsk_info.CountFilesWithIndices = 0;
+
+ bitmap_growable = /* MJB _drive->QuerySectors() != QueryVolumeSectors() */ FALSE;
+
+ if (!mft_bitmap.Initialize(num_mft_bits, TRUE) ||
+ !volume_bitmap.Initialize(volume_clusters, bitmap_growable, _drive,
+ QueryClusterFactor()) ||
+ !(chkdsk_info.NumFileNames = NEW USHORT[chkdsk_info.NumFiles]) ||
+ !(chkdsk_info.ReferenceCount = NEW SHORT[chkdsk_info.NumFiles]) ||
+ !chkdsk_info.FilesWithIndices.Initialize(num_frs, TRUE) ||
+ !chkdsk_info.FilesWithEas.Initialize() ||
+ !chkdsk_info.ChildFrs.Initialize() ||
+ !chkdsk_info.BadFiles.Initialize() ||
+ !chkdsk_info.FilesWhoNeedData.Initialize() ||
+ !chkdsk_info.FilesWithNoReferences.Initialize() ||
+ !chkdsk_info.FilesWithTooManyFileNames.Initialize() ||
+ !chkdsk_info.FilesWithObjectId.Initialize()) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ memset(chkdsk_info.NumFileNames, 0, chkdsk_info.NumFiles*sizeof(USHORT));
+ memset(chkdsk_info.ReferenceCount, 0, chkdsk_info.NumFiles*sizeof(USHORT));
+
+
+ // Mark as allocated on the bitmap, the clusters reserved
+ // for the boot file.
+ //
+
+ volume_bitmap.SetAllocated(0, num_boot_clusters);
+
+ // If the volume size is smaller than the partition size, we figure that
+ // the replica boot sector is at the end of the partition. Otherwise we
+ // figure it must be in the middle.
+ //
+
+ if (QueryVolumeSectors() == _drive->QuerySectors()) {
+ volume_bitmap.SetAllocated(volume_clusters/2, num_boot_clusters);
+ }
+
+ // Fetch the attribute definition table.
+
+ if (!FetchAttributeDefinitionTable(&mft_data,
+ Message,
+ &attribute_def_table)) {
+ return FALSE;
+ }
+
+ // Fetch the upcase table.
+
+ if (!FetchUpcaseTable(&mft_data, Message, &upcase_table)) {
+ return FALSE;
+ }
+
+ if (!hmem.Initialize()) {
+ return FALSE;
+ }
+
+ // Set up the cache priming size.
+
+ frs_size = QueryFrsSize();
+ num_frs_per_prime = MFT_PRIME_SIZE/frs_size;
+ prime_size = num_frs_per_prime*frs_size;
+
+ // Verify and fix all of the file record segments.
+
+ Message->Set(MSG_CHK_NTFS_CHECKING_FILES, PROGRESS_MESSAGE);
+ Message->Display();
+ percent_done = 0;
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", percent_done)) {
+ return FALSE;
+ }
+
+ for (i = 0; i < num_frs; i += 1) {
+
+ if (i*100/num_frs != percent_done) {
+ percent_done = (i*100/num_frs).GetLowPart();
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", percent_done)) {
+ return FALSE;
+ }
+ }
+
+ if (i % num_frs_per_prime == 0) {
+ mft_data.PrimeCache(i*frs_size, prime_size);
+ }
+
+ if (MASTER_FILE_TABLE_NUMBER + 1 == i) {
+
+ // After verifying FRS 0, make sure that the
+ // space for the internal MFT $DATA is allocated in
+ // the internal Volume Bitmap.
+
+ if (!mft_data.MarkAsAllocated(&volume_bitmap)) {
+ Message->Set(MSG_CHK_NTFS_BAD_MFT);
+ Message->Display();
+ *ExitStatus = CHKDSK_EXIT_COULD_NOT_FIX;
+ return FALSE;
+ }
+ if (QueryVolumeSectors() != _drive->QuerySectors()) {
+ volume_bitmap.SetFree(volume_clusters/2, num_boot_clusters);
+ }
+ } else if (BOOT_FILE_NUMBER == i) {
+ volume_bitmap.SetFree(0, num_boot_clusters);
+
+ if (QueryVolumeSectors() == _drive->QuerySectors()) {
+ volume_bitmap.SetFree(volume_clusters/2, num_boot_clusters);
+ }
+ } else if (BOOT_FILE_NUMBER + 1 == i) {
+
+ volume_bitmap.SetAllocated(0, num_boot_clusters);
+
+ if (QueryVolumeSectors() == _drive->QuerySectors()) {
+ volume_bitmap.SetAllocated(volume_clusters/2, num_boot_clusters);
+ }
+
+ } else if (BAD_CLUSTER_FILE_NUMBER + 1 == i) {
+
+ // Now that the bad cluster file is basically intact, we
+ // should be able to add any new bad clusters we find to that
+ // file.
+
+ volume_bitmap.SetMftPointer(&internal_mft);
+ }
+
+
+ if (!frsstruc.Initialize(&hmem,
+ &mft_data,
+ i,
+ QueryClusterFactor(),
+ QueryVolumeSectors(),
+ QueryFrsSize(),
+ &upcase_table)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+
+ // Make sure the FRS is readable. If it isn't then add it to
+ // the list of unreadable FRSs.
+
+ if (!frsstruc.Read()) {
+
+ Message->Set(MSG_CHK_NTFS_UNREADABLE_FRS);
+ Message->Display("%d", i.GetLowPart());
+
+ disk_errors_found = TRUE;
+
+ if (!chkdsk_info.BadFiles.Add(i)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ continue;
+ }
+
+
+ // Ignore FRSs if they are not in use.
+
+ if (!frsstruc.IsInUse()) {
+
+ continue;
+ }
+
+
+ // If the FRS is a child then just add it to the list of child
+ // FRSs for later orphan detection. Besides that just ignore
+ // Child FRSs since they'll be validated with their parents.
+
+ if (!frsstruc.IsBase()) {
+
+ if (!chkdsk_info.ChildFrs.Add(i)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ continue;
+ }
+
+
+ // Verify and fix this base file record segment.
+
+ if (!frsstruc.VerifyAndFix(FixLevel,
+ Message,
+ &attribute_def_table,
+ &disk_errors_found)) {
+ return FALSE;
+ }
+
+
+ // If this FRS was in very bad shape then it was marked as
+ // not in use and should be ignored.
+
+ if (!frsstruc.IsInUse()) {
+
+ continue;
+ }
+
+
+ // Compare this LSN against the current highest LSN.
+
+ if (frsstruc.QueryLsn() > LargestLsnEncountered) {
+ LargestLsnEncountered = frsstruc.QueryLsn();
+ }
+
+
+ // Mark off this FRS in the MFT bitmap.
+
+ mft_bitmap.SetAllocated(i, 1);
+
+
+ if (frsstruc.QueryAttributeList(&attr_list)) {
+
+ // First verify the attribute list.
+
+ if (!attr_list.VerifyAndFix(FixLevel,
+ &volume_bitmap,
+ Message,
+ i,
+ &tube,
+ &disk_errors_found)) {
+ return FALSE;
+ }
+
+ // Make sure that the attribute list has a correct
+ // $STANDARD_INFORMATION entry and that the attribute
+ // list is not cross-linked. Otherwise tube it.
+
+ if (!tube) {
+ if (!attr_rec.Initialize(frsstruc.GetAttributeList()) ||
+ !attr_rec.UseClusters(&volume_bitmap, &cluster_count)) {
+
+ Message->Set(MSG_CHK_NTFS_BAD_ATTR_LIST);
+ Message->Display("%d",
+ frsstruc.QueryFileNumber().GetLowPart());
+
+ DebugPrintf("UNTFS: Cross-link in attr list.\n");
+ DebugPrintf("UNTFS: File 0x%X\n",
+ frsstruc.QueryFileNumber().GetLowPart());
+
+ tube = TRUE;
+
+ } else if (!attr_list.QueryExternalReference(
+ $STANDARD_INFORMATION, &seg_ref, &entry_index) ||
+ !(seg_ref == frsstruc.QuerySegmentReference())) {
+
+ Message->Set(MSG_CHK_NTFS_BAD_ATTR_LIST);
+ Message->Display("%d",
+ frsstruc.QueryFileNumber().GetLowPart());
+
+ DebugPrintf("UNTFS: Missing standard info in attr list.\n");
+ DebugPrintf("UNTFS: File 0x%X\n",
+ frsstruc.QueryFileNumber().GetLowPart());
+
+ attr_rec.UnUseClusters(&volume_bitmap, 0, 0);
+
+ tube = TRUE;
+ }
+ }
+
+ if (tube) {
+
+ // The attribute list needs to be tubed.
+
+ frsstruc.DeleteAttributeRecord(frsstruc.GetAttributeList());
+
+ if (FixLevel != CheckOnly && !frsstruc.Write()) {
+ Message->Set(MSG_CHK_READABLE_FRS_UNWRITEABLE);
+ Message->Display("%d", frsstruc.QueryFileNumber().GetLowPart());
+ return FALSE;
+ }
+
+
+ // Then, treat this FRS as though there were no
+ // attribute list, since there isn't any.
+
+ if (!frsstruc.LoneFrsAllocationCheck(&volume_bitmap,
+ &chkdsk_report,
+ &chkdsk_info,
+ FixLevel,
+ Message,
+ &disk_errors_found)) {
+ *ExitStatus = chkdsk_info.ExitStatus;
+ return FALSE;
+ }
+
+ if (!UpdateChkdskInfo(&frsstruc, &chkdsk_info, Message)) {
+ *ExitStatus = chkdsk_info.ExitStatus;
+ return FALSE;
+ }
+ continue;
+ }
+
+ // Now, we have a valid attribute list.
+
+
+ if (!VerifyAndFixMultiFrsFile(&frsstruc,
+ &attr_list,
+ &mft_data,
+ &attribute_def_table,
+ &volume_bitmap,
+ &mft_bitmap,
+ &chkdsk_report,
+ &chkdsk_info,
+ FixLevel,
+ Message,
+ &disk_errors_found)) {
+
+ *ExitStatus = chkdsk_info.ExitStatus;
+ return FALSE;
+ }
+
+
+ if (!frsstruc.UpdateAttributeList(&attr_list,
+ (FixLevel != CheckOnly))) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ } else {
+
+ // The FRS has no children. Just check that all
+ // of the attribute records start at VCN 0 and
+ // that the alloc length is right on non-residents.
+ // Additionally, mark off the internal bitmap with
+ // the space taken by the non-resident attributes.
+
+ if (!frsstruc.LoneFrsAllocationCheck(&volume_bitmap,
+ &chkdsk_report,
+ &chkdsk_info,
+ FixLevel,
+ Message,
+ &disk_errors_found)) {
+ return FALSE;
+ }
+
+ if (!frsstruc.CheckInstanceTags(FixLevel, Message, &changes)) {
+ return FALSE;
+ }
+
+ if (changes) {
+ *ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ }
+ }
+
+ if (!UpdateChkdskInfo(&frsstruc, &chkdsk_info, Message)) {
+ return FALSE;
+ }
+ }
+
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", 100)) {
+ return FALSE;
+ }
+ Message->Set(MSG_CHK_NTFS_FILE_VERIFICATION_COMPLETED, PROGRESS_MESSAGE);
+ Message->Display();
+
+ // Compute the files that have too many file-names.
+
+ for (i = 0; i < chkdsk_info.NumFiles; i += 1) {
+ if (chkdsk_info.NumFileNames[i.GetLowPart()] > 500) {
+ if (!chkdsk_info.FilesWithTooManyFileNames.Add(i)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ Message->Set(MSG_CHK_NTFS_TOO_MANY_FILE_NAMES);
+ Message->Display("%d", i.GetLowPart());
+ }
+ }
+
+
+ // Clean up orphan file record segments.
+
+ while (chkdsk_info.ChildFrs.QueryCardinality() > 0) {
+
+ child_file_number = chkdsk_info.ChildFrs.QueryNumber(0);
+
+ if (mft_bitmap.IsFree(child_file_number, 1)) {
+
+ Message->Set(MSG_CHK_NTFS_ORPHAN_FRS);
+ Message->Display("%d", child_file_number.GetLowPart());
+
+ disk_errors_found = TRUE;
+
+ if (!frsstruc.Initialize(&hmem,
+ &mft_data,
+ child_file_number,
+ QueryClusterFactor(),
+ QueryVolumeSectors(),
+ QueryFrsSize(),
+ &upcase_table)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!frsstruc.Read()) {
+
+ DebugAssert("previously readable frs is now unreadable");
+ return FALSE;
+ }
+
+ frsstruc.ClearInUse();
+
+ if (FixLevel != CheckOnly && !frsstruc.Write()) {
+ Message->Set(MSG_CHK_READABLE_FRS_UNWRITEABLE);
+ Message->Display("%d", frsstruc.QueryFileNumber().GetLowPart());
+ return FALSE;
+ }
+ }
+
+ if (!chkdsk_info.ChildFrs.Remove(child_file_number)) {
+ DebugAbort("Couldn't remove from the beginning of a num set.");
+ return FALSE;
+ }
+ }
+
+ if (disk_errors_found) {
+ *ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ }
+
+ if (disk_errors_found && FixLevel == CheckOnly) {
+ Message->Set(MSG_CHK_NTFS_ERRORS_FOUND);
+ Message->Display();
+ return FALSE;
+ }
+
+
+ mft_bitmap.SetAllocated(0, FIRST_USER_FILE_NUMBER);
+
+ // Now the internal volume bitmap and internal MFT bitmap are in
+ // ssync with the state of the disk. We must insure that the
+ // internal MFT data attribute, the internal MFT bitmap, the
+ // internal volume bitmap, and the internal attribute definition table
+ // are the same as the corresponding disk structures.
+
+ // The first step is to hotfix all of the unreadable FRS in the
+ // master file table. We'll store bad cluster numbers in a
+ // number set.
+
+ if (!HotfixMftData(&mft_data, &volume_bitmap, &chkdsk_info.BadFiles,
+ &bad_clusters, FixLevel, Message)) {
+
+ return FALSE;
+ }
+
+ if (!internal_mft.Initialize(&mft_data,
+ &mft_bitmap,
+ &volume_bitmap,
+ &upcase_table,
+ QueryClusterFactor(),
+ QueryFrsSize(),
+ _drive->QuerySectorSize(),
+ QueryVolumeSectors(),
+ FixLevel == CheckOnly)) {
+
+ DebugAbort("Couldn't initialize the internal MFT.");
+ return FALSE;
+ }
+
+
+ // Check to see if there's a file cross-linked with the boot
+ // mirror and attempt to fix it by copying the data.
+
+ if (!ResolveCrossLink(&chkdsk_info, &internal_mft, &bad_clusters,
+ FixLevel, Message)) {
+ return FALSE;
+ }
+
+
+ // At this point, use the internal MFT to validate all of the
+ // OS/2 EAs and NTFS indices.
+
+ if (!ValidateEas(&chkdsk_info.FilesWithEas,
+ &internal_mft,
+ FixLevel, Message)) {
+ return FALSE;
+ }
+
+ // Make sure that all of the system files are marked in use.
+ // (They are definitely marked in the MFT bitmap). If they're
+ // not then mark them for orphan recovery.
+
+ if (!EnsureSystemFilesInUse(&chkdsk_info, &internal_mft,
+ FixLevel, Message)) {
+ return FALSE;
+ }
+
+ if (!ValidateIndices(&chkdsk_info,
+ &directory_digraph,
+ &internal_mft,
+ &attribute_def_table,
+ &chkdsk_report,
+ &bad_clusters,
+ FixLevel, Message,
+ &disk_errors_found)) {
+
+ return FALSE;
+ }
+
+ if (disk_errors_found && FixLevel == CheckOnly) {
+ Message->Set(MSG_CHK_NTFS_ERRORS_FOUND);
+ Message->Display();
+ return FALSE;
+ }
+
+
+ // Now recover orphans into a nice directory.
+
+ if (!RecoverOrphans(&chkdsk_info, &directory_digraph, &internal_mft,
+ FixLevel, Message)) {
+
+ return FALSE;
+ }
+
+ DELETE(chkdsk_info.NumFileNames);
+ DELETE(chkdsk_info.ReferenceCount);
+
+ if (major >= 2) {
+ if (!CheckExtendSystemFiles(&chkdsk_info, &chkdsk_report,
+ &internal_mft, FixLevel, Message))
+ return FALSE;
+ }
+
+ // Now make sure that everyone who should have an unnamed $DATA
+ // attribute has one.
+
+ if (!CheckAllForData(&chkdsk_info, &internal_mft, FixLevel, Message)) {
+
+ return FALSE;
+ }
+
+
+ // Make sure that everyone's security descriptor is valid.
+
+ if (!ValidateSecurityDescriptors(&chkdsk_info, &chkdsk_report, &internal_mft,
+ &bad_clusters, FixLevel, Message)) {
+ return FALSE;
+ }
+
+
+ // Verify all user file data if requested.
+
+ if (RecoverAlloc && FixLevel != CheckOnly &&
+ !RecoverAllUserFiles(&internal_mft, &bad_clusters, Message)) {
+
+ return FALSE;
+ }
+
+
+ // Verify all free space if requested.
+
+ if (RecoverFree &&
+ !RecoverFreeSpace(&internal_mft, &bad_clusters, Message)) {
+
+ return FALSE;
+ }
+
+
+ if (!root_file.Initialize(ROOT_FILE_NAME_INDEX_NUMBER, &internal_mft) ||
+ !root_file.Read() ||
+ !index_name.Initialize(FileNameIndexNameData) ||
+ !root_index.Initialize(_drive, QueryClusterFactor(),
+ internal_mft.GetVolumeBitmap(),
+ internal_mft.GetUpcaseTable(),
+ root_file.QuerySize()/2,
+ &root_file, &index_name)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+
+ // In this space Fix the MFT mirror, attribute definition table,
+ // the boot file, the bad cluster file.
+
+ if (!mft_ref.Initialize(&internal_mft)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!mft_ref.Read()) {
+ DebugAbort("Can't read in hotfixed MFT reflection file.");
+ return FALSE;
+ }
+
+ if (!mft_ref.VerifyAndFix(internal_mft.GetDataAttribute(),
+ internal_mft.GetVolumeBitmap(),
+ &bad_clusters,
+ &root_index,
+ FixLevel,
+ Message)) {
+ return FALSE;
+ }
+
+ if (mft_ref.QueryFirstLcn() != QueryMft2StartingLcn()) {
+
+ Message->Set(MSG_CHK_NTFS_CORRECTING_MFT_MIRROR);
+ Message->Display();
+
+ DebugPrintf("UNTFS: Bad Mirror LCN in boot sector.\n");
+
+ _boot_sector->Mft2StartLcn = mft_ref.QueryFirstLcn();
+ }
+
+ if (!attr_def_file.Initialize(&internal_mft)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!attr_def_file.Read()) {
+ DebugAbort("Can't read in hotfixed attribute definition file.");
+ return FALSE;
+ }
+
+ if (!attr_def_file.VerifyAndFix(&attribute_def_table,
+ internal_mft.GetVolumeBitmap(),
+ &bad_clusters,
+ &root_index,
+ FixLevel,
+ Message)) {
+ return FALSE;
+ }
+
+ if (!boot_file.Initialize(&internal_mft)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!boot_file.Read()) {
+ DebugAbort("Can't read in hotfixed boot file.");
+ return FALSE;
+ }
+
+ if (!boot_file.VerifyAndFix(internal_mft.GetVolumeBitmap(),
+ &root_index, FixLevel, Message)) {
+ return FALSE;
+ }
+
+ if (!upcase_file.Initialize(&internal_mft)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!upcase_file.Read()) {
+ DebugAbort("Can't read in hotfixed upcase file.");
+ return FALSE;
+ }
+
+ if (!upcase_file.VerifyAndFix(&upcase_table,
+ internal_mft.GetVolumeBitmap(),
+ &bad_clusters,
+ &root_index,
+ FixLevel,
+ Message)) {
+ return FALSE;
+ }
+
+ if (!log_file.Initialize(&internal_mft)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!log_file.Read()) {
+ DebugAbort("Can't read in hotfixed log file.");
+ return FALSE;
+ }
+
+ if (!log_file.VerifyAndFix(internal_mft.GetVolumeBitmap(),
+ &root_index,
+ &chkdsk_report,
+ FixLevel,
+ resize_log_file,
+ DesiredLogFileSize,
+ Message)) {
+
+ return FALSE;
+ }
+
+ if (!bad_clus_file.Initialize(&internal_mft)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!bad_clus_file.Read()) {
+ DebugAbort("Can't read in hotfixed bad cluster file.");
+ return FALSE;
+ }
+
+ if (!bad_clus_file.VerifyAndFix(internal_mft.GetVolumeBitmap(),
+ &root_index, FixLevel, Message)) {
+ return FALSE;
+ }
+
+ internal_mft.GetMftBitmap()->SetAllocated(BAD_CLUSTER_FILE_NUMBER, 1);
+
+ if (bad_clusters.QueryCardinality() != 0) {
+
+ Message->Set(MSG_CHK_NTFS_ADDING_BAD_CLUSTERS);
+ Message->Display("%d", bad_clusters.QueryCardinality().GetLowPart());
+
+ if (bad_clus_file.Add(&bad_clusters)) {
+
+ if (FixLevel != CheckOnly &&
+ !bad_clus_file.Flush(internal_mft.GetVolumeBitmap())) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_BAD_FILE);
+ if (NULL != ExitStatus) {
+ *ExitStatus = CHKDSK_EXIT_COULD_NOT_FIX;
+ }
+ return FALSE;
+ }
+
+ } else {
+ Message->Set(MSG_CHK_NTFS_CANT_ADD_BAD_CLUSTERS);
+ Message->Display();
+ }
+ }
+
+ // If the largest LSN on the volume has exceeded the
+ // tolerated threshhold, reset all LSN's on the volume
+ // and clear the log file.
+ //
+ LsnResetThreshhold.Set( 0, LsnResetThreshholdHighPart );
+
+ if (FixLevel != CheckOnly &&
+ LargestLsnEncountered > LsnResetThreshhold) {
+
+ // The largest LSN on the volume is beyond the tolerated
+ // threshhold. Set all the LSN's on the volume to zero.
+ // Since the root index file is in memory, we have to
+ // do it separately.
+ //
+ if (!ResetLsns(Message, &internal_mft, TRUE)) {
+
+ *ExitStatus = CHKDSK_EXIT_COULD_NOT_FIX;
+ return FALSE;
+ }
+
+ root_file.SetLsn(0);
+
+ if (!root_index.ResetLsns(Message)) {
+
+ *ExitStatus = CHKDSK_EXIT_COULD_NOT_FIX;
+ return FALSE;
+ }
+
+ LargestLsnEncountered.LowPart = 0;
+ LargestLsnEncountered.HighPart = 0;
+
+ // Now reset the Log File. Note that resetting the log
+ // file does not change its size, so the Log File FRS
+ // won't need to be flushed.
+ //
+ if (!log_file.Initialize( &internal_mft)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display("");
+ return FALSE;
+ }
+
+ if (!log_file.Reset(Message)) {
+ *ExitStatus = CHKDSK_EXIT_COULD_NOT_FIX;
+ return FALSE;
+ }
+ }
+
+ // Mark the volume clean, clearing both the dirty bit
+ // and the resize-log-file bit.
+ //
+ if (FixLevel != CheckOnly &&
+ !SetVolumeClean(VOLUME_DIRTY | VOLUME_RESIZE_LOG_FILE,
+ &log_file, minor > 0 || major > 1,
+ LargestLsnEncountered, &corrupt_volume)) {
+
+ DebugPrint("Could not set volume clean.\n");
+
+ Message->Set(corrupt_volume ? MSG_CHK_NTFS_BAD_MFT :
+ MSG_CHK_NO_MEMORY);
+ Message->Display();
+ if (NULL != ExitStatus) {
+ *ExitStatus = (corrupt_volume ? CHKDSK_EXIT_COULD_NOT_FIX :
+ CHKDSK_EXIT_COULD_NOT_CHK);
+ }
+ return FALSE;
+ }
+
+
+ // Now fix the mft (both data, and bitmap), and the volume bitmap.
+ // Write everything out to disk.
+
+ if (!SynchronizeMft(&root_index, &internal_mft, FixLevel, Message)) {
+ return FALSE;
+ }
+
+
+ // Now flush out the root index that was used in v+f of the critical
+ // files.
+
+ if (FixLevel != CheckOnly) {
+ if (!root_index.Save(&root_file) ||
+ !root_file.Flush(NULL)) {
+
+ DebugPrint("Could not flush root index.\n");
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+
+ // After synchronizing the MFT flush it out so that the MFT mirror
+ // gets written.
+
+ if (!mft_file.Initialize(_drive, QueryMftStartingLcn(),
+ QueryClusterFactor(), QueryFrsSize(),
+ QueryVolumeSectors(),
+ internal_mft.GetVolumeBitmap(),
+ internal_mft.GetUpcaseTable())) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (FixLevel != CheckOnly) {
+ if (!mft_file.Read() || !mft_file.Flush() || !Write(Message)) {
+ DebugAbort("Couldn't IO hotfixed MFT file.");
+ return FALSE;
+ }
+ }
+
+ if (chkdsk_info.ExitStatus && FixLevel != CheckOnly &&
+ !MarkQuotaOutOfDate(&chkdsk_info, &internal_mft, FixLevel, Message)) {
+ Message->Set(MSG_CHK_NTFS_CANNOT_SET_QUOTA_FLAG_OUT_OF_DATE);
+ Message->Display();
+ return FALSE;
+ }
+
+ // Generate the chkdsk report.
+
+ cluster_size = QueryClusterFactor()*_drive->QuerySectorSize();
+
+ disk_size = _drive->QuerySectorSize()*QueryVolumeSectors();
+
+ Message->Set(MSG_CHK_NTFS_TOTAL_DISK_SPACE);
+ Message->Display("%9d", (disk_size/1024).GetLowPart());
+
+ if (chkdsk_report.NumUserFiles != 0) {
+ ULONG kbytes, nfiles;
+
+ kbytes = (chkdsk_report.BytesUserData/1024).GetLowPart();
+ nfiles = chkdsk_report.NumUserFiles.GetLowPart();
+
+ Message->Set(MSG_CHK_NTFS_USER_FILES);
+ Message->Display("%9d%d", kbytes, nfiles);
+ }
+
+ if (chkdsk_report.NumIndices != 0) {
+ ULONG kbytes, nindices;
+
+ kbytes = (chkdsk_report.BytesInIndices/1024).GetLowPart();
+ nindices = chkdsk_report.NumIndices.GetLowPart();
+
+ Message->Set(MSG_CHK_NTFS_INDICES_REPORT);
+ Message->Display("%9d%d", kbytes, nindices);
+ }
+
+ num_bad_clusters = bad_clus_file.QueryNumBad();
+
+ if (num_bad_clusters*cluster_size/1024 != 0) {
+
+ Message->Set(MSG_CHK_NTFS_BAD_SECTORS_REPORT);
+ Message->Display("%9d", (num_bad_clusters*cluster_size/1024).GetLowPart());
+ }
+
+ free_clusters = internal_mft.GetVolumeBitmap()->QueryFreeClusters();
+
+ system_size = disk_size - num_bad_clusters*cluster_size -
+ free_clusters*cluster_size - chkdsk_report.BytesUserData -
+ chkdsk_report.BytesInIndices;
+
+ Message->Set(MSG_CHK_NTFS_SYSTEM_SPACE);
+ Message->Display("%9d", (system_size/1024).GetLowPart());
+
+ Message->Set(MSG_CHK_NTFS_LOGFILE_SPACE);
+ Message->Display("%9d", (chkdsk_report.BytesLogFile/1024).GetLowPart());
+
+ Message->Set(MSG_CHK_NTFS_AVAILABLE_SPACE);
+ Message->Display("%9d", (free_clusters*cluster_size/1024).GetLowPart());
+
+ Message->Set(MSG_BYTES_PER_ALLOCATION_UNIT);
+ Message->Display("%9d", cluster_size);
+
+ Message->Set(MSG_TOTAL_ALLOCATION_UNITS);
+ Message->Display("%9d", volume_clusters.GetLowPart());
+
+ Message->Set(MSG_AVAILABLE_ALLOCATION_UNITS);
+ Message->Display("%9d", free_clusters.GetLowPart());
+
+#if defined( _AUTOCHECK_ )
+
+ // If this is AUTOCHK and we're running on the boot partition then
+ // we should reboot so that the cache doesn't stomp on us.
+
+ DSTRING sdrive, canon_sdrive, canon_drive;
+
+ FSTRING boot_log_file_name;
+
+ if (volume_is_dirty &&
+ IFS_SYSTEM::QueryNtSystemDriveName(&sdrive) &&
+ IFS_SYSTEM::QueryCanonicalNtDriveName(&sdrive, &canon_sdrive) &&
+ IFS_SYSTEM::QueryCanonicalNtDriveName(_drive->GetNtDriveName(),
+ &canon_drive) &&
+ !canon_drive.Stricmp(&canon_sdrive)) {
+
+ Message->Set(MSG_CHK_BOOT_PARTITION_REBOOT);
+ Message->Display();
+
+ boot_log_file_name.Initialize( L"bootex.log" );
+
+ if( FixLevel != CheckOnly &&
+ Message->IsLoggingEnabled() &&
+ !DumpMessagesToFile( &boot_log_file_name,
+ &mft_file,
+ Message ) ) {
+
+ DebugPrintf( "UNTFS: Error writing messages to BOOTEX.LOG\n" );
+ }
+
+ IFS_SYSTEM::Reboot();
+ }
+
+#endif
+
+ *ExitStatus = chkdsk_info.ExitStatus;
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_SA::ValidateCriticalFrs(
+ IN OUT PNTFS_ATTRIBUTE MftData,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine makes sure that the MFT's first four FRS are contiguous
+ and readable. If they are not contiguous, then this routine will
+ print a message stating that this volume is not NTFS. If they are
+ not readable then this routine will read the MFT mirror and if that
+ is readable then it will replace the MFT's first four FRS with
+ the MFT mirror.
+
+Arguments:
+
+ MftData - Supplies the MFT's data attribute.
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_CLUSTER_RUN clusrun;
+ HMEM hmem, volume_hmem;
+ LCN lcn;
+ BIG_INT run_length;
+ ULONG cluster_size;
+ NTFS_FRS_STRUCTURE volume_frs;
+ BIG_INT volume_cluster;
+ ULONG volume_cluster_offset;
+
+ cluster_size = QueryClusterFactor() * _drive->QuerySectorSize();
+
+ if (!MftData->QueryLcnFromVcn(0, &lcn, &run_length)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (lcn != QueryMftStartingLcn() ||
+ run_length <
+ (REFLECTED_MFT_SEGMENTS*QueryFrsSize() + (cluster_size - 1)) /cluster_size ) {
+
+ Message->Set(MSG_CHK_NTFS_BAD_MFT);
+ Message->Display();
+ return FALSE;
+ }
+
+ volume_cluster = lcn-1 + (VOLUME_DASD_NUMBER*QueryFrsSize() +
+ (cluster_size - 1)) / cluster_size;
+
+ volume_cluster_offset = (lcn * cluster_size + VOLUME_DASD_NUMBER * QueryFrsSize()
+ - volume_cluster * cluster_size).GetLowPart();
+
+ if (!hmem.Initialize() ||
+ !clusrun.Initialize(&hmem, _drive, lcn, QueryClusterFactor(),
+ (REFLECTED_MFT_SEGMENTS*QueryFrsSize() + (cluster_size - 1))/cluster_size) ||
+ !volume_hmem.Initialize() ||
+ !volume_frs.Initialize(&volume_hmem, _drive,
+ volume_cluster,
+ QueryClusterFactor(),
+ QueryVolumeSectors(),
+ QueryFrsSize(), NULL,
+ volume_cluster_offset)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!clusrun.Read() || !volume_frs.Read() ||
+ !volume_frs.GetAttribute($VOLUME_INFORMATION)) {
+
+ Message->Set(MSG_CHK_NTFS_USING_MFT_MIRROR);
+ Message->Display();
+
+ clusrun.Relocate(QueryMft2StartingLcn());
+
+ if (!clusrun.Read()) {
+ Message->Set(MSG_CHK_NTFS_UNREADABLE_MFT);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!MftData->ReplaceVcns(0, QueryMft2StartingLcn(),
+ (REFLECTED_MFT_SEGMENTS*QueryFrsSize() + (cluster_size - 1))/cluster_size)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ _boot_sector->MftStartLcn = QueryMft2StartingLcn();
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_SA::FetchMftDataAttribute(
+ IN OUT PMESSAGE Message,
+ OUT PNTFS_ATTRIBUTE MftData
+ )
+/*++
+
+Routine Description:
+
+ This routine weeds through the minimal necessary NTFS disk structures
+ in order to establish the location of the MFT's $DATA attribute.
+
+Arguments:
+
+ Message - Supplies an outlet for messages.
+ MftData - Returns an extent list for the MFT's $DATA attribute.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_FRS_STRUCTURE frs;
+ HMEM hmem;
+ ULONG bytes_per_frs;
+ BIG_INT rounded_value_length;
+ BIG_INT rounded_alloc_length;
+ BIG_INT rounded_valid_length;
+
+ DebugAssert(Message);
+ DebugAssert(MftData);
+
+ bytes_per_frs = QueryFrsSize();
+
+ // Initialize the NTFS_FRS_STRUCTURE object we'll use to manipulate
+ // the mft's FRS. Note that we won't manipulate any named attributes,
+ // so we can pass in NULL for the upcase table.
+
+ if (!hmem.Initialize() ||
+ !frs.Initialize(&hmem, _drive, QueryMftStartingLcn(),
+ QueryClusterFactor(),
+ QueryVolumeSectors(),
+ QueryFrsSize(), NULL)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!frs.Read() ||
+ !frs.SafeQueryAttribute($DATA, MftData, MftData) ||
+ MftData->QueryValueLength() < FIRST_USER_FILE_NUMBER*bytes_per_frs) {
+
+ // The first copy of the FRS is unreadable or corrupt
+ // so try the second copy.
+
+ if (!hmem.Initialize() ||
+ !frs.Initialize(&hmem, _drive, QueryMft2StartingLcn(),
+ QueryClusterFactor(),
+ QueryVolumeSectors(),
+ QueryFrsSize(), NULL)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!frs.Read()) {
+ Message->Set(MSG_CHK_NTFS_UNREADABLE_MFT);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!frs.SafeQueryAttribute($DATA, MftData, MftData)) {
+ Message->Set(MSG_CHK_NTFS_BAD_MFT);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+
+ if (MftData->QueryValueLength() < FIRST_USER_FILE_NUMBER*bytes_per_frs) {
+ Message->Set(MSG_CHK_NTFS_BAD_MFT);
+ Message->Display();
+ return FALSE;
+ }
+
+ // Truncate the MFT to be a whole number of file-records.
+
+ rounded_alloc_length = MftData->QueryAllocatedLength()/bytes_per_frs*
+ bytes_per_frs;
+ rounded_value_length = MftData->QueryValueLength()/bytes_per_frs*
+ bytes_per_frs;
+ rounded_valid_length = MftData->QueryValidDataLength()/bytes_per_frs*
+ bytes_per_frs;
+
+ if (MftData->QueryValidDataLength() != MftData->QueryValueLength()) {
+ MftData->Resize(rounded_valid_length, NULL);
+ } else if (rounded_value_length != MftData->QueryValueLength() ||
+ rounded_alloc_length != MftData->QueryAllocatedLength()) {
+ MftData->Resize(rounded_value_length, NULL);
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_SA::QueryDefaultAttributeDefinitionTable(
+ OUT PNTFS_ATTRIBUTE_COLUMNS AttributeDefinitionTable,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the default attribute definition table as put
+ down by format.
+
+Arguments:
+
+ AttributeDefinitionTable - Returns the default attribute definition
+ table.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ if (!AttributeDefinitionTable->Initialize(
+ NumberOfNtfsAttributeDefinitions,
+ NtfsAttributeDefinitions)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_SA::FetchAttributeDefinitionTable(
+ IN OUT PNTFS_ATTRIBUTE MftData,
+ IN OUT PMESSAGE Message,
+ OUT PNTFS_ATTRIBUTE_COLUMNS AttributeDefinitionTable
+ )
+/*++
+
+Routine Description:
+
+ This routine weeds through the minimal necessary NTFS disk structures
+ in order to establish an attribute definition table. This function
+ should return the attribute definition table supplied by FORMAT if it
+ is unable to retrieve one from disk.
+
+Arguments:
+
+ MftData - Supplies the extent list for the MFT's
+ $DATA attribute.
+ Message - Supplies an outlet for messages.
+ AttributeDefinitionTable - Returns the volume's attribute definition
+ table.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ return QueryDefaultAttributeDefinitionTable(AttributeDefinitionTable,
+ Message);
+
+// Comment out this block for future revisions of CHKDSK that will read
+// the attribute definition table from the disk. Version 1.0 and 1.1
+// of chkdsk will just get the attribute definition table that FORMAT
+// lays out.
+
+#if 0
+ NTFS_FRS_STRUCTURE frs;
+ HMEM hmem;
+ NTFS_ATTRIBUTE attr_def_table;
+ ULONG num_columns;
+ BIG_INT value_length;
+
+ // Initialize an FRS for the attribute definition table file's
+ // FRS. Note that we won't manipulate any named attributes, so
+ // we can pass in NULL for the upcase table.
+
+ if (!hmem.Initialize() ||
+ !frs.Initialize(&hmem, MftData, ATTRIBUTE_DEF_TABLE_NUMBER,
+ QueryClusterFactor(), QueryFrsSize(),
+ QueryVolumeSectors(), NULL)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!frs.Read()) {
+
+ Message->Set(MSG_CHK_NTFS_BAD_ATTR_DEF_TABLE);
+ Message->Display();
+
+ return QueryDefaultAttributeDefinitionTable(AttributeDefinitionTable,
+ Message);
+ }
+
+ if (!frs.SafeQueryAttribute($DATA, MftData, &attr_def_table)) {
+
+ Message->Set(MSG_CHK_NTFS_BAD_ATTR_DEF_TABLE);
+ Message->Display();
+
+ return QueryDefaultAttributeDefinitionTable(AttributeDefinitionTable,
+ Message);
+ }
+
+ attr_def_table.QueryValueLength(&value_length);
+
+ num_columns = (value_length/sizeof(ATTRIBUTE_DEFINITION_COLUMNS)).GetLowPart();
+
+ if (value_length%sizeof(ATTRIBUTE_DEFINITION_COLUMNS) != 0) {
+
+ Message->Set(MSG_CHK_NTFS_BAD_ATTR_DEF_TABLE);
+ Message->Display();
+
+ return QueryDefaultAttributeDefinitionTable(AttributeDefinitionTable,
+ Message);
+ }
+
+ if (!AttributeDefinitionTable->Initialize(num_columns)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!AttributeDefinitionTable->Read(&attr_def_table) ||
+ !AttributeDefinitionTable->Verify()) {
+
+ Message->Set(MSG_CHK_NTFS_BAD_ATTR_DEF_TABLE);
+ Message->Display();
+
+ return QueryDefaultAttributeDefinitionTable(AttributeDefinitionTable,
+ Message);
+ }
+
+ return TRUE;
+#endif
+}
+
+
+BOOLEAN
+NTFS_SA::FetchUpcaseTable(
+ IN OUT PNTFS_ATTRIBUTE MftData,
+ IN OUT PMESSAGE Message,
+ OUT PNTFS_UPCASE_TABLE UpcaseTable
+ )
+/*++
+
+Routine Description:
+
+ This routine safely fetches the NTFS upcase table. It none is
+ available on disk then this routine gets the one from the
+ operating system.
+
+Arguments:
+
+ MftData - Supplies the MFT's data attribute.
+ Message - Supplies an outlet for messages.
+ UpcaseTable - Returns the upcase table.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ // For product 1, always use the system's upcase table. If this upcase
+ // table differs from the upcase table on disk then it will be written
+ // to disk at the end of CHKDSK. CHKDSK will resort indices as
+ // needed to reflect any upcase table changes.
+
+ if (!UpcaseTable->Initialize()) {
+ Message->Set(MSG_CHK_NTFS_CANT_GET_UPCASE_TABLE);
+ Message->Display();
+ return FALSE;
+ }
+
+ return TRUE;
+
+
+#if 0
+ NTFS_FRS_STRUCTURE frs;
+ HMEM hmem;
+ NTFS_ATTRIBUTE upcase_table;
+
+ // Initialize an FRS for the upcase table file's
+ // FRS. Note that we won't manipulate any named attributes, so
+ // we can pass in NULL for the upcase table.
+
+ if (!hmem.Initialize() ||
+ !frs.Initialize(&hmem, MftData, UPCASE_TABLE_NUMBER,
+ QueryClusterFactor(), QueryFrsSize(),
+ QueryVolumeSectors(), NULL)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!frs.Read() ||
+ !frs.SafeQueryAttribute($DATA, MftData, &upcase_table) ||
+ !UpcaseTable->Initialize(&upcase_table) ||
+ !UpcaseTable->Verify()) {
+
+ Message->Set(MSG_CHK_NTFS_BAD_UPCASE_TABLE);
+ Message->Display();
+
+ if (!UpcaseTable->Initialize()) {
+ Message->Set(MSG_CHK_NTFS_CANT_GET_UPCASE_TABLE);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+#endif
+}
+
+
+BOOLEAN
+NTFS_SA::VerifyAndFixMultiFrsFile(
+ IN OUT PNTFS_FRS_STRUCTURE BaseFrs,
+ IN OUT PNTFS_ATTRIBUTE_LIST AttributeList,
+ IN PNTFS_ATTRIBUTE MftData,
+ IN PCNTFS_ATTRIBUTE_COLUMNS AttributeDefTable,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNTFS_BITMAP MftBitmap,
+ IN OUT PNTFS_CHKDSK_REPORT ChkdskReport,
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN DiskErrorsFound
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies, and if necessary fixes, a multi-FRS file.
+
+Arguments:
+
+ BaseFrs - Supplies the base FRS of the file to validate.
+ AttributeList - Supplies the attribute list of the file to
+ validate.
+ MftData - Supplies the MFT's $DATA attribute.
+ AttributeDefTable - Supplies the attribute definition table.
+ VolumeBitmap - Supplies the volume bitmap.
+ MftBitmap - Supplies the MFT bitmap.
+ ChkdskReport - Supplies the current chkdsk report.
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages.
+ DiskErrorsFound - Supplies whether or not there have been any
+ disk errors found so far.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NUMBER_SET child_file_numbers;
+ PHMEM* child_frs_hmem;
+ LIST child_frs_list;
+ PITERATOR iter;
+ PNTFS_FRS_STRUCTURE pfrs;
+ ULONG num_child_frs, i;
+ BOOLEAN changes;
+ BOOLEAN need_write;
+
+ DebugAssert(BaseFrs);
+ DebugAssert(AttributeList);
+ DebugAssert(MftData);
+ DebugAssert(AttributeDefTable);
+ DebugAssert(VolumeBitmap);
+ DebugAssert(MftBitmap);
+ DebugAssert(Message);
+
+
+ // First get a list of the child FRSs pointed to by the
+ // attribube list.
+
+ if (!QueryListOfFrs(BaseFrs, AttributeList, MftData,
+ &child_file_numbers, Message)) {
+
+ return FALSE;
+ }
+
+
+ // Create some HMEMs for the FRS structures.
+
+ num_child_frs = child_file_numbers.QueryCardinality().GetLowPart();
+
+ if (!(child_frs_hmem = NEW PHMEM[num_child_frs])) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ memset(child_frs_hmem, 0, num_child_frs*sizeof(PHMEM));
+
+
+ // Read in all of the child FRS.
+
+ if (!child_frs_list.Initialize() ||
+ !VerifyAndFixChildFrs(&child_file_numbers, MftData, AttributeDefTable,
+ BaseFrs->GetUpcaseTable(),
+ child_frs_hmem, &child_frs_list, FixLevel,
+ Message, DiskErrorsFound)) {
+
+ for (i = 0; i < num_child_frs; i++) {
+ DELETE(child_frs_hmem[i]);
+ }
+ DELETE(child_frs_hmem);
+ child_frs_list.DeleteAllMembers();
+ return FALSE;
+ }
+
+ // At this point we have a list of child FRSs that are all readable.
+ // This list contains all of the possible children for the parent
+ // but are not all necessarily valid children.
+
+
+ // Now go through the attribute list and make sure that all of the
+ // entries in the list correspond to correct attribute records.
+ // Additionally, make sure that multi-record attributes are well-linked
+ // and that there are no cross-links.
+
+ if (!EnsureWellDefinedAttrList(BaseFrs, AttributeList, &child_frs_list,
+ VolumeBitmap, ChkdskReport, ChkdskInfo,
+ FixLevel, Message, DiskErrorsFound)) {
+
+ for (i = 0; i < num_child_frs; i++) {
+ DELETE(child_frs_hmem[i]);
+ }
+ DELETE(child_frs_hmem);
+ child_frs_list.DeleteAllMembers();
+ return FALSE;
+ }
+
+
+ // Next, we go through all of the attribute records in all of the
+ // FRS and make sure that they have a corresponding attribute list
+ // entry.
+
+ if (!EnsureSurjectiveAttrList(BaseFrs, AttributeList, &child_frs_list,
+ FixLevel, Message, DiskErrorsFound)) {
+
+ for (i = 0; i < num_child_frs; i++) {
+ DELETE(child_frs_hmem[i]);
+ }
+ DELETE(child_frs_hmem);
+ child_frs_list.DeleteAllMembers();
+ return FALSE;
+ }
+
+ // Mark all of the child FRS in the MFT bitmap.
+
+ if (!(iter = child_frs_list.QueryIterator())) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+
+ for (i = 0; i < num_child_frs; i++) {
+ DELETE(child_frs_hmem[i]);
+ }
+ DELETE(child_frs_hmem);
+ child_frs_list.DeleteAllMembers();
+ return FALSE;
+ }
+
+ while (pfrs = (PNTFS_FRS_STRUCTURE) iter->GetNext()) {
+ MftBitmap->SetAllocated(pfrs->QueryFileNumber().GetLowPart(), 1);
+ }
+
+ // Check the instance tags on the attribute records in the base
+ // frs and in each child frs.
+
+ need_write = FALSE;
+
+ if (!BaseFrs->CheckInstanceTags(FixLevel,
+ Message,
+ &changes,
+ AttributeList)) {
+ DELETE(iter);
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+
+ for (i = 0; i < num_child_frs; i++) {
+ DELETE(child_frs_hmem[i]);
+ }
+ DELETE(child_frs_hmem);
+ child_frs_list.DeleteAllMembers();
+ return FALSE;
+ }
+
+ need_write |= changes;
+
+ iter->Reset();
+
+ while (pfrs = (PNTFS_FRS_STRUCTURE)iter->GetNext()) {
+ if (!pfrs->CheckInstanceTags(FixLevel,
+ Message,
+ &changes,
+ AttributeList)) {
+ break;
+ }
+
+ need_write |= changes;
+ }
+
+ DELETE(iter);
+
+ if (need_write) {
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+
+ if (FixLevel != CheckOnly) {
+ AttributeList->WriteList(NULL);
+ }
+ }
+
+ for (i = 0; i < num_child_frs; i++) {
+ DELETE(child_frs_hmem[i]);
+ }
+ DELETE(child_frs_hmem);
+ child_frs_list.DeleteAllMembers();
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_SA::QueryListOfFrs(
+ IN PCNTFS_FRS_STRUCTURE BaseFrs,
+ IN PCNTFS_ATTRIBUTE_LIST AttributeList,
+ IN OUT PNTFS_ATTRIBUTE MftData,
+ OUT PNUMBER_SET ChildFileNumbers,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine computes all of the child file numbers pointed to by
+ the given attribute list which is contained in the given FRS.
+
+Arguments:
+
+ BaseFrs - Supplies the base FRS.
+ AttributeList - Supplies the attribute list for the base FRS.
+ MftData - Supplies the Mft's data attribute.
+ ChildFileNumbers - Return a list of child FRS numbers.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ HMEM hmem;
+ NTFS_FRS_STRUCTURE child_frs;
+ ATTRIBUTE_TYPE_CODE attr_code;
+ VCN lowest_vcn;
+ MFT_SEGMENT_REFERENCE seg_ref;
+ DSTRING attr_name;
+ VCN file_number;
+ ULONG i;
+ USHORT instance;
+
+ DebugAssert(BaseFrs);
+ DebugAssert(AttributeList);
+ DebugAssert(ChildFileNumbers);
+ DebugAssert(Message);
+
+ if (!ChildFileNumbers->Initialize()) {
+ return FALSE;
+ }
+
+ for (i = 0; AttributeList->QueryEntry(i,
+ &attr_code,
+ &lowest_vcn,
+ &seg_ref,
+ &instance,
+ &attr_name); i++) {
+
+ file_number.Set(seg_ref.LowPart, (ULONG) seg_ref.HighPart);
+
+ if (file_number != BaseFrs->QueryFileNumber()) {
+ if (!ChildFileNumbers->DoesIntersectSet(file_number, 1)) {
+
+ if (!hmem.Initialize() ||
+ !child_frs.Initialize(&hmem, MftData, file_number,
+ QueryClusterFactor(),
+ QueryVolumeSectors(),
+ QueryFrsSize(),
+ NULL)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+
+ // Only add this FRS to the list of child FRS's
+ // if it is readable and points back to the base.
+
+ if (child_frs.Read() &&
+ child_frs.QueryBaseFileRecordSegment() ==
+ BaseFrs->QuerySegmentReference()) {
+
+ if (!ChildFileNumbers->Add(file_number)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_SA::VerifyAndFixChildFrs(
+ IN PCNUMBER_SET ChildFileNumbers,
+ IN PNTFS_ATTRIBUTE MftData,
+ IN PCNTFS_ATTRIBUTE_COLUMNS AttributeDefTable,
+ IN PNTFS_UPCASE_TABLE UpcaseTable,
+ OUT PHMEM* ChildFrsHmemList,
+ IN OUT PCONTAINER ChildFrsList,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN DiskErrorsFound
+ )
+/*++
+
+Routine Description:
+
+ This routine reads in all of the child FRS listed in 'ChildFileNumbers'
+ and returns the readable ones into the 'ChildFrsList'. These FRS will
+ be initialized with the HMEM provided in 'ChildFrsHmemList'.
+
+ Then this routine verifies all of these FRS. Any FRS that are not
+ good will not be returned in the list.
+
+Arguments:
+
+ ChildFileNumbers - Supplies the file numbers of the child FRS.
+ MftData - Supplies the MFT data attribute.
+ AttributeDefTable - Supplies the attribute definition table.
+ UpcaseTable - Supplies the volume upcase table.
+ ChildFrsHmemList - Returns the HMEM for the FRS structures.
+ ChildFrsList - Returns a list of FRS structures corresponding
+ to the readable FRS found in the given list.
+ Message - Supplies an outlet for messages.
+ DiskErrorsFound - Supplies whether or not disk errors have been
+ found.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG i;
+ ULONG num_child_frs;
+ PNTFS_FRS_STRUCTURE frs;
+
+ num_child_frs = ChildFileNumbers->QueryCardinality().GetLowPart();
+
+ for (i = 0; i < num_child_frs; i++) {
+
+ frs = NULL;
+
+ if (!(ChildFrsHmemList[i] = NEW HMEM) ||
+ !ChildFrsHmemList[i]->Initialize() ||
+ !(frs = NEW NTFS_FRS_STRUCTURE) ||
+ !frs->Initialize(ChildFrsHmemList[i],
+ MftData,
+ ChildFileNumbers->QueryNumber(i),
+ QueryClusterFactor(),
+ QueryVolumeSectors(),
+ QueryFrsSize(),
+ UpcaseTable)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ DELETE(frs);
+ return FALSE;
+ }
+
+ if (!frs->Read()) {
+ DELETE(frs);
+ continue;
+ }
+
+ if (!frs->IsInUse()) {
+ DELETE(frs);
+ continue;
+ }
+
+ if (!frs->VerifyAndFix(FixLevel, Message, AttributeDefTable,
+ DiskErrorsFound)) {
+ DELETE(frs);
+ return FALSE;
+ }
+
+ if (!frs->IsInUse()) {
+ DELETE(frs);
+ continue;
+ }
+
+
+ // Compare the LSN of this FRS with the current largest LSN.
+
+ if (frs->QueryLsn() > LargestLsnEncountered) {
+ LargestLsnEncountered = frs->QueryLsn();
+ }
+
+
+ if (!ChildFrsList->Put(frs)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ DELETE(frs);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+VOID
+DeleteAllAttributes(
+ IN PSEQUENTIAL_CONTAINER AllAttributes
+ )
+{
+ PITERATOR alliter;
+ PSEQUENTIAL_CONTAINER attribute;
+
+ if (!(alliter = AllAttributes->QueryIterator())) {
+ return;
+ }
+
+ while (attribute = (PSEQUENTIAL_CONTAINER) alliter->GetNext()) {
+ attribute->DeleteAllMembers();
+ }
+ DELETE(alliter);
+
+ AllAttributes->DeleteAllMembers();
+}
+
+
+BOOLEAN
+NTFS_SA::EnsureWellDefinedAttrList(
+ IN PNTFS_FRS_STRUCTURE BaseFrs,
+ IN OUT PNTFS_ATTRIBUTE_LIST AttributeList,
+ IN PCSEQUENTIAL_CONTAINER ChildFrsList,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNTFS_CHKDSK_REPORT ChkdskReport,
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN DiskErrorsFound
+ )
+/*++
+
+Routine Desciption:
+
+ This routine makes sure that every entry in the attribute list
+ points to an FRS with the same segment reference and that the
+ attribute record refered to in the entry actually exists in the
+ FRS. Invalid attribute list entries will be deleted.
+
+Arguments:
+
+ BaseFrs - Supplies the base file record segment.
+ AttributeList - Supplies the attribute list.
+ ChildFrsList - Supplies a list of all of the child FRS.
+ VolumeBitmap - Supplies a volume bitmap.
+ ChkdskReport - Supplies the current chkdsk report.
+ FixLevel - Supplies the fix up level.
+ Message - Supplies an outlet for messages.
+ DiskErrorsFound - Supplies whether or not disk errors have been
+ found.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ ULONG i;
+ BOOLEAN changes;
+ PITERATOR child_frs_iter;
+ PITERATOR attribute_iter;
+ ATTRIBUTE_TYPE_CODE attr_code;
+ VCN lowest_vcn;
+ MFT_SEGMENT_REFERENCE seg_ref;
+ MFT_SEGMENT_REFERENCE base_ref;
+ DSTRING attr_name, attr_name2;
+ PNTFS_FRS_STRUCTURE frs;
+ PVOID precord;
+ NTFS_ATTRIBUTE_RECORD attr_record;
+ PLIST attribute;
+ PNTFS_ATTRIBUTE_RECORD pattr_record;
+ BOOLEAN errors_found;
+ LIST all_attributes;
+ BOOLEAN user_file;
+ NTFS_CHKDSK_REPORT dummy_report;
+ USHORT instance;
+
+
+ if (!(child_frs_iter = ChildFrsList->QueryIterator())) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!(attribute = NEW LIST) ||
+ !attribute->Initialize() ||
+ !all_attributes.Initialize()) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+
+ // Go through each attribute entry and make sure it's right.
+ // If it isn't right then delete it. Otherwise, check for
+ // cross-links and consistency between multi-record attributes.
+
+ changes = FALSE;
+ base_ref = BaseFrs->QuerySegmentReference();
+ user_file = FALSE;
+
+
+ for (i = 0; AttributeList->QueryEntry(i,
+ &attr_code,
+ &lowest_vcn,
+ &seg_ref,
+ &instance,
+ &attr_name); ) {
+
+ if (attr_code == $DATA ||
+ attr_code == $EA_DATA ||
+ attr_code >= $FIRST_USER_DEFINED_ATTRIBUTE) {
+
+ VCN FileNumber = BaseFrs->QueryFileNumber();
+
+ if (FileNumber >= FIRST_USER_FILE_NUMBER) {
+ user_file = TRUE;
+ }
+ }
+
+
+ // First find which frs this refers to.
+
+ if (seg_ref == base_ref) {
+
+ frs = BaseFrs;
+
+ } else {
+
+ child_frs_iter->Reset();
+ while (frs = (PNTFS_FRS_STRUCTURE) child_frs_iter->GetNext()) {
+
+ if (frs->QuerySegmentReference() == seg_ref &&
+ frs->QueryBaseFileRecordSegment() == base_ref) {
+ break;
+ }
+ }
+ }
+
+
+ // If the frs is present then look for the record.
+
+ if (frs) {
+
+ // Try to locate the exact attribute record.
+
+ precord = NULL;
+ while (precord = frs->GetNextAttributeRecord(precord)) {
+
+ if (!attr_record.Initialize(precord)) {
+ DebugAbort("Couldn't initialize an attribute record.");
+ return FALSE;
+ }
+
+ if (attr_record.QueryTypeCode() == attr_code &&
+ attr_record.QueryLowestVcn() == lowest_vcn &&
+ attr_record.QueryInstanceTag() == instance) {
+
+ if (!attr_record.QueryName(&attr_name2)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ DELETE(child_frs_iter);
+ return FALSE;
+ }
+
+ if (!attr_name.Strcmp(&attr_name2)) {
+ break;
+ }
+ }
+ }
+
+ } else {
+ precord = NULL;
+ }
+
+
+ // If we have not found a match then delete the entry.
+ // Also, there should be no entries in the attribute list
+ // for the attribute list entry itself. If there is
+ // then remove is without hurting anything.
+
+ if (!precord || attr_code == $ATTRIBUTE_LIST) {
+
+ Message->Set(MSG_CHK_NTFS_BAD_ATTR_LIST_ENTRY);
+ Message->Display("%d%d", attr_code,
+ BaseFrs->QueryFileNumber().GetLowPart());
+
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+
+ AttributeList->DeleteEntry(i);
+
+ attribute->DeleteAllMembers();
+ DeleteAllAttributes(&all_attributes);
+
+ if (!attribute->Initialize() ||
+ !all_attributes.Initialize()) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+
+ DELETE(child_frs_iter);
+ DELETE(attribute);
+ return FALSE;
+ }
+
+ changes = TRUE;
+ i = 0;
+ user_file = FALSE;
+
+ continue;
+ }
+
+
+ // If the lowest vcn of this one is zero then package up the
+ // previous attribute and start a new container for the
+ // next attribute.
+
+ if (attr_record.QueryLowestVcn() == 0 &&
+ attribute->QueryMemberCount()) {
+
+ if (!all_attributes.Put(attribute) ||
+ !(attribute = NEW LIST) ||
+ !attribute->Initialize()) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+
+ DELETE(child_frs_iter);
+ attribute->DeleteAllMembers();
+ DELETE(attribute);
+ DeleteAllAttributes(&all_attributes);
+ return FALSE;
+ }
+ }
+
+ if (!(pattr_record = NEW NTFS_ATTRIBUTE_RECORD) ||
+ !pattr_record->Initialize(precord) ||
+ !attribute->Put(pattr_record)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+
+ DELETE(child_frs_iter);
+ DELETE(pattr_record);
+ attribute->DeleteAllMembers();
+ DELETE(attribute);
+ DeleteAllAttributes(&all_attributes);
+ return FALSE;
+ }
+
+ i++;
+ }
+
+ DELETE(child_frs_iter);
+
+ if (attribute->QueryMemberCount() &&
+ !all_attributes.Put(attribute)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+
+ attribute->DeleteAllMembers();
+ DELETE(attribute);
+ DeleteAllAttributes(&all_attributes);
+ return FALSE;
+ }
+ attribute = NULL;
+
+ if (user_file) {
+ ChkdskReport->NumUserFiles += 1;
+ }
+
+
+ // Now go through all of the attributes in 'all_attributes' and
+ // make sure that every attribute is well-defined and that there
+ // are no cross-links.
+
+ if (!(attribute_iter = all_attributes.QueryIterator())) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+
+ DeleteAllAttributes(&all_attributes);
+ return FALSE;
+ }
+
+
+ while (attribute = (PLIST) attribute_iter->GetNext()) {
+
+ if (!VerifyAndFixAttribute(attribute, AttributeList,
+ VolumeBitmap, BaseFrs, &errors_found,
+ user_file ? ChkdskReport : &dummy_report,
+ ChkdskInfo, Message)) {
+
+ DeleteAllAttributes(&all_attributes);
+ DELETE(attribute_iter);
+ return FALSE;
+ }
+
+ changes = (BOOLEAN) (changes || errors_found);
+ }
+ DELETE(attribute_iter);
+
+ if (changes && DiskErrorsFound) {
+ *DiskErrorsFound = TRUE;
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ }
+
+ if (changes &&
+ FixLevel != CheckOnly &&
+ !AttributeList->WriteList(VolumeBitmap)) {
+ Message->Set(MSG_CHK_READABLE_FRS_UNWRITEABLE);
+ Message->Display("%d", BaseFrs->QueryFileNumber().GetLowPart());
+ return FALSE;
+ }
+
+
+ DeleteAllAttributes(&all_attributes);
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_SA::VerifyAndFixAttribute(
+ IN PCLIST Attribute,
+ IN OUT PNTFS_ATTRIBUTE_LIST AttributeList,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN PCNTFS_FRS_STRUCTURE BaseFrs,
+ OUT PBOOLEAN ErrorsFound,
+ IN OUT PNTFS_CHKDSK_REPORT ChkdskReport,
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies a list of attribute records as an attribute.
+
+Arguments:
+
+ Attribute - Supplies the attribute as a list of attribute
+ records.
+ AttributeList - Supplies the attribute list.
+ VolumeBitmap - Supplies the volume bitmap.
+ BaseFrs - Supplies the base FRS.
+ ErrorsFound - Returns whether or not error were found.
+ ChkdskReport - Supplies the current chkdsk report.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+Notes:
+
+ This thing is speced to take a list because it depends on the
+ attribute records to be in the order that they were in the
+ attribute list.
+
+--*/
+{
+ PITERATOR iter;
+ PNTFS_ATTRIBUTE_RECORD attr_record;
+ DSTRING name;
+ PNTFS_ATTRIBUTE_RECORD first_record;
+ PNTFS_ATTRIBUTE_RECORD last_record;
+ DSTRING first_record_name;
+ DSTRING record_name;
+ BIG_INT value_length;
+ BIG_INT alloc_length;
+ BIG_INT cluster_count;
+ BIG_INT total_clusters = 0;
+ BIG_INT total_allocated;
+ BOOLEAN got_allow_cross_link;
+
+ if (!(iter = Attribute->QueryIterator())) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ *ErrorsFound = FALSE;
+
+ if (!(first_record = (PNTFS_ATTRIBUTE_RECORD) iter->GetNext())) {
+ DebugAbort("Attribute has no attribute records");
+ return FALSE;
+ }
+
+ if (first_record->QueryLowestVcn() != 0) {
+ *ErrorsFound = TRUE;
+ }
+
+ got_allow_cross_link = FALSE;
+
+ if (!first_record->IsResident() &&
+ !first_record->UseClusters(VolumeBitmap,
+ &cluster_count, ChkdskInfo->CrossLinkStart,
+ ChkdskInfo->CrossLinkYet ? 0 :
+ ChkdskInfo->CrossLinkLength,
+ &got_allow_cross_link)) {
+ *ErrorsFound = TRUE;
+ got_allow_cross_link = FALSE;
+
+ //
+ // We don't want to free the clusters allocated to this attribute
+ // record below, because some of them are cross-linked and the ones
+ // that are not have not been allocated in the volume bitmap.
+ //
+
+ first_record->DisableUnUse();
+ }
+
+ if( first_record->IsResident() ) {
+
+ total_clusters = 0;
+
+ } else {
+
+ total_clusters = cluster_count;
+ }
+
+ if (got_allow_cross_link) {
+ ChkdskInfo->CrossLinkYet = TRUE;
+ ChkdskInfo->CrossLinkedFile = BaseFrs->QueryFileNumber().GetLowPart();
+ ChkdskInfo->CrossLinkedAttribute = first_record->QueryTypeCode();
+ if (!first_record->QueryName(&ChkdskInfo->CrossLinkedName)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ }
+ }
+
+ if (!first_record->QueryName(&first_record_name)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ last_record = first_record;
+ while (!(*ErrorsFound) &&
+ (attr_record = (PNTFS_ATTRIBUTE_RECORD) iter->GetNext())) {
+
+ if (!attr_record->QueryName(&record_name)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ // The filesystem only cares about and maintains the Flags member
+ // in the first attribute record of a multi-frs attribute. So
+ // I removed the check below, which used to insure that each set
+ // of flags was identical. -mjb.
+
+ *ErrorsFound = (BOOLEAN) (*ErrorsFound ||
+ (first_record->IsResident()) ||
+ (attr_record->IsResident()) ||
+ (attr_record->QueryTypeCode() != first_record->QueryTypeCode()) ||
+ (attr_record->QueryLowestVcn() != last_record->QueryNextVcn()) ||
+ /* (attr_record->QueryFlags() != first_record->QueryFlags()) || */
+ (record_name.Strcmp(&first_record_name)));
+
+ if (!attr_record->UseClusters(VolumeBitmap,
+ &cluster_count,
+ ChkdskInfo->CrossLinkStart,
+ ChkdskInfo->CrossLinkYet ? 0 :
+ ChkdskInfo->CrossLinkLength,
+ &got_allow_cross_link)) {
+ *ErrorsFound = TRUE;
+ got_allow_cross_link = FALSE;
+
+ //
+ // We don't want to free the clusters allocated to this attribute
+ // record below, because some of them are cross-linked and the ones
+ // that are not have not been allocated in the volume bitmap.
+ //
+
+ attr_record->DisableUnUse();
+ }
+
+ total_clusters += cluster_count;
+
+ if (got_allow_cross_link) {
+ ChkdskInfo->CrossLinkYet = TRUE;
+ ChkdskInfo->CrossLinkedFile = BaseFrs->QueryFileNumber().GetLowPart();
+ ChkdskInfo->CrossLinkedAttribute = attr_record->QueryTypeCode();
+ if (!attr_record->QueryName(&ChkdskInfo->CrossLinkedName)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ }
+ }
+
+ last_record = attr_record;
+ }
+
+ // Check the allocated length.
+
+ first_record->QueryValueLength(&value_length, &alloc_length, NULL,
+ &total_allocated);
+
+ if (!first_record->IsResident()) {
+ if (alloc_length != last_record->QueryNextVcn()*
+ _drive->QuerySectorSize()*
+ QueryClusterFactor()) {
+
+ *ErrorsFound = TRUE;
+ }
+
+#if 0
+//
+// MJB: deleting the attribute because the total allocated is
+// wrong is considered too severe, so what we really want to do is
+// repair the attribute record. Unfortunately, I don't see any
+// reasonable way to do that, so we'll let it be. The filesystem
+// guarantees that nothing terrible will happen if your TotalAllocated
+// field is out-of-whack.
+//
+ if ((first_record->QueryFlags() & ATTRIBUTE_FLAG_COMPRESSION_MASK)
+ != 0) {
+
+ if (total_clusters * _drive->QuerySectorSize() *
+ QueryClusterFactor() != total_allocated) {
+
+ DebugPrintf("multi-frs total allocated wrong\n");
+
+ *ErrorsFound = TRUE;
+ }
+ }
+#endif
+ }
+
+
+ if (*ErrorsFound) {
+
+ // There's a problem so tell the user and tube all of the
+ // attribute list entries concerned.
+
+ Message->Set(MSG_CHK_NTFS_BAD_ATTR_LIST_ENTRY);
+ Message->Display("%d%d", first_record->QueryTypeCode(),
+ BaseFrs->QueryFileNumber().GetLowPart());
+
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+
+ iter->Reset();
+ while (attr_record = (PNTFS_ATTRIBUTE_RECORD) iter->GetNext()) {
+
+ if (!attr_record->IsResident() &&
+ !attr_record->UnUseClusters(VolumeBitmap,
+ ChkdskInfo->CrossLinkStart,
+ ChkdskInfo->CrossLinkLength)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+
+ DELETE(iter);
+ return FALSE;
+ }
+
+ if (!attr_record->QueryName(&name) ||
+ !AttributeList->DeleteEntry(attr_record->QueryTypeCode(),
+ attr_record->QueryLowestVcn(),
+ &name)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+
+ DELETE(iter);
+ return FALSE;
+ }
+ }
+ } else {
+
+ ChkdskReport->BytesUserData += total_clusters *
+ _drive->QuerySectorSize()*
+ QueryClusterFactor();
+ }
+
+ DELETE(iter);
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_SA::EnsureSurjectiveAttrList(
+ IN OUT PNTFS_FRS_STRUCTURE BaseFrs,
+ IN PCNTFS_ATTRIBUTE_LIST AttributeList,
+ IN OUT PSEQUENTIAL_CONTAINER ChildFrsList,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message,
+ IN OUT PBOOLEAN DiskErrorsFound
+ )
+/*++
+
+Routine Description:
+
+ This routine remove any attribute records that are not present in
+ the attribute list.
+
+Arguments:
+
+ BaseFrs - Supplies the base file record segment.
+ AttributeList - Supplies the attribute list.
+ ChildFrsList - Supplies the list of child FRS.
+ FixLevel - Supplies the fix up level.
+ Message - Supplies an outlet for messages.
+ DiskErrorsFound - Supplies whether or not disk errors have been found.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PVOID record;
+ NTFS_ATTRIBUTE_RECORD attr_record;
+ PNTFS_FRS_STRUCTURE frs, del_frs;
+ PITERATOR iter;
+ DSTRING null_string;
+ BOOLEAN changes;
+ DSTRING name;
+ BOOLEAN match_found;
+ ATTRIBUTE_TYPE_CODE attr_code;
+ VCN lowest_vcn;
+ DSTRING list_name;
+
+ if (!(iter = ChildFrsList->QueryIterator()) ||
+ !null_string.Initialize("\"\"")) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ for (frs = BaseFrs; frs; frs = (PNTFS_FRS_STRUCTURE) iter->GetNext()) {
+
+ changes = FALSE;
+
+ record = NULL;
+ while (record = frs->GetNextAttributeRecord(record)) {
+
+ if (!attr_record.Initialize(record)) {
+ DebugAbort("Couldn't initialize an attribute record");
+ return FALSE;
+ }
+
+ // The attribute list entry is not required to be in the
+ // attribute list.
+
+ if (frs == BaseFrs &&
+ attr_record.QueryTypeCode() == $ATTRIBUTE_LIST) {
+
+ continue;
+ }
+
+
+ // Find this attribute record in the attribute list.
+ // Otherwise, tube this attribute record.
+
+ match_found = AttributeList->QueryEntry(
+ frs->QuerySegmentReference(),
+ attr_record.QueryInstanceTag(),
+ &attr_code, &lowest_vcn, &list_name);
+
+ if (!match_found) {
+
+ if (!attr_record.QueryName(&name)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ Message->Set(MSG_CHK_NTFS_BAD_ATTR);
+ Message->Display("%d%W%d", attr_record.QueryTypeCode(),
+ name.QueryChCount() ? &name : &null_string,
+ frs->QueryFileNumber().GetLowPart());
+
+ frs->DeleteAttributeRecord(record);
+ record = NULL;
+ changes = TRUE;
+ }
+ }
+
+ if (frs != BaseFrs && !frs->GetNextAttributeRecord(NULL)) {
+ changes = TRUE;
+ frs->ClearInUse();
+ if (!(del_frs = (PNTFS_FRS_STRUCTURE) ChildFrsList->Remove(iter))) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ iter->GetPrevious();
+ } else {
+ del_frs = NULL;
+ }
+
+ if (changes && DiskErrorsFound) {
+ *DiskErrorsFound = TRUE;
+ }
+
+ if (changes && FixLevel != CheckOnly && !frs->Write()) {
+ Message->Set(MSG_CHK_READABLE_FRS_UNWRITEABLE);
+ Message->Display("%d", frs->QueryFileNumber().GetLowPart());
+ return FALSE;
+ }
+
+ DELETE(del_frs);
+ }
+
+
+ DELETE(iter);
+
+ return TRUE;
+}
+
+BOOLEAN
+NTFS_SA::HotfixMftData(
+ IN OUT PNTFS_ATTRIBUTE MftData,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN PCNUMBER_SET BadFrsList,
+ OUT PNUMBER_SET BadClusterList,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine replaces the unreadable FRS in the MFT with readable
+ FRS allocated from the volume bitmap. This routine will fail if
+ it cannot hotfix all of the system files. If there is not
+ sufficient disk space to hotfix non-system files then these files
+ will be left alone.
+
+ The clusters from the unreadable FRS will be added to the
+ unreadable clusters list. Only those FRS that were successfully
+ hotfixed will be added to this list.
+
+Arguments:
+
+ MftData - Supplies the MFT data attribute.
+ VolumeBitmap - Supplies a valid volume bitmap.
+ BadFrsList - Supplies the list of unreadable FRS.
+ BadClusterList - Returns the list of unreadable clusters.
+ FixLevel - Tells whether the disk should be modified.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ VCN unreadable_vcn;
+ VCN file_number;
+ ULONG i, j;
+ HMEM hmem;
+ NTFS_FRS_STRUCTURE frs;
+ LCN lcn, previous_lcn;
+ NUMBER_SET last_action;
+ ULONG cluster_size;
+ ULONG clusters_per_frs;
+
+ DebugAssert(MftData);
+ DebugAssert(VolumeBitmap);
+ DebugAssert(BadFrsList);
+ DebugAssert(BadClusterList);
+
+ if (!BadClusterList->Initialize()) {
+ return FALSE;
+ }
+
+ cluster_size = QueryClusterFactor() * _drive->QuerySectorSize();
+
+ if (QueryFrsSize() > cluster_size) {
+ clusters_per_frs = QueryFrsSize() / cluster_size;
+ } else {
+ clusters_per_frs = 1;
+ }
+
+ for (i = 0; i < BadFrsList->QueryCardinality(); i++) {
+
+ if (!last_action.Initialize()) {
+ return FALSE;
+ }
+
+ file_number = BadFrsList->QueryNumber(i);
+
+ unreadable_vcn = (file_number * QueryFrsSize()) / cluster_size;
+
+ // Figure out which clusters go with this frs. Save away the
+ // first one so that we can try to copy its contents later, if
+ // necessary.
+ //
+
+ if (!MftData->QueryLcnFromVcn(unreadable_vcn, &previous_lcn)) {
+ return FALSE;
+ }
+
+ for (j = 0; j < clusters_per_frs; j++) {
+ if (!MftData->QueryLcnFromVcn(unreadable_vcn + j, &lcn) ||
+ lcn == LCN_NOT_PRESENT ||
+ !BadClusterList->Add(lcn) ||
+ !last_action.Add(lcn)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ if (MftData->Hotfix(unreadable_vcn,
+ clusters_per_frs,
+ VolumeBitmap,
+ BadClusterList,
+ FALSE)) {
+
+ // The mft data clusters have been successfully replaced with new
+ // clusters. We want to set the new clusters/frs to indicate that
+ // it is not in use.
+ //
+
+ if (!hmem.Initialize() ||
+ !frs.Initialize(&hmem, MftData, file_number,
+ QueryClusterFactor(),
+ QueryVolumeSectors(),
+ QueryFrsSize(),
+ NULL)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ memset(hmem.GetBuf(), 0, hmem.QuerySize());
+ frs.ClearInUse();
+ if (FixLevel != CheckOnly) {
+ frs.Write();
+ }
+
+ // If there were multiple frs in a replaced cluster, we
+ // want to copy all those that can be read to the new location.
+ //
+
+ if (QueryFrsSize() < cluster_size) {
+
+ ULONG sectors_per_frs = QueryFrsSize() / _drive->QuerySectorSize();
+ SECRUN secrun;
+
+ MftData->QueryLcnFromVcn(unreadable_vcn, &lcn);
+
+ for (j = 0; j < cluster_size / QueryFrsSize(); j += sectors_per_frs) {
+
+ if (!hmem.Initialize() ||
+ !secrun.Initialize(&hmem, _drive,
+ previous_lcn * QueryClusterFactor() + j,
+ sectors_per_frs) ||
+ !secrun.Read()) {
+
+ continue;
+ }
+
+ secrun.Relocate(lcn * QueryClusterFactor() + j);
+
+ if (FixLevel != CheckOnly) {
+
+ PreWriteMultiSectorFixup(secrun.GetBuf(), QueryFrsSize());
+
+ secrun.Write();
+
+ PostReadMultiSectorFixup(secrun.GetBuf(), QueryFrsSize());
+ }
+ }
+ }
+
+ } else {
+
+ // We couldn't hot fix it so we don't want it to ever be added
+ // to the bad clusters file.
+
+ for (j = 0; j < last_action.QueryCardinality().GetLowPart(); j++) {
+
+ if (!BadClusterList->Remove(last_action.QueryNumber(j))) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+
+ // If we couldn't fix one of the system files then scream.
+
+ if (file_number < FIRST_USER_FILE_NUMBER) {
+ Message->Set(MSG_CHK_NTFS_CANT_HOTFIX_SYSTEM_FILES);
+ Message->Display("%d", file_number.GetLowPart());
+ return FALSE;
+ } else {
+ Message->Set(MSG_CHK_NTFS_CANT_HOTFIX);
+ Message->Display("%d", file_number.GetLowPart());
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_SA::AreBitmapsEqual(
+ IN OUT PNTFS_ATTRIBUTE BitmapAttribute,
+ IN PCNTFS_BITMAP Bitmap,
+ IN BIG_INT MinimumBitmapSize OPTIONAL,
+ IN OUT PMESSAGE Message,
+ OUT PBOOLEAN CompleteFailure,
+ OUT PBOOLEAN SecondIsSubset
+ )
+/*++
+
+Routine Description:
+
+ This routine compares these two bitmaps and returns whether
+ or not they are equal.
+
+ This routine will return FALSE if it cannot read all of the
+ attribute pointed to by 'BitmapAttribute'.
+
+Arguments:
+
+ BitmapAttribute - Supplies the bitmap attribute to compare.
+ Bitmap - Supplies the in memory bitmap to compare.
+ MinimumBitmapSize - Supplies the minimum number of bits
+ required in the bitmap. All subsequent
+ bits must be zero. If this parameter
+ is zero then both bitmaps must be the
+ same size.
+ Message - Supplies an outlet for messages.
+ CompleteFailure - Returns whether or not an unrecoverable
+ error occured while running.
+ SecondIsSubset - Returns TRUE if 'Bitmap' is has a
+ subset of the bits set by 'BitmapAttribute'.
+
+Return Value:
+
+ FALSE - The bitmaps are not equal.
+ TRUE - The bitmaps are equal.
+
+--*/
+{
+ CONST MaxNumBytesToCompare = 65536;
+
+ ULONG num_bytes, chomp_length, bytes_read, min_num_bytes, disk_bytes;
+ ULONG bytes_left;
+ PUCHAR attr_ptr, in_mem_ptr;
+ PBYTE p1, p2;
+ ULONG i, j;
+
+ *CompleteFailure = FALSE;
+
+ if (SecondIsSubset) {
+ *SecondIsSubset = TRUE;
+ }
+
+ in_mem_ptr = (PUCHAR) Bitmap->GetBitmapData(&num_bytes);
+ disk_bytes = BitmapAttribute->QueryValueLength().GetLowPart();
+
+ // The size of the on-disk bitmap must be a multiple of 8
+ // bytes.
+
+ if (disk_bytes % 8 != 0) {
+ if (SecondIsSubset) {
+ *SecondIsSubset = FALSE;
+ }
+ return FALSE;
+ }
+
+ // Compute the number of bytes that need to be compared.
+ // Beyond this point, all bytes must be zero.
+
+ if (MinimumBitmapSize == 0) {
+ min_num_bytes = num_bytes;
+ } else {
+ min_num_bytes = ((MinimumBitmapSize - 1)/8 + 1).GetLowPart();
+ }
+
+ // If the minimum bitmap size is not defined or the given
+ // value is greater than either of the operands then this
+ // means that the bitmaps must really be equal, including
+ // their lengths.
+
+ if (MinimumBitmapSize == 0 ||
+ min_num_bytes > num_bytes ||
+ min_num_bytes > disk_bytes) {
+
+ if (num_bytes != disk_bytes) {
+ if (SecondIsSubset) {
+ *SecondIsSubset = FALSE;
+ }
+ return FALSE;
+ }
+
+ min_num_bytes = num_bytes;
+ }
+
+ if (!(attr_ptr = NEW UCHAR[min(MaxNumBytesToCompare, min_num_bytes)])) {
+ *CompleteFailure = TRUE;
+ if (SecondIsSubset) {
+ *SecondIsSubset = FALSE;
+ }
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+
+ return FALSE;
+ }
+
+ for (i = 0; i < min_num_bytes; i += MaxNumBytesToCompare) {
+
+ chomp_length = min(MaxNumBytesToCompare, min_num_bytes - i);
+
+ // NOTE: these variables are used to avoid an optimization
+ // bug in the compiler. Before removing them, check that code
+ // generated for the memcmp below is correct.
+ //
+ p1 = attr_ptr;
+ p2 = &in_mem_ptr[i];
+
+ if (!BitmapAttribute->Read(attr_ptr, i, chomp_length, &bytes_read) ||
+ bytes_read != chomp_length) {
+
+ if (SecondIsSubset) {
+ *SecondIsSubset = FALSE;
+ }
+
+ DELETE(attr_ptr);
+ return FALSE;
+ }
+
+ if (memcmp(p1, p2, chomp_length)) {
+
+ if (SecondIsSubset) {
+ for (j = 0; j < chomp_length; j++) {
+ if (~(~in_mem_ptr[i + j] | attr_ptr[j]) != 0) {
+ *SecondIsSubset = FALSE;
+ }
+ }
+ }
+
+ DELETE(attr_ptr);
+ return FALSE;
+ }
+ }
+
+ DELETE(attr_ptr);
+
+ // Make sure that everything after 'min_num_bytes' on both
+ // bitmaps is zero.
+
+ for (i = min_num_bytes; i < num_bytes; i++) {
+ if (in_mem_ptr[i]) {
+
+ if (SecondIsSubset) {
+ *SecondIsSubset = FALSE;
+ }
+
+ return FALSE;
+ }
+ }
+
+ // Read in the remainder of the on disk bitmap.
+
+ bytes_left = disk_bytes - min_num_bytes;
+
+ if (!bytes_left) {
+ return TRUE;
+ }
+
+ if (!(attr_ptr = NEW UCHAR[bytes_left]) ||
+ !BitmapAttribute->Read(attr_ptr, min_num_bytes,
+ bytes_left, &bytes_read) ||
+ bytes_read != bytes_left) {
+
+ if (SecondIsSubset) {
+ *SecondIsSubset = FALSE;
+ }
+
+ DELETE(attr_ptr);
+ return FALSE;
+ }
+
+ for (i = 0; i < bytes_left; i++) {
+ if (attr_ptr[i]) {
+ if (SecondIsSubset) {
+ *SecondIsSubset = FALSE;
+ }
+ return FALSE;
+ }
+ }
+
+ DELETE(attr_ptr);
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_SA::SynchronizeMft(
+ IN OUT PNTFS_INDEX_TREE RootIndex,
+ IN PNTFS_MASTER_FILE_TABLE InternalMft,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine fixes the MFT file with the internal Mft.
+
+Arguments:
+
+ RootIndex - Supplies the root index.
+ InternalMft - Supplies the internal MFT.
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+Notes:
+
+ Any bad clusters discovered by this routine are marked in the volume
+ bitmap but not added to the bad clusters file.
+
+--*/
+{
+ NTFS_FILE_RECORD_SEGMENT mft_file;
+ NTFS_FILE_RECORD_SEGMENT bitmap_file;
+ NTFS_ATTRIBUTE disk_mft_data;
+ NTFS_ATTRIBUTE mft_bitmap_attribute;
+ NTFS_ATTRIBUTE volume_bitmap_attribute;
+ PNTFS_ATTRIBUTE mft_data;
+ PNTFS_BITMAP mft_bitmap;
+ PNTFS_BITMAP volume_bitmap;
+ BOOLEAN replace;
+ BOOLEAN convergence;
+ ULONG i;
+ NTFS_EXTENT_LIST extents;
+ NUMBER_SET bad_clusters;
+ BOOLEAN complete_failure;
+ BOOLEAN second_is_subset;
+ BOOLEAN ErrorInAttribute;
+ ULONG min_bits_in_mft_bitmap;
+
+
+ DebugAssert(InternalMft);
+ DebugAssert(Message);
+
+ if (!bad_clusters.Initialize()) {
+ DebugAssert("Could not initialize a bad clusters list");
+ return FALSE;
+ }
+
+ mft_data = InternalMft->GetDataAttribute();
+ mft_bitmap = InternalMft->GetMftBitmap();
+ volume_bitmap = InternalMft->GetVolumeBitmap();
+
+ DebugAssert(mft_data);
+ DebugAssert(mft_bitmap);
+ DebugAssert(volume_bitmap);
+
+ if (!mft_file.Initialize(MASTER_FILE_TABLE_NUMBER, InternalMft) ||
+ !bitmap_file.Initialize(BIT_MAP_FILE_NUMBER, InternalMft)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!mft_file.Read() || !bitmap_file.Read()) {
+ DebugAbort("Previously readable FRS is unreadable");
+ return FALSE;
+ }
+
+ convergence = FALSE;
+ for (i = 0; !convergence; i++) {
+
+ convergence = TRUE;
+
+
+ // Do the MFT $DATA first.
+
+ if (mft_file.QueryAttribute(&disk_mft_data, &ErrorInAttribute, $DATA)) {
+
+ if (disk_mft_data == *mft_data) {
+ replace = FALSE;
+ } else {
+ replace = TRUE;
+ }
+ } else if (ErrorInAttribute) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ } else {
+ replace = TRUE;
+ }
+
+ if (replace) {
+
+ if (FixLevel != CheckOnly) {
+ convergence = FALSE;
+ }
+
+ // We don't resize the disk MFT to zero because
+ // this could clear bits that are now in use
+ // by other attributes.
+
+ if (!mft_data->MarkAsAllocated(volume_bitmap)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (i == 0) {
+ Message->Set(MSG_CHK_NTFS_CORRECTING_MFT_DATA);
+ Message->Display();
+ }
+
+ if (!mft_data->InsertIntoFile(&mft_file, volume_bitmap)) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_MFT);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (FixLevel != CheckOnly &&
+ !mft_file.Flush(volume_bitmap, RootIndex)) {
+ Message->Set(MSG_CHK_READABLE_FRS_UNWRITEABLE);
+ Message->Display("%d", ROOT_FILE_NAME_INDEX_NUMBER);
+ return FALSE;
+ }
+ }
+
+
+ // Do the MFT $BITMAP next.
+
+ if (mft_file.QueryAttribute(&mft_bitmap_attribute,
+ &ErrorInAttribute, $BITMAP)) {
+
+ min_bits_in_mft_bitmap =
+ (mft_data->QueryValueLength()/mft_file.QuerySize()).GetLowPart();
+
+ if (AreBitmapsEqual(&mft_bitmap_attribute, mft_bitmap,
+ min_bits_in_mft_bitmap,
+ Message, &complete_failure,
+ &second_is_subset)) {
+
+ replace = FALSE;
+
+ } else {
+
+ if (complete_failure) {
+ return FALSE;
+ }
+
+ replace = TRUE;
+ }
+ } else if (ErrorInAttribute) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ } else {
+ replace = TRUE;
+ second_is_subset = FALSE;
+
+ // Create mft_bitmap_attribute.
+
+ if (!extents.Initialize(0, 0) ||
+ !mft_bitmap_attribute.Initialize(_drive,
+ QueryClusterFactor(),
+ &extents,
+ 0, 0, $BITMAP)) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_MFT);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ if (replace) {
+
+ if (FixLevel != CheckOnly) {
+ convergence = FALSE;
+ }
+
+ if (i == 0 || !second_is_subset) {
+
+ Message->Set(second_is_subset ?
+ MSG_CHK_NTFS_MINOR_MFT_BITMAP_ERROR :
+ MSG_CHK_NTFS_CORRECTING_MFT_BITMAP);
+ Message->Display();
+ }
+
+ if (FixLevel != CheckOnly &&
+ (!mft_bitmap_attribute.MakeNonresident(volume_bitmap) ||
+ !mft_bitmap->Write(&mft_bitmap_attribute, volume_bitmap))) {
+
+ if (!mft_bitmap_attribute.RecoverAttribute(volume_bitmap,
+ &bad_clusters) ||
+ !mft_bitmap->Write(&mft_bitmap_attribute, volume_bitmap)) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_MFT);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ if (mft_bitmap_attribute.IsStorageModified() &&
+ !mft_bitmap_attribute.InsertIntoFile(&mft_file,
+ volume_bitmap)) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_MFT);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (FixLevel != CheckOnly &&
+ !mft_file.Flush(volume_bitmap, RootIndex)) {
+ Message->Set(MSG_CHK_READABLE_FRS_UNWRITEABLE);
+ Message->Display("%d", ROOT_FILE_NAME_INDEX_NUMBER);
+ return FALSE;
+ }
+ }
+
+
+ // Do the volume bitmap next.
+
+ if (bitmap_file.QueryAttribute(&volume_bitmap_attribute,
+ &ErrorInAttribute, $DATA)) {
+
+ if (AreBitmapsEqual(&volume_bitmap_attribute, volume_bitmap, 0,
+ Message, &complete_failure,
+ &second_is_subset)) {
+
+ replace = FALSE;
+
+ } else {
+
+ if (complete_failure) {
+ return FALSE;
+ }
+
+ replace = TRUE;
+ }
+ } else if (ErrorInAttribute) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ } else {
+ replace = TRUE;
+ second_is_subset = FALSE;
+
+ // Create mft_bitmap_attribute.
+
+ if (!extents.Initialize(0, 0) ||
+ !volume_bitmap_attribute.Initialize(_drive,
+ QueryClusterFactor(),
+ &extents,
+ 0, 0, $DATA)) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_VOLUME_BITMAP);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ if (replace) {
+
+ if (FixLevel != CheckOnly) {
+ convergence = FALSE;
+ }
+
+ if (i == 0 || !second_is_subset) {
+
+ Message->Set(second_is_subset ?
+ MSG_CHK_NTFS_MINOR_VOLUME_BITMAP_ERROR :
+ MSG_CHK_NTFS_CORRECTING_VOLUME_BITMAP);
+ Message->Display();
+ }
+
+ if (FixLevel != CheckOnly &&
+ (!volume_bitmap_attribute.MakeNonresident(volume_bitmap) ||
+ !volume_bitmap->Write(&volume_bitmap_attribute,
+ volume_bitmap))) {
+
+ if (!volume_bitmap_attribute.RecoverAttribute(volume_bitmap,
+ &bad_clusters) ||
+ !volume_bitmap->Write(&volume_bitmap_attribute,
+ volume_bitmap)) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_VOLUME_BITMAP);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ if (volume_bitmap_attribute.IsStorageModified() &&
+ !volume_bitmap_attribute.InsertIntoFile(&bitmap_file,
+ volume_bitmap)) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_MFT);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (FixLevel != CheckOnly &&
+ !bitmap_file.Flush(volume_bitmap, RootIndex)) {
+ Message->Set(MSG_CHK_READABLE_FRS_UNWRITEABLE);
+ Message->Display("%d", ROOT_FILE_NAME_INDEX_NUMBER);
+ return FALSE;
+ }
+ }
+ }
+
+ if (FixLevel != CheckOnly) {
+ if (!mft_file.Flush(NULL, RootIndex) ||
+ !bitmap_file.Flush(NULL, RootIndex)) {
+ Message->Set(MSG_CHK_READABLE_FRS_UNWRITEABLE);
+ Message->Display("%d", ROOT_FILE_NAME_INDEX_NUMBER);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_SA::ResetLsns(
+ IN OUT PMESSAGE Message,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN BOOLEAN SkipRootIndex
+ )
+/*++
+
+Routine Description:
+
+ This method sets all the LSN's on the volume to zero.
+
+Arguments:
+
+ Message -- Supplies an outlet for messages.
+ Mft -- Supplies the volume's Master File Table.
+ SkipRootIndex -- Supplies a flag which indicates, if TRUE,
+ that the root index FRS and index should
+ be skipped. In that case, the client is
+ responsible for resetting the LSN's on
+ those items.
+--*/
+{
+ NTFS_FILE_RECORD_SEGMENT frs;
+ NTFS_INDEX_TREE index;
+ NTFS_ATTRIBUTE index_root;
+ ULONG i, j, n, frs_size, num_frs_per_prime;
+ ULONG percent_done = 0;
+ BOOLEAN error_in_attribute;
+
+ Message->Set(MSG_CHK_NTFS_RESETTING_LSNS);
+ Message->Display("");
+
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", 0)) {
+ return FALSE;
+ }
+
+ // Compute the number of file records.
+ //
+ frs_size = Mft->QueryFrsSize();
+
+ n = (Mft->GetDataAttribute()->QueryValueLength()/frs_size).GetLowPart();
+ num_frs_per_prime = MFT_PRIME_SIZE/frs_size;
+
+
+
+ for (i = 0; i < n; i += 1) {
+
+ if (i*100/n != percent_done) {
+ percent_done = (i*100/n);
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", percent_done)) {
+ return FALSE;
+ }
+ }
+
+ if (i % num_frs_per_prime == 0) {
+ Mft->GetDataAttribute()->PrimeCache(i*frs_size,
+ num_frs_per_prime*frs_size);
+ }
+
+ // if specified, skip the root file index
+ //
+ if (SkipRootIndex && i == ROOT_FILE_NAME_INDEX_NUMBER) {
+
+ continue;
+ }
+
+ if (!frs.Initialize(i, Mft)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ // If the FRS is unreadable or is not in use, skip it.
+ //
+ if (!frs.Read() || !frs.IsInUse()) {
+
+ continue;
+ }
+
+ frs.SetLsn( 0 );
+ frs.Write();
+
+ // Iterate through all the indices present in this FRS
+ // (if any), resetting LSN's on all of them.
+ //
+ error_in_attribute = FALSE;
+
+ for (j = 0; frs.QueryAttributeByOrdinal( &index_root,
+ &error_in_attribute,
+ $INDEX_ROOT,
+ j ); j++) {
+
+ if (!index.Initialize(_drive,
+ QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ Mft->GetUpcaseTable(),
+ frs.QuerySize()/2,
+ &frs,
+ index_root.GetName()) ||
+ !index.ResetLsns(Message)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ if (error_in_attribute) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ }
+
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", 100)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+NTFS_SA::FindHighestLsn(
+ IN OUT PMESSAGE Message,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ OUT PLSN HighestLsn
+ )
+/*++
+
+Routine Description:
+
+ This function traverses the volume to find the highest LSN
+ on the volume. It is currently unused, but had previously
+ been a worker for ResizeCleanLogFile().
+
+Arguments:
+
+ Message -- Supplies an outlet for messages.
+ Mft -- Supplies the volume Master File Table.
+ HighestLsn -- Receives the highest LSN found on the volume.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ NTFS_FILE_RECORD_SEGMENT frs;
+ NTFS_INDEX_TREE index;
+ NTFS_ATTRIBUTE index_root;
+ LSN HighestLsnInIndex;
+ ULONG i, j, n, frs_size, num_frs_per_prime;
+ ULONG percent_done = 0;
+ BOOLEAN error_in_attribute;
+
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", 0)) {
+ return FALSE;
+ }
+
+ // Compute the number of file records.
+ //
+ frs_size = Mft->QueryFrsSize();
+
+ n = (Mft->GetDataAttribute()->QueryValueLength()/frs_size).GetLowPart();
+ num_frs_per_prime = MFT_PRIME_SIZE/frs_size;
+
+
+ for (i = 0; i < n; i += 1) {
+
+ if (i*100/n != percent_done) {
+ percent_done = (i*100/n);
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", percent_done)) {
+ return FALSE;
+ }
+ }
+
+ if (i % num_frs_per_prime == 0) {
+ Mft->GetDataAttribute()->PrimeCache(i*frs_size,
+ num_frs_per_prime*frs_size);
+ }
+
+ if (!frs.Initialize(i, Mft)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ // If the FRS is unreadable or is not in use, skip it.
+ //
+ if (!frs.Read() || !frs.IsInUse()) {
+
+ continue;
+ }
+
+ if (frs.QueryLsn() > *HighestLsn) {
+
+ *HighestLsn = frs.QueryLsn();
+ }
+
+ // Iterate through all the indices present in this FRS
+ // (if any), resetting LSN's on all of them.
+ //
+ error_in_attribute = FALSE;
+
+ for (j = 0; frs.QueryAttributeByOrdinal( &index_root,
+ &error_in_attribute,
+ $INDEX_ROOT,
+ j ); j++) {
+
+ if (!index.Initialize(_drive,
+ QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ Mft->GetUpcaseTable(),
+ frs.QuerySize()/2,
+ &frs,
+ index_root.GetName()) ||
+ !index.FindHighestLsn(Message, &HighestLsnInIndex)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (HighestLsnInIndex > *HighestLsn) {
+
+ *HighestLsn = HighestLsnInIndex;
+ }
+ }
+
+ if (error_in_attribute) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", 100)) {
+ return FALSE;
+ }
+
+ return TRUE;
+
+}
+
+
+BOOLEAN
+NTFS_SA::ResizeCleanLogFile(
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN ExplicitResize,
+ IN ULONG DesiredSize
+ )
+/*++
+
+Routine Description:
+
+ This method resizes the log file to its default size. It may
+ be used only when the volume has been shut down cleanly.
+
+Arguments:
+
+ Message - Supplies an outlet for messages.
+ ExplicitResize - Tells whether this is just the default check, or
+ if the user explicitly asked for a resize. If FALSE, the
+ logfile will be resized only if it is wildly out of
+ whack. If TRUE, the logfile will be resized to
+ the desired size.
+ DesiredSize - Supplies the desired size, or zero if the user just
+ wants to query the current size.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ NTFS_BITMAP VolumeBitmap;
+ NTFS_UPCASE_TABLE UpcaseTable;
+
+ NTFS_UPCASE_FILE UpcaseFile;
+ NTFS_BITMAP_FILE BitmapFile;
+ NTFS_MFT_FILE MftFile;
+ NTFS_LOG_FILE LogFile;
+ NTFS_FILE_RECORD_SEGMENT MftMirror;
+
+ NTFS_ATTRIBUTE UpcaseAttribute;
+ NTFS_ATTRIBUTE BitmapAttribute;
+ NTFS_ATTRIBUTE MirrorAttribute;
+
+ HMEM MirrorMem;
+
+ LSN HighestLsn;
+ BIG_INT BigZero, TempBigInt;
+ BIG_INT FreeSectorSize;
+ ULONG MirrorSize, BytesTransferred;
+ BOOLEAN error, LogFileGrew, Changed;
+
+
+ // If we're just doing the usual check and not an explicitly-asked for
+ // resize, do a quick check to see if there's anything to do.
+ //
+
+ if (!ExplicitResize && !LogFileMayNeedResize()) {
+ return TRUE;
+ }
+
+ // Initialize the bitmap, fetch the MFT, and read the bitmap
+ // and upcase table.
+ //
+
+ if (!VolumeBitmap.Initialize( QueryVolumeSectors()/QueryClusterFactor(),
+ FALSE, _drive, QueryClusterFactor()) ||
+ !MftFile.Initialize( _drive,
+ QueryMftStartingLcn(),
+ QueryClusterFactor(),
+ QueryFrsSize(),
+ QueryVolumeSectors(),
+ &VolumeBitmap,
+ NULL ) ||
+ !MftFile.Read() ||
+ MftFile.GetMasterFileTable() == NULL ||
+ !BitmapFile.Initialize( MftFile.GetMasterFileTable() ) ||
+ !BitmapFile.Read() ||
+ !BitmapFile.QueryAttribute( &BitmapAttribute, &error, $DATA ) ||
+ !VolumeBitmap.Read( &BitmapAttribute ) ||
+ !UpcaseFile.Initialize( MftFile.GetMasterFileTable() ) ||
+ !UpcaseFile.Read() ||
+ !UpcaseFile.QueryAttribute( &UpcaseAttribute, &error, $DATA ) ||
+ !UpcaseTable.Initialize( &UpcaseAttribute ) ) {
+
+ return FALSE;
+ }
+
+ FreeSectorSize = VolumeBitmap.QueryFreeClusters() * QueryClusterFactor();
+ if (DesiredSize/_drive->QuerySectorSize() > FreeSectorSize) {
+
+ Message->Set( MSG_CHK_NTFS_TOO_BIG_LOGFILE_SIZE );
+ Message->Display();
+ return FALSE;
+ }
+
+ MftFile.SetUpcaseTable( &UpcaseTable );
+ MftFile.GetMasterFileTable()->SetUpcaseTable( &UpcaseTable );
+
+ // Initialize and read the log file. Make sure the volume
+ // was shut down cleanly.
+ //
+
+ if (!LogFile.Initialize( MftFile.GetMasterFileTable() ) ||
+ !LogFile.Read()) {
+
+ return FALSE;
+ }
+
+ if (ExplicitResize && 0 == DesiredSize) {
+
+ NTFS_ATTRIBUTE attrib;
+ ULONG default_size, current_size;
+
+ // The user just wants to query the current logfile size. Do
+ // that and exit. Also print the default logfile size for this
+ // volume.
+ //
+
+ if (!LogFile.QueryAttribute( &attrib, &error, $DATA )) {
+ return FALSE;
+ }
+
+ current_size = attrib.QueryValueLength().GetLowPart() / 1024;
+ default_size = LogFile.QueryDefaultSize( _drive, QueryVolumeSectors() ) / 1024;
+
+ Message->Set( MSG_CHK_LOGFILE_SIZE );
+ Message->Display( "%d%d", current_size, default_size );
+
+ return TRUE;
+ }
+
+ if (ExplicitResize &&
+ DesiredSize < LogFile.QueryMinimumSize( _drive, QueryVolumeSectors() )) {
+
+ Message->Set( MSG_CHK_BAD_LOGFILE_SIZE );
+ Message->Display();
+ return FALSE;
+ }
+
+ // Resize the logfile.
+ //
+
+ if (!LogFile.EnsureCleanShutdown() ||
+ !LogFile.Resize( DesiredSize, &VolumeBitmap, FALSE, &Changed,
+ &LogFileGrew, Message )) {
+
+ return FALSE;
+ }
+
+ if (!Changed) {
+
+ // The log file was already the correct size.
+ //
+
+ return TRUE;
+ }
+
+ // If the log file is growing, write the volume bitmap
+ // before flushing the log file frs; if it's shrinking, write
+ // the bitmap after flushing the log file frs. That way, if
+ // the second operation (either writing the log file FRS or
+ // the bitmap) fails, the only bitmap errors will be free
+ // space marked as allocated.
+ //
+ // Since this is a fixed-size, non-resident attribute, writing
+ // it doesn't change its File Record Segment.
+ //
+
+ if (LogFileGrew && !VolumeBitmap.Write( &BitmapAttribute, NULL )) {
+
+ return FALSE;
+ }
+
+ // Flush the log file. Since the log file never has
+ // external attributes, flushing it won't change the MFT.
+ // Note that the index entry for the log file is not updated.
+ //
+
+ if (!LogFile.Flush( NULL, NULL )) {
+
+ return FALSE;
+ }
+
+ // If we didn't already, write the volume bitmap.
+ //
+
+ if (!LogFileGrew && !VolumeBitmap.Write( &BitmapAttribute, NULL )) {
+
+ return FALSE;
+ }
+
+ // Clear the Resize Log File bit in the Volume DASD file.
+ // Note that the log file is already marked as Checked.
+ //
+
+ BigZero = 0;
+ SetVolumeClean( VOLUME_RESIZE_LOG_FILE,
+ NULL, FALSE, BigZero.GetLargeInteger(), NULL );
+
+ // Update the MFT Mirror.
+ //
+
+ MirrorSize = REFLECTED_MFT_SEGMENTS * MftFile.QuerySize();
+
+ if (!MirrorMem.Initialize() ||
+ !MirrorMem.Acquire( MirrorSize ) ||
+ !MftMirror.Initialize( MASTER_FILE_TABLE2_NUMBER, &MftFile ) ||
+ !MftMirror.Read() ||
+ !MftMirror.QueryAttribute( &MirrorAttribute, &error, $DATA ) ||
+ !MftFile.GetMasterFileTable()->
+ GetDataAttribute()->Read( MirrorMem.GetBuf(), 0,
+ MirrorSize, &BytesTransferred ) ||
+ BytesTransferred != MirrorSize ||
+ !MirrorAttribute.Write( MirrorMem.GetBuf(), 0, MirrorSize,
+ &BytesTransferred, NULL ) ||
+ BytesTransferred != MirrorSize) {
+
+ DebugPrintf( "UNTFS: Error updating MFT Mirror.\n" );
+ // but don't return FALSE, since we've changed the log file.
+ }
+
+
+#if defined( _AUTOCHECK_ )
+
+ // If this is AUTOCHK and we're running on the boot partition then
+ // we should reboot so that the cache doesn't stomp on us.
+
+ DSTRING sdrive, canon_sdrive, canon_drive;
+
+ FSTRING boot_log_file_name;
+
+ if (IFS_SYSTEM::QueryNtSystemDriveName(&sdrive) &&
+ IFS_SYSTEM::QueryCanonicalNtDriveName(&sdrive, &canon_sdrive) &&
+ IFS_SYSTEM::QueryCanonicalNtDriveName(_drive->GetNtDriveName(),
+ &canon_drive) &&
+ !canon_drive.Stricmp(&canon_sdrive)) {
+
+ Message->Set(MSG_CHK_BOOT_PARTITION_REBOOT);
+ Message->Display();
+
+ boot_log_file_name.Initialize( L"bootex.log" );
+
+ if (Message->IsLoggingEnabled() &&
+ !DumpMessagesToFile( &boot_log_file_name,
+ &MftFile,
+ Message )) {
+
+ DebugPrintf( "UNTFS: Error writing messages to BOOTEX.LOG\n" );
+ }
+
+ IFS_SYSTEM::Reboot();
+ }
+
+#endif
+
+ return TRUE;
+}
+
+BOOLEAN
+EnsureValidFileAttributes(
+ IN OUT PNTFS_FILE_RECORD_SEGMENT Frs,
+ IN OUT PNTFS_INDEX_TREE ParentIndex,
+ OUT PBOOLEAN SaveIndex,
+ IN OUT PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine makes sure the FileAttributes in the given
+ Frs has the hidden and system flags set but not the read-only
+ bit.
+
+Arguments:
+
+ Frs - Supplies the frs to examine
+ ParentIndex - Supplies the parent index of the given Frs
+ SaveIndex - Supplies whether there is a need to save the
+ parent index
+ ChkdskInfo - Supplies the current chkdsk info.
+ Mft - Supplies the MFT.
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PSTANDARD_INFORMATION2 pstandard;
+ NTFS_ATTRIBUTE attrib;
+ BOOLEAN error;
+ ULONG file_attributes;
+ ULONG old_file_attributes;
+ PINDEX_ENTRY foundEntry;
+ PNTFS_INDEX_BUFFER containingBuffer;
+ ULONG num_bytes;
+ ULONG length;
+ PFILE_NAME pfile_name;
+
+ //
+ // Check the FileAttributes in $STANDARD_INFORMATION first
+ //
+
+ if (!Frs->QueryAttribute(&attrib, &error, $STANDARD_INFORMATION)) {
+ DebugPrintf("Unable to locate $STANDARD_INFORMATION attribute of file %d\n",
+ Frs->QueryFileNumber().GetLowPart());
+ return FALSE;
+ }
+
+ pstandard = (PSTANDARD_INFORMATION2)attrib.GetResidentValue();
+ if (!pstandard) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ file_attributes = pstandard->FileAttributes;
+ if (!(file_attributes & FAT_DIRENT_ATTR_HIDDEN) ||
+ !(file_attributes & FAT_DIRENT_ATTR_SYSTEM) ||
+ !(file_attributes & DUP_VIEW_INDEX_PRESENT) ||
+ (file_attributes & FAT_DIRENT_ATTR_READ_ONLY)) {
+
+ file_attributes &= ~FAT_DIRENT_ATTR_READ_ONLY;
+ file_attributes |= FAT_DIRENT_ATTR_HIDDEN |
+ FAT_DIRENT_ATTR_SYSTEM |
+ DUP_VIEW_INDEX_PRESENT;
+ pstandard->FileAttributes = file_attributes;
+
+ Message->Set(MSG_CHK_NTFS_MINOR_CHANGES_TO_FRS);
+ Message->Display("%d", Frs->QueryFileNumber().GetLowPart());
+
+ if (FixLevel != CheckOnly &&
+ (!attrib.Write((PVOID)pstandard,
+ 0,
+ sizeof(STANDARD_INFORMATION2),
+ &num_bytes,
+ Mft->GetVolumeBitmap()) ||
+ num_bytes != sizeof(STANDARD_INFORMATION2))) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_ATTRIBUTE);
+ Message->Display("%d%d", attrib.QueryTypeCode(),
+ Frs->QueryFileNumber().GetLowPart());
+ return FALSE;
+ }
+
+ if (FixLevel != CheckOnly && attrib.IsStorageModified() &&
+ !attrib.InsertIntoFile(Frs, Mft->GetVolumeBitmap())) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_ATTRIBUTE);
+ Message->Display("%d%d", attrib.QueryTypeCode(),
+ Frs->QueryFileNumber().GetLowPart());
+ return FALSE;
+ }
+
+ //
+ // Now update the FileAttributes in DUPLICATED_INFORMATION in $FILE_NAME
+ //
+
+ if (!Frs->QueryAttribute(&attrib, &error, $FILE_NAME)) {
+ DebugPrintf("Unable to locate $FILE_NAME attribute of file %d\n",
+ Frs->QueryFileNumber().GetLowPart());
+ return FALSE;
+ }
+
+ DebugAssert(attrib.QueryValueLength().GetHighPart() == 0);
+ length = attrib.QueryValueLength().GetLowPart();
+ if (!(pfile_name = (PFILE_NAME)MALLOC(length))) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!attrib.Read(pfile_name, 0, length, &num_bytes) ||
+ num_bytes != length) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(pfile_name);
+ return FALSE;
+ }
+
+ old_file_attributes = pfile_name->Info.FileAttributes;
+ pfile_name->Info.FileAttributes = file_attributes;
+ if (!attrib.Write(pfile_name, 0, length, &num_bytes,
+ Mft->GetVolumeBitmap())) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_ATTRIBUTE);
+ Message->Display("%d%d", attrib.QueryTypeCode(),
+ Frs->QueryFileNumber().GetLowPart());
+ FREE(pfile_name);
+ return FALSE;
+ }
+
+ //
+ // Finally, delete the $FILE_NAME entry in the index
+ // so that it will get updated later on
+ //
+
+ pfile_name->Info.FileAttributes = old_file_attributes;
+
+ if (ParentIndex->QueryEntry(length,
+ pfile_name,
+ 0,
+ &foundEntry,
+ &containingBuffer,
+ &error)) {
+
+ if (!ParentIndex->DeleteEntry(length, pfile_name, 0)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(pfile_name);
+ return FALSE;
+ }
+ *SaveIndex = TRUE;
+
+ } else if (error) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(pfile_name);
+ return FALSE;
+ }
+
+ FREE(pfile_name);
+
+ if (FixLevel != CheckOnly && !Frs->Flush(NULL)) {
+ if (ChkdskInfo->ObjectIdFileNumber == Frs->QueryFileNumber())
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_OBJID);
+ else if (ChkdskInfo->QuotaFileNumber == Frs->QueryFileNumber())
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_QUOTA);
+ else
+ DebugAssert(FALSE);
+ Message->Display();
+ return FALSE;
+ }
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ }
+ return TRUE;
+}
diff --git a/private/utils/untfs/src/ntfssa.cxx b/private/utils/untfs/src/ntfssa.cxx
new file mode 100644
index 000000000..36ea0f528
--- /dev/null
+++ b/private/utils/untfs/src/ntfssa.cxx
@@ -0,0 +1,1707 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "ntfssa.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+
+#include "array.hxx"
+#include "arrayit.hxx"
+
+#include "mftfile.hxx"
+#include "ntfsbit.hxx"
+#include "frs.hxx"
+#include "wstring.hxx"
+#include "indxtree.hxx"
+#include "badfile.hxx"
+#include "bitfrs.hxx"
+#include "attrib.hxx"
+#include "attrrec.hxx"
+#include "mft.hxx"
+#include "logfile.hxx"
+#include "upcase.hxx"
+#include "upfile.hxx"
+#include "ifssys.hxx"
+
+
+#if !defined( _SETUP_LOADER_ ) && !defined( _AUTOCHECK_ )
+
+#include "path.hxx"
+
+#endif // _SETUP_LOADER_
+
+UCHAR NTFS_SA::_MajorVersion = NTFS_CURRENT_MAJOR_VERSION,
+ NTFS_SA::_MinorVersion = NTFS_CURRENT_MINOR_VERSION;
+
+DEFINE_EXPORTED_CONSTRUCTOR( NTFS_SA, SUPERAREA, UNTFS_EXPORT );
+
+
+VOID
+NTFS_SA::Construct (
+ )
+/*++
+
+Routine Description:
+
+ This routine sets an NTFS_SA to a default initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _boot_sector = NULL;
+ memset(&_bpb, 0, sizeof(BIOS_PARAMETER_BLOCK));
+ _boot2 = 0;
+ _boot3 = 0;
+}
+
+
+VOID
+NTFS_SA::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns an NTFS_SA to a default initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _boot_sector = NULL;
+ memset(&_bpb, 0, sizeof(BIOS_PARAMETER_BLOCK));
+ _boot2 = 0;
+ _boot3 = 0;
+}
+
+
+UNTFS_EXPORT
+NTFS_SA::~NTFS_SA(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for NTFS_SA.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_SA::Initialize(
+ IN OUT PLOG_IO_DP_DRIVE Drive,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine returns an NTFS_SA to a default initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG num_boot_sectors;
+
+ Destroy();
+
+ DebugAssert(Drive);
+ DebugAssert(Message);
+
+ num_boot_sectors = max(1, BYTES_PER_BOOT_SECTOR/Drive->QuerySectorSize());
+
+ if (!_hmem.Initialize() ||
+ !SUPERAREA::Initialize(&_hmem, Drive, num_boot_sectors, Message)) {
+
+ return FALSE;
+ }
+
+ _boot_sector = (PPACKED_BOOT_SECTOR) SECRUN::GetBuf();
+
+ return TRUE;
+}
+
+#if defined( _SETUP_LOADER_ )
+
+BOOLEAN
+NTFS_SA::Create(
+ IN PCNUMBER_SET BadSectors,
+ IN OUT PMESSAGE Message,
+ IN PCWSTRING Label,
+ IN ULONG ClusterSize,
+ IN ULONG VirtualSectors
+
+ )
+{
+ // Dummy implementation for Setup-Loader; the real thing
+ // is in format.cxx.
+
+ return FALSE;
+}
+
+BOOLEAN
+NTFS_SA::Create(
+ IN PCNUMBER_SET BadSectors,
+ IN ULONG ClusterFactor,
+ IN ULONG FrsSize,
+ IN ULONG ClustersPerIndexBuffer,
+ IN ULONG InitialLogFileSize,
+ IN OUT PMESSAGE Message,
+ IN PCWSTRING Label
+ )
+{
+ // Dummy implementation for Setup-Loader; the real thing
+ // is in format.cxx.
+
+ return FALSE;
+}
+
+
+#endif // _SETUP_LOADER_
+
+#if defined( _AUTOCHECK_ ) || defined( _SETUP_LOADER_ )
+
+BOOLEAN
+NTFS_SA::RecoverFile(
+ IN PCWSTRING FullPathFileName,
+ IN OUT PMESSAGE Message
+ )
+{
+ // Dummy implementation for AUTOCHECK and Setup-Loader
+
+ return FALSE;
+}
+
+#else // _AUTOCHECK_ and _SETUP_LOADER_ are NOT defined
+
+
+BOOLEAN
+NTFS_SA::RecoverFile(
+ IN PCWSTRING FullPathFileName,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine recovers a file on the disk.
+
+Arguments:
+
+ FullPathFileName - Supplies the file name of the file to recover.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_ATTRIBUTE BitmapAttribute;
+ NTFS_MFT_FILE MftFile;
+ NTFS_BITMAP_FILE BitmapFile;
+ NTFS_BAD_CLUSTER_FILE BadClusterFile;
+ NTFS_BITMAP VolumeBitmap;
+ NTFS_FILE_RECORD_SEGMENT FrsToRecover;
+ NTFS_UPCASE_FILE UpcaseFile;
+ NTFS_ATTRIBUTE UpcaseAttribute;
+ NTFS_UPCASE_TABLE UpcaseTable;
+ BIG_INT BytesRecovered, TotalBytes;
+ BOOLEAN Error = FALSE;
+ ULONG BadClusters = 0;
+ NUMBER_SET BadClusterList;
+ UCHAR Major, Minor;
+ BOOLEAN CorruptVolume;
+
+
+ // Lock the drive.
+
+ if (!_drive->Lock()) {
+
+ Message->Set(MSG_CANT_LOCK_THE_DRIVE);
+ Message->Display("");
+ return FALSE;
+ }
+
+ // Determine the volume version information.
+ //
+ QueryVolumeFlags(&CorruptVolume, &Major, &Minor);
+
+ if( CorruptVolume ) {
+
+ Message->Set( MSG_NTFS_RECOV_CORRUPT_VOLUME );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( (Major != 1) || (Minor > 2) ) {
+
+ Message->Set( MSG_NTFS_RECOV_WRONG_VERSION );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ SetVersionNumber( Major, Minor );
+
+
+ // Initialize and read the MFT, the Bitmap File, the Bitmap, and the
+ // Bad Cluster File.
+ //
+ if( !VolumeBitmap.Initialize( QueryVolumeSectors()/
+ ((ULONG) QueryClusterFactor()),
+ FALSE, _drive, QueryClusterFactor()) ||
+ !MftFile.Initialize( _drive,
+ QueryMftStartingLcn(),
+ QueryClusterFactor(),
+ QueryFrsSize(),
+ QueryVolumeSectors(),
+ &VolumeBitmap,
+ NULL ) ) {
+
+ Message->Set( MSG_INSUFFICIENT_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !MftFile.Read() ) {
+
+ DebugPrint( "NTFS_SA::RecoverFile: Cannot read MFT.\n" );
+
+ Message->Set( MSG_NTFS_RECOV_CORRUPT_VOLUME );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ // Get the upcase table.
+ //
+ if( !UpcaseFile.Initialize( MftFile.GetMasterFileTable() ) ||
+ !UpcaseFile.Read() ||
+ !UpcaseFile.QueryAttribute( &UpcaseAttribute, &Error, $DATA ) ||
+ !UpcaseTable.Initialize( &UpcaseAttribute ) ) {
+
+ DebugPrint( "UNTFS RecoverFile:Can't get the upcase table.\n" );
+
+ Message->Set( MSG_NTFS_RECOV_CORRUPT_VOLUME );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ MftFile.SetUpcaseTable( &UpcaseTable );
+ MftFile.GetMasterFileTable()->SetUpcaseTable( &UpcaseTable );
+
+
+ // Initialize the Bitmap file and the Bad Cluster file, and
+ // read the volume bitmap.
+ //
+ if( !BitmapFile.Initialize( MftFile.GetMasterFileTable() ) ||
+ !BadClusterFile.Initialize( MftFile.GetMasterFileTable() ) ) {
+
+ Message->Set( MSG_INSUFFICIENT_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ if( !BitmapFile.Read() ||
+ !BitmapFile.QueryAttribute( &BitmapAttribute, &Error, $DATA ) ||
+ !VolumeBitmap.Read( &BitmapAttribute ) ||
+ !BadClusterFile.Read () ) {
+
+ Message->Set( MSG_NTFS_RECOV_CORRUPT_VOLUME );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+
+ // Find the File Record Segment.
+
+ if( !QueryFrsFromPath( FullPathFileName,
+ MftFile.GetMasterFileTable(),
+ &VolumeBitmap,
+ &FrsToRecover,
+ &Error ) ) {
+
+ if( !Error ) {
+
+ Message->Set( MSG_RECOV_FILE_NOT_FOUND );
+ Message->Display( "" );
+ return FALSE;
+
+ } else {
+
+ Message->Set( MSG_INSUFFICIENT_MEMORY );
+ Message->Display( "" );
+ return FALSE;
+ }
+ }
+
+
+ // If the File Record Segment is a system file, don't recover it.
+
+ if( FrsToRecover.QueryFileNumber() < FIRST_USER_FILE_NUMBER ) {
+
+ Message->Set( MSG_NTFS_RECOV_SYSTEM_FILE );
+ Message->Display( "" );
+ return FALSE;
+ }
+
+ // Recover the File Record Segment.
+
+ if( !BadClusterList.Initialize() ||
+ !FrsToRecover.RecoverFile( &VolumeBitmap,
+ &BadClusterList,
+ &BadClusters,
+ &BytesRecovered,
+ &TotalBytes ) ||
+ !BadClusterFile.Add(&BadClusterList)) {
+
+ Message->Set( MSG_NTFS_RECOV_FAILED );
+ Message->Display( "" );
+
+ return FALSE;
+ }
+
+ // If any bad clusters were found, we need to flush the bad cluster
+ // file and the MFT and write the bitmap. If no bad clusters were
+ // found, then these structures will be unchanged.
+
+ if( BadClusters != 0 ) {
+
+ if( !BadClusterFile.Flush( &VolumeBitmap ) ||
+ !MftFile.Flush() ||
+ !VolumeBitmap.Write( &BitmapAttribute, &VolumeBitmap ) ) {
+
+ Message->Set( MSG_NTFS_RECOV_CANT_WRITE_ELEMENTARY );
+ Message->Display( "" );
+
+ return FALSE;
+ }
+
+ }
+
+ Message->Set( MSG_RECOV_BYTES_RECOVERED );
+ Message->Display( "%d%d",
+ BytesRecovered.GetLowPart(),
+ TotalBytes.GetLowPart() );
+
+ return TRUE;
+}
+
+#endif // _AUTOCHECK_ || _SETUP_LOADER_
+
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_SA::Read(
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine reads the NTFS volume's boot sector from disk.
+ If the read fails then a message will be printed and then
+ we will attempt to find an alternate boot sector, looking
+ first at the end of the volume and then in the middle.
+
+Arguments:
+
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ DebugAssert(Message);
+
+ if (!SECRUN::Read()) {
+
+ Message->Set(MSG_NTFS_UNREADABLE_BOOT_SECTOR);
+ Message->Display();
+
+ _boot2 = _drive->QuerySectors() - 1;
+ Relocate(_boot2);
+
+ if (!SECRUN::Read() ||
+ !IFS_SYSTEM::IsThisNtfs(_drive->QuerySectors(),
+ _drive->QuerySectorSize(),
+ (PVOID)_boot_sector)) {
+
+ _boot2 = _drive->QuerySectors()/2;
+ Relocate(_boot2);
+
+ if (!SECRUN::Read() ||
+ !IFS_SYSTEM::IsThisNtfs(_drive->QuerySectors(),
+ _drive->QuerySectorSize(),
+ (PVOID)_boot_sector)) {
+
+ Message->Set(MSG_NTFS_ALL_BOOT_SECTORS_UNREADABLE);
+ Message->Display();
+
+ _boot2 = 0;
+ Relocate(0);
+ return FALSE;
+ }
+ }
+
+ Relocate(0);
+ }
+
+ UnpackBios(&_bpb, &(_boot_sector->PackedBpb));
+
+ if (QueryVolumeSectors() < _drive->QuerySectors()) {
+ _boot2 = _drive->QuerySectors() - 1;
+ } else {
+ _boot2 = _drive->QuerySectors() / 2;
+ }
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+NTFS_SA::Write(
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine writes both of the NTFS volume's boot sector to disk.
+ If the write fails on either of the boot sectors then a message
+ will be printed.
+
+Arguments:
+
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ DebugAssert(Message);
+
+ PackBios(&_bpb, &(_boot_sector->PackedBpb));
+
+ if (SECRUN::Write()) {
+
+ Relocate(_boot2);
+
+ if (!SECRUN::Write()) {
+
+ Message->Set(MSG_NTFS_SECOND_BOOT_SECTOR_UNWRITEABLE);
+ Message->Display();
+ return FALSE;
+ }
+
+ Relocate(0);
+
+ } else {
+
+ Message->Set(MSG_NTFS_FIRST_BOOT_SECTOR_UNWRITEABLE);
+ Message->Display();
+
+ Relocate(_boot2);
+
+ if (!SECRUN::Write()) {
+ Message->Set(MSG_NTFS_ALL_BOOT_SECTORS_UNWRITEABLE);
+ Message->Display();
+ Relocate(0);
+ return FALSE;
+ }
+
+ Relocate(0);
+ }
+
+ return TRUE;
+}
+
+#if !defined( _AUTOCHECK_ ) && !defined( _SETUP_LOADER_ )
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_SA::QueryFrsFromPath(
+ IN PCWSTRING FullPathFileName,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ OUT PNTFS_FILE_RECORD_SEGMENT TargetFrs,
+ OUT PBOOLEAN InternalError
+ )
+/*++
+
+Routine Description:
+
+ This method finds the file segment for a specified path.
+
+Arguments:
+
+ FullPathFileName -- Supplies the full path to the file
+ Mft -- Supplies the volume's Master File Table
+ VolumeBitmap -- Supplies the volume bitmap
+ TargetFrs -- Supplies a File Record Segment which will be
+ initialized to the desired File Record Segment
+ InternalError -- Receives TRUE if the method fails because of
+ a resource error.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+ If the method succeeds, TargetFrs is initialized to the desired
+ File Record Segment.
+
+ If the method fails because of a resource error (ie. because it cannot
+ initialize an object), *InternalError is set to TRUE; if it fails
+ because it can't find the file, then *InternalError is set to FALSE.
+
+--*/
+{
+ PATH FullPath;
+ NTFS_INDEX_TREE IndexTree;
+ DSTRING IndexName;
+ PWSTRING CurrentComponent;
+ PARRAY PathComponents = NULL;
+ PARRAY_ITERATOR Iterator = NULL;
+ PFILE_NAME SearchName;
+ MFT_SEGMENT_REFERENCE FileReference;
+ VCN FileNumber;
+ ULONG MaximumBytesInName;
+
+
+ if( !IndexName.Initialize( FileNameIndexNameData ) ||
+ !FullPath.Initialize( FullPathFileName ) ||
+ (PathComponents = FullPath.QueryComponentArray()) == NULL ||
+ (Iterator =
+ (PARRAY_ITERATOR)PathComponents->QueryIterator()) == NULL ||
+ !TargetFrs->Initialize( ROOT_FILE_NAME_INDEX_NUMBER, Mft ) ||
+ !TargetFrs->Read() ||
+ (MaximumBytesInName = TargetFrs->QuerySize()) == 0 ||
+ (SearchName = (PFILE_NAME)
+ MALLOC(MaximumBytesInName+1+sizeof(FILE_NAME)))
+ == NULL ) {
+
+ DebugPrint( "QueryFrsFromPath--cannot initialize helpers\n" );
+
+ if( SearchName != NULL ) {
+
+ FREE( SearchName );
+ }
+
+ DELETE( PathComponents );
+ DELETE( Iterator );
+
+ *InternalError = TRUE;
+ return FALSE;
+ }
+
+ while( (CurrentComponent = (PWSTRING)Iterator->GetNext()) != NULL ) {
+
+
+ // Set up a FILE_NAME structure to be the search key. We need
+ // to set the length field in the header and copy the name.
+ // Note that this method only deals with NTFS names (not DOS
+ // names), so we also set the file name flag to FILE_NAME_NTFS.
+
+ SearchName->FileNameLength = (UCHAR)CurrentComponent->QueryChCount();
+ SearchName->Flags = FILE_NAME_NTFS;
+
+ if( !CurrentComponent->QueryWSTR( 0,
+ TO_END,
+ NtfsFileNameGetName( SearchName ),
+ MaximumBytesInName ) ||
+ !IndexTree.Initialize( _drive,
+ QueryClusterFactor(),
+ VolumeBitmap,
+ TargetFrs->GetUpcaseTable(),
+ TargetFrs->
+ QueryMaximumAttributeRecordSize(),
+ TargetFrs,
+ &IndexName ) ) {
+
+ DebugPrint( "QueryFrsFromPath--Cannot initialize index tree.\n" );
+
+ if( SearchName != NULL ) {
+
+ FREE( SearchName );
+ }
+
+ DELETE( PathComponents );
+ DELETE( Iterator );
+
+ *InternalError = TRUE;
+ return FALSE;
+ }
+
+ // Find the current component in the tree:
+
+ if( !IndexTree.QueryFileReference( NtfsFileNameGetLength( SearchName ),
+ SearchName,
+ 0,
+ &FileReference,
+ InternalError ) ) {
+
+ if( SearchName != NULL ) {
+
+ FREE( SearchName );
+ }
+
+ DELETE( PathComponents );
+ DELETE( Iterator );
+
+ return FALSE;
+ }
+
+ // Initialize and read a File Record Segment based on that
+ // File Reference. Not only must the FRS be readable, but
+ // its sequence number must match the sequence number in the
+ // File Reference.
+
+ FileNumber.Set( FileReference.LowPart,
+ (LONG) FileReference.HighPart );
+
+ if( !TargetFrs->Initialize( FileNumber, Mft ) ||
+ !TargetFrs->Read() ||
+ !(FileReference == TargetFrs->QuerySegmentReference()) ) {
+
+ // Either we were unable to initialize and read this FRS,
+ // or its segment reference didn't match (ie. the sequence
+ // number is wrong.
+
+ if( SearchName != NULL ) {
+
+ FREE( SearchName );
+ }
+
+ DELETE( PathComponents );
+ DELETE( Iterator );
+
+ *InternalError = TRUE;
+ return FALSE;
+ }
+ }
+
+ if ( SearchName != NULL ) {
+
+ FREE( SearchName );
+ }
+
+ // If we got this far, no errors have been encountered, we've
+ // processed the entire path, and TargetFrs has been initialized
+ // to the File Record Segment we want.
+
+ return TRUE;
+}
+
+#endif // _AUTOCHECK_ || _SETUP_LOADER_
+
+
+VOID
+NTFS_SA::SetVersionNumber(
+ IN UCHAR Major,
+ IN UCHAR Minor
+ )
+{
+ _MajorVersion = Major;
+ _MinorVersion = Minor;
+}
+
+
+VOID
+NTFS_SA::QueryVersionNumber(
+ OUT PUCHAR Major,
+ OUT PUCHAR Minor
+ )
+{
+ *Major = _MajorVersion;
+ *Minor = _MinorVersion;
+}
+
+
+UNTFS_EXPORT
+USHORT
+NTFS_SA::QueryVolumeFlags(
+ OUT PBOOLEAN CorruptVolume,
+ OUT PUCHAR MajorVersion,
+ OUT PUCHAR MinorVersion
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine fetches the volume flags.
+
+Arguments:
+
+ CorruptVolume - Returns whether or not a volume corruption was
+ detected.
+ MajorVersion - Returns the major file system version number.
+ MinorVersion - Returns the minor file system version number.
+
+Return Value:
+
+ The flags describing this volume's state.
+
+--*/
+{
+ NTFS_FRS_STRUCTURE frs;
+ HMEM hmem;
+ LCN cluster_number, alternate;
+ ULONG cluster_offset, alternate_offset;
+ PVOID p;
+ NTFS_ATTRIBUTE_RECORD attr_rec;
+ PVOLUME_INFORMATION vol_info;
+
+ if (CorruptVolume) {
+ *CorruptVolume = FALSE;
+ }
+
+ if (MajorVersion) {
+ *MajorVersion = 0;
+ }
+
+ if (MinorVersion) {
+ *MinorVersion = 0;
+ }
+
+ ULONG cluster_size = QueryClusterFactor() * _drive->QuerySectorSize();
+
+ cluster_number = (VOLUME_DASD_NUMBER * QueryFrsSize())/ cluster_size +
+ QueryMftStartingLcn();
+
+ cluster_offset = (QueryMftStartingLcn()*cluster_size +
+ VOLUME_DASD_NUMBER * QueryFrsSize() - cluster_number * cluster_size).GetLowPart();
+
+ DebugAssert(cluster_offset < cluster_size);
+
+ alternate = (VOLUME_DASD_NUMBER * QueryFrsSize())/ cluster_size +
+ QueryMft2StartingLcn();
+
+ alternate_offset = (QueryMft2StartingLcn()*cluster_size +
+ VOLUME_DASD_NUMBER * QueryFrsSize() - cluster_number * cluster_size).GetLowPart();
+
+ for (;;) {
+
+ if (!hmem.Initialize() ||
+ !frs.Initialize(&hmem, _drive, cluster_number,
+ QueryClusterFactor(),
+ QueryVolumeSectors(),
+ QueryFrsSize(),
+ NULL,
+ cluster_offset) ||
+ !frs.Read()) {
+
+ if (cluster_number == alternate) {
+ break;
+ } else {
+ cluster_number = alternate;
+ cluster_offset = alternate_offset;
+ continue;
+ }
+ }
+
+ p = NULL;
+ while (p = frs.GetNextAttributeRecord(p)) {
+
+ if (!attr_rec.Initialize(p)) {
+ // the attribute record containing the volume flags
+ // is not available--this means that the volume is
+ // dirty.
+ //
+ return VOLUME_DIRTY;
+ }
+
+ if (attr_rec.QueryTypeCode() == $VOLUME_INFORMATION &&
+ attr_rec.QueryNameLength() == 0 &&
+ attr_rec.QueryResidentValueLength() >= sizeof(VOLUME_INFORMATION) &&
+ (vol_info = (PVOLUME_INFORMATION) attr_rec.GetResidentValue())) {
+
+ if (MajorVersion) {
+ *MajorVersion = vol_info->MajorVersion;
+ }
+
+ if (MinorVersion) {
+ *MinorVersion = vol_info->MinorVersion;
+ }
+
+ return (vol_info->VolumeFlags);
+ }
+ }
+
+ // If the desired attribute wasn't found in the first
+ // volume dasd file then check the mirror.
+
+ if (cluster_number == alternate) {
+ break;
+ } else {
+ cluster_number = alternate;
+ cluster_offset = alternate_offset;
+ }
+ }
+
+ if (CorruptVolume) {
+ *CorruptVolume = TRUE;
+ }
+
+ return VOLUME_DIRTY;
+}
+
+
+BOOLEAN
+NTFS_SA::SetVolumeClean(
+ IN USHORT FlagsToClear,
+ IN OUT PNTFS_LOG_FILE LogFile,
+ IN BOOLEAN WriteSecondLogFilePage,
+ IN LSN LargestVolumeLsn,
+ OUT PBOOLEAN CorruptVolume
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the volume clean.
+
+Arguments:
+
+ FlagsToClear - Supplies the volume flags to clear.
+ LogFile - Supplies a valid log file. May be NULL,
+ in which case the log file will not be
+ modified.
+ WriteSecondLogFilePage - Supplies whether or not to write the second
+ log file page. Ignored if LogFile is NULL.
+ LargestVolumeLsn - This supplies the largest LSN on the volume.
+ This parameter will be used if and
+ only if the previous parameter is TRUE.
+ CorruptVolume - Returns whether or not the volume is corrupt.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_FRS_STRUCTURE frs;
+ HMEM hmem;
+ LCN volume_file_lcn;
+ ULONG volume_file_offset;
+ PVOID p;
+ NTFS_ATTRIBUTE_RECORD attr_rec;
+ PVOLUME_INFORMATION vol_info;
+ ULONG cluster_size;
+
+ cluster_size = QueryClusterFactor() * _drive->QuerySectorSize();
+
+ if (CorruptVolume) {
+ *CorruptVolume = FALSE;
+ }
+
+ // Compute the cluster that holds the start of the volume file frs and
+ // the offset into that cluster (which will be zero unless the frs size
+ // is less than the cluster size.)
+ //
+
+ volume_file_lcn = QueryMftStartingLcn();
+ volume_file_offset = VOLUME_DASD_NUMBER * QueryFrsSize();
+
+ if (!hmem.Initialize() ||
+ !frs.Initialize(&hmem, _drive, volume_file_lcn,
+ QueryClusterFactor(),
+ QueryVolumeSectors(),
+ QueryFrsSize(),
+ NULL,
+ volume_file_offset) ||
+ !frs.Read()) {
+
+ return FALSE;
+ }
+
+ p = NULL;
+ while (p = frs.GetNextAttributeRecord(p)) {
+
+ if (!attr_rec.Initialize(p)) {
+ return FALSE;
+ }
+
+ if (attr_rec.QueryTypeCode() == $VOLUME_INFORMATION &&
+ attr_rec.QueryNameLength() == 0 &&
+ attr_rec.QueryResidentValueLength() >= sizeof(VOLUME_INFORMATION) &&
+ (vol_info = (PVOLUME_INFORMATION) attr_rec.GetResidentValue())) {
+
+ break;
+ }
+ }
+
+ if (!p) {
+ if (CorruptVolume) {
+ *CorruptVolume = TRUE;
+ }
+ return FALSE;
+ }
+
+ vol_info->VolumeFlags &= ~(FlagsToClear);
+ if (!frs.Write()) {
+ return FALSE;
+ }
+
+ if( LogFile ) {
+
+ return LogFile->MarkVolumeChecked(WriteSecondLogFilePage,
+ LargestVolumeLsn);
+ } else {
+
+ return TRUE;
+ }
+}
+
+
+BOOLEAN
+NTFS_SA::PostReadMultiSectorFixup(
+ IN OUT PVOID MultiSectorBuffer,
+ IN ULONG BufferSize
+ )
+/*++
+
+Routine Description:
+
+ This routine first verifies that the first element of the
+ update sequence array is written at the end of every
+ SEQUENCE_NUMBER_STRIDE bytes. If not, then this routine
+ returns FALSE.
+
+ Otherwise this routine swaps the following elements in the
+ update sequence array into the appropriate positions in the
+ multi sector buffer.
+
+ This routine will also check to make sure that the update
+ sequence array is valid and that the BufferSize is appropriate
+ for this size of update sequence array. Otherwise, this
+ routine will not update the array sequence and return TRUE.
+
+Arguments:
+
+ MultiSectorBuffer - Supplies the buffer to be updated.
+ BufferSize - Supplies the number of bytes in this
+ buffer.
+
+Return Value:
+
+ TRUE - This function always returns TRUE but write 'BAAD'
+ in the header signature if the last write to this
+ block was only partially completed.
+
+--*/
+{
+ PUNTFS_MULTI_SECTOR_HEADER pheader;
+ USHORT i, size, offset;
+ PUPDATE_SEQUENCE_NUMBER parray, pnumber;
+
+ pheader = (PUNTFS_MULTI_SECTOR_HEADER) MultiSectorBuffer;
+ size = pheader->UpdateSequenceArraySize;
+ offset = pheader->UpdateSequenceArrayOffset;
+
+ if (BufferSize%SEQUENCE_NUMBER_STRIDE ||
+ offset%sizeof(UPDATE_SEQUENCE_NUMBER) ||
+ offset + size*sizeof(UPDATE_SEQUENCE_NUMBER) > BufferSize ||
+ BufferSize/SEQUENCE_NUMBER_STRIDE + 1 != size) {
+
+ return TRUE;
+ }
+
+ parray = (PUPDATE_SEQUENCE_NUMBER) ((PCHAR) pheader + offset);
+
+ for (i = 1; i < size; i++) {
+
+ pnumber = (PUPDATE_SEQUENCE_NUMBER)
+ ((PCHAR) pheader + (i*SEQUENCE_NUMBER_STRIDE -
+ sizeof(UPDATE_SEQUENCE_NUMBER)));
+
+ if (*pnumber != parray[0]) {
+ pheader->Signature[0] = 'B';
+ pheader->Signature[1] = 'A';
+ pheader->Signature[2] = 'A';
+ pheader->Signature[3] = 'D';
+ return TRUE;
+ }
+
+ *pnumber = parray[i];
+ }
+
+ return TRUE;
+}
+
+
+VOID
+NTFS_SA::PreWriteMultiSectorFixup(
+ IN OUT PVOID MultiSectorBuffer,
+ IN ULONG BufferSize
+ )
+/*++
+
+Routine Description:
+
+ This routine first checks to see if the update sequence
+ array is valid. If it is then this routine increments the
+ first element of the update sequence array. It then
+ writes the value of the first element into the buffer at
+ the end of every SEQUENCE_NUMBER_STRIDE bytes while
+ saving the old values of those locations in the following
+ elements of the update sequence arrary.
+
+Arguments:
+
+ MultiSectorBuffer - Supplies the buffer to be updated.
+ BufferSize - Supplies the number of bytes in this
+ buffer.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PUNTFS_MULTI_SECTOR_HEADER pheader;
+ USHORT i, size, offset;
+ PUPDATE_SEQUENCE_NUMBER parray, pnumber;
+
+ pheader = (PUNTFS_MULTI_SECTOR_HEADER) MultiSectorBuffer;
+ size = pheader->UpdateSequenceArraySize;
+ offset = pheader->UpdateSequenceArrayOffset;
+
+ if (BufferSize%SEQUENCE_NUMBER_STRIDE ||
+ offset%sizeof(UPDATE_SEQUENCE_NUMBER) ||
+ offset + size*sizeof(UPDATE_SEQUENCE_NUMBER) > BufferSize ||
+ BufferSize/SEQUENCE_NUMBER_STRIDE + 1 != size) {
+
+ return;
+ }
+
+ parray = (PUPDATE_SEQUENCE_NUMBER) ((PCHAR) pheader + offset);
+
+
+ // Don't allow 0 or all F's to be the update character.
+
+ do {
+ parray[0]++;
+ } while (parray[0] == 0 || parray[0] == (UPDATE_SEQUENCE_NUMBER) -1);
+
+
+ for (i = 1; i < size; i++) {
+
+ pnumber = (PUPDATE_SEQUENCE_NUMBER)
+ ((PCHAR) pheader + (i*SEQUENCE_NUMBER_STRIDE -
+ sizeof(UPDATE_SEQUENCE_NUMBER)));
+
+ parray[i] = *pnumber;
+ *pnumber = parray[0];
+ }
+}
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_SA::IsDosName(
+ IN PCFILE_NAME FileName
+ )
+/*++
+
+Routine Description:
+
+ This routine computes whether or not the given file name would
+ be appropriate under DOS's 8.3 naming convention.
+
+Arguments:
+
+ FileName - Supplies the file name to check.
+
+Return Value:
+
+ FALSE - The supplied name is not a DOS file name.
+ TRUE - The supplied name is a valid DOS file name.
+
+--*/
+{
+ ULONG i, n, name_length, ext_length;
+ BOOLEAN dot_yet;
+ PCWCHAR p;
+
+ n = FileName->FileNameLength;
+ p = FileName->FileName;
+ name_length = n;
+ ext_length = 0;
+
+ if (n > 12) {
+ return FALSE;
+ }
+
+ dot_yet = FALSE;
+ for (i = 0; i < n; i++) {
+
+ if (p[i] < 32) {
+ return FALSE;
+ }
+
+ switch (p[i]) {
+ case '*':
+ case '?':
+ case '/':
+ case '\\':
+ case '|':
+ case ',':
+ case ';':
+ case ':':
+ case '+':
+ case '=':
+ case '<':
+ case '>':
+ case '[':
+ case ']':
+ case '"':
+ return FALSE;
+
+ case '.':
+ if (dot_yet) {
+ return FALSE;
+ }
+ dot_yet = TRUE;
+ name_length = i;
+ ext_length = n - i - 1;
+ break;
+ }
+ }
+
+ if (!name_length) {
+ return dot_yet && n == 1;
+ }
+
+ if (name_length > 8 ||
+ p[name_length - 1] == ' ') {
+
+ return FALSE;
+ }
+
+ if (!ext_length) {
+ return !dot_yet;
+ }
+
+ if (ext_length > 3 ||
+ p[name_length + 1 + ext_length - 1] == ' ') {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_SA::IsValidLabel(
+ IN PCWSTRING Label
+ )
+/*++
+
+Routine Description:
+
+ This method determines whether a specified string is a
+ valid NTFS volume label.
+
+Arguments:
+
+ Label -- Supplies the string to check.
+
+Return Value:
+
+ TRUE if the string is a valid NTFS label.
+
+--*/
+{
+ CHNUM StringLength, i;
+
+ StringLength = Label->QueryChCount();
+
+ for( i = 0; i < StringLength; i++ ) {
+
+ if (Label->QueryChAt(i) < 32) {
+ return FALSE;
+ }
+
+ switch (Label->QueryChAt(i)) {
+ case '*':
+ case '?':
+ case '/':
+ case '\\':
+ case '|':
+ case '<':
+ case '>':
+ case '"':
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+ULONG
+NTFS_SA::QueryDefaultClusterFactor(
+ IN PCDP_DRIVE Drive
+ )
+/*++
+
+Routine Description:
+
+ This method returns the default number of sectors per cluster
+ for a given drive.
+
+Arguments:
+
+ Drive -- Supplies the drive under consideration.
+
+Return Value:
+
+ The appropriate default cluster factor.
+
+--*/
+{
+ // Hold off on this analysis until testing says ok.
+
+ BIG_INT cbDiskSize;
+ ULONG cbClusterSize, csecClusterSize;
+
+ cbDiskSize = Drive->QuerySectors()*Drive->QuerySectorSize();
+
+ if (cbDiskSize > (ULONG) 2*1024*1024*1024) { // > 2 Gig
+ cbClusterSize = 4096;
+ } else if (cbDiskSize > 1024*1024*1024) { // > 1 Gig
+ cbClusterSize = 2048;
+ } else if (cbDiskSize > 512*1024*1024) { // > 512 Meg
+ cbClusterSize = 1024;
+ } else {
+ cbClusterSize = 512;
+ }
+
+ csecClusterSize = cbClusterSize/Drive->QuerySectorSize();
+ if (!csecClusterSize) {
+ csecClusterSize = 1;
+ }
+
+ return csecClusterSize;
+}
+
+UNTFS_EXPORT
+ULONG
+NTFS_SA::QueryDefaultClustersPerIndexBuffer(
+ IN PCDP_DRIVE Drive,
+ IN ULONG ClusterFactor
+ )
+/*++
+
+Routine Description:
+
+ This method computes the default number of clusters per
+ NTFS index allocation buffer.
+
+Arguments:
+
+ Drive -- supplies the drive under consideration.
+ ClusterFactor -- Supplies the cluster factor for the drive.
+
+Return Value:
+
+ The default number of clusters per NTFS index allocation
+ buffer.
+
+--*/
+{
+ ULONG ClusterSize, cbIndexBufferSize;
+
+ if (ClusterFactor) {
+
+ ClusterSize = Drive->QuerySectorSize() * ClusterFactor;
+
+ if (ClusterSize > SMALL_INDEX_BUFFER_SIZE) {
+
+ return 0;
+ }
+
+ cbIndexBufferSize = max(ClusterSize, 2048);
+ return cbIndexBufferSize/ClusterSize;
+
+ } else {
+
+ ClusterSize = Drive->QuerySectorSize();
+
+ if (ClusterSize > SMALL_INDEX_BUFFER_SIZE) {
+
+ return 0;
+ }
+ return( ( 2048 + ClusterSize - 1 ) / ClusterSize );
+ }
+}
+
+BOOLEAN
+NTFS_SA::LogFileMayNeedResize(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine
+
+Arguments:
+
+
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_FRS_STRUCTURE frs;
+ HMEM hmem;
+ PVOID p;
+ NTFS_ATTRIBUTE_RECORD attr_rec;
+ LCN log_file_lcn;
+ ULONG log_file_offset;
+ BIG_INT log_file_size;
+ ULONG cluster_size;
+
+ cluster_size = QueryClusterFactor() * _drive->QuerySectorSize();
+
+ log_file_lcn = QueryMftStartingLcn();
+ log_file_offset = LOG_FILE_NUMBER * QueryFrsSize();
+
+ if (!hmem.Initialize() ||
+ !frs.Initialize(&hmem, _drive,
+ log_file_lcn,
+ QueryClusterFactor(),
+ QueryVolumeSectors(),
+ QueryFrsSize(),
+ NULL,
+ log_file_offset) ||
+ !frs.Read()) {
+
+ return TRUE;
+ }
+
+ p = NULL;
+ while (NULL != (p = frs.GetNextAttributeRecord(p))) {
+
+ if (!attr_rec.Initialize(p)) {
+ return TRUE;
+ }
+
+ if ($DATA == attr_rec.QueryTypeCode()) {
+
+ ULONG max_size, min_size;
+
+ attr_rec.QueryValueLength(&log_file_size);
+
+ max_size = NTFS_LOG_FILE::QueryMaximumSize(_drive, QueryVolumeSectors());
+ min_size = NTFS_LOG_FILE::QueryMinimumSize(_drive, QueryVolumeSectors());
+
+ if (log_file_size < min_size ||
+ log_file_size > max_size) {
+
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_SA::SetVolumeDirty(
+ IN USHORT FlagsToSet,
+ OUT PBOOLEAN CorruptVolume
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the volume dirty.
+
+Arguments:
+
+ FlagsToSet - Supplies the volume flags to set.
+ CorruptVolume - Returns whether or not the volume is corrupt.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_FRS_STRUCTURE frs;
+ HMEM hmem;
+ LCN start_of_volume_file;
+ PVOID p;
+ NTFS_ATTRIBUTE_RECORD attr_rec;
+ PVOLUME_INFORMATION vol_info;
+
+ if (CorruptVolume) {
+ *CorruptVolume = FALSE;
+ }
+
+ ULONG cluster_size = QueryClusterFactor() * _drive->QuerySectorSize();
+
+ start_of_volume_file = QueryMftStartingLcn() +
+ (VOLUME_DASD_NUMBER*QueryFrsSize() + (cluster_size - 1))/cluster_size;
+
+ if (!hmem.Initialize() ||
+ !frs.Initialize(&hmem, _drive, start_of_volume_file,
+ QueryClusterFactor(),
+ QueryVolumeSectors(),
+ QueryFrsSize(),
+ NULL) ||
+ !frs.Read()) {
+
+ return FALSE;
+ }
+
+ p = NULL;
+ while (p = frs.GetNextAttributeRecord(p)) {
+
+ if (!attr_rec.Initialize(p)) {
+ return FALSE;
+ }
+
+ if (attr_rec.QueryTypeCode() == $VOLUME_INFORMATION &&
+ attr_rec.QueryNameLength() == 0 &&
+ attr_rec.QueryResidentValueLength() >= sizeof(VOLUME_INFORMATION) &&
+ (vol_info = (PVOLUME_INFORMATION) attr_rec.GetResidentValue())) {
+
+ break;
+ }
+ }
+
+ if (!p) {
+ if (CorruptVolume) {
+ *CorruptVolume = TRUE;
+ }
+ return FALSE;
+ }
+
+ vol_info->VolumeFlags |= FlagsToSet;
+ if (!frs.Write()) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_SA::Read(
+ )
+/*++
+
+Routine Description:
+
+ This routine simply calls the other read with the default message
+ object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ MESSAGE msg;
+
+ return Read(&msg);
+}
+
+UNTFS_EXPORT
+UCHAR
+NTFS_SA::QueryClusterFactor(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine returns the number of sectors per cluster.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The number of sectors per cluster.
+
+--*/
+{
+ return _bpb.SectorsPerCluster;
+}
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_SA::TakeCensus(
+ IN PNTFS_MASTER_FILE_TABLE Mft,
+ IN ULONG ResidentFileSizeThreshhold,
+ OUT PNTFS_CENSUS_INFO Census
+ )
+/*++
+
+Routine Description:
+
+ This routine examines the MFT and makes a census report on the
+ volume. This is used by convert to determine whether there will
+ be enough space on the volume to convert from NTFS to the new
+ filesystem.
+
+Arguments:
+
+ ResidentFileSizeThreshhold - Used to determine whether a given resident
+ file should be placed in the "small" or "large" resident file
+ category.
+
+ Census - Returns the census information.
+
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ BOOLEAN error;
+ NTFS_ATTRIBUTE attrib;
+ NTFS_FILE_RECORD_SEGMENT frs;
+ ULONG i, j;
+ ULONG num_frs;
+ ULONG length;
+
+ memset(Census, 0, sizeof(*Census));
+
+ Census->NumFiles;
+ Census->BytesLgResidentFiles;
+ Census->BytesIndices;
+ Census->BytesExternalExtentLists;
+ Census->BytesFileNames;
+
+ num_frs = Mft->GetDataAttribute()->QueryValueLength().GetLowPart() / Mft->QueryFrsSize();
+
+ for (i = 0; i < num_frs; i += 1) {
+
+ if (i < FIRST_USER_FILE_NUMBER && i != ROOT_FILE_NAME_INDEX_NUMBER) {
+ continue;
+ }
+
+ if (!frs.Initialize(i, Mft)) {
+ return FALSE;
+ }
+
+ if (!frs.Read()) {
+ return FALSE;
+ }
+ if (!frs.IsInUse() || !frs.IsBase()) {
+ continue;
+ }
+
+ Census->NumFiles += 1;
+
+ //
+ // Examine all the data attributes and see which are Large and
+ // resident.
+ //
+
+ for (j = 0; frs.QueryAttributeByOrdinal(&attrib, &error, $DATA, j); ++j) {
+
+ length = attrib.QueryValueLength().GetLowPart();
+
+ if (attrib.IsResident() && length > ResidentFileSizeThreshhold) {
+ Census->BytesLgResidentFiles += length;
+ }
+ }
+
+ //
+ // If there's an index present, add in its size. (We assume there's
+ // no more than one.
+ //
+
+ if (frs.IsIndexPresent()) {
+
+ if (frs.QueryAttributeByOrdinal(&attrib, &error,
+ $INDEX_ALLOCATION, 0)) {
+
+ length = attrib.QueryValueLength().GetLowPart();
+ Census->BytesIndices += length;
+ }
+ }
+
+ //
+ // Query all the file names and add in the space they occupy.
+ //
+
+ for (j = 0; frs.QueryAttributeByOrdinal(&attrib, &error,
+ $FILE_NAME, j); ++j) {
+
+ length = attrib.QueryValueLength().GetLowPart();
+
+ Census->BytesFileNames += length;
+ }
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/untfs/src/ntfsvol.cxx b/private/utils/untfs/src/ntfsvol.cxx
new file mode 100644
index 000000000..60f7c78af
--- /dev/null
+++ b/private/utils/untfs/src/ntfsvol.cxx
@@ -0,0 +1,527 @@
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "ntfsvol.hxx"
+
+#include "message.hxx"
+#include "rtmsg.h"
+#include "wstring.hxx"
+
+
+DEFINE_CONSTRUCTOR( NTFS_VOL, VOL_LIODPDRV );
+
+BOOLEAN
+VerifyExtendedSpace(
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN BIG_INT StartingCluster,
+ IN BIG_INT NumberClusters,
+ IN OUT PNUMBER_SET BadClusters,
+ IN OUT PMESSAGE Message
+ );
+
+VOID
+NTFS_VOL::Construct (
+ )
+
+/*++
+
+Routine Description:
+
+ Constructor for NTFS_VOL.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ // unreferenced parameters
+ (void)(this);
+}
+
+
+VOID
+NTFS_VOL::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This routine returns a NTFS_VOL object to its initial state.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ // unreferenced parameters
+ (void)(this);
+}
+
+
+NTFS_VOL::~NTFS_VOL(
+ )
+/*++
+
+Routine Description:
+
+ Destructor for NTFS_VOL.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+BOOLEAN
+NTFS_VOL::Initialize(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN ExclusiveWrite,
+ IN BOOLEAN FormatMedia,
+ IN MEDIA_TYPE MediaType
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes a NTFS_VOL object.
+
+Arguments:
+
+ NtDriveName - Supplies the drive path for the volume.
+ Message - Supplies an outlet for messages.
+ ExclusiveWrite - Supplies whether or not the drive should be
+ opened for exclusive write.
+ FormatMedia - Supplies whether or not to format the media.
+ MediaType - Supplies the type of media to format to.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ MESSAGE msg;
+
+ Destroy();
+
+ if (!VOL_LIODPDRV::Initialize(NtDriveName, &_ntfssa, Message,
+ ExclusiveWrite, FormatMedia, MediaType)) {
+ return FALSE;
+ }
+
+ if (!Message) {
+ Message = &msg;
+ }
+
+ if (!_ntfssa.Initialize(this, Message)) {
+ return FALSE;
+ }
+
+ if (!FormatMedia && !_ntfssa.Read(Message)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+PVOL_LIODPDRV
+NTFS_VOL::QueryDupVolume(
+ IN PCWSTRING NtDriveName,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN ExclusiveWrite,
+ IN BOOLEAN FormatMedia,
+ IN MEDIA_TYPE MediaType
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine allocates a NTFS_VOL and initializes it to 'NtDriveName'.
+
+Arguments:
+
+ NtDriveName - Supplies the drive path for the volume.
+ Message - Supplies an outlet for messages.
+ ExclusiveWrite - Supplies whether or not the drive should be
+ opened for exclusive write.
+ FormatMedia - Supplies whether or not to format the media.
+ MediaType - Supplies the type of media to format to.
+
+Return Value:
+
+ A pointer to a newly allocated NTFS volume.
+
+--*/
+{
+ PNTFS_VOL vol;
+
+ // unreferenced parameters
+ (void)(this);
+
+ if (!(vol = NEW NTFS_VOL)) {
+ Message ? Message->Set(MSG_FMT_NO_MEMORY) : 1;
+ Message ? Message->Display("") : 1;
+ return NULL;
+ }
+
+ if (!vol->Initialize(NtDriveName, Message, ExclusiveWrite,
+ FormatMedia, MediaType)) {
+ DELETE(vol);
+ return NULL;
+ }
+
+ return vol;
+}
+
+BOOLEAN
+NTFS_VOL::Extend(
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN Verify,
+ IN BIG_INT nsecOldSize
+ )
+/*++
+
+Routine Description:
+
+ This routine extends the volume. Sector zero will already
+ have been modified.
+
+ The first thing to do is to write the duplicate boot sector
+ at the end of the partition. Then we'll verify the remaining
+ new sectors. Finally, we'll allocate a larger volume bitmap
+ and add any bad clusters that were found to the bad cluster
+ file.
+
+Arguments:
+
+ Message - Supplies an outlet for messages.
+ Verify - Tells whether to verify the space that has been added.
+ nsecOldSize - Supplies the previous size of the volume, in sectors.
+
+Return Value:
+
+ TRUE if successful.
+
+--*/
+{
+ HMEM hmem;
+ BIG_INT last_sector;
+ SECRUN secrun;
+ NUMBER_SET bad_clusters;
+ NTFS_MFT_FILE mft;
+ NTFS_UPCASE_TABLE upcase_table;
+ NTFS_ATTRIBUTE upcase_attr;
+ NTFS_ATTRIBUTE volume_bitmap_attr;
+ NTFS_BITMAP volume_bitmap;
+ NTFS_BITMAP_FILE bitmap_file;
+ NTFS_UPCASE_FILE upcase_file;
+ NTFS_INDEX_TREE root_index;
+ NTFS_FILE_RECORD_SEGMENT root_frs;
+ NTFS_EXTENT_LIST extents;
+ NTFS_BOOT_FILE boot_file;
+ NTFS_ATTRIBUTE boot_attr;
+ DSTRING index_name;
+ ULONG i;
+ BIG_INT li, old_nclus;
+ ULONG cluster_size;
+ ULONG nclus_boot_area;
+ BOOLEAN error;
+
+ // QueryVolumeSectors will return a volume size one less than
+ // the partition size. Note that we'll be writing past the end of
+ // the volume file.
+ //
+
+ last_sector = GetNtfsSuperArea()->QueryVolumeSectors();
+ cluster_size = GetNtfsSuperArea()->QueryClusterFactor() * QuerySectorSize();
+ old_nclus = nsecOldSize / GetNtfsSuperArea()->QueryClusterFactor();
+
+ if (!mft.Initialize(this,
+ GetNtfsSuperArea()->QueryMftStartingLcn(),
+ GetNtfsSuperArea()->QueryClusterFactor(),
+ GetNtfsSuperArea()->QueryFrsSize(),
+ GetNtfsSuperArea()->QueryVolumeSectors(),
+ NULL, NULL) ||
+ !mft.Read() ||
+ !bitmap_file.Initialize(mft.GetMasterFileTable()) ||
+ !bitmap_file.Read() ||
+ !bitmap_file.QueryAttribute(&volume_bitmap_attr, &error, $DATA) ||
+ !volume_bitmap.Initialize(old_nclus, TRUE)) {
+
+ return FALSE;
+ }
+
+
+ if (!volume_bitmap.Read(&volume_bitmap_attr) ||
+ !upcase_file.Initialize(mft.GetMasterFileTable()) ||
+ !upcase_file.Read() ||
+ !upcase_file.QueryAttribute(&upcase_attr, &error, $DATA) ||
+ !upcase_table.Initialize(&upcase_attr) ||
+ !mft.Initialize(this,
+ GetNtfsSuperArea()->QueryMftStartingLcn(),
+ GetNtfsSuperArea()->QueryClusterFactor(),
+ GetNtfsSuperArea()->QueryFrsSize(),
+ GetNtfsSuperArea()->QueryVolumeSectors(),
+ &volume_bitmap,
+ &upcase_table) ||
+ !mft.Read()) {
+
+ return FALSE;
+ }
+
+ if (!index_name.Initialize("$I30") ||
+ !root_frs.Initialize(ROOT_FILE_NAME_INDEX_NUMBER, &mft) ||
+ !root_frs.Read()) {
+ return FALSE;
+ }
+
+ if (!root_index.Initialize(this, GetNtfsSuperArea()->QueryClusterFactor(),
+ &volume_bitmap, &upcase_table, root_frs.QuerySize(), &root_frs, &index_name)) {
+
+ return FALSE;
+ }
+
+ //
+ // Truncate the boot file to be just the sector 0 boot area.
+ //
+
+ nclus_boot_area = (BYTES_IN_BOOT_AREA % cluster_size) ?
+ BYTES_IN_BOOT_AREA / cluster_size + 1 :
+ BYTES_IN_BOOT_AREA / cluster_size;
+
+ if (!boot_file.Initialize(mft.GetMasterFileTable()) ||
+ !boot_file.Read() ||
+ !boot_file.QueryAttribute(&boot_attr, &error, $DATA) ||
+ !boot_attr.Resize(nclus_boot_area * cluster_size, &volume_bitmap) ||
+ !boot_attr.InsertIntoFile(&boot_file, &volume_bitmap) ||
+ !boot_file.Flush(&volume_bitmap, &root_index)) {
+
+ return FALSE;
+ }
+
+ //
+ // Grow the bitmap to represent the new volume size.
+ //
+
+ if (!volume_bitmap.Resize(GetNtfsSuperArea()->QueryVolumeSectors() /
+ GetNtfsSuperArea()->QueryClusterFactor())) {
+
+ return FALSE;
+ }
+
+ // The volume bitmap may have set bits at the end, beyond the end of
+ // the old volume, because format pads the bitmap that way. We clear
+ // those bits because they don't make sense for the new volume.
+ //
+
+ for (li = old_nclus; li < old_nclus + 64; li += 1) {
+
+ volume_bitmap.SetFree(li, 1);
+ }
+
+ // We won't want to resize the bitmap again, and the volume bitmap is
+ // usually considered non-growable, so make it that way now. This will
+ // have the size-effect of setting the padding bits at the end.
+ //
+
+ volume_bitmap.SetGrowable(FALSE);
+
+ //
+ // Copy the boot sector to the end of the partition.
+ //
+
+ if (!secrun.Initialize(&hmem, this, 0, 1)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ if (!secrun.Read()) {
+ //Message->Set(MSG_DEVICE_ERROR);
+ //Message->Display();
+ return FALSE;
+ }
+
+ secrun.Relocate(last_sector);
+
+ if (!secrun.Write()) {
+ //Message->Set(MSG_DEVICE_ERROR);
+ //Message->Display();
+ return FALSE;
+ }
+
+ if (Verify) {
+
+ if (!VerifyExtendedSpace(mft.GetMasterFileTable(),
+ nsecOldSize - 1,
+ (last_sector + 1) - nsecOldSize,
+ &bad_clusters,
+ Message)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ if (!volume_bitmap_attr.MakeNonresident(&volume_bitmap) ||
+ !volume_bitmap.Write(&volume_bitmap_attr, &volume_bitmap)) {
+
+ if (!volume_bitmap_attr.RecoverAttribute(&volume_bitmap, &bad_clusters) ||
+ !volume_bitmap.Write(&volume_bitmap_attr, &volume_bitmap)) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_VOLUME_BITMAP);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ if (!volume_bitmap_attr.InsertIntoFile(&bitmap_file, &volume_bitmap) ||
+ !bitmap_file.Flush(&volume_bitmap, &root_index)) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+//
+// Local support routine
+//
+
+BOOLEAN
+VerifyExtendedSpace(
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN BIG_INT StartingCluster,
+ IN BIG_INT NumberClusters,
+ IN OUT PNUMBER_SET BadClusters,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies all of the unused clusters on the disk.
+ It adds any that are bad to the given bad cluster list.
+
+Arguments:
+
+ StartingCluster - Supplies the cluster to start verifying at.
+ NumberClusters - Supplies the number of clusters to verify.
+ BadClusters - Supplies the current list of bad clusters.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ PLOG_IO_DP_DRIVE drive;
+ PNTFS_BITMAP bitmap;
+ BIG_INT i, len;
+ ULONG percent_done;
+ NUMBER_SET bad_sectors;
+ ULONG cluster_factor;
+ BIG_INT start, run_length, next;
+ ULONG j;
+
+ Message->Set(MSG_CHK_RECOVERING_FREE_SPACE, PROGRESS_MESSAGE);
+ Message->Display();
+
+ drive = Mft->GetDataAttribute()->GetDrive();
+ bitmap = Mft->GetVolumeBitmap();
+ cluster_factor = Mft->QueryClusterFactor();
+
+ percent_done = 0;
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", percent_done)) {
+ return FALSE;
+ }
+
+ for (i = 0; i < NumberClusters; ) {
+
+ len = min(NumberClusters - i, 100);
+
+ if (len < 1) {
+ break;
+ }
+
+ if (!bad_sectors.Initialize() ||
+ !drive->Verify((i + StartingCluster) * cluster_factor,
+ len*cluster_factor,
+ &bad_sectors)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ for (j = 0; j < bad_sectors.QueryNumDisjointRanges(); j++) {
+
+ bad_sectors.QueryDisjointRange(j, &start, &run_length);
+ next = start + run_length;
+
+ // Adjust start and next to be on cluster boundaries.
+ start = start/cluster_factor;
+ next = (next - 1)/cluster_factor + 1;
+
+ // Add the bad clusters to the bad cluster list.
+ if (!BadClusters->Add(start, next - start)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ // Mark the bad clusters as allocated in the bitmap.
+ bitmap->SetAllocated(start, next - start);
+ }
+
+ i += len;
+
+ if (100*i/NumberClusters > percent_done) {
+ percent_done = (100*i/NumberClusters).GetLowPart();
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", percent_done)) {
+ return FALSE;
+ }
+ }
+ }
+
+ percent_done = 100;
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", percent_done)) {
+ return FALSE;
+ }
+
+ Message->Set(MSG_CHK_DONE_RECOVERING_FREE_SPACE, PROGRESS_MESSAGE);
+ Message->Display();
+
+ return TRUE;
+}
diff --git a/private/utils/untfs/src/pch.cxx b/private/utils/untfs/src/pch.cxx
new file mode 100644
index 000000000..e7625e1ef
--- /dev/null
+++ b/private/utils/untfs/src/pch.cxx
@@ -0,0 +1,50 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ pch.cxx
+
+Abstract:
+
+ Pre-compiled header for untfs.
+
+Author:
+
+ Matthew Bradburn (mattbr) 26-Apr-1994
+
+--*/
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+
+#include "untfs.hxx"
+#include "attrcol.hxx"
+#include "attrdef.hxx"
+#include "attrib.hxx"
+#include "attrlist.hxx"
+#include "attrrec.hxx"
+#include "badfile.hxx"
+#include "bitfrs.hxx"
+#include "bootfile.hxx"
+#include "clusrun.hxx"
+#include "extents.hxx"
+#include "frs.hxx"
+#include "frsstruc.hxx"
+#include "hackwc.hxx"
+#include "indxbuff.hxx"
+#include "indxroot.hxx"
+#include "indxtree.hxx"
+#include "logfile.hxx"
+#include "mft.hxx"
+#include "mftfile.hxx"
+#include "mftref.hxx"
+#include "ntfsbit.hxx"
+#include "ntfssa.hxx"
+#include "ntfsvol.hxx"
+#include "upcase.hxx"
+#include "upfile.hxx"
+#include "ifssys.hxx"
diff --git a/private/utils/untfs/src/sdchk.cxx b/private/utils/untfs/src/sdchk.cxx
new file mode 100644
index 000000000..4ac15ba84
--- /dev/null
+++ b/private/utils/untfs/src/sdchk.cxx
@@ -0,0 +1,1752 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ sdchk.cxx
+
+Abstract:
+
+ This module implements Security Descriptors Checking.
+
+Author:
+
+ Daniel Chan (danielch) 30-Sept-96
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "ntfssa.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+#include "ntfsbit.hxx"
+#include "attrcol.hxx"
+#include "frsstruc.hxx"
+#include "attrib.hxx"
+#include "attrrec.hxx"
+#include "attrlist.hxx"
+#include "list.hxx"
+#include "iterator.hxx"
+#include "attrdef.hxx"
+#include "extents.hxx"
+#include "mft.hxx"
+#include "mftref.hxx"
+#include "bootfile.hxx"
+#include "badfile.hxx"
+#include "mftfile.hxx"
+#include "numset.hxx"
+#include "ifssys.hxx"
+#include "indxtree.hxx"
+#include "upcase.hxx"
+#include "upfile.hxx"
+#include "frs.hxx"
+#include "digraph.hxx"
+#include "logfile.hxx"
+#include "rcache.hxx"
+#include "ifsentry.hxx"
+#include "sdchk.hxx"
+
+typedef struct _REPAIR_RECORD {
+ ULONG Offset;
+ ULONG Length;
+};
+
+DEFINE_TYPE(_REPAIR_RECORD, REPAIR_RECORD);
+
+ULONG
+ComputeDefaultSecurityId(
+ PNUMBER_SET SidSet
+);
+
+VOID
+ClearSecurityDescriptorEntry(
+ IN OUT PSECURITY_ENTRY Security_entry,
+ IN ULONG SecurityDescriptorSize
+);
+
+BOOLEAN
+RemainingBlockIsZero(
+ IN OUT PCHAR Buffer,
+ IN ULONG Size
+);
+
+BOOLEAN
+RecoverSecurityDescriptorsDataStream(
+ IN OUT PNTFS_FILE_RECORD_SEGMENT Frs,
+ IN OUT PNTFS_ATTRIBUTE Attrib,
+ IN ULONG AttributeSize,
+ IN PCHAR Buffer,
+ IN ULONG BufferSize,
+ IN ULONG ClusterSize,
+ IN OUT PNTFS_BITMAP Bitmap,
+ OUT PBOOLEAN DiskHasErrors,
+ IN OUT PNUMBER_SET BadClusters,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN FixLevel
+);
+
+BOOLEAN
+RepairSecurityDescriptorsSegment(
+ IN OUT PNTFS_ATTRIBUTE Attrib,
+ IN PCHAR Buffer,
+ IN ULONG Offset,
+ IN ULONG BytesToProcess,
+ IN OUT PREPAIR_RECORD Record,
+ IN OUT USHORT *RecordCount,
+ IN ULONG ClusterSize
+);
+
+#if defined( _SETUP_LOADER_ )
+
+BOOLEAN
+NTFS_SA::ValidateSecurityDescriptors(
+ IN PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PNTFS_CHKDSK_REPORT ChkdskReport,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN OUT PNUMBER_SET BadClusters,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine ensures that every file on the disk contains
+ a valid security descriptor.
+
+Arguments:
+
+ ChkdskInfo - Supplies the current chkdsk information.
+ Mft - Supplies a valid MFT.
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ // Stub for Setup Loader.
+
+ return TRUE;
+}
+
+#else // not _SETUP_LOADER_
+
+BOOLEAN
+NTFS_SA::ValidateSecurityDescriptors(
+ IN PNTFS_CHKDSK_INFO ChkdskInfo,
+ IN OUT PNTFS_CHKDSK_REPORT ChkdskReport,
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft,
+ IN OUT PNUMBER_SET BadClusters,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine ensures that every file on the disk contains
+ a valid security descriptor. If that's not the case, then
+ it expects to find the $SDS data stream in $Secure and each
+ of those files contain a security id.
+
+Arguments:
+
+ ChkdskInfo - Supplies the current chkdsk information.
+ Mft - Supplies a valid MFT.
+ FixLevel - Supplies the fix level.
+ Message - Supplies an outlet for messages
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_FILE_RECORD_SEGMENT myfrs;
+ PNTFS_FILE_RECORD_SEGMENT pfrs;
+ NTFS_FILE_RECORD_SEGMENT security_frs;
+ ULONG i, n;
+ ULONG percent;
+ NTFS_ATTRIBUTE attrib;
+ NTFS_ATTRIBUTE SDS_attrib;
+ NTFS_ATTRIBUTE SII_attrib;
+ BOOLEAN error;
+ BOOLEAN diskHasErrors;
+ BOOLEAN chkdskErrCouldNotFix = FALSE;
+ BOOLEAN attribute_need_write = FALSE;
+ BOOLEAN frs_need_flush = FALSE;
+ BOOLEAN index_need_save = FALSE;
+ BOOLEAN attribute_need_resize;
+ BOOLEAN boundary_problem_found;
+ BOOLEAN need_new;
+ BOOLEAN lastblock;
+ BOOLEAN fixing_mirror;
+ BOOLEAN has_security_descriptor_attribute;
+ PSECURITY_DESCRIPTOR security;
+ ULONG length;
+ ULONG num_bytes;
+ ULONG num_frs_per_prime;
+ ULONG frs_size;
+ BOOLEAN securityDescriptorStreamPresent = FALSE;
+ BOOLEAN alreadyExists;
+ BOOLEAN new_SII_index = FALSE;
+ BOOLEAN new_SDH_index = FALSE;
+ BOOLEAN alloc_present;
+ DSTRING SII_IndexName;
+ DSTRING SDH_IndexName;
+ DSTRING indexName;
+ ULONG hash, offset;
+ ULONG bytesWritten;
+ BIG_INT hashkey;
+ NUMBER_SET sid_entries, sid_entries2, hashkey_entries;
+ NTFS_INDEX_TREE SII_Index;
+ NTFS_INDEX_TREE SDH_Index;
+ ULONG count_sid = 0;
+ ULONG count_hashkey = 0;
+ PCINDEX_ENTRY index_entry;
+ ULONG depth;
+ ULONG securityId;
+ ULONG defaultSecurityId = 0;
+ PSTANDARD_INFORMATION2 standard_information2;
+ PSECURITY_ENTRY security_entry = NULL;
+ PSECURITY_ENTRY previous_security_entry;
+ PSECURITY_ENTRY previous_previous_security_entry;
+ PSECURITY_ENTRY initial_security_entry = NULL;
+ PSECURITY_ENTRY endOfBlock;
+ ULONG lengthUptoPreviousBlock;
+ ULONG resizeTo;
+ ULONG remain_length;
+ ULONG bytesToRead;
+ ULONG lengthOfBlock;
+ ULONG align_num_bytes;
+ ULONG se_offset;
+ ULONG total_length;
+ ULONG sdLength;
+
+ DebugPtrAssert(ChkdskInfo);
+ DebugPtrAssert(ChkdskReport);
+
+ Message->Set(MSG_CHK_NTFS_CHECKING_SECURITY, PROGRESS_MESSAGE);
+ Message->Display();
+
+ // Check for existence of $SecurityDescriptorStream in SECURITY_TABLE_NUMBER
+
+ if (!security_frs.Initialize(SECURITY_TABLE_NUMBER, Mft) ||
+ !indexName.Initialize(SecurityDescriptorStreamNameData)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ // ??what to do if frs is unreadable or not in use or not a base??
+
+ if (security_frs.Read() && security_frs.IsInUse() && security_frs.IsBase()) {
+ securityDescriptorStreamPresent =
+ security_frs.QueryAttribute(&SDS_attrib,
+ &error,
+ $DATA,
+ &indexName) &&
+ ChkdskInfo->major >= 2;
+
+ if (!error && !securityDescriptorStreamPresent && ChkdskInfo->major >= 2) {
+ if (!SDS_attrib.Initialize(_drive,
+ QueryClusterFactor(),
+ NULL,
+ 0,
+ $DATA,
+ &indexName)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ if (!SDS_attrib.InsertIntoFile(&security_frs,
+ Mft->GetVolumeBitmap())) {
+ Message->Set(MSG_CHK_NTFS_CANT_PUT_DATA_ATTRIBUTE);
+ Message->Display();
+ return FALSE;
+ }
+ if (FixLevel != CheckOnly &&
+ !security_frs.Flush(Mft->GetVolumeBitmap())) {
+ Message->Set(MSG_CHK_NTFS_CANT_PUT_DATA_ATTRIBUTE);
+ Message->Display();
+ return FALSE;
+ }
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ securityDescriptorStreamPresent = TRUE;
+ }
+ if (!error && securityDescriptorStreamPresent) {
+
+ if (!SII_IndexName.Initialize(SecurityIdIndexNameData) ||
+ !SDH_IndexName.Initialize(SecurityDescriptorHashIndexNameData)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ // make sure the $SII index exists
+ // if it does not exists, an empty one will be created
+
+ if (!SII_Index.Initialize(_drive,
+ QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ Mft->GetUpcaseTable(),
+ security_frs.QuerySize()/2,
+ &security_frs,
+ &SII_IndexName)) {
+ Message->Set(MSG_CHK_NTFS_CREATE_INDEX);
+ Message->Display("%W%d", &SII_IndexName, SECURITY_TABLE_NUMBER);
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ if (!SII_Index.Initialize(0,
+ _drive,
+ QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ Mft->GetUpcaseTable(),
+ COLLATION_ULONG,
+ SMALL_INDEX_BUFFER_SIZE,
+ security_frs.QuerySize()/2,
+ &SII_IndexName)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (FixLevel != CheckOnly &&
+ (!SII_Index.Save(&security_frs) ||
+ !security_frs.Flush(Mft->GetVolumeBitmap()))) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_INDEX);
+ Message->Display("%d%W",
+ security_frs.QueryFileNumber().GetLowPart(),
+ &SII_IndexName);
+ return FALSE;
+ }
+ ChkdskReport->NumIndices += 1;
+ new_SII_index = TRUE;
+ }
+
+ // make sure the $SDH index exists
+ // if it does not exists, an empty one will be created
+
+ if (!SDH_Index.Initialize(_drive,
+ QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ Mft->GetUpcaseTable(),
+ security_frs.QuerySize()/2,
+ &security_frs,
+ &SDH_IndexName)) {
+ Message->Set(MSG_CHK_NTFS_CREATE_INDEX);
+ Message->Display("%W%d", &SDH_IndexName, SECURITY_TABLE_NUMBER);
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ if (!SDH_Index.Initialize(0,
+ _drive,
+ QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ Mft->GetUpcaseTable(),
+ COLLATION_SECURITY_HASH,
+ SMALL_INDEX_BUFFER_SIZE,
+ security_frs.QuerySize()/2,
+ &SDH_IndexName)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display("%d%W",
+ security_frs.QueryFileNumber().GetLowPart(),
+ &SII_IndexName);
+ return FALSE;
+ }
+
+ if (FixLevel != CheckOnly &&
+ (!SDH_Index.Save(&security_frs) ||
+ !security_frs.Flush(Mft->GetVolumeBitmap()))) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_INDEX);
+ Message->Display("%d%W",
+ security_frs.QueryFileNumber().GetLowPart(),
+ &SDH_IndexName);
+ return FALSE;
+ }
+ ChkdskReport->NumIndices += 1;
+ new_SDH_index = TRUE;
+ }
+
+ // Read in the security descriptor and validate.
+
+ length = SDS_attrib.QueryValueLength().GetLowPart();
+
+ // allocate space for a block of security descriptors
+
+ if (SDS_attrib.QueryValueLength().GetHighPart() != 0 ||
+ !(initial_security_entry = (SECURITY_ENTRY*)
+ MALLOC(SecurityDescriptorsBlockSize))) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!RecoverSecurityDescriptorsDataStream(
+ &security_frs,
+ &SDS_attrib,
+ length,
+ (PCHAR)initial_security_entry,
+ SecurityDescriptorsBlockSize,
+ _drive->QuerySectorSize()*QueryClusterFactor(),
+ Mft->GetVolumeBitmap(),
+ &diskHasErrors,
+ BadClusters,
+ Message,
+ FixLevel)) {
+ FREE(initial_security_entry);
+ return FALSE;
+ } else if (diskHasErrors && FixLevel != CheckOnly &&
+ !security_frs.Flush(Mft->GetVolumeBitmap())) {
+ Message->Set(MSG_CHK_READABLE_FRS_UNWRITEABLE);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+
+ // get the actual length of the first copy of security descriptor data
+
+ if (length < SecurityDescriptorsBlockSize) {
+
+ // Resize the whole thing to zero length
+
+ attribute_need_resize = TRUE;
+ length = 0;
+ } else {
+ attribute_need_resize = FALSE;
+ length -= SecurityDescriptorsBlockSize;
+ }
+
+ offset = 0;
+ lengthUptoPreviousBlock = 0;
+ frs_need_flush = FALSE;
+ boundary_problem_found = FALSE;
+ resizeTo = 0;
+ endOfBlock = (PSECURITY_ENTRY)((PCHAR)initial_security_entry+
+ SecurityDescriptorsBlockSize);
+ remain_length = length;
+
+ if (!sid_entries.Initialize() ||
+ !sid_entries2.Initialize() ||
+ !hashkey_entries.Initialize()) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+
+ for (;length > 0;) {
+ previous_previous_security_entry = previous_security_entry = NULL;
+ attribute_need_write = FALSE;
+ bytesToRead = min(SecurityDescriptorsBlockSize, length);
+ security_entry = initial_security_entry;
+ if (!SDS_attrib.Read(security_entry,
+ offset,
+ bytesToRead, &num_bytes) ||
+ num_bytes != bytesToRead) {
+ Message->Set(MSG_CHK_NTFS_CANT_READ_SECURITY_DATA_STREAM);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+
+ lastblock = length <= SecurityDescriptorsBlockSize;
+ lengthOfBlock = 0;
+
+ // Validate each security descriptor record in the data stream
+
+ while (length > 0) {
+
+ // see if there is a need to move to next security descriptor block
+
+ if (security_entry == endOfBlock ||
+ (security_entry->security_descriptor_header.Length == 0 &&
+ security_entry->security_descriptor_header.HashKey.SecurityId == 0 &&
+ security_entry->security_descriptor_header.HashKey.Hash == 0)) {
+ if (!lastblock &&
+ (remain_length >= (SecurityDescriptorsBlockSize<<1))) {
+ lengthOfBlock = (PCHAR)security_entry-
+ (PCHAR)initial_security_entry;
+ if (!RemainingBlockIsZero((PCHAR)security_entry,
+ (PCHAR)endOfBlock-(PCHAR)security_entry)) {
+ MarkEndOfSecurityDescriptorsBlock(security_entry,
+ (PCHAR)endOfBlock-(PCHAR)security_entry);
+ DebugPrint("Clearing till end of the security descriptors block.\n");
+ attribute_need_write = TRUE;
+ }
+ break;
+ } else
+ boundary_problem_found = TRUE;
+ }
+
+ num_bytes = security_entry->security_descriptor_header.Length;
+ align_num_bytes = (num_bytes + 0xf) & ~0xf;
+
+ if (boundary_problem_found ||
+ ((PCHAR)security_entry-(PCHAR)initial_security_entry+
+ num_bytes > SecurityDescriptorsBlockSize) ||
+ (num_bytes < sizeof(SECURITY_ENTRY)) ||
+ (num_bytes > SecurityDescriptorMaxSize) ||
+ (length < sizeof(SECURITY_ENTRY)) ||
+ (length != num_bytes && length < align_num_bytes)) {
+ boundary_problem_found = FALSE;
+ if (!lastblock) {
+ if ((PCHAR)security_entry-(PCHAR)initial_security_entry+
+ sizeof(SECURITY_DESCRIPTOR_HEADER) <=
+ SecurityDescriptorsBlockSize) {
+ MarkEndOfSecurityDescriptorsBlock(security_entry,
+ (PCHAR)endOfBlock-
+ (PCHAR)security_entry);
+ if (previous_security_entry)
+ lengthOfBlock = (PCHAR)previous_security_entry -
+ (PCHAR)initial_security_entry +
+ previous_security_entry->security_descriptor_header.Length;
+ else
+ lengthOfBlock = 0;
+ } else if (previous_security_entry) {
+ sid_entries.Remove(previous_security_entry->
+ security_descriptor_header.HashKey.SecurityId);
+ hashkey.Set(previous_security_entry->
+ security_descriptor_header.HashKey.Hash,
+ previous_security_entry->
+ security_descriptor_header.HashKey.SecurityId);
+ hashkey_entries.Remove(hashkey);
+
+ // the index entry will automatically be removed at a later stage
+
+ MarkEndOfSecurityDescriptorsBlock(previous_security_entry,
+ (PCHAR)endOfBlock-
+ (PCHAR)previous_security_entry);
+ if (previous_previous_security_entry) {
+ lengthOfBlock = (PCHAR)previous_previous_security_entry -
+ (PCHAR)initial_security_entry +
+ previous_previous_security_entry->
+ security_descriptor_header.Length;
+ } else {
+ lengthOfBlock = 0;
+ }
+ } else {
+ DebugAssert(FALSE);
+
+ // It doesn't make much sense to get here.
+ // If we don't have a previous_security_entry then
+ // security_entry is at the beginning of the block
+ // and should have enough space to include the EOB
+ // mark.
+
+ }
+ attribute_need_write = TRUE;
+ DebugPrint("Clearing till end of the security descriptors block.\n");
+ } else { // if lastblock
+ if (previous_security_entry) {
+ DebugAssert(remain_length <= SecurityDescriptorsBlockSize);
+ bytesToRead = remain_length = lengthOfBlock =
+ (PCHAR)previous_security_entry-
+ (PCHAR)initial_security_entry+
+ previous_security_entry->
+ security_descriptor_header.Length;
+ resizeTo = lengthOfBlock + offset;
+ } else {
+ bytesToRead = remain_length = lengthOfBlock = 0;
+ resizeTo = lengthUptoPreviousBlock;
+ DebugAssert(!attribute_need_write);
+ }
+ attribute_need_resize = TRUE; // no need to write attribute
+ DebugPrint("Truncating the security descriptors block.\n");
+ }
+ break;
+ }
+
+ // skip over invalidated entries
+
+ securityId = security_entry->security_descriptor_header.HashKey.SecurityId;
+ if (securityId == SECURITY_ID_INVALID)
+ goto GetNextSDEntry;
+
+ sdLength = num_bytes - sizeof(SECURITY_DESCRIPTOR_HEADER);
+ if (!IFS_SYSTEM::CheckValidSecurityDescriptor(
+ sdLength,
+ &(security_entry->security)) ||
+ sdLength < RtlLengthSecurityDescriptor(
+ &(security_entry->security))) {
+
+ // the data part is invalid
+ // fill the whole thing with zeros except the length byte in the header
+
+ ClearSecurityDescriptorEntry(security_entry, sdLength);
+ attribute_need_write = TRUE;
+ DebugPrint("Clearing invalid security descriptor.\n");
+ goto GetNextSDEntry;
+ }
+
+ // check to see if we encountered this sid before
+ // also build a set with all the sid encountered
+
+ if (sid_entries.CheckAndAdd(securityId, &alreadyExists)) {
+ if (alreadyExists) {
+ ClearSecurityDescriptorEntry(security_entry, sdLength);
+ attribute_need_write = TRUE;
+ DebugPrint("Clearing duplicate security descriptor.\n");
+ goto GetNextSDEntry;
+ }
+ } else {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+
+ // check to see if the hash value is good
+
+ hash = ComputeSecurityDescriptorHash(
+ &(security_entry->security), sdLength);
+ if (security_entry->security_descriptor_header.HashKey.Hash != hash) {
+ security_entry->security_descriptor_header.HashKey.Hash = hash;
+ attribute_need_write = TRUE;
+ DebugPrint("Repairing hash value of a security descriptor header.\n");
+ }
+
+ // check to see if the offset stored in the security descriptor header is good
+
+ se_offset = (PCHAR)security_entry -
+ (PCHAR)initial_security_entry +
+ offset;
+ if (security_entry->security_descriptor_header.Offset != se_offset) {
+ security_entry->security_descriptor_header.Offset = se_offset;
+ attribute_need_write = TRUE;
+ DebugPrint("Repairing offset value of a security descriptor header.\n");
+ }
+
+ // build a set with all the hashkey encountered
+
+ hashkey.Set(hash, securityId);
+ if (hashkey_entries.CheckAndAdd(hashkey, &alreadyExists)) {
+ DebugAssert(!alreadyExists); // sid is unique thus hashkey
+ } else {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+
+ // now we know the entry is unique and good
+ // make sure there is a corresponding entry in
+ // SecurityIdIndex and SecurityDescriptorHashIndex
+ // index streams
+
+ switch (security_frs.FindSecurityIndexEntryAndValidate(
+ &SII_Index,
+ (PVOID)&securityId,
+ sizeof(securityId),
+ &(security_entry->security_descriptor_header),
+ Mft->GetVolumeBitmap(),
+ FixLevel == CheckOnly)) {
+ case NTFS_SECURITY_INDEX_FOUND:
+
+ // good, entry already exists in the index
+
+ break; // go onto next entry
+
+ case NTFS_SECURITY_INDEX_FIXED:
+ case NTFS_SECURITY_INDEX_DATA_ERROR:
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ Message->Set(MSG_CHK_NTFS_REPAIRING_INDEX_ENTRY);
+ Message->Display("%d%W",
+ security_frs.QueryFileNumber().GetLowPart(),
+ &SII_IndexName);
+ frs_need_flush = TRUE;
+ break;
+
+ case NTFS_SECURITY_INDEX_ENTRY_MISSING:
+ case NTFS_SECURITY_INDEX_INSERTED:
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ Message->Set(MSG_CHK_NTFS_INSERTING_INDEX_ENTRY);
+ Message->Display("%d%W",
+ security_frs.QueryFileNumber().GetLowPart(),
+ &SII_IndexName);
+ frs_need_flush = TRUE;
+ break;
+
+ case NTFS_SECURITY_INSERT_FAILED:
+ chkdskErrCouldNotFix = TRUE;
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_INDEX);
+ Message->Display("%d%W",
+ security_frs.QueryFileNumber().GetLowPart(),
+ &SII_IndexName);
+ break;
+
+ case NTFS_SECURITY_ERROR:
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+ switch (security_frs.FindSecurityIndexEntryAndValidate(
+ &SDH_Index,
+ (PVOID)&(security_entry->security_descriptor_header.HashKey),
+ sizeof(security_entry->security_descriptor_header.HashKey),
+ &(security_entry->security_descriptor_header),
+ Mft->GetVolumeBitmap(),
+ FixLevel == CheckOnly)) {
+ case NTFS_SECURITY_INDEX_FOUND:
+
+ // good, entry already exists in the index
+
+ break; // go onto next entry
+
+ case NTFS_SECURITY_INDEX_FIXED:
+ case NTFS_SECURITY_INDEX_DATA_ERROR:
+
+ //*DiskErrorsFound = TRUE;
+
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ Message->Set(MSG_CHK_NTFS_REPAIRING_INDEX_ENTRY);
+ Message->Display("%d%W",
+ security_frs.QueryFileNumber().GetLowPart(),
+ &SDH_IndexName);
+ frs_need_flush = TRUE;
+ break;
+
+ case NTFS_SECURITY_INDEX_ENTRY_MISSING:
+ case NTFS_SECURITY_INDEX_INSERTED:
+
+ //*DiskErrorsFound = TRUE;
+
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ Message->Set(MSG_CHK_NTFS_INSERTING_INDEX_ENTRY);
+ Message->Display("%d%W",
+ security_frs.QueryFileNumber().GetLowPart(),
+ &SDH_IndexName);
+ frs_need_flush = TRUE;
+ break;
+
+ case NTFS_SECURITY_INSERT_FAILED:
+ chkdskErrCouldNotFix = TRUE;
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_INDEX);
+ Message->Display("%d%W",
+ security_frs.QueryFileNumber().GetLowPart(),
+ &SDH_IndexName);
+ break;
+
+ case NTFS_SECURITY_ERROR:
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+
+ GetNextSDEntry:
+ if (length == num_bytes) {
+ lengthOfBlock = (PCHAR)security_entry-
+ (PCHAR)initial_security_entry+
+ num_bytes;
+ break; // done, leave the while loop
+ } else {
+ length -= align_num_bytes;
+ previous_previous_security_entry = previous_security_entry;
+ previous_security_entry = security_entry;
+ security_entry = (SECURITY_ENTRY*)((char *)security_entry +
+ align_num_bytes);
+ }
+ } // while
+ if (attribute_need_write && FixLevel != CheckOnly) {
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ if (!SDS_attrib.Write(initial_security_entry,
+ offset,
+ bytesToRead,
+ &bytesWritten,
+ Mft->GetVolumeBitmap()) ||
+ bytesWritten != bytesToRead) {
+ chkdskErrCouldNotFix = TRUE;
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_SECURITY_DATA_STREAM);
+ Message->Display();
+ } else
+ frs_need_flush = TRUE;
+ }
+ if (lengthOfBlock)
+ lengthUptoPreviousBlock = lengthOfBlock + offset;
+ offset += (SecurityDescriptorsBlockSize<<1);
+ remain_length -= bytesToRead;
+ if (remain_length >= SecurityDescriptorsBlockSize)
+ remain_length -= SecurityDescriptorsBlockSize;
+ else
+ remain_length = 0;
+ length = remain_length;
+ } // for
+ if (attribute_need_resize && FixLevel != CheckOnly) {
+ if (!SDS_attrib.Resize(resizeTo +
+ SecurityDescriptorsBlockSize,
+ Mft->GetVolumeBitmap())) {
+ chkdskErrCouldNotFix = TRUE;
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_SECURITY_DATA_STREAM);
+ Message->Display();
+ } else
+ frs_need_flush = TRUE;
+ }
+ if (frs_need_flush) {
+ Message->Set(MSG_CHK_NTFS_REPAIRING_SECURITY_FRS);
+ Message->Display();
+ if (FixLevel != CheckOnly &&
+ !security_frs.Flush(Mft->GetVolumeBitmap())) {
+ Message->Set(MSG_CHK_READABLE_FRS_UNWRITEABLE);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+ }
+
+ // now make sure each entry in the index has
+ // a corresponding entry in the $SDS data stream
+
+ index_need_save = FALSE;
+ SII_Index.ResetIterator();
+ while (index_entry = SII_Index.GetNext(&depth, &error)) {
+ securityId = *(ULONG*)GetIndexEntryValue(index_entry);
+ if (!sid_entries.DoesIntersectSet(securityId, 1)) {
+ index_need_save = TRUE;
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ Message->Set(MSG_CHK_NTFS_DELETING_GENERIC_INDEX_ENTRY);
+ Message->Display("%d%W",
+ security_frs.QueryFileNumber().GetLowPart(),
+ SII_Index.GetName());
+ if (FixLevel != CheckOnly && !SII_Index.DeleteCurrentEntry()) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+ } else
+ count_sid++;
+ } // while
+
+ if (index_need_save && FixLevel != CheckOnly) {
+ if (!SII_Index.Save(&security_frs)) {
+ chkdskErrCouldNotFix = TRUE;
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_INDEX);
+ Message->Display("%d%W", security_frs.QueryFileNumber().GetLowPart(),
+ SII_Index.GetName());
+ }
+ if (!security_frs.Flush(Mft->GetVolumeBitmap())) {
+ Message->Set(MSG_CHK_READABLE_FRS_UNWRITEABLE);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+ }
+
+ index_need_save = FALSE;
+ SDH_Index.ResetIterator();
+ while (index_entry = SDH_Index.GetNext(&depth, &error)) {
+ if (hashkey_entries.CheckAndRemove(
+ *(BIG_INT*)GetIndexEntryValue(index_entry),
+ &alreadyExists)) {
+ if (!alreadyExists) {
+ index_need_save = TRUE;
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ Message->Set(MSG_CHK_NTFS_DELETING_GENERIC_INDEX_ENTRY);
+ Message->Display("%d%W",
+ security_frs.QueryFileNumber().GetLowPart(),
+ SDH_Index.GetName());
+ if (FixLevel != CheckOnly && !SDH_Index.DeleteCurrentEntry()) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+ } else
+ count_hashkey++;
+ } else {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+ } // while
+
+ if (index_need_save && FixLevel != CheckOnly) {
+ if (!SDH_Index.Save(&security_frs)) {
+ chkdskErrCouldNotFix = TRUE;
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_INDEX);
+ Message->Display("%d%W", security_frs.QueryFileNumber().GetLowPart(),
+ SDH_Index.GetName());
+ }
+ if (!security_frs.Flush(Mft->GetVolumeBitmap())) {
+ Message->Set(MSG_CHK_READABLE_FRS_UNWRITEABLE);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+ }
+
+ if (FixLevel != CheckOnly && !chkdskErrCouldNotFix) {
+ DebugAssert(count_hashkey == count_sid);
+ }
+ } else if (error) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ Message->Display();
+ return FALSE;
+ } // if (!error && securityDescriptorStreamPresent)
+ } else {
+ DebugPrintf("Hotfixed security frs still has problems\n");
+ return FALSE;
+ }
+
+
+ // now each valid entry in SecurityDescriptorStream has a corresponding
+ // entry in SecurityIdIndex and SecurityDescriptorHashIndex
+
+ // Compute the number of file records.
+
+ frs_size = Mft->QueryFrsSize();
+
+ n = Mft->GetDataAttribute()->QueryValueLength().GetLowPart() / frs_size;
+
+ num_frs_per_prime = MFT_PRIME_SIZE/frs_size;
+
+ percent = 0;
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", percent)) {
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+
+ for (i = 0; i < n; i++) {
+
+ if (i*100/n > percent) {
+ percent = i*100/n;
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", percent)) {
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+ }
+
+ if (Mft->GetMftBitmap()->IsFree(i, 1)) {
+ continue;
+ }
+
+ if (i % num_frs_per_prime == 0) {
+ Mft->GetDataAttribute()->PrimeCache(i*frs_size,
+ num_frs_per_prime*frs_size);
+ }
+
+ if (i == SECURITY_TABLE_NUMBER) {
+ pfrs = &security_frs;
+ } else {
+ if (!myfrs.Initialize(i, Mft)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+ pfrs = &myfrs;
+ }
+
+ if (!pfrs->Read() || !pfrs->IsInUse() || !pfrs->IsBase()) {
+ continue;
+ }
+
+ need_new = has_security_descriptor_attribute = FALSE;
+
+ if (pfrs->QueryAttribute(&attrib, &error, $SECURITY_DESCRIPTOR)) {
+
+ // First recover this attribute to make sure that
+ // everything is readable.
+
+ if (FixLevel != CheckOnly) {
+ attrib.RecoverAttribute(Mft->GetVolumeBitmap(), BadClusters);
+ }
+
+ // Read in the security descriptor and validate.
+
+ length = attrib.QueryValueLength().GetLowPart();
+
+ if (attrib.QueryValueLength().GetHighPart() != 0 ||
+ !(security = (PSECURITY_DESCRIPTOR) MALLOC(length))) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+
+ if (!attrib.Read(security, 0, length, &num_bytes) ||
+ num_bytes != length ||
+ !IFS_SYSTEM::CheckValidSecurityDescriptor(length, security) ||
+ length < RtlLengthSecurityDescriptor(security)) {
+
+ if (!attrib.Resize(0, Mft->GetVolumeBitmap()) ||
+ !pfrs->PurgeAttribute($SECURITY_DESCRIPTOR)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+ need_new = TRUE;
+ } else
+ has_security_descriptor_attribute = TRUE;
+
+ FREE(security);
+
+ } else if (error) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ } else {
+ need_new = (ChkdskInfo->major <= 1);
+ }
+
+ if (ChkdskInfo->major >= 2) {
+ if (pfrs->QueryAttribute(&attrib, &error, $STANDARD_INFORMATION)) {
+ length = attrib.QueryValueLength().GetLowPart();
+ if (length == sizeof(STANDARD_INFORMATION2)) {
+
+ if (!securityDescriptorStreamPresent)
+ continue;
+
+ if (!(standard_information2 =
+ (PSTANDARD_INFORMATION2)attrib.GetResidentValue())) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+
+ securityId = standard_information2->SecurityId;
+
+ if (securityId == SECURITY_ID_INVALID)
+ continue;
+
+ if (has_security_descriptor_attribute ||
+ !sid_entries.DoesIntersectSet(securityId, 1)) {
+
+ standard_information2->SecurityId = SECURITY_ID_INVALID;
+ Message->Set(MSG_CHK_NTFS_INVALID_SECURITY_ID);
+ Message->Display("%d", i);
+
+ if (FixLevel != CheckOnly &&
+ (!attrib.Write((PVOID)standard_information2,
+ 0,
+ sizeof(STANDARD_INFORMATION2),
+ &bytesWritten,
+ Mft->GetVolumeBitmap()) ||
+ bytesWritten != sizeof(STANDARD_INFORMATION2))) {
+ chkdskErrCouldNotFix = TRUE;
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_ATTRIBUTE);
+ Message->Display("%d%d", attrib.QueryTypeCode(), i);
+ }
+ if (FixLevel != CheckOnly && attrib.IsStorageModified() &&
+ !attrib.InsertIntoFile(pfrs, Mft->GetVolumeBitmap())) {
+ chkdskErrCouldNotFix = TRUE;
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_ATTRIBUTE);
+ Message->Display("%d%d", attrib.QueryTypeCode(), i);
+ }
+ if (FixLevel != CheckOnly &&
+ !pfrs->Flush(Mft->GetVolumeBitmap())) {
+ Message->Set(MSG_CHK_READABLE_FRS_UNWRITEABLE);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+ continue;
+ } // if (!sid_entries.DoesIntersectSet(...
+ sid_entries2.Add(standard_information2->SecurityId);
+ } // if (length == sizeof(STANDARD_INFORMATION2))
+ continue;
+ } else if (error) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ } else {
+ DebugPrint("Standard Information Missing\n");
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+ }
+
+ if (need_new) {
+
+ Message->Set(MSG_CHK_NTFS_INVALID_SECURITY_DESCRIPTOR);
+ Message->Display("%d", i);
+
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+
+ if (FixLevel != CheckOnly) {
+ if (!pfrs->AddSecurityDescriptor(EditCannedSd,
+ Mft->GetVolumeBitmap()) ||
+ !pfrs->Flush(Mft->GetVolumeBitmap())) {
+
+ chkdskErrCouldNotFix = TRUE;
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_SECURITY);
+ Message->Display("%d", i);
+ }
+ }
+ }
+ } // for
+
+ Message->Set(MSG_PERCENT_COMPLETE);
+ if (!Message->Display("%d", 100)) {
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+
+ if (securityDescriptorStreamPresent) {
+
+ // now remove those unused sid in the SecurityIdIndex
+
+ index_need_save = FALSE;
+ SII_Index.ResetIterator();
+
+ // calculate the set of sid that are not in use
+
+ sid_entries.Remove(&sid_entries2);
+
+ sid_entries2.RemoveAll();
+
+ if (FixLevel != CheckOnly && !chkdskErrCouldNotFix) {
+
+ DebugAssert(sid_entries.QueryCardinality().GetHighPart() == 0);
+ for (i=0; i<sid_entries.QueryCardinality(); i++) {
+ securityId = sid_entries.QueryNumber(i).GetLowPart();
+ while (index_entry = SII_Index.GetNext(&depth, &error)) {
+ if (*(ULONG*)GetIndexEntryValue(index_entry) == securityId) {
+ index_need_save = TRUE;
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ Message->Set(MSG_CHK_NTFS_DELETING_GENERIC_INDEX_ENTRY);
+ Message->Display("%d%W",
+ security_frs.QueryFileNumber().GetLowPart(),
+ SII_Index.GetName());
+ if (FixLevel != CheckOnly && !SII_Index.DeleteCurrentEntry()) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+ break;
+ }
+ } // while
+ if (FixLevel != CheckOnly && !chkdskErrCouldNotFix)
+ DebugAssert(index_entry != NULL);
+ }
+
+ if (index_need_save && FixLevel != CheckOnly) {
+ if (!SII_Index.Save(&security_frs)) {
+ chkdskErrCouldNotFix = TRUE;
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_INDEX);
+ Message->Display("%d%W", security_frs.QueryFileNumber().GetLowPart(),
+ SII_Index.GetName());
+ }
+ if (!security_frs.Flush(Mft->GetVolumeBitmap())) {
+ Message->Set(MSG_CHK_READABLE_FRS_UNWRITEABLE);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+ }
+
+ //
+ // if the SII index is newly created, then include its size into
+ // chkdsk report
+ //
+
+ if (new_SII_index) {
+ alloc_present = security_frs.QueryAttribute(&attrib,
+ &error,
+ $INDEX_ALLOCATION,
+ SII_Index.GetName());
+
+ if (!alloc_present && error) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+ if (alloc_present) {
+ ChkdskReport->BytesInIndices += attrib.QueryAllocatedLength();
+ }
+ }
+
+ // now removes those unused entries in SecurityDescriptorHashIndex
+
+ if (sid_entries.QueryCardinality().GetLowPart()) {
+ index_need_save = FALSE;
+ SDH_Index.ResetIterator();
+ while (index_entry = SDH_Index.GetNext(&depth, &error)) {
+ securityId = ((PSECURITY_HASH_KEY)GetIndexEntryValue(index_entry))
+ ->SecurityId;
+ if (sid_entries.DoesIntersectSet(securityId, 1)) {
+ index_need_save = TRUE;
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ Message->Set(MSG_CHK_NTFS_DELETING_GENERIC_INDEX_ENTRY);
+ Message->Display("%d%W",
+ security_frs.QueryFileNumber().GetLowPart(),
+ SDH_Index.GetName());
+ if (FixLevel != CheckOnly && !SDH_Index.DeleteCurrentEntry()) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+ }
+ } // while
+
+ if (index_need_save && FixLevel != CheckOnly) {
+ if (!SDH_Index.Save(&security_frs)) {
+ chkdskErrCouldNotFix = TRUE;
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_INDEX);
+ Message->Display("%d%W", security_frs.QueryFileNumber().GetLowPart(),
+ SDH_Index.GetName());
+ }
+ if (!security_frs.Flush(Mft->GetVolumeBitmap())) {
+ Message->Set(MSG_CHK_READABLE_FRS_UNWRITEABLE);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+ }
+ } // if
+
+
+ //
+ // if the SDH index is newly created, then include its size into
+ // chkdsk report
+ //
+
+ if (new_SDH_index) {
+ alloc_present = security_frs.QueryAttribute(&attrib,
+ &error,
+ $INDEX_ALLOCATION,
+ SDH_Index.GetName());
+
+ if (!alloc_present && error) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+ if (alloc_present) {
+ ChkdskReport->BytesInIndices += attrib.QueryAllocatedLength();
+ }
+ }
+
+ // now null those unused entries in SecurityDescriptorStream
+
+ if (sid_entries.QueryCardinality().GetLowPart()) {
+ length = SDS_attrib.QueryValueLength().GetLowPart();
+ length -= SecurityDescriptorsBlockSize;
+ offset = 0;
+ frs_need_flush = FALSE;
+ endOfBlock = (PSECURITY_ENTRY)((PCHAR)initial_security_entry+
+ SecurityDescriptorsBlockSize);
+ remain_length = length;
+
+ for (;length > 0;) {
+ attribute_need_write = FALSE;
+ bytesToRead = min(SecurityDescriptorsBlockSize, length);
+ security_entry = initial_security_entry;
+ if (!SDS_attrib.Read(security_entry,
+ offset,
+ bytesToRead, &num_bytes) ||
+ num_bytes != bytesToRead) {
+ Message->Set(MSG_CHK_NTFS_CANT_READ_SECURITY_DATA_STREAM);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+ while (length > 0) {
+
+ // see if there is a need to move to next security descriptor block
+
+ if (security_entry == endOfBlock ||
+ (security_entry->security_descriptor_header.Length == 0 &&
+ security_entry->security_descriptor_header.HashKey.SecurityId == 0 &&
+ security_entry->security_descriptor_header.HashKey.Hash == 0)) {
+ break;
+ }
+
+ num_bytes = security_entry->security_descriptor_header.Length;
+ securityId = security_entry->security_descriptor_header.HashKey.SecurityId;
+
+ // skip over invalidated entries
+
+ if (securityId == SECURITY_ID_INVALID)
+ goto GetNextSDEntry2;
+
+ if (sid_entries.DoesIntersectSet(securityId, 1)) {
+
+ // fill the whole thing with zeros except the length byte in the header
+
+ DebugPrint("Clearing unuse security descriptor.\n");
+ ClearSecurityDescriptorEntry(security_entry,
+ security_entry->security_descriptor_header.Length -
+ sizeof(SECURITY_DESCRIPTOR_HEADER));
+ attribute_need_write = TRUE;
+ }
+
+ GetNextSDEntry2:
+ if (length == num_bytes) {
+ break; // done, leave the while loop
+ } else {
+ align_num_bytes = (num_bytes + 0xf) & ~0xf;
+ DebugAssert(length > align_num_bytes);
+ length -= align_num_bytes;
+ security_entry = (SECURITY_ENTRY*)
+ ((PCHAR)security_entry + align_num_bytes);
+ }
+ } // while
+ if (attribute_need_write && FixLevel != CheckOnly) {
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ if (!SDS_attrib.Write(initial_security_entry,
+ offset,
+ bytesToRead,
+ &bytesWritten,
+ Mft->GetVolumeBitmap()) ||
+ bytesWritten != bytesToRead) {
+ chkdskErrCouldNotFix = TRUE;
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_SECURITY_DATA_STREAM);
+ Message->Display();
+ } else
+ frs_need_flush = TRUE;
+ }
+ offset += (SecurityDescriptorsBlockSize<<1);
+ remain_length -= bytesToRead;
+ if (remain_length >= SecurityDescriptorsBlockSize)
+ remain_length -= SecurityDescriptorsBlockSize;
+ else
+ remain_length = 0;
+ length = remain_length;
+ } // for
+
+ if (frs_need_flush) {
+ Message->Set(MSG_CHK_NTFS_REPAIRING_SECURITY_FRS);
+ Message->Display();
+ if (FixLevel != CheckOnly &&
+ !security_frs.Flush(Mft->GetVolumeBitmap())) {
+ Message->Set(MSG_CHK_READABLE_FRS_UNWRITEABLE);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+ }
+ } // if
+ } // if
+
+ // now make sure the first copy of the security descriptors in the data
+ // stream matches that in the mirror copy
+
+ FREE(initial_security_entry);
+
+ if (!(initial_security_entry = (PSECURITY_ENTRY)
+ MALLOC(SecurityDescriptorsBlockSize<<1))) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ total_length = SDS_attrib.QueryValueLength().GetLowPart();
+ length = (SecurityDescriptorsBlockSize<<1);
+ fixing_mirror = FALSE;
+ for (offset=0; offset < total_length; offset+=length) {
+ bytesToRead = min(length, total_length-offset);
+ if (!SDS_attrib.Read(initial_security_entry,
+ offset,
+ bytesToRead,
+ &num_bytes) ||
+ num_bytes != bytesToRead) {
+ Message->Set(MSG_CHK_NTFS_CANT_READ_SECURITY_DATA_STREAM);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+ bytesToRead -= SecurityDescriptorsBlockSize;
+ if (memcmp((PVOID)initial_security_entry,
+ (PVOID)((PCHAR)initial_security_entry+
+ SecurityDescriptorsBlockSize),
+ bytesToRead)) {
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_ERRS_FIXED;
+ if (FixLevel != CheckOnly &&
+ (!SDS_attrib.Write(initial_security_entry,
+ offset+SecurityDescriptorsBlockSize,
+ bytesToRead,
+ &bytesWritten,
+ Mft->GetVolumeBitmap()) ||
+ bytesToRead != bytesWritten)) {
+ chkdskErrCouldNotFix = TRUE;
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_SECURITY_DATA_STREAM);
+ Message->Display();
+ } else
+ fixing_mirror = TRUE;
+ }
+ } // for
+ if (fixing_mirror) {
+ Message->Set(MSG_CHK_NTFS_FIXING_SECURITY_DATA_STREAM_MIRROR);
+ Message->Display();
+ if (FixLevel != CheckOnly &&
+ !security_frs.Flush(Mft->GetVolumeBitmap())) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_SECURITY_DATA_STREAM);
+ Message->Display();
+ FREE(initial_security_entry);
+ return FALSE;
+ }
+ }
+
+ FREE(initial_security_entry);
+ } // if (securityDescriptorStreamPresent)
+
+ Message->Set(MSG_CHK_NTFS_SECURITY_VERIFICATION_COMPLETED, PROGRESS_MESSAGE);
+ Message->Display();
+
+ if (chkdskErrCouldNotFix)
+ ChkdskInfo->ExitStatus = CHKDSK_EXIT_COULD_NOT_FIX;
+
+ return TRUE;
+}
+#endif // _SETUP_LOADER_
+
+ULONG
+ComputeSecurityDescriptorHash(
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ IN ULONG Length
+ )
+{
+ ULONG hash = 0;
+ ULONG count = Length / 4;
+ PULONG rover = (PULONG)SecurityDescriptor;
+
+ DebugAssert(rover);
+ if (!rover)
+ return 0;
+
+ while (count--) {
+ hash = ((hash << 3) | (hash >> (32-3))) + *rover++;
+ }
+ return hash;
+}
+
+ULONG
+ComputeDefaultSecurityId(
+ PNUMBER_SET SidSet
+ )
+{
+ BIG_INT start;
+ BIG_INT length;
+
+ if (SidSet->QueryCardinality() == 0)
+ return SECURITY_ID_FIRST;
+
+ SidSet->QueryDisjointRange(0, &start, &length);
+ if (start > SECURITY_ID_FIRST)
+ return SECURITY_ID_FIRST;
+ else {
+ start += length;
+ DebugAssert(start.GetHighPart() == 0);
+ return start.GetLowPart();
+ }
+}
+
+VOID
+ClearSecurityDescriptorEntry(
+ IN OUT PSECURITY_ENTRY Security_entry,
+ IN ULONG SecurityDescriptorSize
+ )
+{
+ Security_entry->security_descriptor_header.Offset =
+ Security_entry->security_descriptor_header.HashKey.Hash = 0;
+ Security_entry->security_descriptor_header.HashKey.SecurityId =
+ SECURITY_ID_INVALID;
+ memset(&(Security_entry->security), 0, SecurityDescriptorSize);
+}
+
+VOID
+MarkEndOfSecurityDescriptorsBlock(
+ IN OUT PSECURITY_ENTRY Security_entry,
+ IN ULONG LengthOfBlock
+ )
+{
+ // zero the length, hash values, and set invalid SID
+ // also zero the rest of the block
+
+ memset(Security_entry, 0, LengthOfBlock);
+ DebugAssert(SECURITY_ID_INVALID == 0);
+}
+
+BOOLEAN
+RemainingBlockIsZero(
+ IN OUT PCHAR Buffer,
+ IN ULONG Size
+ )
+{
+ PCHAR endp;
+
+ endp = Buffer+Size;
+ while (Buffer < endp)
+ if (*Buffer == 0)
+ Buffer++;
+ else
+ return FALSE;
+ return TRUE;
+}
+
+BOOLEAN
+RecoverSecurityDescriptorsDataStream(
+ IN OUT PNTFS_FILE_RECORD_SEGMENT Frs,
+ IN OUT PNTFS_ATTRIBUTE Attrib,
+ IN ULONG AttributeSize,
+ IN PCHAR Buffer,
+ IN ULONG BufferSize,
+ IN ULONG ClusterSize,
+ IN OUT PNTFS_BITMAP Bitmap,
+ OUT PBOOLEAN DiskHasErrors,
+ IN OUT PNUMBER_SET BadClusters,
+ IN OUT PMESSAGE Message,
+ IN BOOLEAN FixLevel
+ )
+/*++
+
+Routine Description:
+
+ This method replaces all those unreadable clusters with readable
+ one. It grabs data from the mirror copy of the stream for those
+ new clusters.
+
+Arguments:
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ PREPAIR_RECORD pRecord;
+ PREPAIR_RECORD pFirstRecord;
+ USHORT recordCount = 0;
+ NUMBER_SET badClusterNumSet;
+ BIG_INT currentBytesRecovered;
+ ULONG bytesToRead;
+ ULONG offset;
+ ULONG length;
+ ULONG num_bytes;
+ BOOLEAN result = TRUE;
+
+ *DiskHasErrors = FALSE;
+
+ if (!badClusterNumSet.Initialize() ||
+ !(pRecord = (PREPAIR_RECORD)MALLOC((SecurityDescriptorsBlockSize/
+ ClusterSize)*sizeof(REPAIR_RECORD)))) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ offset = 0;
+ length = AttributeSize;
+ if (length < SecurityDescriptorsBlockSize) {
+
+ // doesn't matter as the stream will be zapped
+
+ FREE(pRecord);
+ if (FixLevel != CheckOnly) {
+
+ // no need to say disk has errors as its length is invalid anyway
+
+ result = Attrib->RecoverAttribute(Bitmap,
+ &badClusterNumSet,
+ &currentBytesRecovered);
+ } else {
+ FREE(pRecord);
+ return TRUE;
+ }
+ } else {
+
+ length -= SecurityDescriptorsBlockSize;
+
+ while (length > 0) {
+ bytesToRead = min(length, BufferSize);
+
+ if (!Attrib->Read(Buffer,
+ offset,
+ bytesToRead,
+ &num_bytes)) {
+ RepairSecurityDescriptorsSegment(Attrib,
+ Buffer,
+ offset,
+ bytesToRead,
+ pRecord,
+ &recordCount,
+ ClusterSize);
+ *DiskHasErrors = TRUE;
+ }
+ offset += (SecurityDescriptorsBlockSize<<1);
+ length -= bytesToRead;
+ if (length > SecurityDescriptorsBlockSize)
+ length -= SecurityDescriptorsBlockSize;
+ else
+ length = 0;
+ }
+
+ if (*DiskHasErrors) {
+ Message->Set(MSG_CHK_NTFS_REPAIRING_UNREADABLE_SECURITY_DATA_STREAM);
+ Message->Display();
+ } else {
+ FREE(pRecord);
+ return TRUE;
+ }
+
+ if (FixLevel == CheckOnly) {
+ FREE(pRecord);
+ return TRUE;
+ }
+ if (Attrib->RecoverAttribute(Bitmap,
+ &badClusterNumSet,
+ &currentBytesRecovered)) {
+ pFirstRecord = pRecord;
+ while (recordCount-- > 0) {
+ offset = pFirstRecord->Offset;
+ bytesToRead = pFirstRecord->Length;
+ pFirstRecord++;
+ if (Attrib->Read(Buffer,
+ offset+SecurityDescriptorsBlockSize,
+ bytesToRead,
+ &num_bytes) &&
+ num_bytes == bytesToRead) {
+ if (!Attrib->Write(Buffer,
+ offset,
+ bytesToRead,
+ &num_bytes,
+ NULL) ||
+ num_bytes != bytesToRead) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_SECURITY_DATA_STREAM);
+ Message->Display();
+ result = FALSE;
+ break;
+ }
+ } else {
+ Message->Set(MSG_CHK_NTFS_CANT_READ_SECURITY_DATA_STREAM);
+ Message->Display();
+ result = FALSE;
+ break;
+ }
+ } // while
+ } else {
+ result = FALSE;
+ }
+ }
+
+ if (result && Attrib->IsStorageModified() &&
+ !Attrib->InsertIntoFile(Frs, Bitmap)) {
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_ATTRIBUTE);
+ Message->Display("%d%d", $DATA, Frs->QueryFileNumber().GetLowPart());
+ result = FALSE;
+ }
+
+ if (!BadClusters->Add(&badClusterNumSet)) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ result = FALSE;
+ }
+
+ FREE(pRecord);
+ return result;
+}
+
+BOOLEAN
+RepairSecurityDescriptorsSegment(
+ IN OUT PNTFS_ATTRIBUTE Attrib,
+ IN PCHAR Buffer,
+ IN ULONG Offset,
+ IN ULONG BytesToProcess,
+ IN OUT PREPAIR_RECORD Record,
+ IN OUT USHORT *RecordCount,
+ IN ULONG ClusterSize
+ )
+/*++
+
+Routine Description:
+
+ This method identifies all those records that can be fixed up
+ by reading the data out from the mirror copy.
+
+Arguments:
+
+Return Value:
+
+ TRUE if all unreadable records can be recovered with no loss of data.
+ FALSE if not all unreadable records can be recovered with no loss of data.
+
+--*/
+{
+ ULONG bytesToRead;
+ ULONG num_bytes;
+ BOOLEAN completeRecovery = TRUE;
+
+ bytesToRead = BytesToProcess/2;
+
+ if (!Attrib->Read(Buffer,
+ Offset,
+ bytesToRead,
+ &num_bytes) ||
+ bytesToRead != num_bytes) {
+ if (!Attrib->Read(Buffer,
+ Offset+SecurityDescriptorsBlockSize,
+ bytesToRead,
+ &num_bytes)) {
+ if (bytesToRead > ClusterSize) {
+ completeRecovery =
+ completeRecovery &&
+ RepairSecurityDescriptorsSegment(Attrib,
+ Buffer,
+ Offset,
+ bytesToRead,
+ Record,
+ RecordCount,
+ ClusterSize);
+ } else
+ return FALSE;
+ } else {
+ Record[*RecordCount].Offset = Offset;
+ Record[(*RecordCount)++].Length = bytesToRead;
+ }
+ }
+
+ bytesToRead = BytesToProcess-bytesToRead;
+
+ if (!Attrib->Read(Buffer,
+ Offset+bytesToRead,
+ bytesToRead,
+ &num_bytes) ||
+ bytesToRead != num_bytes) {
+ if (!Attrib->Read(Buffer,
+ Offset+bytesToRead+SecurityDescriptorsBlockSize,
+ bytesToRead,
+ &num_bytes)) {
+ if (bytesToRead > ClusterSize) {
+ completeRecovery =
+ completeRecovery &&
+ RepairSecurityDescriptorsSegment(Attrib,
+ Buffer,
+ Offset+bytesToRead,
+ bytesToRead,
+ Record,
+ RecordCount,
+ ClusterSize);
+ } else
+ return FALSE;
+ } else {
+ Record[*RecordCount].Offset = Offset + bytesToRead;
+ Record[(*RecordCount)++].Length = bytesToRead;
+ }
+ }
+ return completeRecovery;
+}
+
diff --git a/private/utils/untfs/src/sources b/private/utils/untfs/src/sources
new file mode 100644
index 000000000..d049af35a
--- /dev/null
+++ b/private/utils/untfs/src/sources
@@ -0,0 +1,101 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in $(BASEDIR)\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=utils
+MINORCOMP=ulib
+
+TARGETNAME=untfs
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+
+TARGETLIBS=$(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ ..\..\ulib\src\obj\*\ulib.lib \
+ ..\..\ifsutil\src\obj\*\ifsutil.lib
+
+USE_CRTDLL=1
+BLDCRT=1
+
+DLLENTRY=InitializeUntfs
+
+PRECOMPILED_INCLUDE= pch.cxx
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES= attrcol.cxx \
+ attrdef.cxx \
+ attrib.cxx \
+ attrlist.cxx \
+ attrrec.cxx \
+ badfile.cxx \
+ bitfrs.cxx \
+ bootfile.cxx \
+ clusrun.cxx \
+ entry.cxx \
+ extents.cxx \
+ format.cxx \
+ frs.cxx \
+ frsstruc.cxx \
+ hackwc.cxx \
+ indxbuff.cxx \
+ indxchk.cxx \
+ indxroot.cxx \
+ indxtree.cxx \
+ largemcb.c \
+ logfile.cxx \
+ mft.cxx \
+ mftfile.cxx \
+ mftref.cxx \
+ ntfsbit.cxx \
+ ntfschk.cxx \
+ ntfssa.cxx \
+ ntfsvol.cxx \
+ sdchk.cxx \
+ untfs.cxx \
+ upcase.cxx \
+ upfile.cxx \
+ untfs.rc
+
+INCLUDES=..\inc;..\..\ulib\inc;..\..\ifsutil\inc;$(BASEDIR)\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+CXXFLAGS=+d
+UMLIBS=obj\*\untfs.lib
+
+UMTYPE=console
+UMRES=obj\*\untfs.res
+
+DLLDEF=untfs.def
diff --git a/private/utils/untfs/src/untfs.cxx b/private/utils/untfs/src/untfs.cxx
new file mode 100644
index 000000000..3828668e4
--- /dev/null
+++ b/private/utils/untfs/src/untfs.cxx
@@ -0,0 +1,175 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ untfs.cxx
+
+Abstract:
+
+ This module contains run-time, global support for the
+ NTFS IFS Utilities library (UNTFS). This support includes:
+
+ - creation of CLASS_DESCRIPTORs
+ - Global objects
+
+Author:
+
+ Bill McJohn (billmc) 15-Aug-1991
+
+Environment:
+
+ User Mode
+
+Notes:
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "untfs.hxx"
+
+
+#if !defined( _AUTOCHECK_ ) && !defined( _SETUP_LOADER_ )
+
+ ERRSTACK* perrstk;
+
+#endif // _AUTOCHECK_ || _SETUP_LOADER_
+
+
+// Local prototypes
+
+STATIC
+BOOLEAN
+DefineClassDescriptors(
+ );
+
+
+extern "C"
+BOOLEAN
+InitializeUntfs (
+ IN PVOID DllHandle,
+ IN ULONG Reason,
+ IN PCONTEXT Context
+ );
+
+BOOLEAN
+InitializeUntfs (
+ IN PVOID DllHandle,
+ IN ULONG Reason,
+ IN PCONTEXT Context
+ )
+/*++
+
+Routine Description:
+
+ Initialize Untfs by constructing and initializing all
+ global objects. These include:
+
+ - all CLASS_DESCRIPTORs (class_cd)
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if all global objects were succesfully constructed
+ and initialized.
+
+--*/
+
+{
+
+ STATIC BOOLEAN fInit = FALSE;
+
+ if ( fInit ) {
+
+ return( TRUE );
+ }
+
+ if ( DefineClassDescriptors() ) {
+
+ fInit = TRUE;
+ return TRUE;
+
+ } else {
+
+ DebugAbort( "Untfs initialization failed!!!\n" );
+ return( FALSE );
+ }
+}
+
+
+
+DECLARE_CLASS( NTFS_ATTRIBUTE );
+DECLARE_CLASS( NTFS_ATTRIBUTE_COLUMNS );
+DECLARE_CLASS( NTFS_ATTRIBUTE_DEFINITION_TABLE );
+DECLARE_CLASS( NTFS_ATTRIBUTE_LIST );
+DECLARE_CLASS( NTFS_ATTRIBUTE_RECORD );
+DECLARE_CLASS( NTFS_BAD_CLUSTER_FILE );
+DECLARE_CLASS( NTFS_BITMAP_FILE );
+DECLARE_CLASS( NTFS_BOOT_FILE );
+DECLARE_CLASS( NTFS_CLUSTER_RUN );
+DECLARE_CLASS( NTFS_EXTENT );
+DECLARE_CLASS( NTFS_EXTENT_LIST );
+DECLARE_CLASS( NTFS_FILE_RECORD_SEGMENT );
+DECLARE_CLASS( NTFS_FRS_STRUCTURE );
+DECLARE_CLASS( NTFS_INDEX_BUFFER );
+DECLARE_CLASS( NTFS_INDEX_ROOT );
+DECLARE_CLASS( NTFS_INDEX_TREE );
+DECLARE_CLASS( NTFS_LOG_FILE );
+DECLARE_CLASS( NTFS_MASTER_FILE_TABLE );
+DECLARE_CLASS( NTFS_MFT_FILE );
+DECLARE_CLASS( NTFS_REFLECTED_MASTER_FILE_TABLE );
+DECLARE_CLASS( NTFS_BITMAP );
+DECLARE_CLASS( NTFS_UPCASE_FILE );
+DECLARE_CLASS( NTFS_UPCASE_TABLE );
+DECLARE_CLASS( NTFS_VOL );
+DECLARE_CLASS( NTFS_SA );
+
+STATIC
+BOOLEAN
+DefineClassDescriptors(
+ )
+{
+ if( DEFINE_CLASS_DESCRIPTOR( NTFS_ATTRIBUTE_DEFINITION_TABLE ) &&
+ DEFINE_CLASS_DESCRIPTOR( NTFS_ATTRIBUTE ) &&
+ DEFINE_CLASS_DESCRIPTOR( NTFS_ATTRIBUTE_COLUMNS ) &&
+ DEFINE_CLASS_DESCRIPTOR( NTFS_ATTRIBUTE_LIST ) &&
+ DEFINE_CLASS_DESCRIPTOR( NTFS_ATTRIBUTE_RECORD ) &&
+ DEFINE_CLASS_DESCRIPTOR( NTFS_BAD_CLUSTER_FILE ) &&
+ DEFINE_CLASS_DESCRIPTOR( NTFS_BITMAP_FILE ) &&
+ DEFINE_CLASS_DESCRIPTOR( NTFS_BOOT_FILE ) &&
+ DEFINE_CLASS_DESCRIPTOR( NTFS_CLUSTER_RUN ) &&
+ DEFINE_CLASS_DESCRIPTOR( NTFS_EXTENT ) &&
+ DEFINE_CLASS_DESCRIPTOR( NTFS_EXTENT_LIST ) &&
+ DEFINE_CLASS_DESCRIPTOR( NTFS_FILE_RECORD_SEGMENT ) &&
+ DEFINE_CLASS_DESCRIPTOR( NTFS_FRS_STRUCTURE ) &&
+ DEFINE_CLASS_DESCRIPTOR( NTFS_INDEX_BUFFER ) &&
+ DEFINE_CLASS_DESCRIPTOR( NTFS_INDEX_ROOT ) &&
+ DEFINE_CLASS_DESCRIPTOR( NTFS_INDEX_TREE ) &&
+ DEFINE_CLASS_DESCRIPTOR( NTFS_LOG_FILE ) &&
+ DEFINE_CLASS_DESCRIPTOR( NTFS_MASTER_FILE_TABLE ) &&
+ DEFINE_CLASS_DESCRIPTOR( NTFS_MFT_FILE ) &&
+ DEFINE_CLASS_DESCRIPTOR( NTFS_REFLECTED_MASTER_FILE_TABLE ) &&
+ DEFINE_CLASS_DESCRIPTOR( NTFS_UPCASE_FILE ) &&
+ DEFINE_CLASS_DESCRIPTOR( NTFS_UPCASE_TABLE ) &&
+ DEFINE_CLASS_DESCRIPTOR( NTFS_VOL ) &&
+ DEFINE_CLASS_DESCRIPTOR( NTFS_SA ) &&
+ DEFINE_CLASS_DESCRIPTOR( NTFS_BITMAP ) ) {
+
+ return TRUE;
+
+ } else {
+
+ DebugPrint( "Could not initialize class descriptors!");
+ return FALSE;
+ }
+}
diff --git a/private/utils/untfs/src/untfs.def b/private/utils/untfs/src/untfs.def
new file mode 100644
index 000000000..3d894c43f
--- /dev/null
+++ b/private/utils/untfs/src/untfs.def
@@ -0,0 +1,12 @@
+LIBRARY UNTFS
+
+DESCRIPTION File System Utilities for NTFS
+
+DATA NONSHARED
+
+EXPORTS
+ Chkdsk
+ Format
+ Recover
+ Extend
+ InitializeUntfs
diff --git a/private/utils/untfs/src/untfs.rc b/private/utils/untfs/src/untfs.rc
new file mode 100644
index 000000000..160b9338c
--- /dev/null
+++ b/private/utils/untfs/src/untfs.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "NTFS Utility DLL"
+#define VER_INTERNALNAME_STR "UNTFS"
+#define VER_ORIGINALFILENAME_STR "UNTFS.DLL"
+
+#include "common.ver"
diff --git a/private/utils/untfs/src/upcase.cxx b/private/utils/untfs/src/upcase.cxx
new file mode 100644
index 000000000..60cbd9eb9
--- /dev/null
+++ b/private/utils/untfs/src/upcase.cxx
@@ -0,0 +1,469 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ upcase.cxx
+
+Abstract:
+
+ This module contains the member function definitions for the
+ NTFS_UPCASE_TABLE class. This class models the upcase table
+ stored on an NTFS volume, which is used to upper-case characters
+ in attribute and file names for comparison.
+
+Author:
+
+ Bill McJohn (billmc) 04-March-92
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "untfs.hxx"
+
+#include "attrib.hxx"
+#include "ntfsbit.hxx"
+#include "upcase.hxx"
+
+extern "C" {
+#include <ctype.h>
+}
+
+
+DEFINE_EXPORTED_CONSTRUCTOR( NTFS_UPCASE_TABLE, OBJECT, UNTFS_EXPORT );
+
+UNTFS_EXPORT
+NTFS_UPCASE_TABLE::~NTFS_UPCASE_TABLE(
+ )
+/*++
+
+Routine Description:
+
+ This method is the destructor for the class.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+NTFS_UPCASE_TABLE::Construct(
+ )
+/*++
+
+routine Description:
+
+ This method is the helper function for object construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _Data = NULL;
+ _Length = 0;
+}
+
+VOID
+NTFS_UPCASE_TABLE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ This method cleans up the object in preparation for destruction
+ or reinitialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ FREE( _Data );
+ _Length = 0;
+}
+
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_UPCASE_TABLE::Initialize(
+ IN PNTFS_ATTRIBUTE Attribute
+ )
+/*++
+
+Routine Description:
+
+ This method initializes the object based on the value of
+ an NTFS Attribute.
+
+Arguments:
+
+ Attribute -- Supplies the attribute whose value is the
+ upcase table.
+
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ ULONG BytesInValue, BytesRead;
+
+
+ DebugPtrAssert( Attribute );
+
+ Destroy();
+
+ // Perform validity checks on the attribute; it must be
+ // small enough that the length fits in a ULONG, and
+ // its length must be a multiple of sizeof(WCHAR).
+
+ if( Attribute->QueryValueLength().GetHighPart() != 0 ) {
+
+ DebugAbort( "Upcase table is impossibly large.\n" );
+ return FALSE;
+ }
+
+ BytesInValue = Attribute->QueryValueLength().GetLowPart();
+
+ if( BytesInValue % sizeof(WCHAR) != 0 ) {
+
+ DebugAbort( "Upcase table is an odd number of bytes.\n" );
+ return FALSE;
+ }
+
+ // Allocate the buffer for the upcase data and read the attribute
+ // value into it.
+
+ if( (_Data = (PWCHAR)MALLOC( BytesInValue )) == NULL ||
+ !Attribute->Read( _Data,
+ 0,
+ BytesInValue,
+ &BytesRead ) ||
+ BytesRead != BytesInValue ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ // _Length is the number of WCHAR's in the table.
+
+ _Length = BytesInValue / sizeof(WCHAR);
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_UPCASE_TABLE::Initialize(
+ IN PWCHAR Data,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This method initializes the upcase table based on client-supplied
+ data.
+
+Arguments:
+
+ Data -- Supplies the data for the table.
+ Length -- Supplies the number of WCHAR's in the table.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ Destroy();
+
+ if( (_Data = (PWCHAR)MALLOC( Length * sizeof(WCHAR) )) == NULL ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ memcpy( _Data, Data, Length * sizeof(WCHAR) );
+
+ _Length = Length;
+
+ return TRUE;
+}
+
+
+
+BOOLEAN
+NTFS_UPCASE_TABLE::Initialize(
+ )
+/*++
+
+Routine Description:
+
+ This method initializes the upcase table based on system defaults.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ CONST ULONG MaximumChunkLength = 16 * 1024;
+ WCHAR w;
+ ULONG i, ChunkLength;
+ UNICODE_STRING UpcaseMe;
+ NTSTATUS Status;
+
+ _Length = QueryDefaultLength();
+
+ if( (_Data = (PWCHAR)MALLOC( _Length * sizeof(WCHAR) )) == NULL ) {
+
+ Destroy();
+ return FALSE;
+ }
+
+ // First, set the table up as an identity transformation:
+ //
+ for( i = 0; i < _Length; i++ ) {
+
+ _Data[i] = (WCHAR)i;
+ }
+
+ // Now call RtlUpcaseUnicodeString on successive chunks
+ // of the buffer.
+ //
+ ChunkLength = MaximumChunkLength;
+
+ for( i = 0; i < _Length; i += ChunkLength ) {
+
+ if( i + ChunkLength > _Length ) {
+
+ ChunkLength = (ULONG)(_Length - i);
+ }
+
+ UpcaseMe.Length = sizeof(WCHAR) * ChunkLength;
+ UpcaseMe.MaximumLength = sizeof(WCHAR) * ChunkLength;
+ UpcaseMe.Buffer = _Data + i;
+
+ Status = RtlUpcaseUnicodeString( &UpcaseMe,
+ &UpcaseMe,
+ FALSE );
+
+ if( !NT_SUCCESS(Status) ) {
+
+ DebugPrintf( "UNTFS: RtlUpcaseUnicodeString failed - status 0x%x\n", Status );
+ Destroy();
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+NTFS_UPCASE_TABLE::Verify(
+ ) CONST
+/*++
+
+Routine Description:
+
+ This routine ensures that the first 128 entries of this
+ table are compliant with the ANSI character set.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE - This table is not valid.
+ TRUE - This table is valid.
+
+--*/
+{
+ WCHAR i;
+
+ if (_Length < 128) {
+ return FALSE;
+ }
+
+ for (i = 0; i < 128; i++) {
+ if (_Data[i] != toupper(i)) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+LONG
+UNTFS_EXPORT
+NtfsUpcaseCompare(
+ IN PCWSTR LeftName,
+ IN ULONG LeftNameLength,
+ IN PCWSTR RightName,
+ IN ULONG RightNameLength,
+ IN PCNTFS_UPCASE_TABLE UpcaseTable,
+ IN BOOLEAN CaseSensitive
+ )
+/*++
+
+Routine Description:
+
+ This function compares two NTFS names.
+
+Arguments:
+
+ LeftName -- Supplies the left-hand operand of the comparison.
+ LeftNameLength -- Supplies the length in characters of LeftName.
+ RightName -- Supplies the Right-hand operand of the comparison.
+ RightNameLength -- Supplies the length in characters of RightName.
+ UpcaseTable -- Supplies the volume upcase table.
+ CaseSensitive -- Supplies a flag which, if TRUE, indicates that
+ the comparison is case-sensitive.
+
+Return Value:
+
+ <0 if LeftName is less than RightName.
+ 0 if the names are equal.
+ >0 if LeftName is greater than RightName.
+
+Notes:
+
+ UpcaseTable may be NULL if either or both names are zero-length,
+ or if the names are exactly identical. Otherwise, it must point
+ at an initialized Upcase Table object.
+
+ If the comparison is case-sensitive, then the names are first
+ compared case-insensitive. If that comparison evaluates to equality,
+ then they are compared case-sensitive. Attribute names and
+ non-DOS, non-NTFS file names are compared case-sensitive.
+
+--*/
+{
+ ULONG ShorterLength, i;
+ LONG Result;
+
+ // First, if both names have zero length, then they're equal.
+ //
+ if( LeftNameLength == 0 && RightNameLength == 0 ) {
+
+ return 0;
+ }
+
+ // At least one has a non-zero-length name. If the other has
+ // a zero-length name, it's the lesser of the two.
+ //
+ if( LeftNameLength == 0 ) {
+
+ return -1;
+ }
+
+ if( RightNameLength == 0 ) {
+
+ return 1;
+ }
+
+ // Both have non-zero length names. If they have the same length,
+ // do a quick memcmp to see if they're identical.
+ //
+ if( LeftNameLength == RightNameLength &&
+ memcmp( LeftName, RightName, LeftNameLength * sizeof(WCHAR) ) == 0 ) {
+
+ return 0;
+ }
+
+ // Perform case-insensitive comparison. This requires
+ // UpcaseTable to be valid.
+ //
+ DebugPtrAssert( UpcaseTable );
+
+ ShorterLength = MIN( LeftNameLength, RightNameLength );
+
+ for( i = 0; i < ShorterLength; i++ ) {
+
+ Result = UpcaseTable->UpperCase( LeftName[i] ) -
+ UpcaseTable->UpperCase( RightName[i] );
+
+ if( Result != 0 ) {
+
+ return Result;
+ }
+ }
+
+ // The names are case-insensitive equal for the length of
+ // the shorter name; if they are of different lengths, the
+ // shorter is the lesser.
+ //
+ Result = LeftNameLength - RightNameLength;
+
+ if( Result != 0 ) {
+
+ return Result;
+ }
+
+ // The names are equal except for case. If this is an
+ // case-sensitive comparison, perform a final comparison;
+ // otherwise, they're equal.
+ //
+ if( !CaseSensitive ) {
+
+ return 0;
+
+ } else {
+
+ // We already know they're of the same length.
+ //
+ for( i = 0; i < LeftNameLength; i++ ) {
+
+ Result = LeftName[i] - RightName[i];
+
+ if( Result != 0 ) {
+
+ return Result;
+ }
+ }
+
+ return 0;
+ }
+}
diff --git a/private/utils/untfs/src/upfile.cxx b/private/utils/untfs/src/upfile.cxx
new file mode 100644
index 000000000..2daff88df
--- /dev/null
+++ b/private/utils/untfs/src/upfile.cxx
@@ -0,0 +1,328 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ upfile.cxx
+
+Abstract:
+
+ This module contains the declarations for the NTFS_UPCASE_FILE
+ class, which models the upcase-table file for an NTFS volume.
+ This class' main purpose in life is to encapsulate the creation
+ of this file.
+
+Author:
+
+ Bill McJohn (billmc) 04-March-1992
+
+Environment:
+
+ ULIB, User Mode
+
+--*/
+
+#include <pch.cxx>
+
+#define _NTAPI_ULIB_
+#define _UNTFS_MEMBER_
+
+#include "ulib.hxx"
+#include "error.hxx"
+#include "untfs.hxx"
+
+#include "ntfsbit.hxx"
+#include "drive.hxx"
+#include "attrib.hxx"
+#include "bitfrs.hxx"
+#include "upfile.hxx"
+#include "upcase.hxx"
+#include "message.hxx"
+#include "rtmsg.h"
+
+DEFINE_EXPORTED_CONSTRUCTOR( NTFS_UPCASE_FILE,
+ NTFS_FILE_RECORD_SEGMENT,
+ UNTFS_EXPORT );
+
+UNTFS_EXPORT
+NTFS_UPCASE_FILE::~NTFS_UPCASE_FILE(
+ )
+{
+ Destroy();
+}
+
+
+VOID
+NTFS_UPCASE_FILE::Construct(
+ )
+/*++
+
+Routine Description:
+
+ Worker function for the construtor.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+}
+
+
+VOID
+NTFS_UPCASE_FILE::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Clean up an NTFS_UPCASE_FILE object in preparation for
+ destruction or reinitialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+}
+
+
+
+UNTFS_EXPORT
+BOOLEAN
+NTFS_UPCASE_FILE::Initialize(
+ IN OUT PNTFS_MASTER_FILE_TABLE Mft
+ )
+/*++
+
+Routine Description:
+
+ This method initializes an Upcase File object. The only special
+ knowledge that it adds to the File Record Segment initialization
+ is the location within the Master File Table of the Upcase table
+ file.
+
+Arguments:
+
+ Mft -- Supplies the volume MasterFile Table.
+ UpcaseTable -- Supplies the volume upcase table.
+
+Return Value:
+
+ TRUE upon successful completion
+
+Notes:
+
+ This class is reinitializable.
+
+
+--*/
+{
+ Destroy();
+
+ return( NTFS_FILE_RECORD_SEGMENT::Initialize( UPCASE_TABLE_NUMBER,
+ Mft ) );
+}
+
+
+BOOLEAN
+NTFS_UPCASE_FILE::Create(
+ IN PCSTANDARD_INFORMATION StandardInformation,
+ IN PNTFS_UPCASE_TABLE UpcaseTable,
+ IN OUT PNTFS_BITMAP VolumeBitmap
+ )
+/*++
+
+Routine Description:
+
+ This method formats an Upcase-File File Record
+ Segment in memory (without writing it to disk).
+
+ It creates a DATA attribute to hold the volume's upcase
+ table and writes the table to disk through that attribute.
+
+Arguments:
+
+ StandardInformation -- Supplies the standard information for the
+ file record segment.
+ UpcaseTable -- Supplies the volume's upcase table.
+ VolumeBitmap -- Supplies the volume bitmap
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ NTFS_ATTRIBUTE DataAttribute;
+ NTFS_EXTENT_LIST Extents;
+
+
+ // Set this object up as a File Record Segment.
+
+ if( !NTFS_FILE_RECORD_SEGMENT::Create( StandardInformation ) ) {
+
+ return FALSE;
+ }
+
+ // Create an unnamed data attribute, write the upcase table out
+ // through that attribute, and save the attribute to this file.
+ //
+ if( !Extents.Initialize( 0, 0 ) ||
+ !DataAttribute.Initialize( GetDrive(),
+ QueryClusterFactor(),
+ &Extents,
+ 0,
+ 0,
+ $DATA,
+ NULL ) ||
+ !UpcaseTable->Write( &DataAttribute, VolumeBitmap ) ||
+ !DataAttribute.InsertIntoFile( this, VolumeBitmap ) ) {
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+NTFS_UPCASE_FILE::VerifyAndFix(
+ IN OUT PNTFS_UPCASE_TABLE UpcaseTable,
+ IN OUT PNTFS_BITMAP VolumeBitmap,
+ IN OUT PNUMBER_SET BadClusterList,
+ IN OUT PNTFS_INDEX_TREE RootIndex,
+ IN FIX_LEVEL FixLevel,
+ IN OUT PMESSAGE Message
+ )
+/*++
+
+Routine Description:
+
+ This routine compares the given attribute definition table with
+ the one contained in this file's DATA attribute and ensures
+ that both are the same. The in-memory version will override the
+ on-disk version.
+
+Arguments:
+
+ UpcaseTable - Supplies the in-memory version of the table.
+ VolumeBitmap - Supplies the volume bitmap.
+ BadClusterList - Supplies the list of bad clusters.
+ RootIndex - Supplies the root index.
+ FixLevel - Supplies the fix up level.
+ Message - Supplies an outlet for messages.
+
+Return Value:
+
+ FALSE - Failure.
+ TRUE - Success.
+
+--*/
+{
+ NTFS_ATTRIBUTE data_attribute;
+ BOOLEAN errors;
+ PCWCHAR mem_upcase;
+ PWCHAR disk_upcase;
+ ULONG num_char;
+ NTFS_EXTENT_LIST extent_list;
+ BOOLEAN ErrorInAttribute;
+ ULONG value_length;
+ ULONG num_bytes;
+
+ errors = FALSE;
+
+ mem_upcase = UpcaseTable->GetUpcaseArray(&num_char);
+
+ if (!(disk_upcase = NEW WCHAR[num_char])) {
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!QueryAttribute(&data_attribute, &ErrorInAttribute, $DATA)) {
+
+ if (!extent_list.Initialize(0, 0)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+
+ if (!data_attribute.Initialize(GetDrive(),
+ QueryClusterFactor(),
+ &extent_list,
+ 0,
+ 0,
+ $DATA)) {
+
+ Message->Set(MSG_CHK_NO_MEMORY);
+ Message->Display();
+ return FALSE;
+ }
+ }
+
+ value_length = num_char*sizeof(WCHAR);
+
+ if (value_length != data_attribute.QueryValueLength() ||
+ !data_attribute.Read(disk_upcase, 0, value_length, &num_bytes) ||
+ num_bytes != value_length ||
+ memcmp(mem_upcase, disk_upcase, value_length)) {
+
+ if (!errors) {
+ Message->Set(MSG_CHK_NTFS_CORRECTING_UPCASE_FILE);
+ Message->Display();
+ errors = TRUE;
+ }
+
+ if (FixLevel != CheckOnly) {
+ if (!data_attribute.MakeNonresident(VolumeBitmap) ||
+ !data_attribute.Resize(value_length, VolumeBitmap) ||
+ !data_attribute.Write(mem_upcase, 0, value_length, &num_bytes,
+ VolumeBitmap) ||
+ num_bytes != value_length) {
+
+ if (!data_attribute.RecoverAttribute(VolumeBitmap, BadClusterList) ||
+ !data_attribute.Write(mem_upcase, 0, value_length,
+ &num_bytes, VolumeBitmap) ||
+ num_bytes != value_length) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_UPCASE_FILE);
+ Message->Display();
+ DELETE(disk_upcase);
+ return FALSE;
+ }
+ }
+ }
+
+ if (!data_attribute.InsertIntoFile(this, VolumeBitmap)) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_UPCASE_FILE);
+ Message->Display();
+ DELETE(disk_upcase);
+ return FALSE;
+ }
+ }
+
+ if (FixLevel != CheckOnly && !Flush(VolumeBitmap, RootIndex)) {
+
+ Message->Set(MSG_CHK_NTFS_CANT_FIX_UPCASE_FILE);
+ Message->Display();
+ DELETE(disk_upcase);
+ return FALSE;
+ }
+
+ DELETE(disk_upcase);
+
+ return TRUE;
+}
diff --git a/private/utils/ureg/dirs b/private/utils/ureg/dirs
new file mode 100644
index 000000000..c4db5a979
--- /dev/null
+++ b/private/utils/ureg/dirs
@@ -0,0 +1,16 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+!ENDIF
+
+DIRS= src
diff --git a/private/utils/ureg/inc/registry.hxx b/private/utils/ureg/inc/registry.hxx
new file mode 100644
index 000000000..0eb075cbd
--- /dev/null
+++ b/private/utils/ureg/inc/registry.hxx
@@ -0,0 +1,677 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ registry.hxx
+
+Abstract:
+
+ This module contains the declarations for the REGISTRY class.
+ REGISTRY is class that provides methods for an application to
+ access the registry of a particular machine.
+
+
+Author:
+
+ Jaime Sasson (jaimes) 01-Mar-1992
+
+
+Environment:
+
+ Ulib, User Mode
+
+
+--*/
+
+
+#if !defined( _REGISTRY_ )
+
+#define _REGISTRY_
+
+
+#include "ulib.hxx"
+#include "array.hxx"
+#include "regkey.hxx"
+#include "regvalue.hxx"
+#include "sortlit.hxx"
+
+#if !defined( _AUTOCHECK_ )
+#include "winreg.h"
+#endif
+
+//
+// The enumeration below is used to access the array of open handles
+// of the registry
+//
+
+typedef enum _PREDEFINED_KEY {
+ PREDEFINED_KEY_CLASSES_ROOT,
+ PREDEFINED_KEY_CURRENT_USER,
+ PREDEFINED_KEY_LOCAL_MACHINE,
+ PREDEFINED_KEY_USERS,
+ PREDEFINED_KEY_CURRENT_CONFIG
+ } PREDEFINED_KEY;
+
+
+#define NUMBER_OF_PREDEFINED_KEYS 5
+
+//
+// The enumeration below contains the error codes that the methods in
+// the REGISTRY class can return
+//
+
+typedef enum _REGISTRY_ERROR {
+#if !defined( _AUTOCHECK_ )
+ REGISTRY_ERROR_BADDB, // Maps ERROR_BADDB
+ REGISTRY_ERROR_ACCESS_DENIED, // Maps ERROR_ACCESS_DENIED
+ REGISTRY_ERROR_CANTOPEN, // Maps ERROR_CANT_OPEN
+ REGISTRY_ERROR_CANTREAD, // Maps ERROR_CANT_READ
+ REGISTRY_ERROR_INVALID_PARAMETER, // Maps ERROR_INVALID_PARAMETER
+ REGISTRY_ERROR_OUTOFMEMORY, // Maps ERROR_OUT_OF_MEMORY
+#endif
+ REGISTRY_ERROR_INITIALIZATION_FAILURE,
+ REGISTRY_ERROR_KEY_DOESNT_EXIST,
+ REGISTRY_ERROR_VALUE_EXISTS,
+ REGISTRY_ERROR_VALUE_DOESNT_EXIST,
+ REGISTRY_ERROR_KEY_INFO_NOT_UPDATED,
+ REGISTRY_ERROR_UNKNOWN_ERROR,
+ REGISTRY_ERROR_PRIVILEGE_NOT_HELD, // Maps ERROR_PRIVILEGE_NOT_HELD
+ REGISTRY_RPC_S_SERVER_UNAVAILABLE, // Maps RPC_S_SERVER_UNAVAILABLE
+ REGISTRY_ERROR_KEY_DELETED, // Maps ERROR_KEY_DELETED
+ REGISTRY_ERROR_KEY_NOT_FOUND, // Maps ERROR_FILE_NOT_FOUND
+ REGISTRY_ERROR_CHILD_MUST_BE_VOLATILE // Maps ERROR_CHILD_MUST_BE_VOLATILE
+ } REGISTRY_ERROR;
+
+
+
+
+DECLARE_CLASS( REGISTRY );
+
+
+class REGISTRY : public OBJECT {
+
+
+
+ public:
+
+ DECLARE_CONSTRUCTOR( REGISTRY );
+
+ DECLARE_CAST_MEMBER_FUNCTION( REGISTRY );
+
+ VIRTUAL
+ ~REGISTRY(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PCWSTRING MachineName DEFAULT NULL,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AddValueEntry(
+ IN PREDEFINED_KEY Predefinedkey,
+ IN PCWSTRING ParentKeyName,
+ IN PCWSTRING KeyName,
+ IN PCREGISTRY_VALUE_ENTRY Value,
+ IN BOOLEAN FailIfExists DEFAULT FALSE,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AddValueEntry(
+ IN PREDEFINED_KEY Predefinedkey,
+ IN OUT PREGISTRY_KEY_INFO KeyInfo,
+ IN PCREGISTRY_VALUE_ENTRY Value,
+ IN BOOLEAN FailIfExists DEFAULT FALSE,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+#if 0 // NOT_IMPLEMENTED
+
+ NONVIRTUAL
+ BOOLEAN // The key copied will be a subkey
+ CopyKey( // of ToParentName
+ IN PREDEFINED_KEY FromPredefinedKey,
+ IN PCWSTRING FromParentName,
+ IN PCWSTRING FromKeyName,
+ IN PREDEFINED_KEY ToPredefinedKey,
+ IN PCWSTRING ToParentName,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN // The key copied will be a subkey
+ CopyKey( // of ToParentKey
+ IN PREDEFINED_KEY FromPredefinedKey,
+ IN PCWSTRING FromParentName,
+ IN PCWSTRING FromKeyName,
+ IN PREDEFINED_KEY ToPredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO ToParentKeyInfo,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CopyAllValueEntries(
+ IN PREDEFINED_KEY FromPredefinedKey,
+ IN PCWSTRING FromParentName,
+ IN PCWSTRING FromKeyName,
+ IN PREDEFINED_KEY ToPredefinedKey,
+ IN PCWSTRING ToParentName,
+ IN PCWSTRING ToKeyName,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CopyAllValueEntries(
+ IN PREDEFINED_KEY FromPredefinedKey,
+ IN PCWSTRING FromParentName,
+ IN PCWSTRING FromKeyName,
+ IN PREDEFINED_KEY ToPredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO ToKeyInfo,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CopyOneValueEntry(
+ IN PREDEFINED_KEY FromPredefinedKey,
+ IN PCWSTRING FromParentName,
+ IN PCWSTRING FromKeyName,
+ IN PCWSTRING FromValueName,
+ IN PREDEFINED_KEY ToPredefinedKey,
+ IN PCWSTRING ToParentName,
+ IN PCWSTRING ToKeyName,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CopyOneValueEntry(
+ IN PREDEFINED_KEY FromPredefinedKey,
+ IN PCWSTRING FromParentName,
+ IN PCWSTRING FromKeyName,
+ IN PCWSTRING FromValueName,
+ IN PREDEFINED_KEY ToPredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO ToKeyInfo,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+#endif // NOT_IMPLEMENTED
+
+ NONVIRTUAL
+ BOOLEAN
+ CreateKey(
+ IN OUT PREGISTRY_KEY_INFO NewSubKeyInfo,
+ IN PREDEFINED_KEY PredefinedKey,
+ OUT PULONG ErrorCode DEFAULT NULL,
+ IN BOOLEAN Volatile DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CreateKey(
+ IN PREDEFINED_KEY Predefinedkey,
+ IN OUT PREGISTRY_KEY_INFO ParentKeyInfo,
+ IN OUT PREGISTRY_KEY_INFO NewSubKeyInfo,
+ OUT PULONG ErrorCode DEFAULT NULL,
+ IN BOOLEAN Volatile DEFAULT FALSE
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DeleteKey(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PCWSTRING ParentKeyName,
+ IN PCWSTRING KeyName,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DeleteKey(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO ParentKeyInfo,
+ IN PCWSTRING KeyName,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DeleteValueEntry(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PCWSTRING ParentKeyName,
+ IN PCWSTRING KeyName,
+ IN PCWSTRING ValueName,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DeleteValueEntry(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO KeyInfo,
+ IN PCWSTRING ValueName,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DoesKeyExist(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PCWSTRING ParentName,
+ IN PCWSTRING KeyName,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DoesValueExist(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PCWSTRING ParentName,
+ IN PCWSTRING KeyName,
+ IN PCWSTRING ValueName,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+#if !defined( _AUTOCHECK_ )
+
+ NONVIRTUAL
+ BOOLEAN
+ EnableRootNotification(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN HANDLE Event,
+ IN DWORD Filter,
+ IN BOOLEAN WatchTree DEFAULT TRUE
+ );
+
+#endif
+
+ NONVIRTUAL
+ PCWSTRING
+ GetMachineName(
+ ) CONST;
+
+
+ NONVIRTUAL
+ BOOLEAN
+ IsAccessAllowed(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PREGISTRY_KEY_INFO KeyInfo,
+ IN REGSAM SamDesired,
+ OUT PULONG ErrorCode
+ );
+
+
+ NONVIRTUAL
+ BOOLEAN
+ IsRemoteRegistry(
+ ) CONST;
+
+
+#if !defined( _AUTOCHECK_ )
+
+ NONVIRTUAL
+ BOOLEAN
+ LoadHive(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PREGISTRY_KEY_INFO KeyInfo,
+ IN PCWSTRING FileName,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+#endif
+
+#if 0 // NOT_IMPLEMENTED
+
+ NONVIRTUAL // Subkey moved becomes
+ BOOLEAN // a subkey of ToParentKeyName
+ MoveKey(
+ IN PREDEFINED_KEY FromPredefinedKey,
+ IN PCWSTRING FromParentKeyName,
+ IN PCWSTRING FromKeyName,
+ IN PREDEFINED_KEY ToPredefinedKey,
+ IN PCWSTRING ToParentKeyName,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN // Subkey moved becomes
+ MoveKey( // a subkey of FromParentKey
+ IN PREDEFINED_KEY FromPredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO FromParentKeyInfo,
+ IN PCWSTRING FromKeyName,
+ IN PREDEFINED_KEY ToPredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO ToParentKeyInfo,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ MoveAllValueEntries(
+ IN PREDEFINED_KEY FromPredefinedKey,
+ IN PCWSTRING FromParentName,
+ IN PCWSTRING FromKeyName,
+ IN PREDEFINED_KEY ToPredefinedKey,
+ IN PCWSTRING ToParentName,
+ IN PCWSTRING ToKeyName,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ MoveAllValueEntries(
+ IN PREDEFINED_KEY FromPredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO FromKeyInfo,
+ IN PREDEFINED_KEY ToPredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO ToKeyInfo,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ MoveOneValueEntry(
+ IN PREDEFINED_KEY FromPredefinedKey,
+ IN PCWSTRING FromParentName,
+ IN PCWSTRING FromKeyName,
+ IN PCWSTRING FromValueName,
+ IN PREDEFINED_KEY ToPredefinedKey,
+ IN PCWSTRING ToParentKeyName,
+ IN PCWSTRING ToKeyName,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ MoveOneValueEntry(
+ IN PREDEFINED_KEY FromPredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO FromKeyInfo,
+ IN PCWSTRING FromValueName,
+ IN PREDEFINED_KEY ToPredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO ToKeyInfo,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+#endif // NOT_IMPLEMENTED
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryKeyInfo(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PCWSTRING ParentKeyName,
+ IN PCWSTRING KeyName,
+ OUT PREGISTRY_KEY_INFO KeyInfo,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryKeySecurity(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PCREGISTRY_KEY_INFO KeyInfo,
+ IN SECURITY_INFORMATION SecurityInformation,
+ IN PSECURITY_DESCRIPTOR* SecurityDescriptor,
+ IN PULONG ErrorCode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QuerySubKeysInfo(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PCWSTRING ParentKey,
+ IN PCWSTRING KeyName,
+ IN OUT PARRAY SubKeysInfo,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryValue(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PCWSTRING ParentKeyName,
+ IN PCWSTRING KeyName,
+ IN PCWSTRING ValueName,
+ IN OUT PREGISTRY_VALUE_ENTRY Values,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ QueryValues(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PCWSTRING ParentKeyName,
+ IN PCWSTRING KeyName,
+ IN OUT PARRAY Values,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SetKeySecurity(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO KeyInfo,
+ IN SECURITY_INFORMATION SecurityInformation,
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ IN PULONG ErrorCode DEFAULT NULL,
+ IN BOOLEAN Recurse DEFAULT FALSE
+ );
+
+
+#if !defined( _AUTOCHECK_ )
+
+ NONVIRTUAL
+ BOOLEAN
+ UnLoadHive(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PREGISTRY_KEY_INFO KeyInfo,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ SaveKeyToFile(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PREGISTRY_KEY_INFO KeyInfo,
+ IN PCWSTRING FileName,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ RestoreKeyFromFile(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PREGISTRY_KEY_INFO KeyInfo,
+ IN PCWSTRING FileName,
+ IN BOOLEAN Volatile DEFAULT FALSE,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+
+
+#endif
+
+ NONVIRTUAL
+ BOOLEAN
+ UpdateKeyInfo(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO KeyInfo,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ PWSTRING
+ BuildCompleteName(
+ IN PCWSTRING ParentName,
+ IN PCWSTRING KeyName
+ );
+
+#if !defined( _AUTOCHECK_ )
+
+ NONVIRTUAL
+ ULONG
+ DeleteTree(
+ IN HKEY KeyHandle
+ );
+
+#endif
+
+
+ NONVIRTUAL
+ BOOLEAN
+ InitializeMachineName(
+ IN PCWSTRING MachineName
+ );
+
+#if !defined( _AUTOCHECK_ )
+
+ NONVIRTUAL
+ BOOLEAN
+ SetSubKeysSecurity(
+ IN HKEY KeyHandle,
+ IN SECURITY_INFORMATION SecurityInformation,
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ IN PULONG ErrorCode
+ );
+#endif
+
+
+#if !defined( _AUTOCHECK_ )
+
+ NONVIRTUAL
+ ULONG
+ MapWin32RegApiToRegistryError(
+ IN ULONG ErrorCode
+ ) CONST;
+
+#endif
+
+#if defined( _AUTOCHECK_ )
+
+ NONVIRTUAL
+ BOOLEAN
+ OpenKey(
+ IN PCWSTRING ParentKeyName,
+ IN PCWSTRING KeyName,
+ IN ULONG Flags,
+ OUT PHANDLE Handle,
+ OUT PULONG ErrorCode
+ );
+
+#endif
+
+#if !defined( _AUTOCHECK_ )
+
+ NONVIRTUAL
+ BOOLEAN
+ OpenKey(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PCWSTRING ParentKeyName,
+ IN PCWSTRING KeyName,
+ IN DWORD Permission,
+ OUT PHKEY Key,
+ OUT PULONG ErrorCode DEFAULT NULL
+ );
+
+#endif
+
+
+
+ DSTRING _MachineName;
+
+ BOOLEAN _RemoteRegistry;
+
+
+#if !defined( _AUTOCHECK_ )
+ HKEY _PredefinedKey[ NUMBER_OF_PREDEFINED_KEYS ];
+#endif
+
+ STATIC
+ PWSTRING _Separator;
+
+
+
+};
+
+
+INLINE
+PCWSTRING
+REGISTRY::GetMachineName(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the name of the machine associated with this REGISTRY object.
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+ PCWSTRING - Pointer to a WSTRING object that contains the machine name.
+
+
+--*/
+
+{
+ return( &_MachineName );
+}
+
+
+
+INLINE
+BOOLEAN
+REGISTRY::IsRemoteRegistry(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Inform the client whether this object represnts a remote registry.
+
+
+Arguments:
+
+ None.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if this object represents a remote registry.
+ Returns FALSE otherwise.
+
+
+--*/
+
+{
+ return( _RemoteRegistry );
+}
+
+
+#endif // _REGISTRY_
diff --git a/private/utils/ureg/inc/regkey.hxx b/private/utils/ureg/inc/regkey.hxx
new file mode 100644
index 000000000..9d376a0d5
--- /dev/null
+++ b/private/utils/ureg/inc/regkey.hxx
@@ -0,0 +1,816 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ regkey.hxx
+
+Abstract:
+
+ This module contains the declarations for the REGISTRY_KEY_INFO class.
+ REGISTRY_KEY_INFO is class that contains all the information of a
+ registry key, sucha as:
+
+ -Key Name
+ -Title Index
+ -Class
+ -Security Attribute
+ -Last Write Time
+ -Number of Sub-keys
+ -Number of Value Entries
+
+ A REGISTRY_KEY_INFO object is reinitializable.
+
+Author:
+
+ Jaime Sasson (jaimes) 01-Mar-1992
+
+
+Environment:
+
+ Ulib, User Mode
+
+
+--*/
+
+
+#if !defined( _REGISTRY_KEY_INFO_ )
+
+#define _REGISTRY_KEY_INFO_
+
+#include "ulib.hxx"
+#include "wstring.hxx"
+
+#if !defined( _AUTOCHECK_ )
+#include "timeinfo.hxx"
+#endif
+
+DECLARE_CLASS( REGISTRY );
+DECLARE_CLASS( REGISTRY_KEY_INFO );
+
+
+#if defined( _AUTOCHECK_ )
+ #define PSECURITY_ATTRIBUTES PVOID
+#endif
+
+class REGISTRY_KEY_INFO : public OBJECT {
+
+
+ FRIEND class REGISTRY;
+
+ public:
+
+ DECLARE_CONSTRUCTOR( REGISTRY_KEY_INFO );
+
+ DECLARE_CAST_MEMBER_FUNCTION( REGISTRY_KEY_INFO );
+
+
+ VIRTUAL
+ ~REGISTRY_KEY_INFO(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PCWSTRING KeyName,
+ IN PCWSTRING ParentName,
+ IN ULONG TitleIndex,
+ IN PCWSTRING Class,
+ IN PSECURITY_ATTRIBUTES SecurityAttributes DEFAULT NULL
+ );
+
+ NONVIRTUAL
+ PCWSTRING
+ GetClass(
+ ) CONST;
+
+#if !defined( _AUTOCHECK_ )
+
+ NONVIRTUAL
+ PCTIMEINFO
+ GetLastWriteTime(
+ ) CONST;
+
+#endif
+
+ NONVIRTUAL
+ PCWSTRING
+ GetName(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetNumberOfSubKeys(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetNumberOfValues(
+ ) CONST;
+
+ NONVIRTUAL
+ PCWSTRING
+ GetParentName(
+ ) CONST;
+
+#if !defined( _AUTOCHECK )
+
+ NONVIRTUAL
+ PSECURITY_ATTRIBUTES
+ GetSecurityAttributes(
+ ) CONST;
+
+#endif
+
+ NONVIRTUAL
+ ULONG
+ GetTitleIndex(
+ ) CONST;
+
+
+ NONVIRTUAL
+ BOOLEAN
+ IsKeyInitialized(
+ ) CONST;
+
+
+
+#if DBG
+
+ NONVIRTUAL
+ VOID
+ DbgPrintKeyInfo(
+ );
+
+#endif // DBG
+
+
+
+ private:
+
+ NONVIRTUAL // Only REGISTRY can access it
+ BOOLEAN
+ Initialize(
+ );
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PutClass(
+ IN PCWSTRING Class
+ );
+
+#if !defined( _AUTOCHECK_ )
+
+ NONVIRTUAL
+ VOID
+ PutLastWriteTime(
+ IN PCTIMEINFO LastWriteTime
+ );
+
+#endif
+
+ NONVIRTUAL
+ BOOLEAN
+ PutName(
+ IN PCWSTRING Name
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PutParentName(
+ IN PCWSTRING ParentName
+ );
+
+#if !defined( _AUTOCHECK )
+
+ NONVIRTUAL
+ VOID
+ PutSecurityAttributes(
+ IN PSECURITY_ATTRIBUTES SecurityAttributes
+ );
+#endif
+
+
+#if defined( _AUTOCHECK_ )
+
+ NONVIRTUAL
+ VOID
+ SetLastWriteTime(
+ IN TIME LastWriteTime
+ );
+
+#endif
+ NONVIRTUAL
+ VOID
+ SetKeyInitializedFlag(
+ IN BOOLEAN Initialized
+ );
+
+ NONVIRTUAL
+ VOID
+ SetNumberOfSubKeys(
+ IN ULONG NumberOfSubKeys
+ );
+
+ NONVIRTUAL
+ VOID
+ SetNumberOfValues(
+ IN ULONG NumberOfValues
+ );
+
+ NONVIRTUAL
+ VOID
+ SetTitleIndex(
+ IN ULONG TitleIndex
+ );
+
+
+ DSTRING _Name;
+ DSTRING _ParentName;
+ ULONG _TitleIndex;
+ DSTRING _Class;
+ ULONG _NumberOfSubKeys;
+ ULONG _NumberOfValues;
+ BOOLEAN _KeyIsCompletelyInitialized;
+
+#if defined( _AUTOCHECK_ )
+
+ TIME _LastWriteTime;
+
+#else
+ TIMEINFO _LastWriteTime;
+ SECURITY_ATTRIBUTES _SecurityAttributes;
+
+#endif
+
+};
+
+
+INLINE
+PCWSTRING
+REGISTRY_KEY_INFO::GetClass(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the class of a key.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+
+ PCWSTRING - Pointer to a WSTRING object that contains the key class.
+
+--*/
+
+{
+ return( &_Class );
+}
+#if !defined( _AUTOCHECK_ )
+
+INLINE
+PCTIMEINFO
+REGISTRY_KEY_INFO::GetLastWriteTime(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the Last Write Time of a key.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+
+ PCTIMEINFO - Pointer to a TIMEINFO object that contains the Last Write Time
+ of the key.
+
+--*/
+
+{
+ return( &_LastWriteTime );
+}
+#endif
+
+
+
+INLINE
+PCWSTRING
+REGISTRY_KEY_INFO::GetName(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the name of a key (relative to its parent).
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+
+ PCWSTRING - Pointer to a WSTRING object that contains the key name.
+
+
+--*/
+
+{
+ return( &_Name );
+}
+
+
+INLINE
+PCWSTRING
+REGISTRY_KEY_INFO::GetParentName(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the name of parent of this key ( full name ).
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+
+ PCWSTRING - Pointer to a WSTRING object that contains the parent's name.
+
+
+--*/
+
+{
+ return( &_ParentName );
+}
+
+
+INLINE
+ULONG
+REGISTRY_KEY_INFO::GetNumberOfSubKeys(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the number of subkeys in the key.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+
+ ULONG - The number of subkeys.
+
+
+--*/
+
+{
+ return( _NumberOfSubKeys );
+}
+
+
+INLINE
+ULONG
+REGISTRY_KEY_INFO::GetNumberOfValues(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the number of value entries in the key.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+
+ ULONG - The number of value entries.
+
+
+--*/
+
+{
+ return( _NumberOfValues );
+}
+
+
+#if !defined( _AUTOCHECK_ )
+
+INLINE
+PSECURITY_ATTRIBUTES
+REGISTRY_KEY_INFO::GetSecurityAttributes(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the security attributes of the key.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+
+ PVOID - Pointer to the security attribute
+
+
+--*/
+
+{
+ return( (PSECURITY_ATTRIBUTES)&_SecurityAttributes );
+}
+#endif
+
+
+INLINE
+ULONG
+REGISTRY_KEY_INFO::GetTitleIndex(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the title index of the key.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+
+ ULONG - The title index.
+
+
+--*/
+
+{
+ return( _TitleIndex );
+}
+
+
+
+INLINE
+BOOLEAN
+REGISTRY_KEY_INFO::IsKeyInitialized(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Inform the caller if the object is completely initialized.
+ This object will be completly initialized only if the registry
+ class was able to query the key to retrieve its calss and last
+ write time.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+
+ BOOLEAN - Returns TRUE if the key is initialized, or FALSE otherwise.
+
+
+--*/
+
+{
+ return( _KeyIsCompletelyInitialized );
+}
+
+
+
+INLINE
+BOOLEAN
+REGISTRY_KEY_INFO::PutClass(
+ IN PCWSTRING Class
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the variable _Class.
+
+
+Arguments:
+
+ Class - Pointer to a WSTRING object that contains the key class.
+
+
+Return Value:
+
+
+ None.
+
+
+--*/
+
+{
+ DebugPtrAssert( Class );
+ return( _Class.Initialize( Class ) );
+}
+
+#if !defined( _AUTOCHECK_ )
+
+INLINE
+VOID
+REGISTRY_KEY_INFO::PutLastWriteTime(
+ IN PCTIMEINFO LastWriteTime
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the variable _LastWriteTime.
+
+
+Arguments:
+
+ LastWriteTime - Pointer to a TIMEINFO object that contains the
+ LastWriteTime of the key.
+
+Return Value:
+
+
+ None.
+
+--*/
+
+{
+ DebugPtrAssert( LastWriteTime );
+ _LastWriteTime.Initialize( LastWriteTime );
+}
+#endif
+
+#if defined( _AUTOCHECK_ )
+
+INLINE
+VOID
+REGISTRY_KEY_INFO::SetLastWriteTime(
+ IN TIME LastWriteTime
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the variable _LastWriteTime.
+
+
+Arguments:
+
+ LastWriteTime - Pointer to a TIMEINFO object that contains the
+ LastWriteTime of the key.
+
+Return Value:
+
+
+ None.
+
+--*/
+
+{
+ _LastWriteTime = LastWriteTime;
+
+}
+#endif
+
+
+INLINE
+BOOLEAN
+REGISTRY_KEY_INFO::PutName(
+ IN PCWSTRING Name
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the key name.
+
+
+Arguments:
+
+ Name - Pointer to a WSTRING object that contains the key name.
+
+Return Value:
+
+
+ None.
+
+
+--*/
+
+{
+ DebugPtrAssert( Name );
+ return( _Name.Initialize( Name ) );
+}
+
+
+INLINE
+BOOLEAN
+REGISTRY_KEY_INFO::PutParentName(
+ IN PCWSTRING ParentName
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the parent name.
+
+
+Arguments:
+
+ Name - Pointer to a WSTRING object that contains the parent name.
+
+Return Value:
+
+
+ None.
+
+
+--*/
+
+{
+ DebugPtrAssert( ParentName );
+ return( _ParentName.Initialize( ParentName ) );
+}
+
+
+INLINE
+VOID
+REGISTRY_KEY_INFO::SetKeyInitializedFlag(
+ IN BOOLEAN Initialized
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes the flag that indicates whether the key is completely
+ initialized. That is, the registry class was able to query the value,
+ and its last write time is initialized.
+
+
+Arguments:
+
+ Initialized - A flag that indicates whether the key is completely
+ initialized.
+
+Return Value:
+
+
+ None.
+
+
+--*/
+
+{
+ _KeyIsCompletelyInitialized = Initialized;
+}
+
+
+
+INLINE
+VOID
+REGISTRY_KEY_INFO::SetNumberOfSubKeys(
+ IN ULONG NumberOfSubKeys
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the variable NumberOfSubKeys.
+
+
+Arguments:
+
+ NumberOfSubkeys - The number of subkeys.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ _NumberOfSubKeys = NumberOfSubKeys;
+}
+
+
+
+
+INLINE
+VOID
+REGISTRY_KEY_INFO::SetNumberOfValues(
+ IN ULONG NumberOfValues
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the variable _NumberOfValues.
+
+
+Arguments:
+
+ NumberOfValues - The number of value entries in the key.
+
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ _NumberOfValues = NumberOfValues;
+}
+
+
+
+INLINE
+VOID
+REGISTRY_KEY_INFO::SetTitleIndex(
+ IN ULONG TitleIndex
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the variable _TitleIndex.
+
+
+Arguments:
+
+ TitleIndex - Title index of the key.
+
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ _TitleIndex = TitleIndex;
+}
+
+
+#endif // _REGISTRY_KEY_INFO_
diff --git a/private/utils/ureg/inc/regvalue.hxx b/private/utils/ureg/inc/regvalue.hxx
new file mode 100644
index 000000000..1b64a5a06
--- /dev/null
+++ b/private/utils/ureg/inc/regvalue.hxx
@@ -0,0 +1,394 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ regvalue.hxx
+
+Abstract:
+
+
+ This module contains the declarations for the REGISTRY_VALUE_ENTRY class.
+ This class models a value entry of a registry key.
+ It contains:
+
+ -value name
+ -title index
+ -data type
+ -buffer that contains the data in a value entry
+
+
+Author:
+
+ Jaime Sasson (jaimes) 06-Aug-1991
+
+
+Environment:
+
+
+ Ulib, User Mode
+
+--*/
+
+
+#if !defined( _REGISTRY_VALUE_ENTRY_ )
+
+#define _REGISTRY_VALUE_ENTRY_
+
+#include "ulib.hxx"
+#include "wstring.hxx"
+
+//
+// Declare primitive value types.
+//
+
+typedef enum _REG_TYPE {
+
+ TYPE_REG_NONE = REG_NONE,
+ TYPE_REG_SZ = REG_SZ,
+ TYPE_REG_EXPAND_SZ = REG_EXPAND_SZ,
+ TYPE_REG_BINARY = REG_BINARY,
+ TYPE_REG_DWORD = REG_DWORD,
+ TYPE_REG_MULTI_SZ = REG_MULTI_SZ,
+ TYPE_REG_RESOURCE_LIST= REG_RESOURCE_LIST,
+ TYPE_REG_FULL_RESOURCE_DESCRIPTOR= REG_FULL_RESOURCE_DESCRIPTOR,
+ TYPE_REG_RESOURCE_REQUIREMENTS_LIST= REG_RESOURCE_REQUIREMENTS_LIST,
+ TYPE_UNKNOWN
+} REG_TYPE;
+
+
+
+DECLARE_CLASS( REGISTRY );
+DECLARE_CLASS( REGISTRY_VALUE_ENTRY );
+
+
+
+class REGISTRY_VALUE_ENTRY : public OBJECT {
+
+ FRIEND class REGISTRY;
+
+ public:
+
+ DECLARE_CONSTRUCTOR( REGISTRY_VALUE_ENTRY );
+
+ DECLARE_CAST_MEMBER_FUNCTION( REGISTRY_VALUE_ENTRY );
+
+
+
+ VIRTUAL
+ ~REGISTRY_VALUE_ENTRY(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ IN PCWSTRING ValueName,
+ IN ULONG TitleIndex,
+ IN REG_TYPE Type,
+ IN PCBYTE Data DEFAULT NULL,
+ IN ULONG Size DEFAULT 0
+ );
+
+ NONVIRTUAL
+ ULONG
+ GetData(
+ OUT PCBYTE* Data
+ ) CONST;
+
+ NONVIRTUAL
+ PCWSTRING
+ GetName(
+ ) CONST;
+
+ NONVIRTUAL
+ ULONG
+ GetTitleIndex(
+ ) CONST;
+
+ NONVIRTUAL
+ REG_TYPE
+ GetType(
+ ) CONST;
+
+ NONVIRTUAL
+ VOID
+ PutData(
+ IN PCBYTE Data,
+ IN ULONG DataSize
+ );
+
+#if DBG
+ NONVIRTUAL
+ VOID
+ DbgPrintValueEntry(
+ );
+#endif
+
+
+
+ private:
+
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize(
+ );
+
+ NONVIRTUAL
+ VOID
+ Construct(
+ );
+
+ NONVIRTUAL
+ VOID
+ Destroy(
+ );
+
+ NONVIRTUAL
+ VOID
+ SetTitleIndex(
+ IN ULONG TitleIndex
+ );
+
+ NONVIRTUAL
+ VOID
+ SetType(
+ IN REG_TYPE Type
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ PutName(
+ IN PCWSTRING ValueName
+ );
+
+
+
+ DSTRING _Name;
+ ULONG _TitleIndex;
+ REG_TYPE _Type;
+ PBYTE _Data;
+ ULONG _Size;
+};
+
+
+
+INLINE
+ULONG
+REGISTRY_VALUE_ENTRY::GetData(
+ OUT PCBYTE* Data
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the buffer that contains the data stored in the value entry.
+
+
+Arguments:
+
+ Data - Variable that will contain the pointer to the buffer that
+ contains the data.
+
+Return Value:
+
+ ULONG - Number of bytes in the buffer (Data size)
+
+
+--*/
+
+
+{
+ *Data = _Data;
+ return( _Size );
+}
+
+
+INLINE
+PCWSTRING
+REGISTRY_VALUE_ENTRY::GetName(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return a pointer to a WSTRING object that contains the value name.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The value name.
+
+
+--*/
+
+
+{
+ return( &_Name );
+}
+
+
+
+INLINE
+ULONG
+REGISTRY_VALUE_ENTRY::GetTitleIndex(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the title index of this value.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ULONG - The title index.
+
+
+--*/
+
+
+{
+ return( _TitleIndex );
+}
+
+
+
+INLINE
+REG_TYPE
+REGISTRY_VALUE_ENTRY::GetType(
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Return the type of data stored in this object.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ REG_TYPE - The data type.
+
+
+--*/
+
+
+{
+ return( _Type );
+}
+
+
+
+INLINE
+BOOLEAN
+REGISTRY_VALUE_ENTRY::PutName(
+ IN PCWSTRING ValueName
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the variable _Name.
+
+
+Arguments:
+
+ ValueName - Pointer to a WSTRING object that contains the value name.
+
+
+Return Value:
+
+ None.
+
+
+--*/
+
+
+{
+ DebugPtrAssert( ValueName );
+ return( _Name.Initialize( ValueName ) );
+}
+
+
+
+INLINE
+VOID
+REGISTRY_VALUE_ENTRY::SetTitleIndex(
+ IN ULONG TitleIndex
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the variable _TitleIndex.
+
+
+Arguments:
+
+ TitleIndex - The title index.
+
+
+Return Value:
+
+ None.
+
+
+--*/
+
+
+{
+ _TitleIndex = TitleIndex;
+}
+
+
+
+INLINE
+VOID
+REGISTRY_VALUE_ENTRY::SetType(
+ IN REG_TYPE Type
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the variable _Type.
+
+
+Arguments:
+
+ Type - The type of data.
+
+
+Return Value:
+
+ None.
+
+
+--*/
+
+
+{
+ _Type = Type;
+}
+
+
+#endif // _REGISTRY_VALUE_ENTRY_
diff --git a/private/utils/ureg/src/defalpha.dbg b/private/utils/ureg/src/defalpha.dbg
new file mode 100644
index 000000000..141783e55
--- /dev/null
+++ b/private/utils/ureg/src/defalpha.dbg
@@ -0,0 +1,2 @@
+ ?DbgPrintKeyInfo@REGISTRY_KEY_INFO@@QAAXXZ
+ ?DbgPrintValueEntry@REGISTRY_VALUE_ENTRY@@QAAXXZ
diff --git a/private/utils/ureg/src/defalpha.fre b/private/utils/ureg/src/defalpha.fre
new file mode 100644
index 000000000..46c7122e6
--- /dev/null
+++ b/private/utils/ureg/src/defalpha.fre
@@ -0,0 +1,31 @@
+LIBRARY UREG
+
+DESCRIPTION 'My test DLL'
+
+EXPORTS
+ InitializeUreg
+ ??0REGISTRY@@QAA@XZ
+ ??1REGISTRY@@UAA@XZ
+ ?Initialize@REGISTRY@@QAAEPBVWSTRING@@PAK@Z
+ ?QueryValues@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PBVWSTRING@@1PAVARRAY@@PAK@Z
+ ??0REGISTRY_KEY_INFO@@QAA@XZ
+ ??0REGISTRY_VALUE_ENTRY@@QAA@XZ
+ ?AddValueEntry@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PBVREGISTRY_VALUE_ENTRY@@EPAK@Z
+ ?CreateKey@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@1PAKE@Z
+ ?DeleteKey@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PBVWSTRING@@PAK@Z
+ ?DeleteValueEntry@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PBVWSTRING@@PAK@Z
+ ?DoesKeyExist@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PBVWSTRING@@1PAK@Z
+ ?DoesValueExist@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PBVWSTRING@@11PAK@Z
+ ?EnableRootNotification@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAXKE@Z
+ ?Initialize@REGISTRY_KEY_INFO@@QAAEPBVWSTRING@@0K0PAU_SECURITY_ATTRIBUTES@@@Z
+ ?Initialize@REGISTRY_VALUE_ENTRY@@QAAEPBVWSTRING@@KW4_REG_TYPE@@PBEK@Z
+ ?IsAccessAllowed@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@KPAK@Z
+ ?LoadHive@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PBVWSTRING@@PAK@Z
+ ?QueryKeyInfo@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PBVWSTRING@@1PAVREGISTRY_KEY_INFO@@PAK@Z
+ ?QueryKeySecurity@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PBVREGISTRY_KEY_INFO@@KPAPAXPAK@Z
+ ?QuerySubKeysInfo@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PBVWSTRING@@1PAVARRAY@@PAK@Z
+ ?RestoreKeyFromFile@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PBVWSTRING@@EPAK@Z
+ ?SaveKeyToFile@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PBVWSTRING@@PAK@Z
+ ?SetKeySecurity@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@KPAXPAKE@Z
+ ?UnLoadHive@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PAK@Z
+ ?UpdateKeyInfo@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PAK@Z
diff --git a/private/utils/ureg/src/defi386.dbg b/private/utils/ureg/src/defi386.dbg
new file mode 100644
index 000000000..a81237f5d
--- /dev/null
+++ b/private/utils/ureg/src/defi386.dbg
@@ -0,0 +1,2 @@
+ ?DbgPrintKeyInfo@REGISTRY_KEY_INFO@@QAEXXZ
+ ?DbgPrintValueEntry@REGISTRY_VALUE_ENTRY@@QAEXXZ
diff --git a/private/utils/ureg/src/defi386.fre b/private/utils/ureg/src/defi386.fre
new file mode 100644
index 000000000..905531ac2
--- /dev/null
+++ b/private/utils/ureg/src/defi386.fre
@@ -0,0 +1,32 @@
+LIBRARY UREG
+
+DESCRIPTION 'My test DLL'
+
+EXPORTS
+ InitializeUreg
+ ??0REGISTRY@@QAE@XZ
+ ??1REGISTRY@@UAE@XZ
+ ?Initialize@REGISTRY@@QAEEPBVWSTRING@@PAK@Z
+ ?QueryValues@REGISTRY@@QAEEW4_PREDEFINED_KEY@@PBVWSTRING@@1PAVARRAY@@PAK@Z
+ ??0REGISTRY_KEY_INFO@@QAE@XZ
+ ??0REGISTRY_VALUE_ENTRY@@QAE@XZ
+ ?AddValueEntry@REGISTRY@@QAEEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PBVREGISTRY_VALUE_ENTRY@@EPAK@Z
+ ?CreateKey@REGISTRY@@QAEEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@1PAKE@Z
+ ?DeleteKey@REGISTRY@@QAEEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PBVWSTRING@@PAK@Z
+ ?DeleteValueEntry@REGISTRY@@QAEEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PBVWSTRING@@PAK@Z
+ ?DoesKeyExist@REGISTRY@@QAEEW4_PREDEFINED_KEY@@PBVWSTRING@@1PAK@Z
+ ?DoesValueExist@REGISTRY@@QAEEW4_PREDEFINED_KEY@@PBVWSTRING@@11PAK@Z
+ ?EnableRootNotification@REGISTRY@@QAEEW4_PREDEFINED_KEY@@PAXKE@Z
+ ?Initialize@REGISTRY_KEY_INFO@@QAEEPBVWSTRING@@0K0PAU_SECURITY_ATTRIBUTES@@@Z
+ ?Initialize@REGISTRY_VALUE_ENTRY@@QAEEPBVWSTRING@@KW4_REG_TYPE@@PBEK@Z
+ ?IsAccessAllowed@REGISTRY@@QAEEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@KPAK@Z
+ ?LoadHive@REGISTRY@@QAEEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PBVWSTRING@@PAK@Z
+ ?QueryKeyInfo@REGISTRY@@QAEEW4_PREDEFINED_KEY@@PBVWSTRING@@1PAVREGISTRY_KEY_INFO@@PAK@Z
+ ?QueryKeySecurity@REGISTRY@@QAEEW4_PREDEFINED_KEY@@PBVREGISTRY_KEY_INFO@@KPAPAXPAK@Z
+ ?QuerySubKeysInfo@REGISTRY@@QAEEW4_PREDEFINED_KEY@@PBVWSTRING@@1PAVARRAY@@PAK@Z
+ ?RestoreKeyFromFile@REGISTRY@@QAEEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PBVWSTRING@@EPAK@Z
+ ?SaveKeyToFile@REGISTRY@@QAEEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PBVWSTRING@@PAK@Z
+ ?SetKeySecurity@REGISTRY@@QAEEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@KPAXPAKE@Z
+ ?UnLoadHive@REGISTRY@@QAEEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PAK@Z
+ ?UpdateKeyInfo@REGISTRY@@QAEEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PAK@Z
+
diff --git a/private/utils/ureg/src/defmips.dbg b/private/utils/ureg/src/defmips.dbg
new file mode 100644
index 000000000..141783e55
--- /dev/null
+++ b/private/utils/ureg/src/defmips.dbg
@@ -0,0 +1,2 @@
+ ?DbgPrintKeyInfo@REGISTRY_KEY_INFO@@QAAXXZ
+ ?DbgPrintValueEntry@REGISTRY_VALUE_ENTRY@@QAAXXZ
diff --git a/private/utils/ureg/src/defmips.fre b/private/utils/ureg/src/defmips.fre
new file mode 100644
index 000000000..ef6cc2d58
--- /dev/null
+++ b/private/utils/ureg/src/defmips.fre
@@ -0,0 +1,32 @@
+LIBRARY UREG
+
+DESCRIPTION 'My test DLL'
+
+EXPORTS
+ InitializeUreg
+ ??0REGISTRY@@QAA@XZ
+ ??1REGISTRY@@UAA@XZ
+ ?Initialize@REGISTRY@@QAAEPBVWSTRING@@PAK@Z
+ ?QueryValues@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PBVWSTRING@@1PAVARRAY@@PAK@Z
+ ??0REGISTRY_KEY_INFO@@QAA@XZ
+ ??0REGISTRY_VALUE_ENTRY@@QAA@XZ
+ ?AddValueEntry@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PBVREGISTRY_VALUE_ENTRY@@EPAK@Z
+ ?CreateKey@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@1PAKE@Z
+ ?DeleteKey@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PBVWSTRING@@PAK@Z
+ ?DeleteValueEntry@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PBVWSTRING@@PAK@Z
+ ?DoesKeyExist@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PBVWSTRING@@1PAK@Z
+ ?DoesValueExist@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PBVWSTRING@@11PAK@Z
+ ?EnableRootNotification@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAXKE@Z
+ ?Initialize@REGISTRY_KEY_INFO@@QAAEPBVWSTRING@@0K0PAU_SECURITY_ATTRIBUTES@@@Z
+ ?Initialize@REGISTRY_VALUE_ENTRY@@QAAEPBVWSTRING@@KW4_REG_TYPE@@PBEK@Z
+ ?IsAccessAllowed@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@KPAK@Z
+ ?LoadHive@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PBVWSTRING@@PAK@Z
+ ?QueryKeyInfo@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PBVWSTRING@@1PAVREGISTRY_KEY_INFO@@PAK@Z
+ ?QueryKeySecurity@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PBVREGISTRY_KEY_INFO@@KPAPAXPAK@Z
+ ?QuerySubKeysInfo@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PBVWSTRING@@1PAVARRAY@@PAK@Z
+ ?RestoreKeyFromFile@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PBVWSTRING@@EPAK@Z
+ ?SaveKeyToFile@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PBVWSTRING@@PAK@Z
+ ?SetKeySecurity@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@KPAXPAKE@Z
+ ?UnLoadHive@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PAK@Z
+ ?UpdateKeyInfo@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PAK@Z
+
diff --git a/private/utils/ureg/src/defppc.dbg b/private/utils/ureg/src/defppc.dbg
new file mode 100644
index 000000000..141783e55
--- /dev/null
+++ b/private/utils/ureg/src/defppc.dbg
@@ -0,0 +1,2 @@
+ ?DbgPrintKeyInfo@REGISTRY_KEY_INFO@@QAAXXZ
+ ?DbgPrintValueEntry@REGISTRY_VALUE_ENTRY@@QAAXXZ
diff --git a/private/utils/ureg/src/defppc.fre b/private/utils/ureg/src/defppc.fre
new file mode 100644
index 000000000..ef6cc2d58
--- /dev/null
+++ b/private/utils/ureg/src/defppc.fre
@@ -0,0 +1,32 @@
+LIBRARY UREG
+
+DESCRIPTION 'My test DLL'
+
+EXPORTS
+ InitializeUreg
+ ??0REGISTRY@@QAA@XZ
+ ??1REGISTRY@@UAA@XZ
+ ?Initialize@REGISTRY@@QAAEPBVWSTRING@@PAK@Z
+ ?QueryValues@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PBVWSTRING@@1PAVARRAY@@PAK@Z
+ ??0REGISTRY_KEY_INFO@@QAA@XZ
+ ??0REGISTRY_VALUE_ENTRY@@QAA@XZ
+ ?AddValueEntry@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PBVREGISTRY_VALUE_ENTRY@@EPAK@Z
+ ?CreateKey@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@1PAKE@Z
+ ?DeleteKey@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PBVWSTRING@@PAK@Z
+ ?DeleteValueEntry@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PBVWSTRING@@PAK@Z
+ ?DoesKeyExist@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PBVWSTRING@@1PAK@Z
+ ?DoesValueExist@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PBVWSTRING@@11PAK@Z
+ ?EnableRootNotification@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAXKE@Z
+ ?Initialize@REGISTRY_KEY_INFO@@QAAEPBVWSTRING@@0K0PAU_SECURITY_ATTRIBUTES@@@Z
+ ?Initialize@REGISTRY_VALUE_ENTRY@@QAAEPBVWSTRING@@KW4_REG_TYPE@@PBEK@Z
+ ?IsAccessAllowed@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@KPAK@Z
+ ?LoadHive@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PBVWSTRING@@PAK@Z
+ ?QueryKeyInfo@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PBVWSTRING@@1PAVREGISTRY_KEY_INFO@@PAK@Z
+ ?QueryKeySecurity@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PBVREGISTRY_KEY_INFO@@KPAPAXPAK@Z
+ ?QuerySubKeysInfo@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PBVWSTRING@@1PAVARRAY@@PAK@Z
+ ?RestoreKeyFromFile@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PBVWSTRING@@EPAK@Z
+ ?SaveKeyToFile@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PBVWSTRING@@PAK@Z
+ ?SetKeySecurity@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@KPAXPAKE@Z
+ ?UnLoadHive@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PAK@Z
+ ?UpdateKeyInfo@REGISTRY@@QAAEW4_PREDEFINED_KEY@@PAVREGISTRY_KEY_INFO@@PAK@Z
+
diff --git a/private/utils/ureg/src/makefile b/private/utils/ureg/src/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/ureg/src/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/ureg/src/makefile.inc b/private/utils/ureg/src/makefile.inc
new file mode 100644
index 000000000..9c1f0688b
--- /dev/null
+++ b/private/utils/ureg/src/makefile.inc
@@ -0,0 +1,11 @@
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+
+obj\$(TARGET_DIRECTORY)\ureg.def: def$(TARGET_DIRECTORY).fre def$(TARGET_DIRECTORY).dbg
+ copy def$(TARGET_DIRECTORY).fre + def$(TARGET_DIRECTORY).dbg obj\$(TARGET_DIRECTORY)\ureg.def
+
+!ELSE
+
+obj\$(TARGET_DIRECTORY)\ureg.def: def$(TARGET_DIRECTORY).fre
+ copy def$(TARGET_DIRECTORY).fre obj\$(TARGET_DIRECTORY)\ureg.def
+
+!ENDIF
diff --git a/private/utils/ureg/src/registry.cxx b/private/utils/ureg/src/registry.cxx
new file mode 100644
index 000000000..fbcd76ed0
--- /dev/null
+++ b/private/utils/ureg/src/registry.cxx
@@ -0,0 +1,5757 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ registry.cxx
+
+Abstract:
+
+ This module contains the methods for the REGISTRY class.
+
+Author:
+
+ Jaime Sasson (jaimes) 26-Aug-1991
+
+Environment:
+
+ Ulib, Regedit, Windows, User Mode
+
+--*/
+
+#include "registry.hxx"
+
+
+#if defined( _AUTOCHECK_ )
+
+#define KEY_BASIC_SIZE sizeof(KEY_BASIC_INFORMATION)+MAXIMUM_FILENAME_LENGTH
+#define KEY_FULL_SIZE sizeof(KEY_FULL_INFORMATION)+MAXIMUM_FILENAME_LENGTH
+#define VALUE_BASIC_SIZE sizeof(KEY_VALUE_BASIC_INFORMATION)+MAXIMUM_FILENAME_LENGTH
+#define VALUE_FULL_SIZE sizeof(KEY_VALUE_FULL_INFORMATION)+MAXIMUM_FILENAME_LENGTH
+
+#endif
+
+
+
+DEFINE_CONSTRUCTOR( REGISTRY, OBJECT );
+
+DEFINE_CAST_MEMBER_FUNCTION( REGISTRY );
+
+
+//
+// Initialization of static variable
+//
+
+PWSTRING REGISTRY::_Separator = NULL;
+
+
+
+
+REGISTRY::~REGISTRY(
+)
+/*++
+
+Routine Description:
+
+ Destroy a REGISTRY object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+REGISTRY::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Worker method for object construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG Index;
+
+#if !defined( _AUTOCHECK_ )
+
+ for( Index = 0; Index < NUMBER_OF_PREDEFINED_KEYS; Index++ ) {
+ _PredefinedKey[ Index ] = 0;
+ }
+
+#endif
+
+}
+
+
+
+VOID
+REGISTRY::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Worker method for object destruction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+#if !defined( _AUTOCHECK_ )
+
+ ULONG Index;
+
+ if( _RemoteRegistry ) {
+ if( _PredefinedKey[ PREDEFINED_KEY_USERS ] != 0 ) {
+ RegCloseKey( _PredefinedKey[ PREDEFINED_KEY_USERS ] );
+ }
+ if( _PredefinedKey[ PREDEFINED_KEY_LOCAL_MACHINE ] != 0 ) {
+ RegCloseKey( _PredefinedKey[ PREDEFINED_KEY_LOCAL_MACHINE ] );
+ }
+ }
+ _RemoteRegistry = FALSE;
+ for( Index = 0; Index < NUMBER_OF_PREDEFINED_KEYS; Index++ ) {
+ _PredefinedKey[ Index ] = 0;
+ }
+
+#endif
+
+}
+
+
+BOOLEAN
+REGISTRY::Initialize(
+ IN PCWSTRING MachineName,
+ IN PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize a REGISTRY object.
+
+Arguments:
+
+ MachineName - The name of the machine whose registry we want to access.
+ NULL means the local machine.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+
+{
+ PWSTR MachineNameString = NULL;
+ ULONG Status;
+ DSTRING TmpName;
+
+
+ Destroy();
+
+ _RemoteRegistry = FALSE;
+
+ if( _Separator == NULL ) {
+ _Separator = ( PWSTRING )NEW( DSTRING );
+ if( _Separator == NULL ) {
+ DebugPtrAssert( _Separator );
+
+#if !defined( _AUTOCHECK_ )
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ }
+#endif
+ return( FALSE );
+ }
+ if( !_Separator->Initialize( "\\" ) ) {
+ DebugPrint( "_Separator.Initialize() failed \n" );
+
+#if !defined( _AUTOCHECK_ )
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_INITIALIZATION_FAILURE;
+ }
+#endif
+
+ return( FALSE );
+ }
+ }
+
+
+#if !defined( _AUTOCHECK_ )
+
+ if( !InitializeMachineName( MachineName ) ) {
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_INITIALIZATION_FAILURE;
+ }
+ return( FALSE );
+ }
+
+ if( !IsRemoteRegistry() ) {
+ _PredefinedKey[ PREDEFINED_KEY_CLASSES_ROOT ] = HKEY_CLASSES_ROOT;
+ _PredefinedKey[ PREDEFINED_KEY_CURRENT_USER ] = HKEY_CURRENT_USER;
+ _PredefinedKey[ PREDEFINED_KEY_LOCAL_MACHINE ] = HKEY_LOCAL_MACHINE;
+ _PredefinedKey[ PREDEFINED_KEY_USERS ] = HKEY_USERS;
+ _PredefinedKey[ PREDEFINED_KEY_CURRENT_CONFIG ] = HKEY_CURRENT_CONFIG;
+ } else {
+ if( !TmpName.Initialize( ( LPWSTR )L"\\\\" ) ||
+ !TmpName.Strcat( MachineName ) ){
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_INITIALIZATION_FAILURE;
+ }
+ return( FALSE );
+ }
+
+ MachineNameString = TmpName.QueryWSTR();
+ if( MachineNameString == NULL ) {
+ DebugPrint( "TmpName.QueryWSTR() failed" );
+ return( FALSE );
+ }
+ _PredefinedKey[ PREDEFINED_KEY_CLASSES_ROOT ] = 0;
+ _PredefinedKey[ PREDEFINED_KEY_CURRENT_USER ] = 0;
+ _PredefinedKey[ PREDEFINED_KEY_CURRENT_CONFIG ] = 0;
+ Status = RegConnectRegistry( MachineNameString,
+ HKEY_LOCAL_MACHINE,
+ &_PredefinedKey[ PREDEFINED_KEY_LOCAL_MACHINE ] );
+ if( Status != 0 ) {
+ DebugPrintf( "RegConnectRegistry() failed: HKEY_LOCAL_MACHINE, Status = %#x \n",
+ Status );
+ DebugPrint( "RegConnectRegistry() failed: HKEY_LOCAL_MACHINE" );
+ FREE( MachineNameString );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+ return( FALSE );
+ }
+ Status = RegConnectRegistry( MachineNameString,
+ HKEY_USERS,
+ &_PredefinedKey[ PREDEFINED_KEY_USERS ] );
+ if( Status != 0 ) {
+ DebugPrintf( "RegConnectRegistry() failed: HKEY_USERS, Status = %#x \n", Status );
+ DebugPrint( "RegConnectRegistry() failed: HKEY_USERS" );
+ FREE( MachineNameString );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+ return( FALSE );
+ }
+ FREE( MachineNameString );
+ }
+
+#endif
+ return( TRUE );
+}
+
+
+
+
+
+BOOLEAN
+REGISTRY::InitializeMachineName(
+ IN PCWSTRING MachineName
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the data member that contains the machine name, and
+ the flag that indicate whether the registry is local or remote
+
+Arguments:
+
+ MachineName - Pointer to a WSTRING object that contains the machine
+ name.
+ It can be NULL, or it can be a NUL string, and in this case
+ this REGISTRY object will represent the local machine.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+
+{
+
+#if defined( _AUTOCHECK_ )
+
+ UNREFERENCED_PARAMETER( MachineName );
+
+ return( FALSE );
+
+#else
+
+
+ WSTR LocalMachineName[ MAX_COMPUTERNAME_LENGTH + 1];
+
+
+ ULONG NameLength;
+ DSTRING Name;
+
+#if 0
+ PSTR DebugNameString;
+#endif
+
+ //
+ // Determine the name of the local machine
+ //
+
+ NameLength = sizeof( LocalMachineName );
+ if( !GetComputerName( LocalMachineName,
+ &NameLength ) ) {
+
+ DebugPrintf( "GetComputerName() failed, Error = %#x \n", GetLastError() );
+ DebugPrint( "GetComputerName() failed" );
+ return( FALSE );
+ }
+ if( !Name.Initialize( LocalMachineName, NameLength ) ) {
+ DebugPrint( "Name.Initialize() failed" );
+ return( FALSE );
+ }
+
+#if 0
+ DebugNameString = Name.QuerySTR();
+ DebugPtrAssert( DebugNameString );
+ DebugPrintf( "MachineName = %s \n", DebugNameString );
+#endif
+
+ //
+ // Find out if the name received as parameter represents the local
+ // machine.
+ //
+
+ if( ( MachineName == NULL ) ||
+ ( MachineName->QueryChCount() == 0 )
+ ) {
+ //
+ // Local machine
+ //
+ if( !_MachineName.Initialize( &Name ) ) {
+ DebugPrint( "_MachineName.Initialize( &Name ) failed" );
+ return( FALSE );
+ }
+ _RemoteRegistry = FALSE;
+ } else {
+ //
+ // Remote machine
+ //
+ if( !_MachineName.Initialize( MachineName ) ) {
+ DebugPrint( "_MachineName.Initialize( MachineName ) failed" );
+ return( FALSE );
+ }
+ _RemoteRegistry = TRUE;
+ }
+ return( TRUE );
+
+#endif
+}
+
+
+
+
+BOOLEAN
+REGISTRY::AddValueEntry(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PCWSTRING ParentName,
+ IN PCWSTRING KeyName,
+ IN PCREGISTRY_VALUE_ENTRY Value,
+ IN BOOLEAN FailIfExists,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Add a value entry to an existing key.
+
+Arguments:
+
+
+ PredefinedKey - The root of the tree where the key is.
+
+ ParentName - The parent name of the key (can be NULL ).
+
+ KeyName - The name of the key where the Value will be added (cannot be NULL).
+
+ Value - Pointer to the object that contains the information about the
+ value to be created.
+
+
+ FailIfExists - If TRUE, overwrite the existing value.
+
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the value entry was added, or FALSE otherwise.
+
+
+--*/
+
+{
+
+#if defined( _AUTOCHECK_ )
+
+ PWSTRING CompleteKeyName;
+ PWSTR CompleteKeyNameString;
+ PWSTR ValueNameString;
+ UNICODE_STRING UnicodeKeyName;
+ UNICODE_STRING UnicodeValueName;
+ OBJECT_ATTRIBUTES ObjAttr;
+ HANDLE Handle;
+ NTSTATUS Status;
+ PBYTE Data;
+ ULONG Size;
+
+
+ if ( !OpenKey( ParentName, KeyName, KEY_SET_VALUE, &Handle, ErrorCode ) ) {
+ return FALSE;
+ }
+
+ if ( !Value ||
+ !(ValueNameString = Value->GetName()->QueryWSTR() )
+
+ ) {
+
+ FREE( ValueNameString );
+ NtClose( Handle );
+ return FALSE;
+ }
+
+
+ if( FailIfExists &&
+ DoesValueExist( PredefinedKey, ParentName, KeyName, Value->GetName() ) ) {
+ if( ErrorCode != NULL ) {
+ *ErrorCode = 0;
+ }
+
+ FREE( ValueNameString );
+ NtClose( Handle );
+ return( FALSE );
+ }
+
+ RtlInitUnicodeString( &UnicodeValueName, ValueNameString );
+
+ Size = Value->GetData( &Data );
+
+ Status = NtSetValueKey( Handle,
+ &UnicodeValueName,
+ Value->GetTitleIndex(),
+ Value->GetType(),
+ Data,
+ Size );
+
+ FREE( ValueNameString );
+ NtClose( Handle );
+
+ if ( !NT_SUCCESS( Status ) ) {
+ if ( ErrorCode != NULL ) {
+ *ErrorCode = Status;
+ }
+ return FALSE;
+ }
+
+ return TRUE;
+
+#else
+
+
+ HKEY Handle;
+ PCWSTRING ValueName;
+ PWSTR ValueNameString;
+ DWORD Status;
+ PBYTE Data;
+ ULONG Size;
+
+
+ DebugPtrAssert( ParentName );
+ DebugPtrAssert( KeyName );
+ DebugPtrAssert( Value );
+
+
+
+ //
+ // Open the key with KEY_SET_VALUE access so that the key is locked
+ //
+
+ if( !OpenKey( PredefinedKey,
+ ParentName,
+ KeyName,
+ KEY_SET_VALUE,
+ &Handle,
+ ErrorCode ) ) {
+ DebugPrint( "OpenKey() failed" );
+ return( FALSE );
+ }
+
+ //
+ // Verify whether the value exists
+ //
+ if( FailIfExists &&
+ DoesValueExist( PredefinedKey, ParentName, KeyName, Value->GetName(), ErrorCode ) ) {
+ //
+ // If the key is not a predefined key, then we must close the handle
+ //
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ return( FALSE );
+ }
+
+ //
+ // Set the value:
+ // .Determine the value name
+ // .Get the value data from Value object
+ // .Create the value entry in the key
+ //
+ ValueName = Value->GetName();
+ DebugPtrAssert( ValueName );
+ ValueNameString = ValueName->QueryWSTR();
+ if( ValueNameString == NULL ) {
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ }
+ DebugPtrAssert( ValueNameString );
+ return( FALSE );
+ }
+ Size = Value->GetData( (PCBYTE *)&Data );
+
+ Status = RegSetValueEx( Handle,
+ ValueNameString,
+ 0, // Value->GetTitleIndex(),
+ Value->GetType(),
+ Data,
+ Size );
+
+ FREE( ValueNameString );
+ if( Status != 0 ) {
+ DebugPrintf( "RegSetValueEx() failed, Status = %#x \n", Status );
+ DebugPrint( "RegSetValueEx() failed" );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+ return( FALSE );
+ }
+ Status = RegFlushKey( Handle );
+ if( Status != 0 ) {
+ DebugPrintf( "RegFlushKey() failed, Status = %#x \n", Status );
+ DebugPrint( "RegFlushKey() failed" );
+ }
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ return( TRUE );
+
+#endif
+}
+
+
+
+BOOLEAN
+REGISTRY::AddValueEntry(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO KeyInfo,
+ IN PCREGISTRY_VALUE_ENTRY Value,
+ IN BOOLEAN FailIfExists,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Add a value entry to an existing key.
+
+Arguments:
+
+
+ PredefinedKey - The root of the tree where the key is.
+
+ KeyInfo - Pointer to the object that contains the information about the
+ the key where the value will be created. This object will be
+ updated to reflect the addition of a new value.
+
+ Value - Pointer to the object that contains the information about the
+ value to be created.
+
+ FailIfExists - A flag that indicates if the method should fail if a
+ value entry with the same name already exists.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+{
+
+#if defined( _AUTOCHECK_ )
+
+ UNREFERENCED_PARAMETER( PredefinedKey );
+ UNREFERENCED_PARAMETER( KeyInfo );
+ UNREFERENCED_PARAMETER( Value );
+ UNREFERENCED_PARAMETER( FailIfExists );
+ UNREFERENCED_PARAMETER( ErrorCode );
+
+ return FALSE;
+
+
+#else
+
+ PCWSTRING ParentName;
+ PCWSTRING KeyName;
+
+
+ DebugPtrAssert( KeyInfo );
+ DebugPtrAssert( Value );
+
+ ParentName = KeyInfo->GetParentName();
+ KeyName = KeyInfo->GetName();
+
+ //
+ // Create the new value entry
+ //
+ if( !AddValueEntry( PredefinedKey,
+ ParentName,
+ KeyName,
+ Value,
+ FailIfExists,
+ ErrorCode ) ) {
+ DebugPrint( "CreateValueEntry() failed \n" );
+ return( FALSE );
+ }
+
+ //
+ // Now that the value entry is created we need to update KeyInfo
+ //
+
+ if( !UpdateKeyInfo( PredefinedKey, KeyInfo, ErrorCode ) ) {
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_KEY_INFO_NOT_UPDATED;
+ }
+ return( FALSE );
+ }
+ return( TRUE );
+
+#endif
+}
+
+
+
+#if 0 // NOT_IMPLEMENTED
+
+BOOLEAN
+REGISTRY::CopyKey(
+ IN PREDEFINED_KEY FromPredefinedKey,
+ IN PCWSTRING FromParentName,
+ IN PCWSTRING FromKeyName,
+ IN PREDEFINED_KEY ToPredefinedKey,
+ IN PCWSTRING ToParentName,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Copy a key and all its sub keys, to another key.
+
+Arguments:
+
+
+ FromPredefinedKey - The root of the tree where the source key is.
+
+ FromParentName - The parent name of the key to be copied.
+
+ FromKeyName - The name of the key to be copied (name relative to its parent).
+
+ ToPredefinedKey - The root of the tree were the new key will be.
+
+ ToParentName - The parent name of the new key.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+
+{
+
+ UNREFERENCED_PARAMETER( FromPredefinedKey );
+ UNREFERENCED_PARAMETER( FromParentName );
+ UNREFERENCED_PARAMETER( FromKeyName );
+ UNREFERENCED_PARAMETER( ToPredefinedKey );
+ UNREFERENCED_PARAMETER( ToParentName );
+ UNREFERENCED_PARAMETER( ErrorCode );
+
+ return FALSE;
+
+}
+
+#endif // NOT_IMPLEMENTED
+
+
+#if 0 // NOT_IMPLEMENTED
+
+BOOLEAN
+REGISTRY::CopyKey(
+ IN PREDEFINED_KEY FromPredefinedKey,
+ IN PCWSTRING FromParentName,
+ IN PCWSTRING FromKeyName,
+ IN PREDEFINED_KEY ToPredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO ToParentName,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Copy a key and all its sub keys, to another key.
+
+Arguments:
+
+
+ FromPredefinedKey - The root of the tree where the source key is.
+
+ FromParentName - The parent name of the key to be copied.
+
+ FromKeyName - The name of the key to be copied (name relative to its parent).
+
+ ToPredefinedKey - The root of the tree were the new key will be.
+
+ ToParentKeyInfo - Pointer to the object that contains the information about
+ the parent key of the new key. The information in this
+ object will be updated to reflect the addition of a new
+ subkey.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+
+{
+ UNREFERENCED_PARAMETER( FromPredefinedKey );
+ UNREFERENCED_PARAMETER( FromParentName );
+ UNREFERENCED_PARAMETER( FromKeyName );
+ UNREFERENCED_PARAMETER( ToPredefinedKey);
+ UNREFERENCED_PARAMETER( ToParentName );
+ UNREFERENCED_PARAMETER( ErrorCode );
+
+ return FALSE;
+}
+#endif // NOT_IMPLEMENTED
+
+
+
+#if 0 // NOT_IMPLEMENTED
+
+BOOLEAN
+REGISTRY::CopyAllValueEntries(
+ IN PREDEFINED_KEY FromPredefinedKey,
+ IN PCWSTRING FromParentName,
+ IN PCWSTRING FromKeyName,
+ IN PREDEFINED_KEY ToPredefinedKey,
+ IN PCWSTRING ToParentName,
+ IN PCWSTRING ToKeyName,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Copy all value entries from a key to another key.
+
+Arguments:
+
+
+ FromPredefinedKey - The root of the tree where the source key is.
+
+ FromParentName - The parent name of the source key.
+
+ FromKeyName - The name of the source key.
+
+ ToPredefinedKey - The root of the tree where the destination key is.
+
+ ToParentName - The parent name of the destination key.
+
+ ToKeyName - The name of the destination key.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+
+{
+
+ UNREFERENCED_PARAMETER( FromPredefinedKey );
+ UNREFERENCED_PARAMETER( FromParentName );
+ UNREFERENCED_PARAMETER( FromKeyName );
+ UNREFERENCED_PARAMETER( ToPredefinedKey);
+ UNREFERENCED_PARAMETER( ToParentName );
+ UNREFERENCED_PARAMETER( ToKeyName );
+ UNREFERENCED_PARAMETER( ErrorCode );
+
+ return FALSE;
+}
+#endif // NOT_IMPLEMENTED
+
+
+#if 0 // NOT_IMPLEMENTED
+
+BOOLEAN
+REGISTRY::CopyAllValueEntries(
+ IN PREDEFINED_KEY FromPredefinedKey,
+ IN PCWSTRING FromParentName,
+ IN PCWSTRING FromKeyName,
+ IN PREDEFINED_KEY ToPredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO ToKeyInfo,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Copy all value entries from a key to another key.
+
+Arguments:
+
+
+ FromPredefinedKey - The root of the tree where the source key is.
+
+ FromParentName - The parent name of the source key.
+
+ FromKeyName - The name of the source key.
+
+ ToPredefinedKey - The root of the tree where the destination key is.
+
+ ToKeyInfo - Pointer to the object that contains the information about
+ the destination key. This object will be updated to reflect
+ the addition of the new values.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+
+{
+ UNREFERENCED_PARAMETER( FromPredefinedKey );
+ UNREFERENCED_PARAMETER( FromParentName );
+ UNREFERENCED_PARAMETER( FromKeyName );
+ UNREFERENCED_PARAMETER( ToPredefinedKey );
+ UNREFERENCED_PARAMETER( ToKeyInfo );
+ UNREFERENCED_PARAMETER( ErrorCode );
+
+ return FALSE;
+}
+
+#endif // NOT_IMPLEMENTED
+
+
+
+#if 0 // NOT_IMPLEMENTED
+
+BOOLEAN
+REGISTRY::CopyOneValueEntry(
+ IN PREDEFINED_KEY FromPredefinedKey,
+ IN PCWSTRING FromParentName,
+ IN PCWSTRING FromKeyName,
+ IN PCWSTRING FromValueName,
+ IN PREDEFINED_KEY ToPredefinedKey,
+ IN PCWSTRING ToParentName,
+ IN PCWSTRING ToKeyName,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Copy one value entry from a key to another key.
+
+Arguments:
+
+
+ FromPredefinedKey - The root of the tree where the source key is.
+
+ FromParentKeyName - The parent name of the source key.
+
+ FromKeyName - The name of the source key.
+
+ FromValueName - The name of the value to be copied (cannot be NULL).
+
+ ToPredefinedKey - The root of the tree where the destination key is.
+
+ ToParentName - The parent name of the destination key.
+
+ ToKeyName - The name of the destination key.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+
+{
+ UNREFERENCED_PARAMETER( FromPredefinedKey );
+ UNREFERENCED_PARAMETER( FromParentName );
+ UNREFERENCED_PARAMETER( FromKeyName );
+ UNREFERENCED_PARAMETER( FromValueName );
+ UNREFERENCED_PARAMETER( ToPredefinedKey );
+ UNREFERENCED_PARAMETER( ToParentName );
+ UNREFERENCED_PARAMETER( ToKeyName );
+ UNREFERENCED_PARAMETER( ErrorCode );
+
+ return FALSE;
+}
+
+#endif // NOT_IMPLEMENTED
+
+
+#if 0 // NOT_IMPLEMENTED
+
+BOOLEAN
+REGISTRY::CopyOneValueEntry(
+ IN PREDEFINED_KEY FromPredefinedKey,
+ IN PCWSTRING FromParentName,
+ IN PCWSTRING FromKeyName,
+ IN PCWSTRING FromValueName,
+ IN PREDEFINED_KEY ToPredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO ToKeyInfo,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Copy one value entry from a key to another key.
+
+Arguments:
+
+
+ FromPredefinedKey - The root of the tree where the source key is.
+
+ FromParentKeyName - The parent name of the source key.
+
+ FromKeyName - The name of the source key.
+
+ FromValueName - The name of the value to be copied (can be NULL).
+
+ ToPredefinedKey - The root of the tree where the destination key is.
+
+ ToKeyInfo - Pointer to the object that contains the information about
+ the destination key. This object will be updated to reflect
+ the addition of the new values.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+
+{
+ UNREFERENCED_PARAMETER( FromPredefinedKey );
+ UNREFERENCED_PARAMETER( FromParentName );
+ UNREFERENCED_PARAMETER( FromKeyName );
+ UNREFERENCED_PARAMETER( FromValueName );
+ UNREFERENCED_PARAMETER( ToPredefinedKey );
+ UNREFERENCED_PARAMETER( ToKeyInfo );
+ UNREFERENCED_PARAMETER( ErrorCode );
+
+ return FALSE;
+}
+
+#endif // NOT_IMPLEMENTED
+
+
+BOOLEAN
+REGISTRY::CreateKey(
+ IN OUT PREGISTRY_KEY_INFO NewSubKeyInfo,
+ IN PREDEFINED_KEY PredefinedKey,
+ OUT PULONG ErrorCode,
+ IN BOOLEAN Volatile
+ )
+
+/*++
+
+Routine Description:
+
+ Add a subkey to an existing key, and update NewSubkeyInfo to reflect the
+ creation of the new key.
+
+Arguments:
+
+
+ PredefinedKey - The root of the tree where the key is.
+
+ NewSubKeyInfo - Pointer to the object that contains the information about
+ the subkey to be created. This object will be updated to
+ reflect the new information about the subkey created.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+ Volatile - Volatile flag.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+{
+
+
+#if defined( _AUTOCHECK_ )
+
+
+ PWSTRING CompleteKeyName;
+ PWSTR CompleteKeyNameString;
+ PWSTR ClassString;
+ UNICODE_STRING UnicodeKeyName;
+ UNICODE_STRING UnicodeClass;
+ OBJECT_ATTRIBUTES ObjAttr;
+ HANDLE Handle;
+ ULONG Length;
+ NTSTATUS Status;
+ BYTE KeyInfo[ KEY_BASIC_SIZE ];
+
+
+
+ if ( !NewSubKeyInfo ) {
+ return FALSE;
+ }
+ if ( !NewSubKeyInfo ||
+ !(CompleteKeyName = BuildCompleteName( NewSubKeyInfo->GetParentName(), NewSubKeyInfo->GetName() ) ) ||
+ !(CompleteKeyNameString = CompleteKeyName->QueryWSTR() ) ||
+ !(ClassString = NewSubKeyInfo->GetClass()->QueryWSTR() )
+ ) {
+
+ DELETE( CompleteKeyName );
+ FREE( CompleteKeyNameString );
+ FREE( ClassString );
+
+ return FALSE;
+ }
+
+
+
+ //
+ // Initialize the OBJECT_ATTRIBUTES structure
+ //
+ RtlInitUnicodeString( &UnicodeKeyName, CompleteKeyNameString );
+ RtlInitUnicodeString( &UnicodeClass, ClassString );
+
+ InitializeObjectAttributes( &ObjAttr,
+ &UnicodeKeyName,
+ OBJ_CASE_INSENSITIVE,
+ 0,
+ 0 );
+
+
+ Status = NtCreateKey( &Handle,
+ KEY_READ,
+ &ObjAttr,
+ NewSubKeyInfo->GetTitleIndex(),
+ &UnicodeClass,
+ Volatile ? REG_OPTION_VOLATILE : REG_OPTION_NON_VOLATILE,
+ NULL );
+
+
+ DELETE( CompleteKeyName );
+ FREE( CompleteKeyNameString );
+ FREE( ClassString );
+
+
+ if ( !NT_SUCCESS( Status ) ) {
+ if ( ErrorCode ) {
+ *ErrorCode = Status;
+ }
+
+ return FALSE;
+ }
+
+
+ Status = NtQueryKey( Handle,
+ KeyBasicInformation,
+ &KeyInfo,
+ KEY_BASIC_SIZE,
+ &Length );
+
+ NtClose( Handle );
+
+ if ( !NT_SUCCESS( Status ) ) {
+ if ( ErrorCode ) {
+ *ErrorCode = Status;
+ }
+
+ return FALSE;
+ }
+
+
+ NewSubKeyInfo->SetNumberOfSubKeys( 0 );
+ NewSubKeyInfo->SetNumberOfValues( 0 );
+ NewSubKeyInfo->SetLastWriteTime( ((PKEY_BASIC_INFORMATION)KeyInfo)->LastWriteTime );
+
+ return TRUE;
+
+
+
+#else
+
+ DWORD Status;
+ HKEY ParentHandle;
+ HKEY SubKeyHandle;
+ PCWSTRING ParentName;
+ PCWSTRING SubKeyName;
+ PWSTR SubKeyNameString;
+ PCWSTRING Class;
+ PWSTR ClassString;
+ TIMEINFO LastWriteTime;
+
+ PWSTR lpClass;
+ DWORD cbClass;
+
+ DWORD cSubKeys;
+ DWORD cbMaxSubKeyLen;
+ DWORD cbMaxClassLen;
+ DWORD cValues;
+ DWORD cbMaxValueNameLen;
+ DWORD cbMaxValueLen;
+ DWORD cbSecurityDescriptor;
+ FILETIME ftLastWriteTime;
+ DSTRING NullString;
+
+
+
+
+ DebugPtrAssert( NewSubKeyInfo );
+
+ //
+ // Open a handle to the parent key
+ //
+ if( !NullString.Initialize( "" ) ) {
+ DebugPrint( "NullString.Initialize() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_INITIALIZATION_FAILURE;
+ }
+ return( FALSE );
+ }
+ ParentName = NewSubKeyInfo->GetParentName();
+ DebugPtrAssert( ParentName );
+
+ if( !OpenKey( PredefinedKey,
+ ParentName,
+ &NullString,
+ KEY_CREATE_SUB_KEY,
+ &ParentHandle,
+ ErrorCode ) ) {
+ DebugPrint( "OpenKey() failed" );
+ return( FALSE );
+ }
+
+ //
+ // To Create the subkey, we need to:
+ //
+ // .Get its name
+ // .Get its class
+ // .Call the API to create the subkey
+ //
+
+ SubKeyName = ( PWSTRING )NewSubKeyInfo->GetName();
+ DebugPtrAssert( SubKeyName );
+ SubKeyNameString = SubKeyName->QueryWSTR();
+
+ if( SubKeyNameString == NULL ) {
+ if( ParentHandle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( ParentHandle );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ }
+ DebugPtrAssert( SubKeyNameString );
+ return( FALSE );
+ }
+
+ Class = NewSubKeyInfo->GetClass();
+ DebugPtrAssert( Class );
+ ClassString = Class->QueryWSTR();
+ if( ClassString == NULL ) {
+ if( ParentHandle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( ParentHandle );
+ }
+ FREE( SubKeyNameString );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ }
+ DebugPtrAssert( SubKeyNameString );
+ return( FALSE );
+ }
+
+ Status = RegCreateKeyEx( ParentHandle,
+ SubKeyNameString,
+ 0, // NewSubKeyInfo->GetTitleIndex(),
+ ClassString,
+ Volatile ? REG_OPTION_VOLATILE : REG_OPTION_NON_VOLATILE,
+ KEY_READ,
+ ( PSECURITY_ATTRIBUTES )NewSubKeyInfo->GetSecurityAttributes(),
+ &SubKeyHandle,
+ NULL );
+ FREE( ClassString );
+ FREE( SubKeyNameString );
+ if( Status != 0 ) {
+ DebugPrint( "RegCreateKey() failed" );
+ DebugPrintf( "RegCreateKeyEx() returned Status = %#x", Status );
+ if( ParentHandle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( ParentHandle );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+ return( FALSE );
+ }
+ Status = RegFlushKey( ParentHandle );
+ if( Status != 0 ) {
+ DebugPrintf( "RegFlushKey() failed, Status = %#x \n", Status );
+ DebugPrint( "RegFlushKey() failed" );
+ }
+
+
+ //
+ // Update NewSubKeyInfo:
+ //
+ // .Call RegQueryInfoKey to retrieve the LastWriteTime
+ //
+ //
+
+ cbClass = ( Class->QueryChCount() + 1 );
+ lpClass = ( PWSTR ) MALLOC( ( size_t )( cbClass*sizeof( WCHAR ) ) );
+ if( lpClass == NULL ) {
+ if( ParentHandle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( ParentHandle );
+ }
+ RegCloseKey( SubKeyHandle );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ }
+ DebugPtrAssert( lpClass );
+ return( FALSE );
+ }
+
+ Status = RegQueryInfoKey( SubKeyHandle,
+ ( LPWSTR )lpClass,
+ &cbClass,
+ NULL,
+ &cSubKeys,
+ &cbMaxSubKeyLen,
+ &cbMaxClassLen,
+ &cValues,
+ &cbMaxValueNameLen,
+ &cbMaxValueLen,
+ &cbSecurityDescriptor,
+ &ftLastWriteTime );
+
+ RegCloseKey( SubKeyHandle );
+ FREE( lpClass );
+ if( ParentHandle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( ParentHandle );
+ }
+ if( Status != 0 ) {
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_KEY_INFO_NOT_UPDATED;
+ }
+ return( FALSE );
+ }
+
+ if( !LastWriteTime.Initialize( &ftLastWriteTime ) ) {
+ DebugPrint( "LastWriteTime.Initialize( &ftLastWriteTime ) failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_KEY_INFO_NOT_UPDATED;
+ }
+ }
+
+ NewSubKeyInfo->SetNumberOfSubKeys( 0 );
+ NewSubKeyInfo->SetNumberOfValues( 0 );
+ NewSubKeyInfo->PutLastWriteTime( &LastWriteTime );
+ NewSubKeyInfo->SetKeyInitializedFlag( TRUE );
+ return( TRUE );
+
+#endif
+
+}
+
+
+
+BOOLEAN
+REGISTRY::CreateKey(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO KeyInfo,
+ IN OUT PREGISTRY_KEY_INFO NewSubKeyInfo,
+ OUT PULONG ErrorCode,
+ IN BOOLEAN Volatile
+ )
+
+/*++
+
+Routine Description:
+
+ Add a subkey to an existing key.
+
+Arguments:
+
+
+ PredefinedKey - The root of the tree where the key is.
+
+ KeyInfo - Pointer to the object that contains the information about the
+ the key where the subkey will be created. This object will be
+ updated to reflect the addition of a new subkey.
+
+ NewSubKeyInfo - Pointer to the object that contains the information about
+ the subkey to be created. This object will be updated to
+ reflect the new information about the subkey created.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+ Volatile - Volatile flag
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+{
+
+#if defined( _AUTOCHECK_ )
+
+ UNREFERENCED_PARAMETER( PredefinedKey );
+ UNREFERENCED_PARAMETER( KeyInfo );
+ UNREFERENCED_PARAMETER( NewSubKeyInfo );
+ UNREFERENCED_PARAMETER( ErrorCode );
+
+ return FALSE;
+
+#else
+
+
+ PCTIMEINFO NewLastWriteTime;
+
+ DebugPtrAssert( KeyInfo );
+ DebugPtrAssert( NewSubKeyInfo );
+
+
+ if( !CreateKey( NewSubKeyInfo,
+ PredefinedKey,
+ ErrorCode,
+ Volatile ) ) {
+
+ DebugPrint( "CreateSubKey() failed" );
+ return( FALSE );
+ }
+
+ NewLastWriteTime = NewSubKeyInfo->GetLastWriteTime();
+ DebugPtrAssert( NewLastWriteTime );
+
+ ( KeyInfo->_LastWriteTime ).Initialize( NewLastWriteTime );
+ KeyInfo->SetNumberOfSubKeys( KeyInfo->GetNumberOfSubKeys() + 1 );
+ return( TRUE );
+
+#endif
+}
+
+
+
+BOOLEAN
+REGISTRY::DeleteKey(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PCWSTRING ParentKeyName,
+ IN PCWSTRING KeyName,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Delete a key and all its subkeys.
+
+Arguments:
+
+
+ PredefinedKey - The root of the tree where the key is.
+
+ ParentKeyName - The parent name of the key. It can be NULL, and in this
+ case the key to be deleted is a subkey of a predefined
+ key.
+
+ KeyName - The name of the key to be deleted (cannot be NULL). This name
+ is relative to its parent.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+{
+#if defined( _AUTOCHECK_ )
+
+ UNREFERENCED_PARAMETER( PredefinedKey );
+ UNREFERENCED_PARAMETER( ParentKeyName );
+ UNREFERENCED_PARAMETER( KeyName );
+ UNREFERENCED_PARAMETER( ErrorCode );
+
+ return FALSE;
+
+#else
+
+ PWSTR KeyNameWSTR;
+ HKEY ParentHandle;
+ HKEY KeyHandle;
+ DWORD Status;
+ DSTRING NullString;
+
+
+ DebugPtrAssert( ParentKeyName );
+ DebugPtrAssert( KeyName );
+
+
+ //
+ // Open a handle to the parent key
+ //
+
+ if( !NullString.Initialize( "" ) ) {
+ DebugPrint( "NullString.Initialize() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_INITIALIZATION_FAILURE;
+ }
+ return( FALSE );
+ }
+ if( !OpenKey( PredefinedKey,
+ ParentKeyName,
+ &NullString,
+ KEY_READ,
+ &ParentHandle,
+ ErrorCode ) ) {
+ DebugPrint( "OpenKey() failed" );
+ return( FALSE );
+ }
+
+ //
+ // We also need a handle to the key to be deleted
+ //
+
+
+ if( !OpenKey( PredefinedKey,
+ ParentKeyName,
+ KeyName,
+ READ_CONTROL | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, // MAXIMUM_ALLOWED,
+ &KeyHandle,
+ ErrorCode ) ) {
+ DebugPrint( "OpenKey() failed" );
+ if( ParentHandle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( ParentHandle );
+ }
+ return( FALSE );
+ }
+
+
+ //
+ // Delete the children
+ //
+ Status = DeleteTree( KeyHandle );
+ if( Status != 0 ) {
+ DebugPrintf( "DeleteTree() failed, Status = %#x \n", Status );
+ DebugPrintf( "DeleteTree() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+
+ }
+ if( ParentHandle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( ParentHandle );
+ }
+ RegFlushKey( KeyHandle );
+ RegCloseKey( KeyHandle );
+ return( FALSE );
+ }
+ RegCloseKey( KeyHandle );
+
+ //
+ // Delete the key
+ //
+ KeyNameWSTR = KeyName->QueryWSTR();
+ if( KeyNameWSTR == NULL ) {
+ DebugPrint( "KeyName->QueryWSTR() failed" );
+ DebugPtrAssert( KeyNameWSTR );
+ if( ParentHandle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( ParentHandle );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ }
+ return( FALSE );
+ }
+
+ Status = RegDeleteKey( ParentHandle, KeyNameWSTR );
+ FREE( KeyNameWSTR );
+ if( Status != 0 ) {
+ DebugPrintf( "RegDeleteKey() failed, Status = %#x \n", Status );
+ DebugPrint( "RegDeleteKey() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+ if( ParentHandle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( ParentHandle );
+ }
+ return( FALSE );
+ }
+ Status = RegFlushKey( ParentHandle );
+ if( Status != 0 ) {
+ DebugPrintf( "RegFlushKey() failed, Status = %#x \n", Status );
+ DebugPrint( "RegFlushKey() failed" );
+ }
+ if( ParentHandle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( ParentHandle );
+ }
+ return( TRUE );
+
+#endif
+}
+
+
+
+BOOLEAN
+REGISTRY::DeleteKey(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO ParentKeyInfo,
+ IN PCWSTRING KeyName,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Delete a key and all its subkeys, and update ParentKeyInfo.
+
+Arguments:
+
+
+ PredefinedKey - The root of the tree where the key is.
+
+ KeyInfo - Pointer to the object that contains the information about the
+ the key that contains the subkey to be deleted. This object
+ will be updated to reflect the deletion of a subkey.
+
+ KeyName - Name of the key to be deleted (cannot be NULL )
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+{
+#if defined( _AUTOCHECK_ )
+
+ UNREFERENCED_PARAMETER( PredefinedKey );
+ UNREFERENCED_PARAMETER( ParentKeyInfo );
+ UNREFERENCED_PARAMETER( KeyName );
+ UNREFERENCED_PARAMETER( ErrorCode );
+
+ return FALSE;
+
+#else
+
+ PWSTRING ParentName;
+ PCWSTRING TmpName;
+ PCWSTRING TmpName1;
+
+ DebugPtrAssert( ParentKeyInfo );
+ DebugPtrAssert( KeyName );
+
+ TmpName = ParentKeyInfo->GetParentName();
+ DebugPtrAssert( TmpName );
+ TmpName1 = ParentKeyInfo->GetName();
+ DebugPtrAssert( TmpName1 );
+
+ ParentName = BuildCompleteName( TmpName, TmpName1 );
+ if( ParentName == NULL ) {
+ DebugPrint( "BuildCompleteName() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_INITIALIZATION_FAILURE;
+ }
+ return( FALSE );
+ }
+
+ if( !DeleteKey( PredefinedKey, ParentName, KeyName, ErrorCode ) ) {
+ DebugPrint( "DeleteKey() failed" );
+ DELETE( ParentName );
+ return( FALSE );
+ }
+ DELETE( ParentName );
+
+ //
+ // Update KeyInfo
+ //
+
+ if( !UpdateKeyInfo( PredefinedKey, ParentKeyInfo, ErrorCode ) ) {
+ DebugPrint( "UpdateKeyInfo() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_KEY_INFO_NOT_UPDATED;
+ }
+ return( FALSE );
+ }
+ return( TRUE );
+
+#endif
+}
+
+
+
+BOOLEAN
+REGISTRY::DeleteValueEntry(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PCWSTRING ParentKeyName,
+ IN PCWSTRING KeyName,
+ IN PCWSTRING ValueName,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Delete a value entry from a key.
+
+Arguments:
+
+
+ PredefinedKey - The root of the tree where the key is.
+
+ ParentKeyName - The parent name of the key (can be NULL ).
+
+ KeyName - The name of that contains the Value (cannot be NULL).
+
+ ValueName - The name of the value to be deleted.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+{
+
+#if defined( _AUTOCHECK_ )
+
+ PWSTR ValueNameString = NULL;
+ UNICODE_STRING UnicodeValueName;
+ HANDLE Handle;
+ NTSTATUS Status;
+ BOOLEAN Done = FALSE;
+
+
+ if ( !OpenKey( ParentKeyName, KeyName, KEY_SET_VALUE, &Handle, ErrorCode ) ) {
+ return FALSE;
+ }
+
+
+ if ( ValueName &&
+ (ValueNameString = ValueName->QueryWSTR() )
+ ) {
+
+ RtlInitUnicodeString( &UnicodeValueName, ValueNameString );
+
+ //
+ // Delete the value
+ //
+ Status = NtDeleteValueKey( Handle, &UnicodeValueName );
+
+
+ if ( NT_SUCCESS( Status ) ) {
+
+ Done = TRUE;
+
+ } else {
+
+ if ( ErrorCode != NULL ) {
+ *ErrorCode = Status;
+ }
+ }
+ }
+
+ NtClose( Handle );
+ FREE( ValueNameString );
+
+ return Done;
+
+
+#else
+
+
+ PWSTR ValueNameString;
+ DWORD Status;
+ HKEY Handle;
+
+
+ DebugPtrAssert( ValueName );
+
+ if( !OpenKey( PredefinedKey,
+ ParentKeyName,
+ KeyName,
+ KEY_SET_VALUE,
+ &Handle,
+ ErrorCode ) ) {
+ DebugPrint( "OpenKey() failed" );
+ return( FALSE );
+ }
+
+ //
+ // Get the value name
+ //
+
+ ValueNameString = ValueName->QueryWSTR();
+ if( ValueNameString == NULL ) {
+ DebugPrint( "ValueName->QueryWSTR() failed" );
+ DebugPtrAssert( ValueNameString );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ }
+ return( FALSE );
+ }
+
+ //
+ // Delete the value
+ //
+
+ Status = RegDeleteValue( Handle, ValueNameString );
+ if( Status != 0 ) {
+ DebugPrint( "RegDeleteValue() failed" );
+ DebugPrintf( "RegDeleteValue() failed, Status = %#x \n", Status );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ FREE( ValueNameString );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+ return( FALSE );
+ }
+ Status = RegFlushKey( Handle );
+ if( Status != 0 ) {
+ DebugPrintf( "RegFlushKey() failed, Status = %#x \n" );
+ DebugPrint( "RegFlushKey() failed" );
+ }
+ FREE( ValueNameString );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ return( TRUE );
+
+#endif
+}
+
+
+
+BOOLEAN
+REGISTRY::DeleteValueEntry(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO KeyInfo,
+ IN PCWSTRING Value,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Delete a value entry from a key.
+
+Arguments:
+
+
+ PredefinedKey - The root of the tree where the key is.
+
+ KeyInfo - Pointer to the object that contains the information about the
+ the key that has the value to be deleted.. This object will be
+ updated to reflect the deletion of a new value.
+
+ Value - Name of the value to be deleted.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+{
+#if defined( _AUTOCHECK_ )
+
+ UNREFERENCED_PARAMETER( PredefinedKey );
+ UNREFERENCED_PARAMETER( KeyInfo );
+ UNREFERENCED_PARAMETER( Value );
+ UNREFERENCED_PARAMETER( ErrorCode);
+
+ return FALSE;
+
+#else
+
+ DebugPtrAssert( KeyInfo );
+ DebugPtrAssert( Value );
+
+
+ PCWSTRING TmpString;
+ PCWSTRING TmpString1;
+
+ TmpString = KeyInfo->GetParentName();
+ DebugPtrAssert( TmpString );
+ TmpString1 = KeyInfo->GetName();
+ DebugPtrAssert( TmpString1 );
+
+ if( !DeleteValueEntry( PredefinedKey, TmpString, TmpString1, Value, ErrorCode ) ) {
+ DebugPrint( "DeleteKey() failed" );
+ return( FALSE );
+ }
+ if( !UpdateKeyInfo( PredefinedKey, KeyInfo, ErrorCode ) ) {
+ if( ( ErrorCode != NULL ) && ( *ErrorCode != REGISTRY_ERROR_OUTOFMEMORY ) ) {
+ *ErrorCode = REGISTRY_ERROR_KEY_INFO_NOT_UPDATED;
+ }
+ return( FALSE );
+ }
+ return( TRUE );
+
+#endif
+}
+
+
+BOOLEAN
+REGISTRY::DoesKeyExist(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PCWSTRING ParentName,
+ IN PCWSTRING KeyName,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Determine whether a value entry exists.
+
+Arguments:
+
+
+ PredefinedKey - The root of the tree where the key is.
+
+ ParentName - The parent name of the key we want to check the existence.
+
+ KeyName - The name of the key we want to check the existence.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+{
+
+#if defined ( _AUTOCHECK_ )
+
+ HANDLE Handle;
+
+
+ if ( !OpenKey( ParentName, KeyName, KEY_QUERY_VALUE, &Handle, ErrorCode ) ) {
+ return FALSE;
+ }
+
+ NtClose( Handle );
+
+ return TRUE;
+
+
+#else
+
+
+ HKEY Handle;
+ ULONG Status;
+
+ DebugPtrAssert( ParentName );
+ DebugPtrAssert( KeyName );
+
+ //
+ // Try to open the key, if it doesn't fail, or if it fails due to
+ // lack of permission, then the key exists
+ //
+ if( OpenKey( PredefinedKey,
+ ParentName,
+ KeyName,
+ KEY_READ, // MAXIMUM_ALLOWED,
+ &Handle,
+ &Status ) ) {
+ RegCloseKey( Handle );
+ return( TRUE );
+ } else if( Status != REGISTRY_ERROR_ACCESS_DENIED ) {
+ if( ErrorCode != NULL ) {
+ *ErrorCode = Status;
+ }
+ return( FALSE );
+ } else {
+ return( TRUE );
+ }
+#endif
+
+}
+
+
+
+
+BOOLEAN
+REGISTRY::DoesValueExist(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PCWSTRING ParentName,
+ IN PCWSTRING KeyName,
+ IN PCWSTRING ValueName,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Determine whether a value entry exists.
+
+Arguments:
+
+
+ PredefinedKey - The root of the tree where the key is.
+
+ ParentName - The the parent name of the key that might contain the value.
+
+ KeyName - The name of the key that might contain the value.
+
+ ValueName - Name of the value we want to check the existence.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+{
+
+#if defined( _AUTOCHECK_ )
+
+
+ PWSTR ValueNameString = NULL;
+ UNICODE_STRING UnicodeValueName;
+ HANDLE Handle;
+ NTSTATUS Status;
+ ULONG Length;
+ BOOLEAN Done = FALSE;
+ BYTE ValueInfo[ VALUE_BASIC_SIZE ];
+
+
+
+ if ( !OpenKey( ParentName, KeyName, KEY_QUERY_VALUE, &Handle, ErrorCode ) ) {
+ return FALSE;
+ }
+
+ if ( ValueName &&
+ (ValueNameString = ValueName->QueryWSTR() )
+ ) {
+
+ RtlInitUnicodeString( &UnicodeValueName, ValueNameString );
+
+ //
+ // At this point we have the handle to the key.
+ // Let's check the existence of the value
+ //
+ Status = NtQueryValueKey( Handle,
+ &UnicodeValueName,
+ KeyValueBasicInformation,
+ &ValueInfo,
+ VALUE_BASIC_SIZE,
+ &Length );
+
+ if ( NT_SUCCESS( Status ) ) {
+
+ Done = TRUE;
+
+ } else {
+
+ if ( ErrorCode != NULL ) {
+ *ErrorCode = Status;
+ }
+ }
+ }
+
+ NtClose( Handle );
+ FREE( ValueNameString );
+
+ return Done;
+
+
+#else
+
+ HKEY Handle;
+ PWSTR ValueNameString;
+ DWORD Status;
+
+ DebugPtrAssert( ParentName );
+ DebugPtrAssert( KeyName );
+ DebugPtrAssert( ValueName );
+
+
+ if( !OpenKey( PredefinedKey,
+ ParentName,
+ KeyName,
+ KEY_QUERY_VALUE,
+ &Handle,
+ ErrorCode ) ) {
+ DebugPrint( "OpenKey failed" );
+ return( FALSE );
+ }
+
+ //
+ // Check the existence of the value on the key
+ //
+ ValueNameString = ValueName->QueryWSTR();
+ if( ValueNameString == NULL ) {
+ DebugPrint( "ValueName->QueryWSTR() failed" );
+ DebugPtrAssert( ValueNameString );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ }
+ return( FALSE );
+ }
+
+ Status = RegQueryValueEx( Handle,
+ ValueNameString,
+ NULL,
+ NULL,
+ NULL,
+ NULL );
+ FREE( ValueNameString );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ //
+ // If we can successfully query the key, then it exists.
+ // Otherwise, we have to examine the status code returned by the
+ // API to determine if the value doesn't exist, or if another error
+ // has occurred
+ //
+ if( Status != 0 ) {
+ if( ErrorCode != NULL ) {
+ if( Status == ERROR_PATH_NOT_FOUND ) {
+ *ErrorCode = REGISTRY_ERROR_VALUE_DOESNT_EXIST;
+ } else {
+// DebugPrintf( "RegQueryValueEx() failed, Status = %#x \n", Status );
+// DebugPrint( "RegQueryValueEx() failed" );
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+ }
+ return( FALSE );
+ }
+ return( TRUE );
+
+#endif
+}
+
+
+
+#if 0 // NOT_IMPLEMENTED
+BOOLEAN
+REGISTRY::MoveKey(
+ IN PREDEFINED_KEY FromPredefinedKey,
+ IN PCWSTRING FromParentName,
+ IN PCWSTRING FromKeyName,
+ IN PREDEFINED_KEY ToPredefinedKey,
+ IN PCWSTRING ToParentName,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Move a key and all its sub keys, to another key.
+
+Arguments:
+
+
+ FromPredefinedKey - The root of the tree where the source key is.
+
+ FromParentName - The parent name of the key to be moved.
+
+ FromKeyName - The name of the key to be moved (name relative to its parent).
+
+ ToPredefinedKey - The root of the tree were the new key will be.
+
+ ToParentName - The parent name of the new key.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+
+{
+ UNREFERENCED_PARAMETER( FromPredefinedKey );
+ UNREFERENCED_PARAMETER( FromParentName );
+ UNREFERENCED_PARAMETER( FromKeyName );
+ UNREFERENCED_PARAMETER( ToPredefinedKey );
+ UNREFERENCED_PARAMETER( ToParentName );
+ UNREFERENCED_PARAMETER( ErrorCode );
+
+ return FALSE;
+}
+
+#endif // NOT_IMPLEMENTED
+
+
+#if 0 // NOT_IMPLEMENTED
+
+BOOLEAN
+REGISTRY::MoveKey(
+ IN PREDEFINED_KEY FromPredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO FromParentKeyInfo,
+ IN PCWSTRING FromKeyName,
+ IN PREDEFINED_KEY ToPredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO ToParentName,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Move a key and all its sub keys, to another key.
+
+Arguments:
+
+
+ FromPredefinedKey - The root of the tree where the source key is.
+
+ FromParentKeyInfo - Pointer to the object that contains information about
+ the key that holds the subkey to be moved.
+ The information in this object will be updated to reflect
+ the removal of a subkey.
+
+ FromKeyName - The name of the key to be copied (name relative to its parent).
+
+ ToPredefinedKey - The root of the tree were the new key will be.
+
+ ToParentKeyInfo - Pointer to the object that contains the information about
+ the parent key of the new key. The information in this
+ object will be updated to reflect the addition of a new
+ subkey.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+
+{
+ UNREFERENCED_PARAMETER( FromPredefinedKey );
+ UNREFERENCED_PARAMETER( FromParentKeyInfo );
+ UNREFERENCED_PARAMETER( FromKeyName );
+ UNREFERENCED_PARAMETER( ToPredefinedKey );
+ UNREFERENCED_PARAMETER( ToParentName );
+ UNREFERENCED_PARAMETER( ErrorCode );
+
+ return FALSE;
+}
+
+#endif // NOT_IMPLEMENTED
+
+
+#if 0 // NOT_IMPLEMENTED
+
+BOOLEAN
+REGISTRY::MoveAllValueEntries(
+ IN PREDEFINED_KEY FromPredefinedKey,
+ IN PCWSTRING FromParentName,
+ IN PCWSTRING FromKeyName,
+ IN PREDEFINED_KEY ToPredefinedKey,
+ IN PCWSTRING ToParentName,
+ IN PCWSTRING ToKeyName,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Copy one or all value entries from a key to another key.
+
+Arguments:
+
+
+ FromPredefinedKey - The root of the tree where the source key is.
+
+ FromParentName - The parent name of the source key (can be NULL ).
+
+ FromKeyName - The name of the source key (cannot be NULL).
+
+ ToPredefinedKey - The root of the tree where the destination key is.
+
+ ToParentName - The parent name of the destination key (can be NULL ).
+
+ ToKeyName - The name of the destination key (cannot be NULL )
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+
+{
+
+ UNREFERENCED_PARAMETER( FromPredefinedKey );
+ UNREFERENCED_PARAMETER( FromParentName );
+ UNREFERENCED_PARAMETER( FromKeyName );
+ UNREFERENCED_PARAMETER( ToPredefinedKey );
+ UNREFERENCED_PARAMETER( ToParentName );
+ UNREFERENCED_PARAMETER( ToKeyName );
+ UNREFERENCED_PARAMETER( ErrorCode );
+
+ return FALSE;
+}
+
+#endif
+
+
+#if 0 // NOT_IMPLEMENTED
+
+BOOLEAN
+REGISTRY::MoveAllValueEntries(
+ IN PREDEFINED_KEY FromPredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO FromKeyInfo,
+ IN PREDEFINED_KEY ToPredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO ToKeyInfo,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Move one or all value entries from a key to another key.
+
+Arguments:
+
+
+ FromPredefinedKey - The root of the tree where the source key is.
+
+ FromKeyInfo - Pointer to the object that contains the information about
+ the source key. The information in this object will be
+ updated to reflect the deletion of values.
+
+ ToPredefinedKey - The root of the tree where the destination key is.
+
+ ToKeyInfo - Pointer to the object that contains the information about
+ the destination key. This object will be updated to reflect
+ the addition of the new values.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+
+{
+ UNREFERENCED_PARAMETER( FromPredefinedKey );
+ UNREFERENCED_PARAMETER( FromKeyInfo );
+ UNREFERENCED_PARAMETER( ToPredefinedKey );
+ UNREFERENCED_PARAMETER( ToKeyInfo );
+ UNREFERENCED_PARAMETER( ErrorCode );
+
+ return FALSE;
+}
+
+#endif // NOT_IMPLEMENTED
+
+
+BOOLEAN
+REGISTRY::QueryKeyInfo(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PCWSTRING ParentName,
+ IN PCWSTRING KeyName,
+ OUT PREGISTRY_KEY_INFO KeyInfo,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Retrieve the information of a key.
+
+Arguments:
+
+
+ PredefinedKey - The root of the tree where the key is.
+
+ ParentName - Name of the parent key (can be NULL).
+
+ KeyName - Name of the key to be queried (cannot be NULL).
+
+ KeyInfo - Pointer to a NON-INITIALIZED object that will contain the
+ information about the key to be queried.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+
+--*/
+
+
+{
+#if defined( _AUTOCHECK_ )
+
+
+ NTSTATUS Status;
+ HANDLE Handle;
+ DSTRING Class;
+ ULONG Length;
+ BYTE KeyBuf[ KEY_FULL_SIZE ];
+
+
+ if ( !KeyInfo ||
+ !OpenKey( ParentName, KeyName, KEY_READ, &Handle, ErrorCode ) ) {
+ return FALSE;
+ }
+
+ Status = NtQueryKey( Handle,
+ KeyFullInformation,
+ &KeyBuf,
+ KEY_FULL_SIZE,
+ &Length );
+
+ NtClose( Handle );
+
+ if ( !NT_SUCCESS( Status ) ) {
+ if ( ErrorCode ) {
+ *ErrorCode = Status;
+ }
+ }
+
+
+ if ( !Class.Initialize( (PWSTR)((PKEY_FULL_INFORMATION)KeyBuf)->Class ) ||
+ !KeyInfo->Initialize( KeyName,
+ ParentName,
+ ((PKEY_FULL_INFORMATION)KeyBuf)->TitleIndex,
+ &Class,
+ NULL )
+
+ ) {
+
+ return FALSE;
+ }
+
+
+ KeyInfo->SetLastWriteTime( ((PKEY_FULL_INFORMATION)KeyBuf)->LastWriteTime );
+ KeyInfo->SetNumberOfSubKeys( ((PKEY_FULL_INFORMATION)KeyBuf)->SubKeys );
+ KeyInfo->SetNumberOfValues( ((PKEY_FULL_INFORMATION)KeyBuf)->Values );
+
+ return TRUE;
+
+#else
+
+ DSTRING TmpClass;
+ TIMEINFO TmpLastWriteTime;
+
+
+ DWORD Status;
+ HKEY Handle;
+
+
+ //
+ // Variables used in QueryKeyInfo()
+ //
+ LPWSTR lpClass;
+ WSTR DummyVariable;
+ DWORD cbClass;
+
+ DWORD cSubKeys;
+ DWORD cbMaxSubKeyLen;
+ DWORD cbMaxClassLen;
+ DWORD cValues;
+ DWORD cbMaxValueNameLen;
+ DWORD cbMaxValueLen;
+ DWORD cbSecurityDescriptor;
+ FILETIME ftLastWriteTime;
+
+
+
+ DebugPtrAssert( KeyInfo );
+ DebugPtrAssert( ParentName );
+ DebugPtrAssert( KeyName );
+
+
+ if( !OpenKey( PredefinedKey,
+ ParentName,
+ KeyName,
+ KEY_READ,
+ &Handle,
+ ErrorCode ) ) {
+// DebugPrint( "OpenKey() failed" );
+ return( FALSE );
+ }
+
+
+ //
+ // Query the key to find out the size of the buffer needed to hold
+ // the class
+ //
+ cbClass = 0;
+ lpClass = &DummyVariable;
+ Status = RegQueryInfoKey( Handle,
+ ( LPWSTR )lpClass,
+ &cbClass,
+ NULL,
+ &cSubKeys,
+ &cbMaxSubKeyLen,
+ &cbMaxClassLen,
+ &cValues,
+ &cbMaxValueNameLen,
+ &cbMaxValueLen,
+ &cbSecurityDescriptor,
+ &ftLastWriteTime );
+
+ if( ( Status != 0 ) && ( Status != ERROR_INVALID_PARAMETER ) && ( Status != ERROR_INSUFFICIENT_BUFFER ) ) {
+ DebugPrintf( "RegQueryInfoKey() failed. Error code = %#x \n", Status );
+ DebugPrint( "RegQueryInfoKey() failed." );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ return( FALSE );
+ }
+
+ //
+ // If the value in cbClass is not zero, then allocate a buffer big
+ // enough to hold the class, and query the key again to obtain its
+ // class.
+ //
+ if( cbClass != 0 ) {
+ cbClass++;
+ lpClass = ( PWSTR )MALLOC( ( size_t )( cbClass*sizeof( WCHAR ) ) );
+ DebugPtrAssert( lpClass );
+ Status = RegQueryInfoKey( Handle,
+ ( LPWSTR )lpClass,
+ &cbClass,
+ NULL,
+ &cSubKeys,
+ &cbMaxSubKeyLen,
+ &cbMaxClassLen,
+ &cValues,
+ &cbMaxValueNameLen,
+ &cbMaxValueLen,
+ &cbSecurityDescriptor,
+ &ftLastWriteTime );
+
+ if( Status != 0 ) {
+ DebugPrintf( "RegQueryInfoKey() failed. Error code = %#x \n", Status );
+ DebugPrint( "RegQueryInfoKey() failed." );
+ FREE( lpClass );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ return( FALSE );
+ }
+ }
+
+ //
+ // At this point there is no need to keep the handle opened.
+ // So, we close the handle.
+ //
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+
+ //
+ // Initialize a WSTRING object that contains the class
+ //
+ if( cbClass != 0 ) {
+ //
+ // Initialize TmpClass using the class size. It is not safe to assume
+ // that the class is NULL terminated
+ //
+ if( !TmpClass.Initialize( ( LPWSTR )lpClass, cbClass ) ) {
+ DebugPrint( "TmpClass.Initialize( lpClass ) failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_INITIALIZATION_FAILURE;
+ }
+ }
+ FREE( lpClass );
+ } else {
+ if( !TmpClass.Initialize( "" ) ) {
+ DebugPrint( "TmpClass.Initialize() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_INITIALIZATION_FAILURE;
+ }
+ }
+ }
+
+ //
+ // Initialize TIMEINFO that contains the last write time
+ //
+ if( !TmpLastWriteTime.Initialize( &ftLastWriteTime ) ) {
+ DebugPrint( "TmpLastWriteTime.Initialize( &ftLastWriteTime ) failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_INITIALIZATION_FAILURE;
+ }
+ return( FALSE );
+ }
+
+ //
+ // Update KeyInfo
+ //
+
+ //
+ // BUGBUG - jaimes - 03/08/92
+ // Security attributes is currently set to NULL since the API
+ // to retrive it is not yet implemented
+ //
+ SECURITY_ATTRIBUTES BugSecAttrib;
+ PSECURITY_DESCRIPTOR BugSecDesc;
+
+ BugSecDesc =( PSECURITY_DESCRIPTOR )MALLOC( (size_t) SECURITY_DESCRIPTOR_MIN_LENGTH );
+ DebugPtrAssert( BugSecDesc );
+ InitializeSecurityDescriptor( BugSecDesc, 1 );
+ BugSecAttrib.nLength = sizeof( SECURITY_ATTRIBUTES );
+ BugSecAttrib.lpSecurityDescriptor = BugSecDesc;
+ BugSecAttrib.bInheritHandle = FALSE;
+
+
+ //
+ // Initialize the REGISTRY_KEY_INFO object
+ //
+ if( !KeyInfo->Initialize( KeyName,
+ ParentName,
+ 0, // TitleIndex,
+ &TmpClass,
+ &BugSecAttrib ) ) {
+ DebugPrint( "KeyInfo->Initialize() failed" );
+ DebugPrint( "KeyInfo->Initialize() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_INITIALIZATION_FAILURE;
+ }
+ FREE( BugSecDesc );
+ return( FALSE );
+ }
+
+ FREE( BugSecDesc );
+ KeyInfo->PutLastWriteTime( &TmpLastWriteTime );
+ KeyInfo->SetNumberOfSubKeys( cSubKeys );
+ KeyInfo->SetNumberOfValues( cValues );
+ KeyInfo->SetKeyInitializedFlag( TRUE );
+ return( TRUE );
+
+#endif
+}
+
+
+BOOLEAN
+REGISTRY::QueryKeySecurity(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PCREGISTRY_KEY_INFO KeyInfo,
+ IN SECURITY_INFORMATION SecurityInformation,
+ IN PSECURITY_DESCRIPTOR* SecurityDescriptor,
+ IN PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Retrieve security information of a particular key.
+
+Arguments:
+
+
+ PredefinedKey - The root of the tree where the key is.
+
+ KeyInfo - Pointer to a REGISTRY_KEY_INFO object that describes the key
+ whose security information is to be retrieved.
+
+ SecurityInformation - Specifies the type of descriptor to retrieve.
+
+ SecurityDescriptor - Address of the variable that will contain the pointer
+ to the security descriptor.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+{
+#if defined ( _AUTOCHECK_ )
+
+ return FALSE;
+
+#else
+
+ PCWSTRING ParentName;
+ PCWSTRING KeyName;
+ HKEY Handle;
+ DWORD DummyVariable;
+ DWORD Size;
+ PBYTE Pointer;
+ DWORD Status;
+ REGSAM samDesired;
+
+#if DBG
+ PSID DebugOwnerSid;
+ PSID DebugGroupSid;
+ PACL DebugDacl;
+ PACL DebugSacl;
+ BOOL DebugFlag;
+ BOOL DebugDaclPresent;
+ BOOL DebugSaclPresent;
+#endif
+
+ DebugPtrAssert( KeyInfo );
+ DebugPtrAssert( SecurityDescriptor );
+
+
+ ParentName = KeyInfo->GetParentName();
+ DebugPtrAssert( ParentName );
+ KeyName = KeyInfo->GetName();
+ DebugPtrAssert( KeyName );
+
+
+ //
+ // Open the key.
+ // Need to use ACCESS_SYSTEM_SECURITY to retrieve SACL
+ //
+
+ samDesired = ( SecurityInformation & SACL_SECURITY_INFORMATION )?
+ ACCESS_SYSTEM_SECURITY | READ_CONTROL : READ_CONTROL;
+
+
+ if( !OpenKey( PredefinedKey,
+ ParentName,
+ KeyName,
+ samDesired,
+ &Handle,
+ ErrorCode ) ) {
+ DebugPrint( "OpenKey() failed" );
+ return( FALSE );
+ }
+
+ //
+ // Find out the size of the security descriptor
+ //
+ Size = 0;
+ Status = RegGetKeySecurity( Handle,
+ SecurityInformation,
+ &DummyVariable,
+ &Size );
+
+ if( ( Status != 0 ) && ( Status != ERROR_INVALID_PARAMETER ) && ( Status != ERROR_INSUFFICIENT_BUFFER ) ) {
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ DebugPrintf( "RegGetKeySecurity() failed, Status = %#x \n", Status );
+ DebugPrint( "RegGetKeySecurity() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+ return( FALSE );
+ }
+
+ //
+ // Read the security descriptor
+ //
+ Pointer = ( PBYTE ) MALLOC( ( size_t )Size );
+ if( Pointer == NULL ) {
+ DebugPrint( "Unable to allocate memory" );
+ DebugPtrAssert( Pointer );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ }
+ return( FALSE );
+ }
+
+ Status = RegGetKeySecurity( Handle,
+ SecurityInformation,
+ ( PSECURITY_DESCRIPTOR )Pointer,
+ &Size );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ if( Status != 0 ) {
+ DebugPrintf( "RegGetKeySecurity() failed, Status = %#x \n", Status );
+ DebugPrint( "RegGetKeySecurity() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );;
+ }
+ FREE( Pointer );
+ return( FALSE );
+ }
+
+ *SecurityDescriptor = Pointer;
+
+ //
+#if DBG // Security Descriptor Validation
+ //
+ if( IsValidSecurityDescriptor( *SecurityDescriptor ) ) {
+// DebugPrintf( "Security Descriptor is valid \n" );
+ } else {
+ DebugPrint( "IsValidSecurityDescriptor() failed" );
+ DebugPrintf( "Security Descriptor is NOT valid, Error = %#d \n", GetLastError() );
+ }
+
+ if( !GetSecurityDescriptorOwner( Pointer, &DebugOwnerSid, &DebugFlag ) ) {
+ DebugPrint( "GetSecurityDescriptorOwner() failed" );
+ DebugPrintf( "Unable to get Sid Owner, Error = %d \n", GetLastError() );
+ } else {
+ if( IsValidSid( DebugOwnerSid ) ) {
+// DebugPrintf( "Owner Sid is valid\n" );
+ } else {
+ DebugPrint( "IsValidSid() failed" );
+ DebugPrintf( "Owner Sid is NOT valid, Error = %#d \n", GetLastError() );
+ }
+ }
+ if( !GetSecurityDescriptorGroup( Pointer, &DebugGroupSid, &DebugFlag ) ) {
+ DebugPrint( "GetSecurityDescriptorGroup() failed" );
+ DebugPrintf( "Unable to get Sid Group, Error = %d \n", GetLastError() );
+ } else {
+ if( IsValidSid( DebugGroupSid ) ) {
+// DebugPrintf( "Group Sid is valid\n" );
+ } else {
+ DebugPrint( "IsValidSid() failed" );
+ DebugPrintf( "Group Sid is NOT valid, Error = %#d \n", GetLastError() );
+ }
+ }
+
+ if( ( SecurityInformation & DACL_SECURITY_INFORMATION ) != 0 ) {
+ if( !GetSecurityDescriptorDacl( Pointer, &DebugDaclPresent, &DebugDacl, &DebugFlag ) ) {
+ DebugPrint( "GetSecurityDescriptorDacl() failed" );
+ DebugPrintf( "Unable to get DACL, Error = %d \n", GetLastError() );
+ } else {
+ if( DebugDaclPresent ) {
+ if( IsValidAcl( DebugDacl ) ) {
+// DebugPrintf( "DACL is valid\n" );
+ } else {
+ DebugPrint( "IsValidAcl() failed" );
+ DebugPrintf( "DACL is NOT valid, Error = %#d \n", GetLastError() );
+ }
+ } else {
+ DebugPrint( "GetSecurityDescriptorDacl() succeeded but DACL is not present" );
+ }
+ }
+ }
+
+ if( ( SecurityInformation & SACL_SECURITY_INFORMATION ) != 0 ) {
+ if( !GetSecurityDescriptorSacl( Pointer, &DebugSaclPresent, &DebugSacl, &DebugFlag ) ) {
+ DebugPrint( "GetSecurityDescriptorDacl() failed" );
+ DebugPrintf( "Unable to get DACL, Error = %d \n", GetLastError() );
+ } else {
+ if( DebugSaclPresent ) {
+ if( IsValidAcl( DebugSacl ) ) {
+// DebugPrintf( "SACL is valid\n" );
+ } else {
+ DebugPrint( "IsValidAcl() failed" );
+ DebugPrintf( "SACL is NOT valid, Error = %#d \n", GetLastError() );
+ }
+ } else {
+ DebugPrint( "GetSecurityDescriptorSacl() succeeded but SACL is not present" );
+ }
+ }
+ }
+#endif //
+ // Security Descriptor Validation
+ //
+
+ return( TRUE );
+
+#endif
+}
+
+
+
+
+
+BOOLEAN
+REGISTRY::QuerySubKeysInfo(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PCWSTRING ParentKey,
+ IN PCWSTRING KeyName,
+ OUT PARRAY SubKeysInfo,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Return an array of PREGISTRY_KEY_INFO objects, each object containing
+ the information of a subkey.
+
+Arguments:
+
+
+ PredefinedKey - The root of the tree where the key is.
+
+ ParentKey - Name of the parent key.
+
+ KeyName - Name of the key that contains the subkeys to be queried.
+
+ SubKeysInfo - Pointer to an initialized array that will contain the
+ information (PREGISTRY_KEY_INFO) about the subkeys queried.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+
+{
+
+
+#if defined( _AUTOCHECK_ )
+
+ UNREFERENCED_PARAMETER( PredefinedKey );
+ UNREFERENCED_PARAMETER( ParentKey );
+ UNREFERENCED_PARAMETER( KeyName );
+ UNREFERENCED_PARAMETER( SubKeysInfo );
+ UNREFERENCED_PARAMETER( ErrorCode );
+
+ return FALSE;
+
+#else
+
+ PWSTRING CompleteName;
+ DSTRING SubKeyName;
+
+
+ PREGISTRY_KEY_INFO TmpInfoKey;
+ ULONG Index;
+
+ DWORD Status;
+ HKEY Handle;
+
+
+ //
+ // Variables used in RegQueryInfoKey() and RegEnumKeyEx()
+ //
+ WCHAR lpName[ MAX_PATH + 1 ];
+ DWORD cbName;
+ LPWSTR lpClass;
+ WSTR DummyVariable;
+ DWORD cbClass;
+
+ DWORD cSubKeys;
+ DWORD cbMaxSubKeyLen;
+ DWORD cbMaxClassLen;
+ DWORD cValues;
+ DWORD cbMaxValueNameLen;
+ DWORD cbMaxValueLen;
+ DWORD cbSecurityDescriptor;
+ FILETIME ftLastWriteTime;
+
+
+
+ DebugPtrAssert( SubKeysInfo );
+ DebugPtrAssert( ParentKey );
+ DebugPtrAssert( KeyName );
+
+
+ //
+ // Open a handle to the key, and find out the number of subkeys it has
+ //
+
+ if( !OpenKey( PredefinedKey,
+ ParentKey,
+ KeyName,
+ KEY_READ,
+ &Handle,
+ ErrorCode ) ) {
+ DebugPrint( "OpenKey failed" );
+ return( FALSE );
+ }
+
+
+ //
+ // Query the key to find out the number of subkeys it has
+ //
+ cbClass = 0;
+ lpClass = &DummyVariable;
+ Status = RegQueryInfoKey( Handle,
+ lpClass,
+ &cbClass,
+ NULL,
+ &cSubKeys,
+ &cbMaxSubKeyLen,
+ &cbMaxClassLen,
+ &cValues,
+ &cbMaxValueNameLen,
+ &cbMaxValueLen,
+ &cbSecurityDescriptor,
+ &ftLastWriteTime );
+
+
+ if( ( Status != 0 ) && ( Status != ERROR_INVALID_PARAMETER ) && ( Status != ERROR_INSUFFICIENT_BUFFER ) ){
+ DebugPrintf( "RegQueryInfoKey() failed, Status = %#x \n", Status );
+ DebugPrint( "RegQueryInfoKey() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ return( FALSE );
+ }
+
+ if( cbClass != 0 ) {
+ //
+ // If the key has a Class, then we need to allocate a buffer and
+ // read the class, even though we don't need it. If it is not
+ // safe to assume that the other information returned by the
+ // API are correct.
+ //
+ cbClass++;
+ lpClass = ( PWSTR )MALLOC( ( size_t )( cbClass*sizeof( WCHAR ) ) );
+ if( lpClass == NULL ) {
+ DebugPrint( "Unable to allocate memory" );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ }
+ DebugPtrAssert( lpClass );
+ return( FALSE );
+ }
+ Status = RegQueryInfoKey( Handle,
+ lpClass,
+ &cbClass,
+ NULL,
+ &cSubKeys,
+ &cbMaxSubKeyLen,
+ &cbMaxClassLen,
+ &cValues,
+ &cbMaxValueNameLen,
+ &cbMaxValueLen,
+ &cbSecurityDescriptor,
+ &ftLastWriteTime );
+
+ FREE( lpClass );
+ if( Status != 0 ) {
+ DebugPrintf( "RegQueryInfoKey() failed, Status = %#x \n", Status );
+ DebugPrint( "RegQueryInfoKey() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ return( FALSE );
+ }
+ }
+
+ //
+ // Get the complete key name. It is the parent name of each
+ // subkey that we are goint to read.
+ //
+
+ CompleteName = BuildCompleteName( ParentKey, KeyName );
+ if( CompleteName == NULL ) {
+ DebugPrint( "BuildCompleteName() failed" );
+ DebugPrint( "BuildCompleteName() failed" );
+ DebugPtrAssert( CompleteName );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_INITIALIZATION_FAILURE;
+ }
+ return( FALSE );
+ }
+
+ //
+ // Get the name of each subkey, build a REGISTRY_INFO_KEY for
+ // each of them, and put them in the array.
+ //
+
+ for( Index = 0; Index < cSubKeys; Index++ ) {
+
+ cbName = sizeof( lpName );
+ Status = RegEnumKeyEx( Handle,
+ Index,
+ ( LPWSTR )lpName,
+ &cbName,
+ NULL,
+ NULL,
+ NULL,
+ &ftLastWriteTime );
+ if( Status != 0 ) {
+ DebugPrintf( "RegEnumKeyEx() failed, Status = %#x \n", Status );
+ DebugPrint( "RegEnumKeyEx() failed" );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+ DELETE( CompleteName );
+ return( FALSE );
+ }
+ //
+ // Initialize SubKeyName using the subkey name length. It is not
+ // safe to assume that the name is NULL terminated.
+ //
+ if( ( cbName != 0 ) &&
+ ( lpName[ cbName - 1 ] == ( WCHAR )'\0' ) ) {
+ cbName--;
+ }
+
+ if( !SubKeyName.Initialize( ( LPWSTR )lpName ) ) {
+ DebugPrint( "SubKeyName.Initialize( ( LPWSTR )lpName ) failed" );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_INITIALIZATION_FAILURE;
+ }
+ DELETE( CompleteName );
+ return( FALSE );
+ }
+ TmpInfoKey = ( PREGISTRY_KEY_INFO )NEW( REGISTRY_KEY_INFO );
+ if( TmpInfoKey == NULL ) {
+ DebugPrint( "Unable to allocate memory" );
+ DELETE( CompleteName );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ }
+ DebugPtrAssert( TmpInfoKey );
+ return( FALSE );
+ }
+
+
+ if( !QueryKeyInfo( PredefinedKey,
+ CompleteName,
+ &SubKeyName,
+ TmpInfoKey,
+ ErrorCode ) ) {
+ //
+ // We have to know why it failed. If it is because we don't have
+ // the right permission, we should continue to query the other
+ // subkeys.
+ //
+// if( ( ErrorCode != NULL ) ) { // && ( *ErrorCode == REGISTRY_ERROR_ACCESS_DENIED ) ) {
+ //
+ // If it failed because we don't have permission to access the key
+ // initialize key info with the parent name and key name only.
+ // Notice that Class and LastWriteTime won't be initialized.ext file
+ //
+ TmpInfoKey->SetKeyInitializedFlag( FALSE );
+ if( !TmpInfoKey->PutParentName( CompleteName ) ||
+ !TmpInfoKey->PutName( &SubKeyName ) ) {
+ DebugPrint( "Initialization failure" );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_INITIALIZATION_FAILURE;
+ }
+ DELETE( CompleteName );
+ DELETE( TmpInfoKey );
+ return( FALSE );
+ }
+
+// } else {
+// DebugPrint( "QueryKeyInfo failed" );
+// if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+// RegCloseKey( Handle );
+// }
+// DELETE( CompleteName );
+// DELETE( TmpInfoKey );
+// return( FALSE );
+// }
+ }
+
+
+ SubKeysInfo->Put( TmpInfoKey );
+ }
+
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ DELETE( CompleteName );
+ return( TRUE );
+
+#endif
+}
+
+
+BOOLEAN
+REGISTRY::QueryValue(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PCWSTRING ParentName,
+ IN PCWSTRING KeyName,
+ IN PCWSTRING ValueName,
+ OUT PREGISTRY_VALUE_ENTRY Value,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Return PREGISTRY_VALUE_ENTRY object, that contains the information
+ of a particular value entry in a key.
+
+
+Arguments:
+
+
+ PredefinedKey - The root of the tree where the key is.
+
+ ParentName - Name of the parent key.
+
+ KeyName - Name of the key that contains the value to be
+ queried.
+
+ ValueName - The name of the desired value.
+
+ Value - Pointer to a non initialized REGISTRY_VLUE_ENTRY object
+ that will contain the information about the desired value.
+
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+
+{
+
+#if defined( _AUTOCHECK_ )
+
+ UNREFERENCED_PARAMETER( PredefinedKey );
+ UNREFERENCED_PARAMETER( ParentName );
+ UNREFERENCED_PARAMETER( KeyName );
+ UNREFERENCED_PARAMETER( ValueName );
+ UNREFERENCED_PARAMETER( Value );
+ UNREFERENCED_PARAMETER( ErrorCode );
+
+ return FALSE;
+
+#else
+
+ PWSTR ValueNameString;
+
+
+ DWORD Status;
+ HKEY Handle;
+
+
+ //
+ // Variables used in RegQueryValueEx()
+ //
+
+ DWORD Type;
+ PBYTE Data;
+ DWORD cbData;
+ DWORD DummyVariable;
+
+ DebugPtrAssert( Value );
+ DebugPtrAssert( ValueName );
+ DebugPtrAssert( ParentName );
+ DebugPtrAssert( KeyName );
+
+
+ if( !OpenKey( PredefinedKey,
+ ParentName,
+ KeyName,
+ KEY_QUERY_VALUE,
+ &Handle,
+ ErrorCode ) ) {
+ DebugPrint( "OpenKey failed" );
+ return( FALSE );
+ }
+
+ //
+ // Get the value information
+ //
+
+ ValueNameString = ValueName->QueryWSTR();
+ if( ValueNameString == NULL ) {
+ DebugPrint( "ValueName->QueryWSTR()" );
+ DebugPtrAssert( ValueNameString );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ }
+ return( FALSE );
+ }
+
+ Data = ( PBYTE )&DummyVariable;
+ cbData = 0;
+ Status = RegQueryValueEx( Handle,
+ ValueNameString,
+ NULL,
+ &Type,
+ Data,
+ &cbData );
+ if( ( Status != 0 ) && ( Status != ERROR_INVALID_PARAMETER ) && ( Status != ERROR_INSUFFICIENT_BUFFER ) ) {
+ DebugPrintf( "RegQueryValueEx() failed, Status = %#x \n", Status );
+ DebugPrint( "RegQueryValue() failed" );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+ FREE( ValueNameString );
+ return( FALSE );
+ }
+
+
+ if( cbData != 0 ) {
+ //
+ // If the value entry has data, then read it
+ //
+ Data = ( PBYTE )MALLOC( ( size_t )cbData );
+ if( Data == NULL ) {
+ DebugPrint( "Unable to allocate memory" );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ FREE( ValueNameString );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ }
+ DebugPtrAssert( Data );
+ return( FALSE );
+ }
+
+ Status = RegQueryValueEx( Handle,
+ ValueNameString,
+ NULL,
+ &Type,
+ Data,
+ &cbData );
+
+ if( Status != 0 ) {
+ DebugPrintf( "RegQueryValueEx() failed, Status = %#x \n", Status );
+ DebugPrint( "RegQueryValue() failed" );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+ FREE( ValueNameString );
+ return( FALSE );
+ }
+ }
+
+ FREE( ValueNameString );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ if( Status != 0 ) {
+ DebugPrintf( "RegQueryValueEx() failed, Status = %#x \n", Status );
+ DebugPrint( "RegQueryValue() failed" );
+
+ //
+ // If the value entry has data, the free the buffer that
+ // contains the data.
+ //
+ if( Data != ( PBYTE )&DummyVariable ) {
+ FREE( Data );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+ return( FALSE );
+ }
+
+ if( !Value->Initialize( ValueName,
+ 0, // TitleIndex,
+ ( REG_TYPE )Type,
+ Data,
+ cbData ) ) {
+ DebugPrint( "Value->Initialize() failed" );
+ if( Data != ( PBYTE )&DummyVariable ) {
+ FREE( Data );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_INITIALIZATION_FAILURE;
+ }
+ return( FALSE );
+ }
+ if( Data != ( PBYTE )&DummyVariable ) {
+ FREE( Data );
+ }
+
+ return( TRUE );
+
+#endif
+}
+
+
+
+
+BOOLEAN
+REGISTRY::QueryValues(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PCWSTRING ParentName,
+ IN PCWSTRING KeyName,
+ OUT PARRAY Values,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Return an array of PREGISTRY_VALUE_ENTRY objects, each object containing
+ the information of a value in a key..
+
+Arguments:
+
+
+ PredefinedKey - The root of the tree where the key is.
+
+ ParentName - Name of the parent key.
+
+ KeyName - Name of the key that contains the values to be
+ queried.
+
+ Values - Pointer to an initialized array that will contain the
+ information (PREGISTRY_VALUE_ENTRY) of each value in the key.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+
+{
+
+#if defined( _AUTOCHECK_ )
+
+ BYTE KeyBuf[ KEY_FULL_SIZE ];
+ PKEY_VALUE_FULL_INFORMATION ValueBuf = NULL;
+ ULONG ValueBufSize = 1;
+ ULONG Length;
+ ULONG Index;
+ PREGISTRY_VALUE_ENTRY RegValue;
+ DSTRING ValueName;
+ PBYTE Data;
+ NTSTATUS Status;
+ HANDLE Handle;
+
+
+ if ( !OpenKey( ParentName, KeyName, KEY_READ, &Handle, ErrorCode ) ) {
+ return FALSE;
+ }
+
+
+ //
+ // Query the key to find out the number of values it has
+ //
+ Status = NtQueryKey( Handle,
+ KeyFullInformation,
+ &KeyBuf,
+ KEY_FULL_SIZE,
+ &Length );
+
+ if ( !NT_SUCCESS( Status ) ) {
+ if ( ErrorCode != NULL ) {
+ *ErrorCode = Status;
+ }
+ NtClose( Handle );
+ return FALSE;
+ }
+
+
+ ValueBufSize = ((PKEY_FULL_INFORMATION)KeyBuf)->MaxValueDataLen;
+
+ if ( !Values ||
+ !(ValueBuf = (PKEY_VALUE_FULL_INFORMATION)MALLOC( ValueBufSize ) )
+ ) {
+
+ NtClose( Handle );
+ return FALSE;
+ }
+
+
+ //
+ // Get each value, build a REGISTRY_VALUE_ENTRY for
+ // each of them, and put them in the array.
+ //
+ Values->Initialize( ((PKEY_FULL_INFORMATION)KeyBuf)->Values );
+
+ for ( Index = 0; Index < ((PKEY_FULL_INFORMATION)KeyBuf)->Values; Index++ ) {
+
+
+ Status = NtEnumerateValueKey( Handle,
+ Index,
+ KeyValueFullInformation,
+ ValueBuf,
+ ValueBufSize,
+ &Length );
+
+ if ( !NT_SUCCESS( Status ) ) {
+
+ //
+ // If overflow, grow the bufer and try again.
+ //
+ if ( Status == STATUS_BUFFER_OVERFLOW ) {
+
+ if ( !(ValueBuf = (PKEY_VALUE_FULL_INFORMATION)REALLOC( ValueBuf, Length ) ) ) {
+ *ErrorCode = 0;
+ NtClose( Handle );
+ FREE( ValueBuf );
+ return FALSE;
+ }
+
+ ValueBufSize = Length;
+
+ Status = NtEnumerateValueKey( Handle,
+ Index,
+ KeyValueFullInformation,
+ ValueBuf,
+ ValueBufSize,
+ &Length );
+
+ }
+
+ if ( !NT_SUCCESS( Status ) ) {
+ if ( ErrorCode ) {
+ *ErrorCode = Status;
+ NtClose( Handle );
+ FREE( ValueBuf );
+ return FALSE;
+ }
+ }
+ }
+
+
+ //
+ // Initialize the REGISTRY_VALUE_ENTRY object and put it in the array
+ //
+ Data = (PBYTE)ValueBuf + ((PKEY_VALUE_FULL_INFORMATION)ValueBuf)->DataOffset;
+
+ if ( !(RegValue = NEW REGISTRY_VALUE_ENTRY ) ||
+ !ValueName.Initialize( (PSTR)((PKEY_VALUE_FULL_INFORMATION)ValueBuf->Name) ) ||
+ !RegValue->Initialize( &ValueName,
+ (ULONG)ValueBuf->TitleIndex,
+ (REG_TYPE)ValueBuf->Type,
+ (PCBYTE)Data,
+ (ULONG)ValueBuf->DataLength ) ||
+ !Values->Put( RegValue )
+
+ ) {
+
+ NtClose( Handle );
+ FREE( ValueBuf );
+ DELETE( RegValue );
+ return FALSE;
+ }
+ }
+
+ NtClose( Handle );
+
+ FREE( ValueBuf );
+
+ return TRUE;
+
+#else
+
+ DSTRING ValueNameString;
+
+ PREGISTRY_VALUE_ENTRY TmpValueEntry;
+ ULONG Index;
+
+ DWORD Status;
+ HKEY Handle;
+
+
+
+ //
+ // Variables used in RegQueryInfoKey() and RegEnumKeyEx()
+ //
+ LPWSTR lpClass;
+ DWORD cbClass;
+ WSTR DummyVariable;
+
+ DWORD cSubKeys;
+ DWORD cbMaxSubKeyLen;
+ DWORD cbMaxClassLen;
+ DWORD cValues;
+ DWORD cbMaxValueNameLen;
+ DWORD cbMaxValueLen;
+ FILETIME ftLastWriteTime;
+
+ PWCHAR ValueName;
+ DWORD cbValueName;
+ DWORD cbSecurityDescriptor;
+ DWORD Type;
+ PBYTE Data;
+ DWORD cbData;
+
+ DebugPtrAssert( Values );
+ DebugPtrAssert( ParentName );
+ DebugPtrAssert( KeyName );
+
+
+ //
+ // Open the key
+ //
+
+ if( !OpenKey( PredefinedKey,
+ ParentName,
+ KeyName,
+ KEY_READ,
+ &Handle,
+ ErrorCode ) ) {
+
+ DebugPrint( "OpenKey() failed" );
+ return( FALSE );
+ }
+
+
+ //
+ // Query the key to find out the number of values it has
+ //
+ lpClass = &DummyVariable;
+ cbClass = 0;
+ Status = RegQueryInfoKey( Handle,
+ ( LPWSTR )lpClass,
+ &cbClass,
+ NULL,
+ &cSubKeys,
+ &cbMaxSubKeyLen,
+ &cbMaxClassLen,
+ &cValues,
+ &cbMaxValueNameLen,
+ &cbMaxValueLen,
+ &cbSecurityDescriptor,
+ &ftLastWriteTime );
+
+
+ if( ( Status != 0 ) && ( Status != ERROR_INVALID_PARAMETER ) && ( Status != ERROR_INSUFFICIENT_BUFFER ) ) {
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ return( FALSE );
+ }
+ //
+ // If the key has a Class, then we have to query it again, to retrieve
+ // its class, becase we cannot assume that the other information that the
+ // API returned is correct
+ //
+ if( cbClass != 0 ) {
+ cbClass++;
+ lpClass = ( PWSTR )MALLOC( ( size_t )( cbClass*sizeof( WCHAR ) ) );
+ if( lpClass == NULL ) {
+ DebugPrint( "Unable to allocate memory" );
+ DebugPtrAssert( lpClass );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ }
+ return( FALSE );
+ }
+
+ Status = RegQueryInfoKey( Handle,
+ ( LPWSTR )lpClass,
+ &cbClass,
+ NULL,
+ &cSubKeys,
+ &cbMaxSubKeyLen,
+ &cbMaxClassLen,
+ &cValues,
+ &cbMaxValueNameLen,
+ &cbMaxValueLen,
+ &cbSecurityDescriptor,
+ &ftLastWriteTime );
+
+ FREE( lpClass );
+ if( Status != 0 ) {
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ return( FALSE );
+ }
+ }
+ //
+ // Get each value, build a REGISTRY_VALUE_ENTRY for
+ // each of them, and put them in the array.
+ //
+ cbMaxValueNameLen++;
+ ValueName = ( PWCHAR )MALLOC( (size_t)( cbMaxValueNameLen*sizeof( WCHAR ) ) );
+ Data = ( PBYTE )MALLOC( ( size_t )cbMaxValueLen );
+ if( ( Data == NULL ) || ( ValueName == NULL ) ) {
+ DebugPrint( "Unable to allocate memory" );
+ DebugPtrAssert( Data );
+ DebugPtrAssert( ValueName );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ }
+ FREE( ValueName );
+ FREE( Data );
+ return( FALSE );
+ }
+ for( Index = 0; Index < cValues; Index++ ) {
+ cbData = cbMaxValueLen;
+ cbValueName = cbMaxValueNameLen;
+ Status = RegEnumValue( Handle,
+ Index,
+ ( LPWSTR )ValueName,
+ &cbValueName,
+ NULL,
+ &Type,
+ Data,
+ &cbData );
+ if( Status != 0 ) {
+ DebugPrintf( "RegEnumValue() failed, Status = %#x, cbValueName = %d \n", Status, cbValueName );
+ DebugPrint( "RegEnumValue() failed" );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ FREE( Data );
+ FREE( ValueName );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+ return( FALSE );
+ }
+ if( ( cbValueName != 0 ) &&
+ ( ValueName[ cbValueName - 1 ] == ( WCHAR )'\0' ) ) {
+ cbValueName--;
+ }
+ if( !ValueNameString.Initialize( ( LPWSTR )ValueName ) ) {
+ DebugPrint( "ValueNameString.Initialize( ( LPWSTR )ValueName ) failed" );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ FREE( Data );
+ FREE( ValueName );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_INITIALIZATION_FAILURE;
+ }
+ return( FALSE );
+ }
+
+ TmpValueEntry = ( PREGISTRY_VALUE_ENTRY )NEW( REGISTRY_VALUE_ENTRY );
+ DebugPtrAssert( TmpValueEntry );
+ if( !TmpValueEntry->Initialize( &ValueNameString,
+ 0, // TitleIndex,
+ (REG_TYPE)Type ) ) {
+ DebugPrint( "TmpValueEntry->Initialize( ) failed" );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ FREE( Data );
+ FREE( ValueName );
+ return( FALSE );
+ }
+ TmpValueEntry->PutData( Data, cbData );
+ Values->Put( TmpValueEntry );
+ }
+ FREE( Data );
+ FREE( ValueName );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ return( TRUE );
+
+#endif
+}
+
+
+
+BOOLEAN
+REGISTRY::SetKeySecurity(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO KeyInfo,
+ IN SECURITY_INFORMATION SecurityInformation,
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ IN PULONG ErrorCode,
+ IN BOOLEAN Recurse
+ )
+
+/*++
+
+Routine Description:
+
+ Set security information of a particular key.
+
+Arguments:
+
+
+ PredefinedKey - The root of the tree where the key is.
+
+ KeyInfo - Pointer to a REGISTRY_KEY_INFO object that describes the key
+ whose security information is to be set.
+
+ SecurityInformation - Specifies the type of descriptor to set.
+
+ SecurityDescriptor - Pointer to the scurity descriptor.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+ Recurse - Indicates whether the security of the subkeys should also be
+ set.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+{
+#if defined ( _AUTOCHECK_ )
+
+ return FALSE;
+
+#else
+
+ PCWSTRING ParentName;
+ PCWSTRING KeyName;
+ HKEY Handle;
+ DWORD Status;
+ REGSAM samDesired;
+
+
+ DebugPtrAssert( KeyInfo );
+ DebugPtrAssert( SecurityDescriptor );
+
+ ParentName = KeyInfo->GetParentName();
+ DebugPtrAssert( ParentName );
+
+ KeyName = KeyInfo->GetName();
+ DebugPtrAssert( KeyName );
+
+ samDesired = MAXIMUM_ALLOWED;
+ if( SecurityInformation & SACL_SECURITY_INFORMATION ) {
+ samDesired |= ACCESS_SYSTEM_SECURITY;
+ } else if( SecurityInformation & DACL_SECURITY_INFORMATION ) {
+ samDesired |= WRITE_DAC;
+ } else if( SecurityInformation & OWNER_SECURITY_INFORMATION ) {
+ samDesired |= WRITE_OWNER;
+ } else {
+ DebugPrint( "ERROR: SecurityInformation is invalid" );
+ DebugPrintf( "SecurityInformation is invalid, SecurityInformation = %# \n",
+ SecurityInformation );
+ }
+
+
+ if( !OpenKey( PredefinedKey,
+ ParentName,
+ KeyName,
+ samDesired,
+ &Handle,
+ ErrorCode ) ) {
+ DebugPrint( "OpenKey() failed" );
+ return( FALSE );
+ }
+
+
+ if( Recurse ) {
+
+ if( !SetSubKeysSecurity( Handle,
+ SecurityInformation,
+ SecurityDescriptor,
+ ErrorCode ) ) {
+
+ DebugPrintf( "SetSubKeysSecurity failed, ErrorCode = %#x \n", *ErrorCode );
+ DebugPrint( "SetSubKeysSecurity failed" );
+ RegFlushKey( Handle );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( *ErrorCode );
+ }
+ return( FALSE );
+ }
+ } else {
+
+
+ Status = RegSetKeySecurity( Handle,
+ SecurityInformation,
+ SecurityDescriptor );
+ if( Status != 0 ) {
+ DebugPrintf( "RegSetKeySecurity() failed, Status = %#x \n", Status );
+ DebugPrint( "RegSetKeySecurity() failed" );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+ return( FALSE );
+ }
+ }
+
+ Status = RegFlushKey( Handle );
+ if( Status != 0 ) {
+ DebugPrintf( "RegFlushKey() failed, Status = %#x \n" );
+ DebugPrint( "RegFlushKey() failed" );
+ }
+
+ //
+ // Close the handle even if it is a predefined handle.
+ // This is necessary so that the predfined handle will contain the new
+ // security, next time it is accesed.
+ //
+ RegCloseKey( Handle );
+
+ return( TRUE );
+
+#endif
+}
+
+
+
+
+
+
+
+BOOLEAN
+REGISTRY::UpdateKeyInfo(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN OUT PREGISTRY_KEY_INFO KeyInfo,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Update _LastWriteTime, _NumberOfSubKeys and _NumberOfValues of
+ a REGISTRY_KEY_INFO object.
+ This method is used by methods that create key or value entry.
+
+
+Arguments:
+
+
+ PredefinedKey - The root of the tree where the key is.
+
+ KeyInfo - Pointer to the object that contains the information about the
+ key to be updated.
+
+ ErrorCode - An optional pointer to a variable that will contain an error
+ code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the opeartion succeeds.
+
+
+--*/
+
+{
+
+#if defined( _AUTOCHECK_ )
+
+ UNREFERENCED_PARAMETER( PredefinedKey );
+ UNREFERENCED_PARAMETER( KeyInfo );
+ UNREFERENCED_PARAMETER( ErrorCode );
+
+ return FALSE;
+
+#else
+
+ PCWSTRING ParentName;
+ PCWSTRING KeyName;
+
+ DWORD Status;
+ HKEY Handle;
+
+ // PTIMEINFO LastWriteTime;
+
+ //
+ // Variables used in QueryKeyInfo()
+ //
+ LPWSTR lpClass;
+ WSTR DummyVariable;
+ DWORD cbClass;
+
+ DWORD cSubKeys;
+ DWORD cbMaxSubKeyLen;
+ DWORD cbMaxClassLen;
+ DWORD cValues;
+ DWORD cbMaxValueNameLen;
+ DWORD cbMaxValueLen;
+ DWORD cbSecurityDescriptor;
+ FILETIME ftLastWriteTime;
+
+
+ DebugPtrAssert( KeyInfo );
+
+ ParentName = KeyInfo->GetParentName();
+ DebugPtrAssert( ParentName );
+
+ KeyName = KeyInfo->GetName();
+ DebugPtrAssert( KeyName );
+
+ if( !OpenKey( PredefinedKey,
+ ParentName,
+ KeyName,
+ KEY_READ,
+ &Handle,
+ ErrorCode ) ) {
+// DebugPrint( "OpenKey() failed" );
+ return( FALSE );
+ }
+
+ //
+ // Query the key to update _LastWriteTime, _NumberOfSubKeys and _NumberOfValues in KeyInfo
+ //
+ lpClass = &DummyVariable;
+ cbClass = 0;
+ Status = RegQueryInfoKey( Handle,
+ ( LPWSTR )lpClass,
+ &cbClass,
+ NULL,
+ &cSubKeys,
+ &cbMaxSubKeyLen,
+ &cbMaxClassLen,
+ &cValues,
+ &cbMaxValueNameLen,
+ &cbMaxValueLen,
+ &cbSecurityDescriptor,
+ &ftLastWriteTime );
+
+ if( ( Status != 0 ) && ( Status != ERROR_INVALID_PARAMETER ) && ( Status != ERROR_INSUFFICIENT_BUFFER ) ) {
+ DebugPrintf( "RegQueryInfoKey() failed, Status = %#x \n" );
+ DebugPrint( "RegQueryInfoKey() failed" );
+
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ }
+
+ //
+ // If the key has a Class, then we need to query the key again to
+ // retrieve its class. This is to make sure that all the information
+ // returned by API is correct
+ //
+
+ if( cbClass != 0 ) {
+ cbClass++;
+ lpClass = ( LPWSTR )MALLOC( ( size_t )( cbClass*sizeof( WCHAR ) ) );
+ if( lpClass == NULL ) {
+ DebugPrint( "Unable to allocate memory" );
+ DebugPtrAssert( lpClass );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ }
+ KeyInfo->SetKeyInitializedFlag( FALSE );
+ return( FALSE );
+ }
+ Status = RegQueryInfoKey( Handle,
+ ( LPWSTR )lpClass,
+ &cbClass,
+ NULL,
+ &cSubKeys,
+ &cbMaxSubKeyLen,
+ &cbMaxClassLen,
+ &cValues,
+ &cbMaxValueNameLen,
+ &cbMaxValueLen,
+ &cbSecurityDescriptor,
+ &ftLastWriteTime );
+
+ FREE( lpClass );
+
+ if( Status != 0 ) {
+ DebugPrintf( "RegQueryInfoKey() failed, Status = %#x \n" );
+ DebugPrint( "RegQueryInfoKey() failed" );
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+ KeyInfo->SetKeyInitializedFlag( FALSE );
+ return( FALSE );
+ }
+ }
+
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+
+
+
+ //
+ // Update _LastWriteTime in KeyInfo
+ //
+ if( !( ( KeyInfo->_LastWriteTime ).Initialize( &ftLastWriteTime ) ) ) {
+ DebugPrint( "( KeyInfo->_LastWriteTime )->Initialize( &ftLastWriteTime ) failed" );
+ KeyInfo->SetKeyInitializedFlag( FALSE );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_INITIALIZATION_FAILURE;
+ }
+ }
+
+ //
+ // Update NumberOfSubKeys and NumberOfValues in KeyInfo
+ //
+ KeyInfo->SetNumberOfSubKeys( cSubKeys );
+ KeyInfo->SetNumberOfValues( cValues );
+ KeyInfo->SetKeyInitializedFlag( TRUE );
+ return( TRUE );
+
+#endif
+}
+
+
+
+PWSTRING
+REGISTRY::BuildCompleteName(
+ IN PCWSTRING ParentName,
+ IN PCWSTRING KeyName
+ )
+
+/*++
+
+Routine Description:
+
+ Build a complete key name based on its parent name and its name
+
+Arguments:
+
+
+ ParentName - The name of a key relative to a predefined key (root of a tree).
+
+ KeyName - The name of a key relative to its parent.
+
+
+Return Value:
+
+ PWSTRING - Returns a WSTRING that contains the complete key name, or
+ NULL if an error occurs..
+
+
+--*/
+
+{
+
+#if defined( _AUTOCHECK_ )
+
+
+ PWSTRING CompleteName;
+
+ if ( !(CompleteName = NEW DSTRING ) ||
+ !CompleteName->Initialize( ParentName ) ||
+ !CompleteName->Strcat( _Separator ) ||
+ !CompleteName->Strcat( KeyName )
+
+ ) {
+
+ DELETE( CompleteName );
+ CompleteName = NULL;
+ }
+
+ return CompleteName;
+
+#else
+
+ PWSTRING CompleteName;
+
+
+ DebugPtrAssert( ParentName );
+ DebugPtrAssert( KeyName );
+
+ CompleteName = ( PWSTRING )NEW( DSTRING );
+ if( CompleteName == NULL ) {
+ DebugPtrAssert( CompleteName );
+ return( NULL );
+ }
+
+ if( ( ParentName->QueryChCount() == 0 ) &&
+ ( KeyName->QueryChCount() == 0 ) ) {
+ //
+ // The key is a predefined key
+ //
+ if( !CompleteName->Initialize( "" ) ) {
+ DebugPrint( "CompleteName->Initialize() failed \n" );
+ DELETE( CompleteName );
+ return( NULL );
+ }
+ } else if( ParentName->QueryChCount() == 0 ) {
+ //
+ // The key is a subkey of a predefined key
+ //
+ if( !CompleteName->Initialize( KeyName ) ) {
+ DebugPrint( "CompleteName->Initialize( KeyName ) failed" );
+ FREE( CompleteName );
+ return( NULL );
+ }
+ } else {
+ if( !CompleteName->Initialize( ParentName ) ) {
+ DebugPrint( "CompleteName->Initialize( ParentName ) failed" );
+ FREE( CompleteName );
+ return( NULL );
+ }
+ if( KeyName->QueryChCount() != 0 ) {
+ CompleteName->Strcat( _Separator );
+ CompleteName->Strcat( KeyName );
+ }
+ }
+ return( CompleteName );
+
+#endif
+}
+
+
+
+
+#if !defined( _AUTOCHECK_ )
+ULONG
+REGISTRY::MapWin32RegApiToRegistryError(
+ IN ULONG Status
+ ) CONST
+
+/*++
+
+Routine Description:
+
+ Maps status codes returned by Win32 Registry APIs to REGISTRY error codes.
+
+Arguments:
+
+ Status - Supplies a Win32 status code.
+
+Return Value:
+
+ LONG - Returns a Registry error code.
+
+
+ - REGISTRY_ERROR_BADDB
+ - REGISTRY_ERROR_CANTOPEN
+ - REGISTRY_ERROR_CANTREAD
+ - REGISTRY_ERROR_ACCESS_DENIED
+ - REGISTRY_ERROR_INVALID_PARAMETER
+ - REGISTRY_ERROR_OUTOFMEMORY
+
+--*/
+
+{
+
+ //
+ // Map the Win 32 code to a Registry error code.
+ //
+
+ switch( Status ) {
+
+ case ERROR_BADDB:
+
+ return REGISTRY_ERROR_BADDB;
+
+ case ERROR_ACCESS_DENIED:
+
+ return REGISTRY_ERROR_ACCESS_DENIED;
+
+ case ERROR_CANTOPEN:
+
+ return REGISTRY_ERROR_CANTOPEN;
+
+ case ERROR_CANTREAD:
+
+ return REGISTRY_ERROR_CANTREAD;
+
+ case ERROR_INVALID_PARAMETER:
+
+ return REGISTRY_ERROR_INVALID_PARAMETER;
+
+ case ERROR_OUTOFMEMORY:
+
+ return REGISTRY_ERROR_OUTOFMEMORY;
+
+ case ERROR_PRIVILEGE_NOT_HELD:
+
+ return REGISTRY_ERROR_PRIVILEGE_NOT_HELD;
+
+ case RPC_S_SERVER_UNAVAILABLE:
+ case RPC_S_CALL_FAILED:
+
+ return REGISTRY_RPC_S_SERVER_UNAVAILABLE;
+
+ case ERROR_KEY_DELETED:
+
+ return REGISTRY_ERROR_KEY_DELETED;
+
+ case ERROR_FILE_NOT_FOUND:
+
+ return REGISTRY_ERROR_KEY_NOT_FOUND;
+
+ case ERROR_CHILD_MUST_BE_VOLATILE:
+
+ return REGISTRY_ERROR_CHILD_MUST_BE_VOLATILE;
+
+ default:
+
+// DebugPrintf( "REGEDIT: Unknown Registry error %#x \n", Status );
+// DebugPrint( "REGEDIT: Unknown Registry error" );
+ return REGISTRY_ERROR_UNKNOWN_ERROR;
+ }
+}
+#endif // _AUTOCHECK
+
+
+
+#if defined( _AUTOCHECK_ )
+
+BOOLEAN
+REGISTRY::OpenKey(
+ IN PCWSTRING ParentKeyName,
+ IN PCWSTRING KeyName,
+ IN ULONG Flags,
+ OUT PHANDLE Handle,
+ OUT PULONG ErrorCode
+ )
+/*++
+
+Routine Description:
+
+
+ Opens a key and obtains a handle to it
+
+Arguments:
+
+
+ ParentName - Supplies the name of a key relative to a predefined key (root of a tree).
+
+ KeyName - Supplies the name of a key relative to its parent.
+
+ Handle - Returns the handle to the key
+
+ Status - Returns the NT status in case of error
+
+
+Return Value:
+
+ BOOLEAN - TRUE if key opened
+
+--*/
+{
+ PWSTRING CompleteKeyName = NULL;
+ PWSTR CompleteKeyNameString = NULL;
+ UNICODE_STRING UnicodeKeyName;
+ OBJECT_ATTRIBUTES ObjAttr;
+ NTSTATUS Status;
+ BOOLEAN Opened = FALSE;
+
+ if ( ParentKeyName &&
+ KeyName &&
+ (CompleteKeyName = BuildCompleteName( ParentKeyName, KeyName ) ) &&
+ (CompleteKeyNameString = CompleteKeyName->QueryWSTR() )
+ ) {
+
+ RtlInitUnicodeString( &UnicodeKeyName, CompleteKeyNameString );
+
+ InitializeObjectAttributes( &ObjAttr,
+ &UnicodeKeyName,
+ OBJ_CASE_INSENSITIVE,
+ 0,
+ 0 );
+
+ //
+ // Open the key
+ //
+ Status = NtOpenKey( Handle, Flags, &ObjAttr );
+
+ if ( NT_SUCCESS( Status ) ) {
+
+ Opened = TRUE;
+
+ } else {
+
+ if ( ErrorCode != NULL ) {
+ *ErrorCode = Status;
+ }
+ }
+ }
+
+ DELETE( CompleteKeyName );
+ FREE( CompleteKeyNameString );
+
+
+ return Opened;
+}
+
+#endif
+
+
+
+#if !defined( _AUTOCHECK_ )
+
+BOOLEAN
+REGISTRY::OpenKey(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PCWSTRING ParentName,
+ IN PCWSTRING KeyName,
+ IN DWORD Permission,
+ OUT PHKEY Key,
+ OUT PULONG ErrorCode
+ )
+/*++
+
+Routine Description:
+
+
+ Opens a handle to a key.
+
+Arguments:
+
+
+ PredefinedKey - The root of the tree where the key is.
+
+ ParentName - Supplies the name of a key relative to a predefined key (root of a tree).
+
+ KeyName - Supplies the name of a key relative to its parent.
+
+ Permission - Type of access to the key
+
+ Handle - Returns the handle to the key
+
+ Status - Returns an error code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - TRUE if key opened
+
+--*/
+{
+
+ PWSTRING CompleteName;
+ PWSTR CompleteNameString;
+ ULONG Status;
+
+#if 0 // DBG
+ PSTR DebugKeyName;
+#endif
+
+
+ DebugPtrAssert( ParentName );
+ DebugPtrAssert( KeyName );
+ DebugPtrAssert( Key );
+
+
+ //
+ // Get the complete key name
+ //
+ CompleteName = BuildCompleteName( ParentName, KeyName );
+ if( CompleteName == NULL ) {
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ }
+ DebugPtrAssert( CompleteName );
+ return( FALSE );
+ }
+ //
+ // Open a handle to the key
+ //
+ if( CompleteName->QueryChCount() == 0 ) {
+ //
+ // This is a predefined key
+ //
+ if( !IsRemoteRegistry() ||
+ ( IsRemoteRegistry() &&
+ ( ( Permission & ACCESS_SYSTEM_SECURITY ) == 0 )
+ )
+ ) {
+ *Key = _PredefinedKey[ PredefinedKey ];
+ DELETE( CompleteName );
+ return( TRUE );
+ }
+ }
+
+ //
+ // Find out the complete name of the key
+ //
+ CompleteNameString = CompleteName->QueryWSTR();
+#if 0 // DBG
+ DebugKeyName = CompleteName->QuerySTR();
+#endif
+ DELETE( CompleteName );
+ if( CompleteNameString == NULL ) {
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ }
+ DebugPtrAssert( CompleteName );
+ return( FALSE );
+ }
+ //
+ // Open handle to the key
+ //
+ Status = RegOpenKeyEx( _PredefinedKey[ PredefinedKey ],
+ CompleteNameString,
+ 0,
+ Permission,
+ Key );
+
+ if( Status != 0 ) {
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+#if 0 // DBG
+ DebugPrintf( "RegOpenKeyEx() failed, KeyName = %s, Permission = %#x, Status = %#x \n",
+ DebugKeyName, Permission, Status );
+#endif
+// DebugPrint( "RegOpenKeyEx() failed" );
+ FREE( CompleteNameString );
+#if 0 // DBG
+ FREE( DebugKeyName );
+#endif
+ return( FALSE );
+ }
+ FREE( CompleteNameString );
+#if 0 // DBG
+ FREE( DebugKeyName );
+#endif
+ return( TRUE );
+}
+
+#endif
+
+
+#if !defined( _AUTOCHECK_ )
+
+ULONG
+REGISTRY::DeleteTree(
+ IN HKEY KeyHandle
+ )
+
+/*++
+
+Routine Description:
+
+
+ Delete the subkeys of the key whose handle was passed as argument.
+ The deletion process is recusive, that is, the children of the
+ subkeys are also deleted.
+
+
+Arguments:
+
+
+ KeyHandle - Handle to the key whose subkeys are to be deleted.
+
+
+Return Value:
+
+ ULONG - Returns 0 if all subkeys were deleted or a Win32 error code
+ if something went wrong.
+
+
+--*/
+{
+
+ ULONG Error;
+ DWORD Index;
+ HKEY ChildHandle;
+
+
+ WCHAR KeyName[ MAX_PATH + 1 ]; // +1 counts for the NULL
+ DWORD KeyNameLength;
+ PWSTR ClassName;
+ DWORD ClassNameLength;
+ WSTR DummyVariable;
+
+ DWORD NumberOfSubKeys;
+ DWORD MaxSubKeyLength;
+ DWORD MaxClassLength;
+ DWORD NumberOfValues;
+ DWORD MaxValueNameLength;
+ DWORD MaxValueDataLength;
+ DWORD SecurityDescriptorLength;
+ FILETIME LastWriteTime;
+ ULONG Status;
+
+
+ //
+ // Find out the total number of subkeys
+ //
+
+
+ ClassNameLength = 0;
+
+ Error = RegQueryInfoKey(
+ KeyHandle,
+ &DummyVariable,
+ &ClassNameLength,
+ NULL,
+ &NumberOfSubKeys,
+ &MaxSubKeyLength,
+ &MaxClassLength,
+ &NumberOfValues,
+ &MaxValueNameLength,
+ &MaxValueDataLength,
+ &SecurityDescriptorLength,
+ &LastWriteTime
+ );
+ if( ( Error != 0 ) && ( Error != ERROR_INVALID_PARAMETER ) && ( Error != ERROR_INSUFFICIENT_BUFFER ) ) {
+ DebugPrintf( "RegQueryInfoKey() failed, Error = %#x \n", Error );
+ DebugPrint( "RegQueryInfoKey() failed" );
+ return( Error );
+ }
+
+ if( ClassNameLength != 0 ) {
+ ClassNameLength++;
+ ClassName = ( PWSTR )MALLOC( ( size_t )( ClassNameLength*sizeof( WCHAR ) ) );
+ if( ClassName == NULL ) {
+ DebugPrint( "UnableToAllocateMemory" );
+ return( ERROR_OUTOFMEMORY );
+ }
+ Error = RegQueryInfoKey(
+ KeyHandle,
+ ClassName,
+ &ClassNameLength,
+ NULL,
+ &NumberOfSubKeys,
+ &MaxSubKeyLength,
+ &MaxClassLength,
+ &NumberOfValues,
+ &MaxValueNameLength,
+ &MaxValueDataLength,
+ &SecurityDescriptorLength,
+ &LastWriteTime
+ );
+ FREE( ClassName );
+ if( Error != 0 ) {
+ DebugPrintf( "RegQueryInfoKey() failed, Error = %#x \n", Error );
+ DebugPrint( "RegQueryInfoKey() failed" );
+ return( Error );
+ }
+ }
+ //
+ // Start de deletion from the last child, instead of the first child.
+ // In this way, it is guaranteed that RegEnumKey() will return
+ // the correct subkey while we are deleting them.
+ //
+ Status = 0;
+ for( Index = NumberOfSubKeys; Index > 0; Index-- ) {
+
+ // If the key has subkeys, then for each subkey, do:
+ //
+ //
+ // - Determine the subkey name
+ //
+ KeyNameLength = sizeof( KeyName );
+
+ Error = RegEnumKey(
+ KeyHandle,
+ Index-1,
+ KeyName,
+ KeyNameLength
+ );
+
+ if( Error != 0 ) {
+ DebugPrintf( "RegQueryInfoKey() failed, Error = %#x \n", Error );
+ DebugPrint( "RegQueryInfoKey() failed" );
+ return( Error );
+ }
+
+ //
+ // - Open a handle to the subkey
+ //
+
+ Error = RegOpenKeyEx(
+ KeyHandle,
+ KeyName,
+ REG_OPTION_RESERVED,
+ READ_CONTROL | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, // MAXIMUM_ALLOWED,
+ &ChildHandle
+ );
+
+ if( Error != 0 ) {
+ DebugPrintf( "RegOpenKeyEx() failed, Error = %#x \n", Error );
+ DebugPrint( "RegOpenKey() failed" );
+ //
+ // We want to delete the maximum number of subkeys.
+ //
+ Status = Error;
+ continue;
+ }
+
+ //
+ // - Delete the child's subkeys
+ //
+
+ Error = DeleteTree( ChildHandle );
+ if( Error != 0 ) {
+ Status = Error;
+ }
+ Error = RegCloseKey(
+ ChildHandle
+ );
+
+ if( Error != 0 ) {
+ DebugPrintf( "CloseKeyx() failed, Error = %#x \n", Error );
+ DebugPrint( "RegCloseKey() failed" );
+ }
+
+ //
+ // -Delete the subkey
+ //
+
+ Error = RegDeleteKey(
+ KeyHandle,
+ KeyName
+ );
+
+ if( Error != 0 ) {
+ DebugPrintf( "RegDeletKey() failed, Error = %#x \n", Error );
+ DebugPrint( "RegDeleteKey() failed" );
+
+ }
+ }
+ return Status;
+}
+
+#endif
+
+
+
+
+#if !defined( _AUTOCHECK_ )
+
+BOOLEAN
+REGISTRY::EnableRootNotification(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN HANDLE Event,
+ IN DWORD NotifyFilter,
+ IN BOOLEAN WatchSubTree
+ )
+
+/*++
+
+Routine Description:
+
+
+ Enable notification in the prdefined key of a registry.
+
+
+Arguments:
+
+ PredefinedKey - Indicates which Predefined Key should be monitored.
+
+ Event - Handle to the event object to be signaled when the predefined
+ key changes.
+
+ NotifyFilter - Flags that specify in what condition the event should
+ be signaled.
+
+ WatchTree - If TRUE, indicates that the root and all its decsendants
+ should be monitored.
+
+
+
+Return Value:
+
+ ULONG - Returns 0 if all subkeys were deleted or a Win32 error code
+ if something went wrong.
+
+
+--*/
+{
+ DWORD Status;
+
+// DebugPrintf( "Calling RegNotifyChangeKeyValue() PredefinedKey = %d \n",
+// PredefinedKey );
+
+// DebugPrintf( "Calling RegNotifyChangeKeyValue(), PredefinedKey =%d \n", PredefinedKey );
+ Status = RegNotifyChangeKeyValue( _PredefinedKey[ PredefinedKey ],
+ WatchSubTree,
+ NotifyFilter,
+ Event,
+ TRUE );
+
+ if( Status != 0 ) {
+
+ DebugPrintf( "RegNotifyChangeKeyValue() failed, PredefinedKey = %d, Status = %#x \n",
+ PredefinedKey,
+ Status );
+ DebugPrint( "RegNotifyChangeKeyValue() failed" );
+ return( FALSE );
+ }
+
+
+ return( TRUE );
+
+}
+
+#endif
+
+
+#if !defined( _AUTOCHECK_ )
+
+BOOLEAN
+REGISTRY::
+SetSubKeysSecurity(
+ IN HKEY KeyHandle,
+ IN SECURITY_INFORMATION SecurityInformation,
+ IN PSECURITY_DESCRIPTOR SecurityDescriptor,
+ IN PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+
+ Set the security of the key whose handle was passed as argument,
+ and all its subkeys.
+
+
+Arguments:
+
+
+ KeyHandle - Handle to the key that contains the subkeys whose security
+ is to be set.
+
+ SecurityInformation -
+
+ SecurityDescriptor - Security descriptor to be set in the key.
+
+ ErrorCode - Contains a win32 error code if the call fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if if security was set successfully, or FALSE
+ otherwise. If it fails, ErrorCode will contain a win32 error
+ code.
+
+
+
+--*/
+{
+
+ ULONG Error;
+ DWORD Index;
+ HKEY ChildHandle;
+
+
+ WCHAR SubKeyName[ MAX_PATH ];
+ DWORD SubKeyNameLength;
+ DWORD ClassNameLength;
+ WSTR DummyVariable;
+
+ DWORD NumberOfSubKeys;
+ DWORD MaxSubKeyLength;
+ DWORD MaxClassLength;
+ DWORD NumberOfValues;
+ DWORD MaxValueNameLength;
+ DWORD MaxValueDataLength;
+ DWORD SecurityDescriptorLength;
+ FILETIME LastWriteTime;
+ REGSAM samDesired;
+ BOOLEAN Status;
+
+ HKEY NewHandle;
+ ULONG Error1;
+ DSTRING ChildKeyName;
+
+
+ //
+ // -Change the security of the current key
+ //
+
+ Error1 = RegSetKeySecurity( KeyHandle,
+ SecurityInformation,
+ SecurityDescriptor );
+
+
+ //
+ // Find out the total number of subkeys
+ //
+
+ Status = TRUE;
+ ClassNameLength = 0;
+
+ Error = RegQueryInfoKey(
+ KeyHandle,
+ &DummyVariable,
+ &ClassNameLength,
+ NULL,
+ &NumberOfSubKeys,
+ &MaxSubKeyLength,
+ &MaxClassLength,
+ &NumberOfValues,
+ &MaxValueNameLength,
+ &MaxValueDataLength,
+ &SecurityDescriptorLength,
+ &LastWriteTime
+ );
+ if( ( Error != 0 ) &&
+ ( Error != ERROR_ACCESS_DENIED ) &&
+ ( Error != ERROR_INVALID_PARAMETER ) &&
+ ( Error != ERROR_INSUFFICIENT_BUFFER ) &&
+ ( Error != ERROR_MORE_DATA ) ) {
+ DebugPrintf( "RegQueryInfoKey() failed, Error = %#x \n", Error );
+ DebugPrint( "RegQueryInfoKey() failed" );
+ *ErrorCode = Error;
+ return( FALSE );
+ }
+
+ if( Error == ERROR_ACCESS_DENIED ) {
+ //
+ // Handle doesn't allow KEY_QUERY_VALUE or READ_CONTROL access.
+ // Open a new handle with these accesses.
+ //
+ samDesired = KEY_QUERY_VALUE | READ_CONTROL; // MAXIMUM_ALLOWED | READ_CONTROL;
+ if( SecurityInformation & SACL_SECURITY_INFORMATION ) {
+ samDesired |= ACCESS_SYSTEM_SECURITY;
+ } else if( SecurityInformation & DACL_SECURITY_INFORMATION ) {
+ samDesired |= WRITE_DAC;
+ } else if( SecurityInformation & OWNER_SECURITY_INFORMATION ) {
+ samDesired |= WRITE_OWNER;
+ } else {
+ DebugPrint( "ERROR: SecurityInformation is invalid" );
+ DebugPrintf( "SecurityInformation is invalid, SecurityInformation = %# \n",
+ SecurityInformation );
+ }
+
+ Error = RegOpenKeyEx( KeyHandle,
+ NULL,
+ REG_OPTION_RESERVED,
+ samDesired,
+ &NewHandle
+ );
+
+ if( Error != 0 ) {
+ DebugPrintf( "RegOpenKeyEx() failed, Error = %#x \n", Error );
+ DebugPrint( "RegOpenKey() failed" );
+ *ErrorCode = Error;
+ return( FALSE );
+ }
+
+ Error = RegQueryInfoKey(
+ NewHandle,
+ &DummyVariable,
+ &ClassNameLength,
+ NULL,
+ &NumberOfSubKeys,
+ &MaxSubKeyLength,
+ &MaxClassLength,
+ &NumberOfValues,
+ &MaxValueNameLength,
+ &MaxValueDataLength,
+ &SecurityDescriptorLength,
+ &LastWriteTime
+ );
+
+ if( ( Error != 0 ) &&
+ ( Error != ERROR_INVALID_PARAMETER ) &&
+ ( Error != ERROR_INSUFFICIENT_BUFFER ) &&
+ ( Error != ERROR_MORE_DATA ) ) {
+ DebugPrintf( "RegQueryInfoKey() failed, Error = %#x \n", Error );
+ DebugPrint( "RegQueryInfoKey() failed" );
+ *ErrorCode = Error;
+ RegCloseKey( NewHandle );
+ return( FALSE );
+ }
+ RegCloseKey( NewHandle );
+ }
+
+ if( NumberOfSubKeys == 0 ) {
+ //
+ // If the key doesn't have any subkey, return TRUE or FALSE
+ // depending on whether RegSetKeySecurity() succeeded.
+ //
+ if( Error1 != ERROR_SUCCESS ) {
+ *ErrorCode = Error1;
+ return( FALSE );
+ }
+ return( TRUE );
+ }
+
+ //
+ // The key has subkeys.
+ // Find out if we are able to enumerate the key using the handle
+ // passed as argument.
+ //
+ SubKeyNameLength = MAX_PATH;
+
+ Error = RegEnumKey( KeyHandle,
+ 0,
+ SubKeyName,
+ SubKeyNameLength
+ );
+
+
+ if( Error == ERROR_ACCESS_DENIED ) {
+ //
+ // Handle doesn't allow 'enumerate' access.
+ // Open a new handle with KEY_ENUMERATE_SUB_KEYS access.
+ //
+#if 0
+ samDesired = MAXIMUM_ALLOWED | KEY_ENUMERATE_SUB_KEYS;
+ if( SecurityInformation & SACL_SECURITY_INFORMATION ) {
+ samDesired |= ACCESS_SYSTEM_SECURITY;
+ } else if( SecurityInformation & DACL_SECURITY_INFORMATION ) {
+ samDesired |= WRITE_DAC;
+ } else if( SecurityInformation & OWNER_SECURITY_INFORMATION ) {
+ samDesired |= WRITE_OWNER;
+ } else {
+ DebugPrint( "ERROR: SecurityInformation is invalid" );
+ DebugPrintf( "SecurityInformation is invalid, SecurityInformation = %# \n",
+ SecurityInformation );
+ }
+#endif
+
+ Error = RegOpenKeyEx( KeyHandle,
+ NULL,
+ REG_OPTION_RESERVED,
+ KEY_ENUMERATE_SUB_KEYS, // samDesired,
+ &NewHandle
+ );
+
+ if( Error != 0 ) {
+ DebugPrintf( "RegOpenKeyEx() failed, Error = %#x \n", Error );
+ DebugPrint( "RegOpenKey() failed" );
+ *ErrorCode = Error;
+ return( FALSE );
+ }
+
+ } else {
+ NewHandle = KeyHandle;
+ }
+
+
+
+
+ for( Index = 0; Index < NumberOfSubKeys; Index++ ) {
+
+ // If the key has subkeys, then for each subkey, do:
+ //
+ //
+ // - Determine the subkey name
+ //
+ SubKeyNameLength = MAX_PATH;
+
+ Error = RegEnumKey( NewHandle,
+ Index,
+ SubKeyName,
+ SubKeyNameLength
+ );
+
+
+ if( Error != ERROR_SUCCESS ) {
+ DebugPrintf( "RegQueryInfoKey() failed, Error = %#x \n", Error );
+ DebugPrint( "RegQueryInfoKey() failed" );
+ *ErrorCode = Error;
+ if( NewHandle != KeyHandle ){
+ RegCloseKey( NewHandle );
+ }
+ return( FALSE );
+ }
+
+ if( !ChildKeyName.Initialize( SubKeyName ) ) {
+ DebugPrint( "ChildKeyName.Initialize() failed" );
+ *ErrorCode = ERROR_OUTOFMEMORY;
+ if( NewHandle != KeyHandle ){
+ RegCloseKey( NewHandle );
+ }
+ return( FALSE );
+ }
+
+
+ //
+ // - Open a handle to the subkey
+ //
+
+ samDesired = MAXIMUM_ALLOWED;
+ if( SecurityInformation & SACL_SECURITY_INFORMATION ) {
+ samDesired |= ACCESS_SYSTEM_SECURITY;
+ } else if( SecurityInformation & DACL_SECURITY_INFORMATION ) {
+ samDesired |= WRITE_DAC;
+ } else if( SecurityInformation & OWNER_SECURITY_INFORMATION ) {
+ samDesired |= WRITE_OWNER;
+ } else {
+ DebugPrint( "ERROR: SecurityInformation is invalid" );
+ DebugPrintf( "SecurityInformation is invalid, SecurityInformation = %# \n",
+ SecurityInformation );
+ }
+
+ Error = RegOpenKeyEx( NewHandle,
+ ( LPWSTR )( ChildKeyName.GetWSTR() ),
+ REG_OPTION_RESERVED,
+ samDesired,
+ &ChildHandle
+ );
+
+
+ if( Error == ERROR_SUCCESS ) {
+
+ //
+ // - Set the security of the child's subkeys
+ //
+
+ if( !SetSubKeysSecurity( ChildHandle,
+ SecurityInformation,
+ SecurityDescriptor,
+ ErrorCode ) ) {
+ Status = FALSE;
+ }
+
+ Error = RegCloseKey( ChildHandle );
+ if( Error != 0 ) {
+ DebugPrintf( "CloseKey() failed, Error = %#x \n", Error );
+ DebugPrint( "RegCloseKey() failed" );
+ }
+
+ } else {
+ DebugPrintf( "RegOpenKeyEx() failed, Error = %#x \n", Error );
+ DebugPrint( "RegOpenKey() failed" );
+ *ErrorCode = Error;
+ Status = FALSE;
+ }
+
+ }
+
+ if( KeyHandle != NewHandle ) {
+ RegCloseKey( NewHandle );
+ }
+
+ if( Error1 != ERROR_SUCCESS ) {
+ *ErrorCode = Error1;
+ return( FALSE );
+ }
+ return Status;
+}
+
+#endif
+
+
+
+#if !defined( _AUTOCHECK_ )
+
+BOOLEAN
+REGISTRY::LoadHive(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PREGISTRY_KEY_INFO KeyInfo,
+ IN PCWSTRING FileName,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+
+ Load a file that conmtains a hive in a particular key in the
+ registry.
+
+
+Arguments:
+
+
+ PredefinedKey
+
+ KeyInfo
+
+ FileName
+
+ ErrorCode
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the hive was loaded.
+
+--*/
+{
+ LONG Status;
+ PCWSTRING ParentName;
+ PCWSTRING KeyName;
+ PWSTRING CompleteName;
+
+ PWSTR String;
+ PWSTR String1;
+
+
+ DebugPtrAssert( KeyInfo );
+ DebugPtrAssert( FileName );
+
+
+ ParentName = KeyInfo->GetParentName();
+ KeyName = KeyInfo->GetName();
+
+ if( ( ParentName == NULL ) ||
+ ( KeyName == NULL ) ) {
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ return( FALSE );
+ }
+ }
+
+ //
+ // Get the complete key name
+ //
+ CompleteName = BuildCompleteName( ParentName, KeyName );
+ if( CompleteName == NULL ) {
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ }
+ DebugPtrAssert( CompleteName );
+ return( FALSE );
+ }
+
+
+ String = CompleteName->QueryWSTR();
+ String1 = FileName->QueryWSTR();
+
+ DELETE( CompleteName );
+
+ if( ( String == NULL ) ||
+ ( String1 == NULL ) ) {
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ }
+ DebugPtrAssert( String );
+ DebugPtrAssert( String1 );
+ return( FALSE );
+ }
+
+ Status = RegLoadKey( _PredefinedKey[ PredefinedKey ],
+ String,
+ String1 );
+
+ FREE( String );
+ FREE( String1 );
+ if( Status != 0 ) {
+ DebugPrint( "RegLoadKey() failed" );
+ DebugPrintf( "RegLoadKey() failed, Status = %d \n", Status );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+ return( FALSE );
+ }
+
+ Status = RegFlushKey( _PredefinedKey[ PredefinedKey ] );
+ if( Status != 0 ) {
+ DebugPrintf( "RegFlushKey() failed, Status = %d \n", Status );
+ DebugPrint( "RegFlushKey() failed" );
+ }
+
+
+ if( !UpdateKeyInfo( PredefinedKey, KeyInfo, ErrorCode ) ) {
+ DebugPrint( "UpdateKeyInfo() failed" );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_KEY_INFO_NOT_UPDATED;
+ }
+ return( FALSE );
+ }
+
+ return( TRUE );
+}
+
+#endif
+
+
+
+
+#if !defined( _AUTOCHECK_ )
+
+BOOLEAN
+REGISTRY::UnLoadHive(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PREGISTRY_KEY_INFO KeyInfo,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+
+ Unload a the key from the registry.
+
+
+Arguments:
+
+
+ PredefinedKey
+
+ KeyInfo
+
+ ErrorCode
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the hive was loaded.
+
+--*/
+{
+ LONG Status;
+ PCWSTRING ParentName;
+ PCWSTRING KeyName;
+ PWSTRING CompleteName;
+
+ PWSTR Name;
+
+
+ ParentName = KeyInfo->GetParentName();
+ KeyName = KeyInfo->GetName();
+
+ if( ( ParentName == NULL ) ||
+ ( KeyName == NULL ) ) {
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ return( FALSE );
+ }
+ }
+
+ //
+ // Get the complete key name
+ //
+ CompleteName = BuildCompleteName( ParentName, KeyName );
+ if( CompleteName == NULL ) {
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ }
+ DebugPtrAssert( CompleteName );
+ return( FALSE );
+ }
+
+
+ Name = CompleteName->QueryWSTR();
+ DELETE( CompleteName );
+
+ if( Name == NULL ) {
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ }
+ DebugPtrAssert( Name );
+ return( FALSE );
+ }
+
+ Status = RegUnLoadKey( _PredefinedKey[ PredefinedKey ],
+ Name );
+
+ FREE( Name );
+ if( Status != 0 ) {
+ DebugPrint( "RegUnLoadKey() failed" );
+ DebugPrintf( "RegUnLoadKey() failed, Status = %d \n", Status );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+ return( FALSE );
+ }
+ Status = RegFlushKey( _PredefinedKey[ PredefinedKey ] );
+ if( Status != 0 ) {
+ DebugPrintf( "RegFlushKey() failed, Status = %d \n", Status );
+ DebugPrint( "RegFlushKey() failed" );
+ }
+ return( TRUE );
+}
+
+#endif
+
+
+
+
+
+BOOLEAN
+REGISTRY::SaveKeyToFile(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PREGISTRY_KEY_INFO KeyInfo,
+ IN PCWSTRING FileName,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+
+ Save a key and all uts subkeys to a file..
+
+
+Arguments:
+
+
+ KeyInfo
+
+ FileName
+
+ ErrorCode
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the key was saved.
+
+--*/
+{
+ LONG Status;
+ PCWSTRING ParentName;
+ PCWSTRING KeyName;
+ HKEY Key;
+ PWSTR Name;
+
+
+ ParentName = KeyInfo->GetParentName();
+ KeyName = KeyInfo->GetName();
+
+ if( ( ParentName == NULL ) ||
+ ( KeyName == NULL ) ) {
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ return( FALSE );
+ }
+ }
+
+
+ if( !OpenKey( PredefinedKey,
+ ParentName,
+ KeyName,
+ KEY_READ,
+ &Key,
+ ErrorCode ) ) {
+
+ DebugPrint( "OpenKey() failed" );
+ DebugPrintf( "OpenKey() failed, ErrorCode = %d \n", *ErrorCode );
+ return( FALSE );
+ }
+
+
+ Name = FileName->QueryWSTR();
+
+ if( Name == NULL ) {
+ if( Key != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Key );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ }
+ return( FALSE );
+ }
+
+ Status = RegSaveKey( Key,
+ Name,
+ NULL );
+ FREE( Name );
+
+ if( Key != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Key );
+ }
+ if( Status != 0 ) {
+ DebugPrint( "RegSaveKey() failed" );
+ DebugPrintf( "RegSaveKey() failed, Status = %d \n", Status );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+REGISTRY::RestoreKeyFromFile(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PREGISTRY_KEY_INFO KeyInfo,
+ IN PCWSTRING FileName,
+ IN BOOLEAN Volatile,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+
+ Save a key and all uts subkeys to a file..
+
+
+Arguments:
+
+
+ KeyInfo - Pointer to the object that describes the key where the
+ contents of the file is to be restored.
+
+ FileName - Name of the file that contains the information to be
+ restored.
+
+ Volatile - Indicates whether the information should be restore as
+ volatile or non-volatile.
+
+ ErrorCode - Contains an error code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the key was restored.
+
+--*/
+{
+ LONG Status;
+ LONG Error;
+ PCWSTRING ParentName;
+ PCWSTRING KeyName;
+ HKEY Key;
+ PWSTR Name;
+
+
+ ParentName = KeyInfo->GetParentName();
+ KeyName = KeyInfo->GetName();
+
+ if( ( ParentName == NULL ) ||
+ ( KeyName == NULL ) ) {
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ return( FALSE );
+ }
+ }
+
+
+ if( !OpenKey( PredefinedKey,
+ ParentName,
+ KeyName,
+ KEY_WRITE,
+ &Key,
+ ErrorCode ) ) {
+
+ DebugPrint( "OpenKey() failed" );
+ DebugPrintf( "OpenKey() failed, ErrorCode = %d \n", *ErrorCode );
+ return( FALSE );
+ }
+
+
+ Name = FileName->QueryWSTR();
+
+ if( Name == NULL ) {
+ if( Key != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Key );
+ }
+ if( ErrorCode != NULL ) {
+ *ErrorCode = REGISTRY_ERROR_OUTOFMEMORY;
+ }
+ return( FALSE );
+ }
+
+ Status = RegRestoreKey( Key,
+ Name,
+ (Volatile)? REG_WHOLE_HIVE_VOLATILE : 0 );
+ FREE( Name );
+
+
+
+
+ if( Status == 0 ) {
+ Error = RegFlushKey( Key );
+ if( Error != 0 ) {
+ DebugPrintf( "RegFlushKey() failed, Error = %d \n", Error );
+ DebugPrint( "RegFlushKey() failed" );
+ }
+ }
+ if( Key != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Key );
+ }
+ if( Status != 0 ) {
+ DebugPrint( "RegRestoreKey() failed" );
+ DebugPrintf( "RegRestoreKey() failed, Status = %d \n", Status );
+ if( ErrorCode != NULL ) {
+ *ErrorCode = MapWin32RegApiToRegistryError( Status );
+ }
+ return( FALSE );
+ }
+
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+REGISTRY::IsAccessAllowed(
+ IN PREDEFINED_KEY PredefinedKey,
+ IN PREGISTRY_KEY_INFO KeyInfo,
+ IN REGSAM SamDesired,
+ OUT PULONG ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+
+ Determine if a key allows a particular access.
+
+Arguments:
+
+
+ PredefinedKey -
+
+ KeyInfo - Pointer to the object that describes the key.
+
+ SamDesired - Access to be verified.
+
+ ErrorCode - Contains an error code if the operation fails.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the key allows the access, or FALSE otherwise
+
+--*/
+{
+ PCWSTRING ParentName;
+ PCWSTRING KeyName;
+
+ HKEY Handle;
+
+
+
+ DebugPtrAssert( KeyInfo );
+
+ ParentName = KeyInfo->GetParentName();
+ DebugPtrAssert( ParentName );
+
+ KeyName = KeyInfo->GetName();
+ DebugPtrAssert( KeyName );
+
+ if( !OpenKey( PredefinedKey,
+ ParentName,
+ KeyName,
+ SamDesired,
+ &Handle,
+ ErrorCode ) ) {
+ DebugPrint( "OpenKey() failed" );
+ return( FALSE );
+ }
+ if( Handle != _PredefinedKey[ PredefinedKey ] ) {
+ RegCloseKey( Handle );
+ }
+ return( TRUE );
+}
diff --git a/private/utils/ureg/src/regkey.cxx b/private/utils/ureg/src/regkey.cxx
new file mode 100644
index 000000000..8cf4ba3ad
--- /dev/null
+++ b/private/utils/ureg/src/regkey.cxx
@@ -0,0 +1,421 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ regkey.cxx
+
+Abstract:
+
+ This module contains the member function definitions for REGISTRY_KEY_INFO
+ class.
+ REGISTRY_KEY_INFO is class that contains all the information of a
+ registry key, such as:
+
+ -Key Name
+ -Title Index
+ -Class
+ -Security Attributes
+ -Last Write Time
+ -Number of Sub-keys
+ -Number of Value Entries
+
+ A REGISTRY_KEY_INFO object is reinitializable.
+
+Author:
+
+ Jaime Sasson (jaimes) 01-Mar-1992
+
+
+Environment:
+
+ Ulib, User Mode
+
+
+--*/
+
+
+#include "regkey.hxx"
+
+
+DEFINE_CONSTRUCTOR( REGISTRY_KEY_INFO, OBJECT );
+
+
+
+REGISTRY_KEY_INFO::~REGISTRY_KEY_INFO(
+
+)
+/*++
+
+Routine Description:
+
+ Destroy a REGISTRY_KEY_INFO object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+
+VOID
+REGISTRY_KEY_INFO::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Worker method for object construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _TitleIndex = 0;
+ _NumberOfSubKeys = 0;
+ _NumberOfValues = 0;
+
+#if !defined( _AUTOCHECK_ )
+ _SecurityAttributes.nLength = 0;
+ _SecurityAttributes.lpSecurityDescriptor = NULL;
+ _SecurityAttributes.bInheritHandle = FALSE;
+#endif
+}
+
+
+
+VOID
+REGISTRY_KEY_INFO::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Worker method for object destruction or reinitialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _NumberOfSubKeys = 0;
+ _NumberOfValues = 0;
+ _TitleIndex = 0;
+ _KeyIsCompletelyInitialized = FALSE;
+
+#if !defined( _AUTOCHECK_ )
+ FREE( _SecurityAttributes.lpSecurityDescriptor );
+ _SecurityAttributes.nLength = 0;
+ _SecurityAttributes.lpSecurityDescriptor = NULL;
+ _SecurityAttributes.bInheritHandle = FALSE;
+#endif
+}
+
+
+
+BOOLEAN
+REGISTRY_KEY_INFO::Initialize(
+ )
+/*++
+
+Routine Description:
+
+ Initialize or re-initialize a REGISTRY_KEY_INFO object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns always TRUE.
+
+--*/
+
+{
+ Destroy();
+ if( !_ParentName.Initialize( "" ) ) {
+ DebugPrint( "_ParentName.Initialize() failed" );
+ return( FALSE );
+ }
+ if( !_Name.Initialize( "" ) ) {
+ DebugPrint( "_Name.Initialize() failed" );
+ return( FALSE );
+ }
+ return( TRUE );
+}
+
+
+
+BOOLEAN
+REGISTRY_KEY_INFO::Initialize(
+ IN PCWSTRING KeyName,
+ IN PCWSTRING ParentName,
+ IN ULONG TitleIndex,
+ IN PCWSTRING Class,
+ IN PSECURITY_ATTRIBUTES SecurityAttributes
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize or re-initialize a REGISTRY_KEY_INFO object.
+
+Arguments:
+
+ KeyName - Pointer to a WSTRING object that contains the key name.
+
+ ParentName - Pointer to a WSTRING object that contains the parent's
+ name.
+
+ TitleIndex - The title index associated to the key.
+
+ Class - Pointer to a WSTRING object that contains the key class.
+
+ SecurityAttributes - Pointer to an initialized security attribute object.
+
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if the operation succeeds.
+
+--*/
+
+{
+ //
+ // Check for NULL pointers
+ //
+ DebugPtrAssert( Class );
+// DebugPtrAssert( SecurityAttributes );
+ DebugAssert( !( ( ParentName != NULL ) && ( KeyName == NULL ) ) ||
+ !( ( ParentName != NULL ) && ( ParentName->QueryChCount() != 0 ) &&
+ ( KeyName != NULL ) && ( KeyName->QueryChCount() == 0 ) ) );
+
+
+
+ Destroy();
+
+
+ if( ( ( KeyName == NULL ) && ( ParentName == NULL ) ) ||
+ ( ( KeyName != NULL ) && ( KeyName->QueryChCount() == 0 ) &&
+ ( ParentName != NULL ) && ( ParentName->QueryChCount() == 0 ) ) ) {
+ //
+ // This REGISTRY_KEY_INFO represents a predefined key.
+ //
+ if( !_ParentName.Initialize( "" ) ) {
+ DebugPrint( "_ParentName.Initialize() failed" );
+ return( FALSE );
+ }
+ if( !_Name.Initialize( "" ) ) {
+ DebugPrint( "_Name.Initialize() failed" );
+ return( FALSE );
+ }
+
+ } else {
+ //
+ // This REGISTRY_KEY_INFO does not represent a predefined key,
+ // so it has a name.
+ // Make sure that the name is relative to its parent
+ //
+ if( KeyName->Strrchr( ( WCHAR )'\\' ) != INVALID_CHNUM ) {
+ DebugPrint( "KeyName is not a valid one" );
+ }
+
+ //
+ // Initialize _ParentName
+ //
+ if( ( ParentName == NULL ) || ( ParentName->QueryChCount() == 0 ) ) {
+ //
+ // This REGISTRY_KEY_INFO represents the subkey of a
+ // predefined key
+ //
+ if( !_ParentName.Initialize( "" ) ) {
+ DebugPrint( "_ParentName.Initialize() failed" );
+ return( FALSE );
+ }
+ } else {
+ if( !_ParentName.Initialize( ParentName ) ) {
+ DebugPrint( "_ParentName.Initialize( ParentName )" );
+ return( FALSE );
+ }
+ }
+
+ //
+ // Initialize _Name
+ //
+ if( !_Name.Initialize( KeyName ) ) {
+ DebugPrint( "_Name.Initialize( KeyName )" );
+ return( FALSE );
+ }
+ }
+
+
+ _TitleIndex = TitleIndex;
+
+ if( !_Class.Initialize( Class ) ) {
+ DebugPrint( "_Class.Initialize( Class )" );
+ return( FALSE );
+ }
+
+#if !defined( _AUTOCHECK_ )
+ PutSecurityAttributes( SecurityAttributes );
+#endif
+ _KeyIsCompletelyInitialized = FALSE;
+ return( TRUE );
+}
+
+#if !defined( _AUTOCHECK_ )
+
+VOID
+REGISTRY_KEY_INFO::PutSecurityAttributes(
+ IN PSECURITY_ATTRIBUTES SecurityAttributes
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize the variable _SecurityAttributes.
+
+
+Arguments:
+
+ SecurityAttributes - Pointer to the security attribute
+
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ ULONG Length;
+ PBYTE Pointer;
+
+
+// DebugPtrAssert( SecurityAttributes );
+ if( SecurityAttributes != NULL ) {
+
+ Length = GetSecurityDescriptorLength( SecurityAttributes->lpSecurityDescriptor );
+
+ FREE( _SecurityAttributes.lpSecurityDescriptor );
+
+ Pointer = ( PBYTE )MALLOC( ( size_t )Length );
+ DebugPtrAssert( Pointer );
+ memcpy( Pointer, SecurityAttributes->lpSecurityDescriptor, ( size_t )Length );
+
+ _SecurityAttributes.nLength = SecurityAttributes->nLength;
+ _SecurityAttributes.lpSecurityDescriptor = Pointer;
+ _SecurityAttributes.bInheritHandle = SecurityAttributes->bInheritHandle;
+ } else {
+ Pointer = ( PBYTE )MALLOC( ( size_t )SECURITY_DESCRIPTOR_MIN_LENGTH );
+ DebugPtrAssert( Pointer );
+ InitializeSecurityDescriptor( Pointer, 1 );
+ _SecurityAttributes.nLength = sizeof( SECURITY_ATTRIBUTES );
+ _SecurityAttributes.lpSecurityDescriptor = Pointer;
+ _SecurityAttributes.bInheritHandle = FALSE;
+ }
+}
+#endif
+
+
+#if DBG
+
+VOID
+REGISTRY_KEY_INFO::DbgPrintKeyInfo(
+ )
+
+/*++
+
+Routine Description:
+
+ Print the contents of a REGISTRY_INFO_KEY.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSTR Pointer;
+ PSTR StrDate;
+ PSTR StrTime;
+
+ DSTRING Date;
+ DSTRING Time;
+
+ DebugPrintf( "====Dumping a REGISTRY_KEY_INFO object ====\n \n" );
+ Pointer = _ParentName.QuerySTR();
+ DebugPtrAssert( Pointer );
+ DebugPrintf( " ParentName = %s \n", Pointer );
+ FREE( Pointer );
+
+ Pointer = _Name.QuerySTR();
+ DebugPtrAssert( Pointer );
+ DebugPrintf( " Name = %s \n", Pointer );
+ FREE( Pointer );
+
+ Pointer = _Class.QuerySTR();
+ DebugPtrAssert( Pointer );
+ DebugPrintf( " Class = %s \n", Pointer );
+ FREE( Pointer );
+
+ DebugPrintf( " Title Index = %d \n", _TitleIndex );
+
+ if( !_LastWriteTime.QueryDate( &Date ) ||
+ !_LastWriteTime.QueryTime( &Time ) ) {
+ DebugPrint( "Can't get date or time" );
+ } else {
+ StrDate = Date.QuerySTR();
+ DebugPtrAssert( StrDate );
+ StrTime = Time.QuerySTR();
+ DebugPtrAssert( StrTime );
+ DebugPrintf( " LastWriteTime = %s %s \n", StrDate, StrTime );
+ FREE( StrDate );
+ FREE( StrTime );
+ }
+
+ DebugPrintf( " SecurityAttributes.nLength = %d \n", _SecurityAttributes.nLength );
+ DebugPrintf( " SecurityAttributes.lpSecurityDescriptor = %08x \n",
+ _SecurityAttributes.lpSecurityDescriptor );
+
+ if( _SecurityAttributes.bInheritHandle ) {
+ DebugPrintf( " SecurityAttributes.bInheritHandle = TRUE \n" );
+ } else {
+ DebugPrintf( " SecurityAttributes.bInheritHandle = FALSE \n" );
+ }
+
+ DebugPrintf( " NumberOfSubKeys = %d \n", _NumberOfSubKeys );
+ DebugPrintf( " NumberOfValues = %d \n", _NumberOfValues );
+ DebugPrintf( "\n\n" );
+}
+
+#endif // DBG
diff --git a/private/utils/ureg/src/regvalue.cxx b/private/utils/ureg/src/regvalue.cxx
new file mode 100644
index 000000000..7b0c32d76
--- /dev/null
+++ b/private/utils/ureg/src/regvalue.cxx
@@ -0,0 +1,358 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ value.cxx
+
+Abstract:
+
+ This module contains the methods for the REGISTRY_VALUE_ENTRY class.
+
+Author:
+
+ Jaime Sasson (jaimes) 26-Aug-1991
+
+Environment:
+
+ Ulib, Regedit, Windows, User Mode
+
+--*/
+
+#include "regvalue.hxx"
+
+
+DEFINE_CONSTRUCTOR( REGISTRY_VALUE_ENTRY, OBJECT );
+
+DEFINE_CAST_MEMBER_FUNCTION( REGISTRY_VALUE_ENTRY );
+
+
+
+REGISTRY_VALUE_ENTRY::~REGISTRY_VALUE_ENTRY(
+
+)
+/*++
+
+Routine Description:
+
+ Destroy a REGISTRY_VALUE_ENTRY object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Destroy();
+}
+
+
+VOID
+REGISTRY_VALUE_ENTRY::Construct (
+ )
+/*++
+
+Routine Description:
+
+ Worker method for object construction.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ _TitleIndex = 0;
+ _Type = TYPE_UNKNOWN;
+ _Size = 0;
+ _Data = NULL;
+}
+
+
+VOID
+REGISTRY_VALUE_ENTRY::Destroy(
+ )
+/*++
+
+Routine Description:
+
+ Worker method for object destruction or reinitialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ DELETE( _Data );
+ _Data = NULL;
+ _TitleIndex = 0;
+ _Type = TYPE_UNKNOWN;
+ _Size = 0;
+}
+
+
+BOOLEAN
+REGISTRY_VALUE_ENTRY::Initialize(
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize or re-initialize a REGISTRY_VALUE_ENTRY object.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns always TRUE
+
+
+--*/
+
+
+{
+ Destroy();
+ return( TRUE );
+}
+
+
+BOOLEAN
+REGISTRY_VALUE_ENTRY::Initialize(
+ IN PCWSTRING ValueName,
+ IN ULONG TitleIndex,
+ IN REG_TYPE Type,
+ IN PCBYTE Data,
+ IN ULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize or re-initialize a REGISTRY_VALUE_ENTRY object.
+
+Arguments:
+
+
+ ValueName - Pointer to a WSTRING that contains the value name.
+
+ TitleIndex - The title index associated with the value name.
+
+ Type - The type of value stored in this object.
+
+ Data - Buffer that contains the value to be stored.
+
+ Size - Number of bytes in the buffer.
+
+
+
+Return Value:
+
+ BOOLEAN - Returns always TRUE
+
+
+--*/
+
+
+{
+ DebugPtrAssert( ValueName );
+ DebugAssert( ( Size == 0 ) || ( Data != NULL ) );
+
+ Destroy();
+ if( !_Name.Initialize( ValueName ) ) {
+ return( FALSE );
+ }
+ _TitleIndex = TitleIndex;
+ _Type = Type;
+ if( Size == 0 ) {
+ _Data = NULL;
+ _Size = 0;
+ } else {
+ PutData( Data, Size );
+ }
+ return( TRUE );
+}
+
+
+
+VOID
+REGISTRY_VALUE_ENTRY::PutData(
+ IN PCBYTE Data,
+ IN ULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ Set the data stored in this object.
+
+
+Arguments:
+
+ Data - Pointer to the buffer that contains the data.
+
+ Size - Number of valid bytes in the buffer (data size).
+
+
+Return Value:
+
+ None.
+
+
+--*/
+
+
+{
+ DebugAssert( ( Size == 0 ) || ( Data != NULL ) );
+
+ if( _Data != NULL ) {
+ FREE( _Data );
+ }
+ if( Size == 0 ) {
+ _Data = NULL;
+ _Size = 0;
+ } else {
+ _Data = ( PBYTE )MALLOC( ( size_t )( Size + 2 ) );
+ _Size = Size;
+ DebugPtrAssert( _Data );
+ memcpy( _Data, Data, ( size_t )Size );
+ *( _Data + Size ) = '\0';
+ *( _Data + Size + 1 ) = '\0';
+ }
+}
+
+
+
+
+#if DBG
+
+VOID
+REGISTRY_VALUE_ENTRY::DbgPrintValueEntry(
+ )
+
+/*++
+
+Routine Description:
+
+ Display the contents of a value entry object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+
+{
+ PSTR Pointer;
+
+ DebugPrintf( "======== Dumping a REGISTRY_VALUE_ENTRY object ==== \n\n" );
+ Pointer = _Name.QuerySTR();
+ DebugPrintf( " _Name = %s \n", Pointer );
+ FREE( Pointer );
+
+ DebugPrintf( " _TitleIndex = %d \n", _TitleIndex );
+
+ switch( _Type ) {
+
+ case TYPE_REG_NONE:
+ DebugPrintf( " _Type = TYPE_REG_NONE \n" );
+ DebugPrintf( " _Size = %d \n", _Size );
+ break;
+
+ case TYPE_REG_SZ:
+ DebugPrintf( " _Type = TYPE_REG_SZ \n" );
+ DebugPrintf( " _Size = %d \n", _Size );
+ if( _Size == 0 ) {
+ DebugPrintf( " There is no data to display in this value entry \n" );
+ } else {
+ DebugPrintf( " _Data = %s \n", _Data );
+ }
+ break;
+
+ case TYPE_REG_BINARY:
+ DebugPrintf( " _Type = TYPE_REG_BINARY \n" );
+ DebugPrintf( " _Size = %d \n", _Size );
+
+ if( _Size == 0 ) {
+ DebugPrintf( " There is no data to display in this value entry \n" );
+ } else {
+ DebugPrintf( " Don't know how to print binary data \n" );
+ }
+ break;
+
+ case TYPE_REG_DWORD:
+ DebugPrintf( " _Type = TYPE_REG_DWORD \n" );
+ if( _Size == sizeof( DWORD ) ) {
+ DebugPrintf( " _Data = %08x \n", *( ( LPDWORD ) _Data ) );
+ } else {
+ DebugPrintf( " ERROR: Data has incorrect size, Size = %d \n", _Size );
+ }
+ break;
+
+ case TYPE_REG_RESOURCE_LIST:
+ DebugPrintf( " _Type = TYPE_REG_RESOURCE_LIST \n" );
+ DebugPrintf( " _Size = %d \n", _Size );
+
+ if( _Size == 0 ) {
+ DebugPrintf( " There is no data to display in this value entry \n" );
+ } else {
+ DebugPrintf( " Don't know how to print resource list \n" );
+ }
+ break;
+
+ case TYPE_REG_FULL_RESOURCE_DESCRIPTOR:
+ DebugPrintf( " _Type = TYPE_REG_FULL_RESOURCE_DESCRIPTOR \n" );
+ DebugPrintf( " _Size = %d \n", _Size );
+
+ if( _Size == 0 ) {
+ DebugPrintf( " There is no data to display in this value entry \n" );
+ } else {
+ DebugPrintf( " Don't know how to print a full resource descriptor \n" );
+ }
+ break;
+
+ case TYPE_REG_RESOURCE_REQUIREMENTS_LIST:
+ DebugPrintf( " _Type = TYPE_REG_RESOURCE_REQUIREMENTS_LIST \n" );
+ DebugPrintf( " _Size = %d \n", _Size );
+
+ if( _Size == 0 ) {
+ DebugPrintf( " There is no data to display in this value entry \n" );
+ } else {
+ DebugPrintf( " Don't know how to print a requirements list \n" );
+ }
+ break;
+
+ case TYPE_UNKNOWN:
+ default:
+ DebugPrintf( " _Type = UNKNOWN \n" );
+ DebugPrintf( " _Size = %d \n", _Size );
+ break;
+ }
+
+}
+
+#endif // DBG
diff --git a/private/utils/ureg/src/sources b/private/utils/ureg/src/sources
new file mode 100644
index 000000000..2bf52eb00
--- /dev/null
+++ b/private/utils/ureg/src/sources
@@ -0,0 +1,75 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=utils
+MINORCOMP=ureg
+
+TARGETNAME=ureg
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+TARGETLIBS=\nt\public\sdk\lib\*\kernel32.lib \
+ \nt\public\sdk\lib\*\advapi32.lib \
+ ..\..\ulib\src\obj\*\ulib.lib
+
+DLLENTRY=InitializeUreg
+
+USE_CRTDLL=1
+BLDCRT=1
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=regvalue.cxx \
+ regkey.cxx \
+ registry.cxx \
+ ureg.cxx \
+ ureg.rc
+
+
+INCLUDES=..\inc;..\..\ulib\inc;\nt\public\sdk\inc
+
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+CXXFLAGS=+d
+UMLIBS=obj\*\ureg.lib
+
+UMTYPE=console
+
+UMTEST=
+UMRES=obj\*\ureg.res
+
+NTTARGETFILE0=obj\*\ureg.def
+
+DLLDEF=obj\*\ureg.def
diff --git a/private/utils/ureg/src/ureg.cxx b/private/utils/ureg/src/ureg.cxx
new file mode 100644
index 000000000..fbcddfb54
--- /dev/null
+++ b/private/utils/ureg/src/ureg.cxx
@@ -0,0 +1,125 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ureg.cxx
+
+Abstract:
+
+ This module contains run-time, global support for the
+ Registry Utilities library (UREG). This support includes:
+
+ - creation of CLASS_DESCRIPTORs
+ - Global objects
+
+Author:
+
+ JAIME SASSON (JAIMES) 02-Dez-1992
+
+Environment:
+
+ User Mode
+
+Notes:
+
+--*/
+
+#include "ulib.hxx"
+
+#include "error.hxx"
+
+#if !defined( _AUTOCHECK_ )
+
+ ERRSTACK* perrstk;
+
+#endif // _AUTOCHECK_
+
+
+// Local prototypes
+
+STATIC
+BOOLEAN
+DefineClassDescriptors(
+ );
+
+extern "C" BOOLEAN
+InitializeUreg (
+ PVOID DllHandle,
+ ULONG Reason,
+ PCONTEXT Context
+ );
+
+BOOLEAN
+InitializeUreg (
+ PVOID DllHandle,
+ ULONG Reason,
+ PCONTEXT Context
+ )
+/*++
+
+Routine Description:
+
+ Initialize Ureg by constructing and initializing all
+ global objects. These include:
+
+ - all CLASS_DESCRIPTORs (class_cd)
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ BOOLEAN - Returns TRUE if all global objects were succesfully constructed
+ and initialized.
+
+--*/
+
+{
+
+ STATIC BOOLEAN fInit = FALSE;
+
+ if ( fInit ) {
+
+ return( TRUE );
+ }
+
+ if ( DefineClassDescriptors() ) {
+
+ fInit = TRUE;
+ return TRUE;
+
+ } else {
+
+ DebugAbort( "Ureg initialization failed!!!\n" );
+ return( FALSE );
+ }
+}
+
+
+
+DECLARE_CLASS( REGISTRY_VALUE_ENTRY );
+DECLARE_CLASS( REGISTRY_KEY_INFO );
+DECLARE_CLASS( REGISTRY );
+
+
+STATIC
+BOOLEAN
+DefineClassDescriptors(
+ )
+{
+ if( DEFINE_CLASS_DESCRIPTOR( REGISTRY_VALUE_ENTRY ) &&
+ DEFINE_CLASS_DESCRIPTOR( REGISTRY_KEY_INFO ) &&
+ DEFINE_CLASS_DESCRIPTOR( REGISTRY )
+ ) {
+
+ return TRUE;
+
+ } else {
+
+ DebugPrint( "Could not initialize class descriptors!");
+ return FALSE;
+ }
+}
diff --git a/private/utils/ureg/src/ureg.rc b/private/utils/ureg/src/ureg.rc
new file mode 100644
index 000000000..97b7db9de
--- /dev/null
+++ b/private/utils/ureg/src/ureg.rc
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Registry Utility DLL"
+#define VER_INTERNALNAME_STR "ureg.dll"
+#define VER_ORIGINALFILENAME_STR "ureg.dll"
+
+#include "common.ver"
diff --git a/private/utils/windisk/clear/clear.cxx b/private/utils/windisk/clear/clear.cxx
new file mode 100644
index 000000000..6f12bcf86
--- /dev/null
+++ b/private/utils/windisk/clear/clear.cxx
@@ -0,0 +1,105 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: clear.cxx
+//
+// Contents: Disk Administrator: utility to clear the registry to make it
+// appear that this is the first time Disk Administrator has been
+// run.
+//
+//
+// The following need to be deleted:
+//
+// The registry key: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\IniFileMapping\windisk.ini
+//
+// The registry key: HKEY_CURRENT_USER\Software\Microsoft\Disk Administrator
+//
+// The registry value: HKEY_CURRENT_MACHINE\System\CurrentControlSet\Control\Lsa : Protect System Partition
+//
+// History: 8-Jun-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+char* program;
+
+void
+usage()
+{
+ fprintf(stderr,"Usage: %s\n",program);
+ exit(1);
+}
+
+void _CRTAPI1
+main(int argc, char* argv[])
+{
+ char* psz;
+
+ program = argv[0];
+
+ if (argc != 1)
+ {
+ usage();
+ }
+
+ LONG ec;
+ HKEY hkey;
+
+ ec = RegDeleteKeyA( HKEY_LOCAL_MACHINE,
+ "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\IniFileMapping\\windisk.ini"
+ );
+
+ psz = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\IniFileMapping\\windisk.ini";
+
+ if (ec != ERROR_SUCCESS)
+ {
+ fprintf(stderr, "Couldn't delete %s\n", psz);
+ }
+ else
+ {
+ fprintf(stdout, "Deleted %s\n", psz);
+ }
+
+ ec = RegDeleteKeyA( HKEY_CURRENT_USER,
+ "Software\\Microsoft\\Disk Administrator"
+ );
+
+ psz = "HKEY_CURRENT_USER\\Software\\Microsoft\\Disk Administrator";
+
+ if (ec != ERROR_SUCCESS)
+ {
+ fprintf(stderr, "Couldn't delete %s\n", psz);
+ }
+ else
+ {
+ fprintf(stdout, "Deleted %s\n", psz);
+ }
+
+ //
+ // get rid of the Registry entry concerning a protected system partition
+ //
+
+ ec = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+ TEXT("System\\CurrentControlSet\\Control\\Lsa"),
+ 0,
+ KEY_SET_VALUE,
+ &hkey
+ );
+
+ if(ec == NO_ERROR)
+ {
+ ec = RegDeleteValue(hkey, TEXT("Protect System Partition"));
+
+ // ignore errors: if we couldn't delete it, it probably wasn't there
+
+ RegCloseKey(hkey);
+ }
+
+
+ exit(0);
+}
diff --git a/private/utils/windisk/clear/makefile b/private/utils/windisk/clear/makefile
new file mode 100644
index 000000000..14f79b701
--- /dev/null
+++ b/private/utils/windisk/clear/makefile
@@ -0,0 +1 @@
+!include $(NTMAKEENV)\makefile.def
diff --git a/private/utils/windisk/clear/sources b/private/utils/windisk/clear/sources
new file mode 100644
index 000000000..39c7f28d0
--- /dev/null
+++ b/private/utils/windisk/clear/sources
@@ -0,0 +1,11 @@
+!include ..\windisk.mk
+
+MINORCOMP= daclear
+
+TARGETNAME= daclear
+TARGETTYPE= PROGRAM
+TARGETPATH= obj
+
+UMTYPE= console
+
+SOURCES= clear.cxx
diff --git a/private/utils/windisk/controls/bmp.cxx b/private/utils/windisk/controls/bmp.cxx
new file mode 100644
index 000000000..b0bca8902
--- /dev/null
+++ b/private/utils/windisk/controls/bmp.cxx
@@ -0,0 +1,219 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: bmp.cxx
+//
+// Contents: Bitmap custom control for use on dialog box.
+//
+// History: 26-Jan-94 BruceFo Created (derived from Chicago Disks tool)
+//
+//--------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include "bmppriv.hxx"
+
+////////////////////////////////////////////////////////////////////////////
+
+#define BITMAP_CONTROL_WNDEXTRA 8
+
+#define GWL_BMPCTL_BITMAP 0
+#define GWL_BMPCTL_HDC 4
+
+////////////////////////////////////////////////////////////////////////////
+
+LRESULT CALLBACK
+BitmapControlWndProc(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+////////////////////////////////////////////////////////////////////////////
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: BitmapControlWndProc
+//
+// Synopsis: The bitmap custom control window procedure
+//
+// Arguments: standard WndProc
+//
+// Returns: standard WndProc
+//
+// History: 26-Jan-94 BruceFo Created (derived from Cairo System
+// Management forms bitmap control)
+//
+//--------------------------------------------------------------------------
+
+LRESULT CALLBACK
+BitmapControlWndProc(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ switch (msg)
+ {
+ case WM_CREATE:
+ {
+ HDC hdc = GetDC(hwnd);
+ HDC hdcMem = CreateCompatibleDC(hdc);
+ ReleaseDC(hwnd, hdc);
+ SetWindowLong(hwnd, GWL_BMPCTL_HDC, (LONG)hdcMem);
+
+ SetWindowLong(hwnd, GWL_BMPCTL_BITMAP, (LONG)NULL);
+ break;
+ }
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+
+ BeginPaint(hwnd,&ps);
+
+ if (!IsIconic(hwnd))
+ {
+ HBITMAP hbmp = (HBITMAP)GetWindowLong(hwnd, GWL_BMPCTL_BITMAP);
+
+ if (NULL != hbmp)
+ {
+ HDC hdcMem = (HDC)GetWindowLong(hwnd, GWL_BMPCTL_HDC);
+ HBITMAP hbmpOld = SelectBitmap(hdcMem, hbmp);
+
+ BITMAP bmp;
+ GetObject(hbmp, sizeof(bmp), &bmp);
+
+ BitBlt(
+ ps.hdc,
+ 0,
+ 0,
+ bmp.bmWidth,
+ bmp.bmHeight,
+ hdcMem,
+ 0,
+ 0,
+ SRCCOPY
+ );
+
+ SelectBitmap(hdcMem, hbmpOld);
+ }
+ }
+
+ EndPaint(hwnd,&ps);
+ break;
+ }
+
+ case WM_DESTROY:
+ {
+ HBITMAP hbmp = (HBITMAP)GetWindowLong(hwnd, GWL_BMPCTL_BITMAP);
+ if (NULL != hbmp)
+ {
+ DeleteBitmap(hbmp);
+ }
+
+ HDC hdcMem = (HDC)GetWindowLong(hwnd, GWL_BMPCTL_HDC);
+ ReleaseDC(hwnd, hdcMem);
+
+ break;
+ }
+
+ case BMPCTL_SETBITMAP:
+ {
+ // wParam = hBitmap
+
+ HBITMAP hbmp = (HBITMAP)GetWindowLong(hwnd, GWL_BMPCTL_BITMAP);
+
+ if (NULL != hbmp)
+ {
+ DeleteBitmap(hbmp);
+ }
+
+ SetWindowLong(hwnd, GWL_BMPCTL_BITMAP, (LONG)wParam);
+
+ InvalidateRect(hwnd, NULL, TRUE); // force a repaint
+ break;
+ }
+
+ default:
+ return DefWindowProc(hwnd,msg,wParam,lParam);
+ }
+
+ return 1;
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: UseBitmapControl
+//
+// Synopsis: Initializes the bitmap custom control. Registers its
+// window class.
+//
+// Arguments: [hInstance] -- instance handle
+//
+// Returns: 0 on success, else Win32 error
+//
+// History: 26-Jan-94 BruceFo Created (derived from Chicago Disks tool)
+//
+//--------------------------------------------------------------------------
+
+DWORD
+UseBitmapControl(
+ IN HINSTANCE hInstance
+ )
+{
+ WNDCLASS wc;
+
+ wc.style = 0;
+ wc.lpfnWndProc = BitmapControlWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = BITMAP_CONTROL_WNDEXTRA;
+ wc.hInstance = hInstance;
+ wc.hIcon = NULL;
+ wc.hCursor = NULL;
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = BITMAP_CONTROL_STRING;
+
+ if (0 == RegisterClass(&wc))
+ {
+ return GetLastError();
+ }
+ return 0L;
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: ReleaseBitmapControl
+//
+// Synopsis:
+//
+// Arguments: [hInstance] -- instance handle
+//
+// Returns: 0 on success, else Win32 error
+//
+// History: 7-Oct-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+DWORD
+ReleaseBitmapControl(
+ IN HINSTANCE hInstance
+ )
+{
+ if (!UnregisterClass(BITMAP_CONTROL_STRING, hInstance))
+ {
+ return GetLastError();
+ }
+ return 0L;
+}
diff --git a/private/utils/windisk/controls/bmppriv.hxx b/private/utils/windisk/controls/bmppriv.hxx
new file mode 100644
index 000000000..eb83461e1
--- /dev/null
+++ b/private/utils/windisk/controls/bmppriv.hxx
@@ -0,0 +1,20 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: bmp.hxx
+//
+// Contents: Declarations for the bitmap custom control
+//
+// History: 26-Jan-94 BruceFo Created (derived from Chicago Disks tool)
+//
+//--------------------------------------------------------------------------
+
+#ifndef __BMP_HXX__
+#define __BMP_HXX__
+
+DWORD UseBitmapControl(IN HINSTANCE hInstance);
+DWORD ReleaseBitmapControl(IN HINSTANCE hInstance);
+
+#endif // __BMP_HXX__
diff --git a/private/utils/windisk/controls/box.cxx b/private/utils/windisk/controls/box.cxx
new file mode 100644
index 000000000..a1244ef2c
--- /dev/null
+++ b/private/utils/windisk/controls/box.cxx
@@ -0,0 +1,186 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: box.cxx
+//
+// Contents: Color box custom control for use on dialog box.
+//
+// History: 27-Jan-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include "boxpriv.hxx"
+
+////////////////////////////////////////////////////////////////////////////
+
+#define COLORBOX_CONTROL_WNDEXTRA 4
+
+#define GWL_BOXCTL_COLOR 0
+
+#define ILLEGAL_COLOR ((COLORREF)-1)
+
+////////////////////////////////////////////////////////////////////////////
+
+LRESULT CALLBACK
+BoxControlWndProc(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+////////////////////////////////////////////////////////////////////////////
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: BoxControlWndProc
+//
+// Synopsis: The color box custom control window procedure
+//
+// Arguments: standard WndProc
+//
+// Returns: standard WndProc
+//
+// History: 27-Jan-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+LRESULT CALLBACK
+BoxControlWndProc(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ switch (msg)
+ {
+ case WM_CREATE:
+ {
+ SetWindowLong(hwnd, GWL_BOXCTL_COLOR, (LONG)ILLEGAL_COLOR);
+ break;
+ }
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ RECT rc;
+
+ BeginPaint(hwnd,&ps);
+
+ COLORREF color = (COLORREF)GetWindowLong(hwnd, GWL_BOXCTL_COLOR);
+
+ if (color != ILLEGAL_COLOR)
+ {
+ HBRUSH BlackBrush = GetStockBrush(BLACK_BRUSH);
+ HBRUSH ColorBrush = CreateSolidBrush(color);
+ GetClientRect(hwnd, &rc);
+ FrameRect(ps.hdc,&rc,BlackBrush);
+ InflateRect(&rc,-1,-1);
+ SetBrushOrgEx(ps.hdc,rc.left,rc.top,NULL);
+ UnrealizeObject(ColorBrush);
+ FillRect(ps.hdc, &rc, ColorBrush);
+ DeleteBrush(ColorBrush);
+ }
+
+ EndPaint(hwnd,&ps);
+ break;
+ }
+
+ case WM_DESTROY:
+ {
+ // don't need to destroy color in GWL_BOXCTL_COLOR
+
+ break;
+ }
+
+ case BOXCTL_SETCOLOR:
+ {
+ // wParam = COLORREF
+
+ SetWindowLong(hwnd, GWL_BOXCTL_COLOR, (LONG)wParam);
+ break;
+ }
+
+ default:
+ return DefWindowProc(hwnd,msg,wParam,lParam);
+ }
+
+ return 1;
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: UseColorBoxControl
+//
+// Synopsis: Initializes the color box custom control. Registers its
+// window class.
+//
+// Arguments: [hInstance] -- instance handle
+//
+// Returns: 0 on success, else Win32 error
+//
+// History: 27-Jan-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+DWORD
+UseColorBoxControl(
+ IN HINSTANCE hInstance
+ )
+{
+ WNDCLASS wc;
+
+ wc.style = 0;
+ wc.lpfnWndProc = BoxControlWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = COLORBOX_CONTROL_WNDEXTRA;
+ wc.hInstance = hInstance;
+ wc.hIcon = NULL;
+ wc.hCursor = NULL;
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = COLORBOX_CONTROL_STRING;
+
+ if (0 == RegisterClass(&wc))
+ {
+ return GetLastError();
+ }
+ return 0L;
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: ReleaseColorBoxControl
+//
+// Synopsis:
+//
+// Arguments: [hInstance] -- instance handle
+//
+// Returns: 0 on success, else Win32 error
+//
+// History: 7-Oct-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+DWORD
+ReleaseColorBoxControl(
+ IN HINSTANCE hInstance
+ )
+{
+ if (!UnregisterClass(COLORBOX_CONTROL_STRING, hInstance))
+ {
+ return GetLastError();
+ }
+ return 0L;
+}
diff --git a/private/utils/windisk/controls/boxpriv.hxx b/private/utils/windisk/controls/boxpriv.hxx
new file mode 100644
index 000000000..cd8c0924e
--- /dev/null
+++ b/private/utils/windisk/controls/boxpriv.hxx
@@ -0,0 +1,20 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: box.hxx
+//
+// Contents: Declarations for the color box custom control
+//
+// History: 27-Jan-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef __BOX_HXX__
+#define __BOX_HXX__
+
+DWORD UseColorBoxControl(IN HINSTANCE hInstance);
+DWORD ReleaseColorBoxControl(IN HINSTANCE hInstance);
+
+#endif // __BOX_HXX__
diff --git a/private/utils/windisk/controls/controls.cxx b/private/utils/windisk/controls/controls.cxx
new file mode 100644
index 000000000..60832f5f4
--- /dev/null
+++ b/private/utils/windisk/controls/controls.cxx
@@ -0,0 +1,45 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: controls.cxx
+//
+// Contents:
+//
+// History: 7-Oct-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include "bmppriv.hxx"
+#include "boxpriv.hxx"
+#include "linepriv.hxx"
+
+////////////////////////////////////////////////////////////////////////////
+
+BOOL
+UseWindiskControls(
+ IN HINSTANCE hInstance
+ )
+{
+ return (
+ 0 == UseBitmapControl(hInstance)
+ && 0 == UseColorBoxControl(hInstance)
+ && 0 == UseLineControl(hInstance)
+ );
+}
+
+BOOL
+ReleaseWindiskControls(
+ IN HINSTANCE hInstance
+ )
+{
+ return (
+ 0 == ReleaseBitmapControl(hInstance)
+ && 0 == ReleaseColorBoxControl(hInstance)
+ && 0 == ReleaseLineControl(hInstance)
+ );
+}
diff --git a/private/utils/windisk/controls/controls.hxx b/private/utils/windisk/controls/controls.hxx
new file mode 100644
index 000000000..5f0472016
--- /dev/null
+++ b/private/utils/windisk/controls/controls.hxx
@@ -0,0 +1,79 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: controls.hxx
+//
+// Contents: Public declarations for Disk Administrator custom controls
+//
+// History: 7-Oct-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef __CONTROLS_HXX__
+#define __CONTROLS_HXX__
+
+//
+// Initialize all the controls
+//
+
+BOOL
+UseWindiskControls(
+ IN HINSTANCE hInstance
+ );
+
+BOOL
+ReleaseWindiskControls(
+ IN HINSTANCE hInstance
+ );
+
+////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap control
+//
+////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////
+
+#ifndef RC_INVOKED
+
+#define BITMAP_CONTROL_STRING TEXT("WinDiskBitmapControl")
+#define BMPCTL_SETBITMAP WM_USER
+
+#endif // RC_INVOKED
+
+
+////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////
+//
+// Box control
+//
+////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////
+
+#ifndef RC_INVOKED
+
+#define COLORBOX_CONTROL_STRING TEXT("WinDiskColorBoxControl")
+#define BOXCTL_SETCOLOR WM_USER
+
+#endif // RC_INVOKED
+
+
+////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////
+//
+// Line control.
+//
+// This simply draws a line from its left to right side a single pixel high.
+//
+////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////
+
+#ifndef RC_INVOKED
+
+#define WC_LINECONTROLCLASS TEXT("SmLineControl")
+
+#endif // RC_INVOKED
+
+#endif // __CONTROLS_HXX__
diff --git a/private/utils/windisk/controls/headers.hxx b/private/utils/windisk/controls/headers.hxx
new file mode 100644
index 000000000..2ed466dab
--- /dev/null
+++ b/private/utils/windisk/controls/headers.hxx
@@ -0,0 +1,28 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: headers.hxx
+//
+// Contents:
+//
+// History: 7-Oct-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef UNICODE
+#error Disk Administrator MUST build with UNICODE defined!
+#endif // UNICODE
+
+////////////////////////////////////////////////////////////////////////////
+
+#include <windows.h>
+#include <windowsx.h>
+
+#include <stdlib.h>
+#include <math.h>
+#include <debug.h>
+#include <dacommon.h> // Common header file for Disk Administrator code
+
+#include "controls.hxx"
diff --git a/private/utils/windisk/controls/line.cxx b/private/utils/windisk/controls/line.cxx
new file mode 100644
index 000000000..f48f80599
--- /dev/null
+++ b/private/utils/windisk/controls/line.cxx
@@ -0,0 +1,159 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: line.cxx
+//
+// Contents: Line custom control for use on dialog box.
+//
+// History: 27-Jan-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include "linepriv.hxx"
+
+////////////////////////////////////////////////////////////////////////////
+
+#define LINE_CONTROL_WNDEXTRA 0
+
+////////////////////////////////////////////////////////////////////////////
+
+LRESULT CALLBACK
+LineControlWndProc(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+////////////////////////////////////////////////////////////////////////////
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: LineControlWndProc
+//
+// Synopsis: The line custom control window procedure
+//
+// Arguments: standard WndProc
+//
+// Returns: standard WndProc
+//
+// History: 27-Jan-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+LRESULT CALLBACK
+LineControlWndProc(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ switch (msg)
+ {
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ RECT rc;
+ HBRUSH ColorBrush;
+ HBRUSH BlackBrush;
+
+ BeginPaint(hwnd,&ps);
+
+#if (WINVER >= 0x0400)
+ ColorBrush = CreateSolidBrush(GetSysColor(COLOR_3DFACE));
+#else
+ ColorBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
+#endif
+ BlackBrush = GetStockBrush(BLACK_BRUSH);
+ GetClientRect(hwnd,&rc);
+ FillRect(ps.hdc, &rc, ColorBrush);
+ rc.bottom = rc.top + 1;
+ FillRect(ps.hdc, &rc, BlackBrush);
+ DeleteBrush(ColorBrush);
+
+ EndPaint(hwnd,&ps);
+ break;
+ }
+
+ default:
+ return DefWindowProc(hwnd,msg,wParam,lParam);
+ }
+
+ return 1;
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: UseLineControl
+//
+// Synopsis: Initializes the line custom control.
+//
+// Arguments: [hInstance] -- instance handle
+//
+// Returns: Win32 error, 0 on success
+//
+// History: 27-Jan-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+DWORD
+UseLineControl(
+ IN HINSTANCE hInstance
+ )
+{
+ WNDCLASS wc;
+
+ wc.style = CS_GLOBALCLASS;
+ wc.lpfnWndProc = LineControlWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = LINE_CONTROL_WNDEXTRA;
+ wc.hInstance = hInstance;
+ wc.hIcon = NULL;
+ wc.hCursor = NULL;
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = WC_LINECONTROLCLASS;
+
+ if (0 == RegisterClass(&wc))
+ {
+ return GetLastError();
+ }
+ return 0L;
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: ReleaseLineControl
+//
+// Synopsis: Releases the line custom control.
+//
+// Arguments: [hInstance] -- instance handle
+//
+// Returns: Win32 error, 0 on success
+//
+// History: 27-Jan-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+DWORD
+ReleaseLineControl(
+ IN HINSTANCE hInstance
+ )
+{
+ if (!UnregisterClass(WC_LINECONTROLCLASS, hInstance))
+ {
+ return GetLastError();
+ }
+ return 0L;
+}
diff --git a/private/utils/windisk/controls/linepriv.hxx b/private/utils/windisk/controls/linepriv.hxx
new file mode 100644
index 000000000..338b066d4
--- /dev/null
+++ b/private/utils/windisk/controls/linepriv.hxx
@@ -0,0 +1,20 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: linepriv.hxx
+//
+// Contents: Line control private header file.
+//
+// History: 21-Jul-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef __LINEPRIV_HXX__
+#define __LINEPRIV_HXX__
+
+DWORD UseLineControl(IN HINSTANCE hInstance);
+DWORD ReleaseLineControl(IN HINSTANCE hInstance);
+
+#endif // __LINEPRIV_HXX__
diff --git a/private/utils/windisk/controls/makefile b/private/utils/windisk/controls/makefile
new file mode 100644
index 000000000..14f79b701
--- /dev/null
+++ b/private/utils/windisk/controls/makefile
@@ -0,0 +1 @@
+!include $(NTMAKEENV)\makefile.def
diff --git a/private/utils/windisk/controls/sources b/private/utils/windisk/controls/sources
new file mode 100644
index 000000000..eade903ae
--- /dev/null
+++ b/private/utils/windisk/controls/sources
@@ -0,0 +1,22 @@
+!include ..\windisk.mk
+
+MINORCOMP= controls
+
+TARGETNAME= controls
+TARGETPATH= obj
+TARGETTYPE= LIBRARY
+
+UMTYPE= windows
+
+INCLUDES=\
+ ..\inc; \
+ $(INCLUDES)
+
+SOURCES=\
+ controls.cxx \
+ bmp.cxx \
+ box.cxx \
+ line.cxx
+
+PRECOMPILED_INCLUDE=headers.hxx
+PRECOMPILED_CXX=1
diff --git a/private/utils/windisk/debug/assert.cxx b/private/utils/windisk/debug/assert.cxx
new file mode 100644
index 000000000..9ab24ed36
--- /dev/null
+++ b/private/utils/windisk/debug/assert.cxx
@@ -0,0 +1,340 @@
+//+---------------------------------------------------------------------------
+// Copyright (C) 1991-1994, Microsoft Corporation.
+//
+// File: assert.cxx
+//
+// Contents: Debugging output routines
+//
+// History: 23-Jul-91 KyleP Created.
+// 09-Oct-91 KevinRo Major changes and comments added
+// 18-Oct-91 vich moved debug print routines out
+// 10-Jun-92 BryanT Switched to w4crt.h instead of wchar.h
+// 30-Sep-93 KyleP DEVL obsolete
+// 7-Oct-94 BruceFo Ripped out all kernel, non-FLAT,
+// DLL-specific, non-Win32 functionality.
+// Now it's basically "print to the
+// debugger" code.
+//
+//----------------------------------------------------------------------------
+
+#if DBG == 1
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#include "debug.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+unsigned long Win4InfoLevel = DEF_INFOLEVEL;
+unsigned long Win4InfoMask = 0xffffffff;
+unsigned long Win4AssertLevel = ASSRT_MESSAGE | ASSRT_BREAK | ASSRT_POPUP;
+
+//////////////////////////////////////////////////////////////////////////////
+
+static int _cdecl w4dprintf(const char *format, ...);
+static int _cdecl w4vdprintf(const char *format, va_list arglist);
+
+//////////////////////////////////////////////////////////////////////////////
+
+static CRITICAL_SECTION s_csMessageBuf;
+static char g_szMessageBuf[500]; // this is the message buffer
+
+static int _cdecl w4dprintf(const char *format, ...)
+{
+ int ret;
+
+ va_list va;
+ va_start(va, format);
+ ret = w4vdprintf(format, va);
+ va_end(va);
+
+ return ret;
+}
+
+
+static int _cdecl w4vdprintf(const char *format, va_list arglist)
+{
+ int ret;
+
+ EnterCriticalSection(&s_csMessageBuf);
+ ret = vsprintf(g_szMessageBuf, format, arglist);
+ OutputDebugStringA(g_szMessageBuf);
+ LeaveCriticalSection(&s_csMessageBuf);
+ return ret;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+//+---------------------------------------------------------------------------
+//
+// Function: _asdprintf
+//
+// Synopsis: Calls vdprintf to output a formatted message.
+//
+// History: 18-Oct-91 vich Created
+//
+//----------------------------------------------------------------------------
+inline void _CRTAPI1
+_asdprintf(
+ char const *pszfmt, ...)
+{
+ va_list va;
+ va_start(va, pszfmt);
+
+ vdprintf(DEB_FORCE, "Assert", pszfmt, va);
+
+ va_end(va);
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: Win4AssertEx, private
+//
+// Synopsis: Display assertion information
+//
+// Effects: Called when an assertion is hit.
+//
+//----------------------------------------------------------------------------
+
+EXPORTIMP void APINOT
+Win4AssertEx(
+ char const * szFile,
+ int iLine,
+ char const * szMessage)
+{
+ if (Win4AssertLevel & ASSRT_MESSAGE)
+ {
+ DWORD tid = GetCurrentThreadId();
+
+ _asdprintf("%s File: %s Line: %u, thread id %d\n",
+ szMessage, szFile, iLine, tid);
+ }
+
+ if (Win4AssertLevel & ASSRT_POPUP)
+ {
+ int id = PopUpError(szMessage,iLine,szFile);
+
+ if (id == IDCANCEL)
+ {
+ DebugBreak();
+ }
+ }
+ else if (Win4AssertLevel & ASSRT_BREAK)
+ {
+ DebugBreak();
+ }
+}
+
+
+//+------------------------------------------------------------
+// Function: SetWin4InfoLevel(unsigned long ulNewLevel)
+//
+// Synopsis: Sets the global info level for debugging output
+// Returns: Old info level
+//
+//-------------------------------------------------------------
+
+EXPORTIMP unsigned long APINOT
+SetWin4InfoLevel(
+ unsigned long ulNewLevel)
+{
+ unsigned long ul;
+
+ ul = Win4InfoLevel;
+ Win4InfoLevel = ulNewLevel;
+ return(ul);
+}
+
+
+//+------------------------------------------------------------
+// Function: SetWin4InfoMask(unsigned long ulNewMask)
+//
+// Synopsis: Sets the global info mask for debugging output
+// Returns: Old info mask
+//
+//-------------------------------------------------------------
+
+EXPORTIMP unsigned long APINOT
+SetWin4InfoMask(
+ unsigned long ulNewMask)
+{
+ unsigned long ul;
+
+ ul = Win4InfoMask;
+ Win4InfoMask = ulNewMask;
+ return(ul);
+}
+
+
+//+------------------------------------------------------------
+// Function: SetWin4AssertLevel(unsigned long ulNewLevel)
+//
+// Synopsis: Sets the global assert level for debugging output
+// Returns: Old assert level
+//
+//-------------------------------------------------------------
+
+EXPORTIMP unsigned long APINOT
+SetWin4AssertLevel(
+ unsigned long ulNewLevel)
+{
+ unsigned long ul;
+
+ ul = Win4AssertLevel;
+ Win4AssertLevel = ulNewLevel;
+ return(ul);
+}
+
+
+//+------------------------------------------------------------
+// Function: PopUpError
+//
+// Synopsis: Displays a dialog box using provided text,
+// and presents the user with the option to
+// continue or cancel.
+//
+// Arguments:
+// szMsg -- The string to display in main body of dialog
+// iLine -- Line number of file in error
+// szFile -- Filename of file in error
+//
+// Returns:
+// IDCANCEL -- User selected the CANCEL button
+// IDOK -- User selected the OK button
+//-------------------------------------------------------------
+
+EXPORTIMP int APINOT
+PopUpError(
+ char const *szMsg,
+ int iLine,
+ char const *szFile)
+{
+ int id;
+ static char szAssertCaption[128];
+ static char szModuleName[128];
+
+ DWORD tid = GetCurrentThreadId();
+ DWORD pid = GetCurrentProcessId();
+ char * pszModuleName;
+
+ if (GetModuleFileNameA(NULL, szModuleName, 128))
+ {
+ pszModuleName = strrchr(szModuleName, '\\');
+ if (!pszModuleName)
+ {
+ pszModuleName = szModuleName;
+ }
+ else
+ {
+ pszModuleName++;
+ }
+ }
+ else
+ {
+ pszModuleName = "Unknown";
+ }
+
+ sprintf(szAssertCaption,"Process: %s File: %s line %u, thread id %d.%d",
+ pszModuleName, szFile, iLine, pid, tid);
+
+ id = MessageBoxA(NULL,
+ szMsg,
+ szAssertCaption,
+ MB_SETFOREGROUND
+ | MB_DEFAULT_DESKTOP_ONLY
+ | MB_TASKMODAL
+ | MB_ICONEXCLAMATION
+ | MB_OKCANCEL);
+
+ //
+ // If id == 0, then an error occurred. There are two possibilities
+ // that can cause the error: Access Denied, which means that this
+ // process does not have access to the default desktop, and everything
+ // else (usually out of memory).
+ //
+
+ if (0 == id)
+ {
+ if (GetLastError() == ERROR_ACCESS_DENIED)
+ {
+ //
+ // Retry this one with the SERVICE_NOTIFICATION flag on. That
+ // should get us to the right desktop.
+ //
+ id = MessageBoxA(NULL,
+ szMsg,
+ szAssertCaption,
+ MB_SETFOREGROUND
+ | MB_SERVICE_NOTIFICATION
+ | MB_TASKMODAL
+ | MB_ICONEXCLAMATION
+ | MB_OKCANCEL);
+ }
+ }
+
+ return id;
+}
+
+
+//+------------------------------------------------------------
+// Function: vdprintf
+//
+// Synopsis: Prints debug output using a pointer to the
+// variable information. Used primarily by the
+// xxDebugOut macros
+//
+// Arguements:
+// ulCompMask -- Component level mask used to determine
+// output ability
+// pszComp -- String const of component prefix.
+// ppszfmt -- Pointer to output format and data
+//
+//-------------------------------------------------------------
+
+static CRITICAL_SECTION s_csDebugPrint;
+
+EXPORTIMP void APINOT
+vdprintf(
+ unsigned long ulCompMask,
+ char const *pszComp,
+ char const *ppszfmt,
+ va_list pargs)
+{
+ if ((ulCompMask & DEB_FORCE) == DEB_FORCE ||
+ ((ulCompMask | Win4InfoLevel) & Win4InfoMask))
+ {
+ EnterCriticalSection(&s_csDebugPrint);
+
+ DWORD tid = GetCurrentThreadId();
+ DWORD pid = GetCurrentProcessId();
+ if ((Win4InfoLevel & (DEB_DBGOUT | DEB_STDOUT)) != DEB_STDOUT)
+ {
+ if (! (ulCompMask & DEB_NOCOMPNAME))
+ {
+ w4dprintf("%d.%03d> %s: ", pid, tid, pszComp);
+ }
+ w4vdprintf(ppszfmt, pargs);
+ }
+
+ if (Win4InfoLevel & DEB_STDOUT)
+ {
+ if (! (ulCompMask & DEB_NOCOMPNAME))
+ {
+ printf("%d.%03d> %s: ", pid, tid, pszComp);
+ }
+ vprintf(ppszfmt, pargs);
+ }
+
+ LeaveCriticalSection(&s_csDebugPrint);
+ }
+}
+
+void InitializeDebugging(void)
+{
+ InitializeCriticalSection(&s_csMessageBuf);
+ InitializeCriticalSection(&s_csDebugPrint);
+}
+
+#endif // DBG == 1
diff --git a/private/utils/windisk/debug/debug.h b/private/utils/windisk/debug/debug.h
new file mode 100644
index 000000000..66e823a03
--- /dev/null
+++ b/private/utils/windisk/debug/debug.h
@@ -0,0 +1,284 @@
+//+---------------------------------------------------------------------------
+// Copyright (C) 1991, Microsoft Corporation.
+//
+// File: debug.h
+//
+// Contents: Debugging macros. Stolen from old Cairo debnot.h with the
+// following history...
+//
+// History: 23-Jul-91 KyleP Created.
+// 15-Oct-91 KevinRo Major changes and comments added
+// 18-Oct-91 vich Consolidated win4p.hxx
+// 22-Oct-91 SatoNa Added SHLSTRICT
+// 29-Apr-92 BartoszM Moved from win4p.h
+// 3-Jun-92 BruceFo Added SMUISTRICT
+// 17-Dec-92 AlexT Moved UN..._PARM out of DEVL==1
+// 30-Sep-93 KyleP DEVL obsolete
+// 18-Jun-94 AlexT Make Assert a better statement
+// 7-Oct-94 BruceFo Stole and ripped out everything except
+// debug prints and asserts.
+//
+//----------------------------------------------------------------------------
+
+#ifndef __DEBUG_H__
+#define __DEBUG_H__
+
+#include <stdarg.h>
+
+//----------------------------------------------------------------------------
+// Parameter Macros
+//
+// To avoid compiler warnings for unimplemented functions, use
+// UNIMPLEMENTED_PARM(x) for each unreferenced parameter. This will
+// later be defined to nul to reveal functions that we forgot to implement.
+//
+// For functions which will never use a parameter, use
+// UNREFERENCED_PARM(x).
+//
+
+#define UNIMPLEMENTED_PARM(x) (x)
+
+#define UNREFERENCED_PARM(x) (x)
+
+
+#if DBG == 1
+
+//
+// DEBUG -- DEBUG -- DEBUG -- DEBUG -- DEBUG
+//
+
+//
+// Debug print functions.
+//
+
+#ifdef __cplusplus
+extern "C" {
+# define EXTRNC "C"
+#else
+# define EXTRNC
+#endif
+
+#ifndef EXPORTDEF
+ #define EXPORTDEF
+#endif
+#ifndef EXPORTIMP
+ #define EXPORTIMP
+#endif
+#ifndef EXPORTED
+ #define EXPORTED _cdecl
+#endif
+#ifndef APINOT
+#ifdef _X86_
+ #define APINOT _stdcall
+#else
+ #define APINOT _cdecl
+#endif
+#endif
+
+
+// vdprintf should only be called from xxDebugOut()
+
+ EXPORTDEF void APINOT
+ vdprintf(
+ unsigned long ulCompMask,
+ char const *pszComp,
+ char const *ppszfmt,
+ va_list ArgList);
+
+ EXPORTDEF void APINOT
+ Win4AssertEx(
+ char const *pszFile,
+ int iLine,
+ char const *pszMsg);
+
+ EXPORTDEF int APINOT
+ PopUpError(
+ char const *pszMsg,
+ int iLine,
+ char const *pszFile);
+
+ EXPORTDEF unsigned long APINOT
+ SetWin4InfoLevel(
+ unsigned long ulNewLevel);
+
+ EXPORTDEF unsigned long APINOT
+ SetWin4InfoMask(
+ unsigned long ulNewMask);
+
+ EXPORTDEF unsigned long APINOT
+ SetWin4AssertLevel(
+ unsigned long ulNewLevel);
+
+ EXPORTDEF void APINOT
+ InitializeDebugging(
+ void);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+# define Win4Assert(x) \
+ (void)((x) || (Win4AssertEx(__FILE__, __LINE__, #x),0))
+
+# define Win4Verify(x) Win4Assert(x)
+
+
+//
+// Debug print macros
+//
+
+# define DEB_ERROR 0x00000001 // exported error paths
+# define DEB_WARN 0x00000002 // exported warnings
+# define DEB_TRACE 0x00000004 // exported trace messages
+
+# define DEB_DBGOUT 0x00000010 // Output to debugger
+# define DEB_STDOUT 0x00000020 // Output to stdout
+
+# define DEB_IERROR 0x00000100 // internal error paths
+# define DEB_IWARN 0x00000200 // internal warnings
+# define DEB_ITRACE 0x00000400 // internal trace messages
+
+# define DEB_USER1 0x00010000 // User defined
+# define DEB_USER2 0x00020000 // User defined
+# define DEB_USER3 0x00040000 // User defined
+# define DEB_USER4 0x00080000 // User defined
+# define DEB_USER5 0x00100000 // User defined
+# define DEB_USER6 0x00200000 // User defined
+# define DEB_USER7 0x00400000 // User defined
+# define DEB_USER8 0x00800000 // User defined
+# define DEB_USER9 0x01000000 // User defined
+# define DEB_USER10 0x02000000 // User defined
+# define DEB_USER11 0x04000000 // User defined
+# define DEB_USER12 0x08000000 // User defined
+# define DEB_USER13 0x10000000 // User defined
+# define DEB_USER14 0x20000000 // User defined
+# define DEB_USER15 0x40000000 // User defined
+
+# define DEB_NOCOMPNAME 0x80000000 // suppress component name
+
+# define DEB_FORCE 0x7fffffff // force message
+
+# define ASSRT_MESSAGE 0x00000001 // Output a message
+# define ASSRT_BREAK 0x00000002 // Int 3 on assertion
+# define ASSRT_POPUP 0x00000004 // And popup message
+
+
+//+----------------------------------------------------------------------
+//
+// DECLARE_DEBUG(comp)
+// DECLARE_INFOLEVEL(comp)
+//
+// This macro defines xxDebugOut where xx is the component prefix
+// to be defined. This declares a static variable 'xxInfoLevel', which
+// can be used to control the type of xxDebugOut messages printed to
+// the terminal. For example, xxInfoLevel may be set at the debug terminal.
+// This will enable the user to turn debugging messages on or off, based
+// on the type desired. The predefined types are defined below. Component
+// specific values should use the upper 24 bits
+//
+// To Use:
+//
+// 1) In your components main include file, include the line
+// DECLARE_DEBUG(comp)
+// where comp is your component prefix
+//
+// 2) In one of your components source files, include the line
+// DECLARE_INFOLEVEL(comp)
+// where comp is your component prefix. This will define the
+// global variable that will control output.
+//
+// It is suggested that any component define bits be combined with
+// existing bits. For example, if you had a specific error path that you
+// wanted, you might define DEB_<comp>_ERRORxxx as being
+//
+// (0x100 | DEB_ERROR)
+//
+// This way, we can turn on DEB_ERROR and get the error, or just 0x100
+// and get only your error.
+//
+//-----------------------------------------------------------------------
+
+# ifndef DEF_INFOLEVEL
+# define DEF_INFOLEVEL (DEB_ERROR | DEB_WARN)
+# endif
+
+
+# define DECLARE_INFOLEVEL(comp) \
+ extern EXTRNC unsigned long comp##InfoLevel = DEF_INFOLEVEL;\
+ extern EXTRNC char* comp##InfoLevelString = #comp;
+
+
+# ifdef __cplusplus
+
+# define DECLARE_DEBUG(comp) \
+ extern EXTRNC unsigned long comp##InfoLevel; \
+ extern EXTRNC char *comp##InfoLevelString; \
+ _inline void \
+ comp##InlineDebugOut(unsigned long fDebugMask, char const *pszfmt, ...) \
+ { \
+ if (comp##InfoLevel & fDebugMask) \
+ { \
+ va_list va; \
+ va_start (va, pszfmt); \
+ vdprintf(fDebugMask, comp##InfoLevelString, pszfmt, va);\
+ va_end(va); \
+ } \
+ } \
+ \
+ class comp##CDbgTrace\
+ {\
+ private:\
+ unsigned long _ulFlags;\
+ char const * const _pszName;\
+ public:\
+ comp##CDbgTrace(unsigned long ulFlags, char const * const pszName);\
+ ~comp##CDbgTrace();\
+ };\
+ \
+ inline comp##CDbgTrace::comp##CDbgTrace(\
+ unsigned long ulFlags,\
+ char const * const pszName)\
+ : _ulFlags(ulFlags), _pszName(pszName)\
+ {\
+ comp##InlineDebugOut(_ulFlags, "Entering %s\n", _pszName);\
+ }\
+ \
+ inline comp##CDbgTrace::~comp##CDbgTrace()\
+ {\
+ comp##InlineDebugOut(_ulFlags, "Exiting %s\n", _pszName);\
+ }
+
+# else // ! __cplusplus
+
+# define DECLARE_DEBUG(comp) \
+ extern EXTRNC unsigned long comp##InfoLevel; \
+ extern EXTRNC char *comp##InfoLevelString; \
+ _inline void \
+ comp##InlineDebugOut(unsigned long fDebugMask, char const *pszfmt, ...) \
+ { \
+ if (comp##InfoLevel & fDebugMask) \
+ { \
+ va_list va; \
+ va_start (va, pszfmt); \
+ vdprintf(fDebugMask, comp##InfoLevelString, pszfmt, va);\
+ va_end(va); \
+ } \
+ }
+
+# endif // ! __cplusplus
+
+#else // DBG == 0
+
+//
+// NO DEBUG -- NO DEBUG -- NO DEBUG -- NO DEBUG -- NO DEBUG
+//
+
+# define Win4Assert(x) NULL
+# define Win4Verify(x) (x)
+
+# define DECLARE_DEBUG(comp)
+# define DECLARE_INFOLEVEL(comp)
+
+#endif // DBG == 0
+
+#endif // __DEBUG_H__
diff --git a/private/utils/windisk/debug/makefile b/private/utils/windisk/debug/makefile
new file mode 100644
index 000000000..60482ff11
--- /dev/null
+++ b/private/utils/windisk/debug/makefile
@@ -0,0 +1,9 @@
+############################################################################
+#
+# Microsoft Windows
+# Copyright (C) Microsoft Corporation, 1992 - 1993.
+# All rights reserved.
+#
+############################################################################
+
+!include $(NTMAKEENV)\makefile.def
diff --git a/private/utils/windisk/debug/sources b/private/utils/windisk/debug/sources
new file mode 100644
index 000000000..030cf571c
--- /dev/null
+++ b/private/utils/windisk/debug/sources
@@ -0,0 +1,12 @@
+MAJORCOMP= cmn
+MINORCOMP= misc
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+UMTYPE= windows
+
+TARGETNAME= debug
+TARGETPATH= obj
+TARGETTYPE= LIBRARY
+
+SOURCES= assert.cxx
diff --git a/private/utils/windisk/dirs b/private/utils/windisk/dirs
new file mode 100644
index 000000000..b262a2701
--- /dev/null
+++ b/private/utils/windisk/dirs
@@ -0,0 +1,33 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+
+Author:
+
+ Isaac Heizer (IsaacHe) 28-Dec-1993
+
+!ENDIF
+
+#
+# This is a list of all subdirectories that build required components.
+# The build follows the order in which the subdirectories are specified.
+#
+
+DIRS= debug util controls src
+
+#
+# This is a list of all subdirectories that build optional components.
+# The build follows the order in which the subdirectories are specified.
+#
+
+OPTIONAL_DIRS= hard clear diskinfo
diff --git a/private/utils/windisk/diskinfo/diskinfo.cxx b/private/utils/windisk/diskinfo/diskinfo.cxx
new file mode 100644
index 000000000..236f77389
--- /dev/null
+++ b/private/utils/windisk/diskinfo/diskinfo.cxx
@@ -0,0 +1,273 @@
+extern "C"
+{
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <ntddnfs.h>
+}
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <ntdddfs.h>
+
+#define MAXBUF 200
+
+#define wstrEqual(a,b) (0 == wcscmp((a),(b)))
+
+char* program;
+
+void
+fatal(char* pszMsg)
+{
+ fprintf(stderr,"Fatal error: %s\n",pszMsg);
+ exit(1);
+}
+
+void
+usage()
+{
+ fprintf(stderr,"Usage: %s\n",program);
+ exit(1);
+}
+
+BOOL GetDeviceObject(
+ WCHAR wcDrive, // drive letter to get info about
+ LPWSTR lpTargetBuffer, // where to put the NT device path
+ DWORD nTargetBuffer) // length of device path buffer in characters
+{
+ NTSTATUS Status;
+
+ HANDLE hSymbolicLink;
+ WCHAR wszLinkName[_MAX_DRIVE+1]; // the +1 is for a backslash
+ UNICODE_STRING ustrLinkName;
+ UNICODE_STRING ustrLinkTarget;
+ OBJECT_ATTRIBUTES LinkAttributes;
+
+ wszLinkName[0] = wcDrive;
+ wszLinkName[1] = L':';
+ wszLinkName[2] = L'\\';
+ wszLinkName[3] = L'\0'; // wszLinkName = L"X:\"
+ _wcsupr(wszLinkName);
+
+ //
+ // Construct the link name by calling RtlDosPathNameToNtPathName, and
+ // strip of the trailing backslash. At the end of this, ustrLinkName
+ // should be of the form \DosDevices\X:
+ //
+
+ RtlDosPathNameToNtPathName_U(wszLinkName, &ustrLinkName, NULL, NULL);
+ ustrLinkName.Length -= sizeof(WCHAR);
+
+ InitializeObjectAttributes(
+ &LinkAttributes,
+ &ustrLinkName,
+ OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
+ NULL,
+ NULL);
+
+ Status = NtOpenSymbolicLinkObject(
+ &hSymbolicLink,
+ GENERIC_READ,
+ &LinkAttributes
+ );
+ if (!NT_SUCCESS(Status))
+ {
+ // No Link
+ return(FALSE);
+ }
+
+
+ //
+ // Find out if the device specified is DFS DeviceObject
+ //
+
+ ustrLinkTarget.Length = 0;
+ ustrLinkTarget.MaximumLength = (USHORT)nTargetBuffer * sizeof(WCHAR);
+ ustrLinkTarget.Buffer = lpTargetBuffer;
+
+ Status = NtQuerySymbolicLinkObject(
+ hSymbolicLink,
+ &ustrLinkTarget, // Name of Link's Target obj.
+ NULL
+ );
+ NtClose(hSymbolicLink);
+
+ if (NT_SUCCESS(Status))
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+void _cdecl
+main(int argc, char* argv[])
+{
+ program = argv[0];
+
+ printf("Disk information:\n");
+
+ WCHAR wszBuf[MAXBUF];
+ DWORD cchBuf = MAXBUF;
+ DWORD r;
+ WCHAR* p;
+ UINT dt;
+
+ BOOL f;
+ DWORD SectorsPerCluster;
+ DWORD BytesPerSector;
+ DWORD FreeClusters;
+ DWORD Clusters;
+
+ WCHAR wszPath[MAXBUF];
+
+ r = GetLogicalDriveStrings(cchBuf, wszBuf);
+ if (0 == r || r > cchBuf)
+ {
+ fatal("GetLogicalDriveStrings() failed.");
+ }
+
+ p = wszBuf;
+ while (*p)
+ {
+ printf("%ws: ",p);
+
+ dt = GetDriveType(p);
+ switch (dt)
+ {
+ case 0:
+ printf("undetermined type");
+ break;
+ case 1:
+ printf("no root directory!");
+ break;
+ case DRIVE_REMOVABLE:
+ printf("removable");
+ break;
+ case DRIVE_FIXED:
+ printf("fixed");
+ break;
+ case DRIVE_REMOTE:
+ printf("remote");
+ break;
+ case DRIVE_CDROM:
+ printf("cd-rom");
+ break;
+ case DRIVE_RAMDISK:
+ printf("RAM disk");
+ break;
+ default:
+ printf("HUH?");
+ break;
+ }
+ printf(", ");
+
+ if (dt == DRIVE_REMOVABLE)
+ {
+ f = FALSE;
+ }
+ else
+ {
+ f = GetDiskFreeSpace(
+ p,
+ &SectorsPerCluster,
+ &BytesPerSector,
+ &FreeClusters,
+ &Clusters);
+ }
+
+ if (f)
+ {
+ DWORD BytesPerCluster = SectorsPerCluster * BytesPerSector;
+ DWORD OneMB = 1024*1024;
+
+ printf("s/c=%d, b/s=%d, free=%d(%d MB), total=%d(%d MB)",
+ SectorsPerCluster,
+ BytesPerSector,
+ FreeClusters,
+ (FreeClusters * BytesPerCluster) / OneMB,
+ Clusters,
+ (Clusters * BytesPerCluster)/OneMB);
+ }
+
+ printf("\n");
+ p = p + wcslen(p) + 1;
+ }
+
+ printf("\n");
+
+ WCHAR wszVolName[MAXBUF];
+ DWORD volSerialNumber;
+ DWORD volMaxCompLen;
+ DWORD volFlags;
+ WCHAR wszVolFSName[MAXBUF];
+
+ p = wszBuf;
+ while (*p)
+ {
+ printf("%ws, ",p);
+
+ if (wstrEqual(p,L"A:\\") ||
+ wstrEqual(p,L"B:\\"))
+ {
+ f = FALSE;
+ }
+ else
+ {
+ f = GetVolumeInformation(
+ p,
+ wszVolName,
+ MAXBUF,
+ &volSerialNumber,
+ &volMaxCompLen,
+ &volFlags,
+ wszVolFSName,
+ MAXBUF);
+ }
+
+ if (f)
+ {
+ printf("%ws, serial # 0x%x, max comp len %d, ",
+ wszVolName,
+ volSerialNumber,
+ volMaxCompLen);
+
+ if (volFlags & FS_CASE_IS_PRESERVED)
+ {
+ printf("case preserved, ");
+ }
+
+ if (volFlags & FS_CASE_SENSITIVE)
+ {
+ printf("case sensitive, ");
+ }
+
+ if (volFlags & FS_UNICODE_STORED_ON_DISK)
+ {
+ printf("UNICODE, ");
+ }
+
+ printf("%ws, ", wszVolFSName);
+ }
+
+ f = GetDeviceObject(*p, wszPath, sizeof(wszPath)/sizeof(WCHAR));
+ if (f)
+ {
+ printf("%ws",wszPath);
+ }
+ else
+ {
+ printf("Error getting NT path");
+ }
+
+ printf("\n");
+
+ p = p + wcslen(p) + 1;
+ }
+
+ printf("\n");
+}
diff --git a/private/utils/windisk/diskinfo/makefile b/private/utils/windisk/diskinfo/makefile
new file mode 100644
index 000000000..14f79b701
--- /dev/null
+++ b/private/utils/windisk/diskinfo/makefile
@@ -0,0 +1 @@
+!include $(NTMAKEENV)\makefile.def
diff --git a/private/utils/windisk/diskinfo/sources b/private/utils/windisk/diskinfo/sources
new file mode 100644
index 000000000..e1de308ce
--- /dev/null
+++ b/private/utils/windisk/diskinfo/sources
@@ -0,0 +1,14 @@
+!include ..\windisk.mk
+
+MINORCOMP= diskinfo
+
+TARGETNAME= diskinfo
+TARGETTYPE= PROGRAM
+TARGETPATH= obj
+
+UMTYPE= console
+
+SOURCES= diskinfo.cxx
+
+TARGETLIBS=\
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
diff --git a/private/utils/windisk/doc/adskman.doc b/private/utils/windisk/doc/adskman.doc
new file mode 100644
index 000000000..acd6397bf
--- /dev/null
+++ b/private/utils/windisk/doc/adskman.doc
Binary files differ
diff --git a/private/utils/windisk/doc/adskman2.doc b/private/utils/windisk/doc/adskman2.doc
new file mode 100644
index 000000000..3a6e1a44d
--- /dev/null
+++ b/private/utils/windisk/doc/adskman2.doc
Binary files differ
diff --git a/private/utils/windisk/doc/demo.txt b/private/utils/windisk/doc/demo.txt
new file mode 100644
index 000000000..d3aed16e8
--- /dev/null
+++ b/private/utils/windisk/doc/demo.txt
@@ -0,0 +1,112 @@
+This note describes the functionality of format and chkdsk in the
+Disk Administrator.
+=================================================================
+
+
+
+Format
+------
+
+Select a volume and choose "Change Format" from the context menu. You
+can specify the new format as any of FAT, HPFS, NTFS, or OFS, and choose
+a label. You can specify whether or not to "quick format" the volume.
+
+If you've selected a fault-tolerant volume (stripe with parity or
+mirror), then "quick format" is disabled.
+
+When formatting, a "thermometer" displays the percentage of formatting
+completed. A "Stop" button allows you to cancel the formatting.
+
+If "Stop" is chosen, a confirmation dialog appears. A message informs
+the user that stopping formatting early is inadvisable. The user can
+choose "Stop" to confirm the original "stop" desire, "continue"
+(the default) to continue formatting where formatting left off, or
+help.
+
+Cancelling format is disabled when quick formatting.
+
+After formatting completes, a summary is printed detailing the amount of
+disk space is on the volume, and the available disk space (with
+thousands separators!).
+
+
+
+Chkdsk
+------
+
+Select a volume and choose "Check for Errors..." from the context menu. You
+can choose one of three levels of operation: (1) read-only, or don't
+fix; (2) fix (i.e., chkdsk /F); or (3) scan for bad sectors (i.e.,
+chkdsk /R).
+
+If the user hits "OK" and the current level of operation choice is
+"don't fix", then a confirmation dialog is displayed, warning the user
+that no error repair actions will be taken, and the reported actions describe
+what would be done in a "fix" case.
+
+When checking a volume, a "thermometer" displays the percentage of checking
+that has been completed in a particular phase. Note that this percentage
+is not the percentage of all checking completed, which is usually
+difficult or impossible information to determine before checking
+begins. Above the thermometer appears a title stating what is currently
+being checked. The thermometer is implemented to not update more than
+10 times a second (unless the value is 0% or 100%). This is done to avoid
+having the UI thread fall very far behind the worker thread which may
+generate many more messages than that.
+
+Note that % done information is currently only implemented for NTFS and
+FAT, not for OFS. (Implementation note: Bob Duke, who originally wrote
+chkdsk for OFS, strongly resisted adding % done information due to the
+incredible complexity of OFS and the lack of an easy means to predetermine
+the total amount of work.)
+
+For the "Do not fix errors" case, a "Stop" button allows you to cancel
+the formatting. If "Stop" is chosen, a confirmation dialog appears. A
+message informs the user that stopping checking early is inadvisable. The
+user can choose "Stop" to confirm the original "stop" desire, "continue"
+(the default) to continue checking where checking left off, or help.
+
+For the other cases, there is no "stop" button; the volume check engines
+don't support stopping in the "fix" cases. (Note that for chkdsk.exe,
+Ctrl-C --- the "stop" mechanism for the command line --- is disabled in
+the fix cases.)
+
+After a successful, complete volume check, a "results" dialog appears.
+Within this dialog is an edit control with any interesting information
+generated by the volume check. For successful checks, this is simply a
+summary of total disk space, the space in user files, the space used by
+the system, etc. Buttons exist to allow this information to be printed
+or logged to a file. The title to this dialog is different in the "don't
+fix" and "fix" cases. In particular, in the "don't fix" case the message
+makes clear that any error repair actions only describe what *would be*
+done, not what *was* done.
+
+This dialog is resizable, to allow the user to easily use more screen
+space where necessary to view the results data, instead of forcing the
+user to use scrollbars (which also are available).
+
+Any number of copies---collated or not---can be printed to the default
+printer. The common Print dialog is used, so the printer can be set up
+before printing, if necessary. Printing can be cancelled, as well.
+
+The results of the check can also be saved to a file by choosing the
+"Log..." button. The common "Save As" dialog is used. The suggested file
+name is "check-X.log" where "X:" is the volume that was checked, and the
+directory that is suggested is the system directory, e.g. "c:\winnt". As
+this is a common dialog, the user can choose a network drive (and even
+connect to one).
+
+Since a standard edit control is used to display the results information,
+the user can select text there via either the keyboard or a mouse, and
+copy it to the clipboard. It can then be pasted in an application like
+notepad when writing a report, for example.
+
+If a volume is to be checked in a "fix" mode, then the volume must be
+opened for exclusive access. If this cannot occur due to the volume
+being in use, then a message appears asking whether the user would like
+to schedule the check for the next system reboot. (For instance, a
+volume can be locked by simply opening a command window and setting the
+current drive to it). The user can choose either yes or no. If the user
+chooses "no", then the check simply ends without performing any work. If
+the user chooses "yes", then a confirmation message box appears stating
+that the check has been scheduled (or could not be scheduled).
diff --git a/private/utils/windisk/doc/dlls.txt b/private/utils/windisk/doc/dlls.txt
new file mode 100644
index 000000000..d78909c8e
--- /dev/null
+++ b/private/utils/windisk/doc/dlls.txt
@@ -0,0 +1,81 @@
+A description of the DLLs used in the Cairo Disk Administrator
+==============================================================
+
+There are several EXEs and DLLs integral to the operation of
+the Disk Administrator. This note discusses those executables,
+their interrelationship, why they are necessary, and why the
+functionality is broken up so.
+
+windisk.exe -- the guts, including partitioning, fault tolerance configuration,
+and file system operations (format, chkdsk, label).
+
+A note on the NT file and disk utilities: All the NT file and disk
+utilities---chkdsk, format, comp, attrib, etc---heavily utilize C++:
+most everything of interest is a class---command-line arguments,
+buffers, strings, stacks, disk drives, HPFS & FAT file system information,
+etc. Much common code, including classes for the examples just
+given, reside in ulib.dll.
+
+fmifs.dll -- a small utitilty converting between NT utility DLL APIs
+and callback functions. This DLL was originally written for use by File
+Manager, for floppy disk formatting and volume label changing. It
+isolates its clients from the vagaries of the utilities library classes,
+namely the message feedback class. All feedback from chkdsk, format, etc,
+is normally reported by a Display() method being called on a MESSAGE
+class, a pointer to which is passed to the file system Format(),
+Chkdsk(), etc. API. The fmifs.dll code converts this message into a
+function callback, passing along any relevant information. To use the
+file system utility APIs directly would force clients to compile in the
+utilities environment, incorporating lots of undesirable C++ stuff.
+
+ifsutil.dll -- installable file system utilities. C++ classes
+providing low-level file system and disk abstractions for the
+NT installable file system interface.
+
+uofs.dll, untfs.dll, uhpfs.dll, ufat.dll -- the file system
+utilities (chkdsk, format, label, etc) for each file system. Note that
+the code incorporated into these DLLs is used in several distinct and
+diverse environments. These are the setup environment, as autochk in
+the boot environment, and from the chkdsk, format, label, etc., front
+ends. And now, from Disk Administrator. Note that these are amazingly
+different. For example, in the boot environment there is no virtual
+memory! Message feedback requirements are obviously different in the
+character-based and GUI environments.
+
+ulib.dll -- a library for the utilities. Includes various common-code
+helper classes, as described above.
+
+
+
+Here are the dependencies (ignoring ntdll.dll, kernel32.dll, etc):
+
+windisk.exe depends on fmifs.dll
+
+fmifs.dll: depends on ulib.dll, ifsutil.dll
+
+ifsutil.dll: depends on ulib.dll
+
+uofs.dll ufat.dll, untfs.dll, uhpfs.dll: depend on ulib.dll, ifsutil.dll
+
+ulib.dll: no dependencies of note
+
+
+
+Here's the *approximate* tree (DAG, actually): things above depend on
+things below. Same level means no dependencies.
+
+
+ windisk.exe
+
+ fmifs.dll
+
+ ufat.dll uhpfs.dll untfs.dll uofs.dll
+
+ ifsutil.dll
+
+ ulib.dll
+
+
+
+Note that windisk lazy-loads fmifs.dll: only when an operation requiring
+file system operations is to be performed does windisk load this dll.
diff --git a/private/utils/windisk/doc/extend.txt b/private/utils/windisk/doc/extend.txt
new file mode 100644
index 000000000..1bb7dcf2c
--- /dev/null
+++ b/private/utils/windisk/doc/extend.txt
@@ -0,0 +1,24 @@
+Disk Administrator Extension Interfaces
+=======================================
+
+The extension interfaces have been commented (#ifdef'ed) out. The interfaces
+are defined in the "types" subdirectory.
+
+This file contains some information on their design and implementation.
+
+-----------------------------Volume Claiming
+
+During initialization, all the extension classes are enumerated. Then,
+the following happens:
+
+1. for each pre-existing volume, determine all the volume extension
+classes that claim it.
+
+2. for each pre-existing formatted volume, determine all the file system
+extension classes that claim it.
+
+3. for each hard drive, determine all the hard disk extension classes
+that claim it.
+
+For now, this will all be done at start-up time, and not dynamically as
+we need it.
diff --git a/private/utils/windisk/doc/misc.txt b/private/utils/windisk/doc/misc.txt
new file mode 100644
index 000000000..b4de21141
--- /dev/null
+++ b/private/utils/windisk/doc/misc.txt
@@ -0,0 +1,51 @@
+Documents
+=========
+
+In \\worf\src\src\cairodwb\sysman\old:
+
+ wddev.doc -- "Cairo Disk Administrator Development Plan". A reasonably
+ up-to-date description of what work items we had in mind to complete
+ windisk. This document is also checked in locally, just in case.
+
+In \\kayak\design\docs:
+
+ windisk.doc -- KevinSch UI design document
+
+Right here (of marginal interest):
+
+ adskman2.doc -- "Architecture of the Cairo Disk Administrator". old. Mainly
+ discusses the extension architecture.
+
+ adskman.doc -- "Cairo Disk Administration". ancient. Purely historical
+ interest.
+
+
+Prototype
+=========
+
+The prototype (originally written by KevinP, munged by BruceFo) is under
+\\kayak\design. I don't know which one is up-to-date, but probably either
+proto\dskman.exe or protos\diskman\dskman.exe.
+
+
+
+Random notes:
+=============
+
+People who have worked on windisk:
+
+ Development
+ TedM -- original writer ?
+ BillMc -- ?
+ BobRi -- NT 3.5, NT 3.51
+ BruceFo -- Cairo version, concurrent with NT 3.5, 3.51
+
+ User Ed:
+ Peget -- UserEd for Daytona windisk
+
+ Program Management
+ KevinP -- original
+ DanPl -- ?
+ KevinSch
+
+Windows 95 "Disks" tool (Windisk): \\tal\msdos\src\win\core\shell\cpls\windisk
diff --git a/private/utils/windisk/doc/progmgmt.bmp b/private/utils/windisk/doc/progmgmt.bmp
new file mode 100644
index 000000000..153f4affa
--- /dev/null
+++ b/private/utils/windisk/doc/progmgmt.bmp
Binary files differ
diff --git a/private/utils/windisk/doc/select.txt b/private/utils/windisk/doc/select.txt
new file mode 100644
index 000000000..c70b77819
--- /dev/null
+++ b/private/utils/windisk/doc/select.txt
@@ -0,0 +1,75 @@
+Selection & Focus
+=================
+
+This section describes the design for selection and focus in the Disk
+Administrator.
+
+The two DA views have different selection and focus characteristics.
+The disks view displays a superset of the information provided in the
+volumes view, by showing free space and the actual breakdown of
+partitions in a volume.
+
+The focus is a pure UI concept that doesn't affect the selection. Thus,
+we don't maintain the focus. We determine a reasonable focus for the
+new view when a view change occurs.
+
+The selection, however, must be maintained. The UI selection is reflected
+in the internal data structures and is what commands operate on. We also
+maintain the visual selection in both views.
+
+The selection in the disks view consists of a set of volumes and a set
+of free spaces. It is impossible to select only one partition of a
+multi-paritition (FT) volume; the entire volume is selected. In the volumes
+view, we only allow a single item to be selected, as we don't support any
+operations on multiple volume selections. In addition, the volumes view doesn't
+display any free space regions, so we must deselect free space when switching
+to the volumes view.
+
+The following analyzes the different cases:
+
+Disks view
+
+ -- mouse select:
+ The subclassed window proc catches the mouse click.
+
+ First, if this isn't a ctrl-click (multiple select), then all
+ regions are cleared of any existing selection. If it is a
+ multiple selection, then no selection is cleared.
+
+ The region is determined, if the click corresponds to a region, and
+ selected. The focus is given to the selected region.
+
+ -- keyboard select:
+ Approximately the same as above, except it is easier to
+ determine what region we are operating on.
+
+Volumes view
+
+ -- mouse select:
+ -- keyboard select:
+
+ In both cases, we only do things when we get a LVN_ITEMCHANGED
+ notification message. The cases we handle:
+
+ volume loses selection:
+ deselect all regions of this volume.
+
+ volume gets selection:
+ select all regions of this volume.
+
+Things to do when switching from disks view to volumes view:
+ -- set the focus. If the disks view focus is on free space, then
+ put the focus on the first volume in the volumes view.
+ -- adjust the selection: deselect all free space.
+
+Things to do when switching from volumes view to disks view:
+ -- set the focus. Pick a random region from the volume that has the
+ focus. For instance, if volume "F:" has the focus, then pick any of
+ its component regions---e.g., it doesn't matter which region of a volume
+ set gets the focus.
+
+Things to do when we initialize Disk Administrator:
+ -- set no selection
+ -- set the focus:
+ -- if disks view: first region on first disk
+ -- if volumes view: first volume
diff --git a/private/utils/windisk/doc/testing.txt b/private/utils/windisk/doc/testing.txt
new file mode 100644
index 000000000..3a0d235e5
--- /dev/null
+++ b/private/utils/windisk/doc/testing.txt
@@ -0,0 +1,48 @@
+Testing scenarios
+=================
+
+What if you break a mirror with no drive letters left?
+
+What about if there is very little space available and the status bar &
+toolbar overlap?
+
+Does "Refresh" reload the format & label? E.g., format a volume in a
+command window, then refresh windisk. does the new label/etc show up?
+
+anything with volumes that don't have drive letters. You can create
+such volumes by creating more than 24 volumes, thereby using up all
+available drive letters.
+
+test that toolbar state is remembered. i.e., if we allow customization,
+then that customization should be saved.
+
+partition a disk, turn off the machine, detach the disk, run windisk to
+change something on another disk, turn off the machine, reattach the old
+disk, re-run windisk. windisk should remember the FT registry settings
+of the old disk even though it didn't exist during one session.
+
+force a disk to be off-line and test how windisk displays it.
+
+out of memory
+
+corrupt or non-existent FT registry data?
+
+entire disk as extended partition w/ some logical volumes?
+
+no extended partition. Try creating too many partitions.
+
+test with a removable hard drive; a Bernoulli box
+
+context menus on formatted volumes (and perhaps disks)
+
+format
+------
+Try all combinations of the following:
+ -- file system: FAT, OFS, HPFS, NTFS
+ -- volume type: simple, volume set, mirror, stripe set, stripe with parity
+
+chkdsk
+------
+Try all combinations of the following:
+ -- file system: FAT, OFS, HPFS, NTFS
+ -- volume type: simple, volume set, mirror, stripe set, stripe with parity
diff --git a/private/utils/windisk/doc/thecode.txt b/private/utils/windisk/doc/thecode.txt
new file mode 100644
index 000000000..73fab8b60
--- /dev/null
+++ b/private/utils/windisk/doc/thecode.txt
@@ -0,0 +1,212 @@
+Notes on the Cairo Disk Administrator source
+-------------------------------------------------------------------------
+
+The Cairo Disk Administrator (windisk) started with the code for
+NT windisk, and evolved from there.
+
+Here is a short overview of the internal architecture of windisk:
+
+Windisk is basically a front-end to the disk partitioning back-end that
+exists in engine.cxx. The back-end was originally used in two places:
+windisk, and in the ARC install program. There are a number of things in
+windisk, particularly data structures, which reflect this structure.
+
+The back-end interface provides an array of regions for each disk, where
+a region is a primary partition or a logical volume. An extended
+partition is actually a type of primary partition. Free space may be
+either primary or logical. The back-end provides methods to create and
+delete partitions, and query various properties of the disks and
+partitions.
+
+The main structure in windisk is a DISKSTATE. There is an array: one for each
+disk. This structure contains various properties of the disk, but
+mainly contains the region array gathered from the partitioning
+back-end, and several parallel arrays holding information about each
+region (such as whether the region is selected).
+
+Each element of the region array for non-freespace regions has something
+called "persistent data". This is a pointer to a PERSISTENT_REGION_DATA
+structure, holding information such as the region's drive volume label,
+file system type, and drive letter. This information is "persistent" in
+that it persists across partition creation and deletion. When a
+partition is created or deleted, windisk notifies the back-end, and then
+throws away its region information for the disk and asks the back-end
+for a new region array. This new region array has all the old
+"persistent" data, attached to the proper regions.
+
+When a volume is composed of more than one region, handling it becomes a
+bit trickier than handling single-partition volumes. There is no data
+structure maintained that maps volumes to regions, thus it is necessary
+to search all the regions to determine which regions belong to a
+multi-partition volume (e.g., volume set, stripe set, mirror). The
+regions for a multi-partition volume have a pointer to an "FT object"
+structure in their persistent data, where it is possible to find
+information about the volume as a whole.
+
+Cairo windisk also supports CD-ROMs in the main view. This is accomplished
+by an array of CDROM_DESCRIPTOR items. CD-ROMs always display after all the
+disks.
+
+
+The UI
+------
+
+The two views are implemented as follows:
+
+ disks view: a subclassed Windows owner-draw listbox where each element
+ in the listbox is a single disk bar.
+
+ volumes view: a Windows 95 common control listview in "report view"
+ mode. Each element represents a volume (something with a drive letter).
+
+The toolbar is a common control toolbar (in comctl32.dll).
+
+The status bar and legend are simply drawn.
+
+
+The file system operations
+--------------------------
+
+Format and Chkdsk are multi-threaded, to allow one (or more) thread(s)
+to display UI while one performs the actual operation. This works as
+follows:
+
+Format: A dialog box is created with a "cancel" button and a "percent
+full" bar. On creation, a thread is created to do the actual
+formatting. Formatting is done by calling the FMIFS.dll Format()
+entrypoint, which takes as an argument a callback function. This
+callback is called for any feedback event, such as a "percent complete"
+message, or a "amount of free space" message. When the callback gets an
+interesting message, it sends a Windows message to the dialog box procedure
+in the other thread, which gets it and interprets it. When the format
+is finished, a "done" message is posted to the dialog, and it goes away.
+If the user presses "cancel" in the dialog, then a state variable is set
+that is checked on the next callback. If the variable has been set,
+then the callback immediately returns and the caller (the actual file
+system format routine) cleans up and exits.
+
+Chkdsk: very similar to format
+
+
+
+A Reader's Guide to the Windisk Code
+====================================
+
+Note that the NT and Cairo coding conventions are different. I have
+used Cairo function headers on all my new functions, and have converted some
+NT headers to Cairo headers where the difference was too glaring. Many
+Cairo-style headers have the history date "16-Aug-93" because that was
+when I put the header on, not necessarily when I wrote the function!
+
+Note that "IN" and "OUT" are only for function documentation: they
+expand to nothing during preprocessing.
+
+
+Source file translation
+=======================
+
+old file name new file name
+------------- -------------
+arrowin.c not used -- Win95 up/down common control used instead
+cdrom.c cdrom.cxx
+commit.c commit.cxx
+dblspace.c dblspace.cxx
+dskmgr.ico <same>
+fd_nt.c nt.cxx
+fdconst.h const.h
+fddata.c data.cxx
+fddlgs.c dlgs.cxx
+fdengine.c engine.cxx
+fdft.c ft.cxx
+fdft.h ft.hxx
+fdglob.h global.hxx
+fdhelp.c help.cxx
+fdhelpid.h helpid.h
+fdinit.c init.cxx
+fdisk.dlg dialogs.dlg
+fdisk.h headers.hxx (master, precompiled header)
+fdisk.rc windisk.rc
+fdiskmsg.mc messages.mc
+fdlistbx.c listbox.cxx
+fdmem.c mem.cxx
+fdmisc.c misc.cxx
+fdprof.c profile.cxx
+fdproto.h proto.hxx
+fdres.h resids.h
+fdstleg.c stleg.cxx
+fdtypes.h types.hxx
+fmifs.c fmifs.cxx
+ftreg.c ftreg.cxx
+ftreg.dlg ftreg.dlg
+ftreg.res ftreg.res
+ftregres.h ftreg.h
+makefile <same>
+makefile.inc <same>
+network.c network.cxx
+ntlow.c ntlow.cxx
+rmdisk.bmp <same>
+scsi.h <same>
+smdisk.bmp <same>
+sources <same>
+windisk.c windisk.cxx, ops.cxx
+
+
+new files
+---------
+cdpage.cxx, cdpage.hxx -- CD-ROM property page
+cdr.bmp -- bitmap of CD-ROM for property page
+cdrom.hxx -- cdrom.cxx declarations
+chkdsk.cxx, chkdsk.hxx -- chkdsk support
+cm.cxx, cm.hxx -- context-menus
+commit.hxx -- commit.cxx declarations
+dblspace.dlg, dblspace.h, dblspace.res -- dialogs for DoubleSpace support
+dblspace.hxx -- dblspace.cxx declarations
+dialogs.h, dialogs.res -- most dialogs (also, dialogs.dlg)
+dispinfo.cxx, dispinfo.hxx -- display information class for volumes view
+dlgs.hxx -- declarations for dlgs.cxx
+drives.cxx, drives.hxx -- all drive-letter code
+engine.hxx -- declarations for engine.cxx
+extend.cxx, extend.hxx -- Disk Administrator extension support (currently
+ not used)
+fill.cxx, fill.hxx -- fills the volume view with data
+fmifs.hxx -- declarations for fmifs.cxx
+format.cxx, format.hxx -- format support
+fs.cxx, fs.hxx -- database of information on supported file
+ systems
+genlpage.cxx, genlpage.hxx -- "General" property page
+graph.cxx, graph.hxx -- Draws a %used/%free graph on property pages
+hard.bmp -- bitmap of hard disk for property page
+help.hxx -- declarations for help.cxx
+help2.cxx, help2.hxx -- "menu item" help, tooltip help
+init.hxx -- declarations for init.cxx
+label.cxx, label.hxx -- support for changing volume label
+listbox.hxx -- declarations for listbox.cxx
+log.cxx -- support for debug logging
+mem.hxx -- declarations for mem.cxx
+menudict.cxx, menudict.hxx -- dictionary of menu ids for use in allocating
+ extensions context-menu slots. (currently not
+ used)
+network.hxx -- declarations for network.cxx
+nt.hxx -- declarations for nt.cxx
+ntlow.hxx -- declarations for ntlow.cxx
+oleclass.cxx, oleclass.hxx -- OLE support for Disk Administrator extensions
+ (currently not used)
+ops.cxx, ops.hxx -- all partition and fault-tolerance configuration
+ occurs here.
+popup.cxx, popup.hxx -- context-menu support
+print.cxx, print.hxx -- support for printing the results of chkdsk
+profile.hxx -- declarations for profile.cxx
+ps.cxx, ps.hxx -- property sheet support
+rect.cxx, rectpriv.hxx -- the Disk Administrator rectangle control (used
+ in the "colors & patterns" dialog)
+scdrom.ico -- icon of CD-ROMs for volumes view
+select.cxx, select.hxx -- all selection handling code
+shard.ico -- icon of hard disks for volumes view
+smcdrom.bmp -- image of CD-ROM for disks view
+stleg.hxx -- declarations for stleg.cxx
+tb.h -- helper macros for the toolbar code
+tbar.cxx, tbar.hxx -- support for the toolbar
+tool16.bmp, xtra16.bmp -- bitmaps for the toolbar
+trffc14.ico -- "stop" icon for chkdsk stop dialog
+volview.cxx, volview.hxx -- main code for volumes view
+windisk.hxx -- declarations for windisk.cxx
diff --git a/private/utils/windisk/doc/todo.txt b/private/utils/windisk/doc/todo.txt
new file mode 100644
index 000000000..642e8e2c1
--- /dev/null
+++ b/private/utils/windisk/doc/todo.txt
@@ -0,0 +1,104 @@
+A very detailed description of Disk Administrator work items can be
+found in wddev.doc. Things found here are
+more detailed or unrelated notes.
+
+Visual/UI improvements for windisk:
+===================================
+
+The columns in volumes view should be sorted when a column header is clicked,
+and sorted in the opposite order when the column is clicked again. There is
+some code in place to support this, but it doesn't work, due to a problem with
+the list control.
+
+When we start using Cairo/Chicago visuals, there are some tweaks to consider:
+(1) highlight at the top of the toolbar, (2) drop the current spin button; use
+the comctl32.dll spin button (which looks really bad unless next to a sunken
+edit field).
+
+The "properties" menu item should possibly be on the "View" menu instead of
+the "Tools" menu.
+
+The comctl32.dll toolbar sits at the left edge of the window, which looks bad
+with NT visuals (i.e., non-bevelled window edges). Either fix this or wait
+for new visuals.
+
+Allow a user to select a printer to print chkdsk results to. Currently, it
+always uses the default printer. If the default printer doesn't exist, it
+pops up a "no default printer; use Print Manager to choose one" message box.
+
+Display what is loaded from a saved configuration, and allow changes,
+etc, before committing. And only commit the saved config if the user
+chooses to after a confirmation. Currently, a "configuration load" loads up
+the saved configuration and saves it: you get what you saved, no changes
+allowed.
+
+Don't regenerate the listview unless it changes. Also, if only one line
+changes, fix that line instead of regenerating the entire view.
+
+Have an option on the "Drive letter" dialog that allows setting all
+drive letters on the system to their default. Essentially, it would set
+everything to "do not assign a drive letter" except FT sets, which don't
+support non-persistent drive letters. So, after all the default ones
+were assigned, all the FT ones would be assigned.
+
+Allow setting a drive letter to something used by a network redirected drive.
+This would require doing the equivalent of a "net use x: /d" before affecting
+the change, and would require user confirmation before doing so.
+
+More columns in volumes view. There is likely more useful information that
+could be placed in the view, such as which volumes have active net sessions,
+which volumes are shared on the network in any way, an "activity" measurement
+so an admin can ask the question "which disks get the most use", etc. The set
+of displayed columns should be configurable, and stored with the user profile.
+
+Visually distinguish formatted & unformatted (i.e., newly created)
+volumes more strongly than now. For example, two volumes (one
+formatted, one not) that both have no label look exactly alike, except
+one has a "file system" named "Unknown". Could we gray the text? Shade
+the volume boxes? Use a different font?
+
+If you try to delete the primary/boot partition on drive 0, you get a
+message that "Windisk can't delete this partition" (similar, anyway).
+DOS Fdisk says the same, but pointed out to me that it was because there
+was an extended partition. After I deleted the extended partition, I
+could delete the primary partition. Windisk should give a better
+error message in this case?
+
+When Disk Administrator is starting, display a "splash screen" pop-up until we
+are ready to go.
+
+Put CD-ROMs in volumes view.
+
+
+
+Functional improvements for windisk:
+====================================
+
+One or more standard disk property sheets should be created that display
+SCSI/IDE adapter info, physical drive info, possibly some performance
+measurements, hardware FT information, etc. There could be one property sheet
+per disk, with any number of pages. Or, if we only need one page per disk, we
+could have a sheet where each page is titled "disk N".
+
+Since we now have on-the-fly partitioning, we should ask the user
+immediately after creating a partition whether or not they wish to format the
+volume, and send them directly into that dialog if they do.
+
+The profile information should use registry calls, not *PrivateProfileString
+APIs.
+
+Q: when does the "Configuration information not available" message get
+displayed in an empty disk box?
+
+I have hard-coded FmMediaFixed in the Format call. What about removable
+hard drives?
+
+Windisk saves information to the registry for every disk that it's ever
+seen. Should we have some kind of "advanced" option that allows an admin to
+purge unused registry information?
+
+
+Other:
+======
+
+Check all BUGBUGs before shipping.
diff --git a/private/utils/windisk/doc/wddev.doc b/private/utils/windisk/doc/wddev.doc
new file mode 100644
index 000000000..e1c2799f8
--- /dev/null
+++ b/private/utils/windisk/doc/wddev.doc
Binary files differ
diff --git a/private/utils/windisk/doc/why.txt b/private/utils/windisk/doc/why.txt
new file mode 100644
index 000000000..41783a646
--- /dev/null
+++ b/private/utils/windisk/doc/why.txt
@@ -0,0 +1,154 @@
+An overview of the Cairo Disk Administrator
+-------------------------------------------
+
+The Cairo Disk Administrator is an evolutionary improvement to the NT
+Disk Administrator. It differs from the NT version as follows:
+
+-- There are now two views: the volumes view and the disks view.
+The disks view is what exists in the current NT Disk Administrator.
+The volumes view is a columnar view filled with information about each
+volume (as opposed to each disk). It is intended to provide a quick
+summary of the volumes on a machine from a logical, as opposed to physical
+perspective. The columns include: (1) volume label, (2) capacity in MB,
+(3) free space in MB, (4) % free space, (5) file system type, (6) whether or
+not the volume is fault tolerant, (7) what type of volume: mirror, stripe,
+parity set, volume set, or simple, (8) the fault tolerance overhead in MB,
+(9) the FT status. The items can be sorted based on a particular column
+by clicking on the column header. Note that this makes it easy for an
+administrator to ask "what volumes have the most free space?" and similar
+questions.
+
+-- Right-button context menus on free space and volumes. A context menu
+displays the full set of allowable operations, even for multiple selections.
+(perhaps none, in which case the context menu indicates there are no valid
+operations). Also, there is a context menu on the legend.
+ Context menus are very valuable in this tool; they surface all the
+operations available in the tool in a simple-to-use manner. For instance, to
+create a volume from free space, you do the following:
+ 1. Right-click on a free space region. This both selects the region and
+ brings up the context menu,
+ 2. Choose "Create..."
+ 3. Pick the size and hit "OK"
+ 4. Choose "Commit Changes..." on any context menu.
+ 5. Right-click again to get a context menu
+ 6. Choose "format".
+ 7. Choose the file system and type a label, hit "OK"
+ 8. You've got a new volume.
+Note that you can also create FT sets by multiply selecting free space (or
+free space + non-free space for mirrors) and using the context menu.
+
+-- CD-ROM devices are displayed in the main view; you don't need to find a
+menu item to do CD-ROM operations. You change a CD-ROM drive letter just as
+you would choose any other volume's drive letter: select the volume (by
+clicking on the CD-ROM "bar"), and invoke the "Drive Letter..." function,
+either from the "Tools" menu or the context menu.
+
+-- "Chkdsk" is supported. The visualization is a %done graph. After it is
+done, a resizeable dialog showing error, warning, and informational messages
+is shown. These messages can be copy-and-pasted, saved to a file, or printed.
+
+-- Property sheets on volumes. The only page is a "General" page. The
+information displayed is similar to that in the volumes view, but
+is formatted for easier consumption. The volume operations are also available
+from the property sheet, namely format, chkdsk, and label (where label
+changing happens by simply editing the label in an edit control, not invoking
+a supplemental "label" dialog).
+
+
+
+Extensibility enhancements
+--------------------------
+
+-- There is a mechanism in place for 3rd parties to write extensions to
+the Disk Administrator using OLE interfaces. An extension provides menu items
+and property sheets. There are two types of extensions: volume and disk.
+During startup, Disk Administrator finds all the extensions (this set is
+currently hard-coded), and determines which extension is interested in which
+volume or disk. An extension may "claim" more than one volume or disk. Then,
+all the menu items and property pages provided by the extension are added
+when a user selects a particular volume or disk.
+
+NOTE: The extension architecture is currently "#ifdef"ed out, due to recent
+changes in the property sheet model (from OLE forms to Chicago common
+controls). The extension interface needs serious attention if it is to be
+useful.
+
+
+
+Basic usability enhancements
+----------------------------
+
+-- A toolbar with tooltips. (It will be customizable.)
+
+-- The width of disk bars in the disks view is set proportional to the
+Disk Administrator *window*, not the *display*, and are resized on window
+resizing. This eliminates the effect of "losing" a partition visually,
+when really all that's happened is that it's off the right edge of the screen.
+
+-- The status bar resizes instead of being clipped.
+
+-- Menu help: the status bar area displays a short help string based
+on the current menu selection
+
+-- The legend only displays the colors that appear in the disks view. For
+instance, the legend item for "Stripe set" doesn't appear if there are no
+stripe sets on the machine.
+
+-- A "stripe set with parity" gets a different legend color, which can be
+changed independent of the "stripe set" color, and is stored to the profile
+separately
+
+-- If the window isn't wide enough for a single-row legend, it wraps to use
+two or more rows.
+
+-- There is a "disk display" option which allows disk bars in the disks view
+to be sized (for width) either proportional to the capacity of the disk or all
+equally. This helps with the problem of hugely disproportionately sized
+disks in the system making the small disk bars hard to use. This value is
+stored to the profile.
+
+-- The "region display" option (which allows partitions in the disks view
+to be sized based on actual size, all equally (on this particular disk), or
+automatically based on Disk Administrator criteria) applies to only a single
+selected disk in standard NT. In the Cairo version, there is an option to
+apply the option choice to all disks. This option is the default. In
+addition, the automatic criteria was improved so Disk Administrator makes a
+much better default choice.
+
+
+
+Other enhancements
+------------------
+
+-- The source code compiles with the C++ compiler for better static checking.
+Few language constructs specific to C++ are used.
+
+-- The source is completely UNICODE
+
+-- Precompiled headers are used for better compilation speed
+
+
+
+What is left to implement before the Cairo version is finished
+--------------------------------------------------------------
+
+-- %done visualization in chkdsk is based on %done messages sent by the
+file system utilities. OFS doesn't send these messages.
+
+-- The extensibility system should be updated and fleshed out, or dropped.
+
+-- There is code to allow context menus on disks. If we don't have any
+interesting items (like property sheets), the code should be ripped out.
+
+-- The toolbar customization needs to be enabled and finished: the full set
+of operations is not available as toolbar buttons.
+
+-- It needs to be thoroughly tested.
+
+
+
+What else?
+----------
+
+-- The wddev.doc document describes a work program for more Disk Administrator
+improvements, including remoting, etc.
diff --git a/private/utils/windisk/doc/windisk.ppt b/private/utils/windisk/doc/windisk.ppt
new file mode 100644
index 000000000..24758aaf9
--- /dev/null
+++ b/private/utils/windisk/doc/windisk.ppt
Binary files differ
diff --git a/private/utils/windisk/hard/chard.cxx b/private/utils/windisk/hard/chard.cxx
new file mode 100644
index 000000000..df1702d44
--- /dev/null
+++ b/private/utils/windisk/hard/chard.cxx
@@ -0,0 +1,265 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: chard.cxx
+//
+// Contents: Disk Administrator volume extension class for hard disks
+//
+// Classes: CHard
+//
+// History: 10-May-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#include <headers.hxx>
+#pragma hdrstop
+
+#include "hard.hxx"
+#include "hardmenu.hxx"
+#include "dialogs.h"
+#include "global.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+static MenuItemType hard_menu[] =
+{
+ {
+ TEXT("&Configure RAID..."),
+ TEXT("Configure the fault tolerance characteristics of this logical disk"),
+ 0,
+ NULL //filled in later
+ }
+};
+
+static HardDiskInfoType hard_info =
+{
+ TEXT("Microsoft SCSI/RAID configuration"),
+ TEXT("MS RAID"),
+ DA_HD_FAULT_TOLERANT,
+
+ // menu items:
+ { ARRAYLEN(hard_menu), hard_menu },
+
+ // property pages:
+ { 0, NULL }
+};
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+//+---------------------------------------------------------------------------
+//
+// Method: CHard::CHard
+//
+// Synopsis: constructor
+//
+// Effects:
+//
+// Arguments: [pUnk] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 10-May-93 BruceFo Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+
+CHard::CHard(
+ IN IUnknown* pUnk
+ )
+ :
+ m_IUnknown(pUnk)
+{
+ HRESULT hr = CoCreateInstance(
+ CLSID_KDA_HardMenu,
+ NULL,
+ CLSCTX_ALL,
+ (REFIID)IID_IDAMenuDispatch,
+ (void**)&_pmenu);
+ if (SUCCEEDED(hr))
+ {
+ daDebugOut((DEB_TRACE, "Found IDAMenuDispatch\n"));
+ }
+ else
+ {
+ daDebugOut((DEB_ERROR, "Couldn't get IDAMenuDispatch\n"));
+
+ _pmenu = NULL;
+ }
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Method: CHard::~CHard
+//
+// Synopsis:
+//
+// Effects:
+//
+// Arguments: (none)
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 10-May-93 BruceFo Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+
+CHard::~CHard()
+{
+ if (_pmenu)
+ {
+ _pmenu->Release();
+ }
+}
+
+STDMETHODIMP
+CHard::QueryInterface(
+ IN REFIID riid,
+ OUT LPVOID* ppvObj
+ )
+{
+ return m_IUnknown->QueryInterface(riid, ppvObj);
+}
+
+STDMETHODIMP_(ULONG)
+CHard::AddRef(
+ VOID
+ )
+{
+ return m_IUnknown->AddRef();
+}
+
+STDMETHODIMP_(ULONG)
+CHard::Release(
+ VOID
+ )
+{
+ return m_IUnknown->Release();
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Method: CHard::Claim
+//
+// Synopsis:
+//
+// Effects:
+//
+// Arguments:
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 6-Jul-93 BruceFo Created
+//
+// Notes: BUGBUG: a mock-up: the first disk gets it, the others don't
+//
+//----------------------------------------------------------------------------
+
+STDMETHODIMP
+CHard::Claim(
+ IN HardDiskInfoBlockType* pInfo,
+ OUT BOOL* pfInterested
+ )
+{
+ daDebugOut((DEB_TRACE,
+ "IDAHardDiskInfo::Claim(%d,...) called\n",
+ pInfo->ulDiskNumber
+ ));
+
+ BOOL fInterested;
+
+ if (0 == pInfo->ulDiskNumber)
+ {
+ fInterested = TRUE;
+ }
+ else
+ {
+ fInterested = FALSE;
+ }
+
+ *pfInterested = fInterested;
+
+ return S_OK;
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Method: CHard::QueryInfo
+//
+// Synopsis:
+//
+// Effects:
+//
+// Arguments: ppInfo
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 10-May-93 BruceFo Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+
+STDMETHODIMP
+CHard::QueryInfo(
+ OUT HardDiskInfoType** ppInfo
+ )
+{
+ daDebugOut((DEB_TRACE,"IDAHardDiskInfo::QueryInfo() called\n"));
+
+ hard_info.mnuOps.aMenuItems[0].pMenuDispatch = _pmenu;
+
+ *ppInfo = &hard_info;
+ return S_OK;
+}
diff --git a/private/utils/windisk/hard/chardmnu.cxx b/private/utils/windisk/hard/chardmnu.cxx
new file mode 100644
index 000000000..f56d33da6
--- /dev/null
+++ b/private/utils/windisk/hard/chardmnu.cxx
@@ -0,0 +1,271 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: chardmnu.cxx
+//
+// Contents: Disk Administrator extension class for hard disks: menu ops
+//
+// Classes: CHardMenu
+//
+// History: 10-May-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#include <headers.hxx>
+#pragma hdrstop
+
+#include "hardmenu.hxx"
+#include "dialogs.h"
+#include "global.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+VOID
+DoConfigureRAID(
+ IN HWND hwndParent,
+ IN PWSTR DeviceName
+ );
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+//+---------------------------------------------------------------------------
+//
+// Method: CHardMenu::CHardMenu
+//
+// Synopsis: constructor
+//
+// Effects:
+//
+// Arguments: [pUnk] --
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 10-May-93 BruceFo Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+
+CHardMenu::CHardMenu(
+ IN IUnknown* pUnk
+ )
+ :
+ m_IUnknown(pUnk)
+{
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Method: CHardMenu::~CHardMenu
+//
+// Synopsis:
+//
+// Effects:
+//
+// Arguments: (none)
+//
+// Requires:
+//
+// Returns:
+//
+// Signals:
+//
+// Modifies:
+//
+// Derivation:
+//
+// Algorithm:
+//
+// History: 10-May-93 BruceFo Created
+//
+// Notes:
+//
+//----------------------------------------------------------------------------
+
+CHardMenu::~CHardMenu()
+{
+}
+
+STDMETHODIMP
+CHardMenu::QueryInterface(
+ IN REFIID riid,
+ OUT LPVOID* ppvObj
+ )
+{
+ return m_IUnknown->QueryInterface(riid, ppvObj);
+}
+
+STDMETHODIMP_(ULONG)
+CHardMenu::AddRef(
+ VOID
+ )
+{
+ return m_IUnknown->AddRef();
+}
+
+STDMETHODIMP_(ULONG)
+CHardMenu::Release(
+ VOID
+ )
+{
+ return m_IUnknown->Release();
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: CHardMenu::MenuDispatch
+//
+// Synopsis: Dispatch routine for Hard disk menu items
+//
+// Arguments: [hwndParent] -- parent HWND for any UI
+// [DeviceName] -- The NT object for the drive, e.g.
+// "\Device\Harddisk0"
+// [Item] -- Item number of invoked menu. This is the item
+// number associated with the menu in the information
+// passed to the Disk Administrator in the QueryInfo call.
+//
+// Returns: HRESULT
+//
+// History: 11-Jan-94 BruceFo Created
+//
+// Notes:
+//
+// item menu choice
+// ---- -----------
+// 0 Configure RAID
+//
+//--------------------------------------------------------------------------
+
+HRESULT
+CHardMenu::MenuDispatch(
+ IN HWND hwndParent,
+ IN LPWSTR DeviceName,
+ IN UINT Item
+ )
+{
+ switch (Item)
+ {
+ case 0:
+ daDebugOut((DEB_TRACE, "Configure RAID for %ws\n", DeviceName));
+ DoConfigureRAID(hwndParent, DeviceName);
+ break;
+
+ default:
+ daDebugOut((DEB_ERROR,
+ "Unknown hard disk extension, drive: %ws, menu item: %d\n",
+ DeviceName,
+ Item));
+ break;
+ }
+
+ return S_OK;
+}
+
+
+////////////////////////////////////////////////////////////////////////////
+
+BOOL CALLBACK ConfigDlgProc(HWND, UINT, WPARAM, LPARAM);
+
+
+VOID
+DoConfigureRAID(
+ IN HWND hwndParent,
+ IN PWSTR DeviceName
+ )
+{
+ HINSTANCE hInstanceSpin = LoadLibrary(L"spincube.dll");
+
+ int iRet = DialogBoxParam(
+ g_hInstance,
+ MAKEINTRESOURCE(IDD_CONFIG),
+ hwndParent,
+ ConfigDlgProc,
+ (LPARAM) g_hInstance
+ );
+
+ if (-1 == iRet)
+ {
+ daDebugOut((DEB_ERROR, "Couldn't create the dialog!\n"));
+ }
+
+ FreeLibrary(hInstanceSpin);
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: ConfigDlgProc, public
+//
+// Synopsis: Dialog procedure for the mocked-up "Configure RAID" dialog.
+//
+// Arguments: [hWnd] -- Window handle of the dialog box.
+// [wMsg] -- Window message.
+// [wParam] -- Message parameter.
+// [lParam] -- Message parameter.
+//
+// Returns: TRUE if message completely processed; FALSE to cause default
+// processing.
+//
+//--------------------------------------------------------------------------
+
+BOOL CALLBACK
+ConfigDlgProc( HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam )
+{
+ switch (wMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ //
+ // Center dialog on screen.
+ //
+
+ RECT rc;
+
+ GetWindowRect(hWnd, &rc);
+ SetWindowPos(
+ hWnd,
+ NULL,
+ (GetSystemMetrics(SM_CXSCREEN) - (rc.right - rc.left)) / 2,
+ (GetSystemMetrics(SM_CYSCREEN) - (rc.bottom - rc.top)) / 2,
+ 0,
+ 0,
+ SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
+
+ return TRUE;
+ }
+
+ case WM_COMMAND:
+ if (GET_WM_COMMAND_CMD(wParam, lParam) == BN_CLICKED)
+ {
+ switch (GET_WM_COMMAND_ID(wParam, lParam))
+ {
+ case IDOK:
+ EndDialog(hWnd, 0);
+ break;
+ }
+ }
+ break;
+
+ case WM_CLOSE:
+ EndDialog(hWnd,0);
+ break;
+ }
+
+ return FALSE;
+}
diff --git a/private/utils/windisk/hard/dialogs.dlg b/private/utils/windisk/hard/dialogs.dlg
new file mode 100644
index 000000000..6f19c545c
--- /dev/null
+++ b/private/utils/windisk/hard/dialogs.dlg
@@ -0,0 +1,8 @@
+IDD_CONFIG DIALOG 60, 24, 190, 161
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Microsoft SCSI/RAID Config"
+BEGIN
+ DEFPUSHBUTTON "OK", IDOK, 68, 138, 50, 14
+ CONTROL "", IDC_PICTURE, "Spincube", 0x0003, 20, 16, 152, 110
+END
diff --git a/private/utils/windisk/hard/dialogs.h b/private/utils/windisk/hard/dialogs.h
new file mode 100644
index 000000000..39b56efdc
--- /dev/null
+++ b/private/utils/windisk/hard/dialogs.h
@@ -0,0 +1,3 @@
+#define IDD_CONFIG 100
+#define IDC_PICTURE 101
+
diff --git a/private/utils/windisk/hard/global.hxx b/private/utils/windisk/hard/global.hxx
new file mode 100644
index 000000000..d48da8fe0
--- /dev/null
+++ b/private/utils/windisk/hard/global.hxx
@@ -0,0 +1,22 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: global.hxx
+//
+// Contents: global variable definitions
+//
+// History: 11-Jan-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef __GLOBAL_HXX__
+#define __GLOBAL_HXX__
+
+extern HINSTANCE g_hInstance;
+
+extern ULONG g_ulcInstancesHard;
+extern ULONG g_ulcInstancesHardMenu;
+
+#endif // __GLOBAL_HXX__
diff --git a/private/utils/windisk/hard/hard.cxx b/private/utils/windisk/hard/hard.cxx
new file mode 100644
index 000000000..12e2adb43
--- /dev/null
+++ b/private/utils/windisk/hard/hard.cxx
@@ -0,0 +1,199 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: hard.cxx
+//
+// Contents: Disk Administrator volume extension class for hard disks
+//
+// Classes:
+//
+// Functions:
+//
+// History: 10-May-93 BruceFo Created from kevinro event report code
+//
+// Note: Eventually, this code will be generated by tools. Therefore, the
+// comments and cleanliness is not up to par.
+//
+//----------------------------------------------------------------------------
+
+#include <headers.hxx>
+#pragma hdrstop
+
+#include "hard.hxx"
+#include "global.hxx"
+
+
+CHardIUnknown::CHardIUnknown()
+ : m_pClass(NULL),
+ m_uRefs(1)
+{
+ InterlockedIncrement((LONG*)&g_ulcInstancesHard);
+}
+
+
+CHardIUnknown::~CHardIUnknown()
+{
+ InterlockedDecrement((LONG*)&g_ulcInstancesHard);
+ delete m_pClass;
+}
+
+STDMETHODIMP
+CHardIUnknown::QueryInterface(REFIID riid, LPVOID* ppvObj)
+{
+ *ppvObj = NULL;
+
+ IUnknown *pUnkTemp = NULL;
+ SCODE sc = S_OK;
+
+ if (IsEqualIID(IID_IUnknown, riid))
+ {
+ pUnkTemp = (IUnknown*) this;
+ }
+ else
+ if (IsEqualIID(IID_IDAHardDiskInfo, riid))
+ {
+ pUnkTemp = (IDAHardDiskInfo*) m_pClass;
+ }
+ else
+ {
+ sc = E_NOINTERFACE;
+ }
+
+ if (pUnkTemp != NULL)
+ {
+ pUnkTemp->AddRef();
+ }
+
+ *ppvObj = pUnkTemp;
+
+ return sc;
+}
+
+
+STDMETHODIMP_(ULONG)
+CHardIUnknown::AddRef()
+{
+ InterlockedIncrement((LONG*)&m_uRefs);
+ return m_uRefs;
+}
+
+
+STDMETHODIMP_(ULONG)
+CHardIUnknown::Release()
+{
+ ULONG cRef;
+
+ if (0 == (cRef=InterlockedDecrement((LONG*)&m_uRefs)))
+ {
+ delete this;
+ }
+
+ return cRef;
+}
+
+
+STDMETHODIMP
+CHardCF::QueryInterface(REFIID riid, LPVOID* ppvObj)
+{
+ *ppvObj = NULL;
+
+ IUnknown* pUnkTemp = NULL;
+ SCODE sc = S_OK;
+
+ if ( IsEqualIID(IID_IUnknown, riid)
+ || IsEqualIID(IID_IClassFactory, riid))
+ {
+ pUnkTemp = (CHardCF *)this;
+ }
+ else
+ {
+ sc = E_NOINTERFACE;
+ }
+
+ if (pUnkTemp != NULL)
+ {
+ pUnkTemp->AddRef();
+ }
+
+ *ppvObj = pUnkTemp;
+
+ return sc;
+}
+
+
+STDMETHODIMP_(ULONG)
+CHardCF::AddRef()
+{
+ InterlockedIncrement((LONG*)&g_ulcInstancesHard);
+ return g_ulcInstancesHard;
+}
+
+STDMETHODIMP_(ULONG)
+CHardCF::Release()
+{
+ InterlockedDecrement((LONG*)&g_ulcInstancesHard);
+ return g_ulcInstancesHard;
+}
+
+
+
+//
+// IClassFactory Overide
+//
+STDMETHODIMP
+CHardCF::CreateInstance(IUnknown* pUnkOuter, REFIID riid, LPVOID* ppvObj)
+{
+ HRESULT hr = S_OK;
+ CHardIUnknown* pIUnk = NULL;
+
+ pIUnk = new CHardIUnknown();
+
+ if (pUnkOuter == NULL)
+ {
+ pIUnk->m_pClass = new CHard(pIUnk);
+
+ hr = pIUnk->m_pClass->QueryInterface(riid, ppvObj);
+ pIUnk->Release();
+
+ if (FAILED(hr))
+ {
+ //
+ // BUGBUG: Whats the error code?
+ //
+
+ hr = E_NOINTERFACE;
+ }
+ }
+ else
+ {
+ if ( ! IsEqualIID(riid, IID_IUnknown) )
+ {
+ hr = E_NOINTERFACE;
+ }
+ else
+ {
+ pIUnk->m_pClass = new CHard(pUnkOuter);
+ *ppvObj = (IUnknown *)pIUnk;
+ pIUnk->AddRef();
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ delete pIUnk;
+ }
+
+ return hr;
+}
+
+
+STDMETHODIMP
+CHardCF::LockServer(BOOL fLock)
+{
+ //
+ // BUGBUG: Whats supposed to happen here?
+ //
+ return S_OK;
+}
diff --git a/private/utils/windisk/hard/hard.def b/private/utils/windisk/hard/hard.def
new file mode 100644
index 000000000..acf804dea
--- /dev/null
+++ b/private/utils/windisk/hard/hard.def
@@ -0,0 +1,11 @@
+#include "..\..\sysmgmt.def"
+
+LIBRARY DAHARD
+DESCRIPTION 'Microsoft Windows NT Disk Administrator Extension Class for Hard Disks'
+
+EXPORTS
+
+ PRIVATESYMBOL( DllGetClassObject, 12 )
+ PRIVATESYN( DllGetClassObject, 12 )
+ PRIVATESYMBOL( DllCanUnloadNow, 0 )
+ PRIVATESYN( DllCanUnloadNow, 0 )
diff --git a/private/utils/windisk/hard/hard.hxx b/private/utils/windisk/hard/hard.hxx
new file mode 100644
index 000000000..b5780dade
--- /dev/null
+++ b/private/utils/windisk/hard/hard.hxx
@@ -0,0 +1,103 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: hard.hxx
+//
+// Contents: Disk Administrator volume extension class for Hard Disks
+//
+// Classes:
+// CHardIUnknown
+// CHardCF
+// CHard
+//
+// History: 10-May-93 BruceFo Created from kevinro event report code
+//
+//----------------------------------------------------------------------------
+
+class CHardIUnknown;
+class CHardCF;
+class CHard;
+
+class CHard : public IDAHardDiskInfo
+{
+public:
+ CHard(IUnknown* pUnk);
+ ~CHard();
+
+ //
+ // IUnknown methods
+ //
+
+ STDMETHOD(QueryInterface)(REFIID riid, LPVOID* ppvObj);
+ STDMETHOD_(ULONG,AddRef)();
+ STDMETHOD_(ULONG,Release)();
+
+ //
+ // IDAHardDiskInfo methods
+ //
+
+ STDMETHOD(Claim)(HardDiskInfoBlockType* pInfo, BOOL* pfInterested);
+ STDMETHOD(QueryInfo)(HardDiskInfoType** ppInfo);
+
+private:
+ friend CHardCF;
+ friend CHardIUnknown;
+ IUnknown* m_IUnknown;
+
+ //
+ // Class variables
+ //
+
+ CLSID m_cidClass;
+
+ IDAMenuDispatch* _pmenu;
+};
+
+class CHardIUnknown : public IUnknown
+{
+public:
+ CHardIUnknown();
+ ~CHardIUnknown();
+
+ //
+ // IUnknown methods
+ //
+
+ STDMETHOD(QueryInterface)(REFIID riid, LPVOID* ppvObj);
+ STDMETHOD_(ULONG,AddRef)();
+ STDMETHOD_(ULONG,Release)();
+
+private:
+ friend CHardCF;
+
+ CHard * m_pClass;
+ unsigned long m_uRefs;
+};
+
+
+
+class CHardCF : public IClassFactory
+{
+public:
+
+ //
+ // IUnknown methods
+ //
+
+ STDMETHOD(QueryInterface)(REFIID riid, LPVOID* ppvObj);
+ STDMETHOD_(ULONG,AddRef)();
+ STDMETHOD_(ULONG,Release)();
+
+ //
+ // IClassFactory methods
+ //
+
+ STDMETHOD(CreateInstance)(
+ IUnknown* pUnkOuter,
+ REFIID riid,
+ LPVOID* ppvObj);
+
+ STDMETHOD(LockServer)(BOOL fLock);
+};
diff --git a/private/utils/windisk/hard/hard.rc b/private/utils/windisk/hard/hard.rc
new file mode 100644
index 000000000..dc53a2f55
--- /dev/null
+++ b/private/utils/windisk/hard/hard.rc
@@ -0,0 +1,28 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: hard.rc
+//
+// Contents: Resources for Disk Administrator Hard Disk extension class
+//
+// History: 27-May-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#include <windows.h>
+#include "dialogs.h"
+#include "dialogs.dlg"
+
+////////////////////////////////////////////////////////////////////////////
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Disk Administrator Hard Disk Extension Class"
+#define VER_INTERNALNAME_STR "dahard\0"
+#define VER_ORIGINALFILENAME_STR "DAHARD.DLL"
+
+#include "common.ver"
diff --git a/private/utils/windisk/hard/hardmenu.cxx b/private/utils/windisk/hard/hardmenu.cxx
new file mode 100644
index 000000000..0d219ebb1
--- /dev/null
+++ b/private/utils/windisk/hard/hardmenu.cxx
@@ -0,0 +1,192 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: hardmenu.cxx
+//
+// Contents: Disk Administrator extension class for hard disks: menu ops
+//
+// History: 11-Jan-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#include <headers.hxx>
+#pragma hdrstop
+
+#include "hardmenu.hxx"
+#include "global.hxx"
+
+
+CHardMenuIUnknown::CHardMenuIUnknown()
+ : m_pClass(NULL),
+ m_uRefs(1)
+{
+ InterlockedIncrement((LONG*)&g_ulcInstancesHardMenu);
+}
+
+
+CHardMenuIUnknown::~CHardMenuIUnknown()
+{
+ InterlockedDecrement((LONG*)&g_ulcInstancesHardMenu);
+ delete m_pClass;
+}
+
+STDMETHODIMP
+CHardMenuIUnknown::QueryInterface(REFIID riid, LPVOID* ppvObj)
+{
+ *ppvObj = NULL;
+
+ IUnknown *pUnkTemp = NULL;
+ SCODE sc = S_OK;
+
+ if (IsEqualIID(IID_IUnknown, riid))
+ {
+ pUnkTemp = (IUnknown*) this;
+ }
+ else
+ if (IsEqualIID(IID_IDAMenuDispatch, riid))
+ {
+ pUnkTemp = (IDAMenuDispatch*) m_pClass;
+ }
+ else
+ {
+ sc = E_NOINTERFACE;
+ }
+
+ if (pUnkTemp != NULL)
+ {
+ pUnkTemp->AddRef();
+ }
+
+ *ppvObj = pUnkTemp;
+
+ return sc;
+}
+
+
+STDMETHODIMP_(ULONG)
+CHardMenuIUnknown::AddRef()
+{
+ InterlockedIncrement((LONG*)&m_uRefs);
+ return m_uRefs;
+}
+
+
+STDMETHODIMP_(ULONG)
+CHardMenuIUnknown::Release()
+{
+ ULONG cRef;
+
+ if (0 == (cRef=InterlockedDecrement((LONG*)&m_uRefs)))
+ {
+ delete this;
+ }
+
+ return cRef;
+}
+
+
+STDMETHODIMP
+CHardMenuCF::QueryInterface(REFIID riid, LPVOID* ppvObj)
+{
+ *ppvObj = NULL;
+
+ IUnknown* pUnkTemp = NULL;
+ SCODE sc = S_OK;
+
+ if ( IsEqualIID(IID_IUnknown, riid)
+ || IsEqualIID(IID_IClassFactory, riid))
+ {
+ pUnkTemp = (CHardMenuCF *)this;
+ }
+ else
+ {
+ sc = E_NOINTERFACE;
+ }
+
+ if (pUnkTemp != NULL)
+ {
+ pUnkTemp->AddRef();
+ }
+
+ *ppvObj = pUnkTemp;
+
+ return sc;
+}
+
+
+STDMETHODIMP_(ULONG)
+CHardMenuCF::AddRef()
+{
+ InterlockedIncrement((LONG*)&g_ulcInstancesHardMenu);
+ return g_ulcInstancesHardMenu;
+}
+
+STDMETHODIMP_(ULONG)
+CHardMenuCF::Release()
+{
+ InterlockedDecrement((LONG*)&g_ulcInstancesHardMenu);
+ return g_ulcInstancesHardMenu;
+}
+
+
+
+//
+// IClassFactory Overide
+//
+STDMETHODIMP
+CHardMenuCF::CreateInstance(IUnknown* pUnkOuter, REFIID riid, LPVOID* ppvObj)
+{
+ HRESULT hr = S_OK;
+ CHardMenuIUnknown* pIUnk = NULL;
+
+ pIUnk = new CHardMenuIUnknown();
+
+ if (pUnkOuter == NULL)
+ {
+ pIUnk->m_pClass = new CHardMenu(pIUnk);
+
+ hr = pIUnk->m_pClass->QueryInterface(riid, ppvObj);
+ pIUnk->Release();
+
+ if (FAILED(hr))
+ {
+ //
+ // BUGBUG: Whats the error code?
+ //
+
+ hr = E_NOINTERFACE;
+ }
+ }
+ else
+ {
+ if ( ! IsEqualIID(riid, IID_IUnknown) )
+ {
+ hr = E_NOINTERFACE;
+ }
+ else
+ {
+ pIUnk->m_pClass = new CHardMenu(pUnkOuter);
+ *ppvObj = (IUnknown *)pIUnk;
+ pIUnk->AddRef();
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ delete pIUnk;
+ }
+
+ return hr;
+}
+
+
+STDMETHODIMP
+CHardMenuCF::LockServer(BOOL fLock)
+{
+ //
+ // BUGBUG: Whats supposed to happen here?
+ //
+ return S_OK;
+}
diff --git a/private/utils/windisk/hard/hardmenu.hxx b/private/utils/windisk/hard/hardmenu.hxx
new file mode 100644
index 000000000..cb92caa89
--- /dev/null
+++ b/private/utils/windisk/hard/hardmenu.hxx
@@ -0,0 +1,104 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: hardmenu.hxx
+//
+// Contents: Disk Administrator extension class for Hard Disks: menu ops
+//
+// Classes:
+// CHardMenuIUnknown
+// CHardMenuCF
+// CHardMenu
+//
+// History: 11-Jan-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+class CHardMenuIUnknown;
+class CHardMenuCF;
+class CHardMenu;
+
+class CHardMenu : public IDAMenuDispatch
+{
+public:
+ CHardMenu(IUnknown* pUnk);
+ ~CHardMenu();
+
+ //
+ // IUnknown methods
+ //
+
+ STDMETHOD(QueryInterface)(REFIID riid, LPVOID* ppvObj);
+ STDMETHOD_(ULONG,AddRef)();
+ STDMETHOD_(ULONG,Release)();
+
+ //
+ // IDAMenuDispatch methods
+ //
+
+ STDMETHOD(MenuDispatch)(
+ HWND hwndParent,
+ LPWSTR DriveName,
+ UINT Item
+ );
+
+private:
+ friend CHardMenuCF;
+ friend CHardMenuIUnknown;
+ IUnknown* m_IUnknown;
+
+ //
+ // Class variables
+ //
+
+ CLSID m_cidClass;
+};
+
+class CHardMenuIUnknown : public IUnknown
+{
+public:
+ CHardMenuIUnknown();
+ ~CHardMenuIUnknown();
+
+ //
+ // IUnknown methods
+ //
+
+ STDMETHOD(QueryInterface)(REFIID riid, LPVOID* ppvObj);
+ STDMETHOD_(ULONG,AddRef)();
+ STDMETHOD_(ULONG,Release)();
+
+private:
+ friend CHardMenuCF;
+
+ CHardMenu * m_pClass;
+ unsigned long m_uRefs;
+};
+
+
+
+class CHardMenuCF : public IClassFactory
+{
+public:
+
+ //
+ // IUnknown methods
+ //
+
+ STDMETHOD(QueryInterface)(REFIID riid, LPVOID* ppvObj);
+ STDMETHOD_(ULONG,AddRef)();
+ STDMETHOD_(ULONG,Release)();
+
+ //
+ // IClassFactory methods
+ //
+
+ STDMETHOD(CreateInstance)(
+ IUnknown* pUnkOuter,
+ REFIID riid,
+ LPVOID* ppvObj);
+
+ STDMETHOD(LockServer)(BOOL fLock);
+};
diff --git a/private/utils/windisk/hard/headers.hxx b/private/utils/windisk/hard/headers.hxx
new file mode 100644
index 000000000..6e5fb0448
--- /dev/null
+++ b/private/utils/windisk/hard/headers.hxx
@@ -0,0 +1,19 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: headers.hxx
+//
+// Contents: Headers for hard disk extension class
+//
+// History: 11-Jan-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+#include <windows.h>
+#include <windowsx.h>
+#include <ole2.h>
+#include <debug.h>
+
+#include <dacommon.h>
diff --git a/private/utils/windisk/hard/libinit.cxx b/private/utils/windisk/hard/libinit.cxx
new file mode 100644
index 000000000..da059962e
--- /dev/null
+++ b/private/utils/windisk/hard/libinit.cxx
@@ -0,0 +1,144 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: libinit.cxx
+//
+// Contents: DLL initialization code
+//
+// Functions:
+// DllMain
+//
+// History: 9-May-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+#include <headers.hxx>
+#pragma hdrstop
+
+#include <util.hxx>
+
+#include "hard.hxx"
+#include "hardmenu.hxx"
+#include "global.hxx"
+
+DECLARE_INFOLEVEL(da)
+
+HINSTANCE g_hInstance = NULL;
+
+ULONG g_ulcInstancesHard;
+ULONG g_ulcInstancesHardMenu;
+
+
+//+-------------------------------------------------------------------
+//
+// Function: DllMain
+//
+// Synopsis: Performs initialization of the DLL.
+//
+// Arguments: hInstance - Handle to this dll
+// dwReason - Reason this function was called. Can be
+// Process/Thread Attach/Detach.
+//
+// Returns: BOOL - TRUE if no error. FALSE otherwise
+//
+// History: 15-May-92 BryanT Created
+//
+//--------------------------------------------------------------------
+
+extern "C" BOOL
+DllMain(
+ HINSTANCE hInstance,
+ DWORD dwReason,
+ LPVOID lpReserved
+ )
+{
+ BOOL fRc = TRUE;
+
+ UNREFERENCED_PARM(lpReserved);
+ UNREFERENCED_PARM(hInstance);
+
+ switch (dwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+
+#ifdef DA_PRIVATE_BUILD
+ daInfoLevel =
+ DEB_ERROR
+ | DEB_WARN
+ | DEB_TRACE
+ | DEB_IERROR
+ | DEB_IWARN
+ | DEB_ITRACE
+ ;
+#endif
+
+ g_hInstance = hInstance;
+
+ //
+ // Disable thread notification from OS
+ //
+ DisableThreadLibraryCalls(hInstance);
+
+ daDebugOut((DEB_ITRACE,"dahard.dll attach\n"));
+ break;
+
+ case DLL_PROCESS_DETACH:
+ daDebugOut((DEB_ITRACE,"dahard.dll detach\n"));
+ break;
+
+ }
+
+ return(fRc);
+}
+
+
+
+STDAPI
+DllCanUnloadNow(
+ VOID
+ )
+{
+ daDebugOut((DEB_ITRACE,"--> enter dahard.dll DllCanUnloadNow\n"));
+
+ if ( 0 == g_ulcInstancesHard
+ && 0 == g_ulcInstancesHardMenu)
+ {
+ return S_OK;
+ }
+ else
+ {
+ return S_FALSE;
+ }
+}
+
+
+CHardCF cfHard;
+CHardMenuCF cfHardMenu;
+
+STDAPI
+DllGetClassObject(
+ REFCLSID cid,
+ REFIID iid,
+ LPVOID* ppvObj
+ )
+{
+#if DBG == 1
+ daDebugOut((DEB_ITRACE,"--> enter dahard.dll DllGetClassObject\n"));
+ DumpGuid(DEB_ITRACE|DEB_NOCOMPNAME, L" clsid = ", cid);
+ DumpGuid(DEB_ITRACE|DEB_NOCOMPNAME, L" iid = ", iid);
+#endif // DBG == 1
+
+ HRESULT hr = E_NOINTERFACE;
+
+ if (IsEqualCLSID(cid, CLSID_KDA_Hard))
+ {
+ hr = cfHard.QueryInterface(iid, ppvObj);
+ }
+ else if (IsEqualCLSID(cid, CLSID_KDA_HardMenu))
+ {
+ hr = cfHardMenu.QueryInterface(iid, ppvObj);
+ }
+ return hr;
+}
diff --git a/private/utils/windisk/hard/makefile b/private/utils/windisk/hard/makefile
new file mode 100644
index 000000000..14f79b701
--- /dev/null
+++ b/private/utils/windisk/hard/makefile
@@ -0,0 +1 @@
+!include $(NTMAKEENV)\makefile.def
diff --git a/private/utils/windisk/hard/makefile.inc b/private/utils/windisk/hard/makefile.inc
new file mode 100644
index 000000000..67ad41348
--- /dev/null
+++ b/private/utils/windisk/hard/makefile.inc
@@ -0,0 +1,6 @@
+obj\$(TARGET_DIRECTORY)\hard.res: \
+ $(BASEDIR)\public\sdk\inc\windows.h \
+ $(BASEDIR)\public\sdk\inc\common.ver \
+ $(BASEDIR)\public\sdk\inc\ntverp.h \
+ dialogs.h \
+ dialogs.dlg
diff --git a/private/utils/windisk/hard/sources b/private/utils/windisk/hard/sources
new file mode 100644
index 000000000..f6f71c4bb
--- /dev/null
+++ b/private/utils/windisk/hard/sources
@@ -0,0 +1,40 @@
+!include ..\windisk.mk
+
+MINORCOMP= dahard
+
+TARGETNAME= dahard
+TARGETPATH= obj
+TARGETTYPE= DYNLINK
+
+UMTYPE= windows
+UMRES= obj\*\hard.res
+
+TARGETLIBS=\
+ ..\util\obj\*\util.lib \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\gdi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+
+DLLDEF= obj\*\hard.def
+DLLENTRY= _DllMainCRTStartup
+DLLBASE= @$(BASEDIR)\public\sdk\lib\coffbase.txt,dahard
+
+INCLUDES=\
+ ..\inc; \
+ ..\util; \
+ $(INCLUDES)
+
+SOURCES=\
+ chard.cxx \
+ hard.cxx \
+ chardmnu.cxx \
+ hardmenu.cxx \
+ libinit.cxx \
+ hard.rc
+
+PRECOMPILED_CXX=1
+PRECOMPILED_INCLUDE=headers.hxx
+
+NTTARGETFILE1= obj\*\hard.res
diff --git a/private/utils/windisk/inc/dacommon.h b/private/utils/windisk/inc/dacommon.h
new file mode 100644
index 000000000..2769ec947
--- /dev/null
+++ b/private/utils/windisk/inc/dacommon.h
@@ -0,0 +1,80 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: dacommon.h
+//
+// Contents: Miscellaneous macros for use by the Disk Administrator
+//
+// History: 9-May-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef _DACOMMON_H_
+#define _DACOMMON_H_
+
+//
+// Fix the warning levels
+
+#pragma warning(3:4092) // sizeof returns 'unsigned long'
+#pragma warning(3:4121) // structure is sensitive to alignment
+#pragma warning(3:4125) // decimal digit in octal sequence
+#pragma warning(3:4130) // logical operation on address of string constant
+#pragma warning(3:4132) // const object should be initialized
+#pragma warning(4:4200) // nonstandard zero-sized array extension
+#pragma warning(4:4206) // Source File is empty
+#pragma warning(3:4208) // delete[exp] - exp evaluated but ignored
+#pragma warning(3:4212) // function declaration used ellipsis
+#pragma warning(3:4220) // varargs matched remaining parameters
+#pragma warning(4:4509) // SEH used in function w/ _trycontext
+#pragma warning(error:4700) // Local used w/o being initialized
+
+#if DBG == 0
+// in the debug build, constant assertions (e.g., FDASSERT(1=2)) cause
+// unreachable code. Only display unreachable code warning in the retail case
+#pragma warning(3:4702) // Unreachable code
+#endif // DBG == 0
+
+#pragma warning(3:4706) // assignment w/i conditional expression
+#pragma warning(3:4709) // command operator w/o index expression
+
+//////////////////////////////////////////////////////////////////////////////
+
+//
+// NOTE: ntsd is stupid about static global symbols, so don't have any
+// for debug builds
+//
+
+#if DBG == 1
+#define LOCAL
+#else // DBG == 1
+#define LOCAL static
+#endif // DBG == 1
+
+//////////////////////////////////////////////////////////////////////////////
+
+#define ARRAYLEN(a) (sizeof(a)/sizeof((a)[0]))
+
+//////////////////////////////////////////////////////////////////////////////
+
+//
+// Debugging flags
+//
+
+#define DEB_SEL DEB_USER1 // selection & focus information
+
+//
+// Debugging macros
+//
+
+#if DBG == 1 ////////////////////////////////////////////////////////
+ DECLARE_DEBUG(da)
+# define daDebugOut(x) daInlineDebugOut x
+# define daAssert(e) Win4Assert( e )
+#else // DBG == 1 ////////////////////////////////////////////////////////
+# define daDebugOut(x)
+# define daAssert(e)
+#endif // DBG == 1 ////////////////////////////////////////////////////////
+
+#endif // _DACOMMON_H_
diff --git a/private/utils/windisk/readme.txt b/private/utils/windisk/readme.txt
new file mode 100644
index 000000000..711ce2f70
--- /dev/null
+++ b/private/utils/windisk/readme.txt
@@ -0,0 +1,4 @@
+The source tree rooted here contains source to the Cairo Disk
+Administrator. To build this, you must:
+ be enlisted in the utils project, with at least utils\fmifs\inc
+ unghosted
diff --git a/private/utils/windisk/src/cdpage.cxx b/private/utils/windisk/src/cdpage.cxx
new file mode 100644
index 000000000..4c7a64202
--- /dev/null
+++ b/private/utils/windisk/src/cdpage.cxx
@@ -0,0 +1,348 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: cdpage.cxx
+//
+// Contents: Implementation of CD-ROM property page in Disk
+// Administrator applet
+//
+// History: 3-Mar-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include <controls.hxx>
+#include <util.hxx>
+
+#include "cdrom.hxx"
+#include "cdpage.hxx"
+#include "graph.hxx"
+#include "ops.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+VOID
+RefreshCdPageData(
+ IN HWND hdlg
+ );
+
+VOID
+SetChangeableData(
+ IN HWND hdlg,
+ IN PCDROM_DESCRIPTOR cdrom
+ );
+
+//////////////////////////////////////////////////////////////////////////////
+
+//+-------------------------------------------------------------------------
+//
+// Method: PAGE_DLGPROC
+//
+// Synopsis: Property page dialog procedure
+//
+//--------------------------------------------------------------------------
+
+BOOL CALLBACK
+PAGE_DLGPROC(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ PAGE_CLASS* pPropPage;
+
+ if (msg == WM_INITDIALOG)
+ {
+ pPropPage = new PAGE_CLASS(hwnd);
+ SetWindowLong(hwnd, GWL_USERDATA, (LPARAM)pPropPage);
+ }
+ else
+ {
+ pPropPage = (PAGE_CLASS*) GetWindowLong(hwnd, GWL_USERDATA);
+ }
+
+ if (pPropPage != NULL)
+ {
+ return (pPropPage->_DlgProc(hwnd, msg, wParam, lParam));
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+//+-------------------------------------------------------------------------
+//
+// Method: PAGE_CLASS::_DlgProc, private
+//
+// Synopsis: Dialog Procedure for the CD-ROM property page
+//
+// Arguments: standard Windows DlgProc
+//
+// Returns: standard Windows DlgProc
+//
+// History: 28-Jan-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+BOOL
+PAGE_CLASS::_DlgProc(
+ HWND hdlg,
+ UINT msg,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ return InitPage(hdlg, wParam, lParam);
+
+ case WM_COMMAND:
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDC_Refresh:
+ //
+ // Note that this "Refresh" option refreshes everything for a
+ // single CD-ROM (the one we're looking at), but nothing else. In
+ // particular, it doesn't refresh volume data.
+ //
+ RefreshCdPageData(hdlg);
+ return TRUE;
+ }
+
+ break;
+ }
+
+ case WM_NOTIFY:
+ {
+ NMHDR* phdr = (NMHDR*)lParam;
+
+ switch (phdr->code)
+ {
+ case PSN_SETACTIVE:
+ break;
+
+ case PSN_KILLACTIVE:
+ SetWindowLong(hdlg, DWL_MSGRESULT, FALSE); //ok to leave
+ break;
+
+ case PSN_QUERYCANCEL:
+ case PSN_RESET: // cancel
+ return FALSE;
+
+ case PSN_HELP:
+ NoHelp(hdlg);
+ return FALSE;
+
+ case PSN_APPLY:
+ SetWindowLong(hdlg, DWL_MSGRESULT, FALSE); // changes ok
+ return TRUE;
+
+ }
+
+ return FALSE;
+ }
+
+ case WM_CTLCOLORDLG:
+ case WM_CTLCOLORLISTBOX:
+ case WM_CTLCOLORSCROLLBAR:
+ case WM_CTLCOLORBTN:
+ case WM_CTLCOLORMSGBOX:
+ case WM_CTLCOLORSTATIC:
+ {
+ HDC hdc = (HDC)wParam;
+ SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
+ return (LRESULT)GetStockBrush(LTGRAY_BRUSH);
+ }
+
+ case WM_DESTROY:
+ DeleteFont(_hDlgFont);
+ SetWindowLong(hdlg, GWL_USERDATA, NULL);
+ delete this;
+ break;
+ }
+
+ return FALSE; // not processed
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Method: PAGE_CLASS::InitPage, private
+//
+// Synopsis: Initialize the data displayed on the CD-ROM property
+// page based on the current Disk Administrator selection
+//
+// Arguments: DlgProc stuff
+//
+// Returns: DlgProc stuff for WM_INITDIALOG
+//
+// History: 11-Oct-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+BOOL
+PAGE_CLASS::InitPage(
+ IN HWND hdlg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ static UINT s_idTextControls[] =
+ {
+ IDC_DriveStatus,
+ IDC_FileSystem,
+ IDC_DriveLetter,
+ IDC_GENL_Label,
+
+ IDC_GENL_1,
+ IDC_GENL_2,
+ IDC_GENL_3,
+ IDC_GENL_4,
+
+ 0
+ };
+
+ _hDlgFont = KillBold(hdlg, s_idTextControls);
+
+ PCDROM_DESCRIPTOR cdrom;
+
+ ULONG i;
+ for (i=0; i<CdRomCount; i++)
+ {
+ cdrom = CdRomFindDevice(i);
+
+ if (cdrom->Selected)
+ {
+ break;
+ }
+ }
+ // if we get out, it better be because we found the right device
+
+ //
+ // Set data that doesn't depend on drive status
+ //
+
+ //
+ // Set the "drive letter" static control
+ //
+
+ WCHAR driveName[3];
+ driveName[0] = cdrom->DriveLetter;
+ driveName[1] = L':';
+ driveName[2] = L'\0';
+ SetDlgItemText(hdlg, IDC_DriveLetter, driveName);
+
+ //
+ // Now set data that depends on drive status
+ //
+
+ SetChangeableData(hdlg, cdrom);
+
+ return TRUE; // didn't set focus to any control
+}
+
+
+VOID
+RefreshCdPageData(
+ IN HWND hdlg
+ )
+{
+ SetCursor(g_hCurWait);
+
+ PCDROM_DESCRIPTOR cdrom;
+
+ ULONG i;
+ for (i=0; i<CdRomCount; i++)
+ {
+ cdrom = CdRomFindDevice(i);
+
+ if (cdrom->Selected)
+ {
+ break; // this is it: only one CD-ROM can be selected
+ }
+ }
+ // if we get out, it better be because we found the right device
+
+ RefreshCdRomData(cdrom);
+ SetChangeableData(hdlg, cdrom);
+ RefreshBothViews(); // refresh the main view as well
+
+ SetCursor(g_hCurNormal);
+}
+
+
+VOID
+SetChangeableData(
+ IN HWND hdlg,
+ IN PCDROM_DESCRIPTOR cdrom
+ )
+{
+ WCHAR buffer[100];
+ HBITMAP hBigBitmap;
+
+ if (0 != lstrcmp(cdrom->TypeName, wszUnknown))
+ {
+ //
+ // Set drive status
+ //
+
+ //BUGBUG: status is always "ready"
+ LoadString(g_hInstance, IDS_READY, buffer, ARRAYLEN(buffer));
+ SetDlgItemText(hdlg, IDC_DriveStatus, buffer);
+
+ //
+ // Set drive label.
+ //
+
+ SetDlgItemText(hdlg, IDC_GENL_Label, cdrom->VolumeLabel);
+
+ //
+ // Set file system type
+ //
+
+ SetDlgItemText(hdlg, IDC_FileSystem, cdrom->TypeName);
+
+ hBigBitmap = CreateGraphBitmap(
+ g_hInstance,
+ GetDlgItem(hdlg, IDC_Graph),
+ DRIVE_CDROM,
+ STATUS_OK,
+ 1000); // assume full
+ }
+ else
+ {
+ LoadString(g_hInstance, IDS_NOTREADY, buffer, ARRAYLEN(buffer));
+ SetDlgItemText(hdlg, IDC_DriveStatus, buffer);
+
+ buffer[0] = L'\0';
+
+ SetDlgItemText(hdlg, IDC_GENL_Label, buffer);
+ SetDlgItemText(hdlg, IDC_FileSystem, buffer);
+
+ hBigBitmap = CreateGraphBitmap(
+ g_hInstance,
+ GetDlgItem(hdlg, IDC_Graph),
+ DRIVE_CDROM,
+ STATUS_OK, //BUGBUG
+ 1000); // assume full
+ }
+
+ //
+ // Set the graph
+ //
+
+ SendDlgItemMessage(
+ hdlg,
+ IDC_Graph,
+ BMPCTL_SETBITMAP,
+ (WPARAM)hBigBitmap,
+ 0);
+}
diff --git a/private/utils/windisk/src/cdpage.hxx b/private/utils/windisk/src/cdpage.hxx
new file mode 100644
index 000000000..5091d59b2
--- /dev/null
+++ b/private/utils/windisk/src/cdpage.hxx
@@ -0,0 +1,76 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: cdpage.hxx
+//
+// Contents: CD-ROM property page of volumes in
+// Disk Administrator applet
+//
+// History: 28-Jul-93 BruceFo Created from WilliamW's sharing applet
+//
+//--------------------------------------------------------------------------
+
+#ifndef __CDPAGE_HXX__
+#define __CDPAGE_HXX__
+
+#include "resids.h"
+#include "dialogs.h"
+
+#undef PAGE_DLGPROC
+#undef PAGE_CLASS
+
+#define PAGE_DLGPROC CdRomPageDlgProc
+#define PAGE_CLASS CCdRomPage
+
+class PAGE_CLASS
+{
+public:
+
+ PAGE_CLASS(
+ IN HWND hwndPage
+ )
+ :
+ _hwndPage(hwndPage),
+ _hDlgFont(NULL)
+ {
+ }
+
+ ~PAGE_CLASS()
+ {
+ }
+
+ BOOL
+ _DlgProc(
+ IN HWND hWnd,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+private:
+
+ friend BOOL CALLBACK
+ PAGE_DLGPROC(
+ HWND hWnd,
+ UINT msg,
+ WPARAM wParam,
+ LPARAM lParam);
+
+ BOOL
+ InitPage(
+ IN HWND hwnd,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+ //
+ // Data
+ //
+
+ HFONT _hDlgFont;
+ HWND _hwndPage;
+};
+
+#endif // __CDPAGE_HXX__
diff --git a/private/utils/windisk/src/cdr.bmp b/private/utils/windisk/src/cdr.bmp
new file mode 100644
index 000000000..006c498f4
--- /dev/null
+++ b/private/utils/windisk/src/cdr.bmp
Binary files differ
diff --git a/private/utils/windisk/src/cdrom.cxx b/private/utils/windisk/src/cdrom.cxx
new file mode 100644
index 000000000..16421588f
--- /dev/null
+++ b/private/utils/windisk/src/cdrom.cxx
@@ -0,0 +1,955 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: cdrom.cxx
+//
+// Contents: This module contains the set of routines that display and
+// control the drive letters for CdRom devices.
+//
+// History: 9-Dec-93 Bob Rinne Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include "cdrom.hxx"
+#include "dialogs.h"
+#include "drives.hxx"
+#include "help.hxx"
+#include "nt.hxx"
+#include "ntlow.hxx"
+
+
+WCHAR g_SourcePathLetter = L'\0';
+WCHAR g_SourcePathKeyName[80];
+WCHAR g_SourcePathValueName[30];
+
+
+PCDROM_DESCRIPTOR
+CdRomFindSelectedDevice(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Find the selected CD-ROM. There should only be one.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ Pointer to the correct structure, or NULL if it doesn't exist
+
+--*/
+
+{
+ FDASSERT(1 == CdRomSelectionCount);
+
+ ULONG i;
+
+ for (i = 0; i < CdRomCount; i++)
+ {
+ if (CdRomArray[i].Selected)
+ {
+ return &CdRomArray[i];
+ }
+ }
+
+ FDASSERT(FALSE);
+ return NULL;
+}
+
+
+
+
+PCDROM_DESCRIPTOR
+CdRomFindDevice(
+ IN ULONG CdRomNumber
+ )
+
+/*++
+
+Routine Description:
+
+ Find the correct CD-ROM
+
+Arguments:
+
+ CdRomNumber - the device number
+
+Return Value:
+
+ Pointer to the correct structure, or NULL if it doesn't exist
+
+--*/
+
+{
+ FDASSERT(0 <= CdRomNumber && CdRomNumber < CdRomCount);
+ return &CdRomArray[CdRomNumber];
+}
+
+
+
+ULONG
+CdRomFindDeviceNumber(
+ IN WCHAR DriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ Find the correct CD-ROM
+
+Arguments:
+
+ CdRomNumber - the device number
+
+Return Value:
+
+ Pointer to the correct structure, or NULL if it doesn't exist
+
+--*/
+
+{
+ FDASSERT(DriveLetter >= L'C' && DriveLetter <= L'Z');
+ ULONG i;
+
+ for (i = 0; i < CdRomCount; i++)
+ {
+ if (CdRomArray[i].DriveLetter == DriveLetter)
+ {
+ return i;
+ }
+ }
+
+ FDASSERT(FALSE);
+ return 0xffffffff;
+}
+
+
+PCDROM_DESCRIPTOR
+CdRomFindDriveLetter(
+ IN WCHAR DriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ Find the CD-ROM with the drive letter
+
+Arguments:
+
+ DriveLetter - the drive letter to find
+
+Return Value:
+
+ Pointer to the correct structure, or NULL if it doesn't exist
+
+--*/
+
+{
+ FDASSERT(DriveLetter >= L'C' && DriveLetter <= L'Z');
+ ULONG i;
+
+ for (i = 0; i < CdRomCount; i++)
+ {
+ if (CdRomArray[i].DriveLetter == DriveLetter)
+ {
+ return &CdRomArray[i];
+ }
+ }
+
+ FDASSERT(FALSE);
+ return NULL;
+}
+
+
+
+
+BOOL
+CdRomUsingDriveLetter(
+ IN WCHAR DriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ Determine if a CD-ROM device is using the drive letter
+
+Arguments:
+
+ DriveLetter - the drive letter to find
+
+Return Value:
+
+ TRUE if one is using the letter
+
+--*/
+
+{
+ FDASSERT(DriveLetter >= L'C' && DriveLetter <= L'Z');
+ ULONG i;
+
+ for (i = 0; i < CdRomCount; i++)
+ {
+ if (CdRomArray[i].DriveLetter == DriveLetter)
+ {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
+
+VOID
+CdRomChangeDriveLetter(
+ IN PCDROM_DESCRIPTOR Cdrom,
+ IN WCHAR NewDriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ Change a CD-ROM drive letter
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ DWORD action;
+ WCHAR deviceName[40];
+ WCHAR driveName[10];
+ OBJECT_ATTRIBUTES oa;
+ HANDLE handle;
+ NTSTATUS status;
+ IO_STATUS_BLOCK statusBlock;
+ UNICODE_STRING unicodeName;
+ UINT errorMode;
+
+ action = ConfirmationDialog(
+ MSG_DRIVE_RENAME_WARNING,
+ MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2);
+
+ if (action == IDNO)
+ {
+ return;
+ }
+
+ // Attempt to open and lock the cdrom.
+
+ wsprintf(deviceName, TEXT("\\Device\\CdRom%d"), Cdrom->DeviceNumber);
+
+ RtlInitUnicodeString(&unicodeName, deviceName);
+
+ memset(&oa, 0, sizeof(OBJECT_ATTRIBUTES));
+ oa.Length = sizeof(OBJECT_ATTRIBUTES);
+ oa.ObjectName = &unicodeName;
+ oa.Attributes = OBJ_CASE_INSENSITIVE;
+
+ errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+ status = NtOpenFile(&handle,
+ SYNCHRONIZE | FILE_READ_DATA,
+ &oa,
+ &statusBlock,
+ FILE_SHARE_READ,
+ FILE_SYNCHRONOUS_IO_ALERT);
+ SetErrorMode(errorMode);
+
+ if (!NT_SUCCESS(status))
+ {
+ ErrorDialog(MSG_CANNOT_LOCK_CDROM);
+ return;
+ }
+
+ // Lock the drive to insure that no other access is occurring
+ // to the volume. This is done via the "Low" routine for
+ // convenience
+
+ status = LowLockDrive(handle);
+
+ if (!NT_SUCCESS(status))
+ {
+ LowCloseDisk(handle);
+ ErrorDialog(MSG_CANNOT_LOCK_CDROM);
+ return;
+ }
+
+ // Before attempting to move the name, see if the letter
+ // is currently in use - could be a new network connection
+ // or a partition that is scheduled for deletion.
+
+ DWORD ec;
+ WCHAR dosName[MAX_PATH];
+ PWSTR linkTarget;
+
+ //
+ // No need to look if anyone is using the no-drive letter.
+ //
+
+ if (NewDriveLetter != NO_DRIVE_LETTER_EVER) {
+
+ wsprintfW(dosName, L"\\DosDevices\\%wc:", NewDriveLetter);
+ ec = GetDriveLetterLinkTarget(dosName, &linkTarget);
+ if (ec == NO_ERROR)
+ {
+ // Something is using this letter.
+
+ LowCloseDisk(handle);
+ ErrorDialog(MSG_CANNOT_MOVE_CDROM);
+ return;
+ }
+
+ }
+
+ //
+ // If it didn't used to have a letter, no point in trying
+ // to remove it.
+ //
+
+ if (Cdrom->DriveLetter != NO_DRIVE_LETTER_EVER) {
+
+ wsprintf(driveName, TEXT("%c:"), Cdrom->DriveLetter);
+ if (!DefineDosDevice(DDD_REMOVE_DEFINITION, driveName, NULL))
+ {
+ LowCloseDisk(handle);
+ ErrorDialog(MSG_CDROM_LETTER_ERROR);
+ return;
+ }
+
+ }
+
+ status = DiskRegistryAssignCdRomLetter(
+ Cdrom->DeviceName,
+ NewDriveLetter);
+
+ if (Cdrom->DriveLetter != NO_DRIVE_LETTER_EVER) {
+
+ MarkDriveLetterFree(Cdrom->DriveLetter);
+
+ // See if this was the device used to install NT
+
+ if (L'\0' != g_SourcePathLetter)
+ {
+ if (g_SourcePathLetter == Cdrom->DriveLetter)
+ {
+ LONG error;
+ HKEY keyHandle;
+ DWORD valueType;
+ ULONG size;
+ PWSTR string;
+
+ // Update the source path
+
+ error = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ g_SourcePathKeyName,
+ 0,
+ KEY_ALL_ACCESS,
+ &keyHandle);
+ if (error == NO_ERROR)
+ {
+ error = RegQueryValueEx(keyHandle,
+ g_SourcePathValueName,
+ NULL,
+ &valueType,
+ NULL,
+ &size);
+ if (error == NO_ERROR)
+ {
+ string = (PWSTR) LocalAlloc(LMEM_FIXED, size);
+ if (NULL != string)
+ {
+ error = RegQueryValueEx(keyHandle,
+ g_SourcePathValueName,
+ NULL,
+ &valueType,
+ (LPBYTE)string,
+ &size);
+ if (error == NO_ERROR)
+ {
+ *string = g_SourcePathLetter = NewDriveLetter;
+ RegSetValueEx(keyHandle,
+ g_SourcePathValueName,
+ 0,
+ REG_SZ,
+ (LPBYTE)string,
+ size);
+ }
+ }
+ LocalFree(string);
+ }
+ RegCloseKey(keyHandle);
+ }
+ }
+ }
+ }
+
+ // set up new device letter - name is already set up, take care not to
+ // assign the no drive letter.
+
+ if (NewDriveLetter != NO_DRIVE_LETTER_EVER) {
+
+ wsprintf(driveName, TEXT("%c:"), NewDriveLetter);
+ if (DefineDosDevice(DDD_RAW_TARGET_PATH, driveName, deviceName))
+ {
+ Cdrom->DriveLetter = NewDriveLetter;
+ MarkDriveLetterUsed(Cdrom->DriveLetter);
+ }
+ else
+ {
+ RegistryChanged = TRUE;
+ }
+ } else {
+
+ Cdrom->DriveLetter = NO_DRIVE_LETTER_EVER;
+
+ }
+ LowCloseDisk(handle);
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: InitializeCdRomInfo
+//
+// Synopsis: Initialize all information about CD-ROMs
+//
+// Arguments: (none)
+//
+// Returns: TRUE on success, FALSE on failure
+//
+// History: 2-Mar-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+BOOL
+InitializeCdRomInfo(
+ VOID
+ )
+{
+ WCHAR driveLetter;
+ PWSTR linkTarget;
+ WCHAR dosDevicesName[sizeof(L"\\DosDevices\\A:")];
+ DWORD ec;
+ ULONG count;
+ PCDROM_DESCRIPTOR cdrom;
+ LONG error;
+ DWORD valueType;
+ HKEY keyHandle;
+ ULONG size;
+ PWSTR string;
+
+ //
+ // Get the CD-ROM source path
+ //
+
+ LoadString(g_hInstance,
+ IDS_SOURCE_PATH,
+ g_SourcePathKeyName,
+ ARRAYLEN(g_SourcePathKeyName));
+ LoadString(g_hInstance,
+ IDS_SOURCE_PATH_NAME,
+ g_SourcePathValueName,
+ ARRAYLEN(g_SourcePathValueName));
+
+ error = RegOpenKey(HKEY_LOCAL_MACHINE, g_SourcePathKeyName, &keyHandle);
+ if (error == NO_ERROR)
+ {
+ error = RegQueryValueEx(keyHandle,
+ g_SourcePathValueName,
+ NULL,
+ &valueType,
+ NULL,
+ &size);
+ if (error == NO_ERROR)
+ {
+ string = (PWSTR) LocalAlloc(LMEM_FIXED, size);
+ if (NULL != string)
+ {
+ error = RegQueryValueEx(keyHandle,
+ g_SourcePathValueName,
+ NULL,
+ &valueType,
+ (LPBYTE)string,
+ &size);
+ if (error == NO_ERROR)
+ {
+ g_SourcePathLetter = *string;
+ }
+ }
+ LocalFree(string);
+ }
+ RegCloseKey(keyHandle);
+ }
+
+ //
+ // First, count how many CD-ROM devices there are
+ //
+
+ wsprintf(dosDevicesName, L"\\DosDevices\\A:");
+
+ CdRomCount = 0;
+
+ {
+
+ NTSTATUS ntStatus;
+ SYSTEM_DEVICE_INFORMATION deviceInformationData;
+
+ ntStatus = NtQuerySystemInformation(
+ SystemDeviceInformation,
+ &deviceInformationData,
+ sizeof(SYSTEM_DEVICE_INFORMATION),
+ NULL
+ );
+
+ if (NT_SUCCESS(ntStatus)) {
+
+ CdRomCount = deviceInformationData.NumberOfCdRoms;
+
+ }
+
+ }
+
+ if (0 == CdRomCount)
+ {
+ return TRUE;
+ }
+
+ g_AllowCdRom = TRUE;
+
+ //
+ // First we find all the cd rom devices that have an actual drive
+ // letter. Afterwards, we will look for those that have have
+ // no letter.
+ //
+
+ CdRomArray = (PCDROM_DESCRIPTOR)Malloc(CdRomCount * sizeof(CDROM_DESCRIPTOR));
+
+ count = 0;
+ for (driveLetter = L'C'; driveLetter <= L'Z'; driveLetter++)
+ {
+ dosDevicesName[12] = driveLetter;
+
+ if ((ec = GetDriveLetterLinkTarget(dosDevicesName, &linkTarget)) == NO_ERROR)
+ {
+ if (_wcsnicmp(linkTarget, L"\\Device\\CdRom", 13) == 0)
+ {
+ cdrom = &CdRomArray[count];
+
+ cdrom->DeviceName = (PWSTR)Malloc((lstrlen(linkTarget)+1) * sizeof(WCHAR));
+ lstrcpy(cdrom->DeviceName, linkTarget);
+
+ //
+ // Get the device number
+ //
+
+ PWCHAR cp;
+
+ cp = cdrom->DeviceName;
+ while (*cp)
+ {
+ if (iswdigit(*cp))
+ {
+ break;
+ }
+ cp++;
+ }
+
+ if (*cp)
+ {
+ cdrom->DeviceNumber = wcstoul(cp, NULL, 10);
+ }
+ else
+ {
+ // error: no device number! Don't add this one
+ Free(cdrom->DeviceName);
+ --CdRomCount;
+ continue;
+ }
+
+ cdrom->hDCMem = NULL;
+ cdrom->hbmMem = NULL;
+ cdrom->Selected = FALSE;
+ cdrom->LeftRight.Left = 0;
+ cdrom->LeftRight.Right = 0;
+ cdrom->DriveLetter = driveLetter;
+
+ cdrom->VolumeLabel = NULL;
+ cdrom->TypeName = NULL;
+
+ RefreshCdRomData(cdrom);
+
+ ++count;
+ }
+ }
+ }
+
+ //
+ // if the count is equal to the number of cdroms in the system
+ // then the're aren't any without a drive letter.
+ //
+ // Keep going until we found all of the Cdroms.
+ //
+
+ DWORD potentialDeviceNumber;
+ WCHAR ntDeviceName[MAX_PATH];
+ UNICODE_STRING ntDeviceNameString;
+
+
+ potentialDeviceNumber = 0;
+ for (
+ potentialDeviceNumber = 0;
+ count != CdRomCount;
+ potentialDeviceNumber++
+ ) {
+
+ DWORD i;
+ HANDLE ntDeviceHandle;
+ OBJECT_ATTRIBUTES deviceObjectAttributes;
+ NTSTATUS openStatus;
+ IO_STATUS_BLOCK ioStatusBlock;
+
+ //
+ // BUG BUG This is very piggish. Look to see if the potential
+ // cdrom device "number" is already in the list of devices we
+ // know about. If it is, go on to the next one.
+ //
+ //
+
+ for (
+ i = 0;
+ i < count;
+ i++
+ ) {
+
+ if (potentialDeviceNumber == CdRomArray[i].DeviceNumber) {
+
+ goto bottomOfPotential;
+
+ }
+
+ }
+
+ //
+ // Form a name based on the number
+ //
+
+ wsprintf(ntDeviceName,L"\\Device\\CdRom%d",potentialDeviceNumber);
+ RtlInitUnicodeString(
+ &ntDeviceNameString,
+ &ntDeviceName[0]
+ );
+
+ InitializeObjectAttributes(
+ &deviceObjectAttributes,
+ &ntDeviceNameString,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+ //
+ // See if it's there.
+ //
+
+ openStatus = NtOpenFile(
+ &ntDeviceHandle,
+ (ACCESS_MASK)SYNCHRONIZE,
+ &deviceObjectAttributes,
+ &ioStatusBlock,
+ FILE_SHARE_READ,
+ 0UL
+ );
+ if ( !NT_SUCCESS(openStatus) ) {
+
+ continue;
+
+ }
+
+ //
+ // We have the device open. Close it right away. Fill
+ // in the cd rom structure. The refresh cdrom code will
+ // know how do deal with a cdrom with no drive letter.
+ // size
+ //
+
+ NtClose(ntDeviceHandle);
+
+ cdrom = &CdRomArray[count];
+
+ cdrom->DeviceName = (PWSTR)Malloc((ntDeviceNameString.Length+1) * sizeof(WCHAR));
+ lstrcpy(cdrom->DeviceName, ntDeviceNameString.Buffer);
+
+ cdrom->DeviceNumber = potentialDeviceNumber;
+ cdrom->hDCMem = NULL;
+ cdrom->hbmMem = NULL;
+ cdrom->Selected = FALSE;
+ cdrom->LeftRight.Left = 0;
+ cdrom->LeftRight.Right = 0;
+ cdrom->DriveLetter = NO_DRIVE_LETTER_EVER;
+
+ cdrom->VolumeLabel = NULL;
+ cdrom->TypeName = NULL;
+
+ RefreshCdRomData(cdrom);
+
+ ++count;
+
+bottomOfPotential:;
+
+ }
+
+
+ return TRUE;
+}
+
+
+VOID
+RefreshCdRomData(
+ PCDROM_DESCRIPTOR Cdrom
+ )
+{
+ WCHAR rootPath[4];
+ rootPath[0] = Cdrom->DriveLetter;
+ rootPath[1] = L':';
+ rootPath[2] = L'\\';
+ rootPath[3] = L'\0';
+
+ WCHAR volumeLabel[100];
+ WCHAR typeName[100];
+
+ // Free old stuff first
+
+ if (NULL != Cdrom->VolumeLabel)
+ {
+ Free(Cdrom->VolumeLabel);
+ }
+
+ if (NULL != Cdrom->TypeName)
+ {
+ Free(Cdrom->TypeName);
+ }
+
+ Cdrom->TotalSpaceInMB = 0;
+ Cdrom->TypeName = NULL;
+ Cdrom->VolumeLabel = NULL;
+
+ UINT errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+
+ HANDLE ntDeviceHandle;
+ OBJECT_ATTRIBUTES deviceObjectAttributes;
+ UNICODE_STRING ntDeviceNameString;
+ NTSTATUS ioStatus;
+ IO_STATUS_BLOCK ioStatusBlock;
+ FILE_FS_SIZE_INFORMATION sizeInformation;
+ PFILE_FS_ATTRIBUTE_INFORMATION attributeInformation;
+ PFILE_FS_VOLUME_INFORMATION volumeInformation;
+ DWORD volumeInformationLength;
+ DWORD attributeInformationLength;
+
+
+ //
+ // Allocate two strings. The first to hold the file system name. The
+ // second to hold the volume name. After we get them both back we will
+ // allocate new memory just big enough to hold them.
+ //
+
+ attributeInformationLength = sizeof(FILE_FS_ATTRIBUTE_INFORMATION) +
+ ((MAX_PATH+1)*sizeof(WCHAR));
+ volumeInformationLength = sizeof(FILE_FS_VOLUME_INFORMATION) +
+ ((MAX_PATH+1)*sizeof(WCHAR));
+
+ attributeInformation = (PFILE_FS_ATTRIBUTE_INFORMATION)Malloc(attributeInformationLength);
+
+ if (!attributeInformation) {
+
+ SetErrorMode(errorMode);
+ return;
+
+ }
+
+ volumeInformation = (PFILE_FS_VOLUME_INFORMATION)Malloc(volumeInformationLength);
+
+ if (!volumeInformation) {
+
+ Free(attributeInformation);
+ SetErrorMode(errorMode);
+ return;
+
+ }
+
+
+ RtlInitUnicodeString(
+ &ntDeviceNameString,
+ Cdrom->DeviceName
+ );
+
+ InitializeObjectAttributes(
+ &deviceObjectAttributes,
+ &ntDeviceNameString,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL
+ );
+
+ //
+ // Open the file
+ //
+
+ ioStatus = NtOpenFile(
+ &ntDeviceHandle,
+ (ACCESS_MASK)FILE_LIST_DIRECTORY | SYNCHRONIZE,
+ &deviceObjectAttributes,
+ &ioStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE
+ );
+
+ if ( !NT_SUCCESS(ioStatus) ) {
+
+ Free(attributeInformation);
+ Free(volumeInformation);
+ SetErrorMode(errorMode);
+ return;
+
+ }
+
+ //
+ // Try to get the volume label
+ //
+
+ ioStatus = NtQueryVolumeInformationFile(
+ ntDeviceHandle,
+ &ioStatusBlock,
+ volumeInformation,
+ volumeInformationLength,
+ FileFsVolumeInformation
+ );
+
+ if (NT_SUCCESS(ioStatus)) {
+
+
+ Cdrom->VolumeLabel = (PWCHAR)Malloc(volumeInformation->VolumeLabelLength
+ + sizeof(WCHAR));
+ if (Cdrom->VolumeLabel) {
+
+ RtlZeroMemory(
+ Cdrom->VolumeLabel,
+ volumeInformation->VolumeLabelLength+sizeof(WCHAR)
+ );
+ RtlMoveMemory(
+ Cdrom->VolumeLabel,
+ volumeInformation->VolumeLabel,
+ volumeInformation->VolumeLabelLength
+ );
+
+
+ }
+
+ }
+
+ Free(volumeInformation);
+
+ ioStatus = NtQueryVolumeInformationFile(
+ ntDeviceHandle,
+ &ioStatusBlock,
+ attributeInformation,
+ attributeInformationLength,
+ FileFsAttributeInformation
+ );
+
+ if (NT_SUCCESS(ioStatus)) {
+
+ Cdrom->TypeName = (PWCHAR)Malloc(attributeInformation->FileSystemNameLength
+ + sizeof(WCHAR));
+
+ if (Cdrom->TypeName) {
+
+ RtlZeroMemory(
+ Cdrom->TypeName,
+ attributeInformation->FileSystemNameLength+
+ sizeof(WCHAR)
+ );
+ RtlMoveMemory(
+ Cdrom->TypeName,
+ attributeInformation->FileSystemName,
+ attributeInformation->FileSystemNameLength
+ );
+
+ }
+
+ }
+
+ Free(attributeInformation);
+
+ //
+ // Determine the size parameters of the volume.
+ //
+
+ ioStatus = NtQueryVolumeInformationFile(
+ ntDeviceHandle,
+ &ioStatusBlock,
+ &sizeInformation,
+ sizeof(sizeInformation),
+ FileFsSizeInformation
+ );
+ NtClose(ntDeviceHandle);
+ SetErrorMode(errorMode);
+ if ( !NT_SUCCESS(ioStatus) ) {
+
+ Cdrom->TotalSpaceInMB = 0;
+
+ } else {
+
+ LONGLONG temp;
+
+ if (sizeInformation.TotalAllocationUnits.HighPart) {
+ sizeInformation.TotalAllocationUnits.LowPart = (ULONG)-1;
+ }
+ temp = UInt32x32To64(
+ sizeInformation.TotalAllocationUnits.LowPart,
+ sizeInformation.SectorsPerAllocationUnit
+ );
+
+ temp *= sizeInformation.BytesPerSector;
+ temp /= (1024*1024);
+ Cdrom->TotalSpaceInMB = (ULONG)temp;
+
+ }
+}
+
+
+VOID
+RefreshAllCdRomData(
+ VOID
+ )
+{
+ PCDROM_DESCRIPTOR cdrom;
+ ULONG i;
+ for (i=0; i<CdRomCount; i++)
+ {
+ cdrom = CdRomFindDevice(i);
+ RefreshCdRomData(cdrom);
+ }
+}
diff --git a/private/utils/windisk/src/cdrom.hxx b/private/utils/windisk/src/cdrom.hxx
new file mode 100644
index 000000000..3065416c4
--- /dev/null
+++ b/private/utils/windisk/src/cdrom.hxx
@@ -0,0 +1,65 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: cdrom.hxx
+//
+// Contents: Declarations for CD-ROM support
+//
+// History: 9-Dec-93 Bob Rinne Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __CDROM_HXX__
+#define __CDROM_HXX__
+
+//////////////////////////////////////////////////////////////////////////////
+
+PCDROM_DESCRIPTOR
+CdRomFindSelectedDevice(
+ VOID
+ );
+
+PCDROM_DESCRIPTOR
+CdRomFindDevice(
+ IN ULONG CdRomNumber
+ );
+
+ULONG
+CdRomFindDeviceNumber(
+ IN WCHAR DriveLetter
+ );
+
+PCDROM_DESCRIPTOR
+CdRomFindDriveLetter(
+ IN WCHAR DriveLetter
+ );
+
+BOOL
+CdRomUsingDriveLetter(
+ IN WCHAR DriveLetter
+ );
+
+VOID
+CdRomChangeDriveLetter(
+ IN PCDROM_DESCRIPTOR Cdrom,
+ IN WCHAR NewDriveLetter
+ );
+
+BOOL
+InitializeCdRomInfo(
+ VOID
+ );
+
+VOID
+RefreshCdRomData(
+ PCDROM_DESCRIPTOR Cdrom
+ );
+
+VOID
+RefreshAllCdRomData(
+ VOID
+ );
+
+#endif // __CDROM_HXX__
diff --git a/private/utils/windisk/src/chkdsk.cxx b/private/utils/windisk/src/chkdsk.cxx
new file mode 100644
index 000000000..897acd4bd
--- /dev/null
+++ b/private/utils/windisk/src/chkdsk.cxx
@@ -0,0 +1,2050 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: chkdsk.cxx
+//
+// Contents: Disk Administrator file system extension class. Chkdsk.
+//
+// History: 2-Jul-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include <util.hxx>
+
+#include "resids.h"
+#include "dialogs.h"
+#include "fs.hxx"
+#include "print.hxx"
+#include "fmifs.hxx"
+#include "chkdsk.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+#define CHK_PROGRESSUPDATE (WM_USER + 0)
+#define CHK_PROGRESSEND (WM_USER + 1)
+#define CHK_PROGRESSCANCEL (WM_USER + 2)
+#define CHK_PROGRESSUNCANCEL (WM_USER + 3)
+#define CHK_PROGRESSTITLE (WM_USER + 4)
+
+#define MIN_TIME_DELTA 100
+
+#define MESSAGE_CHUNK 512
+
+#define MAX_PATH 260
+#define MAX_FILTER 100
+
+//////////////////////////////////////////////////////////////////////////////
+
+// Fix:
+// if IDC_CHKDSK_DontFix, then no flags
+// if IDC_CHKDSK_Fix, then /F
+// if IDC_CHKDSK_FixAll, then /R
+
+#define CHKDSK_SLASH_F(x) ( ((x)==IDC_CHKDSK_Fix) || ((x)==IDC_CHKDSK_FixAll) )
+#define CHKDSK_SLASH_R(x) ((x) == IDC_CHKDSK_FixAll)
+
+typedef struct _CHKDSK_PARAMS
+{
+ //
+ // 'hWorkerThread' is the thread handle of the worker thread. This is used
+ // for synchronization: we wait on it when waiting for it to exit.
+ //
+
+ HANDLE hWorkerThread;
+
+ //
+ // 'AllowCancel' is set by the chkdsk invoker to indicate whether
+ // cancelling the operation is allowed.
+ //
+
+ BOOL AllowCancel;
+
+ //
+ // 'Cancel' is set by the UI thread to indicate the user has chosen
+ // to cancel the operation.
+ //
+
+ BOOL Cancel;
+
+ //
+ // 'Cancelled' is set by the worker thread to indicate a cancel
+ // is in progress, and to ignore all future callback messages.
+ //
+
+ BOOL Cancelled;
+
+ //
+ // 'Final' is set by the worker thread to indicate the a "final"
+ // message has been received. "Final" messages are displayed in a
+ // message box. All other messages are discarded.
+ //
+
+ BOOL Final;
+
+ //
+ // Window handles set by UI thread and used by both UI and chkdsk
+ // threads. The chkdsk thread uses hDlg to send messages; thus the
+ // Windows message queue is used as an IPC mechanism.
+ //
+
+ HWND hwndParent;
+ HWND hDlg; // handle to progress dialog
+
+ //
+ // Volume info used by the Chkdsk dialog box
+ //
+
+ WCHAR Label[MAXLABELLEN];
+
+ //
+ // IN parameters set by the UI thread for use by the chkdsk routine
+ //
+
+ BOOL noPercentDone; // TRUE if the file system doesn't support %done
+ FILE_SYSTEM FileSys;
+ PWSTR FileSystem;
+ PWSTR DriveName;
+
+ //
+ // OUT parameters set by the chkdsk callback routine
+ //
+
+ BOOL fmifsSuccess;
+ UINT Fix;
+ UINT Result;
+
+ PSTR Messages; // all the messages concatenated
+ UINT NumMessageChunks; // # of MESSAGE_CHUNKs allocated
+ UINT NumCharacters; // # characters in the buffer
+
+ //
+ // Parameters specific to a file system, set prior to calling
+ // chkdsk, and used by the callback routine
+ //
+
+ //
+ // The last time a %done message was seen. If < 1/10 second, then
+ // we ignore it (unless it is 0% or 100%). This avoids overloading
+ // the %done thermometer.
+ //
+
+ DWORD lasttime;
+
+} CHKDSK_PARAMS, *PCHKDSK_PARAMS;
+
+//////////////////////////////////////////////////////////////////////////////
+
+LOCAL PCHKDSK_PARAMS ParamsForChkdskCallBack;
+
+LOCAL WCHAR szMessageWindowClass[] = TEXT("MessageWindow");
+
+//////////////////////////////////////////////////////////////////////////////
+
+DWORD
+GetTime(
+ VOID
+ );
+
+BOOL CALLBACK
+StopChkDlgProc(
+ IN HWND hDlg,
+ IN UINT uMsg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+UINT
+GetFileFilterString(
+ OUT PWSTR szFilter,
+ IN INT cchFilter
+ );
+
+BOOL
+GetSaveName(
+ IN HWND hwndOwner,
+ OUT PWSTR pszFile,
+ IN UINT nMaxFile
+ );
+
+VOID
+SaveResults(
+ IN HWND hwndOwner,
+ IN PCHKDSK_PARAMS chkdskParams
+ );
+
+VOID
+PrintResults(
+ IN HWND hwndOwner,
+ IN PCHKDSK_PARAMS chkdskParams
+ );
+
+LOCAL LRESULT CALLBACK
+MessageWndProc(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+VOID
+OnFinalMessage(
+ IN HWND hwndOwner,
+ IN PSTR Message
+ );
+
+LOCAL BOOLEAN
+ChkdskCallback(
+ IN FMIFS_PACKET_TYPE PacketType,
+ IN DWORD PacketLength,
+ IN PVOID PacketData
+ );
+
+LOCAL DWORD WINAPI
+ChkdskVolume(
+ IN LPVOID ThreadParameter
+ );
+
+VOID
+SetChkdskProgressTitle(
+ IN HWND hDlg,
+ IN PCHKDSK_PARAMS chkdskParams
+ );
+
+LOCAL BOOL CALLBACK
+ChkdskProgressDlgProc(
+ IN HWND hDlg,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+int
+FindCheckedRadioButton(
+ HWND hDlg,
+ int wIdFirst,
+ int wIdLast
+ );
+
+LOCAL BOOL CALLBACK
+ChkdskDlgProc(
+ IN HWND hDlg,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: GetTime
+//
+// Synopsis: Returns a time value in milliseconds that wraps
+// approximately every minute.
+//
+// Arguments: none
+//
+// Returns: an integer time that increases every millisecond
+//
+// History: 10-Jan-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+DWORD
+GetTime(
+ VOID
+ )
+{
+ SYSTEMTIME st;
+
+ GetSystemTime(&st);
+ return MIN_TIME_DELTA + (st.wSecond * 1000) + st.wMilliseconds;
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: StopChkDlgProc, private
+//
+// Synopsis: Dialog procedure for the modal "Stop Formatting" dialog
+//
+// Arguments: standard Windows dialog procedure
+//
+// Returns: standard Windows dialog procedure
+//
+// History: 7-Jan-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+BOOL CALLBACK
+StopChkDlgProc(
+ IN HWND hDlg,
+ IN UINT uMsg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ UNREFERENCED_PARM(lParam);
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ //
+ // Set the text
+ //
+
+ TCHAR text[300];
+
+ RetrieveAndFormatMessage(
+ MSG_CHK_CANCELMESSAGE,
+ text,
+ ARRAYLEN(text),
+ NULL
+ );
+
+ SetDlgItemText(hDlg, IDC_StopChk_Text, text);
+
+ SetFocus(GetDlgItem(hDlg, IDC_StopChk_Continue));
+
+ return 0; // called SetFocus
+ }
+
+ case WM_COMMAND:
+
+ switch (GET_WM_COMMAND_ID(wParam, lParam))
+ {
+ case IDC_StopChk_Stop:
+ EndDialog(hDlg, TRUE);
+ break;
+
+ case IDC_StopChk_Continue:
+ EndDialog(hDlg, FALSE);
+ break;
+
+ case IDHELP:
+ Unimplemented(hDlg);
+ break;
+ }
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+}
+
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+//
+// Code for the thread handling the error message window
+//
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+//+---------------------------------------------------------------------------
+//
+// Function: RegisterMessageWindowClass
+//
+// Synopsis: Registers the window classes used by menu feedback code
+//
+// Arguments: (none)
+//
+// Returns: TRUE on success, FALSE on failure
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+BOOL
+RegisterMessageWindowClass(
+ VOID
+ )
+{
+ WNDCLASS wc;
+
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.lpfnWndProc = MessageWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = DLGWINDOWEXTRA;
+ wc.hInstance = g_hInstance;
+ wc.hIcon = NULL;
+ wc.hCursor = LoadCursor(NULL,IDC_ARROW);
+ wc.hbrBackground = GetStockBrush(LTGRAY_BRUSH);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = szMessageWindowClass;
+
+ return (0 != RegisterClass(&wc));
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: GetFileFilterString
+//
+// Synopsis: Gets the filter string to use with the common save
+// dialog from the resource file, and massages it into the
+// correct form.
+//
+// Arguments: [szFilter] -- where the string is put
+// [cchFilter] -- number of characters in the buffer.
+//
+// Returns: size of loaded string, or 0 on failure
+//
+// History: 8-Dec-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+UINT
+GetFileFilterString(
+ OUT PWSTR szFilter,
+ IN INT cchFilter
+ )
+{
+ UINT i, cchString;
+ WCHAR wcReplace;
+
+ if (0 == (cchString =
+ LoadString(g_hInstance, IDS_CHK_FILTERSTRING, szFilter, cchFilter)))
+ {
+ return 0;
+ }
+
+ wcReplace = szFilter[cchString - 1];
+ for (i=0; szFilter[i] != TEXT('\0'); i++)
+ {
+ if (szFilter[i] == wcReplace)
+ {
+ szFilter[i] = TEXT('\0');
+ }
+ }
+ return cchString;
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: GetSaveName
+//
+// Synopsis: Calls the common "Save As" dialog to get a filename for
+// the log file.
+//
+// Arguments: [hwndOwner] -- handle to parent window
+// [pszFile] -- the filename that is retrieved
+// [nMaxFile] -- maximum size of file name
+//
+// Returns: TRUE on success, FALSE on failure
+//
+// History: 8-Dec-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+BOOL
+GetSaveName(
+ IN HWND hwndOwner,
+ OUT PWSTR pszFile,
+ IN UINT nMaxFile
+ )
+{
+ OPENFILENAME ofn = {0};
+ WCHAR szFilter[MAX_FILTER];
+
+ if (0 == GetFileFilterString(szFilter, ARRAYLEN(szFilter)))
+ {
+ return FALSE;
+ }
+
+ WCHAR WindowsDir[MAX_PATH];
+ GetWindowsDirectory(WindowsDir, ARRAYLEN(WindowsDir));
+
+ ofn.lStructSize = sizeof(OPENFILENAME);
+ ofn.hwndOwner = hwndOwner;
+ ofn.lpstrFilter = szFilter;
+ ofn.lpstrFile = pszFile;
+ ofn.nMaxFile = nMaxFile;
+ ofn.lpstrFileTitle = NULL;
+ ofn.nMaxFileTitle = 0;
+ ofn.lpstrInitialDir = WindowsDir;
+ ofn.Flags = OFN_PATHMUSTEXIST
+ | OFN_HIDEREADONLY
+ | OFN_OVERWRITEPROMPT;
+
+ return GetSaveFileName(&ofn);
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: SaveResults
+//
+// Synopsis: Saves the results of a chkdsk to a file: gets a filename
+// to use, then writes out the data.
+//
+// Arguments: [hwndOwner] -- handle to owner window
+// [chkdskParams] -- various chkdsk parameters, including
+// a pointer to the results strings
+//
+// Returns: nothing
+//
+// History: 8-Dec-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+SaveResults(
+ IN HWND hwndOwner,
+ IN PCHKDSK_PARAMS chkdskParams
+ )
+{
+ WCHAR szFile[MAX_PATH];
+ WCHAR filenameProto[MAX_PATH];
+
+ LoadString(
+ g_hInstance,
+ IDS_CHK_DONE_FILENAME,
+ filenameProto,
+ ARRAYLEN(filenameProto));
+
+ wsprintf(szFile, filenameProto, *(chkdskParams->DriveName));
+
+ if (GetSaveName(hwndOwner, szFile, ARRAYLEN(szFile)))
+ {
+ //
+ // user chose to save, so do it:
+ //
+ // 1. open the file
+ // 2. write it out
+ // 3. close the file
+ //
+
+ HANDLE hFile = CreateFile(
+ szFile,
+ GENERIC_WRITE,
+ 0, // prevent sharing
+ NULL, // default security
+ CREATE_ALWAYS, // overwrite old files
+ FILE_ATTRIBUTE_NORMAL,
+ NULL // no template file
+ );
+
+ if (INVALID_HANDLE_VALUE != hFile)
+ {
+ DWORD NumberOfBytesWritten;
+
+ CHAR HeaderProto[256];
+ CHAR Header[256];
+
+ LoadStringA(
+ g_hInstance,
+ IDS_CHK_DONE_FILE_HEADER,
+ HeaderProto,
+ ARRAYLEN(HeaderProto));
+
+ wsprintfA(Header, HeaderProto, chkdskParams->DriveName);
+
+ if (!WriteFile(
+ hFile,
+ Header,
+ lstrlenA(Header) * sizeof(CHAR),
+ &NumberOfBytesWritten,
+ NULL // not overlapped I/O
+ )
+ || !WriteFile(
+ hFile,
+ chkdskParams->Messages,
+ (chkdskParams->NumCharacters - 1) * sizeof(CHAR),
+ &NumberOfBytesWritten,
+ NULL // not overlapped I/O
+ ))
+ {
+ MyMessageBox(
+ g_hInstance,
+ hwndOwner,
+ IDS_CHK_SAVE_ERROR_NOWRITE,
+ IDS_CHK_SAVE_ERROR_TITLE,
+ MB_ICONINFORMATION | MB_OK
+ );
+ }
+
+ CloseHandle(hFile);
+ }
+ else
+ {
+ daDebugOut((DEB_IERROR,"CreateFile failed!\n"));
+
+ MyMessageBox(
+ g_hInstance,
+ hwndOwner,
+ IDS_CHK_SAVE_ERROR_NOFILE,
+ IDS_CHK_SAVE_ERROR_TITLE,
+ MB_ICONEXCLAMATION | MB_OK
+ );
+ }
+ }
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: PrintResults
+//
+// Synopsis: Prints the results of a chkdsk to a printer
+//
+// Arguments: [hwndOwner] -- handle to owner window
+// [chkdskParams] -- various chkdsk parameters, including
+// a pointer to the results strings
+//
+// Returns: nothing
+//
+// History: 8-Dec-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+PrintResults(
+ IN HWND hwndOwner,
+ IN PCHKDSK_PARAMS chkdskParams
+ )
+{
+ PrintString(hwndOwner, chkdskParams->Messages);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: MessageWndProc
+//
+// Synopsis: Window procedure for the chkdsk summary info dialog box.
+// This is a resizable modal dialog box. Thus, the dialog
+// template has an associated window class which specifies
+// this procedure as the window procedure.
+//
+// Arguments: standard Windows procedure
+//
+// Returns: standard Windows procedure
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+LOCAL LRESULT CALLBACK
+MessageWndProc(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ static HBRUSH hbrStaticBrush;
+ static PCHKDSK_PARAMS chkdskParams;
+ static BOOL EverythingCreated;
+ static HFONT hFontText;
+
+ switch (msg)
+ {
+ case WM_CREATE:
+ {
+ // hide the window until all the controls are created and
+ // correctly placed
+ ShowWindow(hwnd, FALSE);
+
+ chkdskParams = ParamsForChkdskCallBack;
+ hbrStaticBrush = CreateSolidBrush(GetSysColor(COLOR_3DFACE));
+ EverythingCreated = FALSE;
+
+ HMENU hmenuSystem = GetSystemMenu(hwnd, FALSE);
+ EnableMenuItem(hmenuSystem, SC_MINIMIZE, MF_BYCOMMAND | MF_DISABLED);
+ EnableMenuItem(hmenuSystem, SC_CLOSE, MF_BYCOMMAND | MF_DISABLED);
+ EnableMenuItem(hmenuSystem, SC_TASKLIST, MF_BYCOMMAND | MF_DISABLED);
+
+ return 0;
+ }
+
+ case WM_ACTIVATE:
+ {
+ //
+ // when we get the WM_CREATE, the controls haven't been created.
+ // So, this just happens to be a reasonable place to hook in after
+ // the controls have been created.
+ //
+
+ if (!EverythingCreated)
+ {
+ EverythingCreated = TRUE;
+
+ TCHAR titleText[MAX_RESOURCE_STRING_LEN];
+
+ LoadString(
+ g_hInstance,
+ (chkdskParams->Fix == IDC_CHKDSK_DontFix)
+ ? IDS_CHK_RESULTS_READONLY
+ : IDS_CHK_RESULTS
+ ,
+ titleText,
+ ARRAYLEN(titleText));
+
+ SetWindowText(
+ GetDlgItem(hwnd,IDC_CHKDONE_TITLE),
+ titleText);
+
+ //
+ // Set the font for the edit control. Get a fixed-width font.
+ //
+
+ hFontText = CreateFont(
+ GetHeightFromPoints(8),
+ 0,
+ 0,
+ 0,
+ FW_NORMAL, // default weight
+ FALSE, // not italic
+ FALSE, // not underlined
+ FALSE, // not strikeout
+ ANSI_CHARSET,
+ OUT_DEFAULT_PRECIS,
+ CLIP_DEFAULT_PRECIS,
+ DEFAULT_QUALITY,
+ FIXED_PITCH | FF_MODERN,
+ TEXT("Courier")
+ );
+
+ if (NULL == hFontText)
+ {
+ daDebugOut((DEB_ERROR,
+ "CreateFont failed, error %d\n",
+ GetLastError()));
+ }
+
+ SendDlgItemMessage(
+ hwnd,
+ IDC_CHKDONE_Messages,
+ WM_SETFONT,
+ (WPARAM)hFontText,
+ MAKELPARAM(FALSE, 0)
+ );
+
+ //
+ // After the font is changed, set the text
+ //
+
+ SetWindowTextA(
+ GetDlgItem(hwnd,IDC_CHKDONE_Messages),
+ chkdskParams->Messages
+ );
+
+ // force a size message & redraw, since by now all the controls
+ // have been created
+
+ RECT rc;
+ GetClientRect(hwnd, &rc);
+ SetWindowPos(
+ hwnd,
+ NULL,
+ 0, 0,
+ rc.right, rc.bottom,
+ SWP_NOMOVE | SWP_NOZORDER | SWP_SHOWWINDOW);
+
+ SetFocus(GetDlgItem(hwnd,IDC_CHKDONE_Close));
+ }
+
+ return 1; // message not processed
+ }
+
+ case WM_GETMINMAXINFO:
+ {
+ LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam;
+
+ //
+ // Don't allow resizing too small
+ //
+
+ lpmmi->ptMinTrackSize.x = 400;
+ lpmmi->ptMinTrackSize.y = 150;
+
+ return 0; // message processed
+ }
+
+ case WM_COMMAND:
+ {
+ WORD wNotifyCode = HIWORD(wParam);
+ WORD wID = LOWORD(wParam);
+ HWND hwndCtrl = (HWND)lParam;
+
+ switch (wID)
+ {
+ case IDOK: // sent by <Enter>
+ case IDCANCEL: // sent by <Esc>
+ case IDC_CHKDONE_Close:
+ EndDialog(hwnd, 0);
+ break;
+
+ case IDC_CHKDONE_Print:
+ PrintResults(hwnd, chkdskParams);
+ break;
+
+ case IDC_CHKDONE_Save:
+ SaveResults(hwnd, chkdskParams);
+ break;
+
+ case IDHELP:
+ NoHelp(hwnd);
+ break;
+ }
+
+ return 0;
+ }
+
+ case WM_NEXTDLGCTL:
+ {
+ BOOL fHandle = (BOOL)LOWORD(lParam);
+ UINT wCtlFocus = wParam;
+
+ if (fHandle)
+ {
+ SetFocus(GetDlgItem(hwnd,wCtlFocus));
+ }
+ else
+ {
+ if (0 == wCtlFocus)
+ {
+ SetFocus(GetDlgItem(hwnd,IDC_CHKDONE_Close));
+ }
+ else
+ {
+ SetFocus(GetDlgItem(hwnd,IDHELP));
+ }
+ }
+ }
+
+ case WM_CTLCOLORSTATIC:
+ {
+ HDC hdcStatic = (HDC)wParam;
+ SetBkColor(hdcStatic, GetSysColor(COLOR_3DFACE));
+
+ UnrealizeObject(hbrStaticBrush);
+ POINT pt;
+ pt.x = pt.y = 0;
+ ClientToScreen(hwnd, &pt);
+ SetBrushOrgEx(hdcStatic, pt.x, pt.y, NULL);
+
+ return (LRESULT)hbrStaticBrush;
+ }
+
+ case WM_SIZE:
+ {
+ if (EverythingCreated)
+ {
+ //
+ // move the controls:
+ //
+ // 1. text control: ?,? : x,?
+ // 2. edit control: ?,? : x,y
+ // 3. "Close": z,M : ?,?
+ // 4. "Save": z,M + (by + bb) : ?,?
+ // 5. "Help": z,M + 2*by + 3*bb : ?,? // extra spacing above
+ //
+ // where dx = width, dy = height of window, bx = button width,
+ // by = button height, M = margin = 7,
+ // bb = inter-button spacing = 6, ? = no change
+ // x = dx - M [left] - M [right] - bx - M [spacing between],
+ // y = dy - M [bottom] - TopPosition
+ // z = dx - bx - M
+ //
+
+ DWORD Width = (DWORD)(LOWORD(lParam));
+ DWORD Height = (DWORD)(HIWORD(lParam));
+ DWORD SideMargin = 7;
+ DWORD InterButtonMargin = 4;
+ DWORD TextBoxHeight = 50;
+ DWORD ButtonWidth = 70;
+ DWORD ButtonHeight = 23;
+ DWORD TopOfEditBox = TextBoxHeight + SideMargin + 2 * SideMargin;
+ DWORD x = Width - ButtonWidth - 4*SideMargin;
+ BOOL f;
+
+ f = SetWindowPos(
+ GetDlgItem(hwnd,IDC_CHKDONE_TITLE),
+ NULL,
+ SideMargin,
+ SideMargin,
+ x,
+ TextBoxHeight,
+ SWP_NOZORDER | SWP_NOREDRAW);
+
+ if (!f) { daDebugOut((DEB_ERROR,"SetWindowPos(title) failed, %d\n",GetLastError())); }
+
+ DWORD y = Height - SideMargin - TopOfEditBox;
+
+ f = SetWindowPos(
+ GetDlgItem(hwnd,IDC_CHKDONE_Messages),
+ NULL,
+ SideMargin,
+ TopOfEditBox,
+ x,
+ y,
+ SWP_NOZORDER | SWP_NOREDRAW);
+
+ if (!f) { daDebugOut((DEB_ERROR,"SetWindowPos(message) failed, %d\n",GetLastError())); }
+
+ DWORD z = Width - ButtonWidth - SideMargin;
+ DWORD t = ButtonHeight + InterButtonMargin;
+
+ f = SetWindowPos(
+ GetDlgItem(hwnd,IDC_CHKDONE_Close),
+ NULL,
+ z,
+ SideMargin,
+ 0,
+ 0,
+ SWP_NOSIZE | SWP_NOZORDER | SWP_NOREDRAW);
+
+ if (!f) { daDebugOut((DEB_ERROR,"SetWindowPos(close) failed, %d\n",GetLastError())); }
+
+ f = SetWindowPos(
+ GetDlgItem(hwnd,IDC_CHKDONE_Print),
+ NULL,
+ z,
+ SideMargin + t,
+ 0,
+ 0,
+ SWP_NOSIZE | SWP_NOZORDER | SWP_NOREDRAW);
+
+ if (!f) { daDebugOut((DEB_ERROR,"SetWindowPos(print) failed, %d\n",GetLastError())); }
+
+ f = SetWindowPos(
+ GetDlgItem(hwnd,IDC_CHKDONE_Save),
+ NULL,
+ z,
+ SideMargin + 2 * t,
+ 0,
+ 0,
+ SWP_NOSIZE | SWP_NOZORDER | SWP_NOREDRAW);
+
+ if (!f) { daDebugOut((DEB_ERROR,"SetWindowPos(save) failed, %d\n",GetLastError())); }
+
+ f = SetWindowPos(
+ GetDlgItem(hwnd,IDHELP),
+ NULL,
+ z,
+ SideMargin + 3 * t + InterButtonMargin, // a bit extra
+ 0,
+ 0,
+ SWP_NOSIZE | SWP_NOZORDER | SWP_NOREDRAW);
+
+ if (!f) { daDebugOut((DEB_ERROR,"SetWindowPos(help) failed, %d\n",GetLastError())); }
+
+ InvalidateRect(hwnd, NULL, FALSE);
+ UpdateWindow(hwnd);
+ }
+
+ return 0;
+ }
+
+ case WM_SYSCOMMAND:
+ {
+ UINT uCmdType = (wParam & 0xfff0);
+
+ if ( SC_CLOSE == uCmdType
+ || SC_MINIMIZE == uCmdType
+ || SC_TASKLIST == uCmdType)
+ {
+ daDebugOut((DEB_ITRACE,"Ignoring a disallowed operation\n"));
+
+ return 0; // disallow these.
+ }
+
+ break;
+ }
+
+ case WM_CLOSE:
+ {
+ EndDialog(hwnd, 0);
+ return 0;
+ }
+
+ case WM_DESTROY:
+ {
+ DeleteBrush(hbrStaticBrush);
+ DeleteFont(hFontText);
+ return 0;
+ }
+
+ default:
+ break;
+ }
+
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+//
+// Code for the thread handling invocation of Chkdsk()
+//
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: OnFinalMessage
+//
+// Synopsis: Put a message in a message box after the final chkdsk message
+//
+// Arguments: [hwndOwner] -- handle to owner window
+// [Message] -- message to display
+//
+// Returns: nothing
+//
+// History: 6-Jan-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+OnFinalMessage(
+ IN HWND hwndOwner,
+ IN PSTR Message
+ )
+{
+ CHAR title[100];
+
+ LoadStringA(
+ g_hInstance,
+ IDS_CHK_TITLE,
+ title,
+ ARRAYLEN(title));
+
+ MessageBoxA(
+ hwndOwner,
+ Message,
+ title,
+ MB_OK | MB_ICONINFORMATION
+ );
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: ChkdskCallback
+//
+// Synopsis: This routine gets callbacks from fmifs.dll regarding
+// progress and status of the ongoing chkdsk. It runs in the
+// same thread as the chkdsk, which is a separate thread from
+// the "cancel" button and the error message window (if
+// any). If the user hits "cancel", this routine
+// notices on the next callback and cancels the chkdsk.
+//
+// Arguments: [PacketType] -- an fmifs packet type
+// [PacketLength] -- length of the packet data
+// [PacketData] -- data associated with the packet
+//
+// Returns: TRUE if the fmifs activity should continue, FALSE if the
+// activity should halt immediately. Thus, we return FALSE if
+// the user has hit "cancel" and we wish fmifs to clean up and
+// return from the Chkdsk() entrypoint call.
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+LOCAL BOOLEAN
+ChkdskCallback(
+ IN FMIFS_PACKET_TYPE PacketType,
+ IN DWORD PacketLength,
+ IN PVOID PacketData
+ )
+{
+ UNREFERENCED_PARM(PacketLength);
+
+ PCHKDSK_PARAMS chkdskParams = ParamsForChkdskCallBack;
+
+ if (chkdskParams->Cancel)
+ {
+ if (!chkdskParams->Cancelled)
+ {
+ //
+ // if we haven't got a cancelled callback yet (that is, we
+ // haven't yet been called here with Cancel set to TRUE), then
+ // send a Cancel message to the dialog.
+ //
+ // we will actually get up to two callbacks with Cancel set to
+ // TRUE: one for the first message following the time when we
+ // set Cancel to TRUE. This can be any message. The second
+ // will be for the FmIfsFinished message.
+ //
+
+ int fOk = DialogBoxParam(
+ g_hInstance,
+ MAKEINTRESOURCE(IDD_StopChk),
+ chkdskParams->hDlg,
+ StopChkDlgProc,
+ (LPARAM)chkdskParams
+ );
+
+ if (-1 == fOk)
+ {
+ // error creating dialog
+ daDebugOut((DEB_ERROR, "DialogBoxParam() failed!\n"));
+ return FALSE;
+ }
+
+ if (fOk)
+ {
+ // stop it!
+
+ PostMessage(chkdskParams->hDlg, CHK_PROGRESSCANCEL, 0, 0);
+
+ chkdskParams->Cancelled = TRUE;
+
+ return FALSE;
+ }
+ else
+ {
+ // user changed mind; doesn't want to stop it
+
+ chkdskParams->Cancel = FALSE;
+
+ // re-enable the cancel button
+
+ PostMessage(chkdskParams->hDlg, CHK_PROGRESSUNCANCEL, 0, 0);
+
+ // now, drop through and perform work on the message...
+ }
+ }
+ else
+ {
+ daDebugOut((DEB_TRACE, "ChkdskCallback called after cancelled\n"));
+ return FALSE;
+ }
+ }
+
+ switch (PacketType)
+ {
+
+ case FmIfsPercentCompleted:
+ {
+ DWORD currentTime = GetTime();
+ DWORD timeDelta = currentTime - chkdskParams->lasttime;
+
+ ULONG PercentCompleted = ((PFMIFS_PERCENT_COMPLETE_INFORMATION)PacketData)->PercentCompleted;
+
+ if ( 0 == PercentCompleted
+ || 100 == PercentCompleted
+ || timeDelta >= MIN_TIME_DELTA)
+ {
+ chkdskParams->lasttime = currentTime;
+
+ PostMessage(
+ chkdskParams->hDlg,
+ CHK_PROGRESSUPDATE,
+ PercentCompleted,
+ 0
+ );
+ }
+
+ return TRUE;
+ }
+
+ case FmIfsCheckOnReboot:
+ {
+ PFMIFS_CHECKONREBOOT_INFORMATION pMess =
+ (PFMIFS_CHECKONREBOOT_INFORMATION)PacketData;
+
+ //
+ // we only query the user if we are in "fix" mode.
+ // Otherwise, we answer the default since nothing really
+ // happens anyway.
+ //
+
+ pMess->QueryResult =
+ (IDYES == MyMessageBox(
+ g_hInstance,
+ chkdskParams->hwndParent,
+ IDS_CHK_ON_REBOOT,
+ IDS_CHK_TITLE,
+ MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON1
+ ));
+
+ daDebugOut((DEB_TRACE,
+ "Callback: reboot query returns \"%s\"\n",
+ pMess->QueryResult ? "yes" : "no"
+ ));
+
+ return TRUE;
+ }
+
+ case FmIfsTextMessage:
+ {
+ PFMIFS_TEXT_MESSAGE pMess = (PFMIFS_TEXT_MESSAGE)PacketData;
+
+ switch (pMess->MessageType)
+ {
+ case MESSAGE_TYPE_RESULTS:
+ {
+ daDebugOut((DEB_TRACE,
+ "Callback: results message \"%s\"\n",
+ pMess->Message
+ ));
+
+ chkdskParams->fmifsSuccess = FALSE;
+
+ //
+ // Append the message to the edit control
+ //
+
+ UINT Length = lstrlenA(pMess->Message);
+
+ while (chkdskParams->NumCharacters + Length
+ > chkdskParams->NumMessageChunks * MESSAGE_CHUNK)
+ {
+ //
+ // need to allocate more memory
+ //
+
+ ++ chkdskParams->NumMessageChunks;
+ PSTR temp = new CHAR[chkdskParams->NumMessageChunks * MESSAGE_CHUNK];
+ lstrcpyA(temp, chkdskParams->Messages);
+ delete[] chkdskParams->Messages;
+ chkdskParams->Messages = temp;
+ }
+
+ lstrcatA(chkdskParams->Messages, pMess->Message);
+ chkdskParams->NumCharacters += Length;
+
+ break;
+ }
+
+ case MESSAGE_TYPE_PROGRESS:
+ {
+ //
+ // I need to send the message from this thread (the worker
+ // thread) to the other thread (the UI thread), so it can be put
+ // in the progress dialog. However, I can't just send the passed-in
+ // pointer, because it points to a static buffer in fmifs that will
+ // get munged before the UI thread does anything. So, allocate a
+ // buffer, copy the string, and pass that pointer in the message.
+ // Then, the UI thread must de-allocate it.
+ //
+
+ daDebugOut((DEB_TRACE,
+ "Callback: progress message \"%s\"\n",
+ pMess->Message
+ ));
+
+ PSTR Message = new CHAR[(lstrlenA(pMess->Message) + 1) * sizeof(CHAR)];
+ lstrcpyA(Message, pMess->Message);
+ PostMessage(chkdskParams->hDlg, CHK_PROGRESSTITLE, (WPARAM)Message, 0);
+
+ break;
+ }
+
+ case MESSAGE_TYPE_FINAL:
+ {
+ daDebugOut((DEB_TRACE,
+ "Callback: final message \"%s\"\n",
+ pMess->Message));
+
+ OnFinalMessage(chkdskParams->hDlg, pMess->Message);
+
+ // now, make sure this is the final message...
+
+ chkdskParams->Final = TRUE;
+
+ break;
+ }
+
+ default:
+ {
+ daDebugOut((DEB_TRACE,
+ "Callback: Unknown message, type %d, \"%s\"\n",
+ pMess->MessageType,
+ pMess->Message
+ ));
+
+ break;
+ }
+ }
+
+ return TRUE;
+ }
+
+ case FmIfsFinished:
+
+ daDebugOut((DEB_TRACE,"Callback: Finished\n"));
+// chkdskParams->fmifsSuccess =
+// ((PFMIFS_FINISHED_INFORMATION)PacketData)->Success;
+
+ PostMessage(chkdskParams->hDlg, CHK_PROGRESSEND, 0, 0);
+
+ return TRUE;
+
+ default:
+
+ daDebugOut((DEB_ERROR,
+ "Chkdsk callback: unexpected message: %d\n",
+ PacketType));
+ return FALSE;
+ }
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: ChkdskVolume
+//
+// Synopsis: Thread procedure that invokes Chkdsk on a volume.
+//
+// Arguments: [ThreadParameter] -- a PCHKDSK_PARAMS pointer
+//
+// Returns: 0
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+LOCAL DWORD WINAPI
+ChkdskVolume(
+ IN LPVOID ThreadParameter
+ )
+{
+ PCHKDSK_PARAMS chkdskParams = (PCHKDSK_PARAMS)ThreadParameter;
+
+ daDebugOut((DEB_TRACE,
+ "Calling Chkdsk(%ws,%ws,/f? %s,/r? %s...)\n",
+ chkdskParams->DriveName,
+ chkdskParams->FileSystem,
+ CHKDSK_SLASH_F(chkdskParams->Fix) ? "yes" : "no",
+ CHKDSK_SLASH_R(chkdskParams->Fix) ? "yes" : "no"
+ ));
+
+ //
+ // The fmifs interface doesn't allow for a context parameter
+ // therefore the chkdskparams must be passed through a global.
+ //
+
+ chkdskParams->lasttime = 0; // force first
+ ParamsForChkdskCallBack = chkdskParams;
+
+ (*lpfnChkdsk)(
+ chkdskParams->DriveName,
+ chkdskParams->FileSystem,
+ CHKDSK_SLASH_F(chkdskParams->Fix), // fix?
+ FALSE, // not verbose
+ FALSE, // not only if dirty (i.e., force a check)
+ CHKDSK_SLASH_R(chkdskParams->Fix), // recover? (i.e. sector check)
+ NULL, // don't check a specific path
+ FALSE, // don't try to extend volume
+ &ChkdskCallback
+ );
+
+ daDebugOut((DEB_TRACE,"Leaving Chkdsk() worker thread\n"));
+ return 0;
+}
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+//
+// Code for the thread handling the "working..." (i.e. cancel) dialog
+// as well as preceeding dialogs (the initial chkdsk choices (fix/no
+// fix) dialog, and the initial invocation of this extension option.
+//
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: SetChkdskProgressTitle
+//
+// Synopsis: Sets the title in the chkdsk progress dialog
+//
+// Arguments: [hDlg] -- handle to dialog window
+// [chkdskParams] -- chkdsk parameters
+//
+// Returns: nothing
+//
+// History: 7-Jan-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+VOID
+SetChkdskProgressTitle(
+ IN HWND hDlg,
+ IN PCHKDSK_PARAMS chkdskParams
+ )
+{
+ //
+ // Set the title, e.g. "Checking Volume D:"
+ //
+
+ TCHAR title[100];
+ TCHAR titleProto[100];
+
+ LoadString(
+ g_hInstance,
+ IDS_CHK_PROGRESS_TITLE,
+ titleProto,
+ ARRAYLEN(titleProto));
+
+ wsprintf(
+ title,
+ titleProto,
+ chkdskParams->DriveName);
+
+ SetDlgItemText(hDlg, IDC_CHKPROG_Title, title);
+}
+
+
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: ChkdskProgressDlgProc
+//
+// Synopsis: Dialog procedure for "cancel" dialog for Chkdsk
+//
+// Arguments: standard Windows dialog procedure
+//
+// Returns: standard Windows dialog procedure
+//
+// History: 16-Aug-93 BruceFo Created
+//
+// Note: If the user chooses "cancel", we need to stop the Chkdsk
+// operation, which is running in a separate thread. That
+// thread, in turn, needs to destroy the error message window
+// (if any), and the associated error message window thread.
+//
+//----------------------------------------------------------------------------
+
+LOCAL BOOL CALLBACK
+ChkdskProgressDlgProc(
+ IN HWND hDlg,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ static DWORD percentDrawn;
+ static PCHKDSK_PARAMS chkdskParams;
+ static BOOL noPercentDone;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ chkdskParams = (PCHKDSK_PARAMS)lParam;
+
+ chkdskParams->hDlg = hDlg;
+ chkdskParams->fmifsSuccess = TRUE;
+ chkdskParams->Result = 0;
+
+ chkdskParams->NumMessageChunks = 1; // initially allocate one
+ chkdskParams->NumCharacters = 1; // NULL character
+ chkdskParams->Messages = new CHAR[MESSAGE_CHUNK];
+ chkdskParams->Messages[0] = '\0';
+
+ CenterWindow(hDlg, chkdskParams->hwndParent);
+
+ SetChkdskProgressTitle(hDlg, chkdskParams);
+
+ //
+ // Create the formatting thread
+ //
+
+ DWORD threadId; // ignored
+ chkdskParams->hWorkerThread = CreateThread(
+ NULL,
+ 0,
+ ChkdskVolume,
+ (LPVOID)chkdskParams,
+ 0,
+ &threadId
+ );
+
+ if (NULL == chkdskParams->hWorkerThread)
+ {
+ daDebugOut((DEB_ERROR,"Error creating chkdsk worker thread\n"));
+
+ chkdskParams->Result = MSG_COULDNT_CREATE_THREAD;
+ EndDialog(hDlg, FALSE);
+ return TRUE;
+ }
+
+ noPercentDone = chkdskParams->noPercentDone;
+
+ //
+ // Initialize the gas gauge
+ //
+
+ if (!noPercentDone)
+ {
+ percentDrawn = 0;
+ InitDrawGasGauge(GetDlgItem(hDlg, IDC_CHKPROG_GasGauge));
+ }
+
+ SetDlgItemTextA(hDlg, IDC_CHKPROG_GasGaugeCaption, "");
+
+ return 1; // didn't call SetFocus
+ }
+
+ case WM_COMMAND:
+
+ switch (LOWORD(wParam))
+ {
+ case IDCANCEL:
+ if (chkdskParams->AllowCancel)
+ {
+ MySetDlgItemText(g_hInstance, hDlg, IDC_CHKPROG_Title, IDS_CANCELPENDING);
+ SetDlgItemText(hDlg, IDC_CHKPROG_GasGaugeCaption, TEXT(""));
+
+ // disable the "stop" button if it's already been pushed.
+
+ EnableWindow(GetDlgItem(hDlg, IDCANCEL), FALSE);
+
+ // leave result at 0, so no pop-up
+ chkdskParams->Cancel = TRUE;
+
+ // only exit after final message: see CHK_PROGRESSCANCEL
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HDC hDC = BeginPaint(hDlg, &ps);
+
+ if (!noPercentDone)
+ {
+ DrawGasGauge(
+ GetDlgItem(hDlg, IDC_CHKPROG_GasGauge),
+ hDlg,
+ hDC,
+ percentDrawn,
+ NULL);
+ }
+
+ EndPaint(hDlg, &ps);
+
+ return TRUE;
+ }
+
+ case CHK_PROGRESSUPDATE:
+ {
+ // wParam = % completed
+
+ if (noPercentDone)
+ {
+ daDebugOut((DEB_TRACE,
+ "ChkdskProgressDlgProc: Got an unexpected progress message\n"));
+ return TRUE;
+ }
+
+ percentDrawn = (INT)wParam;
+
+ RECT rcGauge;
+ HWND hwndGauge = GetDlgItem(hDlg, IDC_CHKPROG_GasGauge);
+
+ GetClientRect(hwndGauge, &rcGauge);
+
+ ClientToScreen(hwndGauge, (LPPOINT)&rcGauge.left);
+ ClientToScreen(hwndGauge, (LPPOINT)&rcGauge.right);
+ ScreenToClient(hDlg, (LPPOINT)&rcGauge.left);
+ ScreenToClient(hDlg, (LPPOINT)&rcGauge.right);
+
+ InvalidateRect(hDlg, &rcGauge, FALSE);
+ UpdateWindow(hDlg);
+
+ return TRUE;
+ }
+
+ case CHK_PROGRESSEND:
+ {
+ daDebugOut((DEB_TRACE,
+ "ChkdskProgressDlgProc: got CHK_PROGRESSEND message\n"));
+
+ //
+ // Wait 15 seconds for it to finish
+ //
+ daDebugOut((DEB_TRACE,"Waiting for worker thread to terminate\n"));
+ DWORD ret = WaitForSingleObject(chkdskParams->hWorkerThread, 15000);
+ if (WAIT_TIMEOUT == ret)
+ {
+ daDebugOut((DEB_ERROR,"Timeout waiting for worker thread to terminate\n"));
+ }
+ else
+ {
+ daDebugOut((DEB_TRACE,"Worker thread terminated\n"));
+ }
+ CloseHandle(chkdskParams->hWorkerThread);
+ EndDialog(hDlg, TRUE);
+
+ return TRUE;
+ }
+
+ case CHK_PROGRESSCANCEL:
+ {
+ //
+ // Wait 15 seconds for it to finish
+ //
+ daDebugOut((DEB_TRACE,"Waiting for worker thread to terminate\n"));
+ DWORD ret = WaitForSingleObject(chkdskParams->hWorkerThread, 15000);
+ if (WAIT_TIMEOUT == ret)
+ {
+ daDebugOut((DEB_ERROR,"Timeout waiting for worker thread to terminate\n"));
+ }
+ else
+ {
+ daDebugOut((DEB_TRACE,"Worker thread terminated\n"));
+ }
+ CloseHandle(chkdskParams->hWorkerThread);
+
+ EndDialog(hDlg, FALSE);
+ return TRUE;
+ }
+
+ case CHK_PROGRESSUNCANCEL:
+ {
+ //
+ // Reset the dialog text/titles/captions
+ //
+
+ SetChkdskProgressTitle(hDlg, chkdskParams);
+
+ //
+ // Re-enable the "stop" button, and set focus to it
+ //
+
+ HWND hwndCancelButton = GetDlgItem(hDlg, IDCANCEL);
+ EnableWindow(hwndCancelButton, TRUE);
+ SetFocus(hwndCancelButton);
+
+ return TRUE;
+ }
+
+ case CHK_PROGRESSTITLE:
+ {
+ PSTR message = (PSTR)wParam;
+ SetDlgItemTextA(hDlg, IDC_CHKPROG_GasGaugeCaption, message);
+ delete[] message;
+ return TRUE;
+ }
+
+ default:
+ break;
+ }
+
+ return FALSE; // message not processed
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: FindCheckedRadioButton
+//
+// Synopsis: Search for which radio button is checked. Returns the
+// first one checked from a sequential set of IDs.
+//
+// Arguments: [hDlg] -- dialog with the radio buttons
+// [wIdFirst] -- first radio button
+// [wIdLast] -- last radio button
+//
+// Returns: the ID or the checked button, or -1 if none
+//
+// History: 4-Nov-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+int
+FindCheckedRadioButton(
+ HWND hDlg,
+ int wIdFirst,
+ int wIdLast
+ )
+{
+ for (int i = wIdFirst; i <= wIdLast; i++)
+ {
+ if (IsDlgButtonChecked(hDlg, i))
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: ChkdskDlgProc
+//
+// Synopsis: Dialog procedure for Chkdsk UI. Allows user to choose
+// Chkdsk options.
+//
+// Arguments: standard Windows dialog procedure
+//
+// Returns: standard Windows dialog procedure
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+LOCAL BOOL CALLBACK
+ChkdskDlgProc(
+ IN HWND hDlg,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ static PCHKDSK_PARAMS chkdskParams;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ chkdskParams = (PCHKDSK_PARAMS)lParam;
+
+ CenterWindow(hDlg, chkdskParams->hwndParent);
+
+ //
+ // set the initial data: the radio button and the label
+ //
+
+ TCHAR volumeInfo[100];
+ TCHAR titleProto[100];
+
+ if (TEXT('\0') != chkdskParams->Label[0])
+ {
+ LoadString(
+ g_hInstance,
+ IDS_CHK_VOLWITHLABEL,
+ titleProto,
+ ARRAYLEN(titleProto));
+
+ wsprintf(
+ volumeInfo,
+ titleProto,
+ chkdskParams->DriveName,
+ chkdskParams->Label);
+ }
+ else
+ {
+ LoadString(
+ g_hInstance,
+ IDS_CHK_VOLNOLABEL,
+ titleProto,
+ ARRAYLEN(titleProto));
+
+ wsprintf(
+ volumeInfo,
+ titleProto,
+ chkdskParams->DriveName);
+ }
+
+ SetDlgItemText(hDlg, IDC_CHKDSK_VolumeToCheck, volumeInfo);
+
+ //
+ // Do filesystem-specific initialization, namely, whether /R is
+ // supported or not.
+ //
+
+ CheckRadioButton(
+ hDlg,
+ IDC_CHKDSK_DontFix,
+ IDC_CHKDSK_FixAll,
+ IDC_CHKDSK_Fix // initially, set to "fix"
+ );
+
+ return 1; // didn't call SetFocus
+ }
+
+ case WM_COMMAND:
+
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ {
+ int ret = IDYES; // by default, hitting OK means exit the dialog
+
+ chkdskParams->Fix = FindCheckedRadioButton(
+ hDlg,
+ IDC_CHKDSK_DontFix,
+ IDC_CHKDSK_FixAll
+ );
+
+ if (IDC_CHKDSK_DontFix == chkdskParams->Fix)
+ {
+ //
+ // if the choice is "don't fix", then make sure
+ //
+
+ TCHAR szTitle[100];
+ TCHAR szMessage[400];
+
+ LoadString(
+ g_hInstance,
+ IDS_CHK_TITLE,
+ szTitle,
+ ARRAYLEN(szTitle));
+
+ RetrieveAndFormatMessage(
+ MSG_CHK_READONLY_WARNING,
+ szMessage,
+ ARRAYLEN(szMessage),
+ NULL
+ );
+
+ ret = MessageBox(
+ hDlg,
+ szMessage,
+ szTitle,
+ MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON1
+ );
+ }
+
+ if (ret == IDYES)
+ {
+ EndDialog(hDlg, TRUE);
+ }
+
+ return TRUE;
+ }
+
+ case IDCANCEL:
+ EndDialog(hDlg, FALSE);
+ return TRUE;
+
+ case IDHELP:
+ NoHelp(hDlg);
+ return TRUE;
+ }
+
+ default:
+ break;
+ }
+
+ return FALSE; // message not processed
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DoChkdsk
+//
+// Synopsis: Perform UI to get user options for the Chkdsk, and then
+// actually perform a chkdsk on a volume.
+//
+// Arguments: none
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DoChkdsk(
+ IN HWND hwndParent
+ )
+{
+ if (!LoadFmifs())
+ {
+ return; // can't load fmifs.dll, so bail
+ }
+
+ static CHKDSK_PARAMS chkdskParams; // This can't be on the stack:
+ // it is passed to other threads
+
+ PREGION_DESCRIPTOR regionDescriptor = &SELECTED_REGION(0);
+ FDASSERT(regionDescriptor);
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(regionDescriptor);
+ FDASSERT(regionData);
+
+ PWSTR typeName = regionData->TypeName;
+
+ lstrcpy(chkdskParams.Label, regionData->VolumeLabel);
+ chkdskParams.Cancel = FALSE;
+ chkdskParams.Cancelled = FALSE;
+ chkdskParams.Final = FALSE;
+ chkdskParams.hwndParent = hwndParent;
+ chkdskParams.FileSystem = typeName;
+
+ FileSystemInfoType* pFSInfo = FindFileSystemInfo(typeName);
+ if (NULL == pFSInfo)
+ {
+ chkdskParams.FileSys = FS_UNKNOWN;
+ }
+ else
+ {
+ chkdskParams.FileSys = pFSInfo->FileSystemType;
+ }
+ chkdskParams.Messages = NULL;
+
+ WCHAR driveName[3];
+ driveName[0] = regionData->DriveLetter;
+ driveName[1] = L':';
+ driveName[2] = L'\0';
+ chkdskParams.DriveName = driveName;
+
+ int fOk = DialogBoxParam(
+ g_hInstance,
+ MAKEINTRESOURCE(IDD_CHKDSK),
+ hwndParent,
+ ChkdskDlgProc,
+ (LPARAM)&chkdskParams
+ );
+
+ if (-1 == fOk)
+ {
+ // error creating dialog
+ daDebugOut((DEB_ERROR, "DialogBoxParam() failed!\n"));
+ return;
+ }
+
+ if (fOk)
+ {
+ EnsureSameDevice(regionDescriptor);
+
+ LPTSTR lpszTemplate;
+
+ chkdskParams.noPercentDone = FALSE; //by default, we have %done info
+
+#ifdef SUPPORT_OFS
+ if (chkdskParam.FileSys == FS_OFS)
+ {
+ chkdskParams.noPercentDone = TRUE;
+ }
+#endif // SUPPORT_OFS
+
+ if ( (chkdskParams.Fix == IDC_CHKDSK_Fix)
+ || (chkdskParams.Fix == IDC_CHKDSK_FixAll) )
+ {
+ chkdskParams.AllowCancel = FALSE;
+#ifdef SUPPORT_OFS
+ if (chkdskParams.noPercentDone)
+ {
+ lpszTemplate = MAKEINTRESOURCE(IDD_CHKDSKPROGRESS_NOSTOP_NOPERCENT);
+ }
+ else
+ {
+#endif // SUPPORT_OFS
+ lpszTemplate = MAKEINTRESOURCE(IDD_CHKDSKPROGRESS_NOSTOP);
+#ifdef SUPPORT_OFS
+ }
+#endif // SUPPORT_OFS
+ }
+ else
+ {
+ chkdskParams.AllowCancel = TRUE;
+#ifdef SUPPORT_OFS
+ if (chkdskParams.noPercentDone)
+ {
+ lpszTemplate = MAKEINTRESOURCE(IDD_CHKDSKPROGRESS_NOPERCENT);
+ }
+ else
+ {
+#endif // SUPPORT_OFS
+ lpszTemplate = MAKEINTRESOURCE(IDD_CHKDSKPROGRESS);
+#ifdef SUPPORT_OFS
+ }
+#endif // SUPPORT_OFS
+ }
+
+ fOk = DialogBoxParam(
+ g_hInstance,
+ lpszTemplate,
+ hwndParent,
+ ChkdskProgressDlgProc,
+ (LPARAM)&chkdskParams);
+
+ if (-1 == fOk)
+ {
+ // error creating dialog
+ daDebugOut((DEB_ERROR, "DialogBoxParam() failed!\n"));
+ }
+ else if (chkdskParams.Cancel)
+ {
+ // operation was cancelled
+ }
+ else if (! chkdskParams.Final)
+ {
+ daDebugOut((DEB_TRACE,"Chkdsk terminated normally\n"));
+
+ //
+ // Chkdsk wasn't cancelled; it finished normally
+ //
+
+ if (chkdskParams.NumCharacters > 1) //more than just a NULL char.
+ {
+ //
+ // If there were no messages, we don't display anything. If
+ // there were messages, so show the results box.
+ //
+
+ //
+ // bad variable name. I can't figure out how to send a
+ // context parameters to a dialog box with a separate class.
+ // DialogBoxParam sends the last param to a dialog procedure's
+ // WM_INITDIALOG message. But, we don't get that message with
+ // our own dialog class.
+ //
+
+ ParamsForChkdskCallBack = &chkdskParams;
+
+ fOk = DialogBox(
+ g_hInstance,
+ MAKEINTRESOURCE(IDD_CHKDONE),
+ hwndParent,
+ NULL
+ );
+
+ if (-1 == fOk)
+ {
+ // error creating dialog
+ daDebugOut((DEB_ERROR, "DialogBoxParam() failed!\n"));
+ }
+ }
+ }
+
+ if (NULL != chkdskParams.Messages)
+ {
+ delete[] chkdskParams.Messages;
+ }
+ }
+}
diff --git a/private/utils/windisk/src/chkdsk.hxx b/private/utils/windisk/src/chkdsk.hxx
new file mode 100644
index 000000000..80d628a05
--- /dev/null
+++ b/private/utils/windisk/src/chkdsk.hxx
@@ -0,0 +1,27 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: chkdsk.hxx
+//
+// Contents: Chkdsk APIs
+//
+// History: 14-Jan-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __CHKDSK_HXX__
+#define __CHKDSK_HXX__
+
+BOOL
+RegisterMessageWindowClass(
+ VOID
+ );
+
+VOID
+DoChkdsk(
+ IN HWND hwndParent
+ );
+
+#endif // __CHKDSK_HXX__
diff --git a/private/utils/windisk/src/cm.cxx b/private/utils/windisk/src/cm.cxx
new file mode 100644
index 000000000..031b188da
--- /dev/null
+++ b/private/utils/windisk/src/cm.cxx
@@ -0,0 +1,888 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: cm.cxx
+//
+// Contents: Context menu functions
+//
+// History: 24-May-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include "cm.hxx"
+#include "listbox.hxx"
+#include "menudict.hxx"
+#include "popup.hxx"
+#include "select.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+#ifdef WINDISK_EXTENSIONS
+INT
+AddExtensionItemsToContextMenu(
+ IN HMENU hmenuContext,
+ IN MenuType* pMenu,
+ IN BOOL fFlags
+ );
+#endif // WINDISK_EXTENSIONS
+
+BOOL
+MyAppendMenu(
+ IN HMENU hmenu,
+ IN UINT idNewItem
+ );
+
+INT
+DoContextMenu(
+ IN HMENU hmenu,
+ IN PPOINT ppt
+ );
+
+VOID
+VolumeContextMenu(
+ IN PPOINT ppt
+ );
+
+VOID
+NewVolumeContextMenu(
+ IN PPOINT ppt
+ );
+
+VOID
+FreeSpaceContextMenu(
+ IN PPOINT ppt
+ );
+
+VOID
+ExtendedFreeSpaceContextMenu(
+ IN PPOINT ppt
+ );
+
+//////////////////////////////////////////////////////////////////////////////
+
+#define MAXMENUTEXTLEN 50
+
+UINT aFileSystemCommands[] =
+{
+ IDM_VOL_FORMAT,
+ IDM_VOL_LETTER,
+ IDM_VOL_EJECT
+};
+
+
+
+UINT aContextMenuCommands[] =
+{
+
+//
+// Tools menu
+//
+
+ IDM_VOL_DBLSPACE ,
+
+//
+// Partition menu
+//
+
+ IDM_PARTITIONCREATE ,
+ IDM_PARTITIONCREATEEX ,
+ IDM_PARTITIONDELETE ,
+#if i386
+ IDM_PARTITIONACTIVE ,
+#endif
+
+//
+// Fault tolerance menu (Advanced Server only)
+//
+
+ IDM_FTESTABLISHMIRROR ,
+ IDM_FTBREAKMIRROR ,
+ IDM_FTCREATESTRIPE ,
+ IDM_FTCREATEVOLUMESET ,
+ IDM_FTRECOVERSTRIPE ,
+ IDM_FTCREATEPSTRIPE ,
+ IDM_FTEXTENDVOLUMESET
+
+};
+
+
+UINT aFinalCommands[] =
+{
+ IDM_PARTITIONCOMMIT,
+ IDM_VOL_PROPERTIES
+};
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+#ifdef WINDISK_EXTENSIONS
+
+//+---------------------------------------------------------------------------
+//
+// Function: AddExtensionItemsToContextMenu
+//
+// Synopsis: Adds an extension menu item to both the menu bar and the
+// given context menu.
+//
+// Arguments: [hmenuContext] -- context menu to add item to
+// [pMenu] -- pointer to extension menu item
+// [fFlags] -- standard menu flags (probably
+// MF_ENABLED or MF_GRAYED)
+//
+// Returns: Count of items added
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+INT
+AddExtensionItemsToContextMenu(
+ IN HMENU hmenuContext,
+ IN MenuType* pMenu,
+ IN BOOL fFlags
+ )
+{
+ INT i;
+
+ for (i=0; i<pMenu->cMenuItems; i++)
+ {
+ MenuItemType* pItem = &(pMenu->aMenuItems[i]);
+
+ INT id = MenuItems.LookupMenuId(pItem); //get the ID
+
+ if (-1 == id)
+ {
+ daDebugOut((DEB_ERROR,
+ "Couldn't add '%ws' to context menu\n",
+ pItem->pszMenu
+ ));
+ }
+ else
+ {
+ BOOL f = AppendMenu(
+ hmenuContext,
+ MF_STRING | fFlags,
+ (UINT)id,
+ pItem->pszMenu);
+
+ if (!f)
+ {
+ daDebugOut((DEB_ERROR,"AppendMenu failed!\n"));
+ }
+ }
+ }
+
+ return pMenu->cMenuItems;
+}
+
+#endif // WINDISK_EXTENSIONS
+
+//+---------------------------------------------------------------------------
+//
+// Function: MyAppendMenu
+//
+// Synopsis: Append to a context menu. The string to use as the menu item
+// content is derived from the frame window menu. Thus,
+// the context menu so added must be a normal menu command of
+// the frame window.
+//
+// Arguments: [hmenu] -- handle of menu to append to
+// [idNewItem] -- ID of new menu item, e.g. IDM_VOL_FORMAT
+//
+// Returns: TRUE if success
+//
+// History: 19-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+BOOL
+MyAppendMenu(
+ IN HMENU hmenu,
+ IN UINT idNewItem
+ )
+{
+ TCHAR szText[MAXMENUTEXTLEN];
+ BOOL f = FALSE;
+
+ if (0 != GetMenuString(
+ g_hmenuFrame,
+ idNewItem,
+ szText,
+ ARRAYLEN(szText),
+ MF_BYCOMMAND))
+ {
+ f = AppendMenu(
+ hmenu,
+ MF_STRING | GetMenuState(g_hmenuFrame, idNewItem, MF_BYCOMMAND),
+ idNewItem,
+ szText
+ );
+ }
+
+ if (!f)
+ {
+ daDebugOut((DEB_ERROR,"AppendMenu failed!\n"));
+ }
+
+ return f;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: DoContextMenu, public
+//
+// Synopsis: Create a context menu
+//
+// Arguments: [hmenu] -- The pop-up context menu to display
+// [ppt] -- pointer to a point (in screen coordinates) for
+// the upper-left corner of the menu
+//
+// Returns: -1 if nothing chosen, or the 0-based index of the item selected
+//
+// History: 24-May-93 BruceFo Created
+//
+// Notes: The owner window for the context menu is the Disk
+// Administrator frame window. It receives a WM_COMMAND based
+// on the menu selection.
+//
+//--------------------------------------------------------------------------
+
+INT
+DoContextMenu(
+ IN HMENU hmenu,
+ IN PPOINT ppt
+ )
+{
+ if (0 == GetMenuItemCount(hmenu))
+ {
+ // nothing in the menu!
+
+ return -1;
+ }
+
+ INT ret = TrackModalPopupMenu(
+ hmenu,
+ TPM_LEFTALIGN | TPM_RIGHTBUTTON,
+ ppt->x,
+ ppt->y,
+ 0,
+ NULL
+ );
+
+ return (ret < 0) ? -1 : ret;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: VolumeContextMenu, public
+//
+// Synopsis: Create a context menu for a selection in the volume view
+//
+// Arguments: [ppt] -- ptr to screen coordinates of point to put
+// context menu at
+//
+// Returns: nothing?
+//
+// History: 24-May-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+VOID
+VolumeContextMenu(
+ IN PPOINT ppt
+ )
+{
+ INT cVolumeCommands = 0;
+ INT cExtensionCommands = 0;
+ INT cPartitionCommands = 0;
+ INT cFinalCommands = 0;
+ INT cSeparators = 0;
+ INT i;
+
+ BOOL f;
+
+ //
+ // Create the menu
+ //
+
+ HMENU hmenuVol = CreatePopupMenu();
+
+ if (NULL == hmenuVol)
+ {
+ daDebugOut((DEB_ERROR,"CreatePopupMenu failed!\n"));
+ return;
+ }
+
+ for (i=0; i<ARRAYLEN(aFileSystemCommands); i++)
+ {
+
+ if (aFileSystemCommands[i] == IDM_VOL_LETTER ||
+ aFileSystemCommands[i] == IDM_VOL_EJECT ||
+ !(MF_GRAYED & GetMenuState(
+ g_hmenuFrame,
+ aFileSystemCommands[i],
+ MF_BYCOMMAND))
+ )
+ {
+ MyAppendMenu(hmenuVol, aFileSystemCommands[i]);
+ ++cVolumeCommands;
+ }
+ }
+
+#ifdef WINDISK_EXTENSIONS
+
+ if (AllowExtensionItems)
+ {
+ //
+ // Determine if there are any context menu items drawn from extension
+ // classes (based on previous claiming). Only allow extension items on
+ // pre-existing volumes or disks, for single selection.
+ //
+
+ PREGION_DESCRIPTOR regionDescriptor = &SELECTED_REGION(0);
+ WCHAR driveLetter = PERSISTENT_DATA(regionDescriptor)->DriveLetter;
+ unsigned driveIndex = (unsigned)DriveLetterToIndex(driveLetter);
+
+ if (NULL != VolumeInfo[driveIndex].VolClaims)
+ {
+ //
+ // add the volume extension items
+ //
+
+ PVOL_CLAIM_LIST volClaims = VolumeInfo[driveIndex].VolClaims;
+ while (NULL != volClaims)
+ {
+ AddExtensionItemsToContextMenu(
+ hmenuVol,
+ &(volClaims->pClaimer->pInfo->mnuOps),
+ MF_ENABLED
+ );
+
+ ++cExtensionCommands;
+
+ volClaims = volClaims->pNext;
+ }
+ }
+ }
+
+#endif // WINDISK_EXTENSIONS
+
+ for (i=0; i<ARRAYLEN(aContextMenuCommands); i++)
+ {
+ if (!(MF_GRAYED & GetMenuState(g_hmenuFrame,
+ aContextMenuCommands[i],
+ MF_BYCOMMAND))
+ )
+ {
+ MyAppendMenu(hmenuVol, aContextMenuCommands[i]);
+ ++cPartitionCommands;
+ }
+ }
+
+ for (i = 0; i < ARRAYLEN(aFinalCommands); i++)
+ {
+ if (aFinalCommands[i] == IDM_VOL_PROPERTIES ||
+ !(MF_GRAYED & GetMenuState(
+ g_hmenuFrame,
+ aFinalCommands[i],
+ MF_BYCOMMAND))
+ )
+ {
+ MyAppendMenu(hmenuVol, aFinalCommands[i]);
+ ++cFinalCommands;
+ }
+ }
+
+ //
+ // Now, add separators if needed
+ //
+
+ if ( cVolumeCommands > 0
+ && (cExtensionCommands + cPartitionCommands + cFinalCommands) > 0)
+ {
+ f = InsertMenu(
+ hmenuVol,
+ cVolumeCommands,
+ MF_BYPOSITION | MF_SEPARATOR,
+ 0,
+ NULL);
+
+ if (!f)
+ {
+ daDebugOut((DEB_ERROR,"InsertMenu failed!\n"));
+ }
+ else
+ {
+ ++cSeparators;
+ }
+ }
+
+#ifdef WINDISK_EXTENSIONS
+
+ if ( cExtensionCommands > 0
+ && (cPartitionCommands + cFinalCommands) > 0)
+ {
+ f = InsertMenu(
+ hmenuVol,
+ cVolumeCommands
+ + cExtensionCommands
+ + cSeparators,
+ MF_BYPOSITION | MF_SEPARATOR,
+ 0,
+ NULL);
+
+ if (!f)
+ {
+ daDebugOut((DEB_ERROR,"InsertMenu failed!\n"));
+ }
+ else
+ {
+ ++cSeparators;
+ }
+ }
+
+#endif // WINDISK_EXTENSIONS
+
+ if ( cPartitionCommands > 0
+ && cFinalCommands > 0)
+ {
+ f = InsertMenu(
+ hmenuVol,
+ cVolumeCommands
+ + cExtensionCommands
+ + cPartitionCommands
+ + cSeparators,
+ MF_BYPOSITION | MF_SEPARATOR,
+ 0,
+ NULL);
+
+ if (!f)
+ {
+ daDebugOut((DEB_ERROR,"InsertMenu failed!\n"));
+ }
+ else
+ {
+ ++cSeparators;
+ }
+ }
+
+
+ //
+ // Now check if the menu is empty. If it is, use a "<<No operations
+ // allowed>>" string
+ //
+
+ if (0 == GetMenuItemCount(hmenuVol))
+ {
+ TCHAR Buffer[MAX_RESOURCE_STRING_LEN];
+
+ LoadString(
+ g_hInstance,
+ IDS_NOOPERATIONS,
+ Buffer,
+ ARRAYLEN(Buffer));
+
+ f = AppendMenu(hmenuVol, MF_STRING, IDM_NOVALIDOPERATION, Buffer);
+
+ if (!f)
+ {
+ daDebugOut((DEB_ERROR,"AppendMenu failed!\n"));
+ }
+ }
+
+ //
+ // Display the menu
+ //
+
+ DoContextMenu(hmenuVol, ppt);
+
+ //
+ // Destroy the menu
+ //
+
+ f = DestroyMenu(hmenuVol);
+ if (!f)
+ {
+ daDebugOut((DEB_ERROR,"DestroyMenu failed!\n"));
+ }
+}
+
+
+#ifdef WINDISK_EXTENSIONS
+
+//+---------------------------------------------------------------------------
+//
+// Function: AddExtensionItemsToDiskMenu
+//
+// Synopsis: Adds an extension menu item to both the menu bar and the
+// given context menu.
+//
+// Arguments: [hmenuContext] -- context menu to add item to
+// [pMenu] -- pointer to extension menu item
+// [fFlags] -- standard menu flags (probably
+// MF_ENABLED or MF_GRAYED)
+//
+// Returns: Count of items added
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+INT
+AddExtensionItemsToDiskMenu(
+ IN HMENU hmenuContext,
+ IN MenuType* pMenu,
+ IN BOOL fFlags
+ )
+{
+ INT i;
+
+ for (i=0; i<pMenu->cMenuItems; i++)
+ {
+ MenuItemType* pItem = &(pMenu->aMenuItems[i]);
+
+ INT id = ContextMenuItems.AllocateId(pItem); //get the ID
+
+ if (-1 == id)
+ {
+ daDebugOut((DEB_ERROR,
+ "Couldn't add '%ws' to context menu\n",
+ pItem->pszMenu
+ ));
+ }
+ else
+ {
+ daDebugOut((DEB_ITRACE,
+ "Add '%ws' to context menu as item %d\n",
+ pItem->pszMenu,
+ (UINT)id
+ ));
+
+ BOOL f = AppendMenu(
+ hmenuContext,
+ MF_STRING | fFlags,
+ (UINT)id,
+ pItem->pszMenu);
+
+ if (!f)
+ {
+ daDebugOut((DEB_ERROR,"AppendMenu failed!\n"));
+ }
+ }
+ }
+
+ return pMenu->cMenuItems;
+}
+
+#endif // WINDISK_EXTENSIONS
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: DiskContextMenu, public
+//
+// Synopsis: Create a context menu for a disk selection
+//
+// Arguments: [ppt] -- ptr to screen coordinates of point to put
+// context menu at
+//
+// Returns: nothing?
+//
+// History: 24-May-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+VOID
+DiskContextMenu(
+ IN PPOINT ppt
+ )
+{
+ //BUGBUG: no disk context menu will be allowed until we have an
+ // interesting operation to perform
+ return;
+
+//BUGBUG!!!!!!!!!!!!!!!!!
+#if 0
+
+ ////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////
+
+ daDebugOut((DEB_ITRACE,"Disk context menu for disk %d\n", LBIndexToDiskNumber(g_MouseLBIndex)));
+
+#ifdef WINDISK_EXTENSIONS
+ ContextMenuItems.DeAllocateMenuIds(); // get rid of what we had last time
+#endif // WINDISK_EXTENSIONS
+
+ BOOL f;
+ BOOL fAnyHardDiskExtensionItems = FALSE;
+
+ //
+ // Create the menu
+ //
+
+ HMENU hmenuDisk = CreatePopupMenu();
+
+ if (NULL == hmenuDisk)
+ {
+ daDebugOut((DEB_ERROR,"CreatePopupMenu failed!\n"));
+ return;
+ }
+
+ // add the hard disk specific items
+
+////////////////////////////////////////////////////////////////////////
+
+#ifdef WINDISK_EXTENSIONS
+
+ //
+ // Add hard disk operations
+ //
+
+ PHARDDISK_CLAIM_LIST hdclaims = DiskArray[LBIndexToDiskNumber(g_MouseLBIndex)]->pClaims;
+
+ if (NULL != hdclaims)
+ {
+ fAnyHardDiskExtensionItems = TRUE;
+ }
+
+ while (NULL != hdclaims)
+ {
+ AddExtensionItemsToDiskMenu(
+ hmenuDisk,
+ &(hdclaims->pClaimer->pInfo->mnuOps),
+ MF_ENABLED
+ );
+
+ hdclaims = hdclaims->pNext;
+ }
+
+#endif // WINDISK_EXTENSIONS
+
+ //
+ // append the "Properties..." entry
+ //
+
+ TCHAR szText[MAXMENUTEXTLEN];
+
+ if (0 != LoadString(
+ g_hInstance,
+ IDS_PROPERTIES,
+ szText,
+ ARRAYLEN(szText)))
+ {
+ if (fAnyHardDiskExtensionItems)
+ {
+ f = AppendMenu(hmenuDisk, MF_SEPARATOR, 0, NULL);
+
+ if (!f)
+ {
+ daDebugOut((DEB_ERROR,"AppendMenu failed!\n"));
+ }
+ }
+
+ f = AppendMenu(
+ hmenuDisk,
+ MF_STRING | MF_DISABLED, //BUGBUG: disable disk property sheet
+ IDM_PROPERTIES,
+ szText
+ );
+
+ if (!f)
+ {
+ daDebugOut((DEB_ERROR,"AppendMenu failed!\n"));
+ }
+ }
+
+ //
+ // if there's nothing on the menu, say "<< no operations >>"
+ //
+
+ if (0 == GetMenuItemCount(hmenuDisk))
+ {
+ TCHAR Buffer[MAX_RESOURCE_STRING_LEN];
+
+ LoadString(
+ g_hInstance,
+ IDS_NOOPERATIONS,
+ Buffer,
+ ARRAYLEN(Buffer));
+
+ f = AppendMenu(hmenuDisk, MF_STRING | MF_DISABLED, 0, Buffer);
+
+ if (!f)
+ {
+ daDebugOut((DEB_ERROR,"AppendMenu failed!\n"));
+ }
+ }
+
+ //
+ // Display the menu
+ //
+
+ DoContextMenu(hmenuDisk, ppt);
+
+ //
+ // Destroy the menu
+ //
+
+ f = DestroyMenu(hmenuDisk);
+ if (!f)
+ {
+ daDebugOut((DEB_ERROR,"DestroyMenu failed!\n"));
+ }
+
+//BUGBUG!!!!!!!!!!
+#endif //0
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: HitTestLegend
+//
+// Synopsis: See if the point is in the legend space
+//
+// Arguments: [ppt] -- ptr to client coordinates of point
+//
+// Returns: TRUE if point is in legend area
+//
+// History: 31-Aug-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+BOOL
+HitTestLegend(
+ IN PPOINT ppt
+ )
+{
+ if (!g_Legend || (g_WhichView == VIEW_VOLUMES))
+ {
+ return FALSE;
+ }
+
+ POINT pt = *ppt;
+
+ RECT rc;
+ GetClientRect(g_hwndFrame,&rc);
+
+ if (g_StatusBar)
+ {
+ rc.bottom -= g_dyStatus;
+ }
+
+ rc.top = rc.bottom - g_dyLegend;
+
+ return PtInRect(&rc, pt);
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: LegendContextMenu, public
+//
+// Synopsis: Create a context menu to invoke the colors and patterns
+// options menu
+//
+// Arguments: [ppt] -- ptr to screen coordinates of point to put
+// context menu at
+//
+// Returns: nothing?
+//
+// History: 31-Aug-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+VOID
+LegendContextMenu(
+ IN PPOINT ppt
+ )
+{
+ BOOL f;
+
+ //
+ // Create the menu
+ //
+
+ HMENU hmenu = CreatePopupMenu();
+
+ if (NULL == hmenu)
+ {
+ daDebugOut((DEB_ERROR,"CreatePopupMenu failed!\n"));
+ return;
+ }
+
+ f = MyAppendMenu(hmenu, IDM_OPTIONSCOLORS);
+
+ if (!f)
+ {
+ daDebugOut((DEB_ERROR,"AppendMenu failed!\n"));
+ }
+
+ //
+ // Display the menu
+ //
+
+ DoContextMenu(hmenu, ppt);
+
+ //
+ // Destroy the menu
+ //
+
+ f = DestroyMenu(hmenu);
+ if (!f)
+ {
+ daDebugOut((DEB_ERROR,"DestroyMenu failed!\n"));
+ }
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: ContextMenu, public
+//
+// Synopsis: Create a context menu. Determines which type of context
+// menu should be displayed, based on the current selection.
+// The selection variables (SelectionCount, SelectDS, SelectRG)
+// must be valid.
+//
+// Arguments: [ppt] -- pointer to a point (in screen coordinates) for
+// the upper-left corner of the menu
+//
+// Returns: -1 if nothing chosen, or the 0-based index of the item selected
+//
+// History: 22-Jun-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+VOID
+ContextMenu(
+ IN PPOINT ppt
+ )
+{
+ //
+ // At this point, the selection state is already determined. Use
+ // the selection to determine which context menu is appropriate to
+ // invoke.
+ //
+
+ if (0 == SelectionCount + CdRomCount)
+ {
+ return; // nothing selected, so no context menu
+ }
+
+ VolumeContextMenu(ppt);
+}
diff --git a/private/utils/windisk/src/cm.hxx b/private/utils/windisk/src/cm.hxx
new file mode 100644
index 000000000..329a3512d
--- /dev/null
+++ b/private/utils/windisk/src/cm.hxx
@@ -0,0 +1,37 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: cm.hxx
+//
+// Contents: Context menu headers
+//
+// History: 31-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __CM_HXX__
+#define __CM_HXX__
+
+VOID
+DiskContextMenu(
+ IN PPOINT ppt
+ );
+
+VOID
+LegendContextMenu(
+ IN PPOINT ppt
+ );
+
+BOOL
+HitTestLegend(
+ IN PPOINT ppt
+ );
+
+VOID
+ContextMenu(
+ IN PPOINT ppt
+ );
+
+#endif // __CM_HXX__
diff --git a/private/utils/windisk/src/commit.cxx b/private/utils/windisk/src/commit.cxx
new file mode 100644
index 000000000..8ca57df8c
--- /dev/null
+++ b/private/utils/windisk/src/commit.cxx
@@ -0,0 +1,1849 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: commit.cxx
+//
+// Contents: This module contains the set of routines that support
+// the commitment of changes to disk without rebooting.
+//
+// History: 15-Nov-93 Bob Rinne Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+extern "C"
+{
+#include <ntddcdrm.h>
+
+#pragma warning(4:4091)
+#include <ntddscsi.h>
+#pragma warning(default:4091)
+}
+
+#include "commit.hxx"
+#include "drives.hxx"
+#include "ft.hxx"
+#include "init.hxx"
+#include "nt.hxx"
+#include "fill.hxx"
+#include "network.hxx"
+#include "ntlow.hxx"
+#include "ops.hxx"
+#include "scsi.h"
+#include "windisk.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+BOOLEAN CommitDueToDelete = FALSE;
+BOOLEAN CommitDueToMirror = FALSE;
+BOOLEAN CommitDueToExtended = FALSE;
+BOOLEAN CommitDueToCreate = FALSE;
+
+// If a mirror is made of the boot partition, this will become
+// non-zero and indicate which disk should get some boot code in
+// the MBR.
+
+ULONG UpdateMbrOnDisk = 0;
+
+// Lock list chain head for deleted partitions.
+
+PDRIVE_LOCKLIST DriveLockListHead = NULL;
+
+PASSIGN_LIST AssignDriveLetterListHead = NULL;
+
+//////////////////////////////////////////////////////////////////////////////
+
+extern HANDLE DisplayMutex;
+extern ULONG DisplayUpdateCount;
+extern DWORD RefreshAllowed;
+
+VOID
+CommitToAssignLetterList(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN BOOLEAN MoveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ Remember this region for assigning a drive letter to it upon commit.
+
+Arguments:
+
+ RegionDescriptor - the region to watch
+ MoveLetter - indicate that the region letter is already
+ assigned to a different partition, therefore
+ it must be "moved".
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PASSIGN_LIST newListEntry;
+ PPERSISTENT_REGION_DATA regionData;
+
+ regionData = PERSISTENT_DATA(RegionDescriptor);
+ FDASSERT(NULL != regionData);
+
+ newListEntry = (PASSIGN_LIST) Malloc(sizeof(ASSIGN_LIST));
+
+ newListEntry->OriginalLetter = regionData->DriveLetter;
+ newListEntry->DriveLetter = regionData->DriveLetter;
+ newListEntry->DiskNumber = RegionDescriptor->Disk;
+ newListEntry->MoveLetter = MoveLetter;
+
+ // place it at the front of the chain.
+
+ newListEntry->Next = AssignDriveLetterListHead;
+ AssignDriveLetterListHead = newListEntry;
+}
+
+VOID
+CommitAssignLetterList(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Walk the assign drive letter list and make all drive letter assignments
+ expected. The regions data structures are moved around, so no pointer
+ can be maintained to look at them. To determine the partition number
+ for a new partition in this list, the Disks[] structure must be searched
+ to find a match on the partition for the drive letter. Then the partition
+ number will be known.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PREGION_DESCRIPTOR regionDescriptor;
+ PPERSISTENT_REGION_DATA regionData;
+ PDISKSTATE diskState;
+ PASSIGN_LIST assignList,
+ prevEntry;
+ WCHAR newDriveName[3];
+ WCHAR targetPath[100];
+ ULONG partitionNumber;
+ ULONG index;
+
+ assignList = AssignDriveLetterListHead;
+ AssignDriveLetterListHead = NULL;
+ while (NULL != assignList)
+ {
+ diskState = DiskArray[assignList->DiskNumber];
+ partitionNumber = 0;
+ for (index = 0; index < diskState->RegionCount; index++)
+ {
+ regionDescriptor = &diskState->RegionArray[index];
+
+ if (DmSignificantRegion(regionDescriptor))
+ {
+ regionData = PERSISTENT_DATA(regionDescriptor);
+
+ if (NULL != regionData)
+ {
+ if (regionData->DriveLetter == assignList->DriveLetter)
+ {
+ partitionNumber = regionDescriptor->Reserved->Partition->PartitionNumber;
+ regionDescriptor->PartitionNumber = partitionNumber;
+ break;
+ }
+ }
+ }
+ }
+
+ if (!IsExtraDriveLetter(assignList->DriveLetter)) {
+
+ if (0 != partitionNumber)
+ {
+ HANDLE handle;
+ ULONG status;
+
+ // first, fix up drive letter data structures
+
+ if (assignList->MoveLetter)
+ {
+ MarkDriveLetterFree(assignList->OriginalLetter);
+ }
+
+ NewDriveLetter(
+ assignList->DriveLetter,
+ assignList->DiskNumber,
+ partitionNumber);
+
+ // now, do the NT object stuff
+
+ // set up the new NT path.
+
+ wsprintf(targetPath,
+ TEXT("%hs\\Partition%d"),
+ GetDiskName(assignList->DiskNumber),
+ partitionNumber);
+
+ newDriveName[1] = L':';
+ newDriveName[2] = L'\0';
+
+ if (assignList->MoveLetter)
+ {
+ // The letter must be removed before it can be assigned.
+
+ newDriveName[0] = assignList->OriginalLetter;
+ NetworkRemoveShare(newDriveName);
+ DefineDosDevice(DDD_REMOVE_DEFINITION, newDriveName, NULL);
+ }
+
+ newDriveName[0] = assignList->DriveLetter;
+
+ // Assign the name - don't worry about errors for now.
+
+ DefineDosDevice(DDD_RAW_TARGET_PATH, newDriveName, targetPath);
+ NetworkShare(newDriveName);
+
+ // Some of the file systems do not actually dismount
+ // when requested. Instead, they set a verification
+ // bit in the device object. Due to dynamic partitioning
+ // this bit may get cleared by the process of the
+ // repartitioning and the file system will then
+ // assume it is still mounted on a new access.
+ // To get around this problem, new drive letters
+ // are always locked and dismounted on creation.
+
+ status = LowOpenDriveLetter(assignList->DriveLetter,
+ &handle);
+
+ if (NT_SUCCESS(status))
+ {
+ // Lock the drive to insure that no other access is occurring
+ // to the volume.
+
+ status = LowLockDrive(handle);
+
+ if (NT_SUCCESS(status))
+ {
+ LowUnlockDrive(handle);
+ }
+ LowCloseDisk(handle);
+ }
+ }
+ else
+ {
+ ErrorDialog(MSG_INTERNAL_LETTER_ASSIGN_ERROR);
+ }
+ }
+
+ prevEntry = assignList;
+ assignList = assignList->Next;
+ Free(prevEntry);
+ }
+}
+
+
+LONG
+CommitInternalLockDriveLetter(
+ IN PDRIVE_LOCKLIST LockListEntry
+ )
+
+/*++
+
+Routine Description:
+
+ Support routine to perform the locking of a drive letter based on
+ the locklist entry given.
+
+Arguments:
+
+ LockListEntry - The information about what to lock.
+
+Return Values:
+
+ zero - success
+ non-zero failure
+
+--*/
+
+{
+ ULONG status;
+
+ // Lock the disk and save the handle.
+
+ status = LowOpenDriveLetter(LockListEntry->DriveLetter, &LockListEntry->LockHandle);
+
+ if (!NT_SUCCESS(status))
+ {
+ return 1;
+ }
+
+
+ // Lock the drive to insure that no other access is occurring
+ // to the volume.
+
+ status = LowLockDrive(LockListEntry->LockHandle);
+
+ if (!NT_SUCCESS(status))
+ {
+ LowCloseDisk(LockListEntry->LockHandle);
+ return 1;
+ }
+
+ LockListEntry->CurrentlyLocked = TRUE;
+ return 0;
+}
+
+
+VOID
+CommitNewRegions(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This converts all regions to be non-new regions after a commit. It
+ redraws the screen to reflect the commit.
+
+Arguments:
+
+ None.
+
+Return Values:
+
+ None.
+
+--*/
+
+{
+ ULONG diskNum;
+ ULONG regionNum;
+ PDISKSTATE diskState;
+ PREGION_DESCRIPTOR regionDescriptor;
+ PPERSISTENT_REGION_DATA regionData;
+
+ for (diskNum = 0; diskNum < DiskCount; diskNum++)
+ {
+ diskState = DiskArray[diskNum];
+
+ for (regionNum = 0; regionNum < diskState->RegionCount; regionNum++)
+ {
+ regionDescriptor = &diskState->RegionArray[regionNum];
+ regionData = PERSISTENT_DATA(regionDescriptor);
+
+ if (NULL != regionDescriptor->Reserved)
+ {
+ if (NULL != regionDescriptor->Reserved->Partition)
+ {
+ regionDescriptor->Reserved->Partition->CommitMirrorBreakNeeded = FALSE;
+ }
+ }
+
+ if (NULL != regionData)
+ {
+ if (regionData->NewRegion)
+ {
+ regionData->NewRegion = FALSE;
+ }
+ }
+ }
+ }
+
+ //
+ // Now, refresh the views. The visualization of non-new regions is
+ // different from that of new regions, so we need to redraw.
+ //
+
+ RefreshBothViews();
+}
+
+
+LONG
+CommitToLockList(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN BOOL RemoveDriveLetter,
+ IN BOOL LockNow,
+ IN BOOL FailOk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds the given drive into the lock list for processing
+ when a commit occurs. If the LockNow flag is set it indicates that
+ the drive letter is to be immediately locked if it is to go in the
+ lock letter list. If this locking fails an error is returned.
+
+Arguments:
+
+ RegionDescriptor - the region for the drive to lock.
+ RemoveDriveLetter - remove the letter when performing the unlock.
+ LockNow - If the letter is inserted in the list - lock it now.
+ FailOk - It is ok to fail the lock - used for disabled FT sets.
+
+Return Values:
+
+ non-zero - failure to add to list.
+
+--*/
+
+{
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(RegionDescriptor);
+ PDRIVE_LOCKLIST lockListEntry;
+ WCHAR driveLetter;
+ ULONG diskNumber;
+
+ if (NULL == regionData)
+ {
+ // without region data there is no need to be on the lock list.
+
+ return 0;
+ }
+
+ // See if this drive letter is already in the lock list.
+
+ driveLetter = regionData->DriveLetter;
+
+ if (IsExtraDriveLetter(driveLetter))
+ {
+ // There is no drive letter to lock.
+
+ CommitDueToDelete = RemoveDriveLetter;
+ return 0;
+ }
+
+ if (regionData->NewRegion)
+ {
+ PASSIGN_LIST assignList, prevEntry;
+
+ // This item has never been created so no need to put it in the
+ // lock list. But it does need to be removed from the assign
+ // letter list.
+
+ prevEntry = NULL;
+ assignList = AssignDriveLetterListHead;
+ while (NULL != assignList)
+ {
+ // If a match is found remove it from the list.
+
+ if (assignList->DriveLetter == driveLetter)
+ {
+
+ //
+ // Free up the drive letter to be used. (Normally done
+ // in the final commit code.)
+ //
+
+ MarkDriveLetterFree(driveLetter);
+
+ if (NULL != prevEntry)
+ {
+ prevEntry->Next = assignList->Next;
+ }
+ else
+ {
+ AssignDriveLetterListHead = assignList->Next;
+ }
+
+ Free(assignList);
+ assignList = NULL;
+ }
+ else
+ {
+ prevEntry = assignList;
+ assignList = assignList->Next;
+ }
+ }
+ return 0;
+ }
+
+ diskNumber = RegionDescriptor->Disk;
+ lockListEntry = DriveLockListHead;
+ while (NULL != lockListEntry)
+ {
+ if (lockListEntry->DriveLetter == driveLetter)
+ {
+ // Already in the list -- update when to lock and unlock
+
+ if (diskNumber < lockListEntry->LockOnDiskNumber)
+ {
+ lockListEntry->LockOnDiskNumber = diskNumber;
+ }
+
+ if (diskNumber > lockListEntry->UnlockOnDiskNumber)
+ {
+ lockListEntry->UnlockOnDiskNumber = diskNumber;
+ }
+
+ // Already in the lock list and information for locking set up.
+ // Check to see if this should be a LockNow request.
+
+ if (LockNow)
+ {
+ if (!lockListEntry->CurrentlyLocked)
+ {
+ // Need to perform the lock.
+
+ if (CommitInternalLockDriveLetter(lockListEntry))
+ {
+ // Leave the element in the list
+
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+ }
+ lockListEntry = lockListEntry->Next;
+ }
+
+ // set up the lock list entry.
+
+ lockListEntry = (PDRIVE_LOCKLIST) Malloc(sizeof(DRIVE_LOCKLIST));
+
+ lockListEntry->LockHandle = NULL;
+ lockListEntry->PartitionNumber = RegionDescriptor->PartitionNumber;
+ lockListEntry->DriveLetter = driveLetter;
+ lockListEntry->RemoveOnUnlock = RemoveDriveLetter;
+ lockListEntry->FailOk = FailOk;
+ lockListEntry->CurrentlyLocked = FALSE;
+ lockListEntry->DiskNumber
+ = lockListEntry->UnlockOnDiskNumber
+ = lockListEntry->LockOnDiskNumber
+ = diskNumber;
+
+ if (LockNow)
+ {
+ if (CommitInternalLockDriveLetter(lockListEntry))
+ {
+ // Do not add this to the list.
+
+ Free(lockListEntry);
+ return 1;
+ }
+ }
+
+ // place it at the front of the chain.
+
+ lockListEntry->Next = DriveLockListHead;
+ DriveLockListHead = lockListEntry;
+ return 0;
+}
+
+LONG
+CommitLockVolumes(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will go through any drive letters inserted in the lock list
+ for the given disk number and attempt to lock the volumes.
+
+ Currently, this routine locks all of the drives letters in the lock list
+ when called the first time (i.e. when Disk == 0).
+
+Arguments:
+
+ Disk - the index into the disk table.
+
+Return Values:
+
+ non-zero - failure to lock the items in the list.
+
+--*/
+
+{
+ PDRIVE_LOCKLIST lockListEntry;
+
+ if (0 != Disk)
+ {
+ return 0;
+ }
+
+ for (lockListEntry = DriveLockListHead;
+ NULL != lockListEntry;
+ lockListEntry = lockListEntry->Next)
+ {
+ // Lock the disk. Return on any failure if that is the
+ // requested action for the entry. It is the responsibility
+ // of the caller to release any successful locks.
+
+ if (!lockListEntry->CurrentlyLocked)
+ {
+ if (CommitInternalLockDriveLetter(lockListEntry))
+ {
+ if (!lockListEntry->FailOk)
+ {
+ return 1;
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+LONG
+CommitUnlockVolumes(
+ IN ULONG Disk,
+ IN BOOLEAN FreeList
+ )
+
+/*++
+
+Routine Description:
+
+ Go through and unlock any locked volumes in the locked list for the
+ given disk.
+
+ Currently this routine waits until the last disk has been processed,
+ then unlocks all disks.
+
+Arguments:
+
+ Disk - the index into the disk table.
+ FreeList - Clean up the list as unlocks are performed or don't
+
+Return Values:
+
+ non-zero - failure to lock the items in the list.
+
+--*/
+
+{
+ PDRIVE_LOCKLIST lockListEntry,
+ previousLockListEntry;
+ WCHAR driveName[3];
+
+ if (Disk != GetDiskCount())
+ {
+ return 0;
+ }
+
+ lockListEntry = DriveLockListHead;
+ if (FreeList)
+ {
+ DriveLockListHead = NULL;
+ }
+
+ while (NULL != lockListEntry)
+ {
+ // Unlock the disk.
+
+ if (lockListEntry->CurrentlyLocked)
+ {
+ if (FreeList && lockListEntry->RemoveOnUnlock)
+ {
+ // set up the new dos name and NT path.
+
+ driveName[0] = lockListEntry->DriveLetter;
+ driveName[1] = L':';
+ driveName[2] = L'\0';
+
+ NetworkRemoveShare(driveName);
+ if (!DefineDosDevice(DDD_REMOVE_DEFINITION, driveName, NULL))
+ {
+ // could not remove name!!?
+ } else {
+
+ //
+ // We only mark the drive letter free after everything has
+ // been committed.
+ //
+
+ MarkDriveLetterFree(lockListEntry->DriveLetter);
+ }
+ }
+
+ LowUnlockDrive(lockListEntry->LockHandle);
+ LowCloseDisk(lockListEntry->LockHandle);
+ }
+
+ // Move to the next entry. If requested free this entry.
+
+ previousLockListEntry = lockListEntry;
+ lockListEntry = lockListEntry->Next;
+ if (FreeList)
+ {
+ Free(previousLockListEntry);
+ }
+ }
+ return 0;
+}
+
+
+BOOL
+CommitDriveLetter(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN WCHAR OldLetter,
+ IN WCHAR NewLetter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will update the drive letter information in the registry and
+ (if the update works) it will attempt to move the current drive letter
+ to the new one via DefineDosDevice()
+
+Arguments:
+
+ RegionDescriptor - the region that should get the letter.
+ OldLetter - the old drive letter for the volume.
+ NewLetter - the new drive letter for the volume.
+
+Return Value:
+
+ TRUE - if the assigning of the letter and the update of the
+ registry succeed.
+
+--*/
+
+{
+ PPERSISTENT_REGION_DATA regionData;
+ PDRIVE_LOCKLIST lockListEntry;
+ PASSIGN_LIST assignList;
+ HANDLE handle = INVALID_HANDLE_VALUE;
+ WCHAR driveName[3];
+ WCHAR targetPath[100];
+ int doIt;
+ BOOL result = FALSE;
+ STATUS_CODE status = ERROR_SEVERITY_ERROR;
+ BOOL changingBootDir = FALSE;
+ BOOL changingSystemDir = FALSE;
+
+ //
+ // Check if the old drive letter is the boot drive and the
+ // new drive letter is nothing. If it is, don't allow
+ // them to do that.
+ //
+
+ if ((OldLetter == BootDir) &&
+ (NewLetter == NO_DRIVE_LETTER_EVER)) {
+
+ ErrorDialog(MSG_BOOT_NEEDS_LETTER);
+ return FALSE;
+
+ }
+
+ //
+ // Check if the old drive letter points to the systemdir and
+ // the new drive letter is nothing. Don't let them do that.
+ //
+ // On x86 it is 99% certain to have been caught above.
+ //
+
+ if ((OldLetter == SystemDir) &&
+ (NewLetter == NO_DRIVE_LETTER_EVER)) {
+
+ ErrorDialog(MSG_SYS_NEEDS_LETTER);
+ return FALSE;
+
+ }
+
+
+
+ //
+ // Check if the old drive letter is the system drive. If it
+ // is put up a popup that says we don't think this is a very
+ // good idea.
+ //
+
+ if (OldLetter == SystemDir) {
+
+ doIt = ConfirmationDialog(
+ MSG_SYS_LETTER_CHANGE,
+ MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2);
+
+ if (doIt != IDYES) {
+
+ return FALSE;
+
+ }
+ changingSystemDir = TRUE;
+ }
+
+ changingBootDir = OldLetter == BootDir;
+
+
+ regionData = PERSISTENT_DATA(RegionDescriptor);
+ FDASSERT(NULL != regionData);
+
+ // check the assign letter list for a match.
+ // If the letter is there, then just update the list
+ // otherwise continue on with the action.
+
+ assignList = AssignDriveLetterListHead;
+ while (NULL != assignList)
+ {
+ if (assignList->DriveLetter == OldLetter)
+ {
+ assignList->DriveLetter = NewLetter;
+
+ // Change the drive letter data
+
+ MarkDriveLetterFree(OldLetter);
+ NewDriveLetter(
+ NewLetter,
+ RegionDescriptor->Disk,
+ RegionDescriptor->PartitionNumber);
+ WaitForSingleObject(DisplayMutex,INFINITE);
+ RefreshAllowed = 1;
+ ReleaseMutex(DisplayMutex);
+ DrawDiskBar(DiskArray[RegionDescriptor->Disk]);
+ return TRUE;
+ }
+ assignList = assignList->Next;
+ }
+
+// daDebugOut((DEB_ERROR,
+// "A new region didn't appear in the 'assign drive letter' list\n"));
+
+ //
+ // Search to see if the drive is currently locked.
+ //
+
+ for (lockListEntry = DriveLockListHead;
+ lockListEntry;
+ lockListEntry = lockListEntry->Next)
+ {
+ if ( (lockListEntry->DiskNumber == RegionDescriptor->Disk)
+ && (lockListEntry->PartitionNumber == RegionDescriptor->PartitionNumber))
+ {
+ if (lockListEntry->CurrentlyLocked)
+ {
+ status = 0;
+ }
+
+ // found the match no need to continue searching.
+
+ break;
+ }
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ // See if the drive can be locked.
+
+ status = LowOpenPartition(GetDiskName(RegionDescriptor->Disk),
+ RegionDescriptor->PartitionNumber,
+ &handle);
+
+ if (!NT_SUCCESS(status))
+ {
+ return FALSE;
+ }
+
+ // Lock the drive to insure that no other access is occurring
+ // to the volume.
+
+ status = LowLockDrive(handle);
+
+ if (!NT_SUCCESS(status))
+ {
+ LowCloseDisk(handle);
+
+ if (IsPagefileOnDrive(OldLetter))
+ {
+ ErrorDialog(MSG_CANNOT_LOCK_PAGEFILE);
+ }
+ else
+ {
+ ErrorDialog(MSG_CANNOT_LOCK_TRY_AGAIN);
+ }
+
+ doIt = ConfirmationDialog(
+ MSG_SCHEDULE_REBOOT,
+ MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2);
+
+ if (doIt == IDYES)
+ {
+ RegistryChanged = TRUE;
+ RestartRequired = TRUE;
+
+ // mark the new letter as used, but don't mark the old letter
+ // as free (since it is still currently in use)
+
+ NewDriveLetter(
+ NewLetter,
+ RegionDescriptor->Disk,
+ RegionDescriptor->PartitionNumber);
+
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+ }
+ else
+ {
+ // This drive was found in the lock list and is already
+ // in the locked state. It is safe to continue with
+ // the drive letter assignment.
+
+ //
+ // Note that we DON'T have a valid handle. So if things
+ // don't go well, DON'T try to free it.
+ //
+
+ }
+
+ if (!RegionDescriptor->PartitionNumber) {
+
+ ErrorDialog(MSG_INTERNAL_LETTER_ASSIGN_ERROR);
+ if (handle != INVALID_HANDLE_VALUE) {
+
+ LowUnlockDrive(handle);
+ LowCloseDisk(handle);
+
+ }
+ return FALSE;
+
+ }
+
+ // Warn the user that the rename will happen immediately, and confirm
+ // that it is ok to perform the rename.
+
+ doIt = ConfirmationDialog(
+ MSG_DRIVE_RENAME_WARNING,
+ MB_ICONQUESTION | MB_YESNOCANCEL | MB_DEFBUTTON2);
+
+ if (doIt != IDYES)
+ {
+ if (handle != INVALID_HANDLE_VALUE) {
+
+ LowUnlockDrive(handle);
+ LowCloseDisk(handle);
+ return FALSE;
+
+ }
+ }
+
+ // Update the registry first. This way if something goes wrong
+ // the new letter will arrive on reboot.
+
+ if (!DiskRegistryAssignDriveLetter(
+ DiskArray[RegionDescriptor->Disk]->Signature,
+ FdGetExactOffset(RegionDescriptor),
+ FdGetExactSize(RegionDescriptor, FALSE),
+ (NewLetter == NO_DRIVE_LETTER_EVER)
+ ? (UCHAR)' '
+ : (UCHAR)NewLetter))
+ {
+ // Registry update failed.
+
+ return FALSE;
+ }
+
+ // It is safe to change the drive letter. First, remove the
+ // existing letter.
+
+ driveName[0] = OldLetter;
+ driveName[1] = L':';
+ driveName[2] = L'\0';
+
+ NetworkRemoveShare(driveName);
+ if (!DefineDosDevice(DDD_REMOVE_DEFINITION, driveName, NULL))
+ {
+
+ if (handle != INVALID_HANDLE_VALUE) {
+
+ LowUnlockDrive(handle);
+ LowCloseDisk(handle);
+
+ }
+ RegistryChanged = TRUE;
+ return FALSE;
+ }
+
+ MarkDriveLetterFree(OldLetter);
+
+ result = FALSE;
+
+ if (NewLetter != NO_DRIVE_LETTER_EVER)
+ {
+ // set up the new dos name and NT path.
+
+ wsprintf(targetPath,
+ TEXT("%hs\\Partition%d"),
+ GetDiskName(RegionDescriptor->Disk),
+ RegionDescriptor->PartitionNumber);
+
+ driveName[0] = NewLetter;
+ driveName[1] = L':';
+ driveName[2] = L'\0';
+
+ if (DefineDosDevice(DDD_RAW_TARGET_PATH, driveName, targetPath))
+ {
+ result = TRUE;
+
+ if (changingSystemDir) {
+
+ SystemDir = NewLetter;
+
+ }
+
+ if (changingBootDir) {
+
+ WCHAR driveLetterBuffer[MAX_PATH+1] = {(WCHAR)0};
+ UNICODE_STRING driveLetterString;
+
+ RTL_QUERY_REGISTRY_TABLE driveLetterTable[2] = {0};
+
+ driveLetterString.Length = 0;
+ driveLetterString.MaximumLength = sizeof(WCHAR)*MAX_PATH;
+ driveLetterString.Buffer = (PWCHAR)&driveLetterBuffer[0];
+ driveLetterTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT |
+ RTL_QUERY_REGISTRY_REQUIRED;
+ driveLetterTable[0].Name = L"BootDir";
+ driveLetterTable[0].EntryContext = &driveLetterString;
+
+ if (NT_SUCCESS(RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
+ L"\\REGISTRY\\MACHINE\\SOFTWARE\\MICROSOFT\\WINDOWS\\CURRENTVERSION\\SETUP",
+ &driveLetterTable[0],
+ NULL,
+ NULL
+ ))) {
+
+ driveLetterBuffer[0] = NewLetter;
+
+ RtlWriteRegistryValue(
+ RTL_REGISTRY_ABSOLUTE,
+ L"\\REGISTRY\\MACHINE\\SOFTWARE\\MICROSOFT\\WINDOWS\\CURRENTVERSION\\SETUP",
+ L"BootDir",
+ REG_SZ,
+ &driveLetterBuffer[0],
+ driveLetterString.Length+sizeof(WCHAR)
+ );
+
+ BootDir = NewLetter;
+ }
+ }
+ }
+ else
+ {
+ RegistryChanged = TRUE;
+ }
+ NetworkShare(driveName);
+
+ NewDriveLetter(
+ NewLetter,
+ RegionDescriptor->Disk,
+ RegionDescriptor->PartitionNumber);
+ }
+ else
+ {
+ //
+ // If we don't need to assign a drive letter, then don't do anything
+ //
+
+ result = TRUE;
+ }
+
+ // Force the file system to dismount
+
+ if (handle != INVALID_HANDLE_VALUE) {
+
+ LowUnlockDrive(handle);
+ LowCloseDisk(handle);
+
+ }
+ return result;
+}
+
+
+DWORD
+CommitChanges(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine updates the disks to reflect changes made by the user
+ the partitioning scheme, or to stamp signatures on disks.
+
+ If the partitioning scheme on a disk has changed at all, a check will
+ first be made for a valid signature on the mbr in sector 0. If the
+ signature is not valid, x86 boot code will be written to the sector.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Windows error code
+
+--*/
+
+{
+ UINT i;
+ DWORD ec;
+ DWORD rc = NO_ERROR;
+
+ for (i=0; i<DiskCount; i++)
+ {
+ if (HavePartitionsBeenChanged(i))
+ {
+ ec = MasterBootCode(i, 0, TRUE, FALSE);
+
+ // MasterBootCode has already translated the NT error
+ // status into a Windows error status.
+
+ if (rc == NO_ERROR)
+ {
+ rc = ec; // save first non-success return code
+ }
+
+ ec = CommitPartitionChanges(i);
+
+ // CommitPartitionChanges returns a native NT error, it
+ // must be translated before it can be saved.
+
+ if (ec != NO_ERROR) {
+ ec = RtlNtStatusToDosError(ec);
+ }
+ if (rc == NO_ERROR)
+ {
+ rc = ec; // save first non-success return code
+ }
+ }
+ }
+ if (rc != NO_ERROR)
+ {
+ // If CommitPartitionChanges returns an error, it will be
+ // an NT status, which needs to be converted to a DOS status.
+ //
+ rc = RtlNtStatusToDosError(rc);
+
+ if (rc == ERROR_MR_MID_NOT_FOUND)
+ {
+ ErrorDialog(MSG_ERROR_DURING_COMMIT);
+ }
+ else
+ {
+ ErrorDialog(rc);
+ }
+ }
+
+ return rc;
+}
+
+
+UINT
+CommitAllChanges(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will go through all of the region descriptors and commit
+ any changes that have occurred to disk. Then it "re-initializes"
+ Disk Administrator and start the display/work process over again.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ 0 -- the user chose to cancel the commit operation
+ 1 -- the commit operation happened (either things were committed or the
+ user chose not to save changes) and the profile was written, but
+ we couldn't reboot
+ 2 -- the commit operation happened (either things were committed or the
+ user chose not to save changes) and the profile was NOT written
+
+--*/
+
+{
+ DWORD action,
+ errorCode;
+ ULONG diskNum,
+ diskCount;
+ BOOL profileWritten,
+ changesMade,
+ mustReboot,
+ configureFt;
+
+ // Determine whether any disks have been changed, and whether
+ // the system must be rebooted. The system must be rebooted
+ // if the registry has changed, if any non-removable disk has
+ // changed, or if any removable disk that was not originally
+ // unpartitioned has changed.
+
+ configureFt = FALSE;
+ changesMade = FALSE;
+ mustReboot = RestartRequired;
+ diskCount = GetDiskCount();
+
+ for (diskNum = 0; diskNum < diskCount; diskNum++)
+ {
+ if (HavePartitionsBeenChanged(diskNum))
+ {
+ changesMade = TRUE;
+ break;
+ }
+ }
+
+ profileWritten = FALSE;
+
+ // Determine if the commit can be done without a reboot.
+
+ // If FT is in the system then it must be notified to
+ // reconfigure if a reboot is not performed. If it is
+ // not in the system, but the new disk information requires
+ // it, then a reboot must be forced.
+
+ if (FtInstalled())
+ {
+ configureFt = TRUE;
+ }
+
+ if (NewConfigurationRequiresFt())
+ {
+ if (!configureFt)
+ {
+ // The FT driver is not loaded currently.
+
+ mustReboot = TRUE;
+ }
+ else
+ {
+ // If the system is going to be rebooted, don't
+ // have FT reconfigure prior to shutdown.
+
+ if (mustReboot)
+ {
+ configureFt = FALSE;
+ }
+ }
+ }
+
+ if (RegistryChanged || changesMade || RestartRequired)
+ {
+ //
+ // BUGBUG: if we must reboot, then say so.
+ //
+
+ if (RestartRequired)
+ {
+ action = IDYES;
+ }
+ else
+ {
+ action = ConfirmationDialog(
+ MSG_CONFIRM_EXIT,
+ MB_ICONQUESTION | MB_YESNOCANCEL | MB_DEFBUTTON2);
+ }
+
+ if (action == IDYES)
+ {
+ errorCode = CommitLockVolumes(0);
+ if (errorCode)
+ {
+ // could not lock all volumes
+
+ ErrorDialog(MSG_CANNOT_LOCK_FOR_COMMIT);
+ CommitUnlockVolumes(diskCount, FALSE);
+ return 0;
+ }
+
+ if (mustReboot)
+ {
+ if (!RestartRequired)
+ {
+ action = ConfirmationDialog(
+ MSG_REQUIRE_REBOOT,
+ MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2);
+ if (action == IDNO)
+ {
+ CommitUnlockVolumes(diskCount, FALSE);
+ return 0;
+ }
+ }
+ }
+
+ SetCursor(g_hCurWait);
+ errorCode = CommitChanges();
+ CommitUnlockVolumes(diskCount, TRUE);
+ SetCursor(g_hCurNormal);
+
+ if (errorCode != NO_ERROR)
+ {
+ ErrorDialog(MSG_BAD_CONFIG_SET);
+ PostQuitMessage(0);
+ }
+ else
+ {
+ ULONG oldBootPartitionNumber;
+ ULONG newBootPartitionNumber;
+ DWORD msgCode;
+
+ // Update the configuration registry
+
+ errorCode = SaveFt();
+
+ // Check if FTDISK driver should reconfigure.
+
+ if (configureFt)
+ {
+ // Issue device control to ftdisk driver to reconfigure.
+
+ FtConfigure();
+ }
+
+ // Register autochk to fix up file systems
+ // in newly extended volume sets, if necessary
+
+ if (RegisterFileSystemExtend())
+ {
+ mustReboot = TRUE;
+ }
+
+ // Determine if the FT driver must be enabled.
+
+ if (DiskRegistryRequiresFt())
+ {
+ if (!FtInstalled())
+ {
+ mustReboot = TRUE;
+ }
+ DiskRegistryEnableFt();
+ }
+ else
+ {
+ DiskRegistryDisableFt();
+ }
+
+ if (errorCode == NO_ERROR)
+ {
+ InfoDialog(MSG_OK_COMMIT);
+ }
+ else
+ {
+ ErrorDialog(MSG_BAD_CONFIG_SET);
+ }
+
+ // Has the partition number of the boot partition changed?
+
+ if (BootPartitionNumberChanged(
+ &oldBootPartitionNumber,
+ &newBootPartitionNumber))
+ {
+ WCHAR oldNumberString[8];
+ WCHAR newNumberString[8];
+#if i386
+ msgCode = MSG_BOOT_PARTITION_CHANGED_X86;
+#else
+ msgCode = MSG_BOOT_PARTITION_CHANGED_ARC;
+#endif
+ wsprintf(oldNumberString, L"%d", oldBootPartitionNumber);
+ wsprintf(newNumberString, L"%d", newBootPartitionNumber);
+ InfoDialog(msgCode, oldNumberString, newNumberString);
+ }
+
+ ClearCommittedDiskInformation();
+
+ if (0 != UpdateMbrOnDisk)
+ {
+ UpdateMasterBootCode(UpdateMbrOnDisk);
+ UpdateMbrOnDisk = 0;
+ }
+
+ // Reboot if necessary.
+
+ if (mustReboot)
+ {
+ SetCursor(g_hCurWait);
+ Sleep(5000);
+ SetCursor(g_hCurNormal);
+ FdShutdownTheSystem();
+
+ // If we get here, then the system couldn't be shut
+ // down. However, the profile has already been written,
+ // so don't bother writing it again.
+
+ profileWritten = TRUE;
+ }
+
+ CommitAssignLetterList();
+ CommitNewRegions();
+
+ //
+ // reset this flag: we've committed registry changes
+ //
+
+ RegistryChanged = FALSE;
+
+ CommitDueToDelete = FALSE;
+ CommitDueToMirror = FALSE;
+ CommitDueToExtended = FALSE;
+ CommitDueToCreate = FALSE;
+ }
+ }
+ else if (action == IDCANCEL)
+ {
+ return 0;
+ }
+ else
+ {
+ FDASSERT(action == IDNO);
+ }
+ }
+
+ return (profileWritten ? 1 : 2);
+}
+
+VOID
+FtConfigure(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine calls the FTDISK driver to ask it to reconfigure as changes
+ have been made in the registry.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ OBJECT_ATTRIBUTES objectAttributes;
+ STRING ntFtName;
+ IO_STATUS_BLOCK statusBlock;
+ UNICODE_STRING unicodeDeviceName;
+ NTSTATUS status;
+ HANDLE handle;
+
+ // Open ft control object.
+
+ RtlInitString(&ntFtName, "\\Device\\FtControl");
+ RtlAnsiStringToUnicodeString(&unicodeDeviceName, &ntFtName, TRUE);
+ InitializeObjectAttributes(&objectAttributes,
+ &unicodeDeviceName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ status = DmOpenFile(&handle,
+ SYNCHRONIZE | FILE_ANY_ACCESS,
+ &objectAttributes,
+ &statusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT);
+ RtlFreeUnicodeString(&unicodeDeviceName);
+
+ if (!NT_SUCCESS(status))
+ {
+ return;
+ }
+
+ // Issue device control to reconfigure FT.
+
+ NtDeviceIoControlFile(handle,
+ NULL,
+ NULL,
+ NULL,
+ &statusBlock,
+ FT_CONFIGURE,
+ NULL,
+ 0L,
+ NULL,
+ 0L);
+
+ DmClose(handle);
+ return;
+}
+
+
+
+BOOL
+CommitAllowed(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Determine if it is ok to perform a commit.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ TRUE if it is ok to commit and there is something to commit
+ FALSE otherwise
+
+--*/
+
+{
+ if ( NULL != DriveLockListHead
+ || NULL != AssignDriveLetterListHead
+ || CommitDueToDelete
+ || CommitDueToMirror
+ || CommitDueToExtended
+ || CommitDueToCreate)
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+
+VOID
+RescanDevices(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine performs all actions necessary to dynamically rescan
+ device buses (i.e. SCSI) and get the appropriate driver support loaded.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ #define SCSI_INFO_BUFFER_SIZE 0x4000
+
+ PSCSI_ADAPTER_BUS_INFO adapterInfo;
+ PSCSI_BUS_DATA busData;
+ PSCSI_INQUIRY_DATA inquiryData;
+ WCHAR deviceName[32];
+ WCHAR physicalName[32];
+ HANDLE volumeHandle;
+ UNICODE_STRING unicodeString;
+ UNICODE_STRING physicalString;
+ OBJECT_ATTRIBUTES objectAttributes;
+ NTSTATUS ntStatus;
+ IO_STATUS_BLOCK statusBlock;
+ BOOLEAN diskFound = FALSE;
+ BOOLEAN cdromFound = FALSE;
+ ULONG bytesTransferred;
+ ULONG i, j;
+ ULONG deviceNumber;
+ ULONG currentPort;
+ ULONG numberOfPorts = 0;
+ ULONG percentComplete = 0;
+ ULONG portNumber = 0;
+
+ while (TRUE)
+ {
+ wsprintf(deviceName, TEXT("\\\\.\\Scsi%d:"), portNumber);
+
+ // Open the SCSI port with the DOS name.
+
+ volumeHandle = CreateFile(deviceName,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ 0);
+
+ if (volumeHandle == INVALID_HANDLE_VALUE)
+ {
+ break;
+ }
+
+ CloseHandle(volumeHandle);
+ ++numberOfPorts;
+ ++portNumber;
+ }
+
+ currentPort = 1;
+ portNumber = 0;
+
+ // Perform the scsi bus rescan
+
+ while (TRUE)
+ {
+ wsprintf(deviceName, TEXT("\\\\.\\Scsi%d:"), portNumber);
+
+ // Open the SCSI port with the DOS name.
+
+ volumeHandle = CreateFile(deviceName,
+ GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ 0);
+
+ if (volumeHandle == INVALID_HANDLE_VALUE)
+ {
+ break;
+ }
+
+ // Issue rescan device control.
+
+ if (!DeviceIoControl(volumeHandle,
+ IOCTL_SCSI_RESCAN_BUS,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &bytesTransferred,
+ NULL))
+ {
+ CloseHandle(volumeHandle);
+
+ break;
+ }
+
+ percentComplete = (currentPort * 100) / numberOfPorts;
+
+ if (percentComplete < 100)
+ {
+ PostMessage(g_InitDlg, WM_STARTUP_UPDATE, percentComplete, 0);
+ }
+
+ ++currentPort;
+
+ // Get a big chuck of memory to store the SCSI bus data.
+
+ adapterInfo = (PSCSI_ADAPTER_BUS_INFO)(Malloc(SCSI_INFO_BUFFER_SIZE));
+
+ if (adapterInfo == NULL)
+ {
+ CloseHandle(volumeHandle);
+ goto finish;
+ }
+
+ // Issue device control to get configuration information.
+
+ if (!DeviceIoControl(volumeHandle,
+ IOCTL_SCSI_GET_INQUIRY_DATA,
+ NULL,
+ 0,
+ adapterInfo,
+ SCSI_INFO_BUFFER_SIZE,
+ &bytesTransferred,
+ NULL))
+ {
+ CloseHandle(volumeHandle);
+ goto finish;
+ }
+
+ // Search for unclaimed disk and cdrom drives.
+
+ for (i=0; i < adapterInfo->NumberOfBuses; i++)
+ {
+ busData = &adapterInfo->BusData[i];
+ inquiryData =
+ (PSCSI_INQUIRY_DATA)((PUCHAR)adapterInfo + busData->InquiryDataOffset);
+
+ for (j=0; j<busData->NumberOfLogicalUnits; j++)
+ {
+ // Check if device is claimed.
+
+ if (!inquiryData->DeviceClaimed)
+ {
+ // Determine the perpherial type.
+
+ switch (inquiryData->InquiryData[0] & 0x1f)
+ {
+ case DIRECT_ACCESS_DEVICE:
+ diskFound = TRUE;
+ break;
+
+ case READ_ONLY_DIRECT_ACCESS_DEVICE:
+ cdromFound = TRUE;
+ break;
+
+ case OPTICAL_DEVICE:
+ diskFound = TRUE;
+ break;
+ }
+ }
+
+ // Get next device data.
+
+ inquiryData =
+ (PSCSI_INQUIRY_DATA)((PUCHAR)adapterInfo + inquiryData->NextInquiryDataOffset);
+ }
+ }
+
+ Free(adapterInfo);
+ CloseHandle(volumeHandle);
+
+ portNumber++;
+ }
+
+ if (diskFound)
+ {
+ // Send IOCTL_DISK_FIND_NEW_DEVICES commands to each existing disk.
+
+ deviceNumber = 0;
+ while (TRUE)
+ {
+ wsprintf(deviceName, L"\\Device\\Harddisk%d\\Partition0", deviceNumber);
+ RtlInitUnicodeString(&unicodeString, deviceName);
+
+ InitializeObjectAttributes(&objectAttributes,
+ &unicodeString,
+ 0,
+ NULL,
+ NULL);
+
+ ntStatus = DmOpenFile(&volumeHandle,
+ FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE,
+ &objectAttributes,
+ &statusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT);
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ break;
+ }
+
+ // Issue find device device control.
+
+ if (!DeviceIoControl(volumeHandle,
+ IOCTL_DISK_FIND_NEW_DEVICES,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &bytesTransferred,
+ NULL))
+ {
+ // nothing?
+ }
+
+ DmClose(volumeHandle);
+
+ // see if the PhysicalDrive# symbolic link is present
+
+ wsprintf(physicalName, TEXT("\\DosDevices\\PhysicalDrive%d"), deviceNumber);
+ deviceNumber++;
+
+ RtlInitUnicodeString(&physicalString, physicalName);
+ InitializeObjectAttributes(&objectAttributes,
+ &physicalString,
+ 0,
+ NULL,
+ NULL);
+ ntStatus = DmOpenFile(&volumeHandle,
+ FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE,
+ &objectAttributes,
+ &statusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT);
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ // Name is not there - create it.
+
+ DefineDosDevice(
+ DDD_RAW_TARGET_PATH,
+ &physicalName[ARRAYLEN("\\DosDevices\\") - 1], // skip prefix
+ deviceName);
+ }
+ else
+ {
+ DmClose(volumeHandle);
+ }
+ }
+ }
+
+ if (cdromFound)
+ {
+ // Send IOCTL_CDROM_FIND_NEW_DEVICES commands to each existing cdrom.
+
+ deviceNumber = 0;
+ while (TRUE)
+ {
+ wsprintf(deviceName, L"\\Device\\Cdrom%d", deviceNumber);
+ RtlInitUnicodeString(&unicodeString, deviceName);
+
+ InitializeObjectAttributes(&objectAttributes,
+ &unicodeString,
+ 0,
+ NULL,
+ NULL);
+
+ ntStatus = DmOpenFile(&volumeHandle,
+ FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE,
+ &objectAttributes,
+ &statusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT);
+
+ if (!NT_SUCCESS(ntStatus))
+ {
+ break;
+ }
+
+ // Issue find device device control.
+
+ if (!DeviceIoControl(volumeHandle,
+ IOCTL_CDROM_FIND_NEW_DEVICES,
+ NULL,
+ 0,
+ NULL,
+ 0,
+ &bytesTransferred,
+ NULL))
+ {
+ // nothing?
+ }
+
+ CloseHandle(volumeHandle);
+ deviceNumber++;
+ }
+ }
+
+finish:
+ PostMessage(g_InitDlg, WM_STARTUP_UPDATE, 100, 0);
+}
diff --git a/private/utils/windisk/src/commit.hxx b/private/utils/windisk/src/commit.hxx
new file mode 100644
index 000000000..52aea23a5
--- /dev/null
+++ b/private/utils/windisk/src/commit.hxx
@@ -0,0 +1,101 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: commit.hxx
+//
+// Contents: Declarations for no-reboot changes
+//
+// History: 15-Jan-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __COMMIT_HXX__
+#define __COMMIT_HXX__
+
+//////////////////////////////////////////////////////////////////////////////
+
+// Commit flag for case where a partition is deleted that has no drive letter
+
+extern BOOLEAN CommitDueToDelete;
+extern BOOLEAN CommitDueToMirror;
+extern BOOLEAN CommitDueToExtended;
+extern BOOLEAN CommitDueToCreate;
+extern ULONG UpdateMbrOnDisk;
+
+//////////////////////////////////////////////////////////////////////////////
+
+VOID
+CommitAssignLetterList(
+ VOID
+ );
+
+VOID
+CommitNewRegions(
+ VOID
+ );
+
+VOID
+CommitToAssignLetterList(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN BOOLEAN MoveLetter
+ );
+
+DWORD
+CommitChanges(
+ VOID
+ );
+
+UINT
+CommitAllChanges(
+ VOID
+ );
+
+VOID
+CommitDeleteLockLetter(
+ IN WCHAR DriveLetter
+ );
+
+BOOL
+CommitAllowed(
+ VOID
+ );
+
+VOID
+RescanDevices(
+ VOID
+ );
+
+BOOL
+CommitDriveLetter(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN WCHAR OldDriveLetter,
+ IN WCHAR NewDriveLetter
+ );
+
+LONG
+CommitToLockList(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN BOOL RemoveDriveLetter,
+ IN BOOL LockNow,
+ IN BOOL FailOk
+ );
+
+LONG
+CommitLockVolumes(
+ IN ULONG Disk
+ );
+
+LONG
+CommitUnlockVolumes(
+ IN ULONG Disk,
+ IN BOOLEAN FreeList
+ );
+
+VOID
+FtConfigure(
+ VOID
+ );
+
+#endif // __COMMIT_HXX__
diff --git a/private/utils/windisk/src/const.h b/private/utils/windisk/src/const.h
new file mode 100644
index 000000000..63437d881
--- /dev/null
+++ b/private/utils/windisk/src/const.h
@@ -0,0 +1,146 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: const.h
+//
+// Contents: Global constants
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __CONST_H__
+#define __CONST_H__
+
+
+//
+// The maximum length of a string in a listview column
+//
+
+#define MAX_LV_ITEM_LEN 200
+
+#define MAX_RESOURCE_STRING_LEN 256
+
+#define MAXTITLELEN 256
+#define MAXMESSAGELEN 256
+#define MAXERRORLEN 256
+#define MAXLABELLEN 32 + 1
+
+//
+// This is the number of entries in a partition table, and is fixed for
+// all time
+//
+
+#define PARTITION_TABLE_SIZE 4
+
+//
+// This is the maximum number of members that WinDisk will support
+// in an FT Set.
+//
+#define MAX_MEMBERS_IN_FT_SET 32
+
+#define STATUS_TEXT_SIZE 250
+
+#define NUM_AVAILABLE_COLORS 16
+#define NUM_AVAILABLE_HATCHES 6
+
+
+#define LEGEND_STRING_COUNT 6
+
+//
+// indices into g_Brushes[], for brushes for drawing legend rectangles
+//
+#define BRUSH_USEDPRIMARY 0
+#define BRUSH_USEDLOGICAL 1
+#define BRUSH_STRIPESET 2
+#define BRUSH_PARITYSET 3
+#define BRUSH_MIRROR 4
+#define BRUSH_VOLUMESET 5
+#define BRUSH_ARRAY_SIZE LEGEND_STRING_COUNT
+
+//
+// indices into AvailableHatches[] (see data.cxx)
+//
+#define DEFAULT_HATCH_USEDPRIMARY 5
+#define DEFAULT_HATCH_USEDLOGICAL 5
+#define DEFAULT_HATCH_STRIPESET 5
+#define DEFAULT_HATCH_MIRROR 5
+#define DEFAULT_HATCH_VOLUMESET 5
+#define DEFAULT_HATCH_PARITYSET 5
+
+//
+// indices into AvailableColors[] (see data.cxx)
+//
+#define DEFAULT_COLOR_USEDPRIMARY 9
+#define DEFAULT_COLOR_USEDLOGICAL 15
+#define DEFAULT_COLOR_STRIPESET 14
+#define DEFAULT_COLOR_MIRROR 5
+#define DEFAULT_COLOR_VOLUMESET 10
+#define DEFAULT_COLOR_PARITYSET 13
+
+//
+// my own hatch identifiers
+//
+
+#define MY_HS_FDIAGONAL 0 /* \\\\\ */
+#define MY_HS_BDIAGONAL 1 // /////
+#define MY_HS_CROSS 2 // +++++
+#define MY_HS_DIAGCROSS 3 // xxxxx
+#define MY_HS_VERTICAL 4 // |||||
+#define MY_HS_SOLIDCLR 5 // solid
+
+
+
+#define MESSAGE_BUFFER_SIZE 4096
+
+#define PEN_WIDTH 1
+
+
+// thickness of the border indicating selection of a region
+
+#define SELECTION_THICKNESS 2
+
+
+//
+// define constants for use with drive letter assignments.
+// use arbitrary symbols that won't ever be drive letters themselves.
+
+#define NO_DRIVE_LETTER_YET L'#'
+#define NO_DRIVE_LETTER_EVER L'%'
+
+
+
+
+// custom windows message for F1 key
+
+#define WM_F1DOWN (WM_USER + 0x17a)
+
+
+
+#define MBOOT_CODE_SIZE 0x1b8
+#define MBOOT_SIG_OFFSET 0x1fe
+#define MBOOT_SIG1 0x55
+#define MBOOT_SIG2 0xaa
+
+
+
+#define UNINIT_FT_TYPE ((FT_TYPE)-1)
+
+// toolbar constants
+
+#define TOOLBAR_HEIGHT 27
+
+
+//
+// Indices into the GraphColors[] array. These are colors used in the neato
+// %free/%used graph in the Volume general property page
+//
+
+#define I_USEDCOLOR 0
+#define I_FREECOLOR 1
+#define I_USEDSHADOW 2
+#define I_FREESHADOW 3
+
+#endif // __CONST_H__
diff --git a/private/utils/windisk/src/data.cxx b/private/utils/windisk/src/data.cxx
new file mode 100644
index 000000000..163a31852
--- /dev/null
+++ b/private/utils/windisk/src/data.cxx
@@ -0,0 +1,288 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: data.cxx
+//
+// Contents: Global data
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+
+DECLARE_INFOLEVEL(da)
+
+
+HINSTANCE g_hInstance;
+
+//
+// IsDiskRemovable is an array of BOOLEANs each of which indicates
+// whether the corresponding physical disk is removable.
+//
+
+PBOOLEAN IsDiskRemovable = NULL;
+
+//
+// RemovableDiskReservedDriveLetters is an array of WCHARs which
+// shows the reserved drive letter for each disk if that disk is
+// removable.
+//
+
+PWCHAR RemovableDiskReservedDriveLetters;
+
+//
+// This will be an array of pointers to DISKSTATE structures, indexed
+// by disk number.
+//
+
+PDISKSTATE* DiskArray;
+
+//
+// BootDiskNumber is the number of the disk on which the boot partition
+// (ie. the disk with the WinNt files) resides. BootPartitionNumber is
+// the original partition number of this partition.
+//
+
+ULONG BootDiskNumber;
+ULONG BootPartitionNumber;
+
+
+// window handles
+
+HWND g_hwndFrame;
+HWND g_hwndList;
+HWND g_hwndToolbar;
+
+HMENU g_hmenuFrame; // the frame window's hmenu
+
+// GDI objects
+
+HBITMAP g_hBitmapSmallDisk;
+HBITMAP g_hBitmapRemovableDisk;
+HBITMAP g_hBitmapSmallCdRom;
+HFONT g_hFontGraph;
+HFONT g_hFontGraphBold;
+HFONT g_hFontStatus;
+HFONT g_hFontLegend;
+
+HBRUSH g_Brushes[BRUSH_ARRAY_SIZE];
+HBRUSH g_hBrushFreeLogical;
+HBRUSH g_hBrushFreePrimary;
+HPEN g_hPenNull;
+HPEN g_hPenThinSolid;
+HCURSOR g_hCurWait;
+HCURSOR g_hCurNormal;
+
+
+// initial stuff for the disk graphs, used when there is
+// no info in win.ini.
+
+int BrushHatches[BRUSH_ARRAY_SIZE] =
+{
+ DEFAULT_HATCH_USEDPRIMARY,
+ DEFAULT_HATCH_USEDLOGICAL,
+ DEFAULT_HATCH_STRIPESET,
+ DEFAULT_HATCH_PARITYSET,
+ DEFAULT_HATCH_MIRROR,
+ DEFAULT_HATCH_VOLUMESET
+};
+
+int BrushColors[BRUSH_ARRAY_SIZE] =
+{
+ DEFAULT_COLOR_USEDPRIMARY,
+ DEFAULT_COLOR_USEDLOGICAL,
+ DEFAULT_COLOR_STRIPESET,
+ DEFAULT_COLOR_PARITYSET,
+ DEFAULT_COLOR_MIRROR,
+ DEFAULT_COLOR_VOLUMESET
+};
+
+// colors and patterns available for the disk graphs
+
+COLORREF AvailableColors[NUM_AVAILABLE_COLORS] =
+{
+ RGB(0,0,0), // 0: black
+ RGB(128,128,128), // 1: dark gray
+ RGB(192,192,192), // 2: light gray
+ RGB(255,255,255), // 3: white
+ RGB(128,128,0), // 4: dark yellow
+ RGB(128,0,128), // 5: violet
+ RGB(128,0,0), // 6: dark red
+ RGB(0,128,128), // 7: dark cyan
+ RGB(0,128,0), // 8: dark green
+ RGB(0,0,128), // 9: dark blue
+ RGB(255,255,0), // 10: yellow
+ RGB(255,0,255), // 11: light violet
+ RGB(255,0,0), // 12: red
+ RGB(0,255,255), // 13: cyan
+ RGB(0,255,0), // 14: green
+ RGB(0,0,255) // 15: blue
+};
+
+int AvailableHatches[NUM_AVAILABLE_HATCHES] =
+{
+ MY_HS_FDIAGONAL, /* \\\\\ */
+ MY_HS_BDIAGONAL, // /////
+ MY_HS_CROSS, // +++++
+ MY_HS_DIAGCROSS, // xxxxx
+ MY_HS_VERTICAL, // |||||
+ MY_HS_SOLIDCLR // solid
+};
+
+
+
+// positions for various items in a disk graph
+
+DWORD GraphWidth = 0;
+
+DWORD GraphHeight;
+DWORD BarTopYOffset;
+DWORD BarBottomYOffset;
+DWORD BarHeight;
+
+DWORD dxDriveLetterStatusArea;
+
+DWORD dxBarTextMargin;
+DWORD dyBarTextLine;
+DWORD BarLeftX;
+DWORD BarWidth;
+DWORD BarWidthMargin;
+DWORD BarWidthMinimum;
+
+DWORD MinimumWindowWidth;
+
+DWORD xSmallDisk;
+DWORD ySmallDisk;
+DWORD dxSmallDisk;
+DWORD dySmallDisk;
+
+DWORD xRemovableDisk;
+DWORD yRemovableDisk;
+DWORD dxRemovableDisk;
+DWORD dyRemovableDisk;
+
+DWORD xSmallCdRom;
+DWORD ySmallCdRom;
+DWORD dxSmallCdRom;
+DWORD dySmallCdRom;
+
+ULONG g_MinimumRegionSize;
+
+//
+// various measurement metrics
+//
+
+DWORD g_wLegendItem; // width of a legend item
+DWORD g_dyLegendSep; // separation between legend items
+
+DWORD g_dyBorder;
+DWORD g_dyToolbar;
+DWORD g_dyStatus;
+DWORD g_dyLegend;
+
+
+// if a single disk region is selected, these vars describe the selection.
+
+PDISKSTATE SingleSel;
+DWORD SingleSelIndex;
+
+// name of the help file
+
+PWSTR g_HelpFile;
+
+
+// number of hard disks and CD-ROMs attached to the system
+
+ULONG DiskCount = 0;
+
+ULONG CdRomCount = 0;
+PCDROM_DESCRIPTOR CdRomArray;
+
+// "Disk %u", "CdRom %u"
+
+LPTSTR DiskN;
+LPTSTR CdRomN;
+
+PWSTR wszUnformatted;
+PWSTR wszUnknown;
+
+//
+// If the following is TRUE, the registry needs to be updated and the user will
+// be prompted to save changed just as if he had made changes to any partitions.
+//
+
+BOOL RegistryChanged = FALSE;
+
+//
+// Restart required to make changes work.
+//
+
+BOOL RestartRequired = FALSE;
+
+//
+// If the following is TRUE, the main window will pass WM_ENTERIDLE
+// messages on to the child dialog box; this will trigger the
+// configuration search.
+//
+
+BOOL ConfigurationSearchIdleTrigger = FALSE;
+
+//
+// This flag indicates whether this is a Server
+// or just regular Windows NT Workstation.
+//
+
+BOOL g_IsLanmanNt = FALSE;
+
+//
+// Whether or not a CD-ROM is present in the system
+//
+
+BOOL g_AllowCdRom = FALSE;
+
+//
+// g_WhichView indicates which view is currently being displayed
+//
+
+VIEW_TYPE g_WhichView;
+
+//
+// listview data
+//
+
+HWND g_hwndLV;
+
+//
+// set this to TRUE if you are programmatically setting listview state,
+// and want to ignore the resulting notification messages.
+//
+
+BOOL g_SettingListviewState = FALSE;
+
+// whether status bar and legend are currently shown
+
+BOOL g_Toolbar = TRUE;
+BOOL g_StatusBar = TRUE;
+BOOL g_Legend = TRUE;
+
+
+
+DISK_TYPE g_DiskDisplayType = DiskProportional;
+
+//
+// Colors used in the %used/%free graph in the volume general property page.
+//
+// DO NOT change the order of these defines (see I_*)
+//
+COLORREF GraphColors[] =
+{
+ RGB( 0, 0, 255), // (I_USEDCOLOR) Used: Blue
+ RGB(255, 0, 255), // (I_FREECOLOR) Free: Red-Blue
+ RGB( 0, 0, 128), // (I_USEDSHADOW) Used shadow: 1/2 Blue
+ RGB(128, 0, 128) // (I_FREESHADOW) Free shadow: 1/2 Red-Blue
+};
diff --git a/private/utils/windisk/src/dblspace.cxx b/private/utils/windisk/src/dblspace.cxx
new file mode 100644
index 000000000..24e9a6202
--- /dev/null
+++ b/private/utils/windisk/src/dblspace.cxx
@@ -0,0 +1,1662 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: dblspace.cxx
+//
+// Contents: This module contains the set of routines that deal with
+// DoubleSpace dialogs and support.
+//
+// History: 15-Nov-93 Bob Rinne Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#if defined( DBLSPACE_ENABLED )
+
+#include <util.hxx>
+
+#include "dblspace.h"
+#include "dblspace.hxx"
+#include "dialogs.h"
+#include "dlgs.hxx"
+#include "drives.hxx"
+#include "fmifs.hxx"
+#include "help.hxx"
+#include "listbox.hxx"
+#include "format.hxx"
+#include "windisk.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+#define MAX_IFS_NAME_LENGTH 200
+
+WCHAR DblSpaceWildCardFileName[] = TEXT("%c:\\dblspace.*");
+
+// All DoubleSpace structures are chained into the base chain
+// this allows for ease in initialization to determine which are
+// mounted. This chain is only used for initialization.
+
+PDBLSPACE_DESCRIPTOR DblChainBase = NULL;
+PDBLSPACE_DESCRIPTOR DblChainLast = NULL;
+
+#define DblSpaceMountDrive(REGDESC, DBLSPACE) \
+ DblSpaceChangeState(REGDESC, DBLSPACE, TRUE)
+#define DblSpaceDismountDrive(REGDESC, DBLSPACE) \
+ DblSpaceChangeState(REGDESC, DBLSPACE, FALSE)
+
+//////////////////////////////////////////////////////////////////////////////
+
+VOID
+DblSpaceUpdateIniFile(
+ IN PREGION_DESCRIPTOR RegionDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is left around in case this code must update DOS
+ based .ini files. Currently it does nothing.
+
+Arguments:
+
+ The region with the DoubleSpace volumes.
+
+Return Value
+
+ None
+
+--*/
+
+{
+}
+
+ULONG
+DblSpaceChangeState(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN PDBLSPACE_DESCRIPTOR DblSpacePtr,
+ IN BOOL Mount
+ )
+
+/*++
+
+Routine Description:
+
+ Based on the value of Mount, either mount the volume or
+ dismount the DoubleSpace volume
+
+Arguments:
+
+ RegionDescriptor - The region containing the DoubleSpace volume
+ DblSpacePtr - The DoubleSpace structure involved.
+ Mount - TRUE == perform a mount function
+ FALSE == dismount the volume
+
+Return Value:
+
+ 0 for success
+
+--*/
+
+{
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(RegionDescriptor);
+ WCHAR dblSpaceUniqueName[32];
+ ULONG index;
+ ULONG result = 0;
+
+ SetCursor(g_hCurWait);
+
+ if (Mount)
+ {
+ // Call fmifs mount routine.
+
+ result = FmIfsMountDblspace(DblSpacePtr->FileName,
+ regionData->DriveLetter,
+ DblSpacePtr->NewDriveLetter);
+ }
+ else
+ {
+ // Call fmifs dismount routine.
+
+ result = FmIfsDismountDblspace(DblSpacePtr->DriveLetter);
+ }
+
+ if (0 == result)
+ {
+ DblSpacePtr->Mounted = Mount;
+ if (Mount)
+ {
+ DblSpacePtr->DriveLetter = DblSpacePtr->NewDriveLetter;
+ MarkDriveLetterUsed(DblSpacePtr->DriveLetter);
+ }
+ else
+ {
+ WCHAR driveName[3];
+
+ // remove the drive letter.
+
+ driveName[0] = DblSpacePtr->DriveLetter;
+ driveName[1] = L':';
+ driveName[2] = L'\0';
+
+ DefineDosDevice(DDD_REMOVE_DEFINITION, driveName, NULL);
+
+ // Now update the internal structures.
+
+ MarkDriveLetterFree(DblSpacePtr->DriveLetter);
+ DblSpacePtr->DriveLetter = L' ';
+ }
+
+ if (!IsDiskRemovable[RegionDescriptor->Disk])
+ {
+ dblSpaceUniqueName[0] = regionData->DriveLetter;
+ dblSpaceUniqueName[1] = L':';
+ dblSpaceUniqueName[2] = L'\\';
+
+ index = 0;
+ while (NULL != (dblSpaceUniqueName[index + 3] = DblSpacePtr->FileName[index]))
+ {
+ index++;
+ }
+
+ result = DiskRegistryAssignDblSpaceLetter(dblSpaceUniqueName,
+ DblSpacePtr->DriveLetter);
+ }
+ }
+
+ SetCursor(g_hCurNormal);
+ return result;
+}
+
+PDBLSPACE_DESCRIPTOR
+DblSpaceCreateInternalStructure(
+ IN WCHAR DriveLetter,
+ IN ULONG Size,
+ IN PWSTR Name,
+ IN BOOLEAN ChainIt
+ )
+
+/*++
+
+Routine Description:
+
+ This routine constructs the internal data structure that represents a
+ DoubleSpace volume.
+
+Arguments:
+
+ DriveLetter - drive letter for new internal structure
+ Size - size of the actual volume
+ Name - name of the containing DoubleSpace file (i.e. dblspace.xxx)
+ ChainIt -
+
+Return Value:
+
+ Pointer to the new structure if created.
+ NULL if it couldn't be created.
+
+--*/
+
+{
+ PDBLSPACE_DESCRIPTOR dblSpace;
+
+ dblSpace = (PDBLSPACE_DESCRIPTOR)Malloc(sizeof(DBLSPACE_DESCRIPTOR));
+
+ if (DriveLetter != L' ')
+ {
+ MarkDriveLetterUsed(DriveLetter);
+ }
+ dblSpace->DblChainNext = NULL;
+ dblSpace->Next = NULL;
+ dblSpace->DriveLetter = DriveLetter;
+ dblSpace->NewDriveLetter = L'\0';
+ dblSpace->ChangeDriveLetter = FALSE;
+ dblSpace->Mounted = FALSE;
+ dblSpace->ChangeMountState = FALSE;
+ dblSpace->AllocatedSize = Size;
+ dblSpace->FileName = (PWSTR)Malloc((lstrlen(Name) + 4) * sizeof(WCHAR));
+
+ // Copy the name.
+
+ lstrcpy(dblSpace->FileName, Name);
+ if (ChainIt)
+ {
+ if (DblChainBase)
+ {
+ DblChainLast->DblChainNext = dblSpace;
+ }
+ else
+ {
+ DblChainBase = dblSpace;
+ }
+ DblChainLast = dblSpace;
+ }
+
+ return dblSpace;
+}
+
+VOID
+DblSpaceDetermineMounted(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine walks through all of the system drive letters to see
+ if any are mounted DoubleSpace volumes. If a mounted DoubleSpace
+ volume is located it updates the state of that volume in the internal
+ data structures for the DoubleSpace volumes.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PDBLSPACE_DESCRIPTOR dblSpace;
+ WCHAR driveLetter[4],
+ ntDriveName[MAX_IFS_NAME_LENGTH],
+ cvfName[MAX_IFS_NAME_LENGTH],
+ hostDriveName[MAX_IFS_NAME_LENGTH];
+ UINT errorMode;
+ BOOLEAN removable,
+ floppy,
+ compressed,
+ error;
+
+ driveLetter[1] = L':';
+ driveLetter[2] = L'\0';
+
+ errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+ for (driveLetter[0] = L'C'; driveLetter[0] < L'Z'; driveLetter[0]++)
+ {
+ if (DriveLetterIsAvailable(driveLetter[0]))
+ {
+ // No sense calling this stuff for something that doesn't exist
+
+ continue;
+ }
+
+ compressed = FALSE;
+ if (FmIfsQueryInformation(&driveLetter[0],
+ &removable,
+ &floppy,
+ &compressed,
+ &error,
+ &ntDriveName[0],
+ MAX_IFS_NAME_LENGTH,
+ &cvfName[0],
+ MAX_IFS_NAME_LENGTH,
+ &hostDriveName[0],
+ MAX_IFS_NAME_LENGTH))
+ {
+ // call worked, see if it is a DoubleSpace volume
+
+ if (compressed)
+ {
+ // now need to find this volume in the chain and
+ // update it mounted state.
+
+ for (dblSpace = DblChainBase;
+ NULL != dblSpace;
+ dblSpace = dblSpace->DblChainNext)
+ {
+ if (0 == lstrcmp(dblSpace->FileName, cvfName))
+ {
+ // found a match.
+
+ dblSpace->Mounted = TRUE;
+ dblSpace->DriveLetter = driveLetter[0];
+ }
+ }
+ }
+ }
+ }
+ SetErrorMode(errorMode);
+}
+
+VOID
+DblSpaceInitialize(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine goes through the disk table and searches for FAT format
+ partitions. When one is found, it checks for the presense of DoubleSpace
+ volumes and initializes the DoubleSpace support structures inside
+ Disk Administrator.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PDISKSTATE diskState;
+ PREGION_DESCRIPTOR regionDesc;
+ PPERSISTENT_REGION_DATA regionData;
+ PDBLSPACE_DESCRIPTOR dblSpace,
+ prevDblSpace;
+ WCHAR fileName[50];
+ unsigned diskIndex,
+ regionIndex;
+
+ for (diskIndex = 0; diskIndex < DiskCount; diskIndex++)
+ {
+ diskState = DiskArray[diskIndex];
+ regionDesc = diskState->RegionArray;
+ for (regionIndex = 0; regionIndex < diskState->RegionCount; regionIndex++)
+ {
+ regionData = PERSISTENT_DATA(&regionDesc[regionIndex]);
+
+ // region may be free or something that isn't recognized by NT
+
+ if (!regionData)
+ {
+ continue;
+ }
+
+ // region may not be formatted yet.
+
+ if (!regionData->TypeName)
+ {
+ continue;
+ }
+
+ // DoubleSpace volumes are only allowed on FAT non-FT partitions.
+
+ if (regionData->FtObject)
+ {
+ continue;
+ }
+
+ if (0 == lstrcmp(regionData->TypeName, L"FAT"))
+ {
+ WIN32_FIND_DATA findInformation;
+ HANDLE findHandle;
+
+ // it is possible to have a DoubleSpace volume here.
+ // Search the root directory of the driver for files with
+ // the name "dblspace.xxx". These are potentially dblspace
+ // volumes.
+
+ prevDblSpace = NULL;
+ wsprintf(fileName, DblSpaceWildCardFileName, regionData->DriveLetter);
+ findHandle = FindFirstFile(fileName, &findInformation);
+ while (findHandle != INVALID_HANDLE_VALUE)
+ {
+ TCHAR* cp;
+ int i;
+ int save;
+
+ // There is at least one dblspace volume. Insure that
+ // the name is of the proper form.
+
+ save = TRUE;
+ cp = &findInformation.cFileName[0];
+
+ while (*cp)
+ {
+ if (*cp == TEXT('.'))
+ {
+ break;
+ }
+ cp++;
+ }
+
+ if (*cp != TEXT('.'))
+ {
+ // not a proper dblspace volume name.
+
+ save = FALSE;
+ }
+ else
+ {
+ cp++;
+
+ for (i = 0; i < 3; i++, cp++)
+ {
+ if ((*cp < TEXT('0')) || (*cp > TEXT('9')))
+ {
+ break;
+ }
+ }
+
+ if (i != 3)
+ {
+ // not a proper dblspace volume name.
+
+ save = FALSE;
+ }
+ }
+
+ if (save)
+ {
+ // save the information and search for more.
+
+ dblSpace =
+ DblSpaceCreateInternalStructure(
+ TEXT(' '),
+ ((findInformation.nFileSizeHigh << 16) |
+ (findInformation.nFileSizeLow)
+ / (1024 * 1024)),
+ &findInformation.cFileName[0],
+ TRUE);
+ if (dblSpace)
+ {
+ // Assume volume is not mounted.
+
+ dblSpace->Mounted = FALSE;
+ dblSpace->ChangeMountState = FALSE;
+
+ // Chain in this description.
+
+ if (prevDblSpace)
+ {
+ prevDblSpace->Next = dblSpace;
+ }
+ else
+ {
+ regionData->DblSpace = dblSpace;
+ }
+
+ // Keep the pointer to this one for the chain.
+
+ prevDblSpace = dblSpace;
+ }
+ else
+ {
+ // no memory
+
+ break;
+ }
+ }
+
+ if (!FindNextFile(findHandle, &findInformation))
+ {
+ // Technically this should double check and call
+ // GetLastError to see that it is ERROR_NO_MORE_FILES
+ // but this code doesn't do that.
+
+ FindClose(findHandle);
+
+ // Get out of the search loop.
+
+ findHandle = INVALID_HANDLE_VALUE;
+ }
+ }
+ }
+ }
+ }
+
+ // Now that all volumes have been located determine which volumes
+ // are mounted by chasing down the drive letters.
+
+ DblSpaceDetermineMounted();
+}
+
+PDBLSPACE_DESCRIPTOR
+DblSpaceGetNextVolume(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN PDBLSPACE_DESCRIPTOR DblSpace
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will check the RegionDescriptor to walk the DoubleSpace
+ volume chain located from the persistent data.
+
+Arguments:
+
+ RegionDescriptor - pointer to the region on the disk that is to be
+ searched for a DoubleSpace volume.
+
+ DblSpace - pointer to the last DoubleSpace volume located on the region.
+
+Return Value:
+
+ pointer to the next DoubleSpace volume if found
+ NULL if no volume found.
+
+--*/
+
+{
+ PPERSISTENT_REGION_DATA regionData;
+
+ // If a previous DoubleSpace location was past, simply walk the chain to the next.
+
+ if (DblSpace)
+ {
+ return DblSpace->Next;
+ }
+
+ // no previous DoubleSpace location, just get the first one and return it.
+ // Could get a NULL RegionDescriptor. If so, return NULL.
+
+ if (RegionDescriptor)
+ {
+ regionData = PERSISTENT_DATA(RegionDescriptor);
+ if (!regionData)
+ {
+ return NULL;
+ }
+ }
+ else
+ {
+ return NULL;
+ }
+ return regionData->DblSpace;
+}
+
+VOID
+DblSpaceLinkNewVolume(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN PDBLSPACE_DESCRIPTOR DblSpace
+ )
+
+/*++
+
+Routine Description:
+
+ Chain the new DoubleSpace volume on the list of DoubleSpace volumes
+ for the region.
+
+Arguments:
+
+ RegionDescriptor - the region the DoubleSpace volume has been added to.
+ DblSpace - the new volume internal data structure.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(RegionDescriptor);
+ PDBLSPACE_DESCRIPTOR prevDblSpace;
+
+ // if this is the first one, chain it first
+
+ if (!regionData->DblSpace)
+ {
+ regionData->DblSpace = DblSpace;
+ return;
+ }
+
+ for (prevDblSpace = regionData->DblSpace;
+ NULL != prevDblSpace->Next;
+ prevDblSpace = prevDblSpace->Next)
+ {
+ // all the work is in the for
+ }
+
+ // found the last one. Add the new one to the chain
+
+ prevDblSpace->Next = DblSpace;
+}
+
+BOOL
+DblSpaceVolumeExists(
+ IN PREGION_DESCRIPTOR RegionDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ Indicate to the caller if the input region contains a DoubleSpace volume.
+
+Arguments:
+
+ RegionDescriptor - a pointer to the region in question.
+
+Return Value:
+
+ TRUE if this region contains DoubleSpace volume(s).
+ FALSE if not
+
+--*/
+
+{
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(RegionDescriptor);
+
+ if (regionData)
+ {
+ return (regionData->DblSpace ? TRUE : FALSE);
+ }
+ return FALSE;
+}
+
+BOOL
+DblSpaceDismountedVolumeExists(
+ IN PREGION_DESCRIPTOR RegionDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ Indicate to the caller if the input region contains a DoubleSpace volume
+ that is not mounted.
+
+Arguments:
+
+ RegionDescriptor - a pointer to the region in question.
+
+Return Value:
+
+ TRUE if this region contains DoubleSpace volume(s).
+ FALSE if not
+
+--*/
+
+{
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(RegionDescriptor);
+ PDBLSPACE_DESCRIPTOR dblSpace;
+
+ if (regionData)
+ {
+ if (NULL != (dblSpace = regionData->DblSpace))
+ {
+ while (NULL != dblSpace)
+ {
+ if (!dblSpace->Mounted)
+ {
+ return TRUE;
+ }
+ dblSpace = dblSpace->Next;
+ }
+ }
+ }
+ return FALSE;
+}
+
+PDBLSPACE_DESCRIPTOR
+DblSpaceFindVolume(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN PWSTR Name
+ )
+
+/*++
+
+Routine Description:
+
+ Given a region and a name, locate the DoubleSpace data structure.
+
+Arguments:
+
+ RegionDescriptor - the region to search
+ Name - the filename wanted.
+
+Return Value:
+
+ A pointer to a DoubleSpace descriptor if found.
+ NULL if not found.
+
+--*/
+
+{
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(RegionDescriptor);
+ PDBLSPACE_DESCRIPTOR dblSpace = NULL;
+
+ if (NULL != regionData)
+ {
+ for (dblSpace = regionData->DblSpace;
+ NULL != dblSpace;
+ dblSpace = dblSpace->Next)
+ {
+ if (0 == lstrcmp(Name, dblSpace->FileName))
+ {
+ // found the desired DoubleSpace volume
+
+ break;
+ }
+ }
+ }
+ return dblSpace;
+}
+
+
+BOOL
+DblSpaceDetermineUniqueFileName(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN PWSTR FileName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will search the actual partition to determine what
+ valid DoubleSpace file name to use (i.e. dblspace.xxx where xxx
+ is a unique number).
+
+Arguments:
+
+ RegionDescriptor - the region to search and determine what DoubleSpace
+ file names are in use.
+ FileName - a pointer to a character buffer for the name.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ DWORD uniqueNumber = 0;
+
+ do
+ {
+ wsprintf(FileName, TEXT("dblspace.%03d"), uniqueNumber++);
+ if (uniqueNumber > 999)
+ {
+ return FALSE;
+ }
+ } while (DblSpaceFindVolume(RegionDescriptor, FileName));
+ return TRUE;
+}
+
+VOID
+DblSpaceRemoveVolume(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN WCHAR DriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ Find the drive letter provided and unlink it from the chain.
+ Currently this also removes the volume for the scaffolding file.
+
+Arguments:
+
+ RegionDescriptor - region containing the DoubleSpace volume.
+ DriveLetter - the drive letter to remove.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(RegionDescriptor);
+ PDBLSPACE_DESCRIPTOR dblSpace,
+ prevDblSpace = NULL;
+
+ // Clean up the internal structures.
+
+ if (NULL != regionData)
+ {
+ for (dblSpace = regionData->DblSpace;
+ NULL != dblSpace;
+ dblSpace = dblSpace->Next)
+ {
+ if (dblSpace->DriveLetter == DriveLetter)
+ {
+ // This is the one to delete
+
+ if (NULL != prevDblSpace)
+ {
+ prevDblSpace->Next = dblSpace->Next;
+ }
+ else
+ {
+ regionData->DblSpace = dblSpace->Next;
+ }
+ Free(dblSpace);
+ break;
+ }
+ prevDblSpace = dblSpace;
+ }
+ }
+}
+
+BOOL CALLBACK
+CreateDblSpaceDlgProc(
+ IN HWND hDlg,
+ IN UINT wMsg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+
+/*++
+
+Routine Description:
+
+ This routine manages the dialog for the creation of a new double
+ space volume.
+
+Arguments:
+
+ hDlg - the dialog box handle.
+ wMsg - the message.
+ wParam - the windows parameter.
+ lParam - depends on message type.
+
+Return Value:
+
+ TRUE is returned back through windows if the create is successful
+ FALSE otherwise
+
+--*/
+{
+ static FORMAT_PARAMS formatParams; // this is passed to other threads
+ // it cannot be located on the stack
+ static DWORD sizeMB = 0,
+ maxSizeMB = 600,
+ minSizeMB = 10;
+
+ PREGION_DESCRIPTOR regionDescriptor = &SingleSel->RegionArray[SingleSelIndex];
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(regionDescriptor);
+ PDBLSPACE_DESCRIPTOR dblSpace;
+ WCHAR outputString[50];
+ WCHAR driveLetter;
+ WCHAR driveLetterString[3]; // big enough for "x:" string.
+ DWORD selection;
+ BOOL validNumber;
+ HWND hwndCombo;
+
+ switch (wMsg)
+ {
+ case WM_INITDIALOG:
+
+ // limit the size of string that may be entered for the label
+
+ Edit_LimitText(GetDlgItem(hDlg, IDC_DBLCREATE_NAME), 11);
+
+ // set up to watch all characters that go thru the size dialog
+ // to allow only decimal numbers.
+
+ OldSizeDlgProc = (WNDPROC) SetWindowLong(
+ GetDlgItem(hDlg, IDC_DBLCREATE_SIZE),
+ GWL_WNDPROC,
+ (LONG)&SizeDlgProc);
+
+ // Add each available drive letter to the list of available
+ // drive letters and set the default letter to the first available.
+
+ hwndCombo = GetDlgItem(hDlg, IDC_DBLCREATE_LETTER_CHOICES);
+
+ driveLetterString[1] = TEXT(':');
+ driveLetterString[2] = TEXT('\0');
+ for (driveLetter = L'C'; driveLetter <= L'Z'; driveLetter++)
+ {
+ if (DriveLetterIsAvailable(driveLetter))
+ {
+ driveLetterString[0] = driveLetter;
+ ComboBox_AddString(hwndCombo, driveLetterString);
+ }
+ }
+ ComboBox_SetCurSel(hwndCombo, 0);
+
+ // Setup the min/max values and the size box.
+
+ wsprintf(outputString, TEXT("%u"), minSizeMB);
+ SetDlgItemText(hDlg, IDC_MINMAX_MIN, outputString);
+ wsprintf(outputString, TEXT("%u"), maxSizeMB);
+ SetDlgItemText(hDlg, IDC_MINMAX_MAX, outputString);
+
+ // set up/down control range
+
+ SendDlgItemMessage(
+ hwnd,
+ IDC_DBLCREATE_ALLOCATED,
+ UDM_SETRANGE,
+ 0,
+ MAKELONG(maxSizeMB, minSizeMB));
+
+ // let the spin control set the edit control
+
+ SendDlgItemMessage(hwnd, IDC_DBLCREATE_ALLOCATED, UDM_SETPOS, 0, MAKELONG(maxSizeMB, 0));
+ SendDlgItemMessage(hwnd, IDC_DBLCREATE_SIZE, EM_SETSEL, 0, -1);
+
+ CenterDialogInFrame(hDlg);
+ return TRUE;
+
+ case WM_VSCROLL:
+ // The up/down control changed the edit control: select it again
+ SendDlgItemMessage(hwnd, IDC_DBLCREATE_SIZE, EM_SETSEL, 0, (LPARAM)-1);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDHELP:
+ break;
+
+ case IDCANCEL:
+
+ EndDialog(hDlg, FALSE);
+ break;
+
+ case IDOK:
+ {
+ int fOk;
+
+ // can only do this if the fmifs dll supports DoubleSpace.
+
+ if (!g_DoubleSpaceSupported)
+ {
+ // could not load the dll
+
+ ErrorDialog(MSG_CANT_LOAD_FMIFS);
+ EndDialog(hDlg, FALSE);
+ break;
+ }
+
+ // Get the current size for this volume.
+
+ sizeMB = GetDlgItemInt(hDlg, IDC_DBLCREATE_SIZE, &validNumber, FALSE);
+ if ( !validNumber
+ || !sizeMB
+ || (sizeMB > maxSizeMB)
+ || (sizeMB < minSizeMB))
+ {
+ ErrorDialog(MSG_INVALID_SIZE);
+ EndDialog(hDlg, FALSE);
+ break;
+ }
+
+ // Get the currently selected item in the listbox for drive letter
+
+ hwndCombo = GetDlgItem(hDlg, IDC_DBLCREATE_LETTER_CHOICES);
+ selection = ComboBox_GetCurSel(hwndCombo);
+ ComboBox_GetLBText(hwndCombo, selection, driveLetterString);
+
+ formatParams.RegionDescriptor = regionDescriptor;
+ formatParams.FileSystemIndex = -1;
+ formatParams.DblspaceFileName = NULL;
+ formatParams.QuickFormat = FALSE;
+ formatParams.Cancel = FALSE;
+ formatParams.DoubleSpace = TRUE;
+ formatParams.TotalSpace = 0;
+ formatParams.SpaceAvailable = sizeMB;
+
+ // get the label
+
+ GetDlgItemText(
+ hDlg,
+ IDC_DBLCREATE_NAME,
+ formatParams.Label,
+ ARRAYLEN(formatParams.Label));
+
+ fOk = DialogBoxParam(
+ g_hInstance,
+ MAKEINTRESOURCE(IDD_DBLSPACE_CANCEL),
+ hDlg,
+ FormatProgressDlgProc,
+ (LPARAM)&formatParams);
+
+ if (-1 == fOk)
+ {
+ // error creating dialog
+ daDebugOut((DEB_ERROR, "DialogBoxParam() failed!\n"));
+ }
+
+ if (formatParams.Result)
+ {
+ // the format failed.
+
+ ErrorDialog(formatParams.Result);
+ EndDialog(hDlg, FALSE);
+ }
+ else if (formatParams.Cancel)
+ {
+ // cancelled
+ }
+ else
+ {
+ WCHAR message[300];
+ WCHAR msgProto[300];
+ WCHAR title[200];
+
+ // save the name
+
+ if (NULL != formatParams.DblspaceFileName)
+ {
+ lstrcpy(message, formatParams.DblspaceFileName);
+ }
+ else
+ {
+ message[0] = L'\0';
+ }
+ Free(formatParams.DblspaceFileName);
+
+ dblSpace = DblSpaceCreateInternalStructure(*driveLetterString,
+ sizeMB,
+ message,
+ FALSE);
+ if (dblSpace)
+ {
+ DblSpaceLinkNewVolume(regionDescriptor, dblSpace);
+ MarkDriveLetterUsed(dblSpace->DriveLetter);
+ dblSpace->Mounted = TRUE;
+ }
+
+ LoadString(g_hInstance,
+ IDS_DBLSPACECOMPLETE,
+ title,
+ ARRAYLEN(title));
+
+ LoadString(g_hInstance,
+ IDS_FMT_STATS,
+ msgProto,
+ ARRAYLEN(msgProto));
+
+ TCHAR totalSpace[100];
+ TCHAR spaceAvailable[100];
+
+ wsprintf(totalSpace, L"%lu", formatParams.TotalSpace);
+ wsprintf(spaceAvailable, L"%lu", formatParams.SpaceAvailable);
+
+ InsertSeparators(totalSpace);
+ InsertSeparators(spaceAvailable);
+
+ wsprintf(
+ message,
+ msgProto,
+ totalSpace,
+ spaceAvailable
+ );
+
+ MessageBox(
+ g_hwndFrame,
+ message,
+ title,
+ MB_ICONINFORMATION | MB_OK);
+
+ EndDialog(hDlg, TRUE);
+ }
+
+ break;
+ }
+
+ default:
+
+ if (HIWORD(wParam) == EN_CHANGE)
+ {
+ // The size value has changed. Update the compressed
+ // size value displayed to the user.
+
+ sizeMB = GetDlgItemInt(hDlg, IDC_DBLCREATE_SIZE, &validNumber, FALSE);
+ if (!validNumber)
+ {
+ sizeMB = 0;
+ }
+
+ }
+ break;
+ }
+ break;
+
+ case WM_DESTROY:
+
+ // restore original subclass to window.
+
+ hwndCombo = GetDlgItem(hDlg, IDC_DBLCREATE_SIZE);
+ SetWindowLong(hwndCombo, GWL_WNDPROC, (LONG) OldSizeDlgProc);
+ break;
+
+ }
+ return FALSE;
+}
+
+VOID
+DblSpaceDelete(
+ IN PDBLSPACE_DESCRIPTOR DblSpace
+ )
+
+/*++
+
+Routine Description:
+
+ Start the dialog box for the deletion of a DoubleSpace volume.
+
+Arguments:
+
+ Param - not currently used.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PREGION_DESCRIPTOR regionDescriptor = &SingleSel->RegionArray[SingleSelIndex];
+
+ if (IDYES == ConfirmationDialog(
+ MSG_CONFIRM_DBLSPACE_DELETE,
+ MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2))
+ {
+ // Delete the drive from view
+
+ DblSpaceRemoveVolume(regionDescriptor, DblSpace->DriveLetter);
+ DblSpaceUpdateIniFile(regionDescriptor);
+ DrawDiskBar(SingleSel);
+ ForceLBRedraw();
+ }
+}
+
+BOOLEAN
+DblSpaceCreate(
+ IN HWND hwndOwner
+ )
+
+/*++
+
+Routine Description:
+
+ Start the dialog box for the creation of a DoubleSpace volume.
+
+Arguments:
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ int result = DialogBox(
+ g_hInstance,
+ MAKEINTRESOURCE(IDD_DBLSPACE_CREATE),
+ hwndOwner,
+ CreateDblSpaceDlgProc);
+ if (result)
+ {
+ DrawDiskBar(SingleSel);
+ ForceLBRedraw();
+ }
+ return (result > 0) ? TRUE : FALSE;
+}
+
+BOOL CALLBACK
+DblSpaceMountDlgProc(
+ IN HWND hDlg,
+ IN UINT wMsg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Handle the dialog for DoubleSpace.
+
+Arguments:
+
+ Standard Windows dialog procedure.
+
+Return Value:
+
+ TRUE if something was deleted.
+ FALSE otherwise.
+
+--*/
+
+{
+ static PDBLSPACE_DESCRIPTOR dblSpace;
+
+ HWND hwndCombo;
+ DWORD selection;
+ WCHAR driveLetter;
+ WCHAR driveLetterString[3];
+
+ switch (wMsg)
+ {
+ case WM_INITDIALOG:
+
+ dblSpace = (PDBLSPACE_DESCRIPTOR) lParam;
+
+ // Update the drive letter selections.
+
+ hwndCombo = GetDlgItem(hDlg, IDC_DBLDRIVELET_LETTER_CHOICES);
+
+ // Add all other available letters. Keep track of current
+ // letters offset to set the cursor correctly
+
+ driveLetterString[1] = TEXT(':');
+ driveLetterString[2] = TEXT('\0');
+ for (driveLetter = L'C'; driveLetter <= L'Z'; driveLetter++)
+ {
+ if (DriveLetterIsAvailable(driveLetter)
+ || (driveLetter == dblSpace->DriveLetter))
+ {
+ driveLetterString[0] = driveLetter;
+ ComboBox_AddString(hwndCombo, driveLetterString);
+ }
+ }
+
+ // set the current selection to the appropriate index
+
+ ComboBox_SetCurSel(hwndCombo, 0);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDHELP:
+
+ DialogHelp(HC_DM_DLG_DOUBLESPACE_MOUNT);
+ break;
+
+ case IDCANCEL:
+
+ EndDialog(hDlg, FALSE);
+ break;
+
+ case IDOK:
+
+ // User has selected the drive letter and wants the mount to occur.
+
+ hwndCombo = GetDlgItem(hDlg, IDC_DBLDRIVELET_LETTER_CHOICES);
+ selection = ComboBox_GetCurSel(hwndCombo);
+ ComboBox_GetLBText(hwndCombo, selection, driveLetterString);
+ dblSpace->NewDriveLetter = driveLetterString[0];
+ EndDialog(hDlg, TRUE);
+ break;
+ }
+ }
+
+ return FALSE;
+}
+
+VOID
+DblSpaceSetDialogState(
+ IN HWND hDlg,
+ IN PDBLSPACE_DESCRIPTOR DblSpace
+ )
+
+/*++
+
+Routine Description:
+
+ Given a DoubleSpace volume this routine will update the buttons
+ in the dialog box to reflect they meaning.
+
+Arguments:
+
+ hDlg - dialog handle
+ DblSpace - The DoubleSpace volume selection for determining dialog state.
+
+Return Value
+
+ None
+
+--*/
+
+{
+ TCHAR outputString[200];
+
+ if (DblSpace->Mounted)
+ {
+ LoadString(g_hInstance,
+ IDS_DBLSPACE_MOUNTED,
+ outputString,
+ ARRAYLEN(outputString));
+ SetDlgItemText(hDlg, IDC_MOUNT_STATE, outputString);
+ LoadString(g_hInstance,
+ IDS_DISMOUNT,
+ outputString,
+ ARRAYLEN(outputString));
+ SetDlgItemText(hDlg, IDC_MOUNT_OR_DISMOUNT, outputString);
+
+ outputString[0] = DblSpace->DriveLetter;
+ outputString[1] = TEXT(':');
+ outputString[2] = TEXT('\0');
+ SetDlgItemText(hDlg, IDC_DBLSPACE_LETTER, outputString);
+ }
+ else
+ {
+ LoadString(g_hInstance,
+ IDS_DBLSPACE_DISMOUNTED,
+ outputString,
+ ARRAYLEN(outputString));
+ SetDlgItemText(hDlg, IDC_MOUNT_STATE, outputString);
+ LoadString(g_hInstance,
+ IDS_MOUNT,
+ outputString,
+ ARRAYLEN(outputString));
+ SetDlgItemText(hDlg, IDC_MOUNT_OR_DISMOUNT, outputString);
+
+ outputString[0] = TEXT(' ');
+ outputString[1] = TEXT(' ');
+ outputString[2] = TEXT('\0');
+ SetDlgItemText(hDlg, IDC_DBLSPACE_LETTER, outputString);
+ }
+}
+
+
+BOOL CALLBACK
+DblSpaceDlgProc(
+ IN HWND hDlg,
+ IN UINT wMsg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Handle the dialog for DoubleSpace.
+
+Arguments:
+
+Return Value:
+
+ TRUE if something was deleted.
+ FALSE otherwise.
+
+--*/
+
+{
+ static PREGION_DESCRIPTOR regionDescriptor;
+ static PPERSISTENT_REGION_DATA regionData;
+ static PDBLSPACE_DESCRIPTOR firstDblSpace;
+
+ PDBLSPACE_DESCRIPTOR dblSpace;
+ WCHAR outputString[200];
+ DWORD selection;
+ BOOLEAN result;
+ ULONG errorMessage;
+ HWND hwndCombo;
+ HWND hwndMountButton;
+ HWND hwndDeleteButton;
+
+ switch (wMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ regionDescriptor = &SingleSel->RegionArray[SingleSelIndex];
+ regionData = PERSISTENT_DATA(regionDescriptor);
+
+ hwndCombo = GetDlgItem(hDlg, IDC_DBLSPACE_VOLUME);
+
+ // place all DoubleSpace file names in the selection
+ // box and remember the first name.
+
+ for (firstDblSpace
+ = dblSpace
+ = DblSpaceGetNextVolume(regionDescriptor, NULL);
+ NULL != dblSpace;
+ dblSpace = DblSpaceGetNextVolume(regionDescriptor, dblSpace))
+ {
+ wsprintf(outputString, TEXT("%s"), dblSpace->FileName);
+ ComboBox_AddString(hwndCombo, outputString);
+ }
+ ComboBox_SetCurSel(hwndCombo, 0);
+
+ // add the drive letter
+
+ hwndMountButton = GetDlgItem(hDlg, IDC_MOUNT_OR_DISMOUNT);
+ hwndDeleteButton = GetDlgItem(hDlg, IDC_DBLSPACE_DELETE);
+
+ if (firstDblSpace)
+ {
+ // update the allocated size.
+
+ wsprintf(outputString, TEXT("%u"), firstDblSpace->AllocatedSize);
+ SetDlgItemText(hDlg, IDC_DBLSPACE_ALLOCATED, outputString);
+
+ // update mount state
+
+ DblSpaceSetDialogState(hDlg, firstDblSpace);
+ EnableWindow(hwndMountButton, TRUE);
+ EnableWindow(hwndDeleteButton, TRUE);
+ }
+ else
+ {
+ // update the Mount/Dismount button to say mount and grey it
+
+ LoadString(g_hInstance,
+ IDS_MOUNT,
+ outputString,
+ ARRAYLEN(outputString));
+ SetDlgItemText(hDlg, IDC_MOUNT_OR_DISMOUNT, outputString);
+ EnableWindow(hwndMountButton, FALSE);
+ EnableWindow(hwndDeleteButton, FALSE);
+ }
+ return TRUE;
+ }
+
+ case WM_COMMAND:
+ switch (wParam)
+ {
+ case IDHELP:
+
+ DialogHelp(HC_DM_DLG_DOUBLESPACE);
+ break;
+
+ case IDCANCEL:
+
+ // Run the dblspace change and forget about any changes.
+
+ for (dblSpace = firstDblSpace;
+ NULL != dblSpace;
+ dblSpace = DblSpaceGetNextVolume(regionDescriptor, dblSpace))
+ {
+ dblSpace->ChangeMountState = FALSE;
+ dblSpace->NewDriveLetter = TEXT('\0');
+ }
+ EndDialog(hDlg, FALSE);
+ break;
+
+ case IDOK:
+
+ EndDialog(hDlg, TRUE);
+ break;
+
+ case IDC_DBLSPACE_ADD:
+
+ DblSpaceCreate(hDlg);
+ break;
+
+ case IDC_DBLSPACE_DELETE:
+
+ hwndCombo = GetDlgItem(hDlg, IDC_DBLSPACE_VOLUME);
+ selection = ComboBox_GetCurSel(hwndCombo);
+ ComboBox_GetLBText(hwndCombo, selection, outputString);
+
+ // relate the name to a DoubleSpace volume
+
+ dblSpace = DblSpaceFindVolume(regionDescriptor, outputString);
+ if (NULL == dblSpace)
+ {
+ break;
+ }
+
+ DblSpaceDelete(dblSpace);
+ break;
+
+ case IDC_MOUNT_OR_DISMOUNT:
+
+ // The state of something in the dialog changed.
+ // Determine which DoubleSpace volume is involved.
+
+ hwndCombo = GetDlgItem(hDlg, IDC_DBLSPACE_VOLUME);
+ selection = ComboBox_GetCurSel(hwndCombo);
+ ComboBox_GetLBText(hwndCombo, selection, outputString);
+
+ // relate the name to a DoubleSpace volume
+
+ dblSpace = DblSpaceFindVolume(regionDescriptor, outputString);
+ if (NULL == dblSpace)
+ {
+ break;
+ }
+
+ if (dblSpace->Mounted)
+ {
+ // dismount the volume
+
+ errorMessage = DblSpaceDismountDrive(regionDescriptor,
+ dblSpace);
+
+ if (errorMessage)
+ {
+ ErrorDialog(errorMessage);
+ }
+ else
+ {
+ // Update the dialog
+
+ DblSpaceSetDialogState(hDlg, dblSpace);
+ DblSpaceUpdateIniFile(regionDescriptor);
+ }
+ }
+ else
+ {
+ // mount the volume unless the user cancels out
+
+ result = DialogBoxParam(g_hInstance,
+ MAKEINTRESOURCE(IDD_DBLSPACE_DRIVELET),
+ hDlg,
+ DblSpaceMountDlgProc,
+ (LPARAM)dblSpace);
+ if (result)
+ {
+ errorMessage = DblSpaceMountDrive(regionDescriptor, dblSpace);
+
+ if (errorMessage)
+ {
+ ErrorDialog(errorMessage);
+ }
+ else
+ {
+ // Update the dialog
+
+ DblSpaceSetDialogState(hDlg, dblSpace);
+ DblSpaceUpdateIniFile(regionDescriptor);
+ }
+ }
+ }
+ DrawDiskBar(SingleSel);
+ ForceLBRedraw();
+ break;
+
+ default:
+
+ // The state of something in the dialog changed.
+ // Determine which DoubleSpace volume is involved.
+
+ hwndCombo = GetDlgItem(hDlg, IDC_DBLSPACE_VOLUME);
+ selection = ComboBox_GetCurSel(hwndCombo);
+ ComboBox_GetLBText(hwndCombo, selection, outputString);
+
+ // relate the name to a DoubleSpace volume
+
+ hwndMountButton = GetDlgItem(hDlg, IDC_MOUNT_OR_DISMOUNT);
+ hwndDeleteButton = GetDlgItem(hDlg, IDC_DBLSPACE_DELETE);
+
+ dblSpace = DblSpaceFindVolume(regionDescriptor, outputString);
+ if (NULL == dblSpace)
+ {
+ // update the Mount/Dismount button to say mount and grey it
+
+ LoadString(g_hInstance,
+ IDS_MOUNT,
+ outputString,
+ ARRAYLEN(outputString));
+ SetDlgItemText(hDlg, IDC_MOUNT_OR_DISMOUNT, outputString);
+ EnableWindow(hwndMountButton, FALSE);
+ EnableWindow(hwndDeleteButton, FALSE);
+ break;
+ }
+ else
+ {
+ EnableWindow(hwndMountButton, TRUE);
+ EnableWindow(hwndDeleteButton, TRUE);
+ }
+
+ if (HIWORD(wParam) == LBN_SELCHANGE)
+ {
+ // update the allocated/compressed size items
+
+ wsprintf(outputString, TEXT("%u"), dblSpace->AllocatedSize);
+ SetDlgItemText(hDlg, IDC_DBLSPACE_ALLOCATED, outputString);
+
+ // update mount state
+
+ DblSpaceSetDialogState(hDlg, dblSpace);
+ }
+
+ break;
+ }
+ break;
+ }
+ return FALSE;
+}
+
+VOID
+DblSpace(
+ IN HWND hwndParent
+ )
+
+/*++
+
+Routine Description:
+
+ Start the dialog box for DoubleSpace.
+
+Arguments:
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ int result;
+
+ if (g_IsFullDoubleSpace)
+ {
+ result = DialogBox(g_hInstance,
+ MAKEINTRESOURCE(IDD_DBLSPACE_FULL),
+ hwndParent,
+ DblSpaceDlgProc);
+
+ }
+ else
+ {
+ result = DialogBox(g_hInstance,
+ MAKEINTRESOURCE(IDD_DBLSPACE),
+ hwndParent,
+ DblSpaceDlgProc);
+ }
+ if (result)
+ {
+ DrawDiskBar(SingleSel);
+ ForceLBRedraw();
+ }
+}
+
+#endif // DBLSPACE_ENABLED
diff --git a/private/utils/windisk/src/dblspace.dlg b/private/utils/windisk/src/dblspace.dlg
new file mode 100644
index 000000000..7b0b382ec
--- /dev/null
+++ b/private/utils/windisk/src/dblspace.dlg
@@ -0,0 +1,115 @@
+1 DLGINCLUDE "dblspace.H"
+
+IDD_ADDDBL DIALOG 5, 17, 212, 57
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Add DoubleSpace Drive"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Drive appears as:", -1, 7, 8, 68, 12
+ LTEXT "Drive label:", -1, 8, 23, 68, 12, NOT WS_GROUP
+ LTEXT "Size of drive (MB):", -1, 7, 37, 68, 12, NOT WS_GROUP
+ COMBOBOX IDC_ADDDBL_DRIVELETTER, 80, 6, 33, 35, CBS_DROPDOWNLIST |
+ CBS_SORT | WS_VSCROLL | WS_GROUP | WS_TABSTOP
+ EDITTEXT IDC_ADDDBL_LABEL, 80, 22, 77, 12, ES_AUTOHSCROLL
+ EDITTEXT IDC_ADDDBL_SIZE, 80, 37, 55, 12, ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK", IDOK, 166, 3, 40, 14, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, 166, 20, 40, 14
+ PUSHBUTTON "&Help", IDHELP, 166, 39, 40, 14
+END
+
+IDD_DBLSPACE_CANCEL DIALOG 7, 18, 160, 65
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+STYLE WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Create DoubleSpace Volume"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CTEXT "", IDC_DBLPROG_Title, 15, 36, 131, 8
+ CONTROL "", IDC_DBLPROG_GasGauge, "Static", SS_BLACKFRAME, 15,
+ 10, 131, 22
+ DEFPUSHBUTTON "Cancel", IDCANCEL, 60, 45, 40, 14
+END
+
+IDD_DBLSPACE DIALOG 10, 28, 180, 115
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "DoubleSpace Volumes"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Volume Names", -1, 10, 15, 90, 8
+ COMBOBOX IDC_DBLSPACE_VOLUME, 10, 25, 100, 45, CBS_SIMPLE |
+ WS_VSCROLL | WS_TABSTOP
+ LTEXT "Allocated Size:", -1, 10, 80, 55, 8
+ LTEXT "", IDC_DBLSPACE_ALLOCATED, 70, 80, 19, 8
+ LTEXT "MB", -1, 90, 80, 15, 8
+ LTEXT "", IDC_MOUNT_STATE, 10, 92, 140, 8
+ LTEXT "", IDC_DBLSPACE_LETTER, 155, 92, 22, 8
+ DEFPUSHBUTTON "", IDC_MOUNT_OR_DISMOUNT, 130, 5, 40, 14
+ DEFPUSHBUTTON "&Done", IDOK, 130, 24, 40, 14
+ DEFPUSHBUTTON "&Help", IDHELP, 130, 43, 40, 14
+END
+
+IDD_DBLSPACE_FULL DIALOG 11, 28, 180, 125
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "DoubleSpace Volumes"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Volume Names", -1, 10, 15, 90, 8
+ COMBOBOX IDC_DBLSPACE_VOLUME, 10, 25, 100, 45, CBS_SIMPLE |
+ WS_VSCROLL | WS_TABSTOP
+ LTEXT "Allocated Size:", -1, 10, 75, 54, 8
+ LTEXT "", IDC_DBLSPACE_ALLOCATED, 75, 75, 14, 8
+ LTEXT "MB", -1, 90, 75, 15, 8
+ LTEXT "", IDC_MOUNT_STATE, 10, 85, 83, 8
+ LTEXT "", IDC_DBLSPACE_LETTER, 99, 85, 22, 8
+ DEFPUSHBUTTON "Create", IDC_DBLSPACE_ADD, 130, 5, 40, 14
+ DEFPUSHBUTTON "Delete", IDC_DBLSPACE_DELETE, 130, 24, 40, 14
+ DEFPUSHBUTTON "", IDC_MOUNT_OR_DISMOUNT, 130, 43, 40, 14
+ DEFPUSHBUTTON "&Done", IDOK, 130, 62, 40, 14
+ DEFPUSHBUTTON "&Help", IDHELP, 130, 80, 40, 14
+END
+
+IDD_DBLSPACE_CREATE DIALOG 10, 28, 183, 102
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Create DoubleSpace Volume"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Minimum Size", IDC_MINMAX_MINLABEL, 10, 8, 70, 8
+ LTEXT "Maximum Size", IDC_MINMAX_MAXLABEL, 10, 18, 70, 8
+ RTEXT "", IDC_MINMAX_MIN, 75, 8, 25, 8
+ RTEXT "", IDC_MINMAX_MAX, 75, 18, 25, 8
+ LTEXT "MB", -1, 112, 8, 11, 8
+ LTEXT "MB", -1, 112, 18, 11, 8
+ LTEXT "&Allocated size:", -1, 10, 35, 62, 8
+ EDITTEXT IDC_DBLCREATE_SIZE, 75, 35, 35, 12, ES_AUTOHSCROLL
+ CONTROL "", IDC_DBLCREATE_ALLOCATED, "msctls_updown32", 0x0000,
+ 103, 35, 7, 12
+ LTEXT "MB", -1, 112, 35, 11, 8
+ LTEXT "Compressed size:", -1, 10, 50, 70, 8
+ RTEXT "", IDC_DBLCREATE_COMPRESSED, 75, 50, 25, 8
+ LTEXT "MB", -1, 112, 50, 11, 8
+ LTEXT "&Drive Letter", IDC_DBLCREATE_LETTER, 10, 65, 50, 8
+ COMBOBOX IDC_DBLCREATE_LETTER_CHOICES, 60, 65, 22, 51,
+ CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "&Label", -1, 10, 85, 50, 8
+ EDITTEXT IDC_DBLCREATE_NAME, 60, 85, 63, 12
+ DEFPUSHBUTTON "OK", IDOK, 135, 10, 40, 14
+ PUSHBUTTON "Cancel", IDCANCEL, 135, 30, 40, 14
+ PUSHBUTTON "&Help", IDHELP, 135, 50, 40, 14
+END
+
+IDD_DBLSPACE_DRIVELET DIALOG 11, 28, 140, 68
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Mount DoubleSpace Volume as..."
+FONT 8, "MS Shell Dlg"
+BEGIN
+ DEFPUSHBUTTON "OK", IDOK, 90, 6, 40, 14
+ PUSHBUTTON "Cancel", IDCANCEL, 90, 23, 40, 14
+ PUSHBUTTON "&Help", IDHELP, 90, 43, 40, 14
+ LTEXT "&Drive Letter", IDC_DBLDRIVELET_LETTER, 10, 10, 50, 8
+ COMBOBOX IDC_DBLDRIVELET_LETTER_CHOICES, 60, 10, 22, 51,
+ CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
+END
diff --git a/private/utils/windisk/src/dblspace.h b/private/utils/windisk/src/dblspace.h
new file mode 100644
index 000000000..d74a63871
--- /dev/null
+++ b/private/utils/windisk/src/dblspace.h
@@ -0,0 +1,91 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: dblspace.h
+//
+// Contents: Constants for Disk Administrator dialogs
+//
+// History: 16-Aug-93 BruceFo Created
+//
+// Notes: These values are in the range 7000 to 8999, with every
+// 100 being a separate dialog.
+//
+//----------------------------------------------------------------------------
+
+//
+// This IDHELP definition is redundant with windows.h, but makes dlgedit
+// happy.
+//
+
+#ifndef IDHELP
+#define IDHELP 9
+#endif
+
+
+//
+// Min/Max dialog
+//
+
+#define IDC_MINMAX_MINLABEL 7801
+#define IDC_MINMAX_MAXLABEL 7802
+#define IDC_MINMAX_MIN 7804
+#define IDC_MINMAX_MAX 7805
+
+//
+// "Add DoubleSpace Drive" dialog
+//
+
+#define IDD_ADDDBL 9100
+
+#define IDC_ADDDBL_LABEL 9101
+#define IDC_ADDDBL_SIZE 9102
+#define IDC_ADDDBL_DRIVELETTER 9103
+
+//
+//
+//
+
+#define IDD_DBLSPACE 9300
+#define IDD_DBLSPACE_FULL 9301
+
+#define IDC_DBLSPACE_VOLUME 9302
+#define IDC_DBLSPACE_ALLOCATED 9303
+#define IDC_DBLSPACE_LETTER 9305
+#define IDC_MOUNT_STATE 9306
+#define IDC_MOUNT_OR_DISMOUNT 9307
+#define IDC_DBLSPACE_ADD 9308
+#define IDC_DBLSPACE_DELETE 9309
+
+//
+// Create DoubleSpace volume dialog. Uses Min/Max control ids.
+//
+
+#define IDD_DBLSPACE_CREATE 9400
+
+#define IDC_DBLCREATE_SIZE 9401
+#define IDC_DBLCREATE_ALLOCATED 9402
+#define IDC_DBLCREATE_COMPRESSED 9403
+#define IDC_DBLCREATE_LETTER 9404
+#define IDC_DBLCREATE_LETTER_CHOICES 9405
+#define IDC_DBLCREATE_NAME 9406
+
+
+//
+//
+//
+
+#define IDD_DBLSPACE_DRIVELET 9800
+
+#define IDC_DBLDRIVELET_LETTER 9801
+#define IDC_DBLDRIVELET_LETTER_CHOICES 9802
+
+//
+//
+//
+
+#define IDD_DBLSPACE_CANCEL 9900
+
+#define IDC_DBLPROG_GasGauge 9901
+#define IDC_DBLPROG_Title 9902
diff --git a/private/utils/windisk/src/dblspace.hxx b/private/utils/windisk/src/dblspace.hxx
new file mode 100644
index 000000000..0859321ff
--- /dev/null
+++ b/private/utils/windisk/src/dblspace.hxx
@@ -0,0 +1,59 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: dblspace.hxx
+//
+// Contents: Declarations for DoubleSpace support
+//
+// History: 15-Jan-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __DBLSPACE_HXX__
+#define __DBLSPACE_HXX__
+
+#if defined( DBLSPACE_ENABLED )
+
+//////////////////////////////////////////////////////////////////////////////
+
+BOOL
+DblSpaceVolumeExists(
+ IN PREGION_DESCRIPTOR RegionDescriptor
+ );
+
+BOOL
+DblSpaceDismountedVolumeExists(
+ IN PREGION_DESCRIPTOR RegionDescriptor
+ );
+
+BOOLEAN
+DblSpaceCreate(
+ IN HWND hwndOwner
+ );
+
+VOID
+DblSpaceDelete(
+ IN PDBLSPACE_DESCRIPTOR DblSpace
+ );
+
+VOID
+DblSpaceInitialize(
+ VOID
+ );
+
+VOID
+DblSpace(
+ IN HWND hwndParent
+ );
+
+PDBLSPACE_DESCRIPTOR
+DblSpaceGetNextVolume(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ IN PDBLSPACE_DESCRIPTOR DblSpace
+ );
+
+#endif // DBLSPACE_ENABLED
+
+#endif // __DBLSPACE_HXX__
diff --git a/private/utils/windisk/src/dblspace.res b/private/utils/windisk/src/dblspace.res
new file mode 100644
index 000000000..1db90bf6c
--- /dev/null
+++ b/private/utils/windisk/src/dblspace.res
Binary files differ
diff --git a/private/utils/windisk/src/dialogs.dlg b/private/utils/windisk/src/dialogs.dlg
new file mode 100644
index 000000000..6389a8b2c
--- /dev/null
+++ b/private/utils/windisk/src/dialogs.dlg
@@ -0,0 +1,126 @@
+1 DLGINCLUDE "dialogs.h"
+
+IDD_DISPLAYOPTIONS DIALOG 6, 18, 211, 156
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Region Display Options"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ COMBOBOX IDC_DISK_COMBOBOX, 65, 51, 30, 40, CBS_DROPDOWNLIST |
+ CBS_SORT | WS_VSCROLL | WS_GROUP | WS_TABSTOP
+ PUSHBUTTON "&Reset All", IDC_RESETALL, 146, 25, 48, 16, WS_GROUP
+ AUTORADIOBUTTON "Size regions based on &actual size", IDC_RBPROPORTIONAL,
+ 18, 84, 158, 10, WS_GROUP | WS_TABSTOP
+ AUTORADIOBUTTON "Size all regions &equally", IDC_RBEQUAL, 18, 96, 158,
+ 10
+ AUTORADIOBUTTON "&Let Disk Administrator decide how to size regions",
+ IDC_RBAUTO, 18, 108, 173, 10
+ DEFPUSHBUTTON "OK", IDOK, 29, 135, 40, 14, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, 85, 135, 40, 14
+ PUSHBUTTON "&Help", IDHELP, 141, 135, 40, 14
+ GROUPBOX "Which disk", -1, 17, 19, 115, 53
+ AUTORADIOBUTTON "&All disks", IDC_AllDisks, 24, 33, 101, 10
+ AUTORADIOBUTTON "For &disk", IDC_OneDisk, 24, 51, 40, 10
+END
+
+IDD_DISKOPTIONS DIALOG 6, 18, 211, 61
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Disk Display Options"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ AUTORADIOBUTTON "&Size disks based on actual size", IDC_DISKPROPORTIONAL,
+ 23, 8, 158, 10, WS_GROUP | WS_TABSTOP
+ AUTORADIOBUTTON "Size all disks &equally", IDC_DISKEQUAL, 23, 20, 158,
+ 10
+ DEFPUSHBUTTON "OK", IDOK, 25, 41, 40, 14, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, 81, 41, 40, 14
+ PUSHBUTTON "&Help", IDHELP, 137, 41, 40, 14
+END
+
+IDD_MINMAX DIALOG 3, 15, 221, 131
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "", IDC_MINMAX_MINLABEL, 10, 18, 136, 8
+ LTEXT "", IDC_MINMAX_MAXLABEL, 10, 30, 136, 8
+ LTEXT "", IDC_MINMAX_SIZLABEL, 10, 54, 136, 8
+ LTEXT "MB", -1, 202, 18, 11, 8
+ LTEXT "MB", -1, 202, 30, 11, 8
+ LTEXT "MB", -1, 202, 54, 11, 8
+ RTEXT "", IDC_MINMAX_MIN, 151, 18, 46, 8
+ RTEXT "", IDC_MINMAX_MAX, 151, 30, 46, 8
+ EDITTEXT IDC_MINMAX_SIZE, 161, 52, 37, 12, ES_AUTOHSCROLL
+ DEFPUSHBUTTON "OK", IDOK, 35, 111, 40, 14, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, 91, 111, 40, 14
+ PUSHBUTTON "&Help", IDHELP, 147, 111, 40, 14
+END
+
+IDD_DRIVELET DIALOG 6, 18, 180, 124
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Assign Drive Letter"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "", IDC_DRIVELET_DESCR, 14, 12, 152, 16
+ GROUPBOX "", -1, 19, 30, 142, 58
+ AUTORADIOBUTTON "&Assign drive letter", IDC_DRIVELET_RBASSIGN, 36, 46,
+ 70, 10
+ AUTORADIOBUTTON "Do &not assign a drive letter", IDC_DRIVELET_RBNOASSIGN,
+ 36, 64, 100, 10
+ COMBOBOX IDC_DRIVELET_COMBOBOX, 109, 46, 24, 77, CBS_DROPDOWNLIST |
+ CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ DEFPUSHBUTTON "OK", IDOK, 15, 101, 40, 17
+ PUSHBUTTON "Cancel", IDCANCEL, 70, 101, 40, 17
+ PUSHBUTTON "&Help", IDHELP, 125, 101, 40, 17
+END
+
+IDD_COLORS DIALOG 4, 16, 289, 131
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Colors and Patterns"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Color &and pattern for:", -1, 10, 8, 229, 8
+ COMBOBOX IDC_COLORDLGCOMBO, 10, 21, 267, 65, CBS_DROPDOWNLIST |
+ WS_VSCROLL | WS_TABSTOP
+ GROUPBOX "&Colors", -1, 10, 39, 106, 80, WS_GROUP
+ CONTROL "", IDC_COLOR1, "RectControl", 0x0002, 27, 55, 15, 11
+ CONTROL "", IDC_COLOR2, "RectControl", 0x0002, 27, 69, 15, 11
+ CONTROL "", IDC_COLOR3, "RectControl", 0x0002, 27, 83, 15, 11
+ CONTROL "", IDC_COLOR4, "RectControl", 0x0002, 27, 97, 15, 11
+ CONTROL "", IDC_COLOR5, "RectControl", 0x0002, 46, 55, 15, 11
+ CONTROL "", IDC_COLOR6, "RectControl", 0x0002, 46, 69, 15, 11
+ CONTROL "", IDC_COLOR7, "RectControl", 0x0002, 46, 83, 15, 11
+ CONTROL "", IDC_COLOR8, "RectControl", 0x0002, 46, 97, 15, 11
+ CONTROL "", IDC_COLOR9, "RectControl", 0x0002, 65, 55, 15, 11
+ CONTROL "", IDC_COLOR10, "RectControl", 0x0002, 65, 69, 15, 11
+ CONTROL "", IDC_COLOR11, "RectControl", 0x0002, 65, 83, 15, 11
+ CONTROL "", IDC_COLOR12, "RectControl", 0x0002, 65, 97, 15, 11
+ CONTROL "", IDC_COLOR13, "RectControl", 0x0002, 84, 55, 15, 11
+ CONTROL "", IDC_COLOR14, "RectControl", 0x0002, 84, 69, 15, 11
+ CONTROL "", IDC_COLOR15, "RectControl", 0x0002, 84, 83, 15, 11
+ CONTROL "", IDC_COLOR16, "RectControl", 0x0002, 84, 97, 15, 11
+ GROUPBOX "&Patterns", -1, 127, 39, 94, 80, WS_GROUP
+ CONTROL "", IDC_PATTERN1, "RectControl", 0x0001, 142, 55, 27, 15
+ CONTROL "", IDC_PATTERN2, "RectControl", 0x0001, 142, 74, 27, 15
+ CONTROL "", IDC_PATTERN3, "RectControl", 0x0001, 142, 93, 27, 15
+ CONTROL "", IDC_PATTERN4, "RectControl", 0x0001, 179, 55, 27, 15
+ CONTROL "", IDC_PATTERN5, "RectControl", 0x0001, 179, 74, 27, 15
+ CONTROL "", IDC_PATTERN6, "RectControl", 0x0001, 179, 93, 27, 15
+ DEFPUSHBUTTON "OK", IDOK, 233, 44, 44, 18, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, 233, 71, 44, 18
+ PUSHBUTTON "&Help", IDHELP, 233, 98, 44, 18
+END
+
+IDD_STARTUP DIALOG 4, 15, 160, 45
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION
+CAPTION "Disk Administrator is initializing"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CTEXT "", IDC_TEXT, 0, 32, 160, 8
+ CONTROL "", IDC_GASGAUGE, "Static", SS_BLACKFRAME, 12, 7, 136,
+ 22
+END
diff --git a/private/utils/windisk/src/dialogs.h b/private/utils/windisk/src/dialogs.h
new file mode 100644
index 000000000..04e1d84ae
--- /dev/null
+++ b/private/utils/windisk/src/dialogs.h
@@ -0,0 +1,263 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: dialogs.h
+//
+// Contents: Constants for Disk Administrator dialogs
+//
+// History: 16-Aug-93 BruceFo Created
+//
+// Notes: These values are in the range 7000 to 8999, with every
+// 100 being a separate dialog.
+//
+//----------------------------------------------------------------------------
+
+//
+// This IDHELP definition is redundant with windows.h, but makes dlgedit
+// happy.
+//
+
+#ifndef IDHELP
+#define IDHELP 9
+#endif
+
+//
+// The first 100 are reserved for common ids
+//
+
+#define IDC_Label_Text 7000
+#define IDC_Label 7001
+
+//
+// The rest are specific to various dialogs
+//
+
+//
+// Format dialog
+//
+
+#define IDD_FORMAT 7100
+
+#define IDC_FormatType_Text 7101
+#define IDC_FormatType 7102
+#define IDC_QuickFormat 7103
+
+//
+// Format progress dialog (w/ %done thermometer)
+//
+
+#define IDD_FORMATPROGRESS 7200
+#define IDD_FORMATPROGRESS_NOSTOP 7201
+
+#define IDC_FMTPROG_GasGauge 7202
+#define IDC_FMTPROG_Title 7203
+
+//
+// "Are you sure you want to stop formatting?" dialog
+//
+
+#define IDD_StopFmt 7300
+
+#define IDC_StopFmt_Stop 7301
+#define IDC_StopFmt_Continue 7302
+#define IDC_StopFmt_Text 7303
+
+//
+// Property sheet "general" page dialog
+//
+
+#define IDD_GENLPAGE 7400
+
+#define IDC_DriveStatus 7401
+#define IDC_FileSystem 7402
+#define IDC_DriveLetter 7403
+#define IDC_FreeColor 7404
+#define IDC_FreeSpace 7405
+#define IDC_FreeSpaceMB 7406
+#define IDC_UsedColor 7407
+#define IDC_UsedSpace 7408
+#define IDC_UsedSpaceMB 7409
+#define IDC_Capacity 7410
+#define IDC_CapacityMB 7411
+#define IDC_Refresh 7412
+#define IDC_Graph 7413
+#define IDC_CheckNow 7415
+#define IDC_Format 7416
+#define IDC_Line1 7417
+#define IDC_Line2 7418
+#define IDC_Line3 7419
+#define IDC_GENL_Label 7420
+
+#define IDC_GENL_1 7430
+#define IDC_GENL_2 7431
+#define IDC_GENL_3 7432
+#define IDC_GENL_4 7433
+#define IDC_GENL_5 7434
+#define IDC_GENL_6 7435
+#define IDC_GENL_7 7436
+
+
+//
+// Options dialog
+//
+
+#define IDD_DISPLAYOPTIONS 7600
+
+#define IDC_DISK_COMBOBOX 7601
+#define IDC_RESETALL 7602
+#define IDC_RBPROPORTIONAL 7603
+#define IDC_RBEQUAL 7604
+#define IDC_RBAUTO 7605
+
+// NOTE: IDC_AllDisks & IDC_OneDisk must be sequential, in that order
+
+#define IDC_AllDisks 7606
+#define IDC_OneDisk 7607
+
+//
+// Disk display dialog
+//
+
+#define IDD_DISKOPTIONS 7700
+
+// NOTE: IDC_DISKPROPORTIONAL & IDC_DISKEQUAL must be sequential, in
+// that order
+
+#define IDC_DISKPROPORTIONAL 7701
+#define IDC_DISKEQUAL 7702
+
+//
+// Min/Max dialog
+//
+
+#define IDD_MINMAX 7800
+
+#define IDC_MINMAX_MINLABEL 7801
+#define IDC_MINMAX_MAXLABEL 7802
+#define IDC_MINMAX_SIZLABEL 7803
+#define IDC_MINMAX_MIN 7804
+#define IDC_MINMAX_MAX 7805
+#define IDC_MINMAX_SIZE 7806
+#define IDC_MINMAX_SCROLL 7807
+
+//
+// Drive letter dialog
+//
+
+#define IDD_DRIVELET 7900
+
+#define IDC_DRIVELET_RBASSIGN 7901
+#define IDC_DRIVELET_RBNOASSIGN 7902
+#define IDC_DRIVELET_DESCR 7903
+#define IDC_DRIVELET_COMBOBOX 7904
+
+//
+// Colors & patters dialog
+//
+
+#define IDD_COLORS 8000
+
+#define IDC_COLORDLGCOMBO 8001
+#define IDC_COLOR1 8002
+#define IDC_COLOR2 8003
+#define IDC_COLOR3 8004
+#define IDC_COLOR4 8005
+#define IDC_COLOR5 8006
+#define IDC_COLOR6 8007
+#define IDC_COLOR7 8008
+#define IDC_COLOR8 8009
+#define IDC_COLOR9 8010
+#define IDC_COLOR10 8011
+#define IDC_COLOR11 8012
+#define IDC_COLOR12 8013
+#define IDC_COLOR13 8014
+#define IDC_COLOR14 8015
+#define IDC_COLOR15 8016
+#define IDC_COLOR16 8017
+#define IDC_PATTERN1 8018
+#define IDC_PATTERN2 8019
+#define IDC_PATTERN3 8020
+#define IDC_PATTERN4 8021
+#define IDC_PATTERN5 8022
+#define IDC_PATTERN6 8023
+
+//
+// "chkdsk" dialog
+//
+
+#define IDD_CHKDSK 8500
+
+#define IDC_CHKDSK_VolumeToCheck 8501
+
+// note: the following 3 are radio buttons, in order
+
+#define IDC_CHKDSK_DontFix 8502
+#define IDC_CHKDSK_Fix 8503
+#define IDC_CHKDSK_FixAll 8504
+
+//
+// Chkdsk progress dialog, w/ %done thermometer
+//
+
+#define IDD_CHKDSKPROGRESS 8600
+#define IDD_CHKDSKPROGRESS_NOSTOP 8601
+#define IDD_CHKDSKPROGRESS_NOPERCENT 9200
+#define IDD_CHKDSKPROGRESS_NOSTOP_NOPERCENT 9700
+
+#define IDC_CHKPROG_Title 8602
+#define IDC_CHKPROG_GasGauge 8603
+#define IDC_CHKPROG_GasGaugeCaption 8604
+
+//
+// "Are you sure you want to stop checking" dialog
+//
+
+#define IDD_StopChk 8700
+
+#define IDC_StopChk_Text 8701
+#define IDC_StopChk_Stop 8702
+#define IDC_StopChk_Continue 8703
+
+//
+// "printing chkdsk results" dialog
+//
+
+#define IDD_CHKPRINT 8800
+
+//
+// Chkdsk results dialog
+//
+
+#define IDD_CHKDONE 8900
+
+#define IDC_CHKDONE_Messages 8901
+#define IDC_CHKDONE_Close 8902
+#define IDC_CHKDONE_TITLE 8903
+#define IDC_CHKDONE_Save 8904
+#define IDC_CHKDONE_Print 8905
+
+//
+// "label" dialog
+//
+
+#define IDD_LABEL 9000
+
+#define IDC_LABEL 9001
+
+//
+// Startup dialog
+//
+
+#define IDD_STARTUP 11000
+
+//
+// CD-ROM property page
+//
+
+#define IDD_CDROMPAGE 200
+#define IDC_TEXT 11001
+#define IDC_GASGAUGE 11002
+
+#define IDI_STOP_SIGN 3002
diff --git a/private/utils/windisk/src/dialogs.res b/private/utils/windisk/src/dialogs.res
new file mode 100644
index 000000000..18152dd1d
--- /dev/null
+++ b/private/utils/windisk/src/dialogs.res
Binary files differ
diff --git a/private/utils/windisk/src/dispinfo.cxx b/private/utils/windisk/src/dispinfo.cxx
new file mode 100644
index 000000000..1028cd3fe
--- /dev/null
+++ b/private/utils/windisk/src/dispinfo.cxx
@@ -0,0 +1,126 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: dispinfo.cxx
+//
+// Contents: Encapsulates display information for windisk
+//
+// History: 27-Oct-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include <stdio.h>
+#include "dispinfo.hxx"
+
+CDispInfo::CDispInfo(
+ VOID
+ )
+{
+ for (int i = 0; i < g_cColumns; i++)
+ {
+ apsz[i] = NULL;
+ }
+}
+
+CDispInfo::~CDispInfo()
+{
+ for (int i = 0; i < g_cColumns; i++)
+ {
+ delete[] apsz[i];
+ }
+}
+
+BOOL
+CDispInfo::SetText(
+ IN int column,
+ IN PWSTR pszString
+ )
+{
+ if (column < 0 || column > g_cColumns - 1)
+ {
+ return FALSE; // this should really be an assertion
+ }
+
+ if (NULL != apsz[column])
+ {
+ delete[] apsz[column];
+ }
+
+ int cchLen = wcslen(pszString);
+ apsz[column] = new WCHAR[cchLen + 1];
+ if (NULL == apsz[column])
+ {
+ return FALSE; // BUGBUG: out of memory!
+ }
+
+ wcscpy(apsz[column], pszString);
+ return TRUE;
+}
+
+BOOL
+CDispInfo::SetNumber(
+ IN int column,
+ IN LONG lNum
+ )
+{
+ if (column < 0 || column > g_cColumns - 1)
+ {
+ return FALSE; // this should really be an assertion
+ }
+
+ if (NULL != apsz[column])
+ {
+ delete[] apsz[column];
+ }
+
+ WCHAR szNum[50];
+ wsprintf(szNum, L"%ld", lNum);
+ int cchLen = wcslen(szNum);
+ apsz[column] = new WCHAR[cchLen + 1];
+ if (NULL == apsz[column])
+ {
+ return FALSE; // BUGBUG: out of memory!
+ }
+
+ wcscpy(apsz[column], szNum);
+ return TRUE;
+}
+
+PWSTR
+CDispInfo::GetText(
+ IN int column
+ )
+{
+ if (column < 0 || column > g_cColumns - 1)
+ {
+ return NULL; // this should really be an assertion
+ }
+
+ return apsz[column];
+}
+
+LONG
+CDispInfo::GetNumber(
+ IN int column
+ )
+{
+ if (column < 0 || column > g_cColumns - 1)
+ {
+ return NULL; // this should really be an assertion
+ }
+
+ if (NULL == apsz[column])
+ {
+ return -1L; // better error code?
+ }
+
+ LONG lResult;
+ swscanf(apsz[column], L"%ld", &lResult);
+
+ return lResult;
+}
diff --git a/private/utils/windisk/src/dispinfo.hxx b/private/utils/windisk/src/dispinfo.hxx
new file mode 100644
index 000000000..dbfbe462e
--- /dev/null
+++ b/private/utils/windisk/src/dispinfo.hxx
@@ -0,0 +1,65 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: dispinfo.hxx
+//
+// Contents: Encapsulates display information for windisk
+//
+// History: 27-Oct-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __DISPINFO_HXX__
+#define __DISPINFO_HXX__
+
+#include <volview.hxx>
+
+class CDispInfo
+{
+public:
+
+ CDispInfo(
+ VOID
+ );
+
+ ~CDispInfo();
+
+ //
+ // Set the data
+ //
+
+ BOOL
+ SetText(
+ IN int column,
+ IN PWSTR pszString
+ );
+
+ BOOL
+ SetNumber(
+ IN int column,
+ IN LONG lNum
+ );
+
+ //
+ // Retrieve the data
+ //
+
+ PWSTR
+ GetText(
+ IN int column
+ );
+
+ LONG
+ GetNumber(
+ IN int column
+ );
+
+private:
+
+ PWSTR apsz[g_cColumns];
+
+};
+
+#endif // __DISPINFO_HXX__
diff --git a/private/utils/windisk/src/dlgs.cxx b/private/utils/windisk/src/dlgs.cxx
new file mode 100644
index 000000000..b7e5afdfe
--- /dev/null
+++ b/private/utils/windisk/src/dlgs.cxx
@@ -0,0 +1,1372 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: dlgs.cxx
+//
+// Contents: Dialog routines and dialog support subroutines.
+//
+// History: 7-Jan-92 TedM Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include "dialogs.h"
+#include "dlgs.hxx"
+#include "drives.hxx"
+#include "help.hxx"
+#include "rectpriv.hxx"
+#include "windisk.hxx"
+
+////////////////////////////////////////////////////////////////////////////
+
+// used in color dialog to indicate what the user has chosen for
+// the various graph element types
+
+DWORD SelectedColor[LEGEND_STRING_COUNT];
+DWORD SelectedHatch[LEGEND_STRING_COUNT];
+
+// used in color dialog, contains element (ie, partition, logical volume,
+// etc) we're selecting for (ie, which item is diaplyed in static text of
+// combo box).
+
+DWORD CurrentElement;
+
+// hold old dialog proc for subclassed size control
+
+WNDPROC OldSizeDlgProc;
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+BOOL CALLBACK
+DisplayOptionsDlgProc(
+ IN HWND hdlg,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+BOOL CALLBACK
+DiskOptionsDlgProc(
+ IN HWND hdlg,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+////////////////////////////////////////////////////////////////////////////
+
+HBRUSH
+MyCreateHatchBrush(
+ int fnStyle,
+ COLORREF clrref
+ )
+
+/*++
+
+Routine Description:
+
+ Same as Windows CreateHatchBrush, except you need to use MY_HS_*
+ identifiers, and I support solid "hatch" brushes.
+
+Arguments:
+
+ same as CreateHatchBrush
+
+Return Value:
+
+ same as CreateHatchBrush
+
+--*/
+
+{
+ int fnWindowsStyle;
+
+ switch (fnStyle)
+ {
+ case MY_HS_FDIAGONAL:
+ fnWindowsStyle = HS_FDIAGONAL;
+ goto tagDoHatch;
+
+ case MY_HS_BDIAGONAL:
+ fnWindowsStyle = HS_BDIAGONAL;
+ goto tagDoHatch;
+
+ case MY_HS_CROSS:
+ fnWindowsStyle = HS_CROSS;
+ goto tagDoHatch;
+
+ case MY_HS_DIAGCROSS:
+ fnWindowsStyle = HS_DIAGCROSS;
+ goto tagDoHatch;
+
+ case MY_HS_VERTICAL:
+ fnWindowsStyle = HS_VERTICAL;
+
+tagDoHatch:
+ return CreateHatchBrush(fnWindowsStyle, clrref);
+
+ case MY_HS_SOLIDCLR:
+ return CreateSolidBrush(clrref);
+
+ default:
+ daDebugOut((DEB_IERROR, "Internal error: bad hatch style!\n"));
+ return NULL;
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+VOID
+CenterDialog(
+ HWND hwndToCenter,
+ HWND hwndContext
+ )
+
+/*++
+
+Routine Description:
+
+ Centers a dialog relative to hwndContext
+
+Arguments:
+
+ hwndToCenter - window handle of dialog to center
+ hwndContext - window handle of window to center with respect to
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ POINT point;
+ RECT rcContext, rcWindow;
+ LONG x, y, w, h;
+ LONG sx = GetSystemMetrics(SM_CXSCREEN);
+ LONG sy = GetSystemMetrics(SM_CYSCREEN);
+
+ point.x = point.y = 0;
+ if (hwndContext)
+ {
+ ClientToScreen(hwndContext, &point);
+ GetClientRect (hwndContext, &rcContext);
+ }
+ else
+ {
+ rcContext.top = rcContext.left = 0;
+ rcContext.right = sx;
+ rcContext.bottom = sy;
+ }
+ GetWindowRect (hwndToCenter, &rcWindow);
+
+ w = rcWindow.right - rcWindow.left + 1;
+ h = rcWindow.bottom - rcWindow.top + 1;
+ x = point.x + ((rcContext.right - rcContext.left + 1 - w) / 2);
+ y = point.y + ((rcContext.bottom - rcContext.top + 1 - h) / 2);
+
+ if (x + w > sx)
+ {
+ x = sx - w;
+ }
+ else if (x < 0)
+ {
+ x = 0;
+ }
+
+ if (y + h > sy)
+ {
+ y = sy - h;
+ }
+ else if (y < 0)
+ {
+ y = 0;
+ }
+
+ if (FALSE == MoveWindow(hwndToCenter, x, y, w, h, FALSE))
+ {
+ daDebugOut((DEB_TRACE, "MoveWindow failed\n"));
+ }
+}
+
+
+
+VOID
+CenterDialogInFrame(
+ HWND hwnd
+ )
+
+/*++
+
+Routine Description:
+
+ Centers a dialog relative to the app's main window
+
+Arguments:
+
+ hwnd - window handle of dialog to center
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CenterDialog(hwnd, g_hwndFrame);
+}
+
+
+INT
+SizeDlgProc(
+ IN HWND hDlg,
+ IN UINT wMsg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+
+/*++
+
+Routine Description:
+
+ This routine keeps non-numeric keystrokes out of the dialog
+ for the size of a volume.
+
+Arguments:
+
+ Windows dialog parameters.
+
+Return Value:
+
+ Windows dialog return values.
+ Returns FALSE for any characters that are not numeric.
+
+--*/
+
+{
+ WCHAR letter;
+
+ switch (wMsg)
+ {
+ case WM_CHAR:
+
+ letter = (WCHAR)wParam;
+ if ((letter == TEXT('\t')) || (letter == TEXT('\b')))
+ {
+ break;
+ }
+
+ if (letter >= TEXT('0') && letter <= TEXT('9'))
+ {
+ // do nothing
+ }
+ else
+ {
+ return FALSE;
+ }
+
+ break;
+ }
+
+ return CallWindowProc(OldSizeDlgProc, hDlg, wMsg, wParam, lParam);
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Member: SizeWndProc, public
+//
+// Synopsis: edit window subclass proc to disallow non-numeric characters.
+//
+// History: 5-Apr-95 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+LRESULT CALLBACK
+SizeWndProc(
+ IN HWND hwnd,
+ IN UINT wMsg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ switch (wMsg)
+ {
+ case WM_CHAR:
+ {
+ WCHAR chCharCode = (WCHAR)wParam;
+ if ( (chCharCode == TEXT('\t'))
+ || (chCharCode == TEXT('\b'))
+ || (chCharCode == TEXT('\n'))
+ )
+ {
+ break;
+ }
+
+ if (chCharCode < TEXT('0') || chCharCode > TEXT('9'))
+ {
+ // bad key: ignore it
+ return FALSE;
+ }
+
+ break;
+ }
+ } // end of switch
+
+ WNDPROC pfnProc = (WNDPROC)GetWindowLong(hwnd,GWL_USERDATA);
+ return CallWindowProc(pfnProc, hwnd, wMsg, wParam, lParam);
+}
+
+
+BOOL CALLBACK
+MinMaxDlgProc(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Dialog procedure for the enter size dialog box. This dialog
+ allows the user to enter a size for a partition, or use
+ spin controls (a tiny scroll bar) to select the size.
+ Possible outcomes are cancel or OK. In the latter case the
+ EndDialog code is the size. In the former it is 0.
+
+Arguments:
+
+ hwnd - window handle of dialog box
+
+ msg - message #
+
+ wParam - msg specific data
+
+ lParam - msg specific data
+
+Return Value:
+
+ msg dependent
+
+--*/
+
+{
+ static DWORD minSizeMB;
+ static DWORD maxSizeMB;
+ static DWORD helpContextId;
+
+ TCHAR outputString[MESSAGE_BUFFER_SIZE];
+ PMINMAXDLG_PARAMS params;
+ BOOL validNumber;
+ DWORD sizeMB;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ CenterDialogInFrame(hwnd);
+ params = (PMINMAXDLG_PARAMS)lParam;
+
+ // Subclass edit control to disallow non-positive numbers
+ WNDPROC pfnProc = (WNDPROC)SetWindowLong(
+ GetDlgItem(hwnd, IDC_MINMAX_SIZE),
+ GWL_WNDPROC,
+ (LONG)&SizeWndProc);
+ SetWindowLong(GetDlgItem(hwnd, IDC_MINMAX_SIZE), GWL_USERDATA, (LONG)pfnProc);
+
+ // set up caption
+
+ LoadString(
+ g_hInstance,
+ params->CaptionStringID,
+ outputString,
+ ARRAYLEN(outputString));
+ SetWindowText(hwnd, outputString);
+
+ // set up minimum/maximum text
+
+ LoadString(
+ g_hInstance,
+ params->MinimumStringID,
+ outputString,
+ ARRAYLEN(outputString));
+ SetDlgItemText(hwnd, IDC_MINMAX_MINLABEL, outputString);
+ LoadString(
+ g_hInstance,
+ params->MaximumStringID,
+ outputString,
+ ARRAYLEN(outputString));
+ SetDlgItemText(hwnd, IDC_MINMAX_MAXLABEL, outputString);
+ LoadString(
+ g_hInstance,
+ params->SizeStringID,
+ outputString,
+ ARRAYLEN(outputString));
+ SetDlgItemText(hwnd, IDC_MINMAX_SIZLABEL, outputString);
+
+ minSizeMB = params->MinSizeMB;
+ maxSizeMB = params->MaxSizeMB;
+ helpContextId = params->HelpContextId;
+
+ wsprintf(outputString, TEXT("%u"), minSizeMB);
+ SetDlgItemText(hwnd, IDC_MINMAX_MIN, outputString);
+ wsprintf(outputString, TEXT("%u"), maxSizeMB);
+ SetDlgItemText(hwnd, IDC_MINMAX_MAX, outputString);
+
+ SetDlgItemInt(hwnd, IDC_MINMAX_SIZE, maxSizeMB, FALSE);
+ SendDlgItemMessage(hwnd, IDC_MINMAX_SIZE, EM_SETSEL, 0, -1);
+
+ SetFocus(GetDlgItem(hwnd, IDC_MINMAX_SIZE));
+ return FALSE; // indicate focus set to a control
+ }
+
+ case WM_DESTROY:
+ {
+ // restore original subclass to window.
+ WNDPROC pfnProc = (WNDPROC)GetWindowLong(
+ GetDlgItem(hwnd, IDC_MINMAX_SIZE),
+ GWL_USERDATA);
+ SetWindowLong(GetDlgItem(hwnd, IDC_MINMAX_SIZE), GWL_WNDPROC, (LONG)pfnProc);
+ return FALSE;
+ }
+
+ case WM_VSCROLL:
+ // The up/down control changed the edit control: select it again
+ SendDlgItemMessage(hwnd, IDC_MINMAX_SIZE, EM_SETSEL, 0, (LPARAM)-1);
+ return TRUE;
+
+ case WM_COMMAND:
+ {
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+
+ sizeMB = GetDlgItemInt(hwnd, IDC_MINMAX_SIZE, &validNumber, FALSE);
+ if ( !validNumber
+ || !sizeMB
+ || (sizeMB > maxSizeMB)
+ || (sizeMB < minSizeMB))
+ {
+ ErrorDialog(MSG_INVALID_SIZE);
+ SendDlgItemMessage(hwnd, IDC_MINMAX_SIZE, EM_SETSEL, 0, -1);
+ SetFocus(GetDlgItem(hwnd, IDC_MINMAX_SIZE));
+ }
+ else
+ {
+ EndDialog(hwnd, sizeMB);
+ }
+ return TRUE;
+
+ case IDCANCEL:
+
+ EndDialog(hwnd, 0);
+ return TRUE;
+
+ case IDHELP:
+
+ DialogHelp( helpContextId );
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+ }
+
+ default:
+ return FALSE;
+ }
+}
+
+
+
+BOOL CALLBACK
+DriveLetterDlgProc(
+ IN HWND hdlg,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Dialog for allowing the user to select a drive letter for a
+ partition, logical drive, volume set, or stripe set.
+
+ The EndDialog codes are as follows:
+
+ FALSE - user cancelled
+ TRUE - user accepted a new drive letter choice, which was put in
+ the NewDriveLetter field of the parameter
+
+Arguments:
+
+ hdlg - window handle of dialog box
+
+ msg - message #
+
+ wParam - msg specific data
+
+ lParam - msg specific data
+
+Return Value:
+
+ msg dependent
+
+--*/
+
+{
+ static HWND hwndCombo;
+ static DWORD currentSelection;
+ static PDRIVELET_DLG_PARAMS params;
+
+ WCHAR driveLetterString[3];
+ DWORD selection;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ WCHAR driveLetter;
+ DWORD defRadioButton;
+
+ params = (PDRIVELET_DLG_PARAMS)lParam;
+ FDASSERT(NULL != params);
+
+ hwndCombo = GetDlgItem(hdlg, IDC_DRIVELET_COMBOBOX);
+
+ CenterDialogInFrame(hdlg);
+
+ //
+ // Add each available drive letter to the list of available
+ // drive letters.
+ //
+
+ driveLetterString[1] = L':';
+ driveLetterString[2] = L'\0';
+ for (driveLetter = L'C'; driveLetter <= L'Z'; driveLetter++)
+ {
+ if (DriveLetterIsAvailable(driveLetter))
+ {
+ driveLetterString[0] = driveLetter;
+ ComboBox_AddString(hwndCombo, driveLetterString);
+ }
+ }
+
+ SetWindowText(GetDlgItem(hdlg, IDC_DRIVELET_DESCR), params->Description);
+
+ driveLetter = params->DriveLetter;
+
+ if (!IsExtraDriveLetter(driveLetter))
+ {
+ DWORD itemIndex;
+
+ //
+ // There is a default drive letter. Place it on the list,
+ // check the correct radio button, and set the correct default
+ // in the combo box.
+ //
+
+ driveLetterString[0] = driveLetter;
+ itemIndex = ComboBox_AddString(hwndCombo, driveLetterString);
+ ComboBox_SetCurSel(hwndCombo, itemIndex);
+ defRadioButton = IDC_DRIVELET_RBASSIGN;
+ SetFocus(hwndCombo);
+ currentSelection = itemIndex;
+ }
+ else
+ {
+ //
+ // Default is no drive letter. Disable the combo box. Select
+ // the correct radio button.
+ //
+
+ EnableWindow(hwndCombo, FALSE);
+ defRadioButton = IDC_DRIVELET_RBNOASSIGN;
+ ComboBox_SetCurSel(hwndCombo, -1);
+ SetFocus(GetDlgItem(hdlg, IDC_DRIVELET_RBNOASSIGN));
+ currentSelection = 0;
+ }
+
+ CheckRadioButton(
+ hdlg,
+ IDC_DRIVELET_RBASSIGN,
+ IDC_DRIVELET_RBNOASSIGN,
+ defRadioButton
+ );
+
+ return FALSE; // focus set to control
+ }
+
+ case WM_COMMAND:
+
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+
+ //
+ // If the 'no letter' button is checked, return NO_DRIVE_LETTER_EVER
+ //
+
+ if (IsDlgButtonChecked(hdlg, IDC_DRIVELET_RBNOASSIGN))
+ {
+ params->NewDriveLetter = NO_DRIVE_LETTER_EVER;
+ EndDialog(hdlg, TRUE);
+ }
+ else
+ {
+ //
+ // Otherwise, get the currently selected item in the listbox.
+ //
+
+ selection = ComboBox_GetCurSel(hwndCombo);
+ ComboBox_GetLBText(hwndCombo, selection, driveLetterString);
+ params->NewDriveLetter = *driveLetterString;
+ EndDialog(hdlg, TRUE);
+ }
+ break;
+
+ case IDCANCEL:
+
+ EndDialog(hdlg, FALSE);
+ break;
+
+ case IDHELP:
+
+ DialogHelp(HC_DM_DLG_DRIVELETTER);
+ break;
+
+ case IDC_DRIVELET_RBASSIGN:
+
+ if (HIWORD(wParam) == BN_CLICKED)
+ {
+ EnableWindow(hwndCombo, TRUE);
+ ComboBox_SetCurSel(hwndCombo, currentSelection);
+ SetFocus(hwndCombo);
+ }
+ break;
+
+ case IDC_DRIVELET_RBNOASSIGN:
+
+ if (HIWORD(wParam) == BN_CLICKED)
+ {
+ currentSelection = ComboBox_GetCurSel(hwndCombo);
+ ComboBox_SetCurSel(hwndCombo, -1);
+ EnableWindow(hwndCombo, FALSE);
+ }
+ break;
+
+ default:
+
+ return FALSE;
+ }
+ break;
+
+ default:
+
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+BOOL CALLBACK
+DisplayOptionsDlgProc(
+ IN HWND hdlg,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Dialog procedure for display options. Currently the only display option
+ is to alter the graph type (proportional/equal) on each disk.
+
+ For this dialog, lParam on creation must point to a buffer into which
+ this dialog procedure will place the user's new choices for the graph
+ display type for each disk.
+
+Arguments:
+
+ hdlg - window handle of dialog box
+
+ msg - message #
+
+ wParam - msg specific data
+
+ lParam - msg specific data
+
+Return Value:
+
+ msg dependent
+
+--*/
+
+{
+ static PBAR_TYPE newBarTypes;
+ static HWND hwndCombo;
+
+ DWORD selection;
+ DWORD i;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+
+ CenterDialogInFrame(hdlg);
+ newBarTypes = (PBAR_TYPE)lParam;
+ hwndCombo = GetDlgItem(hdlg, IDC_DISK_COMBOBOX);
+
+ CheckRadioButton(hdlg, IDC_AllDisks, IDC_OneDisk, IDC_AllDisks);
+ EnableWindow(GetDlgItem(hdlg, IDC_DISK_COMBOBOX), FALSE);
+
+ //
+ // Add each disk to the combo box.
+ //
+
+ for (i=0; i<DiskCount; i++)
+ {
+ TCHAR diskNumberString[10];
+
+ wsprintf(diskNumberString, TEXT("%u"), i);
+ ComboBox_AddString(hwndCombo, diskNumberString);
+ }
+
+ // select the zeroth item in the combobox
+ ComboBox_SetCurSel(hwndCombo, 0);
+ SendMessage(
+ hdlg,
+ WM_COMMAND,
+ MAKEWPARAM(IDC_DISK_COMBOBOX, CBN_SELCHANGE),
+ 0
+ );
+
+ SetFocus(GetDlgItem(hdlg, IDC_AllDisks));
+
+ return FALSE; // I already set the focus
+
+ case WM_COMMAND:
+
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ EndDialog(hdlg, IDOK);
+ break;
+
+ case IDCANCEL:
+ EndDialog(hdlg, IDCANCEL);
+ break;
+
+ case IDHELP:
+ DialogHelp( HC_DM_DLG_DISPLAYOPTION );
+ break;
+
+ case IDC_AllDisks:
+ if (HIWORD(wParam) == BN_CLICKED)
+ {
+ CheckRadioButton(hdlg, IDC_AllDisks, IDC_OneDisk, IDC_AllDisks);
+ EnableWindow(GetDlgItem(hdlg, IDC_DISK_COMBOBOX), FALSE);
+ }
+ break;
+
+ case IDC_OneDisk:
+ if (HIWORD(wParam) == BN_CLICKED)
+ {
+ CheckRadioButton(hdlg, IDC_AllDisks, IDC_OneDisk, IDC_OneDisk);
+ EnableWindow(GetDlgItem(hdlg, IDC_DISK_COMBOBOX), TRUE);
+ }
+ break;
+
+ case IDC_DISK_COMBOBOX:
+
+ if (HIWORD(wParam) == CBN_SELCHANGE)
+ {
+ int rb;
+
+ //
+ // Selection in the combobox has changed; update the radio buttons
+ //
+
+ selection = ComboBox_GetCurSel(hwndCombo);
+
+ switch (newBarTypes[selection])
+ {
+ case BarProportional:
+ rb = IDC_RBPROPORTIONAL;
+ break;
+ case BarEqual:
+ rb = IDC_RBEQUAL;
+ break;
+ case BarAuto:
+ rb = IDC_RBAUTO;
+ break;
+ default:
+ FDASSERT(FALSE);
+ }
+
+ CheckRadioButton(hdlg, IDC_RBPROPORTIONAL, IDC_RBAUTO, rb);
+ }
+ break;
+
+ case IDC_RESETALL:
+
+ if (HIWORD(wParam) == BN_CLICKED)
+ {
+ for (i=0; i<DiskCount; i++)
+ {
+ newBarTypes[i] = BarAuto;
+ }
+ CheckRadioButton(hdlg, IDC_RBPROPORTIONAL, IDC_RBAUTO, IDC_RBAUTO);
+ }
+ break;
+
+ case IDC_RBPROPORTIONAL:
+
+ if (HIWORD(wParam) == BN_CLICKED)
+ {
+ if (IsDlgButtonChecked(hdlg, IDC_AllDisks))
+ {
+ for (i=0; i<DiskCount; i++)
+ {
+ newBarTypes[i] = BarProportional;
+ }
+ }
+ else
+ {
+ selection = ComboBox_GetCurSel(hwndCombo);
+ newBarTypes[selection] = BarProportional;
+ }
+ }
+ break;
+
+ case IDC_RBEQUAL:
+
+ if (HIWORD(wParam) == BN_CLICKED)
+ {
+ if (IsDlgButtonChecked(hdlg, IDC_AllDisks))
+ {
+ for (i=0; i<DiskCount; i++)
+ {
+ newBarTypes[i] = BarEqual;
+ }
+ }
+ else
+ {
+ selection = ComboBox_GetCurSel(hwndCombo);
+ newBarTypes[selection] = BarEqual;
+ }
+ }
+ break;
+
+ case IDC_RBAUTO:
+
+ if (HIWORD(wParam) == BN_CLICKED)
+ {
+ if (IsDlgButtonChecked(hdlg, IDC_AllDisks))
+ {
+ for (i=0; i<DiskCount; i++)
+ {
+ newBarTypes[i] = BarAuto;
+ }
+ }
+ else
+ {
+ selection = ComboBox_GetCurSel(hwndCombo);
+ newBarTypes[selection] = BarAuto;
+ }
+ }
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ break;
+
+ default:
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DoRegionDisplayDialog
+//
+// Synopsis: Invoke the region display (region sizing) dialog
+//
+// Arguments: [hwndParent] -- the parent window
+//
+// Returns: nothing
+//
+// History: 29-Sep-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DoRegionDisplayDialog(
+ IN HWND hwndParent
+ )
+{
+ unsigned i;
+
+ PBAR_TYPE newBarTypes = (PBAR_TYPE)Malloc(DiskCount * sizeof(BAR_TYPE));
+
+ for (i=0; i<DiskCount; i++)
+ {
+ newBarTypes[i] = DiskArray[i]->BarType;
+ }
+
+ switch (
+ DialogBoxParam( g_hInstance,
+ MAKEINTRESOURCE(IDD_DISPLAYOPTIONS),
+ hwndParent,
+ DisplayOptionsDlgProc,
+ (DWORD)newBarTypes
+ )
+ )
+ {
+ case IDOK:
+ SetCursor(g_hCurWait);
+ for (i=0; i<DiskCount; i++)
+ {
+ DiskArray[i]->BarType = newBarTypes[i];
+ }
+ TotalRedrawAndRepaint();
+ SetCursor(g_hCurNormal);
+ break;
+
+ case IDCANCEL:
+ break;
+
+ case -1:
+ ErrorDialog(ERROR_NOT_ENOUGH_MEMORY);
+ break;
+
+ default:
+ FDASSERT(0);
+ }
+
+ Free(newBarTypes);
+}
+
+
+BOOL CALLBACK
+ColorDlgProc(
+ IN HWND hdlg,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Dialog for the select colors/patterns dialog box. Note that this dialog
+ uses a rectangle custom control, defined below.
+
+Arguments:
+
+ hwnd - window handle of dialog box
+
+ msg - message #
+
+ wParam - msg specific data
+
+ lParam - msg specific data
+
+Return Value:
+
+ msg dependent
+
+--*/
+
+{
+ unsigned i;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ unsigned i;
+ LONG ec;
+ HWND hwndCombo = GetDlgItem(hdlg, IDC_COLORDLGCOMBO);
+
+ CenterDialogInFrame(hdlg);
+
+ for (i=0; i<LEGEND_STRING_COUNT; i++)
+ {
+ ec = ComboBox_AddString(hwndCombo, LegendLabels[i]);
+ if ((ec == CB_ERR) || (ec == CB_ERRSPACE))
+ {
+ EndDialog(hdlg, -1);
+ return FALSE;
+ }
+ SelectedColor[i] = IDC_COLOR1 + BrushColors[i];
+ SelectedHatch[i] = IDC_PATTERN1 + BrushHatches[i];
+ }
+ CurrentElement = 0;
+ ComboBox_SetCurSel(hwndCombo, CurrentElement);
+ SendMessage(
+ hdlg,
+ WM_COMMAND,
+ MAKEWPARAM(GetDlgCtrlID(hwndCombo), CBN_SELCHANGE),
+ (LPARAM)hwndCombo);
+ return TRUE;
+ }
+
+ case WM_COMMAND:
+
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+
+ for (i=0; i<LEGEND_STRING_COUNT; i++)
+ {
+ SelectedColor[i] -= IDC_COLOR1;
+ SelectedHatch[i] -= IDC_PATTERN1;
+ }
+ EndDialog(hdlg, IDOK);
+ break;
+
+ case IDCANCEL:
+ EndDialog(hdlg, IDCANCEL);
+ break;
+
+ case IDHELP:
+ DialogHelp( HC_DM_COLORSANDPATTERNS );
+ break;
+
+ case IDC_COLORDLGCOMBO:
+ switch (HIWORD(wParam))
+ {
+ case CBN_SELCHANGE:
+ // deselect previous color
+ SendMessage(GetDlgItem(hdlg, SelectedColor[CurrentElement]),
+ RM_SELECT,
+ FALSE,
+ 0
+ );
+ // deselect previous pattern
+ SendMessage(GetDlgItem(hdlg, SelectedHatch[CurrentElement]),
+ RM_SELECT,
+ FALSE,
+ 0
+ );
+ CurrentElement = ComboBox_GetCurSel((HWND)lParam);
+ SendMessage(
+ hdlg,
+ WM_COMMAND,
+ MAKEWPARAM(SelectedColor[CurrentElement], RN_CLICKED),
+ 0);
+ SendMessage(
+ hdlg,
+ WM_COMMAND,
+ MAKEWPARAM(SelectedHatch[CurrentElement], RN_CLICKED),
+ 0);
+ break;
+
+ default:
+ return FALSE;
+ }
+ break;
+
+ case IDC_COLOR1:
+ case IDC_COLOR2:
+ case IDC_COLOR3:
+ case IDC_COLOR4:
+ case IDC_COLOR5:
+ case IDC_COLOR6:
+ case IDC_COLOR7:
+ case IDC_COLOR8:
+ case IDC_COLOR9:
+ case IDC_COLOR10:
+ case IDC_COLOR11:
+ case IDC_COLOR12:
+ case IDC_COLOR13:
+ case IDC_COLOR14:
+ case IDC_COLOR15:
+ case IDC_COLOR16:
+ {
+ if (HIWORD(wParam) == RN_CLICKED)
+ {
+ // deselect previous color
+ SendMessage(GetDlgItem(hdlg, SelectedColor[CurrentElement]),
+ RM_SELECT,
+ FALSE,
+ 0
+ );
+ SendMessage(GetDlgItem(hdlg, LOWORD(wParam)),
+ RM_SELECT,
+ TRUE,
+ 0
+ );
+
+ SelectedColor[CurrentElement] = LOWORD(wParam);
+
+ // now force patterns to be redrawn in selected color
+
+ for (i = IDC_PATTERN1; i <= IDC_PATTERN6; i++)
+ {
+ InvalidateRect(GetDlgItem(hdlg, i), NULL, FALSE);
+ }
+ }
+
+ break;
+ }
+
+ case IDC_PATTERN1:
+ case IDC_PATTERN2:
+ case IDC_PATTERN3:
+ case IDC_PATTERN4:
+ case IDC_PATTERN5:
+ case IDC_PATTERN6:
+ {
+ if (HIWORD(wParam) == RN_CLICKED)
+ {
+ // deselect previous pattern
+ SendMessage(GetDlgItem(hdlg, SelectedHatch[CurrentElement]),
+ RM_SELECT,
+ FALSE,
+ 0
+ );
+ SendMessage(GetDlgItem(hdlg, LOWORD(wParam)),
+ RM_SELECT,
+ TRUE,
+ 0
+ );
+
+ SelectedHatch[CurrentElement] = LOWORD(wParam);
+ break;
+ }
+
+ break;
+ }
+
+ } // end of WM_COMMAND switch
+
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+}
+
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DoColorsDialog
+//
+// Synopsis: Invoke the colors dialog
+//
+// Arguments: [hwndParent] -- the parent window
+//
+// Returns: nothing
+//
+// History: 1-Oct-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DoColorsDialog(
+ IN HWND hwndParent
+ )
+{
+ UINT i;
+
+ switch (
+ DialogBox(
+ g_hInstance,
+ MAKEINTRESOURCE(IDD_COLORS),
+ hwndParent,
+ ColorDlgProc)
+ )
+ {
+ case IDOK:
+ for (i=0; i<BRUSH_ARRAY_SIZE; i++)
+ {
+ DeleteBrush(g_Brushes[i]);
+ g_Brushes[i] = MyCreateHatchBrush(
+ AvailableHatches[BrushHatches[i] = SelectedHatch[i]],
+ AvailableColors[BrushColors[i] = SelectedColor[i]]
+ );
+ }
+ SetCursor(g_hCurWait);
+ TotalRedrawAndRepaint();
+ if (g_Legend)
+ {
+ InvalidateRect(g_hwndFrame, NULL, FALSE);
+ }
+ SetCursor(g_hCurNormal);
+ break;
+
+ case IDCANCEL:
+ break;
+
+ case -1:
+ ErrorDialog(ERROR_NOT_ENOUGH_MEMORY);
+ break;
+
+ default:
+ FDASSERT(0);
+ }
+}
+
+
+BOOL CALLBACK
+DiskOptionsDlgProc(
+ IN HWND hdlg,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Dialog procedure for disk options.
+
+Arguments:
+
+ hdlg - window handle of dialog box
+
+ msg - message #
+
+ wParam - msg specific data
+
+ lParam - msg specific data
+
+Return Value:
+
+ msg dependent
+
+--*/
+
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+
+ CenterDialogInFrame(hdlg);
+
+ int idButton = (g_DiskDisplayType == DiskProportional)
+ ? IDC_DISKPROPORTIONAL
+ : IDC_DISKEQUAL
+ ;
+
+ CheckRadioButton(
+ hdlg,
+ IDC_DISKPROPORTIONAL,
+ IDC_DISKEQUAL,
+ idButton
+ );
+
+ SetFocus(GetDlgItem(hdlg, IDC_DISKPROPORTIONAL));
+
+ return FALSE; // I already set the focus
+ }
+
+ case WM_COMMAND:
+
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ g_DiskDisplayType = IsDlgButtonChecked(hdlg, IDC_DISKPROPORTIONAL)
+ ? DiskProportional
+ : DiskEqual
+ ;
+
+ EndDialog(hdlg, IDOK);
+ break;
+
+ case IDCANCEL:
+ EndDialog(hdlg, IDCANCEL);
+ break;
+
+ case IDHELP:
+ DialogHelp( HC_DM_DLG_DISKDISPLAY );
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ break;
+
+ default:
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DoDiskOptionsDialog
+//
+// Synopsis: Invoke the disk sizing dialog
+//
+// Arguments: [hwndParent] -- the parent window
+//
+// Returns: nothing
+//
+// History: 29-Sep-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DoDiskOptionsDialog(
+ IN HWND hwndParent
+ )
+{
+ switch (
+ DialogBox( g_hInstance,
+ MAKEINTRESOURCE(IDD_DISKOPTIONS),
+ hwndParent,
+ DiskOptionsDlgProc
+ )
+ )
+ {
+ case IDOK:
+ SetCursor(g_hCurWait);
+ TotalRedrawAndRepaint();
+ SetCursor(g_hCurNormal);
+ break;
+
+ case IDCANCEL:
+ break;
+
+ case -1:
+ ErrorDialog(ERROR_NOT_ENOUGH_MEMORY);
+ break;
+
+ default:
+ FDASSERT(0);
+ }
+
+}
diff --git a/private/utils/windisk/src/dlgs.hxx b/private/utils/windisk/src/dlgs.hxx
new file mode 100644
index 000000000..5f3b0e7d3
--- /dev/null
+++ b/private/utils/windisk/src/dlgs.hxx
@@ -0,0 +1,88 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: dlgs.hxx
+//
+// Contents: Declarations for dialog routines
+//
+// History: 7-Jan-92 TedM Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __DLGS_HXX__
+#define __DLGS_HXX__
+
+//////////////////////////////////////////////////////////////////////////////
+
+HBRUSH
+MyCreateHatchBrush(
+ int fnStyle,
+ COLORREF clrref
+ );
+
+VOID
+CenterDialog(
+ IN HWND hwndToCenter,
+ IN HWND hwndContext
+ );
+
+VOID
+CenterDialogInFrame(
+ IN HWND hwnd
+ );
+
+VOID
+SubclassListBox(
+ IN HWND hwnd
+ );
+
+BOOL CALLBACK
+MinMaxDlgProc(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+BOOL CALLBACK
+DriveLetterDlgProc(
+ IN HWND hdlg,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+VOID
+DoColorsDialog(
+ IN HWND hwndParent
+ );
+
+VOID
+DoRegionDisplayDialog(
+ IN HWND hwndParent
+ );
+
+BOOL CALLBACK
+CreateDlgProc(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+VOID
+DoDiskOptionsDialog(
+ IN HWND hwndParent
+ );
+
+INT
+SizeDlgProc(
+ IN HWND hDlg,
+ IN UINT wMsg,
+ IN WPARAM wParam,
+ IN LONG lParam
+ );
+
+#endif // __DLGS_HXX__
diff --git a/private/utils/windisk/src/drives.cxx b/private/utils/windisk/src/drives.cxx
new file mode 100644
index 000000000..8b661b6ed
--- /dev/null
+++ b/private/utils/windisk/src/drives.cxx
@@ -0,0 +1,871 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: drives.cxx
+//
+// Contents: Routines dealing with drive letters
+//
+// History: 7-Jan-92 TedM Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include "cdrom.hxx"
+#include "drives.hxx"
+#include "nt.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+LOCAL WCHAR
+LocateDriveLetterFromDiskAndPartition(
+ IN ULONG DiskNumber,
+ IN ULONG PartitionNumber
+ );
+
+LOCAL WCHAR
+LocateDriveLetterFromRegion(
+ IN PREGION_DESCRIPTOR RegionDescriptor
+ );
+
+//////////////////////////////////////////////////////////////////////////////
+
+#define IsDigitW(digit) (((digit) >= L'0') && ((digit) <= L'9'))
+
+//
+// For each drive letter, these arrays hold the disk and partition number
+// the the drive letter is linked to. These are (well, SHOULD BE) used SOLELY
+// for initialization of the drive letter persistent data. They are determined
+// by scanning the NT object namespace and decoding which drives and
+// partitions a \DosDevices\X: link points to.
+//
+
+#define UNINIT ((unsigned)(-1))
+
+LOCAL unsigned
+DriveLetterDiskNumbers[24] =
+{
+ UNINIT, UNINIT, UNINIT, UNINIT, UNINIT, UNINIT,
+ UNINIT, UNINIT, UNINIT, UNINIT, UNINIT, UNINIT,
+ UNINIT, UNINIT, UNINIT, UNINIT, UNINIT, UNINIT,
+ UNINIT, UNINIT, UNINIT, UNINIT, UNINIT, UNINIT
+};
+
+LOCAL unsigned
+DriveLetterPartitionNumbers[24] =
+{
+ UNINIT, UNINIT, UNINIT, UNINIT, UNINIT, UNINIT,
+ UNINIT, UNINIT, UNINIT, UNINIT, UNINIT, UNINIT,
+ UNINIT, UNINIT, UNINIT, UNINIT, UNINIT, UNINIT,
+ UNINIT, UNINIT, UNINIT, UNINIT, UNINIT, UNINIT
+};
+
+
+//
+// Drive letter usage map. Bit n (0 <= n <= 24) set means that drive
+// letter 'C'+n is in use.
+//
+
+LOCAL ULONG DriveLetterUsageMap = 0;
+
+
+/////////////////////////////////////////////////////////////////////////
+
+//
+// The following macro APIs take a single ASCII character x, where
+// 'C' <= x <= 'Z'
+//
+
+#define DRIVELETTERBIT(DriveLetter) (1 << (unsigned)((UCHAR)(DriveLetter)-(UCHAR)'C'))
+
+//
+// VOID
+// SetDriveLetterUsed(
+// IN WCHAR DriveLetter
+// );
+//
+
+#define SetDriveLetterUsed(DriveLetter) DriveLetterUsageMap |= DRIVELETTERBIT(DriveLetter)
+
+//
+// VOID
+// SetDriveLetterFree(
+// IN WCHAR DriveLetter
+// );
+//
+
+#define SetDriveLetterFree(DriveLetter) DriveLetterUsageMap &= (~DRIVELETTERBIT(DriveLetter))
+
+//
+// BOOL
+// IsDriveLetterUsed(
+// IN WCHAR DriveLetter
+// );
+//
+
+#define IsDriveLetterUsed(DriveLetter) (DriveLetterUsageMap & DRIVELETTERBIT(DriveLetter))
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: GetAvailableDriveLetter
+//
+// Synopsis: Scan the drive letter usage bitmap and return the next
+// available drive letter.
+//
+// Arguments: (none)
+//
+// Returns: The next available drive letter, or 0 if all are used.
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+WCHAR
+GetAvailableDriveLetter(
+ VOID
+ )
+{
+ WCHAR driveLetter;
+
+ FDASSERT(!(DriveLetterUsageMap & 0xff000000));
+
+ for (driveLetter = L'C'; driveLetter <= L'Z'; driveLetter++)
+ {
+ if (!IsDriveLetterUsed(driveLetter))
+ {
+ return driveLetter;
+ }
+ }
+ return 0;
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: MarkDriveLetterUsed
+//
+// Synopsis: Set the state of a drive letter to 'used'
+//
+// Arguments: [DriveLetter] -- The drive letter to change the state of
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+MarkDriveLetterUsed(
+ IN WCHAR DriveLetter
+ )
+{
+ FDASSERT(!(DriveLetterUsageMap & 0xff000000));
+ FDASSERT((DriveLetter >= L'C' && DriveLetter <= L'Z')
+ || (DriveLetter == NO_DRIVE_LETTER_YET)
+ || (DriveLetter == NO_DRIVE_LETTER_EVER));
+
+ if (!IsExtraDriveLetter(DriveLetter))
+ {
+ SetDriveLetterUsed(DriveLetter);
+ }
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: NewDriveLetter
+//
+// Synopsis: Handle a new drive letter: set the drive letter to
+// "used", and set a region & partition # (any one for FT
+// objects)
+//
+// Arguments: [DriveLetter] -- The drive letter to change the state of
+// [DiskNum] -- a disk number of part of the volume
+// [PartNum] -- a partition number of part of the volume
+//
+// Returns: nothing
+//
+// History: 24-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+NewDriveLetter(
+ IN WCHAR DriveLetter,
+ IN ULONG DiskNumber,
+ IN ULONG PartitionNumber
+ )
+{
+ MarkDriveLetterUsed(DriveLetter);
+ DriveLetterDiskNumbers [ DriveLetterToIndex(DriveLetter) ] = DiskNumber;
+ DriveLetterPartitionNumbers[ DriveLetterToIndex(DriveLetter) ] = PartitionNumber;
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: MarkDriveLetterFree
+//
+// Synopsis: Set the state of a drive letter to 'free'
+//
+// Arguments: [DriveLetter] -- The drive letter to change the state of
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+MarkDriveLetterFree(
+ IN WCHAR DriveLetter
+ )
+{
+ FDASSERT(!(DriveLetterUsageMap & 0xff000000));
+ FDASSERT((DriveLetter >= L'C' && DriveLetter <= L'Z')
+ || (DriveLetter == NO_DRIVE_LETTER_YET)
+ || (DriveLetter == NO_DRIVE_LETTER_EVER));
+
+ if (!IsExtraDriveLetter(DriveLetter))
+ {
+ SetDriveLetterFree(DriveLetter);
+ DriveLetterDiskNumbers [ DriveLetterToIndex(DriveLetter) ] = UNINIT;
+ DriveLetterPartitionNumbers[ DriveLetterToIndex(DriveLetter) ] = UNINIT;
+ }
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DriveLetterIsAvailable
+//
+// Synopsis: Determine if a particular drive letter is available for use
+//
+// Arguments: [DriveLetter] -- The drive letter to check
+//
+// Returns: TRUE if the drive letter is available
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+BOOL
+DriveLetterIsAvailable(
+ IN WCHAR DriveLetter
+ )
+{
+ FDASSERT(!(DriveLetterUsageMap & 0xff000000));
+ FDASSERT(DriveLetter >= L'C' && DriveLetter <= L'Z');
+
+ return !IsDriveLetterUsed(DriveLetter);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: AllDriveLettersAreUsed
+//
+// Synopsis: Determine if all possible drive letters are in use
+//
+// Arguments: (none)
+//
+// Returns: TRUE if all possible drive letters are in use
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+BOOL
+AllDriveLettersAreUsed(
+ VOID
+ )
+{
+ FDASSERT(!(DriveLetterUsageMap & 0xff000000));
+
+ return (DriveLetterUsageMap == 0x00ffffff);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: GetDiskNumberFromDriveLetter
+//
+// Synopsis: Find the disk number on which the volume resides that is
+// assigned a particular drive letter
+//
+// Arguments: [DriveLetter] -- The drive letter in question
+//
+// Returns: A 0-based disk number, or -1 if the drive letter is either
+// illegal or not assigned.
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+ULONG
+GetDiskNumberFromDriveLetter(
+ IN WCHAR DriveLetter
+ )
+{
+ FDASSERT((DriveLetter >= L'C' && DriveLetter <= L'Z')
+ || (DriveLetter == NO_DRIVE_LETTER_YET)
+ || (DriveLetter == NO_DRIVE_LETTER_EVER));
+
+ if (!IsExtraDriveLetter(DriveLetter))
+ {
+ return DriveLetterDiskNumbers[ DriveLetterToIndex(DriveLetter) ];
+ }
+ else
+ {
+ return (ULONG)(-1);
+ }
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: GetPartitionNumberFromDriveLetter
+//
+// Synopsis: Find the partition number on a disk on which the volume resides
+// that is assigned a particular drive letter
+//
+// Arguments: [DriveLetter] -- The drive letter in question
+//
+// Returns: A partition number, or -1 if the drive letter is either
+// illegal or not assigned.
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+ULONG
+GetPartitionNumberFromDriveLetter(
+ IN WCHAR DriveLetter
+ )
+{
+ FDASSERT((DriveLetter >= L'C' && DriveLetter <= L'Z')
+ || (DriveLetter == NO_DRIVE_LETTER_YET)
+ || (DriveLetter == NO_DRIVE_LETTER_EVER));
+
+ if (!IsExtraDriveLetter(DriveLetter))
+ {
+ return DriveLetterPartitionNumbers[ DriveLetterToIndex(DriveLetter) ];
+ }
+ else
+ {
+ return (ULONG)(-1);
+ }
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: LocateDriveLetterFromDiskAndPartition
+//
+// Synopsis: Given a disk number and a partition number, return the drive
+// letter associated with that region/volume.
+// NOTE: This code assumes there is no persistent data yet!
+//
+// Arguments: [DiskNum] -- disk number of interest
+// [PartNum] -- partition number of interest
+//
+// Returns: drive letter of region, or NO_DRIVE_LETTER_YET
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+LOCAL WCHAR
+LocateDriveLetterFromDiskAndPartition(
+ IN ULONG DiskNumber,
+ IN ULONG PartitionNumber
+ )
+{
+ unsigned i;
+
+ for (i=0; i<24; i++)
+ {
+ if (DiskNumber == DriveLetterDiskNumbers[i] &&
+ PartitionNumber == DriveLetterPartitionNumbers[i])
+ {
+ return L'C' + (WCHAR)i;
+ }
+ }
+
+ return NO_DRIVE_LETTER_YET;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: LocateDriveLetterFromRegion
+//
+// Synopsis: Given a disk region, return the drive letter associated with it
+// NOTE: This code assumes there is no persistent data yet!
+//
+// Arguments: [RegionDescriptor] -- the region of interest
+//
+// Returns: drive letter of the region, or NO_DRIVE_LETTER_YET
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+LOCAL WCHAR
+LocateDriveLetterFromRegion(
+ IN PREGION_DESCRIPTOR RegionDescriptor
+ )
+{
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(RegionDescriptor);
+
+ if (NULL != regionData)
+ {
+ if (NULL != regionData->FtObject)
+ {
+ if (regionData->DriveLetter)
+ {
+ return regionData->DriveLetter;
+ }
+ }
+ }
+
+ return LocateDriveLetterFromDiskAndPartition(
+ RegionDescriptor->Disk,
+ RegionDescriptor->OriginalPartitionNumber
+ );
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: RegionFromDiskAndPartitionNumbers
+//
+// Synopsis: Given a disk number and a partition number, return the
+// associated region
+//
+// Arguments: [DiskNum] -- disk number of interest
+// [PartNum] -- partition number of interest
+//
+// Returns: a pointer to a region descriptor for the region
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+PREGION_DESCRIPTOR
+RegionFromDiskAndPartitionNumbers(
+ IN ULONG DiskNumber,
+ IN ULONG PartitionNumber
+ )
+{
+ PREGION_DESCRIPTOR regionDescriptor;
+ PDISKSTATE diskState;
+ ULONG regionIndex;
+
+ diskState = DiskArray[DiskNumber];
+
+ for (regionIndex=0; regionIndex<diskState->RegionCount; regionIndex++)
+ {
+ regionDescriptor = &diskState->RegionArray[regionIndex];
+
+ if (DmSignificantRegion(regionDescriptor)
+ && regionDescriptor->PartitionNumber == PartitionNumber)
+ {
+ return regionDescriptor;
+ }
+ }
+
+ return NULL;
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: RegionFromDriveLetter
+//
+// Synopsis: Given a drive letter, return a pointer to a region descriptor
+// of a volume with that drive letter
+//
+// Arguments: [DriveLetter] -- drive letter of interest
+//
+// Returns: a pointer to a region descriptor for the region
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+PREGION_DESCRIPTOR
+RegionFromDriveLetter(
+ IN WCHAR DriveLetter
+ )
+{
+ FDASSERT((DriveLetter >= L'C' && DriveLetter <= L'Z')
+ || (DriveLetter == NO_DRIVE_LETTER_YET)
+ || (DriveLetter == NO_DRIVE_LETTER_EVER));
+
+ if (!DriveLetterIsAvailable(DriveLetter))
+ {
+ ULONG DiskNum = DriveLetterDiskNumbers[ DriveLetterToIndex(DriveLetter) ];
+ ULONG PartNum = DriveLetterPartitionNumbers[ DriveLetterToIndex(DriveLetter) ];
+
+ if (-1 != DiskNum && -1 != PartNum)
+ {
+ return RegionFromDiskAndPartitionNumbers(DiskNum, PartNum);
+ }
+ }
+
+ return NULL;
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: SignificantDriveLetter
+//
+// Synopsis: Determine if a drive letter is sigificant. A drive letter is
+// significant if is is used, and is associated with a
+// local volume. It can't be a network volume or a floppy
+// drive.
+//
+// Arguments: [DriveLetter] -- the drive letter in question
+//
+// Returns: TRUE if the drive letter is significant
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+BOOL
+SignificantDriveLetter(
+ IN WCHAR DriveLetter
+ )
+{
+ FDASSERT((DriveLetter >= L'C' && DriveLetter <= L'Z')
+ || (DriveLetter == NO_DRIVE_LETTER_YET)
+ || (DriveLetter == NO_DRIVE_LETTER_EVER));
+
+ if (!IsExtraDriveLetter(DriveLetter) && IsDriveLetterUsed(DriveLetter))
+ {
+ PREGION_DESCRIPTOR regionDescriptor = RegionFromDriveLetter(DriveLetter);
+ if (NULL != regionDescriptor)
+ {
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(regionDescriptor);
+
+ return NULL != regionData
+ && !regionData->NewRegion
+ && DmSignificantRegion(regionDescriptor);
+ }
+ }
+
+ return FALSE;
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: GetInfoFromDriveLetter
+//
+// Synopsis: From a drive letter, find a pointer to a disk state
+// representing a volume assigned that drive letter.
+//
+// Arguments: [DriveLetter] -- the drive letter in question
+// [DiskStateOut] -- set to the disk state of the disk with a
+// volume with the argument drive letter
+// [RegionIndexOut] -- set to the region index of the region of
+// interest on the disk
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+GetInfoFromDriveLetter(
+ IN WCHAR DriveLetter,
+ OUT PDISKSTATE* DiskStateOut,
+ OUT int* RegionIndexOut
+ )
+{
+ DWORD diskNumber;
+ DWORD regionIndex;
+
+ for (diskNumber = 0; diskNumber < DiskCount; diskNumber++)
+ {
+ PDISKSTATE diskState = DiskArray[diskNumber];
+
+ for (regionIndex = 0; regionIndex < diskState->RegionCount; regionIndex ++)
+ {
+ PREGION_DESCRIPTOR regionDescriptor = &diskState->RegionArray[regionIndex];
+
+ if (DmSignificantRegion(regionDescriptor))
+ {
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(regionDescriptor);
+
+ if (regionData->DriveLetter == DriveLetter)
+ {
+ *DiskStateOut = diskState;
+ *RegionIndexOut = regionIndex;
+ return;
+ }
+ }
+ }
+ }
+
+ daDebugOut((DEB_ITRACE,
+ "Couldn't find disk state structure with drive letter %wc\n",
+ DriveLetter));
+
+ *DiskStateOut = NULL;
+ *RegionIndexOut = 0;
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: InitializeDriveLetterInfo
+//
+// Synopsis: Initialize all information about drive letters by reading
+// through the NT object namespace and parsing out used drive
+// letters. Assigns drive letters to all volumes.
+//
+// Arguments: (none)
+//
+// Returns: TRUE on success
+//
+// Modifies: all drive letter state information
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+BOOL
+InitializeDriveLetterInfo(
+ VOID
+ )
+{
+ WCHAR driveLetter;
+ PWSTR linkTarget;
+ WCHAR dosDevicesName[ARRAYLEN(L"\\DosDevices\\A:")];
+ unsigned diskNumber;
+ int partitionNumber;
+ PWSTR pattern;
+ PWSTR string;
+ DWORD x;
+ DWORD ec;
+
+ //
+ // For each drive letter c-z, query the symbolic link.
+ //
+
+ for (driveLetter = L'C'; driveLetter <= L'Z'; driveLetter++)
+ {
+ wsprintf(dosDevicesName, L"\\DosDevices\\%c:", driveLetter);
+
+ if ((ec = GetDriveLetterLinkTarget(dosDevicesName, &linkTarget)) == NO_ERROR)
+ {
+ //
+ // The drive letter is used because it is linked to something,
+ // even if we can't figure out what. So mark it used here.
+ //
+
+ SetDriveLetterUsed(driveLetter);
+
+ CharUpper(linkTarget);
+
+ pattern = L"\\DEVICE\\HARDDISK";
+ string = linkTarget;
+
+ //
+ // Attempt to match the '\device\harddisk' part
+ //
+
+ for (x=0; x < (sizeof(L"\\DEVICE\\HARDDISK") / sizeof(WCHAR)) - 1; x++)
+ {
+ if (*pattern++ != *string++)
+ {
+ goto next_letter;
+ }
+ }
+
+ //
+ // Now get the hard disk #
+ //
+
+ if (!IsDigitW(*string))
+ {
+ goto next_letter;
+ }
+
+ diskNumber = 0;
+ while (IsDigitW(*string))
+ {
+ diskNumber = (diskNumber * 10) + (*string - L'0');
+ *string++;
+ }
+
+ //
+ // Attempt to match the '\partition' part
+ //
+
+ pattern = L"\\PARTITION";
+ for (x=0; x < (sizeof(L"\\PARTITION") / sizeof(WCHAR)) - 1; x++)
+ {
+ if (*pattern++ != *string++)
+ {
+ goto next_letter;
+ }
+ }
+
+ //
+ // Now get the partition #, which cannot be 0
+ //
+
+ partitionNumber = 0;
+ while (IsDigitW(*string))
+ {
+ partitionNumber = (partitionNumber * 10) + (*string - L'0');
+ *string++;
+ }
+
+ if (0 == partitionNumber)
+ {
+ goto next_letter;
+ }
+
+ //
+ // Make sure there is nothing left in the link target's name
+ //
+
+ if (*string)
+ {
+ goto next_letter;
+ }
+
+ //
+ // We understand the link target. Store the disk and partition.
+ //
+
+ DriveLetterDiskNumbers[driveLetter - L'C'] = diskNumber;
+ DriveLetterPartitionNumbers[driveLetter - L'C'] = partitionNumber;
+ }
+ else
+ {
+ if (ec == ERROR_ACCESS_DENIED)
+ {
+ ErrorDialog(MSG_ACCESS_DENIED);
+ return FALSE;
+ }
+ }
+next_letter: {}
+ }
+
+
+ //
+ // Now for each non-ft, significant region on each disk, figure out its
+ // drive letter.
+ //
+
+ PFT_OBJECT ftObject;
+ PFT_OBJECT_SET ftSet;
+ PREGION_DESCRIPTOR regionDescriptor;
+ PDISKSTATE diskState;
+ UINT regionIndex;
+
+ for (diskNumber = 0; diskNumber < DiskCount; diskNumber++)
+ {
+ diskState = DiskArray[diskNumber];
+
+ for (regionIndex=0; regionIndex<diskState->RegionCount; regionIndex++)
+ {
+ regionDescriptor = &diskState->RegionArray[regionIndex];
+
+ if (DmSignificantRegion(regionDescriptor))
+ {
+ //
+ // Handle drive letters for FT sets specially.
+ //
+
+ if (NULL == GET_FT_OBJECT(regionDescriptor))
+ {
+ PERSISTENT_DATA(regionDescriptor)->DriveLetter =
+ LocateDriveLetterFromRegion(regionDescriptor);
+ }
+ }
+ }
+
+ // If this is a removable disk, record the reserved drive
+ // letter for that disk.
+ //
+ if (IsDiskRemovable[diskNumber])
+ {
+ RemovableDiskReservedDriveLetters[diskNumber] =
+ LocateDriveLetterFromDiskAndPartition(diskNumber, 1);
+ }
+ else
+ {
+ RemovableDiskReservedDriveLetters[diskNumber] = NO_DRIVE_LETTER_YET;
+ }
+ }
+
+ //
+ // Now handle ft sets. For each set, loop through the objects twice.
+ // On the first pass, figure out which object actually is linked to the
+ // drive letter. On the second pass, assign the drive letter found to
+ // each of the objects in the set.
+ //
+
+ for (ftSet = FtObjectList; NULL != ftSet; ftSet = ftSet->Next)
+ {
+ for (ftObject = ftSet->Members; NULL != ftObject; ftObject = ftObject->Next)
+ {
+ regionDescriptor = ftObject->Region;
+
+ if (regionDescriptor)
+ {
+ if ((driveLetter = LocateDriveLetterFromRegion(regionDescriptor))
+ != NO_DRIVE_LETTER_YET)
+ {
+ break;
+ }
+ }
+ }
+
+ for (ftObject = ftSet->Members; NULL != ftObject; ftObject = ftObject->Next)
+ {
+ regionDescriptor = ftObject->Region;
+
+ if (regionDescriptor)
+ {
+ PERSISTENT_DATA(regionDescriptor)->DriveLetter = driveLetter;
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+
+#undef UNINIT
diff --git a/private/utils/windisk/src/drives.hxx b/private/utils/windisk/src/drives.hxx
new file mode 100644
index 000000000..e5a893994
--- /dev/null
+++ b/private/utils/windisk/src/drives.hxx
@@ -0,0 +1,88 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: drives.hxx
+//
+// Contents: Routines dealing with drive letters
+//
+// History: 24-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __DRIVES_HXX__
+#define __DRIVES_HXX__
+
+WCHAR
+GetAvailableDriveLetter(
+ VOID
+ );
+
+VOID
+MarkDriveLetterUsed(
+ IN WCHAR DriveLetter
+ );
+
+VOID
+NewDriveLetter(
+ IN WCHAR DriveLetter,
+ IN ULONG DiskNum,
+ IN ULONG PartNum
+ );
+
+VOID
+MarkDriveLetterFree(
+ IN WCHAR DriveLetter
+ );
+
+BOOL
+DriveLetterIsAvailable(
+ IN WCHAR DriveLetter
+ );
+
+BOOL
+AllDriveLettersAreUsed(
+ VOID
+ );
+
+ULONG
+GetDiskNumberFromDriveLetter(
+ IN WCHAR DriveLetter
+ );
+
+ULONG
+GetPartitionNumberFromDriveLetter(
+ IN WCHAR DriveLetter
+ );
+
+PREGION_DESCRIPTOR
+RegionFromDiskAndPartitionNumbers(
+ IN ULONG DiskNum,
+ IN ULONG PartNum
+ );
+
+PREGION_DESCRIPTOR
+RegionFromDriveLetter(
+ IN WCHAR DriveLetter
+ );
+
+BOOL
+SignificantDriveLetter(
+ IN WCHAR DriveLetter
+ );
+
+VOID
+GetInfoFromDriveLetter(
+ IN WCHAR DriveLetter,
+ OUT PDISKSTATE* DiskState,
+ OUT int* RegionIndex
+ );
+
+BOOL
+InitializeDriveLetterInfo(
+ VOID
+ );
+
+
+#endif // __DRIVES_HXX__
diff --git a/private/utils/windisk/src/dskmgr.ico b/private/utils/windisk/src/dskmgr.ico
new file mode 100644
index 000000000..f0fa6bfe5
--- /dev/null
+++ b/private/utils/windisk/src/dskmgr.ico
Binary files differ
diff --git a/private/utils/windisk/src/engine.cxx b/private/utils/windisk/src/engine.cxx
new file mode 100644
index 000000000..4262b2b3e
--- /dev/null
+++ b/private/utils/windisk/src/engine.cxx
@@ -0,0 +1,4086 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1991 - 1994.
+//
+// File: engine.cxx
+//
+// Contents: The disk partitioning engine, formerly in the arcinst project.
+//
+// History:
+//
+// Ted Miller (tedm) Nov-1991
+//
+// Bob Rinne (bobri) Feb-1994
+// Moved as actual part of Disk Administrator enlistment instead of being
+// copied from ArcInst. This is due to dynamic partition changes. Removed
+// string table that made this an internationalized file.
+//
+//--------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "engine.hxx"
+#include "ntlow.hxx"
+#include "nt.hxx"
+
+////////////////////////////////////////////////////////////////////////////
+
+#define ENTRIES_PER_BOOTSECTOR 4
+
+////////////////////////////////////////////////////////////////////////////
+
+// Attached disk devices.
+
+ULONG CountOfDisks;
+PCHAR* DiskNames;
+
+// Information about attached disks.
+
+DISKGEOM* DiskGeometryArray;
+
+PPARTITION* PrimaryPartitions;
+PPARTITION* LogicalVolumes;
+
+//
+// A 'signature' is a unique 4-byte value immediately preceeding the
+// partition table in the MBR.
+//
+
+PULONG Signatures;
+
+//
+// Array keeping track of whether each disk is off line.
+//
+PBOOLEAN OffLine;
+
+// Keeps track of whether changes have been requested
+// to each disk's partition structure.
+
+PBOOLEAN ChangesRequested;
+PBOOLEAN ChangesCommitted;
+
+
+//
+// Value used to indicate that the partition entry has changed but in a non-
+// destructive way (ie, made active/inactive).
+//
+#define CHANGED_DONT_ZAP ((BOOLEAN)(5))
+
+////////////////////////////////////////////////////////////////////////////
+
+
+STATUS_CODE
+OpenDisks(
+ VOID
+ );
+
+VOID
+CloseDisks(
+ VOID
+ );
+
+STATUS_CODE
+GetGeometry(
+ VOID
+ );
+
+BOOLEAN
+CheckIfDiskIsOffLine(
+ IN ULONG Disk
+ );
+
+STATUS_CODE
+InitializePartitionLists(
+ VOID
+ );
+
+STATUS_CODE
+GetRegions(
+ IN ULONG Disk,
+ IN PPARTITION p,
+ IN BOOLEAN WantUsedRegions,
+ IN BOOLEAN WantFreeRegions,
+ IN BOOLEAN WantLogicalRegions,
+ OUT PREGION_DESCRIPTOR* Region,
+ OUT PULONG RegionCount,
+ IN REGION_TYPE RegionType
+ );
+
+BOOLEAN
+AddRegionEntry(
+ IN OUT PREGION_DESCRIPTOR* Regions,
+ IN OUT PULONG RegionCount,
+ IN ULONG SizeMB,
+ IN REGION_TYPE RegionType,
+ IN PPARTITION Partition,
+ IN LARGE_INTEGER AlignedRegionOffset,
+ IN LARGE_INTEGER AlignedRegionSize
+ );
+
+VOID
+AddPartitionToLinkedList(
+ IN PARTITION** Head,
+ IN PARTITION* p
+ );
+
+BOOLEAN
+IsInLinkedList(
+ IN PPARTITION p,
+ IN PPARTITION List
+ );
+
+BOOLEAN
+IsInLogicalList(
+ IN ULONG Disk,
+ IN PPARTITION p
+ );
+
+BOOLEAN
+IsInPartitionList(
+ IN ULONG Disk,
+ IN PPARTITION p
+ );
+
+LARGE_INTEGER
+AlignTowardsDiskStart(
+ IN ULONG Disk,
+ IN LARGE_INTEGER Offset
+ );
+
+LARGE_INTEGER
+AlignTowardsDiskEnd(
+ IN ULONG Disk,
+ IN LARGE_INTEGER Offset
+ );
+
+VOID
+FreeLinkedPartitionList(
+ IN PARTITION** q
+ );
+
+VOID
+MergeFreePartitions(
+ IN PPARTITION p
+ );
+
+VOID
+FreePartitionInfoLinkedLists(
+ IN PARTITION** ListHeadArray
+ );
+
+LARGE_INTEGER
+DiskLengthBytes(
+ IN ULONG Disk
+ );
+
+PPARTITION
+AllocatePartitionStructure(
+ IN ULONG Disk,
+ IN LARGE_INTEGER Offset,
+ IN LARGE_INTEGER Length,
+ IN PPARTITION_INFORMATION OriginalPartitionInformation,
+ IN ULONG LayoutSlot,
+ IN UCHAR SysID,
+ IN BOOLEAN Update,
+ IN BOOLEAN Active,
+ IN BOOLEAN Recognized
+ );
+
+////////////////////////////////////////////////////////////////////////////
+
+
+STATUS_CODE
+FdiskInitialize(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the partitioning engine, including allocating
+ arrays, determining attached disk devices, and reading their
+ partition tables.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+ STATUS_CODE status;
+ ULONG i;
+
+ if ((status = LowQueryFdiskPathList(&DiskNames, &CountOfDisks)) != OK_STATUS)
+ {
+ return status;
+ }
+
+ DiskGeometryArray = NULL;
+ PrimaryPartitions = NULL;
+ LogicalVolumes = NULL;
+
+ if (((DiskGeometryArray = (PDISKGEOM) AllocateMemory(CountOfDisks * sizeof(DISKGEOM ))) == NULL)
+ || ((ChangesRequested = (PBOOLEAN) AllocateMemory(CountOfDisks * sizeof(BOOLEAN ))) == NULL)
+ || ((ChangesCommitted = (PBOOLEAN) AllocateMemory(CountOfDisks * sizeof(BOOLEAN ))) == NULL)
+ || ((PrimaryPartitions = (PPARTITION*) AllocateMemory(CountOfDisks * sizeof(PPARTITION))) == NULL)
+ || ((Signatures = (PULONG) AllocateMemory(CountOfDisks * sizeof(ULONG ))) == NULL)
+ || ((OffLine = (PBOOLEAN) AllocateMemory(CountOfDisks * sizeof(BOOLEAN ))) == NULL)
+ || ((LogicalVolumes = (PPARTITION*) AllocateMemory(CountOfDisks * sizeof(PPARTITION))) == NULL))
+ {
+ RETURN_OUT_OF_MEMORY;
+ }
+
+ for (i=0; i<CountOfDisks; i++)
+ {
+ PrimaryPartitions[i] = NULL;
+ LogicalVolumes[i] = NULL;
+ ChangesRequested[i] = FALSE;
+ ChangesCommitted[i] = FALSE;
+ OffLine[i] = CheckIfDiskIsOffLine(i);
+ }
+
+ if ( ((status = GetGeometry() ) != OK_STATUS)
+ || ((status = InitializePartitionLists()) != OK_STATUS))
+ {
+ return status;
+ }
+
+ return OK_STATUS;
+}
+
+
+VOID
+FdiskCleanUp(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deallocates storage used by the partitioning engine.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LowFreeFdiskPathList(DiskNames, CountOfDisks);
+
+ if (DiskGeometryArray != NULL)
+ {
+ FreeMemory(DiskGeometryArray);
+ }
+ if (PrimaryPartitions != NULL)
+ {
+ FreePartitionInfoLinkedLists(PrimaryPartitions);
+ FreeMemory(PrimaryPartitions);
+ }
+ if (LogicalVolumes != NULL)
+ {
+ FreePartitionInfoLinkedLists(LogicalVolumes);
+ FreeMemory(LogicalVolumes);
+ }
+ if (ChangesRequested != NULL)
+ {
+ FreeMemory(ChangesRequested);
+ }
+ if (ChangesCommitted != NULL)
+ {
+ FreeMemory(ChangesCommitted);
+ }
+ if (OffLine != NULL)
+ {
+ FreeMemory(OffLine);
+ }
+ if (Signatures != NULL)
+ {
+ FreeMemory(Signatures);
+ }
+}
+
+
+BOOLEAN
+CheckIfDiskIsOffLine(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ Determine whether a disk is off-line by attempting to open it.
+ If this is diskman, also attempt to read from it.
+
+Arguments:
+
+ Disk - supplies number of the disk to check
+
+Return Value:
+
+ TRUE if disk is off-line, FALSE is disk is on-line.
+
+--*/
+
+{
+ HANDLE_T handle;
+ UINT errorMode;
+ BOOLEAN isOffLine = TRUE;
+
+ errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+ if (LowOpenDisk(GetDiskName(Disk), &handle) == OK_STATUS)
+ {
+ ULONG dummy;
+ ULONG bps;
+ PVOID unalignedBuffer;
+ PVOID buffer;
+
+ isOffLine = TRUE;
+
+ //
+ // The open might succeed even if the disk is off line. So to be
+ // sure, read the first sector from the disk.
+ //
+
+ if (NT_SUCCESS(LowGetDriveGeometry(GetDiskName(Disk), &dummy, &bps, &dummy, &dummy)))
+ {
+ unalignedBuffer = Malloc(2*bps);
+ buffer = (PVOID)(((ULONG)unalignedBuffer+bps) & ~(bps-1));
+
+ if (NT_SUCCESS(LowReadSectors(handle, bps, 0, 1, buffer)))
+ {
+ isOffLine = FALSE;
+ }
+
+ Free(unalignedBuffer);
+ }
+ else
+ {
+ // It is possible this is a removable drive.
+
+ if (IsRemovable(Disk))
+ {
+ isOffLine = FALSE;
+ }
+ }
+
+ LowCloseDisk(handle);
+ }
+ SetErrorMode(errorMode);
+
+ return isOffLine;
+}
+
+
+STATUS_CODE
+GetGeometry(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines disk geometry for each disk device.
+ Disk geometry includes heads, sectors per track, cylinder count,
+ and bytes per sector. It also includes bytes per track and
+ bytes per cylinder, which are calculated from the other values
+ for the convenience of the rest of this module.
+
+ Geometry information is placed in the DiskGeometryArray global variable.
+
+ Geometry information is undefined for an off-line disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+ ULONG i;
+ STATUS_CODE status;
+ ULONG totalSectorCount,
+ sectorSize,
+ sectorsPerTrack,
+ heads;
+
+ for (i=0; i<CountOfDisks; i++)
+ {
+ if (OffLine[i])
+ {
+ continue;
+ }
+
+ status = LowGetDriveGeometry(
+ DiskNames[i],
+ &totalSectorCount,
+ &sectorSize,
+ &sectorsPerTrack,
+ &heads);
+
+ if (status != OK_STATUS)
+ {
+
+ if (IsRemovable(i)) {
+
+ //
+ // Assume that the media has been removed. Null out the
+ // sizes.
+ //
+ status = OK_STATUS;
+ sectorSize = 0;
+ sectorsPerTrack = 0;
+ heads = 0;
+ totalSectorCount = 0;
+
+ } else {
+ return status;
+ }
+ }
+
+ DiskGeometryArray[i].BytesPerSector = sectorSize;
+ DiskGeometryArray[i].SectorsPerTrack = sectorsPerTrack;
+ DiskGeometryArray[i].Heads = heads;
+ if (sectorsPerTrack && heads) {
+ DiskGeometryArray[i].Cylinders.QuadPart = totalSectorCount / (sectorsPerTrack * heads);
+ } else {
+ DiskGeometryArray[i].Cylinders.QuadPart = 0;
+ }
+ DiskGeometryArray[i].BytesPerTrack = sectorsPerTrack * sectorSize;
+ DiskGeometryArray[i].BytesPerCylinder = sectorsPerTrack * sectorSize * heads;
+ }
+ return OK_STATUS;
+}
+
+
+VOID
+SetPartitionActiveFlag(
+ IN PREGION_DESCRIPTOR Region,
+ IN UCHAR value
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PPARTITION p = ((PREGION_DATA)Region->Reserved)->Partition;
+
+ if ((UCHAR)p->Active != value)
+ {
+ //
+ // Unfortuneately, the Update flag becomes the RewritePartition flag
+ // at commit time. This causes us to zap the boot sector. To avoid
+ // this, we use a spacial non-boolean value that can be checked for
+ // at commit time and that will cause us NOT to zap the bootsector
+ // even though RewritePartition will be TRUE.
+ //
+
+ p->Active = value;
+ if (!p->Update)
+ {
+ p->Update = CHANGED_DONT_ZAP;
+ }
+ ChangesRequested[p->Disk] = TRUE;
+ }
+}
+
+
+VOID
+DetermineCreateSizeAndOffset(
+ IN PREGION_DESCRIPTOR Region,
+ IN LARGE_INTEGER MinimumSize,
+ IN ULONG CreationSizeMB,
+ IN REGION_TYPE Type,
+ OUT PLARGE_INTEGER CreationStart,
+ OUT PLARGE_INTEGER CreationSize
+ )
+
+/*++
+
+Routine Description:
+
+ Determine the actual offset and size of the partition, given the
+ size in megabytes.
+
+Arguments:
+
+ Region - a region descriptor returned by GetDiskRegions(). Must
+ be an unused region.
+
+ MinimumSize - if non-0, this is the minimum size that the partition
+ or logical drive can be.
+
+ CreationSizeMB - If MinimumSize is 0, size of partition to create, in MB.
+
+ Type - REGION_PRIMARY, REGION_EXTENDED, or REGION_LOGICAL, for
+ creating a primary partition, extended partition, or
+ logical volume, respectively.
+
+ CreationStart - receives the offset where the partition should be placed.
+
+ CreationSize - receives the exact size for the partition.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PREGION_DATA createData = Region->Reserved;
+ LARGE_INTEGER cSize;
+ LARGE_INTEGER cStart;
+ LARGE_INTEGER mod;
+ ULONG bpc = DiskGeometryArray[Region->Disk].BytesPerCylinder;
+ ULONG bpt = DiskGeometryArray[Region->Disk].BytesPerTrack;
+
+ FDASSERT(Region->SysID == PARTITION_ENTRY_UNUSED);
+
+ //
+ // If we are creating a partition at offset 0, adjust the aligned region
+ // offset and the aligned region size, because no partition can actually
+ // start at offset 0.
+ //
+
+ if (0 == createData->AlignedRegionOffset.QuadPart)
+ {
+ LARGE_INTEGER delta;
+
+ if (Type == REGION_EXTENDED)
+ {
+ delta.QuadPart = bpc;
+ }
+ else
+ {
+ delta.QuadPart = bpt;
+ }
+
+ createData->AlignedRegionOffset = delta;
+ createData->AlignedRegionSize.QuadPart -= delta.QuadPart;
+ }
+
+ cStart = createData->AlignedRegionOffset;
+ if (0 == MinimumSize.QuadPart)
+ {
+ cSize.QuadPart = UInt32x32To64(CreationSizeMB, ONE_MEG);
+ }
+ else
+ {
+ cSize = MinimumSize;
+ if (Type == REGION_LOGICAL)
+ {
+ cSize.QuadPart += bpt;
+ }
+ }
+
+ //
+ // Decide whether to align the ending cylinder up or down.
+ // If the offset of end of the partition is more than half way into the
+ // final cylinder, align towrds the disk end. Otherwise align toward
+ // the disk start.
+ //
+
+ mod.QuadPart = (cStart.QuadPart + cSize.QuadPart) % bpc;
+
+ if (0 != mod.QuadPart)
+ {
+ if ( (0 != MinimumSize.QuadPart) || (mod.QuadPart > (bpc / 2)) )
+ {
+ cSize.QuadPart += ((LONGLONG)bpc - mod.QuadPart);
+ }
+ else
+ {
+ cSize.QuadPart -= mod.QuadPart; // snap downwards tp cyl boundary
+ }
+ }
+
+ if (cSize.QuadPart > createData->AlignedRegionSize.QuadPart)
+ {
+ //
+ // Space available in the free space isn't large enough to accomodate
+ // the request; just use the entire free space.
+ //
+
+ cSize = createData->AlignedRegionSize;
+ }
+
+ *CreationStart = cStart;
+ *CreationSize = cSize;
+}
+
+
+STATUS_CODE
+CreatePartitionEx(
+ IN PREGION_DESCRIPTOR Region,
+ IN LARGE_INTEGER MinimumSize,
+ IN ULONG CreationSizeMB,
+ IN REGION_TYPE Type,
+ IN UCHAR SysId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a partition from a free region on the disk. The
+ partition is always created at the beginning of the free space, and any
+ left over space at the end is kept on the free space list.
+
+Arguments:
+
+ Region - a region descriptor returned by GetDiskRegions(). Must
+ be an unused region.
+
+ CreationSizeMB - size of partition to create, in MB.
+
+ Type - REGION_PRIMARY, REGION_EXTENDED, or REGION_LOGICAL, for
+ creating a primary partition, extended partition, or
+ logical volume, respectively.
+
+ SysId - system ID byte to be assigned to the partition
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+ PPARTITION p1;
+ PPARTITION p2;
+ PPARTITION p3;
+ PREGION_DATA createData = Region->Reserved;
+ LARGE_INTEGER creationStart;
+ LARGE_INTEGER creationSize;
+ LARGE_INTEGER leftOver;
+ LARGE_INTEGER offset;
+ LARGE_INTEGER length;
+ PPARTITION* partitionList;
+ PARTITION_INFORMATION t = {0};
+
+ DetermineCreateSizeAndOffset(Region,
+ MinimumSize,
+ CreationSizeMB,
+ Type,
+ &creationStart,
+ &creationSize);
+
+ // now we've got the start and size of the partition to be created.
+ // If there's left-over at the beginning of the free space (after
+ // alignment), make a new PARTITION structure.
+
+ p1 = NULL;
+ offset = createData->Partition->Offset;
+ length = createData->Partition->Length;
+ leftOver.QuadPart = creationStart.QuadPart - offset.QuadPart;
+
+ if (leftOver.QuadPart > 0)
+ {
+ p1 = AllocatePartitionStructure(Region->Disk,
+ createData->Partition->Offset,
+ leftOver,
+ NULL,
+ 0,
+ PARTITION_ENTRY_UNUSED,
+ FALSE,
+ FALSE,
+ FALSE);
+ if (p1 == NULL)
+ {
+ RETURN_OUT_OF_MEMORY;
+ }
+ }
+
+ // make a new partition structure for space being left free as
+ // a result of this creation.
+
+ p2 = NULL;
+ leftOver.QuadPart = (offset.QuadPart + length.QuadPart)
+ - (creationStart.QuadPart + creationSize.QuadPart);
+
+
+ if (0 != leftOver.QuadPart)
+ {
+ LARGE_INTEGER temp;
+
+ temp.QuadPart = creationStart.QuadPart + creationSize.QuadPart;
+ p2 = AllocatePartitionStructure(Region->Disk,
+ temp,
+ leftOver,
+ NULL,
+ 0,
+ PARTITION_ENTRY_UNUSED,
+ FALSE,
+ FALSE,
+ FALSE);
+ if (p2 == NULL)
+ {
+ RETURN_OUT_OF_MEMORY;
+ }
+ }
+
+ // adjust the free partition's fields.
+
+ createData->Partition->Offset = creationStart;
+ createData->Partition->Length = creationSize;
+ createData->Partition->SysID = SysId;
+ createData->Partition->Update = TRUE;
+ createData->Partition->Recognized = TRUE;
+ createData->Partition->EntryCameFromLayout = FALSE;
+ createData->Partition->OriginalLayoutEntrySlot = 0;
+ createData->Partition->OriginalPartitionInformation = t;
+
+ // if we just created an extended partition, show the whole thing
+ // as one free logical region.
+
+ if (Type == REGION_EXTENDED)
+ {
+
+ FDASSERT(LogicalVolumes[Region->Disk] == NULL);
+
+ p3 = AllocatePartitionStructure(Region->Disk,
+ creationStart,
+ creationSize,
+ NULL,
+ 0,
+ PARTITION_ENTRY_UNUSED,
+ FALSE,
+ FALSE,
+ FALSE);
+ if (p3 == NULL)
+ {
+ RETURN_OUT_OF_MEMORY;
+ }
+ AddPartitionToLinkedList(&LogicalVolumes[Region->Disk], p3);
+ }
+
+ partitionList = (Type == REGION_LOGICAL)
+ ? &LogicalVolumes[Region->Disk]
+ : &PrimaryPartitions[Region->Disk];
+
+ if (NULL != p1)
+ {
+ AddPartitionToLinkedList(partitionList, p1);
+ }
+ if (NULL != p2)
+ {
+ AddPartitionToLinkedList(partitionList, p2);
+ }
+
+ MergeFreePartitions(*partitionList);
+ ChangesRequested[Region->Disk] = TRUE;
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+CreatePartition(
+ IN PREGION_DESCRIPTOR Region,
+ IN ULONG CreationSizeMB,
+ IN REGION_TYPE Type
+ )
+/*++
+
+Routine Description:
+
+ Create a partition.
+
+Arguments:
+
+ Region - A region descriptor pointer.
+ CreationSizeMB - the size for the new region.
+ Type - the type of region being created.
+
+Return Value:
+
+ OK_STATUS or error code
+
+--*/
+
+{
+ LARGE_INTEGER zero;
+
+ zero.QuadPart = 0;
+ return CreatePartitionEx(Region,
+ zero,
+ CreationSizeMB,
+ Type,
+ (UCHAR)((Type == REGION_EXTENDED) ? PARTITION_EXTENDED
+ : PARTITION_HUGE));
+}
+
+
+
+STATUS_CODE
+DeletePartition(
+ IN PREGION_DESCRIPTOR Region
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deletes a partition, returning its space to the
+ free space on the disk. If deleting the extended partition,
+ all logical volumes within it are also deleted.
+
+Arguments:
+
+ Region - a region descriptor returned by GetDiskRegions(). Must
+ be a used region.
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+ PREGION_DATA regionData = Region->Reserved;
+ PPARTITION* partitionList;
+ PARTITION_INFORMATION t = {0};
+
+
+ FDASSERT( IsInPartitionList(Region->Disk, regionData->Partition)
+ || IsInLogicalList (Region->Disk, regionData->Partition));
+
+ if (IsExtended(Region->SysID))
+ {
+ FDASSERT(IsInPartitionList(Region->Disk, regionData->Partition));
+
+ // Deleting extended partition. Also delete all logical volumes.
+
+ FreeLinkedPartitionList(&LogicalVolumes[Region->Disk]);
+ }
+
+ regionData->Partition->SysID = PARTITION_ENTRY_UNUSED;
+ regionData->Partition->Update = TRUE;
+ regionData->Partition->Active = FALSE;
+ regionData->Partition->OriginalPartitionNumber = 0;
+ regionData->Partition->EntryCameFromLayout = FALSE;
+ regionData->Partition->OriginalLayoutEntrySlot = 0;
+ regionData->Partition->OriginalPartitionInformation = t;
+
+ partitionList = (Region->RegionType == REGION_LOGICAL)
+ ? &LogicalVolumes[Region->Disk]
+ : &PrimaryPartitions[Region->Disk];
+
+ MergeFreePartitions(*partitionList);
+ ChangesRequested[Region->Disk] = TRUE;
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+GetDiskRegions(
+ IN ULONG Disk,
+ IN BOOLEAN WantUsedRegions,
+ IN BOOLEAN WantFreeRegions,
+ IN BOOLEAN WantPrimaryRegions,
+ IN BOOLEAN WantLogicalRegions,
+ OUT PREGION_DESCRIPTOR* Region,
+ OUT PULONG RegionCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns an array of region descriptors to the caller.
+ A region desscriptor describes a space on the disk, either used
+ or free. The caller can control which type of regions are returned.
+
+ The caller must free the returned array via FreeRegionArray().
+
+Arguments:
+
+ Disk - index of disk whose regions are to be returned
+
+ WantUsedRegions - whether to return used disk regions
+
+ WantFreeRegions - whether to return free disk regions
+
+ WantPrimaryRegions - whether to return regions not in the
+ extended partition
+
+ WantLogicalRegions - whether to return regions within the
+ extended partition
+
+ Region - where to put a pointer to the array of regions
+
+ RegionCount - where to put the number of items in the returned
+ Region array
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+
+ STATUS_CODE status = OK_STATUS;
+ *Region = (PREGION_DESCRIPTOR)AllocateMemory(0);
+ *RegionCount = 0;
+
+ if (WantPrimaryRegions)
+ {
+ status = GetRegions(Disk,
+ PrimaryPartitions[Disk],
+ WantUsedRegions,
+ WantFreeRegions,
+ WantLogicalRegions,
+ Region,
+ RegionCount,
+ REGION_PRIMARY);
+
+ if ((status != OK_STATUS) || (*RegionCount == 0)) {
+
+ FreeMemory(*Region);
+ *Region = NULL;
+
+ }
+ }
+ else if (WantLogicalRegions)
+ {
+ status = GetRegions(Disk,
+ LogicalVolumes[Disk],
+ WantUsedRegions,
+ WantFreeRegions,
+ FALSE,
+ Region,
+ RegionCount,
+ REGION_LOGICAL);
+
+ if ((status != OK_STATUS) || (*RegionCount == 0)) {
+
+ FreeMemory(*Region);
+ *Region = NULL;
+
+ }
+ }
+ return status;
+}
+
+
+// workers for GetDiskRegions
+
+STATUS_CODE
+GetRegions(
+ IN ULONG Disk,
+ IN PPARTITION p,
+ IN BOOLEAN WantUsedRegions,
+ IN BOOLEAN WantFreeRegions,
+ IN BOOLEAN WantLogicalRegions,
+ OUT PREGION_DESCRIPTOR* Region,
+ OUT PULONG RegionCount,
+ IN REGION_TYPE RegionType
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ STATUS_CODE status;
+ LARGE_INTEGER alignedOffset;
+ LARGE_INTEGER alignedSize;
+ LARGE_INTEGER temp;
+ ULONG sizeMB;
+
+ while (p)
+ {
+ if (p->SysID == PARTITION_ENTRY_UNUSED)
+ {
+ if (WantFreeRegions)
+ {
+ alignedOffset = AlignTowardsDiskEnd(p->Disk, p->Offset);
+ temp.QuadPart = p->Offset.QuadPart + p->Length.QuadPart;
+ temp = AlignTowardsDiskStart(p->Disk, temp);
+ alignedSize.QuadPart = temp.QuadPart - alignedOffset.QuadPart;
+ sizeMB = SIZEMB(alignedSize);
+
+ // Show the space free if it is greater than 1 meg, AND
+ // it is not a space starting at the beginning of the disk
+ // and of length <= 1 cylinder.
+ // This prevents the user from seeing the first cylinder
+ // of the disk as free (could otherwise happen with an
+ // extended partition starting on cylinder 1 and cylinders
+ // of 1 megabyte or larger).
+
+ if ( (alignedSize.QuadPart > 0)
+ && (0 != sizeMB)
+ && ( (0 != p->Offset.QuadPart)
+ || (p->Length.QuadPart >
+ DiskGeometryArray[p->Disk].BytesPerCylinder)))
+ {
+ if (!AddRegionEntry(Region,
+ RegionCount,
+ sizeMB,
+ RegionType,
+ p,
+ alignedOffset,
+ alignedSize))
+ {
+ RETURN_OUT_OF_MEMORY;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (WantUsedRegions)
+ {
+ alignedOffset = p->Offset;
+ alignedSize = p->Length;
+ sizeMB = SIZEMB(alignedSize);
+
+ if (!AddRegionEntry(Region,
+ RegionCount,
+ sizeMB,
+ RegionType,
+ p,
+ alignedOffset,
+ alignedSize))
+ {
+ RETURN_OUT_OF_MEMORY;
+ }
+ }
+
+ if (IsExtended(p->SysID) && WantLogicalRegions)
+ {
+ status = GetRegions(Disk,
+ LogicalVolumes[Disk],
+ WantUsedRegions,
+ WantFreeRegions,
+ FALSE,
+ Region,
+ RegionCount,
+ REGION_LOGICAL);
+ if (status != OK_STATUS)
+ {
+ return status;
+ }
+ }
+ }
+ p = p->Next;
+ }
+ return OK_STATUS;
+}
+
+
+BOOLEAN
+AddRegionEntry(
+ OUT PREGION_DESCRIPTOR* Regions,
+ OUT PULONG RegionCount,
+ IN ULONG SizeMB,
+ IN REGION_TYPE RegionType,
+ IN PPARTITION Partition,
+ IN LARGE_INTEGER AlignedRegionOffset,
+ IN LARGE_INTEGER AlignedRegionSize
+ )
+
+/*++
+
+Routine Description:
+
+ Allocate space for the region descriptor and copy the provided data.
+
+Arguments:
+
+ Regions - return the pointer to the new region
+ RegionCount - number of regions on the disk so far
+ SizeMB - size of the region
+ RegionType - type of the region
+ Partition - partition structure with other related information
+ AlignedRegionOffset - region starting location
+ AlignedRegionSize - region size.
+
+Return Value:
+
+ TRUE - The region was added successfully
+ FALSE - it wasn't
+
+--*/
+
+{
+ PREGION_DESCRIPTOR regionDescriptor;
+ PREGION_DATA data;
+
+ //BUGBUG: what is 20?
+ regionDescriptor = (PREGION_DESCRIPTOR)ReallocateMemory(*Regions, (((*RegionCount) + 1) * sizeof(REGION_DESCRIPTOR)) + 20);
+ if (regionDescriptor == NULL)
+ {
+ return FALSE;
+ }
+ else
+ {
+ *Regions = regionDescriptor;
+ (*RegionCount)++;
+ }
+
+ regionDescriptor = &(*Regions)[(*RegionCount)-1];
+
+ if (!(regionDescriptor->Reserved = (PREGION_DATA)AllocateMemory(sizeof(REGION_DATA))))
+ {
+ return FALSE;
+ }
+
+ regionDescriptor->Disk = Partition->Disk;
+ regionDescriptor->SysID = Partition->SysID;
+ regionDescriptor->SizeMB = SizeMB;
+ regionDescriptor->Active = Partition->Active;
+ regionDescriptor->Recognized = Partition->Recognized;
+ regionDescriptor->PartitionNumber = Partition->PartitionNumber;
+ regionDescriptor->OriginalPartitionNumber = Partition->OriginalPartitionNumber;
+ regionDescriptor->RegionType = RegionType;
+ regionDescriptor->PersistentData = Partition->PersistentData;
+
+ data = regionDescriptor->Reserved;
+
+ data->Partition = Partition;
+ data->AlignedRegionOffset = AlignedRegionOffset;
+ data->AlignedRegionSize = AlignedRegionSize;
+
+ return TRUE;
+}
+
+
+VOID
+FreeRegionArray(
+ IN PREGION_DESCRIPTOR Region,
+ IN ULONG RegionCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees a region array returned by GetDiskRegions().
+
+Arguments:
+
+ Region - pointer to the array of regions to be freed
+
+ RegionCount - number of items in the Region array
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG i;
+
+ for (i=0; i<RegionCount; i++)
+ {
+ if (Region[i].Reserved)
+ {
+ FreeMemory(Region[i].Reserved);
+ }
+ }
+ FreeMemory(Region);
+}
+
+
+
+VOID
+AddPartitionToLinkedList(
+ IN OUT PARTITION** Head,
+ IN PARTITION* p
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds a PARTITION structure to a doubly-linked
+ list, sorted by the Offset field in ascending order.
+
+Arguments:
+
+ Head - pointer to pointer to first element in list
+
+ p - pointer to item to be added to list
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PARTITION *cur, *prev;
+
+ if ((cur = *Head) == NULL)
+ {
+ *Head = p;
+ return;
+ }
+
+ if (p->Offset.QuadPart < cur->Offset.QuadPart)
+ {
+ p->Next = cur;
+ cur->Prev = p;
+ *Head = p;
+ return;
+ }
+
+ prev = *Head;
+ cur = cur->Next;
+
+ while (cur)
+ {
+ if (p->Offset.QuadPart < cur->Offset.QuadPart)
+ {
+ p->Next = cur;
+ p->Prev = prev;
+ prev->Next = p;
+ cur->Prev = p;
+ return;
+ }
+ prev = cur;
+ cur = cur->Next;
+ }
+
+ prev->Next = p;
+ p->Prev = prev;
+ return;
+}
+
+
+BOOLEAN
+IsInLinkedList(
+ IN PPARTITION p,
+ IN PPARTITION List
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether a PARTITION element is in
+ a given linked list of PARTITION elements.
+
+Arguments:
+
+ p - pointer to element to be checked for
+
+ List - first element in list to be scanned
+
+Return Value:
+
+ true if p found in List, false otherwise
+
+--*/
+
+{
+ while (List)
+ {
+ if (p == List)
+ {
+ return TRUE;
+ }
+ List = List->Next;
+ }
+ return FALSE;
+}
+
+
+BOOLEAN
+IsInLogicalList(
+ IN ULONG Disk,
+ IN PPARTITION p
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether a PARTITION element is in
+ the logical volume list for a given disk.
+
+Arguments:
+
+ Disk - index of disk to be checked
+
+ p - pointer to element to be checked for
+
+Return Value:
+
+ true if p found in Disk's logical volume list, false otherwise
+
+--*/
+
+{
+ return IsInLinkedList(p, LogicalVolumes[Disk]);
+}
+
+
+BOOLEAN
+IsInPartitionList(
+ IN ULONG Disk,
+ IN PPARTITION p
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether a PARTITION element is in
+ the primary partition list for a given disk.
+
+Arguments:
+
+ Disk - index of disk to be checked
+
+ p - pointer to element to be checked for
+
+Return Value:
+
+ true if p found in Disk's primary partition list, false otherwise
+
+--*/
+
+{
+ return IsInLinkedList(p, PrimaryPartitions[Disk]);
+}
+
+
+VOID
+MergeFreePartitions(
+ IN PPARTITION p
+ )
+
+/*++
+
+Routine Description:
+
+ This routine merges adjacent free space elements in the
+ given linked list of PARTITION elements. It is designed
+ to be called after adding or deleting a partition.
+
+Arguments:
+
+ p - pointer to first item in list whose free elements are to
+ be merged.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PPARTITION next;
+
+ while (p && p->Next)
+ {
+ if ((p->SysID == PARTITION_ENTRY_UNUSED) && (p->Next->SysID == PARTITION_ENTRY_UNUSED))
+ {
+ next = p->Next;
+
+ p->Length.QuadPart = (next->Offset.QuadPart + next->Length.QuadPart) - p->Offset.QuadPart;
+
+ if (NULL != (p->Next = next->Next))
+ {
+ next->Next->Prev = p;
+ }
+
+ FreeMemory(next);
+ }
+ else
+ {
+ p = p->Next;
+ }
+ }
+}
+
+
+PPARTITION
+FindPartitionElement(
+ IN ULONG Disk,
+ IN ULONG Partition
+ )
+
+/*++
+
+Routine Description:
+
+ This routine locates a PARTITION element for a disk/partition
+ number pair. The partition number is the number that the
+ system assigns to the partition.
+
+Arguments:
+
+ Disk - index of relevent disk
+
+ Partition - partition number of partition to find
+
+Return Value:
+
+ pointer to PARTITION element, or NULL if not found.
+
+--*/
+
+{
+ PPARTITION p;
+
+ FDASSERT(Partition);
+
+ p = PrimaryPartitions[Disk];
+ while (NULL != p)
+ {
+ if ( (p->SysID != PARTITION_ENTRY_UNUSED)
+ && !IsExtended(p->SysID)
+ && (p->PartitionNumber == Partition))
+ {
+ return p;
+ }
+ p = p->Next;
+ }
+ p = LogicalVolumes[Disk];
+ while (NULL != p)
+ {
+ if ( (p->SysID != PARTITION_ENTRY_UNUSED)
+ && (p->PartitionNumber == Partition))
+ {
+ return p;
+ }
+ p = p->Next;
+ }
+ return NULL;
+}
+
+
+VOID
+SetSysID(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ IN UCHAR SysID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the system id of the given partition
+ on the given disk.
+
+Arguments:
+
+ Disk - index of relevent disk
+
+ Partition - partition number of relevent partition
+
+ SysID - new system ID for Partition on Disk
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PPARTITION p = FindPartitionElement(Disk, Partition);
+
+ FDASSERT(p);
+
+ if (NULL != p)
+ {
+ p->SysID = SysID;
+ if (!p->Update)
+ {
+ p->Update = CHANGED_DONT_ZAP;
+ }
+ ChangesRequested[p->Disk] = TRUE;
+ }
+}
+
+
+VOID
+SetSysID2(
+ IN PREGION_DESCRIPTOR Region,
+ IN UCHAR SysID
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PPARTITION p = ((PREGION_DATA)(Region->Reserved))->Partition;
+
+ p->SysID = SysID;
+ if (!p->Update)
+ {
+ p->Update = CHANGED_DONT_ZAP;
+ }
+ ChangesRequested[p->Disk] = TRUE;
+}
+
+
+
+VOID
+FreeLinkedPartitionList(
+ IN OUT PPARTITION *q
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees a linked list of PARTITION elements. The head
+ pointer is set to NULL.
+
+Arguments:
+
+ p - pointer to pointer to first element of list to free.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PARTITION *n;
+ PARTITION *p = *q;
+
+ while (p)
+ {
+ n = p->Next;
+ FreeMemory(p);
+ p = n;
+ }
+ *q = NULL;
+}
+
+
+VOID
+FreePartitionInfoLinkedLists(
+ IN PPARTITION* ListHeadArray
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees the linked lists of PARTITION elements
+ for each disk.
+
+Arguments:
+
+ ListHeadArray - pointer to array of pointers to first elements of
+ PARTITION element lists.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG i;
+
+ for (i=0; i<CountOfDisks; i++)
+ {
+ FreeLinkedPartitionList(&ListHeadArray[i]);
+ }
+}
+
+
+PPARTITION
+AllocatePartitionStructure(
+ IN ULONG Disk,
+ IN LARGE_INTEGER Offset,
+ IN LARGE_INTEGER Length,
+ IN PPARTITION_INFORMATION OriginalPartitionInformation,
+ IN ULONG LayoutSlot,
+ IN UCHAR SysID,
+ IN BOOLEAN Update,
+ IN BOOLEAN Active,
+ IN BOOLEAN Recognized
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates space for, and initializes a PARTITION
+ structure.
+
+Arguments:
+
+ Disk - index of disk, one of whose regions the new PARTITION
+ strucure describes.
+
+ Offset - byte offset of region on the disk
+
+ Length - length in bytes of the region
+
+ OriginalPartitionInfromation - If the partition spec came from a drive layout
+ structure retrieved from the disk, save off these values. We will
+ use them to make sure we don't recalculate any values.
+
+ LayoutSlot - The original slot entry that this originalPartitionInformation
+ came from. We use this so that when recreating the disklayout structure
+ we can determine whether the partition info is moved.
+
+ SysID - system id of region, of PARTITION_ENTRY_UNUSED of this PARTITION
+ is actually a free space.
+
+ Update - whether this PARTITION is dirty, ie, has changed and needs
+ to be written to disk.
+
+ Active - flag for the BootIndicator field in a partition table entry,
+ indicates to the x86 master boot program which partition
+ is active.
+
+ Recognized - whether the partition is a type recognized by NT
+
+Return Value:
+
+ NULL if allocation failed, or new initialized PARTITION strucure.
+
+--*/
+
+{
+ PPARTITION p = (PPARTITION)AllocateMemory(sizeof(PARTITION));
+ PARTITION_INFORMATION t = {0};
+
+ if (NULL != p)
+ {
+ p->Next = NULL;
+ p->Prev = NULL;
+ p->Offset = Offset;
+ p->Length = Length;
+ p->Disk = Disk;
+ p->Update = Update;
+ p->Active = Active;
+ p->Recognized = Recognized;
+ p->SysID = SysID;
+ p->OriginalPartitionNumber = 0;
+ p->PartitionNumber = 0;
+ p->PersistentData = 0;
+ p->CommitMirrorBreakNeeded = FALSE;
+ if (OriginalPartitionInformation) {
+ p->OriginalPartitionInformation = *OriginalPartitionInformation;
+ p->OriginalLayoutEntrySlot = LayoutSlot;
+ p->EntryCameFromLayout = TRUE;
+ } else {
+ p->OriginalPartitionInformation = t;
+ p->OriginalLayoutEntrySlot = 0;
+ p->EntryCameFromLayout = FALSE;
+ }
+ }
+ return p;
+}
+
+
+STATUS_CODE
+InitializeFreeSpace(
+ IN ULONG Disk,
+ IN PPARTITION* PartitionList, // list the free space goes in
+ IN LARGE_INTEGER StartOffset,
+ IN LARGE_INTEGER Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines all the free spaces within a given area
+ on a disk, allocates PARTITION structures to describe them,
+ and adds these structures to the relevent partition list
+ (primary partitions or logical volumes).
+
+ No rounding or alignment is performed here. Spaces of even one
+ byte will be counted and inserted in the partition list.
+
+Arguments:
+
+ Disk - index of disk whose free spaces are being sought.
+
+ PartitionList - pointer to first element on PARTITION list that
+ the free spaces will go in.
+
+ StartOffset - start offset of area on disk to consider (ie, 0 for
+ primary spaces or the first byte of the extended
+ partition for logical spaces).
+
+ Length - length of area on disk to consider (ie, size of disk
+ for primary spaces or size of extended partition for
+ logical spaces).
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+ PPARTITION p = *PartitionList,
+ q;
+ LARGE_INTEGER start,
+ size;
+
+ start = StartOffset;
+
+ while (p)
+ {
+ size.QuadPart = p->Offset.QuadPart - start.QuadPart;
+
+ if (size.QuadPart > 0)
+ {
+ if (!(q = AllocatePartitionStructure(Disk,
+ start,
+ size,
+ NULL,
+ 0,
+ PARTITION_ENTRY_UNUSED,
+ FALSE,
+ FALSE,
+ FALSE)))
+ {
+ RETURN_OUT_OF_MEMORY;
+ }
+
+ AddPartitionToLinkedList(PartitionList, q);
+ }
+
+ start.QuadPart = p->Offset.QuadPart + p->Length.QuadPart;
+ p = p->Next;
+ }
+
+ size.QuadPart = (StartOffset.QuadPart + Length.QuadPart) - start.QuadPart;
+
+ if (size.QuadPart > 0)
+ {
+ if (!(q = AllocatePartitionStructure(Disk,
+ start,
+ size,
+ NULL,
+ 0,
+ PARTITION_ENTRY_UNUSED,
+ FALSE,
+ FALSE,
+ FALSE)))
+ {
+ RETURN_OUT_OF_MEMORY;
+ }
+
+ AddPartitionToLinkedList(PartitionList, q);
+ }
+
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+InitializeLogicalVolumeList(
+ IN ULONG Disk,
+ IN PDRIVE_LAYOUT_INFORMATION DriveLayout
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates the logical volume linked list of
+ PARTITION structures for the given disk.
+
+Arguments:
+
+ Disk - index of disk
+
+ DriveLayout - pointer to structure describing the raw partition
+ layout of the disk.
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+ PPARTITION p,
+ q;
+ ULONG i,
+ j;
+ PPARTITION_INFORMATION d;
+ LARGE_INTEGER hiddenBytes;
+ ULONG bytesPerSector = DiskGeometryArray[Disk].BytesPerSector;
+
+ FreeLinkedPartitionList(&LogicalVolumes[Disk]);
+
+ p = PrimaryPartitions[Disk];
+ while (p)
+ {
+ if (IsExtended(p->SysID))
+ {
+ break;
+ }
+ p = p->Next;
+ }
+
+ if (p)
+ {
+ for (i=ENTRIES_PER_BOOTSECTOR; i<DriveLayout->PartitionCount; i+=ENTRIES_PER_BOOTSECTOR)
+ {
+ for (j=i; j<i+ENTRIES_PER_BOOTSECTOR; j++)
+ {
+ d = &DriveLayout->PartitionEntry[j];
+
+ if ((d->PartitionType != PARTITION_ENTRY_UNUSED) && !IsContainerPartition(d->PartitionType))
+ {
+ LARGE_INTEGER t1, t2;
+
+ hiddenBytes.QuadPart = (LONGLONG)d->HiddenSectors * (LONGLONG)bytesPerSector;
+
+ t1.QuadPart = d->StartingOffset.QuadPart - hiddenBytes.QuadPart;
+ t2.QuadPart = d->PartitionLength.QuadPart + hiddenBytes.QuadPart;
+ if (!(q = AllocatePartitionStructure(
+ Disk,
+ t1,
+ t2,
+ d,
+ j,
+ d->PartitionType,
+ FALSE,
+ d->BootIndicator,
+ d->RecognizedPartition)))
+ {
+ RETURN_OUT_OF_MEMORY;
+ }
+
+ q->PartitionNumber
+ = q->OriginalPartitionNumber
+ = d->PartitionNumber;
+ AddPartitionToLinkedList(&LogicalVolumes[Disk], q);
+
+ break;
+ }
+ }
+ }
+ return InitializeFreeSpace(Disk,
+ &LogicalVolumes[Disk],
+ p->Offset,
+ p->Length);
+ }
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+InitializePrimaryPartitionList(
+ IN ULONG Disk,
+ IN PDRIVE_LAYOUT_INFORMATION DriveLayout
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates the primary partition linked list of
+ PARTITION structures for the given disk.
+
+Arguments:
+
+ Disk - index of disk
+
+ DriveLayout - pointer to structure describing the raw partition
+ layout of the disk.
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+ ULONG i;
+ PPARTITION p;
+ PPARTITION_INFORMATION d;
+ LARGE_INTEGER zero;
+
+ zero.QuadPart = 0;
+
+ FreeLinkedPartitionList(&PrimaryPartitions[Disk]);
+
+ for (i=0; i<DriveLayout->PartitionCount && i<ENTRIES_PER_BOOTSECTOR; i++)
+ {
+ d = &DriveLayout->PartitionEntry[i];
+
+ if (d->PartitionType != PARTITION_ENTRY_UNUSED)
+ {
+ if (!(p = AllocatePartitionStructure(
+ Disk,
+ d->StartingOffset,
+ d->PartitionLength,
+ d,
+ i,
+ d->PartitionType,
+ FALSE,
+ d->BootIndicator,
+ d->RecognizedPartition)))
+ {
+ RETURN_OUT_OF_MEMORY;
+ }
+
+ p->PartitionNumber
+ = p->OriginalPartitionNumber
+ = (IsExtended(p->SysID) ? 0 : d->PartitionNumber);
+
+ AddPartitionToLinkedList(&PrimaryPartitions[Disk], p);
+ }
+ }
+ return InitializeFreeSpace(Disk,
+ &PrimaryPartitions[Disk],
+ zero,
+ DiskLengthBytes(Disk));
+}
+
+VOID
+ReconcilePartitionNumbers(
+ ULONG Disk,
+ PDRIVE_LAYOUT_INFORMATION DriveLayout
+ )
+
+/*++
+
+Routine Description:
+
+ With dynamic partitioning, the partitions on the disk will no longer
+ follow sequencial numbering schemes. It will be possible for a disk
+ to have a partition #1 that is the last partition on the disk and a
+ partition #3 that is the first. This routine runs through the NT
+ namespace for harddisks to resolve this inconsistency.
+
+ This routine has the problem that it will not locate partitions that
+ are part of an FT set because the partition information for these
+ partitions will be modified to reflect the size of the set, not the
+ size of the partition.
+
+Arguments:
+
+ Disk - the disk number
+ DriveLayout - the partitioning information
+
+Return Value:
+
+ None
+
+--*/
+
+{
+#define BUFFERSIZE 1024
+
+ NTSTATUS status;
+ IO_STATUS_BLOCK statusBlock;
+ HANDLE directoryHandle,
+ partitionHandle;
+ CLONG continueProcessing;
+ ULONG context = 0,
+ returnedLength,
+ index;
+ POBJECT_DIRECTORY_INFORMATION dirInfo;
+ PARTITION_INFORMATION partitionInfo;
+ PPARTITION_INFORMATION partitionInfoPtr;
+ OBJECT_ATTRIBUTES attributes;
+ UNICODE_STRING unicodeString;
+ ANSI_STRING ansiName;
+ PUCHAR deviceName;
+ PUCHAR buffer;
+
+ deviceName = (PUCHAR)Malloc(100);
+ if (!deviceName)
+ {
+ return;
+ }
+
+ buffer = (PUCHAR)Malloc(BUFFERSIZE);
+ if (!buffer)
+ {
+ Free(deviceName);
+ return;
+ }
+
+ sprintf((PCHAR)deviceName, "\\Device\\Harddisk%d", Disk);
+ RtlInitAnsiString(&ansiName, (PCHAR)deviceName);
+ status = RtlAnsiStringToUnicodeString(&unicodeString, &ansiName, TRUE);
+
+ if (!NT_SUCCESS(status))
+ {
+ Free(deviceName);
+ Free(buffer);
+ return;
+ }
+ InitializeObjectAttributes(&attributes,
+ &unicodeString,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+ status = NtOpenDirectoryObject(&directoryHandle,
+ DIRECTORY_QUERY,
+ &attributes);
+ if (!NT_SUCCESS(status))
+ {
+ Free(deviceName);
+ Free(buffer);
+ return;
+ }
+
+ // Query the entire directory in one sweep
+
+ continueProcessing = 1;
+ while (continueProcessing)
+ {
+ RtlZeroMemory(buffer, BUFFERSIZE);
+ status = NtQueryDirectoryObject(directoryHandle,
+ buffer,
+ BUFFERSIZE,
+ FALSE,
+ FALSE,
+ &context,
+ &returnedLength);
+
+ // Check the status of the operation.
+
+ if (!NT_SUCCESS(status))
+ {
+ if (status != STATUS_NO_MORE_FILES)
+ {
+ break;
+ }
+ continueProcessing = 0;
+ }
+
+ // For every record in the buffer check for partition name
+
+
+ for (dirInfo = (POBJECT_DIRECTORY_INFORMATION) buffer;
+ TRUE;
+ dirInfo = (POBJECT_DIRECTORY_INFORMATION) (((PUCHAR) dirInfo) +
+ sizeof(OBJECT_DIRECTORY_INFORMATION)))
+ {
+ // Check if there is another record. If there isn't, then get out
+ // of the loop now
+
+ if (dirInfo->Name.Length == 0)
+ {
+ break;
+ }
+
+ // compare the name to see if it is a Partition
+
+ if (0 == _wcsnicmp(dirInfo->Name.Buffer, L"Partition", 9))
+ {
+ UCHAR digits[3];
+ ULONG partitionNumber;
+
+ // Located a partition. This restricts the # of partitions
+ // to 99.
+
+ digits[0] = (UCHAR)dirInfo->Name.Buffer[9];
+ digits[1] = (UCHAR)dirInfo->Name.Buffer[10];
+ digits[2] = 0;
+ partitionNumber = atoi((PCHAR)digits);
+
+ if (partitionNumber <= 0)
+ {
+ // less than zero is really an error...
+ // partition zero is always the same.
+
+ continue;
+ }
+
+ // Have a numbered partition -- match it to the drive layout
+
+ status = LowOpenPartition((PCHAR)deviceName, partitionNumber, &partitionHandle);
+ if (!NT_SUCCESS(status))
+ {
+ // If it cannot be opened perhaps it isn't really a partition
+ continue;
+ }
+
+ status = NtDeviceIoControlFile(partitionHandle,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ IOCTL_DISK_GET_PARTITION_INFO,
+ NULL,
+ 0,
+ &partitionInfo,
+ sizeof(PARTITION_INFORMATION));
+
+ if (!NT_SUCCESS(status))
+ {
+ LowCloseDisk(partitionHandle);
+ continue;
+ }
+
+ // match partition information with drive layout.
+
+ for (index = 0; index < DriveLayout->PartitionCount; index++)
+ {
+ partitionInfoPtr = &DriveLayout->PartitionEntry[index];
+ if ((partitionInfoPtr->StartingOffset.QuadPart == partitionInfo.StartingOffset.QuadPart) &&
+ (partitionInfoPtr->PartitionLength.QuadPart == partitionInfo.PartitionLength.QuadPart))
+ {
+ // This is a match.
+
+ partitionInfoPtr->PartitionNumber = partitionNumber;
+ break;
+ }
+ }
+ LowCloseDisk(partitionHandle);
+ }
+ }
+ }
+
+ // Now close the directory object
+
+ Free(deviceName);
+ Free(buffer);
+ (VOID) NtClose(directoryHandle);
+ return;
+}
+
+
+VOID
+CheckForOldDrivers(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines if an old release 3.1 drive is in the
+ system. If so, it calculates the partition number for each region
+ on a disk. For a used region, the partition number is the number
+ that the system will assign to the partition. All partitions
+ (except the extended partition) are numbered first starting at 1,
+ and then all logical volumes in the extended partition.
+ For a free region, the partition number is the number that the
+ system WOULD assign to the partition if the space were to be
+ converted to a partition and all other regions on the disk were
+ left as is.
+
+ The partition numbers are stored in the PARTITION elements.
+
+Arguments:
+
+ Disk - index of disk whose partitions are to be renumbered.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PPARTITION p = PrimaryPartitions[Disk];
+ ULONG n = 1;
+
+ while (NULL != p)
+ {
+ if (p->SysID != PARTITION_ENTRY_UNUSED)
+ {
+ if ((!IsExtended(p->SysID)) && (IsRecognizedPartition(p->SysID)))
+ {
+ // If there is already a partition number, nothing need be
+ // done here.
+
+ if (p->PartitionNumber)
+ {
+ return;
+ }
+ else
+ {
+ RestartRequired = TRUE;
+ }
+ p->PartitionNumber = n;
+ if (p->SysID != PARTITION_ENTRY_UNUSED)
+ {
+ n++;
+ }
+ }
+ }
+ p = p->Next;
+ }
+
+ p = LogicalVolumes[Disk];
+ while (NULL != p)
+ {
+ if (p->SysID != PARTITION_ENTRY_UNUSED)
+ {
+ if (p->PartitionNumber)
+ {
+ return;
+ }
+ else
+ {
+ RestartRequired = TRUE;
+ }
+ p->PartitionNumber = n;
+ n++;
+ }
+ p = p->Next;
+ }
+}
+
+
+
+STATUS_CODE
+InitializePartitionLists(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scans the PARTITION_INFO array returned for each disk
+ by the OS. A linked list of PARTITION structures is layered on top
+ of each array; the net result is a sorted list that covers an entire
+ disk, because free spaces are also factored in as 'dummy' partitions.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+ STATUS_CODE status;
+ ULONG disk;
+ PDRIVE_LAYOUT_INFORMATION driveLayout;
+
+ for (disk = 0; disk < CountOfDisks; disk++)
+ {
+ if (OffLine[disk])
+ {
+ continue;
+ }
+
+ if ((status = LowGetDiskLayout(DiskNames[disk], &driveLayout)) != OK_STATUS)
+ {
+
+ if (IsRemovable(disk)) {
+
+ status = OK_STATUS;
+ continue;
+
+ }
+ return status;
+ }
+
+ // ReconcilePartitionNumbers(disk, driveLayout);
+
+ status = InitializePrimaryPartitionList(disk, driveLayout);
+ if (status == OK_STATUS)
+ {
+ status = InitializeLogicalVolumeList(disk, driveLayout);
+ }
+
+ if (status != OK_STATUS)
+ {
+ FreeMemory(driveLayout);
+ return status;
+ }
+
+ Signatures[disk] = driveLayout->Signature;
+ FreeMemory(driveLayout);
+ CheckForOldDrivers(disk);
+ }
+ return OK_STATUS;
+}
+
+
+
+LARGE_INTEGER
+DiskLengthBytes(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines the disk length in bytes. This value
+ is calculated from the disk geometry information.
+
+Arguments:
+
+ Disk - index of disk whose size is desired
+
+Return Value:
+
+ Size of Disk.
+
+--*/
+
+{
+ LARGE_INTEGER result;
+
+ result.QuadPart = DiskGeometryArray[Disk].Cylinders.QuadPart *
+ DiskGeometryArray[Disk].BytesPerCylinder;
+ return result;
+}
+
+
+ULONG
+SIZEMB(
+ IN LARGE_INTEGER ByteCount
+ )
+
+/*++
+
+Routine Description:
+
+ Calculate the size in megabytes of a given byte count. The value is
+ properly rounded (ie, not merely truncated).
+
+ This function replaces a macro of the same name that was truncating
+ instead of rounding.
+
+Arguments:
+
+ ByteCount - supplies number of bytes
+
+Return Value:
+
+ Size in MB equivalent to ByteCount.
+
+--*/
+
+{
+ ULONG Remainder;
+ ULONG SizeMB;
+
+ SizeMB = RtlExtendedLargeIntegerDivide(ByteCount,
+ ONE_MEG,
+ &Remainder).LowPart;
+
+ if (Remainder >= ONE_MEG/2)
+ {
+ SizeMB++;
+ }
+
+ return SizeMB;
+}
+
+ULONG
+DiskSizeMB(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines the disk length in megabytes. The returned
+ value is rounded down after division by 1024*1024.
+
+Arguments:
+
+ Disk - index of disk whose size is desired
+
+Return Value:
+
+ Size of Disk.
+
+--*/
+
+{
+ return SIZEMB(DiskLengthBytes(Disk));
+}
+
+
+LARGE_INTEGER
+AlignTowardsDiskStart(
+ IN ULONG Disk,
+ IN LARGE_INTEGER Offset
+ )
+
+/*++
+
+Routine Description:
+
+ This routine snaps a byte offset to a cylinder boundary, towards
+ the start of the disk.
+
+Arguments:
+
+ Disk - index of disk whose offset is to be snapped
+
+ Offset - byte offset to be aligned (snapped to cylinder boundary)
+
+Return Value:
+
+ Aligned offset.
+
+--*/
+
+{
+ LARGE_INTEGER mod, result;
+
+ mod.QuadPart = Offset.QuadPart % DiskGeometryArray[Disk].BytesPerCylinder;
+ result.QuadPart = Offset.QuadPart - mod.QuadPart;
+
+ return result;
+}
+
+
+LARGE_INTEGER
+AlignTowardsDiskEnd(
+ IN ULONG Disk,
+ IN LARGE_INTEGER Offset
+ )
+
+/*++
+
+Routine Description:
+
+ This routine snaps a byte offset to a cylinder boundary, towards
+ the end of the disk.
+
+Arguments:
+
+ Disk - index of disk whose offset is to be snapped
+
+ Offset - byte offset to be aligned (snapped to cylinder boundary)
+
+Return Value:
+
+ Aligned offset.
+
+--*/
+
+{
+ LARGE_INTEGER mod, temp;
+
+ mod.QuadPart = Offset.QuadPart % DiskGeometryArray[Disk].BytesPerCylinder;
+
+ if (0 != mod.QuadPart)
+ {
+ temp.QuadPart = Offset.QuadPart + DiskGeometryArray[Disk].BytesPerCylinder;
+ Offset = AlignTowardsDiskStart(Disk, temp);
+ }
+ return Offset;
+}
+
+
+BOOLEAN
+IsExtended(
+ IN UCHAR SysID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether a given system id is for an
+ extended type (ie, link) entry.
+
+Arguments:
+
+ SysID - system id to be tested.
+
+Return Value:
+
+ true/false based on whether SysID is for an extended type.
+
+--*/
+
+{
+ return (BOOLEAN)(IsContainerPartition(SysID));
+}
+
+
+STATUS_CODE
+IsAnyCreationAllowed(
+ IN ULONG Disk,
+ IN BOOLEAN AllowMultiplePrimaries,
+ OUT PBOOLEAN AnyAllowed,
+ OUT PBOOLEAN PrimaryAllowed,
+ OUT PBOOLEAN ExtendedAllowed,
+ OUT PBOOLEAN LogicalAllowed
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether any partition may be created on a
+ given disk, based on three sub-queries -- whether creation is allowed
+ of a primary partition, an extended partition, or a logical volume.
+
+Arguments:
+
+ Disk - index of disk to check
+
+ AllowMultiplePrimaries - whether to allow multiple primary partitions
+
+ AnyAllowed - returns whether any creation is allowed
+
+ PrimaryAllowed - returns whether creation of a primary partition
+ is allowed
+
+ ExtendedAllowed - returns whether creation of an extended partition
+ is allowed
+
+ Logical Allowed - returns whether creation of a logical volume is allowed.
+
+Return Value:
+
+ OK_STATUS or error code
+
+--*/
+
+{
+ STATUS_CODE status;
+
+ if ((status = IsCreationOfPrimaryAllowed(Disk, AllowMultiplePrimaries, PrimaryAllowed)) != OK_STATUS)
+ {
+ return status;
+ }
+ if ((status = IsCreationOfExtendedAllowed(Disk, ExtendedAllowed)) != OK_STATUS)
+ {
+ return status;
+ }
+ if ((status = IsCreationOfLogicalAllowed(Disk, LogicalAllowed)) != OK_STATUS)
+ {
+ return status;
+ }
+ *AnyAllowed = (BOOLEAN)(*PrimaryAllowed || *ExtendedAllowed || *LogicalAllowed);
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+IsCreationOfPrimaryAllowed(
+ IN ULONG Disk,
+ IN BOOLEAN AllowMultiplePrimaries,
+ OUT PBOOLEAN Allowed
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether creation of a primary partition is
+ allowed. This is true when there is a free entry in the MBR and
+ there is free primary space on the disk. If multiple primaries
+ are not allowed, then there must also not exist any primary partitions
+ in order for a primary creation to be allowed.
+
+Arguments:
+
+ Disk - index of disk to check
+
+ AllowMultiplePrimaries - whether existnace of primary partition
+ disallows creation of a primary partition
+
+ Allowed - returns whether creation of a primary partition
+ is allowed
+
+Return Value:
+
+ OK_STATUS or error code
+
+--*/
+
+{
+ PREGION_DESCRIPTOR regionArray;
+ ULONG regionCount;
+ ULONG usedCount;
+ ULONG recogCount;
+ ULONG i;
+ STATUS_CODE status;
+ BOOLEAN freeSpace = FALSE;
+
+ status = GetPrimaryDiskRegions(Disk, &regionArray, &regionCount);
+ if (status != OK_STATUS)
+ {
+ return status;
+ }
+
+ for (usedCount = recogCount = i = 0; i<regionCount; i++)
+ {
+ FDASSERT(regionArray[i].RegionType != REGION_LOGICAL);
+ if (regionArray[i].SysID == PARTITION_ENTRY_UNUSED)
+ {
+ freeSpace = TRUE;
+ }
+ else
+ {
+ usedCount++;
+ if (!IsExtended(regionArray[i].SysID) && regionArray[i].Recognized)
+ {
+ recogCount++;
+ }
+ }
+ }
+ FDASSERT(usedCount <= ENTRIES_PER_BOOTSECTOR);
+ FDASSERT(recogCount <= ENTRIES_PER_BOOTSECTOR);
+ FDASSERT(recogCount <= usedCount);
+
+ if ( (usedCount < ENTRIES_PER_BOOTSECTOR)
+ && freeSpace
+ && (!recogCount || AllowMultiplePrimaries))
+ {
+ *Allowed = TRUE;
+ }
+ else
+ {
+ *Allowed = FALSE;
+ }
+
+ FreeRegionArray(regionArray, regionCount);
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+IsCreationOfExtendedAllowed(
+ IN ULONG Disk,
+ OUT BOOLEAN *Allowed
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether creation of an extended partition is
+ allowed. This is true when there is a free entry in the MBR,
+ there is free primary space on the disk, and there is no existing
+ extended partition.
+
+Arguments:
+
+ Disk - index of disk to check
+
+ Allowed - returns whether creation of an extended partition
+ is allowed
+
+Return Value:
+
+ OK_STATUS or error code
+
+--*/
+
+{
+ PREGION_DESCRIPTOR regionArray;
+ ULONG regionCount;
+ ULONG usedCount;
+ ULONG freeCount;
+ ULONG i;
+ STATUS_CODE status;
+
+ status = GetPrimaryDiskRegions(Disk, &regionArray, &regionCount);
+ if (status != OK_STATUS)
+ {
+ return status;
+ }
+
+ for (usedCount = freeCount = i = 0; i<regionCount; i++)
+ {
+ FDASSERT(regionArray[i].RegionType != REGION_LOGICAL);
+ if (regionArray[i].SysID == PARTITION_ENTRY_UNUSED)
+ {
+ // BUGBUG should adjust the size here and see if it's non0 first
+ // (ie, take into account that the extended partition can't
+ // start on cyl 0).
+ freeCount++;
+ }
+ else
+ {
+ usedCount++;
+ if (IsExtended(regionArray[i].SysID))
+ {
+ FreeRegionArray(regionArray, regionCount);
+ *Allowed = FALSE;
+ return OK_STATUS;
+ }
+ }
+ }
+ *Allowed = (BOOLEAN)((usedCount < ENTRIES_PER_BOOTSECTOR) && freeCount);
+ FreeRegionArray(regionArray, regionCount);
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+IsCreationOfLogicalAllowed(
+ IN ULONG Disk,
+ OUT BOOLEAN *Allowed
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether creation of a logical volume is
+ allowed. This is true when there is an extended partition and
+ free space within it.
+
+Arguments:
+
+ Disk - index of disk to check
+
+ Allowed - returns whether creation of a logical volume is allowed
+
+Return Value:
+
+ OK_STATUS or error code
+
+--*/
+
+{
+ PREGION_DESCRIPTOR Regions;
+ ULONG RegionCount;
+ ULONG i;
+ STATUS_CODE status;
+ BOOLEAN ExtendedExists;
+
+ *Allowed = FALSE;
+
+ status = DoesExtendedExist(Disk, &ExtendedExists);
+ if (status != OK_STATUS)
+ {
+ return status;
+ }
+ if (!ExtendedExists)
+ {
+ return OK_STATUS;
+ }
+
+ status = GetLogicalDiskRegions(Disk, &Regions, &RegionCount);
+ if (status != OK_STATUS)
+ {
+ return status;
+ }
+
+ for (i = 0; i<RegionCount; i++)
+ {
+ FDASSERT(Regions[i].RegionType == REGION_LOGICAL);
+ if (Regions[i].SysID == PARTITION_ENTRY_UNUSED)
+ {
+ *Allowed = TRUE;
+ break;
+ }
+ }
+ FreeRegionArray(Regions, RegionCount);
+ return OK_STATUS;
+}
+
+
+
+STATUS_CODE
+DoesAnyPartitionExist(
+ IN ULONG Disk,
+ OUT PBOOLEAN AnyExists,
+ OUT PBOOLEAN PrimaryExists,
+ OUT PBOOLEAN ExtendedExists,
+ OUT PBOOLEAN LogicalExists
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether any partition exists on a given disk.
+ This is based on three sub queries: whether there are any primary or
+ extended partitions, or logical volumes on the disk.
+
+Arguments:
+
+ Disk - index of disk to check
+
+ AnyExists - returns whether any partitions exist on Disk
+
+ PrimaryExists - returns whether any primary partitions exist on Disk
+
+ ExtendedExists - returns whether there is an extended partition on Disk
+
+ LogicalExists - returns whether any logical volumes exist on Disk
+
+Return Value:
+
+ OK_STATUS or error code
+
+--*/
+
+{
+ STATUS_CODE status;
+
+ if ((status = DoesAnyPrimaryExist(Disk, PrimaryExists )) != OK_STATUS)
+ {
+ return status;
+ }
+ if ((status = DoesExtendedExist (Disk, ExtendedExists)) != OK_STATUS)
+ {
+ return status;
+ }
+ if ((status = DoesAnyLogicalExist(Disk, LogicalExists )) != OK_STATUS)
+ {
+ return status;
+ }
+ *AnyExists = (BOOLEAN)(*PrimaryExists || *ExtendedExists || *LogicalExists);
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+DoesAnyPrimaryExist(
+ IN ULONG Disk,
+ OUT PBOOLEAN Exists
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether any non-extended primary partition exists
+ on a given disk.
+
+Arguments:
+
+ Disk - index of disk to check
+
+ Exists - returns whether any primary partitions exist on Disk
+
+Return Value:
+
+ OK_STATUS or error code
+
+--*/
+
+{
+ PREGION_DESCRIPTOR regionArray;
+ ULONG regionCount;
+ ULONG i;
+ STATUS_CODE status;
+
+ status = GetUsedPrimaryDiskRegions(Disk, &regionArray, &regionCount);
+ if (status != OK_STATUS)
+ {
+ return status;
+ }
+
+ *Exists = FALSE;
+
+ for (i=0; i<regionCount; i++)
+ {
+ FDASSERT(regionArray[i].RegionType != REGION_LOGICAL);
+ FDASSERT(regionArray[i].SysID != PARTITION_ENTRY_UNUSED);
+ if (!IsExtended(regionArray[i].SysID))
+ {
+ *Exists = TRUE;
+ break;
+ }
+ }
+ FreeRegionArray(regionArray, regionCount);
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+DoesExtendedExist(
+ IN ULONG Disk,
+ OUT PBOOLEAN Exists
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether an extended partition exists
+ on a given disk.
+
+Arguments:
+
+ Disk - index of disk to check
+
+ Exists - returns whether an extended partition exists on Disk
+
+Return Value:
+
+ OK_STATUS or error code
+
+--*/
+
+{
+ PREGION_DESCRIPTOR regionArray;
+ ULONG regionCount;
+ ULONG i;
+ STATUS_CODE status;
+
+ status = GetUsedPrimaryDiskRegions(Disk, &regionArray, &regionCount);
+ if (status != OK_STATUS)
+ {
+ return status;
+ }
+
+ *Exists = FALSE;
+
+ for (i=0; i<regionCount; i++)
+ {
+ FDASSERT(regionArray[i].RegionType != REGION_LOGICAL);
+ FDASSERT(regionArray[i].SysID != PARTITION_ENTRY_UNUSED);
+ if (IsExtended(regionArray[i].SysID))
+ {
+ *Exists = TRUE;
+ break;
+ }
+ }
+ FreeRegionArray(regionArray, regionCount);
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+DoesAnyLogicalExist(
+ IN ULONG Disk,
+ OUT PBOOLEAN Exists
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines whether any logical volumes exist
+ on a given disk.
+
+Arguments:
+
+ Disk - index of disk to check
+
+ Exists - returns whether any logical volumes exist on Disk
+
+Return Value:
+
+ OK_STATUS or error code
+
+--*/
+
+{
+ PREGION_DESCRIPTOR regionArray;
+ ULONG regionCount;
+ STATUS_CODE status;
+
+ status = GetUsedLogicalDiskRegions(Disk, &regionArray, &regionCount);
+ if (status != OK_STATUS)
+ {
+ return status;
+ }
+
+ *Exists = (BOOLEAN)(regionCount != 0);
+ FreeRegionArray(regionArray, regionCount);
+ return OK_STATUS;
+}
+
+
+ULONG
+GetDiskCount(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the number of attached partitionable disk
+ devices. The returned value is one greater than the maximum index
+ allowed for Disk parameters to partitioning engine routines.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Count of disks.
+
+--*/
+
+{
+ return CountOfDisks;
+}
+
+
+PCHAR
+GetDiskName(
+ ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the system name for the disk device whose
+ index is given.
+
+Arguments:
+
+ Disk - index of disk whose name is desired.
+
+Return Value:
+
+ System name for the disk device. The caller must not attempt to
+ free this buffer or modify it.
+
+--*/
+
+{
+ return DiskNames[Disk];
+}
+
+
+// worker routines for WriteDriveLayout
+
+VOID
+UnusedEntryFill(
+ IN PPARTITION_INFORMATION pInfo,
+ IN ULONG EntryCount
+ )
+
+/*++
+
+Routine Description:
+
+ Initialize a partition information structure.
+
+Arguments:
+
+ pInfo - the partition information structure to fill in.
+ EntryCount - the number of entries in the structure to fill.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG i;
+ LARGE_INTEGER zero;
+
+ zero.QuadPart = 0;
+
+ for (i=0; i<EntryCount; i++)
+ {
+ pInfo[i].StartingOffset = zero;
+ pInfo[i].PartitionLength = zero;
+ pInfo[i].HiddenSectors = 0;
+ pInfo[i].PartitionType = PARTITION_ENTRY_UNUSED;
+ pInfo[i].BootIndicator = FALSE;
+ pInfo[i].RewritePartition = TRUE;
+ }
+}
+
+
+LARGE_INTEGER
+MakeBootRec(
+ ULONG Disk,
+ PPARTITION_INFORMATION pInfo,
+ PPARTITION pLogical,
+ PPARTITION pNextLogical,
+ ULONG TargetSlotEntry
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ Disk - the disk number
+ pInfo - the partition information for the disk.
+ pLogical
+ pNextLogical,
+ TargetSlotEntry - Where in the drive layout the entry will go. Need
+ this so we can detect if an entry moves.
+
+Return Value:
+
+ The starting offset.
+
+--*/
+
+{
+ ULONG entry = 0;
+ LARGE_INTEGER bytesPerTrack;
+ LARGE_INTEGER sectorsPerTrack;
+ LARGE_INTEGER startingOffset;
+
+ bytesPerTrack.QuadPart = DiskGeometryArray[Disk].BytesPerTrack;
+ sectorsPerTrack.QuadPart = DiskGeometryArray[Disk].SectorsPerTrack;
+ startingOffset.QuadPart = 0;
+
+ if (pLogical)
+ {
+
+ if (pLogical->EntryCameFromLayout) {
+
+ pInfo[entry] = pLogical->OriginalPartitionInformation;
+
+ } else {
+
+ pInfo[entry].StartingOffset.QuadPart = pLogical->Offset.QuadPart + bytesPerTrack.QuadPart;
+ pInfo[entry].PartitionLength.QuadPart = pLogical->Length.QuadPart - bytesPerTrack.QuadPart;
+ pInfo[entry].HiddenSectors = sectorsPerTrack.LowPart;
+
+ }
+
+ pInfo[entry].RewritePartition = pLogical->Update;
+ pInfo[entry].BootIndicator = pLogical->Active;
+ pInfo[entry].PartitionType = pLogical->SysID;
+
+ if (pLogical->EntryCameFromLayout &&
+ (TargetSlotEntry != pLogical->OriginalLayoutEntrySlot)) {
+
+ pInfo[entry].RewritePartition = TRUE;
+ pLogical->OriginalLayoutEntrySlot = TargetSlotEntry;
+
+ }
+
+ if (pInfo[entry].RewritePartition)
+ {
+ startingOffset = pInfo[entry].StartingOffset;
+ }
+
+ //
+ // Since the data will shortly be going ondisk we need to mark this
+ // entry as being from the disk layout and we should propagate
+ // back the information into the original partition info.
+ //
+
+ pLogical->EntryCameFromLayout = TRUE;
+ pLogical->OriginalLayoutEntrySlot = entry;
+ pLogical->OriginalPartitionInformation = pInfo[entry];
+ pLogical->OriginalPartitionInformation.RewritePartition = FALSE;
+ entry++;
+ }
+
+ if (pNextLogical)
+ {
+ pInfo[entry].StartingOffset = pNextLogical->Offset;
+ pInfo[entry].PartitionLength = pNextLogical->Length;
+ pInfo[entry].HiddenSectors = 0;
+ pInfo[entry].RewritePartition = TRUE;
+ pInfo[entry].BootIndicator = FALSE;
+ pInfo[entry].PartitionType = PARTITION_EXTENDED;
+
+ entry++;
+ }
+
+ UnusedEntryFill(pInfo+entry, ENTRIES_PER_BOOTSECTOR-entry);
+ return startingOffset;
+}
+
+
+STATUS_CODE
+ZapSector(
+ ULONG Disk,
+ LARGE_INTEGER Offset
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes zeros into a sector at a given offset. This is
+ used to clear out a new partition's filesystem boot record, so that
+ no previous filesystem appears in a new partition; or to clear out the
+ first EBR in the extended partition if there are to be no logical vols.
+
+Arguments:
+
+ Disk - disk to write to
+
+ Offset - byte offset to a newly created partition on Disk
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+ ULONG sectorSize = DiskGeometryArray[Disk].BytesPerSector;
+ ULONG i;
+ PCHAR sectorBuffer;
+ PCHAR alignedSectorBuffer;
+ STATUS_CODE status;
+ HANDLE_T handle;
+ LARGE_INTEGER temp;
+
+ if ((sectorBuffer = (PCHAR)AllocateMemory(2*sectorSize)) == NULL)
+ {
+ RETURN_OUT_OF_MEMORY;
+ }
+
+ alignedSectorBuffer = (PCHAR)(((ULONG)sectorBuffer+sectorSize) & ~(sectorSize-1));
+
+ for (i=0; i<sectorSize; i++)
+ {
+ alignedSectorBuffer[i] = 0;
+ }
+
+ if ((status = LowOpenDisk(GetDiskName(Disk), &handle)) != OK_STATUS)
+ {
+ FreeMemory(sectorBuffer);
+ return status;
+ }
+
+ temp.QuadPart = Offset.QuadPart / sectorSize;
+ status = LowWriteSectors(handle,
+ sectorSize,
+ temp.LowPart,
+ 1,
+ alignedSectorBuffer);
+
+ LowCloseDisk(handle);
+
+ // Now to make sure the file system really did a dismount,
+ // force a mount/verify of the partition. This avoids a
+ // problem where HPFS doesn't dismount when asked, but instead
+ // marks the volume for verify.
+
+ if ((status = LowOpenDisk(GetDiskName(Disk),&handle)) == OK_STATUS)
+ {
+ LowCloseDisk(handle);
+ }
+
+ FreeMemory(sectorBuffer);
+
+ return status;
+}
+
+
+STATUS_CODE
+WriteDriveLayout(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes the current partition layout for a given disk
+ out to disk. The high-level PARTITION lists are transformed into
+ a DRIVE_LAYOUT_INFORMATION structure before being passed down
+ to the low-level partition table writing routine.
+
+Arguments:
+
+ Disk - index of disk whose on-disk partition structure is to be updated.
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+#define MAX_DISKS 250
+
+ PDRIVE_LAYOUT_INFORMATION driveLayout;
+ PPARTITION_INFORMATION pInfo;
+ ULONG entryCount;
+ ULONG sectorSize;
+ STATUS_CODE status;
+ LARGE_INTEGER startingOffset,
+ extendedStartingOffset;
+ PPARTITION nextPartition,
+ partition,
+ partitionHash[MAX_DISKS];
+
+ extendedStartingOffset.QuadPart = 0;
+ memset(partitionHash, 0, sizeof(partitionHash));
+
+ // allocate a huge buffer now to avoid complicated dynamic
+ // reallocation schemes later.
+
+ if (!(driveLayout = (PDRIVE_LAYOUT_INFORMATION)AllocateMemory((MAX_DISKS + 1) * sizeof(PARTITION_INFORMATION))))
+ {
+ RETURN_OUT_OF_MEMORY;
+ }
+
+ pInfo = &driveLayout->PartitionEntry[0];
+
+ // first do the mbr.
+
+ entryCount=0;
+ partition = PrimaryPartitions[Disk];
+ sectorSize = DiskGeometryArray[Disk].BytesPerSector;
+
+ while (NULL != partition)
+ {
+ if (partition->SysID != PARTITION_ENTRY_UNUSED)
+ {
+ FDASSERT(entryCount < ENTRIES_PER_BOOTSECTOR);
+
+ if (IsExtended(partition->SysID))
+ {
+ extendedStartingOffset = partition->Offset;
+ }
+ else
+ {
+ partitionHash[entryCount] = partition;
+ }
+
+ //
+ // Check to see if the drive layout information here came
+ // from on-disk. If so, then use that instead of our generated.
+ // Note that we have to set rewrite IF the slot we are going into
+ // isn't the slot we originally were from. If it isn't make
+ // sure we reset the slot entry to where we are going.
+ //
+
+ if (partition->EntryCameFromLayout) {
+
+ pInfo[entryCount] = partition->OriginalPartitionInformation;
+
+ } else {
+
+ pInfo[entryCount].StartingOffset = partition->Offset;
+ pInfo[entryCount].PartitionLength = partition->Length;
+ pInfo[entryCount].HiddenSectors = (ULONG)(partition->Offset.QuadPart / sectorSize);
+
+ }
+
+ pInfo[entryCount].PartitionType = partition->SysID;
+ pInfo[entryCount].BootIndicator = partition->Active;
+ pInfo[entryCount].RewritePartition = partition->Update;
+
+ if (partition->EntryCameFromLayout &&
+ (entryCount != partition->OriginalLayoutEntrySlot)) {
+
+ pInfo[entryCount].RewritePartition = TRUE;
+ partition->OriginalLayoutEntrySlot = entryCount;
+
+ }
+
+ //
+ // Since the data will shortly be going ondisk we need to mark this
+ // entry as being from the disk layout and we should propagate
+ // back the information into the original partition info.
+ //
+
+ partition->EntryCameFromLayout = TRUE;
+ partition->OriginalLayoutEntrySlot = entryCount;
+ partition->OriginalPartitionInformation = pInfo[entryCount];
+ partition->OriginalPartitionInformation.RewritePartition = FALSE;
+
+ // if we're creating this partition, clear out the
+ // filesystem boot sector.
+
+ if ( pInfo[entryCount].RewritePartition
+ && partition->Update
+ && (partition->Update != CHANGED_DONT_ZAP)
+ && !IsExtended(pInfo[entryCount].PartitionType))
+ {
+ status = ZapSector(Disk, pInfo[entryCount].StartingOffset);
+ if (status != OK_STATUS)
+ {
+ FreeMemory(driveLayout);
+ return status;
+ }
+ }
+
+ entryCount++;
+ }
+ partition = partition->Next;
+ }
+
+ // fill the remainder of the MBR with unused entries.
+ // NOTE that there will thus always be an MBR even if there
+ // are no partitions defined.
+
+ UnusedEntryFill(pInfo+entryCount, ENTRIES_PER_BOOTSECTOR - entryCount);
+ entryCount = ENTRIES_PER_BOOTSECTOR;
+
+ //
+ // now handle the logical volumes.
+ // first check to see whether we need a dummy EBR at the beginning
+ // of the extended partition. This is the case when there is
+ // free space at the beginning of the extended partition.
+#if 0
+ // Also handle the case where we are creating an empty extended
+ // partition -- need to zap the first sector to eliminate any residue
+ // that might start an EBR chain.
+#else
+ // BUGBUG 4/24/92 tedm: Currently the io subsystem returns an error
+ // status (status_bad_master_boot_record) if any mbr or ebr is bad.
+ // Zeroing the first sector of the extended partition therefore causes
+ // the whole disk to be seen as empty. So create a blank, but valid,
+ // EBR in the 'empty extended partition' case. Code is in the 'else'
+ // part of the #if 0, below.
+#endif
+ //
+
+ if ( (NULL != (partition = LogicalVolumes[Disk]))
+ && (partition->SysID == PARTITION_ENTRY_UNUSED))
+ {
+ if (partition->Next)
+ {
+ partitionHash[entryCount] = partition;
+ MakeBootRec(Disk, pInfo+entryCount, NULL, partition->Next,entryCount);
+ entryCount += ENTRIES_PER_BOOTSECTOR;
+ partition = partition->Next;
+ }
+ else
+ {
+#if 0
+ status = ZapSector(Disk, extendedStartingOffset);
+ if (status != OK_STATUS)
+ {
+ FreeMemory(driveLayout);
+ return status;
+ }
+#else
+ MakeBootRec(Disk, pInfo+entryCount, NULL, NULL,entryCount);
+ entryCount += ENTRIES_PER_BOOTSECTOR;
+#endif
+ }
+ }
+
+ while (NULL != partition)
+ {
+ if (partition->SysID != PARTITION_ENTRY_UNUSED)
+ {
+ // find the next logical volume.
+
+ nextPartition = partition->Next;
+ while (NULL != nextPartition)
+ {
+ if (nextPartition->SysID != PARTITION_ENTRY_UNUSED)
+ {
+ break;
+ }
+ nextPartition = nextPartition->Next;
+ }
+
+ partitionHash[entryCount] = partition;
+ startingOffset = MakeBootRec(Disk, pInfo+entryCount, partition, nextPartition,entryCount);
+
+ // if we're creating a volume, clear out its filesystem
+ // boot sector so it starts out fresh.
+
+ if ((0 != startingOffset.QuadPart) && partition->Update &&
+ (partition->Update != CHANGED_DONT_ZAP))
+ {
+ status = ZapSector(Disk, startingOffset);
+ if (status != OK_STATUS)
+ {
+ FreeMemory(driveLayout);
+ return status;
+ }
+ }
+
+ entryCount += ENTRIES_PER_BOOTSECTOR;
+ }
+ partition = partition->Next;
+ }
+
+ driveLayout->PartitionCount = entryCount;
+ driveLayout->Signature = Signatures[Disk];
+ status = LowSetDiskLayout(DiskNames[Disk], driveLayout);
+
+ if (NT_SUCCESS(status))
+ {
+ // Update the partition numbers in the region structures.
+
+ // ReconcilePartitionNumbers(Disk, driveLayout);
+
+ for (entryCount = 0; entryCount < MAX_DISKS; entryCount++)
+ {
+ if (NULL != (partition = partitionHash[entryCount]))
+ {
+ if (partition->Update)
+ {
+ pInfo = &driveLayout->PartitionEntry[entryCount];
+ partition->PartitionNumber = pInfo->PartitionNumber;
+ }
+ }
+ }
+ }
+
+ FreeMemory(driveLayout);
+ return status;
+}
+
+
+STATUS_CODE
+CommitPartitionChanges(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the entry point for updating the on-disk partition
+ structures of a disk. The disk is only written to if the partition
+ structure has been changed by adding or deleting partitions.
+
+Arguments:
+
+ Disk - index of disk whose on-disk partition structure is to be updated.
+
+Return Value:
+
+ OK_STATUS or error code.
+
+--*/
+
+{
+ PPARTITION p;
+ STATUS_CODE status;
+
+ FDASSERT(!OffLine[Disk]);
+
+ if (!HavePartitionsBeenChanged(Disk))
+ {
+ return OK_STATUS;
+ }
+
+ if ((status = WriteDriveLayout(Disk)) != OK_STATUS)
+ {
+ return status;
+ }
+
+ // BUGBUG for ARC and NT MIPS, update NVRAM vars so partitions are right.
+ // Do that here, before partition numbers are reassigned.
+
+ p = PrimaryPartitions[Disk];
+ while (NULL != p)
+ {
+ p->Update = FALSE;
+ p->OriginalPartitionNumber = p->PartitionNumber;
+ p = p->Next;
+ }
+ p = LogicalVolumes[Disk];
+ while (NULL != p)
+ {
+ p->Update = FALSE;
+ p->OriginalPartitionNumber = p->PartitionNumber;
+ p = p->Next;
+ }
+
+ ChangesRequested[Disk] = FALSE;
+ ChangesCommitted[Disk] = TRUE;
+ return OK_STATUS;
+}
+
+
+BOOLEAN
+IsRegionCommitted(
+ PREGION_DESCRIPTOR RegionDescriptor
+ )
+
+/*++
+
+Routine Description:
+
+ Given a region descriptor, return TRUE if it actually exists on disk,
+ FALSE otherwise.
+
+Arguments:
+
+ RegionDescriptor - the region to check
+
+Return Value:
+
+ TRUE - if the region actually exists on disk
+ FALSE otherwise.
+
+--*/
+
+{
+ PPERSISTENT_REGION_DATA regionData;
+
+ regionData = PERSISTENT_DATA(RegionDescriptor);
+ return (NULL == regionData) ? NULL : !regionData->NewRegion;
+}
+
+
+BOOLEAN
+HavePartitionsBeenChanged(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns TRUE if the given disk's partition structures
+ have been modified by adding or deleting partitions, since the
+ on-disk structures were last written by a call to CommitPartitionChanges
+ (or first read).
+
+Arguments:
+
+ Disk - index of disk to check
+
+Return Value:
+
+ true if Disk's partition structure has changed.
+
+--*/
+
+{
+ return ChangesRequested[Disk];
+}
+
+BOOLEAN
+ChangeCommittedOnDisk(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will inform the caller if a change was actually committed
+ to the disk given.
+
+Arguments:
+
+ Disk - index of disk to check
+
+Return Value:
+
+ TRUE if disk was changed
+ FALSE otherwise.
+
+--*/
+
+{
+ return ChangesCommitted[Disk];
+}
+
+
+VOID
+ClearCommittedDiskInformation(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Clear all knowledge about any changes that have occurred to the
+ disks.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG i;
+
+ for (i=0; i<CountOfDisks; i++)
+ {
+ ChangesCommitted[i] = FALSE;
+ }
+}
+
+
+VOID
+FdMarkDiskDirty(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ Remember that this disk has had some partitioning changes.
+
+Arguments:
+
+ Disk - the disk number
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ChangesRequested[Disk] = TRUE;
+}
+
+
+VOID
+FdSetPersistentData(
+ IN PREGION_DESCRIPTOR Region,
+ IN PPERSISTENT_REGION_DATA Data
+ )
+
+/*++
+
+Routine Description:
+
+ Set the persistent data area for the specified region.
+
+Arguments:
+
+ Region - the region for which the persistent data is to be set
+ Data - the persistent data for the region.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ Region->Reserved->Partition->PersistentData = Data;
+}
+
+
+ULONG
+FdGetMinimumSizeMB(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ Return the minimum size for a partition on a given disk.
+
+ This is the rounded size of one cylinder or 1, whichever is greater.
+
+Arguments:
+
+ Region - region describing the partition to check.
+
+Return Value:
+
+ Actual offset
+
+--*/
+
+{
+ LARGE_INTEGER temp;
+
+ temp.QuadPart = DiskGeometryArray[Disk].BytesPerCylinder;
+ return max(SIZEMB(temp), 1);
+}
+
+
+ULONG
+FdGetMaximumSizeMB(
+ IN PREGION_DESCRIPTOR Region,
+ IN REGION_TYPE CreationType
+ )
+
+/*++
+
+Routine Description:
+
+ Given a region of disk determine how much of it may be used to
+ create the specified partition type. This code take into consideration
+ the many alignment restrictions imposed by early DOS software versions.
+
+Arguments:
+
+ Region - The affected region
+ CreationType - What is being created
+ (extended partition/primary partition)
+
+Return Value:
+
+ The maximum size that a partition of the specified type can be
+ to fit within the space available in the region.
+
+--*/
+
+{
+ PREGION_DATA createData = Region->Reserved;
+ LARGE_INTEGER maxSize;
+
+ maxSize.QuadPart = createData->AlignedRegionSize.QuadPart;
+
+ if (0 == createData->AlignedRegionOffset.QuadPart)
+ {
+ ULONG delta;
+
+ delta = (CreationType == REGION_EXTENDED)
+ ? DiskGeometryArray[Region->Disk].BytesPerCylinder
+ : DiskGeometryArray[Region->Disk].BytesPerTrack;
+
+ maxSize.QuadPart -= delta;
+ }
+
+ return SIZEMB(maxSize);
+}
+
+
+LARGE_INTEGER
+FdGetExactSize(
+ IN PREGION_DESCRIPTOR Region,
+ IN BOOLEAN ForExtended
+ )
+{
+ PREGION_DATA regionData = Region->Reserved;
+ LARGE_INTEGER largeSize = regionData->AlignedRegionSize;
+ LARGE_INTEGER bytesPerTrack;
+ LARGE_INTEGER bytesPerCylinder;
+
+ bytesPerTrack.QuadPart = DiskGeometryArray[Region->Disk].BytesPerTrack;
+ bytesPerCylinder.QuadPart = DiskGeometryArray[Region->Disk].BytesPerCylinder;
+
+ if (Region->RegionType == REGION_LOGICAL)
+ {
+ //
+ // The region is within the extended partition. It doesn't matter
+ // whether it's free space or used -- in either case, we need to
+ // account for the reserved EBR track.
+ //
+
+ largeSize.QuadPart -= bytesPerTrack.QuadPart;
+ }
+ else if (Region->SysID == PARTITION_ENTRY_UNUSED)
+ {
+ //
+ // The region is unused space not inside the extended partition.
+ // We must know whether the caller will put a primary or extended
+ // partition there -- a primary partition can use all the space, but
+ // a logical volume in the extended partition won't include the first
+ // track. If the free space starts at offset 0 on the disk, a special
+ // calculation must be used to move the start of the partition to
+ // skip a track for a primary or a cylinder and a track for an
+ // extended+logical.
+ //
+
+ if ((0 == regionData->AlignedRegionOffset.QuadPart) || ForExtended)
+ {
+ largeSize.QuadPart -= bytesPerTrack.QuadPart;
+ }
+
+ if ((0 == regionData->AlignedRegionOffset.QuadPart) && ForExtended)
+ {
+ largeSize.QuadPart -= bytesPerCylinder.QuadPart;
+ }
+ }
+
+ return largeSize;
+}
+
+
+LARGE_INTEGER
+FdGetExactOffset(
+ IN PREGION_DESCRIPTOR Region
+ )
+
+/*++
+
+Routine Description:
+
+ Determine where a given partition _actually_ starts, which may be
+ different than where is appears because of EBR reserved tracks, etc.
+
+ NOTE: This routine is not meant to operate on unused regions or
+ extended partitions. In these cases, it just returns the apparant offset.
+
+Arguments:
+
+ Region - region describing the partition to check.
+
+Return Value:
+
+ Actual offset
+
+--*/
+
+{
+ LARGE_INTEGER offset = ((PREGION_DATA)(Region->Reserved))->Partition->Offset;
+
+ if ((Region->SysID != PARTITION_ENTRY_UNUSED) && (Region->RegionType == REGION_LOGICAL))
+ {
+ //
+ // The region is a logical volume.
+ // Account for the reserved EBR track.
+ //
+
+ offset.QuadPart += DiskGeometryArray[Region->Disk].BytesPerTrack;
+ }
+
+ return offset;
+}
+
+
+BOOLEAN
+FdCrosses1024Cylinder(
+ IN PREGION_DESCRIPTOR Region,
+ IN ULONG CreationSizeMB,
+ IN REGION_TYPE RegionType
+ )
+
+/*++
+
+Routine Description:
+
+ Determine whether a used region corsses the 1024th cylinder, or whether
+ a partition created within a free space will cross the 1024th cylinder.
+
+Arguments:
+
+ Region - region describing the partition to check.
+
+ CreationSizeMB - if the Region is for a free space, this is the size of
+ the partition to be checked.
+
+ RegionType - one of REGION_PRIMARY, REGION_EXTENDED, or REGION_LOGICAL
+
+Return Value:
+
+ TRUE if the end cylinder >= 1024.
+
+--*/
+
+{
+ LARGE_INTEGER start, size, end, zero;
+
+ if (Region->SysID == PARTITION_ENTRY_UNUSED)
+ {
+ //
+ // Determine the exact size and offset of the partition, according
+ // to how CreatePartitionEx() will do it.
+ //
+
+ zero.QuadPart = 0;
+ DetermineCreateSizeAndOffset(Region,
+ zero,
+ CreationSizeMB,
+ RegionType,
+ &start,
+ &size);
+ }
+ else
+ {
+ start = ((PREGION_DATA)(Region->Reserved))->Partition->Offset;
+ size = ((PREGION_DATA)(Region->Reserved))->Partition->Length;
+ }
+
+ end.QuadPart = (start.QuadPart + size.QuadPart) - 1;
+
+ //
+ // end is the last byte in the partition. Divide by the number of
+ // bytes in a cylinder and see whether the result is > 1023.
+ //
+
+ end.QuadPart = end.QuadPart / DiskGeometryArray[Region->Disk].BytesPerCylinder;
+ return (end.QuadPart > 1023);
+}
+
+
+BOOLEAN
+IsDiskOffLine(
+ IN ULONG Disk
+ )
+{
+ return OffLine[Disk];
+}
+
+ULONG
+FdGetDiskSignature(
+ IN ULONG Disk
+ )
+{
+ return Signatures[Disk];
+}
+
+VOID
+FdSetDiskSignature(
+ IN ULONG Disk,
+ IN ULONG Signature
+ )
+{
+ Signatures[Disk] = Signature;
+}
+
+
+BOOLEAN
+SignatureIsUniqueToSystem(
+ IN ULONG Disk,
+ IN ULONG Signature
+ )
+{
+ ULONG index;
+
+ for (index = 0; index < Disk; index++)
+ {
+ if (Signatures[index] == Signature)
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
diff --git a/private/utils/windisk/src/engine.hxx b/private/utils/windisk/src/engine.hxx
new file mode 100644
index 000000000..e44a2e351
--- /dev/null
+++ b/private/utils/windisk/src/engine.hxx
@@ -0,0 +1,311 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: engine.hxx
+//
+// Contents: Partitioning engine declarations
+//
+// History: 2-Mar-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __ENGINE_HXX__
+#define __ENGINE_HXX__
+
+//////////////////////////////////////////////////////////////////////////////
+
+ULONG
+GetDiskCount(
+ VOID
+ );
+
+PCHAR
+GetDiskName(
+ ULONG Disk
+ );
+
+ULONG
+DiskSizeMB(
+ IN ULONG Disk
+ );
+
+STATUS_CODE
+GetDiskRegions(
+ IN ULONG Disk,
+ IN BOOLEAN WantUsedRegions,
+ IN BOOLEAN WantFreeRegions,
+ IN BOOLEAN WantPrimaryRegions,
+ IN BOOLEAN WantLogicalRegions,
+ OUT PREGION_DESCRIPTOR* Region,
+ OUT PULONG RegionCount
+ );
+
+#define GetAllDiskRegions(disk,regions,count) \
+ GetDiskRegions(disk,TRUE,TRUE,TRUE,TRUE,regions,count)
+
+#define GetFreeDiskRegions(disk,regions,count) \
+ GetDiskRegions(disk,FALSE,TRUE,TRUE,TRUE,regions,count)
+
+#define GetUsedDiskRegions(disk,regions,count) \
+ GetDiskRegions(disk,TRUE,FALSE,TRUE,TRUE,regions,count)
+
+#define GetPrimaryDiskRegions(disk,regions,count) \
+ GetDiskRegions(disk,TRUE,TRUE,TRUE,FALSE,regions,count)
+
+#define GetLogicalDiskRegions(disk,regions,count) \
+ GetDiskRegions(disk,TRUE,TRUE,FALSE,TRUE,regions,count)
+
+#define GetUsedPrimaryDiskRegions(disk,regions,count) \
+ GetDiskRegions(disk,TRUE,FALSE,TRUE,FALSE,regions,count)
+
+#define GetUsedLogicalDiskRegions(disk,regions,count) \
+ GetDiskRegions(disk,TRUE,FALSE,FALSE,TRUE,regions,count)
+
+#define GetFreePrimaryDiskRegions(disk,regions,count) \
+ GetDiskRegions(disk,FALSE,TRUE,TRUE,FALSE,regions,count)
+
+#define GetFreeLogicalDiskRegions(disk,regions,count) \
+ GetDiskRegions(disk,FALSE,TRUE,FALSE,TRUE,regions,count)
+
+VOID
+FreeRegionArray(
+ IN PREGION_DESCRIPTOR Region,
+ IN ULONG RegionCount
+ );
+
+STATUS_CODE
+IsAnyCreationAllowed(
+ IN ULONG Disk,
+ IN BOOLEAN AllowMultiplePrimaries,
+ OUT PBOOLEAN AnyAllowed,
+ OUT PBOOLEAN PrimaryAllowed,
+ OUT PBOOLEAN ExtendedAllowed,
+ OUT PBOOLEAN LogicalAllowed
+ );
+
+STATUS_CODE
+IsCreationOfPrimaryAllowed(
+ IN ULONG Disk,
+ IN BOOLEAN AllowMultiplePrimaries,
+ OUT PBOOLEAN Allowed
+ );
+
+STATUS_CODE
+IsCreationOfExtendedAllowed(
+ IN ULONG Disk,
+ OUT PBOOLEAN Allowed
+ );
+
+STATUS_CODE
+IsCreationOfLogicalAllowed(
+ IN ULONG Disk,
+ OUT PBOOLEAN Allowed
+ );
+
+STATUS_CODE
+DoesAnyPartitionExist(
+ IN ULONG Disk,
+ OUT PBOOLEAN AnyExists,
+ OUT PBOOLEAN PrimaryExists,
+ OUT PBOOLEAN ExtendedExists,
+ OUT PBOOLEAN LogicalExists
+ );
+
+STATUS_CODE
+DoesAnyPrimaryExist(
+ IN ULONG Disk,
+ OUT PBOOLEAN Exists
+ );
+
+STATUS_CODE
+DoesExtendedExist(
+ IN ULONG Disk,
+ OUT PBOOLEAN Exists
+ );
+
+STATUS_CODE
+DoesAnyLogicalExist(
+ IN ULONG Disk,
+ OUT PBOOLEAN Exists
+ );
+
+BOOLEAN
+IsExtended(
+ IN UCHAR SysID
+ );
+
+VOID
+SetPartitionActiveFlag(
+ IN PREGION_DESCRIPTOR Region,
+ IN UCHAR value
+ );
+
+STATUS_CODE
+CreatePartition(
+ IN PREGION_DESCRIPTOR Region,
+ IN ULONG CreationSizeMB,
+ IN REGION_TYPE Type
+ );
+
+STATUS_CODE
+CreatePartitionEx(
+ IN PREGION_DESCRIPTOR Region,
+ IN LARGE_INTEGER MinimumSize,
+ IN ULONG CreationSizeMB,
+ IN REGION_TYPE Type,
+ IN UCHAR SysId
+ );
+
+STATUS_CODE
+DeletePartition(
+ IN PREGION_DESCRIPTOR Region
+ );
+
+ULONG
+GetHiddenSectorCount(
+ ULONG Disk,
+ ULONG Partition
+ );
+
+VOID
+SetSysID(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ IN UCHAR SysID
+ );
+
+VOID
+SetSysID2(
+ IN PREGION_DESCRIPTOR Region,
+ IN UCHAR SysID
+ );
+
+PCHAR
+GetSysIDName(
+ UCHAR SysID
+ );
+
+STATUS_CODE
+CommitPartitionChanges(
+ IN ULONG Disk
+ );
+
+BOOLEAN
+IsRegionCommitted(
+ PREGION_DESCRIPTOR RegionDescriptor
+ );
+
+BOOLEAN
+HavePartitionsBeenChanged(
+ IN ULONG Disk
+ );
+
+BOOLEAN
+ChangeCommittedOnDisk(
+ IN ULONG Disk
+ );
+
+VOID
+ClearCommittedDiskInformation(
+ VOID
+ );
+
+VOID
+FdMarkDiskDirty(
+ IN ULONG Disk
+ );
+
+VOID
+FdSetPersistentData(
+ IN PREGION_DESCRIPTOR Region,
+ IN PPERSISTENT_REGION_DATA Data
+ );
+
+ULONG
+FdGetMinimumSizeMB(
+ IN ULONG Disk
+ );
+
+ULONG
+FdGetMaximumSizeMB(
+ IN PREGION_DESCRIPTOR Region,
+ IN REGION_TYPE CreationType
+ );
+
+LARGE_INTEGER
+FdGetExactSize(
+ IN PREGION_DESCRIPTOR Region,
+ IN BOOLEAN ForExtended
+ );
+
+LARGE_INTEGER
+FdGetExactOffset(
+ IN PREGION_DESCRIPTOR Region
+ );
+
+BOOLEAN
+FdCrosses1024Cylinder(
+ IN PREGION_DESCRIPTOR Region,
+ IN ULONG CreationSizeMB,
+ IN REGION_TYPE RegionType
+ );
+
+ULONG
+FdGetDiskSignature(
+ IN ULONG Disk
+ );
+
+VOID
+FdSetDiskSignature(
+ IN ULONG Disk,
+ IN ULONG Signature
+ );
+
+BOOLEAN
+IsDiskOffLine(
+ IN ULONG Disk
+ );
+
+
+STATUS_CODE
+FdiskInitialize(
+ VOID
+ );
+
+VOID
+FdiskCleanUp(
+ VOID
+ );
+
+VOID
+ConfigureSystemPartitions(
+ VOID
+ );
+
+
+VOID
+ConfigureOSPartitions(
+ VOID
+ );
+
+BOOLEAN
+SignatureIsUniqueToSystem(
+ IN ULONG Disk,
+ IN ULONG Signature
+ );
+
+//
+// Items below used to be in fdenginp.h -- have been moved here to
+// remove dependency on ArcInst project.
+//
+
+#define ONE_MEG (1024*1024)
+
+ULONG
+SIZEMB(
+ IN LARGE_INTEGER ByteCount
+ );
+
+#endif // __ENGINE_HXX__
diff --git a/private/utils/windisk/src/extend.cxx b/private/utils/windisk/src/extend.cxx
new file mode 100644
index 000000000..036ebe2fc
--- /dev/null
+++ b/private/utils/windisk/src/extend.cxx
@@ -0,0 +1,636 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: extend.cxx
+//
+// Contents: Code to handle disk and volume extensions in windisk
+//
+// History: 28-Sep-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#ifdef WINDISK_EXTENSIONS
+
+// #include <guids.h>
+
+#include "extend.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+ExtensionType Extensions[EX_NUM_EXTENSION_TYPES];
+
+VOLUME_INFO VolumeInfo[24] = { 0 }; // 24 drive letters: no A or B
+
+HARDDISK_INFO* HardDiskExtensions;
+INT cHardDiskExtensions;
+
+VOL_CLAIM_LIST* VolClaims;
+VOL_INFO* VolExtensions;
+INT cVolExtensions;
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: GetNewObj
+//
+// Synopsis: Creates and initializes a new object of the specified class
+//
+// Arguments: [clsid] -- the class ID of the object to initialize
+// [ppUnk] -- returned IUnknown pointer to the object
+//
+// Returns: TRUE on success, FALSE on failure
+//
+// History: 6-Jun-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+BOOL
+GetNewObj(
+ IN CLSID clsid,
+ OUT IUnknown** ppUnk
+ )
+{
+#if DBG == 1
+ daDebugOut((DEB_ITRACE,"GetNewObj, clsid = "));
+ DumpGuid(DEB_ITRACE|DEB_NOCOMPNAME, L"", clsid);
+#endif // DBG == 1
+
+ IUnknown* pUnk = NULL;
+
+ HRESULT hr = CoCreateInstance(
+ clsid,
+ NULL,
+ CLSCTX_ALL,
+ (REFIID)IID_IUnknown,
+ (void**)&pUnk);
+ if (SUCCEEDED(hr))
+ {
+ *ppUnk = pUnk;
+ return TRUE;
+ }
+ else
+ {
+ *ppUnk = NULL;
+ return FALSE;
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+//
+// BUGBUG: for now, all the enumerations are hard-coded
+//
+
+
+CLSID* HardDiskClasses[] =
+{
+// (CLSID*)&CLSID_KDA_SCSI //BUGBUG
+ (CLSID*)&CLSID_KDA_Hard
+};
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: EnumVolumeClasses, public
+//
+// Synopsis: Enumerates the set of Disk Administrator Volume
+// extension classes available.
+//
+// Arguments: [pExtension] -- where to put the extension list
+//
+// Returns: TRUE if succeeded, FALSE if failed
+//
+// History: 19-May-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+BOOL
+EnumVolumeClasses(
+ OUT ExtensionType* pExtension
+ )
+{
+ pExtension->pcls = NULL;
+ pExtension->cClasses = 0; //BUGBUG
+ return TRUE;
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: EnumHardDiskClasses, public
+//
+// Synopsis: Enumerates the set of Disk Administrator Hard Disk
+// extension classes available.
+//
+// Arguments: [pExtension] -- where to put the extension list
+//
+// Returns: TRUE if succeeded, FALSE if failed
+//
+// History: 19-May-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+BOOL
+EnumHardDiskClasses(
+ OUT ExtensionType* pExtension
+ )
+{
+ pExtension->pcls = HardDiskClasses;
+ pExtension->cClasses = ARRAYLEN(HardDiskClasses);
+
+ return TRUE;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: CreateVolume
+//
+// Synopsis: Set the volume information for a volume
+//
+// Arguments: [DriveLetter] -- drive letter of volume
+// [VolClaims] -- the volume claimers
+// [DiskState] -- the disk state the volume resides on
+// [RegionIndex] -- the region index of the volume
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+CreateVolume(
+ IN WCHAR DriveLetter,
+ IN PVOL_CLAIM_LIST VolClaims,
+ IN PDISKSTATE DiskState,
+ IN INT RegionIndex
+ )
+{
+ unsigned i = (unsigned)DriveLetterToIndex(DriveLetter);
+
+ VolumeInfo[i].VolClaims = VolClaims;
+ VolumeInfo[i].DiskState = DiskState;
+ VolumeInfo[i].RegionIndex = RegionIndex;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: ClaimVolume
+//
+// Synopsis: Find all the claimers of a volume
+//
+// Arguments: [DriveLetter] -- drive letter of the volume in question
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+ClaimVolume(
+ IN WCHAR DriveLetter
+ )
+{
+ PDISKSTATE diskState;
+ INT regionIndex;
+ INT i;
+
+ VolClaims = NULL;
+
+ GetInfoFromDriveLetter(DriveLetter, &diskState, &regionIndex);
+
+ if (NULL != diskState)
+ {
+ for (i=0; i<cVolExtensions; i++)
+ {
+ if (NULL != VolExtensions[i].pExtension)
+ {
+ //
+ // Now, test if extension #i is used on the volume identified
+ // by DriveLetter
+ //
+
+ BOOL fInterested = FALSE;
+ VolumeInfoBlockType vi = { DriveLetter };
+
+ VolExtensions[i].pExtension->Claim(
+ &vi,
+ &fInterested
+ );
+
+ if (fInterested)
+ {
+ daDebugOut((DEB_TRACE,
+ "Adding %ws to extensions for %wc:\n",
+ VolExtensions[i].pInfo->pwszShortName,
+ DriveLetter
+ ));
+
+ //
+ // add this extension to the claim list
+ //
+ PVOL_CLAIM_LIST tmp = VolClaims;
+ VolClaims = (VOL_CLAIM_LIST*)Malloc(sizeof(VOL_CLAIM_LIST));
+ VolClaims->pNext = tmp;
+ VolClaims->pClaimer = &VolExtensions[i];
+ }
+ }
+ }
+ }
+
+ CreateVolume(DriveLetter, VolClaims, diskState, regionIndex);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: ClaimDisk
+//
+// Synopsis: Find all the claimers of a disk
+//
+// Arguments: [DiskNum] -- disk number of disk in question
+//
+// Returns: nothing
+//
+// History: 7-Oct-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+ClaimDisk(
+ IN ULONG DiskNum
+ )
+{
+ PHARDDISK_CLAIM_LIST* ppClaims = &DiskArray[DiskNum]->pClaims;
+
+ *ppClaims = NULL;
+
+ for (INT i=0; i<cHardDiskExtensions; i++)
+ {
+ if (NULL != HardDiskExtensions[i].pExtension)
+ {
+ //
+ // Now, test if extension #i is used on the disk identified
+ // by DiskNum
+ //
+
+ BOOL fInterested = FALSE;
+ HardDiskInfoBlockType di = { DiskNum };
+
+ HardDiskExtensions[i].pExtension->Claim(
+ &di,
+ &fInterested
+ );
+
+ if (fInterested)
+ {
+ daDebugOut((DEB_TRACE,
+ "Adding %ws to extensions for disk %d\n",
+ HardDiskExtensions[i].pInfo->pwszShortName,
+ DiskNum
+ ));
+
+ //
+ // add this extension to the claim list
+ //
+
+ PHARDDISK_CLAIM_LIST NewClaim;
+ NewClaim = (PHARDDISK_CLAIM_LIST)Malloc(sizeof(HARDDISK_CLAIM_LIST));
+ NewClaim->pNext = *ppClaims;
+ NewClaim->pClaimer = &HardDiskExtensions[i];
+ *ppClaims = NewClaim;
+ }
+ }
+ }
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: GetExtensions
+//
+// Synopsis: Finds and activates all extensions and claims all significant
+// volumes
+//
+// Arguments: (none)
+//
+// Returns: TRUE on success, FALSE on failure
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+BOOL
+GetExtensions(
+ VOID
+ )
+{
+ BOOL f;
+ HRESULT hr;
+
+ f = EnumVolumeClasses(&Extensions[EX_VOLUME]);
+ if (!f)
+ {
+ daDebugOut((DEB_ERROR,
+ "Failed to enumerate volume extension classes\n"));
+ return f;
+ }
+
+ f = EnumHardDiskClasses(&Extensions[EX_DISK]);
+ if (!f)
+ {
+ daDebugOut((DEB_ERROR,
+ "Failed to enumerate hard disk extension classes\n"));
+ return f;
+ }
+
+ //
+ // At this point, all the extension classes have been found. Call
+ // the Claim() functions to determine who wants to deal with what
+ // volumes/disks/etc. This involves activating all the extension
+ // classes.
+ //
+
+ daDebugOut((DEB_TRACE, "Extensions loaded\n"));
+
+ IUnknown* pUnk;
+ int i;
+
+ //
+ // Activate volume extensions
+ //
+
+ cVolExtensions = Extensions[EX_VOLUME].cClasses;
+ VolExtensions = (VOL_INFO*)Malloc(cVolExtensions * sizeof(VOL_INFO));
+
+ for (i=0; i<cVolExtensions; i++)
+ {
+ f = GetNewObj(*(Extensions[EX_VOLUME].pcls[i]), &pUnk);
+ if (!f)
+ {
+ daDebugOut((DEB_ERROR, "GetNewObj failed on volume extension #%d\n", i));
+ VolExtensions[i].pExtension = NULL;
+ }
+ else
+ {
+ daDebugOut((DEB_TRACE, "Activated volume extension #%d\n", i));
+
+ hr = pUnk->QueryInterface(
+ IID_IDAVolumeInfo,
+ (void**)(&VolExtensions[i].pExtension)
+ );
+ pUnk->Release();
+
+ if (FAILED(hr))
+ {
+ daDebugOut((DEB_ERROR, "QueryInterface failed on #%d\n", i));
+ VolExtensions[i].pExtension = NULL;
+ }
+ else
+ {
+ hr = VolExtensions[i].pExtension->QueryInfo(&VolExtensions[i].pInfo);
+ if (FAILED(hr))
+ {
+ VolExtensions[i].pExtension->Release();
+ VolExtensions[i].pExtension = NULL;
+ }
+ }
+ }
+ }
+
+ //
+ // Activate hard disk extensions
+ //
+
+ cHardDiskExtensions = Extensions[EX_DISK].cClasses;
+ HardDiskExtensions = (HARDDISK_INFO*)Malloc(cHardDiskExtensions * sizeof(HARDDISK_INFO));
+
+ for (i=0; i<cHardDiskExtensions; i++)
+ {
+ f = GetNewObj(*(Extensions[EX_DISK].pcls[i]), &pUnk);
+ if (!f)
+ {
+ daDebugOut((DEB_ERROR, "GetNewObj failed on hard disk extension #%d\n", i));
+ HardDiskExtensions[i].pExtension = NULL;
+ }
+ else
+ {
+ daDebugOut((DEB_TRACE, "Activated Hard Disk extension #%d\n", i));
+
+ hr = pUnk->QueryInterface(
+ IID_IDAHardDiskInfo,
+ (void**)(&HardDiskExtensions[i].pExtension)
+ );
+ pUnk->Release();
+
+ if (FAILED(hr))
+ {
+ daDebugOut((DEB_ERROR, "QueryInterface failed on #%d\n", i));
+ HardDiskExtensions[i].pExtension = NULL;
+ }
+ else
+ {
+ hr = HardDiskExtensions[i].pExtension->QueryInfo(&HardDiskExtensions[i].pInfo);
+ if (FAILED(hr))
+ {
+ HardDiskExtensions[i].pExtension->Release();
+ HardDiskExtensions[i].pExtension = NULL;
+ }
+ }
+ }
+ }
+
+ daDebugOut((DEB_TRACE, "Extensions activated\n"));
+
+ //
+ // With all the extensions activated, perform claiming:
+ //
+ // Extension Item claimed
+ // --------- ------------
+ // file system formatted volume
+ // volume any pre-existing volume
+ // hard disk hard disk
+ //
+ // Note that no extension claims free space.
+ //
+
+ WCHAR driveLetter;
+
+ // for each pre-existing, formatted volume...
+
+ for (driveLetter = L'C'; driveLetter <= L'Z'; driveLetter++)
+ {
+ ClaimVolume(driveLetter);
+ }
+
+ // do hard disk claiming
+
+ for (ULONG DiskNum = 0; DiskNum<DiskCount; DiskNum++)
+ {
+ ClaimDisk(DiskNum);
+ }
+
+#if DBG == 1
+ PrintClaims();
+#endif // DBG == 1
+
+ return TRUE;
+}
+
+//+---------------------------------------------------------------------------
+//
+// Function: DeactivateExtensions
+//
+// Synopsis:
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 28-Sep-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DeactivateExtensions(
+ VOID
+ )
+{
+ INT i;
+
+ //
+ // Deactivate volume extensions
+ //
+
+ for (i=0; i<cVolExtensions; i++)
+ {
+ if (NULL != VolExtensions[i].pExtension)
+ {
+ daDebugOut((DEB_TRACE,
+ "Releasing %ws\n",
+ VolExtensions[i].pInfo->pwszShortName
+ ));
+
+ ULONG cRefs = VolExtensions[i].pExtension->Release();
+
+ daDebugOut((DEB_TRACE, " ... had %s references\n",
+ cRefs > 0 ? ">0" : (cRefs < 0 ? "<0" : "0")
+ ));
+ }
+ else
+ {
+ daDebugOut((DEB_TRACE, "Extension %d didn't exist\n", i));
+ }
+
+ // BUGBUG: MemFree VolExtensions[i].pInfo
+ }
+
+ Free(VolExtensions);
+
+ //
+ // Activate hard disk extensions
+ //
+
+ for (i=0; i<cHardDiskExtensions; i++)
+ {
+ if (NULL != HardDiskExtensions[i].pExtension)
+ {
+ daDebugOut((DEB_TRACE,
+ "Releasing %ws\n",
+ HardDiskExtensions[i].pInfo->pwszShortName
+ ));
+
+ ULONG cRefs = HardDiskExtensions[i].pExtension->Release();
+
+ daDebugOut((DEB_TRACE, " ... had %s references\n",
+ cRefs > 0 ? ">0" : (cRefs < 0 ? "<0" : "0")
+ ));
+ }
+ else
+ {
+ daDebugOut((DEB_TRACE, "Extension %d didn't exist\n", i));
+ }
+
+ // BUGBUG MemFree HardDiskExtensions[i].pInfo
+ }
+
+ Free(HardDiskExtensions);
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: AddExtensionItemsToMenu
+//
+// Synopsis: Adds an extension menu item to both the menu bar and the
+// given context menu.
+//
+// Arguments: [hmenuBar] -- menu bar menu to add item to
+// [pMenu] -- pointer to extension menu item
+// [fFlags] -- standard menu flags (probably
+// MF_ENABLED or MF_GRAYED)
+//
+// Modifies: g_uItemInsertHere
+//
+// Returns: count of items added
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+INT
+AddExtensionItemsToMenu(
+ IN HMENU hmenuBar,
+ IN MenuType* pMenu,
+ IN BOOL fFlags
+ )
+{
+ for (int i=0; i<pMenu->cMenuItems; i++)
+ {
+ MenuItemType* pItem = &(pMenu->aMenuItems[i]);
+
+ UINT id = MenuItems.AllocateId(pItem); //get an ID
+
+ if ((UINT)-1 == id)
+ {
+ daDebugOut((DEB_ERROR,
+ "Couldn't add '%ws' to menu\n",
+ pItem->pszMenu
+ ));
+ }
+ else
+ {
+ InsertMenu(
+ hmenuBar,
+ g_uItemInsertHere++,
+ MF_BYPOSITION | MF_STRING | fFlags,
+ id,
+ pItem->pszMenu
+ );
+ }
+ }
+
+ return pMenu->cMenuItems;
+}
+
+
+#endif // WINDISK_EXTENSIONS
diff --git a/private/utils/windisk/src/extend.hxx b/private/utils/windisk/src/extend.hxx
new file mode 100644
index 000000000..6d944d384
--- /dev/null
+++ b/private/utils/windisk/src/extend.hxx
@@ -0,0 +1,87 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: extend.hxx
+//
+// Contents: Code to handle disk and volume extensions in windisk
+//
+// History: 28-Sep-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __EXTEND_HXX__
+#define __EXTEND_HXX__
+
+#ifdef WINDISK_EXTENSIONS
+
+//////////////////////////////////////////////////////////////////////////////
+
+extern ExtensionType Extensions[];
+
+extern VOLUME_INFO VolumeInfo[];
+
+extern HARDDISK_INFO* HardDiskExtensions;
+extern INT cHardDiskExtensions;
+
+extern VOL_CLAIM_LIST* VolClaims;
+extern VOL_INFO* VolExtensions;
+extern INT cVolExtensions;
+
+//////////////////////////////////////////////////////////////////////////////
+
+BOOL
+GetNewObj(
+ IN CLSID clsid,
+ OUT IUnknown** ppUnk
+ );
+
+BOOL
+EnumVolumeClasses(
+ OUT ExtensionType* pExtension
+ );
+
+BOOL
+EnumHardDiskClasses(
+ OUT ExtensionType* pExtension
+ );
+
+VOID
+CreateVolume(
+ IN WCHAR DriveLetter,
+ IN PVOL_CLAIM_LIST VolClaims,
+ IN PDISKSTATE DiskState,
+ IN INT RegionIndex
+ );
+
+VOID
+ClaimVolume(
+ IN WCHAR DriveLetter
+ );
+
+VOID
+ClaimDisk(
+ IN ULONG DiskNum
+ );
+
+BOOL
+GetExtensions(
+ VOID
+ );
+
+VOID
+DeactivateExtensions(
+ VOID
+ );
+
+INT
+AddExtensionItemsToMenu(
+ IN HMENU hmenuBar,
+ IN MenuType* pMenu,
+ IN BOOL fFlags
+ );
+
+#endif // WINDISK_EXTENSIONS
+
+#endif // __EXTEND_HXX__
diff --git a/private/utils/windisk/src/fill.cxx b/private/utils/windisk/src/fill.cxx
new file mode 100644
index 000000000..42c19f91a
--- /dev/null
+++ b/private/utils/windisk/src/fill.cxx
@@ -0,0 +1,867 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: fill.cxx
+//
+// Contents: Routines to fill the volumes view with data from the Disk
+// Administrator internal state.
+//
+// History: 20-May-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include "cdrom.hxx"
+#include "dispinfo.hxx"
+#include "drives.hxx"
+#include "fill.hxx"
+#include "select.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+extern int IconIndexSmall[];
+
+// indices into Icon* arrays
+
+#define I_HARD 0
+#define I_CDROM 1
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+//+-------------------------------------------------------------------------
+//
+// Function: AddVolumeToListview, public
+//
+// Synopsis: Add a region to the listview
+//
+// Arguments:
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+VOID
+AddVolumeToListview(
+ IN int item,
+ IN WCHAR DriveLetter
+ )
+{
+ //
+ // First, get all the data into the CDispInfo class. If any of this fails,
+ // then ignore the item. After that, then do the listview insertions.
+ //
+
+ CDispInfo* pDispInfo = new CDispInfo();
+ if (NULL == pDispInfo)
+ {
+ return; //BUGBUG: out of memory
+ }
+
+ UINT wId; // resource ID to load & use
+ INT columnIndex;
+ PWSTR pszTemp;
+ WCHAR wszTemp[MAX_LV_ITEM_LEN];
+ DWORD capacityInMB;
+ DWORD overheadInMB;
+ PWSTR volumeLabel;
+ PWSTR typeName;
+ WCHAR driveLetterW;
+
+ BOOL spaceInfoOK = TRUE; // assume no trouble getting data
+ BOOL capacityOK = TRUE;
+
+ PREGION_DESCRIPTOR regionDescriptor;
+ PPERSISTENT_REGION_DATA regionData;
+ PFT_OBJECT_SET ftSet;
+ PFT_OBJECT ftObject;
+
+ WCHAR mbBuffer[16];
+ WCHAR unavailableDataBuffer[16];
+
+ WCHAR freeSpaceInMBString[30];
+ ULONG percentageFree = 0L;
+
+ //
+ // Before setting any columns, get all the data
+ //
+
+ //
+ // Load resource strings:
+ // unavailableDataBuffer -- ?
+ // mbBuffer -- MB
+ //
+
+ LoadString(
+ g_hInstance,
+ IDS_UNAVAILABLE_DATA,
+ unavailableDataBuffer,
+ ARRAYLEN(unavailableDataBuffer)
+ );
+
+ LoadString(
+ g_hInstance,
+ IDS_MEGABYTES_ABBREV,
+ mbBuffer,
+ ARRAYLEN(mbBuffer)
+ );
+
+ //
+ // Get data
+ //
+
+ regionDescriptor = RegionFromDriveLetter(DriveLetter);
+ regionData = PERSISTENT_DATA(regionDescriptor);
+ ftObject = GET_FT_OBJECT(regionDescriptor);
+
+ //
+ // Get the file system type name and volume label from persistent data
+ //
+
+ DetermineRegionInfo(
+ regionDescriptor,
+ &typeName,
+ &volumeLabel,
+ &driveLetterW // just get it again...
+ );
+
+ //
+ // Calculate capacity and fault tolerance overhead
+ //
+
+ // For non-new volumes, use the TotalSpaceInBytes field from
+ // persistent region data?
+
+ if (ftObject)
+ {
+ //
+ // This volume is part of an FT set
+ //
+
+ PFT_OBJECT ftObj;
+ overheadInMB = capacityInMB = 0;
+
+ ftSet = ftObject->Set;
+
+ for (ftObj = ftSet->Members; NULL != ftObj; ftObj = ftObj->Next)
+ {
+ PREGION_DESCRIPTOR componentRegion = ftObj->Region;
+ if (NULL == componentRegion)
+ {
+ // An FT set has a missing component!
+
+ capacityInMB = 0;
+ capacityOK = FALSE;
+ break;
+ }
+
+ capacityInMB += componentRegion->SizeMB;
+ }
+
+ if (capacityOK)
+ {
+ switch (ftSet->Type)
+ {
+ case Mirror:
+ case StripeWithParity:
+ //
+ // Fault tolerant volumes use one region of the set for
+ // redundancy information
+ //
+ overheadInMB = regionDescriptor->SizeMB;
+ break;
+
+ default:
+ //
+ // Simple stripes and volume sets can use all the space
+ // they are given, for user data.
+ //
+ overheadInMB = 0;
+ break;
+ }
+ }
+
+ //
+ // subtract off the overhead from the total amount of space
+ // taken up by the volume; this is what the user gets back when
+ // doing a "dir" or "du" on the volume.
+ //
+
+ capacityInMB -= overheadInMB;
+ }
+ else
+ {
+ //
+ // A simple, non-FT volume
+ //
+
+ capacityInMB = regionDescriptor->SizeMB;
+ overheadInMB = 0;
+ }
+
+ //
+ // Calculate free space and percentage free
+ //
+
+ if (capacityOK && !regionData->NewRegion)
+ {
+ LARGE_INTEGER freeSpaceInMB;
+
+ freeSpaceInMB.QuadPart = regionData->FreeSpaceInBytes.QuadPart
+ / 1048576; // One MB
+
+ LargeIntegerToUnicodeChar(
+ &freeSpaceInMB,
+ 10,
+ ARRAYLEN(freeSpaceInMBString),
+ freeSpaceInMBString
+ );
+
+ if (0 == regionData->TotalSpaceInBytes.QuadPart)
+ {
+ // avoid divide by zero for volumes with no space data
+ percentageFree = 0;
+ }
+ else
+ {
+// percentageFree = 100 * FreeSpaceInBytes / TotalSpaceInBytes;
+
+ percentageFree = (ULONG)(regionData->FreeSpaceInBytes.QuadPart
+ * 100
+ / regionData->TotalSpaceInBytes.QuadPart);
+ }
+ }
+ else
+ {
+ //
+ // new regions don't have any free space info
+ //
+
+ spaceInfoOK = FALSE;
+ }
+
+ columnIndex = 0;
+
+ //
+ // column: drive letter
+ //
+
+ wsprintf(wszTemp, TEXT("%c:"), DriveLetter);
+
+ if (!pDispInfo->SetText(columnIndex++, wszTemp))
+ {
+ daDebugOut((DEB_ITRACE, "SetText failed\n"));
+ }
+
+ //
+ // column: volume label
+ //
+
+ if (!pDispInfo->SetText(columnIndex++, volumeLabel))
+ {
+ daDebugOut((DEB_ITRACE, "SetText failed\n"));
+ }
+
+ //
+ // column: capacity in MB
+ //
+
+ if (capacityOK)
+ {
+ wsprintf(wszTemp, TEXT("%lu %s"), capacityInMB, mbBuffer);
+ }
+ else
+ {
+ wsprintf(wszTemp, unavailableDataBuffer);
+ }
+
+ if (!pDispInfo->SetText(columnIndex++, wszTemp))
+ {
+ daDebugOut((DEB_ITRACE, "SetText failed\n"));
+ }
+
+ //
+ // column: free space in MB
+ //
+
+ if (spaceInfoOK)
+ {
+ wsprintf(wszTemp, TEXT("%s %s"), freeSpaceInMBString, mbBuffer);
+ }
+ else
+ {
+ LoadString(
+ g_hInstance,
+ IDS_UNKNOWNTYPE,
+ wszTemp,
+ ARRAYLEN(wszTemp)
+ );
+ }
+
+ if (!pDispInfo->SetText(columnIndex++, wszTemp))
+ {
+ daDebugOut((DEB_ITRACE, "SetText failed\n"));
+ }
+
+ //
+ // column: % free space
+ //
+
+ if (spaceInfoOK)
+ {
+ wsprintf(wszTemp, TEXT("%d %%"), percentageFree);
+
+ pszTemp = wszTemp;
+ }
+ else
+ {
+ pszTemp = unavailableDataBuffer;
+ }
+
+ if (!pDispInfo->SetText(columnIndex++, pszTemp))
+ {
+ daDebugOut((DEB_ITRACE, "SetText failed\n"));
+ }
+
+ //
+ // column: format (file system type)
+ //
+
+ if (!pDispInfo->SetText(columnIndex++, typeName))
+ {
+ daDebugOut((DEB_ITRACE, "SetText failed\n"));
+ }
+
+ //
+ // column: fault tolerant?
+ //
+
+ if (IsFaultTolerantRegion(regionDescriptor))
+ {
+ wId = IDS_FT_YES;
+ }
+ else
+ {
+ wId = IDS_FT_NO;
+ }
+
+ LoadString(
+ g_hInstance,
+ wId,
+ wszTemp,
+ ARRAYLEN(wszTemp)
+ );
+
+ if (!pDispInfo->SetText(columnIndex++, wszTemp))
+ {
+ daDebugOut((DEB_ITRACE, "SetText failed\n"));
+ }
+
+ //
+ // column: volume type
+ //
+
+ ftObject = GET_FT_OBJECT(regionDescriptor);
+
+ switch (ftObject ? ftObject->Set->Type : -1)
+ {
+ case Mirror:
+ wId = IDS_VOLTYPE_MIRROR;
+ break;
+
+ case Stripe:
+ wId = IDS_VOLTYPE_STRIPE;
+ break;
+
+ case StripeWithParity:
+ wId = IDS_VOLTYPE_PARITY;
+ break;
+
+ case VolumeSet:
+ wId = IDS_VOLTYPE_VOLSET;
+ break;
+
+ default:
+ wId = IDS_VOLTYPE_SIMPLE;
+ break;
+ }
+
+ LoadString(
+ g_hInstance,
+ wId,
+ wszTemp,
+ ARRAYLEN(wszTemp)
+ );
+
+ if (!pDispInfo->SetText(columnIndex++, wszTemp))
+ {
+ daDebugOut((DEB_ITRACE, "SetText failed\n"));
+ }
+
+ //
+ // column: fault tolerance overhead in MB
+ //
+
+ if (capacityOK)
+ {
+ if (overheadInMB != 0)
+ {
+ wsprintf(
+ wszTemp,
+ TEXT("%lu %s (%lu%%)"),
+ overheadInMB,
+ mbBuffer,
+ (ULONG)(100 * overheadInMB / capacityInMB));
+ }
+ else
+ {
+ wsprintf(wszTemp, TEXT(""));
+ }
+ }
+ else
+ {
+ wsprintf(wszTemp, unavailableDataBuffer);
+ }
+
+ if (!pDispInfo->SetText(columnIndex++, wszTemp))
+ {
+ daDebugOut((DEB_ITRACE, "SetText failed\n"));
+ }
+
+ //
+ // column: status
+ //
+
+ switch (ftObject ? ftSet->Status : -1)
+ {
+ case FtSetHealthy:
+ wId = IDS_FTSTATUS_HEALTHY;
+ break;
+
+ case FtSetNew:
+ case FtSetNewNeedsInitialization:
+ wId = IDS_FTSTATUS_NEW;
+ break;
+
+ case FtSetBroken:
+ wId = IDS_FTSTATUS_BROKEN;
+ break;
+
+ case FtSetRecoverable:
+ wId = IDS_FTSTATUS_RECOVERABLE;
+ break;
+
+ case FtSetRecovered:
+ wId = IDS_FTSTATUS_REGENERATED;
+ break;
+
+ case FtSetInitializing:
+ wId = IDS_FTSTATUS_INITIALIZING;
+ break;
+
+ case FtSetRegenerating:
+ wId = IDS_FTSTATUS_REGENERATING;
+ break;
+
+ default:
+ wId = IDS_FTSTATUS_NONE;
+ break;
+ }
+
+ LoadString(
+ g_hInstance,
+ wId,
+ wszTemp,
+ ARRAYLEN(wszTemp)
+ );
+
+ if (!pDispInfo->SetText(columnIndex++, wszTemp))
+ {
+ daDebugOut((DEB_ITRACE, "SetText failed\n"));
+ }
+
+ //
+ // Insert the data into the listview
+ //
+
+ LV_ITEM lvi;
+ lvi.iItem = item;
+ lvi.iSubItem = 0;
+ lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
+ lvi.state = 0;
+ lvi.stateMask = 0;
+ lvi.cchTextMax = 0; // ignored when setting data
+ lvi.pszText = LPSTR_TEXTCALLBACK;
+ lvi.iImage = IconIndexSmall[I_HARD]; //BUGBUG: CD-ROMs?
+ lvi.lParam = (LPARAM)pDispInfo;
+
+ if (ListView_InsertItem(g_hwndLV, &lvi) == -1)
+ {
+ //BUGBUG: why would it fail?
+ delete pDispInfo;
+ return;
+ }
+
+ for (int iSubItem = 1; iSubItem < g_cColumns; iSubItem++)
+ {
+ ListView_SetItemText(
+ g_hwndLV,
+ item,
+ iSubItem,
+ LPSTR_TEXTCALLBACK);
+ }
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: AddCdRomToListview, public
+//
+// Synopsis: Add a region to the listview
+//
+// Arguments:
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+VOID
+AddCdRomToListview(
+ IN int item,
+ IN WCHAR DriveLetter
+ )
+{
+ //
+ // First, get all the data into the CDispInfo class. If any of this fails,
+ // then ignore the item. After that, then do the listview insertions.
+ //
+
+ CDispInfo* pDispInfo = new CDispInfo();
+ if (NULL == pDispInfo)
+ {
+ return; //BUGBUG: out of memory
+ }
+
+ INT columnIndex;
+ WCHAR wszTemp[MAX_LV_ITEM_LEN];
+ WCHAR mbBuffer[16];
+
+ PCDROM_DESCRIPTOR cdrom = CdRomFindDriveLetter(DriveLetter);
+
+ //
+ // Before setting any columns, get all the data
+ //
+
+ //
+ // Load resource strings:
+ // mbBuffer -- MB
+ //
+
+ LoadString(
+ g_hInstance,
+ IDS_MEGABYTES_ABBREV,
+ mbBuffer,
+ ARRAYLEN(mbBuffer)
+ );
+
+ columnIndex = 0;
+
+ //
+ // column: drive letter
+ //
+
+ wsprintf(wszTemp, TEXT("%c:"), DriveLetter);
+
+ if (!pDispInfo->SetText(columnIndex++, wszTemp))
+ {
+ daDebugOut((DEB_ITRACE, "SetText failed\n"));
+ }
+
+ //
+ // column: volume label
+ //
+
+ if (cdrom->VolumeLabel) {
+ if (!pDispInfo->SetText(columnIndex++, cdrom->VolumeLabel))
+ {
+ daDebugOut((DEB_ITRACE, "SetText failed\n"));
+ }
+ } else {
+
+ columnIndex++;
+
+ }
+
+ //
+ // column: capacity in MB
+ //
+
+ if (cdrom->TypeName && cdrom->TotalSpaceInMB) {
+ wsprintf(wszTemp, TEXT("%lu%s"), cdrom->TotalSpaceInMB, mbBuffer);
+
+ if (!pDispInfo->SetText(columnIndex++, wszTemp))
+ {
+ daDebugOut((DEB_ITRACE, "SetText failed\n"));
+ }
+
+ //
+ // column: free space in MB
+ //
+
+ wsprintf(wszTemp, TEXT("0 %s"), mbBuffer);
+
+ if (!pDispInfo->SetText(columnIndex++, wszTemp))
+ {
+ daDebugOut((DEB_ITRACE, "SetText failed\n"));
+ }
+
+ //
+ // column: % free space
+ //
+
+ if (!pDispInfo->SetText(columnIndex++, TEXT("0 %")))
+ {
+ daDebugOut((DEB_ITRACE, "SetText failed\n"));
+ }
+
+ } else {
+
+ columnIndex += 3;
+
+ }
+
+
+ //
+ // column: format (file system type)
+ //
+
+ if (cdrom->TypeName) {
+ if (!pDispInfo->SetText(columnIndex++, cdrom->TypeName))
+ {
+ daDebugOut((DEB_ITRACE, "SetText failed\n"));
+ }
+ } else {
+
+ columnIndex++;
+
+ }
+
+ //
+ // column: fault tolerant?
+ //
+
+ LoadString(
+ g_hInstance,
+ IDS_FT_NO,
+ wszTemp,
+ ARRAYLEN(wszTemp)
+ );
+
+ if (!pDispInfo->SetText(columnIndex++, wszTemp))
+ {
+ daDebugOut((DEB_ITRACE, "SetText failed\n"));
+ }
+
+ //
+ // column: volume type
+ //
+
+ LoadString(
+ g_hInstance,
+ IDS_VOLTYPE_SIMPLE,
+ wszTemp,
+ ARRAYLEN(wszTemp)
+ );
+
+ if (!pDispInfo->SetText(columnIndex++, wszTemp))
+ {
+ daDebugOut((DEB_ITRACE, "SetText failed\n"));
+ }
+
+ //
+ // column: fault tolerance overhead in MB
+ //
+
+ if (!pDispInfo->SetText(columnIndex++, TEXT("")))
+ {
+ daDebugOut((DEB_ITRACE, "SetText failed\n"));
+ }
+
+ //
+ // column: status
+ //
+
+ LoadString(
+ g_hInstance,
+ IDS_FTSTATUS_NONE,
+ wszTemp,
+ ARRAYLEN(wszTemp)
+ );
+
+ if (!pDispInfo->SetText(columnIndex++, wszTemp))
+ {
+ daDebugOut((DEB_ITRACE, "SetText failed\n"));
+ }
+
+ //
+ // Insert the data into the listview
+ //
+
+ LV_ITEM lvi;
+ lvi.iItem = item;
+ lvi.iSubItem = 0;
+ lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
+ lvi.state = 0;
+ lvi.stateMask = 0;
+ lvi.cchTextMax = 0; // ignored when setting data
+ lvi.pszText = LPSTR_TEXTCALLBACK;
+ lvi.iImage = IconIndexSmall[I_CDROM];
+ lvi.lParam = (LPARAM)pDispInfo;
+
+ if (ListView_InsertItem(g_hwndLV, &lvi) == -1)
+ {
+ //BUGBUG: why would it fail?
+ delete pDispInfo;
+ return;
+ }
+
+ for (int iSubItem = 1; iSubItem < g_cColumns; iSubItem++)
+ {
+ ListView_SetItemText(
+ g_hwndLV,
+ item,
+ iSubItem,
+ LPSTR_TEXTCALLBACK);
+ }
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: FillListView
+//
+// Synopsis: Fill the listview with data from internal state
+//
+// Arguments:
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+FillListView(
+ IN BOOL bSetDefaultSelection
+ )
+{
+ WCHAR DriveLetter;
+ int item;
+
+ //
+ // Save the current selection, if one exists
+ //
+
+ WCHAR saveDriveLetter = NO_DRIVE_LETTER_EVER;
+ int itemOld = ListView_GetNextItem(g_hwndLV, -1, LVNI_SELECTED);
+ if (-1 != itemOld)
+ {
+ saveDriveLetter = GetListviewDriveLetter(itemOld);
+ }
+
+ //
+ // Get rid of everything
+ //
+
+ ListView_DeleteAllItems(g_hwndLV);
+
+ //
+ // Next, using the data available to us, fill the listview
+ //
+
+ daDebugOut((DEB_ITRACE, "Adding: "));
+
+ for (item = 0, DriveLetter = L'C';
+ DriveLetter <= L'Z';
+ ++DriveLetter)
+ {
+ if (SignificantDriveLetter(DriveLetter))
+ {
+ daDebugOut((DEB_ITRACE | DEB_NOCOMPNAME, "%wc:, ", DriveLetter));
+ AddVolumeToListview(item++, DriveLetter);
+ }
+ else
+ {
+ // might be a CD-ROM, unused or a network connection.
+ if (!DriveLetterIsAvailable(DriveLetter))
+ {
+ // it is in use. See if it's a CD-ROM.
+ if (CdRomUsingDriveLetter(DriveLetter))
+ {
+ daDebugOut((DEB_ITRACE | DEB_NOCOMPNAME, "%wc:, ", DriveLetter));
+ AddCdRomToListview(item++, DriveLetter);
+ }
+ }
+ }
+ }
+
+ daDebugOut((DEB_ITRACE | DEB_NOCOMPNAME, "\n"));
+
+ if (bSetDefaultSelection)
+ {
+ if (ListView_GetItemCount(g_hwndLV) > 0)
+ {
+ int itemNew = 0;
+ BOOL bChangeDiskViewSelection = FALSE;
+
+ // give the first element the focus and selection, by default
+
+ g_SettingListviewState = TRUE; // no notifications
+
+ if (NO_DRIVE_LETTER_EVER != saveDriveLetter)
+ {
+ itemNew = GetLVIndexFromDriveLetter(saveDriveLetter);
+ if (-1 == itemNew)
+ {
+ bChangeDiskViewSelection = TRUE;
+ itemNew = 0;
+ }
+ }
+
+ // Give the item both the focus *and* the selection, since we only
+ // allow a single listview selection
+
+ ListView_SetItemState(
+ g_hwndLV,
+ itemNew,
+ LVIS_FOCUSED | LVIS_SELECTED,
+ LVIS_FOCUSED | LVIS_SELECTED);
+ ListView_EnsureVisible(g_hwndLV, itemNew, FALSE);
+
+ g_SettingListviewState = FALSE; // accept notifications
+
+ if (bChangeDiskViewSelection)
+ {
+ DeselectSelectedDiskViewRegions(); // visual selection in disk view
+ DeselectSelectedRegions(); // actual selection state
+
+ SetVolumeSelection(itemNew, TRUE); // reflect in disks view
+ }
+ }
+ }
+ else
+ {
+ DeselectSelectedDiskViewRegions(); // visual selection in disk view
+ DeselectSelectedRegions(); // actual selection state
+ }
+}
diff --git a/private/utils/windisk/src/fill.hxx b/private/utils/windisk/src/fill.hxx
new file mode 100644
index 000000000..d52aa58d5
--- /dev/null
+++ b/private/utils/windisk/src/fill.hxx
@@ -0,0 +1,24 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: fill.hxx
+//
+// Contents: Declarations for routines to fill the volumes view with data
+//
+// History: 20-May-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __FILL_HXX__
+#define __FILL_HXX__
+
+//////////////////////////////////////////////////////////////////////////////
+
+VOID
+FillListView(
+ IN BOOL bSetDefaultSelection
+ );
+
+#endif // __FILL_HXX__
diff --git a/private/utils/windisk/src/fmifs.cxx b/private/utils/windisk/src/fmifs.cxx
new file mode 100644
index 000000000..b5ee60061
--- /dev/null
+++ b/private/utils/windisk/src/fmifs.cxx
@@ -0,0 +1,644 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: fmifs.cxx
+//
+// Contents: Routines that work with fmifs.dll
+//
+// History: 7-Jan-94 BruceFo Adapted from BobRi's Daytona code
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include "drives.hxx"
+#include "fmifs.hxx"
+#include "nt.hxx"
+#include "format.hxx"
+#include "windisk.hxx"
+
+//
+// Externals needed for IFS Dll support (format and label)
+//
+
+
+TCHAR szFmifsDll[] = TEXT("fmifs.dll");
+HMODULE g_hFmifsDll = NULL;
+
+PFMIFS_FORMAT_ROUTINE lpfnFormat = NULL;
+PFMIFS_CHKDSK_ROUTINE lpfnChkdsk = NULL;
+PFMIFS_SETLABEL_ROUTINE lpfnSetLabel = NULL;
+
+#if defined( DBLSPACE_ENABLED )
+
+PFMIFS_DOUBLESPACE_CREATE_ROUTINE DblSpaceCreateRoutine = NULL;
+PFMIFS_DOUBLESPACE_MOUNT_ROUTINE DblSpaceMountRoutine = NULL;
+PFMIFS_DOUBLESPACE_DELETE_ROUTINE DblSpaceDeleteRoutine = NULL;
+PFMIFS_DOUBLESPACE_DISMOUNT_ROUTINE DblSpaceDismountRoutine = NULL;
+PFMIFS_DOUBLESPACE_QUERY_INFO_ROUTINE DblSpaceQueryInfoRoutine = NULL;
+
+BOOL g_DoubleSpaceSupported = TRUE;
+BOOL g_IsFullDoubleSpace = FALSE;
+
+#endif // DBLSPACE_ENABLED
+
+BOOL g_ChkdskSupported = TRUE;
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: LoadFmifs
+//
+// Synopsis: If the fmifs DLL is not already loaded, then load it.
+//
+// Arguments: none
+//
+// Returns: TRUE if the load was successful, FALSE otherwise
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+BOOL
+LoadFmifs(
+ VOID
+ )
+{
+ if (NULL == g_hFmifsDll)
+ {
+ SetCursor(g_hCurWait);
+ g_hFmifsDll = LoadLibrary(szFmifsDll);
+ SetCursor(g_hCurNormal);
+
+ if (NULL == g_hFmifsDll)
+ {
+ daDebugOut((DEB_ERROR,"Couldn't load %ws: error 0x%x\n",
+ szFmifsDll,
+ GetLastError()
+ ));
+
+ ErrorDialog(MSG_NOFMIFS);
+ return FALSE;
+ }
+ else
+ {
+#if defined( DBLSPACE_ENABLED )
+ g_DoubleSpaceSupported = TRUE;
+ g_IsFullDoubleSpace = FALSE;
+#endif // DBLSPACE_ENABLED
+
+ g_ChkdskSupported = TRUE;
+
+ daDebugOut((DEB_ITRACE,"Loaded %ws: handle 0x%x\n",
+ szFmifsDll,
+ g_hFmifsDll));
+
+ lpfnFormat = (PFMIFS_FORMAT_ROUTINE)
+ GetProcAddress(g_hFmifsDll, "Format");
+
+ if (!lpfnFormat)
+ {
+ daDebugOut((DEB_ERROR,
+ "Couldn't get 'Format', 0x%x, 0x%x\n",
+ lpfnFormat,
+ GetLastError()));
+ }
+
+ lpfnSetLabel = (PFMIFS_SETLABEL_ROUTINE)
+ GetProcAddress(g_hFmifsDll, "SetLabel");
+
+ if (!lpfnSetLabel)
+ {
+ daDebugOut((DEB_ERROR,
+ "Couldn't get 'SetLabel', 0x%x, 0x%x\n",
+ lpfnSetLabel,
+ GetLastError()));
+ }
+
+ if ( !lpfnFormat
+ || !lpfnSetLabel)
+ {
+ //
+ // If we didn't get at least Format and SetLabel, there
+ // is something seriously wrong.
+ //
+
+ FreeLibrary(g_hFmifsDll);
+ g_hFmifsDll = NULL;
+ ErrorDialog(MSG_NOFMIFS);
+ return FALSE;
+ }
+
+ lpfnChkdsk = (PFMIFS_CHKDSK_ROUTINE)
+ GetProcAddress(g_hFmifsDll, "Chkdsk");
+
+ if (!lpfnChkdsk)
+ {
+ daDebugOut((DEB_ERROR,
+ "Couldn't get 'Chkdsk', 0x%x, 0x%x\n",
+ lpfnChkdsk,
+ GetLastError()));
+ }
+
+ if (!lpfnChkdsk)
+ {
+ // Might be 3.1 or Daytona w/o this entrypoint
+
+ g_ChkdskSupported = FALSE;
+ }
+
+#if defined( DBLSPACE_ENABLED )
+
+ DblSpaceMountRoutine = (PFMIFS_DOUBLESPACE_MOUNT_ROUTINE)
+ GetProcAddress(g_hFmifsDll, "DoubleSpaceMount");
+
+ DblSpaceDismountRoutine = (PFMIFS_DOUBLESPACE_DISMOUNT_ROUTINE)
+ GetProcAddress(g_hFmifsDll, "DoubleSpaceDismount");
+
+ DblSpaceQueryInfoRoutine = (PFMIFS_DOUBLESPACE_QUERY_INFO_ROUTINE)
+ GetProcAddress(g_hFmifsDll, "FmifsQueryDriveInformation");
+
+ if ( !DblSpaceMountRoutine
+ || !DblSpaceDismountRoutine
+ || !DblSpaceQueryInfoRoutine)
+ {
+ // didn't get all of the DoubleSpace support routines
+ // Allow format and label, just don't do DoubleSpace
+
+ g_DoubleSpaceSupported = FALSE;
+ }
+
+ DblSpaceCreateRoutine = (PFMIFS_DOUBLESPACE_CREATE_ROUTINE)
+ GetProcAddress(g_hFmifsDll, "DoubleSpaceCreate");
+
+ DblSpaceDeleteRoutine = (PFMIFS_DOUBLESPACE_DELETE_ROUTINE)
+ GetProcAddress(g_hFmifsDll, "DoubleSpaceDelete");
+
+ if (DblSpaceCreateRoutine && DblSpaceDeleteRoutine)
+ {
+ // Everything is there for read/write double space support.
+ // This will change certain dialogs to allow creation and
+ // deletion of double space volumes.
+
+ g_IsFullDoubleSpace = TRUE;
+ }
+
+#endif // DBLSPACE_ENABLED
+
+ }
+ }
+ return TRUE;
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: UnloadFmifs
+//
+// Synopsis: If the fmifs DLL is loaded, then unload it.
+//
+// Arguments: none
+//
+// Returns: TRUE if the unload was successful, FALSE otherwise
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+VOID
+UnloadFmifs(
+ VOID
+ )
+{
+ if (NULL != g_hFmifsDll)
+ {
+ FreeLibrary(g_hFmifsDll);
+
+ g_hFmifsDll = NULL;
+
+ lpfnFormat = NULL;
+ lpfnChkdsk = NULL;
+ lpfnSetLabel = NULL;
+
+#if defined( DBLSPACE_ENABLED )
+
+ DblSpaceDismountRoutine = NULL;
+ DblSpaceMountRoutine = NULL;
+ DblSpaceCreateRoutine = NULL;
+ DblSpaceDeleteRoutine = NULL;
+ DblSpaceQueryInfoRoutine = NULL;
+
+#endif // DBLSPACE_ENABLED
+ }
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: EnsureSameDevice
+//
+// Synopsis: If a disk is removable, check that it is the same one we
+// thought it was.
+//
+// Arguments: [RegionDescriptor] -- region of interest
+//
+// Returns:
+//
+// History: 9-Feb-94 BruceFo Taken from Daytona
+//
+//--------------------------------------------------------------------------
+
+VOID
+EnsureSameDevice(
+ PREGION_DESCRIPTOR RegionDescriptor
+ )
+{
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(RegionDescriptor);
+
+ if (IsDiskRemovable[RegionDescriptor->Disk])
+ {
+ PWSTR tempName;
+ PWSTR tempLabel;
+ PWSTR typeName;
+ PWSTR volumeLabel;
+ ULONG diskSize;
+ BOOL volumeChanged = FALSE;
+
+ if (!RegionDescriptor->PartitionNumber)
+ {
+ // TODO: something has changed where the code gets to this
+ // point with an incorrect partition number - This happens
+ // when a partition is deleted and added to removable media.
+ // For removable media the partition number is always 1.
+
+ RegionDescriptor->PartitionNumber = 1;
+ }
+
+ if (GetVolumeTypeAndSize(RegionDescriptor->Disk,
+ RegionDescriptor->PartitionNumber,
+ &volumeLabel,
+ &typeName,
+ &diskSize))
+ {
+ // Verify that this is still the same device.
+
+ if (NULL != typeName)
+ {
+ if (0 == lstrcmpi(typeName, L"raw"))
+ {
+ Free(typeName);
+ typeName = (PWSTR)Malloc((wcslen(wszUnknown) + 1) * sizeof(WCHAR));
+ lstrcpy(typeName, wszUnknown);
+ }
+ }
+ else
+ {
+ typeName = (PWSTR)Malloc((wcslen(wszUnknown) + 1) * sizeof(WCHAR));
+ lstrcpy(typeName, wszUnknown);
+ }
+
+ if (regionData)
+ {
+ if (regionData->VolumeLabel)
+ {
+ if (0 != lstrcmp(regionData->VolumeLabel, volumeLabel))
+ {
+ volumeChanged = TRUE;
+ }
+ }
+ if (NULL != regionData->TypeName)
+ {
+ // It is possible the region has no type or is of type
+ // "Unformatted". This says it is ok to format
+
+ if (L'\0' == *regionData->TypeName)
+ {
+ if (0 != lstrcmp(regionData->TypeName, wszUnformatted))
+ {
+ // It has a type and it isn't unformatted - see if
+ // it is the same as before.
+
+ if (0 != lstrcmp(regionData->TypeName, typeName))
+ {
+ volumeChanged = TRUE;
+ }
+ }
+ }
+ }
+ }
+ Free(volumeLabel);
+ Free(typeName);
+
+ if (DiskArray[RegionDescriptor->Disk]->DiskSizeMB != diskSize)
+ {
+ volumeChanged = TRUE;
+ }
+ }
+ if (volumeChanged)
+ {
+ ErrorDialog(MSG_VOLUME_CHANGED);
+
+ // since the user was told the volume changed,
+ // update the display.
+
+ SetCursor(g_hCurWait);
+ if (GetVolumeTypeAndSize(RegionDescriptor->Disk,
+ RegionDescriptor->PartitionNumber,
+ &tempLabel,
+ &tempName,
+ &diskSize) == OK_STATUS)
+ {
+ Free(typeName);
+ typeName = tempName;
+ Free(volumeLabel);
+ volumeLabel = tempLabel;
+ }
+ if (regionData->VolumeLabel)
+ {
+ Free(regionData->VolumeLabel);
+ }
+ regionData->VolumeLabel = volumeLabel;
+ if (regionData->TypeName)
+ {
+ Free(regionData->TypeName);
+ }
+ regionData->TypeName = typeName;
+ SetCursor(g_hCurNormal);
+ TotalRedrawAndRepaint();
+ }
+ else
+ {
+ if (volumeLabel)
+ {
+ Free(volumeLabel);
+ }
+ if (typeName)
+ {
+ Free(typeName);
+ }
+ }
+ }
+}
+
+#if defined( DBLSPACE_ENABLED )
+
+ULONG MountDismountResult;
+#define MOUNT_DISMOUNT_SUCCESS 0
+
+BOOLEAN
+FmIfsMountDismountCallback(
+ IN FMIFS_PACKET_TYPE PacketType,
+ IN DWORD PacketLength,
+ IN PVOID PacketData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine gets callbacks from fmifs.dll regarding
+ progress and status of the ongoing format or doublespace
+
+Arguments:
+
+ [PacketType] -- an fmifs packet type
+ [PacketLength] -- length of the packet data
+ [PacketData] -- data associated with the packet
+
+Return Value:
+
+ TRUE if the fmifs activity should continue, FALSE if the
+ activity should halt immediately. Thus, we return FALSE if
+ the user has hit "cancel" and we wish fmifs to clean up and
+ return from the Format() entrypoint call.
+
+--*/
+
+{
+#if defined( DBLSPACE_ENABLED )
+ switch (PacketType)
+ {
+ case FmIfsDblspaceMounted:
+ MountDismountResult = MOUNT_DISMOUNT_SUCCESS;
+ break;
+ }
+#endif // DBLSPACE_ENABLED
+ return TRUE;
+}
+
+DWORD WINAPI
+FmIfsCreateDblspace(
+ IN LPVOID ThreadParameter
+ )
+
+/*++
+
+Routine Description:
+
+ This routine converts the strings in the formatParams structure
+ and calls the fmifs routines to perform the double space create.
+
+ It assumes it is called by a separate thread and will exit the
+ thread on completion of the create.
+
+Arguments:
+
+ ThreadParameter - a pointer to the FORMAT_PARAMS structure
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PFORMAT_PARAMS formatParams = (PFORMAT_PARAMS) ThreadParameter;
+ PPERSISTENT_REGION_DATA regionData;
+ WCHAR letter;
+ WCHAR newDriveName[4],
+ hostDriveName[4];
+
+ // The fmifs interface doesn't allow for a context parameter
+ // therefore the formatparams must be passed through an external.
+
+ ParamsForFormatCallBack = formatParams;
+
+ // set up a unicode drive letter.
+
+ regionData = PERSISTENT_DATA(formatParams->RegionDescriptor);
+
+ hostDriveName[0] = regionData->DriveLetter;
+ hostDriveName[1] = L':';
+ hostDriveName[2] = L'\0';
+
+ // set up the new letter
+
+ newDriveName[1] = L':';
+ newDriveName[2] = L'\0';
+
+ // Choose the first available. BUGBUG: This should come from the dialog
+ // newDriveName[0] = (WCHAR) formatParams->NewLetter;
+
+ for (letter = L'C'; letter <= L'Z'; letter++)
+ {
+ if (DriveLetterIsAvailable(letter))
+ {
+ newDriveName[0] = letter;
+ break;
+ }
+ }
+
+ (*DblSpaceCreateRoutine)(hostDriveName,
+ formatParams->SpaceAvailable * 1024 * 1024,
+ formatParams->Label,
+ newDriveName,
+ &FormatCallback);
+ return 0;
+}
+
+
+ULONG
+FmIfsDismountDblspace(
+ IN WCHAR DriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ Convert the name provided into unicode and call the
+ FmIfs support routine.
+
+Arguments:
+
+ DriveLetter - the drive letter to dismount.
+
+Return Value:
+
+ 0 for success
+
+--*/
+
+{
+ WCHAR driveName[3];
+
+ driveName[0] = DriveLetter;
+ driveName[1] = L':';
+ driveName[2] = L'\0';
+
+ // The only way to communicate with the fmifs callback
+ // is through global externals.
+
+ MountDismountResult = MSG_CANT_DISMOUNT_DBLSPACE;
+
+ (*DblSpaceDismountRoutine)(driveName, &FmIfsMountDismountCallback);
+
+ return MountDismountResult;
+}
+
+
+ULONG
+FmIfsMountDblspace(
+ IN PWSTR FileName,
+ IN WCHAR HostDriveLetter,
+ IN WCHAR NewDriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ Call the FmIfs support routine to mount the DoubleSpace volume.
+
+Arguments:
+
+ FileName - file name (i.e. dblspace.xxx)
+ HostDriveLetter - Drive drive letter containing double space volume
+ NewDriveLetter - Drive letter to be assigned to the volume
+
+Return Value:
+
+ TRUE it worked.
+
+--*/
+
+{
+ WCHAR hostDriveName[3];
+ WCHAR newDriveName[3];
+
+ newDriveName[0] = NewDriveLetter;
+ hostDriveName[0] = HostDriveLetter;
+
+ newDriveName[1] = hostDriveName[1] = L':';
+ newDriveName[2] = hostDriveName[2] = L'\0';
+
+ // The only way to communicate with the fmifs callback
+ // is through global externals.
+
+ MountDismountResult = MSG_CANT_MOUNT_DBLSPACE;
+
+ (*DblSpaceMountRoutine)(hostDriveName,
+ FileName,
+ newDriveName,
+ &FmIfsMountDismountCallback);
+ return MountDismountResult;
+}
+
+
+
+BOOLEAN
+FmIfsQueryInformation(
+ IN PWSTR DosDriveName,
+ OUT PBOOLEAN IsRemovable,
+ OUT PBOOLEAN IsFloppy,
+ OUT PBOOLEAN IsCompressed,
+ OUT PBOOLEAN Error,
+ OUT PWSTR NtDriveName,
+ IN ULONG MaxNtDriveNameLength,
+ OUT PWSTR CvfFileName,
+ IN ULONG MaxCvfFileNameLength,
+ OUT PWSTR HostDriveName,
+ IN ULONG MaxHostDriveNameLength
+ )
+
+/*++
+
+Routine Description:
+
+ Call through the pointer to the routine in the fmifs dll.
+
+Arguments:
+
+ Same as the Fmifs routine in the DLL.
+
+Return Value:
+
+--*/
+
+{
+ if (!DblSpaceQueryInfoRoutine)
+ {
+ return FALSE;
+ }
+
+ return (*DblSpaceQueryInfoRoutine)(DosDriveName,
+ IsRemovable,
+ IsFloppy,
+ IsCompressed,
+ Error,
+ NtDriveName,
+ MaxNtDriveNameLength,
+ CvfFileName,
+ MaxCvfFileNameLength,
+ HostDriveName,
+ MaxHostDriveNameLength);
+}
+
+#endif // DBLSPACE_ENABLED
diff --git a/private/utils/windisk/src/fmifs.hxx b/private/utils/windisk/src/fmifs.hxx
new file mode 100644
index 000000000..8ded9e8c9
--- /dev/null
+++ b/private/utils/windisk/src/fmifs.hxx
@@ -0,0 +1,183 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: fmifs.hxx
+//
+// Contents: Routines that work with fmifs.dll
+//
+// History: 7-Jan-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __FMIFS_HXX__
+#define __FMIFS_HXX__
+
+//////////////////////////////////////////////////////////////////////////////
+
+#define FMT_PROGRESSUPDATE (WM_USER + 0)
+#define FMT_PROGRESSEND (WM_USER + 1)
+#define FMT_PROGRESSCANCEL (WM_USER + 2)
+#define FMT_PROGRESSUNCANCEL (WM_USER + 3)
+
+//////////////////////////////////////////////////////////////////////////////
+
+typedef struct _FORMAT_PARAMS
+{
+ PREGION_DESCRIPTOR RegionDescriptor;
+
+ //
+ // 'AllowCancel' is set by the format invoker to indicate whether
+ // cancelling the operation is allowed.
+ //
+
+ BOOL AllowCancel;
+
+ //
+ // 'Cancel' is set by the UI thread to indicate the user has chosen
+ // to cancel the operation.
+ //
+
+ BOOL Cancel;
+
+ //
+ // 'Cancelled' is set by the formatting thread to indicate a cancel
+ // is in progress, and to ignore all future callback messages.
+ //
+
+ BOOL Cancelled;
+
+ //
+ // 'Result' is set by the formatting thread to the message id
+ // (currently a resource string id) of the error message, for an error
+ // return. On successful formatting, it remains zero.
+ //
+
+ UINT Result;
+
+ //
+ // Window handles set by UI thread and used by both UI and formatting
+ // threads. The formatting thread uses hDlg to send messages; thus the
+ // Windows message queue is used as an IPC mechanism.
+ //
+
+ HWND hdlgProgress;
+
+ //
+ // Values passed to the format setup dialog proc.
+ //
+
+ BOOL QuickAllowed; // whether or not quick format is allowed
+
+ //
+ // IN parameters set by the UI thread for use by the Format routine
+ //
+
+ PWSTR Label;
+ INT FileSystemIndex;
+
+ BOOL QuickFormat;
+
+ //
+ // OUT parameters set by the format routine
+ //
+
+ ULONG TotalSpace;
+ ULONG SpaceAvailable;
+
+#if defined( DBLSPACE_ENABLED )
+ //
+ // Parameters for DoubleSpace
+ //
+
+ BOOL DoubleSpace; // formatting a DoubleSpace volume?
+ PWSTR DblspaceFileName; // host filename for DoubleSpace volume
+#endif // DBLSPACE_ENABLED
+
+} FORMAT_PARAMS, *PFORMAT_PARAMS;
+
+extern PFORMAT_PARAMS ParamsForFormatCallBack;
+
+
+extern PFMIFS_FORMAT_ROUTINE lpfnFormat;
+extern PFMIFS_CHKDSK_ROUTINE lpfnChkdsk;
+extern PFMIFS_SETLABEL_ROUTINE lpfnSetLabel;
+
+#if defined( DBLSPACE_ENABLED )
+
+extern PFMIFS_DOUBLESPACE_CREATE_ROUTINE DblSpaceCreateRoutine;
+extern PFMIFS_DOUBLESPACE_MOUNT_ROUTINE DblSpaceMountRoutine;
+extern PFMIFS_DOUBLESPACE_DELETE_ROUTINE DblSpaceDeleteRoutine;
+extern PFMIFS_DOUBLESPACE_DISMOUNT_ROUTINE DblSpaceDismountRoutine;
+extern PFMIFS_DOUBLESPACE_QUERY_INFO_ROUTINE DblSpaceQueryInfoRoutine;
+
+extern BOOL g_DoubleSpaceSupported;
+extern BOOL g_IsFullDoubleSpace;
+
+#endif // DBLSPACE_ENABLED
+
+extern BOOL g_ChkdskSupported;
+
+BOOL
+LoadFmifs(
+ VOID
+ );
+
+VOID
+UnloadFmifs(
+ VOID
+ );
+
+VOID
+EnsureSameDevice(
+ PREGION_DESCRIPTOR RegionDescriptor
+ );
+
+BOOLEAN
+FmIfsCallback(
+ IN FMIFS_PACKET_TYPE PacketType,
+ IN DWORD PacketLength,
+ IN PVOID PacketData
+ );
+
+BOOLEAN
+FmIfsMountDismountCallback(
+ IN FMIFS_PACKET_TYPE PacketType,
+ IN DWORD PacketLength,
+ IN PVOID PacketData
+ );
+
+DWORD WINAPI
+FmIfsCreateDblspace(
+ IN LPVOID ThreadParameter
+ );
+
+ULONG
+FmIfsDismountDblspace(
+ IN WCHAR DriveLetter
+ );
+
+ULONG
+FmIfsMountDblspace(
+ IN PWSTR FileName,
+ IN WCHAR HostDriveLetter,
+ IN WCHAR NewDriveLetter
+ );
+
+BOOLEAN
+FmIfsQueryInformation(
+ IN PWSTR DosDriveName,
+ OUT PBOOLEAN IsRemovable,
+ OUT PBOOLEAN IsFloppy,
+ OUT PBOOLEAN IsCompressed,
+ OUT PBOOLEAN Error,
+ OUT PWSTR NtDriveName,
+ IN ULONG MaxNtDriveNameLength,
+ OUT PWSTR CvfFileName,
+ IN ULONG MaxCvfFileNameLength,
+ OUT PWSTR HostDriveName,
+ IN ULONG MaxHostDriveNameLength
+ );
+
+#endif // __FMIFS_HXX__
diff --git a/private/utils/windisk/src/format.cxx b/private/utils/windisk/src/format.cxx
new file mode 100644
index 000000000..3e6c12589
--- /dev/null
+++ b/private/utils/windisk/src/format.cxx
@@ -0,0 +1,65 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: format.cxx
+//
+// Contents: Disk Administrator format dialog
+//
+// History: 10-Jun-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include "windisk.hxx"
+#include "ops.hxx"
+#include "shlobj.h"
+#include "shsemip.h"
+
+//+---------------------------------------------------------------------------
+//
+// Function: DoFormat
+//
+// Synopsis: Display and handle the Disk Administrator portion of
+// formatting, i.e., the dialog box that allows users to choose
+// a file system and quick/non-quick.
+//
+// Arguments: [FormatReport] -- TRUE if we want a format report
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DoFormat(
+ IN HWND hwndParent,
+ IN BOOL FormatReport
+ )
+{
+ PREGION_DESCRIPTOR regionDescriptor = &SELECTED_REGION(0);
+ FDASSERT(regionDescriptor);
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(regionDescriptor);
+ FDASSERT(regionData);
+
+ if (DeletionIsAllowed(regionDescriptor) != NO_ERROR)
+ {
+ ErrorDialog(MSG_CANT_FORMAT_WINNT);
+ return;
+ }
+
+ if ('\0' == regionData->DriveLetter)
+ {
+ ErrorDialog(MSG_CANT_FORMAT_NO_LETTER);
+ return;
+ }
+
+ SHFormatDrive(hwndParent, regionData->DriveLetter - 'A',
+ SHFMT_ID_DEFAULT, 0);
+
+ DoRefresh();
+}
diff --git a/private/utils/windisk/src/format.hxx b/private/utils/windisk/src/format.hxx
new file mode 100644
index 000000000..420e2b9f5
--- /dev/null
+++ b/private/utils/windisk/src/format.hxx
@@ -0,0 +1,38 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: format.hxx
+//
+// Contents: Change volume format.
+//
+// History: 14-Jan-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __FORMAT_HXX__
+#define __FORMAT_HXX__
+
+BOOLEAN
+FormatCallback(
+ IN FMIFS_PACKET_TYPE PacketType,
+ IN DWORD PacketLength,
+ IN PVOID PacketData
+ );
+
+BOOL CALLBACK
+FormatProgressDlgProc(
+ IN HWND hDlg,
+ IN UINT uMsg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+VOID
+DoFormat(
+ IN HWND hwndParent,
+ IN BOOL FormatReport
+ );
+
+#endif // __FORMAT_HXX__
diff --git a/private/utils/windisk/src/fs.cxx b/private/utils/windisk/src/fs.cxx
new file mode 100644
index 000000000..380f18733
--- /dev/null
+++ b/private/utils/windisk/src/fs.cxx
@@ -0,0 +1,96 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: fs.cxx
+//
+// Contents: Disk Administrator file system information
+//
+// History: 14-Jan-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include "fs.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+#define MAX_FAT_LABEL 11
+#define MAX_NTFS_LABEL 32
+
+#ifdef SUPPORT_OFS
+#define MAX_OFS_LABEL 32
+#endif // SUPPORT_OFS
+
+//////////////////////////////////////////////////////////////////////////////
+
+// NOTE: DEFAULT_FILE_SYSTEM defined in fs.hxx is an index into this array!
+
+FileSystemInfoType FileSystems[] =
+{
+ {
+ L"FAT", // not localized
+ IDS_LONG_FAT,
+ FS_FAT,
+ DA_FS_FLOPPY_CAPABLE,
+ MAX_FAT_LABEL
+ }
+ ,
+ {
+ L"NTFS", // not localized
+ IDS_LONG_NTFS,
+ FS_NTFS,
+ DA_FS_EXTENDABLE,
+ MAX_NTFS_LABEL
+ }
+#ifdef SUPPORT_OFS
+ ,
+ {
+ L"OFS", // not localized
+ IDS_LONG_OFS,
+ FS_OFS,
+ DA_FS_FLOPPY_CAPABLE | DA_FS_EXTENDABLE,
+ MAX_OFS_LABEL
+ }
+#endif // SUPPORT_OFS
+};
+
+UINT g_NumKnownFileSystems = ARRAYLEN(FileSystems);
+
+//////////////////////////////////////////////////////////////////////////////
+
+//+---------------------------------------------------------------------------
+//
+// Function: FindFileSystemInfo
+//
+// Synopsis: Find information about a file system type based on its name
+//
+// Arguments: [FileSystem] -- name of the file system
+//
+// Returns: pointer to a file system information structure, or NULL
+// on failure
+//
+// History: 14-Jan-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+FileSystemInfoType*
+FindFileSystemInfo(
+ IN PWSTR FileSystem
+ )
+{
+ INT i;
+
+ for (i=0; i<ARRAYLEN(FileSystems); i++)
+ {
+ if (0 == lstrcmp(FileSystem, FileSystems[i].pwszShortName))
+ {
+ return &(FileSystems[i]);
+ }
+ }
+
+ return NULL;
+}
diff --git a/private/utils/windisk/src/fs.hxx b/private/utils/windisk/src/fs.hxx
new file mode 100644
index 000000000..994975805
--- /dev/null
+++ b/private/utils/windisk/src/fs.hxx
@@ -0,0 +1,93 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: fs.hxx
+//
+// Contents: Disk Administrator file system information
+//
+// History: 14-Jan-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __FS_HXX__
+#define __FS_HXX__
+
+#define DEFAULT_FILE_SYSTEM 1 // NTFS: 0-based index into FileSystems[]
+
+//
+// FileSystemInfoType:
+//
+// FileSystemInfoType encapsulates all interesting file system
+// information for the Disk Administrator. The data:
+//
+// pwszShortName: A short name for the file system, e.g. ``FAT''
+// (not localized).
+//
+// idsDescriptive: Resource table string id of a descriptive name for the
+// file system, e.g. ``FAT (File Allocation Table: DOS, OS/2, NT)''
+//
+// fCapabilities: A bitmask of capabilities:
+// DA_FS_NONE: no extra capabilities
+// DA_FS_FLOPPY_CAPABLE: if set, floppies can be formatted with
+// this file system. Note that NT file system u*.sys code
+// determines during a ``format'' operation if the user is
+// trying to format a floppy. If so, and this file system
+// doesn't support floppies, then a message is displayed,
+// and the format operation fails. The messages displayed
+// look a bit weird, given their order.
+// DA_FS_EXTENDABLE: if set, a volume can be extended by adding
+// partitions to make a multi-partition volume. This will be
+// set by OFS and NTFS.
+//
+// cMaxLabelLen: Maximum length of a volume label for the file system.
+// If -1, then there is no maximum.
+//
+// propPages: Information about property sheet pages specific to
+// this format.
+//
+
+//
+// Note: The below enum must be in ssync with the array in fs.cxx.
+// FS_UNKOWN must begin at -1 so that real file system info begins
+// at index 0.
+//
+
+enum FILE_SYSTEM
+{
+ FS_UNKNOWN = -1,
+ FS_FAT,
+ FS_NTFS,
+#ifdef SUPPORT_OFS
+ FS_OFS,
+#endif // SUPPORT_OFS
+ FS_CDFS
+};
+
+#define DA_FS_NONE 0x0
+#define DA_FS_FLOPPY_CAPABLE 0x1
+#define DA_FS_EXTENDABLE 0x2
+
+typedef struct _FileSystemInfoType
+{
+ PWSTR pwszShortName; // file system name isn't localized
+ UINT idsDescriptive; //resource ID of string
+ FILE_SYSTEM FileSystemType;
+ ULONG fCapabilities;
+ INT cMaxLabelLen;
+} FileSystemInfoType;
+
+//////////////////////////////////////////////////////////////////////////////
+
+extern FileSystemInfoType FileSystems[];
+extern UINT g_NumKnownFileSystems;
+
+//////////////////////////////////////////////////////////////////////////////
+
+FileSystemInfoType*
+FindFileSystemInfo(
+ IN PWSTR FileSystem
+ );
+
+#endif // __FS_HXX__
diff --git a/private/utils/windisk/src/ft.cxx b/private/utils/windisk/src/ft.cxx
new file mode 100644
index 000000000..20649e999
--- /dev/null
+++ b/private/utils/windisk/src/ft.cxx
@@ -0,0 +1,1685 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: ft.cxx
+//
+// Contents: This module contains FT support routines for Disk Administrator
+//
+// History: 15-Nov-91 TedM Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include "ft.hxx"
+#include "nt.hxx"
+#include "ntlow.hxx"
+#include "windisk.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+//
+// This variable heads a linked list of ft object sets.
+//
+PFT_OBJECT_SET FtObjectList = NULL;
+
+//
+// Array of pointers to registry disk descriptors that we
+// remember, ie, save for later use when a disk is not physically
+// present on the machine.
+//
+
+PDISK_DESCRIPTION* RememberedDiskArray;
+ULONG RememberedDiskCount;
+
+PULONG DiskHadRegistryEntry;
+
+
+#define MAX_FT_SET_TYPES 4
+
+ULONG OrdinalToAllocate[MAX_FT_SET_TYPES] =
+{
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+ULONG
+FdpDetermineDiskDescriptionSize(
+ PDISKSTATE DiskState
+ );
+
+ULONG
+FdpConstructDiskDescription(
+ IN PDISKSTATE DiskState,
+ OUT PDISK_DESCRIPTION DiskDescription
+ );
+
+VOID
+FdpRememberDisk(
+ IN PDISK_DESCRIPTION DiskDescription
+ );
+
+VOID
+FdpInitializeMirrors(
+ VOID
+ );
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+VOID
+MaintainOrdinalTables(
+ IN FT_TYPE FtType,
+ IN ULONG Ordinal
+ )
+
+/*++
+
+Routine Description:
+
+ Maintain the minimum and maximum Ordinal value recorded.
+
+Arguments:
+
+ FtType - the type of the FT set.
+ Ordinal - the in use FtGroup (or ordinal) number
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ if (Ordinal > OrdinalToAllocate[FtType])
+ {
+ OrdinalToAllocate[FtType] = Ordinal;
+ }
+}
+
+
+
+DWORD
+FdftNextOrdinal(
+ IN FT_TYPE FtType
+ )
+
+/*++
+
+Routine Description:
+
+ Allocate a number that will uniquely identify the FT set
+ from other sets of the same type. This number must be unique
+ from any given or used by FT sets of the same type due to
+ requirements of FT dynamic partitioning.
+
+Arguments:
+
+ FtType - The type of the FT set.
+
+Return Value:
+
+ The FtGroup number -- called an "ordinal" in the internal
+ structures.
+
+--*/
+
+{
+ DWORD ordinal;
+ PFT_OBJECT_SET ftSet;
+ BOOL looping;
+
+ // The Ordinal value is going to be used as an FtGroup number
+ // FtGroups are USHORTs so don't wrap on the Ordinal. Try
+ // to keep the next ordinal in the largest opening range, that
+ // is if the minimum found is > half way through a USHORT, start
+ // the ordinals over at zero.
+
+ if (OrdinalToAllocate[FtType] > 0x7FFE)
+ {
+ OrdinalToAllocate[FtType] = 0;
+ }
+
+ ordinal = OrdinalToAllocate[FtType];
+ ++ordinal;
+
+ do
+ {
+ looping = FALSE;
+ ftSet = FtObjectList;
+ while (NULL != ftSet)
+ {
+ if ((ftSet->Type == FtType) && (ftSet->Ordinal == ordinal))
+ {
+ ordinal++;
+ looping = TRUE;
+ break;
+ }
+ ftSet = ftSet->Next;
+ }
+ } while (looping);
+
+ OrdinalToAllocate[FtType] = (ordinal + 1);
+ return ordinal;
+}
+
+
+
+VOID
+FdftCreateFtObjectSet(
+ IN FT_TYPE FtType,
+ IN PREGION_DESCRIPTOR* RegionArray,
+ IN DWORD RegionCount,
+ IN FT_SET_STATUS FtStatus
+ )
+
+/*++
+
+Routine Description:
+
+ Create the FT set structures for the give collection of
+ region pointers.
+
+Arguments:
+
+ FtType
+ Regions
+ RegionCount
+ Status
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ DWORD regionIndex;
+ PFT_OBJECT_SET ftSet;
+ PFT_OBJECT ftObject;
+
+ ftSet = (PFT_OBJECT_SET)Malloc(sizeof(FT_OBJECT_SET));
+
+ //
+ // Figure out an ordinal for the new object set.
+ //
+
+ ftSet->Ordinal = FdftNextOrdinal(FtType);
+ ftSet->Type = FtType;
+ ftSet->Members = NULL;
+ ftSet->Member0 = NULL;
+ ftSet->Status = FtStatus;
+
+ //
+ // Link the new object set into the list.
+
+ ftSet->Next = FtObjectList;
+ FtObjectList = ftSet;
+
+ //
+ // For each region in the set, associate the ft info with it.
+ //
+
+ for (regionIndex=0; regionIndex<RegionCount; regionIndex++)
+ {
+ ftObject = (PFT_OBJECT)Malloc(sizeof(FT_OBJECT));
+
+ //
+ // If this is a creation of a stripe set with parity, then
+ // we must mark the 0th item 'Initializing' instead of 'Healthy'.
+ //
+
+ if ((regionIndex == 0)
+ && (FtType == StripeWithParity)
+ && (FtStatus == FtSetNewNeedsInitialization))
+ {
+ ftObject->State = Initializing;
+ }
+ else
+ {
+ ftObject->State = Healthy;
+ }
+
+ if (0 == regionIndex)
+ {
+ ftSet->Member0 = ftObject;
+ }
+
+ ftObject->Set = ftSet;
+ ftObject->MemberIndex = regionIndex;
+ ftObject->Next = ftSet->Members;
+ ftSet->Members = ftObject;
+
+ SET_FT_OBJECT(RegionArray[regionIndex], ftObject);
+ }
+}
+
+
+
+BOOL
+FdftUpdateFtObjectSet(
+ IN PFT_OBJECT_SET FtSet,
+ IN FT_SET_STATUS SetState
+ )
+
+/*++
+
+Routine Description:
+
+ Given an FT set, go back to the registry information and
+ update the state of the members with the state in the registry.
+
+ NOTE: The following condition may exist. It is possible for
+ the FtDisk driver to return that the set is in an initializing
+ or regenerating state and not have this fact reflected in the
+ registry. This can happen when the system has crashed and
+ on restart the FtDisk driver started the regeneration of the
+ check data (parity).
+
+Arguments:
+
+ FtSet - the set to update.
+
+Return Value:
+
+ TRUE if the set state provided has a strong likelyhood of being correct
+ FALSE if the NOTE condition above is occuring.
+
+--*/
+
+{
+ BOOLEAN allHealthy = TRUE;
+ PFT_OBJECT ftObject;
+ PDISK_REGISTRY diskRegistry;
+ PDISK_PARTITION partition;
+ PDISK_DESCRIPTION diskDescription;
+ DWORD ec;
+ ULONG diskIndex,
+ partitionIndex;
+
+ ec = MyDiskRegistryGet(&diskRegistry);
+ if (ec != NO_ERROR)
+ {
+ // No registry information.
+
+ return TRUE;
+ }
+
+ diskDescription = diskRegistry->Disks;
+ for (diskIndex=0; diskIndex<diskRegistry->NumberOfDisks; diskIndex++)
+ {
+ for (partitionIndex=0;
+ partitionIndex < diskDescription->NumberOfPartitions;
+ partitionIndex++)
+ {
+ partition = &diskDescription->Partitions[partitionIndex];
+ if ( (partition->FtType == FtSet->Type)
+ && (partition->FtGroup == (USHORT) FtSet->Ordinal))
+ {
+ // Have a match for a partition within this set.
+ // Find the region descriptor for this partition and
+ // update its state accordingly.
+
+ for (ftObject = FtSet->Members;
+ NULL != ftObject;
+ ftObject = ftObject->Next)
+ {
+ if (ftObject->MemberIndex == (ULONG) partition->FtMember)
+ {
+ ftObject->State = partition->FtState;
+ break;
+ }
+
+ if (partition->FtState != Healthy)
+ {
+ allHealthy = FALSE;
+ }
+ }
+ }
+ }
+
+ diskDescription = (PDISK_DESCRIPTION)&diskDescription->Partitions[diskDescription->NumberOfPartitions];
+ }
+
+ Free(diskRegistry);
+
+ if ((allHealthy) && (SetState != FtSetHealthy))
+ {
+ // This is a condition where the system must be
+ // updating the check data for redundant sets.
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+VOID
+FdftDeleteFtObjectSet(
+ IN PFT_OBJECT_SET FtSet,
+ IN BOOL OffLineDisksOnly
+ )
+
+/*++
+
+Routine Description:
+
+ Delete an ft set, or rather its internal representation as a linked
+ list of ft member structures.
+
+Arguments:
+
+ FtSet - supplies pointer to ft set structure for set to delete.
+
+ OffLineDisksOnly - if TRUE, then do not delete the set but instead
+ scan remembered disks for members of the set and remove such members.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PFT_OBJECT ftObject = FtSet->Members;
+ PFT_OBJECT nextFtObject;
+ PFT_OBJECT_SET ftSetTemp;
+ PDISK_DESCRIPTION diskDescription;
+ PDISK_PARTITION diskPartition;
+ ULONG partitionCount;
+ ULONG size;
+ ULONG i;
+ ULONG j;
+
+ //
+ // Locate any members of the ft set on remembered disks and
+ // remove the entries for such partitions.
+ //
+
+ for (i=0; i<RememberedDiskCount; i++)
+ {
+ diskDescription = RememberedDiskArray[i];
+ partitionCount = diskDescription->NumberOfPartitions;
+
+ for (j=0; j<partitionCount; j++)
+ {
+ diskPartition = &diskDescription->Partitions[j];
+
+ if ( (diskPartition->FtType == FtSet->Type)
+ && (diskPartition->FtGroup == (USHORT)FtSet->Ordinal))
+ {
+ //
+ // Found a member of the ft set being deleted on a
+ // remembered disk. Remove the partition from the
+ // remembered disk.
+ //
+
+ RtlMoveMemory( diskPartition,
+ diskPartition+1,
+ (partitionCount - j - 1) * sizeof(DISK_PARTITION)
+ );
+
+ partitionCount--;
+ j--;
+ }
+ }
+
+ if (partitionCount != diskDescription->NumberOfPartitions)
+ {
+ diskDescription->NumberOfPartitions = (USHORT)partitionCount;
+
+ size = sizeof(DISK_DESCRIPTION);
+ if (partitionCount > 1)
+ {
+ size += (partitionCount - 1) * sizeof(DISK_PARTITION);
+ }
+ RememberedDiskArray[i] = (PDISK_DESCRIPTION)Realloc(RememberedDiskArray[i], size);
+ }
+ }
+
+ if (OffLineDisksOnly)
+ {
+ return;
+ }
+
+ //
+ // First, free all members of the set
+ //
+
+ while (NULL != ftObject)
+ {
+ nextFtObject = ftObject->Next;
+ Free(ftObject);
+ ftObject = nextFtObject;
+ }
+
+ //
+ // now, remove the set from the linked list of sets.
+ //
+
+ if (FtObjectList == FtSet)
+ {
+ FtObjectList = FtSet->Next;
+ }
+ else
+ {
+ ftSetTemp = FtObjectList;
+ while (1)
+ {
+ FDASSERT(ftSetTemp);
+ if (ftSetTemp == NULL)
+ {
+ break;
+ }
+ if (ftSetTemp->Next == FtSet)
+ {
+ ftSetTemp->Next = FtSet->Next;
+ break;
+ }
+ ftSetTemp = ftSetTemp->Next;
+ }
+ }
+ Free(FtSet);
+}
+
+VOID
+FdftExtendFtObjectSet(
+ IN OUT PFT_OBJECT_SET FtSet,
+ IN OUT PREGION_DESCRIPTOR* RegionArray,
+ IN DWORD RegionCount
+ )
+/*++
+
+Routine Description:
+
+ This function adds regions to an existing FT-set.
+
+Arguments:
+
+ FtSet -- Supplies the set to extend.
+ RegionArray -- Supplies the regions to add to the set. Note
+ that these regions are updated with the FT
+ information.
+ RegionCount -- Supplies the number of regions to add.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PFT_OBJECT ftObject;
+ DWORD i;
+ DWORD startingIndex;
+
+ // Determine the starting member index for the new regions.
+ // It is the greatest of the existing member indices plus one.
+ //
+ startingIndex = 0;
+
+ for (ftObject = FtSet->Members;
+ NULL != ftObject;
+ ftObject = ftObject->Next)
+ {
+ if (ftObject->MemberIndex > startingIndex)
+ {
+ startingIndex = ftObject->MemberIndex;
+ }
+ }
+
+ startingIndex++;
+
+ // Associate the ft-set's information with each of the
+ // new regions.
+ //
+ for (i = 0; i < RegionCount; i++)
+ {
+ ftObject = (PFT_OBJECT)Malloc(sizeof(FT_OBJECT));
+
+ ftObject->Set = FtSet;
+ ftObject->MemberIndex = startingIndex + i;
+ ftObject->Next = FtSet->Members;
+ ftObject->State = Healthy;
+ FtSet->Members = ftObject;
+
+ SET_FT_OBJECT(RegionArray[i], ftObject);
+ }
+
+ FtSet->Status = FtSetExtended;
+}
+
+
+ULONG
+ActualPartitionCount(
+ IN PDISKSTATE DiskState
+ )
+
+/*++
+
+Routine Description:
+
+ Given a disk, this routine counts the number of partitions on it.
+ The number of partitions is the number of regions that appear in
+ the NT name space (ie, the maximum value of <x> in
+ \device\harddiskn\partition<x>).
+
+Arguments:
+
+ DiskState - descriptor for the disk in question.
+
+Return Value:
+
+ Partition count (may be 0).
+
+--*/
+
+{
+ ULONG i;
+ ULONG partitionCount = 0;
+ PREGION_DESCRIPTOR region;
+
+ for (i=0; i<DiskState->RegionCount; i++)
+ {
+ region = &DiskState->RegionArray[i];
+ if ((region->SysID != PARTITION_ENTRY_UNUSED)
+ && !IsExtended(region->SysID)
+ && IsRecognizedPartition(region->SysID))
+ {
+ partitionCount++;
+ }
+ }
+ return partitionCount;
+}
+
+
+PDISKSTATE
+LookUpDiskBySignature(
+ IN ULONG Signature
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will look through the disk descriptors created by the
+ fdisk back end looking for a disk with a particular signature.
+
+Arguments:
+
+ Signature - signature of disk to locate
+
+Return Value:
+
+ Pointer to disk descriptor or NULL if no disk with the given signature
+ was found.
+
+--*/
+
+{
+ ULONG diskNumber;
+ PDISKSTATE diskState;
+
+ for (diskNumber = 0; diskNumber < DiskCount; diskNumber++)
+ {
+ diskState = DiskArray[diskNumber];
+ if (diskState->Signature == Signature)
+ {
+ return diskState;
+ }
+ }
+ return NULL;
+}
+
+
+PREGION_DESCRIPTOR
+LookUpPartition(
+ IN PDISKSTATE DiskState,
+ IN LARGE_INTEGER Offset,
+ IN LARGE_INTEGER Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will look through a region descriptor array for a
+ partition with a particular length and starting offset.
+
+Arguments:
+
+ DiskState - disk on which to locate the partition
+ Offset - offset of partition on the disk to find
+ Length - size of the partition to find
+
+Return Value:
+
+ Pointer to region descriptor or NULL if no such partition on that disk
+
+--*/
+
+{
+ ULONG regionIndex;
+ ULONG maxRegion = DiskState->RegionCount;
+ PREGION_DESCRIPTOR regionDescriptor;
+ LARGE_INTEGER offset;
+ LARGE_INTEGER length;
+
+ for (regionIndex = 0; regionIndex < maxRegion; regionIndex++)
+ {
+ regionDescriptor = &DiskState->RegionArray[regionIndex];
+
+ if ((regionDescriptor->SysID != PARTITION_ENTRY_UNUSED)
+ && !IsExtended(regionDescriptor->SysID))
+ {
+ offset = FdGetExactOffset(regionDescriptor);
+ length = FdGetExactSize(regionDescriptor, FALSE);
+
+ if ( (offset.LowPart == Offset.LowPart)
+ && (offset.HighPart == Offset.HighPart)
+ && (length.LowPart == Length.LowPart)
+ && (length.HighPart == Length.HighPart))
+ {
+ return regionDescriptor;
+ }
+ }
+ }
+ return NULL;
+}
+
+
+VOID
+AddObjectToSet(
+ IN PFT_OBJECT FtObjectToAdd,
+ IN FT_TYPE FtType,
+ IN USHORT FtGroup
+ )
+
+/*++
+
+Routine Description:
+
+ Find the FtSet for that this object belongs to and insert
+ it into the chain of members. If the set cannot be found
+ in the existing collection of sets, create a new one.
+
+Arguments:
+
+ FtObjectToAdd - the object point to be added.
+ FtType - the type of the FT set.
+ FtGroup - group for this object.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PFT_OBJECT_SET ftSet = FtObjectList;
+
+ while (NULL != ftSet)
+ {
+ if ((ftSet->Type == FtType) && (ftSet->Ordinal == FtGroup))
+ {
+ break;
+ }
+ ftSet = ftSet->Next;
+ }
+
+ if (NULL == ftSet)
+ {
+ //
+ // There is no such existing ft set. Create one.
+ //
+
+ ftSet = (PFT_OBJECT_SET)Malloc(sizeof(FT_OBJECT_SET));
+
+ ftSet->Status = FtSetHealthy;
+ ftSet->Type = FtType;
+ ftSet->Ordinal = FtGroup;
+ ftSet->Members = NULL;
+ ftSet->Next = FtObjectList;
+ ftSet->Member0 = NULL;
+ ftSet->NumberOfMembers = 0;
+
+ FtObjectList = ftSet;
+ }
+
+ FDASSERT(NULL != ftSet);
+
+ FtObjectToAdd->Next = ftSet->Members;
+ ftSet->Members = FtObjectToAdd;
+ ++ftSet->NumberOfMembers;
+ FtObjectToAdd->Set = ftSet;
+
+ if (FtObjectToAdd->MemberIndex == 0)
+ {
+ ftSet->Member0 = FtObjectToAdd;
+ }
+
+ if (FtType == StripeWithParity || FtType == Mirror)
+ {
+ // Update the set's state based on the state of the new member:
+ //
+ switch (FtObjectToAdd->State)
+ {
+ case Healthy:
+ // Doesn't change state of set.
+ break;
+
+ case Regenerating:
+ ftSet->Status = (ftSet->Status == FtSetHealthy ||
+ ftSet->Status == FtSetRegenerating)
+ ? FtSetRegenerating
+ : FtSetBroken;
+ break;
+
+ case Initializing:
+ ftSet->Status = (ftSet->Status == FtSetHealthy ||
+ ftSet->Status == FtSetInitializing)
+ ? FtSetInitializing
+ : FtSetBroken;
+ break;
+
+ default:
+ // If only one member is bad, the set is recoverable;
+ // otherwise, it's broken.
+ //
+ ftSet->Status = (ftSet->Status == FtSetHealthy)
+ ? FtSetRecoverable
+ : FtSetDisabled;
+ break;
+ }
+ }
+}
+
+
+ULONG
+InitializeFt(
+ IN BOOL DiskSignaturesCreated
+ )
+
+/*++
+
+Routine Description:
+
+ Search the disk registry information to construct the FT
+ relationships in the system.
+
+Arguments:
+
+ DiskSignaturesCreated - boolean to indicate that new disks
+ were located in the system.
+
+Return Value:
+
+ An error code if the disk registry could not be obtained.
+
+--*/
+
+{
+ ULONG disk;
+ ULONG partitionIndex;
+ ULONG partitionCount;
+ PDISK_REGISTRY diskRegistry;
+ PDISK_PARTITION diskPartition;
+ PDISK_DESCRIPTION diskDescription;
+ PDISKSTATE diskState;
+ PREGION_DESCRIPTOR regionDescriptor;
+ PFT_OBJECT ftObject;
+ DWORD ec;
+ BOOL configDiskChanged = FALSE;
+ BOOL configMissingDisk = FALSE;
+ BOOL configExtraDisk = FALSE;
+ BOOL anyDisksOffLine;
+
+
+ RememberedDiskArray = (PDISK_DESCRIPTION*)Malloc(0);
+ RememberedDiskCount = 0;
+
+ ec = MyDiskRegistryGet(&diskRegistry);
+ if (ec != NO_ERROR)
+ {
+ FDLOG((0, "InitializeFt: Error %u from MyDiskRegistryGet\n", ec));
+
+ return ec;
+ }
+
+ DiskHadRegistryEntry = (PULONG)Malloc(DiskCount * sizeof(ULONG));
+ memset(DiskHadRegistryEntry, 0, DiskCount * sizeof(ULONG));
+
+ diskDescription = diskRegistry->Disks;
+
+ for (disk = 0; disk < diskRegistry->NumberOfDisks; disk++)
+ {
+ //
+ // For the disk described in the registry, look up the
+ // corresponding actual disk found by the fdisk init code.
+ //
+
+ diskState = LookUpDiskBySignature(diskDescription->Signature);
+
+ if (NULL != diskState)
+ {
+ FDLOG(( 2,
+ "InitializeFt: disk w/ signature %08lx is disk #%u\n",
+ diskDescription->Signature,
+ diskState->Disk
+ ));
+
+ DiskHadRegistryEntry[diskState->Disk]++;
+
+ partitionCount = ActualPartitionCount(diskState);
+
+ if (partitionCount != diskDescription->NumberOfPartitions)
+ {
+ FDLOG(( 1,
+ "InitializeFt: partition counts for disk %08lx don't match:\n",
+ diskState->Signature));
+
+ FDLOG((1, " Count from actual disk: %u\n", partitionCount));
+ FDLOG((1, " Count from registry : %u\n", diskDescription->NumberOfPartitions));
+
+ configDiskChanged = TRUE;
+ }
+ }
+ else
+ {
+ //
+ // there's an entry in the registry that does not have a
+ // real disk to match. Remember this disk; if it has any
+ // FT partitions, we also want to display a message telling
+ // the user that something's missing.
+ //
+ FDLOG((1, "InitializeFt: Entry for disk w/ signature %08lx has no matching real disk\n", diskDescription->Signature));
+
+ for (partitionIndex = 0;
+ partitionIndex < diskDescription->NumberOfPartitions;
+ partitionIndex++)
+ {
+ diskPartition = &diskDescription->Partitions[partitionIndex];
+ if (diskPartition->FtType != NotAnFtMember)
+ {
+ // This disk has an FT partition, so Windisk will
+ // want to tell the user that some disks are missing.
+ //
+ configMissingDisk = TRUE;
+ break;
+ }
+ }
+
+ FdpRememberDisk(diskDescription);
+ }
+
+ for (partitionIndex = 0;
+ partitionIndex < diskDescription->NumberOfPartitions;
+ partitionIndex++)
+ {
+ diskPartition = &diskDescription->Partitions[partitionIndex];
+
+ regionDescriptor = NULL;
+
+ if (NULL != diskState)
+ {
+ regionDescriptor = LookUpPartition(diskState,
+ diskPartition->StartingOffset,
+ diskPartition->Length
+ );
+ }
+
+ //
+ // At this point one of three conditions exists.
+ //
+ // 1. There is no disk related to this registry information
+ // diskState == NULL && regionDescriptor == NULL
+ // 2. There is a disk, but no partition related to this information
+ // diskState != NULL && regionDescriptor == NULL
+ // 3. There is a disk and a partition related to this information
+ // diskState != NULL && regionDescriptor != NULL
+ //
+ // In any of these conditions, if the registry entry is part
+ // of an FT set and FT object must be created.
+ //
+ // that corresponds to a partition's entry in the
+ // disk registry database.
+ //
+
+ if (diskPartition->FtType != NotAnFtMember)
+ {
+ ftObject = (PFT_OBJECT)Malloc(sizeof(FT_OBJECT));
+ ftObject->Next = NULL;
+ ftObject->Set = NULL;
+ ftObject->MemberIndex = diskPartition->FtMember;
+ ftObject->State = diskPartition->FtState;
+
+ // if a partition was actually found there will be a
+ // regionDescriptor that needs to be updated.
+
+ if (regionDescriptor && regionDescriptor->PersistentData)
+ {
+ FT_SET_STATUS setState;
+ ULONG numberOfMembers;
+
+ SET_FT_OBJECT(regionDescriptor, ftObject);
+
+ // Before the drive letter is moved into the region
+ // data, be certain that the FT volume exists at this
+ // drive letter.
+
+ LowFtVolumeStatusByLetter(diskPartition->DriveLetter,
+ &setState,
+ &numberOfMembers);
+
+ // If the numberOfMembers gets set to 1 then
+ // this letter is not the letter for the FT set,
+ // but rather a default letter assigned because the
+ // FT sets letter could not be assigned.
+
+ if (numberOfMembers > 1)
+ {
+ PERSISTENT_DATA(regionDescriptor)->DriveLetter = diskPartition->DriveLetter;
+ }
+ }
+ else
+ {
+ // There is no region for this partition
+ // so update the set state.
+
+ ftObject->State = Orphaned;
+ }
+
+ //
+ // Now place the ft object in the correct set,
+ // creating the set if necessary.
+ //
+
+ AddObjectToSet(
+ ftObject,
+ diskPartition->FtType,
+ diskPartition->FtGroup);
+
+ MaintainOrdinalTables(
+ diskPartition->FtType,
+ (ULONG) diskPartition->FtGroup);
+ }
+ }
+
+ diskDescription = (PDISK_DESCRIPTION)&diskDescription->Partitions[diskDescription->NumberOfPartitions];
+ }
+
+ Free(diskRegistry);
+
+ //
+ // Check to see if every disk found by the fdisk back end has a
+ // corresponding registry entry.
+ //
+
+ for (disk=0; disk<DiskCount; disk++)
+ {
+ if (DiskArray[disk]->OffLine)
+ {
+ continue;
+ }
+
+ if (!DiskHadRegistryEntry[disk] && !IsRemovable(disk))
+ {
+ //
+ // a real disk does not have a matching registry entry.
+ //
+
+ FDLOG((1, "InitializeFt: Disk %u does not have a registry entry (disk sig = %08lx)\n", disk, DiskArray[disk]->Signature));
+
+ configExtraDisk = TRUE;
+ }
+ }
+
+ //
+ // Determine whether any disks are off line
+ //
+
+ anyDisksOffLine = FALSE;
+ for (disk=0; disk<DiskCount; disk++)
+ {
+ if (DiskArray[disk]->OffLine)
+ {
+ anyDisksOffLine = TRUE;
+ break;
+ }
+ }
+
+ if (configMissingDisk || anyDisksOffLine)
+ {
+ WarningDialog(MSG_CONFIG_MISSING_DISK);
+ }
+
+ if (configDiskChanged)
+ {
+ RegistryChanged = TRUE;
+ WarningDialog(MSG_CONFIG_DISK_CHANGED);
+ }
+
+ if (configExtraDisk || DiskSignaturesCreated)
+ {
+ BOOL badConfigSet = FALSE;
+
+ WarningDialog(MSG_CONFIG_EXTRA_DISK);
+
+ //
+ // Update ft signature on each disk for which a new signature
+ // was created. and update registry for each disk with
+ // DiskHadRegistryEntry[Disk] == 0.
+ //
+
+ for (disk=0; disk<DiskCount; disk++)
+ {
+ BOOL b1 = TRUE;
+ BOOL b2 = TRUE;
+
+ if (DiskArray[disk]->OffLine)
+ {
+ continue;
+ }
+
+ if (DiskArray[disk]->SigWasCreated)
+ {
+ TCHAR name[100];
+ wsprintf(name, DiskN, disk);
+ if (IDYES == ConfirmationDialog(
+ MSG_NO_SIGNATURE,
+ MB_ICONEXCLAMATION | MB_YESNO,
+ name))
+ {
+ b1 = (MasterBootCode(disk, DiskArray[disk]->Signature, TRUE, TRUE) == NO_ERROR);
+ }
+ else
+ {
+ DiskArray[disk]->OffLine = TRUE;
+ continue;
+ }
+ }
+
+ if (!DiskHadRegistryEntry[disk])
+ {
+ ULONG size;
+
+ size = FdpDetermineDiskDescriptionSize(DiskArray[disk]);
+
+ diskDescription = (PDISK_DESCRIPTION)Malloc(size);
+
+ FdpConstructDiskDescription(DiskArray[disk], diskDescription);
+
+ FDLOG((2,
+ "InitializeFt: Adding new disk %08lx to registry.\n",
+ diskDescription->Signature));
+ LOG_ONE_DISK_REGISTRY_DISK_ENTRY("InitializeFt", diskDescription);
+
+ b2 = (EC(DiskRegistryAddNewDisk(diskDescription)) == NO_ERROR);
+
+ Free(diskDescription);
+ }
+
+ if (!(b1 && b2))
+ {
+ badConfigSet = TRUE;
+ }
+ }
+
+ if (badConfigSet)
+ {
+ ErrorDialog(MSG_BAD_CONFIG_SET);
+ }
+ }
+
+ return NO_ERROR;
+}
+
+
+BOOLEAN
+NewConfigurationRequiresFt(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Search the diskstate and region arrays to determine if a single
+ FtDisk element (i.e. stripe, stripe set with parity, mirror or
+ volume set) is contained in the configuration.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ TRUE if the new configuration requires the FtDisk driver.
+ FALSE otherwise.
+
+--*/
+
+{
+ ULONG disk,
+ region;
+ PDISKSTATE diskState;
+ PREGION_DESCRIPTOR regionDescriptor;
+
+ // Look at all disks in the system.
+
+ for (disk = 0; disk < DiskCount; disk++)
+ {
+ diskState = DiskArray[disk];
+ if (diskState->OffLine || IsDiskRemovable[disk])
+ {
+ continue;
+ }
+
+ // Check each region on the disk.
+
+ for (region = 0; region < diskState->RegionCount; region++)
+ {
+ regionDescriptor = &diskState->RegionArray[region];
+ if ( (regionDescriptor->SysID != PARTITION_ENTRY_UNUSED)
+ && !IsExtended(regionDescriptor->SysID)
+ && IsRecognizedPartition(regionDescriptor->SysID))
+ {
+ // If a single region has an FT Object, then FT
+ // is required and the search may be stopped.
+
+ if (NULL != GET_FT_OBJECT(regionDescriptor))
+ {
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ // no FtObject was found.
+
+ return FALSE;
+}
+
+
+
+ULONG
+SaveFt(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine walks all of the internal structures and creates the
+ interface structure for the DiskRegistry interface.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ success/failure code. NO_ERROR is success.
+
+--*/
+
+{
+ ULONG i;
+ ULONG disk;
+ ULONG partitionIndex;
+ ULONG size;
+ PDISK_REGISTRY diskRegistry;
+ PDISK_DESCRIPTION diskDescription;
+ PBYTE start, end;
+ DWORD ec;
+ ULONG offLineDiskCount;
+ ULONG removableDiskCount;
+
+ //
+ // First count partitions and disks so we can allocate a structure
+ // of the correct size.
+ //
+
+ size = sizeof(DISK_REGISTRY) - sizeof(DISK_DESCRIPTION);
+ offLineDiskCount = 0;
+ removableDiskCount = 0;
+
+ for (i=0; i<DiskCount; i++)
+ {
+ if (DiskArray[i]->OffLine)
+ {
+ offLineDiskCount++;
+ }
+ else if (IsDiskRemovable[i])
+ {
+ removableDiskCount++;
+ }
+ else
+ {
+ size += FdpDetermineDiskDescriptionSize(DiskArray[i]);
+ }
+ }
+
+ //
+ // Account for remembered disks.
+ //
+
+ size += RememberedDiskCount * sizeof(DISK_DESCRIPTION);
+ for (i=0; i<RememberedDiskCount; i++)
+ {
+ if (RememberedDiskArray[i]->NumberOfPartitions > 1)
+ {
+ size += (RememberedDiskArray[i]->NumberOfPartitions - 1) * sizeof(DISK_PARTITION);
+ }
+ }
+
+ diskRegistry = (PDISK_REGISTRY)Malloc(size);
+
+ diskRegistry->NumberOfDisks = (USHORT)( DiskCount
+ + RememberedDiskCount
+ - offLineDiskCount
+ - removableDiskCount
+ );
+ diskRegistry->ReservedShort = 0;
+
+ diskDescription = diskRegistry->Disks;
+ for (disk=0; disk<DiskCount; disk++)
+ {
+ if (DiskArray[disk]->OffLine || IsDiskRemovable[disk])
+ {
+ continue;
+ }
+
+ partitionIndex = FdpConstructDiskDescription(DiskArray[disk], diskDescription);
+
+ diskDescription = (PDISK_DESCRIPTION)&diskDescription->Partitions[partitionIndex];
+ }
+
+ //
+ // Toss in remembered disks.
+ //
+
+ for (i=0; i<RememberedDiskCount; i++)
+ {
+ // Compute the beginning and end of this remembered disk's
+ // Disk Description:
+ //
+ partitionIndex = RememberedDiskArray[i]->NumberOfPartitions;
+ start = (PBYTE)RememberedDiskArray[i];
+ end = (PBYTE)&(RememberedDiskArray[i]->Partitions[partitionIndex]);
+
+ RtlMoveMemory(diskDescription, RememberedDiskArray[i], end - start);
+
+ diskDescription = (PDISK_DESCRIPTION)&diskDescription->Partitions[partitionIndex];
+ }
+
+ LOG_DISK_REGISTRY("SaveFt", diskRegistry);
+
+ ec = EC(DiskRegistrySet(diskRegistry));
+
+ Free(diskRegistry);
+
+ if (ec == NO_ERROR)
+ {
+ FdpInitializeMirrors();
+ }
+
+ return ec;
+}
+
+
+ULONG
+FdpDetermineDiskDescriptionSize(
+ PDISKSTATE DiskState
+ )
+
+/*++
+
+Routine Description:
+
+ This routine takes a pointer to a disk and determines how much
+ memory is needed to contain the description of the disk by
+ counting the number of partitions on the disk and multiplying
+ the appropriate counts by the appropriate size of the structures.
+
+Arguments:
+
+ DiskState - the disk in question.
+
+Return Value:
+
+ The memory size needed to contain all of the information on the disk.
+
+--*/
+
+{
+ ULONG partitionCount;
+ ULONG size;
+
+ if (DiskState->OffLine)
+ {
+ return 0;
+ }
+
+ size = sizeof(DISK_DESCRIPTION);
+ partitionCount = ActualPartitionCount(DiskState);
+ size += (partitionCount ? partitionCount-1 : 0) * sizeof(DISK_PARTITION);
+
+ return size;
+}
+
+
+ULONG
+FdpConstructDiskDescription(
+ IN PDISKSTATE DiskState,
+ OUT PDISK_DESCRIPTION DiskDescription
+ )
+
+/*++
+
+Routine Description:
+
+ Given a disk state pointer as input, construct the FtRegistry
+ structure to describe the partitions on the disk.
+
+Arguments:
+
+ DiskState - the disk for which to construct the information
+ DiskDescription - the memory location where the registry
+ structure is to be created.
+
+Return Value:
+
+ The number of partitions described in the DiskDescription.
+
+--*/
+
+{
+ ULONG partitionIndex;
+ ULONG regionIndex;
+ PREGION_DESCRIPTOR regionDescriptor;
+ PDISK_PARTITION diskPartition;
+ WCHAR driveLetter;
+ BOOLEAN assignDriveLetter;
+ PFT_OBJECT ftObject;
+ PFT_OBJECT_SET ftSet;
+
+ partitionIndex = 0;
+
+ for (regionIndex = 0; regionIndex < DiskState->RegionCount; regionIndex++)
+ {
+ regionDescriptor = &DiskState->RegionArray[regionIndex];
+
+ if ( (regionDescriptor->SysID != PARTITION_ENTRY_UNUSED)
+ && !IsExtended(regionDescriptor->SysID)
+ && IsRecognizedPartition(regionDescriptor->SysID))
+ {
+ diskPartition = &DiskDescription->Partitions[partitionIndex++];
+
+ diskPartition->StartingOffset = FdGetExactOffset(regionDescriptor);
+ diskPartition->Length = FdGetExactSize(regionDescriptor, FALSE);
+ diskPartition->LogicalNumber = (USHORT)regionDescriptor->PartitionNumber;
+
+ driveLetter = PERSISTENT_DATA(regionDescriptor)->DriveLetter;
+ switch (driveLetter)
+ {
+ case NO_DRIVE_LETTER_YET:
+ assignDriveLetter = TRUE;
+ driveLetter = L'\0';
+ break;
+
+ case NO_DRIVE_LETTER_EVER:
+ assignDriveLetter = FALSE;
+ driveLetter = L'\0';
+ break;
+
+ default:
+ assignDriveLetter = TRUE;
+ break;
+ }
+
+ diskPartition->DriveLetter = (UCHAR)driveLetter;
+ diskPartition->FtLength.LowPart = 0;
+ diskPartition->FtLength.HighPart = 0;
+ diskPartition->ReservedTwoLongs[0] = 0;
+ diskPartition->ReservedTwoLongs[1] = 0;
+ diskPartition->Modified = TRUE;
+ diskPartition->ReservedChars[0] = 0;
+ diskPartition->ReservedChars[1] = 0;
+ diskPartition->ReservedChars[2] = 0;
+
+ if (NULL != (ftObject = GET_FT_OBJECT(regionDescriptor)))
+ {
+ ftSet = ftObject->Set;
+
+#if 0
+
+// need to do something here, but currently this does not work.
+
+ PREGION_DESCRIPTOR tmpDescriptor;
+ STATUS_CODE status;
+ FT_SET_STATUS setState;
+ ULONG numberOfMembers;
+
+ tmpDescriptor = LocateRegionForFtObject(ftSet->Member0);
+
+ // Only update status if member zero is present.
+ // otherwise the status is know to be Orphaned or
+ // needs regeneration.
+
+ if (tmpDescriptor)
+ {
+ // If the partition number is zero, then this set
+ // has not been committed to the disk yet. Only
+ // update status for existing sets.
+
+ if ( (0 != tmpDescriptor->PartitionNumber)
+ && (ftSet->Status != FtSetNew)
+ && (ftSet->Status != FtSetNewNeedsInitialization))
+ {
+ status = LowFtVolumeStatus(tmpDescriptor->Disk,
+ tmpDescriptor->PartitionNumber,
+ &setState,
+ &numberOfMembers);
+ if (status == OK_STATUS)
+ {
+ if (ftSet->Status != setState)
+ {
+ // Problem here - the FT driver has
+ // updated the status of the set after
+ // windisk last got the status. Need
+ // to restart the process of building
+ // the FT information after updating
+ // the set to the new state.
+
+ FdftUpdateFtObjectSet(ftSet, setState);
+
+ // now recurse and start over
+
+ status = FdpConstructDiskDescription(
+ DiskState,
+ DiskDescription);
+ return status;
+ }
+ }
+ }
+ }
+#endif
+
+ diskPartition->FtState = ftObject->State;
+ diskPartition->FtType = ftSet->Type;
+ diskPartition->FtGroup = (USHORT)ftSet->Ordinal;
+ diskPartition->FtMember = (USHORT)ftObject->MemberIndex;
+ if (assignDriveLetter && (ftObject == ftObject->Set->Member0))
+ {
+ diskPartition->AssignDriveLetter = TRUE;
+ }
+ else
+ {
+ diskPartition->AssignDriveLetter = FALSE;
+ }
+ }
+ else
+ {
+ diskPartition->FtState = Healthy;
+ diskPartition->FtType = NotAnFtMember;
+ diskPartition->FtGroup = (USHORT)(-1);
+ diskPartition->FtMember = 0;
+ diskPartition->AssignDriveLetter = assignDriveLetter;
+ }
+ }
+ }
+
+ DiskDescription->NumberOfPartitions = (USHORT)partitionIndex;
+ DiskDescription->Signature = DiskState->Signature;
+ DiskDescription->ReservedShort = 0;
+
+ return partitionIndex;
+}
+
+
+VOID
+FdpRememberDisk(
+ IN PDISK_DESCRIPTION DiskDescription
+ )
+
+/*++
+
+Routine Description:
+
+ Make a copy of a registry disk description structure for later use.
+
+Arguments:
+
+ DiskDescription - supplies pointer to the registry descriptor for
+ the disk in question.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDISK_DESCRIPTION diskDescription;
+ ULONG size;
+
+ // Only bother remembering disks with at least one partition.
+ //
+ if (DiskDescription->NumberOfPartitions == 0)
+ {
+ return;
+ }
+
+ //
+ // Compute the size of the structure
+ //
+
+ size = sizeof(DISK_DESCRIPTION);
+ if (DiskDescription->NumberOfPartitions > 1)
+ {
+ size += (DiskDescription->NumberOfPartitions - 1) * sizeof(DISK_PARTITION);
+ }
+
+ diskDescription = (PDISK_DESCRIPTION)Malloc(size);
+ RtlMoveMemory(diskDescription, DiskDescription, size);
+
+ RememberedDiskArray = (PDISK_DESCRIPTION*)Realloc(
+ RememberedDiskArray,
+ (RememberedDiskCount+1) * sizeof(PDISK_DESCRIPTION)
+ );
+
+ RememberedDiskArray[RememberedDiskCount++] = diskDescription;
+
+ FDLOG((2,
+ "FdpRememberDisk: remembered disk %08lx, remembered count = %u\n",
+ diskDescription->Signature,
+ RememberedDiskCount));
+}
+
+
+VOID
+FdpInitializeMirrors(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ For each existing partition that was mirrored by the user during this
+ Disk Administrator session, call the FT driver to register initialization
+ of the mirror (ie, cause the primary to be copied to the secondary).
+ Perform a similar initialization for each stripe set with parity created
+ by the user.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PFT_OBJECT_SET ftSet;
+ PFT_OBJECT ftObject;
+
+ //
+ // Look through the list of FT sets for mirrored pairs and parity stripes
+ //
+
+ for (ftSet = FtObjectList; NULL != ftSet; ftSet = ftSet->Next)
+ {
+ //
+ // If the set needs initialization, or was recovered,
+ // call the FT driver.
+ //
+
+ switch (ftSet->Status)
+ {
+ case FtSetNewNeedsInitialization:
+
+ DiskRegistryInitializeSet((USHORT)ftSet->Type,
+ (USHORT)ftSet->Ordinal);
+ ftSet->Status = FtSetInitializing;
+ break;
+
+ case FtSetRecovered:
+
+ //
+ // Find the member that needs to be addressed.
+ //
+
+ for (ftObject = ftSet->Members;
+ NULL != ftObject;
+ ftObject=ftObject->Next)
+ {
+ if (ftObject->State == Regenerating)
+ {
+ break;
+ }
+ }
+
+ DiskRegistryRegenerateSet((USHORT)ftSet->Type,
+ (USHORT)ftSet->Ordinal,
+ (USHORT)ftObject->MemberIndex);
+ ftSet->Status = FtSetRegenerating;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
diff --git a/private/utils/windisk/src/ft.hxx b/private/utils/windisk/src/ft.hxx
new file mode 100644
index 000000000..30094ecc2
--- /dev/null
+++ b/private/utils/windisk/src/ft.hxx
@@ -0,0 +1,67 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: ft.hxx
+//
+// Contents: Declarations for FT support routines for Disk Administrator
+//
+// History: 15-Nov-91 TedM Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __FT_HXX__
+#define __FT_HXX__
+
+//////////////////////////////////////////////////////////////////////////////
+
+DWORD
+FdftNextOrdinal(
+ IN FT_TYPE FtType
+ );
+
+ULONG
+InitializeFt(
+ IN BOOL DiskSignaturesCreated
+ );
+
+BOOLEAN
+NewConfigurationRequiresFt(
+ VOID
+ );
+
+ULONG
+SaveFt(
+ VOID
+ );
+
+VOID
+FdftCreateFtObjectSet(
+ IN FT_TYPE FtType,
+ IN PREGION_DESCRIPTOR* RegionArray,
+ IN DWORD RegionCount,
+ IN FT_SET_STATUS Status
+ );
+
+BOOL
+FdftUpdateFtObjectSet(
+ IN PFT_OBJECT_SET FtSet,
+ IN FT_SET_STATUS SetState
+ );
+
+VOID
+FdftDeleteFtObjectSet(
+ IN PFT_OBJECT_SET FtSet,
+ IN BOOL OffLineDisksOnly
+ );
+
+
+VOID
+FdftExtendFtObjectSet(
+ IN OUT PFT_OBJECT_SET FtSet,
+ IN OUT PREGION_DESCRIPTOR* RegionArray,
+ IN DWORD RegionCount
+ );
+
+#endif // __FT_HXX__
diff --git a/private/utils/windisk/src/ftreg.cxx b/private/utils/windisk/src/ftreg.cxx
new file mode 100644
index 000000000..20f83d29c
--- /dev/null
+++ b/private/utils/windisk/src/ftreg.cxx
@@ -0,0 +1,1329 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: ftreg.cxx
+//
+// Contents: Registry calls related to fault tolerance
+//
+// History: 2-Jan-92 TedM Created
+// 1-Feb-94 BobRi Handle missing floppy disk on registry
+// save/restore
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include <stdlib.h>
+#include <util.hxx>
+
+#include "dlgs.hxx"
+#include "ftreg.h"
+#include "ftreg.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+// attempt to avoid conflict
+
+#define TEMP_KEY_NAME TEXT("xzss3___$$Temp$Hive$$___")
+
+#define DISK_KEY_NAME TEXT("DISK")
+#define DISK_VALUE_NAME TEXT("Information")
+
+
+
+LONG
+FdpLoadHiveIntoRegistry(
+ IN LPTSTR HiveFilename
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes the contents of a given hive file into the registry,
+ rooted at a temporary key in HKEY_LOCAL_MACHINE.
+
+Arguments:
+
+ HiveFilename - supplies filename of the hive to be loaded into
+ the registry
+
+Return Value:
+
+ Windows error code.
+
+--*/
+
+{
+ NTSTATUS status;
+ BOOLEAN oldPrivState;
+ LONG ec;
+
+ //
+ // Attempt to get restore privilege
+ //
+
+ status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE,
+ TRUE,
+ FALSE,
+ &oldPrivState);
+ if (!NT_SUCCESS(status))
+ {
+ return RtlNtStatusToDosError(status);
+ }
+
+ //
+ // Load the hive into our registry
+ //
+
+ ec = RegLoadKey(HKEY_LOCAL_MACHINE, TEMP_KEY_NAME, HiveFilename);
+
+ //
+ // Restore old privilege if necessary
+ //
+
+ if (!oldPrivState)
+ {
+ RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE,
+ FALSE,
+ FALSE,
+ &oldPrivState);
+ }
+
+ return ec;
+}
+
+
+LONG
+FdpUnloadHiveFromRegistry(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine removes a tree (previously loaded with
+ FdpLoadHiveIntoRegistry) from the temporary key in HKEY_LOCAL_MACHINE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Windows error code.
+
+--*/
+
+{
+ NTSTATUS status;
+ BOOLEAN oldPrivState;
+ LONG ec;
+
+ //
+ // Attempt to get restore privilege
+ //
+
+ status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE,
+ TRUE,
+ FALSE,
+ &oldPrivState);
+ if (!NT_SUCCESS(status))
+ {
+ return RtlNtStatusToDosError(status);
+ }
+
+ //
+ // Unload the hive from our registry
+ //
+
+ ec = RegUnLoadKey(HKEY_LOCAL_MACHINE, TEMP_KEY_NAME);
+
+ //
+ // Restore old privilege if necessary
+ //
+
+ if (!oldPrivState)
+ {
+ RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE,
+ FALSE,
+ FALSE,
+ &oldPrivState);
+ }
+
+ return ec;
+}
+
+
+
+LONG
+FdpGetDiskInfoFromKey(
+ IN LPTSTR RootKeyName,
+ OUT PVOID* DiskInfo,
+ OUT PULONG DiskInfoSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine pulls the binary blob containing disk ft, drive letter,
+ and layout information out of a given registry key.
+
+ The info is found in HKEY_LOCAL_MACHINE, <RootKeyName>\DISK:Information.
+
+Arguments:
+
+ RootKeyName - name of the subkey of HKEY_LOCAL_MACHINE that is to
+ contain the DISK key.
+
+ DiskInfo - receives a pointer to a buffer containing the disk info.
+
+ DiskInfoSize - receives size of the disk buffer.
+
+Return Value:
+
+ Windows error code. If NO_ERROR, DiskInfo and DiskInfoSize are
+ filled in, and it is the caller's responsibility to free the buffer
+ when it is finished (via LocalFree()).
+
+--*/
+
+{
+ LONG ec;
+ HKEY hkeyDisk;
+ ULONG bufferSize;
+ ULONG valueType;
+ PBYTE buffer;
+ LPTSTR diskKeyName;
+
+ //
+ // Form the name of the DISK key
+ //
+
+ diskKeyName = (LPTSTR)LocalAlloc( LMEM_FIXED,
+ ( lstrlen(RootKeyName)
+ + lstrlen(DISK_KEY_NAME)
+ + 2 // the \ and nul
+ )
+ * sizeof(TCHAR)
+ );
+
+ if (diskKeyName == NULL)
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ lstrcpy(diskKeyName, RootKeyName);
+ lstrcat(diskKeyName, TEXT("\\"));
+ lstrcat(diskKeyName, DISK_KEY_NAME);
+
+ //
+ // Open the DISK key.
+ //
+
+ ec = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ diskKeyName,
+ REG_OPTION_RESERVED,
+ KEY_READ,
+ &hkeyDisk);
+
+ if (ec != NO_ERROR)
+ {
+ goto CleanUp2;
+ }
+
+ //
+ // Determine how large we need the buffer to be
+ //
+
+ ec = RegQueryValueEx(hkeyDisk,
+ DISK_VALUE_NAME,
+ NULL,
+ &valueType,
+ NULL,
+ &bufferSize);
+
+ if ((ec != NO_ERROR) && (ec != ERROR_MORE_DATA))
+ {
+ goto CleanUp1;
+ }
+
+ //
+ // Allocate a buffer of appropriate size
+ //
+
+ buffer = (PBYTE)LocalAlloc(LMEM_FIXED, bufferSize);
+ if (buffer == NULL)
+ {
+ ec = ERROR_NOT_ENOUGH_MEMORY;
+ goto CleanUp1;
+ }
+
+ //
+ // Query the data
+ //
+
+ ec = RegQueryValueEx(hkeyDisk,
+ DISK_VALUE_NAME,
+ NULL,
+ &valueType,
+ buffer,
+ &bufferSize);
+ if (ec != NO_ERROR)
+ {
+ LocalFree(buffer);
+ goto CleanUp1;
+ }
+
+ *DiskInfo = (PVOID)buffer;
+ *DiskInfoSize = bufferSize;
+
+ CleanUp1:
+
+ RegCloseKey(hkeyDisk);
+
+ CleanUp2:
+
+ LocalFree(diskKeyName);
+
+ return ec;
+}
+
+
+LONG
+FdpGetDiskInfoFromHive(
+ IN LPTSTR HiveFilename,
+ OUT PVOID *DiskInfo,
+ OUT PULONG DiskInfoSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine pulls the binary blob containing disk ft, drive letter,
+ and layout information out of a given registry hive, which must be
+ a file in an alternate NT tree (ie, can't be an active hive).
+
+ The info is found in \DISK:Information within the hive.
+
+Arguments:
+
+ HiveFilename - supplies filename of hive
+
+ DiskInfo - receives a pointer to a buffer containing the disk info.
+
+ DiskInfoSize - receives size of the disk buffer.
+
+Return Value:
+
+ Windows error code. If NO_ERROR, DiskInfo and DiskInfoSize are
+ filled in, and it is the caller's responsibility to free the buffer
+ when it is finished (via LocalFree()).
+
+--*/
+
+{
+ ULONG windowsError;
+
+ windowsError = FdpLoadHiveIntoRegistry(HiveFilename);
+ if (windowsError == NO_ERROR)
+ {
+ windowsError = FdpGetDiskInfoFromKey(TEMP_KEY_NAME,DiskInfo,DiskInfoSize);
+ FdpUnloadHiveFromRegistry();
+ }
+
+ return windowsError;
+}
+
+
+
+
+LONG
+FdTransferOldDiskInfoToRegistry(
+ IN LPTSTR HiveFilename
+ )
+
+/*++
+
+Routine Description:
+
+ This routine transfers disk configuration from a given hive file
+ (which should be an inactive system hive) to the current registry.
+
+Arguments:
+
+ HiveFilename - supplies filename of source hive
+
+Return Value:
+
+ Windows error code.
+
+--*/
+
+{
+ LONG ec;
+ PVOID diskInfo;
+ ULONG diskInfoSize;
+ HKEY hkeyDisk;
+
+
+ //
+ // Load up the hive and pull the disk info from it.
+ //
+
+ ec = FdpGetDiskInfoFromHive(HiveFilename, &diskInfo, &diskInfoSize);
+ if (ec != NO_ERROR)
+ {
+ return ec;
+ }
+
+ //
+ // Propogate the disk info into the current registry.
+ //
+ // Start by opening HKEY_LOCAL_MACHINE, System\DISK
+ //
+
+ ec = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("System\\") DISK_KEY_NAME,
+ REG_OPTION_RESERVED,
+ KEY_WRITE,
+ &hkeyDisk);
+
+ if (ec != NO_ERROR)
+ {
+ LocalFree(diskInfo);
+ return ec;
+ }
+
+ //
+ // Set the Information value in the DISK key.
+ //
+
+ ec = RegSetValueEx(hkeyDisk,
+ DISK_VALUE_NAME,
+ 0,
+ REG_BINARY,
+ (PBYTE)diskInfo,
+ diskInfoSize);
+
+ RegCloseKey(hkeyDisk);
+
+ LocalFree(diskInfo);
+
+ return ec;
+}
+
+
+typedef struct _STRING_LIST_NODE
+{
+ struct _STRING_LIST_NODE *Next;
+ LPTSTR String;
+} STRING_LIST_NODE, *PSTRING_LIST_NODE;
+
+PSTRING_LIST_NODE FoundDirectoryList;
+ULONG FoundDirectoryCount;
+TCHAR Pattern[MAX_PATH + 1];
+CHAR AnsiPattern[MAX_PATH + 1];
+WIN32_FIND_DATA FindData;
+HWND hwndStatus;
+BOOLEAN ScanDrive[26];
+BOOLEAN UserCancelled;
+
+typedef
+BOOL
+(*PFOUND_HIVE_ROUTINE)(
+ IN LPTSTR Directory
+ );
+
+VOID
+ProcessPendingMessages(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Preprocess messages.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ MSG msg;
+
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ DispatchMessage(&msg);
+ }
+}
+
+
+TCHAR ConfigRegistryPath[] = TEXT("\\system32\\config\\system");
+
+
+BOOL
+FdpSearchTreeForSystemHives(
+ IN LPTSTR CurrentDirectory,
+ IN PFOUND_HIVE_ROUTINE FoundHiveRoutine,
+ IN HWND hdlg
+ )
+
+/*++
+
+Routine Description:
+
+ Search an entire directory tree for system and system.alt hive files.
+ When found, call a callback function with the directory in which
+ system32\config\system[.alt] was found, and the full path of the hive
+ file.
+
+ The root directory is not included in the search.
+
+ The top-level call to this function should have a current directory
+ like "C:." (ie, no slash for the root directory).
+
+Arguments:
+
+ CurrentDirectory - supplies current directory search path
+
+Return Value:
+
+ FALSE if error (callback function returned FALSE when we found an entry).
+
+--*/
+
+{
+ HANDLE findHandle;
+ TCHAR newDirectory[MAX_PATH+1];
+ BOOL found = FALSE;
+
+ //
+ // Iterate through the current directory, looking for subdirectories.
+ //
+
+ lstrcpy(Pattern, CurrentDirectory);
+ lstrcat(Pattern, TEXT("\\*"));
+ findHandle = FindFirstFile(Pattern, &FindData);
+
+ if (findHandle != INVALID_HANDLE_VALUE)
+ {
+ do
+ {
+ ProcessPendingMessages();
+ if (UserCancelled)
+ {
+ return FALSE;
+ }
+
+ //
+ // If the current match is not a directory then skip it.
+ //
+
+ if ( !(FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ || !lstrcmp(FindData.cFileName, TEXT("."))
+ || !lstrcmp(FindData.cFileName, TEXT("..")))
+ {
+ continue;
+ }
+
+ found = FALSE;
+
+ //
+ // Form the name of the file we are looking for
+ // [<currentdirectory>\<match>\system32\config\system]
+ //
+
+ lstrcpy(Pattern, CurrentDirectory);
+ lstrcat(Pattern, TEXT("\\"));
+ lstrcat(Pattern, FindData.cFileName);
+
+ lstrcpy(newDirectory, Pattern);
+
+ // Don't decend into the directory unless the path to the
+ // hive.alt name is within MAX_PATH length.
+
+ if (lstrlen(newDirectory) + lstrlen(ConfigRegistryPath) + 4
+ < MAX_PATH)
+ // 4 = length of ".alt"
+ {
+ SetDlgItemText(hdlg, IDC_SIMPLE_TEXT_LINE, newDirectory);
+
+ lstrcat(Pattern, ConfigRegistryPath);
+
+ if (GetFileAttributes(Pattern) != -1)
+ {
+ found = TRUE;
+ }
+
+ //
+ // Also check for a system.alt file there
+ //
+
+ lstrcat(Pattern, TEXT(".alt"));
+
+ if (GetFileAttributes(Pattern) != -1)
+ {
+ found = TRUE;
+ }
+
+ if (found)
+ {
+ if (!FoundHiveRoutine(newDirectory))
+ {
+ return FALSE;
+ }
+ }
+
+ //
+ // Descend into the directory we just found
+ //
+
+ if (!FdpSearchTreeForSystemHives(newDirectory, FoundHiveRoutine, hdlg))
+ {
+ return FALSE;
+ }
+ }
+ } while (FindNextFile(findHandle, &FindData));
+
+ FindClose(findHandle);
+ }
+
+ return TRUE;
+}
+
+
+BOOL
+FdpFoundHiveCallback(
+ IN LPTSTR Directory
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when a directory containing a system hive
+ has been located. If all goes well (allocate memory and the like)
+ this routine will save the directory name in a list for later use.
+ NOTE: No checks are made on the directory name being greater in
+ length than MAX_PATH. It is the responsibility of the caller to
+ insure that this is true.
+
+Arguments:
+
+ Directory - the pointer to the character string for the directory
+ where a hive has been located.
+
+Return Value:
+
+ TRUE - did something with it.
+ FALSE - did not save the directory.
+
+--*/
+
+{
+ TCHAR windowsDir[MAX_PATH + 1];
+ PSTRING_LIST_NODE dirItem;
+ LPTSTR p;
+
+ //
+ // If this is the current windows directory, skip it.
+ //
+
+ GetWindowsDirectory(windowsDir, ARRAYLEN(windowsDir));
+
+ if (0 == lstrcmpi(Directory, windowsDir))
+ {
+ return TRUE;
+ }
+
+ //
+ // Save the directory away in a linked list
+ //
+
+ dirItem = (PSTRING_LIST_NODE)LocalAlloc(
+ LMEM_FIXED | LMEM_ZEROINIT,
+ sizeof(STRING_LIST_NODE));
+ if (dirItem == NULL)
+ {
+ return FALSE;
+ }
+
+ p = (LPTSTR)LocalAlloc(LMEM_FIXED, (lstrlen(Directory)+1) * sizeof(TCHAR));
+ if (p == NULL)
+ {
+ LocalFree(dirItem);
+ return FALSE;
+ }
+
+ dirItem->String = p;
+ lstrcpy(p, Directory);
+
+ // Update the global chain of found directories
+
+ dirItem->Next = FoundDirectoryList;
+ FoundDirectoryList = dirItem;
+
+ FoundDirectoryCount++;
+
+ return TRUE;
+}
+
+
+VOID
+FdpFreeDirectoryList(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Go through the list of directories containing system hives and
+ free the entries.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PSTRING_LIST_NODE n;
+ PSTRING_LIST_NODE p = FoundDirectoryList;
+
+ while (p)
+ {
+ n = p->Next;
+ if (p->String)
+ {
+ LocalFree(p->String);
+ }
+ LocalFree(p);
+ p = n;
+ }
+
+ FoundDirectoryCount = 0;
+ FoundDirectoryList = NULL;
+}
+
+
+BOOL CALLBACK
+FdpScanningDirsDlgProc(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Display the "scanning" dialog, then when the IDLE message arrives
+ process all drive letters and search for system hives.
+
+Arguments:
+
+ Windows dialog proc
+
+Return Value:
+
+ Windows dialog proc
+
+--*/
+
+{
+ TCHAR letterColon[3];
+ TCHAR letter;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+
+ CenterDialogInFrame(hwnd);
+ break;
+
+ case WM_ENTERIDLE:
+
+ //
+ // Sent to us by the main window after the dialog is displayed.
+ // Perform the search here.
+ //
+ ConfigurationSearchIdleTrigger = FALSE;
+
+ UserCancelled = FALSE;
+
+ lstrcpy(letterColon, TEXT("?:"));
+ for (letter = TEXT('A'); letter <= TEXT('Z'); letter++)
+ {
+ if (!ScanDrive[letter - TEXT('A')])
+ {
+ continue;
+ }
+
+ letterColon[0] = letter;
+
+ if (!FdpSearchTreeForSystemHives(letterColon,
+ FdpFoundHiveCallback,
+ hwnd))
+ {
+ EndDialog(hwnd, IDCANCEL);
+ return TRUE;
+ }
+
+ }
+
+ EndDialog(hwnd, IDOK);
+ break;
+
+ case WM_COMMAND:
+
+ switch (LOWORD(wParam))
+ {
+ case IDCANCEL:
+
+ UserCancelled = TRUE;
+ break;
+
+ default:
+
+ return FALSE;
+ }
+ break;
+
+ default:
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+BOOL CALLBACK
+FdpSelectDirDlgProc(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Using the list of directories containing system hives, display the
+ selections to the user and save the selected item if the user so
+ chooses.
+
+Arguments:
+
+ Windows dialog proc.
+
+Return Value:
+
+ Windows dialog proc.
+
+--*/
+
+{
+ static HWND hwndListBox;
+
+ PSTRING_LIST_NODE stringNode;
+ LONG i;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+
+ CenterDialogInFrame(hwnd);
+
+ //
+ // Add each item in the directory list to the listbox
+ //
+
+ hwndListBox = GetDlgItem(hwnd, IDC_LISTBOX);
+
+ for (stringNode = FoundDirectoryList;
+ NULL != stringNode;
+ stringNode = stringNode->Next)
+ {
+ i = SendMessage(hwndListBox, LB_ADDSTRING , 0, (LONG)stringNode->String);
+ SendMessage(hwndListBox, LB_SETITEMDATA, i, (LONG)stringNode );
+ }
+
+ // select the zeroth item
+ SendMessage(hwndListBox, LB_SETCURSEL, 0, 0);
+
+ break;
+
+ case WM_COMMAND:
+
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+
+ //
+ // Get the index of the current list box selection and the
+ // pointer to the string node associated with it.
+ //
+
+ i = SendMessage(hwndListBox, LB_GETCURSEL, 0, 0);
+ EndDialog(hwnd, SendMessage(hwndListBox, LB_GETITEMDATA, i, 0));
+ break;
+
+ case IDCANCEL:
+
+ EndDialog(hwnd, (int)NULL);
+ break;
+
+ default:
+
+ return FALSE;
+ }
+ break;
+
+ default:
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+BOOL
+DoMigratePreviousFtConfig(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Allow the user to move the disk config info from a different Windows NT
+ installation into the current registry.
+
+ For each fixed disk volume, scan it for system hives and present the
+ results to the user so he can select the installation to migrate.
+
+ Then load the system hive from that instllation (system.alt if the system
+ hive is corrupt, etc) and transfer the DISK:Information binary blob.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE if error or user cancelled, TRUE if info was migrated and reboot
+ is required.
+
+--*/
+
+{
+ LONG ec;
+ LONG ret;
+ TCHAR letter;
+ TCHAR letterColon[4];
+ PSTRING_LIST_NODE stringNode;
+
+ //
+ // Tell the user what this will do and prompt for confirmation
+ //
+
+ if (IDYES != ConfirmationDialog(
+ MSG_CONFIRM_MIGRATE_CONFIG,
+ MB_ICONEXCLAMATION | MB_YESNO))
+ {
+ return FALSE;
+ }
+
+ ProcessPendingMessages();
+
+ //
+ // Figure out which drives are relevent
+ //
+
+ SetCursor(g_hCurWait);
+
+ RtlZeroMemory(ScanDrive, sizeof(ScanDrive));
+ lstrcpy(letterColon, TEXT("?:\\"));
+ for (letter = TEXT('A'); letter <= TEXT('Z'); letter++)
+ {
+ letterColon[0] = letter;
+
+ if (GetDriveType(letterColon) == DRIVE_FIXED)
+ {
+ ScanDrive[letter - TEXT('A')] = TRUE;
+ }
+ }
+
+ SetCursor(g_hCurNormal);
+
+ //
+ // Create a window that will list the directories being scanned, to
+ // keep the user entertained.
+ //
+ ConfigurationSearchIdleTrigger = TRUE;
+
+ ret = DialogBox(g_hInstance,
+ MAKEINTRESOURCE(IDD_SIMPLETEXT),
+ g_hwndFrame,
+ FdpScanningDirsDlgProc);
+
+ if (ret == IDCANCEL)
+ {
+ FdpFreeDirectoryList();
+ return FALSE;
+ }
+
+ ProcessPendingMessages();
+
+ if (0 == FoundDirectoryCount)
+ {
+ InfoDialog(MSG_NO_OTHER_NTS);
+ return FALSE;
+ }
+
+ //
+ // Display a dialog box that allows the user to select one of the
+ // directories we found.
+ //
+
+ stringNode = (PSTRING_LIST_NODE)DialogBox(g_hInstance,
+ MAKEINTRESOURCE(IDD_SELDIR),
+ g_hwndFrame,
+ FdpSelectDirDlgProc);
+
+ if (stringNode == NULL)
+ {
+ FdpFreeDirectoryList();
+ return FALSE;
+ }
+
+ //
+ // User made a selection. One last confirmation.
+ //
+
+ if (IDYES != ConfirmationDialog(
+ MSG_ABSOLUTELY_SURE,
+ MB_ICONEXCLAMATION | MB_YESNO))
+ {
+ FdpFreeDirectoryList();
+ return FALSE;
+ }
+
+ ProcessPendingMessages();
+
+ SetCursor(g_hCurWait);
+
+ lstrcpy(Pattern, stringNode->String);
+ lstrcat(Pattern, ConfigRegistryPath);
+
+ ec = FdTransferOldDiskInfoToRegistry(Pattern);
+ if (ec != NO_ERROR)
+ {
+ lstrcat(Pattern, TEXT(".alt"));
+ ec = FdTransferOldDiskInfoToRegistry(Pattern);
+ }
+ FdpFreeDirectoryList();
+ SetCursor(g_hCurNormal);
+
+ if (ec != NO_ERROR)
+ {
+ if (ec == ERROR_FILE_NOT_FOUND)
+ {
+ ErrorDialog(MSG_NO_DISK_INFO);
+ }
+ else if (ec == ERROR_SHARING_VIOLATION)
+ {
+ ErrorDialog(MSG_DISK_INFO_BUSY);
+ }
+ else
+ {
+ ErrorDialog(ec);
+ }
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+
+BOOL
+DoRestoreFtConfig(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Restore previously saved disk configuration information into the
+ active registry.
+
+ The saved config info will come from a floppy that the user is
+ prompted to insert.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE if error or user cancelled, TRUE if info was restored and reboot
+ is required.
+
+--*/
+
+{
+ LONG ec;
+ TCHAR caption[256];
+ UINT errorMode;
+
+ //
+ // Get confirmation
+ //
+
+ if (IDYES != ConfirmationDialog(
+ MSG_CONFIRM_RESTORE_CONFIG,
+ MB_ICONEXCLAMATION | MB_YESNO))
+ {
+ return FALSE;
+ }
+
+ //
+ // Get the diskette into A:.
+ //
+
+ errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+ LoadString(g_hInstance, IDS_INSERT_DISK, caption, ARRAYLEN(caption));
+ if (CommonDialogNoArglist(
+ MSG_INSERT_REGSAVEDISK,
+ caption,
+ MB_OKCANCEL | MB_TASKMODAL)
+ != IDOK)
+ {
+ return FALSE;
+ }
+
+ ProcessPendingMessages();
+
+ SetCursor(g_hCurWait);
+
+ //
+ // If there is no file called SYSTEM on a:\, it appears that the registry
+ // creates one and then keeps it open. To avoid this, check to see
+ // whether there is one first.
+ //
+
+ if (GetFileAttributes(TEXT("A:\\SYSTEM")) == -1)
+ {
+ ec = ERROR_FILE_NOT_FOUND;
+ }
+ else
+ {
+ ec = FdTransferOldDiskInfoToRegistry(TEXT("A:\\SYSTEM"));
+ }
+
+ SetErrorMode(errorMode);
+ SetCursor(g_hCurNormal);
+
+ if (ec != NO_ERROR)
+ {
+ ErrorDialog(ec);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+VOID
+DoSaveFtConfig(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Allow the user to update the registry save diskette with the currently
+ defined disk configuration. The saved info excludes any changes made
+ during this session of disk manager.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LONG err;
+ LONG errAlt;
+ LPTSTR systemHiveName = TEXT("a:\\system");
+ HKEY hkey;
+ TCHAR caption[256];
+ DWORD disposition;
+ UINT errorMode;
+
+ //
+ // Get a diskette into A:.
+ //
+
+ LoadString(g_hInstance, IDS_INSERT_DISK, caption, ARRAYLEN(caption));
+ if (CommonDialogNoArglist(
+ MSG_INSERT_REGSAVEDISK2,
+ caption,
+ MB_OKCANCEL | MB_TASKMODAL)
+ != IDOK)
+ {
+ return;
+ }
+
+ //
+ // Decide what to do based on the presence of a a:\system. If that file
+ // is present, just update the DISK entry in it. If it is not present,
+ // then blast out the entire system hive.
+ //
+
+ errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+ ProcessPendingMessages();
+
+ SetCursor(g_hCurWait);
+
+ if (GetFileAttributes(systemHiveName) == -1)
+ {
+ BOOLEAN oldPrivState;
+ NTSTATUS status;
+
+ //
+ // Blast the entire system hive out to the floppy.
+ // Start by attempting to get backup privilege.
+ //
+
+ status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE,
+ TRUE,
+ FALSE,
+ &oldPrivState);
+
+ err = RtlNtStatusToDosError(status);
+ if (err == NO_ERROR)
+ {
+ err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("system"),
+ REG_OPTION_RESERVED,
+ KEY_READ,
+ &hkey);
+
+ if (err == NO_ERROR)
+ {
+ err = RegSaveKey(hkey, systemHiveName, NULL);
+
+ RegCloseKey(hkey);
+ }
+
+ if (!oldPrivState)
+ {
+ RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, FALSE, FALSE, &oldPrivState);
+ }
+ }
+ }
+ else
+ {
+ PVOID diskInfo;
+ ULONG diskInfoSize;
+
+ //
+ // Load up the saved system hive
+ //
+
+ err = FdpLoadHiveIntoRegistry(systemHiveName);
+ if (err == NO_ERROR)
+ {
+ //
+ // Get the current DISK information
+ //
+
+ err = FdpGetDiskInfoFromKey(TEXT("system"), &diskInfo, &diskInfoSize);
+ if (err == NO_ERROR)
+ {
+ //
+ // Place the current disk information into the saved hive
+ //
+ err = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
+ TEMP_KEY_NAME TEXT("\\") DISK_KEY_NAME,
+ 0,
+ TEXT("Disk and fault tolerance information."),
+ REG_OPTION_NON_VOLATILE,
+ KEY_WRITE,
+ NULL,
+ &hkey,
+ &disposition);
+
+ if (err == NO_ERROR)
+ {
+ err = RegSetValueEx(hkey,
+ DISK_VALUE_NAME,
+ REG_OPTION_RESERVED,
+ REG_BINARY,
+ (PBYTE)diskInfo,
+ diskInfoSize);
+
+ RegFlushKey(hkey);
+ RegCloseKey(hkey);
+ }
+
+ LocalFree(diskInfo);
+ }
+
+ errAlt = FdpUnloadHiveFromRegistry();
+
+ if (err == NO_ERROR && errAlt != NO_ERROR)
+ {
+ err = errAlt;
+ }
+ }
+ }
+
+ SetCursor(g_hCurNormal);
+ SetErrorMode(errorMode);
+
+ if (err == NO_ERROR)
+ {
+ InfoDialog(MSG_CONFIG_SAVED_OK);
+ }
+ else
+ {
+ ErrorDialog(err);
+ }
+
+ return;
+}
diff --git a/private/utils/windisk/src/ftreg.dlg b/private/utils/windisk/src/ftreg.dlg
new file mode 100644
index 000000000..bb2528128
--- /dev/null
+++ b/private/utils/windisk/src/ftreg.dlg
@@ -0,0 +1,22 @@
+IDD_SELDIR DIALOG 6, 18, 154, 127
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+CAPTION "Get Previous Disk Configuration"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LISTBOX IDC_LISTBOX, 16, 28, 122, 66, LBS_SORT | WS_VSCROLL |
+ WS_TABSTOP
+ LTEXT "Select a Windows NT installation:", 102, 10, 10, 118, 8
+ PUSHBUTTON "OK", IDOK, 29, 107, 40, 14
+ PUSHBUTTON "Cancel", IDCANCEL, 85, 107, 40, 14
+END
+
+IDD_SIMPLETEXT DIALOG 6, 18, 270, 54
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+STYLE WS_POPUP | WS_VISIBLE | WS_CLIPCHILDREN | WS_CAPTION
+CAPTION "Searching for Windows NT Installations"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "", IDC_SIMPLE_TEXT_LINE, 10, 10, 250, 8
+ DEFPUSHBUTTON "Cancel", IDCANCEL, 114, 31, 40, 14, WS_GROUP
+END
diff --git a/private/utils/windisk/src/ftreg.h b/private/utils/windisk/src/ftreg.h
new file mode 100644
index 000000000..76bfe95e0
--- /dev/null
+++ b/private/utils/windisk/src/ftreg.h
@@ -0,0 +1,22 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: ftreg.h
+//
+// Contents: Resource constants
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __FTREG_H__
+#define __FTREG_H__
+
+#define IDC_LISTBOX 101
+#define IDD_SELDIR 100
+#define IDC_SIMPLE_TEXT_LINE 201
+#define IDD_SIMPLETEXT 300
+
+#endif // __FTREG_H__
diff --git a/private/utils/windisk/src/ftreg.hxx b/private/utils/windisk/src/ftreg.hxx
new file mode 100644
index 000000000..334fb55e6
--- /dev/null
+++ b/private/utils/windisk/src/ftreg.hxx
@@ -0,0 +1,34 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: ftreg.hxx
+//
+// Contents: Declarations for registry calls related to fault tolerance
+//
+// History: 2-Jan-92 TedM Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __FTREG_HXX__
+#define __FTREG_HXX__
+
+//////////////////////////////////////////////////////////////////////////////
+
+BOOL
+DoMigratePreviousFtConfig(
+ VOID
+ );
+
+BOOL
+DoRestoreFtConfig(
+ VOID
+ );
+
+VOID
+DoSaveFtConfig(
+ VOID
+ );
+
+#endif // __FTREG_HXX__
diff --git a/private/utils/windisk/src/genlpage.cxx b/private/utils/windisk/src/genlpage.cxx
new file mode 100644
index 000000000..16aad58fa
--- /dev/null
+++ b/private/utils/windisk/src/genlpage.cxx
@@ -0,0 +1,726 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: genlpage.cxx
+//
+// Contents: Implementation of General property page of volumes in Disk
+// Administrator applet
+//
+// History: 28-Jul-93 BruceFo Created from WilliamW's sharing applet
+//
+//--------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include <controls.hxx>
+#include <util.hxx>
+
+#include "graph.hxx"
+#include "drives.hxx"
+#include "fs.hxx"
+#include "fmifs.hxx"
+#include "format.hxx"
+#include "chkdsk.hxx"
+
+#include "genlpage.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+VOID
+SetNumber(
+ IN HWND hwnd,
+ IN LARGE_INTEGER Value,
+ IN int idControl,
+ IN UINT widDecoration
+ );
+
+VOID
+SetBytes(
+ IN HWND hwnd,
+ IN LARGE_INTEGER Value,
+ IN int idControl
+ );
+
+VOID
+SetMB(
+ IN HWND hwnd,
+ IN LARGE_INTEGER Value,
+ IN int idControl
+ );
+
+//////////////////////////////////////////////////////////////////////////////
+
+//+-------------------------------------------------------------------------
+//
+// Method: PAGE_DLGPROC
+//
+// Synopsis: Property page dialog procedure
+//
+//--------------------------------------------------------------------------
+
+BOOL CALLBACK
+PAGE_DLGPROC(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ PAGE_CLASS* pPropPage;
+
+ if (msg == WM_INITDIALOG)
+ {
+ pPropPage = new PAGE_CLASS(hwnd);
+ SetWindowLong(hwnd, GWL_USERDATA, (LPARAM)pPropPage);
+ }
+ else
+ {
+ pPropPage = (PAGE_CLASS*) GetWindowLong(hwnd, GWL_USERDATA);
+ }
+
+ if (pPropPage != NULL)
+ {
+ return (pPropPage->_DlgProc(hwnd, msg, wParam, lParam));
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+//+-------------------------------------------------------------------------
+//
+// Method: PAGE_CLASS::IsDirty, public
+//
+// Synopsis:
+//
+// Arguments: none
+//
+// Returns: TRUE if page is dirty, FALSE if not
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+BOOL
+PAGE_CLASS::IsDirty(
+ VOID
+ )
+{
+ return _fDirty;
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: PAGE_CLASS::OnApply, public
+//
+// Synopsis: Apply changes to the object's persistent properties
+//
+// Arguments: none
+//
+// Returns: TRUE to allow, FALSE to abort
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+BOOL
+PAGE_CLASS::OnApply(
+ VOID
+ )
+{
+ if (IsDirty())
+ {
+ if (!LoadFmifs())
+ {
+ return TRUE; // can't load fmifs.dll, so bail
+ }
+
+ // then apply it!
+
+ WCHAR label[MAXLABELLEN];
+ Edit_GetText(GetDlgItem(_hwndPage, IDC_GENL_Label), label, ARRAYLEN(label));
+
+ PREGION_DESCRIPTOR regionDescriptor = &SELECTED_REGION(0);
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(regionDescriptor);
+
+ WCHAR driveName[3];
+ driveName[0] = regionData->DriveLetter;
+ driveName[1] = L':';
+ driveName[2] = L'\0';
+
+ if ( (*lpfnSetLabel)(driveName, label) )
+ {
+ RefreshVolumeData();
+ DisplaySpaceValues(_hwndPage);
+ SetDirty(FALSE);
+ }
+ else
+ {
+ // BUGBUG: better message
+ daDebugOut((DEB_ERROR, "Couldn't set label\n"));
+ }
+ }
+
+ return TRUE;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: PAGE_CLASS::_DlgProc, private
+//
+// Synopsis: Dialog Procedure for the general property page
+//
+// Arguments: standard Windows DlgProc
+//
+// Returns: standard Windows DlgProc
+//
+// History: 28-Jan-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+BOOL
+PAGE_CLASS::_DlgProc(
+ HWND hdlg,
+ UINT msg,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ return InitGeneralPage(hdlg, wParam, lParam);
+
+ case WM_COMMAND:
+ {
+ HWND hwndPropertyFrame = GetParent(hdlg);
+
+ switch (LOWORD(wParam))
+ {
+ case IDC_Refresh:
+ //
+ // Note that this "Refresh" option refreshes everything for a
+ // single volume (the one we're looking at), but nothing else. In
+ // particular, it doesn't refresh CD-ROM or other volume data.
+ //
+ RefreshVolumeData(); // refresh the data, redisplay the current view
+ DisplaySpaceValues(hdlg);
+ SetDirty(FALSE);
+ break;
+
+ case IDC_Format:
+ DoFormat(hwndPropertyFrame, FALSE);
+ DisplaySpaceValues(hdlg);
+ SetDirty(FALSE);
+ break;
+
+ case IDC_CheckNow:
+ DoChkdsk(hwndPropertyFrame);
+ DisplaySpaceValues(hdlg);
+ SetDirty(FALSE);
+ break;
+
+ case IDC_GENL_Label:
+ {
+ switch (HIWORD(wParam))
+ {
+ case EN_CHANGE:
+ SetDirty(TRUE);
+ }
+ }
+
+ default:
+
+ return FALSE; // not processed
+ }
+
+ return TRUE; // processed
+ }
+
+ case WM_NOTIFY:
+ {
+ NMHDR* phdr = (NMHDR*)lParam;
+
+ switch (phdr->code)
+ {
+ case PSN_SETACTIVE:
+ break;
+
+ case PSN_KILLACTIVE:
+ SetWindowLong(hdlg, DWL_MSGRESULT, FALSE); //ok to leave
+ break;
+
+ case PSN_QUERYCANCEL:
+ case PSN_RESET: // cancel
+ return FALSE;
+
+ case PSN_HELP:
+ NoHelp(hdlg);
+ return FALSE;
+
+ case PSN_APPLY:
+ if (OnApply())
+ {
+ SetWindowLong(hdlg, DWL_MSGRESULT, FALSE); // changes ok
+ }
+ else
+ {
+ SetWindowLong(hdlg, DWL_MSGRESULT, TRUE); // reject changes
+ }
+ return TRUE;
+
+ }
+
+ return FALSE;
+ }
+
+ case WM_CTLCOLORDLG:
+ case WM_CTLCOLORLISTBOX:
+ case WM_CTLCOLORSCROLLBAR:
+ case WM_CTLCOLORBTN:
+ case WM_CTLCOLORMSGBOX:
+ case WM_CTLCOLORSTATIC:
+ {
+ HDC hdc = (HDC)wParam;
+ SetBkColor(hdc, GetSysColor(COLOR_3DFACE));
+ return (LRESULT)GetStockBrush(LTGRAY_BRUSH);
+ }
+
+ case WM_DESTROY:
+ DeleteFont(_hDlgFont);
+ SetWindowLong(hdlg, GWL_USERDATA, NULL);
+ delete this;
+ break;
+ }
+
+ return FALSE; // not processed
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Method: PAGE_CLASS::SetDirty, private
+//
+// Synopsis: Set the dirty bit
+//
+// Arguments: [fDirty] -- what to set it to
+//
+// Returns: nothing
+//
+// Derivation: none
+//
+// History: 28-Jan-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+VOID
+PAGE_CLASS::SetDirty(
+ BOOL fDirty
+ )
+{
+ if (_fDirty != fDirty)
+ {
+ _fDirty = fDirty;
+
+ if (_fDirty)
+ {
+ PropSheet_Changed(GetParent(_hwndPage),_hwndPage);
+ }
+ else
+ {
+ PropSheet_UnChanged(GetParent(_hwndPage),_hwndPage);
+ }
+ }
+ // else, no change
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Method: PAGE_CLASS::DisplaySpaceValues, private
+//
+// Synopsis: Calculate and display the space values in the page
+//
+// Arguments: [hdlg] -- handle to property page window
+//
+// Returns: nothing
+//
+// History: 15-Dec-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+PAGE_CLASS::DisplaySpaceValues(
+ IN HWND hdlg
+ )
+{
+ UINT driveStatus;
+ ULONG percentUsedTimes10;
+ WCHAR buffer[100];
+
+ PREGION_DESCRIPTOR regionDescriptor = &SELECTED_REGION(0);
+ FDASSERT(NULL != regionDescriptor);
+
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(regionDescriptor);
+
+ if ( 0 == SelectedFreeSpaces
+ && NULL != regionData
+ && !regionData->NewRegion)
+ {
+ driveStatus = STATUS_OK;
+
+ //
+ // Set drive status
+ //
+
+ //BUGBUG: status is always "ready"
+ LoadString(g_hInstance, IDS_READY, buffer, ARRAYLEN(buffer));
+ SetDlgItemText(hdlg, IDC_DriveStatus, buffer);
+
+ //
+ // Set drive label. Set maximum label limit, clear the
+ // "modified" flag, and select the label.
+ //
+
+ HWND hctlLabel = GetDlgItem(hdlg, IDC_GENL_Label);
+ Edit_SetText(hctlLabel, regionData->VolumeLabel);
+ Edit_Enable(hctlLabel, TRUE);
+ FileSystemInfoType* pFSInfo = FindFileSystemInfo(regionData->TypeName);
+ if (NULL == pFSInfo)
+ {
+ Edit_LimitText(hctlLabel, MAXLABELLEN-1);
+ }
+ else
+ {
+ Edit_LimitText(hctlLabel, pFSInfo->cMaxLabelLen);
+ }
+
+ Edit_SetSel(hctlLabel, 0, (LPARAM)-1);
+ Edit_SetModify(GetDlgItem(hdlg, IDC_GENL_Label), FALSE);
+
+ //
+ // Set file system type
+ //
+
+ SetDlgItemText(hdlg, IDC_FileSystem, regionData->TypeName);
+
+ //
+ // Set the "drive letter" static control
+ //
+
+ WCHAR driveName[3];
+ driveName[0] = regionData->DriveLetter;
+
+ driveName[1] = L':';
+ driveName[2] = L'\0';
+ SetDlgItemText(hdlg, IDC_DriveLetter, driveName);
+
+ //
+ // Set the free/used/capacity values, including the graph
+ //
+
+ LARGE_INTEGER freeSpaceInBytes;
+ LARGE_INTEGER usedSpaceInBytes;
+ LARGE_INTEGER capacityInBytes;
+
+ freeSpaceInBytes = regionData->FreeSpaceInBytes;
+ capacityInBytes = regionData->TotalSpaceInBytes;
+ usedSpaceInBytes.QuadPart = capacityInBytes.QuadPart - freeSpaceInBytes.QuadPart;
+
+ SetBytes(hdlg, freeSpaceInBytes, IDC_FreeSpace);
+ SetBytes(hdlg, usedSpaceInBytes, IDC_UsedSpace);
+ SetBytes(hdlg, capacityInBytes, IDC_Capacity);
+
+ LONGLONG oneMeg = UInt32x32To64(1024,1024);
+
+ if (capacityInBytes.QuadPart > oneMeg)
+ {
+ LARGE_INTEGER freeSpaceInMB;
+ LARGE_INTEGER usedSpaceInMB;
+ LARGE_INTEGER capacityInMB;
+
+ freeSpaceInMB.QuadPart = freeSpaceInBytes.QuadPart / oneMeg;
+ capacityInMB.QuadPart = capacityInBytes.QuadPart / oneMeg;
+ usedSpaceInMB.QuadPart = usedSpaceInBytes.QuadPart / oneMeg;
+
+ SetMB(hdlg, freeSpaceInMB, IDC_FreeSpaceMB);
+ SetMB(hdlg, usedSpaceInMB, IDC_UsedSpaceMB);
+ SetMB(hdlg, capacityInMB, IDC_CapacityMB);
+ }
+ else
+ {
+ //
+ // Clear the "(n MB)" strings if the capacity of the drive is < 1MB
+ //
+ buffer[0] = L'\0';
+ SetDlgItemText(hdlg, IDC_FreeSpaceMB, buffer);
+ SetDlgItemText(hdlg, IDC_UsedSpaceMB, buffer);
+ SetDlgItemText(hdlg, IDC_CapacityMB, buffer);
+ }
+
+ percentUsedTimes10 = (ULONG)((usedSpaceInBytes.QuadPart * (LONGLONG)1000) / capacityInBytes.QuadPart);
+ }
+ else
+ {
+ driveStatus = STATUS_UNKNOWN;
+
+ //
+ // No info: clear the number fields
+ //
+
+ LoadString(g_hInstance, IDS_NOTREADY, buffer, ARRAYLEN(buffer));
+ SetDlgItemText(hdlg, IDC_DriveStatus, buffer);
+
+ buffer[0] = L'\0';
+
+ SetDlgItemText(hdlg, IDC_GENL_Label, buffer);
+ Edit_Enable(GetDlgItem(hdlg, IDC_GENL_Label), FALSE);
+
+ SetDlgItemText(hdlg, IDC_DriveLetter, buffer);
+ SetDlgItemText(hdlg, IDC_FileSystem, buffer);
+ SetDlgItemText(hdlg, IDC_FreeSpace, buffer);
+ SetDlgItemText(hdlg, IDC_FreeSpaceMB, buffer);
+ SetDlgItemText(hdlg, IDC_UsedSpace, buffer);
+ SetDlgItemText(hdlg, IDC_UsedSpaceMB, buffer);
+ SetDlgItemText(hdlg, IDC_Capacity, buffer);
+ SetDlgItemText(hdlg, IDC_CapacityMB, buffer);
+
+ EnableWindow(GetDlgItem(hdlg, IDC_Refresh), FALSE);
+ EnableWindow(GetDlgItem(hdlg, IDC_Format), FALSE);
+ EnableWindow(GetDlgItem(hdlg, IDC_CheckNow), FALSE);
+
+ percentUsedTimes10 = 0;
+ }
+
+ //
+ // Now set the graph
+ //
+
+ UINT driveType = DRIVE_FIXED; // GetDriveType(driveName);
+
+ HBITMAP hBigBitmap = CreateGraphBitmap(
+ g_hInstance,
+ GetDlgItem(hdlg, IDC_Graph),
+ driveType,
+ driveStatus,
+ percentUsedTimes10
+ );
+
+ SendDlgItemMessage(
+ hdlg,
+ IDC_Graph,
+ BMPCTL_SETBITMAP,
+ (WPARAM)hBigBitmap,
+ 0);
+
+ SetDirty(FALSE);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Method: PAGE_CLASS::InitGeneralPage, private
+//
+// Synopsis: Initialize the data displayed on the General property
+// page based on the current Disk Administrator selection
+//
+// Arguments: DlgProc stuff
+//
+// Returns: DlgProc stuff for WM_INITDIALOG
+//
+// History: 11-Oct-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+BOOL
+PAGE_CLASS::InitGeneralPage(
+ IN HWND hdlg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ static UINT s_idTextControls[] =
+ {
+ IDC_DriveStatus,
+ IDC_FileSystem,
+ IDC_DriveLetter,
+ IDC_FreeSpace,
+ IDC_FreeSpaceMB,
+ IDC_UsedSpace,
+ IDC_UsedSpaceMB,
+ IDC_Capacity,
+ IDC_CapacityMB,
+ IDC_Refresh,
+ IDC_CheckNow,
+ IDC_Format,
+ IDC_GENL_Label,
+
+ IDC_GENL_1,
+ IDC_GENL_2,
+ IDC_GENL_3,
+ IDC_GENL_4,
+ IDC_GENL_5,
+ IDC_GENL_6,
+ IDC_GENL_7,
+
+ 0
+ };
+
+ _hDlgFont = KillBold(hdlg, s_idTextControls);
+
+ //
+ // Set the legend for the graph
+ //
+
+ SendDlgItemMessage(
+ hdlg,
+ IDC_UsedColor,
+ BOXCTL_SETCOLOR,
+ (WPARAM)GraphColors[I_USEDCOLOR],
+ 0);
+
+ SendDlgItemMessage(
+ hdlg,
+ IDC_FreeColor,
+ BOXCTL_SETCOLOR,
+ (WPARAM)GraphColors[I_FREECOLOR],
+ 0);
+
+ //
+ // Disable chkdsk if we can't chkdsk (e.g., fmifs.dll doesn't support it)
+ //
+
+ if (MF_GRAYED & GetMenuState(g_hmenuFrame, IDM_VOL_CHKDSK, MF_BYCOMMAND))
+ {
+ EnableWindow(GetDlgItem(hdlg, IDC_CheckNow), FALSE);
+ }
+
+ //
+ // Fill the space numbers, and display the graph
+ //
+
+ DisplaySpaceValues(hdlg);
+
+ return TRUE; // didn't set focus to any control
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: SetNumber
+//
+// Synopsis: Helper function: set a control to a number.
+//
+// Arguments: [hwnd] -- handle of property page
+// [Value] -- number to set
+// [idControl] -- control ID to put number in
+// [widDecoration] -- a resource ID for a 'printf' string with
+// one %s element that will be replaced by the string
+// representation of the number, before being set to the
+// control.
+//
+// Returns: nothing
+//
+// History: 15-Dec-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+SetNumber(
+ IN HWND hwnd,
+ IN LARGE_INTEGER Value,
+ IN int idControl,
+ IN UINT widDecoration
+ )
+{
+ WCHAR decoration[100];
+ WCHAR buffer[100]; // buffer for numbers
+ WCHAR buf2[100]; // buffer for final text
+
+ LoadString(g_hInstance, widDecoration, decoration, ARRAYLEN(decoration));
+
+ NTSTATUS status = LargeIntegerToUnicodeChar(
+ &Value,
+ 10,
+ ARRAYLEN(buffer),
+ buffer
+ );
+ InsertSeparators(buffer);
+ wsprintf(buf2, decoration, buffer);
+ SetDlgItemText(hwnd, idControl, buf2);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: SetBytes
+//
+// Synopsis: Set a bytes control
+//
+// Arguments: [hwnd] -- handle of property page
+// [Value] -- number to set
+// [idControl] -- control ID to put number in
+//
+// Returns: nothing
+//
+// History: 15-Dec-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+SetBytes(
+ IN HWND hwnd,
+ IN LARGE_INTEGER Value,
+ IN int idControl
+ )
+{
+ SetNumber(hwnd, Value, idControl, IDS_BYTES_DECORATION);
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: SetMB
+//
+// Synopsis: Set a MB control
+//
+// Arguments: [hwnd] -- handle of property page
+// [Value] -- number to set
+// [idControl] -- control ID to put number in
+//
+// Returns: nothing
+//
+// History: 15-Dec-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+SetMB(
+ IN HWND hwnd,
+ IN LARGE_INTEGER Value,
+ IN int idControl
+ )
+{
+ SetNumber(hwnd, Value, idControl, IDS_MEG_DECORATION);
+}
diff --git a/private/utils/windisk/src/genlpage.hxx b/private/utils/windisk/src/genlpage.hxx
new file mode 100644
index 000000000..25a3daa47
--- /dev/null
+++ b/private/utils/windisk/src/genlpage.hxx
@@ -0,0 +1,98 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: genlpage.hxx
+//
+// Contents: General property page of volumes in
+// Disk Administrator applet
+//
+// History: 28-Jul-93 BruceFo Created from WilliamW's sharing applet
+//
+//--------------------------------------------------------------------------
+
+#ifndef __GENLPAGE_HXX__
+#define __GENLPAGE_HXX__
+
+#include "resids.h"
+#include "dialogs.h"
+
+#undef PAGE_DLGPROC
+#undef PAGE_CLASS
+
+#define PAGE_DLGPROC GeneralPageDlgProc
+#define PAGE_CLASS CGeneralPage
+
+
+class PAGE_CLASS
+{
+public:
+
+ PAGE_CLASS(
+ IN HWND hwndPage
+ )
+ :
+ _hwndPage(hwndPage),
+ _hDlgFont(NULL)
+ {
+ }
+
+ ~PAGE_CLASS()
+ {
+ }
+
+ friend BOOL CALLBACK
+ PAGE_DLGPROC(
+ HWND hWnd,
+ UINT msg,
+ WPARAM wParam,
+ LPARAM lParam);
+
+ BOOL
+ IsDirty(
+ VOID
+ );
+
+ BOOL
+ OnApply(
+ VOID
+ );
+
+private:
+
+ BOOL
+ _DlgProc(
+ IN HWND hWnd,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+ VOID
+ SetDirty(
+ BOOL fDirty
+ );
+
+ VOID
+ DisplaySpaceValues(
+ IN HWND hwnd
+ );
+
+ BOOL
+ InitGeneralPage(
+ IN HWND hwnd,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+ //
+ // Data
+ //
+
+ BOOL _fDirty;
+ HFONT _hDlgFont;
+ HWND _hwndPage;
+};
+
+#endif // __GENLPAGE_HXX__
diff --git a/private/utils/windisk/src/global.hxx b/private/utils/windisk/src/global.hxx
new file mode 100644
index 000000000..f6191a33b
--- /dev/null
+++ b/private/utils/windisk/src/global.hxx
@@ -0,0 +1,233 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: global.hxx
+//
+// Contents: Global data declarations
+//
+// History: 7-Jan-92 TedM Created
+// 7-Jan-94 BruceFo Incorporated BobRi's DoubleSpace and Commit
+// changes
+//
+//----------------------------------------------------------------------------
+
+#ifndef __GLOBAL_HXX__
+#define __GLOBAL_HXX__
+
+//
+// from data.cxx
+//
+
+extern HINSTANCE g_hInstance;
+extern HWND g_hwndFrame;
+extern HWND g_hwndList;
+extern HWND g_hwndToolbar;
+
+extern HMENU g_hmenuFrame; // the frame window's hmenu
+
+extern HBITMAP g_hBitmapSmallDisk;
+extern HBITMAP g_hBitmapRemovableDisk;
+extern HBITMAP g_hBitmapSmallCdRom;
+extern HFONT g_hFontGraph;
+extern HFONT g_hFontGraphBold;
+extern HFONT g_hFontStatus;
+extern HFONT g_hFontLegend;
+
+extern HBRUSH g_Brushes[BRUSH_ARRAY_SIZE];
+extern HBRUSH g_hBrushFreeLogical;
+extern HBRUSH g_hBrushFreePrimary;
+extern HPEN g_hPenNull;
+extern HPEN g_hPenThinSolid;
+extern HCURSOR g_hCurWait;
+extern HCURSOR g_hCurNormal;
+
+extern PBOOLEAN IsDiskRemovable;
+extern PWCHAR RemovableDiskReservedDriveLetters;
+extern PDISKSTATE* DiskArray;
+extern ULONG BootDiskNumber;
+extern ULONG BootPartitionNumber;
+
+extern int BrushHatches[BRUSH_ARRAY_SIZE];
+extern int BrushColors[BRUSH_ARRAY_SIZE];
+
+extern COLORREF AvailableColors[NUM_AVAILABLE_COLORS];
+extern int AvailableHatches[NUM_AVAILABLE_HATCHES];
+
+extern DWORD GraphWidth;
+extern DWORD GraphHeight;
+extern DWORD BarTopYOffset;
+extern DWORD BarBottomYOffset;
+extern DWORD BarHeight;
+
+extern DWORD dxDriveLetterStatusArea;
+
+extern DWORD dxBarTextMargin;
+extern DWORD dyBarTextLine;
+extern DWORD BarLeftX;
+extern DWORD BarWidth;
+extern DWORD BarWidthMargin;
+extern DWORD BarWidthMinimum;
+
+extern DWORD MinimumWindowWidth;
+
+extern DWORD xSmallDisk;
+extern DWORD ySmallDisk;
+extern DWORD dxSmallDisk;
+extern DWORD dySmallDisk;
+
+extern DWORD xRemovableDisk;
+extern DWORD yRemovableDisk;
+extern DWORD dxRemovableDisk;
+extern DWORD dyRemovableDisk;
+
+extern DWORD xSmallCdRom;
+extern DWORD ySmallCdRom;
+extern DWORD dxSmallCdRom;
+extern DWORD dySmallCdRom;
+
+extern ULONG g_MinimumRegionSize;
+
+extern PDISKSTATE SingleSel;
+extern DWORD SingleSelIndex;
+
+extern PWSTR g_HelpFile;
+
+extern ULONG DiskCount;
+
+extern ULONG CdRomCount;
+extern PCDROM_DESCRIPTOR CdRomArray;
+
+extern LPTSTR DiskN;
+extern LPTSTR CdRomN;
+extern PWSTR wszUnformatted;
+extern PWSTR wszUnknown;
+
+extern BOOL RegistryChanged;
+extern BOOL RestartRequired;
+
+extern BOOL ConfigurationSearchIdleTrigger;
+extern BOOL g_IsLanmanNt;
+extern BOOL g_AllowCdRom;
+
+extern VIEW_TYPE g_WhichView;
+extern HWND g_hwndLV;
+
+extern BOOL g_SettingListviewState;
+
+extern DWORD g_wLegendItem;
+extern DWORD g_dyLegendSep;
+
+extern DWORD g_dyBorder;
+extern DWORD g_dyToolbar;
+extern DWORD g_dyStatus;
+extern DWORD g_dyLegend;
+
+extern BOOL g_Toolbar;
+extern BOOL g_StatusBar;
+extern BOOL g_Legend;
+
+extern DISK_TYPE g_DiskDisplayType;
+
+extern COLORREF GraphColors[];
+
+//
+// from stleg.cxx
+//
+
+extern PWSTR LegendLabels[LEGEND_STRING_COUNT];
+
+extern WCHAR StatusTextStat[STATUS_TEXT_SIZE];
+extern WCHAR StatusTextSize[STATUS_TEXT_SIZE];
+extern WCHAR StatusTextDrlt[3];
+extern WCHAR StatusTextType[STATUS_TEXT_SIZE];
+extern WCHAR StatusTextVoll[STATUS_TEXT_SIZE];
+
+//
+// from windisk.cxx
+//
+
+extern DWORD SelectionCount;
+extern PDISKSTATE SelectedDS[];
+extern ULONG SelectedRG[];
+extern ULONG SelectedFreeSpaces;
+extern ULONG SelectedNonFtPartitions;
+extern PULONG DiskSeenCountArray;
+extern BOOL FtSetSelected;
+extern FT_TYPE FtSelectionType;
+extern BOOL NonFtItemSelected;
+extern BOOL MultipleItemsSelected;
+extern BOOL VolumeSetAndFreeSpaceSelected;
+extern BOOL PartitionAndFreeSpaceSelected;
+extern BOOL PossibleRecover;
+extern ULONG FreeSpaceIndex;
+
+extern BOOL DiskSelected;
+extern BOOL PartitionSelected;
+extern BOOL CdRomSelected;
+extern DWORD CdRomSelectionCount;
+
+extern BOOL AllowFormat;
+extern BOOL AllowVolumeOperations;
+
+extern WCHAR BootDir;
+extern WCHAR SystemDir;
+
+#ifdef WINDISK_EXTENSIONS
+extern BOOL AllowExtensionItems;
+#endif // WINDISK_EXTENSIONS
+
+//
+// from listbox.cxx
+//
+
+extern DWORD LBCursorListBoxItem;
+extern DWORD LBCursorRegion;
+
+//
+// from profile.cxx
+//
+
+extern int ProfileWindowX;
+extern int ProfileWindowY;
+extern int ProfileWindowW;
+extern int ProfileWindowH;
+
+extern int deltaProfileWindowX;
+extern int deltaProfileWindowY;
+extern int deltaProfileWindowW;
+extern int deltaProfileWindowH;
+
+extern BOOL ProfileIsMaximized;
+extern BOOL ProfileIsIconic;
+
+//
+// from dlgs.cxx
+//
+
+extern DWORD SelectedColor[LEGEND_STRING_COUNT];
+extern DWORD SelectedHatch[LEGEND_STRING_COUNT];
+extern WNDPROC OldSizeDlgProc;
+
+//
+// from ft.cxx
+//
+
+extern PFT_OBJECT_SET FtObjectList;
+
+//
+// from help2.cxx
+//
+
+extern BOOL g_fDoingMenuHelp;
+
+//
+// from init.cxx
+//
+
+extern HWND g_InitDlg;
+extern BOOLEAN g_StartedAsIcon;
+extern BOOLEAN g_InitDlgComplete;
+
+#endif // __GLOBAL_HXX__
diff --git a/private/utils/windisk/src/graph.cxx b/private/utils/windisk/src/graph.cxx
new file mode 100644
index 000000000..b91b70eb8
--- /dev/null
+++ b/private/utils/windisk/src/graph.cxx
@@ -0,0 +1,793 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: graph.cxx
+//
+// Contents: Code to generate a nice %free/%used graph on a disk/CD-ROM/
+// memory chip bitmap
+//
+// History: 26-Jan-94 BruceFo Created (derived from Chicago Disks tool)
+//
+//--------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include "graph.hxx"
+
+////////////////////////////////////////////////////////////////////////////
+
+/*
+ * Bits of DrawFlags
+ */
+#define DF_USEBARH 0x0001
+#define DF_USEBARV 0x0002
+#define DF_NEVERFREE 0x0004
+
+typedef struct
+{
+ WORD DrawFlags;
+ int ThreeDHgt;
+ RECT EllipsRect;
+ RECT BarRect;
+
+} DRIVEINFO, *PDRIVEINFO;
+
+
+/*
+ * the following define defines the color in the drive bitmaps
+ * which is mapped to COLOR_MSGBOX to define the "background"
+ * part of the bitmap.
+ */
+#define COLORCHNGTOSCREEN RGB(0,0,255)
+
+////////////////////////////////////////////////////////////////////////////
+
+HBITMAP
+LoadDriveBitmap(
+ IN HINSTANCE hInstance,
+ IN ULONG driveType,
+ IN ULONG driveStatus,
+ OUT PDRIVEINFO pdi
+ );
+
+ULONG
+IntSqrt(
+ IN ULONG Number
+ );
+
+VOID
+DrawPie(
+ IN HDC hDC,
+ IN LPRECT prcItem,
+ IN ULONG uPctX10,
+ IN ULONG uOffset,
+ IN COLORREF* pGraphColors
+ );
+
+BOOL
+ModifyDriveBitmap(
+ IN HWND hwndParent,
+ IN HBITMAP hBigBitmap,
+ IN ULONG driveStatus,
+ IN ULONG percentUsedTimes10,
+ IN PDRIVEINFO pdi
+ );
+
+////////////////////////////////////////////////////////////////////////////
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: LoadDriveBitmap
+//
+// Synopsis: Given a drive type and flags, load a drive bitmap from the
+// resource file.
+//
+// Arguments: [hInstance] -- instance handle of binary with drive bitmap
+// resources
+// [driveType] -- DRIVE_FIXED, etc (see Win32 GetDriveType())
+// [driveStatus] -- STATUS_OK or STATUS_UNKNOWN
+// [pdi] -- Various information about the bitmap is loaded into
+// this structure
+//
+// Returns: handle to the loaded bitmap
+//
+// History: 26-Jan-94 BruceFo Created (derived from Chicago Disks tool)
+//
+//--------------------------------------------------------------------------
+
+HBITMAP
+LoadDriveBitmap(
+ IN HINSTANCE hInstance,
+ IN ULONG driveType,
+ IN ULONG driveStatus,
+ OUT PDRIVEINFO pdi
+ )
+{
+ HRSRC mhand = NULL;
+ HGLOBAL mhandMem;
+ LPWORD hPtr;
+ HBITMAP retbm = 0;
+ WORD retSty = 0;
+ COLORMAP bmColMap;
+
+ bmColMap.from = COLORCHNGTOSCREEN;
+ bmColMap.to = GetSysColor(COLOR_BTNFACE);
+
+ if (driveType == DRIVE_FIXED)
+ {
+ if (driveStatus == STATUS_OK)
+ {
+ mhand = FindResource(
+ hInstance,
+ MAKEINTRESOURCE(ELLIPRESOURCE),
+ MAKEINTRESOURCE(IDB_HARDDISK));
+ retbm = CreateMappedBitmap(hInstance, IDB_HARDDISK, 0, &bmColMap, 1);
+ }
+ }
+ else if (driveType == DRIVE_CDROM)
+ {
+ if (driveStatus == STATUS_OK)
+ {
+ mhand = FindResource(
+ hInstance,
+ MAKEINTRESOURCE(ELLIPRESOURCE),
+ MAKEINTRESOURCE(IDB_CDROM));
+ retbm = CreateMappedBitmap(hInstance, IDB_CDROM, 0, &bmColMap, 1);
+ }
+ }
+
+ mhandMem = LoadResource(hInstance, mhand);
+ if (mhandMem)
+ {
+ hPtr = (LPWORD)LockResource(mhandMem);
+ if (hPtr)
+ {
+ retSty = hPtr[0];
+ if (hPtr[0] == USETYPE_BARH)
+ {
+ pdi->DrawFlags |= DF_USEBARH;
+ }
+ else if (hPtr[0] == USETYPE_BARV)
+ {
+ pdi->DrawFlags |= DF_USEBARV;
+ }
+ else if (hPtr[0] == USETYPE_NONE)
+ {
+ pdi->DrawFlags |= DF_NEVERFREE;
+ }
+ pdi->ThreeDHgt = hPtr[1];
+ pdi->EllipsRect.left = hPtr[2];
+ pdi->EllipsRect.top = hPtr[3];
+ pdi->EllipsRect.right = hPtr[4];
+ pdi->EllipsRect.bottom = hPtr[5];
+ pdi->BarRect.left = hPtr[6];
+ pdi->BarRect.top = hPtr[7];
+ pdi->BarRect.right = hPtr[8];
+ pdi->BarRect.bottom = hPtr[9];
+ UnlockResource(mhandMem);
+ }
+ else
+ {
+ pdi->ThreeDHgt = 0;
+ pdi->EllipsRect.left = 0;
+ pdi->EllipsRect.top = 0;
+ pdi->EllipsRect.right = 0;
+ pdi->EllipsRect.bottom = 0;
+ pdi->BarRect.left = 0;
+ pdi->BarRect.top = 0;
+ pdi->BarRect.right = 0;
+ pdi->BarRect.bottom = 0;
+ }
+ }
+
+ return retbm;
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: IntSqrt
+//
+// Synopsis: Integer square root of a number
+//
+// Arguments: [Number] -- number to take the square root of
+//
+// Returns: The largest integer <= the actual square root of the number
+//
+// History: 26-Jan-94 BruceFo Created (derived from Chicago Disks tool)
+//
+// BUGBUG: better algorithm?
+//
+//--------------------------------------------------------------------------
+
+ULONG
+IntSqrt(
+ IN ULONG Number
+ )
+{
+ for (ULONG i = 1; i*i <= Number; i++)
+ {
+ // nothing
+ }
+
+ return i-1;
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: DrawPie
+//
+// Synopsis: Draws an elliptical pie chart
+//
+// Arguments: [hDC] -- where to draw it
+// [prcItem] -- ?
+// [uPctX10] -- ?
+// [uOffset] -- ?
+// [pGraphColors] -- ?
+//
+// Returns: nothing
+//
+// Modifies: the pie is drawn on the argument DC
+//
+// History: 26-Jan-94 BruceFo Created (derived from Chicago Disks tool)
+//
+//--------------------------------------------------------------------------
+
+VOID
+DrawPie(
+ IN HDC hDC,
+ IN LPRECT prcItem,
+ IN ULONG uPctX10,
+ IN ULONG uOffset,
+ IN COLORREF* pGraphColors
+ )
+{
+ int cx, cy; // center of arc
+ int rx, ry; // "radius" length of ellipse in x & y directions
+ int x, y;
+ int width, height;
+ int uQPctX10;
+ RECT rcItem;
+ HRGN hEllRect, hEllipticRgn, hRectRgn;
+ HBRUSH hBrush, hOldBrush;
+ HPEN hPen, hOldPen;
+
+ width = prcItem->right - prcItem->left;
+ height = (prcItem->bottom - uOffset) - prcItem->top;
+
+ rx = width / 2;
+ cx = prcItem->left + rx - 1;
+ ry = height / 2;
+ cy = prcItem->top + ry - 1;
+ if (rx <= 10 || ry <= 10)
+ {
+ return;
+ }
+
+ rcItem.left = prcItem->left;
+ rcItem.top = prcItem->top;
+ rcItem.right = prcItem->right;
+ rcItem.bottom = prcItem->bottom - uOffset;
+
+ if (uPctX10 > 1000)
+ {
+ uPctX10 = 1000;
+ }
+
+ /* Translate to first quadrant of a Cartesian system
+ */
+ uQPctX10 = (uPctX10 % 500) - 250;
+ if (uQPctX10 < 0)
+ {
+ uQPctX10 = -uQPctX10;
+ }
+
+ /* Calc x and y. I am trying to make the area be the right percentage.
+ ** I don't know how to calculate the area of an elliptical pie slice
+ ** exactly, so I approximate it by using the triangle area instead.
+ */
+ if (uQPctX10 < 120)
+ {
+ x = IntSqrt(
+ ((DWORD)rx * (DWORD)rx * (DWORD)uQPctX10 * (DWORD)uQPctX10)
+ /
+ ((DWORD)uQPctX10 * (DWORD)uQPctX10 + (250L - (DWORD)uQPctX10) * (250L - (DWORD)uQPctX10))
+ );
+
+ y = IntSqrt(
+ ((DWORD)rx * (DWORD)rx - (DWORD)x * (DWORD)x) * (DWORD)ry * (DWORD)ry
+ /
+ ((DWORD)rx * (DWORD)rx)
+ );
+ }
+ else
+ {
+ y = IntSqrt(
+ (DWORD)ry * (DWORD)ry * (250L - (DWORD)uQPctX10) * (250L - (DWORD)uQPctX10)
+ /
+ ((DWORD)uQPctX10 * (DWORD)uQPctX10 + (250L - (DWORD)uQPctX10) * (250L - (DWORD)uQPctX10))
+ );
+
+ x = IntSqrt(
+ ((DWORD)ry * (DWORD)ry - (DWORD)y * (DWORD)y) * (DWORD)rx * (DWORD)rx
+ /
+ ((DWORD)ry * (DWORD)ry)
+ );
+ }
+
+ /* Switch on the actual quadrant
+ */
+ switch (uPctX10 / 250)
+ {
+ case 1:
+ y = -y;
+ break;
+
+ case 2:
+ break;
+
+ case 3:
+ x = -x;
+ break;
+
+ default: // case 0 and case 4
+ x = -x;
+ y = -y;
+ break;
+ }
+
+ /* Now adjust for the center.
+ */
+ x += cx;
+ y += cy;
+
+ /* Draw the shadows using regions (to reduce flicker).
+ */
+ hEllipticRgn = CreateEllipticRgnIndirect(&rcItem);
+ OffsetRgn(hEllipticRgn, 0, uOffset);
+ hEllRect = CreateRectRgn(rcItem.left, cy, rcItem.right, cy+uOffset);
+ hRectRgn = CreateRectRgn(0, 0, 0, 0);
+ CombineRgn(hRectRgn, hEllipticRgn, hEllRect, RGN_OR);
+ OffsetRgn(hEllipticRgn, 0, -(int)uOffset);
+ CombineRgn(hEllRect, hRectRgn, hEllipticRgn, RGN_DIFF);
+
+ /* Always draw the whole area in the free shadow
+ */
+ hBrush = CreateSolidBrush(pGraphColors[I_FREESHADOW]);
+ if (NULL != hBrush)
+ {
+ FillRgn(hDC, hEllRect, hBrush);
+ DeleteBrush(hBrush);
+ }
+
+ /* Draw the used shadow only if the disk is at least half used.
+ */
+ if (uPctX10 > 500
+ && (NULL != (hBrush = CreateSolidBrush(pGraphColors[I_USEDSHADOW])))
+ )
+ {
+ DeleteRgn(hRectRgn);
+ hRectRgn = CreateRectRgn(x, cy, rcItem.right, prcItem->bottom);
+ CombineRgn(hEllipticRgn, hEllRect, hRectRgn, RGN_AND);
+ FillRgn(hDC, hEllipticRgn, hBrush);
+ DeleteBrush(hBrush);
+ }
+
+ DeleteRgn(hRectRgn);
+ DeleteRgn(hEllipticRgn);
+ DeleteObject(hEllRect);
+
+ hPen = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_WINDOWFRAME));
+ hOldPen = SelectPen(hDC, hPen);
+
+ if ((uPctX10 < 100) && (cy == y))
+ {
+ // Less than 10% full, and only a single line of the used color
+ // will be visible.
+
+ hBrush = CreateSolidBrush(pGraphColors[I_FREECOLOR]);
+ hOldBrush = SelectBrush(hDC, hBrush);
+ Ellipse(hDC, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
+ SelectBrush(hDC, hOldBrush);
+ DeleteBrush(hBrush);
+
+ if (uPctX10 != 0)
+ {
+ // There is something there! Draw a single "used" line.
+
+ MoveToEx(hDC, rcItem.left, cy, NULL);
+ LineTo(hDC, cx, cy);
+ }
+ }
+ else if ((uPctX10 > (1000 - 100)) && (cy == y))
+ {
+ // greater than 90% full, and only a single line of the free color
+ // will be visible.
+
+ hBrush = CreateSolidBrush(pGraphColors[I_USEDCOLOR]);
+ hOldBrush = SelectBrush(hDC, hBrush);
+ Ellipse(hDC, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
+ SelectBrush(hDC, hOldBrush);
+ DeleteBrush(hBrush);
+
+ if (uPctX10 != 1000)
+ {
+ // There is something there! Draw a single "free" line.
+
+ MoveToEx(hDC, rcItem.left, cy, NULL);
+ LineTo(hDC, cx, cy);
+ }
+ }
+ else
+ {
+ hBrush = CreateSolidBrush(pGraphColors[I_USEDCOLOR]);
+ hOldBrush = SelectBrush(hDC, hBrush);
+ Ellipse(hDC, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom);
+ SelectBrush(hDC, hOldBrush);
+ DeleteBrush(hBrush);
+
+ hBrush = CreateSolidBrush(pGraphColors[I_FREECOLOR]);
+ hOldBrush = SelectBrush(hDC, hBrush);
+ Pie(hDC, rcItem.left, rcItem.top, rcItem.right, rcItem.bottom,
+ rcItem.left, cy, x, y);
+ SelectBrush(hDC, hOldBrush);
+ DeleteBrush(hBrush);
+ }
+
+ /* Do not draw the lines if the percentage is truely 0 or 100 (completely
+ ** empty disk or completly full disk)
+ */
+ if ((uPctX10 != 0) && (uPctX10 != 1000))
+ {
+ Arc(hDC,
+ rcItem.left,
+ rcItem.top + uOffset,
+ rcItem.right,
+ rcItem.bottom + uOffset,
+ rcItem.left,
+ cy + uOffset,
+ rcItem.right,
+ cy + uOffset - 1);
+
+ // Draw the lines on the left and right side that connect the top
+ // ellipse with the bottom, "highlight" ellipse.
+ MoveToEx(hDC, rcItem.left, cy, NULL);
+ LineTo(hDC, rcItem.left, cy + uOffset);
+ MoveToEx(hDC, rcItem.right - 1, cy, NULL);
+ LineTo(hDC, rcItem.right - 1, cy + uOffset);
+
+ if (uPctX10 > 500)
+ {
+ MoveToEx(hDC, x, y, NULL);
+ LineTo(hDC, x, y + uOffset);
+ }
+ }
+ SelectPen(hDC, hOldPen);
+ DeletePen(hPen);
+}
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: ModifyDriveBitmap
+//
+// Synopsis: Given a drive bitmap, draw a %used/%free indicator on top
+//
+// Arguments: [hwndParent] -- handle to window of parent of bitmap
+// [hBigBitmap] -- handle of bitmap to alter
+// [driveStatus] -- drive status
+// [percentUsedTimes10] -- % used space times 10 (i.e. one decimal
+// point of accuracy)
+// [pdi] -- drawing parameters
+//
+// Returns: TRUE if successful
+//
+// History: 26-Jan-94 BruceFo Created (derived from Chicago Disks tool)
+//
+//--------------------------------------------------------------------------
+
+BOOL
+ModifyDriveBitmap(
+ IN HWND hwndParent,
+ IN HBITMAP hBigBitmap,
+ IN ULONG driveStatus,
+ IN ULONG percentUsedTimes10,
+ IN PDRIVEINFO pdi
+ )
+{
+ HDC hDCWnd;
+ HDC hDCMem;
+ HBITMAP hOrgBm;
+ HBRUSH hOrgBrsh;
+ HBRUSH hUsedBrsh;
+ HBRUSH hUsedSBrsh;
+ HBRUSH hFreeBrsh;
+ HBRUSH hFreeSBrsh;
+ HBRUSH hBlkBrsh;
+ HPEN hBlkPen;
+ LPPOINT lpPnt;
+ POINT Pnt[4];
+
+ // No chart if never writable or drive currently not ready
+
+ if ((pdi->DrawFlags & DF_NEVERFREE) || (driveStatus == STATUS_UNKNOWN))
+ {
+ return TRUE;
+ }
+
+ hDCWnd = GetDC(hwndParent);
+ if (NULL == hDCWnd)
+ {
+ return FALSE;
+ }
+
+ hDCMem = CreateCompatibleDC(hDCWnd);
+ if (NULL == hDCMem)
+ {
+ ReleaseDC(hwndParent,hDCWnd);
+ return FALSE;
+ }
+
+ ReleaseDC(hwndParent,hDCWnd);
+ hBlkPen = GetStockPen(BLACK_PEN);
+ hBlkBrsh = GetStockBrush(BLACK_BRUSH);
+
+ hUsedBrsh = CreateSolidBrush(GraphColors[I_USEDCOLOR]);
+ if (NULL == hUsedBrsh)
+ {
+ return FALSE;
+ }
+
+ hUsedSBrsh = CreateSolidBrush(GraphColors[I_USEDSHADOW]);
+ if (NULL == hUsedSBrsh)
+ {
+ DeleteBrush(hUsedBrsh);
+ return FALSE;
+ }
+
+ hFreeBrsh = CreateSolidBrush(GraphColors[I_FREECOLOR]);
+ if (NULL == hFreeBrsh)
+ {
+ DeleteBrush(hUsedBrsh);
+ DeleteBrush(hUsedSBrsh);
+ return FALSE;
+ }
+
+ hFreeSBrsh = CreateSolidBrush(GraphColors[I_FREESHADOW]);
+ if (NULL == hFreeSBrsh)
+ {
+ DeleteBrush(hUsedBrsh);
+ DeleteBrush(hUsedSBrsh);
+ DeleteBrush(hFreeBrsh);
+ return FALSE;
+ }
+
+ hOrgBm = SelectBitmap(hDCMem,hBigBitmap);
+ hOrgBrsh = SelectBrush(hDCMem,hUsedBrsh);
+
+ if ((pdi->DrawFlags & DF_USEBARH) || (pdi->DrawFlags & DF_USEBARV))
+ {
+ lpPnt = (LPPOINT)&pdi->EllipsRect;
+ SelectPen(hDCMem,hBlkPen);
+
+ if (percentUsedTimes10 == 1000)
+ {
+ SelectBrush(hDCMem,hUsedBrsh);
+ }
+ else
+ {
+ SelectBrush(hDCMem,hFreeBrsh);
+ }
+
+ Polygon(hDCMem,lpPnt,4);
+
+ if (percentUsedTimes10 == 1000)
+ {
+ SelectBrush(hDCMem,hUsedSBrsh);
+ }
+ else
+ {
+ SelectBrush(hDCMem,hFreeSBrsh);
+ }
+
+ if (pdi->DrawFlags & DF_USEBARH)
+ {
+ Pnt[0].x = lpPnt[0].x;
+ Pnt[0].y = lpPnt[0].y;
+ Pnt[1].x = lpPnt[3].x;
+ Pnt[1].y = lpPnt[3].y;
+ Pnt[2].x = lpPnt[3].x;
+ Pnt[2].y = lpPnt[3].y;
+ Pnt[3].x = lpPnt[0].x;
+ Pnt[3].y = lpPnt[0].y;
+ Pnt[2].y += pdi->ThreeDHgt;
+ Pnt[3].y += pdi->ThreeDHgt;
+ Polygon(hDCMem,&Pnt[0],4);
+ Pnt[0].x = lpPnt[3].x;
+ Pnt[0].y = lpPnt[3].y;
+ Pnt[1].x = lpPnt[2].x;
+ Pnt[1].y = lpPnt[2].y;
+ Pnt[2].x = lpPnt[2].x;
+ Pnt[2].y = lpPnt[2].y;
+ Pnt[3].x = lpPnt[3].x;
+ Pnt[3].y = lpPnt[3].y;
+ Pnt[2].y += pdi->ThreeDHgt;
+ Pnt[3].y += pdi->ThreeDHgt;
+ Polygon(hDCMem,&Pnt[0],4);
+ }
+ else
+ {
+ Pnt[0].x = lpPnt[3].x;
+ Pnt[0].y = lpPnt[3].y;
+ Pnt[1].x = lpPnt[2].x;
+ Pnt[1].y = lpPnt[2].y;
+ Pnt[2].x = lpPnt[2].x;
+ Pnt[2].y = lpPnt[2].y;
+ Pnt[3].x = lpPnt[3].x;
+ Pnt[3].y = lpPnt[3].y;
+ Pnt[0].x += pdi->ThreeDHgt;
+ Pnt[1].x += pdi->ThreeDHgt;
+ Polygon(hDCMem,&Pnt[0],4);
+ Pnt[0].x = lpPnt[1].x;
+ Pnt[0].y = lpPnt[1].y;
+ Pnt[1].x = lpPnt[2].x;
+ Pnt[1].y = lpPnt[2].y;
+ Pnt[2].x = lpPnt[2].x;
+ Pnt[2].y = lpPnt[2].y;
+ Pnt[3].x = lpPnt[1].x;
+ Pnt[3].y = lpPnt[1].y;
+ Pnt[2].x += pdi->ThreeDHgt;
+ Pnt[3].x += pdi->ThreeDHgt;
+ Polygon(hDCMem,&Pnt[0],4);
+ }
+
+ if ((percentUsedTimes10 != 0) && (percentUsedTimes10 != 1000))
+ {
+ SelectBrush(hDCMem,hUsedBrsh);
+ Pnt[0].x = lpPnt[0].x;
+ Pnt[0].y = lpPnt[0].y;
+ Pnt[1].x = lpPnt[1].x;
+ Pnt[1].y = lpPnt[1].y;
+ Pnt[2].x = lpPnt[2].x;
+ Pnt[2].y = lpPnt[2].y;
+ Pnt[3].x = lpPnt[3].x;
+ Pnt[3].y = lpPnt[3].y;
+ if (pdi->DrawFlags & DF_USEBARH)
+ {
+ Pnt[1].x = Pnt[0].x + (int)(((DWORD)(Pnt[1].x - Pnt[0].x) * (DWORD)percentUsedTimes10) / 1000L);
+ Pnt[2].x = Pnt[3].x + (int)(((DWORD)(Pnt[2].x - Pnt[3].x) * (DWORD)percentUsedTimes10) / 1000L);
+ }
+ else
+ {
+ Pnt[0].y = Pnt[3].y - (int)(((DWORD)(Pnt[3].y - Pnt[0].y) * (DWORD)percentUsedTimes10) / 1000L);
+ Pnt[1].y = Pnt[2].y - (int)(((DWORD)(Pnt[2].y - Pnt[1].y) * (DWORD)percentUsedTimes10) / 1000L);
+ }
+ Polygon(hDCMem,&Pnt[0],4);
+ SelectBrush(hDCMem,hUsedSBrsh);
+
+ if (pdi->DrawFlags & DF_USEBARH)
+ {
+ Pnt[0].x = Pnt[3].x;
+ Pnt[0].y = Pnt[3].y;
+ Pnt[1].x = Pnt[2].x;
+ Pnt[1].y = Pnt[2].y;
+ Pnt[2].y += pdi->ThreeDHgt;
+ Pnt[3].y += pdi->ThreeDHgt;
+ Polygon(hDCMem,&Pnt[0],4);
+ Pnt[0].x = lpPnt[0].x;
+ Pnt[0].y = lpPnt[0].y;
+ Pnt[1].x = lpPnt[3].x;
+ Pnt[1].y = lpPnt[3].y;
+ Pnt[2].x = lpPnt[3].x;
+ Pnt[2].y = lpPnt[3].y;
+ Pnt[3].x = lpPnt[0].x;
+ Pnt[3].y = lpPnt[0].y;
+ Pnt[2].y += pdi->ThreeDHgt;
+ Pnt[3].y += pdi->ThreeDHgt;
+ Polygon(hDCMem,&Pnt[0],4);
+ }
+ else
+ {
+ Pnt[0].x = Pnt[1].x;
+ Pnt[0].y = Pnt[1].y;
+ Pnt[3].x = Pnt[2].x;
+ Pnt[3].y = Pnt[2].y;
+ Pnt[1].x += pdi->ThreeDHgt;
+ Pnt[2].x += pdi->ThreeDHgt;
+ Polygon(hDCMem,&Pnt[0],4);
+ Pnt[0].x = lpPnt[3].x;
+ Pnt[0].y = lpPnt[3].y;
+ Pnt[1].x = lpPnt[2].x;
+ Pnt[1].y = lpPnt[2].y;
+ Pnt[2].x = lpPnt[2].x;
+ Pnt[2].y = lpPnt[2].y;
+ Pnt[3].x = lpPnt[3].x;
+ Pnt[3].y = lpPnt[3].y;
+ Pnt[0].x += pdi->ThreeDHgt;
+ Pnt[1].x += pdi->ThreeDHgt;
+ Polygon(hDCMem,&Pnt[0],4);
+ }
+ }
+ }
+ else
+ {
+ DrawPie(
+ hDCMem,
+ &pdi->EllipsRect,
+ percentUsedTimes10,
+ pdi->ThreeDHgt,
+ GraphColors
+ );
+ }
+
+ SelectBrush(hDCMem,hOrgBrsh);
+ SelectBitmap(hDCMem,hOrgBm);
+ DeleteBrush(hUsedBrsh);
+ DeleteBrush(hUsedSBrsh);
+ DeleteBrush(hFreeBrsh);
+ DeleteBrush(hFreeSBrsh);
+ DeleteDC(hDCMem);
+
+ return TRUE;
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: CreateGraphBitmap
+//
+// Synopsis: Creates a %free/%used bitmap to be used in a volume property
+// page
+//
+// Arguments: [hInstance] -- handle to application instance
+// [hwndParent] -- parent window
+// [driveType] -- DRIVE_FIXED, etc (see Win32 GetDriveType())
+// [driveStatus] -- STATUS_OK or STATUS_UNKNOWN
+// [percentUsedTimes10] -- % used space times 10 (i.e. one decimal
+// point of accuracy)
+//
+// Returns: the created bitmap
+//
+// History: 26-Jan-94 BruceFo Created (derived from Chicago Disks tool)
+//
+//--------------------------------------------------------------------------
+
+HBITMAP
+CreateGraphBitmap(
+ IN HINSTANCE hInstance,
+ IN HWND hwndParent,
+ IN ULONG driveType,
+ IN ULONG driveStatus,
+ IN ULONG percentUsedTimes10
+ )
+{
+ DRIVEINFO di = {0};
+
+ HBITMAP hBigBitmap = LoadDriveBitmap(
+ hInstance,
+ driveType,
+ driveStatus,
+ &di);
+
+ if (hBigBitmap)
+ {
+ ModifyDriveBitmap(
+ hwndParent,
+ hBigBitmap,
+ driveStatus,
+ percentUsedTimes10,
+ &di);
+ }
+
+ return hBigBitmap;
+}
diff --git a/private/utils/windisk/src/graph.hxx b/private/utils/windisk/src/graph.hxx
new file mode 100644
index 000000000..39b074ab1
--- /dev/null
+++ b/private/utils/windisk/src/graph.hxx
@@ -0,0 +1,32 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: graph.hxx
+//
+// Contents: Declarations for the %free/%used graph creation code
+//
+// History: 26-Jan-94 BruceFo Created (derived from Chicago Disks tool)
+//
+//--------------------------------------------------------------------------
+
+#ifndef __GRAPH_HXX__
+#define __GRAPH_HXX__
+
+//
+// Status values
+//
+#define STATUS_OK 1
+#define STATUS_UNKNOWN 2
+
+HBITMAP
+CreateGraphBitmap(
+ HINSTANCE hInstance,
+ HWND hwndParent,
+ ULONG driveType,
+ ULONG driveStatus,
+ ULONG percentUsedTimes10
+ );
+
+#endif // __GRAPH_HXX__
diff --git a/private/utils/windisk/src/hard.bmp b/private/utils/windisk/src/hard.bmp
new file mode 100644
index 000000000..7e0cd6e3e
--- /dev/null
+++ b/private/utils/windisk/src/hard.bmp
Binary files differ
diff --git a/private/utils/windisk/src/headers.hxx b/private/utils/windisk/src/headers.hxx
new file mode 100644
index 000000000..623d33731
--- /dev/null
+++ b/private/utils/windisk/src/headers.hxx
@@ -0,0 +1,95 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: headers.hxx
+//
+// Contents: Main include file for Disk Administrator
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef UNICODE
+#error Disk Administrator MUST build with UNICODE defined!
+#endif // UNICODE
+
+////////////////////////////////////////////////////////////////////////////
+
+extern "C"
+{
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+
+#pragma warning(4:4091)
+#include <ntdddisk.h>
+#pragma warning(default:4091)
+
+#include <ntdskreg.h>
+#include <ntddft.h>
+}
+
+#include <fmifs.h>
+#include <windows.h>
+#include <windowsx.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <shellapi.h>
+
+#ifdef WINDISK_EXTENSIONS
+// #include <ole2.h>
+// #include <oleext.h>
+// #include <prividl.h> // Windisk interfaces
+#endif // WINDISK_EXTENSIONS
+
+#include <commdlg.h>
+#include <debug.h> // my debnot.h replacement
+#include <commctrl.h>
+
+#include <dacommon.h> // Common header file for Disk Administrator code
+
+//
+// The constants...
+//
+
+#include "const.h"
+#include "helpid.h"
+#include "resids.h"
+
+#include "messages.h"
+
+//
+// The types...
+//
+
+#include "types.hxx"
+
+//
+// The globals...
+//
+
+#include "global.hxx"
+
+//
+// The function prototypes...
+//
+
+#include "mem.hxx"
+#include "proto.hxx"
+
+//
+// These defines are for virtualized types in engine.cxx, ntlow.cxx
+//
+#define STATUS_CODE NTSTATUS
+#define OK_STATUS STATUS_SUCCESS
+#define RETURN_OUT_OF_MEMORY return STATUS_NO_MEMORY;
+#define HANDLE_T HANDLE
+#define HANDLE_PT PHANDLE
+#define AllocateMemory Malloc
+#define ReallocateMemory Realloc
+#define FreeMemory Free
+
+#include "engine.hxx"
diff --git a/private/utils/windisk/src/help.cxx b/private/utils/windisk/src/help.cxx
new file mode 100644
index 000000000..3cfba9089
--- /dev/null
+++ b/private/utils/windisk/src/help.cxx
@@ -0,0 +1,312 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: help.cxx
+//
+// Contents: Routines to support context-sensitive help in the disk manager.
+//
+// History: 18-Mar-92 TedM Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include "help.hxx"
+#include "help2.hxx"
+#include "stleg.hxx"
+
+
+//
+// Define macro to convert between a menu id and its corresponding
+// context-sensitive help id, in a switch statement.
+//
+
+#define MENUID_TO_HELPID(name) case IDM_##name : \
+ HelpContext = HC_DM_MENU_##name; \
+ break;
+
+
+//
+// Current help context
+//
+
+DWORD HelpContext = (DWORD)(-1);
+
+
+//
+// Handle to windows hook for F1 key
+//
+HHOOK hHook;
+
+
+
+LRESULT CALLBACK
+HookProc(
+ IN int nCode,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Hook proc to detect F1 key presses.
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ PMSG pmsg = (PMSG)lParam;
+
+ if (nCode < 0)
+ {
+ return CallNextHookEx(hHook, nCode, wParam, lParam);
+ }
+
+ if ( ((nCode == MSGF_DIALOGBOX) || (nCode == MSGF_MENU))
+ && (pmsg->message == WM_KEYDOWN)
+ && (LOWORD(pmsg->wParam) == VK_F1))
+ {
+ PostMessage(g_hwndFrame, WM_F1DOWN, nCode, 0);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
+VOID
+Help(
+ IN LONG Code
+ )
+
+/*++
+
+Routine Description:
+
+ Display context-sensitive help.
+
+Arguments:
+
+ Code - supplies type of message (MSGF_DIALOGBOX, MSGF_MENU, etc).
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if (HelpContext != -1)
+ {
+ WinHelp(g_hwndFrame, g_HelpFile, HELP_CONTEXT, HelpContext);
+ DrawMenuBar(g_hwndFrame);
+ }
+}
+
+
+
+VOID
+DialogHelp(
+ IN DWORD HelpId
+ )
+/*++
+
+Routine Description:
+
+ Display help on a specific item.
+
+Arguments:
+
+ HelpId -- Supplies the help item to display.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ WinHelp(g_hwndFrame, g_HelpFile, HELP_CONTEXT, HelpId);
+ DrawMenuBar(g_hwndFrame);
+}
+
+
+
+VOID
+SetMenuItemHelpContext(
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+
+/*++
+
+Routine Description:
+
+ Routine to set help context based on which menu item is currently
+ selected.
+
+Arguments:
+
+ wParam, lParam - params to window proc in WM_MENUSELECT case
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UINT uItem = (UINT)LOWORD(wParam);
+ UINT fuFlags = (UINT)HIWORD(wParam);
+ HMENU hmenu = (HMENU)lParam;
+
+ if (fuFlags == 0xFFFF && hmenu == NULL) // menu closed
+ {
+ HelpContext = (DWORD)(-1);
+
+ //
+ // restore status bar display
+ //
+
+ g_fDoingMenuHelp = FALSE;
+ UpdateStatusBarDisplay();
+ }
+ else if (fuFlags & MF_POPUP) // popup selected
+ {
+ HelpContext = (DWORD)(-1);
+
+ DrawMenuHelpItem(
+ hmenu, // menu of selection
+ uItem, // menu item
+ fuFlags // flags
+ );
+ }
+ else // regular old menu item
+ {
+ switch (uItem)
+ {
+
+//
+// Volume menu
+//
+
+// MENUID_TO_HELPID(PARTITIONLETTER) //BUGBUG
+ MENUID_TO_HELPID(QUIT)
+
+//
+// Partition menu
+//
+
+ MENUID_TO_HELPID(PARTITIONCREATE)
+ MENUID_TO_HELPID(PARTITIONCREATEEX)
+ MENUID_TO_HELPID(PARTITIONDELETE)
+#if i386
+ MENUID_TO_HELPID(PARTITIONACTIVE)
+#else
+ MENUID_TO_HELPID(SECURESYSTEM)
+#endif
+
+ MENUID_TO_HELPID(PARTITIONCOMMIT)
+
+//
+// Configuration sub-menu
+//
+
+ MENUID_TO_HELPID(CONFIGMIGRATE)
+ MENUID_TO_HELPID(CONFIGSAVE)
+ MENUID_TO_HELPID(CONFIGRESTORE)
+
+//
+// Fault-tolerance menu
+//
+
+ MENUID_TO_HELPID(FTESTABLISHMIRROR)
+ MENUID_TO_HELPID(FTBREAKMIRROR)
+ MENUID_TO_HELPID(FTCREATESTRIPE)
+ MENUID_TO_HELPID(FTCREATEPSTRIPE)
+ MENUID_TO_HELPID(FTCREATEVOLUMESET)
+ MENUID_TO_HELPID(FTEXTENDVOLUMESET)
+ MENUID_TO_HELPID(FTRECOVERSTRIPE)
+
+//
+// Tools Menu
+//
+ MENUID_TO_HELPID(VOL_FORMAT)
+ MENUID_TO_HELPID(VOL_LETTER)
+ MENUID_TO_HELPID(VOL_EJECT)
+ MENUID_TO_HELPID(VOL_PROPERTIES)
+
+//
+// View menu
+//
+
+ MENUID_TO_HELPID(VIEWVOLUMES)
+ MENUID_TO_HELPID(VIEWDISKS)
+ MENUID_TO_HELPID(VIEW_REFRESH)
+
+//
+// Options menu
+//
+
+ MENUID_TO_HELPID(OPTIONSTOOLBAR)
+ MENUID_TO_HELPID(OPTIONSSTATUS)
+ MENUID_TO_HELPID(OPTIONSLEGEND)
+ MENUID_TO_HELPID(OPTIONSCOLORS)
+ MENUID_TO_HELPID(OPTIONSDISK)
+ MENUID_TO_HELPID(OPTIONSDISPLAY)
+ MENUID_TO_HELPID(OPTIONSCUSTTOOLBAR)
+
+//
+// Help menu
+//
+
+ MENUID_TO_HELPID(HELPCONTENTS)
+ MENUID_TO_HELPID(HELPSEARCH)
+ MENUID_TO_HELPID(HELPHELP)
+ MENUID_TO_HELPID(HELPABOUT)
+
+ default:
+ HelpContext = (DWORD)(-1);
+ }
+
+ //
+ // Set the status bar text
+ //
+
+ DrawMenuHelpItem(
+ hmenu, // menu of selection
+ uItem, // menu item
+ fuFlags // flags
+ );
+ }
+}
+
+
+VOID
+InitHelp(
+ VOID
+ )
+{
+ hHook = SetWindowsHookEx(
+ WH_MSGFILTER,
+ HookProc,
+ NULL,
+ GetCurrentThreadId());
+}
+
+
+VOID
+TermHelp(
+ VOID
+ )
+{
+ UnhookWindowsHookEx(hHook);
+}
diff --git a/private/utils/windisk/src/help.hxx b/private/utils/windisk/src/help.hxx
new file mode 100644
index 000000000..b1db28843
--- /dev/null
+++ b/private/utils/windisk/src/help.hxx
@@ -0,0 +1,45 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: help.hxx
+//
+// Contents: Declarations for routines to support context-sensitive help
+//
+// History: 18-Mar-92 TedM Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __HELP_HXX__
+#define __HELP_HXX__
+
+//////////////////////////////////////////////////////////////////////////////
+
+VOID
+InitHelp(
+ VOID
+ );
+
+VOID
+TermHelp(
+ VOID
+ );
+
+VOID
+Help(
+ IN LONG Code
+ );
+
+VOID
+DialogHelp(
+ IN DWORD HelpId
+ );
+
+VOID
+SetMenuItemHelpContext(
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+#endif // __HELP_HXX__
diff --git a/private/utils/windisk/src/help2.cxx b/private/utils/windisk/src/help2.cxx
new file mode 100644
index 000000000..07ebce841
--- /dev/null
+++ b/private/utils/windisk/src/help2.cxx
@@ -0,0 +1,506 @@
+//----------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: help2.cxx
+//
+// Contents: Status bar help for toolbar & menu bar items
+//
+// History: 15-Jul-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include "resids.h"
+#include "stleg.hxx"
+#include "menudict.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+VOID
+GetMenuHelp(
+ IN HMENU hmenu,
+ IN UINT uItem,
+ IN UINT fuFlags,
+ OUT PWSTR Buffer,
+ IN UINT cchBuf
+ );
+
+//////////////////////////////////////////////////////////////////////////////
+
+// the Partition menu is the first menu on the menu bar (0 in 0-based counting)
+
+#define PARTITION_MENU_INDEX 0
+
+//////////////////////////////////////////////////////////////////////////////
+
+BOOL g_fDoingMenuHelp;
+
+struct MENU_HELP
+{
+ UINT uItem; // menu id
+ UINT uID; // string id of help text
+};
+
+
+MENU_HELP MenuHelpArray[] =
+{
+//
+// Partition menu
+//
+
+ IDM_PARTITIONCREATE, IDS_HELP_CREATE,
+ IDM_PARTITIONCREATEEX, IDS_HELP_CREATEEX,
+ IDM_PARTITIONDELETE, IDS_HELP_DELETE,
+ IDM_FTCREATEVOLUMESET, IDS_HELP_CREATEVOLSET,
+ IDM_FTEXTENDVOLUMESET, IDS_HELP_EXTENDVOLSET,
+ IDM_FTCREATESTRIPE, IDS_HELP_CREATESTRIPE,
+#if i386
+ IDM_PARTITIONACTIVE, IDS_HELP_MARKACTIVE,
+#else
+ IDM_SECURESYSTEM, IDS_HELP_SECURE,
+#endif
+
+ //
+ // Configuration sub-menu
+ //
+
+ IDM_CONFIGSAVE, IDS_HELP_SAVECONFIG,
+ IDM_CONFIGRESTORE, IDS_HELP_RESTORECONFIG,
+ IDM_CONFIGMIGRATE, IDS_HELP_SEARCHCONFIG,
+
+ IDM_PARTITIONCOMMIT, IDS_HELP_PARTITIONCOMMIT,
+ IDM_QUIT, IDS_HELP_QUIT,
+
+//
+// Fault-tolerance menu
+//
+
+ IDM_FTESTABLISHMIRROR, IDS_HELP_ESTABLISHMIRROR,
+ IDM_FTBREAKMIRROR, IDS_HELP_BREAKMIRROR,
+ IDM_FTCREATEPSTRIPE, IDS_HELP_CREATEPSET,
+ IDM_FTRECOVERSTRIPE, IDS_HELP_REGENSTRIPE,
+
+//
+// Tools menu
+//
+
+ IDM_VOL_FORMAT, IDS_HELP_FORMAT,
+ IDM_VOL_LETTER, IDS_HELP_DRIVELET,
+#if defined( DBLSPACE_ENABLED )
+ IDM_VOL_DBLSPACE, IDS_HELP_DBLSPACE,
+ IDM_VOL_AUTOMOUNT, IDS_HELP_AUTOMOUNT,
+#endif // DBLSPACE_ENABLED
+ IDM_VOL_PROPERTIES, IDS_HELP_PROPERTIES,
+
+
+//
+// View menu
+//
+
+ IDM_VIEWVOLUMES, IDS_HELP_VOLUMESVIEW,
+ IDM_VIEWDISKS, IDS_HELP_DISKSVIEW,
+ IDM_VIEW_REFRESH, IDS_HELP_REFRESH,
+
+//
+// Options menu
+//
+
+ IDM_OPTIONSTOOLBAR, IDS_HELP_TOOLBAR,
+ IDM_OPTIONSSTATUS, IDS_HELP_STATUSBAR,
+ IDM_OPTIONSLEGEND, IDS_HELP_LEGEND,
+ IDM_OPTIONSCOLORS, IDS_HELP_COLORS,
+ IDM_OPTIONSDISK, IDS_HELP_OPTIONSDISK,
+ IDM_OPTIONSDISPLAY, IDS_HELP_REGIONDISPLAY,
+ IDM_OPTIONSCUSTTOOLBAR, IDS_HELP_CUSTTOOLBAR,
+
+//
+// Help menu
+//
+
+ IDM_HELPCONTENTS, IDS_HELP_HELPCONTENTS,
+ IDM_HELPSEARCH, IDS_HELP_HELPSEARCH,
+ IDM_HELPHELP, IDS_HELP_HELPHELP,
+ IDM_HELPABOUT, IDS_HELP_HELPABOUT,
+
+//
+// Debug menu (only for debug builds)
+//
+
+#if DBG == 1
+ IDM_DEBUGALLOWDELETES, IDS_HELP_DELETEALL,
+ IDM_DEBUGLOG, IDS_HELP_LOG,
+ IDM_RAID, IDS_HELP_RAID,
+#endif // DBG == 1
+
+//
+// Menu items that don't appear in the top-level menu (i.e. context-menu only)
+//
+
+ IDM_PROPERTIES, IDS_HELP_PROPERTIES,
+ IDM_NOVALIDOPERATION, IDS_HELP_NOVALIDOPERATION,
+
+//
+// End-of-data sentinel
+//
+
+ 0, 0
+};
+
+
+//
+// This is an array where the index is the 0-based index of the top-level
+// popup menu and the value is the resource string id.
+//
+// There are two arrays: one for the normal NT, one for advanced server, which
+// has an extra menu item.
+//
+
+UINT PopupMenuHelpArray[] =
+{
+ IDS_HELP_MENU_PARTITION,
+ IDS_HELP_MENU_VOLUMES,
+ IDS_HELP_MENU_VIEW,
+ IDS_HELP_MENU_OPTIONS,
+ IDS_HELP_MENU_HELP
+};
+
+UINT AdvancedServerPopupMenuHelpArray[] =
+{
+ IDS_HELP_MENU_PARTITION,
+ IDS_HELP_MENU_FT,
+ IDS_HELP_MENU_VOLUMES,
+ IDS_HELP_MENU_VIEW,
+ IDS_HELP_MENU_OPTIONS,
+ IDS_HELP_MENU_HELP
+};
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+//+---------------------------------------------------------------------------
+//
+// Function: InitMenuHelp
+//
+// Synopsis: Initialize menu help: determine all menu bar menu handles
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+InitMenuHelp(
+ VOID
+ )
+{
+ g_fDoingMenuHelp = FALSE;
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: GetMenuHelp
+//
+// Synopsis: Gets the help string for a particular menu and item
+//
+// Arguments: [hmenu] -- menu handle of menu to get help for
+// [uItem] -- menu item index
+// [fuFlags] -- menu item flags
+// [Buffer] -- a buffer to write the help string to
+// [cchBuf] -- number of characters in the buffer
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+GetMenuHelp(
+ IN HMENU hmenu,
+ IN UINT uItem,
+ IN UINT fuFlags,
+ OUT PWSTR Buffer,
+ IN UINT cchBuf
+ )
+{
+ UINT i;
+
+ if (cchBuf == 0)
+ {
+ return;
+ }
+
+ Buffer[0] = TEXT('\0');
+
+ if (fuFlags & MF_SEPARATOR) // display nothing for a separator
+ {
+ return;
+ }
+
+ if (fuFlags & MF_POPUP) // a popup selected
+ {
+ HMENU hmenuFrame = GetMenu(g_hwndFrame);
+
+ //
+ // It is a menu, not an item in itself
+ //
+
+ if (hmenu == hmenuFrame)
+ {
+ UINT resID;
+
+ if (g_IsLanmanNt)
+ {
+ if (uItem >= ARRAYLEN(AdvancedServerPopupMenuHelpArray))
+ {
+ daDebugOut((DEB_ERROR,"Illegal WinNT AS menu id %d!\n",uItem));
+ return; // illegal uItem!
+ }
+
+ resID = AdvancedServerPopupMenuHelpArray[uItem];
+ }
+ else
+ {
+ if (uItem >= ARRAYLEN(PopupMenuHelpArray))
+ {
+ daDebugOut((DEB_ERROR,"Illegal WinNT menu id %d!\n",uItem));
+ return; // illegal uItem!
+ }
+
+ resID = PopupMenuHelpArray[uItem];
+ }
+
+ LoadString(
+ g_hInstance,
+ resID,
+ Buffer,
+ cchBuf);
+ return;
+ }
+ else if (hmenu == GetSubMenu(hmenuFrame, PARTITION_MENU_INDEX))
+ {
+ //
+ // the "Configuration ->" sub-menu is the only sub-menu on
+ // the "Partition" menu, so ignore the index and just load the
+ // configuration menu help
+ //
+
+ LoadString(
+ g_hInstance,
+ IDS_HELP_MENU_CONFIG,
+ Buffer,
+ cchBuf);
+ return;
+ }
+#if DBG == 1
+ else if (hmenu == GetSubMenu(hmenuFrame, g_IsLanmanNt ? 5 : 4))
+ {
+ //
+ // the "Debug ->" sub-menu is the only sub-menu on the "Help"
+ // menu, so ignore the index and just load the debug menu help
+ //
+
+ LoadString(
+ g_hInstance,
+ IDS_HELP_MENU_DEBUG,
+ Buffer,
+ cchBuf);
+ return;
+ }
+#endif // DBG == 1
+ else
+ {
+ daDebugOut((DEB_IERROR,
+ "Unknown menu! hmenu = 0x%x, uItem = %d, flags = 0x%x\n",
+ hmenu,
+ uItem,
+ fuFlags));
+
+ return;
+ }
+ }
+
+ //
+ // It is an actual item
+ //
+
+#ifdef WINDISK_EXTENSIONS
+
+ if (MenuItems.IsExtensionId(uItem)) // an extension item?
+ {
+ MenuItemType* pMenu = MenuItems.LookupMenuItem(uItem);
+
+ UINT cchItem = lstrlen(pMenu->pszMenuHelp) + 1;
+ UINT cchCopy = min(cchItem, cchBuf);
+ wcsncpy(Buffer, pMenu->pszMenuHelp, cchCopy);
+ return;
+ }
+ else
+ if (ContextMenuItems.IsExtensionId(uItem)) // an extension item?
+ {
+ MenuItemType* pMenu = ContextMenuItems.LookupMenuItem(uItem);
+
+ UINT cchItem = lstrlen(pMenu->pszMenuHelp) + 1;
+ UINT cchCopy = min(cchItem, cchBuf);
+ wcsncpy(Buffer, pMenu->pszMenuHelp, cchCopy);
+ return;
+ }
+ else // a normal, internal (non-extension) item
+ {
+#endif // WINDISK_EXTENSIONS
+
+ for (i=0; 0 != MenuHelpArray[i].uItem; i++)
+ {
+ if (uItem == MenuHelpArray[i].uItem)
+ {
+ LoadString(
+ g_hInstance,
+ MenuHelpArray[i].uID,
+ Buffer,
+ cchBuf);
+ return;
+ }
+ }
+
+#ifdef WINDISK_EXTENSIONS
+ }
+#endif // WINDISK_EXTENSIONS
+
+ daDebugOut((DEB_TRACE, "No help found for item %d\n", uItem));
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: PaintHelpStatusBar
+//
+// Synopsis: Paint the help bar (space borrowed from the status bar, if any)
+//
+// Arguments: [Text] -- help text to print
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+// BUGBUG: This will write off the right side of the bevelled window
+//
+//----------------------------------------------------------------------------
+
+VOID
+PaintHelpStatusBar(
+ IN LPTSTR Text
+ )
+{
+ RECT rc;
+ HDC hdcFrame = GetDC(g_hwndFrame);
+ HFONT hFontOld;
+ LPTSTR HelpString;
+
+ GetClientRect(g_hwndFrame,&rc);
+ rc.top = rc.bottom - g_dyStatus;
+ rc.left = 8 * g_dyBorder;
+ rc.right = GraphWidth - (8*g_dyBorder);
+
+ hFontOld = SelectFont(hdcFrame, g_hFontStatus);
+
+ if (Text)
+ {
+ HelpString = Text;
+ }
+ else
+ {
+ HelpString = TEXT("");
+ }
+
+ DrawStatusAreaItem(&rc, hdcFrame, HelpString);
+
+ if (hFontOld)
+ {
+ SelectFont(hdcFrame,hFontOld);
+ }
+
+ ReleaseDC(g_hwndFrame,hdcFrame);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DrawMenuHelpItem
+//
+// Synopsis: Draw the menu help for an item
+//
+// Arguments: [hmenu] -- menu handle of menu to get help for
+// [uItem] -- menu item index
+// [fuFlags] -- menu item flags
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DrawMenuHelpItem(
+ IN HMENU hmenu,
+ IN UINT uItem,
+ IN UINT fuFlags
+ )
+{
+ if (g_StatusBar)
+ {
+ //
+ // We use the same space as the status bar, so if the user isn't
+ // viewing the status bar, we don't show any help
+ //
+
+ TCHAR buf[256];
+
+ GetMenuHelp(hmenu, uItem, fuFlags, buf, ARRAYLEN(buf));
+ PaintHelpStatusBar(buf);
+
+ g_fDoingMenuHelp = TRUE;
+ }
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: GetTooltip
+//
+// Synopsis: Load a tooltip
+//
+// Arguments: [uItem] -- menu item index
+//
+// Returns: resource id of tooltip string
+//
+// History: 26-Sep-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+UINT
+GetTooltip(
+ IN UINT uItem
+ )
+{
+ for (int i=0; 0 != MenuHelpArray[i].uItem; i++)
+ {
+ if (uItem == MenuHelpArray[i].uItem)
+ {
+ return MenuHelpArray[i].uID;
+ }
+ }
+
+ return 0; // error, really
+}
diff --git a/private/utils/windisk/src/help2.hxx b/private/utils/windisk/src/help2.hxx
new file mode 100644
index 000000000..61914a25e
--- /dev/null
+++ b/private/utils/windisk/src/help2.hxx
@@ -0,0 +1,39 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: help2.hxx
+//
+// Contents: Status bar help for toolbar & menu bar items
+//
+// History: 15-Jul-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __HELP2_HXX__
+#define __HELP2_HXX__
+
+VOID
+InitMenuHelp(
+ VOID
+ );
+
+VOID
+PaintHelpStatusBar(
+ IN LPTSTR Text
+ );
+
+VOID
+DrawMenuHelpItem(
+ IN HMENU hmenu,
+ IN UINT uItem,
+ IN UINT fuFlags
+ );
+
+UINT
+GetTooltip(
+ IN UINT uItem
+ );
+
+#endif // __HELP2_HXX__
diff --git a/private/utils/windisk/src/helpid.h b/private/utils/windisk/src/helpid.h
new file mode 100644
index 000000000..cf64f260c
--- /dev/null
+++ b/private/utils/windisk/src/helpid.h
@@ -0,0 +1,220 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: helpid.h
+//
+// Contents: Context ids for context-sensitive help for the disk manager
+//
+// History: 18-Mar-92 TedM Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __HELPID_H__
+#define __HELPID_H__
+
+//
+// NOTE: if you change the numbers in this file, you must notify User Education
+// NOTE: so they can change the help file sources
+//
+
+//
+// All ids in this file start with HC_DM, as in "Help Context for Disk Manager"
+//
+
+//
+// Menu items. In the form HC_DM_MENU_xxx, where xxx matches the name used
+// in windisk.rc for the menu item (of the form IDM_xxx).
+//
+
+//
+// The volume menu
+//
+
+#define HC_DM_MENU_QUIT 118
+
+//
+// The partition menu
+//
+
+#define HC_DM_MENU_PARTITIONCREATE 110
+#define HC_DM_MENU_PARTITIONCREATEEX 111
+#define HC_DM_MENU_PARTITIONDELETE 112
+#define HC_DM_MENU_FTCREATEVOLUMESET 113
+#define HC_DM_MENU_FTEXTENDVOLUMESET 114
+#define HC_DM_MENU_FTCREATESTRIPE 115
+#if i386
+#define HC_DM_MENU_PARTITIONACTIVE 116
+#else
+#define HC_DM_MENU_SECURESYSTEM 119
+#endif
+#define HC_DM_MENU_VOL_LETTER 117 // really in tools menu
+#define HC_DM_MENU_PARTITIONEXIT 118
+#define HC_DM_MENU_PARTITIONCOMMIT 120
+
+//
+// The configuration menu
+//
+
+#define HC_DM_MENU_CONFIGMIGRATE 210
+#define HC_DM_MENU_CONFIGSAVE 211
+#define HC_DM_MENU_CONFIGRESTORE 212
+#define HC_DM_MENU_CONFIG 213
+
+//
+// The fault tolerance menu
+//
+
+#define HC_DM_MENU_FTESTABLISHMIRROR 310
+#define HC_DM_MENU_FTBREAKMIRROR 311
+#define HC_DM_MENU_FTCREATEPSTRIPE 312
+#define HC_DM_MENU_FTRECOVERSTRIPE 313
+
+//
+// The tools menu
+//
+
+#define HC_DM_MENU_AUTOMOUNT 610
+#if defined( DBLSPACE_ENABLED )
+#define HC_DM_MENU_DBLSPACE 611
+#endif // DBLSPACE_ENABLED
+#define HC_DM_MENU_CDROM 612
+#define HC_DM_MENU_VOL_FORMAT 613
+#define HC_DM_MENU_LABEL 614
+
+
+#define HC_DM_MENU_VOL_EJECT 710
+#define HC_DM_MENU_VOL_PROPERTIES 720
+
+//
+// View Menu
+//
+
+#define HC_DM_MENU_VIEWVOLUMES 810
+#define HC_DM_MENU_VIEWDISKS 820
+#define HC_DM_MENU_VIEW_REFRESH 830
+
+//
+// The options menu
+//
+
+#define HC_DM_MENU_OPTIONSTOOLBAR 416
+#define HC_DM_MENU_OPTIONSSTATUS 410
+#define HC_DM_MENU_OPTIONSLEGEND 411
+#define HC_DM_MENU_OPTIONSCOLORS 412
+#define HC_DM_MENU_OPTIONSDISK 414
+#define HC_DM_MENU_OPTIONSDISPLAY 413
+#define HC_DM_MENU_OPTIONSCUSTTOOLBAR 415
+
+
+//
+// The help menu
+//
+
+#define HC_DM_MENU_HELPCONTENTS 510
+#define HC_DM_MENU_HELPSEARCH 511
+#define HC_DM_MENU_HELPHELP 512
+#define HC_DM_MENU_HELPABOUT 513
+
+
+//
+// The system menu
+//
+
+#define HC_DM_SYSMENU_RESTORE 910
+#define HC_DM_SYSMENU_MOVE 911
+#define HC_DM_SYSMENU_SIZE 912
+#define HC_DM_SYSMENU_MINIMIZE 913
+#define HC_DM_SYSMENU_MAXIMIZE 914
+#define HC_DM_SYSMENU_CLOSE 915
+#define HC_DM_SYSMENU_SWITCHTO 916
+
+//
+// Dialog boxes. In the form HC_DM_DLG_xxx, where xxx is some reasonably
+// descriptive name for the dialog.
+//
+//
+// These dialog boxes do not have help buttons:
+//
+// - About
+// - Searching for Previous Installation
+// - Confirmation dialogs
+
+//
+// Min/Max dialogs for creating various items
+//
+
+#define HC_DM_DLG_CREATEPRIMARY 1010
+#define HC_DM_DLG_CREATEEXTENDED 1011
+#define HC_DM_DLG_CREATELOGICAL 1012
+#define HC_DM_DLG_CREATEVOLUMESET 1013
+#define HC_DM_DLG_EXTENDVOLUMESET 1014
+#define HC_DM_DLG_CREATESTRIPESET 1015
+#define HC_DM_DLG_CREATEPARITYSTRIPE 1016
+
+//
+// Dialog for assigning drive letters
+//
+
+#define HC_DM_DLG_DRIVELETTER 1020
+
+//
+// Dialog for determining region sizing
+//
+
+#define HC_DM_DLG_DISPLAYOPTION 1030
+
+//
+// Dialog for determining disk sizing
+//
+
+#define HC_DM_DLG_DISKDISPLAY 1075
+
+//
+// Configuration migration dialog to select previous installation
+//
+
+#define HC_DM_DLG_SELECTINSTALLATION 1040
+
+//
+// Colors and patterns dialog
+//
+
+#define HC_DM_COLORSANDPATTERNS 1050
+
+#define HC_DM_DLG_CUSTOMIZETOOL 1095
+
+//
+// DoubleSpace dialog
+//
+
+#define HC_DM_DLG_DOUBLESPACE 1060
+#define HC_DM_DLG_DOUBLESPACE_MOUNT 1061
+
+//
+// Format dialog
+//
+
+#define HC_DM_DLG_FORMAT 1070
+
+//
+// Label dialog
+//
+
+#define HC_DM_DLG_LABEL 1080
+
+//
+// CdRom dialog
+//
+
+#define HC_DM_DLG_CDROM 1090
+
+//
+// Chkdsk dialog
+//
+
+#define HC_DM_DLG_CHKDSK 1100
+
+
+#endif // __HELPID_H__
diff --git a/private/utils/windisk/src/init.cxx b/private/utils/windisk/src/init.cxx
new file mode 100644
index 000000000..c7396e2b6
--- /dev/null
+++ b/private/utils/windisk/src/init.cxx
@@ -0,0 +1,949 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: init.cxx
+//
+// Contents: Code for initializing the Disk Administrator
+//
+// History: 7-Jan-92 TedM Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include <controls.hxx>
+#include <util.hxx>
+
+#include "cdrom.hxx"
+#include "chkdsk.hxx"
+#include "dblspace.hxx"
+#include "dialogs.h"
+#include "dlgs.hxx"
+#include "drives.hxx"
+#include "fmifs.hxx"
+#include "ft.hxx"
+#include "init.hxx"
+#include "help2.hxx"
+#include "listbox.hxx"
+#include "network.hxx"
+#include "nt.hxx"
+#include "oleclass.hxx"
+#include "profile.hxx"
+#include "rectpriv.hxx"
+#include "stleg.hxx"
+#include "tbar.hxx"
+#include "volview.hxx"
+#include "windisk.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+HWND g_InitDlg;
+BOOLEAN g_StartedAsIcon = FALSE;
+BOOLEAN g_InitDlgComplete = FALSE;
+
+//////////////////////////////////////////////////////////////////////////////
+
+VOID
+CreateDiskState(
+ OUT PDISKSTATE *DiskState,
+ IN DWORD Disk,
+ OUT PBOOL SignatureCreated
+ );
+
+BOOL
+InitializeWindowData(
+ VOID
+ );
+
+DWORD
+InitializeDiskData(
+ VOID
+ );
+
+LPTSTR
+LoadOneString(
+ IN DWORD StringID
+ );
+
+//////////////////////////////////////////////////////////////////////////////
+
+// class name for frame window
+
+TCHAR g_szFrame[] = TEXT("fdFrame");
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: InitializeApp
+//
+// Synopsis: Main initialization routine for Disk Administrator.
+//
+// Arguments: (none)
+//
+// Returns: TRUE on success, FALSE on failure
+//
+// Modifies: lots and lots of state variables
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+BOOL
+InitializeApp(
+ VOID
+ )
+{
+ HDC hdcScreen = GetDC(NULL);
+
+ ReadProfile();
+
+ if (!InitOle())
+ {
+ daDebugOut((DEB_ERROR, "Failed to initialize OLE\n"));
+ return FALSE;
+ }
+
+ if (!InitializeWindowData())
+ {
+ daDebugOut((DEB_ERROR, "Failed to initialize Windows data\n"));
+ return FALSE;
+ }
+
+ if (InitializeDiskData() != NO_ERROR)
+ {
+ return FALSE;
+ }
+
+ DetermineExistence();
+
+ //
+ // Fill the listbox with bogus data, and draw the items. Set the
+ // initial list box selection cursor (don't allow to fall on an
+ // extended partition).
+ //
+ InitializeListBox(g_hwndList);
+ LBCursorListBoxItem = 0;
+ ResetLBCursorRegion();
+
+ //
+ // Initialize the listview control (volumes view)
+ //
+
+ InitializeListview();
+
+#ifdef WINDISK_EXTENSIONS
+
+ //
+ // Load the extension code
+ //
+
+ if (!GetExtensions())
+ {
+ daDebugOut((DEB_ERROR, "Failed to get the extension classes\n"));
+ return FALSE;
+ }
+
+#endif // WINDISK_EXTENSIONS
+
+ return TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+LPTSTR
+LoadOneString(
+ IN DWORD StringID
+ )
+
+/*++
+
+Routine Description:
+
+ Loads a string from the resource file and allocates a buffer of exactly
+ the right size to hold it.
+
+Arguments:
+
+ StringID - resource ID of string to load
+
+Return Value:
+
+ pointer to buffer. If string is not found, the first
+ (and only) char in the returned buffer will be 0.
+
+--*/
+
+{
+ TCHAR text[500];
+ LPTSTR buffer;
+
+ text[0] = TEXT('\0');
+ LoadString(g_hInstance, StringID, text, ARRAYLEN(text));
+ buffer = (LPTSTR)Malloc((lstrlen(text)+1)*sizeof(TCHAR));
+ lstrcpy(buffer, text);
+ return buffer;
+}
+
+
+
+BOOL
+InitializeWindowData(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes Windows data. It registers the frame window
+ class, creates the frame window, initializes all controls, and determines
+ all the global constant drawing metrics.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ boolean value indicating success or failure.
+
+--*/
+
+{
+ WNDCLASS wc;
+ TCHAR titleString[80];
+ HDC hdcScreen = GetDC(NULL);
+ TEXTMETRIC tm;
+ BITMAP bitmap;
+ HFONT hfontT;
+ unsigned i;
+
+ //
+ // Load cursors
+ //
+
+ g_hCurWait = LoadCursor(NULL, MAKEINTRESOURCE(IDC_WAIT));
+ g_hCurNormal = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
+
+ // fonts
+
+#ifdef JAPAN
+ g_hFontGraph = CreateFont(
+ GetHeightFromPoints(10),
+ 0,
+ 0,
+ 0,
+ 400,
+ FALSE,
+ FALSE,
+ FALSE,
+ SHIFTJIS_CHARSET,
+ OUT_DEFAULT_PRECIS,
+ CLIP_DEFAULT_PRECIS,
+ DEFAULT_QUALITY,
+ VARIABLE_PITCH | FF_SWISS,
+ TEXT("System")
+ );
+#else
+ g_hFontGraph = CreateFont(
+ GetHeightFromPoints(8),
+ 0,
+ 0,
+ 0,
+ 400,
+ FALSE,
+ FALSE,
+ FALSE,
+ ANSI_CHARSET,
+ OUT_DEFAULT_PRECIS,
+ CLIP_DEFAULT_PRECIS,
+ DEFAULT_QUALITY,
+ VARIABLE_PITCH | FF_SWISS,
+ TEXT("Helv")
+ );
+#endif
+
+ g_hFontLegend = g_hFontGraph;
+ g_hFontStatus = g_hFontGraph;
+
+#ifdef JAPAN
+ g_hFontGraphBold = CreateFont(
+ GetHeightFromPoints(10),
+ 0,
+ 0,
+ 0,
+ 700,
+ FALSE,
+ FALSE,
+ FALSE,
+ SHIFTJIS_CHARSET,
+ OUT_DEFAULT_PRECIS,
+ CLIP_DEFAULT_PRECIS,
+ DEFAULT_QUALITY,
+ VARIABLE_PITCH | FF_SWISS,
+ TEXT("System")
+ );
+#else
+ g_hFontGraphBold = CreateFont(
+ GetHeightFromPoints(8),
+ 0,
+ 0,
+ 0,
+ 700,
+ FALSE,
+ FALSE,
+ FALSE,
+ ANSI_CHARSET,
+ OUT_DEFAULT_PRECIS,
+ CLIP_DEFAULT_PRECIS,
+ DEFAULT_QUALITY,
+ VARIABLE_PITCH | FF_SWISS,
+ TEXT("Helv")
+ );
+#endif
+
+ //
+ // get the text metrics
+ //
+
+ hfontT = SelectFont(hdcScreen, g_hFontGraph);
+ GetTextMetrics(hdcScreen, &tm);
+ if (hfontT)
+ {
+ SelectFont(hdcScreen, hfontT);
+ }
+
+ g_hPenNull = CreatePen(PS_NULL , 0, 0);
+ g_hPenThinSolid = CreatePen(PS_SOLID, PEN_WIDTH, RGB(0, 0, 0));
+
+ GraphHeight = 25 * tm.tmHeight / 4; // 6.25 x font height
+
+ g_dyBorder = GetSystemMetrics(SM_CYBORDER);
+ g_dyStatus = tm.tmHeight + tm.tmExternalLeading + 7 * g_dyBorder;
+
+ g_wLegendItem = GetSystemMetrics(SM_CXHTHUMB);
+ g_dyLegendSep = 2*g_dyBorder; // used to be g_wLegendItem / 2, but that's too much
+
+ // set up brushes
+
+ for (i=0; i<BRUSH_ARRAY_SIZE; i++)
+ {
+ g_Brushes[i] = MyCreateHatchBrush(
+ AvailableHatches[BrushHatches[i]],
+ AvailableColors[BrushColors[i]]
+ );
+ }
+
+ g_hBrushFreeLogical = CreateHatchBrush(HS_FDIAGONAL, RGB(128, 128, 128));
+ g_hBrushFreePrimary = CreateHatchBrush(HS_BDIAGONAL, RGB(128, 128, 128));
+
+ // load legend strings
+
+ for (i = IDS_LEGEND_FIRST; i <= IDS_LEGEND_LAST; i++)
+ {
+ if (NULL == (LegendLabels[i-IDS_LEGEND_FIRST] = LoadOneString(i)))
+ {
+ return FALSE;
+ }
+ }
+
+ if ( ((wszUnformatted = LoadOneString(IDS_UNFORMATTED)) == NULL)
+ || ((wszUnknown = LoadOneString(IDS_UNKNOWN)) == NULL))
+ {
+ return FALSE;
+ }
+
+ BarTopYOffset = tm.tmHeight;
+ BarHeight = 21 * tm.tmHeight / 4;
+ BarBottomYOffset = BarTopYOffset + BarHeight;
+ dxBarTextMargin = 5*tm.tmAveCharWidth/4;
+ dyBarTextLine = tm.tmHeight;
+
+ dxDriveLetterStatusArea = 5 * tm.tmAveCharWidth / 2
+ + 8 * g_dyBorder // margin on either side
+ ;
+
+ //
+ // Get the small disk bitmap that goes to the left of the disk bar
+ //
+
+ g_hBitmapSmallDisk = LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_SMALLDISK));
+ GetObject(g_hBitmapSmallDisk, sizeof(BITMAP), &bitmap);
+ dxSmallDisk = bitmap.bmWidth;
+ dySmallDisk = bitmap.bmHeight;
+
+ xSmallDisk = dxSmallDisk / 2;
+ ySmallDisk = BarTopYOffset + (2*dyBarTextLine) - dySmallDisk - tm.tmDescent;
+
+ //
+ // Get the removable disk bitmap
+ //
+
+ g_hBitmapRemovableDisk = LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_REMOVABLEDISK));
+ GetObject(g_hBitmapRemovableDisk, sizeof(BITMAP), &bitmap);
+ dxRemovableDisk = bitmap.bmWidth;
+ dyRemovableDisk = bitmap.bmHeight;
+
+ xRemovableDisk = dxRemovableDisk / 2;
+ yRemovableDisk = BarTopYOffset + (2*dyBarTextLine) - dyRemovableDisk - tm.tmDescent;
+
+ //
+ // Get the small CD-ROM bitmap
+ //
+
+ g_hBitmapSmallCdRom = LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_SMALLCDROM));
+ GetObject(g_hBitmapSmallCdRom, sizeof(BITMAP), &bitmap);
+ dxSmallCdRom = bitmap.bmWidth;
+ dySmallCdRom = bitmap.bmHeight;
+
+ xSmallCdRom = xSmallDisk;
+ ySmallCdRom = ySmallDisk;
+
+
+ //
+ // Now, some numbers for drawing the bars
+ //
+
+ BarLeftX = 7 * dxSmallDisk;
+
+ // BarWidthMargin: the total amount of space that must exist
+ // excepting the bar itself
+ BarWidthMargin = BarLeftX + (5 * tm.tmAveCharWidth);
+
+ // BarWidthMinimum: the smallest allowable bar width
+ BarWidthMinimum = BarWidthMargin;
+
+ MinimumWindowWidth = BarWidthMargin + BarWidthMinimum;
+
+ DiskN = LoadOneString(IDS_DISKN);
+ CdRomN = LoadOneString(IDS_CDROMN);
+
+ //
+ // calculate the minimum region size
+ //
+
+ TCHAR szDrive[] = TEXT("A:");
+ SIZE size = {0};
+
+ hfontT = SelectFont(hdcScreen, g_hFontGraphBold);
+ if (!GetTextExtentPoint32(hdcScreen, szDrive, ARRAYLEN(szDrive) - 1, &size))
+ {
+ daDebugOut((DEB_ERROR,
+ "GetTextExtentPoint32 failed, error = 0x%08lx\n",
+ GetLastError()
+ ));
+ }
+ SelectFont(hdcScreen, hfontT);
+
+ ReleaseDC(NULL, hdcScreen);
+
+ g_MinimumRegionSize = size.cx + 2 * dxBarTextMargin;
+
+ // register the frame class
+
+ wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
+ wc.lpfnWndProc = MyFrameWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = g_hInstance;
+ wc.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDFDISK));
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = GetStockBrush(LTGRAY_BRUSH);
+ wc.lpszMenuName = MAKEINTRESOURCE(IDFDISK);
+ wc.lpszClassName = g_szFrame;
+
+ if (!RegisterClass(&wc))
+ {
+ return FALSE;
+ }
+
+ LoadString(g_hInstance, IDS_APPNAME, titleString, ARRAYLEN(titleString));
+
+ // create the frame window. Note that this also creates the listbox
+ // and the listview (volumes view), and the toolbar.
+
+ g_hwndFrame = CreateWindowEx(
+ 0,
+// WS_EX_WINDOWEDGE, //BUGBUG: not in Daytona USER
+ g_szFrame,
+ titleString,
+ WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
+ ProfileWindowX,
+ ProfileWindowY,
+ ProfileWindowW,
+ ProfileWindowH,
+ NULL,
+ NULL,
+ g_hInstance,
+ NULL
+ );
+
+ if (NULL == g_hwndFrame)
+ {
+ return FALSE;
+ }
+
+ InitToolbarButtons();
+
+ //
+ // Initialize the menu help
+ //
+
+ InitMenuHelp();
+
+ //
+ // Initialize the custom controls
+ //
+
+ UseRectControl(g_hInstance);
+ UseWindiskControls(g_hInstance);
+
+ return TRUE;
+}
+
+
+
+VOID
+CreateDiskState(
+ OUT PDISKSTATE* DiskState,
+ IN DWORD Disk,
+ OUT PBOOL SignatureCreated
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is designed to be called once, at initialization time,
+ per disk. It creates and initializes a disk state -- which includes
+ creating a memory DC and compatible bitmap for drawing the disk's
+ graph, and getting some information that is static in nature about
+ the disk (ie, its total size.)
+
+Arguments:
+
+ DiskState - structure whose fields are to be intialized
+
+ Disk - number of disk
+
+ SignatureCreated - received boolean indicating whether an FT signature was created for
+ the disk.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDISKSTATE diskState = (PDISKSTATE)Malloc(sizeof(DISKSTATE));
+
+ diskState->LeftRight = (PLEFTRIGHT)Malloc(0);
+ diskState->Selected = (PBOOLEAN)Malloc(0);
+ diskState->Disk = Disk;
+
+ // the memory DC and bitmap are created after a resize event
+
+ diskState->hDCMem = NULL;
+ diskState->hbmMem = NULL;
+
+ diskState->RegionArray = NULL;
+ diskState->RegionCount = 0;
+ diskState->BarType = BarAuto;
+ diskState->OffLine = IsDiskOffLine(Disk);
+
+ if (diskState->OffLine)
+ {
+ FDLOG((1, "CreateDiskState: Disk %u is off-line\n", Disk));
+
+ diskState->DiskSizeMB = 0;
+ diskState->SigWasCreated = FALSE;
+ diskState->Signature = 0;
+ }
+ else
+ {
+ diskState->DiskSizeMB = DiskSizeMB(Disk);
+
+ if (0 != (diskState->Signature = FdGetDiskSignature(Disk)))
+ {
+ if (SignatureIsUniqueToSystem(Disk, diskState->Signature))
+ {
+ FDLOG((2,
+ "CreateDiskState: Found signature %08lx on disk %u\n",
+ diskState->Signature,
+ Disk));
+
+ diskState->SigWasCreated = FALSE;
+ }
+ else
+ {
+ goto createSignature;
+ }
+ }
+ else
+ {
+
+createSignature:
+
+ if (!IsRemovable(Disk)) {
+ diskState->Signature = FormDiskSignature();
+ FdSetDiskSignature(Disk, diskState->Signature);
+ diskState->SigWasCreated = TRUE;
+
+ FDLOG((1,
+ "CreateDiskState: disk %u has either no signature or a non-unique signature; created signature %08lx\n",
+ Disk,
+ diskState->Signature));
+
+ }
+ }
+ }
+
+ *SignatureCreated = (BOOL)diskState->SigWasCreated;
+ *DiskState = diskState;
+}
+
+
+
+
+DWORD
+InitializeDiskData(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates the disk state structures, and determines the initial
+ volume labels and type names for all significant partitions.
+
+Arguments:
+
+ none
+
+Return Value:
+
+ Windows error code (esp. out of memory)
+
+--*/
+
+{
+ PPERSISTENT_REGION_DATA regionData;
+ TCHAR windowsDir[MAX_PATH];
+ unsigned i;
+ PDISKSTATE diskState;
+ DWORD ec;
+ ULONG regionIndex;
+ BOOL diskSignaturesCreated;
+ BOOL signatureCreated;
+
+ //
+ // First, create the array that will hold the diskstates,
+ // the IsDiskRemovable array and the RemovableDiskReservedDriveLetters
+ // array.
+ //
+
+ DiskArray = (PDISKSTATE*)Malloc(DiskCount * sizeof(PDISKSTATE));
+ DiskSeenCountArray = (PULONG)Malloc(DiskCount * sizeof(ULONG));
+
+ IsDiskRemovable = (PBOOLEAN)Malloc(DiskCount * sizeof(BOOLEAN));
+
+ RemovableDiskReservedDriveLetters = (PWCHAR)Malloc(DiskCount * sizeof(WCHAR));
+
+ //
+ // Determine which disks are removable and which are unpartitioned.
+ //
+ for (i=0; i<DiskCount; i++)
+ {
+ IsDiskRemovable[i] = IsRemovable(i);
+ }
+
+ // next, create all disk states
+
+ FDASSERT(DiskCount>0);
+ diskSignaturesCreated = FALSE;
+
+ for (i=0; i<DiskCount; i++)
+ {
+ // first create the disk state structure
+
+ CreateDiskState(&diskState, i, &signatureCreated);
+ diskSignaturesCreated = diskSignaturesCreated || signatureCreated;
+
+ DiskArray[i] = diskState;
+
+ // next determine the state of the disk's partitioning scheme
+
+ DeterminePartitioningState(diskState);
+
+ //
+ // Next create a blank logical disk structure for each region.
+ //
+
+ for (regionIndex = 0; regionIndex < diskState->RegionCount; regionIndex++)
+ {
+ if (DmSignificantRegion(&diskState->RegionArray[regionIndex]))
+ {
+ regionData = (PPERSISTENT_REGION_DATA)
+ Malloc(sizeof(PERSISTENT_REGION_DATA));
+
+ LARGE_INTEGER zero;
+ zero.QuadPart = 0;
+
+ DmInitPersistentRegionData(
+ regionData,
+ NULL,
+ NULL,
+ NULL,
+ NO_DRIVE_LETTER_YET,
+ FALSE,
+ zero,
+ zero
+ );
+ }
+ else
+ {
+ regionData = NULL;
+ }
+ DmSetPersistentRegionData(&diskState->RegionArray[regionIndex], regionData);
+ }
+ }
+
+ //
+ // Read the configuration registry
+ //
+
+ if ((ec = InitializeFt(diskSignaturesCreated)) != NO_ERROR)
+ {
+ ErrorDialog(ec);
+ return ec;
+ }
+
+ //
+ // Now, the correct FT persistent data is set based on the registry.
+ //
+
+ SetFTObjectBackPointers();
+
+ //
+ // Construct list of drives with pagefiles
+ //
+
+ LoadExistingPageFileInfo();
+
+ //
+ // Determine drive letter mappings
+ //
+
+ if (!InitializeDriveLetterInfo())
+ {
+ return ERROR_ACCESS_DENIED; //anything but NO_ERROR
+ }
+
+ // Initialize network information
+
+ NetworkInitialize();
+
+ if (!InitializeCdRomInfo())
+ {
+ return ERROR_ACCESS_DENIED; //anything but NO_ERROR
+ }
+
+ //
+ // Determine volume labels and type names.
+ //
+
+ InitVolumeInformation();
+
+ //
+ // Determine which disk is the boot disk.
+ //
+ if (GetWindowsDirectory(windowsDir, ARRAYLEN(windowsDir)) < 2
+ || windowsDir[1] != TEXT(':'))
+ {
+ BootDiskNumber = (ULONG)-1;
+ BootPartitionNumber = (ULONG)-1;
+ }
+ else
+ {
+ BootDiskNumber = GetDiskNumberFromDriveLetter(windowsDir[0]);
+ BootPartitionNumber = GetPartitionNumberFromDriveLetter(windowsDir[0]);
+ }
+
+#if defined( DBLSPACE_ENABLED )
+ //
+ // Locate and create data structures for any DoubleSpace volumes
+ //
+
+ DblSpaceInitialize();
+#endif // DBLSPACE_ENABLED
+
+ return NO_ERROR;
+}
+
+
+
+BOOL
+InitializationDlgProc(
+ IN HWND hDlg,
+ IN UINT uMsg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ standard Windows dialog procedure
+
+Return Values:
+
+ standard Windows dialog procedure
+
+--*/
+
+{
+ static DWORD percentDrawn;
+ static BOOL captionIsLoaded;
+ static PFORMAT_PARAMS formatParams;
+ TCHAR title[100],
+ templateString[100];
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ g_InitDlg = hDlg;
+ percentDrawn = 0;
+ g_StartedAsIcon = IsIconic(hDlg);
+ return TRUE;
+ }
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ HDC hDC = BeginPaint(hDlg, &ps);
+ DrawGasGauge(
+ GetDlgItem(hDlg, IDC_GASGAUGE),
+ hDlg,
+ hDC,
+ percentDrawn,
+ NULL);
+ EndPaint(hDlg, &ps);
+
+ if (percentDrawn == 100)
+ {
+ g_InitDlgComplete = TRUE;
+ }
+ return TRUE;
+ }
+
+ case WM_STARTUP_UPDATE:
+ {
+ // wParam = % completed
+
+ percentDrawn = (INT)wParam;
+
+ RECT rcGauge;
+ HWND hwndGauge = GetDlgItem(hDlg, IDC_GASGAUGE);
+
+ GetClientRect(hwndGauge, &rcGauge);
+
+ ClientToScreen(hwndGauge, (LPPOINT)&rcGauge.left);
+ ClientToScreen(hwndGauge, (LPPOINT)&rcGauge.right);
+ ScreenToClient(hDlg, (LPPOINT)&rcGauge.left);
+ ScreenToClient(hDlg, (LPPOINT)&rcGauge.right);
+
+ InvalidateRect(hDlg, &rcGauge, FALSE);
+ UpdateWindow(hDlg);
+
+ return TRUE;
+ }
+
+ case WM_STARTUP_END:
+ EndDialog(hDlg, TRUE);
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+}
+
+DWORD WINAPI
+InitializationMessageThread(
+ LPVOID ThreadParameter
+ )
+
+/*++
+
+Routine Description:
+
+ This is the entry for the initialization message thread. It creates
+ a dialog that simply tells the user to be patient.
+
+Arguments:
+
+ ThreadParameter - not used.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ DialogBox(g_hInstance,
+ MAKEINTRESOURCE(IDD_STARTUP),
+ g_hwndFrame,
+ InitializationDlgProc);
+ g_InitDlg = NULL;
+ ExitThread(0L);
+ return 0L;
+}
+
+
+VOID
+DisplayInitializationMessage(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Create a 2nd thread to display an initialization message.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ HANDLE threadHandle;
+ DWORD threadId;
+
+ threadHandle = CreateThread(NULL,
+ 0,
+ InitializationMessageThread,
+ NULL,
+ 0,
+ &threadId);
+ if (NULL != threadHandle)
+ {
+ CloseHandle(threadHandle);
+ }
+}
diff --git a/private/utils/windisk/src/init.hxx b/private/utils/windisk/src/init.hxx
new file mode 100644
index 000000000..2586b6212
--- /dev/null
+++ b/private/utils/windisk/src/init.hxx
@@ -0,0 +1,32 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: init.hxx
+//
+// Contents: Declarations for initializing the Disk Administrator
+//
+// History: 7-Jan-92 TedM Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __INIT_HXX__
+#define __INIT_HXX__
+
+//////////////////////////////////////////////////////////////////////////////
+
+#define WM_STARTUP_UPDATE (WM_USER)
+#define WM_STARTUP_END (WM_USER + 1)
+
+BOOL
+InitializeApp(
+ VOID
+ );
+
+VOID
+DisplayInitializationMessage(
+ VOID
+ );
+
+#endif // __INIT_HXX__
diff --git a/private/utils/windisk/src/label.cxx b/private/utils/windisk/src/label.cxx
new file mode 100644
index 000000000..1ed79f9ab
--- /dev/null
+++ b/private/utils/windisk/src/label.cxx
@@ -0,0 +1,216 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: label.cxx
+//
+// Contents: Change volume label.
+//
+// History: 14-Jan-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include <util.hxx>
+
+#include "dialogs.h"
+#include "fmifs.hxx"
+#include "fs.hxx"
+#include "help.hxx"
+#include "label.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+LOCAL BOOL CALLBACK
+SetLabelDlgProc(
+ IN HWND hDlg,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+//////////////////////////////////////////////////////////////////////////////
+
+typedef struct _LABEL_PARAMS
+{
+ INT MaxLabelLen;
+ WCHAR Label[MAXLABELLEN];
+
+ HWND hwndParent;
+
+} LABEL_PARAMS, *PLABEL_PARAMS;
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: SetLabelDlgProc
+//
+// Synopsis: Dialog procedure for Set Label UI.
+//
+// Arguments: standard Windows dialog procedure
+//
+// Returns: standard Windows dialog procedure
+//
+// History: 27-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+LOCAL BOOL CALLBACK
+SetLabelDlgProc(
+ IN HWND hDlg,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ static PLABEL_PARAMS labelParams;
+
+ switch (msg)
+ {
+ case WM_INITDIALOG:
+ {
+ labelParams = (PLABEL_PARAMS)lParam;
+
+ CenterWindow(hDlg, labelParams->hwndParent);
+
+ SendDlgItemMessage(
+ hDlg,
+ IDC_LABEL,
+ EM_LIMITTEXT,
+ labelParams->MaxLabelLen,
+ 0L);
+
+ // set the label to the current label, and select it
+
+ SetDlgItemText(hDlg, IDC_LABEL, labelParams->Label);
+ SendDlgItemMessage(hDlg, IDC_LABEL, EM_SETSEL, 0, (LPARAM)-1);
+
+ SetFocus(GetDlgItem(hDlg, IDC_LABEL));
+
+ return 0; // called SetFocus
+ }
+
+ case WM_COMMAND:
+
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ GetDlgItemText(
+ hDlg,
+ IDC_LABEL,
+ labelParams->Label,
+ ARRAYLEN(labelParams->Label));
+
+ EndDialog(hDlg, TRUE);
+ return TRUE;
+
+ case IDCANCEL:
+ EndDialog(hDlg, FALSE);
+ return TRUE;
+
+ case IDHELP:
+ DialogHelp(HC_DM_DLG_LABEL);
+ return TRUE;
+ }
+
+ default:
+ break;
+ }
+
+ return FALSE; // message not processed
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DoLabel
+//
+// Synopsis: Get a volume label from the user, and set the volume label
+//
+// Arguments: none
+//
+// Returns: nothing
+//
+// History: 27-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DoLabel(
+ IN HWND hwndParent
+ )
+{
+ if (!LoadFmifs())
+ {
+ return; // can't load fmifs.dll, so bail
+ }
+
+ DWORD ec;
+
+ PREGION_DESCRIPTOR regionDescriptor = &SELECTED_REGION(0);
+ FDASSERT(regionDescriptor);
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(regionDescriptor);
+ FDASSERT(regionData);
+
+ LABEL_PARAMS labelParams;
+
+ FileSystemInfoType* pFSInfo = FindFileSystemInfo(regionData->TypeName);
+
+ labelParams.hwndParent = hwndParent;
+ lstrcpy(labelParams.Label, regionData->VolumeLabel);
+
+ if (NULL == pFSInfo)
+ {
+ labelParams.MaxLabelLen = MAXLABELLEN - 1;
+ }
+ else
+ {
+ labelParams.MaxLabelLen = pFSInfo->cMaxLabelLen;
+ }
+
+ int fOk = DialogBoxParam(
+ g_hInstance,
+ MAKEINTRESOURCE(IDD_LABEL),
+ hwndParent,
+ SetLabelDlgProc,
+ (LPARAM)&labelParams
+ );
+
+ if (-1 == fOk)
+ {
+ // error creating dialog
+ daDebugOut((DEB_ERROR, "DialogBox() failed!\n"));
+ return;
+ }
+
+ if (fOk)
+ {
+ EnsureSameDevice(regionDescriptor);
+
+ WCHAR DriveName[3];
+ DriveName[0] = regionData->DriveLetter;
+ DriveName[1] = L':';
+ DriveName[2] = L'\0';
+
+ SetLastError(NO_ERROR);
+ (*lpfnSetLabel)(DriveName, labelParams.Label);
+ ec = GetLastError();
+
+ if (ec != NO_ERROR)
+ {
+ ErrorDialog(ec);
+ }
+ else
+ {
+ RefreshVolumeData();
+ }
+ }
+}
diff --git a/private/utils/windisk/src/label.hxx b/private/utils/windisk/src/label.hxx
new file mode 100644
index 000000000..8b3bdda3d
--- /dev/null
+++ b/private/utils/windisk/src/label.hxx
@@ -0,0 +1,22 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: label.hxx
+//
+// Contents: Change volume label.
+//
+// History: 14-Jan-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __LABEL_HXX__
+#define __LABEL_HXX__
+
+VOID
+DoLabel(
+ IN HWND hwndParent
+ );
+
+#endif // __LABEL_HXX__
diff --git a/private/utils/windisk/src/listbox.cxx b/private/utils/windisk/src/listbox.cxx
new file mode 100644
index 000000000..798d72912
--- /dev/null
+++ b/private/utils/windisk/src/listbox.cxx
@@ -0,0 +1,1113 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: listbox.cxx
+//
+// Contents: Routines for handling the subclassed owner-draw listbox
+// used for the disks view display.
+//
+// History: 7-Jan-92 TedM Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include "cdrom.hxx"
+#include "cm.hxx"
+#include "listbox.hxx"
+#include "select.hxx"
+#include "windisk.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+/*
+
+ Notes on the disks view implementation.
+
+ The disks view is a subclassed, owner-draw, Windows listbox control.
+ The listbox items are irrelevant: it is only the number of items
+ that is important. Both disks (including off-line disks) and CD-ROMs
+ are shown in this view, as follows:
+
+ Disk 0
+ Disk 1
+ ...
+ Disk N
+ CD-ROM 0
+ CD-ROM 1
+ ...
+ CD-ROM N
+
+ So, the CD-ROMs follow all the disks. What this means is that the
+ listbox index can be used as an index into the DiskArray array. The
+ listbox index minus DiskCount is the CD-ROM DeviceNumber. The
+ number of CD-ROMs and Disks in the system is constant after the SCSI
+ bus is rescanned upon Windisk startup.
+
+*/
+
+//////////////////////////////////////////////////////////////////////////////
+
+// constants used when listbox or its focus rectangle is
+// scrolled/moved.
+
+#define DIR_NONE 0
+#define DIR_UP 1
+#define DIR_DN 2
+
+//////////////////////////////////////////////////////////////////////////////
+
+// original window procedure for our subclassed listbox
+
+WNDPROC OldListBoxProc;
+
+// item which has focus
+
+DWORD LBCursorListBoxItem;
+DWORD LBCursorRegion;
+BOOL LBCursorOn = FALSE;
+
+ULONG g_MouseLBIndex; // listbox index of mouse click
+ULONG g_MouseRegion;
+
+//////////////////////////////////////////////////////////////////////////////
+
+BOOL
+IsItemUnderCursorSelected(
+ IN PPOINT ppt
+ );
+
+BOOL
+ContextMenuSelection(
+ IN PPOINT ppt
+ );
+
+ULONG
+CalcBarIndex(
+ IN PPOINT ppt
+ );
+
+VOID
+ToggleLBCursor(
+ IN HDC hdc
+ );
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: LBIsDisk
+//
+// Synopsis: returns TRUE if the listbox index is for a disk
+//
+// Arguments: [itemIndex] -- a listbox index
+//
+// Returns: TRUE if the item is a disk
+//
+// History: 1-Mar-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+BOOL
+LBIsDisk(
+ IN ULONG itemIndex
+ )
+{
+ return (itemIndex < DiskCount);
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: LBIsCdRom
+//
+// Synopsis: returns TRUE if the listbox index is for a CD-ROM
+//
+// Arguments: [itemIndex] -- a listbox index
+//
+// Returns: TRUE if the item is a CD-ROM
+//
+// History: 1-Mar-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+BOOL
+LBIsCdRom(
+ IN ULONG itemIndex
+ )
+{
+ return (DiskCount <= itemIndex) && (itemIndex < DiskCount + CdRomCount);
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: LBIndexToDiskNumber
+//
+// Synopsis: returns the disk number of a listbox index
+//
+// Arguments: [ItemIndex] -- a listbox index
+//
+// Returns: A disk number
+//
+// History: 1-Mar-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+BOOL
+LBIndexToDiskNumber(
+ IN ULONG ItemIndex
+ )
+{
+ FDASSERT(LBIsDisk(ItemIndex));
+ return ItemIndex;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: LBIndexToCdRomNumber
+//
+// Synopsis: returns the CD-ROM number of a listbox index
+//
+// Arguments: [ItemIndex] -- a listbox index
+//
+// Returns: A CD-ROM number
+//
+// History: 1-Mar-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+BOOL
+LBIndexToCdRomNumber(
+ IN ULONG ItemIndex
+ )
+{
+ FDASSERT(LBIsCdRom(ItemIndex));
+ return ItemIndex - DiskCount;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: LBDiskNumberToIndex
+//
+// Synopsis: returns the listbox index of a disk
+//
+// Arguments: [DiskNumber] -- the number of the disk
+//
+// Returns: A listbox index
+//
+// History: 1-Mar-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+ULONG
+LBDiskNumberToIndex(
+ IN ULONG DiskNumber
+ )
+{
+ FDASSERT(0 <= DiskNumber && DiskNumber < DiskCount);
+ return DiskNumber;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: LBCdRomNumberToIndex
+//
+// Synopsis: returns the listbox index of a CD-ROM
+//
+// Arguments: [CdRomNumber] -- a CD-ROM number
+//
+// Returns: A listbox index
+//
+// History: 1-Mar-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+ULONG
+LBCdRomNumberToIndex(
+ IN ULONG CdRomNumber
+ )
+{
+ FDASSERT(0 <= CdRomNumber && CdRomNumber < CdRomCount);
+ return CdRomNumber + DiskCount;
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: IsItemUnderCursorSelected
+//
+// Synopsis:
+//
+// Arguments: [ppt] -- point in screen coordinates of point to check
+//
+// Returns: TRUE if the item under the point is selected
+//
+// Modifies: g_MouseLBIndex, g_MouseRegion
+//
+// History: 26-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+BOOL
+IsItemUnderCursorSelected(
+ IN PPOINT ppt
+ )
+{
+ DWORD x, y;
+ DWORD i;
+ RECT rc;
+ POINT pt = *ppt;
+
+ g_MouseLBIndex = (ULONG)-1;
+ g_MouseRegion = (ULONG)-1;
+
+ ScreenToClient(g_hwndList, &pt);
+
+ x = pt.x;
+ y = pt.y;
+ GetClientRect(g_hwndList, &rc);
+
+ // first make sure that the click was within a bar and not in space
+ // between two bars
+
+ for (i = rc.top; i <= (DWORD)rc.bottom; i += GraphHeight)
+ {
+ if ((y >= i+BarTopYOffset) && (y <= i+BarBottomYOffset))
+ {
+ break;
+ }
+ }
+ if (i > (DWORD)rc.bottom)
+ {
+ return FALSE;
+ }
+
+ g_MouseLBIndex = CalcBarIndex(ppt);
+
+ if (-1 == g_MouseLBIndex)
+ {
+ return FALSE;
+ }
+
+ if (LBIsDisk(g_MouseLBIndex))
+ {
+ PDISKSTATE diskState = DiskArray[LBIndexToDiskNumber(g_MouseLBIndex)];
+
+ for (i=0; i<diskState->RegionCount; i++)
+ {
+ if ( (x >= (unsigned)diskState->LeftRight[i].Left)
+ && (x <= (unsigned)diskState->LeftRight[i].Right))
+ {
+ //
+ // found the region, now is it selected?
+ //
+ g_MouseRegion = i;
+ return diskState->Selected[i];
+ }
+ }
+ }
+ else if (LBIsCdRom(g_MouseLBIndex))
+ {
+ PCDROM_DESCRIPTOR cdrom = CdRomFindDevice(LBIndexToCdRomNumber(g_MouseLBIndex));
+ if ( (x >= (unsigned)cdrom->LeftRight.Left)
+ && (x <= (unsigned)cdrom->LeftRight.Right))
+ {
+ return cdrom->Selected;
+ }
+ }
+ else
+ {
+ FDASSERT(FALSE);
+ }
+
+ return FALSE;
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: ContextMenuSelection
+//
+// Synopsis: Determines whether there is a valid context menu to display
+// at a particular point, and set state variables to indicate
+// which one is legal.
+//
+// Arguments: [ppt] -- point in screen coordinates of location of right-mouse
+// click
+//
+// Returns: TRUE if there may is valid context menu selection, FALSE if
+// there is no possible context menu
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+BOOL
+ContextMenuSelection(
+ IN PPOINT ppt
+ )
+{
+ DiskSelected = FALSE;
+
+ PartitionSelected = IsItemUnderCursorSelected(ppt);
+
+ if (-1 != g_MouseLBIndex)
+ {
+ // user has clicked on a list box item.
+
+ if (LBIsDisk(g_MouseLBIndex))
+ {
+ PDISKSTATE diskState;
+ DWORD x, y;
+ POINT pt = *ppt;
+
+ diskState = DiskArray[LBIndexToDiskNumber(g_MouseLBIndex)];
+
+ //
+ // Ignore clicks on off-line disks.
+ //
+
+ if (diskState->OffLine)
+ {
+ return FALSE; //BUGBUG: what to do with off-line disks?
+ }
+
+ ScreenToClient(g_hwndList, &pt);
+
+ x = pt.x;
+ y = pt.y;
+
+ if (x >= 0 && x < (unsigned)diskState->LeftRight[0].Left)
+ {
+ //
+ // select the disk by right-clicking to the left of the disk bar
+ // BUGBUG: only allow selecting the disk context menu by
+ // clicking the mini-icon
+ //
+
+ DiskSelected = TRUE;
+ }
+ }
+ else if (LBIsCdRom(g_MouseLBIndex))
+ {
+ //BUGBUG: context menu on CD-ROM?
+ }
+ else
+ {
+ FDASSERT(FALSE);
+ }
+ }
+
+ return (PartitionSelected || DiskSelected);
+}
+
+
+
+
+
+LPARAM CALLBACK
+ListBoxSubProc(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the window procedure used for our subclassed listbox.
+ We subclass the listbox so that we can handle keyboard input processing.
+ All other messages are passed through to the original listbox procedure.
+
+ Significant keys are arrows, pageup/dn, tab, space, return, home, and end.
+ Control may be used to modify space and return.
+ Shift may be used to modify tab.
+
+Arguments:
+
+ hwnd - window handle of listbox
+
+ msg - message #
+
+ wParam - user param # 1
+
+ lParam - user param # 2
+
+Return Value:
+
+ see below
+
+--*/
+
+{
+ USHORT vKey;
+ DWORD maxRegionIndex;
+ DWORD maxLBIndex;
+ PDISKSTATE diskState;
+ int focusDirection = DIR_NONE;
+ LONG topItem;
+ LONG bottomWholeItem;
+ LONG visibleItems;
+ RECT rc;
+
+ switch (msg)
+ {
+ case WM_RBUTTONDOWN:
+ {
+ BOOL fCtrl = GetKeyState(VK_CONTROL) & ~1; // strip toggle bit
+ DWORD pos = GetMessagePos();
+ POINT pt;
+ pt.x = LOWORD(pos);
+ pt.y = HIWORD(pos);
+
+ if (fCtrl || !IsItemUnderCursorSelected(&pt))
+ {
+ //
+ // Select the region under the mouse. Do this by setting
+ // the selected listbox item then setting the region selection.
+ //
+
+ ULONG lbIndex = CalcBarIndex(&pt);
+ if (SendMessage(hwnd, LB_SETCURSEL, lbIndex, 0) == LB_ERR)
+ {
+ return FALSE;
+ }
+
+ MouseSelection(fCtrl, &pt);
+ }
+
+ break;
+ }
+
+ case WM_RBUTTONUP:
+ {
+ POINT pt;
+ DWORD pos = GetMessagePos();
+ pt.x = LOWORD(pos);
+ pt.y = HIWORD(pos);
+
+ //
+ // Then, pop up an appropriate context menu
+ //
+
+ if (ContextMenuSelection(&pt))
+ {
+ if (DiskSelected)
+ {
+ DiskContextMenu(&pt);
+ }
+ else if (PartitionSelected)
+ {
+ ContextMenu(&pt); // volume or free space
+ }
+ // else, no context menu, but this shouldn't happen inside the
+ // ContextMenuSelection() true case
+ }
+
+ break;
+ }
+
+ case WM_CHAR:
+
+ break;
+
+ case WM_KEYDOWN:
+
+ switch (vKey = LOWORD(wParam))
+ {
+ case VK_LEFT:
+ case VK_RIGHT:
+ case VK_UP:
+ case VK_DOWN:
+
+ ToggleLBCursor(NULL);
+ switch (vKey)
+ {
+ case VK_LEFT:
+ if (LBCursorRegion > 0)
+ {
+ LBCursorRegion--;
+ }
+ break;
+
+ case VK_RIGHT:
+ if (LBIsDisk(LBCursorListBoxItem))
+ {
+ maxRegionIndex = DiskArray[LBIndexToDiskNumber(LBCursorListBoxItem)]->RegionCount - 1;
+ }
+ else if (LBIsCdRom(LBCursorListBoxItem))
+ {
+ maxRegionIndex = 0;
+ }
+
+ if (LBCursorRegion < maxRegionIndex)
+ {
+ LBCursorRegion++;
+ }
+ break;
+
+ case VK_UP:
+ if (LBCursorListBoxItem > 0)
+ {
+ LBCursorListBoxItem--;
+ LBCursorRegion = 0;
+ focusDirection = DIR_UP;
+ }
+ break;
+
+ case VK_DOWN:
+ maxLBIndex = SendMessage(hwnd, LB_GETCOUNT, 0, 0) - 1;
+
+ if (LBCursorListBoxItem < maxLBIndex)
+ {
+ LBCursorListBoxItem++;
+ LBCursorRegion = 0;
+ focusDirection = DIR_DN;
+ }
+ break;
+ }
+
+ // don't allow list box cursor to fall on extended partition
+
+ if (LBIsDisk(LBCursorListBoxItem))
+ {
+ diskState = DiskArray[LBIndexToDiskNumber(LBCursorListBoxItem)];
+
+ if (diskState->RegionCount) {
+ maxRegionIndex = diskState->RegionCount - 1;
+ if (IsExtended(diskState->RegionArray[LBCursorRegion].SysID))
+ {
+ if (LBCursorRegion
+ && ((vKey == VK_LEFT) || (LBCursorRegion == maxRegionIndex)))
+ {
+ LBCursorRegion--;
+ }
+ else
+ {
+ LBCursorRegion++;
+ }
+ }
+ }
+ }
+
+ ToggleLBCursor(NULL);
+ break;
+
+ case VK_TAB:
+
+ ToggleLBCursor(NULL);
+
+ if (GetKeyState(VK_SHIFT) & ~1) // shift-tab
+ {
+ LBCursorListBoxItem--;
+ focusDirection = DIR_UP;
+ }
+ else
+ {
+ LBCursorListBoxItem++;
+ focusDirection = DIR_DN;
+ }
+
+ maxLBIndex = SendMessage(hwnd, LB_GETCOUNT, 0, 0) - 1;
+
+ if (LBCursorListBoxItem == (DWORD)(-1))
+ {
+ LBCursorListBoxItem = maxLBIndex;
+ focusDirection = DIR_DN;
+ }
+ else if (LBCursorListBoxItem == maxLBIndex + 1)
+ {
+ LBCursorListBoxItem = 0;
+ focusDirection = DIR_UP;
+ }
+
+ ResetLBCursorRegion();
+ ToggleLBCursor(NULL);
+ break;
+
+ case VK_HOME:
+ case VK_END:
+
+ ToggleLBCursor(NULL);
+ maxLBIndex = SendMessage(hwnd, LB_GETCOUNT, 0, 0) - 1;
+ topItem = (vKey == VK_HOME) ? 0 : maxLBIndex;
+ SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)topItem, 0);
+ LBCursorListBoxItem = topItem;
+ ResetLBCursorRegion();
+ ToggleLBCursor(NULL);
+ break;
+
+ case VK_PRIOR:
+ case VK_NEXT:
+
+ ToggleLBCursor(NULL);
+ topItem = SendMessage(hwnd, LB_GETTOPINDEX, 0, 0);
+ maxLBIndex = SendMessage(hwnd, LB_GETCOUNT, 0, 0) - 1;
+ GetClientRect(hwnd, &rc);
+ visibleItems = (rc.bottom - rc.top) / GraphHeight;
+ if (0 == visibleItems)
+ {
+ visibleItems = 1;
+ }
+ topItem = (vKey == VK_PRIOR)
+ ? max(topItem - visibleItems, 0)
+ : min(topItem + visibleItems, (LONG)maxLBIndex);
+ SendMessage(hwnd, LB_SETTOPINDEX, (WPARAM)topItem, 0);
+ LBCursorListBoxItem = SendMessage(hwnd, LB_GETTOPINDEX, 0, 0);
+ ResetLBCursorRegion();
+ ToggleLBCursor(NULL);
+ break;
+
+ case VK_RETURN:
+ case VK_SPACE:
+
+ // Select the region that currently has the list box selection cursor.
+
+ if (LBIsDisk(LBCursorListBoxItem))
+ {
+ if (!DiskArray[LBIndexToDiskNumber(LBCursorListBoxItem)]->OffLine)
+ {
+ SelectDiskRegion(
+ GetKeyState(VK_CONTROL) & ~1, // strip toggle bit
+ DiskArray[LBIndexToDiskNumber(LBCursorListBoxItem)],
+ LBCursorRegion
+ );
+ }
+ }
+ else if (LBIsCdRom(LBCursorListBoxItem))
+ {
+ SelectCdRom(
+ GetKeyState(VK_CONTROL) & ~1, // strip toggle bit
+ LBIndexToCdRomNumber(LBCursorListBoxItem)
+ );
+ }
+ break;
+ }
+
+ // now scroll the newly focused item into view if necessary
+
+ switch (focusDirection)
+ {
+ case DIR_UP:
+ if (LBCursorListBoxItem < (DWORD)SendMessage(hwnd, LB_GETTOPINDEX, 0, 0))
+ {
+ SendMessage(hwnd, LB_SETTOPINDEX, LBCursorListBoxItem, 0);
+ }
+ break;
+
+ case DIR_DN:
+ GetClientRect(hwnd, &rc);
+ topItem = SendMessage(hwnd, LB_GETTOPINDEX, 0, 0);
+ bottomWholeItem = topItem + ((rc.bottom - rc.top) / GraphHeight) - 1;
+ if (bottomWholeItem < topItem)
+ {
+ bottomWholeItem = topItem;
+ }
+
+ if ((DWORD)bottomWholeItem > DiskCount - 1)
+ {
+ bottomWholeItem = DiskCount-1;
+ }
+
+ if (LBCursorListBoxItem > (DWORD)bottomWholeItem)
+ {
+ SendMessage(hwnd,
+ LB_SETTOPINDEX,
+ topItem + LBCursorListBoxItem - bottomWholeItem,
+ 0
+ );
+ }
+ break;
+ }
+ break;
+
+ default:
+ return CallWindowProc(OldListBoxProc, hwnd, msg, wParam, lParam);
+ }
+ return 0;
+}
+
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: CalcBarIndex
+//
+// Synopsis: Given a point (in screen coordinates), return what bar index
+// corresponds to it.
+//
+// Arguments: [ppt] -- point in screen coordinates
+//
+// Returns: Index of bar in disks listbox, -1 if no disk
+//
+// History: 26-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+ULONG
+CalcBarIndex(
+ IN PPOINT ppt
+ )
+{
+ ULONG barDelta;
+ POINT pt = *ppt;
+
+ ScreenToClient(g_hwndList, &pt);
+
+ barDelta = SendMessage(g_hwndList, LB_GETTOPINDEX, 0, 0)
+ + (pt.y / GraphHeight);
+
+ if (barDelta >= (ULONG)SendMessage(g_hwndList, LB_GETCOUNT, 0, 0))
+ {
+ barDelta = (ULONG)-1;
+ }
+
+ return barDelta;
+}
+
+
+
+
+LONG
+CalcBarTop(
+ DWORD Bar
+ )
+
+/*++
+
+Routine Description:
+
+ This routine calculates the current top y coord of a given bar.
+ The value is in listbox client coords.
+
+Arguments:
+
+ Bar - # of bar whose position is desired
+
+Return Value:
+
+ Y-coord, or -1 if bar is not visible.
+
+--*/
+
+{
+ RECT rc;
+ LONG barDelta = (LONG)Bar - SendMessage(g_hwndList, LB_GETTOPINDEX, 0, 0);
+ LONG pos = -1;
+
+ if (barDelta >= 0) // BUGBUG check bottom too
+ {
+ GetClientRect(g_hwndList, &rc);
+ pos = rc.top + (barDelta * GraphHeight);
+ }
+ return pos;
+}
+
+
+
+
+VOID
+ResetLBCursorRegion(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine resets the list box focus cursor to the 0th (leftmost)
+ region on the current disk. If the 0th region is the extended
+ partition, focus is set to the first logical volume or free space
+ with the extended partition instead.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LBCursorRegion = 0;
+
+ if (LBIsDisk(LBCursorListBoxItem))
+ {
+ PDISKSTATE diskState = DiskArray[LBIndexToDiskNumber(LBCursorListBoxItem)];
+ unsigned i;
+
+ if (!diskState->OffLine) {
+ if (IsExtended(diskState->RegionArray[LBCursorRegion].SysID))
+ {
+ for (i=0; i<diskState->RegionCount; i++)
+ {
+ if (diskState->RegionArray[i].RegionType == REGION_LOGICAL)
+ {
+ LBCursorRegion = i;
+ return;
+ }
+ }
+ FDASSERT(FALSE); //shouldn't ever get here
+ }
+ }
+ }
+}
+
+
+
+
+VOID
+ToggleLBCursor(
+ IN HDC hdc
+ )
+
+/*++
+
+Routine Description:
+
+ This routine visually toggles the focus state of the disk region
+ described by the LBCursorListBoxItem and LBCursorRegion globals.
+
+Arguments:
+
+ hdc - If non-NULL, device context to use for drawing. If NULL,
+ we'll first get a DC via GetDC().
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LONG barTop = CalcBarTop(LBCursorListBoxItem);
+
+ if (barTop != -1)
+ {
+ PLEFTRIGHT leftRight;
+ PDISKSTATE LBCursorDisk = DiskArray[LBCursorListBoxItem];
+
+ if (LBIsDisk(LBCursorListBoxItem))
+ {
+ leftRight = &DiskArray[LBIndexToDiskNumber(LBCursorListBoxItem)]->LeftRight[LBCursorRegion];
+ }
+ else if (LBIsCdRom(LBCursorListBoxItem))
+ {
+ PCDROM_DESCRIPTOR cdrom = CdRomFindDevice(LBIndexToCdRomNumber(LBCursorListBoxItem));
+ leftRight = &cdrom->LeftRight;
+ }
+ else
+ {
+ FDASSERT(FALSE);
+ }
+
+ RECT rc;
+ HDC hdcActual = hdc ? hdc : GetDC(g_hwndList);
+
+ LBCursorOn = !LBCursorOn;
+
+ rc.left = leftRight->Left;
+ rc.right = leftRight->Right;
+ rc.top = barTop + BarTopYOffset;
+ rc.bottom = barTop + BarBottomYOffset;
+
+ FrameRect(hdcActual,
+ &rc,
+ GetStockBrush(LBCursorOn ? WHITE_BRUSH : BLACK_BRUSH));
+
+ if (LBCursorOn)
+ {
+ DrawFocusRect(hdcActual, &rc);
+ }
+
+ if (NULL == hdc)
+ {
+ ReleaseDC(g_hwndList, hdcActual);
+ }
+ }
+}
+
+
+
+
+VOID
+ForceLBRedraw(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine forces redraw of the listbox by invalidating its
+ entire client area.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ InvalidateRect(g_hwndList, NULL, TRUE);
+ UpdateWindow(g_hwndList);
+}
+
+
+
+BOOL
+WMDrawItem(
+ IN PDRAWITEMSTRUCT pDrawItem
+ )
+{
+ if ( (pDrawItem->itemID != (DWORD)(-1))
+ && (pDrawItem->itemAction == ODA_DRAWENTIRE))
+ {
+ DWORD regionIndex;
+ PDISKSTATE diskState;
+ PCDROM_DESCRIPTOR cdrom;
+ HDC hDCMem;
+
+ if (LBIsDisk(pDrawItem->itemID))
+ {
+ diskState = DiskArray[LBIndexToDiskNumber(pDrawItem->itemID)];
+ hDCMem = diskState->hDCMem;
+ }
+ else if (LBIsCdRom(pDrawItem->itemID))
+ {
+ cdrom = CdRomFindDevice(LBIndexToCdRomNumber(pDrawItem->itemID));
+ hDCMem = cdrom->hDCMem;
+ }
+
+ // blt the disk's bar from the off-screen bitmap to the screen
+
+ BitBlt(pDrawItem->hDC,
+ pDrawItem->rcItem.left,
+ pDrawItem->rcItem.top,
+ pDrawItem->rcItem.right - pDrawItem->rcItem.left + 1,
+ pDrawItem->rcItem.bottom - pDrawItem->rcItem.top + 1,
+ hDCMem,
+ 0,
+ 0,
+ SRCCOPY
+ );
+
+ // if we just overwrote the focus cursor, redraw it
+
+ if (pDrawItem->itemID == LBCursorListBoxItem)
+ {
+ LBCursorOn = FALSE;
+ ToggleLBCursor(pDrawItem->hDC);
+ }
+
+ // select any items selected in this bar
+
+ if (LBIsDisk(pDrawItem->itemID))
+ {
+ for (regionIndex = 0; regionIndex<diskState->RegionCount; regionIndex++)
+ {
+ if (diskState->Selected[regionIndex])
+ {
+ PaintDiskRegion(diskState, regionIndex, pDrawItem->hDC);
+ }
+ }
+ }
+ else if (LBIsCdRom(pDrawItem->itemID))
+ {
+ if (cdrom->Selected)
+ {
+ PaintCdRom(LBIndexToCdRomNumber(pDrawItem->itemID), pDrawItem->hDC);
+ }
+ }
+
+ return TRUE; // message handled
+ }
+
+ return FALSE; // message NOT handled
+}
+
+
+
+VOID
+SubclassListBox(
+ IN HWND hwnd
+ )
+{
+ OldListBoxProc = (WNDPROC)GetWindowLong(hwnd, GWL_WNDPROC);
+ SetWindowLong(hwnd, GWL_WNDPROC, (LONG)ListBoxSubProc);
+
+ //
+ // There is a scantily documented 'feature' of a listbox wherein it will
+ // use its parent's DC. This means that drawing is not always clipped to
+ // the client area of the listbox. Seeing as we're subclassing listboxes
+ // anyway, take care of this here.
+ //
+ SetClassLong(hwnd, GCL_STYLE, GetClassLong(hwnd, GCL_STYLE) & ~CS_PARENTDC);
+}
+
+
+
+
+
+VOID
+InitializeListBox(
+ IN HWND hwndListBox
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets up the list box. The disk state structures must
+ have been previously created.
+
+Arguments:
+
+ hwndListBox - handle of the list box that will hold the disk graphs
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ ULONG i;
+ DWORD ec;
+ ULONG count;
+
+ FDASSERT(DiskCount>0);
+
+ count = DiskCount + CdRomCount;
+
+ for (i=0; i<count; i++)
+ {
+ while (((ec = SendMessage(hwndListBox, LB_ADDSTRING, 0, 0)) == LB_ERR)
+ || (ec == LB_ERRSPACE))
+ {
+ ConfirmOutOfMemory();
+ }
+ }
+
+ TotalRedrawAndRepaint();
+}
diff --git a/private/utils/windisk/src/listbox.hxx b/private/utils/windisk/src/listbox.hxx
new file mode 100644
index 000000000..68ff96f1b
--- /dev/null
+++ b/private/utils/windisk/src/listbox.hxx
@@ -0,0 +1,85 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: listbox.hxx
+//
+// Contents: Declarations for handling the subclassed owner-draw listbox
+// used for the disks view display.
+//
+// History: 7-Jan-92 TedM Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __LISTBOX_HXX__
+#define __LISTBOX_HXX__
+
+//////////////////////////////////////////////////////////////////////////////
+
+BOOL
+LBIsDisk(
+ IN ULONG itemIndex
+ );
+
+BOOL
+LBIsCdRom(
+ IN ULONG itemIndex
+ );
+
+BOOL
+LBIndexToDiskNumber(
+ IN ULONG ItemIndex
+ );
+
+BOOL
+LBIndexToCdRomNumber(
+ IN ULONG ItemIndex
+ );
+
+ULONG
+LBDiskNumberToIndex(
+ IN ULONG DiskNumber
+ );
+
+ULONG
+LBCdRomNumberToIndex(
+ IN ULONG CdRomNumber
+ );
+
+LONG
+CalcBarTop(
+ DWORD Bar
+ );
+
+VOID
+ResetLBCursorRegion(
+ VOID
+ );
+
+VOID
+ToggleLBCursor(
+ IN HDC hdc
+ );
+
+VOID
+ForceLBRedraw(
+ VOID
+ );
+
+BOOL
+WMDrawItem(
+ IN PDRAWITEMSTRUCT pDrawItem
+ );
+
+VOID
+SubclassListBox(
+ IN HWND hwnd
+ );
+
+VOID
+InitializeListBox(
+ IN HWND hwndListBox
+ );
+
+#endif // __LISTBOX_HXX__
diff --git a/private/utils/windisk/src/log.cxx b/private/utils/windisk/src/log.cxx
new file mode 100644
index 000000000..f064b12e8
--- /dev/null
+++ b/private/utils/windisk/src/log.cxx
@@ -0,0 +1,1289 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: log.cxx
+//
+// Contents: Logging routines used only in debug builds
+//
+// History: 7-Jan-92 TedM Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#if DBG == 1
+
+#include <stdio.h>
+
+#include "drives.hxx"
+#include "engine.hxx"
+#include "windisk.hxx"
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+//
+// stuff internal to the fdisk engine that I want to look at:
+//
+
+extern ULONG CountOfDisks;
+extern PCHAR* DiskNames;
+extern DISKGEOM* DiskGeometryArray;
+extern PPARTITION* PrimaryPartitions;
+extern PPARTITION* LogicalVolumes;
+extern PBOOLEAN OffLine;
+extern BOOLEAN* ChangesRequested;
+extern BOOLEAN* ChangesCommitted;
+
+//
+// stuff internal to commit.cxx:
+//
+
+extern PDRIVE_LOCKLIST DriveLockListHead;
+extern PASSIGN_LIST AssignDriveLetterListHead;
+
+//
+// Locals
+//
+
+FILE* LogFile = NULL;
+int LoggingLevel = 1000;
+
+//////////////////////////////////////////////////////////////////////////////
+
+PCHAR
+GetFtType(
+ IN FT_TYPE ty
+ );
+
+PCHAR
+GetSysId(
+ IN UCHAR SysID
+ );
+
+PCHAR
+IsSysIdFT(
+ IN UCHAR SysID
+ );
+
+PCHAR
+GetRegionType(
+ IN REGION_TYPE RegionType
+ );
+
+VOID
+LOG_PERSISTENT(
+ IN PSTR pszPrefix,
+ IN PSTR pszWhitespace,
+ IN PPERSISTENT_REGION_DATA p
+ );
+
+VOID
+LOG_ONE_DISK(
+ PPARTITION p
+ );
+
+VOID
+LOG_REGION_DESCRIPTOR(
+ IN PREGION_DESCRIPTOR reg
+ );
+
+VOID
+LOG_ENGINE_DATA(
+ VOID
+ );
+
+VOID
+LOG_FTOBJECTSET(
+ VOID
+ );
+
+VOID
+LOG_DISKSTATE(
+ VOID
+ );
+
+VOID
+LOG_DRIVELETTERS(
+ VOID
+ );
+
+VOID
+LOG_WINDOWSTATE(
+ VOID
+ );
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+PCHAR
+GetFtType(
+ IN FT_TYPE ty
+ )
+{
+ switch (ty)
+ {
+ case Mirror: return "Mirror";
+ case Stripe: return "Stripe";
+ case StripeWithParity: return "Parity";
+ case VolumeSet: return "VolSet";
+ case NotAnFtMember: return "Not FT";
+ case WholeDisk: return "Whole ";
+ default: return "HUH? ";
+ }
+}
+
+
+PCHAR
+GetFtStatus(
+ IN FT_SET_STATUS Status
+ )
+{
+ switch (Status)
+ {
+ case FtSetHealthy: return "Healthy ";
+ case FtSetBroken: return "Broken ";
+ case FtSetRecoverable: return "Recoverable ";
+ case FtSetRecovered: return "Recovered ";
+ case FtSetNew: return "New ";
+ case FtSetNewNeedsInitialization: return "NewNeedsInit";
+ case FtSetExtended: return "Extended ";
+ case FtSetInitializing: return "Initializing";
+ case FtSetRegenerating: return "Regenerating";
+ default: return "HUH? ";
+ }
+}
+
+
+
+PCHAR
+GetSysId(
+ IN UCHAR SysID
+ )
+{
+ switch (SysID & (~PARTITION_NTFT))
+ {
+ case PARTITION_ENTRY_UNUSED: return "Unused";
+ case PARTITION_FAT_12: return "Fat-12";
+ case PARTITION_XENIX_1: return "Xenix1";
+ case PARTITION_XENIX_2: return "Xenix2";
+ case PARTITION_FAT_16: return "Fat-16";
+ case PARTITION_EXTENDED: return "Extend";
+ case PARTITION_HUGE: return "FAT ";
+ case PARTITION_IFS: return "IFS ";
+ case PARTITION_XINT13: return "xFAT ";
+ case PARTITION_XINT13_EXTENDED: return "xExtnd";
+ case PARTITION_PREP: return "PPC ";
+ case PARTITION_UNIX: return "Unix ";
+ default: return "Huh? ";
+ }
+}
+
+PCHAR
+IsSysIdFT(
+ IN UCHAR SysID
+ )
+{
+ if (SysID & PARTITION_NTFT)
+ {
+ return "yes";
+ }
+ else
+ {
+ return "no ";
+ }
+}
+
+PCHAR
+GetRegionType(
+ IN REGION_TYPE RegionType
+ )
+{
+ switch (RegionType)
+ {
+ case REGION_PRIMARY: return "Primary ";
+ case REGION_EXTENDED: return "Extended";
+ case REGION_LOGICAL: return "Logical ";
+ default: return "Huh? ";
+ }
+}
+
+
+
+VOID
+FdiskAssertFailedRoutine(
+ IN char *Expression,
+ IN char *FileName,
+ IN int LineNumber
+ )
+
+/*++
+
+Routine Description:
+
+ Routine that is called when an assertion fails in the debug version.
+ Throw up a list box giving appriopriate information and terminate
+ the program.
+
+Arguments:
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ char text[500];
+
+ wsprintfA(text,
+ "Line #%u in File '%hs'\n[%hs]\n\nClick OK to exit.",
+ LineNumber,
+ FileName,
+ Expression
+ );
+
+ MessageBoxA(NULL,text,"Assertion Failure",MB_TASKMODAL | MB_OK);
+ exit(1);
+}
+
+
+
+VOID
+InitLogging(
+ VOID
+ )
+{
+ LogFile = fopen("c:\\windisk.log","wt");
+ if (LogFile == NULL)
+ {
+ MessageBox(GetActiveWindow(),
+ TEXT("Can't open log file; logging turned off"),
+ TEXT("DEBUG"),
+ MB_SYSTEMMODAL|MB_OK);
+ LoggingLevel = -1;
+ }
+}
+
+
+
+VOID
+EndLogging(
+ VOID
+ )
+{
+ if (LogFile != NULL)
+ {
+ fclose(LogFile);
+ }
+}
+
+
+VOID
+FDLOG_WORK(
+ IN int Level,
+ IN PCHAR FormatString,
+ ...
+ )
+{
+ if (Level <= LoggingLevel)
+ {
+ va_list arglist;
+ va_start(arglist,FormatString);
+
+ if (vfprintf(LogFile,FormatString,arglist) < 0)
+ {
+ LoggingLevel = -1;
+ MessageBox(GetActiveWindow(),
+ TEXT("Error writing to log file; logging turned off"),
+ TEXT("DEBUG"),
+ MB_SYSTEMMODAL|MB_OK);
+ fclose(LogFile);
+ }
+ else
+ {
+ fflush(LogFile);
+ }
+
+ va_end(arglist);
+ }
+}
+
+
+VOID
+LOG_DISK_REGISTRY(
+ IN PCHAR RoutineName,
+ IN PDISK_REGISTRY DiskRegistry
+ )
+{
+ ULONG i;
+ PDISK_DESCRIPTION diskDesc;
+
+ FDLOG_WORK(2,"%hs: %u disks; registry info follows:\n",RoutineName,DiskRegistry->NumberOfDisks);
+
+ diskDesc = DiskRegistry->Disks;
+
+ for (i=0; i<DiskRegistry->NumberOfDisks; i++)
+ {
+ LOG_ONE_DISK_REGISTRY_DISK_ENTRY(NULL,diskDesc);
+ diskDesc = (PDISK_DESCRIPTION)&diskDesc->Partitions[diskDesc->NumberOfPartitions];
+ }
+}
+
+
+VOID
+LOG_ONE_DISK_REGISTRY_DISK_ENTRY(
+ IN PCHAR RoutineName OPTIONAL,
+ IN PDISK_DESCRIPTION DiskDescription
+ )
+{
+ USHORT j;
+ PDISK_PARTITION partDesc;
+ PDISK_DESCRIPTION diskDesc = DiskDescription;
+
+ if (ARGUMENT_PRESENT(RoutineName))
+ {
+ FDLOG_WORK(2,"%hs: disk registry entry follows:\n",RoutineName);
+ }
+
+ FDLOG_WORK(2," Disk signature : %08lx\n",diskDesc->Signature);
+ FDLOG_WORK(2," Partition count: %u\n",diskDesc->NumberOfPartitions);
+ if (diskDesc->NumberOfPartitions)
+ {
+ FDLOG_WORK(2," # Dr FtType FtGrp FtMem Start Length\n");
+ }
+
+ for (j=0; j<diskDesc->NumberOfPartitions; j++)
+ {
+ CHAR dr1,dr2;
+
+ partDesc = &diskDesc->Partitions[j];
+
+ if (partDesc->AssignDriveLetter)
+ {
+ if (partDesc->DriveLetter)
+ {
+ dr1 = partDesc->DriveLetter;
+ dr2 = ':';
+ }
+ else
+ {
+ dr1 = dr2 = ' ';
+ }
+ }
+ else
+ {
+ dr1 = 'n';
+ dr2 = 'o';
+ }
+
+ PCHAR pType = GetFtType(partDesc->FtType);
+
+ FDLOG_WORK( 2,
+ " %02u %c%c %hs %-5u %-5u %08lx:%08lx %08lx:%08lx\n",
+ partDesc->LogicalNumber,
+ dr1,dr2,
+ pType,
+ partDesc->FtGroup,
+ partDesc->FtMember,
+ partDesc->StartingOffset.HighPart,
+ partDesc->StartingOffset.LowPart,
+ partDesc->Length.HighPart,
+ partDesc->Length.LowPart
+ );
+ }
+}
+
+
+VOID
+LOG_DRIVE_LAYOUT(
+ IN PDRIVE_LAYOUT_INFORMATION DriveLayout
+ )
+{
+ ULONG i;
+
+ FDLOG_WORK(2," Disk signature : %08lx\n",DriveLayout->Signature);
+ FDLOG_WORK(2," Partition count: %u\n",DriveLayout->PartitionCount);
+
+ FDLOG_WORK(2,
+" ID FT? Active Recog Start Size Hidden\n");
+
+ for (i=0; i<DriveLayout->PartitionCount; i++)
+ {
+ PPARTITION_INFORMATION p = &(DriveLayout->PartitionEntry[i]);
+
+ PCHAR pType;
+ switch (p->PartitionType & (~VALID_NTFT))
+ {
+ case PARTITION_ENTRY_UNUSED:
+ pType = "Unused ";
+ break;
+
+ case PARTITION_FAT_12:
+ pType = "FAT 12 ";
+ break;
+
+ case PARTITION_XENIX_1:
+ pType = "Xenix 1 ";
+ break;
+
+ case PARTITION_XENIX_2:
+ pType = "Xenix 2 ";
+ break;
+
+ case PARTITION_FAT_16:
+ pType = "FAT 16 ";
+ break;
+
+ case PARTITION_EXTENDED:
+ pType = "Extended";
+ break;
+
+ case PARTITION_HUGE:
+ pType = "FAT Huge";
+ break;
+
+ case PARTITION_IFS:
+ pType = "IFS ";
+ break;
+
+ case PARTITION_XINT13:
+ pType = "xFAT ";
+ break;
+
+ case PARTITION_XINT13_EXTENDED:
+ pType = "xExtend ";
+ break;
+
+ case PARTITION_PREP:
+ pType = "PowerPC ";
+ break;
+
+ case PARTITION_UNIX:
+ pType = "Unix ";
+ break;
+
+ default:
+ pType = "Huh? ";
+ break;
+ }
+
+ FDLOG_WORK( 2,
+ " %02x(%hs) %hs %hs %hs %08lx:%08lx %08lx:%08lx %08lx\n",
+ p->PartitionType,
+ pType,
+ (p->PartitionType & VALID_NTFT) ? "yes" : "no ",
+ p->BootIndicator ? "yes" : "no ",
+ p->RecognizedPartition ? "yes" : "no ",
+ p->StartingOffset.HighPart,
+ p->StartingOffset.LowPart,
+ p->PartitionLength.HighPart,
+ p->PartitionLength.LowPart,
+ p->HiddenSectors
+ );
+ }
+
+}
+
+
+VOID
+LOG_PERSISTENT(
+ IN PSTR pszPrefix,
+ IN PSTR pszWhitespace,
+ IN PPERSISTENT_REGION_DATA p
+ )
+{
+ if (NULL != p)
+ {
+ FDLOG_WORK(2, "%hs", pszPrefix);
+ FDLOG_WORK(2, "FT obj: 0x%08lx; %lc:[%ls], Type: %ls, New Region? %hs\n",
+ p->FtObject,
+ p->DriveLetter,
+ p->VolumeLabel,
+ p->TypeName,
+ p->NewRegion ? "yes" : "no"
+ );
+
+#if defined( DBLSPACE_ENABLED )
+
+ PDBLSPACE_DESCRIPTOR pd = p->DblSpace;
+
+ if (NULL != pd)
+ {
+ FDLOG_WORK(2,
+ "%hs DblSpace: 0x%08lx\n", pszWhitespace, p->DblSpace);
+ FDLOG_WORK(2,
+ "%hs size MB mounted? chg state? new letter chg? volume\n",
+ pszWhitespace);
+
+ while (NULL != pd)
+ {
+ FDLOG_WORK(2,
+ "%hs %7lu %hs %hs %lc: %hs %lc: %ls\n",
+ pszWhitespace,
+ pd->AllocatedSize,
+ pd->Mounted ? "yes" : "no ",
+ pd->ChangeMountState ? "yes" : "no ",
+ pd->NewDriveLetter,
+ pd->ChangeDriveLetter ? "yes" : "no ",
+ pd->DriveLetter,
+ pd->FileName
+ );
+
+ pd = pd->Next;
+ }
+ }
+
+#endif // DBLSPACE_ENABLED
+
+ }
+}
+
+
+
+VOID
+LOG_ONE_DISK(
+ PPARTITION p
+ )
+{
+ LARGE_INTEGER tmp;
+
+ for (; NULL != p; p = p->Next)
+ {
+ tmp.QuadPart = p->Offset.QuadPart + p->Length.QuadPart;
+
+ FDLOG_WORK(2," %1d %08lx:%08lx %08lx:%08lx %08lx:%08lx %4d %5d 0x%08lx %hs %hs %hs %2d:%hs %hs\n",
+ p->Disk,
+ p->Offset.HighPart,
+ p->Offset.LowPart,
+ p->Length.HighPart,
+ p->Length.LowPart,
+ tmp.HighPart,
+ tmp.LowPart,
+ p->OriginalPartitionNumber,
+ p->PartitionNumber,
+ p->PersistentData,
+ p->Update ? "Yes " : "No ",
+ p->Active ? "Yes " : "No ",
+ p->Recognized ? "Yes " : "No ",
+ (UINT)p->SysID,
+ GetSysId(p->SysID),
+ IsSysIdFT(p->SysID)
+ );
+
+ LOG_PERSISTENT(
+ " == persistent: ",
+ " ",
+ (PPERSISTENT_REGION_DATA)(p->PersistentData)
+ );
+ }
+}
+
+VOID
+LOG_ENGINE_DATA(
+ VOID
+ )
+{
+ ULONG Disk;
+
+ FDLOG_WORK(2,"\nFdisk engine data\n");
+ FDLOG_WORK(2, "=================\n");
+
+ FDLOG_WORK(2,"# of disks: %d\n",CountOfDisks);
+ for (Disk=0; Disk<CountOfDisks; Disk++)
+ {
+ FDLOG_WORK(2," Disk %d = %hs\n",Disk,DiskNames[Disk]);
+ }
+
+ FDLOG_WORK(2,"\n"
+"Disk Cylinder Heads Sectors/Track Bytes/Sector Bytes/Cylinder Bytes/Track OffLine ChangesRequested ChangesCommitted\n"
+ );
+
+ for (Disk=0; Disk<CountOfDisks; Disk++)
+ {
+ FDLOG_WORK(2,"%-4d %08lx:%08lx %-5d %-13d %-12d %-14d %-11d %hs %2d:%hs %2d:%hs\n",
+ Disk,
+ DiskGeometryArray[Disk].Cylinders.HighPart,
+ DiskGeometryArray[Disk].Cylinders.LowPart,
+ DiskGeometryArray[Disk].Heads,
+ DiskGeometryArray[Disk].SectorsPerTrack,
+ DiskGeometryArray[Disk].BytesPerSector,
+ DiskGeometryArray[Disk].BytesPerCylinder,
+ DiskGeometryArray[Disk].BytesPerTrack,
+ OffLine[Disk] ? "yes " : "no ",
+ ChangesRequested[Disk],
+ ChangesRequested[Disk] ? "yes " : "no ",
+ ChangesCommitted[Disk],
+ ChangesCommitted[Disk] ? "yes " : "no "
+ );
+ }
+
+ FDLOG_WORK(2,"\n");
+
+ for (Disk=0; Disk<CountOfDisks; Disk++)
+ {
+ FDLOG_WORK(2,"Disk %d\n",Disk);
+ FDLOG_WORK(2," D Offset Length End Orig Part# Persistent Upd? Act? Rec? SysID FT?\n");
+
+ FDLOG_WORK(2," == Primary Partitions:\n");
+ LOG_ONE_DISK(PrimaryPartitions[Disk]);
+ FDLOG_WORK(2," == Logical Volumes:\n");
+ LOG_ONE_DISK(LogicalVolumes[Disk]);
+ }
+
+ FDLOG_WORK(2,"\n");
+}
+
+
+VOID
+LOG_REGION_DESCRIPTOR(
+ IN PREGION_DESCRIPTOR reg
+ )
+{
+ FDLOG_WORK(2," Persist D Part# Orig# SizeMB Type Act? Rec? SysID FT?\n");
+
+ FDLOG_WORK(2," 0x%08lx %1d %-5d %-5d %-6d %hs %hs %hs %2d:%hs %hs\n",
+ reg->PersistentData,
+ reg->Disk,
+ reg->PartitionNumber,
+ reg->OriginalPartitionNumber,
+ reg->SizeMB,
+ GetRegionType(reg->RegionType),
+ reg->Active ? "yes " : "no ",
+ reg->Recognized ? "yes " : "no ",
+ (UINT)reg->SysID,
+ GetSysId(reg->SysID),
+ IsSysIdFT(reg->SysID)
+ );
+
+ LOG_PERSISTENT(
+ " persistent: ",
+ " ",
+ (PPERSISTENT_REGION_DATA)(reg->PersistentData)
+ );
+
+ FDLOG_WORK(2,"\n");
+}
+
+
+VOID
+LOG_DISKSTATE(
+ VOID
+ )
+{
+ ULONG i;
+ ULONG Disk;
+ PDISKSTATE p;
+
+ FDLOG_WORK(2,"\nDisk state data, %d disks\n",DiskCount);
+ FDLOG_WORK(2, "=========================\n");
+
+ for (Disk=0; Disk<DiskCount; Disk++)
+ {
+ FDLOG_WORK(2,
+" Create: Exist:\n"
+" D SizeMB Any? Prim? Ext? Log? Any? Prim? Ext? Log? Signatur Cre? Offline? BarType\n"
+ );
+
+ PCHAR pBarType;
+
+ p = DiskArray[Disk];
+
+ if (NULL == p) // Disks hasn't been initialized yet for this disk!
+ {
+ FDLOG_WORK(2," %1d --- NO info!\n",Disk);
+ continue;
+ }
+
+ switch (p->BarType)
+ {
+ case BarProportional:
+ pBarType = "Propor";
+ break;
+
+ case BarEqual:
+ pBarType = "Equal";
+ break;
+
+ case BarAuto:
+ pBarType = "Auto";
+ break;
+
+ default:
+ pBarType = "HUH?";
+ break;
+
+ }
+
+ FDLOG_WORK(2," %1d %6d %hs %hs %hs %hs %hs %hs %hs %hs %08lx %hs %hs %hs\n",
+ p->Disk,
+ p->DiskSizeMB,
+ p->CreateAny ? "yes " : "no ",
+ p->CreatePrimary ? "yes " : "no ",
+ p->CreateExtended ? "yes " : "no ",
+ p->CreateLogical ? "yes " : "no ",
+ p->ExistAny ? "yes " : "no ",
+ p->ExistPrimary ? "yes " : "no ",
+ p->ExistExtended ? "yes " : "no ",
+ p->ExistLogical ? "yes " : "no ",
+ p->Signature,
+ p->SigWasCreated ? "yes " : "no ",
+ p->OffLine ? "yes " : "no ",
+ pBarType
+ );
+
+ FDLOG_WORK(2," == Region Descriptor Selected? left right\n");
+
+ for (i=0; i<p->RegionCount; i++)
+ {
+ FDLOG_WORK(2, " %-6d 0x%08lx %hs %08lx %08lx\n",
+ i,
+ &(p->RegionArray[i]),
+ p->Selected[i] ? "yes" : "no ",
+ p->LeftRight[i].Left,
+ p->LeftRight[i].Right
+ );
+
+ LOG_REGION_DESCRIPTOR(&(p->RegionArray[i]));
+ }
+ }
+}
+
+
+VOID
+LOG_FTOBJECTSET(
+ VOID
+ )
+{
+ PFT_OBJECT_SET p;
+ PFT_OBJECT q;
+
+ FDLOG_WORK(2,"\nFT objects data\n");
+ FDLOG_WORK(2, "===============\n");
+
+ FDLOG_WORK(2,
+" Address Type Ordinal &Mem0 Status Flag\n\n"
+ );
+
+ for (p = FtObjectList; NULL != p; p = p->Next)
+ {
+ PCHAR pSetStatus, pType, pFlag;
+
+ pType = GetFtType(p->Type);
+ pSetStatus = GetFtStatus(p->Status);
+
+ if (p->Flag)
+ {
+ pFlag = "TRUE ";
+ }
+ else
+ {
+ pFlag = "FALSE";
+ }
+
+ FDLOG_WORK(2," 0x%08lx %hs %-7d 0x%08lx %hs %hs\n",
+ p,
+ pType,
+ p->Ordinal,
+ p->Member0,
+ pSetStatus,
+ pFlag
+ );
+
+ FDLOG_WORK(2,
+" == Elements:\n"
+" Address Set Address Index State Region\n"
+ );
+
+ for (q = p->Members; NULL != q; q = q->Next)
+ {
+ PCHAR pMemberState;
+
+ switch (q->State)
+ {
+ case Healthy:
+ pMemberState = "Healthy ";
+ break;
+
+ case Orphaned:
+ pMemberState = "Orphaned ";
+ break;
+
+ case Initializing:
+ pMemberState = "Initializing";
+ break;
+
+ default:
+ pMemberState = "HUH? ";
+ break;
+
+ }
+
+ FDLOG_WORK(2," 0x%08x 0x%08x %-5d %hs 0x%08x\n",
+ q,
+ q->Set,
+ q->MemberIndex,
+ pMemberState,
+ q->Region
+ );
+ }
+
+ FDLOG_WORK(2,"\n");
+ }
+}
+
+
+
+VOID
+LOG_DRIVELETTERS(
+ VOID
+ )
+{
+ WCHAR DriveLetter;
+
+ FDLOG_WORK(2,"\nDrive letters\n");
+ FDLOG_WORK(2, "===============\n");
+
+ FDLOG_WORK(2, " used: ");
+
+ for (DriveLetter = L'C'; DriveLetter <= L'Z'; DriveLetter++)
+ {
+ if (!DriveLetterIsAvailable(DriveLetter))
+ {
+ FDLOG_WORK(2, "%lc ", DriveLetter);
+ }
+ }
+
+ FDLOG_WORK(2, "\n free: ");
+
+ for (DriveLetter = L'C'; DriveLetter <= L'Z'; DriveLetter++)
+ {
+ if (DriveLetterIsAvailable(DriveLetter))
+ {
+ FDLOG_WORK(2, "%lc ", DriveLetter);
+ }
+ }
+
+ FDLOG_WORK(2, "\n");
+
+ FDLOG_WORK(2, " Drive disk part region1(letter) region2(drive,part) Significant?\n");
+
+ for (DriveLetter = L'C'; DriveLetter <= L'Z'; DriveLetter++)
+ {
+ if (!DriveLetterIsAvailable(DriveLetter))
+ {
+ ULONG DiskNum = GetDiskNumberFromDriveLetter(DriveLetter);
+ ULONG PartNum = GetPartitionNumberFromDriveLetter(DriveLetter);
+ PREGION_DESCRIPTOR Region1 = NULL;
+ if (-1 != DiskNum && -1 != PartNum)
+ {
+ Region1 = RegionFromDiskAndPartitionNumbers(
+ DiskNum,
+ PartNum);
+ }
+ PREGION_DESCRIPTOR Region2 = RegionFromDriveLetter(DriveLetter);
+ BOOL f = SignificantDriveLetter(DriveLetter);
+
+ FDLOG_WORK(2,
+ " %lc: %-4d %-4d 0x%08lx 0x%08lx %hs\n",
+ DriveLetter,
+ DiskNum,
+ PartNum,
+ Region1,
+ Region2,
+ f ? "yes" : "no "
+ );
+ }
+ }
+}
+
+
+VOID
+LOG_CDROM(
+ VOID
+ )
+{
+ FDLOG_WORK(2,"\nCD-ROM data\n");
+ FDLOG_WORK(2, "===========\n");
+
+ if (0 == CdRomCount)
+ {
+ FDLOG_WORK(2, "None!\n");
+ }
+ else
+ {
+ FDLOG_WORK(2, "%d CD-ROMs\n\n", CdRomCount);
+
+ FDLOG_WORK(2, "Drive Letter Device # Device Name\n");
+
+ for (ULONG i = 0; i < CdRomCount; i++)
+ {
+ FDLOG_WORK(2, "%lc: %8ld %ls\n",
+ CdRomArray[i].DriveLetter,
+ CdRomArray[i].DeviceNumber,
+ CdRomArray[i].DeviceName
+ );
+ }
+ }
+}
+
+
+VOID
+LOG_LOCKLIST(
+ VOID
+ )
+{
+ FDLOG_WORK(2,"\nLOCKLIST data\n");
+ FDLOG_WORK(2, "=============\n");
+
+ PDRIVE_LOCKLIST p = DriveLockListHead;
+
+ if (NULL == p)
+ {
+ FDLOG_WORK(2, "None!\n");
+ }
+ else
+ {
+ FDLOG_WORK(2,
+ "Handle D# P# LockDisk UnlockDisk Drive Remove? FailOK? Locked?\n");
+
+ while (NULL != p)
+ {
+ FDLOG_WORK(2,
+ "0x%08lx %3d %3d %8d %10d %lc: %hs %hs %hs\n",
+ p->LockHandle,
+ p->DiskNumber,
+ p->PartitionNumber,
+ p->LockOnDiskNumber,
+ p->UnlockOnDiskNumber,
+ p->DriveLetter,
+ p->RemoveOnUnlock ? "yes" : "no ",
+ p->FailOk ? "yes" : "no ",
+ p->CurrentlyLocked ? "yes" : "no "
+ );
+
+ p = p->Next;
+ }
+ }
+}
+
+
+VOID
+LOG_ASSIGNLIST(
+ VOID
+ )
+{
+ FDLOG_WORK(2,"\nASSIGNLIST data\n");
+ FDLOG_WORK(2, "===============\n");
+
+ PASSIGN_LIST p = AssignDriveLetterListHead;
+
+ if (NULL == p)
+ {
+ FDLOG_WORK(2, "None!\n");
+ }
+ else
+ {
+ FDLOG_WORK(2, " D# Drive\n");
+
+ while (NULL != p)
+ {
+ FDLOG_WORK(2, "%3d %lc:\n",
+ p->DiskNumber,
+ p->DriveLetter
+ );
+
+ p = p->Next;
+ }
+ }
+}
+
+
+
+
+
+VOID
+LOG_WINDOWSTATE(
+ VOID
+ )
+{
+ FDLOG_WORK(2,"\nWindow state data\n");
+ FDLOG_WORK(2, "=================\n");
+
+ FDLOG_WORK(2,
+"\n"
+"g_WhichView = "
+ );
+
+ if (VIEW_VOLUMES == g_WhichView)
+ {
+ FDLOG_WORK(2, "Volumes\n");
+ }
+ else
+ if (VIEW_DISKS == g_WhichView)
+ {
+ FDLOG_WORK(2, "Disks\n");
+ }
+ else
+ {
+ FDLOG_WORK(2, "HUH????\n");
+ }
+
+ FDLOG_WORK(2,
+"\n"
+"GraphWidth = %d, GraphHeight = %d\n"
+"BarTopYOffset = %d, BarBottomYOffset = %d\n"
+"dxDriveLetterStatusArea = %d\n"
+"dxBarTextMargin = %d, dyBarTextLine = %d\n"
+"BarLeftX = %d, BarWidth = %d\n"
+"xSmallDisk = %d, ySmallDisk = %d, dxSmallDisk = %d, dySmallDisk = %d\n"
+"g_wLegendItem = %d, g_dyLegendSep = %d\n"
+"g_dyBorder = %d, g_dyToolbar = %d, g_dyLegend = %d, g_dyStatus = %d\n"
+"g_Toolbar? %hs, g_StatusBar? %hs, g_Legend? %hs\n"
+,
+GraphWidth, GraphHeight,
+BarTopYOffset, BarBottomYOffset,
+dxDriveLetterStatusArea,
+dxBarTextMargin, dyBarTextLine,
+BarLeftX, BarWidth,
+xSmallDisk, ySmallDisk, dxSmallDisk, dySmallDisk,
+g_wLegendItem, g_dyLegendSep,
+g_dyBorder, g_dyToolbar, g_dyLegend, g_dyStatus,
+g_Toolbar ? "yes" : "no", g_StatusBar ? "yes" : "no", g_Legend ? "yes" : "no"
+ );
+
+ FDLOG_WORK(2,
+"\n"
+"RegistryChanged? %hs\n"
+,
+RegistryChanged ? "yes" : "no"
+ );
+
+ FDLOG_WORK(2,
+"\n"
+"SelectionCount = %d\n"
+"SelectedFreeSpaces = %d\n"
+"SelectedNonFtPartitions = %d\n"
+"FreeSpaceIndex = %d\n"
+"FtSelectionType = %d\n"
+"FtSetSelected? %hs\n"
+"NonFtItemSelected? %hs\n"
+"MultipleItemsSelected? %hs\n"
+"VolumeSetAndFreeSpaceSelected? %hs\n"
+"PartitionAndFreeSpaceSelected? %hs\n"
+"PossibleRecover? %hs\n"
+"DiskSelected? %hs\n"
+"PartitionSelected? %hs\n"
+"LBCursorListBoxItem = %d\n"
+"LBCursorRegion = %d\n"
+,
+SelectionCount,
+SelectedFreeSpaces,
+SelectedNonFtPartitions,
+FreeSpaceIndex,
+(INT)FtSelectionType,
+FtSetSelected ? "yes" : "no",
+NonFtItemSelected ? "yes" : "no",
+MultipleItemsSelected ? "yes" : "no",
+VolumeSetAndFreeSpaceSelected ? "yes" : "no",
+PartitionAndFreeSpaceSelected ? "yes" : "no",
+PossibleRecover ? "yes" : "no",
+DiskSelected ? "yes" : "no",
+PartitionSelected ? "yes" : "no",
+LBCursorListBoxItem,
+LBCursorRegion
+ );
+
+ FDLOG_WORK(2, "\n");
+
+ for (DWORD i = 0; i < SelectionCount; i++)
+ {
+ FDLOG_WORK(2,
+ "SelectedRG[%d] = %d\n",
+ i,
+ SelectedRG[i]
+ );
+ }
+
+ FDLOG_WORK(2, "\n");
+
+ for (ULONG j = 0; j < DiskCount; j++)
+ {
+ FDLOG_WORK(2,
+ "DiskSeenCountArray[%d] = %d\n",
+ j,
+ DiskSeenCountArray[j]
+ );
+ }
+
+ FDLOG_WORK(2,
+"\n"
+"ProfileWindowX = %d\n"
+"ProfileWindowY = %d\n"
+"ProfileWindowW = %d\n"
+"ProfileWindowH = %d\n"
+"ProfileIsMaximized? %hs\n"
+"ProfileIsIconic? %hs\n"
+,
+ProfileWindowX,
+ProfileWindowY,
+ProfileWindowW,
+ProfileWindowH,
+ProfileIsMaximized ? "yes" : "no",
+ProfileIsIconic ? "yes" : "no"
+ );
+}
+
+
+VOID
+LOG_ALL(
+ VOID
+ )
+{
+ daDebugOut((DEB_ITRACE,"Logging...\n"));
+
+ FDLOG_WORK(2,"\n\nLogging...........................................\n");
+ FDLOG_WORK(2, "==================================================\n\n");
+
+ LOG_ENGINE_DATA();
+ LOG_FTOBJECTSET();
+ LOG_DISKSTATE();
+ LOG_DRIVELETTERS();
+ LOG_CDROM();
+ LOG_LOCKLIST();
+ LOG_ASSIGNLIST();
+ LOG_WINDOWSTATE();
+}
+
+
+#ifdef WINDISK_EXTENSIONS
+
+//+---------------------------------------------------------------------------
+//
+// Function: PrintVolumeClaims
+//
+// Synopsis: Print the extension claims for a drive letter to the debugger
+// (if DEB_TRACE is set in daInfoLevel)
+//
+// Arguments: [DriveLetter] -- the drive letter
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+PrintVolumeClaims(
+ IN WCHAR DriveLetter
+ )
+{
+ unsigned i = (unsigned)DriveLetterToIndex(DriveLetter);
+
+ // if drive DriveLetter is used...
+ if (NULL != VolumeInfo[i].DiskState)
+ {
+ PVOL_CLAIM_LIST volClaims = VolumeInfo[i].VolClaims;
+
+ if (NULL != volClaims)
+ {
+ daDebugOut((DEB_TRACE,
+ "Volume extensions: Drive %lc, Disk %d, Region %d: ",
+ DriveLetter,
+ VolumeInfo[i].DiskState->Disk,
+ VolumeInfo[i].RegionIndex
+ ));
+
+ while (NULL != volClaims)
+ {
+ daDebugOut((DEB_TRACE | DEB_NOCOMPNAME,
+ "%ls, ",
+ volClaims->pClaimer->pInfo->pwszShortName));
+
+ volClaims = volClaims->pNext;
+ }
+
+ daDebugOut((DEB_TRACE | DEB_NOCOMPNAME, "\n"));
+ }
+ }
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: PrintDiskClaims
+//
+// Synopsis: Print the extension claims for a disk to the debugger
+// (if DEB_TRACE is set in daInfoLevel)
+//
+// Arguments: [DiskNum] --
+//
+// Returns: nothing
+//
+// History: 7-Oct-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+PrintDiskClaims(
+ IN ULONG DiskNum
+ )
+{
+ PHARDDISK_CLAIM_LIST pClaims = DiskArray[DiskNum]->pClaims;
+
+ if (NULL != pClaims)
+ {
+ daDebugOut((DEB_TRACE, "Disk extensions, Disk %d: ", DiskNum));
+
+ while (NULL != pClaims)
+ {
+ daDebugOut((DEB_TRACE | DEB_NOCOMPNAME,
+ "%ls, ",
+ pClaims->pClaimer->pInfo->pwszShortName));
+
+ pClaims = pClaims->pNext;
+ }
+ daDebugOut((DEB_TRACE | DEB_NOCOMPNAME, "\n"));
+ }
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: PrintClaims
+//
+// Synopsis: Dump all claims
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+PrintClaims(
+ VOID
+ )
+{
+ for (WCHAR DriveLetter = L'C'; DriveLetter <= L'Z'; DriveLetter++)
+ {
+ PrintVolumeClaims(DriveLetter);
+ }
+
+ for (ULONG DiskNum = 0; DiskNum<DiskCount; DiskNum++)
+ {
+ PrintDiskClaims(DiskNum);
+ }
+}
+
+#endif // WINDISK_EXTENSIONS
+
+#endif // DBG == 1
diff --git a/private/utils/windisk/src/makefile b/private/utils/windisk/src/makefile
new file mode 100644
index 000000000..14f79b701
--- /dev/null
+++ b/private/utils/windisk/src/makefile
@@ -0,0 +1 @@
+!include $(NTMAKEENV)\makefile.def
diff --git a/private/utils/windisk/src/makefile.inc b/private/utils/windisk/src/makefile.inc
new file mode 100644
index 000000000..4686e9ef8
--- /dev/null
+++ b/private/utils/windisk/src/makefile.inc
@@ -0,0 +1,24 @@
+obj\$(TARGET_DIRECTORY)\windisk.res: \
+ $(BASEDIR)\public\sdk\inc\windows.h \
+ $(BASEDIR)\public\sdk\inc\common.ver \
+ $(BASEDIR)\public\sdk\inc\ntverp.h \
+ resids.h \
+ dialogs.h \
+ dialogs.dlg \
+ dblspace.h \
+ dblspace.dlg \
+ ftreg.h \
+ ftreg.dlg \
+ dskmgr.ico \
+ trffc14.ico \
+ shard.ico \
+ scdrom.ico \
+ tool16.bmp \
+ xtra16.bmp \
+ smdisk.bmp \
+ smcdrom.bmp \
+ rmdisk.bmp \
+ cdr.bmp \
+ hard.bmp \
+ obj\messages.h \
+ obj\messages.rc
diff --git a/private/utils/windisk/src/mem.cxx b/private/utils/windisk/src/mem.cxx
new file mode 100644
index 000000000..fa1dff75e
--- /dev/null
+++ b/private/utils/windisk/src/mem.cxx
@@ -0,0 +1,92 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: mem.cxx
+//
+// Contents: Memory management routines. These are used by the fdisk
+// engine fdengine.c as well as the rest of Disk Administrator.
+// Since fdengine.c is a C file, these must by C entrypoints,
+// even though they must compile in a C++ file so they can access
+// the CommonDialog() API.
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+//////////////////////////////////////////////////////////////////////////////
+
+PVOID
+Malloc(
+ IN ULONG Size
+ )
+{
+ PVOID p;
+
+ while (NULL == (p = malloc(Size)))
+ {
+ ConfirmOutOfMemory();
+ }
+ return p;
+}
+
+
+PVOID
+Realloc(
+ IN PVOID Block,
+ IN ULONG NewSize
+ )
+{
+ PVOID p;
+
+ if (0 != NewSize)
+ {
+ while (NULL == (p = realloc(Block, NewSize)))
+ {
+ ConfirmOutOfMemory();
+ }
+ }
+ else
+ {
+ //
+ // realloc with a size of 0 is the same as free,
+ // so special case that here.
+ //
+
+ free(Block);
+ while (NULL == (p = malloc(0)))
+ {
+ ConfirmOutOfMemory();
+ }
+ }
+ return p;
+}
+
+
+VOID
+Free(
+ IN PVOID Block
+ )
+{
+ free(Block);
+}
+
+
+
+VOID
+ConfirmOutOfMemory(
+ VOID
+ )
+{
+ if (IDRETRY != CommonDialogNoArglist(
+ MSG_OUT_OF_MEMORY,
+ NULL,
+ MB_ICONHAND | MB_RETRYCANCEL | MB_SYSTEMMODAL))
+ {
+ exit(1);
+ }
+}
diff --git a/private/utils/windisk/src/mem.hxx b/private/utils/windisk/src/mem.hxx
new file mode 100644
index 000000000..b3d37878b
--- /dev/null
+++ b/private/utils/windisk/src/mem.hxx
@@ -0,0 +1,38 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: mem.hxx
+//
+// Contents: C++ definitions for memory functions in mem.cxx.
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __MEM_HXX__
+#define __MEM_HXX__
+
+PVOID
+Malloc(
+ IN ULONG Size
+ );
+
+PVOID
+Realloc(
+ IN PVOID Block,
+ IN ULONG NewSize
+ );
+
+VOID
+Free(
+ IN PVOID Block
+ );
+
+VOID
+ConfirmOutOfMemory(
+ VOID
+ );
+
+#endif // __MEM_HXX__
diff --git a/private/utils/windisk/src/menudict.cxx b/private/utils/windisk/src/menudict.cxx
new file mode 100644
index 000000000..98eddd002
--- /dev/null
+++ b/private/utils/windisk/src/menudict.cxx
@@ -0,0 +1,201 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: menudict.cxx
+//
+// Contents: Dictionary of extension menu IDs
+//
+// History: 2-Jul-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#ifdef WINDISK_EXTENSIONS
+
+#include "resids.h"
+#include "menudict.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+CMenuItems
+MenuItems(
+ IDM_EXTENSION_START,
+ IDM_EXTENSION_END
+ );
+
+CMenuItems
+ContextMenuItems(
+ IDM_CONTEXT_EXTENSION_START,
+ IDM_CONTEXT_EXTENSION_END
+ );
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+//+---------------------------------------------------------------------------
+//
+// Member: CMenuItems::AllocateId
+//
+// Synopsis: Given an extension menu item, assign it an unused resource
+// ID, and return it.
+//
+// Arguments: [pItem] -- the extension menu item
+//
+// Returns: The assigned resource ID, or -1 on error (out of memory or no
+// IDs available)
+//
+// Derivation: none
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+INT
+CMenuItems::AllocateId(
+ IN MenuItemType* pItem
+ )
+{
+ if (_NextMenuId > _wIdEnd)
+ {
+ daDebugOut((DEB_IERROR,
+ "No extension IDs left! (next = %d, start = %d, end = %d\n",
+ _NextMenuId,
+ _wIdStart,
+ _wIdEnd
+ ));
+
+ return -1; // no IDs left!
+ }
+
+ MenuIDDictType* pElem = (MenuIDDictType*)Malloc(sizeof(MenuIDDictType));
+ if (NULL == pElem)
+ {
+ daDebugOut((DEB_ERROR, "Malloc failed!\n"));
+
+ return -1; // out of memory
+ }
+
+ pElem->pNext = _pHead;
+ pElem->Id = _NextMenuId;
+ pElem->pItem = pItem;
+
+ _pHead = pElem; // the new one is first
+
+ return _NextMenuId++;
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Member: CMenuItems::LookupMenuItem
+//
+// Synopsis: Given a resource ID, return the associated extension menu item,
+// or NULL if the ID isn't associated with an extension menu item
+//
+// Arguments: [Id] -- a resource ID
+//
+// Returns: The extension menu item, or NULL if no item has the ID
+//
+// Derivation: none
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+MenuItemType*
+CMenuItems::LookupMenuItem(
+ IN UINT Id
+ )
+{
+ MenuIDDictType* pElem = _pHead;
+
+ while (NULL != pElem)
+ {
+ if (Id == pElem->Id)
+ {
+ return pElem->pItem;
+ }
+ pElem = pElem->pNext;
+ }
+ return NULL;
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Member: CMenuItems::LookupMenuId
+//
+// Synopsis: Given a menu item, return the associated menu ID, if
+// any, or -1
+//
+// Arguments: [pItem] -- the extension menu item
+//
+// Returns: The assigned resource ID, or -1 on error
+//
+// Derivation: none
+//
+// History: 26-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+INT
+CMenuItems::LookupMenuId(
+ IN MenuItemType* pItem
+ )
+{
+ MenuIDDictType* pElem = _pHead;
+
+ while (NULL != pElem)
+ {
+ if (pItem == pElem->pItem)
+ {
+ return pElem->Id;
+ }
+ pElem = pElem->pNext;
+ }
+ return -1;
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Member: CMenuItems::DeAllocateMenuIds
+//
+// Synopsis: Deallocate all the menu IDs
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+CMenuItems::DeAllocateMenuIds(
+ VOID
+ )
+{
+ MenuIDDictType* pTmp;
+ MenuIDDictType* pElem = _pHead;
+
+ while (NULL != pElem)
+ {
+ pTmp = pElem->pNext;
+ Free(pElem);
+ pElem = pTmp;
+ }
+ _pHead = NULL;
+
+ _NextMenuId = _wIdStart;
+}
+
+#endif // WINDISK_EXTENSIONS
diff --git a/private/utils/windisk/src/menudict.hxx b/private/utils/windisk/src/menudict.hxx
new file mode 100644
index 000000000..77f489116
--- /dev/null
+++ b/private/utils/windisk/src/menudict.hxx
@@ -0,0 +1,113 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: menudict.hxx
+//
+// Contents: Dictionary of extension menu IDs
+//
+// History: 2-Jul-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __MENUDICT_HXX__
+#define __MENUDICT_HXX__
+
+#ifdef WINDISK_EXTENSIONS
+
+//
+// The dictionary structure is a linked list:
+//
+
+struct MenuIDDictType
+{
+ MenuIDDictType* pNext;
+ UINT Id;
+ MenuItemType* pItem;
+};
+
+
+//+---------------------------------------------------------------------------
+//
+// Class: CMenuItems
+//
+// Purpose: A dictionary of extension menu IDs
+//
+// Interface: AllocateId -- given an extension menu item,
+// return a Windows menu ID
+// LookupMenuItem -- given a Windows menu ID, lookup the
+// extension menu item
+// LookupMenuId -- given an extension item, find the
+// Windows menu ID already associated with it
+// extension menu item
+// DeAllocateMenuIds -- Deallocate all space associated
+// with the mapping
+//
+// History: 2-Jul-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+class CMenuItems
+{
+public:
+
+ CMenuItems(
+ IN UINT wIdStart,
+ IN UINT wIdEnd
+ )
+ :
+ _pHead(NULL),
+ _wIdStart(wIdStart),
+ _wIdEnd(wIdEnd),
+ _NextMenuId(wIdStart)
+ {
+ }
+
+ ~CMenuItems()
+ {
+ DeAllocateMenuIds();
+ }
+
+ INT
+ AllocateId(
+ IN MenuItemType* pItem
+ );
+
+ MenuItemType*
+ LookupMenuItem(
+ IN UINT Id
+ );
+
+ INT
+ LookupMenuId(
+ IN MenuItemType* pItem
+ );
+
+ VOID
+ DeAllocateMenuIds(
+ VOID
+ );
+
+ BOOL
+ IsExtensionId(
+ IN UINT Id
+ )
+ {
+ return (_wIdStart <= Id) && (Id < _NextMenuId);
+ }
+
+private:
+
+ MenuIDDictType* _pHead;
+ UINT _wIdStart;
+ UINT _wIdEnd;
+ UINT _NextMenuId;
+};
+
+extern CMenuItems MenuItems;
+extern CMenuItems ContextMenuItems;
+
+#endif // WINDISK_EXTENSIONS
+
+#endif // __MENUDICT_HXX__
diff --git a/private/utils/windisk/src/messages.mc b/private/utils/windisk/src/messages.mc
new file mode 100644
index 000000000..4900fcb72
--- /dev/null
+++ b/private/utils/windisk/src/messages.mc
@@ -0,0 +1,617 @@
+;/*++
+;
+;Copyright (c) 1991 Microsoft Corporation
+;
+;Module Name:
+;
+; messages.h
+;
+;Abstract:
+;
+; This file contains the message definitions for Disk Administrator
+;
+;Author:
+;
+; Ted Miller (tedm) 5-Dec-1991
+;
+;Revision History:
+;
+;Notes:
+;
+; This file is generated from messages.mc
+;
+;--*/
+;
+;#ifndef ___MESSAGES_H__
+;#define ___MESSAGES_H__
+;
+;
+
+MessageID=9000 SymbolicName=MSG_FIRST_FDISK_MSG
+Language=English
+.
+
+MessageID=9001 SymbolicName=MSG_CANT_INITIALIZE
+Language=English
+Disk Administrator was unable to initialize.
+Click OK to exit.
+.
+
+MessageID=9002 SymbolicName=MSG_NO_DISKS
+Language=English
+Disk Administrator has determined that there are no fixed disks attached to the system, or all such disks are off-line. Click OK to exit.
+.
+
+MessageID=9003 SymbolicName=MSG_ACCESS_DENIED
+Language=English
+Access is denied. You must be logged on with Administrative privilege to run Disk Administrator.
+.
+
+MessageID=9004 SymbolicName=MSG_CONFIRM_DELETE
+Language=English
+All data in the partition or logical drive will be lost!
+
+Are you sure you want to delete the chosen partition or logical drive?
+.
+
+MessageID=9005 SymbolicName=MSG_CREATE_NOT_COMPAT
+Language=English
+This operation will result in a disk whose partition scheme may not be compatible with MS-DOS. Some partitions may not be accessible if the disk is used with MS-DOS in the future.
+
+Do you want to continue and create the partition anyway?
+.
+
+MessageID=9006 SymbolicName=MSG_INVALID_SIZE
+Language=English
+Invalid size.
+.
+
+MessageID=9007 SymbolicName=MSG_ALREADY_RUNNING
+Language=English
+Disk Administrator is already running.
+.
+
+MessageID=9008 SymbolicName=MSG_CONFIRM_EXIT
+Language=English
+Changes have been made to your disk configuration.
+
+Do you want to save the changes?
+.
+
+MessageID=9009 SymbolicName=MSG_OUT_OF_MEMORY
+Language=English
+Disk Administrator has run out of memory. Select Cancel to exit Disk Administrator, or try closing other applications to free memory and then select Retry. If you exit, all changes will be lost.
+.
+
+MessageID=9010 SymbolicName=MSG_OK_COMMIT
+Language=English
+Disks were updated successfully.
+
+It is recommended that you update the emergency repair configuration information and create a new Emergency Repair Disk. You can do this with the system utility RDISK.EXE.
+.
+
+MessageID=9011 SymbolicName=MSG_CANT_DELETE_WINNT
+Language=English
+Disk Administrator cannot delete the partition containing Windows NT system files.
+.
+
+MessageID=9012 SymbolicName=MSG_HELP_ERROR
+Language=English
+Could not invoke help application.
+.
+
+MessageID=9013 SymbolicName=MSG_NO_AVAIL_LETTER
+Language=English
+All available drive letters are already assigned.
+
+You will not be able to access the %1 from Windows NT unless you rearrange drive letter usage.
+
+Do you want to continue and create the %1 anyway?
+.
+
+MessageID=9014 SymbolicName=MSG_BAD_CONFIG_SET
+Language=English
+An error occurred while updating disk configuration.
+
+Drive letter and fault tolerance information may be lost and/or some partitions may be inaccessible.
+.
+
+MessageID=9015 SymbolicName=MSG_CONFIG_MISSING_DISK
+Language=English
+Disk Administrator has determined that one or more disks have been removed from your computer since Disk Administrator was last run, or that one or more disks are off-line.
+
+Configuration information about the missing disk(s) will be retained.
+.
+
+MessageID=9016 SymbolicName=MSG_CONFIG_EXTRA_DISK
+Language=English
+Disk Administrator has determined that this is the first time Disk Administrator has been run, or that one or more disks have been added to your computer since Disk Administrator was last run.
+
+System configuration will now be updated.
+.
+
+MessageID=9017 SymbolicName=MSG_CONFIG_DISK_CHANGED
+Language=English
+Disk Administrator has determined that the configuration of one of more disks has been altered since Disk Administrator was last run.
+
+System configuration will be automatically updated to reflect these changes when you next opt to save changes when exiting Disk Administrator.
+.
+
+MessageID=9018 SymbolicName=MSG_ALL_DRIVE_LETTERS_USED
+Language=English
+All drive letters are already assigned.
+.
+
+MessageID=9019 SymbolicName=MSG_PART_TABLE_FULL
+Language=English
+No more primary partitions can be created on the disk. A disk cannot hold more than four partitions (including the extended partition but not including logical drives).
+.
+
+MessageID=9020 SymbolicName=MSG_EXTENDED_ALREADY_EXISTS
+Language=English
+An extended partition already exists on the disk.
+.
+
+MessageID=9021 SymbolicName=MSG_NO_OTHER_NTS
+Language=English
+No other Windows NT installations were found.
+.
+
+MessageID=9022 SymbolicName=MSG_CONFIRM_MIGRATE_CONFIG
+Language=English
+Warning: This operation will overwrite your disk configuration information with the configuration from a different installation of Windows NT. Currently defined drive letters, volume sets, stripe sets, parity stripes, and mirrors may be lost depending on the disk configuration associated with the Windows NT installation you select.
+
+No partitions will be created or deleted by this operation, but any changes you have made during this session of Disk Administrator will be lost.
+
+Do you want to search for other installations of Windows NT?
+.
+
+MessageID=9023 SymbolicName=MSG_CONFIRM_RESTORE_CONFIG
+Language=English
+Warning: This operation will overwrite your disk configuration information with a previously saved configuration. Currently defined drive letters, volume sets, stripe sets, parity stripes, and mirrors may be lost depending on the previously saved disk configuration.
+
+No partitions will be created or deleted by this operation, but any changes you have made during this session of Disk Administrator will be lost.
+
+Do you want to continue with the restoration?
+.
+
+MessageID=9024 SymbolicName=MSG_INSERT_REGSAVEDISK
+Language=English
+Please insert a disk (which may be the Emergency Repair Disk), onto which you have previously saved disk configuration information, into drive A:.
+
+Press OK when the disk is in the drive.
+.
+
+MessageID=9025 SymbolicName=MSG_INSERT_REGSAVEDISK2
+Language=English
+This operation will save configuration information about currently defined drive letters, volume sets, stripe sets, stripe sets with parity, and mirror sets. The saved configuration information will be placed on a floppy disk.
+
+Please insert a formatted disk into drive A:. Press OK when the disk is in the drive.
+.
+
+MessageID=9026 SymbolicName=MSG_CONFIG_SAVED_OK
+Language=English
+Disk configuration information was saved successfully.
+.
+
+MessageID=9027 SymbolicName=MSG_ABSOLUTELY_SURE
+Language=English
+Current disk configuration information will be overwritten! Are you absolutely sure you want to continue?
+.
+
+MessageID=9028 SymbolicName=MSG_NO_SIGNATURE
+Language=English
+No signature found on %1. Writing a signature is a safe operation and will not affect your ability to access this disk from other operating systems, such as DOS.
+
+If you choose not to write a signature, the disk will be marked OFF-LINE and be inaccessable to the Windows NT Disk Administrator program.
+
+Do you want to write a signature on %1 so that Disk Administrator can access the drive?
+.
+
+MessageID=9029 SymbolicName=MSG_SCHEDULE_REBOOT
+Language=English
+The drive is in use by other programs. The drive letter cannot be changed without either shutting down those programs or restarting the computer.
+
+Do you wish to perform this change and restart the computer upon exiting Disk Administrator?
+.
+
+MessageId=9030 SymbolicName=MSG_REQUIRE_REBOOT
+Language=English
+The changes requested will require you to restart your computer. Do you wish to continue with the changes and restart the computer?
+.
+
+MessageId=9031 SymbolicName=MSG_NOFMIFS
+Language=English
+Disk Administrator could not locate or use the system file FMIFS.DLL, which is necessary to perform this action.
+.
+
+MessageID=9032 SymbolicName=MSG_MUST_COMMIT_BREAK
+Language=English
+You have selected a partition that is still a member of a mirror set. Breaking the mirror set relationship does not actually happen until you quit Disk Administrator or choose the Commit Changes Now command.
+
+Please do one or the other of these actions and then delete the partition.
+.
+
+MessageID=9034 SymbolicName=MSG_TOO_BIG_FOR_FAT
+Language=English
+This volume cannot be formatted to the FAT file system. FAT can only support volumes up to 4GB in size.
+.
+
+MessageID=9035 SymbolicName=MSG_NO_DISK_INFO
+Language=English
+The configuration selected does not contain any disk configuration information. No change will be made to the current configuration.
+.
+
+MessageID=9036 SymbolicName=MSG_DISK_INFO_BUSY
+Language=English
+The configuration selected is currently open by another application. Close the other accesses to this file and try again.
+.
+
+;//////////////// 9037 -> 9050: unused
+
+MessageId=9051 SymbolicName=MSG_CONFIRM_SHUTDOWN_FOR_MIRROR
+Language=English
+The mirror set cannot be locked. To break this mirror relationship the system must be restarted. This restart of the system will occur on exiting Disk Administrator.
+
+Do you wish to continue with this operation?
+.
+
+MessageId=9052 SymbolicName=MSG_EXTEND_VOLSET_MUST_BE_NTFS
+Language=English
+The volume set is not formatted to NTFS; only NTFS volume sets can be extended.
+.
+
+MessageId=9053 SymbolicName=MSG_CONFIRM_BRKANDDEL_MIRROR
+Language=English
+All data in the mirror will be lost!
+
+Are you sure you want to break the selected mirror and delete its component partitions?
+.
+
+MessageID=9054 SymbolicName=MSG_CANT_EXTEND_WINNT
+Language=English
+Disk Administrator cannot extend the partition containing Windows NT system files.
+.
+
+MessageID=9055 SymbolicName=MSG_CONFIRM_PROTECT_SYSTEM
+Language=English
+Are you sure you want to restrict access to the System Partition to System Administrators?
+
+Performing this operation will require a restart of the system.
+.
+
+MessageID=9056 SymbolicName=MSG_CONFIRM_UNPROTECT_SYSTEM
+Language=English
+Are you sure you want to allow all users access to the System Partition?
+
+Performing this operation will require a restart of the system.
+.
+
+MessageID=9057 SymbolicName=MSG_CANT_PROTECT_SYSTEM
+Language=English
+Disk Administrator cannot mark the System Partition secure.
+.
+
+MessageID=9058 SymbolicName=MSG_CANT_UNPROTECT_SYSTEM
+Language=English
+Disk Administrator cannot mark the System Partition as non-secure.
+.
+
+MessageID=9059 SymbolicName=MSG_NO_REMOVABLE_IN_STRIPE
+Language=English
+Stripe sets cannot include partitions on removable media.
+.
+
+MessageID=9060 SymbolicName=MSG_NO_REMOVABLE_IN_VOLUMESET
+Language=English
+Volume sets cannot include partitions on removable media.
+.
+
+MessageID=9061 SymbolicName=MSG_NO_REMOVABLE_IN_MIRROR
+Language=English
+Mirror pairs cannot include partitions on removable media.
+.
+
+MessageID=9062 SymbolicName=MSG_CANT_ASSIGN_LETTER_TO_REMOVABLE
+Language=English
+Disk Administrator cannot assign drive letters to partitions on removable media.
+.
+
+MessageID=9063 SymbolicName=MSG_NO_EXTENDED_ON_REMOVABLE
+Language=English
+Disk Administrator cannot create extended partitions on removable media.
+.
+
+MessageID=9064 SymbolicName=MSG_ONLY_ONE_PARTITION_ON_REMOVABLE
+Language=English
+Disk Administrator can only create one partition on a removable disk.
+.
+
+MessageID=9065 SymbolicName=MSG_REMOVABLE_PARTITION_NOT_FULL_SIZE
+Language=English
+Disk Administrator can only create one partition on a removable disk. Therefore, if you create a partition which does not use the entire disk, you will not be able to use the remaining free space.
+
+Are you sure you want to create this partition?
+.
+
+;//////////////// 9066 -> 9067 : unused
+
+MessageID=9068 SymbolicName=MSG_CANT_FORMAT_WINNT
+Language=English
+Disk Administrator cannot format a volume containing Windows NT system files.
+.
+
+MessageID=9069 SymbolicName=MSG_CANT_DELETE_INITIALIZING_SET
+Language=English
+Disk Administrator cannot delete an FT set while it is initializing or regenerating.
+.
+
+MessageID=9070 SymbolicName=MSG_CANT_BREAK_INITIALIZING_SET
+Language=English
+Disk Administrator cannot break a Mirror set while it is initializing.
+.
+
+MessageID=9071 SymbolicName=MSG_CANT_REGEN_INITIALIZING_SET
+Language=English
+Disk Administrator cannot regenerate a Stripe set with Parity while it is initializing or regenerating.
+.
+
+MessageID=9072 SymbolicName=MSG_MIRROR_OF_BOOT
+Language=English
+This will be a Mirror set of the system boot partition. Please refer to the Windows NT Server Concepts and Planning Guide for information on how to create a Fault Tolerant boot floppy disk.
+.
+
+MessageID=9073 SymbolicName=MSG_CHANGED_BOOT_PARTITION_X86
+Language=English
+This change will modify the partition number of the partition which contains your Windows NT system files.
+
+The old partition number was %1; the new partition number is %2.
+
+Edit BOOT.INI to reflect this change before shutting the system down.
+.
+
+MessageID=9074 SymbolicName=MSG_CHANGED_BOOT_PARTITION_ARC
+Language=English
+This change will modify the partition number of the partition which contains your Windows NT system files.
+
+The old partition number was %1; the new partition number is %2.
+.
+
+MessageID=9075 SymbolicName=MSG_BOOT_PARTITION_CHANGED_X86
+Language=English
+The partition number of the partition which contains your Windows NT system files has changed.
+
+The old partition number was %1; the new partition number is %2.
+
+Edit BOOT.INI to reflect this change before shutting the system down.
+.
+
+MessageID=9076 SymbolicName=MSG_BOOT_PARTITION_CHANGED_ARC
+Language=English
+The partition number of the partition which contains your Windows NT system files has changed.
+
+The old partition number was %1; the new partition number is %2.
+.
+
+;//////////////// 9077 -> 9099: unused
+
+MessageID=9100 SymbolicName=MSG_CONFIRM_DEL_STRP
+Language=English
+All data in the stripe set will be lost!
+
+Are you sure you want to delete the selected stripe set?
+.
+
+MessageID=9101 SymbolicName=MSG_CRTSTRP_FULL
+Language=English
+The disk containing one of the free spaces you have chosen is not able to accept any more partitions.
+.
+
+MessageID=9102 SymbolicName=MSG_CRTMIRROR_BADFREE
+Language=English
+The free space you have chosen is not large enough to contain a mirror of the partition you have chosen.
+.
+
+MessageID=9103 SymbolicName=MSG_CONFIRM_BRK_MIRROR
+Language=English
+This will end mirroring and create two independent partitions.
+
+Are you sure you want to break the selected mirror?
+.
+
+MessageID=9104 SymbolicName=MSG_CONFIRM_DEL_VSET
+Language=English
+All data in the volume set will be lost!
+
+Are you sure you want to delete the selected volume set?
+.
+
+MessageId=9105 SymbolicName=MSG_CANT_INIT_FT
+Language=English
+Disk Administrator was unable to configure the Fault Tolerance Device. Mirrors and stripe sets with parity will not be initialized or regenerated.
+.
+
+MessageId=9106 SymbolicName=MSG_NOT_LARGE_ENOUGH_FOR_STRIPE
+Language=English
+The free space you have chosen is not large enough to contain an element in the stripe set you have chosen for regeneration.
+.
+
+MessageId=9107 SymbolicName=MSG_MUST_REBOOT
+Language=English
+Changes have been made which require you to restart your computer. Click OK to initiate system shutdown.
+.
+
+MessageId=9108 SymbolicName=MSG_COULDNT_REBOOT
+Language=English
+Disk Administrator was unable to restart your computer. To ensure the integrity of your disks and data, you should initiate system shutdown from the Program Manager. Click OK to exit Disk Administrator.
+.
+
+;//////////////// 9109, 9110: unused
+
+MessageID=9120 SymbolicName=MSG_CANT_LOAD_FMIFS
+Language=English
+Disk Administrator cannot locate fmifs.dll.
+.
+
+MessageID=9121 SymbolicName=MSG_CANT_FORMAT_NO_LETTER
+Language=English
+Disk Administrator cannot format a volume that is not assigned a drive letter.
+.
+
+MessageID=9122 SymbolicName=MSG_CONFIRM_FORMAT
+Language=English
+Warning: This operation will overwrite the data contained on this volume. Are you sure you wish to continue with this operation?
+.
+
+MessageID=9123 SymbolicName=MSG_COULDNT_CREATE_THREAD
+Language=English
+Disk Administrator could not create a thread to perform this operation.
+.
+
+MessageID=9124 SymbolicName=MSG_IO_ERROR
+Language=English
+An operation failed while attempting to format the volume.
+.
+
+;//////////////// 9126 -> 9199: unused
+
+MessageID=9200 SymbolicName=MSG_CANNOT_LOCK_TRY_AGAIN
+Language=English
+The drive cannot be locked for exclusive use.
+
+Please check to see if some applications are currently accessing the drive. If so, close them and try again.
+.
+
+MessageID=9201 SymbolicName=MSG_CANNOT_LOCK_FOR_COMMIT
+Language=English
+Disk Administrator could not lock all of the volumes affected by the changes selected. Please exit any applications holding references to the affected volumes and try again.
+.
+
+MessageID=9202 SymbolicName=MSG_NOT_COMMITTED
+Language=English
+The requested partitions and/or volumes have not been committed to disk. Retry this operation after committing this change.
+.
+
+MessageID=9203 SymbolicName=MSG_DRIVE_RENAME_WARNING
+Language=English
+This new drive letter assignment will happen immediately.
+
+Do you wish to continue?
+.
+
+MessageID=9204 SymbolicName=MSG_NO_COMMIT
+Language=English
+Not all of the affected disks can be changed without restarting the Windows NT system.
+.
+
+MessageID=9205 SymbolicName=MSG_VOLUME_CHANGED
+Language=English
+The removable media has changed. Insure the proper media is in the drive and perform the operation again.
+.
+
+MessageID=9206 SymbolicName=MSG_CANNOT_LOCK_PAGEFILE
+Language=English
+The drive letter cannot be changed because a Windows NT paging file is located on this drive.
+
+Relocate the paging file using the control panel system option.
+.
+
+MessageID=9207 SymbolicName=MSG_CDROM_LETTER_ERROR
+Language=English
+An error occurred attempting to change the CD-ROM drive letter.
+
+The drive letter has not been changed.
+.
+
+MessageID=9208 SymbolicName=MSG_CANNOT_LOCK_CDROM
+Language=English
+The CD-ROM cannot be locked for exclusive use.
+
+Please check to see if some applications are currently accessing the drive. If so, close them and try again.
+.
+
+MessageID=9209 SymbolicName=MSG_CANT_BREAK_WHILE_INITIALIZING
+Language=English
+The mirror set cannot be broken at this time.
+.
+
+MessageID=9210 SymbolicName=MSG_INTERNAL_LETTER_ASSIGN_ERROR
+Language=English
+An internal error occurred and some drive letters could not be assigned.
+.
+
+MessageID=9212 SymbolicName=MSG_ERROR_DURING_COMMIT
+Language=English
+Disk Administrator encountered an unknown error while making the requested changes. Some of the requested actions may not have occurred.
+.
+
+MessageID=9213 SymbolicName=MSG_CANNOT_MOVE_CDROM
+Language=English
+The new drive letter for the CD-ROM is still in use. Commit current Disk Administrator changes, verify network drive letter assignments and try again.
+.
+
+MessageID=9214 SymbolicName=MSG_BOOT_NEEDS_LETTER
+Language=English
+The boot drive MUST have a letter.
+.
+
+MessageID=9215 SymbolicName=MSG_SYS_LETTER_CHANGE
+Language=English
+Changing the drive letter for the windows directory may produce unexpected results. Are you sure you want to do this?
+.
+
+MessageID=9216 SymbolicName=MSG_SYS_NEEDS_LETTER
+Language=English
+The drive containing the windows directory MUST have a letter.
+.
+
+;//////////////// 9217 -> 9299: unused
+
+;//////////////////////////////////////////////////////////////////////////////
+;//////////////////////////////////////////////////////////////////////////////
+;/////
+;///// NOTE: the following messages are x86-specific!
+;/////
+;//////////////////////////////////////////////////////////////////////////////
+;//////////////////////////////////////////////////////////////////////////////
+
+MessageID=9300 SymbolicName=MSG_DISK0_ACTIVE
+Language=English
+The requested partition has been marked active.
+When you reboot your computer the operating system on that partition will be started.
+.
+
+MessageID=9301 SymbolicName=MSG_PRI_1024_CYL
+Language=English
+The partition created may not be accessible from other operating systems such as MS-DOS because the start or end cylinder value is too large.
+
+Do you want to create the partition anyway?
+.
+
+MessageID=9302 SymbolicName=MSG_EXT_1024_CYL
+Language=English
+Logical drives created within the extended partition will not be accessible from other operating systems such as MS-DOS because the start or end cylinder value is too large.
+
+Do you want to create the extended partition anyway?
+.
+
+MessageID=9303 SymbolicName=MSG_CANT_DELETE_ACTIVE0
+Language=English
+Disk Administrator cannot delete the active partition on disk 0.
+.
+
+MessageID=9304 SymbolicName=MSG_CANT_EXTEND_ACTIVE0
+Language=English
+Disk Administrator cannot convert the active partition on disk 0 into a volume set.
+.
+
+;//////////////////////////////////////////////////////////////////////////////
+;//////////////////////////////////////////////////////////////////////////////
+;/////
+;///// NOTE: end of x86-specific messages
+;/////
+;//////////////////////////////////////////////////////////////////////////////
+;//////////////////////////////////////////////////////////////////////////////
+
+
+;#endif // __MESSAGES_H__
diff --git a/private/utils/windisk/src/misc.cxx b/private/utils/windisk/src/misc.cxx
new file mode 100644
index 000000000..ff0710d96
--- /dev/null
+++ b/private/utils/windisk/src/misc.cxx
@@ -0,0 +1,1404 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: misc.cxx
+//
+// Contents: Miscellaneous routines
+//
+// History: 7-Jan-90 TedM Created
+// 13-Dec-94 BruceFo Incorporated BobRi's Daytona changes
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include <process.h>
+#include <stdlib.h>
+
+#include <util.hxx>
+
+#include "init.hxx"
+#include "nt.hxx"
+#include "profile.hxx"
+#include "stleg.hxx"
+#include "fill.hxx"
+#include "ops.hxx"
+#include "windisk.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+BOOL
+AllDisksOffLine(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Determine whether all hard disks are off line.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if all disks off-line, false otherwise.
+
+--*/
+
+{
+ ULONG i;
+
+ FDASSERT(DiskCount);
+
+ for (i=0; i<DiskCount; i++)
+ {
+ if (!IsDiskOffLine(i))
+ {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+
+VOID
+FdShutdownTheSystem(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to update the caller privilege, then shutdown the
+ Windows NT system. If it fails it prints a warning dialog. If it
+ succeeds then it doesn't return to the caller.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ NTSTATUS status;
+ BOOLEAN previousPriv;
+
+ InfoDialog(MSG_MUST_REBOOT);
+ SetCursor(g_hCurWait);
+ WriteProfile();
+
+ //
+ // Enable shutdown privilege
+ //
+
+ status = RtlAdjustPrivilege( SE_SHUTDOWN_PRIVILEGE,
+ TRUE,
+ FALSE,
+ &previousPriv
+ );
+
+#if DBG == 1
+ if (status)
+ {
+ DbgPrint("DISKMAN: status %lx attempting to enable shutdown privilege\n", status);
+ }
+#endif // DBG == 1
+
+ Sleep(3000);
+ if (!ExitWindowsEx(EWX_REBOOT, (DWORD)(-1)))
+ {
+ WarningDialog(MSG_COULDNT_REBOOT);
+ }
+}
+
+
+int
+GetHeightFromPoints(
+ IN int Points
+ )
+
+/*++
+
+Routine Description:
+
+ This routine calculates the height of a font given a point value.
+ The calculation is based on 72 points per inch and the display's
+ pixels/inch device capability.
+
+Arguments:
+
+ Points - number of points
+
+Return Value:
+
+ pixel count (negative and therefore suitable for passing to
+ CreateFont())
+
+--*/
+
+{
+ HDC hdc = GetDC(NULL);
+ int height = MulDiv(-Points, GetDeviceCaps(hdc, LOGPIXELSY), 72);
+
+ ReleaseDC(NULL, hdc);
+
+ return height;
+}
+
+
+VOID
+RetrieveAndFormatMessage(
+ IN DWORD Msg,
+ OUT LPTSTR Buffer,
+ IN DWORD BufferSize,
+ IN va_list* parglist
+ )
+{
+ DWORD x;
+ TCHAR text[MAX_RESOURCE_STRING_LEN];
+
+ // get message from system or app msg file.
+
+ x = FormatMessage( (Msg >= MSG_FIRST_FDISK_MSG)
+ ? FORMAT_MESSAGE_FROM_HMODULE
+ : FORMAT_MESSAGE_FROM_SYSTEM
+ ,
+ NULL,
+ Msg,
+ 0,
+ Buffer,
+ BufferSize,
+ parglist
+ );
+
+ if (!x) // couldn't find message
+ {
+ LoadString(g_hInstance,
+ (Msg >= MSG_FIRST_FDISK_MSG)
+ ? IDS_NOT_IN_APP_MSG_FILE
+ : IDS_NOT_IN_SYS_MSG_FILE,
+ text,
+ ARRAYLEN(text)
+ );
+
+ wsprintf(Buffer, text, Msg);
+ }
+}
+
+
+
+
+DWORD
+CommonDialog(
+ IN DWORD MsgCode,
+ IN LPTSTR Caption,
+ IN DWORD Flags,
+ IN va_list arglist
+ )
+
+/*++
+
+Routine Description:
+
+ Simple dialog routine to get dialogs out of the resource
+ for the program and run them as a message box.
+
+Arguments:
+
+ MsgCode - dialog message code
+ Caption - message box caption
+ Flags - standard message box flags
+ arglist - list to be given when pulling the message text
+
+Return Value:
+
+ The MessageBox() return value
+
+--*/
+
+{
+ // If we're starting up and get an error, make sure the "Starting
+ // Disk Administrator..." dialog goes away
+
+// STARTUP EndStartup();
+
+ TCHAR msgBuf[MESSAGE_BUFFER_SIZE];
+
+ if (NULL != g_InitDlg)
+ {
+ PostMessage(g_InitDlg, WM_STARTUP_END, 0, 0);
+ g_InitDlg = NULL;
+ }
+
+ RetrieveAndFormatMessage(MsgCode, msgBuf, ARRAYLEN(msgBuf), &arglist);
+ return MessageBox(GetActiveWindow(), msgBuf, Caption, Flags);
+}
+
+
+
+
+DWORD
+CommonDialogNoArglist(
+ IN DWORD MsgCode,
+ IN LPTSTR Caption,
+ IN DWORD Flags
+ )
+
+/*++
+
+Routine Description:
+
+ Simple dialog routine to get dialogs out of the resource
+ for the program and run them as a message box.
+
+ There had better not be any FormatMessage "inserts"!
+
+Arguments:
+
+ MsgCode - dialog message code
+ Caption - message box caption
+ Flags - standard message box flags
+
+Return Value:
+
+ The MessageBox() return value
+
+--*/
+
+{
+ // If we're starting up and get an error, make sure the "Starting
+ // Disk Administrator..." dialog goes away
+
+// STARTUP EndStartup();
+
+ TCHAR msgBuf[MESSAGE_BUFFER_SIZE];
+
+ if (NULL != g_InitDlg)
+ {
+ PostMessage(g_InitDlg, WM_STARTUP_END, 0, 0);
+ g_InitDlg = NULL;
+ }
+
+ RetrieveAndFormatMessage(MsgCode, msgBuf, ARRAYLEN(msgBuf), NULL);
+ return MessageBox(GetActiveWindow(), msgBuf, Caption, Flags);
+}
+
+
+
+
+VOID
+ErrorDialog(
+ IN DWORD ErrorCode,
+ ...
+ )
+
+/*++
+
+-Routine Description:
+
+ This routine retreives a message from the app or system message file
+ and displays it in a message box.
+
+Arguments:
+
+ ErrorCode - number of message
+
+ ... - strings for insertion into message
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ va_list arglist;
+
+ va_start(arglist, ErrorCode);
+
+ CommonDialog(ErrorCode, NULL, MB_ICONHAND | MB_OK | MB_SYSTEMMODAL, arglist);
+
+ va_end(arglist);
+}
+
+
+
+
+VOID
+WarningDialog(
+ IN DWORD MsgCode,
+ ...
+ )
+
+/*++
+
+Routine Description:
+
+ This routine retreives a message from the app or system message file
+ and displays it in a message box.
+
+Arguments:
+
+ MsgCode - number of message
+
+ ... - strings for insertion into message
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ TCHAR caption[MAX_RESOURCE_STRING_LEN];
+ va_list arglist;
+
+ va_start(arglist, MsgCode);
+
+ LoadString(g_hInstance, IDS_APPNAME, caption, ARRAYLEN(caption));
+ CommonDialog(MsgCode, caption, MB_ICONEXCLAMATION | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND, arglist);
+
+ va_end(arglist);
+}
+
+
+
+
+DWORD
+ConfirmationDialog(
+ IN DWORD MsgCode,
+ IN DWORD Flags,
+ ...
+ )
+
+/*++
+
+Routine Description:
+
+ Support for a simple confirmation dialog
+
+Arguments:
+
+ MsgCode - resource code for message
+ Flags - dialog flags
+
+Return Value:
+
+ Result from the CommonDialog() performed.
+
+--*/
+
+{
+ TCHAR caption[MAX_RESOURCE_STRING_LEN];
+ DWORD x;
+ va_list arglist;
+
+ va_start(arglist, Flags);
+
+ LoadString(g_hInstance, IDS_CONFIRM, caption, ARRAYLEN(caption));
+ x = CommonDialog(MsgCode, caption, Flags | MB_TASKMODAL, arglist);
+ va_end(arglist);
+ return x;
+}
+
+
+
+VOID
+InfoDialogTitle(
+ IN UINT TitleId,
+ IN DWORD MsgCode,
+ ...
+ )
+
+/*++
+
+Routine Description:
+
+ This routine retreives a message from the app or system message file
+ and displays it in a message box.
+
+Arguments:
+
+ MsgCode - number of message
+
+ ... - strings for insertion into message
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ TCHAR caption[MAX_RESOURCE_STRING_LEN];
+
+ va_list arglist;
+ va_start(arglist, MsgCode);
+
+ LoadString(g_hInstance, TitleId, caption, ARRAYLEN(caption));
+ CommonDialog(MsgCode, caption, MB_ICONINFORMATION | MB_OK | MB_TASKMODAL, arglist);
+ va_end(arglist);
+}
+
+
+
+
+VOID
+InfoDialog(
+ IN DWORD MsgCode,
+ ...
+ )
+
+/*++
+
+Routine Description:
+
+ This routine retreives a message from the app or system message file
+ and displays it in a message box.
+
+Arguments:
+
+ MsgCode - number of message
+
+ ... - strings for insertion into message
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ TCHAR caption[MAX_RESOURCE_STRING_LEN];
+ va_list arglist;
+
+ va_start(arglist, MsgCode);
+
+ LoadString(g_hInstance, IDS_APPNAME, caption, ARRAYLEN(caption));
+ CommonDialog(MsgCode, caption, MB_ICONINFORMATION | MB_OK | MB_TASKMODAL, arglist);
+ va_end(arglist);
+}
+
+
+PREGION_DESCRIPTOR
+LocateRegionForFtObject(
+ IN PFT_OBJECT FtObject
+ )
+
+/*++
+
+Routine Description:
+
+ Given an FtObject, find the associated region descriptor
+
+Arguments:
+
+ FtObject - the ft object to search for.
+
+Return Value:
+
+ NULL - no descriptor found
+ !NULL - a pointer to the region descriptor for the FT object
+
+++*/
+
+{
+ PDISKSTATE diskState;
+ PREGION_DESCRIPTOR regionDescriptor;
+ DWORD diskNumber;
+ DWORD regionIndex;
+ PPERSISTENT_REGION_DATA regionData;
+
+ for (diskNumber = 0; diskNumber < DiskCount; diskNumber++)
+ {
+ diskState = DiskArray[diskNumber];
+
+ for (regionIndex = 0; regionIndex < diskState->RegionCount; regionIndex++)
+ {
+ regionDescriptor = &diskState->RegionArray[regionIndex];
+ regionData = PERSISTENT_DATA(regionDescriptor);
+
+ if (NULL != regionData)
+ {
+ if (regionData->FtObject == FtObject)
+ {
+ return regionDescriptor;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: ClonePersistentData
+//
+// Synopsis: Copies volume label, file system name, drive letter, new
+// region flag, and space information. Doesn't copy
+// FtObject pointer (which is different for every region).
+//
+// Arguments: [RegionFrom] --
+// [RegionTo] --
+//
+// Returns: nothing
+//
+// History: 7-Dec-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+VOID
+ClonePersistentData(
+ IN PREGION_DESCRIPTOR RegionFrom,
+ OUT PREGION_DESCRIPTOR RegionTo
+ )
+{
+ daDebugOut((DEB_ITRACE,
+ "Cloning data from disk %d TO disk %d ...\n",
+ RegionFrom->Disk,
+ RegionTo->Disk
+ ));
+
+ PWSTR volumeLabel = NULL;
+ PWSTR typeName = NULL;
+
+ PPERSISTENT_REGION_DATA regionDataFrom = PERSISTENT_DATA(RegionFrom);
+ PPERSISTENT_REGION_DATA regionDataTo = PERSISTENT_DATA(RegionTo);
+
+ FDASSERT(NULL != regionDataFrom);
+ FDASSERT(NULL != regionDataTo);
+
+ if (regionDataFrom->VolumeLabel)
+ {
+ volumeLabel = (PWSTR)Malloc((lstrlen(regionDataFrom->VolumeLabel)+1)*sizeof(WCHAR));
+ lstrcpy(volumeLabel, regionDataFrom->VolumeLabel);
+ }
+
+ if (regionDataFrom->TypeName)
+ {
+ typeName = (PWSTR)Malloc((lstrlen(regionDataFrom->TypeName)+1)*sizeof(WCHAR));
+ lstrcpy(typeName, regionDataFrom->TypeName);
+ }
+
+ DmInitPersistentRegionData(
+ regionDataTo,
+ regionDataTo->FtObject, // keep the same FtObject
+ volumeLabel,
+ typeName,
+ regionDataFrom->DriveLetter,
+ regionDataFrom->NewRegion,
+ regionDataFrom->FreeSpaceInBytes,
+ regionDataFrom->TotalSpaceInBytes
+ );
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: GetPersistentData
+//
+// Synopsis: Loads volume label and file system type name into the
+// persistent data. Frees old data first.
+//
+// Arguments: [RegionDescriptor] -- The region in question
+//
+// Returns: The actual region that data was loaded for.
+//
+// History: 1-Oct-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+PREGION_DESCRIPTOR
+GetPersistentData(
+ IN OUT PREGION_DESCRIPTOR RegionDescriptor
+ )
+{
+ if (DmSignificantRegion(RegionDescriptor))
+ {
+ WCHAR volumeLabel[100];
+ WCHAR typeName[100];
+ LARGE_INTEGER freeSpaceInBytes;
+ LARGE_INTEGER totalSpaceInBytes;
+
+ //
+ // If the region has a drive letter, use the drive letter
+ // to get the info via the Windows API. Otherwise we'll
+ // have to use the NT API.
+ //
+
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(RegionDescriptor);
+
+ if (NULL == regionData)
+ {
+ return NULL;
+ }
+
+ if (IsExtraDriveLetter(regionData->DriveLetter))
+ {
+ PWSTR tempLabel;
+ PWSTR tempName;
+
+ //
+ // No drive letter. Use NT API.
+ //
+
+ daDebugOut((DEB_ITRACE,
+ "Getting space info for disk %d, partition %d\n",
+ RegionDescriptor->Disk,
+ RegionDescriptor->PartitionNumber
+ ));
+
+ // If this is an FT set use the zero member disk for the
+ // call so all members get the right type and label
+
+ if (regionData->FtObject)
+ {
+ PFT_OBJECT searchFtObject;
+
+ // Want to get RegionDescriptor pointing to the zeroth member
+
+ searchFtObject = regionData->FtObject->Set->Member0;
+
+ // Now search regions for this match
+
+ RegionDescriptor = LocateRegionForFtObject(searchFtObject);
+
+ if (NULL == RegionDescriptor)
+ {
+ return NULL;
+ }
+ }
+
+ if (NO_ERROR == GetVolumeLabel(
+ RegionDescriptor->Disk,
+ RegionDescriptor->PartitionNumber,
+ &tempLabel))
+ {
+ lstrcpy(volumeLabel, tempLabel);
+ Free(tempLabel);
+ }
+ else
+ {
+ volumeLabel[0] = L'\0';
+ }
+
+ if (NO_ERROR == GetTypeName(
+ RegionDescriptor->Disk,
+ RegionDescriptor->PartitionNumber,
+ &tempName))
+ {
+ lstrcpy(typeName, tempName);
+ Free(tempName);
+ }
+ else
+ {
+ lstrcpy(typeName, wszUnknown);
+ }
+
+ //
+ // get space info
+ //
+
+ if (NO_ERROR != GetSpaceInformation(
+ RegionDescriptor->Disk,
+ RegionDescriptor->PartitionNumber,
+ &freeSpaceInBytes,
+ &totalSpaceInBytes))
+ {
+ freeSpaceInBytes.QuadPart
+ = totalSpaceInBytes.QuadPart
+ = 0
+ ;
+ }
+ }
+ else
+ {
+ //
+ // Use Windows API.
+ //
+
+ WCHAR diskRootPath[4];
+ diskRootPath[0] = regionData->DriveLetter;
+ diskRootPath[1] = L':';
+ diskRootPath[2] = L'\\';
+ diskRootPath[3] = L'\0';
+
+ daDebugOut((DEB_ITRACE,
+ "Getting space info for volume %ws\n",
+ diskRootPath
+ ));
+
+ UINT errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+ if (!GetVolumeInformation(
+ diskRootPath,
+ volumeLabel,
+ ARRAYLEN(volumeLabel),
+ NULL,
+ NULL,
+ NULL,
+ typeName,
+ ARRAYLEN(typeName)))
+ {
+ lstrcpy(typeName, wszUnknown);
+ volumeLabel[0] = L'\0';
+ }
+
+ //
+ // Get space info
+ //
+
+ DWORD sectorsPerCluster;
+ DWORD bytesPerSector;
+ DWORD freeClusters;
+ DWORD clusters;
+
+ if (GetDiskFreeSpace(
+ diskRootPath,
+ &sectorsPerCluster,
+ &bytesPerSector,
+ &freeClusters,
+ &clusters))
+ {
+ freeSpaceInBytes.QuadPart = UInt32x32To64(freeClusters, sectorsPerCluster);
+ freeSpaceInBytes.QuadPart *= bytesPerSector;
+
+ totalSpaceInBytes.QuadPart = UInt32x32To64(clusters, sectorsPerCluster);
+ totalSpaceInBytes.QuadPart *= bytesPerSector;
+ }
+ else
+ {
+ freeSpaceInBytes.QuadPart
+ = totalSpaceInBytes.QuadPart
+ = 0
+ ;
+ }
+ SetErrorMode(errorMode);
+ }
+
+ regionData->FreeSpaceInBytes = freeSpaceInBytes;
+ regionData->TotalSpaceInBytes = totalSpaceInBytes;
+
+ if (!lstrcmpi(typeName, L"raw"))
+ {
+ lstrcpy(typeName, wszUnknown);
+ }
+
+ if (NULL != regionData->TypeName)
+ {
+ Free(regionData->TypeName);
+ }
+
+ if (NULL != regionData->VolumeLabel)
+ {
+ Free(regionData->VolumeLabel);
+ }
+
+ regionData->TypeName = (PWSTR)Malloc((lstrlen(typeName) + 1) * sizeof(WCHAR));
+ regionData->VolumeLabel = (PWSTR)Malloc((lstrlen(volumeLabel) + 1) * sizeof(WCHAR));
+
+ lstrcpy(regionData->TypeName, typeName);
+ lstrcpy(regionData->VolumeLabel, volumeLabel);
+ }
+
+ return RegionDescriptor;
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: RefreshVolumeData
+//
+// Synopsis:
+//
+// Assumes all volume data (persistent data) changed. Reloads it
+// and refreshes the display.
+//
+// Arguments: none
+//
+// Assumes: There is a legal volume selection
+//
+// Returns: nothing
+//
+// History: 11-Jan-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+RefreshVolumeData(
+ VOID
+ )
+{
+ SetCursor(g_hCurWait);
+
+ PREGION_DESCRIPTOR regionDescriptor = &SELECTED_REGION(0);
+ regionDescriptor = GetPersistentData(regionDescriptor);
+
+ DWORD i;
+ for (i=1; i<SelectionCount; i++)
+ {
+ //
+ // For an FT set, just clone the volume data for each region
+ //
+
+ ClonePersistentData(regionDescriptor, &SELECTED_REGION(i));
+ }
+
+#ifdef WINDISK_EXTENSIONS
+
+ //
+ // If the format changed, we need a new claim list:
+ //
+
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(regionDescriptor);
+ ClaimVolume(regionData->DriveLetter);
+
+#endif // WINDISK_EXTENSIONS
+
+ //
+ // Change the menu based on this new format
+ //
+
+ SetUpMenu(&SingleSel, &SingleSelIndex);
+
+ //
+ // refresh the display
+ //
+
+ RefreshBothViews();
+
+ SetCursor(g_hCurNormal);
+}
+
+
+
+
+
+
+VOID
+InitVolumeInformation(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Determine the volume information (label, type, size info) for each
+ significant (non-extended, non-free, recognized) partition.
+
+ Assumes that persistent data has already been set up, and drive letters
+ determined.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DWORD diskNum;
+ DWORD regionNum;
+ PDISKSTATE diskState;
+ PREGION_DESCRIPTOR regionDescriptor;
+ PFT_OBJECT ftObject;
+ PFT_OBJECT ftObj;
+
+ //
+ // First, set the FT flag to FALSE for all FT regions
+ //
+
+ for (diskNum=0; diskNum<DiskCount; diskNum++)
+ {
+ diskState = DiskArray[diskNum];
+
+ for (regionNum=0; regionNum<diskState->RegionCount; regionNum++)
+ {
+ regionDescriptor = &diskState->RegionArray[regionNum];
+ ftObject = GET_FT_OBJECT(regionDescriptor);
+ if (ftObject)
+ {
+ ftObject->Set->Flag = FALSE;
+ }
+ }
+ }
+
+ //
+ // Now, for all simple regions and all FT regions that don't have their
+ // flag set, get the persistent data. For FT regions, get the data for
+ // one, then clone it for the rest, and set the flag.
+ //
+
+ for (diskNum=0; diskNum<DiskCount; diskNum++)
+ {
+ diskState = DiskArray[diskNum];
+
+ for (regionNum=0; regionNum<diskState->RegionCount; regionNum++)
+ {
+ regionDescriptor = &diskState->RegionArray[regionNum];
+ ftObject = GET_FT_OBJECT(regionDescriptor);
+ if (NULL == ftObject || !ftObject->Set->Flag)
+ {
+ regionDescriptor = GetPersistentData(regionDescriptor);
+
+ if (regionDescriptor == NULL)
+ continue;
+
+ if (ftObject)
+ {
+ ftObject->Set->Flag = TRUE;
+
+ for (ftObj = ftObject->Set->Members;
+ NULL != ftObj;
+ ftObj = ftObj->Next)
+ {
+ PREGION_DESCRIPTOR componentRegion = ftObj->Region;
+ FDASSERT(NULL != componentRegion);
+
+ if ( NULL != componentRegion // off-line
+ && componentRegion != regionDescriptor)
+ {
+ // don't clone to self
+ ClonePersistentData(regionDescriptor, componentRegion);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+VOID
+DetermineRegionInfo(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ OUT PWSTR* TypeName,
+ OUT PWSTR* VolumeLabel,
+ OUT PWCHAR DriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ For a given region, fetch the persistent data, appropriately modified
+ depending on whether the region is used or free, recognized, etc.
+
+Arguments:
+
+ RegionDescriptor - supplies a pointer to the region whose data is to be fetched.
+
+ TypeName - receives a pointer to the type name. If the region is
+ unrecognized, the type is determined based on the system id of
+ the partition.
+
+ VolumeLabel - receives a pointer to the volume label. If the region is
+ free space or unrecognized, the volume label is "".
+
+ DriveLetter - recieves the drive letter. If the region is free space
+ or unrecognized, the drive letter is ' ' (space).
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PWSTR typeName;
+ PWSTR volumeLabel;
+ WCHAR driveLetter;
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(RegionDescriptor);
+
+ if (DmSignificantRegion(RegionDescriptor))
+ {
+ typeName = regionData->TypeName;
+ volumeLabel = regionData->VolumeLabel;
+ driveLetter = regionData->DriveLetter;
+ if (IsExtraDriveLetter(driveLetter))
+ {
+ driveLetter = L' ';
+ }
+ }
+ else
+ {
+ typeName = GetWideSysIDName(RegionDescriptor->SysID);
+ volumeLabel = L"";
+ driveLetter = L' ';
+ }
+
+ *TypeName = typeName;
+ *VolumeLabel = volumeLabel;
+ *DriveLetter = driveLetter;
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: IsFaultTolerantRegion
+//
+// Synopsis: Determines if a given region is part of a fault tolerant
+// volume, i.e., a mirror set (RAID 1) or a stripe set with
+// parity (RAID 5)
+//
+// Arguments: [RegionDescriptor] -- The region in question
+//
+// Returns: TRUE if the region is part of a fault tolerant volume
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+BOOL
+IsFaultTolerantRegion(
+ IN PREGION_DESCRIPTOR RegionDescriptor
+ )
+{
+ PFT_OBJECT ftObject = GET_FT_OBJECT(RegionDescriptor);
+
+ if (NULL == ftObject)
+ {
+ return FALSE;
+ }
+
+ FT_TYPE ftType = ftObject->Set->Type;
+
+ return (Mirror == ftType || StripeWithParity == ftType);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: MyCheckMenuItem
+//
+// Synopsis: For a range of menu items, uncheck everything but one,
+// which is checked
+//
+// Arguments: [hMenu] -- handle of menu to affect
+// [idFirst] -- menu id of first sequential item
+// [idLast] -- menu id of last sequential item
+// [idCheckItem] -- menu id of the sole item to check
+//
+// Returns: nothing
+//
+// History: 2-Sep-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+MyCheckMenuItem(
+ HMENU hMenu,
+ UINT idFirst,
+ UINT idLast,
+ UINT idCheckItem
+ )
+{
+ CheckMenuRadioItem(hMenu, idFirst, idLast, idCheckItem, MF_BYCOMMAND);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: MyEnableMenuItem
+//
+// Synopsis: For a range of menu items, set the menu flags
+//
+// Arguments: [hMenu] -- handle of menu to affect
+// [idFirst] -- menu id of first sequential item
+// [idLast] -- menu id of last sequential item
+// [fItemFlags] -- menu flags to set
+//
+// Returns: nothing
+//
+// History: 2-Sep-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+MyEnableMenuItem(
+ HMENU hMenu,
+ UINT idFirst,
+ UINT idLast,
+ UINT fItemFlags
+ )
+{
+ for (UINT i = idFirst; i <= idLast; i++)
+ {
+ EnableMenuItem(
+ g_hmenuFrame,
+ i,
+ MF_BYCOMMAND | fItemFlags
+ );
+ }
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: InitDrawGasGauge
+//
+// Synopsis: Initializes drawing a gas gauge rectangle
+//
+// Arguments: [hwndGauge] -- handle to the gauge.
+//
+// Returns: nothing
+//
+// History: 12-Nov-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+InitDrawGasGauge(
+ IN HWND hwndGauge
+ )
+{
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DrawGasGauge
+//
+// Synopsis: draws a gas gauge rectangle
+//
+// Arguments: [hwndGauge] -- handle to the gauge.
+// [hwndParent] -- handle to the gauge's parent.
+// [hDC] -- hDC to draw with.
+// [PercentDone] -- % finished. if -1, then don't display a
+// percent done. instead, display the caption.
+// [Caption] -- string caption to display in the rectangle,
+// only if PercentDone is -1.
+//
+// Returns: nothing
+//
+// History: 12-Nov-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DrawGasGauge(
+ IN HWND hwndGauge,
+ IN HWND hwndParent,
+ IN HDC hDC,
+ IN INT PercentDone,
+ IN PWSTR Caption
+ )
+{
+ // The gas gauge is drawn by drawing a text string stating
+ // what percentage of the job is done into the middle of
+ // the gas gauge rectangle, and by separating that rectangle
+ // into two parts: rectDone (the left part, filled in blue)
+ // and rectLeftToDo(the right part, filled in white).
+ // nDivideRects is the x coordinate that divides these two rects.
+ //
+ // The text in the blue rectangle is drawn white, and vice versa
+ // This is easy to do with ExtTextOut()!
+
+ RECT rcGauge;
+ TCHAR buffer[100];
+ SIZE size;
+ INT xText, yText;
+ INT nDivideRects;
+ RECT rcDone;
+ RECT rcLeftToDo;
+
+ GetClientRect(hwndGauge, &rcGauge);
+
+ INT width = rcGauge.right - rcGauge.left;
+ INT height = rcGauge.bottom - rcGauge.top;
+
+ ClientToScreen(hwndGauge, (LPPOINT)&rcGauge.left);
+ ClientToScreen(hwndGauge, (LPPOINT)&rcGauge.right);
+ ScreenToClient(hwndParent, (LPPOINT)&rcGauge.left);
+ ScreenToClient(hwndParent, (LPPOINT)&rcGauge.right);
+
+ //
+ // We use SS_BLACKFRAME static controls with one pixel borders in
+ // the client area: deflate the rect to avoid drawing over the border
+ //
+ InflateRect(&rcGauge, -1, -1);
+
+ if (-1 == PercentDone)
+ {
+ wsprintf(buffer, TEXT("%s"), Caption);
+
+ nDivideRects = 0;
+ }
+ else
+ {
+ wsprintf(buffer, TEXT("%3d%%"), PercentDone);
+
+ nDivideRects = (width * PercentDone) / 100;
+ }
+
+ UINT bufferLength = lstrlen(buffer);
+ COLORREF blue = RGB(0, 0, 255);
+ COLORREF white = RGB(255, 255, 255);
+
+ GetTextExtentPoint32(hDC, buffer, bufferLength, &size);
+ xText = rcGauge.left + (width - size.cx) / 2;
+ yText = rcGauge.top + (height - size.cy) / 2;
+
+ // Paint in the "done so far" rectangle of the gas
+ // gauge with blue background and white text
+
+ SetRect(
+ &rcDone,
+ rcGauge.left,
+ rcGauge.top,
+ rcGauge.left + nDivideRects,
+ rcGauge.bottom
+ );
+
+ SetTextColor(hDC, white);
+ SetBkColor(hDC, blue);
+
+ ExtTextOut(
+ hDC,
+ xText,
+ yText,
+ ETO_CLIPPED | ETO_OPAQUE,
+ &rcDone,
+ buffer,
+ bufferLength,
+ NULL
+ );
+
+ // Paint in the "still left to do" rectangle of the gas
+ // gauge with white background and blue text
+
+ SetRect(
+ &rcLeftToDo,
+ rcGauge.left + nDivideRects,
+ rcGauge.top,
+ rcGauge.right,
+ rcGauge.bottom
+ );
+
+ SetTextColor(hDC, blue);
+ SetBkColor(hDC, white);
+
+ ExtTextOut(
+ hDC,
+ xText,
+ yText,
+ ETO_CLIPPED | ETO_OPAQUE,
+ &rcLeftToDo,
+ buffer,
+ bufferLength,
+ NULL
+ );
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: KillBold
+//
+// Synopsis:
+//
+// Arguments:
+//
+// Returns:
+//
+// History: 31-Jan-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+HFONT
+KillBold(
+ IN HWND hdlg,
+ IN PUINT aControls
+ )
+{
+ LOGFONT lFont;
+
+ HFONT hDlgFont = (HFONT)SendMessage(hdlg, WM_GETFONT, 0, 0);
+ if (NULL != hDlgFont)
+ {
+ if (GetObject(hDlgFont, sizeof(LOGFONT), (LPVOID)&lFont))
+ {
+ lFont.lfWeight = FW_NORMAL;
+ hDlgFont = CreateFontIndirect(&lFont);
+ if (NULL != hDlgFont)
+ {
+ for (UINT i = 0; 0 != aControls[i]; i++)
+ {
+ SendDlgItemMessage(
+ hdlg,
+ aControls[i],
+ WM_SETFONT,
+ (WPARAM)hDlgFont,
+ MAKELPARAM(FALSE, 0));
+ }
+ }
+ else
+ {
+ daDebugOut((DEB_ITRACE, "Couldn't create font\n"));
+ }
+ }
+ else
+ {
+ daDebugOut((DEB_ITRACE, "Couldn't get font object\n"));
+ }
+ }
+ else
+ {
+ daDebugOut((DEB_ITRACE, "Couldn't get font handle\n"));
+ }
+
+ return hDlgFont;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: LargeIntegerToUnicodeChar
+//
+// Synopsis: converts a LARGE_INTEGER to a unicode string representation
+//
+// Arguments: Same as RtlLargeIntegerToChar (except takes a UNICODE string)
+//
+// Returns: nothing
+//
+// History: 6-Dec-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+NTSTATUS
+LargeIntegerToUnicodeChar(
+ IN PLARGE_INTEGER Value,
+ IN ULONG Base OPTIONAL,
+ IN LONG OutputLength,
+ OUT PWSTR String
+ )
+{
+ CHAR ansiString[100];
+ NTSTATUS status = RtlLargeIntegerToChar(Value, Base, OutputLength, ansiString);
+ mbstowcs(String, ansiString, OutputLength);
+ return status;
+}
diff --git a/private/utils/windisk/src/network.cxx b/private/utils/windisk/src/network.cxx
new file mode 100644
index 000000000..609a88757
--- /dev/null
+++ b/private/utils/windisk/src/network.cxx
@@ -0,0 +1,184 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: network.cxx
+//
+// Contents: The set of routines that support updating network
+// drive shares when adding and deleting drive letters.
+//
+// History: 12-26-94 Bob Rinne Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include <lm.h>
+
+#include "network.hxx"
+
+// Data area to hold the permissions that are to be assigned to the
+// administrative shares C$, D$, etc. This is obtained during initialization
+// and not changed, just used when a new administrator share needes to
+// be made.
+
+LPBYTE ShareInformationBuffer;
+
+// Only perform network actions if this value is true. This value
+// is set if the initialization of this module completes successfully.
+
+BOOLEAN NetworkEnabled;
+
+
+VOID
+NetworkInitialize(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Intialize the permissions constants for any new administrator
+ driver letter shares.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ WCHAR shareName[3];
+ NET_API_STATUS status;
+ PSHARE_INFO_502 info;
+ LPTSTR string;
+
+ shareName[1] = L'$';
+ shareName[2] = L'\0';
+
+ for (shareName[0] = L'C'; shareName[0] <= L'Z'; shareName[0]++)
+ {
+ status = NetShareGetInfo(NULL,
+ shareName,
+ 502,
+ &ShareInformationBuffer);
+ if (status == NERR_Success)
+ {
+ // Update the remarks and password to be NULL.
+
+ info = (PSHARE_INFO_502) ShareInformationBuffer;
+ string = info->shi502_remark;
+ if (string)
+ {
+ *string = L'\0';
+ }
+ string = info->shi502_passwd;
+ if (string)
+ {
+ *string = L'\0';
+ }
+
+ // Network shares are to be updated.
+
+ NetworkEnabled = TRUE;
+ return;
+ }
+ }
+
+ // Can't find any network shares - do not attempt updates
+ // of administrator shares.
+
+ NetworkEnabled = FALSE;
+}
+
+VOID
+NetworkShare(
+ IN LPCTSTR DriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ Given a drive letter, construct the default administrator share
+ for the letter. This is the C$, D$, etc share for the drive.
+
+Arguments:
+
+ DriveLetter - the drive letter to share.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ NET_API_STATUS status;
+ PSHARE_INFO_502 info;
+ LPTSTR string;
+
+ if (NetworkEnabled)
+ {
+ info = (PSHARE_INFO_502) ShareInformationBuffer;
+
+ // Set up the new network name.
+
+ string = info->shi502_netname;
+ *string = *DriveLetter;
+
+ // Set up the path. All that needs be added is the drive letter;
+ // the rest of the path (":\") is already in the structure.
+
+ string = info->shi502_path;
+ *string = *DriveLetter;
+
+ status = NetShareAdd(NULL,
+ 502,
+ ShareInformationBuffer,
+ NULL);
+ }
+}
+
+
+VOID
+NetworkRemoveShare(
+ IN LPCTSTR DriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ Remove the administrator share for the given letter.
+
+Arguments:
+
+ DriveLetter - the drive letter to share.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ NET_API_STATUS status;
+ WCHAR shareName[3];
+
+ if (NetworkEnabled)
+ {
+ shareName[0] = *DriveLetter;
+ shareName[1] = L'$';
+ shareName[2] = L'\0';
+
+ status = NetShareDel(NULL, shareName, 0);
+ }
+}
diff --git a/private/utils/windisk/src/network.hxx b/private/utils/windisk/src/network.hxx
new file mode 100644
index 000000000..bc29c4fe1
--- /dev/null
+++ b/private/utils/windisk/src/network.hxx
@@ -0,0 +1,33 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: network.hxx
+//
+// Contents: The set of routines that support updating network
+// drive shares when adding and deleting drive letters.
+//
+// History: 12-26-94 Bob Rinne Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __NETWORK_HXX__
+#define __NETWORK_HXX__
+
+VOID
+NetworkInitialize(
+ VOID
+ );
+
+VOID
+NetworkShare(
+ IN LPCTSTR DriveLetter
+ );
+
+VOID
+NetworkRemoveShare(
+ IN LPCTSTR DriveLetter
+ );
+
+#endif __NETWORK_HXX__
diff --git a/private/utils/windisk/src/nt.cxx b/private/utils/windisk/src/nt.cxx
new file mode 100644
index 000000000..1fad4475f
--- /dev/null
+++ b/private/utils/windisk/src/nt.cxx
@@ -0,0 +1,1187 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: nt.cxx
+//
+// Contents: Functions that wrap fdisk partition engine functions,
+// including functions that manipulate fdisk engine structures
+// (REGIONs, for example).
+//
+// History: 5-Dec-92 TedM Created
+// 22-Jan-94 BobRi Misc cleanup
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include <string.h>
+#include <stdio.h>
+
+#include "nt.hxx"
+#include "ntlow.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+// Pagefile support structures.
+
+typedef struct _PAGEFILE_LOCATION
+{
+ struct _PAGEFILE_LOCATION* Next;
+ WCHAR DriveLetter;
+} PAGEFILE_LOCATION, *PPAGEFILE_LOCATION;
+
+PPAGEFILE_LOCATION PagefileHead = NULL;
+
+// For some reason the file systems don't like being accessed shortly after
+// a format or lock event.
+
+#define SLEEP_TIME (1000*2) // 2 seconds
+
+//
+// These partition ID's are for systems recognized by WINDISK,
+// even though they don't appear in ntdddisk.h.
+//
+#define PARTITION_OS2_BOOT 0xa
+#define PARTITION_EISA 0x12
+
+
+WCHAR SysIdName[100];
+
+PWSTR
+GetWideSysIDName(
+ IN UCHAR SysID
+ )
+{
+ DWORD stringId;
+
+ switch (SysID)
+ {
+ case PARTITION_ENTRY_UNUSED:
+ stringId = IDS_PARTITION_FREE;
+ break;
+
+ case PARTITION_XENIX_1:
+ stringId = IDS_PARTITION_XENIX1;
+ break;
+
+ case PARTITION_XENIX_2:
+ stringId = IDS_PARTITION_XENIX2;
+ break;
+
+ case PARTITION_OS2_BOOT:
+ stringId = IDS_PARTITION_OS2_BOOT;
+ break;
+
+ case PARTITION_EISA:
+ stringId = IDS_PARTITION_EISA;
+ break;
+
+ case PARTITION_UNIX:
+ stringId = IDS_PARTITION_UNIX;
+ break;
+
+ case PARTITION_PREP:
+#ifdef _PPC_
+ stringId = IDS_PARTITION_POWERPC;
+#else
+ // If not on a PPC platform, assume this is Eisa related
+ stringId = IDS_PARTITION_EISA;
+#endif
+ break;
+
+ default:
+ stringId = IDS_UNKNOWN;
+ break;
+ }
+
+ LoadString(
+ g_hInstance,
+ stringId,
+ SysIdName,
+ ARRAYLEN(SysIdName));
+
+ return SysIdName;
+}
+
+
+ULONG
+MyDiskRegistryGet(
+ OUT PDISK_REGISTRY *DiskRegistry
+ )
+
+/*++
+
+Routine Description:
+
+ Allocate memory for the size of the disk registry, obtain
+ the registry contents (if any) and return the pointer to the
+ allocated memory.
+
+Arguments:
+
+ A pointer to a disk registry pointer.
+
+Return Value:
+
+ status indicating success or failure.
+
+--*/
+
+{
+ ULONG length;
+ PDISK_REGISTRY diskRegistry;
+ NTSTATUS status;
+
+ while ( ((status = DiskRegistryGet(NULL, &length)) == STATUS_NO_MEMORY)
+ || (status == STATUS_INSUFFICIENT_RESOURCES))
+ {
+ ConfirmOutOfMemory();
+ }
+
+ if (!NT_SUCCESS(status))
+ {
+ return EC(status);
+ }
+
+ diskRegistry = (PDISK_REGISTRY)Malloc(length);
+
+ while ( ((status = DiskRegistryGet(diskRegistry, &length)) == STATUS_NO_MEMORY)
+ || (status == STATUS_INSUFFICIENT_RESOURCES))
+ {
+ ConfirmOutOfMemory();
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ LOG_DISK_REGISTRY("MyDiskRegistryGet", diskRegistry);
+
+ *DiskRegistry = diskRegistry;
+ }
+
+ return EC(status);
+}
+
+
+ULONG
+FormDiskSignature(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Return a ULONG disk signature. This is derived from the current
+ system time.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ A 32-bit signature
+
+--*/
+
+{
+ static ULONG baseSignature = 0;
+
+ LARGE_INTEGER time;
+
+ if (!baseSignature)
+ {
+ NtQuerySystemTime(&time);
+ time.QuadPart = time.QuadPart >> 16;
+ baseSignature = time.LowPart;
+ }
+ return baseSignature++;
+}
+
+
+BOOLEAN
+GetVolumeSizeMB(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ OUT PULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ Given a disk and a partition, query the "volume" to get its size.
+ By performing the query on the 1st partition of a potential FT set,
+ the total size of the set will be returned. If the partition isn't
+ an FT set, it will work too.
+
+Arguments:
+
+ Disk - the disk number
+ Partition - the partition number
+ Size - the size of the "volume"
+
+Return Value:
+
+ TRUE - a size was returned.
+ FALSE - something failed in getting the size.
+
+--*/
+
+{
+ BOOLEAN retValue = FALSE;
+ IO_STATUS_BLOCK statusBlock;
+ HANDLE handle;
+ STATUS_CODE sc;
+ PARTITION_INFORMATION partitionInfo;
+ LARGE_INTEGER partitionLength;
+
+ *Size = 0;
+ sc = LowOpenPartition(GetDiskName(Disk), Partition, &handle);
+ if (sc == OK_STATUS)
+ {
+ sc = NtDeviceIoControlFile(handle,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ IOCTL_DISK_GET_PARTITION_INFO,
+ NULL,
+ 0,
+ &partitionInfo,
+ sizeof(PARTITION_INFORMATION));
+
+ if (sc == OK_STATUS)
+ {
+ // Convert to MB
+
+ partitionLength.QuadPart = partitionInfo.PartitionLength.QuadPart >> 20;
+ *Size = partitionLength.LowPart;
+ retValue = TRUE;
+ }
+ LowCloseDisk(handle);
+ }
+ return retValue;
+}
+
+
+ULONG
+GetVolumeTypeAndSize(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ OUT PWSTR *Label,
+ OUT PWSTR *Type,
+ OUT PULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ Given a disk and partition number, determine its size, label and file
+ system type. This routine will allocate the space for label and file
+ system type. It is the responsibility of the caller to free this memory.
+
+Arguments:
+
+ Disk - the disk number
+ Partition - the partition number
+ Label - a pointer to a pointer for a WCHAR string to contain the label
+ Type - a pointer to a pointer for a WCHAR string to contain the file system
+ type.
+ Size - a pointer to a ULONG for the size of the disk in KB.
+
+Return Value:
+
+ OK_STATUS - everything was performed.
+ !OK_STATUS - the error code that was returned in the process of performing
+ this work.
+
+--*/
+
+{
+ IO_STATUS_BLOCK statusBlock;
+ HANDLE handle;
+ UCHAR buffer[256];
+ PWSTR label,
+ name;
+ ULONG length;
+ UINT oldErrorMode;
+ DISK_GEOMETRY diskGeometry;
+ STATUS_CODE sc;
+ BOOLEAN firstTime = TRUE;
+ PFILE_FS_VOLUME_INFORMATION labelInfo = (PFILE_FS_VOLUME_INFORMATION)buffer;
+ PFILE_FS_ATTRIBUTE_INFORMATION info = (PFILE_FS_ATTRIBUTE_INFORMATION)buffer;
+
+ while (1)
+ {
+ oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+ sc = LowOpenPartition(GetDiskName(Disk), Partition, &handle);
+ SetErrorMode(oldErrorMode);
+
+ if (sc == OK_STATUS)
+ {
+ sc = NtQueryVolumeInformationFile(handle,
+ &statusBlock,
+ buffer,
+ sizeof(buffer),
+ FileFsVolumeInformation);
+ if (sc == OK_STATUS)
+ {
+ length = labelInfo->VolumeLabelLength;
+ labelInfo->VolumeLabel[length/sizeof(WCHAR)] = 0;
+ length = (length+1) * sizeof(WCHAR);
+
+ label = (PWSTR)Malloc(length);
+ RtlMoveMemory(label, labelInfo->VolumeLabel, length);
+ }
+ else
+ {
+ label = (PWSTR)Malloc(sizeof(WCHAR));
+ *label = 0;
+ }
+ *Label = label;
+
+ if (sc == OK_STATUS)
+ {
+ sc = NtQueryVolumeInformationFile(handle,
+ &statusBlock,
+ buffer,
+ sizeof(buffer),
+ FileFsAttributeInformation);
+ if (sc == OK_STATUS)
+ {
+ length = info->FileSystemNameLength;
+ info->FileSystemName[length/sizeof(WCHAR)] = 0;
+ length = (length+1)*sizeof(WCHAR);
+ name = (PWSTR)Malloc(length);
+ RtlMoveMemory(name, info->FileSystemName, length);
+ }
+ else
+ {
+ name = (PWSTR)Malloc(sizeof(WCHAR));
+ *name = 0;
+ }
+ *Type = name;
+ }
+
+ if (sc == OK_STATUS)
+ {
+ sc = NtDeviceIoControlFile(handle,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ IOCTL_DISK_GET_DRIVE_GEOMETRY,
+ NULL,
+ 0,
+ (PVOID)&diskGeometry,
+ sizeof(diskGeometry));
+ if (NT_SUCCESS(sc))
+ {
+ LARGE_INTEGER sizeInBytes;
+ ULONG cylinderBytes;
+
+ cylinderBytes = diskGeometry.TracksPerCylinder *
+ diskGeometry.SectorsPerTrack *
+ diskGeometry.BytesPerSector;
+
+ sizeInBytes.QuadPart = diskGeometry.Cylinders.QuadPart * cylinderBytes;
+
+ // Now convert everything to KB
+
+ sizeInBytes.QuadPart = sizeInBytes.QuadPart >> 10;
+ *Size = (ULONG) sizeInBytes.LowPart;
+ }
+ }
+ DmClose(handle);
+ sc = OK_STATUS;
+ break;
+ }
+ else
+ {
+ if (firstTime)
+ {
+ firstTime = FALSE;
+ }
+ else
+ {
+ *Label = (PWSTR)Malloc(sizeof(WCHAR));
+ if (*Label) {
+
+ *((PWSTR)*Label) = 0;
+
+ }
+ *Type = (PWSTR)Malloc(sizeof(WCHAR));
+ if (*Type) {
+
+ *((PWSTR)*Type) = 0;
+
+ }
+ *Size = 0;
+ break;
+ }
+
+ Sleep(SLEEP_TIME);
+ }
+ }
+
+ return EC(sc);
+}
+
+
+
+ULONG
+GetVolumeLabel(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ OUT PWSTR *Label
+ )
+
+/*++
+
+Routine Description:
+
+ Given a disk number and a partition number return the volume label (if
+ any).
+
+Arguments:
+
+ Disk - the disk number
+ Partition - the partition number
+ Label - a pointer to a pointer for a WCHAR string to contain the label
+
+Return Value:
+
+ OK_STATUS - everything was performed.
+ !OK_STATUS - the error code that was returned in the process of performing
+ this work.
+--*/
+
+{
+ IO_STATUS_BLOCK status_block;
+ HANDLE handle;
+ STATUS_CODE sc;
+ BOOLEAN firstTime = TRUE;
+ unsigned char buffer[256];
+ PFILE_FS_VOLUME_INFORMATION LabelInfo = (PFILE_FS_VOLUME_INFORMATION)buffer;
+ PWSTR label;
+ ULONG length;
+
+ while (1)
+ {
+ sc = LowOpenPartition(GetDiskName(Disk), Partition, &handle);
+ if (sc == OK_STATUS)
+ {
+ sc = NtQueryVolumeInformationFile(handle,
+ &status_block,
+ buffer,
+ sizeof(buffer),
+ FileFsVolumeInformation);
+ DmClose(handle);
+
+ if (sc == OK_STATUS)
+ {
+ length = LabelInfo->VolumeLabelLength;
+
+ LabelInfo->VolumeLabel[length/sizeof(WCHAR)] = L'\0';
+
+ length = (length+1) * sizeof(WCHAR);
+
+ label = (PWSTR)Malloc(length);
+ RtlMoveMemory(label, LabelInfo->VolumeLabel, length);
+ }
+ else
+ {
+ label = (PWSTR)Malloc(sizeof(WCHAR));
+ sc = OK_STATUS;
+ *label = L'\0';
+ }
+
+ *Label = label;
+ break;
+ }
+ else
+ {
+ if (firstTime)
+ {
+ firstTime = FALSE;
+ }
+ else
+ {
+ *Label = NULL;
+ break;
+ }
+
+ Sleep(SLEEP_TIME);
+ }
+ }
+ return EC(sc);
+}
+
+
+ULONG
+GetTypeName(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ OUT PWSTR* Name
+ )
+
+/*++
+
+Routine Description:
+
+ Given a disk number and partition number return the file system type
+ string.
+
+Arguments:
+
+ Disk - the disk number
+ Partition - the partition number
+ Name - a pointer to a pointer for a WCHAR string to contain the file system
+ type.
+
+Return Value:
+
+ OK_STATUS - everything was performed.
+ !OK_STATUS - the error code that was returned in the process of performing
+ this work.
+--*/
+
+{
+ PWSTR name;
+ STATUS_CODE sc;
+ HANDLE handle;
+ UCHAR buffer[256];
+ BOOLEAN firstTime = TRUE;
+ PFILE_FS_ATTRIBUTE_INFORMATION info = (PFILE_FS_ATTRIBUTE_INFORMATION)buffer;
+ IO_STATUS_BLOCK status_block;
+ ULONG length;
+
+ // For some reason, the file systems believe they are locked or need
+ // to be verified after formats and the like. Therefore this is attempted
+ // twice before it actually gives up.
+
+ while (1)
+ {
+ sc = LowOpenPartition(GetDiskName(Disk), Partition, &handle);
+ if (sc == OK_STATUS)
+ {
+ sc = NtQueryVolumeInformationFile(handle,
+ &status_block,
+ buffer,
+ sizeof(buffer),
+ FileFsAttributeInformation);
+ DmClose(handle);
+
+ if (sc == OK_STATUS)
+ {
+ length = info->FileSystemNameLength;
+ info->FileSystemName[length/sizeof(WCHAR)] = L'\0';
+ length = (length+1)*sizeof(WCHAR);
+ name = (PWSTR)Malloc(length);
+ RtlMoveMemory(name, info->FileSystemName, length);
+ }
+ else
+ {
+ name = (PWSTR)Malloc(sizeof(WCHAR));
+ *name = L'\0';
+ sc = OK_STATUS;
+ }
+ *Name = name;
+ break;
+ }
+ else
+ {
+ if (firstTime)
+ {
+ firstTime = FALSE;
+ }
+ else
+ {
+ break;
+ }
+
+ Sleep(SLEEP_TIME);
+ }
+ }
+
+ return EC(sc);
+}
+
+
+ULONG
+GetSpaceInformation(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ OUT PLARGE_INTEGER FreeSpaceInBytes,
+ OUT PLARGE_INTEGER TotalSpaceInBytes
+ )
+{
+ STATUS_CODE sc;
+ HANDLE handle;
+ FILE_FS_SIZE_INFORMATION info;
+ IO_STATUS_BLOCK status_block;
+
+ TotalSpaceInBytes->QuadPart = FreeSpaceInBytes->QuadPart = 0;
+
+ sc = LowOpenPartition(GetDiskName(Disk), Partition, &handle);
+ if (sc == OK_STATUS)
+ {
+ sc = NtQueryVolumeInformationFile(handle,
+ &status_block,
+ &info,
+ sizeof(info),
+ FileFsSizeInformation);
+ NtClose(handle);
+
+ if (sc == OK_STATUS)
+ {
+ FreeSpaceInBytes->QuadPart =
+ info.AvailableAllocationUnits.QuadPart *
+ UInt32x32To64(info.SectorsPerAllocationUnit, info.BytesPerSector)
+ ;
+
+ TotalSpaceInBytes->QuadPart =
+ info.TotalAllocationUnits.QuadPart *
+ UInt32x32To64(info.SectorsPerAllocationUnit, info.BytesPerSector)
+ ;
+ }
+ }
+
+ return EC(sc);
+}
+
+
+
+BOOLEAN
+IsRemovable(
+ IN ULONG DiskNumber
+ )
+/*++
+
+Routine Description:
+
+ This function determines whether the specified physical
+ disk is removable.
+
+Arguments:
+
+ DiskNumber -- The Physical Disk Number of the disk in question.
+
+Return Value:
+
+ TRUE if the disk is removable.
+
+--*/
+{
+ STATUS_CODE sc;
+ NTSTATUS status;
+ HANDLE handle;
+ DISK_GEOMETRY diskGeometry;
+ IO_STATUS_BLOCK statusBlock;
+ BOOLEAN result = FALSE;
+ PCHAR name;
+
+ name = GetDiskName(DiskNumber);
+ sc = LowOpenDisk(name, &handle);
+
+ if (sc == OK_STATUS)
+ {
+ status = NtDeviceIoControlFile( handle,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ IOCTL_DISK_GET_DRIVE_GEOMETRY,
+ NULL,
+ 0,
+ (PVOID)&diskGeometry,
+ sizeof(diskGeometry));
+ LowCloseDisk(handle);
+
+ if (NT_SUCCESS(status))
+ {
+ if (diskGeometry.MediaType == RemovableMedia)
+ {
+ char ntDeviceName[100];
+
+ // Do a dismount/force mount sequence to make sure
+ // the media hasn't changed since last mount.
+ // Dismount partition 1 by lock/unlock/close.
+
+ sprintf(ntDeviceName, "%s\\Partition1", name);
+ status= LowOpenNtName(ntDeviceName, &handle);
+ if (NT_SUCCESS(status))
+ {
+ status = LowLockDrive(handle);
+ if (NT_SUCCESS(status)) {
+ LowUnlockDrive(handle);
+ LowCloseDisk(handle);
+
+ // Now force the mount by opening the device with a '\'
+ // This is done on partition 1 of the device.
+
+ sprintf(ntDeviceName, "%s\\Partition1\\", name);
+ status= LowOpenNtName(ntDeviceName, &handle);
+ if (NT_SUCCESS(status))
+ {
+ LowCloseDisk(handle);
+ }
+ }
+ }
+ result = TRUE;
+ }
+ } else if (status == STATUS_NO_MEDIA_IN_DEVICE) {
+
+ //
+ // This is a pretty good indication that this is a removable.
+ //
+
+ result = TRUE;
+
+ }
+ }
+
+ return result;
+}
+
+
+
+
+ULONG
+GetDriveLetterLinkTarget(
+ IN PWSTR SourceNameStr,
+ OUT PWSTR *LinkTarget
+ )
+{
+ static WCHAR targetNameBuffer[50];
+
+ NTSTATUS status;
+ UNICODE_STRING sourceName;
+ UNICODE_STRING targetName;
+ OBJECT_ATTRIBUTES oa;
+ HANDLE handle;
+
+
+ RtlInitUnicodeString(&sourceName, SourceNameStr);
+
+ InitializeObjectAttributes(&oa, &sourceName, OBJ_CASE_INSENSITIVE, NULL, NULL);
+
+ status = NtOpenSymbolicLinkObject(&handle, READ_CONTROL | SYMBOLIC_LINK_QUERY, &oa);
+
+ if (NT_SUCCESS(status))
+ {
+ RtlZeroMemory(targetNameBuffer, sizeof(targetNameBuffer));
+ targetName.Buffer = targetNameBuffer;
+ targetName.MaximumLength = sizeof(targetNameBuffer);
+
+ status = NtQuerySymbolicLinkObject(handle, &targetName, NULL);
+ NtClose(handle);
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ *LinkTarget = targetName.Buffer;
+ }
+ else
+ {
+ *LinkTarget = NULL;
+ }
+
+ return EC(status);
+}
+
+
+#include "bootmbr.h"
+
+#if X86BOOTCODE_SIZE < MBOOT_CODE_SIZE
+#error Something is wrong with the boot code (it's too small)!
+#endif
+
+ULONG
+MasterBootCode(
+ IN ULONG Disk,
+ IN ULONG Signature,
+ IN BOOLEAN SetBootCode,
+ IN BOOLEAN SetSignature
+ )
+
+/*++
+
+Routine Description:
+
+ If the zero sector of the disk does not have a valid MBR
+ signature (i.e. AA55), update it such that it has a valid
+ MBR and fill in the disk signature and bootcode in the
+ process.
+
+Arguments:
+
+ Disk - the disk ordinal to be affected
+ SetSignature - if TRUE update the disk signature
+ Signature - the disk signature for the update
+
+Return Value:
+
+ status
+
+--*/
+
+{
+ HANDLE handle;
+ STATUS_CODE status;
+ PCHAR diskName = GetDiskName(Disk);
+ PUCHAR unalignedSectorBuffer;
+ PUCHAR sectorBuffer;
+ ULONG bps;
+ ULONG dummy;
+ ULONG i;
+ BOOLEAN writeIt;
+
+ #ifndef max
+ #define max(a, b) (((a) > (b)) ? (a) : (b))
+ #endif
+
+ if (SetBootCode)
+ {
+ writeIt = FALSE;
+
+ // allocate sector buffer
+
+ status = LowGetDriveGeometry(diskName, &dummy, &bps, &dummy, &dummy);
+ if (status != OK_STATUS)
+ {
+ return EC(status);
+ }
+ if (bps < 512)
+ {
+ bps = 512;
+ }
+ unalignedSectorBuffer = (PUCHAR)Malloc(2*bps);
+ sectorBuffer = (PUCHAR)(((ULONG)unalignedSectorBuffer+bps) & ~(bps-1));
+
+ // open entire disk (partition 0)
+
+ if ((status = LowOpenDisk(diskName, &handle)) != OK_STATUS)
+ {
+ return EC(status);
+ }
+
+ // read (at least) first 512 bytes
+
+ status = LowReadSectors(handle, bps, 0, 1, sectorBuffer);
+ if (status == OK_STATUS)
+ {
+ if ( (sectorBuffer[MBOOT_SIG_OFFSET+0] != MBOOT_SIG1)
+ || (sectorBuffer[MBOOT_SIG_OFFSET+1] != MBOOT_SIG2))
+ {
+ // xfer boot code into sectorBuffer
+
+ for (i=0; i<MBOOT_CODE_SIZE; i++)
+ {
+ sectorBuffer[i] = x86BootCode[i];
+ }
+
+ // wipe partition table
+
+ for (i=MBOOT_CODE_SIZE; i<MBOOT_SIG_OFFSET; i++)
+ {
+ sectorBuffer[i] = 0;
+ }
+
+ // set the signature
+
+ sectorBuffer[MBOOT_SIG_OFFSET+0] = MBOOT_SIG1;
+ sectorBuffer[MBOOT_SIG_OFFSET+1] = MBOOT_SIG2;
+
+ writeIt = TRUE;
+ }
+
+ if (writeIt)
+ {
+ status = LowWriteSectors(handle, bps, 0, 1, sectorBuffer);
+ }
+ }
+
+ LowCloseDisk(handle);
+
+ Free(unalignedSectorBuffer);
+ }
+
+ if (SetSignature)
+ {
+ PDRIVE_LAYOUT_INFORMATION layout;
+
+ // Use the IOCTL to set the signature. This code really does
+ // not know where the MBR exists. (ezDrive extensions).
+
+ status = LowGetDiskLayout(diskName, &layout);
+
+ if (status == OK_STATUS)
+ {
+ layout->Signature = Signature;
+ LowSetDiskLayout(diskName, layout);
+ }
+ }
+
+ return EC(status);
+}
+
+
+ULONG
+UpdateMasterBootCode(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ This routine updates the zero sector of the disk to insure that boot
+ code is present.
+
+Arguments:
+
+ Disk - the disk number onto which to put the boot code.
+
+Return Value:
+
+ status
+
+--*/
+
+{
+ HANDLE handle;
+ STATUS_CODE status;
+ PUCHAR unalignedSectorBuffer,
+ sectorBuffer;
+ ULONG bps,
+ dummy,
+ i;
+ PCHAR diskName = GetDiskName(Disk);
+
+#ifndef max
+#define max(a,b) ((a > b) ? a : b)
+#endif
+
+ // allocate sector buffer
+
+ status = LowGetDriveGeometry(diskName, &dummy, &bps, &dummy, &dummy);
+ if (status != OK_STATUS)
+ {
+ return EC(status);
+ }
+ if (bps < 512)
+ {
+ bps = 512;
+ }
+ unalignedSectorBuffer = (PUCHAR)Malloc(2*bps);
+ sectorBuffer = (PUCHAR)(((ULONG)unalignedSectorBuffer+bps) & ~(bps-1));
+
+ // open entire disk (partition 0)
+
+ if ((status = LowOpenDisk(diskName, &handle)) != OK_STATUS)
+ {
+ return EC(status);
+ }
+
+ // read (at least) first 512 bytes
+
+ status = LowReadSectors(handle, bps, 0, 1, sectorBuffer);
+ if (status == OK_STATUS)
+ {
+ // xfer boot code into sectorBuffer. This avoids changing the
+ // disk signature and the partition table information.
+
+ for (i=0; i<MBOOT_CODE_SIZE; i++)
+ {
+ sectorBuffer[i] = x86BootCode[i];
+ }
+
+ status = LowWriteSectors(handle, bps, 0, 1, sectorBuffer);
+ }
+
+ LowCloseDisk(handle);
+
+ // free the sector buffer
+
+ Free(unalignedSectorBuffer);
+ return EC(status);
+}
+
+
+
+VOID
+MakePartitionActive(
+ IN PREGION_DESCRIPTOR DiskRegionArray,
+ IN ULONG RegionCount,
+ IN ULONG RegionIndex
+ )
+
+/*++
+
+Routine Description:
+
+ Update the information in the internal structures to indicate
+ that the specified partition is active.
+
+Arguments:
+
+ DiskRegionArray
+ RegionCount
+ RegionIndex
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ unsigned i;
+
+ for (i=0; i<RegionCount; i++)
+ {
+ if (DiskRegionArray[i].RegionType == REGION_PRIMARY)
+ {
+ DiskRegionArray[i].Active = FALSE;
+ SetPartitionActiveFlag(&DiskRegionArray[i], FALSE);
+ }
+ }
+ DiskRegionArray[RegionIndex].Active = (BOOLEAN)0x80;
+ SetPartitionActiveFlag(&DiskRegionArray[RegionIndex], 0x80);
+}
+
+
+VOID
+LoadExistingPageFileInfo(
+ IN VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine finds all pagefiles in the system and updates the internal
+ structures.
+
+Arguments:
+
+ None
+
+Return Values:
+
+ None
+
+--*/
+
+{
+ NTSTATUS status;
+ SYSTEM_INFO sysInfo;
+ UCHAR genericBuffer[0x10000];
+ PSYSTEM_PAGEFILE_INFORMATION pageFileInfo;
+ ANSI_STRING ansiPageFileName;
+ PPAGEFILE_LOCATION pageFileListEntry;
+ PCHAR p;
+
+ GetSystemInfo(&sysInfo);
+
+ status = NtQuerySystemInformation(SystemPageFileInformation,
+ genericBuffer,
+ sizeof(genericBuffer),
+ NULL);
+ if (!NT_SUCCESS(status))
+ {
+ // It's possible that this call will fail if the
+ // the system is running without ANY paging files.
+
+ return;
+ }
+
+ pageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION) genericBuffer;
+
+ for (;;)
+ {
+ RtlUnicodeStringToAnsiString(&ansiPageFileName,
+ &pageFileInfo->PageFileName,
+ TRUE);
+
+ // Since the format of the pagefile name generally
+ // looks something like "\DosDevices\h:\pagefile.sys",
+ // just use the first character before the colon
+ // and assume that's the drive letter.
+
+ p = strchr(_strlwr(ansiPageFileName.Buffer), ':');
+
+ if ((p-- != NULL) && (*p >= 'a') && (*p <= 'z'))
+ {
+ pageFileListEntry = (PPAGEFILE_LOCATION)Malloc(sizeof(PAGEFILE_LOCATION));
+ if (NULL != pageFileListEntry)
+ {
+ if (NULL != PagefileHead)
+ {
+ pageFileListEntry->Next = PagefileHead;
+ }
+ else
+ {
+ PagefileHead = pageFileListEntry;
+ pageFileListEntry->Next = NULL;
+ }
+ pageFileListEntry->DriveLetter = (WCHAR)(*p);
+ }
+ }
+
+ RtlFreeAnsiString(&ansiPageFileName);
+
+ if (pageFileInfo->NextEntryOffset == 0)
+ {
+ break;
+ }
+
+ pageFileInfo = (PSYSTEM_PAGEFILE_INFORMATION)((PCHAR) pageFileInfo
+ + pageFileInfo->NextEntryOffset);
+ }
+}
+
+BOOLEAN
+IsPagefileOnDrive(
+ WCHAR DriveLetter
+ )
+
+/*++
+
+Routine Description:
+
+ Walk the page file list and determine if the drive letter given has
+ a paging file. NOTE: The assumption is that drive letters that
+ contain paging files can never get changed during the execution of
+ Disk Administrator. Therefore this list is never updated, but
+ can be used during the execution of Disk Administrator.
+
+Arguments:
+
+ DriveLetter - the drive in question.
+
+Return Value:
+
+ TRUE if this drive contains a page file.
+
+--*/
+
+{
+ PPAGEFILE_LOCATION pageFileListEntry = PagefileHead;
+
+ while (NULL != pageFileListEntry)
+ {
+ if (pageFileListEntry->DriveLetter == DriveLetter)
+ {
+ return TRUE;
+ }
+ pageFileListEntry = pageFileListEntry->Next;
+ }
+ return FALSE;
+}
diff --git a/private/utils/windisk/src/nt.hxx b/private/utils/windisk/src/nt.hxx
new file mode 100644
index 000000000..8ff8c2c84
--- /dev/null
+++ b/private/utils/windisk/src/nt.hxx
@@ -0,0 +1,115 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: nt.hxx
+//
+// Contents: Delcarations for functions that wrap fdisk partition engine
+// functions
+//
+// History: 5-Dec-92 TedM Created
+// 22-Jan-94 BobRi Misc cleanup
+//
+//----------------------------------------------------------------------------
+
+#ifndef __NT_HXX__
+#define __NT_HXX__
+
+//////////////////////////////////////////////////////////////////////////////
+
+ULONG
+GetVolumeTypeAndSize(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ OUT PWSTR *Label,
+ OUT PWSTR *Type,
+ OUT PULONG Size
+ );
+
+PWSTR
+GetWideSysIDName(
+ IN UCHAR SysID
+ );
+
+ULONG
+MyDiskRegistryGet(
+ OUT PDISK_REGISTRY *DiskRegistry
+ );
+
+ULONG
+MasterBootCode(
+ IN ULONG Disk,
+ IN ULONG Signature,
+ IN BOOLEAN SetBootCode,
+ IN BOOLEAN SetSignature
+ );
+
+ULONG
+FormDiskSignature(
+ VOID
+ );
+
+BOOLEAN
+GetVolumeSizeMB(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ OUT PULONG Size
+ );
+
+ULONG
+GetVolumeLabel(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ OUT PWSTR *Label
+ );
+
+ULONG
+GetTypeName(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ OUT PWSTR *Name
+ );
+
+ULONG
+GetSpaceInformation(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ OUT PLARGE_INTEGER FreeSpaceInBytes,
+ OUT PLARGE_INTEGER TotalSpaceInBytes
+ );
+
+BOOLEAN
+IsRemovable(
+ IN ULONG DiskNumber
+ );
+
+ULONG
+GetDriveLetterLinkTarget(
+ IN PWSTR SourceNameStr,
+ OUT PWSTR *LinkTarget
+ );
+
+ULONG
+UpdateMasterBootCode(
+ IN ULONG Disk
+ );
+
+VOID
+MakePartitionActive(
+ IN PREGION_DESCRIPTOR DiskRegionArray,
+ IN ULONG RegionCount,
+ IN ULONG RegionIndex
+ );
+
+BOOLEAN
+IsPagefileOnDrive(
+ WCHAR DriveLetter
+ );
+
+VOID
+LoadExistingPageFileInfo(
+ IN VOID
+ );
+
+#endif // __NT_HXX__
diff --git a/private/utils/windisk/src/ntlow.cxx b/private/utils/windisk/src/ntlow.cxx
new file mode 100644
index 000000000..48e326052
--- /dev/null
+++ b/private/utils/windisk/src/ntlow.cxx
@@ -0,0 +1,1134 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: ntlow.cxx
+//
+// Contents: Low-level I/O routines, implemented to run on NT.
+//
+// History: 8-Nov-91 TedM Created
+// 2-Feb-94 BobRi Dynamic partitioning changes
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include <stdio.h>
+#include <string.h>
+
+#include "engine.hxx"
+#include "ntlow.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+STATUS_CODE
+LowQueryFdiskPathList(
+ OUT PCHAR** PathList,
+ OUT PULONG ListLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine determines how many drives are present in the
+ system and returns a list of Ascii strings for the names of
+ each of the drives found.
+
+ When a drive is located, a check is made to insure that the
+ associated DosName for the physical drive is also present in
+ the system.
+
+Arguments:
+
+ PathList - pointer to a pointer for the list
+ ListLength - the number of entries returned in the list
+
+Return Value:
+
+ Error status if there is a problem.
+
+--*/
+
+{
+ HANDLE dummyHandle;
+ STATUS_CODE status;
+ ULONG count = 0;
+ ULONG i;
+ char buffer[100];
+ PCHAR* pathArray;
+ UINT errorMode;
+
+ errorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+ while (1)
+ {
+ sprintf(buffer,"\\Device\\Harddisk%u",count);
+
+ status = LowOpenDisk(buffer, &dummyHandle);
+
+ //
+ // Only STATUS_OBJECT_PATH_NOT_FOUND can terminate the count.
+ //
+
+ if (NT_SUCCESS(status))
+ {
+ char dosNameBuffer[80];
+
+ LowCloseDisk(dummyHandle);
+
+ // Insure that the physicaldrive name is present
+
+ sprintf(dosNameBuffer, "\\dosdevices\\PhysicalDrive%u", count);
+ status = LowOpenNtName(dosNameBuffer, &dummyHandle);
+ if (NT_SUCCESS(status))
+ {
+ LowCloseDisk(dummyHandle);
+ }
+ else
+ {
+ // Not there, create it.
+
+ char devicePath[50];
+ wsprintfA(devicePath, "\\Device\\Harddisk%u\\Partition0", count);
+ DefineDosDeviceA(DDD_RAW_TARGET_PATH, dosNameBuffer, devicePath);
+ }
+ }
+ else if (status == STATUS_OBJECT_PATH_NOT_FOUND)
+ {
+ break;
+ }
+ else if (status == STATUS_ACCESS_DENIED)
+ {
+ SetErrorMode(errorMode);
+ return status;
+ }
+
+ count++;
+ }
+
+ pathArray = (PCHAR*)Malloc(count * sizeof(PCHAR));
+
+ for (i=0; i<count; i++)
+ {
+ sprintf(buffer,"\\Device\\Harddisk%u",i);
+
+ pathArray[i] = (PCHAR)Malloc(lstrlenA(buffer)+1);
+
+ strcpy(pathArray[i], buffer);
+ }
+
+ *PathList = pathArray;
+ *ListLength = count;
+
+ SetErrorMode(errorMode);
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+LowFreeFdiskPathList(
+ IN OUT PCHAR* PathList,
+ IN ULONG ListLength
+ )
+
+/*++
+
+Routine Description:
+
+ Walk the provided list up to its length and free the memory
+ allocated. Upon completion, free the memory for the list
+ itself.
+
+Arguments:
+
+ PathList - pointer to base of path list
+ ListLength - number of entries in the list
+
+Return Value:
+
+ Always OK_STATUS
+
+--*/
+
+{
+ ULONG i;
+
+ for (i=0; i<ListLength; i++)
+ {
+ FreeMemory(PathList[i]);
+ }
+ FreeMemory(PathList);
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+LowOpenNtName(
+ IN PCHAR Name,
+ IN HANDLE_PT Handle
+ )
+
+/*++
+
+Routine Description:
+
+ This is an internal "Low" routine to handle open requests.
+
+Arguments:
+
+ Name - pointer to the NT name for the open.
+ Handle - pointer for the handle returned.
+
+Return Value:
+
+ NT status
+
+--*/
+
+{
+ OBJECT_ATTRIBUTES oa;
+ NTSTATUS status;
+ IO_STATUS_BLOCK statusBlock;
+ ANSI_STRING ansiName;
+ UNICODE_STRING unicodeName;
+
+ RtlInitAnsiString(&ansiName, Name);
+ status = RtlAnsiStringToUnicodeString(&unicodeName, &ansiName, TRUE);
+
+ if (!NT_SUCCESS(status))
+ {
+ return status;
+ }
+
+ memset(&oa, 0, sizeof(OBJECT_ATTRIBUTES));
+ oa.Length = sizeof(OBJECT_ATTRIBUTES);
+ oa.ObjectName = &unicodeName;
+ oa.Attributes = OBJ_CASE_INSENSITIVE;
+
+ status = DmOpenFile(Handle,
+ SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
+ &oa,
+ &statusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT);
+
+ if (!NT_SUCCESS(status))
+ {
+ FDLOG((1,"LowOpen: 1st open failed with 0x%x\n", status));
+
+ // try a 2nd time to get around an FS glitch or a test
+ // bug where this doesn't work on an attempt to delete a
+ // partition
+
+ Sleep(500);
+ status = DmOpenFile(Handle,
+ SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
+ &oa,
+ &statusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ FILE_SYNCHRONOUS_IO_ALERT);
+ FDLOG((1,"LowOpen: 2nd open 0x%x\n", status));
+ }
+
+ RtlFreeUnicodeString(&unicodeName);
+ return status;
+}
+
+
+STATUS_CODE
+LowOpenDriveLetter(
+ IN WCHAR DriveLetter,
+ IN HANDLE_PT Handle
+ )
+
+/*++
+
+Routine Description:
+
+ Given a drive letter, open it and return a handle.
+
+Arguments:
+
+ DriveLetter - the letter to open
+ Handle - a pointer to a handle
+
+Return Value:
+
+ NT status
+
+--*/
+
+{
+ char ntDeviceName[100];
+
+ sprintf(ntDeviceName, "\\DosDevices\\%c:", (CHAR)DriveLetter);
+ return LowOpenNtName(ntDeviceName, Handle);
+}
+
+
+STATUS_CODE
+LowOpenPartition(
+ IN PCHAR DevicePath,
+ IN ULONG Partition,
+ OUT HANDLE_PT Handle
+ )
+
+/*++
+
+Routine Description:
+
+ Construct the NT device name for the Partition value given
+ and perform the NT APIs to open the device.
+
+Arguments:
+
+ DevicePath - the string to the device without the partition
+ portion of the name. This is constructed using
+ the Partition value passed
+ Partition - the partion desired
+ Handle - pointer to a handle pointer for the result
+
+Return Value:
+
+ NT status
+
+--*/
+
+{
+ char ntDeviceName[100];
+
+ sprintf(ntDeviceName, "%s\\partition%u", DevicePath, Partition);
+ return LowOpenNtName(ntDeviceName, Handle);
+}
+
+
+STATUS_CODE
+LowOpenDisk(
+ IN PCHAR DevicePath,
+ OUT HANDLE_PT DiskId
+ )
+
+/*++
+
+Routine Description:
+
+ Perform the NT actions to open a device.
+
+Arguments:
+
+ DevicePath - Ascii device name
+ DiskId - pointer to a handle pointer for the returned
+ handle value
+
+Return Value:
+
+ NT status
+
+--*/
+
+{
+ return LowOpenPartition(DevicePath, 0, DiskId);
+}
+
+
+
+STATUS_CODE
+LowCloseDisk(
+ IN HANDLE_T DiskId
+ )
+
+/*++
+
+Routine Description:
+
+ Close a disk handle.
+
+Arguments:
+
+ DiskId - the actual NT handle
+
+Return Value:
+
+ NT status
+
+--*/
+
+{
+ return DmClose(DiskId);
+}
+
+
+STATUS_CODE
+LowLockDrive(
+ IN HANDLE_T DiskId
+ )
+
+/*++
+
+Routine Description:
+
+ Perform the NT API to cause a volume to be locked.
+ This is a File System device control.
+
+Arguments:
+
+ DiskId - the actual NT handle to the drive
+
+Return Value:
+
+ NT status
+
+--*/
+
+{
+ NTSTATUS status;
+ IO_STATUS_BLOCK statusBlock;
+
+ status = NtFsControlFile(DiskId,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ FSCTL_LOCK_VOLUME,
+ NULL,
+ 0,
+ NULL,
+ 0);
+
+ if (!NT_SUCCESS(status))
+ {
+ FDLOG((1, "LowLock: failed with 0x%x\n", status));
+ }
+
+ return status;
+}
+
+
+STATUS_CODE
+LowUnlockDrive(
+ IN HANDLE_T DiskId
+ )
+
+/*++
+
+Routine Description:
+
+ Perform the NT API to cause a volume to be unlocked.
+ This is a File System device control.
+
+Arguments:
+
+ DiskId - the actual NT handle to the drive
+
+Return Value:
+
+ NT status
+
+--*/
+
+{
+ NTSTATUS status;
+ IO_STATUS_BLOCK statusBlock;
+
+ status = NtFsControlFile(DiskId,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ FSCTL_DISMOUNT_VOLUME,
+ NULL,
+ 0,
+ NULL,
+ 0);
+
+ status = NtFsControlFile(DiskId,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ FSCTL_UNLOCK_VOLUME,
+ NULL,
+ 0,
+ NULL,
+ 0);
+ return status;
+}
+
+
+
+STATUS_CODE
+LowGetDriveGeometry(
+ IN PCHAR Path,
+ OUT PULONG TotalSectorCount,
+ OUT PULONG SectorSize,
+ OUT PULONG SectorsPerTrack,
+ OUT PULONG Heads
+ )
+
+/*++
+
+Routine Description:
+
+ Routine collects information concerning the geometry
+ of a specific drive.
+
+Arguments:
+
+ Path - Ascii path name to get to disk object
+ this is not a full path, but rather
+ a path without the Partition indicator
+ \device\harddiskX
+ TotalSectorCount- pointer to ULONG for result
+ SectorSize - pointer to ULONG for result
+ SectorsPerTrack - pointer to ULONG for result
+ Heads - pointer to ULONG for result
+
+Return Value:
+
+ NT status
+
+--*/
+
+{
+ IO_STATUS_BLOCK statusBlock;
+ DISK_GEOMETRY diskGeometry;
+ STATUS_CODE status;
+ HANDLE handle;
+
+ if ((status = LowOpenDisk(Path, &handle)) != OK_STATUS)
+ {
+ return status;
+ }
+
+ status = NtDeviceIoControlFile(handle,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ IOCTL_DISK_GET_DRIVE_GEOMETRY,
+ NULL,
+ 0,
+ &diskGeometry,
+ sizeof(DISK_GEOMETRY));
+ if (!NT_SUCCESS(status))
+ {
+ return (STATUS_CODE)status;
+ }
+ LowCloseDisk(handle);
+
+ *SectorSize = diskGeometry.BytesPerSector;
+ *SectorsPerTrack = diskGeometry.SectorsPerTrack;
+ *Heads = diskGeometry.TracksPerCylinder;
+ *TotalSectorCount = (RtlExtendedIntegerMultiply(
+ diskGeometry.Cylinders,
+ (*SectorsPerTrack) * (*Heads))).LowPart;
+ return OK_STATUS;
+}
+
+
+
+STATUS_CODE
+LowGetDiskLayout(
+ IN PCHAR Path,
+ OUT PDRIVE_LAYOUT_INFORMATION* DriveLayout
+ )
+
+/*++
+
+Routine Description:
+
+ Perform the necessary NT API calls to get the drive
+ layout from the disk and return it in a memory buffer
+ allocated by this routine.
+
+Arguments:
+
+ Path - Ascii path name to get to disk object
+ this is not a full path, but rather
+ a path without the Partition indicator
+ \device\harddiskX
+
+ DriveLayout - pointer to pointer for the drive layout result
+
+Return Value:
+
+ NT status
+
+--*/
+
+{
+ PDRIVE_LAYOUT_INFORMATION layout;
+ IO_STATUS_BLOCK statusBlock;
+ STATUS_CODE status;
+ ULONG bufferSize;
+ HANDLE handle;
+
+ bufferSize = sizeof(DRIVE_LAYOUT_INFORMATION)
+ + (500 * sizeof(PARTITION_INFORMATION));
+
+ layout = (PDRIVE_LAYOUT_INFORMATION)AllocateMemory(bufferSize);
+ if (NULL == layout)
+ {
+ RETURN_OUT_OF_MEMORY;
+ }
+
+ if ((status = LowOpenDisk(Path, &handle)) != OK_STATUS)
+ {
+ FreeMemory(layout);
+ return status;
+ }
+
+ status = NtDeviceIoControlFile(handle,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ IOCTL_DISK_GET_DRIVE_LAYOUT,
+ NULL,
+ 0,
+ layout,
+ bufferSize);
+ LowCloseDisk(handle);
+
+ if (!NT_SUCCESS(status))
+ {
+ if (status == STATUS_BAD_MASTER_BOOT_RECORD)
+ {
+ FDLOG((1,"LowGetDiskLayout: Disk device %s has bad MBR\n",Path));
+
+ // Zero the drive layout information for the fdengine to process.
+
+ RtlZeroMemory(layout, bufferSize);
+ }
+ else
+ {
+ FDLOG((0,"LowGetDiskLayout: Status %lx getting layout for disk device %s\n",status,Path));
+ FreeMemory(layout);
+ return status;
+ }
+ }
+ else
+ {
+
+ FDLOG((2,"LowGetDiskLayout: layout received from ioctl for %s follows:\n",Path));
+ LOG_DRIVE_LAYOUT(layout);
+ }
+
+ // Check to insure that the drive supports dynamic partitioning
+
+ *DriveLayout = layout;
+ return OK_STATUS;
+}
+
+
+STATUS_CODE
+LowSetDiskLayout(
+ IN PCHAR Path,
+ IN PDRIVE_LAYOUT_INFORMATION DriveLayout
+ )
+
+/*++
+
+Routine Description:
+
+ Perform the NT API actions of opening Partition0 for
+ the specified drive and setting the drive layout.
+
+Arguments:
+
+ Path - Ascii path name to get to disk object
+ this is not a full path, but rather
+ a path without the Partition indicator
+ \device\harddiskX
+
+ DriveLayout - new layout to set
+
+Return Value:
+
+ NT status
+
+--*/
+
+{
+ IO_STATUS_BLOCK statusBlock;
+ STATUS_CODE status;
+ HANDLE handle;
+ ULONG bufferSize;
+
+ if ((status = LowOpenDisk(Path, &handle)) != OK_STATUS)
+ {
+ return status;
+ }
+ else
+ {
+ FDLOG((2, "LowSetDiskLayout: calling ioctl for %s, layout follows:\n", Path));
+ LOG_DRIVE_LAYOUT(DriveLayout);
+ }
+
+ bufferSize = sizeof(DRIVE_LAYOUT_INFORMATION)
+ + ( (DriveLayout->PartitionCount - 1)
+ * sizeof(PARTITION_INFORMATION));
+ status = NtDeviceIoControlFile(handle,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ IOCTL_DISK_SET_DRIVE_LAYOUT,
+ DriveLayout,
+ bufferSize,
+ DriveLayout,
+ bufferSize);
+ LowCloseDisk(handle);
+ return status;
+}
+
+
+STATUS_CODE
+LowWriteSectors(
+ IN HANDLE_T VolumeId,
+ IN ULONG SectorSize,
+ IN ULONG StartingSector,
+ IN ULONG NumberOfSectors,
+ IN PVOID Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ Routine to write to a volume handle. This routine
+ insulates the NT issues concerning the call from the
+ caller.
+
+Arguments:
+
+ VolumeId - actually the NT handle.
+ SectorSize - used to calculate starting byte offset for I/O
+ StartingSector - starting sector for write.
+ NumberOfSectors - size of I/O in sectors
+ Buffer - the location for the data
+
+Return Value:
+
+ Standard NT status values
+
+--*/
+
+{
+ IO_STATUS_BLOCK statusBlock;
+ LARGE_INTEGER byteOffset;
+
+ byteOffset.QuadPart = UInt32x32To64(StartingSector, SectorSize);
+
+ statusBlock.Status = 0;
+ statusBlock.Information = 0;
+ return NtWriteFile(VolumeId,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ Buffer,
+ NumberOfSectors * SectorSize,
+ &byteOffset,
+ NULL);
+}
+
+
+STATUS_CODE
+LowReadSectors(
+ IN HANDLE_T VolumeId,
+ IN ULONG SectorSize,
+ IN ULONG StartingSector,
+ IN ULONG NumberOfSectors,
+ IN PVOID Buffer
+ )
+
+/*++
+
+Routine Description:
+
+ Routine to read from a volume handle. This routine
+ insulates the NT issues concerning the call from the
+ caller.
+
+Arguments:
+
+ VolumeId - actually the NT handle.
+ SectorSize - used to calculate starting byte offset for I/O
+ StartingSector - starting sector for write.
+ NumberOfSectors - size of I/O in sectors
+ Buffer - the location for the data
+
+Return Value:
+
+ Standard NT status values
+
+--*/
+
+{
+ IO_STATUS_BLOCK statusBlock;
+ LARGE_INTEGER byteOffset;
+
+ byteOffset.QuadPart = UInt32x32To64(StartingSector, SectorSize);
+
+ statusBlock.Status = 0;
+ statusBlock.Information = 0;
+ return NtReadFile(VolumeId,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ Buffer,
+ NumberOfSectors * SectorSize,
+ &byteOffset,
+ NULL);
+}
+
+
+STATUS_CODE
+LowFtVolumeStatus(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ IN PFT_SET_STATUS FtStatus,
+ IN PULONG NumberOfMembers
+ )
+
+/*++
+
+Routine Description:
+
+ Open the requested partition and query the FT state.
+
+Arguments:
+
+ DriveLetter - the letter for the current state
+ FtState - a pointer to a location to return state
+ NumberOfMembers - a pointer to a ULONG for number of members
+ in the FT set.
+
+Return Value:
+
+ Standard NT status values
+
+--*/
+
+{
+ HANDLE handle;
+ STATUS_CODE status;
+ IO_STATUS_BLOCK statusBlock;
+ FT_SET_INFORMATION setInfo;
+
+ status = LowOpenPartition(GetDiskName(Disk),
+ Partition,
+ &handle);
+
+ if (status == OK_STATUS)
+ {
+ status = NtDeviceIoControlFile(handle,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ FT_QUERY_SET_STATE,
+ NULL,
+ 0,
+ &setInfo,
+ sizeof(setInfo));
+ LowCloseDisk(handle);
+
+ if (status == OK_STATUS)
+ {
+ switch (setInfo.SetState)
+ {
+ case FtStateOk:
+ *FtStatus = FtSetHealthy;
+ break;
+
+ case FtHasOrphan:
+ switch (setInfo.Type)
+ {
+ case Mirror:
+ *FtStatus = FtSetBroken;
+ break;
+ case StripeWithParity:
+ *FtStatus = FtSetRecoverable;
+ break;
+ }
+ break;
+
+ case FtRegenerating:
+ *FtStatus = FtSetRegenerating;
+ break;
+
+ case FtCheckParity:
+ *FtStatus = FtSetInitializationFailed;
+ break;
+
+ case FtInitializing:
+ *FtStatus = FtSetInitializing;
+ break;
+
+ case FtDisabled:
+
+ // This will never happen.
+
+ *FtStatus = FtSetDisabled;
+ break;
+
+ case FtNoCheckData:
+ default:
+
+ // BUGBUG: there is no mapping here.
+
+ *FtStatus = FtSetHealthy;
+ break;
+ }
+ *NumberOfMembers = setInfo.NumberOfMembers;
+ }
+ }
+ else
+ {
+ // If the FT set could not be opened, then it must be
+ // disabled if the return code is "No such device".
+
+ if (status == 0xc000000e)
+ {
+ *FtStatus = FtSetDisabled;
+ status = OK_STATUS;
+ }
+ }
+
+ // Always update the state to the caller.
+
+ return status;
+}
+
+
+STATUS_CODE
+LowFtVolumeStatusByLetter(
+ IN CHAR DriveLetter,
+ IN PFT_SET_STATUS FtStatus,
+ IN PULONG NumberOfMembers
+ )
+
+/*++
+
+Routine Description:
+
+ Open the requested drive letter and query the FT state.
+
+Arguments:
+
+ DriveLetter - the letter for the current state
+ FtState - a pointer to a location to return state
+ NumberOfMembers - a pointer to a ULONG for number of members
+ in the FT set.
+
+Return Value:
+
+ Standard NT status values
+
+--*/
+
+{
+ HANDLE handle;
+ STATUS_CODE status;
+ IO_STATUS_BLOCK statusBlock;
+ FT_SET_INFORMATION setInfo;
+
+ *NumberOfMembers = 1;
+ status = LowOpenDriveLetter(DriveLetter,
+ &handle);
+
+ if (status == OK_STATUS)
+ {
+ status = NtDeviceIoControlFile(handle,
+ 0,
+ NULL,
+ NULL,
+ &statusBlock,
+ FT_QUERY_SET_STATE,
+ NULL,
+ 0,
+ &setInfo,
+ sizeof(setInfo));
+ LowCloseDisk(handle);
+
+ if (status == OK_STATUS)
+ {
+ switch (setInfo.SetState)
+ {
+ case FtStateOk:
+ *FtStatus = FtSetHealthy;
+ break;
+
+ case FtHasOrphan:
+ switch (setInfo.Type)
+ {
+ case Mirror:
+ *FtStatus = FtSetBroken;
+ break;
+ case StripeWithParity:
+ *FtStatus = FtSetRecoverable;
+ break;
+ }
+ break;
+
+ case FtRegenerating:
+ *FtStatus = FtSetRegenerating;
+ break;
+
+ case FtCheckParity:
+ *FtStatus = FtSetInitializationFailed;
+ break;
+
+ case FtInitializing:
+ *FtStatus = FtSetInitializing;
+ break;
+
+ case FtDisabled:
+
+ // This will never happen.
+
+ *FtStatus = FtSetDisabled;
+ break;
+
+ case FtNoCheckData:
+ default:
+
+ // BUGBUG: there is no mapping here.
+
+ *FtStatus = FtSetHealthy;
+ break;
+ }
+ *NumberOfMembers = setInfo.NumberOfMembers;
+ }
+ }
+ else
+ {
+ // If the FT set could not be opened, then it must be
+ // disabled if the return code is "No such device".
+
+ if (status == 0xc000000e)
+ {
+ *FtStatus = FtSetDisabled;
+ status = OK_STATUS;
+ }
+ }
+
+ // Always update the state to the caller.
+
+ return status;
+}
+
+#if DBG == 1
+
+#define NUMBER_OF_HANDLES_TRACKED 500
+HANDLE OpenHandleArray[NUMBER_OF_HANDLES_TRACKED];
+BOOLEAN DmFirstTime = TRUE;
+ULONG HandleHighWaterMark = 0;
+
+NTSTATUS
+DmOpenFile(
+ OUT PHANDLE FileHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ IN ULONG ShareAccess,
+ IN ULONG OpenOptions
+ )
+
+/*++
+
+Routine Description:
+
+ A debugging aid to track open and closes of partitions.
+
+Arguments:
+
+ Same as for NtOpenFile()
+
+Return Value:
+
+ Same as for NtOpenFile()
+
+--*/
+
+{
+ ULONG index;
+ NTSTATUS status;
+
+ if (DmFirstTime)
+ {
+ DmFirstTime = FALSE;
+ for (index = 0; index < NUMBER_OF_HANDLES_TRACKED; index++)
+ {
+ OpenHandleArray[index] = (HANDLE) 0;
+ }
+ }
+
+ status = NtOpenFile(FileHandle,
+ DesiredAccess,
+ ObjectAttributes,
+ IoStatusBlock,
+ ShareAccess,
+ OpenOptions);
+ if (NT_SUCCESS(status))
+ {
+ for (index = 0; index < NUMBER_OF_HANDLES_TRACKED; index++)
+ {
+ if (OpenHandleArray[index] == (HANDLE) 0)
+ {
+ OpenHandleArray[index] = *FileHandle;
+
+ if (index > HandleHighWaterMark)
+ {
+ HandleHighWaterMark = index;
+ }
+ break;
+ }
+ }
+ }
+ return status;
+}
+
+
+NTSTATUS
+DmClose(
+ IN HANDLE Handle
+ )
+
+/*++
+
+Routine Description:
+
+ A debugging aid for tracking open and closes
+
+Arguments:
+
+ Same as for NtClose()
+
+Return Value:
+
+ Same as for NtClose()
+
+--*/
+
+{
+ ULONG index;
+
+ for (index = 0; index < NUMBER_OF_HANDLES_TRACKED; index++)
+ {
+ if (OpenHandleArray[index] == Handle)
+ {
+ OpenHandleArray[index] = (HANDLE) 0;
+ break;
+ }
+ }
+
+ return NtClose(Handle);
+}
+
+#endif // DBG == 1
diff --git a/private/utils/windisk/src/ntlow.hxx b/private/utils/windisk/src/ntlow.hxx
new file mode 100644
index 000000000..305978e61
--- /dev/null
+++ b/private/utils/windisk/src/ntlow.hxx
@@ -0,0 +1,134 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: ntlow.hxx
+//
+// Contents: Low-level I/O routines, implemented to run on NT.
+//
+// History: 8-Nov-91 TedM Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __NTLOW_HXX__
+#define __NTLOW_HXX__
+
+//////////////////////////////////////////////////////////////////////////////
+
+STATUS_CODE
+LowQueryFdiskPathList(
+ OUT PCHAR** PathList,
+ OUT PULONG ListLength
+ );
+
+STATUS_CODE
+LowFreeFdiskPathList(
+ IN OUT PCHAR* PathList,
+ IN ULONG ListLength
+ );
+
+STATUS_CODE
+LowOpenNtName(
+ IN PCHAR Name,
+ IN HANDLE_PT Handle
+ );
+
+STATUS_CODE
+LowOpenDisk(
+ IN PCHAR DevicePath,
+ OUT HANDLE_PT DiskId
+ );
+
+STATUS_CODE
+LowOpenPartition(
+ IN PCHAR DevicePath,
+ IN ULONG Partition,
+ OUT HANDLE_PT Handle
+ );
+
+STATUS_CODE
+LowCloseDisk(
+ IN HANDLE_T DiskId
+ );
+
+STATUS_CODE
+LowGetDriveGeometry(
+ IN PCHAR DevicePath,
+ OUT PULONG TotalSectorCount,
+ OUT PULONG SectorSize,
+ OUT PULONG SectorsPerTrack,
+ OUT PULONG Heads
+ );
+
+STATUS_CODE
+LowGetDiskLayout(
+ IN PCHAR Path,
+ OUT PDRIVE_LAYOUT_INFORMATION* DriveLayout
+ );
+
+STATUS_CODE
+LowSetDiskLayout(
+ IN PCHAR Path,
+ IN PDRIVE_LAYOUT_INFORMATION DriveLayout
+ );
+
+STATUS_CODE
+LowGetPartitionGeometry(
+ IN PCHAR PartitionPath,
+ OUT PULONG TotalSectorCount,
+ OUT PULONG SectorSize,
+ OUT PULONG SectorsPerTrack,
+ OUT PULONG Heads
+ );
+
+STATUS_CODE
+LowReadSectors(
+ IN HANDLE_T VolumeId,
+ IN ULONG SectorSize,
+ IN ULONG StartingSector,
+ IN ULONG NumberOfSectors,
+ OUT PVOID Buffer
+ );
+
+STATUS_CODE
+LowWriteSectors(
+ IN HANDLE_T VolumeId,
+ IN ULONG SectorSize,
+ IN ULONG StartingSector,
+ IN ULONG NumberOfSectors,
+ IN PVOID Buffer
+ );
+
+STATUS_CODE
+LowLockDrive(
+ IN HANDLE_T DiskId
+ );
+
+STATUS_CODE
+LowUnlockDrive(
+ IN HANDLE_T DiskId
+ );
+
+STATUS_CODE
+LowOpenDriveLetter(
+ IN WCHAR DriveLetter,
+ IN HANDLE_PT Handle
+ );
+
+STATUS_CODE
+LowFtVolumeStatus(
+ IN ULONG Disk,
+ IN ULONG Partition,
+ IN PFT_SET_STATUS FtStatus,
+ IN PULONG NumberOfMembers
+ );
+
+STATUS_CODE
+LowFtVolumeStatusByLetter(
+ IN CHAR DriveLetter,
+ IN PFT_SET_STATUS FtStatus,
+ IN PULONG NumberOfMembers
+ );
+
+#endif // __NTLOW_HXX__
diff --git a/private/utils/windisk/src/oleclass.cxx b/private/utils/windisk/src/oleclass.cxx
new file mode 100644
index 000000000..d7b29c033
--- /dev/null
+++ b/private/utils/windisk/src/oleclass.cxx
@@ -0,0 +1,84 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: oleclass.cxx
+//
+// Contents: OLE class code helpers
+//
+// Functions:
+//
+// History: 14-Jan-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include <util.hxx>
+#include "oleclass.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: ReleaseOle, public
+//
+// Synopsis: Unlink from OLE libraries
+//
+// Arguments: none
+//
+// Returns: nothing
+//
+// History: 27-May-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+VOID
+ReleaseOle(
+ VOID
+ )
+{
+#ifdef WINDISK_EXTENSIONS
+ OleUninitialize();
+#endif // WINDISK_EXTENSIONS
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: InitOle, public
+//
+// Synopsis: Link to OLE libraries
+//
+// Arguments: none
+//
+// Returns: TRUE on success, FALSE on failure
+//
+// History: 27-May-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+BOOL
+InitOle(
+ VOID
+ )
+{
+ BOOL fReturn = TRUE;
+
+#ifdef WINDISK_EXTENSIONS
+ if (OleInitializeEx(NULL, COINIT_MULTITHREADED) != 0)
+ {
+ ReleaseOle();
+ fReturn = FALSE;
+ }
+ else
+ {
+ fReturn = TRUE;
+ }
+#endif // WINDISK_EXTENSIONS
+
+ return fReturn;
+}
diff --git a/private/utils/windisk/src/oleclass.hxx b/private/utils/windisk/src/oleclass.hxx
new file mode 100644
index 000000000..d1c9ba11b
--- /dev/null
+++ b/private/utils/windisk/src/oleclass.hxx
@@ -0,0 +1,29 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: oleclass.hxx
+//
+// Contents: OLE class code helpers
+//
+// Functions:
+//
+// History: 14-Jan-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef __OLECLASS_HXX__
+#define __OLECLASS_HXX__
+
+VOID
+ReleaseOle(
+ VOID
+ );
+
+BOOL
+InitOle(
+ VOID
+ );
+
+#endif // __OLECLASS_HXX__
diff --git a/private/utils/windisk/src/ops.cxx b/private/utils/windisk/src/ops.cxx
new file mode 100644
index 000000000..7ffb127b5
--- /dev/null
+++ b/private/utils/windisk/src/ops.cxx
@@ -0,0 +1,2823 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: ops.cxx
+//
+// Contents: Main operations: Create partition, etc.
+//
+// History: 4-Mar-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include "cdrom.hxx"
+#include "commit.hxx"
+#include "dialogs.h"
+#include "dlgs.hxx"
+#include "drives.hxx"
+#include "fill.hxx"
+#include "ft.hxx"
+#include "listbox.hxx"
+#include "nt.hxx"
+#include "ntlow.hxx"
+#include "ops.hxx"
+#include "select.hxx"
+#include "stleg.hxx"
+#include "windisk.hxx"
+
+////////////////////////////////////////////////////////////////////////////
+
+VOID
+DoDeleteFTSet(
+ IN DWORD ConfirmationMsg
+ );
+
+////////////////////////////////////////////////////////////////////////////
+
+//+---------------------------------------------------------------------------
+//
+// Function: CompleteSingleRegionOperation
+//
+// Synopsis: Complete a single region operation: repaint the disks,
+// regenerate the listview, adjust the status area and menus.
+//
+// Arguments: [DiskState] -- disk on which the operation was performed
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+CompleteSingleRegionOperation(
+ IN PDISKSTATE DiskState
+ )
+{
+ RECT rc;
+ signed displayOffset;
+
+ EnableMenuItem(GetMenu(g_hwndFrame), IDM_CONFIGSAVE, MF_GRAYED);
+
+ DeterminePartitioningState(DiskState);
+ SetDriveLetterInfo(DiskState->Disk);
+
+ SetFTObjectBackPointers();
+
+ DrawDiskBar(DiskState);
+
+ SetUpMenu(&SingleSel, &SingleSelIndex);
+
+ if (VIEW_DISKS == g_WhichView)
+ {
+ // BUGBUG use of disk# as offset in listbox
+ displayOffset = (signed)DiskState->Disk
+ - (signed)SendMessage(g_hwndList, LB_GETTOPINDEX, 0, 0);
+
+ if (displayOffset > 0) // otherwise it's not visible
+ {
+ // make a thin rectangle to force update
+ rc.left = BarLeftX + 5;
+ rc.right = rc.left + 5;
+ rc.top = (displayOffset * GraphHeight) + BarTopYOffset;
+ rc.bottom = rc.top + 5;
+ InvalidateRect(g_hwndList, &rc, FALSE);
+ }
+
+ ResetLBCursorRegion();
+ ForceLBRedraw();
+ }
+ else if (VIEW_VOLUMES == g_WhichView)
+ {
+ FillListView(TRUE); // refresh it!
+ }
+
+ ClearStatusArea();
+ DetermineExistence();
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: CompleteMultiRegionOperation
+//
+// Synopsis: Complete a multiple region operation: redraw and repaint
+// all the disks, regenerate the listview, adjust the status
+// area and menus.
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+CompleteMultiRegionOperation(
+ VOID
+ )
+{
+ ULONG i;
+
+ EnableMenuItem(GetMenu(g_hwndFrame), IDM_CONFIGSAVE, MF_GRAYED);
+
+ for (i=0; i<DiskCount; i++)
+ {
+ DeterminePartitioningState(DiskArray[i]);
+ SetDriveLetterInfo(i);
+ }
+ SetFTObjectBackPointers();
+
+ SetUpMenu(&SingleSel, &SingleSelIndex);
+
+ if (VIEW_DISKS == g_WhichView)
+ {
+ ResetLBCursorRegion();
+ TotalRedrawAndRepaint();
+ }
+ else if (VIEW_VOLUMES == g_WhichView)
+ {
+ FillListView(TRUE); // refresh it!
+ }
+
+ ClearStatusArea();
+ DetermineExistence();
+}
+
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: CompleteDriveLetterChange
+//
+// Synopsis:
+//
+// Arguments: none
+//
+// Returns: nothing
+//
+// History: 2-Mar-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+CompleteDriveLetterChange(
+ IN WCHAR NewDriveLetter
+ )
+{
+ SetCursor(g_hCurWait);
+
+ //
+ // Change the menu based on this new format
+ //
+
+ SetUpMenu(&SingleSel, &SingleSelIndex);
+
+ //
+ // refresh the display
+ //
+
+ //
+ // for either view, still need to redraw the disks view bars
+ //
+
+// RedrawSelectedBars();
+
+ if (VIEW_DISKS == g_WhichView)
+ {
+// ForceLBRedraw();
+ }
+ else if (VIEW_VOLUMES == g_WhichView)
+ {
+// CheckSelection(); //BUGBUG: why is this necessary to complete a drive letter change?
+ FillListView(FALSE);
+
+ // give the first element the focus and selection, by default
+
+ g_SettingListviewState = TRUE; // no notifications
+
+
+ if (NewDriveLetter != NO_DRIVE_LETTER_EVER) {
+ INT itemNew = GetLVIndexFromDriveLetter(NewDriveLetter);
+
+ // Give the item both the focus *and* the selection, since we only
+ // allow a single listview selection
+
+ ListView_SetItemState(
+ g_hwndLV,
+ itemNew,
+ LVIS_FOCUSED | LVIS_SELECTED,
+ LVIS_FOCUSED | LVIS_SELECTED);
+ ListView_EnsureVisible(g_hwndLV, itemNew, FALSE);
+
+ g_SettingListviewState = FALSE; // accept notifications
+
+ DeselectSelectedDiskViewRegions(); // visual selection in disk view
+ DeselectSelectedRegions(); // actual selection state
+ SetVolumeSelection(itemNew, TRUE); // reflect in disks view
+ }
+ }
+
+ AdjustMenuAndStatus();
+ EnableMenuItem(g_hmenuFrame, IDM_CONFIGSAVE, MF_GRAYED);
+
+ SetCursor(g_hCurNormal);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DoSetDriveLetter
+//
+// Synopsis: Set the drive letter for the selected volume
+//
+// Arguments: none
+//
+// Requires: A valid selection for creation, as determined by
+// DetermineSelectionState()
+//
+// Returns: nothing
+//
+// History: 1-Sep-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DoSetDriveLetter(
+ VOID
+ )
+{
+ PCDROM_DESCRIPTOR cdrom;
+ PREGION_DESCRIPTOR regionDescriptor;
+ PPERSISTENT_REGION_DATA regionData;
+ WCHAR description[MAX_RESOURCE_STRING_LEN];
+ DRIVELET_DLG_PARAMS params;
+ ULONG index;
+
+ params.NewDriveLetter = L'\0';
+ params.Description = description;
+
+ if (CdRomSelected)
+ {
+ cdrom = CdRomFindSelectedDevice();
+ FDASSERT(NULL != cdrom);
+
+ params.DriveLetter = cdrom->DriveLetter;
+
+ wsprintf(description, CdRomN, cdrom->DeviceNumber);
+ }
+ else
+ {
+ PFT_OBJECT ftObject;
+
+ regionDescriptor = &SELECTED_REGION(0);
+ FDASSERT(NULL != regionDescriptor);
+
+ regionData = PERSISTENT_DATA(regionDescriptor);
+ FDASSERT(NULL != regionData);
+
+ ftObject = regionData->FtObject;
+ if (NULL != ftObject)
+ {
+ // Must find the zero member of this set for the
+ // drive letter assignment. Search all of the selected
+ // regions
+
+ index = 0;
+ while (ftObject->MemberIndex)
+ {
+ // search the next selected item if there is one
+
+ index++;
+ if (index >= SelectionCount)
+ {
+ ftObject = NULL;
+ break;
+ }
+
+ regionDescriptor = &SELECTED_REGION(index);
+ FDASSERT(NULL != regionDescriptor);
+
+ regionData = PERSISTENT_DATA(regionDescriptor);
+ FDASSERT(NULL != regionData);
+
+ ftObject = regionData->FtObject;
+
+ // must have an FtObject to continue
+
+ if (NULL == ftObject)
+ {
+ break;
+ }
+ }
+
+ FDASSERT(NULL != ftObject);
+
+ // regionDescriptor locates the zero element now.
+ }
+
+ params.DriveLetter = regionData->DriveLetter;
+
+ if (IsDiskRemovable[regionDescriptor->Disk])
+ {
+ ErrorDialog(MSG_CANT_ASSIGN_LETTER_TO_REMOVABLE);
+ return;
+ }
+ else if (AllDriveLettersAreUsed() && IsExtraDriveLetter(params.DriveLetter))
+ {
+ ErrorDialog(MSG_ALL_DRIVE_LETTERS_USED);
+ return;
+ }
+
+ //
+ // Format the description of the partition.
+ //
+
+ if (NULL != (ftObject = GET_FT_OBJECT(regionDescriptor)))
+ {
+ WCHAR descriptionProto[MAX_RESOURCE_STRING_LEN];
+ DWORD resid;
+
+ //
+ // Ft. Description is something like "Stripe set with parity #0"
+ //
+
+ switch (ftObject->Set->Type)
+ {
+ case Mirror:
+ resid = IDS_DLGCAP_MIRROR;
+ break;
+
+ case Stripe:
+ resid = IDS_STATUS_STRIPESET;
+ break;
+
+ case StripeWithParity:
+ resid = IDS_DLGCAP_PARITY;
+ break;
+
+ case VolumeSet:
+ resid = IDS_STATUS_VOLUMESET;
+ break;
+
+ default:
+ FDASSERT(FALSE);
+ }
+
+ LoadString(g_hInstance, resid, descriptionProto, ARRAYLEN(descriptionProto));
+ wsprintf(description, descriptionProto, ftObject->Set->Ordinal);
+ }
+ else
+ {
+ //
+ // Non-ft. description is something like '500 MB Unformatted
+ // logical drive on disk 3' or '400 MB NTFS partition on disk 4'
+ //
+
+ LPTSTR args[4];
+ TCHAR sizeStr[20];
+ TCHAR partTypeStr[100];
+ TCHAR diskNumStr[10];
+ TCHAR typeName[150];
+ TCHAR formatString[MAX_RESOURCE_STRING_LEN];
+
+ args[0] = sizeStr;
+ args[1] = typeName;
+ args[2] = partTypeStr;
+ args[3] = diskNumStr;
+
+ wsprintf(sizeStr, TEXT("%u"), regionDescriptor->SizeMB);
+ wsprintf(typeName, TEXT("%s"), PERSISTENT_DATA(regionDescriptor)->TypeName);
+ LoadString(
+ g_hInstance,
+ (regionDescriptor->RegionType == REGION_LOGICAL)
+ ? IDS_LOGICALVOLUME
+ : IDS_PARTITION,
+ partTypeStr,
+ ARRAYLEN(partTypeStr));
+ wsprintf(diskNumStr, TEXT("%u"), regionDescriptor->Disk);
+
+ LoadString(
+ g_hInstance,
+ IDS_DRIVELET_DESCR,
+ formatString,
+ ARRAYLEN(formatString));
+
+ FormatMessage(
+ FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
+ formatString,
+ 0,
+ 0,
+ description,
+ sizeof(description),
+ (va_list*)args
+ );
+ }
+ }
+
+ int fOk = DialogBoxParam(
+ g_hInstance,
+ MAKEINTRESOURCE(IDD_DRIVELET),
+ g_hwndFrame,
+ DriveLetterDlgProc,
+ (LPARAM)&params
+ );
+
+ if ( (-1 != fOk) // DialogBoxParam error
+ && (FALSE != fOk) ) // user cancelled
+ {
+ if (IsExtraDriveLetter(params.DriveLetter))
+ {
+ // Must insure that driveLetterIn maps to same things
+ // as is returned by the dialog when the user selects
+ // no letter.
+
+ params.DriveLetter = NO_DRIVE_LETTER_EVER;
+ }
+
+ if (params.DriveLetter != params.NewDriveLetter)
+ {
+ //
+ // Something changed: the user isn't just choosing the same drive
+ // letter
+ //
+
+ if (CdRomSelected)
+ {
+ CdRomChangeDriveLetter(cdrom, params.NewDriveLetter);
+ CompleteDriveLetterChange(params.NewDriveLetter);
+ }
+ else
+ {
+ // Assume a disk is selected
+
+ if (CommitDriveLetter(regionDescriptor, params.DriveLetter, params.NewDriveLetter))
+ {
+ //
+ // The following would be more rigorously correct:
+ // if non-ft, just set regionData->DriveLetter. If
+ // ft, scan all regions on all disks for members of
+ // ft set and set their drive letter fields.
+ //
+ // The below is probably correct, though.
+ //
+
+ DWORD i;
+ for (i=0; i<SelectionCount; i++)
+ {
+ regionData = PERSISTENT_DATA(&SELECTED_REGION(i));
+ FDASSERT(NULL != regionData);
+
+ regionData->DriveLetter = params.NewDriveLetter;
+ }
+
+ CompleteDriveLetterChange(params.NewDriveLetter);
+ }
+ }
+ }
+ }
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DoCreate
+//
+// Synopsis: Create a primary or extended partition in the selected
+// free space
+//
+// Arguments: [CreationType] -- REGION_EXTENDED or REGION_PRIMARY
+//
+// Requires: A valid selection for creation, as determined by
+// DetermineSelectionState()
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DoCreate(
+ IN REGION_TYPE CreationType
+ )
+{
+ PREGION_DESCRIPTOR regionDescriptor = &SingleSel->RegionArray[SingleSelIndex];
+ ULONG diskNumber = regionDescriptor->Disk;
+ PPERSISTENT_REGION_DATA regionData;
+ MINMAXDLG_PARAMS dlgParams;
+ DWORD creationSize;
+ DWORD ec;
+ BOOLEAN isRemovable;
+ WCHAR driveLetter;
+
+ FDASSERT(SingleSel);
+ FDASSERT(regionDescriptor->SysID == PARTITION_ENTRY_UNUSED);
+
+ //
+ // WinDisk can only create a single partition on a removable
+ // disk--no extended partitions and only one primary.
+ //
+ isRemovable = IsDiskRemovable[diskNumber];
+
+ if ( isRemovable )
+ {
+ if ( CreationType == REGION_EXTENDED )
+ {
+ ErrorDialog( MSG_NO_EXTENDED_ON_REMOVABLE );
+ return;
+ }
+
+ if ( DiskArray[diskNumber]->ExistAny )
+ {
+ ErrorDialog( MSG_ONLY_ONE_PARTITION_ON_REMOVABLE );
+ return;
+ }
+ }
+
+
+ //
+ // Make sure the partition table is not full, and that we are allowed to
+ // create the type of partition to be created.
+ //
+
+ if (regionDescriptor->RegionType == REGION_PRIMARY)
+ {
+ if (!SingleSel->CreatePrimary)
+ {
+ ErrorDialog(MSG_PART_TABLE_FULL);
+ return;
+ }
+
+ if ((CreationType == REGION_EXTENDED) && !SingleSel->CreateExtended)
+ {
+ ErrorDialog(MSG_EXTENDED_ALREADY_EXISTS);
+ return;
+ }
+ }
+
+ //
+ // If not creating an extended partition, allocate a drive letter.
+ // If no drive letter is available, warn the user and allow him to cancel.
+ // If the new partition is on a removable disk, use the reserved
+ // drive letter for that removable disk.
+ //
+ if (CreationType != REGION_EXTENDED)
+ {
+ CreationType = regionDescriptor->RegionType; // primary or logical
+
+ if (isRemovable)
+ {
+ driveLetter = RemovableDiskReservedDriveLetters[diskNumber];
+ }
+ else
+ {
+ if (!AssignDriveLetter(
+ TRUE,
+ (CreationType == REGION_LOGICAL)
+ ? IDS_LOGICALVOLUME : IDS_PARTITION,
+ &driveLetter))
+ {
+ return;
+ }
+ }
+ }
+ else
+ {
+ CommitDueToExtended = TRUE;
+ }
+
+#if i386
+ // if the user is creating a primary partition and there are already
+ // primary partitions, warn him that the scheme he will create may
+ // not be DOS compatible.
+
+ if ((CreationType == REGION_PRIMARY) && SingleSel->ExistPrimary)
+ {
+ if (IDYES != ConfirmationDialog(
+ MSG_CREATE_NOT_COMPAT,
+ MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2))
+ {
+ return;
+ }
+ }
+#endif
+
+ // now get the size.
+ //
+ dlgParams.MinSizeMB = FdGetMinimumSizeMB(diskNumber);
+ dlgParams.MaxSizeMB = FdGetMaximumSizeMB(regionDescriptor, CreationType);
+
+ switch (CreationType)
+ {
+ case REGION_PRIMARY:
+ dlgParams.CaptionStringID = IDS_CRTPART_CAPTION_P;
+ dlgParams.MinimumStringID = IDS_CRTPART_MIN_P;
+ dlgParams.MaximumStringID = IDS_CRTPART_MAX_P;
+ dlgParams.SizeStringID = IDS_CRTPART_SIZE_P;
+ dlgParams.HelpContextId = HC_DM_DLG_CREATEPRIMARY;
+ break;
+
+ case REGION_EXTENDED:
+ dlgParams.CaptionStringID = IDS_CRTPART_CAPTION_E;
+ dlgParams.MinimumStringID = IDS_CRTPART_MIN_P;
+ dlgParams.MaximumStringID = IDS_CRTPART_MAX_P;
+ dlgParams.SizeStringID = IDS_CRTPART_SIZE_P;
+ dlgParams.HelpContextId = HC_DM_DLG_CREATEEXTENDED;
+ break;
+
+ case REGION_LOGICAL:
+ dlgParams.CaptionStringID = IDS_CRTPART_CAPTION_L;
+ dlgParams.MinimumStringID = IDS_CRTPART_MIN_L;
+ dlgParams.MaximumStringID = IDS_CRTPART_MAX_L;
+ dlgParams.SizeStringID = IDS_CRTPART_SIZE_L;
+ dlgParams.HelpContextId = HC_DM_DLG_CREATELOGICAL;
+ break;
+
+ default:
+ FDASSERT(FALSE);
+ }
+
+ creationSize = DialogBoxParam(g_hInstance,
+ MAKEINTRESOURCE(IDD_MINMAX),
+ g_hwndFrame,
+ MinMaxDlgProc,
+ (LPARAM)&dlgParams);
+
+ if (0 == creationSize) // user cancelled
+ {
+ return;
+ }
+
+ // Since the WinDisk can only create one partition on a removable
+ // disk, if the user requests a size smaller than the maximum
+ // on a removable disk, prompt to confirm:
+ //
+ if (isRemovable
+ && creationSize != FdGetMaximumSizeMB(regionDescriptor, CreationType))
+ {
+ if (IDYES != ConfirmationDialog(
+ MSG_REMOVABLE_PARTITION_NOT_FULL_SIZE,
+ MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2))
+ {
+ return;
+ }
+ }
+
+#if i386
+
+ //
+ // See whether the partition will cross over the 1024 cylinder boundary
+ // and warn the user if it will.
+ //
+ // Don't warn about creating logical partitions: the user's already
+ // been warned once about creating the extended partition, so they
+ // presumably know the warning. This is different from NT 3.1, which
+ // warned every time.
+ //
+
+ if (CreationType != REGION_LOGICAL)
+ {
+ if (FdCrosses1024Cylinder(regionDescriptor, creationSize, CreationType))
+ {
+ DWORD msgId = (CreationType == REGION_PRIMARY)
+ ? MSG_PRI_1024_CYL
+ : MSG_EXT_1024_CYL
+ ;
+ if (IDYES != ConfirmationDialog(
+ msgId,
+ MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2))
+ {
+ return;
+ }
+ }
+ }
+
+#endif
+
+ SetCursor(g_hCurWait);
+
+ //
+ // If not creating an extended partition, we need to create a new
+ // persistent region data structure to associate with the new
+ // partition.
+ //
+
+ if (CreationType == REGION_EXTENDED)
+ {
+ regionData = NULL;
+ }
+ else
+ {
+ LARGE_INTEGER zero;
+ zero.QuadPart = 0;
+
+ regionData = DmAllocatePersistentData(
+ NULL,
+ L"",
+ wszUnformatted,
+ driveLetter,
+ TRUE,
+ zero,
+ zero
+ );
+ }
+
+ ec = CreatePartition(
+ regionDescriptor,
+ creationSize,
+ CreationType
+ );
+
+ if (ec != NO_ERROR)
+ {
+ SetCursor(g_hCurNormal);
+ ErrorDialog(ec);
+ }
+
+ DmSetPersistentRegionData(regionDescriptor, regionData);
+
+ if (CreationType != REGION_EXTENDED)
+ {
+ if (!isRemovable)
+ {
+ MarkDriveLetterUsed(driveLetter);
+ CommitToAssignLetterList(regionDescriptor, FALSE);
+ } else {
+ CommitDueToCreate = TRUE;
+ }
+ }
+
+ // this clears all selections on the disk
+ CompleteSingleRegionOperation(SingleSel);
+
+ SetCursor(g_hCurNormal);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DoDelete
+//
+// Synopsis: Delete a selected volume
+//
+// Arguments: (none)
+//
+// Requires: A selected volume
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DoDelete(
+ VOID
+ )
+{
+ PREGION_DESCRIPTOR regionDescriptor = &SingleSel->RegionArray[SingleSelIndex];
+ ULONG diskNumber = regionDescriptor->Disk;
+ PPERSISTENT_REGION_DATA regionData;
+ DWORD actualIndex = SingleSelIndex;
+ DWORD i;
+ DWORD ec;
+ BOOL deletingExtended;
+
+ FDASSERT(SingleSel);
+
+ // if deleting a free space in the extended partition, then delete the
+ // extended partition itself.
+
+ if ((regionDescriptor->RegionType == REGION_LOGICAL)
+ && !SingleSel->ExistLogical)
+ {
+ FDASSERT(SingleSel->ExistExtended);
+
+ // find the extended partition
+
+ for (i=0; i<SingleSel->RegionCount; i++)
+ {
+ if (IsExtended(SingleSel->RegionArray[i].SysID))
+ {
+ actualIndex = i;
+ break;
+ }
+ }
+
+ deletingExtended = TRUE;
+ FDASSERT(actualIndex != SingleSelIndex);
+ }
+ else
+ {
+ deletingExtended = FALSE;
+
+ //
+ // Make sure deletion of this partition is allowed. It is not allowed
+ // if it is the boot partition (or sys partition on x86).
+ //
+
+ if (NO_ERROR
+ != (ec = DeletionIsAllowed(&SingleSel->RegionArray[actualIndex])))
+ {
+ ErrorDialog(ec);
+ return;
+ }
+ }
+
+ // If this is a partition that will become the result of a
+ // mirror break, insure that the break has occurred. Otherwise
+ // this delete will have bad results.
+
+ // actualIndex is the thing to delete.
+ regionDescriptor = &SingleSel->RegionArray[actualIndex];
+ if (NULL != regionDescriptor->Reserved)
+ {
+ if (NULL != regionDescriptor->Reserved->Partition)
+ {
+ if (regionDescriptor->Reserved->Partition->CommitMirrorBreakNeeded)
+ {
+ ErrorDialog(MSG_MUST_COMMIT_BREAK);
+ return;
+ }
+ }
+ }
+
+ FDASSERT(regionDescriptor->SysID != PARTITION_ENTRY_UNUSED);
+ regionData = PERSISTENT_DATA(regionDescriptor);
+ if (!deletingExtended)
+ {
+ BOOL fNew = FALSE;
+ if (NULL != regionData && regionData->NewRegion)
+ {
+ fNew = TRUE;
+ }
+
+ if (!fNew
+ && (IDYES != ConfirmationDialog(
+ MSG_CONFIRM_DELETE,
+ MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2)))
+ {
+ return;
+ }
+ }
+
+ if (NULL != regionData)
+ {
+ // Remember drive letter if there is one in order to lock it for delete
+
+ if (CommitToLockList(
+ regionDescriptor,
+ !IsDiskRemovable[diskNumber],
+ TRUE,
+ FALSE))
+ {
+ // Could not lock exclusively - do not allow delete
+
+ if (IsPagefileOnDrive(regionData->DriveLetter))
+ {
+ ErrorDialog(MSG_CANNOT_LOCK_PAGEFILE);
+ return;
+ }
+ else
+ {
+ if (CommitToLockList(
+ regionDescriptor,
+ !IsDiskRemovable[diskNumber],
+ TRUE,
+ FALSE))
+ {
+ FDLOG((1,"DoDelete: Couldn't lock 2 times - popup shown\n"));
+ ErrorDialog(MSG_CANNOT_LOCK_TRY_AGAIN);
+ return;
+ }
+ }
+ }
+ }
+ else
+ {
+ // Deleting an extended partition - enable commit.
+
+ CommitDueToDelete = TRUE;
+ }
+
+
+ SetCursor(g_hCurWait);
+
+ ec = DeletePartition(regionDescriptor);
+
+ if (ec != NO_ERROR)
+ {
+ SetCursor(g_hCurNormal);
+ ErrorDialog(ec);
+ }
+
+ if (NULL != regionData)
+ {
+
+ //
+ // Note that one might think to free the drive letter here so that it is
+ // available for other drives to use. BUT! we don't. The reason is that
+ // the change isn't actually committed yet. If the changes aren't committed
+ // we don't want to have let the user reassign the drive letter to any other
+ // drive.
+ //
+ DmFreePersistentData(regionData);
+ DmSetPersistentRegionData(regionDescriptor, NULL);
+ }
+
+ // this clears all selections on the disk
+ CompleteSingleRegionOperation(SingleSel);
+
+ SetCursor(g_hCurNormal);
+}
+
+
+
+#if i386
+
+//+---------------------------------------------------------------------------
+//
+// Function: DoMakeActive
+//
+// Synopsis: Make the selected volume active
+//
+// Arguments: (none)
+//
+// Requires: A legal selection (see DetermineSelectionState())
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DoMakeActive(
+ VOID
+ )
+{
+ DWORD i;
+ PREGION_DESCRIPTOR regionDescriptor;
+
+ SetCursor(g_hCurWait);
+
+ if (SelectionCount == 1) {
+
+ FDASSERT(SingleSel);
+ FDASSERT(!SingleSel->RegionArray[SingleSelIndex].Active);
+ FDASSERT(SingleSel->RegionArray[SingleSelIndex].RegionType == REGION_PRIMARY);
+ FDASSERT(SingleSel->RegionArray[SingleSelIndex].SysID != PARTITION_ENTRY_UNUSED);
+
+ MakePartitionActive(SingleSel->RegionArray,
+ SingleSel->RegionCount,
+ SingleSelIndex
+ );
+
+ SetCursor(g_hCurNormal);
+
+ InfoDialog(MSG_DISK0_ACTIVE);
+
+ SetCursor(g_hCurWait);
+
+ CompleteSingleRegionOperation(SingleSel);
+
+
+ } else {
+
+ //
+ // Mirror case.
+ //
+
+ for (i = 0; i < SelectionCount; i++) {
+ regionDescriptor = &SELECTED_REGION(i);
+ if (regionDescriptor->SysID != PARTITION_ENTRY_UNUSED &&
+ regionDescriptor->RegionType == REGION_PRIMARY &&
+ !regionDescriptor->Active) {
+
+ MakePartitionActive(SelectedDS[i]->RegionArray,
+ SelectedDS[i]->RegionCount,
+ SelectedRG[i]);
+ }
+ }
+
+ SetCursor(g_hCurNormal);
+
+ InfoDialog(MSG_DISK0_ACTIVE);
+
+ SetCursor(g_hCurWait);
+
+ CompleteMultiRegionOperation();
+ }
+
+ SetCursor(g_hCurNormal);
+}
+
+#endif
+
+
+#ifndef i386
+
+//+---------------------------------------------------------------------------
+//
+// Function: DoProtectSystemPartition
+//
+// Synopsis: This function toggles the state of the system partition
+// security: if the system partition is secure, it makes it
+// non-secure; if the system partition is not secure, it makes
+// it secure.
+//
+// Arguments: (none)
+//
+// Requires: A legal selection (see DetermineSelectionState())
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DoProtectSystemPartition(
+ VOID
+ )
+{
+ LONG ec;
+ HKEY hkey;
+ DWORD value;
+ DWORD messageId;
+
+ messageId = SystemPartitionIsSecure ? MSG_CONFIRM_UNPROTECT_SYSTEM :
+ MSG_CONFIRM_PROTECT_SYSTEM;
+
+ if (IDYES != ConfirmationDialog(
+ messageId,
+ MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2))
+ {
+ return;
+ }
+
+ ec = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+ TEXT("System\\CurrentControlSet\\Control\\Lsa"),
+ 0,
+ KEY_SET_VALUE,
+ &hkey );
+
+ if (ec != ERROR_SUCCESS)
+ {
+ messageId = SystemPartitionIsSecure ? MSG_CANT_UNPROTECT_SYSTEM :
+ MSG_CANT_PROTECT_SYSTEM;
+ ErrorDialog(messageId);
+ return;
+ }
+
+ // If the system partition is currently secure, change it
+ // to not secure; if it is not secure, make it secure.
+ //
+ value = SystemPartitionIsSecure ? 0 : 1;
+
+ ec = RegSetValueEx( hkey,
+ TEXT("Protect System Partition"),
+ 0,
+ REG_DWORD,
+ (PBYTE)&value,
+ sizeof( DWORD ) );
+
+ RegCloseKey(hkey);
+
+ if (ec != ERROR_SUCCESS)
+ {
+ messageId = SystemPartitionIsSecure ? MSG_CANT_UNPROTECT_SYSTEM :
+ MSG_CANT_PROTECT_SYSTEM;
+ ErrorDialog(messageId);
+ return;
+ }
+
+ SystemPartitionIsSecure = !SystemPartitionIsSecure;
+
+ SetCursor(g_hCurWait);
+ SetUpMenu(&SingleSel, &SingleSelIndex);
+ RestartRequired = TRUE;
+ SetCursor(g_hCurNormal);
+}
+
+#endif // !i386
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DoEstablishMirror
+//
+// Synopsis: Establish a mirrored volume from the selection
+//
+// Arguments: (none)
+//
+// Requires: A legal selection for mirror creation (see
+// DetermineSelectionState())
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DoEstablishMirror(
+ VOID
+ )
+{
+ LARGE_INTEGER partitionSize;
+ LARGE_INTEGER freeSpaceSize;
+ LARGE_INTEGER zero;
+ DWORD i;
+ DWORD partitionIndex = 0;
+ DWORD freeSpaceIndex = 0;
+ PREGION_DESCRIPTOR regionDescriptor;
+ PREGION_DESCRIPTOR freeSpaceRegion = NULL;
+ PREGION_DESCRIPTOR existingRegion = NULL;
+ PREGION_DESCRIPTOR regionArray[MAX_MEMBERS_IN_FT_SET];
+ UCHAR newSysID;
+ PPERSISTENT_REGION_DATA regionData;
+
+ FDASSERT(SelectionCount == 2);
+
+ zero.QuadPart = 0;
+
+ // Make sure that the mirror pair does not include any
+ // partitions on removable media.
+ //
+ for (i=0; i<SelectionCount; i++)
+ {
+ if (IsDiskRemovable[SELECTED_REGION(i).Disk])
+ {
+ ErrorDialog(MSG_NO_REMOVABLE_IN_MIRROR);
+ return;
+ }
+ }
+
+ for (i=0; i<2; i++)
+ {
+ regionDescriptor = &SELECTED_REGION(i);
+ if (regionDescriptor->SysID == PARTITION_ENTRY_UNUSED)
+ {
+ freeSpaceIndex = i;
+ freeSpaceRegion = regionDescriptor;
+ }
+ else
+ {
+ partitionIndex = i;
+ existingRegion = regionDescriptor;
+ }
+ }
+
+ FDASSERT((freeSpaceRegion != NULL) && (existingRegion != NULL));
+
+ //
+ // Make sure that we are allowed to create a partition in the free space.
+ //
+
+ if (!( ((freeSpaceRegion->RegionType == REGION_LOGICAL)
+ && SelectedDS[freeSpaceIndex]->CreateLogical)
+ || ((freeSpaceRegion->RegionType == REGION_PRIMARY)
+ && SelectedDS[freeSpaceIndex]->CreatePrimary)))
+ {
+ ErrorDialog(MSG_CRTSTRP_FULL);
+ return;
+ }
+
+ //
+ // Make sure that the free space is large enough to hold a mirror of
+ // the existing partition. Do this by getting the EXACT size of
+ // the existing partition and the free space.
+ //
+
+ partitionSize = FdGetExactSize(existingRegion, FALSE);
+ freeSpaceSize = FdGetExactSize(freeSpaceRegion, FALSE);
+
+ if (freeSpaceSize.QuadPart < partitionSize.QuadPart)
+ {
+ ErrorDialog(MSG_CRTMIRROR_BADFREE);
+ return;
+ }
+
+ if (BootDiskNumber != (ULONG)-1)
+ {
+ // If the disk number and original partition number of this
+ // region match the recorded disk number and partition number
+ // of the boot partition, warn the user about mirroring the boot
+ // drive.
+
+ if ( existingRegion->Disk == BootDiskNumber
+ && existingRegion->OriginalPartitionNumber == BootPartitionNumber)
+ {
+ WarningDialog(MSG_MIRROR_OF_BOOT);
+
+ UpdateMbrOnDisk = freeSpaceRegion->Disk;
+ }
+ }
+
+ SetCursor(g_hCurWait);
+
+ regionData = DmAllocatePersistentData(
+ NULL,
+ PERSISTENT_DATA(existingRegion)->VolumeLabel,
+ PERSISTENT_DATA(existingRegion)->TypeName,
+ PERSISTENT_DATA(existingRegion)->DriveLetter,
+ TRUE,
+ zero,
+ zero
+ );
+
+ //
+ // Create the new partition.
+ //
+
+ newSysID = (UCHAR)(existingRegion->SysID | (UCHAR)PARTITION_NTFT);
+
+ CreatePartitionEx(freeSpaceRegion,
+ partitionSize,
+ 0,
+ freeSpaceRegion->RegionType,
+ newSysID);
+
+ DmSetPersistentRegionData(freeSpaceRegion, regionData);
+
+ //
+ // Cause the existing partition to be treated as new, to disallow
+ // file system operations
+ //
+
+ PERSISTENT_DATA(existingRegion)->NewRegion = TRUE;
+
+ //
+ // Check if the source partition is active and then mark the shadow
+ // partition active as well.
+ //
+
+ regionDescriptor = &SELECTED_REGION(partitionIndex);
+ if (regionDescriptor->Active) {
+ MakePartitionActive(SelectedDS[freeSpaceIndex]->RegionArray,
+ SelectedDS[freeSpaceIndex]->RegionCount,
+ SelectedRG[freeSpaceIndex]);
+ }
+
+ //
+ // Set the partition type of the existing partition.
+ //
+
+ SetSysID2(existingRegion, newSysID);
+
+ regionArray[0] = existingRegion;
+ regionArray[1] = freeSpaceRegion;
+ FdftCreateFtObjectSet( Mirror,
+ regionArray,
+ 2,
+ FtSetNewNeedsInitialization);
+
+ CompleteMultiRegionOperation();
+ CommitDueToMirror = TRUE;
+
+ EnableMenuItem(g_hmenuFrame, IDM_PARTITIONCOMMIT, MF_ENABLED); //BUGBUG: huh?
+
+ SetCursor(g_hCurNormal);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DoBreakMirror
+//
+// Synopsis: Using the global selection variables, this routine will break
+// the mirror relationship and modify their region descriptors to
+// describe two non-ft partitions giving either the primary
+// member of the mirror the drive letter for the mirror, or
+// the only healthy member of the mirror the drive letter.
+// The remaining "new" partition will receive the next
+// available drive letter.
+//
+// Arguments: (none)
+//
+// Requires: A legal selection (see DetermineSelectionState())
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DoBreakMirror(
+ VOID
+ )
+{
+ DWORD i;
+ PFT_OBJECT_SET ftSet;
+ PFT_OBJECT ftObject0;
+ PFT_OBJECT ftObject1;
+ PREGION_DESCRIPTOR regionDescriptor;
+ PPERSISTENT_REGION_DATA regionData;
+ ULONG newDriveLetterRegionIndex;
+ WCHAR driveLetter;
+
+ FDASSERT((SelectionCount == 1) || (SelectionCount == 2));
+
+ ftObject0 = GET_FT_OBJECT(&SELECTED_REGION(0));
+ if (SelectionCount == 2)
+ {
+ ftObject1 = GET_FT_OBJECT(&SELECTED_REGION(1));
+ }
+ else
+ {
+ ftObject1 = NULL;
+ }
+ ftSet = ftObject0->Set;
+
+ // Determine if the action is allowed.
+
+ switch (ftSet->Status)
+ {
+ case FtSetInitializing:
+ case FtSetRegenerating:
+
+ ErrorDialog(MSG_CANT_BREAK_INITIALIZING_SET);
+ return;
+
+ default:
+ break;
+ }
+
+
+ if (IDYES != ConfirmationDialog(
+ MSG_CONFIRM_BRK_MIRROR,
+ MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2))
+ {
+ return;
+ }
+
+ SetCursor(g_hCurWait);
+
+ //
+ // Figure out which region gets the new drive letter. A complication is
+ // that selection 0 is not necessarily member 0.
+ //
+ // If there is only one selection, then only one part of the mirror set
+ // is present -- no new drive letters are assigned.
+ // Otherwise, if one of the members is orphaned, it gets the new
+ // drive letter. Else the secondary member gets the new drive letter.
+ //
+
+ if (SelectionCount == 2)
+ {
+ if (ftObject0->State == Orphaned)
+ {
+ newDriveLetterRegionIndex = 0;
+ }
+ else
+ {
+ if (ftObject1->State == Orphaned)
+ {
+ newDriveLetterRegionIndex = 1;
+ }
+ else
+ {
+ //
+ // Neither member is orphaned; determine which is
+ // member 0 and give the other one the new drive letter.
+ //
+
+ if (ftObject0->MemberIndex) // secondary member ?
+ {
+ newDriveLetterRegionIndex = 0;
+ }
+ else
+ {
+ newDriveLetterRegionIndex = 1;
+ }
+ }
+ }
+ }
+ else
+ {
+ // The one remaining member could be the shadow.
+ // The drive letter must move to locate this partition
+
+ regionDescriptor = &SELECTED_REGION(0);
+ regionData = PERSISTENT_DATA(regionDescriptor);
+ if (!regionData->FtObject->MemberIndex)
+ {
+ // The shadow has become the valid partition.
+ // move the current letter there.
+
+ CommitToAssignLetterList(regionDescriptor, TRUE);
+ }
+
+ newDriveLetterRegionIndex = (ULONG)(-1);
+ }
+
+ // if newDriveLetterRegion is -1 this will still work and
+ // select the 0 selected region.
+
+ if (CommitToLockList(
+ &SELECTED_REGION(newDriveLetterRegionIndex ? 0 : 1),
+ FALSE,
+ TRUE,
+ FALSE))
+ {
+ if (IDYES != ConfirmationDialog(
+ MSG_CONFIRM_SHUTDOWN_FOR_MIRROR,
+ MB_ICONQUESTION | MB_YESNO))
+ {
+ return;
+ }
+ RestartRequired = TRUE;
+ }
+
+ if (newDriveLetterRegionIndex != (ULONG)(-1))
+ {
+ if (AssignDriveLetter(FALSE, 0, &driveLetter))
+ {
+ // Got a valid drive letter
+
+ MarkDriveLetterUsed(driveLetter);
+ }
+ else
+ {
+ // didn't get a letter. Instead the magic value
+ // for no drive letter assigned has been returned
+ }
+
+ regionDescriptor = &SELECTED_REGION(newDriveLetterRegionIndex);
+ regionData = PERSISTENT_DATA(regionDescriptor);
+ regionData->DriveLetter = driveLetter;
+ CommitToAssignLetterList(regionDescriptor, FALSE);
+
+ if (!regionData->FtObject->MemberIndex)
+ {
+ // The shadow has become the valid partition.
+ // move the current letter there.
+
+ CommitToAssignLetterList(
+ &SELECTED_REGION(newDriveLetterRegionIndex ? 0 : 1),
+ TRUE);
+ }
+ }
+ else
+ {
+ regionDescriptor = &SELECTED_REGION(0);
+ regionData = PERSISTENT_DATA(regionDescriptor);
+ if (0 != regionData->FtObject->MemberIndex)
+ {
+ // The shadow is all that is left.
+
+ CommitToAssignLetterList(regionDescriptor, TRUE);
+ }
+ }
+
+
+ FdftDeleteFtObjectSet(ftSet, FALSE);
+
+ for (i=0; i<SelectionCount; i++)
+ {
+ regionDescriptor = &SELECTED_REGION(i);
+ if (NULL != regionDescriptor->Reserved)
+ {
+ if (NULL != regionDescriptor->Reserved->Partition)
+ {
+ regionDescriptor->Reserved->Partition->CommitMirrorBreakNeeded
+ = TRUE;
+ }
+ }
+ SET_FT_OBJECT(regionDescriptor, 0);
+ SetSysID2(
+ regionDescriptor,
+ (UCHAR)(regionDescriptor->SysID & ~VALID_NTFT));
+ }
+
+ CompleteMultiRegionOperation();
+
+ SetCursor(g_hCurNormal);
+ CommitDueToMirror = TRUE;
+ EnableMenuItem(g_hmenuFrame, IDM_PARTITIONCOMMIT, MF_ENABLED); //BUGBUG: huh?
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DoCreateStripe
+//
+// Synopsis: This routine starts the dialog with the user to determine
+// the parameters of the creation of a stripe or stripe set
+// with parity. Based on the user response it creates the
+// internal structures necessary for the creation of a stripe
+// or stripe set with parity.
+//
+// The regions involved in the stripe creation are located via
+// the global parameters for multiple selections.
+//
+// Arguments: [Parity] -- if TRUE, create a stripe set with parity
+// (RAID 5), else create a simple stripe set (RAID 0)
+//
+// Requires: A legal selection (see DetermineSelectionState())
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DoCreateStripe(
+ IN BOOL Parity
+ )
+{
+ MINMAXDLG_PARAMS params;
+ DWORD smallestSize = (DWORD)(-1);
+ DWORD creationSize;
+ ULONG i;
+ PREGION_DESCRIPTOR regionDescriptor;
+ PREGION_DESCRIPTOR regionArray[MAX_MEMBERS_IN_FT_SET];
+ PPERSISTENT_REGION_DATA regionData;
+ WCHAR driveLetter;
+ LARGE_INTEGER zero;
+
+ zero.QuadPart = 0;
+
+ // Make sure that the volume set does not include any
+ // partitions on removable media.
+ //
+ for (i=0; i<SelectionCount; i++)
+ {
+ if (IsDiskRemovable[SELECTED_REGION(i).Disk])
+ {
+ ErrorDialog(MSG_NO_REMOVABLE_IN_STRIPE);
+ return;
+ }
+ }
+
+ // Scan the disks to determine the maximum size, which is
+ // the size of the smallest partition times the number of
+ // partitions.
+ //
+ for (i=0; i<SelectionCount; i++)
+ {
+ FDASSERT(SELECTED_REGION(i).SysID == PARTITION_ENTRY_UNUSED);
+ if (SELECTED_REGION(i).SizeMB < smallestSize)
+ {
+ smallestSize = SELECTED_REGION(i).SizeMB;
+ }
+ }
+
+ //
+ // Figure out a drive letter.
+ //
+
+ if (!AssignDriveLetter(TRUE, IDS_STRIPESET, &driveLetter))
+ {
+ return;
+ }
+
+ params.CaptionStringID = Parity ? IDS_CRTPSTRP_CAPTION : IDS_CRTSTRP_CAPTION;
+ params.MinimumStringID = IDS_CRTSTRP_MIN;
+ params.MaximumStringID = IDS_CRTSTRP_MAX;
+ params.SizeStringID = IDS_CRTSTRP_SIZE;
+ params.MinSizeMB = SelectionCount;
+ params.MaxSizeMB = smallestSize * SelectionCount;
+ if (Parity)
+ {
+ params.HelpContextId = HC_DM_DLG_CREATEPARITYSTRIPE;
+ }
+ else
+ {
+ params.HelpContextId = HC_DM_DLG_CREATESTRIPESET;
+ }
+
+ creationSize = DialogBoxParam(g_hInstance,
+ MAKEINTRESOURCE(IDD_MINMAX),
+ g_hwndFrame,
+ MinMaxDlgProc,
+ (LPARAM)&params);
+
+ if (0 == creationSize) // user cancelled
+ {
+ return;
+ }
+
+ //
+ // Determine how large we have to make each member of the stripe set.
+ //
+
+ creationSize = (creationSize / SelectionCount);
+ FDASSERT(creationSize <= smallestSize);
+ if (creationSize % SelectionCount)
+ {
+ creationSize++; // round up.
+ }
+
+ //
+ // Make sure we are allowed to create all the partitions
+ //
+ for (i=0; i<SelectionCount; i++)
+ {
+ regionDescriptor = &SELECTED_REGION(i);
+ FDASSERT(regionDescriptor->RegionType != REGION_EXTENDED);
+
+ if (!( ((regionDescriptor->RegionType == REGION_LOGICAL)
+ && SelectedDS[i]->CreateLogical)
+ || ((regionDescriptor->RegionType == REGION_PRIMARY)
+ && SelectedDS[i]->CreatePrimary)))
+ {
+ ErrorDialog(MSG_CRTSTRP_FULL);
+ return;
+ }
+ }
+
+ SetCursor(g_hCurWait);
+
+ //
+ // Now actually perform the creation.
+ //
+
+ for (i=0; i<SelectionCount; i++)
+ {
+ regionDescriptor = &SELECTED_REGION(i);
+
+ CreatePartitionEx(regionDescriptor,
+ RtlConvertLongToLargeInteger(0L),
+ creationSize,
+ regionDescriptor->RegionType,
+ (UCHAR)(PARTITION_HUGE | PARTITION_NTFT)
+ );
+
+ // Finish setting up the FT set.
+
+ regionData = DmAllocatePersistentData(
+ NULL,
+ L"",
+ wszUnformatted,
+ driveLetter,
+ TRUE,
+ zero,
+ zero
+ );
+
+ DmSetPersistentRegionData(regionDescriptor, regionData);
+
+ regionArray[i] = regionDescriptor;
+ }
+
+ // The zeroth element is the one to assign the drive letter to
+
+ CommitToAssignLetterList(&SELECTED_REGION(0), FALSE);
+
+ FdftCreateFtObjectSet(Parity ? StripeWithParity : Stripe,
+ regionArray,
+ SelectionCount,
+ Parity ? FtSetNewNeedsInitialization : FtSetNew
+ );
+
+ MarkDriveLetterUsed(driveLetter);
+ CompleteMultiRegionOperation();
+ SetCursor(g_hCurNormal);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DoDeleteFTSet
+//
+// Synopsis: Common code for the deletion of a stripe or volume set.
+// This routine will display a message giving the user a 2nd
+// chance to change their mind, then based on the answer perform
+// the work of deleting the item. This consists of removing
+// the region descriptors (and related information) from the
+// collection of Disk structures.
+//
+// Arguments: [ConfirmationMsg] -- resource ID of message to display
+// to user asking them to confirm this delete (indicating
+// either a stripe or a volume set is to be deleted).
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DoDeleteFTSet(
+ IN DWORD ConfirmationMsg
+ )
+{
+ DWORD i;
+ PFT_OBJECT_SET ftSet;
+ PFT_OBJECT ftObject;
+ PREGION_DESCRIPTOR regionDescriptor;
+ WCHAR driveLetter;
+ FT_SET_STATUS setState;
+ ULONG numberOfMembers;
+ BOOL setIsHealthy = TRUE;
+
+ // Attempt to lock this before continuing.
+
+ regionDescriptor = &SELECTED_REGION(0);
+ ftObject = GET_FT_OBJECT(regionDescriptor);
+ ftSet = ftObject->Set;
+
+ LowFtVolumeStatus(regionDescriptor->Disk,
+ regionDescriptor->PartitionNumber,
+ &setState,
+ &numberOfMembers);
+
+ if (ftSet->Status != setState)
+ {
+ ftSet->Status = setState;
+ }
+
+ // Determine if the action is allowed.
+
+ switch (ftSet->Status)
+ {
+ case FtSetDisabled:
+ setIsHealthy = FALSE;
+ break;
+
+ case FtSetInitializing:
+ case FtSetRegenerating:
+
+ ErrorDialog(MSG_CANT_DELETE_INITIALIZING_SET);
+ return;
+
+ default:
+ break;
+ }
+
+ if (CommitToLockList(
+ regionDescriptor,
+ TRUE,
+ setIsHealthy,
+ (ConfirmationMsg == MSG_CONFIRM_BRKANDDEL_MIRROR) // mirror?
+ ? FALSE
+ : TRUE
+ ))
+ {
+ // Could not lock the volume - try again. The file systems
+ // appear to be confused.
+
+ if (CommitToLockList(
+ regionDescriptor,
+ TRUE,
+ setIsHealthy,
+ (ConfirmationMsg == MSG_CONFIRM_BRKANDDEL_MIRROR) // mirror?
+ ? FALSE
+ : TRUE
+ ))
+ {
+ ErrorDialog(MSG_CANNOT_LOCK_TRY_AGAIN);
+ return;
+ }
+ }
+
+ if (IDYES != ConfirmationDialog(
+ ConfirmationMsg,
+ MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2))
+ {
+ return;
+ }
+
+ SetCursor(g_hCurWait);
+
+ FdftDeleteFtObjectSet(ftSet, FALSE);
+
+ for (i=0; i<SelectionCount; i++)
+ {
+ regionDescriptor = &SELECTED_REGION(i);
+
+ if (0 == i)
+ {
+ driveLetter = PERSISTENT_DATA(regionDescriptor)->DriveLetter;
+ }
+ else
+ {
+ FDASSERT(PERSISTENT_DATA(regionDescriptor)->DriveLetter == driveLetter);
+ }
+
+ // Free the pieces of the set.
+
+ DmFreePersistentData(PERSISTENT_DATA(regionDescriptor));
+ DmSetPersistentRegionData(regionDescriptor, NULL);
+ DeletePartition(regionDescriptor);
+ }
+
+ //
+ // Note that one might think to free the drive letter here so that it is
+ // available for other drives to use. BUT! we don't. The reason is that
+ // the change isn't actually committed yet. If the changes aren't committed
+ // we don't want to have let the user reassign the drive letter to any other
+ // drive.
+ //
+
+ CompleteMultiRegionOperation();
+
+ SetCursor(g_hCurNormal);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DoDeleteStripe
+//
+// Synopsis: Deletes a stripe set or a stripe set with parity
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DoDeleteStripe(
+ VOID
+ )
+{
+ DoDeleteFTSet(MSG_CONFIRM_DEL_STRP);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DoBreakAndDeleteMirror
+//
+// Synopsis: Delete both volumes composing a mirror
+//
+// Arguments: (none)
+//
+// Requires: A legal selection (see DetermineSelectionState())
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DoBreakAndDeleteMirror(
+ VOID
+ )
+{
+ DoDeleteFTSet(MSG_CONFIRM_BRKANDDEL_MIRROR);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DoDeleteVolumeSet
+//
+// Synopsis: Delete a volume set
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DoDeleteVolumeSet(
+ VOID
+ )
+{
+ DoDeleteFTSet(MSG_CONFIRM_DEL_VSET);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DoCreateVolumeSet
+//
+// Synopsis: Creates a volume set
+//
+// Arguments: (none)
+//
+// Requires: A legal selection (see DetermineSelectionState())
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DoCreateVolumeSet(
+ VOID
+ )
+{
+ MINMAXDLG_PARAMS params;
+ DWORD creationSize;
+ DWORD size;
+ DWORD maxTotalSize = 0;
+ DWORD totalSizeUsed;
+ DWORD sizeArray[MAX_MEMBERS_IN_FT_SET];
+ PULONG primarySpacesToUseOnDisk;
+ UINT i;
+ PREGION_DESCRIPTOR regionDescriptor;
+ PREGION_DESCRIPTOR regionArray[MAX_MEMBERS_IN_FT_SET];
+ PPERSISTENT_REGION_DATA regionData;
+ WCHAR driveLetter;
+
+ // Make sure that the volume set does not include any
+ // partitions on removable media.
+ //
+ for (i=0; i<SelectionCount; i++)
+ {
+ if (IsDiskRemovable[SELECTED_REGION(i).Disk])
+ {
+ ErrorDialog(MSG_NO_REMOVABLE_IN_VOLUMESET);
+ return;
+ }
+ }
+
+ for (i=0; i<SelectionCount; i++)
+ {
+ FDASSERT(SELECTED_REGION(i).SysID == PARTITION_ENTRY_UNUSED);
+ size = SELECTED_REGION(i).SizeMB;
+ sizeArray[i] = size;
+ maxTotalSize += size;
+ }
+
+ //
+ // Figure out a drive letter.
+ //
+
+ if (!AssignDriveLetter(TRUE, IDS_VOLUMESET, &driveLetter))
+ {
+ return;
+ }
+
+ params.CaptionStringID = IDS_CRTVSET_CAPTION;
+ params.MinimumStringID = IDS_CRTVSET_MIN;
+ params.MaximumStringID = IDS_CRTVSET_MAX;
+ params.SizeStringID = IDS_CRTVSET_SIZE;
+ params.MinSizeMB = SelectionCount;
+ params.MaxSizeMB = maxTotalSize;
+ params.HelpContextId = HC_DM_DLG_CREATEVOLUMESET;
+
+ creationSize = DialogBoxParam(g_hInstance,
+ MAKEINTRESOURCE(IDD_MINMAX),
+ g_hwndFrame,
+ MinMaxDlgProc,
+ (LPARAM)&params
+ );
+
+ if (!creationSize) // user cancelled
+ {
+ return;
+ }
+
+ SetCursor(g_hCurWait);
+
+ //
+ // Determine how large we have to make each member of the volume set.
+ // The percentage of each free space that will be used is the ratio
+ // of the total space he chose to the total free space.
+ //
+ // Example: 2 75 meg free spaces for a total set size of 150 MB.
+ // User chooses a set size of 100 MB. Use 50 MB of each space.
+ //
+ totalSizeUsed = 0;
+
+ for (i=0; i<SelectionCount; i++)
+ {
+ sizeArray[i] = (DWORD)((LONGLONG)sizeArray[i] * creationSize / maxTotalSize);
+ if (((DWORD)((LONGLONG)sizeArray[i] * creationSize % maxTotalSize)))
+ {
+ sizeArray[i]++;
+ }
+
+ if (sizeArray[i] == 0)
+ {
+ sizeArray[i]++;
+ }
+
+ totalSizeUsed += sizeArray[i];
+ }
+
+ // Make sure that the total amount used is not greater than the
+ // maximum amount available. Note that this loop is certain
+ // to terminate because maxTotalSize >= SelectionCount; if
+ // each of the sizes goes down to one, we will exit the loop
+ //
+ while (totalSizeUsed > maxTotalSize)
+ {
+ for (i=0;
+ (i<SelectionCount) && (totalSizeUsed > maxTotalSize);
+ i++)
+ {
+ if (sizeArray[i] > 1)
+ {
+ sizeArray[i]--;
+ totalSizeUsed--;
+ }
+ }
+ }
+
+ //
+ // Make sure that we are allowed to create a partition in the space.
+ //
+ // This is tricky because a volume set could contain more than one
+ // primary partition on a disk -- which means that if we're not careful
+ // we could create a disk with more than 4 primary partitions!
+ //
+
+ primarySpacesToUseOnDisk = (PULONG)Malloc(DiskCount * sizeof(ULONG));
+ RtlZeroMemory(primarySpacesToUseOnDisk, DiskCount * sizeof(ULONG));
+
+ for (i=0; i<SelectionCount; i++)
+ {
+ regionDescriptor = &SELECTED_REGION(i);
+ FDASSERT(regionDescriptor->RegionType != REGION_EXTENDED);
+
+ if (regionDescriptor->RegionType == REGION_PRIMARY)
+ {
+ primarySpacesToUseOnDisk[SelectedDS[i]->Disk]++;
+ }
+
+ if (!( ((regionDescriptor->RegionType == REGION_LOGICAL)
+ && SelectedDS[i]->CreateLogical)
+ || ((regionDescriptor->RegionType == REGION_PRIMARY)
+ && SelectedDS[i]->CreatePrimary)))
+ {
+ Free(primarySpacesToUseOnDisk);
+ SetCursor(g_hCurNormal);
+ ErrorDialog(MSG_CRTSTRP_FULL);
+ return;
+ }
+ }
+
+ //
+ // Look through the array we built to see whether we are supposed to use
+ // more than one primary partition on a given disk. For each such disk,
+ // make sure that we can actually create that many primary partitions.
+ //
+
+ for (i=0; i<DiskCount; i++)
+ {
+ //
+ // If there are not enough primary partition slots, fail.
+ //
+
+ if ((primarySpacesToUseOnDisk[i] > 1)
+ && (PARTITION_TABLE_SIZE - PartitionCount(i) < primarySpacesToUseOnDisk[i]))
+ {
+ Free(primarySpacesToUseOnDisk);
+ SetCursor(g_hCurNormal);
+ ErrorDialog(MSG_CRTSTRP_FULL);
+ return;
+ }
+ }
+
+ Free(primarySpacesToUseOnDisk);
+
+ //
+ // Now actually perform the creation.
+ //
+
+ for (i=0; i<SelectionCount; i++)
+ {
+ regionDescriptor = &SELECTED_REGION(i);
+ FDASSERT(regionDescriptor->RegionType != REGION_EXTENDED);
+
+ CreatePartitionEx(regionDescriptor,
+ RtlConvertLongToLargeInteger(0L),
+ sizeArray[i],
+ regionDescriptor->RegionType,
+ (UCHAR)(PARTITION_HUGE | PARTITION_NTFT)
+ );
+
+ LARGE_INTEGER zero;
+ zero.QuadPart = 0;
+
+ regionData = DmAllocatePersistentData(
+ NULL,
+ L"",
+ wszUnformatted,
+ driveLetter,
+ TRUE,
+ zero,
+ zero
+ );
+
+ DmSetPersistentRegionData(regionDescriptor, regionData);
+
+ regionArray[i] = regionDescriptor;
+ }
+
+ // The zeroth element is the one to assign the drive letter to
+
+ FdftCreateFtObjectSet(VolumeSet, regionArray, SelectionCount, FtSetNew);
+ MarkDriveLetterUsed(driveLetter);
+ CommitToAssignLetterList(&SELECTED_REGION(0), FALSE);
+ CompleteMultiRegionOperation();
+ SetCursor(g_hCurNormal);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DoExtendVolumeSet
+//
+// Synopsis: Adds a partition to a volume set
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DoExtendVolumeSet(
+ VOID
+ )
+{
+ MINMAXDLG_PARAMS params;
+ DWORD currentSize = 0,
+ freeSize = 0,
+ totalFreeSpaceUsed,
+ freeSpaceUsed,
+ maxTotalSize = 0,
+ newSize = 0,
+ sizeTemp;
+ DWORD sizeArray[MAX_MEMBERS_IN_FT_SET];
+ ULONG nonFtPartitionCount = 0,
+ freeRegionCount = 0;
+ PULONG primarySpacesToUseOnDisk;
+ WCHAR driveLetter = L' ';
+ PWSTR typeName = NULL;
+ PWSTR volumeLabel = NULL;
+ ULONG i;
+ DWORD ec;
+ PREGION_DESCRIPTOR regionDescriptor;
+ PREGION_DESCRIPTOR newRegionArray[MAX_MEMBERS_IN_FT_SET];
+ PREGION_DESCRIPTOR convertedRegion;
+ PPERSISTENT_REGION_DATA regionData;
+ PFT_OBJECT_SET ftSet = NULL;
+
+
+ // Make sure that the volume set does not include any
+ // partitions on removable media.
+ //
+ for (i=0; i<SelectionCount; i++)
+ {
+ if (IsDiskRemovable[SELECTED_REGION(i).Disk])
+ {
+ ErrorDialog(MSG_NO_REMOVABLE_IN_VOLUMESET);
+ return;
+ }
+ }
+
+
+ // First, determine the current size of the volume set,
+ // it's file system type and associated drive letter,
+ // and the size of the selected free space
+ //
+ for (i = 0; i < SelectionCount; i++)
+ {
+ regionDescriptor = &(SELECTED_REGION(i));
+
+ sizeTemp = regionDescriptor->SizeMB;
+ sizeArray[i] = sizeTemp;
+ maxTotalSize += sizeTemp;
+
+ if (regionDescriptor->SysID == PARTITION_ENTRY_UNUSED)
+ {
+ // This region is a chunk of free space; include it
+ // in the free space tallies.
+ //
+ newRegionArray[freeRegionCount] = regionDescriptor;
+ sizeArray[freeRegionCount] = sizeTemp;
+
+ freeRegionCount++;
+ freeSize += sizeTemp;
+
+ }
+ else if (NULL != GET_FT_OBJECT(regionDescriptor))
+ {
+ // This is an element of an existing volume set.
+ //
+ currentSize += sizeTemp;
+
+ if (ftSet == NULL)
+ {
+ DetermineRegionInfo( regionDescriptor,
+ &typeName,
+ &volumeLabel,
+ &driveLetter
+ );
+
+ ftSet = GET_FT_OBJECT(regionDescriptor)->Set;
+ }
+ }
+ else
+ {
+ // This is a non-FT partition.
+ //
+ nonFtPartitionCount++;
+ DetermineRegionInfo(regionDescriptor,
+ &typeName,
+ &volumeLabel,
+ &driveLetter);
+ currentSize = sizeTemp;
+ convertedRegion = regionDescriptor;
+ }
+ }
+
+ // Check for consistency: the selection must have either a volume
+ // set or a partition, but not both, and cannot have more than
+ // one non-FT partition.
+ //
+ if ( nonFtPartitionCount > 1
+ || (ftSet != NULL && nonFtPartitionCount != 0)
+ || (ftSet == NULL && nonFtPartitionCount == 0 ) )
+ {
+ return;
+ }
+
+
+ if ( nonFtPartitionCount != 0
+ && NO_ERROR != (ec = DeletionIsAllowed(convertedRegion)) )
+ {
+ // If the error-message is delete-specific, remap it.
+ //
+ switch (ec)
+ {
+#if i386
+ case MSG_CANT_DELETE_ACTIVE0:
+ ec = MSG_CANT_EXTEND_ACTIVE0;
+ break;
+#endif
+ case MSG_CANT_DELETE_WINNT:
+ ec = MSG_CANT_EXTEND_WINNT;
+ break;
+
+ default:
+ break;
+ }
+
+ ErrorDialog(ec);
+ return;
+ }
+
+ if (lstrcmp(typeName, L"NTFS") != 0)
+ {
+ ErrorDialog(MSG_EXTEND_VOLSET_MUST_BE_NTFS);
+ return;
+ }
+
+ params.CaptionStringID = IDS_EXPVSET_CAPTION;
+ params.MinimumStringID = IDS_CRTVSET_MIN;
+ params.MaximumStringID = IDS_CRTVSET_MAX;
+ params.SizeStringID = IDS_CRTVSET_SIZE;
+ params.MinSizeMB = currentSize + freeRegionCount;
+ params.MaxSizeMB = maxTotalSize;
+ params.HelpContextId = HC_DM_DLG_EXTENDVOLUMESET;
+
+ newSize = DialogBoxParam(g_hInstance,
+ MAKEINTRESOURCE(IDD_MINMAX),
+ g_hwndFrame,
+ MinMaxDlgProc,
+ (LPARAM)&params
+ );
+
+ if (!newSize) // user cancelled
+ {
+ return;
+ }
+
+ SetCursor(g_hCurWait);
+
+ // Determine how large to make each new member of the volume
+ // set. The percentage of free space to use is the ratio of
+ // the amount by which the volume set will grow to the total
+ // free space.
+ //
+ freeSpaceUsed = newSize - currentSize;
+ totalFreeSpaceUsed = 0;
+
+ for (i = 0; i < freeRegionCount; i++)
+ {
+ sizeArray[i] = (DWORD)((LONGLONG)sizeArray[i] * freeSpaceUsed/freeSize);
+ if ( (DWORD)(((LONGLONG)sizeArray[i]*freeSpaceUsed) % freeSize) )
+ {
+ sizeArray[i]++;
+ }
+
+ if (sizeArray[i] == 0)
+ {
+ sizeArray[i]++;
+ }
+
+ totalFreeSpaceUsed += sizeArray[i];
+ }
+
+ // Make sure that the total amount of free space used is not
+ // greater than the amount available. Note that this loop is
+ // certain to terminate because the amount of free space used
+ // is >= the number of free regions, so this loop will exit
+ // if one megabyte is used in each free region (the degenerate
+ // case).
+ //
+ while (totalFreeSpaceUsed > freeSize)
+ {
+ for (i = 0;
+ (i < freeRegionCount) && (totalFreeSpaceUsed > freeSize);
+ i++)
+ {
+ if (sizeArray[i] > 1)
+ {
+ sizeArray[i]--;
+ totalFreeSpaceUsed--;
+ }
+ }
+ }
+
+ //
+ // Make sure that we are allowed to create a partition in the space.
+ //
+ // This is tricky because a volume set could contain more than one
+ // primary partition on a disk -- which means that if we're not careful
+ // we could create a disk with more than 4 primary partitions!
+ //
+
+ primarySpacesToUseOnDisk = (PULONG)Malloc(DiskCount * sizeof(ULONG));
+ RtlZeroMemory(primarySpacesToUseOnDisk, DiskCount * sizeof(ULONG));
+
+ for (i=0; i<SelectionCount; i++)
+ {
+ regionDescriptor = &SELECTED_REGION(i);
+
+ if (regionDescriptor->SysID == PARTITION_ENTRY_UNUSED)
+ {
+ FDASSERT(regionDescriptor->RegionType != REGION_EXTENDED);
+
+ if (regionDescriptor->RegionType == REGION_PRIMARY)
+ {
+ primarySpacesToUseOnDisk[SelectedDS[i]->Disk]++;
+ }
+
+ if (!( ((regionDescriptor->RegionType == REGION_LOGICAL)
+ && SelectedDS[i]->CreateLogical)
+ || ((regionDescriptor->RegionType == REGION_PRIMARY)
+ && SelectedDS[i]->CreatePrimary)))
+ {
+ Free(primarySpacesToUseOnDisk);
+ SetCursor(g_hCurNormal);
+ ErrorDialog(MSG_CRTSTRP_FULL);
+ return;
+ }
+ }
+ }
+
+ //
+ // Look through the array we built to see whether we are supposed to use
+ // more than one primary partition on a given disk. For each such disk,
+ // make sure that we can actually create that many primary partitions.
+ //
+
+ for (i=0; i<DiskCount; i++)
+ {
+ //
+ // If there are not enough primary partition slots, fail.
+ //
+
+ if ((primarySpacesToUseOnDisk[i] > 1)
+ && (PARTITION_TABLE_SIZE - PartitionCount(i) < primarySpacesToUseOnDisk[i]))
+ {
+ Free(primarySpacesToUseOnDisk);
+ SetCursor(g_hCurNormal);
+ ErrorDialog(MSG_CRTSTRP_FULL);
+ return;
+ }
+ }
+
+ Free(primarySpacesToUseOnDisk);
+
+ //
+ // Now actually perform the creation.
+ //
+
+ for (i=0; i<freeRegionCount; i++)
+ {
+ regionDescriptor = newRegionArray[i];
+ FDASSERT(regionDescriptor->RegionType != REGION_EXTENDED);
+
+ CreatePartitionEx( regionDescriptor,
+ RtlConvertLongToLargeInteger(0L),
+ sizeArray[i],
+ regionDescriptor->RegionType,
+ (UCHAR)(PARTITION_IFS | PARTITION_NTFT)
+ );
+
+ LARGE_INTEGER zero;
+ zero.QuadPart = 0;
+
+ regionData = DmAllocatePersistentData(
+ NULL,
+ volumeLabel,
+ typeName,
+ driveLetter,
+ TRUE,
+ zero,
+ zero
+ );
+
+ DmSetPersistentRegionData(regionDescriptor, regionData);
+ }
+
+ //
+ // Set the "NewRegion" flag of all the existing partitions to TRUE,
+ // so they get grayed out: we can't perform file system operations on
+ // this volume.
+ //
+
+ if (ftSet)
+ {
+ //
+ // An existing FT set is being expanded
+ //
+
+ for (i=0; i<SelectionCount; i++)
+ {
+ regionDescriptor = &(SELECTED_REGION(i));
+
+ if (GET_FT_OBJECT(regionDescriptor))
+ {
+ //
+ // this region is part of an FT volume set
+ //
+
+ PERSISTENT_DATA(regionDescriptor)->NewRegion = TRUE;
+ }
+ }
+ }
+ else
+ {
+ //
+ // A single-partition volume is to be converted to a volume set
+ // before being expanded
+ //
+
+ PERSISTENT_DATA(convertedRegion)->NewRegion = TRUE;
+ }
+
+ if (nonFtPartitionCount != 0)
+ {
+ // Create the volume set so we can extend it
+ //
+ FdftCreateFtObjectSet(VolumeSet, &convertedRegion, 1, FtSetExtended);
+ ftSet = GET_FT_OBJECT(convertedRegion)->Set;
+
+ // Set the converted region's partition System Id to indicate
+ // that it is now part of a volume set.
+ //
+ SetSysID2(convertedRegion, (UCHAR)(convertedRegion->SysID | PARTITION_NTFT));
+ }
+
+ CommitDueToExtended = TRUE;
+ FdftExtendFtObjectSet(ftSet, newRegionArray, freeRegionCount);
+ CompleteMultiRegionOperation();
+ SetCursor(g_hCurNormal);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DoRecoverStripe
+//
+// Synopsis: Using the global selection information this routine will
+// set up a stripe with parity such that a problem member is
+// regenerated. This new member may either be the problem member
+// (i.e. regeneration is "in place") or new free space on a
+// different disk.
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DoRecoverStripe(
+ VOID
+ )
+{
+ PREGION_DESCRIPTOR freeSpaceRegion = NULL;
+ PREGION_DESCRIPTOR unhealthyRegion = NULL;
+ ULONG freeSpaceIndex = 0;
+ ULONG i;
+ PREGION_DESCRIPTOR regionArray[MAX_MEMBERS_IN_FT_SET];
+ LARGE_INTEGER minimumSize;
+ PFT_OBJECT ftObject;
+
+ // Initialize minimumSize to the maximum possible positive value
+
+ minimumSize.HighPart = 0x7FFFFFFF;
+ minimumSize.LowPart = 0xFFFFFFFF;
+
+ FDASSERT(SelectionCount > 1);
+ FDASSERT(SelectionCount <= MAX_MEMBERS_IN_FT_SET);
+
+ if ( !IsRegionCommitted(&SELECTED_REGION(0))
+ && !IsRegionCommitted(&SELECTED_REGION(1)))
+ {
+ ErrorDialog(MSG_NOT_COMMITTED);
+ return;
+ }
+
+ SetCursor(g_hCurWait);
+
+ //
+ // Determine the exact size of the smallest member of the stripe set.
+ // If the user is regenerating using an additional free space, this
+ // will be the size requirement for the free space.
+ // Also find the free space (if any).
+ // If there is no free space, then we're doing an 'in-place' recover
+ // (ie regnerating into the unhealthy member). If there is a free space,
+ // make sure we are allowed to create a partition or logical drive in it.
+ //
+
+ for (i=0; i<SelectionCount; i++)
+ {
+ regionArray[i] = &SELECTED_REGION(i);
+
+ FDASSERT(!IsExtended(regionArray[i]->SysID));
+
+ if (regionArray[i]->SysID == PARTITION_ENTRY_UNUSED)
+ {
+ PDISKSTATE diskState;
+
+ FDASSERT(freeSpaceRegion == NULL);
+
+ freeSpaceRegion = regionArray[i];
+ freeSpaceIndex = i;
+
+ //
+ // Make sure we are allowed to create a partition or logical
+ // drive in the selected free space.
+ //
+
+ diskState = SelectedDS[freeSpaceIndex];
+
+ if (!( ((freeSpaceRegion->RegionType == REGION_LOGICAL)
+ && diskState->CreateLogical)
+ || ((freeSpaceRegion->RegionType == REGION_PRIMARY)
+ && diskState->CreatePrimary)))
+ {
+ SetCursor(g_hCurNormal);
+ ErrorDialog(MSG_CRTSTRP_FULL);
+ return;
+ }
+ }
+ else
+ {
+ LARGE_INTEGER largeTemp;
+
+ largeTemp = FdGetExactSize(regionArray[i], FALSE);
+ if (largeTemp.QuadPart < minimumSize.QuadPart)
+ {
+ minimumSize = largeTemp;
+ }
+
+ if (GET_FT_OBJECT(regionArray[i])->State != Healthy)
+ {
+ FDASSERT(unhealthyRegion == NULL);
+ unhealthyRegion = regionArray[i];
+ }
+ }
+ }
+
+ //
+ // If there is a free space, place it at item 0 of the regionArray array
+ // to simplify processing later.
+ //
+
+ if (NULL != freeSpaceRegion)
+ {
+ PREGION_DESCRIPTOR tempRegion = regionArray[0];
+ regionArray[0] = regionArray[freeSpaceIndex];
+ regionArray[freeSpaceIndex] = tempRegion;
+ i = 1;
+ }
+ else
+ {
+ i = 0;
+ }
+
+ //
+ // Get a pointer to the FT object for the broken member. Can't do this
+ // in the loop above because the broken member might be on an off-line
+ // disk.
+ //
+
+ for (ftObject = GET_FT_OBJECT(regionArray[i])->Set->Members;
+ NULL != ftObject;
+ ftObject = ftObject->Next)
+ {
+ if (ftObject->State != Healthy)
+ {
+ break;
+ }
+ }
+ FDASSERT(NULL != ftObject);
+
+ //
+ // Determine if the action is allowed.
+ //
+
+ if (NULL != ftObject->Set)
+ {
+ switch (ftObject->Set->Status)
+ {
+ case FtSetInitializing:
+ case FtSetRegenerating:
+
+ ErrorDialog(MSG_CANT_REGEN_INITIALIZING_SET);
+ return;
+
+ default:
+ break;
+ }
+ }
+
+ if (NULL != freeSpaceRegion)
+ {
+ PPERSISTENT_REGION_DATA regionData, regionDataTemp;
+ LARGE_INTEGER temp;
+
+ //
+ // Make sure the free space region is large enough.
+ //
+
+ temp = FdGetExactSize(freeSpaceRegion, FALSE);
+ if (temp.QuadPart < minimumSize.QuadPart)
+ {
+ SetCursor(g_hCurNormal);
+ ErrorDialog(MSG_NOT_LARGE_ENOUGH_FOR_STRIPE);
+ return;
+ }
+
+ //
+ // Create the new partition.
+ //
+
+ CreatePartitionEx(freeSpaceRegion,
+ minimumSize,
+ 0,
+ freeSpaceRegion->RegionType,
+ regionArray[1]->SysID
+ );
+
+ //
+ // Set up the new partition's persistent data
+ //
+
+ regionDataTemp = PERSISTENT_DATA(regionArray[1]);
+
+ regionData = DmAllocatePersistentData(
+ NULL,
+ regionDataTemp->VolumeLabel,
+ regionDataTemp->TypeName,
+ regionDataTemp->DriveLetter,
+ TRUE,
+ regionDataTemp->FreeSpaceInBytes,
+ regionDataTemp->TotalSpaceInBytes
+ );
+
+ regionData->FtObject = ftObject;
+
+ DmSetPersistentRegionData(freeSpaceRegion, regionData);
+
+ // Check to see if member zero of the set changed and
+ // the drive letter needs to move.
+
+ if (0 == ftObject->MemberIndex)
+ {
+ // Move the drive letter to the new region descriptor.
+
+ CommitToAssignLetterList(freeSpaceRegion, TRUE);
+ }
+
+ //
+ // If the unhealthy member is on-line, delete it.
+ // Otherwise remove it from the off-line disk.
+ //
+
+ if (NULL != unhealthyRegion)
+ {
+ DmFreePersistentData(PERSISTENT_DATA(unhealthyRegion));
+ DmSetPersistentRegionData(unhealthyRegion, NULL);
+ DeletePartition(unhealthyRegion);
+ }
+
+ // Remove any offline disks - this doesn't really delete the set
+
+ FdftDeleteFtObjectSet(ftObject->Set, TRUE);
+ }
+
+ ftObject->Set->Ordinal = FdftNextOrdinal(StripeWithParity);
+ ftObject->State = Regenerating;
+ ftObject->Set->Status = FtSetRecovered;
+ RegistryChanged = TRUE;
+ CompleteMultiRegionOperation();
+ SetCursor(g_hCurNormal);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DoRefresh
+//
+// Synopsis: Reload the persistent volume data for all regions
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 7-Dec-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DoRefresh(
+ VOID
+ )
+{
+ SetCursor(g_hCurWait);
+
+ InitVolumeInformation();
+ RefreshAllCdRomData();
+
+ //
+ // Now refresh the view. It is likely that the free space and %free
+ // numbers have changed, so refreshing the listview makes sense.
+ // Refreshing the disks view makes sense if the user has done a
+ // format and wants to see the new label/FS.
+ //
+
+ RefreshBothViews();
+ AdjustMenuAndStatus();
+
+ SetCursor(g_hCurNormal);
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: RefreshBothViews
+//
+// Synopsis: Redraws both views
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 7-Dec-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+RefreshBothViews(
+ VOID
+ )
+{
+ FillListView(TRUE); // Volumes view
+ TotalRedrawAndRepaint(); // Disks view
+ UpdateStatusBarDisplay();
+}
diff --git a/private/utils/windisk/src/ops.hxx b/private/utils/windisk/src/ops.hxx
new file mode 100644
index 000000000..0f5426d3a
--- /dev/null
+++ b/private/utils/windisk/src/ops.hxx
@@ -0,0 +1,114 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: ops.hxx
+//
+// Contents: Main operations: Create partition, etc.
+//
+// History: 4-Mar-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+#ifndef __OPS_HXX__
+#define __OPS_HXX__
+
+////////////////////////////////////////////////////////////////////////////
+
+VOID
+CompleteSingleRegionOperation(
+ IN PDISKSTATE DiskState
+ );
+
+VOID
+CompleteMultiRegionOperation(
+ VOID
+ );
+
+VOID
+CompleteDriveLetterChange(
+ IN WCHAR NewDriveLetter
+ );
+
+VOID
+DoSetDriveLetter(
+ VOID
+ );
+
+VOID
+DoCreate(
+ IN REGION_TYPE CreationType
+ );
+
+VOID
+DoDelete(
+ VOID
+ );
+
+VOID
+DoMakeActive(
+ VOID
+ );
+
+VOID
+DoProtectSystemPartition(
+ VOID
+ );
+
+VOID
+DoEstablishMirror(
+ VOID
+ );
+
+VOID
+DoBreakMirror(
+ VOID
+ );
+
+VOID
+DoBreakAndDeleteMirror(
+ VOID
+ );
+
+VOID
+DoCreateStripe(
+ IN BOOL Parity
+ );
+
+VOID
+DoDeleteStripe(
+ VOID
+ );
+
+VOID
+DoCreateVolumeSet(
+ VOID
+ );
+
+VOID
+DoExtendVolumeSet(
+ VOID
+ );
+
+VOID
+DoDeleteVolumeSet(
+ VOID
+ );
+
+VOID
+DoRecoverStripe(
+ VOID
+ );
+
+VOID
+DoRefresh(
+ VOID
+ );
+
+VOID
+RefreshBothViews(
+ VOID
+ );
+
+#endif // __OPS_HXX__
diff --git a/private/utils/windisk/src/popup.cxx b/private/utils/windisk/src/popup.cxx
new file mode 100644
index 000000000..e51767bc7
--- /dev/null
+++ b/private/utils/windisk/src/popup.cxx
@@ -0,0 +1,96 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: popup.cxx
+//
+// Contents: Implementation of popup menu functions.
+//
+// Functions: TrackModalPopupMenu
+//
+// History: 16-Aug-93 BruceFo Created from JohnEls code
+//
+//--------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include "popup.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: TrackModalPopupMenu, public
+//
+// Synopsis: Displays a popup menu and returns the user's choice.
+//
+// Arguments: [hMenu] -- The popup menu to display.
+// [dwFlags] -- Flags (see flags for [TrackPopupMenu()].
+// [x], [y] -- Menu position, in screen coordinates.
+// [nReserved] -- Reserved. Must be 0.
+// [lpReserved] -- Reserved. Must be NULL.
+//
+// Returns: The ID corresponding to the menu item chosen by the user.
+// If the user cancels the menu, -1 is returned. If the
+// attempt to display the menu fails, -2 is returned.
+//
+// History: 05-Mar-92 JohnEls Created.
+//
+//--------------------------------------------------------------------------
+
+INT
+TrackModalPopupMenu(
+ HMENU hMenu,
+ UINT dwFlags,
+ int x,
+ int y,
+ int nReserved,
+ LPRECT prc
+ )
+{
+ INT ret;
+
+ if (TrackPopupMenu(
+ hMenu,
+ dwFlags,
+ x,
+ y,
+ nReserved,
+ g_hwndFrame,
+ prc))
+ {
+ MSG msg;
+
+ //
+ // Look for a WM_COMMAND message in the queue. If there is none,
+ // then the user cancelled the menu.
+ //
+
+ if (PeekMessage(
+ &msg,
+ g_hwndFrame,
+ WM_COMMAND,
+ WM_COMMAND,
+ PM_NOREMOVE | PM_NOYIELD))
+ {
+ ret = LOWORD(msg.wParam);
+ }
+ else
+ {
+ ret = -1;
+ }
+ }
+ else
+ {
+ //
+ // Failed to display the menu.
+ //
+
+ ret = -2;
+ }
+
+ return ret;
+}
diff --git a/private/utils/windisk/src/popup.hxx b/private/utils/windisk/src/popup.hxx
new file mode 100644
index 000000000..65e3acbcf
--- /dev/null
+++ b/private/utils/windisk/src/popup.hxx
@@ -0,0 +1,29 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: popup.hxx
+//
+// Contents: Declaration of popup menu functions.
+//
+// History: 16-Aug-93 BruceFo Created from JohnEls code
+//
+//--------------------------------------------------------------------------
+
+#ifndef __POPUP_HXX__
+#define __POPUP_HXX__
+
+//////////////////////////////////////////////////////////////////////////////
+
+INT
+TrackModalPopupMenu(
+ IN HMENU hMenu,
+ IN UINT dwFlags,
+ IN int x,
+ IN int y,
+ IN int nReserved,
+ IN LPRECT prc
+ );
+
+#endif // __POPUP_HXX__
diff --git a/private/utils/windisk/src/print.cxx b/private/utils/windisk/src/print.cxx
new file mode 100644
index 000000000..105cdc515
--- /dev/null
+++ b/private/utils/windisk/src/print.cxx
@@ -0,0 +1,338 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: print.cxx
+//
+// Contents: Disk Administrator file system extension class. Code to
+// print the results of chkdsk.
+//
+// History: 15-Dec-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include <ctype.h>
+#include <commdlg.h>
+
+#include "resids.h"
+#include "dialogs.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+BOOL CALLBACK
+PrintDlgProc(
+ HWND hDlg,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+ );
+
+BOOL CALLBACK
+AbortProc(
+ HDC hPrinterDC,
+ int iError
+ );
+
+//////////////////////////////////////////////////////////////////////////////
+
+BOOL bUserAbort ;
+HWND hDlgPrint ;
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: PrintDlgProc
+//
+// Synopsis: the "Printing..." w/ cancel button dialog box
+//
+// Arguments: standard DialogProc
+//
+// Returns: standard DialogProc
+//
+// History: 15-Dec-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+BOOL CALLBACK
+PrintDlgProc(
+ HWND hDlg,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam
+ )
+{
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ EnableMenuItem(GetSystemMenu(hDlg, FALSE), SC_CLOSE, MF_GRAYED);
+ return TRUE;
+
+ case WM_COMMAND:
+ bUserAbort = TRUE;
+ EnableWindow(GetParent(hDlg), TRUE);
+ DestroyWindow(hDlg);
+ hDlgPrint = NULL;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: AbortProc
+//
+// Synopsis: Abort procedure for the print code
+//
+// Arguments: standard AbortProc
+//
+// Returns: standard AbortProc
+//
+// History: 15-Dec-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+BOOL CALLBACK
+AbortProc(
+ HDC hPrinterDC,
+ int iError
+ )
+{
+ MSG msg ;
+
+ while (!bUserAbort && PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ if (!hDlgPrint || !IsDialogMessage (hDlgPrint, &msg))
+ {
+ TranslateMessage (&msg) ;
+ DispatchMessage (&msg) ;
+ }
+ }
+ return !bUserAbort ;
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: PrintString
+//
+// Synopsis: Prints a null-terminated string to the printer
+//
+// Arguments: [hwndParent] -- handle to parent window
+// [Buf] -- buffer to print
+//
+// Returns: TRUE on success, FALSE on failure
+//
+// History: 15-Dec-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+BOOL
+PrintString(
+ HWND hwndParent,
+ LPSTR Buf
+ )
+{
+ static PRINTDLG pd;
+
+ PCHAR pCurrent;
+ PCHAR pCurrentPage;
+ INT nCharsThisLine;
+
+ BOOL bSuccess ;
+ WCHAR szJobName [60] ;
+ PSTR pstrBuffer ;
+ INT yChar, nCharsPerLine, nLinesPerPage, nPage, nLine;
+ TEXTMETRIC tm ;
+ WORD nColCopy, nNonColCopy ;
+ DOCINFO di;
+
+ //////////////////////////////////////////////////////////////////
+
+ pd.lStructSize = sizeof (PRINTDLG) ;
+ pd.hwndOwner = hwndParent ;
+ pd.hDevMode = NULL ;
+ pd.hDevNames = NULL ;
+ pd.hDC = NULL ;
+ pd.Flags = PD_ALLPAGES
+ | PD_DISABLEPRINTTOFILE
+ | PD_NOPAGENUMS
+ | PD_NOSELECTION
+ | PD_COLLATE
+ | PD_RETURNDC
+ ;
+
+ pd.nFromPage = 0 ;
+ pd.nToPage = 0 ;
+ pd.nMinPage = 0 ;
+ pd.nMaxPage = 0 ;
+ pd.nCopies = 1 ;
+ pd.hInstance = NULL ;
+ pd.lCustData = 0L ;
+ pd.lpfnPrintHook = NULL ;
+ pd.lpfnSetupHook = NULL ;
+ pd.lpPrintTemplateName = NULL ;
+ pd.lpSetupTemplateName = NULL ;
+ pd.hPrintTemplate = NULL ;
+ pd.hSetupTemplate = NULL ;
+
+ if (!PrintDlg (&pd))
+ {
+ return FALSE ;
+ }
+
+ //
+ // Now print it
+ //
+
+ GetTextMetrics (pd.hDC, &tm) ;
+ yChar = tm.tmHeight + tm.tmExternalLeading ;
+ nCharsPerLine = GetDeviceCaps (pd.hDC, HORZRES) / tm.tmAveCharWidth ;
+ nLinesPerPage = GetDeviceCaps (pd.hDC, VERTRES) / yChar ;
+
+ pstrBuffer = new CHAR[nCharsPerLine + 1];
+ if (NULL == pstrBuffer)
+ {
+ return FALSE;
+ }
+
+ EnableWindow (hwndParent, FALSE) ;
+
+ bSuccess = TRUE ;
+ bUserAbort = FALSE ;
+
+ hDlgPrint = CreateDialog(
+ g_hInstance,
+ MAKEINTRESOURCE(IDD_CHKPRINT),
+ hwndParent,
+ PrintDlgProc);
+
+ SetAbortProc(pd.hDC, AbortProc);
+
+ LoadString(g_hInstance, IDS_CHK_TITLE, szJobName, ARRAYLEN(szJobName));
+
+ di.cbSize = sizeof(DOCINFO);
+ di.lpszDocName = szJobName;
+ di.lpszOutput = NULL;
+
+ if (StartDoc(pd.hDC, &di) > 0)
+ {
+ for (nColCopy = 0 ;
+ nColCopy < (pd.Flags & PD_COLLATE ? pd.nCopies : 1) ;
+ nColCopy++)
+ {
+ pCurrentPage = Buf;
+
+ for (nPage = 0 ; '\0' != *pCurrentPage; nPage++)
+ {
+ for (nNonColCopy = 0 ;
+ nNonColCopy < (pd.Flags & PD_COLLATE ? 1 : pd.nCopies);
+ nNonColCopy++)
+ {
+ pCurrent = pCurrentPage;
+
+ if (SP_ERROR == StartPage(pd.hDC))
+ {
+ bSuccess = FALSE ;
+ break ;
+ }
+
+ for (nLine = 0 ;
+ '\0' != *pCurrent && nLine < nLinesPerPage ;
+ nLine++)
+ {
+ nCharsThisLine = 0;
+
+ while ( ('\0' != *pCurrent)
+ && ('\n' != *pCurrent)
+ && (nCharsThisLine < nCharsPerLine)
+ )
+ {
+ if (isprint(*pCurrent)) // only printable chars...
+ {
+ pstrBuffer[nCharsThisLine++] = *pCurrent;
+ }
+
+ pCurrent++;
+ }
+
+ if ('\n' == *pCurrent)
+ {
+ pCurrent++;
+ }
+
+ if (nCharsThisLine > 0)
+ {
+ TextOutA(
+ pd.hDC,
+ 0,
+ yChar * nLine,
+ pstrBuffer,
+ nCharsThisLine
+ );
+ }
+
+ if (bUserAbort)
+ {
+ break ;
+ }
+ }
+
+ if (SP_ERROR == EndPage(pd.hDC))
+ {
+ bSuccess = FALSE ;
+ break ;
+ }
+
+ if (bUserAbort)
+ {
+ break ;
+ }
+ }
+
+ if (!bSuccess || bUserAbort)
+ {
+ break ;
+ }
+
+ pCurrentPage = pCurrent;
+ }
+
+ if (!bSuccess || bUserAbort)
+ {
+ break ;
+ }
+ }
+ }
+ else
+ {
+ bSuccess = FALSE ;
+ }
+
+ if (bSuccess)
+ {
+ EndDoc(pd.hDC);
+ }
+
+ if (!bUserAbort)
+ {
+ EnableWindow (hwndParent, TRUE) ;
+ DestroyWindow (hDlgPrint) ;
+ }
+
+ delete[] pstrBuffer;
+ DeleteDC(pd.hDC);
+
+ return bSuccess && !bUserAbort ;
+}
diff --git a/private/utils/windisk/src/print.hxx b/private/utils/windisk/src/print.hxx
new file mode 100644
index 000000000..487bf5cb6
--- /dev/null
+++ b/private/utils/windisk/src/print.hxx
@@ -0,0 +1,23 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: print.hxx
+//
+// Contents: Print a buffer to the printer
+//
+// History: 14-Jan-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __PRINT_HXX__
+#define __PRINT_HXX__
+
+BOOL
+PrintString(
+ HWND hwnd,
+ LPSTR Buf
+ );
+
+#endif // __PRINT_HXX__
diff --git a/private/utils/windisk/src/profile.cxx b/private/utils/windisk/src/profile.cxx
new file mode 100644
index 000000000..a87b0b458
--- /dev/null
+++ b/private/utils/windisk/src/profile.cxx
@@ -0,0 +1,598 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: profile.cxx
+//
+// Contents: Routines to read and write profile settings. Settings that
+// are saved include the window position, whether it is maximized
+// or not, iconic or not, which view is active, whether the
+// toolbar, status bar, and legend is visible, and the chosen
+// color/pattern scheme.
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include <stdio.h>
+
+#include "profile.hxx"
+#include "tb.h"
+#include "tbar.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+#define CURRENT_VERSION 2
+
+//////////////////////////////////////////////////////////////////////////////
+
+int ProfileWindowX,
+ ProfileWindowY,
+ ProfileWindowW,
+ ProfileWindowH;
+
+//
+// Save the delta values of the workarea, so that we can avoid the task bar.
+//
+int deltaProfileWindowX,
+ deltaProfileWindowY,
+ deltaProfileWindowW,
+ deltaProfileWindowH;
+
+BOOL ProfileIsMaximized;
+BOOL ProfileIsIconic;
+
+CHAR szMainSection[] = "Disk Administrator";
+
+CHAR szVersion[] = "Version";
+CHAR szWindowPosition[] = "WindowPosition";
+CHAR szWindowMaximized[] = "WindowMaximized";
+CHAR szWindowIconic[] = "WindowIconic";
+CHAR szWindowPosFormatString[] = "%d, %d, %d, %d";
+CHAR szWhichView[] = "WhichView";
+CHAR szToolbar[] = "Toolbar";
+CHAR szStatusBar[] = "StatusBar";
+CHAR szLegend[] = "Legend";
+CHAR szDiskSizing[] = "DiskSizing";
+CHAR szElementN[] = "Element %u Color/Pattern";
+
+CHAR szIniFile[] = "windisk.ini";
+WCHAR wszIniFile[] = L"windisk.ini";
+CHAR szIniFilePath[] = "Software\\Microsoft\\Windows NT\\CurrentVersion\\IniFileMapping\\windisk.ini";
+CHAR szIniFileMapping[] = "USR:Software\\Microsoft\\Disk Administrator";
+
+CHAR szSectionLocation[] = "Software\\Microsoft\\Disk Administrator";
+
+TCHAR tszToolbarSettings[] = TEXT("Toolbar Settings");
+TCHAR tszSubKey[] = TEXT("Software\\Microsoft\\Disk Administrator");
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// In NT 3.1, NT 3.5, and NT 3.51, there was no "Version" number in the
+// profile. In NT 4.0, we introduced a version entry, which is an integer
+// only used by Disk Administrator. Here is what that version number means:
+//
+// Version # Version of NT
+// --------- -------------
+// non-existent 3.1, 3.5, or 3.51
+// 2 4.0
+//
+//////////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////////
+
+//
+// The colors/patterns values are stored in the registry in "Element N
+// Color/Pattern:". In NT before 4.0, there were 5 colors/patterns, identified
+// as follows:
+//
+// registry "element" number / NT 4.0 internal index
+//
+// 0/0 -- used primary partition
+// 1/1 -- logical drive
+// 2/2 -- stripe set
+// 3/4 -- mirror
+// 4/5 -- volume set
+//
+// In NT 4.0, there are 6 values. An additional value exists for
+// "stripe set with parity":
+//
+// 5/3 -- stripe set with parity
+//
+// This appears in the legend after "stripe set". However, to maintain
+// backwards compatibility with the registry layout for NT before 4.0, we must
+// only add element numbers to the end.
+//
+// The mapRegistryToInternal array takes as index the Color/Pattern
+// number used in the registry (from the list above), and returns the
+// internal "brush" number.
+//
+// NOTE: you can only add to the *END* of this array to maintain
+// compatibility.
+//
+
+int mapRegistryToInternal[] =
+{
+ BRUSH_USEDPRIMARY,
+ BRUSH_USEDLOGICAL,
+ BRUSH_STRIPESET,
+ BRUSH_MIRROR,
+ BRUSH_VOLUMESET,
+ BRUSH_PARITYSET
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+//
+// In NT 3.5, it was decided to drop support for undocumented hatch styles
+// of which windisk was apparently the only user, including the undocumented
+// solid hatch. However, in NT 3.1 we stored the hatch index in the user
+// profile. To avoid having things show up really weird for the user, we
+// map all stored non-supported hatches to the new solid hatch.
+//
+// The registry basically stores the BrushHatches[] array, which is an
+// array of indices into the AvailableHatches array of hatch numbers.
+//
+// NT 3.1:
+//
+// int AvailableHatches[NUM_AVAILABLE_HATCHES] =
+// {
+// 2, /* \\\\\ */
+// 3, // /////
+// 4, // +++++
+// 5, // xxxxx
+// 16, // dots
+// 14, // mini-plusses
+// 12, // denser plusses
+// 10, // even denser plusses
+// 8 // solid
+// };
+//
+// NT 3.5:
+//
+// int AvailableHatches[NUM_AVAILABLE_HATCHES] =
+// {
+// 2, /* \\\\\ */
+// 3, // /////
+// 4, // +++++
+// 5, // xxxxx
+// 6, // this appears to be solid, but isn't documented
+// };
+//
+// new:
+//
+// int AvailableHatches[NUM_AVAILABLE_HATCHES] =
+// {
+// MY_HS_FDIAGONAL, /* \\\\\ */
+// MY_HS_BDIAGONAL, // /////
+// MY_HS_CROSS, // +++++
+// MY_HS_DIAGCROSS, // xxxxx
+// MY_HS_VERTICAL, // |||||
+// MY_HS_SOLIDCLR // solid
+// };
+//
+// To convert, use the following logic:
+//
+// for hatch 'i':
+// if (there is no "Version" attribute)
+// {
+// if (i >= 4)
+// {
+// i = 5; // current index to MY_HS_SOLIDCLR
+// }
+// }
+//
+// Note that index 4 in NT 3.1 will be magically transformed from dots to
+// solid... oh well.
+//
+
+//////////////////////////////////////////////////////////////////////////////
+
+VOID
+SetupIniFileMapping(
+ VOID
+ );
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: SetupIniFileMapping
+//
+// Synopsis: Ensure the INI-file mapping exists. The mapping is only
+// set up once per session; subsequent calls are no-ops.
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 2-Sep-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+SetupIniFileMapping(
+ VOID
+ )
+{
+ static BOOL fMappingCreated = FALSE;
+
+ if (!fMappingCreated)
+ {
+ fMappingCreated = TRUE; // don't try again if there are any errors
+
+ DWORD Disposition;
+ HKEY Key1, Key2;
+ LONG Err;
+
+ Err = RegCreateKeyExA( HKEY_LOCAL_MACHINE,
+ szIniFilePath,
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_WRITE,
+ NULL,
+ &Key1,
+ &Disposition );
+
+ if (Err != ERROR_SUCCESS)
+ {
+ return;
+ }
+
+ if (Disposition == REG_CREATED_NEW_KEY)
+ {
+ //
+ // Set up the registry keys for the INI mapping.
+ //
+ // First, create the "Disk Administrator" value on the windisk.ini
+ // key, which indicates the location of the key which maps
+ // the "Disk Administrator" section.
+ //
+
+ Err = RegSetValueExA(Key1,
+ szMainSection,
+ 0,
+ REG_SZ,
+ (LPBYTE)szIniFileMapping,
+ (lstrlenA(szIniFileMapping) + 1) * sizeof(CHAR));
+
+ if (Err != ERROR_SUCCESS)
+ {
+ RegCloseKey( Key1 );
+ return;
+ }
+
+ //
+ // Now create the key to which the section mapping points:
+ //
+ Err = RegCreateKeyExA(HKEY_CURRENT_USER,
+ szSectionLocation,
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_WRITE,
+ NULL,
+ &Key2,
+ &Disposition);
+
+ if (Err != ERROR_SUCCESS)
+ {
+ RegCloseKey(Key1);
+ return;
+ }
+
+ RegCloseKey(Key2);
+ }
+
+ //
+ // Now, we have a windisk.ini INI-file mapping. In Windows NT 3.1
+ // we have a "Disk Administrator" section mapping to
+ // HKEY_CURRENT_USER\Software\Microsoft\Disk Administrator, under
+ // which are a bunch of name/value pairs. We really should have just
+ // mapped the whole file there, which we will do now. Anything with
+ // a section name other than "Disk Administrator" will get a key under
+ // the "Disk Administrator" key, and its values go below that.
+ //
+ // We really only need to do this if the value doesn't already exist
+ // (i.e., for previous installations of NT), but it is cheaper (I think)
+ // to just do it everytime for everybody.
+ //
+
+ Err = RegSetValueExA(Key1,
+ NULL,
+ 0,
+ REG_SZ,
+ (LPBYTE)szIniFileMapping,
+ (strlen(szIniFileMapping) + 1) * sizeof(CHAR));
+
+ if (Err != ERROR_SUCCESS)
+ {
+ RegCloseKey(Key1);
+ return;
+ }
+
+ RegCloseKey(Key1);
+
+ //
+ // Now flush the ini-file mapping cache
+ //
+
+ WritePrivateProfileStringW(NULL, NULL, NULL, wszIniFile);
+ }
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: WriteProfile
+//
+// Synopsis: Write Disk Administrator settings to the registry
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+WriteProfile(
+ VOID
+ )
+{
+ CHAR text[100], text2[100];
+ int i;
+ UINT version;
+
+ SetupIniFileMapping();
+
+ version = (UINT)GetPrivateProfileIntA(szMainSection, szVersion, 0, szIniFile);
+ if (version > CURRENT_VERSION)
+ {
+ // The user has run a later version of Disk Administrator. Don't save
+ // their profile, for fear of corrupting the later version's
+ // profile structure.
+
+ return;
+ }
+
+ // OK, the registry location is set up. Write the initialization
+ // information.
+ //
+
+ wsprintfA(text, "%u", CURRENT_VERSION);
+ WritePrivateProfileStringA(szMainSection, szVersion, text, szIniFile);
+
+ // write window position
+
+ wsprintfA(text,
+ szWindowPosFormatString,
+ ProfileWindowX,
+ ProfileWindowY,
+ ProfileWindowW,
+ ProfileWindowH
+ );
+ WritePrivateProfileStringA(szMainSection, szWindowPosition, text, szIniFile);
+ wsprintfA(text, "%u", IsZoomed(g_hwndFrame));
+ WritePrivateProfileStringA(szMainSection, szWindowMaximized, text, szIniFile);
+ wsprintfA(text, "%u", IsIconic(g_hwndFrame));
+ WritePrivateProfileStringA(szMainSection, szWindowIconic, text, szIniFile);
+
+ //
+ // Which View
+ //
+ wsprintfA(text, "%u", g_WhichView);
+ WritePrivateProfileStringA(szMainSection, szWhichView, text, szIniFile);
+
+ //
+ // Whether disks are sized equally or proportionally
+ //
+
+ wsprintfA(text, "%u", g_DiskDisplayType);
+ WritePrivateProfileStringA(szMainSection, szDiskSizing, text, szIniFile);
+
+ // toolbar, status bar and legend stuff
+
+ wsprintfA(text, "%u", g_Toolbar);
+ WritePrivateProfileStringA(szMainSection, szToolbar, text, szIniFile);
+
+ wsprintfA(text, "%u", g_StatusBar);
+ WritePrivateProfileStringA(szMainSection, szStatusBar, text, szIniFile);
+
+ wsprintfA(text, "%u", g_Legend);
+ WritePrivateProfileStringA(szMainSection, szLegend, text, szIniFile);
+
+ // disk graph colors/patterns
+
+ for (i=0; i<LEGEND_STRING_COUNT; i++)
+ {
+ wsprintfA(text2, szElementN, i);
+
+ int iInternal = mapRegistryToInternal[i];
+
+ wsprintfA(
+ text,
+ "%u/%u",
+ BrushColors[iInternal],
+ BrushHatches[iInternal]
+ );
+
+ WritePrivateProfileStringA(szMainSection, text2, text, szIniFile);
+ }
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: ReadProfile
+//
+// Synopsis: Read Disk Administrator settings from the registry
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+ReadProfile(
+ VOID
+ )
+{
+ CHAR text[100], text2[100];
+ int i;
+ UINT version;
+
+ version = (UINT)GetPrivateProfileIntA(szMainSection, szVersion, 0, szIniFile);
+ if (version > CURRENT_VERSION)
+ {
+ // The user has run a more recent version of windisk; ignore the
+ // profile, for fear of reading or writing bad values. Set defaults.
+
+ ProfileIsMaximized = FALSE;
+ ProfileIsIconic = FALSE;
+ ProfileWindowX = CW_USEDEFAULT;
+ ProfileWindowY = 0;
+ ProfileWindowW = CW_USEDEFAULT;
+ ProfileWindowH = 0;
+
+ g_WhichView = VIEW_DISKS;
+ g_DiskDisplayType = DiskProportional;
+ g_Toolbar = TRUE;
+ g_StatusBar = TRUE;
+ g_Legend = TRUE;
+
+ // BrushHatches already has a default
+
+ return;
+ }
+
+ // get the window position data
+
+ ProfileIsMaximized = GetPrivateProfileIntA(szMainSection, szWindowMaximized, 0, szIniFile);
+ ProfileIsIconic = GetPrivateProfileIntA(szMainSection, szWindowIconic , 0, szIniFile);
+
+ *text = 0;
+ if (GetPrivateProfileStringA(
+ szMainSection,
+ szWindowPosition,
+ "",
+ text,
+ ARRAYLEN(text),
+ szIniFile)
+ && *text)
+ {
+ sscanf(text,
+ szWindowPosFormatString,
+ &ProfileWindowX,
+ &ProfileWindowY,
+ &ProfileWindowW,
+ &ProfileWindowH
+ );
+
+
+ }
+ else
+ {
+ ProfileWindowX = CW_USEDEFAULT;
+ ProfileWindowY = 0;
+ ProfileWindowW = CW_USEDEFAULT;
+ ProfileWindowH = 0;
+ }
+
+ g_WhichView = (VIEW_TYPE)GetPrivateProfileIntA(szMainSection, szWhichView, VIEW_DISKS, szIniFile);
+ g_DiskDisplayType = (DISK_TYPE)GetPrivateProfileIntA(szMainSection, szDiskSizing, DiskProportional, szIniFile);
+
+ // toolbar, status bar and legend stuff
+
+ g_Toolbar = GetPrivateProfileIntA(szMainSection, szToolbar , TRUE, szIniFile);
+ g_StatusBar = GetPrivateProfileIntA(szMainSection, szStatusBar, TRUE, szIniFile);
+ g_Legend = GetPrivateProfileIntA(szMainSection, szLegend , TRUE, szIniFile);
+
+ // disk graph colors/patterns
+
+ for (i=0; i<LEGEND_STRING_COUNT; i++)
+ {
+ wsprintfA(text2, szElementN, i);
+
+ *text = 0;
+ if (GetPrivateProfileStringA(
+ szMainSection,
+ text2,
+ "",
+ text,
+ ARRAYLEN(text),
+ szIniFile)
+ && *text)
+ {
+ int iInternal = mapRegistryToInternal[i];
+ int registryHatchIndex;
+
+ sscanf(
+ text,
+ "%u/%u",
+ &BrushColors[iInternal],
+ &registryHatchIndex
+ );
+
+ // map registry hatch data as necessary
+ if (version < 2)
+ {
+ if (registryHatchIndex >= 4)
+ {
+ registryHatchIndex = 5;
+ }
+ }
+
+ BrushHatches[iInternal] = registryHatchIndex;
+ }
+ }
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: SaveRestoreToolbar
+//
+// Synopsis: save or restore the toolbar
+//
+// Arguments: [bSave] -- TRUE to save the toolbar, FALSE to restore it
+//
+// Returns: nothing
+//
+// History: 2-Sep-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+SaveRestoreToolbar(
+ BOOL bSave
+ )
+{
+ SetupIniFileMapping();
+
+ TBSAVEPARAMS tbsp;
+ tbsp.hkr = HKEY_CURRENT_USER;
+ tbsp.pszSubKey = TEXT("Software\\Microsoft\\Disk Administrator");
+ tbsp.pszValueName = TEXT("Toolbar Settings");
+
+ BOOL bSuccess = Toolbar_SaveRestore(g_hwndToolbar, bSave, &tbsp);
+
+ if (!bSuccess && !bSave)
+ {
+ ResetToolbar();
+ SaveRestoreToolbar(TRUE);
+ }
+}
diff --git a/private/utils/windisk/src/profile.hxx b/private/utils/windisk/src/profile.hxx
new file mode 100644
index 000000000..ecc29a804
--- /dev/null
+++ b/private/utils/windisk/src/profile.hxx
@@ -0,0 +1,32 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: profile.hxx
+//
+// Contents: Routines to load/save the profile
+//
+// History: 2-Sep-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __PROFILE_HXX__
+#define __PROFILE_HXX__
+
+VOID
+WriteProfile(
+ VOID
+ );
+
+VOID
+ReadProfile(
+ VOID
+ );
+
+VOID
+SaveRestoreToolbar(
+ BOOL bSave
+ );
+
+#endif // __PROFILE_HXX__
diff --git a/private/utils/windisk/src/proto.hxx b/private/utils/windisk/src/proto.hxx
new file mode 100644
index 000000000..dea854fce
--- /dev/null
+++ b/private/utils/windisk/src/proto.hxx
@@ -0,0 +1,468 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: proto.hxx
+//
+// Contents: Global macros and function prototypes
+//
+// History: 7-Jan-92 TedM Created
+// 2-Feb-94 BobRi Moved arcinst definitions here
+//
+//----------------------------------------------------------------------------
+
+#ifndef __PROTO_HXX__
+#define __PROTO_HXX__
+
+////////////////////////////////////////////////////////////////////////////
+
+//
+// Returns the i'th selected region, where 0 <= i < SelectionCount
+//
+// REGION_DESCRIPTOR
+// SELECTED_REGION(
+// IN INT i
+// );
+//
+
+#define SELECTED_REGION(i) (SelectedDS[i]->RegionArray[SelectedRG[i]])
+
+//
+// Given a drive letter (from C to Z), calculate a 0-based index to use
+// in array indexing.
+//
+// UINT
+// DriveLetterToIndex(
+// IN WCHAR DriveLetter
+// );
+//
+
+#define DriveLetterToIndex(DriveLetter) ((DriveLetter) - L'C')
+
+//
+// BOOLEAN
+// IsLegalDriveLetter(
+// IN WCHAR DriveLetter
+// );
+//
+
+#define IsLegalDriveLetter(DriveLetter) \
+ ( ((DriveLetter) >= L'C') && ((DriveLetter) <= L'Z') )
+
+//
+// BOOLEAN
+// IsExtraDriveLetter(
+// IN WCHAR DriveLetter
+// );
+//
+
+#define IsExtraDriveLetter(DriveLetter) \
+ ( ((DriveLetter) == NO_DRIVE_LETTER_YET) \
+ || ((DriveLetter) == NO_DRIVE_LETTER_EVER) \
+ )
+
+//
+// BOOLEAN
+// DmSignificantRegion(
+// IN PREGION_DESCRIPTOR RegionDescriptor
+// );
+//
+
+#define DmSignificantRegion(RegionDescriptor) \
+ (((RegionDescriptor)->SysID != PARTITION_ENTRY_UNUSED) \
+ && (!IsExtended((RegionDescriptor)->SysID)) \
+ && (IsRecognizedPartition((RegionDescriptor)->SysID)))
+
+//
+// VOID
+// DmSetPersistentRegionData(
+// IN PREGION_DESCRIPTOR RegionDescriptor,
+// IN PPERSISTENT_REGION_DATA RegionData
+// );
+//
+
+#define DmSetPersistentRegionData(RegionDescriptor,RegionData) \
+ FdSetPersistentData((RegionDescriptor),RegionData); \
+ (RegionDescriptor)->PersistentData = RegionData
+
+
+//
+// VOID
+// DmInitPersistentRegionData(
+// OUT PPERSISTENT_REGION_DATA RegionData,
+// IN PFT_OBJECT ftObject,
+// IN PWSTR volumeLabel,
+// IN PWSTR typeName,
+// IN WCHAR driveLetter,
+// IN BOOL newRegion,
+// IN LARGE_INTEGER freeSpaceInBytes,
+// IN LARGE_INTEGER totalSpaceInBytes
+// );
+//
+
+#if defined( DBLSPACE_ENABLED )
+#define DmInitPersistentRegionData(RegionData,ftObject,volumeLabel,typeName,driveLetter,newRegion,freeSpaceInBytes,totalSpaceInBytes) \
+ RegionData->DblSpace = NULL; \
+ RegionData->FtObject = ftObject; \
+ RegionData->VolumeLabel = volumeLabel; \
+ RegionData->TypeName = typeName; \
+ RegionData->DriveLetter = driveLetter; \
+ RegionData->NewRegion = newRegion; \
+ RegionData->FreeSpaceInBytes = freeSpaceInBytes; \
+ RegionData->TotalSpaceInBytes = totalSpaceInBytes
+#else
+#define DmInitPersistentRegionData(RegionData,ftObject,volumeLabel,typeName,driveLetter,newRegion,freeSpaceInBytes,totalSpaceInBytes) \
+ RegionData->FtObject = ftObject; \
+ RegionData->VolumeLabel = volumeLabel; \
+ RegionData->TypeName = typeName; \
+ RegionData->DriveLetter = driveLetter; \
+ RegionData->NewRegion = newRegion; \
+ RegionData->FreeSpaceInBytes = freeSpaceInBytes; \
+ RegionData->TotalSpaceInBytes = totalSpaceInBytes
+#endif // DBLSPACE_ENABLED
+
+//
+// PPERSISTENT_REGION_DATA
+// PERSISTENT_DATA(
+// IN PREGION_DESCRIPTOR RegionDescriptor
+// );
+//
+
+#define PERSISTENT_DATA(RegionDescriptor) ((PPERSISTENT_REGION_DATA)((RegionDescriptor)->PersistentData))
+
+//
+// PFT_OBJECT
+// GET_FT_OBJECT(
+// IN PREGION_DESCRIPTOR RegionDescriptor
+// );
+//
+
+#define GET_FT_OBJECT(RegionDescriptor) ((RegionDescriptor)->PersistentData ? PERSISTENT_DATA(RegionDescriptor)->FtObject : NULL)
+
+//
+// VOID
+// SET_FT_OBJECT(
+// IN PREGION_DESCRIPTOR RegionDescriptor,
+// IN PFT_OBJECT ftObject
+// );
+//
+
+#define SET_FT_OBJECT(RegionDescriptor,ftObject) (PERSISTENT_DATA(RegionDescriptor)->FtObject = ftObject)
+
+//
+// ULONG
+// EC(
+// IN NTSTATUS Status
+// );
+//
+
+#define EC(Status) RtlNtStatusToDosError(Status)
+
+#if 0
+
+//
+// Macros to convert between WCHARs and CHARs for a specific range.
+// These are used to handle drive letters. For both APIs, the argument
+// character must be in the range of ASCII characters.
+//
+
+//
+// CHAR
+// WcharToChar(
+// IN WCHAR wch
+// );
+//
+
+#define WcharToChar(wch) ((CHAR)(wch))
+
+//
+// WCHAR
+// CharToWchar(
+// IN CHAR ch
+// );
+//
+
+#define CharToWchar(ch) ((WCHAR)(UCHAR)(ch))
+
+#endif // 0
+
+//////////////////////////////////////////////////////////////////////////////
+
+//
+// stuff in misc.cxx
+//
+
+BOOL
+AllDisksOffLine(
+ VOID
+ );
+
+VOID
+FdShutdownTheSystem(
+ VOID
+ );
+
+int
+GetHeightFromPoints(
+ IN int Points
+ );
+
+VOID
+RetrieveAndFormatMessage(
+ IN DWORD Msg,
+ OUT LPTSTR Buffer,
+ IN DWORD BufferSize,
+ IN va_list* parglist
+ );
+
+DWORD
+CommonDialog(
+ IN DWORD MsgCode,
+ IN LPTSTR Caption,
+ IN DWORD Flags,
+ IN va_list arglist
+ );
+
+
+DWORD
+CommonDialogNoArglist(
+ IN DWORD MsgCode,
+ IN LPTSTR Caption,
+ IN DWORD Flags
+ );
+
+VOID
+ErrorDialog(
+ IN DWORD ErrorCode,
+ ...
+ );
+
+VOID
+WarningDialog(
+ IN DWORD MsgCode,
+ ...
+ );
+
+DWORD
+ConfirmationDialog(
+ IN DWORD MsgCode,
+ IN DWORD Flags,
+ ...
+ );
+
+VOID
+InfoDialogTitle(
+ IN UINT TitleId,
+ IN DWORD MsgCode,
+ ...
+ );
+
+VOID
+InfoDialog(
+ IN DWORD MsgCode,
+ ...
+ );
+
+PREGION_DESCRIPTOR
+LocateRegionForFtObject(
+ IN PFT_OBJECT FtObject
+ );
+
+VOID
+ClonePersistentData(
+ IN PREGION_DESCRIPTOR RegionFrom,
+ OUT PREGION_DESCRIPTOR RegionTo
+ );
+
+PREGION_DESCRIPTOR
+GetPersistentData(
+ IN OUT PREGION_DESCRIPTOR RegionDescriptor
+ );
+
+VOID
+RefreshVolumeData(
+ VOID
+ );
+
+VOID
+InitVolumeInformation(
+ VOID
+ );
+
+VOID
+DetermineRegionInfo(
+ IN PREGION_DESCRIPTOR RegionDescriptor,
+ OUT PWSTR* TypeName,
+ OUT PWSTR* VolumeLabel,
+ OUT PWCHAR DriveLetter
+ );
+
+BOOL
+IsFaultTolerantRegion(
+ IN PREGION_DESCRIPTOR RegionDescriptor
+ );
+
+VOID
+MyCheckMenuItem(
+ IN HMENU hMenu,
+ IN UINT idFirst,
+ IN UINT idLast,
+ IN UINT idCheckItem
+ );
+
+VOID
+MyEnableMenuItem(
+ IN HMENU hMenu,
+ IN UINT idFirst,
+ IN UINT idLast,
+ IN UINT fItemFlags
+ );
+
+VOID
+InitDrawGasGauge(
+ IN HWND hwndGauge
+ );
+
+VOID
+DrawGasGauge(
+ IN HWND hwndGauge,
+ IN HWND hwndParent,
+ IN HDC hDC,
+ IN INT PercentDone,
+ IN PWSTR Caption
+ );
+
+HFONT
+KillBold(
+ IN HWND hdlg,
+ IN PUINT aControls
+ );
+
+NTSTATUS
+LargeIntegerToUnicodeChar(
+ IN PLARGE_INTEGER Value,
+ IN ULONG Base OPTIONAL,
+ IN LONG OutputLength,
+ OUT PWSTR String
+ );
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+//
+// Debugging support for opens
+//
+
+#if DBG == 1
+
+NTSTATUS
+DmOpenFile(
+ OUT PHANDLE FileHandle,
+ IN ACCESS_MASK DesiredAccess,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ OUT PIO_STATUS_BLOCK IoStatusBlock,
+ IN ULONG ShareAccess,
+ IN ULONG OpenOptions
+ );
+
+NTSTATUS
+DmClose(
+ IN HANDLE Handle
+ );
+
+#else
+
+#define DmOpenFile NtOpenFile
+#define DmClose NtClose
+
+#endif
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+//
+// assertion checking, logging, from log.cxx
+//
+
+#if DBG == 1
+
+// #define FDASSERT(expr) if (!(expr)) FdiskAssertFailedRoutine(#expr,__FILE__,__LINE__);
+#define FDASSERT(expr) Win4Assert( expr )
+
+VOID
+FdiskAssertFailedRoutine(
+ IN char *Expression,
+ IN char *FileName,
+ IN int LineNumber
+ );
+
+VOID
+FDLOG_WORK(
+ IN int Level,
+ IN PCHAR FormatString,
+ ...
+ );
+
+#define FDLOG(x) FDLOG_WORK x
+
+VOID
+LOG_DISK_REGISTRY(
+ IN PCHAR RoutineName,
+ IN PDISK_REGISTRY DiskRegistry
+ );
+
+VOID
+LOG_ONE_DISK_REGISTRY_DISK_ENTRY(
+ IN PCHAR RoutineName OPTIONAL,
+ IN PDISK_DESCRIPTION DiskDescription
+ );
+
+VOID
+LOG_DRIVE_LAYOUT(
+ IN PDRIVE_LAYOUT_INFORMATION DriveLayout
+ );
+
+VOID
+LOG_ALL(
+ VOID
+ );
+
+VOID
+InitLogging(
+ VOID
+ );
+
+VOID
+EndLogging(
+ VOID
+ );
+
+#ifdef WINDISK_EXTENSIONS
+
+VOID
+PrintVolumeClaims(
+ IN CHAR DriveLetter
+ );
+
+VOID
+PrintClaims(
+ VOID
+ );
+
+#endif // WINDISK_EXTENSIONS
+
+#else // DBG == 1
+
+#define FDASSERT(expr)
+#define FDLOG(x)
+#define LOG_DISK_REGISTRY(x,y)
+#define LOG_ONE_DISK_REGISTRY_DISK_ENTRY(x,y)
+#define LOG_DRIVE_LAYOUT(x)
+#define LOG_ALL()
+
+#endif // DBG == 1
+
+#endif // __PROTO_HXX__
diff --git a/private/utils/windisk/src/ps.cxx b/private/utils/windisk/src/ps.cxx
new file mode 100644
index 000000000..7659109b8
--- /dev/null
+++ b/private/utils/windisk/src/ps.cxx
@@ -0,0 +1,205 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: ps.cxx
+//
+// Contents: Property sheet functions.
+//
+// History: 28-Jul-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include "genlpage.hxx"
+#include "cdpage.hxx"
+#include "ps.hxx"
+#include "cdrom.hxx"
+#include "windisk.hxx"
+
+#include "shlobj.h"
+#include "shsemip.h"
+
+//////////////////////////////////////////////////////////////////////////////
+
+//+-------------------------------------------------------------------------
+//
+// Function: DiskPropSheet, public
+//
+// Synopsis: Create a property sheet for a disk selection
+//
+// Arguments: (none)
+//
+// Returns: nothing?
+//
+// History: 28-Jul-93 BruceFo Created
+//
+// Notes: UNDONE
+//
+//--------------------------------------------------------------------------
+
+VOID
+DiskPropSheet(
+ VOID
+ )
+{
+#ifndef WINDISK_EXTENSIONS
+ //BUGBUG: we have no default property sheets for disks, so unless there
+ // are extensions, there are no property sheets at all!
+
+ return;
+#endif // !WINDISK_EXTENSIONS
+
+#ifdef WINDISK_EXTENSIONS
+
+ daDebugOut((DEB_ITRACE,"Disk property sheet\n"));
+
+ PAGE_TYPE DiskPages = {0};
+
+ //
+ // First, determine how many pages there will be and allocate
+ // space for them
+ //
+
+ UINT cPages = 0;
+
+ PHARDDISK_CLAIM_LIST hdclaims;
+
+ hdclaims = DiskArray[LBIndexToDiskNumber(g_MouseLBIndex)]->pClaims;
+
+ if (NULL != hdclaims)
+ {
+ while (NULL != hdclaims)
+ {
+ ++cPages;
+ hdclaims = hdclaims->pNext;
+ }
+ }
+
+ if (0 == cPages)
+ {
+ daDebugOut((DEB_ITRACE,"No hard disk extension pages\n"));
+
+ return;
+ }
+
+ DiskPages.cPages = cPages; // the eventual number of pages
+ DiskPages.paPages = new PCLSID[cPages];
+
+ //
+ // add the extension items
+ //
+
+ daDebugOut((DEB_ITRACE,"Add disk pages\n"));
+
+ hdclaims = DiskArray[LBIndexToDiskNumber(g_MouseLBIndex)]->pClaims;
+
+ if (NULL != hdclaims)
+ {
+ while (NULL != hdclaims)
+ {
+ daDebugOut((DEB_ITRACE,"Adding %d pages for %ws\n",
+ hdclaims->pClaimer->pInfo->propPages.cPropPages,
+ hdclaims->pClaimer->pInfo->pwszShortName));
+
+ PropPageSetType* Pages = &hdclaims->pClaimer->pInfo->propPages;
+
+ for (INT i = 0; i < Pages->cPropPages; i++)
+ {
+ DiskPages.paPages[cPages] = Pages->aPropPages[i].pPage;
+ cPages++;
+ }
+
+ hdclaims = hdclaims->pNext;
+ }
+ }
+
+ daDebugOut((DEB_ITRACE,"Create the property sheet\n"));
+
+ DoPropSheet(&DiskPages);
+
+ delete[] DiskPages.paPages;
+
+#endif // WINDISK_EXTENSIONS
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: PropSheet, public
+//
+// Synopsis: Create a property sheet. Determines which type of property
+// sheet should be displayed, based on the current selection.
+// The selection variables (SelectionCount, SelectDS, SelectRG)
+// must be valid.
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 28-Jul-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+VOID
+PropSheet(
+ VOID
+ )
+{
+
+ //
+ // The selection is already determined when we call this function
+ //
+
+#ifdef WINDISK_EXTENSIONS
+ if (DiskSelected) {
+ DiskPropSheet();
+ return;
+ }
+#endif // WINDISK_EXTENSIONS
+
+ if (0 == (SelectionCount + CdRomSelectionCount)) {
+ return; // nothing selected, so no property sheet
+ }
+
+ if (CdRomSelected) {
+
+ PCDROM_DESCRIPTOR cdrom;
+ ULONG i;
+ WCHAR rootDirectory[5];
+
+ for (i = 0; i < CdRomCount; i++) {
+ cdrom = CdRomFindDevice(i);
+ if (cdrom->Selected) {
+
+ rootDirectory[0] = cdrom->DriveLetter;
+ rootDirectory[1] = ':';
+ rootDirectory[2] = '\\';
+ rootDirectory[3] = 0;
+
+ SHObjectProperties(g_hwndFrame, SHOP_FILEPATH,
+ rootDirectory, TEXT("General"));
+ break;
+ }
+ }
+
+ } else if (SingleVolumeSelected()) {
+
+
+ PREGION_DESCRIPTOR regionDescriptor = &SELECTED_REGION(0);
+ WCHAR driveLetter = PERSISTENT_DATA(regionDescriptor)->DriveLetter;
+ WCHAR rootDirectory[5];
+ FDASSERT(NULL != regionDescriptor);
+
+ rootDirectory[0] = driveLetter;
+ rootDirectory[1] = ':';
+ rootDirectory[2] = '\\';
+ rootDirectory[3] = 0;
+
+ SHObjectProperties(g_hwndFrame, SHOP_FILEPATH,
+ rootDirectory, TEXT("General"));
+ }
+}
diff --git a/private/utils/windisk/src/ps.hxx b/private/utils/windisk/src/ps.hxx
new file mode 100644
index 000000000..4f972e24c
--- /dev/null
+++ b/private/utils/windisk/src/ps.hxx
@@ -0,0 +1,22 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: ps.hxx
+//
+// Contents: Property sheet functions
+//
+// History: 17-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __PS_HXX__
+#define __PS_HXX__
+
+VOID
+PropSheet(
+ VOID
+ );
+
+#endif // __PS_HXX__
diff --git a/private/utils/windisk/src/rect.cxx b/private/utils/windisk/src/rect.cxx
new file mode 100644
index 000000000..9eb265678
--- /dev/null
+++ b/private/utils/windisk/src/rect.cxx
@@ -0,0 +1,310 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: rect.cxx
+//
+// Contents: Rectangle custom control: pattern or color
+//
+// History: 7-Oct-94 BruceFo Created from old windisk source
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include "dialogs.h"
+#include "dlgs.hxx"
+#include "rectpriv.hxx"
+
+////////////////////////////////////////////////////////////////////////////
+
+#define RECT_CONTROL_WNDEXTRA 4
+#define GWW_SELECTED 0
+
+////////////////////////////////////////////////////////////////////////////
+
+LRESULT CALLBACK
+RectWndProc(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+////////////////////////////////////////////////////////////////////////////
+
+//+-------------------------------------------------------------------------
+//
+// Function: RectWndProc
+//
+// Synopsis: The rectangle custom control window procedure
+//
+// Arguments: standard WndProc
+//
+// Returns: standard WndProc
+//
+//--------------------------------------------------------------------------
+
+LRESULT CALLBACK
+RectWndProc(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ switch (msg)
+ {
+ case WM_CREATE:
+
+ daAssert(GetWindowLong(hwnd, GWL_STYLE) & (RS_PATTERN | RS_COLOR));
+ SetWindowWord(hwnd, GWW_SELECTED, FALSE);
+ break;
+
+ case WM_LBUTTONDOWN:
+
+ SetFocus(hwnd);
+ break;
+
+ case WM_GETDLGCODE:
+ return DLGC_WANTARROWS;
+
+ case WM_KEYDOWN:
+ {
+ INT nVirtKey = (int)wParam;
+ INT rows;
+ INT columns;
+ INT x;
+ INT y;
+ INT ctrlId = GetDlgCtrlID(hwnd);
+ BOOL isColorControl = GetWindowLong(hwnd, GWL_STYLE) & RS_COLOR;
+
+ if (isColorControl)
+ {
+ rows = 4; // 4x4 for colors
+ columns = 4;
+ x = (ctrlId - IDC_COLOR1) / rows;
+ y = (ctrlId - IDC_COLOR1) % rows;
+ }
+ else
+ {
+ rows = 3; // 2x3 for patterns
+ columns = 2;
+ x = (ctrlId - IDC_PATTERN1) / rows;
+ y = (ctrlId - IDC_PATTERN1) % rows;
+ }
+
+ switch (nVirtKey)
+ {
+ case VK_LEFT:
+ if (x > 0)
+ {
+ --x;
+ }
+ break;
+
+ case VK_UP:
+ if (y > 0)
+ {
+ --y;
+ }
+ break;
+
+ case VK_RIGHT:
+ if (x < columns - 1)
+ {
+ ++x;
+ }
+ break;
+
+ case VK_DOWN:
+ if (y < rows - 1)
+ {
+ ++y;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ SetFocus(GetDlgItem(
+ GetParent(hwnd),
+ (isColorControl ? IDC_COLOR1 : IDC_PATTERN1)
+ + x * rows + y));
+ break;
+ }
+
+ case WM_SETFOCUS:
+
+ SendMessage(
+ GetParent(hwnd),
+ WM_COMMAND,
+ MAKEWPARAM(GetDlgCtrlID(hwnd), RN_CLICKED),
+ (LPARAM)hwnd);
+ break;
+
+ case WM_PAINT:
+ {
+ PAINTSTRUCT ps;
+ RECT rc;
+ int controlID;
+ HBRUSH hbr, hbrT;
+
+ BeginPaint(hwnd, &ps);
+
+ GetClientRect(hwnd, &rc);
+ controlID = GetDlgCtrlID(hwnd);
+
+#if (WINVER >= 0x0400)
+ DWORD windowColor = GetSysColor(COLOR_BTNFACE);
+#else
+ DWORD windowColor = GetSysColor(COLOR_COLORWINDOW);
+#endif
+
+ hbr = CreateSolidBrush(
+ GetWindowWord(hwnd, GWW_SELECTED)
+ ? (~windowColor) & 0xffffff
+ : windowColor
+ );
+
+ hbrT = SelectBrush(ps.hdc, hbr);
+ SelectPen(ps.hdc, g_hPenNull);
+
+ Rectangle(ps.hdc, rc.left, rc.top, rc.right, rc.bottom);
+
+ if (hbrT)
+ {
+ SelectBrush(ps.hdc, hbrT);
+ }
+ DeleteBrush(hbr);
+
+ InflateRect(&rc, -2, -2);
+ rc.right--;
+ rc.bottom--;
+
+ if (GetWindowLong(hwnd, GWL_STYLE) & RS_COLOR)
+ {
+ hbr = CreateSolidBrush(AvailableColors[controlID-IDC_COLOR1]);
+ }
+ else
+ {
+ DWORD currentSelection = ComboBox_GetCurSel(GetDlgItem(GetParent(hwnd), IDC_COLORDLGCOMBO));
+ hbr = MyCreateHatchBrush(
+ AvailableHatches[controlID - IDC_PATTERN1],
+ AvailableColors[SelectedColor[currentSelection] - IDC_COLOR1]);
+ }
+
+ hbrT = SelectBrush(ps.hdc, hbr);
+ SelectPen(ps.hdc, g_hPenThinSolid);
+
+ Rectangle(ps.hdc, rc.left, rc.top, rc.right, rc.bottom);
+
+ if (hbrT)
+ {
+ SelectBrush(ps.hdc, hbrT);
+ }
+
+ DeleteBrush(hbr);
+
+ EndPaint(hwnd, &ps);
+ break;
+ }
+
+ case RM_SELECT:
+ {
+ DWORD style;
+
+ // wParam = TRUE/FALSE for selected/not selected
+
+ if (GetWindowWord(hwnd, GWW_SELECTED) != (WORD)wParam)
+ {
+ SetWindowWord(hwnd, GWW_SELECTED, (WORD)wParam);
+ InvalidateRect(hwnd, NULL, FALSE);
+
+ // make keyboard interface work correctly
+
+ style = (DWORD)GetWindowLong(hwnd, GWL_STYLE);
+ style = wParam ? style | WS_TABSTOP
+ : style & ~WS_TABSTOP;
+ SetWindowLong(hwnd, GWL_STYLE, (LONG)style);
+ }
+
+ break;
+ }
+
+ default:
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+ return 1;
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: UseRectControl
+//
+// Synopsis: Uses the Rect custom control.
+//
+// Arguments: [hInstance] -- instance handle
+//
+// Returns: Win32 error, 0 on success
+//
+// History: 27-Jan-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+DWORD
+UseRectControl(
+ IN HINSTANCE hInstance
+ )
+{
+ WNDCLASS wc;
+
+ wc.style = 0;
+ wc.lpfnWndProc = RectWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = RECT_CONTROL_WNDEXTRA;
+ wc.hInstance = hInstance;
+ wc.hIcon = NULL;
+ wc.hCursor = NULL;
+ wc.hbrBackground = NULL;
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = RECT_CONTROL_STRING;
+
+ if (0 == RegisterClass(&wc))
+ {
+ return GetLastError();
+ }
+ return 0L;
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: ReleaseRectControl
+//
+// Synopsis: Releases the Rect custom control.
+//
+// Arguments: [hInstance] -- instance handle
+//
+// Returns: Win32 error, 0 on success
+//
+// History: 27-Jan-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+DWORD
+ReleaseRectControl(
+ IN HINSTANCE hInstance
+ )
+{
+ if (!UnregisterClass(RECT_CONTROL_STRING, hInstance))
+ {
+ return GetLastError();
+ }
+ return 0L;
+}
diff --git a/private/utils/windisk/src/rectpriv.hxx b/private/utils/windisk/src/rectpriv.hxx
new file mode 100644
index 000000000..c050a9d72
--- /dev/null
+++ b/private/utils/windisk/src/rectpriv.hxx
@@ -0,0 +1,50 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: rectpriv.hxx
+//
+// Contents: Declarations for the rectangle custom control
+//
+// History: 26-Jan-94 BruceFo Created (derived from Chicago Disks tool)
+//
+//--------------------------------------------------------------------------
+
+#ifndef __RECTPRIV_HXX__
+#define __RECTPRIV_HXX__
+
+////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////
+//
+// Rectangle control.
+//
+////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////
+
+#ifndef RC_INVOKED
+
+#define RECT_CONTROL_STRING TEXT("RectControl")
+
+// notifications
+
+#define RN_CLICKED 213
+
+#endif // RC_INVOKED
+
+// window messages
+
+#define RM_SELECT WM_USER
+
+// styles (NOTE: these should be used in the
+// dialogs.dlg file, but the dialog editor strips them out and replaces
+// them with constants when it writes its data.
+
+#define RS_PATTERN 0x00000001
+#define RS_COLOR 0x00000002
+
+
+DWORD UseRectControl(IN HINSTANCE hInstance);
+DWORD ReleaseRectControl(IN HINSTANCE hInstance);
+
+#endif // __RECTPRIV_HXX__
diff --git a/private/utils/windisk/src/resids.h b/private/utils/windisk/src/resids.h
new file mode 100644
index 000000000..483a1221c
--- /dev/null
+++ b/private/utils/windisk/src/resids.h
@@ -0,0 +1,514 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: resids.h
+//
+// Contents: Resource file constants
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __RESIDS_H__
+#define __RESIDS_H__
+
+//
+// Miscellaneous: ids 100 to 199
+//
+
+#define IDFDISK 100
+
+#define ID_FRAME_ACCELERATORS 101
+
+// the disks view small disk bitmap
+
+#define IDB_SMALLDISK 102
+#define IDB_REMOVABLEDISK 103
+#define IDB_SMALLCDROM 104
+
+// toolbar buttons (bitmaps in the resource file)
+
+#define IDB_TOOLBAR 105
+#define IDB_EXTRATOOLS 106
+
+#define IDC_TOOLBAR 107
+
+#define ID_LISTBOX 108
+#define ID_LISTVIEW 109
+
+
+//
+// dialogs: ids 1000 to 1999. every 100 is a dialog
+//
+
+
+
+//
+// Menu ids: ids 2000 to 2999. every 100 is a new top-level menu
+//
+// Note: these must be in the correct order for the toolbar customization
+// code to work
+//
+
+#define IDM_FIRST_MENU 2000
+#define IDM_MENU_DELTA 100
+
+//
+// Partition menu
+//
+
+#define IDM_PARTITIONCREATE 2000
+#define IDM_PARTITIONCREATEEX 2001
+#define IDM_PARTITIONDELETE 2002
+#define IDM_FTCREATEVOLUMESET 2003
+#define IDM_FTEXTENDVOLUMESET 2004
+#define IDM_FTCREATESTRIPE 2005
+#if i386
+#define IDM_PARTITIONACTIVE 2006
+#else
+#define IDM_SECURESYSTEM 2007
+#endif
+
+//
+// Configuration sub-menu
+//
+
+#define IDM_CONFIGSAVE 2008
+#define IDM_CONFIGRESTORE 2009
+#define IDM_CONFIGMIGRATE 2010
+
+#define IDM_PARTITIONCOMMIT 2011
+#define IDM_QUIT 2012
+
+
+//
+// Fault tolerance menu (Server only)
+//
+
+#define IDM_FTESTABLISHMIRROR 2100
+#define IDM_FTBREAKMIRROR 2101
+#define IDM_FTCREATEPSTRIPE 2102
+#define IDM_FTRECOVERSTRIPE 2103
+
+//
+// Tools menu
+//
+
+#define IDM_VOL_FORMAT 2200
+#define IDM_VOL_EJECT 2201
+#define IDM_VOL_LETTER 2203
+#define IDM_VOL_DBLSPACE 2204
+#define IDM_VOL_AUTOMOUNT 2205
+#define IDM_VOL_PROPERTIES 2206
+
+//
+// View menu
+//
+
+//
+// IDM_VIEWVOLUMES must immediately precede IDM_VIEWDISKS numerically
+//
+#define IDM_VIEWVOLUMES 2300
+#define IDM_VIEWDISKS 2301
+
+#if IDM_VIEWVOLUMES != (IDM_VIEWDISKS - 1)
+#error IDM_VIEWVOLUMES must be immediately followed by IDM_VIEWDISKS!
+#endif
+
+#define IDM_VIEW_REFRESH 2302
+
+//
+// Options menu
+//
+
+#define IDM_OPTIONSTOOLBAR 2400
+#define IDM_OPTIONSSTATUS 2401
+#define IDM_OPTIONSLEGEND 2402
+#define IDM_OPTIONSCOLORS 2403
+#define IDM_OPTIONSDISK 2404
+#define IDM_OPTIONSDISPLAY 2405
+#define IDM_OPTIONSCUSTTOOLBAR 2406
+
+//
+// Help menu
+//
+
+#define IDM_HELPCONTENTS 2500
+#define IDM_HELPSEARCH 2501
+#define IDM_HELPHELP 2502
+#define IDM_HELPABOUT 2503
+
+//
+// Debug menu (debug builds only)
+//
+
+#if DBG == 1
+#define IDM_DEBUGALLOWDELETES 2600
+#define IDM_DEBUGLOG 2601
+#define IDM_RAID 2602
+#endif // DBG == 1
+
+
+#ifdef WINDISK_EXTENSIONS
+
+//
+// Reserve space for extension menu items
+//
+
+#define IDM_EXTENSION_START 2700
+#define IDM_EXTENSION_END 2799 // some # > IDM_EXTENSION_START
+
+#if IDM_EXTENSION_START > IDM_EXTENSION_END
+#error IDM_EXTENSION_START must be less than IDM_EXTENSION_END!
+#endif
+
+//
+// Reserve space for extension context-menu-only items
+//
+
+#define IDM_CONTEXT_EXTENSION_START 2800
+#define IDM_CONTEXT_EXTENSION_END 2899 // some # > IDM_CONTEXT_EXTENSION_START
+
+#if IDM_CONTEXT_EXTENSION_START > IDM_CONTEXT_EXTENSION_END
+#error IDM_CONTEXT_EXTENSION_START must be less than IDM_CONTEXT_EXTENSION_END!
+#endif
+
+#endif // WINDISK_EXTENSIONS
+
+
+//
+// Menu ids for things on context menus but not the menu bar
+//
+
+#define IDM_PROPERTIES 2900
+#define IDM_NOVALIDOPERATION 2901
+
+
+//
+// Icons: Ids 3000 to 3999
+//
+
+#define IDI_S_HARD 3000
+#define IDI_S_CDROM 3001
+// in dialogs.h: #define IDI_STOP_SIGN 3002
+
+
+//
+// strings (except menu help): Ids 4000 to 4999
+//
+
+#define IDS_APPNAME 4001
+#define IDS_MULTIPLEITEMS 4002
+#define IDS_FREESPACE 4003
+#define IDS_PARTITION 4004
+#define IDS_LOGICALVOLUME 4005
+#define IDS_DISKN 4006
+#define IDS_CONFIRM 4007
+#define IDS_NOT_IN_APP_MSG_FILE 4008
+#define IDS_NOT_IN_SYS_MSG_FILE 4009
+#define IDS_UNFORMATTED 4010
+#define IDS_UNKNOWN 4011
+#define IDS_STRIPESET 4012
+#define IDS_VOLUMESET 4013
+#define IDS_EXTENDEDPARTITION 4014
+#define IDS_FREEEXT 4015
+#define IDS_DRIVELET_DESCR 4016
+#define IDS_HEALTHY 4017
+#define IDS_BROKEN 4018
+#define IDS_RECOVERABLE 4019
+#define IDS_REGENERATED 4020
+#define IDS_NEW 4021
+#define IDS_OFFLINE 4022
+#define IDS_INSERT_DISK 4023
+#define IDS_MEGABYTES_ABBREV 4024
+#define IDS_INITIALIZING 4025
+#define IDS_REGENERATING 4026
+#define IDS_CDROMN 4027
+#define IDS_CDROM 4028
+#define IDS_DISABLED 4029
+
+#define IDS_CRTPART_CAPTION_P 4030
+#define IDS_CRTPART_CAPTION_E 4031
+#define IDS_CRTPART_CAPTION_L 4032
+#define IDS_CRTPART_MIN_P 4033
+#define IDS_CRTPART_MAX_P 4034
+#define IDS_CRTPART_MIN_L 4035
+#define IDS_CRTPART_MAX_L 4036
+#define IDS_CRTPART_SIZE_P 4037
+#define IDS_CRTPART_SIZE_L 4038
+
+#define IDS_CRTSTRP_CAPTION 4039
+#define IDS_CRTSTRP_MIN 4040
+#define IDS_CRTSTRP_MAX 4041
+#define IDS_CRTSTRP_SIZE 4042
+
+#define IDS_CRTVSET_CAPTION 4043
+#define IDS_EXPVSET_CAPTION 4044
+#define IDS_CRTVSET_MIN 4045
+#define IDS_CRTVSET_MAX 4046
+#define IDS_CRTVSET_SIZE 4047
+
+#define IDS_STATUS_STRIPESET 4048
+#define IDS_STATUS_PARITY 4049
+#define IDS_STATUS_VOLUMESET 4050
+#define IDS_STATUS_MIRROR 4051
+#define IDS_CRTPSTRP_CAPTION 4052
+#define IDS_DLGCAP_PARITY 4053
+#define IDS_DLGCAP_MIRROR 4054
+#define IDS_UNKNOWNTYPE 4055
+#define IDS_INIT_FAILED 4056
+
+#define IDS_SOURCE_PATH 4057
+#define IDS_SOURCE_PATH_NAME 4058
+
+// these must be contigous, and kept in sync with BRUSH_xxx constants
+
+#define IDS_LEGEND_FIRST IDS_LEGEND_PRIMARY
+#define IDS_LEGEND_PRIMARY 4100
+#define IDS_LEGEND_LOGICAL 4101
+#define IDS_LEGEND_STRIPESET 4102
+#define IDS_LEGEND_PARITYSET 4103
+#define IDS_LEGEND_MIRROR 4104
+#define IDS_LEGEND_VOLUMESET 4105
+#define IDS_LEGEND_LAST IDS_LEGEND_VOLUMESET
+
+
+//
+// These are the strings for system-names other than those which are
+// meaningful to NT.
+//
+#define IDS_PARTITION_FREE 4120
+#define IDS_PARTITION_XENIX1 4121
+#define IDS_PARTITION_XENIX2 4122
+#define IDS_PARTITION_OS2_BOOT 4123
+#define IDS_PARTITION_EISA 4124
+#define IDS_PARTITION_UNIX 4125
+#define IDS_PARTITION_POWERPC 4126
+
+
+#if i386
+#define IDS_ACTIVEPARTITION 4200
+#endif
+
+#define IDS_MENUANDITEM 4201
+
+//NOTE: space here
+
+#define IDS_CHANGEFORMAT 4204
+#define IDS_FORMAT 4205
+
+#define IDS_NOOPERATIONS 4206
+
+//
+// DoubleSpace support strings
+//
+
+#define IDS_DBLSPACE_DELETE 4207
+#define IDS_WITH_DBLSPACE 4208
+#define IDS_DBLSPACE_MOUNTED 4209
+#define IDS_DBLSPACE_DISMOUNTED 4210
+#define IDS_MOUNT 4211
+#define IDS_DISMOUNT 4212
+#define IDS_CREATING_DBLSPACE 4213
+#define IDS_DBLSPACECOMPLETE 4214
+
+//
+// Volume view column titles
+//
+
+#define IDS_VV_VOLUME 4250
+#define IDS_VV_NAME 4251
+#define IDS_VV_CAPACITY 4252
+#define IDS_VV_FREESPACE 4253
+#define IDS_VV_PCTFREE 4254
+#define IDS_VV_FORMAT 4255
+#define IDS_VV_FT 4256
+#define IDS_VV_VOLTYPE 4257
+#define IDS_VV_OVERHEAD 4258
+#define IDS_VV_STATUS 4259
+
+#define IDS_FMT_TITLEPROTO 4270
+
+//
+// Volume view column data strings
+//
+
+#define IDS_VOLTYPE_MIRROR 4300
+#define IDS_VOLTYPE_STRIPE 4301
+#define IDS_VOLTYPE_PARITY 4302
+#define IDS_VOLTYPE_VOLSET 4303
+#define IDS_VOLTYPE_SIMPLE 4304
+
+#define IDS_FT_YES 4310
+#define IDS_FT_NO 4311
+
+#define IDS_FTSTATUS_HEALTHY 4320
+#define IDS_FTSTATUS_NEW 4321
+#define IDS_FTSTATUS_BROKEN 4322
+#define IDS_FTSTATUS_RECOVERABLE 4323
+#define IDS_FTSTATUS_REGENERATED 4324
+#define IDS_FTSTATUS_INITIALIZING 4325
+#define IDS_FTSTATUS_REGENERATING 4326
+#define IDS_FTSTATUS_NONE 4327
+
+//
+// Miscellaneous
+//
+
+#define IDS_PROPERTIES 4900
+#define IDS_UNAVAILABLE_DATA 4901
+#define IDS_BYTES_DECORATION 4902
+#define IDS_MEG_DECORATION 4903
+#define IDS_READY 4904
+#define IDS_NOTREADY 4905
+#define IDS_NO_CONFIG_INFO 4906
+
+
+//
+// Menu help defines ids 5000 to 6999. every 100 is a new top-level menu
+//
+
+//
+// Volume menu
+//
+
+#define IDS_HELP_FORMAT 5000
+#define IDS_HELP_DRIVELET 5003
+#define IDS_HELP_DBLSPACE 5004
+#define IDS_HELP_AUTOMOUNT 5005
+#define IDS_HELP_PROPERTIES 5006
+#define IDS_HELP_QUIT 5007
+
+//
+// Partition menu
+//
+
+#define IDS_HELP_CREATE 5100
+#define IDS_HELP_CREATEEX 5101
+#define IDS_HELP_DELETE 5102
+#define IDS_HELP_CREATEVOLSET 5103
+#define IDS_HELP_EXTENDVOLSET 5104
+#define IDS_HELP_CREATESTRIPE 5105
+#ifdef i386
+#define IDS_HELP_MARKACTIVE 5106
+#else // i386
+#define IDS_HELP_SECURE 5107
+#endif // i386
+
+//
+// Configuration sub-menu
+//
+
+#define IDS_HELP_SAVECONFIG 5109
+#define IDS_HELP_RESTORECONFIG 5110
+#define IDS_HELP_SEARCHCONFIG 5111
+
+#define IDS_HELP_PARTITIONCOMMIT 5112
+
+//
+// Fault tolerance menu (Advanced Server only)
+//
+
+#define IDS_HELP_ESTABLISHMIRROR 5200
+#define IDS_HELP_BREAKMIRROR 5201
+#define IDS_HELP_CREATEPSET 5202
+#define IDS_HELP_REGENSTRIPE 5203
+
+//
+// View menu
+//
+
+#define IDS_HELP_VOLUMESVIEW 5300
+#define IDS_HELP_DISKSVIEW 5301
+#define IDS_HELP_REFRESH 5302
+
+//
+// Options menu
+//
+
+#define IDS_HELP_TOOLBAR 5400
+#define IDS_HELP_STATUSBAR 5401
+#define IDS_HELP_LEGEND 5402
+#define IDS_HELP_COLORS 5403
+#define IDS_HELP_OPTIONSDISK 5404
+#define IDS_HELP_REGIONDISPLAY 5405
+#define IDS_HELP_CUSTTOOLBAR 5406
+
+//
+// Help menu
+//
+
+#define IDS_HELP_HELPCONTENTS 5500
+#define IDS_HELP_HELPSEARCH 5501
+#define IDS_HELP_HELPHELP 5502
+#define IDS_HELP_HELPABOUT 5503
+
+//
+// Debug menu (debug builds only)
+//
+
+#if DBG == 1
+#define IDS_HELP_DELETEALL 5600
+#define IDS_HELP_LOG 5601
+#define IDS_HELP_RAID 5602
+#endif // DBG == 1
+
+//
+// Miscellaneous
+//
+
+#define IDS_HELP_NOVALIDOPERATION 5700
+
+//
+// For the menus themselves:
+//
+
+#define IDS_HELP_MENU_VOLUMES 5900
+#define IDS_HELP_MENU_PARTITION 5901
+#define IDS_HELP_MENU_FT 5902
+#define IDS_HELP_MENU_VIEW 5903
+#define IDS_HELP_MENU_OPTIONS 5904
+#define IDS_HELP_MENU_HELP 5905
+#define IDS_HELP_MENU_DEBUG 5906
+
+#define IDS_HELP_MENU_CONFIG 5907
+
+//
+// File system descriptions
+//
+
+#define IDS_LONG_FAT 6400
+#define IDS_LONG_NTFS 6401
+
+#ifdef SUPPORT_OFS
+#define IDS_LONG_OFS 6402
+#endif // SUPPORT_OFS
+
+//
+// The following data is used for the %used/%free bitmap
+//
+
+#define USETYPE_NONE 0x0
+#define USETYPE_ELLIPS 0x1
+#define USETYPE_BARH 0x2
+#define USETYPE_BARV 0x4
+
+/*
+ * NOTE that the following values MUST be > 255 because
+ * they are also used as the resource types for the
+ * raw ELLIPRESOURCE resource.
+ */
+#define IDB_HARDDISK 6500
+#define IDB_CDROM 6501
+
+#define ELLIPRESOURCE 6600
+
+
+
+//
+// RESERVED: ids 7000 to 19999 are used by dialogs in the dialogs.h file
+//
+
+#endif // __RESIDS_H__
diff --git a/private/utils/windisk/src/rmdisk.bmp b/private/utils/windisk/src/rmdisk.bmp
new file mode 100644
index 000000000..7dd7d57fb
--- /dev/null
+++ b/private/utils/windisk/src/rmdisk.bmp
Binary files differ
diff --git a/private/utils/windisk/src/scdrom.ico b/private/utils/windisk/src/scdrom.ico
new file mode 100644
index 000000000..8e0b42de5
--- /dev/null
+++ b/private/utils/windisk/src/scdrom.ico
Binary files differ
diff --git a/private/utils/windisk/src/scsi.h b/private/utils/windisk/src/scsi.h
new file mode 100644
index 000000000..92f0d2173
--- /dev/null
+++ b/private/utils/windisk/src/scsi.h
@@ -0,0 +1,77 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1993 - 1994.
+//
+// File: scsi.h
+//
+// Contents: This is a subset of the header file for SCSI definitions that
+// is located in the kernel tree.
+//
+// History: Mike Glass (mglass) Created
+//
+//----------------------------------------------------------------------------
+
+//
+// Inquiry buffer structure. This is the data returned from the target
+// after it receives an inquiry.
+//
+// This structure may be extended by the number of bytes specified
+// in the field AdditionalLength. The defined size constant only
+// includes fields through ProductRevisionLevel.
+//
+// The NT SCSI drivers are only interested in the first 36 bytes of data.
+//
+
+#define INQUIRYDATABUFFERSIZE 36
+
+typedef struct _INQUIRYDATA {
+ UCHAR DeviceType : 5;
+ UCHAR DeviceTypeQualifier : 3;
+ UCHAR DeviceTypeModifier : 7;
+ UCHAR RemovableMedia : 1;
+ UCHAR Versions;
+ UCHAR ResponseDataFormat;
+ UCHAR AdditionalLength;
+ UCHAR Reserved[2];
+ UCHAR SoftReset : 1;
+ UCHAR CommandQueue : 1;
+ UCHAR Reserved2 : 1;
+ UCHAR LinkedCommands : 1;
+ UCHAR Synchronous : 1;
+ UCHAR Wide16Bit : 1;
+ UCHAR Wide32Bit : 1;
+ UCHAR RelativeAddressing : 1;
+ UCHAR VendorId[8];
+ UCHAR ProductId[16];
+ UCHAR ProductRevisionLevel[4];
+ UCHAR VendorSpecific[20];
+ UCHAR Reserved3[40];
+} INQUIRYDATA, *PINQUIRYDATA;
+
+//
+// Inquiry defines. Used to interpret data returned from target as result
+// of inquiry command.
+//
+// DeviceType field
+//
+
+#define DIRECT_ACCESS_DEVICE 0x00 // disks
+#define SEQUENTIAL_ACCESS_DEVICE 0x01 // tapes
+#define PRINTER_DEVICE 0x02 // printers
+#define PROCESSOR_DEVICE 0x03 // scanners, printers, etc
+#define WRITE_ONCE_READ_MULTIPLE_DEVICE 0x04 // worms
+#define READ_ONLY_DIRECT_ACCESS_DEVICE 0x05 // cdroms
+#define SCANNER_DEVICE 0x06 // scanners
+#define OPTICAL_DEVICE 0x07 // optical disks
+#define MEDIUM_CHANGER 0x08 // jukebox
+#define COMMUNICATION_DEVICE 0x09 // network
+#define LOGICAL_UNIT_NOT_PRESENT_DEVICE 0x7F
+#define DEVICE_QUALIFIER_NOT_SUPPORTED 0x03
+
+//
+// DeviceTypeQualifier field
+//
+
+#define DEVICE_CONNECTED 0x00
+
diff --git a/private/utils/windisk/src/select.cxx b/private/utils/windisk/src/select.cxx
new file mode 100644
index 000000000..600063604
--- /dev/null
+++ b/private/utils/windisk/src/select.cxx
@@ -0,0 +1,1845 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: select.cxx
+//
+// Contents: Routines for handling selection and focus in the volumes
+// and disks views.
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include "cdrom.hxx"
+#include "dblspace.hxx"
+#include "drives.hxx"
+#include "fill.hxx"
+#include "ft.hxx"
+#include "listbox.hxx"
+#include "ntlow.hxx"
+#include "select.hxx"
+#include "stleg.hxx"
+#include "tbar.hxx"
+#include "volview.hxx"
+#include "windisk.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+VOID
+ToggleCdRomSelection(
+ IN ULONG CdRomNumber
+ );
+
+VOID
+ToggleDiskSelection(
+ IN PDISKSTATE DiskState,
+ IN DWORD RegionIndex
+ );
+
+VOID
+SetFocusFromListview(
+ VOID
+ );
+
+//////////////////////////////////////////////////////////////////////////////
+
+//+---------------------------------------------------------------------------
+//
+// Function: AdjustMenuAndStatus
+//
+// Synopsis: Adjust the status bar description based on the selection
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+AdjustMenuAndStatus(
+ VOID
+ )
+{
+ TCHAR mbBuffer[16];
+ TCHAR statusBarPartitionString[200];
+#if defined( DBLSPACE_ENABLED )
+ TCHAR dblSpaceString[200];
+#endif // DBLSPACE_ENABLED
+ DWORD selectionCount;
+ DWORD msg;
+ PDISKSTATE diskState;
+ PCDROM_DESCRIPTOR cdrom;
+ DWORD regionIndex;
+ PWSTR volumeLabel;
+ PWSTR typeName;
+ WCHAR driveLetter;
+
+ selectionCount = SetUpMenu(&SingleSel, &SingleSelIndex);
+
+ switch (selectionCount)
+ {
+
+ case 0:
+
+ StatusTextDrlt[0]
+ = StatusTextSize[0]
+ = StatusTextStat[0]
+ = StatusTextVoll[0]
+ = StatusTextType[0]
+ = L'\0';
+ break;
+
+ case 1:
+
+ if (CdRomSelected)
+ {
+ cdrom = CdRomFindSelectedDevice();
+
+ WCHAR rootPath[4];
+ WCHAR volumeLabel[100];
+ WCHAR typeName[100];
+
+ if (!cdrom->TypeName) {
+
+ typeName[0] = L'\0';
+ volumeLabel[0] = L'\0';
+
+ } else {
+
+ lstrcpy(typeName,cdrom->TypeName);
+ lstrcpy(volumeLabel,cdrom->VolumeLabel);
+
+ }
+
+ lstrcpy(StatusTextType, typeName);
+ lstrcpy(StatusTextVoll, volumeLabel);
+
+ LoadString(
+ g_hInstance,
+ IDS_CDROM,
+ StatusTextStat,
+ ARRAYLEN(StatusTextStat));
+
+ if (!cdrom->TypeName) {
+
+ StatusTextSize[0] = L'\0';
+
+ } else {
+
+ LoadString(
+ g_hInstance,
+ IDS_MEGABYTES_ABBREV,
+ mbBuffer,
+ ARRAYLEN(mbBuffer));
+ wsprintf(
+ StatusTextSize,
+ TEXT("%u %s"),
+ cdrom->TotalSpaceInMB,
+ mbBuffer);
+
+ }
+
+ if (cdrom->DriveLetter == NO_DRIVE_LETTER_EVER) {
+
+ StatusTextDrlt[0] = L'\0';
+ StatusTextDrlt[1] = L'\0';
+
+ } else {
+
+ StatusTextDrlt[0] = cdrom->DriveLetter;
+ StatusTextDrlt[1] = L':';
+
+ }
+ }
+ else
+ {
+ //
+ // Might be part of a partial FT set.
+ //
+
+ if (FtSelectionType != UNINIT_FT_TYPE)
+ {
+ goto tagFtSet;
+ }
+
+ diskState = SingleSel;
+ regionIndex = SingleSelIndex;
+
+ DetermineRegionInfo(
+ &diskState->RegionArray[regionIndex],
+ &typeName,
+ &volumeLabel,
+ &driveLetter
+ );
+
+ lstrcpy(StatusTextType, typeName);
+ lstrcpy(StatusTextVoll, volumeLabel);
+
+ if (diskState->RegionArray[regionIndex].SysID == PARTITION_ENTRY_UNUSED)
+ {
+ if (diskState->RegionArray[regionIndex].RegionType == REGION_LOGICAL)
+ {
+ if (diskState->ExistLogical)
+ {
+ msg = IDS_FREEEXT;
+ }
+ else
+ {
+ msg = IDS_EXTENDEDPARTITION;
+ }
+ }
+ else
+ {
+ msg = IDS_FREESPACE;
+ }
+ driveLetter = L' ';
+ StatusTextType[0] = L'\0';
+ }
+ else
+ {
+ msg = (diskState->RegionArray[regionIndex].RegionType == REGION_LOGICAL)
+ ? IDS_LOGICALVOLUME
+ : IDS_PARTITION
+ ;
+
+#if i386
+ if ( (msg == IDS_PARTITION)
+ && (diskState->Disk == 0)
+ && diskState->RegionArray[regionIndex].Active)
+ {
+ msg = IDS_ACTIVEPARTITION;
+ }
+#endif
+ }
+
+ LoadString(
+ g_hInstance,
+ msg,
+ statusBarPartitionString,
+ ARRAYLEN(statusBarPartitionString));
+
+#if defined( DBLSPACE_ENABLED )
+ if (DblSpaceVolumeExists(&diskState->RegionArray[regionIndex]))
+ {
+ LoadString(
+ g_hInstance,
+ IDS_WITH_DBLSPACE,
+ dblSpaceString,
+ ARRAYLEN(dblSpaceString));
+ }
+ else
+ {
+ dblSpaceString[0] = dblSpaceString[1] = L'\0';
+ }
+ wsprintf(StatusTextStat,
+ TEXT("%s%s"),
+ statusBarPartitionString,
+ dblSpaceString);
+#else // DBLSPACE_ENABLED
+ wsprintf(StatusTextStat,
+ TEXT("%s"),
+ statusBarPartitionString);
+#endif // !DBLSPACE_ENABLED
+
+ LoadString(
+ g_hInstance,
+ IDS_MEGABYTES_ABBREV,
+ mbBuffer,
+ ARRAYLEN(mbBuffer));
+ wsprintf(
+ StatusTextSize,
+ TEXT("%u %s"),
+ diskState->RegionArray[regionIndex].SizeMB,
+ mbBuffer);
+
+ StatusTextDrlt[0] = driveLetter;
+ StatusTextDrlt[1] = ((driveLetter == L' ') ? L'\0' : L':');
+ }
+
+ break;
+
+ default:
+
+tagFtSet:
+
+ //
+ // Might be an ft set, might be multiple items
+ //
+
+ if (FtSelectionType == UNINIT_FT_TYPE)
+ {
+ LoadString(
+ g_hInstance,
+ IDS_MULTIPLEITEMS,
+ StatusTextStat,
+ ARRAYLEN(StatusTextStat));
+
+ StatusTextDrlt[0]
+ = StatusTextSize[0]
+ = StatusTextType[0]
+ = StatusTextVoll[0]
+ = L'\0';
+ }
+ else
+ {
+ PREGION_DESCRIPTOR regionDescriptor;
+ DWORD i;
+ DWORD resid;
+ DWORD size = 0;
+ TCHAR textbuf[STATUS_TEXT_SIZE];
+ PFT_OBJECT_SET ftSet;
+ PFT_OBJECT ftObject;
+ WCHAR ftStatusText[65];
+ FT_SET_STATUS setState;
+ ULONG numberOfMembers;
+ STATUS_CODE status;
+
+ DetermineRegionInfo(
+ &SELECTED_REGION(0),
+ &typeName,
+ &volumeLabel,
+ &driveLetter
+ );
+ if (NULL == typeName)
+ {
+ typeName = wszUnknown;
+ volumeLabel = L"";
+ }
+
+ lstrcpy(StatusTextType, typeName);
+ lstrcpy(StatusTextVoll, volumeLabel);
+
+ switch (FtSelectionType)
+ {
+ case Mirror:
+ resid = IDS_STATUS_MIRROR;
+ size = SELECTED_REGION(0).SizeMB;
+ break;
+
+ case Stripe:
+ resid = IDS_STATUS_STRIPESET;
+ goto tagCalcSize;
+
+ case StripeWithParity:
+ resid = IDS_STATUS_PARITY;
+ goto tagCalcSize;
+
+ case VolumeSet:
+ resid = IDS_STATUS_VOLUMESET;
+ goto tagCalcSize;
+
+tagCalcSize:
+ for (i=0; i<selectionCount; i++)
+ {
+ size += SELECTED_REGION(i).SizeMB;
+ }
+ break;
+
+ default:
+ FDASSERT(FALSE);
+ }
+
+
+ {
+
+ //
+ // Loop through trying to find the actual ftset.
+ //
+
+ DWORD j;
+
+ for (j = 0;
+ j<selectionCount;
+ j++
+ ) {
+
+ ftObject = GET_FT_OBJECT(&SELECTED_REGION(j));
+
+ //
+ // If trying to regenerate an FT set the drive
+ // being used to regenerate might be before the
+ // actual ftset. If the ftobject is null, then
+ // try to get the ftobject from the second selected
+ // region. Since we are doing an ftoperation we
+ // will always have at least two.
+ //
+
+ if (ftObject) {
+
+ break;
+
+ }
+
+ }
+
+ }
+
+ ftSet = ftObject->Set;
+
+ if (FtSelectionType != VolumeSet)
+ {
+ regionDescriptor = LocateRegionForFtObject(ftSet->Member0);
+
+ if (NULL == regionDescriptor)
+ {
+ // The zeroth member is off line
+
+ ftObject = ftSet->Members;
+ while (NULL != ftObject)
+ {
+ // Find member 1
+
+ if (ftObject->MemberIndex == 1)
+ {
+ regionDescriptor = LocateRegionForFtObject(ftObject);
+ break;
+ }
+ ftObject = ftObject->Next;
+ }
+ }
+
+ // If the partition number is zero, then this set has
+ // not been committed to the disk yet.
+
+ if ( (NULL != regionDescriptor)
+ && (0 != regionDescriptor->PartitionNumber))
+ {
+ status = LowFtVolumeStatus(regionDescriptor->Disk,
+ regionDescriptor->PartitionNumber,
+ &setState,
+ &numberOfMembers);
+ if (status == OK_STATUS)
+ {
+ if ( (ftSet->Status != FtSetNewNeedsInitialization)
+ && (ftSet->Status != FtSetNew))
+ {
+ if (ftSet->Status != setState)
+ {
+ PFT_OBJECT tempFtObjectPtr;
+
+ ftSet->Status = setState;
+
+ // Determine if each object should be updated.
+
+ switch (setState)
+ {
+ case FtSetHealthy:
+
+ // Each object in the set should have
+ // the partition state updated. Determine
+ // the value for the update and walk
+ // the chain to perform the update.
+
+ for (tempFtObjectPtr = ftSet->Members;
+ NULL != tempFtObjectPtr;
+ tempFtObjectPtr = tempFtObjectPtr->Next)
+ {
+ tempFtObjectPtr->State = Healthy;
+ }
+ TotalRedrawAndRepaint();
+ break;
+
+ case FtSetInitializing:
+ case FtSetRegenerating:
+ case FtSetDisabled:
+
+ FdftUpdateFtObjectSet(ftSet, setState);
+ TotalRedrawAndRepaint();
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ LoadString(g_hInstance, resid, textbuf, ARRAYLEN(textbuf));
+
+ switch (resid)
+ {
+ case IDS_STATUS_STRIPESET:
+ case IDS_STATUS_VOLUMESET:
+ wsprintf(StatusTextStat, textbuf, ftSet->Ordinal);
+ break;
+
+ case IDS_STATUS_PARITY:
+ case IDS_STATUS_MIRROR:
+ {
+ switch (ftSet->Status)
+ {
+ case FtSetHealthy:
+ resid = IDS_HEALTHY;
+ break;
+
+ case FtSetNew:
+ case FtSetNewNeedsInitialization:
+ resid = IDS_NEW;
+ break;
+
+ case FtSetBroken:
+ resid = IDS_BROKEN;
+ break;
+
+ case FtSetRecoverable:
+ resid = IDS_RECOVERABLE;
+ break;
+
+ case FtSetRecovered:
+ resid = IDS_REGENERATED;
+ break;
+
+ case FtSetInitializing:
+ resid = IDS_INITIALIZING;
+ break;
+
+ case FtSetRegenerating:
+ resid = IDS_REGENERATING;
+ break;
+
+ case FtSetDisabled:
+ resid = IDS_DISABLED;
+ break;
+
+ case FtSetInitializationFailed:
+ resid = IDS_INIT_FAILED;
+ break;
+
+ default:
+ FDASSERT(FALSE);
+ }
+
+ LoadString(g_hInstance, resid, ftStatusText, ARRAYLEN(ftStatusText));
+ wsprintf(StatusTextStat, textbuf, ftSet->Ordinal, ftStatusText);
+ break;
+ }
+
+ default:
+ FDASSERT(FALSE);
+ }
+
+ LoadString(
+ g_hInstance,
+ IDS_MEGABYTES_ABBREV,
+ mbBuffer,
+ ARRAYLEN(mbBuffer));
+ wsprintf(StatusTextSize, TEXT("%u %s"), size, mbBuffer);
+
+ StatusTextDrlt[0] = driveLetter;
+ StatusTextDrlt[1] = ((driveLetter == L' ') ? L'\0' : L':');
+ }
+ }
+ UpdateStatusBarDisplay();
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: CheckSelection
+//
+// Synopsis: Check the selection state. Deselect anything which is
+// not a legal selection for the listview. This includes
+// "new" regions, free space, and CD-ROMs.
+//
+// Arguments: none
+//
+// Returns: nothing
+//
+// History: 4-Oct-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+CheckSelection(
+ VOID
+ )
+{
+ ULONG disk;
+ PDISKSTATE diskState;
+ PREGION_DESCRIPTOR region;
+ PPERSISTENT_REGION_DATA regionData;
+ ULONG regionIndex;
+
+ //
+ // Deselect the region if it is not a significant region (Only
+ // significant regions get put in the volumes view)
+ //
+
+ for (disk=0; disk<DiskCount; disk++)
+ {
+ diskState = DiskArray[disk];
+
+ for (regionIndex=0; regionIndex<diskState->RegionCount; regionIndex++)
+ {
+ region = &diskState->RegionArray[regionIndex];
+
+ if (diskState->Selected[regionIndex])
+ {
+ regionData = PERSISTENT_DATA(region);
+
+ if (NULL == regionData
+ || !SignificantDriveLetter(regionData->DriveLetter))
+ {
+ // NOTE: the previous test is likely to be SLOW!
+
+ daDebugOut((DEB_ITRACE,
+ "Deselecting disk %d, region %d, drive %c:\n",
+ disk,
+ regionIndex,
+ (NULL == regionData)
+ ? '?'
+ : regionData->DriveLetter
+ ));
+
+ diskState->Selected[regionIndex] = FALSE;
+ PaintDiskRegion(diskState, regionIndex, NULL);
+ }
+ }
+ }
+ }
+
+ for (ULONG i=0; i<CdRomCount; i++)
+ {
+ if (CdRomArray[i].Selected)
+ {
+ CdRomArray[i].Selected = FALSE;
+ PaintCdRom(i, NULL);
+ }
+ }
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: GetLVIndexFromDriveLetter
+//
+// Synopsis: Given a drive letter, search for the volume in the listview,
+// and return the item's listview index
+//
+// Arguments: [DriveLetter] -- Drive letter of the volume in question
+//
+// Returns: listview index of the volume, or -1 if not found
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+INT
+GetLVIndexFromDriveLetter(
+ IN WCHAR DriveLetter
+ )
+{
+ WCHAR driveName[3];
+ driveName[0] = DriveLetter;
+ driveName[1] = L':';
+ driveName[2] = L'\0';
+
+ LV_FINDINFO lvfi = { LVFI_STRING, driveName, 0 };
+ INT index = ListView_FindItem(g_hwndLV, -1, &lvfi); // -1 == from start
+ if (index == -1)
+ {
+ daDebugOut((DEB_IERROR,
+ "Couldn't find volume %ws in the listview!\n",
+ driveName
+ ));
+ }
+
+ return index;
+}
+
+
+
+VOID
+PaintCdRom(
+ IN ULONG CdRomNumber,
+ IN HDC hdc
+ )
+
+/*++
+
+Routine Description:
+
+ This routine visually toggles the selection state of a CD-ROM
+
+Arguments:
+
+ Cdrom - structure for CD-ROM to select
+
+ hdc - if non-NULL, device context to use for drawing. If NULL, we'll
+ first get a device context via GetDC().
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCDROM_DESCRIPTOR cdrom = CdRomFindDevice(CdRomNumber);
+ PLEFTRIGHT leftRight = &cdrom->LeftRight;
+ HDC hdcActual;
+ RECT rc;
+ LONG barTop = CalcBarTop(LBCdRomNumberToIndex(CdRomNumber));
+ BOOL selected = (BOOL)cdrom->Selected;
+ int i;
+ HBRUSH hbr = GetStockBrush(BLACK_BRUSH);
+
+ if (barTop != -1)
+ {
+ hdcActual = hdc ? hdc : GetDC(g_hwndList);
+
+ rc.left = leftRight->Left + 1;
+ rc.right = leftRight->Right - 1;
+ rc.top = barTop + BarTopYOffset + 1;
+ rc.bottom = barTop + BarBottomYOffset - 1;
+
+ if (selected)
+ {
+ for (i=0; i<SELECTION_THICKNESS; i++)
+ {
+ FrameRect(hdcActual, &rc, hbr);
+ InflateRect(&rc, -1, -1);
+ }
+ }
+ else
+ {
+ //
+ // Blt the region from the off-screen bitmap onto the
+ // screen. But first exclude the center of the region
+ // from the clip region so we only blt the necessary bits.
+ // This speeds up selections noticably.
+ //
+
+ InflateRect(&rc, -SELECTION_THICKNESS, -SELECTION_THICKNESS);
+ ExcludeClipRect(hdcActual, rc.left, rc.top, rc.right, rc.bottom);
+
+ BitBlt(hdcActual,
+ leftRight->Left,
+ barTop + BarTopYOffset,
+ leftRight->Right - leftRight->Left,
+ barTop + BarBottomYOffset,
+ cdrom->hDCMem,
+ leftRight->Left,
+ BarTopYOffset,
+ SRCCOPY
+ );
+ }
+
+ if (NULL == hdc)
+ {
+ ReleaseDC(g_hwndList, hdcActual);
+ }
+ }
+}
+
+
+
+
+VOID
+PaintDiskRegion(
+ IN PDISKSTATE DiskState,
+ IN DWORD RegionIndex,
+ IN HDC hdc
+ )
+
+/*++
+
+Routine Description:
+
+ This routine visually toggles the selection state of a given disk region.
+
+Arguments:
+
+ DiskState - master structure for disk containing region to select
+
+ RegionIndex - which region on the disk to toggle
+
+ hdc - if non-NULL, device context to use for drawing. If NULL, we'll
+ first get a device context via GetDC().
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PLEFTRIGHT leftRight = &DiskState->LeftRight[RegionIndex];
+ HDC hdcActual;
+ RECT rc;
+ LONG barTop = CalcBarTop(DiskState->Disk);
+ BOOL selected = (BOOL)DiskState->Selected[RegionIndex];
+ int i;
+ HBRUSH hbr = GetStockBrush(BLACK_BRUSH);
+
+ if (barTop != -1)
+ {
+ hdcActual = hdc ? hdc : GetDC(g_hwndList);
+
+ rc.left = leftRight->Left + 1;
+ rc.right = leftRight->Right - 1;
+ rc.top = barTop + BarTopYOffset + 1;
+ rc.bottom = barTop + BarBottomYOffset - 1;
+
+ if (selected)
+ {
+ for (i=0; i<SELECTION_THICKNESS; i++)
+ {
+ FrameRect(hdcActual, &rc, hbr);
+ InflateRect(&rc, -1, -1);
+ }
+ }
+ else
+ {
+
+ //
+ // Blt the region from the off-screen bitmap onto the
+ // screen. But first exclude the center of the region
+ // from the clip region so we only blt the necessary bits.
+ // This speeds up selections noticably.
+ //
+
+ InflateRect(&rc, -SELECTION_THICKNESS, -SELECTION_THICKNESS);
+ ExcludeClipRect(hdcActual, rc.left, rc.top, rc.right, rc.bottom);
+
+ BitBlt(hdcActual,
+ leftRight->Left,
+ barTop + BarTopYOffset,
+ leftRight->Right - leftRight->Left,
+ barTop + BarBottomYOffset,
+ DiskState->hDCMem,
+ leftRight->Left,
+ BarTopYOffset,
+ SRCCOPY
+ );
+ }
+
+ if (NULL == hdc)
+ {
+ ReleaseDC(g_hwndList, hdcActual);
+ }
+ }
+}
+
+
+
+
+VOID
+SetVolumeSelectedState(
+ IN CHAR DriveLetter,
+ IN BOOL Select
+ )
+
+/*++
+
+Routine Description:
+
+ This routine selects or deselects items in the volumes view.
+
+Arguments:
+
+ DriveLetter - indicates the volume to change the selection state of
+
+ Select - TRUE to select the volume, FALSE to deselect it
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Get the listview index of the volume with drive letter DriveLetter
+ //
+
+ INT index = GetLVIndexFromDriveLetter(DriveLetter);
+
+ g_SettingListviewState = TRUE;
+
+ //
+ // Set the state of this item to selected or not, based on the Select
+ // parameter.
+ //
+ ListView_SetItemState(
+ g_hwndLV,
+ index,
+ (Select ? LVIS_SELECTED : 0),
+ LVIS_SELECTED
+ );
+
+// daDebugOut((DEB_ITRACE, "SetVolumeSelectedState: %s %c: (index %d)\n",
+// Select ? "selected" : "deselected",
+// DriveLetter,
+// index
+// ));
+
+ g_SettingListviewState = FALSE;
+}
+
+
+
+VOID
+DeselectSelectedRegions(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deselects all selected regions.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+//BUGBUG: why not just use the Selected* arrays? so its linear in the
+//number of selected regions?
+
+ DWORD i;
+ DWORD j;
+ PDISKSTATE diskState;
+ PCDROM_DESCRIPTOR cdrom;
+
+ for (i=0; i<DiskCount; i++)
+ {
+ diskState = DiskArray[i];
+ for (j=0; j<diskState->RegionCount; j++)
+ {
+ diskState->Selected[j] = FALSE;
+ }
+ }
+
+ for (i=0; i<CdRomCount; i++)
+ {
+ cdrom = CdRomFindDevice(i);
+ cdrom->Selected = FALSE;
+ }
+}
+
+
+
+
+VOID
+DeselectSelectedDiskViewRegions(
+ VOID
+ )
+{
+ DWORD i;
+ DWORD j;
+ PDISKSTATE diskState;
+ PCDROM_DESCRIPTOR cdrom;
+
+ for (i=0; i<DiskCount; i++)
+ {
+ diskState = DiskArray[i];
+ for (j=0; j<diskState->RegionCount; j++)
+ {
+ if (diskState->Selected[j])
+ {
+ diskState->Selected[j] = FALSE;
+ PaintDiskRegion(diskState, j, NULL);
+ diskState->Selected[j] = TRUE;
+ }
+ }
+ }
+
+ for (i=0; i<CdRomCount; i++)
+ {
+ cdrom = CdRomFindDevice(i);
+ if (cdrom->Selected)
+ {
+ cdrom->Selected = FALSE;
+ PaintCdRom(i, NULL);
+ cdrom->Selected = TRUE;
+ }
+ }
+}
+
+
+
+
+VOID
+DeselectSelectedListViewRegions(
+ VOID
+ )
+{
+ g_SettingListviewState = TRUE;
+
+ INT item = -1;
+
+ while ((item = ListView_GetNextItem(g_hwndLV, item, LVNI_SELECTED))
+ != -1)
+ {
+ ListView_SetItemState(
+ g_hwndLV,
+ item,
+ 0,
+ LVIS_SELECTED);
+ }
+
+ g_SettingListviewState = FALSE;
+}
+
+
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: ToggleCdRomSelection
+//
+// Synopsis: Toggle the selection state of a CD-ROM in the disks view.
+//
+// Arguments: [CdRomNumber] -- the number of the CD-ROM
+//
+// Returns: nothing
+//
+// History: 1-Mar-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+ToggleCdRomSelection(
+ IN ULONG CdRomNumber
+ )
+{
+ PCDROM_DESCRIPTOR cdrom;
+
+ ToggleLBCursor(NULL); // remove previous selection
+
+ cdrom = CdRomFindDevice(CdRomNumber);
+ cdrom->Selected = !cdrom->Selected;
+ PaintCdRom(CdRomNumber, NULL);
+
+ LBCursorListBoxItem = LBCdRomNumberToIndex(CdRomNumber);
+ LBCursorRegion = 0;
+
+ ToggleLBCursor(NULL); // visualize new selection
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: ToggleDiskSelection
+//
+// Synopsis: Toggle the selection state of a region in the disks view. If
+// the region is part of a volume, then toggle the state of all
+// regions associated with the volume (which will be >1 for FT
+// sets)
+//
+// Arguments: [DiskState] -- a disk state structure
+// [RegionIndex] -- the region index
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+ToggleDiskSelection(
+ IN PDISKSTATE DiskState,
+ IN DWORD RegionIndex
+ )
+{
+ PFT_OBJECT ftObject;
+ PFT_OBJECT ftObj;
+ PFT_OBJECT_SET ftSet;
+ ULONG disk;
+ ULONG regionIndex;
+
+ // remove the list box selection cursor from its previous region
+
+ ToggleLBCursor(NULL);
+
+ //
+ // The selected region might be part of an ft object set. If it is,
+ // scan each region in each disk and select each item in the set.
+ //
+
+ if (NULL != (ftObject = GET_FT_OBJECT(&DiskState->RegionArray[RegionIndex])))
+ {
+ ftSet = ftObject->Set;
+
+ for (disk = 0; disk<DiskCount; disk++)
+ {
+ PDISKSTATE diskState = DiskArray[disk];
+
+ for (regionIndex = 0; regionIndex<diskState->RegionCount; regionIndex++)
+ {
+ PREGION_DESCRIPTOR regionDescriptor = &diskState->RegionArray[regionIndex];
+
+ if (DmSignificantRegion(regionDescriptor))
+ {
+ if (NULL != (ftObj = GET_FT_OBJECT(regionDescriptor)))
+ {
+ if (ftObj->Set == ftSet)
+ {
+ diskState->Selected[regionIndex] = (BOOLEAN)(!diskState->Selected[regionIndex]);
+ PaintDiskRegion(diskState, regionIndex, NULL);
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ //
+ // Only a single-partition volume
+ //
+
+ DiskState->Selected[RegionIndex] = (BOOLEAN)(!DiskState->Selected[RegionIndex]);
+ PaintDiskRegion(DiskState, RegionIndex, NULL);
+ }
+
+ LBCursorListBoxItem = LBDiskNumberToIndex(DiskState->Disk);
+ LBCursorRegion = RegionIndex;
+
+ ToggleLBCursor(NULL);
+}
+
+
+
+
+VOID
+SelectCdRom(
+ IN BOOL MultipleSel,
+ IN ULONG CdRomNumber
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles a user selection of a CD-ROM. It is called
+ directly for a keyboard selection or indirectly for a mouse selection.
+ If not a multiple selection, all selected regions are deselected.
+ The focus rectangle is moved to the selected region, which is then
+ visually selected.
+
+Arguments:
+
+ MultipleSel - whether the user has made a multiple selection
+ (ie, control-clicked).
+
+ CdRomNumber - index of selected CD-ROM on the disk
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if (!MultipleSel)
+ {
+ // need to deselect all selected regions first.
+
+ DeselectSelectedDiskViewRegions(); // visual selection in disk view
+ DeselectSelectedRegions(); // actual selection state
+ }
+
+ //
+ // select or deselect the region
+ //
+
+ ToggleCdRomSelection(CdRomNumber);
+
+ AdjustMenuAndStatus();
+}
+
+
+
+
+VOID
+SelectDiskRegion(
+ IN BOOL MultipleSel,
+ IN PDISKSTATE DiskState,
+ IN DWORD RegionIndex
+ )
+
+/*++
+
+Routine Description:
+
+ This routine handles a user selection of a disk region. It is called
+ directly for a keyboard selection or indirectly for a mouse selection.
+ If not a multiple selection, all selected regions are deselected.
+ The focus rectangle is moved to the selected region, which is then
+ visually selected.
+
+Arguments:
+
+ MultipleSel - whether the user has made a multiple selection
+ (ie, control-clicked).
+
+ DiskState - master disk structure for disk containing selected region
+
+ RegionIndex - index of selected region on the disk
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ if (!MultipleSel)
+ {
+ // need to deselect all selected regions first.
+
+ DeselectSelectedDiskViewRegions(); // visual selection in disk view
+ DeselectSelectedRegions(); // actual selection state
+ }
+
+ //
+ // select or deselect the region
+ //
+
+ ToggleDiskSelection(DiskState, RegionIndex);
+
+ AdjustMenuAndStatus();
+}
+
+
+
+VOID
+MouseSelection(
+ IN BOOL MultipleSel,
+ IN OUT PPOINT ppt
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when the user clicks in the list box. It determines
+ which disk region the user has clicked on before calling the common
+ selection subroutine.
+
+Arguments:
+
+ MultipleSel - whether the user has made a multiple selection
+ (ie, control-clicked).
+
+ ppt - screen coords of the click
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDISKSTATE diskState;
+ DWORD selectedItem;
+ DWORD x;
+ DWORD y;
+ DWORD i;
+ RECT rc;
+ BOOL Valid;
+ PLEFTRIGHT leftRight;
+
+ if ((selectedItem = SendMessage(g_hwndList, LB_GETCURSEL, 0, 0)) == LB_ERR)
+ {
+ return;
+ }
+
+ // user has clicked on a list box item.
+
+ if (LBIsDisk(selectedItem))
+ {
+ diskState = DiskArray[LBIndexToDiskNumber(selectedItem)];
+
+ //
+ // Ignore clicks on off-line disks.
+ //
+
+ if (diskState->OffLine)
+ {
+ return;
+ }
+ }
+
+ ScreenToClient(g_hwndList, ppt);
+ x = ppt->x;
+ y = ppt->y;
+
+ // Now determine the client rectange of the listbox control
+
+ GetClientRect(g_hwndList, &rc);
+
+ // first make sure that the click was within a bar and not in space
+ // between two bars. This computation doesn't depend on the value
+ // of the horizontal scroll position.
+
+ Valid = FALSE;
+ for (i = rc.top; i <= (DWORD)rc.bottom; i += GraphHeight)
+ {
+ if ((y >= i+BarTopYOffset) && (y <= i+BarBottomYOffset))
+ {
+ Valid = TRUE;
+ break;
+ }
+ }
+ if (!Valid)
+ {
+ return;
+ }
+
+ if (LBIsDisk(selectedItem))
+ {
+ // determine which region was clicked on
+
+ for (i=0; i<diskState->RegionCount; i++)
+ {
+ leftRight = &diskState->LeftRight[i];
+ if ( (x >= (unsigned)leftRight->Left)
+ && (x <= (unsigned)leftRight->Right))
+ {
+ SelectDiskRegion(MultipleSel, diskState, i);
+ break;
+ }
+ }
+ }
+ else if (LBIsCdRom(selectedItem))
+ {
+ PCDROM_DESCRIPTOR cdrom = CdRomFindDevice(LBIndexToCdRomNumber(selectedItem));
+ leftRight = &cdrom->LeftRight;
+
+ if ( (x >= (unsigned)leftRight->Left)
+ && (x <= (unsigned)leftRight->Right))
+ {
+ SelectCdRom(MultipleSel, LBIndexToCdRomNumber(selectedItem));
+ }
+ }
+ else
+ {
+ FDASSERT(FALSE);
+ }
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: GetListviewDriveLetter
+//
+// Synopsis: Find the drive letter associated with a listview item
+//
+// Arguments: [Index] -- listview index
+//
+// Returns: Given a listview index, return the drive letter of the volume
+// at that index, or NO_DRIVE_LETTER if no volume is at that index
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+WCHAR
+GetListviewDriveLetter(
+ IN INT Index
+ )
+{
+ INT cch;
+ WCHAR buffer[MAX_LV_ITEM_LEN];
+
+ LV_ITEM lvi;
+ lvi.iSubItem = 0;
+ lvi.pszText = buffer;
+ lvi.cchTextMax = ARRAYLEN(buffer);
+
+ cch = SendMessage(g_hwndLV, LVM_GETITEMTEXT, (WPARAM)Index, (LPARAM)&lvi);
+
+ // the ListView_GetItemText macro doesn't allow you to get the return code
+
+ if (cch < 1)
+ {
+ daDebugOut((DEB_ERROR,
+ "GetListviewDriveLetter: Listview_GetItemText on item %d failed!\n",
+ Index));
+
+ return NO_DRIVE_LETTER_EVER; //BUGBUG: ok?
+ }
+
+ daDebugOut((DEB_ERROR,
+ "GetListviewDriveLetter: got %ws\n",
+ lvi.pszText));
+
+ return lvi.pszText[0];
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: SetVolumeSelection
+//
+// Synopsis: Given a listview index of the selection, reflect that selection
+// in the disks view.
+//
+// Arguments: [Index] -- listview index
+// [Selected] -- TRUE if the item should be selected
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+SetVolumeSelection(
+ IN INT Index,
+ IN BOOL Selected
+ )
+{
+ //
+ // Change the stored selection state
+ //
+
+ WCHAR driveLetter = GetListviewDriveLetter(Index);
+
+ if (CdRomUsingDriveLetter(driveLetter))
+ {
+ PCDROM_DESCRIPTOR cdrom = CdRomFindDriveLetter(driveLetter);
+ cdrom->Selected = Selected;
+ }
+ else
+ {
+ DWORD diskNum;
+ DWORD regionIndex;
+
+ for (diskNum = 0; diskNum < DiskCount; diskNum++)
+ {
+ PDISKSTATE diskState = DiskArray[diskNum];
+
+ for (regionIndex = 0; regionIndex < diskState->RegionCount; regionIndex++)
+ {
+ PREGION_DESCRIPTOR regionDescriptor = &diskState->RegionArray[regionIndex];
+
+ if (DmSignificantRegion(regionDescriptor))
+ {
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(regionDescriptor);
+
+ if (regionData->DriveLetter == driveLetter)
+ {
+ diskState->Selected[regionIndex] = Selected;
+
+ // don't break out or return: if this is an FT volume,
+ // there will be more regions.
+ }
+ }
+ }
+ }
+ }
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: ChangeToVolumesView
+//
+// Synopsis: Perform tasks necessary to switch the view to the volumes view
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+ChangeToVolumesView(
+ VOID
+ )
+{
+ PDISKSTATE diskState;
+ PREGION_DESCRIPTOR region;
+
+ //
+ // disable the Options: Legend, Colors, Disk Display, Region Display
+ //
+
+ EnableMenuItem(
+ g_hmenuFrame,
+ IDM_OPTIONSLEGEND,
+ MF_BYCOMMAND | MF_DISABLED
+ );
+
+ EnableMenuItem(
+ g_hmenuFrame,
+ IDM_OPTIONSCOLORS,
+ MF_BYCOMMAND | MF_DISABLED
+ );
+
+ EnableMenuItem(
+ g_hmenuFrame,
+ IDM_OPTIONSDISK,
+ MF_BYCOMMAND | MF_DISABLED
+ );
+
+ EnableMenuItem(
+ g_hmenuFrame,
+ IDM_OPTIONSDISPLAY,
+ MF_BYCOMMAND | MF_DISABLED
+ );
+
+ //
+ // Put the right stuff in the listview
+ //
+
+// CheckSelection();//BUGBUG: why is this necessary?
+ FillListView(FALSE);
+
+ //
+ // The following is done when changing to the volumes view:
+ // -- the focus is set. If the disks view focus is on free space, then
+ // put the focus on the first volume in the volumes view.
+ // -- adjust the selection: deselect all free space.
+ //
+
+ //
+ // set g_SettingListviewState to avoid handling listview notifications here
+ //
+
+ g_SettingListviewState = TRUE;
+
+ //
+ // determine which item will get the focus, and give it to it
+ //
+
+ INT index = -1;
+ WCHAR driveLetter;
+
+ if (LBIsDisk(LBCursorListBoxItem))
+ {
+ diskState = DiskArray[LBIndexToDiskNumber(LBCursorListBoxItem)];
+ region = &diskState->RegionArray[LBCursorRegion];
+
+ if (DmSignificantRegion(region))
+ {
+ //
+ // Find the volume in the volumes view that has the focus in the
+ // disks view
+ //
+
+ driveLetter = PERSISTENT_DATA(region)->DriveLetter;
+
+ if (!IsExtraDriveLetter(driveLetter))
+ {
+ index = GetLVIndexFromDriveLetter(driveLetter);
+ }
+ }
+ }
+ else if (LBIsCdRom(LBCursorListBoxItem))
+ {
+ PCDROM_DESCRIPTOR cdrom = CdRomFindDevice(LBIndexToCdRomNumber(LBCursorListBoxItem));
+ driveLetter = cdrom->DriveLetter;
+ index = GetLVIndexFromDriveLetter(driveLetter);
+ }
+
+ if (-1 == index)
+ {
+ if (ListView_GetItemCount(g_hwndLV) > 0)
+ {
+ index = 0;
+ }
+ }
+
+ if (index != -1)
+ {
+ daDebugOut((DEB_SEL,
+ "listview focus ==> %wc:(%d)\n",
+ driveLetter,
+ index));
+
+ // Give the item both the focus *and* the selection, since we only
+ // allow a single listview selection
+
+ ListView_SetItemState(
+ g_hwndLV,
+ index,
+ LVIS_FOCUSED | LVIS_SELECTED,
+ LVIS_FOCUSED | LVIS_SELECTED);
+ ListView_EnsureVisible(g_hwndLV, index, FALSE);
+
+ SetVolumeSelection(index, TRUE); // reflect in disks view
+ }
+ else
+ {
+ daDebugOut((DEB_ITRACE, "Nobody gets the focus\n"));
+ }
+
+#if 0
+
+ //BUGBUG: this section is commented out. We used to ensure that the
+ // the selection in the list view was exactly the same as in the disks
+ // view, except for items that doen't show up in the volumes view.
+ // Now, we only allow a single selection in the volumes view. So, we've
+ // added code above to make the focus the selection as well. The following
+ // code can probably be deleted, but I'm too much a pack rat to do
+ // it right now.
+
+ //
+ // For every selected volume, select it in the volumes
+ // view. This code unfortunately sends an FT volume "select" messages
+ // once for every region composing the FT set.
+ //
+
+ ULONG disk;
+ PPERSISTENT_REGION_DATA regionData;
+ ULONG regionIndex;
+
+ daDebugOut((DEB_SEL, "selection ==> "));
+
+ for (disk=0; disk<DiskCount; disk++)
+ {
+ diskState = DiskArray[disk];
+
+ for (regionIndex=0; regionIndex<diskState->RegionCount; regionIndex++)
+ {
+ if (diskState->Selected[regionIndex])
+ {
+ region = &diskState->RegionArray[regionIndex];
+ regionData = PERSISTENT_DATA(region);
+
+ if (NULL != regionData)
+ {
+ driveLetter = regionData->DriveLetter;
+
+ index = GetLVIndexFromDriveLetter(driveLetter);
+
+ if (-1 != index)
+ {
+ //
+ // if the volume has a drive letter...
+ //
+
+ daDebugOut((DEB_SEL | DEB_NOCOMPNAME,
+ "%wc:(%d, disk %d, region %d); ",
+ driveLetter,
+ index,
+ disk,
+ regionIndex
+ ));
+
+ ListView_SetItemState(
+ g_hwndLV,
+ index,
+ LVIS_SELECTED,
+ LVIS_SELECTED
+ );
+ }
+ }
+ }
+ }
+ }
+
+ daDebugOut((DEB_SEL | DEB_NOCOMPNAME, "\n"));
+
+#endif // 0
+
+
+ //
+ // we can take notifications again...
+ //
+
+ g_SettingListviewState = FALSE;
+
+ //
+ // Disable the disks view listbox control
+ //
+
+ ShowWindow(g_hwndList, SW_HIDE);
+ ShowWindow(g_hwndLV, SW_SHOW);
+
+ SetFocus(g_hwndLV); // give listview the focus
+
+ //
+ // Initialize listview sorting direction array
+ //
+
+ g_aColumnOrder = 1;
+ g_iLastColumnSorted = -1;
+
+ //
+ // Change the menu
+ //
+
+ AdjustMenuAndStatus();
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: SetFocusFromListview
+//
+// Synopsis: Using the current listview focus, set the disks view focus
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 2-Sep-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+SetFocusFromListview(
+ VOID
+ )
+{
+ //
+ // set the focus. Pick a random region from the volume that has the
+ // focus. For instance, if volume "F:" has the focus, then pick any of
+ // its component regions---e.g., it doesn't matter which region of a volume
+ // set gets the focus.
+ //
+
+#if DBG == 1
+
+ {
+ INT item;
+
+ //
+ // Verify that there is exactly one volume with the focus
+ //
+
+ if (-1 == (item = ListView_GetNextItem(g_hwndLV, -1, LVNI_FOCUSED)))
+ {
+ daDebugOut((DEB_ERROR, "No volume has the focus!\n"));
+ }
+ else if (-1 != ListView_GetNextItem(g_hwndLV, item, LVNI_FOCUSED))
+ {
+ daDebugOut((DEB_ERROR, "More than one volume has the focus!\n"));
+ }
+
+ item = -1;
+ while ((item = ListView_GetNextItem(g_hwndLV, item, LVNI_FOCUSED))
+ != -1)
+ {
+ daDebugOut((DEB_ITRACE, "Listview item %d has the focus\n", item));
+// daDebugOut((DEB_SEL, "Listview item %d has the focus\n", item));
+ }
+ }
+
+#endif // DBG == 1
+
+ INT item = ListView_GetNextItem(g_hwndLV, -1, LVNI_FOCUSED);
+ if (-1 != item)
+ {
+ WCHAR driveLetter = GetListviewDriveLetter(item);
+
+ if (CdRomUsingDriveLetter(driveLetter))
+ {
+ ToggleLBCursor(NULL);
+ LBCursorListBoxItem = LBCdRomNumberToIndex(CdRomFindDeviceNumber(driveLetter));
+ LBCursorRegion = 0;
+ ToggleLBCursor(NULL);
+ }
+ else
+ {
+ PDISKSTATE diskState;
+ INT regionIndex;
+
+ GetInfoFromDriveLetter(driveLetter, &diskState, &regionIndex);
+
+ ToggleLBCursor(NULL);
+ LBCursorListBoxItem = LBDiskNumberToIndex(diskState->Disk);
+ LBCursorRegion = regionIndex;
+ ToggleLBCursor(NULL);
+ }
+ }
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: ChangeToDisksView
+//
+// Synopsis: Perform tasks necessary to switch the view to the disks view
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+ChangeToDisksView(
+ VOID
+ )
+{
+ CheckTBButton(IDM_VIEWDISKS);
+
+ //
+ // Enable the disks view listbox control
+ //
+
+ ShowWindow(g_hwndLV, SW_HIDE);
+ ShowWindow(g_hwndList, SW_SHOW);
+
+ SetFocus(g_hwndList); // give listbox the focus
+ ForceLBRedraw();
+
+ //
+ // enable the Options: Legend, Colors, Disk Display, Region Display
+ //
+
+ EnableMenuItem(
+ g_hmenuFrame,
+ IDM_OPTIONSLEGEND,
+ MF_BYCOMMAND | MF_ENABLED
+ );
+
+ EnableMenuItem(
+ g_hmenuFrame,
+ IDM_OPTIONSCOLORS,
+ MF_BYCOMMAND | MF_ENABLED
+ );
+
+ EnableMenuItem(
+ g_hmenuFrame,
+ IDM_OPTIONSDISK,
+ MF_BYCOMMAND | MF_ENABLED
+ );
+
+ EnableMenuItem(
+ g_hmenuFrame,
+ IDM_OPTIONSDISPLAY,
+ MF_BYCOMMAND | MF_ENABLED
+ );
+
+ SetFocusFromListview();
+}
diff --git a/private/utils/windisk/src/select.hxx b/private/utils/windisk/src/select.hxx
new file mode 100644
index 000000000..6d10926e2
--- /dev/null
+++ b/private/utils/windisk/src/select.hxx
@@ -0,0 +1,108 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: select.hxx
+//
+// Contents: Routines for handling selection and focus in the volumes
+// and disks views.
+//
+// History: 3-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __SELECT_HXX__
+#define __SELECT_HXX__
+
+//////////////////////////////////////////////////////////////////////////////
+
+extern ULONG g_MouseLBIndex;
+
+//////////////////////////////////////////////////////////////////////////////
+
+VOID
+AdjustMenuAndStatus(
+ VOID
+ );
+
+INT
+GetLVIndexFromDriveLetter(
+ IN WCHAR DriveLetter
+ );
+
+VOID
+CheckSelection(
+ VOID
+ );
+
+VOID
+PaintCdRom(
+ IN ULONG CdRomNumber,
+ IN HDC hdc
+ );
+
+VOID
+PaintDiskRegion(
+ IN PDISKSTATE DiskState,
+ IN DWORD RegionIndex,
+ IN HDC hdc
+ );
+
+VOID
+SetVolumeSelectedState(
+ IN WCHAR DriveLetter,
+ IN BOOL Select
+ );
+
+VOID
+DeselectSelectedRegions(
+ VOID
+ );
+
+VOID
+DeselectSelectedDiskViewRegions(
+ VOID
+ );
+
+VOID
+SelectCdRom(
+ IN BOOL MultipleSel,
+ IN ULONG CdRomNumber
+ );
+
+VOID
+SelectDiskRegion(
+ IN BOOL MultipleSel,
+ IN PDISKSTATE DiskState,
+ IN DWORD region
+ );
+
+VOID
+MouseSelection(
+ IN BOOL MultipleSel,
+ IN OUT PPOINT ppt
+ );
+
+WCHAR
+GetListviewDriveLetter(
+ IN INT index
+ );
+
+VOID
+SetVolumeSelection(
+ IN INT index,
+ IN BOOL Selected
+ );
+
+VOID
+ChangeToVolumesView(
+ VOID
+ );
+
+VOID
+ChangeToDisksView(
+ VOID
+ );
+
+#endif // __SELECT_HXX__
diff --git a/private/utils/windisk/src/shard.ico b/private/utils/windisk/src/shard.ico
new file mode 100644
index 000000000..d7c0bc280
--- /dev/null
+++ b/private/utils/windisk/src/shard.ico
Binary files differ
diff --git a/private/utils/windisk/src/smcdrom.bmp b/private/utils/windisk/src/smcdrom.bmp
new file mode 100644
index 000000000..b8040e819
--- /dev/null
+++ b/private/utils/windisk/src/smcdrom.bmp
Binary files differ
diff --git a/private/utils/windisk/src/smdisk.bmp b/private/utils/windisk/src/smdisk.bmp
new file mode 100644
index 000000000..db2c6b252
--- /dev/null
+++ b/private/utils/windisk/src/smdisk.bmp
Binary files differ
diff --git a/private/utils/windisk/src/sources b/private/utils/windisk/src/sources
new file mode 100644
index 000000000..7e2e83adc
--- /dev/null
+++ b/private/utils/windisk/src/sources
@@ -0,0 +1,79 @@
+!include ..\windisk.mk
+
+# BUGBUG: name should be just "windisk"
+TARGETNAME= windisk
+#TARGETNAME= windisk2
+
+TARGETTYPE= PROGRAM
+TARGETPATH= obj
+
+UMTYPE= windows
+UMRES= obj\*\windisk.res
+
+TARGETLIBS=\
+ ..\debug\obj\*\debug.lib \
+ ..\util\obj\*\util.lib \
+ ..\controls\obj\*\controls.lib \
+ $(BASEDIR)\public\sdk\lib\*\diskreg.lib \
+ $(BASEDIR)\public\sdk\lib\*\comctl32.lib \
+ $(BASEDIR)\public\sdk\lib\*\comdlg32.lib \
+ $(BASEDIR)\public\sdk\lib\*\shell32.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\netapi32.lib
+
+INCLUDES=\
+ obj; \
+ ..\inc; \
+ ..\util; \
+ ..\controls; \
+ ..\..\fmifs\inc; \
+ $(BASEDIR)\private\windows\inc; \
+ $(BASEDIR)\private\windows\inc16; \
+ $(INCLUDES)
+
+SOURCES=\
+ messages.mc \
+ cdrom.cxx \
+ cm.cxx \
+ commit.cxx \
+ data.cxx \
+ dblspace.cxx \
+ dispinfo.cxx \
+ dlgs.cxx \
+ drives.cxx \
+ engine.cxx \
+ fill.cxx \
+ fmifs.cxx \
+ format.cxx \
+ fs.cxx \
+ ft.cxx \
+ ftreg.cxx \
+ help.cxx \
+ help2.cxx \
+ init.cxx \
+ listbox.cxx \
+ log.cxx \
+ mem.cxx \
+ menudict.cxx \
+ misc.cxx \
+ network.cxx \
+ nt.cxx \
+ ntlow.cxx \
+ oleclass.cxx \
+ ops.cxx \
+ popup.cxx \
+ profile.cxx \
+ ps.cxx \
+ rect.cxx \
+ select.cxx \
+ stleg.cxx \
+ tbar.cxx \
+ volview.cxx \
+ windisk.cxx
+
+PRECOMPILED_INCLUDE=headers.hxx
+PRECOMPILED_CXX=1
+
+NTTARGETFILE1= obj\*\windisk.res
+PASS0_HEADERDIR=obj
+PASS0_SOURCEDIR=obj
diff --git a/private/utils/windisk/src/stleg.cxx b/private/utils/windisk/src/stleg.cxx
new file mode 100644
index 000000000..adc97c646
--- /dev/null
+++ b/private/utils/windisk/src/stleg.cxx
@@ -0,0 +1,534 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: stleg.cxx
+//
+// Contents: Routines to support the status bar and legend displays.
+//
+// History: 7-Jan-92 TedM Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include "stleg.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+PWSTR LegendLabels[LEGEND_STRING_COUNT];
+
+// text for status area
+
+WCHAR StatusTextStat[STATUS_TEXT_SIZE];
+WCHAR StatusTextSize[STATUS_TEXT_SIZE];
+WCHAR StatusTextDrlt[3];
+WCHAR StatusTextType[STATUS_TEXT_SIZE];
+WCHAR StatusTextVoll[STATUS_TEXT_SIZE];
+
+
+// The following indices apply to the fAnyOfType array. They must
+// parallel the BRUSH_* constants:
+
+#define ANYOF_PRIMARY 0
+#define ANYOF_LOGICAL 1
+#define ANYOF_STRIPE 2
+#define ANYOF_PARITY 3
+#define ANYOF_MIRROR 4
+#define ANYOF_VOLSET 5
+
+BOOL fAnyOfType[LEGEND_STRING_COUNT];
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: UpdateStatusBarDisplay
+//
+// Synopsis: Cause the status bar and legend areas of the display to be
+// invalidated (and hence redrawn).
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+UpdateStatusBarDisplay(
+ VOID
+ )
+{
+ //
+ // The legend can change; we only display legend items for types
+ // that exist on the screen
+ //
+
+ if ( g_StatusBar
+ || (g_Legend && (VIEW_DISKS == g_WhichView)))
+ {
+ RECT rc;
+
+ GetClientRect(g_hwndFrame, &rc);
+ rc.top = rc.bottom;
+
+ if (g_Legend)
+ {
+ rc.top -= g_dyLegend;
+ }
+
+ if (g_StatusBar)
+ {
+ rc.top -= g_dyStatus;
+ }
+
+ InvalidateRect(g_hwndFrame, &rc, FALSE);
+ }
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: ClearStatusArea
+//
+// Synopsis: Clear the status area of any message
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+ClearStatusArea(
+ VOID
+ )
+{
+ StatusTextStat[0]
+ = StatusTextSize[0]
+ = StatusTextVoll[0]
+ = StatusTextType[0]
+ = StatusTextDrlt[0]
+ = L'\0';
+
+ UpdateStatusBarDisplay();
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DetermineExistence
+//
+// Synopsis: Determine what types of volumes exist so we know what legend
+// items to show
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// Modifies: [fAnyOfType]
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DetermineExistence(
+ VOID
+ )
+{
+ UINT i, j;
+ PDISKSTATE diskState;
+ PREGION_DESCRIPTOR regionDescriptor;
+ PFT_OBJECT ftObject;
+ PFT_OBJECT_SET ftSet;
+
+ for (i=0; i<LEGEND_STRING_COUNT; i++)
+ {
+ fAnyOfType[i] = FALSE;
+ }
+
+ for (i=0; i<DiskCount; i++)
+ {
+ diskState = DiskArray[i];
+ for (j=0; j<diskState->RegionCount; j++)
+ {
+ regionDescriptor = &diskState->RegionArray[j];
+ if (NULL != (ftObject = GET_FT_OBJECT(regionDescriptor)))
+ {
+ ftSet = ftObject->Set;
+
+ switch (ftSet->Type)
+ {
+ case Stripe:
+ fAnyOfType[ANYOF_STRIPE] = TRUE;
+ break;
+
+ case StripeWithParity:
+ fAnyOfType[ANYOF_PARITY] = TRUE;
+ break;
+
+ case Mirror:
+ fAnyOfType[ANYOF_MIRROR] = TRUE;
+ break;
+
+ case VolumeSet:
+ fAnyOfType[ANYOF_VOLSET] = TRUE;
+ break;
+ }
+ }
+ else
+ {
+ if (regionDescriptor->SysID != PARTITION_ENTRY_UNUSED
+ && !IsExtended(regionDescriptor->SysID))
+ {
+ if (REGION_PRIMARY == regionDescriptor->RegionType)
+ {
+ fAnyOfType[ANYOF_PRIMARY] = TRUE;
+ }
+ else if (REGION_LOGICAL == regionDescriptor->RegionType)
+ {
+ fAnyOfType[ANYOF_LOGICAL] = TRUE;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+VOID
+CalculateLegendHeight(
+ IN DWORD newGraphWidth
+ )
+
+/*++
+
+Routine Description:
+
+ This routine calculates the legend height. It may be a multi-row
+ legend.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DWORD width = 0;
+ DWORD elementWidth;
+ DWORD allowedWidth = newGraphWidth - 18*g_dyBorder;
+ SIZE size;
+ UINT rows = 1;
+ UINT i;
+ HDC hdc = GetDC(g_hwndFrame);
+ HFONT hfontOld = SelectFont(hdc, g_hFontLegend);
+
+ for (i=0; i<BRUSH_ARRAY_SIZE; i++)
+ {
+ if (fAnyOfType[i])
+ {
+ GetTextExtentPoint32(
+ hdc,
+ LegendLabels[i],
+ lstrlen(LegendLabels[i]),
+ &size
+ );
+
+ elementWidth = (DWORD)size.cx + (5*g_wLegendItem/2);
+
+ if ( width != 0
+ && (width + elementWidth > allowedWidth))
+ {
+ width = 0;
+ ++rows;
+ }
+
+ width += elementWidth;
+ }
+ }
+
+ g_dyLegend = rows * g_wLegendItem // height of a row
+ + (rows + 1) * g_dyLegendSep // separation between rows
+ // + border on top
+ // + border on bottom
+ + 2 * (3*g_dyBorder) // the top & bottom bevelling eat
+ // ... up 3*g_dyBorder each
+ ;
+
+ if (NULL != hfontOld)
+ {
+ SelectFont(hdc, hfontOld);
+ }
+ ReleaseDC(g_hwndFrame, hdc);
+}
+
+
+VOID
+DrawLegend(
+ IN HDC hdc,
+ IN PRECT prc
+ )
+
+/*++
+
+Routine Description:
+
+ This routine draws the legend onto the given device context. The legend
+ lists the brush styles used to indicate various region types in the
+ disk graphs.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DWORD width;
+ DWORD elementWidth;
+ DWORD allowedWidth;
+ DWORD i;
+ DWORD left;
+ DWORD top;
+ DWORD leftMargin;
+ DWORD topMargin;
+ DWORD delta = GraphWidth / BRUSH_ARRAY_SIZE;
+ RECT rc1;
+ RECT rc2;
+ RECT rcClip;
+ HFONT hfontOld;
+ HBRUSH hBrush;
+ SIZE size;
+ COLORREF oldTextColor;
+ COLORREF oldBkColor;
+
+ rc1 = *prc;
+ rc2 = *prc;
+
+ allowedWidth = prc->right - prc->left - 18*g_dyBorder;
+
+ // first draw the background.
+
+ hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
+ rc1.right = rc1.left + GraphWidth; // erase it all
+ FillRect(hdc, &rc1, hBrush);
+ DeleteBrush(hBrush);
+
+ // now draw the nice container
+
+ rc2.left += 8 * g_dyBorder;
+ rc2.right -= 8 * g_dyBorder;
+ DrawStatusAreaItem(&rc2, hdc, NULL);
+
+ // now draw the legend items
+
+ leftMargin = rc2.left + (g_wLegendItem / 2);
+ topMargin = prc->top + (g_dyBorder*3) + g_dyLegendSep;
+
+ SelectPen(hdc, g_hPenThinSolid);
+ SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));
+ hfontOld = SelectFont(hdc, g_hFontLegend);
+ oldTextColor = SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
+ SetBkMode(hdc, OPAQUE);
+
+ rcClip.left = rc2.left + g_dyBorder;
+ rcClip.top = rc2.top + (3*g_dyBorder);
+ rcClip.right = rc2.right - g_dyBorder;
+ rcClip.bottom = rc2.bottom - (3*g_dyBorder);
+
+ IntersectClipRect(hdc, rcClip.left, rcClip.top, rcClip.right, rcClip.bottom);
+
+ left = leftMargin;
+ top = topMargin;
+ width = 0;
+ for (i=0; i<BRUSH_ARRAY_SIZE; i++)
+ {
+ if (fAnyOfType[i])
+ {
+ GetTextExtentPoint32(
+ hdc,
+ LegendLabels[i],
+ lstrlen(LegendLabels[i]),
+ &size
+ );
+
+ elementWidth = (DWORD)size.cx + (5*g_wLegendItem/2);
+
+ if ( width != 0
+ && (width + elementWidth > allowedWidth))
+ {
+ top += g_wLegendItem + g_dyLegendSep; // row height + margin
+ left = leftMargin;
+ width = 0;
+ }
+
+ width += elementWidth;
+
+ hBrush = SelectBrush(hdc, g_Brushes[i]);
+
+ oldBkColor = SetBkColor(hdc, RGB(255, 255, 255));
+
+ Rectangle(
+ hdc,
+ left,
+ top,
+ left + g_wLegendItem,
+ top + g_wLegendItem
+ );
+
+ SetBkColor(hdc, oldBkColor);
+
+ ExtTextOut(
+ hdc,
+ left + (3*g_wLegendItem/2),
+ top + ((g_wLegendItem-size.cy)/2), // vertically center it
+ ETO_CLIPPED,
+ &rcClip,
+ LegendLabels[i],
+ lstrlen(LegendLabels[i]),
+ NULL
+ );
+
+ left += elementWidth;
+
+ if (NULL != hBrush)
+ {
+ SelectBrush(hdc, hBrush);
+ }
+ }
+ }
+
+ SelectClipRgn(hdc, NULL); // reset to no clipping region
+
+ if (NULL != hfontOld)
+ {
+ SelectFont(hdc, hfontOld);
+ }
+
+ SetTextColor(hdc, oldTextColor);
+}
+
+
+
+VOID
+DrawStatusAreaItem(
+ IN PRECT prc,
+ IN HDC hdc,
+ IN LPTSTR Text
+ )
+
+/*++
+
+Routine Description:
+
+ This routine draws a status area item into a given dc. This
+ includes drawing the nice shaded button-like container, and
+ then drawing text within it.
+
+Arguments:
+
+ prc - rectangle describing the status area item
+
+ hdc - device context into which to draw
+
+ Text - optional parameter that if present represents text to
+ be placed in the item.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ HBRUSH hBrush;
+ RECT rcx;
+
+ // the shadow
+
+ if (NULL != (hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW))))
+ {
+ // left edge
+
+ rcx.left = prc->left;
+ rcx.right = prc->left + g_dyBorder;
+ rcx.top = prc->top + (2*g_dyBorder);
+ rcx.bottom = prc->bottom - (2*g_dyBorder);
+ FillRect(hdc, &rcx, hBrush);
+
+ // top edge
+
+ rcx.right = prc->right;
+ rcx.bottom = rcx.top + g_dyBorder;
+ FillRect(hdc, &rcx, hBrush);
+
+ DeleteBrush(hBrush);
+ }
+
+ // the highlight
+
+ if (NULL != (hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNHIGHLIGHT))))
+ {
+ // right edge
+
+ rcx.left = prc->right - g_dyBorder;
+ rcx.right = prc->right;
+ rcx.top = prc->top + (2*g_dyBorder);
+ rcx.bottom = prc->bottom - (2*g_dyBorder);
+ FillRect(hdc, &rcx, hBrush);
+
+ // bottom edge
+
+ rcx.left = prc->left;
+ rcx.right = prc->right;
+ rcx.top = prc->bottom - (3*g_dyBorder);
+ rcx.bottom = rcx.top + g_dyBorder;
+ FillRect(hdc, &rcx, hBrush);
+
+ DeleteBrush(hBrush);
+ }
+
+ if (Text)
+ {
+ // draw the text
+
+ SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
+ SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));
+
+ rcx.top = prc->top + (3*g_dyBorder);
+ rcx.bottom = prc->bottom - (3*g_dyBorder);
+ rcx.left = prc->left + g_dyBorder;
+ rcx.right = prc->right - g_dyBorder;
+
+ ExtTextOut(
+ hdc,
+ rcx.left+(2*g_dyBorder),
+ rcx.top,
+ ETO_OPAQUE | ETO_CLIPPED,
+ &rcx,
+ Text,
+ lstrlen(Text),
+ NULL
+ );
+ }
+}
diff --git a/private/utils/windisk/src/stleg.hxx b/private/utils/windisk/src/stleg.hxx
new file mode 100644
index 000000000..c3106b959
--- /dev/null
+++ b/private/utils/windisk/src/stleg.hxx
@@ -0,0 +1,50 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: stleg.hxx
+//
+// Contents: Routines for handling the status bar and legend
+//
+// History: 26-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __STLEG_HXX__
+#define __STLEG_HXX__
+
+VOID
+UpdateStatusBarDisplay(
+ VOID
+ );
+
+VOID
+ClearStatusArea(
+ VOID
+ );
+
+VOID
+DetermineExistence(
+ VOID
+ );
+
+VOID
+CalculateLegendHeight(
+ IN DWORD newGraphWidth
+ );
+
+VOID
+DrawLegend(
+ IN HDC hdc,
+ IN PRECT rc
+ );
+
+VOID
+DrawStatusAreaItem(
+ IN PRECT rc,
+ IN HDC hdc,
+ IN LPTSTR Text
+ );
+
+#endif // __STLEG_HXX__
diff --git a/private/utils/windisk/src/tb.h b/private/utils/windisk/src/tb.h
new file mode 100644
index 000000000..7ef159c6e
--- /dev/null
+++ b/private/utils/windisk/src/tb.h
@@ -0,0 +1,129 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: tb.h
+//
+// Contents: Message APIs for the toolbar control
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __TB_H__
+#define __TB_H__
+
+// void Toolbar_AddBitmap(HWND hwnd, int nButtons, HINSTANCE hBMInst, UINT nBMID);
+#define Toolbar_AddBitmap(hwnd, nButtons, hBMInst, nBMID) \
+ { TBADDBITMAP _tbBM; \
+ _tbBM.hInst = hBMInst; \
+ _tbBM.nID = nBMID; \
+ (int)SendMessage((hwnd),TB_ADDBITMAP,(WPARAM)(nButtons),(LPARAM)&_tbBM); \
+ }
+
+// BOOL Toolbar_AddButtons(HWND hwnd, int nButtons, LPTBBUTTON lpButtons);
+#define Toolbar_AddButtons(hwnd, nButtons, lpButtons) \
+ (BOOL)SendMessage((hwnd),TB_ADDBUTTONS,(WPARAM)(nButtons),(LPARAM)(LPTBBUTTON)(lpButtons))
+
+// int Toolbar_AddString(HWND hwnd, HINSTANCE hInst, UINT idString);
+#define Toolbar_AddString(hwnd, hInst, idString) \
+ (int)SendMessage((hwnd),TB_ADDSTRING,(WPARAM)(HINSTANCE)(hInst),(LPARAM)(MAKELPARAM((idString),0)))
+
+// void Toolbar_AutoSize(HWND hwnd);
+#define Toolbar_AutoSize(hwnd) \
+ (void)SendMessage((hwnd),TB_AUTOSIZE,(WPARAM)0,(LPARAM)0)
+
+// int Toolbar_ButtonCount(HWND hwnd);
+#define Toolbar_ButtonCount(hwnd) \
+ (int)SendMessage((hwnd),TB_BUTTONCOUNT,(WPARAM)0,(LPARAM)0)
+
+// int Toolbar_ButtonStructSize(HWND hwnd, int cb);
+#define Toolbar_ButtonStructSize(hwnd, cb) \
+ (int)SendMessage((hwnd),TB_BUTTONSTRUCTSIZE,(WPARAM)(cb),(LPARAM)0)
+
+// BOOL Toolbar_CheckButton(HWND hwnd, UINT idButton, BOOL fCheck);
+#define Toolbar_CheckButton(hwnd, idButton, fCheck) \
+ (BOOL)SendMessage((hwnd),TB_CHECKBUTTON,(WPARAM)(idButton),(LPARAM)MAKELPARAM((fCheck),0))
+
+// int Toolbar_CommandToIndex(HWND hwnd, UINT idButton);
+#define Toolbar_CommandToIndex(hwnd, idButton) \
+ (int)SendMessage((hwnd),TB_COMMANDTOINDEX,(WPARAM)(idButton),(LPARAM)0)
+
+// void Toolbar_Customize(HWND hwnd);
+#define Toolbar_Customize(hwnd) \
+ (void)SendMessage((hwnd),TB_CUSTOMIZE,(WPARAM)0,(LPARAM)0)
+
+// BOOL Toolbar_DeleteButton(HWND hwnd, UINT idButton);
+#define Toolbar_DeleteButton(hwnd, idButton) \
+ (BOOL)SendMessage((hwnd),TB_DELETEBUTTON,(WPARAM)(idButton),(LPARAM)0)
+
+// BOOL Toolbar_EnableButton(HWND hwnd, UINT idButton, BOOL fEnable);
+#define Toolbar_EnableButton(hwnd, idButton, fEnable) \
+ (BOOL)SendMessage((hwnd),TB_ENABLEBUTTON,(WPARAM)(idButton),(LPARAM)MAKELPARAM((fEnable),0))
+
+// BOOL Toolbar_GetButton(HWND hwnd, UINT iButton, LPTBBUTTON lpButton);
+#define Toolbar_GetButton(hwnd, iButton, lpButton) \
+ (BOOL)SendMessage((hwnd),TB_GETBUTTON,(WPARAM)(iButton),(LPARAM)(LPTBBUTTON)(lpButton))
+
+// BOOL Toolbar_GetItemRect(HWND hwnd, UINT iButton, LPRECT lpRect);
+#define Toolbar_GetItemRect(hwnd, iButton, lpRect) \
+ (BOOL)SendMessage((hwnd),TB_GETITEMRECT,(WPARAM)(iButton),(LPARAM)(LPRECT)(lpRect))
+
+// int Toolbar_GetState(HWND hwnd, UINT iButton);
+#define Toolbar_GetState(hwnd, iButton, lpRect) \
+ (int)SendMessage((hwnd),TB_GETSTATE,(WPARAM)(iButton),(LPARAM)0)
+
+// BOOL Toolbar_HideButton(HWND hwnd, UINT idButton, BOOL fShow);
+#define Toolbar_HideButton(hwnd, idButton, fShow) \
+ (BOOL)SendMessage((hwnd),TB_HIDEBUTTON,(WPARAM)(idButton),(LPARAM)MAKELPARAM((fShow),0))
+
+// BOOL Toolbar_Indeterminate(HWND hwnd, UINT iButton, BOOL fIndeterminate);
+#define Toolbar_Indeterminate(hwnd, iButton, fIndeterminate) \
+ (BOOL)SendMessage((hwnd),TB_INDETERMINATE,(WPARAM)(iButton),(LPARAM)MAKELPARAM((fIndeterminate),0))
+
+// BOOL Toolbar_InsertButton(HWND hwnd, UINT iButton, LPTBBUTTON lpButton);
+#define Toolbar_InsertButton(hwnd, iButton, lpButton) \
+ (BOOL)SendMessage((hwnd),TB_INSERTBUTTON,(WPARAM)(iButton),(LPARAM)(LPTBBUTTON)(lpButton))
+
+// int Toolbar_IsButtonChecked(HWND hwnd, UINT idButton);
+#define Toolbar_IsButtonChecked(hwnd, idButton) \
+ (int)SendMessage((hwnd),TB_ISBUTTONCHECKED,(WPARAM)(idButton),(LPARAM)0)
+
+// int Toolbar_IsButtonEnabled(HWND hwnd, UINT idButton);
+#define Toolbar_IsButtonEnabled(hwnd, idButton) \
+ (int)SendMessage((hwnd),TB_ISBUTTONENABLED,(WPARAM)(idButton),(LPARAM)0)
+
+// int Toolbar_IsButtonHidden(HWND hwnd, UINT idButton);
+#define Toolbar_IsButtonHidden(hwnd, idButton) \
+ (int)SendMessage((hwnd),TB_ISBUTTONHIDDEN,(WPARAM)(idButton),(LPARAM)0)
+
+// int Toolbar_IsButtonIndeterminate(HWND hwnd, UINT idButton);
+#define Toolbar_IsButtonIndeterminate(hwnd, idButton) \
+ (int)SendMessage((hwnd),TB_ISBUTTONINDETERMINATE,(WPARAM)(idButton),(LPARAM)0)
+
+// int Toolbar_IsButtonPressed(HWND hwnd, UINT idButton);
+#define Toolbar_IsButtonPressed(hwnd, idButton) \
+ (int)SendMessage((hwnd),TB_ISBUTTONPRESSED,(WPARAM)(idButton),(LPARAM)0)
+
+// BOOL Toolbar_PressButton(HWND hwnd, UINT idButton, BOOL fPress);
+#define Toolbar_PressButton(hwnd, idButton, fPress) \
+ (BOOL)SendMessage((hwnd),TB_PRESSBUTTON,(WPARAM)(idButton),(LPARAM)MAKELPARAM((fPress),0))
+
+// BOOL Toolbar_SaveRestore(HWND hwnd, BOOL fSave, TBSAVEPARAMS* lpSaveRestore);
+#define Toolbar_SaveRestore(hwnd, fSave, lpSaveRestore) \
+ (BOOL)SendMessage((hwnd),TB_SAVERESTORE,(WPARAM)(fSave),(LPARAM)(TBSAVEPARAMS*)(lpSaveRestore))
+
+// BOOL Toolbar_SetBitmapSize(HWND hwnd, WORD dxBitmap, WORD dyBitmap);
+#define Toolbar_SetBitmapSize(hwnd, dxBitmap, dyBitmap) \
+ (BOOL)SendMessage((hwnd),TB_SETBITMAPSIZE,(WPARAM)0,(LPARAM)MAKELPARAM((dxBitmap),(dyBitmap)))
+
+// BOOL Toolbar_SetButtonSize(HWND hwnd, WORD dxButton, WORD dyButton);
+#define Toolbar_SetButtonSize(hwnd, dxButton, dyButton) \
+ (BOOL)SendMessage((hwnd),TB_SETBUTTONSIZE,(WPARAM)0,(LPARAM)MAKELPARAM((dxButton),(dyButton)))
+
+// BOOL Toolbar_SetState(HWND hwnd, UINT idButton, BOOL fState);
+#define Toolbar_SetState(hwnd, idButton, fState) \
+ (BOOL)SendMessage((hwnd),TB_SETSTATE,(WPARAM)(idButton),(LPARAM)MAKELPARAM((fState),0))
+
+#endif // __TB_H__
diff --git a/private/utils/windisk/src/tbar.cxx b/private/utils/windisk/src/tbar.cxx
new file mode 100644
index 000000000..d15f8c86a
--- /dev/null
+++ b/private/utils/windisk/src/tbar.cxx
@@ -0,0 +1,701 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: tbar.cxx
+//
+// Contents: Disk Administrator toolbar support routines.
+//
+// History: 7-Jun-93 BruceFo Created from NT winfile
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include <util.hxx>
+
+#include "help.hxx"
+#include "help2.hxx"
+#include "profile.hxx"
+#include "stleg.hxx"
+#include "tb.h"
+#include "tbar.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+LRESULT
+Toolbar_OnGetButtonInfo(
+ IN OUT TBNOTIFY* ptbn
+ );
+
+//////////////////////////////////////////////////////////////////////////////
+
+#define DX_BITMAP 16
+#define DY_BITMAP 16
+
+#define MAXDESCLEN 128
+
+#define TBAR_BITMAP_COUNT 14 /* number of std toolbar bitmaps */
+#define TBAR_EXTRA_BITMAPS 4
+
+/* Note that the idsHelp field is used internally to determine if the
+ * button is "available" or not.
+ */
+static TBBUTTON tbButtons[] =
+{
+ { 2, IDM_VIEWVOLUMES , TBSTATE_ENABLED, TBSTYLE_BUTTON, 0},
+ { 3, IDM_VIEWDISKS , TBSTATE_ENABLED, TBSTYLE_BUTTON, 0},
+ { 0, 0 , TBSTATE_ENABLED, TBSTYLE_SEP , 0},
+ { 11, IDM_VOL_PROPERTIES , TBSTATE_ENABLED, TBSTYLE_BUTTON, 0}
+};
+
+#define TBAR_BUTTON_COUNT ARRAYLEN(tbButtons)
+
+
+struct BUTTON_MAP
+{
+ INT idM; // menu item id
+ INT idB; // button bitmap id
+};
+
+static BUTTON_MAP g_sServerButtons[] =
+{
+
+//
+// Partition menu
+//
+
+ IDM_PARTITIONCREATE, 0,
+ IDM_PARTITIONDELETE, 1,
+#if i386
+ IDM_PARTITIONACTIVE, 8,
+#else
+ IDM_SECURESYSTEM, 17,
+#endif
+
+// IDM_FTCREATEVOLUMESET
+
+ IDM_FTEXTENDVOLUMESET, 5,
+ IDM_QUIT, 15,
+
+//
+// Fault tolerance menu (Advanced Server only)
+//
+
+ IDM_FTESTABLISHMIRROR, 6,
+ IDM_FTBREAKMIRROR, 7,
+ IDM_FTCREATESTRIPE, 16,
+
+// IDM_FTRECOVERSTRIPE
+// IDM_FTCREATEPSTRIPE
+
+//
+// Tools menu
+//
+
+ IDM_VOL_FORMAT, 4,
+ IDM_VOL_PROPERTIES, 11,
+
+//
+// View menu
+//
+
+ IDM_VIEWVOLUMES, 2,
+ IDM_VIEWDISKS, 3,
+
+//
+// Options menu
+//
+
+ IDM_OPTIONSCOLORS, 9,
+ IDM_OPTIONSDISPLAY, 10,
+
+//
+// Help menu
+//
+
+ IDM_HELPCONTENTS, 12
+
+};
+
+
+static BUTTON_MAP g_sWorkstationButtons[] =
+{
+
+//
+// Partition menu
+//
+
+ IDM_PARTITIONCREATE, 0,
+ IDM_PARTITIONDELETE, 1,
+#if i386
+ IDM_PARTITIONACTIVE, 8,
+#else
+ IDM_SECURESYSTEM, 17,
+#endif
+
+// IDM_FTCREATEVOLUMESET
+
+ IDM_FTEXTENDVOLUMESET, 5,
+ IDM_QUIT, 15,
+
+//
+// Tools menu
+//
+
+ IDM_VOL_FORMAT, 4,
+ IDM_VOL_PROPERTIES, 11,
+
+//
+// View menu
+//
+
+ IDM_VIEWVOLUMES, 2,
+ IDM_VIEWDISKS, 3,
+
+//
+// Options menu
+//
+
+ IDM_OPTIONSCOLORS, 9,
+ IDM_OPTIONSDISPLAY, 10,
+
+//
+// Help menu
+//
+
+ IDM_HELPCONTENTS, 12
+
+};
+
+
+static BUTTON_MAP* g_sButtons; // points to the right one based on platform
+static UINT g_cButtons; // correct count based on platform
+
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: SetToolbarButtonState
+//
+// Synopsis: set the state of the toolbar buttons based on menu state
+//
+// Arguments: none
+//
+// Returns: nothing
+//
+// History: 2-Sep-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+SetToolbarButtonState(
+ VOID
+ )
+{
+ UINT i;
+ int idCommand;
+ HMENU hMenu;
+ UINT state;
+
+ // Set the states correctly
+
+ hMenu = GetMenu(g_hwndFrame);
+
+ for (i=0; i<g_cButtons; ++i)
+ {
+ idCommand = g_sButtons[i].idM;
+ state = GetMenuState(hMenu, idCommand, MF_BYCOMMAND);
+
+ if (state != 0xFFFFFFFF)
+ {
+ Toolbar_CheckButton(
+ g_hwndToolbar,
+ idCommand,
+ state & MF_CHECKED);
+
+ Toolbar_EnableButton(
+ g_hwndToolbar,
+ idCommand,
+ !(state & (MF_DISABLED | MF_GRAYED)));
+ }
+ else
+ {
+ Toolbar_HideButton(g_hwndToolbar, idCommand, TRUE);
+ }
+ }
+}
+
+
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: ResetToolbar
+//
+// Synopsis: resets the toolbar to the standard state
+//
+// Arguments: none
+//
+// Returns: nothing
+//
+// History: 2-Sep-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+ResetToolbar(
+ VOID
+ )
+{
+ INT nItem;
+ INT i, idCommand;
+ HMENU hMenu;
+ UINT state;
+
+ // Remove from back to front as a speed optimization
+
+ for (nItem = Toolbar_ButtonCount(g_hwndToolbar) - 1;
+ nItem >= 0;
+ --nItem)
+ {
+ Toolbar_DeleteButton(g_hwndToolbar, nItem);
+ }
+
+ // Add the default list of buttons
+
+ Toolbar_AddButtons(g_hwndToolbar, TBAR_BUTTON_COUNT, tbButtons);
+
+ // Set the states correctly
+
+ hMenu = GetMenu(g_hwndFrame);
+
+ for (i=0; i<TBAR_BUTTON_COUNT; ++i)
+ {
+ if (tbButtons[i].fsStyle == TBSTYLE_SEP)
+ {
+ continue;
+ }
+
+ idCommand = tbButtons[i].idCommand;
+ state = GetMenuState(hMenu, idCommand, MF_BYCOMMAND);
+
+ Toolbar_CheckButton(
+ g_hwndToolbar,
+ idCommand,
+ state & MF_CHECKED);
+
+ Toolbar_EnableButton(
+ g_hwndToolbar,
+ idCommand,
+ !(state & (MF_DISABLED | MF_GRAYED)));
+ }
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: LoadDesc
+//
+// Synopsis: Given a menu command identifier, determine its description
+// string
+//
+// Arguments: [uID] -- menu id (e.g., IDM_VOL_PROPERTIES)
+// [pDesc] -- string buffer to fill, with up to MAXDESCLEN
+// characters
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+static VOID
+LoadDesc(
+ IN UINT uID,
+ OUT PWSTR pDesc
+ )
+{
+ HMENU hMenu;
+ WCHAR szFormat[20];
+ WCHAR szMenu[20];
+ WCHAR szItem[MAXDESCLEN - ARRAYLEN(szMenu)];
+ PWSTR pIn;
+ UINT uMenu;
+
+ szItem[0] = *pDesc = TEXT('\0');
+
+ hMenu = GetMenu(g_hwndFrame);
+
+ uMenu = uID;
+ if (!g_IsLanmanNt && (uMenu > IDM_FTRECOVERSTRIPE))
+ {
+ //
+ // In the workstation (non-server) case, we need to remove the FT
+ // menu from consideration. Since we are calculating an index into
+ // the menu by compile-time menu ids, simply subract off one menu
+ // range if the id is greater than the last FT item.
+ //
+
+ uMenu -= IDM_MENU_DELTA;
+ }
+
+ //
+ // generate a 0-based index for GetMenuString
+ //
+ uMenu = (uMenu - IDM_FIRST_MENU) / IDM_MENU_DELTA;
+
+ GetMenuString(hMenu, uMenu, szMenu, ARRAYLEN(szMenu), MF_BYPOSITION);
+
+ if (GetMenuString(hMenu, uID, szItem, ARRAYLEN(szItem), MF_BYCOMMAND) <= 0)
+ {
+ //
+ // unknown menu id
+ //
+
+ return;
+ }
+
+ LoadString(g_hInstance, IDS_MENUANDITEM, szFormat, ARRAYLEN(szFormat));
+ wsprintf(pDesc, szFormat, szMenu, szItem);
+
+ // Remove the ampersands
+
+ for (pIn=pDesc; ; ++pIn, ++pDesc)
+ {
+ WCHAR cTemp;
+
+ cTemp = *pIn;
+ if (cTemp == TEXT('&'))
+ {
+ cTemp = *(++pIn);
+ }
+
+ if (cTemp == TEXT('\t'))
+ {
+ cTemp = TEXT('\0');
+ }
+
+ *pDesc = cTemp;
+ if (cTemp == TEXT('\0'))
+ {
+ break;
+ }
+ }
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: CheckTBButton
+//
+// Synopsis: Treat the "volumes view" and "disks view" buttons as
+// mutually exclusive: exactly one must be up at any time.
+//
+// Arguments: [idCommand] -- either IDM_VIEWVOLUMES or IDM_VIEWDISKS
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+CheckTBButton(
+ IN DWORD idCommand
+ )
+{
+ UINT i, begin, end;
+
+ //
+ // Make sure to "pop-up" any other buttons in the group.
+ //
+ if ((UINT)(idCommand-IDM_VIEWVOLUMES) <= IDM_VIEWDISKS-IDM_VIEWVOLUMES)
+ {
+ begin = IDM_VIEWVOLUMES;
+ end = IDM_VIEWDISKS;
+ }
+ else
+ {
+ begin = end = (UINT)idCommand;
+ }
+
+ for (i=begin; i<=end; ++i)
+ {
+ Toolbar_CheckButton(g_hwndToolbar, i, i==idCommand);
+ }
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: CreateDAToolbar
+//
+// Synopsis: Create a toolbar control for the Disk Administrator
+//
+// Arguments: [hwndParent] -- the parent (frame) window
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+CreateDAToolbar(
+ IN HWND hwndParent
+ )
+{
+ // We'll start out by adding no buttons; that will be done in
+ // InitToolbarButtons
+
+ g_hwndToolbar = CreateToolbarEx(
+ hwndParent, // parent
+ WS_CHILD
+ | CCS_ADJUSTABLE
+ | TBSTYLE_TOOLTIPS
+ | (g_Toolbar ? WS_VISIBLE : 0)
+ ,
+ IDC_TOOLBAR, // toolbar id
+ TBAR_BITMAP_COUNT, // number of bitmaps
+ g_hInstance, // module instance
+ IDB_TOOLBAR, // resource id for the bitmap
+ tbButtons, // address of buttons
+ TBAR_BUTTON_COUNT, // number of buttons
+ DX_BITMAP, DY_BITMAP, // width & height of the buttons
+ DX_BITMAP, DY_BITMAP, // width & height of the bitmaps
+ sizeof(TBBUTTON)); // structure size
+
+ if (g_hwndToolbar == NULL)
+ {
+ daDebugOut((DEB_ERROR, "Couldn't create toolbar!\n"));
+ return;
+ }
+
+ //
+ // Load up the second bitmap
+ //
+
+ Toolbar_AddBitmap(
+ g_hwndToolbar,
+ TBAR_EXTRA_BITMAPS,
+ g_hInstance,
+ IDB_EXTRATOOLS
+ );
+
+ //
+ // Calculate toolbar height
+ //
+
+ RECT rc;
+ GetWindowRect(g_hwndToolbar, &rc);
+ g_dyToolbar = rc.bottom - rc.top;
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: InitToolbarButtons
+//
+// Synopsis: Initialize the visual state of the buttons on the toolbar.
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+InitToolbarButtons(
+ VOID
+ )
+{
+ if (g_IsLanmanNt)
+ {
+ g_sButtons = g_sServerButtons;
+ g_cButtons = ARRAYLEN(g_sServerButtons);
+ }
+ else
+ {
+ g_sButtons = g_sWorkstationButtons;
+ g_cButtons = ARRAYLEN(g_sWorkstationButtons);
+ }
+
+ SaveRestoreToolbar(FALSE);
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: Toolbar_OnGetButtonInfo
+//
+// Synopsis: Get the information for a button during customization
+//
+// Arguments:
+//
+// Returns:
+//
+// History: 26-Sep-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+LRESULT
+Toolbar_OnGetButtonInfo(
+ IN OUT TBNOTIFY* ptbn
+ )
+{
+ if (ptbn->iItem < (int)g_cButtons)
+ {
+ daDebugOut((DEB_ITRACE, "Getting button %d\n", ptbn->iItem));
+
+ WCHAR szDescription[MAXDESCLEN];
+
+ ptbn->tbButton.iBitmap = g_sButtons[ptbn->iItem].idB;
+ ptbn->tbButton.idCommand = g_sButtons[ptbn->iItem].idM;
+ ptbn->tbButton.fsState = TBSTATE_ENABLED;
+ ptbn->tbButton.fsStyle = TBSTYLE_BUTTON;
+ ptbn->tbButton.dwData = 0;
+ ptbn->tbButton.iString = 0;
+
+ LoadDesc(ptbn->tbButton.idCommand, szDescription);
+ wcsncpy(ptbn->pszText, szDescription, min(1+lstrlen(szDescription), ptbn->cchText));
+
+ daDebugOut((DEB_ITRACE,
+ "Got button %d, cchText %d, return \"%ws\"\n",
+ ptbn->iItem,
+ ptbn->cchText,
+ ptbn->pszText));
+
+ return (LRESULT)TRUE;
+ }
+ else
+ {
+ daDebugOut((DEB_ITRACE, "Didn't get button %d\n", ptbn->iItem));
+
+ return (LRESULT)FALSE;
+ }
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: HandleToolbarNotify
+//
+// Synopsis: Handles toolbar notifications via WM_NOTIFY
+//
+// Arguments:
+//
+// Returns:
+//
+// History: 29-Sep-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+LRESULT
+HandleToolbarNotify(
+ IN TBNOTIFY* ptbn
+ )
+{
+ switch (ptbn->hdr.code)
+ {
+ case TBN_QUERYINSERT:
+ case TBN_QUERYDELETE:
+ return TRUE; // allow any deletion or insertion
+
+ case TBN_BEGINADJUST:
+ case TBN_ENDADJUST:
+ break; // return value ignored
+
+ case TBN_GETBUTTONINFO:
+ daDebugOut((DEB_ITRACE, "TBN_GETBUTTONINFO\n"));
+ return Toolbar_OnGetButtonInfo(ptbn);
+
+ case TBN_RESET:
+// daDebugOut((DEB_TRACE, "TBN_RESET\n"));
+
+ ResetToolbar();
+ break;
+
+ case TBN_TOOLBARCHANGE:
+// daDebugOut((DEB_TRACE, "TBN_TOOLBARCHANGE\n"));
+
+ SetToolbarButtonState();
+ SaveRestoreToolbar(TRUE);
+ break;
+
+ case TBN_CUSTHELP:
+// daDebugOut((DEB_ITRACE, "TBN_CUSTHELP\n"));
+
+ DialogHelp(HC_DM_DLG_CUSTOMIZETOOL);
+ break;
+
+ case TBN_BEGINDRAG:
+// daDebugOut((DEB_ITRACE, "TBN_BEGINDRAG (command %d)\n",
+// ptbn->iItem)); // actually, the command, not the item!
+
+ //
+ // display help for the item
+ //
+
+ DrawMenuHelpItem(NULL, ptbn->iItem, 0);
+ break;
+
+ case TBN_ENDDRAG:
+// daDebugOut((DEB_ITRACE, "TBN_ENDDRAG\n"));
+
+ //
+ // stop displaying help
+ //
+
+ g_fDoingMenuHelp = FALSE;
+ UpdateStatusBarDisplay();
+
+ break;
+ } // end switch
+
+ return 0L;
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: HandleTooltipNotify
+//
+// Synopsis: Handles tool tips notifications via WM_NOTIFY. The only
+// tooltips in windisk are toolbar tips.
+//
+// Arguments:
+//
+// Returns:
+//
+// History: 29-Sep-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+LRESULT
+HandleTooltipNotify(
+ IN TOOLTIPTEXT* pttt
+ )
+{
+ pttt->hinst = g_hInstance;
+ pttt->lpszText = MAKEINTRESOURCE(GetTooltip(pttt->hdr.idFrom));
+ // command ID to get tip for
+ return 0L; // ignored
+}
diff --git a/private/utils/windisk/src/tbar.hxx b/private/utils/windisk/src/tbar.hxx
new file mode 100644
index 000000000..be36422aa
--- /dev/null
+++ b/private/utils/windisk/src/tbar.hxx
@@ -0,0 +1,52 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: tbar.hxx
+//
+// Contents: Disk Administrator toolbar support routines.
+//
+// History: 2-Sep-93 BruceFo Created from NT winfile
+//
+//----------------------------------------------------------------------------
+
+#ifndef __TBAR_HXX__
+#define __TBAR_HXX__
+
+VOID
+SetToolbarButtonState(
+ VOID
+ );
+
+VOID
+ResetToolbar(
+ VOID
+ );
+
+VOID
+CheckTBButton(
+ IN DWORD idCommand
+ );
+
+VOID
+CreateDAToolbar(
+ IN HWND hwndParent
+ );
+
+VOID
+InitToolbarButtons(
+ VOID
+ );
+
+LRESULT
+HandleToolbarNotify(
+ IN TBNOTIFY* ptbn
+ );
+
+LRESULT
+HandleTooltipNotify(
+ IN TOOLTIPTEXT* pttt
+ );
+
+#endif // __TBAR_HXX__
diff --git a/private/utils/windisk/src/tool16.bmp b/private/utils/windisk/src/tool16.bmp
new file mode 100644
index 000000000..df6d247b5
--- /dev/null
+++ b/private/utils/windisk/src/tool16.bmp
Binary files differ
diff --git a/private/utils/windisk/src/trffc14.ico b/private/utils/windisk/src/trffc14.ico
new file mode 100644
index 000000000..3de105412
--- /dev/null
+++ b/private/utils/windisk/src/trffc14.ico
Binary files differ
diff --git a/private/utils/windisk/src/types.hxx b/private/utils/windisk/src/types.hxx
new file mode 100644
index 000000000..d27d7b213
--- /dev/null
+++ b/private/utils/windisk/src/types.hxx
@@ -0,0 +1,489 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: types.hxx
+//
+// Contents: Type declarations
+//
+// History: 7-Jan-92 TedM Created
+// 16-Aug-93 BruceFo Added Cairo support
+// 11-Nov-93 BobRi DoubleSpace & Commit support
+// 2-Feb-94 BobRi moved arcinst data here
+//
+//----------------------------------------------------------------------------
+
+#ifndef __TYPES_HXX__
+#define __TYPES_HXX__
+
+//
+// Partitioning engine types
+//
+
+//
+// This structure is used to hold the information returned by the
+// get drive geometry call.
+//
+
+typedef struct _DISKGEOM
+{
+ LARGE_INTEGER Cylinders;
+ ULONG Heads;
+ ULONG SectorsPerTrack;
+ ULONG BytesPerSector;
+ // These two are not part of drive geometry info, but calculated from it.
+ ULONG BytesPerCylinder;
+ ULONG BytesPerTrack;
+} DISKGEOM, *PDISKGEOM;
+
+
+
+typedef enum
+{
+ REGION_PRIMARY,
+ REGION_EXTENDED,
+ REGION_LOGICAL
+} REGION_TYPE;
+
+
+// These structures are used in doubly-linked per disk lists that
+// describe the layout of the disk.
+//
+// Free spaces are indicated by entries with a SysID of 0 (note that
+// these entries don't actually appear anywhere on-disk!)
+//
+// The partition number is the number the system will assign to
+// the partition in naming it. For free spaces, this is the number
+// that the system WOULD assign to it if it was a partition.
+// The number is good only for one transaction (create or delete),
+// after which partitions must be renumbered.
+
+struct _PERSISTENT_REGION_DATA;
+
+typedef struct _PARTITION
+{
+ struct _PARTITION* Next;
+ struct _PARTITION* Prev;
+ struct _PERSISTENT_REGION_DATA* PersistentData;
+
+ LARGE_INTEGER Offset;
+ LARGE_INTEGER Length;
+ PARTITION_INFORMATION OriginalPartitionInformation;
+ ULONG Disk;
+ ULONG OriginalPartitionNumber;
+ ULONG PartitionNumber;
+ ULONG OriginalLayoutEntrySlot;
+ BOOLEAN EntryCameFromLayout;
+ BOOLEAN Update;
+ BOOLEAN Active;
+ BOOLEAN Recognized;
+ UCHAR SysID;
+ BOOLEAN CommitMirrorBreakNeeded;
+} PARTITION, *PPARTITION;
+
+
+typedef struct _REGION_DATA
+{
+ PPARTITION Partition;
+ LARGE_INTEGER AlignedRegionOffset;
+ LARGE_INTEGER AlignedRegionSize;
+} REGION_DATA, *PREGION_DATA;
+
+//
+// DoubleSpace support structure. This is tagged off of the persistent data
+// for each region.
+//
+
+typedef struct _DBLSPACE_DESCRIPTOR
+{
+ struct _DBLSPACE_DESCRIPTOR* Next;
+ struct _DBLSPACE_DESCRIPTOR* DblChainNext;
+
+ ULONG AllocatedSize;
+ PWSTR FileName;
+ WCHAR DriveLetter;
+ BOOLEAN Mounted;
+ BOOLEAN ChangeMountState;
+ WCHAR NewDriveLetter;
+ BOOLEAN ChangeDriveLetter;
+} DBLSPACE_DESCRIPTOR, *PDBLSPACE_DESCRIPTOR;
+
+
+//
+// structure that describes an ft object (mirror, stripe component, etc).
+//
+struct _FT_OBJECT_SET;
+struct _REGION_DESCRIPTOR;
+typedef struct _FT_OBJECT
+{
+ struct _FT_OBJECT* Next;
+ struct _FT_OBJECT_SET* Set;
+ ULONG MemberIndex;
+ FT_PARTITION_STATE State;
+ struct _REGION_DESCRIPTOR* Region;
+} FT_OBJECT, *PFT_OBJECT;
+
+
+//
+// Enum for the states in which an ft set can be.
+//
+
+typedef enum _FT_SET_STATUS
+{
+ FtSetHealthy,
+ FtSetBroken,
+ FtSetRecoverable,
+ FtSetRecovered,
+ FtSetNew,
+ FtSetNewNeedsInitialization,
+ FtSetExtended,
+ FtSetInitializing,
+ FtSetRegenerating,
+ FtSetInitializationFailed,
+ FtSetDisabled
+} FT_SET_STATUS, *PFT_SET_STATUS;
+
+
+//
+// structure that describes an ft object set (ie, mirrored pair, stripe set).
+//
+
+typedef struct _FT_OBJECT_SET
+{
+ struct _FT_OBJECT_SET* Next;
+
+ FT_TYPE Type;
+ ULONG Ordinal;
+ PFT_OBJECT Members;
+ PFT_OBJECT Member0;
+ FT_SET_STATUS Status;
+ ULONG NumberOfMembers;
+
+ //
+ // This flag is used when we are iterating over "volumes", and wish
+ // to touch FT regions only once.
+ //
+ BOOL Flag;
+
+} FT_OBJECT_SET, *PFT_OBJECT_SET;
+
+
+
+//
+// Define the structure that is associated with each non-extended, recognized
+// partition. This structure is associated with the partition, and persists
+// across region array free/get from the back end. It is used for logical
+// and ft information.
+//
+
+typedef struct _PERSISTENT_REGION_DATA
+{
+ PFT_OBJECT FtObject;
+
+ PWSTR VolumeLabel;
+ PWSTR TypeName;
+ WCHAR DriveLetter;
+
+ //
+ // NewRegion: TRUE if this region was created during the current session
+ //
+
+ BOOL NewRegion;
+
+ //
+ // Volume space information
+ //
+
+ LARGE_INTEGER FreeSpaceInBytes;
+ LARGE_INTEGER TotalSpaceInBytes;
+
+#if defined( DBLSPACE_ENABLED )
+ //
+ // DoubleSpace information
+ //
+
+ PDBLSPACE_DESCRIPTOR DblSpace;
+#endif // DBLSPACE_ENABLED
+
+} PERSISTENT_REGION_DATA, *PPERSISTENT_REGION_DATA;
+
+
+
+typedef struct _REGION_DESCRIPTOR
+{
+ PPERSISTENT_REGION_DATA PersistentData;
+ PREGION_DATA Reserved;
+ ULONG Disk;
+ ULONG PartitionNumber;
+ ULONG OriginalPartitionNumber;
+ ULONG SizeMB;
+ REGION_TYPE RegionType;
+ BOOLEAN Active;
+ BOOLEAN Recognized;
+ UCHAR SysID;
+} REGION_DESCRIPTOR, *PREGION_DESCRIPTOR;
+
+
+typedef struct _LEFTRIGHT
+{
+ LONG Left;
+ LONG Right;
+} LEFTRIGHT, *PLEFTRIGHT;
+
+
+//
+// Types of views that can be used for a disk bar.
+//
+// Proportional means that the amount of space taken up in the bar is
+// directly proportional to the size of the partition or free space
+// Equal means that all free spaces and partitions are sized equally on
+// screen regardless of their actual size
+//
+
+typedef enum _BAR_TYPE
+{
+ BarProportional,
+ BarEqual,
+ BarAuto
+} BAR_TYPE, *PBAR_TYPE;
+
+
+//
+// Type of display of disks
+//
+
+typedef enum _DISK_TYPE
+{
+ DiskProportional,
+ DiskEqual
+} DISK_TYPE, *PDISK_TYPE;
+
+
+//
+// One DISKSTATE structure is associated with each item in the
+// listbox. The structure is the crux of the implementation.
+//
+
+typedef struct _DISKSTATE
+{
+ ULONG Disk; // number of disk
+ ULONG DiskSizeMB; // size in MB of disk
+ ULONG RegionCount; // # items in region array
+
+ PREGION_DESCRIPTOR RegionArray; // RegionCount-size region array
+ PBOOLEAN Selected; // RegionCount-size array for whether
+ //... each region is selected
+ PLEFTRIGHT LeftRight; // RegionCount-size array for left/
+ //...right coords of boxes in graph
+
+ BOOLEAN CreateAny; // any creations allowed on disk?
+ BOOLEAN CreatePrimary; // allowed to create primary partition?
+ BOOLEAN CreateExtended; // allowed to create extended partition?
+ BOOLEAN CreateLogical; // allowed to create logical volume?
+ BOOLEAN ExistAny; // any partitions/logicals exist?
+ BOOLEAN ExistPrimary; // primary partition(s) exist?
+ BOOLEAN ExistExtended; // extended partition exists?
+ BOOLEAN ExistLogical; // logical volume(s) exist?
+ HDC hDCMem; // for off-screen drawing
+ HBITMAP hbmMem; // for offscreen bitmap
+ ULONG Signature; // unique disk registry index
+ BAR_TYPE BarType; // how to display the disk's bar
+ BOOLEAN SigWasCreated; // whether we had to make up a sig
+ BOOLEAN OffLine; // FALSE if disk is accessible.
+
+#ifdef WINDISK_EXTENSIONS
+ struct HARDDISK_CLAIM_LIST* pClaims; // pointer to extension claim list
+ //... for this disk
+#endif // WINDISK_EXTENSIONS
+
+} DISKSTATE, *PDISKSTATE;
+
+
+
+//
+// CdRom support structures.
+//
+
+typedef struct _CDROM_DESCRIPTOR
+{
+ PWSTR DeviceName;
+ ULONG DeviceNumber;
+ WCHAR DriveLetter;
+
+ HDC hDCMem;
+ HBITMAP hbmMem;
+ BOOLEAN Selected;
+ LEFTRIGHT LeftRight;
+
+ PWSTR VolumeLabel;
+ PWSTR TypeName;
+ ULONG TotalSpaceInMB;
+} CDROM_DESCRIPTOR, *PCDROM_DESCRIPTOR;
+
+
+//
+// Commit support structures
+//
+
+typedef struct _DRIVE_LOCKLIST
+{
+ struct _DRIVE_LOCKLIST* Next;
+
+ HANDLE LockHandle;
+ ULONG DiskNumber;
+ ULONG PartitionNumber;
+ ULONG LockOnDiskNumber;
+ ULONG UnlockOnDiskNumber;
+ WCHAR DriveLetter;
+ BOOLEAN RemoveOnUnlock;
+ BOOLEAN FailOk;
+ BOOLEAN CurrentlyLocked;
+} DRIVE_LOCKLIST, *PDRIVE_LOCKLIST;
+
+
+//
+// List of drive letters to assign
+//
+
+typedef struct _ASSIGN_LIST
+{
+ struct _ASSIGN_LIST* Next;
+
+ ULONG DiskNumber;
+ BOOLEAN MoveLetter;
+ WCHAR OriginalLetter;
+ WCHAR DriveLetter;
+} ASSIGN_LIST, *PASSIGN_LIST;
+
+//
+// The View type
+//
+
+enum VIEW_TYPE
+{
+ VIEW_VOLUMES,
+ VIEW_DISKS
+};
+
+#ifdef WINDISK_EXTENSIONS
+
+/////////////////////////////////////////////////////////////////////////
+
+//
+// Extension types
+//
+
+struct OneExtension
+{
+ CLSID* pcls;
+ IUnknown* pUnk;
+};
+
+struct ExtensionType
+{
+ CLSID** pcls;
+ ULONG cClasses;
+};
+
+enum ExtensionIndices
+{
+ EX_VOLUME = 0,
+ EX_DISK = 1
+};
+
+#define EX_NUM_EXTENSION_TYPES 2
+
+/////////////////////////////////////////////////////////////////////////
+
+struct HARDDISK_INFO
+{
+ IDAHardDiskInfo* pExtension;
+ HardDiskInfoType* pInfo;
+};
+
+struct HARDDISK_CLAIM_LIST
+{
+ HARDDISK_CLAIM_LIST* pNext;
+ HARDDISK_INFO* pClaimer;
+};
+typedef HARDDISK_CLAIM_LIST* PHARDDISK_CLAIM_LIST;
+
+//////////////////////////////////////////////
+
+struct VOL_INFO
+{
+ IDAVolumeInfo* pExtension;
+ VolumeInfoType* pInfo;
+};
+
+struct VOL_CLAIM_LIST
+{
+ VOL_CLAIM_LIST* pNext;
+ VOL_INFO* pClaimer;
+};
+typedef VOL_CLAIM_LIST* PVOL_CLAIM_LIST;
+
+//////////////////////////////////////////////////////////////////////////
+
+//
+// VOLUME_INFO: this structure represents the interesting information
+// for a single volume (i.e., something denoted by a drive letter).
+// There is a list of claimers for file system and volume extension
+// classes. The volume is identified by a PDISKSTATE and region index,
+// which together uniquely identifies a region. This region must be a used
+// (not free) region. If it is an FT set, any of the FT components can be
+// used to identify the volume.
+//
+struct VOLUME_INFO
+{
+ PVOL_CLAIM_LIST VolClaims;
+ PDISKSTATE DiskState;
+ INT RegionIndex;
+};
+
+//////////////////////////////////////////////////////////////////////////
+
+#endif // WINDISK_EXTENSIONS
+
+//
+// params for the MinMax dialog -- used at WM_INITDIALOG time
+//
+
+typedef struct _tagMINMAXDLG_PARAMS
+{
+ DWORD CaptionStringID;
+ DWORD MinimumStringID;
+ DWORD MaximumStringID;
+ DWORD SizeStringID;
+ DWORD MinSizeMB;
+ DWORD MaxSizeMB;
+ DWORD HelpContextId;
+} MINMAXDLG_PARAMS, *PMINMAXDLG_PARAMS;
+
+//
+// params for the DriveLetter dialog -- used at WM_INITDIALOG time
+//
+
+typedef struct _DRIVELET_DLG_PARAMS
+{
+ IN PWSTR Description;
+ IN WCHAR DriveLetter;
+ OUT WCHAR NewDriveLetter;
+} DRIVELET_DLG_PARAMS, *PDRIVELET_DLG_PARAMS;
+
+//
+// params for the DoubleSpace dialog -- used at WM_INITDIALOG time
+//
+
+typedef struct _DBLSPACE_PARAMS
+{
+ DWORD CaptionStringID;
+ PVOID RegionDescriptor;
+ PPERSISTENT_REGION_DATA RegionData;
+ PDBLSPACE_DESCRIPTOR DblSpace;
+} DBLSPACE_PARAMS, *PDBLSPACE_PARAMS;
+
+
+
+#endif // __TYPES_HXX__
diff --git a/private/utils/windisk/src/unused/startup.cxx b/private/utils/windisk/src/unused/startup.cxx
new file mode 100644
index 000000000..0f26bd005
--- /dev/null
+++ b/private/utils/windisk/src/unused/startup.cxx
@@ -0,0 +1,166 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: startup.cxx
+//
+// Contents: (Unused) code to provide an "app is starting" dialog.
+// Unfortunately, I haven't been able to figure out all the
+// foreground/background active/inactive window focus problems
+//
+// History: 20-Apr-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+HWND g_hwndStartup;
+#define MYWM_ENDSTARTUP WM_USER
+
+//+-------------------------------------------------------------------------
+//
+// Function: StartupDlgProc, private
+//
+// Synopsis: Dialog procedure for the startup dialog
+//
+// Arguments: standard Windows dialog procedure
+//
+// Returns: standard Windows dialog procedure
+//
+// History: 23-Feb-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+BOOL CALLBACK
+StartupDlgProc(
+ IN HWND hDlg,
+ IN UINT uMsg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ g_hwndStartup = hDlg;
+ CenterWindow(hDlg, NULL);
+ return 1; // didn't call SetFocus
+
+ case MYWM_ENDSTARTUP:
+ EndDialog(hDlg, TRUE);
+ return 1;
+
+ default:
+ return 0; // didn't process
+ }
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: StartupThread
+//
+// Synopsis: Thread routine called for Disk Administrator startup
+//
+// Arguments: [ThreadParameter] -- unused
+//
+// Returns: 0
+//
+// History: 23-Feb-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+LOCAL DWORD WINAPI
+StartupThread(
+ IN LPVOID ThreadParameter
+ )
+{
+ DialogBox(
+ g_hInstance,
+ MAKEINTRESOURCE(IDD_STARTUP),
+ NULL,
+ StartupDlgProc
+ );
+ return 0;
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: BeginStartup
+//
+// Synopsis: Puts up a dialog box indicating that Disk Administrator is
+// initializing
+//
+// Arguments: none
+//
+// Returns: nothing
+//
+// Requires: g_hInstance must be set already
+//
+// History: 23-Feb-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+VOID
+BeginStartup(
+ VOID
+ )
+{
+ DWORD threadId;
+ HANDLE hThread;
+
+ g_hwndStartup = NULL;
+
+ hThread = CreateThread(
+ NULL,
+ 0,
+ StartupThread,
+ NULL,
+ 0,
+ &threadId
+ );
+
+ if (NULL == hThread)
+ {
+ daDebugOut((DEB_ERROR, "Error creating startup thread\n"));
+ return;
+ }
+
+ // No reason to keep handle around
+
+ CloseHandle(hThread);
+}
+
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: EndStartup
+//
+// Synopsis: Kills the "startup" dialog box
+//
+// Arguments: none
+//
+// Returns: nothing
+//
+// History: 23-Feb-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+VOID
+EndStartup(
+ VOID
+ )
+{
+ if (NULL != g_hwndStartup)
+ {
+ PostMessage(g_hwndStartup, MYWM_ENDSTARTUP, 0, 0);
+ g_hwndStartup = NULL;
+ }
+}
diff --git a/private/utils/windisk/src/unused/startup.hxx b/private/utils/windisk/src/unused/startup.hxx
new file mode 100644
index 000000000..2f44a98c5
--- /dev/null
+++ b/private/utils/windisk/src/unused/startup.hxx
@@ -0,0 +1,27 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: startup.hxx
+//
+// Contents: (Unused) code to provide an "app is starting" dialog.
+//
+// History: 20-Apr-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __STARTUP_HXX__
+#define __STARTUP_HXX__
+
+VOID
+BeginStartup(
+ VOID
+ );
+
+VOID
+EndStartup(
+ VOID
+ );
+
+#endif // __STARTUP_HXX__
diff --git a/private/utils/windisk/src/unused/time.cxx b/private/utils/windisk/src/unused/time.cxx
new file mode 100644
index 000000000..b0de622d7
--- /dev/null
+++ b/private/utils/windisk/src/unused/time.cxx
@@ -0,0 +1,599 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: time.cxx
+//
+// Contents: Functions dealing with time, relating to time stamping
+// chkdsk. All functions will be prefixed by "Ts", meaning
+// "time stamp".
+//
+// Functions:
+//
+// History: 31-Jan-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include "time.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+WCHAR KeyProto[] = L"\\registry\\machine\\system\\VolumeInfo\\%c:\\%s";
+WCHAR KeyProto1[] = L"\\registry\\machine\\system\\VolumeInfo";
+WCHAR KeyProto2[] = L"\\%c:";
+WCHAR KeyProto3[] = L"\\%s";
+WCHAR KeyProto4[] = L"\\registry\\machine\\system\\VolumeInfo\\%c:";
+WCHAR ClassName[] = L"Volume information";
+WCHAR ValueName[] = L"TimeStamp";
+
+//////////////////////////////////////////////////////////////////////////////
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+NTSTATUS
+TspOpenKey(
+ OUT PHANDLE HandlePtr,
+ IN PWSTR KeyName
+ )
+
+/*++
+
+Routine Description:
+
+ Given a null-terminated UNICODE key name, this routine will open the key
+ in the configuration registry and return the HANDLE to the caller.
+
+Arguments:
+
+ HandlePtr - location for HANDLE on success.
+ KeyName - UNICODE string for the key to be opened.
+
+Return Value:
+
+ NTSTATUS - from the config registry calls.
+
+--*/
+
+{
+ NTSTATUS status;
+ OBJECT_ATTRIBUTES objectAttributes;
+ UNICODE_STRING keyName;
+
+ RtlInitUnicodeString(&keyName, KeyName);
+
+ memset(&objectAttributes, 0, sizeof(OBJECT_ATTRIBUTES));
+ InitializeObjectAttributes(&objectAttributes,
+ &keyName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ status = NtOpenKey(HandlePtr, MAXIMUM_ALLOWED, &objectAttributes);
+ if (!NT_SUCCESS(status))
+ {
+ daDebugOut((DEB_ERROR,"Couldn't open key %ws\n",KeyName));
+ }
+
+ return status;
+}
+
+
+NTSTATUS
+TspCreateKey(
+ OUT PHANDLE HandlePtr,
+ IN PWSTR KeyName,
+ IN PWSTR KeyClass,
+ IN ULONG Index
+ )
+
+/*++
+
+Routine Description:
+
+ Given a UNICODE name, this routine will create a key in the configuration
+ registry.
+
+Arguments:
+
+ HandlePtr - location for HANDLE on success.
+ KeyName - UNICODE string, the name of the key to create.
+ KeyClass - registry class for the new key.
+ Index - registry index value for the new key.
+
+Return Value:
+
+ NTSTATUS - from the config registry calls.
+
+--*/
+
+{
+ NTSTATUS status;
+ UNICODE_STRING keyName;
+ UNICODE_STRING className;
+ OBJECT_ATTRIBUTES objectAttributes;
+ ULONG disposition;
+ HANDLE tempHandle;
+
+ //
+ // Initialize the object for the key.
+ //
+
+ RtlInitUnicodeString(&keyName, KeyName);
+
+ memset(&objectAttributes, 0, sizeof(OBJECT_ATTRIBUTES));
+ InitializeObjectAttributes(&objectAttributes,
+ &keyName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
+
+ //
+ // Setup the unicode class value.
+ //
+
+ RtlInitUnicodeString(&className, KeyClass);
+
+ //
+ // Create the key.
+ //
+
+ status = NtCreateKey(&tempHandle,
+ KEY_READ | KEY_WRITE,
+ &objectAttributes,
+ Index,
+ &className,
+ REG_OPTION_NON_VOLATILE,
+ &disposition);
+ if (!NT_SUCCESS(status))
+ {
+ daDebugOut((DEB_ERROR,"Couldn't create key %ws\n",keyName));
+ }
+
+ if (HandlePtr != NULL)
+ {
+ *HandlePtr = tempHandle;
+ }
+ else
+ {
+ NtClose(tempHandle);
+ }
+
+ return status;
+}
+
+
+
+NTSTATUS
+TspCreateAllKeys(
+ IN WCHAR DriveLetter,
+ IN PWSTR Category
+ )
+
+/*++
+
+Routine Description:
+
+ Create all keys for the volume information stuff
+
+Arguments:
+
+ none.
+
+Return Value:
+
+ NTSTATUS - from the registry calls.
+
+--*/
+
+{
+ NTSTATUS status;
+ HANDLE keyHandle;
+ WCHAR keyName[200];
+ WCHAR buffer[200];
+
+ wsprintf(keyName, KeyProto1);
+ daDebugOut((DEB_ITRACE,"creating keyName = %ws\n",keyName));
+
+ status = TspCreateKey(
+ &keyHandle,
+ keyName,
+ ClassName,
+ 0);
+ if (!NT_SUCCESS(status))
+ {
+ daDebugOut((DEB_ERROR,"Couldn't create key %ws\n",keyName));
+ return status;
+ }
+
+ wsprintf(buffer, KeyProto2, DriveLetter);
+ lstrcat(keyName, buffer);
+ daDebugOut((DEB_ITRACE,"creating keyName = %ws\n",keyName));
+
+ status = TspCreateKey(
+ &keyHandle,
+ keyName,
+ ClassName,
+ 0);
+ if (!NT_SUCCESS(status))
+ {
+ daDebugOut((DEB_ERROR,"Couldn't create key %ws\n",keyName));
+ return status;
+ }
+
+ wsprintf(buffer, KeyProto3, Category);
+ lstrcat(keyName, buffer);
+ daDebugOut((DEB_ITRACE,"creating keyName = %ws\n",keyName));
+
+ status = TspCreateKey(
+ &keyHandle,
+ keyName,
+ ClassName,
+ 0);
+ if (!NT_SUCCESS(status))
+ {
+ daDebugOut((DEB_ERROR,"Couldn't create key %ws\n",keyName));
+ return status;
+ }
+
+ return status;
+}
+
+
+
+NTSTATUS
+TspDeleteValue(
+ IN HANDLE KeyHandle,
+ IN PWSTR ValueName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will delete a value within a key.
+
+Arguments:
+
+ KeyHandle - an open HANDLE to the key in the registry containing the value.
+ ValueName - a UNICODE string for the value name to delete.
+
+Return Value:
+
+ NTSTATUS - from the configuration registry.
+
+--*/
+
+{
+ NTSTATUS status;
+ UNICODE_STRING valueName;
+
+ RtlInitUnicodeString(&valueName, ValueName);
+
+ status = NtDeleteValueKey(KeyHandle, &valueName);
+ if (!NT_SUCCESS(status))
+ {
+ daDebugOut((DEB_ERROR,"Couldn't delete value %ws\n",ValueName));
+ }
+
+ return status;
+}
+
+
+
+NTSTATUS
+TspSetValue(
+ IN PWSTR KeyName,
+ IN PWSTR ValueName,
+ IN PVOID DataBuffer,
+ IN ULONG DataLength,
+ IN ULONG Type
+ )
+
+/*++
+
+Routine Description:
+
+ This routine stores a value in the configuration registry.
+
+Arguments:
+
+ KeyName - Name of key of interest
+ ValueName - UNICODE value name.
+ DataBuffer - contents for the value.
+ DataLength - length of the value contents.
+ Type - The type of data (i.e. REG_BINARY, REG_DWORD, etc).
+
+Return Value:
+
+ NTSTATUS - from the configuration registry.
+
+--*/
+
+{
+ NTSTATUS status;
+ HANDLE keyHandle;
+ UNICODE_STRING valueName;
+
+ status = TspOpenKey(&keyHandle, KeyName);
+ if (NT_SUCCESS(status))
+ {
+ RtlInitUnicodeString(&valueName, ValueName);
+ status = NtSetValueKey(
+ keyHandle,
+ &valueName,
+ 0,
+ Type,
+ DataBuffer,
+ DataLength);
+
+ NtClose(keyHandle);
+ }
+
+ return status;
+}
+
+
+NTSTATUS
+TspQueryValue(
+ IN PWSTR KeyName,
+ IN PWSTR ValueName,
+ IN OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ OUT PULONG LengthReturned,
+ OUT VOID** Data
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens the specified volume key and gets the contents of the
+ specified value. It returns this contents to the caller.
+
+Arguments:
+
+ KeyName - Name of key of interest
+ ValueName - UNICODE string for the value name to query.
+ Buffer - pointer to buffer for return of value contents.
+ BufferLength - maximum amount of registry information that can be returned.
+ LengthReturned - pointer to location for the size of the contents returned.
+ Data - pointer to returned data
+
+Return Value:
+
+ NTSTATUS - from the configuration registry.
+
+--*/
+
+{
+ NTSTATUS status;
+ HANDLE keyHandle;
+ UNICODE_STRING valueName;
+ PKEY_VALUE_FULL_INFORMATION keyValueInformation;
+
+ *LengthReturned = 0;
+ status = TspOpenKey(&keyHandle, KeyName);
+ if (NT_SUCCESS(status))
+ {
+ RtlInitUnicodeString(&valueName, ValueName);
+ keyValueInformation = (PKEY_VALUE_FULL_INFORMATION)Buffer;
+ status = NtQueryValueKey(keyHandle,
+ &valueName,
+ KeyValueFullInformation,
+ keyValueInformation,
+ BufferLength,
+ LengthReturned);
+
+ if (NT_SUCCESS(status))
+ {
+ if (keyValueInformation->DataLength == 0)
+ {
+ //
+ // Treat this as if there was not disk information.
+ //
+
+ return STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ else
+ {
+ //
+ // Set up the pointers for the caller.
+ //
+
+ *Data = (PVOID)((PUCHAR)keyValueInformation + keyValueInformation->DataOffset);
+ }
+ }
+
+ NtClose(keyHandle);
+ }
+ else
+ {
+ daDebugOut((DEB_ERROR,"Couldn't open key %ws\n",KeyName));
+ }
+
+ return status;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: TsChangeDriveLetter
+//
+// Synopsis: If a drive letter changes, adjust the registry time
+// stamps entries.
+//
+// Arguments: [OldDriveLetter] -- Drive letter that was changed
+// [NewDriveLetter] -- New drive letter
+//
+// Returns: nothing
+//
+// History: 31-Jan-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+TsChangeDriveLetter(
+ IN WCHAR OldDriveLetter,
+ IN WCHAR NewDriveLetter
+ )
+{
+ //BUGBUG: TsChangeDriveLetter is unimplemented
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: TsSetTime
+//
+// Synopsis: Set the time for a volume to the current time.
+//
+// Arguments: [DriveLetter] -- indicates the volume of interest
+// [Category] -- type of thing to timestamp, e.g. "Chkdsk",
+// "Format"
+//
+// Returns: nothing
+//
+// History: 31-Jan-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+TsSetTime(
+ IN WCHAR DriveLetter,
+ IN PWSTR Category
+ )
+{
+ WCHAR keyName[200];
+ LARGE_INTEGER SystemTime;
+ NTSTATUS status;
+ TIME_FIELDS Time; //debug only
+
+ status = NtQuerySystemTime(&SystemTime);
+ if (!NT_SUCCESS(status))
+ {
+ daDebugOut((DEB_ERROR, "Couldn't get system time\n"));
+ return;
+ }
+
+ status = TspCreateAllKeys(
+ DriveLetter,
+ Category
+ );
+ if (!NT_SUCCESS(status))
+ {
+ daDebugOut((DEB_ERROR, "Couldn't create all keys\n"));
+ return;
+ }
+
+ wsprintf(keyName, KeyProto, DriveLetter, Category);
+ daDebugOut((DEB_ITRACE,"keyName = %ws\n",keyName));
+
+ status = TspSetValue(
+ keyName,
+ ValueName,
+ (PVOID)&SystemTime,
+ sizeof(SystemTime),
+ REG_BINARY
+ );
+ if (!NT_SUCCESS(status))
+ {
+ daDebugOut((DEB_ERROR,
+ "Couldn't set key %ws, value %ws\n",
+ keyName,
+ ValueName));
+ }
+
+ //
+ // debug only:
+ //
+
+ memset(&Time, 0, sizeof(TIME_FIELDS));
+ RtlTimeToTimeFields(&SystemTime, &Time);
+
+ daDebugOut((DEB_ITRACE,
+ "set time: %d %d %d %d %d %d %d %d\n",
+ Time.Year,
+ Time.Month,
+ Time.Day,
+ Time.Hour,
+ Time.Minute,
+ Time.Second,
+ Time.Milliseconds,
+ Time.Weekday));
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: TsGetTime
+//
+// Synopsis: Gets the time stamp for a volume
+//
+// Arguments: [DriveLetter] -- indicates the volume of interest
+// [Category] -- type of thing to timestamp, e.g. "Chkdsk",
+// "Format"
+// [Time] -- a time structure to fill in
+//
+// Returns: nothing
+//
+// History: 31-Jan-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+TsGetTime(
+ IN WCHAR DriveLetter,
+ IN PWSTR Category,
+ OUT PTIME_FIELDS Time
+ )
+{
+ WCHAR Key[200];
+ CHAR Buffer[100];
+ ULONG Ignore;
+ PLARGE_INTEGER SystemTime;
+ NTSTATUS status;
+
+ wsprintf(Key, KeyProto, DriveLetter, Category);
+ daDebugOut((DEB_ITRACE,"key = %ws\n",Key));
+
+ status = TspQueryValue(
+ Key,
+ ValueName,
+ (PVOID)Buffer,
+ sizeof(Buffer),
+ &Ignore,
+ (VOID**)&SystemTime
+ );
+ if (!NT_SUCCESS(status))
+ {
+ daDebugOut((DEB_ERROR,
+ "Couldn't query key %ws, value %ws\n",
+ Key,
+ ValueName));
+ }
+
+ memset(Time, 0, sizeof(TIME_FIELDS));
+ RtlTimeToTimeFields(SystemTime, Time);
+
+ daDebugOut((DEB_ITRACE,
+ "get time: %d %d %d %d %d %d %d %d\n",
+ Time->Year,
+ Time->Month,
+ Time->Day,
+ Time->Hour,
+ Time->Minute,
+ Time->Second,
+ Time->Milliseconds,
+ Time->Weekday));
+}
diff --git a/private/utils/windisk/src/unused/time.hxx b/private/utils/windisk/src/unused/time.hxx
new file mode 100644
index 000000000..612fc3c8a
--- /dev/null
+++ b/private/utils/windisk/src/unused/time.hxx
@@ -0,0 +1,39 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: time.hxx
+//
+// Contents: Functions dealing with time, relating to time stamping
+// chkdsk.
+//
+// Functions:
+//
+// History: 31-Jan-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __TIME_HXX__
+#define __TIME_HXX__
+
+VOID
+TsChangeDriveLetter(
+ IN WCHAR OldDriveLetter,
+ IN WCHAR NewDriveLetter
+ );
+
+VOID
+TsSetTime(
+ IN WCHAR DriveLetter,
+ IN PWSTR Category
+ );
+
+VOID
+TsGetTime(
+ IN WCHAR DriveLetter,
+ IN PWSTR Category,
+ OUT PTIME_FIELDS Time
+ );
+
+#endif // __TIME_HXX__
diff --git a/private/utils/windisk/src/volview.cxx b/private/utils/windisk/src/volview.cxx
new file mode 100644
index 000000000..e186328cc
--- /dev/null
+++ b/private/utils/windisk/src/volview.cxx
@@ -0,0 +1,400 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: volview.cxx
+//
+// Contents: Routines for handling the volumes view
+//
+// History: 18-Jun-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include <stdio.h>
+
+#include "cm.hxx"
+#include "dispinfo.hxx"
+#include "select.hxx"
+#include "volview.hxx"
+
+//////////////////////////////////////////////////////////////////////////////
+
+LRESULT
+OnGetDispInfo(
+ IN LV_DISPINFO* plvdi
+ );
+
+int CALLBACK
+ListViewCompareProc(
+ LPARAM lParam1,
+ LPARAM lParam2,
+ LPARAM lParamSort
+ );
+
+//////////////////////////////////////////////////////////////////////////////
+
+//
+// BUGBUG: Hardcoded initialization of columns.
+//
+
+LOCAL LV_COLUMN s_aColumnInit[g_cColumns] =
+{
+ { LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM, LVCFMT_LEFT, 50, NULL, 0, 0 },
+ { LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM, LVCFMT_LEFT, 90, NULL, 0, 0 },
+ { LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM, LVCFMT_RIGHT, 70, NULL, 0, 0 },
+ { LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM, LVCFMT_RIGHT, 70, NULL, 0, 0 },
+ { LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM, LVCFMT_RIGHT, 50, NULL, 0, 0 },
+ { LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM, LVCFMT_LEFT, 70, NULL, 0, 0 },
+ { LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM, LVCFMT_LEFT, 110, NULL, 0, 0 },
+ { LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM, LVCFMT_LEFT, 90, NULL, 0, 0 },
+ { LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM, LVCFMT_LEFT, 150, NULL, 0, 0 },
+ { LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM, LVCFMT_LEFT, 90, NULL, 0, 0 }
+};
+
+//
+// The following array exactly parallels the previous array, and must
+// have the same number of entries. It contains resource IDs for column
+// strings
+//
+LOCAL UINT s_aColumnStringID[g_cColumns] =
+{
+ IDS_VV_VOLUME,
+ IDS_VV_NAME,
+ IDS_VV_CAPACITY,
+ IDS_VV_FREESPACE,
+ IDS_VV_PCTFREE,
+ IDS_VV_FORMAT,
+ IDS_VV_FT,
+ IDS_VV_VOLTYPE,
+ IDS_VV_OVERHEAD,
+ IDS_VV_STATUS
+};
+
+// The column order: 1 for ascending, -1 for descending
+int g_aColumnOrder;
+int g_iLastColumnSorted;
+
+WORD IconListSmall[] =
+{
+ IDI_S_HARD,
+ IDI_S_CDROM
+};
+
+int IconIndexSmall[ARRAYLEN(IconListSmall)] = {0};
+
+//////////////////////////////////////////////////////////////////////////////
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: InitializeListview, public
+//
+// Synopsis: create and test a listview control
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+VOID
+InitializeListview(
+ VOID
+ )
+{
+ FDASSERT(ARRAYLEN(s_aColumnInit) == ARRAYLEN(s_aColumnStringID));
+
+ int i;
+ int cxSmallIcon, cySmallIcon;
+ HIMAGELIST himlSmall;
+ HICON hIcon;
+
+ //
+ // Set the image lists to have all the icons we need
+ //
+
+ cxSmallIcon = 16; // = GetSystemMetrics(SM_CXSMICON);
+ cySmallIcon = 16; // = GetSystemMetrics(SM_CYSMICON);
+
+ FDASSERT(cxSmallIcon == 16);
+ FDASSERT(cySmallIcon == 16);
+
+ himlSmall = ImageList_Create(cxSmallIcon, cySmallIcon, TRUE, ARRAYLEN(IconListSmall), 0);
+ if (NULL == himlSmall)
+ {
+ daDebugOut((DEB_ERROR, "ImageList_Create failed\n"));
+ }
+
+ for (i=0; i<ARRAYLEN(IconListSmall); i++)
+ {
+ hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IconListSmall[i]));
+ IconIndexSmall[i] = ImageList_AddIcon(himlSmall, hIcon);
+ DestroyIcon(hIcon);
+ }
+
+ // now, all needed icons are in the HIMAGELIST
+
+ if (!ListView_SetImageList(g_hwndLV, himlSmall, LVSIL_SMALL))
+ {
+ daDebugOut((DEB_ERROR, "ListView_SetImageList failed\n"));
+ //BUGBUG: comctl32.dll seems to always return false
+ }
+
+ //
+ // Add the default columns
+ //
+
+ LV_COLUMN lvC;
+ TCHAR szColumn[MAX_RESOURCE_STRING_LEN];
+
+ for (i = 0; i<ARRAYLEN(s_aColumnInit); i++)
+ {
+ LoadString(
+ g_hInstance,
+ s_aColumnStringID[i],
+ szColumn,
+ ARRAYLEN(szColumn));
+
+ lvC = s_aColumnInit[i];
+ lvC.pszText = szColumn;
+
+ daDebugOut((DEB_ITRACE, "listview column %d ==> %ws\n", i, szColumn));
+
+ if (-1 == ListView_InsertColumn(g_hwndLV, i, &lvC))
+ {
+ daDebugOut((DEB_ERROR,"ListView_InsertColumn (%d) failed\n",i));
+ }
+ }
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: HandleListviewNotify
+//
+// Synopsis: Handles WM_NOTIFY message for the listview control
+//
+// Arguments: [pnmlv] -- notification information
+//
+// Returns: standard window procedure
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+LRESULT
+HandleListviewNotify(
+ IN NM_LISTVIEW* pnmlv
+ )
+{
+ switch (pnmlv->hdr.code)
+ {
+ case LVN_ITEMCHANGING:
+ return FALSE; // allow all changes
+
+ case LVN_ITEMCHANGED:
+ {
+ if (g_SettingListviewState)
+ {
+ //
+ // I'm setting the state because of a disks view change;
+ // don't do normal selection
+ //
+ break;
+ }
+
+ if (!(pnmlv->uChanged & LVIF_STATE))
+ {
+ daDebugOut((DEB_ITRACE,
+" NOT A STATE CHANGE\n\n"));
+ break;
+ }
+
+ if ( (pnmlv->uOldState & LVIS_SELECTED)
+ || (pnmlv->uNewState & LVIS_SELECTED))
+ {
+ //
+ // A selection change: either the item became selected or
+ // lost the selection
+ //
+
+ SetVolumeSelection(pnmlv->iItem, pnmlv->uNewState & LVIS_SELECTED);
+ AdjustMenuAndStatus();
+ }
+
+ break;
+ }
+
+ case LVN_BEGINDRAG:
+ case LVN_BEGINRDRAG:
+ return FALSE; // don't allow any drag/drop
+
+ case LVN_DELETEITEM:
+ {
+ CDispInfo* pdi = (CDispInfo*)pnmlv->lParam;
+ delete pdi;
+ return 0L; //ignored?
+ }
+
+ case LVN_GETDISPINFO:
+ return OnGetDispInfo((LV_DISPINFO *)pnmlv);
+
+ case LVN_COLUMNCLICK:
+ {
+ if (pnmlv->iSubItem != g_iLastColumnSorted)
+ {
+ g_aColumnOrder = 1;
+ g_iLastColumnSorted = pnmlv->iSubItem;
+ }
+
+ // The user clicked on one of the column headings - sort the column.
+ ListView_SortItems( pnmlv->hdr.hwndFrom,
+ ListViewCompareProc,
+ (LPARAM)(pnmlv->iSubItem));
+ g_aColumnOrder = -g_aColumnOrder; //invert
+ return TRUE;
+ }
+
+ case NM_CLICK:
+ case NM_RCLICK:
+ {
+ //
+ // got a button 2 click on a listview item. Bring up a
+ // context menu
+ //
+
+ LV_HITTESTINFO hti;
+ POINT pt;
+
+ GetCursorPos(&pt);
+ hti.pt = pt;
+ ScreenToClient(g_hwndLV, &hti.pt);
+ INT item = ListView_HitTest(g_hwndLV, &hti);
+
+ if (-1 != item)
+ {
+ if ( (NM_RCLICK == pnmlv->hdr.code)
+ && (hti.flags & LVHT_ONITEM))
+ {
+ ContextMenu(&pt);
+ }
+ }
+
+ break;
+ } // end case NM_RCLICK:
+
+ } // end switch (pnmlv->hdr.code)
+
+ return (LRESULT)0;
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: OnGetDispInfo
+//
+// Synopsis:
+//
+// Arguments:
+//
+// Returns:
+//
+//----------------------------------------------------------------------------
+
+LRESULT
+OnGetDispInfo(
+ IN LV_DISPINFO* plvdi
+ )
+{
+ CDispInfo* pdi = (CDispInfo*)(plvdi->item.lParam);
+ plvdi->item.pszText = pdi->GetText(plvdi->item.iSubItem);
+ return 0L; //ignored?
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: ListViewCompareProc
+//
+// Synopsis: Callback function that sorts depending on the column click
+//
+// Arguments:
+//
+// Returns: -, 0, or +, based on order
+//
+//----------------------------------------------------------------------------
+
+int CALLBACK
+ListViewCompareProc(
+ LPARAM lParam1,
+ LPARAM lParam2,
+ LPARAM lParamSort
+ )
+{
+ // string: lstrcmpi(string1, string2);
+ // number: number1 - number2
+
+ CDispInfo* pdi1 = (CDispInfo*)lParam1;
+ CDispInfo* pdi2 = (CDispInfo*)lParam2;
+ int iSubItem = (int)lParamSort;
+ int iResult;
+
+ switch (iSubItem)
+ {
+ case 0: // column 0: drive letter
+ case 1: // column 1: volume label
+ case 5: // column 5: format (file system type)
+ case 6: // column 6: fault tolerant?
+ case 7: // column 7: volume type
+ case 8: // column 8: fault tolerance overhead in MB
+ case 9: // column 9: status
+ {
+ PWSTR psz1 = pdi1->GetText(iSubItem);
+ PWSTR psz2 = pdi2->GetText(iSubItem);
+ iResult = lstrcmpi(psz1, psz2);
+ break;
+ }
+
+ case 2: // column 2: capacity in MB
+ case 3: // column 3: free space in MB
+ case 4: // column 4: % free space
+ {
+ LONG l1 = pdi1->GetNumber(iSubItem);
+ LONG l2 = pdi2->GetNumber(iSubItem);
+
+ if (l1 > l2)
+ {
+ iResult = 1;
+ }
+ else if (l1 < l2)
+ {
+ iResult = -1;
+ }
+ else
+ {
+ iResult = 0;
+ }
+ break;
+ }
+
+ default: // This shouldn't happen!
+ daDebugOut((DEB_ERROR,
+ "ListViewCompareProc: unknown column (%d)",
+ iSubItem));
+
+ iResult = 0;
+ break;
+
+ } // switch (iSubItem)
+
+ return iResult * g_aColumnOrder;
+}
diff --git a/private/utils/windisk/src/volview.hxx b/private/utils/windisk/src/volview.hxx
new file mode 100644
index 000000000..bf83432bc
--- /dev/null
+++ b/private/utils/windisk/src/volview.hxx
@@ -0,0 +1,36 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: volview.hxx
+//
+// Contents: Declarations for the volumes view
+//
+// History: 18-Jun-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __VOLVIEW_HXX__
+#define __VOLVIEW_HXX__
+
+//////////////////////////////////////////////////////////////////////////////
+
+const int g_cColumns = 10;
+
+extern int g_aColumnOrder;
+extern int g_iLastColumnSorted;
+
+//////////////////////////////////////////////////////////////////////////////
+
+VOID
+InitializeListview(
+ VOID
+ );
+
+LRESULT
+HandleListviewNotify(
+ IN NM_LISTVIEW* pnmlv
+ );
+
+#endif // __VOLVIEW_HXX__
diff --git a/private/utils/windisk/src/windisk.cxx b/private/utils/windisk/src/windisk.cxx
new file mode 100644
index 000000000..468cbadec
--- /dev/null
+++ b/private/utils/windisk/src/windisk.cxx
@@ -0,0 +1,5753 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: windisk.cxx
+//
+// Contents: Disk Administrator main Windows routines
+//
+// History: 6-Jun-93 BruceFo Created from NT Disk Administrator
+// 8-Jan-94 BruceFo Added BobRi's Daytona CD-ROM,
+// DoubleSpace, and Commit support
+//
+//--------------------------------------------------------------------------
+
+#include "headers.hxx"
+#pragma hdrstop
+
+#include <stdlib.h>
+#include <string.h>
+#include <shellapi.h>
+#include <shlobj.h>
+#include <shlobjp.h>
+#include <shsemip.h>
+
+#include <util.hxx>
+
+#include "cdrom.hxx"
+#include "chkdsk.hxx"
+#include "cm.hxx"
+#include "commit.hxx"
+#include "controls.hxx"
+#include "dialogs.h"
+#include "dblspace.hxx"
+#include "dlgs.hxx"
+#include "drives.hxx"
+#include "fill.hxx"
+#include "fmifs.hxx"
+#include "format.hxx"
+#include "ft.hxx"
+#include "ftreg.hxx"
+#include "genlpage.hxx"
+#include "help.hxx"
+#include "help2.hxx"
+#include "init.hxx"
+#include "label.hxx"
+#include "listbox.hxx"
+#include "menudict.hxx"
+#include "nt.hxx"
+#include "ntlow.hxx"
+#include "oleclass.hxx"
+#include "ops.hxx"
+#include "ps.hxx"
+#include "profile.hxx"
+#include "rectpriv.hxx"
+#include "select.hxx"
+#include "stleg.hxx"
+#include "tb.h"
+#include "tbar.hxx"
+#include "volview.hxx"
+#include "windisk.hxx"
+#include "dbt.h"
+
+
+////////////////////////////////////////////////////////////////////////////
+
+//
+// This is the index of the Fault Tolerance menu. It is currently the
+// second menu across the menu bar, so it is index 1 in 0-based numbering
+//
+
+#define FT_MENU_INDEX 1
+
+////////////////////////////////////////////////////////////////////////////
+
+TCHAR WinHelpFile[] = TEXT("windisk.hlp");
+TCHAR LanmanHelpFile[] = TEXT("windiska.hlp");
+
+
+#if DBG == 1
+
+BOOL AllowAllDeletes = FALSE; // whether to allow deleting boot/sys parts
+BOOL BothViews = FALSE; // show both volumes & disks view on same pane?
+
+#endif // DBG == 1
+
+
+//
+// The following vars keep track of the currently selected regions.
+//
+DWORD SelectionCount = 0;
+PDISKSTATE SelectedDS[MAX_MEMBERS_IN_FT_SET];
+ULONG SelectedRG[MAX_MEMBERS_IN_FT_SET];
+
+ULONG SelectedFreeSpaces;
+ULONG SelectedNonFtPartitions;
+PULONG DiskSeenCountArray;
+BOOL FtSetSelected;
+FT_TYPE FtSelectionType;
+BOOL NonFtItemSelected;
+BOOL MultipleItemsSelected;
+BOOL VolumeSetAndFreeSpaceSelected;
+BOOL PartitionAndFreeSpaceSelected;
+BOOL PossibleRecover;
+ULONG FreeSpaceIndex;
+
+BOOL DiskSelected;
+BOOL PartitionSelected;
+BOOL CdRomSelected;
+DWORD CdRomSelectionCount;
+
+BOOL AllowFormat;
+BOOL AllowVolumeOperations;
+
+#ifdef WINDISK_EXTENSIONS
+BOOL AllowExtensionItems;
+#endif // WINDISK_EXTENSIONS
+
+
+HANDLE DisplayMutex;
+ULONG DisplayUpdateCount;
+DWORD RefreshAllowed = 0;
+
+
+#ifndef i386
+
+//
+// This variable tracks whether the system partition is secure.
+//
+BOOL SystemPartitionIsSecure = FALSE;
+
+#endif // !i386
+
+#if defined( DBLSPACE_ENABLED )
+BOOL DoubleSpaceAutomount;
+#endif // DBLSPACE_ENABLED
+
+BOOLEAN g_oneTime = TRUE;
+
+////////////////////////////////////////////////////////////////////////////
+
+//
+// g_uItemInsertHere is an index into the "Volume" menu of where the
+// next extension menu item may be inserted. The UITEM_INSERT_HERE constant
+// points to the initial position, which is currently the 0-based index
+// of the "Format" item, plus one.
+//
+#define UITEM_INSERT_HERE (0 + 1)
+
+UINT g_uItemInsertHere = UITEM_INSERT_HERE;
+
+
+////////////////////////////////////////////////////////////////////////////
+
+VOID _CRTAPI1
+main(
+ IN int argc,
+ IN char* argv[],
+ IN char* envp[]
+ );
+
+#ifndef i386
+BOOL
+IsSystemPartitionSecure(
+ VOID
+ );
+#endif // !i386
+
+VOID
+SetProductType(
+ VOID
+ );
+
+VOID
+CleanUp(
+ VOID
+ );
+
+#if i386
+VOID
+SetUpMenui386(
+ IN HMENU hMenu
+ );
+#endif
+
+VOID
+ChangeView(
+ VOID
+ );
+
+VOID
+AdjustOptionsMenu(
+ VOID
+ );
+
+VOID
+PaintStatusBar(
+ IN HWND hwnd,
+ IN PAINTSTRUCT* pps,
+ IN PRECT prc
+ );
+
+VOID
+PaintLegend(
+ IN HWND hwnd,
+ IN PAINTSTRUCT* pps,
+ IN PRECT prc
+ );
+
+VOID
+PaintVolumesView(
+ IN HWND hwnd,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+VOID
+PaintDisksView(
+ IN HWND hwnd,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+LRESULT
+FrameCreateHandler(
+ IN HWND hwnd,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+LRESULT
+FrameResizeHandler(
+ IN HWND hwnd,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+LRESULT
+FramePaintHandler(
+ IN HWND hwnd,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+LRESULT
+FrameCommandHandler(
+ IN HWND hwnd,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+LRESULT
+FrameCloseHandler(
+ IN HWND hwnd,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+LRESULT
+FrameDestroyHandler(
+ IN HWND hwnd,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+ULONG
+GetLargestDiskSize(
+ VOID
+ );
+
+VOID
+DrawCdRomBar(
+ IN ULONG CdRomNumber
+ );
+
+WCHAR BootDir = (WCHAR)0;
+WCHAR SystemDir = (WCHAR)0;
+////////////////////////////////////////////////////////////////////////////
+
+//+---------------------------------------------------------------------------
+//
+// Function: main
+//
+// Synopsis: Entrypoint for all Disk Administrator functionality
+//
+// Arguments: standard C/C++ main
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID _CRTAPI1
+main(
+ IN int argc,
+ IN char* argv[],
+ IN char* envp[]
+ )
+{
+ MSG msg;
+ NTSTATUS status;
+ HANDLE mutex;
+ HACCEL hAccel;
+ WCHAR driveLetterBuffer[MAX_PATH];
+ UNICODE_STRING driveLetterString;
+
+ RTL_QUERY_REGISTRY_TABLE driveLetterTable[2] = {0};
+
+#if DBG == 1
+ InitializeDebugging();
+#endif // DBG == 1
+
+ daDebugOut((DEB_TRACE, "Starting Disk Administrator...\n"));
+
+ g_hInstance = GetModuleHandle(NULL);
+
+ mutex = CreateMutex(NULL, FALSE, TEXT("Disk Administrator Is Running"));
+
+ if (mutex == NULL)
+ {
+ // An error (like out of memory) has occurred.
+ return;
+ }
+
+ //
+ // Make sure we are the only process with a handle to our named mutex.
+ //
+
+ if (GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+ CloseHandle(mutex);
+ InfoDialog(MSG_ALREADY_RUNNING);
+ return;
+ }
+
+ __try
+ {
+ //
+ // Figure out the product type (Normal WinNT or Server)
+ //
+
+ SetProductType();
+
+#if DBG == 1
+ //
+ // The code below will allow users to run WinDisk in Lanman
+ // mode on WinNt. It should never be enabled in a released
+ // build, but is very useful for internal users.
+ //
+
+ --argc;
+ ++argv;
+ while (argc > 0)
+ {
+ if (0 == _stricmp( *argv, "/both" ))
+ {
+ BothViews = TRUE;
+ }
+ else if (0 == _stricmp( *argv, "/server" ))
+ {
+ g_IsLanmanNt = TRUE;
+ }
+ else if (0 == _stricmp( *argv, "/workstation" ))
+ {
+ g_IsLanmanNt = FALSE;
+ }
+ else if (0 == _stricmp( *argv, "/debug" ))
+ {
+ daInfoLevel =
+ DEB_ERROR
+ | DEB_WARN
+ | DEB_TRACE
+ | DEB_IERROR
+ | DEB_IWARN
+ | DEB_ITRACE
+ ;
+ }
+ else
+ {
+ MessageBox(NULL,
+ L"Disk Administrator command-line usage:\n"
+ L"\t/server\t-- Use the Windows NT Server version\n"
+ L"\t/workstation\t-- Use the Windows NT Workstation version\n"
+ L"\n"
+ L"For debugging:\n"
+ L"\t/both\t-- see both views at once\n"
+ L"\t/debug\t-- see trace and error output on the debugger\n"
+ ,
+
+ L"Disk Administrator",
+ MB_ICONINFORMATION | MB_OK);
+ return;
+ }
+
+ --argc;
+ ++argv;
+ }
+#endif // DBG == 1
+
+ //
+ // Get a handle to the display mutex lock.
+ //
+
+ DisplayMutex = CreateMutex(
+ NULL,
+ FALSE,
+ NULL
+ );
+
+ if (!DisplayMutex) {
+
+ ErrorDialog(MSG_CANT_INITIALIZE);
+ goto xx2;
+
+ }
+
+ DisplayUpdateCount = 0;
+
+
+
+ DisplayInitializationMessage();
+
+ // Set the Help file name to the file appropriate to
+ // the product.
+ //
+ g_HelpFile = g_IsLanmanNt ? LanmanHelpFile : WinHelpFile;
+
+ InitCommonControls();
+
+#ifndef i386
+ //
+ // Determine whether the system partition is protected:
+ //
+ SystemPartitionIsSecure = IsSystemPartitionSecure();
+#endif // !i386
+
+#if DBG == 1
+ InitLogging();
+#endif // DBG == 1
+
+// STARTUP BeginStartup();
+
+ //
+ // Ensure that all drives are present before looking
+ //
+
+ RescanDevices();
+
+ status = FdiskInitialize();
+ if (!NT_SUCCESS(status))
+ {
+ ErrorDialog(status == STATUS_ACCESS_DENIED
+ ? MSG_ACCESS_DENIED
+ : EC(status));
+ goto xx1;
+ }
+
+ if (((DiskCount = GetDiskCount()) == 0) || AllDisksOffLine())
+ {
+ ErrorDialog(MSG_NO_DISKS);
+ goto xx2;
+ }
+
+ if (!InitializeApp())
+ {
+ ErrorDialog(MSG_CANT_INITIALIZE);
+ goto xx2;
+ }
+
+ //
+ // Get the drive letter of the boot drive.
+ //
+
+ driveLetterString.Length = 0;
+ driveLetterString.MaximumLength = sizeof(driveLetterBuffer);
+ driveLetterString.Buffer = (PWCHAR)&driveLetterBuffer[0];
+ driveLetterTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT |
+ RTL_QUERY_REGISTRY_REQUIRED;
+ driveLetterTable[0].Name = L"BootDir";
+ driveLetterTable[0].EntryContext = &driveLetterString;
+
+ if (NT_SUCCESS(RtlQueryRegistryValues(
+ RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
+ L"\\REGISTRY\\MACHINE\\SOFTWARE\\MICROSOFT\\WINDOWS\\CURRENTVERSION\\SETUP",
+ &driveLetterTable[0],
+ NULL,
+ NULL
+ ))) {
+
+ BootDir = driveLetterBuffer[0];
+
+ }
+
+ {
+ UINT pathSize;
+
+ pathSize = GetWindowsDirectory(
+ &driveLetterBuffer[0],
+ sizeof(driveLetterBuffer)
+ );
+
+ if ((pathSize <= MAX_PATH) && pathSize) {
+
+ SystemDir = driveLetterBuffer[0];
+
+ }
+ }
+
+
+
+ SetUpMenu(&SingleSel, &SingleSelIndex);
+
+#if DBG == 1
+ // All initialization has been done by now
+ LOG_ALL();
+#endif // DBG == 1
+
+ ChangeView();
+ AdjustOptionsMenu();
+
+ InitHelp();
+
+ hAccel = LoadAccelerators(
+ g_hInstance,
+ MAKEINTRESOURCE(ID_FRAME_ACCELERATORS)
+ );
+
+ //
+ // Finally, make the window visible before starting the message pump
+ //
+
+ ShowWindow(
+ g_hwndFrame,
+ ProfileIsIconic ? SW_SHOWMINIMIZED
+ : (ProfileIsMaximized ? SW_SHOWMAXIMIZED
+ : SW_SHOWDEFAULT)
+ );
+ UpdateWindow(g_hwndFrame);
+
+#if DBG == 1
+ // All initialization has been done by now
+ LOG_ALL();
+#endif // DBG == 1
+
+// STARTUP EndStartup();
+// STARTUP SetForegroundWindow(g_hwndFrame);
+
+ //
+ // Start the message pump: this is where everything happens!
+ //
+
+ if (NULL != g_InitDlg)
+ {
+ PostMessage(g_InitDlg, WM_STARTUP_END, 0, 0);
+ g_InitDlg = NULL;
+ }
+
+ while (GetMessage(&msg, NULL, 0, 0))
+ {
+ if (!TranslateAccelerator(g_hwndFrame, hAccel, &msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ CleanUp();
+
+ xx2:
+
+ FdiskCleanUp();
+
+ xx1:
+
+#if DBG == 1
+ EndLogging();
+#endif // DBG == 1
+
+ ;
+
+ }
+ __finally
+ {
+ // Destroy the mutex.
+
+ CloseHandle(mutex);
+ }
+}
+
+
+#ifndef i386
+
+//+---------------------------------------------------------------------------
+//
+// Function: IsSystemPartitionSecure
+//
+// Synopsis: Determines if the system partition is secure by
+// examining the registry.
+//
+// Arguments: (none)
+//
+// Returns: TRUE if the registry indicates the system partition is secure
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+BOOL
+IsSystemPartitionSecure(
+ VOID
+ )
+{
+ LONG ec;
+ HKEY hkey;
+ DWORD type;
+ DWORD size;
+ ULONG value;
+
+ value = FALSE;
+
+ ec = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+ TEXT("System\\CurrentControlSet\\Control\\Lsa"),
+ 0,
+ KEY_QUERY_VALUE,
+ &hkey
+ );
+
+ if (ec == NO_ERROR)
+ {
+ size = sizeof(ULONG);
+ ec = RegQueryValueEx( hkey,
+ TEXT("Protect System Partition"),
+ NULL,
+ &type,
+ (PBYTE)&value,
+ &size
+ );
+
+ if ((ec != NO_ERROR) || (type != REG_DWORD))
+ {
+ value = FALSE;
+ }
+
+ RegCloseKey(hkey);
+ }
+
+ return value;
+}
+
+#endif // !i386
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: SetProductType
+//
+// Synopsis: Sets the [g_IsLanmanNt] global variable based on the
+// product type: workstation or advanced server
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// Modifies: [g_IsLanmanNt] -- set to TRUE for an advanced server
+// installation that allows fault tolerance configuration.
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+SetProductType(
+ VOID
+ )
+{
+ //
+ // Determine whether this is LanmanNt or Windows NT by looking at
+ // HKEY_LOCAL_MACHINE, System\CurrentControlSet\Control\ProductOptions.
+ // If the ProductType value therein is "LanmanNt" then this is LanmanNt.
+ //
+
+ LONG ec;
+ HKEY hkey;
+ DWORD type;
+ DWORD size;
+ UCHAR buf[100];
+
+ g_IsLanmanNt = FALSE;
+
+ ec = RegOpenKeyEx(
+ HKEY_LOCAL_MACHINE,
+ TEXT("System\\CurrentControlSet\\Control\\ProductOptions"),
+ 0,
+ KEY_QUERY_VALUE,
+ &hkey
+ );
+
+ if (ec == NO_ERROR)
+ {
+ size = sizeof(buf);
+ ec = RegQueryValueEx(hkey,
+ TEXT("ProductType"),
+ NULL,
+ &type,
+ buf,
+ &size);
+
+ if ((ec == NO_ERROR) && (type == REG_SZ))
+ {
+ if (0 == lstrcmpi((LPTSTR)buf, TEXT("lanmannt")))
+ {
+ g_IsLanmanNt = TRUE;
+ }
+
+ if (0 == lstrcmpi((LPTSTR)buf, TEXT("servernt")))
+ {
+ g_IsLanmanNt = TRUE;
+ }
+ }
+
+ RegCloseKey(hkey);
+ }
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: CleanUp
+//
+// Synopsis: Miscellaneous cleanup before exit
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 22-Oct-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+CleanUp(
+ VOID
+ )
+{
+ ReleaseRectControl(g_hInstance);
+ ReleaseWindiskControls(g_hInstance);
+ TermHelp();
+ ReleaseOle();
+ UnloadFmifs();
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: MyFrameWndProc
+//
+// Synopsis: Window procedure for the frame window
+//
+// Arguments: standard Windows procedure
+//
+// Returns: standard Windows procedure
+//
+// History: 16-Aug-93 BruceFo Created
+//
+// Notes: Creates the listbox control for the disks view, the
+// listview control for the volumes view, the toolbar control.
+//
+//----------------------------------------------------------------------------
+
+LRESULT CALLBACK
+MyFrameWndProc(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ RECT rc;
+ UINT oldErrorMode;
+
+ switch (msg)
+ {
+
+ case WM_CREATE:
+
+ return FrameCreateHandler(hwnd, wParam, lParam);
+
+//
+// Toolbar notification
+//
+
+ case WM_NOTIFY:
+ {
+ NMHDR* phdr = (NMHDR*)lParam;
+
+ //
+ // The tooltip notification sends the command id as wParam instead of
+ // a control id such as the toolbar id. Since commctrl notification
+ // codes are disjoint, check for tooltip notifications first, then
+ // the others.
+ //
+
+ switch (phdr->code)
+ {
+ case TTN_NEEDTEXT:
+ return HandleTooltipNotify((TOOLTIPTEXT*)phdr);
+ } // end switch (phdr->code)
+
+ switch (wParam)
+ {
+ case ID_LISTVIEW:
+ return HandleListviewNotify((NM_LISTVIEW*)phdr);
+
+ case IDC_TOOLBAR:
+ return HandleToolbarNotify((TBNOTIFY*)phdr);
+
+ default:
+ daDebugOut((DEB_ITRACE,
+ "WM_NOTIFY: unknown! control %d, idFrom %d, code %d\n",
+ wParam,
+ phdr->idFrom,
+ phdr->code));
+ return 0L; //shouldn't happen!
+
+ } // end switch (wParam)
+ }
+
+ case WM_SETFOCUS:
+
+ PostMessage(hwnd,WM_USER, 0, 0);
+
+ switch (g_WhichView)
+ {
+ case VIEW_VOLUMES:
+ SetFocus(g_hwndLV);
+ break;
+
+ case VIEW_DISKS:
+ SetFocus(g_hwndList);
+ break;
+
+ default:
+ FDASSERT(0);
+ }
+ break;
+
+ case WM_DEVICECHANGE:
+
+ if ((wParam == DBT_DEVICEARRIVAL) ||
+ (wParam == DBT_DEVICEREMOVECOMPLETE)) {
+ WaitForSingleObject(DisplayMutex, INFINITE);
+ RefreshAllowed = 1;
+ ReleaseMutex(DisplayMutex);
+ PostMessage(hwnd, WM_USER, 0, 0);
+ } else {
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+ break;
+
+ case WM_WININICHANGE:
+
+ if (((LPTSTR)lParam == NULL)
+ || !lstrcmpi((LPTSTR)lParam, TEXT("colors")))
+ {
+ TotalRedrawAndRepaint();
+ InvalidateRect(hwnd, NULL, FALSE);
+ }
+ break;
+
+ case WM_GETMINMAXINFO:
+ {
+ LPMINMAXINFO lpmmi = (LPMINMAXINFO)lParam;
+
+ //
+ // Don't allow resizing too small
+ //
+
+ lpmmi->ptMinTrackSize.x = MinimumWindowWidth;
+
+ return 0; // message processed
+ }
+
+ case WM_SIZE:
+
+ FrameResizeHandler(hwnd, wParam, lParam);
+
+ // FALL THROUGH
+
+ case WM_MOVE:
+
+ // if not iconic or minimized, save new position for profile
+
+ if (!IsZoomed(hwnd) && !IsIconic(hwnd))
+ {
+ GetWindowRect(hwnd, &rc);
+ ProfileWindowX = rc.left;
+ ProfileWindowY = rc.top;
+ ProfileWindowW = rc.right - rc.left;
+ ProfileWindowH = rc.bottom - rc.top;
+ }
+ break;
+
+ case WM_ENTERIDLE:
+
+ if (ConfigurationSearchIdleTrigger == TRUE && wParam == MSGF_DIALOGBOX)
+ {
+ PostMessage((HWND)lParam, WM_ENTERIDLE, wParam, lParam);
+ }
+ else
+ {
+ // If we're coming from a dialog box and the F1 key is down,
+ // kick the dialog box and make it spit out help.
+ //
+ if ((wParam == MSGF_DIALOGBOX)
+ && (GetKeyState(VK_F1) & 0x8000)
+ && GetDlgItem((HWND) lParam, IDHELP))
+ {
+ PostMessage((HWND) lParam, WM_COMMAND, IDHELP, 0L);
+ }
+ }
+
+ return 1; // indicate we did not process the message
+
+ case WM_PAINT:
+
+ return FramePaintHandler(hwnd, wParam, lParam);
+
+ case WM_COMMAND: {
+
+ LRESULT localResult;
+
+ WaitForSingleObject(
+ DisplayMutex,
+ INFINITE
+ );
+ DisplayUpdateCount++;
+ ReleaseMutex(DisplayMutex);
+
+ localResult = FrameCommandHandler(hwnd, wParam, lParam);
+
+ WaitForSingleObject(
+ DisplayMutex,
+ INFINITE
+ );
+ DisplayUpdateCount--;
+ ReleaseMutex(DisplayMutex);
+
+ return localResult;
+
+ }
+
+ case WM_RBUTTONUP:
+ {
+ //
+ // Handle context menu on legend
+ //
+
+ POINT pt;
+ pt.x = (LONG)(LOWORD(lParam));
+ pt.y = (LONG)(HIWORD(lParam));
+
+ // pt is now in client coordinates
+
+ if (HitTestLegend(&pt))
+ {
+ ClientToScreen(hwnd, &pt);
+ LegendContextMenu(&pt);
+ }
+
+ break;
+ }
+
+ case WM_MEASUREITEM:
+ {
+ PMEASUREITEMSTRUCT pMeasureItem = (PMEASUREITEMSTRUCT)lParam;
+ pMeasureItem->itemHeight = GraphHeight;
+ break;
+ }
+
+ case WM_DRAWITEM:
+
+ return WMDrawItem((PDRAWITEMSTRUCT)lParam);
+
+ case WM_CTLCOLORLISTBOX:
+
+ if ((HWND)lParam == g_hwndList)
+ {
+ return (LRESULT)GetStockBrush(LTGRAY_BRUSH);
+ }
+ else
+ {
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+
+ case WM_CLOSE:
+
+ return FrameCloseHandler(hwnd, wParam, lParam);
+
+ case WM_DESTROY:
+
+ return FrameDestroyHandler(hwnd, wParam, lParam);
+
+ case WM_INITMENU:
+
+ if (g_StatusBar)
+ {
+ PaintHelpStatusBar(NULL);
+ }
+ break;
+
+ case WM_MENUSELECT:
+
+ SetMenuItemHelpContext(wParam, lParam);
+ break;
+
+ case WM_F1DOWN:
+
+ Help(wParam);
+ break;
+
+ case WM_USER:
+
+
+ WaitForSingleObject(
+ DisplayMutex,
+ INFINITE
+ );
+
+ if (DisplayUpdateCount || !RefreshAllowed) {
+
+ ReleaseMutex(DisplayMutex);
+ break;
+
+ }
+
+ DisplayUpdateCount++;
+
+ ReleaseMutex(DisplayMutex);
+
+ oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+ DoRefresh();
+ SetErrorMode(oldErrorMode);
+
+ WaitForSingleObject(
+ DisplayMutex,
+ INFINITE
+ );
+
+ RefreshAllowed = 0;
+ DisplayUpdateCount--;
+ ReleaseMutex(DisplayMutex);
+
+ break;
+
+ default:
+
+ return DefWindowProc(hwnd, msg, wParam, lParam);
+ }
+
+ return 0;
+}
+
+
+
+#if i386
+
+//+---------------------------------------------------------------------------
+//
+// Function: SetUpMenui386
+//
+// Synopsis: For x86 machines, set up the "Mark active" item
+//
+// Arguments: [hMenu] -- handle to menu with "Mark active" item
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+SetUpMenui386(
+ IN HMENU hMenu
+ )
+{
+ BOOL allowActive = FALSE;
+ PREGION_DESCRIPTOR regionDescriptor;
+ DWORD i;
+
+ if ((SelectionCount == 1) && (FtSelectionType == UNINIT_FT_TYPE))
+ {
+ regionDescriptor = &SingleSel->RegionArray[SingleSelIndex];
+
+ //
+ // allow it to be made active if
+ // - it is not free space
+ // - it is a primary partition
+ // - it is not already active
+ // - it is not part of an ft set
+ //
+
+ if ( (regionDescriptor->SysID != PARTITION_ENTRY_UNUSED)
+ && (regionDescriptor->RegionType == REGION_PRIMARY)
+ && !regionDescriptor->Active
+ && (GET_FT_OBJECT(regionDescriptor) == NULL))
+ {
+ allowActive = TRUE;
+ }
+
+ } else if (SelectionCount == 2 && FtSelectionType == Mirror) {
+
+ //
+ // If either of the two partitions in the mirror is primary
+ // and not active then allow the menu item.
+ //
+
+ for (i = 0; i < SelectionCount; i++) {
+ regionDescriptor = &SELECTED_REGION(i);
+ if (regionDescriptor->SysID != PARTITION_ENTRY_UNUSED &&
+ regionDescriptor->RegionType == REGION_PRIMARY &&
+ !regionDescriptor->Active) {
+
+ allowActive = TRUE;
+ }
+ }
+ }
+
+ EnableMenuItem(hMenu,
+ IDM_PARTITIONACTIVE,
+ allowActive ? MF_ENABLED : MF_GRAYED
+ );
+}
+
+#endif
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: IsVolumeFormatted, public
+//
+// Synopsis: Returns TRUE if volume represented by the argument
+// region is formatted.
+//
+// Arguments: [RegionDescriptor] -- indicates region
+//
+// Returns: TRUE/FALSE
+//
+// History: 2-Jul-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+BOOL
+IsVolumeFormatted(
+ IN PREGION_DESCRIPTOR RegionDescriptor
+ )
+{
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(RegionDescriptor);
+ if (NULL != regionData)
+ {
+ return (0 != lstrcmp(regionData->TypeName, wszUnknown))
+ && (0 != lstrcmp(regionData->TypeName, wszUnformatted))
+ ;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: DetermineSelectionState, public
+//
+// Synopsis: Returns TRUE if volume represented by the argument
+// region is formatted.
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// Modifies: lots of selection state variables
+//
+// History: 29-Jul-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+VOID
+DetermineSelectionState(
+ VOID
+ )
+{
+ ULONG i;
+ ULONG j;
+ PDISKSTATE diskState;
+ PCDROM_DESCRIPTOR cdrom;
+ PFT_OBJECT_SET ftSet;
+ PFT_OBJECT ftObject;
+ FT_TYPE ftType;
+ ULONG ordinal;
+ ULONG componentsInFtSet = 0;
+
+ //
+ // Initialize globals
+ //
+
+ FtSetSelected = FALSE;
+ FtSelectionType = UNINIT_FT_TYPE;
+ NonFtItemSelected = FALSE;
+ MultipleItemsSelected = FALSE;
+ VolumeSetAndFreeSpaceSelected = FALSE;
+ PartitionAndFreeSpaceSelected = FALSE;
+ SelectedNonFtPartitions = 0;
+ SelectionCount = 0;
+ CdRomSelectionCount = 0;
+ CdRomSelected = FALSE;
+ RtlZeroMemory(DiskSeenCountArray, DiskCount * sizeof(DiskSeenCountArray[0]));
+
+ for (i=0; i<DiskCount; i++)
+ {
+ diskState = DiskArray[i];
+
+ for (j=0; j<diskState->RegionCount; j++)
+ {
+ if (diskState->Selected[j])
+ {
+ SelectionCount++;
+
+ if (SelectionCount <= MAX_MEMBERS_IN_FT_SET)
+ {
+ SelectedDS[SelectionCount-1] = diskState;
+ SelectedRG[SelectionCount-1] = j;
+ }
+
+ DiskSeenCountArray[diskState->Disk]++;
+
+ if (NULL != (ftObject = GET_FT_OBJECT(&diskState->RegionArray[j])))
+ {
+ ftSet = ftObject->Set;
+ if (componentsInFtSet == 0)
+ {
+ ordinal = ftSet->Ordinal;
+ ftType = ftSet->Type;
+ FtSetSelected = TRUE;
+ componentsInFtSet = 1;
+ }
+ else if ((ftSet->Ordinal == ordinal)
+ && (ftSet->Type == ftType))
+ {
+ componentsInFtSet++;
+ }
+ else
+ {
+ FtSetSelected = FALSE;
+ }
+ }
+ else
+ {
+ NonFtItemSelected = TRUE;
+
+ if (IsRecognizedPartition(diskState->RegionArray[j].SysID))
+ {
+ SelectedNonFtPartitions += 1;
+ }
+ }
+ }
+ }
+ }
+
+ for (i=0; i<CdRomCount; i++)
+ {
+ cdrom = CdRomFindDevice(i);
+
+ if (cdrom->Selected)
+ {
+ CdRomSelectionCount++;
+ CdRomSelected = TRUE;
+ }
+ }
+
+ //
+ // Determine the number of free-space regions selected:
+ //
+ SelectedFreeSpaces = 0;
+
+ for (i=0; i<SelectionCount && i < MAX_MEMBERS_IN_FT_SET; i++)
+ {
+ if (SELECTED_REGION(i).SysID == PARTITION_ENTRY_UNUSED)
+ {
+ FreeSpaceIndex = i;
+ SelectedFreeSpaces++;
+ }
+ }
+
+ PossibleRecover = FALSE;
+ if (NonFtItemSelected && FtSetSelected)
+ {
+ //
+ // Both FT and Non-FT items have been selected. First,
+ // check to see if a volume set and free space have been
+ // selected; then reset the state to indicate that the
+ // selection does not consists of a mix of FT and non-FT
+ // objects.
+ //
+ if (ftType == VolumeSet
+ && SelectedFreeSpaces + componentsInFtSet == SelectionCount)
+ {
+ VolumeSetAndFreeSpaceSelected = TRUE;
+ }
+
+ FtSelectionType = ftType;
+ FtSetSelected = FALSE;
+ NonFtItemSelected = FALSE;
+ MultipleItemsSelected = TRUE;
+ PossibleRecover = TRUE;
+ }
+
+ if (FtSetSelected)
+ {
+ FtSelectionType = ftType;
+ }
+
+ // the only way to get a disk selected right now is via context-menu
+ // right-mouse click
+
+ DiskSelected = FALSE;
+
+ if (SelectionCount > 0)
+ {
+ PartitionSelected = TRUE;
+ }
+ else
+ {
+ PartitionSelected = FALSE;
+ }
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: SingleVolumeSelected, public
+//
+// Synopsis: Returns TRUE if a single volume is selected. A single volume
+// is either a single, simple partition that isn't unused (i.e.,
+// is used), OR a single fault tolerant set.
+//
+// Arguments: (none)
+//
+// Returns: TRUE/FALSE
+//
+// History: 29-Jul-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+BOOL
+SingleVolumeSelected(
+ VOID
+ )
+{
+ BOOL singleVolume = FALSE;
+
+ if (!CdRomSelected && (SelectionCount == 1) && !FtSetSelected)
+ {
+ PREGION_DESCRIPTOR regionDescriptor = &SELECTED_REGION(0);
+
+ if (DmSignificantRegion(regionDescriptor))
+ {
+ //
+ // single selection, simple (single-partition) volume
+ //
+
+ singleVolume = TRUE;
+ }
+ }
+
+ if (!CdRomSelected && FtSetSelected)
+ {
+ //
+ // single volume selected, but it is a multiple-region FT volume
+ //
+
+ singleVolume = TRUE;
+ }
+
+ if (CdRomSelected && CdRomSelectionCount == 1)
+ {
+ singleVolume = TRUE;
+ }
+
+ return singleVolume;
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: SetUpMenu
+//
+// Synopsis: Set up the menu bar based on the state of the tool and
+// the disks
+//
+// If multiple items are selected, allow neither create nor delete.
+// If a single partition is selected, allow delete.
+// If a single free space is selected, allow create.
+// If the free space is the only free space in the extended partitions,
+// also allow delete. (This is how to delete the extended partition).
+//
+// If a single volume is selected, allow format.
+//
+// Arguments: [SinglySelectedDisk] -- if there is only one selected item,
+// the PDISKSTATE pointed to by this paramater will get a
+// pointer to the selected region's disk structure. If
+// there are multiple selected items (or none), then the value
+// will be set to NULL.
+// [SinglySelectedRegion] -- if there is only one selected item,
+// the DWORD pointed to by this paramater will get the
+// selected region #. Otherwise the DWORD gets -1.
+//
+// Returns: Count of selected regions
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+DWORD
+SetUpMenu(
+ IN PDISKSTATE *SinglySelectedDisk,
+ IN DWORD *SinglySelectedRegion
+ )
+{
+ PFT_OBJECT_SET ftSet = NULL;
+ PFT_OBJECT ftObject = NULL;
+ PDISKSTATE selectedDiskState;
+ DWORD selectedRegion;
+ PREGION_DESCRIPTOR regionDescriptor;
+ PPERSISTENT_REGION_DATA regionData;
+ DWORD i;
+ BOOL onDifferentDisks;
+ WCHAR rootDirectory[5];
+
+ BOOL allowCommit = FALSE,
+ allowCreate = FALSE,
+ allowCreateEx = FALSE,
+#if defined( DBLSPACE_ENABLED )
+ allowDblSpace = FALSE,
+#endif // DBLSPACE_ENABLED
+ allowDelete = FALSE,
+ allowProperties = FALSE,
+ allowCreateMirror = FALSE,
+ allowBreakMirror = FALSE,
+ allowCreateStripe = FALSE,
+ allowCreateVolumeSet = FALSE,
+ allowExtendVolumeSet = FALSE,
+ allowCreatePStripe = FALSE,
+ allowDriveLetter = FALSE,
+ allowRecoverParity = FALSE,
+ allowEject = FALSE;
+
+ WCHAR driveLetter = L' ';
+ PWSTR typeName = NULL;
+ PWSTR volumeLabel = NULL;
+
+ AllowFormat = FALSE;
+ AllowVolumeOperations = FALSE;
+
+#ifdef WINDISK_EXTENSIONS
+ AllowExtensionItems = FALSE;
+#endif // WINDISK_EXTENSIONS
+
+ //
+ // Start by setting a bunch of global variables based on the selection
+ // state.
+ //
+
+ DetermineSelectionState();
+
+ if (CdRomSelected)
+ {
+ if (CdRomSelectionCount == 1 && SelectionCount == 0)
+ {
+ allowDriveLetter = TRUE;
+
+ //
+ // Find (the hard way) the selected drive.
+ //
+
+ for (i=0;i<CdRomCount;i++) {
+
+ PCDROM_DESCRIPTOR cdrom = CdRomFindDevice(i);
+
+ if (cdrom->Selected) {
+
+
+ //
+ // If there is no cdrom, no point in eject.
+ //
+
+ if (cdrom->TotalSpaceInMB) {
+
+ allowEject = TRUE;
+
+ }
+
+ //
+ // If there is no drive letter, nothing to give the properties
+ //
+
+ if (cdrom->DriveLetter != NO_DRIVE_LETTER_EVER) {
+
+ allowProperties = TRUE;
+
+ }
+
+ }
+
+ }
+ }
+ }
+ else if ((SelectionCount == 1) && !FtSetSelected)
+ {
+ selectedDiskState = SelectedDS[0];
+ selectedRegion = SelectedRG[0];
+
+ *SinglySelectedDisk = selectedDiskState;
+ *SinglySelectedRegion = selectedRegion;
+
+ regionDescriptor = &selectedDiskState->RegionArray[selectedRegion];
+
+ if (regionDescriptor && IsDiskRemovable[regionDescriptor->Disk]) {
+ allowEject = TRUE;
+ allowProperties = TRUE;
+ }
+
+ if (regionDescriptor->SysID == PARTITION_ENTRY_UNUSED)
+ {
+ //
+ // Free region. Always allow create; let DoCreate() sort out
+ // details about whether partition table is full, etc.
+ //
+
+ allowCreate = TRUE;
+
+ if (regionDescriptor->RegionType == REGION_PRIMARY)
+ {
+ allowCreateEx = TRUE;
+ }
+
+ // special case -- allow deletion of the extended partition if
+ // there are no logicals in it.
+
+ if ( (regionDescriptor->RegionType == REGION_LOGICAL)
+ && selectedDiskState->ExistExtended
+ && !selectedDiskState->ExistLogical)
+ {
+ FDASSERT(regionDescriptor->SysID == PARTITION_ENTRY_UNUSED);
+ allowDelete = TRUE;
+ }
+ }
+ else
+ {
+ // used region. Delete always allowed.
+
+ allowDelete = TRUE;
+
+ // also allow format of used region, if it has a drive letter, and
+ // is not the system or boot partition.
+
+ regionData = PERSISTENT_DATA(regionDescriptor);
+ if ( NULL != regionData
+ && !regionData->NewRegion
+ && IsLegalDriveLetter(regionData->DriveLetter))
+ {
+ AllowFormat = TRUE;
+
+#ifdef WINDISK_EXTENSIONS
+ if (SingleVolumeSelected())
+ {
+ AllowExtensionItems = TRUE;
+ }
+#endif // WINDISK_EXTENSIONS
+ }
+
+ //
+ // If the region is recognized, then also allow drive letter
+ // manipulation.
+ //
+
+ if (IsRecognizedPartition(regionDescriptor->SysID))
+ {
+
+ //
+ // Not on removables though.
+ //
+
+ if (!IsDiskRemovable[regionDescriptor->Disk]) {
+ allowDriveLetter = TRUE;
+ }
+
+ DetermineRegionInfo(regionDescriptor,
+ &typeName,
+ &volumeLabel,
+ &driveLetter);
+
+ if (!IsExtraDriveLetter(driveLetter))
+ {
+ if (0 == lstrcmp(typeName, L"FAT"))
+ {
+ AllowVolumeOperations = AllowFormat;
+#if defined( DBLSPACE_ENABLED )
+ // DblSpace volumes are allowed on non-FT, FAT
+ // volumes only
+ allowDblSpace = AllowFormat;
+#endif // DBLSPACE_ENABLED
+ }
+
+ //BUGBUG: better way to determine if file system ops
+ //are allowed?
+ if ( (lstrcmp(typeName, L"NTFS") == 0)
+#ifdef SUPPORT_OFS
+ || (lstrcmp(typeName, L"OFS") == 0)
+#endif // SUPPORT_OFS
+ )
+ {
+ AllowVolumeOperations = AllowFormat;
+ }
+ }
+ }
+ }
+ }
+ else if (0 != SelectionCount)
+ {
+ *SinglySelectedDisk = NULL;
+ *SinglySelectedRegion = (DWORD)(-1);
+
+ //
+ // Multiple regions are selected. This might be an existing ft set,
+ // a set of regions that allow creation of an ft set, or just plain
+ // old multiple items.
+ //
+ // First deal with a selected ft set.
+ //
+
+ if (FtSetSelected)
+ {
+ regionDescriptor = &SELECTED_REGION(0);
+ regionData = PERSISTENT_DATA(regionDescriptor);
+
+ // Should locate member zero of the set since it may not be
+ // committed yet.
+
+ if (NULL != regionData)
+ {
+ if (!regionData->NewRegion)
+ {
+ if (!IsExtraDriveLetter(regionData->DriveLetter))
+ {
+ // Now check for special cases on FT sets
+
+ ftObject = regionData->FtObject;
+ if (NULL != ftObject)
+ {
+ ftSet = ftObject->Set;
+ if (NULL != ftSet)
+ {
+ FT_SET_STATUS setState = ftSet->Status;
+ ULONG numberOfMembers;
+
+ LowFtVolumeStatus(
+ regionDescriptor->Disk,
+ regionDescriptor->PartitionNumber,
+ &setState,
+ &numberOfMembers);
+
+ if ( (ftSet->Status != FtSetDisabled)
+ && (setState != FtSetDisabled))
+ {
+ AllowFormat = TRUE;
+ }
+ }
+ }
+ }
+
+ //BUGBUG: better way to determine if file system ops
+ //are allowed?
+ if (NULL != regionData->TypeName)
+ {
+ typeName = regionData->TypeName;
+ if ( (lstrcmp(typeName, L"NTFS") == 0)
+#ifdef SUPPORT_OFS
+ || (lstrcmp(typeName, L"OFS") == 0)
+#endif // SUPPORT_OFS
+ || (lstrcmp(typeName, L"FAT") == 0))
+ {
+ AllowVolumeOperations = AllowFormat;
+ }
+ }
+ else
+ {
+ typeName = NULL;
+ DetermineRegionInfo(regionDescriptor,
+ &typeName,
+ &volumeLabel,
+ &driveLetter);
+ if (NULL == typeName)
+ {
+ if (SelectionCount > 1)
+ {
+ // it is an FT set - try the next member.
+
+ regionDescriptor = &SELECTED_REGION(1);
+ DetermineRegionInfo(regionDescriptor,
+ &typeName,
+ &volumeLabel,
+ &driveLetter);
+ regionDescriptor = &SELECTED_REGION(0);
+ }
+ }
+
+ if ( (lstrcmp(regionData->TypeName, L"NTFS") == 0)
+#ifdef SUPPORT_OFS
+ || (lstrcmp(regionData->TypeName, L"OFS") == 0)
+#endif // SUPPORT_OFS
+ || (lstrcmp(regionData->TypeName, L"FAT") == 0))
+ {
+ AllowVolumeOperations = AllowFormat;
+ }
+ }
+ }
+ }
+
+#ifdef WINDISK_EXTENSIONS
+ if (AllowFormat && !regionData->NewRegion)
+ {
+ AllowExtensionItems = TRUE;
+ }
+#endif // WINDISK_EXTENSIONS
+
+ //
+ // allow the correct type of ft-related delete.
+ //
+
+ switch (FtSelectionType)
+ {
+ case Mirror:
+ allowDelete = TRUE;
+ allowBreakMirror = TRUE;
+ break;
+
+ case StripeWithParity:
+ ftObject = GET_FT_OBJECT(&SELECTED_REGION(0));
+ ftSet = ftObject->Set;
+ if ( SelectionCount == ftSet->NumberOfMembers
+ && (ftSet->Status == FtSetRecoverable))
+ {
+ // Are all members present?
+
+ allowRecoverParity = TRUE;
+ }
+ allowDelete = TRUE;
+ break;
+
+ case Stripe:
+ case VolumeSet:
+ allowDelete = TRUE;
+ break;
+
+ default:
+ FDASSERT(FALSE);
+ }
+
+ if (FtSelectionType == StripeWithParity)
+ {
+ // If the set is disabled, do not allow drive
+ // letter changes - This is done because there are
+ // conditions whereby the drive letter code will
+ // access violate if this is done.
+
+ if (ftSet->Status != FtSetDisabled)
+ {
+ // Must have either member 0 or member 1 for access
+
+ for (ftObject = ftSet->Members;
+ NULL != ftObject;
+ ftObject = ftObject->Next)
+ {
+ if ( (ftObject->MemberIndex == 0)
+ || (ftObject->MemberIndex == 1))
+ {
+ allowDriveLetter = TRUE;
+ break;
+ }
+ }
+
+ // if the drive letter cannot be done, then no live
+ // action can be done.
+
+ if (!allowDriveLetter)
+ {
+ ftSet->Status = FtSetDisabled;
+ AllowFormat = FALSE;
+ AllowVolumeOperations = FALSE;
+ }
+ }
+ }
+ else
+ {
+ allowDriveLetter = TRUE;
+ }
+ }
+ else
+ {
+ //
+ // Next figure out whether some sort of ft object set could
+ // be created out of the selected regions.
+ //
+
+ if (SelectionCount <= MAX_MEMBERS_IN_FT_SET)
+ {
+ //
+ // Determine whether the selected regions are all on
+ // different disks.
+ //
+
+ onDifferentDisks = TRUE;
+ for (i=0; i<DiskCount; i++)
+ {
+ if (DiskSeenCountArray[i] > 1)
+ {
+ onDifferentDisks = FALSE;
+ break;
+ }
+ }
+
+ //
+ // Check for allowing mirror creation. User must have
+ // selected two regions -- one a recognized partition,
+ // the other a free space.
+ //
+
+ if ( onDifferentDisks
+ && (SelectionCount == 2)
+ && ((SELECTED_REGION(0).SysID == PARTITION_ENTRY_UNUSED)
+ != (SELECTED_REGION(1).SysID == PARTITION_ENTRY_UNUSED))
+ && ( IsRecognizedPartition(SELECTED_REGION(0).SysID)
+ || IsRecognizedPartition(SELECTED_REGION(1).SysID))
+ && !GET_FT_OBJECT(&SELECTED_REGION(0))
+ && !GET_FT_OBJECT(&SELECTED_REGION(1)))
+ {
+ allowCreateMirror = TRUE;
+ }
+
+ //
+ // Check for allowing volume set or stripe set
+ //
+
+ if (SelectedFreeSpaces == SelectionCount)
+ {
+ allowCreateVolumeSet = TRUE;
+ if (onDifferentDisks)
+ {
+ allowCreateStripe = TRUE;
+ if (SelectedFreeSpaces > 2)
+ {
+ allowCreatePStripe = TRUE;
+ }
+ }
+ }
+
+ // Check for allowing volume set expansion. If
+ // the selected regions consist of one volume set
+ // and free space, then that volume set can be
+ // extended. If the selection consists of one
+ // recognized non-FT partition and free space,
+ // then we can convert those regions into a
+ // volume set.
+ //
+ if ( VolumeSetAndFreeSpaceSelected
+ || ( SelectionCount > 1
+ && SelectedFreeSpaces == SelectionCount - 1
+ && SelectedNonFtPartitions == 1) )
+ {
+ allowExtendVolumeSet = TRUE;
+ }
+
+ //
+ // If the ftselection type is non-zero then
+ // we have selection of ft partitions. However
+ // since it might not be the 0th one make sure
+ // to try the 1st.
+ //
+
+ if ((FtSelectionType == StripeWithParity) ||
+ (FtSelectionType == Mirror)) {
+
+ ftObject = GET_FT_OBJECT(&SELECTED_REGION(0));
+
+ if (ftObject == NULL) {
+
+ ftObject = GET_FT_OBJECT(&SELECTED_REGION(1));
+
+ }
+
+ }
+
+ //
+ // Check for allowing non-in-place FT recover
+ //
+
+ if ( (SelectionCount > 1)
+ && (SelectedFreeSpaces == 1)
+ && PossibleRecover
+ && (FtSelectionType == StripeWithParity)
+ && (NULL != ftObject)
+ && (NULL != (ftSet = ftObject->Set))
+ && (ftSet->Status == FtSetRecoverable))
+ {
+ BOOL orphanOnSameDiskAsFreeSpace = FALSE;
+
+ if (!onDifferentDisks)
+ {
+ //
+ // Determine whether the orphan is on the same
+ // disk as the free space. First find the orphan.
+ //
+
+ for (i=0; i<SelectionCount; i++)
+ {
+ PREGION_DESCRIPTOR reg = &SELECTED_REGION(i);
+
+ if ( (i != FreeSpaceIndex)
+ && (GET_FT_OBJECT(reg)->State == Orphaned))
+ {
+ if (SELECTED_REGION(FreeSpaceIndex).Disk == reg->Disk)
+ {
+ orphanOnSameDiskAsFreeSpace = TRUE;
+ }
+ break;
+ }
+ }
+ }
+
+ if (onDifferentDisks || orphanOnSameDiskAsFreeSpace)
+ {
+ allowRecoverParity = TRUE;
+ }
+ }
+
+ if ( (SelectionCount == 2)
+ && (SelectedFreeSpaces == 1)
+ && PossibleRecover
+ && (FtSelectionType == Mirror)
+ && (NULL != (ftObject = GET_FT_OBJECT(&SELECTED_REGION(0))))
+ && (NULL != (ftSet = ftObject->Set))
+ && (ftSet->Status == FtSetRecoverable))
+ {
+ BOOL orphanOnSameDiskAsFreeSpace = FALSE;
+
+ if (!onDifferentDisks)
+ {
+ //
+ // Determine whether the orphan is on the same
+ // disk as the free space. First find the orphan.
+ //
+
+ for (i=0; i<SelectionCount; i++)
+ {
+ PREGION_DESCRIPTOR reg = &SELECTED_REGION(i);
+
+ if ( (i != FreeSpaceIndex)
+ && (GET_FT_OBJECT(reg)->State == Orphaned))
+ {
+ if (SELECTED_REGION(FreeSpaceIndex).Disk == reg->Disk)
+ {
+ orphanOnSameDiskAsFreeSpace = TRUE;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //
+ // Formattabilty is akin to propertibility. (That and explorer lets you see
+ // the properties).
+ //
+
+ if (AllowFormat)
+ {
+ allowProperties = TRUE;
+ }
+
+ if (RegistryChanged || CommitAllowed())
+ {
+ allowCommit = TRUE;
+ }
+
+ //
+ // Now that we've determined whether to allow or disallow all commands,
+ // enable or disable each access method to those commands.
+ //
+
+ HMENU hMenu = GetMenu(g_hwndFrame);
+
+//
+// Volume menu
+//
+ //
+ // Change the "format" entry to be either "format" or "change
+ // format" based on whether the selection is unformatted or not
+ // (respectively)
+ //
+
+ WCHAR formatTextBuffer[MAX_RESOURCE_STRING_LEN];
+
+ if ( AllowFormat
+ && SingleVolumeSelected()
+ && IsVolumeFormatted(&SELECTED_REGION(0)))
+ {
+ LoadString(
+ g_hInstance,
+ IDS_CHANGEFORMAT,
+ formatTextBuffer,
+ ARRAYLEN(formatTextBuffer));
+ }
+ else
+ {
+ LoadString(
+ g_hInstance,
+ IDS_FORMAT,
+ formatTextBuffer,
+ ARRAYLEN(formatTextBuffer));
+ }
+
+ ModifyMenu(
+ hMenu,
+ IDM_VOL_FORMAT,
+ MF_BYCOMMAND | MF_STRING,
+ IDM_VOL_FORMAT,
+ formatTextBuffer);
+
+ EnableMenuItem(hMenu,
+ IDM_VOL_FORMAT,
+ AllowFormat ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem(hMenu, IDM_VOL_EJECT, allowEject ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem(hMenu,
+ IDM_VOL_LETTER,
+ allowDriveLetter ? MF_ENABLED : MF_GRAYED);
+
+#if defined( DBLSPACE_ENABLED )
+ EnableMenuItem(hMenu,
+ IDM_VOL_DBLSPACE,
+ (allowDblSpace && g_DoubleSpaceSupported)
+ ? MF_ENABLED : MF_GRAYED);
+
+ DoubleSpaceAutomount = DiskRegistryAutomountCurrentState();
+
+ if (DoubleSpaceAutomount)
+ {
+ CheckMenuItem(hMenu, IDM_VOL_AUTOMOUNT, MF_BYCOMMAND | MF_CHECKED);
+ }
+
+ EnableMenuItem(hMenu,
+ IDM_VOL_AUTOMOUNT,
+ MF_ENABLED);
+#endif // DBLSPACE_ENABLED
+
+ EnableMenuItem(hMenu,
+ IDM_VOL_PROPERTIES,
+ allowProperties ? MF_ENABLED : MF_GRAYED);
+
+//
+// Partition menu
+//
+
+ EnableMenuItem(hMenu,
+ IDM_PARTITIONCREATE,
+ allowCreate ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem(hMenu,
+ IDM_PARTITIONCREATEEX,
+ allowCreateEx ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem(hMenu,
+ IDM_PARTITIONDELETE,
+ allowDelete ? MF_ENABLED : MF_GRAYED);
+
+#if i386
+ SetUpMenui386(hMenu);
+#else
+ EnableMenuItem(hMenu,
+ IDM_SECURESYSTEM,
+ MF_ENABLED);
+
+ CheckMenuItem(hMenu,
+ IDM_SECURESYSTEM,
+ SystemPartitionIsSecure ? MF_CHECKED : MF_UNCHECKED);
+#endif
+
+ EnableMenuItem(hMenu,
+ IDM_PARTITIONCOMMIT,
+ allowCommit ? MF_ENABLED : MF_GRAYED);
+
+//
+// Fault Tolerance menu
+//
+
+ EnableMenuItem(hMenu,
+ IDM_FTBREAKMIRROR,
+ allowBreakMirror ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem(hMenu,
+ IDM_FTESTABLISHMIRROR,
+ g_IsLanmanNt &&
+ allowCreateMirror ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem(hMenu,
+ IDM_FTCREATESTRIPE,
+ allowCreateStripe ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem(hMenu,
+ IDM_FTCREATEPSTRIPE,
+ allowCreatePStripe ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem(hMenu,
+ IDM_FTCREATEVOLUMESET,
+ allowCreateVolumeSet ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem(hMenu,
+ IDM_FTEXTENDVOLUMESET,
+ allowExtendVolumeSet ? MF_ENABLED : MF_GRAYED);
+
+ EnableMenuItem(hMenu,
+ IDM_FTRECOVERSTRIPE,
+ g_IsLanmanNt &&
+ allowRecoverParity ? MF_ENABLED : MF_GRAYED);
+
+
+ EnableMenuItem(hMenu,
+ IDM_OPTIONSCOLORS,
+ g_WhichView == VIEW_VOLUMES ? MF_GRAYED : MF_ENABLED);
+
+ EnableMenuItem(hMenu,
+ IDM_OPTIONSDISK,
+ g_WhichView == VIEW_VOLUMES ? MF_GRAYED : MF_ENABLED);
+
+ EnableMenuItem(hMenu,
+ IDM_OPTIONSDISPLAY,
+ g_WhichView == VIEW_VOLUMES ? MF_GRAYED : MF_ENABLED);
+
+ ///////////////////////////////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////
+
+#ifdef WINDISK_EXTENSIONS
+
+ BOOL fAnyVolExtensionItems = FALSE;
+
+ HMENU hmenuVolume = GetSubMenu(hMenu, 0);
+
+ //
+ // erase the dictionary of context menu command identifiers
+ //
+
+ MenuItems.DeAllocateMenuIds();
+
+ //
+ // Delete the extension items on the menu bar
+ //
+
+ while (g_uItemInsertHere > UITEM_INSERT_HERE)
+ {
+ DeleteMenu(hmenuVolume, --g_uItemInsertHere, MF_BYPOSITION);
+ }
+
+ //
+ // Determine if there are any context menu items drawn from extension
+ // classes (based on previous claiming). Only allow extension items on
+ // pre-existing volumes or disks, for single selection.
+ //
+
+ if (AllowExtensionItems)
+ {
+ regionDescriptor = &SELECTED_REGION(0);
+ WCHAR driveLetter = PERSISTENT_DATA(regionDescriptor)->DriveLetter;
+
+ if (IsLegalDriveLetter(driveLetter))
+ {
+ unsigned driveIndex = DriveLetterToIndex(driveLetter);
+
+ //
+ // add the volume extension items
+ //
+
+ if (NULL != VolumeInfo[driveIndex].VolClaims)
+ {
+ fAnyVolExtensionItems = TRUE;
+ }
+
+ if (fAnyVolExtensionItems)
+ {
+ unsigned index = DriveLetterToIndex(driveLetter);
+ PVOL_CLAIM_LIST volClaims = VolumeInfo[index].VolClaims;
+ while (NULL != volClaims)
+ {
+ AddExtensionItemsToMenu(
+ hmenuVolume,
+ &(volClaims->pClaimer->pInfo->mnuOps),
+ AllowExtensionItems ? MF_ENABLED : MF_GRAYED
+ );
+
+ volClaims = volClaims->pNext;
+ }
+ }
+ }
+ }
+
+#endif // WINDISK_EXTENSIONS
+
+ //////////////////////////////////////////////////////////////////////////
+
+ SetToolbarButtonState();
+
+ //////////////////////////////////////////////////////////////////////////
+
+ return SelectionCount + CdRomSelectionCount;
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: SetDriveLetterInfo
+//
+// Synopsis: After we get the partition information for a disk, the
+// partition number might have changed, so reset our Drive Letter
+// knowledge.
+//
+// Arguments: [DiskNum] -- The disk number
+//
+// Returns: nothing
+//
+// History: 24-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+SetDriveLetterInfo(
+ IN UINT DiskNum
+ )
+{
+ PDISKSTATE diskState = DiskArray[DiskNum];
+
+ for (ULONG i=0; i<diskState->RegionCount; i++)
+ {
+ PREGION_DESCRIPTOR regionDescriptor = &diskState->RegionArray[i];
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(regionDescriptor);
+
+ if (regionData && !regionData->NewRegion)
+ {
+ NewDriveLetter(
+ regionData->DriveLetter,
+ DiskNum,
+ regionDescriptor->PartitionNumber
+ );
+ }
+ }
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: TotalRedraw
+//
+// Synopsis: Redraws the entire disks view
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 1-Mar-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+TotalRedraw(
+ VOID
+ )
+{
+ ULONG i;
+
+ for (i=0; i<DiskCount; i++)
+ {
+ DrawDiskBar(DiskArray[i]);
+ }
+
+ for (i=0; i<CdRomCount; i++)
+ {
+ DrawCdRomBar(i);
+ }
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: RedrawSelectedBars
+//
+// Synopsis: Redraws bars that form part of the current selection
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 1-Mar-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+RedrawSelectedBars(
+ VOID
+ )
+{
+ ULONG i;
+
+ for (i=0; i<DiskCount; i++)
+ {
+ if (DiskSeenCountArray[i] > 0)
+ {
+ DrawDiskBar(DiskArray[i]);
+ }
+ }
+
+ for (i=0; i<CdRomCount; i++)
+ {
+ if (CdRomArray[i].Selected)
+ {
+ DrawCdRomBar(i);
+ }
+ }
+}
+
+
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: TotalRedrawAndRepaint
+//
+// Synopsis: Redraws and repaints the entire disks view
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+TotalRedrawAndRepaint(
+ VOID
+ )
+{
+ TotalRedraw();
+ ForceLBRedraw(); // a repaint
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DmAllocatePersistentData
+//
+// Synopsis: Allocate a structure to hold persistent region data. Fill
+// in the volume label, type name, and drive letter. The volume
+// label and type name are duplicated.
+//
+// Arguments:
+//
+// [FtObject] -- the FT object, or NULL if this region isn't in
+// an FT set.
+//
+// [VolumeLabel] -- volume label to be stored in the the persistent data.
+// The string will be duplicated first and a pointer to the duplicate
+// copy is what is stored in the persistent data. May be NULL.
+//
+// [TypeName] -- name of type of region, ie unformatted, FAT, etc.
+// May be NULL.
+//
+// [DriveLetter] -- drive letter to be stored in persistent data
+//
+// [NewRegion] -- TRUE if this is a newly created region
+//
+// Returns: Pointer to newly allocated persistent data structure. The
+// structure may be freed via DmFreePersistentData(), below.
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+PPERSISTENT_REGION_DATA
+DmAllocatePersistentData(
+ IN PFT_OBJECT FtObject,
+ IN PWSTR VolumeLabel,
+ IN PWSTR TypeName,
+ IN WCHAR DriveLetter,
+ IN BOOL NewRegion,
+ IN LARGE_INTEGER FreeSpaceInBytes,
+ IN LARGE_INTEGER TotalSpaceInBytes
+ )
+{
+ PWSTR volumeLabel = NULL;
+ PWSTR typeName = NULL;
+
+ if (VolumeLabel)
+ {
+ volumeLabel = (PWSTR)Malloc((lstrlen(VolumeLabel)+1)*sizeof(WCHAR));
+ lstrcpy(volumeLabel, VolumeLabel);
+ }
+
+ if (TypeName)
+ {
+ typeName = (PWSTR)Malloc((lstrlen(TypeName)+1)*sizeof(WCHAR));
+ lstrcpy(typeName, TypeName);
+ }
+
+ PPERSISTENT_REGION_DATA regionData
+ = (PPERSISTENT_REGION_DATA)Malloc(sizeof(PERSISTENT_REGION_DATA));
+
+ DmInitPersistentRegionData(
+ regionData,
+ FtObject,
+ volumeLabel,
+ typeName,
+ DriveLetter,
+ NewRegion,
+ FreeSpaceInBytes,
+ TotalSpaceInBytes
+ );
+
+ return regionData;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DmFreePersistentData
+//
+// Synopsis: Free a persistent data structure and storage used for
+// volume label and type name (does not free ft objects).
+//
+// Arguments: [RegionData] -- structure to be freed.
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DmFreePersistentData(
+ IN OUT PPERSISTENT_REGION_DATA RegionData
+ )
+{
+ if (RegionData->VolumeLabel)
+ {
+ Free(RegionData->VolumeLabel);
+ }
+ if (RegionData->TypeName)
+ {
+ Free(RegionData->TypeName);
+ }
+
+ Free(RegionData);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: ChangeView
+//
+// Synopsis: Toggle the view between the volumes and disks view
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+ChangeView(
+ VOID
+ )
+{
+ SetCursor(g_hCurWait);
+
+ //
+ // 'g_WhichView' is set to the new view
+ //
+
+ MyCheckMenuItem(
+ g_hmenuFrame,
+ IDM_VIEWVOLUMES,
+ IDM_VIEWDISKS,
+ (g_WhichView == VIEW_VOLUMES) ? IDM_VIEWVOLUMES : IDM_VIEWDISKS
+ );
+
+ switch (g_WhichView)
+ {
+ case VIEW_VOLUMES:
+ ChangeToVolumesView();
+ break;
+
+ case VIEW_DISKS:
+ ChangeToDisksView();
+ break;
+
+ default:
+ FDASSERT(0);
+ }
+
+#if DBG == 1
+ if (BothViews)
+ {
+ ShowWindow(g_hwndList, SW_SHOW);
+ ShowWindow(g_hwndLV, SW_SHOW);
+ EnableMenuItem(g_hmenuFrame,IDM_OPTIONSLEGEND,MF_BYCOMMAND|MF_ENABLED);
+ }
+#endif // DBG == 1
+
+ RECT rc;
+ GetClientRect(g_hwndFrame, &rc);
+
+ // Send a WM_SIZE message to force recalculation of the size of various
+ // child windows and spaces based on the new view options. E.g., changing
+ // to volumes view from disks view forces legend to disappear.
+
+ SendMessage(g_hwndFrame, WM_SIZE, SIZE_RESTORED, MAKELONG(rc.right, rc.bottom));
+ InvalidateRect(g_hwndFrame, NULL, TRUE);
+
+ SetCursor(g_hCurNormal);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: AdjustOptionsMenu
+//
+// Synopsis: Set the options menu to be consistent with the tool state
+//
+// Arguments: (none)
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+AdjustOptionsMenu(
+ VOID
+ )
+{
+ CheckMenuItem(g_hmenuFrame,
+ IDM_OPTIONSTOOLBAR,
+ MF_BYCOMMAND | (g_Toolbar ? MF_CHECKED : MF_UNCHECKED)
+ );
+
+ CheckMenuItem(g_hmenuFrame,
+ IDM_OPTIONSSTATUS,
+ MF_BYCOMMAND | (g_StatusBar ? MF_CHECKED : MF_UNCHECKED)
+ );
+
+ CheckMenuItem(g_hmenuFrame,
+ IDM_OPTIONSLEGEND,
+ MF_BYCOMMAND | (g_Legend ? MF_CHECKED : MF_UNCHECKED)
+ );
+
+ RECT rc;
+ GetClientRect(g_hwndFrame, &rc);
+
+ // Send a WM_SIZE message to force recalculation of the size of various
+ // child windows and spaces based on the new set of options
+
+ SendMessage(g_hwndFrame, WM_SIZE, SIZE_RESTORED, MAKELONG(rc.right, rc.bottom));
+ InvalidateRect(g_hwndFrame, NULL, TRUE);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: PaintStatusBar
+//
+// Synopsis: Paint the status bar
+//
+// Arguments: [hwnd] -- window to paint to
+// [pps] -- the paint structure returned by BeginPaint
+// [prc] -- the rectangle for the entire frame. Paint at
+// the bottom of it.
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+PaintStatusBar(
+ IN HWND hwnd,
+ IN PAINTSTRUCT* pps,
+ IN PRECT prc
+ )
+{
+ if (g_fDoingMenuHelp)
+ {
+ return; // don't paint the status bar if we're showing menu help
+ }
+
+ HDC hdcTemp, hdcScr;
+ HBITMAP hbmTemp;
+ HBRUSH hBrush;
+ HFONT hFontOld;
+ RECT rcTemp;
+ RECT rc;
+ DWORD dxSeparation;
+
+ rc = *prc;
+ hdcScr = pps->hdc;
+
+ rc.top = rc.bottom - g_dyStatus;
+
+ hdcTemp = CreateCompatibleDC(hdcScr);
+ hbmTemp = CreateCompatibleBitmap(
+ hdcScr,
+ rc.right - rc.left,
+ rc.bottom - rc.top
+ );
+ SelectBitmap(hdcTemp, hbmTemp);
+
+ // adjust position for off-screen bitmap
+
+ rcTemp = rc;
+ rc.bottom -= rc.top;
+ rc.top = 0;
+
+ hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
+ if (hBrush)
+ {
+ FillRect(hdcTemp, &rc, hBrush);
+ DeleteBrush(hBrush);
+ }
+
+ // draw the status bar at the bottom of the window
+
+ hFontOld = SelectFont(hdcTemp, g_hFontStatus);
+
+ //
+ // There are 5 status items, drawn in this order:
+ //
+ // description example
+ // ----------- -------
+ // Status text Stripe set #0
+ // size 51 MB
+ // file system type FAT
+ // drive letter F:
+ // volume label MYVOLUME
+ //
+ // All except drive letter are proportional to the window width.
+ //
+
+ // Separation between status elements, and between a status element
+ // and the window border
+ dxSeparation = 8 * g_dyBorder;
+
+ // Status text
+ rc.left = dxSeparation;
+ rc.right = 2 * GraphWidth / 5;
+ DrawStatusAreaItem(&rc, hdcTemp, StatusTextStat);
+
+ // size
+ rc.left = rc.right + dxSeparation;
+ rc.right = rc.left + (GraphWidth / 9);
+ DrawStatusAreaItem(&rc, hdcTemp, StatusTextSize);
+
+ // type
+ rc.left = rc.right + dxSeparation;
+ rc.right = rc.left + (GraphWidth / 5);
+ DrawStatusAreaItem(&rc, hdcTemp, StatusTextType);
+
+ // drive letter
+ rc.left = rc.right + dxSeparation;
+ rc.right = rc.left + dxDriveLetterStatusArea;
+ DrawStatusAreaItem(&rc, hdcTemp, StatusTextDrlt);
+
+ // vol label
+ rc.left = rc.right + dxSeparation;
+ rc.right = GraphWidth - dxSeparation;
+ DrawStatusAreaItem(&rc, hdcTemp, StatusTextVoll);
+
+ BitBlt(hdcScr,
+ rcTemp.left,
+ rcTemp.top,
+ rcTemp.right-rcTemp.left+1,
+ rcTemp.bottom-rcTemp.top+1,
+ hdcTemp,
+ 0,
+ 0,
+ SRCCOPY
+ );
+
+ if (hFontOld)
+ {
+ SelectFont(hdcTemp, hFontOld);
+ }
+ DeleteDC(hdcTemp);
+ DeleteBitmap(hbmTemp);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: PaintLegend
+//
+// Synopsis: Paint the legend
+//
+// Arguments: [hwnd] -- window to paint to
+// [pps] -- the paint structure returned by BeginPaint
+// [prc] -- the rectangle for the entire frame. Paint at
+// the bottom of it.
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+PaintLegend(
+ IN HWND hwnd,
+ IN PAINTSTRUCT* pps,
+ IN PRECT prc
+ )
+{
+ HDC hdcScr = pps->hdc;
+ RECT rc = *prc;
+
+ // draw the legend onto the screen
+
+ rc.top = rc.bottom - g_dyLegend;
+ DrawLegend(hdcScr, &rc);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: PaintVolumesView
+//
+// Synopsis: Paint the volumes view: Handle WM_PAINT for the volumes view
+//
+// Arguments: standard Windows procedure arguments for WM_PAINT
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+PaintVolumesView(
+ IN HWND hwnd,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ HDC hdcScr;
+ PAINTSTRUCT ps;
+ HBRUSH hBrush;
+ RECT rc;
+
+ hdcScr = BeginPaint(hwnd, &ps);
+
+ GetClientRect(hwnd, &rc);
+
+ if (g_Toolbar)
+ {
+ //
+ // The toolbar is a control; it paints itself
+ //
+
+ rc.top += g_dyToolbar;
+ }
+
+ if (g_StatusBar)
+ {
+ PaintStatusBar(hwnd, &ps, &rc);
+ rc.bottom -= g_dyStatus;
+ }
+
+ EndPaint(hwnd, &ps);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: PaintDisksView
+//
+// Synopsis: Paint the disks view: Handle WM_PAINT for the disks view
+//
+// Arguments: standard Windows procedure arguments for WM_PAINT
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+PaintDisksView(
+ IN HWND hwnd,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ HDC hdcScr;
+ PAINTSTRUCT ps;
+ HBRUSH hBrush;
+ RECT rc;
+
+ hdcScr = BeginPaint(hwnd, &ps);
+
+ GetClientRect(hwnd, &rc);
+
+ if (g_Toolbar)
+ {
+ //
+ // The toolbar is a control; it paints itself
+ //
+
+ rc.top += g_dyToolbar;
+ }
+
+ if (g_StatusBar)
+ {
+ PaintStatusBar(hwnd, &ps, &rc);
+ rc.bottom -= g_dyStatus;
+ }
+
+ if (g_Legend)
+ {
+ PaintLegend(hwnd, &ps, &rc);
+ rc.bottom -= g_dyLegend;
+ }
+
+ //
+ // dark line across top of status/legend area, and across bottom of
+ // toolbar.
+ //
+
+ if (g_StatusBar || g_Legend || g_Toolbar)
+ {
+ if (NULL != (hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNTEXT))))
+ {
+ RECT rcT;
+
+ if (g_StatusBar || g_Legend)
+ {
+ rcT = rc;
+ rcT.top = rcT.bottom - g_dyBorder; // the thickness of the line
+ FillRect(hdcScr, &rcT, hBrush);
+ }
+
+ if (g_Toolbar)
+ {
+ rcT = rc;
+ rcT.bottom = rcT.top + g_dyBorder; // the thickness of the line
+ FillRect(hdcScr, &rcT, hBrush);
+ }
+
+ DeleteBrush(hBrush);
+ }
+ }
+
+ EndPaint(hwnd, &ps);
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: FrameCreateHandler
+//
+// Synopsis: Handle WM_CREATE for the frame window
+//
+// Arguments: standard Windows procedure arguments for WM_CREATE
+//
+// Returns: standard Windows procedure arguments for WM_CREATE
+//
+// History: 9-Oct-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+LRESULT
+FrameCreateHandler(
+ IN HWND hwnd,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ HMENU hMenu;
+
+ //BUGBUG: huh?
+ if (!g_StartedAsIcon)
+ {
+ g_StartedAsIcon = IsIconic(hwnd);
+ }
+
+ g_hmenuFrame = GetMenu(hwnd);
+
+ g_hwndList = CreateWindow(
+ TEXT("listbox"),
+ NULL,
+ WS_CHILD
+ | WS_VSCROLL
+ | LBS_NOTIFY
+ | LBS_NOINTEGRALHEIGHT
+ | LBS_OWNERDRAWFIXED,
+ 0, 0, 0, 0,
+ hwnd,
+ (HMENU)ID_LISTBOX,
+ g_hInstance,
+ NULL
+ );
+
+ if (NULL == g_hwndList)
+ {
+ daDebugOut((DEB_ERROR,
+ "CreateWindow for listbox failed, error = 0x%x\n",
+ GetLastError()
+ ));
+
+ return -1; // fail window creation & exit Disk Admin
+ }
+
+ // subclass the listbox so we can handle keyboard
+ // input our way.
+
+ SubclassListBox(g_hwndList);
+
+ //
+ // Create the listview (volumes view)
+
+ g_hwndLV = CreateWindowEx(
+ WS_EX_CLIENTEDGE,
+ WC_LISTVIEW,
+ NULL,
+ WS_CHILD
+ | WS_BORDER //BUGBUG: needed?
+ | LVS_REPORT
+ | LVS_SINGLESEL
+ | LVS_SHOWSELALWAYS
+ | LVS_SHAREIMAGELISTS
+ ,
+ 0, 0, 0, 0,
+ hwnd,
+ (HMENU)ID_LISTVIEW,
+ g_hInstance,
+ NULL
+ );
+
+ if (NULL == g_hwndLV)
+ {
+ daDebugOut((DEB_ERROR,
+ "CreateWindow for listview failed, error = 0x%x\n",
+ GetLastError()
+ ));
+
+ return -1; // fail window creation & exit Disk Admin
+ }
+
+ //
+ // Create the toolbar
+ //
+
+ CreateDAToolbar(hwnd);
+
+ //
+ // If we are not running the LanmanNt version of
+ // Windisk, remove the Fault-Tolerance menu item.
+ //
+ if (!g_IsLanmanNt && (hMenu = GetMenu(hwnd)) != NULL)
+ {
+ DeleteMenu(hMenu, FT_MENU_INDEX, MF_BYPOSITION);
+ DrawMenuBar(hwnd);
+ }
+
+ //
+ // initialize the status bar strings
+ //
+
+ StatusTextDrlt[0]
+ = StatusTextStat[0]
+ = StatusTextSize[0]
+ = StatusTextType[0]
+ = StatusTextVoll[0]
+ = L'\0';
+
+ return 0; // window was created fine
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: FrameResizeHandler
+//
+// Synopsis: Handle WM_SIZE for the frame window
+//
+// Arguments: standard Windows procedure arguments for WM_SIZE
+//
+// Returns: standard Windows procedure arguments for WM_SIZE
+//
+// History: 9-Oct-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+LRESULT
+FrameResizeHandler(
+ IN HWND hwnd,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ RECT rc, rcT;
+
+ GetClientRect(hwnd, &rc);
+
+ DWORD newGraphWidth = rc.right - rc.left;
+
+ CalculateLegendHeight(newGraphWidth);
+
+#if DBG == 1
+ if (!BothViews)
+ {
+#endif // DBG == 1
+
+ //
+ // resize the listbox (disks view)
+ //
+
+ rcT = rc;
+ rcT.top = rc.top
+ + (g_Toolbar ? g_dyToolbar : 0)
+ + (g_Toolbar ? g_dyBorder : 0)
+ // if tool bar, space for a line
+ ;
+ rcT.bottom = rc.bottom
+ - (g_StatusBar ? g_dyStatus : 0)
+ - (g_Legend ? g_dyLegend : 0)
+ - ( (g_StatusBar || g_Legend) ? g_dyBorder : 0)
+ // if stat bar or legend, space for a line
+ ;
+
+ MoveWindow(
+ g_hwndList,
+ rcT.left,
+ rcT.top,
+ rcT.right - rcT.left,
+ rcT.bottom - rcT.top,
+ TRUE);
+
+ //
+ // resize the listview
+ //
+
+ rcT = rc;
+ rcT.top = rc.top
+ + (g_Toolbar ? g_dyToolbar : 0)
+ ;
+ rcT.bottom = rc.bottom
+ - (g_StatusBar ? g_dyStatus : 0)
+ //note: no legend in volumes view
+ ;
+
+ MoveWindow(
+ g_hwndLV,
+ rcT.left,
+ rcT.top,
+ rcT.right - rcT.left,
+ rcT.bottom - rcT.top,
+ TRUE);
+
+#if DBG == 1
+ }
+#endif // DBG == 1
+
+#if DBG == 1
+ if (BothViews)
+ {
+ // put both disks view and volumes view on same screen
+
+ rcT = rc;
+ rcT.top = rc.top
+ + (g_Toolbar ? g_dyToolbar : 0)
+ + (g_Toolbar ? g_dyBorder : 0)
+ // if tool bar, space for a line
+ ;
+ rcT.bottom = rc.bottom
+ - (g_StatusBar ? g_dyStatus : 0)
+ - (g_Legend ? g_dyLegend : 0)
+ - ( (g_StatusBar || g_Legend) ? g_dyBorder : 0)
+ // if stat bar or legend, space for a line
+ ;
+
+ RECT rcT2;
+
+ rcT2 = rcT;
+ rcT2.bottom -= (rcT.bottom - rcT.top) / 2;
+
+ MoveWindow(
+ g_hwndList,
+ rcT2.left,
+ rcT2.top,
+ rcT2.right - rcT2.left,
+ rcT2.bottom - rcT2.top,
+ TRUE);
+
+ rcT2.top = rcT2.bottom;
+ rcT2.bottom = rcT.bottom;
+
+ MoveWindow(
+ g_hwndLV,
+ rcT2.left,
+ rcT2.top,
+ rcT2.right - rcT2.left,
+ rcT2.bottom - rcT2.top,
+ TRUE);
+ }
+#endif // DBG == 1
+
+ //
+ // resize the toolbar
+ //
+
+ if (g_Toolbar)
+ {
+ // forward the message to the toolbar: it resizes itself
+ SendMessage(g_hwndToolbar, WM_SIZE, wParam, lParam);
+ }
+
+ //
+ // Invalidate status/legend area so that the clipping
+ // rectangle is right for redraws. Also invalidate the line, if it
+ // exists, below the toolbar.
+ //
+
+ // first, do the status/legend
+
+ rcT = rc;
+ rcT.top = rcT.bottom;
+
+ if (g_StatusBar)
+ {
+ rcT.top -= g_dyStatus;
+ }
+
+ if ( g_Legend && (g_WhichView == VIEW_DISKS) )
+ {
+ rcT.top -= g_dyLegend;
+ }
+
+#if DBG == 1
+ if (BothViews)
+ {
+ if ( g_Legend && (g_WhichView != VIEW_DISKS) )
+ {
+ rcT.top -= g_dyLegend;
+ }
+ }
+#endif // DBG == 1
+
+ if (rcT.top != rcT.bottom)
+ {
+ // there was either a status or a legend
+
+ rcT.top -= g_dyBorder; // adjust for the border line
+
+ InvalidateRect(hwnd, &rcT, FALSE); // get WM_PAINT for status/legend
+ }
+
+ // now, do the line under the toolbar
+
+ if (g_Toolbar && (g_WhichView == VIEW_DISKS))
+ {
+ rcT = rc;
+ rcT.top += g_dyToolbar;
+ rcT.bottom = rcT.top + g_dyBorder;
+ InvalidateRect(hwnd, &rcT, FALSE); // get WM_PAINT for toolbar line
+ }
+
+ //
+ // Recalculate the window width, and re-allocate off-screen bitmaps
+ //
+
+ if (GraphWidth != newGraphWidth)
+ {
+ GraphWidth = newGraphWidth;
+
+ BarWidth = GraphWidth - BarWidthMargin;
+
+ // create a memory DC for drawing the bar off-screen,
+ // and the correct bitmap
+
+ PDISKSTATE diskState;
+ PCDROM_DESCRIPTOR cdrom;
+ ULONG i;
+
+ HDC hDCFrame = GetDC(g_hwndFrame);
+ HDC hDCMem;
+
+ for (i=0; i<DiskCount; i++)
+ {
+ diskState = DiskArray[i];
+ if (NULL != diskState->hDCMem)
+ {
+ DeleteDC(diskState->hDCMem);
+ }
+ if (NULL != diskState->hbmMem)
+ {
+ DeleteBitmap(diskState->hbmMem);
+ }
+
+ diskState->hDCMem = hDCMem = CreateCompatibleDC(hDCFrame);
+ diskState->hbmMem = CreateCompatibleBitmap(
+ hDCFrame,
+ GraphWidth,
+ GraphHeight);
+
+ SelectBitmap(hDCMem, diskState->hbmMem);
+
+ //
+ // since the bitmap/DC has changed, we need to redraw it
+ //
+
+ DrawDiskBar(diskState);
+ }
+
+ for (i=0; i<CdRomCount; i++)
+ {
+ cdrom = CdRomFindDevice(i);
+
+ if (NULL != cdrom->hDCMem)
+ {
+ DeleteDC(cdrom->hDCMem);
+ }
+ if (NULL != cdrom->hbmMem)
+ {
+ DeleteBitmap(cdrom->hbmMem);
+ }
+
+ cdrom->hDCMem = hDCMem = CreateCompatibleDC(hDCFrame);
+ cdrom->hbmMem = CreateCompatibleBitmap(
+ hDCFrame,
+ GraphWidth,
+ GraphHeight);
+
+ SelectBitmap(hDCMem, cdrom->hbmMem);
+
+ //
+ // since the bitmap/DC has changed, we need to redraw it
+ //
+
+ DrawCdRomBar(i);
+ }
+ }
+
+ return (LRESULT)0; // message processed
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: FramePaintHandler
+//
+// Synopsis: Handle WM_PAINT for the frame window
+//
+// Arguments: standard Windows procedure arguments for WM_PAINT
+//
+// Returns: standard Windows procedure arguments for WM_PAINT
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+LRESULT
+FramePaintHandler(
+ IN HWND hwnd,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ if (IsIconic(hwnd))
+ {
+ return 0; // no painting necessary if we're iconic
+ }
+
+ if ((NULL != g_InitDlg) && g_StartedAsIcon)
+ {
+ return 0; // there is an initialization dialog still visible
+ }
+
+#if DBG == 1
+
+ if (BothViews)
+ {
+ PaintDisksView(hwnd, wParam, lParam);
+ return 0;
+ }
+
+#endif // DBG == 1
+
+ switch (g_WhichView)
+ {
+ case VIEW_VOLUMES:
+
+ PaintVolumesView(hwnd, wParam, lParam);
+ break;
+
+ case VIEW_DISKS:
+
+ PaintDisksView(hwnd, wParam, lParam);
+ break;
+
+ default:
+
+ FDASSERT(0);
+ }
+
+ if (NULL != g_InitDlg)
+ {
+ if (g_InitDlgComplete)
+ {
+ PostMessage(g_InitDlg, WM_STARTUP_END, 0, 0);
+ g_InitDlg = NULL;
+ }
+
+ if (g_oneTime)
+ {
+ if (!g_StartedAsIcon)
+ {
+ SetForegroundWindow(hwnd);
+ }
+ g_oneTime = FALSE;
+ }
+ }
+
+ return 0;
+}
+
+VOID
+DoEject(
+ IN HWND hwnd
+ )
+
+/*++
+
+Routine Description:
+
+ This routine ejects the selected disk.
+
+Arguments:
+
+ hwnd - Supplies a handle to the frame window.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ WCHAR deviceName[100];
+ UINT oldErrorMode;
+
+ if (0 == (SelectionCount + CdRomSelectionCount)) {
+ return; // nothing selected
+ }
+
+ deviceName[0] = '\\';
+ deviceName[1] = '\\';
+ deviceName[2] = '.';
+ deviceName[3] = '\\';
+ deviceName[5] = ':';
+ deviceName[6] = 0;
+
+ oldErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS);
+
+ if (CdRomSelected) {
+
+ PCDROM_DESCRIPTOR cdrom;
+ ULONG i;
+ HANDLE handle;
+ DWORD bytes;
+
+ for (i = 0; i < CdRomCount; i++) {
+ cdrom = CdRomFindDevice(i);
+ if (cdrom->Selected) {
+
+ deviceName[4] = cdrom->DriveLetter;
+ handle = CreateFile(deviceName, GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ 0, OPEN_EXISTING, 0, 0);
+ if (handle == INVALID_HANDLE_VALUE) {
+ SetErrorMode(oldErrorMode);
+ return;
+ }
+
+ DeviceIoControl(handle, IOCTL_DISK_EJECT_MEDIA, 0, 0, 0, 0,
+ &bytes, 0);
+
+ CloseHandle(handle);
+ break;
+ }
+ }
+
+ } else if (SelectionCount == 1) {
+
+ PREGION_DESCRIPTOR regionDescriptor = &SELECTED_REGION(0);
+ FDASSERT(regionDescriptor);
+ HANDLE handle;
+ DWORD bytes;
+ PREVENT_MEDIA_REMOVAL pmr;
+
+ if (regionDescriptor->PersistentData) {
+ deviceName[4] = regionDescriptor->PersistentData->DriveLetter;
+ } else {
+ wsprintf(deviceName, L"\\\\.\\PhysicalDrive%d",
+ regionDescriptor->Disk);
+ }
+
+ handle = CreateFile(deviceName, GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, 0,
+ OPEN_EXISTING, 0, INVALID_HANDLE_VALUE);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+
+ ErrorDialog(GetLastError());
+ SetErrorMode(oldErrorMode);
+ return;
+ }
+
+
+ if (!DeviceIoControl(handle, FSCTL_LOCK_VOLUME, 0, 0, 0, 0, &bytes,
+ 0) ||
+ !DeviceIoControl(handle, FSCTL_DISMOUNT_VOLUME, 0, 0, 0, 0,
+ &bytes, 0)) {
+
+ ErrorDialog(GetLastError());
+ CloseHandle(handle);
+ SetErrorMode(oldErrorMode);
+ return;
+ }
+
+
+ pmr.PreventMediaRemoval = FALSE;
+ if (!DeviceIoControl(handle, IOCTL_DISK_MEDIA_REMOVAL,
+ &pmr, sizeof(pmr), 0, 0, &bytes, 0) ||
+ !DeviceIoControl(handle, IOCTL_DISK_EJECT_MEDIA, 0, 0, 0, 0,
+ &bytes, 0)) {
+
+ ErrorDialog(GetLastError());
+ }
+
+ CloseHandle(handle);
+ }
+
+ DoRefresh();
+
+ SetErrorMode(oldErrorMode);
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: FrameCommandHandler
+//
+// Synopsis: Handle WM_COMMAND messages for the frame window
+//
+// Arguments: standard Windows procedure arguments for WM_COMMAND
+//
+// Returns: standard Windows procedure arguments for WM_COMMAND
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+LRESULT
+FrameCommandHandler(
+ IN HWND hwnd,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ DWORD helpFlag;
+ WORD wId = LOWORD(wParam);
+
+ switch (wId)
+ {
+
+//
+// Volume menu
+//
+
+ case IDM_VOL_FORMAT:
+
+ DoFormat(hwnd, TRUE);
+ break;
+
+ case IDM_VOL_EJECT:
+
+ DoEject(hwnd);
+ break;
+
+ case IDM_VOL_LETTER:
+
+ if (LoadFmifs())
+ {
+ DoSetDriveLetter();
+ }
+ break;
+
+#if defined( DBLSPACE_ENABLED )
+ case IDM_VOL_DBLSPACE:
+ if (LoadFmifs())
+ {
+ DblSpace(hwnd);
+ }
+ break;
+
+ case IDM_VOL_AUTOMOUNT:
+ {
+ if (LoadFmifs())
+ {
+ DoubleSpaceAutomount = (DoubleSpaceAutomount ? FALSE : TRUE);
+ DiskRegistryDblSpaceRemovable(DoubleSpaceAutomount);
+ CheckMenuItem(GetMenu(hwnd),
+ IDM_VOL_AUTOMOUNT,
+ DoubleSpaceAutomount ? MF_CHECKED : MF_UNCHECKED);
+ }
+ break;
+ }
+#endif // DBLSPACE_ENABLED
+
+ case IDM_PARTITIONCOMMIT:
+ CommitAllChanges();
+ EnableMenuItem(GetMenu(g_hwndFrame), IDM_CONFIGSAVE, MF_ENABLED);
+ AdjustMenuAndStatus();
+ break;
+
+ case IDM_VOL_PROPERTIES:
+ case IDM_PROPERTIES:
+
+ WaitForSingleObject(DisplayMutex, INFINITE);
+ RefreshAllowed = 1;
+ ReleaseMutex(DisplayMutex);
+ PropSheet();
+ break;
+
+ case IDM_NOVALIDOPERATION:
+
+ // nothing to do: it's not a valid operation!
+
+ break;
+
+ case IDM_QUIT:
+
+ SendMessage(hwnd, WM_CLOSE, 0, 0);
+ break;
+
+//
+// Partition menu
+//
+
+ case IDM_PARTITIONCREATE:
+
+ DoCreate(REGION_PRIMARY);
+ break;
+
+ case IDM_PARTITIONCREATEEX:
+
+ DoCreate(REGION_EXTENDED);
+ break;
+
+ case IDM_PARTITIONDELETE:
+
+ switch (FtSelectionType)
+ {
+ case Mirror:
+
+ DoBreakAndDeleteMirror();
+ break;
+
+ case Stripe:
+ case StripeWithParity:
+
+ DoDeleteStripe();
+ break;
+
+ case VolumeSet:
+
+ DoDeleteVolumeSet();
+ break;
+
+ default:
+
+ DoDelete();
+ break;
+ }
+
+ break;
+
+#if i386
+
+ case IDM_PARTITIONACTIVE:
+
+ DoMakeActive();
+ break;
+
+#else // i386
+
+ case IDM_SECURESYSTEM:
+
+ DoProtectSystemPartition();
+ break;
+
+#endif // i386
+
+ case IDM_CONFIGMIGRATE:
+
+ if (DoMigratePreviousFtConfig())
+ {
+ SetCursor(g_hCurWait);
+
+ //
+ // Determine if the FT driver must be enabled.
+ //
+ Sleep(2000);
+
+ if (DiskRegistryRequiresFt() == TRUE)
+ {
+ DiskRegistryEnableFt();
+ }
+ else
+ {
+ DiskRegistryDisableFt();
+ }
+
+ Sleep(4000);
+ SetCursor(g_hCurNormal);
+ FdShutdownTheSystem();
+ }
+ break;
+
+ case IDM_CONFIGSAVE:
+
+ DoSaveFtConfig();
+ break;
+
+ case IDM_CONFIGRESTORE:
+
+ if (DoRestoreFtConfig())
+ {
+ //
+ // Determine if the FT driver must be enabled.
+ //
+ if (DiskRegistryRequiresFt() == TRUE)
+ {
+ DiskRegistryEnableFt();
+ }
+ else
+ {
+ DiskRegistryDisableFt();
+ }
+
+ SetCursor(g_hCurWait);
+ Sleep(5000);
+ SetCursor(g_hCurNormal);
+ FdShutdownTheSystem();
+ }
+ break;
+
+//
+// Fault tolerance menu (Advanced Server only)
+//
+
+ case IDM_FTESTABLISHMIRROR:
+
+ DoEstablishMirror();
+ break;
+
+ case IDM_FTBREAKMIRROR:
+
+ DoBreakMirror();
+ break;
+
+ case IDM_FTCREATESTRIPE:
+
+ DoCreateStripe(FALSE);
+ break;
+
+ case IDM_FTCREATEPSTRIPE:
+
+ DoCreateStripe(TRUE);
+ break;
+
+ case IDM_FTCREATEVOLUMESET:
+
+ DoCreateVolumeSet();
+ break;
+
+ case IDM_FTEXTENDVOLUMESET:
+
+ DoExtendVolumeSet();
+ break;
+
+ case IDM_FTRECOVERSTRIPE: // BUGBUG: allow mirror recovery also?
+
+ DoRecoverStripe();
+ break;
+
+//
+// View Menu
+//
+
+ case IDM_VIEWVOLUMES:
+
+ if (g_WhichView != VIEW_VOLUMES)
+ {
+ g_WhichView = VIEW_VOLUMES;
+ ChangeView();
+ }
+ break;
+
+ case IDM_VIEWDISKS:
+
+ if (g_WhichView != VIEW_DISKS)
+ {
+ g_WhichView = VIEW_DISKS;
+ ChangeView();
+ }
+ break;
+
+ case IDM_VIEW_REFRESH:
+
+ DoRefresh();
+ break;
+
+//
+// Options menu
+//
+
+ case IDM_OPTIONSTOOLBAR:
+
+ g_Toolbar = !g_Toolbar;
+ ShowWindow(g_hwndToolbar, (g_Toolbar ? SW_SHOW : SW_HIDE));
+ AdjustOptionsMenu();
+ break;
+
+ case IDM_OPTIONSSTATUS:
+
+ g_StatusBar = !g_StatusBar;
+ AdjustOptionsMenu();
+ break;
+
+ case IDM_OPTIONSLEGEND:
+
+ g_Legend = !g_Legend;
+ AdjustOptionsMenu();
+ break;
+
+ case IDM_OPTIONSCOLORS:
+
+ DoColorsDialog(hwnd);
+ break;
+
+ case IDM_OPTIONSDISPLAY:
+
+ DoRegionDisplayDialog(hwnd);
+ break;
+
+ case IDM_OPTIONSDISK:
+
+ DoDiskOptionsDialog(hwnd);
+ break;
+
+ case IDM_OPTIONSCUSTTOOLBAR:
+
+ Toolbar_Customize(g_hwndToolbar);
+ break;
+
+//
+// Help menu
+//
+
+ case IDM_HELPCONTENTS:
+
+ helpFlag = HELP_FINDER;
+ goto CallWinHelp;
+
+ case IDM_HELPSEARCH:
+
+ helpFlag = HELP_PARTIALKEY;
+ goto CallWinHelp;
+
+ case IDM_HELPHELP:
+
+ helpFlag = HELP_HELPONHELP;
+ goto CallWinHelp;
+
+ case IDM_HELPABOUT:
+ {
+ TCHAR title[100];
+
+ LoadString(g_hInstance, IDS_APPNAME, title, ARRAYLEN(title));
+ ShellAbout(
+ hwnd,
+ title,
+ NULL,
+ (HICON)GetClassLong(hwnd, GCL_HICON)
+ );
+ break;
+ }
+
+#if DBG == 1
+
+ case IDM_DEBUGALLOWDELETES:
+
+ AllowAllDeletes = !AllowAllDeletes;
+ CheckMenuItem(GetMenu(hwnd),
+ IDM_DEBUGALLOWDELETES,
+ AllowAllDeletes ? MF_CHECKED : MF_UNCHECKED
+ );
+ break;
+
+ case IDM_DEBUGLOG:
+
+ LOG_ALL();
+ break;
+
+ case IDM_RAID:
+
+ MessageBox(hwnd,
+ L"To file a bug against the Disk Administrator, use:\n"
+ L"\n"
+ L"\tServer:\tntraid\n"
+ L"\tDatabase name:\t\tntbug\n"
+ L"\tComponent:\t\tADMIN\n"
+ L"\tSub-Comp:\t\tDISK_MGR\n"
+ L"\tType:\t\t\tNT2 NOW\n",
+
+ L"RAID Information",
+ MB_ICONINFORMATION | MB_OK);
+ //
+ // OR, Component: SYSMAN, Sub-Comp: DISK MGMT
+ //
+ break;
+
+#endif // DBG == 1
+
+
+//
+// Listbox event
+//
+
+ case ID_LISTBOX:
+
+ switch (HIWORD(wParam))
+ {
+ case LBN_SELCHANGE:
+ {
+ POINT pt;
+ DWORD pos = GetMessagePos();
+
+ pt.x = LOWORD(pos);
+ pt.y = HIWORD(pos);
+ MouseSelection(
+ GetKeyState(VK_CONTROL) & ~1, // strip toggle bit
+ &pt
+ );
+ break;
+ }
+ default:
+ DefWindowProc(hwnd, WM_COMMAND, wParam, lParam);
+ break;
+ }
+ break;
+
+//
+// Default... extension menu items
+//
+
+ default:
+ {
+
+#ifdef WINDISK_EXTENSIONS
+
+ if (MenuItems.IsExtensionId(wId))
+ {
+ daDebugOut((DEB_ITRACE, "Extension menu item %d\n", wId));
+
+ //
+ // BUGBUG: need to invoke the extension menu ONLY if there
+ // is a single selection. Then, need to pass it a drive name
+ //
+
+ PREGION_DESCRIPTOR regionDescriptor = &SELECTED_REGION(0);
+ FDASSERT(regionDescriptor);
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(regionDescriptor);
+ FDASSERT(regionData);
+
+ WCHAR driveName[3];
+ driveName[0] = regionData->DriveLetter;
+ driveName[1] = L':';
+ driveName[2] = L'\0';
+
+ MenuItemType* pMenu = MenuItems.LookupMenuItem(wId);
+
+ // BUGBUG: try/except around extension code. pass hwnd?
+ HRESULT hr = pMenu->pMenuDispatch->MenuDispatch(
+ hwnd,
+ driveName,
+ pMenu->iIndex);
+
+ switch (hr)
+ {
+ case DA_E_VOLUMEINFOCHANGED:
+ RefreshVolumeData();
+ break;
+ }
+ }
+ else if (ContextMenuItems.IsExtensionId(wId))
+ {
+ daDebugOut((DEB_ITRACE,
+ "Context menu extension menu item %d\n",
+ wId));
+
+ WCHAR driveName[256];
+
+ wsprintf(driveName, L"\\Device\\Harddisk%d", LBIndexToDiskNumber(g_MouseLBIndex));
+
+ MenuItemType* pMenu = ContextMenuItems.LookupMenuItem(wId);
+
+ // BUGBUG: try/except around extension code. pass hwnd?
+ HRESULT hr = pMenu->pMenuDispatch->MenuDispatch(
+ hwnd,
+ driveName,
+ pMenu->iIndex);
+
+ switch (hr)
+ {
+ case DA_E_VOLUMEINFOCHANGED:
+ RefreshVolumeData();
+ break;
+ }
+ }
+ else
+ {
+#endif // WINDISK_EXTENSIONS
+
+ return DefWindowProc(hwnd, WM_COMMAND, wParam, lParam);
+
+#ifdef WINDISK_EXTENSIONS
+ }
+#endif // WINDISK_EXTENSIONS
+
+ break;
+ }
+
+ } // end of main WM_COMMAND switch
+
+ return 0;
+
+CallWinHelp:
+
+ if (!WinHelp(hwnd, g_HelpFile, helpFlag, (DWORD)""))
+ {
+ WarningDialog(MSG_HELP_ERROR);
+ }
+ return 0;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: FrameCloseHandler
+//
+// Synopsis: Handle WM_CLOSE messages for the frame window.
+//
+// Arguments: standard Windows procedure arguments for WM_CLOSE
+//
+// Returns: standard Windows procedure arguments for WM_CLOSE
+//
+// History: 10-Nov-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+LRESULT
+FrameCloseHandler(
+ IN HWND hwnd,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ UINT ret = CommitAllChanges();
+
+ if (0 != ret)
+ {
+ if (1 != ret) // if we haven't written the profile, then do it
+ {
+ WriteProfile();
+ }
+ DestroyWindow(hwnd);
+ }
+
+ return 0;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: FrameDestroyHandler
+//
+// Synopsis: Handle WM_DESTROY messages for the frame window. Clean up
+// memory, etc.
+//
+// Arguments: standard Windows procedure arguments for WM_DESTROY
+//
+// Returns: standard Windows procedure arguments for WM_DESTROY
+//
+// History: 22-Oct-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+LRESULT
+FrameDestroyHandler(
+ IN HWND hwnd,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ )
+{
+ // BUGBUG clean up here -- release dc's, free DiskStates, etc.
+
+#ifdef WINDISK_EXTENSIONS
+ DeactivateExtensions();
+#endif // WINDISK_EXTENSIONS
+
+ //
+ // Other cleanup
+ //
+
+ WinHelp(hwnd, g_HelpFile, HELP_QUIT, 0);
+
+ PostQuitMessage(0);
+
+ return 0; // message processed
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DeletionIsAllowed
+//
+// Synopsis:
+//
+// This routine makes sure deletion of the partition is allowed. We do
+// not allow the user to delete the Windows NT boot partition or the
+// active partition on disk 0 (x86 only).
+//
+// Note that this routine is also used to determine whether an existing
+// single-partition volume can be extended into a volume set, since the
+// criteria are the same.
+//
+// Arguments: [RegionDescriptor] -- points to region descriptor for the
+// region which the user would like to delete.
+//
+// Returns: NO_ERROR if deletion is allowed; error number for message
+// to display if not.
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+DWORD
+DeletionIsAllowed(
+ IN PREGION_DESCRIPTOR RegionDescriptor
+ )
+{
+ ULONG ec;
+ PPERSISTENT_REGION_DATA regionData = PERSISTENT_DATA(RegionDescriptor);
+
+ FDASSERT(!IsExtended(RegionDescriptor->SysID)); // can't be extended partition
+ FDASSERT(RegionDescriptor->SysID != PARTITION_ENTRY_UNUSED); // can't be free space
+
+#if DBG == 1
+ if (AllowAllDeletes)
+ {
+ return NO_ERROR;
+ }
+#endif // DBG == 1
+
+ // if this is not an original region, deletion is allowed.
+
+ if (0 == RegionDescriptor->OriginalPartitionNumber)
+ {
+ return NO_ERROR;
+ }
+
+ // if there is no persistent data for this region, allow deletion.
+
+ if (regionData == NULL)
+ {
+ return NO_ERROR;
+ }
+
+ ec = NO_ERROR;
+ if (BootDiskNumber != (ULONG)-1)
+ {
+ // If the disk number and original partition number of this
+ // region match the recorded disk number and partition number
+ // of the boot partition, don't allow deletion.
+ //
+ if (RegionDescriptor->Disk == BootDiskNumber
+ && RegionDescriptor->OriginalPartitionNumber == BootPartitionNumber)
+ {
+ ec = MSG_CANT_DELETE_WINNT;
+ }
+ }
+
+ if (ec == NO_ERROR)
+ {
+ if (regionData->DriveLetter == BootDir)
+ {
+ ec = MSG_CANT_DELETE_ACTIVE0;
+ }
+ }
+
+ return ec;
+}
+
+
+VOID
+CheckForBootNumberChange(
+ IN ULONG Disk
+ )
+
+/*++
+
+Routine Description:
+
+ Determine if the disk that has just changed is the boot disk.
+ If so, determine if the boot partition number changed. If it
+ did, warn the user.
+
+Arguments:
+
+ RegionDescriptor - the region that has just changed.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ ULONG newPart;
+ TCHAR oldNumberString[8],
+ newNumberString[8];
+ DWORD msgCode;
+
+ if (Disk == BootDiskNumber)
+ {
+ // Pass a pointer to Disk even though this is just to get the
+ // old partition number back.
+
+ if (BootPartitionNumberChanged(&Disk, &newPart))
+ {
+#if i386
+ msgCode = MSG_CHANGED_BOOT_PARTITION_X86;
+#else
+ msgCode = MSG_CHANGED_BOOT_PARTITION_ARC;
+#endif
+ wsprintf(oldNumberString, L"%d", Disk);
+ wsprintf(newNumberString, L"%d", newPart);
+ InfoDialog(msgCode, oldNumberString, newNumberString);
+ }
+ }
+}
+
+
+
+BOOLEAN
+BootPartitionNumberChanged(
+ PULONG OldNumber,
+ PULONG NewNumber
+ )
+
+/*++
+
+Routine Description
+
+ This function determines whether the partition number of
+ the boot partition has changed during this invocation of
+ Windisk. With dynamic partitioning enabled, the work of
+ this routine increases. This routine must guess what the
+ partition numbers will be when the system is rebooted to
+ determine if the partition number for the boot partition
+ has changed. It does this via the following algorithm:
+
+ 1. Count all primary partitions - These get numbers first
+ starting from 1.
+
+ 2. Count all logical drives - These get numbers second starting
+ from the count of primary partitions plus 1.
+
+ The partition numbers located in the region structures cannot
+ be assumed to be valid. This work must be done from the
+ region array located in the disk state structure for the
+ disk.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if the boot partition's partition number has changed.
+
+--*/
+
+{
+ PDISKSTATE bootDisk;
+ PREGION_DESCRIPTOR regionDescriptor,
+ bootDescriptor = NULL;
+ ULONG i,
+ partitionNumber = 0;
+
+ if (BootDiskNumber == (ULONG)(-1) || BootDiskNumber > DiskCount)
+ {
+ // Can't tell--assume it hasn't.
+
+ return FALSE;
+ }
+
+ if (!ChangeCommittedOnDisk(BootDiskNumber))
+ {
+ // disk wasn't changed - no possibility for a problem.
+
+ return FALSE;
+ }
+
+ bootDisk = DiskArray[BootDiskNumber];
+
+ // Find the region descriptor for the boot partition
+
+ for (i = 0; i < bootDisk->RegionCount; i++)
+ {
+ regionDescriptor = &bootDisk->RegionArray[i];
+ if (regionDescriptor->OriginalPartitionNumber == BootPartitionNumber)
+ {
+ bootDescriptor = regionDescriptor;
+ break;
+ }
+ }
+
+ if (!bootDescriptor)
+ {
+ // Can't find boot partition - assume no change
+
+ return FALSE;
+ }
+
+ // No go through the region descriptors and count the partition
+ // numbers as they will be counted during system boot.
+ //
+ // If the boot region is located determine if the partition
+ // number changed.
+
+ for (i = 0; i < bootDisk->RegionCount; i++)
+ {
+ regionDescriptor = &bootDisk->RegionArray[i];
+ if ( regionDescriptor->RegionType == REGION_PRIMARY
+ && !IsExtended(regionDescriptor->SysID)
+ && (regionDescriptor->SysID != PARTITION_ENTRY_UNUSED))
+ {
+ partitionNumber++;
+
+ if (regionDescriptor == bootDescriptor)
+ {
+ if (partitionNumber != regionDescriptor->OriginalPartitionNumber)
+ {
+ *OldNumber = regionDescriptor->OriginalPartitionNumber;
+ *NewNumber = partitionNumber;
+ return TRUE;
+ }
+ else
+ {
+ // Numbers match, no problem.
+
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ // Check the logical drives as well.
+
+ for (i = 0; i < bootDisk->RegionCount; i++)
+ {
+ regionDescriptor = &bootDisk->RegionArray[i];
+
+ if (regionDescriptor->RegionType == REGION_LOGICAL)
+ {
+ partitionNumber++;
+
+ if (regionDescriptor == bootDescriptor)
+ {
+ if (partitionNumber != regionDescriptor->OriginalPartitionNumber)
+ {
+ *OldNumber = regionDescriptor->OriginalPartitionNumber;
+ *NewNumber = partitionNumber;
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: AssignDriveLetter
+//
+// Synopsis: Determine the next available drive letter. If no drive
+// letters are available, optionally warn the user and allow
+// him to cancel the operation.
+//
+// Arguments:
+//
+// [WarnIfNoLetter] - whether to warn the user if no drive letters are
+// available and allow him to cancel the operation.
+//
+// [StringId] - resource containing the name of the object being created
+// that will need a drive letter (ie, partition, logical drive, stripe
+// set, volume set).
+//
+// [DriveLetter] - receives the drive letter to assign, or
+// NO_DRIVE_LETTER_YET
+// if no more left.
+//
+// Returns: If there were no more drive letters, returns TRUE if the
+// user wants to create anyway, FALSE if he canceled. If there
+// were drive letters available, the return value is undefined.
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+BOOL
+AssignDriveLetter(
+ IN BOOL WarnIfNoLetter,
+ IN DWORD StringId,
+ OUT PWCHAR DriveLetter
+ )
+{
+ WCHAR driveLetter;
+ TCHAR name[256];
+
+ driveLetter = GetAvailableDriveLetter();
+ if (WarnIfNoLetter && L'\0' == driveLetter)
+ {
+ LoadString(g_hInstance, StringId, name, ARRAYLEN(name));
+ if (IDYES != ConfirmationDialog(
+ MSG_NO_AVAIL_LETTER,
+ MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2,
+ name))
+ {
+ return FALSE;
+ }
+ }
+ if (L'\0' == driveLetter)
+ {
+ driveLetter = NO_DRIVE_LETTER_YET;
+ }
+ *DriveLetter = driveLetter;
+ return TRUE;
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: SetFTObjectBackPointers
+//
+// Synopsis: Traverse the regions, setting back-pointers from FT
+// objects to the region they correspond to. This needs to
+// be done at initialization time as well as after region
+// operations.
+//
+// Arguments: none
+//
+// Returns: nothing
+//
+// History: 23-Sep-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+SetFTObjectBackPointers(
+ VOID
+ )
+{
+ //
+ // First, clear all the back pointers using the chain of FT sets
+ //
+
+ PFT_OBJECT ftObject;
+ PFT_OBJECT_SET ftSet;
+
+ for (ftSet = FtObjectList; NULL != ftSet; ftSet = ftSet->Next)
+ {
+ for (ftObject = ftSet->Members; NULL != ftObject; ftObject = ftObject->Next)
+ {
+ ftObject->Region = NULL;
+ }
+ }
+
+ //
+ // Now, iterate over all regions. For regions which are members of FT
+ // sets (and hence have a non-NULL FtObjectList member in their persistent
+ // region data), set their FT_OBJECT region backpointer
+ //
+
+ DWORD diskNum;
+ DWORD regionNum;
+ PREGION_DESCRIPTOR regionDescriptor;
+ PDISKSTATE diskState;
+
+ for (diskNum=0; diskNum<DiskCount; diskNum++)
+ {
+ diskState = DiskArray[diskNum];
+
+ for (regionNum=0; regionNum<diskState->RegionCount; regionNum++)
+ {
+ regionDescriptor = &diskState->RegionArray[regionNum];
+ ftObject = GET_FT_OBJECT(regionDescriptor);
+
+ if (NULL != ftObject)
+ {
+ ftObject->Region = regionDescriptor;
+ }
+ }
+ }
+}
+
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DeterminePartitioningState
+//
+// Synopsis:
+//
+// This routine determines the disk's partitioning state (ie, what types
+// of partitions exist and may be created), filling out a DISKSTATE
+// structure with the info. It also allocates the array for the
+// left/right position pairs for each region's on-screen square.
+//
+// Arguments: [DiskState] -- the CreateXXX and ExistXXX fields will be
+// filled in for the disk in the Disk field
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DeterminePartitioningState(
+ IN OUT PDISKSTATE DiskState
+ )
+{
+ DWORD i;
+
+ //
+ // If there's an existing region array there, free it.
+ //
+
+ if (DiskState->RegionArray)
+ {
+ FreeRegionArray(DiskState->RegionArray, DiskState->RegionCount);
+ }
+
+ // get the region array for the disk in question
+
+ GetAllDiskRegions( DiskState->Disk,
+ &DiskState->RegionArray,
+ &DiskState->RegionCount
+ );
+
+ // Allocate the array for the left/right coords for the graph.
+ // This may overallocate by one square (for extended partition).
+
+ DiskState->LeftRight = (PLEFTRIGHT)Realloc( DiskState->LeftRight,
+ DiskState->RegionCount * sizeof(LEFTRIGHT)
+ );
+
+ DiskState->Selected = (PBOOLEAN)Realloc( DiskState->Selected,
+ DiskState->RegionCount * sizeof(BOOLEAN)
+ );
+
+ for (i=0; i<DiskState->RegionCount; i++)
+ {
+ DiskState->Selected[i] = FALSE;
+ }
+
+ // figure out whether various creations are allowed
+
+ IsAnyCreationAllowed( DiskState->Disk,
+ TRUE,
+ &DiskState->CreateAny,
+ &DiskState->CreatePrimary,
+ &DiskState->CreateExtended,
+ &DiskState->CreateLogical
+ );
+
+ // figure out whether various partition types exist
+
+ DoesAnyPartitionExist( DiskState->Disk,
+ &DiskState->ExistAny,
+ &DiskState->ExistPrimary,
+ &DiskState->ExistExtended,
+ &DiskState->ExistLogical
+ );
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: GetLargestDiskSize
+//
+// Synopsis: Compute the size of the largest disk or CD-ROM
+//
+// Arguments: none
+//
+// Returns: nothing
+//
+// History: 4-Mar-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+ULONG
+GetLargestDiskSize(
+ VOID
+ )
+{
+ ULONG i;
+ ULONG size;
+ ULONG largestSize = 0L;
+ PCDROM_DESCRIPTOR cdrom;
+
+ for (i = 0; i < DiskCount; i++)
+ {
+ size = DiskArray[i]->DiskSizeMB;
+
+ if (size > largestSize)
+ {
+ largestSize = size;
+ }
+ }
+ for (i = 0; i < CdRomCount; i++)
+ {
+ cdrom = CdRomFindDevice(i);
+ size = cdrom->TotalSpaceInMB;
+
+ if (size > largestSize)
+ {
+ largestSize = size;
+ }
+ }
+
+ return largestSize;
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DrawCdRomBar
+//
+// Synopsis: Draw a CD-ROM bar for the disks view
+//
+// Arguments: [CdRomNumber] -- the number of the CD-ROM to draw
+//
+// Returns: nothing
+//
+// History: 28-Feb-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DrawCdRomBar(
+ IN ULONG CdRomNumber
+ )
+{
+ HDC hDCMem;
+ HPEN hpenT;
+ TCHAR text[100];
+ TCHAR textBold[5];
+ TCHAR mbBuffer[16];
+ RECT rcBar;
+ RECT rcClip;
+ RECT rcText;
+ HFONT hfontT;
+ HDC hdcTemp;
+ HBITMAP hbmOld;
+ DWORD xCdRomText;
+ ULONG largestSize;
+ ULONG cdromSize;
+ ULONG cx;
+
+ //
+ // Figure out the type name and volume label.
+ //
+
+ PCDROM_DESCRIPTOR cdrom = CdRomFindDevice(CdRomNumber);
+ FDASSERT(NULL != cdrom);
+
+ hDCMem = cdrom->hDCMem;
+
+ // erase the graph background
+
+ rcBar.left = 0;
+ rcBar.top = 0;
+ rcBar.right = GraphWidth;
+ rcBar.bottom = GraphHeight;
+ FillRect(hDCMem, &rcBar, GetStockBrush(LTGRAY_BRUSH));
+
+ hpenT = SelectPen(hDCMem, g_hPenThinSolid);
+
+ //
+ // Draw the info area: small bitmap, some text, and a
+ // line across the top.
+ //
+ // First draw the bitmap.
+ //
+
+ hdcTemp = CreateCompatibleDC(hDCMem);
+ hbmOld = SelectBitmap(hdcTemp, g_hBitmapSmallCdRom);
+
+ BitBlt(hDCMem,
+ xSmallCdRom,
+ ySmallCdRom,
+ dxSmallCdRom,
+ dySmallCdRom,
+ hdcTemp,
+ 0,
+ 0,
+ SRCCOPY
+ );
+
+ if (hbmOld)
+ {
+ SelectBitmap(hdcTemp, hbmOld);
+ }
+ DeleteDC(hdcTemp);
+
+ //
+ // Now draw the line.
+ //
+
+ MoveToEx(hDCMem, xSmallCdRom, BarTopYOffset, NULL);
+ LineTo(hDCMem, BarLeftX - xSmallCdRom, BarTopYOffset);
+
+ //
+ // Now draw the text.
+ //
+
+ hfontT = SelectFont(hDCMem, g_hFontGraphBold);
+ SetTextColor(hDCMem, RGB(0, 0, 0));
+ SetBkColor(hDCMem, RGB(192, 192, 192));
+
+ //use the width of the disk bitmap as a buffer width
+ xCdRomText = dxSmallCdRom + dxSmallDisk;
+
+ wsprintf(text, CdRomN, CdRomNumber);
+ TextOut(hDCMem,
+ xCdRomText,
+ BarTopYOffset + dyBarTextLine,
+ text,
+ lstrlen(text)
+ );
+
+ SelectFont(hDCMem, g_hFontGraph);
+
+ LoadString(g_hInstance, IDS_MEGABYTES_ABBREV, mbBuffer, ARRAYLEN(mbBuffer));
+
+ if (cdrom->TypeName) {
+ wsprintf(text, TEXT("%u %s"), cdrom->TotalSpaceInMB, mbBuffer);
+
+ TextOut(hDCMem,
+ xCdRomText,
+ BarTopYOffset + (4*dyBarTextLine),
+ text,
+ lstrlen(text)
+ );
+
+ }
+
+ //
+ // Now draw the bar. First figure out largest size.
+ //
+
+ largestSize = GetLargestDiskSize();
+
+ if (DiskProportional == g_DiskDisplayType)
+ {
+ cdromSize = cdrom->TotalSpaceInMB;
+
+ //
+ // Account for extreme differences in largest to smallest disk
+ //
+
+ if (cdromSize < largestSize / 4)
+ {
+ cdromSize = largestSize / 4;
+ }
+ }
+ else
+ {
+ cdromSize = largestSize;
+ }
+
+ // cx = BarWidth * (cdromSize / largestSize);
+ //
+ // ===>
+ //
+ // cx = (BarWidth * cdromSize) / largestSize;
+
+ cx = (ULONG)(UInt32x32To64(BarWidth, cdromSize) / largestSize) + 1;
+
+ rcClip.left = BarLeftX;
+ rcClip.top = BarTopYOffset;
+ rcClip.right = BarLeftX + cx;
+ rcClip.bottom = BarBottomYOffset;
+
+ cdrom->LeftRight.Left = rcClip.left;
+ cdrom->LeftRight.Right = rcClip.right;
+
+ SelectBrush(hDCMem, GetStockBrush(WHITE_BRUSH));
+
+ Rectangle(
+ hDCMem,
+ rcClip.left,
+ rcClip.top,
+ rcClip.right,
+ rcClip.bottom
+ );
+
+ InflateRect(&rcClip, -PEN_WIDTH, -PEN_WIDTH);
+
+ if (cdrom->TypeName) {
+ wsprintf(text,
+ TEXT("\n%s\n%s\n%u %s"),
+ cdrom->VolumeLabel,
+ cdrom->TypeName,
+ cdrom->TotalSpaceInMB,
+ mbBuffer);
+ }
+
+ *textBold = L'\0';
+ if (cdrom->DriveLetter != NO_DRIVE_LETTER_EVER)
+ {
+ wsprintf(textBold, TEXT("%wc:"), cdrom->DriveLetter);
+ }
+
+ // output the text
+
+ rcText.left = rcClip.left + dxBarTextMargin;
+ rcText.top = BarTopYOffset + dyBarTextLine;
+ rcText.right = rcClip.right - dxBarTextMargin;
+ rcText.bottom = BarBottomYOffset;
+
+ SetBkMode(hDCMem, TRANSPARENT);
+ SetTextColor(hDCMem, RGB(0, 0, 0));
+
+ SelectFont(hDCMem, g_hFontGraphBold);
+ DrawText(hDCMem, textBold, -1, &rcText, DT_LEFT | DT_NOPREFIX);
+
+ if (cdrom->TypeName) {
+
+ SelectFont(hDCMem, g_hFontGraph);
+ DrawText(hDCMem, text, -1, &rcText, DT_LEFT | DT_NOPREFIX);
+
+ }
+
+ SelectPen(hDCMem, hpenT);
+ SelectFont(hDCMem, hfontT);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DrawDiskBar
+//
+// Synopsis: Draw a disk bar for the disks view
+//
+// Arguments: [DiskState] -- the disk state for the disk to draw
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DrawDiskBar(
+ IN PDISKSTATE DiskState
+ )
+{
+ LONGLONG temp1, temp2;
+ ULONG i;
+ HDC hDCMem = DiskState->hDCMem;
+ DWORD leftAdjust = BarLeftX;
+ DWORD cx;
+ DWORD diskWidth;
+ HPEN hpenT;
+ TCHAR text[100];
+ TCHAR textBold[5];
+ TCHAR mbBuffer[16];
+ RECT rc;
+ RECT rcRegion;
+ HFONT hfontT;
+ DWORD brushIndex;
+ COLORREF previousColor;
+ HBRUSH hbr;
+ BOOL isFree;
+ BOOL isLogical;
+ BOOL isNew;
+ HDC hdcTemp;
+ HBITMAP hbmOld;
+ DWORD xDiskText;
+ PWSTR typeName;
+ PWSTR volumeLabel;
+ WCHAR driveLetter;
+ BAR_TYPE barType;
+ ULONG diskSize;
+ ULONG largestSize;
+ PREGION_DESCRIPTOR regionDescriptor;
+
+ // If this is a removable, update to whatever its current
+ // information may be.
+
+ if (IsDiskRemovable[DiskState->Disk])
+ {
+
+ //
+ // We are going to find out the partition type and disk size for
+ // this removable.
+ //
+ // If the disk size is zero we will assume that the drive is empty.
+ //
+ // If the drive is empty we have two cases.
+ //
+ // 1) We may have previously had something in the drive.
+ //
+ // if this is the case then we need to free up its region
+ // structures.
+ //
+ // 2) We didn't previously have something in the drive.
+ //
+ // Nothing really to do in this case. Essentially there was
+ // no change.
+ //
+ // If the drive contains something we have 2 cases.
+ //
+ // 1) The drive didn't contain anything previouly.
+ //
+ // In this case we should build up the region and partition structures
+ // for the drive.
+ //
+ // 2) The drive contained something previously.
+ //
+ // This has two subcases.
+ //
+ // a) The drive contained something with the same label and size
+ //
+ // b) The drive contained something with a different label or size.
+ //
+ //
+ //
+
+ PPERSISTENT_REGION_DATA regionData;
+
+ // Update the information on this disk.
+
+ regionDescriptor = &DiskState->RegionArray[0];
+
+ GetVolumeTypeAndSize(DiskState->Disk,
+ 1,
+ &volumeLabel,
+ &typeName,
+ &diskSize);
+
+ if (!diskSize) {
+
+ //
+ // If we have region data then free it up it's invalid.
+ //
+
+ if (regionDescriptor) {
+
+ regionData = PERSISTENT_DATA(regionDescriptor);
+
+ if (regionData) {
+
+ if (regionData->VolumeLabel) {
+
+ Free(regionData->VolumeLabel);
+ regionData->VolumeLabel = NULL;
+
+ }
+
+ if (regionData->TypeName) {
+
+ Free(regionData->TypeName);
+ regionData->TypeName = NULL;
+
+ }
+
+ }
+
+ }
+
+ }
+
+
+
+ if (regionDescriptor) {
+ regionData = PERSISTENT_DATA(regionDescriptor);
+
+ if (GetVolumeTypeAndSize(DiskState->Disk,
+ 1,
+ &volumeLabel,
+ &typeName,
+ &diskSize))
+ {
+ // Update the values for the removable.
+
+ if (NULL != regionData)
+ {
+ if (0 == lstrcmpi(typeName, L"raw"))
+ {
+ // Always want RAW file systems to display as "Unknown"
+
+ Free(typeName);
+ typeName = (PWSTR)Malloc((lstrlen(wszUnknown) + 1) * sizeof(WCHAR));
+ lstrcpy(typeName, wszUnknown);
+ }
+
+ if (NULL != regionData->VolumeLabel)
+ {
+ Free(regionData->VolumeLabel);
+ }
+ regionData->VolumeLabel = volumeLabel;
+
+ if (NULL != regionData->TypeName)
+ {
+ Free(regionData->TypeName);
+ }
+ regionData->TypeName = typeName;
+ regionData->TotalSpaceInBytes.LowPart = diskSize;
+
+ }
+
+ DiskState->DiskSizeMB = diskSize;
+ }
+ }
+ }
+
+ largestSize = GetLargestDiskSize();
+
+ // erase the graph background
+
+ rc.left = rc.top = 0;
+ rc.right = GraphWidth;
+ rc.bottom = GraphHeight;
+ FillRect(hDCMem, &rc, GetStockBrush(LTGRAY_BRUSH));
+
+ hpenT = SelectPen(hDCMem, g_hPenThinSolid);
+
+ //
+ // Draw the info area: small disk bitmap, some text, and a
+ // line across the top.
+ //
+ // First draw the bitmap.
+ //
+
+ hdcTemp = CreateCompatibleDC(hDCMem);
+ if (IsDiskRemovable[DiskState->Disk])
+ {
+ hbmOld = SelectBitmap(hdcTemp, g_hBitmapRemovableDisk);
+ BitBlt(hDCMem,
+ xRemovableDisk,
+ yRemovableDisk,
+ dxRemovableDisk,
+ dyRemovableDisk,
+ hdcTemp,
+ 0,
+ 0,
+ SRCCOPY);
+ }
+ else
+ {
+ hbmOld = SelectBitmap(hdcTemp, g_hBitmapSmallDisk);
+ BitBlt(hDCMem,
+ xSmallDisk,
+ ySmallDisk,
+ dxSmallDisk,
+ dySmallDisk,
+ hdcTemp,
+ 0,
+ 0,
+ SRCCOPY);
+ }
+
+ if (hbmOld)
+ {
+ SelectBitmap(hdcTemp, hbmOld);
+ }
+ DeleteDC(hdcTemp);
+
+ //
+ // Now draw the line.
+ //
+
+ if (IsDiskRemovable[DiskState->Disk])
+ {
+ MoveToEx(hDCMem, xRemovableDisk, BarTopYOffset, NULL);
+ LineTo(hDCMem, BarLeftX - xRemovableDisk, BarTopYOffset);
+ xDiskText = 2 * dxRemovableDisk;
+ }
+ else
+ {
+ MoveToEx(hDCMem, xSmallDisk, BarTopYOffset, NULL);
+ LineTo(hDCMem, BarLeftX - xSmallDisk, BarTopYOffset);
+ xDiskText = 2 * dxSmallDisk;
+ }
+
+ //
+ // Now draw the text.
+ //
+
+ hfontT = SelectFont(hDCMem, g_hFontGraphBold);
+ SetTextColor(hDCMem, RGB(0, 0, 0));
+ SetBkColor(hDCMem, RGB(192, 192, 192));
+ wsprintf(text, DiskN, DiskState->Disk);
+ TextOut(hDCMem,
+ xDiskText,
+ BarTopYOffset + dyBarTextLine,
+ text,
+ lstrlen(text)
+ );
+
+ SelectFont(hDCMem, g_hFontGraph);
+ if (DiskState->OffLine)
+ {
+ LoadString(g_hInstance, IDS_OFFLINE, text, ARRAYLEN(text));
+ }
+ else
+ {
+ LoadString(g_hInstance, IDS_MEGABYTES_ABBREV, mbBuffer, ARRAYLEN(mbBuffer));
+
+ if (!DiskState->DiskSizeMB && IsDiskRemovable[DiskState->Disk]) {
+
+ text[0] = L'\0';
+
+ } else {
+ wsprintf(text, TEXT("%u %s"), DiskState->DiskSizeMB, mbBuffer);
+ }
+ }
+
+
+ TextOut(hDCMem,
+ xDiskText,
+ BarTopYOffset + (4*dyBarTextLine),
+ text,
+ lstrlen(text)
+ );
+
+ //
+ // Now draw the disk bar
+ //
+
+ if (DiskState->OffLine)
+ {
+ //
+ // if a disk is offline, just draw an empty box with the text
+ // "configuration information not available" inside
+ //
+
+ SelectBrush(hDCMem, GetStockBrush(LTGRAY_BRUSH));
+
+ RECT rcClip;
+
+ rcClip.left = BarLeftX;
+ rcClip.top = BarTopYOffset;
+ rcClip.right = BarLeftX + BarWidth;
+ rcClip.bottom = BarBottomYOffset;
+
+ Rectangle(
+ hDCMem,
+ rcClip.left,
+ rcClip.top,
+ rcClip.right,
+ rcClip.bottom
+ );
+
+ LoadString(g_hInstance, IDS_NO_CONFIG_INFO, text, ARRAYLEN(text));
+
+ InflateRect(&rcClip, -PEN_WIDTH, -PEN_WIDTH);
+ ExtTextOut(
+ hDCMem,
+ BarLeftX + dxBarTextMargin,
+ BarTopYOffset + (4*dyBarTextLine),
+ ETO_CLIPPED,
+ &rcClip,
+ text,
+ lstrlen(text),
+ NULL
+ );
+ }
+ else
+ {
+ if (DiskProportional == g_DiskDisplayType)
+ {
+ diskSize = DiskState->DiskSizeMB;
+
+ //
+ // Account for extreme differences in largest to smallest disk
+ //
+
+ if (diskSize < largestSize / 4)
+ {
+ diskSize = largestSize / 4;
+ }
+ }
+ else
+ {
+ diskSize = largestSize;
+ }
+
+ //
+ // If user wants WinDisk to decide which type of view to use, do that
+ // here. We'll use a proportional view unless any single region would
+ // have a width less than 3 times the selection thickness plus the
+ // width of a drive letter.
+ //
+
+ barType = DiskState->BarType;
+
+ if (barType == BarAuto)
+ {
+ ULONG regionSize;
+
+ barType = BarProportional;
+
+ for (i=0; i<DiskState->RegionCount; i++)
+ {
+ regionDescriptor = &DiskState->RegionArray[i];
+
+ if (IsExtended(regionDescriptor->SysID))
+ {
+ continue;
+ }
+
+// regionSize = (regionDescriptor->SizeMB * BarWidth * diskSize)
+// / (largestSize * DiskState->DiskSizeMB);
+
+ temp1 = UInt32x32To64(BarWidth, diskSize);
+ temp1 *= regionDescriptor->SizeMB;
+ temp2 = UInt32x32To64(largestSize, (DiskState->DiskSizeMB?DiskState->DiskSizeMB:diskSize));
+ if (!temp2) {
+ temp2 = temp1;
+ }
+ regionSize = (ULONG) (temp1 / temp2);
+
+ if (regionSize < g_MinimumRegionSize)
+ {
+ barType = BarEqual;
+ break;
+ }
+ }
+ }
+
+// diskWidth = BarWidth * (diskSize / largestSize);
+
+ diskWidth = (DWORD)(UInt32x32To64(BarWidth, diskSize) / largestSize);
+
+ if (barType == BarEqual)
+ {
+
+// cx = 1 / (# of regions)
+// // % of the disk for this region
+// * BarWidth * (diskSize / largestSize)
+// // pixels in the disk
+// ;
+//
+// ===>
+//
+// cx = BarWidth * diskSize
+// / ((DiskState->RegionCount - (DiskState->ExistExtended ? 1 : 0)) * largestSize) ;
+
+ temp1 = UInt32x32To64(BarWidth, diskSize);
+ temp2 = UInt32x32To64(
+ (DiskState->RegionCount - (DiskState->ExistExtended ? 1 : 0)),
+ largestSize);
+ if (!temp2) {
+ temp2 = temp1;
+ }
+ cx = (ULONG) (temp1 / temp2);
+ }
+
+ for (i=0; i<DiskState->RegionCount; i++)
+ {
+ PFT_OBJECT ftObject;
+
+ regionDescriptor = &DiskState->RegionArray[i];
+
+ if (!IsExtended(regionDescriptor->SysID))
+ {
+ if (barType == BarProportional)
+ {
+
+// cx = (regionDescriptor->SizeMB / DiskState->DiskSizeMB)
+// // % of the disk for this region
+// * BarWidth * (diskSize / largestSize)
+// // pixels in the disk
+// ;
+//
+// ===>
+//
+// cx = regionDescriptor->SizeMB * BarWidth * diskSize
+// / (largestSize * DiskState->DiskSizeMB);
+
+ temp1 = UInt32x32To64(BarWidth, diskSize);
+ temp1 *= regionDescriptor->SizeMB;
+ temp2 = UInt32x32To64(largestSize, (DiskState->DiskSizeMB?DiskState->DiskSizeMB:diskSize));
+ if (!temp2) {
+ temp2 = temp1;
+ }
+ cx = (ULONG) (temp1 / temp2) + 1;
+ }
+
+ isFree = (regionDescriptor->SysID == PARTITION_ENTRY_UNUSED);
+ isLogical = (regionDescriptor->RegionType == REGION_LOGICAL);
+
+ if (NULL == regionDescriptor->PersistentData)
+ {
+ //
+ // no persistent data: free space or extended partition
+ //
+ isNew = FALSE;
+ }
+ else
+ {
+ isNew = PERSISTENT_DATA(regionDescriptor)->NewRegion;
+ }
+
+ if (!isFree)
+ {
+ //
+ // If we've got a mirror or stripe set, use special colors.
+ //
+
+ ftObject = GET_FT_OBJECT(regionDescriptor);
+ switch (ftObject ? ftObject->Set->Type : -1)
+ {
+ case Mirror:
+ brushIndex = BRUSH_MIRROR;
+ break;
+ case Stripe:
+ brushIndex = BRUSH_STRIPESET;
+ break;
+ case StripeWithParity:
+ brushIndex = BRUSH_PARITYSET;
+ break;
+ case VolumeSet:
+ brushIndex = BRUSH_VOLUMESET;
+ break;
+ default:
+ brushIndex = isLogical ? BRUSH_USEDLOGICAL : BRUSH_USEDPRIMARY;
+ }
+ }
+
+ previousColor = SetBkColor(hDCMem, RGB(255, 255, 255));
+ SetBkMode(hDCMem, OPAQUE);
+
+ rcRegion.left = leftAdjust;
+ rcRegion.top = BarTopYOffset;
+ rcRegion.right = leftAdjust + cx;
+ rcRegion.bottom = BarBottomYOffset;
+
+ if ( (DiskEqual == g_DiskDisplayType)
+ && (i == DiskState->RegionCount - 1) )
+ {
+ // for the last disk, to avoid off-by-one errors,
+ // simply set its right side to a fixed number
+
+ rcRegion.right = BarLeftX + diskWidth;
+ }
+
+ if (isFree)
+ {
+ //
+ // Free space -- cross hatch the whole block.
+ //
+
+ hbr = SelectBrush(
+ hDCMem,
+ isLogical
+ ? g_hBrushFreeLogical
+ : g_hBrushFreePrimary
+ );
+ Rectangle(
+ hDCMem,
+ rcRegion.left,
+ rcRegion.top,
+ rcRegion.right,
+ rcRegion.bottom
+ );
+ }
+ else
+ {
+ //
+ // Used space -- make most of the block white except for
+ // a small strip at the top, which gets an identifying
+ // color. If the partition is not recognized, leave
+ // it all white.
+ //
+
+ hbr = SelectBrush(hDCMem, GetStockBrush(WHITE_BRUSH));
+ Rectangle(
+ hDCMem,
+ rcRegion.left,
+ rcRegion.top,
+ rcRegion.right,
+ rcRegion.bottom
+ );
+
+ if (IsRecognizedPartition(regionDescriptor->SysID))
+ {
+ SelectBrush(hDCMem, g_Brushes[brushIndex]);
+ Rectangle(
+ hDCMem,
+ rcRegion.left,
+ rcRegion.top,
+ rcRegion.right,
+ rcRegion.top + (4 * dyBarTextLine / 5) + 1
+ );
+ }
+ }
+
+ if (hbr)
+ {
+ SelectBrush(hDCMem, hbr);
+ }
+
+ //
+ // Figure out the type name (ie, unformatted, fat, etc) and
+ // volume label.
+ //
+
+ DetermineRegionInfo(regionDescriptor, &typeName, &volumeLabel, &driveLetter);
+ LoadString(
+ g_hInstance,
+ IDS_MEGABYTES_ABBREV,
+ mbBuffer,
+ ARRAYLEN(mbBuffer));
+
+ if (NULL == typeName)
+ {
+ typeName = wszUnknown;
+ }
+
+ if (NULL == volumeLabel)
+ {
+ volumeLabel = L"";
+ }
+
+ wsprintf(text,
+ TEXT("\n%s\n%s\n%u %s"),
+ volumeLabel,
+ typeName,
+ regionDescriptor->SizeMB,
+ mbBuffer);
+
+ *textBold = L'\0';
+ if (driveLetter != L' ')
+ {
+ wsprintf(textBold, TEXT("%wc:"), driveLetter);
+ }
+
+ // output the text
+
+ rc.left = rcRegion.left + dxBarTextMargin;
+ rc.right = rcRegion.right - dxBarTextMargin;
+ rc.top = BarTopYOffset + dyBarTextLine;
+ rc.bottom = BarBottomYOffset;
+
+ SetBkMode(hDCMem, TRANSPARENT);
+
+ SelectFont(hDCMem, g_hFontGraphBold);
+
+ //
+ // If this is an unhealthy ft set member, draw the text in red.
+ //
+
+ if ( !isFree
+ && ftObject
+ && (ftObject->State != Healthy)
+ && (ftObject->State != Initializing))
+ {
+ SetTextColor(hDCMem, RGB(192, 0, 0));
+ }
+ else if (isNew)
+ {
+ //
+ // New volumes have gray text
+ //
+
+ SetTextColor(hDCMem, RGB(100, 100, 100));
+ }
+ else
+ {
+ SetTextColor(hDCMem, RGB(0, 0, 0));
+ }
+
+ DrawText(hDCMem, textBold, -1, &rc, DT_LEFT | DT_NOPREFIX);
+
+ SelectFont(hDCMem, g_hFontGraph);
+
+ DrawText(hDCMem, text, -1, &rc, DT_LEFT | DT_NOPREFIX);
+
+#if i386
+ //
+ // if this guy is active make a mark in the upper left
+ // corner of his rectangle.
+ //
+
+ if ( (regionDescriptor->SysID != PARTITION_ENTRY_UNUSED)
+ && (regionDescriptor->RegionType == REGION_PRIMARY)
+ && regionDescriptor->Active)
+ {
+ TextOut(hDCMem,
+ leftAdjust + dxBarTextMargin,
+ BarTopYOffset + 2,
+ TEXT("*"),
+ 1);
+ }
+#endif
+
+#if defined( DBLSPACE_ENABLED )
+ // Check for DoubleSpace volumes and update display accordingly
+
+ PDBLSPACE_DESCRIPTOR dblSpace;
+ UINT dblSpaceIndex;
+
+ dblSpaceIndex = 0;
+ dblSpace = NULL;
+ while (NULL != (dblSpace = DblSpaceGetNextVolume(
+ regionDescriptor,
+ dblSpace)))
+ {
+ if (dblSpace->Mounted)
+ {
+ SetTextColor(hDCMem, RGB(192, 0, 0));
+ }
+ else
+ {
+ SetTextColor(hDCMem, RGB(0, 0, 0));
+ }
+
+ if (dblSpace->DriveLetter == TEXT(' '))
+ {
+ wsprintf(text,
+ TEXT("%s"),
+ dblSpace->FileName);
+ }
+ else
+ {
+ wsprintf(text,
+ TEXT("%c: %s"),
+ dblSpace->DriveLetter,
+ dblSpace->FileName);
+ }
+
+ rc.left = leftAdjust + dxBarTextMargin + 60;
+ rc.right = leftAdjust + cx - dxBarTextMargin;
+ rc.top = BarTopYOffset + dyBarTextLine + (dblSpaceIndex * 15);
+ rc.bottom = BarBottomYOffset;
+ DrawText(hDCMem, text, -1, &rc, DT_LEFT | DT_NOPREFIX);
+ dblSpaceIndex++;
+ }
+#endif // DBLSPACE_ENABLED
+
+ SetBkColor(hDCMem, previousColor);
+
+ DiskState->LeftRight[i].Left = rcRegion.left;
+ DiskState->LeftRight[i].Right = rcRegion.right;
+
+ // Now, add a delta to move to the next region.
+ // Note that the rectangles overlap: the right edge of a region
+ // is redrawn as the left edge of the following region, to
+ // avoid getting double-width lines between regions.
+
+ leftAdjust = rcRegion.right - 1;
+ }
+ else
+ {
+ DiskState->LeftRight[i].Left = DiskState->LeftRight[i].Right = 0;
+ }
+ }
+ }
+
+ SelectPen(hDCMem, hpenT);
+ SelectFont(hDCMem, hfontT);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: PartitionCount
+//
+// Synopsis: Returns a count of used primary partitions on a disk.
+// If =4, then no more primary partitions may be created.
+//
+// Arguments: [Disk] -- 0-based number of the disk of interest
+//
+// Returns: number of partitions
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+ULONG
+PartitionCount(
+ IN ULONG Disk
+ )
+{
+ ULONG i;
+ ULONG partitions = 0;
+
+ for (i=0; i<DiskArray[Disk]->RegionCount; i++)
+ {
+ PREGION_DESCRIPTOR regionDescriptor = &DiskArray[Disk]->RegionArray[i];
+
+ if ( (regionDescriptor->RegionType != REGION_LOGICAL)
+ && (regionDescriptor->SysID != PARTITION_ENTRY_UNUSED))
+ {
+ partitions++;
+ }
+ }
+
+ return partitions;
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: RegisterFileSystemExtend
+//
+// Synopsis: This function adds registry entries to extend the file
+// system structures in volume sets that have been extended.
+//
+// Arguments: (none)
+//
+// Returns: TRUE if a file system was extended
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+BOOL
+RegisterFileSystemExtend(
+ VOID
+ )
+{
+ BYTE buf[1024];
+ PWSTR templateString = L"autochk /x ";
+ PWSTR appendPoint;
+ DWORD templateLength;
+ WCHAR extendedDrives[26];
+ PDISKSTATE diskState;
+ PREGION_DESCRIPTOR regionDescriptor;
+ PFT_OBJECT ftObject;
+ DWORD i;
+ DWORD j;
+ DWORD cExt = 0;
+ DWORD valueType;
+ DWORD size;
+ HKEY hkey;
+ LONG ec;
+
+
+ // Traverse the disks to find any volume sets that have been extended.
+ //
+ for (i = 0; i < DiskCount; i++)
+ {
+ diskState = DiskArray[i];
+
+ for (j = 0; j < diskState->RegionCount; j++)
+ {
+ regionDescriptor = &diskState->RegionArray[j];
+
+ if ( (NULL != (ftObject = GET_FT_OBJECT(regionDescriptor)))
+ && ftObject->MemberIndex == 0
+ && ftObject->Set->Type == VolumeSet
+ && ftObject->Set->Status == FtSetExtended)
+ {
+ extendedDrives[cExt++] = PERSISTENT_DATA(regionDescriptor)->DriveLetter;
+ }
+ }
+ }
+
+ if (0 != cExt)
+ {
+ //
+ // Fetch the BootExecute value of the Session Manager key.
+ //
+ ec = RegOpenKeyEx(
+ HKEY_LOCAL_MACHINE,
+ TEXT("System\\CurrentControlSet\\Control\\Session Manager"),
+ 0,
+ KEY_QUERY_VALUE | KEY_SET_VALUE,
+ &hkey
+ );
+
+ if (ec != NO_ERROR)
+ {
+ return FALSE;
+ }
+
+ size = sizeof(buf);
+ ec = RegQueryValueEx(hkey,
+ TEXT("BootExecute"),
+ NULL,
+ &valueType,
+ buf,
+ &size
+ );
+
+ if (ec != NO_ERROR || valueType != REG_MULTI_SZ)
+ {
+ return FALSE;
+ }
+
+ //
+ // Decrement size to get rid of the extra trailing null
+ //
+ if (0 != size)
+ {
+ size -= sizeof(WCHAR);
+ }
+
+ templateLength = wcslen(templateString);
+ appendPoint = (PWSTR)(buf + size);
+
+ for (i = 0; i < cExt; i++)
+ {
+ //
+ // Add an entry for this drive to the BootExecute value.
+ //
+ wcsncpy( appendPoint, templateString, templateLength );
+ appendPoint += templateLength;
+
+ *appendPoint++ = extendedDrives[i];
+ *appendPoint++ = L':';
+ *appendPoint++ = L'\0';
+ }
+
+ //
+ // Add an additional trailing null at the end
+ //
+ *appendPoint++ = L'\0';
+
+ //
+ // Recalculate the size of the buffer, adding all the new autochk
+ // strings.
+ //
+
+ size += ( (templateLength + 3) * cExt + 1 ) * sizeof(WCHAR);
+
+ //
+ // Save the value.
+ //
+ ec = RegSetValueEx(hkey,
+ TEXT("BootExecute"),
+ 0,
+ REG_MULTI_SZ,
+ buf,
+ size
+ );
+ RegCloseKey(hkey);
+
+ if (ec != NO_ERROR)
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/private/utils/windisk/src/windisk.hxx b/private/utils/windisk/src/windisk.hxx
new file mode 100644
index 000000000..82bf15220
--- /dev/null
+++ b/private/utils/windisk/src/windisk.hxx
@@ -0,0 +1,140 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: windisk.hxx
+//
+// Contents: Declarations
+//
+// History: 4-Mar-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#ifndef __WINDISK_HXX__
+#define __WINDISK_HXX__
+
+//////////////////////////////////////////////////////////////////////////////
+
+#ifndef i386
+
+extern BOOL SystemPartitionIsSecure;
+
+#endif // !i386
+
+//////////////////////////////////////////////////////////////////////////////
+
+LRESULT CALLBACK
+MyFrameWndProc(
+ IN HWND hwnd,
+ IN UINT msg,
+ IN WPARAM wParam,
+ IN LPARAM lParam
+ );
+
+BOOL
+IsVolumeFormatted(
+ IN PREGION_DESCRIPTOR RegionDescriptor
+ );
+
+BOOL
+SingleVolumeSelected(
+ VOID
+ );
+
+VOID
+DetermineSelectionState(
+ VOID
+ );
+
+DWORD
+SetUpMenu(
+ IN PDISKSTATE *SinglySelectedDisk,
+ IN DWORD *SinglySelectedRegion
+ );
+
+VOID
+SetDriveLetterInfo(
+ IN UINT DiskNum
+ );
+
+VOID
+TotalRedraw(
+ VOID
+ );
+
+VOID
+RedrawSelectedBars(
+ VOID
+ );
+
+VOID
+TotalRedrawAndRepaint(
+ VOID
+ );
+
+PPERSISTENT_REGION_DATA
+DmAllocatePersistentData(
+ IN PFT_OBJECT FtObject,
+ IN PWSTR VolumeLabel,
+ IN PWSTR TypeName,
+ IN WCHAR DriveLetter,
+ IN BOOL NewRegion,
+ IN LARGE_INTEGER FreeSpaceInBytes,
+ IN LARGE_INTEGER TotalSpaceInBytes
+ );
+
+VOID
+DmFreePersistentData(
+ IN OUT PPERSISTENT_REGION_DATA RegionData
+ );
+
+DWORD
+DeletionIsAllowed(
+ IN PREGION_DESCRIPTOR RegionDescriptor
+ );
+
+VOID
+CheckForBootNumberChange(
+ IN ULONG Disk
+ );
+
+BOOLEAN
+BootPartitionNumberChanged(
+ PULONG OldNumber,
+ PULONG NewNumber
+ );
+
+BOOL
+AssignDriveLetter(
+ IN BOOL WarnIfNoLetter,
+ IN DWORD StringId,
+ OUT PWCHAR DriveLetter
+ );
+
+VOID
+SetFTObjectBackPointers(
+ VOID
+ );
+
+VOID
+DeterminePartitioningState(
+ IN OUT PDISKSTATE DiskState
+ );
+
+VOID
+DrawDiskBar(
+ IN PDISKSTATE DiskState
+ );
+
+ULONG
+PartitionCount(
+ IN ULONG Disk
+ );
+
+BOOL
+RegisterFileSystemExtend(
+ VOID
+ );
+
+#endif // __WINDISK_HXX__
diff --git a/private/utils/windisk/src/windisk.rc b/private/utils/windisk/src/windisk.rc
new file mode 100644
index 000000000..276f4c509
--- /dev/null
+++ b/private/utils/windisk/src/windisk.rc
@@ -0,0 +1,563 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: windisk.rc
+//
+// Contents: Main Disk Administrator resource definition file
+//
+// History: 6-Jun-93 BruceFo Created from NT Disk Administrator
+//
+//--------------------------------------------------------------------------
+
+#include <windows.h>
+#include "resids.h"
+#include "dialogs.h"
+
+
+////////////////////////////////////////////////////////////////////////////
+
+IDFDISK ICON dskmgr.ico // main icon
+IDB_SMALLDISK BITMAP smdisk.bmp // small disk for disks view
+IDB_REMOVABLEDISK BITMAP rmdisk.bmp // removable disk for disks view
+IDB_SMALLCDROM BITMAP smcdrom.bmp // small CD-ROM for disks view
+
+IDB_TOOLBAR BITMAP tool16.bmp
+IDB_EXTRATOOLS BITMAP xtra16.bmp
+
+IDI_S_HARD ICON shard.ico
+IDI_S_CDROM ICON scdrom.ico
+
+IDI_STOP_SIGN ICON trffc14.ico
+
+
+////////////////////////////////////////////////////////////////////////////
+
+STRINGTABLE BEGIN
+ IDS_APPNAME "Disk Administrator"
+ IDS_MULTIPLEITEMS "Multiple items selected"
+ IDS_FREESPACE "Free space"
+ IDS_PARTITION "Partition"
+ IDS_LOGICALVOLUME "Logical drive"
+ IDS_CDROM "CD-ROM"
+ IDS_DISKN "Disk %u"
+ IDS_CDROMN "CD-ROM %u"
+ IDS_CONFIRM "Confirm"
+ IDS_NOT_IN_APP_MSG_FILE "Could not find message %u in the application message file"
+ IDS_NOT_IN_SYS_MSG_FILE "Could not find message %u in the system message file"
+ IDS_UNFORMATTED "Unformatted"
+ IDS_UNKNOWN "Unknown"
+ IDS_STRIPESET "Stripe set"
+ IDS_VOLUMESET "Volume set"
+ IDS_EXTENDEDPARTITION "Empty extended partition"
+ IDS_FREEEXT "Free space in extended partition"
+ IDS_DRIVELET_DESCR "%1 MB %2 %3 on disk %4"
+ IDS_HEALTHY "HEALTHY"
+ IDS_BROKEN "BROKEN"
+ IDS_RECOVERABLE "RECOVERABLE"
+ IDS_INITIALIZING "INITIALIZING"
+ IDS_REGENERATING "REGENERATING"
+ IDS_REGENERATED "REGENERATED"
+ IDS_NEW "NEW"
+ IDS_OFFLINE "OFF-LINE"
+ IDS_DISABLED "DISABLED"
+ IDS_INIT_FAILED "Initialization Failed"
+ IDS_INSERT_DISK "Insert Disk"
+ IDS_MEGABYTES_ABBREV "MB"
+ IDS_UNAVAILABLE_DATA "?"
+ IDS_BYTES_DECORATION "%s bytes"
+ IDS_MEG_DECORATION "(%s MB)"
+ IDS_READY "Ready"
+ IDS_NOTREADY "Not Ready"
+ IDS_NO_CONFIG_INFO "Configuration information not available"
+
+#if i386
+ IDS_ACTIVEPARTITION "Active partition"
+#endif
+ IDS_CRTPART_CAPTION_P "Create Primary Partition"
+ IDS_CRTPART_CAPTION_E "Create Extended Partition"
+ IDS_CRTPART_CAPTION_L "Create Logical Drive"
+ IDS_CRTPART_MIN_P "Minimum size for the partition is"
+ IDS_CRTPART_MAX_P "Maximum size for the partition is"
+ IDS_CRTPART_MIN_L "Minimum size for the logical drive is"
+ IDS_CRTPART_MAX_L "Maximum size for the logical drive is"
+ IDS_CRTPART_SIZE_P "&Create partition of size"
+ IDS_CRTPART_SIZE_L "&Create logical drive of size"
+
+ IDS_CRTPSTRP_CAPTION "Create Stripe Set With Parity"
+ IDS_CRTSTRP_CAPTION "Create Stripe Set"
+ IDS_CRTSTRP_MIN "Minimum total size for the stripe set is"
+ IDS_CRTSTRP_MAX "Maximum total size for the stripe set is"
+ IDS_CRTSTRP_SIZE "&Create stripe set of total size"
+
+ IDS_CRTVSET_CAPTION "Create Volume Set"
+ IDS_EXPVSET_CAPTION "Extend Volume Set"
+ IDS_CRTVSET_MIN "Minimum total size for the volume set is"
+ IDS_CRTVSET_MAX "Maximum total size for the volume set is"
+ IDS_CRTVSET_SIZE "&Create volume set of total size"
+
+ IDS_STATUS_STRIPESET "Stripe set #%u"
+ IDS_STATUS_PARITY "Stripe set with parity #%u [%s]"
+ IDS_DLGCAP_PARITY "Stripe set with parity #%u"
+ IDS_STATUS_VOLUMESET "Volume set #%u"
+ IDS_STATUS_MIRROR "Mirror set #%u [%s]"
+ IDS_DLGCAP_MIRROR "Mirror set #%u"
+
+ IDS_UNKNOWNTYPE "?"
+
+ // Note: these must be in same order as BRUSH_xxx constants in const.h
+
+ IDS_LEGEND_PRIMARY "Primary partition"
+ IDS_LEGEND_LOGICAL "Logical drive"
+ IDS_LEGEND_STRIPESET "Stripe set"
+ IDS_LEGEND_PARITYSET "Stripe set with parity"
+ IDS_LEGEND_MIRROR "Mirror set"
+ IDS_LEGEND_VOLUMESET "Volume set"
+
+ IDS_PARTITION_FREE "Free Space"
+ IDS_PARTITION_XENIX1 "XENIX1"
+ IDS_PARTITION_XENIX2 "XENIX2"
+ IDS_PARTITION_OS2_BOOT "OS/2 Boot Manager"
+ IDS_PARTITION_EISA "EISA Utilities"
+ IDS_PARTITION_UNIX "Unix"
+ IDS_PARTITION_POWERPC "PowerPC Boot"
+
+ IDS_MENUANDITEM "%s - %s"
+
+ IDS_CHANGEFORMAT "&Format..."
+ IDS_FORMAT "&Format..."
+
+ IDS_NOOPERATIONS "<< No valid operations >>"
+
+ IDS_SOURCE_PATH "\\Software\\Microsoft\\Windows NT\\CurrentVersion"
+ IDS_SOURCE_PATH_NAME "SourcePath"
+
+#if defined( DBLSPACE_ENABLED )
+ //
+ // DoubleSpace support strings
+ //
+
+ IDS_DBLSPACE_DELETE "Delete DoubleSpace Volume"
+ IDS_DBLSPACE_MOUNTED "DoubleSpace Volume currently mounted as drive"
+ IDS_DBLSPACE_DISMOUNTED "DoubleSpace Volume is dismounted"
+ IDS_WITH_DBLSPACE " with DoubleSpace Volumes"
+ IDS_MOUNT "Mount"
+ IDS_DISMOUNT "Dismount"
+ IDS_CREATING_DBLSPACE "Creating DoubleSpace volume..."
+ IDS_DBLSPACECOMPLETE "Creation of DoubleSpace volume is complete"
+#endif // DBLSPACE_ENABLED
+
+
+//
+// Volume view column titles
+//
+
+ IDS_VV_VOLUME "Volume"
+ IDS_VV_NAME "Name"
+ IDS_VV_CAPACITY "Capacity"
+ IDS_VV_FREESPACE "Free Space"
+ IDS_VV_PCTFREE "% Free"
+ IDS_VV_FORMAT "Format"
+ IDS_VV_FT "Fault Tolerant?"
+ IDS_VV_VOLTYPE "Volume Type"
+ IDS_VV_OVERHEAD "Fault Tolerance Overhead"
+ IDS_VV_STATUS "Status"
+
+//
+// Volume view column data strings
+//
+
+ IDS_VOLTYPE_MIRROR "Mirror set"
+ IDS_VOLTYPE_STRIPE "Stripe set"
+ IDS_VOLTYPE_PARITY "Stripe set with parity"
+ IDS_VOLTYPE_VOLSET "Volume set"
+ IDS_VOLTYPE_SIMPLE ""
+
+ IDS_FT_YES "yes"
+ IDS_FT_NO "no"
+
+ IDS_FTSTATUS_HEALTHY "Healthy"
+ IDS_FTSTATUS_BROKEN "Broken"
+ IDS_FTSTATUS_RECOVERABLE "Recoverable"
+ IDS_FTSTATUS_INITIALIZING "Initializing"
+ IDS_FTSTATUS_REGENERATING "Regenerating"
+ IDS_FTSTATUS_REGENERATED "Regenerated"
+ IDS_FTSTATUS_NEW "New"
+ IDS_FTSTATUS_NONE ""
+
+//
+// Miscellaneous
+//
+
+ IDS_PROPERTIES "Properties..."
+
+
+//
+// strings for menu help
+//
+
+//
+// Partition menu
+//
+
+ IDS_HELP_CREATE "Create Partition"
+ IDS_HELP_CREATEEX "Create Extended Partition"
+ IDS_HELP_DELETE "Delete"
+ IDS_HELP_CREATEVOLSET "Create Volume Set"
+ IDS_HELP_EXTENDVOLSET "Extend Volume Set"
+ IDS_HELP_CREATESTRIPE "Create Stripe Set"
+#ifdef i386
+ IDS_HELP_MARKACTIVE "Mark Active"
+#else // i386
+ IDS_HELP_SECURE "Secure System Partition"
+#endif // i386
+
+//
+// Configuration sub-menu
+//
+
+ IDS_HELP_SAVECONFIG "Saves the disk configuration to floppy"
+ IDS_HELP_RESTORECONFIG "Restores the disk configuration from floppy"
+ IDS_HELP_SEARCHCONFIG "Searches for another installation of Windows NT"
+
+ IDS_HELP_PARTITIONCOMMIT "Commit partition changes to disk"
+ IDS_HELP_QUIT "Exit"
+
+//
+// Fault-tolerance menu
+//
+
+ IDS_HELP_ESTABLISHMIRROR "Establish Mirror"
+ IDS_HELP_BREAKMIRROR "Break Mirror"
+ IDS_HELP_CREATEPSET "Creates a fault tolerant stripe set with parity"
+ IDS_HELP_REGENSTRIPE "Regenerates a stripe set"
+
+//
+// Tools menu
+//
+
+ IDS_HELP_FORMAT "Format"
+ IDS_HELP_DRIVELET "Reassigns a volume's drive letter"
+#if defined( DBLSPACE_ENABLED )
+ IDS_HELP_DBLSPACE "Configures DoubleSpace volumes"
+ IDS_HELP_AUTOMOUNT "Toggles whether or not DoubleSpace volumes are mounted"
+#endif // DBLSPACE_ENABLED
+ IDS_HELP_PROPERTIES "Properties"
+
+//
+// View menu
+//
+
+ IDS_HELP_VOLUMESVIEW "Volumes"
+ IDS_HELP_DISKSVIEW "Disk Configuration"
+ IDS_HELP_REFRESH "Reload volume information"
+
+//
+// Options menu
+//
+
+ IDS_HELP_TOOLBAR "Displays or hides the toolbar"
+ IDS_HELP_STATUSBAR "Displays or hides the status bar"
+ IDS_HELP_LEGEND "Displays or hides the legend"
+ IDS_HELP_COLORS "Colors and Patterns"
+ IDS_HELP_OPTIONSDISK "Controls the display of disks in the disk view"
+ IDS_HELP_REGIONDISPLAY "Region Display"
+ IDS_HELP_CUSTTOOLBAR "Customizes the toolbar"
+
+//
+// Help menu
+//
+
+ IDS_HELP_HELPCONTENTS "Help"
+ IDS_HELP_HELPSEARCH "Searches for a topic in Disk Administrator help"
+ IDS_HELP_HELPHELP "Displays information about using help"
+ IDS_HELP_HELPABOUT "Displays information about Disk Administrator"
+
+//
+// Debug menu (only for debug builds)
+//
+
+#if DBG == 1
+ IDS_HELP_DELETEALL "If checked, then all partitions can be deleted"
+ IDS_HELP_LOG "Write internal data structures to c:\\windisk.log"
+ IDS_HELP_RAID "RAID bug database information"
+#endif // DBG == 1
+
+//
+// Things not on top-level menus
+//
+
+ IDS_HELP_NOVALIDOPERATION "No operations are valid with the current selection"
+
+//
+// For the menus themselves:
+//
+
+ IDS_HELP_MENU_PARTITION "Commands for operating on partitions"
+ IDS_HELP_MENU_FT "Commands for NT fault tolerance configuration"
+ IDS_HELP_MENU_VOLUMES "Commands for administering volumes"
+ IDS_HELP_MENU_VIEW "Commands for determining how information is displayed"
+ IDS_HELP_MENU_OPTIONS "Commands for setting options"
+ IDS_HELP_MENU_HELP "Commands for displaying Disk Administrator help"
+
+ IDS_HELP_MENU_CONFIG "Commands to save or restore the disk configuration"
+
+#if DBG == 1
+ IDS_HELP_MENU_DEBUG "Commands to aid debugging"
+#endif // DBG == 1
+
+//
+// File system strings
+//
+
+ IDS_LONG_FAT "FAT (File Allocation Table; Windows NT, Windows, DOS, OS/2)"
+ IDS_LONG_NTFS "NTFS (New Technology File System; Windows NT)"
+#ifdef SUPPORT_OFS
+ IDS_LONG_OFS "OFS (Object File System; Windows Cairo)"
+#endif // SUPPORT_OFS
+
+END
+
+
+////////////////////////////////////////////////////////////////////////////
+
+IDFDISK MENU
+BEGIN
+ POPUP "&Partition"
+ BEGIN
+ MENUITEM "&Create..." ,IDM_PARTITIONCREATE , GRAYED
+ MENUITEM "Create &Extended..." ,IDM_PARTITIONCREATEEX, GRAYED
+ MENUITEM "&Delete" ,IDM_PARTITIONDELETE , GRAYED
+ MENUITEM SEPARATOR
+ MENUITEM "Create &Volume Set..." ,IDM_FTCREATEVOLUMESET, GRAYED
+ MENUITEM "Ex&tend Volume Set..." ,IDM_FTEXTENDVOLUMESET, GRAYED
+ MENUITEM SEPARATOR
+ MENUITEM "Create &Stripe Set..." ,IDM_FTCREATESTRIPE , GRAYED
+ MENUITEM SEPARATOR
+#if i386
+ MENUITEM "Mark &Active" ,IDM_PARTITIONACTIVE , GRAYED
+#else
+ MENUITEM "Sec&ure System Partition",IDM_SECURESYSTEM
+#endif
+ POPUP "Confi&guration"
+ BEGIN
+ MENUITEM "&Save..." ,IDM_CONFIGSAVE
+ MENUITEM "&Restore..." ,IDM_CONFIGRESTORE
+ MENUITEM "Sear&ch..." ,IDM_CONFIGMIGRATE
+ END
+
+ MENUITEM SEPARATOR
+ MENUITEM "C&ommit Changes Now..." ,IDM_PARTITIONCOMMIT , GRAYED
+ MENUITEM "E&xit" ,IDM_QUIT
+ END
+
+ POPUP "&Fault Tolerance"
+ BEGIN
+ MENUITEM "Establish &Mirror" ,IDM_FTESTABLISHMIRROR, GRAYED
+ MENUITEM "&Break Mirror..." ,IDM_FTBREAKMIRROR , GRAYED
+ MENUITEM SEPARATOR
+ MENUITEM "Create Stripe Set with &Parity...",IDM_FTCREATEPSTRIPE , GRAYED
+ MENUITEM "&Regenerate" ,IDM_FTRECOVERSTRIPE , GRAYED
+ END
+
+ POPUP "&Tools"
+ BEGIN
+ MENUITEM "&Format..." ,IDM_VOL_FORMAT
+ MENUITEM "Assign Dri&ve Letter...",IDM_VOL_LETTER , GRAYED
+ MENUITEM "Eject" ,IDM_VOL_EJECT , GRAYED
+#if defined( DBLSPACE_ENABLED )
+ MENUITEM SEPARATOR
+ MENUITEM "&DoubleSpace Volumes...",IDM_VOL_DBLSPACE , GRAYED
+ MENUITEM "&Automount DoubleSpace Floppies",IDM_VOL_AUTOMOUNT, GRAYED
+#endif // DBLSPACE_ENABLED
+
+ MENUITEM SEPARATOR
+ MENUITEM "P&roperties" ,IDM_VOL_PROPERTIES
+
+ END
+
+ POPUP "&View"
+ BEGIN
+ MENUITEM "&Volumes\tCtrl+V" ,IDM_VIEWVOLUMES
+ MENUITEM "&Disk Configuration\tCtrl+D" ,IDM_VIEWDISKS
+ MENUITEM SEPARATOR
+ MENUITEM "R&efresh\tF5" ,IDM_VIEW_REFRESH
+ END
+
+ POPUP "&Options"
+ BEGIN
+ MENUITEM "&Toolbar\tCtrl+T" ,IDM_OPTIONSTOOLBAR
+ MENUITEM "&Status Bar\tCtrl+S" ,IDM_OPTIONSSTATUS
+ MENUITEM "&Legend\tCtrl+L" ,IDM_OPTIONSLEGEND
+ MENUITEM SEPARATOR
+ MENUITEM "&Colors and Patterns..." ,IDM_OPTIONSCOLORS
+ MENUITEM "&Disk Display..." ,IDM_OPTIONSDISK
+ MENUITEM "&Region Display..." ,IDM_OPTIONSDISPLAY
+ MENUITEM SEPARATOR
+ MENUITEM "Customize Tool&bar..." ,IDM_OPTIONSCUSTTOOLBAR
+ END
+
+ POPUP "&Help"
+ BEGIN
+ MENUITEM "&Contents" ,IDM_HELPCONTENTS
+ MENUITEM "&Search for Help on..." ,IDM_HELPSEARCH
+ MENUITEM "&How to Use Help" ,IDM_HELPHELP
+ MENUITEM SEPARATOR
+ MENUITEM "&About Disk Administrator..." ,IDM_HELPABOUT
+#if DBG == 1
+ MENUITEM SEPARATOR
+ POPUP "&DEBUG"
+ BEGIN
+ MENUITEM "&Allow delete all partitions",IDM_DEBUGALLOWDELETES
+ MENUITEM "&Log partition info" ,IDM_DEBUGLOG
+ END
+ MENUITEM "&RAID Information..." ,IDM_RAID
+#endif // DBG == 1
+ END
+
+END
+
+////////////////////////////////////////////////////////////////////////////
+
+ID_FRAME_ACCELERATORS ACCELERATORS
+{
+ "^V", IDM_VIEWVOLUMES
+ "^D", IDM_VIEWDISKS
+ "^T", IDM_OPTIONSTOOLBAR
+ "^S", IDM_OPTIONSSTATUS
+ "^L", IDM_OPTIONSLEGEND
+ VK_F5, IDM_VIEW_REFRESH, VIRTKEY
+ VK_F1, IDM_HELPCONTENTS, VIRTKEY
+ VK_RETURN,IDM_VOL_PROPERTIES,VIRTKEY,ALT
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+//
+// The following data is used for the nice drive bitmap for the volume
+// property page
+//
+
+IDB_HARDDISK BITMAP LOADONCALL HARD.BMP
+IDB_CDROM BITMAP LOADONCALL CDR.BMP
+
+/*
+ * This resource defines a word flag a word and 8 additional words
+ *
+ * The flag defines whether this drive bitmap uses an ellips or a
+ * parallelogram to represent its free/used space. USETYPE_ELLIPS,
+ * USETYPE_BARH, USETYPE_BARV and USETYPE_NONE are the four defines
+ * for these flag values.
+ *
+ * USETYPE_NONE is for never-writable drives (like CD-ROM).
+ * USETYPE_ELLIPS is for circular type drives (Fixed Floppy).
+ * USETYPE_BARH is a horizontal parallelogram.
+ * USETYPE_BARV is a verticle parallelogram.
+ *
+ * The word is the "3-D effect" height/width for the parallelogram or ellips.
+ * NOTE that the 3-D effect can be disabled by specifying a height/width
+ * value of 0. Also note that with 3-D effect disabled, the parallelogram
+ * can be turned into a rectangle.
+ *
+ * The following 8 words are either one rect for USETYPE_ELLIPS or
+ * four points for USETYPE_BARH or USETYPE_BARV.
+ *
+ * For USETYPE_ELLIPS the first four words form a RECT structure
+ * which specifies the bounding rectangle for the ellips. The other
+ * 4 words must be 0. It is critical that these extra words be 0
+ * as they are reserved for future expansion.
+ *
+ * For USETYPE_BAR? the 8 words form an array of 4 POINT structures.
+ *
+ * USETYPE_BARH (0.y)==(1.y) and (3.y)==(2.y)
+ *
+ * 0 _____________ 1
+ * \ \
+ * 3-D-> \ \
+ * \ \
+ * 3 ------------- 2
+ * ^
+ * 3-D
+ *
+ * USETYPE_BARV (0.x)==(3.x) and (1.x)==(2.x)
+ *
+ * 1
+ * /|
+ * / |
+ * / |
+ * 0 | |
+ * | |
+ * | | <- 3-D
+ * | |
+ * | |
+ * | |
+ * | |
+ * | | 2
+ * | /
+ * | / <- 3-D
+ * |/
+ *
+ * 3
+ *
+ * NOTE that the ellips RECT INCLUDES the 3-D effect but that the
+ * parallelogram points DO NOT.
+ *
+ */
+
+ELLIPRESOURCE IDB_HARDDISK DISCARDABLE LOADONCALL
+BEGIN
+ USETYPE_ELLIPS, /* FLAG */
+ 3, /* 3-D effect height/width */
+ 39, /* Left */
+ 26, /* Top */
+ 145, /* Right */
+ 91, /* Bottom */
+ 0,
+ 0,
+ 0,
+ 0
+END
+
+ELLIPRESOURCE IDB_CDROM DISCARDABLE LOADONCALL
+BEGIN
+ USETYPE_NONE, /* FLAG */
+ 0, /* 3-D effect height/width */
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+END
+
+////////////////////////////////////////////////////////////////////////////
+
+#include "dialogs.dlg"
+
+#if defined( DBLSPACE_ENABLED )
+#include "dblspace.h"
+#include "dblspace.dlg"
+#endif // DBLSPACE_ENABLED
+
+#include "ftreg.h"
+#include "ftreg.dlg"
+
+#if 0
+#include "messages.mc" // trick build.exe into this transitive dependency
+#endif // 0
+#include "messages.rc"
+
+////////////////////////////////////////////////////////////////////////////
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Disk Partitioning Utility"
+#define VER_INTERNALNAME_STR "fdisk\0"
+#define VER_ORIGINALFILENAME_STR "WINDISK.EXE"
+
+#include "common.ver"
diff --git a/private/utils/windisk/src/xtra16.bmp b/private/utils/windisk/src/xtra16.bmp
new file mode 100644
index 000000000..e37d7b2d2
--- /dev/null
+++ b/private/utils/windisk/src/xtra16.bmp
Binary files differ
diff --git a/private/utils/windisk/types/daexts.idl b/private/utils/windisk/types/daexts.idl
new file mode 100644
index 000000000..e53d08b94
--- /dev/null
+++ b/private/utils/windisk/types/daexts.idl
@@ -0,0 +1,233 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: daexts.idl
+//
+// Contents: Types for the windisk extension interfaces
+//
+// History: 4-Jan-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+LOCAL_INTERFACE(cbf36b48-03e1-101b-b36a-00dd01101592)
+interface DAExtensionTypes
+{
+
+
+// disable "nonstandard extension used : zero-sized array in struct/union"
+// #pragma warning(disable:4200)
+
+//////////////////////////////////////////////////////////////////////////////
+
+//
+// HRESULT error codes
+//
+
+cpp_quote("#define DA_E_OPERATIONFAILED MAKE_SCODE(SEVERITY_ERROR, FACILITY_NULL, 1000)")
+cpp_quote("#define DA_E_OPERATIONCANCELLED MAKE_SCODE(SEVERITY_ERROR, FACILITY_NULL, 1001)")
+cpp_quote("#define DA_E_VOLUMEINFOCHANGED MAKE_SCODE(SEVERITY_SUCCESS,FACILITY_NULL,1002)")
+
+//////////////////////////////////////////////////////////////////////////////
+
+//
+// VolumeInfoBlockType:
+//
+// This information identifies a volume to volume extension code.
+// It will contain the minimal useful set of information about a
+// volume, preferably only a drive letter. If any information
+// in addition to the drive letter is useful, we'll add it here.
+//
+// A volume can be identified by a Win32/DOS drive letter, if a
+// drive letter is assigned (and all volumes have drive letters),
+// e.g. 'C'. From this, the ISV can call the following Win32 APIs:
+// -- GetDriveType, but in most/all cases it will be a Fixed drive
+// -- GetDiskFreeSpace, to get allocation unit information (sectors
+// per unit, bytes per sector, # free units, total # of units)
+// -- GetVolumeInformation, to get the volume name, serial number,
+// maximum component length of a filename component, a set of
+// flags (case sensitive/insensitive, whether filename case is
+// preserved, whether UNICODE filenames are supported), and the
+// filesystem name
+//
+// Note that you can use GetLogicalDrives() and
+// GetLogicalDriveStrings() to determine which drive letters are
+// in use.
+//
+// An alternate volume identifier is an NT object path, e.g.,
+// \Device\HardDisk0\Partition0. From this the ISV can call
+// NtOpenFile followed by NtQueryVolumeInformationFile. This provides
+// the volume label, volume serial number, volume creation time,
+// allocation information (total units, available units, sectors
+// per unit, bytes per sector), device information, and perhaps more.
+//
+// All the IFS entrypoints (Format, ChkDsk, Convert) take an NT
+// object path.
+//
+// The utility routine GetDeviceObject() converts between a Win32 drive
+// letter and an NT ``\Device\...'' object path by following the
+// ``\DosDevices\X:'' symbolic link.
+//
+// I suppose it is possible to take an NT object path and search
+// the targets of the items in the \DosDevices directory to see if
+// any point to it, and then test if the \DosDevices object has
+// the form of a Win32 drive letter link. Seems ugly, though.
+//
+
+typedef struct _VolumeInfoBlockType
+{
+ WCHAR wcDriveLetter;
+} VolumeInfoBlockType;
+
+
+
+//
+// MenuItemType:
+//
+
+typedef struct _MenuItemType
+{
+ WCHAR* pszMenu; // text of menu item
+ WCHAR* pszMenuHelp; // short menu item help string
+ INT iIndex;
+ IDAMenuDispatch* pMenuDispatch;
+} MenuItemType;
+
+
+//
+// MenuType:
+//
+// A menu is a counted-array of menu items. These menu items will
+// be added to the context-menu of an appropriate item (a FAT
+// volume, for instance), as well as to the menu bar as appropriate.
+//
+
+typedef struct _MenuType
+{
+ INT cMenuItems; // Number of items on the menu
+ MenuItemType* aMenuItems; //BUGBUG: should be counted array???
+ // Array of 'cMenuItems' items, in
+ //... counted-array form.
+} MenuType;
+
+
+//
+// PropPageType:
+//
+// PropPageType describes a property page, by a moniker to the
+// property page. This is required by the property engine. I
+// have no idea what a moniker to a page will ``look'' like.
+//
+
+typedef struct _PropPageType
+{
+ CLSID* pPage;
+} PropPageType;
+
+
+//
+// PropPageSetType:
+//
+// PropPageSetType describes a set of property pages, as a counted
+// array of property pages.
+//
+typedef struct _PropPageSetType
+{
+ INT cPropPages; // Count of property pages
+ PropPageType* aPropPages; //BUGBUG: should be counted array????
+ // Array of 'cPropPages' items, in
+ //... counted-array form.
+} PropPageSetType;
+
+
+
+//
+// VolumeInfoType:
+//
+// VolumeInfoType encapsulates all the data provided by a volume
+// extension class to the Disk Administrator. The data:
+//
+// pwszDescriptiveName: A descriptive name for the extension,
+// e.g. ``Norton Utilities OFS de-fragmentation''
+//
+// pwszShortName: A short name for the extension, e.g. ``Norton
+// De-frag''
+//
+// mnuOps: Information about extension operations that can be
+// put in the ``Volume'' menu of Disk Administrator, as well
+// as on the context-menu for this volume.
+//
+// propPages: Information about property sheet pages specific
+// to this format.
+//
+
+typedef struct _VolumeInfoType
+{
+ LPWSTR pwszDescriptiveName;
+ LPWSTR pwszShortName;
+ MenuType mnuOps;
+ PropPageSetType propPages;
+} VolumeInfoType;
+
+
+
+//
+// HardDiskInfoBlockType:
+//
+// This information identifies a hard disk to hard disk
+// extension code. It will contain the minimal useful
+// set of information about a hard disk, preferably only a
+// disk number. If any additional information is useful,
+// we'll add it here.
+//
+// Disk numbers start at 0, and correspond to the value of
+// N in the NT object path \Device\HardDiskN. From the NT
+// object path, one can send any number of I/O controls to
+// the driver requesting information and operations. See
+// ntdddisk.h for details.
+//
+
+typedef struct _HardDiskInfoBlockType
+{
+ ULONG ulDiskNumber;
+} HardDiskInfoBlockType;
+
+
+
+//
+// HardDiskInfoType:
+//
+// HardDiskInfoType encapsulates all the data provided by a hard
+// disk extension class to the Disk Administrator. The data:
+//
+// pwszDescriptiveName: A descriptive name for the hard disk
+// type, e.g. ``Hard disk''
+//
+// pwszShortName: A short name for the hard disk type, e.g. ``Hard''
+//
+// fCapabilities: A bitmask of capabilities:
+// DA_HD_FAULT_TOLERANT: if set, the ``hard disk'' is fault
+// tolerant. Disk Administrator will (probably) not allow
+// software fault tolerant volumes to span fault tolerant
+// hardware.
+//
+// mnuOps: Information about hard disk type operations that can
+// be put in the ``Volume'' menu of Disk Administrator, as
+// well as on the context-menu for volumes of this hardware type.
+//
+// propPages: Information about property sheet pages specific to this
+// hardware type.
+//
+
+cpp_quote("#define DA_HD_FAULT_TOLERANT 0x1")
+
+typedef struct _HardDiskInfoType
+{
+ LPWSTR pwszDescriptiveName;
+ LPWSTR pwszShortName;
+ ULONG fCapabilities;
+ MenuType mnuOps;
+ PropPageSetType propPages;
+} HardDiskInfoType;
+
+}
diff --git a/private/utils/windisk/types/dahard.idl b/private/utils/windisk/types/dahard.idl
new file mode 100644
index 000000000..bf2c1bb98
--- /dev/null
+++ b/private/utils/windisk/types/dahard.idl
@@ -0,0 +1,39 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: dahard.idl
+//
+// Contents: IDAHardDiskInfo interface definition
+//
+// History: 4-Jan-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+LOCAL_INTERFACE(f2eb2278-3915-101b-ab21-00000b65c03c)
+interface IDAHardDiskInfo : IUnknown
+{
+
+ //
+ // Claim: Sets *pfInterested to TRUE if this extension class
+ // wants to provide information and UI for the hard
+ // disk indicated by pInfo.
+ //
+
+ HRESULT
+ Claim(
+ [in] HardDiskInfoBlockType* pInfo,
+ [out] BOOL* pfInterested
+ );
+
+ //
+ // QueryInfo: The ppInfo pointer is filled in with the address of a
+ // structure with all the information needed when
+ // specifying a hard disk
+ //
+
+ HRESULT
+ QueryInfo(
+ [out] HardDiskInfoType** ppInfo
+ );
+}
diff --git a/private/utils/windisk/types/damenu.idl b/private/utils/windisk/types/damenu.idl
new file mode 100644
index 000000000..6dcf038cd
--- /dev/null
+++ b/private/utils/windisk/types/damenu.idl
@@ -0,0 +1,42 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: damenu.idl
+//
+// Contents: IDAMenuDispatch interface definition
+//
+// History: 7-Jan-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+LOCAL_INTERFACE(f2eb2279-3915-101b-ab21-00000b65c03c)
+interface IDAMenuDispatch : IUnknown
+{
+ //
+ // This method is used to handle extension menu operations. The
+ // arguments are as follows:
+ //
+ // hwndParent -- The parent window handle for any UI
+ // DriveName -- DOS device name for the drive, e.g., "C:"
+ // Item -- An integer indicating which menu item was invoked.
+ // The item number is the number assigned to the menu
+ // item by the extension writer, and passed to Disk
+ // Administrator via the QueryInfo method.
+ //
+ // The return value is an HRESULT, one of the following:
+ //
+ // S_OK -- No problems
+ // E_FAIL -- An error occurred. For example, the Item value might
+ // not have been understood (an internal error to the
+ // extension code), or the menu operation may have failed.
+ //
+
+ HRESULT
+ MenuDispatch(
+ [in] HWND hwndParent,
+ [in] LPWSTR DriveName,
+ [in] UINT Item
+ );
+
+}
diff --git a/private/utils/windisk/types/davol.idl b/private/utils/windisk/types/davol.idl
new file mode 100644
index 000000000..7214d7a90
--- /dev/null
+++ b/private/utils/windisk/types/davol.idl
@@ -0,0 +1,39 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: davol.idl
+//
+// Contents: IDAVolumeInfo interface definition
+//
+// History: 4-Jan-94 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+LOCAL_INTERFACE(f2eb227a-3915-101b-ab21-00000b65c03c)
+interface IDAVolumeInfo : IUnknown
+{
+
+ //
+ // Claim: Sets *pfInterested to TRUE if this extension class wants
+ // to provide information and UI for the volume indicated by pInfo.
+ //
+
+ HRESULT
+ Claim(
+ [in] VolumeInfoBlockType* pInfo,
+ [out] BOOL* pfInterested
+ );
+
+ //
+ // QueryInfo: The ppInfo pointer is filled in with the address
+ // of a structure with all the information needed when specifying a
+ // volume extension
+ //
+
+ HRESULT
+ QueryInfo(
+ [out] VolumeInfoType** ppInfo
+ );
+}
diff --git a/private/utils/windisk/types/guids.h b/private/utils/windisk/types/guids.h
new file mode 100644
index 000000000..664c02da0
--- /dev/null
+++ b/private/utils/windisk/types/guids.h
@@ -0,0 +1,24 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: guids.h
+//
+// Contents: non-interface GUIDs
+//
+// History: 5-May-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+//
+// Windisk extension classes
+//
+
+DEFINE_GUID(CLSID_KDA_Hard, \
+ 0xf2eb226e, 0x3915, 0x101b, \
+ 0xab, 0x21, 0x00, 0x00, 0x0b, 0x65, 0xc0, 0x3c);
+
+DEFINE_GUID(CLSID_KDA_HardMenu, \
+ 0xf2eb226f, 0x3915, 0x101b, \
+ 0xab, 0x21, 0x00, 0x00, 0x0b, 0x65, 0xc0, 0x3c);
diff --git a/private/utils/windisk/types/readme.txt b/private/utils/windisk/types/readme.txt
new file mode 100644
index 000000000..8871b3f3d
--- /dev/null
+++ b/private/utils/windisk/types/readme.txt
@@ -0,0 +1,2 @@
+This directory contains the "types" information used to define the Disk
+Administrator extension interfaces.
diff --git a/private/utils/windisk/util/debug.cxx b/private/utils/windisk/util/debug.cxx
new file mode 100644
index 000000000..f1a789c68
--- /dev/null
+++ b/private/utils/windisk/util/debug.cxx
@@ -0,0 +1,95 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1994.
+//
+// File: debug.cxx
+//
+// Contents: Debug helper routines
+//
+// Functions:
+// FormatGuid
+// DumpGuid
+//
+// History: 20-May-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#if DBG == 1
+
+#ifdef WINDISK_EXTENSIONS
+
+#include "headers.hxx"
+
+#include <util.hxx>
+
+//+---------------------------------------------------------------------------
+//
+// Function: FormatGuid
+//
+// Synopsis: Format a GUID into a string for possible printing. The
+// string must be GUID_STRING_LEN characters long.
+//
+// Arguments: IN [guid] -- a GUID
+// OUT [wszGuid] -- string representation of GUID
+//
+// Returns: nothing
+//
+// History: 20-May-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+FormatGuid(
+ IN const GUID& guid,
+ OUT PWSTR GuidString
+ )
+{
+ wsprintf(GuidString,
+ TEXT("%08lx-%04hx-%04hx-%02x%02x%02x%02x%02x%02x%02x%02x"),
+ guid.Data1,
+ guid.Data2,
+ guid.Data3,
+ guid.Data4[0],
+ guid.Data4[1],
+ guid.Data4[2],
+ guid.Data4[3],
+ guid.Data4[4],
+ guid.Data4[5],
+ guid.Data4[6],
+ guid.Data4[7]);
+}
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: DumpGuid
+//
+// Synopsis: Dump a guid to the debugger
+//
+// Arguments: IN [Level] -- debug level, e.g. DEB_ITRACE
+// IN [Message] -- a message to precede the guid
+// IN [guid] -- the GUID
+//
+// Returns: nothing
+//
+// History: 11-Nov-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+DumpGuid(
+ IN UINT Level,
+ IN PWSTR Message,
+ IN const GUID& guid
+ )
+{
+ WCHAR wszGuid[GUID_STRING_LEN];
+
+ FormatGuid(guid, wszGuid);
+ daDebugOut((Level, "%ws%ws\n", Message, wszGuid));
+}
+
+#endif // WINDISK_EXTENSIONS
+
+#endif // DBG == 1
diff --git a/private/utils/windisk/util/headers.hxx b/private/utils/windisk/util/headers.hxx
new file mode 100644
index 000000000..756a6a06c
--- /dev/null
+++ b/private/utils/windisk/util/headers.hxx
@@ -0,0 +1,32 @@
+//+-------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: headers.hxx
+//
+// Contents: Headers for windisk utilities library.
+//
+// History: 14-Jan-94 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+extern "C"
+{
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <ntddnfs.h>
+}
+
+#include <windows.h>
+#include <windowsx.h>
+
+#ifdef WINDISK_EXTENSIONS
+// #include <ole2.h> // GUID definition
+#endif // WINDISK_EXTENSIONS
+
+#include <stdlib.h>
+#include <debug.h>
+
+#include <dacommon.h>
diff --git a/private/utils/windisk/util/makefile b/private/utils/windisk/util/makefile
new file mode 100644
index 000000000..14f79b701
--- /dev/null
+++ b/private/utils/windisk/util/makefile
@@ -0,0 +1 @@
+!include $(NTMAKEENV)\makefile.def
diff --git a/private/utils/windisk/util/sources b/private/utils/windisk/util/sources
new file mode 100644
index 000000000..ab12ffb1b
--- /dev/null
+++ b/private/utils/windisk/util/sources
@@ -0,0 +1,17 @@
+!include ..\windisk.mk
+
+MINORCOMP= util
+
+TARGETNAME= util
+TARGETPATH= obj
+TARGETTYPE= LIBRARY
+
+UMTYPE= windows
+
+INCLUDES=\
+ ..\inc; \
+ $(INCLUDES)
+
+SOURCES=\
+ debug.cxx \
+ util.cxx
diff --git a/private/utils/windisk/util/util.cxx b/private/utils/windisk/util/util.cxx
new file mode 100644
index 000000000..ca47cfd09
--- /dev/null
+++ b/private/utils/windisk/util/util.cxx
@@ -0,0 +1,427 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: util.cxx
+//
+// Contents: Utility routines
+//
+// History: 26-May-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+#include "headers.hxx"
+
+#define MAX_RESOURCE_STRING_LEN 256
+#define MAXLABELLEN 256
+#define MAXTITLELEN 256
+#define MAXMESSAGELEN 350
+#define MAXERRORLEN 256
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: MyMessageBox
+//
+// Synopsis: Same as Win32 MessageBox, but takes resource identifiers
+// and loads the strings to display from the resource file.
+// Also, the message box is made task-modal.
+//
+// Arguments: [hInstance] -- the instance to load the strings from
+// [hwndOwner] -- handle of owner window
+// [idTitle] -- resource ID of message box title string
+// [idMessage] -- resource ID of message box message string
+// [fuStyle] -- style of message box (see MessageBox() API)
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+INT
+MyMessageBox(
+ IN HINSTANCE hInstance,
+ IN HWND hwndOwner,
+ IN DWORD idMessage,
+ IN DWORD idTitle,
+ IN UINT fuStyle
+ )
+{
+ TCHAR szTitle[MAXTITLELEN];
+ TCHAR szMessage[MAXMESSAGELEN];
+
+ LoadString(hInstance, idTitle, szTitle, ARRAYLEN(szTitle));
+ LoadString(hInstance, idMessage, szMessage, ARRAYLEN(szMessage));
+
+ return MessageBox(hwndOwner, szMessage, szTitle, fuStyle);
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: MySetDlgItemText
+//
+// Synopsis: Same as Win32 SetDlgItemText, but takes a resource ID
+// instead of a string pointer.
+//
+// Arguments: [hInstance] -- the instance to load the strings from
+// [hwndDlg] -- handle of dialog box
+// [idControl] -- identifier of control
+// [wID] -- resource identifier
+//
+// Returns: return TRUE on success
+//
+// History: 8-Sep-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+BOOL
+MySetDlgItemText(
+ IN HINSTANCE hInstance,
+ IN HWND hwndDlg,
+ IN int idControl,
+ IN UINT wID
+ )
+{
+ WCHAR szBuf[MAX_RESOURCE_STRING_LEN];
+
+ int cch = LoadString(
+ hInstance,
+ wID,
+ szBuf,
+ ARRAYLEN(szBuf));
+
+ return (0 != cch) && SetDlgItemText(hwndDlg, idControl, szBuf);
+}
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: FindCenterValues
+//
+// Synopsis: Calculate the values for use in centering a window
+//
+// Arguments: [hwndToCenter] -- the window to center
+// [hwndContext] -- the window to center with respect to.
+// If NULL, center with respect to the screen.
+//
+// [px] -- x value
+// [py] -- y value
+// [pw] -- width value
+// [ph] -- height value
+//
+// Returns: none
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+VOID
+FindCenterValues(
+ IN HWND hwndToCenter,
+ IN HWND hwndContext,
+ OUT PLONG px,
+ OUT PLONG py,
+ OUT PLONG pw,
+ OUT PLONG ph
+ )
+{
+ RECT rcContext,rcWindow;
+ LONG x,y,w,h;
+ POINT pt;
+ LONG sx = GetSystemMetrics(SM_CXSCREEN);
+ LONG sy = GetSystemMetrics(SM_CYSCREEN);
+
+ pt.x = pt.y = 0;
+ if (hwndContext)
+ {
+ ClientToScreen(hwndContext,&pt);
+ GetClientRect (hwndContext,&rcContext);
+ }
+ else
+ {
+ rcContext.top = rcContext.left = 0;
+ rcContext.right = sx;
+ rcContext.bottom = sy;
+ }
+
+ GetWindowRect(hwndToCenter,&rcWindow);
+
+ w = rcWindow.right - rcWindow.left;
+ h = rcWindow.bottom - rcWindow.top;
+ x = pt.x + ((rcContext.right - rcContext.left - w) / 2);
+ y = pt.y + ((rcContext.bottom - rcContext.top - h) / 2);
+
+ if (x + w > sx)
+ {
+ x = sx - w;
+ }
+ else if (x < 0)
+ {
+ x = 0;
+ }
+
+ if (y + h > sy)
+ {
+ y = sy - h;
+ }
+ else if (y < 0)
+ {
+ y = 0;
+ }
+
+ *px = x;
+ *py = y;
+ *pw = w;
+ *ph = h;
+}
+
+
+
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: CenterWindow
+//
+// Synopsis: Center a window with respect to a given parent or the screen
+//
+// Arguments: [hwndToCenter] -- the window to center
+// [hwndContext] -- the window to center with respect to.
+// If NULL, center with respect to the screen.
+//
+// Returns: none
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+VOID
+CenterWindow(
+ IN HWND hwndToCenter,
+ IN HWND hwndContext
+ )
+{
+ LONG x,y,w,h;
+
+ FindCenterValues(hwndToCenter, hwndContext, &x, &y, &w, &h);
+
+ if (FALSE == MoveWindow(hwndToCenter,x,y,w,h,FALSE))
+ {
+ daDebugOut((DEB_TRACE,"MoveWindow failed\n"));
+ }
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: InsertSeparators
+//
+// Synopsis: Insert separators ( ',' or '.', probably ) every three
+// digits in a number (thousands, millions, etc).
+//
+// Arguments: [Number] -- String representation of an integer to
+// insert separators in. The number is assumed to simply
+// be an array of digits. The buffer must be big
+// enough to have separators inserted every third character.
+//
+// Returns: nothing
+//
+// History: 15-Dec-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+InsertSeparators(
+ IN OUT PWCHAR Number
+ )
+{
+ WCHAR szSeparator[10];
+ WCHAR Separator;
+
+ if (0 != GetLocaleInfoW(
+ GetUserDefaultLCID(),
+ LOCALE_STHOUSAND,
+ szSeparator,
+ ARRAYLEN(szSeparator)
+ ))
+ {
+ Separator = szSeparator[0];
+ }
+ else
+ {
+ Separator = L',';
+ }
+
+ WCHAR Buffer[100];
+ ULONG cchNumber = lstrlen(Number);
+ UINT Triples = 0;
+
+ Buffer[99] = L'\0';
+ PWCHAR pch = &Buffer[98];
+
+ while (cchNumber > 0)
+ {
+ *pch-- = Number[--cchNumber];
+
+ ++Triples;
+ if ( (0 == (Triples % 3)) && (cchNumber > 0) )
+ {
+ *pch-- = Separator;
+ }
+ }
+
+ lstrcpy(Number, pch + 1); // the Number buffer better be able to handle it!
+}
+
+
+//+-------------------------------------------------------------------------
+//
+// Function: GetDeviceObject, public
+//
+// Synopsis: Given a drive letter, return the NT object space device
+// path corresponding to that drive letter. Basically,
+// traverse the \DosDevices\<Drive Letter>: symbolic link.
+//
+// Arguments: IN [wcDrive] -- Unicode drive letter
+// OUT [pszDevPath] -- where to put the NT object path
+// IN [cchDevPath] -- length of [pszDevPath] in characters
+//
+// Returns: TRUE if succeeded, FALSE if failed (e.g., the drive letter is
+// unrecognized)
+//
+// History: 19-May-93 BruceFo Created
+//
+//--------------------------------------------------------------------------
+
+BOOL
+GetDeviceObject(
+ IN WCHAR wcDrive,
+ OUT LPWSTR pszDevPath,
+ IN DWORD cchDevPath)
+{
+ NTSTATUS Status;
+ HANDLE hSymbolicLink;
+ WCHAR wszLinkName[_MAX_DRIVE+1]; // the +1 is for a backslash
+ UNICODE_STRING ustrLinkName;
+ UNICODE_STRING ustrLinkTarget;
+ OBJECT_ATTRIBUTES LinkAttributes;
+
+ wszLinkName[0] = wcDrive;
+ wszLinkName[1] = L':';
+ wszLinkName[2] = L'\\';
+ wszLinkName[3] = L'\0'; // wszLinkName = L"X:\"
+ _wcsupr(wszLinkName);
+
+ //
+ // Construct the link name by calling RtlDosPathNameToNtPathName, and
+ // strip of the trailing backslash. At the end of this, ustrLinkName
+ // should be of the form \DosDevices\X:
+ //
+
+ RtlDosPathNameToNtPathName_U(wszLinkName, &ustrLinkName, NULL, NULL);
+ ustrLinkName.Length -= sizeof(WCHAR);
+
+ InitializeObjectAttributes(
+ &LinkAttributes,
+ &ustrLinkName,
+ OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
+ NULL,
+ NULL);
+
+ Status = NtOpenSymbolicLinkObject(
+ &hSymbolicLink,
+ GENERIC_READ,
+ &LinkAttributes
+ );
+ if (!NT_SUCCESS(Status))
+ {
+ // No Link
+ return(FALSE);
+ }
+
+ //
+ // Get the link target
+ //
+
+ ustrLinkTarget.Length = 0;
+ ustrLinkTarget.MaximumLength = (USHORT)(cchDevPath * sizeof(WCHAR));
+ // Length & MaximumLength are USHORTs
+
+ ustrLinkTarget.Buffer = pszDevPath;
+
+ Status = NtQuerySymbolicLinkObject(
+ hSymbolicLink,
+ &ustrLinkTarget // Name of Link's Target obj.
+ ,NULL
+ );
+ NtClose(hSymbolicLink);
+
+ return (NT_SUCCESS(Status)) ? TRUE : FALSE;
+}
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+//+---------------------------------------------------------------------------
+//
+// Function: BUGBUG: NoHelp
+//
+// Synopsis: until we have help, do this
+//
+// Arguments: [hwndOwner] -- owner window
+//
+// Returns: nothing
+//
+// History: 16-Aug-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+NoHelp(
+ IN HWND hwndOwner
+ )
+{
+ MessageBox(
+ hwndOwner,
+ TEXT("No help available yet"),
+ TEXT("Help"),
+ MB_ICONINFORMATION | MB_OK
+ );
+}
+
+
+
+//+---------------------------------------------------------------------------
+//
+// Function: BUGBUG: Unimplemented
+//
+// Synopsis: for unimplemented features
+//
+// Arguments: [hwndOwner] -- owner window
+//
+// Returns: nothing
+//
+// History: 9-Nov-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+VOID
+Unimplemented(
+ IN HWND hwndOwner
+ )
+{
+ MessageBox(
+ hwndOwner,
+ TEXT("Unimplemented feature"),
+ TEXT("Sorry"),
+ MB_ICONINFORMATION | MB_OK
+ );
+}
diff --git a/private/utils/windisk/util/util.hxx b/private/utils/windisk/util/util.hxx
new file mode 100644
index 000000000..4a764aaff
--- /dev/null
+++ b/private/utils/windisk/util/util.hxx
@@ -0,0 +1,100 @@
+//+---------------------------------------------------------------------------
+//
+// Microsoft Windows
+// Copyright (C) Microsoft Corporation, 1992 - 1993.
+//
+// File: util.hxx
+//
+// Contents: Utility routines for Cairo Disk Administrator
+//
+// History: 20-May-93 BruceFo Created
+//
+//----------------------------------------------------------------------------
+
+
+//
+// util.cxx functions
+//
+
+INT
+MyMessageBox(
+ IN HINSTANCE hInstance,
+ IN HWND hwndOwner,
+ IN DWORD idMessage,
+ IN DWORD idTitle,
+ IN UINT fuStyle
+ );
+
+BOOL
+MySetDlgItemText(
+ IN HINSTANCE hInstance,
+ IN HWND hwndDlg,
+ IN int idControl,
+ IN UINT wID
+ );
+
+VOID
+FindCenterValues(
+ IN HWND hwndToCenter,
+ IN HWND hwndContext,
+ OUT PLONG px,
+ OUT PLONG py,
+ OUT PLONG pw,
+ OUT PLONG ph
+ );
+
+VOID
+CenterWindow(
+ IN HWND hwndToCenter,
+ IN HWND hwndContext
+ );
+
+VOID
+InsertSeparators(
+ IN OUT PWCHAR Number
+ );
+
+VOID
+NoHelp(
+ IN HWND hwndOwner
+ );
+
+VOID
+Unimplemented(
+ IN HWND hwndOwner
+ );
+
+BOOL
+GetDeviceObject(
+ IN WCHAR wcDrive,
+ OUT LPWSTR pszDevPath,
+ IN DWORD cchDevPath
+ );
+
+
+#if DBG == 1
+
+#ifdef WINDISK_EXTENSIONS
+
+//
+// debug.cxx functions
+//
+
+#define GUID_STRING_LEN 36
+
+VOID
+FormatGuid(
+ IN const GUID& guid,
+ OUT PWSTR GuidString
+ );
+
+VOID
+DumpGuid(
+ IN UINT Level,
+ IN PWSTR Message,
+ IN const GUID& guid
+ );
+
+#endif // WINDISK_EXTENSIONS
+
+#endif // DBG == 1
diff --git a/private/utils/windisk/windisk.mk b/private/utils/windisk/windisk.mk
new file mode 100644
index 000000000..76464ae54
--- /dev/null
+++ b/private/utils/windisk/windisk.mk
@@ -0,0 +1,9 @@
+USE_CRTDLL= 1
+
+MSC_WARNING_LEVEL=/W3 /WX
+C_DEFINES= $(C_DEFINES) -DUNICODE -D_UNICODE -DWINVER=0x0400
+
+MAJORCOMP= windisk
+
+INCLUDES=\
+ ..\debug
diff --git a/private/utils/wizards/addgrpw/exgrp.cpp b/private/utils/wizards/addgrpw/exgrp.cpp
new file mode 100644
index 000000000..8993e5377
--- /dev/null
+++ b/private/utils/wizards/addgrpw/exgrp.cpp
@@ -0,0 +1,315 @@
+/**********************************************************************/
+/** Microsoft Windows NT **/
+/** Copyright(c) Microsoft Corp., 1991-1996 **/
+/**********************************************************************/
+
+/*
+ ExGrp.cpp : implementation file
+
+ CPropertyPage support for Group management wizard
+
+ FILE HISTORY:
+ Jony Apr-1996 created
+*/
+
+#include "stdafx.h"
+#include "Romaine.h"
+#include "userlist.h"
+#include "ExGrp.h"
+
+#include <lmaccess.h>
+#include <lmcons.h>
+#include <lmapibuf.h>
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CExGrp property page
+
+IMPLEMENT_DYNCREATE(CExGrp, CPropertyPage)
+
+CExGrp::CExGrp() : CPropertyPage(CExGrp::IDD)
+{
+ //{{AFX_DATA_INIT(CExGrp)
+ // NOTE: the ClassWizard will add member initialization here
+ //}}AFX_DATA_INIT
+ m_pApp = (CRomaineApp*)AfxGetApp();
+}
+
+CExGrp::~CExGrp()
+{
+}
+
+void CExGrp::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CExGrp)
+ DDX_Control(pDX, IDC_GROUP_LIST, m_lbGroupList);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CExGrp, CPropertyPage)
+ //{{AFX_MSG_MAP(CExGrp)
+ ON_BN_CLICKED(IDC_ADD_NEW_BUTTON, OnAddNewButton)
+ ON_BN_CLICKED(IDC_DELETE_BUTTON, OnDeleteButton)
+ ON_WM_SHOWWINDOW()
+ ON_LBN_DBLCLK(IDC_GROUP_LIST, OnDblclkGroupList)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CExGrp message handlers
+
+BOOL CExGrp::OnInitDialog()
+{
+ CPropertyPage::OnInitDialog();
+
+ /*
+ int nVal = ClassifyGroup();
+ if (nVal == 1)
+ {
+ pApp->m_nGroupType = 0;
+ pApp->m_cps1.SetActivePage(6); // global group
+ }
+
+ else if (nVal == 3)
+ {
+ pApp->m_nGroupType = 1;
+ pApp->m_cps1.SetActivePage(5); // local Group
+ }
+ */
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+LRESULT CExGrp::OnWizardNext()
+{
+ UpdateData(TRUE);
+ USHORT sSel = m_lbGroupList.GetCurSel();
+
+ if (sSel == -1)
+ {
+ AfxMessageBox(IDS_NO_GROUP_SELECTED);
+ return -1;
+ }
+
+ m_pApp->m_csGroupName = m_lbGroupList.GetGroupName(sSel);
+
+ int sSelType = m_lbGroupList.GetSelType(sSel);
+ if (sSelType == 1)
+ {
+ m_pApp->m_nGroupType = 0;
+ return IDD_GLOBAL_USERS; // global group
+ }
+
+ else
+ {
+ m_pApp->m_nGroupType = 1;
+ return IDD_LOCAL_USERS; // local Group
+ }
+
+ return CPropertyPage::OnWizardNext();
+}
+
+void CExGrp::OnAddNewButton()
+{
+ m_pApp->m_cps1.SetActivePage(1);
+
+}
+
+void CExGrp::OnDeleteButton()
+{
+ UpdateData(TRUE);
+
+ if (AfxMessageBox(IDS_DELETE_GROUP_CONFIRM, MB_YESNO) != IDYES) return;
+
+ TCHAR* pServer = m_pApp->m_csServer.GetBuffer(m_pApp->m_csServer.GetLength());
+ m_pApp->m_csServer.ReleaseBuffer();
+
+ USHORT sSel = m_lbGroupList.GetCurSel();
+ if (sSel == -1)
+ {
+ AfxMessageBox(IDS_NO_GROUP_SELECTED);
+ return;
+ }
+
+ CString csGroupName = m_lbGroupList.GetGroupName(sSel);
+ TCHAR* pGroupName = csGroupName.GetBuffer(csGroupName.GetLength());
+ csGroupName.ReleaseBuffer();
+
+ int sSelType = m_lbGroupList.GetSelType(sSel);
+ if (sSelType == 1) // global group
+ {
+ if (NetGroupDel(pServer, pGroupName) == 0L)
+ {
+ m_lbGroupList.DeleteString(sSel);
+ AfxMessageBox(IDS_GROUP_DELETED);
+ }
+ else AfxMessageBox(IDS_GROUP_NOT_DELETED);
+ }
+
+ else // local Group
+ {
+ if (NetLocalGroupDel(pServer, pGroupName) == 0L)
+ {
+ m_lbGroupList.DeleteString(sSel);
+ AfxMessageBox(IDS_GROUP_DELETED);
+ }
+ else AfxMessageBox(IDS_GROUP_NOT_DELETED);
+ }
+
+// set a new selection
+ if (m_lbGroupList.GetCount() > 0)
+ {
+ if (sSel == 0) m_lbGroupList.SetCurSel(0);
+ else m_lbGroupList.SetCurSel(sSel - 1);
+ }
+ else m_pApp->m_cps1.SetWizardButtons(PSWIZB_BACK);
+
+
+}
+
+int CExGrp::ClassifyGroup()
+{
+ UpdateData(TRUE);
+
+ if (m_pApp->m_csCmdLineGroupName == L"") return 0;
+
+ unsigned short sCount = m_lbGroupList.GetCount();
+ unsigned short sCount2 = 0;
+
+ while (sCount2 < sCount)
+ {
+ if (m_lbGroupList.GetGroupName(sCount2) == m_pApp->m_csCmdLineGroupName)
+ return m_lbGroupList.GetSelType(sCount2);
+
+ sCount2++;
+ }
+ return 0;
+}
+
+LRESULT CExGrp::OnWizardBack()
+{
+ return IDD_LR_DIALOG;
+}
+
+void CExGrp::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CPropertyPage::OnShowWindow(bShow, nStatus);
+
+ CWaitCursor wait;
+ if (bShow)
+ {
+// start fresh each time
+ m_lbGroupList.ResetContent();
+
+ DWORD dwEntriesRead;
+ DWORD dwTotalEntries;
+ DWORD dwResumeHandle = 0;
+
+ TCHAR* pServer = m_pApp->m_csServer.GetBuffer(m_pApp->m_csServer.GetLength());
+ m_pApp->m_csServer.ReleaseBuffer();
+
+ PLOCALGROUP_INFO_1 pInfo;
+ NET_API_STATUS nApi = NetLocalGroupEnum(pServer, (DWORD)1,
+ (PBYTE*)&pInfo, (DWORD)5000, &dwEntriesRead,
+ &dwTotalEntries, &dwResumeHandle);
+
+ unsigned long sIndex;
+ for (sIndex = 0; sIndex < dwEntriesRead; sIndex++)
+ {
+ wchar_t sTemp[150];
+
+ swprintf(sTemp, TEXT("%s;%s"), pInfo[sIndex].lgrpi1_name, pInfo[sIndex].lgrpi1_comment);
+ m_lbGroupList.AddString(3, sTemp);
+ }
+
+ NetApiBufferFree(pInfo);
+
+ while (dwResumeHandle != 0)
+ {
+ nApi = NetLocalGroupEnum(pServer, (DWORD)1,
+ (PBYTE*)&pInfo, (DWORD)5000, &dwEntriesRead,
+ &dwTotalEntries, &dwResumeHandle);
+
+ for (sIndex = 0; sIndex < dwEntriesRead; sIndex++)
+ {
+ wchar_t sTemp[150];
+
+ swprintf(sTemp, TEXT("%s;%s"), pInfo[sIndex].lgrpi1_name, pInfo[sIndex].lgrpi1_comment);
+ m_lbGroupList.AddString(3, sTemp);
+ }
+
+ NetApiBufferFree(pInfo);
+ }
+
+ if (m_pApp->m_bDomain)
+ {
+ PGROUP_INFO_1 pGInfo1;
+ nApi = NetGroupEnum(pServer, (DWORD)1,
+ (PBYTE*)&pGInfo1, (DWORD)5000, &dwEntriesRead,
+ &dwTotalEntries, &dwResumeHandle);
+
+ for (sIndex = 0; sIndex < dwEntriesRead; sIndex++)
+ {
+ wchar_t sTemp[150];
+
+ swprintf(sTemp, TEXT("%s;%s"), pGInfo1[sIndex].grpi1_name, pGInfo1[sIndex].grpi1_comment);
+ m_lbGroupList.AddString(1, sTemp);
+ }
+
+ NetApiBufferFree(pGInfo1);
+
+ while (dwResumeHandle != 0)
+ {
+ nApi = NetGroupEnum(pServer, (DWORD)1,
+ (PBYTE*)&pGInfo1, (DWORD)5000, &dwEntriesRead,
+ &dwTotalEntries, &dwResumeHandle);
+
+ for (sIndex = 0; sIndex < dwEntriesRead; sIndex++)
+ {
+ wchar_t sTemp[150];
+
+ swprintf(sTemp, TEXT("%s;%s"), pGInfo1[sIndex].grpi1_name, pGInfo1[sIndex].grpi1_comment);
+ m_lbGroupList.AddString(1, sTemp);
+ }
+
+ NetApiBufferFree(pGInfo1);
+ }
+ }
+ m_lbGroupList.SetCurSel(0);
+
+ if (m_pApp->m_csCmdLine != L"") m_pApp->m_cps1.SetWizardButtons(PSWIZB_NEXT);
+ else m_pApp->m_cps1.SetWizardButtons(PSWIZB_NEXT | PSWIZB_BACK);
+ }
+ else m_pApp->m_cps1.SetWizardButtons(PSWIZB_NEXT | PSWIZB_BACK);
+
+}
+
+void CExGrp::OnDblclkGroupList()
+{
+ UpdateData(TRUE);
+ USHORT sSel = m_lbGroupList.GetCurSel();
+
+ m_pApp->m_csGroupName = m_lbGroupList.GetGroupName(sSel);
+
+ int sSelType = m_lbGroupList.GetSelType(sSel);
+ if (sSelType == 1)
+ {
+ m_pApp->m_nGroupType = 0;
+ m_pApp->m_cps1.SetActivePage(7); // global group
+ }
+
+ else
+ {
+ m_pApp->m_nGroupType = 1;
+ m_pApp->m_cps1.SetActivePage(6); // local Group
+ }
+
+
+}
diff --git a/private/utils/wizards/addgrpw/exgrp.h b/private/utils/wizards/addgrpw/exgrp.h
new file mode 100644
index 000000000..04beba4e2
--- /dev/null
+++ b/private/utils/wizards/addgrpw/exgrp.h
@@ -0,0 +1,60 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ ExGrp.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CExGrp dialog
+
+class CExGrp : public CPropertyPage
+{
+ DECLARE_DYNCREATE(CExGrp)
+
+// Construction
+public:
+ CExGrp();
+ ~CExGrp();
+
+// Dialog Data
+ //{{AFX_DATA(CExGrp)
+ enum { IDD = IDD_GROUP_LIST_DIALOG };
+ CUserList m_lbGroupList;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CExGrp)
+ public:
+ virtual LRESULT OnWizardNext();
+ virtual LRESULT OnWizardBack();
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+ CRomaineApp* m_pApp;
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CExGrp)
+ virtual BOOL OnInitDialog();
+ afx_msg void OnAddNewButton();
+ afx_msg void OnDeleteButton();
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ afx_msg void OnDblclkGroupList();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+ int ClassifyGroup();
+
+};
diff --git a/private/utils/wizards/addgrpw/finish.cpp b/private/utils/wizards/addgrpw/finish.cpp
new file mode 100644
index 000000000..c0593744d
--- /dev/null
+++ b/private/utils/wizards/addgrpw/finish.cpp
@@ -0,0 +1,541 @@
+// Finish.cpp : implementation file
+//
+
+#include "stdafx.h"
+#include "Romaine.h"
+#include "Finish.h"
+#include "transbmp.h"
+
+#include <lmcons.h>
+#include <lmaccess.h>
+#include <lmerr.h>
+#include <lmapibuf.h>
+#include <winnetwk.h>
+#include <ntsecapi.h>
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+NTSTATUS OpenPolicy(
+ LPWSTR ServerName, // machine to open policy on (Unicode)
+ DWORD DesiredAccess, // desired access to policy
+ PLSA_HANDLE PolicyHandle); // resultant policy handle
+
+
+void InitLsaString(
+ PLSA_UNICODE_STRING LsaString, // destination
+ LPWSTR String); // source (Unicode)
+
+
+#ifndef STATUS_SUCCESS
+#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
+#endif
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CFinish property page
+
+IMPLEMENT_DYNCREATE(CFinish, CPropertyPage)
+
+CFinish::CFinish() : CPropertyPage(CFinish::IDD)
+{
+ //{{AFX_DATA_INIT(CFinish)
+ m_csGroupType = _T("");
+ m_csGroupLocation = _T("");
+ m_csStaticText1 = _T("");
+ m_csStaticText2 = _T("");
+ //}}AFX_DATA_INIT
+}
+
+CFinish::~CFinish()
+{
+}
+
+void CFinish::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CFinish)
+ DDX_Text(pDX, IDC_GROUP_TYPE_STATIC, m_csGroupType);
+ DDX_Text(pDX, IDC_LOCATION_STATIC, m_csGroupLocation);
+ DDX_Text(pDX, IDC_STATIC1, m_csStaticText1);
+ DDX_Text(pDX, IDC_STATIC2, m_csStaticText2);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CFinish, CPropertyPage)
+ //{{AFX_MSG_MAP(CFinish)
+ ON_WM_SHOWWINDOW()
+ ON_WM_PAINT()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CFinish message handlers
+
+BOOL CFinish::OnWizardFinish()
+{
+ CRomaineApp* pApp = (CRomaineApp*)AfxGetApp();
+ CWaitCursor wait;
+
+ UINT uiMessage;
+ short sStatus = 0;
+
+ if (pApp->m_nGroupType == 0)
+ {
+ TCHAR* pServer = pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength());
+ pApp->m_csServer.ReleaseBuffer();
+
+ TCHAR* pGroupName = pApp->m_csGroupName.GetBuffer(pApp->m_csGroupName.GetLength());
+ pApp->m_csGroupName.ReleaseBuffer();
+
+// create the global group
+ if (pApp->m_sMode == 0)
+ {
+ PGROUP_INFO_1 gi = (PGROUP_INFO_1)malloc(sizeof(GROUP_INFO_1));
+ gi->grpi1_name = pGroupName;
+ gi->grpi1_comment = pApp->m_csGroupDesc.GetBuffer(pApp->m_csGroupDesc.GetLength());
+ pApp->m_csGroupDesc.ReleaseBuffer();
+
+ DWORD dwErr = NetGroupAdd(pServer,
+ 1, (LPBYTE)gi, NULL);
+ free(gi);
+
+ if (dwErr == 2223)
+ {
+ AfxMessageBox(IDS_GROUP_EXISTS);
+ pApp->m_cps1.SetWizardButtons(PSWIZB_NEXT | PSWIZB_BACK);
+ pApp->m_cps1.SetActivePage(1);
+ return FALSE;
+ }
+
+ else if (dwErr == 5)
+ {
+ AfxMessageBox(IDS_INSUFFICIENT_PERMISSION);
+ pApp->m_cps1.SetWizardButtons(PSWIZB_NEXT | PSWIZB_BACK);
+ pApp->m_cps1.SetActivePage(2);
+ return FALSE;
+ }
+ else if ((dwErr == 1379) || (dwErr == NERR_GroupExists))
+ {
+ AfxMessageBox(IDS_GROUP_EXISTS);
+ pApp->m_cps1.SetWizardButtons(PSWIZB_NEXT | PSWIZB_BACK);
+ pApp->m_cps1.SetActivePage(1);
+ return FALSE;
+ }
+ else if (dwErr != NERR_Success)
+ {
+ AfxMessageBox(IDS_UNKNOWN_ERROR);
+ return CPropertyPage::OnWizardFinish();
+ }
+ }
+
+// build the array of users
+ POSITION pos;
+ CString csName;
+
+ short sCount = pApp->m_csaNames.GetCount();
+ GROUP_USERS_INFO_0* pUsers = (GROUP_USERS_INFO_0*)malloc(sCount * sizeof(GROUP_USERS_INFO_0));
+ GROUP_USERS_INFO_0* ppUsers = pUsers;
+ for (pos = pApp->m_csaNames.GetHeadPosition(); pos != NULL;)
+ {
+ csName = pApp->m_csaNames.GetNext(pos);
+ TCHAR* pName = (TCHAR*)csName.GetBuffer(csName.GetLength());
+ csName.ReleaseBuffer();
+
+ pUsers->grui0_name = (LPTSTR)GlobalAlloc(GPTR, (csName.GetLength() + 1) * sizeof(TCHAR));
+ _tcscpy(pUsers->grui0_name, pName);
+ pUsers++;
+ }
+
+ DWORD dwErr = NetGroupSetUsers(pServer,
+ pGroupName,
+ 0,
+ (BYTE*)ppUsers,
+ sCount);
+
+ if (dwErr == NERR_Success) sStatus = 0; // success
+ else sStatus = 1; //failure
+
+ void* pTemp = ppUsers;
+// clean up names buffer
+ while (sCount > 0)
+ {
+ GlobalFree((HGLOBAL)ppUsers->grui0_name);
+ ppUsers++;
+ sCount--;
+ }
+ free(pTemp);
+
+ }
+ else
+ {
+ TCHAR* pServer = pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength());
+ pApp->m_csServer.ReleaseBuffer();
+
+ TCHAR* pGroupName = pApp->m_csGroupName.GetBuffer(pApp->m_csGroupName.GetLength());
+ pApp->m_csGroupName.ReleaseBuffer();
+
+// create the local group
+ if (pApp->m_sMode == 0)
+ {
+ PLOCALGROUP_INFO_1 gi = (PLOCALGROUP_INFO_1)malloc(sizeof(LOCALGROUP_INFO_1));
+ gi->lgrpi1_name = pGroupName;
+ gi->lgrpi1_comment = pApp->m_csGroupDesc.GetBuffer(pApp->m_csGroupDesc.GetLength());
+ DWORD dwErr = NetLocalGroupAdd(pServer,
+ 1, (LPBYTE)gi, NULL);
+
+ pApp->m_csGroupDesc.ReleaseBuffer();
+ free(gi);
+
+ if ((dwErr == 1379) || (dwErr == 2223))
+ {
+ AfxMessageBox(IDS_GROUP_EXISTS);
+ pApp->m_cps1.SetWizardButtons(PSWIZB_NEXT | PSWIZB_BACK);
+ pApp->m_cps1.SetActivePage(1);
+ return FALSE;
+ }
+
+ else if (dwErr == 5)
+ {
+ AfxMessageBox(IDS_INSUFFICIENT_PERMISSION);
+ pApp->m_cps1.SetWizardButtons(PSWIZB_NEXT | PSWIZB_BACK);
+ pApp->m_cps1.SetActivePage(2);
+ return FALSE;
+ }
+ else if (dwErr != NERR_Success)
+ {
+ AfxMessageBox(IDS_UNKNOWN_ERROR);
+ return CPropertyPage::OnWizardFinish();
+ }
+ }
+
+ short sCount = pApp->m_csaNames.GetCount();
+ LOCALGROUP_MEMBERS_INFO_0* pMembers = (LOCALGROUP_MEMBERS_INFO_0*)malloc(sCount * sizeof(LOCALGROUP_MEMBERS_INFO_0));
+ LOCALGROUP_MEMBERS_INFO_0* ppMembers = pMembers;
+
+// go through the user list and get a SID for each member
+ POSITION pos;
+ CString csName;
+ USHORT uCount = 0;
+ for (pos = pApp->m_csaNames.GetHeadPosition(); pos != NULL;)
+ {
+ CString csName = pApp->m_csaNames.GetNext(pos);
+ CString csNameLocation = csName.Left(csName.Find(L"\\"));
+// if the account comes from a domain, we need a DC name
+ if ((csNameLocation != (pApp->m_csCurrentMachine.Right(pApp->m_csCurrentMachine.GetLength() - 2))) &&
+ (csNameLocation != (pApp->m_csServer.Right(pApp->m_csServer.GetLength() - 2))))
+ {
+ TCHAR* pDCName;
+ NET_API_STATUS nAPI = NetGetDCName(NULL,
+ csNameLocation.GetBuffer(csNameLocation.GetLength()),
+ (LPBYTE*)&pDCName);
+ csNameLocation.ReleaseBuffer();
+ csNameLocation = pDCName;
+ NetApiBufferFree(pDCName);
+
+ if (nAPI != ERROR_SUCCESS)
+ {
+ AfxMessageBox(IDS_CANT_ADDNAME);
+ continue;
+ }
+ }
+ else csNameLocation = pApp->m_csCurrentMachine;
+
+ csName = csName.Right(csName.GetLength() - (csName.Find(L"\\") + 1));
+
+ TCHAR* pNameLocation = csNameLocation.GetBuffer(csNameLocation.GetLength());
+ csNameLocation.ReleaseBuffer();
+
+ DWORD sidSize = 0;
+ DWORD strSize = 80;
+ TCHAR str[80];
+ SID_NAME_USE sidType;
+ DWORD ret = LookupAccountName(pNameLocation, (LPCTSTR)csName, NULL, &sidSize, str, &strSize, &sidType);
+
+ pMembers->lgrmi0_sid = (PSID)GlobalAlloc(GPTR, sidSize);
+ strSize = 80;
+ ret=LookupAccountName(pNameLocation, (LPCTSTR)csName, pMembers->lgrmi0_sid, &sidSize, str, &strSize, &sidType);
+
+ pMembers++;
+ uCount++;
+ }
+
+ DWORD err = NetLocalGroupSetMembers(pServer,
+ pGroupName,
+ 0,
+ (LPBYTE)ppMembers,
+ sCount);
+
+ if (err == NERR_Success) uiMessage = IDS_SUCCESS;
+ else if ((err == NERR_GroupExists) || (err == 1376) || (err == 1379))
+ {
+ AfxMessageBox(IDS_GROUP_EXISTS);
+ pApp->m_cps1.SetWizardButtons(PSWIZB_NEXT | PSWIZB_BACK);
+ pApp->m_cps1.SetActivePage(1);
+ return FALSE;
+ }
+
+ else if (err == 2220) sStatus = 1;
+ else sStatus = 1;
+
+
+#ifdef _DEBUG
+ TCHAR tErr[20];
+ swprintf(tErr, L"Error = %d\n\r", err);
+ TRACE(tErr);
+#endif
+ pApp->m_csGroupName.ReleaseBuffer();
+ pApp->m_csServer.ReleaseBuffer();
+
+ void* pTemp = ppMembers;
+// clean up names buffer
+ while (uCount > 0)
+ {
+ GlobalFree(ppMembers->lgrmi0_sid);
+ ppMembers++;
+ uCount--;
+ }
+ free(pTemp);
+ }
+
+ if (pApp->m_csCmdLine != L"") //cmdline - no restart
+ {
+ if (pApp->m_sMode == 0)//create new
+ {
+ if (sStatus == 0) uiMessage = IDS_SUCCESS;
+ else uiMessage = IDS_CANT_ADD_NAMES;
+ }
+ else // modify
+ {
+ if (sStatus == 0) uiMessage = IDS_SUCCESS;
+ else uiMessage = IDS_CANT_ADD_NAMES;
+ }
+
+ AfxMessageBox(uiMessage);
+ return CPropertyPage::OnWizardFinish();
+ }
+
+ else
+ {
+ if (pApp->m_sMode == 0)//create new
+ {
+ if (sStatus == 0)
+ {
+// clear out old values
+ pApp->m_csGroupName = L"";
+ pApp->m_csGroupDesc = L"";
+
+ uiMessage = IDS_SUCCESS_CREATE_RETRY;
+ }
+ else uiMessage = IDS_CANT_ADD_NAMES_CREATE_RETRY;
+ }
+ else // modify
+ {
+ if (sStatus == 0)
+ {
+// clear out old values
+ pApp->m_csGroupName = L"";
+ pApp->m_csGroupDesc = L"";
+
+ uiMessage = IDS_SUCCESS_MODIFY_RETRY;
+ }
+ else uiMessage = IDS_CANT_ADD_NAMES_MODIFY_RETRY;
+ }
+
+ if (AfxMessageBox(uiMessage, MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
+ {
+
+ // clear out old info
+ pApp->m_csaNames.RemoveAll();
+ pApp->bRestart1 = TRUE;
+ pApp->bRestart2 = TRUE;
+ pApp->m_cps1.SetWizardButtons(PSWIZB_NEXT | PSWIZB_BACK);
+ pApp->m_cps1.SetActivePage(1);
+ return FALSE;
+ }
+ }
+
+ return CPropertyPage::OnWizardFinish();
+}
+
+void InitLsaString(PLSA_UNICODE_STRING LsaString, LPWSTR String)
+{
+ DWORD StringLength;
+
+ if (String == NULL)
+ {
+ LsaString->Buffer = NULL;
+ LsaString->Length = 0;
+ LsaString->MaximumLength = 0;
+ return;
+ }
+
+ StringLength = wcslen(String);
+ LsaString->Buffer = String;
+ LsaString->Length = (USHORT) StringLength * sizeof(WCHAR);
+ LsaString->MaximumLength=(USHORT)(StringLength+1) * sizeof(WCHAR);
+}
+
+NTSTATUS OpenPolicy(LPWSTR ServerName, DWORD DesiredAccess, PLSA_HANDLE PolicyHandle)
+{
+ LSA_OBJECT_ATTRIBUTES ObjectAttributes;
+ LSA_UNICODE_STRING ServerString;
+ PLSA_UNICODE_STRING Server = NULL;
+
+ //
+ // Always initialize the object attributes to all zeroes.
+ //
+ ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
+
+ if (ServerName != NULL)
+ {
+ //
+ // Make a LSA_UNICODE_STRING out of the LPWSTR passed in
+ //
+ InitLsaString(&ServerString, ServerName);
+ Server = &ServerString;
+ }
+
+ //
+ // Attempt to open the policy.
+ //
+ return LsaOpenPolicy(
+ Server,
+ &ObjectAttributes,
+ DesiredAccess,
+ PolicyHandle);
+}
+
+void CFinish::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CPropertyPage::OnShowWindow(bShow, nStatus);
+
+ CRomaineApp* pApp = (CRomaineApp*)AfxGetApp();
+ if (bShow)
+ {
+ if (pApp->m_nGroupType == 1)
+ m_csGroupType.LoadString(IDS_LOCAL_GROUP);
+ else
+ m_csGroupType.LoadString(IDS_GLOBAL_GROUP);
+
+ m_csGroupType += pApp->m_csGroupName;
+
+ if (pApp->m_bDomain)
+ m_csGroupLocation = pApp->m_csDomain;
+ else
+ m_csGroupLocation = pApp->m_csServer;
+
+ if (pApp->m_sMode == 1)
+ {
+ m_csStaticText1.LoadString(IDS_MODIFY_TEXT);
+ m_csStaticText2.LoadString(IDS_MODIFY_TEXT2);
+ }
+ else
+ {
+ m_csStaticText1.LoadString(IDS_CREATE_TEXT);
+ m_csStaticText2.LoadString(IDS_CREATE_TEXT2);
+ }
+
+ UpdateData(FALSE);
+ }
+
+}
+
+void CFinish::OnPaint()
+{
+ CPaintDC dc(this); // device context for painting
+
+ CTransBmp* pBitmap = new CTransBmp;
+ pBitmap->LoadBitmap(IDB_END_FLAG);
+
+ pBitmap->DrawTrans(&dc, 0,0);
+ delete pBitmap;
+
+}
+
+LRESULT CFinish::OnWizardBack()
+{
+ CRomaineApp* pApp = (CRomaineApp*)AfxGetApp();
+ pApp->m_cps1.SetWizardButtons(PSWIZB_BACK | PSWIZB_NEXT);
+
+ if (pApp->m_nGroupType == 0) return IDD_GLOBAL_USERS;
+ else return IDD_LOCAL_USERS;
+
+}
+
+
+// im using the LSA functions as the std LookupAccountName doesn't work on Local Users
+ /*
+ LSA_HANDLE Policy_Handle;
+ NTSTATUS Status;
+
+ LPTSTR lpServer = pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength());
+ Status = OpenPolicy(lpServer, POLICY_LOOKUP_NAMES, &Policy_Handle);
+
+// Did OpenPolicy work?
+ if (Status != STATUS_SUCCESS)
+ {
+ AfxMessageBox(IDS_CANT_ADD_NAMES);
+ pApp->m_csServer.ReleaseBuffer();
+ return CPropertyPage::OnWizardFinish();
+ }
+
+ POSITION pos;
+ CString csName;
+ LPWSTR lpName;
+ USHORT uCount = 0;
+ LSA_UNICODE_STRING lusName;
+ PLSA_UNICODE_STRING plusName = NULL;
+ BYTE domainbuffer[1000];
+ PLSA_REFERENCED_DOMAIN_LIST lsarDomainList = (PLSA_REFERENCED_DOMAIN_LIST)&domainbuffer;
+
+ BYTE sidbuffer[100];
+ PLSA_TRANSLATED_SID lsatSID = (PLSA_TRANSLATED_SID)&sidbuffer;
+
+ for (pos = pApp->m_csaNames.GetHeadPosition(); pos != NULL;)
+ {
+ csName = pApp->m_csaNames.GetNext(pos);
+ lpName = csName.GetBuffer(csName.GetLength());
+ InitLsaString(&lusName, lpName); // Make a LSA_UNICODE_STRING out of the LPWSTR passed in
+ plusName = &lusName;
+
+ Status = LsaLookupNames(Policy_Handle,
+ 1, // count
+ plusName, // LSA_UNICODE_STRING
+ &lsarDomainList,
+ &lsatSID);
+
+ ULONG uErr = LsaNtStatusToWinError(Status);
+ if (!uErr) // success
+ {
+ NetLocalGroupAddMember(lpServer,
+ pApp->m_csGroupName.GetBuffer(pApp->m_csGroupName.GetLength()),
+
+
+ }
+ csName.ReleaseBuffer();
+ }
+
+
+ pApp->m_csServer.ReleaseBuffer();
+ */
+/* BYTE sidbuffer[100];
+ PSID pSID = (PSID)&sidbuffer;
+ DWORD cbSID = 100;
+ TCHAR domainBuffer[80];
+ DWORD domainBufferSize = 80;
+ SID_NAME_USE snu;
+
+ BOOL bRet = LookupAccountName((const TCHAR*)pApp->m_csServer,
+ L"Guest",
+ pSID,
+ &cbSID,
+ domainBuffer,
+ &domainBufferSize,
+ &snu);
+
+ TRACE(L"blob"); */
diff --git a/private/utils/wizards/addgrpw/finish.h b/private/utils/wizards/addgrpw/finish.h
new file mode 100644
index 000000000..3ad6a4560
--- /dev/null
+++ b/private/utils/wizards/addgrpw/finish.h
@@ -0,0 +1,57 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Finish.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CFinish dialog
+
+class CFinish : public CPropertyPage
+{
+ DECLARE_DYNCREATE(CFinish)
+
+// Construction
+public:
+ CFinish();
+ ~CFinish();
+
+// Dialog Data
+ //{{AFX_DATA(CFinish)
+ enum { IDD = IDD_FINISH_DLG };
+ CString m_csGroupType;
+ CString m_csGroupLocation;
+ CString m_csStaticText1;
+ CString m_csStaticText2;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CFinish)
+ public:
+ virtual BOOL OnWizardFinish();
+ virtual LRESULT OnWizardBack();
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CFinish)
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ afx_msg void OnPaint();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+};
diff --git a/private/utils/wizards/addgrpw/gusers.cpp b/private/utils/wizards/addgrpw/gusers.cpp
new file mode 100644
index 000000000..bca9c1442
--- /dev/null
+++ b/private/utils/wizards/addgrpw/gusers.cpp
@@ -0,0 +1,407 @@
+/**********************************************************************/
+/** Microsoft Windows NT **/
+/** Copyright(c) Microsoft Corp., 1991-1996 **/
+/**********************************************************************/
+
+/*
+ GUsers.cpp : implementation file
+
+ CPropertyPage support for Group management wizard
+
+ FILE HISTORY:
+ Jony Apr-1996 created
+*/
+
+#include "stdafx.h"
+#include "Romaine.h"
+#include "userlist.h"
+#include "GUsers.h"
+
+#include <lmcons.h>
+#include <lmaccess.h>
+#include <lmerr.h>
+#include <lmapibuf.h>
+#include <winnetwk.h>
+#include <winreg.h>
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CGUsers property page
+
+IMPLEMENT_DYNCREATE(CGUsers, CPropertyPage)
+
+CGUsers::CGUsers() : CPropertyPage(CGUsers::IDD)
+{
+ //{{AFX_DATA_INIT(CGUsers)
+ // NOTE: the ClassWizard will add member initialization here
+ //}}AFX_DATA_INIT
+}
+
+CGUsers::~CGUsers()
+{
+}
+
+void CGUsers::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CGUsers)
+ DDX_Control(pDX, IDC_SELECTED_MEMBERS_LIST, m_lbSelectedUsers);
+ DDX_Control(pDX, IDC_AVAILABLE_MEMBERS_LIST, m_lbAvailableUsers);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CGUsers, CPropertyPage)
+ //{{AFX_MSG_MAP(CGUsers)
+ ON_BN_CLICKED(IDC_ADD_BUTTON, OnAddButton)
+ ON_BN_CLICKED(IDC_REMOVE_BUTTON, OnRemoveButton)
+ ON_LBN_SETFOCUS(IDC_AVAILABLE_MEMBERS_LIST, OnSetfocusAvailableMembersList)
+ ON_LBN_SETFOCUS(IDC_SELECTED_MEMBERS_LIST, OnSetfocusSelectedMembersList)
+ ON_WM_SHOWWINDOW()
+ ON_LBN_DBLCLK(IDC_AVAILABLE_MEMBERS_LIST, OnDblclkAvailableMembersList)
+ ON_LBN_DBLCLK(IDC_SELECTED_MEMBERS_LIST, OnDblclkSelectedMembersList)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CGUsers message handlers
+// enum users thread
+void CGUsers::EnumUsers(TCHAR* lpszPrimaryDC)
+{
+ CString csTemp;
+
+// now enumerate the users on that machine
+ void* netUserBuffer;
+ DWORD dwReturnedEntries;
+ DWORD err = NetQueryDisplayInformation(lpszPrimaryDC, 1,
+ 0, 100, 100 * sizeof(NET_DISPLAY_USER),
+ &dwReturnedEntries, &netUserBuffer);
+
+// check return for error
+ if (err != NERR_Success && err != ERROR_MORE_DATA) return;
+
+// add these users to the dialog
+ DWORD dwCurrent;
+ NET_DISPLAY_USER* netUser;
+ netUser = (NET_DISPLAY_USER*)netUserBuffer;
+ for (dwCurrent = 0; dwCurrent < dwReturnedEntries; dwCurrent++)
+ {
+ csTemp = netUser->usri1_name;
+ if (netUser->usri1_flags & UF_NORMAL_ACCOUNT) m_lbAvailableUsers.AddString(0, csTemp);
+// else m_lbAvailableUsers.AddString(4, csTemp);
+
+ netUser++;
+ }
+
+// add more users?
+ DWORD dwNext;
+ while (err == ERROR_MORE_DATA)
+ {
+ netUser--;
+ NetGetDisplayInformationIndex(lpszPrimaryDC, 1, netUser->usri1_name, &dwNext);
+ NetApiBufferFree(netUserBuffer);
+ err = NetQueryDisplayInformation(lpszPrimaryDC, 1,
+ dwNext, 100, 32767,
+ &dwReturnedEntries, &netUserBuffer);
+
+// check return for error
+ if (err != NERR_Success && err != ERROR_MORE_DATA) return;
+
+ netUser = (NET_DISPLAY_USER*)netUserBuffer;
+ for (dwCurrent = 0; dwCurrent < dwReturnedEntries; dwCurrent++)
+ {
+ csTemp = netUser->usri1_name;
+ if (netUser->usri1_flags & UF_NORMAL_ACCOUNT) m_lbAvailableUsers.AddString(0, csTemp);
+// else m_lbAvailableUsers.AddString(4, csTemp);
+ netUser++;
+ }
+ }
+
+ NetApiBufferFree(netUserBuffer);
+
+}
+
+LRESULT CGUsers::OnWizardBack()
+{
+ CRomaineApp* pApp = (CRomaineApp*)AfxGetApp();
+ if (pApp->m_bServer) return IDD_GROUP_TYPE_DLG;
+ else if (pApp->m_csCmdLine != L"") return IDD_GROUP_LIST_DIALOG;
+ else if (pApp->m_sMode == 1) return IDD_GROUP_LIST_DIALOG;
+ else return IDD_LR_DIALOG;
+
+}
+
+void CGUsers::OnAddButton()
+{
+ UpdateData(TRUE);
+ USHORT usSel = m_lbAvailableUsers.GetCurSel();
+ if (usSel == 65535)
+ {
+ GetDlgItem(IDC_ADD_BUTTON)->EnableWindow(FALSE);
+ GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(TRUE);
+ m_lbSelectedUsers.SetCurSel(0);
+ return;
+ }
+
+ CString csSel;
+ m_lbAvailableUsers.GetText(usSel, csSel);
+ ULONG ulBmp = m_lbAvailableUsers.GetItemData(usSel);
+ m_lbSelectedUsers.AddString(csSel, ulBmp);
+ m_lbAvailableUsers.DeleteString(usSel);
+
+// anybody left?
+ if (m_lbAvailableUsers.GetCount() != 0)
+ m_lbAvailableUsers.SetCurSel(0);
+
+ else
+ {
+ m_lbSelectedUsers.SetCurSel(0);
+ GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(TRUE);
+ GetDlgItem(IDC_ADD_BUTTON)->EnableWindow(FALSE);
+ m_lbAvailableUsers.SetHorizontalExtent(0);
+ }
+
+}
+
+void CGUsers::OnRemoveButton()
+{
+ UpdateData(TRUE);
+ USHORT usSel = m_lbSelectedUsers.GetCurSel();
+ if (usSel == 65535)
+ {
+ GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(FALSE);
+ GetDlgItem(IDC_ADD_BUTTON)->EnableWindow(TRUE);
+ m_lbAvailableUsers.SetCurSel(0);
+ return;
+ }
+
+ CString csSel;
+ m_lbSelectedUsers.GetText(usSel, csSel);
+ ULONG ulBmp = m_lbSelectedUsers.GetItemData(usSel);
+ m_lbAvailableUsers.AddString(csSel, ulBmp);
+ m_lbSelectedUsers.DeleteString(usSel);
+
+// anybody left?
+ if (m_lbSelectedUsers.GetCount() != 0)
+ m_lbSelectedUsers.SetCurSel(0);
+
+ else
+ {
+ m_lbAvailableUsers.SetCurSel(0);
+ GetDlgItem(IDC_ADD_BUTTON)->EnableWindow(TRUE);
+ GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(FALSE);
+ m_lbSelectedUsers.SetHorizontalExtent(0);
+ }
+
+}
+
+void CGUsers::OnSetfocusAvailableMembersList()
+{
+ CWnd* pWnd = GetDlgItem(IDC_ADD_BUTTON);
+ pWnd->EnableWindow(TRUE);
+
+ pWnd = GetDlgItem(IDC_REMOVE_BUTTON);
+ pWnd->EnableWindow(FALSE);
+
+ m_lbSelectedUsers.SetCurSel(-1);
+
+}
+
+void CGUsers::OnSetfocusSelectedMembersList()
+{
+ CWnd* pWnd = GetDlgItem(IDC_ADD_BUTTON);
+ pWnd->EnableWindow(FALSE);
+
+ pWnd = GetDlgItem(IDC_REMOVE_BUTTON);
+ pWnd->EnableWindow(TRUE);
+
+ m_lbAvailableUsers.SetCurSel(-1);
+}
+
+LRESULT CGUsers::OnWizardNext()
+{
+ UpdateData(TRUE);
+ CRomaineApp* pApp = (CRomaineApp*)AfxGetApp();
+ pApp->m_cps1.SetWizardButtons(PSWIZB_FINISH | PSWIZB_BACK);
+
+
+// empty the list
+ pApp->m_csaNames.RemoveAll();
+
+// fill with new names.
+ USHORT us;
+ CString csTemp;
+ for (us = 0; us < m_lbSelectedUsers.GetCount(); us++)
+ {
+ m_lbSelectedUsers.GetText(us, csTemp);
+ pApp->m_csaNames.AddHead(csTemp);
+ }
+ return CPropertyPage::OnWizardNext();
+}
+
+void CGUsers::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CPropertyPage::OnShowWindow(bShow, nStatus);
+ CRomaineApp* pApp = (CRomaineApp*)AfxGetApp();
+
+ CWaitCursor wait;
+ if (bShow)
+ {
+ if (m_csServer != pApp->m_csServer)
+ {
+ m_csServer = pApp->m_csServer;
+ m_lbSelectedUsers.ResetContent();
+ }
+// on a rerun clean out the members from the last group
+ else if (pApp->bRestart2)
+ {
+ m_lbSelectedUsers.ResetContent();
+ pApp->bRestart2 == FALSE;
+ }
+ else return;
+
+ m_lbAvailableUsers.ResetContent();
+ TCHAR* pServer = pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength());
+ pApp->m_csServer.ReleaseBuffer();
+ EnumUsers(pServer);
+
+// editing a group? add the current members
+ if (pApp->m_sMode == 1)
+ {
+ DWORD dwEntriesRead;
+ DWORD dwTotalEntries;
+ DWORD dwResumeHandle = 0;
+
+ m_lbSelectedUsers.ResetContent();
+
+ TCHAR* pGroup = pApp->m_csGroupName.GetBuffer(pApp->m_csGroupName.GetLength());
+ pApp->m_csGroupName.ReleaseBuffer();
+
+ PGROUP_USERS_INFO_0 pMembers;
+ NET_API_STATUS nApi = NetGroupGetUsers(pServer,
+ pGroup,
+ 0,
+ (LPBYTE*)&pMembers,
+ 5000,
+ &dwEntriesRead,
+ &dwTotalEntries,
+ &dwResumeHandle);
+ if (nApi != ERROR_SUCCESS)
+ {
+ AfxMessageBox(IDS_CANT_GET_USERS);
+ goto keepgoing;
+ }
+
+ USHORT sIndex;
+ for (sIndex = 0; sIndex < dwEntriesRead; sIndex++)
+ {
+ wchar_t sTemp[150];
+ swprintf(sTemp, TEXT("%s"), pMembers[sIndex].grui0_name);
+
+ m_lbSelectedUsers.AddString(0, sTemp);
+ }
+
+ NetApiBufferFree(pMembers);
+
+ while (dwResumeHandle != 0)
+ {
+ nApi = NetGroupGetUsers(pServer,
+ pGroup,
+ 0,
+ (LPBYTE*)&pMembers,
+ 5000,
+ &dwEntriesRead,
+ &dwTotalEntries,
+ &dwResumeHandle);
+ if (nApi != ERROR_SUCCESS)
+ {
+ AfxMessageBox(IDS_CANT_GET_USERS);
+ goto keepgoing;
+ }
+
+ USHORT sIndex;
+ for (sIndex = 0; sIndex < dwEntriesRead; sIndex++)
+ {
+ wchar_t sTemp[150];
+ swprintf(sTemp, TEXT("%s"), pMembers[sIndex].grui0_name);
+
+ m_lbSelectedUsers.AddString(0, sTemp);
+ }
+ NetApiBufferFree(pMembers);
+ }
+ }
+
+
+keepgoing:
+ m_lbSelectedUsers.SetHorizontalExtent(200);
+ m_lbAvailableUsers.SetHorizontalExtent(200);
+
+// now clean up list to remove those users already added
+ USHORT sValueCount = m_lbSelectedUsers.GetCount();
+ USHORT sCount, sSel;
+ CString csValue;
+ for (sCount = 0; sCount < sValueCount; sCount++)
+ {
+ m_lbSelectedUsers.GetText(sCount, csValue);
+ m_lbAvailableUsers.SelectString(-1, csValue);
+ sSel = m_lbAvailableUsers.GetCurSel();
+ m_lbAvailableUsers.DeleteString(sSel);
+ }
+
+ m_lbAvailableUsers.SetCurSel(0);
+ }
+
+}
+
+void CGUsers::OnDblclkAvailableMembersList()
+{
+ UpdateData(TRUE);
+ USHORT usSel = m_lbAvailableUsers.GetCurSel();
+ CString csSel;
+ m_lbAvailableUsers.GetText(usSel, csSel);
+ ULONG ulBmp = m_lbAvailableUsers.GetItemData(usSel);
+ m_lbSelectedUsers.AddString(csSel, ulBmp);
+ m_lbAvailableUsers.DeleteString(usSel);
+
+// anybody left?
+ if (m_lbAvailableUsers.GetCount() != 0)
+ m_lbAvailableUsers.SetCurSel(0);
+
+ else
+ {
+ m_lbSelectedUsers.SetCurSel(0);
+ GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(TRUE);
+ GetDlgItem(IDC_ADD_BUTTON)->EnableWindow(FALSE);
+ m_lbAvailableUsers.SetHorizontalExtent(0);
+ }
+
+}
+
+void CGUsers::OnDblclkSelectedMembersList()
+{
+ UpdateData(TRUE);
+ USHORT usSel = m_lbSelectedUsers.GetCurSel();
+ CString csSel;
+ m_lbSelectedUsers.GetText(usSel, csSel);
+ ULONG ulBmp = m_lbSelectedUsers.GetItemData(usSel);
+ m_lbAvailableUsers.AddString(csSel, ulBmp);
+ m_lbSelectedUsers.DeleteString(usSel);
+
+// anybody left?
+ if (m_lbSelectedUsers.GetCount() != 0)
+ m_lbSelectedUsers.SetCurSel(0);
+
+ else
+ {
+ m_lbAvailableUsers.SetCurSel(0);
+ GetDlgItem(IDC_ADD_BUTTON)->EnableWindow(TRUE);
+ GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(FALSE);
+ m_lbSelectedUsers.SetHorizontalExtent(0);
+ }
+
+}
diff --git a/private/utils/wizards/addgrpw/gusers.h b/private/utils/wizards/addgrpw/gusers.h
new file mode 100644
index 000000000..96c1d103f
--- /dev/null
+++ b/private/utils/wizards/addgrpw/gusers.h
@@ -0,0 +1,63 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ GUsers.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CGUsers dialog
+
+class CGUsers : public CPropertyPage
+{
+ DECLARE_DYNCREATE(CGUsers)
+
+// Construction
+public:
+ CGUsers();
+ ~CGUsers();
+
+// Dialog Data
+ //{{AFX_DATA(CGUsers)
+ enum { IDD = IDD_GLOBAL_USERS };
+ CUserList m_lbSelectedUsers;
+ CUserList m_lbAvailableUsers;
+ //}}AFX_DATA
+
+ int m_nMax;
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CGUsers)
+ public:
+ virtual LRESULT OnWizardBack();
+ virtual LRESULT OnWizardNext();
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+private:
+ void EnumUsers(TCHAR* lpszPrimaryDC);
+ CString m_csServer;
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CGUsers)
+ afx_msg void OnAddButton();
+ afx_msg void OnRemoveButton();
+ afx_msg void OnSetfocusAvailableMembersList();
+ afx_msg void OnSetfocusSelectedMembersList();
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ afx_msg void OnDblclkAvailableMembersList();
+ afx_msg void OnDblclkSelectedMembersList();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+};
diff --git a/private/utils/wizards/addgrpw/lrem.cpp b/private/utils/wizards/addgrpw/lrem.cpp
new file mode 100644
index 000000000..eb677a580
--- /dev/null
+++ b/private/utils/wizards/addgrpw/lrem.cpp
@@ -0,0 +1,138 @@
+/**********************************************************************/
+/** Microsoft Windows NT **/
+/** Copyright(c) Microsoft Corp., 1991-1996 **/
+/**********************************************************************/
+
+/*
+ LRem.cpp : implementation file
+
+ CPropertyPage support for Group management wizard
+
+ FILE HISTORY:
+ Jony Apr-1996 created
+*/
+
+#include "stdafx.h"
+#include "Romaine.h"
+#include "LRem.h"
+
+#include <lmcons.h>
+#include <lmaccess.h>
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+extern int ClassifyMachine(CString& csMachineName);
+
+/////////////////////////////////////////////////////////////////////////////
+// CLRem property page
+
+IMPLEMENT_DYNCREATE(CLRem, CPropertyPage)
+
+CLRem::CLRem() : CPropertyPage(CLRem::IDD)
+{
+ //{{AFX_DATA_INIT(CLRem)
+ m_nLocation = 0;
+ m_csStatic1 = _T("");
+ //}}AFX_DATA_INIT
+}
+
+CLRem::~CLRem()
+{
+}
+
+void CLRem::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CLRem)
+ DDX_Radio(pDX, IDC_LOCAL_RADIO, m_nLocation);
+ DDX_Text(pDX, IDC_STATIC1, m_csStatic1);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CLRem, CPropertyPage)
+ //{{AFX_MSG_MAP(CLRem)
+ ON_WM_SHOWWINDOW()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CLRem message handlers
+
+LRESULT CLRem::OnWizardNext()
+{
+ CRomaineApp* pApp = (CRomaineApp*)AfxGetApp();
+
+ UpdateData(TRUE);
+ if (m_nLocation == 0)
+ {
+ int nVal = ClassifyMachine(pApp->m_csCurrentMachine);
+
+ // if we are creating a new group, go ahead and check the name for uniqueness
+ if (pApp->m_sMode == 0)
+ {
+ TCHAR* pServer = pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength());
+ pApp->m_csServer.ReleaseBuffer();
+
+ TCHAR* pGroupName = pApp->m_csGroupName.GetBuffer(pApp->m_csGroupName.GetLength());
+ pApp->m_csGroupName.ReleaseBuffer();
+
+ GROUP_INFO_0* pInfo;
+ NET_API_STATUS nAPI = NetGroupGetInfo(pServer,
+ pGroupName,
+ 0,
+ (LPBYTE*)&pInfo);
+
+ if (nAPI == ERROR_SUCCESS)
+ {
+ AfxMessageBox(IDS_GROUP_EXISTS);
+ return IDD_NAME_DLG;
+ }
+
+ LOCALGROUP_INFO_0* pLInfo;
+ nAPI = NetLocalGroupGetInfo(pServer,
+ pGroupName,
+ 0,
+ (LPBYTE*)&pLInfo);
+
+ if (nAPI == ERROR_SUCCESS)
+ {
+ AfxMessageBox(IDS_GROUP_EXISTS);
+ return IDD_NAME_DLG;
+ }
+ }
+ return nVal;
+ }
+
+ else return IDD_MACHINE_DLG;
+
+}
+
+void CLRem::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CPropertyPage::OnShowWindow(bShow, nStatus);
+
+ UpdateData(TRUE);
+ if (bShow)
+ {
+ CRomaineApp* pApp = (CRomaineApp*)AfxGetApp();
+ if (pApp->m_sMode == 1) m_csStatic1.LoadString(IDS_MODIFY3);
+ else m_csStatic1.LoadString(IDS_CREATE3);
+ UpdateData(FALSE);
+ }
+
+}
+
+LRESULT CLRem::OnWizardBack()
+{
+ UpdateData(TRUE);
+ CRomaineApp* pApp = (CRomaineApp*)AfxGetApp();
+ if (pApp->m_sMode == 1) return IDD_WELCOME_DLG;
+ else return IDD_NAME_DLG;
+
+ return CPropertyPage::OnWizardBack();
+}
diff --git a/private/utils/wizards/addgrpw/lrem.h b/private/utils/wizards/addgrpw/lrem.h
new file mode 100644
index 000000000..2a835d794
--- /dev/null
+++ b/private/utils/wizards/addgrpw/lrem.h
@@ -0,0 +1,54 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ LRem.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CLRem dialog
+
+class CLRem : public CPropertyPage
+{
+ DECLARE_DYNCREATE(CLRem)
+
+// Construction
+public:
+ CLRem();
+ ~CLRem();
+
+// Dialog Data
+ //{{AFX_DATA(CLRem)
+ enum { IDD = IDD_LR_DIALOG };
+ int m_nLocation;
+ CString m_csStatic1;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CLRem)
+ public:
+ virtual LRESULT OnWizardNext();
+ virtual LRESULT OnWizardBack();
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CLRem)
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+};
diff --git a/private/utils/wizards/addgrpw/lusers.cpp b/private/utils/wizards/addgrpw/lusers.cpp
new file mode 100644
index 000000000..ee0cbd720
--- /dev/null
+++ b/private/utils/wizards/addgrpw/lusers.cpp
@@ -0,0 +1,632 @@
+/**********************************************************************/
+/** Microsoft Windows NT **/
+/** Copyright(c) Microsoft Corp., 1991-1996 **/
+/**********************************************************************/
+
+/*
+ LUsers.cpp : implementation file
+
+ CPropertyPage support for Group management wizard
+
+ FILE HISTORY:
+ Jony Apr-1996 created
+*/
+
+#include "stdafx.h"
+#include "Romaine.h"
+#include "userlist.h"
+#include "LUsers.h"
+#include "trstlist.h"
+
+#include <winreg.h>
+#include <lmcons.h>
+#include <lmaccess.h>
+#include <lmerr.h>
+#include <lmapibuf.h>
+#include <winnetwk.h>
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+// some global objects used in the EnumUsers and EnumGroups threads
+CStringList csaNames;
+CStringList csaLNames;
+CStringList csaGroups;
+void EnumGroups(DWORD pDCName);
+void EnumLocalGroups(DWORD pDCName);
+void EnumUsers(DWORD pDCName);
+
+/////////////////////////////////////////////////////////////////////////////
+// CLUsers property page
+
+IMPLEMENT_DYNCREATE(CLUsers, CPropertyPage)
+
+CLUsers::CLUsers() : CPropertyPage(CLUsers::IDD)
+{
+ //{{AFX_DATA_INIT(CLUsers)
+ m_csDomainName = _T("");
+ m_csAvailableUserList = _T("");
+ //}}AFX_DATA_INIT
+}
+
+CLUsers::~CLUsers()
+{
+}
+
+void CLUsers::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CLUsers)
+ DDX_Control(pDX, IDC_ADDED_LOCAL_USERS, m_lbAddedUserList);
+ DDX_Control(pDX, IDC_AVAILABLE_LOCAL_USERS, m_lbAvailableUserList);
+ DDX_Control(pDX, IDC_DOMAIN_COMBO, m_csDomainList);
+ DDX_CBString(pDX, IDC_DOMAIN_COMBO, m_csDomainName);
+ DDX_LBString(pDX, IDC_AVAILABLE_LOCAL_USERS, m_csAvailableUserList);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CLUsers, CPropertyPage)
+ //{{AFX_MSG_MAP(CLUsers)
+ ON_BN_CLICKED(IDC_ADD_BUTTON, OnAddButton)
+ ON_CBN_SELCHANGE(IDC_DOMAIN_COMBO, OnSelchangeDomainCombo)
+ ON_WM_SHOWWINDOW()
+ ON_LBN_DBLCLK(IDC_ADDED_LOCAL_USERS, OnDblclkAddedLocalUsers)
+ ON_LBN_DBLCLK(IDC_AVAILABLE_LOCAL_USERS, OnDblclkAvailableLocalUsers)
+ ON_LBN_SETFOCUS(IDC_AVAILABLE_LOCAL_USERS, OnSetfocusAvailableLocalUsers)
+ ON_LBN_SETFOCUS(IDC_ADDED_LOCAL_USERS, OnSetfocusAddedLocalUsers)
+ ON_BN_CLICKED(IDC_REMOVE_BUTTON, OnRemoveButton)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CLUsers message handlers
+
+BOOL CLUsers::OnInitDialog()
+{
+ CPropertyPage::OnInitDialog();
+
+ return FALSE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+
+// launch two threads to enumerate the global groups and user accounts in the selected domain
+void CLUsers::CatalogAccounts(const TCHAR* lpDomain, CUserList& pListBox, BOOL bLocal /* = FALSE*/)
+{
+ CWaitCursor wait;
+ wchar_t lpwDomain[255];
+ _tcscpy(lpwDomain, lpDomain);
+
+ wchar_t* lpszPrimaryDC = NULL;
+
+ NET_API_STATUS err = 0;
+// first get the name of the PDC machine
+ if (bLocal)
+ {
+ lpszPrimaryDC = (TCHAR*)malloc((_tcslen(lpDomain) + 1)* sizeof(TCHAR));
+ _tcscpy(lpszPrimaryDC, lpDomain);
+ }
+
+ else
+ err = NetGetDCName( NULL, // Local Machine
+ lpwDomain, // Domain Name
+ (LPBYTE *)&lpszPrimaryDC ); // returned PDC *
+
+// empty the listbox
+ pListBox.ResetContent();
+
+ if (err != 0)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_PDC, MB_ICONEXCLAMATION);
+ return;
+ }
+
+ csaNames.RemoveAll();
+ csaLNames.RemoveAll();
+ csaGroups.RemoveAll();
+
+// create a thread each for names and groups. Run them simultaneously to save some time.
+ HANDLE hThreads[2];
+ USHORT usObjCount = 2;
+ DWORD dwThreadID;
+ hThreads[0] = ::CreateThread(NULL, 100,
+ (LPTHREAD_START_ROUTINE)EnumUsers,
+ lpszPrimaryDC,
+ 0,
+ &dwThreadID);
+
+ if (!bLocal)
+ {
+ hThreads[1] = ::CreateThread(NULL, 100,
+ (LPTHREAD_START_ROUTINE)EnumGroups,
+ lpszPrimaryDC,
+ 0,
+ &dwThreadID);
+ }
+ else usObjCount = 1;
+
+// when both threads return, add all the names to the listbox.
+ DWORD dwWait = WaitForMultipleObjects(usObjCount,
+ hThreads,
+ TRUE,
+ INFINITE);
+
+ POSITION pos;
+ CRomaineApp* pApp = (CRomaineApp*)AfxGetApp();
+
+ for (pos = csaNames.GetHeadPosition(); pos != NULL;)
+ pListBox.AddString(0, csaNames.GetNext(pos));
+
+ if (!bLocal)
+ {
+ for (pos = csaGroups.GetHeadPosition(); pos != NULL;)
+ pListBox.AddString(1, csaGroups.GetNext(pos));
+ }
+
+ if (!bLocal) NetApiBufferFree( lpszPrimaryDC );
+ else free(lpszPrimaryDC);
+
+}
+
+
+// enum users thread
+void EnumUsers(DWORD pDCName)
+{
+ wchar_t* lpszPrimaryDC = NULL;
+ lpszPrimaryDC = (TCHAR*)pDCName;
+ CString csTemp;
+
+// now enumerate the users on that machine
+ void* netUserBuffer;
+ DWORD dwReturnedEntries;
+ DWORD err = NetQueryDisplayInformation(lpszPrimaryDC, 1,
+ 0, 100, 100 * sizeof(NET_DISPLAY_USER),
+ &dwReturnedEntries, &netUserBuffer);
+
+// check return for error
+ if (err != NERR_Success && err != ERROR_MORE_DATA) return;
+
+// add these users to the dialog
+ DWORD dwCurrent;
+ NET_DISPLAY_USER* netUser;
+ netUser = (NET_DISPLAY_USER*)netUserBuffer;
+ for (dwCurrent = 0; dwCurrent < dwReturnedEntries; dwCurrent++)
+ {
+ csTemp = netUser->usri1_name;
+ csTemp += ";";
+ csTemp += netUser->usri1_comment;
+
+ if (netUser->usri1_flags & UF_NORMAL_ACCOUNT) csaNames.AddHead(csTemp);
+ else csaLNames.AddHead(csTemp);
+
+ netUser++;
+ }
+
+// add more users?
+ DWORD dwNext;
+ while (err == ERROR_MORE_DATA)
+ {
+ netUser--;
+ NetGetDisplayInformationIndex(lpszPrimaryDC, 1, netUser->usri1_name, &dwNext);
+ NetApiBufferFree(netUserBuffer);
+ err = NetQueryDisplayInformation(lpszPrimaryDC, 1,
+ dwNext, 100, 32767,
+ &dwReturnedEntries, &netUserBuffer);
+
+// check return for error
+ if (err != NERR_Success && err != ERROR_MORE_DATA) return;
+
+ netUser = (NET_DISPLAY_USER*)netUserBuffer;
+ for (dwCurrent = 0; dwCurrent < dwReturnedEntries; dwCurrent++)
+ {
+ csTemp = netUser->usri1_name;
+ csTemp += ";";
+ csTemp += netUser->usri1_comment;
+
+ if (netUser->usri1_flags & UF_NORMAL_ACCOUNT) csaNames.AddHead(csTemp);
+ else csaLNames.AddHead(csTemp);
+ netUser++;
+ }
+ }
+
+ NetApiBufferFree(netUserBuffer);
+
+}
+
+
+void EnumGroups(DWORD pDCName)
+{
+ wchar_t* lpszPrimaryDC = NULL;
+ lpszPrimaryDC = (TCHAR*)pDCName;
+ CString csTemp;
+
+ void* netGroupBuffer;
+ DWORD dwReturnedEntries;
+ DWORD dwCurrent;
+ DWORD dwNext;
+// now enumerate the groups on that machine
+ DWORD err = NetQueryDisplayInformation(lpszPrimaryDC, 3,
+ 0, 100, 100 * sizeof(NET_DISPLAY_GROUP),
+ &dwReturnedEntries, &netGroupBuffer);
+
+// check return for error
+ if (err != NERR_Success && err != ERROR_MORE_DATA) return;
+
+ NET_DISPLAY_GROUP* netGroup;
+ netGroup = (NET_DISPLAY_GROUP*)netGroupBuffer;
+
+// add these names to the dialog
+ netGroup = (NET_DISPLAY_GROUP*)netGroupBuffer;
+ for (dwCurrent = 0; dwCurrent < dwReturnedEntries; dwCurrent++)
+ {
+ csTemp = netGroup->grpi3_name;
+ csTemp += ";";
+ csTemp += netGroup->grpi3_comment;
+ csaGroups.AddHead(csTemp);
+ netGroup++;
+ }
+
+// add more names?
+ while (err == ERROR_MORE_DATA)
+ {
+ netGroup--;
+ NetGetDisplayInformationIndex(lpszPrimaryDC, 3, netGroup->grpi3_name, &dwNext);
+ NetApiBufferFree(netGroupBuffer);
+ err = NetQueryDisplayInformation(lpszPrimaryDC, 3,
+ dwNext, 100, 32767,
+ &dwReturnedEntries, &netGroupBuffer);
+
+// check return for error
+ if (err != NERR_Success && err != ERROR_MORE_DATA) return;
+
+ netGroup = (NET_DISPLAY_GROUP*)netGroupBuffer;
+ for (dwCurrent = 0; dwCurrent < dwReturnedEntries; dwCurrent++)
+ {
+ csTemp = netGroup->grpi3_name;
+ csTemp += ";";
+ csTemp += netGroup->grpi3_comment;
+ csaGroups.AddHead(csTemp);
+ netGroup++;
+ }
+ }
+ NetApiBufferFree(netGroupBuffer);
+
+}
+
+
+
+void CLUsers::OnAddButton()
+{
+ UpdateData(TRUE);
+
+// start with the domain or machine name to create the account information
+ CString csValue = m_csDomainName;
+ if (csValue.Left(2) == _T("\\\\"))
+ csValue = csValue.Right(csValue.GetLength() - 2);
+
+ csValue += "\\";
+ csValue += m_csAvailableUserList.Left(m_csAvailableUserList.Find(_T(";")));;
+
+ if (m_lbAddedUserList.FindString(-1, csValue) == LB_ERR)
+ m_lbAddedUserList.AddString(csValue, m_lbAvailableUserList.GetItemData(m_lbAvailableUserList.GetCurSel()));
+
+/*
+// start with the domain or machine name to create the account information
+ CString csValue = m_csDomainName;
+ if (csValue.Left(2) == _T("\\\\"))
+ csValue = csValue.Right(csValue.GetLength() - 2);
+ csValue += "\\";
+
+ INT* pnItems;
+ m_lbAvailableUserList.GetSelItems(1024, pnItems);
+ USHORT sCount = 0;
+ while (sCount < m_lbAvailableUserList.GetSelCount())
+ {
+ CString csUserName = csValue;
+ CString csSelItem;
+ m_lbAvailableUserList.GetText(*pnItems, csSelItem);
+
+ csUserName += csSelItem.Left(csSelItem.Find(_T(";")));
+
+ if (m_lbAddedUserList.FindString(-1, csUserName) == LB_ERR)
+ m_lbAddedUserList.AddString(csUserName,
+ m_lbAvailableUserList.GetItemData(*pnItems));
+
+ pnItems++;
+ sCount++;
+ }
+ */
+}
+
+LRESULT CLUsers::OnWizardBack()
+{
+ CRomaineApp* pApp = (CRomaineApp*)AfxGetApp();
+ if (pApp->m_bServer) return IDD_GROUP_TYPE_DLG;
+ else if (pApp->m_csCmdLine != L"") return IDD_GROUP_LIST_DIALOG;
+ else if (pApp->m_sMode == 1) return IDD_GROUP_LIST_DIALOG;
+ else return IDD_LR_DIALOG;
+
+}
+
+LRESULT CLUsers::OnWizardNext()
+{
+ CRomaineApp* pApp = (CRomaineApp*)AfxGetApp();
+ pApp->m_cps1.SetWizardButtons(PSWIZB_FINISH | PSWIZB_BACK);
+
+// empty the list
+ pApp->m_csaNames.RemoveAll();
+
+// fill with new names.
+ USHORT us;
+ CString csTemp;
+ for (us = 0; us < m_lbAddedUserList.GetCount(); us++)
+ {
+ m_lbAddedUserList.GetText(us, csTemp);
+ pApp->m_csaNames.AddHead(csTemp);
+ }
+
+ return IDD_FINISH_DLG;
+}
+
+void CLUsers::OnSelchangeDomainCombo()
+{
+ UpdateData(TRUE);
+ m_lbAvailableUserList.ResetContent();
+ if (m_csDomainName.Left(2) == "\\\\")
+ CatalogAccounts((const TCHAR*)m_csDomainName, m_lbAvailableUserList, TRUE);
+ else
+ CatalogAccounts((const TCHAR*)m_csDomainName, m_lbAvailableUserList);
+
+}
+
+void CLUsers::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CPropertyPage::OnShowWindow(bShow, nStatus);
+ CRomaineApp* pApp = (CRomaineApp*)AfxGetApp();
+
+ CWaitCursor wait;
+ if (bShow)
+ {
+ if (m_csServer != pApp->m_csServer)
+ {
+ m_csServer = pApp->m_csServer;
+ m_lbAddedUserList.ResetContent();
+ }
+// on a rerun clean out the members from the last group
+ else if (pApp->bRestart2)
+ {
+ m_lbAddedUserList.ResetContent();
+ pApp->bRestart2 = FALSE;
+ }
+ else return;
+
+ m_csDomainList.ResetContent();
+// get domain list
+ CWaitCursor wait;
+
+ CTrustList pList;
+ if (!pList.BuildTrustList((LPTSTR)pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength())))
+ {
+ AfxMessageBox(IDS_NO_WKSALLOWED);
+ pApp->m_cps1.SetActivePage(1);
+ return;
+ }
+
+ UINT i;
+ for(i = 0 ; i < pList.m_dwTrustCount ; i++)
+ m_csDomainList.AddString(pList.m_ppszTrustList[i]);
+
+// remove the current machine from the list
+ if ((i = m_csDomainList.FindStringExact(-1, pApp->m_csServer.Right(pApp->m_csServer.GetLength() - 2))) != LB_ERR)
+ m_csDomainList.DeleteString(i);
+
+// put machine name into list (assuming we are adding to a machine and not a domain)
+ if (!pApp->m_bDomain) m_csDomainList.AddString(pApp->m_csServer);
+
+// get primary domain
+ DWORD dwRet;
+ HKEY hKey;
+ DWORD cbProv = 0;
+ TCHAR* lpProv = NULL;
+
+ CRomaineApp* pApp = (CRomaineApp*)AfxGetApp();
+ long lRet = RegConnectRegistry(
+ (LPTSTR)pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength()),
+ HKEY_LOCAL_MACHINE,
+ &hKey);
+
+ dwRet = RegOpenKey(hKey,
+ TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"), &hKey );
+
+ TCHAR* lpPrimaryDomain = NULL;
+ if ((dwRet = RegQueryValueEx( hKey, TEXT("CachePrimaryDomain"), NULL, NULL, NULL, &cbProv )) == ERROR_SUCCESS)
+ {
+ lpPrimaryDomain = (TCHAR*)malloc(cbProv);
+ if (lpPrimaryDomain == NULL)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
+ exit(1);
+ }
+
+ dwRet = RegQueryValueEx( hKey, TEXT("CachePrimaryDomain"), NULL, NULL, (LPBYTE) lpPrimaryDomain, &cbProv );
+
+ }
+
+ m_csPrimaryDomain = lpPrimaryDomain;
+ free(lpPrimaryDomain);
+ RegCloseKey(hKey);
+
+ CatalogAccounts((const TCHAR*)m_csPrimaryDomain, m_lbAvailableUserList);
+ m_csDomainList.SelectString(-1, (const TCHAR*)m_csPrimaryDomain);
+
+ GetDlgItem(IDC_AVAILABLE_LOCAL_USERS)->SetFocus();
+ m_lbAvailableUserList.SetCurSel(0);
+
+// editing a group? add the current members
+ if (pApp->m_sMode == 1)
+ {
+ DWORD dwEntriesRead;
+ DWORD dwTotalEntries;
+ DWORD dwResumeHandle = 0;
+ // m_lbAddedUserList.ResetContent();
+
+ TCHAR* pServer = pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength());
+ pApp->m_csServer.ReleaseBuffer();
+
+ TCHAR* pGroup = pApp->m_csGroupName.GetBuffer(pApp->m_csGroupName.GetLength());
+ pApp->m_csGroupName.ReleaseBuffer();
+
+ PLOCALGROUP_MEMBERS_INFO_1 pMembers;
+ NET_API_STATUS nApi = NetLocalGroupGetMembers(pServer,
+ pGroup,
+ 1,
+ (LPBYTE*)&pMembers,
+ 5000,
+ &dwEntriesRead,
+ &dwTotalEntries,
+ &dwResumeHandle);
+
+ if (nApi != ERROR_SUCCESS) return;
+
+ USHORT sIndex;
+ for (sIndex = 0; sIndex < dwEntriesRead; sIndex++)
+ {
+ TCHAR pName[50];
+ DWORD dwNameSize = 50;
+ TCHAR pDomain[50];
+ DWORD dwDomainNameSize = 50;
+ SID_NAME_USE pUse;
+ LookupAccountSid(pServer, pMembers[sIndex].lgrmi1_sid,
+ pName, &dwNameSize,
+ pDomain, &dwDomainNameSize,
+ &pUse);
+
+ wchar_t sTemp[150];
+ swprintf(sTemp, TEXT("%s\\%s"), pDomain, pName);
+
+ if (pUse == 1) m_lbAddedUserList.AddString(0, sTemp);
+ else m_lbAddedUserList.AddString(1, sTemp);
+ }
+
+ NetApiBufferFree(pMembers);
+
+ while (dwResumeHandle != 0)
+ {
+ nApi = NetLocalGroupGetMembers(pServer,
+ pGroup,
+ 1,
+ (LPBYTE*)&pMembers,
+ 5000,
+ &dwEntriesRead,
+ &dwTotalEntries,
+ &dwResumeHandle);
+
+ if (nApi != ERROR_SUCCESS) return;
+
+ USHORT sIndex;
+ for (sIndex = 0; sIndex < dwEntriesRead; sIndex++)
+ {
+ TCHAR pName[50];
+ DWORD dwNameSize = 50;
+ TCHAR pDomain[50];
+ DWORD dwDomainNameSize = 50;
+ SID_NAME_USE pUse;
+ LookupAccountSid(pServer, pMembers[sIndex].lgrmi1_sid,
+ pName, &dwNameSize,
+ pDomain, &dwDomainNameSize,
+ &pUse);
+
+ wchar_t sTemp[150];
+ swprintf(sTemp, TEXT("%s\\%s"), pDomain, pName);
+
+ if (pUse == 1) m_lbAddedUserList.AddString(0, sTemp);
+ else m_lbAddedUserList.AddString(1, sTemp);
+
+ }
+ NetApiBufferFree(pMembers);
+ }
+ }
+ }
+
+}
+
+
+void CLUsers::OnDblclkAddedLocalUsers()
+{
+// CString csSelItem;
+// int nSel = m_lbAddedUserList.GetCaretIndex();
+// m_lbAddedUserList.DeleteString(nSel);
+ m_lbAddedUserList.DeleteString(m_lbAddedUserList.GetCurSel());
+
+}
+
+void CLUsers::OnDblclkAvailableLocalUsers()
+{
+ UpdateData(TRUE);
+// start with the domain or machine name to create the account information
+ CString csValue = m_csDomainName;
+ if (csValue.Left(2) == _T("\\\\"))
+ csValue = csValue.Right(csValue.GetLength() - 2);
+
+ csValue += "\\";
+ csValue += m_csAvailableUserList.Left(m_csAvailableUserList.Find(_T(";")));;
+
+ if (m_lbAddedUserList.FindString(-1, csValue) == LB_ERR)
+ m_lbAddedUserList.AddString(csValue, m_lbAvailableUserList.GetItemData(m_lbAvailableUserList.GetCurSel()));
+// start with the domain or machine name to create the account information
+/* CString csValue = m_csDomainName;
+ if (csValue.Left(2) == _T("\\\\"))
+ csValue = csValue.Right(csValue.GetLength() - 2);
+
+ csValue += "\\";
+
+ CString csSelItem;
+ int nSel = m_lbAvailableUserList.GetCaretIndex();
+ m_lbAvailableUserList.GetText(nSel, csSelItem);
+ csValue += csSelItem.Left(csSelItem.Find(_T(";")));
+
+ if (m_lbAddedUserList.FindString(-1, csValue) == LB_ERR)
+ m_lbAddedUserList.AddString(csValue, m_lbAvailableUserList.GetItemData(nSel));
+ */
+
+
+}
+
+void CLUsers::OnSetfocusAvailableLocalUsers()
+{
+ GetDlgItem(IDC_ADD_BUTTON)->EnableWindow(TRUE);
+ GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(FALSE);
+ m_lbAddedUserList.SetCurSel(-1);
+
+}
+
+void CLUsers::OnSetfocusAddedLocalUsers()
+{
+ GetDlgItem(IDC_ADD_BUTTON)->EnableWindow(FALSE);
+ GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(TRUE);
+ m_lbAvailableUserList.SetCurSel(-1);
+
+}
+
+void CLUsers::OnRemoveButton()
+{
+/* INT* pnItems;
+ m_lbAddedUserList.GetSelItems(1024, pnItems);
+ USHORT sCount = 0;
+ while (sCount < m_lbAddedUserList.GetSelCount())
+ {
+ // m_lbAddedUserList.DeleteString(*pnItems);
+ TRACE(L"Item = %d\n\r", *pnItems);
+
+ pnItems++;
+ sCount++;
+ }
+ */
+ m_lbAddedUserList.DeleteString(m_lbAddedUserList.GetCurSel());
+ m_lbAddedUserList.SetCurSel(0);
+
+}
diff --git a/private/utils/wizards/addgrpw/lusers.h b/private/utils/wizards/addgrpw/lusers.h
new file mode 100644
index 000000000..def773edb
--- /dev/null
+++ b/private/utils/wizards/addgrpw/lusers.h
@@ -0,0 +1,72 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ LUsers.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+/////////////////////////////////////////////////////////////////////////////
+// CLUsers dialog
+
+class CLUsers : public CPropertyPage
+{
+ DECLARE_DYNCREATE(CLUsers)
+
+// Construction
+public:
+ CLUsers();
+ ~CLUsers();
+
+// Dialog Data
+ //{{AFX_DATA(CLUsers)
+ enum { IDD = IDD_LOCAL_USERS };
+ CUserList m_lbAddedUserList;
+ CUserList m_lbAvailableUserList;
+ CComboBox m_csDomainList;
+ CString m_csDomainName;
+ CString m_csAvailableUserList;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CLUsers)
+ public:
+ virtual LRESULT OnWizardBack();
+ virtual LRESULT OnWizardNext();
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CLUsers)
+ virtual BOOL OnInitDialog();
+ afx_msg void OnAddButton();
+ afx_msg void OnSelchangeDomainCombo();
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ afx_msg void OnDblclkAddedLocalUsers();
+ afx_msg void OnDblclkAvailableLocalUsers();
+ afx_msg void OnSetfocusAvailableLocalUsers();
+ afx_msg void OnSetfocusAddedLocalUsers();
+ afx_msg void OnRemoveButton();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+private:
+ void LoadDomainList();
+ void CatalogAccounts(const TCHAR* lpDomain, CUserList& pListBox, BOOL bLocal = FALSE);
+
+ CStringArray m_csaDomainList;
+ CString m_csMyMachineName;
+ CString m_csPrimaryDomain;
+ CString m_csServer;
+};
diff --git a/private/utils/wizards/addgrpw/makefile b/private/utils/wizards/addgrpw/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/wizards/addgrpw/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/wizards/addgrpw/nettree.cpp b/private/utils/wizards/addgrpw/nettree.cpp
new file mode 100644
index 000000000..4c7038b67
--- /dev/null
+++ b/private/utils/wizards/addgrpw/nettree.cpp
@@ -0,0 +1,578 @@
+/**********************************************************************/
+/** Microsoft Windows NT **/
+/** Copyright(c) Microsoft Corp., 1991-1996 **/
+/**********************************************************************/
+
+/*
+ NetTree.cpp : implementation file
+
+ FILE HISTORY:
+ Randyfe Jan-1996 created for Licence compliancy wizard
+ Jony Apr-1996 modified to fit this wizard
+*/
+
+
+#include "stdafx.h"
+#include "Romaine.h"
+#include "resource.h"
+#include "NetTree.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// Global variables
+
+extern TCHAR pszTreeEvent[];
+
+/////////////////////////////////////////////////////////////////////////////
+// CNetTreeCtrl
+
+CNetTreeCtrl::CNetTreeCtrl()
+: m_pThread(NULL), m_bExitThread(FALSE), m_event(TRUE, TRUE, pszTreeEvent)
+{
+ // Get a handle to the process heap
+ m_hHeap = ::GetProcessHeap();
+
+ ASSERT(m_hHeap != NULL);
+}
+
+CNetTreeCtrl::~CNetTreeCtrl()
+{
+ // Make sure the tree thread knows it's time to exit.
+ NotifyThread(TRUE);
+
+ // Create an event object to match the tree thread event object.
+ CEvent event(TRUE, TRUE, pszTreeEvent);
+
+ // Create a lock object for the event object.
+ CSingleLock lock(&event);
+
+ // Lock the lock object and make the main thread wait for the
+ // threads to signal their event objects.
+ lock.Lock();
+
+ // Free all of the pointers to LPTSTRs in the list
+ POSITION pos = m_ptrlistStrings.GetHeadPosition();
+
+ while (pos != NULL)
+ {
+ // Memory deallocation fails if there's a null char
+ // at the end of the string.
+ LPTSTR psz = m_ptrlistStrings.GetNext(pos);
+ *(::_tcslen(psz) + psz) = (TCHAR)0xFD;
+ delete[] psz;
+ }
+
+ // Free all of the pointers to NETRESOURCE structs in the list
+ pos = m_ptrlistContainers.GetHeadPosition();
+
+ while (pos != NULL)
+ {
+ delete m_ptrlistContainers.GetNext(pos);
+ }
+}
+
+
+BEGIN_MESSAGE_MAP(CNetTreeCtrl, CTreeCtrl)
+ //{{AFX_MSG_MAP(CNetTreeCtrl)
+ ON_NOTIFY_REFLECT(TVN_ITEMEXPANDING, OnItemExpanding)
+ ON_WM_SETCURSOR()
+ ON_WM_DESTROY()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// Global functions
+
+UINT FillTree(LPVOID pParam)
+{
+ CEvent event(TRUE, TRUE, pszTreeEvent);
+ CRomaineApp* pApp = (CRomaineApp*)AfxGetApp();
+ PTREEINFO pti = (PTREEINFO)pParam;
+ CNetTreeCtrl* pTree = (CNetTreeCtrl*)pti->pTree;
+ BOOL bResult = FALSE;
+ DWORD dwEntries = 0xFFFFFFFF;
+ LPVOID lpvBuffer = NULL;
+ HANDLE hEnum = NULL;
+
+ // Because this function may call itself, keep a usage count
+ // so that pti is freed only when the first instance returns.
+ static USHORT uUsage = 0;
+
+ // Keep a handle to the heap in case the CNetTreeCtrl object
+ // goes away before the thread ends.
+ HANDLE hHeap = pTree->m_hHeap;
+ DWORD dwResult;
+ LPNETRESOURCE pnrRoot;
+ HTREEITEM hTreeItem, hTreeExpand;
+
+ hTreeItem = hTreeExpand = NULL;
+
+ try
+ {
+ // Unsignal the event object.
+ event.ResetEvent();
+
+ // Show the wait cursor
+ pTree->BeginWaitCursor();
+
+ // Exit if the handle to the heap is invalid.
+ if (hHeap == NULL)
+ goto ExitFunction;
+
+ if (pti->hTreeItem == TVI_ROOT)
+ {
+ pnrRoot = NULL;
+ if (pTree->m_imagelist.Create(IDB_NET_TREE, 16, 3, CNetTreeCtrl::IMG_MASK))
+ {
+ pTree->SetImageList(&(pTree->m_imagelist), TVSIL_NORMAL);
+ pTree->m_imagelist.SetBkColor(CLR_NONE);
+ }
+ }
+ else
+ pnrRoot = (LPNETRESOURCE)pTree->GetItemData(pti->hTreeItem);
+
+ // Get an enumeration handle.
+ if ((dwResult = ::WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_ANY,
+ RESOURCEUSAGE_CONTAINER, pnrRoot, &hEnum)) != NO_ERROR)
+ {
+ // Exit if WNetOpenEnum fails.
+ dwResult = ::GetLastError();
+ goto ExitFunction;
+ }
+
+ // Allocate a buffer for enumeration.
+ if ((lpvBuffer = ::HeapAlloc(hHeap, HEAP_ZERO_MEMORY, pti->dwBufSize)) == NULL)
+ // Exit if memory allocation failed
+ goto ExitFunction;
+
+ // Retrieve a block of network entries.
+ while ((dwResult = ::WNetEnumResource(hEnum, &dwEntries, lpvBuffer, &(pti->dwBufSize))) != ERROR_NO_MORE_ITEMS)
+ {
+ // See if it's time to exit.
+ if (pTree->m_bExitThread)
+ {
+ pTree->NotifyThread(FALSE);
+ bResult = TRUE;
+ goto ExitFunction;
+ }
+
+ // Exit if WNetEnumResource failed.
+ if (dwResult != NO_ERROR)
+ {
+ dwResult = ::GetLastError();
+ goto ExitFunction;
+ }
+
+ LPNETRESOURCE pnrLeaf = (LPNETRESOURCE)lpvBuffer;
+ TV_INSERTSTRUCT tviLeaf;
+
+ // Fill in the TV_INSERTSTRUCT members.
+ tviLeaf.hParent = pti->hTreeItem;
+ tviLeaf.hInsertAfter = TVI_SORT;
+ tviLeaf.item.hItem = NULL;
+ tviLeaf.item.state = 0;
+ tviLeaf.item.stateMask = 0;
+ tviLeaf.item.cchTextMax = 0;
+ tviLeaf.item.iSelectedImage = 0;
+
+ // Set the correct image for the leaf.
+ switch (pnrLeaf->dwDisplayType)
+ {
+ case RESOURCEDISPLAYTYPE_DOMAIN:
+ tviLeaf.item.iImage = tviLeaf.item.iSelectedImage = CNetTreeCtrl::IMG_DOMAIN;
+ break;
+
+ case RESOURCEDISPLAYTYPE_SERVER:
+ tviLeaf.item.iImage = tviLeaf.item.iSelectedImage = CNetTreeCtrl::IMG_SERVER;
+ break;
+
+ default:
+ tviLeaf.item.iImage = tviLeaf.item.iSelectedImage = CNetTreeCtrl::IMG_ROOT;
+ }
+
+ // Fool the tree into thinking that this leaf has children
+ // since we don't know initially.
+ if (pnrLeaf->dwDisplayType == RESOURCEDISPLAYTYPE_SERVER)
+ {
+ tviLeaf.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ tviLeaf.item.cChildren = 0;
+ }
+ else
+ {
+ tviLeaf.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_CHILDREN | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ tviLeaf.item.cChildren = 1;
+ }
+
+ // Add leaves to the branch.
+ for (DWORD i = 0; i < dwEntries; i++)
+ {
+ // See if it's time to exit.
+ if (pTree->m_bExitThread)
+ {
+ pTree->NotifyThread(FALSE);
+ bResult = TRUE;
+ goto ExitFunction;
+ }
+
+ // Create a permanent NETRESOURCE struct for later use.
+ LPNETRESOURCE pnrTemp = new NETRESOURCE;
+ pTree->m_ptrlistContainers.AddTail(pnrTemp);
+
+ ::memcpy(pnrTemp, pnrLeaf, sizeof(NETRESOURCE));
+
+ if (pnrLeaf->lpRemoteName != NULL)
+ {
+ pnrTemp->lpRemoteName = new TCHAR[::_tcslen(pnrLeaf->lpRemoteName) + 1];
+ ::_tcscpy(pnrTemp->lpRemoteName, pnrLeaf->lpRemoteName);
+ pTree->m_ptrlistStrings.AddTail(pnrTemp->lpRemoteName);
+ }
+
+ if (pnrLeaf->lpProvider != NULL)
+ {
+ pnrTemp->lpProvider = new TCHAR[::_tcslen(pnrLeaf->lpProvider) + 1];
+ ::_tcscpy(pnrTemp->lpProvider, pnrLeaf->lpProvider);
+ pTree->m_ptrlistStrings.AddTail(pnrTemp->lpProvider);
+ }
+
+ // Increment the buffer pointer.
+ pnrLeaf++;
+
+ // Use "Enterprise" as the item text if this is the root.
+ if (pti->hTreeItem == TVI_ROOT)
+ {
+ CString strRoot;
+
+ tviLeaf.item.pszText = new TCHAR[::_tcslen(pnrTemp->lpProvider) + 1];
+ ::_tcscpy(tviLeaf.item.pszText, (LPCTSTR)pnrTemp->lpProvider);
+ }
+ else if (pnrTemp->dwDisplayType == RESOURCEDISPLAYTYPE_SERVER)
+ {
+ // Skip the initial backslashes before adding the server
+ // name to the tree.
+ tviLeaf.item.pszText = pnrTemp->lpRemoteName;// + 2;
+ }
+ else
+ tviLeaf.item.pszText = pnrTemp->lpRemoteName;
+
+ tviLeaf.item.lParam = (LPARAM)(LPVOID)pnrTemp;
+
+ // Make sure the pointer to the tree control is still valid.
+ if (::IsWindow(pTree->m_hWnd))
+ {
+ hTreeItem = pTree->InsertItem(&tviLeaf);
+ }
+ else // Otherwise, exit the thread.
+ {
+ bResult = TRUE;
+ goto ExitFunction;
+ }
+
+ // Delete the string allocated for the root node text.
+ if (pti->hTreeItem == TVI_ROOT)
+ delete tviLeaf.item.pszText;
+
+ // See if the lpRemoteName member is equal to the default domain
+ // name.
+ if (!_tcscmp(pnrTemp->lpRemoteName, pApp->m_csCurrentDomain) ||
+ pti->hTreeItem == TVI_ROOT)
+ {
+
+ // Store the handle.
+ hTreeExpand = hTreeItem;
+ }
+
+ // Select the name of the license server in the tree.
+ if (!_tcscmp(pnrTemp->lpRemoteName, pApp->m_csCurrentMachine))
+ {
+ pTree->SelectItem(hTreeItem);
+ pTree->SetFocus();
+ }
+ }
+
+ // Everything went all right.
+ bResult = TRUE;
+ }
+
+ // Expand the branch but only if it isn't the root.
+ // The root item thinks it has children, but really doesn't the first time through.
+ if (pti->hTreeItem != TVI_ROOT && pTree->ItemHasChildren(pti->hTreeItem))
+ {
+ // Indicate that the branch has been expanded once.
+ pTree->SetItemState(pti->hTreeItem, TVIS_EXPANDEDONCE, TVIS_EXPANDEDONCE);
+ pTree->Expand(pti->hTreeItem, TVE_EXPAND);
+ }
+
+ // Fill the branch for the current domain if the bExpand member is TRUE.
+ if (hTreeExpand != NULL && pti->bExpand)
+ {
+ TREEINFO ti;
+
+ ti.hTreeItem = hTreeExpand;
+ ti.dwBufSize = pti->dwBufSize;
+ ti.pTree = pti->pTree;
+ ti.bExpand = TRUE;
+
+ // Increment the usage count.
+ uUsage++;
+
+ ::FillTree((LPVOID)&ti);
+
+ // Decrement the usage count.
+ uUsage--;
+ }
+
+ ExitFunction:
+ // Display a message if an error occurred.
+ if (!bResult)
+ pTree->ErrorHandler(dwResult);
+
+ // Close the enumeration handle.
+ if (hEnum != NULL)
+ if (!(bResult = (::WNetCloseEnum(hEnum) == NO_ERROR)))
+ dwResult = ::GetLastError();
+
+ // Free memory allocated on the heap.
+ if (lpvBuffer != NULL)
+ ::HeapFree(hHeap, 0, lpvBuffer);
+
+ // Free the TREEINFO pointer only if the usage count is zero.
+ if (uUsage == 0)
+ delete pti;
+
+ // Reset the thread pointer.
+ pTree->m_pThread = NULL;
+
+ // Turn off the wait cursor
+ pTree->EndWaitCursor();
+
+ // Make sure the tree control still exists before posting a message.
+ if (::IsWindow(pTree->m_hWnd))
+ pTree->PostMessage(WM_SETCURSOR);
+
+ // Signal the event object.
+ if (uUsage == 0)
+ event.SetEvent();
+
+ return (UINT)!bResult;
+ }
+ catch(...)
+ {
+ // Close the enumeration handle.
+ if (hEnum != NULL)
+ if (!(bResult = (::WNetCloseEnum(hEnum) == NO_ERROR)))
+ dwResult = ::GetLastError();
+
+ // Free memory allocated on the heap.
+ if (lpvBuffer != NULL)
+ ::HeapFree(hHeap, 0, lpvBuffer);
+
+ // Free the TREEINFO pointer
+ delete pti;
+
+ // Reset the thread pointer.
+ pTree->m_pThread = NULL;
+
+ // Turn off the wait cursor
+ pTree->EndWaitCursor();
+
+ // Signal the event object.
+ event.SetEvent();
+
+ return (UINT)2;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CNetTreeCtrl member functions
+
+BOOL CNetTreeCtrl::PopulateTree(BOOL bExpand /* = TRUE */, const HTREEITEM hParentBranch /* = TVI_ROOT */,
+ DWORD dwBufSize /* = BUFFER_SIZE */)
+{
+ PTREEINFO pti = new TREEINFO;
+
+ pti->hTreeItem = hParentBranch;
+ pti->dwBufSize = dwBufSize;
+ pti->pTree = this;
+ pti->bExpand = bExpand;
+
+ // Don't begin a new thread until the last one has ended.
+ if (m_pThread != NULL)
+ {
+ NotifyThread(TRUE);
+
+ CEvent event(TRUE, TRUE, pszTreeEvent);
+ CSingleLock lock(&event);
+
+ // Wait.
+ lock.Lock();
+ }
+
+ m_pThread = AfxBeginThread((AFX_THREADPROC)::FillTree, (LPVOID)pti);
+
+ return TRUE;
+}
+
+void CNetTreeCtrl::ErrorHandler(const DWORD dwCode)
+{
+ CString strError;
+ BOOL bNetError = FALSE;
+
+#ifdef _DEBUG
+ switch (dwCode)
+ {
+ case ERROR_MORE_DATA:
+ strError = "ERROR_MORE_DATA";
+ break;
+
+ case ERROR_INVALID_HANDLE:
+ strError = "ERROR_INVALID_HANDLE";
+ break;
+
+ case ERROR_NOT_CONTAINER:
+ strError = "ERROR_NOT_CONTAINER";
+ break;
+
+ case ERROR_INVALID_PARAMETER:
+ strError = "ERROR_INVALID_PARAMETER";
+ break;
+
+ case ERROR_NO_NETWORK:
+ strError = "ERROR_NO_NETWORK";
+ break;
+
+ case ERROR_EXTENDED_ERROR:
+ strError = "ERROR_EXTENDED_ERROR";
+ break;
+
+ default:
+ {
+#endif // _DEBUG
+ DWORD dwErrCode;
+ CString strErrDesc, strProvider;
+ LPTSTR pszErrDesc = strErrDesc.GetBuffer(MAX_STRING);
+ LPTSTR pszProvider = strProvider.GetBuffer(MAX_STRING);
+
+ if (::WNetGetLastError(&dwErrCode, pszErrDesc, MAX_STRING,
+ pszProvider, MAX_STRING) == NO_ERROR)
+ {
+ strErrDesc.ReleaseBuffer();
+ strProvider.ReleaseBuffer();
+
+ CString strErrMsg;
+
+ // Don't display the WNetGetLastError message if dwErrCode == 0.
+ if (dwErrCode)
+ {
+ // Trim of any leading or trailing white space.
+ strProvider.TrimRight();
+ strProvider.TrimLeft();
+ strErrDesc.TrimRight();
+ strErrDesc.TrimLeft();
+ strErrMsg.Format(IDS_NET_ERROR, strProvider, strErrDesc);
+ }
+ else
+ strErrMsg.LoadString(IDS_NET_NO_SERVERS);
+
+ MessageBox(strErrMsg, AfxGetAppName(), MB_OK | MB_ICONEXCLAMATION);
+
+ bNetError = TRUE;
+ }
+ else
+ strError.LoadString(IDS_ERROR);
+#ifdef _DEBUG
+ }
+ }
+#endif // _DEBUG
+
+ if (!bNetError)
+ AfxMessageBox(strError, MB_OK | MB_ICONEXCLAMATION);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CNetTreeCtrl functions
+
+void CNetTreeCtrl::NotifyThread(BOOL bExit)
+{
+ CCriticalSection cs;
+
+ if (cs.Lock())
+ {
+ m_bExitThread = bExit;
+ cs.Unlock();
+ }
+}
+
+void CNetTreeCtrl::PumpMessages()
+{
+ // Must call Create() before using the dialog
+ ASSERT(m_hWnd!=NULL);
+
+ MSG msg;
+ // Handle dialog messages
+ while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ if(!IsDialogMessage(&msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CNetTreeCtrl message handlers
+
+void CNetTreeCtrl::OnItemExpanding(NMHDR* pNMHDR, LRESULT* pResult)
+{
+ NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
+
+ // Exit and stop expansion if the thread is running.
+ if (m_pThread != NULL)
+ {
+ *pResult = TRUE;
+ return;
+ }
+
+ // Exit if this branch has been expanded once.
+ if (!(pNMTreeView->itemNew.state & TVIS_EXPANDEDONCE))
+ {
+ // Add new leaves to the branch.
+ if (pNMTreeView->itemNew.mask & TVIF_HANDLE)
+ {
+ PopulateTree(FALSE, pNMTreeView->itemNew.hItem);
+ pNMTreeView->itemNew.mask |= TVIS_EXPANDEDONCE;
+ }
+ }
+
+ *pResult = FALSE;
+}
+
+BOOL CNetTreeCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
+{
+ if (m_pThread == NULL)
+ {
+ return CTreeCtrl::OnSetCursor(pWnd, nHitTest, message);
+ }
+ else
+ {
+ // Restore the wait cursor if the thread is running.
+ RestoreWaitCursor();
+
+ return TRUE;
+ }
+}
+
+void CNetTreeCtrl::OnDestroy()
+{
+ NotifyThread(TRUE);
+ PumpMessages();
+
+ CTreeCtrl::OnDestroy();
+}
+
diff --git a/private/utils/wizards/addgrpw/nettree.h b/private/utils/wizards/addgrpw/nettree.h
new file mode 100644
index 000000000..48a8c41e1
--- /dev/null
+++ b/private/utils/wizards/addgrpw/nettree.h
@@ -0,0 +1,94 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ NetTree.h : header file
+
+File History:
+
+ Randyfe Jan-96 created
+
+--*/
+
+
+// NetTree.h : header file
+//
+/////////////////////////////////////////////////////////////////////////////
+// Global declarations
+
+UINT FillTree(LPVOID pParam);
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CNetTreeCtrl window
+
+class CNetTreeCtrl : public CTreeCtrl
+{
+// Construction
+public:
+ CNetTreeCtrl();
+ virtual ~CNetTreeCtrl();
+
+// Data members
+public:
+ enum
+ {
+ ROOT_LEVEL = 0x0,
+ DOMAIN_LEVEL = 0x1,
+ SERVER_LEVEL = 0x2,
+
+ BUFFER_SIZE = 0x4000,
+ MAX_STRING = 0x100,
+
+ IMG_ROOT = 0,
+ IMG_DOMAIN = 1,
+ IMG_SERVER = 2,
+
+ IMG_SIZE = 16,
+ IMG_GROW = 3,
+ IMG_MASK = RGB(0xFF, 0xFF, 0xFF)
+ };
+
+public:
+ HANDLE m_hHeap;
+ CImageList m_imagelist;
+ CTypedPtrList<CPtrList, LPNETRESOURCE> m_ptrlistContainers;
+ CTypedPtrList<CPtrList, LPTSTR> m_ptrlistStrings;
+ CWinThread* m_pThread;
+ CEvent m_event;
+ BOOL m_bExitThread;
+
+// Attributes
+public:
+
+// Operations
+public:
+ BOOL PopulateTree(BOOL bExpand= TRUE, const HTREEITEM hParentBranch = TVI_ROOT, DWORD dwBufSize = BUFFER_SIZE);
+ void ErrorHandler(const DWORD dwCode);
+ void NotifyThread(BOOL bExit);
+
+protected:
+ void PumpMessages();
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CNetTreeCtrl)
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+
+ // Generated message map functions
+protected:
+ //{{AFX_MSG(CNetTreeCtrl)
+ afx_msg void OnItemExpanding(NMHDR* pNMHDR, LRESULT* pResult);
+ afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
+ afx_msg void OnDestroy();
+ //}}AFX_MSG
+
+ DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/private/utils/wizards/addgrpw/res/endflag.bmp b/private/utils/wizards/addgrpw/res/endflag.bmp
new file mode 100644
index 000000000..2deab795c
--- /dev/null
+++ b/private/utils/wizards/addgrpw/res/endflag.bmp
Binary files differ
diff --git a/private/utils/wizards/addgrpw/res/global.bmp b/private/utils/wizards/addgrpw/res/global.bmp
new file mode 100644
index 000000000..aab380fbf
--- /dev/null
+++ b/private/utils/wizards/addgrpw/res/global.bmp
Binary files differ
diff --git a/private/utils/wizards/addgrpw/res/group.bmp b/private/utils/wizards/addgrpw/res/group.bmp
new file mode 100644
index 000000000..c0886c97f
--- /dev/null
+++ b/private/utils/wizards/addgrpw/res/group.bmp
Binary files differ
diff --git a/private/utils/wizards/addgrpw/res/groupb.bmp b/private/utils/wizards/addgrpw/res/groupb.bmp
new file mode 100644
index 000000000..f060a7d45
--- /dev/null
+++ b/private/utils/wizards/addgrpw/res/groupb.bmp
Binary files differ
diff --git a/private/utils/wizards/addgrpw/res/luser.bmp b/private/utils/wizards/addgrpw/res/luser.bmp
new file mode 100644
index 000000000..ddee6e956
--- /dev/null
+++ b/private/utils/wizards/addgrpw/res/luser.bmp
Binary files differ
diff --git a/private/utils/wizards/addgrpw/res/net_tree.bmp b/private/utils/wizards/addgrpw/res/net_tree.bmp
new file mode 100644
index 000000000..89a17b4d2
--- /dev/null
+++ b/private/utils/wizards/addgrpw/res/net_tree.bmp
Binary files differ
diff --git a/private/utils/wizards/addgrpw/res/romaine.ico b/private/utils/wizards/addgrpw/res/romaine.ico
new file mode 100644
index 000000000..43a5c0cca
--- /dev/null
+++ b/private/utils/wizards/addgrpw/res/romaine.ico
Binary files differ
diff --git a/private/utils/wizards/addgrpw/res/romaine.rc2 b/private/utils/wizards/addgrpw/res/romaine.rc2
new file mode 100644
index 000000000..db4bef79f
--- /dev/null
+++ b/private/utils/wizards/addgrpw/res/romaine.rc2
@@ -0,0 +1,26 @@
+//
+// ROMAINE.RC2 - resources Microsoft Visual C++ does not edit directly
+//
+
+#ifdef APSTUDIO_INVOKED
+ #error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Add manually edited resources here...
+
+/////////////////////////////////////////////////////////////////////////////
+
+//
+// Version resources
+//
+#include <winver.h>
+#include <ntverp.h>
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Group management wizard"
+#define VER_INTERNALNAME_STR "romaine.exe"
+#define VER_ORIGINALFILENAME_STR "addgrpw.exe"
+#include <common.ver>
+
diff --git a/private/utils/wizards/addgrpw/res/user.bmp b/private/utils/wizards/addgrpw/res/user.bmp
new file mode 100644
index 000000000..b615d743c
--- /dev/null
+++ b/private/utils/wizards/addgrpw/res/user.bmp
Binary files differ
diff --git a/private/utils/wizards/addgrpw/res/world.bmp b/private/utils/wizards/addgrpw/res/world.bmp
new file mode 100644
index 000000000..d4c1f2a31
--- /dev/null
+++ b/private/utils/wizards/addgrpw/res/world.bmp
Binary files differ
diff --git a/private/utils/wizards/addgrpw/resource.h b/private/utils/wizards/addgrpw/resource.h
new file mode 100644
index 000000000..1329bd5ce
--- /dev/null
+++ b/private/utils/wizards/addgrpw/resource.h
@@ -0,0 +1,106 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by Romaine.rc
+//
+#define IDS_GENERIC_NO_HEAP 1
+#define IDS_GENERIC_NO_PDC 2
+#define IDS_GENERIC_BAD_MACHINE 3
+#define IDS_NO_GROUP_NAME 4
+#define IDS_GROUP_INVALID_NAME 5
+#define IDS_DOMAIN_SET 6
+#define IDS_TREE_ROOT 7
+#define IDS_NET_ERROR 8
+#define IDS_NET_NO_SERVERS 9
+#define IDS_ERROR 10
+#define IDS_GROUP_EXISTS 11
+#define IDS_INSUFFICIENT_PERMISSION 12
+#define IDS_CANT_ADD_NAMES 13
+#define IDS_LOCAL_GROUP 14
+#define IDS_GLOBAL_GROUP 15
+#define IDS_NO_MACHINE_NAME 16
+#define IDS_SUCCESS 17
+#define IDS_NO_DC 18
+#define IDS_NO_GROUP_SELECTED 19
+#define IDS_GROUP_DELETED 20
+#define IDS_GROUP_NOT_DELETED 21
+#define IDD_ROMAINE_DIALOG 102
+#define IDD_WELCOME_DLG 102
+#define IDD_NAME_DLG 106
+#define IDR_MAINFRAME 128
+#define IDD_MACHINE_DLG 130
+#define IDD_GROUP_TYPE_DLG 131
+#define IDD_LOCAL_USERS 132
+#define IDD_GLOBAL_USERS 133
+#define IDB_WORLD 133
+#define IDB_USER_BITMAP 134
+#define IDD_FINISH_DLG 134
+#define IDB_LOCAL_GROUP_BITMAP 135
+#define IDB_GLOBAL_GROUP_BITMAP 136
+#define IDB_LUSER_BITMAP 137
+#define IDB_NET_TREE 138
+#define IDB_BITMAP1 143
+#define IDD_GROUP_LIST_DIALOG 144
+#define IDD_LR_DIALOG 145
+#define IDB_END_FLAG 148
+#define IDC_PICTURE_BOX 1000
+#define IDC_MACHINE_NAME 1001
+#define IDC_GROUP_NAME 1002
+#define IDC_GROUP_TYPE_RADIO 1003
+#define IDC_RADIO2 1004
+#define IDC_AVAILABLE_LOCAL_USERS 1005
+#define IDC_ADDED_LOCAL_USERS 1006
+#define IDC_ADD_BUTTON 1007
+#define IDC_DOMAIN_COMBO 1008
+#define IDC_AVAILABLE_MEMBERS_LIST 1009
+#define IDC_SELECTED_MEMBERS_LIST 1010
+#define IDC_REMOVE_BUTTON 1012
+#define IDC_DESCRIPTION 1013
+#define IDC_SERVER_TREE 1014
+#define IDC_GROUP_STATIC 1015
+#define IDC_GROUP_TYPE_STATIC 1016
+#define IDC_LOCATION_STATIC 1017
+#define IDC_NEW_GROUP_RADIO 1018
+#define IDC_LOCAL_RADIO 1019
+#define IDC_REMOTE_RADIO 1020
+#define IDC_GROUP_LIST 1021
+#define IDC_ADD_NEW_BUTTON 1022
+#define IDC_DELETE_BUTTON 1023
+#define IDC_STATIC1 1025
+#define IDC_STATIC2 1026
+#define IDC_WELCOME 1028
+#define IDC_FILE_TREE 1100
+#define IDC_FILE_LIST 1101
+#define IDD_MACHINEDLG 1102
+#define IDP_OLE_INIT_FAILED 1103
+#define IDS_INVOKECMD_FAILED 1104
+#define IDS_GETUIOBJOF_FAILED 1105
+#define IDS_BAD_VERSION 1106
+#define IDS_ANOTHER_TRY 57345
+#define IDS_CREATE_TEXT 57346
+#define IDS_MODIFY_TEXT 57347
+#define IDS_CREATE_TEXT2 57348
+#define IDS_MODIFY_TEXT2 57349
+#define IDS_WELCOME 57350
+#define IDS_MODIFY3 57351
+#define IDS_CREATE3 57352
+#define IDS_SUCCESS_CREATE_RETRY 57353
+#define IDS_CANT_ADD_NAMES_CREATE_RETRY 57354
+#define IDS_SUCCESS_MODIFY_RETRY 57355
+#define IDS_CANT_ADD_NAMES_MODIFY_RETRY 57356
+#define IDS_UNKNOWN_ERROR 57357
+#define IDS_DELETE_GROUP_CONFIRM 57358
+#define IDS_CANT_ADDNAME 57359
+#define IDS_CANT_GET_USERS 57360
+#define IDS_NO_WKSALLOWED 57361
+#define IDS_GROUP 57362
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 149
+#define _APS_NEXT_COMMAND_VALUE 32771
+#define _APS_NEXT_CONTROL_VALUE 1029
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/private/utils/wizards/addgrpw/romaine.cpp b/private/utils/wizards/addgrpw/romaine.cpp
new file mode 100644
index 000000000..55da11e4d
--- /dev/null
+++ b/private/utils/wizards/addgrpw/romaine.cpp
@@ -0,0 +1,294 @@
+/**********************************************************************/
+/** Microsoft Windows NT **/
+/** Copyright(c) Microsoft Corp., 1991-1996 **/
+/**********************************************************************/
+
+/*
+ stdafx.cpp
+
+ Romaine.cpp : Defines the class behaviors for the application.
+
+ FILE HISTORY:
+ jony Apr-1996 created
+*/
+
+#include "stdafx.h"
+#include "NetTree.h"
+#include "Romaine.h"
+#include "Welcome.h"
+#include "Where.h"
+#include "Type.h"
+#include "What.h"
+#include "userlist.h"
+#include "LUsers.h"
+#include "GUsers.h"
+#include "finish.h"
+#include "ExGrp.h"
+#include "LRem.h"
+
+#include <winreg.h>
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+TCHAR pszTreeEvent[] = _T("TreeThread");
+extern int ClassifyMachine(CString& csMachine);
+
+/////////////////////////////////////////////////////////////////////////////
+// CRomaineApp
+
+BEGIN_MESSAGE_MAP(CRomaineApp, CWinApp)
+ //{{AFX_MSG_MAP(CRomaineApp)
+ //}}AFX_MSG
+// ON_COMMAND(ID_HELP, CWinApp::OnHelp)
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CRomaineApp construction
+
+CRomaineApp::CRomaineApp()
+{
+ bRestart1 = FALSE;
+ bRestart2 = FALSE;
+
+// get our primary domain and save it for NETTREE
+ DWORD dwRet;
+ HKEY hKey;
+ DWORD cbProv = 0;
+ TCHAR* lpProv = NULL;
+
+ CRomaineApp* pApp = (CRomaineApp*)AfxGetApp();
+
+ dwRet = RegOpenKey(HKEY_LOCAL_MACHINE,
+ TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"), &hKey );
+
+ TCHAR* lpPrimaryDomain = NULL;
+ if ((dwRet = RegQueryValueEx( hKey, TEXT("CachePrimaryDomain"), NULL, NULL, NULL, &cbProv )) == ERROR_SUCCESS)
+ {
+ lpPrimaryDomain = (TCHAR*)malloc(cbProv);
+ if (lpPrimaryDomain == NULL)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
+ exit(1);
+ }
+
+ dwRet = RegQueryValueEx( hKey, TEXT("CachePrimaryDomain"), NULL, NULL, (LPBYTE) lpPrimaryDomain, &cbProv );
+
+ }
+
+ RegCloseKey(hKey);
+
+ pApp->m_csCurrentDomain = lpPrimaryDomain;
+
+// store the machine name too
+ CString csMachineName;
+ DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1;
+ GetComputerName(csMachineName.GetBufferSetLength(MAX_COMPUTERNAME_LENGTH + 1), &dwSize);
+
+ pApp->m_csCurrentMachine = "\\\\";
+ pApp->m_csCurrentMachine += csMachineName;
+
+ free(lpPrimaryDomain);
+
+
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// The one and only CRomaineApp object
+
+CRomaineApp theApp;
+
+/////////////////////////////////////////////////////////////////////////////
+// CRomaineApp initialization
+BOOL CRomaineApp::IsSecondInstance()
+{
+ HANDLE hSem;
+
+ //create a semaphore object with max count of 1
+ hSem = CreateSemaphore(NULL, 0, 1, L"Group Wizard Semaphore");
+ if (hSem!=NULL && GetLastError() == ERROR_ALREADY_EXISTS) {
+ CloseHandle(hSem);
+ CString csAppName;
+ csAppName.LoadString(AFX_IDS_APP_TITLE);
+ CWnd* pWnd = CWnd::FindWindow(NULL, (LPCTSTR)csAppName);
+
+ if (pWnd)
+ pWnd->SetForegroundWindow();
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOL CRomaineApp::InitInstance()
+{
+// check for OS version
+ OSVERSIONINFO os;
+ os.dwOSVersionInfoSize = sizeof(os);
+ GetVersionEx(&os);
+
+ if (os.dwMajorVersion < 4)
+ {
+ AfxMessageBox(IDS_BAD_VERSION, MB_ICONSTOP);
+ ExitProcess(0);
+ }
+
+ if (IsSecondInstance())
+ return FALSE;
+
+// if there is a directory name on the command line, load an extra class
+ if (m_lpCmdLine[0] != '\0')
+ {
+ m_csCmdLine = m_lpCmdLine;
+ m_sCmdLine = __argc;
+
+ TCHAR* pFolder = _tcstok(m_lpCmdLine, L" ");
+ if (_tcsicmp(pFolder, L"/folder")) return FALSE; // anything else on the cmdline and boot it out
+
+ m_sMode = 1;
+ if (m_sCmdLine == 3)
+ {
+ TCHAR* pParam3 = _tcstok(NULL, L" ");
+ if (*(pParam3 + 1) == 'g')
+ {
+ pParam3+=3;
+ m_csCmdLineGroupName = pParam3;
+ }
+ else
+ {
+ pParam3+=3;
+ m_csServer = pParam3;
+ if (ClassifyMachine(m_csServer) == -1) ExitProcess(1);
+ }
+ }
+
+ if (m_sCmdLine == 4)
+ {
+ TCHAR* pParam3 = _tcstok(NULL, L" ");
+ TCHAR* pParam4 = _tcstok(NULL, L" ");
+ if (*(pParam3 + 1) == 'g')
+ {
+ pParam3+=3;
+ pParam4+=3;
+ m_csCmdLineGroupName = pParam3;
+ m_csServer = pParam4;
+ }
+ else
+ {
+ pParam3+=3;
+ pParam4+=3;
+ m_csServer = pParam3;
+ m_csCmdLineGroupName = pParam4;
+ }
+
+ if (ClassifyMachine(m_csServer) == -1) ExitProcess(1);
+ }
+ }
+
+#ifdef _AFXDLL
+ Enable3dControls(); // Call this when using MFC in a shared DLL
+#else
+ Enable3dControlsStatic(); // Call this when linking to MFC statically
+#endif
+
+// create the property sheet,set 'wizmode' & set app icon
+ m_cps1.SetTitle(TEXT("Group Management Wizard"), 0);
+
+ m_cps1.SetWizardMode();
+
+ CWelcome* pWelcome = new CWelcome;
+ CLRem* pLRem = new CLRem;
+ CWhere* pWhere = new CWhere;
+ CType* pType = new CType;
+ CWhat* pWhat = new CWhat;
+ CExGrp* pEx = new CExGrp;
+
+ CLUsers* pLUsers = new CLUsers;
+ CGUsers* pGUsers = new CGUsers;
+ CFinish* pFinish = new CFinish;
+
+// add pages
+ m_cps1.AddPage(pEx);
+
+ m_cps1.AddPage(pWelcome);
+ m_cps1.AddPage(pWhat);
+ m_cps1.AddPage(pLRem);
+ m_cps1.AddPage(pWhere);
+ m_cps1.AddPage(pType);
+ m_cps1.AddPage(pLUsers);
+ m_cps1.AddPage(pGUsers);
+ m_cps1.AddPage(pFinish);
+
+// show the wizard
+ if (m_csServer != L"") m_cps1.SetActivePage(0);
+ else m_cps1.SetActivePage(1);
+
+ m_cps1.DoModal();
+
+// clean up
+ delete pWelcome;
+ delete pWhere;
+ delete pLRem;
+ delete pType;
+ delete pWhat;
+ delete pLUsers;
+ delete pGUsers;
+ delete pFinish;
+ delete pEx;
+
+ return FALSE;
+}
+/////////////////////////////////////////////////////////////////////////////
+// CMySheet
+
+IMPLEMENT_DYNAMIC(CMySheet, CPropertySheet)
+
+CMySheet::CMySheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage)
+ :CPropertySheet(nIDCaption, pParentWnd, iSelectPage)
+{
+}
+
+CMySheet::CMySheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage)
+ :CPropertySheet(pszCaption, pParentWnd, iSelectPage)
+{
+}
+
+CMySheet::CMySheet() : CPropertySheet()
+{
+}
+
+CMySheet::~CMySheet()
+{
+}
+
+
+BEGIN_MESSAGE_MAP(CMySheet, CPropertySheet)
+ //{{AFX_MSG_MAP(CMySheet)
+ ON_WM_CREATE()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CMySheet message handlers
+
+BOOL CMySheet::OnInitDialog()
+{
+ CRomaineApp* pApp = (CRomaineApp*)AfxGetApp();
+ HICON hIcon = LoadIcon(pApp->m_hInstance, MAKEINTRESOURCE(IDR_MAINFRAME));
+ ::SetClassLong(m_hWnd, GCL_HICON, (long)hIcon);
+
+ return CPropertySheet::OnInitDialog();
+}
+
+int CMySheet::OnCreate(LPCREATESTRUCT lpCreateStruct)
+{
+ if (CPropertySheet::OnCreate(lpCreateStruct) == -1)
+ return -1;
+
+// lpCreateStruct->style = WS_OVERLAPPEDWINDOW;
+
+ return 0;
+}
diff --git a/private/utils/wizards/addgrpw/romaine.h b/private/utils/wizards/addgrpw/romaine.h
new file mode 100644
index 000000000..e8cfd2aa1
--- /dev/null
+++ b/private/utils/wizards/addgrpw/romaine.h
@@ -0,0 +1,125 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Romaine.h : main header file for the ROMAINE application
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+#ifndef __AFXWIN_H__
+ #error include 'stdafx.h' before including this file for PCH
+#endif
+
+#include "resource.h" // main symbols
+
+/////////////////////////////////////////////////////////////////////////////
+// CMySheet
+
+class CMySheet : public CPropertySheet
+{
+ DECLARE_DYNAMIC(CMySheet)
+
+// Construction
+public:
+ CMySheet(UINT nIDCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0);
+ CMySheet(LPCTSTR pszCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0);
+ CMySheet();
+
+// Attributes
+public:
+
+// Operations
+public:
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CMySheet)
+ public:
+ virtual BOOL OnInitDialog();
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CMySheet();
+
+ // Generated message map functions
+protected:
+ //{{AFX_MSG(CMySheet)
+ afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////////////////////////////
+// CRomaineApp:
+// See Romaine.cpp for the implementation of this class
+//
+
+typedef struct tagTREEINFO
+{
+ HTREEITEM hTreeItem;
+ DWORD dwBufSize;
+ CObject* pTree;
+ BOOL bExpand;
+}
+TREEINFO, *PTREEINFO;
+
+class CRomaineApp : public CWinApp
+{
+public:
+ CRomaineApp();
+
+ CMySheet m_cps1;
+
+ BOOL m_bServer;
+ BOOL m_bDomain;
+ CString m_csServer;
+ CString m_csDomain;
+ CString m_csCurrentDomain;
+ CString m_csCurrentMachine;
+
+// group attributes
+ CString m_csGroupName;
+ CString m_csGroupDesc;
+
+ int m_nGroupType;
+
+ CStringList m_csaNames;
+
+// cmdline stuff
+ CString m_csCmdLine;
+ short m_sCmdLine;
+ CString m_csCmdLineGroupName;
+
+ USHORT m_sMode;
+
+ CPropertyPage* pMach;
+ BOOL bRestart2;
+ BOOL bRestart1;
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CRomaineApp)
+ public:
+ virtual BOOL InitInstance();
+ //}}AFX_VIRTUAL
+
+// Implementation
+
+ //{{AFX_MSG(CRomaineApp)
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+private:
+ BOOL IsSecondInstance();
+
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/private/utils/wizards/addgrpw/romaine.rc b/private/utils/wizards/addgrpw/romaine.rc
new file mode 100644
index 000000000..c3e65be67
--- /dev/null
+++ b/private/utils/wizards/addgrpw/romaine.rc
@@ -0,0 +1,423 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
+ "#define _AFX_NO_OLE_RESOURCES\r\n"
+ "#define _AFX_NO_TRACKER_RESOURCES\r\n"
+ "#define _AFX_NO_PROPERTY_RESOURCES\r\n"
+ "\r\n"
+ "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
+ "#ifdef _WIN32\r\n"
+ "LANGUAGE 9, 1\r\n"
+ "#pragma code_page(1252)\r\n"
+ "#endif\r\n"
+ "#include ""res\\Romaine.rc2"" // non-Microsoft Visual C++ edited resources\r\n"
+ "#include ""afxres.rc"" // Standard components\r\n"
+ "#endif\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDR_MAINFRAME ICON DISCARDABLE "res\\Romaine.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_WELCOME_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 269
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 134
+ END
+
+ IDD_NAME_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 269
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 133
+ END
+
+ IDD_GROUP_TYPE_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 269
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 133
+ END
+
+ IDD_LOCAL_USERS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 269
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 133
+ END
+
+ IDD_GLOBAL_USERS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 269
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 133
+ END
+
+ IDD_FINISH_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 269
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 133
+ END
+
+ IDD_GROUP_LIST_DIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 269
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 133
+ END
+
+ IDD_LR_DIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 269
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 133
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_MACHINE_DLG DIALOG DISCARDABLE 0, 0, 276, 140
+STYLE WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Group Management Wizard"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Computer name:",IDC_STATIC,91,39,151,8
+ EDITTEXT IDC_MACHINE_NAME,91,49,181,14,ES_AUTOHSCROLL
+ CONTROL "Tree1",IDC_SERVER_TREE,"SysTreeView32",TVS_HASBUTTONS |
+ TVS_HASLINES | TVS_LINESATROOT | WS_BORDER | WS_TABSTOP,
+ 91,67,181,73
+ LTEXT "Type the computer or domain name where you want to manage group accounts. Computer names are preceded by \\\\. Or select the computer or domain name from the list.",
+ IDC_STATIC,91,0,182,34
+ CONTROL 143,IDC_PICTURE_BOX,"Static",SS_BITMAP | SS_SUNKEN,0,0,
+ 80,140
+END
+
+IDD_WELCOME_DLG DIALOG DISCARDABLE 0, 0, 276, 141
+STYLE WS_MINIMIZEBOX | WS_POPUP | WS_DISABLED | WS_CAPTION
+CAPTION "Group Management Wizard"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL 143,IDC_PICTURE_BOX,"Static",SS_BITMAP | SS_SUNKEN,0,0,
+ 80,140
+ LTEXT "",IDC_WELCOME,91,7,183,16
+ LTEXT "With this wizard you can create a new group and add members to that group. You can also change the members in an existing group.",
+ IDC_STATIC,91,27,178,24
+ LTEXT "What do you want to do?",IDC_STATIC,91,66,81,8
+ CONTROL "&Create a new group and add members",
+ IDC_NEW_GROUP_RADIO,"Button",BS_AUTORADIOBUTTON |
+ WS_GROUP,91,80,136,10
+ CONTROL "&Modify an existing group",IDC_RADIO2,"Button",
+ BS_AUTORADIOBUTTON,91,94,122,10
+END
+
+IDD_NAME_DLG DIALOG DISCARDABLE 0, 0, 276, 140
+STYLE WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Group Management Wizard"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Type the name you want to give this new group:",
+ IDC_STATIC,92,14,178,8
+ EDITTEXT IDC_GROUP_NAME,92,24,184,14,ES_AUTOHSCROLL
+ LTEXT "Type a &description for this group (optional):",
+ IDC_STATIC,92,59,177,8
+ EDITTEXT IDC_DESCRIPTION,92,69,184,14,ES_AUTOHSCROLL
+ CONTROL 143,IDC_PICTURE_BOX,"Static",SS_BITMAP | SS_SUNKEN,0,0,
+ 80,140
+END
+
+IDD_GROUP_TYPE_DLG DIALOG DISCARDABLE 0, 0, 276, 140
+STYLE WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Group Management Wizard"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "You can create two types of groups:",IDC_STATIC,91,6,
+ 159,8
+ CONTROL "&Global Group",IDC_GROUP_TYPE_RADIO,"Button",
+ BS_AUTORADIOBUTTON | WS_GROUP,91,108,64,10
+ CONTROL "&Local Group",IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,91,
+ 123,59,10
+ LTEXT "A global group, which contains user accounts from the domain where it is created. A global group can be used in its own domain and in trusting domains.",
+ IDC_STATIC,91,22,184,25
+ CONTROL 143,IDC_PICTURE_BOX,"Static",SS_BITMAP,0,0,80,140
+ LTEXT "A local group, which contains user and group accounts from its own domain and from trusted domains. A local group can only be used on servers in its own domain.",
+ IDC_STATIC,91,56,183,25
+ LTEXT "What type of group do you want to create?",IDC_STATIC,
+ 91,88,136,8
+END
+
+IDD_LOCAL_USERS DIALOG DISCARDABLE 0, 0, 276, 140
+STYLE WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Group Management Wizard"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&Domain",IDC_STATIC,0,24,59,8
+ COMBOBOX IDC_DOMAIN_COMBO,0,34,89,61,CBS_DROPDOWNLIST | CBS_SORT |
+ WS_VSCROLL | WS_TABSTOP
+ LTEXT "A&vailable members:",IDC_STATIC,0,49,90,8
+ LISTBOX IDC_AVAILABLE_LOCAL_USERS,0,59,89,81,LBS_SORT |
+ LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | WS_VSCROLL |
+ WS_TABSTOP
+ LTEXT "Added &members:",IDC_STATIC,152,49,90,9
+ LISTBOX IDC_ADDED_LOCAL_USERS,152,59,124,81,LBS_SORT |
+ LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS |
+ LBS_WANTKEYBOARDINPUT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "&Add >",IDC_ADD_BUTTON,98,67,44,14,WS_DISABLED
+ PUSHBUTTON "< &Remove",IDC_REMOVE_BUTTON,98,85,44,14,WS_DISABLED
+ LTEXT "Select the user or group you want to have membership in the local group, then click Add. To add names from other domains, select a different domain name.",
+ IDC_STATIC,0,0,275,24
+END
+
+IDD_GLOBAL_USERS DIALOG DISCARDABLE 0, 0, 276, 140
+STYLE WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Group Management Wizard"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "A&vailable members:",IDC_STATIC,0,25,62,8
+ LISTBOX IDC_AVAILABLE_MEMBERS_LIST,0,35,99,105,LBS_SORT |
+ LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS |
+ LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "&Selected members:",IDC_STATIC,177,25,61,8
+ LISTBOX IDC_SELECTED_MEMBERS_LIST,176,35,99,105,LBS_SORT |
+ LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS |
+ LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "&Add ->",IDC_ADD_BUTTON,113,54,50,14
+ PUSHBUTTON "<- &Remove",IDC_REMOVE_BUTTON,113,73,50,14
+ LTEXT "Select the user or group you want to have membership in the global group, then click Add.",
+ IDC_STATIC,0,0,265,18
+END
+
+IDD_FINISH_DLG DIALOG DISCARDABLE 0, 0, 276, 140
+STYLE WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Group Management Wizard"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "",IDC_STATIC2,89,53,182,37
+ LTEXT "",IDC_STATIC1,89,5,126,8
+ LTEXT "Static",IDC_GROUP_TYPE_STATIC,89,18,181,8
+ LTEXT "on",IDC_STATIC,89,29,9,8
+ LTEXT "Static",IDC_LOCATION_STATIC,102,29,165,8
+END
+
+IDD_GROUP_LIST_DIALOG DIALOG DISCARDABLE 0, 0, 276, 140
+STYLE WS_POPUP | WS_CAPTION
+CAPTION "Group Management Wizard"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LISTBOX IDC_GROUP_LIST,0,33,275,81,LBS_SORT |
+ LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS |
+ LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_HSCROLL |
+ WS_TABSTOP
+ PUSHBUTTON "&Add New",IDC_ADD_NEW_BUTTON,225,18,50,14,NOT
+ WS_VISIBLE | WS_DISABLED
+ PUSHBUTTON "&Delete",IDC_DELETE_BUTTON,225,120,50,14
+ LTEXT "The following is a list of groups you can modify. To add or remove members in the group, select the group and click Next.",
+ IDC_STATIC,0,0,275,16
+ LTEXT "To delete a group, select the group and click Delete.",
+ IDC_STATIC,0,122,193,8
+END
+
+IDD_LR_DIALOG DIALOG DISCARDABLE 0, 0, 276, 140
+STYLE WS_CHILD | WS_CAPTION
+CAPTION "Group Management Wizard"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "On &my computer",IDC_LOCAL_RADIO,"Button",
+ BS_AUTORADIOBUTTON | WS_GROUP,91,35,155,10
+ CONTROL "On &another computer or a domain",IDC_REMOTE_RADIO,
+ "Button",BS_AUTORADIOBUTTON,91,51,147,10
+ LTEXT "",IDC_STATIC1,91,9,137,19
+ CONTROL 143,IDC_PICTURE_BOX,"Static",SS_BITMAP | SS_SUNKEN,0,0,
+ 80,140
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_WORLD BITMAP DISCARDABLE "res\\world.bmp"
+IDB_USER_BITMAP BITMAP DISCARDABLE "res\\user.bmp"
+IDB_LOCAL_GROUP_BITMAP BITMAP DISCARDABLE "res\\group.bmp"
+IDB_GLOBAL_GROUP_BITMAP BITMAP DISCARDABLE "res\\global.bmp"
+IDB_LUSER_BITMAP BITMAP DISCARDABLE "res\\luser.bmp"
+IDB_NET_TREE BITMAP DISCARDABLE "res\\net_tree.bmp"
+IDB_BITMAP1 BITMAP DISCARDABLE "res\\groupb.bmp"
+IDB_END_FLAG BITMAP DISCARDABLE "res\\endflag.BMP"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_GENERIC_NO_HEAP "There is insufficient memory to continue. This program will stop."
+ IDS_GENERIC_NO_PDC "Unable to find a domain controller for this domain. Group and user lists are unavailable."
+ IDS_GENERIC_BAD_MACHINE "Unable to find the computer. The selected computer is either offline or not a Windows NT Workstation or Windows NT Server."
+ IDS_NO_GROUP_NAME "You must provide a group name."
+ IDS_GROUP_INVALID_NAME "The name you typed is too long. Please provide a group name that is 20 characters or less. Names can contain any characters except: ? \\ * "" < > | / [ ] ; : , + ="
+ IDS_DOMAIN_SET "The selected computer is a domain controller. Focus will be set to its affiliated primary domain."
+ IDS_TREE_ROOT "Enterprise"
+ IDS_NET_ERROR "IDS_NET_ERROR"
+ IDS_NET_NO_SERVERS "No servers were found in the selected domain."
+ IDS_ERROR "IDS_ERROR"
+ IDS_GROUP_EXISTS "There is already a group by this name on the selected server. Please choose a different name."
+ IDS_INSUFFICIENT_PERMISSION
+ "You do not have permission to add a group to this server."
+ IDS_CANT_ADD_NAMES "Unable to add names to the new group. An empty group will be created."
+ IDS_LOCAL_GROUP "local group:"
+ IDS_GLOBAL_GROUP "global group:"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_INVOKECMD_FAILED "InvokeCommand failed. hr = %lx"
+ IDS_GETUIOBJOF_FAILED "GetUIObjectOf failed! hr = %lx"
+ IDS_BAD_VERSION "You need to be running Windows NT version 4.00 in order to use this application."
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_NO_MACHINE_NAME "Please enter a computer name or a domain name."
+ IDS_SUCCESS "The group was created and all selected names were successfully added."
+ IDS_NO_DC "Unable to find a domain controller for this domain."
+ IDS_NO_GROUP_SELECTED "Please select a group."
+ IDS_GROUP_DELETED "The selected group was successfully deleted."
+ IDS_GROUP_NOT_DELETED "An error has occurred. The selected group was not deleted."
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDP_OLE_INIT_FAILED "OLE initialization failed. Make sure that the OLE libraries are the correct version."
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ AFX_IDS_APP_TITLE "Group Management Wizard"
+ IDS_ANOTHER_TRY "Would you like to restart the wizard?"
+ IDS_CREATE_TEXT "You are creating the following"
+ IDS_MODIFY_TEXT "You are modifying the following"
+ IDS_CREATE_TEXT2 "Click Finish to create the group or Cancel to exit the wizard without creating the group."
+ IDS_MODIFY_TEXT2 "Click Finish to modify the group or Cancel to exit the wizard without modifying the group."
+ IDS_WELCOME "Welcome to the Group Management Wizard"
+ IDS_MODIFY3 "What is the location of this group?"
+ IDS_CREATE3 "Where do you want to create this group?"
+ IDS_SUCCESS_CREATE_RETRY
+ "The group was successfully created. Would you like to restart the wizard?"
+ IDS_CANT_ADD_NAMES_CREATE_RETRY
+ "Unable to add names to the new group. An empty group will be created. Would you like to create another one?"
+ IDS_SUCCESS_MODIFY_RETRY
+ "The group was successfully modified. Would you like to restart the wizard?"
+ IDS_CANT_ADD_NAMES_MODIFY_RETRY
+ "Unable to modify the members of this group. Would you like to restart the wizard?"
+ IDS_UNKNOWN_ERROR "An error has occurred. No changes to user groups will occur."
+ IDS_DELETE_GROUP_CONFIRM
+ "Are you sure you want to delete the selected group?"
+ IDS_CANT_ADDNAME "An error has occurred while looking up account names. Not all of the selected names will be added to this group."
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_CANT_GET_USERS "Unable to load the current members of the selected group."
+ IDS_NO_WKSALLOWED "You must be logged onto a domain account to use this wizard with groups containing other domain accounts."
+ IDS_GROUP " group:"
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#define _AFX_NO_SPLITTER_RESOURCES
+#define _AFX_NO_OLE_RESOURCES
+#define _AFX_NO_TRACKER_RESOURCES
+#define _AFX_NO_PROPERTY_RESOURCES
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE 9, 1
+#pragma code_page(1252)
+#endif
+#include "res\Romaine.rc2" // non-Microsoft Visual C++ edited resources
+#include "afxres.rc" // Standard components
+#endif
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/private/utils/wizards/addgrpw/sources b/private/utils/wizards/addgrpw/sources
new file mode 100644
index 000000000..6cc59b37e
--- /dev/null
+++ b/private/utils/wizards/addgrpw/sources
@@ -0,0 +1,62 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+TARGETNAME=addgrpw
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+USE_MFCUNICODE=1
+
+PRECOMPILED_INCLUDE=stdafx.h
+PRECOMPILED_CXX=1
+
+SOURCES=EXGRP.CPP \
+ FINISH.CPP \
+ TRSTLIST.CPP \
+ LREM.CPP \
+ WELCOME.CPP \
+ EXGRP.CPP \
+ GUSERS.CPP \
+ WHERE.CPP \
+ LUSERS.CPP \
+ NETTREE.CPP \
+ TRANSBMP.CPP \
+ ROMAINE.CPP \
+ USERLIST.CPP \
+ WHAT.CPP \
+ TYPE.CPP \
+ ROMAINE.RC
+
+UMTYPE=windows
+UMLIBS= $(BASEDIR)\public\sdk\lib\*\netapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\mpr.lib \
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\comdlg32.lib \
+ $(BASEDIR)\public\sdk\lib\*\comctl32.lib \
+ $(BASEDIR)\public\sdk\lib\*\shell32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\gdi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+
diff --git a/private/utils/wizards/addgrpw/stdafx.cpp b/private/utils/wizards/addgrpw/stdafx.cpp
new file mode 100644
index 000000000..db7e43d67
--- /dev/null
+++ b/private/utils/wizards/addgrpw/stdafx.cpp
@@ -0,0 +1,20 @@
+/**********************************************************************/
+/** Microsoft Windows NT **/
+/** Copyright(c) Microsoft Corp., 1991-1996 **/
+/**********************************************************************/
+
+/*
+ stdafx.cpp
+
+// stdafx.cpp : source file that includes just the standard includes
+// Romaine.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+
+ FILE HISTORY:
+ jony Apr-1996 created
+*/
+
+
+#include "stdafx.h"
+
diff --git a/private/utils/wizards/addgrpw/stdafx.h b/private/utils/wizards/addgrpw/stdafx.h
new file mode 100644
index 000000000..904433070
--- /dev/null
+++ b/private/utils/wizards/addgrpw/stdafx.h
@@ -0,0 +1,39 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+//
+
+#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
+
+#include <afxwin.h> // MFC core and standard components
+#include <afxext.h> // MFC extensions
+#include <afxdisp.h> // MFC OLE automation classes
+#include <afxtempl.h> // MFC templated classes
+
+#ifndef _AFX_NO_AFXCMN_SUPPORT
+#include <afxcmn.h> // MFC support for Windows 95 Common Controls
+#endif // _AFX_NO_AFXCMN_SUPPORT
+
+#include <afxmt.h> // MFC synchronization classes
+#include <winnetwk.h>
+#include <shlobj.h> // Shell objects
+#include <afxpriv.h>
+
+
+
+
+
diff --git a/private/utils/wizards/addgrpw/transbmp.cpp b/private/utils/wizards/addgrpw/transbmp.cpp
new file mode 100644
index 000000000..4634a74cd
--- /dev/null
+++ b/private/utils/wizards/addgrpw/transbmp.cpp
@@ -0,0 +1,175 @@
+/**********************************************************************/
+/** Microsoft Windows NT **/
+/** Copyright(c) Microsoft Corp., 1991-1996 **/
+/**********************************************************************/
+
+/*
+ transbmp.cpp
+
+// transbmp.cpp : implementation of the CTransBmp class
+//
+// support for transparent CBitmap objects. Used in the CUserList class.
+// Based on a class from MSDN 7/95
+
+ FILE HISTORY:
+ jony Apr-1996 created
+*/
+
+#include "stdafx.h"
+#include "transbmp.h"
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char BASED_CODE THIS_FILE[] = __FILE__;
+#endif
+
+// Colors
+#define rgbWhite RGB(255,255,255)
+// Raster op codes
+#define DSa 0x008800C6L
+#define DSx 0x00660046L
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CTransBmp construction/destruction
+
+CTransBmp::CTransBmp()
+{
+ m_iWidth = 0;
+ m_iHeight = 0;
+ m_hbmMask = NULL;
+}
+
+CTransBmp::~CTransBmp()
+{
+ if (m_hbmMask != NULL) delete m_hbmMask;
+}
+
+void CTransBmp::GetMetrics()
+{
+ // Get the width and height
+ BITMAP bm;
+ GetObject(sizeof(bm), &bm);
+ m_iWidth = bm.bmWidth;
+ m_iHeight = bm.bmHeight;
+}
+
+
+int CTransBmp::GetWidth()
+{
+ if ((m_iWidth == 0) || (m_iHeight == 0)){
+ GetMetrics();
+ }
+ return m_iWidth;
+}
+
+int CTransBmp::GetHeight()
+{
+ if ((m_iWidth == 0) || (m_iHeight == 0)){
+ GetMetrics();
+ }
+ return m_iHeight;
+}
+
+
+void CTransBmp::CreateMask(CDC* pDC)
+{
+ m_hbmMask = new CBitmap;
+// Nuke any existing mask
+ if (m_hbmMask) m_hbmMask->DeleteObject();
+
+// Create memory DCs to work with
+ CDC* hdcMask = new CDC;
+ CDC* hdcImage = new CDC;
+
+ hdcMask->CreateCompatibleDC(pDC);
+ hdcImage->CreateCompatibleDC(pDC);
+
+// Create a monochrome bitmap for the mask
+ m_hbmMask->CreateBitmap(GetWidth(),
+ GetHeight(),
+ 1,
+ 1,
+ NULL);
+
+// Select the mono bitmap into its DC
+ CBitmap* hbmOldMask = hdcMask->SelectObject(m_hbmMask);
+// Select the image bitmap into its DC
+ CBitmap* hbmOldImage = hdcImage->SelectObject(CBitmap::FromHandle((HBITMAP)m_hObject));
+
+// Set the transparency color to be the top-left pixel
+ hdcImage->SetBkColor(hdcImage->GetPixel(0, 0));
+// Make the mask
+ hdcMask->BitBlt(0, 0,
+ GetWidth(), GetHeight(),
+ hdcImage,
+ 0, 0,
+ SRCCOPY);
+// clean up
+ hdcMask->SelectObject(hbmOldMask);
+ hdcImage->SelectObject(hbmOldImage);
+ delete hdcMask;
+ delete hdcImage;
+}
+
+// draw the transparent bitmap using the created mask
+void CTransBmp::DrawTrans(CDC* pDC, int x, int y)
+{
+ if (m_hbmMask == NULL) CreateMask(pDC);
+
+ int dx = GetWidth();
+ int dy = GetHeight();
+
+// Create a memory DC to do the drawing to
+ CDC* hdcOffScr = new CDC;
+ hdcOffScr->CreateCompatibleDC(pDC);
+
+// Create a bitmap for the off-screen DC that is really
+// color compatible with the destination DC.
+ CBitmap hbmOffScr;
+ hbmOffScr.CreateBitmap(dx, dy,
+ pDC->GetDeviceCaps(PLANES),
+ pDC->GetDeviceCaps(BITSPIXEL),
+ NULL);
+
+// Select the buffer bitmap into the off-screen DC
+ HBITMAP hbmOldOffScr = (HBITMAP)hdcOffScr->SelectObject(hbmOffScr);
+
+// Copy the image of the destination rectangle to the
+// off-screen buffer DC so we can play with it
+ hdcOffScr->BitBlt(0, 0, dx, dy, pDC, x, y, SRCCOPY);
+
+// Create a memory DC for the source image
+ CDC* hdcImage = new CDC;
+ hdcImage->CreateCompatibleDC(pDC);
+
+ CBitmap* hbmOldImage = hdcImage->SelectObject(CBitmap::FromHandle((HBITMAP)m_hObject));
+
+ // Create a memory DC for the mask
+ CDC* hdcMask = new CDC;
+ hdcMask->CreateCompatibleDC(pDC);
+
+ CBitmap* hbmOldMask = hdcMask->SelectObject(m_hbmMask);
+
+ // XOR the image with the destination
+ hdcOffScr->SetBkColor(rgbWhite);
+ hdcOffScr->BitBlt(0, 0, dx, dy ,hdcImage, 0, 0, DSx);
+ // AND the destination with the mask
+ hdcOffScr->BitBlt(0, 0, dx, dy, hdcMask, 0,0, DSa);
+ // XOR the destination with the image again
+ hdcOffScr->BitBlt(0, 0, dx, dy, hdcImage, 0, 0, DSx);
+
+ // Copy the resultant image back to the screen DC
+ pDC->BitBlt(x, y, dx, dy, hdcOffScr, 0, 0, SRCCOPY);
+
+ // Tidy up
+ hdcOffScr->SelectObject(hbmOldOffScr);
+ hdcImage->SelectObject(hbmOldImage);
+ hdcMask->SelectObject(hbmOldMask);
+
+ delete hdcOffScr;
+ delete hdcImage;
+ delete hdcMask;
+}
+
+
diff --git a/private/utils/wizards/addgrpw/transbmp.h b/private/utils/wizards/addgrpw/transbmp.h
new file mode 100644
index 000000000..3593517d6
--- /dev/null
+++ b/private/utils/wizards/addgrpw/transbmp.h
@@ -0,0 +1,40 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ transbmp.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+/////////////////////////////////////////////////////////////////////////////
+
+class CTransBmp : public CBitmap
+{
+public:
+ CTransBmp();
+ ~CTransBmp();
+ void Draw(HDC hDC, int x, int y);
+ void Draw(CDC* pDC, int x, int y);
+ void DrawTrans(HDC hDC, int x, int y);
+ void DrawTrans(CDC* pDC, int x, int y);
+ int GetWidth();
+ int GetHeight();
+
+private:
+ int m_iWidth;
+ int m_iHeight;
+ CBitmap* m_hbmMask; // handle to mask bitmap
+
+ void GetMetrics();
+ void CreateMask(HDC hDC);
+ void CreateMask(CDC* pDC);
+
+};
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/private/utils/wizards/addgrpw/trstlist.cpp b/private/utils/wizards/addgrpw/trstlist.cpp
new file mode 100644
index 000000000..77e44a7b1
--- /dev/null
+++ b/private/utils/wizards/addgrpw/trstlist.cpp
@@ -0,0 +1,414 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ disptrus.c(pp)
+
+Author:
+
+ Scott Field (sfield) 16-Mar-96
+
+Revision:
+ JonY 16-Apr-96 Modified to .cpp
+
+--*/
+
+#include "stdafx.h"
+#include "trstlist.h"
+
+
+#define RTN_OK 0
+#define RTN_ERROR 13
+
+//
+// if you have the ddk, include ntstatus.h
+//
+#ifndef STATUS_SUCCESS
+#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
+#define STATUS_MORE_ENTRIES ((NTSTATUS)0x00000105L)
+#define STATUS_NO_MORE_ENTRIES ((NTSTATUS)0x8000001AL)
+#endif
+
+
+#define ELEMENT_COUNT 64 // number of array elements to allocate
+
+CTrustList::CTrustList()
+{
+ m_dwTrustCount = 0;
+ m_ppszTrustList = (LPWSTR *)HeapAlloc(
+ GetProcessHeap(), HEAP_ZERO_MEMORY,
+ ELEMENT_COUNT * sizeof(LPWSTR)
+ );
+}
+
+CTrustList::~CTrustList()
+{
+ //
+ // free trust list
+ //
+ unsigned int i;
+ for(i = 0 ; i < m_dwTrustCount ; i++) {
+ if(m_ppszTrustList[i] != NULL)
+ HeapFree(GetProcessHeap(), 0, m_ppszTrustList[i]);
+ }
+
+ HeapFree(GetProcessHeap(), 0, m_ppszTrustList);
+
+}
+
+BOOL
+CTrustList::BuildTrustList(
+ LPTSTR Target
+ )
+{
+ LSA_HANDLE PolicyHandle;
+ NTSTATUS Status;
+
+ PPOLICY_ACCOUNT_DOMAIN_INFO AccountDomain;
+ BOOL bDC;
+ NET_API_STATUS nas = NERR_Success; // assume success
+
+ BOOL bSuccess = FALSE; // assume this function will fail
+
+ //
+ // open the policy on the specified machine
+ //
+ Status = OpenPolicy(
+ Target,
+ POLICY_VIEW_LOCAL_INFORMATION,
+ &PolicyHandle
+ );
+
+ if(Status != STATUS_SUCCESS) {
+ SetLastError( LsaNtStatusToWinError(Status) );
+ return FALSE;
+ }
+
+ //
+ // obtain the AccountDomain, which is common to all three cases
+ //
+ Status = LsaQueryInformationPolicy(
+ PolicyHandle,
+ PolicyAccountDomainInformation,
+ (LPVOID*)&AccountDomain
+ );
+
+ if(Status != STATUS_SUCCESS)
+ goto cleanup;
+
+ //
+ // Note: AccountDomain->DomainSid will contain binary Sid
+ //
+ AddTrustToList(&AccountDomain->DomainName);
+
+ //
+ // free memory allocated for account domain
+ //
+ LsaFreeMemory(AccountDomain);
+
+ //
+ // find out if the target machine is a domain controller
+ //
+ if(!IsDomainController(Target, &bDC)) {
+ ////
+ goto cleanup;
+ }
+
+ if(!bDC) {
+ PPOLICY_PRIMARY_DOMAIN_INFO PrimaryDomain;
+ TCHAR* szPrimaryDomainName = NULL;
+ TCHAR* DomainController = NULL;
+
+ //
+ // get the primary domain
+ //
+ Status = LsaQueryInformationPolicy(
+ PolicyHandle,
+ PolicyPrimaryDomainInformation,
+ (LPVOID*)&PrimaryDomain
+ );
+
+ if(Status != STATUS_SUCCESS)
+ goto cleanup;
+
+ //
+ // if the primary domain Sid is NULL, we are a non-member, and
+ // our work is done.
+ //
+ if(PrimaryDomain->Sid == NULL) {
+ LsaFreeMemory(PrimaryDomain);
+ bSuccess = TRUE;
+ goto cleanup;
+ }
+
+ AddTrustToList(&PrimaryDomain->Name);
+
+ //
+ // build a copy of what we just added. This is necessary in order
+ // to lookup the domain controller for the specified domain.
+ // the Domain name must be NULL terminated for NetGetDCName(),
+ // and the LSA_UNICODE_STRING buffer is not necessarilly NULL
+ // terminated. Note that in a practical implementation, we
+ // could just extract the element we added, since it ends up
+ // NULL terminated.
+ //
+
+ szPrimaryDomainName = (LPTSTR)HeapAlloc(
+ GetProcessHeap(), 0,
+ PrimaryDomain->Name.Length + sizeof(WCHAR) // existing length + NULL
+ );
+
+ if(szPrimaryDomainName != NULL) {
+ //
+ // copy the existing buffer to the new storage, appending a NULL
+ //
+ _tcsncpy(
+ szPrimaryDomainName,
+ PrimaryDomain->Name.Buffer,
+ (PrimaryDomain->Name.Length / 2) + 1
+ );
+ }
+
+ LsaFreeMemory(PrimaryDomain);
+
+ if(szPrimaryDomainName == NULL) goto cleanup;
+
+ //
+ // get the primary domain controller computer name
+ //
+ nas = NetGetDCName(
+ NULL,
+ szPrimaryDomainName,
+ (LPBYTE *)&DomainController
+ );
+
+ HeapFree(GetProcessHeap(), 0, szPrimaryDomainName);
+
+ if(nas != NERR_Success)
+ goto cleanup;
+
+ //
+ // close the policy handle, because we don't need it anymore
+ // for the workstation case, as we open a handle to a DC
+ // policy below
+ //
+ LsaClose(PolicyHandle);
+ PolicyHandle = INVALID_HANDLE_VALUE; // invalidate handle value
+
+ //
+ // open the policy on the domain controller
+ //
+ Status = OpenPolicy(
+ DomainController,
+ POLICY_VIEW_LOCAL_INFORMATION,
+ &PolicyHandle
+ );
+
+ //
+ // free the domaincontroller buffer
+ //
+ NetApiBufferFree(DomainController);
+
+ if(Status != STATUS_SUCCESS)
+ goto cleanup;
+ }
+
+ //
+ // build additional trusted domain(s) list and indicate if successful
+ //
+ bSuccess = EnumTrustedDomains(PolicyHandle);
+
+cleanup:
+
+ //
+ // close the policy handle
+ //
+ if(PolicyHandle != INVALID_HANDLE_VALUE)
+ LsaClose(PolicyHandle);
+
+ if(!bSuccess) {
+ if(Status != STATUS_SUCCESS)
+ SetLastError( LsaNtStatusToWinError(Status) );
+ else if(nas != NERR_Success)
+ SetLastError( nas );
+ }
+
+ return bSuccess;
+}
+
+BOOL
+CTrustList::EnumTrustedDomains(
+ LSA_HANDLE PolicyHandle
+ )
+{
+ LSA_ENUMERATION_HANDLE lsaEnumHandle=0; // start an enum
+ PLSA_TRUST_INFORMATION TrustInfo;
+ ULONG ulReturned; // number of items returned
+ ULONG ulCounter; // counter for items returned
+ NTSTATUS Status;
+
+ do {
+ Status = LsaEnumerateTrustedDomains(
+ PolicyHandle, // open policy handle
+ &lsaEnumHandle, // enumeration tracker
+ (LPVOID*)&TrustInfo, // buffer to receive data
+ 32000, // recommended buffer size
+ &ulReturned // number of items returned
+ );
+ //
+ // get out if an error occurred
+ //
+ if( (Status != STATUS_SUCCESS) &&
+ (Status != STATUS_MORE_ENTRIES) &&
+ (Status != STATUS_NO_MORE_ENTRIES)
+ ) {
+ SetLastError( LsaNtStatusToWinError(Status) );
+ return FALSE;
+ }
+
+ //
+ // Display results
+ // Note: Sids are in TrustInfo[ulCounter].Sid
+ //
+ for(ulCounter = 0 ; ulCounter < ulReturned ; ulCounter++)
+ AddTrustToList(&TrustInfo[ulCounter].Name);
+
+ //
+ // free the buffer
+ //
+ LsaFreeMemory(TrustInfo);
+
+ } while (Status != STATUS_NO_MORE_ENTRIES);
+
+ return TRUE;
+}
+
+BOOL
+CTrustList::IsDomainController(
+ LPTSTR Server,
+ LPBOOL bDomainController
+ )
+{
+ PSERVER_INFO_101 si101;
+ NET_API_STATUS nas;
+
+ nas = NetServerGetInfo(
+ Server,
+ 101, // info-level
+ (LPBYTE *)&si101
+ );
+
+ if(nas != NERR_Success) {
+ SetLastError(nas);
+ return FALSE;
+ }
+
+ if( (si101->sv101_type & SV_TYPE_DOMAIN_CTRL) ||
+ (si101->sv101_type & SV_TYPE_DOMAIN_BAKCTRL) ) {
+ //
+ // we are dealing with a DC
+ //
+ *bDomainController = TRUE;
+ } else {
+ *bDomainController = FALSE;
+ }
+
+ NetApiBufferFree(si101);
+
+ return TRUE;
+}
+
+BOOL
+CTrustList::AddTrustToList(
+ PLSA_UNICODE_STRING UnicodeString
+ )
+{
+ if(m_dwTrustCount > ELEMENT_COUNT) return FALSE;
+
+ //
+ // allocate storage for array element
+ //
+ m_ppszTrustList[m_dwTrustCount] = (LPWSTR)HeapAlloc(
+ GetProcessHeap(), 0,
+ UnicodeString->Length + sizeof(WCHAR) // existing length + NULL
+ );
+
+ if(m_ppszTrustList[m_dwTrustCount] == NULL) return FALSE;
+
+ //
+ // copy the existing buffer to the new storage, appending a NULL
+ //
+ lstrcpynW(
+ m_ppszTrustList[m_dwTrustCount],
+ UnicodeString->Buffer,
+ (UnicodeString->Length / 2) + 1
+ );
+
+ m_dwTrustCount++; // increment the trust count
+
+ return TRUE;
+}
+
+void
+CTrustList::InitLsaString(
+ PLSA_UNICODE_STRING LsaString,
+ LPTSTR String
+ )
+{
+ DWORD StringLength;
+
+ if (String == NULL) {
+ LsaString->Buffer = NULL;
+ LsaString->Length = 0;
+ LsaString->MaximumLength = 0;
+
+ return;
+ }
+
+ StringLength = _tcslen(String);
+ LsaString->Buffer = String;
+ LsaString->Length = (USHORT) StringLength * sizeof(WCHAR);
+ LsaString->MaximumLength = (USHORT) (StringLength + 1) * sizeof(WCHAR);
+}
+
+NTSTATUS
+CTrustList::OpenPolicy(
+ LPTSTR ServerName,
+ DWORD DesiredAccess,
+ PLSA_HANDLE PolicyHandle
+ )
+{
+ LSA_OBJECT_ATTRIBUTES ObjectAttributes;
+ LSA_UNICODE_STRING ServerString;
+ PLSA_UNICODE_STRING Server;
+
+ //
+ // Always initialize the object attributes to all zeroes
+ //
+ ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
+
+ if(ServerName != NULL) {
+ //
+ // Make a LSA_UNICODE_STRING out of the LPWSTR passed in
+ //
+ InitLsaString(&ServerString, ServerName);
+
+ Server = &ServerString;
+ } else {
+ Server = NULL;
+ }
+
+ //
+ // Attempt to open the policy
+ //
+ return LsaOpenPolicy(
+ Server,
+ &ObjectAttributes,
+ DesiredAccess,
+ PolicyHandle
+ );
+}
+
+
diff --git a/private/utils/wizards/addgrpw/trstlist.h b/private/utils/wizards/addgrpw/trstlist.h
new file mode 100644
index 000000000..a1d407bd9
--- /dev/null
+++ b/private/utils/wizards/addgrpw/trstlist.h
@@ -0,0 +1,52 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Trstlist.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+#include <windows.h>
+#include <lm.h>
+#include <ntsecapi.h> // \mstools\security\ntsecapi.h
+#include <tchar.h>
+
+class CTrustList
+{
+ public:
+ TCHAR** m_ppszTrustList; // array of trust elements
+ DWORD m_dwTrustCount; // number of elements in m_ppszTrustList
+
+ CTrustList();
+ ~CTrustList();
+
+ BOOL BuildTrustList(LPTSTR Target);
+
+ private:
+ BOOL IsDomainController(LPTSTR Server,
+ LPBOOL bDomainController);
+
+ BOOL EnumTrustedDomains(LSA_HANDLE PolicyHandle);
+
+ BOOL AddTrustToList(PLSA_UNICODE_STRING UnicodeString);
+
+ //
+ // helper functions
+ //
+
+ void InitLsaString(PLSA_UNICODE_STRING LsaString,
+ LPTSTR String);
+
+ NTSTATUS OpenPolicy(LPTSTR ServerName,
+ DWORD DesiredAccess,
+ PLSA_HANDLE PolicyHandle);
+
+
+};
+
diff --git a/private/utils/wizards/addgrpw/type.cpp b/private/utils/wizards/addgrpw/type.cpp
new file mode 100644
index 000000000..fd875c9bd
--- /dev/null
+++ b/private/utils/wizards/addgrpw/type.cpp
@@ -0,0 +1,67 @@
+/**********************************************************************/
+/** Microsoft Windows NT **/
+/** Copyright(c) Microsoft Corp., 1991-1996 **/
+/**********************************************************************/
+
+/*
+ Type.cpp
+
+ CPropertyPage support for Group management wizard
+
+ FILE HISTORY:
+ jony Apr-1996 created
+*/
+
+#include "stdafx.h"
+#include "Romaine.h"
+#include "Type.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CType property page
+
+IMPLEMENT_DYNCREATE(CType, CPropertyPage)
+
+CType::CType() : CPropertyPage(CType::IDD)
+{
+ //{{AFX_DATA_INIT(CType)
+ m_nGroupType = 0;
+ //}}AFX_DATA_INIT
+}
+
+CType::~CType()
+{
+}
+
+void CType::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CType)
+ DDX_Radio(pDX, IDC_GROUP_TYPE_RADIO, m_nGroupType);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CType, CPropertyPage)
+ //{{AFX_MSG_MAP(CType)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CType message handlers
+
+LRESULT CType::OnWizardNext()
+{
+ UpdateData(TRUE);
+ CRomaineApp* pApp = (CRomaineApp*)AfxGetApp();
+ pApp->m_nGroupType = m_nGroupType;
+ if (m_nGroupType == 0) return IDD_GLOBAL_USERS;
+ else return IDD_LOCAL_USERS;
+
+ return CPropertyPage::OnWizardNext();
+}
diff --git a/private/utils/wizards/addgrpw/type.h b/private/utils/wizards/addgrpw/type.h
new file mode 100644
index 000000000..943a8495a
--- /dev/null
+++ b/private/utils/wizards/addgrpw/type.h
@@ -0,0 +1,50 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Type.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+/////////////////////////////////////////////////////////////////////////////
+// CType dialog
+
+class CType : public CPropertyPage
+{
+ DECLARE_DYNCREATE(CType)
+
+// Construction
+public:
+ CType();
+ ~CType();
+
+// Dialog Data
+ //{{AFX_DATA(CType)
+ enum { IDD = IDD_GROUP_TYPE_DLG };
+ int m_nGroupType;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CType)
+ public:
+ virtual LRESULT OnWizardNext();
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CType)
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+};
diff --git a/private/utils/wizards/addgrpw/userlist.cpp b/private/utils/wizards/addgrpw/userlist.cpp
new file mode 100644
index 000000000..af9c51f8f
--- /dev/null
+++ b/private/utils/wizards/addgrpw/userlist.cpp
@@ -0,0 +1,250 @@
+/**********************************************************************/
+/** Microsoft Windows NT **/
+/** Copyright(c) Microsoft Corp., 1991-1996 **/
+/**********************************************************************/
+
+/*
+ UserList.cpp
+
+ CListBox class for owner draw list that displays users and groups
+
+ FILE HISTORY:
+ jony Apr-1996 created
+*/
+
+#include "stdafx.h"
+#include "resource.h"
+#include "UserList.h"
+
+const unsigned short BITMAP_HEIGHT = 18;
+const unsigned short BITMAP_WIDTH = 18;
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CUserList
+
+CUserList::CUserList()
+{
+ m_pBitmap[0] = new CTransBmp;
+ m_pBitmap[0]->LoadBitmap(IDB_USER_BITMAP);
+
+ m_pBitmap[1] = new CTransBmp;
+ m_pBitmap[1]->LoadBitmap(IDB_GLOBAL_GROUP_BITMAP);
+
+ m_pBitmap[2] = new CTransBmp;
+ m_pBitmap[2]->LoadBitmap(IDB_WORLD);
+
+ m_pBitmap[3] = new CTransBmp;
+ m_pBitmap[3]->LoadBitmap(IDB_LOCAL_GROUP_BITMAP);
+
+ m_pBitmap[4] = new CTransBmp;
+ m_pBitmap[4]->LoadBitmap(IDB_LUSER_BITMAP);
+
+ m_sHScrollWidth = 0;
+}
+
+CUserList::~CUserList()
+{
+ delete m_pBitmap[0];
+ delete m_pBitmap[1];
+ delete m_pBitmap[2];
+ delete m_pBitmap[3];
+ delete m_pBitmap[4];
+
+}
+
+
+BEGIN_MESSAGE_MAP(CUserList, CListBox)
+ //{{AFX_MSG_MAP(CUserList)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CUserList message handlers
+void CUserList::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
+{
+// is this a valid item?
+ if ((GetCount() == LB_ERR) || (lpDrawItemStruct->itemID > (UINT)GetCount())) return;
+
+ COLORREF crefOldText;
+ COLORREF crefOldBk;
+
+ CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
+ pDC->SetBkMode(TRANSPARENT);
+
+ HBRUSH hBrush;
+ CTransBmp* pTempBmp = (CTransBmp*)lpDrawItemStruct->itemData;
+
+ switch (lpDrawItemStruct->itemAction)
+ {
+ case ODA_SELECT:
+ case ODA_DRAWENTIRE:
+// Display the text associated with the item.
+ HBITMAP hBitmapOld;
+
+// Is the item selected?
+ if (lpDrawItemStruct->itemState & ODS_SELECTED)
+ {
+ hBrush = CreateSolidBrush( GetSysColor(COLOR_HIGHLIGHT));
+ hBitmapOld = (HBITMAP)pDC->SelectObject(pTempBmp);
+
+ crefOldText = pDC->SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT) );
+ crefOldBk = pDC->SetBkColor(GetSysColor(COLOR_HIGHLIGHT) );
+ }
+ else
+ {
+ hBrush = (HBRUSH)GetStockObject( GetSysColor(COLOR_WINDOW));
+ hBitmapOld = (HBITMAP)pDC->SelectObject(pTempBmp);
+
+ crefOldText = pDC->SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
+ crefOldBk = pDC->SetBkColor(GetSysColor(COLOR_WINDOW));
+
+ }
+
+ pDC->FillRect(&(lpDrawItemStruct->rcItem), CBrush::FromHandle(hBrush));
+
+// display text
+// split apart the string to put the comments out to the side
+ TCHAR* pName = (TCHAR*)malloc(255 * sizeof(TCHAR));
+ if (pName == NULL)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
+ exit(1);
+ }
+
+ GetText(lpDrawItemStruct->itemID, pName);
+
+ TCHAR* pName2;
+ pName = _tcstok(pName, _T(";")); // gets the name
+ pName2 = _tcstok(NULL, _T(";")); // gets the comment
+
+// format the name + comment
+ int nTop = (lpDrawItemStruct->rcItem.bottom + lpDrawItemStruct->rcItem.top) / 2;
+ pDC->TextOut(BITMAP_WIDTH + 6,
+ (nTop - 8),
+ pName);
+
+ if (pName2 != NULL) pDC->TextOut(200,
+ (nTop - 8),
+ pName2);
+
+// calculate width for horizontal scrolling
+ CSize cs;
+ cs = pDC->GetTextExtent(pName2);
+ short nWidth = cs.cx + 200;
+
+ if (nWidth > m_sHScrollWidth)
+ {
+ m_sHScrollWidth = nWidth;
+ SetHorizontalExtent(m_sHScrollWidth);
+ }
+
+ free(pName);
+
+// Display bitmap
+ nTop = (lpDrawItemStruct->rcItem.bottom + lpDrawItemStruct->rcItem.top - BITMAP_HEIGHT) / 2;
+
+ pTempBmp->DrawTrans(pDC, lpDrawItemStruct->rcItem.left, nTop);
+
+ pDC->SetBkColor(crefOldBk );
+ pDC->SetTextColor(crefOldText );
+ pDC->SelectObject(hBitmapOld);
+
+ break;
+ }
+
+}
+
+int CUserList::GetSelType(short sSel)
+{
+ int sCount = 0;
+ while (sCount < 5)
+ {
+ if (m_pBitmap[sCount] == (CTransBmp*)GetItemData(sSel)) return sCount;
+ sCount ++;
+ }
+ return -1;
+
+}
+
+CString CUserList::GetGroupName(short sSel)
+{
+ CString csText;
+ GetText(sSel, csText);
+
+ csText = csText.Left(csText.Find(L";"));
+ return csText;
+}
+
+int CUserList::AddString(short nType, LPCTSTR lpItem)
+{
+ int nPos = CListBox::AddString((const TCHAR*) lpItem);
+ if (nPos == LB_ERR) return LB_ERR;
+ SetItemData(nPos, (DWORD)m_pBitmap[nType]);
+
+ return nPos;
+}
+
+int CUserList::AddString(LPCTSTR lpItem, DWORD dwBitmap)
+{
+ int nPos = CListBox::AddString((const TCHAR*) lpItem);
+ if (nPos == LB_ERR) return LB_ERR;
+ SetItemData(nPos, dwBitmap);
+
+ return nPos;
+}
+
+void CUserList::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
+{
+ lpMeasureItemStruct->itemHeight = 18;
+}
+
+
+int CUserList::VKeyToItem(UINT nKey, UINT nIndex)
+{
+ // TODO: Add your code to handle a particular virtual key
+ // return -1 = default action
+ // return -2 = no further action
+ // return index = perform default action for keystroke on
+ // item specified by index
+
+ if (nKey == 46) DeleteString(GetCurSel());
+ return -1;
+}
+
+
+int CUserList::CompareItem(LPCOMPAREITEMSTRUCT lpCompareItemStruct)
+{
+
+ TCHAR* pName1 = (TCHAR*)malloc(255 * sizeof(TCHAR));
+ if (pName1 == NULL)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
+ ExitProcess(1);
+ }
+
+ GetText(lpCompareItemStruct->itemID1, pName1);
+
+
+ TCHAR* pName2 = (TCHAR*)malloc(255 * sizeof(TCHAR));
+ if (pName2 == NULL)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
+ ExitProcess(1);
+ }
+
+ GetText(lpCompareItemStruct->itemID2, pName2);
+
+ int nRet = _tcsicmp(pName1, pName2);
+
+ free(pName1);
+ free(pName2);
+
+ return nRet;
+
+}
diff --git a/private/utils/wizards/addgrpw/userlist.h b/private/utils/wizards/addgrpw/userlist.h
new file mode 100644
index 000000000..829c1a465
--- /dev/null
+++ b/private/utils/wizards/addgrpw/userlist.h
@@ -0,0 +1,59 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ UserList.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+#include "transbmp.h"
+/////////////////////////////////////////////////////////////////////////////
+// CUserList window
+
+class CUserList : public CListBox
+{
+// Construction
+public:
+ CUserList();
+
+// Attributes
+public:
+private:
+ CTransBmp* m_pBitmap[7];
+ unsigned short m_sHScrollWidth;
+// Operations
+public:
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CUserList)
+ public:
+ virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
+ virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
+ virtual int VKeyToItem(UINT nKey, UINT nIndex);
+ virtual int CompareItem(LPCOMPAREITEMSTRUCT lpCompareItemStruct);
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CUserList();
+ int AddString(short nType, LPCTSTR lpItem);
+ int AddString(LPCTSTR lpItem, DWORD dwBitmap);
+ int GetSelType(short sSel);
+ CString GetGroupName(short sSel);
+
+ // Generated message map functions
+protected:
+ //{{AFX_MSG(CUserList)
+ //}}AFX_MSG
+
+ DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/private/utils/wizards/addgrpw/welcome.cpp b/private/utils/wizards/addgrpw/welcome.cpp
new file mode 100644
index 000000000..3ce74a3fd
--- /dev/null
+++ b/private/utils/wizards/addgrpw/welcome.cpp
@@ -0,0 +1,107 @@
+/**********************************************************************/
+/** Microsoft Windows NT **/
+/** Copyright(c) Microsoft Corp., 1991-1996 **/
+/**********************************************************************/
+
+/*
+ Welcome.cpp
+
+ Property Page support for Group management wizard
+
+ FILE HISTORY:
+ jony Apr-1996 created
+*/
+
+#include "stdafx.h"
+#include "Romaine.h"
+#include "Welcome.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CWelcome property page
+
+IMPLEMENT_DYNCREATE(CWelcome, CPropertyPage)
+
+CWelcome::CWelcome() : CPropertyPage(CWelcome::IDD)
+{
+ //{{AFX_DATA_INIT(CWelcome)
+ m_nMode = 0;
+ //}}AFX_DATA_INIT
+ m_pApp = (CRomaineApp*)AfxGetApp();
+ m_pFont = NULL;
+
+}
+
+CWelcome::~CWelcome()
+{
+ if (m_pFont != NULL) delete m_pFont;
+}
+
+void CWelcome::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CWelcome)
+ DDX_Radio(pDX, IDC_NEW_GROUP_RADIO, m_nMode);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CWelcome, CPropertyPage)
+ //{{AFX_MSG_MAP(CWelcome)
+ ON_WM_SHOWWINDOW()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CWelcome message handlers
+LRESULT CWelcome::OnWizardNext()
+{
+ UpdateData(TRUE);
+ m_pApp->m_sMode = m_nMode;
+
+ m_pApp->m_cps1.SetWizardButtons(PSWIZB_BACK | PSWIZB_NEXT);
+ if (m_nMode == 1)
+ {
+ m_pApp->m_csGroupName = L"";
+ return IDD_LR_DIALOG;
+ }
+
+ else return IDD_NAME_DLG;
+}
+
+BOOL CWelcome::OnInitDialog()
+{
+ CPropertyPage::OnInitDialog();
+
+ m_pFont = new CFont;
+ LOGFONT lf;
+
+ memset(&lf, 0, sizeof(LOGFONT)); // Clear out structure.
+ lf.lfHeight = 15;
+ _tcscpy(lf.lfFaceName, L"MS Sans Serif");
+ lf.lfWeight = 700;
+ m_pFont->CreateFontIndirect(&lf); // Create the font.
+
+ CString cs;
+ cs.LoadString(IDS_WELCOME);
+ CWnd* pWnd = GetDlgItem(IDC_WELCOME);
+ pWnd->SetWindowText(cs);
+ pWnd->SetFont(m_pFont);
+
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+void CWelcome::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CPropertyPage::OnShowWindow(bShow, nStatus);
+
+ if (bShow) m_pApp->m_cps1.SetWizardButtons(PSWIZB_NEXT);
+
+}
diff --git a/private/utils/wizards/addgrpw/welcome.h b/private/utils/wizards/addgrpw/welcome.h
new file mode 100644
index 000000000..1f2f3c885
--- /dev/null
+++ b/private/utils/wizards/addgrpw/welcome.h
@@ -0,0 +1,54 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Welcome.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+/////////////////////////////////////////////////////////////////////////////
+// CWelcome dialog
+
+class CWelcome : public CPropertyPage
+{
+ DECLARE_DYNCREATE(CWelcome)
+
+// Construction
+public:
+ CWelcome();
+ ~CWelcome();
+
+// Dialog Data
+ //{{AFX_DATA(CWelcome)
+ enum { IDD = IDD_WELCOME_DLG };
+ int m_nMode;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CWelcome)
+ public:
+ virtual LRESULT OnWizardNext();
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+ CRomaineApp* m_pApp;
+ CFont* m_pFont;
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CWelcome)
+ virtual BOOL OnInitDialog();
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+};
diff --git a/private/utils/wizards/addgrpw/what.cpp b/private/utils/wizards/addgrpw/what.cpp
new file mode 100644
index 000000000..40714e972
--- /dev/null
+++ b/private/utils/wizards/addgrpw/what.cpp
@@ -0,0 +1,124 @@
+/**********************************************************************/
+/** Microsoft Windows NT **/
+/** Copyright(c) Microsoft Corp., 1991-1996 **/
+/**********************************************************************/
+
+/*
+ What.cpp
+
+ Property Page support for Group management wizard
+
+ FILE HISTORY:
+ jony Apr-1996 created
+*/
+
+#include "stdafx.h"
+#include "Romaine.h"
+#include "What.h"
+
+#include <lmcons.h>
+#include <lmaccess.h>
+#include <lmerr.h>
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CWhat property page
+
+IMPLEMENT_DYNCREATE(CWhat, CPropertyPage)
+
+CWhat::CWhat() : CPropertyPage(CWhat::IDD)
+{
+ //{{AFX_DATA_INIT(CWhat)
+ m_csGroupName = _T("");
+ m_csDescription = _T("");
+ //}}AFX_DATA_INIT
+}
+
+CWhat::~CWhat()
+{
+}
+
+void CWhat::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CWhat)
+ DDX_Text(pDX, IDC_GROUP_NAME, m_csGroupName);
+ DDX_Text(pDX, IDC_DESCRIPTION, m_csDescription);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CWhat, CPropertyPage)
+ //{{AFX_MSG_MAP(CWhat)
+ ON_WM_SHOWWINDOW()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CWhat message handlers
+
+LRESULT CWhat::OnWizardNext()
+{
+ UpdateData(TRUE);
+ CWnd* pWnd = GetDlgItem(IDC_GROUP_NAME);
+ CRomaineApp* pApp = (CRomaineApp*)AfxGetApp();
+
+ if (m_csGroupName == "")
+ {
+ AfxMessageBox(IDS_NO_GROUP_NAME);
+ pWnd->SetFocus();
+ return -1;
+ }
+
+ if (m_csGroupName.FindOneOf(L"\"\\/[];:|=,+*?<>") != -1)
+ {
+ AfxMessageBox(IDS_GROUP_INVALID_NAME);
+ pWnd->SetFocus();
+ return -1;
+ }
+
+ if (m_csGroupName.GetLength() > 20)
+ {
+ AfxMessageBox(IDS_GROUP_INVALID_NAME);
+ pWnd->SetFocus();
+ return -1;
+ }
+
+ pApp->m_csGroupName = m_csGroupName;
+ pApp->m_csGroupDesc = m_csDescription;
+
+ return CPropertyPage::OnWizardNext();
+}
+
+void CWhat::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CPropertyPage::OnShowWindow(bShow, nStatus);
+
+ CRomaineApp* pApp = (CRomaineApp*)AfxGetApp();
+ if (bShow)
+ {
+ GetDlgItem(IDC_GROUP_NAME)->SetFocus();
+ pApp->m_cps1.SetWizardButtons(PSWIZB_NEXT | PSWIZB_BACK);
+ if (pApp->bRestart1 == TRUE)
+ {
+ m_csGroupName = _T("");
+ m_csDescription = _T("");
+ UpdateData(FALSE);
+ pApp->bRestart1 == FALSE;
+ }
+ }
+
+}
+
+LRESULT CWhat::OnWizardBack()
+{
+ CRomaineApp* pApp = (CRomaineApp*)AfxGetApp();
+ pApp->m_cps1.SetWizardButtons(PSWIZB_NEXT);
+
+ return CPropertyPage::OnWizardBack();
+}
diff --git a/private/utils/wizards/addgrpw/what.h b/private/utils/wizards/addgrpw/what.h
new file mode 100644
index 000000000..cea603999
--- /dev/null
+++ b/private/utils/wizards/addgrpw/what.h
@@ -0,0 +1,53 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ What.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+/////////////////////////////////////////////////////////////////////////////
+// CWhat dialog
+
+class CWhat : public CPropertyPage
+{
+ DECLARE_DYNCREATE(CWhat)
+
+// Construction
+public:
+ CWhat();
+ ~CWhat();
+
+// Dialog Data
+ //{{AFX_DATA(CWhat)
+ enum { IDD = IDD_NAME_DLG };
+ CString m_csGroupName;
+ CString m_csDescription;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CWhat)
+ public:
+ virtual LRESULT OnWizardNext();
+ virtual LRESULT OnWizardBack();
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CWhat)
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+};
diff --git a/private/utils/wizards/addgrpw/where.cpp b/private/utils/wizards/addgrpw/where.cpp
new file mode 100644
index 000000000..d9bd7c984
--- /dev/null
+++ b/private/utils/wizards/addgrpw/where.cpp
@@ -0,0 +1,298 @@
+/**********************************************************************/
+/** Microsoft Windows NT **/
+/** Copyright(c) Microsoft Corp., 1991-1996 **/
+/**********************************************************************/
+
+/*
+ where.cpp
+
+ Property Page support for Group management wizard
+
+ FILE HISTORY:
+ jony Apr-1996 created
+*/
+
+#include "stdafx.h"
+#include "Romaine.h"
+#include "NetTree.h"
+#include "Where.h"
+
+#include <winreg.h>
+#include <lmcons.h>
+#include <lmaccess.h>
+#include <lmerr.h>
+#include <lmapibuf.h>
+#include <winnetwk.h>
+#include <lmserver.h>
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+unsigned int WhichNTProduct(CString& lpMachineName);
+int ClassifyMachine(CString& csMachineName);
+
+/////////////////////////////////////////////////////////////////////////////
+// CWhere property page
+
+IMPLEMENT_DYNCREATE(CWhere, CPropertyPage)
+
+CWhere::CWhere() : CPropertyPage(CWhere::IDD)
+{
+ //{{AFX_DATA_INIT(CWhere)
+ m_csMachineName = _T("");
+ //}}AFX_DATA_INIT
+ m_bExpandedOnce = 0;
+}
+
+CWhere::~CWhere()
+{
+}
+
+void CWhere::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CWhere)
+ DDX_Control(pDX, IDC_SERVER_TREE, m_ctServerTree);
+ DDX_Text(pDX, IDC_MACHINE_NAME, m_csMachineName);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CWhere, CPropertyPage)
+ //{{AFX_MSG_MAP(CWhere)
+ ON_WM_SHOWWINDOW()
+ ON_NOTIFY(TVN_SELCHANGED, IDC_SERVER_TREE, OnSelchangedServerTree)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CWhere message handlers
+
+LRESULT CWhere::OnWizardNext()
+{
+ UpdateData(TRUE);
+
+ if (m_csMachineName == "")
+ {
+ AfxMessageBox(IDS_NO_MACHINE_NAME);
+ CWnd* pWnd = GetDlgItem(IDC_MACHINE_NAME);
+ pWnd->SetFocus();
+ return -1;
+ }
+
+ int nVal = ClassifyMachine(m_csMachineName);
+
+ CRomaineApp* pApp = (CRomaineApp*)AfxGetApp();
+ pApp->m_csServer = m_csMachineName;
+// go ahead and check the name for uniqueness
+ TCHAR* pServer = m_csMachineName.GetBuffer(m_csMachineName.GetLength());
+ m_csMachineName.ReleaseBuffer();
+
+ TCHAR* pGroupName = pApp->m_csGroupName.GetBuffer(pApp->m_csGroupName.GetLength());
+ pApp->m_csGroupName.ReleaseBuffer();
+
+ GROUP_INFO_0* pInfo;
+ NET_API_STATUS nAPI = NetGroupGetInfo(pServer,
+ pGroupName,
+ 0,
+ (LPBYTE*)&pInfo);
+
+ if (nAPI == ERROR_SUCCESS)
+ {
+ AfxMessageBox(IDS_GROUP_EXISTS);
+ return IDD_NAME_DLG;
+ }
+
+ LOCALGROUP_INFO_0* pLInfo;
+ nAPI = NetLocalGroupGetInfo(pServer,
+ pGroupName,
+ 0,
+ (LPBYTE*)&pLInfo);
+
+ if (nAPI == ERROR_SUCCESS)
+ {
+ AfxMessageBox(IDS_GROUP_EXISTS);
+ return IDD_NAME_DLG;
+ }
+
+ return nVal;
+
+}
+
+int ClassifyMachine(CString& csMachineName)
+{
+ UINT ui;
+ HKEY hKey;
+ DWORD dwRet;
+ DWORD cbProv = 0;
+
+ CRomaineApp* pApp = (CRomaineApp*)AfxGetApp();
+ csMachineName.MakeUpper();
+// if a machine name is entered we need to know the domain
+// if a domain name is entered we need to know the DC name
+ if (csMachineName.Left(2) == "\\\\")
+ {
+ pApp->m_bDomain = FALSE;
+ ui = WhichNTProduct(csMachineName);
+// depending on the server type, provide an option for group type
+ if ((ui == 2) || (ui == 1)) // standalone server or wks
+ {
+ pApp->m_bServer = FALSE;
+ pApp->m_csServer = csMachineName;
+ pApp->m_nGroupType = 1;
+ if (pApp->m_sMode == 0) return IDD_LOCAL_USERS;
+ else return IDD_GROUP_LIST_DIALOG;
+ }
+ else if (ui == 3) //pdc \ bdc
+ {
+ AfxMessageBox(IDS_DOMAIN_SET);
+
+// find out what domain this is a server for
+ TCHAR* lpProv = NULL;
+
+ CRomaineApp* pApp = (CRomaineApp*)AfxGetApp();
+ long lRet = RegConnectRegistry(
+ (LPTSTR)csMachineName.GetBuffer(csMachineName.GetLength()),
+ HKEY_LOCAL_MACHINE,
+ &hKey);
+
+ dwRet = RegOpenKey(hKey,
+ TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"), &hKey );
+
+ TCHAR* lpPrimaryDomain = NULL;
+ if ((dwRet = RegQueryValueEx( hKey, TEXT("CachePrimaryDomain"), NULL, NULL, NULL, &cbProv )) == ERROR_SUCCESS)
+ {
+ lpPrimaryDomain = (TCHAR*)malloc(cbProv);
+ if (lpPrimaryDomain == NULL)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
+ ExitProcess(1);
+ }
+
+ dwRet = RegQueryValueEx( hKey, TEXT("CachePrimaryDomain"), NULL, NULL, (LPBYTE) lpPrimaryDomain, &cbProv );
+
+ }
+
+ RegCloseKey(hKey);
+
+ TCHAR* lpszPrimaryDC;
+ DWORD err = NetGetDCName(NULL,
+ lpPrimaryDomain, // Domain Name
+ (LPBYTE *)&lpszPrimaryDC ); // returned PDC *
+
+ pApp->m_csDomain = lpPrimaryDomain;
+ pApp->m_csServer = lpszPrimaryDC;
+ pApp->m_bDomain = TRUE;
+ pApp->m_bServer = FALSE;
+ free(lpPrimaryDomain);
+ if (pApp->m_sMode == 0) return IDD_GROUP_TYPE_DLG;
+ else return IDD_GROUP_LIST_DIALOG;
+ }
+ else
+ {
+ AfxMessageBox(IDS_GENERIC_BAD_MACHINE);
+ return -1;
+ }
+ }
+
+ else
+ {
+ pApp->m_bDomain = TRUE;
+ pApp->m_bServer = FALSE;
+ TCHAR* lpszPrimaryDC;
+ TCHAR* lpwDomain = csMachineName.GetBuffer(csMachineName.GetLength());
+ DWORD err = NetGetDCName(NULL,
+ lpwDomain, // Domain Name
+ (LPBYTE *)&lpszPrimaryDC ); // returned PDC *
+
+ csMachineName.ReleaseBuffer();
+
+ if (err == 2453)
+ {
+ AfxMessageBox(IDS_NO_DC);
+ return -1;
+ }
+
+ pApp->m_csDomain = csMachineName;
+ pApp->m_csServer = lpszPrimaryDC;
+ if (pApp->m_sMode == 0) return IDD_GROUP_TYPE_DLG;
+ else return IDD_GROUP_LIST_DIALOG;
+ }
+ return -1;
+}
+
+// given a machine name, return whether its a server or wks
+unsigned int WhichNTProduct(CString& csMachineName)
+{
+ UINT uiRetVal = 0;
+ PSERVER_INFO_101 si101;
+ NET_API_STATUS nas;
+
+ nas = NetServerGetInfo(
+ (LPTSTR)csMachineName.GetBuffer(csMachineName.GetLength()),
+ 101, // info-level
+ (LPBYTE *)&si101
+ );
+
+ if(nas != NERR_Success)
+ {
+ NetApiBufferFree(si101);
+ SetLastError(nas);
+ return 0;
+ }
+
+ if( (si101->sv101_type & SV_TYPE_DOMAIN_CTRL) ||
+ (si101->sv101_type & SV_TYPE_DOMAIN_BAKCTRL) )
+ uiRetVal = 3;
+ else if (si101->sv101_type & SV_TYPE_WORKSTATION) uiRetVal = 2; //wks
+ else if (si101->sv101_type & SV_TYPE_SERVER) uiRetVal = 1; // server
+
+ NetApiBufferFree(si101);
+
+ // else return Unknown
+ return uiRetVal;
+}
+
+void CWhere::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CPropertyPage::OnShowWindow(bShow, nStatus);
+
+// Do the default domain expansion only once.
+ if ((bShow) && (!m_bExpandedOnce))
+ {
+ m_bExpandedOnce = TRUE;
+ m_ctServerTree.PopulateTree();
+ }
+
+}
+
+void CWhere::OnSelchangedServerTree(NMHDR* pNMHDR, LRESULT* pResult)
+{
+ NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
+
+ HTREEITEM hItem = m_ctServerTree.GetSelectedItem();
+
+ int nImage;
+ m_ctServerTree.GetItemImage(hItem, nImage, nImage);
+ if (nImage > 0)
+ {
+ CString csName;
+ csName = m_ctServerTree.GetItemText(hItem);
+
+ m_csMachineName = csName;
+ }
+ UpdateData(FALSE);
+
+
+ *pResult = 0;
+}
+
+LRESULT CWhere::OnWizardBack()
+{
+ CRomaineApp* pApp = (CRomaineApp*)AfxGetApp();
+ if (pApp->m_sMode == 1) return IDD_WELCOME_DLG;
+ else return CPropertyPage::OnWizardBack();
+}
diff --git a/private/utils/wizards/addgrpw/where.h b/private/utils/wizards/addgrpw/where.h
new file mode 100644
index 000000000..a5b138efc
--- /dev/null
+++ b/private/utils/wizards/addgrpw/where.h
@@ -0,0 +1,56 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Where.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CWhere dialog
+
+class CWhere : public CPropertyPage
+{
+ DECLARE_DYNCREATE(CWhere)
+
+// Construction
+public:
+ CWhere();
+ ~CWhere();
+
+// Dialog Data
+ //{{AFX_DATA(CWhere)
+ enum { IDD = IDD_MACHINE_DLG };
+ CNetTreeCtrl m_ctServerTree;
+ CString m_csMachineName;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CWhere)
+ public:
+ virtual LRESULT OnWizardNext();
+ virtual LRESULT OnWizardBack();
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+private:
+ BOOL m_bExpandedOnce;
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CWhere)
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ afx_msg void OnSelchangedServerTree(NMHDR* pNMHDR, LRESULT* pResult);
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+};
diff --git a/private/utils/wizards/addusrw/accexp.cpp b/private/utils/wizards/addusrw/accexp.cpp
new file mode 100644
index 000000000..0916848bc
--- /dev/null
+++ b/private/utils/wizards/addusrw/accexp.cpp
@@ -0,0 +1,330 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ AccExp.cpp : implementation file
+
+ CPropertyPage support for User mgmt wizard
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+#include "stdafx.h"
+#include "speckle.h"
+#include "wizbased.h"
+#include "AccExp.h"
+
+#include <winreg.h>
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CAccExp property page
+
+IMPLEMENT_DYNCREATE(CAccExp, CWizBaseDlg)
+
+CAccExp::CAccExp() : CWizBaseDlg(CAccExp::IDD)
+{
+ //{{AFX_DATA_INIT(CAccExp)
+ m_sDayEdit = 0;
+ m_sYearEdit = 0;
+ m_sMonthEdit = 0;
+ //}}AFX_DATA_INIT
+ CTime t = CTime::GetCurrentTime();
+
+ m_sDayEdit = t.GetDay();
+ m_sMonthEdit = t.GetMonth();
+ m_sYearEdit = t.GetYear() + 1;
+}
+
+CAccExp::~CAccExp()
+{
+}
+
+void CAccExp::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CAccExp)
+ DDX_Control(pDX, IDC_STATIC2, m_cStatic2);
+ DDX_Control(pDX, IDC_STATIC1, m_cStatic1);
+ DDX_Control(pDX, IDC_DATE_SPIN, m_sbSpin);
+ DDX_Text(pDX, IDC_MONTH_EDIT, m_csMonthEdit);
+ DDX_Text(pDX, IDC_DAY_EDIT, m_csDayEdit);
+ DDX_Text(pDX, IDC_YEAR_EDIT, m_csYearEdit);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CAccExp, CWizBaseDlg)
+ //{{AFX_MSG_MAP(CAccExp)
+ ON_EN_SETFOCUS(IDC_DAY_EDIT, OnSetfocusDayEdit)
+ ON_EN_SETFOCUS(IDC_MONTH_EDIT, OnSetfocusMonthEdit)
+ ON_EN_SETFOCUS(IDC_YEAR_EDIT, OnSetfocusYearEdit)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CAccExp message handlers
+
+BOOL CAccExp::OnInitDialog()
+{
+ CWizBaseDlg::OnInitDialog();
+
+ GetDlgItem(IDC_DAY_EDIT)->EnableWindow(TRUE);
+ GetDlgItem(IDC_MONTH_EDIT)->EnableWindow(TRUE);
+ GetDlgItem(IDC_YEAR_EDIT)->EnableWindow(TRUE);
+ GetDlgItem(IDC_DATE_SPIN)->EnableWindow(TRUE);
+
+// get date format from registry
+ DWORD dwRet;
+ HKEY hKey;
+ DWORD cbProv = 0;
+ TCHAR* lpProv = NULL;
+
+ dwRet = RegOpenKey(HKEY_CURRENT_USER,
+ TEXT("Control Panel\\International"), &hKey );
+
+ TCHAR* lpSep;
+
+// date separator
+ if ((dwRet = RegQueryValueEx( hKey, TEXT("sDate"), NULL, NULL, NULL, &cbProv )) == ERROR_SUCCESS)
+ {
+ lpSep = (TCHAR*)malloc(cbProv);
+ if (lpSep == NULL)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
+ ExitProcess(1);
+ }
+ dwRet = RegQueryValueEx( hKey, TEXT("sDate"), NULL, NULL, (LPBYTE) lpSep, &cbProv );
+ }
+
+ m_cStatic2.m_csDateSep = lpSep;
+
+// only use one char
+ m_cStatic2.m_csDateSep = m_cStatic2.m_csDateSep.Left(1);
+ m_cStatic1.m_csDateSep = m_cStatic2.m_csDateSep;
+
+// date order
+ TCHAR* lpTemp;
+ if ((dwRet = RegQueryValueEx( hKey, TEXT("sShortDate"), NULL, NULL, NULL, &cbProv )) == ERROR_SUCCESS)
+ {
+ lpTemp = (TCHAR*)malloc(cbProv);
+ if (lpTemp == NULL)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
+ ExitProcess(1);
+ }
+ dwRet = RegQueryValueEx( hKey, TEXT("sShortDate"), NULL, NULL, (LPBYTE) lpTemp, &cbProv );
+ }
+
+// determine the order
+ TCHAR* pTemp = _tcstok(lpTemp, lpSep);
+ USHORT xPos = 170; // left most control
+ USHORT yPos = 41;
+ USHORT sCount = 0;
+ while(pTemp != NULL)
+ {
+ CRect cr;
+ if ((*pTemp == 'm') || (*pTemp == 'M'))
+ {
+ GetDlgItem(IDC_MONTH_EDIT)->SetWindowPos(0, xPos, yPos, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
+ GetDlgItem(IDC_MONTH_EDIT)->GetWindowRect(&cr);
+ xPos += cr.Width();
+ }
+
+ else if ((*pTemp == 'd') || (*pTemp == 'D'))
+ {
+ GetDlgItem(IDC_DAY_EDIT)->SetWindowPos(0, xPos, yPos, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
+ GetDlgItem(IDC_DAY_EDIT)->GetWindowRect(&cr);
+ xPos += cr.Width();
+ }
+
+ else if ((*pTemp == 'y') || (*pTemp == 'Y'))
+ {
+ GetDlgItem(IDC_YEAR_EDIT)->SetWindowPos(0, xPos, yPos, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
+ GetDlgItem(IDC_YEAR_EDIT)->GetWindowRect(&cr);
+ xPos += cr.Width();
+ }
+
+ if (sCount == 0)
+ {
+ GetDlgItem(IDC_STATIC1)->SetWindowPos(0, xPos, yPos, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
+ GetDlgItem(IDC_STATIC1)->GetWindowRect(&cr);
+ xPos += cr.Width();
+ }
+
+ if (sCount == 1)
+ {
+ GetDlgItem(IDC_STATIC2)->SetWindowPos(0, xPos, yPos, 0, 0, SWP_NOSIZE | SWP_NOZORDER);
+ GetDlgItem(IDC_STATIC2)->GetWindowRect(&cr);
+ xPos += cr.Width();
+ }
+
+ pTemp = _tcstok(NULL, lpSep);
+ sCount++;
+ }
+
+ free(lpTemp);
+ free(lpSep);
+ RegCloseKey(hKey);
+
+// put the initial numeric values into the edit controls
+ TCHAR pTemp2[4];
+ wsprintf(pTemp2, L"%d", m_sDayEdit);
+ m_csDayEdit = pTemp2;
+ wsprintf(pTemp2, L"%d", m_sMonthEdit);
+ m_csMonthEdit = pTemp2;
+ wsprintf(pTemp2, L"%d", m_sYearEdit);
+ m_csYearEdit = pTemp2;
+
+ UpdateData(FALSE);
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+void CAccExp::OnSetfocusDayEdit()
+{
+ m_sbSpin.SetBuddy(GetDlgItem(IDC_DAY_EDIT));
+ m_sbSpin.SetRange(1,31);
+}
+
+void CAccExp::OnSetfocusMonthEdit()
+{
+ m_sbSpin.SetBuddy(GetDlgItem(IDC_MONTH_EDIT));
+ m_sbSpin.SetRange(1,12);
+}
+
+void CAccExp::OnSetfocusYearEdit()
+{
+ m_sbSpin.SetBuddy(GetDlgItem(IDC_YEAR_EDIT));
+ m_sbSpin.SetRange(1996, 2030);
+}
+
+
+LRESULT CAccExp::OnWizardNext()
+{
+ UpdateData(TRUE);
+
+// get the numberic values back out of the edit control(s)
+ m_sDayEdit = _wtoi((LPCTSTR)m_csDayEdit);
+ m_sMonthEdit = _wtoi((LPCTSTR)m_csMonthEdit);
+ m_sYearEdit = _wtoi((LPCTSTR)m_csYearEdit);
+
+// check for valid values
+ USHORT sDays[] = {31,28,31,30,31,30,31,31,30,31,30,31};
+
+// leap year?
+ if (((m_sYearEdit - 1992) % 4) == 0) sDays[1] = 29;
+
+ if ((m_sDayEdit > sDays[m_sMonthEdit - 1]) || (m_sDayEdit < 1))
+ {
+ AfxMessageBox(IDS_INVALID_DAY);
+ GetDlgItem(IDC_DAY_EDIT)->SetFocus();
+ return -1;
+ }
+
+ if ((m_sMonthEdit > 12) || (m_sMonthEdit < 1))
+ {
+ AfxMessageBox(IDS_INVALID_MONTH);
+ GetDlgItem(IDC_MONTH_EDIT)->SetFocus();
+ return -1;
+ }
+
+ if ((m_sYearEdit > 2030) || (m_sYearEdit < 1970))
+ {
+ AfxMessageBox(IDS_INVALID_YEAR);
+ GetDlgItem(IDC_YEAR_EDIT)->SetFocus();
+ return -1;
+ }
+
+ CTime t = CTime::GetCurrentTime();
+ CTime tSet = CTime(m_sYearEdit, m_sMonthEdit, m_sDayEdit + 1, 23, 59, 59);
+
+ if (tSet < t)
+ {
+ if (AfxMessageBox(IDS_ALREADY_EXPIRED, MB_YESNO) != IDYES) return -1;
+ }
+
+// convert both values to GMT
+ struct tm* GMTTime;
+ GMTTime = tSet.GetGmtTm(NULL);
+ CTime tGMTSet = CTime((GMTTime->tm_year + 1900),
+ GMTTime->tm_mon + 1,
+ GMTTime->tm_mday,
+ 0, 0, 30, GMTTime->tm_isdst);
+
+ CTime tStart = CTime(1970, 1, 1, 0, 0, 0);
+ GMTTime = tStart.GetGmtTm(NULL);
+ CTime tGMTStart = CTime((GMTTime->tm_year + 1900),
+ GMTTime->tm_mon + 1,
+ GMTTime->tm_mday,
+ 0, 0, 0, GMTTime->tm_isdst);
+
+ CTimeSpan ct = tGMTSet - tGMTStart;
+
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+ pApp->m_dwExpirationDate = ct.GetTotalSeconds();
+
+ if (pApp->m_bHours) return IDD_HOURS_DLG;
+ else if (pApp->m_bWorkstation) return IDD_LOGONTO_DLG;
+ else if (pApp->m_bNW) return IDD_NWLOGON_DIALOG;
+ else return IDD_FINISH;
+ return CWizBaseDlg::OnWizardNext();
+}
+
+LRESULT CAccExp::OnWizardBack()
+{
+ return IDD_RESTRICTIONS_DIALOG;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CStaticDelim
+
+CStaticDelim::CStaticDelim()
+{
+ m_pFont = new CFont;
+ LOGFONT lf;
+
+ memset(&lf, 0, sizeof(LOGFONT)); // Clear out structure.
+ lf.lfHeight = 15;
+ _tcscpy(lf.lfFaceName, TEXT("Arial"));
+ lf.lfWeight = 100;
+ m_pFont->CreateFontIndirect(&lf); // Create the font.
+
+}
+
+CStaticDelim::~CStaticDelim()
+{
+ delete m_pFont;
+}
+
+
+BEGIN_MESSAGE_MAP(CStaticDelim, CStatic)
+ //{{AFX_MSG_MAP(CStaticDelim)
+ ON_WM_PAINT()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CStaticDelim message handlers
+
+void CStaticDelim::OnPaint()
+{
+ CPaintDC dc(this); // device context for painting
+
+ dc.SetBkColor(RGB(255, 255, 255));
+
+ dc.SelectObject(m_pFont);
+ dc.TextOut(0, 0, m_csDateSep);
+ // Do not call CStatic::OnPaint() for painting messages
+}
diff --git a/private/utils/wizards/addusrw/accexp.h b/private/utils/wizards/addusrw/accexp.h
new file mode 100644
index 000000000..05901adc6
--- /dev/null
+++ b/private/utils/wizards/addusrw/accexp.h
@@ -0,0 +1,102 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ AccExp.h : header file
+
+ CPropertyPage support for User mgmt wizard
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+/////////////////////////////////////////////////////////////////////////////
+// CStaticDelim window
+
+class CStaticDelim : public CStatic
+{
+// Construction
+public:
+ CStaticDelim();
+ CString m_csDateSep;
+
+// Attributes
+public:
+
+// Operations
+public:
+ CFont* m_pFont;
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CStaticDelim)
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CStaticDelim();
+
+ // Generated message map functions
+protected:
+ //{{AFX_MSG(CStaticDelim)
+ afx_msg void OnPaint();
+ //}}AFX_MSG
+
+ DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////////////////////////////
+// CAccExp dialog
+
+class CAccExp : public CWizBaseDlg
+{
+ DECLARE_DYNCREATE(CAccExp)
+
+// Construction
+public:
+ CAccExp();
+ ~CAccExp();
+
+// Dialog Data
+ //{{AFX_DATA(CAccExp)
+ enum { IDD = IDD_ACCOUNT_EXP_DIALOG };
+ CStaticDelim m_cStatic2;
+ CStaticDelim m_cStatic1;
+ CSpinButtonCtrl m_sbSpin;
+ CString m_csDayEdit;
+ CString m_csYearEdit;
+ CString m_csMonthEdit;
+ //}}AFX_DATA
+
+ short m_sDayEdit;
+ short m_sYearEdit;
+ short m_sMonthEdit;
+
+ // Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CAccExp)
+ public:
+ virtual LRESULT OnWizardNext();
+ virtual LRESULT OnWizardBack();
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CAccExp)
+ virtual BOOL OnInitDialog();
+ afx_msg void OnSetfocusDayEdit();
+ afx_msg void OnSetfocusMonthEdit();
+ afx_msg void OnSetfocusYearEdit();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+};
diff --git a/private/utils/wizards/addusrw/dapi.h b/private/utils/wizards/addusrw/dapi.h
new file mode 100644
index 000000000..10d3c0b01
--- /dev/null
+++ b/private/utils/wizards/addusrw/dapi.h
@@ -0,0 +1,1322 @@
+
+/*******************************************************************
+ *
+ * Copyright (c) Microsoft Corp. 1986-1996. All Rights Reserved.
+ *
+ *
+ * DESCRIPTION: This header file defines the functions, structures,
+ * and macros used to access the Microsoft Exchange
+ * APIs for modifying entries in the Exchange 4.0 DIT.
+ * These APIs permit a calling process to create,
+ * modify, or delete DIT objects by specifying the
+ * name of a CSV text file containing attributes
+ * for objects to import into ( or to modify)
+ * the DIT. See the Directory Access Functions
+ * section of the Exchange Developer's Kit for
+ * more detailed description of this interface.
+ *
+ * Calling programs must link with DAPI.LIB.
+ *
+ * Error and warning codes are defined in DAPIMSG.H
+ *
+ *
+ *******************************************************************/
+
+/** include files **/
+#ifndef _WINDOWS_
+#include <windows.h>
+#endif
+
+/** local definitions **/
+
+#ifndef _DAPI_INCLUDED_
+#define _DAPI_INCLUDED_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+// Import / Export APIs check for the presence of this signature in
+// the dwDAPISignature field in the import parameter blocks.
+// This signature will be incremented each time one of the parameter
+// blocks is changed so that header synchronization problems can be
+// detected.
+#define DAPI_SIGNATURE 0x46414400
+
+
+// Combinable flags used to control the API functions.
+
+ // The following flags control filtering of DAPI events
+ // The default action is DAPI_EVENT_ALL
+#define DAPI_EVENT_MASK 0x00000007 /* bit-field containing event-filtering requested
+ if none of these bits are set, DAPI_EVENT_ALL is assumed */
+#define DAPI_EVENT_MIN 0x00000001 /* No warning or error logging.
+ Log start and stop messages */
+#define DAPI_EVENT_SOME 0x00000002 /* Start, Stop, and Error messages will be logged. */
+#define DAPI_EVENT_ALL 0x00000004 /* Start, Stop, Error, and Warning messages
+ will be logged. */
+
+ // The following flags control schema read and use of the schema
+#define DAPI_FORCE_SCHEMA_LOAD 0x00000010 /* Unload previously loaded schema
+ and read schema again.
+ Default action is to re-use
+ previously loaded schema if read
+ from the same messaging domain */
+#define DAPI_RAW_MODE 0x00000020 /* Import / Export in "Raw" mode. Import
+ lines are taken literally. No
+ attributes will be inherited,
+ constructed, etc. Aliases for
+ attribute and class names will
+ not be recognized. */
+
+#define DAPI_OVERRIDE_CONTAINER 0x00000040 /* Container specified in the parameter block
+ overrides the contents of the container column.
+ Default behaviour is for the value specified
+ in the Obj-Container column to override
+ that specified in the parameter block */
+
+#define DAPI_IMPORT_NO_ERR_FILE 0x00000080 /* Do not create Error File -- BatchImport only */
+#define DAPI_IMPORT_WRITE_THROUGH 0x00400000 /* Commit write operations immediately */
+
+// Flags defined for "Batch" operations only -- ignored by DAPIRead, DAPIWrite
+#define DAPI_YES_TO_ALL 0x00000100 /* Force "yes" response on any
+ user-prompt UI
+ (i.e., continue w/o proxy addresses, etc.) */
+
+#define DAPI_SUPPRESS_PROGRESS 0x00000200 /* Suppress progress thermometer on batch operations.
+ Default is to display progress */
+#define DAPI_SUPPRESS_COMPLETION 0x00000400 /* Suppress completion notification message box on batch operations */
+
+#define DAPI_SUPPRESS_ARCHIVES 0x00000800 /* Suppress creation of "archive" copies
+ of output files -- BatchImport and BatchExport only*/
+
+
+
+// Flags defined for BatchExport
+#define DAPI_EXPORT_MAILBOX 0x00001000 /* Export Mailbox recipients */
+#define DAPI_EXPORT_CUSTOM 0x00002000 /* Export remote address recipients */
+#define DAPI_EXPORT_DIST_LIST 0x00004000 /* Export Distribution Lists */
+#define DAPI_EXPORT_RECIPIENTS (DAPI_EXPORT_MAILBOX | DAPI_EXPORT_CUSTOM | DAPI_EXPORT_DIST_LIST)
+ /* Export all recipient objects */
+
+#define DAPI_EXPORT_ALL_CLASSES 0x00008000 /* If this flag is set, all objects meeting other restrictions
+ (i.e., USN level, container scope, etc.) will be exported,
+ regardless of class */
+
+#define DAPI_EXPORT_HIDDEN 0x00010000 /* Include Hidden objects in export.
+ Default is no export if Hide-From-Address-Book */
+#define DAPI_EXPORT_SUBTREE 0x00020000 /* Traverse the Directory Information Tree hierarchy,
+ exporting objects that meet the export restrictions */
+#define DAPI_EXPORT_BASEPOINT_ONLY 0x00040000 /* Export only the requested attributes from
+ the named BasePoint object. All other
+ export restrictions are ignored (class flags,
+ rgpszClasses, pszServerName).
+ This flag implies DAPI_SUPPRESS_PROGRESS
+ and DAPI_SUPPRESS_COMPLETION */
+
+// Flags defined only for BatchImport
+#define DAPI_OVERRIDE_SYNCH_STATE 0x00080000 /* Override server's synchronization status,
+ normally checked on BatchImport.
+ NOTE: This flag should normally NOT be set.
+ The normal behaviour is to prevent BatchImport
+ operations from possible conflict with directory
+ synchronization */
+
+
+// Flags defined only for DAPIRead
+#define DAPI_READ_DEFINED_ATTRIBUTES 0x00100000 /* return all attributes that are set
+ for the current object.
+ This flag is ignored if pAttributes is specified. */
+
+#define DAPI_READ_ALL_ATTRIBUTES 0x00200000 /* return all attributes that are defined
+ for the class of the current object.
+ This flag is ignored if pAttributes is specified. */
+
+
+ // The following flags control NT Security management
+#define DAPI_RESTRICT_ACCESS 0x01000000 /* Apply NT Security Descriptor to
+ created objects */
+#define DAPI_CREATE_NT_ACCOUNT 0x02000000 /* Create NT accounts
+ (valid only in Create/Modify mode) */
+#define DAPI_CREATE_RANDOM_PASSWORD 0x04000000 /* Generate random passwords for
+ created NT accounts. Ignored if DAPI_CREATE_NT_ACCOUNT
+ is not set */
+
+#define DAPI_DELETE_NT_ACCOUNT 0x08000000 /* Delete ASSOC-NT-ACCOUNT when
+ deleting mailbox */
+// Flags defined only for DAPIWrite
+#define DAPI_MODIFY_REPLACE_PROPERTIES 0x00800000 /* Append values to multi-value attributes when modifying */
+
+#define DAPI_WRITE_UPDATE 0x10000000 /* Modify if object exists, create if it doesn't.
+ NOTE: This is the default mode */
+#define DAPI_WRITE_CREATE 0x20000000 /* Create object -- fail if object exists */
+#define DAPI_WRITE_MODIFY 0x30000000 /* Modify object -- fail if object does not exist */
+#define DAPI_WRITE_DELETE 0x40000000 /* Delete object */
+#define DAPI_WRITE_MODE_MASK 0x70000000
+
+
+
+// Callback flags
+#define DAPI_CALLBACK_CHAIN 0x00000001 /* If set in dwFlags field of the ERROR_CALLBACK
+ and the CALLBACKPROGRESS structures, the default
+ handler will be invoked after calling out to the
+ caller-supplied handler function, unless the user
+ function returns FALSE, indicating cancel.
+ NOTE: This flag is not defined for the EXPORT_CALLBACK
+ structure.
+ NOTE: This flag should not be set in the dwFlags
+ field of the main parameter block */
+
+
+// default delimiter values used when parsing the import file
+
+#define DAPI_DEFAULT_DELIMA ','
+#define DAPI_DEFAULT_QUOTEA '"'
+#define DAPI_DEFAULT_MV_SEPA '%'
+#define DAPI_DEFAULT_DELIMW L','
+#define DAPI_DEFAULT_QUOTEW L'"'
+#define DAPI_DEFAULT_MV_SEPW L'%'
+
+
+#define DAPI_CTRL_FILE_PTRA '='
+#define DAPI_CTRL_FILE_PTRW L'='
+#define DAPI_CTRL_META_CHARA '~'
+#define DAPI_CTRL_META_CHARW L'~'
+#define pszSubstServerA "~SERVER"
+#define pszSubstServerW L"~SERVER"
+#define cchSubstServer ((sizeof (pszSubstServerA) / sizeof(CHAR)) - 1)
+#define pszDeleteKeyA "~DEL"
+#define pszDeleteKeyW L"~DEL"
+#define cchDeleteKey ((sizeof (pszDeleteKeyA) / sizeof(CHAR)) - 1)
+
+#define DAPI_UNICODE_FILE ((UINT)-1)
+
+#ifdef UNICODE
+
+#define DAPI_DEFAULT_DELIM DAPI_DEFAULT_DELIMW
+#define DAPI_DEFAULT_QUOTE DAPI_DEFAULT_QUOTEW
+#define DAPI_DEFAULT_MV_SEP DAPI_DEFAULT_MV_SEPW
+#define DAPI_CTRL_FILE_PTR DAPI_CTRL_FILE_PTRW
+#define DAPI_CTRL_META_CHAR DAPI_CTRL_META_CHARW
+#define pszSubstServer pszSubstServerW
+#define pszDeleteKey pszDeleteKeyW
+
+#else
+
+#define DAPI_DEFAULT_DELIM DAPI_DEFAULT_DELIMA
+#define DAPI_DEFAULT_QUOTE DAPI_DEFAULT_QUOTEA
+#define DAPI_DEFAULT_MV_SEP DAPI_DEFAULT_MV_SEPA
+#define DAPI_CTRL_FILE_PTR DAPI_CTRL_FILE_PTRA
+#define DAPI_CTRL_META_CHAR DAPI_CTRL_META_CHARA
+#define pszSubstServer pszSubstServerA
+#define pszDeleteKey pszDeleteKeyA
+
+#endif
+
+
+/*******************************************************************************
+* Batch Operation Progress Callback Function Definitions
+* Pointers to functions of these types are provided by the caller via the
+* CALLBACKPROGRESS structure in the Batch function parameter block
+*
+********************************************************************************
+*
+* procedure : PDAPI_FInitProgress
+*
+* purpose : Initialize progress handler (possibly progress display dialog)
+*
+* parameters : lpvAppDefined value provided in the progress callback structure
+* nMac Maximum Anticipated Calls. If non-zero, this indicates
+* the number of progress events anticipated.
+* If zero, the number of items to process is unknown,
+* so the number of calls to UpdateProgress is indeterminate.
+*
+* returns : TRUE Indicates that all is well
+* FALSE Could not initialize progress handler, cancel session.
+*
+********************************************************************************
+*
+* procedure : PDAPI_FResetProgress
+*
+* purpose : Re-initialize progress handler (possibly reset progress bar)
+*
+* parameters : lpvAppDefined value provided in the progress callback structure
+* nMac Maximum Anticipated Calls. If non-zero, this indicates
+* the number of progress events anticipated.
+* If zero, the number of items to process is unknown,
+* so the number of calls to UpdateProgress is indeterminate.
+*
+* returns : TRUE Indicates that all is well
+* FALSE Could not re-initialize progress handler, cancel session.
+*
+********************************************************************************
+*
+* procedure : PDAPI_FEndProgress
+*
+* purpose : Terminate progress handler (possibly progress display dialog)
+*
+* parameters : lpvAppDefined value provided in the progress callback structure
+*
+* returns : TRUE Indicates that all is well
+* FALSE Could not terminate progress handler, cancel session.
+*
+********************************************************************************
+*
+* procedure : PDAPI_FUpdateProgress
+*
+* purpose : Completed processing item. Called to indicate time to increment
+* progress display.
+*
+* parameters : lpvAppDefined value provided in the progress callback structure
+*
+* returns : TRUE Indicates that all is well
+* FALSE Cancel session (i.e., cancel button pressed).
+*
+********************************************************************************
+*
+* procedure : PDAPI_FUpdateProgressText
+*
+* purpose : Replace progress text area with provided text string
+*
+* parameters : lpvAppDefined value provided in the progress callback structure
+*
+* returns : TRUE Indicates that all is well
+* FALSE Cancel session (i.e., cancel button pressed).
+*
+********************************************************************************/
+typedef BOOL (PASCAL * PDAPI_FInitProgress)
+ (LPVOID lpvAppDefined, INT nMac);
+typedef BOOL (PASCAL * PDAPI_FUpdateProgress)
+ (LPVOID lpvAppDefined);
+typedef BOOL (PASCAL * PDAPI_FEndProgress)
+ (LPVOID lpvAppDefined);
+typedef BOOL (PASCAL * PDAPI_FResetProgress)
+ (LPVOID lpvAppDefined, INT nMac);
+typedef BOOL (PASCAL * PDAPI_FUpdateProgressText)
+ (LPVOID lpvAppDefined, LPTSTR pszText);
+
+typedef struct CallBackProgressEntryPoints
+{
+ DWORD dwFlags;
+ LPVOID lpvAppDefined;
+ PDAPI_FInitProgress pfnInitProgress;
+ PDAPI_FUpdateProgress pfnUpdateProgress;
+ PDAPI_FEndProgress pfnEndProgress;
+ PDAPI_FResetProgress pfnResetProgress;
+ PDAPI_FUpdateProgressText pfnUpdateProgressText;
+} CALLBACKPROGRESS, *PCALLBACKPROGRESS;
+
+
+
+// Values specified in the ulEvalTag field of the
+// DAPI_ENTRY and EXPORT_CALLBACK structures
+//
+typedef enum _DAPI_EVAL
+{
+ VALUE_ARRAY = 0, // Each attribute has an entry in the array
+ // Text strings and object names exported as text
+ // Numerical values exported as numbers
+ // Binary data exported as binary string
+ TEXT_VALUE_ARRAY, // Each attribute has an entry in the array
+ // All values converted to text representation
+ TEXT_LINE // first item in the rgEntryValues array
+ // is a delimited text line
+} DAPI_EVAL, *PDAPI_EVAL;
+
+typedef enum _EXP_TYPE_TAG
+{
+ EXPORT_HEADER = 0, // export item contains column headers
+ EXPORT_ENTRY // export item contains attribute values
+} EXP_TYPE, * PEXP_TYPE;
+
+
+typedef enum enumDAPI_DATA_TYPE
+{
+ DAPI_NO_VALUE = 0,
+ DAPI_STRING8,
+ DAPI_UNICODE,
+ DAPI_BINARY,
+ DAPI_INT,
+ DAPI_BOOL,
+} DAPI_DATA_TYPE, * PDAPI_DATA_TYPE;
+
+#ifdef UNICODE
+#define DAPI_TEXT DAPI_UNICODE
+#else
+#define DAPI_TEXT DAPI_STRING8
+#endif
+
+typedef union _DAPI_VALUE
+{
+ LPSTR pszA;
+ LPWSTR pszW;
+#ifdef UNICODE
+ LPWSTR pszValue;
+#else
+ LPSTR pszValue;
+#endif
+ LPBYTE lpBinary;
+ INT iValue;
+ BOOL bool;
+} DAPI_VALUE, * PDAPI_VALUE;
+
+
+
+// The ATT_VALUE structure contains a text representation of an attribute value
+// A linked list of these structures is used for a multi-valued attribute
+typedef struct _ATT_VALUE
+{
+ DAPI_DATA_TYPE DapiType; // How to evaluate DAPI_VALUE union
+ DAPI_VALUE Value;
+ UINT size; // size of the value --
+ // # chars if string type
+ // else, # bytes
+ struct _ATT_VALUE * pNextValue;
+} ATT_VALUE, * PATT_VALUE;
+
+
+typedef struct _DAPI_ENTRY
+{
+ UINT unAttributes; // Number of attributes exported
+ DAPI_EVAL ulEvalTag; // rgEntryValues is interpreted based on this value
+ PATT_VALUE rgEntryValues; // if (ulEvalTag == TEXT_LINE)
+ // There is a single value, w/ delimited line
+ // else
+ // unAttributes, each w/ 1 or more value in list
+} DAPI_ENTRY, * PDAPI_ENTRY;
+
+// Define type for address of application routine
+// for call-back on each exported entry.
+// Return value of FALSE indicates that export operation should be cancelled
+typedef BOOL (PASCAL DAPI_FNExportEntry) (
+ EXP_TYPE ExportDataType, // What type of data is being exported
+ LPVOID lpvAppDefined, // Application-defined parameter,
+ // passed in EXPORT_CALLBACK structure
+ // on initialization
+ PDAPI_ENTRY pExportEntry // pointer to exported entry data
+ // NOTE: Data in this structure
+ // will NOT remain valid after return
+ // from this function
+ );
+typedef DAPI_FNExportEntry * PDAPI_FNExportEntry;
+
+typedef struct _EXPORT_CALLBACK
+{
+ DWORD dwFlags; // Flags defined to control callback functionality
+ // See flag definitions below
+ DAPI_EVAL ulEvalTag; // Specifies data format on callback
+ LPVOID lpvAppDefined; // Application-defined field, passed as parm to callback
+ PDAPI_FNExportEntry pfnExportEntry; // Pointer to function called to process
+ // each exported entry
+
+} EXPORT_CALLBACK, * PEXPORT_CALLBACK;
+
+
+
+/*******************************************************************************
+* procedure : pfnErrorCallback
+*
+* purpose : The following section defines structures for the error callback
+* mechanism of the Batch Import APIs
+* Events will be filtered based on the ControlfFlags set in the
+* API parameter block
+*
+********************************************************************************/
+
+// Define flags used for export callback
+
+// Define the maximum number of substitutions in a single event string
+#define DAPI_MAX_SUBST 8
+
+
+typedef struct _DAPI_EVENTA
+{
+ DWORD dwDAPIError; // Message ID for event log
+ LPSTR rgpszSubst[DAPI_MAX_SUBST]; // Event message substitution array
+ UINT unSubst; // number of substitution strings
+ LPSTR pszAttribute; // Name of attribute specifically affected
+ // Note: may be NULL on some errors
+ LPSTR pszHoldLine; // point to buffer containing copy
+ // of current import line
+ HINSTANCE hinstDAPI; // Instance of DAPI DLL
+ struct _DAPI_EVENTA * pNextEvent; // Pointer to next event
+} DAPI_EVENTA, *PDAPI_EVENTA;
+
+typedef struct _DAPI_EVENTW
+{
+ DWORD dwDAPIError; // Message ID for event log
+ LPWSTR rgpszSubst[DAPI_MAX_SUBST]; // Event message substitution array
+ UINT unSubst; // number of substitution strings
+ LPWSTR pszAttribute; // Name of attribute specifically affected
+ // Note: may be NULL on some errors
+ LPWSTR pszHoldLine; // point to buffer containing copy
+ // of current import line
+ HINSTANCE hinstDAPI; // Instance of DAPI DLL
+ struct _DAPI_EVENTW * pNextEvent; // Pointer to next event
+} DAPI_EVENTW, *PDAPI_EVENTW;
+
+#ifdef UNICODE
+typedef DAPI_EVENTW DAPI_EVENT;
+typedef PDAPI_EVENTW PDAPI_EVENT;
+#else
+typedef DAPI_EVENTA DAPI_EVENT;
+typedef PDAPI_EVENTA PDAPI_EVENT;
+#endif
+
+// Define type for address of application routine
+// for call-back on each error encountered.
+// Return value of FALSE indicates that operation should be cancelled
+typedef BOOL (PASCAL DAPI_FNErrorCallback) (
+ LPVOID lpvAppDefined, // Application-defined parameter,
+ // passed in EXPORT_CALLBACK structure
+ // on initialization
+ PDAPI_EVENT pDapiEvent // Event information structure
+ // NOTE: Data in the event record
+ // will NOT remain valid after return
+ // from this function
+ );
+typedef DAPI_FNErrorCallback * PDAPI_FNErrorCallback;
+
+
+typedef struct tagERROR_CALLBACK
+{
+ DWORD dwFlags; // Flags defined to control callback functionality
+ // See flag definitions above
+ LPVOID lpvAppDefined; // Application-defined field, passed back in callback
+ PDAPI_FNErrorCallback pfnErrorCallback; // Address of function that should be
+ // called on each error encountered
+ // If not supplied (NULL), default
+ // error handler is called, which
+ // writes the error into the
+ // NT Application event log
+
+} ERROR_CALLBACK, * PERROR_CALLBACK;
+
+
+
+
+
+/*******************************************************************************
+*
+* Batch Directory Import Interface definitions
+*
+********************************************************************************/
+
+/*******************************************************************************
+* procedure : DAPIUninitialize
+*
+* purpose : Notify DAPI that it is time to terminate background threads
+* and such in preparation for process shutdown
+*
+* parameters : dwFlags combinable bits which may be set to control function
+*
+* returns : nothing
+*
+* created : 11/01/95
+*
+* changes :
+*
+********************************************************************************/
+extern void APIENTRY DAPIUninitialize (
+ DWORD dwFlags // Flags for call
+);
+
+
+
+/*******************************************************************************
+* procedure : SchemaPreload
+*
+* purpose : Called to perform asyncronous schema load. This entry point
+* spawns a thread that initializes all the attribute and class
+* tables for normal import/export operation.
+*
+* parameters : pSchemaPreloadParms pointer to SchemaPreloadParameter block
+*
+* returns : nothing
+*
+* history :
+*
+********************************************************************************/
+extern void APIENTRY SchemaPreloadA (
+ DWORD dwFlags, // Flags used to control schema load.
+ LPSTR pszDSA // name of DSA from which to read schema
+);
+
+extern void APIENTRY SchemaPreloadW (
+ DWORD dwFlags, // Flags used to control schema load.
+ LPWSTR pszDSA // name of DSA from which to read schema
+);
+
+#ifdef UNICODE
+#define SchemaPreload SchemaPreloadW
+#else
+#define SchemaPreload SchemaPreloadA
+#endif
+
+typedef struct _BIMPORT_PARMSW
+{
+ // NOTE: the order of the first three fields of this structure
+ // should NOT be changed.
+ DWORD dwDAPISignature;
+ DWORD dwFlags; // Bitmapped flags that control import action
+ HWND hwndParent; // Windows handle to use when displaying message boxes
+ LPWSTR pszImportFile; // Fully qualified pathname to Import Data file
+ // On Batch Import, objects are imported into
+ // the DIT from this file.
+ UINT uCodePage; // Code page specification for import file.
+ // The following values are interpreted:
+ // DAPI_UNICODE_FILE Import file is Unicode
+ // Will return error if file is ANSI
+ // 0 Auto-detect file type
+ // If ANSI, assume CP_ACP
+ // other File contains text in the
+ // specified code page
+ // Will return error if file is Unicode
+ // Will return error if code page is not
+ // supported by the system
+ LPWSTR pszDSAName; // Computer name of DSA to update
+ // Default: local DSA (if operating)
+ // if no local DSA, first DSA found
+ // on network is used
+ LPWSTR pszBasePoint; // DN of base-point in DIT for bulk operations
+ // Default values:
+ // if NULL, Messaging Site containing bound server
+ // if empty string, enterprise containing bound server
+ LPWSTR pszContainer; // RDN of default container under which
+ // to perform bulk import operations
+ // NOTE: This container is assumed to be
+ // at the level below that indicated by
+ // the pszBasePoint. If NULL,
+ // bulk operations will be performed at
+ // the level below BaseImportPoint.
+ // Container names specified in the
+ // import file will override this value.
+ WCHAR chColSep; // Column Separator --
+ // DEFAULT_DELIM is used if this value is zero
+ WCHAR chQuote; // String enclosing character --
+ // DEFAULT_QUOTE is used if this value is zero
+ WCHAR chMVSep; // Multi-value Property Separator --
+ // DEFAULT_MV_SEP is used if this value is zero
+ WCHAR creserved; // alignment
+ CALLBACKPROGRESS ProgressCallBacks; // Progress call-back entry points
+ ERROR_CALLBACK ErrorCallback;
+
+ LPWSTR pszNTDomain; // Name of NT Domain in which to lookup / create NT accounts.
+ // Defaults to current logon domain if NULL or empty
+ LPWSTR pszCreateTemplate; // DN of the Default User (NULL if none) from which
+ // to draw template values
+
+} BIMPORT_PARMSW, *PBIMPORT_PARMSW, *LPBIMPORT_PARMSW;
+
+typedef struct _BIMPORT_PARMSA
+{
+ // NOTE: the order of the first three fields of this structure
+ // should NOT be changed.
+ DWORD dwDAPISignature;
+ DWORD dwFlags; // Bitmapped flags that control import action
+ HWND hwndParent; // Windows handle to use when displaying message boxes
+ LPSTR pszImportFile; // Fully qualified pathname to Import Data file
+ // On Batch Import, objects are imported into
+ // the DIT from this file.
+ UINT uCodePage; // Code page specification for import file.
+ // The following values are interpreted:
+ // DAPI_UNICODE_FILE Import file is Unicode
+ // Will return error if file is ANSI
+ // 0 Auto-detect file type
+ // If ANSI, assume CP_ACP
+ // other File contains text in the
+ // specified code page
+ // Will return error if file is Unicode
+ // Will return error if code page is not
+ // supported by the system
+ LPSTR pszDSAName; // Computer name of DSA to update
+ // Default: local DSA (if operating)
+ // if no local DSA, first DSA found
+ // on network is used
+ LPSTR pszBasePoint; // DN of base-point in DIT for bulk operations
+ // Default values:
+ // if NULL, Messaging Site containing bound server
+ // if empty string, enterprise containing bound server
+ LPSTR pszContainer; // RDN of default container under which
+ // to perform bulk import operations
+ // NOTE: This container is assumed to be
+ // at the level below that indicated by
+ // the pszBasePoint. If NULL,
+ // bulk operations will be performed at
+ // the level below BaseImportPoint.
+ // Container names specified in the
+ // import file will override this value.
+ CHAR chColSep; // Column Separator --
+ // DEFAULT_DELIM is used if this value is zero
+ CHAR chQuote; // String enclosing character --
+ // DEFAULT_QUOTE is used if this value is zero
+ CHAR chMVSep; // Multi-value Property Separator --
+ // DEFAULT_MV_SEP is used if this value is zero
+ CHAR creserved; // alignment
+ CALLBACKPROGRESS ProgressCallBacks; // Progress call-back entry points
+ ERROR_CALLBACK ErrorCallback;
+
+ LPSTR pszNTDomain; // Name of NT Domain in which to lookup / create NT accounts.
+ // Defaults to current logon domain if NULL or empty
+ LPSTR pszCreateTemplate; // DN of the Default User (NULL if none) from which
+ // to draw template values
+
+} BIMPORT_PARMSA, *PBIMPORT_PARMSA, *LPBIMPORT_PARMSA;
+
+#ifdef UNICODE
+typedef BIMPORT_PARMSW BIMPORT_PARMS;
+typedef PBIMPORT_PARMSW PBIMPORT_PARMS;
+typedef LPBIMPORT_PARMSW LPBIMPORT_PARMS;
+#else
+typedef BIMPORT_PARMSA BIMPORT_PARMS;
+typedef PBIMPORT_PARMSA PBIMPORT_PARMS;
+typedef LPBIMPORT_PARMSA LPBIMPORT_PARMS;
+#endif
+
+// The BatchImport function provides single-call BatchImport from the
+// specified import file. All import parameters are specified in the
+// BIMPORT_PARMS structure pointed to by lpBimportParms.
+// The return value indicates the number of errors logged in the
+// NT Application log. Please note that this does not indicate
+// success or failure of the Batch Import.
+// UI and Logging of errors and warnings into the Application log
+// are controlled through import parameters.
+extern DWORD APIENTRY BatchImportW (LPBIMPORT_PARMSW lpBimportParms);
+extern DWORD APIENTRY BatchImportA (LPBIMPORT_PARMSA lpBimportParms);
+
+#ifdef UNICODE
+#define BatchImport BatchImportW
+#else
+#define BatchImport BatchImportA
+#endif
+
+/*******************************************************************************
+*
+* Batch Directory Export Interface definitions
+*
+********************************************************************************/
+
+typedef struct _BEXPORT_PARMSW
+{
+ DWORD dwDAPISignature;
+ DWORD dwFlags; // Bitmapped flags that control export action
+ HWND hwndParent; // Windows handle to use when displaying message boxes
+ LPWSTR pszExportFile; // Fully qualified pathname of file to export into
+ // Ignored if ExportCallback is specified
+ UINT uCodePage; // Code page specification for export file.
+ // The following values are interpreted:
+ // DAPI_UNICODE_FILE Export file is Unicode.
+ // Will return error
+ // if file exists and is ANSI
+ // 0 Auto-detect file type
+ // If file does not exist,
+ // export file will contain CP_ACP text.
+ // If file exists and is ANSI
+ // export file will contain CP_ACP text.
+ // If file exists and is Unicode,
+ // export file will contain Unicode
+ // other Export text to file in the
+ // specified code page
+ // Will return error
+ // if file exists and is Unicode
+ // Will return error if code page is not
+ // supported by the system
+ LPWSTR pszDSAName; // Computer name of DSA from which to export
+ // Default: local DSA (if operating)
+ // if no local DSA, first DSA found
+ // on network is used
+ LPWSTR pszBasePoint; // DN of base-point in DIT for bulk operations
+ // Default values:
+ // if NULL, Messaging Site containing bound server
+ // if empty string, enterprise containing bound server
+ LPWSTR pszContainer; // RDN of container from which to export objects
+ // NOTE: This container is assumed to be
+ // at the level below that indicated by
+ // the pszBasePoint. If NULL,
+ // the contents of all containers below
+ // the BaseImportPoint will be exported.
+ WCHAR chColSep; // Column Separator --
+ // DEFAULT_DELIM is used if this value is zero
+ WCHAR chQuote; // String enclosing character --
+ // DEFAULT_QUOTE is used if this value is zero
+ WCHAR chMVSep; // Multi-value Property Separator --
+ // DEFAULT_MV_SEP is used if this value is zero
+ WCHAR cReserved; // alignment
+
+ CALLBACKPROGRESS ProgressCallBacks; // Progress call-back entry points
+ ERROR_CALLBACK ErrorCallback;
+ EXPORT_CALLBACK ExportCallback; // Structure filled in by calling app to
+ // receive callback on each exported item
+ // NOTE: Callback functions are optional
+ // The default export function (write to file)
+ // will be called if these pointers are NULL
+ PDAPI_ENTRY pAttributes; // DAPI_ENTRY filled with names of attributes to export
+ // Optional if pszExportFile specified
+ // Required if ExportCallback specified
+ LPWSTR pszHomeServer; // Name of server for server-associated export
+ LPWSTR * rgpszClasses; // array of pointers to zero-terminated object classes to export
+ // The last entry must be NULL
+ // NOTE: The Directory will be queried for objects
+ // of the classes in the specified order.
+ ULONG ulUSNBase; // Base USN to use for export restriction.
+ // If non-zero, only items having USN-Changed >= ulUSNBase will be exported
+ LPVOID pReserved; // Reserved -- Must be zero
+
+} BEXPORT_PARMSW, *PBEXPORT_PARMSW, *LPBEXPORT_PARMSW;
+
+typedef struct _BEXPORT_PARMSA
+{
+ DWORD dwDAPISignature;
+ DWORD dwFlags; // Bitmapped flags that control export action
+ HWND hwndParent; // Windows handle to use when displaying message boxes
+ LPSTR pszExportFile; // Fully qualified pathname of file to export into
+ // Ignored if ExportCallback is specified
+ UINT uCodePage; // Code page specification for export file.
+ // The following values are interpreted:
+ // DAPI_UNICODE_FILE Export file is Unicode.
+ // Will return error
+ // if file exists and is ANSI
+ // 0 Auto-detect file type
+ // If file does not exist,
+ // export file will contain CP_ACP text.
+ // If file exists and is ANSI
+ // export file will contain CP_ACP text.
+ // If file exists and is Unicode,
+ // export file will contain Unicode
+ // other Export text to file in the
+ // specified code page
+ // Will return error
+ // if file exists and is Unicode
+ // Will return error if code page is not
+ // supported by the system
+ LPSTR pszDSAName; // Computer name of DSA from which to export
+ // Default: local DSA (if operating)
+ // if no local DSA, first DSA found
+ // on network is used
+ LPSTR pszBasePoint; // DN of base-point in DIT for bulk operations
+ // Default values:
+ // if NULL, Messaging Site containing bound server
+ // if empty string, enterprise containing bound server
+ LPSTR pszContainer; // RDN of container from which to export objects
+ // NOTE: This container is assumed to be
+ // at the level below that indicated by
+ // the pszBasePoint. If NULL,
+ // the contents of all containers below
+ // the BaseImportPoint will be exported.
+ CHAR chColSep; // Column Separator --
+ // DEFAULT_DELIM is used if this value is zero
+ CHAR chQuote; // String enclosing character --
+ // DEFAULT_QUOTE is used if this value is zero
+ CHAR chMVSep; // Multi-value Property Separator --
+ // DEFAULT_MV_SEP is used if this value is zero
+ CHAR cReserved; // alignment
+
+ CALLBACKPROGRESS ProgressCallBacks; // Progress call-back entry points
+ ERROR_CALLBACK ErrorCallback;
+ EXPORT_CALLBACK ExportCallback; // Structure filled in by calling app to
+ // receive callback on each exported item
+ // NOTE: Callback functions are optional
+ // The default export function (write to file)
+ // will be called if these pointers are NULL
+ PDAPI_ENTRY pAttributes; // DAPI_ENTRY filled with names of attributes to export
+ // Optional if pszExportFile specified
+ // Required if ExportCallback specified
+ LPSTR pszHomeServer; // Name of server for server-associated export
+ LPSTR * rgpszClasses; // array of pointers to zero-terminated object classes to export
+ // The last entry must be NULL
+ // NOTE: The Directory will be queried for objects
+ // of the classes in the specified order.
+ ULONG ulUSNBase; // Base USN to use for export restriction.
+ // If non-zero, only items having USN-Changed >= ulUSNBase will be exported
+ LPVOID pReserved; // Reserved -- Must be zero
+
+} BEXPORT_PARMSA, *PBEXPORT_PARMSA, *LPBEXPORT_PARMSA;
+
+
+#ifdef UNICODE
+typedef BEXPORT_PARMSW BEXPORT_PARMS;
+typedef PBEXPORT_PARMSW PBEXPORT_PARMS;
+typedef LPBEXPORT_PARMSW LPBEXPORT_PARMS;
+#else
+typedef BEXPORT_PARMSA BEXPORT_PARMS;
+typedef PBEXPORT_PARMSA PBEXPORT_PARMS;
+typedef LPBEXPORT_PARMSA LPBEXPORT_PARMS;
+#endif
+
+
+
+// Batch Export entry points
+
+// The BatchExport function provides single-call BatchExport from the
+// specified import file. All import parameters are specified in the
+// BEXPORT_PARMS structure pointed to by lpBexportParms.
+// The return value indicates the number of errors logged in the
+// NT Application log. Please note that this does not indicate
+// success or failure of the Batch Export.
+// UI and Logging of errors and warnings into the Application log
+// are controlled through import parameters.
+extern DWORD APIENTRY BatchExportW (LPBEXPORT_PARMSW lpBexportParms);
+extern DWORD APIENTRY BatchExportA (LPBEXPORT_PARMSA lpBexportParms);
+
+#ifdef UNICODE
+#define BatchExport BatchExportW
+#else
+#define BatchExport BatchExportA
+#endif
+
+
+/*******************************************************************************
+*
+* Single-Object Interface definitions
+*
+********************************************************************************/
+
+typedef struct _DAPI_PARMSW
+{
+ DWORD dwDAPISignature;
+ DWORD dwFlags; // Bitmapped flags that control import action
+ // See Import Control flags defined above.
+ LPWSTR pszDSAName; // Computer name of DSA to update
+ // Default: local DSA (if operating)
+ // if no local DSA, first DSA found
+ // on network is used
+ LPWSTR pszBasePoint; // DN of base-point in DIT for bulk operations
+ // Default values:
+ // if NULL, Messaging Site containing bound server
+ // if empty string, enterprise containing bound server
+ LPWSTR pszContainer; // RDN of default container under which
+ // to perform bulk import operations
+ // NOTE: This container is assumed to be
+ // at the level below that indicated by
+ // the pszBasePoint. If NULL,
+ // bulk operations will be performed at
+ // the level below BaseImportPoint.
+ // Container names specified in the
+ // import file will override this value.
+ LPWSTR pszNTDomain; // Name of NT Domain in which to lookup accounts
+ // and to create NT accounts.
+ // Current logon domain is used if NULL or empty string.
+ LPWSTR pszCreateTemplate;// DN of the template object used for default values
+ PDAPI_ENTRY pAttributes; // DAPI_ENTRY filled with default attribute list
+} DAPI_PARMSW, *PDAPI_PARMSW, FAR *LPDAPI_PARMSW;
+
+typedef struct _DAPI_PARMSA
+{
+ DWORD dwDAPISignature;
+ DWORD dwFlags; // Bitmapped flags that control import action
+ // See Import Control flags defined above.
+ LPSTR pszDSAName; // Computer name of DSA to update
+ // Default: local DSA (if operating)
+ // if no local DSA, first DSA found
+ // on network is used
+ LPSTR pszBasePoint; // DN of base-point in DIT for bulk operations
+ // Default values:
+ // if NULL, Messaging Site containing bound server
+ // if empty string, enterprise containing bound server
+ LPSTR pszContainer; // RDN of default container under which
+ // to perform bulk import operations
+ // NOTE: This container is assumed to be
+ // at the level below that indicated by
+ // the pszBasePoint. If NULL,
+ // bulk operations will be performed at
+ // the level below BaseImportPoint.
+ // Container names specified in the
+ // import file will override this value.
+ LPSTR pszNTDomain; // Name of NT Domain in which to lookup accounts
+ // and to create NT accounts.
+ // Current logon domain is used if NULL or empty string.
+ LPSTR pszCreateTemplate; // DN of the template object used for default values
+ PDAPI_ENTRY pAttributes; // DAPI_ENTRY filled with default attribute list
+} DAPI_PARMSA, *PDAPI_PARMSA, FAR *LPDAPI_PARMSA;
+
+
+#ifdef UNICODE
+typedef DAPI_PARMSW DAPI_PARMS;
+typedef PDAPI_PARMSW PDAPI_PARMS;
+typedef LPDAPI_PARMSW LPDAPI_PARMS;
+#else
+typedef DAPI_PARMSA DAPI_PARMS;
+typedef PDAPI_PARMSA PDAPI_PARMS;
+typedef LPDAPI_PARMSA LPDAPI_PARMS;
+#endif
+
+
+typedef LPVOID DAPI_HANDLE;
+typedef LPVOID * PDAPI_HANDLE;
+typedef LPVOID FAR * LPDAPI_HANDLE;
+
+#define DAPI_INVALID_HANDLE ((DAPI_HANDLE) -1)
+
+
+
+// DAPIStart initializes a DAPI session.
+// for use by DAPIRead and DAPIWrite. The return value is 0 if no errors
+// are encountered. A pointer to a DAPI_EVENT structure is returned if an
+// error is encountered.
+// NOTE: The DAPI_HANDLE must be returned via a call to DAPIEnd.
+// If a non-NULL value is returned, its memory must be freed by
+// a call to DAPIFreeMemory
+extern PDAPI_EVENTW APIENTRY DAPIStartW (LPDAPI_HANDLE lphDAPISession,
+ LPDAPI_PARMSW lpDAPIParms);
+extern PDAPI_EVENTA APIENTRY DAPIStartA (LPDAPI_HANDLE lphDAPISession,
+ LPDAPI_PARMSA lpDAPIParms);
+
+#ifdef UNICODE
+#define DAPIStart DAPIStartW
+#else
+#define DAPIStart DAPIStartA
+#endif
+
+// DAPIEnd invalidates the DAPI_HANDLE obtained by the call to DAPIStart.
+// NOTE: There are no separate Unicode / Ansi entry points defined
+extern void APIENTRY DAPIEnd (LPDAPI_HANDLE lphDAPISession);
+
+
+// DAPIRead() Reads indicated attributes from the named Directory Object
+// Parameters:
+// Returned value: NULL indicates no difficulties encountered.
+// Else, pointer to structure containing description of
+// error(s) or warning(s) encountered.
+// Must be freed by call to DAPIFreeMemory.
+// hDAPISession DAPI Session handle obtained via InitDAPISession
+// dwFlags control operation
+// pszObjectName String containing name of object to read.
+// If specified as RDN, combined w/ session's
+// pszBasePoint and pszParentContainer.
+// If specified w/ prefix of "/cn=", the string
+// is concatenated to the session pszBasePoint.
+// If specified w/ prefix of "/o=", the string
+// is taken to be a fully-qualified DN.
+// pAttList Pointer to DAPI_ENTRY structure containing names of
+// attributes to read. The session default list is
+// overridden for the present call only.
+// ppValues Address of variable receiving pointer to DAPI_ENTRY
+// structure containing the values read from the DIT entry.
+// The pointer returned must be freed by call to
+// DAPIFreeMemory.
+// ppAttributes Address of variable receiving pointer to DAPI_ENTRY
+// structure containing the names of attributes read
+// from the DIT IFF DAPI_ALL_ATTRIBUTES or DAPI_LEGAL_ATTRIBUTES
+// were set in dwFlags.
+// The pointer returned must be freed by call to
+// DAPIFreeMemory.
+extern PDAPI_EVENTW APIENTRY DAPIReadW (DAPI_HANDLE hDAPISession,
+ DWORD dwFlags,
+ LPWSTR pszObjectName,
+ PDAPI_ENTRY pAttList,
+ PDAPI_ENTRY * ppValues,
+ PDAPI_ENTRY * ppAttributes);
+extern PDAPI_EVENTA APIENTRY DAPIReadA (DAPI_HANDLE hDAPISession,
+ DWORD dwFlags,
+ LPSTR pszObjectName,
+ PDAPI_ENTRY pAttList,
+ PDAPI_ENTRY * ppValues,
+ PDAPI_ENTRY * ppAttributes);
+
+#ifdef UNICODE
+#define DAPIRead DAPIReadW
+#else
+#define DAPIRead DAPIReadA
+#endif
+
+
+// DAPIWrite()
+// Perform the indicated write operation on the named object
+// Returned value: NULL indicates no difficulties encountered.
+// Else, pointer to structure containing description of
+// error(s) or warning(s) encountered.
+// Must be freed by call to DAPIFreeMemory.
+// Parameters:
+// hDAPISession DAPI Session handle obtained via InitDAPISession
+// dwFlags Operational control
+// pAttributes Pointer to DAPI_ENTRY structure containing names of
+// attributes to write. The session default list is
+// used if this parameter is NULL
+// pValues Pointer to DAPI_ENTRY structure containing the values
+// to set on the DIT entry.
+// lpulUSN Optional: Address of variable receiving USN of updated
+// DIT entry. May be specified as NULL to suppress this
+// return value.
+// lppszCreatedAccount Address receiving pointer to name of created NT account
+// lppszPassword Address receiving pointer to password generated if
+// NT Account is created.
+extern PDAPI_EVENTW APIENTRY DAPIWriteW (DAPI_HANDLE hDAPISession,
+ DWORD dwFlags,
+ PDAPI_ENTRY pAttributes,
+ PDAPI_ENTRY pValues,
+ PULONG lpulUSN,
+ LPWSTR * lppszCreatedAccount,
+ LPWSTR * lppszPassword);
+extern PDAPI_EVENTA APIENTRY DAPIWriteA (DAPI_HANDLE hDAPISession,
+ DWORD dwFlags,
+ PDAPI_ENTRY pAttributes,
+ PDAPI_ENTRY pValues,
+ PULONG lpulUSN,
+ LPSTR * lppszCreatedAccount,
+ LPSTR * lppszPassword);
+#ifdef UNICODE
+#define DAPIWrite DAPIWriteW
+#else
+#define DAPIWrite DAPIWriteA
+#endif
+
+
+/*******************************************************************************
+* procedure : DAPIAllocBuffer
+*
+* purpose : Allocate buffer, logically linking it to the pvAllocBase
+* The first buffer in logically linked set of allocations must be
+* freed by call to DAPIFreeMemory
+*
+* parameters : cbSize dword containing size of allocation request (in bytes)
+* pvAllocBase base for logical linking of allocated block
+* May be NULL
+* If non-NULL, must be a block previously allocated
+* by DAPIAllocBuffer or returned by DAPI function
+*
+* returns : ptr to allocated block
+*
+* history :
+*
+********************************************************************************/
+extern LPVOID APIENTRY DAPIAllocBuffer (DWORD cbSize, LPVOID pvAllocBase);
+
+
+/*******************************************************************************
+* procedure : DAPIFreeMemory
+*
+* purpose : Release memory allocated for structures returned by DAPI calls.
+*
+* parameters : lpVoid pointer to block to free
+*
+* returns : nothing
+*
+* history :
+*
+********************************************************************************/
+extern void APIENTRY DAPIFreeMemory (LPVOID lpVoid);
+
+
+/*
+ * NetUserList interface definitions
+ */
+// When getting callbacks from NTExport / NWExport, these indices
+// can be used to interpret the value array returned in the callback
+// >>>> NOTE: These indices are NOT valid for Bexport callback! <<<<
+#define NET_CLASS 0
+#define NET_COMMON_NAME 1
+#define NET_DISPLAY_NAME 2
+#define NET_HOME_SERVER 3
+#define NET_COMMENT 4 /* NTExport only */
+
+#define NTEXP_ENTRY_COUNT 5 /* number of parts in NT User export */
+#define NWEXP_ENTRY_COUNT 4 /* number of parts in NetWare user export */
+
+
+
+/*******************************************************************************
+*
+* NTIMPORT Interface definitions
+*
+********************************************************************************/
+
+typedef struct _NTEXPORT_PARMSW
+{
+ DWORD dwDAPISignature;
+ DWORD dwFlags; // Bitmapped flags that control the user export
+ HWND hwndParent; // Windows handle to use when displaying message boxes
+ LPWSTR pszExportFile; // Name of file to create
+ // Ignored if using callbacks
+ CALLBACKPROGRESS ProgressCallBacks;// Progress call-back entry points
+ ERROR_CALLBACK ErrorCallback;
+ EXPORT_CALLBACK ExportCallback; // Structure filled in by calling app to
+ // receive callback on each exported item
+ // NOTE: Callback functions are optional
+ // The default export function (write to file)
+ // will be called if these pointers are NULL
+ LPWSTR pszDCName; // Name of Domain Controller from which to get users
+ // NOTE: Specification of Domain Controller overrides
+ // the NTDomain
+ LPWSTR pszNTDomain; // Name of Domain from which to read users
+ // If neither pszNTDomain and pszDCName are specified,
+ // users are extracted from the current login domain
+} NTEXPORT_PARMSW, *PNTEXPORT_PARMSW, FAR *LPNTEXPORT_PARMSW;
+
+typedef struct _NTEXPORT_PARMSA
+{
+ DWORD dwDAPISignature;
+ DWORD dwFlags; // Bitmapped flags that control the user export
+ HWND hwndParent; // Windows handle to use when displaying message boxes
+ LPSTR pszExportFile; // Name of file to create
+ // Ignored if using callbacks
+ CALLBACKPROGRESS ProgressCallBacks;// Progress call-back entry points
+ ERROR_CALLBACK ErrorCallback;
+ EXPORT_CALLBACK ExportCallback; // Structure filled in by calling app to
+ // receive callback on each exported item
+ // NOTE: Callback functions are optional
+ // The default export function (write to file)
+ // will be called if these pointers are NULL
+ LPSTR pszDCName; // NOTE: Specification of Domain Controller overrides
+ // the NTDomain
+ // Name of Domain from which to read users
+ LPSTR pszNTDomain; // If neither pszNTDomain and pszDCName are specified,
+ // users are extracted from the current login domain
+
+} NTEXPORT_PARMSA, *PNTEXPORT_PARMSA, FAR *LPNTEXPORT_PARMSA;
+
+#ifdef UNICODE
+typedef NTEXPORT_PARMSW NTEXPORT_PARMS;
+typedef PNTEXPORT_PARMSW PNTEXPORT_PARMS;
+typedef LPNTEXPORT_PARMSW LPNTEXPORT_PARMS;
+#else
+typedef NTEXPORT_PARMSA NTEXPORT_PARMS;
+typedef PNTEXPORT_PARMSA PNTEXPORT_PARMS;
+typedef LPNTEXPORT_PARMSA LPNTEXPORT_PARMS;
+#endif
+
+extern DWORD APIENTRY NTExportW (LPNTEXPORT_PARMSW pNTExportParms);
+extern DWORD APIENTRY NTExportA (LPNTEXPORT_PARMSA pNTExportParms);
+
+#ifdef UNICODE
+#define NTExport NTExportW
+#else
+#define NTExport NTExportA
+#endif
+
+
+/*******************************************************************************
+*
+* NWIMPORT Interface definitions
+*
+********************************************************************************/
+
+typedef struct _NWEXPORT_PARMSW
+{
+ DWORD dwDAPISignature;
+ DWORD dwFlags; // Bitmapped flags that control the user export
+ HWND hwndParent; // Windows handle to use when displaying message boxes
+ LPWSTR pszExportFile; // Name of file to create
+ // Ignored if using callbacks
+ CALLBACKPROGRESS ProgressCallBacks;// Progress call-back entry points
+ ERROR_CALLBACK ErrorCallback;
+ EXPORT_CALLBACK ExportCallback; // Structure filled in by calling app to
+ // receive callback on each exported item
+ // NOTE: Callback functions are optional
+ // The default export function (write to file)
+ // will be called if these pointers are NULL
+ LPWSTR pszFileServer; // Name of the file server to connect to
+ LPWSTR pszUserName; // User Name -- Must have administrator priviliges
+ LPWSTR pszPassword; // Password to connect to the server
+} NWEXPORT_PARMSW, *PNWEXPORT_PARMSW, *LPNWEXPORT_PARMSW;
+
+typedef struct _NWEXPORT_PARMSA
+{
+ DWORD dwDAPISignature;
+ DWORD dwFlags; // Bitmapped flags that control the user export
+ HWND hwndParent; // Windows handle to use when displaying message boxes
+ LPSTR pszExportFile; // Name of file to create
+ // Ignored if using callbacks
+ CALLBACKPROGRESS ProgressCallBacks;// Progress call-back entry points
+ ERROR_CALLBACK ErrorCallback;
+ EXPORT_CALLBACK ExportCallback; // Structure filled in by calling app to
+ // receive callback on each exported item
+ // NOTE: Callback functions are optional
+ // The default export function (write to file)
+ // will be called if these pointers are NULL
+ LPSTR pszFileServer; // Name of the file server to connect to
+ LPSTR pszUserName; // User Name -- Must have administrator priviliges
+ LPSTR pszPassword; // Password to connect to the server
+} NWEXPORT_PARMSA, *PNWEXPORT_PARMSA, *LPNWEXPORT_PARMSA;
+
+#ifdef UNICODE
+typedef NWEXPORT_PARMSW NWEXPORT_PARMS;
+typedef PNWEXPORT_PARMSW PNWEXPORT_PARMS;
+typedef LPNWEXPORT_PARMSW LPNWEXPORT_PARMS;
+#else
+typedef NWEXPORT_PARMSA NWEXPORT_PARMS;
+typedef PNWEXPORT_PARMSA PNWEXPORT_PARMS;
+typedef LPNWEXPORT_PARMSA LPNWEXPORT_PARMS;
+#endif
+
+extern DWORD APIENTRY NWExportW (LPNWEXPORT_PARMSW pNWExportParms);
+extern DWORD APIENTRY NWExportA (LPNWEXPORT_PARMSA pNWExportParms);
+
+#ifdef UNICODE
+#define NWExport NWExportW
+#else
+#define NWExport NWExportA
+#endif
+
+
+// Definitions for the DAPIGetSiteInfo call
+
+typedef struct _NAME_INFOA
+{
+ LPSTR pszName; // Simple object name
+ LPSTR pszDNString; // DN of object
+ LPSTR pszDisplayName; // Display name of object
+} NAME_INFOA, *PNAME_INFOA;
+
+typedef struct _NAME_INFOW
+{
+ LPWSTR pszName; // Simple object name
+ LPWSTR pszDNString; // DN of object
+ LPWSTR pszDisplayName; // Display name of object
+} NAME_INFOW, *PNAME_INFOW;
+
+typedef struct _PSITE_INFOA
+{
+ LPSTR pszCountry; // Country code
+ NAME_INFOA objServer; // Name information for server
+ NAME_INFOA objSite; // Name information for site containing server
+ NAME_INFOA objEnterprise; // Name information for enterprise containing server
+} SITE_INFOA, *PSITE_INFOA;
+
+typedef struct _PSITE_INFOW
+{
+ LPWSTR pszCountry; // Country code
+ NAME_INFOW objServer; // Name information for server
+ NAME_INFOW objSite; // Name information for site containing server
+ NAME_INFOW objEnterprise; // Name information for enterprise containing server
+} SITE_INFOW, *PSITE_INFOW;
+
+#ifdef UNICODE
+typedef NAME_INFOW NAME_INFO;
+typedef PNAME_INFOW PNAME_INFO;
+typedef SITE_INFOW SITE_INFO;
+typedef PSITE_INFOW PSITE_INFO;
+#else
+typedef NAME_INFOA NAME_INFO;
+typedef PNAME_INFOA PNAME_INFO;
+typedef SITE_INFOA SITE_INFO;
+typedef PSITE_INFOA PSITE_INFO;
+#endif
+
+extern PDAPI_EVENTA APIENTRY DAPIGetSiteInfoA (
+ DWORD dwFlags, // Flags for request
+ LPSTR pszDSA, // name of DSA from which to get information
+ PSITE_INFOA * ppSiteInfo // Address receiving pointer to pSiteInfo structure
+ // containing return data
+);
+
+extern PDAPI_EVENTW APIENTRY DAPIGetSiteInfoW (
+ DWORD dwFlags, // Flags for request
+ LPWSTR pszDSA, // name of DSA from which to get information
+ PSITE_INFOW * ppSiteInfo // Address receiving pointer to pSiteInfo structure
+ // containing return dataname of DSA from which to read schema
+);
+
+#ifdef UNICODE
+#define DAPIGetSiteInfo DAPIGetSiteInfoW
+#else
+#define DAPIGetSiteInfo DAPIGetSiteInfoA
+#endif
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _DAPI_INCLUDED
diff --git a/private/utils/wizards/addusrw/exch.cpp b/private/utils/wizards/addusrw/exch.cpp
new file mode 100644
index 000000000..1edbb8042
--- /dev/null
+++ b/private/utils/wizards/addusrw/exch.cpp
@@ -0,0 +1,177 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Exch.cpp : implementation file
+
+ CPropertyPage support for User mgmt wizard
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+#include "stdafx.h"
+#include "speckle.h"
+#include "Exch.h"
+
+#include "sadapi.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+
+
+
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CExch property page
+
+IMPLEMENT_DYNCREATE(CExch, CPropertyPage)
+
+CExch::CExch() : CPropertyPage(CExch::IDD)
+{
+ //{{AFX_DATA_INIT(CExch)
+ m_csDomainName = _T("");
+ m_csServerName = _T("");
+ //}}AFX_DATA_INIT
+}
+
+CExch::~CExch()
+{
+}
+
+void CExch::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CExch)
+ DDX_Text(pDX, IDC_STATIC_DOMAIN, m_csDomainName);
+ DDX_Text(pDX, IDC_SERVERNAME_EDIT, m_csServerName);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CExch, CPropertyPage)
+ //{{AFX_MSG_MAP(CExch)
+ ON_WM_SHOWWINDOW()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CExch message handlers
+
+LRESULT CExch::OnWizardNext()
+{
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+ UpdateData(TRUE);
+ if (m_csServerName == L"")
+ {
+ AfxMessageBox(IDS_NO_EXCH_SERVER);
+ GetDlgItem(IDC_SERVERNAME_EDIT)->SetFocus();
+ return -1;
+ }
+
+ pApp->m_csExchangeServer = m_csServerName;
+ return IDD_RESTRICTIONS_DIALOG;
+
+}
+
+LRESULT CExch::OnWizardBack()
+{
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+ if (pApp->m_bNW) return IDD_FPNW_DLG;
+ else if (pApp->m_bRAS) return IDD_RAS_PERM_DIALOG;
+ else if (pApp->m_bHomeDir) return IDD_HOMEDIR_DIALOG;
+ else if (pApp->m_bLoginScript) return IDD_LOGON_SCRIPT_DIALOG;
+ else if (pApp->m_bProfile) return IDD_PROFILE;
+ else return IDD_OPTIONS_DIALOG;
+
+}
+
+
+void CExch::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CPropertyPage::OnShowWindow(bShow, nStatus);
+
+ if (bShow)
+ {
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+ m_csDomainName = pApp->m_csDomain;
+ UpdateData(FALSE);
+
+// bind to the first Exch server
+/* PRPCBINDINFO pBindInfo = new RPCBINDINFO;
+ ZeroMemory(pBindInfo, sizeof(RPCBINDINFO));
+
+ TCHAR wszServer[256];
+// ZeroMemory(wszServer, 256);
+ _tcscpy(wszServer, L"");
+
+ RPC_SC rVal = SAD_ScBind(pBindInfo, wszServer);
+ if (rVal != ERROR_SUCCESS)
+ {
+ AfxMessageBox(L"cant bind");
+ return;
+ }
+
+// using the first server, enumerate the rest
+ BackupListNode* BackupNode = NULL;
+ rVal = SAD_ScGetBackupListNodeW(pBindInfo->wszServer, &BackupNode);
+
+ SAD_FreeBackupListNode(BackupNode);
+ SAD_Unbind(pBindInfo);
+
+ delete pBindInfo; */
+
+
+ /*
+ RPC_NS_HANDLE ic;
+ RPC_STATUS rpcstat;
+ RPC_BINDING_HANDLE h;
+ BackupListNode * pBLN = NULL;
+
+#define szRPCEntryNameSAA L"/.:/MSExchangeSAA"
+
+ // create context for looking up entries in the RPC name service
+ rpcstat = RpcNsBindingImportBegin(RPC_C_NS_SYNTAX_DEFAULT,
+ szRPCEntryNameSAA,
+ TriggerBackupRPC_ClientIfHandle,
+ NULL,
+ &ic);
+
+ if (rpcstat == RPC_S_OK)
+ {
+ do
+ {
+ FreeBackupListNode(pBLN);
+ pBLN = NULL;
+
+ // bind to a server somewhere out there
+ rpcstat = RpcNsBindingImportNext(ic, &h);
+ if (rpcstat == RPC_S_OK)
+ {
+ // bind successful - try to get the list of servers
+ RPC_SC rVal = ScGetBackupListNode(h, &pBLN);
+ RpcBindingFree(&h);
+ if (pBLN != NULL)
+ {
+ ASSERT(0);
+ break;
+ }
+ }
+ }
+ while (rpcstat != RPC_S_NO_MORE_BINDINGS);
+ RpcNsBindingImportDone(&ic);
+ } */
+ }
+}
diff --git a/private/utils/wizards/addusrw/exch.h b/private/utils/wizards/addusrw/exch.h
new file mode 100644
index 000000000..bcc364a90
--- /dev/null
+++ b/private/utils/wizards/addusrw/exch.h
@@ -0,0 +1,57 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Exch.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CExch dialog
+
+class CExch : public CPropertyPage
+{
+ DECLARE_DYNCREATE(CExch)
+
+// Construction
+public:
+ CExch();
+ ~CExch();
+
+// Dialog Data
+ //{{AFX_DATA(CExch)
+ enum { IDD = IDD_EXCHANGE_DIALOG };
+ CString m_csDomainName;
+ CString m_csServerName;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CExch)
+ public:
+ virtual LRESULT OnWizardNext();
+ virtual LRESULT OnWizardBack();
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+private:
+ CString m_csDomain;
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CExch)
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+};
diff --git a/private/utils/wizards/addusrw/finish.cpp b/private/utils/wizards/addusrw/finish.cpp
new file mode 100644
index 000000000..1d41c7470
--- /dev/null
+++ b/private/utils/wizards/addusrw/finish.cpp
@@ -0,0 +1,794 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Finish.cpp : implementation file
+
+ CPropertyPage support for User mgmt wizard
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+#include "stdafx.h"
+#include "Speckle.h"
+#include "wizbased.h"
+#include "Finish.h"
+#include "transbmp.h"
+
+#include <lmaccess.h>
+#include <lmapibuf.h>
+#include <lmcons.h>
+
+typedef long NTSTATUS;
+
+#include "usrprop.h"
+#include <rassapi.h>
+#include "dapi.h"
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+typedef ULONG (*SWAPOBJECTID) (ULONG);
+typedef ULONG (*MAPRIDTOOBJECTID) (DWORD, LPWSTR, BOOL, BOOL);
+typedef NTSTATUS (*GETREMOTENCPSECRETKEY) (PUNICODE_STRING, CHAR *);
+typedef NTSTATUS (*RETURNNETWAREFORM)(const char *, DWORD, const WCHAR *, UCHAR *);
+typedef NTSTATUS (*SETUSERPROPERTY)(LPWSTR, LPWSTR, UNICODE_STRING, WCHAR, LPWSTR*, BOOL*);
+
+typedef DWORD (*RASADMINGETUSERACCOUNTSERVER)(const WCHAR*, const WCHAR*, LPWSTR);
+typedef DWORD (*RASADMINUSERSETINFO)(const WCHAR*, const WCHAR*, const PRAS_USER_0);
+
+typedef DWORD (*BATCHIMPORT) (LPBIMPORT_PARMSW);
+
+/////////////////////////////////////////////////////////////////////////////
+// CFinish property page
+
+IMPLEMENT_DYNCREATE(CFinish, CWizBaseDlg)
+
+CFinish::CFinish() : CWizBaseDlg(CFinish::IDD)
+{
+ //{{AFX_DATA_INIT(CFinish)
+ m_csCaption = _T("");
+ //}}AFX_DATA_INIT
+}
+
+CFinish::~CFinish()
+{
+}
+
+void CFinish::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CFinish)
+ DDX_Text(pDX, IDC_STATIC1, m_csCaption);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CFinish, CWizBaseDlg)
+ //{{AFX_MSG_MAP(CFinish)
+ ON_WM_SHOWWINDOW()
+ ON_WM_PAINT()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CFinish message handlers
+BOOL CFinish::OnInitDialog()
+{
+ CPropertyPage::OnInitDialog();
+
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+LRESULT CFinish::OnWizardBack()
+{
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+ pApp->m_cps1.SetWizardButtons(PSWIZB_BACK | PSWIZB_NEXT);
+
+ if (pApp->m_bNW & pApp->m_bEnableRestrictions) return IDD_NWLOGON_DIALOG;
+ else if (pApp->m_bWorkstation & pApp->m_bEnableRestrictions) return IDD_LOGONTO_DLG;
+ else if (pApp->m_bHours & pApp->m_bEnableRestrictions) return IDD_HOURS_DLG;
+ else if (pApp->m_bExpiration & pApp->m_bEnableRestrictions) return IDD_ACCOUNT_EXP_DIALOG;
+ return IDD_RESTRICTIONS_DIALOG;
+
+}
+
+BOOL CFinish::OnWizardFinish()
+{
+ CString csSuccess, csTemp;
+
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+ CWaitCursor wait;
+
+ TCHAR* pDomainServer = pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength());
+
+ PUSER_INFO_3 pui1 = (PUSER_INFO_3)VirtualAlloc(NULL, sizeof(_USER_INFO_3), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+
+ pui1->usri3_name = pApp->m_csUserName.GetBuffer(pApp->m_csUserName.GetLength());
+ pui1->usri3_password = pApp->m_csPassword1.GetBuffer(pApp->m_csPassword1.GetLength());
+ pui1->usri3_priv = USER_PRIV_USER;
+ pui1->usri3_comment = pApp->m_csDescription.GetBuffer(pApp->m_csDescription.GetLength());
+ pui1->usri3_flags = dwPasswordFlags();
+// availability hours - has to stay here to get the proper defaults!
+ if (pApp->m_bHours) pui1->usri3_logon_hours = NULL;
+
+ DWORD dwRet;
+ NET_API_STATUS napi = NetUserAdd((unsigned short*)pDomainServer, (DWORD)1, (unsigned char*)pui1, &dwRet);
+ VirtualFree(pui1, 0, MEM_RELEASE | MEM_DECOMMIT);
+ if (napi != 0)
+ {
+ csTemp.LoadString(IDS_NO_NEW_USER);
+ csSuccess.Format(csTemp, pApp->m_csFullName, pApp->m_csUserName);
+ if (AfxMessageBox(csSuccess, MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
+ {
+ pApp->m_cps1.SetActivePage(0);
+ return FALSE;
+ }
+ else return TRUE;
+ }
+
+// set local group memberships
+ short sGroupCount = pApp->m_csaSelectedLocalGroups.GetSize();
+ short sCount;
+ CString csVal;
+ for (sCount = 0; sCount < sGroupCount; sCount++)
+ {
+ csVal = pApp->m_csaSelectedLocalGroups.GetAt(sCount);
+ if (!bAddLocalGroups(csVal.GetBuffer(csVal.GetLength())))
+ {
+ AfxMessageBox(IDS_NO_LOCAL_GROUP);
+ break;
+ }
+ }
+
+// set global group memberships
+ sGroupCount = pApp->m_csaSelectedGlobalGroups.GetSize();
+ for (sCount = 0; sCount < sGroupCount; sCount++)
+ {
+ csVal = pApp->m_csaSelectedGlobalGroups.GetAt(sCount);
+ if (!bAddGlobalGroups(csVal.GetBuffer(csVal.GetLength())))
+ {
+ AfxMessageBox(IDS_NO_GLOBAL_GROUP);
+ break;
+ }
+ }
+
+ pApp->m_csUserName.ReleaseBuffer();
+ pApp->m_csPassword1.ReleaseBuffer();
+ pApp->m_csDescription.ReleaseBuffer();
+
+// more information to be set
+ PUSER_INFO_3 pui2 = (PUSER_INFO_3)VirtualAlloc(NULL, sizeof(_USER_INFO_3), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+
+ napi = NetUserGetInfo((unsigned short*)pDomainServer,
+ pApp->m_csUserName.GetBuffer(pApp->m_csUserName.GetLength()),
+ 3,
+ (LPBYTE*)&pui2);
+
+ if (napi != ERROR_SUCCESS) goto failure;
+
+ if (pApp->m_bHours) pui2->usri3_logon_hours = pApp->m_pHours;
+
+// full name
+ pui2->usri3_full_name = pApp->m_csFullName.GetBuffer(pApp->m_csFullName.GetLength());
+ pApp->m_csFullName.ReleaseBuffer();
+
+// seconds till expiration
+ if (pApp->m_bExpiration) pui2->usri3_acct_expires = pApp->m_dwExpirationDate;
+
+ if (pApp->m_bLoginScript)
+ {
+ pui2->usri3_script_path = pApp->m_csLogonScript.GetBuffer(pApp->m_csLogonScript.GetLength());
+ pApp->m_csLogonScript.ReleaseBuffer();
+ }
+
+ if (pApp->m_bHomeDir)
+ {
+ pui2->usri3_home_dir = pApp->m_csHomeDir.GetBuffer(pApp->m_csHomeDir.GetLength());
+ pApp->m_csHomeDir.ReleaseBuffer();
+ }
+
+ if (pApp->m_bProfile)
+ {
+ pui2->usri3_profile = pApp->m_csProfilePath.GetBuffer(pApp->m_csProfilePath.GetLength());
+ pApp->m_csProfilePath.ReleaseBuffer();
+ }
+
+// home dir drive
+ if (pApp->m_bHomeDir)
+ {
+ pui2->usri3_home_dir_drive = pApp->m_csHome_dir_drive.GetBuffer(pApp->m_csHome_dir_drive.GetLength());
+ pApp->m_csHome_dir_drive.ReleaseBuffer();
+ }
+
+// available workstations
+ if (pApp->m_bWorkstation)
+ {
+ pui2->usri3_workstations = pApp->m_csAllowedMachines.GetBuffer(pApp->m_csAllowedMachines.GetLength());
+ pApp->m_csAllowedMachines.ReleaseBuffer();
+ }
+
+ if (pApp->m_bMust_Change_PW) pui2->usri3_password_expired = 1;
+
+// primary group id //accept the default! will become domain users.
+ pui2->usri3_primary_group_id = DOMAIN_GROUP_RID_USERS;
+
+ DWORD dwBuf;
+ napi = NetUserSetInfo((unsigned short*)pDomainServer,
+ pApp->m_csUserName.GetBuffer(pApp->m_csUserName.GetLength()),
+ 3,
+ (LPBYTE)pui2,
+ &dwBuf);
+
+ VirtualFree(pui2, 0, MEM_RELEASE | MEM_DECOMMIT);
+ if (napi != ERROR_SUCCESS) goto failure;
+
+// NetWare compatible?
+ if (pApp->m_bNW)
+ {
+ TCHAR* pUsername = pApp->m_csUserName.GetBuffer(pApp->m_csUserName.GetLength());
+ pApp->m_csUserName.ReleaseBuffer();
+
+ // get NWSETINFO fn
+ HINSTANCE hLib = LoadLibrary(L"fpnwclnt.dll");
+ SETUSERPROPERTY pSetUserProperty = (SETUSERPROPERTY)GetProcAddress(hLib, "SetUserProperty");
+
+ UNICODE_STRING uString;
+ BOOL bRet;
+
+// first set the password
+ CString ucPW = pApp->m_csPassword1;
+ ucPW.MakeUpper();
+ UCHAR* pNWPW = (UCHAR*)malloc(16);
+ ULONG ulRet = ReturnNetwareEncryptedPassword(pui2->usri3_user_id,
+ pui2->usri3_name,
+ pApp->m_bDomain,
+ (LPCTSTR)ucPW,
+ pNWPW);
+
+ if (ulRet != 0)
+ {
+ AfxMessageBox(IDS_NW_PW_ERROR);
+ goto failure;
+ }
+
+ try
+ {
+ uString.Length = NWENCRYPTEDPASSWORDLENGTH * sizeof(WCHAR);
+ uString.MaximumLength = NWENCRYPTEDPASSWORDLENGTH * sizeof(WCHAR);
+ uString.Buffer = (PWCHAR)pNWPW;
+
+ bRet = SetUserParam(uString, NWPASSWORD);
+ }
+ catch(...)
+ {
+ AfxMessageBox(IDS_NW_PW_ERROR);
+ goto failure;
+ }
+
+// grace logins - allowed
+ try
+ {
+ uString.Length = 2;
+ uString.MaximumLength = 2;
+ uString.Buffer = &pApp->m_sNWRemainingGraceLogins;
+ bRet = SetUserParam(uString, GRACELOGINREMAINING);
+
+ uString.Buffer = &pApp->m_sNWAllowedGraceLogins;
+ bRet = SetUserParam(uString, GRACELOGINALLOWED);
+ }
+ catch(...)
+ {
+ AfxMessageBox(IDS_NW_GRACELOGIN_ERROR);
+ goto failure;
+ }
+
+// concurrent connections
+ try
+ {
+ uString.Length = 2;
+ uString.MaximumLength = 2;
+ uString.Buffer = &pApp->m_sNWConcurrentConnections;
+
+ bRet = SetUserParam(uString, MAXCONNECTIONS);
+ }
+ catch(...)
+ {
+ AfxMessageBox(IDS_NW_CONCON_ERROR);
+ goto failure;
+ }
+
+// set allowed machines
+ try
+ {
+ TCHAR* pNWWks = pApp->m_csAllowedLoginFrom.GetBuffer(pApp->m_csAllowedLoginFrom.GetLength());
+ pApp->m_csAllowedLoginFrom.ReleaseBuffer();
+
+ if (SetNWWorkstations(pNWWks) != ERROR_SUCCESS)
+ {
+ AfxMessageBox(IDS_NOFP_WS);
+ goto failure;
+ }
+ }
+ catch(...)
+ {
+ AfxMessageBox(IDS_NOFP_WS);
+ goto failure;
+ }
+
+// all done?
+ FreeLibrary(hLib);
+ if (pNWPW != NULL) free(pNWPW);
+ }
+
+// RAS
+ HINSTANCE hLib;
+ if ((hLib = LoadLibrary(L"rassapi.dll")) != NULL && pApp->m_bRAS)
+ {
+ RASADMINGETUSERACCOUNTSERVER pRasAdminGetUserAccountServer = (RASADMINGETUSERACCOUNTSERVER)GetProcAddress(hLib, "RasAdminGetUserAccountServer");
+ RASADMINUSERSETINFO pRasAdminUserSetInfo = (RASADMINUSERSETINFO)GetProcAddress(hLib, "RasAdminUserSetInfo");
+
+ TCHAR pAccount[30];
+ TCHAR* pDomain = pApp->m_csDomain.GetBuffer(pApp->m_csDomain.GetLength());
+ pApp->m_csDomain.ReleaseBuffer();
+
+ DWORD dwErr = pRasAdminGetUserAccountServer(pDomain, pDomainServer, pAccount);
+
+ PRAS_USER_0 pBit = (PRAS_USER_0)malloc(sizeof(_RAS_USER_0) + 1);
+ZeroMemory(pBit, sizeof(RAS_USER_0));
+ pBit->bfPrivilege = 0;
+
+// this is always set since they selected RAS in the first place
+ pBit->bfPrivilege |= RASPRIV_DialinPrivilege;
+
+ switch(pApp->m_sCallBackType)
+ {
+ case 0:
+ pBit->bfPrivilege |= RASPRIV_NoCallback;
+ break;
+
+ case 1:
+ pBit->bfPrivilege |= RASPRIV_CallerSetCallback;
+ break;
+
+ case 2:
+ pBit->bfPrivilege |= RASPRIV_AdminSetCallback;
+ _tcscpy(pBit->szPhoneNumber, (LPCTSTR)pApp->m_csRasPhoneNumber);
+ break;
+ }
+
+ dwErr = pRasAdminUserSetInfo(pAccount, pui1->usri3_name, pBit);
+ if (dwErr != ERROR_SUCCESS)
+ {
+ AfxMessageBox(IDS_RAS_ERROR);
+DWORD dd = GetLastError();
+CString cs;
+cs.Format(L"getlasterror = %d, dwerr = %d", dd, dwErr);
+AfxMessageBox(cs);
+ goto failure;
+ }
+
+ FreeLibrary(hLib);
+ free(pBit);
+ }
+
+
+// exchange?
+ if (pApp->m_bExchange)
+ {
+// pApp->m_csExchangeServer = L"IRIS2";
+ // first create the script file
+ TCHAR lpPath[MAX_PATH];
+ UINT ui = GetTempFileName(L".", L"auw", 0, lpPath);
+ if (ui == 0)
+ goto failure;
+
+ HANDLE hFile = CreateFile(lpPath,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ goto failure;
+
+ TCHAR pHeader[] = L"OBJ-CLASS, Common-Name, Home-Server, Comment, Hide-from-address-book, Display-name\n\r";
+ DWORD dwLen = _tcslen(pHeader) * sizeof(TCHAR);
+ DWORD dwBytesWritten;
+ BOOL bVal = WriteFile(hFile,
+ pHeader,
+ dwLen,
+ &dwBytesWritten,
+ NULL);
+
+ if (!bVal)
+ goto failure;
+
+ // now write the user's info
+ CString csExchangeVal;
+ csExchangeVal.Format(L"MAILBOX, %s, %s, %s, 0, %s",
+ pApp->m_csUserName,
+ pApp->m_csExchangeServer,
+ pApp->m_csDescription,
+ pApp->m_csFullName);
+
+ bVal = WriteFile(hFile,
+ (LPCTSTR)csExchangeVal,
+ csExchangeVal.GetLength() * sizeof(TCHAR),
+ &dwBytesWritten,
+ NULL);
+
+ if (!bVal)
+ goto failure;
+
+ // batch import function
+ BIMPORT_PARMSW* pBImport = (BIMPORT_PARMSW*)malloc(sizeof(BIMPORT_PARMSW) * sizeof(TCHAR));
+ ZeroMemory(pBImport, sizeof(BIMPORT_PARMSW) * sizeof(TCHAR));
+
+ pBImport->dwDAPISignature = DAPI_SIGNATURE;
+ pBImport->dwFlags = DAPI_YES_TO_ALL | DAPI_SUPPRESS_PROGRESS |
+ DAPI_SUPPRESS_COMPLETION | DAPI_SUPPRESS_ARCHIVES;
+ pBImport->hwndParent = GetSafeHwnd();
+ pBImport->pszImportFile = lpPath; // path to filename
+ pBImport->uCodePage = DAPI_UNICODE_FILE; // UNICODE file
+ pBImport->pszDSAName = pApp->m_csExchangeServer.GetBuffer(pApp->m_csExchangeServer.GetLength()); // this is the exchange server we are adding to
+ pApp->m_csExchangeServer.ReleaseBuffer();
+ pBImport->pszBasePoint = NULL;
+ pBImport->pszContainer = L"Recipients";
+ pBImport->chColSep = DAPI_DEFAULT_DELIMW; // default column sep
+ pBImport->chQuote = DAPI_DEFAULT_QUOTEW; // default quote mark
+ pBImport->chMVSep = DAPI_DEFAULT_MV_SEPW; // multi value column sep
+ pBImport->pszNTDomain = pApp->m_csDomain.GetBuffer(pApp->m_csDomain.GetLength());// Domain to lookup accounts in
+ pApp->m_csDomain.ReleaseBuffer();
+ pBImport->pszCreateTemplate = NULL; // template user
+
+ HINSTANCE hExLib = LoadLibrary(L"dapi.dll");
+ if (hExLib == NULL)
+ goto failure;
+
+ BATCHIMPORT pBatchImport = (BATCHIMPORT)GetProcAddress(hExLib, "BatchImportW@4");
+ if (pBatchImport == NULL)
+ goto failure;
+
+ CloseHandle(hFile);// have to close the file before exch can see it
+ DWORD dw = pBatchImport(pBImport);
+
+// don't forget to delete the tmp file
+ FreeLibrary(hExLib);
+ DeleteFile(lpPath);
+ free(pBImport);
+
+ if (dw != ERROR_SUCCESS) goto failure;
+ }
+
+ if (pApp->m_csFullName != L"")
+ {
+ csTemp.LoadString(IDS_SUCCESS);
+ csSuccess.Format(csTemp, pApp->m_csFullName, pApp->m_csUserName);
+ }
+ else
+ {
+ csTemp.LoadString(IDS_SUCCESS2);
+ csSuccess.Format(csTemp, pApp->m_csUserName);
+ }
+
+ if (AfxMessageBox(csSuccess, MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
+ {
+ pApp->m_cps1.SetWizardButtons(PSWIZB_NEXT);
+ pApp->m_cps1.SetActivePage(0);
+ pApp->m_bPRSReset = TRUE;
+ pApp->m_bPWReset = TRUE;
+// pApp->m_bGReset = TRUE;
+ return FALSE;
+ }
+ else return TRUE;
+
+failure:
+ if (pApp->m_csFullName != L"")
+ {
+ csTemp.LoadString(IDS_BAD_USER_DATA);
+ csSuccess.Format(csTemp, pApp->m_csFullName, pApp->m_csUserName);
+ }
+ else
+ {
+ csTemp.LoadString(IDS_BAD_USER_DATA2);
+ csSuccess.Format(csTemp, pApp->m_csUserName);
+ }
+
+ csSuccess.Format(csTemp, pApp->m_csFullName, pApp->m_csUserName);
+ if (AfxMessageBox(csSuccess, MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
+ {
+ pApp->m_cps1.SetWizardButtons(PSWIZB_NEXT);
+ pApp->m_cps1.SetActivePage(0);
+ pApp->m_bPRSReset = TRUE;
+ pApp->m_bPWReset = TRUE;
+
+ return FALSE;
+ }
+ else return TRUE;
+
+}
+
+DWORD CFinish::dwPasswordFlags()
+{
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+ DWORD dwFlags = UF_SCRIPT;
+
+ if (pApp->m_bDisabled) dwFlags |= UF_ACCOUNTDISABLE;
+ if (!pApp->m_bChange_Password) dwFlags |= UF_PASSWD_CANT_CHANGE;
+ if (pApp->m_bPW_Never_Expires) dwFlags |= UF_DONT_EXPIRE_PASSWD;
+
+ return dwFlags;
+
+}
+
+BOOL CFinish::bAddLocalGroups(LPWSTR lpwGroupName)
+{
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+ TCHAR* pDomainServer = pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength());
+
+ LOCALGROUP_MEMBERS_INFO_3 localgroup_members;
+
+ localgroup_members.lgrmi3_domainandname = pApp->m_csUserName.GetBuffer(pApp->m_csUserName.GetLength());
+
+ DWORD err = NetLocalGroupAddMembers( (unsigned short*)pDomainServer, /* PDC name */
+ lpwGroupName, /* group name */
+ 3, /* passing in name */
+ (LPBYTE)&localgroup_members, /* Buffer */
+ 1 ); /* count passed in */
+
+ pApp->m_csUserName.ReleaseBuffer();
+ pApp->m_csServer.ReleaseBuffer();
+
+ if (err != 0) return FALSE;
+ return TRUE;
+}
+
+BOOL CFinish::bAddGlobalGroups(LPTSTR lpwGroupName)
+{
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+ TCHAR* pDomainServer = pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength());
+
+ DWORD dwErr = NetGroupAddUser((LPTSTR)pDomainServer,
+ lpwGroupName,
+ pApp->m_csUserName.GetBuffer(pApp->m_csUserName.GetLength()));
+
+ pApp->m_csUserName.ReleaseBuffer();
+ pApp->m_csServer.ReleaseBuffer();
+
+ if ((dwErr != 0) && (dwErr != 2236)) return FALSE;
+ return TRUE;
+}
+
+
+
+ULONG
+CFinish::ReturnNetwareEncryptedPassword(DWORD UserId,
+ LPWSTR pszUserName,
+ BOOL bDomain,
+ LPCTSTR clearTextPassword,
+ UCHAR* NetwareEncryptedPassword ) // 16 byte encrypted password
+{
+ char lsaSecret[20];
+ NTSTATUS status;
+ ULONG objectId;
+
+ HINSTANCE hLib = LoadLibrary(L"fpnwclnt.dll");
+ if (hLib == NULL) return 1;
+
+// if this is a server, modify the User ID:
+ if (bDomain) UserId |= 0x10000000;
+
+// get lsa key from GetNcpSecretKey
+ GETREMOTENCPSECRETKEY pGetRemoteNcpSecretKey = (GETREMOTENCPSECRETKEY)GetProcAddress(hLib, "GetRemoteNcpSecretKey");
+ if (pGetRemoteNcpSecretKey == NULL) return 1;
+
+ UNICODE_STRING usServer;
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+ usServer.Length = pApp->m_csServer.GetLength() * sizeof(WCHAR);
+ usServer.MaximumLength = pApp->m_csServer.GetLength() * sizeof(WCHAR);
+ usServer.Buffer = pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength());
+ pApp->m_csServer.ReleaseBuffer();
+
+ status = (*pGetRemoteNcpSecretKey)( &usServer, lsaSecret );
+ if (status != ERROR_SUCCESS) return 1;
+
+// Convert rid to object id
+ MAPRIDTOOBJECTID pMapRidToObjectId = (MAPRIDTOOBJECTID)GetProcAddress(hLib, "MapRidToObjectId");
+ if (pMapRidToObjectId == NULL) return 1;
+
+ objectId = (*pMapRidToObjectId)( UserId, pszUserName, bDomain, FALSE );
+
+// now get the password
+ RETURNNETWAREFORM pReturnNetwareForm = (RETURNNETWAREFORM)GetProcAddress(hLib, "ReturnNetwareForm");
+ if (pReturnNetwareForm == NULL) return 1;
+
+ try
+ {
+ status = (*pReturnNetwareForm)( lsaSecret,
+ objectId,
+ clearTextPassword,
+ NetwareEncryptedPassword);
+ }
+ catch(...)
+ {
+ FreeLibrary(hLib);
+ return 1L;
+ }
+
+ // clean up
+ FreeLibrary(hLib);
+
+ return 0L;
+
+}
+
+
+BOOL CFinish::SetUserParam(UNICODE_STRING uString, LPWSTR lpwProp)
+{
+// get existing prop value
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+ TCHAR* pUsername = pApp->m_csUserName.GetBuffer(pApp->m_csUserName.GetLength());
+ pApp->m_csUserName.ReleaseBuffer();
+
+ TCHAR* pServer = pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength());
+ pApp->m_csServer.ReleaseBuffer();
+
+ PUSER_INFO_3 pui2 = (PUSER_INFO_3)VirtualAlloc(NULL, sizeof(_USER_INFO_3), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+
+ NET_API_STATUS napi = NetUserGetInfo(pServer,
+ pUsername,
+ 3,
+ (LPBYTE*)&pui2);
+
+// set NW prop
+ HINSTANCE hLib = LoadLibrary(L"fpnwclnt.dll");
+ SETUSERPROPERTY pSetUserProperty = (SETUSERPROPERTY)GetProcAddress(hLib, "SetUserProperty");
+
+ LPWSTR lpNewProp = NULL;
+ BOOL bUpdate;
+
+ NTSTATUS status = (*pSetUserProperty)((LPWSTR)pui2->usri3_parms,
+ (LPWSTR)lpwProp,
+ uString,
+ USER_PROPERTY_TYPE_ITEM,
+ &lpNewProp,
+ &bUpdate);
+
+ if (status != ERROR_SUCCESS) return FALSE;
+
+// reset user prop
+ DWORD dwBuf;
+ if (bUpdate)
+ {
+ pui2->usri3_parms = lpNewProp;
+ napi = NetUserSetInfo(pServer,
+ pUsername,
+ 3,
+ (LPBYTE)pui2,
+ &dwBuf);
+
+ }
+
+ if (lpNewProp != NULL) LocalFree(lpNewProp);
+ VirtualFree(pui2, 0, MEM_RELEASE | MEM_DECOMMIT);
+ FreeLibrary(hLib);
+ return TRUE;
+
+}
+
+void CFinish::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CWizBaseDlg::OnShowWindow(bShow, nStatus);
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+ if (bShow)
+ {
+ pApp->m_cps1.SetWizardButtons(PSWIZB_BACK | PSWIZB_FINISH);
+
+ CString csTemp;
+ csTemp.LoadString(IDS_FINISH_CAPTION);
+
+ CString csTemp2;
+ csTemp2.Format(csTemp, pApp->m_csUserName);
+ m_csCaption = csTemp2;
+ UpdateData(FALSE);
+ }
+// else pApp->m_cps1.SetWizardButtons(PSWIZB_BACK | PSWIZB_NEXT);
+
+}
+
+/*******************************************************************
+
+ NAME: USER_NW::SetNWWorkstations
+
+ SYNOPSIS: Store NetWare allowed workstation addresses to UserParms
+ If pchNWWorkstations is NULL, this function will delete
+ "NWLgonFrom" field from UserParms.
+
+ EXIT:
+
+ HISTORY:
+ CongpaY 01-Oct-93 Created.
+
+********************************************************************/
+
+DWORD CFinish::SetNWWorkstations( const TCHAR * pchNWWorkstations)
+{
+ DWORD err = ERROR_SUCCESS;
+ UNICODE_STRING uniNWWorkstations;
+ CHAR * pchTemp = NULL;
+
+ if (pchNWWorkstations == NULL)
+ {
+ uniNWWorkstations.Buffer = NULL;
+ uniNWWorkstations.Length = 0;
+ uniNWWorkstations.MaximumLength = 0;
+ }
+ else
+ {
+ BOOL fDummy;
+ INT nStringLength = lstrlen(pchNWWorkstations) + 1;
+ pchTemp = (CHAR *) LocalAlloc (LPTR, nStringLength);
+
+ if ( pchTemp == NULL )
+ err = ERROR_NOT_ENOUGH_MEMORY;
+
+ if ( err == ERROR_SUCCESS &&
+ !WideCharToMultiByte (CP_ACP,
+ 0,
+ pchNWWorkstations,
+ nStringLength,
+ pchTemp,
+ nStringLength,
+ NULL,
+ &fDummy))
+ {
+ err = ::GetLastError();
+ }
+
+ if ( err == ERROR_SUCCESS )
+ {
+ uniNWWorkstations.Buffer = (WCHAR *) pchTemp;
+ uniNWWorkstations.Length = nStringLength;
+ uniNWWorkstations.MaximumLength = nStringLength;
+ }
+ }
+
+ if (!SetUserParam(uniNWWorkstations, NWLOGONFROM)) err = 1;
+ else err = ERROR_SUCCESS;
+
+ if (pchTemp != NULL)
+ {
+ LocalFree (pchTemp);
+ }
+
+ return err;
+}
+
+void CFinish::OnPaint()
+{
+ CPaintDC dc(this); // device context for painting
+
+ CTransBmp* pBitmap = new CTransBmp;
+ pBitmap->LoadBitmap(IDB_ENDFLAG);
+
+ pBitmap->DrawTrans(&dc, 0,0);
+ delete pBitmap;
+
+}
diff --git a/private/utils/wizards/addusrw/finish.h b/private/utils/wizards/addusrw/finish.h
new file mode 100644
index 000000000..5d712ca33
--- /dev/null
+++ b/private/utils/wizards/addusrw/finish.h
@@ -0,0 +1,81 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Finish.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+// Finish.h : header file
+//
+
+/////////////////////////////////////////////////////////////////////////////
+// CFinish dialog
+
+// these will have to be revised for NTBUILD
+typedef struct _UNICODE_STRING {
+ USHORT Length;
+ USHORT MaximumLength;
+#ifdef MIDL_PASS
+ [size_is(MaximumLength / 2), length_is((Length) / 2) ] USHORT * Buffer;
+#else // MIDL_PASS
+ PWSTR Buffer;
+#endif // MIDL_PASS
+} UNICODE_STRING;
+typedef UNICODE_STRING *PUNICODE_STRING;
+
+
+class CFinish : public CWizBaseDlg
+{
+ DECLARE_DYNCREATE(CFinish)
+
+// Construction
+public:
+ CFinish();
+ ~CFinish();
+ virtual BOOL OnWizardFinish();
+// Dialog Data
+ //{{AFX_DATA(CFinish)
+ enum { IDD = IDD_FINISH };
+ CString m_csCaption;
+ //}}AFX_DATA
+
+ DWORD dwPasswordFlags();
+ BOOL bAddLocalGroups(LPWSTR lpwGroupName);
+ BOOL bAddGlobalGroups(LPWSTR lpwGroupName);
+ LRESULT OnWizardBack();
+
+
+ ULONG ReturnNetwareEncryptedPassword(DWORD UserId,
+ LPWSTR pszUserName,
+ BOOL bDomain,
+ LPCTSTR clearTextPassword,
+ UCHAR* NetwareEncryptedPassword ); // 16 byte encrypted password
+
+ BOOL SetUserParam(UNICODE_STRING uString, LPWSTR lpwProp);
+ DWORD SetNWWorkstations( const TCHAR * pchNWWorkstations);
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CFinish)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CFinish)
+ virtual BOOL OnInitDialog();
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ afx_msg void OnPaint();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+};
diff --git a/private/utils/wizards/addusrw/fpinfo.cpp b/private/utils/wizards/addusrw/fpinfo.cpp
new file mode 100644
index 000000000..48324503e
--- /dev/null
+++ b/private/utils/wizards/addusrw/fpinfo.cpp
@@ -0,0 +1,179 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ FPInfo.cpp : implementation file
+
+ CPropertyPage support for User mgmt wizard
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+#include "stdafx.h"
+#include "speckle.h"
+#include "wizbased.h"
+#include "FPInfo.h"
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CFPInfo property page
+
+IMPLEMENT_DYNCREATE(CFPInfo, CWizBaseDlg)
+
+CFPInfo::CFPInfo() : CWizBaseDlg(CFPInfo::IDD)
+{
+ //{{AFX_DATA_INIT(CFPInfo)
+ m_nGraceLogins = 0;
+ m_nConcurrentConnections = 0;
+ m_csCaption = _T("");
+ m_sAllowedGraceLogins = 6;
+ m_sConcurrentConnections = 1;
+ //}}AFX_DATA_INIT
+}
+CFPInfo::~CFPInfo()
+{
+}
+
+void CFPInfo::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CFPInfo)
+ DDX_Control(pDX, IDC_CONCURRENT_CONNECTIONS_SPIN, m_sbConconSpin);
+ DDX_Control(pDX, IDC_GRACE_LOGIN_SPIN, m_sbGraceLogins);
+ DDX_Radio(pDX, IDC_GRACE_LOGIN_RADIO, m_nGraceLogins);
+ DDX_Radio(pDX, IDC_CONCURRENT_CONNECTIONS_RADIO1, m_nConcurrentConnections);
+ DDX_Text(pDX, IDC_STATIC1, m_csCaption);
+ DDX_Text(pDX, IDC_ALLOWED_GRACE_LOGINS_EDIT, m_sAllowedGraceLogins);
+ DDV_MinMaxUInt(pDX, m_sAllowedGraceLogins, 0, 200);
+ DDX_Text(pDX, IDC_CONCURRENT_CONNECTIONS_EDIT, m_sConcurrentConnections);
+ DDV_MinMaxUInt(pDX, m_sConcurrentConnections, 1, 1000);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CFPInfo, CWizBaseDlg)
+ //{{AFX_MSG_MAP(CFPInfo)
+ ON_BN_CLICKED(IDC_GRACE_LOGIN_RADIO, OnGraceLoginRadio)
+ ON_BN_CLICKED(IDC_GRACE_LOGIN_RADIO2, OnGraceLoginRadio2)
+ ON_BN_CLICKED(IDC_CONCURRENT_CONNECTIONS_RADIO1, OnConcurrentConnectionsRadio)
+ ON_BN_CLICKED(IDC_CONCURRENT_CONNECTIONS_RADIO2, OnConcurrentConnectionsRadio2)
+ ON_WM_SHOWWINDOW()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CFPInfo message handlers
+
+// Disable the contents of the group control
+void CFPInfo::OnGraceLoginRadio()
+{
+ m_nGraceLogins = 0;
+ GetDlgItem(IDC_ALLOWED_GRACE_LOGINS_EDIT)->EnableWindow(FALSE);
+ GetDlgItem(IDC_GRACE_LOGIN_SPIN)->EnableWindow(FALSE);
+
+}
+
+// Enable the contents of the group control
+void CFPInfo::OnGraceLoginRadio2()
+{
+ m_nGraceLogins = 1;
+ GetDlgItem(IDC_ALLOWED_GRACE_LOGINS_EDIT)->EnableWindow(TRUE);
+ GetDlgItem(IDC_GRACE_LOGIN_SPIN)->EnableWindow(TRUE);
+
+ m_sbGraceLogins.SetRange(0,200);
+
+}
+
+BOOL CFPInfo::OnInitDialog()
+{
+ CWizBaseDlg::OnInitDialog();
+
+// set group box defaults
+ GetDlgItem(IDC_ALLOWED_GRACE_LOGINS_EDIT)->EnableWindow(FALSE);
+ GetDlgItem(IDC_GRACE_LOGIN_SPIN)->EnableWindow(FALSE);
+
+ GetDlgItem(IDC_CONCURRENT_CONNECTIONS_EDIT)->EnableWindow(FALSE);
+ GetDlgItem(IDC_CONCURRENT_CONNECTIONS_SPIN)->EnableWindow(FALSE);
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+// disable
+void CFPInfo::OnConcurrentConnectionsRadio()
+{
+ GetDlgItem(IDC_CONCURRENT_CONNECTIONS_EDIT)->EnableWindow(FALSE);
+ GetDlgItem(IDC_CONCURRENT_CONNECTIONS_SPIN)->EnableWindow(FALSE);
+}
+
+// enable
+void CFPInfo::OnConcurrentConnectionsRadio2()
+{
+ GetDlgItem(IDC_CONCURRENT_CONNECTIONS_EDIT)->EnableWindow(TRUE);
+ GetDlgItem(IDC_CONCURRENT_CONNECTIONS_SPIN)->EnableWindow(TRUE);
+ m_sbConconSpin.SetRange(1, 1000);
+}
+
+LRESULT CFPInfo::OnWizardNext()
+{
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+ UpdateData(TRUE);
+
+ if (m_nGraceLogins != 0) // limited
+ {
+ pApp->m_sNWAllowedGraceLogins = m_sAllowedGraceLogins;
+ pApp->m_sNWRemainingGraceLogins = m_sAllowedGraceLogins;
+ }
+ else // unlimited
+ {
+ pApp->m_sNWAllowedGraceLogins = 0x6;
+ pApp->m_sNWRemainingGraceLogins = 0xff;
+ }
+
+ if (m_nConcurrentConnections == 0) pApp->m_sNWConcurrentConnections = 0xffff;
+ else pApp->m_sNWConcurrentConnections = m_sConcurrentConnections;
+
+ if (pApp->m_bExchange) return IDD_EXCHANGE_DIALOG;
+ else return IDD_RESTRICTIONS_DIALOG;
+
+}
+
+LRESULT CFPInfo::OnWizardBack()
+{
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+ if (pApp->m_bRAS) return IDD_RAS_PERM_DIALOG;
+ else if (pApp->m_bHomeDir) return IDD_HOMEDIR_DIALOG;
+ else if (pApp->m_bLoginScript) return IDD_LOGON_SCRIPT_DIALOG;
+ else if (pApp->m_bProfile) return IDD_PROFILE;
+ else return IDD_OPTIONS_DIALOG;
+
+}
+
+void CFPInfo::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CWizBaseDlg::OnShowWindow(bShow, nStatus);
+
+ if (bShow)
+ {
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+ CString csTemp;
+ csTemp.LoadString(IDS_FPNW_CAPTION);
+
+ CString csTemp2;
+ csTemp2.Format(csTemp, pApp->m_csUserName);
+ m_csCaption = csTemp2;
+ UpdateData(FALSE);
+ }
+
+}
diff --git a/private/utils/wizards/addusrw/fpinfo.h b/private/utils/wizards/addusrw/fpinfo.h
new file mode 100644
index 000000000..74ac16799
--- /dev/null
+++ b/private/utils/wizards/addusrw/fpinfo.h
@@ -0,0 +1,65 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ FPInfo.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CFPInfo dialog
+
+class CFPInfo : public CWizBaseDlg
+{
+ DECLARE_DYNCREATE(CFPInfo)
+
+// Construction
+public:
+ CFPInfo();
+ ~CFPInfo();
+
+// Dialog Data
+ //{{AFX_DATA(CFPInfo)
+ enum { IDD = IDD_FPNW_DLG };
+ CSpinButtonCtrl m_sbConconSpin;
+ CSpinButtonCtrl m_sbGraceLogins;
+ BOOL m_bExpireNWPassword;
+ int m_nGraceLogins;
+ int m_nConcurrentConnections;
+ CString m_csCaption;
+ UINT m_sAllowedGraceLogins;
+ UINT m_sConcurrentConnections;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CFPInfo)
+ public:
+ virtual LRESULT OnWizardNext();
+ virtual LRESULT OnWizardBack();
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CFPInfo)
+ afx_msg void OnGraceLoginRadio();
+ afx_msg void OnGraceLoginRadio2();
+ virtual BOOL OnInitDialog();
+ afx_msg void OnConcurrentConnectionsRadio();
+ afx_msg void OnConcurrentConnectionsRadio2();
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+};
diff --git a/private/utils/wizards/addusrw/fpnwcomm.h b/private/utils/wizards/addusrw/fpnwcomm.h
new file mode 100644
index 000000000..8c3509199
--- /dev/null
+++ b/private/utils/wizards/addusrw/fpnwcomm.h
@@ -0,0 +1,307 @@
+/*++
+
+Copyright (c) 1993-1995 Microsoft Corporation
+
+Module Name:
+
+ nw\inc\ncmcomm.h
+
+Abstract:
+
+ This module contains common constants and types for the NCP server.
+
+Author:
+
+ Shawn Walker (vswalk) 06-17-1993
+ Andy Herron (andyhe)
+
+Revision History:
+
+--*/
+
+#ifndef _NCPCOMM_
+#define _NCPCOMM_
+
+//
+// signature for pserver
+//
+#define NCP_PSERVER_SIGNATURE L"PS_"
+
+//
+// well known object IDs
+//
+#define NCP_WELL_KNOWN_SUPERVISOR_ID (ULONG) 0x00000001
+#define NCP_WELL_KNOWN_SUPERVISOR_ID_SWAPPED (ULONG) 0x01000000
+#define NCP_WELL_KNOWN_SUPERVISOR_ID_CHICAGO (ULONG) 0x00010000
+#define NCP_WELL_KNOWN_PSERVER_ID (ULONG) 0x00000002
+
+//
+// misc macros that are useful
+//
+#define SWAPWORD(w) ((WORD)((w & 0xFF) << 8)|(WORD)(w >> 8))
+#define SWAPLONG(l) MAKELONG(SWAPWORD(HIWORD(l)),SWAPWORD(LOWORD(l)))
+
+#define SWAP_OBJECT_ID(id) (id == NCP_WELL_KNOWN_SUPERVISOR_ID) ? \
+ NCP_WELL_KNOWN_SUPERVISOR_ID_SWAPPED : \
+ MAKELONG(LOWORD(id),SWAPWORD(HIWORD(id)))
+
+#define UNSWAP_OBJECT_ID(id) (id == NCP_WELL_KNOWN_SUPERVISOR_ID_SWAPPED || id == NCP_WELL_KNOWN_SUPERVISOR_ID_CHICAGO) ?\
+ NCP_WELL_KNOWN_SUPERVISOR_ID : \
+ MAKELONG(LOWORD(id),SWAPWORD(HIWORD(id)))
+
+
+//
+// misc masks/bits for Object ID munging
+//
+
+#define BINDLIB_ID_MASK 0xF0000000
+
+#define BINDLIB_NCP_SAM 0x00000000
+
+//
+// This bit is set when the server is running on a NTAS machine or
+// the object is from a trusted domain.
+//
+// !! Note that there are places where we check this bit to see if either
+// !! BINDLIB_REMOTE_DOMAIN_BIAS or BINDLIB_LOCAL_USER_BIAS is set.
+//
+
+#define BINDLIB_REMOTE_DOMAIN_BIAS 0x10000000
+
+//
+// If the client is from the builtin domain, this bit will be set. This
+// is opposed to the local domain, which is different.
+//
+
+#define BINDLIB_BUILTIN_BIAS 0x20000000
+
+//
+// If the client is from a trusted domain and the rid is from the
+// local domain and the client's rid is the same as the rid from the
+// sid, we will mark that the rid is the same as the local user's sid.
+//
+// !! Note... this is a value, not a flag. This will require special casing
+// !! everywhere but we can't spare any more bits.
+//
+
+#define BINDLIB_LOCAL_USER_BIAS 0x70000000
+
+//
+// User defined objects that is stored in the registry.
+//
+
+#define BINDLIB_NCP_USER_DEFINED 0x40000000
+
+//
+// Print Queues and Print Servers that is stored in the registry.
+// The bindery keeps a list of print queues in a link list so that
+// the bindery does not have to go look in the registry all the time.
+//
+
+#define BINDLIB_NCP_REGISTRY 0x80000000
+
+//
+// The SAP Agent uses these bits. The SAP Agent cannot go any higher
+// than the value below.
+//
+
+#define BINDLIB_NCP_SAP 0xC0000000
+#define BINDLIB_NCP_MAX_SAP 0xCFFFFFFF
+
+//
+// We have some reserved fields for unknown users that will go into the
+// following range....
+//
+
+#define NCP_UNKNOWN_USER 0xD0000000
+#define NCP_SAME_RID_AS_CLIENT_BUT_LOCAL 0xDFFFFFFF
+#define NCP_USER_IS_CONNECTED_BUT_REMOTE(connid) (0xD0000000 | (connid))
+#define NCP_WELL_KNOWN_RID(rid) (0xD1000000 | (rid))
+
+//
+// Chicago will use a range of object ids that start at the below value
+// and go to 0xFFFFFFFF. We should never see these on our server when
+// a chicago server is passing through to us.
+//
+
+#define BINDLIB_CHICAGO 0xE0000000
+
+//
+// This is used to remove the domain bias from a object id.
+//
+
+#define BINDLIB_MASK_OUT_DOMAIN_BIAS 0x70000000
+
+
+#define NCP_INITIAL_SEARCH (ULONG) 0xFFFFFFFF
+#define NCP_ANY_TARGET_SERVER (ULONG) 0xFFFFFFFF
+
+#define NCP_OBJECT_HAS_PROPERTIES (UCHAR) 0xFF
+#define NCP_OBJECT_HAS_NO_PROPERTIES (UCHAR) 0
+
+#define NCP_PROPERTY_HAS_VALUE (UCHAR) 0xFF
+#define NCP_PROPERTY_HAS_NO_VALUE (UCHAR) 0
+
+#define NCP_MORE_PROPERTY (UCHAR) 0xFF
+#define NCP_NO_MORE_PROPERTY (UCHAR) 0
+
+#define NCP_MORE_SEGMENTS (UCHAR) 0xFF
+#define NCP_NO_MORE_SEGMENTS (UCHAR) 0
+
+#define NCP_DO_REMOVE_REMAINING_SEGMENTS (UCHAR) 0
+#define NCP_DO_NOT_REMOVE_REMAINING_SEGMENTS (UCHAR) 0xFF
+
+
+/*++
+*******************************************************************
+ Maximum length for the Bindery
+*******************************************************************
+--*/
+
+#define NETWARE_OBJECTNAMELENGTH 47
+#define NETWARE_PROPERTYNAMELENGTH 16
+#define NETWARE_PROPERTYVALUELENGTH 128
+#define NETWARE_TIME_RESTRICTION_LENGTH 42
+
+#define NETWARE_PASSWORDLENGTH 128
+#define NCP_MAX_ENCRYPTED_PASSWORD_LENGTH 16
+
+#define NETWARE_MAX_OBJECT_IDS_IN_SET 32
+
+#define NETWARE_SERVERNAMELENGTH 48
+#define NETWARE_VOLUMENAMELENGTH 16
+#define NETWARE_MAX_PATH_LENGTH 255
+
+
+/*++
+*******************************************************************
+ Well known NetWare object types
+*******************************************************************
+--*/
+
+#define NCP_OT_WILD 0xFFFF
+#define NCP_OT_UNKNOWN 0x0000
+#define NCP_OT_USER 0x0001
+#define NCP_OT_USER_GROUP 0x0002
+#define NCP_OT_PRINT_QUEUE 0x0003
+#define NCP_OT_FILE_SERVER 0x0004
+#define NCP_OT_JOB_SERVER 0x0005
+#define NCP_OT_GATEWAY 0x0006
+#define NCP_OT_PRINT_SERVER 0x0007
+#define NCP_OT_ARCHIVE_QUEUE 0x0008
+#define NCP_OT_ARCHIVE_SEVER 0x0009
+#define NCP_OT_JOB_QUEUE 0x000A
+#define NCP_OT_ADMINISTRATION 0x000B
+#define NCP_OT_SNA_GATEWAY 0x0021
+#define NCP_OT_REMOTE_BRIDGE 0x0024
+#define NCP_OT_REMOTE_BRIDGE_SERVER 0x0026
+#define NCP_OT_ADVERTISING_PRINT_SERVER 0x0047
+
+
+/*++
+*******************************************************************
+ Bindery flags
+*******************************************************************
+--*/
+
+/** NetWare Bindery Flags **/
+
+#define NCP_STATIC 0x00 /* Property or Object exists until it
+ is deleted with Delete Property or
+ Object */
+#define NCP_DYNAMIC 0x01 /* Property or Object is deleted from
+ bindery when file server is started */
+#define NCP_ITEM 0x00 /* Values are defined and interpreted by
+ applications or by APIs */
+#define NCP_SET 0x02 /* Series of Object ID numbers, each 4
+ bytes long */
+
+/** NetWare Bindery Security Flags **/
+
+#define NCP_ANY_READ 0x00 /* Readable by anyone */
+#define NCP_LOGGED_READ 0x01 /* Must be logged in to read */
+#define NCP_OBJECT_READ 0x02 /* Readable by same object or super */
+#define NCP_BINDERY_READ 0x04 /* Readable only by the bindery */
+
+#define NCP_SUPER_READ NCP_LOGGED_READ | NCP_OBJECT_READ
+
+#define NCP_ALL_READ NCP_ANY_READ | NCP_LOGGED_READ | NCP_OBJECT_READ
+
+#define NCP_ANY_WRITE 0x00 /* Writeable by anyone */
+#define NCP_LOGGED_WRITE 0x10 /* Must be logged in to write */
+#define NCP_OBJECT_WRITE 0x20 /* Writeable by same object or super */
+#define NCP_BINDERY_WRITE 0x40 /* Writeable only by the bindery */
+
+#define NCP_SUPER_WRITE NCP_LOGGED_WRITE | NCP_OBJECT_WRITE
+
+#define NCP_ALL_WRITE NCP_ANY_WRITE | NCP_LOGGED_WRITE | NCP_OBJECT_WRITE
+
+// File Attributes
+
+#define NW_ATTRIBUTE_SHARABLE 0x80
+#define NW_ATTRIBUTE_ARCHIVE 0x20
+#define NW_ATTRIBUTE_DIRECTORY 0x10
+#define NW_ATTRIBUTE_EXECUTE_ONLY 0x08
+#define NW_ATTRIBUTE_SYSTEM 0x04
+#define NW_ATTRIBUTE_HIDDEN 0x02
+#define NW_ATTRIBUTE_READ_ONLY 0x01
+
+// Open Flags
+
+#define NW_OPEN_EXCLUSIVE 0x10
+#define NW_DENY_WRITE 0x08
+#define NW_DENY_READ 0x04
+#define NW_OPEN_FOR_WRITE 0x02
+#define NW_OPEN_FOR_READ 0x01
+
+//
+// Connection status flags
+//
+
+#define NCP_STATUS_BAD_CONNECTION 0x01
+#define NCP_STATUS_NO_CONNECTIONS 0x02
+#define NCP_STATUS_SERVER_DOWN 0x04
+#define NCP_STATUS_MSG_PENDING 0x08
+
+//
+// Special values for SmallWorld PDC object and property name
+//
+
+#define MS_WINNT_NAME "MS_WINNT"
+#define MS_SYNC_PDC_NAME "SYNCPDC"
+#define MS_WINNT_OBJ_TYPE 0x06BB
+
+//
+// User Property values (ie. User Parms stuff)
+//
+
+#define USER_PROPERTY_SIGNATURE L'P'
+
+#define NWPASSWORD L"NWPassword"
+#define OLDNWPASSWORD L"OldNWPassword"
+#define MAXCONNECTIONS L"MaxConnections"
+#define NWTIMEPASSWORDSET L"NWPasswordSet"
+#define SZTRUE L"TRUE"
+#define GRACELOGINALLOWED L"GraceLoginAllowed"
+#define GRACELOGINREMAINING L"GraceLoginRemaining"
+#define NWLOGONFROM L"NWLogonFrom"
+#define NWHOMEDIR L"NWHomeDir"
+#define NW_PRINT_SERVER_REF_COUNT L"PSRefCount"
+
+#define SUPERVISOR_USERID NCP_WELL_KNOWN_SUPERVISOR_ID
+#define SUPERVISOR_NAME_STRING L"Supervisor"
+#define SYSVOL_NAME_STRING L"SYS"
+#define NWENCRYPTEDPASSWORDLENGTH 8
+#define NO_LIMIT 0xffff
+
+#define DEFAULT_MAXCONNECTIONS NO_LIMIT
+#define DEFAULT_NWPASSWORDEXPIRED FALSE
+#define DEFAULT_GRACELOGINALLOWED 6
+#define DEFAULT_GRACELOGINREMAINING 6
+#define DEFAULT_NWLOGONFROM NULL
+#define DEFAULT_NWHOMEDIR NULL
+
+#define USER_PROPERTY_TYPE_ITEM 1
+#define USER_PROPERTY_TYPE_SET 2
+
+#endif /* _NCPCOMM_ */
diff --git a/private/utils/wizards/addusrw/ginfo.cpp b/private/utils/wizards/addusrw/ginfo.cpp
new file mode 100644
index 000000000..bc9b3d9e5
--- /dev/null
+++ b/private/utils/wizards/addusrw/ginfo.cpp
@@ -0,0 +1,339 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ ginfo.cpp : implementation file
+
+ CPropertyPage support for User mgmt wizard
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+#include "stdafx.h"
+#include "Speckle.h"
+#include "userlist.h"
+#include "wizbased.h"
+#include "ginfo.h"
+
+#include <lmcons.h>
+#include <lmapibuf.h>
+#include <lmaccess.h>
+
+#ifdef _DEBUG
+//#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CGroupInfo property page
+
+IMPLEMENT_DYNCREATE(CGroupInfo, CWizBaseDlg)
+
+CGroupInfo::CGroupInfo() : CWizBaseDlg(CGroupInfo::IDD)
+{
+ //{{AFX_DATA_INIT(CGroupInfo)
+ m_csCaption = _T("");
+ //}}AFX_DATA_INIT
+}
+
+CGroupInfo::~CGroupInfo()
+{
+}
+
+void CGroupInfo::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CGroupInfo)
+ DDX_Control(pDX, IDC_GROUP_MEMBER_LIST, m_lbSelectedGroups);
+ DDX_Control(pDX, IDC_GROUP_AVAILABLE_LIST, m_lbAvailableGroups);
+ DDX_Text(pDX, IDC_STATIC1, m_csCaption);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CGroupInfo, CWizBaseDlg)
+ //{{AFX_MSG_MAP(CGroupInfo)
+ ON_BN_CLICKED(IDC_ADD_BUTTON, OnAddButton)
+ ON_BN_CLICKED(IDC_REMOVE_BUTTON, OnRemoveButton)
+ ON_LBN_SETFOCUS(IDC_GROUP_AVAILABLE_LIST, OnSetfocusGroupAvailableList)
+ ON_LBN_SETFOCUS(IDC_GROUP_MEMBER_LIST, OnSetfocusGroupMemberList)
+ ON_LBN_SELCHANGE(IDC_GROUP_MEMBER_LIST, OnSelchangeGroupMemberList)
+ ON_WM_SHOWWINDOW()
+ ON_LBN_DBLCLK(IDC_GROUP_AVAILABLE_LIST, OnDblclkGroupAvailableList)
+ ON_LBN_DBLCLK(IDC_GROUP_MEMBER_LIST, OnDblclkGroupMemberList)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CGroupInfo message handlers
+
+BOOL CGroupInfo::OnInitDialog()
+{
+ CWizBaseDlg::OnInitDialog();
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+void CGroupInfo::OnAddButton()
+{
+ UpdateData(TRUE);
+ USHORT usSel = m_lbAvailableGroups.GetCurSel();
+ if (usSel == LB_ERR)
+ {
+ GetDlgItem(IDC_ADD_BUTTON)->EnableWindow(FALSE);
+ GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(TRUE);
+ m_lbSelectedGroups.SetCurSel(0);
+ return;
+ }
+
+ CString csSel;
+ m_lbAvailableGroups.GetText(usSel, csSel);
+ USHORT usBmp = m_lbAvailableGroups.GetBitmapID(usSel);
+ m_lbSelectedGroups.AddString(csSel, usBmp);
+ m_lbAvailableGroups.DeleteString(usSel);
+
+// anybody left?
+ if (m_lbAvailableGroups.GetCount() != 0)
+ m_lbAvailableGroups.SetCurSel(0);
+
+ else
+ {
+ m_lbSelectedGroups.SetCurSel(0);
+ GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(TRUE);
+ GetDlgItem(IDC_ADD_BUTTON)->EnableWindow(FALSE);
+ m_lbAvailableGroups.SetHorizontalExtent(0);
+ }
+
+
+}
+
+void CGroupInfo::OnRemoveButton()
+{
+ UpdateData(TRUE);
+ USHORT usSel = m_lbSelectedGroups.GetCurSel();
+ if (usSel == 65535)
+ {
+ GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(FALSE);
+ GetDlgItem(IDC_ADD_BUTTON)->EnableWindow(TRUE);
+ m_lbAvailableGroups.SetCurSel(0);
+ return;
+ }
+
+ CString csSel;
+ m_lbSelectedGroups.GetText(usSel, csSel);
+
+ USHORT usBmp = m_lbSelectedGroups.GetBitmapID(usSel);
+ m_lbAvailableGroups.AddString(csSel, usBmp);
+ m_lbSelectedGroups.DeleteString(usSel);
+
+// anybody left?
+ if (m_lbSelectedGroups.GetCount() != 0)
+ m_lbSelectedGroups.SetCurSel(0);
+
+ else
+ {
+ m_lbAvailableGroups.SetCurSel(0);
+ GetDlgItem(IDC_ADD_BUTTON)->EnableWindow(TRUE);
+ GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(FALSE);
+ m_lbSelectedGroups.SetHorizontalExtent(0);
+ }
+}
+
+LRESULT CGroupInfo::OnWizardBack()
+{
+ return CPropertyPage::OnWizardBack();
+}
+
+LRESULT CGroupInfo::OnWizardNext()
+{
+ UpdateData(TRUE);
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+// add selected groups to list
+ pApp->m_csaSelectedLocalGroups.RemoveAll();
+ pApp->m_csaSelectedGlobalGroups.RemoveAll();
+ short sGroupCount = m_lbSelectedGroups.GetCount();
+ short sCount;
+ CString csVal;
+ for (sCount = 0; sCount < sGroupCount; sCount++)
+ {
+ USHORT usBmp = m_lbSelectedGroups.GetBitmapID(sCount);
+ m_lbSelectedGroups.GetText(sCount, csVal);
+
+ if (usBmp == 3) pApp->m_csaSelectedLocalGroups.Add(csVal);
+ else if (usBmp == 1) pApp->m_csaSelectedGlobalGroups.Add(csVal);
+ }
+
+ pApp->m_cps1.SetWizardButtons(PSWIZB_NEXT | PSWIZB_BACK);
+
+ return CPropertyPage::OnWizardNext();
+}
+
+void CGroupInfo::OnSetfocusGroupAvailableList()
+{
+ m_lbSelectedGroups.SetCurSel(-1);
+ GetDlgItem(IDC_ADD_BUTTON)->EnableWindow(TRUE);
+ GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(FALSE);
+
+}
+
+void CGroupInfo::OnSetfocusGroupMemberList()
+{
+ UpdateData(TRUE);
+ m_lbAvailableGroups.SetCurSel(-1);
+ GetDlgItem(IDC_ADD_BUTTON)->EnableWindow(FALSE);
+ GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(TRUE);
+
+}
+
+void CGroupInfo::OnSelchangeGroupMemberList()
+{
+ UpdateData(TRUE);
+}
+
+void CGroupInfo::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CWizBaseDlg::OnShowWindow(bShow, nStatus);
+
+ if (!bShow) return;
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+ if (!pApp->m_bGReset) return;
+ pApp->m_bGReset = FALSE;
+ m_lbAvailableGroups.ResetContent();
+ m_lbSelectedGroups.ResetContent();
+
+ CWaitCursor wait;
+
+ DWORD dwEntriesRead = 0;
+ DWORD dwTotalEntries = 0;
+ DWORD dwResumeHandle = 0;
+
+ NET_API_STATUS nApi;
+ unsigned long sIndex;
+
+ TCHAR* pServer = pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength());
+ pApp->m_csServer.ReleaseBuffer();
+
+// if this is on a domain, check for global groups
+ if (pApp->m_bDomain)
+ {
+ PGROUP_INFO_1 pInfo;
+
+ do
+ {
+ nApi = NetGroupEnum(pServer,
+ (DWORD)1,
+ (PBYTE*)&pInfo,
+ (DWORD)5000,
+ &dwEntriesRead,
+ &dwTotalEntries,
+ &dwResumeHandle);
+
+ for (sIndex = 0; sIndex < dwEntriesRead; sIndex++)
+ {
+ TCHAR sTemp[50];
+
+ swprintf(sTemp, TEXT("%s"), pInfo[sIndex].grpi1_name);
+ m_lbAvailableGroups.AddString(1, sTemp);
+ }
+
+ NetApiBufferFree(pInfo);
+ } while (dwResumeHandle != 0);
+
+// m_lbSelectedGroups.AddString(1, TEXT("Domain Users"));
+
+ UpdateData(FALSE);
+ }
+
+ PLOCALGROUP_INFO_1 pLocalInfo;
+ dwResumeHandle = 0;
+ do
+ {
+ nApi = NetLocalGroupEnum(pServer,
+ (DWORD)1,
+ (PBYTE*)&pLocalInfo,
+ (DWORD)5000,
+ &dwEntriesRead,
+ &dwTotalEntries,
+ &dwResumeHandle);
+
+ for (sIndex = 0; sIndex < dwEntriesRead; sIndex++)
+ {
+ TCHAR sTemp[50];
+
+ swprintf(sTemp, TEXT("%s"), pLocalInfo[sIndex].lgrpi1_name);
+ m_lbAvailableGroups.AddString(3, sTemp);
+ }
+
+ NetApiBufferFree(pLocalInfo);
+ } while (dwResumeHandle != 0);
+
+ m_lbAvailableGroups.SetCurSel(0);
+
+// set caption text
+ CString csTemp;
+ csTemp.LoadString(IDS_GROUP_CAPTION);
+
+ CString csTemp2;
+ csTemp2.Format(csTemp, pApp->m_csUserName);
+ m_csCaption = csTemp2;
+ UpdateData(FALSE);
+
+}
+
+void CGroupInfo::OnDblclkGroupAvailableList()
+{
+ UpdateData(TRUE);
+ USHORT usSel = m_lbAvailableGroups.GetCurSel();
+ CString csSel;
+ m_lbAvailableGroups.GetText(usSel, csSel);
+ USHORT usBmp = m_lbAvailableGroups.GetBitmapID(usSel);
+ m_lbSelectedGroups.AddString(csSel, usBmp);
+ m_lbAvailableGroups.DeleteString(usSel);
+
+// anybody left?
+ if (m_lbAvailableGroups.GetCount() != 0)
+ m_lbAvailableGroups.SetCurSel(0);
+
+ else
+ {
+ m_lbSelectedGroups.SetCurSel(0);
+ GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(TRUE);
+ GetDlgItem(IDC_ADD_BUTTON)->EnableWindow(FALSE);
+ m_lbAvailableGroups.SetHorizontalExtent(0);
+ }
+
+}
+
+void CGroupInfo::OnDblclkGroupMemberList()
+{
+ UpdateData(TRUE);
+ USHORT usSel = m_lbSelectedGroups.GetCurSel();
+ CString csSel;
+ m_lbSelectedGroups.GetText(usSel, csSel);
+
+ USHORT usBmp = m_lbSelectedGroups.GetBitmapID(usSel);
+ m_lbAvailableGroups.AddString(csSel, usBmp);
+ m_lbSelectedGroups.DeleteString(usSel);
+
+// anybody left?
+ if (m_lbSelectedGroups.GetCount() != 0)
+ m_lbSelectedGroups.SetCurSel(0);
+
+ else
+ {
+ m_lbAvailableGroups.SetCurSel(0);
+ GetDlgItem(IDC_ADD_BUTTON)->EnableWindow(TRUE);
+ GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(FALSE);
+ m_lbSelectedGroups.SetHorizontalExtent(0);
+ }
+
+}
diff --git a/private/utils/wizards/addusrw/ginfo.h b/private/utils/wizards/addusrw/ginfo.h
new file mode 100644
index 000000000..76b6ac5d1
--- /dev/null
+++ b/private/utils/wizards/addusrw/ginfo.h
@@ -0,0 +1,65 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ GInfo.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CGroupInfo dialog
+
+class CGroupInfo : public CWizBaseDlg
+{
+ DECLARE_DYNCREATE(CGroupInfo)
+
+// Construction
+public:
+ CGroupInfo();
+ ~CGroupInfo();
+
+// Dialog Data
+ //{{AFX_DATA(CGroupInfo)
+ enum { IDD = IDD_GROUP_INFO };
+ CUserList m_lbSelectedGroups;
+ CUserList m_lbAvailableGroups;
+ CString m_csCaption;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CGroupInfo)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+ public:
+ virtual LRESULT OnWizardBack();
+ virtual LRESULT OnWizardNext();
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CGroupInfo)
+ virtual BOOL OnInitDialog();
+ afx_msg void OnAddButton();
+ afx_msg void OnRemoveButton();
+ afx_msg void OnSetfocusGroupAvailableList();
+ afx_msg void OnSetfocusGroupMemberList();
+ afx_msg void OnSelchangeGroupMemberList();
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ afx_msg void OnDblclkGroupAvailableList();
+ afx_msg void OnDblclkGroupMemberList();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+private:
+
+};
diff --git a/private/utils/wizards/addusrw/homedir.cpp b/private/utils/wizards/addusrw/homedir.cpp
new file mode 100644
index 000000000..109be9def
--- /dev/null
+++ b/private/utils/wizards/addusrw/homedir.cpp
@@ -0,0 +1,245 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ HomeDir.cpp : implementation file
+
+ CPropertyPage support for User mgmt wizard
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+#include "stdafx.h"
+#include "speckle.h"
+#include "wizbased.h"
+#include "HomeDir.h"
+
+#ifdef _DEBUG
+//#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CHomeDir property page
+
+IMPLEMENT_DYNCREATE(CHomeDir, CWizBaseDlg)
+
+CHomeDir::CHomeDir() : CWizBaseDlg(CHomeDir::IDD)
+{
+ //{{AFX_DATA_INIT(CHomeDir)
+ m_csHome_dir_drive = _T("");
+ m_csRemotePath = _T("");
+ m_rbPathLocale = 0;
+ m_csCaption = _T("");
+ //}}AFX_DATA_INIT
+}
+
+CHomeDir::~CHomeDir()
+{
+}
+
+void CHomeDir::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CHomeDir)
+ DDX_Control(pDX, IDC_DRIVE_LETTER, m_cbDriveLetter);
+ DDX_CBString(pDX, IDC_DRIVE_LETTER, m_csHome_dir_drive);
+ DDX_Text(pDX, IDC_REMOTE_PATH, m_csRemotePath);
+ DDX_Radio(pDX, IDC_LOCAL_PATH_BUTTON, m_rbPathLocale);
+ DDX_Text(pDX, IDC_STATIC1, m_csCaption);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CHomeDir, CWizBaseDlg)
+ //{{AFX_MSG_MAP(CHomeDir)
+ ON_WM_SHOWWINDOW()
+ ON_BN_CLICKED(IDC_LOCAL_PATH_BUTTON, OnLocalPathButton)
+ ON_BN_CLICKED(IDC_REMOTE_PATH_BUTTON, OnRemotePathButton)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CHomeDir message handlers
+LRESULT CHomeDir::OnWizardNext()
+{
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+ UpdateData(TRUE);
+ if (m_rbPathLocale == 0) // local
+ {
+ pApp->m_csHomeDir = L""; // leave this empty per JonN and spec
+ pApp->m_csHome_dir_drive = "";
+ }
+ else // remote
+ {
+ if (m_csRemotePath.Left(2) != L"\\\\")
+ {
+ AfxMessageBox(IDS_INVALID_PATH);
+ GetDlgItem(IDC_REMOTE_PATH)->SetFocus();
+ return -1;
+ }
+
+ if (m_csHome_dir_drive == L"")
+ {
+ AfxMessageBox(IDS_NO_HOMEDIR_DRIVE_LETTER);
+ GetDlgItem(IDC_DRIVE_LETTER)->SetFocus();
+ return -1;
+ }
+
+ CWaitCursor wait;
+// make sure directory exists
+ if (CreateFile((const TCHAR*)m_csRemotePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL) == INVALID_HANDLE_VALUE)
+ {
+ DWORD dwErr = GetLastError();
+ if (dwErr == 5) // access denied
+ {
+ AfxMessageBox(IDS_NO_DIR_PERMISSION, MB_ICONSTOP);
+ return -1;
+ }
+
+// store the current dir so it can be restored
+ CString csCurDir;
+ GetCurrentDirectory(256, csCurDir.GetBufferSetLength(256));
+ csCurDir.ReleaseBuffer();
+
+ CString csMessage;
+ AfxFormatString1(csMessage, IDS_INVALID_DIRECTORY_NAME, m_csRemotePath);
+ if (AfxMessageBox(csMessage, MB_YESNO) != IDYES) return -1;
+ if (!CreateNewDirectory((const TCHAR*)m_csRemotePath))
+ {
+ if (AfxMessageBox(IDS_CANT_CREATE_DIRECTORY, MB_YESNO) != IDYES) return -1;
+ }
+ SetCurrentDirectory((LPCTSTR)csCurDir);
+ }
+
+ pApp->m_csHomeDir = m_csRemotePath;
+ GetDlgItem(IDC_DRIVE_LETTER)->GetWindowText(pApp->m_csHome_dir_drive);
+ pApp->m_csHome_dir_drive = pApp->m_csHome_dir_drive.Left(2); // trim off trailing blank
+ pApp->m_csHome_dir_drive.MakeUpper();
+ }
+
+ if (pApp->m_bRAS) return IDD_RAS_PERM_DIALOG;
+ else if (pApp->m_bNW) return IDD_FPNW_DLG;
+ else if (pApp->m_bExchange) return IDD_EXCHANGE_DIALOG;
+ else return IDD_RESTRICTIONS_DIALOG;
+
+}
+
+BOOL CHomeDir::CreateNewDirectory(const TCHAR* m_csDirectoryName)
+{
+// first remove the \\server\share info and CD to it
+ CString csDir = m_csDirectoryName;
+ csDir = csDir.Right(csDir.GetLength() - 2);
+ CString csServer = csDir.Left(csDir.Find(L"\\"));
+ csDir = csDir.Right((csDir.GetLength() - csServer.GetLength()) - 1);
+ CString csShare = csDir.Left(csDir.Find(L"\\"));
+ csDir = csDir.Right((csDir.GetLength() - csShare.GetLength()) - 1);
+
+ CString csPath;
+ csPath.Format(L"\\\\%s\\%s", csServer, csShare);
+ if (!SetCurrentDirectory(csPath)) return FALSE;
+
+// parse out the individual path names and cd / md them
+ TCHAR* pDirectory = new TCHAR[_tcslen(csDir) * sizeof(TCHAR)];
+ _tcscpy(pDirectory, csDir);
+ TCHAR* ppDir = pDirectory;
+
+ TCHAR* pDir;
+ pDir = _tcstok(pDirectory, L"\\");
+
+ while (pDir != NULL)
+ {
+ if (!SetCurrentDirectory(pDir))
+ {
+ CreateDirectory(pDir, NULL);
+ if (!SetCurrentDirectory(pDir))
+ {
+ delete ppDir;
+ return FALSE;
+ }
+ }
+ pDir = _tcstok(NULL, L"\\");
+ }
+
+ delete ppDir;
+
+ TCHAR pCurDir[256];
+ GetCurrentDirectory(256, pCurDir);
+ CString csNewDir, csTemp;
+ csTemp.LoadString(IDS_NEW_DIR_CREATED);
+ csNewDir.Format(csTemp, pCurDir);
+ AfxMessageBox(csNewDir);
+ return TRUE;
+}
+
+
+LRESULT CHomeDir::OnWizardBack()
+{
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+ if (pApp->m_bLoginScript) return IDD_LOGON_SCRIPT_DIALOG;
+ else if (pApp->m_bProfile) return IDD_PROFILE;
+ else return IDD_OPTIONS_DIALOG;
+
+}
+
+BOOL CHomeDir::OnInitDialog()
+{
+ CWizBaseDlg::OnInitDialog();
+
+// m_csLocalPath = "c:\\users\\default";
+
+// create list of available drives
+ int drive;
+ TCHAR tDrive[3];
+
+ for( drive = 3; drive <= 26; drive++ )
+ {
+ swprintf(tDrive, L"%c: ", drive + 'A' - 1 );
+ m_cbDriveLetter.AddString(tDrive);
+ }
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+void CHomeDir::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CWizBaseDlg::OnShowWindow(bShow, nStatus);
+
+ if (bShow)
+ {
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+ CString csTemp;
+ csTemp.LoadString(IDS_HOMEDIR_CAPTION);
+
+ CString csTemp2;
+ csTemp2.Format(csTemp, pApp->m_csUserName);
+ m_csCaption = csTemp2;
+ UpdateData(FALSE);
+ }
+
+
+}
+
+void CHomeDir::OnLocalPathButton()
+{
+ GetDlgItem(IDC_DRIVE_LETTER)->EnableWindow(FALSE);
+ GetDlgItem(IDC_REMOTE_PATH)->EnableWindow(FALSE);
+
+}
+
+void CHomeDir::OnRemotePathButton()
+{
+ GetDlgItem(IDC_DRIVE_LETTER)->EnableWindow(TRUE);
+ GetDlgItem(IDC_REMOTE_PATH)->EnableWindow(TRUE);
+
+}
diff --git a/private/utils/wizards/addusrw/homedir.h b/private/utils/wizards/addusrw/homedir.h
new file mode 100644
index 000000000..c3b603f02
--- /dev/null
+++ b/private/utils/wizards/addusrw/homedir.h
@@ -0,0 +1,61 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ HomeDir.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CHomeDir dialog
+
+class CHomeDir : public CWizBaseDlg
+{
+ DECLARE_DYNCREATE(CHomeDir)
+
+// Construction
+public:
+ CHomeDir();
+ ~CHomeDir();
+
+// Dialog Data
+ //{{AFX_DATA(CHomeDir)
+ enum { IDD = IDD_HOMEDIR_DIALOG };
+ CComboBox m_cbDriveLetter;
+ CString m_csHome_dir_drive;
+ CString m_csRemotePath;
+ int m_rbPathLocale;
+ CString m_csCaption;
+ //}}AFX_DATA
+
+ BOOL CreateNewDirectory(const TCHAR* m_csDirectoryName);
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CHomeDir)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+ LRESULT OnWizardBack();
+ LRESULT OnWizardNext();
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CHomeDir)
+ virtual BOOL OnInitDialog();
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ afx_msg void OnLocalPathButton();
+ afx_msg void OnRemotePathButton();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+};
diff --git a/private/utils/wizards/addusrw/hours.cpp b/private/utils/wizards/addusrw/hours.cpp
new file mode 100644
index 000000000..d2e723d3b
--- /dev/null
+++ b/private/utils/wizards/addusrw/hours.cpp
@@ -0,0 +1,165 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Hours.cpp : implementation file
+
+ CPropertyPage support for User mgmt wizard
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+#include "stdafx.h"
+#include "Speckle.h"
+#include "wizbased.h"
+#include "Timelist.h"
+#include "Hours.h"
+#include "hours1.h"
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CHoursDlg property page
+
+IMPLEMENT_DYNCREATE(CHoursDlg, CWizBaseDlg)
+
+CHoursDlg::CHoursDlg() : CWizBaseDlg(CHoursDlg::IDD)
+{
+ //{{AFX_DATA_INIT(CHoursDlg)
+ //}}AFX_DATA_INIT
+
+ m_swDisAllowed.bWhich = FALSE;
+ m_swAllowed.bWhich = TRUE;
+
+}
+
+CHoursDlg::~CHoursDlg()
+{
+}
+
+void CHoursDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CHoursDlg)
+ DDX_Control(pDX, IDC_STATIC_DISALLOWEDTIMES, m_swDisAllowed);
+ DDX_Control(pDX, IDC_STATIC_ALLOWEDTIMES, m_swAllowed);
+ DDX_Control(pDX, IDC_HOURSCTRL1, m_ccHours);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CHoursDlg, CWizBaseDlg)
+ //{{AFX_MSG_MAP(CHoursDlg)
+ ON_WM_SHOWWINDOW()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CHoursDlg message handlers
+
+BOOL CHoursDlg::OnInitDialog()
+{
+ CWizBaseDlg::OnInitDialog();
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+LRESULT CHoursDlg::OnWizardNext()
+{
+ UpdateData(TRUE);
+
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+// build a SAFEARRAY to receive data from the control
+ VARIANT vaResult;
+ VariantInit(&vaResult);
+
+ vaResult.vt = VT_ARRAY | VT_UI1;
+
+ SAFEARRAYBOUND sab[1];
+ sab[0].cElements = 21;
+ sab[0].lLbound = 0;
+
+ vaResult.parray = SafeArrayCreate(VT_UI1, 1, sab);
+
+ void* vRet;
+ BYTE* bRet;
+
+// get the data from the control
+ vaResult = m_ccHours.GetDateData();
+
+ SafeArrayAccessData(vaResult.parray, &vRet);
+
+ USHORT sCount = 0;
+ bRet = (BYTE*)vRet;
+ while (sCount < 21)
+ {
+ memcpy(&pApp->m_pHours[sCount], bRet + (sCount * sizeof(BYTE)), sizeof(BYTE));
+ sCount++;
+ }
+
+ if (pApp->m_bWorkstation) return IDD_LOGONTO_DLG;
+ else if (pApp->m_bNW) return IDD_NWLOGON_DIALOG;
+ else return IDD_FINISH;
+
+}
+
+LRESULT CHoursDlg::OnWizardBack()
+{
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+ if (pApp->m_bExpiration) return IDD_ACCOUNT_EXP_DIALOG;
+ return IDD_RESTRICTIONS_DIALOG;
+
+}
+
+void CHoursDlg::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CWizBaseDlg::OnShowWindow(bShow, nStatus);
+ if (bShow)
+ {
+ m_ccHours.SetCrPermitColor(GetSysColor(COLOR_ACTIVECAPTION));
+ m_ccHours.SetCrDenyColor(GetSysColor(COLOR_CAPTIONTEXT));
+ }
+
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CSWnd
+
+CSWnd::CSWnd()
+{
+}
+
+CSWnd::~CSWnd()
+{
+}
+
+
+BEGIN_MESSAGE_MAP(CSWnd, CStatic)
+ //{{AFX_MSG_MAP(CSWnd)
+ ON_WM_PAINT()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CSWnd message handlers
+
+void CSWnd::OnPaint()
+{
+ CPaintDC dc(this); // device context for painting
+
+ if (bWhich) dc.FillRect(&dc.m_ps.rcPaint, CBrush::FromHandle(CreateSolidBrush(GetSysColor(COLOR_ACTIVECAPTION))));
+ else dc.FillRect(&dc.m_ps.rcPaint, CBrush::FromHandle(CreateSolidBrush(GetSysColor(COLOR_CAPTIONTEXT))));
+
+ // Do not call CStatic::OnPaint() for painting messages
+}
+
diff --git a/private/utils/wizards/addusrw/hours.h b/private/utils/wizards/addusrw/hours.h
new file mode 100644
index 000000000..178510f03
--- /dev/null
+++ b/private/utils/wizards/addusrw/hours.h
@@ -0,0 +1,93 @@
+//{{AFX_INCLUDES()
+#include "hours1.h"
+//}}AFX_INCLUDES
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Hours.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+//
+/////////////////////////////////////////////////////////////////////////////
+// CSWnd window
+
+class CSWnd : public CStatic
+{
+// Construction
+public:
+ CSWnd();
+ BOOL bWhich;
+// Attributes
+public:
+
+// Operations
+public:
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CSWnd)
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CSWnd();
+
+ // Generated message map functions
+protected:
+ //{{AFX_MSG(CSWnd)
+ afx_msg void OnPaint();
+ //}}AFX_MSG
+
+ DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+/////////////////////////////////////////////////////////////////////////////
+// CHoursDlg dialog
+
+class CHoursDlg : public CWizBaseDlg
+{
+ DECLARE_DYNCREATE(CHoursDlg)
+
+// Construction
+public:
+ CHoursDlg();
+ ~CHoursDlg();
+
+// Dialog Data
+ //{{AFX_DATA(CHoursDlg)
+ enum { IDD = IDD_HOURS_DLG };
+ CSWnd m_swDisAllowed;
+ CSWnd m_swAllowed;
+ CHours m_ccHours;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CHoursDlg)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CHoursDlg)
+ virtual BOOL OnInitDialog();
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+ LRESULT OnWizardNext();
+ LRESULT OnWizardBack();
+
+};
diff --git a/private/utils/wizards/addusrw/hours1.cpp b/private/utils/wizards/addusrw/hours1.cpp
new file mode 100644
index 000000000..9d4445ad4
--- /dev/null
+++ b/private/utils/wizards/addusrw/hours1.cpp
@@ -0,0 +1,55 @@
+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++
+
+// NOTE: Do not modify the contents of this file. If this class is regenerated by
+// Microsoft Visual C++, your modifications will be overwritten.
+
+
+#include "stdafx.h"
+#include "hours1.h"
+
+/////////////////////////////////////////////////////////////////////////////
+// CHours
+
+IMPLEMENT_DYNCREATE(CHours, CWnd)
+
+/////////////////////////////////////////////////////////////////////////////
+// CHours properties
+
+unsigned long CHours::GetCrPermitColor()
+{
+ unsigned long result;
+ GetProperty(0x1, VT_I4, (void*)&result);
+ return result;
+}
+
+void CHours::SetCrPermitColor(unsigned long propVal)
+{
+ SetProperty(0x1, VT_I4, propVal);
+}
+
+unsigned long CHours::GetCrDenyColor()
+{
+ unsigned long result;
+ GetProperty(0x2, VT_I4, (void*)&result);
+ return result;
+}
+
+void CHours::SetCrDenyColor(unsigned long propVal)
+{
+ SetProperty(0x2, VT_I4, propVal);
+}
+
+VARIANT CHours::GetDateData()
+{
+ VARIANT result;
+ GetProperty(0x3, VT_VARIANT, (void*)&result);
+ return result;
+}
+
+void CHours::SetDateData(const VARIANT& propVal)
+{
+ SetProperty(0x3, VT_VARIANT, &propVal);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CHours operations
diff --git a/private/utils/wizards/addusrw/hours1.h b/private/utils/wizards/addusrw/hours1.h
new file mode 100644
index 000000000..bee62f321
--- /dev/null
+++ b/private/utils/wizards/addusrw/hours1.h
@@ -0,0 +1,50 @@
+#ifndef __HOURS1_H__
+#define __HOURS1_H__
+
+// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++
+
+// NOTE: Do not modify the contents of this file. If this class is regenerated by
+// Microsoft Visual C++, your modifications will be overwritten.
+
+/////////////////////////////////////////////////////////////////////////////
+// CHours wrapper class
+
+class CHours : public CWnd
+{
+protected:
+ DECLARE_DYNCREATE(CHours)
+public:
+ CLSID const& GetClsid()
+ {
+ static CLSID const clsid
+ = { 0xa44ea7ad, 0x9d58, 0x11cf, { 0xa3, 0x5f, 0x0, 0xaa, 0x0, 0xb6, 0x74, 0x3b } };
+ return clsid;
+ }
+ virtual BOOL Create(LPCTSTR lpszClassName,
+ LPCTSTR lpszWindowName, DWORD dwStyle,
+ const RECT& rect,
+ CWnd* pParentWnd, UINT nID,
+ CCreateContext* pContext = NULL)
+ { return CreateControl(GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd, nID); }
+
+ BOOL Create(LPCTSTR lpszWindowName, DWORD dwStyle,
+ const RECT& rect, CWnd* pParentWnd, UINT nID,
+ CFile* pPersist = NULL, BOOL bStorage = FALSE,
+ BSTR bstrLicKey = NULL)
+ { return CreateControl(GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd, nID,
+ pPersist, bStorage, bstrLicKey); }
+
+// Attributes
+public:
+ unsigned long GetCrPermitColor();
+ void SetCrPermitColor(unsigned long);
+ unsigned long GetCrDenyColor();
+ void SetCrDenyColor(unsigned long);
+ VARIANT GetDateData();
+ void SetDateData(const VARIANT&);
+
+// Operations
+public:
+};
+
+#endif // __HOURS1_H__
diff --git a/private/utils/wizards/addusrw/limit.cpp b/private/utils/wizards/addusrw/limit.cpp
new file mode 100644
index 000000000..e66abd685
--- /dev/null
+++ b/private/utils/wizards/addusrw/limit.cpp
@@ -0,0 +1,276 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Limit.cpp : implementation file
+
+ CPropertyPage support for User mgmt wizard
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+#include "stdafx.h"
+#include "Speckle.h"
+#include "wizbased.h"
+#include "Limit.h"
+
+#ifdef _DEBUG
+//#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CLimitLogon property page
+
+IMPLEMENT_DYNCREATE(CLimitLogon, CWizBaseDlg)
+
+CLimitLogon::CLimitLogon() : CWizBaseDlg(CLimitLogon::IDD)
+{
+ //{{AFX_DATA_INIT(CLimitLogon)
+ m_nWorkstationRadio = 0;
+ m_csCaption = _T("");
+ //}}AFX_DATA_INIT
+}
+
+CLimitLogon::~CLimitLogon()
+{
+}
+
+void CLimitLogon::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CLimitLogon)
+ DDX_Control(pDX, IDC_LIST1, m_lbWksList);
+ DDX_Radio(pDX, IDC_WORKSTATION_RADIO, m_nWorkstationRadio);
+ DDX_Text(pDX, IDC_STATIC2, m_csCaption);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CLimitLogon, CWizBaseDlg)
+ //{{AFX_MSG_MAP(CLimitLogon)
+ ON_BN_CLICKED(IDC_ADD_BUTTON, OnAddButton)
+ ON_BN_CLICKED(IDC_REMOVE_BUTTON, OnRemoveButton)
+ ON_BN_CLICKED(IDC_WORKSTATION_RADIO, OnWorkstationRadio)
+ ON_BN_CLICKED(IDC_WORKSTATION_RADIO2, OnWorkstationRadio2)
+ ON_WM_SHOWWINDOW()
+ ON_LBN_SETFOCUS(IDC_LIST1, OnSetfocusList1)
+ ON_WM_DESTROY()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CLimitLogon message handlers
+LRESULT CLimitLogon::OnWizardNext()
+{
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+ UpdateData(TRUE);
+
+ if ((m_nWorkstationRadio == 1) && (m_lbWksList.GetCount() == 0))
+ {
+ AfxMessageBox(IDS_NEEDA_WORKSTATION);
+ return -1;
+ }
+
+ if (m_nWorkstationRadio == 0) pApp->m_csAllowedMachines = L"";
+ else
+ {
+// make workstation list and store it
+ USHORT sCount;
+ CString csWksList;
+ for (sCount = 0; sCount < m_lbWksList.GetCount(); sCount++)
+ {
+ CString csWks;
+ m_lbWksList.GetText(sCount, csWks);
+ csWksList += csWks;
+ csWksList += L",";
+ }
+
+// remove trailing ','
+ csWksList = csWksList.Left(csWksList.GetLength() - 1);
+ pApp->m_csAllowedMachines = csWksList;
+ }
+
+ if (pApp->m_bNW) return IDD_NWLOGON_DIALOG;
+ else return IDD_FINISH;
+
+}
+
+LRESULT CLimitLogon::OnWizardBack()
+{
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+ if (pApp->m_bHours) return IDD_HOURS_DLG;
+ else if (pApp->m_bExpiration) return IDD_ACCOUNT_EXP_DIALOG;
+ return IDD_RESTRICTIONS_DIALOG;
+
+}
+
+
+void CLimitLogon::OnAddButton()
+{
+ CAddWorkstation pWks;
+ pWks.pListBox = &m_lbWksList;
+ pWks.DoModal();
+
+ if (m_lbWksList.GetCount() > 0) GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(TRUE);
+ else GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(FALSE);
+
+ GetDlgItem(IDC_LIST1)->SetFocus();
+ m_lbWksList.SetCurSel(0);
+
+}
+
+void CLimitLogon::OnRemoveButton()
+{
+ int ui = m_lbWksList.GetCurSel();
+ if (ui == LB_ERR) return;
+
+ m_lbWksList.DeleteString(ui);
+ if (ui > 0) m_lbWksList.SetCurSel(ui - 1);
+ else if (m_lbWksList.GetCount() > 0) m_lbWksList.SetCurSel(0);
+ else GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(FALSE);
+
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CAddWorkstation dialog
+
+
+CAddWorkstation::CAddWorkstation(CWnd* pParent /*=NULL*/)
+ : CDialog(CAddWorkstation::IDD, pParent)
+{
+ //{{AFX_DATA_INIT(CAddWorkstation)
+ m_csWorkstation = _T("");
+ //}}AFX_DATA_INIT
+}
+
+
+void CAddWorkstation::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CAddWorkstation)
+ DDX_Text(pDX, IDC_WORKSTATION_EDIT, m_csWorkstation);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CAddWorkstation, CDialog)
+ //{{AFX_MSG_MAP(CAddWorkstation)
+ ON_BN_CLICKED(IDOK, OnAdd)
+ ON_BN_CLICKED(IDCANCEL, OnClose)
+ ON_EN_CHANGE(IDC_WORKSTATION_EDIT, OnChangeWorkstationEdit)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CAddWorkstation message handlers
+
+void CAddWorkstation::OnAdd()
+{
+ UpdateData(TRUE);
+ if (m_csWorkstation == L"")
+ {
+ GetDlgItem(IDC_WORKSTATION_EDIT)->SetFocus();
+ return;
+ }
+
+// check for validity
+ if (m_csWorkstation.FindOneOf(L"/.,<>;;'[{]}=+)(*&^%$#@!~`| ") != -1)
+ {
+ AfxMessageBox(IDS_BAD_WS_NAME);
+ GetDlgItem(IDC_WORKSTATION_EDIT)->SetFocus();
+ }
+
+ if (m_csWorkstation.GetLength() > 15)
+ {
+ AfxMessageBox(IDS_WSNAME_TOOLONG);
+ GetDlgItem(IDC_WORKSTATION_EDIT)->SetFocus();
+ return;
+ }
+
+ while (m_csWorkstation.Left(1) == L"\\")
+ m_csWorkstation = m_csWorkstation.Right(m_csWorkstation.GetLength() - 1);
+
+// make sure its unique
+ if (pListBox->FindString(-1, m_csWorkstation) == LB_ERR) pListBox->AddString(m_csWorkstation);
+ UpdateData(FALSE);
+ EndDialog(1);
+
+}
+
+void CAddWorkstation::OnClose()
+{
+ EndDialog(0);
+
+}
+
+void CLimitLogon::OnWorkstationRadio()
+{
+ GetDlgItem(IDC_STATIC1)->EnableWindow(FALSE);
+ GetDlgItem(IDC_LIST1)->EnableWindow(FALSE);
+ GetDlgItem(IDC_ADD_BUTTON)->EnableWindow(FALSE);
+ GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(FALSE);
+
+}
+
+void CLimitLogon::OnWorkstationRadio2()
+{
+ GetDlgItem(IDC_STATIC1)->EnableWindow(TRUE);
+ GetDlgItem(IDC_LIST1)->EnableWindow(TRUE);
+ GetDlgItem(IDC_ADD_BUTTON)->EnableWindow(TRUE);
+ if (m_lbWksList.GetCount() > 0) GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(TRUE);
+ else GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(FALSE);
+
+}
+
+void CLimitLogon::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CWizBaseDlg::OnShowWindow(bShow, nStatus);
+
+ if (bShow)
+ {
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+ CString csTemp;
+ csTemp.LoadString(IDS_WORKSTATION_CAPTION);
+
+ CString csTemp2;
+ csTemp2.Format(csTemp, pApp->m_csUserName);
+ m_csCaption = csTemp2;
+ UpdateData(FALSE);
+ }
+
+}
+
+void CLimitLogon::OnSetfocusList1()
+{
+ if (m_lbWksList.GetCount() > 0) GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(TRUE);
+ else GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(FALSE);
+
+}
+
+void CAddWorkstation::OnChangeWorkstationEdit()
+{
+ UpdateData(TRUE);
+
+// check for validity
+ if (m_csWorkstation.FindOneOf(L"/.,<>;;'[{]}=+)(*&^%$#@!~`| ") != -1)
+ {
+ AfxMessageBox(IDS_BAD_WS_NAME);
+ GetDlgItem(IDC_WORKSTATION_EDIT)->SetFocus();
+ }
+
+ if (m_csWorkstation.GetLength() > 15)
+ {
+ AfxMessageBox(IDS_WSNAME_TOOLONG);
+ GetDlgItem(IDC_WORKSTATION_EDIT)->SetFocus();
+ return;
+ }
+
+}
diff --git a/private/utils/wizards/addusrw/limit.h b/private/utils/wizards/addusrw/limit.h
new file mode 100644
index 000000000..253499145
--- /dev/null
+++ b/private/utils/wizards/addusrw/limit.h
@@ -0,0 +1,94 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Limit.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+/////////////////////////////////////////////////////////////////////////////
+// CAddWorkstation dialog
+
+class CAddWorkstation : public CDialog
+{
+// Construction
+public:
+ CAddWorkstation(CWnd* pParent = NULL); // standard constructor
+
+// Dialog Data
+ //{{AFX_DATA(CAddWorkstation)
+ enum { IDD = IDD_ADD_WKS_DIALOG };
+ CString m_csWorkstation;
+ //}}AFX_DATA
+
+ CListBox* pListBox;
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CAddWorkstation)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+
+ // Generated message map functions
+ //{{AFX_MSG(CAddWorkstation)
+ afx_msg void OnAdd();
+ afx_msg void OnClose();
+ afx_msg void OnChangeWorkstationEdit();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+// CLimitLogon dialog
+
+class CLimitLogon : public CWizBaseDlg
+{
+ DECLARE_DYNCREATE(CLimitLogon)
+
+// Construction
+public:
+ CLimitLogon();
+ ~CLimitLogon();
+
+// Dialog Data
+ //{{AFX_DATA(CLimitLogon)
+ enum { IDD = IDD_LOGONTO_DLG };
+ CListBox m_lbWksList;
+ int m_nWorkstationRadio;
+ CString m_csCaption;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CLimitLogon)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+ LRESULT OnWizardNext();
+ LRESULT OnWizardBack();
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CLimitLogon)
+ afx_msg void OnAddButton();
+ afx_msg void OnRemoveButton();
+ afx_msg void OnWorkstationRadio();
+ afx_msg void OnWorkstationRadio2();
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ afx_msg void OnSetfocusList1();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+private:
+ void Toggle(BOOL bParam);
+
+};
diff --git a/private/utils/wizards/addusrw/lscript.cpp b/private/utils/wizards/addusrw/lscript.cpp
new file mode 100644
index 000000000..fb70dffc4
--- /dev/null
+++ b/private/utils/wizards/addusrw/lscript.cpp
@@ -0,0 +1,83 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ LScript.cpp : implementation file
+
+ CPropertyPage support for User mgmt wizard
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+#include "stdafx.h"
+#include "speckle.h"
+#include "wizbased.h"
+#include "LScript.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CLoginScript property page
+
+IMPLEMENT_DYNCREATE(CLoginScript, CWizBaseDlg)
+
+CLoginScript::CLoginScript() : CWizBaseDlg(CLoginScript::IDD)
+{
+ //{{AFX_DATA_INIT(CLoginScript)
+ m_csLogonScript = _T("");
+ //}}AFX_DATA_INIT
+}
+
+CLoginScript::~CLoginScript()
+{
+}
+
+void CLoginScript::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CLoginScript)
+ DDX_Text(pDX, IDC_LOGON_SCRIPT, m_csLogonScript);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CLoginScript, CWizBaseDlg)
+ //{{AFX_MSG_MAP(CLoginScript)
+ // NOTE: the ClassWizard will add message map macros here
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CLoginScript message handlers
+
+LRESULT CLoginScript::OnWizardNext()
+{
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+ UpdateData(TRUE);
+ pApp->m_csLogonScript = m_csLogonScript;
+
+ if (pApp->m_bHomeDir) return IDD_HOMEDIR_DIALOG;
+ else if (pApp->m_bRAS) return IDD_RAS_PERM_DIALOG;
+ else if (pApp->m_bNW) return IDD_FPNW_DLG;
+ else if (pApp->m_bExchange) return IDD_EXCHANGE_DIALOG;
+ else return IDD_RESTRICTIONS_DIALOG;
+
+}
+
+LRESULT CLoginScript::OnWizardBack()
+{
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+ if (pApp->m_bProfile) return IDD_PROFILE;
+ else return IDD_OPTIONS_DIALOG;
+
+}
diff --git a/private/utils/wizards/addusrw/lscript.h b/private/utils/wizards/addusrw/lscript.h
new file mode 100644
index 000000000..3494cdd61
--- /dev/null
+++ b/private/utils/wizards/addusrw/lscript.h
@@ -0,0 +1,52 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ LScript.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+/////////////////////////////////////////////////////////////////////////////
+// CLoginScript dialog
+
+class CLoginScript : public CWizBaseDlg
+{
+ DECLARE_DYNCREATE(CLoginScript)
+
+// Construction
+public:
+ CLoginScript();
+ ~CLoginScript();
+
+// Dialog Data
+ //{{AFX_DATA(CLoginScript)
+ enum { IDD = IDD_LOGON_SCRIPT_DIALOG };
+ CString m_csLogonScript;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CLoginScript)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+ LRESULT OnWizardBack();
+ LRESULT OnWizardNext();
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CLoginScript)
+ // NOTE: the ClassWizard will add member functions here
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+};
diff --git a/private/utils/wizards/addusrw/makefile b/private/utils/wizards/addusrw/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/wizards/addusrw/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/wizards/addusrw/nwlim.cpp b/private/utils/wizards/addusrw/nwlim.cpp
new file mode 100644
index 000000000..0abded1b8
--- /dev/null
+++ b/private/utils/wizards/addusrw/nwlim.cpp
@@ -0,0 +1,312 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ NWLim.cpp : implementation file
+
+ CPropertyPage support for User mgmt wizard
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+#include "stdafx.h"
+#include "speckle.h"
+#include "NWLim.h"
+#include "NWWKS.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+class WKSMember
+ {
+ public:
+ CString csWKSAddress;
+ CString csWKSNode;
+ };
+
+/////////////////////////////////////////////////////////////////////////////
+// CNWLimitLogon dialog
+IMPLEMENT_DYNCREATE(CNWLimitLogon, CPropertyPage)
+CNWLimitLogon::CNWLimitLogon() : CPropertyPage(CNWLimitLogon::IDD)
+{
+ //{{AFX_DATA_INIT(CNWLimitLogon)
+ m_nWorkstationRadio = 0;
+ m_csCaption = _T("");
+ //}}AFX_DATA_INIT
+}
+
+
+void CNWLimitLogon::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CNWLimitLogon)
+ DDX_Control(pDX, IDC_NWLOGON_LIST, m_lbWksList);
+ DDX_Radio(pDX, IDC_WORKSTATION_RADIO, m_nWorkstationRadio);
+ DDX_Text(pDX, IDC_STATIC1, m_csCaption);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CNWLimitLogon, CPropertyPage)
+ //{{AFX_MSG_MAP(CNWLimitLogon)
+ ON_BN_CLICKED(IDC_ADD_BUTTON, OnAddButton)
+ ON_BN_CLICKED(IDC_REMOVE_BUTTON, OnRemoveButton)
+ ON_BN_CLICKED(IDC_WORKSTATION_RADIO, OnWorkstationRadio)
+ ON_BN_CLICKED(IDC_WORKSTATION_RADIO2, OnWorkstationRadio2)
+ ON_WM_SHOWWINDOW()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CNWLimitLogon message handlers
+LRESULT CNWLimitLogon::OnWizardNext()
+{
+ UpdateData(TRUE);
+ if ((m_nWorkstationRadio == 1) && (m_lbWksList.GetCount() == 0))
+ {
+ AfxMessageBox(IDS_NEEDA_WORKSTATION);
+ return -1;
+ }
+
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+ USHORT sCount = 0;
+ BOOL bMatch = FALSE;
+ pApp->m_csAllowedLoginFrom = L"";
+ while (sCount < m_lbWksList.GetCount())
+ {
+ WKSMember* pMem = (WKSMember*)m_lbWksList.GetItemData(sCount);
+ CString csTemp;
+ if (pMem->csWKSNode == L"0000000000-1") csTemp.Format(L"%s%s", pMem->csWKSAddress, L"ffffffffffff");
+ else csTemp.Format(L"%s%s", pMem->csWKSAddress, pMem->csWKSNode);
+
+ pApp->m_csAllowedLoginFrom += csTemp;
+ sCount++;
+ }
+
+ if (m_lbWksList.GetCount() > 0) pApp->m_csAllowedLoginFrom += L"00";
+
+ return IDD_FINISH;
+
+}
+
+LRESULT CNWLimitLogon::OnWizardBack()
+{
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+ if (pApp->m_bWorkstation) return IDD_LOGONTO_DLG;
+ else if (pApp->m_bHours) return IDD_HOURS_DLG;
+ else if (pApp->m_bExpiration) return IDD_ACCOUNT_EXP_DIALOG;
+ else return IDD_RESTRICTIONS_DIALOG;
+
+}
+
+
+void CNWLimitLogon::OnAddButton()
+{
+ CAddNWWKS add;
+ if (add.DoModal() == 1)
+ {
+ // check for uniqueness
+ USHORT sCount = 0;
+ BOOL bMatch = FALSE;
+ while (sCount < m_lbWksList.GetCount())
+ {
+ WKSMember* pMem = (WKSMember*)m_lbWksList.GetItemData(sCount);
+ if ((pMem->csWKSAddress == add.m_csNetworkAddress) &&
+ (pMem->csWKSNode == add.m_csNodeAddress))
+ {
+ bMatch = TRUE;
+ break;
+ }
+
+ sCount++;
+ }
+
+ if (bMatch) return;
+
+ WKSMember* member = new WKSMember;
+ member->csWKSAddress = add.m_csNetworkAddress;
+ member->csWKSNode = add.m_csNodeAddress;
+
+ int nEntry = m_lbWksList.AddString(L" ");
+ m_lbWksList.SetItemData(nEntry, (DWORD)member);
+
+ // enable the remove button since there is something to remove
+ GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(TRUE);
+ GetDlgItem(IDC_NWLOGON_LIST)->SetFocus();
+ m_lbWksList.SetCurSel(0);
+ }
+
+}
+
+void CNWLimitLogon::OnRemoveButton()
+{
+ USHORT sSel = m_lbWksList.GetCurSel();
+
+ WKSMember* member = (WKSMember*)m_lbWksList.GetItemData(sSel);
+ free(member);
+ m_lbWksList.DeleteString(sSel);
+
+ if (m_lbWksList.GetCount() == 0) GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(FALSE);
+ else if (sSel > 0) m_lbWksList.SetCurSel(sSel - 1);
+ else m_lbWksList.SetCurSel(0);
+
+}
+
+void CNWLimitLogon::OnWorkstationRadio()
+{
+ GetDlgItem(IDC_NWSTATIC1)->EnableWindow(FALSE);
+ GetDlgItem(IDC_NWSTATIC2)->EnableWindow(FALSE);
+ GetDlgItem(IDC_NWLOGON_LIST)->EnableWindow(FALSE);
+ GetDlgItem(IDC_ADD_BUTTON)->EnableWindow(FALSE);
+ GetDlgItem(IDC_REMOVE_BUTTON)->EnableWindow(FALSE);
+
+}
+
+void CNWLimitLogon::OnWorkstationRadio2()
+{
+ GetDlgItem(IDC_NWSTATIC1)->EnableWindow(TRUE);
+ GetDlgItem(IDC_NWSTATIC2)->EnableWindow(TRUE);
+ GetDlgItem(IDC_NWLOGON_LIST)->EnableWindow(TRUE);
+ GetDlgItem(IDC_ADD_BUTTON)->EnableWindow(TRUE);
+
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CWorkstationList
+
+CWorkstationList::CWorkstationList()
+{
+}
+
+CWorkstationList::~CWorkstationList()
+{
+}
+
+
+BEGIN_MESSAGE_MAP(CWorkstationList, CListBox)
+ //{{AFX_MSG_MAP(CWorkstationList)
+ ON_WM_DESTROY()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CWorkstationList message handlers
+
+void CWorkstationList::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
+{
+ COLORREF crefOldText;
+ COLORREF crefOldBk;
+ HBRUSH hBrush;
+
+ CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
+ switch (lpDrawItemStruct->itemAction)
+ {
+ case ODA_SELECT:
+ case ODA_DRAWENTIRE:
+// Is the item selected?
+ if (lpDrawItemStruct->itemState & ODS_SELECTED)
+ {
+ hBrush = CreateSolidBrush( GetSysColor(COLOR_HIGHLIGHT));
+ crefOldText = pDC->SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT) );
+ crefOldBk = pDC->SetBkColor(GetSysColor(COLOR_HIGHLIGHT) );
+ }
+ else
+ {
+ hBrush = (HBRUSH)GetStockObject( GetSysColor(COLOR_WINDOW));
+ crefOldText = pDC->SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
+ crefOldBk = pDC->SetBkColor(GetSysColor(COLOR_WINDOW));
+ }
+
+// fill in the background
+ pDC->FillRect(&(lpDrawItemStruct->rcItem), CBrush::FromHandle(hBrush));
+
+// display text
+ TCHAR* pName = (TCHAR*)malloc(255 * sizeof(TCHAR));
+ if (pName == NULL)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
+ exit(1);
+ }
+
+ DWORD dwAddr = GetItemData(lpDrawItemStruct->itemID);
+
+ WKSMember* member = (WKSMember*)dwAddr;
+
+// format the name + comment
+ int nTop = (lpDrawItemStruct->rcItem.bottom + lpDrawItemStruct->rcItem.top) / 2;
+ pDC->TextOut(0,
+ (nTop - 8),
+ member->csWKSAddress);
+
+ if (member->csWKSNode == L"0000000000-1")
+ pDC->TextOut(130,
+ (nTop - 8),
+ L"All Nodes");
+
+ else
+ pDC->TextOut(130,
+ (nTop - 8),
+ member->csWKSNode);
+
+ free(pName);
+ break;
+ }
+
+ pDC->SetBkColor(crefOldBk );
+ pDC->SetTextColor(crefOldText );
+}
+
+int CWorkstationList::CompareItem(LPCOMPAREITEMSTRUCT lpCompareItemStruct)
+{
+ // TODO: Add your code to determine the sorting order of the specified items
+ // return -1 = item 1 sorts before item 2
+ // return 0 = item 1 and item 2 sort the same
+ // return 1 = item 1 sorts after item 2
+
+ return 0;
+}
+
+void CWorkstationList::OnDestroy()
+{
+ while(GetCount() > 0)
+ {
+ WKSMember* member = (WKSMember*)GetItemData(0);
+ delete member;
+ DeleteString(0);
+ }
+ CListBox::OnDestroy();
+
+
+}
+
+
+void CNWLimitLogon::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CPropertyPage::OnShowWindow(bShow, nStatus);
+
+ if (bShow)
+ {
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+ CString csTemp;
+ csTemp.LoadString(IDS_NWLOGON_CAPTION);
+
+ CString csTemp2;
+ csTemp2.Format(csTemp, pApp->m_csUserName);
+ m_csCaption = csTemp2;
+ UpdateData(FALSE);
+ }
+
+}
diff --git a/private/utils/wizards/addusrw/nwlim.h b/private/utils/wizards/addusrw/nwlim.h
new file mode 100644
index 000000000..6fc6ecb4b
--- /dev/null
+++ b/private/utils/wizards/addusrw/nwlim.h
@@ -0,0 +1,92 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ NWLim.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+/////////////////////////////////////////////////////////////////////////////
+// CWorkstationList window
+
+class CWorkstationList : public CListBox
+{
+// Construction
+public:
+ CWorkstationList();
+
+// Attributes
+public:
+
+// Operations
+public:
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CWorkstationList)
+ public:
+ virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
+ virtual int CompareItem(LPCOMPAREITEMSTRUCT lpCompareItemStruct);
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CWorkstationList();
+
+ // Generated message map functions
+protected:
+ //{{AFX_MSG(CWorkstationList)
+ afx_msg void OnDestroy();
+ //}}AFX_MSG
+
+ DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+/////////////////////////////////////////////////////////////////////////////
+// CNWLimitLogon dialog
+
+class CNWLimitLogon : public CPropertyPage
+{
+DECLARE_DYNCREATE(CNWLimitLogon)
+// Construction
+public:
+ CNWLimitLogon(); // standard constructor
+
+// Dialog Data
+ //{{AFX_DATA(CNWLimitLogon)
+ enum { IDD = IDD_NWLOGON_DIALOG };
+ CWorkstationList m_lbWksList;
+ int m_nWorkstationRadio;
+ CString m_csCaption;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CNWLimitLogon)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+ LRESULT OnWizardNext();
+ LRESULT OnWizardBack();
+
+// Implementation
+protected:
+
+ // Generated message map functions
+ //{{AFX_MSG(CNWLimitLogon)
+ afx_msg void OnAddButton();
+ afx_msg void OnRemoveButton();
+ afx_msg void OnWorkstationRadio();
+ afx_msg void OnWorkstationRadio2();
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
diff --git a/private/utils/wizards/addusrw/nwwks.cpp b/private/utils/wizards/addusrw/nwwks.cpp
new file mode 100644
index 000000000..e33fc3ba4
--- /dev/null
+++ b/private/utils/wizards/addusrw/nwwks.cpp
@@ -0,0 +1,159 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ NWWKS.cpp : implementation file
+
+ CPropertyPage support for User mgmt wizard
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+#include "stdafx.h"
+#include "speckle.h"
+#include "NWWKS.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CAddNWWKS dialog
+
+
+CAddNWWKS::CAddNWWKS(CWnd* pParent /*=NULL*/)
+ : CDialog(CAddNWWKS::IDD, pParent)
+{
+ //{{AFX_DATA_INIT(CAddNWWKS)
+ m_csNetworkAddress = _T("");
+ m_csNodeAddress = _T("");
+ //}}AFX_DATA_INIT
+}
+
+
+void CAddNWWKS::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CAddNWWKS)
+ DDX_Text(pDX, IDC_NETWORK_ADDRESS_EDIT, m_csNetworkAddress);
+ DDX_Text(pDX, IDC_NODE_ADDRESS_EDIT, m_csNodeAddress);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CAddNWWKS, CDialog)
+ //{{AFX_MSG_MAP(CAddNWWKS)
+ ON_EN_CHANGE(IDC_NETWORK_ADDRESS_EDIT, OnChangeNetworkAddressEdit)
+ ON_EN_CHANGE(IDC_NODE_ADDRESS_EDIT, OnChangeNodeAddressEdit)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CAddNWWKS message handlers
+
+void CAddNWWKS::OnOK()
+{
+// 8 digit address
+// 12 digit node
+// network is req'd. Node is not.
+ UpdateData(TRUE);
+
+ if (m_csNetworkAddress == L"")
+ {
+ AfxMessageBox(IDS_NEED_ADDRESS);
+ GetDlgItem(IDC_NETWORK_ADDRESS_EDIT)->SetFocus();
+ return;
+ }
+
+ if (m_csNetworkAddress.FindOneOf(L"GgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz~`!@#$%^&*()-_+={[}}]|\\:;\"',<.>/?") != -1)
+ {
+ AfxMessageBox(IDS_BAD_NWADDRESS);
+ GetDlgItem(IDC_NETWORK_ADDRESS_EDIT)->SetFocus();
+ return;
+ }
+
+ if (m_csNetworkAddress.GetLength() > 8)
+ {
+ AfxMessageBox(IDS_TOOLONG_NWADDRESS);
+ GetDlgItem(IDC_NETWORK_ADDRESS_EDIT)->SetFocus();
+ return;
+ }
+
+ if (m_csNodeAddress.FindOneOf(L"GgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz~`!@#$%^&*()-_+={[}}]|\\:;\"',<.>/?") != -1)
+ {
+ AfxMessageBox(IDS_BAD_NWNODE);
+ GetDlgItem(IDC_NODE_ADDRESS_EDIT)->SetFocus();
+ return;
+ }
+
+ if (m_csNodeAddress.GetLength() > 12)
+ {
+ AfxMessageBox(IDS_TOOLONG_NWNODE);
+ GetDlgItem(IDC_NODE_ADDRESS_EDIT)->SetFocus();
+ return;
+ }
+
+ if (m_csNodeAddress == L"")
+ {
+ if (AfxMessageBox(IDS_ALL_NODES, MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
+ m_csNodeAddress = L"-1";
+
+ else return;
+ }
+
+// pad out the numbers to the appropriate length
+ while (m_csNodeAddress.GetLength() < 12) m_csNodeAddress = L"0" + m_csNodeAddress;
+ while (m_csNetworkAddress.GetLength() < 8) m_csNetworkAddress = L"0" + m_csNetworkAddress;
+
+ EndDialog(1);
+
+}
+
+void CAddNWWKS::OnCancel()
+{
+ EndDialog(0);
+}
+
+BOOL CAddNWWKS::OnInitDialog()
+{
+ CDialog::OnInitDialog();
+
+ GetDlgItem(IDC_NETWORK_ADDRESS_EDIT)->SetFocus();
+
+ return FALSE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+void CAddNWWKS::OnChangeNetworkAddressEdit()
+{
+ UpdateData(TRUE);
+ if (m_csNetworkAddress.FindOneOf(L"GgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz~`!@#$%^&*()-_+={[}}]|\\:;\"',<.>/?") != -1)
+ {
+ AfxMessageBox(IDS_BAD_NWADDRESS);
+ }
+
+ if (m_csNetworkAddress.GetLength() > 8)
+ {
+ AfxMessageBox(IDS_TOOLONG_NWADDRESS);
+ }
+
+}
+
+void CAddNWWKS::OnChangeNodeAddressEdit()
+{
+ UpdateData(TRUE);
+ if (m_csNodeAddress.FindOneOf(L"GgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz~`!@#$%^&*()-_+={[}}]|\\:;\"',<.>/?") != -1)
+ AfxMessageBox(IDS_BAD_NWNODE);
+
+ if (m_csNodeAddress.GetLength() > 12)
+ AfxMessageBox(IDS_TOOLONG_NWNODE);
+
+}
diff --git a/private/utils/wizards/addusrw/nwwks.h b/private/utils/wizards/addusrw/nwwks.h
new file mode 100644
index 000000000..5c0049e74
--- /dev/null
+++ b/private/utils/wizards/addusrw/nwwks.h
@@ -0,0 +1,51 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ NWWKS.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+/////////////////////////////////////////////////////////////////////////////
+// CAddNWWKS dialog
+
+class CAddNWWKS : public CDialog
+{
+// Construction
+public:
+ CAddNWWKS(CWnd* pParent = NULL); // standard constructor
+
+// Dialog Data
+ //{{AFX_DATA(CAddNWWKS)
+ enum { IDD = IDD_ADD_NWWKS_DIALOG };
+ CString m_csNetworkAddress;
+ CString m_csNodeAddress;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CAddNWWKS)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+
+ // Generated message map functions
+ //{{AFX_MSG(CAddNWWKS)
+ virtual void OnOK();
+ virtual void OnCancel();
+ virtual BOOL OnInitDialog();
+ afx_msg void OnChangeNetworkAddressEdit();
+ afx_msg void OnChangeNodeAddressEdit();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
diff --git a/private/utils/wizards/addusrw/optdlg.cpp b/private/utils/wizards/addusrw/optdlg.cpp
new file mode 100644
index 000000000..29b0c0914
--- /dev/null
+++ b/private/utils/wizards/addusrw/optdlg.cpp
@@ -0,0 +1,167 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ OptDlg.cpp : implementation file
+
+ CPropertyPage support for User mgmt wizard
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+#include "stdafx.h"
+#include "speckle.h"
+#include "wizbased.h"
+#include "OptDlg.h"
+
+#include <lmcons.h>
+#include <lmerr.h>
+#include <lmserver.h>
+#include <winreg.h>
+
+#ifdef _DEBUG
+//#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// COptionsDlg property page
+
+IMPLEMENT_DYNCREATE(COptionsDlg, CWizBaseDlg)
+
+COptionsDlg::COptionsDlg() : CWizBaseDlg(COptionsDlg::IDD)
+{
+ //{{AFX_DATA_INIT(COptionsDlg)
+ m_bNW = FALSE;
+ m_bProfile = FALSE;
+ m_bRAS = FALSE;
+ m_bExchange = FALSE;
+ m_bHomeDir = FALSE;
+ m_bLoginScript = FALSE;
+ m_csCaption = _T("");
+ //}}AFX_DATA_INIT
+}
+
+COptionsDlg::~COptionsDlg()
+{
+}
+
+void COptionsDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(COptionsDlg)
+ DDX_Check(pDX, IDC_NW_CHECK, m_bNW);
+ DDX_Check(pDX, IDC_PROFILE_CHECK, m_bProfile);
+ DDX_Check(pDX, IDC_RAS_CHECK, m_bRAS);
+ DDX_Check(pDX, IDC_EXCHANGE_CHECK, m_bExchange);
+ DDX_Check(pDX, IDC_HOMEDIR_CHECK, m_bHomeDir);
+ DDX_Check(pDX, IDC_LOGIN_SCRIPT_CHECK, m_bLoginScript);
+ DDX_Text(pDX, IDC_STATIC1, m_csCaption);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(COptionsDlg, CWizBaseDlg)
+ //{{AFX_MSG_MAP(COptionsDlg)
+ ON_WM_SHOWWINDOW()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// COptionsDlg message handlers
+
+void COptionsDlg::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CWizBaseDlg::OnShowWindow(bShow, nStatus);
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+ if (bShow)
+ {
+ CString csTemp;
+ csTemp.LoadString(IDS_OPTION_CAPTION);
+
+ CString csTemp2;
+ csTemp2.Format(csTemp, pApp->m_csUserName);
+ m_csCaption = csTemp2;
+ UpdateData(FALSE);
+
+// first find out whats installed so we know what to enable/disable
+ TCHAR* pServer = (TCHAR*)pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength());
+ pApp->m_csServer.ReleaseBuffer();
+
+ SERVER_INFO_102* pInfo;
+ NET_API_STATUS nApi = NetServerGetInfo(pServer,
+ 102,
+ (LPBYTE*)&pInfo);
+
+ if (nApi != ERROR_SUCCESS)
+ {
+ AfxMessageBox(IDS_UNKNOWN_COMPONENTS);
+ GetDlgItem(IDC_NW_CHECK)->EnableWindow(FALSE);
+ return;
+ }
+
+// FPNW
+ GetDlgItem(IDC_NW_CHECK)->EnableWindow(pInfo->sv102_type & SV_TYPE_SERVER_MFPN);
+ m_bNW = (pInfo->sv102_type & SV_TYPE_SERVER_MFPN) ? m_bNW : FALSE;
+ UpdateData(FALSE);
+
+// exchange- look for the usrmgr extension entry
+ HKEY hKey;
+
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+ long lRet = RegConnectRegistry(
+ (LPTSTR)pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength()),
+ HKEY_LOCAL_MACHINE,
+ &hKey);
+
+ if (lRet != ERROR_SUCCESS)
+ {
+ GetDlgItem(IDC_EXCHANGE_CHECK)->EnableWindow(FALSE);
+ m_bExchange = FALSE;
+ UpdateData(FALSE);
+ return;
+ }
+
+ DWORD cbProv = 0;
+ DWORD dwRet = RegOpenKey(hKey,
+ TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Network\\UMAddOns"), &hKey );
+
+ TCHAR* lpPrimaryDomain = NULL;
+ if ((dwRet = RegQueryValueEx( hKey, TEXT("Mailumx"), NULL, NULL, NULL, &cbProv )) == ERROR_SUCCESS)
+ GetDlgItem(IDC_EXCHANGE_CHECK)->EnableWindow(TRUE);
+ else GetDlgItem(IDC_EXCHANGE_CHECK)->EnableWindow(FALSE);
+
+ RegCloseKey(hKey);
+ }
+
+}
+
+LRESULT COptionsDlg::OnWizardNext()
+{
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+ UpdateData(TRUE);
+ pApp->m_bProfile = m_bProfile;
+ pApp->m_bLoginScript = m_bLoginScript;
+ pApp->m_bHomeDir = m_bHomeDir;
+ pApp->m_bRAS = m_bRAS;
+ pApp->m_bNW = m_bNW;
+ pApp->m_bExchange = m_bExchange;
+
+ if (m_bProfile) return IDD_PROFILE;
+ else if (m_bLoginScript) return IDD_LOGON_SCRIPT_DIALOG;
+ else if (m_bHomeDir) return IDD_HOMEDIR_DIALOG;
+ else if (m_bRAS) return IDD_RAS_PERM_DIALOG;
+ else if (m_bNW) return IDD_FPNW_DLG;
+ else if (m_bExchange) return IDD_EXCHANGE_DIALOG;
+ else return IDD_RESTRICTIONS_DIALOG;
+
+}
diff --git a/private/utils/wizards/addusrw/optdlg.h b/private/utils/wizards/addusrw/optdlg.h
new file mode 100644
index 000000000..081a37be7
--- /dev/null
+++ b/private/utils/wizards/addusrw/optdlg.h
@@ -0,0 +1,59 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ OptDlg.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+/////////////////////////////////////////////////////////////////////////////
+// COptionsDlg dialog
+
+class COptionsDlg : public CWizBaseDlg
+{
+ DECLARE_DYNCREATE(COptionsDlg)
+
+// Construction
+public:
+ COptionsDlg();
+ ~COptionsDlg();
+
+// Dialog Data
+ //{{AFX_DATA(COptionsDlg)
+ enum { IDD = IDD_OPTIONS_DIALOG };
+ BOOL m_bNW;
+ BOOL m_bProfile;
+ BOOL m_bRAS;
+ BOOL m_bExchange;
+ BOOL m_bHomeDir;
+ BOOL m_bLoginScript;
+ CString m_csCaption;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(COptionsDlg)
+ public:
+ virtual LRESULT OnWizardNext();
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(COptionsDlg)
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+};
diff --git a/private/utils/wizards/addusrw/profile.cpp b/private/utils/wizards/addusrw/profile.cpp
new file mode 100644
index 000000000..688d6f410
--- /dev/null
+++ b/private/utils/wizards/addusrw/profile.cpp
@@ -0,0 +1,105 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Profile.cpp : implementation file
+
+ CPropertyPage support for User mgmt wizard
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+#include "stdafx.h"
+#include "Speckle.h"
+#include "wizbased.h"
+#include "Profile.h"
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CProfile property page
+
+IMPLEMENT_DYNCREATE(CProfile, CWizBaseDlg)
+
+CProfile::CProfile() : CWizBaseDlg(CProfile::IDD)
+{
+ //{{AFX_DATA_INIT(CProfile)
+ m_csProfilePath = _T("");
+ //}}AFX_DATA_INIT
+}
+
+CProfile::~CProfile()
+{
+}
+
+void CProfile::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CProfile)
+ DDX_Text(pDX, IDC_PROFILE_PATH, m_csProfilePath);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CProfile, CWizBaseDlg)
+ //{{AFX_MSG_MAP(CProfile)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CProfile message handlers
+BOOL CProfile::OnInitDialog()
+{
+ CPropertyPage::OnInitDialog();
+
+ UpdateData(FALSE);
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+ /*
+void CProfile::OnBrowseButton()
+{
+ static TCHAR szFilter[] = _T("All Files (*.*)|*.*||");
+
+ CFileDialog cf(TRUE, L"", NULL, OFN_FILEMUSTEXIST | OFN_EXPLORER | OFN_PATHMUSTEXIST, szFilter);
+ if (cf.DoModal() == IDOK)
+ {
+ m_csProfilePath = cf.GetPathName();
+ UpdateData(FALSE);
+ }
+
+
+} */
+
+LRESULT CProfile::OnWizardNext()
+{
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+ UpdateData(TRUE);
+ pApp->m_csProfilePath = m_csProfilePath;
+
+ if (pApp->m_bLoginScript) return IDD_LOGON_SCRIPT_DIALOG;
+ else if (pApp->m_bHomeDir) return IDD_HOMEDIR_DIALOG;
+ else if (pApp->m_bRAS) return IDD_RAS_PERM_DIALOG;
+ else if (pApp->m_bNW) return IDD_FPNW_DLG;
+ else if (pApp->m_bExchange) return IDD_EXCHANGE_DIALOG;
+ else return IDD_RESTRICTIONS_DIALOG;
+
+
+}
+
+LRESULT CProfile::OnWizardBack()
+{
+ return IDD_OPTIONS_DIALOG;
+
+}
diff --git a/private/utils/wizards/addusrw/profile.h b/private/utils/wizards/addusrw/profile.h
new file mode 100644
index 000000000..4b6d9b849
--- /dev/null
+++ b/private/utils/wizards/addusrw/profile.h
@@ -0,0 +1,52 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Profile.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CProfile dialog
+
+class CProfile : public CWizBaseDlg
+{
+ DECLARE_DYNCREATE(CProfile)
+
+// Construction
+public:
+ CProfile();
+ ~CProfile();
+
+// Dialog Data
+ //{{AFX_DATA(CProfile)
+ enum { IDD = IDD_PROFILE };
+ CString m_csProfilePath;
+ //}}AFX_DATA
+
+ LRESULT OnWizardNext();
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CProfile)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CProfile)
+ virtual BOOL OnInitDialog();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+ LRESULT OnWizardBack();
+
+};
diff --git a/private/utils/wizards/addusrw/prsinfo.cpp b/private/utils/wizards/addusrw/prsinfo.cpp
new file mode 100644
index 000000000..aabd0c3f7
--- /dev/null
+++ b/private/utils/wizards/addusrw/prsinfo.cpp
@@ -0,0 +1,162 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ PersonalInfo.cpp : implementation file
+
+ CPropertyPage support for User mgmt wizard
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+#include "stdafx.h"
+#include "Speckle.h"
+#include "wizbased.h"
+#include "Prsinfo.h"
+
+#include <lmerr.h>
+#include <lmaccess.h>
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CPersonalInfo dialog
+IMPLEMENT_DYNCREATE(CPersonalInfo, CWizBaseDlg)
+
+CPersonalInfo::CPersonalInfo() : CWizBaseDlg(CPersonalInfo::IDD)
+{
+ //{{AFX_DATA_INIT(CPersonalInfo)
+ m_csDescription = _T("");
+ m_csFullName = _T("");
+ m_csUserName = _T("");
+ //}}AFX_DATA_INIT
+}
+
+
+void CPersonalInfo::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CPersonalInfo)
+ DDX_Text(pDX, IDC_DESCRIPTION, m_csDescription);
+ DDX_Text(pDX, IDC_FULLNAME, m_csFullName);
+ DDX_Text(pDX, IDC_USERNAME, m_csUserName);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CPersonalInfo, CWizBaseDlg)
+ //{{AFX_MSG_MAP(CPersonalInfo)
+ ON_WM_SHOWWINDOW()
+ ON_EN_CHANGE(IDC_USERNAME, OnChangeUsername)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CPersonalInfo message handlers
+LRESULT CPersonalInfo::OnWizardBack()
+{
+ SetButtonAccess(PSWIZB_NEXT | PSWIZB_BACK);
+
+ return CPropertyPage::OnWizardBack();
+}
+
+LRESULT CPersonalInfo::OnWizardNext()
+{
+ SetButtonAccess(PSWIZB_NEXT | PSWIZB_BACK);
+
+// eventually this needs to be changed to I_NetNameValidate from private\net\inc\icanon.h from netlib.lib
+ UpdateData(TRUE);
+ if (m_csUserName == "")
+ {
+ AfxMessageBox(IDS_NO_USERNAME);
+ GetDlgItem(IDC_USERNAME)->SetFocus();
+ return -1;
+ }
+
+ if (m_csUserName.GetLength() > 20)
+ {
+ AfxMessageBox(IDS_USERNAME_TOOLONG);
+ GetDlgItem(IDC_USERNAME)->SetFocus();
+ return -1;
+ }
+
+ if (m_csUserName.FindOneOf(L"\"\\/[];:|=,+*?<>") != -1)
+ {
+ AfxMessageBox(IDS_BAD_USERNAME);
+ GetDlgItem(IDC_USERNAME)->SetFocus();
+ return -1;
+ }
+
+ CWaitCursor wait;
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+ TCHAR* pServer = pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength());
+ pApp->m_csServer.ReleaseBuffer();
+
+ TCHAR* pUser = m_csUserName.GetBuffer(m_csUserName.GetLength());
+ m_csUserName.ReleaseBuffer();
+
+// is username unique?
+ LPBYTE* pUserInfo = new LPBYTE[256];
+ NET_API_STATUS nAPI = NetUserGetInfo(pServer,
+ pUser,
+ 0,
+ pUserInfo);
+
+ delete (pUserInfo);
+ if (nAPI == NERR_Success)
+ {
+ CString csDup;
+ csDup.Format(IDS_DUPLICATE_NAME, m_csUserName, m_csUserName, pApp->m_csDomain);
+ AfxMessageBox(csDup);
+ GetDlgItem(IDC_USERNAME)->SetFocus();
+ return -1;
+ }
+
+ pApp->m_csDescription = m_csDescription;
+ pApp->m_csFullName = m_csFullName;
+ pApp->m_csUserName = m_csUserName;
+
+ return CPropertyPage::OnWizardNext();
+
+}
+
+void CPersonalInfo::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CWizBaseDlg::OnShowWindow(bShow, nStatus);
+
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+ if (bShow && pApp->m_bPRSReset)
+ {
+ m_csDescription = L"";
+ m_csFullName = L"";
+ m_csUserName = L"";
+ pApp->m_bPRSReset = FALSE;
+ UpdateData(FALSE);
+ }
+}
+
+void CPersonalInfo::OnChangeUsername()
+{
+ UpdateData(TRUE);
+
+ if (m_csUserName.GetLength() > 20)
+ {
+ AfxMessageBox(IDS_USERNAME_TOOLONG);
+ GetDlgItem(IDC_USERNAME)->SetFocus();
+ }
+
+ if (m_csUserName.FindOneOf(L"\"\\/[];:|=,+*?<>") != -1)
+ {
+ AfxMessageBox(IDS_BAD_USERNAME);
+ GetDlgItem(IDC_USERNAME)->SetFocus();
+ }
+
+}
diff --git a/private/utils/wizards/addusrw/prsinfo.h b/private/utils/wizards/addusrw/prsinfo.h
new file mode 100644
index 000000000..d74678417
--- /dev/null
+++ b/private/utils/wizards/addusrw/prsinfo.h
@@ -0,0 +1,54 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ PrsInfo.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CPersonalInfo dialog
+
+class CPersonalInfo : public CWizBaseDlg
+{
+DECLARE_DYNCREATE(CPersonalInfo)
+
+// Construction
+public:
+ CPersonalInfo(); // standard constructor
+
+// Dialog Data
+ //{{AFX_DATA(CPersonalInfo)
+ enum { IDD = IDD_USER_NAME };
+ CString m_csDescription;
+ CString m_csFullName;
+ CString m_csUserName;
+ //}}AFX_DATA
+
+ LRESULT OnWizardBack();
+ LRESULT OnWizardNext();
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CPersonalInfo)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+
+ // Generated message map functions
+ //{{AFX_MSG(CPersonalInfo)
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ afx_msg void OnChangeUsername();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
diff --git a/private/utils/wizards/addusrw/pwinfo.cpp b/private/utils/wizards/addusrw/pwinfo.cpp
new file mode 100644
index 000000000..3669c1d88
--- /dev/null
+++ b/private/utils/wizards/addusrw/pwinfo.cpp
@@ -0,0 +1,207 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ PasswordInfo.cpp : implementation file
+
+ CPropertyPage support for User mgmt wizard
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+#include "stdafx.h"
+#include "Speckle.h"
+#include "wizbased.h"
+#include "PwInfo.h"
+
+#include <lmaccess.h>
+#include <lmerr.h>
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CPasswordInfo property page
+
+IMPLEMENT_DYNCREATE(CPasswordInfo, CWizBaseDlg)
+
+CPasswordInfo::CPasswordInfo() : CWizBaseDlg(CPasswordInfo::IDD)
+{
+ //{{AFX_DATA_INIT(CPasswordInfo)
+ m_csPassword1 = _T("");
+ m_csPassword2 = _T("");
+ m_nPWOptions = 0;
+ m_bNeverExpirePW = FALSE;
+ m_csCaption = _T("");
+ //}}AFX_DATA_INIT
+}
+
+CPasswordInfo::~CPasswordInfo()
+{
+}
+
+void CPasswordInfo::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CPasswordInfo)
+ DDX_Text(pDX, IDC_PASSWORD1, m_csPassword1);
+ DDX_Text(pDX, IDC_PASSWORD2, m_csPassword2);
+ DDX_Radio(pDX, IDC_PWOPTIONS_RADIO, m_nPWOptions);
+ DDX_Check(pDX, IDC_EXPIREPW_CHECK, m_bNeverExpirePW);
+ DDX_Text(pDX, IDC_STATIC1, m_csCaption);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CPasswordInfo, CWizBaseDlg)
+ //{{AFX_MSG_MAP(CPasswordInfo)
+ ON_WM_SHOWWINDOW()
+ ON_EN_CHANGE(IDC_PASSWORD1, OnChangePassword1)
+ ON_EN_CHANGE(IDC_PASSWORD2, OnChangePassword2)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CPasswordInfo message handlers
+
+LRESULT CPasswordInfo::OnWizardNext()
+{
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+ UpdateData(TRUE);
+ SetButtonAccess(PSWIZB_NEXT | PSWIZB_BACK);
+
+ TCHAR* pServer = pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength());
+ pApp->m_csServer.ReleaseBuffer();
+
+ if (m_csPassword1 != m_csPassword2)
+ {
+ CString csPW;
+ csPW.Format(IDS_PW_NOMATCH, pApp->m_csUserName);
+ AfxMessageBox(csPW);
+ GetDlgItem(IDC_PASSWORD1)->SetFocus();
+ return -1;
+ }
+
+ if (m_csPassword1.GetLength() > 14)
+ {
+ AfxMessageBox(IDS_PW_TOOLONG);
+ GetDlgItem(IDC_PASSWORD1)->SetFocus();
+ return -1;
+ }
+
+ if (m_csPassword2.GetLength() > 14)
+ {
+ AfxMessageBox(IDS_PW_TOOLONG);
+ GetDlgItem(IDC_PASSWORD2)->SetFocus();
+ return -1;
+ }
+
+ LPBYTE pBuf;
+ NET_API_STATUS nAPI = NetUserModalsGet(
+ pServer,
+ 0,
+ &pBuf);
+
+ PUSER_MODALS_INFO_0 pModals = (PUSER_MODALS_INFO_0)pBuf;
+
+ if (nAPI != NERR_Success)
+ {
+ AfxMessageBox(IDS_BAD_GETMODALS);
+ ExitProcess(1);
+ }
+
+ if (m_csPassword1.GetLength() < (int)pModals->usrmod0_min_passwd_len)
+ {
+ CString csMin;
+ csMin.Format(IDS_PW_TOOSHORT,
+ pModals->usrmod0_min_passwd_len);
+
+ AfxMessageBox(csMin);
+ GetDlgItem(IDC_PASSWORD1)->SetFocus();
+ return -1;
+ }
+
+ pApp->m_csPassword1 = m_csPassword1;
+ m_csPassword1 = L"";
+
+ if (m_nPWOptions == 0 && m_bNeverExpirePW) AfxMessageBox(IDS_WONT_REQUIRE);
+
+
+ pApp->m_bPW_Never_Expires = m_bNeverExpirePW;
+
+ if (m_nPWOptions == 0)
+ {
+ pApp->m_bMust_Change_PW = TRUE;
+ pApp->m_bChange_Password = TRUE;
+ }
+ else if (m_nPWOptions == 1)
+ {
+ pApp->m_bChange_Password = TRUE;
+ pApp->m_bMust_Change_PW = FALSE;
+ }
+
+ else pApp->m_bChange_Password = FALSE;
+
+ return CPropertyPage::OnWizardNext();
+
+}
+
+
+void CPasswordInfo::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CWizBaseDlg::OnShowWindow(bShow, nStatus);
+
+ if (bShow)
+ {
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+ CString csTemp;
+ csTemp.LoadString(IDS_PASSWORD_CAPTION);
+
+ CString csTemp2;
+ csTemp2.Format(csTemp, pApp->m_csUserName);
+ m_csCaption = csTemp2;
+
+ if (pApp->m_bPWReset)
+ {
+ m_csPassword1 = L"";
+ m_csPassword2 = L"";
+ m_nPWOptions = 0;
+ m_bNeverExpirePW = FALSE;
+ pApp->m_bPWReset = FALSE;
+ }
+ UpdateData(FALSE);
+ }
+
+}
+
+void CPasswordInfo::OnChangePassword1()
+{
+ UpdateData(TRUE);
+
+ if (m_csPassword1.GetLength() > 14)
+ {
+ AfxMessageBox(IDS_PW_TOOLONG);
+ GetDlgItem(IDC_PASSWORD1)->SetFocus();
+ }
+
+}
+
+void CPasswordInfo::OnChangePassword2()
+{
+ UpdateData(TRUE);
+
+ if (m_csPassword2.GetLength() > 14)
+ {
+ AfxMessageBox(IDS_PW_TOOLONG);
+ GetDlgItem(IDC_PASSWORD2)->SetFocus();
+ }
+
+}
diff --git a/private/utils/wizards/addusrw/pwinfo.h b/private/utils/wizards/addusrw/pwinfo.h
new file mode 100644
index 000000000..f049b0cf1
--- /dev/null
+++ b/private/utils/wizards/addusrw/pwinfo.h
@@ -0,0 +1,56 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ PwInfo.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+/////////////////////////////////////////////////////////////////////////////
+// CPasswordInfo dialog
+class CPasswordInfo : public CWizBaseDlg
+{
+ DECLARE_DYNCREATE(CPasswordInfo)
+
+// Construction
+public:
+ CPasswordInfo();
+ ~CPasswordInfo();
+
+ LRESULT OnWizardNext();
+
+// Dialog Data
+ //{{AFX_DATA(CPasswordInfo)
+ enum { IDD = IDD_PASSWORD_INFO };
+ CString m_csPassword1;
+ CString m_csPassword2;
+ int m_nPWOptions;
+ BOOL m_bNeverExpirePW;
+ CString m_csCaption;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CPasswordInfo)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CPasswordInfo)
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ afx_msg void OnChangePassword1();
+ afx_msg void OnChangePassword2();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+};
diff --git a/private/utils/wizards/addusrw/rasperm.cpp b/private/utils/wizards/addusrw/rasperm.cpp
new file mode 100644
index 000000000..c2e82546a
--- /dev/null
+++ b/private/utils/wizards/addusrw/rasperm.cpp
@@ -0,0 +1,155 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ CRasPerm.cpp : implementation file
+
+ CPropertyPage support for User mgmt wizard
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+#include "stdafx.h"
+#include "Speckle.h"
+#include "wizbased.h"
+#include "RasPerm.h"
+#include <rassapi.h>
+
+#ifdef _DEBUG
+//#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CRasPerm property page
+
+IMPLEMENT_DYNCREATE(CRasPerm, CWizBaseDlg)
+
+CRasPerm::CRasPerm() : CWizBaseDlg(CRasPerm::IDD)
+{
+ //{{AFX_DATA_INIT(CRasPerm)
+ m_csRasPhoneNumber = _T("");
+ m_nCallBackRadio = 0;
+ m_csCaption = _T("");
+ //}}AFX_DATA_INIT
+}
+
+CRasPerm::~CRasPerm()
+{
+}
+
+void CRasPerm::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CRasPerm)
+ DDX_Text(pDX, IDC_RASPHONE_EDIT, m_csRasPhoneNumber);
+ DDX_Radio(pDX, IDC_CALL_BACK_RADIO, m_nCallBackRadio);
+ DDX_Text(pDX, IDC_STATIC1, m_csCaption);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CRasPerm, CWizBaseDlg)
+ //{{AFX_MSG_MAP(CRasPerm)
+ ON_WM_SHOWWINDOW()
+ ON_BN_CLICKED(IDC_RADIO3, OnRadio3)
+ ON_BN_CLICKED(IDC_RADIO2, OnRadio2)
+ ON_BN_CLICKED(IDC_CALL_BACK_RADIO, OnCallBackRadio)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CRasPerm message handlers
+LRESULT CRasPerm::OnWizardNext()
+{
+ UpdateData(TRUE);
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+ if ((m_nCallBackRadio == 2) && (m_csRasPhoneNumber == L""))
+ {
+ AfxMessageBox(IDS_NO_RAS_NUMBER);
+ return -1;
+ }
+
+// check for invalid phone number
+ if (m_nCallBackRadio == 2)
+ {
+ if (m_csRasPhoneNumber.GetLength() > RASSAPI_MAX_PHONENUMBER_SIZE)
+ {
+ AfxMessageBox(IDS_RAS_NUMBER_TOO_LONG);
+ GetDlgItem(IDC_RASPHONE_EDIT)->SetFocus();
+ return -1;
+ }
+
+ TCHAR* pNum = m_csRasPhoneNumber.GetBuffer(m_csRasPhoneNumber.GetLength());
+ TCHAR pValid[] = {L"0123456789TPW()@- "};
+
+ if (_tcsspnp(pNum, pValid) != NULL)
+ {
+ AfxMessageBox(IDS_BAD_RAS_NUMBER);
+ GetDlgItem(IDC_RASPHONE_EDIT)->SetFocus();
+ return -1;
+ }
+ }
+
+ pApp->m_csRasPhoneNumber = m_csRasPhoneNumber;
+ pApp->m_sCallBackType = m_nCallBackRadio;
+
+ if (pApp->m_bNW) return IDD_FPNW_DLG;
+ else if (pApp->m_bExchange) return IDD_EXCHANGE_DIALOG;
+ else return IDD_RESTRICTIONS_DIALOG;
+
+}
+
+LRESULT CRasPerm::OnWizardBack()
+{
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+ if (pApp->m_bHomeDir) return IDD_HOMEDIR_DIALOG;
+ else if (pApp->m_bLoginScript) return IDD_LOGON_SCRIPT_DIALOG;
+ else if (pApp->m_bProfile) return IDD_PROFILE;
+ else return IDD_OPTIONS_DIALOG;
+
+}
+
+void CRasPerm::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CWizBaseDlg::OnShowWindow(bShow, nStatus);
+ if (bShow)
+ {
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+ CString csTemp;
+ csTemp.LoadString(IDS_RAS_CAPTION);
+
+ CString csTemp2;
+ csTemp2.Format(csTemp, pApp->m_csUserName);
+ m_csCaption = csTemp2;
+ UpdateData(FALSE);
+ }
+
+}
+
+void CRasPerm::OnRadio3()
+{
+ GetDlgItem(IDC_RASPHONE_EDIT)->EnableWindow(TRUE);
+ GetDlgItem(IDC_RASPHONE_EDIT)->SetFocus();
+
+}
+
+void CRasPerm::OnRadio2()
+{
+ GetDlgItem(IDC_RASPHONE_EDIT)->EnableWindow(FALSE);
+
+}
+
+void CRasPerm::OnCallBackRadio()
+{
+ GetDlgItem(IDC_RASPHONE_EDIT)->EnableWindow(FALSE);
+
+}
diff --git a/private/utils/wizards/addusrw/rasperm.h b/private/utils/wizards/addusrw/rasperm.h
new file mode 100644
index 000000000..c239222a2
--- /dev/null
+++ b/private/utils/wizards/addusrw/rasperm.h
@@ -0,0 +1,58 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ RasPerm.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CRasPerm dialog
+
+class CRasPerm : public CWizBaseDlg
+{
+ DECLARE_DYNCREATE(CRasPerm)
+
+// Construction
+public:
+ CRasPerm();
+ ~CRasPerm();
+
+// Dialog Data
+ //{{AFX_DATA(CRasPerm)
+ enum { IDD = IDD_RAS_PERM_DIALOG };
+ CString m_csRasPhoneNumber;
+ int m_nCallBackRadio;
+ CString m_csCaption;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CRasPerm)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+ LRESULT OnWizardNext();
+ LRESULT OnWizardBack();
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CRasPerm)
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ afx_msg void OnRadio3();
+ afx_msg void OnRadio2();
+ afx_msg void OnCallBackRadio();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+};
diff --git a/private/utils/wizards/addusrw/res/bitmap1.bmp b/private/utils/wizards/addusrw/res/bitmap1.bmp
new file mode 100644
index 000000000..3643a9d03
--- /dev/null
+++ b/private/utils/wizards/addusrw/res/bitmap1.bmp
Binary files differ
diff --git a/private/utils/wizards/addusrw/res/endflag.bmp b/private/utils/wizards/addusrw/res/endflag.bmp
new file mode 100644
index 000000000..2deab795c
--- /dev/null
+++ b/private/utils/wizards/addusrw/res/endflag.bmp
Binary files differ
diff --git a/private/utils/wizards/addusrw/res/global.bmp b/private/utils/wizards/addusrw/res/global.bmp
new file mode 100644
index 000000000..aab380fbf
--- /dev/null
+++ b/private/utils/wizards/addusrw/res/global.bmp
Binary files differ
diff --git a/private/utils/wizards/addusrw/res/global_g.bmp b/private/utils/wizards/addusrw/res/global_g.bmp
new file mode 100644
index 000000000..aab380fbf
--- /dev/null
+++ b/private/utils/wizards/addusrw/res/global_g.bmp
Binary files differ
diff --git a/private/utils/wizards/addusrw/res/group.bmp b/private/utils/wizards/addusrw/res/group.bmp
new file mode 100644
index 000000000..c0886c97f
--- /dev/null
+++ b/private/utils/wizards/addusrw/res/group.bmp
Binary files differ
diff --git a/private/utils/wizards/addusrw/res/net_tree.bmp b/private/utils/wizards/addusrw/res/net_tree.bmp
new file mode 100644
index 000000000..89a17b4d2
--- /dev/null
+++ b/private/utils/wizards/addusrw/res/net_tree.bmp
Binary files differ
diff --git a/private/utils/wizards/addusrw/res/speckle.ico b/private/utils/wizards/addusrw/res/speckle.ico
new file mode 100644
index 000000000..1cdd35abc
--- /dev/null
+++ b/private/utils/wizards/addusrw/res/speckle.ico
Binary files differ
diff --git a/private/utils/wizards/addusrw/res/speckle.rc2 b/private/utils/wizards/addusrw/res/speckle.rc2
new file mode 100644
index 000000000..d110b38b6
--- /dev/null
+++ b/private/utils/wizards/addusrw/res/speckle.rc2
@@ -0,0 +1,26 @@
+//
+// SPECKLE.RC2 - resources Microsoft Visual C++ does not edit directly
+//
+
+#ifdef APSTUDIO_INVOKED
+ #error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Add manually edited resources here...
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version resources
+//
+#include <winver.h>
+#include <ntverp.h>
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "user account management wizard"
+#define VER_INTERNALNAME_STR "speckle.exe"
+#define VER_ORIGINALFILENAME_STR "addusrw.exe"
+#include <common.ver>
+
+
diff --git a/private/utils/wizards/addusrw/res/user.bmp b/private/utils/wizards/addusrw/res/user.bmp
new file mode 100644
index 000000000..b615d743c
--- /dev/null
+++ b/private/utils/wizards/addusrw/res/user.bmp
Binary files differ
diff --git a/private/utils/wizards/addusrw/res/user_bit.bmp b/private/utils/wizards/addusrw/res/user_bit.bmp
new file mode 100644
index 000000000..b615d743c
--- /dev/null
+++ b/private/utils/wizards/addusrw/res/user_bit.bmp
Binary files differ
diff --git a/private/utils/wizards/addusrw/res/world.bmp b/private/utils/wizards/addusrw/res/world.bmp
new file mode 100644
index 000000000..d4c1f2a31
--- /dev/null
+++ b/private/utils/wizards/addusrw/res/world.bmp
Binary files differ
diff --git a/private/utils/wizards/addusrw/resource.h b/private/utils/wizards/addusrw/resource.h
new file mode 100644
index 000000000..f1e37afcd
--- /dev/null
+++ b/private/utils/wizards/addusrw/resource.h
@@ -0,0 +1,244 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by speckle.rc
+//
+#define IDS_GENERIC_NO_HEAP 1
+#define IDS_GENERIC_NO_PDC 2
+#define IDS_GENERIC_BAD_MACHINE 3
+#define IDS_NO_GROUP_NAME 4
+#define IDS_GROUP_INVALID_NAME 5
+#define IDS_DOMAIN_SET 6
+#define IDS_TREE_ROOT 7
+#define IDS_NET_ERROR 8
+#define IDS_NET_NO_SERVERS 9
+#define IDS_ERROR 10
+#define IDS_GROUP_EXISTS 11
+#define IDS_INSUFFICIENT_PERMISSION 12
+#define IDS_CANT_ADD_NAMES 13
+#define IDS_LOCAL_GROUP 14
+#define IDS_GLOBAL_GROUP 15
+#define IDS_NO_MACHINE_NAME 16
+#define IDS_NO_VALID_WORKSTATIONS 17
+#define IDS_NO_NEW_USER 18
+#define IDS_BAD_USER_DATA 19
+#define IDS_NO_LOCAL_GROUP 20
+#define IDS_NO_GLOBAL_GROUP 21
+#define IDD_SPECKLE_DIALOG 102
+#define IDD_RAS_PERM_DIALOG 102
+#define IDR_MAINFRAME 128
+#define IDD_BASE_DIALOG 129
+#define IDB_BITMAP1 130
+#define IDD_WELCOME_DIALOG 131
+#define IDD_LOCAL_REMOTE 132
+#define IDD_REMOTE_NAME 133
+#define IDD_USER_NAME 134
+#define IDB_USER_BITMAP 134
+#define IDD_PASSWORD_INFO 135
+#define IDB_GLOBAL_GROUP_BITMAP 136
+#define IDD_GROUP_INFO 138
+#define IDB_NET_TREE 138
+#define IDD_PROFILE 139
+#define IDB_USER_BITMAP1 139
+#define IDD_FINISH 140
+#define IDD_FPNW_DLG 142
+#define IDB_LOCAL_GROUP_BITMAP 143
+#define IDB_WORLD 144
+#define IDD_ADD_NWWKS_DIALOG 145
+#define IDD_ACCOUNT_EXP_DIALOG 146
+#define IDD_OPTIONS_DIALOG 148
+#define IDD_HOMEDIR_DIALOG 150
+#define IDD_LOGON_SCRIPT_DIALOG 151
+#define IDD_RESTRICTIONS_DIALOG 152
+#define IDD_NWLOGON_DIALOG 153
+#define IDD_EXCHANGE_DIALOG 154
+#define IDD_ADD_WKS_DIALOG 155
+#define IDB_ENDFLAG 156
+#define IDD_HOURS_DLG 164
+#define IDD_LOGONTO_DLG 165
+#define IDC_PAINT_BOX 1000
+#define IDC_RADIO_LOCAL 1001
+#define IDC_RADIO_REMOTE 1002
+#define IDC_REMOTE_SERVER 1003
+#define IDC_USERNAME 1004
+#define IDC_FULLNAME 1005
+#define IDC_DESCRIPTION 1006
+#define IDC_LOCATION 1007
+#define IDC_MUST_CHANGE_PASSWORD 1010
+#define IDC_CANNOT_CHANGE_PASSWORD 1011
+#define IDC_PASSWORD_NEVER_EXPIRES 1012
+#define IDC_ACCOUNT_DISABLED 1013
+#define IDC_PASSWORD1 1015
+#define IDC_PASSWORD2 1016
+#define IDC_AVAILABLE_GROUPS 1017
+#define IDC_SELECTED_GROUPS 1018
+#define IDC_GROUP_MEMBER_LIST 1018
+#define IDC_ADD_GROUP 1019
+#define IDC_GROUP_AVAILABLE_LIST 1019
+#define IDC_REMOVE_GROUP 1020
+#define IDC_ADD_BUTTON 1020
+#define IDC_LOGON_SCRIPT 1021
+#define IDC_REMOVE_BUTTON 1021
+#define IDC_LOCAL_PATH_BUTTON 1022
+#define IDC_LOCALPATH_TEXT 1023
+#define IDC_REMOTE_PATH_BUTTON 1024
+#define IDC_DRIVE_LETTER 1026
+#define IDC_REMOTE_PATH 1027
+#define IDC_DIALIN_CHECK 1028
+#define IDC_CALL_BACK_RADIO 1029
+#define IDC_RADIO2 1030
+#define IDC_RADIO3 1031
+#define IDC_RASPHONE_EDIT 1032
+#define IDC_EXPIRE_NW_PASSWORD 1033
+#define IDC_GRACE_LOGIN_RADIO 1034
+#define IDC_ALLOWED_GRACE_LOGINS_EDIT 1035
+#define IDC_GRACE_LOGIN_SPIN 1036
+#define IDC_REMAINING_GRACE_LOGINS_EDIT 1037
+#define IDC_CONCURRENT_CONNECTIONS_RADIO 1038
+#define IDC_CONCURRENT_CONNECTIONS_RADIO2 1039
+#define IDC_CONCURRENT_CONNNECTIONS_EDIT 1040
+#define IDC_CONNCURRENT_CONNECTIONS_SPIN 1041
+#define IDC_STATIC1 1042
+#define IDC_STATIC2 1043
+#define IDC_STATIC3 1044
+#define IDC_GRACE_LOGIN_RADIO2 1045
+#define IDC_NETTREE 1048
+#define IDC_NETTREE_EDIT 1049
+#define IDC_NWPATH_EDIT 1051
+#define IDC_PROFILE_PATH 1052
+#define IDC_NWLOGON_RADIO 1053
+#define IDC_NWLOGON_LIST 1054
+#define IDC_NWLOGON_RADIO2 1057
+#define IDC_NWSTATIC1 1058
+#define IDC_NWSTATIC2 1059
+#define IDC_NETWORK_ADDRESS_EDIT 1060
+#define IDC_AVAILABLE_TIMES 1061
+#define IDC_NODE_ADDRESS_EDIT 1061
+#define IDC_SU_BUTTON 1064
+#define IDC_DAY_EDIT 1064
+#define IDC_MONTH_EDIT 1065
+#define IDC_YEAR_EDIT 1066
+#define IDC_WHERE_LOGON_RADIO 1068
+#define IDC_DATE_SPIN 1068
+#define IDC_LOCATION_EDIT1 1069
+#define IDC_M_BUTTON 1069
+#define IDC_LOCATION_EDIT2 1070
+#define IDC_TU_BUTTON 1070
+#define IDC_LOCATION_EDIT3 1071
+#define IDC_W_BUTTON 1071
+#define IDC_LOCATION_EDIT4 1072
+#define IDC_TH_BUTTON 1072
+#define IDC_LOCATION_EDIT5 1073
+#define IDC_F_BUTTON 1073
+#define IDC_NW_CHECK 1073
+#define IDC_LOCATION_EDIT6 1074
+#define IDC_SA_BUTTON 1074
+#define IDC_RAS_CHECK 1074
+#define IDC_LOCATION_EDIT7 1075
+#define IDC_LOCATION_EDIT8 1076
+#define IDC_STATIC4 1078
+#define IDC_PROFILE_CHECK 1078
+#define IDC_STATIC5 1079
+#define IDC_STATIC6 1080
+#define IDC_STATIC7 1081
+#define IDC_STATIC8 1082
+#define IDC_WHERE_LOGON_RADIO2 1083
+#define IDC_DOMAIN_LIST 1090
+#define IDC_PWOPTIONS_RADIO 1091
+#define IDC_EXPIREPW_CHECK 1092
+#define IDC_BROWSE_BUTTON 1093
+#define IDC_LOGIN_SCRIPT_CHECK 1094
+#define IDC_HOMEDIR_CHECK 1095
+#define IDC_EXCHANGE_CHECK 1096
+#define IDC_RESTRICTIONS_RADIO 1097
+#define IDC_RESTRICTIONS_RADIO2 1098
+#define IDC_ACCOUNT_EXPIRE_CHECK 1099
+#define IDC_LOGIN_TIMES_CHECK 1100
+#define IDC_WORKSTATIONS_CHECK 1101
+#define IDC_PRIMARY_GROUP 1102
+#define IDC_DISABLED_CHECK 1102
+#define IDC_SET_PRIMARY_GROUP_BUTTON 1103
+#define IDC_LIST1 1103
+#define IDC_CONCURRENT_CONNECTIONS_RADIO1 1106
+#define IDC_CONCURRENT_CONNECTIONS_EDIT 1107
+#define IDC_CONCURRENT_CONNECTIONS_SPIN 1109
+#define IDC_WORKSTATION_EDIT 1110
+#define IDC_RADIO1 1113
+#define IDC_WORKSTATION_RADIO 1113
+#define IDC_BUTTON1 1114
+#define IDC_COMBO2 1117
+#define IDC_WORKSTATION_RADIO2 1118
+#define IDC_STATIC_ALLOWEDTIMES 1119
+#define IDC_STATIC_DISALLOWEDTIMES 1120
+#define IDC_SERVER_LIST 1121
+#define IDC_STATIC_FRAME 1124
+#define IDC_STATIC_DOMAIN 1130
+#define IDC_SERVERNAME_EDIT 1131
+#define IDC_HOURSCTRL1 1132
+#define IDS_BAD_VERSION 57345
+#define IDS_WELCOME_STRING 57346
+#define IDS_PASSWORD_CAPTION 57347
+#define IDS_FINISH_CAPTION 57348
+#define IDS_OPTION_CAPTION 57349
+#define IDS_FPNW_CAPTION 57350
+#define IDS_GROUP_CAPTION 57351
+#define IDS_RAS_CAPTION 57352
+#define IDS_WORKSTATION_CAPTION 57353
+#define IDS_HOMEDIR_CAPTION 57354
+#define IDS_RESTRICTION_CAPTION 57355
+#define IDS_NWLOGON_CAPTION 57356
+#define IDS_SUCCESS 57357
+#define IDS_NW_PW_ERROR 57358
+#define IDS_NW_GRACELOGIN_ERROR 57359
+#define IDS_NW_CONCON_ERROR 57360
+#define IDS_RAS_ERROR 57361
+#define IDS_NEEDA_WORKSTATION 57362
+#define IDS_NEED_ADDRESS 57363
+#define IDS_UNKNOWN_COMPONENTS 57364
+#define IDS_BAD_WS_NAME 57365
+#define IDS_BAD_USERNAME 57366
+#define IDS_DUPLICATE_NAME 57367
+#define IDS_PW_NOMATCH 57368
+#define IDS_PW_TOOLONG 57369
+#define IDS_BAD_GETMODALS 57370
+#define IDS_PW_TOOSHORT 57371
+#define IDS_NODC 57372
+#define IDS_NO_USERNAME 57373
+#define IDS_USERNAME_TOOLONG 57374
+#define IDS_NOFP_WS 57375
+#define IDS_ALL_NODES 57376
+#define IDS_NOT_ADMIN 57377
+#define IDS_WSNAME_TOOLONG 57378
+#define IDS_INVALID_DAY 57379
+#define IDS_INVALID_MONTH 57380
+#define IDS_INVALID_YEAR 57381
+#define IDS_BAD_NWADDRESS 57382
+#define IDS_BAD_NWNODE 57383
+#define IDS_TOOLONG_NWADDRESS 57384
+#define IDS_TOOLONG_NWNODE 57385
+#define IDS_ALREADY_EXPIRED 57386
+#define IDS_INVALID_DIRECTORY_NAME 57388
+#define IDS_NO_DIR_PERMISSION 57389
+#define IDS_CANT_CREATE_DIRECTORY 57390
+#define IDS_INVALID_PATH 57391
+#define IDS_NEW_DIR_CREATED 57392
+#define IDS_SUCCESS2 57393
+#define IDS_WONT_REQUIRE 57394
+#define IDS_BAD_USER_DATA2 57395
+#define IDC_NO_WKSALLOWED 57396
+#define IDS_NO_HOMEDIR_DRIVE_LETTER 57397
+#define IDS_NO_RAS_NUMBER 57398
+#define IDS_NO_EXCH_SERVER 57399
+#define IDS_BAD_RAS_NUMBER 57400
+#define IDS_RAS_NUMBER_TOO_LONG 57401
+#define IDS_INVALID_GL_NUMBER 57402
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 158
+#define _APS_NEXT_COMMAND_VALUE 32771
+#define _APS_NEXT_CONTROL_VALUE 1133
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/private/utils/wizards/addusrw/restrct.cpp b/private/utils/wizards/addusrw/restrct.cpp
new file mode 100644
index 000000000..1b3e4995d
--- /dev/null
+++ b/private/utils/wizards/addusrw/restrct.cpp
@@ -0,0 +1,190 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Restrct.cpp : implementation file
+
+ CPropertyPage support for User mgmt wizard
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+//
+//
+
+#include "stdafx.h"
+#include "speckle.h"
+#include "wizbased.h"
+#include "Restrct.h"
+
+#ifdef _DEBUG
+//#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CRestrictions property page
+
+IMPLEMENT_DYNCREATE(CRestrictions, CWizBaseDlg)
+
+CRestrictions::CRestrictions() : CWizBaseDlg(CRestrictions::IDD)
+{
+ //{{AFX_DATA_INIT(CRestrictions)
+ m_bAccountExpire = FALSE;
+ m_bAccountDisabled = FALSE;
+ m_bLoginTimes = FALSE;
+ m_bLimitWorkstations = FALSE;
+ m_nRestrictions = 0;
+ m_csCaption = _T("");
+ //}}AFX_DATA_INIT
+
+ m_bEnable = FALSE;
+ m_bHours = FALSE;
+
+}
+
+CRestrictions::~CRestrictions()
+{
+}
+
+void CRestrictions::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CRestrictions)
+ DDX_Check(pDX, IDC_ACCOUNT_EXPIRE_CHECK, m_bAccountExpire);
+ DDX_Check(pDX, IDC_DISABLED_CHECK, m_bAccountDisabled);
+ DDX_Check(pDX, IDC_LOGIN_TIMES_CHECK, m_bLoginTimes);
+ DDX_Check(pDX, IDC_WORKSTATIONS_CHECK, m_bLimitWorkstations);
+ DDX_Radio(pDX, IDC_RESTRICTIONS_RADIO, m_nRestrictions);
+ DDX_Text(pDX, IDC_STATIC1, m_csCaption);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CRestrictions, CWizBaseDlg)
+ //{{AFX_MSG_MAP(CRestrictions)
+ ON_BN_CLICKED(IDC_RESTRICTIONS_RADIO, OnRestrictionsRadio)
+ ON_BN_CLICKED(IDC_RESTRICTIONS_RADIO2, OnRestrictionsRadio2)
+ ON_WM_SHOWWINDOW()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CRestrictions message handlers
+
+LRESULT CRestrictions::OnWizardBack()
+{
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+ if (pApp->m_bExchange) return IDD_EXCHANGE_DIALOG;
+ else if (pApp->m_bNW) return IDD_FPNW_DLG;
+ else if (pApp->m_bRAS) return IDD_RAS_PERM_DIALOG;
+ else if (pApp->m_bHomeDir) return IDD_HOMEDIR_DIALOG;
+ else if (pApp->m_bLoginScript) return IDD_LOGON_SCRIPT_DIALOG;
+ else if (pApp->m_bProfile) return IDD_PROFILE;
+ else return IDD_OPTIONS_DIALOG;
+
+}
+
+LRESULT CRestrictions::OnWizardNext()
+{
+ UpdateData(TRUE);
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+ pApp->m_bEnableRestrictions = m_bEnable;
+ pApp->m_bExpiration = m_bAccountExpire & m_bEnable;
+ pApp->m_bDisabled = m_bAccountDisabled & m_bEnable;
+ pApp->m_bHours = m_bLoginTimes & m_bEnable;
+ pApp->m_bWorkstation = m_bLimitWorkstations & m_bEnable;
+
+ if (m_bAccountExpire & m_bEnable) return IDD_ACCOUNT_EXP_DIALOG;
+ else if (m_bLoginTimes & m_bEnable) return IDD_HOURS_DLG;
+ else if (m_bLimitWorkstations & m_bEnable) return IDD_LOGONTO_DLG;
+ else if (pApp->m_bNW & m_bEnable) return IDD_NWLOGON_DIALOG;
+ else return IDD_FINISH;
+
+ return CWizBaseDlg::OnWizardNext();
+
+}
+
+void CRestrictions::OnRestrictionsRadio()
+{
+ GetDlgItem(IDC_ACCOUNT_EXPIRE_CHECK)->EnableWindow(FALSE);
+ GetDlgItem(IDC_DISABLED_CHECK)->EnableWindow(FALSE);
+ GetDlgItem(IDC_LOGIN_TIMES_CHECK)->EnableWindow(FALSE);
+ GetDlgItem(IDC_WORKSTATIONS_CHECK)->EnableWindow(FALSE);
+
+ m_bEnable = FALSE;
+
+}
+
+void CRestrictions::OnRestrictionsRadio2()
+{
+ GetDlgItem(IDC_ACCOUNT_EXPIRE_CHECK)->EnableWindow(TRUE);
+ GetDlgItem(IDC_DISABLED_CHECK)->EnableWindow(TRUE);
+ GetDlgItem(IDC_LOGIN_TIMES_CHECK)->EnableWindow(m_bHours);
+ GetDlgItem(IDC_WORKSTATIONS_CHECK)->EnableWindow(TRUE);
+
+ m_bEnable = TRUE;
+
+}
+
+void CRestrictions::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CWizBaseDlg::OnShowWindow(bShow, nStatus);
+
+ if (bShow)
+ {
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+ CString csTemp;
+ csTemp.LoadString(IDS_RESTRICTION_CAPTION);
+
+ CString csTemp2;
+ csTemp2.Format(csTemp, pApp->m_csUserName);
+ m_csCaption = csTemp2;
+ UpdateData(FALSE);
+ }
+
+}
+
+BOOL CRestrictions::OnInitDialog()
+{
+ CWizBaseDlg::OnInitDialog();
+
+ CString csPath;
+ TCHAR pDir[256];
+ GetSystemDirectory(pDir, 256);
+ csPath = pDir;
+ csPath += L"\\hours.ocx";
+
+ HINSTANCE hLib = LoadLibrary((LPCTSTR)csPath);
+
+ if (hLib < (HINSTANCE)HINSTANCE_ERROR)
+ {
+ m_bHours = FALSE; //unable to load DLL
+ return TRUE;
+ }
+
+ // Find the entry point.
+ FARPROC lpDllEntryPoint = NULL;
+ (FARPROC&)lpDllEntryPoint = GetProcAddress(hLib,
+ "DllRegisterServer");
+ if (lpDllEntryPoint != NULL)
+ {
+ HRESULT h = (*lpDllEntryPoint)();
+ if (h == 0) m_bHours = TRUE;
+ else m_bHours = FALSE;
+ }
+ else
+ m_bHours = FALSE;
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
diff --git a/private/utils/wizards/addusrw/restrct.h b/private/utils/wizards/addusrw/restrct.h
new file mode 100644
index 000000000..36429536b
--- /dev/null
+++ b/private/utils/wizards/addusrw/restrct.h
@@ -0,0 +1,63 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Restrct.h : header file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+/////////////////////////////////////////////////////////////////////////////
+// CRestrictions dialog
+
+class CRestrictions : public CWizBaseDlg
+{
+ DECLARE_DYNCREATE(CRestrictions)
+
+// Construction
+public:
+ CRestrictions();
+ ~CRestrictions();
+
+// Dialog Data
+ //{{AFX_DATA(CRestrictions)
+ enum { IDD = IDD_RESTRICTIONS_DIALOG };
+ BOOL m_bAccountExpire;
+ BOOL m_bAccountDisabled;
+ BOOL m_bLoginTimes;
+ BOOL m_bLimitWorkstations;
+ int m_nRestrictions;
+ CString m_csCaption;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CRestrictions)
+ public:
+ virtual LRESULT OnWizardBack();
+ virtual LRESULT OnWizardNext();
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CRestrictions)
+ afx_msg void OnRestrictionsRadio();
+ afx_msg void OnRestrictionsRadio2();
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ virtual BOOL OnInitDialog();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+private:
+ BOOL m_bEnable;
+ BOOL m_bHours;
+};
diff --git a/private/utils/wizards/addusrw/rpcbak.h b/private/utils/wizards/addusrw/rpcbak.h
new file mode 100644
index 000000000..47c66b17e
--- /dev/null
+++ b/private/utils/wizards/addusrw/rpcbak.h
@@ -0,0 +1,225 @@
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+/* File created by MIDL compiler version 2.00.0102 */
+/* at Thu Apr 11 13:52:52 1996
+ */
+//@@MIDL_FILE_HEADING( )
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __rpcbak_h__
+#define __rpcbak_h__
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+/* Forward Declarations */
+
+void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t);
+void __RPC_USER MIDL_user_free( void __RPC_FAR * );
+
+#ifndef __TriggerBackupRPC_INTERFACE_DEFINED__
+#define __TriggerBackupRPC_INTERFACE_DEFINED__
+
+/****************************************
+ * Generated header for interface: TriggerBackupRPC
+ * at Thu Apr 11 13:52:52 1996
+ * using MIDL 2.00.0102
+ ****************************************/
+/* [auto_handle][unique][version][uuid] */
+
+
+#ifndef RPC_COMMON_IDL
+#define RPC_COMMON_IDL
+#define szTriggerRPCProtocol TEXT("ncacn_np")
+#define szTriggerRPCSecurity TEXT("Security=impersonation dynamic true")
+ /* size is 4 */
+typedef long RPC_BOOL;
+
+ /* size is 1 */
+typedef small RPC_BYTE;
+
+ /* size is 4 */
+typedef long RPC_INT;
+
+ /* size is 4 */
+typedef long RPC_SC;
+
+ /* size is 4 */
+typedef long RPC_EC;
+
+ /* size is 4 */
+typedef long RPC_DWORD;
+
+ /* size is 2 */
+typedef wchar_t RPC_CHAR;
+
+ /* size is 4 */
+typedef /* [string] */ RPC_CHAR __RPC_FAR *RPC_SZ;
+
+ /* size is 16 */
+typedef struct __MIDL_TriggerBackupRPC_0001
+ {
+ short rgwSystemTime[ 8 ];
+ } RPC_SYSTEMTIME;
+
+ /* size is 172 */
+typedef struct __MIDL_TriggerBackupRPC_0002
+ {
+ RPC_BYTE rgbTzi[ 172 ];
+ } RPC_TIME_ZONE_INFORMATION;
+
+ /* size is 28 */
+typedef struct __MIDL_TriggerBackupRPC_0003
+ {
+ long rgdwServiceStatus[ 7 ];
+ } RPC_SERVICE_STATUS;
+
+#define ecOK 0 // no error
+#define ecGeneralFailure 50001 // a failure occurred that caused proxy generation to stop
+#define ecSomeProxiesFailed 50002 // some proxies failed to get generated
+#define ecTargetNotValid 50003 // supplied target address not valid
+#define ecTargetNotUnique 50004 // supplied target address not unique
+#define ecProxyDLLNotImplemented 50005 // not implemented yet
+#define ecProxyDLLOOM 50006 // memory allocation error
+#define ecProxyDLLError 50007 // general error
+#define ecProxyDLLProtocol 50008 // protocol error
+#define ecProxyDLLSyntax 50009 // syntax error
+#define ecProxyDLLEOF 50010 // end of file
+#define ecProxyDLLSoftware 50011 // error in software
+#define ecProxyDLLConfig 50012 // configuration error
+#define ecProxyDLLContention 50013 // contention error
+#define ecProxyDLLNotFound 50014 // not found
+#define ecProxyDLLDiskSpace 50015 // out of disk space
+#define ecProxyDLLException 50016 // exception thrown
+#define ecProxyDLLDefault 50017 // unknown error
+#define ecProxyNotValid 50018 // supplied proxy not valid
+#define ecProxyNotUnique 50019 // supplied proxy not unique or unable to generate a unique proxy
+#define ecProxyDuplicate 50020 // a primary proxy of the same type was also supplied
+ /* size is 16 */
+typedef struct _PROXYNODE
+ {
+ struct _PROXYNODE __RPC_FAR *pnodeNext;
+ RPC_SZ wszProxy;
+ RPC_EC ec;
+ RPC_SZ wszDN;
+ } PROXYNODE;
+
+ /* size is 4 */
+typedef struct _PROXYNODE __RPC_FAR *PPROXYNODE;
+
+ /* size is 48 */
+typedef struct _PROXYINFO
+ {
+ RPC_BOOL fContinueOnError;
+ RPC_BOOL fIgnoreOldSecondaries;
+ RPC_SZ wszDN;
+ RPC_SZ wszNickName;
+ RPC_SZ wszCommonName;
+ RPC_SZ wszDisplayName;
+ RPC_SZ wszSurName;
+ RPC_SZ wszGivenName;
+ RPC_SZ wszInitials;
+ RPC_SZ wszTargetAddress;
+ PROXYNODE __RPC_FAR *pPNVerifyProxy;
+ PROXYNODE __RPC_FAR *pPNExcludeProxy;
+ } PROXYINFO;
+
+ /* size is 4 */
+typedef struct _PROXYINFO __RPC_FAR *PPROXYINFO;
+
+ /* size is 8 */
+typedef struct _PROXYLIST
+ {
+ PROXYNODE __RPC_FAR *__RPC_FAR *ppPNProxy;
+ PROXYNODE __RPC_FAR *__RPC_FAR *ppPNFailedProxyType;
+ } PROXYLIST;
+
+ /* size is 4 */
+typedef struct _PROXYLIST __RPC_FAR *PPROXYLIST;
+
+ /* size is 192 */
+typedef struct __MIDL_TriggerBackupRPC_0004
+ {
+ RPC_SYSTEMTIME st;
+ RPC_TIME_ZONE_INFORMATION tzi;
+ RPC_DWORD dwReturn;
+ } RemoteSystemTimeInfo;
+
+ /* size is 48 */
+typedef struct _RemoteServiceStatus
+ {
+ RPC_SC sc;
+ RPC_SZ szShortName;
+ RPC_SZ szDisplayName;
+ RPC_SZ szVersion;
+ RPC_SERVICE_STATUS ss;
+ struct _RemoteServiceStatus __RPC_FAR *prssNext;
+ } RemoteServiceStatus;
+
+#define rmsSuspendRepair 0x0001
+#define rmsSuspendNotif 0x0002
+ /* size is 24 */
+typedef struct _RemoteMaintenanceStatus
+ {
+ RPC_DWORD dwStatus;
+ RPC_SYSTEMTIME st;
+ RPC_SZ szUser;
+ } RemoteMaintenanceStatus;
+
+ /* size is 12 */
+typedef struct _BackupListNode
+ {
+ struct _BackupListNode __RPC_FAR *pnodeNext;
+ struct _BackupListNode __RPC_FAR *pnodeChildren;
+ RPC_SZ szName;
+ } BackupListNode;
+
+ /* size is 44 */
+typedef struct _DistributedLockOwner
+ {
+ RPC_CHAR rgchComputer[ 17 ];
+ RPC_DWORD dwPID;
+ RPC_DWORD dwTID;
+ } DistributedLockOwner;
+
+#define DLR_NO_WAIT 0x00000001
+#define cchMaxLockName 17
+ /* size is 84 */
+typedef struct _DistributedLockRequest
+ {
+ RPC_CHAR rgchLockName[ 17 ];
+ RPC_DWORD dwFlags;
+ DistributedLockOwner dlo;
+ } DistributedLockRequest;
+
+ /* size is 48 */
+typedef struct _DistributedLockReply
+ {
+ RPC_BOOL fGranted;
+ DistributedLockOwner dlo;
+ } DistributedLockReply;
+
+#endif // #ifndef RPC_COMMON_IDL
+ /* size is 4 */
+RPC_SC __cdecl ScGetBackupListNode(
+ /* [in] */ handle_t h,
+ /* [out][in] */ BackupListNode __RPC_FAR *__RPC_FAR *ppnode);
+
+
+
+extern RPC_IF_HANDLE TriggerBackupRPC_ClientIfHandle;
+extern RPC_IF_HANDLE TriggerBackupRPC_ServerIfHandle;
+#endif /* __TriggerBackupRPC_INTERFACE_DEFINED__ */
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/private/utils/wizards/addusrw/rpcpub.h b/private/utils/wizards/addusrw/rpcpub.h
new file mode 100644
index 000000000..fd831750c
--- /dev/null
+++ b/private/utils/wizards/addusrw/rpcpub.h
@@ -0,0 +1,387 @@
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+/* File created by MIDL compiler version 2.00.0102 */
+/* at Thu Apr 11 09:26:39 1996
+ */
+//@@MIDL_FILE_HEADING( )
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __rpcpub_h__
+#define __rpcpub_h__
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+/* Forward Declarations */
+
+void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t);
+void __RPC_USER MIDL_user_free( void __RPC_FAR * );
+
+#ifndef __TriggerPublicRPC_INTERFACE_DEFINED__
+#define __TriggerPublicRPC_INTERFACE_DEFINED__
+
+/****************************************
+ * Generated header for interface: TriggerPublicRPC
+ * at Thu Apr 11 09:26:39 1996
+ * using MIDL 2.00.0102
+ ****************************************/
+/* [auto_handle][unique][version][uuid] */
+
+
+#ifndef RPC_COMMON_IDL
+#define RPC_COMMON_IDL
+#define szTriggerRPCProtocol TEXT("ncacn_np")
+#define szTriggerRPCSecurity TEXT("Security=impersonation dynamic true")
+ /* size is 4 */
+typedef long RPC_BOOL;
+
+ /* size is 1 */
+typedef small RPC_BYTE;
+
+ /* size is 4 */
+typedef long RPC_INT;
+
+ /* size is 4 */
+typedef long RPC_SC;
+
+ /* size is 4 */
+typedef long RPC_EC;
+
+ /* size is 4 */
+typedef long RPC_DWORD;
+
+ /* size is 2 */
+typedef wchar_t RPC_CHAR;
+
+ /* size is 4 */
+typedef /* [string] */ RPC_CHAR __RPC_FAR *RPC_SZ;
+
+ /* size is 16 */
+typedef struct __MIDL_TriggerPublicRPC_0001
+ {
+ short rgwSystemTime[ 8 ];
+ } RPC_SYSTEMTIME;
+
+ /* size is 172 */
+typedef struct __MIDL_TriggerPublicRPC_0002
+ {
+ RPC_BYTE rgbTzi[ 172 ];
+ } RPC_TIME_ZONE_INFORMATION;
+
+ /* size is 28 */
+typedef struct __MIDL_TriggerPublicRPC_0003
+ {
+ long rgdwServiceStatus[ 7 ];
+ } RPC_SERVICE_STATUS;
+
+#define ecOK 0 // no error
+#define ecGeneralFailure 50001 // a failure occurred that caused proxy generation to stop
+#define ecSomeProxiesFailed 50002 // some proxies failed to get generated
+#define ecTargetNotValid 50003 // supplied target address not valid
+#define ecTargetNotUnique 50004 // supplied target address not unique
+#define ecProxyDLLNotImplemented 50005 // not implemented yet
+#define ecProxyDLLOOM 50006 // memory allocation error
+#define ecProxyDLLError 50007 // general error
+#define ecProxyDLLProtocol 50008 // protocol error
+#define ecProxyDLLSyntax 50009 // syntax error
+#define ecProxyDLLEOF 50010 // end of file
+#define ecProxyDLLSoftware 50011 // error in software
+#define ecProxyDLLConfig 50012 // configuration error
+#define ecProxyDLLContention 50013 // contention error
+#define ecProxyDLLNotFound 50014 // not found
+#define ecProxyDLLDiskSpace 50015 // out of disk space
+#define ecProxyDLLException 50016 // exception thrown
+#define ecProxyDLLDefault 50017 // unknown error
+#define ecProxyNotValid 50018 // supplied proxy not valid
+#define ecProxyNotUnique 50019 // supplied proxy not unique or unable to generate a unique proxy
+#define ecProxyDuplicate 50020 // a primary proxy of the same type was also supplied
+ /* size is 16 */
+typedef struct _PROXYNODE
+ {
+ struct _PROXYNODE __RPC_FAR *pnodeNext;
+ RPC_SZ wszProxy;
+ RPC_EC ec;
+ RPC_SZ wszDN;
+ } PROXYNODE;
+
+ /* size is 4 */
+typedef struct _PROXYNODE __RPC_FAR *PPROXYNODE;
+
+ /* size is 48 */
+typedef struct _PROXYINFO
+ {
+ RPC_BOOL fContinueOnError;
+ RPC_BOOL fIgnoreOldSecondaries;
+ RPC_SZ wszDN;
+ RPC_SZ wszNickName;
+ RPC_SZ wszCommonName;
+ RPC_SZ wszDisplayName;
+ RPC_SZ wszSurName;
+ RPC_SZ wszGivenName;
+ RPC_SZ wszInitials;
+ RPC_SZ wszTargetAddress;
+ PROXYNODE __RPC_FAR *pPNVerifyProxy;
+ PROXYNODE __RPC_FAR *pPNExcludeProxy;
+ } PROXYINFO;
+
+ /* size is 4 */
+typedef struct _PROXYINFO __RPC_FAR *PPROXYINFO;
+
+ /* size is 8 */
+typedef struct _PROXYLIST
+ {
+ PROXYNODE __RPC_FAR *__RPC_FAR *ppPNProxy;
+ PROXYNODE __RPC_FAR *__RPC_FAR *ppPNFailedProxyType;
+ } PROXYLIST;
+
+ /* size is 4 */
+typedef struct _PROXYLIST __RPC_FAR *PPROXYLIST;
+
+ /* size is 192 */
+typedef struct __MIDL_TriggerPublicRPC_0004
+ {
+ RPC_SYSTEMTIME st;
+ RPC_TIME_ZONE_INFORMATION tzi;
+ RPC_DWORD dwReturn;
+ } RemoteSystemTimeInfo;
+
+ /* size is 48 */
+typedef struct _RemoteServiceStatus
+ {
+ RPC_SC sc;
+ RPC_SZ szShortName;
+ RPC_SZ szDisplayName;
+ RPC_SZ szVersion;
+ RPC_SERVICE_STATUS ss;
+ struct _RemoteServiceStatus __RPC_FAR *prssNext;
+ } RemoteServiceStatus;
+
+#define rmsSuspendRepair 0x0001
+#define rmsSuspendNotif 0x0002
+ /* size is 24 */
+typedef struct _RemoteMaintenanceStatus
+ {
+ RPC_DWORD dwStatus;
+ RPC_SYSTEMTIME st;
+ RPC_SZ szUser;
+ } RemoteMaintenanceStatus;
+
+ /* size is 12 */
+typedef struct _BackupListNode
+ {
+ struct _BackupListNode __RPC_FAR *pnodeNext;
+ struct _BackupListNode __RPC_FAR *pnodeChildren;
+ RPC_SZ szName;
+ } BackupListNode;
+
+ /* size is 44 */
+typedef struct _DistributedLockOwner
+ {
+ RPC_CHAR rgchComputer[ 17 ];
+ RPC_DWORD dwPID;
+ RPC_DWORD dwTID;
+ } DistributedLockOwner;
+
+#define DLR_NO_WAIT 0x00000001
+#define cchMaxLockName 17
+ /* size is 84 */
+typedef struct _DistributedLockRequest
+ {
+ RPC_CHAR rgchLockName[ 17 ];
+ RPC_DWORD dwFlags;
+ DistributedLockOwner dlo;
+ } DistributedLockRequest;
+
+ /* size is 48 */
+typedef struct _DistributedLockReply
+ {
+ RPC_BOOL fGranted;
+ DistributedLockOwner dlo;
+ } DistributedLockReply;
+
+#endif // #ifndef RPC_COMMON_IDL
+ /* size is 4 */
+RPC_SC __cdecl ScNetworkTimingTest(
+ /* [in] */ handle_t h,
+ /* [in] */ long cbSend,
+ /* [size_is][in] */ small __RPC_FAR rgbSend[ ],
+ /* [in] */ long cbReceive,
+ /* [size_is][out] */ small __RPC_FAR rgbReceive[ ]);
+
+ /* size is 4 */
+RPC_SC __cdecl ScRunRID(
+ /* [in] */ handle_t h);
+
+ /* size is 4 */
+RPC_SC __cdecl ScRunRIDEx(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_BOOL fProxySpace,
+ /* [in] */ RPC_BOOL fGwart);
+
+ /* size is 4 */
+RPC_SC __cdecl ScRunDRACheck(
+ /* [in] */ handle_t h,
+ RPC_DWORD dw);
+
+#define BPTAdd 1
+#define BPTRemove 2
+#define BPTUpdate 3
+ /* size is 4 */
+RPC_SC __cdecl ScBulkCreateProxy(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_SZ szHeader,
+ /* [in] */ RPC_DWORD dwOptions);
+
+ /* size is 4 */
+RPC_SC __cdecl ScBulkCreateMultiProxy(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_INT cszHeader,
+ /* [size_is][in] */ RPC_SZ __RPC_FAR rgszRecipients[ ],
+ /* [in] */ RPC_DWORD dwOptions);
+
+ /* size is 4 */
+RPC_SC __cdecl ScBulkUpdateMultiProxy(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_INT cszSiteAddress,
+ /* [size_is][in] */ RPC_SZ __RPC_FAR rgszOldSiteAddress[ ],
+ /* [size_is][in] */ RPC_SZ __RPC_FAR rgszNewSiteAddress[ ],
+ /* [in] */ RPC_BOOL fSaveSiteAddress);
+
+ /* size is 4 */
+RPC_SC __cdecl ScGetBulkProxyStatus(
+ /* [in] */ handle_t h,
+ /* [out] */ RPC_SYSTEMTIME __RPC_FAR *pstTimeStart,
+ /* [out] */ RPC_DWORD __RPC_FAR *pdwTimeStart,
+ /* [out] */ RPC_DWORD __RPC_FAR *pdwTimeCur,
+ /* [out] */ RPC_INT __RPC_FAR *piRecipients,
+ /* [out] */ RPC_INT __RPC_FAR *pcRecipients);
+
+ /* size is 4 */
+RPC_SC __cdecl ScBulkProxyHalt(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_BOOL fWaitForShutdown);
+
+ /* size is 4 */
+RPC_EC __cdecl EcGetProxies(
+ /* [in] */ handle_t h,
+ /* [in] */ PPROXYINFO pProxyInfo,
+ /* [out][in] */ PPROXYLIST pProxyList);
+
+ /* size is 4 */
+RPC_SC __cdecl ScIsProxyUnique(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_SZ szProxy,
+ /* [out] */ RPC_BOOL __RPC_FAR *pfUnique,
+ /* [out] */ RPC_SZ __RPC_FAR *pszOwner);
+
+ /* size is 4 */
+RPC_SC __cdecl ScProxyValidate(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_SZ szProxy,
+ /* [out] */ RPC_BOOL __RPC_FAR *pfValid,
+ /* [out] */ RPC_SZ __RPC_FAR *pszProxyCorrected);
+
+ /* size is 4 */
+RPC_SC __cdecl ScSiteProxyValidate(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_SZ szSiteProxy,
+ /* [out] */ RPC_BOOL __RPC_FAR *pfValid,
+ /* [out] */ RPC_SZ __RPC_FAR *pszSiteProxyCorrected);
+
+ /* size is 4 */
+RPC_SC __cdecl ScProxyReset(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_BOOL fWaitUntilCompleted);
+
+#define scNoError 0
+#define scInvalidData 1
+#define scCannotLogData 2
+ /* size is 4 */
+RPC_SC __cdecl ScSaveTrackingData(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_INT cb,
+ /* [size_is][in] */ RPC_BYTE __RPC_FAR pb[ ],
+ /* [in] */ RPC_DWORD dwFlags);
+
+#define tevtMessageTransferIn 0
+#define tevtReportTransferIn 2
+#define tevtMessageSubmission 4
+#define tevtMessageTransferOut 7
+#define tevtReportTransferOut 8
+#define tevtMessageDelivery 9
+#define tevtReportDelivery 10
+#define tevtStartAssocByMTSUser 18
+#define tevtReleaseAssocByMTSUser 23
+#define tevtDLExpansion 26
+#define tevtRedirection 28
+#define tevtRerouting 29
+#define tevtDowngrading 31
+#define tevtReportAbsorption 33
+#define tevtReportGenerated 34
+#define tevtUnroutableReportDiscard 43
+#define tevtMessageLocalDelivery 1000
+#define tevtMessageBackboneTransferIn 1001
+#define tevtMessageBackboneTransferOut 1002
+#define tevtMessageGatewayTransferOut 1003
+#define tevtMessageGatewayTransferIn 1004
+#define tevtReportGatewayTransferIn 1005
+#define tevtReportGatewayTransferOut 1006
+#define tevtReportGatewayGenerated 1007
+#define tevtUserMin 2000
+ /* size is 60 */
+typedef struct __MIDL_TriggerPublicRPC_0005
+ {
+ RPC_INT nEventType;
+ RPC_SYSTEMTIME stEvent;
+ RPC_SZ szGatewayName;
+ RPC_SZ szPartner;
+ RPC_SZ szMTSID;
+ RPC_SZ szRemoteID;
+ RPC_SZ szOriginator;
+ RPC_INT nPriority;
+ RPC_INT nLength;
+ RPC_INT nSeconds;
+ RPC_INT nCost;
+ RPC_SZ szSubjectID;
+ } RPC_GATEWAY_TRACK_INFORMATION;
+
+ /* size is 4 */
+RPC_SC __cdecl ScSaveGatewayTrackingData(
+ /* [in] */ handle_t h,
+ /* [in] */ RPC_GATEWAY_TRACK_INFORMATION __RPC_FAR *pgti,
+ /* [in] */ RPC_INT cszRecipients,
+ /* [size_is][in] */ RPC_SZ __RPC_FAR rgszRecipients[ ]);
+
+
+
+extern RPC_IF_HANDLE TriggerPublicRPC_ClientIfHandle;
+extern RPC_IF_HANDLE TriggerPublicRPC_ServerIfHandle;
+#endif /* __TriggerPublicRPC_INTERFACE_DEFINED__ */
+
+/****************************************
+ * Generated header for interface: __MIDL__intf_0001
+ * at Thu Apr 11 09:26:39 1996
+ * using MIDL 2.00.0102
+ ****************************************/
+/* [local] */
+
+
+#define szTrackReportRecipientInfoDelivered L("\t0")
+#define szTrackReportRecipientInfoNonDelivered L("\t1")
+
+
+extern RPC_IF_HANDLE __MIDL__intf_0001_ClientIfHandle;
+extern RPC_IF_HANDLE __MIDL__intf_0001_ServerIfHandle;
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/private/utils/wizards/addusrw/sadapi.h b/private/utils/wizards/addusrw/sadapi.h
new file mode 100644
index 000000000..3f024ed0b
--- /dev/null
+++ b/private/utils/wizards/addusrw/sadapi.h
@@ -0,0 +1,197 @@
+/*
+ * sadapi.h
+ *
+ * Copyright (c) Microsoft Corp. 1986-1996. All Rights Reserved.
+ *
+ * Definition of the public RPC APIs from the SAD Exchange service
+ *
+ */
+
+
+#ifndef _SADLIB_H_
+#define _SADLIB_H_
+
+#include "rpcpub.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+/*
+ * Return codes for all functions except SAD_EcGetProxies() and SAD_EcGetProxiesBI().
+ * In addition to this list are all normal NT error codes...
+ */
+typedef enum _SC_RETURN_VALUES
+{
+ SC_OK = 0, // no error
+ SC_Error = 49001, // general error
+ SC_BPActive, // bulk proxy generation is currently running
+ SC_BPInactive, // bulk proxy generation is not currently running
+ SC_BPShutdownPending, // a shutdown in bulk proxy generation is in progress
+ SC_BPSiteAddressMismatch, // a Site Address Mismatch between rgszOldSiteAddress
+ // and rgszNewSiteAddress lists in ScBulkUpdateMultiProxy
+} SC_RETURN_VALUES;
+
+
+#define cchMaxServer (MAX_COMPUTERNAME_LENGTH + 1)
+
+typedef struct _RPCBINDINFO
+{
+ handle_t h;
+ WCHAR wszServer[cchMaxServer];
+ RPC_IF_HANDLE hClientIfHandle;
+} RPCBINDINFO, *PRPCBINDINFO;
+
+
+// Utility entry points
+RPC_SC WINAPI SAD_ScBindA(PRPCBINDINFO pBI, LPSTR szServer);
+RPC_SC WINAPI SAD_ScBindW(PRPCBINDINFO pBI, LPWSTR wszServer);
+void WINAPI SAD_Unbind(PRPCBINDINFO pBI);
+
+#ifdef UNICODE
+#define SAD_ScBind SAD_ScBindW
+#else
+#define SAD_ScBind SAD_ScBindA
+#endif
+
+
+
+// Message Tracking group
+RPC_SC WINAPI SAD_ScSaveGatewayTrackingData(PRPCBINDINFO pBI,
+ RPC_GATEWAY_TRACK_INFORMATION * pgti,
+ INT cszRecipients,
+ LPWSTR rgwszRecipients[]);
+
+// for Microsoft Internal Use ONLY
+RPC_SC WINAPI SAD_ScSaveTrackingData(PRPCBINDINFO pBI, INT cb, BYTE pb[], DWORD dwFlags);
+
+
+// for Gateways - cause the routing table to be recalculated
+RPC_SC WINAPI SAD_ScRunRIDA(LPSTR szServer);
+RPC_SC WINAPI SAD_ScRunRIDW(LPWSTR wszServer);
+RPC_SC WINAPI SAD_ScRunRIDExA(LPSTR szServer, RPC_BOOL fProxySpace, RPC_BOOL fGwart);
+RPC_SC WINAPI SAD_ScRunRIDExW(LPWSTR wszServer, RPC_BOOL fProxySpace, RPC_BOOL fGwart);
+
+#ifdef UNICODE
+#define SAD_ScRunRID SAD_ScRunRIDW
+#define SAD_ScRunRIDEx SAD_ScRunRIDExW
+#else
+#define SAD_ScRunRID SAD_ScRunRIDA
+#define SAD_ScRunRIDEx SAD_ScRunRIDExA
+#endif
+
+
+
+// Proxy Entry points
+
+RPC_EC WINAPI SAD_EcGetProxies(LPWSTR wszServer, PPROXYINFO pProxyInfo, PPROXYLIST pProxyList);
+RPC_EC WINAPI SAD_EcGetProxiesBI(PRPCBINDINFO pBI, PPROXYINFO pProxyInfo, PPROXYLIST pProxyList);
+void WINAPI SAD_FreeProxyListNode(PPROXYNODE pnode);
+RPC_SC WINAPI SAD_ScIsProxyUniqueA(LPSTR szServer,
+ LPSTR szProxy, RPC_BOOL * pfUnique, LPSTR * pszExisting);
+RPC_SC WINAPI SAD_ScIsProxyUniqueW(LPWSTR wszServer,
+ LPWSTR szProxy, RPC_BOOL * pfUnique, LPWSTR * pszExisting);
+
+// dwOptions values for SAD_ScBulkCreateProxy() and SAD_ScBulkCreateMultiProxy()
+#define BPTAdd 1
+#define BPTRemove 2
+#define BPTUpdate 3
+
+RPC_SC WINAPI SAD_ScBulkCreateProxyA(LPSTR szServer, LPSTR szHeader, DWORD dwOptions);
+RPC_SC WINAPI SAD_ScBulkCreateProxyW(LPWSTR wszServer, LPWSTR wszHeader, DWORD dwOptions);
+RPC_SC WINAPI SAD_ScBulkCreateMultiProxyA(LPSTR szServer,
+ INT cszHeader,
+ LPSTR rgszHeader[],
+ DWORD dwOptions);
+RPC_SC WINAPI SAD_ScBulkCreateMultiProxyW(LPWSTR wszServer,
+ INT cwszHeader,
+ LPWSTR rgwszHeader[],
+ DWORD dwOptions);
+RPC_SC WINAPI SAD_ScBulkUpdateMultiProxy(LPWSTR wszServer,
+ INT cwszSiteAddress,
+ LPWSTR rgwszOldSiteAddress[],
+ LPWSTR rgwszNewSiteAddress[],
+ RPC_BOOL fSaveSiteAddress);
+
+
+RPC_SC WINAPI SAD_ScGetBulkProxyStatusA(LPSTR szServer,
+ RPC_SYSTEMTIME * pstTimeStart,
+ DWORD * pdwTimeStart,
+ DWORD * pdwTimeCur,
+ INT * piRecipients,
+ INT * pcRecipients);
+RPC_SC WINAPI SAD_ScGetBulkProxyStatusW(LPWSTR wszServer,
+ RPC_SYSTEMTIME * pstTimeStart,
+ DWORD * pdwTimeStart,
+ DWORD * pdwTimeCur,
+ INT * piRecipients,
+ INT * pcRecipients);
+RPC_SC WINAPI SAD_ScBulkProxyHaltA(LPSTR szServer, RPC_BOOL fWaitForShutdown);
+RPC_SC WINAPI SAD_ScBulkProxyHaltW(LPWSTR wszServer, RPC_BOOL fWaitForShutdown);
+
+#ifdef UNICODE
+#define SAD_ScIsProxyUnique SAD_ScIsProxyUniqueW
+#define SAD_ScBulkCreateProxy SAD_ScBulkCreateProxyW
+#define SAD_ScBulkCreateMultiProxy SAD_ScBulkCreateMultiProxyW
+#define SAD_ScGetBulkProxyStatus SAD_ScGetBulkProxyStatusW
+#define SAD_ScBulkProxyHalt SAD_ScBulkProxyHaltW
+#else
+#define SAD_ScIsProxyUnique SAD_ScIsProxyUniqueA
+#define SAD_ScBulkCreateProxy SAD_ScBulkCreateProxyA
+#define SAD_ScBulkCreateMultiProxy SAD_ScBulkCreateMultiProxyA
+#define SAD_ScGetBulkProxyStatus SAD_ScGetBulkProxyStatusA
+#define SAD_ScBulkProxyHalt SAD_ScBulkProxyHaltA
+#endif
+
+
+
+
+
+
+// Backup entry point (available only in UNICODE!)
+
+RPC_SC WINAPI SAD_ScGetBackupListNodeW(LPWSTR wszServer, BackupListNode ** ppnode);
+void WINAPI SAD_FreeBackupListNode(BackupListNode * pnode);
+
+
+// Run DRA Check calling parameters (dwCheck)
+#define INTRASITE_CHECK 0
+#define INTERSITE_CHECK 1
+
+RPC_SC WINAPI SAD_ScRunDRACheck(LPWSTR wszServer, RPC_DWORD dwCheck);
+
+
+
+// These few lines (or equivalent) need to be supplied by the application that links
+// with SADAPI.LIB.
+#ifdef _SAMPLE_CODE
+void __RPC_FAR * __RPC_API midl_user_allocate(size_t cb)
+{
+ void * pv;
+
+ pv = GlobalAlloc(GMEM_FIXED, cb);
+ if (!pv)
+ RpcRaiseException(RPC_S_OUT_OF_MEMORY);
+
+ return pv;
+}
+
+void __RPC_API midl_user_free(void __RPC_FAR * pv)
+{
+ GlobalFree(pv);
+}
+#endif
+
+
+
+
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // #ifndef _SADLIB_H_
diff --git a/private/utils/wizards/addusrw/sources b/private/utils/wizards/addusrw/sources
new file mode 100644
index 000000000..5fa1a7827
--- /dev/null
+++ b/private/utils/wizards/addusrw/sources
@@ -0,0 +1,75 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+TARGETNAME=addusrw
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+USE_MFCUNICODE=1
+
+PRECOMPILED_INCLUDE=stdafx.h
+PRECOMPILED_CXX=1
+
+INCLUDES=$(BASEDIR)\private\net\inc; $(BASEDIR)\private\net\svcdlls\fpnw\inc
+
+SOURCES= \
+ accexp.cpp \
+ finish.cpp \
+ fpinfo.cpp \
+ ginfo.cpp \
+ hours.cpp \
+ hours1.cpp \
+ limit.cpp \
+ nwwks.cpp \
+ optdlg.cpp \
+ profile.cpp \
+ prsinfo.cpp \
+ pwinfo.cpp \
+ rasperm.cpp \
+ speckle.cpp \
+ timelist.cpp \
+ transbmp.cpp \
+ userlist.cpp \
+ welcome.cpp \
+ wizbased.cpp \
+ exch.cpp \
+ homedir.cpp \
+ nwlim.cpp \
+ restrct.cpp \
+ lscript.cpp \
+ speckle.rc \
+ trstlist.cpp
+
+UMTYPE=windows
+UMENTRY=wwinmain
+TARGETLIBS= \
+ $(BASEDIR)\public\sdk\lib\*\netapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\mpr.lib \
+ $(BASEDIR)\public\sdk\lib\*\comdlg32.lib \
+ $(BASEDIR)\public\sdk\lib\*\comctl32.lib \
+ $(BASEDIR)\public\sdk\lib\*\shell32.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\oleaut32.lib \
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib
+
diff --git a/private/utils/wizards/addusrw/speckle.cpp b/private/utils/wizards/addusrw/speckle.cpp
new file mode 100644
index 000000000..351e30d0b
--- /dev/null
+++ b/private/utils/wizards/addusrw/speckle.cpp
@@ -0,0 +1,262 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Speckle.cpp : Defines the class behaviors for the application.
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+#include "stdafx.h"
+#include "Speckle.h"
+
+#include "wizbased.h"
+#include "welcome.h"
+#include "prsinfo.h"
+#include "pwinfo.h"
+#include "userlist.h"
+#include "ginfo.h"
+#include "Profile.h"
+#include "finish.h"
+#include "RasPerm.h"
+#include "FPInfo.h"
+#include "Limit.h"
+#include "Timelist.h"
+#include "hours.h"
+#include "AccExp.h"
+#include "optdlg.h"
+#include "Restrct.h"
+#include "HomeDir.h"
+#include "LScript.h"
+#include "Exch.h"
+#include "NWLim.h"
+
+#include <fpnwcomm.h>
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+TCHAR pszTreeEvent[] = _T("TreeThread");
+/////////////////////////////////////////////////////////////////////////////
+// CSpeckleApp
+
+BEGIN_MESSAGE_MAP(CSpeckleApp, CWinApp)
+ //{{AFX_MSG_MAP(CSpeckleApp)
+ //}}AFX_MSG
+// ON_COMMAND(ID_HELP, CWinApp::OnHelp)
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CSpeckleApp construction
+
+CSpeckleApp::CSpeckleApp()
+{
+ m_bLocal = 0; // local or remote
+ m_dwExpirationDate = TIMEQ_FOREVER;
+ *m_pHours = NULL;
+
+ m_sNWAllowedGraceLogins = 0x6;
+ m_sNWRemainingGraceLogins = 0xff;
+ m_sNWConcurrentConnections = NO_LIMIT;
+ m_csNWHomeDir = (TCHAR*)DEFAULT_NWHOMEDIR;
+ m_csAllowedLoginFrom = (TCHAR*)DEFAULT_NWLOGONFROM;
+
+ m_bDisabled = FALSE;
+ m_bChange_Password = FALSE;
+ m_bMust_Change_PW = FALSE;
+ m_bPW_Never_Expires = FALSE;
+
+ m_bExpiration = FALSE;
+ m_bHours = FALSE;
+ m_bNW = FALSE;
+ m_bProfile = FALSE;
+ m_bRAS = FALSE;
+ m_bWorkstation = FALSE;
+ m_bExchange = FALSE;
+ m_bHomeDir = FALSE;
+ m_bLoginScript = FALSE;
+ m_bDisabled = FALSE;
+ m_bEnableRestrictions = FALSE;
+
+ m_sCallBackType = 0;
+
+ m_bPRSReset = TRUE;
+ m_bPWReset = TRUE;
+ m_bGReset = TRUE;
+}
+
+CSpeckleApp::~CSpeckleApp()
+{
+// zero out the password before we leave.
+ m_csPassword1 = L"";
+
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// The one and only CSpeckleApp object
+
+CSpeckleApp theApp;
+
+/////////////////////////////////////////////////////////////////////////////
+// CSpeckleApp initialization
+BOOL CSpeckleApp::IsSecondInstance()
+{
+ HANDLE hSem;
+
+ //create a semaphore object with max count of 1
+ hSem = CreateSemaphore(NULL, 0, 1, L"Adduser Wizard Semaphore");
+ if (hSem!=NULL && GetLastError() == ERROR_ALREADY_EXISTS) {
+ CloseHandle(hSem);
+ CString csAppName;
+ csAppName.LoadString(AFX_IDS_APP_TITLE);
+ CWnd* pWnd = CWnd::FindWindow(NULL, (LPCTSTR)csAppName);
+
+ if (pWnd)
+ pWnd->SetForegroundWindow();
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOL CSpeckleApp::InitInstance()
+{
+// check for OS version
+ OSVERSIONINFO os;
+ os.dwOSVersionInfoSize = sizeof(os);
+ GetVersionEx(&os);
+
+ if (os.dwMajorVersion < 4)
+ {
+ AfxMessageBox(IDS_BAD_VERSION, MB_ICONSTOP);
+ ExitProcess(0);
+ }
+ if (IsSecondInstance())
+ return FALSE;
+
+ AfxEnableControlContainer();
+
+ // Standard initialization
+
+#ifdef _AFXDLL
+ Enable3dControls(); // Call this when using MFC in a shared DLL
+#else
+ Enable3dControlsStatic(); // Call this when linking to MFC statically
+#endif
+
+// create the dialogs
+ CWelcomeDlg* pWelcome = new CWelcomeDlg;
+ CPersonalInfo* pInfo = new CPersonalInfo;
+ CPasswordInfo* pPassword = new CPasswordInfo;
+ CGroupInfo* pGroup = new CGroupInfo;
+ CProfile* pProfile = new CProfile;
+ CFinish* pFinish = new CFinish;
+ CRasPerm* pRasP = new CRasPerm;
+ CFPInfo* pFP = new CFPInfo;
+ CLimitLogon* pLim = new CLimitLogon;
+ CHoursDlg* pHours = new CHoursDlg;
+ CAccExp* pExp = new CAccExp;
+ COptionsDlg* pOpt = new COptionsDlg;
+ CRestrictions* pRestrictions = new CRestrictions;
+ CHomeDir* pHomeDir = new CHomeDir;
+ CLoginScript* pLScript = new CLoginScript;
+ CExch* pExch = new CExch;
+ CNWLimitLogon* pNWLim = new CNWLimitLogon;
+
+// create the property sheet and set 'wizmode'
+ m_cps1.SetWizardMode();
+
+// Add the dialogs
+ m_cps1.AddPage(pWelcome);
+ m_cps1.AddPage(pInfo);
+ m_cps1.AddPage(pPassword);
+ m_cps1.AddPage(pGroup);
+
+ m_cps1.AddPage(pOpt);
+ m_cps1.AddPage(pProfile);
+ m_cps1.AddPage(pLScript);
+ m_cps1.AddPage(pHomeDir);
+ m_cps1.AddPage(pRasP);
+ m_cps1.AddPage(pFP);
+
+ m_cps1.AddPage(pExch);
+
+ m_cps1.AddPage(pRestrictions);
+ m_cps1.AddPage(pExp);
+ m_cps1.AddPage(pHours);
+ m_cps1.AddPage(pLim);
+ m_cps1.AddPage(pNWLim);
+ m_cps1.AddPage(pFinish);
+
+// start the wizard
+ m_cps1.DoModal();
+
+// clean up
+ delete pWelcome;
+ delete pInfo;
+ delete pPassword;
+ delete pGroup;
+ delete pProfile;
+ delete pFinish;
+ delete pRasP;
+ delete pFP;
+ delete pLim;
+ delete pHours;
+ delete pExp;
+ delete pOpt;
+ delete pRestrictions;
+ delete pHomeDir;
+ delete pLScript;
+ delete pExch;
+ delete pNWLim;
+
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CMySheet
+
+IMPLEMENT_DYNAMIC(CMySheet, CPropertySheet)
+
+CMySheet::CMySheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage)
+ :CPropertySheet(nIDCaption, pParentWnd, iSelectPage)
+{
+}
+
+CMySheet::CMySheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage)
+ :CPropertySheet(pszCaption, pParentWnd, iSelectPage)
+{
+}
+
+CMySheet::CMySheet() : CPropertySheet()
+{
+}
+
+CMySheet::~CMySheet()
+{
+}
+
+
+BEGIN_MESSAGE_MAP(CMySheet, CPropertySheet)
+ //{{AFX_MSG_MAP(CMySheet)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CMySheet message handlers
+
+BOOL CMySheet::OnInitDialog()
+{
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+ HICON hIcon = LoadIcon(pApp->m_hInstance, MAKEINTRESOURCE(IDR_MAINFRAME));
+ ::SetClassLong(m_hWnd, GCL_HICON, (long)hIcon);
+
+ return CPropertySheet::OnInitDialog();
+}
diff --git a/private/utils/wizards/addusrw/speckle.h b/private/utils/wizards/addusrw/speckle.h
new file mode 100644
index 000000000..1f1b2628a
--- /dev/null
+++ b/private/utils/wizards/addusrw/speckle.h
@@ -0,0 +1,176 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Speckle.h : main header file for the SPECKLE application
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+#ifndef __AFXWIN_H__
+ #error include 'stdafx.h' before including this file for PCH
+#endif
+
+#include "resource.h" // main symbols
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CMySheet
+
+class CMySheet : public CPropertySheet
+{
+ DECLARE_DYNAMIC(CMySheet)
+
+// Construction
+public:
+ CMySheet(UINT nIDCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0);
+ CMySheet(LPCTSTR pszCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0);
+ CMySheet();
+
+// Attributes
+public:
+
+// Operations
+public:
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CMySheet)
+ public:
+ virtual BOOL OnInitDialog();
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CMySheet();
+
+ // Generated message map functions
+protected:
+ //{{AFX_MSG(CMySheet)
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+// CSpeckleApp:
+// See Speckle.cpp for the implementation of this class
+//
+
+typedef struct tagTREEINFO
+{
+ HTREEITEM hTreeItem;
+ DWORD dwBufSize;
+ CObject* pTree;
+ BOOL bExpand;
+}
+TREEINFO, *PTREEINFO;
+
+class CSpeckleApp : public CWinApp
+{
+public:
+ CSpeckleApp();
+ ~CSpeckleApp();
+
+ CMySheet m_cps1;
+ BOOL IsSecondInstance();
+
+ short m_bLocal;
+
+// remote server name
+ BOOL m_bDomain;
+ BOOL m_bServer;
+ CString m_csServer;
+ int m_nGroupType;
+ CString m_csCurrentDomain;
+ CString m_csCurrentMachine;
+ CString m_csDomain;
+
+// account information
+// password info
+ BOOL m_bChange_Password;
+ BOOL m_bMust_Change_PW;
+ BOOL m_bPW_Never_Expires;
+ CString m_csPassword1;
+
+// personal info
+ CString m_csDescription;
+ CString m_csFullName;
+ CString m_csUserName;
+
+// profile info
+ CString m_csLogonScript; // usri3_script_path
+ CString m_csProfilePath; // usri3_profile
+
+// homedir info
+ CString m_csHomeDir; // usri3_home_dir
+ CString m_csHome_dir_drive; // usri3_home_dir_drive
+
+// group list
+ CStringArray m_csaSelectedLocalGroups;
+ CStringArray m_csaSelectedGlobalGroups;
+
+// permitted machine list
+ CString m_csAllowedMachines;
+
+// Account expiration date (seconds since 1/1/1970 00:00:00)
+ DWORD m_dwExpirationDate;
+
+// time of availability
+ BYTE m_pHours[21];
+
+// NetWare params
+ USHORT m_sNWAllowedGraceLogins;
+ USHORT m_sNWConcurrentConnections;
+ USHORT m_sNWRemainingGraceLogins;
+ CString m_csNWHomeDir;
+ CString m_csAllowedLoginFrom;
+
+// RAS params;
+ CString m_csRasPhoneNumber;
+ USHORT m_sCallBackType; // 0- no call back 1- caller set 2-preset
+
+// primary group ID
+ DWORD m_dwPrimaryGroupID;
+
+// Which windows to use
+ BOOL m_bExpiration;
+ BOOL m_bHours;
+ BOOL m_bNW;
+ BOOL m_bProfile;
+ BOOL m_bRAS;
+ BOOL m_bWorkstation;
+ BOOL m_bExchange;
+ BOOL m_bHomeDir;
+ BOOL m_bLoginScript;
+ BOOL m_bDisabled;
+
+ BOOL m_bEnableRestrictions;
+
+// restarting the app?
+ BOOL m_bPRSReset;
+ BOOL m_bPWReset;
+ BOOL m_bGReset;
+
+// Exchange server
+ CString m_csExchangeServer;
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CSpeckleApp)
+ public:
+ virtual BOOL InitInstance();
+ //}}AFX_VIRTUAL
+
+// Implementation
+
+ //{{AFX_MSG(CSpeckleApp)
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/private/utils/wizards/addusrw/speckle.rc b/private/utils/wizards/addusrw/speckle.rc
new file mode 100644
index 000000000..868f5cb3d
--- /dev/null
+++ b/private/utils/wizards/addusrw/speckle.rc
@@ -0,0 +1,766 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
+ "#define _AFX_NO_OLE_RESOURCES\r\n"
+ "#define _AFX_NO_TRACKER_RESOURCES\r\n"
+ "#define _AFX_NO_PROPERTY_RESOURCES\r\n"
+ "\r\n"
+ "#include ""res\\Speckle.rc2"" // non-Microsoft Visual C++ edited resources\r\n"
+ "#include ""afxres.rc"" // Standard components\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDR_MAINFRAME ICON DISCARDABLE "res\\Speckle.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_BASE_DIALOG DIALOG DISCARDABLE 0, 0, 276, 140
+STYLE WS_POPUP | WS_VISIBLE | WS_DISABLED | WS_BORDER
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL "",IDC_PAINT_BOX,"Static",SS_BLACKFRAME,0,0,80,140
+END
+
+IDD_WELCOME_DIALOG DIALOG DISCARDABLE 0, 0, 276, 140
+STYLE WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION
+CAPTION "Add User Account Wizard"
+FONT 8, "MS Sans Serif"
+BEGIN
+ LTEXT "&Domain name:",IDC_STATIC,92,56,48,8
+ COMBOBOX IDC_DOMAIN_LIST,147,54,123,51,CBS_DROPDOWNLIST |
+ CBS_SORT | WS_VSCROLL | WS_TABSTOP
+ CONTROL 130,IDC_PAINT_BOX,"Static",SS_BITMAP | SS_SUNKEN,0,0,80,
+ 140
+ LTEXT "Welcome to the Add User Account wizard",IDC_STATIC1,91,
+ 7,184,8
+ LTEXT "Use this wizard to create an account for a user on this domain:",
+ IDC_STATIC,91,27,179,18
+END
+
+IDD_USER_NAME DIALOG DISCARDABLE 0, 0, 276, 140
+STYLE WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION
+CAPTION "Add User Account Wizard"
+FONT 8, "MS Sans Serif"
+BEGIN
+ LTEXT "What is the user's &full name?",IDC_STATIC,93,9,155,8
+ EDITTEXT IDC_FULLNAME,93,19,175,14,ES_AUTOHSCROLL
+ LTEXT "Type a &unique name to identify the user. This username will be used for logging on and using resources.",
+ IDC_STATIC,93,47,174,19
+ EDITTEXT IDC_USERNAME,93,65,175,14,ES_AUTOHSCROLL
+ LTEXT "Type a &description for this user (optional).",
+ IDC_STATIC,93,93,174,8
+ EDITTEXT IDC_DESCRIPTION,93,103,175,14,ES_AUTOHSCROLL
+ CONTROL 130,IDC_PAINT_BOX,"Static",SS_BITMAP | SS_SUNKEN,0,0,80,
+ 140
+END
+
+IDD_PASSWORD_INFO DIALOG DISCARDABLE 0, 0, 276, 140
+STYLE WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION
+FONT 8, "MS Sans Serif"
+BEGIN
+ LTEXT "&Password:",IDC_STATIC,91,25,32,8
+ EDITTEXT IDC_PASSWORD1,157,22,112,13,ES_PASSWORD | ES_AUTOHSCROLL
+ LTEXT "&Confirm password:",IDC_STATIC,91,42,58,8
+ EDITTEXT IDC_PASSWORD2,157,39,112,13,ES_PASSWORD | ES_AUTOHSCROLL
+ LTEXT "",IDC_STATIC1,91,6,184,8
+ CONTROL 130,IDC_PAINT_BOX,"Static",SS_BITMAP | SS_SUNKEN,0,0,80,
+ 140
+ CONTROL "The user &must change the password at the next ",
+ IDC_PWOPTIONS_RADIO,"Button",BS_AUTORADIOBUTTON |
+ WS_GROUP,91,64,178,10
+ CONTROL "The user c&an change the password at any time.",
+ IDC_RADIO2,"Button",BS_AUTORADIOBUTTON,91,89,164,10
+ CONTROL "The user is n&ot allowed to change the password.",
+ IDC_RADIO3,"Button",BS_AUTORADIOBUTTON,91,105,167,10
+ CONTROL "This password never &expires",IDC_EXPIREPW_CHECK,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,91,126,105,10
+ LTEXT "logon and can change it at any time.",IDC_STATIC,103,74,
+ 166,8
+END
+
+IDD_PROFILE DIALOG DISCARDABLE 0, 0, 276, 140
+STYLE WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION
+FONT 8, "MS Sans Serif"
+BEGIN
+ LTEXT "User profiles contain desktop settings, such as which applications appear and which network connections are restored when the user logs on. If the profile path is left blank, the wizard will use the default profile stored in the Default User folder.",
+ IDC_STATIC,9,5,264,28
+ LTEXT "What is the user's &profile path?",IDC_STATIC,9,35,110,
+ 8
+ EDITTEXT IDC_PROFILE_PATH,8,44,260,14,ES_AUTOHSCROLL
+END
+
+IDD_FINISH DIALOG DISCARDABLE 0, 0, 276, 140
+STYLE WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION
+CAPTION "Add User Account Wizard"
+FONT 8, "MS Sans Serif"
+BEGIN
+ LTEXT "",IDC_STATIC1,93,7,172,34
+ LTEXT "Click Finish to add the account, or click Cancel to cancel the wizard without adding the account.",
+ IDC_STATIC,93,51,159,18
+END
+
+IDD_RAS_PERM_DIALOG DIALOG DISCARDABLE 0, 0, 276, 140
+STYLE WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Add User Account Wizard"
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL "&No call back by the Remote Access server",
+ IDC_CALL_BACK_RADIO,"Button",BS_AUTORADIOBUTTON |
+ WS_GROUP,90,55,174,10
+ CONTROL "User can call in from &any number",IDC_RADIO2,"Button",
+ BS_AUTORADIOBUTTON,90,71,176,10
+ CONTROL "User can only call from &this number",IDC_RADIO3,
+ "Button",BS_AUTORADIOBUTTON,90,87,176,10
+ EDITTEXT IDC_RASPHONE_EDIT,101,97,90,14,ES_AUTOHSCROLL |
+ WS_DISABLED
+ CONTROL 130,IDC_PAINT_BOX,"Static",SS_BITMAP | SS_SUNKEN,0,0,80,
+ 140
+ LTEXT "What are the Dial-Up Networking options you want for %s?",
+ IDC_STATIC1,90,7,180,17
+END
+
+IDD_FPNW_DLG DIALOG DISCARDABLE 0, 0, 276, 140
+STYLE WS_POPUP | WS_CAPTION
+CAPTION "Add User Account Wizard"
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL "&Yes",IDC_GRACE_LOGIN_RADIO,"Button",BS_AUTORADIOBUTTON |
+ WS_GROUP,22,38,36,10
+ CONTROL "N&o, allow only",IDC_GRACE_LOGIN_RADIO2,"Button",
+ BS_AUTORADIOBUTTON | WS_TABSTOP,22,52,60,10
+ EDITTEXT IDC_ALLOWED_GRACE_LOGINS_EDIT,83,50,40,14,ES_AUTOHSCROLL
+ CONTROL "Spin1",IDC_GRACE_LOGIN_SPIN,"msctls_updown32",
+ UDS_SETBUDDYINT | UDS_AUTOBUDDY | UDS_ARROWKEYS,122,50,
+ 11,14
+ LTEXT "grace login(s)",IDC_STATIC2,137,53,55,8
+ LTEXT "Do you want to allow unlimited logins after the password has expired?",
+ IDC_STATIC,9,24,218,8
+ LTEXT "Do you want to allow an unlimited number of concurrent connections?",
+ IDC_STATIC,9,79,220,8
+ CONTROL "Y&es",IDC_CONCURRENT_CONNECTIONS_RADIO1,"Button",
+ BS_AUTORADIOBUTTON | WS_GROUP,23,93,28,10
+ CONTROL "No, &allow only",IDC_CONCURRENT_CONNECTIONS_RADIO2,
+ "Button",BS_AUTORADIOBUTTON,23,107,60,10
+ EDITTEXT IDC_CONCURRENT_CONNECTIONS_EDIT,83,105,40,14,
+ ES_AUTOHSCROLL
+ CONTROL "Spin1",IDC_CONCURRENT_CONNECTIONS_SPIN,
+ "msctls_updown32",UDS_SETBUDDYINT | UDS_AUTOBUDDY |
+ UDS_ARROWKEYS,122,105,11,14
+ LTEXT "concurrent connection(s)",IDC_STATIC,137,108,102,8
+ LTEXT "",IDC_STATIC1,9,6,245,8
+END
+
+IDD_GROUP_INFO DIALOG DISCARDABLE 0, 0, 276, 140
+STYLE WS_POPUP | WS_CAPTION
+CAPTION "Add User Account Wizard"
+FONT 8, "MS Sans Serif"
+BEGIN
+ LTEXT "A&vailable groups:",IDC_STATIC,1,21,75,8
+ LISTBOX IDC_GROUP_AVAILABLE_LIST,0,31,105,108,LBS_SORT |
+ LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS |
+ LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "&Selected groups:",IDC_STATIC,171,21,62,8
+ LISTBOX IDC_GROUP_MEMBER_LIST,170,31,105,108,LBS_SORT |
+ LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS |
+ LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "&Add >",IDC_ADD_BUTTON,112,56,50,14
+ PUSHBUTTON "< &Remove",IDC_REMOVE_BUTTON,112,74,50,14
+ LTEXT "",IDC_STATIC1,0,1,266,19
+END
+
+IDD_LOGONTO_DLG DIALOG DISCARDABLE 0, 0, 276, 140
+STYLE WS_POPUP | WS_CAPTION
+CAPTION "Add User Account Wizard"
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL "A&ll workstations",IDC_WORKSTATION_RADIO,"Button",
+ BS_AUTORADIOBUTTON | WS_GROUP,6,15,109,10
+ GROUPBOX "Static",IDC_STATIC,0,29,271,111
+ CONTROL "User can only log on from &these workstations",
+ IDC_WORKSTATION_RADIO2,"Button",BS_AUTORADIOBUTTON,6,28,
+ 154,10
+ LISTBOX IDC_LIST1,9,52,253,61,LBS_SORT | LBS_NOINTEGRALHEIGHT |
+ WS_DISABLED | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "&Add...",IDC_ADD_BUTTON,9,118,50,14,WS_DISABLED
+ PUSHBUTTON "&Remove",IDC_REMOVE_BUTTON,64,118,50,14,WS_DISABLED
+ LTEXT "Workstations:",IDC_STATIC1,10,42,44,8,WS_DISABLED
+ LTEXT "",IDC_STATIC2,7,2,268,8
+END
+
+IDD_HOURS_DLG DIALOG DISCARDABLE 0, 0, 276, 141
+STYLE WS_POPUP | WS_CAPTION
+CAPTION "Add User Account Wizard"
+FONT 8, "MS Sans Serif"
+BEGIN
+ LTEXT "Select the times the user can logon. Click on a square to allow or disallow a time. Click on a day to allow or disallow a whole day.",
+ IDC_STATIC,0,0,275,16
+ LTEXT "Allowed times - ",IDC_STATIC,56,131,50,8
+ CONTROL "",IDC_STATIC_ALLOWEDTIMES,"Static",SS_BLACKFRAME,109,
+ 131,9,9
+ LTEXT "Disallowed times - ",IDC_STATIC,143,131,59,8
+ CONTROL "",IDC_STATIC_DISALLOWEDTIMES,"Static",SS_BLACKFRAME,204,
+ 131,9,9
+ CONTROL "",IDC_HOURSCTRL1,
+ "{A44EA7AD-9D58-11CF-A35F-00AA00B6743B}",WS_TABSTOP,13,
+ 30,249,100
+ LTEXT "Midnight",IDC_STATIC,54,19,27,8
+ LTEXT "Noon",IDC_STATIC,155,18,18,8
+ LTEXT "Midnight",IDC_STATIC,245,19,28,8
+ CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME,84,27,1,3
+ CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME,100,27,1,3
+ CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME,116,27,1,3
+ CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME,132,27,1,3
+ CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME,148,27,1,3
+ CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME,180,27,1,3
+ CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME,196,27,1,3
+ CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME,212,27,1,3
+ CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME,228,27,1,3
+ CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME,244,27,1,3
+ CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME,68,27,1,3
+ CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME,164,27,1,3
+ CONTROL "",IDC_STATIC,"Static",SS_BLACKFRAME,260,27,1,3
+END
+
+IDD_ADD_NWWKS_DIALOG DIALOG DISCARDABLE 0, 0, 183, 92
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Add NetWare Compatible Workstation"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,43,68,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,102,68,50,14
+ LTEXT "&Network Address:",IDC_STATIC,7,19,59,8
+ EDITTEXT IDC_NETWORK_ADDRESS_EDIT,74,16,102,14,ES_AUTOHSCROLL
+ LTEXT "N&ode Address:",IDC_STATIC,7,40,48,8
+ EDITTEXT IDC_NODE_ADDRESS_EDIT,74,37,102,14,ES_AUTOHSCROLL
+END
+
+IDD_ACCOUNT_EXP_DIALOG DIALOG DISCARDABLE 0, 0, 276, 140
+STYLE WS_POPUP | WS_CAPTION
+CAPTION "Add User Account WIzard"
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL "",IDC_STATIC,"Static",SS_ETCHEDFRAME,106,23,93,17
+ CONTROL "",IDC_STATIC_FRAME,"Static",SS_WHITERECT,108,24,90,14
+ EDITTEXT IDC_DAY_EDIT,135,25,13,12,ES_AUTOHSCROLL | ES_NUMBER |
+ NOT WS_BORDER
+ EDITTEXT IDC_YEAR_EDIT,160,25,27,12,ES_AUTOHSCROLL | ES_NUMBER |
+ NOT WS_BORDER
+ CONTROL "Spin1",IDC_DATE_SPIN,"msctls_updown32",UDS_SETBUDDYINT |
+ UDS_AUTOBUDDY | UDS_ARROWKEYS | UDS_NOTHOUSANDS,188,23,
+ 11,16
+ CTEXT "/",IDC_STATIC1,125,25,8,8
+ CTEXT "/",IDC_STATIC2,151,25,8,8
+ EDITTEXT IDC_MONTH_EDIT,110,25,13,12,ES_AUTOHSCROLL | ES_NUMBER |
+ NOT WS_BORDER
+ LTEXT "When do you want this account to expire?",IDC_STATIC,92,
+ 8,172,8
+ CONTROL 130,IDC_PAINT_BOX,"Static",SS_BITMAP | SS_SUNKEN,1,0,80,
+ 140
+END
+
+IDD_OPTIONS_DIALOG DIALOG DISCARDABLE 0, 0, 276, 140
+STYLE WS_POPUP | WS_CAPTION
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL "&Profile",IDC_PROFILE_CHECK,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,91,40,39,10
+ CONTROL "&Login script",IDC_LOGIN_SCRIPT_CHECK,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,91,55,52,10
+ CONTROL "&Home Directory",IDC_HOMEDIR_CHECK,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,91,70,65,10
+ CONTROL "&Dial-Up Networking",IDC_RAS_CHECK,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,91,85,130,10
+ CONTROL "&File and Print Services for NetWare",IDC_NW_CHECK,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,91,100,131,10
+ CONTROL "Microsoft &Exchange",IDC_EXCHANGE_CHECK,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,91,115,103,10
+ CONTROL 130,IDC_PAINT_BOX,"Static",SS_BITMAP | SS_SUNKEN,0,0,80,
+ 140
+ LTEXT "",IDC_STATIC1,89,6,177,28
+END
+
+IDD_HOMEDIR_DIALOG DIALOG DISCARDABLE 0, 0, 276, 140
+STYLE WS_POPUP | WS_CAPTION
+CAPTION "Add User Account Wizard"
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL "Use the default home directory on the &user's computer",
+ IDC_LOCAL_PATH_BUTTON,"Button",BS_AUTORADIOBUTTON |
+ WS_GROUP,13,56,232,14
+ GROUPBOX "",IDC_STATIC,7,74,262,57
+ CONTROL "On &another computer",IDC_REMOTE_PATH_BUTTON,"Button",
+ BS_AUTORADIOBUTTON,14,74,80,10
+ LTEXT "&Connect drive:",IDC_STATIC,16,91,48,8
+ COMBOBOX IDC_DRIVE_LETTER,70,89,27,58,CBS_DROPDOWN | CBS_SORT |
+ WS_DISABLED | WS_VSCROLL | WS_TABSTOP
+ LTEXT "&To:",IDC_STATIC,16,110,10,10
+ EDITTEXT IDC_REMOTE_PATH,33,107,227,14,ES_AUTOHSCROLL |
+ WS_DISABLED
+ LTEXT "",IDC_STATIC1,7,30,255,8
+ LTEXT "Home directories are for users to have a default location to store files and folders. A home directory can be on a user's computer, or on another computer in the domain.",
+ IDC_STATIC,7,7,262,23
+END
+
+IDD_LOGON_SCRIPT_DIALOG DIALOG DISCARDABLE 0, 0, 272, 140
+STYLE WS_POPUP | WS_CAPTION
+CAPTION "Add User Accont Wizard"
+FONT 8, "MS Sans Serif"
+BEGIN
+ LTEXT "What is the user's logon &script name?",IDC_STATIC,7,35,
+ 124,8
+ EDITTEXT IDC_LOGON_SCRIPT,7,45,258,13,ES_AUTOHSCROLL
+ LTEXT "Logon scripts can be used to configure the user's work environment, such as starting applications, or creating new network connections. If you leave the logon scripts blank, no logon script will be used for the user account.",
+ IDC_STATIC,7,7,258,28
+END
+
+IDD_RESTRICTIONS_DIALOG DIALOG DISCARDABLE 0, 0, 272, 141
+STYLE WS_POPUP | WS_CAPTION
+CAPTION "Add User Account Wizard"
+FONT 8, "MS Sans Serif"
+BEGIN
+ GROUPBOX "Static",IDC_STATIC,93,48,178,80
+ CONTROL "&No restrictions",IDC_RESTRICTIONS_RADIO,"Button",
+ BS_AUTORADIOBUTTON | WS_GROUP,99,32,61,10
+ CONTROL "The following &restrictions",IDC_RESTRICTIONS_RADIO2,
+ "Button",BS_AUTORADIOBUTTON,99,47,90,10
+ CONTROL "When the &account will expire",IDC_ACCOUNT_EXPIRE_CHECK,
+ "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,103,
+ 63,107,10
+ CONTROL "The &times when the user can logon",
+ IDC_LOGIN_TIMES_CHECK,"Button",BS_AUTOCHECKBOX |
+ WS_DISABLED | WS_TABSTOP,103,78,140,10
+ CONTROL "The &workstations from which the user can logon",
+ IDC_WORKSTATIONS_CHECK,"Button",BS_AUTOCHECKBOX |
+ WS_DISABLED | WS_TABSTOP,103,93,164,10
+ CONTROL "The account is currently &disabled",IDC_DISABLED_CHECK,
+ "Button",BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,103,
+ 108,120,10
+ LTEXT "",IDC_STATIC1,93,7,177,17
+ CONTROL 130,IDC_PAINT_BOX,"Static",SS_BITMAP | SS_SUNKEN,1,0,80,
+ 140
+END
+
+IDD_NWLOGON_DIALOG DIALOG DISCARDABLE 0, 0, 276, 140
+STYLE WS_POPUP | WS_CAPTION
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL "A&ll NetWare compatible workstations",
+ IDC_WORKSTATION_RADIO,"Button",BS_AUTORADIOBUTTON |
+ WS_GROUP,6,15,132,10
+ GROUPBOX "Static",IDC_STATIC,0,29,271,111
+ CONTROL "User can only log on from &these workstations",
+ IDC_WORKSTATION_RADIO2,"Button",BS_AUTORADIOBUTTON,6,28,
+ 154,10
+ LISTBOX IDC_NWLOGON_LIST,9,52,253,63,LBS_SORT |
+ LBS_OWNERDRAWFIXED | WS_DISABLED | WS_VSCROLL |
+ WS_TABSTOP
+ PUSHBUTTON "&Add...",IDC_ADD_BUTTON,9,118,50,14,WS_DISABLED
+ PUSHBUTTON "&Remove",IDC_REMOVE_BUTTON,64,118,50,14,WS_DISABLED
+ LTEXT "Network Address:",IDC_NWSTATIC1,10,42,70,8,WS_DISABLED
+ LTEXT "Node Address:",IDC_NWSTATIC2,120,42,70,8,WS_DISABLED
+ LTEXT "",IDC_STATIC1,7,2,263,8
+END
+
+IDD_EXCHANGE_DIALOG DIALOG DISCARDABLE 0, 0, 276, 140
+STYLE WS_POPUP | WS_CAPTION
+FONT 8, "MS Sans Serif"
+BEGIN
+ EDITTEXT IDC_SERVERNAME_EDIT,7,33,204,14,ES_AUTOHSCROLL
+ LTEXT "Please enter the name of a Microsoft Exchange server in the domain:",
+ IDC_STATIC,7,6,228,8
+ LISTBOX IDC_SERVER_LIST,63,96,122,39,LBS_SORT |
+ LBS_NOINTEGRALHEIGHT | NOT WS_VISIBLE | WS_VSCROLL |
+ WS_TABSTOP
+ LTEXT "Static",IDC_STATIC_DOMAIN,7,19,82,8
+END
+
+IDD_ADD_WKS_DIALOG DIALOG DISCARDABLE 0, 0, 186, 95
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Workstations"
+FONT 8, "MS Sans Serif"
+BEGIN
+ EDITTEXT IDC_WORKSTATION_EDIT,6,22,172,14,ES_AUTOHSCROLL
+ DEFPUSHBUTTON "&Add",IDOK,40,74,50,14
+ PUSHBUTTON "&Close",IDCANCEL,95,74,50,14
+ LTEXT "&Please enter the name of a workstation:",IDC_STATIC,7,
+ 12,126,8
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_BASE_DIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 269
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 133
+ END
+
+ IDD_WELCOME_DIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 269
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 135
+ END
+
+ IDD_USER_NAME, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 269
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 135
+ END
+
+ IDD_PASSWORD_INFO, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 269
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 135
+ END
+
+ IDD_PROFILE, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 269
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 135
+ END
+
+ IDD_FINISH, DIALOG
+ BEGIN
+ LEFTMARGIN, 5
+ RIGHTMARGIN, 269
+ TOPMARGIN, 5
+ BOTTOMMARGIN, 135
+ END
+
+ IDD_RAS_PERM_DIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 269
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 133
+ END
+
+ IDD_FPNW_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 269
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 133
+ END
+
+ IDD_GROUP_INFO, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 269
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 133
+ END
+
+ IDD_LOGONTO_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 269
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 133
+ END
+
+ IDD_HOURS_DLG, DIALOG
+ BEGIN
+ RIGHTMARGIN, 269
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 134
+ END
+
+ IDD_ADD_NWWKS_DIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 176
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 85
+ END
+
+ IDD_ACCOUNT_EXP_DIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 269
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 133
+ END
+
+ IDD_OPTIONS_DIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 269
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 133
+ END
+
+ IDD_HOMEDIR_DIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 269
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 133
+ END
+
+ IDD_LOGON_SCRIPT_DIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 265
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 133
+ END
+
+ IDD_RESTRICTIONS_DIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 265
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 134
+ END
+
+ IDD_NWLOGON_DIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 269
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 133
+ END
+
+ IDD_EXCHANGE_DIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 269
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 133
+ END
+
+ IDD_ADD_WKS_DIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 179
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 88
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_BITMAP1 BITMAP DISCARDABLE "res\\bitmap1.bmp"
+IDB_NET_TREE BITMAP DISCARDABLE "res\\net_tree.bmp"
+IDB_USER_BITMAP BITMAP DISCARDABLE "res\\user.bmp"
+IDB_USER_BITMAP1 BITMAP DISCARDABLE "res\\user_bit.bmp"
+IDB_GLOBAL_GROUP_BITMAP BITMAP DISCARDABLE "res\\global.bmp"
+IDB_LOCAL_GROUP_BITMAP BITMAP DISCARDABLE "res\\group.bmp"
+IDB_WORLD BITMAP DISCARDABLE "res\\world.bmp"
+IDB_ENDFLAG BITMAP DISCARDABLE "res\\endflag.BMP"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog Info
+//
+
+IDD_HOURS_DLG DLGINIT
+BEGIN
+ IDC_HOURSCTRL1, 0x376, 20, 0
+0x0000, 0x0000, 0x0000, 0x0001, 0x26a7, 0x0000, 0x10d9, 0x0000, 0x0000,
+0x0000,
+ 0
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_NO_MACHINE_NAME "Please enter the name of a computer or domain."
+ IDS_NO_VALID_WORKSTATIONS
+ "You did not specify any valid logon workstations. You must select that all workstations are permissible, or specify one or more workstations in the spaces provided."
+ IDS_NO_NEW_USER "An error occurred while adding the user account for %s with the username %s. The user account was not created. Do you want to restart the wizard?"
+ IDS_BAD_USER_DATA "An error occurred while parameters were being set for %s with the username %s. Not all parameters were set. Would you like to restart the wizard?"
+ IDS_NO_LOCAL_GROUP "An error occurred while adding this user to some local groups."
+ IDS_NO_GLOBAL_GROUP "An error occurred while adding this user to some global groups."
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_GENERIC_NO_HEAP "There is insufficient memory to continue. This program will stop."
+ IDS_GENERIC_NO_PDC "Unable to contact a domain controller for this domain. Group and user lists are unavailable."
+ IDS_GENERIC_BAD_MACHINE "Unable to locate computer. The selected computer is not available or is not running Windows NT Workstation or Windows NT Server."
+ IDS_NO_GROUP_NAME "Please enter a group name."
+ IDS_GROUP_INVALID_NAME "Please enter a group name with 20 characters or less. The name can contain any character except: ""\\/[];:|=,+*?<>"
+ IDS_DOMAIN_SET "The selected computer is a domain controller. Focus will be set to its affiliated primary domain."
+ IDS_NET_ERROR "IDS_NET_ERROR"
+ IDS_NET_NO_SERVERS "No servers were found in the selected domain."
+ IDS_ERROR "IDS_ERROR"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ AFX_IDS_APP_TITLE "Add User Account Wizard"
+ IDS_BAD_VERSION "You must be running Windows NT version 4.0 in order to use this application."
+ IDS_WELCOME_STRING "Welcome to the Add User Account wizard"
+ IDS_PASSWORD_CAPTION "Type a password for %s."
+ IDS_FINISH_CAPTION "You have entered all the information to add a user account for %s. To make changes to existing user accounts, use User Manager for Domains in the Administrative Tools group."
+ IDS_OPTION_CAPTION "Which of the following options do you want to configure for %s? If any of these options are not available, you will not be able to select it."
+ IDS_FPNW_CAPTION "Select the File and Print Services for NetWare settings for %s:"
+ IDS_GROUP_CAPTION "By default, all users are members of the Domain Users group. What other groups do you want %s to be a member of?"
+ IDS_RAS_CAPTION "What are the calling options you want for %s?"
+ IDS_WORKSTATION_CAPTION "Which workstations running Microsoft Windows NT can %s log on from?"
+ IDS_HOMEDIR_CAPTION "Where do you want the home directory for %s?"
+ IDS_RESTRICTION_CAPTION "What restrictions do you want %s to have?"
+ IDS_NWLOGON_CAPTION "Which NetWare compatible workstations can %s log on from?"
+ IDS_SUCCESS "The new user account was created for %s with the username %s. Do you want to restart the wizard?"
+ IDS_NW_PW_ERROR "An error occurred during encryption of the NetWare password."
+ IDS_NW_GRACELOGIN_ERROR "Error setting NetWare grace login limit."
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_NW_CONCON_ERROR "Error setting NetWare concurrent connection limit."
+ IDS_RAS_ERROR "Error setting RAS account information."
+ IDS_NEEDA_WORKSTATION "Please provide a valid workstation from which the user can log on."
+ IDS_NEED_ADDRESS "Please provide the network address."
+ IDS_UNKNOWN_COMPONENTS "Unable to determine which optional components are installed."
+ IDS_BAD_WS_NAME "Invalid characters in workstation name."
+ IDS_BAD_USERNAME "Username contains illegal characters."
+ IDS_DUPLICATE_NAME "You can not create an account called %s because username %s already exists in %s. Please type a different username."
+ IDS_PW_NOMATCH "The passwords you entered are not identical. You need to type and confirm the password for %s."
+ IDS_PW_TOOLONG "The selected password is too long. Please select another password that is 14 characters or less."
+ IDS_BAD_GETMODALS "Error with NetUserGetModals."
+ IDS_PW_TOOSHORT "The selected password is too short. Please select another password that is at least %d characters long."
+ IDS_NODC "Unable to find a domain controller for this domain."
+ IDS_NO_USERNAME "Please type a username for this user."
+ IDS_USERNAME_TOOLONG "The username must be 20 characters or less."
+ IDS_NOFP_WS "Error setting the allowed NetWare compatible workstations."
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_ALL_NODES "Do you want to include all nodes?"
+ IDS_NOT_ADMIN "You are not a member of the Administrators group on the selected domain."
+ IDS_WSNAME_TOOLONG "The workstation name must be 15 characters or less."
+ IDS_INVALID_DAY "The selected month does not contain that many days."
+ IDS_INVALID_MONTH "The value for month must be between 1 and 12."
+ IDS_INVALID_YEAR "The value for year must be between 1996 and 2030."
+ IDS_BAD_NWADDRESS "The specified NetWare address contains invalid characters."
+ IDS_BAD_NWNODE "The specified NetWare node contains invalid characters."
+ IDS_TOOLONG_NWADDRESS "The specified NetWare address must be 8 characters or less."
+ IDS_TOOLONG_NWNODE "The specified NetWare node must be 12 characters or less."
+ IDS_ALREADY_EXPIRED "The selected date will create an account that has already expired. Do you want to continue creating this account with this expiration date?"
+ IDS_INVALID_DIRECTORY_NAME
+ "The folder %1 does not exist. Would you like to create it?"
+ IDS_NO_DIR_PERMISSION "You do not have permission to access the specifed folder."
+ IDS_CANT_CREATE_DIRECTORY
+ "Unable to create the specified directory. Would you like to continue creating this new account with this home directory?"
+ IDS_INVALID_PATH "The specified path is invalid."
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_NEW_DIR_CREATED "The folder %s has been created."
+ IDS_SUCCESS2 "The new user account was created with the username %s. Do you want to restart the wizard?"
+ IDS_WONT_REQUIRE "You have selected no password expiration. The user will not be required to change passwords at next logon."
+ IDS_BAD_USER_DATA2 "An error occurred while parameters were being set for the username %s. Not all parameters were set. Would you like to restart the wizard?"
+ IDC_NO_WKSALLOWED "You are currently logged in with a user account valid only for the computer. You must be logged on with a user account valid for a domain to run this wizard. Please log on with a valid domain user account."
+ IDS_NO_HOMEDIR_DRIVE_LETTER
+ "You must select a drive letter that will be used to connect to another computer."
+ IDS_NO_RAS_NUMBER "Please provide a callback number."
+ IDS_NO_EXCH_SERVER "Please enter the name of an Exchange server."
+ IDS_BAD_RAS_NUMBER "Phone number contains invalid characters."
+ IDS_RAS_NUMBER_TOO_LONG "The phone number is too long."
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#define _AFX_NO_SPLITTER_RESOURCES
+#define _AFX_NO_OLE_RESOURCES
+#define _AFX_NO_TRACKER_RESOURCES
+#define _AFX_NO_PROPERTY_RESOURCES
+
+#include "res\Speckle.rc2" // non-Microsoft Visual C++ edited resources
+#include "afxres.rc" // Standard components
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/private/utils/wizards/addusrw/stdafx.cpp b/private/utils/wizards/addusrw/stdafx.cpp
new file mode 100644
index 000000000..22a4fceb6
--- /dev/null
+++ b/private/utils/wizards/addusrw/stdafx.cpp
@@ -0,0 +1,6 @@
+// stdafx.cpp : source file that includes just the standard includes
+// Speckle.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
diff --git a/private/utils/wizards/addusrw/stdafx.h b/private/utils/wizards/addusrw/stdafx.h
new file mode 100644
index 000000000..86bc34ada
--- /dev/null
+++ b/private/utils/wizards/addusrw/stdafx.h
@@ -0,0 +1,32 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ stdafx.h : header file
+
+ stdafx.h : include file for standard system include files,
+ or project specific include files that are used frequently, but
+ are changed infrequently
+
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+#include <afxwin.h> // MFC core and standard components
+#include <afxext.h> // MFC extensions
+
+#ifndef _AFX_NO_AFXCMN_SUPPORT
+#include <afxcmn.h> // MFC support for Windows 95 Common Controls
+#endif // _AFX_NO_AFXCMN_SUPPORT
+
+//#include <afxdisp.h> // MFC OLE automation classes
+#include <lmaccess.h>
+#include <afxtempl.h> // MFC template classes
+#include <afxmt.h> // MFC synchronization classes
+#include <afxctl.h>
+
diff --git a/private/utils/wizards/addusrw/timelist.cpp b/private/utils/wizards/addusrw/timelist.cpp
new file mode 100644
index 000000000..6eb91c1af
--- /dev/null
+++ b/private/utils/wizards/addusrw/timelist.cpp
@@ -0,0 +1,92 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ TimesList.cpp : implementation file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+#include "stdafx.h"
+#include "Speckle.h"
+#include "TimeList.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CTimesList
+
+CTimesList::CTimesList()
+{
+
+}
+
+CTimesList::~CTimesList()
+{
+}
+
+
+BEGIN_MESSAGE_MAP(CTimesList, CListBox)
+ //{{AFX_MSG_MAP(CTimesList)
+ // NOTE - the ClassWizard will add and remove mapping macros here.
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CTimesList message handlers
+
+void CTimesList::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
+{
+ CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
+
+ USHORT dwValue = (USHORT)GetItemData(lpDrawItemStruct->itemID);
+
+ switch (lpDrawItemStruct->itemAction)
+ {
+ case ODA_SELECT:
+ {
+ if (dwValue == 1)
+ {
+ SetItemData(lpDrawItemStruct->itemID, 0);
+ InvalidateRect(&lpDrawItemStruct->rcItem);
+ }
+ else
+ {
+ SetItemData(lpDrawItemStruct->itemID, 1);
+ InvalidateRect(&lpDrawItemStruct->rcItem);
+ }
+ }
+ break;
+
+ case ODA_DRAWENTIRE:
+ if (dwValue == 0)
+ {
+ pDC->FillRect(&(lpDrawItemStruct->rcItem),
+ CBrush::FromHandle(CreateSolidBrush(GetSysColor(COLOR_CAPTIONTEXT))));
+
+ pDC->DrawEdge(&lpDrawItemStruct->rcItem,
+ BDR_RAISEDOUTER | BDR_SUNKENINNER,
+ BF_BOTTOM | BF_BOTTOMRIGHT);
+ }
+ else
+ {
+ pDC->FillRect(&(lpDrawItemStruct->rcItem),
+ CBrush::FromHandle(CreateSolidBrush(GetSysColor(COLOR_ACTIVECAPTION))));
+
+ pDC->DrawEdge(&lpDrawItemStruct->rcItem,
+ BDR_RAISEDINNER | BDR_SUNKENOUTER,
+ BF_BOTTOM | BF_BOTTOMRIGHT);
+ }
+ break;
+ }
+}
diff --git a/private/utils/wizards/addusrw/timelist.h b/private/utils/wizards/addusrw/timelist.h
new file mode 100644
index 000000000..f920ad15c
--- /dev/null
+++ b/private/utils/wizards/addusrw/timelist.h
@@ -0,0 +1,53 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ TimesList.h : header file
+
+ CPropertyPage support for User mgmt wizard
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CTimesList window
+
+class CTimesList : public CListBox
+{
+// Construction
+public:
+ CTimesList();
+
+// Attributes
+public:
+
+// Operations
+public:
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CTimesList)
+ public:
+ virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CTimesList();
+
+ // Generated message map functions
+protected:
+ //{{AFX_MSG(CTimesList)
+ // NOTE - the ClassWizard will add and remove member functions here.
+ //}}AFX_MSG
+
+ DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/private/utils/wizards/addusrw/transbmp.cpp b/private/utils/wizards/addusrw/transbmp.cpp
new file mode 100644
index 000000000..7b5d7fec5
--- /dev/null
+++ b/private/utils/wizards/addusrw/transbmp.cpp
@@ -0,0 +1,175 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ // transbmp.cpp : implementation of the CTransBmp class
+//
+// support for transparent CBitmap objects. Used in the CUserList class.
+// Based on a class from MSDN 7/95
+
+ File History:
+
+ JonY Apr-96 created
+
+--*/
+
+#include "stdafx.h"
+#include "transbmp.h"
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char BASED_CODE THIS_FILE[] = __FILE__;
+#endif
+
+// Colors
+#define rgbWhite RGB(255,255,255)
+// Raster op codes
+#define DSa 0x008800C6L
+#define DSx 0x00660046L
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CTransBmp construction/destruction
+
+CTransBmp::CTransBmp()
+{
+ m_iWidth = 0;
+ m_iHeight = 0;
+ m_hbmMask = NULL;
+}
+
+CTransBmp::~CTransBmp()
+{
+ if (m_hbmMask != NULL) delete m_hbmMask;
+}
+
+void CTransBmp::GetMetrics()
+{
+ // Get the width and height
+ BITMAP bm;
+ GetObject(sizeof(bm), &bm);
+ m_iWidth = bm.bmWidth;
+ m_iHeight = bm.bmHeight;
+}
+
+
+int CTransBmp::GetWidth()
+{
+ if ((m_iWidth == 0) || (m_iHeight == 0)){
+ GetMetrics();
+ }
+ return m_iWidth;
+}
+
+int CTransBmp::GetHeight()
+{
+ if ((m_iWidth == 0) || (m_iHeight == 0)){
+ GetMetrics();
+ }
+ return m_iHeight;
+}
+
+
+void CTransBmp::CreateMask(CDC* pDC)
+{
+ m_hbmMask = new CBitmap;
+// Nuke any existing mask
+ if (m_hbmMask) m_hbmMask->DeleteObject();
+
+// Create memory DCs to work with
+ CDC* hdcMask = new CDC;
+ CDC* hdcImage = new CDC;
+
+ hdcMask->CreateCompatibleDC(pDC);
+ hdcImage->CreateCompatibleDC(pDC);
+
+// Create a monochrome bitmap for the mask
+ m_hbmMask->CreateBitmap(GetWidth(),
+ GetHeight(),
+ 1,
+ 1,
+ NULL);
+ CBitmap* pTempBmp;
+// Select the mono bitmap into its DC
+ CBitmap* hbmOldMask = hdcMask->SelectObject(m_hbmMask);
+// Select the image bitmap into its DC
+ CBitmap* hbmOldImage = hdcImage->SelectObject(pTempBmp->FromHandle((HBITMAP)m_hObject));
+
+// Set the transparency color to be the top-left pixel
+ hdcImage->SetBkColor(hdcImage->GetPixel(0, 0));
+// Make the mask
+ hdcMask->BitBlt(0, 0,
+ GetWidth(), GetHeight(),
+ hdcImage,
+ 0, 0,
+ SRCCOPY);
+// clean up
+ hdcMask->SelectObject(hbmOldMask);
+ hdcImage->SelectObject(hbmOldImage);
+ delete hdcMask;
+ delete hdcImage;
+}
+
+// draw the transparent bitmap using the created mask
+void CTransBmp::DrawTrans(CDC* pDC, int x, int y)
+{
+ if (m_hbmMask == NULL) CreateMask(pDC);
+
+ int dx = GetWidth();
+ int dy = GetHeight();
+
+// Create a memory DC to do the drawing to
+ CDC* hdcOffScr = new CDC;
+ hdcOffScr->CreateCompatibleDC(pDC);
+
+// Create a bitmap for the off-screen DC that is really
+// color compatible with the destination DC.
+ CBitmap hbmOffScr;
+ hbmOffScr.CreateBitmap(dx, dy,
+ pDC->GetDeviceCaps(PLANES),
+ pDC->GetDeviceCaps(BITSPIXEL),
+ NULL);
+
+// Select the buffer bitmap into the off-screen DC
+ HBITMAP hbmOldOffScr = (HBITMAP)hdcOffScr->SelectObject(hbmOffScr);
+
+// Copy the image of the destination rectangle to the
+// off-screen buffer DC so we can play with it
+ hdcOffScr->BitBlt(0, 0, dx, dy, pDC, x, y, SRCCOPY);
+
+// Create a memory DC for the source image
+ CDC* hdcImage = new CDC;
+ hdcImage->CreateCompatibleDC(pDC);
+
+ CBitmap* hbmOldImage = hdcImage->SelectObject(CBitmap::FromHandle((HBITMAP)m_hObject));
+
+ // Create a memory DC for the mask
+ CDC* hdcMask = new CDC;
+ hdcMask->CreateCompatibleDC(pDC);
+
+ CBitmap* hbmOldMask = hdcMask->SelectObject(m_hbmMask);
+
+ // XOR the image with the destination
+ hdcOffScr->SetBkColor(rgbWhite);
+ hdcOffScr->BitBlt(0, 0, dx, dy ,hdcImage, 0, 0, DSx);
+ // AND the destination with the mask
+ hdcOffScr->BitBlt(0, 0, dx, dy, hdcMask, 0,0, DSa);
+ // XOR the destination with the image again
+ hdcOffScr->BitBlt(0, 0, dx, dy, hdcImage, 0, 0, DSx);
+
+ // Copy the resultant image back to the screen DC
+ pDC->BitBlt(x, y, dx, dy, hdcOffScr, 0, 0, SRCCOPY);
+
+ // Tidy up
+ hdcOffScr->SelectObject(hbmOldOffScr);
+ hdcImage->SelectObject(hbmOldImage);
+ hdcMask->SelectObject(hbmOldMask);
+
+ delete hdcOffScr;
+ delete hdcImage;
+ delete hdcMask;
+}
+
+
diff --git a/private/utils/wizards/addusrw/transbmp.h b/private/utils/wizards/addusrw/transbmp.h
new file mode 100644
index 000000000..5694b66f1
--- /dev/null
+++ b/private/utils/wizards/addusrw/transbmp.h
@@ -0,0 +1,42 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ transbmp.h : header file
+
+ CPropertyPage support for User mgmt wizard
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+/////////////////////////////////////////////////////////////////////////////
+
+class CTransBmp : public CBitmap
+{
+public:
+ CTransBmp();
+ ~CTransBmp();
+ void Draw(HDC hDC, int x, int y);
+ void Draw(CDC* pDC, int x, int y);
+ void DrawTrans(HDC hDC, int x, int y);
+ void DrawTrans(CDC* pDC, int x, int y);
+ int GetWidth();
+ int GetHeight();
+
+private:
+ int m_iWidth;
+ int m_iHeight;
+ CBitmap* m_hbmMask; // handle to mask bitmap
+
+ void GetMetrics();
+ void CreateMask(HDC hDC);
+ void CreateMask(CDC* pDC);
+
+};
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/private/utils/wizards/addusrw/trstlist.cpp b/private/utils/wizards/addusrw/trstlist.cpp
new file mode 100644
index 000000000..77e44a7b1
--- /dev/null
+++ b/private/utils/wizards/addusrw/trstlist.cpp
@@ -0,0 +1,414 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ disptrus.c(pp)
+
+Author:
+
+ Scott Field (sfield) 16-Mar-96
+
+Revision:
+ JonY 16-Apr-96 Modified to .cpp
+
+--*/
+
+#include "stdafx.h"
+#include "trstlist.h"
+
+
+#define RTN_OK 0
+#define RTN_ERROR 13
+
+//
+// if you have the ddk, include ntstatus.h
+//
+#ifndef STATUS_SUCCESS
+#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
+#define STATUS_MORE_ENTRIES ((NTSTATUS)0x00000105L)
+#define STATUS_NO_MORE_ENTRIES ((NTSTATUS)0x8000001AL)
+#endif
+
+
+#define ELEMENT_COUNT 64 // number of array elements to allocate
+
+CTrustList::CTrustList()
+{
+ m_dwTrustCount = 0;
+ m_ppszTrustList = (LPWSTR *)HeapAlloc(
+ GetProcessHeap(), HEAP_ZERO_MEMORY,
+ ELEMENT_COUNT * sizeof(LPWSTR)
+ );
+}
+
+CTrustList::~CTrustList()
+{
+ //
+ // free trust list
+ //
+ unsigned int i;
+ for(i = 0 ; i < m_dwTrustCount ; i++) {
+ if(m_ppszTrustList[i] != NULL)
+ HeapFree(GetProcessHeap(), 0, m_ppszTrustList[i]);
+ }
+
+ HeapFree(GetProcessHeap(), 0, m_ppszTrustList);
+
+}
+
+BOOL
+CTrustList::BuildTrustList(
+ LPTSTR Target
+ )
+{
+ LSA_HANDLE PolicyHandle;
+ NTSTATUS Status;
+
+ PPOLICY_ACCOUNT_DOMAIN_INFO AccountDomain;
+ BOOL bDC;
+ NET_API_STATUS nas = NERR_Success; // assume success
+
+ BOOL bSuccess = FALSE; // assume this function will fail
+
+ //
+ // open the policy on the specified machine
+ //
+ Status = OpenPolicy(
+ Target,
+ POLICY_VIEW_LOCAL_INFORMATION,
+ &PolicyHandle
+ );
+
+ if(Status != STATUS_SUCCESS) {
+ SetLastError( LsaNtStatusToWinError(Status) );
+ return FALSE;
+ }
+
+ //
+ // obtain the AccountDomain, which is common to all three cases
+ //
+ Status = LsaQueryInformationPolicy(
+ PolicyHandle,
+ PolicyAccountDomainInformation,
+ (LPVOID*)&AccountDomain
+ );
+
+ if(Status != STATUS_SUCCESS)
+ goto cleanup;
+
+ //
+ // Note: AccountDomain->DomainSid will contain binary Sid
+ //
+ AddTrustToList(&AccountDomain->DomainName);
+
+ //
+ // free memory allocated for account domain
+ //
+ LsaFreeMemory(AccountDomain);
+
+ //
+ // find out if the target machine is a domain controller
+ //
+ if(!IsDomainController(Target, &bDC)) {
+ ////
+ goto cleanup;
+ }
+
+ if(!bDC) {
+ PPOLICY_PRIMARY_DOMAIN_INFO PrimaryDomain;
+ TCHAR* szPrimaryDomainName = NULL;
+ TCHAR* DomainController = NULL;
+
+ //
+ // get the primary domain
+ //
+ Status = LsaQueryInformationPolicy(
+ PolicyHandle,
+ PolicyPrimaryDomainInformation,
+ (LPVOID*)&PrimaryDomain
+ );
+
+ if(Status != STATUS_SUCCESS)
+ goto cleanup;
+
+ //
+ // if the primary domain Sid is NULL, we are a non-member, and
+ // our work is done.
+ //
+ if(PrimaryDomain->Sid == NULL) {
+ LsaFreeMemory(PrimaryDomain);
+ bSuccess = TRUE;
+ goto cleanup;
+ }
+
+ AddTrustToList(&PrimaryDomain->Name);
+
+ //
+ // build a copy of what we just added. This is necessary in order
+ // to lookup the domain controller for the specified domain.
+ // the Domain name must be NULL terminated for NetGetDCName(),
+ // and the LSA_UNICODE_STRING buffer is not necessarilly NULL
+ // terminated. Note that in a practical implementation, we
+ // could just extract the element we added, since it ends up
+ // NULL terminated.
+ //
+
+ szPrimaryDomainName = (LPTSTR)HeapAlloc(
+ GetProcessHeap(), 0,
+ PrimaryDomain->Name.Length + sizeof(WCHAR) // existing length + NULL
+ );
+
+ if(szPrimaryDomainName != NULL) {
+ //
+ // copy the existing buffer to the new storage, appending a NULL
+ //
+ _tcsncpy(
+ szPrimaryDomainName,
+ PrimaryDomain->Name.Buffer,
+ (PrimaryDomain->Name.Length / 2) + 1
+ );
+ }
+
+ LsaFreeMemory(PrimaryDomain);
+
+ if(szPrimaryDomainName == NULL) goto cleanup;
+
+ //
+ // get the primary domain controller computer name
+ //
+ nas = NetGetDCName(
+ NULL,
+ szPrimaryDomainName,
+ (LPBYTE *)&DomainController
+ );
+
+ HeapFree(GetProcessHeap(), 0, szPrimaryDomainName);
+
+ if(nas != NERR_Success)
+ goto cleanup;
+
+ //
+ // close the policy handle, because we don't need it anymore
+ // for the workstation case, as we open a handle to a DC
+ // policy below
+ //
+ LsaClose(PolicyHandle);
+ PolicyHandle = INVALID_HANDLE_VALUE; // invalidate handle value
+
+ //
+ // open the policy on the domain controller
+ //
+ Status = OpenPolicy(
+ DomainController,
+ POLICY_VIEW_LOCAL_INFORMATION,
+ &PolicyHandle
+ );
+
+ //
+ // free the domaincontroller buffer
+ //
+ NetApiBufferFree(DomainController);
+
+ if(Status != STATUS_SUCCESS)
+ goto cleanup;
+ }
+
+ //
+ // build additional trusted domain(s) list and indicate if successful
+ //
+ bSuccess = EnumTrustedDomains(PolicyHandle);
+
+cleanup:
+
+ //
+ // close the policy handle
+ //
+ if(PolicyHandle != INVALID_HANDLE_VALUE)
+ LsaClose(PolicyHandle);
+
+ if(!bSuccess) {
+ if(Status != STATUS_SUCCESS)
+ SetLastError( LsaNtStatusToWinError(Status) );
+ else if(nas != NERR_Success)
+ SetLastError( nas );
+ }
+
+ return bSuccess;
+}
+
+BOOL
+CTrustList::EnumTrustedDomains(
+ LSA_HANDLE PolicyHandle
+ )
+{
+ LSA_ENUMERATION_HANDLE lsaEnumHandle=0; // start an enum
+ PLSA_TRUST_INFORMATION TrustInfo;
+ ULONG ulReturned; // number of items returned
+ ULONG ulCounter; // counter for items returned
+ NTSTATUS Status;
+
+ do {
+ Status = LsaEnumerateTrustedDomains(
+ PolicyHandle, // open policy handle
+ &lsaEnumHandle, // enumeration tracker
+ (LPVOID*)&TrustInfo, // buffer to receive data
+ 32000, // recommended buffer size
+ &ulReturned // number of items returned
+ );
+ //
+ // get out if an error occurred
+ //
+ if( (Status != STATUS_SUCCESS) &&
+ (Status != STATUS_MORE_ENTRIES) &&
+ (Status != STATUS_NO_MORE_ENTRIES)
+ ) {
+ SetLastError( LsaNtStatusToWinError(Status) );
+ return FALSE;
+ }
+
+ //
+ // Display results
+ // Note: Sids are in TrustInfo[ulCounter].Sid
+ //
+ for(ulCounter = 0 ; ulCounter < ulReturned ; ulCounter++)
+ AddTrustToList(&TrustInfo[ulCounter].Name);
+
+ //
+ // free the buffer
+ //
+ LsaFreeMemory(TrustInfo);
+
+ } while (Status != STATUS_NO_MORE_ENTRIES);
+
+ return TRUE;
+}
+
+BOOL
+CTrustList::IsDomainController(
+ LPTSTR Server,
+ LPBOOL bDomainController
+ )
+{
+ PSERVER_INFO_101 si101;
+ NET_API_STATUS nas;
+
+ nas = NetServerGetInfo(
+ Server,
+ 101, // info-level
+ (LPBYTE *)&si101
+ );
+
+ if(nas != NERR_Success) {
+ SetLastError(nas);
+ return FALSE;
+ }
+
+ if( (si101->sv101_type & SV_TYPE_DOMAIN_CTRL) ||
+ (si101->sv101_type & SV_TYPE_DOMAIN_BAKCTRL) ) {
+ //
+ // we are dealing with a DC
+ //
+ *bDomainController = TRUE;
+ } else {
+ *bDomainController = FALSE;
+ }
+
+ NetApiBufferFree(si101);
+
+ return TRUE;
+}
+
+BOOL
+CTrustList::AddTrustToList(
+ PLSA_UNICODE_STRING UnicodeString
+ )
+{
+ if(m_dwTrustCount > ELEMENT_COUNT) return FALSE;
+
+ //
+ // allocate storage for array element
+ //
+ m_ppszTrustList[m_dwTrustCount] = (LPWSTR)HeapAlloc(
+ GetProcessHeap(), 0,
+ UnicodeString->Length + sizeof(WCHAR) // existing length + NULL
+ );
+
+ if(m_ppszTrustList[m_dwTrustCount] == NULL) return FALSE;
+
+ //
+ // copy the existing buffer to the new storage, appending a NULL
+ //
+ lstrcpynW(
+ m_ppszTrustList[m_dwTrustCount],
+ UnicodeString->Buffer,
+ (UnicodeString->Length / 2) + 1
+ );
+
+ m_dwTrustCount++; // increment the trust count
+
+ return TRUE;
+}
+
+void
+CTrustList::InitLsaString(
+ PLSA_UNICODE_STRING LsaString,
+ LPTSTR String
+ )
+{
+ DWORD StringLength;
+
+ if (String == NULL) {
+ LsaString->Buffer = NULL;
+ LsaString->Length = 0;
+ LsaString->MaximumLength = 0;
+
+ return;
+ }
+
+ StringLength = _tcslen(String);
+ LsaString->Buffer = String;
+ LsaString->Length = (USHORT) StringLength * sizeof(WCHAR);
+ LsaString->MaximumLength = (USHORT) (StringLength + 1) * sizeof(WCHAR);
+}
+
+NTSTATUS
+CTrustList::OpenPolicy(
+ LPTSTR ServerName,
+ DWORD DesiredAccess,
+ PLSA_HANDLE PolicyHandle
+ )
+{
+ LSA_OBJECT_ATTRIBUTES ObjectAttributes;
+ LSA_UNICODE_STRING ServerString;
+ PLSA_UNICODE_STRING Server;
+
+ //
+ // Always initialize the object attributes to all zeroes
+ //
+ ZeroMemory(&ObjectAttributes, sizeof(ObjectAttributes));
+
+ if(ServerName != NULL) {
+ //
+ // Make a LSA_UNICODE_STRING out of the LPWSTR passed in
+ //
+ InitLsaString(&ServerString, ServerName);
+
+ Server = &ServerString;
+ } else {
+ Server = NULL;
+ }
+
+ //
+ // Attempt to open the policy
+ //
+ return LsaOpenPolicy(
+ Server,
+ &ObjectAttributes,
+ DesiredAccess,
+ PolicyHandle
+ );
+}
+
+
diff --git a/private/utils/wizards/addusrw/trstlist.h b/private/utils/wizards/addusrw/trstlist.h
new file mode 100644
index 000000000..dc60275a3
--- /dev/null
+++ b/private/utils/wizards/addusrw/trstlist.h
@@ -0,0 +1,56 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Trstlist.h : header file
+
+ CPropertyPage support for User mgmt wizard
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+
+#include <windows.h>
+#include <lm.h>
+#include <ntsecapi.h> // \mstools\security\ntsecapi.h
+#include <tchar.h>
+
+class CTrustList
+{
+ public:
+ TCHAR** m_ppszTrustList; // array of trust elements
+ DWORD m_dwTrustCount; // number of elements in m_ppszTrustList
+
+ CTrustList();
+ ~CTrustList();
+
+ BOOL BuildTrustList(LPTSTR Target);
+
+ private:
+ BOOL IsDomainController(LPTSTR Server,
+ LPBOOL bDomainController);
+
+ BOOL EnumTrustedDomains(LSA_HANDLE PolicyHandle);
+
+ BOOL AddTrustToList(PLSA_UNICODE_STRING UnicodeString);
+
+ //
+ // helper functions
+ //
+
+ void InitLsaString(PLSA_UNICODE_STRING LsaString,
+ LPTSTR String);
+
+ NTSTATUS OpenPolicy(LPTSTR ServerName,
+ DWORD DesiredAccess,
+ PLSA_HANDLE PolicyHandle);
+
+
+};
+
diff --git a/private/utils/wizards/addusrw/userlist.cpp b/private/utils/wizards/addusrw/userlist.cpp
new file mode 100644
index 000000000..31ffcd973
--- /dev/null
+++ b/private/utils/wizards/addusrw/userlist.cpp
@@ -0,0 +1,216 @@
+/**********************************************************************/
+/** Microsoft Windows NT **/
+/** Copyright(c) Microsoft Corp., 1991-1996 **/
+/**********************************************************************/
+
+/*
+ UserList.cpp
+
+ CListBox class for owner draw list that displays users and groups
+
+ FILE HISTORY:
+ jony Apr-1996 created
+*/
+
+#include "stdafx.h"
+#include "resource.h"
+#include "UserList.h"
+
+const unsigned short BITMAP_HEIGHT = 18;
+const unsigned short BITMAP_WIDTH = 18;
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CUserList
+
+CUserList::CUserList()
+{
+ m_pBitmap[0] = new CTransBmp;
+ m_pBitmap[0]->LoadBitmap(IDB_USER_BITMAP);
+
+ m_pBitmap[1] = new CTransBmp;
+ m_pBitmap[1]->LoadBitmap(IDB_GLOBAL_GROUP_BITMAP);
+
+ m_pBitmap[2] = new CTransBmp;
+ m_pBitmap[2]->LoadBitmap(IDB_WORLD);
+
+ m_pBitmap[3] = new CTransBmp;
+ m_pBitmap[3]->LoadBitmap(IDB_LOCAL_GROUP_BITMAP);
+
+ m_sHScrollWidth = 0;
+}
+
+CUserList::~CUserList()
+{
+ delete m_pBitmap[0];
+ delete m_pBitmap[1];
+ delete m_pBitmap[2];
+ delete m_pBitmap[3];
+
+}
+
+
+BEGIN_MESSAGE_MAP(CUserList, CListBox)
+ //{{AFX_MSG_MAP(CUserList)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CUserList message handlers
+void CUserList::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
+{
+// is this a valid item?
+ if ((GetCount() == LB_ERR) || (lpDrawItemStruct->itemID > (UINT)GetCount())) return;
+
+ COLORREF crefOldText;
+ COLORREF crefOldBk;
+
+ CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
+ pDC->SetBkMode(TRANSPARENT);
+
+ HBRUSH hBrush;
+ CTransBmp* pTempBmp = (CTransBmp*)lpDrawItemStruct->itemData;
+
+ switch (lpDrawItemStruct->itemAction)
+ {
+ case ODA_SELECT:
+ case ODA_DRAWENTIRE:
+// Display the text associated with the item.
+ HBITMAP hBitmapOld;
+
+// Is the item selected?
+ if (lpDrawItemStruct->itemState & ODS_SELECTED)
+ {
+ hBrush = CreateSolidBrush( GetSysColor(COLOR_HIGHLIGHT));
+ hBitmapOld = (HBITMAP)pDC->SelectObject(pTempBmp);
+
+ crefOldText = pDC->SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT) );
+ crefOldBk = pDC->SetBkColor(GetSysColor(COLOR_HIGHLIGHT) );
+ }
+ else
+ {
+ hBrush = (HBRUSH)GetStockObject( GetSysColor(COLOR_WINDOW));
+ hBitmapOld = (HBITMAP)pDC->SelectObject(pTempBmp);
+
+ crefOldText = pDC->SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
+ crefOldBk = pDC->SetBkColor(GetSysColor(COLOR_WINDOW));
+
+ }
+
+ pDC->FillRect(&(lpDrawItemStruct->rcItem), CBrush::FromHandle(hBrush));
+
+// display text
+ TCHAR* pName = (TCHAR*)malloc(255 * sizeof(TCHAR));
+ if (pName == NULL)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
+ exit(1);
+ }
+
+ GetText(lpDrawItemStruct->itemID, pName);
+ TCHAR* pName2;
+ pName = _tcstok(pName, _T(";")); // gets the name
+ pName2 = _tcstok(NULL, _T(";")); // gets the comment
+
+// format the name + comment
+ int nTop = (lpDrawItemStruct->rcItem.bottom + lpDrawItemStruct->rcItem.top) / 2;
+ pDC->TextOut(BITMAP_WIDTH + 6,
+ (nTop - 8),
+ pName);
+
+ pDC->TextOut(130,
+ (nTop - 8),
+ pName2);
+
+ free(pName);
+
+// Display bitmap
+ nTop = (lpDrawItemStruct->rcItem.bottom + lpDrawItemStruct->rcItem.top - BITMAP_HEIGHT) / 2;
+
+ pTempBmp->DrawTrans(pDC, lpDrawItemStruct->rcItem.left, nTop);
+
+ pDC->SetBkColor(crefOldBk );
+ pDC->SetTextColor(crefOldText );
+ pDC->SelectObject(hBitmapOld);
+
+ break;
+ }
+
+}
+int CUserList::AddString(LPCTSTR lpItem)
+{
+ int nPos = CListBox::AddString((const TCHAR*) lpItem);
+ if (nPos == LB_ERR) return LB_ERR;
+ SetItemData(nPos, (unsigned long)m_pBitmap[1]);
+
+ return nPos;
+}
+
+int CUserList::AddString(LPCTSTR lpItem, USHORT usBitmapID)
+{
+ int nPos = CListBox::AddString((const TCHAR*) lpItem);
+ if (nPos == LB_ERR) return LB_ERR;
+ SetItemData(nPos, (DWORD)m_pBitmap[usBitmapID]);
+
+ return nPos;
+}
+
+
+void CUserList::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
+{
+ lpMeasureItemStruct->itemHeight = 20;
+}
+
+
+int CUserList::VKeyToItem(UINT nKey, UINT nIndex)
+{
+ // TODO: Add your code to handle a particular virtual key
+ // return -1 = default action
+ // return -2 = no further action
+ // return index = perform default action for keystroke on
+ // item specified by index
+
+ if (nKey == 46) DeleteString(GetCurSel());
+ return -1;
+}
+
+int CUserList::AddString(short nType, LPCTSTR lpItem)
+{
+ int nPos = CListBox::AddString((const TCHAR*) lpItem);
+ if (nPos == LB_ERR) return LB_ERR;
+ SetItemData(nPos, (DWORD)m_pBitmap[nType]);
+
+ return nPos;
+}
+
+short CUserList::GetBitmapID()
+{
+ USHORT sSel = GetCurSel();
+ if (sSel == LB_ERR) return -1;
+ USHORT sCount = 0;
+
+ while ((sCount < 4) && ((CBitmap*)GetItemData(sSel) != m_pBitmap[sCount])) sCount++;
+ return sCount;
+
+}
+
+short CUserList::GetBitmapID(USHORT sSel)
+{
+ USHORT sCount = 0;
+
+ DWORD dwData = GetItemData(sSel);
+ DWORD dwBmp = (DWORD)m_pBitmap[0];
+ while ((sCount < 4) && (dwData != dwBmp))
+ {
+ sCount++;
+ dwBmp = (DWORD)m_pBitmap[sCount];
+ }
+
+ return sCount;
+
+}
diff --git a/private/utils/wizards/addusrw/userlist.h b/private/utils/wizards/addusrw/userlist.h
new file mode 100644
index 000000000..ed4fc5e69
--- /dev/null
+++ b/private/utils/wizards/addusrw/userlist.h
@@ -0,0 +1,61 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ UserList.h : header file
+
+ CPropertyPage support for User mgmt wizard
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+#include "transbmp.h"
+/////////////////////////////////////////////////////////////////////////////
+// CUserList window
+
+class CUserList : public CListBox
+{
+// Construction
+public:
+ CUserList();
+
+// Attributes
+public:
+private:
+ CTransBmp* m_pBitmap[4];
+ unsigned short m_sHScrollWidth;
+// Operations
+public:
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CUserList)
+ public:
+ virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
+ virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
+ virtual int VKeyToItem(UINT nKey, UINT nIndex);
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CUserList();
+ int AddString(LPCTSTR lpItem);
+ int AddString(short nType, LPCTSTR lpItem);
+ int AddString(LPCTSTR lpItem, USHORT dwBitmap);
+ short GetBitmapID();
+ short GetBitmapID(USHORT sSel);
+
+ // Generated message map functions
+protected:
+ //{{AFX_MSG(CUserList)
+ //}}AFX_MSG
+
+ DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/private/utils/wizards/addusrw/welcome.cpp b/private/utils/wizards/addusrw/welcome.cpp
new file mode 100644
index 000000000..320243514
--- /dev/null
+++ b/private/utils/wizards/addusrw/welcome.cpp
@@ -0,0 +1,576 @@
+/**********************************************************************/
+/** Microsoft Windows NT **/
+/** Copyright(c) Microsoft Corp., 1991-1996 **/
+/**********************************************************************/
+
+/*
+ WelcomeDlg.cpp
+
+ CPropertyPage support for User management wizard
+
+ FILE HISTORY:
+ jony Apr-1996 created
+*/
+
+#include "stdafx.h"
+#include "Speckle.h"
+#include "wizbased.h"
+#include "Welcome.h"
+#include "trstlist.h"
+
+#include <winreg.h>
+#include <lmerr.h>
+#include <lmapibuf.h>
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CWelcomeDlg property page
+
+IMPLEMENT_DYNCREATE(CWelcomeDlg, CWizBaseDlg)
+
+CWelcomeDlg::CWelcomeDlg() : CWizBaseDlg(CWelcomeDlg::IDD)
+{
+ //{{AFX_DATA_INIT(CWelcomeDlg)
+ //}}AFX_DATA_INIT
+
+ m_pFont = NULL;
+}
+
+CWelcomeDlg::~CWelcomeDlg()
+{
+ if (m_pFont != NULL) delete m_pFont;
+}
+
+void CWelcomeDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CWelcomeDlg)
+ DDX_Control(pDX, IDC_DOMAIN_LIST, m_cbDomainList);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CWelcomeDlg, CPropertyPage)
+ //{{AFX_MSG_MAP(CWelcomeDlg)
+ ON_WM_SHOWWINDOW()
+ //}}AFX_MSG_MAP
+
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CWelcomeDlg message handlers
+BOOL CWelcomeDlg::OnInitDialog()
+{
+ CPropertyPage::OnInitDialog();
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+// read cached domain list from registry
+ DWORD dwRet;
+ HKEY hKey;
+ DWORD cbProv = 0;
+ TCHAR* lpProv = NULL;
+
+ BOOL bFoundOne = FALSE;
+
+ long lRet = RegConnectRegistry(
+ (LPTSTR)pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength()),
+ HKEY_LOCAL_MACHINE,
+ &hKey);
+
+ dwRet = RegOpenKey(hKey,
+ TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"), &hKey );
+
+ TCHAR* lpPrimaryDomain = NULL;
+ if ((dwRet = RegQueryValueEx( hKey, TEXT(/*"CachePrimaryDomain"*/"DefaultDomainName"), NULL, NULL, NULL, &cbProv )) == ERROR_SUCCESS)
+ {
+ lpPrimaryDomain = (TCHAR*)malloc(cbProv);
+ if (lpPrimaryDomain == NULL)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
+ ExitProcess(1);
+ }
+ dwRet = RegQueryValueEx( hKey, TEXT(/*"CachePrimaryDomain"*/"DefaultDomainName"), NULL, NULL, (LPBYTE) lpPrimaryDomain, &cbProv );
+ bFoundOne = TRUE;
+ }
+
+ m_csPrimaryDomain = lpPrimaryDomain;
+ free(lpPrimaryDomain);
+ RegCloseKey(hKey);
+
+ CString csMachineName;
+ DWORD dwSize = MAX_COMPUTERNAME_LENGTH + 1;
+ GetComputerName(csMachineName.GetBufferSetLength(MAX_COMPUTERNAME_LENGTH + 1), &dwSize);
+
+ pApp->m_csCurrentMachine = csMachineName;
+
+// read the list of trusted domains
+ CTrustList pList;
+ if (!pList.BuildTrustList((LPTSTR)pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength())))
+ {
+/* if this fails its probably because they are running the wizard
+ from a machine account that doesn't exist on the domain level.
+ Add only the local machine and select it.*/
+ m_cbDomainList.AddString(pApp->m_csCurrentMachine);
+ m_cbDomainList.SelectString(-1, pApp->m_csCurrentMachine);
+ }
+
+ else
+ {
+ UINT i;
+ for(i = 0 ; i < pList.m_dwTrustCount ; i++)
+ m_cbDomainList.AddString(pList.m_ppszTrustList[i]);
+
+// remove the current machine from the list
+// if ((i = m_cbDomainList.FindStringExact(-1, pApp->m_csCurrentMachine)) != LB_ERR)
+// m_cbDomainList.DeleteString(i);
+
+// now select the default domain into view
+ int nSel = m_cbDomainList.SelectString(-1, m_csPrimaryDomain);
+ m_cbDomainList.GetWindowText(m_csDomain);
+ UpdateData(FALSE);
+ }
+
+// welcome text
+ m_pFont = new CFont;
+ LOGFONT lf;
+
+ memset(&lf, 0, sizeof(LOGFONT)); // Clear out structure.
+ lf.lfHeight = 15;
+ _tcscpy(lf.lfFaceName, L"MS Sans Serif");
+ lf.lfWeight = 700;
+ m_pFont->CreateFontIndirect(&lf); // Create the font.
+
+ CString cs;
+ cs.LoadString(IDS_WELCOME_STRING);
+ CWnd* pWnd = GetDlgItem(IDC_STATIC1);
+ pWnd->SetWindowText(cs);
+ pWnd->SetFont(m_pFont);
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+LRESULT CWelcomeDlg::OnWizardNext()
+{
+ UpdateData(TRUE);
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+// get the DC of the selected domain
+ m_cbDomainList.GetWindowText(m_csDomain);
+
+// same as last time? no need to check again.
+ if (m_csLastDomain == m_csDomain) return CPropertyPage::OnWizardNext();
+
+ CWaitCursor wait;
+
+ pApp->m_csDomain = m_csDomain;
+ pApp->m_bDomain = FALSE;
+ TCHAR* pDomain = m_csDomain.GetBuffer(m_csDomain.GetLength());
+ m_csDomain.ReleaseBuffer();
+
+ TCHAR* pDC;
+ NET_API_STATUS nApi;
+
+// local machine?
+ if (m_csDomain == pApp->m_csCurrentMachine)
+ {
+ pApp->m_csServer = CString(L"\\\\") + pApp->m_csCurrentMachine;
+ pDC = pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength());
+ }
+
+ else
+ {
+ nApi = NetGetDCName(NULL,
+ pDomain,
+ (LPBYTE*)&pDC);
+
+ if (nApi != NERR_Success)
+ {
+ AfxMessageBox(IDS_NODC, MB_ICONSTOP);
+ return -1;
+ }
+ pApp->m_csServer = pDC;
+ pApp->m_bDomain = TRUE;
+ }
+
+// we really shouldn't proceed until we know we are an admin on the remote machine
+ BYTE sidBuffer[100];
+ PSID pSID = (PSID)&sidBuffer;
+ BOOL bRet;
+
+// create a SID for the Administrators group
+ SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
+ bRet = AllocateAndInitializeSid(&SIDAuth,
+ 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ &pSID);
+
+ if (!bRet)
+ {
+ DWORD dw = GetLastError();
+ ASSERT(0);
+ }
+
+ TCHAR pName[256];
+ DWORD dwNameLen = 256;
+ TCHAR pDomainName[256];
+ DWORD dwDomainNameLen = 256;
+ SID_NAME_USE SNU;
+
+ bRet = LookupAccountSid(pDC,
+ pSID,
+ pName,
+ &dwNameLen,
+ pDomainName,
+ &dwDomainNameLen,
+ &SNU);
+
+// get the users name and domain from the reg for comparison
+ DWORD dwRet;
+ HKEY hKey;
+ DWORD cbProv = 0;
+
+ CString csUsername;
+ CString csDomainName;
+ dwRet = RegOpenKey(HKEY_LOCAL_MACHINE,
+ TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"), &hKey );
+
+ if ((dwRet = RegQueryValueEx( hKey, TEXT("DefaultDomainName"), NULL, NULL, NULL, &cbProv )) == ERROR_SUCCESS)
+ {
+ dwRet = RegQueryValueEx( hKey, TEXT("DefaultDomainName"),
+ NULL,
+ NULL,
+ (LPBYTE)csDomainName.GetBufferSetLength(cbProv),
+ &cbProv );
+ }
+
+ TCHAR* lpDefaultUserName = NULL;
+ if ((dwRet = RegQueryValueEx( hKey, TEXT("DefaultUserName"), NULL, NULL, NULL, &cbProv )) == ERROR_SUCCESS)
+ {
+ dwRet = RegQueryValueEx( hKey, TEXT("DefaultUserName"),
+ NULL,
+ NULL,
+ (LPBYTE)csUsername.GetBufferSetLength(cbProv),
+ &cbProv );
+ }
+
+ RegCloseKey(hKey);
+
+// now enumerate the members of the admin group to see if we are a member
+ BOOL bAdmin = FALSE;
+ PLOCALGROUP_MEMBERS_INFO_1 pMembers;
+ DWORD dwEntriesRead, dwTotalEntries;
+ DWORD dwResumeHandle = 0;
+ nApi = NetLocalGroupGetMembers(pDC,
+ pName,
+ 1,
+ (LPBYTE*)&pMembers,
+ 5000,
+ &dwEntriesRead,
+ &dwTotalEntries,
+ &dwResumeHandle);
+
+ if (nApi == NERR_Success)
+ {
+ USHORT sIndex = 0;
+ while (sIndex < dwEntriesRead)
+ {
+ TCHAR pName[50];
+ DWORD dwNameSize = 50;
+ TCHAR pDomain[50];
+ DWORD dwDomainNameSize = 50;
+ SID_NAME_USE pUse;
+ LookupAccountSid(pDC, pMembers[sIndex].lgrmi1_sid,
+ pName, &dwNameSize,
+ pDomain, &dwDomainNameSize,
+ &pUse);
+
+ if (((pUse == SidTypeGroup) && (bParseGlobalGroup(pName, csUsername, csDomainName))) ||
+ ((!csUsername.CompareNoCase(pName)) && (!csDomainName.CompareNoCase(pDomain))))
+ {
+ bAdmin = TRUE;
+ break;
+ }
+
+ sIndex++;
+ }
+
+ NetApiBufferFree(pMembers);
+
+ while ((dwResumeHandle != 0) && (!bAdmin))
+ {
+ nApi = NetLocalGroupGetMembers(pDC,
+ pName,
+ 1,
+ (LPBYTE*)&pMembers,
+ 5000,
+ &dwEntriesRead,
+ &dwTotalEntries,
+ &dwResumeHandle);
+
+ if (nApi == NERR_Success)
+ {
+ USHORT sIndex = 0;
+ while (sIndex < dwEntriesRead)
+ {
+ TCHAR pName[50];
+ DWORD dwNameSize = 50;
+ TCHAR pDomain[50];
+ DWORD dwDomainNameSize = 50;
+ SID_NAME_USE pUse;
+ LookupAccountSid(pDC, pMembers[sIndex].lgrmi1_sid,
+ pName, &dwNameSize,
+ pDomain, &dwDomainNameSize,
+ &pUse);
+
+ if (((pUse == SidTypeGroup) && (bParseGlobalGroup(pName, csUsername, csDomainName))) ||
+ ((!csUsername.CompareNoCase(pName)) && (!csDomainName.CompareNoCase(pDomain))))
+ {
+ bAdmin = TRUE;
+ break;
+ }
+
+ sIndex++;
+ }
+ }
+ NetApiBufferFree(pMembers);
+ }
+ }
+
+ if (!bAdmin) // not in the administrators group - check the account ops group
+ {
+ BYTE sidBuffer[100];
+ PSID pSID = (PSID)&sidBuffer;
+ BOOL bRet;
+
+// create a SID for the Account Operators group
+ SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
+ bRet = AllocateAndInitializeSid(&SIDAuth,
+ 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ACCOUNT_OPS,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ 0,
+ &pSID);
+
+ if (!bRet)
+ {
+ DWORD dw = GetLastError();
+ ASSERT(0);
+ }
+
+ TCHAR pName[256];
+ DWORD dwNameLen = 256;
+ TCHAR pDomainName[256];
+ DWORD dwDomainNameLen = 256;
+ SID_NAME_USE SNU;
+
+ bRet = LookupAccountSid(pDC,
+ pSID,
+ pName,
+ &dwNameLen,
+ pDomainName,
+ &dwDomainNameLen,
+ &SNU);
+
+// now enumerate the members of the group to see if we are a member
+ PLOCALGROUP_MEMBERS_INFO_1 pMembers;
+ DWORD dwEntriesRead, dwTotalEntries;
+ DWORD dwResumeHandle = 0;
+ nApi = NetLocalGroupGetMembers(pDC,
+ pName,
+ 1,
+ (LPBYTE*)&pMembers,
+ 5000,
+ &dwEntriesRead,
+ &dwTotalEntries,
+ &dwResumeHandle);
+
+ if (nApi == NERR_Success)
+ {
+ USHORT sIndex = 0;
+ while (sIndex < dwEntriesRead)
+ {
+ TCHAR pName[50];
+ DWORD dwNameSize = 50;
+ TCHAR pDomain[50];
+ DWORD dwDomainNameSize = 50;
+ SID_NAME_USE pUse;
+ LookupAccountSid(pDC, pMembers[sIndex].lgrmi1_sid,
+ pName, &dwNameSize,
+ pDomain, &dwDomainNameSize,
+ &pUse);
+
+ if (((pUse == SidTypeGroup) && (bParseGlobalGroup(pName, csUsername, csDomainName))) ||
+ ((!csUsername.CompareNoCase(pName)) && (!csDomainName.CompareNoCase(pDomain))))
+ {
+ bAdmin = TRUE;
+ break;
+ }
+
+ sIndex++;
+ }
+
+ NetApiBufferFree(pMembers);
+
+ while ((dwResumeHandle != 0) && (!bAdmin))
+ {
+ nApi = NetLocalGroupGetMembers(pDC,
+ pName,
+ 1,
+ (LPBYTE*)&pMembers,
+ 5000,
+ &dwEntriesRead,
+ &dwTotalEntries,
+ &dwResumeHandle);
+
+ if (nApi == NERR_Success)
+ {
+ USHORT sIndex = 0;
+ while (sIndex < dwEntriesRead)
+ {
+ TCHAR pName[50];
+ DWORD dwNameSize = 50;
+ TCHAR pDomain[50];
+ DWORD dwDomainNameSize = 50;
+ SID_NAME_USE pUse;
+ LookupAccountSid(pDC, pMembers[sIndex].lgrmi1_sid,
+ pName, &dwNameSize,
+ pDomain, &dwDomainNameSize,
+ &pUse);
+
+ if (((pUse == SidTypeGroup) && (bParseGlobalGroup(pName, csUsername, csDomainName))) ||
+ ((!csUsername.CompareNoCase(pName)) && (!csDomainName.CompareNoCase(pDomain))))
+ {
+ bAdmin = TRUE;
+ break;
+ }
+
+ sIndex++;
+ }
+ }
+ NetApiBufferFree(pMembers);
+ }
+ }
+
+ }
+
+// not an admin? don't continue
+ if (!bAdmin)
+ {
+ AfxMessageBox(IDS_NOT_ADMIN);
+ return -1;
+ }
+
+// store the domain name for a possible rerun.
+ m_csLastDomain = m_csDomain;
+
+ return CPropertyPage::OnWizardNext();
+
+}
+
+// this gets called to look into a global group which is included in the admin or account ops local group.
+// these groups live on the DC of the domain passed in.
+BOOL CWelcomeDlg::bParseGlobalGroup(LPTSTR lpGroupName, CString& lpName, CString& lpDomain)
+{
+ DWORD dwEntriesRead;
+ DWORD dwTotalEntries;
+ DWORD dwResumeHandle = 0;
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+ TCHAR* pDomain = lpDomain.GetBuffer(lpDomain.GetLength());
+ lpDomain.ReleaseBuffer();
+
+ TCHAR* pServer;
+ NET_API_STATUS nApi = NetGetDCName(NULL,
+ pDomain,
+ (LPBYTE*)&pServer);
+
+ if (nApi != NERR_Success)
+ {
+ AfxMessageBox(IDS_NODC, MB_ICONSTOP);
+ return FALSE;
+ }
+
+ PGROUP_USERS_INFO_1 pMembers;
+ nApi = NetGroupGetUsers(pServer,
+ lpGroupName,
+ 1,
+ (LPBYTE*)&pMembers,
+ 5000,
+ &dwEntriesRead,
+ &dwTotalEntries,
+ &dwResumeHandle);
+
+ if (nApi != ERROR_SUCCESS)
+ {
+ NetApiBufferFree(pServer);
+ return FALSE;
+ }
+
+ USHORT sIndex;
+ for (sIndex = 0; sIndex < dwEntriesRead; sIndex++)
+ {
+ if (!lpName.CompareNoCase(pMembers[sIndex].grui1_name))
+ {
+ NetApiBufferFree(pServer);
+ return TRUE;
+ }
+ }
+
+ while (dwResumeHandle != 0)
+ {
+ nApi = NetGroupGetUsers(pServer,
+ lpGroupName,
+ 1,
+ (LPBYTE*)&pMembers,
+ 5000,
+ &dwEntriesRead,
+ &dwTotalEntries,
+ &dwResumeHandle);
+
+ if (nApi != ERROR_SUCCESS)
+ {
+ NetApiBufferFree(pServer);
+ return FALSE;
+ }
+
+ for (sIndex = 0; sIndex < dwEntriesRead; sIndex++)
+ {
+ if (!lpName.CompareNoCase(pMembers[sIndex].grui1_name))
+ {
+ NetApiBufferFree(pServer);
+ return TRUE;
+ }
+ }
+ }
+
+ NetApiBufferFree(pServer);
+ return FALSE;
+}
+
+
+void CWelcomeDlg::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CPropertyPage::OnShowWindow(bShow, nStatus);
+
+ CSpeckleApp* pApp = (CSpeckleApp*)AfxGetApp();
+
+ if (bShow) pApp->m_cps1.SetWizardButtons(PSWIZB_NEXT);
+ else pApp->m_cps1.SetWizardButtons(PSWIZB_BACK | PSWIZB_NEXT);
+
+}
diff --git a/private/utils/wizards/addusrw/welcome.h b/private/utils/wizards/addusrw/welcome.h
new file mode 100644
index 000000000..f77d2973a
--- /dev/null
+++ b/private/utils/wizards/addusrw/welcome.h
@@ -0,0 +1,62 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ WelcomeDlg.h : header file
+
+ CPropertyPage support for User mgmt wizard
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CWelcomeDlg dialog
+
+class CWelcomeDlg : public CWizBaseDlg
+{
+ DECLARE_DYNCREATE(CWelcomeDlg)
+
+// Construction
+public:
+ CWelcomeDlg();
+ ~CWelcomeDlg();
+
+// Dialog Data
+ //{{AFX_DATA(CWelcomeDlg)
+ enum { IDD = IDD_WELCOME_DIALOG };
+ CComboBox m_cbDomainList;
+ //}}AFX_DATA
+ virtual LRESULT OnWizardNext();
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CWelcomeDlg)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CWelcomeDlg)
+ virtual BOOL OnInitDialog();
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ //}}AFX_MSG
+
+ DECLARE_MESSAGE_MAP()
+
+private:
+ CString m_csPrimaryDomain;
+ CString m_csDomain;
+ CFont* m_pFont;
+ CString m_csLastDomain;
+ BOOL bParseGlobalGroup(LPTSTR lpGroupName, CString& lpName, CString& lpDomain);
+
+};
diff --git a/private/utils/wizards/addusrw/wizbased.cpp b/private/utils/wizards/addusrw/wizbased.cpp
new file mode 100644
index 000000000..da5a407c2
--- /dev/null
+++ b/private/utils/wizards/addusrw/wizbased.cpp
@@ -0,0 +1,68 @@
+/**********************************************************************/
+/** Microsoft Windows NT **/
+/** Copyright(c) Microsoft Corp., 1991-1996 **/
+/**********************************************************************/
+
+/*
+ WizBaseD.cpp
+
+ CPropertyPage support for User management wizard
+
+ FILE HISTORY:
+ jony Apr-1996 created
+*/
+
+
+#include "stdafx.h"
+#include "Speckle.h"
+#include "WizBaseD.h"
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CWizBaseDlg property page
+
+IMPLEMENT_DYNCREATE(CWizBaseDlg, CPropertyPage)
+
+CWizBaseDlg::CWizBaseDlg() : CPropertyPage(CWizBaseDlg::IDD)
+{
+ //{{AFX_DATA_INIT(CWizBaseDlg)
+ // NOTE: the ClassWizard will add member initialization here
+ //}}AFX_DATA_INIT
+}
+
+CWizBaseDlg::~CWizBaseDlg()
+{
+}
+
+CWizBaseDlg::CWizBaseDlg(short sIDD) : CPropertyPage(sIDD)
+{
+
+}
+
+void CWizBaseDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CWizBaseDlg)
+ // NOTE: the ClassWizard will add DDX and DDV calls here
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CWizBaseDlg, CPropertyPage)
+ //{{AFX_MSG_MAP(CWizBaseDlg)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CWizBaseDlg message handlers
+void CWizBaseDlg::SetButtonAccess(short sFlags)
+{
+ CPropertySheet* cp = (CPropertySheet*)GetParent();
+ cp->SetWizardButtons(sFlags);
+
+}
+
diff --git a/private/utils/wizards/addusrw/wizbased.h b/private/utils/wizards/addusrw/wizbased.h
new file mode 100644
index 000000000..9178a15fb
--- /dev/null
+++ b/private/utils/wizards/addusrw/wizbased.h
@@ -0,0 +1,57 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ WizBaseD.h : header file
+
+ CPropertyPage support for User mgmt wizard
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CWizBaseDlg dialog
+
+class CWizBaseDlg : public CPropertyPage
+{
+ DECLARE_DYNCREATE(CWizBaseDlg)
+
+// Construction
+public:
+ CWizBaseDlg();
+ CWizBaseDlg(short sIDD);
+ ~CWizBaseDlg();
+
+public:
+// base class paint fn for space on left side of dialog
+ void SetButtonAccess(short sFlags);
+
+// Dialog Data
+ //{{AFX_DATA(CWizBaseDlg)
+ enum { IDD = IDD_BASE_DIALOG };
+ // NOTE - ClassWizard will add data members here.
+ // DO NOT EDIT what you see in these blocks of generated code !
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CWizBaseDlg)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CWizBaseDlg)
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+};
diff --git a/private/utils/wizards/dirs b/private/utils/wizards/dirs
new file mode 100644
index 000000000..a969cc054
--- /dev/null
+++ b/private/utils/wizards/dirs
@@ -0,0 +1,21 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ dirs.
+
+Abstract:
+
+ This file specifies the subdirectories of the current directory that
+ contain component makefiles.
+
+!ENDIF
+
+DIRS= ADDGRPW \
+ ADDUSRW \
+ LICCOMP \
+ SHRPUB \
+ WIZMGR \
+ HOURSCTL
diff --git a/private/utils/wizards/hoursctl/hours.cpp b/private/utils/wizards/hoursctl/hours.cpp
new file mode 100644
index 000000000..36b9afd5f
--- /dev/null
+++ b/private/utils/wizards/hoursctl/hours.cpp
@@ -0,0 +1,90 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Hours.cpp : Defines the class behaviors for the application.
+
+File History:
+
+ JonY May-96 created
+
+--*/
+
+
+
+#include "stdafx.h"
+#include "Hours.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+
+CHoursApp NEAR theApp;
+
+const GUID CDECL BASED_CODE _tlid =
+ { 0xa44ea7aa, 0x9d58, 0x11cf, { 0xa3, 0x5f, 0, 0xaa, 0, 0xb6, 0x74, 0x3b } };
+const WORD _wVerMajor = 1;
+const WORD _wVerMinor = 0;
+
+
+////////////////////////////////////////////////////////////////////////////
+// CHoursApp::InitInstance - DLL initialization
+
+BOOL CHoursApp::InitInstance()
+{
+ BOOL bInit = COleControlModule::InitInstance();
+
+ if (bInit)
+ {
+ }
+
+ return bInit;
+}
+
+
+////////////////////////////////////////////////////////////////////////////
+// CHoursApp::ExitInstance - DLL termination
+
+int CHoursApp::ExitInstance()
+{
+ return COleControlModule::ExitInstance();
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// DllRegisterServer - Adds entries to the system registry
+
+STDAPI DllRegisterServer(void)
+{
+ AFX_MANAGE_STATE(_afxModuleAddrThis);
+
+ if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))
+ return ResultFromScode(SELFREG_E_TYPELIB);
+
+ if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
+ return ResultFromScode(SELFREG_E_CLASS);
+
+ return NOERROR;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// DllUnregisterServer - Removes entries from the system registry
+
+STDAPI DllUnregisterServer(void)
+{
+ AFX_MANAGE_STATE(_afxModuleAddrThis);
+
+ if (!AfxOleUnregisterTypeLib(_tlid))
+ return ResultFromScode(SELFREG_E_TYPELIB);
+
+ if (!COleObjectFactoryEx::UpdateRegistryAll(FALSE))
+ return ResultFromScode(SELFREG_E_CLASS);
+
+ return NOERROR;
+}
diff --git a/private/utils/wizards/hoursctl/hours.def b/private/utils/wizards/hoursctl/hours.def
new file mode 100644
index 000000000..ba00d0270
--- /dev/null
+++ b/private/utils/wizards/hoursctl/hours.def
@@ -0,0 +1,9 @@
+; Hours.def : Declares the module parameters.
+
+LIBRARY "HOURS.OCX"
+
+EXPORTS
+ DllCanUnloadNow @1 PRIVATE
+ DllGetClassObject @2 PRIVATE
+ DllRegisterServer @3 PRIVATE
+ DllUnregisterServer @4 PRIVATE
diff --git a/private/utils/wizards/hoursctl/hours.h b/private/utils/wizards/hoursctl/hours.h
new file mode 100644
index 000000000..c482ef425
--- /dev/null
+++ b/private/utils/wizards/hoursctl/hours.h
@@ -0,0 +1,35 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+// Hours.h : main header file for HOURS.DLL
+
+File History:
+
+ JonY May-96 created
+
+--*/
+
+
+
+#if !defined( __AFXCTL_H__ )
+ #error include 'afxctl.h' before including this file
+#endif
+
+#include "resource.h" // main symbols
+
+/////////////////////////////////////////////////////////////////////////////
+// CHoursApp : See Hours.cpp for implementation.
+
+class CHoursApp : public COleControlModule
+{
+public:
+ BOOL InitInstance();
+ int ExitInstance();
+};
+
+extern const GUID CDECL _tlid;
+extern const WORD _wVerMajor;
+extern const WORD _wVerMinor;
diff --git a/private/utils/wizards/hoursctl/hours.rc b/private/utils/wizards/hoursctl/hours.rc
new file mode 100644
index 000000000..8cbf1268e
--- /dev/null
+++ b/private/utils/wizards/hoursctl/hours.rc
@@ -0,0 +1,138 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "1 TYPELIB ""Hours.tlb""\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_HOURS BITMAP DISCARDABLE "HoursCtl.bmp"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_PROPPAGE_HOURS DIALOG DISCARDABLE 0, 0, 250, 62
+STYLE WS_CHILD
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "TODO: Place controls to manipulate properties of Hours Control on this dialog.",
+ IDC_STATIC,7,25,229,16
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_PROPPAGE_HOURS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 243
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 55
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_HOURS "Hours Control"
+ IDS_HOURS_PPG "Hours Property Page"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_HOURS_PPG_CAPTION "General"
+ IDS_SUNDAY "Sunday"
+ IDS_MONDAY "Monday"
+ IDS_TUESDAY "Tuesday"
+ IDS_WEDNESDAY "Wednesday"
+ IDS_THURSDAY "Thursday"
+ IDS_FRIDAY "Friday"
+ IDS_SATURDAY "Saturday"
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+1 TYPELIB "Hours.tlb"
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
+//
+// Version resources
+//
+#include <winver.h>
+#include <ntverp.h>
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "hours of logon common control"
+#define VER_INTERNALNAME_STR "hours.ocx"
+#define VER_ORIGINALFILENAME_STR "hours.ocx"
+#include <common.ver>
diff --git a/private/utils/wizards/hoursctl/hours.tlb b/private/utils/wizards/hoursctl/hours.tlb
new file mode 100644
index 000000000..e13b9dfc5
--- /dev/null
+++ b/private/utils/wizards/hoursctl/hours.tlb
Binary files differ
diff --git a/private/utils/wizards/hoursctl/hoursctl.bmp b/private/utils/wizards/hoursctl/hoursctl.bmp
new file mode 100644
index 000000000..3ffeb056f
--- /dev/null
+++ b/private/utils/wizards/hoursctl/hoursctl.bmp
Binary files differ
diff --git a/private/utils/wizards/hoursctl/hoursctl.cpp b/private/utils/wizards/hoursctl/hoursctl.cpp
new file mode 100644
index 000000000..17eabfe5a
--- /dev/null
+++ b/private/utils/wizards/hoursctl/hoursctl.cpp
@@ -0,0 +1,1047 @@
+// HoursCtl.cpp : Implementation of the CHoursCtrl OLE control class.
+
+#include "stdafx.h"
+#include "Hours.h"
+#include "HoursCtl.h"
+#include "HoursPpg.h"
+
+#include <time.h>
+#include <sys\timeb.h>
+
+#ifdef _DEBUG
+//#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+
+IMPLEMENT_DYNCREATE(CHoursCtrl, COleControl)
+
+const USHORT CONTROL_WIDTH = 375;
+const USHORT CONTROL_HEIGHT = 163;
+const USHORT DAY_BUTTON_WIDTH = 83;
+const USHORT HOUR_BUTTON_HEIGHT = 20;
+
+const USHORT CELL_WIDTH = ((CONTROL_WIDTH - DAY_BUTTON_WIDTH) / 24);
+const USHORT CELL_HEIGHT = ((CONTROL_HEIGHT - HOUR_BUTTON_HEIGHT) / 7);
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Message map
+
+BEGIN_MESSAGE_MAP(CHoursCtrl, COleControl)
+ //{{AFX_MSG_MAP(CHoursCtrl)
+ ON_WM_CREATE()
+ ON_WM_SETCURSOR()
+ ON_WM_LBUTTONDOWN()
+ ON_WM_LBUTTONUP()
+ ON_WM_MOUSEMOVE()
+ //}}AFX_MSG_MAP
+ ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
+END_MESSAGE_MAP()
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Dispatch map VT_ARRAY
+
+BEGIN_DISPATCH_MAP(CHoursCtrl, COleControl)
+ //{{AFX_DISPATCH_MAP(CHoursCtrl)
+ DISP_PROPERTY_NOTIFY(CHoursCtrl, "crPermitColor", m_crPermitColor, OnCrPermitColorChanged, VT_COLOR)
+ DISP_PROPERTY_NOTIFY(CHoursCtrl, "crDenyColor", m_crDenyColor, OnCrDenyColorChanged, VT_COLOR)
+ DISP_PROPERTY_EX(CHoursCtrl, "DateData", GetDateData, SetDateData, VT_VARIANT)
+ //}}AFX_DISPATCH_MAP
+END_DISPATCH_MAP()
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Event map
+
+BEGIN_EVENT_MAP(CHoursCtrl, COleControl)
+ //{{AFX_EVENT_MAP(CHoursCtrl)
+ //}}AFX_EVENT_MAP
+END_EVENT_MAP()
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Property pages
+
+BEGIN_PROPPAGEIDS(CHoursCtrl, 1)
+ PROPPAGEID(CHoursPropPage::guid)
+END_PROPPAGEIDS(CHoursCtrl)
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Initialize class factory and guid
+
+IMPLEMENT_OLECREATE_EX(CHoursCtrl, "HOURS.HoursCtrl.1",
+ 0xa44ea7ad, 0x9d58, 0x11cf, 0xa3, 0x5f, 0, 0xaa, 0, 0xb6, 0x74, 0x3b)
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Type library ID and version
+
+IMPLEMENT_OLETYPELIB(CHoursCtrl, _tlid, _wVerMajor, _wVerMinor)
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Interface IDs
+
+const IID BASED_CODE IID_DHours =
+ { 0xa44ea7ab, 0x9d58, 0x11cf, { 0xa3, 0x5f, 0, 0xaa, 0, 0xb6, 0x74, 0x3b } };
+const IID BASED_CODE IID_DHoursEvents =
+ { 0xa44ea7ac, 0x9d58, 0x11cf, { 0xa3, 0x5f, 0, 0xaa, 0, 0xb6, 0x74, 0x3b } };
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Control type information
+
+static const DWORD BASED_CODE _dwHoursOleMisc =
+ OLEMISC_ACTIVATEWHENVISIBLE |
+ OLEMISC_SETCLIENTSITEFIRST |
+ OLEMISC_INSIDEOUT |
+ OLEMISC_CANTLINKINSIDE |
+ OLEMISC_RECOMPOSEONRESIZE;
+
+IMPLEMENT_OLECTLTYPE(CHoursCtrl, IDS_HOURS, _dwHoursOleMisc)
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CHoursCtrl::CHoursCtrlFactory::UpdateRegistry -
+// Adds or removes system registry entries for CHoursCtrl
+
+BOOL CHoursCtrl::CHoursCtrlFactory::UpdateRegistry(BOOL bRegister)
+{
+ // TODO: Verify that your control follows apartment-model threading rules.
+ // Refer to MFC TechNote 64 for more information.
+ // If your control does not conform to the apartment-model rules, then
+ // you must modify the code below, changing the 6th parameter from
+ // afxRegApartmentThreading to 0.
+
+ if (bRegister)
+ return AfxOleRegisterControlClass(
+ AfxGetInstanceHandle(),
+ m_clsid,
+ m_lpszProgID,
+ IDS_HOURS,
+ IDB_HOURS,
+ /* afxRegApartmentThreading, */0,
+ _dwHoursOleMisc,
+ _tlid,
+ _wVerMajor,
+ _wVerMinor);
+ else
+ return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CHoursCtrl::CHoursCtrl - Constructor
+
+CHoursCtrl::CHoursCtrl()
+{
+ InitializeIIDs(&IID_DHours, &IID_DHoursEvents);
+
+// regular font
+ m_pFont = new CFont;
+ LOGFONT lf;
+
+ memset(&lf, 0, sizeof(LOGFONT)); // Clear out structure.
+ lf.lfHeight = 15;
+ _tcscpy(lf.lfFaceName, TEXT("Arial"));
+ lf.lfWeight = 100;
+ m_pFont->CreateFontIndirect(&lf); // Create the font.
+
+// create the individual 'cells' (m_sCells)
+ USHORT x, y;
+ x = HOUR_BUTTON_HEIGHT;
+ y = DAY_BUTTON_WIDTH;
+
+ CRect crOuter;
+ USHORT sCount = 1;
+ USHORT sRow = 1;
+ USHORT sCol = 1;
+
+ for (x = DAY_BUTTON_WIDTH; (x + CELL_WIDTH) < CONTROL_WIDTH; x += CELL_WIDTH)
+ {
+ for (y = HOUR_BUTTON_HEIGHT; (y + CELL_HEIGHT) < CONTROL_HEIGHT; y += CELL_HEIGHT)
+ {
+ m_sCell[sCount].x = x;
+ m_sCell[sCount].y = y;
+ m_sCell[sCount].cx = x + CELL_WIDTH + 1;
+ m_sCell[sCount].cy = y + CELL_HEIGHT + 1;
+ m_sCell[sCount].bVal = TRUE;
+ m_sCell[sCount].row = sRow;
+ m_sCell[sCount].col = sCol;
+ m_sCell[sCount].bSelected = FALSE;
+ sCount++;
+ sRow++;
+ }
+ sRow = 1;
+ sCol++;
+ }
+
+// create the buttons
+ // start with the days
+ y = HOUR_BUTTON_HEIGHT;
+ sRow = 0;
+
+ while (sCount < 176)
+ {
+ m_sCell[sCount].x = 2;
+ m_sCell[sCount].y = y;
+ m_sCell[sCount].cx = m_sCell[sCount].x + DAY_BUTTON_WIDTH;
+ m_sCell[sCount].cy = y + CELL_HEIGHT;
+ m_sCell[sCount].bVal = TRUE;
+ m_sCell[sCount].row = sRow;
+ m_sCell[sCount].col = 0;
+ m_sCell[sCount].bSelected = FALSE;
+
+ sCount++;
+ sRow++;
+ y += HOUR_BUTTON_HEIGHT;
+ }
+
+// 'select all' button
+ m_sCell[sCount].x = 2;
+ m_sCell[sCount].y = 2;
+ m_sCell[sCount].cx = m_sCell[sCount].x + DAY_BUTTON_WIDTH;
+ m_sCell[sCount].cy = m_sCell[sCount].y + CELL_HEIGHT;
+
+ m_sCell[sCount].bVal = TRUE;
+ m_sCell[sCount].row = 0;
+ m_sCell[sCount].col = 0;
+ m_sCell[sCount].bSelected = FALSE;
+
+ x = 83;
+ sCount++;
+ while (sCount < 201)
+ {
+ m_sCell[sCount].x = x;
+ m_sCell[sCount].y = 2;
+ m_sCell[sCount].cx = x + CELL_WIDTH;
+ m_sCell[sCount].cy = m_sCell[sCount].y + CELL_HEIGHT;
+
+ m_sCell[sCount].bVal = TRUE;
+ m_sCell[sCount].row = sRow;
+ m_sCell[sCount].col = 0;
+ m_sCell[sCount].bSelected = FALSE;
+
+ sCount++;
+ sRow++;
+ x += CELL_WIDTH;
+ }
+
+ m_sCurrentRow = 1;
+ m_sCurrentCol = 1;
+
+ bToggle = TRUE;
+
+// set default color values
+ m_crPermitColor = GetSysColor(COLOR_ACTIVECAPTION);
+ m_crDenyColor = GetSysColor(COLOR_CAPTIONTEXT);
+
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CHoursCtrl::~CHoursCtrl - Destructor
+
+CHoursCtrl::~CHoursCtrl()
+{
+// remove button CFont*
+ if (m_pFont != NULL) delete m_pFont;
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CHoursCtrl::OnDraw - Drawing function
+
+void CHoursCtrl::OnDraw(
+ CDC* pDC, const CRect& rcBounds, const CRect& rcInvalid)
+{
+// create pen for the grid lines
+ CPen pBlackPen(PS_SOLID, 1, RGB(0,0,0));
+ CPen* pOriginalPen = (CPen*)pDC->SelectObject(pBlackPen);
+
+// create the two brushes for allowed color and denied color
+ CBrush* pAllowedBrush = new CBrush;
+ pAllowedBrush->CreateSolidBrush(m_crPermitColor);
+
+ CBrush* pDeniedBrush = new CBrush;
+ pDeniedBrush->CreateSolidBrush(m_crDenyColor);
+
+ CBrush* pDragBrush = new CBrush;
+ pDragBrush->CreateHatchBrush(HS_BDIAGONAL, GetSysColor(COLOR_ACTIVECAPTION));
+
+ USHORT sCount = 1;
+ CRect crOuter;
+
+ pDC->SetBkColor(GetSysColor(COLOR_BTNFACE));
+
+// draw the grid
+ while (sCount < 169)
+ {
+ crOuter = CRect(m_sCell[sCount].x,
+ m_sCell[sCount].y,
+ m_sCell[sCount].cx,
+ m_sCell[sCount].cy);
+
+ CRect crInterSect = (rcInvalid & crOuter);
+ if (!crInterSect.IsRectNull())
+ {
+ pDC->Rectangle(&crOuter);
+ crOuter.DeflateRect(1, 1);
+
+ if (m_sCell[sCount].bSelected) pDC->FillRect(&crOuter, pDragBrush);
+ else pDC->FillRect(&crOuter, (m_sCell[sCount].bVal ? pAllowedBrush : pDeniedBrush));
+
+ if ((m_sCurrentRow && m_sCurrentCol) && (sCount == m_sCurrentLoc())) // is this the 'selected' cell?
+ {
+ crOuter.DeflateRect(2, 4);
+ pDC->DrawFocusRect(&crOuter);
+ }
+ }
+
+ sCount++;
+ }
+
+ delete pAllowedBrush;
+ delete pDeniedBrush;
+ delete pDragBrush;
+
+
+// draw the surrounding buttons
+ CBrush* pButtonBrush = new CBrush;
+ pButtonBrush->CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
+
+ CPen pWhitePen(PS_SOLID, 1, RGB(255, 255, 255));
+ pOriginalPen = (CPen*)pDC->SelectObject(pWhitePen);
+
+ CPen pDkGreyPen(PS_SOLID, 1, RGB(128, 128, 128));
+ CPen pLtGreyPen(PS_SOLID, 1, RGB(196, 196, 196));
+
+ CFont* pOldFont = pDC->SelectObject(m_pFont);
+
+ while (sCount < 176) // start with the days of the week
+ {
+ crOuter = CRect(m_sCell[sCount].x,
+ m_sCell[sCount].y,
+ m_sCell[sCount].cx,
+ m_sCell[sCount].cy);
+
+ CRect crInterSect = (rcInvalid & crOuter);
+ if (!crInterSect.IsRectNull())
+ {
+ crOuter.DeflateRect(1, 1);
+ pDC->FillRect(&crOuter, pButtonBrush);
+ if (m_sCell[sCount].bVal)
+ {
+ pDC->SelectObject(pWhitePen);
+ pDC->MoveTo(m_sCell[sCount].x, m_sCell[sCount].cy - 1);
+ pDC->LineTo(m_sCell[sCount].x, m_sCell[sCount].y + 1);
+ pDC->LineTo(m_sCell[sCount].cx - 2, m_sCell[sCount].y + 1);
+
+ pDC->SelectObject(pBlackPen);
+ pDC->LineTo(m_sCell[sCount].cx - 2, m_sCell[sCount].cy);
+ pDC->LineTo(m_sCell[sCount].x - 1, m_sCell[sCount].cy);
+
+ pDC->SelectObject(pDkGreyPen);
+ pDC->MoveTo(m_sCell[sCount].cx - 3, m_sCell[sCount].y + 2);
+ pDC->LineTo(m_sCell[sCount].cx - 3, m_sCell[sCount].cy - 1);
+ pDC->LineTo(m_sCell[sCount].x, m_sCell[sCount].cy - 1);
+ }
+ else
+ {
+ pDC->SelectObject(pBlackPen);
+ pDC->MoveTo(m_sCell[sCount].x, m_sCell[sCount].cy - 1);
+ pDC->LineTo(m_sCell[sCount].x, m_sCell[sCount].y + 1);
+ pDC->LineTo(m_sCell[sCount].cx - 2, m_sCell[sCount].y + 1);
+
+ pDC->SelectObject(pWhitePen);
+ pDC->MoveTo(m_sCell[sCount].cx - 2, m_sCell[sCount].cy);
+ pDC->LineTo(m_sCell[sCount].x - 1, m_sCell[sCount].cy);
+
+ pDC->SelectObject(pLtGreyPen);
+ pDC->MoveTo(m_sCell[sCount].cx - 3, m_sCell[sCount].y + 2);
+ pDC->LineTo(m_sCell[sCount].cx - 3, m_sCell[sCount].cy - 1);
+ pDC->LineTo(m_sCell[sCount].x, m_sCell[sCount].cy - 1);
+ }
+
+ pDC->SetBkMode(TRANSPARENT);
+ crOuter.DeflateRect(3, 2);
+ if (m_sCell[sCount].bVal)
+ pDC->DrawText(csDay[sCount - 169],
+ &crOuter,
+ DT_CENTER);
+ else
+ {
+ crOuter.OffsetRect(1, 1);
+ pDC->DrawText(csDay[sCount - 169],
+ &crOuter,
+ DT_CENTER);
+ }
+ // current selection?
+ if ((m_sCurrentCol == 0) && (m_sCurrentRow == sCount - 168))
+ {
+ CRect crSelection = CRect(m_sCell[sCount].x,
+ m_sCell[sCount].y,
+ m_sCell[sCount].cx,
+ m_sCell[sCount].cy);
+
+ crSelection.DeflateRect(5, 5);
+ pDC->DrawFocusRect(&crSelection);
+ }
+ }
+ sCount++;
+ }
+
+// 'select all' button
+ crOuter = CRect(m_sCell[sCount].x,
+ m_sCell[sCount].y,
+ m_sCell[sCount].cx + 1,
+ m_sCell[sCount].cy + 1);
+
+ CRect crInterSect = (rcInvalid & crOuter);
+ if (!crInterSect.IsRectNull())
+ {
+ crOuter.DeflateRect(1, 1);
+
+ pDC->FillRect(&crOuter, pButtonBrush);
+
+ if (m_sCell[sCount].bVal)
+ {
+ pDC->SelectObject(pWhitePen);
+ pDC->MoveTo(m_sCell[sCount].x, m_sCell[sCount].cy - 1);
+ pDC->LineTo(m_sCell[sCount].x, m_sCell[sCount].y);
+ pDC->LineTo(m_sCell[sCount].cx - 2, m_sCell[sCount].y);
+
+ pDC->SelectObject(pBlackPen);
+ pDC->LineTo(m_sCell[sCount].cx - 2, m_sCell[sCount].cy - 2);
+ pDC->LineTo(m_sCell[sCount].x - 1, m_sCell[sCount].cy - 2);
+
+ pDC->SelectObject(pDkGreyPen);
+ pDC->MoveTo(m_sCell[sCount].cx - 3, m_sCell[sCount].y + 1);
+ pDC->LineTo(m_sCell[sCount].cx - 3, m_sCell[sCount].cy - 3);
+ pDC->LineTo(m_sCell[sCount].x, m_sCell[sCount].cy - 3);
+ }
+ else
+ {
+ pDC->SelectObject(pBlackPen);
+ pDC->MoveTo(m_sCell[sCount].x, m_sCell[sCount].cy - 1);
+ pDC->LineTo(m_sCell[sCount].x, m_sCell[sCount].y);
+ pDC->LineTo(m_sCell[sCount].cx - 2, m_sCell[sCount].y);
+
+ pDC->SelectObject(pWhitePen);
+ pDC->LineTo(m_sCell[sCount].cx - 2, m_sCell[sCount].cy - 2);
+ pDC->LineTo(m_sCell[sCount].x - 1, m_sCell[sCount].cy - 2);
+
+ pDC->SelectObject(pLtGreyPen);
+ pDC->MoveTo(m_sCell[sCount].cx - 3, m_sCell[sCount].y + 1);
+ pDC->LineTo(m_sCell[sCount].cx - 3, m_sCell[sCount].cy - 3);
+ pDC->LineTo(m_sCell[sCount].x, m_sCell[sCount].cy - 3);
+ }
+
+ // current selection?
+ if ((m_sCurrentCol == 0) && (m_sCurrentRow == 0))
+ {
+ CRect crSelection = CRect(m_sCell[sCount].x,
+ m_sCell[sCount].y,
+ m_sCell[sCount].cx,
+ m_sCell[sCount].cy);
+
+ crSelection.DeflateRect(5, 5);
+ pDC->DrawFocusRect(&crSelection);
+ }
+
+ }
+
+ sCount++;
+// finish with col headers
+ while (sCount < 201)
+ {
+ crOuter = CRect(m_sCell[sCount].x,
+ m_sCell[sCount].y,
+ m_sCell[sCount].cx,
+ m_sCell[sCount].cy);
+
+ CRect crInterSect = (rcInvalid & crOuter);
+ if (!crInterSect.IsRectNull())
+ {
+ crOuter.DeflateRect(1, 1);
+
+ pDC->FillRect(&crOuter, pButtonBrush);
+
+ if (m_sCell[sCount].bVal)
+ {
+ pDC->SelectObject(pWhitePen);
+ pDC->MoveTo(m_sCell[sCount].x + 1, m_sCell[sCount].cy - 2);
+ pDC->LineTo(m_sCell[sCount].x + 1, m_sCell[sCount].y);
+ pDC->LineTo(m_sCell[sCount].cx, m_sCell[sCount].y);
+
+ pDC->SelectObject(pBlackPen);
+ pDC->LineTo(m_sCell[sCount].cx, m_sCell[sCount].cy - 2);
+ pDC->LineTo(m_sCell[sCount].x - 1, m_sCell[sCount].cy - 2);
+
+ pDC->SelectObject(pDkGreyPen);
+ pDC->MoveTo(m_sCell[sCount].cx - 1, m_sCell[sCount].y + 1);
+ pDC->LineTo(m_sCell[sCount].cx - 1, m_sCell[sCount].cy - 3);
+ pDC->LineTo(m_sCell[sCount].x, m_sCell[sCount].cy - 3);
+ }
+ else
+ {
+ pDC->SelectObject(pBlackPen);
+ pDC->MoveTo(m_sCell[sCount].x + 1, m_sCell[sCount].cy - 2);
+ pDC->LineTo(m_sCell[sCount].x + 1, m_sCell[sCount].y);
+ pDC->LineTo(m_sCell[sCount].cx, m_sCell[sCount].y);
+
+ pDC->SelectObject(pWhitePen);
+ pDC->LineTo(m_sCell[sCount].cx, m_sCell[sCount].cy - 2);
+ pDC->LineTo(m_sCell[sCount].x - 1, m_sCell[sCount].cy - 2);
+
+ pDC->SelectObject(pLtGreyPen);
+ pDC->MoveTo(m_sCell[sCount].cx - 1, m_sCell[sCount].y + 1);
+ pDC->LineTo(m_sCell[sCount].cx - 1, m_sCell[sCount].cy - 3);
+ pDC->LineTo(m_sCell[sCount].x, m_sCell[sCount].cy - 3);
+ }
+
+ // current selection?
+ if ((m_sCurrentCol == sCount - 176) && (m_sCurrentRow == 0))
+ {
+ CRect crSelection = CRect(m_sCell[sCount].x,
+ m_sCell[sCount].y,
+ m_sCell[sCount].cx,
+ m_sCell[sCount].cy);
+
+ crSelection.DeflateRect(3, 3);
+ pDC->DrawFocusRect(&crSelection);
+ }
+
+ }
+ sCount++;
+ }
+
+ delete pButtonBrush;
+ pDC->SelectObject(pOldFont);
+
+// draw the border
+ pDC->SelectObject(pBlackPen);
+ pDC->MoveTo(1, rcBounds.BottomRight().y - 1);
+ pDC->LineTo(rcBounds.TopLeft().x + 1, rcBounds.TopLeft().y + 1);
+ pDC->LineTo(rcBounds.BottomRight().x + 1, 1);
+
+ pDC->SelectObject(pDkGreyPen);
+ pDC->MoveTo(0, rcBounds.BottomRight().y);
+ pDC->LineTo(rcBounds.TopLeft().x, rcBounds.TopLeft().y);
+ pDC->LineTo(rcBounds.BottomRight().x, 0);
+
+ pDC->SelectObject(pWhitePen);
+ pDC->MoveTo(1, rcBounds.BottomRight().y - 1);
+ pDC->LineTo(rcBounds.BottomRight().x - 1, rcBounds.BottomRight().y - 1);
+ pDC->LineTo(rcBounds.BottomRight().x - 1, 0);
+
+ pDC->SelectObject(pLtGreyPen);
+ pDC->MoveTo(2, rcBounds.BottomRight().y - 2);
+ pDC->LineTo(rcBounds.BottomRight().x - 2, rcBounds.BottomRight().y - 2);
+ pDC->LineTo(rcBounds.BottomRight().x - 2, 2);
+
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CHoursCtrl::DoPropExchange - Persistence support
+
+void CHoursCtrl::DoPropExchange(CPropExchange* pPX)
+{
+ ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
+ COleControl::DoPropExchange(pPX);
+
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CHoursCtrl::OnResetState - Reset control to default state
+
+void CHoursCtrl::OnResetState()
+{
+ COleControl::OnResetState(); // Resets defaults found in DoPropExchange
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CHoursCtrl message handlers
+
+int CHoursCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
+{
+ if (COleControl::OnCreate(lpCreateStruct) == -1)
+ return -1;
+
+// load the text for the day buttons
+ csDay[0].LoadString(IDS_SUNDAY);
+ csDay[1].LoadString(IDS_MONDAY);
+ csDay[2].LoadString(IDS_TUESDAY);
+ csDay[3].LoadString(IDS_WEDNESDAY);
+ csDay[4].LoadString(IDS_THURSDAY);
+ csDay[5].LoadString(IDS_FRIDAY);
+ csDay[6].LoadString(IDS_SATURDAY);
+
+ return 0;
+}
+
+// make the cursor over the control into the '+' sign
+BOOL CHoursCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
+{
+ ::SetCursor(::LoadCursor(NULL, IDC_CROSS));
+ return TRUE;
+}
+
+// trap lButton clicks to toggle single cells
+void CHoursCtrl::OnLButtonDown(UINT nFlags, CPoint point)
+{
+// invalidate the previous selection
+ InvalidateCell(m_sCurrentLoc());
+
+ Click(point);
+ pointDrag = point;
+
+ USHORT sCount = 1;
+// clear out the old drag selection(s)
+ while (sCount < 168)
+ {
+ if (m_sCell[sCount].bSelected)
+ {
+ m_sCell[sCount].bSelected = FALSE;
+
+ InvalidateCell(sCount);
+ }
+
+ sCount++;
+ }
+
+// COleControl::OnLButtonDown(nFlags, point);
+}
+
+
+void CHoursCtrl::InvalidateCell(USHORT sCellID)
+{
+ CRect crCell = CRect(m_sCell[sCellID].x,
+ m_sCell[sCellID].y,
+ m_sCell[sCellID].cx,
+ m_sCell[sCellID].cy);
+ InvalidateRect(crCell);
+}
+
+void CHoursCtrl::OnMouseMove(UINT nFlags, CPoint point)
+{
+ if (nFlags == MK_LBUTTON)
+ {
+ USHORT sEndCell = GetCellID(point);
+ USHORT sStartCell = GetCellID(pointDrag);
+ if (sStartCell == sEndCell) return;
+
+ CRect crSelected = CRect(min(m_sCell[sStartCell].x, m_sCell[sEndCell].x),
+ min(m_sCell[sStartCell].y, m_sCell[sEndCell].y),
+ max(m_sCell[sStartCell].x, m_sCell[sEndCell].x) + CELL_WIDTH,
+ max(m_sCell[sStartCell].y, m_sCell[sEndCell].y) + CELL_HEIGHT);
+
+ USHORT sCount = 0;
+// clear out the old selection
+ while (sCount < 169)
+ {
+ if (!crSelected.PtInRect(CPoint(m_sCell[sCount].x + 1, m_sCell[sCount].y + 1)))
+ {
+ if (m_sCell[sCount].bSelected)
+ {
+ m_sCell[sCount].bSelected = FALSE;
+
+ InvalidateCell(sCount);
+ }
+ }
+ else
+ {
+ if (!m_sCell[sCount].bSelected)
+ {
+ m_sCell[sCount].bSelected = TRUE;
+ InvalidateCell(sCount);
+ }
+ }
+
+ sCount++;
+ }
+ }
+
+ COleControl::OnMouseMove(nFlags, point);
+}
+
+void CHoursCtrl::OnLButtonUp(UINT nFlags, CPoint point)
+{
+ USHORT sEndCell = GetCellID(point);
+ USHORT sStartCell = GetCellID(pointDrag);
+ if (sStartCell == sEndCell) return;
+
+ CRect crSelected = CRect(min(m_sCell[sStartCell].x, m_sCell[sEndCell].x),
+ min(m_sCell[sStartCell].y, m_sCell[sEndCell].y),
+ max(m_sCell[sStartCell].x, m_sCell[sEndCell].x) + CELL_WIDTH,
+ max(m_sCell[sStartCell].y, m_sCell[sEndCell].y) + CELL_HEIGHT);
+
+// first get the avg
+ short sTmp = 0;
+ USHORT sCount = 0;
+ while (sCount < 169)
+ {
+ if (crSelected.PtInRect(CPoint(m_sCell[sCount].x + 1, m_sCell[sCount].y + 1)))
+ {
+ if (m_sCell[sCount].bVal) sTmp++;
+ else sTmp--;
+ }
+
+ sCount++;
+ }
+
+ BOOL bNewVal;
+ if (sTmp >= 0) bNewVal = FALSE;
+ else bNewVal = TRUE;
+ sCount = 0;
+// now change them all to be !the average
+// first get the avg
+ while (sCount < 169)
+ {
+ if (crSelected.PtInRect(CPoint(m_sCell[sCount].x + 1, m_sCell[sCount].y + 1)))
+ {
+ m_sCell[sCount].bVal = bNewVal;
+ m_sCell[sCount].bSelected = FALSE;
+ InvalidateCell(sCount);
+ }
+
+ sCount++;
+ }
+
+ COleControl::OnLButtonUp(nFlags, point);
+}
+
+USHORT CHoursCtrl::GetCellID(CPoint point)
+{
+ USHORT sCount = 1;
+
+// big grid?
+ CRect crOuter;
+ while (sCount < 169)
+ {
+ crOuter = CRect(m_sCell[sCount].x,
+ m_sCell[sCount].y,
+ m_sCell[sCount].x + CELL_WIDTH + 1,
+ m_sCell[sCount].y + CELL_HEIGHT + 1);
+ if (crOuter.PtInRect(point)) return sCount;
+
+ sCount++;
+ }
+
+// day button?
+ while (sCount < 176)
+ {
+ crOuter = CRect(m_sCell[sCount].x,
+ m_sCell[sCount].y,
+ m_sCell[sCount].x + DAY_BUTTON_WIDTH + 1,
+ m_sCell[sCount].y + CELL_HEIGHT + 1);
+ if (crOuter.PtInRect(point)) return sCount;
+
+ sCount++;
+ }
+
+// big button?
+ crOuter = CRect(m_sCell[sCount].x,
+ m_sCell[sCount].y,
+ m_sCell[sCount].x + DAY_BUTTON_WIDTH + 1,
+ m_sCell[sCount].y + CELL_HEIGHT + 1);
+ if (crOuter.PtInRect(point)) return sCount;
+
+// column button?
+ while (sCount < 201)
+ {
+ crOuter = CRect(m_sCell[sCount].x,
+ m_sCell[sCount].y,
+ m_sCell[sCount].x + CELL_WIDTH + 1,
+ m_sCell[sCount].y + CELL_HEIGHT + 1);
+ if (crOuter.PtInRect(point)) return sCount;
+
+ sCount++;
+ }
+
+ return 0;
+}
+
+void CHoursCtrl::Click(CPoint point)
+{
+ USHORT sCount = 0;
+ CRect crOuter;
+
+ USHORT sCell = GetCellID(point);
+
+ m_sCurrentRow = m_sCell[sCell].row;
+ m_sCurrentCol = m_sCell[sCell].col;
+
+ if (sCell < 168) m_sCell[sCell].bVal = !m_sCell[sCell].bVal;
+
+ InvalidateCell(sCell);
+
+// if we clicked on a button toggle its value and redraw
+ if (sCell > 168)
+ {
+ if ((sCell > 168) && (sCell < 176)) // day button
+ ToggleDay(sCell - 168);
+
+ else if (sCell == 176) // toggle all
+ OnBigButton();
+
+ else // column header
+ ToggleCol(sCell - 177);
+ }
+
+}
+
+// toggle the values of a row (by day)
+void CHoursCtrl::ToggleDay(UINT nID)
+{
+ USHORT sCount;
+ CRect crOuter;
+
+ for (sCount = nID; sCount < 169; sCount += 7)
+ {
+ m_sCell[sCount].bVal = !m_sCell[nID + 168].bVal;
+ InvalidateCell(sCount);
+ }
+ m_sCell[nID + 168].bVal = !m_sCell[nID + 168].bVal;
+ m_sCurrentRow = nID;
+ m_sCurrentCol = 0;
+
+}
+
+// toggle the values of a column
+void CHoursCtrl::ToggleCol(UINT nID)
+{
+ USHORT sCount;
+ CRect crOuter;
+
+ m_sCurrentRow = 0;
+ m_sCurrentCol = nID + 1;
+
+ USHORT sVal = nID + 177;
+ nID *= 7;
+
+ for (sCount = 1; sCount < 8; sCount += 1)
+ {
+ m_sCell[sCount + nID].bVal = !m_sCell[sVal].bVal;
+ InvalidateCell(sCount + nID);
+ }
+ m_sCell[sVal].bVal = !m_sCell[sVal].bVal;
+
+}
+
+// toggle the whole page
+void CHoursCtrl::OnBigButton()
+{
+ USHORT sCount;
+ CRect crOuter;
+
+ m_sCurrentRow = 0;
+ m_sCurrentCol = 0;
+
+ for (sCount = 1; sCount < 169; sCount ++)
+ {
+ m_sCell[sCount].bVal = !m_sCell[176].bVal;
+ InvalidateCell(sCount);
+ }
+
+ m_sCell[176].bVal = !m_sCell[176].bVal;
+
+}
+
+BOOL CHoursCtrl::PreTranslateMessage(LPMSG lpmsg)
+{
+ BOOL bHandleNow = FALSE;
+ CRect crOld, crNew;
+
+ switch (lpmsg->message)
+ {
+ case WM_KEYDOWN:
+ switch (lpmsg->wParam)
+ {
+ case VK_SPACE: // toggle the cell under the dot
+ {
+ short sOldCell = m_sCurrentLoc();
+ Click(CPoint(m_sCell[sOldCell].x + 1, m_sCell[sOldCell].y + 1));
+ bHandleNow = TRUE;
+ break;
+ }
+
+ case VK_UP:
+ {
+ // first store the old cell pos so we can erase it
+ short sOldCell = m_sCurrentLoc();
+
+ // move the carat to the new cell
+ m_sCurrentRow--;
+ if (m_sCurrentRow < 0) m_sCurrentRow = 7;
+
+ // now draw the new cell
+ short sNewCell = m_sCurrentLoc();
+ InvalidateCell(sOldCell);
+ InvalidateCell(sNewCell);
+ bHandleNow = TRUE;
+ break;
+ }
+
+ case VK_DOWN:
+ {
+ short sOldCell = m_sCurrentLoc();
+
+ m_sCurrentRow++;
+ if (m_sCurrentRow > 7) m_sCurrentRow = 0;
+
+ short sNewCell = m_sCurrentLoc();
+ InvalidateCell(sOldCell);
+ InvalidateCell(sNewCell);
+ bHandleNow = TRUE;
+ break;
+ }
+
+ case VK_LEFT:
+ {
+ short sOldCell = m_sCurrentLoc();
+ m_sCurrentCol--;
+ if (m_sCurrentCol < 0) m_sCurrentCol = 24;
+
+ short sNewCell = m_sCurrentLoc();
+ InvalidateCell(sOldCell);
+ InvalidateCell(sNewCell);
+ bHandleNow = TRUE;
+ break;
+ }
+
+ case VK_RIGHT:
+ {
+ short sOldCell = m_sCurrentLoc();
+ m_sCurrentCol++;
+ if (m_sCurrentCol > 24) m_sCurrentCol = 0;
+
+ short sNewCell = m_sCurrentLoc();
+ InvalidateCell(sOldCell);
+ InvalidateCell(sNewCell);
+ bHandleNow = TRUE;
+ break;
+ }
+ }
+ }
+
+ return bHandleNow;
+}
+
+
+short CHoursCtrl::m_sCurrentLoc()
+{
+ if (!m_sCurrentCol && !m_sCurrentRow) // select all button
+ return 176;
+
+ else if (!m_sCurrentCol)
+ return m_sCurrentRow + 168;
+
+ else if (!m_sCurrentRow)
+ return m_sCurrentCol + 176;
+
+ return ((max(m_sCurrentCol - 1, 0) * 7) + m_sCurrentRow);
+}
+
+// these are triggered when the client app changes one of the exported properties
+void CHoursCtrl::OnCrPermitColorChanged()
+{
+ Invalidate();
+
+ SetModifiedFlag();
+}
+
+void CHoursCtrl::OnCrDenyColorChanged()
+{
+ Invalidate();
+
+ SetModifiedFlag();
+}
+
+VARIANT CHoursCtrl::GetDateData()
+{
+ VARIANT vaResult;
+ VariantInit(&vaResult);
+
+ vaResult.vt = VT_ARRAY | VT_UI1;
+
+ SAFEARRAYBOUND sab[1];
+ sab[0].cElements = 21;
+ sab[0].lLbound = 0;
+
+ vaResult.parray = SafeArrayCreate(VT_UI1, 1, sab);
+
+ // load constant offsets into an array
+ DWORD dwOffset[8];
+ USHORT sCount;
+ short sVal = 1;
+ for (sCount = 0; sCount < 8; sCount++)
+ {
+ dwOffset[sCount] = sVal;
+ sVal = sVal << 1;
+ }
+
+// find the diff between current time and GMT (UTC)
+ struct _timeb tstruct;
+ _tzset();
+ _ftime( &tstruct );
+
+// time difference in "seconds moving westward" - this is the amount of hours to add to the
+// listbox values to get GMT
+ short sHourDiff = tstruct.timezone / 60;
+
+ sCount = 0;
+ short sOffset = 0;
+
+// adjust for GMT
+ if (sHourDiff != 0)
+ {
+ sOffset += (sHourDiff % 8);
+ sCount = (int)(sHourDiff / 8);
+ }
+
+ USHORT sCount2 = 1; // address 0 is used elsewhere
+ USHORT sBase;
+ BYTE bRet[21];
+ ZeroMemory(bRet, 21);
+
+ for (sBase = 1; sBase < 8; sBase++)
+ {
+ sCount2 = sBase;
+ while (sCount2 < 169)
+ {
+ if (m_sCell[sCount2].bVal) // 1 = marked
+ bRet[sCount] |= dwOffset[sOffset];
+
+ sOffset++;
+ if (sOffset > 7)
+ {
+ sOffset = 0;
+ sCount++;
+ if (sCount > 20) sCount = 0;
+ }
+ sCount2+=7;
+ }
+ }
+
+
+ long index[1];
+ for (index[0] = 0; index[0] < 21; index[0]++)
+ SafeArrayPutElement(vaResult.parray, &index[0], &bRet[index[0]]);
+
+ return vaResult;
+}
+
+void CHoursCtrl::SetDateData(const VARIANT FAR& newValue)
+{
+ // TODO: Add your property handler here
+
+ SetModifiedFlag();
+}
diff --git a/private/utils/wizards/hoursctl/hoursctl.h b/private/utils/wizards/hoursctl/hoursctl.h
new file mode 100644
index 000000000..0b9504c74
--- /dev/null
+++ b/private/utils/wizards/hoursctl/hoursctl.h
@@ -0,0 +1,118 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+// HoursCtl.h : Declaration of the CHoursCtrl OLE control class.
+
+File History:
+
+ JonY May-96 created
+
+--*/
+
+/////////////////////////////////////////////////////////////////////////////
+// CHoursCtrl : See HoursCtl.cpp for implementation.
+
+class CHoursCtrl : public COleControl
+{
+ DECLARE_DYNCREATE(CHoursCtrl)
+
+// Constructor
+public:
+ CHoursCtrl();
+
+// Overrides
+
+ // Drawing function
+ virtual void OnDraw(
+ CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid);
+
+ // Persistence
+ virtual void DoPropExchange(CPropExchange* pPX);
+
+ // Reset control state
+ virtual void OnResetState();
+
+ virtual BOOL PreTranslateMessage(LPMSG lpmsg);
+
+private:
+ CFont* m_pFont;
+
+ struct
+ {
+ USHORT x;
+ USHORT y;
+ USHORT cx;
+ USHORT cy;
+ BOOL bVal; // TRUE = access allowed (default)
+ BOOL bSelected;
+ USHORT row;
+ USHORT col;
+ } m_sCell[202]; // 169 cells + 7 days + 24 hours + 1 big
+
+ CString csDay[7];
+
+ CPoint pointDrag;
+ USHORT GetCellID(CPoint point);
+ void InvalidateCell(USHORT sCellID);
+
+public:
+ short m_sCurrentCol;
+ short m_sCurrentRow;
+
+ short m_sCurrentLoc();
+ void Click(CPoint point);
+
+ void ToggleDay(UINT nID);
+ void ToggleCol(UINT nID);
+ void OnBigButton();
+ BOOL bToggle;
+
+// Implementation
+protected:
+ ~CHoursCtrl();
+
+ DECLARE_OLECREATE_EX(CHoursCtrl) // Class factory and guid
+ DECLARE_OLETYPELIB(CHoursCtrl) // GetTypeInfo
+ DECLARE_PROPPAGEIDS(CHoursCtrl) // Property page IDs
+ DECLARE_OLECTLTYPE(CHoursCtrl) // Type name and misc status
+
+// Message maps
+ //{{AFX_MSG(CHoursCtrl)
+ afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
+ afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
+ afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
+ afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
+ afx_msg void OnMouseMove(UINT nFlags, CPoint point);
+ //}}AFX_MSG
+
+ DECLARE_MESSAGE_MAP()
+
+// Dispatch maps
+ //{{AFX_DISPATCH(CHoursCtrl)
+ OLE_COLOR m_crPermitColor;
+ afx_msg void OnCrPermitColorChanged();
+ OLE_COLOR m_crDenyColor;
+ afx_msg void OnCrDenyColorChanged();
+ afx_msg VARIANT GetDateData();
+ afx_msg void SetDateData(const VARIANT FAR& newValue);
+ //}}AFX_DISPATCH
+ DECLARE_DISPATCH_MAP()
+
+// Event maps
+ //{{AFX_EVENT(CHoursCtrl)
+ //}}AFX_EVENT
+ DECLARE_EVENT_MAP()
+
+// Dispatch and event IDs
+public:
+ enum {
+ //{{AFX_DISP_ID(CHoursCtrl)
+ dispidCrPermitColor = 1L,
+ dispidCrDenyColor = 2L,
+ dispidDateData = 3L,
+ //}}AFX_DISP_ID
+ };
+};
diff --git a/private/utils/wizards/hoursctl/hoursppg.cpp b/private/utils/wizards/hoursctl/hoursppg.cpp
new file mode 100644
index 000000000..e5cdff088
--- /dev/null
+++ b/private/utils/wizards/hoursctl/hoursppg.cpp
@@ -0,0 +1,82 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+// HoursPpg.cpp : Implementation of the CHoursPropPage property page class.
+
+File History:
+
+ JonY May-96 created
+
+--*/
+
+#include "stdafx.h"
+#include "Hours.h"
+#include "HoursPpg.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+
+IMPLEMENT_DYNCREATE(CHoursPropPage, COlePropertyPage)
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Message map
+
+BEGIN_MESSAGE_MAP(CHoursPropPage, COlePropertyPage)
+ //{{AFX_MSG_MAP(CHoursPropPage)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Initialize class factory and guid
+
+IMPLEMENT_OLECREATE_EX(CHoursPropPage, "HOURS.HoursPropPage.1",
+ 0xa44ea7ae, 0x9d58, 0x11cf, 0xa3, 0x5f, 0, 0xaa, 0, 0xb6, 0x74, 0x3b)
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CHoursPropPage::CHoursPropPageFactory::UpdateRegistry -
+// Adds or removes system registry entries for CHoursPropPage
+
+BOOL CHoursPropPage::CHoursPropPageFactory::UpdateRegistry(BOOL bRegister)
+{
+ if (bRegister)
+ return AfxOleRegisterPropertyPageClass(AfxGetInstanceHandle(),
+ m_clsid, IDS_HOURS_PPG);
+ else
+ return AfxOleUnregisterClass(m_clsid, NULL);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CHoursPropPage::CHoursPropPage - Constructor
+
+CHoursPropPage::CHoursPropPage() :
+ COlePropertyPage(IDD, IDS_HOURS_PPG_CAPTION)
+{
+ //{{AFX_DATA_INIT(CHoursPropPage)
+ //}}AFX_DATA_INIT
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CHoursPropPage::DoDataExchange - Moves data between page and properties
+
+void CHoursPropPage::DoDataExchange(CDataExchange* pDX)
+{
+ //{{AFX_DATA_MAP(CHoursPropPage)
+ //}}AFX_DATA_MAP
+ DDP_PostProcessing(pDX);
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CHoursPropPage message handlers
diff --git a/private/utils/wizards/hoursctl/hoursppg.h b/private/utils/wizards/hoursctl/hoursppg.h
new file mode 100644
index 000000000..f6d7e8e8b
--- /dev/null
+++ b/private/utils/wizards/hoursctl/hoursppg.h
@@ -0,0 +1,42 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+// HoursPpg.h : Declaration of the CHoursPropPage property page class.
+
+File History:
+
+ JonY May-96 created
+
+--*/
+
+////////////////////////////////////////////////////////////////////////////
+// CHoursPropPage : See HoursPpg.cpp.cpp for implementation.
+
+class CHoursPropPage : public COlePropertyPage
+{
+ DECLARE_DYNCREATE(CHoursPropPage)
+ DECLARE_OLECREATE_EX(CHoursPropPage)
+
+// Constructor
+public:
+ CHoursPropPage();
+
+// Dialog Data
+ //{{AFX_DATA(CHoursPropPage)
+ enum { IDD = IDD_PROPPAGE_HOURS };
+ //}}AFX_DATA
+
+// Implementation
+protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+
+// Message maps
+protected:
+ //{{AFX_MSG(CHoursPropPage)
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+};
diff --git a/private/utils/wizards/hoursctl/makefile b/private/utils/wizards/hoursctl/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/wizards/hoursctl/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/wizards/hoursctl/resource.h b/private/utils/wizards/hoursctl/resource.h
new file mode 100644
index 000000000..8c879359f
--- /dev/null
+++ b/private/utils/wizards/hoursctl/resource.h
@@ -0,0 +1,27 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by Hours.rc
+//
+#define IDS_HOURS 1
+#define IDB_HOURS 1
+#define IDS_HOURS_PPG 2
+#define IDS_HOURS_PPG_CAPTION 100
+#define IDD_PROPPAGE_HOURS 100
+#define IDS_SUNDAY 101
+#define IDS_MONDAY 102
+#define IDS_TUESDAY 103
+#define IDS_WEDNESDAY 104
+#define IDS_THURSDAY 105
+#define IDS_FRIDAY 106
+#define IDS_SATURDAY 107
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 202
+#define _APS_NEXT_COMMAND_VALUE 32769
+#define _APS_NEXT_CONTROL_VALUE 201
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/private/utils/wizards/hoursctl/sources b/private/utils/wizards/hoursctl/sources
new file mode 100644
index 000000000..0221849be
--- /dev/null
+++ b/private/utils/wizards/hoursctl/sources
@@ -0,0 +1,50 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+TARGETNAME=hours
+TARGETPATH=obj
+TARGETTYPE=DYNLINK
+TARGETEXT=ocx
+DLLBASE=0x5a500000
+DLLENTRY=_DllMainCRTStartup
+
+USE_MFCUNICODE=1
+
+PRECOMPILED_INCLUDE=stdafx.h
+PRECOMPILED_CXX=1
+
+SOURCES= \
+ hours.cpp \
+ hoursctl.cpp \
+ hoursppg.cpp \
+ hours.rc
+
+UMTYPE=windows
+
+TARGETLIBS= \
+ $(BASEDIR)\public\sdk\lib\*\gdi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\oleaut32.lib \
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib
+
diff --git a/private/utils/wizards/hoursctl/stdafx.cpp b/private/utils/wizards/hoursctl/stdafx.cpp
new file mode 100644
index 000000000..9f120a2f8
--- /dev/null
+++ b/private/utils/wizards/hoursctl/stdafx.cpp
@@ -0,0 +1,18 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+// stdafx.cpp : source file that includes just the standard includes
+
+File History:
+
+ JonY May-96 created
+
+--*/
+
+// stdafx.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
diff --git a/private/utils/wizards/hoursctl/stdafx.h b/private/utils/wizards/hoursctl/stdafx.h
new file mode 100644
index 000000000..5a20a10cf
--- /dev/null
+++ b/private/utils/wizards/hoursctl/stdafx.h
@@ -0,0 +1,22 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+// stdafx.h : include file for standard system include files,
+
+File History:
+
+ JonY May-96 created
+
+--*/
+
+// or project specific include files that are used frequently,
+// but are changed infrequently
+
+#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
+
+#include <afxwin.h>
+#include <afxctl.h> // MFC support for OLE Controls
+
diff --git a/private/utils/wizards/liccomp/finpic.cpp b/private/utils/wizards/liccomp/finpic.cpp
new file mode 100644
index 000000000..3ae77567f
--- /dev/null
+++ b/private/utils/wizards/liccomp/finpic.cpp
@@ -0,0 +1,46 @@
+// FinPic.cpp : implementation file
+//
+
+#include "stdafx.h"
+#include "lcwiz.h"
+#include "FinPic.h"
+#include "transbmp.h"
+#include "resource.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CFinalPicture
+
+CFinalPicture::CFinalPicture()
+{
+}
+
+CFinalPicture::~CFinalPicture()
+{
+}
+
+
+BEGIN_MESSAGE_MAP(CFinalPicture, CStatic)
+ //{{AFX_MSG_MAP(CFinalPicture)
+ ON_WM_PAINT()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CFinalPicture message handlers
+
+void CFinalPicture::OnPaint()
+{
+ CPaintDC dc(this); // device context for painting
+ CTransBmp transbmp;
+
+ transbmp.LoadBitmap(IDB_END_FLAG);
+ transbmp.DrawTrans(&dc, 0, 0);
+
+ // Do not call CStatic::OnPaint() for painting messages
+}
diff --git a/private/utils/wizards/liccomp/finpic.h b/private/utils/wizards/liccomp/finpic.h
new file mode 100644
index 000000000..fd35c3b7c
--- /dev/null
+++ b/private/utils/wizards/liccomp/finpic.h
@@ -0,0 +1,37 @@
+// FinPic.h : header file
+//
+
+/////////////////////////////////////////////////////////////////////////////
+// CFinalPicture window
+
+class CFinalPicture : public CStatic
+{
+// Construction
+public:
+ CFinalPicture();
+
+// Attributes
+public:
+
+// Operations
+public:
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CFinalPicture)
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CFinalPicture();
+
+ // Generated message map functions
+protected:
+ //{{AFX_MSG(CFinalPicture)
+ afx_msg void OnPaint();
+ //}}AFX_MSG
+
+ DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/private/utils/wizards/liccomp/lcwiz.cpp b/private/utils/wizards/liccomp/lcwiz.cpp
new file mode 100644
index 000000000..3606dce90
--- /dev/null
+++ b/private/utils/wizards/liccomp/lcwiz.cpp
@@ -0,0 +1,255 @@
+// LCWiz.cpp : Defines the class behaviors for the application.
+//
+
+#include "stdafx.h"
+#include "LCWiz.h"
+#include "LCWizSht.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CLicCompWizApp
+
+BEGIN_MESSAGE_MAP(CLicCompWizApp, CWinApp)
+ //{{AFX_MSG_MAP(CLicCompWizApp)
+ // NOTE - the ClassWizard will add and remove mapping macros here.
+ // DO NOT EDIT what you see in these blocks of generated code!
+ //}}AFX_MSG
+ //ON_COMMAND(ID_HELP, CWinApp::OnHelp)
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// Global variables
+
+TCHAR pszMutex[] = _T("LicenseMutex");
+TCHAR pszLicenseEvent[] = _T("LicenseThread");
+TCHAR pszTreeEvent[] = _T("TreeThread");
+
+/////////////////////////////////////////////////////////////////////////////
+// CLicCompWizApp construction
+
+CLicCompWizApp::CLicCompWizApp()
+: m_pLicenseThread(NULL), m_bExitLicenseThread(FALSE),
+ m_event(TRUE, TRUE, pszLicenseEvent), m_nRemote(0)
+{
+ m_strEnterprise.Empty();
+ m_strDomain.Empty();
+ m_strEnterpriseServer.Empty();
+ m_strUser.Empty();
+
+ // Create a mutex object for use when checking for
+ // multiple instances.
+ m_hMutex = ::CreateMutex(NULL, TRUE, pszMutex);
+
+ // Place all significant initialization in InitInstance
+}
+
+CLicCompWizApp::~CLicCompWizApp()
+{
+ ::ReleaseMutex(m_hMutex);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// The one and only CLicCompWizApp object
+
+CLicCompWizApp theApp;
+
+/////////////////////////////////////////////////////////////////////////////
+// CLicCompWizApp initialization
+
+BOOL CLicCompWizApp::InitInstance()
+{
+ // Make sure we're running on the correct OS version.
+ OSVERSIONINFO os;
+
+ os.dwOSVersionInfoSize = sizeof(os);
+ ::GetVersionEx(&os);
+
+ if (os.dwMajorVersion < 4 || os.dwPlatformId != VER_PLATFORM_WIN32_NT)
+ {
+ AfxMessageBox(IDS_BAD_VERSION, MB_OK | MB_ICONSTOP);
+ return FALSE;
+ }
+
+ // If there's an instance already running, bring it to the
+ // top and exit.
+ if (::WaitForSingleObject(m_hMutex, 0) != WAIT_OBJECT_0)
+ {
+ CString strWindow;
+
+ strWindow.LoadString(AFX_IDS_APP_TITLE);
+ HWND hwnd = ::FindWindow(NULL, (LPCTSTR)strWindow);
+
+ if (hwnd != NULL)
+ ::SetForegroundWindow(hwnd);
+ else
+ {
+ TRACE(_T("%lu: FindWindow\n"), ::GetLastError());
+ }
+
+ return FALSE;
+ }
+
+#ifdef OLE_AUTO
+ // Initialize OLE libraries
+ if (!AfxOleInit())
+ {
+ AfxMessageBox(IDP_OLE_INIT_FAILED);
+ return FALSE;
+ }
+#endif // OLE_AUTO
+
+ // Standard initialization
+ // If you are not using these features and wish to reduce the size
+ // of your final executable, you should remove from the following
+ // the specific initialization routines you do not need.
+
+#ifdef _AFXDLL
+ Enable3dControls(); // Call this when using MFC in a shared DLL
+#else
+ Enable3dControlsStatic(); // Call this when linking to MFC statically
+#endif
+
+#ifdef OLE_AUTO
+ // Parse the command line to see if launched as OLE server
+ if (RunEmbedded() || RunAutomated())
+ {
+ // Register all OLE server (factories) as running. This enables the
+ // OLE libraries to create objects from other applications.
+ COleTemplateServer::RegisterAll();
+
+ // Application was run with /Embedding or /Automation. Don't show the
+ // main window in this case.
+ return TRUE;
+ }
+
+ // When a server application is launched stand-alone, it is a good idea
+ // to update the system registry in case it has been damaged.
+ COleObjectFactory::UpdateRegistryAll();
+
+#endif // OLE_AUTO
+
+ PLLS_CONNECT_INFO_0 pllsci;
+
+ // Get the default domain and license server.
+ NTSTATUS status = ::LlsEnterpriseServerFind(NULL, 0, (LPBYTE*)&pllsci);
+
+ if (NT_SUCCESS(status))
+ {
+ m_strDomain = pllsci->Domain;
+ m_strEnterpriseServer = pllsci->EnterpriseServer;
+
+ // Free embedded pointers.
+ //::LlsFreeMemory(pllsci->Domain);
+ //::LlsFreeMemory(pllsci->EnterpriseServer);
+ ::LlsFreeMemory(pllsci);
+ }
+ else
+ {
+ // There is no license server if this is a workstation
+ // so get the local computer name instead.
+
+ DWORD dwBufSize = BUFFER_SIZE;
+ LPTSTR pszTemp = m_strEnterpriseServer.GetBuffer(dwBufSize);
+ ::GetComputerName(pszTemp, &dwBufSize);
+ m_strDomain.ReleaseBuffer();
+
+ // Get the default domain name from the registry.
+ GetRegString(m_strDomain, IDS_SUBKEY, IDS_REG_VALUE);
+ }
+
+ CString strDomain, strUser;
+
+ // Get the user's name and domain.
+ GetRegString(strDomain, IDS_SUBKEY, IDS_REG_VALUE_DOMAIN);
+ GetRegString(strUser, IDS_SUBKEY, IDS_REG_VALUE_USER);
+
+ m_strUser.Format(IDS_DOMAIN_USER, strDomain, strUser);
+
+ // Launch the wizard.
+ OnWizard();
+
+ // Since the dialog has been closed, return FALSE so that we exit the
+ // application, rather than start the application's message pump.
+ return FALSE;
+}
+
+void CLicCompWizApp::OnWizard()
+{
+ // The property sheet attached to your project
+ // via this function is not hooked up to any message
+ // handler. In order to actually use the property sheet,
+ // you will need to associate this function with a control
+ // in your project such as a menu item or tool bar button.
+
+ CLicCompWizSheet propSheet;
+ m_pMainWnd = &propSheet;
+
+ propSheet.DoModal();
+
+ // This is where you would retrieve information from the property
+ // sheet if propSheet.DoModal() returned IDOK. We aren't doing
+ // anything for simplicity.
+}
+
+BOOL CLicCompWizApp::GetRegString(CString& strIn, UINT nSubKey, UINT nValue, HKEY hHive /* = HKEY_LOCAL_MACHINE */)
+{
+ BOOL bReturn = FALSE;
+ HKEY hKey;
+ LPTSTR pszTemp;
+ DWORD dwBufSize = BUFFER_SIZE;
+ CString strSubkey;
+ strSubkey.LoadString(nSubKey);
+
+ if (::RegOpenKeyEx(hHive, (LPCTSTR)strSubkey, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
+ {
+ DWORD dwType = REG_SZ;
+ CString strValue;
+ strValue.LoadString(nValue);
+
+ pszTemp = strIn.GetBuffer(dwBufSize);
+ ::RegQueryValueEx(hKey, (LPCTSTR)strValue, NULL, &dwType, (LPBYTE)pszTemp, &dwBufSize);
+ ::RegCloseKey(hKey);
+ strIn.ReleaseBuffer();
+
+ bReturn = TRUE;
+ }
+
+ return bReturn;
+}
+
+int CLicCompWizApp::ExitInstance()
+{
+ ExitThreads();
+
+ return CWinApp::ExitInstance();
+}
+
+void CLicCompWizApp::NotifyLicenseThread(BOOL bExit)
+{
+ CCriticalSection cs;
+
+ if (cs.Lock())
+ {
+ m_bExitLicenseThread = bExit;
+ cs.Unlock();
+ }
+}
+
+void CLicCompWizApp::ExitThreads()
+{
+ // Make sure the license thread knows it's supposed to quit.
+ if (m_pLicenseThread != NULL)
+ NotifyLicenseThread(TRUE);
+
+ // Create a lock object for the event object.
+ CSingleLock lock(&m_event);
+
+ // Lock the lock object and make the main thread wait for the
+ // threads to signal their event objects.
+ lock.Lock();
+}
diff --git a/private/utils/wizards/liccomp/lcwiz.h b/private/utils/wizards/liccomp/lcwiz.h
new file mode 100644
index 000000000..73f0f922e
--- /dev/null
+++ b/private/utils/wizards/liccomp/lcwiz.h
@@ -0,0 +1,82 @@
+// LCWiz.h : main header file for the LCWIZ application
+//
+
+#ifndef __AFXWIN_H__
+ #error include 'stdafx.h' before including this file for PCH
+#endif
+
+#ifndef __LCWIZ_H__
+#define __LCWIZ_H__
+
+#include <winreg.h>
+#include "resource.h" // main symbols
+
+typedef struct tagTREEINFO
+{
+ HTREEITEM hTreeItem;
+ DWORD dwBufSize;
+ CObject* pTree;
+ BOOL bExpand;
+}
+TREEINFO, *PTREEINFO;
+
+/////////////////////////////////////////////////////////////////////////////
+// CLicCompWizApp:
+// See LCWiz.cpp for the implementation of this class
+//
+
+class CLicCompWizApp : public CWinApp
+{
+public:
+ void OnWizard();
+ CLicCompWizApp();
+ ~CLicCompWizApp();
+ void NotifyLicenseThread(BOOL bExit);
+ void ExitThreads();
+
+// Data members
+public:
+ CString m_strEnterprise;
+ CWinThread* m_pLicenseThread;
+ BOOL m_bExitLicenseThread;
+ CEvent m_event;
+ CString m_strDomain, m_strEnterpriseServer, m_strUser;
+ int m_nRemote;
+
+protected:
+ HANDLE m_hMutex;
+
+// Attributes
+public:
+ inline int& IsRemote() {return m_nRemote;}
+
+protected:
+ BOOL GetRegString(CString& strIn, UINT nSubKey, UINT nValue, HKEY hHive = HKEY_LOCAL_MACHINE);
+
+// Constants
+ enum
+ {
+ BUFFER_SIZE = 256
+ };
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CLicCompWizApp)
+ public:
+ virtual BOOL InitInstance();
+ virtual int ExitInstance();
+ //}}AFX_VIRTUAL
+
+// Implementation
+
+ //{{AFX_MSG(CLicCompWizApp)
+ // NOTE - the ClassWizard will add and remove member functions here.
+ // DO NOT EDIT what you see in these blocks of generated code !
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+#endif __LCWIZ_H__
+
+/////////////////////////////////////////////////////////////////////////////
+
diff --git a/private/utils/wizards/liccomp/lcwiz.rc b/private/utils/wizards/liccomp/lcwiz.rc
new file mode 100644
index 000000000..b0665d33f
--- /dev/null
+++ b/private/utils/wizards/liccomp/lcwiz.rc
@@ -0,0 +1,271 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
+ "#define _AFX_NO_OLE_RESOURCES\r\n"
+ "#define _AFX_NO_TRACKER_RESOURCES\r\n"
+ "#define _AFX_NO_PROPERTY_RESOURCES\r\n"
+ "\r\n"
+ "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
+ "#ifdef _WIN32\r\n"
+ "LANGUAGE 9, 1\r\n"
+ "#pragma code_page(1252)\r\n"
+ "#endif\r\n"
+ "#include ""res\\LCWiz.rc2"" // non-Microsoft Visual C++ edited resources\r\n"
+ "#include ""afxres.rc"" // Standard components\r\n"
+ "#endif\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDR_MAINFRAME ICON DISCARDABLE "res\\LCWiz.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_PROPPAGE1 DIALOG DISCARDABLE 0, 0, 290, 141
+STYLE DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION
+CAPTION "License Compliance Wizard"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL 135,IDC_PAINT_BOX,"Static",SS_BITMAP | SS_CENTERIMAGE |
+ SS_REALSIZEIMAGE | SS_SUNKEN | WS_GROUP,0,0,80,140
+ LTEXT "",IDC_TEXT,92,20,197,65,SS_NOPREFIX
+ LTEXT "Welcome to the License Compliance Wizard",IDC_WELCOME,
+ 92,0,197,20
+ CONTROL "On &this domain (your computer's domain)",
+ IDC_RADIO_LOCAL_COMPUTER,"Button",BS_AUTORADIOBUTTON |
+ WS_GROUP | WS_TABSTOP,92,110,196,12
+ CONTROL "On &another domain",IDC_RADIO_DOMAIN,"Button",
+ BS_AUTORADIOBUTTON,92,123,196,12
+ CONTROL "Where do you want to search for unlicensed products?",
+ IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,92,95,
+ 197,14
+END
+
+IDD_PROPPAGE3 DIALOG DISCARDABLE 0, 0, 290, 140
+STYLE DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION
+CAPTION "License Compliance Wizard"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Type the domain name where you want to search for licensing information. Or, select the domain name from the list.",
+ IDC_TEXT_DOMAIN,0,0,288,18
+ LTEXT "D&omain name:",IDC_TEXT_SELECT_DOMAIN,0,24,54,8,NOT
+ WS_GROUP
+ EDITTEXT IDC_EDIT_ENTERPRISE,54,22,235,14,ES_UPPERCASE |
+ ES_AUTOHSCROLL
+ CONTROL "Tree1",IDC_TREE_NETWORK,"SysTreeView32",TVS_HASBUTTONS |
+ TVS_HASLINES | TVS_LINESATROOT | TVS_DISABLEDRAGDROP |
+ WS_BORDER | WS_TABSTOP,0,40,289,100
+END
+
+IDD_PROPPAGE4 DIALOG DISCARDABLE 0, 0, 290, 140
+STYLE DS_3DLOOK | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION
+CAPTION "License Compliance Wizard"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ PUSHBUTTON "&Print...",IDC_BUT_PRINT,240,126,49,14
+ CONTROL "List1",IDC_LIST_PRODUCTS,"SysListView32",LVS_REPORT |
+ LVS_SINGLESEL | LVS_SORTASCENDING | LVS_NOLABELWRAP |
+ LVS_AUTOARRANGE | LVS_NOSORTHEADER | WS_BORDER |
+ WS_TABSTOP,91,19,198,101
+ LTEXT "",IDC_TEXT_UNCOMP_PRODUCTS,90,0,200,15
+ LTEXT "Picture",IDC_FLAG_BMP,0,0,80,140
+END
+
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 4,0,0,0
+ PRODUCTVERSION 4,0,0,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Microsoft Corporation\0"
+ VALUE "FileDescription", "License Compliance Wizard\0"
+ VALUE "FileVersion", "4.00\0"
+ VALUE "InternalName", "LCWIZ.EXE\0"
+ VALUE "LegalCopyright", "Copyright © 1996 Microsoft Corporation\0"
+ VALUE "OriginalFilename", "LCWIZ.EXE\0"
+ VALUE "ProductName", "License Compliance Wizard\0"
+ VALUE "ProductVersion", "4.00\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // !_MAC
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_NET_TREE BITMAP DISCARDABLE "res\\net_tree.bmp"
+IDB_PAGE_ART BITMAP DISCARDABLE "res\\LICCOMP.BMP"
+IDB_END_FLAG BITMAP DISCARDABLE "res\\endflag.BMP"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDP_OLE_INIT_FAILED "OLE initialization failed. Make sure that the OLE libraries are the correct version."
+ IDS_PROPSHT_CAPTION "License Compliance Wizard"
+ IDS_TEXT_PAGE1 "This wizard detects software applications for which you do not have licenses.\n\nThe wizard searches the enterprise server for unlicensed copies of applications that conform to the LSAPI or SLSAPI licensing standards. The wizard then displays a report of unlicensed products, for which you may be required to buy more licenses.\n"
+ IDS_NET_ERROR "%s: %s."
+ IDS_NET_NO_SERVERS "The list of servers for this domain is not currently available."
+ IDS_PRODUCTS "Product"
+ IDS_LICENSES "Needed"
+ IDS_FONT "Arial"
+ IDS_FONT_BOLD "Arial Bold"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ AFX_IDS_APP_TITLE "License Compliance Wizard"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_UNLICENSED_PRODUCTS "Unlicensed products for %s:"
+ IDS_FMT_DATE "%x"
+ IDS_NO_LICENSE_INFO_LOCAL
+ "No licensing information was found after searching your computer. Either no license information is available or you are not logged on as an administrator."
+ IDS_DONE "&Done"
+ IDS_ERROR "An error occurred."
+ IDS_TREE_ROOT "Enterprise"
+ IDS_WORKING "Looking for license information..."
+ IDS_DOC_NAME "License Compliance Report for %s"
+ IDS_PAGE_DATE "Page %u - %s"
+ IDS_PURCHASED "Purchased"
+ IDS_USED "In Use"
+ IDS_PRODUCTS_LIST "Product"
+ IDS_LICENSES_LIST "Licenses needed"
+ IDS_ENUM_PRODUCTS "Gathering license information..."
+ IDS_MEM_ERROR "Out of memory. The list is too large to display."
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_NO_UNLICENSED_PRODUCTS "No unlicensed products were found."
+ IDS_ELLIPSIS "..."
+ IDS_SUBKEY "Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"
+ IDS_REG_VALUE "CachePrimaryDomain"
+ IDS_BAD_DOMAIN_NAME "%s is not a valid domain name or the primary domain controller is unavailable."
+ IDS_SERVER_UNAVAILABLE "No server is available to handle your request for licensing information."
+ IDS_NO_LICENSE_INFO_REMOTE
+ "No licensing information was found after searching %s."
+ IDS_ACCESS_DENIED "You have been denied access to %s. Make sure you are logged on as a domain administrator."
+ IDS_GENERIC_ERROR "An error occurred while attempting to access licensing information."
+ IDS_REG_VALUE_USER "DefaultUserName"
+ IDS_REG_VALUE_DOMAIN "DefaultDomainName"
+ IDS_DOMAIN_USER "%s\\%s"
+ IDS_ADMIN "Administrators"
+ IDS_LOCAL_ACCESS_DENIED "Access to your computer's domain has been denied. Make sure you are logged on as a domain administrator."
+ IDS_UNAVAILABLE "License information is not available."
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_SPECIFY_DOMAIN "Please enter the name of a domain."
+ IDS_BAD_VERSION "You need to be running Windows NT version 4.00 in order to use this application."
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#define _AFX_NO_SPLITTER_RESOURCES
+#define _AFX_NO_OLE_RESOURCES
+#define _AFX_NO_TRACKER_RESOURCES
+#define _AFX_NO_PROPERTY_RESOURCES
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE 9, 1
+#pragma code_page(1252)
+#endif
+#include "res\LCWiz.rc2" // non-Microsoft Visual C++ edited resources
+#include "afxres.rc" // Standard components
+#endif
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/private/utils/wizards/liccomp/lcwizpgs.cpp b/private/utils/wizards/liccomp/lcwizpgs.cpp
new file mode 100644
index 000000000..fbf7e35b4
--- /dev/null
+++ b/private/utils/wizards/liccomp/lcwizpgs.cpp
@@ -0,0 +1,1070 @@
+// LCWizPgs.cpp : implementation file
+//
+
+#include "stdafx.h"
+#include "resource.h"
+#include "LCWizPgs.h"
+#include "LCWiz.h"
+#include "LCWizSht.h"
+#include <lmaccess.h>
+#include <lmapibuf.h>
+#include <lmerr.h>
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char BASED_CODE THIS_FILE[] = __FILE__;
+#endif
+
+IMPLEMENT_DYNCREATE(CLicCompWizPage1, CPropertyPage)
+IMPLEMENT_DYNCREATE(CLicCompWizPage3, CPropertyPage)
+IMPLEMENT_DYNCREATE(CLicCompWizPage4, CPropertyPage)
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CLicCompWizPage1 property page
+
+CLicCompWizPage1::CLicCompWizPage1() : CPropertyPage(CLicCompWizPage1::IDD)
+{
+ //{{AFX_DATA_INIT(CLicCompWizPage1)
+ m_nRadio = 0;
+ m_strText = _T("");
+ //}}AFX_DATA_INIT
+}
+
+CLicCompWizPage1::~CLicCompWizPage1()
+{
+}
+
+void CLicCompWizPage1::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CLicCompWizPage1)
+ DDX_Control(pDX, IDC_WELCOME, m_wndWelcome);
+ DDX_Radio(pDX, IDC_RADIO_LOCAL_COMPUTER, m_nRadio);
+ DDX_Text(pDX, IDC_TEXT, m_strText);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CLicCompWizPage1, CPropertyPage)
+ //{{AFX_MSG_MAP(CLicCompWizPage1)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CLicCompWizPage1 property page
+
+BOOL CLicCompWizPage1::OnSetActive()
+{
+ ((CLicCompWizSheet*)GetParent())->SetWizardButtons(PSWIZB_NEXT);
+
+ return CPropertyPage::OnSetActive();
+}
+
+BOOL CLicCompWizPage1::OnInitDialog()
+{
+ CPropertyPage::OnInitDialog();
+
+ m_strText.LoadString(IDS_TEXT_PAGE1);
+
+ // Get the font for the welcome static control and make the font bold.
+ CFont* pFont = m_wndWelcome.GetFont();
+
+ // Get the default GUI font if GetFont() fails.
+ if (pFont == NULL)
+ pFont = CFont::FromHandle((HFONT)::GetStockObject(DEFAULT_GUI_FONT));
+
+ LOGFONT lf;
+
+ if (pFont != NULL && pFont->GetLogFont(&lf))
+ {
+ // Add to the font weight to make it bold.
+ lf.lfWeight += BOLD_WEIGHT;
+
+ if (m_fontBold.CreateFontIndirect(&lf))
+ {
+ // Set the font for the static control.
+ m_wndWelcome.SetFont(&m_fontBold);
+ }
+ }
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+
+LRESULT CLicCompWizPage1::OnWizardNext()
+{
+ UpdateData();
+
+ CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
+ CLicCompWizSheet* pSheet = (CLicCompWizSheet*)GetParent();
+
+ pApp->IsRemote() = m_nRadio;
+
+ pApp->m_strEnterprise.Empty();
+
+ if (m_nRadio == 0)
+ {
+ if (::IsWindow(pSheet->m_Page3.m_hWnd))
+ {
+ pSheet->m_Page3.GetEnterpriseEdit().SetWindowText(_T(""));
+ }
+
+ return IDD_PROPPAGE4;
+ }
+ else
+ return CPropertyPage::OnWizardNext();
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CLicCompWizPage3 property page
+
+CLicCompWizPage3::CLicCompWizPage3()
+: CPropertyPage(CLicCompWizPage3::IDD), m_bExpandedOnce(FALSE)
+{
+ //{{AFX_DATA_INIT(CLicCompWizPage3)
+ //}}AFX_DATA_INIT
+}
+
+CLicCompWizPage3::~CLicCompWizPage3()
+{
+}
+
+void CLicCompWizPage3::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CLicCompWizPage3)
+ DDX_Control(pDX, IDC_TEXT_SELECT_DOMAIN, m_wndTextSelectDomain);
+ DDX_Control(pDX, IDC_TEXT_DOMAIN, m_wndTextDomain);
+ DDX_Control(pDX, IDC_EDIT_ENTERPRISE, m_wndEnterprise);
+ DDX_Control(pDX, IDC_TREE_NETWORK, m_wndTreeNetwork);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CLicCompWizPage3, CPropertyPage)
+ //{{AFX_MSG_MAP(CLicCompWizPage3)
+ ON_NOTIFY(TVN_SELCHANGED, IDC_TREE_NETWORK, OnSelChangedTree)
+ ON_EN_CHANGE(IDC_EDIT_ENTERPRISE, OnChangeEditEnterprise)
+ ON_NOTIFY(NM_OUTOFMEMORY, IDC_TREE_NETWORK, OnNetworkTreeOutOfMemory)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CLicCompWizPage3 message handlers
+
+BOOL CLicCompWizPage3::OnSetActive()
+{
+ BOOL bReturn = CPropertyPage::OnSetActive();
+
+ CLicCompWizSheet* pSheet = (CLicCompWizSheet*)GetParent();
+
+ // Do the default domain expansion only once.
+ if (!m_bExpandedOnce)
+ {
+ m_bExpandedOnce = TRUE;
+ m_wndTreeNetwork.PopulateTree();
+ }
+
+ pSheet->SetWizardButtons(PSWIZB_BACK | PSWIZB_NEXT);
+
+ return bReturn;
+}
+
+void CLicCompWizPage3::OnSelChangedTree(NMHDR* pNMHDR, LRESULT* pResult)
+{
+ NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
+
+ ASSERT(pNMTreeView->itemNew.mask & TVIF_PARAM);
+
+ // Copy the remote name for the selected item into the edit control.
+ if (pNMTreeView->itemNew.mask & TVIF_PARAM)
+ {
+ CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
+
+ int nImage, nSelectedImage;
+
+ nImage = nSelectedImage = 0;
+
+ m_wndTreeNetwork.GetItemImage(m_wndTreeNetwork.GetSelectedItem(), nImage, nSelectedImage);
+
+ // Set the enterprise name in the App object.
+ if (nImage == CNetTreeCtrl::IMG_ROOT)
+ pApp->m_strEnterprise.Empty();
+ else
+ pApp->m_strEnterprise = ((LPNETRESOURCE)pNMTreeView->itemNew.lParam)->lpRemoteName;
+
+ // Set the text in the edit control.
+ m_wndEnterprise.SetWindowText(pApp->m_strEnterprise);
+
+ // Select the text in the edit control.
+ m_wndEnterprise.SetSel(0, -1);
+ }
+
+ *pResult = 0;
+}
+
+void CLicCompWizPage3::OnChangeEditEnterprise()
+{
+ CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
+
+ m_wndEnterprise.GetWindowText(pApp->m_strEnterprise);
+}
+
+void CLicCompWizPage3::OnNetworkTreeOutOfMemory(NMHDR* pNMHDR, LRESULT* pResult)
+{
+ m_wndTreeNetwork.NotifyThread(TRUE);
+
+ AfxMessageBox(IDS_MEM_ERROR, MB_OK | MB_ICONSTOP);
+
+ *pResult = 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CLicCompWizPage3 functions
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Global variables
+
+extern TCHAR pszLicenseEvent[];
+
+/////////////////////////////////////////////////////////////////////////////
+// Static member functions
+
+UINT CLicCompWizPage4::GetLicenseInfo(LPVOID pParam)
+{
+ // Create an event object to match that in the application object.
+ CEvent event(TRUE, TRUE, pszLicenseEvent);
+
+ CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
+ CLicCompWizPage4* pPage = (CLicCompWizPage4*)pParam;
+ CLicCompWizSheet* pSheet = (CLicCompWizSheet*)pPage->GetParent();
+ CWaitCursor wc;
+ NTSTATUS status = STATUS_ACCESS_DENIED;
+
+ try
+ {
+ CString strText;
+
+ // Unsignal the event object.
+ event.ResetEvent();
+
+ // Reset the exit flag.
+ pApp->NotifyLicenseThread(FALSE);
+
+ // Disable the Back and Next buttons while the thread is running.
+ pSheet->SetWizardButtons(0);
+
+ LPBYTE lpbBuf = NULL;
+ LLS_HANDLE hLls = NULL;
+ DWORD dwTotalEntries, dwResumeHandle;
+
+ dwTotalEntries = dwResumeHandle = 0;
+
+ // Save the machine or domain name that the user typed.
+ CString strFocus = pApp->m_strEnterprise;
+
+ // Display a message indicating what the wizard is doing.
+ strText.LoadString(IDS_WORKING);
+ pPage->m_wndUnlicensedProducts.SetWindowText(strText);
+ strText.Empty(); // Avoids a memory leak.
+
+ // Connect to the license server.
+ status = ::LlsConnectEnterprise(const_cast<LPTSTR>((LPCTSTR)pApp->m_strEnterprise),
+ &hLls, 0, &lpbBuf);
+
+ if (NT_ERROR(status))
+ goto ErrorMessage;
+
+ // It's OK for the user to click the Back button now, so enable it.
+ pSheet->SetWizardButtons(PSWIZB_BACK);
+
+ if (lpbBuf != NULL)
+ {
+ PLLS_CONNECT_INFO_0 pllsci = (PLLS_CONNECT_INFO_0)lpbBuf;
+
+ // Reset the domain and enterprise server names.
+ pApp->m_strDomain = pllsci->Domain;
+ pApp->m_strEnterpriseServer = pllsci->EnterpriseServer;
+
+ // Free embedded pointers
+ //::LlsFreeMemory(pllsci->Domain);
+ //::LlsFreeMemory(pllsci->EnterpriseServer);
+
+ // Free memory allocated by the LLS API.
+ status = ::LlsFreeMemory(lpbBuf);
+ lpbBuf = NULL;
+ }
+
+ if (NT_SUCCESS(status))
+ {
+ // Display a message indicating what the wizard is doing.
+ strText.LoadString(IDS_ENUM_PRODUCTS);
+ pPage->m_wndUnlicensedProducts.SetWindowText(strText);
+ strText.Empty(); // Avoids a memory leak.
+
+ USHORT nProductCount = 0;
+ DWORD dwEntriesRead, dwTotalEntriesRead;
+
+ dwEntriesRead = dwTotalEntriesRead = 0;
+
+ // Build a list of all the products.
+ do
+ {
+ // Check the exit thread flag. The user may have clicked the Back button.
+ if (pApp->m_bExitLicenseThread)
+ goto ExitThread;
+
+ status = ::LlsProductEnum(hLls, 1, &lpbBuf, CLicCompWizPage4::LLS_PREFERRED_LENGTH,
+ &dwEntriesRead, &dwTotalEntries, &dwResumeHandle);
+
+ if (!NT_SUCCESS(status))
+ goto ErrorMessage;
+
+ dwTotalEntriesRead += dwEntriesRead;
+
+ PLLS_PRODUCT_INFO_1 pllspi = (PLLS_PRODUCT_INFO_1)lpbBuf;
+
+ while (dwEntriesRead--)
+ {
+ // Check the exit thread flag. The user may have clicked the Back button.
+ if (pApp->m_bExitLicenseThread)
+ goto ExitThread;
+
+ if ((LONG)pllspi->InUse > (LONG)pllspi->Purchased)
+ {
+ pPage->FillListCtrl(pllspi->Product, (WORD)pllspi->InUse, (WORD)pllspi->Purchased);
+
+ // Increment the unlicensed products counter.
+ nProductCount++;
+ }
+
+ // Free embedded pointer.
+ ::LlsFreeMemory(pllspi->Product);
+
+ pllspi++;
+ }
+
+ // Free memory allocated by the LLS API.
+ status = ::LlsFreeMemory(lpbBuf);
+ lpbBuf = NULL;
+
+ ASSERT(NT_SUCCESS(status));
+ }
+ while (dwTotalEntries);
+
+ // Close the LLS handle.
+ status = ::LlsClose(hLls);
+
+ // Check the exit thread flag. The user may have clicked the Back button.
+ if (pApp->m_bExitLicenseThread)
+ goto ExitThread;
+
+ ASSERT(NT_SUCCESS(status));
+
+ // Show the user how many unlicensed products were found.
+ if (nProductCount)
+ {
+ strText.Format(IDS_UNLICENSED_PRODUCTS, pApp->m_strEnterpriseServer);
+ pPage->m_wndUnlicensedProducts.SetWindowText(strText);
+
+ // Make the static text box the appropriate size.
+ pPage->m_wndUnlicensedProducts.SetWindowPos(&CWnd::wndTop, 0, 0,
+ pPage->m_sizeSmallText.cx,
+ pPage->m_sizeSmallText.cy,
+ SWP_NOMOVE | SWP_NOZORDER);
+
+ // Make sure the list control is visible.
+ pPage->m_wndProductList.ShowWindow(SW_SHOW);
+
+ // Make sure the print button is visible.
+ pPage->m_wndPrint.ShowWindow(SW_SHOW);
+ }
+ else
+ {
+ // Make the static text box the appropriate size.
+ pPage->m_wndUnlicensedProducts.SetWindowPos(&CWnd::wndTop, 0, 0,
+ pPage->m_sizeLargeText.cx,
+ pPage->m_sizeLargeText.cy,
+ SWP_NOMOVE | SWP_NOZORDER);
+
+ // Display a message if no unlicensed products were found.
+ strText.LoadString(IDS_NO_UNLICENSED_PRODUCTS);
+ pPage->m_wndUnlicensedProducts.SetWindowText(strText);
+ }
+
+ // Enable the Back button.
+ pSheet->SetWizardButtons(PSWIZB_BACK);
+
+ CString strFinished;
+ CButton* pCancel = (CButton*)pSheet->GetDlgItem(IDCANCEL);
+
+ // Change the text on the cancel button to "Done."
+ strFinished.LoadString(IDS_DONE);
+ pCancel->SetWindowText(strFinished);
+
+ // Signal the event object.
+ event.SetEvent();
+
+ // Reset the pointer to the license thread.
+ pApp->m_pLicenseThread = NULL;
+
+ // Restore the normal cursor.
+ pPage->PostMessage(WM_SETCURSOR);
+ }
+
+ return 0;
+
+ ErrorMessage:
+ // Check the exit thread flag. The user may have clicked the Back button.
+ if (pApp->m_bExitLicenseThread)
+ goto ExitThread;
+
+ // Make the static text box the appropriate size.
+ pPage->m_wndUnlicensedProducts.SetWindowPos(&CWnd::wndTop, 0, 0,
+ pPage->m_sizeLargeText.cx,
+ pPage->m_sizeLargeText.cy,
+ SWP_NOMOVE | SWP_NOZORDER);
+
+ // Create an error message based on the return value from LlsConnectEnterprise().
+ switch (status)
+ {
+ case STATUS_NO_SUCH_DOMAIN:
+ if (pApp->IsRemote())
+ strText.Format(IDS_BAD_DOMAIN_NAME, strFocus);
+ else
+ strText.LoadString(IDS_UNAVAILABLE);
+ break;
+
+ case STATUS_ACCESS_DENIED:
+ if (pApp->IsRemote())
+ strText.Format(IDS_ACCESS_DENIED, strFocus);
+ else
+ strText.LoadString(IDS_LOCAL_ACCESS_DENIED);
+ break;
+
+ case RPC_NT_SERVER_UNAVAILABLE:
+ strText.Format(IDS_SERVER_UNAVAILABLE);
+ break;
+
+ default:
+ if (pApp->IsRemote())
+ strText.Format(IDS_NO_LICENSE_INFO_REMOTE, strFocus);
+ else
+ strText.LoadString(IDS_NO_LICENSE_INFO_LOCAL);
+ }
+
+ // Display an error message if LlsProductEnum() fails.
+ pPage->m_wndUnlicensedProducts.SetWindowText(strText);
+
+ // Enable the Back button.
+ pSheet->SetWizardButtons(PSWIZB_BACK);
+
+ // Signal the event object.
+ event.SetEvent();
+
+ // Reset the pointer to the license thread.
+ pApp->m_pLicenseThread = NULL;
+
+ // Restore the normal cursor.
+ pPage->PostMessage(WM_SETCURSOR);
+
+ return 1;
+
+ ExitThread:
+ // Signal the event object.
+ event.SetEvent();
+
+ // Reset the pointer to the license thread.
+ pApp->m_pLicenseThread = NULL;
+
+ return 2;
+ }
+ catch(...)
+ {
+ // Signal the event object.
+ event.SetEvent();
+
+ CString strText;
+
+ // Display an error message.
+ strText.LoadString(IDS_GENERIC_ERROR);
+ pPage->m_wndUnlicensedProducts.SetWindowText(strText);
+
+ // Reset the pointer to the license thread.
+ pApp->m_pLicenseThread = NULL;
+
+ // Restore the normal cursor.
+ pPage->PostMessage(WM_SETCURSOR);
+
+ return 3;
+ }
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CLicCompWizPage4 property page
+
+CLicCompWizPage4::CLicCompWizPage4()
+: CPropertyPage(CLicCompWizPage4::IDD), m_ptPrint(0, 0), m_nHorzMargin(0),
+m_nVertMargin(0),m_ptOrg(0, 0), m_ptExt(0, 0), m_sizeSmallText(0, 0),
+m_sizeLargeText(0, 0)
+{
+ //{{AFX_DATA_INIT(CLicCompWizPage4)
+ //}}AFX_DATA_INIT
+
+ m_strCancel.Empty();
+ m_pTabs = new INT[PRINT_COLUMNS];
+}
+
+CLicCompWizPage4::~CLicCompWizPage4()
+{
+ if (m_pTabs != NULL)
+ delete[] m_pTabs;
+}
+
+void CLicCompWizPage4::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CLicCompWizPage4)
+ DDX_Control(pDX, IDC_FLAG_BMP, m_wndPicture);
+ DDX_Control(pDX, IDC_BUT_PRINT, m_wndPrint);
+ DDX_Control(pDX, IDC_TEXT_UNCOMP_PRODUCTS, m_wndUnlicensedProducts);
+ DDX_Control(pDX, IDC_LIST_PRODUCTS, m_wndProductList);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CLicCompWizPage4, CPropertyPage)
+ //{{AFX_MSG_MAP(CLicCompWizPage4)
+ ON_BN_CLICKED(IDC_BUT_PRINT, OnPrintButton)
+ ON_NOTIFY(NM_OUTOFMEMORY, IDC_LIST_PRODUCTS, OnListProductsOutOfMemory)
+ ON_WM_DESTROY()
+ ON_WM_SETCURSOR()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+
+void CLicCompWizPage4::PumpMessages()
+{
+ // Must call Create() before using the dialog
+ ASSERT(m_hWnd!=NULL);
+
+ MSG msg;
+
+ try
+ {
+ // Handle dialog messages
+ while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ if(!IsDialogMessage(&msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ }
+ catch(...)
+ {
+ TRACE(_T("Exception in CLicCompWizPage4::PumpMessages()\n"));
+ }
+
+}
+
+BOOL CLicCompWizPage4::FillListCtrl(LPTSTR pszProduct, WORD wInUse, WORD wPurchased)
+{
+ TCHAR pszLicenses[BUFFER_SIZE];
+
+ ::wsprintf(pszLicenses, _T("%u"), wInUse - wPurchased);
+
+ USHORT nIndex;
+ LV_ITEM lvi;
+
+ lvi.mask = LVIF_TEXT | LVIF_PARAM;
+ lvi.iItem = 0;
+ lvi.iSubItem = 0;
+ lvi.lParam = MAKELONG(wInUse, wPurchased);
+ lvi.pszText = pszProduct;
+
+ if ((nIndex = m_wndProductList.InsertItem(&lvi)) != (USHORT)-1)
+ {
+ m_wndProductList.SetItemText(nIndex, 1, pszLicenses);
+ }
+
+ return TRUE;
+}
+
+BOOL CLicCompWizPage4::OnInitDialog()
+{
+ CPropertyPage::OnInitDialog();
+
+ // Set the header text for the list control.
+ CRect rcList;
+
+ m_wndProductList.GetWindowRect(&rcList);
+
+ CString strColumnTitle;
+ LV_COLUMN lvc;
+
+ lvc.mask = LVCF_FMT | LVCF_TEXT | LVCF_WIDTH;
+ lvc.fmt = LVCFMT_LEFT;
+
+ USHORT nColumns = COLUMNS;
+ UINT uStringID[COLUMNS] = {IDS_PRODUCTS_LIST, IDS_LICENSES_LIST};
+
+ for (USHORT i = 0; i < nColumns; i++)
+ {
+ strColumnTitle.LoadString(uStringID[i]);
+ lvc.pszText = strColumnTitle.GetBuffer(strColumnTitle.GetLength());
+ lvc.cx = rcList.Width() / COLUMNS;
+
+ m_wndProductList.InsertColumn(i, &lvc);
+
+ strColumnTitle.ReleaseBuffer();
+ }
+
+ CLicCompWizSheet* pSheet = (CLicCompWizSheet*)GetParent();
+
+ // Store the text on the cancel button.
+ CButton* pCancel = (CButton*)pSheet->GetDlgItem(IDCANCEL);
+ pCancel->GetWindowText(m_strCancel);
+
+ CRect rcText;
+
+ // Create the large and small extents for the static text control.
+ m_wndUnlicensedProducts.GetWindowRect(&rcText);
+
+ m_sizeSmallText.cx = rcText.right - rcText.left;
+ m_sizeSmallText.cy = rcText.bottom - rcText.top;
+
+ // Make the large extents match those for the list control.
+ m_sizeLargeText.cx = rcList.right - rcList.left;
+ m_sizeLargeText.cy = rcList.bottom - rcList.top;
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+void CLicCompWizPage4::OnListProductsOutOfMemory(NMHDR* pNMHDR, LRESULT* pResult)
+{
+ AfxMessageBox(IDS_MEM_ERROR, MB_OK | MB_ICONSTOP);
+
+ CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
+
+ // Let the license thread know it's supposed to quit.
+ pApp->NotifyLicenseThread(TRUE);
+
+ *pResult = 0;
+}
+
+void CLicCompWizPage4::OnPrintButton()
+{
+ CDC dc;
+ CPrintDialog dlg(FALSE,
+ PD_ALLPAGES | PD_USEDEVMODECOPIESANDCOLLATE |
+ PD_NOPAGENUMS | PD_HIDEPRINTTOFILE |
+ PD_NOSELECTION,
+ this);
+
+ if (dlg.DoModal() == IDOK)
+ {
+ CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
+ m_wndPrint.RedrawWindow();
+
+ DOCINFO di;
+ CString strDocName;
+
+ strDocName.Format(IDS_DOC_NAME, pApp->m_strEnterpriseServer);
+
+ di.cbSize = sizeof(DOCINFO);
+ di.lpszDocName = strDocName.GetBuffer(BUFFER_SIZE);
+ di.lpszOutput = NULL;
+
+ if (dc.Attach(dlg.GetPrinterDC()))
+ {
+ PrepareForPrinting(dc);
+ dc.StartDoc(&di);
+ PrintReport(dc);
+ dc.EndDoc();
+ dc.DeleteDC();
+ ::GlobalFree(dlg.m_pd.hDevNames);
+ ::GlobalFree(dlg.m_pd.hDevMode);
+ }
+ }
+}
+
+BOOL CLicCompWizPage4::PrepareForPrinting(CDC& dc)
+{
+ // Create various fonts...
+ CString strFont;
+
+ // Create a heading font.
+ strFont.LoadString(IDS_FONT_BOLD);
+ m_fontHeading.CreatePointFont(FONT_SIZE_HEADING, strFont, &dc);
+
+ // Create a bold, underlined header font.
+ strFont.LoadString(IDS_FONT_BOLD);
+ m_fontHeader.CreatePointFont(FONT_SIZE, strFont, &dc);
+
+ LOGFONT lf;
+ m_fontHeader.GetLogFont(&lf);
+ m_fontHeader.DeleteObject();
+ lf.lfUnderline = TRUE;
+ m_fontHeader.CreateFontIndirect(&lf);
+
+ // Create a footer font.
+ strFont.LoadString(IDS_FONT_BOLD);
+ m_fontFooter.CreatePointFont(FONT_SIZE_FOOTER, strFont, &dc);
+
+ // Create a default font.
+ strFont.LoadString(IDS_FONT);
+ m_fontNormal.CreatePointFont(FONT_SIZE, strFont, &dc);
+
+ // Get the text metrics for each font.
+ CFont* pOldFont = dc.SelectObject(&m_fontHeading);
+ dc.GetTextMetrics(&m_tmHeading);
+
+ dc.SelectObject(&m_fontHeader);
+ dc.GetTextMetrics(&m_tmHeader);
+
+ dc.SelectObject(&m_fontFooter);
+ dc.GetTextMetrics(&m_tmFooter);
+
+ dc.SelectObject(&m_fontNormal);
+ dc.GetTextMetrics(&m_tmNormal);
+
+ // Select the original font back in to the device context.
+ dc.SelectObject(pOldFont);
+
+ // Set the horizontal and vertical margins.
+ m_nHorzMargin = (LONG)(dc.GetDeviceCaps(LOGPIXELSX) * HORZ_MARGIN);
+ m_nVertMargin = (LONG)(dc.GetDeviceCaps(LOGPIXELSY) * VERT_MARGIN);
+
+ // Get the printable page offsets for the origin.
+ m_ptOrg.x = dc.GetDeviceCaps(PHYSICALOFFSETX);
+ m_ptOrg.y = dc.GetDeviceCaps(PHYSICALOFFSETY);
+
+ dc.SetWindowOrg(m_ptOrg);
+
+ m_ptOrg.x += m_nHorzMargin;
+ m_ptOrg.y += m_nVertMargin;
+
+ // Get the printable page offsets for the page extents.
+ m_ptExt.x = dc.GetDeviceCaps(PHYSICALWIDTH) - m_ptOrg.x;
+ m_ptExt.y = dc.GetDeviceCaps(PHYSICALHEIGHT) - m_ptOrg.y;
+
+ dc.SetViewportOrg(m_ptOrg);
+
+ CalculateTabs(dc);
+
+ return TRUE;
+}
+
+BOOL CLicCompWizPage4::PrintReport(CDC& dc)
+{
+ // Set the starting point for printing.
+ m_ptPrint.x = m_ptPrint.y = 0;
+
+ // Prepare to print a heading.
+ CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
+ CString strHeading;
+
+ CFont* pOldFont = dc.SelectObject(&m_fontHeading);
+ strHeading.Format(IDS_DOC_NAME, pApp->m_strEnterpriseServer);
+
+ dc.StartPage();
+
+ CRect rc(m_ptPrint.x, m_ptPrint.y, m_ptExt.x - m_ptOrg.x, m_tmHeading.tmHeight);
+
+ // Calculate the size of the rectangle needed to draw the text.
+ m_ptPrint.y += dc.DrawText(strHeading, &rc, DT_EXTERNALLEADING | DT_CENTER | DT_WORDBREAK | DT_NOCLIP);
+
+ // Normalize the rectangle.
+ rc.NormalizeRect();
+
+ // Add a blank line below the heading.
+ m_ptPrint.y += m_tmHeading.tmHeight;
+
+ // Move the right side of the rectangle out to the right margin so text is properly centered.
+ rc.right = m_ptExt.x - m_ptOrg.x;
+
+ // Draw the text in the rectangle.
+ dc.DrawText(strHeading, &rc, DT_EXTERNALLEADING | DT_CENTER | DT_WORDBREAK | DT_NOCLIP);
+
+ dc.SelectObject(pOldFont);
+
+ PrintPages(dc, 100);
+
+ // Delete the fonts.
+ m_fontNormal.DeleteObject();
+ m_fontHeader.DeleteObject();
+ m_fontFooter.DeleteObject();
+ m_fontHeading.DeleteObject();
+
+ return TRUE;
+}
+
+BOOL CLicCompWizPage4::PrintPageHeader(CDC& dc)
+{
+ CFont* pOldFont = dc.SelectObject(&m_fontHeader);
+
+ dc.StartPage();
+
+ CString strHeader, strProducts, strLicenses, strPurchased, strUsed;
+ strProducts.LoadString(IDS_PRODUCTS);
+ strLicenses.LoadString(IDS_LICENSES);
+ strPurchased.LoadString(IDS_PURCHASED);
+ strUsed.LoadString(IDS_USED);
+ strHeader.Format(_T("%s\t%s\t%s\t%s"), strProducts, strLicenses,
+ strPurchased, strUsed);
+
+ dc.TabbedTextOut(m_ptPrint.x, m_ptPrint.y, strHeader, PRINT_COLUMNS, m_pTabs, 0);
+
+ m_ptPrint.y += ((m_tmHeader.tmHeight + m_tmHeader.tmExternalLeading) * 2);
+
+ dc.SelectObject(pOldFont);
+
+ return TRUE;
+}
+
+BOOL CLicCompWizPage4::PrintPageFooter(CDC& dc, USHORT nPage)
+{
+ CFont* pOldFont = dc.SelectObject(&m_fontFooter);
+
+ CString strFooter;
+ CTime time(CTime::GetCurrentTime());
+
+ strFooter.Format(IDS_PAGE_DATE, nPage, time.Format(IDS_FMT_DATE));
+
+ CRect rc(m_ptPrint.x, m_ptExt.y - m_nVertMargin, m_ptOrg.x, m_tmFooter.tmHeight);
+
+ // Calculate the size of the rectangle needed to draw the text.
+ m_ptPrint.y += dc.DrawText(strFooter, &rc, DT_CALCRECT | DT_EXTERNALLEADING | DT_CENTER | DT_WORDBREAK | DT_NOCLIP);
+
+ // Move the right side of the rectangle out to the right margin so text is properly centered.
+ rc.right = m_ptExt.x - m_ptOrg.x;
+
+ // Draw the text in the rectangle.
+ dc.DrawText(strFooter, &rc, DT_EXTERNALLEADING | DT_CENTER | DT_WORDBREAK | DT_NOCLIP);
+
+ dc.EndPage();
+
+ dc.SelectObject(pOldFont);
+
+ return TRUE;
+}
+
+BOOL CLicCompWizPage4::PrintPages(CDC& dc, UINT nStart)
+{
+ CFont* pOldFont = dc.SelectObject(&m_fontNormal);
+
+ UINT nPage = 1;
+ UINT nItems = m_wndProductList.GetItemCount();
+
+ // Print the initial header.
+ PrintPageHeader(dc);
+
+ DWORD dwParam = 0;
+ CString strTextOut;
+
+ for (UINT i = 0; i < nItems; i++)
+ {
+ dwParam = m_wndProductList.GetItemData(i);
+
+ CString strProduct = m_wndProductList.GetItemText(i, 0);
+
+ CSize sizeProduct = dc.GetTextExtent(strProduct);
+
+ if (sizeProduct.cx > m_pTabs[0] - (m_tmNormal.tmAveCharWidth * TAB_WIDTH))
+ TruncateText(dc, strProduct);
+
+ // Format the output text.
+ strTextOut.Format(_T("%s\t%s\t%u\t%u"), strProduct,
+ m_wndProductList.GetItemText(i, 1),
+ HIWORD(dwParam), LOWORD(dwParam));
+
+ dc.TabbedTextOut(m_ptPrint.x, m_ptPrint.y, strTextOut, PRINT_COLUMNS, m_pTabs, 0);
+
+ // Calculate the vertical position for the next line of text.
+ m_ptPrint.y += m_tmNormal.tmHeight + m_tmNormal.tmExternalLeading;
+
+ if ((m_ptPrint.y + m_ptOrg.y) >= m_ptExt.y)
+ {
+ PrintPageFooter(dc, nPage++);
+
+ // Reset the printing position.
+ m_ptPrint.y = 0;
+
+ PrintPageHeader(dc);
+ }
+ }
+
+ // Print the final footer.
+ PrintPageFooter(dc, nPage);
+
+ dc.SelectObject(pOldFont);
+
+ return TRUE;
+}
+
+void CLicCompWizPage4::TruncateText(CDC& dc, CString& strInput)
+{
+ CString strText, strEllipsis;
+
+ USHORT nLen, nChars = 0;
+ UINT nMaxWidth = m_pTabs[0] - (m_tmNormal.tmAveCharWidth * TAB_WIDTH);
+ nLen = strInput.GetLength();
+
+ strEllipsis.LoadString(IDS_ELLIPSIS);
+
+ CSize sizeText = dc.GetTextExtent(strInput);
+
+ // Keep lopping off characters until the string is short enough.
+ while ((UINT)sizeText.cx > nMaxWidth)
+ {
+ strText = strInput.Left(nLen - nChars++);
+ sizeText = dc.GetTextExtent(strText);
+ }
+
+ // Remove the last characters and replace them with an ellipsis.
+ ASSERT(strText.GetLength() > strEllipsis.GetLength());
+ strInput = strText.Left(strText.GetLength() - strEllipsis.GetLength()) + strEllipsis;
+}
+
+BOOL CLicCompWizPage4::CalculateTabs(CDC& dc)
+{
+ INT nTotalExt = 0;
+ INT nTabSize = TAB_WIDTH * m_tmHeader.tmAveCharWidth;
+
+ UINT uStrIds[] = {IDS_LICENSES, IDS_PURCHASED, IDS_USED};
+
+ m_pTabs[0] = 0;
+
+ for (USHORT i = 1; i < PRINT_COLUMNS; i++)
+ {
+ CString strText;
+
+ strText.LoadString(uStrIds[i - 1]);
+ // Get the text extent for each string.
+ m_pTabs[i] = dc.GetTextExtent(strText).cx;
+ // Keep a running total of the extents.
+ nTotalExt += m_pTabs[i];
+ }
+
+ // Add tab space between columns.
+ nTotalExt += nTabSize * (PRINT_COLUMNS - 2);
+
+ // The second column will begin at the difference between the right
+ // margin and the total extent.
+ m_pTabs[0] = m_ptExt.x - m_ptOrg.x - nTotalExt;
+
+ // Now set the actual tab positions in the array.
+ for (i = 1; i < PRINT_COLUMNS; i++)
+ {
+ m_pTabs[i] += m_pTabs[i - 1] + nTabSize;
+ }
+
+ return TRUE;
+}
+
+LRESULT CLicCompWizPage4::OnWizardBack()
+{
+ CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
+
+ // Let the license thread know it's time to quit.
+ pApp->NotifyLicenseThread(TRUE);
+
+ CLicCompWizSheet* pSheet = (CLicCompWizSheet*)GetParent();
+
+ // Set the cancel button text back to "Cancel."
+ CButton* pCancel = (CButton*)pSheet->GetDlgItem(IDCANCEL);
+ pCancel->SetWindowText(m_strCancel);
+
+ if (pSheet->m_Page1.m_nRadio == 0)
+ return IDD_PROPPAGE1;
+ else
+ return CPropertyPage::OnWizardBack();
+}
+
+void CLicCompWizPage4::OnDestroy()
+{
+ CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
+
+ pApp->NotifyLicenseThread(TRUE);
+ PumpMessages();
+
+ CPropertyPage::OnDestroy();
+}
+
+BOOL CLicCompWizPage4::OnSetActive()
+{
+ CLicCompWizSheet* pSheet = (CLicCompWizSheet*)GetParent();
+
+ pSheet->SetWizardButtons(PSWIZB_BACK);
+
+ // Hide the list control and clear it.
+ m_wndProductList.ShowWindow(SW_HIDE);
+ m_wndProductList.DeleteAllItems();
+
+ // Hide the print button.
+ m_wndPrint.ShowWindow(SW_HIDE);
+
+ CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
+
+ // Make sure the last thread has terminated before starting a new one.
+ if (pApp->m_pLicenseThread != NULL)
+ {
+ pApp->NotifyLicenseThread(TRUE);
+
+ CEvent event(TRUE, TRUE, pszLicenseEvent);
+ CSingleLock lock(&event);
+
+ lock.Lock();
+ }
+
+ // Keep a pointer to the thread so we can find out if it's still running.
+ pApp->m_pLicenseThread = AfxBeginThread((AFX_THREADPROC)GetLicenseInfo, (LPVOID)this);
+
+ return CPropertyPage::OnSetActive();
+}
+
+LRESULT CLicCompWizPage3::OnWizardNext()
+{
+ CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
+
+ m_wndEnterprise.GetWindowText(pApp->m_strEnterprise);
+
+ // Trim off any white space in the enterprise name.
+ pApp->m_strEnterprise.TrimLeft();
+ pApp->m_strEnterprise.TrimRight();
+
+ if (pApp->m_strEnterprise.IsEmpty() ||
+ pApp->m_strEnterprise.Find(_T("\\\\")) != -1)
+ {
+ AfxMessageBox(IDS_SPECIFY_DOMAIN, MB_OK | MB_ICONEXCLAMATION);
+ return IDD;
+ }
+
+ return CPropertyPage::OnWizardNext();
+}
+
+BOOL CLicCompWizPage4::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
+{
+ CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
+
+ if (pApp->m_pLicenseThread == NULL)
+ {
+ return CPropertyPage::OnSetCursor(pWnd, nHitTest, message);
+ }
+ else
+ {
+ // Restore the wait cursor if the thread is running.
+ RestoreWaitCursor();
+
+ return TRUE;
+ }
+}
diff --git a/private/utils/wizards/liccomp/lcwizpgs.h b/private/utils/wizards/liccomp/lcwizpgs.h
new file mode 100644
index 000000000..48865cc03
--- /dev/null
+++ b/private/utils/wizards/liccomp/lcwizpgs.h
@@ -0,0 +1,208 @@
+// LCWizPgs.h : header file
+//
+
+#ifndef __LCWIZPGS_H__
+#define __LCWIZPGS_H__
+
+#include "NetTree.h"
+#include "FinPic.h"
+
+#define HORZ_MARGIN 1 // Inches
+#define VERT_MARGIN 1.25 // Inches
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CLicCompWizPage1 dialog
+
+class CLicCompWizPage1 : public CPropertyPage
+{
+ DECLARE_DYNCREATE(CLicCompWizPage1)
+
+// Construction
+public:
+ CLicCompWizPage1();
+ ~CLicCompWizPage1();
+
+// Dialog Data
+
+ CFont m_fontBold;
+
+ //{{AFX_DATA(CLicCompWizPage1)
+ enum { IDD = IDD_PROPPAGE1 };
+ CStatic m_wndWelcome;
+ int m_nRadio;
+ CString m_strText;
+ //}}AFX_DATA
+
+// Constants
+ enum
+ {
+ BOLD_WEIGHT = 300
+ };
+
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CLicCompWizPage1)
+ public:
+ virtual BOOL OnSetActive();
+ virtual LRESULT OnWizardNext();
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CLicCompWizPage1)
+ virtual BOOL OnInitDialog();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+};
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CLicCompWizPage3 dialog
+
+class CLicCompWizPage3 : public CPropertyPage
+{
+ DECLARE_DYNCREATE(CLicCompWizPage3)
+
+// Construction
+public:
+ CLicCompWizPage3();
+ ~CLicCompWizPage3();
+
+// Dialog Data
+protected:
+ BOOL m_bExpandedOnce;
+
+ //{{AFX_DATA(CLicCompWizPage3)
+ enum { IDD = IDD_PROPPAGE3 };
+ CStatic m_wndTextSelectDomain;
+ CStatic m_wndTextDomain;
+ CEdit m_wndEnterprise;
+ CNetTreeCtrl m_wndTreeNetwork;
+ //}}AFX_DATA
+
+ // Constants
+ enum
+ {
+ BUFFER_SIZE = 0x100
+ };
+
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CLicCompWizPage3)
+ public:
+ virtual BOOL OnSetActive();
+ virtual LRESULT OnWizardNext();
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ inline CEdit& GetEnterpriseEdit() {return m_wndEnterprise;}
+
+protected:
+
+ // Generated message map functions
+ //{{AFX_MSG(CLicCompWizPage3)
+ afx_msg void OnSelChangedTree(NMHDR* pNMHDR, LRESULT* pResult);
+ afx_msg void OnChangeEditEnterprise();
+ afx_msg void OnNetworkTreeOutOfMemory(NMHDR* pNMHDR, LRESULT* pResult);
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CLicCompWizPage4 dialog
+
+class CLicCompWizPage4 : public CPropertyPage
+{
+ DECLARE_DYNCREATE(CLicCompWizPage4)
+
+// Construction
+public:
+ CLicCompWizPage4();
+ ~CLicCompWizPage4();
+
+// Dialog Data
+protected:
+ CFont m_fontNormal, m_fontHeader, m_fontFooter, m_fontHeading;
+ TEXTMETRIC m_tmNormal, m_tmHeader, m_tmFooter, m_tmHeading;
+ CPoint m_ptPrint, m_ptOrg, m_ptExt;
+ LONG m_nHorzMargin, m_nVertMargin;
+ LPINT m_pTabs;
+ CString m_strCancel;
+ CSize m_sizeSmallText, m_sizeLargeText;
+
+ //{{AFX_DATA(CLicCompWizPage4)
+ enum { IDD = IDD_PROPPAGE4 };
+ CFinalPicture m_wndPicture;
+ CButton m_wndPrint;
+ CStatic m_wndUnlicensedProducts;
+ CListCtrl m_wndProductList;
+ //}}AFX_DATA
+
+ // Constants
+ enum
+ {
+ LLS_PREFERRED_LENGTH = 500,
+
+ COLUMNS = 2,
+ PRINT_COLUMNS = 4,
+ TAB_WIDTH = 3,
+
+ BUFFER_SIZE = 0x100,
+
+ FONT_SIZE = 100,
+ FONT_SIZE_HEADING = 140,
+ FONT_SIZE_FOOTER = 80,
+ };
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CLicCompWizPage4)
+ public:
+ virtual BOOL OnSetActive();
+ virtual LRESULT OnWizardBack();
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ BOOL FillListCtrl(LPTSTR pszProduct, WORD wInUse, WORD wPurchased);
+ static UINT GetLicenseInfo(LPVOID pParam);
+
+protected:
+ BOOL PrintReport(CDC& dc);
+ BOOL PrintPages(CDC& dc, UINT nStart);
+ BOOL PrepareForPrinting(CDC& dc);
+ BOOL PrintPageHeader(CDC& dc);
+ BOOL PrintPageFooter(CDC& dc, USHORT nPage);
+ BOOL CalculateTabs(CDC& dc);
+ void TruncateText(CDC& dc, CString& strText);
+ void PumpMessages();
+
+ // Generated message map functions
+ //{{AFX_MSG(CLicCompWizPage4)
+ virtual BOOL OnInitDialog();
+ afx_msg void OnPrintButton();
+ afx_msg void OnListProductsOutOfMemory(NMHDR* pNMHDR, LRESULT* pResult);
+ afx_msg void OnDestroy();
+ afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+};
+
+#endif // __LCWIZPGS_H__
+
diff --git a/private/utils/wizards/liccomp/lcwizsht.cpp b/private/utils/wizards/liccomp/lcwizsht.cpp
new file mode 100644
index 000000000..05a55eb36
--- /dev/null
+++ b/private/utils/wizards/liccomp/lcwizsht.cpp
@@ -0,0 +1,59 @@
+// LCWizSht.cpp : implementation file
+//
+
+#include "stdafx.h"
+#include "resource.h"
+#include "LCWizSht.h"
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char BASED_CODE THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CLicCompWizSheet
+
+IMPLEMENT_DYNAMIC(CLicCompWizSheet, CPropertySheet)
+
+CLicCompWizSheet::CLicCompWizSheet(CWnd* pWndParent)
+ : CPropertySheet(IDS_PROPSHT_CAPTION, pWndParent)
+{
+ // Add all of the property pages here. Note that
+ // the order that they appear in here will be
+ // the order they appear in on screen. By default,
+ // the first page of the set is the active one.
+ // One way to make a different property page the
+ // active one is to call SetActivePage().
+
+ AddPage(&m_Page1);
+ AddPage(&m_Page3);
+ AddPage(&m_Page4);
+
+ SetWizardMode();
+}
+
+CLicCompWizSheet::~CLicCompWizSheet()
+{
+}
+
+
+BEGIN_MESSAGE_MAP(CLicCompWizSheet, CPropertySheet)
+ //{{AFX_MSG_MAP(CLicCompWizSheet)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CLicCompWizSheet message handlers
+
+
+BOOL CLicCompWizSheet::OnInitDialog()
+{
+ if ((m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME)) != NULL)
+ {
+ ::SetClassLong(m_hWnd, GCL_HICON, (LONG)m_hIcon);
+ ::SetClassLong(m_hWnd, GCL_HICONSM, (LONG)m_hIcon);
+ }
+
+ return CPropertySheet::OnInitDialog();
+}
diff --git a/private/utils/wizards/liccomp/lcwizsht.h b/private/utils/wizards/liccomp/lcwizsht.h
new file mode 100644
index 000000000..da5845c45
--- /dev/null
+++ b/private/utils/wizards/liccomp/lcwizsht.h
@@ -0,0 +1,56 @@
+// LCWizSht.h : header file
+//
+// This class defines custom modal property sheet
+// CLicCompWizSheet.
+
+#ifndef __LCWIZSHT_H__
+#define __LCWIZSHT_H__
+
+#include "LCWizPgs.h"
+
+/////////////////////////////////////////////////////////////////////////////
+// CLicCompWizSheet
+
+class CLicCompWizSheet : public CPropertySheet
+{
+ DECLARE_DYNAMIC(CLicCompWizSheet)
+
+// Construction
+public:
+ CLicCompWizSheet(CWnd* pParentWnd = NULL);
+
+// Data members
+public:
+ CLicCompWizPage1 m_Page1;
+ CLicCompWizPage3 m_Page3;
+ CLicCompWizPage4 m_Page4;
+ HICON m_hIcon;
+
+// Attributes
+public:
+
+// Operations
+public:
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CLicCompWizSheet)
+ public:
+ virtual BOOL OnInitDialog();
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CLicCompWizSheet();
+
+// Generated message map functions
+protected:
+ //{{AFX_MSG(CLicCompWizSheet)
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+#endif // __LCWIZSHT_H__
+
diff --git a/private/utils/wizards/liccomp/llsapi.h b/private/utils/wizards/liccomp/llsapi.h
new file mode 100644
index 000000000..a56a43abd
--- /dev/null
+++ b/private/utils/wizards/liccomp/llsapi.h
@@ -0,0 +1,1034 @@
+/*++
+
+Copyright (c) 1994-95 Microsoft Corporation
+
+Module Name:
+
+ llsapi.h
+
+Abstract:
+
+ License logging server's RPC API's.
+
+Author:
+
+ Arthur Hanson (arth) 21-Mar-1995
+
+Environment:
+
+ User Mode - Win32
+
+Revision History:
+
+--*/
+
+#ifndef _LLSAPI_H
+#define _LLSAPI_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define LLS_FLAG_LICENSED 0x0001
+#define LLS_FLAG_UPDATE 0x0002
+#define LLS_FLAG_SUITE_USE 0x0004
+#define LLS_FLAG_SUITE_AUTO 0x0008
+
+#define LLS_FLAG_PRODUCT_PERSEAT 0x0010
+#define LLS_FLAG_PRODUCT_SWITCH 0x0020
+
+#define LLS_FLAG_DELETED 0x1000
+
+
+typedef PVOID LLS_HANDLE, *PLLS_HANDLE;
+
+
+typedef struct _LLS_LICENSE_INFO_0 {
+ LPTSTR Product;
+ LONG Quantity;
+ DWORD Date;
+ LPTSTR Admin;
+ LPTSTR Comment;
+} LLS_LICENSE_INFO_0, *PLLS_LICENSE_INFO_0;
+
+
+typedef struct _LLS_PRODUCT_INFO_0 {
+ LPTSTR Product;
+} LLS_PRODUCT_INFO_0, *PLLS_PRODUCT_INFO_0;
+
+typedef struct _LLS_PRODUCT_INFO_1 {
+ LPTSTR Product;
+ ULONG Purchased;
+ ULONG InUse;
+ ULONG ConcurrentTotal;
+ ULONG HighMark;
+} LLS_PRODUCT_INFO_1, *PLLS_PRODUCT_INFO_1;
+
+
+typedef struct _LLS_PRODUCT_USER_INFO_0 {
+ LPTSTR User;
+} LLS_PRODUCT_USER_INFO_0, *PLLS_PRODUCT_USER_INFO_0;
+
+typedef struct _LLS_PRODUCT_USER_INFO_1 {
+ LPTSTR User;
+ DWORD Flags;
+ DWORD LastUsed;
+ ULONG UsageCount;
+} LLS_PRODUCT_USER_INFO_1, *PLLS_PRODUCT_USER_INFO_1;
+
+
+typedef struct _LLS_PRODUCT_LICENSE_INFO_0 {
+ LONG Quantity;
+ DWORD Date;
+ LPTSTR Admin;
+ LPTSTR Comment;
+} LLS_PRODUCT_LICENSE_INFO_0, *PLLS_PRODUCT_LICENSE_INFO_0;
+
+typedef struct _LLS_USER_INFO_0 {
+ LPTSTR Name;
+} LLS_USER_INFO_0, *PLLS_USER_INFO_0;
+
+typedef struct _LLS_USER_INFO_1 {
+ LPTSTR Name;
+ DWORD Flags;
+ LPTSTR Group;
+ ULONG Licensed;
+ ULONG UnLicensed;
+} LLS_USER_INFO_1, *PLLS_USER_INFO_1;
+
+typedef struct _LLS_USER_INFO_2 {
+ LPTSTR Name;
+ DWORD Flags;
+ LPTSTR Group;
+ ULONG Licensed;
+ ULONG UnLicensed;
+ LPTSTR Products;
+} LLS_USER_INFO_2, *PLLS_USER_INFO_2;
+
+typedef struct _LLS_USER_PRODUCT_INFO_0 {
+ LPTSTR Product;
+} LLS_USER_PRODUCT_INFO_0, *PLLS_USER_PRODUCT_INFO_0;
+
+typedef struct _LLS_USER_PRODUCT_INFO_1 {
+ LPTSTR Product;
+ DWORD Flags;
+ DWORD LastUsed;
+ ULONG UsageCount;
+} LLS_USER_PRODUCT_INFO_1, *PLLS_USER_PRODUCT_INFO_1;
+
+typedef struct _LLS_GROUP_INFO_0 {
+ LPTSTR Name;
+} LLS_GROUP_INFO_0, *PLLS_GROUP_INFO_0;
+
+typedef struct _LLS_GROUP_INFO_1 {
+ LPTSTR Name;
+ LPTSTR Comment;
+ ULONG Licenses;
+} LLS_GROUP_INFO_1, *PLLS_GROUP_INFO_1;
+
+
+#define LLS_REPLICATION_TYPE_DELTA 0
+#define LLS_REPLICATION_TYPE_TIME 1
+
+#define LLS_MODE_LICENSE_SERVER 0
+#define LLS_MODE_PDC 1
+#define LLS_MODE_ENTERPRISE_SERVER 2
+
+typedef struct _LLS_SERVICE_INFO_0 {
+ DWORD Version;
+ DWORD TimeStarted;
+ DWORD Mode;
+ LPTSTR ReplicateTo;
+ LPTSTR EnterpriseServer;
+ DWORD ReplicationType;
+ DWORD ReplicationTime;
+ DWORD UseEnterprise;
+ DWORD LastReplicated;
+} LLS_SERVICE_INFO_0, *PLLS_SERVICE_INFO_0;
+
+typedef struct _LLS_CONNECT_INFO_0 {
+ LPTSTR Domain;
+ LPTSTR EnterpriseServer;
+} LLS_CONNECT_INFO_0, *PLLS_CONNECT_INFO_0;
+
+
+typedef struct _LLS_SERVER_PRODUCT_INFO_0 {
+ LPTSTR Name;
+} LLS_SERVER_PRODUCT_INFO_0, *PLLS_SERVER_PRODUCT_INFO_0;
+
+typedef struct _LLS_SERVER_PRODUCT_INFO_1 {
+ LPTSTR Name;
+ DWORD Flags;
+ ULONG MaxUses;
+ ULONG MaxSetUses;
+ ULONG HighMark;
+} LLS_SERVER_PRODUCT_INFO_1, *PLLS_SERVER_PRODUCT_INFO_1;
+
+
+typedef struct _LLS_SERVER_INFO_0 {
+ LPTSTR Name;
+} LLS_SERVER_INFO_0, *PLLS_SERVER_INFO_0;
+
+
+
+#ifndef NO_LLS_APIS
+//
+// Connection control API's
+//
+
+NTSTATUS
+NTAPI
+LlsConnectW(
+ IN LPWSTR Server,
+ OUT PLLS_HANDLE Handle
+ );
+
+NTSTATUS
+NTAPI
+LlsConnectA(
+ IN LPSTR Server,
+ OUT PLLS_HANDLE Handle
+ );
+#ifdef UNICODE
+#define LlsConnect LlsConnectW
+#else
+#define LlsConnect LlsConnectA
+#endif
+
+NTSTATUS
+NTAPI
+LlsConnectEnterpriseW(
+ IN LPWSTR Focus,
+ OUT PLLS_HANDLE Handle,
+ IN DWORD Level,
+ OUT LPBYTE *bufptr
+ );
+
+NTSTATUS
+NTAPI
+LlsConnectEnterpriseA(
+ IN LPSTR Focus,
+ OUT PLLS_HANDLE Handle,
+ IN DWORD Level,
+ OUT LPBYTE *bufptr
+ );
+#ifdef UNICODE
+#define LlsConnectEnterprise LlsConnectEnterpriseW
+#else
+#define LlsConnectEnterprise LlsConnectEnterpriseA
+#endif
+
+NTSTATUS
+NTAPI
+LlsClose(
+ IN LLS_HANDLE Handle
+ );
+
+NTSTATUS
+NTAPI
+LlsFreeMemory(
+ IN PVOID bufptr
+ );
+
+
+NTSTATUS
+NTAPI
+LlsEnterpriseServerFindW(
+ IN LPWSTR Focus,
+ IN DWORD Level,
+ OUT LPBYTE *bufptr
+ );
+
+NTSTATUS
+NTAPI
+LlsEnterpriseServerFindA(
+ IN LPSTR Focus,
+ IN DWORD Level,
+ OUT LPBYTE *bufptr
+ );
+#ifdef UNICODE
+#define LlsEnterpriseServerFind LlsEnterpriseServerFindW
+#else
+#define LlsEnterpriseServerFind LlsEnterpriseServerFindA
+#endif
+
+//
+// License control API's
+//
+
+// Enum purchase history of licenses for all products.
+NTSTATUS
+NTAPI
+LlsLicenseEnumW(
+ IN LLS_HANDLE Handle,
+ IN DWORD Level, // Level 0 supported
+ OUT LPBYTE* bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ );
+
+NTSTATUS
+NTAPI
+LlsLicenseEnumA(
+ IN LLS_HANDLE Handle,
+ IN DWORD Level, // Level 0 supported
+ OUT LPBYTE* bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ );
+#ifdef UNICODE
+#define LlsLicenseEnum LlsLicenseEnumW
+#else
+#define LlsLicenseEnum LlsLicenseEnumA
+#endif
+
+// Add purchase of license for a product.
+NTSTATUS
+NTAPI
+LlsLicenseAddW(
+ IN LLS_HANDLE Handle,
+ IN DWORD Level, // Level 0 supported
+ IN LPBYTE bufptr
+ );
+
+NTSTATUS
+NTAPI
+LlsLicenseAddA(
+ IN LLS_HANDLE Handle,
+ IN DWORD Level, // Level 0 supported
+ IN LPBYTE bufptr
+ );
+#ifdef UNICODE
+#define LlsLicenseAdd LlsLicenseAddW
+#else
+#define LlsLicenseAdd LlsLicenseAddA
+#endif
+
+//
+// Product control API's
+//
+// Product is SQL, BackOffice, Exchange, Etc. (Even though BackOffice isn't
+// a product - we count it like one to keep things simplistic.
+//
+
+// Enum all products with purchase and InUse info.
+NTSTATUS
+NTAPI
+LlsProductEnumW(
+ IN LLS_HANDLE Handle,
+ IN DWORD Level, // Levels 0,1 supported
+ OUT LPBYTE* bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ );
+
+NTSTATUS
+NTAPI
+LlsProductEnumA(
+ IN LLS_HANDLE Handle,
+ IN DWORD Level, // Levels 0,1 supported
+ OUT LPBYTE* bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ );
+#ifdef UNICODE
+#define LlsProductEnum LlsProductEnumW
+#else
+#define LlsProductEnum LlsProductEnumA
+#endif
+
+// Add purchase of license for a product.
+NTSTATUS
+NTAPI
+LlsProductAddW(
+ IN LLS_HANDLE Handle,
+ IN LPWSTR ProductFamily,
+ IN LPWSTR Product,
+ IN LPWSTR Version
+ );
+
+NTSTATUS
+NTAPI
+LlsProductAddA(
+ IN LLS_HANDLE Handle,
+ IN LPSTR ProductFamily,
+ IN LPSTR Product,
+ IN LPSTR Version
+ );
+#ifdef UNICODE
+#define LlsProductAdd LlsProductAddW
+#else
+#define LlsProductAdd LlsProductAddA
+#endif
+
+// For a particular product enum all users.
+NTSTATUS
+NTAPI
+LlsProductUserEnumW(
+ IN LLS_HANDLE Handle,
+ IN LPWSTR Product,
+ IN DWORD Level, // Levels 0,1 supported
+ OUT LPBYTE* bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ );
+
+NTSTATUS
+NTAPI
+LlsProductUserEnumA(
+ IN LLS_HANDLE Handle,
+ IN LPSTR Product,
+ IN DWORD Level, // Levels 0,1 supported
+ OUT LPBYTE* bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ );
+#ifdef UNICODE
+#define LlsProductUserEnum LlsProductUserEnumW
+#else
+#define LlsProductUserEnum LlsProductUserEnumA
+#endif
+
+// For a particular product enum all license purchases.
+NTSTATUS
+NTAPI
+LlsProductLicenseEnumW(
+ IN LLS_HANDLE Handle,
+ IN LPWSTR Product,
+ IN DWORD Level, // Level 0 supported
+ OUT LPBYTE* bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ );
+
+NTSTATUS
+NTAPI
+LlsProductLicenseEnumA(
+ IN LLS_HANDLE Handle,
+ IN LPSTR Product,
+ IN DWORD Level, // Level 0 supported
+ OUT LPBYTE* bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ );
+#ifdef UNICODE
+#define LlsProductLicenseEnum LlsProductLicenseEnumW
+#else
+#define LlsProductLicenseEnum LlsProductLicenseEnumA
+#endif
+
+
+// For given product enum all servers with concurrent limits
+NTSTATUS
+NTAPI
+LlsProductServerEnumW(
+ IN LLS_HANDLE Handle,
+ IN LPWSTR Product,
+ IN DWORD Level, // Levels 0,1 supported
+ OUT LPBYTE* bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ );
+
+NTSTATUS
+NTAPI
+LlsProductServerEnumA(
+ IN LLS_HANDLE Handle,
+ IN LPSTR Product,
+ IN DWORD Level, // Levels 0,1 supported
+ OUT LPBYTE* bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ );
+#ifdef UNICODE
+#define LlsProductServerEnum LlsProductServerEnumW
+#else
+#define LlsProductServerEnum LlsProductServerEnumA
+#endif
+//
+// User control API's
+// A user can be a mapped user or a normal user
+//
+
+// Enums all users
+NTSTATUS
+NTAPI
+LlsUserEnumW(
+ IN LLS_HANDLE Handle,
+ IN DWORD Level, // Levels 0,1 supported
+ OUT LPBYTE* bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ );
+
+NTSTATUS
+NTAPI
+LlsUserEnumA(
+ IN LLS_HANDLE Handle,
+ IN DWORD Level, // Levels 0,1 supported
+ OUT LPBYTE* bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ );
+#ifdef UNICODE
+#define LlsUserEnum LlsUserEnumW
+#else
+#define LlsUserEnum LlsUserEnumA
+#endif
+
+// Info is Group and whether to force back-office license
+NTSTATUS
+NTAPI
+LlsUserInfoGetW(
+ IN LLS_HANDLE Handle,
+ IN LPWSTR User,
+ IN DWORD Level, // Level 1 supported
+ OUT LPBYTE* bufptr
+ );
+
+NTSTATUS
+NTAPI
+LlsUserInfoGetA(
+ IN LLS_HANDLE Handle,
+ IN LPSTR User,
+ IN DWORD Level, // Level 1 supported
+ OUT LPBYTE* bufptr
+ );
+#ifdef UNICODE
+#define LlsUserInfoGet LlsUserInfoGetW
+#else
+#define LlsUserInfoGet LlsUserInfoGetA
+#endif
+
+NTSTATUS
+NTAPI
+LlsUserInfoSetW(
+ IN LLS_HANDLE Handle,
+ IN LPWSTR User,
+ IN DWORD Level,
+ IN LPBYTE bufptr // Level 1 supported
+ );
+
+NTSTATUS
+NTAPI
+LlsUserInfoSetA(
+ IN LLS_HANDLE Handle,
+ IN LPSTR User,
+ IN DWORD Level,
+ IN LPBYTE bufptr // Level 1 supported
+ );
+#ifdef UNICODE
+#define LlsUserInfoSet LlsUserInfoSetW
+#else
+#define LlsUserInfoSet LlsUserInfoSetA
+#endif
+
+NTSTATUS
+NTAPI
+LlsUserDeleteW(
+ IN LLS_HANDLE Handle,
+ IN LPWSTR User
+ );
+
+NTSTATUS
+NTAPI
+LlsUserDeleteA(
+ IN LLS_HANDLE Handle,
+ IN LPSTR User
+ );
+#ifdef UNICODE
+#define LlsUserDelete LlsUserDeleteW
+#else
+#define LlsUserDelete LlsUserDeleteA
+#endif
+
+// For a given user enums all license useages
+NTSTATUS
+NTAPI
+LlsUserProductEnumW(
+ IN LLS_HANDLE Handle,
+ IN LPWSTR User,
+ IN DWORD Level, // Levels 0,1 supported
+ OUT LPBYTE* bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ );
+
+NTSTATUS
+NTAPI
+LlsUserProductEnumA(
+ IN LLS_HANDLE Handle,
+ IN LPSTR User,
+ IN DWORD Level, // Levels 0,1 supported
+ OUT LPBYTE* bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ );
+#ifdef UNICODE
+#define LlsUserProductEnum LlsUserProductEnumW
+#else
+#define LlsUserProductEnum LlsUserProductEnumA
+#endif
+
+// For a given user deletes a license useage
+NTSTATUS
+NTAPI
+LlsUserProductDeleteW(
+ IN LLS_HANDLE Handle,
+ IN LPWSTR User,
+ IN LPWSTR Product
+ );
+
+NTSTATUS
+NTAPI
+LlsUserProductDeleteA(
+ IN LLS_HANDLE Handle,
+ IN LPSTR User,
+ IN LPSTR Product
+ );
+#ifdef UNICODE
+#define LlsUserProductDelete LlsUserProductDeleteW
+#else
+#define LlsUserProductDelete LlsUserProductDeleteA
+#endif
+
+//
+// Group control API's
+//
+
+// Enums all user Groups
+NTSTATUS
+NTAPI
+LlsGroupEnumW(
+ IN LLS_HANDLE Handle,
+ IN DWORD Level, // Levels 0,1 supported
+ OUT LPBYTE* bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ );
+
+NTSTATUS
+NTAPI
+LlsGroupEnumA(
+ IN LLS_HANDLE Handle,
+ IN DWORD Level, // Levels 0,1 supported
+ OUT LPBYTE* bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ );
+#ifdef UNICODE
+#define LlsGroupEnum LlsGroupEnumW
+#else
+#define LlsGroupEnum LlsGroupEnumA
+#endif
+
+// For given Group gets info, info is name, comment and # licenses used
+NTSTATUS
+NTAPI
+LlsGroupInfoGetW(
+ IN LLS_HANDLE Handle,
+ IN LPWSTR Group,
+ IN DWORD Level, // Level 1 supported
+ OUT LPBYTE* bufptr
+ );
+
+NTSTATUS
+NTAPI
+LlsGroupInfoGetA(
+ IN LLS_HANDLE Handle,
+ IN LPSTR Group,
+ IN DWORD Level, // Level 1 supported
+ OUT LPBYTE* bufptr
+ );
+#ifdef UNICODE
+#define LlsGroupInfoGet LlsGroupInfoGetW
+#else
+#define LlsGroupInfoGet LlsGroupInfoGetA
+#endif
+
+NTSTATUS
+NTAPI
+LlsGroupInfoSetW(
+ IN LLS_HANDLE Handle,
+ IN LPWSTR Group,
+ IN DWORD Level, // Level 1 supported
+ IN LPBYTE bufptr
+ );
+
+NTSTATUS
+NTAPI
+LlsGroupInfoSetA(
+ IN LLS_HANDLE Handle,
+ IN LPSTR Group,
+ IN DWORD Level, // Level 1 supported
+ IN LPBYTE bufptr
+ );
+#ifdef UNICODE
+#define LlsGroupInfoSet LlsGroupInfoSetW
+#else
+#define LlsGroupInfoSet LlsGroupInfoSetA
+#endif
+
+// For given Group enum all users
+NTSTATUS
+NTAPI
+LlsGroupUserEnumW(
+ IN LLS_HANDLE Handle,
+ IN LPWSTR Group,
+ IN DWORD Level, // Levels 0,1 supported
+ OUT LPBYTE* bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ );
+
+NTSTATUS
+NTAPI
+LlsGroupUserEnumA(
+ IN LLS_HANDLE Handle,
+ IN LPSTR Group,
+ IN DWORD Level, // Levels 0,1 supported
+ OUT LPBYTE* bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ );
+#ifdef UNICODE
+#define LlsGroupUserEnum LlsGroupUserEnumW
+#else
+#define LlsGroupUserEnum LlsGroupUserEnumA
+#endif
+
+// Add user to given Group
+NTSTATUS
+NTAPI
+LlsGroupUserAddW(
+ IN LLS_HANDLE Handle,
+ IN LPWSTR Group,
+ IN LPWSTR User
+ );
+
+NTSTATUS
+NTAPI
+LlsGroupUserAddA(
+ IN LLS_HANDLE Handle,
+ IN LPSTR Group,
+ IN LPSTR User
+ );
+#ifdef UNICODE
+#define LlsGroupUserAdd LlsGroupUserAddW
+#else
+#define LlsGroupUserAdd LlsGroupUserAddA
+#endif
+
+// Delete user from given Group
+NTSTATUS
+NTAPI
+LlsGroupUserDeleteW(
+ IN LLS_HANDLE Handle,
+ IN LPWSTR Group,
+ IN LPWSTR User
+ );
+
+NTSTATUS
+NTAPI
+LlsGroupUserDeleteA(
+ IN LLS_HANDLE Handle,
+ IN LPSTR Group,
+ IN LPSTR User
+ );
+#ifdef UNICODE
+#define LlsGroupUserDelete LlsGroupUserDeleteW
+#else
+#define LlsGroupUserDelete LlsGroupUserDeleteA
+#endif
+
+// Add a given Group
+NTSTATUS
+NTAPI
+LlsGroupAddW(
+ IN LLS_HANDLE Handle,
+ IN DWORD Level, // Level 1 supported
+ IN LPBYTE bufptr
+ );
+
+NTSTATUS
+NTAPI
+LlsGroupAddA(
+ IN LLS_HANDLE Handle,
+ IN DWORD Level, // Level 1 supported
+ IN LPBYTE bufptr
+ );
+#ifdef UNICODE
+#define LlsGroupAdd LlsGroupAddW
+#else
+#define LlsGroupAdd LlsGroupAddA
+#endif
+
+NTSTATUS
+NTAPI
+LlsGroupDeleteW(
+ IN LLS_HANDLE Handle,
+ IN LPWSTR Group
+ );
+
+NTSTATUS
+NTAPI
+LlsGroupDeleteA(
+ IN LLS_HANDLE Handle,
+ IN LPSTR Group
+ );
+#ifdef UNICODE
+#define LlsGroupDelete LlsGroupDeleteW
+#else
+#define LlsGroupDelete LlsGroupDeleteA
+#endif
+
+
+//
+// Service control API's
+//
+
+NTSTATUS
+NTAPI
+LlsServiceInfoGetW(
+ IN LLS_HANDLE Handle,
+ IN DWORD Level,
+ OUT LPBYTE* bufptr
+ );
+
+NTSTATUS
+NTAPI
+LlsServiceInfoGetA(
+ IN LLS_HANDLE Handle,
+ IN DWORD Level,
+ OUT LPBYTE* bufptr
+ );
+#ifdef UNICODE
+#define LlsServiceInfoGet LlsServiceInfoGetW
+#else
+#define LlsServiceInfoGet LlsServiceInfoGetA
+#endif
+
+NTSTATUS
+NTAPI
+LlsServiceInfoSetW(
+ IN LLS_HANDLE Handle,
+ IN DWORD Level,
+ IN LPBYTE bufptr
+ );
+
+NTSTATUS
+NTAPI
+LlsServiceInfoSetA(
+ IN LLS_HANDLE Handle,
+ IN DWORD Level,
+ IN LPBYTE bufptr
+ );
+#ifdef UNICODE
+#define LlsServiceInfoSet LlsServiceInfoSetW
+#else
+#define LlsServiceInfoSet LlsServiceInfoSetA
+#endif
+
+
+//
+// Server Table Stuff (Replicated Server / Product Tree)
+//
+NTSTATUS
+NTAPI
+LlsServerEnumW(
+ IN LLS_HANDLE Handle,
+ IN DWORD Level, // Levels 0,1 supported
+ OUT LPBYTE* bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ );
+
+NTSTATUS
+NTAPI
+LlsServerEnumA(
+ IN LLS_HANDLE Handle,
+ IN DWORD Level, // Levels 0,1 supported
+ OUT LPBYTE* bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ );
+#ifdef UNICODE
+#define LlsServerEnum LlsServerEnumW
+#else
+#define LlsServerEnum LlsServerEnumA
+#endif
+
+
+NTSTATUS
+NTAPI
+LlsServerProductEnumW(
+ IN LLS_HANDLE Handle,
+ IN LPWSTR Server,
+ IN DWORD Level, // Levels 0,1 supported
+ OUT LPBYTE* bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ );
+
+NTSTATUS
+NTAPI
+LlsServerProductEnumA(
+ IN LLS_HANDLE Handle,
+ IN LPSTR Server,
+ IN DWORD Level, // Levels 0,1 supported
+ OUT LPBYTE* bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ );
+#ifdef UNICODE
+#define LlsServerUserEnum LlsServerUserEnumW
+#else
+#define LlsServerUserEnum LlsServerUserEnumA
+#endif
+
+
+//
+// Concurrent (Per-Server) mode API's (these will interact with the registry
+// on the remote system).
+//
+NTSTATUS
+NTAPI
+LlsLocalProductEnumW(
+ IN LLS_HANDLE Handle,
+ IN DWORD Level, // Levels 0,1 supported
+ OUT LPBYTE* bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ );
+
+NTSTATUS
+NTAPI
+LlsLocalProductEnumA(
+ IN LLS_HANDLE Handle,
+ IN DWORD Level, // Levels 0,1 supported
+ OUT LPBYTE* bufptr,
+ IN DWORD prefmaxlen,
+ OUT LPDWORD EntriesRead,
+ OUT LPDWORD TotalEntries,
+ IN OUT LPDWORD ResumeHandle
+ );
+#ifdef UNICODE
+#define LlsLocalProductEnum LlsLocalProductEnumW
+#else
+#define LlsLocalProductEnum LlsLocalProductEnumA
+#endif
+
+
+NTSTATUS
+NTAPI
+LlsLocalProductInfoGetW(
+ IN LLS_HANDLE Handle,
+ IN LPWSTR Product,
+ IN DWORD Level,
+ IN LPBYTE bufptr
+ );
+
+NTSTATUS
+NTAPI
+LlsLocalProductInfoGetA(
+ IN LLS_HANDLE Handle,
+ IN LPSTR Product,
+ IN DWORD Level,
+ IN LPBYTE bufptr
+ );
+#ifdef UNICODE
+#define LlsLocalProductInfoGet LlsLocalProductInfoGetW
+#else
+#define LlsLocalProductInfoGet LlsLocalProductInfoGetA
+#endif
+
+
+NTSTATUS
+NTAPI
+LlsLocalProductInfoSetW(
+ IN LLS_HANDLE Handle,
+ IN LPWSTR Product,
+ IN DWORD Level,
+ IN LPBYTE bufptr
+ );
+
+NTSTATUS
+NTAPI
+LlsLocalProductInfoSetA(
+ IN LLS_HANDLE Handle,
+ IN LPSTR Product,
+ IN DWORD Level,
+ IN LPBYTE bufptr
+ );
+#ifdef UNICODE
+#define LlsLocalProductInfoSet LlsLocalProductInfoSetW
+#else
+#define LlsLocalProductInfoSet LlsLocalProductInfoSetA
+#endif
+
+
+#endif
+
+//
+// Registry values
+//
+
+#define REG_KEY_LICENSE TEXT("SYSTEM\\CurrentControlSet\\Services\\LicenseInfo")
+
+#define REG_VALUE_NAME TEXT("DisplayName")
+#define REG_VALUE_MODE TEXT("Mode")
+#define REG_VALUE_FLIP TEXT("FlipAllow")
+#define REG_VALUE_LIMIT TEXT("ConcurrentLimit")
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/private/utils/wizards/liccomp/makefile b/private/utils/wizards/liccomp/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/wizards/liccomp/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/wizards/liccomp/nettree.cpp b/private/utils/wizards/liccomp/nettree.cpp
new file mode 100644
index 000000000..fc5fb52af
--- /dev/null
+++ b/private/utils/wizards/liccomp/nettree.cpp
@@ -0,0 +1,595 @@
+// NetTree.cpp : implementation file
+//
+
+#include "stdafx.h"
+#include "NetTree.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// Global variables
+
+extern TCHAR pszTreeEvent[];
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CNetTreeCtrl
+
+CNetTreeCtrl::CNetTreeCtrl()
+: m_pThread(NULL), m_bExitThread(FALSE), m_event(TRUE, TRUE, pszTreeEvent)
+{
+ // Get a handle to the process heap
+ m_hHeap = ::GetProcessHeap();
+
+ ASSERT(m_hHeap != NULL);
+}
+
+CNetTreeCtrl::~CNetTreeCtrl()
+{
+ // Make sure the thread knows it's time to terminate.
+ NotifyThread(TRUE);
+
+ // Create an event object to match the tree thread event object.
+ CEvent event(TRUE, TRUE, pszTreeEvent);
+
+ // Create a lock object for the event object.
+ CSingleLock lock(&event);
+
+ // Lock the lock object and make the main thread wait for the
+ // threads to signal their event objects.
+ lock.Lock();
+
+ // Free all of the pointers to LPTSTRs in the list
+ POSITION pos = m_ptrlistStrings.GetHeadPosition();
+
+ while (pos != NULL)
+ {
+ // Memory deallocation fails if there's a null char
+ // at the end of the string.
+ LPTSTR psz = m_ptrlistStrings.GetNext(pos);
+ *(::_tcslen(psz) + psz) = (TCHAR)0xFD;
+ delete[] psz;
+ }
+
+ // Free all of the pointers to NETRESOURCE structs in the list
+ pos = m_ptrlistContainers.GetHeadPosition();
+
+ while (pos != NULL)
+ {
+ delete m_ptrlistContainers.GetNext(pos);
+ }
+}
+
+
+BEGIN_MESSAGE_MAP(CNetTreeCtrl, CTreeCtrl)
+ //{{AFX_MSG_MAP(CNetTreeCtrl)
+ ON_NOTIFY_REFLECT(TVN_ITEMEXPANDING, OnItemExpanding)
+ ON_WM_SETCURSOR()
+ ON_WM_DESTROY()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// Static member functions
+
+UINT CNetTreeCtrl::FillTree(LPVOID pParam)
+{
+ CEvent event(TRUE, TRUE, pszTreeEvent);
+ CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
+ PTREEINFO pti = (PTREEINFO)pParam;
+ CNetTreeCtrl* pTree = (CNetTreeCtrl*)pti->pTree;
+ BOOL bResult = FALSE;
+ DWORD dwEntries = 0xFFFFFFFF;
+ LPVOID lpvBuffer = NULL;
+ HANDLE hEnum = NULL;
+
+ // Because this function may call itself, keep a usage count
+ // so that pti is freed only when the first instance returns.
+ static USHORT uUsage = 0;
+
+ // Keep a handle to the heap in case the CNetTreeCtrl object
+ // goes away before the thread ends.
+ HANDLE hHeap = pTree->m_hHeap;
+ DWORD dwResult;
+ LPNETRESOURCE pnrRoot;
+ HTREEITEM hTreeItem, hTreeExpand;
+
+ hTreeItem = hTreeExpand = NULL;
+
+ try
+ {
+ // Unsignal the event object.
+ event.ResetEvent();
+
+ // Show the wait cursor
+ pTree->BeginWaitCursor();
+
+ // Exit if the handle to the heap is invalid.
+ if (hHeap == NULL)
+ goto ExitFunction;
+
+ if (pti->hTreeItem == TVI_ROOT)
+ {
+ pnrRoot = NULL;
+ if (pTree->m_imagelist.Create(IDB_NET_TREE, 16, 3, CNetTreeCtrl::IMG_MASK))
+ {
+ pTree->SetImageList(&(pTree->m_imagelist), TVSIL_NORMAL);
+ pTree->m_imagelist.SetBkColor(CLR_NONE);
+ }
+ }
+ else
+ pnrRoot = (LPNETRESOURCE)pTree->GetItemData(pti->hTreeItem);
+
+ // Get an enumeration handle.
+ if ((dwResult = ::WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_ANY,
+ RESOURCEUSAGE_CONTAINER, pnrRoot, &hEnum)) != NO_ERROR)
+ {
+ // Exit if WNetOpenEnum fails.
+ dwResult = ::GetLastError();
+ goto ExitFunction;
+ }
+
+ // Allocate a buffer for enumeration.
+ if ((lpvBuffer = ::HeapAlloc(hHeap, HEAP_ZERO_MEMORY, pti->dwBufSize)) == NULL)
+ // Exit if memory allocation failed
+ goto ExitFunction;
+
+ // Retrieve a block of network entries.
+ while ((dwResult = ::WNetEnumResource(hEnum, &dwEntries, lpvBuffer, &(pti->dwBufSize))) != ERROR_NO_MORE_ITEMS)
+ {
+ // See if it's time to exit.
+ if (pTree->m_bExitThread)
+ {
+ pTree->NotifyThread(FALSE);
+ bResult = TRUE;
+ goto ExitFunction;
+ }
+
+ // Exit if WNetEnumResource failed.
+ if (dwResult != NO_ERROR)
+ {
+ dwResult = ::GetLastError();
+ goto ExitFunction;
+ }
+
+ LPNETRESOURCE pnrLeaf = (LPNETRESOURCE)lpvBuffer;
+ TV_INSERTSTRUCT tviLeaf;
+
+ // Fill in the TV_INSERTSTRUCT members.
+ tviLeaf.hParent = pti->hTreeItem;
+ tviLeaf.hInsertAfter = TVI_SORT;
+ tviLeaf.item.hItem = NULL;
+ tviLeaf.item.state = 0;
+ tviLeaf.item.stateMask = 0;
+ tviLeaf.item.cchTextMax = 0;
+ tviLeaf.item.iSelectedImage = 0;
+
+ // Set the correct image for the leaf.
+ switch (pnrLeaf->dwDisplayType)
+ {
+ case RESOURCEDISPLAYTYPE_DOMAIN:
+ tviLeaf.item.iImage = tviLeaf.item.iSelectedImage = CNetTreeCtrl::IMG_DOMAIN;
+ break;
+
+ case RESOURCEDISPLAYTYPE_SERVER:
+ tviLeaf.item.iImage = tviLeaf.item.iSelectedImage = CNetTreeCtrl::IMG_SERVER;
+ break;
+
+ default:
+ tviLeaf.item.iImage = tviLeaf.item.iSelectedImage = CNetTreeCtrl::IMG_ROOT;
+ }
+
+ // Fool the tree into thinking that this leaf has children
+ // since we don't know initially.
+#if 0
+ if (pnrLeaf->dwDisplayType == RESOURCEDISPLAYTYPE_SERVER)
+#else
+ if (pnrLeaf->dwDisplayType == RESOURCEDISPLAYTYPE_DOMAIN ||
+ pnrLeaf->dwDisplayType == RESOURCEDISPLAYTYPE_SERVER)
+#endif
+ {
+ tviLeaf.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ tviLeaf.item.cChildren = 0;
+ }
+ else
+ {
+ tviLeaf.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_CHILDREN | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ tviLeaf.item.cChildren = 1;
+ }
+
+ // Add leaves to the branch.
+ for (DWORD i = 0; i < dwEntries; i++)
+ {
+ // See if it's time to exit.
+ if (pTree->m_bExitThread)
+ {
+ pTree->NotifyThread(FALSE);
+ bResult = TRUE;
+ goto ExitFunction;
+ }
+
+ // Create a permanent NETRESOURCE struct for later use.
+ LPNETRESOURCE pnrTemp = new NETRESOURCE;
+ pTree->m_ptrlistContainers.AddTail(pnrTemp);
+
+ ::CopyMemory(pnrTemp, pnrLeaf, sizeof(NETRESOURCE));
+
+ // Initialize members.
+ pnrTemp->lpLocalName = NULL;
+ pnrTemp->lpRemoteName = NULL;
+ pnrTemp->lpComment = NULL;
+ pnrTemp->lpProvider = NULL;
+
+ if (pnrLeaf->lpRemoteName != NULL)
+ {
+ pnrTemp->lpRemoteName = new TCHAR[::_tcslen(pnrLeaf->lpRemoteName) + 1];
+ ::_tcscpy(pnrTemp->lpRemoteName, pnrLeaf->lpRemoteName);
+ pTree->m_ptrlistStrings.AddTail(pnrTemp->lpRemoteName);
+ }
+
+ if (pnrLeaf->lpProvider != NULL)
+ {
+ pnrTemp->lpProvider = new TCHAR[::_tcslen(pnrLeaf->lpProvider) + 1];
+ ::_tcscpy(pnrTemp->lpProvider, pnrLeaf->lpProvider);
+ pTree->m_ptrlistStrings.AddTail(pnrTemp->lpProvider);
+ }
+
+ // Increment the buffer pointer.
+ pnrLeaf++;
+
+ // Use "Enterprise" as the item text if this is the root.
+ if (pti->hTreeItem == TVI_ROOT)
+ {
+ CString strRoot;
+
+ strRoot.LoadString(IDS_TREE_ROOT);
+ tviLeaf.item.pszText = new TCHAR[strRoot.GetLength() + 1];
+ ::_tcscpy(tviLeaf.item.pszText, (LPCTSTR)strRoot);
+ }
+ else if (pnrTemp->dwDisplayType == RESOURCEDISPLAYTYPE_SERVER)
+ {
+ // Skip the initial backslashes before adding the server
+ // name to the tree.
+ tviLeaf.item.pszText = pnrTemp->lpRemoteName + 2;
+ }
+ else
+ tviLeaf.item.pszText = pnrTemp->lpRemoteName;
+
+ tviLeaf.item.lParam = (LPARAM)(LPVOID)pnrTemp;
+
+ // Make sure the pointer to the tree control is still valid.
+ if (::IsWindow(pTree->m_hWnd))
+ {
+ hTreeItem = pTree->InsertItem(&tviLeaf);
+ }
+ else // Otherwise, exit the thread.
+ {
+ bResult = TRUE;
+ goto ExitFunction;
+ }
+
+ // Delete the string allocated for the root node text.
+ if (pti->hTreeItem == TVI_ROOT)
+ delete tviLeaf.item.pszText;
+
+ // See if the lpRemoteName member is equal to the default domain
+ // name.
+#if 0
+ if (!_tcscmp(pnrTemp->lpRemoteName, pApp->m_strDomain) ||
+#else
+ if (
+#endif
+ pti->hTreeItem == TVI_ROOT)
+ {
+ // Store the handle.
+ hTreeExpand = hTreeItem;
+ }
+
+ // Select the name of the license server in the tree.
+#if 0
+ if (!_tcsicmp(pnrTemp->lpRemoteName, pApp->m_strEnterpriseServer))
+#else
+ if (!_tcsicmp(pnrTemp->lpRemoteName, pApp->m_strDomain))
+#endif
+ {
+ pTree->SelectItem(hTreeItem);
+ pTree->EnsureVisible(hTreeItem);
+ pTree->SetFocus();
+ }
+ }
+
+ // Everything went all right.
+ bResult = TRUE;
+ }
+
+ // Expand the branch but only if it isn't the root.
+ // The root item thinks it has children, but really doesn't the first time through.
+ if (pti->hTreeItem != TVI_ROOT && pTree->ItemHasChildren(pti->hTreeItem))
+ {
+ // Indicate that the branch has been expanded once.
+ pTree->SetItemState(pti->hTreeItem, TVIS_EXPANDEDONCE, TVIS_EXPANDEDONCE);
+ pTree->Expand(pti->hTreeItem, TVE_EXPAND);
+ }
+
+ // Fill the branch for the current domain if the bExpand member is TRUE.
+ if (hTreeExpand != NULL && pti->bExpand)
+ {
+ TREEINFO ti;
+
+ ti.hTreeItem = hTreeExpand;
+ ti.dwBufSize = pti->dwBufSize;
+ ti.pTree = pti->pTree;
+ ti.bExpand = TRUE;
+
+ // Increment the usage count.
+ uUsage++;
+
+ FillTree((LPVOID)&ti);
+
+ // Decrement the usage count.
+ uUsage--;
+ }
+
+ ExitFunction:
+ // Display a message if an error occurred.
+ if (!bResult)
+ pTree->ErrorHandler(dwResult);
+
+ // Close the enumeration handle.
+ if (hEnum != NULL)
+ if (!(bResult = (::WNetCloseEnum(hEnum) == NO_ERROR)))
+ dwResult = ::GetLastError();
+
+ // Free memory allocated on the heap.
+ if (lpvBuffer != NULL)
+ ::HeapFree(hHeap, 0, lpvBuffer);
+
+ // Free the TREEINFO pointer only if the usage count is zero.
+ if (uUsage == 0)
+ delete pti;
+
+ // Reset the thread pointer.
+ pTree->m_pThread = NULL;
+
+ // Turn off the wait cursor
+ pTree->EndWaitCursor();
+
+ // Make sure the tree control still exists before posting a message.
+ if (::IsWindow(pTree->m_hWnd))
+ pTree->PostMessage(WM_SETCURSOR);
+
+ // Signal the event object.
+ if (uUsage == 0)
+ event.SetEvent();
+
+ return (UINT)!bResult;
+ }
+ catch(...)
+ {
+ // Close the enumeration handle.
+ if (hEnum != NULL)
+ if (!(bResult = (::WNetCloseEnum(hEnum) == NO_ERROR)))
+ dwResult = ::GetLastError();
+
+ // Free memory allocated on the heap.
+ if (lpvBuffer != NULL)
+ ::HeapFree(hHeap, 0, lpvBuffer);
+
+ // Free the TREEINFO pointer
+ delete pti;
+
+ // Reset the thread pointer.
+ pTree->m_pThread = NULL;
+
+ // Turn off the wait cursor
+ pTree->EndWaitCursor();
+
+ // Signal the event object.
+ event.SetEvent();
+
+ return (UINT)2;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CNetTreeCtrl member functions
+
+BOOL CNetTreeCtrl::PopulateTree(BOOL bExpand /* = TRUE */, const HTREEITEM hParentBranch /* = TVI_ROOT */,
+ DWORD dwBufSize /* = BUFFER_SIZE */)
+{
+ PTREEINFO pti = new TREEINFO;
+
+ pti->hTreeItem = hParentBranch;
+ pti->dwBufSize = dwBufSize;
+ pti->pTree = this;
+ pti->bExpand = bExpand;
+
+ // Don't begin a new thread until the last one has ended.
+ if (m_pThread != NULL)
+ {
+ NotifyThread(TRUE);
+
+ CEvent event(TRUE, TRUE, pszTreeEvent);
+ CSingleLock lock(&event);
+
+ // Wait.
+ lock.Lock();
+ }
+
+ m_pThread = AfxBeginThread((AFX_THREADPROC)FillTree, (LPVOID)pti);
+
+ return TRUE;
+}
+
+void CNetTreeCtrl::ErrorHandler(const DWORD dwCode)
+{
+ CString strError;
+ BOOL bNetError = FALSE;
+
+#ifdef _DEBUG
+ switch (dwCode)
+ {
+ case ERROR_MORE_DATA:
+ strError = "ERROR_MORE_DATA";
+ break;
+
+ case ERROR_INVALID_HANDLE:
+ strError = "ERROR_INVALID_HANDLE";
+ break;
+
+ case ERROR_NOT_CONTAINER:
+ strError = "ERROR_NOT_CONTAINER";
+ break;
+
+ case ERROR_INVALID_PARAMETER:
+ strError = "ERROR_INVALID_PARAMETER";
+ break;
+
+ case ERROR_NO_NETWORK:
+ strError = "ERROR_NO_NETWORK";
+ break;
+
+ case ERROR_EXTENDED_ERROR:
+ strError = "ERROR_EXTENDED_ERROR";
+ break;
+
+ default:
+ {
+#endif // _DEBUG
+ DWORD dwErrCode;
+ CString strErrDesc, strProvider;
+ LPTSTR pszErrDesc = strErrDesc.GetBuffer(MAX_STRING);
+ LPTSTR pszProvider = strProvider.GetBuffer(MAX_STRING);
+
+ if (::WNetGetLastError(&dwErrCode, pszErrDesc, MAX_STRING,
+ pszProvider, MAX_STRING) == NO_ERROR)
+ {
+ strErrDesc.ReleaseBuffer();
+ strProvider.ReleaseBuffer();
+
+ CString strErrMsg;
+
+ // Don't display the WNetGetLastError message if dwErrCode == 0.
+ if (dwErrCode)
+ {
+ // Trim of any leading or trailing white space.
+ strProvider.TrimRight();
+ strProvider.TrimLeft();
+ strErrDesc.TrimRight();
+ strErrDesc.TrimLeft();
+ strErrMsg.Format(IDS_NET_ERROR, strProvider, strErrDesc);
+ }
+ else
+ strErrMsg.LoadString(IDS_NET_NO_SERVERS);
+
+ MessageBox(strErrMsg, AfxGetAppName(), MB_OK | MB_ICONEXCLAMATION);
+
+ bNetError = TRUE;
+ }
+ else
+ strError.LoadString(IDS_ERROR);
+#ifdef _DEBUG
+ }
+ }
+#endif // _DEBUG
+
+ if (!bNetError)
+ AfxMessageBox(strError, MB_OK | MB_ICONEXCLAMATION);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CNetTreeCtrl functions
+
+void CNetTreeCtrl::NotifyThread(BOOL bExit)
+{
+ CCriticalSection cs;
+
+ if (cs.Lock())
+ {
+ m_bExitThread = bExit;
+ cs.Unlock();
+ }
+}
+
+void CNetTreeCtrl::PumpMessages()
+{
+ // Must call Create() before using the dialog
+ ASSERT(m_hWnd!=NULL);
+
+ MSG msg;
+
+ try
+ {
+ // Handle dialog messages
+ while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ if(!IsDialogMessage(&msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ }
+ catch(...)
+ {
+ TRACE(_T("Exception in CNetTreeCtrl::PumpMessages()\n"));
+ }
+
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CNetTreeCtrl message handlers
+
+void CNetTreeCtrl::OnItemExpanding(NMHDR* pNMHDR, LRESULT* pResult)
+{
+ NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
+
+ // Exit and stop expansion if the thread is running.
+ if (m_pThread != NULL)
+ {
+ *pResult = TRUE;
+ return;
+ }
+
+ // Exit if this branch has been expanded once.
+ if (!(pNMTreeView->itemNew.state & TVIS_EXPANDEDONCE))
+ {
+ // Add new leaves to the branch.
+ if (pNMTreeView->itemNew.mask & TVIF_HANDLE)
+ {
+ PopulateTree(FALSE, pNMTreeView->itemNew.hItem);
+ pNMTreeView->itemNew.mask |= TVIS_EXPANDEDONCE;
+ }
+ }
+
+ *pResult = FALSE;
+}
+
+BOOL CNetTreeCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
+{
+ CLicCompWizApp* pApp = (CLicCompWizApp*)AfxGetApp();
+
+ if (m_pThread == NULL && pApp->m_pLicenseThread == NULL)
+ {
+ return CTreeCtrl::OnSetCursor(pWnd, nHitTest, message);
+ }
+ else
+ {
+ // Restore the wait cursor if the thread is running.
+ RestoreWaitCursor();
+
+ return TRUE;
+ }
+}
+
+void CNetTreeCtrl::OnDestroy()
+{
+ NotifyThread(TRUE);
+ PumpMessages();
+
+ CTreeCtrl::OnDestroy();
+}
diff --git a/private/utils/wizards/liccomp/nettree.h b/private/utils/wizards/liccomp/nettree.h
new file mode 100644
index 000000000..b591926ce
--- /dev/null
+++ b/private/utils/wizards/liccomp/nettree.h
@@ -0,0 +1,77 @@
+// NetTree.h : header file
+//
+
+#include "lcwiz.h"
+
+/////////////////////////////////////////////////////////////////////////////
+// CNetTreeCtrl window
+
+class CNetTreeCtrl : public CTreeCtrl
+{
+// Construction
+public:
+ CNetTreeCtrl();
+ virtual ~CNetTreeCtrl();
+
+// Data members
+public:
+ enum
+ {
+ ROOT_LEVEL = 0x0,
+ DOMAIN_LEVEL = 0x1,
+ SERVER_LEVEL = 0x2,
+
+ BUFFER_SIZE = 0x4000,
+ MAX_STRING = 0x100,
+
+ IMG_ROOT = 0,
+ IMG_DOMAIN = 1,
+ IMG_SERVER = 2,
+
+ IMG_SIZE = 16,
+ IMG_GROW = 3,
+ IMG_MASK = RGB(0xFF, 0xFF, 0xFF)
+ };
+
+public:
+ HANDLE m_hHeap;
+ CImageList m_imagelist;
+ CTypedPtrList<CPtrList, LPNETRESOURCE> m_ptrlistContainers;
+ CTypedPtrList<CPtrList, LPTSTR> m_ptrlistStrings;
+ CWinThread* m_pThread;
+ CEvent m_event;
+ BOOL m_bExitThread;
+
+// Attributes
+public:
+
+// Operations
+public:
+ BOOL PopulateTree(BOOL bExpand= TRUE, const HTREEITEM hParentBranch = TVI_ROOT, DWORD dwBufSize = BUFFER_SIZE);
+ void ErrorHandler(const DWORD dwCode);
+ void NotifyThread(BOOL bExit);
+ static UINT FillTree(LPVOID pParam);
+
+protected:
+ void CNetTreeCtrl::PumpMessages();
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CNetTreeCtrl)
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+
+ // Generated message map functions
+protected:
+ //{{AFX_MSG(CNetTreeCtrl)
+ afx_msg void OnItemExpanding(NMHDR* pNMHDR, LRESULT* pResult);
+ afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
+ afx_msg void OnDestroy();
+ //}}AFX_MSG
+
+ DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/private/utils/wizards/liccomp/res/endflag.bmp b/private/utils/wizards/liccomp/res/endflag.bmp
new file mode 100644
index 000000000..549f1fb80
--- /dev/null
+++ b/private/utils/wizards/liccomp/res/endflag.bmp
Binary files differ
diff --git a/private/utils/wizards/liccomp/res/lcwiz.ico b/private/utils/wizards/liccomp/res/lcwiz.ico
new file mode 100644
index 000000000..16354aec5
--- /dev/null
+++ b/private/utils/wizards/liccomp/res/lcwiz.ico
Binary files differ
diff --git a/private/utils/wizards/liccomp/res/lcwiz.rc2 b/private/utils/wizards/liccomp/res/lcwiz.rc2
new file mode 100644
index 000000000..dde9879fd
--- /dev/null
+++ b/private/utils/wizards/liccomp/res/lcwiz.rc2
@@ -0,0 +1,13 @@
+//
+// LCWIZ.RC2 - resources Microsoft Visual C++ does not edit directly
+//
+
+#ifdef APSTUDIO_INVOKED
+ #error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Add manually edited resources here...
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/private/utils/wizards/liccomp/res/liccomp.bmp b/private/utils/wizards/liccomp/res/liccomp.bmp
new file mode 100644
index 000000000..b82c700ad
--- /dev/null
+++ b/private/utils/wizards/liccomp/res/liccomp.bmp
Binary files differ
diff --git a/private/utils/wizards/liccomp/res/net_tree.bmp b/private/utils/wizards/liccomp/res/net_tree.bmp
new file mode 100644
index 000000000..2c4827508
--- /dev/null
+++ b/private/utils/wizards/liccomp/res/net_tree.bmp
Binary files differ
diff --git a/private/utils/wizards/liccomp/resource.h b/private/utils/wizards/liccomp/resource.h
new file mode 100644
index 000000000..3342811a3
--- /dev/null
+++ b/private/utils/wizards/liccomp/resource.h
@@ -0,0 +1,84 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by LCWiz.rc
+//
+#define IDP_OLE_INIT_FAILED 100
+#define IDD_LCWIZ_DIALOG 102
+#define IDS_PROPSHT_CAPTION 103
+#define IDS_TEXT_PAGE1 104
+#define IDS_TEXT_PAGE2 105
+#define IDS_NET_ERROR 106
+#define IDS_NET_NO_SERVERS 107
+#define IDS_PRODUCTS 108
+#define IDS_LICENSES 109
+#define IDS_FONT 110
+#define IDS_FONT_BOLD 111
+#define IDS_UNLICENSED_PRODUCTS 112
+#define IDS_FMT_DATE 113
+#define IDS_NO_LICENSE_INFO 114
+#define IDS_NO_LICENSE_INFO_LOCAL 114
+#define IDS_DONE 115
+#define IDS_ERROR 116
+#define IDS_TREE_ROOT 117
+#define IDS_WORKING 118
+#define IDS_DOC_NAME 119
+#define IDS_PAGE_DATE 120
+#define IDS_PURCHASED 121
+#define IDS_USED 122
+#define IDS_PRODUCTS_LIST 123
+#define IDS_LICENSES_LIST 124
+#define IDS_ENUM_PRODUCTS 125
+#define IDS_WELCOME 126
+#define IDS_MEM_ERROR 127
+#define IDR_MAINFRAME 128
+#define IDS_NO_UNLICENSED_PRODUCTS 128
+#define IDD_PROPPAGE1 129
+#define IDS_ELLIPSIS 129
+#define IDD_PROPPAGE2 130
+#define IDS_SUBKEY 130
+#define IDD_PROPPAGE3 131
+#define IDS_REG_VALUE 131
+#define IDD_PROPPAGE4 132
+#define IDS_BAD_DOMAIN_NAME 132
+#define IDS_SERVER_UNAVAILABLE 133
+#define IDB_NET_TREE 134
+#define IDS_NO_LICENSE_INFO_REMOTE 134
+#define IDB_PAGE_ART 135
+#define IDS_ACCESS_DENIED 135
+#define IDS_GENERIC_ERROR 136
+#define IDS_REG_VALUE_USER 137
+#define IDS_REG_VALUE_DOMAIN 138
+#define IDS_DOMAIN_USER 139
+#define IDB_END_FLAG 140
+#define IDS_ADMIN 140
+#define IDS_LOCAL_ACCESS_DENIED 141
+#define IDS_UNAVAILABLE 142
+#define IDS_SERVER_UNAVAILABLE_LOCAL 143
+#define IDS_SPECIFY_DOMAIN 144
+#define IDS_BAD_VERSION 145
+#define IDC_PAINT_BOX 1000
+#define IDC_TEXT 1003
+#define IDC_TREE_NETWORK 1007
+#define IDC_CHECK_LOCAL_COMPUTER 1008
+#define IDC_EDIT_ENTERPRISE 1018
+#define IDC_LIST_PRODUCTS 1019
+#define IDC_TEXT_COMP_PRODUCTS 1023
+#define IDC_TEXT_UNCOMP_PRODUCTS 1024
+#define IDC_BUT_PRINT 1025
+#define IDC_RADIO_LOCAL_COMPUTER 1026
+#define IDC_RADIO_DOMAIN 1027
+#define IDC_TEXT_DOMAIN 1028
+#define IDC_TEXT_SELECT_DOMAIN 1029
+#define IDC_WELCOME 1031
+#define IDC_FLAG_BMP 1033
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 141
+#define _APS_NEXT_COMMAND_VALUE 32771
+#define _APS_NEXT_CONTROL_VALUE 1034
+#define _APS_NEXT_SYMED_VALUE 108
+#endif
+#endif
diff --git a/private/utils/wizards/liccomp/sources b/private/utils/wizards/liccomp/sources
new file mode 100644
index 000000000..cb980665a
--- /dev/null
+++ b/private/utils/wizards/liccomp/sources
@@ -0,0 +1,56 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+TARGETNAME=lcwiz
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+USE_MFCUNICODE=1
+
+PRECOMPILED_INCLUDE=stdafx.h
+PRECOMPILED_CXX=1
+
+SOURCES= LCWIZ.CPP \
+ LCWIZPGS.CPP \
+ LCWIZSHT.CPP \
+ NETTREE.CPP \
+ FINPIC.CPP \
+ TRANSBMP.CPP \
+ LCWIZ.RC
+
+
+UMTYPE=windows
+UMENTRY=wwinmain
+UMLIBS= $(BASEDIR)\public\sdk\lib\*\netapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\mpr.lib \
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\comdlg32.lib \
+ $(BASEDIR)\public\sdk\lib\*\comctl32.lib \
+ $(BASEDIR)\public\sdk\lib\*\shell32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\gdi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib \
+ $(BASEDIR)\public\sdk\lib\*\llsrpc.lib
+
diff --git a/private/utils/wizards/liccomp/stdafx.cpp b/private/utils/wizards/liccomp/stdafx.cpp
new file mode 100644
index 000000000..0ff2f2284
--- /dev/null
+++ b/private/utils/wizards/liccomp/stdafx.cpp
@@ -0,0 +1,6 @@
+// stdafx.cpp : source file that includes just the standard includes
+// LCWiz.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
diff --git a/private/utils/wizards/liccomp/stdafx.h b/private/utils/wizards/liccomp/stdafx.h
new file mode 100644
index 000000000..5cc5eace7
--- /dev/null
+++ b/private/utils/wizards/liccomp/stdafx.h
@@ -0,0 +1,27 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#ifdef ASSERT
+# undef ASSERT
+#endif
+#include <afxwin.h> // MFC core and standard components
+#include <afxext.h> // MFC extensions
+#include <afxdisp.h> // MFC OLE automation classes
+#ifndef _AFX_NO_AFXCMN_SUPPORT
+#include <afxcmn.h> // MFC support for Windows 95 Common Controls
+#endif // _AFX_NO_AFXCMN_SUPPORT
+#include <afxtempl.h> // MFC template classes
+#include <afxmt.h> // MFC synchronization classes
+#include <winnetwk.h>
+#include <llsapi.h>
+
+
+
+
diff --git a/private/utils/wizards/liccomp/transbmp.cpp b/private/utils/wizards/liccomp/transbmp.cpp
new file mode 100644
index 000000000..a16c3ac45
--- /dev/null
+++ b/private/utils/wizards/liccomp/transbmp.cpp
@@ -0,0 +1,161 @@
+// transbmp.cpp : implementation of the CTransBmp class
+//
+// support for transparent CBitmap objects. Used in the CUserList class.
+// Based on a class from MSDN 7/95
+#include "stdafx.h"
+#include "transbmp.h"
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char BASED_CODE THIS_FILE[] = __FILE__;
+#endif
+
+// Colors
+#define rgbWhite RGB(255,255,255)
+// Raster op codes
+#define DSa 0x008800C6L
+#define DSx 0x00660046L
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CTransBmp construction/destruction
+
+CTransBmp::CTransBmp()
+{
+ m_iWidth = 0;
+ m_iHeight = 0;
+ m_hbmMask = NULL;
+}
+
+CTransBmp::~CTransBmp()
+{
+ if (m_hbmMask != NULL) delete m_hbmMask;
+}
+
+void CTransBmp::GetMetrics()
+{
+ // Get the width and height
+ BITMAP bm;
+ GetObject(sizeof(bm), &bm);
+ m_iWidth = bm.bmWidth;
+ m_iHeight = bm.bmHeight;
+}
+
+
+int CTransBmp::GetWidth()
+{
+ if ((m_iWidth == 0) || (m_iHeight == 0)){
+ GetMetrics();
+ }
+ return m_iWidth;
+}
+
+int CTransBmp::GetHeight()
+{
+ if ((m_iWidth == 0) || (m_iHeight == 0)){
+ GetMetrics();
+ }
+ return m_iHeight;
+}
+
+
+void CTransBmp::CreateMask(CDC* pDC)
+{
+ m_hbmMask = new CBitmap;
+// Nuke any existing mask
+ if (m_hbmMask) m_hbmMask->DeleteObject();
+
+// Create memory DCs to work with
+ CDC* hdcMask = new CDC;
+ CDC* hdcImage = new CDC;
+
+ hdcMask->CreateCompatibleDC(pDC);
+ hdcImage->CreateCompatibleDC(pDC);
+
+// Create a monochrome bitmap for the mask
+ m_hbmMask->CreateBitmap(GetWidth(),
+ GetHeight(),
+ 1,
+ 1,
+ NULL);
+// Select the mono bitmap into its DC
+ CBitmap* hbmOldMask = hdcMask->SelectObject(m_hbmMask);
+// Select the image bitmap into its DC
+ CBitmap* hbmOldImage = hdcImage->SelectObject(CBitmap::FromHandle((HBITMAP)m_hObject));
+
+// Set the transparency color to be the top-left pixel
+ hdcImage->SetBkColor(hdcImage->GetPixel(0, 0));
+// Make the mask
+ hdcMask->BitBlt(0, 0,
+ GetWidth(), GetHeight(),
+ hdcImage,
+ 0, 0,
+ SRCCOPY);
+// clean up
+ hdcMask->SelectObject(hbmOldMask);
+ hdcImage->SelectObject(hbmOldImage);
+ delete hdcMask;
+ delete hdcImage;
+}
+
+// draw the transparent bitmap using the created mask
+void CTransBmp::DrawTrans(CDC* pDC, int x, int y)
+{
+ if (m_hbmMask == NULL) CreateMask(pDC);
+
+ int dx = GetWidth();
+ int dy = GetHeight();
+
+// Create a memory DC to do the drawing to
+ CDC* hdcOffScr = new CDC;
+ hdcOffScr->CreateCompatibleDC(pDC);
+
+// Create a bitmap for the off-screen DC that is really
+// color compatible with the destination DC.
+ CBitmap hbmOffScr;
+ hbmOffScr.CreateBitmap(dx, dy,
+ pDC->GetDeviceCaps(PLANES),
+ pDC->GetDeviceCaps(BITSPIXEL),
+ NULL);
+
+// Select the buffer bitmap into the off-screen DC
+ HBITMAP hbmOldOffScr = (HBITMAP)hdcOffScr->SelectObject(hbmOffScr);
+
+// Copy the image of the destination rectangle to the
+// off-screen buffer DC so we can play with it
+ hdcOffScr->BitBlt(0, 0, dx, dy, pDC, x, y, SRCCOPY);
+
+// Create a memory DC for the source image
+ CDC* hdcImage = new CDC;
+ hdcImage->CreateCompatibleDC(pDC);
+
+ CBitmap* hbmOldImage = hdcImage->SelectObject(CBitmap::FromHandle((HBITMAP)m_hObject));
+
+ // Create a memory DC for the mask
+ CDC* hdcMask = new CDC;
+ hdcMask->CreateCompatibleDC(pDC);
+
+ CBitmap* hbmOldMask = hdcMask->SelectObject(m_hbmMask);
+
+ // XOR the image with the destination
+ hdcOffScr->SetBkColor(rgbWhite);
+ hdcOffScr->BitBlt(0, 0, dx, dy ,hdcImage, 0, 0, DSx);
+ // AND the destination with the mask
+ hdcOffScr->BitBlt(0, 0, dx, dy, hdcMask, 0,0, DSa);
+ // XOR the destination with the image again
+ hdcOffScr->BitBlt(0, 0, dx, dy, hdcImage, 0, 0, DSx);
+
+ // Copy the resultant image back to the screen DC
+ pDC->BitBlt(x, y, dx, dy, hdcOffScr, 0, 0, SRCCOPY);
+
+ // Tidy up
+ hdcOffScr->SelectObject(hbmOldOffScr);
+ hdcImage->SelectObject(hbmOldImage);
+ hdcMask->SelectObject(hbmOldMask);
+
+ delete hdcOffScr;
+ delete hdcImage;
+ delete hdcMask;
+}
+
+
diff --git a/private/utils/wizards/liccomp/transbmp.h b/private/utils/wizards/liccomp/transbmp.h
new file mode 100644
index 000000000..a167ed16f
--- /dev/null
+++ b/private/utils/wizards/liccomp/transbmp.h
@@ -0,0 +1,28 @@
+// transbmp.h : interface of the CTransBitmap class
+//
+/////////////////////////////////////////////////////////////////////////////
+
+class CTransBmp : public CBitmap
+{
+public:
+ CTransBmp();
+ ~CTransBmp();
+ void Draw(HDC hDC, int x, int y);
+ void Draw(CDC* pDC, int x, int y);
+ void DrawTrans(HDC hDC, int x, int y);
+ void DrawTrans(CDC* pDC, int x, int y);
+ int GetWidth();
+ int GetHeight();
+
+private:
+ int m_iWidth;
+ int m_iHeight;
+ CBitmap* m_hbmMask; // handle to mask bitmap
+
+ void GetMetrics();
+ void CreateMask(HDC hDC);
+ void CreateMask(CDC* pDC);
+
+};
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/private/utils/wizards/shrpub/dirtree.cpp b/private/utils/wizards/shrpub/dirtree.cpp
new file mode 100644
index 000000000..1d98d3fd6
--- /dev/null
+++ b/private/utils/wizards/shrpub/dirtree.cpp
@@ -0,0 +1,261 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ DirTree.cpp : implementation file
+
+File History:
+
+ JonY Jan-96 created
+
+--*/
+
+#include "stdafx.h"
+#include "turtle.h"
+#include "resource.h"
+#include "DirTree.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CDirTree
+
+CDirTree::CDirTree()
+{
+// create the image list
+ m_pIList = new CImageList;
+
+ SHFILEINFO sfi;
+ HIMAGELIST hilSys = (HIMAGELIST)SHGetFileInfo(_T("."), 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
+
+ m_pIList->Attach(hilSys);
+ m_pIList->SetBkColor(CLR_NONE);
+}
+
+CDirTree::~CDirTree()
+{
+ m_pIList->Detach();
+ delete m_pIList;
+}
+
+
+BEGIN_MESSAGE_MAP(CDirTree, CTreeCtrl)
+ //{{AFX_MSG_MAP(CDirTree)
+ // NOTE - the ClassWizard will add and remove mapping macros here.
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CDirTree message handlers
+HTREEITEM CDirTree::AddBranch(HTREEITEM hItem, LPCTSTR lpPath, const TCHAR* lpText, long lParam)
+{
+ TCHAR* lpText2 = (TCHAR*)malloc((_tcslen(lpText) + 2) * sizeof(TCHAR));
+ if (lpText2 == NULL)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP);
+ exit(1);
+ }
+
+ _tcscpy(lpText2, lpText);
+
+ TV_INSERTSTRUCT TreeCtrlItem;
+
+ TreeCtrlItem.hParent = hItem;
+ TreeCtrlItem.hInsertAfter = TVI_LAST;
+ TreeCtrlItem.item.mask = TVIF_TEXT | TVIF_PARAM | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+
+ TreeCtrlItem.item.pszText = lpText2;
+ TreeCtrlItem.item.lParam = lParam;
+
+ IsShared(lpPath, &TreeCtrlItem.item);
+
+ HTREEITEM hNewItem;
+ if (hItem != NULL)
+ {
+ GetIconIndices(lpPath, &TreeCtrlItem.item.iImage, &TreeCtrlItem.item.iSelectedImage);
+
+ hNewItem = InsertItem(&TreeCtrlItem);
+ }
+ else
+ {
+// associate the image list with the tree
+ SetImageList(m_pIList, TVSIL_NORMAL);
+
+// add the root item
+ LPITEMIDLIST pPIDL;
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+ if (pApp->m_nShareType == 0)
+ SHGetSpecialFolderLocation(GetSafeHwnd(), CSIDL_DRIVES, &pPIDL);
+ else
+ SHGetSpecialFolderLocation(GetSafeHwnd(), CSIDL_NETWORK, &pPIDL);
+
+ SHFILEINFO sfi;
+ SHGetFileInfo((LPCTSTR)pPIDL, NULL, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX | SHGFI_PIDL | SHGFI_SMALLICON);
+ TreeCtrlItem.item.iImage = sfi.iIcon;
+
+ SHGetFileInfo((LPCTSTR)pPIDL, NULL, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX | SHGFI_PIDL | SHGFI_SMALLICON | SHGFI_SELECTED);
+ TreeCtrlItem.item.iSelectedImage = sfi.iIcon;
+
+ hNewItem = InsertItem(&TreeCtrlItem);
+ }
+ free(lpText2);
+ return hNewItem;
+}
+
+CString CDirTree::GetItemPath(HTREEITEM hItem)
+{
+ HTREEITEM hParent;
+ CString csParent;
+ hParent = GetParentItem(hItem);
+ if (hParent != NULL)
+ csParent = GetItemPath(hParent);
+ else return L"";
+
+ CString csText = GetItemText(hItem);
+ if (GetItemLParam(hItem) == 1L)
+ {
+ csText = csText.Left(3);
+ return csText;
+ }
+
+ csParent += csText;
+ int nImage;
+ GetItemImage(hItem, nImage, nImage);
+ csParent += "\\";
+
+ return csParent;
+}
+
+long CDirTree::GetItemLParam(HTREEITEM hItem)
+{
+ TV_ITEM tv;
+
+ tv.mask = TVIF_PARAM;
+ tv.hItem = hItem;
+
+ GetItem(&tv);
+ return tv.lParam;
+}
+
+CString CDirTree::GetCurrentDrive(HTREEITEM hItem)
+{
+ CString csDrive;
+ csDrive = GetItemPath(hItem);
+ csDrive = csDrive.Left(3);
+
+ return csDrive;
+}
+
+void CDirTree::GetIconIndices(LPCTSTR pszPathName, PINT piNormal, PINT piSelected)
+{
+ SHFILEINFO sfi;
+
+ // Get the index for the normal icon.
+ SHGetFileInfo(pszPathName, 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX | SHGFI_SMALLICON);
+ *piNormal = sfi.iIcon;
+
+ // Get the index for the selected icon.
+ SHGetFileInfo(pszPathName, 0, &sfi, sizeof(sfi), SHGFI_SYSICONINDEX | SHGFI_SMALLICON | SHGFI_OPENICON);
+ *piSelected = sfi.iIcon;
+}
+
+BOOL CDirTree::IsShared(LPCWSTR pszPathName, LPTV_ITEM ptvi /* = NULL */)
+{
+ BOOL bReturn = TRUE;
+ /*NET_API_STATUS status;
+ PSHARE_INFO_2 psi2;
+ DWORD dwType;
+ CString strPathName(pszPathName), strServer(""), strDevice("");
+
+ strPathName.TrimLeft();
+ strPathName.TrimRight();
+
+ if (strPathName.Find(_T("\\\\")) == 0)
+ {
+ int nPos = strPathName.ReverseFind('\\');
+
+ if (nPos != -1)
+ {
+ strServer = strPathName.Left(nPos);
+ strDevice = strPathName.Right(strPathName.GetLength() - nPos - 1);
+
+ status = NetShareGetInfo(const_cast<LPTSTR>((LPCTSTR)strServer),
+ const_cast<LPTSTR>((LPCTSTR)strDevice),
+ 2, (LPBYTE*)&psi2);
+ if (status == NERR_Success)
+ {
+ strDevice = psi2->shi2_path;
+ status = NetApiBufferFree((LPVOID)psi2);
+ }
+ }
+ }
+ else
+ {
+ strDevice = pszPathName;
+ }
+
+ status = NetShareCheck(const_cast<LPTSTR>((LPCTSTR)strServer), const_cast<LPTSTR>((LPCTSTR)strDevice), &dwType);
+
+ bReturn = (BOOL)(status == NERR_Success);
+
+ if (bReturn && ptvi != NULL)
+ {
+ ptvi->mask |= TVIF_STATE;
+ ptvi->stateMask = TVIS_OVERLAYMASK;
+ ptvi->state = INDEXTOOVERLAYMASK(1);
+ }
+
+ return bReturn;*/
+
+ /*HRESULT hr;
+ LPSHELLFOLDER pshf;
+
+ // Get an IShellFolder interface pointer.
+ hr = SHGetDesktopFolder(&pshf);
+
+ if (SUCCEEDED(hr))
+ {
+ LPITEMIDLIST pidl;
+ ULONG cbEaten, dwAttributes;
+
+ // Translate the pathname into a pidl.
+ hr = pshf->ParseDisplayName(GetParent()->m_hWnd, NULL, const_cast<LPWSTR>(pszPathName),
+ &cbEaten, &pidl, &dwAttributes);
+
+ if (SUCCEEDED(hr))
+ {
+ ULONG ulAttributes = SFGAO_HASSUBFOLDER | SFGAO_SHARE | SFGAO_REMOVABLE |SFGAO_FILESYSANCESTOR | SFGAO_FILESYSTEM | SFGAO_CAPABILITYMASK;
+
+ // Find out if the folder is shared.
+ hr = pshf->GetAttributesOf(1, (LPCITEMIDLIST*)&pidl, &ulAttributes);
+
+ if (SUCCEEDED(hr))
+ {
+ bReturn = (ulAttributes & SFGAO_SHARE);
+ }
+
+ LPMALLOC pMalloc;
+
+ // Get a pointer to the shell's IMalloc interface.
+ hr = SHGetMalloc(&pMalloc);
+
+ if (SUCCEEDED(hr))
+ {
+ // Free the pidl.
+ pMalloc->Free(pidl);
+ pMalloc->Release();
+ }
+ }
+
+ pshf->Release();
+ }*/
+
+ return bReturn;
+
+}
diff --git a/private/utils/wizards/shrpub/dirtree.h b/private/utils/wizards/shrpub/dirtree.h
new file mode 100644
index 000000000..33495e32e
--- /dev/null
+++ b/private/utils/wizards/shrpub/dirtree.h
@@ -0,0 +1,59 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ DirTree.h : header file
+
+File History:
+
+ JonY Jan-96 created
+
+--*/
+
+/////////////////////////////////////////////////////////////////////////////
+// CDirTree window
+
+class CDirTree : public CTreeCtrl
+{
+// Construction
+public:
+ CString GetItemPath(HTREEITEM hItem);
+ CDirTree();
+
+// Attributes
+public:
+
+// Operations
+public:
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CDirTree)
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CDirTree();
+ HTREEITEM AddBranch(HTREEITEM hItem, LPCTSTR lpPath, const TCHAR* lpText, long lParam);
+ CString GetCurrentDrive(HTREEITEM hItem);
+ void SetCurrentBranch(CString& csItem);
+ void GetIconIndices(LPCTSTR pszPathName, PINT piNormal, PINT piSelected);
+ BOOL IsShared(LPCWSTR pszPathName, LPTV_ITEM ptvi = NULL);
+
+ // Generated message map functions
+protected:
+ //{{AFX_MSG(CDirTree)
+ // NOTE - the ClassWizard will add and remove member functions here.
+ //}}AFX_MSG
+
+ DECLARE_MESSAGE_MAP()
+private:
+ CImageList* m_pIList;
+
+ HTREEITEM FindBranch(CString csItem, HTREEITEM hItem);
+ long GetItemLParam(HTREEITEM hItem);
+};
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/private/utils/wizards/shrpub/finish.cpp b/private/utils/wizards/shrpub/finish.cpp
new file mode 100644
index 000000000..4092d9150
--- /dev/null
+++ b/private/utils/wizards/shrpub/finish.cpp
@@ -0,0 +1,187 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Finish.cpp : implementation file
+
+// This class is the "Finish" screen. It calls the 'DoSharing' function in the application class
+// when the "finish" button is clicked.
+
+File History:
+
+ JonY Jan-96 created
+
+--*/
+
+#include "stdafx.h"
+#include "resource.h"
+#include "turtle.h"
+#include "WizBaseD.h"
+#include "transbmp.h"
+
+#include "Finish.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CFinish property page
+
+IMPLEMENT_DYNCREATE(CFinish, CWizBaseDlg)
+
+CFinish::CFinish() : CWizBaseDlg(CFinish::IDD)
+{
+ //{{AFX_DATA_INIT(CFinish)
+ m_csDirectoryName = _T("");
+ m_csShareName = _T("");
+ m_csStaticWhat = _T("");
+ //}}AFX_DATA_INIT
+}
+
+CFinish::~CFinish()
+{
+}
+
+void CFinish::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CFinish)
+ DDX_Text(pDX, IDC_DIRECTORY_NAME_STATIC, m_csDirectoryName);
+ DDX_Text(pDX, IDC_SHARE_NAME_STATIC, m_csShareName);
+ DDX_Text(pDX, IDC_STATIC_WHAT, m_csStaticWhat);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CFinish, CPropertyPage)
+ //{{AFX_MSG_MAP(CFinish)
+ ON_WM_PAINT()
+ ON_WM_SHOWWINDOW()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CFinish message handlers
+
+void CFinish::OnPaint()
+{
+ CPaintDC dc(this); // device context for painting
+
+ CTransBmp* pBitmap = new CTransBmp;
+ pBitmap->LoadBitmap(IDB_END_FLAG);
+
+ pBitmap->DrawTrans(&dc, 0,0);
+ delete pBitmap;
+
+}
+
+LRESULT CFinish::OnWizardBack()
+{
+ SetButtonAccess(PSWIZB_NEXT | PSWIZB_BACK);
+
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+ if (pApp->m_sMode == 1) return IDD_PERM_TYPE_DIALOG; // NTFS file
+ else if (pApp->m_sMode == 2)
+ {
+ if (pApp->m_bShareThis) return IDD_HOW_TO_SHARE_DLG; // FAT
+ else return IDD_WHAT_TO_SHARE_DLG;
+ }
+ else
+ {
+ if (pApp->m_bShareThis) return IDD_HOW_TO_SHARE_DLG; // NTFS
+ else return IDD_PERM_TYPE_DIALOG;
+ }
+
+ return CPropertyPage::OnWizardBack();
+
+}
+
+BOOL CFinish::OnWizardFinish()
+{
+ UINT uiMessage;
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+
+ if (pApp->DoSharing()) uiMessage = IDS_PUBLISH_ANOTHER;
+ else uiMessage = IDS_PUBLISH_ANOTHER_ERROR;
+
+ if (AfxMessageBox(uiMessage, MB_YESNO | MB_ICONEXCLAMATION) == IDYES)
+ {
+ SetButtonAccess(PSWIZB_NEXT | PSWIZB_BACK);
+ pApp->m_cps1.SetActivePage(0);
+ return FALSE;
+ }
+
+ return CPropertyPage::OnWizardFinish();
+}
+
+void CFinish::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CPropertyPage::OnShowWindow(bShow, nStatus);
+
+ CWnd* pStatic[3];
+ pStatic[0] = GetDlgItem(IDC_SERVICE_1);
+ pStatic[1] = GetDlgItem(IDC_SERVICE_2);
+ pStatic[2] = GetDlgItem(IDC_SERVICE_3);
+
+ if (bShow)
+ {
+ SetButtonAccess(PSWIZB_FINISH | PSWIZB_BACK);
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+
+// pApp->m_sMode (1 - NTFS file 2 - FAT vol 3 - NTFS vol)
+// m_bShareThis
+
+ if (pApp->m_bShareThis)
+ {
+ GetDlgItem(IDC_STATIC_AS)->ShowWindow(SW_SHOW);
+ GetDlgItem(IDC_SHARE_NAME_STATIC)->ShowWindow(SW_SHOW);
+ GetDlgItem(IDC_STATIC_WHO)->ShowWindow(SW_SHOW);
+
+
+ m_csStaticWhat.LoadString(IDS_FINISH_SETSHARE);
+ USHORT sCount = 0;
+ CString csText;
+ if (pApp->m_bGoSMB)
+ {
+ csText.LoadString(IDS_SMB);
+ pStatic[sCount]->SetWindowText((const TCHAR*)csText);
+ sCount++;
+ }
+
+ if (pApp->m_bGoFPNW)
+ {
+ csText.LoadString(IDS_FPNW);
+ pStatic[sCount]->SetWindowText((const TCHAR*)csText);
+ sCount++;
+ }
+
+ if (pApp->m_bGoSFM)
+ {
+ csText.LoadString(IDS_SFM);
+ pStatic[sCount]->SetWindowText((const TCHAR*)csText);
+ sCount++;
+ }
+ }
+ else
+ {
+ GetDlgItem(IDC_STATIC_AS)->ShowWindow(SW_HIDE);
+ GetDlgItem(IDC_SHARE_NAME_STATIC)->ShowWindow(SW_HIDE);
+ GetDlgItem(IDC_STATIC_WHO)->ShowWindow(SW_HIDE);
+ m_csStaticWhat.LoadString(IDS_FINISH_SET);
+ }
+
+
+ m_csDirectoryName = pApp->m_csSharePath;
+ m_csShareName = pApp->m_csShareName;
+
+ }
+ else SetButtonAccess(PSWIZB_NEXT | PSWIZB_BACK);
+ UpdateData(FALSE);
+
+}
+
diff --git a/private/utils/wizards/shrpub/finish.h b/private/utils/wizards/shrpub/finish.h
new file mode 100644
index 000000000..7691c8e3b
--- /dev/null
+++ b/private/utils/wizards/shrpub/finish.h
@@ -0,0 +1,55 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Finish.h : header file
+
+File History:
+
+ JonY Jan-96 created
+
+--*/
+
+/////////////////////////////////////////////////////////////////////////////
+// CFinish dialog
+
+class CFinish : public CWizBaseDlg
+{
+ DECLARE_DYNCREATE(CFinish)
+
+// Construction
+public:
+ CFinish();
+ ~CFinish();
+
+// Dialog Data
+ //{{AFX_DATA(CFinish)
+ enum { IDD = IDD_FINISH_DIALOG };
+ CString m_csDirectoryName;
+ CString m_csShareName;
+ CString m_csStaticWhat;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CFinish)
+ public:
+ virtual LRESULT OnWizardBack();
+ virtual BOOL OnWizardFinish();
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CFinish)
+ afx_msg void OnPaint();
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+};
diff --git a/private/utils/wizards/shrpub/fpnwapi.h b/private/utils/wizards/shrpub/fpnwapi.h
new file mode 100644
index 000000000..fd3f060ff
--- /dev/null
+++ b/private/utils/wizards/shrpub/fpnwapi.h
@@ -0,0 +1,349 @@
+/****************************************************************************
+* *
+* fpnwapi.h -- FPNW procedure declarations, constant definitions and macros *
+* *
+* Copyright (c) 1994-1995, Microsoft Corp. All rights reserved. *
+* *
+****************************************************************************/
+
+#ifndef _FPNWAPI_H_
+#define _FPNWAPI_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+//
+// Volume flags returned by VolumeGetInfo
+//
+
+#define FPNWVOL_TYPE_DISKTREE 0
+#define FPNWVOL_TYPE_CDROM 104
+#define FPNWVOL_TYPE_REMOVABLE 105
+
+//
+// Permissions flags returned in structure FPNWFILEINFO
+//
+
+#define FPNWFILE_PERM_NONE 0
+#define FPNWFILE_PERM_READ 0x01
+#define FPNWFILE_PERM_WRITE 0x02
+#define FPNWFILE_PERM_CREATE 0x04
+#define FPNWFILE_PERM_EXEC 0x08
+#define FPNWFILE_PERM_DELETE 0x10
+#define FPNWFILE_PERM_ATRIB 0x20
+#define FPNWFILE_PERM_PERM 0x40
+
+typedef BYTE FPNWSERVERADDR[12]; // Network address, first 4 bytes is
+ // the network number, and bytes
+ // 5-10 is the physical node
+ // address. The last two bytes are
+ // reserved.
+
+//
+// This is the level 1 structure for FpnwServerGetInfo & FpnwServerSetInfo.
+//
+
+typedef struct _FPNWServerInfo
+{
+ LPWSTR lpServerName; // Name of the server
+ DWORD dwNetwareMajorVersion; // Netware compatible major version num
+ DWORD dwNetwareMinorVersion; // Netware compatible minor version num
+ DWORD dwOSRevision; // OS revision number
+ DWORD dwMaxConnections; // Maximum number of connections
+ // supported
+ DWORD dwVolumes; // The current number of volumes on the
+ // server
+ DWORD dwLoggedOnUsers; // Number of current users logged on
+ DWORD dwConnectedWorkstations;// Number of workstations connected
+ DWORD dwOpenFiles; // Number of open files
+ DWORD dwFileLocks; // Number of file locks
+ FPNWSERVERADDR NetworkAddress; // Address consisting of network
+ // number (first 4 bytes) and the
+ // physical node address(bytes 5-10)
+ BOOL fEnableLogin; // TRUE if users are allowed to logged
+ // on, FALSE otherwise.
+ LPWSTR lpDescription; // Description of the server
+ LPWSTR lpHomeDirectory; // Path of the home directory
+
+} FPNWSERVERINFO, *PFPNWSERVERINFO;
+
+
+//
+// This is the level 1 structure for FpnwVolumeAdd, FpnwVolumeDel, FpnwVolumeEnum,
+// FpnwVolumeGetInfo, & FpnwVolumeSetInfo.
+//
+
+typedef struct _FPNWVolumeInfo
+{
+ LPWSTR lpVolumeName; // Name of the volume
+ DWORD dwType; // The type of the volume. It can be one of the
+ // following: FPNWVOL_TYPE_DISK, FPNWVOL_TYPE_PRINT
+ DWORD dwMaxUses; // Maximum number of connections that are
+ // allowed to the volume
+ DWORD dwCurrentUses; // Current number of connections to the volume
+ LPWSTR lpPath; // Path of the volume
+
+} FPNWVOLUMEINFO, *PFPNWVOLUMEINFO;
+
+
+//
+// This is the level 2 structure for FpnwVolumeAdd, FpnwVolumeDel, FpnwVolumeEnum,
+// FpnwVolumeGetInfo, & FpnwVolumeSetInfo.
+// Note that this is not supported on the FPNW beta.
+//
+
+typedef struct _FPNWVolumeInfo_2
+{
+ LPWSTR lpVolumeName; // Name of the volume
+ DWORD dwType; // The type of the volume. It can be one of the
+ // following: FPNWVOL_TYPE_DISK, FPNWVOL_TYPE_PRINT
+ DWORD dwMaxUses; // Maximum number of connections that are
+ // allowed to the volume
+ DWORD dwCurrentUses; // Current number of connections to the volume
+ LPWSTR lpPath; // Path of the volume
+
+ DWORD dwFileSecurityDescriptorLength; // reserved, this is calculated
+ PSECURITY_DESCRIPTOR FileSecurityDescriptor;
+
+} FPNWVOLUMEINFO_2, *PFPNWVOLUMEINFO_2;
+
+
+//
+// This is the level 1 structure for FpnwConnectionEnum.
+//
+
+typedef struct _FPNWConnectionInfo
+{
+ DWORD dwConnectionId; // Identification number for this connection
+ FPNWSERVERADDR WkstaAddress; // The workstation address which established
+ // the conn.
+ DWORD dwAddressType; // Address type: IP, IPX ...
+ LPWSTR lpUserName; // The name of the user which established
+ // the conn.
+ DWORD dwOpens; // Number of resources opened during this conn.
+ DWORD dwLogonTime; // Time this connection has been active
+ BOOL fLoggedOn; // TRUE if the user is logged on,FALSE otherwise
+ DWORD dwForcedLogoffTime; // Time left before forcing logoff
+ BOOL fAdministrator; // TRUE if the user is an administrator,
+ // FALSE otherwise
+
+} FPNWCONNECTIONINFO, *PFPNWCONNECTIONINFO;
+
+
+//
+// This is the level 1 structure for FpnwVolumeConnEnum.
+//
+
+typedef struct _FPNWVolumeConnectionInfo
+{
+ USHORT nDriveLetter; // Driver letter mapped to the volume by user
+ DWORD dwConnectionId; // Identification number for this connection
+ DWORD dwConnType; // The type of connection: FPNWVOL_TYPE_DISK,
+ // FPNWVOL_TYPE_PRINTER
+ DWORD dwOpens; // The number of open files on this connection.
+ DWORD dwTime; // Time this connection is active (or connected)
+ LPWSTR lpUserName; // The user who established the connection
+ LPWSTR lpConnectName; // The workstation address OR volume name based
+ // on the qualifier to FpnwConnectionEnum
+
+} FPNWVOLUMECONNINFO, *PFPNWVOLUMECONNINFO;
+
+
+//
+// This is the level 1 structure for FpnwFileEnum.
+//
+
+typedef struct _FPNWFileInfo
+{
+ DWORD dwFileId; // File identification number
+ LPWSTR lpPathName; // Full path name of this file
+ LPWSTR lpVolumeName; // Volume name this file is on
+ DWORD dwPermissions; // Permission mask: FPNWFILE_PERM_READ,
+ // FPNWFILE_PERM_WRITE,
+ // FPNWFILE_PERM_CREATE...
+ DWORD dwLocks; // Number of locks on this file
+ LPWSTR lpUserName; // The name of the user that established the
+ // connection and opened the file
+ FPNWSERVERADDR WkstaAddress; // The workstation address which opened the file
+ DWORD dwAddressType; // Address type: IP, IPX
+
+} FPNWFILEINFO, *PFPNWFILEINFO;
+
+
+//
+// Below are the APIs available to manipulate FPNW servers, volumes, etc.
+//
+
+//
+// The FpnwApiBufferFree should be called for any buffer returned by the
+// other APIs.
+//
+
+DWORD
+FpnwApiBufferFree(
+ IN LPVOID pBuffer
+);
+
+//
+// For Level 1, an FPNWSERVERINFO structure is returned in *ppServerInfo.
+//
+
+DWORD
+FpnwServerGetInfo(
+ IN LPWSTR pServerName OPTIONAL,
+ IN DWORD dwLevel,
+ OUT LPBYTE *ppServerInfo
+);
+
+
+//
+// The following fields are modified by a call to FpnwServerSetInfo :
+//
+// LPWSTR lpDescription; // Description of the server
+// BOOL fEnableLogin; // TRUE if users are allowed to logged
+// LPWSTR lpHomeDirectory; // Path of the home directory
+//
+// All other fields in FPNWSERVERINFO structure are ignored. Also note
+// that lpHomeDirectory and lpDescription require a restart for the server
+// to pick up the changes.
+//
+
+//
+// For Level 1, an FPNWSERVERINFO structure should be passed as pServerInfo.
+//
+
+DWORD
+FpnwServerSetInfo(
+ IN LPWSTR pServerName OPTIONAL,
+ IN DWORD dwLevel,
+ IN LPBYTE pServerInfo
+);
+
+
+//
+// For FpnwVolumeAdd, FpnwVolumeEnum, FpnwVolumeSetInfo, and
+// FpnwVolumeGetInfo, the following holds:
+// Level 1 -> an FPNWVOLUMEINFO structure should be passed as pVolumeInfo.
+// Level 2 -> an FPNWVOLUMEINFO_2 structure should be passed as pVolumeInfo.
+//
+
+DWORD
+FpnwVolumeAdd(
+ IN LPWSTR pServerName OPTIONAL,
+ IN DWORD dwLevel,
+ IN LPBYTE pVolumeInfo
+);
+
+DWORD
+FpnwVolumeDel(
+ IN LPWSTR pServerName OPTIONAL,
+ IN LPWSTR pVolumeName
+);
+
+DWORD
+FpnwVolumeEnum(
+ IN LPWSTR pServerName OPTIONAL,
+ IN DWORD dwLevel,
+ OUT LPBYTE *ppVolumeInfo,
+ OUT PDWORD pEntriesRead,
+ IN OUT PDWORD resumeHandle OPTIONAL
+);
+
+DWORD
+FpnwVolumeGetInfo(
+ IN LPWSTR pServerName OPTIONAL,
+ IN LPWSTR pVolumeName,
+ IN DWORD dwLevel,
+ OUT LPBYTE *ppVolumeInfo
+);
+
+
+//
+// The following fields are modified by a call to FpnwVolumeSetInfo :
+//
+// DWORD dwMaxUses; // Maximum number of connections that are
+// PSECURITY_DESCRIPTOR FileSecurityDescriptor;
+//
+// All other fields in FPNWVOLUMEINFO structure are ignored. You may send
+// in a pointer to an FPNWVOLUMEINFO_2 structure instead of FPNWVOLUMEINFO.
+//
+
+DWORD
+FpnwVolumeSetInfo(
+ IN LPWSTR pServerName OPTIONAL,
+ IN LPWSTR pVolumeName,
+ IN DWORD dwLevel,
+ IN LPBYTE pVolumeInfo
+);
+
+//
+// For Level 1, an FPNWCONNECTIONINFO structure is returned in *ppConnectionInfo.
+//
+
+DWORD
+FpnwConnectionEnum(
+ IN LPWSTR pServerName OPTIONAL,
+ IN DWORD dwLevel,
+ OUT LPBYTE *ppConnectionInfo,
+ OUT PDWORD pEntriesRead,
+ IN OUT PDWORD resumeHandle OPTIONAL
+);
+
+DWORD FpnwConnectionDel(
+ IN LPWSTR pServerName OPTIONAL,
+ IN DWORD dwConnectionId
+);
+
+
+//
+// For Level 1, an PFPNWVOLUMECONNINFO structure is returned in *ppVolumeConnInfo.
+//
+
+DWORD
+FpnwVolumeConnEnum(
+ IN LPWSTR pServerName OPTIONAL,
+ IN DWORD dwLevel,
+ IN LPWSTR pVolumeName,
+ IN DWORD dwConnectionId,
+ OUT LPBYTE *ppVolumeConnInfo,
+ OUT PDWORD pEntriesRead,
+ IN OUT PDWORD resumeHandle OPTIONAL
+);
+
+
+//
+// For Level 1, an PFPNWFILEINFO structure is returned in *ppFileInfo.
+//
+
+DWORD
+FpnwFileEnum(
+ IN LPWSTR pServerName OPTIONAL,
+ IN DWORD dwLevel,
+ IN LPWSTR pPathName OPTIONAL,
+ OUT LPBYTE *ppFileInfo,
+ OUT PDWORD pEntriesRead,
+ IN OUT PDWORD resumeHandle OPTIONAL
+);
+
+DWORD
+FpnwFileClose(
+ IN LPWSTR pServerName OPTIONAL,
+ IN DWORD nFileId
+);
+
+
+DWORD FpnwMessageBufferSend(
+ IN LPWSTR pServerName OPTIONAL,
+ IN DWORD dwConnectionId,
+ IN DWORD fConsoleBroadcast,
+ IN LPBYTE pbBuffer,
+ IN DWORD cbBuffer
+);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
+
diff --git a/private/utils/wizards/shrpub/howtoshd.cpp b/private/utils/wizards/shrpub/howtoshd.cpp
new file mode 100644
index 000000000..04fc00375
--- /dev/null
+++ b/private/utils/wizards/shrpub/howtoshd.cpp
@@ -0,0 +1,283 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ HowToShD.cpp : implementation file
+
+ // Depending on what DLLs are found, ask the user what
+// directory services to share through
+
+File History:
+
+ JonY Jan-96 created
+
+--*/
+
+#include "stdafx.h"
+#include "turtle.h"
+#include "resource.h"
+#include "WizBaseD.h"
+#include "HowToShD.h"
+
+#include "macfile.h"
+#include "fpnwapi.h"
+
+#include <winreg.h>
+#include <lmcons.h>
+#include <lmshare.h>
+#include <lmerr.h>
+#include <lmserver.h>
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+typedef DWORD (CALLBACK *AFPADMINCONNECT)(LPTSTR, PAFP_SERVER_HANDLE);
+typedef VOID (CALLBACK *AFPADMINDISCONNECT)(AFP_SERVER_HANDLE);
+typedef DWORD (CALLBACK *AFPADMINVOLUMEGETINFO)(AFP_SERVER_HANDLE, LPWSTR, LPBYTE*);
+
+typedef DWORD (CALLBACK *FPNWVOLUMEGETINFO) (LPWSTR, LPWSTR, DWORD, LPBYTE*);
+
+/////////////////////////////////////////////////////////////////////////////
+// CHowToShareDlg property page
+
+IMPLEMENT_DYNCREATE(CHowToShareDlg, CWizBaseDlg)
+
+CHowToShareDlg::CHowToShareDlg() : CWizBaseDlg(CHowToShareDlg::IDD)
+{
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+
+ //{{AFX_DATA_INIT(CHowToShareDlg)
+ m_bFPNWCheck = FALSE;
+ m_bSFMCheck = FALSE;
+ m_bSMBCheck = TRUE;
+ m_csShareComment = _T("");
+ m_csShareName = _T("");
+ m_csFolderName = _T("");
+ //}}AFX_DATA_INIT
+}
+
+CHowToShareDlg::~CHowToShareDlg()
+{
+}
+
+void CHowToShareDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CHowToShareDlg)
+ DDX_Check(pDX, IDC_FPNW_CHECK, m_bFPNWCheck);
+ DDX_Check(pDX, IDC_SFM_CHECK, m_bSFMCheck);
+ DDX_Check(pDX, IDC_SMB_CHECK, m_bSMBCheck);
+ DDX_Text(pDX, IDC_SHARE_COMMENT, m_csShareComment);
+ DDX_Text(pDX, IDC_SHARE_NAME_EDIT, m_csShareName);
+ DDX_Text(pDX, IDC_FOLDERNAME_EDIT, m_csFolderName);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CHowToShareDlg, CPropertyPage)
+ //{{AFX_MSG_MAP(CHowToShareDlg)
+ ON_WM_SHOWWINDOW()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CHowToShareDlg message handlers
+BOOL CHowToShareDlg::OnInitDialog()
+{
+ CPropertyPage::OnInitDialog();
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+// store the results of the selections in the application class
+LRESULT CHowToShareDlg::OnWizardNext()
+{
+// first make sure this share name is unique
+ UpdateData(TRUE);
+
+ if (m_csShareName.GetLength() == 0)
+ {
+ DoMessageBox(IDS_SHARE_NAME_BLANK);
+ GetDlgItem(IDC_SHARE_NAME)->SetFocus();
+ return -1;
+ }
+
+ if (m_csShareName.GetLength() > 12)
+ {
+ CString csTemp;
+ csTemp.Format(IDS_SHARE_NAME_TOO_LONG, m_csShareName);
+ AfxMessageBox(csTemp);
+
+ /*if (AfxMessageBox(csTemp, MB_YESNO) != IDYES) */return -1;
+ }
+
+// check share name for invalid characters
+ if (m_csShareName.FindOneOf(_T(",<>/?';:\\\"]}[{|+=")) != -1)
+ {
+ DoMessageBox(IDS_INVALID_SHARE_NAME);
+ GetDlgItem(IDC_SHARE_NAME)->SetFocus();
+ return -1;
+ }
+
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+
+ pApp->m_csShareName = m_csShareName;
+ TCHAR* pServer = (TCHAR*)pApp->m_csRemoteServer.GetBuffer(pApp->m_csRemoteServer.GetLength());
+ pApp->m_csRemoteServer.ReleaseBuffer();
+ TCHAR* pShare = (TCHAR*)pApp->m_csShareName.GetBuffer(pApp->m_csShareName.GetLength());
+ pApp->m_csShareName.ReleaseBuffer();
+
+ pApp->m_csShareComment = m_csShareComment;
+
+///SMB
+ if (m_bSMBCheck)
+ {
+ SHARE_INFO_0* pInfo;
+ NET_API_STATUS nApi = NetShareGetInfo(pServer,
+ pShare,
+ 0,
+ (LPBYTE*)&pInfo);
+
+ if (nApi == NERR_Success)
+ {
+ DoMessageBox(IDS_GENERIC_VOLUME_NOT_UNIQUE);
+ GetDlgItem(IDC_SHARE_NAME_EDIT)->SetFocus();
+ return -1;
+ }
+ }
+///SFM
+ if (m_bSFMCheck)
+ {
+ HINSTANCE hSFMLib = LoadLibrary(TEXT("sfmapi.dll"));
+ if (hSFMLib == NULL)
+ {
+ AfxMessageBox(IDS_NO_SFM, MB_ICONSTOP);
+ m_bSFMCheck = FALSE;
+ }
+ else
+ {
+ AFPADMINCONNECT pAfpAdminConnect = (AFPADMINCONNECT) GetProcAddress(hSFMLib, "AfpAdminConnect");
+// get an SFM server handle
+ AFP_SERVER_HANDLE hAfpServerHandle;
+ DWORD dwRetCode = (*pAfpAdminConnect)(pServer, &hAfpServerHandle);
+
+ AFPADMINVOLUMEGETINFO pAfpAdminVolumeGetInfo = (AFPADMINVOLUMEGETINFO) GetProcAddress(hSFMLib, "AfpAdminVolumeGetInfo");
+ PAFP_VOLUME_INFO pSFMShareInfo2;
+ dwRetCode = (*pAfpAdminVolumeGetInfo)(hAfpServerHandle, pShare, (LPBYTE*)&pSFMShareInfo2);
+
+ AFPADMINDISCONNECT pAfpAdminDisconnect = (AFPADMINDISCONNECT) GetProcAddress(hSFMLib, "AfpAdminDisconnect");
+ (*pAfpAdminDisconnect)(hAfpServerHandle);
+
+ FreeLibrary(hSFMLib);
+
+ if (dwRetCode == 0L)
+ {
+ DoMessageBox(IDS_GENERIC_VOLUME_NOT_UNIQUE);
+ GetDlgItem(IDC_SHARE_NAME_EDIT)->SetFocus();
+ return -1;
+ }
+ }
+ }
+
+ //FPNW
+ if (m_bFPNWCheck)
+ {
+ HINSTANCE hFPNWLib = LoadLibrary(TEXT("fpnwclnt.dll"));
+ if (hFPNWLib == NULL)
+ {
+ AfxMessageBox(IDS_NO_FPNW, MB_ICONSTOP);
+ m_bFPNWCheck = FALSE;
+ }
+ else
+ {
+ FPNWVOLUMEGETINFO pFPNWVolumeGetInfo = (FPNWVOLUMEGETINFO)GetProcAddress(hFPNWLib, "FpnwVolumeGetInfo");
+ FPNWVOLUMEINFO* pFPNWShareInfo2;
+ DWORD dwRetCode = (*pFPNWVolumeGetInfo)(pServer,
+ pShare,
+ 1,
+ (LPBYTE*)&pFPNWShareInfo2);
+
+ FreeLibrary(hFPNWLib);
+ if (dwRetCode == 0)
+ {
+ DoMessageBox(IDS_GENERIC_VOLUME_NOT_UNIQUE);
+ GetDlgItem(IDC_SHARE_NAME_EDIT)->SetFocus();
+ return -1;
+ }
+ }
+ }
+
+ pApp->m_bGoFPNW = m_bFPNWCheck;
+ pApp->m_bGoSFM = m_bSFMCheck;
+ pApp->m_bGoSMB = m_bSMBCheck;
+
+ SetButtonAccess(PSWIZB_NEXT | PSWIZB_BACK);
+
+// nothing was checked?
+ if ((!m_bSMBCheck) && (!m_bSFMCheck) && (!m_bFPNWCheck))
+ {
+ DoMessageBox(IDS_GENERIC_INDICATE_SERVICE);
+ return -1;
+ }
+
+// where to? depends on the file system
+ if (pApp->m_sMode == 3) // NTFS
+ return IDD_FINISH_DIALOG;
+ else return IDD_PERM_TYPE_DIALOG; // FAT
+
+}
+
+// enable the FPNW and SFM check boxes if the support DLLs are found
+void CHowToShareDlg::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CPropertyPage::OnShowWindow(bShow, nStatus);
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+// get defaults from the app
+ m_bFPNWCheck = pApp->m_bGoFPNW;
+ m_bSFMCheck = pApp->m_bGoSFM;
+ m_bSMBCheck = pApp->m_bGoSMB;
+
+ m_csFolderName = pApp->m_csSharePath;
+ m_csShareName = m_csFolderName.Right(m_csFolderName.GetLength() - (m_csFolderName.ReverseFind('\\') + 1));
+ UpdateData(FALSE);
+
+ if (bShow)
+ {
+ if ((!pApp->m_bPermitSMB) && (!pApp->m_bPermitSFM) && (!pApp->m_bPermitFPNW))
+ AfxMessageBox(IDS_ALL_SERVICES_USED);
+
+ TCHAR* pServer = (TCHAR*)pApp->m_csRemoteServer.GetBuffer(pApp->m_csRemoteServer.GetLength());
+ pApp->m_csRemoteServer.ReleaseBuffer();
+
+ SERVER_INFO_102* pInfo;
+ NET_API_STATUS nApi = NetServerGetInfo(pServer,
+ 102,
+ (LPBYTE*)&pInfo);
+
+ if (pInfo->sv102_type & SV_TYPE_AFP) GetDlgItem(IDC_SFM_CHECK)->EnableWindow(pApp->m_bPermitSFM);
+ if (pInfo->sv102_type & SV_TYPE_SERVER_MFPN) GetDlgItem(IDC_FPNW_CHECK)->EnableWindow(pApp->m_bPermitFPNW);
+
+ GetDlgItem(IDC_SMB_CHECK)->EnableWindow(pApp->m_bPermitSMB);
+ }
+ else
+ {
+ GetDlgItem(IDC_SFM_CHECK)->EnableWindow(FALSE);
+ GetDlgItem(IDC_FPNW_CHECK)->EnableWindow(FALSE);
+ GetDlgItem(IDC_SMB_CHECK)->EnableWindow(FALSE);
+ }
+
+}
+
+LRESULT CHowToShareDlg::OnWizardBack()
+{
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+
+ if (pApp->m_sMode == 2) return IDD_WHAT_TO_SHARE_DLG; // FAT
+ else return IDD_PERM_TYPE_DIALOG; // NTFS
+
+}
diff --git a/private/utils/wizards/shrpub/howtoshd.h b/private/utils/wizards/shrpub/howtoshd.h
new file mode 100644
index 000000000..e81d087b5
--- /dev/null
+++ b/private/utils/wizards/shrpub/howtoshd.h
@@ -0,0 +1,60 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ HowToShD.h : header file
+
+File History:
+
+ JonY Jan-96 created
+
+--*/
+
+
+//
+
+/////////////////////////////////////////////////////////////////////////////
+// CHowToShareDlg dialog
+
+class CHowToShareDlg : public CWizBaseDlg
+{
+ DECLARE_DYNCREATE(CHowToShareDlg)
+
+// Construction
+public:
+ CHowToShareDlg();
+ ~CHowToShareDlg();
+
+// Dialog Data
+ //{{AFX_DATA(CHowToShareDlg)
+ enum { IDD = IDD_HOW_TO_SHARE_DLG };
+ BOOL m_bFPNWCheck;
+ BOOL m_bSFMCheck;
+ BOOL m_bSMBCheck;
+ CString m_csShareComment;
+ CString m_csShareName;
+ CString m_csFolderName;
+ //}}AFX_DATA
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CHowToShareDlg)
+ public:
+ virtual LRESULT OnWizardNext();
+ virtual LRESULT OnWizardBack();
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CHowToShareDlg)
+ virtual BOOL OnInitDialog();
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+};
diff --git a/private/utils/wizards/shrpub/macfile.h b/private/utils/wizards/shrpub/macfile.h
new file mode 100644
index 000000000..411542fbc
--- /dev/null
+++ b/private/utils/wizards/shrpub/macfile.h
@@ -0,0 +1,908 @@
+/*
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ macfile.h
+
+Abstract:
+
+ This module contains data structures, related constants and functions,
+ error retuen codes and prototypes of AfpAdminxxx APIs. This file should
+ be included by any application that will administer the MACFILE service.
+
+Author:
+
+ Narendra Gidwani (microsoft!nareng)
+
+
+Revision History:
+ 12 Jume 1992 NarenG Initial version. Split admin.h into admin.h
+ and macfile.h.
+--*/
+
+#ifndef _MACFILE_
+#define _MACFILE_
+
+// Used as RPC binding handle to server
+
+typedef ULONG AFP_SERVER_HANDLE;
+typedef ULONG *PAFP_SERVER_HANDLE;
+
+#define AFP_SERVICE_NAME TEXT("MacFile")
+
+// Error return values from AfpAdminxxx Api's
+// WARNING! If you change any any codes below, please change
+// afpmgr.h accoringly.
+
+#define AFPERR_BASE -6000
+
+#define AFPERR_InvalidVolumeName (AFPERR_BASE-1)
+#define AFPERR_InvalidId (AFPERR_BASE-2)
+#define AFPERR_InvalidParms (AFPERR_BASE-3)
+#define AFPERR_CodePage (AFPERR_BASE-4)
+#define AFPERR_InvalidServerName (AFPERR_BASE-5)
+#define AFPERR_DuplicateVolume (AFPERR_BASE-6)
+#define AFPERR_VolumeBusy (AFPERR_BASE-7)
+#define AFPERR_VolumeReadOnly (AFPERR_BASE-8)
+#define AFPERR_DirectoryNotInVolume (AFPERR_BASE-9)
+#define AFPERR_SecurityNotSupported (AFPERR_BASE-10)
+#define AFPERR_BufferSize (AFPERR_BASE-11)
+#define AFPERR_DuplicateExtension (AFPERR_BASE-12)
+#define AFPERR_UnsupportedFS (AFPERR_BASE-13)
+#define AFPERR_InvalidSessionType (AFPERR_BASE-14)
+#define AFPERR_InvalidServerState (AFPERR_BASE-15)
+#define AFPERR_NestedVolume (AFPERR_BASE-16)
+#define AFPERR_InvalidComputername (AFPERR_BASE-17)
+#define AFPERR_DuplicateTypeCreator (AFPERR_BASE-18)
+#define AFPERR_TypeCreatorNotExistant (AFPERR_BASE-19)
+#define AFPERR_CannotDeleteDefaultTC (AFPERR_BASE-20)
+#define AFPERR_CannotEditDefaultTC (AFPERR_BASE-21)
+#define AFPERR_InvalidTypeCreator (AFPERR_BASE-22)
+#define AFPERR_InvalidExtension (AFPERR_BASE-23)
+#define AFPERR_TooManyEtcMaps (AFPERR_BASE-24)
+#define AFPERR_InvalidPassword (AFPERR_BASE-25)
+#define AFPERR_VolumeNonExist (AFPERR_BASE-26)
+#define AFPERR_NoSuchUserGroup (AFPERR_BASE-27)
+#define AFPERR_NoSuchUser (AFPERR_BASE-28)
+#define AFPERR_NoSuchGroup (AFPERR_BASE-29)
+
+#define AFPERR_MIN AFPERR_NoSuchGroup
+
+// Constants related to the following data strucutures.
+
+#define AFP_SERVERNAME_LEN 31
+#define AFP_VOLNAME_LEN 27
+#define AFP_VOLPASS_LEN 8
+#define AFP_WKSTANAME_LEN 65
+#define AFP_EXTENSION_LEN 3
+#define AFP_CREATOR_LEN 4
+#define AFP_TYPE_LEN 4
+#define AFP_MESSAGE_LEN 199
+#define AFP_MAXICONSIZE 2048
+#define AFP_MAXSESSIONS 0XFFFFFFFF
+#define AFP_ETC_COMMENT_LEN 29
+
+
+// Relative paths to registry keys that contain information for the macfile
+// server.
+
+#define AFP_KEYPATH_SERVER_PARAMS \
+ TEXT("SYSTEM\\CurrentControlSet\\Services\\MacFile\\PARAMETERS")
+
+#define AFP_KEYPATH_VOLUMES \
+ TEXT("SYSTEM\\CurrentControlSet\\Services\\MacFile\\PARAMETERS\\VOLUMES")
+
+#define AFP_KEYPATH_TYPE_CREATORS \
+ TEXT("SYSTEM\\CurrentControlSet\\Services\\MacFile\\PARAMETERS\\TYPE_CREATORS")
+
+#define AFP_KEYPATH_EXTENSIONS \
+ TEXT("SYSTEM\\CurrentControlSet\\Services\\MacFile\\PARAMETERS\\EXTENSIONS")
+
+#define AFP_KEYPATH_ICONS \
+ TEXT("SYSTEM\\CurrentControlSet\\Services\\MacFile\\PARAMETERS\\ICONS")
+
+#define AFP_KEYPATH_CODEPAGE \
+ TEXT("SYSTEM\\CurrentControlSet\\Control\\Nls\\Codepage")
+
+// Value names for server parameters
+
+#define AFPREG_VALNAME_SVRNAME TEXT("ServerName")
+#define AFPREG_VALNAME_SRVOPTIONS TEXT("ServerOptions")
+#define AFPREG_VALNAME_MAXSESSIONS TEXT("MaxSessions")
+#define AFPREG_VALNAME_LOGINMSG TEXT("LoginMsg")
+#define AFPREG_VALNAME_MAXPAGEDMEM TEXT("PagedMemLimit")
+#define AFPREG_VALNAME_MAXNONPAGEDMEM TEXT("NonPagedMemLimit")
+#define AFPREG_VALNAME_TYPE TEXT("Type")
+#define AFPREG_VALNAME_CREATOR TEXT("Creator")
+#define AFPREG_VALNAME_COMMENT TEXT("Comment")
+#define AFPREG_VALNAME_PASSWORD TEXT("Password")
+#define AFPREG_VALNAME_MAXUSES TEXT("MaxUses")
+#define AFPREG_VALNAME_PROPS TEXT("Properties")
+#define AFPREG_VALNAME_PATH TEXT("Path")
+#define AFPREG_VALNAME_ID TEXT("Id")
+#define AFPREG_VALNAME_ICONTYPE TEXT("IconType")
+#define AFPREG_VALNAME_DATA TEXT("Data")
+#define AFPREG_VALNAME_LENGTH TEXT("Length")
+#define AFPREG_VALNAME_CODEPAGE TEXT("MACCP")
+
+// Limits on server parameters
+
+#define AFP_MAX_ALLOWED_SRV_SESSIONS AFP_MAXSESSIONS
+#define AFP_MIN_ALLOWED_PAGED_MEM 1000
+#define AFP_MAX_ALLOWED_PAGED_MEM 256000
+#define AFP_MIN_ALLOWED_NONPAGED_MEM 256
+#define AFP_MAX_ALLOWED_NONPAGED_MEM 16000
+
+// Server default parameter values
+
+#define AFP_DEF_SRVOPTIONS (AFP_SRVROPT_GUESTLOGONALLOWED)
+#define AFP_DEF_MAXSESSIONS AFP_MAXSESSIONS
+#define AFP_DEF_TYPE TEXT("TEXT")
+#define AFP_DEF_CREATOR TEXT("LMAN")
+#define AFP_DEF_EXTENSION_W L"*"
+#define AFP_DEF_EXTENSION_A "*"
+#define AFP_DEF_TCID 0
+#define AFP_DEF_MAXPAGEDMEM 20000
+#define AFP_DEF_MAXNONPAGEDMEM 4000
+#define AFP_DEF_CODEPAGE_PATH TEXT("C:\\NT\\SYSTEM32\\C_10000.NLS")
+
+// Will be concatenated to the system path to form source path of volume icon
+#define AFP_DEF_VOLICON_SRCNAME TEXT("\\SFMICON.VOL")
+
+// Server options
+
+#define AFP_SRVROPT_NONE 0x0000
+#define AFP_SRVROPT_GUESTLOGONALLOWED 0x0001
+#define AFP_SRVROPT_CLEARTEXTLOGONALLOWED 0x0002
+#define AFP_SRVROPT_ALLOWSAVEDPASSWORD 0x0004
+#define AFP_SRVROPT_STANDALONE 0x0008
+#define AFP_SRVROPT_4GB_VOLUMES 0x0010
+#define AFP_SRVROPT_ALL ( AFP_SRVROPT_GUESTLOGONALLOWED \
+ | AFP_SRVROPT_CLEARTEXTLOGONALLOWED \
+ | AFP_SRVROPT_ALLOWSAVEDPASSWORD \
+ | AFP_SRVROPT_4GB_VOLUMES \
+ | AFP_SRVROPT_STANDALONE )
+
+// AFP Service default parameters
+
+
+#define AFP_SERVER_PARMNUM_LOGINMSG 0x00000001
+#define AFP_SERVER_PARMNUM_MAX_SESSIONS 0x00000002
+#define AFP_SERVER_PARMNUM_OPTIONS 0x00000004
+#define AFP_SERVER_PARMNUM_NAME 0x00000008
+#define AFP_SERVER_PARMNUM_PAGEMEMLIM 0x00000010
+#define AFP_SERVER_PARMNUM_NONPAGEMEMLIM 0x00000020
+#define AFP_SERVER_PARMNUM_CODEPAGE 0x00000040
+#define AFP_SERVER_PARMNUM_ALL ( AFP_SERVER_PARMNUM_LOGINMSG \
+ | AFP_SERVER_PARMNUM_MAX_SESSIONS \
+ | AFP_SERVER_PARMNUM_OPTIONS \
+ | AFP_SERVER_PARMNUM_NAME \
+ | AFP_SERVER_PARMNUM_PAGEMEMLIM \
+ | AFP_SERVER_PARMNUM_NONPAGEMEMLIM \
+ | AFP_SERVER_PARMNUM_CODEPAGE)
+
+typedef struct _AFP_SERVER_INFO
+{
+ LPWSTR afpsrv_name; // Macintosh name of the server
+ // max. AFP_SERVERNAME_LEN.
+ DWORD afpsrv_max_sessions; // Maximum simultaneous sessions
+ // In the range 1 - AFP_MAXSESSIONS.
+ // 0 is invalid
+ DWORD afpsrv_options; // Server Options
+ DWORD afpsrv_max_paged_mem; // Cap on paged memory usage
+ DWORD afpsrv_max_nonpaged_mem;// Cap on paged memory usage
+ LPWSTR afpsrv_login_msg; // NULL terminated UNICODE string.
+ // MAX AFP_MESSAGE_LEN chars.
+ // NULL => no login msg.
+ LPWSTR afpsrv_codepage; // NULL terminated UNICODE path
+ // NULL => no codepage path.
+} AFP_SERVER_INFO, *PAFP_SERVER_INFO;
+
+// Volume properties mask values. Values may be or'ed together.
+// Volume flags with msk 0x0000001F are defined by the AFP specification.
+// Do not overload these. Most of these values (except for READONLY above)
+// are not exposed via admin apis.
+#define AFP_VOLUME_READONLY 0x00000001
+#define AFP_VOLUME_GUESTACCESS 0x00008000
+#define AFP_VOLUME_EXCLUSIVE 0x00010000
+#define AFP_VOLUME_HAS_CUSTOM_ICON 0x00020000
+#define AFP_VOLUME_4GB 0x00040000
+#define AFP_VOLUME_AGE_DFES 0x00080000
+#define AFP_VOLUME_ALL_DOWNLEVEL (AFP_VOLUME_READONLY | \
+ AFP_VOLUME_GUESTACCESS)
+#define AFP_VOLUME_ALL (AFP_VOLUME_READONLY | \
+ AFP_VOLUME_GUESTACCESS | \
+ AFP_VOLUME_EXCLUSIVE | \
+ AFP_VOLUME_HAS_CUSTOM_ICON | \
+ AFP_VOLUME_4GB | \
+ AFP_VOLUME_AGE_DFES)
+
+#define AFP_VOLUME_UNLIMITED_USES 0xFFFFFFFF
+
+// The following bits define the fields within the AFP_VOLUME_INFO
+// structure whose values will be set.
+//
+#define AFP_VOL_PARMNUM_MAXUSES 0x00000002
+#define AFP_VOL_PARMNUM_PROPSMASK 0x00000004
+#define AFP_VOL_PARMNUM_PASSWORD 0x00000001
+#define AFP_VOL_PARMNUM_ALL ( AFP_VOL_PARMNUM_PASSWORD \
+ | AFP_VOL_PARMNUM_MAXUSES \
+ | AFP_VOL_PARMNUM_PROPSMASK )
+
+typedef struct _AFP_VOLUME_INFO
+{
+ LPWSTR afpvol_name; // Name of the volume max.
+ DWORD afpvol_id; // id of this volume. generated by sever
+ LPWSTR afpvol_password; // Volume password, max. AFP_VOLPASS_LEN
+ DWORD afpvol_max_uses; // Max opens allowed
+ DWORD afpvol_props_mask; // Mask of volume properties
+ DWORD afpvol_curr_uses; // Number of curr open connections.
+ LPWSTR afpvol_path; // The actual path
+ // Ignored for VolumeSetInfo
+} AFP_VOLUME_INFO, *PAFP_VOLUME_INFO;
+
+typedef struct _AFP_SESSION_INFO
+{
+ DWORD afpsess_id; // Id of the session
+ LPWSTR afpsess_ws_name; // Workstation Name,
+ LPWSTR afpsess_username; // User Name, max. UNLEN
+ DWORD afpsess_num_cons; // Number of open volumes
+ DWORD afpsess_num_opens; // Number of open files
+ LONG afpsess_time; // Time session established
+ DWORD afpsess_logon_type; // How the user logged on
+
+} AFP_SESSION_INFO, *PAFP_SESSION_INFO;
+
+// afpicon_type values
+
+#define ICONTYPE_SRVR 0 // Large, monochrome
+#define ICONTYPE_ICN 1 // Large. monochrome
+#define ICONTYPE_ICS 2 // Small, monochrome
+#define ICONTYPE_ICN4 3 // Large, 4 color
+#define ICONTYPE_ICN8 4 // Large, 8 color
+#define ICONTYPE_ICS4 5 // Small, 4 color
+#define ICONTYPE_ICS8 6 // Small, 8 color
+#define MAX_ICONTYPE 7
+
+// afpicon_length values
+
+#define ICONSIZE_ICN 256 // Large. monochrome
+#define ICONSIZE_ICS 64 // Small, monochrome
+#define ICONSIZE_ICN4 1024// Large, 4 color
+#define ICONSIZE_ICN8 2048// Large, 8 color
+#define ICONSIZE_ICS4 256 // Small, 4 color
+#define ICONSIZE_ICS8 512 // Small, 8 color
+
+typedef struct _AFP_ICON_INFO
+{
+ WCHAR afpicon_type[AFP_TYPE_LEN+1]; // Resource Type
+ WCHAR afpicon_creator[AFP_CREATOR_LEN+1]; // Resource Creator
+ DWORD afpicon_icontype; // Icon type
+ DWORD afpicon_length; // Length of icon block
+ PBYTE afpicon_data; // The actual icon.
+
+} AFP_ICON_INFO, *PAFP_ICON_INFO;
+
+// The AfpAdminConnectionEnum Filter values
+
+#define AFP_NO_FILTER 0
+#define AFP_FILTER_ON_VOLUME_ID 1
+#define AFP_FILTER_ON_SESSION_ID 2
+
+typedef struct _AFP_CONNECTION_INFO
+{
+ DWORD afpconn_id; // Connection Id
+ LPWSTR afpconn_username; // User who has this session open
+ // Max. UNLEN
+ LPWSTR afpconn_volumename; // Volume corresponding to this
+ // connection
+ ULONG afpconn_time; // Time since the vol was opened.(secs)
+ DWORD afpconn_num_opens; // Number of open resources
+
+} AFP_CONNECTION_INFO, *PAFP_CONNECTION_INFO;
+
+// Various File open modes
+
+#define AFP_OPEN_MODE_NONE 0x00000000
+#define AFP_OPEN_MODE_READ 0x00000001
+#define AFP_OPEN_MODE_WRITE 0x00000002
+
+// Fork type of an open file
+#define AFP_FORK_DATA 0x00000000
+#define AFP_FORK_RESOURCE 0x00000001
+
+typedef struct _AFP_FILE_INFO
+{
+ DWORD afpfile_id; // Id of the open file fork
+ DWORD afpfile_open_mode; // Mode in which file is opened
+ DWORD afpfile_num_locks; // Number of locks on the file
+ DWORD afpfile_fork_type; // Fork type
+ LPWSTR afpfile_username; // File opened by this user. max UNLEN
+ LPWSTR afpfile_path; // Absolute canonical path to the file
+
+} AFP_FILE_INFO, *PAFP_FILE_INFO;
+
+// The following bits define the permissions mask
+// NOTE: These MUST be consistent with the AFP permissions
+
+#define AFP_PERM_WORLD_SFO 0x00010000
+#define AFP_PERM_WORLD_SFI 0x00020000
+#define AFP_PERM_WORLD_MC 0x00040000
+#define AFP_PERM_WORLD_MASK 0x00070000
+#define AFP_PERM_GROUP_SFO 0x00000100
+#define AFP_PERM_GROUP_SFI 0x00000200
+#define AFP_PERM_GROUP_MC 0x00000400
+#define AFP_PERM_GROUP_MASK 0x00000700
+#define AFP_PERM_OWNER_SFO 0x00000001
+#define AFP_PERM_OWNER_SFI 0x00000002
+#define AFP_PERM_OWNER_MC 0x00000004
+#define AFP_PERM_OWNER_MASK 0x00000007
+#define AFP_PERM_INHIBIT_MOVE_DELETE 0x01000000
+#define AFP_PERM_SET_SUBDIRS 0x02000000
+
+
+// The following bits define the fields within the AFP_DIRECTORY_INFO
+// structure whose values will be set.
+//
+#define AFP_DIR_PARMNUM_PERMS 0x00000001
+#define AFP_DIR_PARMNUM_OWNER 0x00000002
+#define AFP_DIR_PARMNUM_GROUP 0x00000004
+#define AFP_DIR_PARMNUM_ALL ( AFP_DIR_PARMNUM_PERMS \
+ | AFP_DIR_PARMNUM_OWNER \
+ | AFP_DIR_PARMNUM_GROUP )
+typedef struct _AFP_DIRECTORY_INFO
+{
+ LPWSTR afpdir_path; // Absolute dir path,
+ DWORD afpdir_perms; // Directory permissions
+ LPWSTR afpdir_owner; // Directory owner, max. UNLEN
+ LPWSTR afpdir_group; // Group Association max. GNLEN
+ BOOLEAN afpdir_in_volume; // TRUE indicates that this directory
+ // is part of a volume, FALSE otherwise.
+
+} AFP_DIRECTORY_INFO, *PAFP_DIRECTORY_INFO;
+
+// The following bits define the fields within the AFP_FINDER_INFO
+// structure whos values will be set
+//
+#define AFP_FD_PARMNUM_TYPE 0x00000001
+#define AFP_FD_PARMNUM_CREATOR 0x00000002
+#define AFP_FD_PARMNUM_ALL ( AFP_FD_PARMNUM_TYPE \
+ | AFP_FD_PARMNUM_CREATOR)
+typedef struct _AFP_FINDER_INFO
+{
+ LPWSTR afpfd_path; // Absolute file/dir path
+ WCHAR afpfd_type[AFP_TYPE_LEN+1]; // Finder type
+ WCHAR afpfd_creator[AFP_CREATOR_LEN+1]; // Finder creator
+
+} AFP_FINDER_INFO, *PAFP_FINDER_INFO;
+
+typedef struct _AFP_EXTENSION {
+
+ WCHAR afpe_extension[AFP_EXTENSION_LEN+1];
+ DWORD afpe_tcid;
+
+} AFP_EXTENSION, *PAFP_EXTENSION;
+
+typedef struct _AFP_TYPE_CREATOR
+{
+ WCHAR afptc_creator[AFP_CREATOR_LEN+1]; // Resource Creator
+ WCHAR afptc_type[AFP_TYPE_LEN+1]; // Resource Type
+ WCHAR afptc_comment[AFP_ETC_COMMENT_LEN+1];
+ DWORD afptc_id;
+
+} AFP_TYPE_CREATOR, *PAFP_TYPE_CREATOR;
+
+typedef struct _AFP_MESSAGE_INFO
+{
+ DWORD afpmsg_session_id; // Session Id of the user to which
+ // the message is to be sent.
+ LPWSTR afpmsg_text; // Must be at most AFP_MESSAGE_LEN
+
+} AFP_MESSAGE_INFO, *PAFP_MESSAGE_INFO;
+
+typedef struct _AFP_ETCMAP_INFO {
+
+ DWORD afpetc_num_type_creators;
+
+#ifdef MIDL_PASS
+ [size_is(afpetc_num_type_creators)] PAFP_TYPE_CREATOR afpetc_type_creator;
+#else
+ PAFP_TYPE_CREATOR afpetc_type_creator;
+#endif
+
+ DWORD afpetc_num_extensions;
+#ifdef MIDL_PASS
+ [size_is(afpetc_num_extensions)] PAFP_EXTENSION afpetc_extension;
+#else
+ PAFP_EXTENSION afpetc_extension;
+#endif
+
+} AFP_ETCMAP_INFO, *PAFP_ETCMAP_INFO;
+
+
+/* Our version of the AFP Function codes organized by class */
+#define _AFP_INVALID_OPCODE 0x00
+#define _AFP_UNSUPPORTED_OPCODE 0x01
+
+#define _AFP_GET_SRVR_INFO 0x02 /* SERVER APIs */
+#define _AFP_GET_SRVR_PARMS 0x03
+#define _AFP_CHANGE_PASSWORD 0x04
+#define _AFP_LOGIN 0x05
+#define _AFP_LOGIN_CONT 0x06
+#define _AFP_LOGOUT 0x07
+#define _AFP_MAP_ID 0x08
+#define _AFP_MAP_NAME 0x09
+#define _AFP_GET_USER_INFO 0x0A
+#define _AFP_GET_SRVR_MSG 0x0B
+#define _AFP_GET_DOMAIN_LIST 0x0C
+
+#define _AFP_OPEN_VOL 0x0D /* VOLUME APIs */
+#define _AFP_CLOSE_VOL 0x0E
+#define _AFP_GET_VOL_PARMS 0x0F
+#define _AFP_SET_VOL_PARMS 0x10
+#define _AFP_FLUSH 0x11
+
+#define _AFP_GET_FILE_DIR_PARMS 0x12 /* FILE-DIRECTORY APIs */
+#define _AFP_SET_FILE_DIR_PARMS 0x13
+#define _AFP_DELETE 0x14
+#define _AFP_RENAME 0x15
+#define _AFP_MOVE_AND_RENAME 0x16
+
+#define _AFP_OPEN_DIR 0x17 /* DIRECTORY APIs */
+#define _AFP_CLOSE_DIR 0x18
+#define _AFP_CREATE_DIR 0x19
+#define _AFP_ENUMERATE 0x1A
+#define _AFP_SET_DIR_PARMS 0x1B
+
+#define _AFP_CREATE_FILE 0x1C /* FILE APIs */
+#define _AFP_COPY_FILE 0x1D
+#define _AFP_CREATE_ID 0x1E
+#define _AFP_DELETE_ID 0x1F
+#define _AFP_RESOLVE_ID 0x20
+#define _AFP_SET_FILE_PARMS 0x21
+#define _AFP_EXCHANGE_FILES 0x22
+
+#define _AFP_OPEN_FORK 0x23 /* FORK APIs */
+#define _AFP_CLOSE_FORK 0x24
+#define _AFP_FLUSH_FORK 0x25
+#define _AFP_READ 0x26
+#define _AFP_WRITE 0x27
+#define _AFP_BYTE_RANGE_LOCK 0x28
+#define _AFP_GET_FORK_PARMS 0x29
+#define _AFP_SET_FORK_PARMS 0x2A
+
+#define _AFP_OPEN_DT 0x2B /* DESKTOP APIs */
+#define _AFP_CLOSE_DT 0x2C
+#define _AFP_ADD_APPL 0x2D
+#define _AFP_GET_APPL 0x2E
+#define _AFP_REMOVE_APPL 0x2F
+#define _AFP_ADD_COMMENT 0x30
+#define _AFP_GET_COMMENT 0x31
+#define _AFP_REMOVE_COMMENT 0x32
+#define _AFP_ADD_ICON 0x33
+#define _AFP_GET_ICON 0x34
+#define _AFP_GET_ICON_INFO 0x35
+
+#define _AFP_CAT_SEARCH 0x36
+#define _AFP_MAX_ENTRIES 0x38 /* Keep it even */
+
+typedef struct _AFP_STATISTICS_INFO
+{
+ DWORD stat_ServerStartTime; // Server start time
+ DWORD stat_TimeStamp; // Statistics collected since
+ DWORD stat_Errors; // Unexpected Errors
+ DWORD stat_MaxSessions; // Max. sessions active simulataneously
+ DWORD stat_TotalSessions; // Total number of sessions created
+ DWORD stat_CurrentSessions; // Number of sessions active now
+ DWORD stat_NumAdminReqs; // Total number of admin requests
+ DWORD stat_NumAdminChanges; // Number of admin reqs causing change
+ // The file statistics are actually fork statistics i.e. opening both the
+ // data and the resource forks will yield a count of TWO
+ DWORD stat_MaxFilesOpened; // Max. files opened simulataneously
+ DWORD stat_TotalFilesOpened; // Total number of files opened
+ DWORD stat_CurrentFilesOpen; // Number of files open now
+ DWORD stat_CurrentFileLocks; // Current count of locks
+ DWORD stat_NumFailedLogins; // Number of unsuccessful logins
+ DWORD stat_NumForcedLogoffs; // Number of sessions kicked out
+ DWORD stat_NumMessagesSent; // Number of messages sent out
+ DWORD stat_MaxNonPagedUsage; // High-water mark of the non-paged
+ // memory usage
+ DWORD stat_CurrNonPagedUsage; // Amount of non-paged memory in use
+ DWORD stat_MaxPagedUsage; // High-water mark of the paged
+ // memory usage
+ DWORD stat_CurrPagedUsage; // Amount of paged memory in use
+} AFP_STATISTICS_INFO, *PAFP_STATISTICS_INFO;
+
+typedef struct _AFP_STATISTICS_INFO_EX
+{
+ DWORD stat_ServerStartTime; // Server start time
+ DWORD stat_TimeStamp; // Statistics collected since
+ DWORD stat_Errors; // Unexpected Errors
+
+ DWORD stat_MaxSessions; // Max. sessions active simulataneously
+ DWORD stat_TotalSessions; // Total number of sessions created
+ DWORD stat_CurrentSessions; // Number of sessions active now
+
+ DWORD stat_NumAdminReqs; // Total number of admin requests
+ DWORD stat_NumAdminChanges; // Number of admin reqs causing change
+
+ // The file statistics are actually fork statistics i.e. opening both the
+ // data and the resource forks will yield a count of TWO
+ DWORD stat_MaxFilesOpened; // Max. files opened simulataneously
+ DWORD stat_TotalFilesOpened; // Total number of files opened
+ DWORD stat_CurrentFilesOpen; // Number of files open now
+ DWORD stat_CurrentFileLocks; // Current count of locks
+
+ DWORD stat_NumFailedLogins; // Number of unsuccessful logins
+ DWORD stat_NumForcedLogoffs; // Number of sessions kicked out
+ DWORD stat_NumMessagesSent; // Number of messages sent out
+
+ DWORD stat_MaxNonPagedUsage; // High-water mark of the non-paged
+ // memory usage
+ DWORD stat_CurrNonPagedUsage; // Amount of non-paged memory in use
+ DWORD stat_MaxPagedUsage; // High-water mark of the paged
+ // memory usage
+ DWORD stat_CurrPagedUsage; // Amount of paged memory in use
+
+ // NOTE: MAKE SURE THE STRUCTURE ABOVE THIS LINE MATCHES EXACTLY THE AFP_STATISTICS_INFO
+
+ DWORD stat_PagedCount; // Number of current allocations
+ DWORD stat_NonPagedCount; // Number of current allocations
+
+ DWORD stat_EnumCacheHits; // # of times cache was hit
+ DWORD stat_EnumCacheMisses; // # of times cache was missed
+ DWORD stat_IoPoolHits; // # of times Io Pool was hit
+ DWORD stat_IoPoolMisses; // # of times Io Pool was missed
+
+ DWORD stat_MaxInternalOpens; // Max # of internal opens
+ DWORD stat_TotalInternalOpens;// Total # of internal opens
+ DWORD stat_CurrentInternalOpens;// Current # of internal opens
+
+
+ DWORD stat_CurrQueueLength; // # of requests in the queue
+ DWORD stat_MaxQueueLength; // Max # of requests in the queue
+ DWORD stat_CurrThreadCount; // # of worker threads active
+ DWORD stat_MaxThreadCount; // Max # of worker threads active
+
+ // Make sure the following is Quadword aligned for efficiency
+ LARGE_INTEGER stat_DataRead; // Amount of data read (disk)
+ LARGE_INTEGER stat_DataWritten; // Amount of data written (disk)
+ LARGE_INTEGER stat_DataReadInternal; // Amount of data read (disk)
+ LARGE_INTEGER stat_DataWrittenInternal;// Amount of data written (disk)
+ LARGE_INTEGER stat_DataOut; // Amount of data sent out (wire)
+ LARGE_INTEGER stat_DataIn; // Amount of data read in (wire)
+
+} AFP_STATISTICS_INFO_EX, *PAFP_STATISTICS_INFO_EX;
+
+typedef struct _AFP_PROFILE_INFO
+{
+ DWORD perf_ApiCounts[_AFP_MAX_ENTRIES];
+ // # of times each Api is called
+ LARGE_INTEGER perf_ApiCumTimes[_AFP_MAX_ENTRIES];
+ // Cummulative time spent in Apis
+ LARGE_INTEGER perf_ApiWorstTime[_AFP_MAX_ENTRIES];
+ // Worst time for an api
+ LARGE_INTEGER perf_ApiBestTime[_AFP_MAX_ENTRIES];
+ // Best time for an api
+ LARGE_INTEGER perf_OpenTimeRA; // Time spent in NtOpenFile for ReadAttr
+ LARGE_INTEGER perf_OpenTimeRC; // Time spent in NtOpenFile for ReadControl
+ LARGE_INTEGER perf_OpenTimeWC; // Time spent in NtOpenFile for WriteControl
+ LARGE_INTEGER perf_OpenTimeRW; // Time spent in NtOpenFile for Read/Write
+ LARGE_INTEGER perf_OpenTimeDL; // Time spent in NtOpenFile for Delete
+ LARGE_INTEGER perf_OpenTimeDR; // Time spent in NtOpenFile for Directories
+ LARGE_INTEGER perf_CreateTimeFIL; // Time spent in NtCreateFile for file/data stream
+ LARGE_INTEGER perf_CreateTimeSTR; // Time spent in NtCreateFile for file/other streams
+ LARGE_INTEGER perf_CreateTimeDIR; // Time spent in NtCreateFile for dir/data stream
+ LARGE_INTEGER perf_CloseTime; // Time spent in NtClose
+ LARGE_INTEGER perf_DeleteTime; // Time spent in NtSetInformationFile
+ LARGE_INTEGER perf_GetInfoTime; // Time spent in NtQueryInformationFile
+ LARGE_INTEGER perf_SetInfoTime; // Time spent in NtSetInformationFile
+ LARGE_INTEGER perf_GetPermsTime; // Time spent on getting permissions
+ LARGE_INTEGER perf_SetPermsTime; // Time spent on setting permissions
+ LARGE_INTEGER perf_PathMapTime; // Time spent in pathmap code
+ LARGE_INTEGER perf_ScavengerTime; // Time spent in scavenger
+ LARGE_INTEGER perf_IdIndexUpdTime; // Time spent updating idindex
+ LARGE_INTEGER perf_DesktopUpdTime; // Time spent updating desktop
+ LARGE_INTEGER perf_SwmrWaitTime; // Time spent waiting for Swmr
+ LARGE_INTEGER perf_SwmrLockTimeR; // Time swmr was locked for read
+ LARGE_INTEGER perf_SwmrLockTimeW; // Time swmr was locked for write
+ LARGE_INTEGER perf_QueueTime; // Time Apis spent in queue
+ LARGE_INTEGER perf_UnmarshallTime; // Time spent in un-marshalling a request
+ LARGE_INTEGER perf_InterReqTime; // Time elapse between subsequent requests
+ LARGE_INTEGER perf_ExAllocTimeN; // Time spent in ExAllocatePool (NonPaged)
+ LARGE_INTEGER perf_ExFreeTimeN; // Time spent in ExFreePool (NonPaged)
+ LARGE_INTEGER perf_ExAllocTimeP; // Time spent in ExAllocatePool (Paged)
+ LARGE_INTEGER perf_ExFreeTimeP; // Time spent in ExFreePool (Paged)
+ LARGE_INTEGER perf_AfpAllocTimeN; // Time spent in AfpAllocateMemory (NonPaged)
+ LARGE_INTEGER perf_AfpFreeTimeN; // Time spent in AfpFreeMemory (NonPaged)
+ LARGE_INTEGER perf_AfpAllocTimeP; // Time spent in AfpAllocateMemory (Paged)
+ LARGE_INTEGER perf_AfpFreeTimeP; // Time spent in AfpFreeMemory (Paged)
+ LARGE_INTEGER perf_BPAllocTime; // Time spent in BP Alloc
+ LARGE_INTEGER perf_BPFreeTime; // Time spent in BP Free
+ LARGE_INTEGER perf_DFEAllocTime; // Time spent in allocating a DFE
+ LARGE_INTEGER perf_DFEFreeTime; // Time spent in freeing a DFE
+ LARGE_INTEGER perf_ChangeNotifyTime; // Time spent processing change notifies
+ LARGE_INTEGER perf_ScanTreeTime; // Time spent in scanning a directory tree
+ LARGE_INTEGER perf_PerfFreq; // Perf. counter frequency
+ DWORD perf_NumFastIoSucceeded;// Fast IO success count
+ DWORD perf_NumFastIoFailed; // Fast Io failure count
+ DWORD perf_OpenCountRA; // # of times NtOpenFile called for ReadAttr
+ DWORD perf_OpenCountRC; // # of times NtOpenFile called for ReadControl
+ DWORD perf_OpenCountWC; // # of times NtOpenFile called for WriteControl
+ DWORD perf_OpenCountRW; // # of times NtOpenFile called for Read/Write
+ DWORD perf_OpenCountDL; // # of times NtOpenFile called for Delete
+ DWORD perf_OpenCountDR; // # of times NtOpenFile called for Directories
+ DWORD perf_CreateCountFIL; // # of times NtCreateFile called - file/data
+ DWORD perf_CreateCountSTR; // # of times NtCreateFile called - file/other
+ DWORD perf_CreateCountDIR; // # of times NtCreateFile called - dir/data
+ DWORD perf_CloseCount; // # of times NtClose called
+ DWORD perf_DeleteCount; // # of times NtSetInformationFile called
+ DWORD perf_GetInfoCount; // # of times NtQueryInformationFile called
+ DWORD perf_SetInfoCount; // # of times NtSetInformationFile called
+ DWORD perf_GetPermsCount; // # of times Get permissions called
+ DWORD perf_SetPermsCount; // # of times Get permissions called
+ DWORD perf_PathMapCount; // # of times PathMap was invoked
+ DWORD perf_ScavengerCount; // # of times scavenger was scheduled
+ DWORD perf_IdIndexUpdCount; // # of times idindex was updated
+ DWORD perf_DesktopUpdCount; // # of times desktop was updated
+ DWORD perf_SwmrWaitCount; // # of times swmr access was blocked
+ DWORD perf_SwmrLockCountR; // # of times swmr was locked for read
+ DWORD perf_SwmrLockCountW; // # of times swmr was locked for write
+ DWORD perf_SwmrUpgradeCount; // # of times swmr was upgraded
+ DWORD perf_SwmrDowngradeCount;// # of times swmr was downgraded
+ DWORD perf_QueueCount; // # of times worker was queued
+ DWORD perf_UnmarshallCount; // # of times api unmarshalling done
+ DWORD perf_ReqCount; // # of apis - this is essentially total of perf_ApiCounts[i]
+ DWORD perf_ExAllocCountN; // # of times in ExAllocatePool (NonPaged) called
+ DWORD perf_ExFreeCountN; // # of times in ExFreePool (NonPaged) called
+ DWORD perf_ExAllocCountP; // # of times in ExAllocatePool (Paged) called
+ DWORD perf_ExFreeCountP; // # of times in ExFreePool (Paged) called
+ DWORD perf_AfpAllocCountN; // # of times in AfpAllocateMemory (NonPaged) called
+ DWORD perf_AfpFreeCountN; // # of times in AfpFreeMemory (NonPaged) called
+ DWORD perf_AfpAllocCountP; // # of times in AfpAllocateMemory (Paged) called
+ DWORD perf_AfpFreeCountP; // # of times in AfpFreeMemory (Paged) called
+ DWORD perf_BPAllocCount; // # of times in BP Alloc called
+ DWORD perf_BPFreeCount; // # of times in BP Free called
+ DWORD perf_BPAgeCount; // # of times in BP aged out
+ DWORD perf_DFEAllocCount; // # of times in a DFE is allocated
+ DWORD perf_DFEFreeCount; // # of times in a DFE is freed
+ DWORD perf_DFEAgeCount; // # of times in DFE aged out
+ DWORD perf_ChangeNotifyCount; // # of times ChangeNotify called
+ DWORD perf_ScanTreeCount; // # of items scanned during scantree
+ DWORD perf_NumDfeLookupByName;// # of times DFE lookup by Name was called
+ DWORD perf_NumDfeLookupById; // # of times DFE lookup by Id was called
+ DWORD perf_DfeDepthTraversed; // How deep in the hash buckets did we go
+ DWORD perf_DfeCacheHits; // # of times DFE cache was hit
+ DWORD perf_DfeCacheMisses; // # of times DFE cache was missed
+ DWORD perf_MaxDfrdReqCount; // Current # of request deferred
+ DWORD perf_CurDfrdReqCount; // Max # of request deferred
+ DWORD perf_cAllocatedIrps; // Total # of Irps allocated
+ DWORD perf_cAllocatedMdls; // Total # of Mdls allocated
+} AFP_PROFILE_INFO, *PAFP_PROFILE_INFO;
+
+
+// AfpAdminXXX API prototypes
+//
+DWORD
+AfpAdminConnect(
+ IN LPWSTR lpwsServerName,
+ OUT PAFP_SERVER_HANDLE phAfpServer
+);
+
+VOID
+AfpAdminDisconnect(
+ IN AFP_SERVER_HANDLE hAfpServer
+);
+
+VOID
+AfpAdminBufferFree(
+ IN PVOID pBuffer
+);
+
+DWORD
+AfpAdminVolumeEnum(
+ IN AFP_SERVER_HANDLE hAfpServer,
+ OUT LPBYTE * lpbBuffer,
+ IN DWORD dwPrefMaxLen,
+ OUT LPDWORD lpdwEntriesRead,
+ OUT LPDWORD lpdwTotalEntries,
+ IN LPDWORD lpdwResumeHandle
+);
+
+DWORD
+AfpAdminVolumeSetInfo (
+ IN AFP_SERVER_HANDLE hAfpServer,
+ IN LPBYTE pBuffer,
+ IN DWORD dwParmNum
+);
+
+DWORD
+AfpAdminVolumeGetInfo (
+ IN AFP_SERVER_HANDLE hAfpServer,
+ IN LPWSTR lpwsVolumeName,
+ OUT LPBYTE * lpbBuffer
+);
+
+
+DWORD
+AfpAdminVolumeDelete(
+ IN AFP_SERVER_HANDLE hAfpServer,
+ IN LPWSTR lpwsVolumeName
+);
+
+DWORD
+AfpAdminVolumeAdd(
+ IN AFP_SERVER_HANDLE hAfpServer,
+ IN LPBYTE pBuffer
+);
+
+DWORD
+AfpAdminInvalidVolumeEnum(
+ IN AFP_SERVER_HANDLE hAfpServer,
+ OUT LPBYTE * lpbBuffer,
+ OUT LPDWORD lpdwEntriesRead
+);
+
+DWORD
+AfpAdminInvalidVolumeDelete(
+ IN AFP_SERVER_HANDLE hAfpServer,
+ IN LPWSTR lpwsVolumeName
+);
+
+DWORD
+AfpAdminDirectoryGetInfo(
+ IN AFP_SERVER_HANDLE hAfpServer,
+ IN LPWSTR lpwsPath,
+ OUT LPBYTE *ppAfpDirectoryInfo
+);
+
+DWORD
+AfpAdminDirectorySetInfo(
+ IN AFP_SERVER_HANDLE hAfpServer,
+ IN LPBYTE pAfpDirectoryInfo,
+ IN DWORD dwParmNum
+);
+
+DWORD
+AfpAdminServerGetInfo(
+ IN AFP_SERVER_HANDLE hAfpServer,
+ OUT LPBYTE *ppAfpServerInfo
+);
+
+DWORD
+AfpAdminServerSetInfo(
+ IN AFP_SERVER_HANDLE hAfpServer,
+ IN LPBYTE pAfpServerInfo,
+ IN DWORD dwParmNum
+);
+
+DWORD
+AfpAdminSessionEnum(
+ IN AFP_SERVER_HANDLE hAfpServer,
+ OUT LPBYTE * lpbBuffer,
+ IN DWORD dwPrefMaxLen,
+ OUT LPDWORD lpdwEntriesRead,
+ OUT LPDWORD lpdwTotalEntries,
+ IN LPDWORD lpdwResumeHandle
+);
+
+DWORD
+AfpAdminSessionClose(
+ IN AFP_SERVER_HANDLE hAfpServer,
+ IN DWORD dwSessionId
+);
+
+DWORD
+AfpAdminConnectionEnum(
+ IN AFP_SERVER_HANDLE hAfpServer,
+ OUT LPBYTE * lpbBuffer,
+ IN DWORD dwFilter,
+ IN DWORD dwId,
+ IN DWORD dwPrefMaxLen,
+ OUT LPDWORD lpdwEntriesRead,
+ OUT LPDWORD lpdwTotalEntries,
+ IN LPDWORD lpdwResumeHandle
+);
+
+DWORD
+AfpAdminConnectionClose(
+ IN AFP_SERVER_HANDLE hAfpServer,
+ IN DWORD dwConnectionId
+);
+
+DWORD
+AfpAdminFileEnum(
+ IN AFP_SERVER_HANDLE hAfpServer,
+ OUT LPBYTE * lpbBuffer,
+ IN DWORD dwPrefMaxLen,
+ OUT LPDWORD lpdwEntriesRead,
+ OUT LPDWORD lpdwTotalEntries,
+ IN LPDWORD lpdwResumeHandle
+);
+
+DWORD
+AfpAdminFileClose(
+ IN AFP_SERVER_HANDLE hAfpServer,
+ IN DWORD dwConnectionId
+);
+
+DWORD
+AfpAdminETCMapGetInfo(
+ IN AFP_SERVER_HANDLE hAfpServer,
+ OUT LPBYTE * ppbBuffer
+);
+
+DWORD
+AfpAdminETCMapAdd(
+ IN AFP_SERVER_HANDLE hAfpServer,
+ IN PAFP_TYPE_CREATOR pAfpTypeCreator
+);
+
+DWORD
+AfpAdminETCMapDelete(
+ IN AFP_SERVER_HANDLE hAfpServer,
+ IN PAFP_TYPE_CREATOR pAfpTypeCreator
+);
+
+DWORD
+AfpAdminETCMapSetInfo(
+ IN AFP_SERVER_HANDLE hAfpServer,
+ IN PAFP_TYPE_CREATOR pAfpTypeCreator
+);
+
+DWORD
+AfpAdminETCMapAssociate(
+ IN AFP_SERVER_HANDLE hAfpServer,
+ IN PAFP_TYPE_CREATOR pAfpTypeCreator,
+ IN PAFP_EXTENSION pAfpExtension
+);
+
+DWORD
+AfpAdminMessageSend(
+ IN AFP_SERVER_HANDLE hAfpServer,
+ IN PAFP_MESSAGE_INFO pAfpMessage
+);
+
+DWORD
+AfpAdminStatisticsGet(
+ IN AFP_SERVER_HANDLE hAfpServer,
+ OUT LPBYTE * ppbBuffer
+);
+
+DWORD
+AfpAdminStatisticsGetEx(
+ IN AFP_SERVER_HANDLE hAfpServer,
+ OUT LPBYTE * ppbBuffer
+);
+
+DWORD
+AfpAdminStatisticsClear(
+ IN AFP_SERVER_HANDLE hAfpServer
+);
+
+DWORD
+AfpAdminProfileGet(
+ IN AFP_SERVER_HANDLE hAfpServer,
+ OUT LPBYTE * ppbBuffer
+);
+
+DWORD
+AfpAdminProfileClear(
+ IN AFP_SERVER_HANDLE hAfpServer
+);
+
+DWORD
+AfpAdminFinderSetInfo(
+ IN AFP_SERVER_HANDLE hAfpServer,
+ IN LPWSTR pType,
+ IN LPWSTR pCreator,
+ IN LPWSTR pData,
+ IN LPWSTR pResource,
+ IN LPWSTR pTarget,
+ IN DWORD dwParmNum
+);
+
+#endif // _MACFILE_
+
diff --git a/private/utils/wizards/shrpub/makefile b/private/utils/wizards/shrpub/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/wizards/shrpub/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/wizards/shrpub/nettree.cpp b/private/utils/wizards/shrpub/nettree.cpp
new file mode 100644
index 000000000..488108d0b
--- /dev/null
+++ b/private/utils/wizards/shrpub/nettree.cpp
@@ -0,0 +1,578 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ NetTree.cpp : implementation file
+
+File History:
+
+ RandyFe Jan-96 created (1/1/96 from the License Compliancy Wizard)
+
+--*/
+
+#include "stdafx.h"
+#include "turtle.h"
+#include "resource.h"
+#include "NetTree.h"
+
+#ifdef _DEBUG
+//#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// Global variables
+
+extern TCHAR pszTreeEvent[];
+
+/////////////////////////////////////////////////////////////////////////////
+// CNetTreeCtrl
+
+CNetTreeCtrl::CNetTreeCtrl()
+: m_pThread(NULL), m_bExitThread(FALSE), m_event(TRUE, TRUE, pszTreeEvent)
+{
+ // Get a handle to the process heap
+ m_hHeap = ::GetProcessHeap();
+
+ ASSERT(m_hHeap != NULL);
+}
+
+CNetTreeCtrl::~CNetTreeCtrl()
+{
+ // Make sure the tree thread knows it's time to exit.
+ NotifyThread(TRUE);
+
+ // Create an event object to match the tree thread event object.
+ CEvent event(TRUE, TRUE, pszTreeEvent);
+
+ // Create a lock object for the event object.
+ CSingleLock lock(&event);
+
+ // Lock the lock object and make the main thread wait for the
+ // threads to signal their event objects.
+ lock.Lock();
+
+ // Free all of the pointers to LPTSTRs in the list
+ POSITION pos = m_ptrlistStrings.GetHeadPosition();
+
+ while (pos != NULL)
+ {
+ // Memory deallocation fails if there's a null char
+ // at the end of the string.
+ LPTSTR psz = m_ptrlistStrings.GetNext(pos);
+ *(::_tcslen(psz) + psz) = (TCHAR)0xFD;
+ delete[] psz;
+ }
+
+ // Free all of the pointers to NETRESOURCE structs in the list
+ pos = m_ptrlistContainers.GetHeadPosition();
+
+ while (pos != NULL)
+ {
+ delete m_ptrlistContainers.GetNext(pos);
+ }
+}
+
+
+BEGIN_MESSAGE_MAP(CNetTreeCtrl, CTreeCtrl)
+ //{{AFX_MSG_MAP(CNetTreeCtrl)
+ ON_NOTIFY_REFLECT(TVN_ITEMEXPANDING, OnItemExpanding)
+ ON_WM_SETCURSOR()
+ ON_WM_DESTROY()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// Global functions
+
+UINT FillTree(LPVOID pParam)
+{
+ CEvent event(TRUE, TRUE, pszTreeEvent);
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+ PTREEINFO pti = (PTREEINFO)pParam;
+ CNetTreeCtrl* pTree = (CNetTreeCtrl*)pti->pTree;
+ BOOL bResult = FALSE;
+ DWORD dwEntries = 0xFFFFFFFF;
+ LPVOID lpvBuffer = NULL;
+ HANDLE hEnum = NULL;
+
+ // Because this function may call itself, keep a usage count
+ // so that pti is freed only when the first instance returns.
+ static USHORT uUsage = 0;
+
+ // Keep a handle to the heap in case the CNetTreeCtrl object
+ // goes away before the thread ends.
+ HANDLE hHeap = pTree->m_hHeap;
+ DWORD dwResult;
+ LPNETRESOURCE pnrRoot;
+ HTREEITEM hTreeItem, hTreeExpand;
+
+ hTreeItem = hTreeExpand = NULL;
+
+ try
+ {
+ // Unsignal the event object.
+ event.ResetEvent();
+
+ // Show the wait cursor
+ pTree->BeginWaitCursor();
+
+ // Exit if the handle to the heap is invalid.
+ if (hHeap == NULL)
+ goto ExitFunction;
+
+ if (pti->hTreeItem == TVI_ROOT)
+ {
+ pnrRoot = NULL;
+ if (pTree->m_imagelist.Create(IDB_NET_TREE, 16, 3, CNetTreeCtrl::IMG_MASK))
+ {
+ pTree->SetImageList(&(pTree->m_imagelist), TVSIL_NORMAL);
+ pTree->m_imagelist.SetBkColor(CLR_NONE);
+ }
+ }
+ else
+ pnrRoot = (LPNETRESOURCE)pTree->GetItemData(pti->hTreeItem);
+
+ // Get an enumeration handle.
+ if ((dwResult = ::WNetOpenEnum(RESOURCE_GLOBALNET, RESOURCETYPE_ANY,
+ RESOURCEUSAGE_CONTAINER, pnrRoot, &hEnum)) != NO_ERROR)
+ {
+ // Exit if WNetOpenEnum fails.
+ dwResult = ::GetLastError();
+ goto ExitFunction;
+ }
+
+ // Allocate a buffer for enumeration.
+ if ((lpvBuffer = ::HeapAlloc(hHeap, HEAP_ZERO_MEMORY, pti->dwBufSize)) == NULL)
+ // Exit if memory allocation failed
+ goto ExitFunction;
+
+ // Retrieve a block of network entries.
+ while ((dwResult = ::WNetEnumResource(hEnum, &dwEntries, lpvBuffer, &(pti->dwBufSize))) != ERROR_NO_MORE_ITEMS)
+ {
+ // See if it's time to exit.
+ if (pTree->m_bExitThread)
+ {
+ pTree->NotifyThread(FALSE);
+ bResult = TRUE;
+ goto ExitFunction;
+ }
+
+ // Exit if WNetEnumResource failed.
+ if (dwResult != NO_ERROR)
+ {
+ dwResult = ::GetLastError();
+ goto ExitFunction;
+ }
+
+ LPNETRESOURCE pnrLeaf = (LPNETRESOURCE)lpvBuffer;
+ TV_INSERTSTRUCT tviLeaf;
+
+ // Fill in the TV_INSERTSTRUCT members.
+ tviLeaf.hParent = pti->hTreeItem;
+ tviLeaf.hInsertAfter = TVI_SORT;
+ tviLeaf.item.hItem = NULL;
+ tviLeaf.item.state = 0;
+ tviLeaf.item.stateMask = 0;
+ tviLeaf.item.cchTextMax = 0;
+ tviLeaf.item.iSelectedImage = 0;
+
+ // Set the correct image for the leaf.
+ switch (pnrLeaf->dwDisplayType)
+ {
+ case RESOURCEDISPLAYTYPE_DOMAIN:
+ tviLeaf.item.iImage = tviLeaf.item.iSelectedImage = CNetTreeCtrl::IMG_DOMAIN;
+ break;
+
+ case RESOURCEDISPLAYTYPE_SERVER:
+ tviLeaf.item.iImage = tviLeaf.item.iSelectedImage = CNetTreeCtrl::IMG_SERVER;
+ break;
+
+ default:
+ tviLeaf.item.iImage = tviLeaf.item.iSelectedImage = CNetTreeCtrl::IMG_ROOT;
+ }
+
+ // Fool the tree into thinking that this leaf has children
+ // since we don't know initially.
+ if (pnrLeaf->dwDisplayType == RESOURCEDISPLAYTYPE_SERVER)
+ {
+ tviLeaf.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ tviLeaf.item.cChildren = 0;
+ }
+ else
+ {
+ tviLeaf.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_CHILDREN | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+ tviLeaf.item.cChildren = 1;
+ }
+
+ // Add leaves to the branch.
+ for (DWORD i = 0; i < dwEntries; i++)
+ {
+ // See if it's time to exit.
+ if (pTree->m_bExitThread)
+ {
+ pTree->NotifyThread(FALSE);
+ bResult = TRUE;
+ goto ExitFunction;
+ }
+
+ // Create a permanent NETRESOURCE struct for later use.
+ LPNETRESOURCE pnrTemp = new NETRESOURCE;
+ pTree->m_ptrlistContainers.AddTail(pnrTemp);
+
+ ::memcpy(pnrTemp, pnrLeaf, sizeof(NETRESOURCE));
+
+ if (pnrLeaf->lpRemoteName != NULL)
+ {
+ pnrTemp->lpRemoteName = new TCHAR[::_tcslen(pnrLeaf->lpRemoteName) + 1];
+ ::_tcscpy(pnrTemp->lpRemoteName, pnrLeaf->lpRemoteName);
+ pTree->m_ptrlistStrings.AddTail(pnrTemp->lpRemoteName);
+ }
+
+ if (pnrLeaf->lpProvider != NULL)
+ {
+ pnrTemp->lpProvider = new TCHAR[::_tcslen(pnrLeaf->lpProvider) + 1];
+ ::_tcscpy(pnrTemp->lpProvider, pnrLeaf->lpProvider);
+ pTree->m_ptrlistStrings.AddTail(pnrTemp->lpProvider);
+ }
+
+ // Increment the buffer pointer.
+ pnrLeaf++;
+
+ // Use "Enterprise" as the item text if this is the root.
+ if (pti->hTreeItem == TVI_ROOT)
+ {
+ CString strRoot;
+
+ tviLeaf.item.pszText = new TCHAR[::_tcslen(pnrTemp->lpProvider) + 1];
+ ::_tcscpy(tviLeaf.item.pszText, (LPCTSTR)pnrTemp->lpProvider);
+ }
+ else if (pnrTemp->dwDisplayType == RESOURCEDISPLAYTYPE_SERVER)
+ {
+ // Skip the initial backslashes before adding the server
+ // name to the tree.
+ tviLeaf.item.pszText = pnrTemp->lpRemoteName;// + 2;
+ }
+ else
+ tviLeaf.item.pszText = pnrTemp->lpRemoteName;
+
+ tviLeaf.item.lParam = (LPARAM)(LPVOID)pnrTemp;
+
+ // Make sure the pointer to the tree control is still valid.
+ if (::IsWindow(pTree->m_hWnd))
+ {
+ hTreeItem = pTree->InsertItem(&tviLeaf);
+ }
+ else // Otherwise, exit the thread.
+ {
+ bResult = TRUE;
+ goto ExitFunction;
+ }
+
+ // Delete the string allocated for the root node text.
+ if (pti->hTreeItem == TVI_ROOT)
+ delete tviLeaf.item.pszText;
+
+ // See if the lpRemoteName member is equal to the default domain
+ // name.
+ if (!_tcscmp(pnrTemp->lpRemoteName, pApp->m_csCurrentDomain) ||
+ pti->hTreeItem == TVI_ROOT)
+ {
+
+ // Store the handle.
+ hTreeExpand = hTreeItem;
+ }
+
+ // Select the name of the license server in the tree.
+ if (!_tcscmp(pnrTemp->lpRemoteName, pApp->m_csCurrentMachine))
+ {
+ pTree->SelectItem(hTreeItem);
+ pTree->SetFocus();
+ }
+ }
+
+ // Everything went all right.
+ bResult = TRUE;
+ }
+
+ // Expand the branch but only if it isn't the root.
+ // The root item thinks it has children, but really doesn't the first time through.
+ if (pti->hTreeItem != TVI_ROOT && pTree->ItemHasChildren(pti->hTreeItem))
+ {
+ // Indicate that the branch has been expanded once.
+ pTree->SetItemState(pti->hTreeItem, TVIS_EXPANDEDONCE, TVIS_EXPANDEDONCE);
+ pTree->Expand(pti->hTreeItem, TVE_EXPAND);
+ }
+
+ // Fill the branch for the current domain if the bExpand member is TRUE.
+ if (hTreeExpand != NULL && pti->bExpand)
+ {
+ TREEINFO ti;
+
+ ti.hTreeItem = hTreeExpand;
+ ti.dwBufSize = pti->dwBufSize;
+ ti.pTree = pti->pTree;
+ ti.bExpand = TRUE;
+
+ // Increment the usage count.
+ uUsage++;
+
+ ::FillTree((LPVOID)&ti);
+
+ // Decrement the usage count.
+ uUsage--;
+ }
+
+ ExitFunction:
+ // Display a message if an error occurred.
+ if (!bResult)
+ pTree->ErrorHandler(dwResult);
+
+ // Close the enumeration handle.
+ if (hEnum != NULL)
+ if (!(bResult = (::WNetCloseEnum(hEnum) == NO_ERROR)))
+ dwResult = ::GetLastError();
+
+ // Free memory allocated on the heap.
+ if (lpvBuffer != NULL)
+ ::HeapFree(hHeap, 0, lpvBuffer);
+
+ // Free the TREEINFO pointer only if the usage count is zero.
+ if (uUsage == 0)
+ delete pti;
+
+ // Reset the thread pointer.
+ pTree->m_pThread = NULL;
+
+ // Turn off the wait cursor
+ pTree->EndWaitCursor();
+
+ // Make sure the tree control still exists before posting a message.
+ if (::IsWindow(pTree->m_hWnd))
+ pTree->PostMessage(WM_SETCURSOR);
+
+ // Signal the event object.
+ if (uUsage == 0)
+ event.SetEvent();
+
+ return (UINT)!bResult;
+ }
+ catch(...)
+ {
+ // Close the enumeration handle.
+ if (hEnum != NULL)
+ if (!(bResult = (::WNetCloseEnum(hEnum) == NO_ERROR)))
+ dwResult = ::GetLastError();
+
+ // Free memory allocated on the heap.
+ if (lpvBuffer != NULL)
+ ::HeapFree(hHeap, 0, lpvBuffer);
+
+ // Free the TREEINFO pointer
+ delete pti;
+
+ // Reset the thread pointer.
+ pTree->m_pThread = NULL;
+
+ // Turn off the wait cursor
+ pTree->EndWaitCursor();
+
+ // Signal the event object.
+ event.SetEvent();
+
+ return (UINT)2;
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CNetTreeCtrl member functions
+
+BOOL CNetTreeCtrl::PopulateTree(BOOL bExpand /* = TRUE */, const HTREEITEM hParentBranch /* = TVI_ROOT */,
+ DWORD dwBufSize /* = BUFFER_SIZE */)
+{
+ PTREEINFO pti = new TREEINFO;
+
+ pti->hTreeItem = hParentBranch;
+ pti->dwBufSize = dwBufSize;
+ pti->pTree = this;
+ pti->bExpand = bExpand;
+
+ // Don't begin a new thread until the last one has ended.
+ if (m_pThread != NULL)
+ {
+ NotifyThread(TRUE);
+
+ CEvent event(TRUE, TRUE, pszTreeEvent);
+ CSingleLock lock(&event);
+
+ // Wait.
+ lock.Lock();
+ }
+
+ m_pThread = AfxBeginThread((AFX_THREADPROC)::FillTree, (LPVOID)pti);
+
+ return TRUE;
+}
+
+void CNetTreeCtrl::ErrorHandler(const DWORD dwCode)
+{
+ CString strError;
+ BOOL bNetError = FALSE;
+
+#ifdef _DEBUG
+ switch (dwCode)
+ {
+ case ERROR_MORE_DATA:
+ strError = "ERROR_MORE_DATA";
+ break;
+
+ case ERROR_INVALID_HANDLE:
+ strError = "ERROR_INVALID_HANDLE";
+ break;
+
+ case ERROR_NOT_CONTAINER:
+ strError = "ERROR_NOT_CONTAINER";
+ break;
+
+ case ERROR_INVALID_PARAMETER:
+ strError = "ERROR_INVALID_PARAMETER";
+ break;
+
+ case ERROR_NO_NETWORK:
+ strError = "ERROR_NO_NETWORK";
+ break;
+
+ case ERROR_EXTENDED_ERROR:
+ strError = "ERROR_EXTENDED_ERROR";
+ break;
+
+ default:
+ {
+#endif // _DEBUG
+ DWORD dwErrCode;
+ CString strErrDesc, strProvider;
+ LPTSTR pszErrDesc = strErrDesc.GetBuffer(MAX_STRING);
+ LPTSTR pszProvider = strProvider.GetBuffer(MAX_STRING);
+
+ if (::WNetGetLastError(&dwErrCode, pszErrDesc, MAX_STRING,
+ pszProvider, MAX_STRING) == NO_ERROR)
+ {
+ strErrDesc.ReleaseBuffer();
+ strProvider.ReleaseBuffer();
+
+ CString strErrMsg;
+
+ // Don't display the WNetGetLastError message if dwErrCode == 0.
+ if (dwErrCode)
+ {
+ // Trim of any leading or trailing white space.
+ strProvider.TrimRight();
+ strProvider.TrimLeft();
+ strErrDesc.TrimRight();
+ strErrDesc.TrimLeft();
+ strErrMsg.Format(IDS_NET_ERROR, strProvider, strErrDesc);
+ }
+ else
+ strErrMsg.LoadString(IDS_NET_NO_SERVERS);
+
+ MessageBox(strErrMsg, AfxGetAppName(), MB_OK | MB_ICONEXCLAMATION);
+
+ bNetError = TRUE;
+ }
+ else
+ strError.LoadString(IDS_ERROR);
+#ifdef _DEBUG
+ }
+ }
+#endif // _DEBUG
+
+ if (!bNetError)
+ AfxMessageBox(strError, MB_OK | MB_ICONEXCLAMATION);
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CNetTreeCtrl functions
+
+void CNetTreeCtrl::NotifyThread(BOOL bExit)
+{
+ CCriticalSection cs;
+
+ if (cs.Lock())
+ {
+ m_bExitThread = bExit;
+ cs.Unlock();
+ }
+}
+
+void CNetTreeCtrl::PumpMessages()
+{
+ // Must call Create() before using the dialog
+ ASSERT(m_hWnd!=NULL);
+
+ MSG msg;
+ // Handle dialog messages
+ while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ if(!IsDialogMessage(&msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CNetTreeCtrl message handlers
+
+void CNetTreeCtrl::OnItemExpanding(NMHDR* pNMHDR, LRESULT* pResult)
+{
+ NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
+
+ // Exit and stop expansion if the thread is running.
+ if (m_pThread != NULL)
+ {
+ *pResult = TRUE;
+ return;
+ }
+
+ // Exit if this branch has been expanded once.
+ if (!(pNMTreeView->itemNew.state & TVIS_EXPANDEDONCE))
+ {
+ // Add new leaves to the branch.
+ if (pNMTreeView->itemNew.mask & TVIF_HANDLE)
+ {
+ PopulateTree(FALSE, pNMTreeView->itemNew.hItem);
+ pNMTreeView->itemNew.mask |= TVIS_EXPANDEDONCE;
+ }
+ }
+
+ *pResult = FALSE;
+}
+
+BOOL CNetTreeCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
+{
+ if (m_pThread == NULL)
+ {
+ return CTreeCtrl::OnSetCursor(pWnd, nHitTest, message);
+ }
+ else
+ {
+ // Restore the wait cursor if the thread is running.
+ RestoreWaitCursor();
+
+ return TRUE;
+ }
+}
+
+void CNetTreeCtrl::OnDestroy()
+{
+ NotifyThread(TRUE);
+ PumpMessages();
+
+ CTreeCtrl::OnDestroy();
+}
+
diff --git a/private/utils/wizards/shrpub/nettree.h b/private/utils/wizards/shrpub/nettree.h
new file mode 100644
index 000000000..51410388e
--- /dev/null
+++ b/private/utils/wizards/shrpub/nettree.h
@@ -0,0 +1,92 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ NetTree.h : header file
+
+File History:
+
+ RandyFe Jan-96 created
+
+--*/
+
+//
+/////////////////////////////////////////////////////////////////////////////
+// Global declarations
+
+UINT FillTree(LPVOID pParam);
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CNetTreeCtrl window
+
+class CNetTreeCtrl : public CTreeCtrl
+{
+// Construction
+public:
+ CNetTreeCtrl();
+ virtual ~CNetTreeCtrl();
+
+// Data members
+public:
+ enum
+ {
+ ROOT_LEVEL = 0x0,
+ DOMAIN_LEVEL = 0x1,
+ SERVER_LEVEL = 0x2,
+
+ BUFFER_SIZE = 0x4000,
+ MAX_STRING = 0x100,
+
+ IMG_ROOT = 0,
+ IMG_DOMAIN = 1,
+ IMG_SERVER = 2,
+
+ IMG_SIZE = 16,
+ IMG_GROW = 3,
+ IMG_MASK = RGB(0xFF, 0xFF, 0xFF)
+ };
+
+public:
+ HANDLE m_hHeap;
+ CImageList m_imagelist;
+ CTypedPtrList<CPtrList, LPNETRESOURCE> m_ptrlistContainers;
+ CTypedPtrList<CPtrList, LPTSTR> m_ptrlistStrings;
+ CWinThread* m_pThread;
+ CEvent m_event;
+ BOOL m_bExitThread;
+
+// Attributes
+public:
+
+// Operations
+public:
+ BOOL PopulateTree(BOOL bExpand= TRUE, const HTREEITEM hParentBranch = TVI_ROOT, DWORD dwBufSize = BUFFER_SIZE);
+ void ErrorHandler(const DWORD dwCode);
+ void NotifyThread(BOOL bExit);
+
+protected:
+ void PumpMessages();
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CNetTreeCtrl)
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+
+ // Generated message map functions
+protected:
+ //{{AFX_MSG(CNetTreeCtrl)
+ afx_msg void OnItemExpanding(NMHDR* pNMHDR, LRESULT* pResult);
+ afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
+ afx_msg void OnDestroy();
+ //}}AFX_MSG
+
+ DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/private/utils/wizards/shrpub/permtype.cpp b/private/utils/wizards/shrpub/permtype.cpp
new file mode 100644
index 000000000..c8b657cb1
--- /dev/null
+++ b/private/utils/wizards/shrpub/permtype.cpp
@@ -0,0 +1,654 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ PermType.cpp : implementation file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+#include "stdafx.h"
+#include "turtle.h"
+#include "resource.h"
+#include "wizbased.h"
+#include "PermType.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CPermType dialog
+CPermType::CPermType() : CWizBaseDlg(CPermType::IDD)
+{
+ //{{AFX_DATA_INIT(CPermType)
+ m_nPermRadio = 0;
+ m_nPermType = 0;
+ m_bApplyRecursively = TRUE;
+ //}}AFX_DATA_INIT
+
+// create a CImageList
+ pIList = NULL;
+ pIList = new CImageList;
+ pIList->Create(IDB_IMAGE_LIST2, 18, 1, RGB(0, 255, 0));
+ m_sEntryArrayCount = 0;
+ m_bHasSYSTEM = FALSE;
+ m_dwSysPerm1 = 0;
+ m_dwSysPerm2 = 0;
+
+// load some defaults
+ m_csTempEveryone.LoadString(IDS_SID_EVERYONE);
+ m_csTempInteractive.LoadString(IDS_SID_INTERACTIVE);
+ m_csTempNetwork.LoadString(IDS_SID_NETWORK);
+ m_csTempSystem.LoadString(IDS_SID_SYSTEM);
+
+ m_csSharePath = L"!";
+
+}
+
+CPermType::~CPermType()
+{
+// clean up stored share info
+ short sCount;
+ for (sCount = 0;sCount < m_sEntryArrayCount; sCount++)
+ delete((CDisplayInfo*)m_lEntryArray[sCount]);
+
+ m_sEntryArrayCount = 0;
+
+ if (pIList != NULL) delete pIList;
+}
+
+void CPermType::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CPermType)
+ DDX_Control(pDX, IDC_PERMS_LIST, m_lcPermsList);
+ DDX_Radio(pDX, IDC_PERM_RADIO, m_nPermRadio);
+ DDX_Radio(pDX, IDC_PERM_TYPE_RADIO, m_nPermType);
+ DDX_Check(pDX, IDC_RECURSIVE_CHECK, m_bApplyRecursively);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CPermType, CPropertyPage)
+ //{{AFX_MSG_MAP(CPermType)
+ ON_BN_CLICKED(IDC_PERM_RADIO, OnPermRadioDefault)
+ ON_BN_CLICKED(IDC_PERM_RADIO2, OnPermRadioSpecial)
+ ON_BN_CLICKED(IDC_PERM_TYPE_RADIO, OnPermTypeRadio)
+ ON_BN_CLICKED(IDC_PERM_TYPE_RADIO2, OnPermTypeRadio2)
+ ON_BN_CLICKED(IDC_PERM_TYPE_RADIO3, OnPermTypeRadio3)
+ ON_WM_SHOWWINDOW()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CPermType message handlers
+LRESULT CPermType::OnWizardBack()
+{
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+
+ if (pApp->m_sMode == 1) return IDD_WHAT_TO_SHARE_DLG;
+ else if (pApp->m_sMode == 2) return IDD_HOW_TO_SHARE_DLG;
+ else return IDD_WHAT_TO_SHARE_DLG;
+
+}
+
+LRESULT CPermType::OnWizardNext()
+{
+ UpdateData(TRUE);
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+
+// remove existing permission info from app class
+ short sCount;
+ for (sCount = 0;sCount < pApp->m_sEntryArrayCount; sCount++)
+ delete((CDisplayInfo*)pApp->m_lEntryArray[sCount]);
+
+ pApp->m_sEntryArrayCount = 0;
+
+// copy stored share info to App class
+ for (sCount = 0;sCount < m_sEntryArrayCount; sCount++)
+ {
+ CDisplayInfo* pOldItem = (CDisplayInfo*)m_lEntryArray[sCount];
+ CDisplayInfo* pNewItem = new CDisplayInfo;
+ pNewItem->csName = pOldItem->csName;
+ pNewItem->dwPermission = pOldItem->dwPermission;
+ pNewItem->dwPermission2 = pOldItem->dwPermission2;
+ pNewItem->bAccessDenied = pOldItem->bAccessDenied;
+
+ pApp->m_lEntryArray[sCount] = (long)pNewItem;
+ delete((CDisplayInfo*)m_lEntryArray[sCount]);
+ }
+
+ pApp->m_sEntryArrayCount = m_sEntryArrayCount;
+ m_sEntryArrayCount = 0;
+
+ pApp->m_bApplyRecursively = m_bApplyRecursively;
+
+ if (m_nPermRadio == 0) pApp->m_bSetPermissions = FALSE;
+ else pApp->m_bSetPermissions = TRUE;
+
+ if (pApp->m_sMode == 1) return IDD_FINISH_DIALOG; // NTFS file
+ else if (pApp->m_sMode == 2) return IDD_FINISH_DIALOG; // FAT folder
+ else // NTFS folder
+ {
+ CString csMessage;
+ csMessage.LoadString(IDS_NTFS_VOLUME);
+ if (AfxMessageBox(csMessage, MB_YESNO) == IDYES)
+ {
+ pApp->m_bShareThis = TRUE;
+ return IDD_HOW_TO_SHARE_DLG;
+ }
+ else pApp->m_bShareThis = FALSE;
+ return IDD_FINISH_DIALOG;
+ }
+
+}
+
+BOOL CPermType::OnInitDialog()
+{
+ CPropertyPage::OnInitDialog();
+
+// set the listview in details mode
+ DWORD dwStyle = GetWindowLong(m_lcPermsList.m_hWnd, GWL_STYLE);
+
+ if ((dwStyle & LVS_TYPEMASK) != LVS_REPORT)
+ SetWindowLong(m_lcPermsList.m_hWnd, GWL_STYLE,
+ (dwStyle & ~LVS_TYPEMASK) | LVS_REPORT);
+
+// add columns to the listview
+ CString csColHeader;
+ csColHeader.LoadString(IDS_NAME_COLUMN);
+ if (m_lcPermsList.InsertColumn(0, csColHeader, LVCFMT_LEFT, 225) == -1)
+ return NULL;
+
+ csColHeader.LoadString(IDS_PERM_COLUMN);
+ if (m_lcPermsList.InsertColumn(1, csColHeader, LVCFMT_LEFT, 200) == -1)
+ return NULL;
+
+// add the image list
+ m_lcPermsList.SetImageList(pIList, LVSIL_SMALL);
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+
+LRESULT CPermType::NotifyHandler(UINT message, WPARAM wParam, LPARAM lParam)
+{
+ LV_DISPINFO* pLvdi = (LV_DISPINFO *)lParam;
+ NM_LISTVIEW* pNm = (NM_LISTVIEW *)lParam;
+ CDisplayInfo* pEntry = (CDisplayInfo*)(pLvdi->item.lParam);
+
+ TCHAR* pItem;
+ switch(pLvdi->hdr.code)
+ {
+ case LVN_GETDISPINFO:
+
+ switch (pLvdi->item.iSubItem)
+ {
+ case 0: // Name
+ pItem = pEntry->csName.GetBuffer(pEntry->csName.GetLength());
+ pEntry->csName.ReleaseBuffer();
+ pLvdi->item.pszText = pItem;
+ break;
+
+ case 1: // Permission
+ {
+ pItem = pEntry->csDisplay.GetBuffer(pEntry->csDisplay.GetLength());
+ pEntry->csDisplay.ReleaseBuffer();
+
+ pLvdi->item.pszText = pItem;
+ break;
+ }
+ }
+ break;
+ case LVN_COLUMNCLICK:
+ // The user clicked on one of the column headings - sort by
+ // this column.
+ m_lcPermsList.SortItems( ListViewCompareProc,
+ (LPARAM)(pNm->iSubItem));
+ break;
+
+ }
+ return 0L;
+}
+
+int CALLBACK CPermType::ListViewCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+{
+ CDisplayInfo* pItem1 = (CDisplayInfo*)lParam1;
+ CDisplayInfo* pItem2 = (CDisplayInfo*)lParam2;
+ int iResult = 0;
+
+ if (pItem2 && pItem2)
+ {
+ switch( lParamSort)
+ {
+ case 0: // sort by Names
+ iResult = pItem1->csName.CompareNoCase(pItem2->csName);
+ break;
+
+ case 1: // sort by Permissions
+ iResult = pItem1->csPermission.CompareNoCase(pItem2->csPermission);
+ break;
+
+ default:
+ iResult = 0;
+ break;
+
+ }
+
+ }
+ return(iResult);
+}
+
+LRESULT CPermType::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
+{
+ if (message == WM_NOTIFY)
+ NotifyHandler(message, wParam, lParam);
+
+ return CPropertyPage::WindowProc(message, wParam, lParam);
+}
+
+
+BOOL CPermType::AddEntry(CString csName, DWORD dwPermType, USHORT sImage, BOOL bAccessDenied /* = FALSE*/)
+{
+ CString csPermission;
+ DWORD CHANGE = FILE_GENERIC_READ | FILE_GENERIC_WRITE | DELETE | FILE_EXECUTE; // 0x001301bf
+
+// already added?
+ short sCount = 0;
+ while (sCount < m_sEntryArrayCount)
+ {
+ CDisplayInfo* pInfo = (CDisplayInfo*)m_lEntryArray[sCount];
+ if (!pInfo->csName.CompareNoCase(csName))
+ {
+ pInfo->dwPermission2 = dwPermType;
+
+ if (bAccessDenied) pInfo->csDisplay.LoadString(IDS_SID_NO_ACCESS);
+ else
+ {
+ if ((pInfo->dwPermission == GENERIC_ALL) && (dwPermType == FILE_ALL_ACCESS)) pInfo->csDisplay.LoadString(IDS_SID_FULL_ACCESS);
+ else if ((pInfo->dwPermission == FILE_ALL_ACCESS) && (pInfo->dwPermission2 == FILE_ALL_ACCESS)) pInfo->csDisplay.LoadString(IDS_SID_FULL_ACCESS);
+ else if (pInfo->dwPermission == (GENERIC_READ | GENERIC_EXECUTE))
+ {
+ if ((dwPermType & SPECIFIC_RIGHTS_ALL) == (FILE_READ_ATTRIBUTES | FILE_EXECUTE | FILE_READ_EA | FILE_LIST_DIRECTORY)) pInfo->csDisplay.LoadString(IDS_SID_READ);
+ else if ((dwPermType & SPECIFIC_RIGHTS_ALL) == FILE_GENERIC_READ | FILE_EXECUTE) pInfo->csDisplay.LoadString(IDS_SID_ADD_READ);
+ else pInfo->csDisplay.LoadString(IDS_SID_SPECIAL);
+ }
+ else if ((dwPermType == CHANGE) && (pInfo->dwPermission == (DELETE | GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE))) pInfo->csDisplay.LoadString(IDS_SID_CHANGE);
+ else if ((pInfo->dwPermission == CHANGE) && (pInfo->dwPermission2 == CHANGE)) pInfo->csDisplay.LoadString(IDS_SID_CHANGE);
+ else pInfo->csDisplay.LoadString(IDS_SID_SPECIAL);
+ }
+
+ return TRUE;
+ }
+ sCount++;
+ }
+
+// make a place and store it
+ CDisplayInfo* pNewItem = new CDisplayInfo;
+ pNewItem->csName = csName;
+ pNewItem->dwPermission = dwPermType;
+ pNewItem->dwPermission2 = 0L;
+ pNewItem->bAccessDenied = bAccessDenied;
+ pNewItem->csDisplay.LoadString(IDS_SID_SPECIAL);
+
+ if (bAccessDenied) pNewItem->csDisplay.LoadString(IDS_SID_NO_ACCESS);
+ else
+ {
+ if ((dwPermType & SPECIFIC_RIGHTS_ALL) == (FILE_READ_ATTRIBUTES | FILE_EXECUTE | FILE_READ_EA | FILE_LIST_DIRECTORY)) pNewItem->csDisplay.LoadString(IDS_SID_LIST);
+ else if (dwPermType == FILE_ALL_ACCESS) pNewItem->csDisplay.LoadString(IDS_SID_FULL_ACCESS);
+ else if (dwPermType == FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES | FILE_EXECUTE) pNewItem->csDisplay.LoadString(IDS_SID_ADD);
+ else pNewItem->csDisplay.LoadString(IDS_SID_SPECIAL);
+ }
+
+ m_lEntryArray[m_sEntryArrayCount] = (long)pNewItem;
+ m_sEntryArrayCount++;
+
+ LV_ITEM lvI; // list view item structure
+ // Finally, add the actual items to the control.
+ // Fill out the LV_ITEM structure for each item to add to the list.
+ // The mask specifies that the pszText, iImage, lParam and state
+ // members of the LV_ITEM structure are valid.
+ lvI.mask = LVIF_TEXT | LVIF_PARAM | LVIF_STATE | LVIF_IMAGE;
+ lvI.state = 0;
+ lvI.stateMask = 0;
+ lvI.iImage = sImage;
+
+ lvI.iItem = m_sEntryArrayCount - 1;
+ lvI.iSubItem = 0;
+ // The parent window is responsible for storing the text.
+ // The list view control will send an LVN_GETDISPINFO
+ // when it needs the text to display.
+ lvI.pszText = LPSTR_TEXTCALLBACK;
+ lvI.cchTextMax = MAX_ITEMLEN;
+ lvI.lParam = (long)pNewItem;
+
+ USHORT sSubItem;
+ if (m_lcPermsList.InsertItem(&lvI) == -1)
+ return FALSE;
+
+ for (sSubItem = 1; sSubItem < 2; sSubItem++)
+ m_lcPermsList.SetItemText(m_sEntryArrayCount - 1, sSubItem, LPSTR_TEXTCALLBACK);
+
+ return TRUE;
+}
+
+BOOL CPermType::bSidBlaster(PSECURITY_DESCRIPTOR pSID)
+{
+ BOOL bDACLPresent, bDACLDefaulted;
+ PACL pDACL;
+
+ if (!IsValidSecurityDescriptor(pSID))
+ {
+ AfxMessageBox(IDS_SID_PARSING_ERROR);
+ return FALSE;
+ }
+
+ BOOL bRet = GetSecurityDescriptorDacl(pSID,
+ &bDACLPresent,
+ &pDACL,
+ &bDACLDefaulted);
+
+ if (!bRet)
+ {
+ AfxMessageBox(IDS_SID_PARSING_ERROR);
+ return FALSE;
+ }
+
+ if (!bDACLPresent)
+ {
+ AfxMessageBox(IDS_SID_PARSING_ERROR);
+ return FALSE;
+ }
+
+ ACL_SIZE_INFORMATION aclSize;
+ try
+ {
+ bRet = GetAclInformation(pDACL,
+ &aclSize,
+ sizeof(ACL_SIZE_INFORMATION),
+ AclSizeInformation);
+ }
+ catch(...)
+ {
+ AfxMessageBox(IDS_SID_PARSING_ERROR);
+ return FALSE;
+ }
+
+ if (!bRet)
+ {
+ DWORD dwerr = GetLastError();
+ AfxMessageBox(IDS_SID_PARSING_ERROR);
+ return FALSE;
+ }
+
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+ TCHAR* pServer = pApp->m_csRemoteServer.GetBuffer(pApp->m_csRemoteServer.GetLength());
+ pApp->m_csRemoteServer.ReleaseBuffer();
+
+ ACCESS_ALLOWED_ACE* pAAce;
+ USHORT sCount;
+ USHORT sIconType;
+ CString csEntry;
+
+ for (sCount = 0; sCount < aclSize.AceCount; sCount++)
+ {
+ // get ACE info
+ bRet = GetAce(pDACL, sCount, (LPVOID*) &pAAce);
+ if (!bRet)
+ {
+ AfxMessageBox(IDS_SID_PARSING_ERROR);
+ return FALSE;
+ }
+
+ TCHAR pAccountName[80];
+ TCHAR pDomainName[80];
+ DWORD dwAccountNameSize = 80, pDomainNameSize = 80;
+ SID_NAME_USE sidType;
+
+ bRet = LookupAccountSid( pServer,
+ &pAAce->SidStart,
+ pAccountName, &dwAccountNameSize, pDomainName, &pDomainNameSize, &sidType);
+
+ if (!_tcscmp(pAccountName, L"")) continue;
+
+// build the new entry
+ if (!m_csTempEveryone.CompareNoCase(pAccountName))
+ {
+ csEntry = m_csTempEveryone;
+ sIconType = 2;
+ }
+ else if (!m_csTempInteractive.CompareNoCase(pAccountName))
+ {
+ csEntry = m_csTempInteractive;
+ sIconType = 4;
+ }
+ else if (!m_csTempNetwork.CompareNoCase(pAccountName))
+ {
+ csEntry = m_csTempNetwork;
+ sIconType = 5;
+ }
+ else if (!m_csTempSystem.CompareNoCase(pAccountName))
+ {
+ csEntry = m_csTempSystem;
+ sIconType = 6;
+ m_bHasSYSTEM = TRUE;
+ if (m_dwSysPerm1 != 0) m_dwSysPerm1 = pAAce->Mask;
+ else m_dwSysPerm2 = pAAce->Mask;
+ }
+ else if (sidType == SidTypeGroup)
+ {
+ csEntry = GetCurrentNameInfo(CString(pAccountName), CString(pDomainName));
+ sIconType = 1;
+ }
+ else if (sidType == SidTypeAlias)
+ {
+ csEntry = pAccountName;
+ sIconType = 3;
+ }
+ else
+ {
+ csEntry = GetCurrentNameInfo(CString(pAccountName), CString(pDomainName));
+ sIconType = 0;
+ }
+
+// parse out the permissions
+ if (pAAce->Header.AceType == ACCESS_DENIED_ACE_TYPE) AddEntry(csEntry, pAAce->Mask, sIconType, TRUE);
+ else AddEntry(csEntry, pAAce->Mask, sIconType);
+ }
+ return TRUE;
+}
+
+void CPermType::LoadDefaultPermissions()
+{
+ CWaitCursor wait;
+// reset listcontrol
+ EmptyListControl();
+
+// get the SID for this file/folder
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+
+ if (pApp->m_sMode == 2) // FAT volume
+ {
+ AddEntry(m_csTempEveryone, 0x10000000, 2);
+ AddEntry(m_csTempEveryone, 0x001f01ff, 2);
+ return;
+ }
+
+ SECURITY_DESCRIPTOR* psDesc = NULL;
+ DWORD dwLen = 0;
+
+ if (!GetFileSecurity(pApp->m_csSharePath,
+ DACL_SECURITY_INFORMATION,
+ psDesc,
+ 0L,
+ &dwLen))
+ {
+ DWORD dwErr = GetLastError();
+ if (dwErr== 122) // not enough buffer
+ {
+ psDesc = (SECURITY_DESCRIPTOR*)GlobalAlloc(GPTR, dwLen);
+ GetFileSecurity(pApp->m_csSharePath,
+ DACL_SECURITY_INFORMATION,
+ psDesc,
+ dwLen,
+ &dwLen);
+ }
+ else
+ {
+ AfxMessageBox(IDS_CANT_GET_CUR_INFO);
+ return;
+ }
+ }
+
+ bSidBlaster(psDesc);
+ GlobalFree(psDesc);
+
+}
+
+// accept current permissions (or reset to)
+void CPermType::OnPermRadioDefault()
+{
+ GetDlgItem(IDC_PERM_TYPE_RADIO)->EnableWindow(FALSE);
+ GetDlgItem(IDC_PERM_TYPE_RADIO2)->EnableWindow(FALSE);
+ GetDlgItem(IDC_PERM_TYPE_RADIO3)->EnableWindow(FALSE);
+
+// load the defaults
+ LoadDefaultPermissions();
+
+}
+
+// pick one of the 'special' three
+void CPermType::OnPermRadioSpecial()
+{
+ GetDlgItem(IDC_PERM_TYPE_RADIO)->EnableWindow(TRUE);
+ GetDlgItem(IDC_PERM_TYPE_RADIO2)->EnableWindow(TRUE);
+ GetDlgItem(IDC_PERM_TYPE_RADIO3)->EnableWindow(TRUE);
+
+ UpdateData(TRUE);
+ switch(m_nPermType)
+ {
+ case 0:
+ OnPermTypeRadio();
+ break;
+
+ case 1:
+ OnPermTypeRadio2();
+ break;
+
+ case 2:
+ OnPermTypeRadio3();
+ break;
+ }
+}
+
+// reset the list control
+void CPermType::EmptyListControl()
+{
+// clear out any existing items
+ m_lcPermsList.DeleteAllItems();
+
+// clean up stored share info
+ short sCount;
+ for (sCount = 0;sCount < m_sEntryArrayCount; sCount++)
+ delete((CDisplayInfo*)m_lEntryArray[sCount]);
+
+ m_sEntryArrayCount = 0;
+
+}
+
+// pick which of the 'special' three
+void CPermType::OnPermTypeRadio() // me only
+{
+ EmptyListControl();
+ if (m_bHasSYSTEM)
+ {
+ AddEntry(m_csTempSystem, m_dwSysPerm1, 6);
+ if (m_dwSysPerm2 != 0) AddEntry(m_csTempSystem, m_dwSysPerm2, 6);
+ }
+
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+ CString csME = pApp->m_csMyDomainName;
+ csME += L"\\";
+ csME += pApp->m_csMyUserName;
+ AddEntry(csME, 0x10000000, 0);
+ AddEntry(csME, 0x001f01ff, 0);
+
+}
+
+void CPermType::OnPermTypeRadio2() // me full everyone read
+{
+ EmptyListControl();
+ if (m_bHasSYSTEM)
+ {
+ AddEntry(m_csTempSystem, m_dwSysPerm1, 6);
+ if (m_dwSysPerm2 != 0) AddEntry(m_csTempSystem, m_dwSysPerm2, 6);
+ }
+
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+ CString csME = pApp->m_csMyDomainName;
+ csME += L"\\";
+ csME += pApp->m_csMyUserName;
+ AddEntry(csME, 0x10000000, 0);
+ AddEntry(csME, 0x001f01ff, 0);
+
+ AddEntry(m_csTempEveryone, 0xa0000000, 2);
+ AddEntry(m_csTempEveryone, 0x001200a9, 2);
+
+}
+
+void CPermType::OnPermTypeRadio3() // everyone full
+{
+ EmptyListControl();
+ if (m_bHasSYSTEM)
+ {
+ AddEntry(m_csTempSystem, m_dwSysPerm1, 6);
+ if (m_dwSysPerm2 != 0) AddEntry(m_csTempSystem, m_dwSysPerm2, 6);
+ }
+
+ AddEntry(m_csTempEveryone, 0x10000000, 2);
+ AddEntry(m_csTempEveryone, 0x001f01ff, 2);
+
+}
+
+void CPermType::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CPropertyPage::OnShowWindow(bShow, nStatus);
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+
+ if (bShow)
+ {
+ if (pApp->m_sMode == 1) GetDlgItem(IDC_RECURSIVE_CHECK)->ShowWindow(SW_HIDE); // NTFS file
+ else if (pApp->m_sMode == 2) //FAT volume
+ {
+ GetDlgItem(IDC_RECURSIVE_CHECK)->ShowWindow(SW_SHOW);
+ GetDlgItem(IDC_RECURSIVE_CHECK)->EnableWindow(FALSE);
+ m_bApplyRecursively = TRUE;
+ UpdateData(FALSE);
+ }
+ else if (pApp->m_sMode == 3) // NTFS volume
+ {
+ GetDlgItem(IDC_RECURSIVE_CHECK)->ShowWindow(SW_SHOW);
+ GetDlgItem(IDC_RECURSIVE_CHECK)->EnableWindow(TRUE);
+ m_bApplyRecursively = TRUE;
+ UpdateData(FALSE);
+ }
+
+ // if (m_csSharePath != pApp->m_csSharePath) m_csSharePath = pApp->m_csSharePath;
+ // else return;
+// load the defaults
+ if (m_nPermRadio == 0) LoadDefaultPermissions();
+ else OnPermRadioSpecial();
+ }
+
+}
+
+
diff --git a/private/utils/wizards/shrpub/permtype.h b/private/utils/wizards/shrpub/permtype.h
new file mode 100644
index 000000000..f8c8bde48
--- /dev/null
+++ b/private/utils/wizards/shrpub/permtype.h
@@ -0,0 +1,86 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ PermType.h : header file
+
+File History:
+
+ JonY Jan-96 created
+
+--*/
+
+//
+#define MAX_ITEMLEN 64
+
+/////////////////////////////////////////////////////////////////////////////
+// CPermType dialog
+class CPermType : public CWizBaseDlg
+{
+// Construction
+public:
+ CPermType(); // standard constructor
+ ~CPermType();
+
+// Dialog Data
+ //{{AFX_DATA(CPermType)
+ enum { IDD = IDD_PERM_TYPE_DIALOG };
+ CListCtrl m_lcPermsList;
+ int m_nPermRadio;
+ int m_nPermType;
+ BOOL m_bApplyRecursively;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CPermType)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ LRESULT OnWizardNext();
+ LRESULT OnWizardBack();
+
+ // Generated message map functions
+ //{{AFX_MSG(CPermType)
+ virtual BOOL OnInitDialog();
+ afx_msg void OnPermRadioDefault();
+ afx_msg void OnPermRadioSpecial();
+ afx_msg void OnPermTypeRadio();
+ afx_msg void OnPermTypeRadio2();
+ afx_msg void OnPermTypeRadio3();
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+ static int CALLBACK ListViewCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
+ LRESULT NotifyHandler(UINT message, WPARAM wParam, LPARAM lParam);
+ BOOL AddEntry(CString csName, DWORD dwPermType, USHORT sImage, BOOL bAccessDenied = FALSE);
+
+ USHORT m_sEntryArrayCount;
+ long m_lEntryArray[1000];
+ CImageList* pIList;
+ BOOL m_bHasSYSTEM; // set to true if the file/folder start with the SYSTEM group having access
+ DWORD m_dwSysPerm1;
+ DWORD m_dwSysPerm2;
+
+ BOOL bSidBlaster(PSECURITY_DESCRIPTOR pSID);
+ void LoadDefaultPermissions();
+ void EmptyListControl();
+
+ CString m_csTempEveryone;
+ CString m_csTempInteractive;
+ CString m_csTempNetwork;
+ CString m_csTempSystem;
+
+ CString m_csSharePath;
+
+
+
+};
diff --git a/private/utils/wizards/shrpub/res/bitmap1.bmp b/private/utils/wizards/shrpub/res/bitmap1.bmp
new file mode 100644
index 000000000..2a7f0966d
--- /dev/null
+++ b/private/utils/wizards/shrpub/res/bitmap1.bmp
Binary files differ
diff --git a/private/utils/wizards/shrpub/res/bitmap3.bmp b/private/utils/wizards/shrpub/res/bitmap3.bmp
new file mode 100644
index 000000000..534279c46
--- /dev/null
+++ b/private/utils/wizards/shrpub/res/bitmap3.bmp
Binary files differ
diff --git a/private/utils/wizards/shrpub/res/endflag.bmp b/private/utils/wizards/shrpub/res/endflag.bmp
new file mode 100644
index 000000000..549f1fb80
--- /dev/null
+++ b/private/utils/wizards/shrpub/res/endflag.bmp
Binary files differ
diff --git a/private/utils/wizards/shrpub/res/global.bmp b/private/utils/wizards/shrpub/res/global.bmp
new file mode 100644
index 000000000..aab380fbf
--- /dev/null
+++ b/private/utils/wizards/shrpub/res/global.bmp
Binary files differ
diff --git a/private/utils/wizards/shrpub/res/group.bmp b/private/utils/wizards/shrpub/res/group.bmp
new file mode 100644
index 000000000..c0886c97f
--- /dev/null
+++ b/private/utils/wizards/shrpub/res/group.bmp
Binary files differ
diff --git a/private/utils/wizards/shrpub/res/image_li.bmp b/private/utils/wizards/shrpub/res/image_li.bmp
new file mode 100644
index 000000000..e5b6a140e
--- /dev/null
+++ b/private/utils/wizards/shrpub/res/image_li.bmp
Binary files differ
diff --git a/private/utils/wizards/shrpub/res/interac.bmp b/private/utils/wizards/shrpub/res/interac.bmp
new file mode 100644
index 000000000..5dfa8ad34
--- /dev/null
+++ b/private/utils/wizards/shrpub/res/interac.bmp
Binary files differ
diff --git a/private/utils/wizards/shrpub/res/net_tree.bmp b/private/utils/wizards/shrpub/res/net_tree.bmp
new file mode 100644
index 000000000..0bae4f223
--- /dev/null
+++ b/private/utils/wizards/shrpub/res/net_tree.bmp
Binary files differ
diff --git a/private/utils/wizards/shrpub/res/network.bmp b/private/utils/wizards/shrpub/res/network.bmp
new file mode 100644
index 000000000..1149c1def
--- /dev/null
+++ b/private/utils/wizards/shrpub/res/network.bmp
Binary files differ
diff --git a/private/utils/wizards/shrpub/res/server.bmp b/private/utils/wizards/shrpub/res/server.bmp
new file mode 100644
index 000000000..c04e44d31
--- /dev/null
+++ b/private/utils/wizards/shrpub/res/server.bmp
Binary files differ
diff --git a/private/utils/wizards/shrpub/res/shrpub.bmp b/private/utils/wizards/shrpub/res/shrpub.bmp
new file mode 100644
index 000000000..b51e1b5eb
--- /dev/null
+++ b/private/utils/wizards/shrpub/res/shrpub.bmp
Binary files differ
diff --git a/private/utils/wizards/shrpub/res/system.bmp b/private/utils/wizards/shrpub/res/system.bmp
new file mode 100644
index 000000000..24794ab6e
--- /dev/null
+++ b/private/utils/wizards/shrpub/res/system.bmp
Binary files differ
diff --git a/private/utils/wizards/shrpub/res/turtle.ico b/private/utils/wizards/shrpub/res/turtle.ico
new file mode 100644
index 000000000..31439bf08
--- /dev/null
+++ b/private/utils/wizards/shrpub/res/turtle.ico
Binary files differ
diff --git a/private/utils/wizards/shrpub/res/turtle.rc2 b/private/utils/wizards/shrpub/res/turtle.rc2
new file mode 100644
index 000000000..5b0c5bb76
--- /dev/null
+++ b/private/utils/wizards/shrpub/res/turtle.rc2
@@ -0,0 +1,26 @@
+//
+// TURTLE.RC2 - resources Microsoft Visual C++ does not edit directly
+//
+
+#ifdef APSTUDIO_INVOKED
+ #error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Add manually edited resources here...
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version resources
+//
+#include <winver.h>
+#include <ntverp.h>
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "file / folder access wizard"
+#define VER_INTERNALNAME_STR "turtle.exe"
+#define VER_ORIGINALFILENAME_STR "shrpubw.exe"
+#include <common.ver>
+
+
diff --git a/private/utils/wizards/shrpub/res/user.bmp b/private/utils/wizards/shrpub/res/user.bmp
new file mode 100644
index 000000000..b615d743c
--- /dev/null
+++ b/private/utils/wizards/shrpub/res/user.bmp
Binary files differ
diff --git a/private/utils/wizards/shrpub/res/world.bmp b/private/utils/wizards/shrpub/res/world.bmp
new file mode 100644
index 000000000..d4c1f2a31
--- /dev/null
+++ b/private/utils/wizards/shrpub/res/world.bmp
Binary files differ
diff --git a/private/utils/wizards/shrpub/resource.h b/private/utils/wizards/shrpub/resource.h
new file mode 100644
index 000000000..b092cddc3
--- /dev/null
+++ b/private/utils/wizards/shrpub/resource.h
@@ -0,0 +1,279 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by turtle.rc
+//
+#define IDS_NET_ERROR 8
+#define IDS_NET_NO_SERVERS 9
+#define IDS_ERROR 10
+#define IDP_OLE_INIT_FAILED 100
+#define IDS_FPNW_ERROR_NOSHARE 101
+#define IDD_TURTLE_DIALOG 102
+#define IDS_GENERIC_VOLUME_NOT_UNIQUE 102
+#define IDS_FPNW_NO_SECURITY 103
+#define IDS_GENERIC_NOT_NTFS 104
+#define IDS_GENERIC_PLEASE_SELECT_DIR 105
+#define IDS_GENERIC_NO_DISK 106
+#define IDS_GENERIC_DRIVE_UNACCESSIBLE 107
+#define IDS_GENERIC_NO_PERMISSION 108
+#define IDS_SMB_STRING_NOT_UNIQUE 109
+#define IDS_SMB_NO_SECURITY 110
+#define IDS_GENERIC_INDICATE_SERVICE 111
+#define IDS_GENERIC_NO_PDC 112
+#define IDS_GENERIC_NO_VOLUME 113
+#define IDS_SFM_PASSWORD_MISMATCH 114
+#define IDS_WAIT_LOADING_GROUPS 115
+#define IDS_GENERIC_NO_HEAP 116
+#define IDS_GENERIC_NO_SECURITY 117
+#define IDS_INVALID_SHARE_NAME 118
+#define IDS_INVALID_DIRECTORY_NAME 119
+#define IDS_CANT_CREATE_DIRECTORY 120
+#define IDR_MAINFRAME 128
+#define IDD_BASE_DIALOG 129
+#define IDB_BITMAP1 130
+#define IDD_WHERE_TO_SHARE_DLG 130
+#define IDD_WELCOME_DIALOG 131
+#define IDD_WHAT_TO_SHARE_DLG 132
+#define IDD_HOW_TO_SHARE_DLG 133
+#define IDD_SFM_DIALOG 134
+#define IDD_SMB_INFO_DIALOG 135
+#define IDD_FPNW_INFO_DIALOG 136
+#define IDB_CLOSED_FOLDER_BITMAP 138
+#define IDD_SFM_INFO_DIALOG1 139
+#define IDB_FOLDER_BITMAP 140
+#define IDB_GROUP_BITMAP 141
+#define IDB_LOCAL_GROUP_BITMAP 141
+#define IDB_USER_BITMAP 142
+#define IDB_BITMAP2 145
+#define IDD_WAIT_DIALOG 147
+#define IDD_FINISH_DIALOG 148
+#define IDB_WORLD 152
+#define IDB_GLOBAL_GROUP_BITMAP 155
+#define IDB_NETWORK_BITMAP 158
+#define IDB_SYSTEM_BITMAP 160
+#define IDB_INTERACTIVE_BITMAP 161
+#define IDB_CDDISK_BITMAP 162
+#define IDB_FIXEDDISK_BITMAP 163
+#define IDB_FLOPPYDISK_BITMAP 164
+#define IDB_NETDISK_BITMAP 165
+#define IDB_NET_TREE 166
+#define IDR_ACCELERATOR1 170
+#define IDD_SMALL_WHAT 172
+#define IDD_HOW_MANY_DIALOG 176
+#define IDB_END_FLAG 177
+#define IDB_IMAGE_LIST 178
+#define IDB_IMAGE_LIST2 179
+#define IDD_PERM_TYPE_DIALOG 180
+#define IDD_SPECIAL_ACL_DIALOG 181
+#define IDB_BITMAP3 184
+#define IDC_PAINT_BOX 1000
+#define IDC_PICTURE_BOX 1000
+#define IDC_MACHINE_NAME 1001
+#define IDC_LISTING_TREE 1005
+#define IDC_DRIVE_COMBO 1006
+#define IDC_SMB_CHECK 1007
+#define IDC_SFM_CHECK 1008
+#define IDC_GUEST_ACCESS 1008
+#define IDC_FPNW_CHECK 1009
+#define IDC_READ_ONLY 1009
+#define IDC_EDIT1 1010
+#define IDC_SHARE_NAME 1010
+#define IDC_COUNT_EDIT 1010
+#define IDC_SHARE_NAME_EDIT 1010
+#define IDC_EDIT2 1011
+#define IDC_SFM_GROUP_EDIT 1011
+#define IDC_MANUAL 1011
+#define IDC_SHARE_COMMENT 1011
+#define IDC_CHECK3 1012
+#define IDC_OWNER_SEE_FILES 1012
+#define IDC_MANUAL2 1012
+#define IDC_CHECK4 1013
+#define IDC_OWNER_SEE_FOLDERS 1013
+#define IDC_OWNER_SEE_FILES2 1013
+#define IDC_CHECK5 1014
+#define IDC_OWNER_MAKE_CHANGES 1014
+#define IDC_OWNER_SEE_FOLDERS2 1014
+#define IDC_SERVER_TREE 1014
+#define IDC_CHECK6 1015
+#define IDC_GROUP_SEE_FILES 1015
+#define IDC_OWNER_MAKE_CHANGES2 1015
+#define IDC_CHECK7 1016
+#define IDC_GROUP_SEE_FOLDERS 1016
+#define IDC_GROUP_SEE_FILES2 1016
+#define IDC_CHECK8 1017
+#define IDC_GROUP_MAKE_CHANGES 1017
+#define IDC_GROUP_SEE_FOLDERS2 1017
+#define IDC_CHECK9 1018
+#define IDC_EVERYONE_SEE_FILES 1018
+#define IDC_GROUP_MAKE_CHANGES2 1018
+#define IDC_CHECK10 1019
+#define IDC_EVERYONE_SEE_FOLDERS 1019
+#define IDC_EVERYONE_SEE_FILES2 1019
+#define IDC_CHECK11 1020
+#define IDC_EVERYONE_MAKE_CHANGES 1020
+#define IDC_EVERYONE_SEE_FOLDERS2 1020
+#define IDC_BUTTON1 1021
+#define IDC_EVERYONE_MAKE_CHANGES2 1021
+#define IDC_REMOVE_SHARE_BUTTON 1021
+#define IDC_REMOVE_BUTTON 1021
+#define IDC_BUTTON2 1022
+#define IDC_ADD_NEW_SHARE_BUTTON 1022
+#define IDC_BUTTON3 1023
+#define IDC_EDIT3 1024
+#define IDC_BUTTON4 1024
+#define IDC_VOLUME_NAME 1024
+#define IDC_DIRECTORY_NAME 1024
+#define IDC_FOLDERNAME_EDIT 1024
+#define IDC_EDIT4 1025
+#define IDC_BUTTON5 1025
+#define IDC_PASSWORD 1025
+#define IDC_EDIT5 1026
+#define IDC_CONFIRM_PASSWORD 1026
+#define IDC_FPNW_USER_LIST1 1026
+#define IDC_DIRECTORY_LIST 1026
+#define IDC_SMB_NAMES_LIST 1026
+#define IDC_SERVICES_LIST 1026
+#define IDC_SHARE_LIST 1026
+#define IDC_LIST2 1027
+#define IDC_FPNW_NAMES_LIST 1027
+#define IDC_LIST3 1028
+#define IDC_DOMAIN_COMBO 1028
+#define IDC_LIST4 1029
+#define IDC_BUTTON6 1030
+#define IDC_USER_LIST1 1031
+#define IDC_SFM_OWNER_EDIT 1032
+#define IDC_ADD_OWNER_BUTTON 1033
+#define IDC_REMOVE_OWNER_BUTTON 1034
+#define IDC_ADD_GROUP_BUTTON 1035
+#define IDC_REMOVE_GROUP_BUTTON 1036
+#define IDC_OWNER 1037
+#define IDC_GROUP 1038
+#define IDC_REPLACE_PERMISSIONS 1039
+#define IDC_NO_REMOVE 1040
+#define IDC_SMB_DOMAIN_COMBO 1041
+#define IDC_SMB_USER_LIST 1042
+#define IDC_WAIT_MESSAGE 1043
+#define IDC_FPNW_DOMAIN_COMBO 1044
+#define IDC_READ_LIST 1045
+#define IDC_WRITE_LIST 1046
+#define IDC_ADD_READ_BUTTON 1048
+#define IDC_DEL_READ_BUTTON 1049
+#define IDC_ADD_WRITE_BUTTON 1050
+#define IDC_DEL_WRITE_BUTTON 1051
+#define IDC_NOACC_LIST 1054
+#define IDC_ADD_NOACC_BUTTON 1055
+#define IDC_DEL_NOACC_BUTTON 1056
+#define IDC_FULLAC_LIST 1057
+#define IDC_ADD_FULLAC_BUTTON 1058
+#define IDC_DEL_FULLAC_BUTTON 1059
+#define IDC_DEFAULT_CHECK 1060
+#define IDC_DIRECTORY_NAME_STATIC 1061
+#define IDC_SHARE_NAME_STATIC 1062
+#define IDC_SERVICE_1 1069
+#define IDC_SERVICE_2 1070
+#define IDC_WELCOME 1070
+#define IDC_SERVICE_3 1071
+#define IDC_NETWORK_CHECK 1071
+#define IDC_USER_COUNT_RADIO 1072
+#define IDC_RADIO2 1073
+#define IDC_MAX_USER_SPIN 1074
+#define IDC_LABEL2_STATIC 1076
+#define IDC_LABEL1_STATIC 1077
+#define IDC_WHERE_2_SHARE_RADIO 1078
+#define IDC_NAMES_LIST 1087
+#define IDC_PERM_TYPE_RADIO 1088
+#define IDC_RADIO3 1089
+#define IDC_PERM_TYPE_RADIO3 1089
+#define IDC_RADIO4 1090
+#define IDC_PERM_RADIO2 1090
+#define IDC_PERMS_LIST 1091
+#define IDC_SHARE_RADIO 1092
+#define IDC_STATIC1 1093
+#define IDC_STATIC2 1094
+#define IDC_DONT_SHARE_RADIO 1095
+#define IDC_PERM_RADIO 1096
+#define IDC_PERM_TYPE_RADIO2 1097
+#define IDC_RECURSIVE_CHECK 1098
+#define IDC_STATIC_WHAT 1100
+#define IDC_STATIC_AS 1101
+#define IDC_STATIC_WHO 1102
+#define IDS_SHARE_NAME_TOO_LONG 57345
+#define IDS_FPNW 57346
+#define IDS_SFM 57347
+#define IDS_SMB 57348
+#define IDS_WELCOME 57349
+#define IDS_DEFAULT_ENTRY 57350
+#define IDS_SID_NO_ACCESS 57351
+#define IDS_SID_READ 57352
+#define IDS_SID_CHANGE 57353
+#define IDS_SID_FULL_ACCESS 57354
+#define IDS_SID_EVERYONE 57355
+#define IDS_SID_NETWORK 57356
+#define IDS_SID_INTERACTIVE 57357
+#define IDS_SID_SYSTEM 57358
+#define IDS_SID_DOMAIN_USERS 57359
+#define IDS_PUBLISH_ANOTHER 57360
+#define IDS_SFM_ERROR_NOSHARE 57361
+#define IDS_GENERIC_EVERYONE 57362
+#define IDS_GENERIC_INTERACTIVE 57363
+#define IDS_GENERIC_NETWORK 57364
+#define IDS_GENERIC_SYSTEM 57365
+#define IDS_SMB_ERROR_NOSHARE 57366
+#define IDS_PUBLISH_ANOTHER_ERROR 57367
+#define IDS_SUCCESS_QUIT 57368
+#define IDS_SHARE_NAME_BLANK 57369
+#define IDS_BAD_USER_COUNT 57370
+#define IDS_DOMAIN_SET 57371
+#define IDS_NO_MACHINE_NAME 57372
+#define IDS_GENERIC_BAD_MACHINE 57373
+#define IDS_NO_DC_FOUND 57374
+#define IDS_NO_UNC_PATHS 57375
+#define IDS_NEW_DIR_CREATED 57376
+#define IDS_UNKNOWN_MEDIA_TYPE 57377
+#define IDS_ENUM_ERROR 57378
+#define IDS_NO_SERVER_PERMISSION 57379
+#define IDS_INVALID_DRIVE 57380
+#define IDS_BAD_DIRECTORY_NAME 57381
+#define IDS_SERVER_UNAVAILABLE 57382
+#define IDS_ERROR_QUIT 57383
+#define IDS_SHARE_DELETED 57384
+#define IDS_SHARE_NOT_DELETED 57385
+#define IDS_ALL_SHARES_DELETED 57386
+#define IDS_SHARE_NOT_ALL_DELETED 57387
+#define IDS_GENERIC_NEXT 57388
+#define IDS_GENERIC_MODIFY 57389
+#define IDS_SFM_NESTED_VOLUME 57390
+#define IDS_ALL_SERVICES_USED 57391
+#define IDS_GENERIC_NO_DIR_NAME 57392
+#define IDS_SID_PARSING_ERROR 57393
+#define IDS_CANT_EDIT_SHARE 57394
+#define IDS_SELECT_DELETE 57395
+#define IDS_BAD_VERSION 57396
+#define IDS_FAT_VOLUME 57397
+#define IDS_FAT_FILE 57398
+#define IDS_SID_LIST 57399
+#define IDS_SID_ADD 57400
+#define IDS_SID_ADD_READ 57401
+#define IDS_SID_SPECIAL 57402
+#define IDS_CANT_GET_CUR_INFO 57403
+#define IDS_NTFS_VOLUME 57404
+#define IDS_NO_SFM 57405
+#define IDS_NO_FPNW 57406
+#define IDS_NO_DIR_PERMISSION 57407
+#define IDS_SID_CREATOR_OWNER 57408
+#define IDS_FINISH_SETSHARE 57409
+#define IDS_FINISH_SET 57410
+#define IDS_NAME_COLUMN 57411
+#define IDS_PERM_COLUMN 57412
+#define IDS_CDFS_FILE 57413
+#define IDS_CDFS_VOLUME 57414
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 185
+#define _APS_NEXT_COMMAND_VALUE 32771
+#define _APS_NEXT_CONTROL_VALUE 1103
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/private/utils/wizards/shrpub/shtree.h b/private/utils/wizards/shrpub/shtree.h
new file mode 100644
index 000000000..f736d1792
--- /dev/null
+++ b/private/utils/wizards/shrpub/shtree.h
@@ -0,0 +1,58 @@
+// SHTree.h : header file
+//
+
+#ifndef __SHTREE_H__
+#define __SHTREE_H__
+
+#include "pidl.h"
+
+/////////////////////////////////////////////////////////////////////////////
+// CShellTreeCtrl window
+
+class CShellTreeCtrl : public CTreeCtrl, public CPidlHelper
+{
+// Construction
+public:
+ CShellTreeCtrl();
+
+// Attributes
+protected:
+ BOOL m_bFileObjectsOnly, m_bNoRemovable;
+ int m_nLastFolder;
+
+// Operations
+public:
+ static int CALLBACK TreeCompareProc(LPARAM, LPARAM, LPARAM);
+ void Refresh(int nFolder = -1, BOOL bFileObjectsOnly = FALSE, BOOL bNoRemoveable = FALSE);
+ inline BOOL FileObjectsOnly() {return m_bFileObjectsOnly;}
+ inline BOOL NoRemovable() {return m_bNoRemovable;}
+ CString GetItemText(HTREEITEM hItem, DWORD dwFlags = SHGDN_NORMAL);
+
+protected:
+ void AttachImageList(LPITEMIDLIST pidl);
+ void FillTree(LPSHELLFOLDER lpsf, LPITEMIDLIST lpifq, HTREEITEM hParent);
+ void GetNormalAndSelectedIcons(LPITEMIDLIST lpifq, LPTV_ITEM lptvitem);
+ BOOL DisplayContextMenu(HWND hwnd, LPSHELLFOLDER lpsfParent, LPITEMIDLIST lpi, LPPOINT lppt);
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CShellTreeCtrl)
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CShellTreeCtrl();
+
+ // Generated message map functions
+protected:
+ //{{AFX_MSG(CShellTreeCtrl)
+ afx_msg void OnDeleteItem(NMHDR* pNMHDR, LRESULT* pResult);
+ afx_msg void OnItemExpanding(NMHDR* pNMHDR, LRESULT* pResult);
+ afx_msg void OnRightClick(NMHDR* pNMHDR, LRESULT* pResult);
+ //}}AFX_MSG
+
+ DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // __SHTREE_H__
diff --git a/private/utils/wizards/shrpub/sources b/private/utils/wizards/shrpub/sources
new file mode 100644
index 000000000..46859e3b5
--- /dev/null
+++ b/private/utils/wizards/shrpub/sources
@@ -0,0 +1,60 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+TARGETNAME=shrpubw
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+USE_MFCUNICODE=1
+
+PRECOMPILED_INCLUDE=stdafx.h
+PRECOMPILED_CXX=1
+
+SOURCES=DIRTREE.CPP \
+ FINISH.CPP \
+ HOWTOSHD.CPP \
+ NETTREE.CPP \
+ PERMTYPE.CPP \
+ TRANSBMP.CPP \
+ TURTLE.CPP \
+ WAIT.CPP \
+ WELCOMED.CPP \
+ WHATTOSH.CPP \
+ WIZBASED.CPP \
+ WHERE.CPP \
+ TURTLE.RC
+
+UMTYPE=windows
+UMENTRY=wwinmain
+UMLIBS= $(BASEDIR)\public\sdk\lib\*\netapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\mpr.lib \
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\comdlg32.lib \
+ $(BASEDIR)\public\sdk\lib\*\comctl32.lib \
+ $(BASEDIR)\public\sdk\lib\*\shell32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\gdi32.lib
+
+
diff --git a/private/utils/wizards/shrpub/stdafx.cpp b/private/utils/wizards/shrpub/stdafx.cpp
new file mode 100644
index 000000000..eb62fdde3
--- /dev/null
+++ b/private/utils/wizards/shrpub/stdafx.cpp
@@ -0,0 +1,19 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+// stdafx.cpp : source file that includes just the standard includes
+// turtle.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+#include "stdafx.h"
+
diff --git a/private/utils/wizards/shrpub/stdafx.h b/private/utils/wizards/shrpub/stdafx.h
new file mode 100644
index 000000000..ac57e6b72
--- /dev/null
+++ b/private/utils/wizards/shrpub/stdafx.h
@@ -0,0 +1,38 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+
+File History:
+
+ JonY Jan-96 created
+
+--*/
+
+
+
+//
+#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
+
+#include <afxwin.h> // MFC core and standard components
+#include <afxext.h> // MFC extensions
+//#include <afxdisp.h> // MFC OLE automation classes
+#include <afxtempl.h> // MFC templated classes
+
+//#include <afxdisp.h> // MFC OLE automation classes
+#ifndef _AFX_NO_AFXCMN_SUPPORT
+#include <afxcmn.h> // MFC support for Windows 95 Common Controls
+#endif // _AFX_NO_AFXCMN_SUPPORT
+
+#include <afxtempl.h> // MFC template classes
+#include <afxmt.h> // MFC synchronization classes
+#include <winnetwk.h>
+#include <shlobj.h> // Shell objects
+//#include <afxpriv.h>
+
+
diff --git a/private/utils/wizards/shrpub/transbmp.cpp b/private/utils/wizards/shrpub/transbmp.cpp
new file mode 100644
index 000000000..f7973cd1e
--- /dev/null
+++ b/private/utils/wizards/shrpub/transbmp.cpp
@@ -0,0 +1,175 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+// transbmp.cpp : implementation of the CTransBmp class
+//
+// support for transparent CBitmap objects. Used in the CUserList class.
+// Based on a class from MSDN 7/95
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+#include "stdafx.h"
+#include "transbmp.h"
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char BASED_CODE THIS_FILE[] = __FILE__;
+#endif
+
+// Colors
+#define rgbWhite RGB(255,255,255)
+// Raster op codes
+#define DSa 0x008800C6L
+#define DSx 0x00660046L
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CTransBmp construction/destruction
+
+CTransBmp::CTransBmp()
+{
+ m_iWidth = 0;
+ m_iHeight = 0;
+ m_hbmMask = NULL;
+}
+
+CTransBmp::~CTransBmp()
+{
+ if (m_hbmMask != NULL) delete m_hbmMask;
+}
+
+void CTransBmp::GetMetrics()
+{
+ // Get the width and height
+ BITMAP bm;
+ GetObject(sizeof(bm), &bm);
+ m_iWidth = bm.bmWidth;
+ m_iHeight = bm.bmHeight;
+}
+
+
+int CTransBmp::GetWidth()
+{
+ if ((m_iWidth == 0) || (m_iHeight == 0)){
+ GetMetrics();
+ }
+ return m_iWidth;
+}
+
+int CTransBmp::GetHeight()
+{
+ if ((m_iWidth == 0) || (m_iHeight == 0)){
+ GetMetrics();
+ }
+ return m_iHeight;
+}
+
+
+void CTransBmp::CreateMask(CDC* pDC)
+{
+ m_hbmMask = new CBitmap;
+// Nuke any existing mask
+ if (m_hbmMask) m_hbmMask->DeleteObject();
+
+// Create memory DCs to work with
+ CDC* hdcMask = new CDC;
+ CDC* hdcImage = new CDC;
+
+ hdcMask->CreateCompatibleDC(pDC);
+ hdcImage->CreateCompatibleDC(pDC);
+
+// Create a monochrome bitmap for the mask
+ m_hbmMask->CreateBitmap(GetWidth(),
+ GetHeight(),
+ 1,
+ 1,
+ NULL);
+// Select the mono bitmap into its DC
+ CBitmap* hbmOldMask = hdcMask->SelectObject(m_hbmMask);
+// Select the image bitmap into its DC
+ CBitmap* hbmOldImage = hdcImage->SelectObject(CBitmap::FromHandle((HBITMAP)m_hObject));
+
+// Set the transparency color to be the top-left pixel
+ hdcImage->SetBkColor(hdcImage->GetPixel(0, 0));
+// Make the mask
+ hdcMask->BitBlt(0, 0,
+ GetWidth(), GetHeight(),
+ hdcImage,
+ 0, 0,
+ SRCCOPY);
+// clean up
+ hdcMask->SelectObject(hbmOldMask);
+ hdcImage->SelectObject(hbmOldImage);
+ delete hdcMask;
+ delete hdcImage;
+}
+
+// draw the transparent bitmap using the created mask
+void CTransBmp::DrawTrans(CDC* pDC, int x, int y)
+{
+ if (m_hbmMask == NULL) CreateMask(pDC);
+
+ int dx = GetWidth();
+ int dy = GetHeight();
+
+// Create a memory DC to do the drawing to
+ CDC* hdcOffScr = new CDC;
+ hdcOffScr->CreateCompatibleDC(pDC);
+
+// Create a bitmap for the off-screen DC that is really
+// color compatible with the destination DC.
+ CBitmap hbmOffScr;
+ hbmOffScr.CreateBitmap(dx, dy,
+ pDC->GetDeviceCaps(PLANES),
+ pDC->GetDeviceCaps(BITSPIXEL),
+ NULL);
+
+// Select the buffer bitmap into the off-screen DC
+ HBITMAP hbmOldOffScr = (HBITMAP)hdcOffScr->SelectObject(hbmOffScr);
+
+// Copy the image of the destination rectangle to the
+// off-screen buffer DC so we can play with it
+ hdcOffScr->BitBlt(0, 0, dx, dy, pDC, x, y, SRCCOPY);
+
+// Create a memory DC for the source image
+ CDC* hdcImage = new CDC;
+ hdcImage->CreateCompatibleDC(pDC);
+
+ CBitmap* hbmOldImage = hdcImage->SelectObject(CBitmap::FromHandle((HBITMAP)m_hObject));
+
+ // Create a memory DC for the mask
+ CDC* hdcMask = new CDC;
+ hdcMask->CreateCompatibleDC(pDC);
+
+ CBitmap* hbmOldMask = hdcMask->SelectObject(m_hbmMask);
+
+ // XOR the image with the destination
+ hdcOffScr->SetBkColor(rgbWhite);
+ hdcOffScr->BitBlt(0, 0, dx, dy ,hdcImage, 0, 0, DSx);
+ // AND the destination with the mask
+ hdcOffScr->BitBlt(0, 0, dx, dy, hdcMask, 0,0, DSa);
+ // XOR the destination with the image again
+ hdcOffScr->BitBlt(0, 0, dx, dy, hdcImage, 0, 0, DSx);
+
+ // Copy the resultant image back to the screen DC
+ pDC->BitBlt(x, y, dx, dy, hdcOffScr, 0, 0, SRCCOPY);
+
+ // Tidy up
+ hdcOffScr->SelectObject(hbmOldOffScr);
+ hdcImage->SelectObject(hbmOldImage);
+ hdcMask->SelectObject(hbmOldMask);
+
+ delete hdcOffScr;
+ delete hdcImage;
+ delete hdcMask;
+}
+
+
diff --git a/private/utils/wizards/shrpub/transbmp.h b/private/utils/wizards/shrpub/transbmp.h
new file mode 100644
index 000000000..7be2ea8b9
--- /dev/null
+++ b/private/utils/wizards/shrpub/transbmp.h
@@ -0,0 +1,40 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ transbmp.h : interface of the CTransBitmap class
+
+File History:
+
+ JonY Jan-96 created
+
+--*/
+
+
+//
+/////////////////////////////////////////////////////////////////////////////
+
+class CTransBmp : public CBitmap
+{
+public:
+ CTransBmp();
+ ~CTransBmp();
+ void Draw(HDC hDC, int x, int y);
+ void Draw(CDC* pDC, int x, int y);
+ void DrawTrans(HDC hDC, int x, int y);
+ void DrawTrans(CDC* pDC, int x, int y);
+ int GetWidth();
+ int GetHeight();
+private:
+ int m_iWidth;
+ int m_iHeight;
+
+ void GetMetrics();
+ CBitmap* m_hbmMask; // handle to mask bitmap
+ void CreateMask(CDC* pDC);
+
+};
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/private/utils/wizards/shrpub/turtle.cpp b/private/utils/wizards/shrpub/turtle.cpp
new file mode 100644
index 000000000..31d873b23
--- /dev/null
+++ b/private/utils/wizards/shrpub/turtle.cpp
@@ -0,0 +1,995 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ turtle.cpp : Defines the class behaviors for the application.
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+// The application class.
+#include "stdafx.h"
+#include "resource.h" // main symbols
+
+#include "turtle.h"
+#include "wizbased.h"
+#include "welcomed.h"
+#include "dirtree.h"
+#include "whattosh.h"
+#include "howtoshd.h"
+#include "finish.h"
+#include "nettree.h"
+#include "where.h"
+#include "permtype.h"
+
+#include <lmcons.h>
+#include <lmaccess.h>
+#include <lmerr.h>
+#include <lmapibuf.h>
+#include <winnetwk.h>
+
+#include <direct.h>
+#include <windef.h>
+#include <lmshare.h>
+
+#include <winreg.h>
+#include <malloc.h>
+
+#include "fpnwapi.h"
+#include "macfile.h"
+
+#include "wait.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+TCHAR pszTreeEvent[] = _T("TreeThread");
+
+// some global objects used in the EnumUsers and EnumGroups threads
+CStringList csaNames;
+CStringList csaGroups;
+
+typedef DWORD (*FPNWVOLUMEADD)(LPWSTR, DWORD, LPBYTE);
+
+typedef DWORD (*AFPADMINCONNECT)(LPTSTR, PAFP_SERVER_HANDLE);
+typedef VOID (*AFPADMINDISCONNECT)(AFP_SERVER_HANDLE);
+typedef DWORD (*AFPADMINVOLUMEADD)(AFP_SERVER_HANDLE, LPBYTE);
+
+/////////////////////////////////////////////////////////////////////////////
+// CTurtleApp
+
+BEGIN_MESSAGE_MAP(CTurtleApp, CWinApp)
+ //{{AFX_MSG_MAP(CTurtleApp)
+ //}}AFX_MSG
+// ON_COMMAND(ID_HELP, CWinApp::OnHelp)
+ ON_COMMAND(ID_CONTEXT_HELP, CWinApp::OnContextHelp)
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CTurtleApp construction
+
+CTurtleApp::CTurtleApp()
+{
+ m_bGoFPNW = FALSE;
+ m_bGoSFM = FALSE;
+ m_bGoSMB = TRUE;
+
+ m_bPermitSFM = TRUE;
+ m_bPermitFPNW = TRUE;
+ m_bPermitSMB = TRUE;
+
+ m_bShareThis = FALSE;
+
+// load and store some default information
+ DWORD dwRet;
+ HKEY hKey;
+ DWORD cbProv = 0;
+ TCHAR* lpProv = NULL;
+
+// check for OS version
+ OSVERSIONINFO os;
+ os.dwOSVersionInfoSize = sizeof(os);
+ GetVersionEx(&os);
+
+ if (os.dwMajorVersion < 4)
+ {
+ AfxMessageBox(IDS_BAD_VERSION, MB_ICONSTOP);
+ ExitProcess(0);
+ }
+
+// get some current system and user information
+ dwRet = RegOpenKey(HKEY_LOCAL_MACHINE,
+ TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"), &hKey );
+
+ TCHAR* lpDefaultDomainName = NULL;
+ if ((dwRet = RegQueryValueEx( hKey, TEXT("DefaultDomainName"), NULL, NULL, NULL, &cbProv )) == ERROR_SUCCESS)
+ {
+ lpDefaultDomainName = (TCHAR*)malloc(cbProv);
+ if (lpDefaultDomainName == NULL)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
+ ExitProcess(1);
+ }
+
+ dwRet = RegQueryValueEx( hKey, TEXT("DefaultDomainName"), NULL, NULL, (LPBYTE) lpDefaultDomainName, &cbProv );
+
+ }
+
+ TCHAR* lpDefaultUserName = NULL;
+ if ((dwRet = RegQueryValueEx( hKey, TEXT("DefaultUserName"), NULL, NULL, NULL, &cbProv )) == ERROR_SUCCESS)
+ {
+ lpDefaultUserName = (TCHAR*)malloc(cbProv);
+ if (lpDefaultUserName == NULL)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
+ ExitProcess(1);
+ }
+
+ dwRet = RegQueryValueEx( hKey, TEXT("DefaultUserName"), NULL, NULL, (LPBYTE) lpDefaultUserName, &cbProv );
+
+ }
+
+ TCHAR* lpPrimaryDomain = NULL;
+ if ((dwRet = RegQueryValueEx( hKey, TEXT("CachePrimaryDomain"), NULL, NULL, NULL, &cbProv )) == ERROR_SUCCESS)
+ {
+ lpPrimaryDomain = (TCHAR*)malloc(cbProv);
+ if (lpPrimaryDomain == NULL)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
+ ExitProcess(1);
+ }
+
+ dwRet = RegQueryValueEx( hKey, TEXT("CachePrimaryDomain"), NULL, NULL, (LPBYTE) lpPrimaryDomain, &cbProv );
+
+ }
+
+ RegCloseKey(hKey);
+ dwRet = RegOpenKey(HKEY_LOCAL_MACHINE,
+ TEXT("SYSTEM\\CurrentControlSet\\Control\\ComputerName\\ActiveComputerName"), &hKey );
+
+ TCHAR* lpMachineName = NULL;
+ if ((dwRet = RegQueryValueEx( hKey, TEXT("ComputerName"), NULL, NULL, NULL, &cbProv )) == ERROR_SUCCESS)
+ {
+ lpMachineName = (TCHAR*)malloc(cbProv);
+ if (lpMachineName == NULL)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
+ ExitProcess(1);
+ }
+
+ dwRet = RegQueryValueEx( hKey, TEXT("ComputerName"), NULL, NULL, (LPBYTE) lpMachineName, &cbProv );
+
+ }
+
+ m_csMyDomainName = lpDefaultDomainName;
+ m_csMyUserName = lpDefaultUserName;
+ m_csMyMachineName = "\\\\";
+ m_csMyMachineName += lpMachineName;
+ m_csPrimaryDomain = lpPrimaryDomain;
+
+ RegCloseKey(hKey);
+ free(lpDefaultUserName);
+ free(lpDefaultDomainName);
+ free(lpMachineName);
+ free(lpPrimaryDomain);
+
+ m_pACL = NULL;
+
+}
+
+CTurtleApp::~CTurtleApp()
+{
+// clean up stored share info
+ short sCount;
+ for (sCount = 0;sCount < m_sEntryArrayCount; sCount++)
+ delete((CDisplayInfo*)m_lEntryArray[sCount]);
+
+ m_sEntryArrayCount = 0;
+
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// The one and only CTurtleApp object
+
+CTurtleApp theApp;
+
+/////////////////////////////////////////////////////////////////////////////
+// CTurtleApp initialization
+BOOL CTurtleApp::IsSecondInstance()
+{
+ HANDLE hSem;
+
+ //create a semaphore object with max count of 1
+ hSem = CreateSemaphore(NULL, 0, 1, L"DirPub Wizard Semaphore");
+ if (hSem!=NULL && GetLastError() == ERROR_ALREADY_EXISTS) {
+ CloseHandle(hSem);
+ CString csAppName;
+ csAppName.LoadString(AFX_IDS_APP_TITLE);
+ CWnd* pWnd = CWnd::FindWindow(NULL, (LPCTSTR)csAppName);
+ if (pWnd)
+ pWnd->SetForegroundWindow();
+ return TRUE;
+ }
+
+ return FALSE;
+
+}
+
+BOOL CTurtleApp::InitInstance()
+{
+// Standard initialization
+ if (IsSecondInstance())
+ return FALSE;
+
+ // Standard initialization
+ InitCommonControls();
+#ifdef _AFXDLL
+ Enable3dControls(); // Call this when using MFC in a shared DLL
+#else
+ Enable3dControlsStatic(); // Call this when linking to MFC statically
+#endif
+
+// create the property sheet,set 'wizmode' & set app icon
+ m_cps1.SetTitle(TEXT("Directory Publishing Wizard"), 0);
+
+ m_cps1.SetWizardMode();
+ m_cps1.m_psh.dwFlags |= PSH_USEICONID;
+ m_cps1.m_psh.pszIcon = MAKEINTRESOURCE(IDR_MAINFRAME);
+
+// create the dialogs
+ CWelcomeDlg* pWelcome = new CWelcomeDlg;
+ if (pWelcome == 0)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
+ ExitProcess(1);
+ }
+
+ CWhere* pWhere = new CWhere;
+ if (pWhere == 0)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
+ ExitProcess(1);
+ }
+
+ CWhatToShareDlg* pWhat = new CWhatToShareDlg;
+ if (pWhat == 0)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
+ ExitProcess(1);
+ }
+
+ CHowToShareDlg* pHow = new CHowToShareDlg;
+ if (pHow == 0)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
+ ExitProcess(1);
+ }
+
+ CFinish* pFinish = new CFinish;
+ if (pFinish == 0)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
+ ExitProcess(1);
+ }
+
+ CPermType* pType = new CPermType;
+ if (pType == 0)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
+ ExitProcess(1);
+ }
+
+
+// add them to the wizard
+ m_cps1.AddPage(pWelcome);
+ m_cps1.AddPage(pWhere);
+ m_cps1.AddPage(pWhat);
+ m_cps1.AddPage(pType);
+ m_cps1.AddPage(pHow);
+ m_cps1.AddPage(pFinish);
+
+// show the wizard
+ m_cps1.DoModal();
+
+// clean up
+ delete pWelcome;
+ delete pWhere;
+ delete pWhat;
+ delete pType;
+ delete pHow;
+ delete pFinish;
+
+// Since the dialog has been closed, return FALSE so that we exit the
+// application, rather than start the application's message pump.
+ return FALSE;
+}
+
+// ** this section needs to be reorganized. I patched in the CDFS code late in the game. **
+
+// This gets called from CFinish when 'finish' is clicked. It instructs the selected services
+// to create the share(s) and set permissions
+BOOL CTurtleApp::DoSharing()
+{
+ BOOL bRet = TRUE;
+// create security descriptor
+ SECURITY_DESCRIPTOR* pSD = new SECURITY_DESCRIPTOR;
+
+ if (!CreateSID(pSD))
+ {
+ AfxMessageBox(IDS_GENERIC_NO_SECURITY);
+ return FALSE;
+ }
+
+ switch(m_sMode)
+ {
+ case 1: // NTFS file
+ {
+ if (!m_bSetPermissions) return TRUE;
+ bRet = SetFileSecurity(m_csSharePath,
+ DACL_SECURITY_INFORMATION,
+ pSD);
+
+ break;
+ }
+
+ case 2: // FAT volume
+ {
+ TCHAR* pShare = (TCHAR*)malloc((m_csSharePath.GetLength() + 1) * sizeof(TCHAR));
+ if (pShare == NULL)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONSTOP);
+ ExitProcess(1);
+ }
+
+ TCHAR* ppShare = pShare;
+
+ _tcscpy(pShare, (const TCHAR*)m_csSharePath);
+ _tcscat(pShare, TEXT("\0"));
+
+ TCHAR* pShareName = m_csShareName.GetBuffer(m_csShareName.GetLength());
+ m_csShareName.ReleaseBuffer();
+
+ TCHAR* pServer = (LPTSTR)m_csRemoteServer.GetBuffer(m_csRemoteServer.GetLength());
+ m_csRemoteServer.ReleaseBuffer();
+
+ TCHAR* pVolumeName = (LPTSTR)m_csShareName.GetBuffer(m_csShareName.GetLength());
+ m_csShareName.ReleaseBuffer();
+
+ if (m_bGoSMB)
+ {
+ SHARE_INFO_502* sInfo = (SHARE_INFO_502*)malloc((sizeof(SHARE_INFO_502) + 1) * sizeof(TCHAR));
+ if (sInfo == NULL)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP);
+ ExitProcess(1);
+ }
+
+ sInfo->shi502_netname = pVolumeName;
+
+ sInfo->shi502_type = STYPE_DISKTREE;
+ sInfo->shi502_remark = (LPTSTR)m_csShareComment.GetBuffer(m_csShareComment.GetLength());
+ m_csShareComment.ReleaseBuffer();
+
+ sInfo->shi502_permissions = NULL;
+ sInfo->shi502_max_uses = (ULONG)-1;
+ sInfo->shi502_current_uses = 0;
+
+ if (m_csRemoteServer != L"")
+ {
+ sInfo->shi502_path = m_csRemoteServerPath.GetBuffer(m_csRemoteServerPath.GetLength());
+ m_csRemoteServerPath.ReleaseBuffer();
+ }
+ else sInfo->shi502_path = pShare;
+
+ sInfo->shi502_passwd = NULL;
+ sInfo->shi502_reserved = NULL;
+
+
+ sInfo->shi502_security_descriptor = pSD;
+
+ DWORD dwRetVal = 0;
+ DWORD dwErr = 0;
+
+ NET_API_STATUS dwNet;
+// create the share
+ dwNet = NetShareAdd(pServer,
+ 502,
+ (LPBYTE)sInfo,
+ &dwRetVal);
+
+ if (dwNet != 0)
+ {
+ AfxMessageBox(IDS_SMB_ERROR_NOSHARE);
+ dwErr = GetLastError();
+ bRet = FALSE;
+ }
+
+ free(sInfo);
+ }
+
+ if (m_bGoFPNW)
+ {
+// load the pointer to the FPNW functions
+ HINSTANCE hInst = LoadLibrary(TEXT("fpnwclnt.dll"));
+ FPNWVOLUMEADD pFPNWVolumeAdd = (FPNWVOLUMEADD)GetProcAddress(hInst, "FpnwVolumeAdd");
+
+ FPNWVOLUMEINFO_2* pVolumeInfo2 = new FPNWVOLUMEINFO_2;
+ if (pVolumeInfo2 == 0)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONSTOP);
+ ExitProcess(1);
+ }
+
+ pVolumeInfo2->lpVolumeName = pVolumeName;
+
+ pVolumeInfo2->dwType = FPNWVOL_TYPE_DISKTREE;
+ pVolumeInfo2->dwMaxUses = (ULONG)-1; // unlimited
+ pVolumeInfo2->dwCurrentUses = 0;
+
+ if (m_csRemoteServer != L"")
+ {
+ pVolumeInfo2->lpPath = m_csRemoteServerPath.GetBuffer(m_csRemoteServerPath.GetLength());
+ m_csRemoteServerPath.ReleaseBuffer();
+ }
+ else pVolumeInfo2->lpPath = pShare;
+
+ pVolumeInfo2->FileSecurityDescriptor = pSD;
+
+ DWORD dwRetVal = 0;
+
+// create the volume
+ dwRetVal = (*pFPNWVolumeAdd)(pServer, 2, (LPBYTE)pVolumeInfo2);
+ if (dwRetVal != 0)
+ {
+ AfxMessageBox(IDS_FPNW_ERROR_NOSHARE);
+ bRet = FALSE;
+ }
+
+// clean up
+ delete pVolumeInfo2;
+ FreeLibrary(hInst);
+ }
+
+ if (m_bGoSFM) // this will only apply to CDFS volumes
+ {
+// load the function prototypes
+ HINSTANCE hLibInst = LoadLibrary(_T("sfmapi.dll"));
+ if (hLibInst == NULL)
+ {
+ AfxMessageBox(IDS_SFM_ERROR_NOSHARE);
+ return FALSE;
+ }
+
+ AFPADMINCONNECT pAfpAdminConnect = (AFPADMINCONNECT) GetProcAddress(hLibInst, "AfpAdminConnect");
+ AFPADMINDISCONNECT pAfpAdminDisconnect = (AFPADMINDISCONNECT) GetProcAddress(hLibInst, "AfpAdminDisconnect");
+ AFPADMINVOLUMEADD pAfpAdminVolumeAdd = (AFPADMINVOLUMEADD) GetProcAddress(hLibInst, "AfpAdminVolumeAdd");
+
+ LPTSTR lpServerName = NULL;
+// is this a share on a remote machine?
+ if (m_csRemoteServerPath != "")
+ {
+ lpServerName = (LPTSTR)m_csRemoteServer.GetBuffer(m_csRemoteServer.GetLength());
+ lpServerName += 2;
+ m_csRemoteServer.ReleaseBuffer();
+ }
+
+// get an SFM server handle
+ DWORD dwRetCode;
+ AFP_SERVER_HANDLE hAfpServerHandle;
+ dwRetCode = (*pAfpAdminConnect)(lpServerName, &hAfpServerHandle);
+ if (dwRetCode != NO_ERROR)
+ {
+ AfxMessageBox(IDS_SFM_ERROR_NOSHARE);
+ return FALSE;
+ }
+
+// set volume options
+ AFP_VOLUME_INFO AfpVolumeInfo;
+ if (m_csRemoteServer != L"")
+ {
+ AfpVolumeInfo.afpvol_path = m_csRemoteServerPath.GetBuffer(m_csRemoteServerPath.GetLength());
+ m_csRemoteServerPath.ReleaseBuffer();
+ }
+ else AfpVolumeInfo.afpvol_path = pShare;
+
+ AfpVolumeInfo.afpvol_name = pVolumeName;
+ AfpVolumeInfo.afpvol_password = NULL;
+ AfpVolumeInfo.afpvol_props_mask = 0;
+ AfpVolumeInfo.afpvol_props_mask |= AFP_VOLUME_GUESTACCESS;
+
+// User limit
+ AfpVolumeInfo.afpvol_max_uses = AFP_VOLUME_UNLIMITED_USES;
+
+// create the new volume
+ dwRetCode = (*pAfpAdminVolumeAdd)(hAfpServerHandle, (LPBYTE)&AfpVolumeInfo);
+ if (dwRetCode == AFPERR_NestedVolume)
+ {
+ AfxMessageBox(IDS_SFM_NESTED_VOLUME, MB_ICONSTOP);
+ return FALSE;
+ }
+
+ else if (dwRetCode != NO_ERROR)
+ {
+ AfxMessageBox(IDS_SFM_ERROR_NOSHARE);
+ return FALSE;
+ }
+// disconnect from the server
+// (*pAfpAdminDisconnect)(hAfpServerHandle);
+
+// clean up
+ FreeLibrary(hLibInst);
+
+ }
+
+ free(ppShare);
+ }
+ break;
+
+ case 3: // NTFS volume
+ {
+ if (m_bSetPermissions) bRet = SetFileSecurity(m_csSharePath,
+ DACL_SECURITY_INFORMATION,
+ pSD);
+
+// apply perms to subdirs and files?
+ if (m_bApplyRecursively) ApplyDownStream((const TCHAR*)m_csSharePath, pSD);
+
+ if (!bRet)
+ {
+ DWORD dw = GetLastError();
+ ASSERT(0);
+ }
+
+ TCHAR* pShare = (TCHAR*)malloc((m_csSharePath.GetLength() + 1) * sizeof(TCHAR));
+ if (pShare == NULL)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONSTOP);
+ ExitProcess(1);
+ }
+
+ TCHAR* ppShare = pShare;
+
+ _tcscpy(pShare, (const TCHAR*)m_csSharePath);
+ _tcscat(pShare, TEXT("\0"));
+
+ TCHAR* pShareName = m_csShareName.GetBuffer(m_csShareName.GetLength());
+ m_csShareName.ReleaseBuffer();
+
+ TCHAR* pServer = (LPTSTR)m_csRemoteServer.GetBuffer(m_csRemoteServer.GetLength());
+ m_csRemoteServer.ReleaseBuffer();
+
+ TCHAR* pVolumeName = (LPTSTR)m_csShareName.GetBuffer(m_csShareName.GetLength());
+ m_csShareName.ReleaseBuffer();
+
+ if (m_bGoFPNW && m_bShareThis)
+ {
+// load the pointer to the FPNW functions
+ HINSTANCE hInst = LoadLibrary(TEXT("fpnwclnt.dll"));
+ FPNWVOLUMEADD pFPNWVolumeAdd = (FPNWVOLUMEADD)GetProcAddress(hInst, "FpnwVolumeAdd");
+
+ FPNWVOLUMEINFO_2* pVolumeInfo2 = new FPNWVOLUMEINFO_2;
+ if (pVolumeInfo2 == 0)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONSTOP);
+ ExitProcess(1);
+ }
+
+ pVolumeInfo2->lpVolumeName = pVolumeName;
+
+ pVolumeInfo2->dwType = FPNWVOL_TYPE_DISKTREE;
+ pVolumeInfo2->dwMaxUses = (ULONG)-1; // unlimited
+ pVolumeInfo2->dwCurrentUses = 0;
+
+ if (m_csRemoteServer != L"")
+ {
+ pVolumeInfo2->lpPath = m_csRemoteServerPath.GetBuffer(m_csRemoteServerPath.GetLength());
+ m_csRemoteServerPath.ReleaseBuffer();
+ }
+ else pVolumeInfo2->lpPath = pShare;
+
+ pVolumeInfo2->FileSecurityDescriptor = NULL;
+
+ DWORD dwRetVal = 0;
+
+// create the volume
+ dwRetVal = (*pFPNWVolumeAdd)(pServer, 2, (LPBYTE)pVolumeInfo2);
+ if (dwRetVal != 0)
+ {
+ AfxMessageBox(IDS_FPNW_ERROR_NOSHARE);
+ bRet = FALSE;
+ }
+
+// clean up
+ delete pVolumeInfo2;
+ FreeLibrary(hInst);
+ }
+
+ if (m_bGoSMB && m_bShareThis)
+ {
+ SHARE_INFO_502* sInfo = (SHARE_INFO_502*)malloc((sizeof(SHARE_INFO_502) + 1) * sizeof(TCHAR));
+ if (sInfo == NULL)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP);
+ ExitProcess(1);
+ }
+
+ sInfo->shi502_netname = pVolumeName;
+
+ sInfo->shi502_type = STYPE_DISKTREE;
+ sInfo->shi502_remark = (LPTSTR)m_csShareComment.GetBuffer(m_csShareComment.GetLength());
+ m_csShareComment.ReleaseBuffer();
+
+ sInfo->shi502_permissions = NULL;
+ sInfo->shi502_max_uses = (ULONG)-1;
+ sInfo->shi502_current_uses = 0;
+
+ if (m_csRemoteServer != L"")
+ {
+ sInfo->shi502_path = m_csRemoteServerPath.GetBuffer(m_csRemoteServerPath.GetLength());
+ m_csRemoteServerPath.ReleaseBuffer();
+ }
+ else sInfo->shi502_path = pShare;
+
+ sInfo->shi502_passwd = NULL;
+ sInfo->shi502_reserved = NULL;
+
+ sInfo->shi502_security_descriptor = NULL;
+
+ DWORD dwRetVal = 0;
+ DWORD dwErr = 0;
+
+ NET_API_STATUS dwNet;
+// create the share
+ dwNet = NetShareAdd(pServer,
+ 502,
+ (LPBYTE)sInfo,
+ &dwRetVal);
+
+ if (dwNet != 0)
+ {
+ AfxMessageBox(IDS_SMB_ERROR_NOSHARE);
+ dwErr = GetLastError();
+ bRet = FALSE;
+ }
+
+ free(sInfo);
+ }
+
+
+ if (m_bGoSFM && m_bShareThis)
+ {
+// load the function prototypes
+ HINSTANCE hLibInst = LoadLibrary(_T("sfmapi.dll"));
+ if (hLibInst == NULL)
+ {
+ AfxMessageBox(IDS_SFM_ERROR_NOSHARE);
+ return FALSE;
+ }
+
+ AFPADMINCONNECT pAfpAdminConnect = (AFPADMINCONNECT) GetProcAddress(hLibInst, "AfpAdminConnect");
+ AFPADMINDISCONNECT pAfpAdminDisconnect = (AFPADMINDISCONNECT) GetProcAddress(hLibInst, "AfpAdminDisconnect");
+ AFPADMINVOLUMEADD pAfpAdminVolumeAdd = (AFPADMINVOLUMEADD) GetProcAddress(hLibInst, "AfpAdminVolumeAdd");
+
+ LPTSTR lpServerName = NULL;
+// is this a share on a remote machine?
+ if (m_csRemoteServerPath != "")
+ {
+ lpServerName = (LPTSTR)m_csRemoteServer.GetBuffer(m_csRemoteServer.GetLength());
+ lpServerName += 2;
+ m_csRemoteServer.ReleaseBuffer();
+ }
+
+// get an SFM server handle
+ DWORD dwRetCode;
+ AFP_SERVER_HANDLE hAfpServerHandle;
+ dwRetCode = (*pAfpAdminConnect)(lpServerName, &hAfpServerHandle);
+ if (dwRetCode != NO_ERROR)
+ {
+ AfxMessageBox(IDS_SFM_ERROR_NOSHARE);
+ return FALSE;
+ }
+
+// set volume options
+ AFP_VOLUME_INFO AfpVolumeInfo;
+ if (m_csRemoteServer != L"")
+ {
+ AfpVolumeInfo.afpvol_path = m_csRemoteServerPath.GetBuffer(m_csRemoteServerPath.GetLength());
+ m_csRemoteServerPath.ReleaseBuffer();
+ }
+ else AfpVolumeInfo.afpvol_path = pShare;
+
+ AfpVolumeInfo.afpvol_name = pVolumeName;
+ AfpVolumeInfo.afpvol_password = NULL;
+ AfpVolumeInfo.afpvol_props_mask = 0;
+ AfpVolumeInfo.afpvol_props_mask |= AFP_VOLUME_GUESTACCESS;
+
+// User limit
+ AfpVolumeInfo.afpvol_max_uses = AFP_VOLUME_UNLIMITED_USES;
+
+// create the new volume
+ dwRetCode = (*pAfpAdminVolumeAdd)(hAfpServerHandle, (LPBYTE)&AfpVolumeInfo);
+ if (dwRetCode == AFPERR_NestedVolume)
+ {
+ AfxMessageBox(IDS_SFM_NESTED_VOLUME, MB_ICONSTOP);
+ return FALSE;
+ }
+
+ else if (dwRetCode != NO_ERROR)
+ {
+ AfxMessageBox(IDS_SFM_ERROR_NOSHARE);
+ return FALSE;
+ }
+// disconnect from the server
+ (*pAfpAdminDisconnect)(hAfpServerHandle);
+
+// clean up
+ FreeLibrary(hLibInst);
+
+ }
+
+ free(ppShare);
+ }
+ break;
+ }
+
+ delete pSD;
+ free(m_pACL);
+ return bRet;
+
+}
+
+
+short CTurtleApp::sParseAdminPath(CString& csDirectoryName, CString& csCurrentDrive)
+{
+ m_csRemoteServerDrivePath = csDirectoryName.Left(1) + ":\\";
+ if (csDirectoryName.GetAt(1) == ':') csDirectoryName.SetAt(1, '$');
+ m_csSharePath = csDirectoryName ;
+ m_csSharePath.SetAt(1,':');
+
+ m_csRemoteServerPath = m_csSharePath;
+
+ csCurrentDrive = m_csServer + "\\" + csDirectoryName.Left(2) + "\\";
+
+// test for valid entry - at this point we are forcing either admin$ shares only (ie C$, D$) (UNC paths are handled above)
+ if (csDirectoryName.GetAt(1) != '$') return 1;
+
+// since we don't have a current dir on the remote drive, force all dirs to start at the root
+ if (csDirectoryName.GetAt(2) != '\\')
+ {
+ short sLen = csDirectoryName.GetLength();
+ csDirectoryName = csDirectoryName.Left(2) + "\\" + csDirectoryName.Right(sLen - 2);
+ }
+
+// test for valid drive letter
+ CString csTempDrive;
+ GetCurrentDirectory(256, csTempDrive.GetBufferSetLength(256));
+ if (!SetCurrentDirectory((LPCTSTR)csCurrentDrive)) return 2;
+
+ SetCurrentDirectory(csTempDrive);
+
+ csDirectoryName = m_csServer + "\\" + csDirectoryName;
+ m_csRemoteServer = m_csServer;
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// CMySheet
+
+IMPLEMENT_DYNAMIC(CMySheet, CPropertySheet)
+
+CMySheet::CMySheet(UINT nIDCaption, CWnd* pParentWnd, UINT iSelectPage)
+ :CPropertySheet(nIDCaption, pParentWnd, iSelectPage)
+{
+}
+
+CMySheet::CMySheet(LPCTSTR pszCaption, CWnd* pParentWnd, UINT iSelectPage)
+ :CPropertySheet(pszCaption, pParentWnd, iSelectPage)
+{
+}
+
+CMySheet::CMySheet() : CPropertySheet()
+{
+}
+
+CMySheet::~CMySheet()
+{
+}
+
+
+BEGIN_MESSAGE_MAP(CMySheet, CPropertySheet)
+ //{{AFX_MSG_MAP(CMySheet)
+ // NOTE - the ClassWizard will add and remove mapping macros here.
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CMySheet message handlers
+
+BOOL CMySheet::OnInitDialog()
+{
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+ HICON hIcon = LoadIcon(pApp->m_hInstance, MAKEINTRESOURCE(IDR_MAINFRAME));
+ ::SetClassLong(m_hWnd, GCL_HICON, (long)hIcon);
+
+ return CPropertySheet::OnInitDialog();
+}
+
+// create a SecurityDescriptor
+BOOL CTurtleApp::CreateSID(PSECURITY_DESCRIPTOR pSD)
+{
+ if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) return FALSE;
+
+// try to guess the size of the ACL
+ DWORD cbAddEntries = m_sEntryArrayCount * 2;
+
+ DWORD cbACL = sizeof(ACL) +
+ (cbAddEntries * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD))) +
+ (cbAddEntries * 100 /* sizeof SID that is used */);
+
+ m_pACL = (ACL*)malloc(cbACL);
+ if (m_pACL == NULL)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONSTOP);
+ ExitProcess(1);
+ }
+
+ if (!InitializeAcl(m_pACL, cbACL, ACL_REVISION)) return FALSE;
+
+ if (!AddAces(m_pACL)) return FALSE;
+
+ if (!IsValidAcl(m_pACL)) return FALSE;
+
+// add a new discresionary ACL to the SID
+ if (!SetSecurityDescriptorDacl(pSD,
+ TRUE,
+ m_pACL,
+ FALSE)) return FALSE;
+
+ return TRUE;
+
+}
+
+BOOL CTurtleApp::AddAces(ACL* pACL)
+{
+// some buffers
+ BYTE sidbuffer[100];
+ PSID pSID = (PSID)&sidbuffer;
+ DWORD cbSID = 100;
+ TCHAR domainBuffer[80];
+ DWORD domainBufferSize = 80;
+ SID_NAME_USE snu;
+ CDisplayInfo* pDisplayInfo;
+ short sCount;
+
+ TCHAR* pServer = m_csRemoteServer.GetBuffer(m_csRemoteServer.GetLength());
+ m_csRemoteServer.ReleaseBuffer();
+
+ for (sCount = 0;sCount < m_sEntryArrayCount; sCount++)
+ {
+ pDisplayInfo = (CDisplayInfo*)m_lEntryArray[sCount];
+
+ TCHAR* pName = (TCHAR*)pDisplayInfo->csName.GetBuffer(pDisplayInfo->csName.GetLength());
+ pDisplayInfo->csName.ReleaseBuffer();
+
+ if (!LookupAccountName((LPWSTR)pServer,
+ pName,
+ pSID,
+ &cbSID,
+ domainBuffer,
+ &domainBufferSize,
+ &snu))
+ {
+ AfxMessageBox(IDS_GENERIC_NO_SECURITY);
+ break;
+ }
+
+ if (!IsValidSid(pSID))
+ {
+ AfxMessageBox(IDS_GENERIC_NO_SECURITY);
+ return FALSE;
+ }
+
+
+ ACCESS_ALLOWED_ACE* pAce;
+ void* pAceStart;
+ FindFirstFreeAce(pACL, &pAceStart);
+
+ pAce = (ACCESS_ALLOWED_ACE*)pAceStart;
+
+ DWORD dwSid = GetLengthSid(pSID);
+ WORD wAceSize = (WORD)(sizeof(ACE_HEADER) +
+ sizeof(ACCESS_MASK) +
+ dwSid);
+
+ CopySid(dwSid, (PSID)(&pAce->SidStart), pSID);
+
+ pAce->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
+ pAce->Header.AceFlags = INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE;
+ pAce->Mask = pDisplayInfo->dwPermission;
+ pAce->Header.AceSize = wAceSize;
+
+ if (!AddAce(pACL,
+ ACL_REVISION,
+ MAXDWORD,
+ (LPVOID)pAce,
+ wAceSize)) return FALSE;
+
+
+ ACCESS_ALLOWED_ACE* pAce2;
+ FindFirstFreeAce(pACL, &pAceStart);
+ pAce2 = (ACCESS_ALLOWED_ACE*)pAceStart;
+ CopySid(dwSid, (PSID)(&pAce2->SidStart), pSID);
+
+ pAce2->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
+ pAce2->Header.AceFlags = CONTAINER_INHERIT_ACE;
+ pAce2->Mask = pDisplayInfo->dwPermission2;
+ pAce2->Header.AceSize = wAceSize;
+
+ if (!AddAce(pACL,
+ ACL_REVISION,
+ MAXDWORD,
+ (LPVOID)pAce2,
+ pAce2->Header.AceSize)) return FALSE;
+
+ cbSID = 100;
+ domainBufferSize = 80;
+ }
+
+ return TRUE;
+
+}
+
+void CTurtleApp::ApplyDownStream(const TCHAR* csPath, PSECURITY_DESCRIPTOR pSD)
+{
+ TCHAR* filename;
+ TCHAR curdir[256];
+ TCHAR fullname[256];
+ HANDLE fileHandle;
+ WIN32_FIND_DATA findData;
+
+ if (!GetCurrentDirectory(256, curdir)) return;
+
+ if (_tcscmp(csPath, L".") && _tcscmp (csPath, L".."))
+ {
+ if (!SetCurrentDirectory(csPath)) return;
+ }
+ else return;
+
+ if (!GetFullPathName(L"*.*", 256, fullname, &filename)) return;
+
+ fileHandle = FindFirstFile( L"*.*", &findData);
+ while (fileHandle != INVALID_HANDLE_VALUE)
+ {
+ if (!SetFileSecurity(findData.cFileName,
+ DACL_SECURITY_INFORMATION,
+ pSD)) return;
+
+ if (!FindNextFile(fileHandle, &findData) ) break;
+ }
+
+ FindClose(fileHandle);
+
+ fileHandle = FindFirstFile( L"*.*", &findData);
+ while (fileHandle != INVALID_HANDLE_VALUE)
+ {
+ if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ ApplyDownStream(findData.cFileName, pSD);
+
+ if (!FindNextFile(fileHandle, &findData) ) break;
+ }
+
+ SetCurrentDirectory(curdir);
+ FindClose(fileHandle);
+
+}
+
+
diff --git a/private/utils/wizards/shrpub/turtle.h b/private/utils/wizards/shrpub/turtle.h
new file mode 100644
index 000000000..de9212417
--- /dev/null
+++ b/private/utils/wizards/shrpub/turtle.h
@@ -0,0 +1,190 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ turtle.h : main header file for the TURTLE application
+
+File History:
+
+ JonY Jan-96 created
+
+--*/
+
+//
+//
+
+#ifndef __AFXWIN_H__
+ #error include 'stdafx.h' before including this file for PCH
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CMySheet
+
+class CMySheet : public CPropertySheet
+{
+ DECLARE_DYNAMIC(CMySheet)
+
+// Construction
+public:
+ CMySheet(UINT nIDCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0);
+ CMySheet(LPCTSTR pszCaption, CWnd* pParentWnd = NULL, UINT iSelectPage = 0);
+ CMySheet();
+
+// Attributes
+public:
+
+// Operations
+public:
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CMySheet)
+ public:
+ virtual BOOL OnInitDialog();
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CMySheet();
+
+ // Generated message map functions
+protected:
+ //{{AFX_MSG(CMySheet)
+ // NOTE - the ClassWizard will add and remove member functions here.
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+/////////////////////////////////////////////////////////////////////////////
+
+#define RERUN_SFM 0x00000001
+#define RERUN_SMB 0x00000002
+#define RERUN_FPNW 0x00000004
+
+/////////////////////////////////////////////////////////////////////////////
+// User / permission items displayed in CListCtrl objects
+class CDisplayInfo
+{
+ public:
+ CString csName;
+ CString csPermission;
+ DWORD dwPermission;
+ DWORD dwPermission2;
+ CString csDisplay;
+ BOOL bAccessDenied;
+
+};
+
+////////////////////////////////////////////////////////////////////////////
+// CTurtleApp:
+// See turtle.cpp for the implementation of this class
+//
+typedef struct tagTREEINFO
+{
+ HTREEITEM hTreeItem;
+ DWORD dwBufSize;
+ CObject* pTree;
+ BOOL bExpand;
+}
+TREEINFO, *PTREEINFO;
+
+class CTurtleApp : public CWinApp
+{
+public:
+ CTurtleApp();
+ ~CTurtleApp();
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CTurtleApp)
+ public:
+ virtual BOOL InitInstance();
+ //}}AFX_VIRTUAL
+
+// Implementation
+
+ //{{AFX_MSG(CTurtleApp)
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+public:
+ BOOL IsSecondInstance();
+ void LoadDomainList();
+// void CatalogAccounts(const TCHAR* lpDomain, CUserList* pListBox, BOOL bLocal = FALSE);
+ short sParseAdminPath(CString& csDirectoryName, CString& csCurrentDrive);
+
+ CMySheet m_cps1/*(_T("title"))*/;
+
+ short m_nShareType;
+ unsigned short m_sMode; // 0 - FAT file 1 - NTFS file 2 - FAT vol 3 - NTFS vol
+
+// something on the cmd line?
+ BOOL m_bReentrant;
+
+// wizard data
+ CString m_csSFMOwnerName;
+ CString m_csSFMGroupName;
+ CString m_csMyDomainName;
+ CString m_csMyUserName;
+ CString m_csMyMachineName;
+ CString m_csPrimaryDomain;
+
+ CString m_csSharePath;
+ CStringArray m_csaDomainList;
+ CString m_csRemoteServer;
+ CString m_csRemoteServerPath;
+ CString m_csRemoteServerDrivePath;
+
+ CString m_csShareName;
+ CString m_csShareComment;
+
+ BOOL m_bGoFPNW;
+ BOOL m_bGoSFM;
+ BOOL m_bGoSMB;
+
+ BOOL m_bPermitSFM;
+ BOOL m_bPermitFPNW;
+ BOOL m_bPermitSMB;
+
+// specific SFM permissions
+ BOOL m_bEveryoneMakeChanges;
+ BOOL m_bEveryoneSeeFiles;
+ BOOL m_bEveryoneSeeFolders;
+ BOOL m_bGroupMakeChanges;
+ BOOL m_bGroupSeeFiles;
+ BOOL m_bGroupSeeFolders;
+ BOOL m_bOwnerMakeChanges;
+ BOOL m_bOwnerSeeFiles;
+ BOOL m_bOwnerSeeFolders;
+
+ BOOL DoSharing();
+
+ BOOL m_bServer;
+ BOOL m_bDomain;
+ CString m_csServer;
+ CString m_csDomain;
+ CString m_csCurrentDomain;
+ CString m_csCurrentMachine;
+
+ DWORD m_bReRun;
+
+ BOOL m_bShareThis;
+
+// permissions list stuff
+ USHORT m_sEntryArrayCount;
+ long m_lEntryArray[1000];
+ BOOL m_bSetPermissions;
+ BOOL m_bApplyRecursively;
+
+private:
+ BOOL CreateSID(PSECURITY_DESCRIPTOR pSD);
+ void ApplyDownStream(const TCHAR* csPath, PSECURITY_DESCRIPTOR pSD);
+ BOOL AddAces(ACL* pACL);
+ ACL* m_pACL;
+
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/private/utils/wizards/shrpub/turtle.rc b/private/utils/wizards/shrpub/turtle.rc
new file mode 100644
index 000000000..2f0b6ac16
--- /dev/null
+++ b/private/utils/wizards/shrpub/turtle.rc
@@ -0,0 +1,492 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
+ "#define _AFX_NO_OLE_RESOURCES\r\n"
+ "#define _AFX_NO_TRACKER_RESOURCES\r\n"
+ "#define _AFX_NO_PROPERTY_RESOURCES\r\n"
+ "\r\n"
+ "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
+ "#ifdef _WIN32\r\n"
+ "LANGUAGE 9, 1\r\n"
+ "#pragma code_page(1252)\r\n"
+ "#endif\r\n"
+ "#include ""res\\turtle.rc2"" // non-Microsoft Visual C++ edited resources\r\n"
+ "#include ""afxres.rc"" // Standard components\r\n"
+ "#endif\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDR_MAINFRAME ICON DISCARDABLE "res\\turtle.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_LOCAL_GROUP_BITMAP BITMAP DISCARDABLE "res\\group.bmp"
+IDB_USER_BITMAP BITMAP DISCARDABLE "res\\user.bmp"
+IDB_WORLD BITMAP DISCARDABLE "res\\world.bmp"
+IDB_GLOBAL_GROUP_BITMAP BITMAP DISCARDABLE "res\\global.bmp"
+IDB_NETWORK_BITMAP BITMAP DISCARDABLE "res\\network.bmp"
+IDB_SYSTEM_BITMAP BITMAP DISCARDABLE "res\\system.bmp"
+IDB_INTERACTIVE_BITMAP BITMAP DISCARDABLE "res\\interac.bmp"
+IDB_BITMAP1 BITMAP DISCARDABLE "res\\shrpub.bmp"
+IDB_NET_TREE BITMAP DISCARDABLE "res\\net_tree.bmp"
+IDB_END_FLAG BITMAP DISCARDABLE "res\\endflag.BMP"
+IDB_IMAGE_LIST BITMAP DISCARDABLE "res\\bitmap3.bmp"
+IDB_IMAGE_LIST2 BITMAP DISCARDABLE "res\\image_li.bmp"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_BASE_DIALOG DIALOG DISCARDABLE 0, 0, 293, 154
+STYLE DS_3DLOOK | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_DISABLED |
+ WS_BORDER
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "",IDC_PAINT_BOX,"Static",SS_BLACKFRAME,7,7,80,140
+END
+
+IDD_WELCOME_DIALOG DIALOG DISCARDABLE 0, 0, 290, 154
+STYLE DS_3DLOOK | DS_CENTER | WS_CHILD | WS_VISIBLE | WS_DISABLED |
+ WS_CAPTION
+CAPTION "Managing Folder and File Access"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "On &my computer",IDC_WHERE_2_SHARE_RADIO,"Button",
+ BS_AUTORADIOBUTTON | WS_GROUP,99,95,177,10
+ CONTROL "On &another computer",IDC_RADIO2,"Button",
+ BS_AUTORADIOBUTTON,99,109,139,10
+ CONTROL 130,IDC_PAINT_BOX,"Static",SS_BITMAP | SS_SUNKEN,0,0,87,
+ 153
+ LTEXT "Welcome to the Share Management Wizard",IDC_WELCOME,99,
+ 8,190,18
+ LTEXT "Where are the folders and files you want to provide access to?",
+ IDC_STATIC,99,70,189,16
+ LTEXT "With this wizard you can allow others to use folders and files. You allow access by setting permissions on folders and files, and by making folders available to users on the network.",
+ IDC_STATIC,99,30,183,34
+END
+
+IDD_WHAT_TO_SHARE_DLG DIALOG DISCARDABLE 0, 0, 292, 154
+STYLE WS_CHILD | WS_CAPTION
+CAPTION "Managing Folder and File Access"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "Tree2",IDC_DIRECTORY_LIST,"SysTreeView32",TVS_HASLINES |
+ TVS_SHOWSELALWAYS | WS_BORDER | WS_TABSTOP,0,10,291,114
+ EDITTEXT IDC_DIRECTORY_NAME,0,139,291,14,ES_AUTOHSCROLL
+ LTEXT "&Select the drive, then the folder or file you want to provide access to:",
+ IDC_STATIC,0,0,291,9
+ LTEXT "&To create a new folder, type a new name:",IDC_STATIC,0,
+ 130,184,8
+END
+
+IDD_HOW_TO_SHARE_DLG DIALOG DISCARDABLE 0, 0, 291, 154
+STYLE WS_CHILD | WS_CAPTION
+CAPTION "Managing Folder and File Access"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ CONTROL "Users of &Microsoft Windows",IDC_SMB_CHECK,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,19,111,184,10
+ CONTROL "M&acintosh users",IDC_SFM_CHECK,"Button",
+ BS_AUTOCHECKBOX | WS_DISABLED | WS_TABSTOP,19,139,184,10
+ CONTROL "N&etWare users",IDC_FPNW_CHECK,"Button",BS_AUTOCHECKBOX |
+ WS_DISABLED | WS_TABSTOP,19,125,184,10
+ LTEXT "To &rename this share, type a different name:",
+ IDC_STATIC1,19,30,249,8
+ EDITTEXT IDC_SHARE_NAME_EDIT,19,40,248,14,ES_AUTOHSCROLL
+ LTEXT "Type a &description for this share:",IDC_STATIC2,19,59,
+ 249,8
+ EDITTEXT IDC_SHARE_COMMENT,19,69,248,14,ES_AUTOHSCROLL
+ LTEXT "This is the &folder you selected to share:",IDC_STATIC,
+ 19,1,124,8
+ EDITTEXT IDC_FOLDERNAME_EDIT,19,11,248,14,ES_AUTOHSCROLL |
+ ES_READONLY
+ LTEXT "Who do you want to have access to this share?",
+ IDC_STATIC,19,93,152,8
+END
+
+IDD_WAIT_DIALOG DIALOG DISCARDABLE 0, 0, 184, 47
+STYLE DS_SETFOREGROUND | DS_3DLOOK | WS_POPUP | WS_VISIBLE | WS_BORDER
+FONT 8, "MS Shell Dlg"
+BEGIN
+ ICON IDR_MAINFRAME,IDC_STATIC,9,14,18,20
+ LTEXT "Static",IDC_WAIT_MESSAGE,41,5,135,17
+ LTEXT "Please Wait",IDC_STATIC,41,26,39,8
+END
+
+IDD_FINISH_DIALOG DIALOG DISCARDABLE 0, 0, 292, 154
+STYLE WS_POPUP | WS_CAPTION
+CAPTION "Managing Folder and File Access"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "static",IDC_STATIC_WHAT,86,7,205,18
+ LTEXT "Static directory name",IDC_DIRECTORY_NAME_STATIC,86,28,
+ 204,8
+ LTEXT "as the following share name:",IDC_STATIC_AS,86,41,92,8,
+ NOT WS_VISIBLE
+ LTEXT "Static share name",IDC_SHARE_NAME_STATIC,187,41,93,8,
+ NOT WS_VISIBLE
+ LTEXT "for these network users:",IDC_STATIC_WHO,86,58,110,8,
+ NOT WS_VISIBLE
+ LTEXT "",IDC_SERVICE_1,86,74,132,8
+ LTEXT "",IDC_SERVICE_2,86,87,132,8
+ LTEXT "",IDC_SERVICE_3,86,97,132,8
+END
+
+IDD_SMALL_WHAT DIALOG DISCARDABLE 0, 0, 290, 154
+STYLE WS_POPUP | WS_CAPTION
+CAPTION "Managing Folder and File Access"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ PUSHBUTTON "D&elete",IDC_REMOVE_SHARE_BUTTON,184,137,50,14
+ PUSHBUTTON "&Add New",IDC_ADD_NEW_SHARE_BUTTON,239,137,50,14
+ CONTROL "List1",IDC_SHARE_LIST,"SysListView32",LVS_LIST |
+ LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,0,19,289,113
+END
+
+IDD_WHERE_TO_SHARE_DLG DIALOG DISCARDABLE 0, 0, 292, 154
+STYLE WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Managing Folder and File Access"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Type the computer name where you want to set access for a folder or file. You can also select the computer name from the list.",
+ IDC_STATIC,99,0,189,25
+ EDITTEXT IDC_MACHINE_NAME,99,39,193,14,ES_AUTOHSCROLL
+ LTEXT "&Computer name:",IDC_STATIC,99,29,151,8
+ CONTROL "Tree1",IDC_SERVER_TREE,"SysTreeView32",TVS_HASBUTTONS |
+ TVS_HASLINES | TVS_LINESATROOT | WS_BORDER | WS_TABSTOP,
+ 99,59,193,94
+ CONTROL 130,IDC_PICTURE_BOX,"Static",SS_BITMAP | SS_SUNKEN,0,0,
+ 87,153
+END
+
+IDD_PERM_TYPE_DIALOG DIALOG DISCARDABLE 0, 0, 290, 154
+STYLE WS_POPUP | WS_CAPTION
+CAPTION "Managing Folder and File Access"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "&These are the current permissions:",IDC_STATIC,0,0,197,
+ 8
+ CONTROL "&Only I have access and full control",
+ IDC_PERM_TYPE_RADIO,"Button",BS_AUTORADIOBUTTON |
+ WS_DISABLED | WS_GROUP,8,102,189,10
+ CONTROL "&I have access and full control, everyone else can only read it",
+ IDC_PERM_TYPE_RADIO2,"Button",BS_AUTORADIOBUTTON |
+ WS_DISABLED,8,114,220,10
+ CONTROL "&Everyone has access and full control",
+ IDC_PERM_TYPE_RADIO3,"Button",BS_AUTORADIOBUTTON |
+ WS_DISABLED,8,126,167,10
+ CONTROL "List1",IDC_PERMS_LIST,"SysListView32",LVS_REPORT |
+ WS_BORDER | WS_TABSTOP,0,10,289,48
+ CONTROL "&Keep the original permissions",IDC_PERM_RADIO,"Button",
+ BS_AUTORADIOBUTTON | WS_GROUP,4,77,120,10
+ GROUPBOX "",IDC_STATIC,0,90,289,51
+ CONTROL "&Change permissions",IDC_PERM_RADIO2,"Button",
+ BS_AUTORADIOBUTTON,4,89,76,10
+ CONTROL "A&pply these permissions to all folders and files within this folder.",
+ IDC_RECURSIVE_CHECK,"Button",BS_AUTOCHECKBOX |
+ WS_DISABLED | WS_TABSTOP,0,145,243,8
+ LTEXT "You can keep these permissions or change them. What do you want to do?",
+ IDC_STATIC,0,64,273,8
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_BASE_DIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 286
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 147
+ END
+
+ IDD_WELCOME_DIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 283
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 147
+ END
+
+ IDD_WHAT_TO_SHARE_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 285
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 147
+ END
+
+ IDD_HOW_TO_SHARE_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 284
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 147
+ END
+
+ IDD_WAIT_DIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 177
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 40
+ END
+
+ IDD_FINISH_DIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 285
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 147
+ END
+
+ IDD_SMALL_WHAT, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 283
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 147
+ END
+
+ IDD_WHERE_TO_SHARE_DLG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 285
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 147
+ END
+
+ IDD_PERM_TYPE_DIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 283
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 147
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDR_ACCELERATOR1 ACCELERATORS DISCARDABLE
+BEGIN
+ VK_F1, ID_CONTEXT_HELP, VIRTKEY, SHIFT, NOINVERT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDP_OLE_INIT_FAILED "OLE initialization failed. Make sure that the OLE libraries are the correct version."
+ IDS_FPNW_ERROR_NOSHARE "An error occurred while sharing the folder for users of File and Print Services for NetWare. The folder was not shared."
+ IDS_GENERIC_VOLUME_NOT_UNIQUE
+ "The name you typed for the share is not unique. Please type a different name for this share."
+ IDS_FPNW_NO_SECURITY "Unable to set security on the shared resource for File and Print Services for NetWare users."
+ IDS_GENERIC_NOT_NTFS "The selected drive is not formatted as NTFS. Services for Macintosh will not be available. File security for NetWare users will be available."
+ IDS_GENERIC_PLEASE_SELECT_DIR "Please select a folder or file."
+ IDS_GENERIC_NO_DISK "There is no disk in the selected drive."
+ IDS_GENERIC_DRIVE_UNACCESSIBLE
+ "The folder was not shared. Microsoft Windows 95 directories cannot be shared using this wizard."
+ IDS_GENERIC_NO_PERMISSION
+ "You do not have permissions to share the folder. "
+ IDS_SMB_NO_SECURITY "Unable to set security on the shared folder for Microsoft Windows Network users."
+ IDS_GENERIC_INDICATE_SERVICE
+ "Please select the type of users who will be using this shared folder."
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_GENERIC_NO_PDC "The primary domain controller could not be found. User names and group names will not be available."
+ IDS_GENERIC_NO_VOLUME "Please type a name for this shared folder."
+ IDS_GENERIC_NO_HEAP "There is insufficient memory to complete this operation."
+ IDS_GENERIC_NO_SECURITY "Unable to set security on the shared resource."
+ IDS_INVALID_SHARE_NAME "The share name contains invalid characters."
+ IDS_INVALID_DIRECTORY_NAME
+ "The folder %1 does not exist. Would you like to create it?"
+ IDS_CANT_CREATE_DIRECTORY "Unable to create new folder."
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ AFX_IDS_APP_TITLE "Managing Folder and File Access"
+ IDS_SHARE_NAME_TOO_LONG "The share name %s is too long. For this share to be accessible from all MS-DOS workstations, the share name must be 12 characters or less."
+ IDS_FPNW "NetWare users"
+ IDS_SFM "Macintosh users"
+ IDS_SMB "Microsoft Windows Network users"
+ IDS_WELCOME "Welcome to the Managing Folder and File Access wizard"
+ IDS_SID_NO_ACCESS "No access"
+ IDS_SID_READ "Read"
+ IDS_SID_CHANGE "Change"
+ IDS_SID_FULL_ACCESS "Full access"
+ IDS_SID_EVERYONE "Everyone"
+ IDS_SID_NETWORK "NETWORK"
+ IDS_SID_INTERACTIVE "INTERACTIVE"
+ IDS_SID_SYSTEM "SYSTEM"
+ IDS_SID_DOMAIN_USERS "Domain Users"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_PUBLISH_ANOTHER "Access was successfully set. Do you want to set access for another folder or file?"
+ IDS_SFM_ERROR_NOSHARE "An error occurred while sharing the folder for users of Services for Macintosh. The folder was not shared."
+ IDS_SMB_ERROR_NOSHARE "An error occurred while sharing the folder for Windows NT Network users. The folder was not shared."
+ IDS_PUBLISH_ANOTHER_ERROR
+ "There were problems setting permissions on the file or folder. Would you like to restart the wizard?"
+ IDS_SUCCESS_QUIT "The folder was successfully shared."
+ IDS_SHARE_NAME_BLANK "Please type a name for this share."
+ IDS_NO_MACHINE_NAME "Please enter a computer name."
+ IDS_GENERIC_BAD_MACHINE "The selected computer could not be found."
+ IDS_NO_DC_FOUND "Unable to locate a domain controller for this domain."
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_NET_ERROR "IDS_NET_ERROR"
+ IDS_NET_NO_SERVERS "No servers were found in the selected domain."
+ IDS_ERROR "IDS_ERROR"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_NEW_DIR_CREATED "New Folder Created: "
+ IDS_UNKNOWN_MEDIA_TYPE "Unable to determine the file system type for the selected drive. Macintosh and NetWare users will not be able to be able to have access."
+ IDS_ENUM_ERROR "An error occurred while listing shares on the selected computer."
+ IDS_NO_SERVER_PERMISSION
+ "You do not have administrator rights on the selected computer."
+ IDS_INVALID_DRIVE "The specified drive does not exist or is not available."
+ IDS_BAD_DIRECTORY_NAME "Please select one of the available admin$ shares."
+ IDS_SERVER_UNAVAILABLE "The specified server\\share is unavailable or off-line."
+ IDS_ERROR_QUIT "An error has occurred. The folder was not shared."
+ IDS_SHARE_DELETED "The share was successfully deleted."
+ IDS_SHARE_NOT_DELETED "An error has occurred. The share was not deleted."
+ IDS_ALL_SHARES_DELETED "All shares were successfully deleted."
+ IDS_SHARE_NOT_ALL_DELETED
+ "An error has occurred. Not all of the shares were successfully deleted."
+ IDS_SFM_NESTED_VOLUME "The selected folder contains or is contained by a previously shared Macintosh folder.The folder will not be shared."
+ IDS_ALL_SERVICES_USED "The selected folder has already been shared for Microsoft Windows, NetWare, and Macintosh users."
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_GENERIC_NO_DIR_NAME "Please enter a folder name to share."
+ IDS_SID_PARSING_ERROR "An error occurred while reading in existing account information. Previous information will not be available for editing."
+ IDS_CANT_EDIT_SHARE "Unable to read in share information for the selected share."
+ IDS_SELECT_DELETE "Please select a share to delete."
+ IDS_BAD_VERSION "You must be running Windows NT version 4.0 or higher to use this wizard."
+ IDS_FAT_VOLUME "The folder you selected is on the FATfile system. You can only set permissions on the folder by sharing it. The permissions only apply to people using the folder over the network. Do you want to share this folder?"
+ IDS_FAT_FILE "You selected a file that is on a drive formatted by the FAT file system. You cannot set access permissions on this file. To set permissions on this file it must be on a drive formatted by the NTFS file system."
+ IDS_SID_LIST "List"
+ IDS_SID_ADD "Add"
+ IDS_SID_ADD_READ "Add & Read"
+ IDS_SID_SPECIAL "Special"
+ IDS_CANT_GET_CUR_INFO "Unable to get current security information"
+ IDS_NTFS_VOLUME "Do you want to share this folder with network users?"
+ IDS_NO_SFM "There was an error with Services for Macintosh. You cannot share this folder for Macintosh users at this time."
+ IDS_NO_FPNW "There was an error with File and Print Services for NetWare. You cannot share this folder for NetWare users at this time."
+ IDS_NO_DIR_PERMISSION "You do not have permission to view or modify permissions on the folders within the folder you have selected."
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_SID_CREATOR_OWNER "CREATOR OWNER"
+ IDS_FINISH_SETSHARE "You have selected to set access permissions and share"
+ IDS_FINISH_SET "You have selected to set access permissions for"
+ IDS_NAME_COLUMN "Name"
+ IDS_PERM_COLUMN "Permissions"
+ IDS_CDFS_FILE "You selected a file that is on a drive formatted by the CDFS file system. You cannot set access permissions on this file. To set permissions on this file it must be on a drive formatted by the NTFS file system."
+ IDS_CDFS_VOLUME "The folder you selected is on the CDFS file system. You can only set permissions on the folder by sharing it. The permissions only apply to people using the folder over the network. Do you want to share this folder?"
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#define _AFX_NO_SPLITTER_RESOURCES
+#define _AFX_NO_OLE_RESOURCES
+#define _AFX_NO_TRACKER_RESOURCES
+#define _AFX_NO_PROPERTY_RESOURCES
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE 9, 1
+#pragma code_page(1252)
+#endif
+#include "res\turtle.rc2" // non-Microsoft Visual C++ edited resources
+#include "afxres.rc" // Standard components
+#endif
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/private/utils/wizards/shrpub/wait.cpp b/private/utils/wizards/shrpub/wait.cpp
new file mode 100644
index 000000000..c373cbdea
--- /dev/null
+++ b/private/utils/wizards/shrpub/wait.cpp
@@ -0,0 +1,77 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Wait.cpp : implementation file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+#include "stdafx.h"
+#include "turtle.h"
+#include "resource.h"
+#include "Wait.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CWait dialog
+
+CWait::CWait(CWnd* pParent /*=NULL*/)
+ : CDialog(CWait::IDD, pParent)
+{
+ BOOL b = CDialog::Create(CWait::IDD);
+ //{{AFX_DATA_INIT(CWait)
+ m_csMessage = _T("");
+ //}}AFX_DATA_INIT
+}
+
+CWait::~CWait()
+{
+ DestroyWindow();
+
+}
+
+void CWait::SetMessage(UINT uiMessage)
+{
+ m_csMessage.LoadString(uiMessage);
+ UpdateData(FALSE);
+
+}
+
+void CWait::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CWait)
+ DDX_Text(pDX, IDC_WAIT_MESSAGE, m_csMessage);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CWait, CDialog)
+ //{{AFX_MSG_MAP(CWait)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CWait message handlers
+
+BOOL CWait::OnInitDialog()
+{
+ CDialog::OnInitDialog();
+
+ CenterWindow();
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
diff --git a/private/utils/wizards/shrpub/wait.h b/private/utils/wizards/shrpub/wait.h
new file mode 100644
index 000000000..4a715c614
--- /dev/null
+++ b/private/utils/wizards/shrpub/wait.h
@@ -0,0 +1,48 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Wait.h : header file
+
+File History:
+
+ JonY Jan-96 created
+
+--*/
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CWait dialog
+
+class CWait : public CDialog
+{
+// Construction
+public:
+ CWait(CWnd* pParent = NULL); // standard constructor
+ ~CWait();
+ void SetMessage(UINT uiMessage);
+// Dialog Data
+ //{{AFX_DATA(CWait)
+ enum { IDD = IDD_WAIT_DIALOG };
+ CString m_csMessage;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CWait)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+
+ // Generated message map functions
+ //{{AFX_MSG(CWait)
+ virtual BOOL OnInitDialog();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
diff --git a/private/utils/wizards/shrpub/welcomed.cpp b/private/utils/wizards/shrpub/welcomed.cpp
new file mode 100644
index 000000000..a0317a374
--- /dev/null
+++ b/private/utils/wizards/shrpub/welcomed.cpp
@@ -0,0 +1,116 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ WelcomeDlg.cpp : implementation file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+#include "stdafx.h"
+#include "Turtle.h"
+#include "resource.h"
+#include "wizbased.h"
+#include "WelcomeD.h"
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CWelcomeDlg property page
+
+IMPLEMENT_DYNCREATE(CWelcomeDlg, CWizBaseDlg)
+
+CWelcomeDlg::CWelcomeDlg() : CWizBaseDlg(CWelcomeDlg::IDD)
+{
+ //{{AFX_DATA_INIT(CWelcomeDlg)
+ m_nShareType = 0;
+ //}}AFX_DATA_INIT
+ m_pFont = NULL;
+
+}
+
+CWelcomeDlg::~CWelcomeDlg()
+{
+ if (m_pFont != NULL) delete m_pFont;
+}
+
+void CWelcomeDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CWelcomeDlg)
+ DDX_Control(pDX, IDC_WELCOME, m_sWelcome);
+ DDX_Radio(pDX, IDC_WHERE_2_SHARE_RADIO, m_nShareType);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CWelcomeDlg, CPropertyPage)
+ //{{AFX_MSG_MAP(CWelcomeDlg)
+ ON_WM_SHOWWINDOW()
+ //}}AFX_MSG_MAP
+
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CWelcomeDlg message handlers
+BOOL CWelcomeDlg::OnInitDialog()
+{
+ CPropertyPage::OnInitDialog();
+ SetButtonAccess(PSWIZB_NEXT);
+
+ m_pFont = new CFont;
+ LOGFONT lf;
+
+ memset(&lf, 0, sizeof(LOGFONT)); // Clear out structure.
+ lf.lfHeight = 15;
+ _tcscpy(lf.lfFaceName, L"MS Sans Serif");
+ lf.lfWeight = 700;
+ m_pFont->CreateFontIndirect(&lf); // Create the font.
+
+ CString cs;
+ cs.LoadString(IDS_WELCOME);
+ CWnd* pWnd = GetDlgItem(IDC_WELCOME);
+ pWnd->SetWindowText(cs);
+ pWnd->SetFont(m_pFont);
+
+
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+LRESULT CWelcomeDlg::OnWizardNext()
+{
+ SetButtonAccess(PSWIZB_NEXT | PSWIZB_BACK);
+ UpdateData(TRUE);
+
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+ pApp->m_nShareType = m_nShareType;
+
+ if (m_nShareType == 0)
+ {
+ pApp->m_csServer = L"";
+ return IDD_WHAT_TO_SHARE_DLG;
+ }
+ else
+ return IDD_WHERE_TO_SHARE_DLG;
+
+}
+
+void CWelcomeDlg::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CPropertyPage::OnShowWindow(bShow, nStatus);
+
+ if (!bShow) SetButtonAccess(PSWIZB_NEXT | PSWIZB_BACK);
+ else SetButtonAccess(PSWIZB_NEXT);
+
+}
diff --git a/private/utils/wizards/shrpub/welcomed.h b/private/utils/wizards/shrpub/welcomed.h
new file mode 100644
index 000000000..e4fd459a0
--- /dev/null
+++ b/private/utils/wizards/shrpub/welcomed.h
@@ -0,0 +1,55 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ WelcomeD.h : header file
+
+File History:
+
+ JonY Jan-96 created
+
+--*/
+
+
+//
+
+/////////////////////////////////////////////////////////////////////////////
+// CWelcomeDlg dialog
+
+class CWelcomeDlg : public CWizBaseDlg
+{
+ DECLARE_DYNCREATE(CWelcomeDlg)
+
+// Construction
+public:
+ CWelcomeDlg();
+ ~CWelcomeDlg();
+
+// Dialog Data
+ //{{AFX_DATA(CWelcomeDlg)
+ enum { IDD = IDD_WELCOME_DIALOG };
+ CStatic m_sWelcome;
+ int m_nShareType;
+ //}}AFX_DATA
+ virtual LRESULT OnWizardNext();
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CWelcomeDlg)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CWelcomeDlg)
+ virtual BOOL OnInitDialog();
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ //}}AFX_MSG
+
+ DECLARE_MESSAGE_MAP()
+ CFont* m_pFont;
+};
diff --git a/private/utils/wizards/shrpub/whattosh.cpp b/private/utils/wizards/shrpub/whattosh.cpp
new file mode 100644
index 000000000..2364a8b2f
--- /dev/null
+++ b/private/utils/wizards/shrpub/whattosh.cpp
@@ -0,0 +1,788 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ WhatToShD.cpp : implementation file
+ Creates the CDirectoryList class in the listbox.
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+#include "stdafx.h"
+#include "turtle.h"
+#include "resource.h"
+#include "dirtree.h"
+#include "WizBaseD.h"
+#include "WhatToSh.h"
+
+#include <direct.h>
+#include <winnetwk.h>
+#include <windef.h>
+#include <lmcons.h>
+#include <lmshare.h>
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+extern unsigned int WhichNTProduct(CString& lpMachineName);
+
+/////////////////////////////////////////////////////////////////////////////
+// CWhatToShareDlg property page
+
+IMPLEMENT_DYNCREATE(CWhatToShareDlg, CWizBaseDlg)
+
+CWhatToShareDlg::CWhatToShareDlg() : CWizBaseDlg(CWhatToShareDlg::IDD)
+{
+ //{{AFX_DATA_INIT(CWhatToShareDlg)
+ m_bShowConnectedDrives = FALSE;
+ m_csDirectoryName = _T("");
+ //}}AFX_DATA_INIT
+ m_bConnectedDrivesShown = FALSE;
+ m_sLevel = 0;
+ m_sStyle = 99;
+ m_csCurrentMachine = L"!";
+ m_bFile = FALSE;
+ m_bUpdate = FALSE;
+
+}
+
+CWhatToShareDlg::~CWhatToShareDlg()
+{
+
+}
+
+void CWhatToShareDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CWhatToShareDlg)
+ DDX_Control(pDX, IDC_DIRECTORY_LIST, m_cDirectoryList);
+ DDX_Text(pDX, IDC_DIRECTORY_NAME, m_csDirectoryName);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CWhatToShareDlg, CPropertyPage)
+ //{{AFX_MSG_MAP(CWhatToShareDlg)
+ ON_NOTIFY(NM_DBLCLK, IDC_DIRECTORY_LIST, OnDblclkListingTree)
+ ON_NOTIFY(TVN_SELCHANGED, IDC_DIRECTORY_LIST, OnSelchangedDirectoryList)
+ ON_WM_SHOWWINDOW()
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CWhatToShareDlg message handlers
+LRESULT CWhatToShareDlg::OnWizardNext()
+{
+ UpdateData(TRUE);
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+// make sure something is selected
+ HTREEITEM hItem = m_cDirectoryList.GetSelectedItem();
+ if (hItem == m_cDirectoryList.GetRootItem())
+ {
+ DoMessageBox(IDS_GENERIC_PLEASE_SELECT_DIR);
+ return -1;
+ }
+
+ if (m_csDirectoryName == L"")
+ {
+ m_csDirectoryName = m_cDirectoryList.GetItemPath(hItem);
+ if (m_csDirectoryName.GetLength() > 3)
+ m_csDirectoryName = m_csDirectoryName.Left(m_csDirectoryName.GetLength() - 1);
+ }
+
+ UINT uiMediaType;
+ CString csCurrentDrive;
+// share remote machine? (not connected)
+ if (pApp->m_nShareType == 1)
+ {
+ short sRet = pApp->sParseAdminPath(m_csDirectoryName, csCurrentDrive);
+ if (sRet == 1)
+ {
+ AfxMessageBox(IDS_BAD_DIRECTORY_NAME);
+ return -1;
+ }
+ else if (sRet == 2)
+ {
+ AfxMessageBox(IDS_INVALID_DRIVE);
+ return -1;
+ }
+ }
+
+ else
+ {
+// check drive type
+ if (m_csDirectoryName.GetAt(1) != ':')
+ {
+ GetCurrentDirectory(256, csCurrentDrive.GetBufferSetLength(256));
+ csCurrentDrive = csCurrentDrive.Left(2);
+ csCurrentDrive.ReleaseBuffer();
+ }
+ else
+ {
+ csCurrentDrive = m_csDirectoryName.Left(3);
+// test for valid drive letter
+ CString csTempDrive;
+ GetCurrentDirectory(256, csTempDrive.GetBufferSetLength(256));
+ if (!SetCurrentDirectory((LPCTSTR)csCurrentDrive))
+ {
+ AfxMessageBox(IDS_INVALID_DRIVE);
+ return -1;
+ }
+ SetCurrentDirectory(csTempDrive);
+
+ }
+ uiMediaType = GetDriveType((const TCHAR*)csCurrentDrive);
+ }
+
+// if its a remote drive we need to determine
+// 1)where it is
+// 2)what is the path on the host server?
+ if ((pApp->m_nShareType == 0) && (uiMediaType == DRIVE_REMOTE))
+ {
+ DWORD dwBufferSize = 100;
+ LPVOID lpBuffer;
+ lpBuffer = (LPVOID)malloc(100);
+ if (lpBuffer == NULL)
+ {
+ DoMessageBox(IDS_GENERIC_NO_HEAP);
+ ExitProcess(1);
+ }
+
+ DWORD dwRet = WNetGetUniversalName((const TCHAR*)csCurrentDrive,
+ UNIVERSAL_NAME_INFO_LEVEL,
+ lpBuffer,
+ &dwBufferSize);
+
+ if (dwRet != NO_ERROR)
+ {
+ DWORD dwErr = GetLastError();
+ TCHAR p[50];
+ wsprintf(p, L"%d", dwErr);
+ DoMessageBox(IDS_GENERIC_DRIVE_UNACCESSIBLE);
+ AfxMessageBox(p);
+ return -1;
+ }
+
+// get the share information
+ UNIVERSAL_NAME_INFO* pName = (UNIVERSAL_NAME_INFO*)lpBuffer;
+ *(pName->lpUniversalName + (_tcslen(pName->lpUniversalName))) = 0;
+
+ pApp->m_csRemoteServerPath = pName->lpUniversalName;
+
+// parse out the sharename
+ CString csShareName = pApp->m_csRemoteServerPath;
+ int nLen = csShareName.ReverseFind(_T('\\'));
+ csShareName = csShareName.Right(csShareName.GetLength() - (nLen + 1));
+
+ pApp->m_csRemoteServer = pApp->m_csRemoteServerPath.Left(nLen);
+
+ TCHAR* pShareName = csShareName.GetBuffer(csShareName.GetLength());
+ csShareName.ReleaseBuffer();
+
+ TCHAR* pServer = pApp->m_csRemoteServerPath.GetBuffer(pApp->m_csRemoteServerPath.GetLength());
+ pApp->m_csRemoteServerPath.ReleaseBuffer();
+ pServer += 2;
+ pServer = _tcstok(pServer, _T("\\"));
+
+ SHARE_INFO_2* pShareInfo2;
+// get information on the net drive
+ dwRet = NetShareGetInfo(pServer,
+ pShareName,
+ 2,
+ (LPBYTE*)&pShareInfo2);
+
+// do we have permission to modify access information?
+ if (dwRet == 5) // access denied - not permitted
+ {
+ DoMessageBox(IDS_GENERIC_NO_PERMISSION);
+ free(lpBuffer);
+ return -1;
+ }
+
+// some unknown error occurred
+ if (dwRet != 0)
+ {
+ DWORD dwErr = GetLastError();
+ DoMessageBox(IDS_GENERIC_DRIVE_UNACCESSIBLE);
+ free(lpBuffer);
+ return -1;
+ }
+
+// save the drive + path
+ pApp->m_csRemoteServerDrivePath = pShareInfo2->shi2_path;
+ free(lpBuffer);
+ }
+ else if (pApp->m_nShareType == 0)
+ {
+ pApp->m_csRemoteServerPath = "";
+ pApp->m_csRemoteServer = "";
+ pApp->m_csRemoteServerDrivePath = "";
+ }
+
+// make sure directory exists
+ if ((!m_bFile) && (CreateFile((const TCHAR*)m_csDirectoryName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL) == INVALID_HANDLE_VALUE))
+ {
+ DWORD dwErr = GetLastError();
+ if (dwErr == 5) // access denied
+ {
+ AfxMessageBox(IDS_NO_DIR_PERMISSION, MB_ICONSTOP);
+ return -1;
+ }
+
+ CString csCurDir;
+ GetCurrentDirectory(256, csCurDir.GetBufferSetLength(256));
+ csCurDir.ReleaseBuffer();
+
+ if (pApp->m_nShareType != 3) //UNC path
+ {
+ // new root
+ if ((m_csDirectoryName.GetAt(0) == '\\') && (m_csDirectoryName.GetAt(1) != '\\'))
+ m_csDirectoryName = csCurDir.Left(2) + m_csDirectoryName;
+
+ // new subdir on the current drive
+ else if ((m_csDirectoryName.GetAt(0) != '\\') && (m_csDirectoryName.GetAt(1) != ':'))
+ m_csDirectoryName = csCurDir + "\\" + m_csDirectoryName;
+ }
+
+ CString csMessage;
+ AfxFormatString1(csMessage, IDS_INVALID_DIRECTORY_NAME, m_csDirectoryName);
+ if (AfxMessageBox(csMessage, MB_YESNO) != IDYES) return -1;
+ if (!CreateNewDirectory((const TCHAR*)m_csDirectoryName))
+ {
+ DoMessageBox(IDS_CANT_CREATE_DIRECTORY);
+ return -1;
+ }
+ m_bUpdate = TRUE;
+ SetCurrentDirectory((LPCTSTR)csCurDir);
+ }
+
+ DWORD dwVolumeNameSize, dwVolumeSerialNumber, dwFileSystemFlags;
+ TCHAR* pFSNameBuffer = (TCHAR*)malloc(10);
+ if (pFSNameBuffer == NULL)
+ {
+ DoMessageBox(IDS_GENERIC_NO_HEAP);
+ ExitProcess(1);
+ }
+
+ BOOL bNTFS = FALSE;
+ if (!GetVolumeInformation((const TCHAR*)csCurrentDrive,
+ NULL, NULL,
+ &dwVolumeNameSize, &dwVolumeSerialNumber,
+ &dwFileSystemFlags,
+ pFSNameBuffer, 10)) AfxMessageBox(IDS_UNKNOWN_MEDIA_TYPE);
+
+ pApp->m_csSharePath = m_csDirectoryName;
+
+// depending on whether it is a file or folder selected, decide where to go
+ int nImage, nImage2;
+ m_cDirectoryList.GetItemImage(hItem, nImage, nImage2);
+
+// depending on the icon
+ SetButtonAccess(PSWIZB_NEXT | PSWIZB_BACK);
+
+ CString csPath;
+ // find the path of the selected item
+ if (pApp->m_nShareType == 0)
+ {
+ if (m_csDirectoryName != L"") csPath = m_csDirectoryName;
+ else
+ {
+ csPath = m_cDirectoryList.GetItemPath(hItem);
+ csPath = csPath.Left(csPath.GetLength() - 1);
+ }
+ }
+
+ else
+ {
+ if (m_csDirectoryName != L"") csPath = m_csDirectoryName;
+ else
+ {
+ csPath = pApp->m_csServer + "\\" + m_cDirectoryList.GetItemPath(hItem);
+ csPath = csPath.Left(csPath.GetLength() - 1);
+ }
+ }
+
+ DWORD dwType = GetFileAttributes(csPath);
+
+ if (dwType & FILE_ATTRIBUTE_DIRECTORY) // directory
+ {
+ if (!_tcscmp(pFSNameBuffer, _T("NTFS")))
+ {
+ pApp->m_sMode = 3;
+ pApp->m_bPermitSFM = TRUE;
+ pApp->m_bPermitFPNW = TRUE;
+ pApp->m_bShareThis = FALSE;
+ free(pFSNameBuffer);
+ return IDD_PERM_TYPE_DIALOG;
+ }
+
+ else if (!_tcscmp(pFSNameBuffer, _T("CDFS")))
+ {
+ pApp->m_sMode = 2;
+ CString csMessage;
+ pApp->m_bPermitSFM = TRUE;
+ pApp->m_bPermitFPNW = TRUE;
+ AfxFormatString1(csMessage, IDS_CDFS_VOLUME, m_csDirectoryName);
+ if (AfxMessageBox(csMessage, MB_YESNO) != IDYES)
+ {
+ pApp->m_bShareThis = FALSE;
+ free(pFSNameBuffer);
+ return -1;
+ }
+ pApp->m_bShareThis = TRUE;
+ free(pFSNameBuffer);
+ return IDD_HOW_TO_SHARE_DLG;
+ }
+
+ else
+ {
+ pApp->m_sMode = 2;
+ CString csMessage;
+ pApp->m_bPermitSFM = FALSE;
+ pApp->m_bPermitFPNW = TRUE;
+ AfxFormatString1(csMessage, IDS_FAT_VOLUME, m_csDirectoryName);
+ if (AfxMessageBox(csMessage, MB_YESNO) != IDYES)
+ {
+ pApp->m_bShareThis = FALSE;
+ free(pFSNameBuffer);
+ return -1;
+ }
+ pApp->m_bShareThis = TRUE;
+ free(pFSNameBuffer);
+ return IDD_HOW_TO_SHARE_DLG;
+ }
+ }
+ else // file
+ {
+ if (!_tcscmp(pFSNameBuffer, _T("NTFS")))
+ {
+ pApp->m_sMode = 1;
+ pApp->m_bShareThis = FALSE;
+ }
+
+ else if (!_tcscmp(pFSNameBuffer, _T("CDFS")))
+ {
+ pApp->m_sMode = 0;
+ AfxMessageBox(IDS_CDFS_FILE);
+ free(pFSNameBuffer);
+ return -1;
+ }
+
+ else
+ {
+ pApp->m_sMode = 0;
+ AfxMessageBox(IDS_FAT_FILE);
+ free(pFSNameBuffer);
+ return -1;
+ }
+
+ free(pFSNameBuffer);
+ return IDD_PERM_TYPE_DIALOG;
+ }
+
+ free(pFSNameBuffer);
+ return CPropertyPage::OnWizardNext();
+
+}
+
+LRESULT CWhatToShareDlg::OnWizardBack()
+{
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+ if (pApp->m_nShareType == 0)
+ {
+ SetButtonAccess(PSWIZB_NEXT);
+ return IDD_WELCOME_DIALOG;
+ }
+
+ else
+ {
+ SetButtonAccess(PSWIZB_NEXT | PSWIZB_BACK);
+ return IDD_WHERE_TO_SHARE_DLG;
+ }
+
+ return CPropertyPage::OnWizardNext();
+
+}
+
+BOOL CWhatToShareDlg::OnInitDialog()
+{
+ CPropertyPage::OnInitDialog();
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+// get all (sub)directories in the selected directory.
+void CWhatToShareDlg::EnumDirs(HTREEITEM hItem, const TCHAR* dirname)
+{
+ TCHAR *filename;
+ TCHAR fullname[256];
+ HANDLE fileHandle;
+ WIN32_FIND_DATA findData;
+ HTREEITEM hNew;
+ TCHAR* filemask = L"*.*";
+
+ CWaitCursor wait;
+ CString strFullPath;
+
+ if (_tcscmp(dirname, TEXT(".")) && _tcscmp(dirname, TEXT("..")))
+ {
+ if (!SetCurrentDirectory(dirname)) return;
+ }
+ else return;
+
+ GetFullPathName(filemask, 256, fullname, &filename);
+
+// iterate all files
+ fileHandle = FindFirstFile(TEXT("*.*"), &findData);
+ while (fileHandle != INVALID_HANDLE_VALUE)
+ {
+ if ((!_tcscmp(findData.cFileName, L".")) || (!_tcscmp(findData.cFileName, L".."))) goto skip;
+
+ TV_INSERTSTRUCT TreeCtrlItem;
+
+ TreeCtrlItem.hParent = hItem;
+ TreeCtrlItem.hInsertAfter = TVI_LAST;
+ TreeCtrlItem.item.mask = TVIF_TEXT | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
+
+ TreeCtrlItem.item.pszText = findData.cFileName;
+
+ strFullPath.Format(_T("%s\\%s"), dirname, findData.cFileName);
+
+ m_cDirectoryList.IsShared((LPCTSTR)strFullPath, &TreeCtrlItem.item);
+ m_cDirectoryList.GetIconIndices(findData.cFileName, &TreeCtrlItem.item.iImage,
+ &TreeCtrlItem.item.iSelectedImage);
+ hNew = m_cDirectoryList.InsertItem(&TreeCtrlItem);
+
+skip:
+ if (!FindNextFile(fileHandle, &findData) ) break;
+ }
+
+ FindClose(fileHandle);
+}
+
+// Check removable media to make sure that something is there
+BOOL CWhatToShareDlg::CheckRM(LPCTSTR lpszDriveName)
+{
+ SetErrorMode(1);
+ HANDLE iRC;
+ try
+ {
+ iRC=CreateFile(lpszDriveName, 0, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ }
+ catch(...)
+ {
+ return FALSE;
+ }
+ SetErrorMode(0);
+ if (iRC == INVALID_HANDLE_VALUE)
+ return FALSE;
+ CloseHandle(iRC);
+ return TRUE;
+}
+
+void CWhatToShareDlg::OnDblclkListingTree(NMHDR* pNMHDR, LRESULT* pResult)
+{
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+ CString csPath;
+ CString csCurrentDrive;
+ HTREEITEM hItem = m_cDirectoryList.GetSelectedItem();
+ m_sLevel = 0;
+ int nImage, nImage2;
+ m_cDirectoryList.GetItemImage(hItem, nImage, nImage2);
+
+// if this item has already been iterated then return. Otherwise look into it
+ if (m_cDirectoryList.ItemHasChildren(hItem)) return;
+
+// find the path of the selected item
+ if (pApp->m_nShareType == 0)
+ {
+ csPath = m_cDirectoryList.GetItemPath(hItem);
+ csCurrentDrive = m_cDirectoryList.GetCurrentDrive(hItem);
+ }
+ else
+ {
+ csPath = pApp->m_csServer + "\\" + m_cDirectoryList.GetItemPath(hItem);
+ csCurrentDrive = m_cDirectoryList.GetCurrentDrive(hItem);
+ }
+
+// depending on the icon look into it
+ UINT uiDrive = GetDriveType((LPCTSTR)csCurrentDrive);
+
+ switch(uiDrive)
+ {
+ case DRIVE_FIXED: // local fixed drive
+ EnumDirs(hItem, (const TCHAR*)csPath);
+ break;
+
+ case DRIVE_REMOVABLE: // if the drive is removable, make sure it has something in it
+ case DRIVE_CDROM:
+ if (!CheckRM((const TCHAR*)csCurrentDrive))
+ {
+ DoMessageBox(IDS_GENERIC_NO_DISK);
+ return;
+ }
+
+ EnumDirs(hItem, (const TCHAR*)csPath);
+ break;
+
+ default:
+ return;
+ }
+
+ *pResult = 0;
+
+}
+
+// expand or contract sub-directory list depending on current state
+void CWhatToShareDlg::OnSelchangedDirectoryList(NMHDR* pNMHDR, LRESULT* pResult)
+{
+ if (bDontCheck) return;
+ NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
+ HTREEITEM hItem = m_cDirectoryList.GetSelectedItem();
+
+ // depending on the icon look into it
+ CString csCurrentDrive = m_cDirectoryList.GetCurrentDrive(hItem);
+ UINT uiDrive = GetDriveType((LPCTSTR)csCurrentDrive);
+ if (uiDrive == DRIVE_REMOVABLE || uiDrive == DRIVE_CDROM)
+ if (!CheckRM((const TCHAR*)csCurrentDrive))
+ {
+ DoMessageBox(IDS_GENERIC_NO_DISK);
+ return;
+ }
+
+ int nImage, nImage2;
+ m_cDirectoryList.GetItemImage(hItem, nImage, nImage2);
+
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+ CString csPath;
+
+ // find the path of the selected item
+ if (pApp->m_nShareType == 0) csPath = m_cDirectoryList.GetItemPath(hItem);
+ else csPath = pApp->m_csServer + "\\" + m_cDirectoryList.GetItemPath(hItem);
+
+ if (csPath.GetLength() > 3) csPath = csPath.Left(csPath.GetLength() - 1);
+
+ m_csDirectoryName = m_cDirectoryList.GetItemPath(hItem);
+ if (m_csDirectoryName.GetLength() > 3)
+ m_csDirectoryName = m_csDirectoryName.Left(m_csDirectoryName.GetLength() - 1);
+
+ DWORD dwType = GetFileAttributes(csPath);
+
+ if (dwType & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ UpdateData(FALSE);
+
+ if (m_cDirectoryList.ItemHasChildren(hItem))
+ {
+ m_cDirectoryList.Expand(hItem, TVE_EXPAND);
+ return;
+ }
+ else
+ {
+ EnumDirs(hItem, (const TCHAR*)csPath);
+ m_cDirectoryList.Expand(hItem, TVE_EXPAND);
+ }
+ }
+ else //if (dwType & FILE_ATTRIBUTE_NORMAL)
+ {
+ m_csDirectoryName = L"";
+ UpdateData(FALSE);
+ m_bFile = TRUE;
+ return;
+ }
+
+ *pResult = 0;
+}
+
+BOOL CWhatToShareDlg::CreateNewDirectory(const TCHAR* m_csDirectoryName)
+{
+ TCHAR* pDirectory = (TCHAR*)malloc(_tcslen(m_csDirectoryName) * sizeof(TCHAR*));
+ _tcscpy(pDirectory, m_csDirectoryName);
+ TCHAR* ppDir = pDirectory;
+
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+ TCHAR* pDir;
+ if (pApp->m_nShareType == 1) // remote machine
+ {
+ CString csTemp = m_csDirectoryName;
+ short sSel = csTemp.Find('$');
+ csTemp = csTemp.Left(sSel + 1);
+ SetCurrentDirectory(csTemp);
+
+ pDirectory += (sSel + 2);
+ }
+
+ pDir = _tcstok(pDirectory, L"\\");
+
+ while (pDir != NULL)
+ {
+ if (!SetCurrentDirectory(pDir))
+ {
+ CreateDirectory(pDir, NULL);
+ if (!SetCurrentDirectory(pDir))
+ {
+ free(ppDir);
+ return FALSE;
+ }
+ }
+ if (pDir[1] == ':') SetCurrentDirectory(L"\\");
+ pDir = _tcstok(NULL, L"\\");
+ }
+
+ free(ppDir);
+
+ TCHAR pCurDir[256];
+ GetCurrentDirectory(256, pCurDir);
+ CString csNewDir;
+ csNewDir.LoadString(IDS_NEW_DIR_CREATED);
+ csNewDir += pCurDir;
+ AfxMessageBox(csNewDir);
+ return TRUE;
+}
+
+
+void CWhatToShareDlg::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CPropertyPage::OnShowWindow(bShow, nStatus);
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+
+// did the style change since we were last displayed?
+// if so, reset everything
+/* if (pApp->m_nShareType != m_sStyle)
+ {
+ m_cDirectoryList.DeleteAllItems();
+ m_sStyle = pApp->m_nShareType;
+ GetDlgItem(IDC_NETWORK_CHECK)->ShowWindow(SW_SHOW);
+ GetDlgItem(IDC_NETWORK_CHECK)->EnableWindow(TRUE);
+ m_csDirectoryName = L"";
+ UpdateData(FALSE);
+ } */
+
+ if (bShow)
+ {
+ if ((m_bUpdate) || (m_csCurrentMachine != pApp->m_csServer)) m_csCurrentMachine = pApp->m_csServer;
+ else return;
+
+ bDontCheck = TRUE;
+ m_bUpdate = FALSE;
+ m_cDirectoryList.DeleteItem(TVI_ROOT);
+ bDontCheck = FALSE;
+ HTREEITEM hRoot;
+// get display name of current machine
+ if (m_csCurrentMachine == L"")
+ {
+ LPITEMIDLIST pPIDL;
+ SHGetSpecialFolderLocation(GetSafeHwnd(), CSIDL_DRIVES, &pPIDL);
+
+ SHFILEINFO sfi;
+ SHGetFileInfo((LPCTSTR)pPIDL, NULL, &sfi, sizeof(sfi), SHGFI_DISPLAYNAME | SHGFI_PIDL);
+ hRoot = m_cDirectoryList.AddBranch(NULL, L".", (LPCTSTR)sfi.szDisplayName, 0L);
+ }
+ else
+ {
+ hRoot = m_cDirectoryList.AddBranch(NULL, L".", (LPCTSTR)m_csCurrentMachine, 0L);
+ }
+
+ if (pApp->m_nShareType == 1)
+ {
+ PSHARE_INFO_2 pShareInfo = (PSHARE_INFO_2)malloc(sizeof(SHARE_INFO_2));
+ PSHARE_INFO_2 ppShare = pShareInfo;
+ DWORD dwEntriesRead, dwTotalEntries;
+ DWORD napi = NetShareEnum(pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength()),
+ 2, (LPBYTE *)&pShareInfo,
+ MAX_PREFERRED_LENGTH, &dwEntriesRead, &dwTotalEntries, NULL);
+
+ USHORT usCount;
+ TCHAR* pDriveInformation = (TCHAR*)malloc(50 * sizeof(TCHAR));
+
+ for (usCount = 0; usCount < dwEntriesRead; usCount++)
+ {
+ if ((!(pShareInfo->shi2_type & (STYPE_SPECIAL))) || (_tcslen(pShareInfo->shi2_netname)) > 3)
+ {
+ pShareInfo++;
+ continue;
+ }
+ wsprintf(pDriveInformation, _T("%s\\ [%s]"), pShareInfo->shi2_netname, pShareInfo->shi2_remark);
+
+ CString csNetPath;
+ csNetPath.Format(_T("%s\\%s"), m_csCurrentMachine, pShareInfo->shi2_netname);
+
+ m_cDirectoryList.AddBranch(hRoot, (LPCTSTR)csNetPath, pDriveInformation, 1L/*, 3*/);
+ pShareInfo++;
+ }
+ free(pDriveInformation);
+ free(ppShare);
+ }
+
+ else
+ {
+ CWaitCursor wait;
+
+ DWORD dw = GetLogicalDriveStrings(0, NULL);
+ TCHAR* lpDriveStrings = (TCHAR*)malloc(dw * sizeof(TCHAR));
+ if (lpDriveStrings == NULL)
+ {
+ DoMessageBox(IDS_GENERIC_NO_HEAP);
+ ExitProcess(1);
+ }
+
+ TCHAR* pDriveStrings = lpDriveStrings;
+
+// Get the drives string names in our buffer.
+ GetLogicalDriveStrings(dw, lpDriveStrings);
+
+ TCHAR* pDriveInformation = (TCHAR*)malloc(50 * sizeof(TCHAR));
+ if (pDriveInformation == NULL)
+ {
+ DoMessageBox(IDS_GENERIC_NO_HEAP);
+ ExitProcess(1);
+ }
+
+ TCHAR* lpStart2 = pDriveInformation;
+
+// Parse the memory block, and fill the combo box.
+ while (*lpDriveStrings != 0)
+ {
+ if (GetDriveType((const TCHAR*)lpDriveStrings) != DRIVE_REMOTE)
+// if this is a local drive get the volume label (if any)
+ {
+ TCHAR* pVolNameBuffer = (TCHAR*)calloc(50, sizeof(TCHAR));
+ if (pVolNameBuffer == NULL)
+ {
+ DoMessageBox(IDS_GENERIC_NO_HEAP);
+ ExitProcess(1);
+ }
+
+ GetVolumeInformation((const TCHAR*)lpDriveStrings,
+ pVolNameBuffer, 50,
+ NULL, NULL,
+ NULL,
+ NULL, 0);
+
+ if (_tcscmp(pVolNameBuffer, _T("")))
+ wsprintf(pDriveInformation, _T("%s [%s]"), lpDriveStrings, pVolNameBuffer);
+ else (_tcscpy(pDriveInformation, lpDriveStrings));
+ free(pVolNameBuffer);
+ m_cDirectoryList.AddBranch(hRoot, lpDriveStrings, pDriveInformation, 1L);
+ }
+
+ lpDriveStrings = _tcschr(lpDriveStrings, 0) + 1; // Point to next string.
+ }
+
+ free(lpStart2);
+ free(pDriveStrings);
+ }
+ }
+ m_cDirectoryList.Expand(m_cDirectoryList.GetRootItem(), TVE_EXPAND);
+
+}
+
diff --git a/private/utils/wizards/shrpub/whattosh.h b/private/utils/wizards/shrpub/whattosh.h
new file mode 100644
index 000000000..4f809a3b5
--- /dev/null
+++ b/private/utils/wizards/shrpub/whattosh.h
@@ -0,0 +1,76 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ WhatToShD.h : header file
+
+File History:
+
+ JonY Jan-96 created
+
+--*/
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CWhatToShareDlg dialog
+
+class CWhatToShareDlg : public CWizBaseDlg
+{
+ DECLARE_DYNCREATE(CWhatToShareDlg)
+
+// Construction
+public:
+ CWhatToShareDlg();
+ ~CWhatToShareDlg();
+
+// Dialog Data
+ //{{AFX_DATA(CWhatToShareDlg)
+ enum { IDD = IDD_WHAT_TO_SHARE_DLG };
+ CDirTree m_cDirectoryList;
+ BOOL m_bShowConnectedDrives;
+ CString m_csDirectoryName;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CWhatToShareDlg)
+ public:
+ virtual LRESULT OnWizardNext();
+ virtual LRESULT OnWizardBack();
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CWhatToShareDlg)
+ virtual BOOL OnInitDialog();
+ afx_msg void OnDblclkListingTree(NMHDR* pNMHDR, LRESULT* pResult);
+ afx_msg void OnSelchangedDirectoryList(NMHDR* pNMHDR, LRESULT* pResult);
+ afx_msg void OnShowNetworkDrivesCheck();
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+
+private:
+ void EnumDirs(HTREEITEM hItem, const TCHAR* dirname);
+ BOOL CheckRM(LPCTSTR lpszDriveName);
+ BOOL CreateNewDirectory(const TCHAR* m_csDirectoryName);
+
+ BOOL m_bConnectedDrivesShown;
+ short ShareRemoteDrive();
+
+ USHORT m_sLevel;
+
+ BOOL bDontCheck;
+ USHORT m_sStyle;
+ CString m_csCurrentMachine;
+ BOOL m_bFile;
+
+ BOOL m_bUpdate;
+};
diff --git a/private/utils/wizards/shrpub/where.cpp b/private/utils/wizards/shrpub/where.cpp
new file mode 100644
index 000000000..1adc1842d
--- /dev/null
+++ b/private/utils/wizards/shrpub/where.cpp
@@ -0,0 +1,274 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Where.cpp : implementation file
+
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+#include "stdafx.h"
+#include "turtle.h"
+#include "NetTree.h"
+#include "resource.h"
+#include "Where.h"
+
+#include <winreg.h>
+#include <lmcons.h>
+#include <lmaccess.h>
+#include <lmerr.h>
+#include <lmapibuf.h>
+#include <winnetwk.h>
+#include <lmshare.h>
+#include <lmserver.h>
+
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+unsigned int WhichNTProduct(CString& lpMachineName);
+
+/////////////////////////////////////////////////////////////////////////////
+// CWhere property page
+
+IMPLEMENT_DYNCREATE(CWhere, CPropertyPage)
+
+CWhere::CWhere() : CPropertyPage(CWhere::IDD)
+{
+ //{{AFX_DATA_INIT(CWhere)
+ m_csMachineName = _T("");
+ //}}AFX_DATA_INIT
+ m_bExpandedOnce = 0;
+}
+
+CWhere::~CWhere()
+{
+}
+
+void CWhere::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CWhere)
+ DDX_Control(pDX, IDC_SERVER_TREE, m_ctServerTree);
+ DDX_Text(pDX, IDC_MACHINE_NAME, m_csMachineName);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CWhere, CPropertyPage)
+ //{{AFX_MSG_MAP(CWhere)
+ ON_WM_SHOWWINDOW()
+ ON_NOTIFY(TVN_SELCHANGED, IDC_SERVER_TREE, OnSelchangedServerTree)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CWhere message handlers
+
+LRESULT CWhere::OnWizardNext()
+{
+ UpdateData(TRUE);
+
+ if (m_csMachineName == "")
+ {
+ AfxMessageBox(IDS_NO_MACHINE_NAME);
+ CWnd* pWnd = GetDlgItem(IDC_MACHINE_NAME);
+ pWnd->SetFocus();
+ return -1;
+ }
+
+ UINT ui;
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+ m_csMachineName.MakeUpper();
+// if a machine name is entered we need to know the domain
+// if a domain name is entered we need to know the DC name
+ if (m_csMachineName.Left(2) == "\\\\")
+ {
+ pApp->m_bDomain = FALSE;
+ ui = WhichNTProduct(m_csMachineName);
+ if (ui != 0) // standalone server or wks
+ {
+ pApp->m_bServer = FALSE;
+ pApp->m_csServer = m_csMachineName;
+
+ PSHARE_INFO_2 pShareInfo = (PSHARE_INFO_2)malloc(sizeof(SHARE_INFO_2));
+ PSHARE_INFO_2 ppShare = pShareInfo;
+ DWORD dwEntriesRead, dwTotalEntries;
+ DWORD napi = NetShareEnum(pApp->m_csServer.GetBuffer(pApp->m_csServer.GetLength()),
+ 2, (LPBYTE *)&pShareInfo,
+ MAX_PREFERRED_LENGTH, &dwEntriesRead, &dwTotalEntries, NULL);
+
+ if (napi == 5)
+ {
+ AfxMessageBox(IDS_NO_SERVER_PERMISSION);
+ free(ppShare);
+ return -1;
+ }
+
+ else if (napi != 0)
+ {
+ AfxMessageBox(IDS_ENUM_ERROR);
+ free(ppShare);
+ return -1;
+ }
+ free(ppShare);
+ return CPropertyPage::OnWizardNext();
+ }
+ else
+ {
+ AfxMessageBox(IDS_GENERIC_BAD_MACHINE);
+ return -1;
+ }
+ }
+
+ else
+ {
+ AfxMessageBox(IDS_NO_MACHINE_NAME);
+ return -1;
+ }
+
+ return CPropertyPage::OnWizardNext();
+}
+
+// given a machine name, return whether its a server or wks
+unsigned int WhichNTProduct(CString& csMachineName)
+{
+ #define MY_BUFSIZE 32 // arbitrary. Use dynamic allocation
+ HKEY hKey;
+ wchar_t szProductType[MY_BUFSIZE];
+ DWORD dwBufLen=MY_BUFSIZE;
+
+ long lRet = RegConnectRegistry(
+ (LPTSTR)csMachineName.GetBuffer(csMachineName.GetLength()),
+ HKEY_LOCAL_MACHINE,
+ &hKey);
+
+ if(RegOpenKeyEx(hKey,
+ L"SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
+ 0,
+ KEY_EXECUTE,
+ &hKey) != ERROR_SUCCESS) return(5);
+
+ if(RegQueryValueEx(hKey,
+ L"ProductType",
+ NULL,
+ NULL,
+ (LPBYTE)szProductType,
+ &dwBufLen) != ERROR_SUCCESS) return(5);
+
+ RegCloseKey(hKey);
+
+ // check product options, in order of likelihood
+ if(_tcsicmp(L"WINNT", szProductType) == 0) return(2); //wks
+ if(_tcsicmp(L"SERVERNT", szProductType) == 0) return(1); // server
+ if(_tcsicmp(L"LANMANNT", szProductType) == 0) return(3); // pdc\bdc
+
+ // else return Unknown
+ return 0;
+
+}
+
+void CWhere::OnShowWindow(BOOL bShow, UINT nStatus)
+{
+ CPropertyPage::OnShowWindow(bShow, nStatus);
+
+// Do the default domain expansion only once.
+ if ((bShow) && (!m_bExpandedOnce))
+ {
+ m_bExpandedOnce = TRUE;
+ m_ctServerTree.PopulateTree();
+ }
+
+}
+
+void CWhere::OnSelchangedServerTree(NMHDR* pNMHDR, LRESULT* pResult)
+{
+ NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
+
+ HTREEITEM hItem = m_ctServerTree.GetSelectedItem();
+
+ int nImage;
+ m_ctServerTree.GetItemImage(hItem, nImage, nImage);
+ if (nImage > 0)
+ {
+ CString csName;
+ csName = m_ctServerTree.GetItemText(hItem);
+
+ m_csMachineName = csName;
+ }
+ UpdateData(FALSE);
+
+
+ *pResult = 0;
+}
+
+BOOL CWhere::OnInitDialog()
+{
+ CPropertyPage::OnInitDialog();
+
+// get our primary domain and save it for NETTREE
+ DWORD dwRet;
+ HKEY hKey;
+ DWORD cbProv = 0;
+ TCHAR* lpProv = NULL;
+
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+
+ dwRet = RegOpenKey(HKEY_LOCAL_MACHINE,
+ TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon"), &hKey );
+
+ TCHAR* lpPrimaryDomain = NULL;
+ if ((dwRet = RegQueryValueEx( hKey, TEXT("CachePrimaryDomain"), NULL, NULL, NULL, &cbProv )) == ERROR_SUCCESS)
+ {
+ lpPrimaryDomain = (TCHAR*)malloc(cbProv);
+ if (lpPrimaryDomain == NULL)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
+ ExitProcess(1);
+ }
+
+ dwRet = RegQueryValueEx( hKey, TEXT("CachePrimaryDomain"), NULL, NULL, (LPBYTE) lpPrimaryDomain, &cbProv );
+
+ }
+
+ RegCloseKey(hKey);
+
+ pApp->m_csCurrentDomain = lpPrimaryDomain;
+
+// store the machine name too
+ dwRet = RegOpenKey(HKEY_LOCAL_MACHINE,
+ TEXT("SYSTEM\\CurrentControlSet\\Control\\ComputerName\\ActiveComputerName"), &hKey );
+
+ TCHAR* lpMachineName = NULL;
+ if ((dwRet = RegQueryValueEx( hKey, TEXT("ComputerName"), NULL, NULL, NULL, &cbProv )) == ERROR_SUCCESS)
+ {
+ lpMachineName = (TCHAR*)malloc(cbProv);
+ if (lpMachineName == NULL)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
+ ExitProcess(1);
+ }
+
+ dwRet = RegQueryValueEx( hKey, TEXT("ComputerName"), NULL, NULL, (LPBYTE) lpMachineName, &cbProv );
+
+ }
+
+ pApp->m_csCurrentMachine = "\\\\";
+ pApp->m_csCurrentMachine += lpMachineName;
+
+ free(lpPrimaryDomain);
+ free(lpMachineName);
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
diff --git a/private/utils/wizards/shrpub/where.h b/private/utils/wizards/shrpub/where.h
new file mode 100644
index 000000000..aee8607af
--- /dev/null
+++ b/private/utils/wizards/shrpub/where.h
@@ -0,0 +1,56 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Where.h : header file
+
+File History:
+
+ JonY Jan-96 created
+
+--*/
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CWhere dialog
+
+class CWhere : public CPropertyPage
+{
+ DECLARE_DYNCREATE(CWhere)
+
+// Construction
+public:
+ CWhere();
+ ~CWhere();
+
+// Dialog Data
+ //{{AFX_DATA(CWhere)
+ enum { IDD = IDD_WHERE_TO_SHARE_DLG };
+ CNetTreeCtrl m_ctServerTree;
+ CString m_csMachineName;
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CWhere)
+ public:
+ virtual LRESULT OnWizardNext();
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+private:
+ BOOL m_bExpandedOnce;
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CWhere)
+ afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
+ afx_msg void OnSelchangedServerTree(NMHDR* pNMHDR, LRESULT* pResult);
+ virtual BOOL OnInitDialog();
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+};
diff --git a/private/utils/wizards/shrpub/wizbased.cpp b/private/utils/wizards/shrpub/wizbased.cpp
new file mode 100644
index 000000000..f026aa9d0
--- /dev/null
+++ b/private/utils/wizards/shrpub/wizbased.cpp
@@ -0,0 +1,419 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ WizBaseD.cpp : implementation file
+
+ base class for most of the internal pages.
+File History:
+
+ JonY Apr-96 created
+
+--*/
+
+
+#include "stdafx.h"
+#include "Turtle.h"
+#include "resource.h"
+#include "WizBaseD.h"
+
+#ifdef _DEBUG
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CWizBaseDlg property page
+
+IMPLEMENT_DYNCREATE(CWizBaseDlg, CPropertyPage)
+
+CWizBaseDlg::CWizBaseDlg() : CPropertyPage(CWizBaseDlg::IDD)
+{
+ //{{AFX_DATA_INIT(CWizBaseDlg)
+ // NOTE: the ClassWizard will add member initialization here
+ //}}AFX_DATA_INIT
+
+}
+
+CWizBaseDlg::~CWizBaseDlg()
+{
+}
+
+CWizBaseDlg::CWizBaseDlg(short sIDD) : CPropertyPage(sIDD)
+{
+
+}
+
+void CWizBaseDlg::DoDataExchange(CDataExchange* pDX)
+{
+ CPropertyPage::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CWizBaseDlg)
+ // NOTE: the ClassWizard will add DDX and DDV calls here
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CWizBaseDlg, CPropertyPage)
+ //{{AFX_MSG_MAP(CWizBaseDlg)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CWizBaseDlg message handlers
+
+// draw the bitmap resource in the box on the left side of the dialog
+void CWizBaseDlg::PaintSpace(CDC* pDC, short sBitmapID)
+{
+ CDC* pDisplayMemDC = new CDC;
+ CBitmap* pBitmap = new CBitmap;
+ pBitmap->LoadBitmap(sBitmapID);
+
+ pDisplayMemDC->CreateCompatibleDC(pDC);
+ pDisplayMemDC->SelectObject(pBitmap);
+
+ PBITMAP lpb = (PBITMAP)VirtualAlloc(NULL,sizeof(BITMAP), MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+ pBitmap->GetObject(sizeof(BITMAP), (LPVOID)lpb);
+
+ CWnd* pWnd = (CWnd*)GetDlgItem(IDC_PAINT_BOX);
+ CRect cr;
+ pWnd->GetClientRect(&cr);
+
+ pDC->SetMapMode(MM_TEXT);
+ pDC->DPtoLP(&cr);
+ pDC->StretchBlt(0, 0, cr.Width(), cr.Height(), pDisplayMemDC,
+ 0, 0, lpb->bmWidth, lpb->bmHeight, SRCCOPY);
+
+// cleanup
+ delete pDisplayMemDC;
+ delete pBitmap;
+ VirtualFree(lpb, 0, MEM_RELEASE | MEM_DECOMMIT);
+
+}
+
+void CWizBaseDlg::SetButtonAccess(short sFlags)
+{
+ CPropertySheet* cp = (CPropertySheet*)GetParent();
+ cp->SetWizardButtons(sFlags);
+
+}
+
+// Load a string resource and display it in a message box with an exclamation point
+void CWizBaseDlg::DoMessageBox(UINT uiStringResID)
+{
+ CString csMessage;
+ csMessage.LoadString(uiStringResID);
+ AfxMessageBox(csMessage, MB_ICONEXCLAMATION);
+
+}
+
+// create domain + user/group name
+CString CWizBaseDlg::GetCurrentNameInfo(CString& csUserName, CString& csDomainName)
+{
+// first check to see if its a name that we shouldn't append
+// if so, just return it.
+ if ((!csUserName.CompareNoCase(LoadStringX(IDS_SID_EVERYONE))) ||
+ (csUserName == LoadStringX(IDS_SID_NETWORK)) ||
+ (csUserName == LoadStringX(IDS_SID_INTERACTIVE)) ||
+ (csUserName == LoadStringX(IDS_SID_SYSTEM)) ||
+ (csUserName == LoadStringX(IDS_SID_CREATOR_OWNER)))
+ return csUserName;
+
+// start with the domain or machine name to create the account information
+ CString csValue = csDomainName;
+ if (csValue.Left(2) == _T("\\\\"))
+ csValue = csValue.Right(csValue.GetLength() - 2);
+
+ csValue += "\\";
+ csValue += csUserName;
+
+ return csValue;
+
+}
+
+CString CWizBaseDlg::LoadStringX(UINT ID)
+{
+ CString csTemp;
+ csTemp.LoadString(ID);
+ return csTemp;
+}
+ /*
+// add ACEs to the ACL. Both AccessAllowed and AccessDenied.
+void CWizBaseDlg::AddAces(ACL* pACL, CListBox* pListBox, DWORD dwPermissions, LPCTSTR lpPermText)
+{
+// some buffers
+ LPTSTR pAccount = (LPTSTR)malloc(256);
+ if (pAccount == NULL)
+ {
+ DoMessageBox(IDS_GENERIC_NO_HEAP);
+ ExitProcess(1);
+ }
+
+ BYTE sidbuffer[100];
+ PSID pSID = (PSID)&sidbuffer;
+ DWORD cbSID = 100;
+ TCHAR domainBuffer[80];
+ DWORD domainBufferSize = 80;
+ SID_NAME_USE snu;
+
+ int nCount = 0;
+ int nBoxCount = pListBox->GetCount();
+
+ while (nCount < nBoxCount)
+ {
+ pListBox->GetText(nCount, pAccount);
+
+ TCHAR* pPerm;
+ pPerm = _tcstok(pAccount, _T(";")); // gets the name
+ pPerm = _tcstok(NULL, _T(";")); // gets the comment
+
+ if (!_tcscmp(lpPermText, pPerm))
+ {
+// pListBox->DeleteString(nCount);
+ if (!LookupAccountName((LPWSTR)NULL,
+ pAccount,
+ pSID,
+ &cbSID,
+ domainBuffer,
+ &domainBufferSize,
+ &snu))
+ {
+ // strip off the machine name and try again
+ TCHAR* pLocalGroup = _tcsrchr(pAccount, L'\\');
+ pLocalGroup++;
+
+ if (!LookupAccountName((LPWSTR)NULL,
+ pLocalGroup,
+ pSID,
+ &cbSID,
+ domainBuffer,
+ &domainBufferSize,
+ &snu))
+ {
+ DoMessageBox(IDS_GENERIC_NO_SECURITY);
+ break;
+ }
+
+ }
+
+ if (!IsValidSid(pSID))
+ {
+ DoMessageBox(IDS_GENERIC_NO_SECURITY);
+ return;
+ }
+ if (dwPermissions != 0)
+ {
+ if (!AddAccessAllowedAce(pACL, ACL_REVISION,
+ dwPermissions, pSID))
+ {
+ DoMessageBox(IDS_GENERIC_NO_SECURITY);
+ return;
+ }
+ }
+ else
+ {
+ if (!AddAccessDeniedAce(pACL, ACL_REVISION,
+ GENERIC_ALL, pSID))
+ {
+ DoMessageBox(IDS_GENERIC_NO_SECURITY);
+ return;
+ }
+ }
+
+
+ pSID = (PSID)&sidbuffer;
+ cbSID = 100;
+ domainBufferSize = 80;
+ }
+
+ nCount++;
+ }
+
+ free(pAccount);
+
+} */
+
+void CWizBaseDlg::CheckUniqueness(CString& csItem, CListBox& cLB)
+{
+ short sPos;
+ if ((sPos = cLB.FindString(-1, csItem)) != LB_ERR)
+ cLB.DeleteString(sPos);
+
+}
+ /*
+void CWizBaseDlg::AddAce(ACL* pACL, LPTSTR pName, DWORD dwPermissions)
+{
+ BYTE sidbuffer[100];
+ PSID pSID = (PSID)&sidbuffer;
+ DWORD cbSID = 100;
+ TCHAR domainBuffer[80];
+ DWORD domainBufferSize = 80;
+ SID_NAME_USE snu;
+
+
+ if (!LookupAccountName((LPWSTR)NULL,
+ pName,
+ pSID,
+ &cbSID,
+ domainBuffer,
+ &domainBufferSize,
+ &snu))
+ {
+ DoMessageBox(IDS_GENERIC_NO_SECURITY);
+ return;
+ }
+
+ if (!IsValidSid(pSID))
+ {
+ DoMessageBox(IDS_GENERIC_NO_SECURITY);
+ return;
+ }
+
+
+ if (!AddAccessAllowedAce(pACL, ACL_REVISION,
+ dwPermissions, pSID))
+ {
+ DoMessageBox(IDS_GENERIC_NO_SECURITY);
+ return;
+ }
+
+}
+
+
+BOOL CWizBaseDlg::bSidBlaster(PSECURITY_DESCRIPTOR pSID, CUserList& cLB)
+{
+ BOOL bDACLPresent, bDACLDefaulted;
+ PACL pDACL;
+
+ if (!IsValidSecurityDescriptor(pSID))
+ {
+ AfxMessageBox(IDS_SID_PARSING_ERROR);
+ return FALSE;
+ }
+
+ BOOL bRet = GetSecurityDescriptorDacl(pSID,
+ &bDACLPresent,
+ &pDACL,
+ &bDACLDefaulted);
+
+ if (!bRet)
+ {
+ AfxMessageBox(IDS_SID_PARSING_ERROR);
+ return FALSE;
+ }
+
+
+ if (!bDACLPresent)
+ {
+ AfxMessageBox(IDS_SID_PARSING_ERROR);
+ return TRUE;
+ }
+
+ ACL_SIZE_INFORMATION aclSize;
+ bRet = GetAclInformation(pDACL,
+ &aclSize,
+ sizeof(ACL_SIZE_INFORMATION),
+ AclSizeInformation);
+
+ if (!bRet)
+ {
+ DWORD dwerr = GetLastError();
+ AfxMessageBox(IDS_SID_PARSING_ERROR);
+ return FALSE;
+ }
+
+ CTurtleApp* pApp = (CTurtleApp*)AfxGetApp();
+ TCHAR* pServer = pApp->m_csRemoteServerPath.GetBuffer(pApp->m_csRemoteServerPath.GetLength());
+ pApp->m_csRemoteServerPath.ReleaseBuffer();
+
+// load some defaults
+ CString csTempEveryone;
+ csTempEveryone.LoadString(IDS_SID_EVERYONE);
+
+ CString csTempInteractive;
+ csTempInteractive.LoadString(IDS_SID_INTERACTIVE);
+
+ CString csTempNetwork;
+ csTempNetwork.LoadString(IDS_SID_NETWORK);
+
+ CString csTempSystem;
+ csTempSystem.LoadString(IDS_SID_SYSTEM);
+
+ ACCESS_ALLOWED_ACE* pAAce;
+ USHORT sCount;
+ USHORT sIconType;
+ CString csEntry;
+
+ for (sCount = 0; sCount < aclSize.AceCount; sCount++)
+ {
+ // get ACE info
+ bRet = GetAce(pDACL, sCount, (LPVOID*) &pAAce);
+ if (!bRet)
+ {
+ AfxMessageBox(IDS_SID_PARSING_ERROR);
+ return FALSE;
+ }
+
+ TCHAR pAccountName[80];
+ TCHAR pDomainName[80];
+ DWORD dwAccountNameSize = 80, pDomainNameSize = 80;
+ SID_NAME_USE sidType;
+
+ bRet = LookupAccountSid( pServer,
+ &pAAce->SidStart,
+ pAccountName, &dwAccountNameSize, pDomainName, &pDomainNameSize, &sidType);
+
+// build the new entry
+ if (!csTempEveryone.CompareNoCase(pAccountName))
+ {
+ csEntry = csTempEveryone;
+ sIconType = 2;
+ }
+ else if (!csTempInteractive.CompareNoCase(pAccountName))
+ {
+ csEntry = csTempInteractive;
+ sIconType = 4;
+ }
+ else if (!csTempNetwork.CompareNoCase(pAccountName))
+ {
+ csEntry = csTempNetwork;
+ sIconType = 5;
+ }
+ else if (!csTempSystem.CompareNoCase(pAccountName))
+ {
+ csEntry = csTempSystem;
+ sIconType = 6;
+ }
+ else if (sidType == SidTypeGroup)
+ {
+ csEntry = GetCurrentNameInfo(CString(pAccountName), CString(pDomainName));
+ sIconType = 1;
+ }
+ else if (sidType == SidTypeAlias)
+ {
+ csEntry = pAccountName;
+ sIconType = 3;
+ }
+ else
+ {
+ csEntry = GetCurrentNameInfo(CString(pAccountName), CString(pDomainName));
+ sIconType = 0;
+ }
+
+ csEntry += L";";
+ CString csAccessType;
+ if (pAAce->Mask == 0x001f01ff) csAccessType.LoadString(IDS_SID_FULL_ACCESS);
+ if (pAAce->Mask == 0x001200a9) csAccessType.LoadString(IDS_SID_READ);
+ if (pAAce->Mask == 0x001301bf) csAccessType.LoadString(IDS_SID_CHANGE);
+ csEntry += csAccessType;
+
+ cLB.AddString(sIconType, (const TCHAR*)csEntry);
+ }
+ return TRUE;
+}
+
+
+ */
+
+
diff --git a/private/utils/wizards/shrpub/wizbased.h b/private/utils/wizards/shrpub/wizbased.h
new file mode 100644
index 000000000..4f719b05d
--- /dev/null
+++ b/private/utils/wizards/shrpub/wizbased.h
@@ -0,0 +1,63 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ WizBaseD.h : header file
+
+File History:
+
+ JonY Jan-96 created
+
+--*/
+
+/////////////////////////////////////////////////////////////////////////////
+// CWizBaseDlg dialog
+
+class CWizBaseDlg : public CPropertyPage
+{
+ DECLARE_DYNCREATE(CWizBaseDlg)
+
+// Construction
+public:
+ static void DoMessageBox(UINT uiStringResID);
+ CWizBaseDlg();
+ CWizBaseDlg(short sIDD);
+ ~CWizBaseDlg();
+
+public:
+// base class paint fn for space on left side of dialog
+ virtual void PaintSpace(CDC* pDC, short sBitmapID = IDB_BITMAP1);
+ void SetButtonAccess(short sFlags);
+ void AddAces(ACL* pACL, CListBox* pListBox, DWORD dwPermissions, LPCTSTR lpPermText);
+ void AddAce(ACL* pACL, LPTSTR pName, DWORD dwPermissions);
+ void CheckUniqueness(CString& csItem, CListBox& cLB);
+ CString LoadStringX(UINT ID);
+// BOOL bSidBlaster(PSECURITY_DESCRIPTOR pSID, CUserList& cLB);
+
+// Dialog Data
+ //{{AFX_DATA(CWizBaseDlg)
+ enum { IDD = IDD_BASE_DIALOG };
+ // NOTE - ClassWizard will add data members here.
+ // DO NOT EDIT what you see in these blocks of generated code !
+ //}}AFX_DATA
+
+
+// Overrides
+ // ClassWizard generate virtual function overrides
+ //{{AFX_VIRTUAL(CWizBaseDlg)
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+ CString GetCurrentNameInfo(CString& csUserName, CString& csDomainName);
+
+// Implementation
+protected:
+ // Generated message map functions
+ //{{AFX_MSG(CWizBaseDlg)
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+
+};
diff --git a/private/utils/wizards/wizmgr/listdata.h b/private/utils/wizards/wizmgr/listdata.h
new file mode 100644
index 000000000..8af4f9de0
--- /dev/null
+++ b/private/utils/wizards/wizmgr/listdata.h
@@ -0,0 +1,27 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Listdata.h : class implementation of list member data
+
+File History:
+
+ JonY Jan-96 created
+
+--*/
+
+
+//
+
+class CItemData : public CObject
+{
+ public:
+ HICON hIcon;
+ HICON hSelIcon;
+ CString csName;
+ CString csDesc;
+ CString csAppStart1;
+ CString csAppStart2;
+};
diff --git a/private/utils/wizards/wizmgr/makefile b/private/utils/wizards/wizmgr/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/wizards/wizmgr/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/wizards/wizmgr/mustard.cpp b/private/utils/wizards/wizmgr/mustard.cpp
new file mode 100644
index 000000000..d6c2844eb
--- /dev/null
+++ b/private/utils/wizards/wizmgr/mustard.cpp
@@ -0,0 +1,108 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Mustard.cpp : implementation file
+
+File History:
+
+ JonY Jan-96 created
+
+--*/
+
+#include "stdafx.h"
+#include "Mustard.h"
+#include "wizlist.h"
+#include "Startd.h"
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+/////////////////////////////////////////////////////////////////////////////
+// CMustardApp
+
+BEGIN_MESSAGE_MAP(CMustardApp, CWinApp)
+ //{{AFX_MSG_MAP(CMustardApp)
+ //}}AFX_MSG
+ ON_COMMAND(ID_HELP, CWinApp::OnHelp)
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CMustardApp construction
+
+BOOL CMustardApp::IsSecondInstance()
+{
+ HANDLE hSem;
+
+ //create a semaphore object with max count of 1
+ hSem = CreateSemaphore(NULL, 0, 1, L"Wizmgr Semaphore");
+ if (hSem!=NULL && GetLastError() == ERROR_ALREADY_EXISTS) {
+ CloseHandle(hSem);
+ CString csAppName;
+ csAppName.LoadString(AFX_IDS_APP_TITLE);
+ CWnd* pWnd = CWnd::FindWindow(NULL, (LPCTSTR)csAppName);
+ if (pWnd)
+ {
+ pWnd->ShowWindow(SW_RESTORE);
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+CMustardApp::CMustardApp()
+{
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// The one and only CMustardApp object
+
+CMustardApp theApp;
+
+/////////////////////////////////////////////////////////////////////////////
+// CMustardApp initialization
+
+BOOL CMustardApp::InitInstance()
+{
+ if (IsSecondInstance())
+ return FALSE;
+
+// check for OS version
+ OSVERSIONINFO os;
+ os.dwOSVersionInfoSize = sizeof(os);
+ GetVersionEx(&os);
+
+ if (os.dwMajorVersion < 4)
+ {
+ AfxMessageBox(IDS_BAD_VERSION, MB_ICONSTOP);
+ ExitProcess(0);
+ }
+ // Standard initialization
+
+#ifdef _AFXDLL
+ Enable3dControls(); // Call this when using MFC in a shared DLL
+#else
+ Enable3dControlsStatic(); // Call this when linking to MFC statically
+#endif
+
+ CStartD dlg;
+ m_pMainWnd = &dlg;
+ int nResponse = dlg.DoModal();
+ if (nResponse == IDOK)
+ {
+ }
+ else if (nResponse == IDCANCEL)
+ {
+ }
+
+ // Since the dialog has been closed, return FALSE so that we exit the
+ // application, rather than start the application's message pump.
+ return FALSE;
+}
diff --git a/private/utils/wizards/wizmgr/mustard.h b/private/utils/wizards/wizmgr/mustard.h
new file mode 100644
index 000000000..aacce3b71
--- /dev/null
+++ b/private/utils/wizards/wizmgr/mustard.h
@@ -0,0 +1,47 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ Mustard.h : main header file for the MUSTARD application
+
+File History:
+
+ JonY Jan-96 created
+
+--*/
+
+
+#ifndef __AFXWIN_H__
+ #error include 'stdafx.h' before including this file for PCH
+#endif
+
+#include "resource.h" // main symbols
+
+/////////////////////////////////////////////////////////////////////////////
+// CMustardApp:
+// See Mustard.cpp for the implementation of this class
+//
+
+class CMustardApp : public CWinApp
+{
+public:
+ CMustardApp();
+ BOOL IsSecondInstance();
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CMustardApp)
+ public:
+ virtual BOOL InitInstance();
+ //}}AFX_VIRTUAL
+
+// Implementation
+
+ //{{AFX_MSG(CMustardApp)
+ //}}AFX_MSG
+ DECLARE_MESSAGE_MAP()
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/private/utils/wizards/wizmgr/mustard.rc b/private/utils/wizards/wizmgr/mustard.rc
new file mode 100644
index 000000000..f9114e466
--- /dev/null
+++ b/private/utils/wizards/wizmgr/mustard.rc
@@ -0,0 +1,208 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#define _AFX_NO_SPLITTER_RESOURCES\r\n"
+ "#define _AFX_NO_OLE_RESOURCES\r\n"
+ "#define _AFX_NO_TRACKER_RESOURCES\r\n"
+ "#define _AFX_NO_PROPERTY_RESOURCES\r\n"
+ "\r\n"
+ "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
+ "#ifdef _WIN32\r\n"
+ "LANGUAGE 9, 1\r\n"
+ "#pragma code_page(1252)\r\n"
+ "#endif\r\n"
+ "#include ""res\\Mustard.rc2"" // non-Microsoft Visual C++ edited resources\r\n"
+ "#include ""afxres.rc"" // Standard components\r\n"
+ "#endif\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDR_MAINFRAME ICON DISCARDABLE "res\\Mustard.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_MUSTARD_DIALOG DIALOGEX 0, 0, 402, 246
+STYLE WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
+EXSTYLE WS_EX_APPWINDOW
+CAPTION "Administrative Wizards"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LISTBOX IDC_WIZ_LIST,2,48,199,175,LBS_OWNERDRAWVARIABLE |
+ LBS_NOINTEGRALHEIGHT | NOT WS_BORDER | WS_TABSTOP
+ LTEXT "Static",IDC_STATIC1,6,0,395,21
+ PUSHBUTTON "&Close",IDC_QUIT_BUTTON,347,227,50,14
+ CONTROL "&Show this Getting Started screen next time you log on",
+ IDC_STARTUP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,6,31,
+ 341,10
+ LISTBOX IDC_WIZ_LIST2,200,48,198,175,LBS_OWNERDRAWVARIABLE |
+ LBS_NOINTEGRALHEIGHT | NOT WS_BORDER | WS_TABSTOP
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_MUSTARD_DIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 395
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 239
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_BITMAP1 BITMAP DISCARDABLE "res\\bitmap2.bmp"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDR_ACCELERATOR1 ACCELERATORS DISCARDABLE
+BEGIN
+ "C", IDCANCEL, VIRTKEY, ALT, NOINVERT
+ "F", ID_ACCEL_SHARE, VIRTKEY, ALT, NOINVERT
+ "G", ID_ACCEL_GROUP, VIRTKEY, ALT, NOINVERT
+ "L", ID_ACCEL_LICENSE, VIRTKEY, ALT, NOINVERT
+ "M", ID_ACCEL_MODEM, VIRTKEY, ALT, NOINVERT
+ "N", ID_ACCEL_NETWORK, VIRTKEY, ALT, NOINVERT
+ "P", ID_ACCEL_PRINT, VIRTKEY, ALT, NOINVERT
+ "R", ID_ACCEL_PROGRAMS, VIRTKEY, ALT, NOINVERT
+ "U", ID_ACCEL_USER, VIRTKEY, ALT, NOINVERT
+ VK_ESCAPE, IDCANCEL, VIRTKEY, NOINVERT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_GENERIC_NO_HEAP "There is insufficient memory to continue. This program will exit."
+ IDS_GENERIC_NO_PRINTLIB "Error loading printui.dll. Add Printer wizard will not be run."
+ IDS_GENERIC_NO_PRINTER_CREATED
+ "An error occurred during the Add Printer wizard. No printer was created."
+ IDS_PRINT_NAME "Add &Printer"
+ IDS_PRINT_DESC "Set up printers that are connected to your computer or are on a network"
+ IDS_MODEM_NAME "Install New &Modem"
+ IDS_MODEM_DESC "Set up modems that are connected to your computer"
+ IDS_ARS_NAME "Add/&Remove Programs"
+ IDS_ARS_DESC "Install or remove programs from your computer"
+ IDS_WKSSETUP_NAME "&Network Client Administrator"
+ IDS_WKSSETUP_DESC "Installs or updates network client workstations"
+ IDS_GROUP_NAME "&Group Management"
+ IDS_GROUP_DESC "Create and modify group accounts"
+ IDS_USER_NAME "Add &User Accounts"
+ IDS_USER_DESC "Create new user accounts"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_SHRPUB_NAME "Managing &File and Folder Access"
+ IDS_SHRPUB_DESC "Set permissions on files and folders"
+ IDS_FDS_NAME "&License Compliance"
+ IDS_FDS_DESC "Check licensing for installed applications"
+ IDS_NO_START "Unable to start application at this time"
+ IDS_BAD_VERSION "You must be running Windows NT version 4.0 in order to use this application."
+ IDS_ADD_PRINTER "Add Printer"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ AFX_IDS_APP_TITLE "Administrative Wizards"
+ IDS_CAPTION "Getting started with Windows NT Server"
+ IDS_APPWIZ "Add/Remove Programs"
+ IDS_MODEM "Modems"
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+#define _AFX_NO_SPLITTER_RESOURCES
+#define _AFX_NO_OLE_RESOURCES
+#define _AFX_NO_TRACKER_RESOURCES
+#define _AFX_NO_PROPERTY_RESOURCES
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE 9, 1
+#pragma code_page(1252)
+#endif
+#include "res\Mustard.rc2" // non-Microsoft Visual C++ edited resources
+#include "afxres.rc" // Standard components
+#endif
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/private/utils/wizards/wizmgr/res/bitmap1.bmp b/private/utils/wizards/wizmgr/res/bitmap1.bmp
new file mode 100644
index 000000000..4fca8309c
--- /dev/null
+++ b/private/utils/wizards/wizmgr/res/bitmap1.bmp
Binary files differ
diff --git a/private/utils/wizards/wizmgr/res/bitmap2.bmp b/private/utils/wizards/wizmgr/res/bitmap2.bmp
new file mode 100644
index 000000000..ac1328d3f
--- /dev/null
+++ b/private/utils/wizards/wizmgr/res/bitmap2.bmp
Binary files differ
diff --git a/private/utils/wizards/wizmgr/res/mustard.ico b/private/utils/wizards/wizmgr/res/mustard.ico
new file mode 100644
index 000000000..09a54322a
--- /dev/null
+++ b/private/utils/wizards/wizmgr/res/mustard.ico
Binary files differ
diff --git a/private/utils/wizards/wizmgr/res/mustard.rc2 b/private/utils/wizards/wizmgr/res/mustard.rc2
new file mode 100644
index 000000000..618fe50b3
--- /dev/null
+++ b/private/utils/wizards/wizmgr/res/mustard.rc2
@@ -0,0 +1,27 @@
+//
+// MUSTARD.RC2 - resources Microsoft Visual C++ does not edit directly
+//
+
+#ifdef APSTUDIO_INVOKED
+ #error this file is not editable by Microsoft Visual C++
+#endif //APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Add manually edited resources here...
+
+/////////////////////////////////////////////////////////////////////////////
+
+//
+// Version resources
+//
+#include <winver.h>
+#include <ntverp.h>
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "wizard manager"
+#define VER_INTERNALNAME_STR "mustard.exe"
+#define VER_ORIGINALFILENAME_STR "wizmgr.exe"
+#include <common.ver>
+
+
diff --git a/private/utils/wizards/wizmgr/resource.h b/private/utils/wizards/wizmgr/resource.h
new file mode 100644
index 000000000..5906b40d4
--- /dev/null
+++ b/private/utils/wizards/wizmgr/resource.h
@@ -0,0 +1,59 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by Mustard.rc
+//
+#define IDS_GENERIC_NO_HEAP 1
+#define IDS_GENERIC_NO_PRINTLIB 2
+#define IDS_GENERIC_NO_PRINTER_CREATED 3
+#define IDS_PRINT_NAME 4
+#define IDS_PRINT_DESC 5
+#define IDS_MODEM_NAME 6
+#define IDS_MODEM_DESC 7
+#define IDS_ARS_NAME 8
+#define IDS_ARS_DESC 9
+#define IDS_WKSSETUP_NAME 10
+#define IDS_WKSSETUP_DESC 11
+#define IDS_GROUP_NAME 12
+#define IDS_GROUP_DESC 13
+#define IDS_USER_NAME 14
+#define IDS_USER_DESC 15
+#define IDS_SHRPUB_NAME 16
+#define IDS_SHRPUB_DESC 17
+#define IDS_FDS_NAME 18
+#define IDS_FDS_DESC 19
+#define IDS_NO_START 20
+#define IDS_BAD_VERSION 21
+#define IDS_ADD_PRINTER 22
+#define IDD_MUSTARD_DIALOG 102
+#define IDR_MAINFRAME 128
+#define IDB_BITMAP1 130
+#define IDR_ACCELERATOR1 131
+#define IDR_ACCELERATOR2 132
+#define IDC_WIZ_LIST 1000
+#define IDC_STATIC1 1002
+#define IDC_STATIC2 1003
+#define IDC_QUIT_BUTTON 1004
+#define IDC_STARTUP 1005
+#define IDC_WIZ_LIST2 1006
+#define ID_ACCEL_PRINT 32771
+#define ID_ACCEL_MODEM 32772
+#define ID_ACCEL_NETWORK 32773
+#define ID_ACCEL_GROUP 32774
+#define ID_ACCEL_USER 32775
+#define ID_ACCEL_SHARE 32776
+#define ID_ACCEL_PROGRAMS 32777
+#define ID_ACCEL_LICENSE 32779
+#define IDS_CAPTION 57345
+#define IDS_APPWIZ 57346
+#define IDS_MODEM 57347
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 133
+#define _APS_NEXT_COMMAND_VALUE 32780
+#define _APS_NEXT_CONTROL_VALUE 1006
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/private/utils/wizards/wizmgr/sources b/private/utils/wizards/wizmgr/sources
new file mode 100644
index 000000000..d30a3a961
--- /dev/null
+++ b/private/utils/wizards/wizmgr/sources
@@ -0,0 +1,42 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+TARGETNAME=wizmgr
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+USE_MFCUNICODE=1
+
+PRECOMPILED_INCLUDE=stdafx.h
+PRECOMPILED_CXX=1
+
+SOURCES=MUSTARD.CPP \
+ STARTD.CPP \
+ WIZLIST.CPP \
+ MUSTARD.RC
+
+UMTYPE=windows
+UMENTRY=wwinmain
+TARGETLIBS= \
+ $(BASEDIR)\public\sdk\lib\*\shell32.lib
diff --git a/private/utils/wizards/wizmgr/startd.cpp b/private/utils/wizards/wizmgr/startd.cpp
new file mode 100644
index 000000000..84c6fda8d
--- /dev/null
+++ b/private/utils/wizards/wizmgr/startd.cpp
@@ -0,0 +1,759 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ StartD.cpp : implementation file
+
+File History:
+
+ JonY Jan-96 created
+
+--*/
+
+
+#include "stdafx.h"
+#include "Mustard.h"
+#include "wizlist.h"
+#include "StartD.h"
+#include "Listdata.h"
+
+#include <winreg.h>
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+LPITEMIDLIST CreatePIDL(UINT cbSize);
+LPITEMIDLIST ConcatPIDLs(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
+LPITEMIDLIST Next(LPCITEMIDLIST pidl);
+UINT GetSize(LPCITEMIDLIST pidl);
+
+/////////////////////////////////////////////////////////////////////////////
+// CStartD dialog
+
+
+CStartD::CStartD(CWnd* pParent /*=NULL*/)
+ : CDialog(CStartD::IDD, pParent), m_bActive(TRUE),
+ m_hAccelTable(NULL)
+{
+ //{{AFX_DATA_INIT(CStartD)
+ m_bStartup = TRUE;
+ //}}AFX_DATA_INIT
+ m_pFont1 = NULL;
+ m_pFont2 = NULL;
+
+ m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
+
+// Load the accelerator tables.
+ m_hAccelTable = LoadAccelerators(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_ACCELERATOR1));
+}
+
+CStartD::~CStartD()
+{
+ if (m_pFont1 != NULL) delete m_pFont1;
+// if (m_pFont2 != NULL) delete m_pFont2;
+
+}
+void CStartD::DoDataExchange(CDataExchange* pDX)
+{
+ CDialog::DoDataExchange(pDX);
+ //{{AFX_DATA_MAP(CStartD)
+ DDX_Control(pDX, IDC_WIZ_LIST2, m_lbWizList2);
+ DDX_Control(pDX, IDC_WIZ_LIST, m_lbWizList);
+ DDX_Check(pDX, IDC_STARTUP, m_bStartup);
+ //}}AFX_DATA_MAP
+}
+
+
+BEGIN_MESSAGE_MAP(CStartD, CDialog)
+ //{{AFX_MSG_MAP(CStartD)
+ ON_WM_PAINT()
+ ON_BN_CLICKED(IDC_QUIT_BUTTON, OnQuitButton)
+ ON_WM_ACTIVATEAPP()
+ ON_WM_QUERYDRAGICON()
+ ON_WM_MOUSEMOVE()
+ //}}AFX_MSG_MAP
+ ON_COMMAND(ID_ACCEL_GROUP, OnAccelGroup)
+ ON_COMMAND(ID_ACCEL_MODEM, OnAccelModem)
+ ON_COMMAND(ID_ACCEL_NETWORK, OnAccelNetwork)
+ ON_COMMAND(ID_ACCEL_PRINT, OnAccelPrint)
+ ON_COMMAND(ID_ACCEL_SHARE, OnAccelShare)
+ ON_COMMAND(ID_ACCEL_USER, OnAccelUser)
+ ON_COMMAND(ID_ACCEL_PROGRAMS, OnAccelPrograms)
+ ON_COMMAND(ID_ACCEL_LICENSE, OnAccelLicense)
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CStartD message handlers
+BOOL CStartD::OnInitDialog()
+{
+ CDialog::OnInitDialog();
+
+// tell the two sides about each other
+ m_lbWizList2.m_pOtherGuy = &m_lbWizList;
+ m_lbWizList.m_pOtherGuy = &m_lbWizList2;
+
+ SetIcon(m_hIcon, TRUE); // Set big icon
+ SetIcon(m_hIcon, FALSE); // Set small icon
+
+// font information for the headings
+ m_pFont1 = new CFont;
+ LOGFONT lf;
+
+ memset(&lf, 0, sizeof(LOGFONT)); // Clear out structure.
+ lf.lfHeight = 35;
+ _tcscpy(lf.lfFaceName, L"Arial");
+ lf.lfWeight = 700;
+ m_pFont1->CreateFontIndirect(&lf); // Create the font.
+
+ CString cs;
+ cs.LoadString(IDS_CAPTION);
+ CWnd* pWnd = GetDlgItem(IDC_STATIC1);
+ pWnd->SetWindowText(cs);
+ pWnd->SetFont(m_pFont1);
+
+ CMustardApp* pApp = (CMustardApp*)AfxGetApp();
+
+// get install dir
+ TCHAR pSysDir[256];
+ UINT nLen = GetWindowsDirectory(pSysDir, 256);
+ if (*(pSysDir + nLen) != '\\') _tcscat(pSysDir, L"\\");
+ _tcscat(pSysDir, L"SYSTEM32\\");
+
+// Add User
+ CItemData* pData = new CItemData;
+ pData->csName.LoadString(IDS_USER_NAME);// = L"Add User";
+ pData->csDesc.LoadString(IDS_USER_DESC);// = L"Add User";
+
+ pData->csAppStart1 = pSysDir + CString(L"addusrw.exe");
+ pData->csAppStart2 = L"";
+
+ GetIconIndices(pData->csAppStart1, &pData->hIcon, &pData->hSelIcon);
+
+ m_lbWizList.InsertString(0, _T(""));
+ m_lbWizList.SetItemData(0, (long)pData);
+
+// Group Creation
+ pData = new CItemData;
+ pData->csName.LoadString(IDS_GROUP_NAME);// = L"Group Creation";
+ pData->csDesc.LoadString(IDS_GROUP_DESC);// = L"Group Creation";
+
+ pData->csAppStart1 = pSysDir + CString(L"addgrpw.exe");
+ pData->csAppStart2 = L"";
+
+ GetIconIndices(pData->csAppStart1, &pData->hIcon, &pData->hSelIcon);
+
+ m_lbWizList.InsertString(1, _T(""));
+ m_lbWizList.SetItemData(1, (long)pData);
+
+// Share Publishing / folder security
+ pData = new CItemData;
+ pData->csName.LoadString(IDS_SHRPUB_NAME);// = L"Share Publishing";
+ pData->csDesc.LoadString(IDS_SHRPUB_DESC);// = L"Share Publishing ";
+
+ pData->csAppStart1 = pSysDir + CString(L"shrpubw.exe");
+ pData->csAppStart2 = L"";
+
+ GetIconIndices(pData->csAppStart1, &pData->hIcon, &pData->hSelIcon);
+
+ m_lbWizList.InsertString(2, _T(""));
+ m_lbWizList.SetItemData(2, (long)pData);
+
+// printer
+ pData = new CItemData;
+ pData->csName.LoadString(IDS_PRINT_NAME);// = L"Add Printer";
+ pData->csDesc.LoadString(IDS_PRINT_DESC);// = L"Print manager";
+
+ pData->csAppStart1 = L"";
+ pData->csAppStart2 = L"";
+
+ GetCPLIcon(IDS_ADD_PRINTER, &pData->hIcon, &pData->hSelIcon, TRUE);
+
+ m_lbWizList.InsertString(3, _T(""));
+ m_lbWizList.SetItemData(3, (long)pData);
+
+// Add/remove software
+ pData = new CItemData;
+ pData->csName.LoadString(IDS_ARS_NAME);// = L"Add/Remove software";
+ pData->csDesc.LoadString(IDS_ARS_DESC);// = L"Add/Remove software";
+
+ pData->csAppStart1 = L"control.exe";
+ pData->csAppStart2 = L"appwiz.cpl";
+
+ GetCPLIcon(IDS_APPWIZ, &pData->hIcon, &pData->hSelIcon);
+
+ m_lbWizList2.InsertString(0, _T(""));
+ m_lbWizList2.SetItemData(0, (long)pData);
+
+// modem
+ pData = new CItemData;
+ pData->csName.LoadString(IDS_MODEM_NAME);// = L"Add Modem";
+ pData->csDesc.LoadString(IDS_MODEM_DESC);// = L"Modems, ports, etc";
+
+ pData->csAppStart1 = L"control.exe";
+ pData->csAppStart2 = L"modem.cpl";
+
+ GetCPLIcon(IDS_MODEM, &pData->hIcon, &pData->hSelIcon);
+
+ m_lbWizList2.InsertString(1, _T(""));
+ m_lbWizList2.SetItemData(1, (long)pData);
+
+// Workstation installation
+ pData = new CItemData;
+ pData->csName.LoadString(IDS_WKSSETUP_NAME);// = L"Workstation Installation";
+ pData->csDesc.LoadString(IDS_WKSSETUP_DESC);// = L"Workstation Installation";
+
+ pData->csAppStart1 = pSysDir + CString(L"ncadmin.exe");
+ pData->csAppStart2 = L"";
+
+ GetIconIndices(pData->csAppStart1, &pData->hIcon, &pData->hSelIcon);
+
+ m_lbWizList2.InsertString(2, _T(""));
+ m_lbWizList2.SetItemData(2, (long)pData);
+
+// license compliancy
+ pData = new CItemData;
+ pData->csName.LoadString(IDS_FDS_NAME);
+ pData->csDesc.LoadString(IDS_FDS_DESC);
+
+ pData->csAppStart1 = pSysDir + CString(L"lcwiz.exe");
+ pData->csAppStart2 = L"";
+
+ GetIconIndices(pData->csAppStart1, &pData->hIcon, &pData->hSelIcon);
+
+ m_lbWizList2.InsertString(3, _T(""));
+ m_lbWizList2.SetItemData(3, (long)pData);
+
+
+// check the registry to see if we are loaded automatically at startup
+ DWORD dwRet;
+ HKEY hKey;
+ DWORD cbProv = 0;
+ TCHAR* lpProv = NULL;
+
+ dwRet = RegOpenKey(HKEY_CURRENT_USER,
+ TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows"), &hKey );
+
+ TCHAR* lpStartup = NULL;
+ if ((dwRet = RegQueryValueEx( hKey, TEXT("run"), NULL, NULL, NULL, &cbProv )) == ERROR_SUCCESS)
+ {
+ lpStartup = (TCHAR*)malloc(cbProv);
+ if (lpStartup == NULL)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
+ ExitProcess(1);
+ }
+ dwRet = RegQueryValueEx( hKey, TEXT("run"), NULL, NULL, (LPBYTE) lpStartup, &cbProv );
+// see if we are included
+ if (_tcsstr(lpStartup, L"wizmgr.exe") != NULL)
+ m_bStartup = TRUE;
+ else m_bStartup = FALSE;
+ UpdateData(FALSE);
+ }
+
+ free(lpStartup);
+ RegCloseKey(hKey);
+
+ return TRUE; // return TRUE unless you set the focus to a control
+ // EXCEPTION: OCX Property Pages should return FALSE
+}
+
+void CStartD::OnPaint()
+{
+ CPaintDC dc(this); // device context for painting
+ if (IsIconic())
+ {
+
+ SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
+
+ // Center icon in client rectangle
+ int cxIcon = GetSystemMetrics(SM_CXICON);
+ int cyIcon = GetSystemMetrics(SM_CYICON);
+ CRect rect;
+ GetClientRect(&rect);
+ int x = (rect.Width() - cxIcon + 1) / 2;
+ int y = (rect.Height() - cyIcon + 1) / 2;
+
+ // Draw the icon
+ dc.DrawIcon(x, y, m_hIcon);
+ }
+
+ else
+ {
+ CPen pBlackPen(PS_SOLID, 1, RGB(0,0,0));
+ CPen* pOriginalPen = (CPen*)dc.SelectObject(pBlackPen);
+ dc.MoveTo(596, 77);
+ dc.LineTo(2, 77);
+ dc.LineTo(2, 362);
+
+ CPen pLtGreyPen(PS_SOLID, 1, RGB(192, 192, 192));
+ dc.SelectObject(pLtGreyPen);
+ dc.LineTo(596, 362);
+ dc.LineTo(596, 77);
+
+ CPen pDkGreyPen(PS_SOLID, 1, RGB(128, 128, 128));
+ dc.SelectObject(pDkGreyPen);
+ dc.MoveTo(597, 76);
+ dc.LineTo(1, 76);
+ dc.LineTo(1, 363);
+
+ CPen pWhitePen(PS_SOLID, 1, RGB(255, 255, 255));
+ dc.SelectObject(pWhitePen);
+ dc.MoveTo(2, 363);
+ dc.LineTo(598, 363);
+ dc.LineTo(598, 76);
+ }
+// Do not call CDialog::OnPaint() for painting messages
+}
+
+HCURSOR CStartD::OnQueryDragIcon()
+{
+ return (HCURSOR) m_hIcon;
+}
+
+void CStartD::OnQuitButton()
+{
+ CItemData* pData;
+ ULONG lData;
+
+ USHORT us = 0;
+ while((lData = m_lbWizList.GetItemData(us)) != LB_ERR)
+ {
+ pData = (CItemData*)lData;
+ delete pData;
+ m_lbWizList.DeleteString(us);
+ }
+
+ while((lData = m_lbWizList2.GetItemData(us)) != LB_ERR)
+ {
+ pData = (CItemData*)lData;
+ delete pData;
+ m_lbWizList2.DeleteString(us);
+ }
+
+// set the reg value for startup
+ UpdateData(TRUE);
+
+ DWORD dwRet;
+ HKEY hKey;
+ DWORD cbProv = 0;
+ TCHAR* lpProv = NULL;
+
+ dwRet = RegOpenKey(HKEY_CURRENT_USER,
+ TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows"), &hKey );
+
+ TCHAR* lpStartup = NULL;
+ if ((dwRet = RegQueryValueEx( hKey, TEXT("run"), NULL, NULL, NULL, &cbProv )) == ERROR_SUCCESS)
+ {
+ lpStartup = (TCHAR*)malloc(cbProv);
+ if (lpStartup == NULL)
+ {
+ AfxMessageBox(IDS_GENERIC_NO_HEAP, MB_ICONEXCLAMATION);
+ ExitProcess(1);
+ }
+ dwRet = RegQueryValueEx( hKey, TEXT("run"), NULL, NULL, (LPBYTE) lpStartup, &cbProv );
+
+// see if we are included
+ TCHAR* pPos;
+ if ((pPos = _tcsstr(lpStartup, L"wizmgr.exe")) != NULL) // included
+ {
+ if (!m_bStartup) // don't want to be
+ {
+ UINT nPos = pPos - lpStartup;
+ CString csCurrentValue = lpStartup;
+ CString csNewVal = csCurrentValue.Left(nPos);
+ csNewVal += csCurrentValue.Right(csCurrentValue.GetLength() - nPos - _tcslen(L"wizmgr.exe"));
+
+ RegSetValueEx(hKey,
+ TEXT("run"),
+ 0,
+ REG_SZ,
+ (BYTE *)csNewVal.GetBuffer(csNewVal.GetLength()),
+ csNewVal.GetLength() * sizeof(TCHAR));
+ }
+ }
+ else // not included
+ {
+ if (m_bStartup) // want to be
+ {
+ CString csNewVal = lpStartup;
+ csNewVal += L" wizmgr.exe";
+
+ RegSetValueEx(hKey,
+ TEXT("run"),
+ 0,
+ REG_SZ,
+ (BYTE *)csNewVal.GetBuffer(csNewVal.GetLength()),
+ csNewVal.GetLength() * sizeof(TCHAR));
+ }
+ }
+
+ UpdateData(FALSE);
+ }
+
+ free(lpStartup);
+ RegCloseKey(hKey);
+
+ EndDialog(1);
+}
+
+void CStartD::OnActivateApp(BOOL bActive, HTASK hTask)
+{
+ CDialog::OnActivateApp(bActive, hTask);
+
+ m_bActive = bActive;
+
+ // Remove the selections from the list boxes if
+ // the application is being deactivated.
+ if (!m_bActive)
+ {
+ m_lbWizList.SetCurSel(-1);
+ m_lbWizList2.SetCurSel(-1);
+ }
+}
+
+void CStartD::OnMouseMove(UINT nFlags, CPoint point)
+{
+ if (m_bActive)
+ {
+ // Remove the selection from the list boxes if
+ // the mouse has moved outside of them.
+ m_lbWizList.SetCurSel(-1);
+ m_lbWizList2.SetCurSel(-1);
+ }
+
+ CDialog::OnMouseMove(nFlags, point);
+}
+
+BOOL CStartD::PreTranslateMessage(MSG* pMsg)
+{
+ if (m_hAccelTable != NULL)
+ {
+ if (!TranslateAccelerator(GetSafeHwnd(), m_hAccelTable, pMsg) )
+ return CDialog::PreTranslateMessage(pMsg);
+ else
+ return TRUE;
+ }
+
+ return CDialog::PreTranslateMessage(pMsg);
+}
+
+void CStartD::HandleAccelerator1(USHORT nIndex)
+{
+ // Change the selection in the listbox and
+ // make it think it's been clicked.
+ // Remove the selection from the other listbox, too.
+ m_lbWizList.SetCurSel(nIndex);
+ m_lbWizList2.SetCurSel(-1);
+ m_lbWizList.PostMessage(WM_LBUTTONDOWN);
+}
+
+void CStartD::HandleAccelerator2(USHORT nIndex)
+{
+ m_lbWizList2.SetCurSel(nIndex);
+ m_lbWizList.SetCurSel(-1);
+ m_lbWizList2.PostMessage(WM_LBUTTONDOWN);
+}
+
+void CStartD::OnAccelUser()
+{
+ HandleAccelerator1(ACCEL_USER);
+}
+
+void CStartD::OnAccelGroup()
+{
+ HandleAccelerator1(ACCEL_GROUP);
+}
+
+void CStartD::OnAccelShare()
+{
+ HandleAccelerator1(ACCEL_SHARE);
+}
+
+void CStartD::OnAccelPrint()
+{
+ HandleAccelerator1(ACCEL_PRINT);
+}
+
+void CStartD::OnAccelPrograms()
+{
+ HandleAccelerator2(ACCEL_PROGRAMS);
+}
+
+void CStartD::OnAccelModem()
+{
+ HandleAccelerator2(ACCEL_MODEM);
+}
+
+void CStartD::OnAccelNetwork()
+{
+ HandleAccelerator2(ACCEL_NETWORK);
+}
+
+void CStartD::OnAccelLicense()
+{
+ HandleAccelerator2(ACCEL_LICENSE);
+}
+
+void CStartD::GetIconIndices(LPCTSTR pszPathName, HICON* hiNormal, HICON* hiSelected)
+{
+ SHFILEINFO sfi;
+
+ // Get the index for the normal icon.
+ SHGetFileInfo(pszPathName, 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_LARGEICON);
+ *hiNormal = sfi.hIcon;
+
+ // Get the index for the selected icon.
+ SHGetFileInfo(pszPathName, 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_LARGEICON | SHGFI_SELECTED);
+ *hiSelected = sfi.hIcon;
+}
+
+void CStartD::GetCPLIcon(UINT pszCplItem, HICON* hiNormal, HICON* hiSelected, BOOL bPrinters)
+{
+ LPSHELLFOLDER pshf, pshfCPLItem;
+ LPITEMIDLIST pidlCPLFolder, pidlCPLObj;
+ LPMALLOC pMalloc;
+ HRESULT hr;
+
+ // Get a pointer to the shell's IMalloc interface.
+ hr = SHGetMalloc(&pMalloc);
+
+ if (SUCCEEDED(hr))
+ {
+ // Get a pointer to the shell's IShellFolder interface.
+ hr = SHGetDesktopFolder(&pshf);
+
+ if (SUCCEEDED(hr))
+ {
+ // Get a PIDL for the specified folder.
+ if (!bPrinters)
+ hr = SHGetSpecialFolderLocation(GetSafeHwnd(), CSIDL_CONTROLS, &pidlCPLFolder);
+ else
+ hr = SHGetSpecialFolderLocation(GetSafeHwnd(), CSIDL_PRINTERS, &pidlCPLFolder);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = pshf->BindToObject(pidlCPLFolder, NULL, IID_IShellFolder, (LPVOID*)&pshfCPLItem);
+
+ if (SUCCEEDED(hr))
+ GetCPLObject(pszCplItem, pshfCPLItem, &pidlCPLObj, hiNormal, hiSelected, pidlCPLFolder);
+
+ }
+ pMalloc->Free(pidlCPLFolder);
+ }
+ }
+ pMalloc->Release();
+}
+
+HRESULT CStartD::GetCPLObject(UINT pszCplItem, LPSHELLFOLDER pshf, LPITEMIDLIST* ppidl, HICON* hiNormal, HICON* hiSelected, LPITEMIDLIST pParentPIDL)
+{
+ HRESULT hr;
+ LPENUMIDLIST pEnum;
+ LPMALLOC pMalloc;
+
+ // Get a pointer to the shell's IMalloc interface.
+ hr = SHGetMalloc(&pMalloc);
+
+ if (SUCCEEDED(hr))
+ {
+ // Get a pointer to the folder's IEnumIDList interface.
+ hr = pshf->EnumObjects(GetSafeHwnd(), SHCONTF_NONFOLDERS, &pEnum);
+
+ if (SUCCEEDED(hr))
+ {
+ STRRET str;
+ CString strCPLObj, strEnumObj;
+
+ // Load the display name for the control panel object.
+ strCPLObj.LoadString(pszCplItem);
+
+ // Enumerate the objects in the control panel folder.
+ while (pEnum->Next(1, ppidl, NULL) == NOERROR)
+ {
+ // Get the display name for the object.
+ hr = pshf->GetDisplayNameOf((LPCITEMIDLIST)*ppidl, SHGDN_INFOLDER, &str);
+
+ if (SUCCEEDED(hr))
+ {
+ // Copy the display name to the strEnumObj string.
+ switch (str.uType)
+ {
+ case STRRET_CSTR:
+ strEnumObj = str.cStr;
+ break;
+
+ case STRRET_OFFSET:
+ char pStr[255];
+ strcpy(pStr, (LPCSTR)(((UINT)*ppidl) + str.uOffset));
+ TCHAR wStr[255];
+ mbstowcs(wStr, pStr, 255);
+ strEnumObj = wStr;
+ break;
+
+ case STRRET_WSTR:
+ strEnumObj = str.pOleStr;
+ break;
+
+ case 0x04:
+ strEnumObj = (LPCTSTR)(((UINT)*ppidl) + str.uOffset);
+ break;
+
+ case 0x05:
+ {
+ TCHAR pStr[255];
+ memcpy(pStr, str.cStr, 255);
+ strEnumObj = pStr;
+ break;
+ }
+
+ default:
+ strEnumObj.Empty();
+ }
+
+ // If we found the correct object, exit the loop.
+ if (strCPLObj == strEnumObj)
+ {
+ LPITEMIDLIST pBigPIDL = ConcatPIDLs(pParentPIDL, *ppidl);
+ SHFILEINFO sfi;
+ // Get the index for the normal icon.
+ SHGetFileInfo((LPCTSTR)pBigPIDL, 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_LARGEICON | SHGFI_PIDL);
+ *hiNormal = sfi.hIcon;
+
+ // Get the index for the selected icon.
+ SHGetFileInfo((LPCTSTR)pBigPIDL, 0, &sfi, sizeof(sfi), SHGFI_ICON | SHGFI_LARGEICON | SHGFI_SELECTED | SHGFI_PIDL);
+ *hiSelected = sfi.hIcon;
+
+ }
+
+
+ // Free the PIDL returned by IEnumIDList::Next().
+ pMalloc->Free(*ppidl);
+
+ if (FAILED(hr))
+ {
+ TRACE(_T("IMalloc::Free failed.\n"));
+ break;
+ }
+ }
+ else
+ {
+ TRACE(_T("IShellFolder::GetDisplayNameOf failed.\n"));
+ }
+ }
+
+ // Release the IEnumIDList pointer.
+ pEnum->Release();
+ }
+ else
+ {
+ TRACE(_T("IShellFolder::EnumObjects failed.\n"));
+ }
+
+ // Release the IMalloc pointer.
+ pMalloc->Release();
+ }
+
+ return hr;
+}
+
+/****************************************************************************
+*
+* FUNCTION: Create(UINT cbSize)
+*
+* PURPOSE: Allocates a PIDL
+*
+****************************************************************************/
+LPITEMIDLIST CreatePIDL(UINT cbSize)
+{
+ LPMALLOC lpMalloc;
+ HRESULT hr;
+ LPITEMIDLIST pidl=NULL;
+
+ hr=SHGetMalloc(&lpMalloc);
+
+ if (FAILED(hr))
+ return 0;
+
+ pidl=(LPITEMIDLIST)lpMalloc->Alloc(cbSize);
+
+ if (pidl)
+ memset(pidl, 0, cbSize); // zero-init for external task alloc
+
+ if (lpMalloc) lpMalloc->Release();
+
+ return pidl;
+}
+
+/****************************************************************************
+*
+* FUNCTION: ConcatPidls(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
+*
+* PURPOSE: Concatenates two PIDLs
+*
+****************************************************************************/
+LPITEMIDLIST ConcatPIDLs(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
+{
+ LPITEMIDLIST pidlNew;
+ UINT cb1;
+ UINT cb2;
+
+ if (pidl1) //May be NULL
+ cb1 = GetSize(pidl1) - sizeof(pidl1->mkid.cb);
+ else
+ cb1 = 0;
+
+ cb2 = GetSize(pidl2);
+
+ pidlNew = CreatePIDL(cb1 + cb2);
+ if (pidlNew)
+ {
+ if (pidl1)
+ memcpy(pidlNew, pidl1, cb1);
+ memcpy(((LPSTR)pidlNew) + cb1, pidl2, cb2);
+ }
+ return pidlNew;
+}
+
+/****************************************************************************
+*
+* FUNCTION: Next(LPCITEMIDLIST pidl)
+*
+* PURPOSE: Gets the next PIDL in the list
+*
+****************************************************************************/
+LPITEMIDLIST Next(LPCITEMIDLIST pidl)
+{
+ LPSTR lpMem=(LPSTR)pidl;
+
+ lpMem+=pidl->mkid.cb;
+
+ return (LPITEMIDLIST)lpMem;
+}
+
+/****************************************************************************
+*
+* FUNCTION: GetSize(LPCITEMIDLIST pidl)
+*
+* PURPOSE: Gets the size of the PIDL
+*
+****************************************************************************/
+UINT GetSize(LPCITEMIDLIST pidl)
+{
+ UINT cbTotal = 0;
+ if (pidl)
+ {
+ cbTotal += sizeof(pidl->mkid.cb); // Null terminator
+ while (pidl->mkid.cb)
+ {
+ cbTotal += pidl->mkid.cb;
+ pidl = Next(pidl);
+ }
+ }
+
+ return cbTotal;
+}
+
diff --git a/private/utils/wizards/wizmgr/startd.h b/private/utils/wizards/wizmgr/startd.h
new file mode 100644
index 000000000..6636a9927
--- /dev/null
+++ b/private/utils/wizards/wizmgr/startd.h
@@ -0,0 +1,95 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ StartD.h : header file
+
+File History:
+
+ JonY Jan-96 created
+
+--*/
+
+
+// StartD.h : header file
+//
+/////////////////////////////////////////////////////////////////////////////
+// CStartD dialog
+
+class CStartD : public CDialog
+{
+// Construction
+public:
+ CStartD(CWnd* pParent = NULL); // standard constructor
+ ~CStartD();
+ inline BOOL IsActive() {return m_bActive;}
+
+// Dialog Data
+ //{{AFX_DATA(CStartD)
+ enum { IDD = IDD_MUSTARD_DIALOG };
+ CWizList m_lbWizList2;
+ CWizList m_lbWizList;
+ BOOL m_bStartup;
+ //}}AFX_DATA
+
+// CStatPic m_statPic;
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CStartD)
+ public:
+ virtual BOOL PreTranslateMessage(MSG* pMsg);
+ protected:
+ virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
+ //}}AFX_VIRTUAL
+
+// Implementation
+protected:
+ HICON m_hIcon;
+ BOOL m_bActive;
+ HACCEL m_hAccelTable;
+
+ enum
+ {
+ ACCEL_USER = 0,
+ ACCEL_GROUP,
+ ACCEL_SHARE,
+ ACCEL_PRINT,
+ ACCEL_PROGRAMS = 0,
+ ACCEL_MODEM,
+ ACCEL_NETWORK,
+ ACCEL_LICENSE
+ };
+
+ void HandleAccelerator1(USHORT nIndex);
+ void HandleAccelerator2(USHORT nIndex);
+
+ // Generated message map functions
+ //{{AFX_MSG(CStartD)
+ virtual BOOL OnInitDialog();
+ afx_msg void OnPaint();
+ afx_msg void OnQuitButton();
+ afx_msg void OnActivateApp(BOOL bActive, HTASK hTask);
+ afx_msg HCURSOR OnQueryDragIcon();
+ afx_msg void OnMouseMove(UINT nFlags, CPoint point);
+ //}}AFX_MSG
+ afx_msg void OnAccelGroup();
+ afx_msg void OnAccelModem();
+ afx_msg void OnAccelNetwork();
+ afx_msg void OnAccelPrint();
+ afx_msg void OnAccelShare();
+ afx_msg void OnAccelUser();
+ afx_msg void OnAccelPrograms();
+ afx_msg void OnAccelLicense();
+
+ DECLARE_MESSAGE_MAP()
+
+private:
+ CFont* m_pFont1;
+ CFont* m_pFont2;
+ void GetIconIndices(LPCTSTR pszPathName, HICON* hiNormal, HICON* hiSelected);
+ void GetCPLIcon(UINT pszCplItem, HICON* hiNormal, HICON* hiSelected, BOOL bPrinters = FALSE);
+ HRESULT GetCPLObject(UINT pszCplItem, LPSHELLFOLDER pshf, LPITEMIDLIST* ppidl, HICON* hiNormal, HICON* hiSelected, LPITEMIDLIST pParentPIDL);
+
+};
diff --git a/private/utils/wizards/wizmgr/stdafx.cpp b/private/utils/wizards/wizmgr/stdafx.cpp
new file mode 100644
index 000000000..4a444224f
--- /dev/null
+++ b/private/utils/wizards/wizmgr/stdafx.cpp
@@ -0,0 +1,20 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ stdafx.cpp : implementation file
+
+File History:
+
+ JonY Jan-96 created
+
+--*/
+
+// stdafx.cpp : source file that includes just the standard includes
+// Mustard.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
diff --git a/private/utils/wizards/wizmgr/stdafx.h b/private/utils/wizards/wizmgr/stdafx.h
new file mode 100644
index 000000000..3ae9f9cb0
--- /dev/null
+++ b/private/utils/wizards/wizmgr/stdafx.h
@@ -0,0 +1,30 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ stdafx.h : header file
+
+File History:
+
+ JonY Jan-96 created
+
+--*/
+
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers
+
+#include <afxwin.h> // MFC core and standard components
+#include <afxext.h> // MFC extensions
+#ifndef _AFX_NO_AFXCMN_SUPPORT
+#include <afxcmn.h> // MFC support for Windows 95 Common Controls
+#endif // _AFX_NO_AFXCMN_SUPPORT
+
+
+
+
diff --git a/private/utils/wizards/wizmgr/wizlist.cpp b/private/utils/wizards/wizmgr/wizlist.cpp
new file mode 100644
index 000000000..a2afb6dd3
--- /dev/null
+++ b/private/utils/wizards/wizmgr/wizlist.cpp
@@ -0,0 +1,535 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ WizList.cpp : implementation file
+
+File History:
+
+ JonY Jan-96 created
+
+--*/
+
+#include "stdafx.h"
+#include "Mustard.h"
+#include "WizList.h"
+#include "Listdata.h"
+#include "startd.h"
+#include <winnetwk.h>
+#include <shlobj.h>
+
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#undef THIS_FILE
+static char THIS_FILE[] = __FILE__;
+#endif
+
+const USHORT BITMAP_WIDTH = 32;
+const USHORT BITMAP_HEIGHT = 32;
+const USHORT MAX_PRINTER_NAME = 256 + 2;
+const USHORT CELL_HEIGHT = 71;
+const USHORT CELL_WIDTH = 300;
+
+typedef BOOL (*BPRINTERSETUP)(HWND, UINT, UINT, LPTSTR, UINT*, LPCTSTR);
+
+
+/////////////////////////////////////////////////////////////////////////////
+// CWizList
+
+CWizList::CWizList()
+{
+// regular font
+ m_pFont = new CFont;
+ LOGFONT lf;
+
+ memset(&lf, 0, sizeof(LOGFONT)); // Clear out structure.
+ lf.lfHeight = 16;
+ _tcscpy(lf.lfFaceName, TEXT("Arial"));
+ lf.lfWeight = 100;
+ m_pFont->CreateFontIndirect(&lf); // Create the font.
+
+// bold font
+ m_pFontBold = new CFont;
+
+ memset(&lf, 0, sizeof(LOGFONT)); // Clear out structure.
+ lf.lfHeight = 16;
+ _tcscpy(lf.lfFaceName, TEXT("Arial"));
+ lf.lfWeight = 700;
+ m_pFontBold->CreateFontIndirect(&lf); // Create the font.
+
+ m_hPrinterLib = NULL;
+
+}
+
+CWizList::~CWizList()
+{
+ if (m_pFont != NULL) delete m_pFont;
+ if (m_pFontBold != NULL) delete m_pFontBold;
+ if (m_hPrinterLib != NULL) FreeLibrary(m_hPrinterLib);
+
+}
+
+
+BEGIN_MESSAGE_MAP(CWizList, CListBox)
+ //{{AFX_MSG_MAP(CWizList)
+ ON_WM_MOUSEMOVE()
+ ON_WM_LBUTTONDOWN()
+ ON_CONTROL_REFLECT(LBN_SETFOCUS, OnSetfocus)
+ //}}AFX_MSG_MAP
+END_MESSAGE_MAP()
+
+/////////////////////////////////////////////////////////////////////////////
+// CWizList message handlers
+
+void CWizList::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
+{
+ COLORREF crefOldText;
+
+ CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
+ pDC->SetBkMode(OPAQUE);
+
+// save the current font for later
+ CFont* pOldFont = (CFont*)pDC->SelectObject(m_pFont);
+
+ CItemData* pData = (CItemData*)GetItemData(lpDrawItemStruct->itemID);
+ LPCTSTR pName2 = (const TCHAR*)pData->csDesc;
+ LPCTSTR pName = (const TCHAR*)pData->csName;
+
+ HICON hIcon = pData->hIcon;
+ HICON hSelIcon = pData->hSelIcon;
+
+ int nTop = (lpDrawItemStruct->rcItem.bottom + lpDrawItemStruct->rcItem.top) / 2;
+ switch (lpDrawItemStruct->itemAction)
+ {
+ case ODA_SELECT:
+ case ODA_DRAWENTIRE:
+
+// paint the left side - then draw text
+ CRect crRight(50, lpDrawItemStruct->rcItem.top,
+ lpDrawItemStruct->rcItem.right,
+ lpDrawItemStruct->rcItem.bottom);
+
+ CBrush* pBrush = new CBrush;
+ pBrush->CreateSolidBrush(GetSysColor(COLOR_WINDOW));
+
+ pDC->FillRect(crRight, pBrush);
+
+// paint the right - then draw text
+ pDC->SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
+
+ crRight = CRect(lpDrawItemStruct->rcItem.left, lpDrawItemStruct->rcItem.top,
+ 50,
+ lpDrawItemStruct->rcItem.bottom);
+ pDC->FillRect(crRight, pBrush);
+
+ crRight = CRect(lpDrawItemStruct->rcItem.left + 5, lpDrawItemStruct->rcItem.top + 3,
+ 140,
+ lpDrawItemStruct->rcItem.bottom);
+
+// Is the item selected?
+ if (lpDrawItemStruct->itemState & ODS_SELECTED)
+ {
+// Display bitmap
+ nTop = (lpDrawItemStruct->rcItem.bottom + lpDrawItemStruct->rcItem.top - BITMAP_HEIGHT) / 2;
+ pDC->DrawIcon(lpDrawItemStruct->rcItem.left + 9, nTop - 9, hSelIcon);
+
+// paint the right - then draw text
+ crefOldText = pDC->SetTextColor(GetSysColor(COLOR_HIGHLIGHTTEXT));
+ pDC->SetBkColor(GetSysColor(COLOR_HIGHLIGHT));
+ }
+ else
+ {
+// Display bitmap
+ nTop = (lpDrawItemStruct->rcItem.bottom + lpDrawItemStruct->rcItem.top - BITMAP_HEIGHT) / 2;
+ pDC->DrawIcon(lpDrawItemStruct->rcItem.left + 9, nTop - 9, hIcon);
+
+ crefOldText = pDC->SetTextColor(GetSysColor(COLOR_WINDOWTEXT));
+ pDC->SetBkColor(GetSysColor(COLOR_WINDOW));
+ }
+
+// draw the top (bold) text
+ pDC->SelectObject(m_pFontBold);
+ CRect crTop = CRect(60, lpDrawItemStruct->rcItem.top + 8,
+ lpDrawItemStruct->rcItem.right - 10, lpDrawItemStruct->rcItem.bottom);
+
+ pDC->DrawText(pName, _tcslen(pName),
+ crTop,
+ DT_WORDBREAK);
+
+// draw the lower text
+ pDC->SelectObject(m_pFont);
+
+ CRect crBottom = CRect(60, lpDrawItemStruct->rcItem.top + 28,
+ lpDrawItemStruct->rcItem.right - 10, lpDrawItemStruct->rcItem.bottom);
+
+ pDC->DrawText(pName2, _tcslen(pName2),
+ crBottom,
+ DT_WORDBREAK);
+
+ pDC->SelectObject(pOldFont);
+
+ pDC->SetTextColor(crefOldText );
+
+ delete pBrush;
+ break;
+ }
+// Restore the original font
+ pDC->SelectObject(pOldFont);
+
+}
+
+void CWizList::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
+{
+ lpMeasureItemStruct->itemHeight = CELL_HEIGHT;
+ lpMeasureItemStruct->itemWidth = CELL_WIDTH;
+}
+
+void CWizList::OnMouseMove(UINT nFlags, CPoint point)
+{
+ if (((CStartD*)GetParent())->IsActive())
+ {
+ USHORT y = point.y / CELL_HEIGHT;
+ USHORT usCurSel = GetCurSel();
+
+ if (usCurSel != y) SetCurSel(y);
+
+ // tell the other guy not to show any selection
+ m_pOtherGuy->SetCurSel(-1);
+ }
+
+ CListBox::OnMouseMove(nFlags, point);
+}
+
+void CWizList::OnLButtonDown(UINT nFlags, CPoint point)
+{
+ USHORT usCurSel = GetCurSel();
+
+ // Exit if there's no selection.
+ if (usCurSel == (USHORT)-1)
+ return;
+
+ CItemData* pData = (CItemData*)GetItemData(usCurSel);
+
+// is this the printer wiz?
+ if (pData->csAppStart1 == "")
+ {
+ try
+ {
+ LaunchPrinterWizard();
+ }
+ catch (...)
+ {
+ TRACE(_T("An exception occurred while attempting to start the Add Printer Wizard.\n"));
+ }
+ }
+ else
+ {
+// otherwise
+ CString csCmdLine = pData->csAppStart1 + " ";
+ csCmdLine += pData->csAppStart2;
+ TCHAR* pCmdLine = csCmdLine.GetBuffer(csCmdLine.GetLength());
+
+ STARTUPINFO sInfo;
+ ZeroMemory(&sInfo, sizeof(sInfo));
+ sInfo.cb = sizeof(sInfo);
+
+ PROCESS_INFORMATION pInfo;
+
+ BOOL bProc = CreateProcess(NULL,
+ pCmdLine,
+ NULL, NULL,
+ TRUE,
+ NORMAL_PRIORITY_CLASS,
+ NULL, NULL,
+ &sInfo,
+ &pInfo);
+
+ if (!bProc) AfxMessageBox(IDS_NO_START);
+ csCmdLine.ReleaseBuffer();
+
+ }
+
+// CListBox::OnLButtonDown(nFlags, point);
+}
+
+void CWizList::PumpMessages()
+{
+ MSG msg;
+// check outstanding messages
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ if (!IsDialogMessage(&msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+}
+
+BOOL CWizList::LaunchPrinterWizard()
+{
+ CWaitCursor wc;
+ BOOL bReturn = TRUE;
+ HRESULT hr;
+ LPSHELLFOLDER pshf, pshfPrinters;
+ LPITEMIDLIST pidlPrintFolder, pidlPrintObj;
+ LPMALLOC pMalloc;
+
+ // Get a pointer to the shell's IMalloc interface.
+ hr = SHGetMalloc(&pMalloc);
+
+ if (SUCCEEDED(hr))
+ {
+ // Get a pointer to the shell's IShellFolder interface.
+ hr = SHGetDesktopFolder(&pshf);
+
+ if (SUCCEEDED(hr))
+ {
+ // Get a PIDL for the Printers folder.
+ hr = SHGetSpecialFolderLocation(GetSafeHwnd(), CSIDL_PRINTERS, &pidlPrintFolder);
+
+ if (SUCCEEDED(hr))
+ {
+ // Get a pointer to the IShellFolder interface for the Printer folder.
+ hr = pshf->BindToObject(pidlPrintFolder, NULL, IID_IShellFolder, (LPVOID*)&pshfPrinters);
+
+ if (SUCCEEDED(hr))
+ {
+ // Get a PIDL for the Add Printer object in the Printers folder.
+ hr = GetAddPrinterObject(pshfPrinters, &pidlPrintObj);
+
+ if (SUCCEEDED(hr))
+ {
+ LPCONTEXTMENU pcm;
+
+ // Get a pointer to the Printer folder's IContextMenu interface.
+ hr = pshfPrinters->GetUIObjectOf(GetSafeHwnd(), 1, (LPCITEMIDLIST*)&pidlPrintObj, IID_IContextMenu, NULL, (LPVOID*)&pcm);
+
+ if (SUCCEEDED(hr))
+ {
+ // Create a popup menu to hold the items in the context menu.
+ HMENU hMenu = CreatePopupMenu();
+
+ if (hMenu != NULL)
+ {
+ // Fill the menu.
+ hr = pcm->QueryContextMenu(hMenu, 0, 1, 0x7FFF, CMF_EXPLORE);
+
+ if (SUCCEEDED(hr))
+ {
+ CString strCmd(CMDSTR_NEWFOLDER);
+ CHAR szCmd[MAX_PATH + 1];
+ int i, nCmd, nItems = ::GetMenuItemCount(hMenu);
+
+ for (i = 0; i < nItems; i++)
+ {
+ // Search through the menu to find the language-independent
+ // identifier for the Add Printer object's Open command.
+ nCmd = GetMenuItemID(hMenu, i);
+ hr = pcm->GetCommandString(i, GCS_VERB, NULL, szCmd, MAX_PATH);
+
+ TCHAR wStr[255];
+ memcpy(wStr, szCmd, 255);
+ if (SUCCEEDED(hr) && strCmd == wStr)
+ {
+
+ CMINVOKECOMMANDINFO cmi;
+
+ cmi.cbSize = sizeof(CMINVOKECOMMANDINFO);
+ cmi.fMask = 0;
+ cmi.hwnd = GetSafeHwnd();
+ cmi.lpVerb = (LPSTR)MAKEINTRESOURCE(nCmd - 1);
+ cmi.lpParameters = NULL;
+ cmi.lpDirectory = NULL;
+ cmi.nShow = SW_SHOW;
+ cmi.dwHotKey = 0;
+ cmi.hIcon = NULL;
+
+ // Invoke the Open command.
+ hr = pcm->InvokeCommand(&cmi);
+
+ // Exit the loop.
+ break;
+
+ if (FAILED(hr))
+ {
+ TRACE(_T("IContextMenu::InvokeCommand failed.\n"));
+ bReturn = FALSE;
+ }
+ }
+ else
+ {
+ TRACE(_T("IContextMenu::GetCommandString failed.\n"));
+ bReturn = FALSE;
+ }
+ }
+
+ pcm->Release();
+ }
+ else
+ {
+ TRACE(_T("IShellFolder::GetUIObjectOf failed.\n"));
+ bReturn = FALSE;
+ }
+
+ // Destroy the temporary menu.
+ if (!DestroyMenu(hMenu))
+ TRACE(_T("DestroyMenu failed.\n"));
+ }
+ else
+ {
+ TRACE(_T("CreatePopupMenu failed.\n"));
+ bReturn = FALSE;
+ }
+ }
+
+ // Release the IShellFolder interface for the Printers folder.
+ pshfPrinters->Release();
+ }
+
+ // Free the PIDL for the Add Printer object.
+ pMalloc->Free(pidlPrintObj);
+ }
+ else
+ {
+ TRACE(_T("IShellFolder::BindToObject failed.\n"));
+ bReturn = FALSE;
+ }
+
+ // Free the PIDL for the Printers folder.
+ pMalloc->Free(pidlPrintFolder);
+ }
+ else
+ {
+ TRACE(_T("SHGetSpecialFolderLocation failed.\n"));
+ bReturn = FALSE;
+ }
+
+ // Release the pointer to the shell's IShellFolder interface.
+ pshf->Release();
+ }
+ else
+ {
+ TRACE(_T("SHGetDesktopFolder failed.\n"));
+ bReturn = FALSE;
+ }
+
+ // Release the pointer to the shell's IMalloc interface.
+ pMalloc->Release();
+ }
+ else
+ {
+ TRACE(_T("SHGetMalloc failed.\n"));
+ bReturn = FALSE;
+ }
+
+ return bReturn;
+}
+
+HRESULT CWizList::GetAddPrinterObject(LPSHELLFOLDER pshf, LPITEMIDLIST* ppidl)
+{
+ HRESULT hr;
+ LPENUMIDLIST pEnum;
+ LPMALLOC pMalloc;
+
+ // Get a pointer to the shell's IMalloc interface.
+ hr = SHGetMalloc(&pMalloc);
+
+ if (SUCCEEDED(hr))
+ {
+ // Get a pointer to the folder's IEnumIDList interface.
+ hr = pshf->EnumObjects(GetSafeHwnd(), SHCONTF_NONFOLDERS, &pEnum);
+
+ if (SUCCEEDED(hr))
+ {
+ STRRET str;
+ CString strPrintObj, strEnumObj;
+
+ // Load the display name for the Add Printer object.
+ strPrintObj.LoadString(IDS_ADD_PRINTER);
+
+ // Enumerate the objects in the Printers folder.
+ while (pEnum->Next(1, ppidl, NULL) == NOERROR)
+ {
+ // Get the display name for the object.
+ hr = pshf->GetDisplayNameOf((LPCITEMIDLIST)*ppidl, SHGDN_INFOLDER, &str);
+
+ if (SUCCEEDED(hr))
+ {
+ // Copy the display name to the strEnumObj string.
+ switch (str.uType)
+ {
+ case STRRET_CSTR:
+ strEnumObj = str.cStr;
+ break;
+
+ case STRRET_OFFSET:
+ char pStr[255];
+ strcpy(pStr, (LPCSTR)(((UINT)*ppidl) + str.uOffset));
+ TCHAR wStr[255];
+ mbstowcs(wStr, pStr, 255);
+ strEnumObj = wStr;
+ break;
+
+ case STRRET_WSTR:
+ strEnumObj = str.pOleStr;
+ break;
+
+ case 0x04: //STRRET_OFFSETW
+ strEnumObj = (LPCTSTR)(((UINT)*ppidl) + str.uOffset);
+ break;
+
+ case 0x05:
+ {
+ TCHAR pStr[255];
+ memcpy(pStr, str.cStr, 255);
+ strEnumObj = pStr;
+ break;
+ }
+
+ default:
+ strEnumObj.Empty();
+ }
+
+ // If we found the correct object, exit the loop.
+ if (strPrintObj == strEnumObj)
+ break;
+
+ // Free the PIDL returned by IEnumIDList::Next().
+ pMalloc->Free(*ppidl);
+
+ if (FAILED(hr))
+ {
+ TRACE(_T("IMalloc::Free failed.\n"));
+ break;
+ }
+ }
+ else
+ {
+ TRACE(_T("IShellFolder::GetDisplayNameOf failed.\n"));
+ }
+ }
+
+ // Release the IEnumIDList pointer.
+ pEnum->Release();
+ }
+ else
+ {
+ TRACE(_T("IShellFolder::EnumObjects failed.\n"));
+ }
+
+ // Release the IMalloc pointer.
+ pMalloc->Release();
+ }
+
+ return hr;
+}
+
+void CWizList::OnSetfocus()
+{
+// tell the other guy not to show any selection
+ m_pOtherGuy->SetCurSel(-1);
+
+}
diff --git a/private/utils/wizards/wizmgr/wizlist.h b/private/utils/wizards/wizmgr/wizlist.h
new file mode 100644
index 000000000..f7fca29c9
--- /dev/null
+++ b/private/utils/wizards/wizmgr/wizlist.h
@@ -0,0 +1,71 @@
+/*++
+
+Copyright (c) 1996 Microsoft Corporation
+
+Module Name:
+
+ WizList.h : header file
+
+File History:
+
+ JonY Jan-96 created
+
+--*/
+
+
+#include <winnetwk.h>
+#include <shlobj.h>
+
+/////////////////////////////////////////////////////////////////////////////
+// CWizList window
+
+class CWizList : public CListBox
+{
+// Construction
+public:
+ CWizList();
+
+// Attributes
+public:
+ CWizList* m_pOtherGuy;
+ void PumpMessages();
+
+// Operations
+public:
+private:
+ BOOL LaunchPrinterWizard();
+ HRESULT GetAddPrinterObject(LPSHELLFOLDER pshf, LPITEMIDLIST* ppidl);
+
+ CFont* m_pFont;
+ CFont* m_pFontBold;
+
+ BOOL m_bSignalled;
+
+
+// Overrides
+ // ClassWizard generated virtual function overrides
+ //{{AFX_VIRTUAL(CWizList)
+ public:
+ virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
+ virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
+ //}}AFX_VIRTUAL
+
+// Implementation
+public:
+ virtual ~CWizList();
+
+ // Generated message map functions
+protected:
+ //{{AFX_MSG(CWizList)
+ afx_msg void OnMouseMove(UINT nFlags, CPoint point);
+ afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
+ afx_msg void OnSetfocus();
+ //}}AFX_MSG
+
+ DECLARE_MESSAGE_MAP()
+
+private:
+ HMODULE m_hPrinterLib;
+};
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/private/utils/xcopy/argument.cxx b/private/utils/xcopy/argument.cxx
new file mode 100644
index 000000000..07caf733d
--- /dev/null
+++ b/private/utils/xcopy/argument.cxx
@@ -0,0 +1,875 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Argument
+
+Abstract:
+
+ Argument processing for the XCopy directory copy utility
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 01-May-1991
+
+Notes:
+
+ The arguments accepted by the XCopy utility are:
+
+ Source directory.- Source path.
+
+ Dest. directory.- Destination path.
+
+ Archive switch.- Copy files that have their archive bit set
+
+ Date.- Copy files modified on or after the specifiec
+ date.
+
+ Empty switch.- Copy directories even if empty. Subdir switch
+ must also be set.
+
+ Modify switch.- Same as Archive switch, but turns off archive
+ bit in the source file after copying.
+
+ Prompt switch.- Prompts before copying each file.
+
+ Subdir switch.- Copies also subdirectories, unless they are empty.
+ (Empty directories are copied if the Empty switch
+ is set).
+
+ Verify switch.- Verifies each copy.
+
+ Wait switch.- Wait before starting to copy the files.
+
+Revision History:
+
+
+--*/
+
+
+#include "ulib.hxx"
+#include "arg.hxx"
+#include "arrayit.hxx"
+#include "dir.hxx"
+#include "xcopy.hxx"
+#include "stringar.hxx"
+#include "file.hxx"
+#include "filestrm.hxx"
+
+//
+// Switch characters. Used for maintaining DOS5 compatibility when
+// displaying error messages
+//
+#define SWITCH_CHARACTERS "dDaAeEmMpPsSvVwW?"
+
+//
+// Static variables
+//
+
+PARRAY LexArray;
+PPATH_ARGUMENT FirstPathArgument = NULL;
+PPATH_ARGUMENT FirstQuotedPathArgument = NULL;
+PPATH_ARGUMENT SecondPathArgument = NULL;
+PPATH_ARGUMENT SecondQuotedPathArgument = NULL;
+PFLAG_ARGUMENT ArchiveArgument = NULL;
+PTIMEINFO_ARGUMENT DateArgument = NULL;
+PFLAG_ARGUMENT EmptyArgument = NULL;
+PFLAG_ARGUMENT ModifyArgument = NULL;
+PFLAG_ARGUMENT PromptArgument = NULL;
+PFLAG_ARGUMENT SubdirArgument = NULL;
+PFLAG_ARGUMENT VerifyArgument = NULL;
+PFLAG_ARGUMENT WaitArgument = NULL;
+PFLAG_ARGUMENT HelpArgument = NULL;
+PFLAG_ARGUMENT ContinueArgument = NULL;
+
+PFLAG_ARGUMENT IntelligentArgument = NULL;
+PFLAG_ARGUMENT VerboseArgument = NULL;
+PFLAG_ARGUMENT OldArgument = NULL;
+PFLAG_ARGUMENT HiddenArgument = NULL;
+PFLAG_ARGUMENT ReadOnlyArgument = NULL;
+PFLAG_ARGUMENT SilentArgument = NULL;
+PFLAG_ARGUMENT NoCopyArgument = NULL;
+PFLAG_ARGUMENT StructureArgument = NULL;
+PFLAG_ARGUMENT UpdateArgument = NULL;
+PFLAG_ARGUMENT CopyAttrArgument = NULL;
+PFLAG_ARGUMENT UseShortArgument = NULL;
+PFLAG_ARGUMENT RestartableArgument = NULL;
+
+PSTRING_ARGUMENT ExclusionListArgument = NULL;
+
+PSTRING_ARGUMENT InvalidSwitchArgument = NULL;
+
+
+BOOLEAN HelpSwitch;
+
+//
+// Prototypes
+//
+
+
+VOID
+XCOPY::SetArguments(
+ )
+
+/*++
+
+Routine Description:
+
+ Obtains the arguments for the XCopy utility
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+
+ PATH_ARGUMENT LocalFirstPathArgument;
+ PATH_ARGUMENT LocalFirstQuotedPathArgument;
+ PATH_ARGUMENT LocalSecondPathArgument;
+ PATH_ARGUMENT LocalSecondQuotedPathArgument;
+ FLAG_ARGUMENT LocalArchiveArgument;
+ TIMEINFO_ARGUMENT LocalDateArgument;
+ FLAG_ARGUMENT LocalOldArgument;
+ FLAG_ARGUMENT LocalEmptyArgument;
+ FLAG_ARGUMENT LocalModifyArgument;
+ FLAG_ARGUMENT LocalPromptArgument;
+ FLAG_ARGUMENT LocalSubdirArgument;
+ FLAG_ARGUMENT LocalVerifyArgument;
+ FLAG_ARGUMENT LocalWaitArgument;
+ FLAG_ARGUMENT LocalHelpArgument;
+ FLAG_ARGUMENT LocalContinueArgument;
+ FLAG_ARGUMENT LocalIntelligentArgument;
+ FLAG_ARGUMENT LocalVerboseArgument;
+ FLAG_ARGUMENT LocalHiddenArgument;
+ FLAG_ARGUMENT LocalReadOnlyArgument;
+ FLAG_ARGUMENT LocalSilentArgument;
+ FLAG_ARGUMENT LocalNoCopyArgument;
+ FLAG_ARGUMENT LocalStructureArgument;
+ FLAG_ARGUMENT LocalUpdateArgument;
+ FLAG_ARGUMENT LocalCopyAttrArgument;
+ FLAG_ARGUMENT LocalUseShortArgument;
+ FLAG_ARGUMENT LocalRestartableArgument;
+ STRING_ARGUMENT LocalExclusionListArgument;
+
+
+ STRING_ARGUMENT LocalInvalidSwitchArgument;
+ ARRAY LocalLexArray;
+
+ //
+ // Set the static global pointers
+ //
+ FirstPathArgument = &LocalFirstPathArgument;
+ FirstQuotedPathArgument = &LocalFirstQuotedPathArgument;
+ SecondPathArgument = &LocalSecondPathArgument;
+ SecondQuotedPathArgument = &LocalSecondQuotedPathArgument;
+ ArchiveArgument = &LocalArchiveArgument;
+ DateArgument = &LocalDateArgument;
+ OldArgument = &LocalOldArgument;
+ EmptyArgument = &LocalEmptyArgument;
+ ModifyArgument = &LocalModifyArgument;
+ PromptArgument = &LocalPromptArgument;
+ SubdirArgument = &LocalSubdirArgument;
+ VerifyArgument = &LocalVerifyArgument;
+ WaitArgument = &LocalWaitArgument;
+ HelpArgument = &LocalHelpArgument;
+ ContinueArgument = &LocalContinueArgument;
+ IntelligentArgument = &LocalIntelligentArgument;
+ VerboseArgument = &LocalVerboseArgument;
+ HiddenArgument = &LocalHiddenArgument;
+ ReadOnlyArgument = &LocalReadOnlyArgument;
+ SilentArgument = &LocalSilentArgument;
+ NoCopyArgument = &LocalNoCopyArgument;
+ StructureArgument = &LocalStructureArgument;
+ UpdateArgument = &LocalUpdateArgument;
+ CopyAttrArgument = &LocalCopyAttrArgument;
+ UseShortArgument = &LocalUseShortArgument;
+ ExclusionListArgument = &LocalExclusionListArgument;
+ InvalidSwitchArgument = &LocalInvalidSwitchArgument;
+ LexArray = &LocalLexArray;
+ RestartableArgument = &LocalRestartableArgument;
+
+ //
+ // Parse the arguments
+ //
+ GetArgumentsCmd();
+
+ //
+ // Verify the arguments
+ //
+ CheckArgumentConsistency();
+
+ LocalLexArray.DeleteAllMembers();
+}
+
+
+VOID
+GetSourceAndDestinationPath(
+ IN OUT PPATH_ARGUMENT FirstPathArgument,
+ IN OUT PPATH_ARGUMENT FirstQuotedPathArgument,
+ IN OUT PPATH_ARGUMENT SecondPathArgument,
+ IN OUT PPATH_ARGUMENT SecondQuotedPathArgument,
+ IN OUT PARGUMENT_LEXEMIZER ArgLex,
+ OUT PPATH* SourcePath,
+ OUT PPATH* DestinationPath
+ )
+/*++
+
+Routine Description:
+
+ This routine computes the Source and Destination path from
+ the given list of arguments.
+
+Arguments:
+
+ FirstPathArgument - Supplies the first unquoted path argument.
+ FirstQuotedPathArgument - Supplies the first quoted path argument.
+ SecondPathArgument - Supplies the second unquoted path argument.
+ SecondQuotedPathArgument - Supplies the second quoted path argument.
+ ArgLex - Supplies the argument lexemizer.
+ SourcePath - Returns the source path.
+ DestinationPath - Returns the destination path.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ BOOLEAN f, qf, s, qs;
+ PPATH_ARGUMENT source, destination;
+ ULONG i;
+ PWSTRING string, qstring;
+
+ f = FirstPathArgument->IsValueSet();
+ qf = FirstQuotedPathArgument->IsValueSet();
+ s = SecondPathArgument->IsValueSet();
+ qs = SecondQuotedPathArgument->IsValueSet();
+ source = NULL;
+ destination = NULL;
+ *SourcePath = NULL;
+ *DestinationPath = NULL;
+
+ if (f && !qf && s && !qs) {
+
+ source = FirstPathArgument;
+ destination = SecondPathArgument;
+
+ } else if (!f && qf && !s && qs) {
+
+ source = FirstQuotedPathArgument;
+ destination = SecondQuotedPathArgument;
+
+ } else if (f && qf && !s && !qs) {
+
+ string = FirstPathArgument->GetLexeme();
+ qstring = FirstQuotedPathArgument->GetLexeme();
+
+ for (i = 0; i < ArgLex->QueryLexemeCount(); i++) {
+ if (!ArgLex->GetLexemeAt(i)->Strcmp(string)) {
+ source = FirstPathArgument;
+ destination = FirstQuotedPathArgument;
+ break;
+ }
+
+ if (!ArgLex->GetLexemeAt(i)->Strcmp(qstring)) {
+ source = FirstQuotedPathArgument;
+ destination = FirstPathArgument;
+ break;
+ }
+ }
+ } else if (f && !qf && !s && !qs) {
+ source = FirstPathArgument;
+ } else if (!f && qf && !s && !qs) {
+ source = FirstQuotedPathArgument;
+ }
+
+ if (source) {
+ if (!(*SourcePath = NEW PATH) ||
+ !(*SourcePath)->Initialize(source->GetPath(),
+ VerboseArgument->IsValueSet())) {
+
+ *SourcePath = NULL;
+ }
+ }
+
+ if (destination) {
+ if (!(*DestinationPath = NEW PATH) ||
+ !(*DestinationPath)->Initialize(destination->GetPath(),
+ VerboseArgument->IsValueSet())) {
+
+ *DestinationPath = NULL;
+ }
+ }
+}
+
+
+
+VOID
+XCOPY::GetArgumentsCmd(
+ )
+
+/*++
+
+Routine Description:
+
+ Obtains the arguments from the Command line
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ARRAY ArgArray;
+ PATH_ARGUMENT ProgramNameArgument;
+ DSTRING CmdLine;
+ DSTRING InvalidParms;
+ WCHAR Ch;
+ PWSTRING InvalidSwitch;
+ PARGUMENT_LEXEMIZER ArgLex;
+
+ //
+ // Prepare for parsing
+ //
+ if (//
+ // Initialize the arguments
+ //
+ !(CmdLine.Initialize( GetCommandLine() )) ||
+ !(ArgArray.Initialize( 15, 15 )) ||
+ !(ProgramNameArgument.Initialize( "*" )) ||
+ !(FirstPathArgument->Initialize( "*", FALSE )) ||
+ !(FirstQuotedPathArgument->Initialize( "\"*\"", FALSE )) ||
+ !(SecondPathArgument->Initialize( "*", FALSE)) ||
+ !(SecondQuotedPathArgument->Initialize( "\"*\"", FALSE)) ||
+ !(ArchiveArgument->Initialize( "/A" )) ||
+ !(DateArgument->Initialize( "/D:*" )) ||
+ !(OldArgument->Initialize( "/D" )) ||
+ !(EmptyArgument->Initialize( "/E" )) ||
+ !(ModifyArgument->Initialize( "/M" )) ||
+ !(PromptArgument->Initialize( "/P" )) ||
+ !(SubdirArgument->Initialize( "/S" )) ||
+ !(VerifyArgument->Initialize( "/V" )) ||
+ !(WaitArgument->Initialize( "/W" )) ||
+ !(HelpArgument->Initialize( "/?" )) ||
+ !(ContinueArgument->Initialize( "/C" )) ||
+ !(IntelligentArgument->Initialize( "/I" )) ||
+ !(VerboseArgument->Initialize( "/F" )) ||
+ !(HiddenArgument->Initialize( "/H" )) ||
+ !(ReadOnlyArgument->Initialize( "/R" )) ||
+ !(SilentArgument->Initialize( "/Q" )) ||
+ !(NoCopyArgument->Initialize( "/L" )) ||
+ !(StructureArgument->Initialize( "/T" )) ||
+ !(UpdateArgument->Initialize( "/U" )) ||
+ !(CopyAttrArgument->Initialize( "/K" )) ||
+ !(UseShortArgument->Initialize( "/N" )) ||
+ !(RestartableArgument->Initialize( "/Z" )) ||
+ !(ExclusionListArgument->Initialize("/EXCLUDE:*")) ||
+ !(InvalidSwitchArgument->Initialize( "/*" )) ||
+ //
+ // Put the arguments in the argument array
+ //
+ !(ArgArray.Put( &ProgramNameArgument )) ||
+ !(ArgArray.Put( ArchiveArgument )) ||
+ !(ArgArray.Put( DateArgument )) ||
+ !(ArgArray.Put( OldArgument )) ||
+ !(ArgArray.Put( EmptyArgument )) ||
+ !(ArgArray.Put( ModifyArgument )) ||
+ !(ArgArray.Put( PromptArgument )) ||
+ !(ArgArray.Put( SubdirArgument )) ||
+ !(ArgArray.Put( VerifyArgument )) ||
+ !(ArgArray.Put( WaitArgument )) ||
+ !(ArgArray.Put( HelpArgument )) ||
+ !(ArgArray.Put( ContinueArgument )) ||
+ !(ArgArray.Put( IntelligentArgument )) ||
+ !(ArgArray.Put( VerboseArgument )) ||
+ !(ArgArray.Put( HiddenArgument )) ||
+ !(ArgArray.Put( ReadOnlyArgument )) ||
+ !(ArgArray.Put( SilentArgument )) ||
+ !(ArgArray.Put( RestartableArgument )) ||
+ !(ArgArray.Put( NoCopyArgument )) ||
+ !(ArgArray.Put( StructureArgument )) ||
+ !(ArgArray.Put( UpdateArgument )) ||
+ !(ArgArray.Put( CopyAttrArgument )) ||
+ !(ArgArray.Put( UseShortArgument )) ||
+ !(ArgArray.Put( ExclusionListArgument )) ||
+ !(ArgArray.Put( InvalidSwitchArgument )) ||
+ !(ArgArray.Put( FirstQuotedPathArgument )) ||
+ !(ArgArray.Put( SecondQuotedPathArgument )) ||
+ !(ArgArray.Put( FirstPathArgument )) ||
+ !(ArgArray.Put( SecondPathArgument ))
+ ) {
+
+ DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY, NULL, EXIT_MISC_ERROR);
+ }
+
+ //
+ // Parse the arguments
+ //
+ ArgLex = ParseArguments( &CmdLine, &ArgArray );
+
+ if ( InvalidSwitchArgument->IsValueSet() ) {
+
+ InvalidSwitch = InvalidSwitchArgument->GetString();
+
+ InvalidParms.Initialize( SWITCH_CHARACTERS );
+
+ Ch = InvalidSwitch->QueryChAt(0);
+
+ if ( Ch == 'd' || Ch == 'D' ) {
+ Ch = InvalidSwitch->QueryChAt(1);
+ if ( Ch == INVALID_CHAR ) {
+ DisplayMessageAndExit( XCOPY_ERROR_INVALID_NUMBER_PARAMETERS,
+ NULL,
+ EXIT_MISC_ERROR );
+ } else if ( Ch != ':' || InvalidSwitch->QueryChCount() == 2 ) {
+ DisplayMessageAndExit( XCOPY_ERROR_INVALID_SWITCH_SWITCH,
+ InvalidSwitchArgument->GetLexeme(),
+ EXIT_MISC_ERROR );
+ }
+ } else if ( Ch == '/' ) {
+ Ch = InvalidSwitch->QueryChAt(1);
+ if ( Ch == ':' && InvalidSwitchArgument->GetString()->QueryChAt(2) == INVALID_CHAR ) {
+ InvalidSwitchArgument->GetLexeme()->Truncate(1);
+ }
+ }
+
+ Ch = InvalidSwitch->QueryChAt(0);
+
+ if ( InvalidParms.Strchr( Ch ) != INVALID_CHNUM ) {
+ DisplayMessageAndExit( XCOPY_ERROR_INVALID_PARAMETER,
+ InvalidSwitchArgument->GetLexeme(),
+ EXIT_MISC_ERROR );
+ } else {
+ DisplayMessageAndExit( XCOPY_ERROR_INVALID_SWITCH_SWITCH,
+ InvalidSwitchArgument->GetLexeme(),
+ EXIT_MISC_ERROR );
+ }
+ }
+
+ //
+ // Set the switches
+ //
+ _EmptySwitch = EmptyArgument->QueryFlag();
+ _ModifySwitch = ModifyArgument->QueryFlag();
+
+ //
+ // ModifySwitch implies ArchiveSwitch
+ //
+ if ( _ModifySwitch ) {
+ _ArchiveSwitch = TRUE;
+ } else {
+ _ArchiveSwitch = ArchiveArgument->QueryFlag();
+ }
+
+ //
+ // Set the switches
+ //
+ _PromptSwitch = PromptArgument->QueryFlag();
+ _SubdirSwitch = SubdirArgument->QueryFlag();
+ _VerifySwitch = VerifyArgument->QueryFlag();
+ _WaitSwitch = WaitArgument->QueryFlag();
+ _ContinueSwitch = ContinueArgument->QueryFlag();
+ _IntelligentSwitch = IntelligentArgument->QueryFlag();
+ _CopyIfOldSwitch = OldArgument->QueryFlag();
+ _VerboseSwitch = VerboseArgument->QueryFlag();
+ _HiddenSwitch = HiddenArgument->QueryFlag();
+ _ReadOnlySwitch = ReadOnlyArgument->QueryFlag();
+ _SilentSwitch = SilentArgument->QueryFlag();
+ _DontCopySwitch = NoCopyArgument->QueryFlag();
+ _StructureOnlySwitch= StructureArgument->QueryFlag();
+ _UpdateSwitch = UpdateArgument->QueryFlag();
+ _CopyAttrSwitch = CopyAttrArgument->QueryFlag();
+ _UseShortSwitch = UseShortArgument->QueryFlag();
+ _RestartableSwitch = RestartableArgument->QueryFlag();
+ HelpSwitch = HelpArgument->QueryFlag();
+
+
+ //
+ // Set the source and destination paths. Argument checking is
+ // done somewhere else, so it is ok. to set the source path to
+ // NULL here.
+ //
+ GetSourceAndDestinationPath(FirstPathArgument,
+ FirstQuotedPathArgument,
+ SecondPathArgument,
+ SecondQuotedPathArgument,
+ ArgLex,
+ &_SourcePath,
+ &_DestinationPath);
+
+ DELETE(ArgLex);
+
+ //
+ // Set the date argument
+ //
+
+ if ( DateArgument->IsValueSet() ) {
+
+ if ((_Date = NEW TIMEINFO) == NULL ) {
+
+ DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY, NULL, EXIT_MISC_ERROR );
+ }
+
+ _Date->Initialize( DateArgument->GetTimeInfo() );
+
+ } else {
+
+ _Date = NULL;
+ }
+
+ if( ExclusionListArgument->IsValueSet() ) {
+
+ InitializeExclusionList( ExclusionListArgument->GetString() );
+ }
+}
+
+PARGUMENT_LEXEMIZER
+XCOPY::ParseArguments(
+ IN PWSTRING CmdLine,
+ OUT PARRAY ArgArray
+ )
+
+/*++
+
+Routine Description:
+
+ Parses a group of arguments
+
+Arguments:
+
+ CmdLine - Supplies pointer to a command line to parse
+ ArgArray - Supplies pointer to array of arguments
+
+Return Value:
+
+ Returns the argument lexemizer used which then needs to be freed
+ by the client.
+
+Notes:
+
+--*/
+
+{
+ PARGUMENT_LEXEMIZER ArgLex;
+
+ //
+ // Initialize lexeme array and the lexemizer.
+ //
+ if ( !(ArgLex = NEW ARGUMENT_LEXEMIZER) ||
+ !(LexArray->Initialize( 9, 9 )) ||
+ !(ArgLex->Initialize( LexArray )) ) {
+
+ DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY,
+ NULL,
+ EXIT_MISC_ERROR );
+ }
+
+ //
+ // Set our parsing preferences
+ //
+ ArgLex->PutMultipleSwitch( "/?AMDPSEVWCIFHRQLKTUNZ" );
+ ArgLex->PutSwitches( "/" );
+ ArgLex->SetCaseSensitive( FALSE );
+ ArgLex->PutSeparators( " \t" );
+ ArgLex->PutStartQuotes( "\"" );
+ ArgLex->PutEndQuotes( "\"" );
+ ArgLex->SetAllowSwitchGlomming( TRUE );
+ ArgLex->SetNoSpcBetweenDstAndSwitch( TRUE );
+
+ //
+ // Parse the arguments
+ //
+ if ( !(ArgLex->PrepareToParse( CmdLine ))) {
+
+ DisplayMessageAndExit( XCOPY_ERROR_PARSE,
+ NULL,
+ EXIT_MISC_ERROR );
+
+ }
+
+ if ( !ArgLex->DoParsing( ArgArray ) ) {
+
+ DisplayMessageAndExit( XCOPY_ERROR_INVALID_NUMBER_PARAMETERS,
+ NULL,
+ EXIT_MISC_ERROR );
+ }
+
+ return ArgLex;
+}
+
+VOID
+XCOPY::CheckArgumentConsistency (
+ )
+
+/*++
+
+Routine Description:
+
+ Checks the consistency of the arguments
+
+Arguments:
+
+ none
+
+Return Value:
+
+ none
+
+Notes:
+
+--*/
+
+{
+ PFSN_DIRECTORY DirSrc;
+ PFSN_DIRECTORY DirDst;
+ PWSTRING DevSrc;
+ PWSTRING DevDst;
+ PATH PathSrc, PathSrc1;
+ PATH PathDst, PathDst1;
+ DSTRING Slash;
+
+ if ( HelpSwitch ) {
+ //
+ // Help requested
+ //
+ Usage();
+ DisplayMessageAndExit( 0,
+ NULL,
+ EXIT_NORMAL );
+ }
+
+
+ //
+ // Make sure that we have a source path
+ //
+ if ( _SourcePath == NULL ) {
+
+ DisplayMessageAndExit( XCOPY_ERROR_INVALID_NUMBER_PARAMETERS,
+ NULL,
+ EXIT_MISC_ERROR );
+ }
+
+ //
+ // The empty switch implies Subdir switch (note that DOS
+ // requires Subdir switch explicitly, but we are not that
+ // brain-damaged).
+ //
+ if ( _EmptySwitch ) {
+ _SubdirSwitch = TRUE;
+ }
+
+
+ //
+ // The StructureOnly switch imples the subdir switch
+ //
+ if ( _StructureOnlySwitch ) {
+ _SubdirSwitch = TRUE;
+ }
+
+ //
+ // If destination path is null, then the destination path is the
+ // current directory
+ //
+ if ( _DestinationPath == NULL ) {
+
+ if ( ((_DestinationPath = NEW PATH) == NULL ) ||
+ !_DestinationPath->Initialize( (LPWSTR)L".", TRUE ) ) {
+
+ DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY, NULL, EXIT_MISC_ERROR );
+ }
+ }
+
+ _DestinationPath->TruncateNameAtColon();
+
+ if ( !PathSrc1.Initialize( _SourcePath, TRUE ) ||
+ !PathDst1.Initialize( _DestinationPath, TRUE ) ||
+ !(DevSrc = PathSrc1.QueryDevice()) ||
+ !(DevDst = PathDst1.QueryDevice()) ||
+ !PathSrc.Initialize( DevSrc ) ||
+ !PathDst.Initialize( DevDst ) ||
+ !Slash.Initialize( "\\" ) ||
+ !PathSrc.AppendBase( &Slash ) ||
+ !PathDst.AppendBase( &Slash ) ||
+ !(DirSrc = SYSTEM::QueryDirectory( &PathSrc )) ||
+ !(DirDst = SYSTEM::QueryDirectory( &PathDst )) ) {
+ DisplayMessageAndExit( XCOPY_ERROR_INVALID_DRIVE, NULL, EXIT_MISC_ERROR );
+ }
+ DELETE( DevSrc );
+ DELETE( DevDst );
+ DELETE( DirSrc );
+ DELETE( DirDst );
+}
+
+BOOLEAN
+XCOPY::AddToExclusionList(
+ IN PWSTRING ExclusionListFileName
+ )
+/*++
+
+Routine Description:
+
+ This method adds the contents of the specified file to
+ the exclusion list.
+
+Arguments:
+
+ ExclusionListFileName -- Supplies the name of a file which
+ contains the exclusion list.
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ PATH ExclusionPath;
+ PDSTRING String;
+ PFSN_FILE File;
+ PFILE_STREAM Stream;
+ CHNUM Position;
+
+ DebugPtrAssert( ExclusionListFileName );
+
+ if( !ExclusionPath.Initialize( ExclusionListFileName ) ||
+ (File = SYSTEM::QueryFile( &ExclusionPath )) == NULL ||
+ (Stream = File->QueryStream( READ_ACCESS )) == NULL ) {
+
+ DisplayMessageAndExit( MSG_COMP_UNABLE_TO_READ,
+ ExclusionListFileName,
+ EXIT_MISC_ERROR );
+ }
+
+ while( !Stream->IsAtEnd() &&
+ (String = NEW DSTRING) != NULL &&
+ Stream->ReadLine ( String ) ) {
+
+ if( String->QueryChCount() == 0 ) {
+
+ continue;
+ }
+
+ // Convert the string to upper-case and remove
+ // trailing whitespace (blanks and tabs).
+ //
+ String->Strupr();
+ Position = String->QueryChCount() - 1;
+
+ while( Position != 0 &&
+ (String->QueryChAt( Position ) == ' ' ||
+ String->QueryChAt( Position ) == '\t') ) {
+
+ Position -= 1;
+ }
+
+ if( String->QueryChAt( Position ) != ' ' &&
+ String->QueryChAt( Position ) != '\t' ) {
+
+ Position++;
+ }
+
+ if( Position != String->QueryChCount() ) {
+
+ String->Truncate( Position );
+ }
+
+ if( String->QueryChCount() != 0 && !_ExclusionList->Put( String ) ) {
+
+ DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY,
+ NULL,
+ EXIT_MISC_ERROR );
+ }
+ }
+
+ DELETE( Stream );
+ DELETE( File );
+ return TRUE;
+}
+
+BOOLEAN
+XCOPY::InitializeExclusionList(
+ IN PWSTRING ListOfFiles
+ )
+/*++
+
+Routine Description:
+
+ This method reads the exclusion list and initializes the
+ exclusion list array.
+
+Arguments:
+
+ ListOfFiles -- Supplies a string containing a list of file
+ names, separated by '+' (e.g. file1+file2+file3)
+
+Return Value:
+
+ TRUE upon successful completion.
+
+--*/
+{
+ DSTRING CurrentName;
+ CHNUM LastPosition, Position;
+
+ DebugPtrAssert( ListOfFiles );
+
+ if( (_ExclusionList = NEW STRING_ARRAY) == NULL ||
+ !_ExclusionList->Initialize() ||
+ (_Iterator = _ExclusionList->QueryIterator()) == NULL ) {
+
+ DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY, NULL, EXIT_MISC_ERROR );
+ }
+
+ LastPosition = 0;
+
+ while( LastPosition != ListOfFiles->QueryChCount() ) {
+
+ Position = ListOfFiles->Strchr( '+', LastPosition );
+
+ if( Position == INVALID_CHNUM ) {
+
+ Position = ListOfFiles->QueryChCount();
+ }
+
+ if( Position != LastPosition ) {
+
+ if( !CurrentName.Initialize( ListOfFiles,
+ LastPosition,
+ Position - LastPosition ) ) {
+
+ DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY,
+ NULL,
+ EXIT_MISC_ERROR );
+ }
+
+ AddToExclusionList( &CurrentName );
+ }
+
+ // Advance past any separators.
+ //
+ while( Position < ListOfFiles->QueryChCount() &&
+ ListOfFiles->QueryChAt( Position ) == '+' ) {
+
+ Position += 1;
+ }
+
+ LastPosition = Position;
+ }
+
+ return TRUE;
+}
diff --git a/private/utils/xcopy/makefile b/private/utils/xcopy/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/utils/xcopy/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/utils/xcopy/sources b/private/utils/xcopy/sources
new file mode 100644
index 000000000..cefcf7d7f
--- /dev/null
+++ b/private/utils/xcopy/sources
@@ -0,0 +1,83 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+BLDCRT=1
+
+MAJORCOMP=utils
+MINORCOMP=xcopy
+
+TARGETNAME=xcopy
+TARGETPATH=obj
+TARGETTYPE=PROGRAM
+
+MSC_WARNING_LEVEL=/W3 /WX
+
+SOURCES=argument.cxx \
+ support.cxx \
+ xcopy.cxx \
+ xcopy.rc
+
+INCLUDES=..\ulib\inc;..\ifsutil\inc;\nt\public\sdk\inc
+#
+# Debug support.
+#
+# We have 4 levels:
+#
+# 1.- FREE: Non-debug
+# 2.- NTDBG: Debug, no memleak
+# 3.- MEMLEAK: 2 + memleak
+# 4.- STACK_TRACE 3 + stack trace
+#
+#
+# By default, whenever the NTDEBUG symbol is defined, you get level
+# 3. In order to get level 2 you have to define the symbol NOMEMLEAK.
+# In order to get level 4, you have to the file the symbol STACK_TRACE
+#
+# In summary here is how to get each one:
+#
+# 1.- Undefine NTDEBUG
+# 2.- define NTDEBUG, define NOMEMLEAK
+# 3.- define NTDEBUG, undefine NOMEMLEAK
+# 4.- define NTDEBUG, undefine NOMEMLEAK, define STACK_TRACE
+#
+!IF "$(NTDEBUG)" == "cvp" || "$(NTDEBUG)" == "ntsd"
+!IFDEF NOMEMLEAK
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DUNICODE=1
+!ELSE
+!IFDEF STACK_TRACE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DSTACK_TRACE -DUNICODE=1
+!ELSE
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=1 -DMEMLEAK -DUNICODE=1
+!ENDIF
+!ENDIF
+!ELSE # NTDEBUG
+C_DEFINES=-DCONDITION_HANDLING=1 -DDBG=0 -DUNICODE=1
+!ENDIF # NTDEBUG
+
+TARGETLIBS= \
+ ..\ulib\src\obj\*\ulib.lib \
+ ..\ifsutil\src\obj\*\ifsutil.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+
+UMTYPE=console
diff --git a/private/utils/xcopy/support.cxx b/private/utils/xcopy/support.cxx
new file mode 100644
index 000000000..5ff45624f
--- /dev/null
+++ b/private/utils/xcopy/support.cxx
@@ -0,0 +1,183 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Support
+
+Abstract:
+
+ Miscelaneous support functions for the XCopy directory copy
+ utility. All functions that are not involved directly in the
+ copy process go here.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 02-May-1991
+
+Revision History:
+
+--*/
+
+
+
+#include "ulib.hxx"
+#include "system.hxx"
+#include "xcopy.hxx"
+
+
+
+
+
+VOID
+XCOPY::DisplayMessageAndExit (
+ IN MSGID MsgId,
+ IN PWSTRING String,
+ IN ULONG ExitCode
+ )
+
+/*++
+
+Routine Description:
+
+ Displays a message and exits the program with the supplied error code.
+ We support a maximum of one string parameter for the message.
+
+Arguments:
+
+ MsgId - Supplies the Id of the message to display.
+ String - Supplies a string parameter for the message.
+ ExitCode - Supplies the exit code with which to exit.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ //
+ // XCopy first displays the error message (if any) and then
+ // displays the number of files copied.
+ //
+ if ( MsgId != 0 ) {
+ if ( String ) {
+ DisplayMessage( MsgId, ERROR_MESSAGE, "%W", String );
+ } else {
+ DisplayMessage( MsgId, ERROR_MESSAGE );
+ }
+ }
+
+ if ( _DontCopySwitch ) {
+ DisplayMessage( XCOPY_MESSAGE_FILES, NORMAL_MESSAGE, "%d", _FilesCopied );
+ } else if ( !_StructureOnlySwitch ) {
+ DisplayMessage( XCOPY_MESSAGE_FILES_COPIED, NORMAL_MESSAGE, "%d", _FilesCopied );
+ }
+ ExitProgram( ExitCode );
+
+}
+
+PWSTRING
+XCOPY::QueryMessageString (
+ IN MSGID MsgId
+ )
+/*++
+
+Routine Description:
+
+ Obtains a string object initialized to the contents of some message
+
+Arguments:
+
+ MsgId - Supplies ID of the message
+
+Return Value:
+
+ PWSTRING - Pointer to initialized string object
+
+Notes:
+
+--*/
+
+{
+
+ PWSTRING String;
+
+ if ( ((String = NEW DSTRING) == NULL ) ||
+ !(SYSTEM::QueryResourceString( String, MsgId, "" )) ) {
+
+ DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY, NULL, EXIT_MISC_ERROR );
+ }
+
+ return String;
+
+}
+
+VOID
+XCOPY::ExitWithError(
+ IN DWORD ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Displays a message based on a WIN32 error code, and exits.
+
+Arguments:
+
+ ErrorCode - Supplies Windows error code
+
+Return Value:
+
+ none
+
+--*/
+
+{
+ MSGID ReadWriteMsgId = 0;
+
+ switch ( ErrorCode ) {
+
+ case ERROR_DISK_FULL:
+ ReadWriteMsgId = XCOPY_ERROR_DISK_FULL;
+ break;
+
+ case ERROR_WRITE_PROTECT:
+ ReadWriteMsgId = XCOPY_ERROR_WRITE_PROTECT;
+ break;
+
+ case ERROR_ACCESS_DENIED:
+ ReadWriteMsgId = XCOPY_ERROR_ACCESS_DENIED;
+ break;
+
+ case ERROR_SHARING_VIOLATION:
+ ReadWriteMsgId = XCOPY_ERROR_SHARING_VIOLATION;
+ break;
+
+ case ERROR_TOO_MANY_OPEN_FILES:
+ ReadWriteMsgId = XCOPY_ERROR_TOO_MANY_OPEN_FILES;
+ break;
+
+ case ERROR_LOCK_VIOLATION:
+ ReadWriteMsgId = XCOPY_ERROR_LOCK_VIOLATION;
+ break;
+
+ case ERROR_CANNOT_MAKE:
+ ReadWriteMsgId = XCOPY_ERROR_CANNOT_MAKE;
+ break;
+
+ default:
+ break;
+ }
+
+ if ( ReadWriteMsgId != 0 ) {
+ DisplayMessageAndExit( ReadWriteMsgId, NULL, EXIT_READWRITE_ERROR );
+ }
+
+ Fatal( EXIT_MISC_ERROR, XCOPY_ERROR_EXTENDED, "%d", ErrorCode );
+
+}
diff --git a/private/utils/xcopy/xcopy.cxx b/private/utils/xcopy/xcopy.cxx
new file mode 100644
index 000000000..8cf8f83bf
--- /dev/null
+++ b/private/utils/xcopy/xcopy.cxx
@@ -0,0 +1,2324 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ XCopy
+
+Abstract:
+
+ Xcopy is a DOS5-Compatible directory copy utility
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 01-May-1991
+
+Revision History:
+
+--*/
+
+#define _NTAPI_ULIB_
+
+#include "ulib.hxx"
+#include "array.hxx"
+#include "arrayit.hxx"
+#include "dir.hxx"
+#include "file.hxx"
+#include "filter.hxx"
+#include "stream.hxx"
+#include "system.hxx"
+#include "xcopy.hxx"
+#include "bigint.hxx"
+#include "ifssys.hxx"
+#include "error.hxx"
+#include "stringar.hxx"
+#include "arrayit.hxx"
+
+extern "C" {
+ #include <ctype.h>
+}
+
+
+#define CTRL_C (WCHAR)3
+
+
+
+ERRSTACK *perrstk;
+
+
+VOID _CRTAPI1
+main (
+ )
+
+/*++
+
+Routine Description:
+
+ Main function of the XCopy utility
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ //
+ // Initialize stuff
+ //
+ DEFINE_CLASS_DESCRIPTOR( XCOPY );
+
+ //
+ // Now do the copy
+ //
+ {
+ XCOPY XCopy;
+
+ //
+ // Initialize the XCOPY object.
+ //
+ if( XCopy.Initialize() ) {
+
+ //
+ // Do the copy
+ //
+ XCopy.DoCopy();
+ }
+ }
+}
+
+
+
+DEFINE_CONSTRUCTOR( XCOPY, PROGRAM );
+
+VOID
+XCOPY::Construct (
+ )
+{
+ _Keyboard = NULL;
+ _TargetPath = NULL;
+ _SourcePath = NULL;
+ _DestinationPath = NULL;
+ _Date = NULL;
+ _FileNamePattern = NULL;
+ _ExclusionList = NULL;
+ _Iterator = NULL;
+}
+
+
+
+
+BOOLEAN
+XCOPY::Initialize (
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes the XCOPY object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ //
+ // Initialize program object
+ //
+ if( !PROGRAM::Initialize( XCOPY_MESSAGE_USAGE ) ) {
+
+ return FALSE;
+ }
+
+ //
+ // Allocate resources
+ //
+ InitializeThings();
+
+ //
+ // Parse the arguments
+ //
+ SetArguments();
+
+
+ return TRUE;
+}
+
+XCOPY::~XCOPY (
+ )
+
+/*++
+
+Routine Description:
+
+ Destructs an XCopy object
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ //
+ // Deallocate the global structures previously allocated
+ //
+ DeallocateThings();
+
+ //
+ // Exit without error
+ //
+ if( _Standard_Input != NULL &&
+ _Standard_Output != NULL ) {
+
+ DisplayMessageAndExit( 0, NULL, EXIT_NORMAL );
+ }
+
+}
+
+VOID
+XCOPY::InitializeThings (
+ )
+
+/*++
+
+Routine Description:
+
+ Initializes the global variables that need initialization
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+
+ //
+ // Get a keyboard, because we will need to switch back and
+ // forth between raw and cooked mode and because we need
+ // to enable ctrl-c handling (so that we can exit with
+ // the right level if the program is interrupted).
+ //
+ if ( !( _Keyboard = KEYBOARD::Cast(GetStandardInput()) )) {
+ //
+ // Not reading from standard input, we will get
+ // the real keyboard.
+ //
+ _Keyboard = NEW KEYBOARD;
+
+ if( !_Keyboard ) {
+
+ exit(4);
+ }
+
+ _Keyboard->Initialize();
+
+ }
+
+ //
+ // Set Ctrl-C handler
+ //
+ _Keyboard->EnableBreakHandling();
+
+ //
+ // Initialize our internal data
+ //
+ _FilesCopied = 0;
+ _CanRemoveEmptyDirectories = TRUE;
+ _TargetIsFile = FALSE;
+ _TargetPath = NULL;
+ _SourcePath = NULL;
+ _DestinationPath = NULL;
+ _Date = NULL;
+ _FileNamePattern = NULL;
+ _ExclusionList = NULL;
+ _Iterator = NULL;
+
+ // The following switches are being used by DisplayMessageAndExit
+ // before any of those boolean _*Switch is being initialized
+
+ _DontCopySwitch = FALSE;
+ _StructureOnlySwitch = TRUE;
+}
+
+VOID
+XCOPY::DeallocateThings (
+ )
+
+/*++
+
+Routine Description:
+
+ Deallocates the stuff that was initialized in InitializeThings()
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ //
+ // Deallocate local data
+ //
+ DELETE( _TargetPath );
+ DELETE( _SourcePath );
+ DELETE( _DestinationPath );
+ DELETE( _Date );
+ DELETE( _FileNamePattern );
+ DELETE( _Iterator );
+
+ if( _ExclusionList ) {
+
+ _ExclusionList->DeleteAllMembers();
+ }
+
+ DELETE( _ExclusionList );
+
+ //
+ // Reset Ctrl-C handleing
+ //
+ _Keyboard->DisableBreakHandling();
+
+ //
+ // If standard input is not the keyboard, we get rid of
+ // the keyboard object.
+ //
+ if ( !(_Keyboard == KEYBOARD::Cast(GetStandardInput()) )) {
+ DELETE( _Keyboard );
+ }
+}
+
+BOOLEAN
+XCOPY::DoCopy (
+ )
+
+/*++
+
+Routine Description:
+
+ This is the function that performs the XCopy.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+
+ PFSN_DIRECTORY SourceDirectory = NULL;
+ PFSN_DIRECTORY DestinationDirectory = NULL;
+ PFSN_DIRECTORY PartialDirectory = NULL;
+ PATH PathToDelete;
+ WCHAR Char;
+ CHNUM CharsInPartialDirectoryPath;
+ BOOLEAN DirDeleted;
+ BOOLEAN CopyingManyFiles;
+ PATH TmpPath;
+ PFSN_FILTER FileFilter = NULL;
+ PFSN_FILTER DirectoryFilter = NULL;
+ WIN32_FIND_DATA FindData;
+ PWSTRING Device = NULL;
+ HANDLE FindHandle;
+
+
+ //
+ // Make sure that we won't try to copy to ourselves
+ //
+ if ( _SubdirSwitch && IsCyclicalCopy( _SourcePath, _DestinationPath ) ) {
+
+ DisplayMessageAndExit( XCOPY_ERROR_CYCLE, NULL, EXIT_MISC_ERROR );
+ }
+
+ AbortIfCtrlC();
+
+ //
+ // Get the source directory object and the filename that we will be
+ // matching.
+ //
+ GetDirectoryAndFilters( _SourcePath, &SourceDirectory, &FileFilter, &DirectoryFilter, &CopyingManyFiles );
+
+ DebugPtrAssert( SourceDirectory );
+ DebugPtrAssert( FileFilter );
+ DebugPtrAssert( DirectoryFilter );
+
+ if ( _WaitSwitch ) {
+
+ // Pause before we start copying.
+ //
+ DisplayMessage( XCOPY_MESSAGE_WAIT );
+
+ AbortIfCtrlC();
+
+ //
+ // All input is in raw mode.
+ //
+ _Keyboard->DisableLineMode();
+ if( GetStandardInput()->IsAtEnd() ) {
+ // Insufficient input--treat as CONTROL-C.
+ //
+ Char = ' ';
+ } else {
+ GetStandardInput()->ReadChar( &Char );
+ }
+ _Keyboard->EnableLineMode();
+
+ if ( Char == CTRL_C ) {
+ exit ( EXIT_TERMINATED );
+ } else {
+ GetStandardOutput()->WriteChar( Char );
+ GetStandardOutput()->WriteChar( (WCHAR)'\r');
+ GetStandardOutput()->WriteChar( (WCHAR)'\n');
+ }
+ }
+
+ //
+ // Get the destination directory and the file pattern.
+ //
+ GetDirectoryAndFilePattern( _DestinationPath, CopyingManyFiles, &_TargetPath, &_FileNamePattern );
+
+ DebugPtrAssert( _TargetPath );
+ DebugPtrAssert( _FileNamePattern );
+
+ //
+ // Get as much of the destination directory as possible.
+ //
+ if ( !_DontCopySwitch ) {
+ PartialDirectory = SYSTEM::QueryDirectory( _TargetPath, TRUE );
+
+ if (PartialDirectory == NULL ) {
+
+ DisplayMessageAndExit( XCOPY_ERROR_CREATE_DIRECTORY, NULL, EXIT_MISC_ERROR );
+
+ }
+
+ //
+ // All the directories up to the parent of the target have to exist. If
+ // they don't, we have to create them.
+ //
+ if ( *(PartialDirectory->GetPath()->GetPathString()) ==
+ *(_TargetPath->GetPathString()) ) {
+
+ DestinationDirectory = PartialDirectory;
+
+ } else {
+
+ TmpPath.Initialize( _TargetPath );
+ if( !_TargetIsFile ) {
+ TmpPath.TruncateBase();
+ }
+ DestinationDirectory = PartialDirectory->CreateDirectoryPath( &TmpPath );
+ }
+
+ if( !DestinationDirectory ) {
+
+ DisplayMessageAndExit( XCOPY_ERROR_INVALID_PATH, NULL, EXIT_MISC_ERROR );
+ }
+
+
+ //
+ // Determine if destination if floppy
+ //
+ Device = _TargetPath->QueryDevice();
+ if ( Device ) {
+ _DisketteCopy = (SYSTEM::QueryDriveType( Device ) == RemovableDrive);
+ DELETE( Device );
+ }
+ }
+
+
+ //
+ // Now traverse the source directory.
+ //
+ TmpPath.Initialize( _TargetPath );
+
+ if (!_UpdateSwitch) {
+
+ Traverse( SourceDirectory,
+ &TmpPath,
+ FileFilter,
+ DirectoryFilter,
+ !SourceDirectory->GetPath()->GetPathString()->Strcmp(
+ _SourcePath->GetPathString()));
+
+ } else {
+
+ PATH DestDirectoryPath;
+ PFSN_DIRECTORY DestDirectory;
+
+ DestDirectoryPath.Initialize(&TmpPath);
+ DestDirectory = SYSTEM::QueryDirectory(&DestDirectoryPath);
+
+ TmpPath.Initialize(SourceDirectory->GetPath());
+
+ UpdateTraverse( DestDirectory,
+ &TmpPath,
+ FileFilter,
+ DirectoryFilter,
+ !SourceDirectory->GetPath()->GetPathString()->Strcmp(
+ _SourcePath->GetPathString()));
+ }
+
+ DELETE( _TargetPath);
+
+ if (( _FilesCopied == 0 ) && _CanRemoveEmptyDirectories && !_DontCopySwitch ) {
+
+ //
+ // Delete any directories that we created
+ //
+ if ( PartialDirectory != DestinationDirectory ) {
+
+ if (!PathToDelete.Initialize( DestinationDirectory->GetPath() )) {
+ DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY, NULL, EXIT_MISC_ERROR );
+ }
+
+ CharsInPartialDirectoryPath = PartialDirectory->GetPath()->GetPathString()->QueryChCount();
+
+ while ( PathToDelete.GetPathString()->QueryChCount() >
+ CharsInPartialDirectoryPath ) {
+
+ DirDeleted = DestinationDirectory->DeleteDirectory();
+
+ DebugAssert( DirDeleted );
+
+ DELETE( DestinationDirectory );
+
+ PathToDelete.TruncateBase();
+ DestinationDirectory = SYSTEM::QueryDirectory( &PathToDelete );
+ DebugPtrAssert( DestinationDirectory );
+ }
+ }
+
+ //
+ // We display the "File not found" message only if there are no
+ // files that match our pattern, regardless of other factors such
+ // as attributes etc. This is just to maintain DOS5 compatibility.
+ //
+ TmpPath.Initialize( SourceDirectory->GetPath() );
+ TmpPath.AppendBase( FileFilter->GetFileName() );
+ if ((FindHandle = FindFirstFile( &TmpPath, &FindData )) == INVALID_HANDLE_VALUE ) {
+ DisplayMessage( XCOPY_ERROR_FILE_NOT_FOUND, ERROR_MESSAGE, "%W", FileFilter->GetFileName() );
+ }
+ FindClose(FindHandle);
+
+ }
+
+ DELETE( SourceDirectory );
+ if ( PartialDirectory != DestinationDirectory ) {
+ DELETE( PartialDirectory );
+ }
+ DELETE( DestinationDirectory );
+ DELETE( FileFilter );
+ DELETE( DirectoryFilter );
+
+ return TRUE;
+}
+
+BOOLEAN
+XCOPY::Traverse (
+ IN PFSN_DIRECTORY Directory,
+ IN OUT PPATH DestinationPath,
+ IN PFSN_FILTER FileFilter,
+ IN PFSN_FILTER DirectoryFilter,
+ IN BOOLEAN CopyDirectoryStreams
+ )
+
+/*++
+
+Routine Description:
+
+ Traverses a directory, calling the callback function for each node
+ (directory of file) visited. The traversal may be finished
+ prematurely when the callback function returnes FALSE.
+
+ The destination path is modified to reflect the directory structure
+ being traversed.
+
+Arguments:
+
+ Directory - Supplies pointer to directory to traverse
+
+ DestinationPath - Supplies pointer to path to be used with the
+ callback function.
+
+ FileFilter - Supplies a pointer to the file filter.
+
+ DirectoryFilter - Supplies a pointer to the directory filter.
+
+ CopyDirectoryStreams - Specifies to copy directory streams when
+ copying directories.
+
+Return Value:
+
+ BOOLEAN - TRUE if everything traversed
+ FALSE otherwise.
+
+--*/
+
+
+{
+
+ PFSN_DIRECTORY TargetDirectory = NULL;
+ PARRAY NodeArray;
+ PARRAY_ITERATOR Iterator;
+ BOOLEAN MemoryOk;
+ PFSN_FILE File;
+ PFSN_DIRECTORY Dir;
+ PWSTRING Name;
+ BOOLEAN Created = FALSE;
+ FSN_FILTER Filter;
+ PCPATH TemplatePath = NULL;
+
+ DebugPtrAssert( Directory );
+ DebugPtrAssert( DestinationPath );
+ DebugPtrAssert( FileFilter );
+ DebugPtrAssert( DirectoryFilter );
+
+ if ( !Filter.Initialize() ) {
+ return FALSE;
+ }
+
+ //
+ // We only traverse this directory if it is not empty (unless the
+ // empty switch is set).
+ //
+ if ( _EmptySwitch || !Directory->IsEmpty() ) {
+
+ NodeArray = Directory->QueryFsnodeArray( &Filter );
+ DebugPtrAssert( NodeArray );
+
+ if ( NodeArray ) {
+ //
+ // Get an iterator for processing the nodes
+ //
+ Iterator = ( PARRAY_ITERATOR ) NodeArray->QueryIterator( );
+ DebugPtrAssert( Iterator );
+ }
+
+ MemoryOk = (BOOLEAN)( NodeArray && Iterator );
+
+ //
+ // Create the target directory (if we are not copying to a file).
+ //
+ if ( MemoryOk && !_TargetIsFile && !_DontCopySwitch ) {
+
+ TargetDirectory = SYSTEM::QueryDirectory( DestinationPath );
+
+ if ( !TargetDirectory ) {
+
+ //
+ // The target directory does not exist, create the
+ // directory and remember that we might delete it if
+ // no files or subdirectories were created.
+ //
+ if (CopyDirectoryStreams) {
+ TemplatePath = Directory->GetPath();
+ }
+ TargetDirectory = SYSTEM::MakeDirectory( DestinationPath,
+ TemplatePath );
+ if (TargetDirectory && !_CopyAttrSwitch) {
+ DWORD dwError;
+ // always set the archive bit so that it gets backup
+ TargetDirectory->MakeArchived(&dwError);
+ }
+ Created = TRUE;
+ }
+
+ if ( !TargetDirectory ) {
+ //
+ // If the Continue Switch is set, we just display an error message and
+ // continue, otherwise we exit with error.
+ //
+ if ( _ContinueSwitch ) {
+
+ DisplayMessage( XCOPY_ERROR_CREATE_DIRECTORY1, ERROR_MESSAGE, "%W", DestinationPath->GetPathString() );
+ DELETE( Iterator );
+ NodeArray->DeleteAllMembers();
+ DELETE( NodeArray );
+ return TRUE;
+
+ } else {
+
+ DisplayMessageAndExit( XCOPY_ERROR_CREATE_DIRECTORY, NULL, EXIT_MISC_ERROR );
+
+ }
+ }
+
+ if( !_CopyAttrSwitch ) {
+
+ TargetDirectory->ResetReadOnlyAttribute();
+ }
+ }
+
+
+ //
+ // Copy all the files in the array.
+ //
+ while ( MemoryOk && ( ( File = (PFSN_FILE)Iterator->GetNext( )) != NULL )) {
+
+ if ( !FileFilter->DoesNodeMatch( (PFSNODE)File ) ) {
+ continue;
+ }
+
+ DebugAssert( !File->IsDirectory() );
+
+ // If we're supposed to use the short name then convert fsnode.
+
+ if (_UseShortSwitch && !File->UseAlternateName()) {
+ MemoryOk = FALSE;
+ continue;
+ }
+
+ //
+ // Append the name portion of the node to the destination path.
+ //
+ Name = File->QueryName();
+ DebugPtrAssert( Name );
+
+ if ( Name ) {
+
+ MemoryOk = DestinationPath->AppendBase( Name );
+ DebugAssert( MemoryOk );
+
+ DELETE( Name );
+
+ if ( MemoryOk ) {
+ //
+ // Copy the file
+ //
+ if ( !Copier( File, DestinationPath ) ) {
+ ExitProgram( EXIT_MISC_ERROR );
+ }
+
+ //
+ // Restore the destination path
+ //
+ DestinationPath->TruncateBase();
+ }
+
+ } else {
+
+ MemoryOk = FALSE;
+
+ }
+
+ }
+
+ if ( MemoryOk ) {
+
+ //
+ // If recursing, Traverse all the subdirectories
+ //
+ if ( _SubdirSwitch ) {
+
+ Iterator->Reset();
+
+ MemoryOk = (BOOLEAN)( NodeArray && Iterator );
+
+ //
+ // Recurse thru all the subdirectories
+ //
+ while ( MemoryOk && ( ( Dir = (PFSN_DIRECTORY)Iterator->GetNext( )) != NULL )) {
+
+ if ( !DirectoryFilter->DoesNodeMatch( (PFSNODE)Dir ) ) {
+ continue;
+ }
+
+ if( _ExclusionList != NULL && IsExcluded( Dir->GetPath() ) ) {
+ continue;
+ }
+
+ DebugAssert( Dir->IsDirectory() );
+
+ // If we're using short names then convert this fsnode.
+
+ if (_UseShortSwitch && !Dir->UseAlternateName()) {
+ MemoryOk = FALSE;
+ continue;
+ }
+
+ //
+ // Append the name portion of the node to the destination path.
+ //
+ Name = Dir->QueryName();
+ DebugPtrAssert( Name );
+
+ if ( Name ) {
+ MemoryOk = DestinationPath->AppendBase( Name );
+ DebugAssert( MemoryOk );
+
+ DELETE( Name );
+
+ _CanRemoveEmptyDirectories = (BOOLEAN)!_EmptySwitch;
+
+ if ( MemoryOk ) {
+
+ //
+ // Recurse
+ //
+ Traverse( Dir, DestinationPath, FileFilter, DirectoryFilter, TRUE );
+
+ //
+ // Restore the destination path
+ //
+ DestinationPath->TruncateBase();
+ }
+ } else {
+ MemoryOk = FALSE;
+ }
+
+ }
+ }
+ }
+
+ DELETE( Iterator );
+ NodeArray->DeleteAllMembers();
+ DELETE( NodeArray );
+
+ if ( !MemoryOk ) {
+ DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY, NULL, EXIT_MISC_ERROR );
+ }
+
+ //
+ // If we created this directory but did not copy anything to it, we
+ // have to remove it.
+ //
+ if ( Created && TargetDirectory->IsEmpty() && !_EmptySwitch && !_StructureOnlySwitch ) {
+
+ SYSTEM::RemoveNode( (PFSNODE *)&TargetDirectory, TRUE );
+
+ } else {
+
+ DELETE( TargetDirectory );
+
+ }
+ }
+
+ return TRUE;
+}
+
+BOOLEAN
+XCOPY::UpdateTraverse (
+ IN PFSN_DIRECTORY DestDirectory,
+ IN OUT PPATH SourcePath,
+ IN PFSN_FILTER FileFilter,
+ IN PFSN_FILTER DirectoryFilter,
+ IN BOOLEAN CopyDirectoryStreams
+ )
+
+/*++
+
+Routine Description:
+
+ Traverse routine for update.
+
+ Like XCOPY::Traverse, except we traverse the *destination*
+ directory, possibly updating files we find there. The theory
+ being that there will be fewer files in the destination than
+ the source, so we can save time this way.
+
+ The callback function is invoked on each node
+ (directory or file) visited. The traversal may be finished
+ prematurely when the callback function returns FALSE.
+
+Arguments:
+
+ DestDirectory - Supplies pointer to destination directory
+
+ SourcePath - Supplies pointer to path to be used with the
+ callback function.
+
+ FileFilter - Supplies a pointer to the file filter.
+
+ DirectoryFilter - Supplies a pointer to the directory filter.
+
+ CopyDirectoryStreams - Specifies to copy directory streams when
+ copying directories.
+
+Return Value:
+
+ BOOLEAN - TRUE if everything traversed
+ FALSE otherwise.
+
+--*/
+
+{
+
+ PARRAY NodeArray;
+ PARRAY_ITERATOR Iterator;
+ BOOLEAN MemoryOk;
+ PFSN_FILE File;
+ PFSN_DIRECTORY Dir;
+ PWSTRING Name;
+ BOOLEAN Created = FALSE;
+ FSN_FILTER Filter;
+ PCPATH TemplatePath = NULL;
+
+ DebugPtrAssert( SourcePath );
+ DebugPtrAssert( FileFilter );
+ DebugPtrAssert( DirectoryFilter );
+
+ if ( !Filter.Initialize() ) {
+ return FALSE;
+ }
+
+ // Don't bother to traverse if
+ // destination directory is null
+
+ if (!DestDirectory)
+ return TRUE;
+
+ //
+ // We only traverse this directory if it is not empty (unless the
+ // empty switch is set).
+ //
+ if ( _EmptySwitch || !DestDirectory->IsEmpty() ) {
+
+ NodeArray = DestDirectory->QueryFsnodeArray( &Filter );
+ DebugPtrAssert( NodeArray );
+
+ if ( NodeArray ) {
+ //
+ // Get an iterator for processing the nodes
+ //
+ Iterator = ( PARRAY_ITERATOR ) NodeArray->QueryIterator( );
+ DebugPtrAssert( Iterator );
+ }
+
+ MemoryOk = (BOOLEAN)( NodeArray && Iterator );
+
+ //
+ // Copy all the files in the array.
+ //
+
+ while (MemoryOk && ((File = (PFSN_FILE)Iterator->GetNext()) != NULL)) {
+
+ if ( !FileFilter->DoesNodeMatch( (PFSNODE)File ) ) {
+ continue;
+ }
+
+ DebugAssert( !File->IsDirectory() );
+
+ // If we're supposed to use the short name then convert fsnode.
+
+ if (_UseShortSwitch && !File->UseAlternateName()) {
+ MemoryOk = FALSE;
+ continue;
+ }
+
+ //
+ // Append the name portion of the node to the destination path.
+ //
+ Name = File->QueryName();
+ DebugPtrAssert( Name );
+
+ if ( Name ) {
+ PFSN_FILE SourceFile;
+ PATH DestinationPath;
+ PATH TmpPath;
+
+ TmpPath.Initialize(SourcePath);
+ TmpPath.AppendBase(Name);
+
+ SourceFile = SYSTEM::QueryFile(&TmpPath);
+
+ DestinationPath.Initialize(DestDirectory->GetPath());
+
+ MemoryOk = DestinationPath.AppendBase( Name );
+ DebugAssert( MemoryOk );
+
+ DELETE( Name );
+
+ if ( MemoryOk && NULL != SourceFile ) {
+ //
+ // Copy the file
+ //
+
+ if ( !Copier( SourceFile, &DestinationPath ) ) {
+ ExitProgram( EXIT_MISC_ERROR );
+ }
+ }
+
+ } else {
+
+ MemoryOk = FALSE;
+
+ }
+
+ }
+
+ if ( MemoryOk ) {
+
+ //
+ // If recursing, Traverse all the subdirectories
+ //
+ if ( _SubdirSwitch ) {
+
+ Iterator->Reset();
+
+ MemoryOk = (BOOLEAN)( NodeArray && Iterator );
+
+ //
+ // Recurse thru all the subdirectories
+ //
+ while (MemoryOk &&
+ ((Dir = (PFSN_DIRECTORY)Iterator->GetNext()) != NULL)) {
+
+ if ( !DirectoryFilter->DoesNodeMatch( (PFSNODE)Dir ) ) {
+ continue;
+ }
+
+ if( _ExclusionList != NULL && IsExcluded(Dir->GetPath())) {
+ continue;
+ }
+
+ DebugAssert( Dir->IsDirectory() );
+
+ // If we're using short names then convert this fsnode.
+
+ if (_UseShortSwitch && !Dir->UseAlternateName()) {
+ MemoryOk = FALSE;
+ continue;
+ }
+
+ //
+ // Append the name portion of the node to the destination
+ // path.
+ //
+ Name = Dir->QueryName();
+ DebugPtrAssert( Name );
+
+ if ( Name ) {
+ MemoryOk = SourcePath->AppendBase( Name );
+ DebugAssert( MemoryOk );
+
+ DELETE( Name );
+
+ _CanRemoveEmptyDirectories = (BOOLEAN)!_EmptySwitch;
+
+ if ( MemoryOk ) {
+
+ //
+ // Recurse
+ //
+
+ UpdateTraverse( Dir, SourcePath, FileFilter,
+ DirectoryFilter, TRUE );
+
+ }
+
+ SourcePath->TruncateBase();
+
+ } else {
+ MemoryOk = FALSE;
+ }
+
+ }
+ }
+ }
+
+ DELETE( Iterator );
+ NodeArray->DeleteAllMembers();
+ DELETE( NodeArray );
+
+ if ( !MemoryOk ) {
+ DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY, NULL, EXIT_MISC_ERROR );
+ }
+ }
+
+ return TRUE;
+}
+
+
+XCOPY::ProgressCallBack(
+ LARGE_INTEGER TotalFileSize,
+ LARGE_INTEGER TotalBytesTransferred,
+ LARGE_INTEGER StreamSize,
+ LARGE_INTEGER StreamBytesTransferred,
+ DWORD dwStreamNumber,
+ DWORD dwCallbackReason,
+ HANDLE hSourceFile,
+ HANDLE hDestinationFile,
+ LPVOID lpData OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ Callback routine passed to CopyFileEx.
+
+ Check to see if the user hit Ctrl-C and return appropriate
+ value to CopyFileEx.
+
+Arguments:
+
+ TotalFileSize - Total size of the file in bytes.
+
+ TotalBytesTransferred - Total number of bytes transferred.
+
+ StreamSize - Size of the stream being copied in bytes.
+
+ StreamBytesTransferred - Number of bytes in current stream transferred.
+
+ dwStreamNumber - Stream number of the current stream.
+
+ dwCallBackReason - CALLBACK_CHUNK_FINISHED if a block was transferred,
+ CALLBACK_STREAM_SWITCH if a stream completed copying.
+
+ hSourceFile - Handle to the source file.
+
+ hDestinationFile - Handle to the destination file.
+
+ lpData - Pointer to opaque data that was passed to CopyFileEx. Used
+ in this instance to pass the "this" pointer to an XCOPY object.
+
+Return Value:
+
+ DWORD - PROGRESS_STOP if a Ctrl-C was hit and the copy was restartable,
+ PROGESS_CANCEL otherwise.
+
+--*/
+
+{
+ FILETIME LastWriteTime;
+
+ //
+ // If the file was just created then roll back LastWriteTime a little so a subsequent
+ // xcopy /d /z
+ // will work if the copy was interrupted.
+ //
+ if ( dwStreamNumber == 1 && dwCallbackReason == CALLBACK_STREAM_SWITCH )
+ {
+ if ( GetFileTime(hSourceFile, NULL, NULL, &LastWriteTime) )
+ {
+ LastWriteTime.dwLowDateTime -= 1000;
+ SetFileTime(hDestinationFile, NULL, NULL, &LastWriteTime);
+ }
+ }
+
+ // GetPFlagBreak returns a pointer to the flag indicating whether a Ctrl-C was hit
+ if ( *((( XCOPY *) lpData)->_Keyboard->GetPFlagBreak()) )
+ return ((XCOPY *) lpData)->_RestartableSwitch ? PROGRESS_STOP : PROGRESS_CANCEL;
+
+ return PROGRESS_CONTINUE;
+}
+
+BOOLEAN
+XCOPY::Copier (
+ IN OUT PFSN_FILE File,
+ IN PPATH DestinationPath
+ )
+/*++
+
+Routine Description:
+
+ This is the heart of XCopy. This is the guy who actually does
+ the copying.
+
+Arguments:
+
+ File - Supplies pointer to the source File.
+ DestinationPath - Supplies path of the desired destination.
+
+Return Value:
+
+ BOOLEAN - TRUE if copy successful.
+ FALSE otherwise
+
+Notes:
+
+--*/
+
+{
+ PATH PathToCopy;
+ PCWSTRING Name;
+ COPY_ERROR CopyError;
+ PFSN_FILE TargetFile = NULL;
+ BOOLEAN Proceed;
+ DWORD Attempts;
+ WCHAR PathBuffer[MAX_PATH + 2];
+ FSTRING WriteBuffer;
+ FSTRING EndOfLine;
+ DSTRING ErrorMessage;
+ PATH CanonSourcePath;
+
+
+ EndOfLine.Initialize((PWSTR) L"\r\n");
+ PathBuffer[0] = 0;
+ WriteBuffer.Initialize(PathBuffer, MAX_PATH);
+
+
+ //
+ // Maximum number of attempts to copy a file
+ //
+ #define MAX_ATTEMPTS 3
+
+ AbortIfCtrlC();
+
+ _CanRemoveEmptyDirectories = FALSE;
+
+ // If this file is on the exclusion list, don't bother.
+ //
+ if( _ExclusionList != NULL && IsExcluded( File->GetPath() ) ) {
+
+ return TRUE;
+ }
+
+ if ( _TargetIsFile ) {
+
+ //
+ // We replace the entire path
+ //
+ PathToCopy.Initialize( _TargetPath->GetPathString() );
+ PathToCopy.AppendBase( _FileNamePattern );
+
+ } else {
+
+ //
+ // Set the correct target file name.
+ //
+ PathToCopy.Initialize( DestinationPath );
+ if (!PathToCopy.ModifyName( _FileNamePattern )) {
+
+ _Message.Set(MSG_COMP_UNABLE_TO_EXPAND);
+ _Message.Display("%W%W", PathToCopy.QueryName(),
+ _FileNamePattern);
+ return FALSE;
+ }
+ }
+
+ //
+ // If in Update or CopyIfOld mode, determine if the target file
+ // already exists and if it is older than the source file.
+ //
+ if ( _CopyIfOldSwitch || _UpdateSwitch ) {
+
+ if ( TargetFile = SYSTEM::QueryFile( &PathToCopy ) ) {
+
+ //
+ // Target exists. If in CopyIfOld mode, copy only if target
+ // is older. If in Update mode, copy always.
+ //
+ if ( _CopyIfOldSwitch ) {
+ Proceed = *(File->QueryTimeInfo()) > *(TargetFile->QueryTimeInfo());
+ } else {
+ Proceed = TRUE;
+ }
+
+ DELETE( TargetFile );
+
+ if ( !Proceed ) {
+ return TRUE;
+ }
+ } else if ( _UpdateSwitch ) {
+ //
+ // In update mode but target does not exist. We do not
+ // copy.
+ //
+ return TRUE;
+ }
+ }
+
+
+ if ( !_PromptSwitch || UserConfirmedCopy( File ) ) {
+
+ //
+ // If the target is a file, we use that file path. Otherwise
+ // we figure out the correct path for the destination. Then
+ // we do the copy.
+ //
+
+ Name = File->GetPath()->GetPathString();
+
+ //
+ // If we are not prompting, we display the file name (unless we
+ // are in silent mode ).
+ //
+ if ( !_PromptSwitch && !_SilentSwitch && !_StructureOnlySwitch ) {
+ if ( _VerboseSwitch ) {
+
+ DisplayMessage( XCOPY_MESSAGE_VERBOSE_COPY, NORMAL_MESSAGE, "%W%W", Name, PathToCopy.GetPathString() );
+
+ } else {
+ WriteBuffer.Resize(0);
+ if (WriteBuffer.Strcat(Name) &&
+ WriteBuffer.Strcat(&EndOfLine)) {
+
+ GetStandardOutput()->WriteString(&WriteBuffer);
+
+ } else {
+ DebugPrintf("Path is longer than MAX_PATH");
+ return FALSE;
+ }
+ }
+ }
+
+ //
+ // Make sure that we are not copying to ourselves
+ //
+ CanonSourcePath.Initialize(Name, TRUE);
+ if (*(CanonSourcePath.GetPathString()) == *(PathToCopy.GetPathString())) {
+ DisplayMessageAndExit( XCOPY_ERROR_SELF_COPY, NULL, EXIT_MISC_ERROR );
+ }
+
+ //
+ // Copy file (unless we are in display-only mode)
+ //
+ if ( _DontCopySwitch || _StructureOnlySwitch ) {
+
+ _FilesCopied++;
+
+ } else {
+
+ Attempts = 0;
+
+ while ( TRUE ) {
+ LPPROGRESS_ROUTINE Progress = NULL;
+ PBOOL PCancelFlag = NULL;
+ //
+ // If copying to floppy, we must determine if there is
+ // enough disk space for the file, and if not then we
+ // must ask for another disk and create all the directory
+ // structure up to the parent directory.
+ //
+ if ( _DisketteCopy ) {
+
+ CheckTargetSpace( File, &PathToCopy );
+ }
+
+ //
+ // If the copy is restartable, pass the address of the callback
+ // routine. Otherwise, pass the address of _FlagBreak as the
+ // cancel flag.
+ //
+ if ( _RestartableSwitch )
+ Progress = (LPPROGRESS_ROUTINE) ProgressCallBack;
+ else
+ PCancelFlag = _Keyboard->GetPFlagBreak();
+
+ if ( File->Copy( &PathToCopy, &CopyError, _ReadOnlySwitch, !_CopyAttrSwitch,
+ _RestartableSwitch, Progress, (VOID *) this, PCancelFlag )) {
+
+ if (!_CopyAttrSwitch && (TargetFile = SYSTEM::QueryFile( &PathToCopy )) ) {
+ DWORD dwError;
+ TargetFile->MakeArchived(&dwError);
+ }
+
+ if ( _ModifySwitch ) {
+ File->ResetArchivedAttribute();
+ }
+
+ if( _VerifySwitch ) {
+
+ // Check that the new file is the same length as
+ // the old file.
+ //
+ if( (TargetFile = SYSTEM::QueryFile( &PathToCopy )) == NULL ||
+ TargetFile->QuerySize() != File->QuerySize() ) {
+
+ DELETE( TargetFile );
+
+ DisplayMessage( XCOPY_ERROR_VERIFY_FAILED, ERROR_MESSAGE );
+ if ( !_ContinueSwitch ) {
+ return FALSE;
+ }
+
+ break;
+ }
+
+ DELETE( TargetFile );
+ }
+
+ _FilesCopied++;
+
+ break;
+
+ } else {
+
+ //
+ // If the copy was cancelled mid-stream, exit.
+ //
+ AbortIfCtrlC();
+
+ //
+ // In case of error, wait for a little while and try
+ // again, otherwise display the error.
+ //
+ if ( Attempts++ < MAX_ATTEMPTS ) {
+
+ Sleep( 100 );
+
+ } else {
+
+ switch ( CopyError ) {
+
+ case COPY_ERROR_ACCESS_DENIED:
+ DisplayMessage( XCOPY_ERROR_ACCESS_DENIED, ERROR_MESSAGE);
+ break;
+
+ case COPY_ERROR_SHARE_VIOLATION:
+ DisplayMessage( XCOPY_ERROR_SHARING_VIOLATION, ERROR_MESSAGE);
+ break;
+
+ default:
+
+ //
+ // At this point we don't know if the copy left a
+ // bogus file on disk. If the target file exist,
+ // we assume that it is bogus so we delete it.
+ //
+ if ( TargetFile = SYSTEM::QueryFile( &PathToCopy ) ) {
+
+ TargetFile->DeleteFromDisk( TRUE );
+
+ DELETE( TargetFile );
+ }
+
+ switch ( CopyError ) {
+ case COPY_ERROR_DISK_FULL:
+ DisplayMessageAndExit( XCOPY_ERROR_DISK_FULL, NULL, EXIT_MISC_ERROR );
+ break;
+
+ default:
+ if (SYSTEM::QueryWindowsErrorMessage(CopyError, &ErrorMessage)) {
+ DisplayMessage( XCOPY_ERROR_CANNOT_MAKE, ERROR_MESSAGE, "%W", &ErrorMessage );
+ }
+ break;
+ }
+
+ break;
+ }
+
+ if ( !_ContinueSwitch ) {
+ return FALSE;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+
+BOOLEAN
+XCOPY::CheckTargetSpace (
+ IN OUT PFSN_FILE File,
+ IN PPATH DestinationPath
+ )
+/*++
+
+Routine Description:
+
+ Makes sure that there is enought disk space in the target disk.
+ Asks the user to change the disk if necessary.
+
+Arguments:
+
+ File - Supplies pointer to the source File.
+ DestinationPath - Supplies path of the desired destination.
+
+Return Value:
+
+ BOOLEAN - TRUE if OK
+ FALSE otherwise
+
+--*/
+{
+
+ PFSN_FILE TargetFile = NULL;
+ ULONG TargetSize;
+ PWSTRING TargetDrive;
+ WCHAR Resp;
+ DSTRING TargetRoot;
+ DSTRING Slash;
+ PATH TmpPath;
+ PATH TmpPath1;
+ PFSN_DIRECTORY PartialDirectory = NULL;
+ PFSN_DIRECTORY DestinationDirectory = NULL;
+ BOOLEAN DirDeleted = NULL;
+ PATH PathToDelete;
+ CHNUM CharsInPartialDirectoryPath;
+ BIG_INT FreeSpace;
+ BIG_INT FileSize;
+
+ if ( TargetFile = SYSTEM::QueryFile( DestinationPath ) ) {
+
+ TargetSize = TargetFile->QuerySize();
+
+ DELETE( TargetFile );
+
+ } else {
+
+ TargetSize = 0;
+ }
+
+ TargetDrive = DestinationPath->QueryDevice();
+
+ FileSize = File->QuerySize();
+
+ if ( TargetDrive ) {
+
+ TargetRoot.Initialize( TargetDrive );
+
+ if ( TargetRoot.QueryChAt( TargetRoot.QueryChCount()-1) != (WCHAR)'\\' ) {
+ Slash.Initialize( "\\" );
+ TargetRoot.Strcat( &Slash );
+ }
+
+
+ while ( TRUE ) {
+
+ if ( IFS_SYSTEM::QueryFreeDiskSpace( &TargetRoot, &FreeSpace ) ) {
+
+ FreeSpace = FreeSpace + TargetSize;
+
+ // DebugPrintf( "Disk Space: %d Needed: %d\n", FreeSpace.GetLowPart(), FileSize.GetLowPart() );
+
+ if ( FreeSpace < FileSize ) {
+
+ //
+ // Not enough free space, ask for another
+ // disk and create the directory structure.
+ //
+ DisplayMessage( XCOPY_MESSAGE_CHANGE_DISK, NORMAL_MESSAGE );
+ AbortIfCtrlC();
+
+ _Keyboard->DisableLineMode();
+ if( GetStandardInput()->IsAtEnd() ) {
+ // Insufficient input--treat as CONTROL-C.
+ //
+ Resp = CTRL_C;
+ } else {
+ GetStandardInput()->ReadChar( &Resp );
+ }
+ _Keyboard->EnableLineMode();
+
+ if ( Resp == CTRL_C ) {
+ exit( EXIT_TERMINATED );
+ } else {
+ GetStandardOutput()->WriteChar( Resp );
+ GetStandardOutput()->WriteChar( '\r' );
+ GetStandardOutput()->WriteChar( '\n' );
+ }
+
+
+ //
+ // Create directory structure in target
+ //
+ TmpPath.Initialize( DestinationPath );
+ TmpPath.TruncateBase();
+
+ PartialDirectory = SYSTEM::QueryDirectory( &TmpPath, TRUE );
+
+ if (PartialDirectory == NULL ) {
+ continue;
+ } else {
+
+ if ( *(PartialDirectory->GetPath()->GetPathString()) !=
+ *(TmpPath.GetPathString()) ) {
+
+ TmpPath1.Initialize( &TmpPath );
+ DestinationDirectory = PartialDirectory->CreateDirectoryPath( &TmpPath1 );
+ } else {
+ DestinationDirectory = PartialDirectory;
+ }
+ }
+
+ //
+ // If still not enough disk space, remove the directories
+ // that we created and try again
+ //
+ IFS_SYSTEM::QueryFreeDiskSpace( TargetDrive, &FreeSpace );
+ FreeSpace = FreeSpace + TargetSize;
+
+ if ( FreeSpace < FileSize ) {
+
+ if ( PartialDirectory != DestinationDirectory ) {
+
+ if (!PathToDelete.Initialize( DestinationDirectory->GetPath() )) {
+ DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY, NULL, EXIT_MISC_ERROR );
+ }
+
+ CharsInPartialDirectoryPath = PartialDirectory->GetPath()->GetPathString()->QueryChCount();
+
+ while ( PathToDelete.GetPathString()->QueryChCount() >
+ CharsInPartialDirectoryPath ) {
+
+ DirDeleted = DestinationDirectory->DeleteDirectory();
+
+ DebugAssert( DirDeleted );
+
+ DELETE( DestinationDirectory );
+ DestinationDirectory = NULL;
+
+ PathToDelete.TruncateBase();
+ DestinationDirectory = SYSTEM::QueryDirectory( &PathToDelete );
+ DebugPtrAssert( DestinationDirectory );
+ }
+ }
+ }
+
+ if ( PartialDirectory != DestinationDirectory ) {
+ DELETE( PartialDirectory );
+ DELETE( DestinationDirectory );
+ } else {
+ DELETE( PartialDirectory );
+ }
+
+ } else {
+ break;
+ }
+
+ } else {
+
+ //
+ // Cannot determine free disk space!
+ //
+ break;
+ }
+ }
+
+ DELETE( TargetDrive );
+ }
+
+ return TRUE;
+}
+
+
+
+
+VOID
+XCOPY::GetDirectoryAndFilters (
+ IN PPATH Path,
+ OUT PFSN_DIRECTORY *OutDirectory,
+ OUT PFSN_FILTER *FileFilter,
+ OUT PFSN_FILTER *DirectoryFilter,
+ OUT PBOOLEAN CopyingManyFiles
+ )
+
+/*++
+
+Routine Description:
+
+ Obtains a directory object and the filename to match
+
+Arguments:
+
+ Path - Supplies pointer to the path
+ OutDirectory - Supplies pointer to pointer to directory
+ FileFilter - Supplies filter for files
+ DirectoryFilter - Supplies filter for directories
+ CopyingManyFiles - Supplies pointer to flag which if TRUE means that
+ we are copying many files
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+
+ PFSN_DIRECTORY Directory;
+ PFSN_FILE File;
+ PWSTRING Prefix = NULL;
+ PWSTRING FileName = NULL;
+ PATH PrefixPath;
+ PATH TmpPath;
+ FSN_ATTRIBUTE All = (FSN_ATTRIBUTE)0;
+ FSN_ATTRIBUTE Any = (FSN_ATTRIBUTE)0;
+ FSN_ATTRIBUTE None = (FSN_ATTRIBUTE)0;
+ PFSN_FILTER FilFilter;
+ PFSN_FILTER DirFilter;
+ DSTRING Name;
+
+
+
+ //
+ // Create filters
+ //
+ if ( ( (FilFilter = NEW FSN_FILTER) == NULL ) ||
+ ( (DirFilter = NEW FSN_FILTER) == NULL ) ||
+ !FilFilter->Initialize() ||
+ !DirFilter->Initialize() ) {
+ DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY, NULL, EXIT_MISC_ERROR );
+ }
+
+ if (( Directory = SYSTEM::QueryDirectory( Path )) != NULL ) {
+
+ //
+ // Copying a directory. We will want everything in the directory
+ //
+ FilFilter->SetFileName( "*.*" );
+ *CopyingManyFiles = TRUE;
+
+ } else {
+
+ //
+ // The path is not a directory. Get the prefix part (which SHOULD
+ // be a directory, and try to make a directory from it
+ //
+ *CopyingManyFiles = Path->HasWildCard();
+
+ if ( !*CopyingManyFiles ) {
+
+ //
+ // If the path is not a file, then this is an error
+ //
+ if ( !(File = SYSTEM::QueryFile( Path )) ) {
+
+ if ((FileName = Path->QueryName()) == NULL ||
+ !Name.Initialize( FileName )) {
+ DisplayMessageAndExit( XCOPY_ERROR_INVALID_PATH, NULL, EXIT_MISC_ERROR );
+ }
+ DisplayMessageAndExit( XCOPY_ERROR_FILE_NOT_FOUND,
+ &Name,
+ EXIT_MISC_ERROR );
+
+ }
+
+ DELETE( File );
+ }
+
+ Prefix = Path->QueryPrefix();
+
+ if ( !Prefix ) {
+
+ //
+ // No prefix, use the drive part.
+ //
+ TmpPath.Initialize( Path, TRUE );
+
+ Prefix = TmpPath.QueryDevice();
+ }
+
+ if ( !PrefixPath.Initialize( Prefix, FALSE ) ) {
+ DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY, NULL, EXIT_MISC_ERROR );
+ }
+
+ if (( Directory = SYSTEM::QueryDirectory( &PrefixPath )) != NULL ) {
+
+ //
+ // Directory is ok, set the filter's filename criteria
+ // with the file (pattern) specified.
+ //
+ if ((FileName = Path->QueryName()) == NULL ) {
+ DisplayMessageAndExit( XCOPY_ERROR_INVALID_PATH, NULL, EXIT_MISC_ERROR );
+ }
+
+ FilFilter->SetFileName( FileName );
+
+ } else {
+
+ //
+ // Something went wrong...
+ //
+ if ((FileName = Path->QueryName()) == NULL ||
+ !Name.Initialize( FileName )) {
+ DisplayMessageAndExit( XCOPY_ERROR_INVALID_PATH, NULL, EXIT_MISC_ERROR );
+ }
+ DisplayMessageAndExit( XCOPY_ERROR_FILE_NOT_FOUND,
+ &Name,
+ EXIT_MISC_ERROR );
+ }
+
+ DELETE( Prefix );
+ DELETE( FileName );
+
+ }
+
+ //
+ // Ok, we have the directory object and the filefilter's path set.
+ //
+
+ //
+ // Set the file filter attribute criteria
+ //
+ None = (FSN_ATTRIBUTE)(None | FSN_ATTRIBUTE_DIRECTORY );
+ if ( !_HiddenSwitch ) {
+ None = (FSN_ATTRIBUTE)(None | FSN_ATTRIBUTE_HIDDEN | FSN_ATTRIBUTE_SYSTEM );
+ }
+
+ if (_ArchiveSwitch) {
+ All = (FSN_ATTRIBUTE)(All | FSN_ATTRIBUTE_ARCHIVE);
+ }
+
+ FilFilter->SetAttributes( All, Any, None );
+
+ //
+ // Set the file filter's time criteria
+ //
+ if ( _Date != NULL ) {
+ FilFilter->SetTimeInfo( _Date,
+ FSN_TIME_MODIFIED,
+ (TIME_AT | TIME_AFTER) );
+ }
+
+ //
+ // Set the directory filter attribute criteria.
+ //
+ All = (FSN_ATTRIBUTE)0;
+ Any = (FSN_ATTRIBUTE)0;
+ None = (FSN_ATTRIBUTE)0;
+
+ if ( !_HiddenSwitch ) {
+ None = (FSN_ATTRIBUTE)(None | FSN_ATTRIBUTE_HIDDEN | FSN_ATTRIBUTE_SYSTEM );
+ }
+
+ if (_SubdirSwitch) {
+ All = (FSN_ATTRIBUTE)(All | FSN_ATTRIBUTE_DIRECTORY);
+ } else {
+ None = (FSN_ATTRIBUTE)(None | FSN_ATTRIBUTE_DIRECTORY);
+ }
+
+ DirFilter->SetAttributes( All, Any, None );
+
+
+ *FileFilter = FilFilter;
+ *DirectoryFilter = DirFilter;
+ *OutDirectory = Directory;
+
+}
+
+VOID
+XCOPY::GetDirectoryAndFilePattern(
+ IN PPATH Path,
+ IN BOOLEAN CopyingManyFiles,
+ OUT PPATH *OutDirectory,
+ OUT PWSTRING *OutFilePattern
+ )
+
+/*++
+
+Routine Description:
+
+ Gets the path of the destination directory and the pattern that
+ will be used for filename conversion.
+
+Arguments:
+
+ Path - Supplies pointer to the path
+ CopyingManyFiles - Supplies flag which if true means that we are copying many
+ files.
+ OutDirectory - Supplies pointer to pointer to directory path
+ OutFilePattern - Supplies pointer to pointer to file name
+ IsDir ` - Supplies pointer to isdir flag
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ PPATH Directory;
+ PWSTRING FileName;
+ PWSTRING Prefix;
+ PWSTRING Name;
+ BOOLEAN DeletePath = FALSE;
+ PFSN_DIRECTORY TmpDir;
+ PATH TmpPath;
+ DSTRING Slash;
+ DSTRING TmpPath1Str;
+ PATH TmpPath1;
+
+ if ( !Path ) {
+
+ //
+ // There is no path, we invent our own
+ //
+ if ( ((Path = NEW PATH) == NULL ) ||
+ !Path->Initialize( (LPWSTR)L"*.*", FALSE)) {
+
+ DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY, NULL, EXIT_MISC_ERROR );
+ }
+ DeletePath = TRUE;
+ }
+
+ TmpDir = SYSTEM::QueryDirectory( Path );
+
+ if ( !TmpDir && (Path->HasWildCard() || IsFileName( Path, CopyingManyFiles ))) {
+
+ //
+ // The path is not a directory, so we use the prefix as a
+ // directory path and the filename becomes the pattern.
+ //
+ if ( !TmpPath.Initialize( Path, TRUE ) ||
+ ((Prefix = TmpPath.QueryPrefix()) == NULL) ||
+ !Slash.Initialize( "\\" ) ||
+ !TmpPath1Str.Initialize( Prefix ) ||
+ !TmpPath1.Initialize( &TmpPath1Str, FALSE ) ||
+ ((Name = TmpPath.QueryName()) == NULL) ||
+ ((Directory = NEW PATH) == NULL) ||
+ !Directory->Initialize( &TmpPath1, TRUE ) ||
+ ((FileName = NEW DSTRING) == NULL ) ||
+ !FileName->Initialize( Name ) ) {
+
+ DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY, NULL, EXIT_MISC_ERROR );
+
+ }
+
+ DELETE( Prefix );
+ DELETE( Name );
+
+ } else {
+
+ //
+ // The path specifies a directory, so we use all of it and the
+ // pattern is "*.*"
+ //
+ if ( ((Directory = NEW PATH) == NULL ) ||
+ !Directory->Initialize( Path,TRUE ) ||
+ ((FileName = NEW DSTRING) == NULL ) ||
+ !FileName->Initialize( "*.*" ) ) {
+
+ DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY, NULL, EXIT_MISC_ERROR );
+
+ }
+ DELETE( TmpDir );
+
+ }
+
+ *OutDirectory = Directory;
+ *OutFilePattern = FileName;
+
+ //
+ // If we created the path, we have to delete it
+ //
+ if ( DeletePath ) {
+ DELETE( Path );
+ }
+}
+
+BOOL
+XCOPY::IsCyclicalCopy(
+ IN PPATH PathSrc,
+ IN PPATH PathTrg
+ )
+
+/*++
+
+Routine Description:
+
+ Determines if there is a cycle between two paths
+
+Arguments:
+
+ PathSrc - Supplies pointer to first path
+ PathTrg - Supplies pointer to second path
+
+Return Value:
+
+ TRUE if there is a cycle,
+ FALSE otherwise
+
+--*/
+
+{
+ PATH SrcPath;
+ PATH TrgPath;
+ PARRAY ArraySrc, ArrayTrg;
+ PARRAY_ITERATOR IteratorSrc, IteratorTrg;
+ PWSTRING ComponentSrc, ComponentTrg;
+ BOOLEAN IsCyclical = FALSE;
+
+ DebugAssert( PathSrc != NULL );
+
+ if ( PathTrg != NULL ) {
+
+ //
+ // Get canonicalized paths for both source and target
+ //
+ SrcPath.Initialize(PathSrc, TRUE );
+ TrgPath.Initialize(PathTrg, TRUE );
+
+ //
+ // Split the paths into their components
+ //
+ ArraySrc = SrcPath.QueryComponentArray();
+ ArrayTrg = TrgPath.QueryComponentArray();
+
+ DebugPtrAssert( ArraySrc );
+ DebugPtrAssert( ArrayTrg );
+
+ if ( !ArraySrc || !ArrayTrg ) {
+ DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY, NULL, EXIT_MISC_ERROR );
+ }
+
+ //
+ // Get iterators for the components
+ //
+ IteratorSrc = ( PARRAY_ITERATOR )ArraySrc->QueryIterator();
+ IteratorTrg = ( PARRAY_ITERATOR )ArrayTrg->QueryIterator();
+
+ DebugPtrAssert( IteratorSrc );
+ DebugPtrAssert( IteratorTrg );
+
+ if ( !IteratorSrc || !IteratorTrg ) {
+ DisplayMessageAndExit( XCOPY_ERROR_NO_MEMORY, NULL, EXIT_MISC_ERROR );
+ }
+
+ //
+ // There is a cycle if all of the source is along the target.
+ //
+ while ( TRUE ) {
+
+ ComponentSrc = (PWSTRING)IteratorSrc->GetNext();
+
+ if ( !ComponentSrc ) {
+
+ //
+ // The source path is along the target path. This is a
+ // cycle.
+ //
+ IsCyclical = TRUE;
+ break;
+
+ }
+
+ ComponentTrg = (PWSTRING)IteratorTrg->GetNext();
+
+ if ( !ComponentTrg ) {
+
+ //
+ // The target path is along the source path. This is no
+ // cycle.
+ //
+ break;
+
+ }
+
+ if ( *ComponentSrc != *ComponentTrg ) {
+
+ //
+ // One path is not along the other. There is no cycle.
+ //
+ break;
+ }
+ }
+
+ DELETE( IteratorSrc );
+ DELETE( IteratorTrg );
+
+ ArraySrc->DeleteAllMembers();
+ ArrayTrg->DeleteAllMembers();
+
+ DELETE( ArraySrc );
+ DELETE( ArrayTrg );
+
+ }
+
+ return IsCyclical;
+}
+
+BOOL
+XCOPY::IsFileName(
+ IN PPATH Path,
+ IN BOOLEAN CopyingManyFiles
+ )
+
+/*++
+
+Routine Description:
+
+ Figures out if a name refers to a directory or a file.
+
+Arguments:
+
+ Path - Supplies pointer to the path
+ CopyingManyFiles - Supplies flag which if TRUE means that we are
+ copying many files.
+
+Return Value:
+
+ BOOLEAN - TRUE if name refers to file,
+ FALSE otherwise
+
+Notes:
+
+--*/
+
+{
+
+ PFSN_DIRECTORY FsnDirectory;
+ PFSN_FILE FsnFile;
+ WCHAR Resp;
+ PWSTRING DirMsg;
+ PWSTRING FilMsg;
+
+ //
+ // If the path is an existing directory, then this is obviously
+ // not a file.
+ //
+ //
+ if ((FsnDirectory = SYSTEM::QueryDirectory( Path )) != NULL ) {
+
+ DELETE( FsnDirectory );
+ return FALSE;
+ }
+
+ //
+ // If the path ends with a delimiter, then it is a directory.
+ // We remove the delimiter.
+ //
+ if ( Path->EndsWithDelimiter() ) {
+ ((PWSTRING) Path->GetPathString())->Truncate( Path->GetPathString()->QueryChCount() - 1 );
+ Path->Initialize( Path->GetPathString() );
+ return FALSE;
+ }
+
+ //
+ // If the path is an existing file, then it is a file.
+ //
+ if ((FsnFile = SYSTEM::QueryFile( Path )) != NULL ) {
+
+ DELETE( FsnFile );
+ return _TargetIsFile = TRUE;
+ }
+
+ DirMsg = QueryMessageString(XCOPY_RESPONSE_DIRECTORY);
+ FilMsg = QueryMessageString(XCOPY_RESPONSE_FILE);
+
+ DebugPtrAssert( DirMsg );
+ DebugPtrAssert( FilMsg );
+
+ //
+ // If the path does not exist, we are copying many files, and we are intelligent,
+ // then the target is obviously a directory.
+ //
+ // Otherwise we simply ask the user.
+ //
+ if ( _IntelligentSwitch && CopyingManyFiles ) {
+
+ _TargetIsFile = FALSE;
+
+ } else {
+
+ while ( TRUE ) {
+
+ DisplayMessage( XCOPY_MESSAGE_FILE_OR_DIRECTORY, NORMAL_MESSAGE, "%W", Path->GetPathString() );
+
+ AbortIfCtrlC();
+
+ _Keyboard->DisableLineMode();
+ if( GetStandardInput()->IsAtEnd() ) {
+ // Insufficient input--treat as CONTROL-C.
+ //
+ Resp = CTRL_C;
+ } else {
+ GetStandardInput()->ReadChar( &Resp );
+ }
+ _Keyboard->EnableLineMode();
+
+ if ( Resp == CTRL_C ) {
+ exit( EXIT_TERMINATED );
+ } else {
+ GetStandardOutput()->WriteChar( Resp );
+ GetStandardOutput()->WriteChar( '\r' );
+ GetStandardOutput()->WriteChar( '\n' );
+ }
+
+ Resp = (WCHAR)towupper( (wchar_t)Resp );
+
+ if ( FilMsg->QueryChAt(0) == Resp ) {
+ _TargetIsFile = TRUE;
+ break;
+ } else if ( DirMsg->QueryChAt(0) == Resp ) {
+ _TargetIsFile = FALSE;
+ break;
+ }
+ }
+ }
+
+ DELETE( DirMsg );
+ DELETE( FilMsg );
+
+ return _TargetIsFile;
+
+}
+
+BOOLEAN
+XCOPY::UserConfirmedCopy (
+ IN PCFSNODE FsNode
+ )
+
+/*++
+
+Routine Description:
+
+ Gets confirmation from the user about a file to be copied
+
+Arguments:
+
+ FsNode - Supplies pointer to FSNODE of file to be
+ copied
+
+Return Value:
+
+ BOOLEAN - TRUE if the user confirmed the copy
+ FALSE otherwise
+
+--*/
+
+{
+ PWSTRING YesMsg;
+ PWSTRING NoMsg;
+ WCHAR Resp;
+ BOOLEAN Confirmed;
+
+
+ YesMsg = QueryMessageString(XCOPY_RESPONSE_YES);
+ NoMsg = QueryMessageString(XCOPY_RESPONSE_NO);
+
+ DebugPtrAssert( YesMsg );
+ DebugPtrAssert( NoMsg );
+
+ while ( TRUE ) {
+
+ DisplayMessage( XCOPY_MESSAGE_CONFIRM, NORMAL_MESSAGE, "%W", FsNode->GetPath()->GetPathString() );
+
+ AbortIfCtrlC();
+
+ _Keyboard->DisableLineMode();
+
+ if( GetStandardInput()->IsAtEnd() ) {
+ // Insufficient input--treat as CONTROL-C.
+ //
+ Resp = NoMsg->QueryChAt( 0 );
+ break;
+ } else {
+ GetStandardInput()->ReadChar( &Resp );
+ }
+ _Keyboard->EnableLineMode();
+
+ if ( Resp == CTRL_C ) {
+ exit( EXIT_TERMINATED );
+ } else {
+ GetStandardOutput()->WriteChar( Resp );
+ GetStandardOutput()->WriteChar( '\r' );
+ GetStandardOutput()->WriteChar( '\n' );
+ }
+
+ Resp = (WCHAR)towupper( (wchar_t)Resp );
+
+ if ( YesMsg->QueryChAt( 0 ) == Resp ) {
+ Confirmed = TRUE;
+ break;
+ }
+ else if ( NoMsg->QueryChAt( 0 ) == Resp ) {
+ Confirmed = FALSE;
+ break;
+ }
+ }
+
+ DELETE( YesMsg );
+ DELETE( NoMsg );
+
+ return Confirmed;
+
+
+}
+
+
+BOOLEAN
+XCOPY::IsExcluded(
+ IN PCPATH Path
+ )
+/*++
+
+Routine Description:
+
+ This method determines whether the specified path should be
+ excluded from the XCOPY.
+
+Arguments:
+
+ Path -- Supplies the path of the file in question.
+
+Return Value:
+
+ TRUE if this file should be excluded, i.e. if any element of
+ the exclusion list array appears as a substring of this path.
+
+--*/
+{
+ PWSTRING CurrentString;
+ DSTRING UpcasedPath;
+
+
+ if( _ExclusionList == NULL ) {
+
+ return FALSE;
+ }
+
+ if( !UpcasedPath.Initialize( Path->GetPathString() ) ) {
+
+ return FALSE;
+ }
+
+ UpcasedPath.Strupr( );
+
+ _Iterator->Reset();
+
+ while( (CurrentString = (PWSTRING)_Iterator->GetNext()) != NULL ) {
+
+ if( UpcasedPath.Strstr( CurrentString ) != INVALID_CHNUM ) {
+
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
diff --git a/private/utils/xcopy/xcopy.hxx b/private/utils/xcopy/xcopy.hxx
new file mode 100644
index 000000000..51366d442
--- /dev/null
+++ b/private/utils/xcopy/xcopy.hxx
@@ -0,0 +1,353 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ XCopy.hxx
+
+Abstract:
+
+ This module contains the definition for the XCOPY class, which
+ implements the DOS5-compatible XCopy utility.
+
+Author:
+
+ Ramon Juan San Andres (ramonsa) 01-May-1990
+
+
+Revision History:
+
+
+--*/
+
+
+#if !defined( _XCOPY_ )
+
+#define _XCOPY_
+
+//
+// Exit codes
+//
+#define EXIT_NORMAL 0
+#define EXIT_NO_FILES 1
+#define EXIT_TERMINATED 2
+#define EXIT_MISC_ERROR 4
+#define EXIT_READWRITE_ERROR 5
+
+#include "object.hxx"
+#include "keyboard.hxx"
+#include "program.hxx"
+
+//
+// Forward references
+//
+DECLARE_CLASS( ARRAY );
+DECLARE_CLASS( FSN_DIRECTORY );
+DECLARE_CLASS( FSNODE );
+DECLARE_CLASS( FSN_FILE );
+DECLARE_CLASS( FSN_FILTER );
+DECLARE_CLASS( TIMEINFO );
+DECLARE_CLASS( XCOPY );
+DECLARE_CLASS( ARGUMENT_LEXEMIZER );
+DECLARE_CLASS( STRING_ARRAY );
+DECLARE_CLASS( ITERATOR );
+
+class XCOPY : public PROGRAM {
+
+ public:
+
+ DECLARE_CONSTRUCTOR( XCOPY );
+
+ NONVIRTUAL
+ ~XCOPY (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Initialize (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ DoCopy (
+ );
+
+
+ private:
+
+ NONVIRTUAL
+ VOID
+ Construct (
+ );
+
+ NONVIRTUAL
+ VOID
+ AbortIfCtrlC(
+ VOID
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ CheckTargetSpace (
+ IN OUT PFSN_FILE File,
+ IN PPATH DestinationPath
+ );
+
+ NONVIRTUAL
+ VOID
+ CheckArgumentConsistency (
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Copier (
+ IN OUT PFSN_FILE File,
+ IN PPATH DestinationPath
+ );
+
+ NONVIRTUAL
+ VOID
+ DeallocateThings (
+ );
+
+ NONVIRTUAL
+ VOID
+ DisplayMessageAndExit (
+ IN MSGID MsgId,
+ IN PWSTRING String,
+ IN ULONG ExitCode
+ );
+
+ NONVIRTUAL
+ VOID
+ ExitWithError(
+ IN DWORD ErrorCode
+ );
+
+ NONVIRTUAL
+ VOID
+ GetArgumentsCmd(
+ );
+
+ NONVIRTUAL
+ VOID
+ GetDirectoryAndFilePattern(
+ IN PPATH Path,
+ IN BOOLEAN CopyingManyFiles,
+ OUT PPATH *OutDirectory,
+ OUT PWSTRING *OutFilePattern
+ );
+
+ NONVIRTUAL
+ VOID
+ GetDirectoryAndFilters(
+ IN PPATH Path,
+ OUT PFSN_DIRECTORY *OutDirectory,
+ OUT PFSN_FILTER *FileFilter,
+ OUT PFSN_FILTER *DirectoryFilter,
+ OUT PBOOLEAN CopyingManyFiles
+ );
+
+ NONVIRTUAL
+ VOID
+ InitializeThings (
+ );
+
+ NONVIRTUAL
+ BOOL
+ IsCyclicalCopy(
+ IN PPATH PathSrc,
+ IN PPATH PathTrg
+ );
+
+ NONVIRTUAL
+ BOOL
+ IsFileName(
+ IN PPATH Path,
+ IN BOOLEAN CopyingManyFiles
+ );
+
+ NONVIRTUAL
+ PARGUMENT_LEXEMIZER
+ ParseArguments(
+ IN PWSTRING CmdLine,
+ OUT PARRAY ArgArray
+ );
+
+ STATIC
+ WINAPI
+ ProgressCallBack(
+ LARGE_INTEGER TotalFileSize,
+ LARGE_INTEGER TotalBytesTransferred,
+ LARGE_INTEGER StreamSize,
+ LARGE_INTEGER StreamBytesTransferred,
+ DWORD dwStreamNumber,
+ DWORD dwCallbackReason,
+ HANDLE hSourceFile,
+ HANDLE hDestinationFile,
+ LPVOID lpData OPTIONAL
+ );
+
+ NONVIRTUAL
+ PWSTRING
+ QueryMessageString (
+ IN MSGID MsgId
+ );
+
+ VOID
+ SetArguments(
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ Traverse (
+ IN PFSN_DIRECTORY Directory,
+ IN OUT PPATH DestinationPath,
+ IN PFSN_FILTER FileFilter,
+ IN PFSN_FILTER DirectoryFilter,
+ IN BOOLEAN CopyDirectoryStreams
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ UpdateTraverse (
+ IN PFSN_DIRECTORY Directory,
+ IN OUT PPATH DestinationPath,
+ IN PFSN_FILTER FileFilter,
+ IN PFSN_FILTER DirectoryFilter,
+ IN BOOLEAN CopyDirectoryStreams
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ UserConfirmedCopy (
+ IN PCFSNODE FsNode
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ InitializeExclusionList(
+ IN PWSTRING ListOfFiles
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ AddToExclusionList(
+ IN PWSTRING ExclusionListFileName
+ );
+
+ NONVIRTUAL
+ BOOLEAN
+ IsExcluded(
+ IN PCPATH Path
+ );
+
+
+ //
+ // Paths, switches etc. specified in the command line.
+ //
+
+ //
+ // DOS options
+ //
+ PPATH _SourcePath;
+ PPATH _DestinationPath;
+ PTIMEINFO _Date;
+ BOOLEAN _ArchiveSwitch;
+ BOOLEAN _EmptySwitch;
+ BOOLEAN _ModifySwitch;
+ BOOLEAN _PromptSwitch;
+ BOOLEAN _SubdirSwitch;
+ BOOLEAN _VerifySwitch;
+ BOOLEAN _WaitSwitch;
+
+
+ //
+ // Windows NT additional options
+ //
+ BOOLEAN _ContinueSwitch; // Continue if error
+ BOOLEAN _CopyIfOldSwitch; // Only newer files
+ BOOLEAN _IntelligentSwitch; // Don't ask F or D
+ BOOLEAN _HiddenSwitch; // Copy hidden
+ BOOLEAN _ReadOnlySwitch; // Overwrite RO
+ BOOLEAN _SilentSwitch; // Silent mode
+ BOOLEAN _VerboseSwitch; // Verbose mode
+ BOOLEAN _DontCopySwitch; // Display only
+ BOOLEAN _StructureOnlySwitch; // Structure only
+ BOOLEAN _UpdateSwitch; // Apdate existing
+ BOOLEAN _CopyAttrSwitch; // Copy attributes
+ BOOLEAN _UseShortSwitch; // Use short names
+ BOOLEAN _RestartableSwitch; // Copy is restartable
+ //
+ // Are we copying to diskette?
+ //
+ BOOLEAN _DisketteCopy;
+
+ //
+ // Number of files copied.
+ //
+ ULONG _FilesCopied;
+
+ //
+ // Keyboard
+ //
+ PKEYBOARD _Keyboard;
+
+ //
+ // Destination file specification. Used to convert source file
+ // names to destination file names.
+ //
+ PWSTRING _FileNamePattern;
+
+ //
+ // Indicates if it is ok to remove empty directories.
+ //
+ BOOLEAN _CanRemoveEmptyDirectories;
+
+ //
+ // Indicate if the destination is a file, and what the target
+ // file name should be.
+ //
+ BOOLEAN _TargetIsFile;
+ PPATH _TargetPath;
+
+ // File name with the exclusion list.
+ //
+ PSTRING_ARRAY _ExclusionList;
+ PITERATOR _Iterator;
+
+ BOOLEAN _Cancelled;
+};
+
+INLINE
+VOID
+XCOPY::AbortIfCtrlC (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ Aborts the program if Ctrl-C was hit.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Notes:
+
+--*/
+
+{
+ if ( _Keyboard->GotABreak() ) {
+ exit( EXIT_TERMINATED );
+ }
+}
+
+#endif // _XCOPY_
diff --git a/private/utils/xcopy/xcopy.rc b/private/utils/xcopy/xcopy.rc
new file mode 100644
index 000000000..44b1003cf
--- /dev/null
+++ b/private/utils/xcopy/xcopy.rc
@@ -0,0 +1,11 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_APP
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Extended Copy Utility"
+#define VER_INTERNALNAME_STR "xcopy\0"
+#define VER_ORIGINALFILENAME_STR "XCOPY.EXE"
+
+#include "common.ver"
+